[
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\"\n    schedule:\n      interval: \"daily\"\n    open-pull-requests-limit: 1\n"
  },
  {
    "path": ".github/matchers/gradle-build-kotlin-error-matcher.json",
    "content": "{\n  \"problemMatcher\": [\n    {\n      \"owner\": \"gradle-build-kotlin-error-matcher\",\n      \"severity\": \"error\",\n      \"pattern\": [\n        {\n          \"regexp\": \"^e:\\\\sfile:\\/\\/([^:]+):(\\\\d+):(\\\\d+)\\\\s(.+)$\",\n          \"file\": 1,\n          \"line\": 2,\n          \"column\": 3,\n          \"message\": 4\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": ".github/matchers/gradle-build-kotlin-error-matcher.json.license",
    "content": "SPDX-FileCopyrightText: none\nSPDX-License-Identifier: CC0-1.0\n"
  },
  {
    "path": ".github/matchers/gradle-build-matcher.json",
    "content": "{\n  \"problemMatcher\": [\n    {\n      \"owner\": \"gradle-build-matcher\",\n      \"pattern\": [\n        {\n          \"regexp\": \"^\\\\s*([^:]+):(\\\\d+):\\\\s(error|Error):\\\\s(.+)$\",\n          \"file\": 1,\n          \"line\": 2,\n          \"severity\": 3,\n          \"message\": 4\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": ".github/matchers/gradle-build-matcher.json.license",
    "content": "SPDX-FileCopyrightText: none\nSPDX-License-Identifier: CC0-1.0\n"
  },
  {
    "path": ".github/workflows/build.yml",
    "content": "name: \"Gradle build\"\npermissions: {}\non:\n  - push\n  - pull_request\n  - workflow_dispatch\n\njobs:\n  build:\n    name: \"Gradle build ${{ matrix.target }}\"\n    runs-on: ubuntu-latest\n    env:\n      GRADLE_MICROG_VERSION_WITHOUT_GIT: 1\n\n    strategy:\n      matrix:\n        target: [Debug, Release]\n\n    steps:\n      - name: \"Free disk space\"\n        run: |\n          # Deleting unneeded software packages\n          sudo rm -rf /opt/hostedtoolcache/CodeQL\n          sudo rm -rf /opt/hostedtoolcache/go\n\n          # Log available space\n          df -h\n      - name: \"Checkout sources\"\n        uses: actions/checkout@v6\n        with:\n          fetch-depth: 0\n      - name: \"Setup Java\"\n        uses: actions/setup-java@v5\n        with:\n          distribution: \"temurin\"\n          java-version: \"17\"\n      - name: \"Setup Gradle\"\n        uses: gradle/actions/setup-gradle@v5\n        with:\n          cache-encryption-key: ${{ secrets.GradleEncryptionKey }}\n          build-scan-publish: true\n          build-scan-terms-of-use-url: \"https://gradle.com/help/legal-terms-of-use\"\n          build-scan-terms-of-use-agree: \"yes\"\n      - name: \"Setup matchers\"\n        run: |\n          # Setting up matchers...\n\n          matchers_dir='${{ github.workspace }}/.github/matchers'\n          matcher_list()\n          {\n            echo 'gradle-build-matcher.json'\n            echo 'gradle-build-kotlin-error-matcher.json'\n          }\n\n          matcher_list | while IFS='' read -r NAME; do\n            if test -f \"${matchers_dir:?}/${NAME:?}\"; then\n              echo \"::add-matcher::${matchers_dir:?}/${NAME:?}\"\n              echo \"Matcher configured: ${NAME:?}\"\n            fi\n          done\n      - name: \"Execute Gradle assemble\"\n        run: \"./gradlew assemble${{ matrix.target }}\"\n      - name: \"Execute Gradle lint\"\n        run: \"./gradlew lint${{ matrix.target }}\"\n"
  },
  {
    "path": ".github/workflows/dependency-submission.yml",
    "content": "name: Dependency Submission\npermissions:\n  contents: write\non:\n  push:\n    branches: [ 'master' ]\n\njobs:\n  dependency-submission:\n    runs-on: ubuntu-latest\n    env:\n      GRADLE_MICROG_VERSION_WITHOUT_GIT: 1\n\n    steps:\n      - name: \"Checkout sources\"\n        uses: actions/checkout@v6\n        with:\n          fetch-depth: 0\n      - name: \"Setup Java\"\n        uses: actions/setup-java@v5\n        with:\n          distribution: \"temurin\"\n          java-version: \"17\"\n      - name: \"Generate and submit gradle dependency graph\"\n        uses: gradle/actions/dependency-submission@v5\n        with:\n          cache-encryption-key: ${{ secrets.GradleEncryptionKey }}\n          dependency-graph-continue-on-failure: true\n          build-scan-publish: true\n          build-scan-terms-of-use-url: \"https://gradle.com/help/legal-terms-of-use\"\n          build-scan-terms-of-use-agree: \"yes\"\n"
  },
  {
    "path": ".gitignore",
    "content": "*.iml\ngen/\nbin/\nbuild/\n.gradle/\n.idea/\nuser.gradle\nlocal.properties\n.directory\n\n.settings\n.classpath\n.project\n"
  },
  {
    "path": "Android.mk",
    "content": "# Copyright (c) 2015 μg Project Team\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\nLOCAL_PATH:= $(call my-dir)\ninclude $(CLEAR_VARS)\n\nLOCAL_MODULE := GmsCore\nLOCAL_MODULE_TAGS := optional\nLOCAL_PACKAGE_NAME := GmsCore\n\ngmscore_root  := $(LOCAL_PATH)\ngmscore_dir   := play-services-core\ngmscore_out   := $(TARGET_COMMON_OUT_ROOT)/obj/APPS/$(LOCAL_MODULE)_intermediates\ngmscore_build := $(gmscore_dir)/build\ngmscore_apk   := $(gmscore_build)/outputs/apk/release/play-services-core-release-unsigned.apk\n\n$(gmscore_root)/$(gmscore_apk):\n\trm -Rf $(gmscore_root)/$(gmscore_build)\n\tmkdir -p $(ANDROID_BUILD_TOP)/$(gmscore_out)\n\tln -s $(ANDROID_BUILD_TOP)/$(gmscore_out) $(ANDROID_BUILD_TOP)/$(gmscore_root)/$(gmscore_build)\n\techo \"sdk.dir=$(ANDROID_HOME)\" > $(gmscore_root)/local.properties\n\tcd $(gmscore_root) && git submodule update --recursive --init\n\tcd $(gmscore_root)/$(gmscore_dir) && JAVA_TOOL_OPTIONS=\"$(JAVA_TOOL_OPTIONS) -Dfile.encoding=UTF8\" ../gradlew assembleRelease\n\nLOCAL_CERTIFICATE := platform\nLOCAL_SRC_FILES := $(gmscore_apk)\nLOCAL_MODULE_CLASS := APPS\nLOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)\n\ninclude $(BUILD_PREBUILT)\n"
  },
  {
    "path": "LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          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\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. 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\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n"
  },
  {
    "path": "LICENSES/Apache-2.0.txt",
    "content": "Apache License\n\nVersion 2.0, January 2004\n\nhttp://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION,\nAND DISTRIBUTION\n\n   1. Definitions.\n\n      \n\n\"License\" shall mean the terms and conditions for use, reproduction, and distribution\nas defined by Sections 1 through 9 of this document.\n\n      \n\n\"Licensor\" shall mean the copyright owner or entity authorized by the copyright\nowner that is granting the License.\n\n      \n\n\"Legal Entity\" shall mean the union of the acting entity and all other entities\nthat control, are controlled by, or are under common control with that entity.\nFor the purposes of this definition, \"control\" means (i) the power, direct\nor indirect, to cause the direction or management of such entity, whether\nby contract or otherwise, or (ii) ownership of fifty percent (50%) or more\nof the outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \n\n\"You\" (or \"Your\") shall mean an individual or Legal Entity exercising permissions\ngranted by this License.\n\n      \n\n\"Source\" form shall mean the preferred form for making modifications, including\nbut not limited to software source code, documentation source, and configuration\nfiles.\n\n      \n\n\"Object\" form shall mean any form resulting from mechanical transformation\nor translation of a Source form, including but not limited to compiled object\ncode, generated documentation, and conversions to other media types.\n\n      \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 Appendix\nbelow).\n\n      \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 revisions,\nannotations, elaborations, or other modifications represent, as a whole, an\noriginal work of authorship. For the purposes of this License, Derivative\nWorks shall not include works that remain separable from, or merely link (or\nbind by name) to the interfaces of, the Work and Derivative Works thereof.\n\n      \n\n\"Contribution\" shall mean any work of authorship, including the original version\nof the Work and any modifications or additions to that Work or Derivative\nWorks thereof, that is intentionally submitted to Licensor for inclusion in\nthe Work by the copyright owner or by an individual or Legal Entity authorized\nto submit on behalf of the copyright owner. For the purposes of this definition,\n\"submitted\" means any form of electronic, verbal, or written communication\nsent to the Licensor or its representatives, including but not limited to\ncommunication on electronic mailing lists, source code control systems, and\nissue tracking systems that are managed by, or on behalf of, the Licensor\nfor the purpose of discussing and improving the Work, but excluding communication\nthat is conspicuously marked or otherwise designated in writing by the copyright\nowner as \"Not a Contribution.\"\n\n      \n\n\"Contributor\" shall mean Licensor and any individual or Legal Entity on behalf\nof whom a Contribution has been received by Licensor and subsequently incorporated\nwithin the Work.\n\n2. Grant of Copyright License. Subject to the terms and conditions of this\nLicense, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive,\nno-charge, royalty-free, irrevocable copyright license to reproduce, prepare\nDerivative Works of, publicly display, publicly perform, sublicense, and distribute\nthe Work and such Derivative Works in Source or Object form.\n\n3. Grant of Patent License. Subject to the terms and conditions of this License,\neach Contributor hereby grants to You a perpetual, worldwide, non-exclusive,\nno-charge, royalty-free, irrevocable (except as stated in this section) patent\nlicense to make, have made, use, offer to sell, sell, import, and otherwise\ntransfer the Work, where such license applies only to those patent claims\nlicensable by such Contributor that are necessarily infringed by their Contribution(s)\nalone or by combination of their Contribution(s) with the Work to which such\nContribution(s) was submitted. If You institute patent litigation against\nany entity (including a cross-claim or counterclaim in a lawsuit) alleging\nthat the Work or a Contribution incorporated within the Work constitutes direct\nor contributory patent infringement, then any patent licenses granted to You\nunder this License for that Work shall terminate as of the date such litigation\nis filed.\n\n4. Redistribution. You may reproduce and distribute copies of the Work or\nDerivative Works thereof in any medium, with or without modifications, and\nin Source or Object form, provided that You meet the following conditions:\n\n(a) You must give any other recipients of the Work or Derivative Works a copy\nof this License; and\n\n(b) You must cause any modified files to carry prominent notices stating that\nYou changed the files; and\n\n(c) You must retain, in the Source form of any Derivative Works that You distribute,\nall copyright, patent, trademark, and attribution notices from the Source\nform of the Work, excluding those notices that do not pertain to any part\nof the Derivative Works; and\n\n(d) If the Work includes a \"NOTICE\" text file as part of its distribution,\nthen any Derivative Works that You distribute must include a readable copy\nof the attribution notices contained within such NOTICE file, excluding those\nnotices that do not pertain to any part of the Derivative Works, in at least\none of the following places: within a NOTICE text file distributed as part\nof the Derivative Works; within the Source form or documentation, if provided\nalong with the Derivative Works; or, within a display generated by the Derivative\nWorks, if and wherever such third-party notices normally appear. The contents\nof the NOTICE file are for informational purposes only and do not modify the\nLicense. You may add Your own attribution notices within Derivative Works\nthat You distribute, alongside or as an addendum to the NOTICE text from the\nWork, provided that such additional attribution notices cannot be construed\nas modifying the License.\n\nYou may add Your own copyright statement to Your modifications and may provide\nadditional or different license terms and conditions for use, reproduction,\nor distribution of Your modifications, or for any such Derivative Works as\na whole, provided Your use, reproduction, and distribution of the Work otherwise\ncomplies with the conditions stated in this License.\n\n5. Submission of Contributions. Unless You explicitly state otherwise, any\nContribution intentionally submitted for inclusion in the Work by You to the\nLicensor shall be under the terms and conditions of this License, without\nany additional terms or conditions. Notwithstanding the above, nothing herein\nshall supersede or modify the terms of any separate license agreement you\nmay have executed with Licensor regarding such Contributions.\n\n6. Trademarks. This License does not grant permission to use the trade names,\ntrademarks, service marks, or product names of the Licensor, except as required\nfor reasonable and customary use in describing the origin of the Work and\nreproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty. Unless required by applicable law or agreed to\nin writing, Licensor provides the Work (and each Contributor provides its\nContributions) on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\nKIND, either express or implied, including, without limitation, any warranties\nor conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR\nA PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness\nof using or redistributing the Work and assume any risks associated with Your\nexercise of permissions under this License.\n\n8. Limitation of Liability. In no event and under no legal theory, whether\nin tort (including negligence), contract, or otherwise, unless required by\napplicable law (such as deliberate and grossly negligent acts) or agreed to\nin writing, shall any Contributor be liable to You for damages, including\nany direct, indirect, special, incidental, or consequential damages of any\ncharacter arising as a result of this License or out of the use or inability\nto use the Work (including but not limited to damages for loss of goodwill,\nwork stoppage, computer failure or malfunction, or any and all other commercial\ndamages or losses), even if such Contributor has been advised of the possibility\nof such damages.\n\n9. Accepting Warranty or Additional Liability. While redistributing the Work\nor Derivative Works thereof, You may choose to offer, and charge a fee for,\nacceptance of support, warranty, indemnity, or other liability obligations\nand/or rights consistent with this License. However, in accepting such obligations,\nYou may act only on Your own behalf and on Your sole responsibility, not on\nbehalf of any other Contributor, and only if You agree to indemnify, defend,\nand hold each Contributor harmless for any liability incurred by, or claims\nasserted against, such Contributor by reason of your accepting any such warranty\nor additional liability. END OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work.\n\nTo apply the Apache License to your work, attach the following boilerplate\nnotice, with the fields enclosed by brackets \"[]\" replaced with your own identifying\ninformation. (Don't include the brackets!) The text should be enclosed in\nthe appropriate comment syntax for the file format. We also recommend that\na file or class name and description of purpose be included on the same \"printed\npage\" as the copyright notice for easier identification within third-party\narchives.\n\nCopyright [yyyy] [name of copyright owner]\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\n\nyou may not use this file except in compliance with the License.\n\nYou may obtain a copy of the License at\n\nhttp://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\n\ndistributed under the License is distributed on an \"AS IS\" BASIS,\n\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n\nSee the License for the specific language governing permissions and\n\nlimitations under the License.\n"
  },
  {
    "path": "LICENSES/CC-BY-4.0.txt",
    "content": "Creative Commons Attribution 4.0 International Creative Commons Corporation\n(\"Creative Commons\") is not a law firm and does not provide legal services\nor legal advice. Distribution of Creative Commons public licenses does not\ncreate a lawyer-client or other relationship. Creative Commons makes its licenses\nand related information available on an \"as-is\" basis. Creative Commons gives\nno warranties regarding its licenses, any material licensed under their terms\nand conditions, or any related information. Creative Commons disclaims all\nliability for damages resulting from their use to the fullest extent possible.\n\nUsing Creative Commons Public Licenses\n\nCreative Commons public licenses provide a standard set of terms and conditions\nthat creators and other rights holders may use to share original works of\nauthorship and other material subject to copyright and certain other rights\nspecified in the public license below. The following considerations are for\ninformational purposes only, are not exhaustive, and do not form part of our\nlicenses.\n\nConsiderations for licensors: Our public licenses are intended for use by\nthose authorized to give the public permission to use material in ways otherwise\nrestricted by copyright and certain other rights. Our licenses are irrevocable.\nLicensors should read and understand the terms and conditions of the license\nthey choose before applying it. Licensors should also secure all rights necessary\nbefore applying our licenses so that the public can reuse the material as\nexpected. Licensors should clearly mark any material not subject to the license.\nThis includes other CC-licensed material, or material used under an exception\nor limitation to copyright. More considerations for licensors : wiki.creativecommons.org/Considerations_for_licensors\n\nConsiderations for the public: By using one of our public licenses, a licensor\ngrants the public permission to use the licensed material under specified\nterms and conditions. If the licensor's permission is not necessary for any\nreason–for example, because of any applicable exception or limitation to copyright–then\nthat use is not regulated by the license. Our licenses grant only permissions\nunder copyright and certain other rights that a licensor has authority to\ngrant. Use of the licensed material may still be restricted for other reasons,\nincluding because others have copyright or other rights in the material. A\nlicensor may make special requests, such as asking that all changes be marked\nor described. Although not required by our licenses, you are encouraged to\nrespect those requests where reasonable. More considerations for the public\n: wiki.creativecommons.org/Considerations_for_licensees Creative Commons Attribution\n4.0 International Public License\n\nBy exercising the Licensed Rights (defined below), You accept and agree to\nbe bound by the terms and conditions of this Creative Commons Attribution\n4.0 International Public License (\"Public License\"). To the extent this Public\nLicense may be interpreted as a contract, You are granted the Licensed Rights\nin consideration of Your acceptance of these terms and conditions, and the\nLicensor grants You such rights in consideration of benefits the Licensor\nreceives from making the Licensed Material available under these terms and\nconditions.\n\nSection 1 – Definitions.\n\na. Adapted Material means material subject to Copyright and Similar Rights\nthat is derived from or based upon the Licensed Material and in which the\nLicensed Material is translated, altered, arranged, transformed, or otherwise\nmodified in a manner requiring permission under the Copyright and Similar\nRights held by the Licensor. For purposes of this Public License, where the\nLicensed Material is a musical work, performance, or sound recording, Adapted\nMaterial is always produced where the Licensed Material is synched in timed\nrelation with a moving image.\n\nb. Adapter's License means the license You apply to Your Copyright and Similar\nRights in Your contributions to Adapted Material in accordance with the terms\nand conditions of this Public License.\n\nc. Copyright and Similar Rights means copyright and/or similar rights closely\nrelated to copyright including, without limitation, performance, broadcast,\nsound recording, and Sui Generis Database Rights, without regard to how the\nrights are labeled or categorized. For purposes of this Public License, the\nrights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights.\n\nd. Effective Technological Measures means those measures that, in the absence\nof proper authority, may not be circumvented under laws fulfilling obligations\nunder Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996,\nand/or similar international agreements.\n\ne. Exceptions and Limitations means fair use, fair dealing, and/or any other\nexception or limitation to Copyright and Similar Rights that applies to Your\nuse of the Licensed Material.\n\nf. Licensed Material means the artistic or literary work, database, or other\nmaterial to which the Licensor applied this Public License.\n\ng. Licensed Rights means the rights granted to You subject to the terms and\nconditions of this Public License, which are limited to all Copyright and\nSimilar Rights that apply to Your use of the Licensed Material and that the\nLicensor has authority to license.\n\nh. Licensor means the individual(s) or entity(ies) granting rights under this\nPublic License.\n\ni. Share means to provide material to the public by any means or process that\nrequires permission under the Licensed Rights, such as reproduction, public\ndisplay, public performance, distribution, dissemination, communication, or\nimportation, and to make material available to the public including in ways\nthat members of the public may access the material from a place and at a time\nindividually chosen by them.\n\nj. Sui Generis Database Rights means rights other than copyright resulting\nfrom Directive 96/9/EC of the European Parliament and of the Council of 11\nMarch 1996 on the legal protection of databases, as amended and/or succeeded,\nas well as other essentially equivalent rights anywhere in the world.\n\nk. You means the individual or entity exercising the Licensed Rights under\nthis Public License. Your has a corresponding meaning.\n\nSection 2 – Scope.\n\n   a. License grant.\n\n1. Subject to the terms and conditions of this Public License, the Licensor\nhereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive,\nirrevocable license to exercise the Licensed Rights in the Licensed Material\nto:\n\n         A. reproduce and Share the Licensed Material, in whole or in part; and\n\n         B. produce, reproduce, and Share Adapted Material.\n\n2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions\nand Limitations apply to Your use, this Public License does not apply, and\nYou do not need to comply with its terms and conditions.\n\n      3. Term. The term of this Public License is specified in Section 6(a).\n\n4. Media and formats; technical modifications allowed. The Licensor authorizes\nYou to exercise the Licensed Rights in all media and formats whether now known\nor hereafter created, and to make technical modifications necessary to do\nso. The Licensor waives and/or agrees not to assert any right or authority\nto forbid You from making technical modifications necessary to exercise the\nLicensed Rights, including technical modifications necessary to circumvent\nEffective Technological Measures. For purposes of this Public License, simply\nmaking modifications authorized by this Section 2(a)(4) never produces Adapted\nMaterial.\n\n      5. Downstream recipients.\n\nA. Offer from the Licensor – Licensed Material. Every recipient of the Licensed\nMaterial automatically receives an offer from the Licensor to exercise the\nLicensed Rights under the terms and conditions of this Public License.\n\nB. No downstream restrictions. You may not offer or impose any additional\nor different terms or conditions on, or apply any Effective Technological\nMeasures to, the Licensed Material if doing so restricts exercise of the Licensed\nRights by any recipient of the Licensed Material.\n\n6. No endorsement. Nothing in this Public License constitutes or may be construed\nas permission to assert or imply that You are, or that Your use of the Licensed\nMaterial is, connected with, or sponsored, endorsed, or granted official status\nby, the Licensor or others designated to receive attribution as provided in\nSection 3(a)(1)(A)(i).\n\n   b. Other rights.\n\n1. Moral rights, such as the right of integrity, are not licensed under this\nPublic License, nor are publicity, privacy, and/or other similar personality\nrights; however, to the extent possible, the Licensor waives and/or agrees\nnot to assert any such rights held by the Licensor to the limited extent necessary\nto allow You to exercise the Licensed Rights, but not otherwise.\n\n2. Patent and trademark rights are not licensed under this Public License.\n\n3. To the extent possible, the Licensor waives any right to collect royalties\nfrom You for the exercise of the Licensed Rights, whether directly or through\na collecting society under any voluntary or waivable statutory or compulsory\nlicensing scheme. In all other cases the Licensor expressly reserves any right\nto collect such royalties.\n\nSection 3 – License Conditions.\n\nYour exercise of the Licensed Rights is expressly made subject to the following\nconditions.\n\n   a. Attribution.\n\n1. If You Share the Licensed Material (including in modified form), You must:\n\nA. retain the following if it is supplied by the Licensor with the Licensed\nMaterial:\n\ni. identification of the creator(s) of the Licensed Material and any others\ndesignated to receive attribution, in any reasonable manner requested by the\nLicensor (including by pseudonym if 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 warranties;\n\nv. a URI or hyperlink to the Licensed Material to the extent reasonably practicable;\n\nB. indicate if You modified the Licensed Material and retain an indication\nof any previous modifications; and\n\nC. indicate the Licensed Material is licensed under this Public License, and\ninclude the text of, or the URI or hyperlink to, this Public License.\n\n2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner\nbased on the medium, means, and context in which You Share the Licensed Material.\nFor example, it may be reasonable to satisfy the conditions by providing a\nURI or hyperlink to a resource that includes the required information.\n\n3. If requested by the Licensor, You must remove any of the information required\nby Section 3(a)(1)(A) to the extent reasonably practicable.\n\n4. If You Share Adapted Material You produce, the Adapter's License You apply\nmust not prevent recipients of the Adapted Material from complying with this\nPublic License.\n\nSection 4 – Sui Generis Database Rights.\n\nWhere the Licensed Rights include Sui Generis Database Rights that apply to\nYour use of the Licensed Material:\n\na. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract,\nreuse, reproduce, and Share all or a substantial portion of the contents of\nthe database;\n\nb. if You include all or a substantial portion of the database contents in\na database in which You have Sui Generis Database Rights, then the database\nin which You have Sui Generis Database Rights (but not its individual contents)\nis Adapted Material; and\n\nc. You must comply with the conditions in Section 3(a) if You Share all or\na substantial portion of the contents of the database.\n\nFor the avoidance of doubt, this Section 4 supplements and does not replace\nYour obligations under this Public License where the Licensed Rights include\nother Copyright and Similar Rights.\n\nSection 5 – Disclaimer of Warranties and Limitation of Liability.\n\na. Unless otherwise separately undertaken by the Licensor, to the extent possible,\nthe Licensor offers the Licensed Material as-is and as-available, and makes\nno representations or warranties of any kind concerning the Licensed Material,\nwhether express, implied, statutory, or other. This includes, without limitation,\nwarranties of title, merchantability, fitness for a particular purpose, non-infringement,\nabsence of latent or other defects, accuracy, or the presence or absence of\nerrors, whether or not known or discoverable. Where disclaimers of warranties\nare not allowed in full or in part, this disclaimer may not apply to You.\n\nb. To the extent possible, in no event will the Licensor be liable to You\non any legal theory (including, without limitation, negligence) or otherwise\nfor any direct, special, indirect, incidental, consequential, punitive, exemplary,\nor other losses, costs, expenses, or damages arising out of this Public License\nor use of the Licensed Material, even if the Licensor has been advised of\nthe possibility of such losses, costs, expenses, or damages. Where a limitation\nof liability is not allowed in full or in part, this limitation may not apply\nto You.\n\nc. The disclaimer of warranties and limitation of liability provided above\nshall be interpreted in a manner that, to the extent possible, most closely\napproximates an absolute disclaimer and waiver of all liability.\n\nSection 6 – Term and Termination.\n\na. This Public License applies for the term of the Copyright and Similar Rights\nlicensed here. However, if You fail to comply with this Public License, then\nYour rights under this Public License terminate automatically.\n\nb. Where Your right to use the Licensed Material has terminated under Section\n6(a), it reinstates:\n\n1. automatically as of the date the violation is cured, provided it is cured\nwithin 30 days of Your discovery of the violation; or\n\n      2. upon express reinstatement by the Licensor.\n\nc. For the avoidance of doubt, this Section 6(b) does not affect any right\nthe Licensor may have to seek remedies for Your violations of this Public\nLicense.\n\nd. For the avoidance of doubt, the Licensor may also offer the Licensed Material\nunder separate terms or conditions or stop distributing the Licensed Material\nat any time; however, doing so will not terminate this Public License.\n\n   e. Sections 1, 5, 6, 7, and 8 survive termination of this Public License.\n\nSection 7 – Other Terms and Conditions.\n\na. The Licensor shall not be bound by any additional or different terms or\nconditions communicated by You unless expressly agreed.\n\nb. Any arrangements, understandings, or agreements regarding the Licensed\nMaterial not stated herein are separate from and independent of the terms\nand conditions of this Public License.\n\nSection 8 – Interpretation.\n\na. For the avoidance of doubt, this Public License does not, and shall not\nbe interpreted to, reduce, limit, restrict, or impose conditions on any use\nof the Licensed Material that could lawfully be made without permission under\nthis Public License.\n\nb. To the extent possible, if any provision of this Public License is deemed\nunenforceable, it shall be automatically reformed to the minimum extent necessary\nto make it enforceable. If the provision cannot be reformed, it shall be severed\nfrom this Public License without affecting the enforceability of the remaining\nterms and conditions.\n\nc. No term or condition of this Public License will be waived and no failure\nto comply consented to unless expressly agreed to by the Licensor.\n\nd. Nothing in this Public License constitutes or may be interpreted as a limitation\nupon, or waiver of, any privileges and immunities that apply to the Licensor\nor You, including from the legal processes of any jurisdiction or authority.\n\nCreative Commons is not a party to its public licenses. Notwithstanding, Creative\nCommons may elect to apply one of its public licenses to material it publishes\nand in those instances will be considered the \"Licensor.\" The text of the\nCreative Commons public licenses is dedicated to the public domain under the\nCC0 Public Domain Dedication. Except for the limited purpose of indicating\nthat material is shared under a Creative Commons public license or as otherwise\npermitted by the Creative Commons policies published at creativecommons.org/policies,\nCreative Commons does not authorize the use of the trademark \"Creative Commons\"\nor any other trademark or logo of Creative Commons without its prior written\nconsent including, without limitation, in connection with any unauthorized\nmodifications to any of its public licenses or any other arrangements, understandings,\nor agreements concerning use of licensed material. For the avoidance of doubt,\nthis paragraph does not form part of the public licenses.\n\nCreative Commons may be contacted at creativecommons.org.\n"
  },
  {
    "path": "LICENSES/CC0-1.0.txt",
    "content": "Creative Commons Legal Code\n\nCC0 1.0 Universal\n\n    CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE\n    LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN\n    ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS\n    INFORMATION ON AN \"AS-IS\" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES\n    REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS\n    PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM\n    THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED\n    HEREUNDER.\n\nStatement of Purpose\n\nThe laws of most jurisdictions throughout the world automatically confer\nexclusive Copyright and Related Rights (defined below) upon the creator\nand subsequent owner(s) (each and all, an \"owner\") of an original work of\nauthorship and/or a database (each, a \"Work\").\n\nCertain owners wish to permanently relinquish those rights to a Work for\nthe purpose of contributing to a commons of creative, cultural and\nscientific works (\"Commons\") that the public can reliably and without fear\nof later claims of infringement build upon, modify, incorporate in other\nworks, reuse and redistribute as freely as possible in any form whatsoever\nand for any purposes, including without limitation commercial purposes.\nThese owners may contribute to the Commons to promote the ideal of a free\nculture and the further production of creative, cultural and scientific\nworks, or to gain reputation or greater distribution for their Work in\npart through the use and efforts of others.\n\nFor these and/or other purposes and motivations, and without any\nexpectation of additional consideration or compensation, the person\nassociating CC0 with a Work (the \"Affirmer\"), to the extent that he or she\nis an owner of Copyright and Related Rights in the Work, voluntarily\nelects to apply CC0 to the Work and publicly distribute the Work under its\nterms, with knowledge of his or her Copyright and Related Rights in the\nWork and the meaning and intended legal effect of CC0 on those rights.\n\n1. Copyright and Related Rights. A Work made available under CC0 may be\nprotected by copyright and related or neighboring rights (\"Copyright and\nRelated Rights\"). Copyright and Related Rights include, but are not\nlimited to, the following:\n\n  i. the right to reproduce, adapt, distribute, perform, display,\n     communicate, and translate a Work;\n ii. moral rights retained by the original author(s) and/or performer(s);\niii. publicity and privacy rights pertaining to a person's image or\n     likeness depicted in a Work;\n iv. rights protecting against unfair competition in regards to a Work,\n     subject to the limitations in paragraph 4(a), below;\n  v. rights protecting the extraction, dissemination, use and reuse of data\n     in a Work;\n vi. database rights (such as those arising under Directive 96/9/EC of the\n     European Parliament and of the Council of 11 March 1996 on the legal\n     protection of databases, and under any national implementation\n     thereof, including any amended or successor version of such\n     directive); and\nvii. other similar, equivalent or corresponding rights throughout the\n     world based on applicable law or treaty, and any national\n     implementations thereof.\n\n2. Waiver. To the greatest extent permitted by, but not in contravention\nof, applicable law, Affirmer hereby overtly, fully, permanently,\nirrevocably and unconditionally waives, abandons, and surrenders all of\nAffirmer's Copyright and Related Rights and associated claims and causes\nof action, whether now known or unknown (including existing as well as\nfuture claims and causes of action), in the Work (i) in all territories\nworldwide, (ii) for the maximum duration provided by applicable law or\ntreaty (including future time extensions), (iii) in any current or future\nmedium and for any number of copies, and (iv) for any purpose whatsoever,\nincluding without limitation commercial, advertising or promotional\npurposes (the \"Waiver\"). Affirmer makes the Waiver for the benefit of each\nmember of the public at large and to the detriment of Affirmer's heirs and\nsuccessors, fully intending that such Waiver shall not be subject to\nrevocation, rescission, cancellation, termination, or any other legal or\nequitable action to disrupt the quiet enjoyment of the Work by the public\nas contemplated by Affirmer's express Statement of Purpose.\n\n3. Public License Fallback. Should any part of the Waiver for any reason\nbe judged legally invalid or ineffective under applicable law, then the\nWaiver shall be preserved to the maximum extent permitted taking into\naccount Affirmer's express Statement of Purpose. In addition, to the\nextent the Waiver is so judged Affirmer hereby grants to each affected\nperson a royalty-free, non transferable, non sublicensable, non exclusive,\nirrevocable and unconditional license to exercise Affirmer's Copyright and\nRelated Rights in the Work (i) in all territories worldwide, (ii) for the\nmaximum duration provided by applicable law or treaty (including future\ntime extensions), (iii) in any current or future medium and for any number\nof copies, and (iv) for any purpose whatsoever, including without\nlimitation commercial, advertising or promotional purposes (the\n\"License\"). The License shall be deemed effective as of the date CC0 was\napplied by Affirmer to the Work. Should any part of the License for any\nreason be judged legally invalid or ineffective under applicable law, such\npartial invalidity or ineffectiveness shall not invalidate the remainder\nof the License, and in such case Affirmer hereby affirms that he or she\nwill not (i) exercise any of his or her remaining Copyright and Related\nRights in the Work or (ii) assert any associated claims and causes of\naction with respect to the Work, in either case contrary to Affirmer's\nexpress Statement of Purpose.\n\n4. Limitations and Disclaimers.\n\n a. No trademark or patent rights held by Affirmer are waived, abandoned,\n    surrendered, licensed or otherwise affected by this document.\n b. Affirmer offers the Work as-is and makes no representations or\n    warranties of any kind concerning the Work, express, implied,\n    statutory or otherwise, including without limitation warranties of\n    title, merchantability, fitness for a particular purpose, non\n    infringement, or the absence of latent or other defects, accuracy, or\n    the present or absence of errors, whether or not discoverable, all to\n    the greatest extent permissible under applicable law.\n c. Affirmer disclaims responsibility for clearing rights of other persons\n    that may apply to the Work or any use thereof, including without\n    limitation any person's Copyright and Related Rights in the Work.\n    Further, Affirmer disclaims responsibility for obtaining any necessary\n    consents, permissions or other rights required for any use of the\n    Work.\n d. Affirmer understands and acknowledges that Creative Commons is not a\n    party to this document and has no duty or obligation with respect to\n    this CC0 or use of the Work.\n"
  },
  {
    "path": "README.md",
    "content": "# microG Services\n\n[![Build status](https://github.com/microg/GmsCore/actions/workflows/build.yml/badge.svg)](https://github.com/microg/GmsCore/actions/workflows/build.yml)\n<a href=TRANSLATION.md>\n<img src=\"https://hosted.weblate.org/widget/microg/svg-badge.svg\" alt=\"Translation status\" />\n</a>\n\nmicroG Services is a FLOSS (Free/Libre Open Source Software) framework to allow applications designed for Google Play Services to run on systems, where Play Services is not available.\n\n### Please refer to the [wiki](https://github.com/microg/GmsCore/wiki) for downloads and instructions\n\n## Translations\n\nIf you'd like to help translate microG, take a look at [TRANSLATION](TRANSLATION.md).\n\n\nLicense\n-------\n    Copyright 2013-2025 microG Project Team\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"
  },
  {
    "path": "TRANSLATION.md",
    "content": "# Translating microG\nmicroG [can be translated using Weblate](https://hosted.weblate.org/projects/microg/#languages). Thanks Weblate for free libre hosting!\n\nPreferably do not use pull requests to submit translations, as merge conflicts can happen easily. If you already made one or did it manually, you can try [importing](https://docs.weblate.org/en/latest/user/files.html#uploading-translations) the files manually into Weblate.\n\n> [!TIP]\n> At the moment, the [microG-UI-tools](play-services-core/microg-ui-tools) component is not available for translation using Weblate. You may want to open a pull request for this. This component stores strings for the \"Self-Check\" menu and a few other things.\n\nIf your language does not seem to be available for translation, you may have to add it first. If you're not logged in, you'll need to create an account and configure your known languages, once that's set up, you should be able to get working.\n\nThanks for your help maintaining accessibility for other users worldwide! We appreciate it.\n"
  },
  {
    "path": "artwork/styles/README.md",
    "content": "## The files\n\n* `style-microg-normal-openmaptiles.json` is a pure OpenMapTiles schema version of microG's custom style. The sources are set to Stadia but could be modified to be used with another schema-compliant vendor, e.g. MapTiler.\n* `style-microg-normal-stadia.json` is a variant with Stadia custom layers.\n* `style-microg-normal-mapbox.json` is a historic, unmaintained variant for use with Mapbox.\n* `style-microg-satellite-*.json` is the same, but with a satellite layer (the stadia variant is almost pure openmaptiles, but openmaptiles does not specify a satellite layer).\n* `style-stadia-outdoors.json` is identical to Stadia's Outdoors style, but with added microG metadata.\n\n* `sprite_sources` files can be generated to a single sprite file as found in the app's assets using `spreet` (see below).\n* PBF files for fonts can be generated using `build_pbf_glyphs` from the `fonts` folder.\n\n## Resources\n\n### For creating styles\n\n* Tool: https://maputnik.github.io/\n* Style spec: https://maplibre.org/maplibre-style-spec/\n\t* https://maplibre.org/maplibre-style-spec/expressions/\n* Style schema: **https://openmaptiles.org/schema/**\n* Schema tileset explorer (requires maptiler login): https://cloud.maptiler.com/tiles/v3-openmaptiles/\n\n#### Vendor-specific\n* Mapbox\n    * https://docs.mapbox.com/data/tilesets/reference/mapbox-streets-v8/\n* Stadia\n    * https://docs.stadiamaps.com/custom-styles/\n    * https://docs.stadiamaps.com/tilesets/\n    \n### For converting assets\n\n* https://github.com/flother/spreet\n* https://github.com/stadiamaps/sdf_font_tools/tree/main/build_pbf_glyphs\n\n\nCommands:\n\n```\n$ cp style-microg-{satellite,normal}-{mapbox,stadia}.json style-stadia-outdoors.json style-mapbox-outdoors-v12.json ../../play-services-maps-core-mapbox/src/main/assets/\n$ spreet sprite_sources/ ../../play-services-maps-core-mapbox/src/main/assets/sprites\n$ spreet --retina sprite_sources/ ../../play-services-maps-core-mapbox/src/main/assets/sprites@2x\n$ build_pbf_glyphs --overwrite -c fonts/combinations.json fonts/ ../../play-services-maps-core-mapbox/src/main/assets\n$ rm -r ../../play-services-maps-core-mapbox/src/main/assets/OpenSans\\ Regular # remove temporary files\n```\n\n* We combine Open Sans Regular with Roboto Regular so that no glyphs are missing.\n* A symbolic link in the assets folder points from the font stack specification \"Open Sans Regular,Arial Unicode MS Regular\" to \"Roboto Regular\". It is unclear why MapLibre sometimes tries to access this font and fails rendering entire tiles if it is not present.\n\nThe assets are referenced using `asset://` in the style. For using Maputnik, it may be convenient to set the glyphs and sprites source to these Mapbox-hosted sources:\n\n```\n    \"sprite\": \"mapbox://sprites/microg/cjui4020201oo1fmca7yuwbor/8fkcj5fgn4mftlzuak3guz1f9\",\n    \"glyphs\": \"mapbox://fonts/microg/{fontstack}/{range}.pbf\",\n```\n\n## Legal\n\n* normal and satellite microG styles based on Mapbox Basic, part of the Mapbox Open Styles, licensed under\n    * Style code: BSD license\n    * Style virtual features / design: CC BY 3.0\n    * Reference: https://github.com/mapbox/mapbox-gl-styles/blob/master/LICENSE.md\n* derivation created by larma\n* derivation created by /e/ foundation\n* makes use of snippets from [Stadia's variant of OSM Bright](https://docs.stadiamaps.com/map-styles/osm-bright/), also a derivation of Mapbox Open Styles\n\t* Style code: BSD 3-Clause License\n\t* Style design: CC-BY 4.0\n\t* Reference: https://stadiamaps.com/attribution/\n* fonts: Roboto family, licensed Apache 2.0, https://fonts.google.com/specimen/Roboto/about\n\n* outdoor style based on https://docs.stadiamaps.com/map-styles/outdoors/#__tabbed_1_2\n    * Style code: BSD 3-Clause License\n\t* Style design: CC-BY 4.0\n\t* Reference: https://stadiamaps.com\n\n"
  },
  {
    "path": "artwork/styles/fonts/combinations.json",
    "content": "{\"Roboto Regular\": [\"Roboto Regular\", \"OpenSans Regular\"]}\n"
  },
  {
    "path": "artwork/styles/style-mapbox-outdoors-v12.json",
    "content": "{\n    \"name\": \"Mapbox Outdoors\",\n    \"sprite\": \"mapbox://sprites/mapbox/outdoors-v12\",\n    \"glyphs\": \"mapbox://fonts/mapbox/{fontstack}/{range}.pbf\",\n    \"center\": [\n        9.1,\n        42.2\n    ],\n    \"zoom\": 7.5,\n    \"fog\": {\n        \"range\": [\n            1,\n            20\n        ],\n        \"color\": [\n            \"interpolate\",\n            [\n                \"linear\"\n            ],\n            [\n                \"zoom\"\n            ],\n            4,\n            \"hsl(200, 100%, 100%)\",\n            6,\n            \"hsl(200, 50%, 90%)\"\n        ],\n        \"high-color\": [\n            \"interpolate\",\n            [\n                \"linear\"\n            ],\n            [\n                \"zoom\"\n            ],\n            4,\n            \"hsl(200, 100%, 60%)\",\n            6,\n            \"hsl(310, 60%, 80%)\"\n        ],\n        \"space-color\": [\n            \"interpolate\",\n            [\n                \"exponential\",\n                1.2\n            ],\n            [\n                \"zoom\"\n            ],\n            4,\n            \"hsl(205, 10%, 10%)\",\n            6,\n            \"hsl(205, 60%, 50%)\"\n        ],\n        \"horizon-blend\": [\n            \"interpolate\",\n            [\n                \"exponential\",\n                1.2\n            ],\n            [\n                \"zoom\"\n            ],\n            4,\n            0.01,\n            6,\n            0.1\n        ],\n        \"star-intensity\": [\n            \"interpolate\",\n            [\n                \"exponential\",\n                1.2\n            ],\n            [\n                \"zoom\"\n            ],\n            4,\n            0.1,\n            6,\n            0\n        ]\n    },\n    \"projection\": {\n        \"name\": \"globe\"\n    },\n    \"visibility\": \"public\",\n    \"version\": 8,\n    \"layers\": [\n        {\n            \"id\": \"land\",\n            \"type\": \"background\",\n            \"layout\": {},\n            \"minzoom\": 0,\n            \"paint\": {\n                \"background-color\": \"hsl(60, 20%, 85%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"land-and-water\",\n                \"mapbox:group\": \"Land & water, land\",\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"landcover\",\n            \"type\": \"fill\",\n            \"source\": \"composite\",\n            \"source-layer\": \"landcover\",\n            \"minzoom\": 0,\n            \"maxzoom\": 12,\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"wood\",\n                    \"hsla(103, 50%, 60%, 0.8)\",\n                    \"scrub\",\n                    \"hsla(98, 47%, 68%, 0.6)\",\n                    \"crop\",\n                    \"hsla(68, 55%, 70%, 0.6)\",\n                    \"grass\",\n                    \"hsla(98, 50%, 74%, 0.6)\",\n                    \"snow\",\n                    \"hsl(205, 45%, 95%)\",\n                    \"hsl(98, 48%, 67%)\"\n                ],\n                \"fill-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    0.8,\n                    12,\n                    0\n                ],\n                \"fill-antialias\": false\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"land-and-water\",\n                \"mapbox:group\": \"Land & water, land\",\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"national-park\",\n            \"type\": \"fill\",\n            \"source\": \"composite\",\n            \"source-layer\": \"landuse_overlay\",\n            \"minzoom\": 5,\n            \"filter\": [\n                \"==\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                \"national_park\"\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": \"hsl(98, 38%, 68%)\",\n                \"fill-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    5,\n                    0,\n                    6,\n                    0.6,\n                    12,\n                    0.2\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"land-and-water\",\n                \"mapbox:group\": \"Land & water, land\",\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"national-park_tint-band\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"landuse_overlay\",\n            \"minzoom\": 9,\n            \"filter\": [\n                \"==\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                \"national_park\"\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsl(98, 38%, 68%)\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    1,\n                    14,\n                    8\n                ],\n                \"line-blur\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    1,\n                    14,\n                    8\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"land-and-water\",\n                \"mapbox:group\": \"Land & water, land\",\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"landuse\",\n            \"type\": \"fill\",\n            \"source\": \"composite\",\n            \"source-layer\": \"landuse\",\n            \"minzoom\": 5,\n            \"filter\": [\n                \"all\",\n                [\n                    \">=\",\n                    [\n                        \"to-number\",\n                        [\n                            \"get\",\n                            \"sizerank\"\n                        ]\n                    ],\n                    0\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"agriculture\",\n                        \"wood\",\n                        \"grass\",\n                        \"scrub\",\n                        \"glacier\",\n                        \"pitch\",\n                        \"sand\"\n                    ],\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        false,\n                        11,\n                        true\n                    ],\n                    \"residential\",\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        true,\n                        10,\n                        false\n                    ],\n                    [\n                        \"park\",\n                        \"airport\"\n                    ],\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        false,\n                        8,\n                        [\n                            \"case\",\n                            [\n                                \"==\",\n                                [\n                                    \"get\",\n                                    \"sizerank\"\n                                ],\n                                1\n                            ],\n                            true,\n                            false\n                        ],\n                        10,\n                        true\n                    ],\n                    [\n                        \"facility\",\n                        \"industrial\"\n                    ],\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        false,\n                        12,\n                        true\n                    ],\n                    \"rock\",\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        false,\n                        11,\n                        true\n                    ],\n                    \"cemetery\",\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        false,\n                        11,\n                        true\n                    ],\n                    \"school\",\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        false,\n                        11,\n                        true\n                    ],\n                    \"hospital\",\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        false,\n                        11,\n                        true\n                    ],\n                    \"commercial_area\",\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        false,\n                        11,\n                        true\n                    ],\n                    false\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"-\",\n                        [\n                            \"to-number\",\n                            [\n                                \"get\",\n                                \"sizerank\"\n                            ]\n                        ],\n                        [\n                            \"interpolate\",\n                            [\n                                \"exponential\",\n                                1.5\n                            ],\n                            [\n                                \"zoom\"\n                            ],\n                            12,\n                            0,\n                            18,\n                            14\n                        ]\n                    ],\n                    14\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        \"wood\",\n                        \"hsla(103, 50%, 60%, 0.8)\",\n                        \"scrub\",\n                        \"hsla(98, 47%, 68%, 0.6)\",\n                        \"agriculture\",\n                        \"hsla(98, 50%, 74%, 0.6)\",\n                        \"park\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"type\"\n                            ],\n                            [\n                                \"garden\",\n                                \"playground\",\n                                \"zoo\"\n                            ],\n                            \"hsl(98, 38%, 68%)\",\n                            \"hsl(98, 55%, 70%)\"\n                        ],\n                        \"grass\",\n                        \"hsla(98, 50%, 74%, 0.6)\",\n                        \"airport\",\n                        \"hsl(230, 40%, 82%)\",\n                        \"cemetery\",\n                        \"hsl(98, 45%, 75%)\",\n                        \"glacier\",\n                        \"hsl(205, 45%, 95%)\",\n                        \"hospital\",\n                        \"hsl(20, 45%, 82%)\",\n                        \"pitch\",\n                        \"hsl(88, 65%, 75%)\",\n                        \"sand\",\n                        \"hsl(69, 60%, 72%)\",\n                        \"rock\",\n                        \"hsl(60, 0%, 85%)\",\n                        \"school\",\n                        \"hsl(40, 45%, 78%)\",\n                        \"commercial_area\",\n                        \"hsl(55, 45%, 85%)\",\n                        \"residential\",\n                        \"hsl(60, 7%, 87%)\",\n                        [\n                            \"facility\",\n                            \"industrial\"\n                        ],\n                        \"hsl(230, 20%, 85%)\",\n                        \"hsl(60, 22%, 72%)\"\n                    ],\n                    16,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        \"wood\",\n                        \"hsla(103, 50%, 60%, 0.8)\",\n                        \"scrub\",\n                        \"hsla(98, 47%, 68%, 0.6)\",\n                        \"agriculture\",\n                        \"hsla(98, 50%, 74%, 0.6)\",\n                        \"park\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"type\"\n                            ],\n                            [\n                                \"garden\",\n                                \"playground\",\n                                \"zoo\"\n                            ],\n                            \"hsl(98, 38%, 68%)\",\n                            \"hsl(98, 55%, 70%)\"\n                        ],\n                        \"grass\",\n                        \"hsla(98, 50%, 74%, 0.6)\",\n                        \"airport\",\n                        \"hsl(230, 40%, 82%)\",\n                        \"cemetery\",\n                        \"hsl(98, 45%, 75%)\",\n                        \"glacier\",\n                        \"hsl(205, 45%, 95%)\",\n                        \"hospital\",\n                        \"hsl(20, 45%, 82%)\",\n                        \"pitch\",\n                        \"hsl(88, 65%, 75%)\",\n                        \"sand\",\n                        \"hsl(69, 60%, 72%)\",\n                        \"rock\",\n                        \"hsla(60, 0%, 85%, 0.5)\",\n                        \"school\",\n                        \"hsl(40, 45%, 78%)\",\n                        \"commercial_area\",\n                        \"hsla(55, 45%, 85%, 0.5)\",\n                        [\n                            \"facility\",\n                            \"industrial\"\n                        ],\n                        \"hsl(230, 20%, 85%)\",\n                        \"hsl(60, 22%, 72%)\"\n                    ]\n                ],\n                \"fill-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        \"residential\",\n                        0.8,\n                        0.2\n                    ],\n                    10,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        \"residential\",\n                        0,\n                        1\n                    ]\n                ],\n                \"fill-antialias\": false\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"land-and-water\",\n                \"mapbox:group\": \"Land & water, land\",\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"pitch-outline\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"landuse\",\n            \"minzoom\": 15,\n            \"filter\": [\n                \"==\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                \"pitch\"\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsl(88, 60%, 65%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"land-and-water\",\n                \"mapbox:group\": \"Land & water, land\",\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"waterway-shadow\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"waterway\",\n            \"minzoom\": 10,\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    11,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    11,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-color\": \"hsl(224, 79%, 69%)\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.3\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"canal\",\n                            \"river\"\n                        ],\n                        0.1,\n                        0\n                    ],\n                    20,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"canal\",\n                            \"river\"\n                        ],\n                        8,\n                        3\n                    ]\n                ],\n                \"line-translate\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.2\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    7,\n                    [\n                        \"literal\",\n                        [\n                            0,\n                            0\n                        ]\n                    ],\n                    16,\n                    [\n                        \"literal\",\n                        [\n                            -1,\n                            -1\n                        ]\n                    ]\n                ],\n                \"line-translate-anchor\": \"viewport\",\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    0,\n                    8.5,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"land-and-water\",\n                \"mapbox:group\": \"Land & water, water\",\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"water-shadow\",\n            \"type\": \"fill\",\n            \"source\": \"composite\",\n            \"source-layer\": \"water\",\n            \"minzoom\": 10,\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": \"hsl(224, 79%, 69%)\",\n                \"fill-translate\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.2\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    7,\n                    [\n                        \"literal\",\n                        [\n                            0,\n                            0\n                        ]\n                    ],\n                    16,\n                    [\n                        \"literal\",\n                        [\n                            -1,\n                            -1\n                        ]\n                    ]\n                ],\n                \"fill-translate-anchor\": \"viewport\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"land-and-water\",\n                \"mapbox:group\": \"Land & water, water\",\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"waterway\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"waterway\",\n            \"minzoom\": 8,\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    11,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    11,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-color\": \"hsl(205, 75%, 70%)\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.3\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"canal\",\n                            \"river\"\n                        ],\n                        0.1,\n                        0\n                    ],\n                    20,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"canal\",\n                            \"river\"\n                        ],\n                        8,\n                        3\n                    ]\n                ],\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    0,\n                    8.5,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"land-and-water\",\n                \"mapbox:group\": \"Land & water, water\",\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"water\",\n            \"type\": \"fill\",\n            \"source\": \"composite\",\n            \"source-layer\": \"water\",\n            \"minzoom\": 0,\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": \"hsl(205, 75%, 70%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"land-and-water\",\n                \"mapbox:group\": \"Land & water, water\",\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"water-depth\",\n            \"type\": \"fill\",\n            \"source\": \"composite\",\n            \"source-layer\": \"depth\",\n            \"minzoom\": 0,\n            \"maxzoom\": 8,\n            \"layout\": {},\n            \"paint\": {\n                \"fill-antialias\": false,\n                \"fill-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    6,\n                    [\n                        \"interpolate\",\n                        [\n                            \"linear\"\n                        ],\n                        [\n                            \"get\",\n                            \"min_depth\"\n                        ],\n                        0,\n                        \"hsla(205, 75%, 70%, 0.35)\",\n                        200,\n                        \"hsla(205, 75%, 63%, 0.35)\",\n                        7000,\n                        \"hsla(205, 75%, 56%, 0.35)\"\n                    ],\n                    8,\n                    [\n                        \"interpolate\",\n                        [\n                            \"linear\"\n                        ],\n                        [\n                            \"get\",\n                            \"min_depth\"\n                        ],\n                        0,\n                        \"hsla(205, 75%, 70%, 0)\",\n                        200,\n                        \"hsla(205, 75%, 63%, 0)\",\n                        7000,\n                        \"hsla(205, 75%, 53%, 0)\"\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"land-and-water\",\n                \"mapbox:group\": \"Land & water, water\",\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"wetland\",\n            \"type\": \"fill\",\n            \"source\": \"composite\",\n            \"source-layer\": \"landuse_overlay\",\n            \"minzoom\": 5,\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"wetland\",\n                    \"wetland_noveg\"\n                ],\n                true,\n                false\n            ],\n            \"paint\": {\n                \"fill-color\": \"hsl(194, 38%, 74%)\",\n                \"fill-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    10,\n                    0.25,\n                    10.5,\n                    0.15\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"land-and-water\",\n                \"mapbox:group\": \"Land & water, water\",\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"wetland-pattern\",\n            \"type\": \"fill\",\n            \"source\": \"composite\",\n            \"source-layer\": \"landuse_overlay\",\n            \"minzoom\": 5,\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"wetland\",\n                    \"wetland_noveg\"\n                ],\n                true,\n                false\n            ],\n            \"paint\": {\n                \"fill-color\": \"hsl(194, 38%, 74%)\",\n                \"fill-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    10,\n                    0,\n                    10.5,\n                    1\n                ],\n                \"fill-pattern\": \"wetland\",\n                \"fill-translate-anchor\": \"viewport\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"land-and-water\",\n                \"mapbox:group\": \"Land & water, water\",\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"hillshade\",\n            \"type\": \"fill\",\n            \"source\": \"composite\",\n            \"source-layer\": \"hillshade\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"==\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        \"shadow\"\n                    ],\n                    11,\n                    true\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"level\"\n                    ],\n                    89,\n                    true,\n                    78,\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        false,\n                        5,\n                        true\n                    ],\n                    67,\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        false,\n                        9,\n                        true\n                    ],\n                    56,\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        false,\n                        6,\n                        true\n                    ],\n                    94,\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        false,\n                        11,\n                        true\n                    ],\n                    90,\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        false,\n                        12,\n                        true\n                    ],\n                    false\n                ]\n            ],\n            \"minzoom\": 0,\n            \"maxzoom\": 16,\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        \"shadow\",\n                        \"hsla(66, 38%, 17%, 0.08)\",\n                        \"hsla(60, 20%, 95%, 0.14)\"\n                    ],\n                    16,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        \"shadow\",\n                        \"hsla(66, 38%, 17%, 0)\",\n                        \"hsla(60, 20%, 95%, 0)\"\n                    ]\n                ],\n                \"fill-antialias\": false\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"terrain\",\n                \"mapbox:group\": \"Terrain, land\",\n                \"microg:gms-type-feature\": \"landscape.natural.terrain\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"contour-line\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"contour\",\n            \"minzoom\": 11,\n            \"filter\": [\n                \"!=\",\n                [\n                    \"get\",\n                    \"index\"\n                ],\n                -1\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    11,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"index\"\n                        ],\n                        [\n                            1,\n                            2\n                        ],\n                        0.15,\n                        0.3\n                    ],\n                    13,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"index\"\n                        ],\n                        [\n                            1,\n                            2\n                        ],\n                        0.3,\n                        0.5\n                    ]\n                ],\n                \"line-color\": \"hsl(60, 10%, 35%)\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    13,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"index\"\n                        ],\n                        [\n                            1,\n                            2\n                        ],\n                        0.5,\n                        0.6\n                    ],\n                    16,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"index\"\n                        ],\n                        [\n                            1,\n                            2\n                        ],\n                        0.8,\n                        1.2\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"terrain\",\n                \"mapbox:group\": \"Terrain, land\",\n                \"microg:gms-type-feature\": \"landscape.natural.terrain\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"land-structure-polygon\",\n            \"type\": \"fill\",\n            \"source\": \"composite\",\n            \"source-layer\": \"structure\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"land\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"Polygon\"\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": \"hsl(60, 20%, 85%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"land-and-water\",\n                \"mapbox:group\": \"Land & water, built\",\n                \"microg:gms-type-feature\": \"landscape.natural.terrain\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"land-structure-line\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"structure\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"land\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": \"square\"\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.99\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.75,\n                    20,\n                    40\n                ],\n                \"line-color\": \"hsl(60, 20%, 85%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"land-and-water\",\n                \"mapbox:group\": \"Land & water, built\",\n                \"microg:gms-type-feature\": \"landscape.natural.terrain\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"aeroway-polygon\",\n            \"type\": \"fill\",\n            \"source\": \"composite\",\n            \"source-layer\": \"aeroway\",\n            \"minzoom\": 11,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    [\n                        \"runway\",\n                        \"taxiway\",\n                        \"helipad\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"Polygon\"\n                ]\n            ],\n            \"paint\": {\n                \"fill-color\": \"hsl(230, 36%, 74%)\",\n                \"fill-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    10,\n                    0,\n                    11,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"transit\",\n                \"mapbox:group\": \"Transit, built\",\n                \"microg:gms-type-feature\": \"transit.station.airport\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"aeroway-line\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"aeroway\",\n            \"minzoom\": 9,\n            \"filter\": [\n                \"==\",\n                [\n                    \"geometry-type\"\n                ],\n                \"LineString\"\n            ],\n            \"paint\": {\n                \"line-color\": \"hsl(230, 36%, 74%)\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"type\"\n                        ],\n                        \"runway\",\n                        1,\n                        0.5\n                    ],\n                    18,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"type\"\n                        ],\n                        \"runway\",\n                        80,\n                        20\n                    ]\n                ],\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    10,\n                    0,\n                    11,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"transit\",\n                \"mapbox:group\": \"Transit, built\",\n                \"microg:gms-type-feature\": \"transit.station.airport\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"building\",\n            \"type\": \"fill\",\n            \"source\": \"composite\",\n            \"source-layer\": \"building\",\n            \"minzoom\": 15,\n            \"filter\": [\n                \"all\",\n                [\n                    \"!=\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    \"building:part\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"underground\"\n                    ],\n                    \"false\"\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": \"hsl(50, 15%, 75%)\",\n                \"fill-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    0,\n                    16,\n                    1\n                ],\n                \"fill-outline-color\": \"hsl(60, 10%, 65%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"buildings\",\n                \"mapbox:group\": \"Buildings, built\",\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"building-underground\",\n            \"type\": \"fill\",\n            \"source\": \"composite\",\n            \"source-layer\": \"building\",\n            \"minzoom\": 15,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"underground\"\n                    ],\n                    \"true\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"Polygon\"\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": \"hsl(260, 60%, 85%)\",\n                \"fill-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    0,\n                    16,\n                    0.5\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"buildings\",\n                \"mapbox:group\": \"Buildings, built\",\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"tunnel-minor-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"track\"\n                    ],\n                    true,\n                    \"service\",\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        false,\n                        14,\n                        true\n                    ],\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.8,\n                    22,\n                    2\n                ],\n                \"line-color\": \"hsl(60, 3%, 57%)\",\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    18,\n                    10,\n                    22,\n                    100\n                ],\n                \"line-dasharray\": [\n                    3,\n                    3\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, tunnels-case\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"tunnel-street-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"street\",\n                        \"street_limited\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.8,\n                    22,\n                    2\n                ],\n                \"line-color\": \"hsl(60, 3%, 57%)\",\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.5,\n                    18,\n                    20,\n                    22,\n                    200\n                ],\n                \"line-opacity\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    14,\n                    1\n                ],\n                \"line-dasharray\": [\n                    3,\n                    3\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, tunnels-case\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"tunnel-minor-link-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary_link\",\n                        \"secondary_link\",\n                        \"tertiary_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.8,\n                    22,\n                    2\n                ],\n                \"line-color\": \"hsl(60, 10%, 70%)\",\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.4,\n                    18,\n                    18,\n                    22,\n                    180\n                ],\n                \"line-opacity\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    11,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, tunnels-case\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"tunnel-secondary-tertiary-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 11,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"secondary\",\n                        \"tertiary\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    22,\n                    2\n                ],\n                \"line-color\": \"hsl(60, 3%, 57%)\",\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0,\n                    18,\n                    26,\n                    22,\n                    260\n                ],\n                \"line-dasharray\": [\n                    3,\n                    3\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, tunnels-case\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"tunnel-primary-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 10,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"primary\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    22,\n                    2\n                ],\n                \"line-color\": \"hsl(60, 3%, 57%)\",\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0.8,\n                    18,\n                    28,\n                    22,\n                    280\n                ],\n                \"line-dasharray\": [\n                    3,\n                    3\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, tunnels-case\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"tunnel-major-link-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 12,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"motorway_link\",\n                        \"trunk_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.8,\n                    22,\n                    2\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\",\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.8,\n                    18,\n                    20,\n                    22,\n                    200\n                ],\n                \"line-dasharray\": [\n                    3,\n                    3\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, tunnels-case\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"tunnel-motorway-trunk-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"motorway\",\n                        \"trunk\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    22,\n                    2\n                ],\n                \"line-color\": \"hsl(60, 10%, 82%)\",\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0.8,\n                    18,\n                    30,\n                    22,\n                    300\n                ],\n                \"line-dasharray\": [\n                    3,\n                    3\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, tunnels-case\",\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"tunnel-path-trail\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"path\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    [\n                        \"hiking\",\n                        \"mountain_bike\",\n                        \"trail\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    1,\n                    18,\n                    4\n                ],\n                \"line-color\": \"hsl(60, 32%, 90%)\",\n                \"line-dasharray\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            5,\n                            0.5\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            4,\n                            0.5\n                        ]\n                    ],\n                    16,\n                    [\n                        \"literal\",\n                        [\n                            4,\n                            0.45\n                        ]\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., tunnels\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"tunnel-path-cycleway-piste\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 12,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"path\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    [\n                        \"cycleway\",\n                        \"piste\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    1,\n                    18,\n                    4\n                ],\n                \"line-color\": \"hsl(60, 32%, 90%)\",\n                \"line-dasharray\": [\n                    10,\n                    0\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., tunnels\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"tunnel-path\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"path\"\n                ],\n                [\n                    \"!=\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    \"steps\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    1,\n                    18,\n                    4\n                ],\n                \"line-color\": \"hsl(60, 32%, 90%)\",\n                \"line-dasharray\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            1.75,\n                            1\n                        ]\n                    ],\n                    16,\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0.75\n                        ]\n                    ],\n                    17,\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0.5\n                        ]\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., tunnels\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"tunnel-steps\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    \"steps\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    1,\n                    16,\n                    1.6,\n                    18,\n                    6\n                ],\n                \"line-color\": \"hsl(60, 32%, 90%)\",\n                \"line-dasharray\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            1.75,\n                            1\n                        ]\n                    ],\n                    16,\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0.75\n                        ]\n                    ],\n                    17,\n                    [\n                        \"literal\",\n                        [\n                            0.3,\n                            0.3\n                        ]\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., tunnels\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"tunnel-pedestrian\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"pedestrian\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.5,\n                    18,\n                    12\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\",\n                \"line-dasharray\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            1.5,\n                            0.4\n                        ]\n                    ],\n                    16,\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0.2\n                        ]\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., tunnels\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"tunnel-construction\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"construction\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    2,\n                    18,\n                    20,\n                    22,\n                    200\n                ],\n                \"line-color\": \"hsl(60, 10%, 70%)\",\n                \"line-dasharray\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            0.4,\n                            0.8\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            0.3,\n                            0.6\n                        ]\n                    ],\n                    16,\n                    [\n                        \"literal\",\n                        [\n                            0.2,\n                            0.3\n                        ]\n                    ],\n                    17,\n                    [\n                        \"literal\",\n                        [\n                            0.2,\n                            0.25\n                        ]\n                    ],\n                    18,\n                    [\n                        \"literal\",\n                        [\n                            0.15,\n                            0.15\n                        ]\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, tunnels\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"tunnel-minor\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"track\"\n                    ],\n                    true,\n                    \"service\",\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        false,\n                        14,\n                        true\n                    ],\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    18,\n                    10,\n                    22,\n                    100\n                ],\n                \"line-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"street_limited\",\n                    \"hsl(60, 22%, 80%)\",\n                    \"hsl(0, 0%, 95%)\"\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, tunnels\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"tunnel-minor-link\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary_link\",\n                        \"secondary_link\",\n                        \"tertiary_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    13,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    13,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.4,\n                    18,\n                    18,\n                    22,\n                    180\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, tunnels\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"tunnel-major-link\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 12,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"motorway_link\",\n                        \"trunk_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.8,\n                    18,\n                    20,\n                    22,\n                    200\n                ],\n                \"line-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"motorway_link\",\n                    \"hsl(15, 100%, 85%)\",\n                    \"hsl(35, 78%, 85%)\"\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, tunnels\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"tunnel-street\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"street\",\n                        \"street_limited\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.5,\n                    18,\n                    20,\n                    22,\n                    200\n                ],\n                \"line-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"street_limited\",\n                    \"hsl(60, 22%, 80%)\",\n                    \"hsl(0, 0%, 95%)\"\n                ],\n                \"line-opacity\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    14,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, tunnels\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"tunnel-street-low\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"maxzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"street\",\n                        \"street_limited\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.5,\n                    18,\n                    20,\n                    22,\n                    200\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, tunnels\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"tunnel-secondary-tertiary\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"secondary\",\n                        \"tertiary\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0,\n                    18,\n                    26,\n                    22,\n                    260\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, tunnels\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"tunnel-primary\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"primary\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0.8,\n                    18,\n                    28,\n                    22,\n                    280\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, tunnels\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"tunnel-motorway-trunk\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"motorway\",\n                        \"trunk\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0.8,\n                    18,\n                    30,\n                    22,\n                    300\n                ],\n                \"line-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"motorway\",\n                    \"hsl(15, 100%, 85%)\",\n                    \"hsl(35, 78%, 85%)\"\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, tunnels\",\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"tunnel-oneway-arrow-blue\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 16,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"oneway\"\n                    ],\n                    \"true\"\n                ],\n                [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"primary\",\n                            \"secondary\",\n                            \"street\",\n                            \"street_limited\",\n                            \"tertiary\"\n                        ],\n                        true,\n                        false\n                    ],\n                    16,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"primary\",\n                            \"secondary\",\n                            \"tertiary\",\n                            \"street\",\n                            \"street_limited\",\n                            \"primary_link\",\n                            \"secondary_link\",\n                            \"tertiary_link\",\n                            \"service\",\n                            \"track\"\n                        ],\n                        true,\n                        false\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"symbol-placement\": \"line\",\n                \"icon-image\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"oneway-small\",\n                    18,\n                    \"oneway-large\"\n                ],\n                \"symbol-spacing\": 200,\n                \"icon-rotation-alignment\": \"map\",\n                \"icon-allow-overlap\": true,\n                \"icon-ignore-placement\": true\n            },\n            \"paint\": {},\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, tunnels\",\n                \"microg:gms-type-feature\": \"road\",\n                \"microg:gms-type-element\": \"labels.icon\"\n            }\n        },\n        {\n            \"id\": \"tunnel-oneway-arrow-white\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 16,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"motorway\",\n                        \"motorway_link\",\n                        \"trunk\",\n                        \"trunk_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"oneway\"\n                    ],\n                    \"true\"\n                ]\n            ],\n            \"layout\": {\n                \"symbol-placement\": \"line\",\n                \"icon-image\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"oneway-white-small\",\n                    18,\n                    \"oneway-white-large\"\n                ],\n                \"symbol-spacing\": 200,\n                \"icon-rotation-alignment\": \"map\",\n                \"icon-allow-overlap\": true,\n                \"icon-ignore-placement\": true\n            },\n            \"paint\": {},\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, tunnels\",\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"labels.icon\"\n            }\n        },\n        {\n            \"id\": \"cliff\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"structure\",\n            \"minzoom\": 15,\n            \"filter\": [\n                \"==\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                \"cliff\"\n            ],\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    0,\n                    15.25,\n                    1\n                ],\n                \"line-width\": 10,\n                \"line-pattern\": \"cliff\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"terrain\",\n                \"mapbox:group\": \"Terrain, surface\",\n                \"microg:gms-type-feature\": \"landscape.natural.terrain\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"ferry\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 8,\n            \"filter\": [\n                \"==\",\n                [\n                    \"get\",\n                    \"type\"\n                ],\n                \"ferry\"\n            ],\n            \"paint\": {\n                \"line-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    \"hsl(214, 68%, 63%)\",\n                    17,\n                    \"hsl(239, 68%, 63%)\"\n                ],\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.5,\n                    20,\n                    1\n                ],\n                \"line-dasharray\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0\n                        ]\n                    ],\n                    13,\n                    [\n                        \"literal\",\n                        [\n                            12,\n                            4\n                        ]\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"transit\",\n                \"mapbox:group\": \"Transit, ferries\",\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"ferry-auto\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 8,\n            \"filter\": [\n                \"==\",\n                [\n                    \"get\",\n                    \"type\"\n                ],\n                \"ferry_auto\"\n            ],\n            \"paint\": {\n                \"line-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    \"hsl(214, 68%, 63%)\",\n                    17,\n                    \"hsl(239, 68%, 63%)\"\n                ],\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.5,\n                    20,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"transit\",\n                \"mapbox:group\": \"Transit, ferries\",\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"road-pedestrian-polygon-fill\",\n            \"type\": \"fill\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"path\",\n                        \"pedestrian\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"case\",\n                    [\n                        \"has\",\n                        \"layer\"\n                    ],\n                    [\n                        \">=\",\n                        [\n                            \"get\",\n                            \"layer\"\n                        ],\n                        0\n                    ],\n                    true\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"Polygon\"\n                ]\n            ],\n            \"paint\": {\n                \"fill-color\": \"hsl(60, 20%, 85%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"road-pedestrian-polygon-pattern\",\n            \"type\": \"fill\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 16,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"path\",\n                        \"pedestrian\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"case\",\n                    [\n                        \"has\",\n                        \"layer\"\n                    ],\n                    [\n                        \">=\",\n                        [\n                            \"get\",\n                            \"layer\"\n                        ],\n                        0\n                    ],\n                    true\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"Polygon\"\n                ]\n            ],\n            \"paint\": {\n                \"fill-pattern\": \"pedestrian-polygon\",\n                \"fill-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    16,\n                    0,\n                    17,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"road-path-bg\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 12,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"path\"\n                ],\n                [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"!\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"type\"\n                            ],\n                            [\n                                \"steps\",\n                                \"sidewalk\",\n                                \"crossing\"\n                            ],\n                            true,\n                            false\n                        ]\n                    ],\n                    16,\n                    [\n                        \"!=\",\n                        [\n                            \"get\",\n                            \"type\"\n                        ],\n                        \"steps\"\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    2,\n                    18,\n                    7\n                ],\n                \"line-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    \"piste\",\n                    \"hsl(215, 80%, 48%)\",\n                    [\n                        \"mountain_bike\",\n                        \"hiking\",\n                        \"trail\",\n                        \"cycleway\",\n                        \"footway\",\n                        \"path\",\n                        \"bridleway\"\n                    ],\n                    \"hsl(35, 80%, 48%)\",\n                    \"hsl(60, 1%, 64%)\"\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"road-steps-bg\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    \"steps\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    2,\n                    17,\n                    4.6,\n                    18,\n                    7\n                ],\n                \"line-color\": \"hsl(35, 80%, 48%)\",\n                \"line-opacity\": 0.75\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"road-pedestrian-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"pedestrian\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"case\",\n                    [\n                        \"has\",\n                        \"layer\"\n                    ],\n                    [\n                        \">=\",\n                        [\n                            \"get\",\n                            \"layer\"\n                        ],\n                        0\n                    ],\n                    true\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    2,\n                    18,\n                    14.5\n                ],\n                \"line-color\": \"hsl(60, 10%, 70%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"road-path-trail\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 12,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"path\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    [\n                        \"hiking\",\n                        \"mountain_bike\",\n                        \"trail\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    1,\n                    18,\n                    4\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\",\n                \"line-dasharray\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            5,\n                            0.5\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            4,\n                            0.5\n                        ]\n                    ],\n                    16,\n                    [\n                        \"literal\",\n                        [\n                            4,\n                            0.45\n                        ]\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"road-path-cycleway-piste\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 12,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"path\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    [\n                        \"cycleway\",\n                        \"piste\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    1,\n                    18,\n                    4\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\",\n                \"line-dasharray\": [\n                    10,\n                    0\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"road-path\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 12,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"path\"\n                ],\n                [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"!\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"type\"\n                            ],\n                            [\n                                \"steps\",\n                                \"sidewalk\",\n                                \"crossing\"\n                            ],\n                            true,\n                            false\n                        ]\n                    ],\n                    16,\n                    [\n                        \"!=\",\n                        [\n                            \"get\",\n                            \"type\"\n                        ],\n                        \"steps\"\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    13,\n                    0.5,\n                    14,\n                    1,\n                    15,\n                    1,\n                    18,\n                    4\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\",\n                \"line-dasharray\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            4,\n                            0.3\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            1.75,\n                            0.3\n                        ]\n                    ],\n                    16,\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0.3\n                        ]\n                    ],\n                    17,\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0.25\n                        ]\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"road-steps\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    \"steps\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    1,\n                    16,\n                    1.6,\n                    18,\n                    6\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\",\n                \"line-dasharray\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            1.75,\n                            1\n                        ]\n                    ],\n                    16,\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0.75\n                        ]\n                    ],\n                    17,\n                    [\n                        \"literal\",\n                        [\n                            0.3,\n                            0.3\n                        ]\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"road-pedestrian\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 12,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"pedestrian\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"case\",\n                    [\n                        \"has\",\n                        \"layer\"\n                    ],\n                    [\n                        \">=\",\n                        [\n                            \"get\",\n                            \"layer\"\n                        ],\n                        0\n                    ],\n                    true\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.5,\n                    18,\n                    12\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\",\n                \"line-dasharray\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            1.5,\n                            0.4\n                        ]\n                    ],\n                    16,\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0.2\n                        ]\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"golf-hole-line\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 16,\n            \"filter\": [\n                \"==\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                \"golf\"\n            ],\n            \"paint\": {\n                \"line-color\": \"hsl(98, 26%, 56%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., surface\",\n                \"microg:gms-type-feature\": \"poi.attraction\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"road-polygon\",\n            \"type\": \"fill\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 12,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary\",\n                        \"secondary\",\n                        \"tertiary\",\n                        \"primary_link\",\n                        \"secondary_link\",\n                        \"tertiary_link\",\n                        \"trunk\",\n                        \"trunk_link\",\n                        \"street\",\n                        \"street_limited\",\n                        \"track\",\n                        \"service\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"Polygon\"\n                ]\n            ],\n            \"paint\": {\n                \"fill-color\": \"hsl(0, 0%, 95%)\",\n                \"fill-outline-color\": \"hsl(60, 10%, 70%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface\",\n                \"microg:gms-type-feature\": \"road\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"turning-feature-outline\",\n            \"type\": \"circle\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 15,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"turning_circle\",\n                        \"turning_loop\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"Point\"\n                ]\n            ],\n            \"paint\": {\n                \"circle-radius\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    4.5,\n                    16,\n                    8,\n                    18,\n                    20,\n                    22,\n                    200\n                ],\n                \"circle-color\": \"hsl(0, 0%, 95%)\",\n                \"circle-stroke-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    0.8,\n                    16,\n                    1.2,\n                    18,\n                    2\n                ],\n                \"circle-stroke-color\": \"hsl(60, 10%, 70%)\",\n                \"circle-pitch-alignment\": \"map\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface\",\n                \"microg:gms-type-feature\": \"road\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"road-minor-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"track\"\n                    ],\n                    true,\n                    \"service\",\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        false,\n                        14,\n                        true\n                    ],\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.8,\n                    22,\n                    2\n                ],\n                \"line-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"track\",\n                    \"hsl(35, 80%, 48%)\",\n                    \"hsl(60, 10%, 70%)\"\n                ],\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    18,\n                    10,\n                    22,\n                    100\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"road-street-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"street\",\n                        \"street_limited\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.8,\n                    22,\n                    2\n                ],\n                \"line-color\": \"hsl(60, 10%, 70%)\",\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.5,\n                    18,\n                    20,\n                    22,\n                    200\n                ],\n                \"line-opacity\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    14,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"road-minor-link-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary_link\",\n                        \"secondary_link\",\n                        \"tertiary_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.8,\n                    22,\n                    2\n                ],\n                \"line-color\": \"hsl(60, 10%, 70%)\",\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.4,\n                    18,\n                    18,\n                    22,\n                    180\n                ],\n                \"line-opacity\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    11,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"road-secondary-tertiary-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 11,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"secondary\",\n                        \"tertiary\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.8,\n                    22,\n                    2\n                ],\n                \"line-color\": \"hsl(60, 10%, 70%)\",\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0,\n                    18,\n                    26,\n                    22,\n                    260\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"road-primary-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 10,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"primary\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    22,\n                    2\n                ],\n                \"line-color\": \"hsl(60, 10%, 70%)\",\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0.8,\n                    18,\n                    28,\n                    22,\n                    280\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"road-major-link-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 12,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"motorway_link\",\n                        \"trunk_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.8,\n                    22,\n                    2\n                ],\n                \"line-color\": \"hsl(60, 10%, 82%)\",\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.8,\n                    18,\n                    20,\n                    22,\n                    200\n                ],\n                \"line-opacity\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    11,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"road-motorway-trunk-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 3,\n            \"filter\": [\n                \"all\",\n                [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"motorway\",\n                            \"trunk\"\n                        ],\n                        true,\n                        false\n                    ],\n                    5,\n                    [\n                        \"all\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ],\n                            [\n                                \"motorway\",\n                                \"trunk\"\n                            ],\n                            true,\n                            false\n                        ],\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"structure\"\n                            ],\n                            [\n                                \"none\",\n                                \"ford\"\n                            ],\n                            true,\n                            false\n                        ]\n                    ]\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    22,\n                    2\n                ],\n                \"line-color\": \"hsl(60, 10%, 82%)\",\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0.8,\n                    18,\n                    30,\n                    22,\n                    300\n                ],\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0,\n                    3.5,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface\",\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"turning-feature\",\n            \"type\": \"circle\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 15,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"turning_circle\",\n                        \"turning_loop\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"Point\"\n                ]\n            ],\n            \"paint\": {\n                \"circle-radius\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    4.5,\n                    16,\n                    8,\n                    18,\n                    20,\n                    22,\n                    200\n                ],\n                \"circle-color\": \"hsl(0, 0%, 95%)\",\n                \"circle-pitch-alignment\": \"map\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface\",\n                \"microg:gms-type-feature\": \"road\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"road-construction\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"construction\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    2,\n                    18,\n                    20,\n                    22,\n                    200\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\",\n                \"line-dasharray\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            0.4,\n                            0.8\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            0.3,\n                            0.6\n                        ]\n                    ],\n                    16,\n                    [\n                        \"literal\",\n                        [\n                            0.2,\n                            0.3\n                        ]\n                    ],\n                    17,\n                    [\n                        \"literal\",\n                        [\n                            0.2,\n                            0.25\n                        ]\n                    ],\n                    18,\n                    [\n                        \"literal\",\n                        [\n                            0.15,\n                            0.15\n                        ]\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"road-minor\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"track\"\n                    ],\n                    true,\n                    \"service\",\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        false,\n                        14,\n                        true\n                    ],\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    18,\n                    10,\n                    22,\n                    100\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"road-minor-link\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 12,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary_link\",\n                        \"secondary_link\",\n                        \"tertiary_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    13,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    13,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.4,\n                    18,\n                    18,\n                    22,\n                    180\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"road-major-link\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 12,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"motorway_link\",\n                        \"trunk_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    13,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    13,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.8,\n                    18,\n                    20,\n                    22,\n                    200\n                ],\n                \"line-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"motorway_link\",\n                    \"hsl(15, 100%, 75%)\",\n                    \"hsl(35, 89%, 75%)\"\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"road-street\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"street\",\n                        \"street_limited\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.5,\n                    18,\n                    20,\n                    22,\n                    200\n                ],\n                \"line-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"street_limited\",\n                    \"hsl(60, 22%, 80%)\",\n                    \"hsl(0, 0%, 95%)\"\n                ],\n                \"line-opacity\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    14,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"road-street-low\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 11,\n            \"maxzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"street\",\n                        \"street_limited\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.5,\n                    18,\n                    20,\n                    22,\n                    200\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"road-secondary-tertiary\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 9,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"secondary\",\n                        \"tertiary\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0,\n                    18,\n                    26,\n                    22,\n                    260\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"road-primary\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 6,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"primary\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0.8,\n                    18,\n                    28,\n                    22,\n                    280\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"road-motorway-trunk\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 3,\n            \"filter\": [\n                \"all\",\n                [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"motorway\",\n                            \"trunk\"\n                        ],\n                        true,\n                        false\n                    ],\n                    5,\n                    [\n                        \"all\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ],\n                            [\n                                \"motorway\",\n                                \"trunk\"\n                            ],\n                            true,\n                            false\n                        ],\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"structure\"\n                            ],\n                            [\n                                \"none\",\n                                \"ford\"\n                            ],\n                            true,\n                            false\n                        ]\n                    ]\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    13,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    13,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0.8,\n                    18,\n                    30,\n                    22,\n                    300\n                ],\n                \"line-color\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        \"motorway\",\n                        \"hsl(15, 88%, 69%)\",\n                        \"trunk\",\n                        \"hsl(35, 81%, 59%)\",\n                        \"hsl(60, 18%, 85%)\"\n                    ],\n                    9,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        \"motorway\",\n                        \"hsl(15, 100%, 75%)\",\n                        \"hsl(35, 89%, 75%)\"\n                    ]\n                ],\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0,\n                    3.5,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface\",\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"road-rail\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"major_rail\",\n                        \"minor_rail\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"paint\": {\n                \"line-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    13,\n                    \"hsl(75, 25%, 68%)\",\n                    16,\n                    \"hsl(60, 0%, 56%)\"\n                ],\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.5,\n                    20,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"transit\",\n                \"mapbox:group\": \"Transit, surface\",\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"road-rail-tracks\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"major_rail\",\n                        \"minor_rail\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"paint\": {\n                \"line-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    13,\n                    \"hsl(75, 25%, 68%)\",\n                    16,\n                    \"hsl(60, 0%, 56%)\"\n                ],\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    4,\n                    20,\n                    8\n                ],\n                \"line-dasharray\": [\n                    0.1,\n                    15\n                ],\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    13.75,\n                    0,\n                    14,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"transit\",\n                \"mapbox:group\": \"Transit, surface\",\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"level-crossing\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 16,\n            \"filter\": [\n                \"==\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                \"level_crossing\"\n            ],\n            \"layout\": {\n                \"icon-image\": \"level-crossing\",\n                \"icon-rotation-alignment\": \"map\",\n                \"icon-allow-overlap\": true,\n                \"icon-ignore-placement\": true\n            },\n            \"paint\": {},\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface-icons\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"labels.icon\"\n            }\n        },\n        {\n            \"id\": \"road-oneway-arrow-blue\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 16,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"oneway\"\n                    ],\n                    \"true\"\n                ],\n                [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"primary\",\n                            \"secondary\",\n                            \"tertiary\",\n                            \"street\",\n                            \"street_limited\"\n                        ],\n                        true,\n                        false\n                    ],\n                    16,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"primary\",\n                            \"secondary\",\n                            \"tertiary\",\n                            \"street\",\n                            \"street_limited\",\n                            \"primary_link\",\n                            \"secondary_link\",\n                            \"tertiary_link\",\n                            \"service\",\n                            \"track\"\n                        ],\n                        true,\n                        false\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"symbol-placement\": \"line\",\n                \"icon-image\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"oneway-small\",\n                    18,\n                    \"oneway-large\"\n                ],\n                \"symbol-spacing\": 200,\n                \"icon-rotation-alignment\": \"map\",\n                \"icon-allow-overlap\": true,\n                \"icon-ignore-placement\": true\n            },\n            \"paint\": {},\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface-icons\",\n                \"microg:gms-type-feature\": \"road\",\n                \"microg:gms-type-element\": \"labels.icon\"\n            }\n        },\n        {\n            \"id\": \"road-oneway-arrow-white\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 16,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"oneway\"\n                    ],\n                    \"true\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"motorway\",\n                        \"trunk\",\n                        \"motorway_link\",\n                        \"trunk_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"symbol-placement\": \"line\",\n                \"icon-image\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"oneway-white-small\",\n                    18,\n                    \"oneway-white-large\"\n                ],\n                \"symbol-spacing\": 200,\n                \"icon-rotation-alignment\": \"map\",\n                \"icon-allow-overlap\": true,\n                \"icon-ignore-placement\": true\n            },\n            \"paint\": {},\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface-icons\",\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"labels.icon\"\n            }\n        },\n        {\n            \"id\": \"crosswalks\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"structure\",\n            \"minzoom\": 17,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    \"crosswalk\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"Point\"\n                ]\n            ],\n            \"layout\": {\n                \"icon-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    16,\n                    0.1,\n                    18,\n                    0.2,\n                    19,\n                    0.5,\n                    22,\n                    1.5\n                ],\n                \"icon-image\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"crosswalk-small\",\n                    18,\n                    \"crosswalk-large\"\n                ],\n                \"icon-rotate\": [\n                    \"get\",\n                    \"direction\"\n                ],\n                \"icon-rotation-alignment\": \"map\",\n                \"icon-allow-overlap\": true,\n                \"icon-ignore-placement\": true\n            },\n            \"paint\": {},\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface-icons\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"labels.icon\"\n            }\n        },\n        {\n            \"id\": \"gate-fence-hedge\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"structure\",\n            \"minzoom\": 16,\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"gate\",\n                    \"fence\",\n                    \"hedge\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"hedge\",\n                    \"hsl(98, 32%, 56%)\",\n                    \"hsl(60, 25%, 63%)\"\n                ],\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    16,\n                    1,\n                    20,\n                    3\n                ],\n                \"line-opacity\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"gate\",\n                    0.5,\n                    1\n                ],\n                \"line-dasharray\": [\n                    1,\n                    2,\n                    5,\n                    2,\n                    1,\n                    2\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., barriers-bridges\",\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"bridge-path-bg\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"path\"\n                ],\n                [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"!\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"type\"\n                            ],\n                            [\n                                \"steps\",\n                                \"sidewalk\",\n                                \"crossing\"\n                            ],\n                            true,\n                            false\n                        ]\n                    ],\n                    16,\n                    [\n                        \"!=\",\n                        [\n                            \"get\",\n                            \"type\"\n                        ],\n                        \"steps\"\n                    ]\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    2,\n                    18,\n                    7\n                ],\n                \"line-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    \"piste\",\n                    \"hsl(215, 80%, 48%)\",\n                    [\n                        \"mountain_bike\",\n                        \"hiking\",\n                        \"trail\",\n                        \"cycleway\",\n                        \"footway\",\n                        \"path\",\n                        \"bridleway\"\n                    ],\n                    \"hsl(35, 80%, 48%)\",\n                    \"hsl(60, 1%, 64%)\"\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., barriers-bridges\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"bridge-steps-bg\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    \"steps\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    2,\n                    17,\n                    4.6,\n                    18,\n                    7\n                ],\n                \"line-color\": \"hsl(35, 80%, 48%)\",\n                \"line-opacity\": 0.75\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., barriers-bridges\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"bridge-pedestrian-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"pedestrian\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    2,\n                    18,\n                    14.5\n                ],\n                \"line-color\": \"hsl(60, 10%, 70%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., barriers-bridges\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"bridge-path-trail\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"path\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    [\n                        \"hiking\",\n                        \"mountain_bike\",\n                        \"trail\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    1,\n                    18,\n                    4\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\",\n                \"line-dasharray\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            5,\n                            0.5\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            4,\n                            0.5\n                        ]\n                    ],\n                    16,\n                    [\n                        \"literal\",\n                        [\n                            4,\n                            0.45\n                        ]\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., barriers-bridges\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"bridge-path-cycleway-piste\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"path\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    [\n                        \"cycleway\",\n                        \"piste\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    1,\n                    18,\n                    4\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\",\n                \"line-dasharray\": [\n                    10,\n                    0\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., barriers-bridges\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"bridge-path\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"path\"\n                ],\n                [\n                    \"!=\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    \"steps\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    1,\n                    18,\n                    4\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\",\n                \"line-dasharray\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            4,\n                            0.3\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            1.75,\n                            0.3\n                        ]\n                    ],\n                    16,\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0.3\n                        ]\n                    ],\n                    17,\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0.25\n                        ]\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., barriers-bridges\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"bridge-steps\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    \"steps\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    1,\n                    16,\n                    1.6,\n                    18,\n                    6\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\",\n                \"line-dasharray\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            1.75,\n                            1\n                        ]\n                    ],\n                    16,\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0.75\n                        ]\n                    ],\n                    17,\n                    [\n                        \"literal\",\n                        [\n                            0.3,\n                            0.3\n                        ]\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., barriers-bridges\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"bridge-pedestrian\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"pedestrian\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.5,\n                    18,\n                    12\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\",\n                \"line-dasharray\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            1.5,\n                            0.4\n                        ]\n                    ],\n                    16,\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0.2\n                        ]\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., barriers-bridges\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"gate-label\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"structure\",\n            \"minzoom\": 16,\n            \"filter\": [\n                \"==\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                \"gate\"\n            ],\n            \"layout\": {\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    \"gate\",\n                    \"gate\",\n                    \"lift_gate\",\n                    \"lift-gate\",\n                    \"\"\n                ]\n            },\n            \"paint\": {},\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., barriers-bridges\",\n                \"microg:gms-type-feature\": \"road\",\n                \"microg:gms-type-element\": \"labels.icon\"\n            }\n        },\n        {\n            \"id\": \"bridge-minor-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"track\"\n                    ],\n                    true,\n                    \"service\",\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        false,\n                        14,\n                        true\n                    ],\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.8,\n                    22,\n                    2\n                ],\n                \"line-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"track\",\n                    \"hsl(35, 80%, 48%)\",\n                    \"hsl(60, 10%, 70%)\"\n                ],\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    18,\n                    10,\n                    22,\n                    100\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"bridge-street-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"street\",\n                        \"street_limited\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.8,\n                    22,\n                    2\n                ],\n                \"line-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"track\",\n                    \"hsl(35, 80%, 48%)\",\n                    \"hsl(60, 10%, 70%)\"\n                ],\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.5,\n                    18,\n                    20,\n                    22,\n                    200\n                ],\n                \"line-opacity\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    14,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"bridge-minor-link-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary_link\",\n                        \"secondary_link\",\n                        \"tertiary_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.8,\n                    22,\n                    2\n                ],\n                \"line-color\": \"hsl(60, 10%, 70%)\",\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.4,\n                    18,\n                    18,\n                    22,\n                    180\n                ],\n                \"line-opacity\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    11,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"bridge-secondary-tertiary-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 11,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"secondary\",\n                        \"tertiary\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    22,\n                    2\n                ],\n                \"line-color\": \"hsl(60, 10%, 70%)\",\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0,\n                    18,\n                    26,\n                    22,\n                    260\n                ],\n                \"line-opacity\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    10,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"bridge-primary-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 10,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"primary\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    22,\n                    2\n                ],\n                \"line-color\": \"hsl(60, 10%, 70%)\",\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0.8,\n                    18,\n                    28,\n                    22,\n                    280\n                ],\n                \"line-opacity\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    10,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"bridge-major-link-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 12,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"motorway_link\",\n                        \"trunk_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"layer\"\n                    ],\n                    1\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.8,\n                    22,\n                    2\n                ],\n                \"line-color\": \"hsl(60, 10%, 82%)\",\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.8,\n                    18,\n                    20,\n                    22,\n                    200\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"bridge-motorway-trunk-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"motorway\",\n                        \"trunk\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"layer\"\n                    ],\n                    1\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    22,\n                    2\n                ],\n                \"line-color\": \"hsl(60, 10%, 82%)\",\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0.8,\n                    18,\n                    30,\n                    22,\n                    300\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"bridge-construction\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"construction\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    2,\n                    18,\n                    20,\n                    22,\n                    200\n                ],\n                \"line-color\": \"hsl(60, 10%, 70%)\",\n                \"line-dasharray\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            0.4,\n                            0.8\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            0.3,\n                            0.6\n                        ]\n                    ],\n                    16,\n                    [\n                        \"literal\",\n                        [\n                            0.2,\n                            0.3\n                        ]\n                    ],\n                    17,\n                    [\n                        \"literal\",\n                        [\n                            0.2,\n                            0.25\n                        ]\n                    ],\n                    18,\n                    [\n                        \"literal\",\n                        [\n                            0.15,\n                            0.15\n                        ]\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"bridge-minor\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"track\"\n                    ],\n                    true,\n                    \"service\",\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        false,\n                        14,\n                        true\n                    ],\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    18,\n                    10,\n                    22,\n                    100\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"bridge-minor-link\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary_link\",\n                        \"secondary_link\",\n                        \"tertiary_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.4,\n                    18,\n                    18,\n                    22,\n                    180\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"bridge-major-link\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 12,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"motorway_link\",\n                        \"trunk_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"layer\"\n                    ],\n                    1\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    13,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.8,\n                    18,\n                    20,\n                    22,\n                    200\n                ],\n                \"line-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"motorway_link\",\n                    \"hsl(15, 100%, 75%)\",\n                    \"hsl(35, 89%, 75%)\"\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"bridge-street\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"street\",\n                        \"street_limited\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.5,\n                    18,\n                    20,\n                    22,\n                    200\n                ],\n                \"line-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"street_limited\",\n                    \"hsl(60, 22%, 80%)\",\n                    \"hsl(0, 0%, 95%)\"\n                ],\n                \"line-opacity\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    14,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"bridge-street-low\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"maxzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"street\",\n                        \"street_limited\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.5,\n                    18,\n                    20,\n                    22,\n                    200\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"bridge-secondary-tertiary\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"secondary\",\n                        \"tertiary\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0,\n                    18,\n                    26,\n                    22,\n                    260\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"bridge-primary\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"primary\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0.8,\n                    18,\n                    28,\n                    22,\n                    280\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"bridge-motorway-trunk\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"motorway\",\n                        \"trunk\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"layer\"\n                    ],\n                    1\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0.8,\n                    18,\n                    30,\n                    22,\n                    300\n                ],\n                \"line-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"motorway\",\n                    \"hsl(15, 100%, 75%)\",\n                    \"hsl(35, 89%, 75%)\"\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"bridge-major-link-2-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 12,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \">=\",\n                    [\n                        \"get\",\n                        \"layer\"\n                    ],\n                    2\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"motorway_link\",\n                        \"trunk_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.8,\n                    22,\n                    2\n                ],\n                \"line-color\": \"hsl(60, 10%, 82%)\",\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.8,\n                    18,\n                    20,\n                    22,\n                    200\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"bridge-motorway-trunk-2-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \">=\",\n                    [\n                        \"get\",\n                        \"layer\"\n                    ],\n                    2\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"motorway\",\n                        \"trunk\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    22,\n                    2\n                ],\n                \"line-color\": \"hsl(60, 10%, 82%)\",\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0.8,\n                    18,\n                    30,\n                    22,\n                    300\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"bridge-major-link-2\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 12,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \">=\",\n                    [\n                        \"get\",\n                        \"layer\"\n                    ],\n                    2\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"motorway_link\",\n                        \"trunk_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    13,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.8,\n                    18,\n                    20,\n                    22,\n                    200\n                ],\n                \"line-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"motorway_link\",\n                    \"hsl(15, 100%, 75%)\",\n                    \"hsl(35, 89%, 75%)\"\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"bridge-motorway-trunk-2\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \">=\",\n                    [\n                        \"get\",\n                        \"layer\"\n                    ],\n                    2\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"motorway\",\n                        \"trunk\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0.8,\n                    18,\n                    30,\n                    22,\n                    300\n                ],\n                \"line-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"motorway\",\n                    \"hsl(15, 100%, 75%)\",\n                    \"hsl(35, 89%, 75%)\"\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"bridge-oneway-arrow-blue\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 16,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"oneway\"\n                    ],\n                    \"true\"\n                ],\n                [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"primary\",\n                            \"secondary\",\n                            \"tertiary\",\n                            \"street\",\n                            \"street_limited\"\n                        ],\n                        true,\n                        false\n                    ],\n                    16,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"primary\",\n                            \"secondary\",\n                            \"tertiary\",\n                            \"street\",\n                            \"street_limited\",\n                            \"primary_link\",\n                            \"secondary_link\",\n                            \"tertiary_link\",\n                            \"service\",\n                            \"track\"\n                        ],\n                        true,\n                        false\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"symbol-placement\": \"line\",\n                \"icon-image\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"oneway-small\",\n                    18,\n                    \"oneway-large\"\n                ],\n                \"symbol-spacing\": 200,\n                \"icon-rotation-alignment\": \"map\",\n                \"icon-allow-overlap\": true,\n                \"icon-ignore-placement\": true\n            },\n            \"paint\": {},\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road\",\n                \"microg:gms-type-element\": \"labels.icon\"\n            }\n        },\n        {\n            \"id\": \"bridge-oneway-arrow-white\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 16,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"motorway\",\n                        \"trunk\",\n                        \"motorway_link\",\n                        \"trunk_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"oneway\"\n                    ],\n                    \"true\"\n                ]\n            ],\n            \"layout\": {\n                \"symbol-placement\": \"line\",\n                \"icon-image\": \"oneway-white-small\",\n                \"symbol-spacing\": 200,\n                \"icon-rotation-alignment\": \"map\",\n                \"icon-allow-overlap\": true,\n                \"icon-ignore-placement\": true\n            },\n            \"paint\": {},\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"labels.icon\"\n            }\n        },\n        {\n            \"id\": \"bridge-rail\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"major_rail\",\n                        \"minor_rail\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"paint\": {\n                \"line-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    13,\n                    \"hsl(75, 25%, 68%)\",\n                    16,\n                    \"hsl(60, 0%, 56%)\"\n                ],\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.5,\n                    20,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"transit\",\n                \"mapbox:group\": \"Transit, bridges\",\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"bridge-rail-tracks\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"major_rail\",\n                        \"minor_rail\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"paint\": {\n                \"line-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    13,\n                    \"hsl(75, 25%, 68%)\",\n                    16,\n                    \"hsl(60, 0%, 56%)\"\n                ],\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    4,\n                    20,\n                    8\n                ],\n                \"line-dasharray\": [\n                    0.1,\n                    15\n                ],\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    13.75,\n                    0,\n                    14,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"transit\",\n                \"mapbox:group\": \"Transit, bridges\",\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"aerialway\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 12,\n            \"filter\": [\n                \"==\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                \"aerialway\"\n            ],\n            \"paint\": {\n                \"line-color\": \"hsl(230, 50%, 60%)\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    20,\n                    2\n                ],\n                \"line-dasharray\": [\n                    4,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"transit\",\n                \"mapbox:group\": \"Transit, elevated\",\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"admin-1-boundary-bg\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"admin\",\n            \"minzoom\": 7,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"admin_level\"\n                    ],\n                    1\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"maritime\"\n                    ],\n                    \"false\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"worldview\"\n                    ],\n                    [\n                        \"all\",\n                        \"US\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"paint\": {\n                \"line-color\": \"hsl(350, 90%, 88%)\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    3,\n                    12,\n                    6\n                ],\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    7,\n                    0,\n                    8,\n                    0.5\n                ],\n                \"line-dasharray\": [\n                    1,\n                    0\n                ],\n                \"line-blur\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0,\n                    12,\n                    3\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"admin-boundaries\",\n                \"mapbox:group\": \"Administrative boundaries, admin\",\n                \"microg:gms-type-feature\": \"administrative.province\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"admin-0-boundary-bg\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"admin\",\n            \"minzoom\": 1,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"admin_level\"\n                    ],\n                    0\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"maritime\"\n                    ],\n                    \"false\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"worldview\"\n                    ],\n                    [\n                        \"all\",\n                        \"US\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    4,\n                    12,\n                    8\n                ],\n                \"line-color\": \"hsl(350, 90%, 88%)\",\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0,\n                    4,\n                    0.5\n                ],\n                \"line-blur\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0,\n                    12,\n                    2\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"admin-boundaries\",\n                \"mapbox:group\": \"Administrative boundaries, admin\",\n                \"microg:gms-type-feature\": \"administrative.country\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"admin-1-boundary\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"admin\",\n            \"minzoom\": 2,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"admin_level\"\n                    ],\n                    1\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"maritime\"\n                    ],\n                    \"false\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"worldview\"\n                    ],\n                    [\n                        \"all\",\n                        \"US\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-dasharray\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            2,\n                            0\n                        ]\n                    ],\n                    7,\n                    [\n                        \"literal\",\n                        [\n                            2,\n                            2,\n                            6,\n                            2\n                        ]\n                    ]\n                ],\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0.3,\n                    12,\n                    1.5\n                ],\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    2,\n                    0,\n                    3,\n                    1\n                ],\n                \"line-color\": \"hsl(350, 30%, 55%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"admin-boundaries\",\n                \"mapbox:group\": \"Administrative boundaries, admin\",\n                \"microg:gms-type-feature\": \"administrative.province\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"admin-0-boundary\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"admin\",\n            \"minzoom\": 1,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"admin_level\"\n                    ],\n                    0\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"disputed\"\n                    ],\n                    \"false\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"maritime\"\n                    ],\n                    \"false\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"worldview\"\n                    ],\n                    [\n                        \"all\",\n                        \"US\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsl(350, 30%, 50%)\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0.5,\n                    12,\n                    2\n                ],\n                \"line-dasharray\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            2,\n                            0\n                        ]\n                    ],\n                    7,\n                    [\n                        \"literal\",\n                        [\n                            2,\n                            2,\n                            6,\n                            2\n                        ]\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"admin-boundaries\",\n                \"mapbox:group\": \"Administrative boundaries, admin\",\n                \"microg:gms-type-feature\": \"administrative.country\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"admin-0-boundary-disputed\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"admin\",\n            \"minzoom\": 1,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"disputed\"\n                    ],\n                    \"true\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"admin_level\"\n                    ],\n                    0\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"maritime\"\n                    ],\n                    \"false\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"worldview\"\n                    ],\n                    [\n                        \"all\",\n                        \"US\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"paint\": {\n                \"line-color\": \"hsl(350, 30%, 50%)\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0.5,\n                    12,\n                    2\n                ],\n                \"line-dasharray\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            3,\n                            2,\n                            5\n                        ]\n                    ],\n                    7,\n                    [\n                        \"literal\",\n                        [\n                            2,\n                            1.5\n                        ]\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"admin-boundaries\",\n                \"mapbox:group\": \"Administrative boundaries, admin\",\n                \"microg:gms-type-feature\": \"administrative.country\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"contour-label\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"contour\",\n            \"minzoom\": 11,\n            \"filter\": [\n                \"any\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"index\"\n                    ],\n                    10\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"index\"\n                    ],\n                    5\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"ele\"\n                    ],\n                    \" m\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-pitch-alignment\": \"viewport\",\n                \"text-max-angle\": 25,\n                \"text-padding\": 5,\n                \"text-font\": [\n                    \"DIN Pro Medium\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    9.5,\n                    20,\n                    12\n                ]\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(60, 10%, 35%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-color\": \"hsl(60, 10%, 85%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"terrain\",\n                \"mapbox:group\": \"Terrain, terrain-labels\",\n                \"microg:gms-type-feature\": \"landscape.natural.terrain\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"id\": \"building-entrance\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"structure\",\n            \"minzoom\": 18,\n            \"filter\": [\n                \"==\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                \"entrance\"\n            ],\n            \"layout\": {\n                \"icon-image\": \"marker\",\n                \"text-field\": [\n                    \"get\",\n                    \"ref\"\n                ],\n                \"text-size\": 10,\n                \"text-offset\": [\n                    0,\n                    -0.5\n                ],\n                \"text-font\": [\n                    \"DIN Pro Italic\",\n                    \"Arial Unicode MS Regular\"\n                ]\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(60, 8%, 38%)\",\n                \"text-halo-color\": \"hsl(60, 13%, 77%)\",\n                \"text-halo-width\": 1,\n                \"icon-opacity\": 0.4\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"buildings\",\n                \"mapbox:group\": \"Buildings, building-labels\",\n                \"microg:gms-type-feature\": \"poi\",\n                \"microg:gms-type-element\": \"labels.icon\"\n            }\n        },\n        {\n            \"id\": \"building-number-label\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"housenum_label\",\n            \"minzoom\": 17,\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"house_num\"\n                ],\n                \"text-font\": [\n                    \"DIN Pro Italic\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-padding\": 4,\n                \"text-max-width\": 7,\n                \"text-size\": 10\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(60, 8%, 38%)\",\n                \"text-halo-color\": \"hsl(60, 13%, 77%)\",\n                \"text-halo-width\": 1\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"buildings\",\n                \"mapbox:group\": \"Buildings, building-labels\",\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"id\": \"block-number-label\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"place_label\",\n            \"minzoom\": 16,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"settlement_subdivision\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    \"block\"\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"name\"\n                ],\n                \"text-font\": [\n                    \"DIN Pro Italic\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-max-width\": 7,\n                \"text-size\": 11\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(60, 18%, 44%)\",\n                \"text-halo-color\": \"hsl(60, 17%, 84%)\",\n                \"text-halo-width\": 0.5,\n                \"text-halo-blur\": 0.5\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"buildings\",\n                \"mapbox:group\": \"Buildings, building-labels\",\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"id\": \"road-label\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 10,\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"motorway\",\n                            \"trunk\",\n                            \"primary\",\n                            \"secondary\",\n                            \"tertiary\"\n                        ],\n                        true,\n                        false\n                    ],\n                    12,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"motorway\",\n                            \"trunk\",\n                            \"primary\",\n                            \"secondary\",\n                            \"tertiary\",\n                            \"street\",\n                            \"street_limited\",\n                            \"track\"\n                        ],\n                        true,\n                        false\n                    ],\n                    15,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"path\",\n                            \"pedestrian\",\n                            \"golf\",\n                            \"ferry\",\n                            \"aerialway\"\n                        ],\n                        false,\n                        true\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    10,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"motorway\",\n                            \"trunk\",\n                            \"primary\",\n                            \"secondary\",\n                            \"tertiary\"\n                        ],\n                        10,\n                        [\n                            \"motorway_link\",\n                            \"trunk_link\",\n                            \"primary_link\",\n                            \"secondary_link\",\n                            \"tertiary_link\",\n                            \"street\",\n                            \"street_limited\",\n                            \"track\"\n                        ],\n                        9,\n                        6.5\n                    ],\n                    18,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"motorway\",\n                            \"trunk\",\n                            \"primary\",\n                            \"secondary\",\n                            \"tertiary\"\n                        ],\n                        16,\n                        [\n                            \"motorway_link\",\n                            \"trunk_link\",\n                            \"primary_link\",\n                            \"secondary_link\",\n                            \"tertiary_link\",\n                            \"street\",\n                            \"street_limited\",\n                            \"track\"\n                        ],\n                        14,\n                        13\n                    ]\n                ],\n                \"text-max-angle\": 30,\n                \"text-font\": [\n                    \"DIN Pro Regular\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-padding\": 1,\n                \"text-rotation-alignment\": \"map\",\n                \"text-pitch-alignment\": \"viewport\",\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-letter-spacing\": 0.01\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(0,0%, 0%)\",\n                \"text-halo-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"motorway\",\n                        \"trunk\"\n                    ],\n                    \"hsla(60, 25%, 100%, 0.75)\",\n                    \"hsl(60, 25%, 100%)\"\n                ],\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, road-labels\",\n                \"microg:gms-type-feature\": \"road\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"id\": \"road-intersection\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 15,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"intersection\"\n                ],\n                [\n                    \"has\",\n                    \"name\"\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"icon-image\": \"intersection\",\n                \"icon-text-fit\": \"both\",\n                \"icon-text-fit-padding\": [\n                    1,\n                    2,\n                    1,\n                    2\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.2\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    9,\n                    18,\n                    12\n                ],\n                \"text-font\": [\n                    \"DIN Pro Bold\",\n                    \"Arial Unicode MS Bold\"\n                ]\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(230, 36%, 64%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, road-labels\",\n                \"microg:gms-type-feature\": \"road\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"id\": \"road-number-shield\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 6,\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"reflen\"\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"reflen\"\n                    ],\n                    6\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"pedestrian\",\n                        \"service\"\n                    ],\n                    false,\n                    true\n                ],\n                [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"==\",\n                        [\n                            \"geometry-type\"\n                        ],\n                        \"Point\"\n                    ],\n                    11,\n                    [\n                        \">\",\n                        [\n                            \"get\",\n                            \"len\"\n                        ],\n                        5000\n                    ],\n                    12,\n                    [\n                        \">\",\n                        [\n                            \"get\",\n                            \"len\"\n                        ],\n                        2500\n                    ],\n                    13,\n                    [\n                        \">\",\n                        [\n                            \"get\",\n                            \"len\"\n                        ],\n                        1000\n                    ],\n                    14,\n                    true\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": 9,\n                \"icon-image\": [\n                    \"case\",\n                    [\n                        \"has\",\n                        \"shield_beta\"\n                    ],\n                    [\n                        \"coalesce\",\n                        [\n                            \"image\",\n                            [\n                                \"concat\",\n                                [\n                                    \"get\",\n                                    \"shield_beta\"\n                                ],\n                                \"-\",\n                                [\n                                    \"to-string\",\n                                    [\n                                        \"get\",\n                                        \"reflen\"\n                                    ]\n                                ]\n                            ]\n                        ],\n                        [\n                            \"image\",\n                            [\n                                \"concat\",\n                                \"default-\",\n                                [\n                                    \"to-string\",\n                                    [\n                                        \"get\",\n                                        \"reflen\"\n                                    ]\n                                ]\n                            ]\n                        ]\n                    ],\n                    [\n                        \"concat\",\n                        [\n                            \"get\",\n                            \"shield\"\n                        ],\n                        \"-\",\n                        [\n                            \"to-string\",\n                            [\n                                \"get\",\n                                \"reflen\"\n                            ]\n                        ]\n                    ]\n                ],\n                \"icon-rotation-alignment\": \"viewport\",\n                \"text-max-angle\": 38,\n                \"symbol-spacing\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    11,\n                    400,\n                    14,\n                    600\n                ],\n                \"text-font\": [\n                    \"DIN Pro Bold\",\n                    \"Arial Unicode MS Bold\"\n                ],\n                \"symbol-placement\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"point\",\n                    11,\n                    \"line\"\n                ],\n                \"text-rotation-alignment\": \"viewport\",\n                \"text-field\": [\n                    \"get\",\n                    \"ref\"\n                ],\n                \"text-letter-spacing\": 0.05\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"case\",\n                    [\n                        \"all\",\n                        [\n                            \"has\",\n                            \"shield_text_color_beta\"\n                        ],\n                        [\n                            \"to-boolean\",\n                            [\n                                \"coalesce\",\n                                [\n                                    \"image\",\n                                    [\n                                        \"concat\",\n                                        [\n                                            \"get\",\n                                            \"shield_beta\"\n                                        ],\n                                        \"-\",\n                                        [\n                                            \"to-string\",\n                                            [\n                                                \"get\",\n                                                \"reflen\"\n                                            ]\n                                        ]\n                                    ]\n                                ],\n                                \"\"\n                            ]\n                        ]\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"shield_text_color_beta\"\n                        ],\n                        \"white\",\n                        \"hsl(0, 0%, 100%)\",\n                        \"yellow\",\n                        \"hsl(50, 63%, 70%)\",\n                        \"orange\",\n                        \"hsl(25, 63%, 75%)\",\n                        \"blue\",\n                        \"hsl(230, 36%, 44%)\",\n                        \"red\",\n                        \"hsl(0, 54%, 59%)\",\n                        \"green\",\n                        \"hsl(140, 46%, 37%)\",\n                        \"hsl(230, 11%, 13%)\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"shield_text_color\"\n                        ],\n                        \"white\",\n                        \"hsl(0, 0%, 100%)\",\n                        \"yellow\",\n                        \"hsl(50, 63%, 70%)\",\n                        \"orange\",\n                        \"hsl(25, 63%, 75%)\",\n                        \"blue\",\n                        \"hsl(230, 36%, 44%)\",\n                        \"red\",\n                        \"hsl(0, 54%, 59%)\",\n                        \"green\",\n                        \"hsl(140, 46%, 37%)\",\n                        \"hsl(230, 11%, 13%)\"\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, road-labels\",\n                \"microg:gms-type-feature\": \"road\",\n                \"microg:gms-type-element\": \"labels.icon\"\n            }\n        },\n        {\n            \"id\": \"road-exit-shield\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"motorway_junction\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"reflen\"\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"reflen\"\n                    ],\n                    9\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"ref\"\n                ],\n                \"text-size\": 9,\n                \"icon-image\": [\n                    \"concat\",\n                    \"motorway-exit-\",\n                    [\n                        \"to-string\",\n                        [\n                            \"get\",\n                            \"reflen\"\n                        ]\n                    ]\n                ],\n                \"text-font\": [\n                    \"DIN Pro Bold\",\n                    \"Arial Unicode MS Bold\"\n                ]\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(0, 0%, 100%)\",\n                \"text-translate\": [\n                    0,\n                    0\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, road-labels\",\n                \"microg:gms-type-feature\": \"road\",\n                \"microg:gms-type-element\": \"labels.icon\"\n            }\n        },\n        {\n            \"id\": \"path-pedestrian-label\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 12,\n            \"filter\": [\n                \"all\",\n                [\n                    \"case\",\n                    [\n                        \"has\",\n                        \"layer\"\n                    ],\n                    [\n                        \">=\",\n                        [\n                            \"get\",\n                            \"layer\"\n                        ],\n                        0\n                    ],\n                    true\n                ],\n                [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"pedestrian\"\n                        ],\n                        true,\n                        false\n                    ],\n                    15,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"path\",\n                            \"pedestrian\"\n                        ],\n                        true,\n                        false\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    10,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        \"pedestrian\",\n                        9,\n                        6.5\n                    ],\n                    18,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        \"pedestrian\",\n                        14,\n                        13\n                    ]\n                ],\n                \"text-max-angle\": 30,\n                \"text-font\": [\n                    \"DIN Pro Regular\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-padding\": 1,\n                \"text-rotation-alignment\": \"map\",\n                \"text-pitch-alignment\": \"viewport\",\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-letter-spacing\": 0.01\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(0,0%, 0%)\",\n                \"text-halo-color\": \"hsl(60, 25%, 100%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., walking-cycling-labels\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"id\": \"golf-hole-label\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 16,\n            \"filter\": [\n                \"==\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                \"golf\"\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"DIN Pro Medium\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-size\": 12\n            },\n            \"paint\": {\n                \"text-halo-color\": \"hsl(98, 60%, 55%)\",\n                \"text-halo-width\": 0.5,\n                \"text-halo-blur\": 0.5,\n                \"text-color\": \"hsl(100, 80%, 18%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., walking-cycling-labels\",\n                \"microg:gms-type-feature\": \"poi.attraction\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"id\": \"ferry-aerialway-label\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 15,\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                \"aerialway\",\n                true,\n                \"ferry\",\n                true,\n                false\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    10,\n                    6.5,\n                    18,\n                    13\n                ],\n                \"text-max-angle\": 30,\n                \"text-font\": [\n                    \"DIN Pro Regular\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-padding\": 1,\n                \"text-rotation-alignment\": \"map\",\n                \"text-pitch-alignment\": \"viewport\",\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-letter-spacing\": 0.01\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"ferry\",\n                    \"hsl(205, 43%, 100%)\",\n                    \"hsl(230, 50%, 60%)\"\n                ],\n                \"text-halo-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"ferry\",\n                    \"hsl(205, 75%, 70%)\",\n                    \"hsl(60, 20%, 100%)\"\n                ],\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"transit\",\n                \"mapbox:group\": \"Transit, ferry-aerialway-labels\",\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"id\": \"waterway-label\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"natural_label\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"canal\",\n                        \"river\",\n                        \"stream\",\n                        \"disputed_canal\",\n                        \"disputed_river\",\n                        \"disputed_stream\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"worldview\"\n                        ],\n                        [\n                            \"all\",\n                            \"US\"\n                        ],\n                        true,\n                        false\n                    ],\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"text-font\": [\n                    \"DIN Pro Italic\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-max-angle\": 30,\n                \"symbol-spacing\": [\n                    \"interpolate\",\n                    [\n                        \"linear\",\n                        1\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    250,\n                    17,\n                    400\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    13,\n                    12,\n                    18,\n                    18\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-pitch-alignment\": \"viewport\",\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(205, 43%, 90%)\",\n                \"text-halo-color\": \"hsla(60, 17%, 84%, 0.5)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"natural-features\",\n                \"mapbox:group\": \"Natural features, natural-labels\",\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"id\": \"natural-line-label\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"natural-features\",\n                \"mapbox:group\": \"Natural features, natural-labels\",\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"natural_label\",\n            \"minzoom\": 4,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"glacier\",\n                        \"landform\",\n                        \"disputed_glacier\",\n                        \"disputed_landform\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"worldview\"\n                        ],\n                        [\n                            \"all\",\n                            \"US\"\n                        ],\n                        true,\n                        false\n                    ],\n                    false\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    4\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"sizerank\"\n                        ],\n                        18,\n                        5,\n                        12\n                    ],\n                    17,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"sizerank\"\n                        ],\n                        18,\n                        13,\n                        12\n                    ]\n                ],\n                \"text-max-angle\": 30,\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"DIN Pro Medium\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"symbol-placement\": \"line-center\",\n                \"text-pitch-alignment\": \"viewport\"\n            },\n            \"paint\": {\n                \"text-halo-width\": 0.5,\n                \"text-halo-color\": \"hsl(60, 17%, 84%)\",\n                \"text-halo-blur\": 0.5,\n                \"text-color\": \"hsl(340, 10%, 38%)\"\n            }\n        },\n        {\n            \"id\": \"natural-point-label\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"natural_label\",\n            \"minzoom\": 4,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"dock\",\n                        \"glacier\",\n                        \"landform\",\n                        \"water_feature\",\n                        \"wetland\",\n                        \"disputed_dock\",\n                        \"disputed_glacier\",\n                        \"disputed_landform\",\n                        \"disputed_water_feature\",\n                        \"disputed_wetland\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"worldview\"\n                        ],\n                        [\n                            \"all\",\n                            \"US\"\n                        ],\n                        true,\n                        false\n                    ],\n                    false\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    4\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"Point\"\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"sizerank\"\n                        ],\n                        18,\n                        5,\n                        12\n                    ],\n                    17,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"sizerank\"\n                        ],\n                        18,\n                        13,\n                        12\n                    ]\n                ],\n                \"icon-image\": [\n                    \"get\",\n                    \"maki\"\n                ],\n                \"text-font\": [\n                    \"DIN Pro Medium\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-offset\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"sizerank\"\n                        ],\n                        [\n                            \"literal\",\n                            [\n                                0,\n                                0\n                            ]\n                        ],\n                        5,\n                        [\n                            \"literal\",\n                            [\n                                0,\n                                0.8\n                            ]\n                        ]\n                    ],\n                    17,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"sizerank\"\n                        ],\n                        [\n                            \"literal\",\n                            [\n                                0,\n                                0\n                            ]\n                        ],\n                        13,\n                        [\n                            \"literal\",\n                            [\n                                0,\n                                0.8\n                            ]\n                        ]\n                    ]\n                ],\n                \"text-anchor\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"sizerank\"\n                        ],\n                        \"center\",\n                        5,\n                        \"top\"\n                    ],\n                    17,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"sizerank\"\n                        ],\n                        \"center\",\n                        13,\n                        \"top\"\n                    ]\n                ],\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"icon-opacity\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"sizerank\"\n                        ],\n                        0,\n                        5,\n                        1\n                    ],\n                    17,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"sizerank\"\n                        ],\n                        0,\n                        13,\n                        1\n                    ]\n                ],\n                \"text-halo-color\": \"hsl(60, 20%, 100%)\",\n                \"text-halo-width\": 0.5,\n                \"text-halo-blur\": 0.5,\n                \"text-color\": \"hsl(340, 10%, 38%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"natural-features\",\n                \"mapbox:group\": \"Natural features, natural-labels\",\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"id\": \"water-line-label\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"natural-features\",\n                \"mapbox:group\": \"Natural features, natural-labels\",\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"natural_label\",\n            \"minzoom\": 1,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"bay\",\n                        \"ocean\",\n                        \"reservoir\",\n                        \"sea\",\n                        \"water\",\n                        \"disputed_bay\",\n                        \"disputed_ocean\",\n                        \"disputed_reservoir\",\n                        \"disputed_sea\",\n                        \"disputed_water\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"worldview\"\n                        ],\n                        [\n                            \"all\",\n                            \"US\"\n                        ],\n                        true,\n                        false\n                    ],\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"*\",\n                        [\n                            \"-\",\n                            16,\n                            [\n                                \"sqrt\",\n                                [\n                                    \"get\",\n                                    \"sizerank\"\n                                ]\n                            ]\n                        ],\n                        1\n                    ],\n                    22,\n                    [\n                        \"*\",\n                        [\n                            \"-\",\n                            22,\n                            [\n                                \"sqrt\",\n                                [\n                                    \"get\",\n                                    \"sizerank\"\n                                ]\n                            ]\n                        ],\n                        1\n                    ]\n                ],\n                \"text-max-angle\": 30,\n                \"text-letter-spacing\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"ocean\",\n                    0.25,\n                    [\n                        \"sea\",\n                        \"bay\"\n                    ],\n                    0.15,\n                    0\n                ],\n                \"text-font\": [\n                    \"DIN Pro Italic\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"symbol-placement\": \"line-center\",\n                \"text-pitch-alignment\": \"viewport\",\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"bay\",\n                        \"ocean\",\n                        \"sea\"\n                    ],\n                    \"hsl(205, 71%, 90%)\",\n                    \"hsl(205, 43%, 90%)\"\n                ],\n                \"text-halo-color\": \"hsla(60, 17%, 84%, 0.5)\"\n            }\n        },\n        {\n            \"id\": \"water-point-label\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"natural_label\",\n            \"minzoom\": 1,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"bay\",\n                        \"ocean\",\n                        \"reservoir\",\n                        \"sea\",\n                        \"water\",\n                        \"disputed_bay\",\n                        \"disputed_ocean\",\n                        \"disputed_reservoir\",\n                        \"disputed_sea\",\n                        \"disputed_water\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"worldview\"\n                        ],\n                        [\n                            \"all\",\n                            \"US\"\n                        ],\n                        true,\n                        false\n                    ],\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"Point\"\n                ]\n            ],\n            \"layout\": {\n                \"text-line-height\": 1.3,\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"*\",\n                        [\n                            \"-\",\n                            16,\n                            [\n                                \"sqrt\",\n                                [\n                                    \"get\",\n                                    \"sizerank\"\n                                ]\n                            ]\n                        ],\n                        1\n                    ],\n                    22,\n                    [\n                        \"*\",\n                        [\n                            \"-\",\n                            22,\n                            [\n                                \"sqrt\",\n                                [\n                                    \"get\",\n                                    \"sizerank\"\n                                ]\n                            ]\n                        ],\n                        1\n                    ]\n                ],\n                \"text-font\": [\n                    \"DIN Pro Italic\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-letter-spacing\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"ocean\",\n                    0.25,\n                    [\n                        \"bay\",\n                        \"sea\"\n                    ],\n                    0.15,\n                    0.01\n                ],\n                \"text-max-width\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"ocean\",\n                    4,\n                    \"sea\",\n                    5,\n                    [\n                        \"bay\",\n                        \"water\"\n                    ],\n                    7,\n                    10\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"bay\",\n                        \"ocean\",\n                        \"sea\"\n                    ],\n                    \"hsl(205, 71%, 90%)\",\n                    \"hsl(205, 43%, 90%)\"\n                ],\n                \"text-halo-color\": \"hsla(60, 17%, 84%, 0.5)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"natural-features\",\n                \"mapbox:group\": \"Natural features, natural-labels\",\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"id\": \"poi-label\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"poi_label\",\n            \"minzoom\": 6,\n            \"filter\": [\n                \"<=\",\n                [\n                    \"get\",\n                    \"filterrank\"\n                ],\n                [\n                    \"+\",\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        0,\n                        16,\n                        1,\n                        17,\n                        2\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        \"food_and_drink_stores\",\n                        3,\n                        \"historic\",\n                        3,\n                        \"landmark\",\n                        3,\n                        \"medical\",\n                        3,\n                        \"motorist\",\n                        3,\n                        \"park_like\",\n                        4,\n                        \"sport_and_leisure\",\n                        4,\n                        \"visitor_amenities\",\n                        4,\n                        2\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"sizerank\"\n                        ],\n                        18,\n                        5,\n                        12\n                    ],\n                    17,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"sizerank\"\n                        ],\n                        18,\n                        13,\n                        12\n                    ]\n                ],\n                \"icon-image\": [\n                    \"case\",\n                    [\n                        \"has\",\n                        \"maki_beta\"\n                    ],\n                    [\n                        \"coalesce\",\n                        [\n                            \"image\",\n                            [\n                                \"get\",\n                                \"maki_beta\"\n                            ]\n                        ],\n                        [\n                            \"image\",\n                            [\n                                \"get\",\n                                \"maki\"\n                            ]\n                        ]\n                    ],\n                    [\n                        \"image\",\n                        [\n                            \"get\",\n                            \"maki\"\n                        ]\n                    ]\n                ],\n                \"text-font\": [\n                    \"DIN Pro Medium\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-offset\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"sizerank\"\n                        ],\n                        [\n                            \"literal\",\n                            [\n                                0,\n                                0\n                            ]\n                        ],\n                        5,\n                        [\n                            \"literal\",\n                            [\n                                0,\n                                0.8\n                            ]\n                        ]\n                    ],\n                    17,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"sizerank\"\n                        ],\n                        [\n                            \"literal\",\n                            [\n                                0,\n                                0\n                            ]\n                        ],\n                        13,\n                        [\n                            \"literal\",\n                            [\n                                0,\n                                0.8\n                            ]\n                        ]\n                    ]\n                ],\n                \"text-anchor\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"sizerank\"\n                        ],\n                        \"center\",\n                        5,\n                        \"top\"\n                    ],\n                    17,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"sizerank\"\n                        ],\n                        \"center\",\n                        13,\n                        \"top\"\n                    ]\n                ],\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"icon-opacity\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"sizerank\"\n                        ],\n                        0,\n                        5,\n                        1\n                    ],\n                    17,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"sizerank\"\n                        ],\n                        0,\n                        13,\n                        1\n                    ]\n                ],\n                \"text-halo-color\": \"hsl(60, 20%, 100%)\",\n                \"text-halo-width\": 0.5,\n                \"text-halo-blur\": 0.5,\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"food_and_drink\",\n                    \"hsl(35, 80%, 38%)\",\n                    \"park_like\",\n                    \"hsl(100, 80%, 18%)\",\n                    \"education\",\n                    \"hsl(30, 60%, 28%)\",\n                    \"medical\",\n                    \"hsl(10, 60%, 43%)\",\n                    \"sport_and_leisure\",\n                    \"hsl(210, 60%, 38%)\",\n                    \"hsl(340, 10%, 38%)\"\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"point-of-interest-labels\",\n                \"mapbox:group\": \"Point of interest labels, poi-labels\",\n                \"microg:gms-type-feature\": \"poi\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"id\": \"transit-label\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"transit_stop_label\",\n            \"minzoom\": 12,\n            \"filter\": [\n                \"step\",\n                [\n                    \"zoom\"\n                ],\n                [\n                    \"all\",\n                    [\n                        \"<=\",\n                        [\n                            \"get\",\n                            \"filterrank\"\n                        ],\n                        4\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"mode\"\n                        ],\n                        \"rail\",\n                        true,\n                        \"metro_rail\",\n                        true,\n                        false\n                    ],\n                    [\n                        \"!=\",\n                        [\n                            \"get\",\n                            \"stop_type\"\n                        ],\n                        \"entrance\"\n                    ]\n                ],\n                14,\n                [\n                    \"all\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"mode\"\n                        ],\n                        \"rail\",\n                        true,\n                        \"metro_rail\",\n                        true,\n                        false\n                    ],\n                    [\n                        \"!=\",\n                        [\n                            \"get\",\n                            \"stop_type\"\n                        ],\n                        \"entrance\"\n                    ]\n                ],\n                15,\n                [\n                    \"all\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"mode\"\n                        ],\n                        \"rail\",\n                        true,\n                        \"metro_rail\",\n                        true,\n                        \"ferry\",\n                        true,\n                        \"light_rail\",\n                        true,\n                        false\n                    ],\n                    [\n                        \"!=\",\n                        [\n                            \"get\",\n                            \"stop_type\"\n                        ],\n                        \"entrance\"\n                    ]\n                ],\n                16,\n                [\n                    \"all\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"mode\"\n                        ],\n                        \"bus\",\n                        false,\n                        true\n                    ],\n                    [\n                        \"!=\",\n                        [\n                            \"get\",\n                            \"stop_type\"\n                        ],\n                        \"entrance\"\n                    ]\n                ],\n                17,\n                [\n                    \"!=\",\n                    [\n                        \"get\",\n                        \"stop_type\"\n                    ],\n                    \"entrance\"\n                ],\n                19,\n                true\n            ],\n            \"layout\": {\n                \"text-size\": 12,\n                \"icon-image\": [\n                    \"get\",\n                    \"network\"\n                ],\n                \"text-font\": [\n                    \"DIN Pro Medium\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-justify\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"stop_type\"\n                    ],\n                    \"entrance\",\n                    \"left\",\n                    \"center\"\n                ],\n                \"text-offset\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"stop_type\"\n                    ],\n                    \"entrance\",\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0\n                        ]\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            0,\n                            0.8\n                        ]\n                    ]\n                ],\n                \"text-anchor\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"stop_type\"\n                    ],\n                    \"entrance\",\n                    \"left\",\n                    \"top\"\n                ],\n                \"text-field\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"\",\n                    13,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"mode\"\n                        ],\n                        [\n                            \"rail\",\n                            \"metro_rail\"\n                        ],\n                        [\n                            \"coalesce\",\n                            [\n                                \"get\",\n                                \"name_en\"\n                            ],\n                            [\n                                \"get\",\n                                \"name\"\n                            ]\n                        ],\n                        \"\"\n                    ],\n                    14,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"mode\"\n                        ],\n                        [\n                            \"bus\",\n                            \"bicycle\"\n                        ],\n                        \"\",\n                        [\n                            \"coalesce\",\n                            [\n                                \"get\",\n                                \"name_en\"\n                            ],\n                            [\n                                \"get\",\n                                \"name\"\n                            ]\n                        ]\n                    ],\n                    18,\n                    [\n                        \"coalesce\",\n                        [\n                            \"get\",\n                            \"name_en\"\n                        ],\n                        [\n                            \"get\",\n                            \"name\"\n                        ]\n                    ]\n                ],\n                \"text-letter-spacing\": 0.01,\n                \"text-max-width\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"stop_type\"\n                    ],\n                    \"entrance\",\n                    15,\n                    9\n                ]\n            },\n            \"paint\": {\n                \"text-halo-color\": \"hsl(60, 20%, 100%)\",\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"network\"\n                    ],\n                    \"tokyo-metro\",\n                    \"hsl(180, 30%, 30%)\",\n                    \"mexico-city-metro\",\n                    \"hsl(25, 63%, 63%)\",\n                    [\n                        \"barcelona-metro\",\n                        \"delhi-metro\",\n                        \"hong-kong-mtr\",\n                        \"milan-metro\",\n                        \"osaka-subway\"\n                    ],\n                    \"hsl(0, 57%, 47%)\",\n                    [\n                        \"boston-t\",\n                        \"washington-metro\"\n                    ],\n                    \"hsl(230, 11%, 20%)\",\n                    [\n                        \"chongqing-rail-transit\",\n                        \"kiev-metro\",\n                        \"singapore-mrt\",\n                        \"taipei-metro\"\n                    ],\n                    \"hsl(140, 56%, 25%)\",\n                    \"hsl(230, 50%, 60%)\"\n                ],\n                \"text-halo-blur\": 0.5,\n                \"text-halo-width\": 0.5\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"transit\",\n                \"mapbox:group\": \"Transit, transit-labels\",\n                \"microg:gms-type-feature\": \"transit.station.bus\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"id\": \"airport-label\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"airport_label\",\n            \"minzoom\": 8,\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"military\",\n                    \"civil\",\n                    \"disputed_military\",\n                    \"disputed_civil\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"worldview\"\n                    ],\n                    [\n                        \"all\",\n                        \"US\"\n                    ],\n                    true,\n                    false\n                ],\n                false\n            ],\n            \"layout\": {\n                \"text-line-height\": 1.1,\n                \"text-size\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"sizerank\"\n                    ],\n                    18,\n                    9,\n                    12\n                ],\n                \"icon-image\": [\n                    \"get\",\n                    \"maki\"\n                ],\n                \"text-font\": [\n                    \"DIN Pro Medium\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-offset\": [\n                    0,\n                    0.8\n                ],\n                \"text-rotation-alignment\": \"viewport\",\n                \"text-anchor\": \"top\",\n                \"text-field\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"sizerank\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"has\",\n                            \"ref\"\n                        ],\n                        [\n                            \"concat\",\n                            [\n                                \"get\",\n                                \"ref\"\n                            ],\n                            \" -\\n\",\n                            [\n                                \"coalesce\",\n                                [\n                                    \"get\",\n                                    \"name_en\"\n                                ],\n                                [\n                                    \"get\",\n                                    \"name\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"coalesce\",\n                            [\n                                \"get\",\n                                \"name_en\"\n                            ],\n                            [\n                                \"get\",\n                                \"name\"\n                            ]\n                        ]\n                    ],\n                    15,\n                    [\n                        \"get\",\n                        \"ref\"\n                    ]\n                ],\n                \"text-letter-spacing\": 0.01,\n                \"text-max-width\": 9\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(230, 40%, 55%)\",\n                \"text-halo-color\": \"hsl(60, 20%, 100%)\",\n                \"text-halo-width\": 1\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"transit\",\n                \"mapbox:group\": \"Transit, transit-labels\",\n                \"microg:gms-type-feature\": \"transit.station.airport\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"id\": \"settlement-subdivision-label\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"place_label\",\n            \"minzoom\": 10,\n            \"maxzoom\": 15,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"settlement_subdivision\",\n                        \"disputed_settlement_subdivision\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"worldview\"\n                        ],\n                        [\n                            \"all\",\n                            \"US\"\n                        ],\n                        true,\n                        false\n                    ],\n                    false\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    3\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-transform\": \"uppercase\",\n                \"text-font\": [\n                    \"DIN Pro Regular\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-letter-spacing\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    \"suburb\",\n                    0.15,\n                    0.05\n                ],\n                \"text-max-width\": 7,\n                \"text-padding\": 3,\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"cubic-bezier\",\n                        0.5,\n                        0,\n                        1,\n                        1\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    11,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"type\"\n                        ],\n                        \"suburb\",\n                        11,\n                        10.5\n                    ],\n                    15,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"type\"\n                        ],\n                        \"suburb\",\n                        15,\n                        14\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-halo-color\": \"hsla(60, 25%, 100%, 0.75)\",\n                \"text-halo-width\": 1,\n                \"text-color\": \"hsl(230, 29%, 36%)\",\n                \"text-halo-blur\": 0.5\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"place-labels\",\n                \"mapbox:group\": \"Place labels, place-labels\",\n                \"microg:gms-type-feature\": \"administrative.neighborhood\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"id\": \"settlement-minor-label\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"place_label\",\n            \"minzoom\": 2,\n            \"maxzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    3\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"settlement\",\n                        \"disputed_settlement\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"worldview\"\n                        ],\n                        [\n                            \"all\",\n                            \"US\"\n                        ],\n                        true,\n                        false\n                    ],\n                    false\n                ],\n                [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \">\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        6\n                    ],\n                    4,\n                    [\n                        \">=\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        7\n                    ],\n                    6,\n                    [\n                        \">=\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        8\n                    ],\n                    7,\n                    [\n                        \">=\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        10\n                    ],\n                    10,\n                    [\n                        \">=\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        11\n                    ],\n                    11,\n                    [\n                        \">=\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        13\n                    ],\n                    12,\n                    [\n                        \">=\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        15\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"symbol-sort-key\": [\n                    \"get\",\n                    \"symbolrank\"\n                ],\n                \"icon-image\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"==\",\n                            [\n                                \"get\",\n                                \"capital\"\n                            ],\n                            2\n                        ],\n                        \"border-dot-13\",\n                        [\n                            \"step\",\n                            [\n                                \"get\",\n                                \"symbolrank\"\n                            ],\n                            \"dot-11\",\n                            9,\n                            \"dot-10\",\n                            11,\n                            \"dot-9\"\n                        ]\n                    ],\n                    8,\n                    \"\"\n                ],\n                \"text-font\": [\n                    \"DIN Pro Regular\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-radial-offset\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"capital\"\n                        ],\n                        2,\n                        0.6,\n                        0.55\n                    ],\n                    8,\n                    0\n                ],\n                \"text-anchor\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"get\",\n                        \"text_anchor\"\n                    ],\n                    8,\n                    \"center\"\n                ],\n                \"text-justify\": \"auto\",\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-max-width\": 7,\n                \"text-line-height\": 1.1,\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"cubic-bezier\",\n                        0.2,\n                        0,\n                        0.9,\n                        1\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        11,\n                        9,\n                        10\n                    ],\n                    6,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        14,\n                        9,\n                        12,\n                        12,\n                        10\n                    ],\n                    8,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        16,\n                        9,\n                        14,\n                        12,\n                        12,\n                        15,\n                        10\n                    ],\n                    13,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        22,\n                        9,\n                        20,\n                        12,\n                        16,\n                        15,\n                        14\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(230, 29%, 0%)\",\n                \"text-halo-color\": \"hsl(60, 25%, 100%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"place-labels\",\n                \"mapbox:group\": \"Place labels, place-labels\",\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"id\": \"settlement-major-label\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"place_label\",\n            \"minzoom\": 2,\n            \"maxzoom\": 15,\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    3\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"settlement\",\n                        \"disputed_settlement\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"worldview\"\n                        ],\n                        [\n                            \"all\",\n                            \"US\"\n                        ],\n                        true,\n                        false\n                    ],\n                    false\n                ],\n                [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    false,\n                    2,\n                    [\n                        \"<=\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        6\n                    ],\n                    4,\n                    [\n                        \"<\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        7\n                    ],\n                    6,\n                    [\n                        \"<\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        8\n                    ],\n                    7,\n                    [\n                        \"<\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        10\n                    ],\n                    10,\n                    [\n                        \"<\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        11\n                    ],\n                    11,\n                    [\n                        \"<\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        13\n                    ],\n                    12,\n                    [\n                        \"<\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        15\n                    ],\n                    13,\n                    [\n                        \">=\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        11\n                    ],\n                    14,\n                    [\n                        \">=\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        15\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"symbol-sort-key\": [\n                    \"get\",\n                    \"symbolrank\"\n                ],\n                \"icon-image\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"==\",\n                            [\n                                \"get\",\n                                \"capital\"\n                            ],\n                            2\n                        ],\n                        \"border-dot-13\",\n                        [\n                            \"step\",\n                            [\n                                \"get\",\n                                \"symbolrank\"\n                            ],\n                            \"dot-11\",\n                            9,\n                            \"dot-10\",\n                            11,\n                            \"dot-9\"\n                        ]\n                    ],\n                    8,\n                    \"\"\n                ],\n                \"text-font\": [\n                    \"DIN Pro Medium\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-radial-offset\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"capital\"\n                        ],\n                        2,\n                        0.6,\n                        0.55\n                    ],\n                    8,\n                    0\n                ],\n                \"text-anchor\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"get\",\n                        \"text_anchor\"\n                    ],\n                    8,\n                    \"center\"\n                ],\n                \"text-justify\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"text_anchor\"\n                        ],\n                        [\n                            \"left\",\n                            \"bottom-left\",\n                            \"top-left\"\n                        ],\n                        \"left\",\n                        [\n                            \"right\",\n                            \"bottom-right\",\n                            \"top-right\"\n                        ],\n                        \"right\",\n                        \"center\"\n                    ],\n                    8,\n                    \"center\"\n                ],\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-max-width\": 7,\n                \"text-line-height\": 1.1,\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"cubic-bezier\",\n                        0.2,\n                        0,\n                        0.9,\n                        1\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        13,\n                        6,\n                        11\n                    ],\n                    6,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        18,\n                        6,\n                        16,\n                        7,\n                        14\n                    ],\n                    8,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        20,\n                        9,\n                        16,\n                        10,\n                        14\n                    ],\n                    15,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        24,\n                        9,\n                        20,\n                        12,\n                        16,\n                        15,\n                        14\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(230, 29%, 0%)\",\n                \"text-halo-color\": \"hsl(60, 25%, 100%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"place-labels\",\n                \"mapbox:group\": \"Place labels, place-labels\",\n                \"microg:gms-type-feature\": \"administrative.land_parcel\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"id\": \"state-label\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"place_label\",\n            \"minzoom\": 3,\n            \"maxzoom\": 9,\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"state\",\n                    \"disputed_state\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"worldview\"\n                    ],\n                    [\n                        \"all\",\n                        \"US\"\n                    ],\n                    true,\n                    false\n                ],\n                false\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"cubic-bezier\",\n                        0.85,\n                        0.7,\n                        0.65,\n                        1\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    4,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        9,\n                        6,\n                        8,\n                        7,\n                        7\n                    ],\n                    9,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        21,\n                        6,\n                        16,\n                        7,\n                        14\n                    ]\n                ],\n                \"text-transform\": \"uppercase\",\n                \"text-font\": [\n                    \"DIN Pro Bold\",\n                    \"Arial Unicode MS Bold\"\n                ],\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-letter-spacing\": 0.15,\n                \"text-max-width\": 6\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(230, 29%, 0%)\",\n                \"text-halo-color\": \"hsl(60, 25%, 100%)\",\n                \"text-halo-width\": 1,\n                \"text-opacity\": 0.5\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"place-labels\",\n                \"mapbox:group\": \"Place labels, place-labels\",\n                \"microg:gms-type-feature\": \"administrative.province\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"id\": \"country-label\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"place_label\",\n            \"minzoom\": 1,\n            \"maxzoom\": 10,\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"country\",\n                    \"disputed_country\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"worldview\"\n                    ],\n                    [\n                        \"all\",\n                        \"US\"\n                    ],\n                    true,\n                    false\n                ],\n                false\n            ],\n            \"layout\": {\n                \"icon-image\": \"\",\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-line-height\": 1.1,\n                \"text-max-width\": 6,\n                \"text-font\": [\n                    \"DIN Pro Medium\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-radial-offset\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    0.6,\n                    8,\n                    0\n                ],\n                \"text-justify\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"text_anchor\"\n                        ],\n                        [\n                            \"left\",\n                            \"bottom-left\",\n                            \"top-left\"\n                        ],\n                        \"left\",\n                        [\n                            \"right\",\n                            \"bottom-right\",\n                            \"top-right\"\n                        ],\n                        \"right\",\n                        \"center\"\n                    ],\n                    7,\n                    \"auto\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"cubic-bezier\",\n                        0.2,\n                        0,\n                        0.7,\n                        1\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    1,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        11,\n                        4,\n                        9,\n                        5,\n                        8\n                    ],\n                    9,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        22,\n                        4,\n                        19,\n                        5,\n                        17\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"icon-opacity\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"has\",\n                            \"text_anchor\"\n                        ],\n                        1,\n                        0\n                    ],\n                    7,\n                    0\n                ],\n                \"text-color\": \"hsl(230, 29%, 0%)\",\n                \"text-halo-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    2,\n                    \"hsla(60, 25%, 100%, 0.75)\",\n                    3,\n                    \"hsl(60, 25%, 100%)\"\n                ],\n                \"text-halo-width\": 1.25\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"place-labels\",\n                \"mapbox:group\": \"Place labels, place-labels\",\n                \"microg:gms-type-feature\": \"administrative.country\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"id\": \"continent-label\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"natural_label\",\n            \"minzoom\": 0.75,\n            \"maxzoom\": 3,\n            \"filter\": [\n                \"==\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                \"continent\"\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-line-height\": 1.1,\n                \"text-max-width\": 6,\n                \"text-font\": [\n                    \"DIN Pro Medium\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        0.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    10,\n                    2.5,\n                    15\n                ],\n                \"text-transform\": \"uppercase\",\n                \"text-letter-spacing\": 0.05\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(230, 29%, 0%)\",\n                \"text-halo-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    \"hsla(60, 25%, 100%, 0.75)\",\n                    3,\n                    \"hsl(60, 25%, 100%)\"\n                ],\n                \"text-halo-width\": 1.5,\n                \"text-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    0.8,\n                    1.5,\n                    0.5,\n                    2.5,\n                    0\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"place-labels\",\n                \"mapbox:group\": \"Place labels, place-labels\",\n                \"microg:gms-type-feature\": \"administrative.country\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        }\n    ],\n    \"sources\": {\n        \"composite\": {\n            \"url\": \"mapbox://mapbox.mapbox-streets-v8,mapbox.mapbox-terrain-v2,mapbox.mapbox-bathymetry-v2\",\n            \"type\": \"vector\"\n        }\n    },\n    \"created\": \"1970-01-01T00:00:00.000Z\",\n    \"modified\": \"1970-01-01T00:00:00.000Z\",\n    \"owner\": \"mapbox\",\n    \"id\": \"outdoors-v12\",\n    \"draft\": false\n}\n"
  },
  {
    "path": "artwork/styles/style-microg-normal-mapbox.json",
    "content": "{\n    \"version\": 8,\n    \"name\": \"Mountain View Full\",\n    \"metadata\": {\n        \"mapbox:origin\": \"basic-template\",\n        \"mapbox:autocomposite\": true,\n        \"mapbox:type\": \"template\",\n        \"mapbox:sdk-support\": {\n            \"js\": \"0.50.0\",\n            \"android\": \"6.7.0\",\n            \"ios\": \"4.6.0\"\n        },\n        \"mapbox:trackposition\": false,\n        \"mapbox:groups\": {\n            \"f51b507d2a17e572c70a5db74b0fec7e\": {\n                \"name\": \"Base\",\n                \"collapsed\": false\n            },\n            \"3f48b8dc54ff2e6544b9ef9cedbf2990\": {\n                \"name\": \"Streets\",\n                \"collapsed\": true\n            },\n            \"29bb589e8d1b9b402583363648b70302\": {\n                \"name\": \"Buildings\",\n                \"collapsed\": true\n            },\n            \"3c26e9cbc75335c6f0ba8de5439cf1fa\": {\n                \"name\": \"Country borders\",\n                \"collapsed\": true\n            },\n            \"7b44201d7f1682d99f7140188aff23ce\": {\n                \"name\": \"Labels\",\n                \"collapsed\": true\n            },\n            \"24306bdccbff03e2ee08d5d1a4ca7312\": {\n                \"name\": \"Street name\",\n                \"collapsed\": true\n            },\n            \"124a9d7a8e5226775d947c592110dfad\": {\n                \"name\": \"POI\",\n                \"collapsed\": true\n            }\n        },\n        \"mapbox:uiParadigm\": \"layers\"\n    },\n    \"center\": [\n        12.819420849458652,\n        50.03325860617235\n    ],\n    \"zoom\": 3.315829104862067,\n    \"bearing\": 0,\n    \"pitch\": 1.5,\n    \"light\": {\n        \"intensity\": 0.5,\n        \"color\": \"hsl(0, 0%, 100%)\",\n        \"anchor\": \"viewport\"\n    },\n    \"sources\": {\n        \"composite\": {\n            \"url\": \"mapbox://mapbox.mapbox-streets-v8,mapbox.mapbox-terrain-v2\",\n            \"type\": \"vector\"\n        }\n    },\n    \"sprite\": \"mapbox://sprites/microg/cjui4020201oo1fmca7yuwbor/8fkcj5fgn4mftlzuak3guz1f9\",\n    \"glyphs\": \"mapbox://fonts/microg/{fontstack}/{range}.pbf\",\n    \"layers\": [\n        {\n            \"id\": \"background\",\n            \"type\": \"background\",\n            \"layout\": {},\n            \"paint\": {\n                \"background-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    4,\n                    \"hsl(43, 30%, 91%)\",\n                    5,\n                    \"hsl(0, 0%, 96%)\",\n                    8,\n                    \"hsl(0, 0%, 96%)\",\n                    9,\n                    \"#efeee8\",\n                    16,\n                    \"hsl(0, 0%, 95%)\",\n                    18,\n                    \"#f8f9fb\"\n                ]\n            },\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"grass\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"landcover\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"grass\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    \"hsl(124, 30%, 90%)\",\n                    11,\n                    \"hsl(107, 30%, 94%)\",\n                    12.5,\n                    \"hsl(107, 30%, 94%)\",\n                    13.5,\n                    \"hsl(45, 12%, 93%)\"\n                ]\n            }\n        },\n        {\n            \"id\": \"forrest\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"landcover\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"wood\",\n                    \"scrub\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    \"hsl(124, 42%, 86%)\",\n                    11,\n                    \"hsl(107, 47%, 94%)\",\n                    12.5,\n                    \"hsl(107, 47%, 94%)\",\n                    13.5,\n                    \"hsl(45, 12%, 93%)\"\n                ]\n            }\n        },\n        {\n            \"id\": \"national_park\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"landuse_overlay\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"national_park\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": \"hsl(106, 58%, 85%)\"\n            }\n        },\n        {\n            \"id\": \"snow\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"landcover\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"snow\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": \"#f9fafc\"\n            }\n        },\n        {\n            \"id\": \"hillshade\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"landscape.natural.terrain\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"hillshade\",\n            \"layout\": {},\n            \"paint\": {\n                \"fill-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    0.03,\n                    13,\n                    0\n                ]\n            }\n        },\n        {\n            \"id\": \"park\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"poi.park\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"landuse\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"park\",\n                    \"scrub\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": \"#c1ecaf\"\n            }\n        },\n        {\n            \"id\": \"pitch\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"landscape.natural.terrain\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"landuse\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"pitch\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": \"#c8efbb\"\n            }\n        },\n        {\n            \"id\": \"landuse\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"landuse\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"airport\",\n                    \"school\",\n                    \"hospital\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": \"hsl(202, 26%, 94%)\"\n            }\n        },\n        {\n            \"id\": \"river\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"water\",\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": \"hsl(206, 100%, 83%)\"\n            }\n        },\n        {\n            \"id\": \"path\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"path\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    [\n                        \"platform\",\n                        \"steps\"\n                    ],\n                    false,\n                    true\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsl(118, 34%, 66%)\",\n                \"line-dasharray\": [\n                    4,\n                    2\n                ]\n            }\n        },\n        {\n            \"id\": \"steps\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"path\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    [\n                        \"steps\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsl(118, 5%, 66%)\",\n                \"line-dasharray\": [\n                    1,\n                    1\n                ],\n                \"line-gap-width\": 1\n            }\n        },\n        {\n            \"id\": \"platform\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"transit.station.rail\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    [\n                        \"platform\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    false,\n                    true\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    \"hsl(2, 20%, 92%)\",\n                    16,\n                    \"hsl(2, 95%, 92%)\"\n                ],\n                \"fill-outline-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    \"hsl(1, 10%, 76%)\",\n                    16,\n                    \"hsl(1, 74%, 76%)\"\n                ],\n                \"fill-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0,\n                    16,\n                    1\n                ]\n            }\n        },\n        {\n            \"id\": \"primary_tunnel_border\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary_link\",\n                        \"primary\",\n                        \"motorway_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    7,\n                    0,\n                    8,\n                    1,\n                    12,\n                    4,\n                    14,\n                    6,\n                    16,\n                    10,\n                    22,\n                    64\n                ],\n                \"line-color\": \"#cbcccd\"\n            }\n        },\n        {\n            \"id\": \"primary_tunnel\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary_link\",\n                        \"primary\",\n                        \"motorway_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    1,\n                    12,\n                    4,\n                    14,\n                    6,\n                    16,\n                    10,\n                    22,\n                    64\n                ],\n                \"line-color\": \"hsl(0, 0%, 89%)\"\n            }\n        },\n        {\n            \"id\": \"aeroway\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"transit.station.airport\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"aeroway\",\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsla(0, 0%, 0%, 0.1)\"\n            }\n        },\n        {\n            \"id\": \"service_road\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"service\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsla(0, 0%, 0%, 0.1)\"\n            }\n        },\n        {\n            \"id\": \"pedestrian_border\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"pedestrian\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"has\",\n                    \"name\"\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    13,\n                    1,\n                    16,\n                    4,\n                    22,\n                    32\n                ],\n                \"line-color\": \"#e3e3e3\",\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12.5,\n                    0,\n                    13.5,\n                    1\n                ]\n            }\n        },\n        {\n            \"id\": \"street_border\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"street\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    1,\n                    16,\n                    6,\n                    22,\n                    40\n                ],\n                \"line-color\": \"#e3e3e3\"\n            }\n        },\n        {\n            \"id\": \"secondary_border\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"secondary\",\n                    \"secondary_link\",\n                    \"tertiary_link\",\n                    \"tertiary\",\n                    \"trunk_link\",\n                    \"trunk\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    10,\n                    1,\n                    17,\n                    10,\n                    22,\n                    48\n                ],\n                \"line-color\": \"#e3e3e3\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    16,\n                    1,\n                    20,\n                    2\n                ]\n            }\n        },\n        {\n            \"id\": \"primary_border\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary_link\",\n                        \"primary\",\n                        \"motorway_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    false,\n                    true\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": \"round\"\n            },\n            \"paint\": {\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    1,\n                    16,\n                    8,\n                    22,\n                    64\n                ],\n                \"line-color\": \"#ecd283\"\n            }\n        },\n        {\n            \"id\": \"motorway_border\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"motorway\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    1,\n                    15.5,\n                    8,\n                    22,\n                    78\n                ],\n                \"line-color\": \"#ecd283\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    1,\n                    15,\n                    2\n                ]\n            }\n        },\n        {\n            \"id\": \"railway\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"major_rail\",\n                        \"minor_rail\",\n                        \"service_rail\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    false,\n                    true\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsl(220, 4%, 85%)\"\n            }\n        },\n        {\n            \"id\": \"pedestrian\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"pedestrian\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    [\n                        \"platform\"\n                    ],\n                    false,\n                    true\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"#ffffff\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    13,\n                    1,\n                    16,\n                    4,\n                    22,\n                    32\n                ],\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12.5,\n                    0,\n                    13.5,\n                    1\n                ]\n            }\n        },\n        {\n            \"id\": \"street\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"street\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"#ffffff\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    1,\n                    16,\n                    6,\n                    22,\n                    40\n                ]\n            }\n        },\n        {\n            \"id\": \"secondary\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"secondary\",\n                    \"secondary_link\",\n                    \"trunk_link\",\n                    \"tertiary\",\n                    \"tertiary_link\",\n                    \"trunk\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"#ffffff\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    10,\n                    1,\n                    17,\n                    10,\n                    22,\n                    48\n                ]\n            }\n        },\n        {\n            \"id\": \"primary\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary_link\",\n                        \"primary\",\n                        \"motorway_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    false,\n                    true\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"hsl(50, 100%, 75%)\",\n                    7,\n                    \"hsl(50, 100%, 85%)\"\n                ],\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    1,\n                    16,\n                    8,\n                    22,\n                    64\n                ]\n            }\n        },\n        {\n            \"id\": \"motorway\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"motorway\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"#ffeba3\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    1,\n                    15.5,\n                    8,\n                    22,\n                    78\n                ]\n            }\n        },\n        {\n            \"id\": \"primary_bridge_border\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary_link\",\n                        \"primary\",\n                        \"motorway_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"bridge\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    1,\n                    16,\n                    8,\n                    22,\n                    64\n                ],\n                \"line-color\": \"hsl(45, 73%, 72%)\"\n            }\n        },\n        {\n            \"id\": \"primary_bridge\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary_link\",\n                        \"primary\",\n                        \"motorway_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"bridge\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"hsl(50, 100%, 75%)\",\n                    7,\n                    \"hsl(50, 100%, 85%)\"\n                ],\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    1,\n                    16,\n                    8,\n                    22,\n                    64\n                ]\n            }\n        },\n        {\n            \"id\": \"building\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"29bb589e8d1b9b402583363648b70302\",\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"building\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"type\"\n                ],\n                [\n                    \"roof\"\n                ],\n                false,\n                true\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    [\n                        \"store\",\n                        \"retail\",\n                        \"church\",\n                        \"kiosk\",\n                        \"civic\",\n                        \"hotel\",\n                        \"supermarket\",\n                        \"pub\",\n                        \"dormitory\"\n                    ],\n                    \"hsl(33, 100%, 96%)\",\n                    \"#ededed\"\n                ],\n                \"fill-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    0,\n                    17,\n                    1\n                ]\n            }\n        },\n        {\n            \"id\": \"building_border\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"29bb589e8d1b9b402583363648b70302\",\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"building\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"type\"\n                ],\n                [\n                    \"roof\"\n                ],\n                false,\n                true\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    [\n                        \"store\",\n                        \"retail\",\n                        \"church\",\n                        \"kiosk\",\n                        \"civic\",\n                        \"commercial\",\n                        \"hotel\",\n                        \"supermarket\",\n                        \"pub\"\n                    ],\n                    \"#f8e1c7\",\n                    \"#dcdcdc\"\n                ],\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    0,\n                    17,\n                    1\n                ]\n            }\n        },\n        {\n            \"id\": \"building_3d\",\n            \"type\": \"fill-extrusion\",\n            \"metadata\": {\n                \"mapbox:group\": \"29bb589e8d1b9b402583363648b70302\",\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"building\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"extrude\"\n                ],\n                [\n                    \"true\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"fill-extrusion-height\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    0,\n                    16,\n                    [\n                        \"get\",\n                        \"height\"\n                    ]\n                ],\n                \"fill-extrusion-opacity\": 0.3,\n                \"fill-extrusion-color\": \"hsl(0, 0%, 93%)\"\n            }\n        },\n        {\n            \"id\": \"admin_0\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3c26e9cbc75335c6f0ba8de5439cf1fa\",\n                \"microg:gms-type-feature\": \"administrative.country\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"admin\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maritime\"\n                    ],\n                    [\n                        \"false\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"admin_level\"\n                    ],\n                    [\n                        0\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": [\n                    \"case\",\n                    [\n                        \"==\",\n                        [\n                            \"get\",\n                            \"disputed\"\n                        ],\n                        true\n                    ],\n                    \"hsl(0, 24%, 48%)\",\n                    \"#787a7b\"\n                ]\n            }\n        },\n        {\n            \"id\": \"admin_1\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3c26e9cbc75335c6f0ba8de5439cf1fa\",\n                \"microg:gms-type-feature\": \"administrative.province\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"admin\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maritime\"\n                    ],\n                    [\n                        \"false\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"admin_level\"\n                    ],\n                    [\n                        1\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": [\n                    \"case\",\n                    [\n                        \"==\",\n                        [\n                            \"get\",\n                            \"disputed\"\n                        ],\n                        true\n                    ],\n                    \"hsl(0, 24%, 48%)\",\n                    \"#787a7b\"\n                ],\n                \"line-dasharray\": [\n                    1,\n                    1\n                ]\n            }\n        },\n        {\n            \"id\": \"river_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"natural_label\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"river\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"symbol-placement\": \"line\",\n                \"symbol-spacing\": 500,\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ]\n            },\n            \"paint\": {\n                \"text-color\": \"#5083c1\",\n                \"text-halo-color\": \"#5083c1\",\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"city_label_right\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"place_label\",\n            \"maxzoom\": 8,\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    [\n                        \"/\",\n                        [\n                            \"zoom\"\n                        ],\n                        3\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"settlement\",\n                        \"settlement_subdivision\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-optional\": true,\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"-\",\n                        14,\n                        [\n                            \"max\",\n                            0,\n                            [\n                                \"-\",\n                                [\n                                    \"get\",\n                                    \"symbolrank\"\n                                ],\n                                8\n                            ]\n                        ]\n                    ],\n                    22,\n                    [\n                        \"-\",\n                        20,\n                        [\n                            \"/\",\n                            [\n                                \"get\",\n                                \"symbolrank\"\n                            ],\n                            4\n                        ]\n                    ]\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"capital\"\n                    ],\n                    [\n                        0,\n                        2\n                    ],\n                    \"capital\",\n                    \"city\"\n                ],\n                \"text-font\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"symbolrank\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\"\n                        ]\n                    ],\n                    10,\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Regular\"\n                        ]\n                    ]\n                ],\n                \"text-justify\": \"left\",\n                \"text-offset\": [\n                    0.5,\n                    0.1\n                ],\n                \"icon-size\": [\n                    \"/\",\n                    5,\n                    [\n                        \"get\",\n                        \"symbolrank\"\n                    ]\n                ],\n                \"text-anchor\": \"left\",\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"*\",\n                                [\n                                    \"get\",\n                                    \"symbolrank\"\n                                ],\n                                2\n                            ],\n                            5\n                        ],\n                        \"%)\"\n                    ],\n                    22,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"get\",\n                                \"symbolrank\"\n                            ],\n                            25\n                        ],\n                        \"%)\"\n                    ]\n                ],\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"text-halo-color\": \"hsl(0, 0%, 100%)\",\n                \"icon-opacity\": 0.8\n            }\n        },\n        {\n            \"id\": \"city_label_left\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"place_label\",\n            \"maxzoom\": 8,\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    [\n                        \"/\",\n                        [\n                            \"zoom\"\n                        ],\n                        3\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"settlement\",\n                        \"settlement_subdivision\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"-\",\n                        14,\n                        [\n                            \"max\",\n                            0,\n                            [\n                                \"-\",\n                                [\n                                    \"get\",\n                                    \"symbolrank\"\n                                ],\n                                8\n                            ]\n                        ]\n                    ],\n                    22,\n                    [\n                        \"-\",\n                        20,\n                        [\n                            \"/\",\n                            [\n                                \"get\",\n                                \"symbolrank\"\n                            ],\n                            4\n                        ]\n                    ]\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"capital\"\n                    ],\n                    [\n                        0,\n                        2\n                    ],\n                    \"capital\",\n                    \"city\"\n                ],\n                \"text-font\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"symbolrank\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\"\n                        ]\n                    ],\n                    10,\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Regular\"\n                        ]\n                    ]\n                ],\n                \"text-justify\": \"right\",\n                \"text-offset\": [\n                    -0.5,\n                    0.1\n                ],\n                \"icon-size\": [\n                    \"/\",\n                    5,\n                    [\n                        \"get\",\n                        \"symbolrank\"\n                    ]\n                ],\n                \"text-anchor\": \"right\",\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"*\",\n                                [\n                                    \"get\",\n                                    \"symbolrank\"\n                                ],\n                                2\n                            ],\n                            5\n                        ],\n                        \"%)\"\n                    ],\n                    22,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"get\",\n                                \"symbolrank\"\n                            ],\n                            25\n                        ],\n                        \"%)\"\n                    ]\n                ],\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"text-halo-color\": \"hsl(0, 0%, 100%)\",\n                \"icon-opacity\": 0.8\n            }\n        },\n        {\n            \"id\": \"city_label_below\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"place_label\",\n            \"maxzoom\": 8,\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    [\n                        \"/\",\n                        [\n                            \"zoom\"\n                        ],\n                        3\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"settlement\",\n                        \"settlement_subdivision\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"-\",\n                        14,\n                        [\n                            \"max\",\n                            0,\n                            [\n                                \"-\",\n                                [\n                                    \"get\",\n                                    \"symbolrank\"\n                                ],\n                                8\n                            ]\n                        ]\n                    ],\n                    22,\n                    [\n                        \"-\",\n                        20,\n                        [\n                            \"/\",\n                            [\n                                \"get\",\n                                \"symbolrank\"\n                            ],\n                            4\n                        ]\n                    ]\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"capital\"\n                    ],\n                    [\n                        0,\n                        2\n                    ],\n                    \"capital\",\n                    \"city\"\n                ],\n                \"text-font\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"symbolrank\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\"\n                        ]\n                    ],\n                    10,\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Regular\"\n                        ]\n                    ]\n                ],\n                \"text-offset\": [\n                    0,\n                    0.4\n                ],\n                \"icon-size\": [\n                    \"/\",\n                    5,\n                    [\n                        \"get\",\n                        \"symbolrank\"\n                    ]\n                ],\n                \"text-anchor\": \"top\",\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"*\",\n                                [\n                                    \"get\",\n                                    \"symbolrank\"\n                                ],\n                                2\n                            ],\n                            5\n                        ],\n                        \"%)\"\n                    ],\n                    22,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"get\",\n                                \"symbolrank\"\n                            ],\n                            25\n                        ],\n                        \"%)\"\n                    ]\n                ],\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"text-halo-color\": \"hsl(0, 0%, 100%)\",\n                \"icon-opacity\": 0.8\n            }\n        },\n        {\n            \"id\": \"city_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"place_label\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    [\n                        \"/\",\n                        [\n                            \"zoom\"\n                        ],\n                        3\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"settlement\",\n                        \"settlement_subdivision\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"-\",\n                        14,\n                        [\n                            \"max\",\n                            0,\n                            [\n                                \"-\",\n                                [\n                                    \"get\",\n                                    \"symbolrank\"\n                                ],\n                                8\n                            ]\n                        ]\n                    ],\n                    22,\n                    [\n                        \"-\",\n                        20,\n                        [\n                            \"/\",\n                            [\n                                \"get\",\n                                \"symbolrank\"\n                            ],\n                            4\n                        ]\n                    ]\n                ],\n                \"icon-image\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"capital\"\n                        ],\n                        [\n                            0,\n                            2\n                        ],\n                        \"capital\",\n                        \"city\"\n                    ],\n                    8,\n                    \"\"\n                ],\n                \"text-transform\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"symbolrank\"\n                    ],\n                    \"none\",\n                    15,\n                    \"uppercase\"\n                ],\n                \"text-font\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"symbolrank\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\"\n                        ]\n                    ],\n                    10,\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Regular\"\n                        ]\n                    ]\n                ],\n                \"text-offset\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            0,\n                            -0.2\n                        ]\n                    ],\n                    8,\n                    [\n                        \"literal\",\n                        [\n                            0,\n                            0\n                        ]\n                    ]\n                ],\n                \"icon-size\": [\n                    \"/\",\n                    5,\n                    [\n                        \"get\",\n                        \"symbolrank\"\n                    ]\n                ],\n                \"text-anchor\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"bottom\",\n                    8,\n                    \"center\"\n                ],\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-letter-spacing\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"get\",\n                        \"symbolrank\"\n                    ],\n                    0,\n                    0,\n                    8,\n                    0,\n                    12,\n                    0.1,\n                    16,\n                    0.2\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"*\",\n                                [\n                                    \"get\",\n                                    \"symbolrank\"\n                                ],\n                                2\n                            ],\n                            5\n                        ],\n                        \"%)\"\n                    ],\n                    22,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"get\",\n                                \"symbolrank\"\n                            ],\n                            25\n                        ],\n                        \"%)\"\n                    ]\n                ],\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"text-halo-color\": \"hsl(0, 0%, 100%)\",\n                \"icon-opacity\": 0.8\n            }\n        },\n        {\n            \"id\": \"park_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"poi.park\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"poi_label\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maki\"\n                    ],\n                    [\n                        \"park\",\n                        \"cemetery\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"sizerank\"\n                    ],\n                    10\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-size\": 14\n            },\n            \"paint\": {\n                \"text-color\": \"#297925\",\n                \"text-halo-color\": \"hsl(0, 0%, 100%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"road-number-shield\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road\",\n                \"microg:gms-type-element\": \"labels.icon\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"ref\"\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"reflen\"\n                    ],\n                    6\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": 9,\n                \"icon-image\": [\n                    \"case\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"shield\"\n                        ],\n                        [\n                            \"de-motorway\",\n                            \"rectangle-green\",\n                            \"rectangle-yellow\",\n                            \"rectangle-white\",\n                            \"rectangle-blue\",\n                            \"rectangle-red\",\n                            \"us-interstate\"\n                        ],\n                        true,\n                        false\n                    ],\n                    [\n                        \"concat\",\n                        \"shield_\",\n                        [\n                            \"get\",\n                            \"shield\"\n                        ],\n                        \"_\",\n                        [\n                            \"get\",\n                            \"reflen\"\n                        ]\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"shield_text_color\"\n                        ],\n                        [\n                            \"white\"\n                        ],\n                        true,\n                        false\n                    ],\n                    [\n                        \"concat\",\n                        \"shield_rectangle-blue_\",\n                        [\n                            \"get\",\n                            \"reflen\"\n                        ]\n                    ],\n                    [\n                        \"concat\",\n                        \"shield_rectangle-white_\",\n                        [\n                            \"get\",\n                            \"reflen\"\n                        ]\n                    ]\n                ],\n                \"icon-rotation-alignment\": \"viewport\",\n                \"text-font\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"shield_text_color\"\n                    ],\n                    [\n                        \"white\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Bold\"\n                        ]\n                    ],\n                    [\n                        \"black\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\"\n                        ]\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Bold\"\n                        ]\n                    ]\n                ],\n                \"symbol-placement\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"point\",\n                    11,\n                    \"line\"\n                ],\n                \"text-offset\": [\n                    0,\n                    0.1\n                ],\n                \"text-rotation-alignment\": \"viewport\",\n                \"icon-size\": 0.75,\n                \"text-field\": [\n                    \"get\",\n                    \"ref\"\n                ],\n                \"text-letter-spacing\": 0.05\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"case\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"shield_text_color\"\n                        ],\n                        [\n                            \"white\"\n                        ],\n                        true,\n                        false\n                    ],\n                    \"#ffffff\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"shield_text_color\"\n                        ],\n                        [\n                            \"black\"\n                        ],\n                        true,\n                        false\n                    ],\n                    \"hsl(0, 0%, 7%)\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"shield_text_color\"\n                        ],\n                        [\n                            \"yellow\"\n                        ],\n                        true,\n                        false\n                    ],\n                    \"hsl(50, 100%, 70%)\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"shield_text_color\"\n                        ],\n                        [\n                            \"orange\"\n                        ],\n                        true,\n                        false\n                    ],\n                    \"hsl(25, 100%, 75%)\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"shield_text_color\"\n                        ],\n                        [\n                            \"blue\"\n                        ],\n                        true,\n                        false\n                    ],\n                    \"hsl(230, 48%, 34%)\",\n                    \"#ffffff\"\n                ]\n            }\n        },\n        {\n            \"id\": \"country_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"administrative.country\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"place_label\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"country\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {\n                \"text-letter-spacing\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    1,\n                    0,\n                    3,\n                    0.15\n                ],\n                \"text-font\": [\n                    \"Roboto Medium\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.2\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    1,\n                    12,\n                    7,\n                    [\n                        \"/\",\n                        100,\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ]\n                    ]\n                ],\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(0, 0%, 10%)\",\n                \"text-halo-color\": \"hsl(0, 0%, 100%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"text-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    6,\n                    1,\n                    7,\n                    0\n                ]\n            }\n        },\n        {\n            \"id\": \"pedestrian_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 16,\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"pedestrian\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    [\n                        \"platform\"\n                    ],\n                    false,\n                    true\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"name\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    17,\n                    10,\n                    22,\n                    14\n                ],\n                \"text-padding\": 5\n            },\n            \"paint\": {\n                \"text-color\": \"#575757\",\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"street_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"street\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"name\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    6,\n                    16,\n                    10\n                ],\n                \"text-padding\": 5\n            },\n            \"paint\": {\n                \"text-color\": \"#575757\",\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"secondary_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"secondary\",\n                        \"secondary_link\",\n                        \"tertiary_link\",\n                        \"tertiary\",\n                        \"trunk_link\",\n                        \"trunk\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"name\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    8,\n                    16,\n                    13\n                ],\n                \"symbol-spacing\": 300,\n                \"text-padding\": 25\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(196, 0%, 34%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"primary_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary\",\n                        \"primary_link\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"name\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    10,\n                    18,\n                    14\n                ],\n                \"symbol-spacing\": 800,\n                \"text-padding\": 50\n            },\n            \"paint\": {\n                \"text-color\": \"#6e481d\",\n                \"text-halo-width\": 1,\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"poi_label_below\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"124a9d7a8e5226775d947c592110dfad\",\n                \"microg:gms-type-element\": \"labels.text\",\n                \"microg:gms-type-feature\": \"poi\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"poi_label\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    [\n                        \"/\",\n                        [\n                            \"zoom\"\n                        ],\n                        3.5\n                    ]\n                ],\n                [\n                    \"!\",\n                    [\n                        \"all\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"maki\"\n                            ],\n                            [\n                                \"park\",\n                                \"cemetery\"\n                            ],\n                            true,\n                            false\n                        ],\n                        [\n                            \"<=\",\n                            [\n                                \"get\",\n                                \"sizerank\"\n                            ],\n                            10\n                        ]\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-optional\": true,\n                \"text-line-height\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    15,\n                    1.2\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    13,\n                    15,\n                    14\n                ],\n                \"icon-offset\": [\n                    0,\n                    -36\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maki\"\n                    ],\n                    [\n                        \"museum\",\n                        \"lodging\",\n                        \"theatre\",\n                        \"grocery\",\n                        \"restaurant\"\n                    ],\n                    [\n                        \"concat\",\n                        \"poi_\",\n                        [\n                            \"get\",\n                            \"maki\"\n                        ]\n                    ],\n                    [\n                        \"fitness-centre\",\n                        \"golf\",\n                        \"campsite\",\n                        \"bowling-alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic-site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog-park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"poi_generic_green\",\n                    [\n                        \"bank\",\n                        \"parking\",\n                        \"parking-garage\"\n                    ],\n                    \"poi_generic_purple\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\"\n                    ],\n                    \"poi_generic_orange\",\n                    [\n                        \"alcohol-shop\",\n                        \"shop\",\n                        \"shoe\",\n                        \"convenience\",\n                        \"clothing-store\",\n                        \"jewelry-store\"\n                    ],\n                    \"poi_generic_blue\",\n                    [\n                        \"casino\",\n                        \"castle\",\n                        \"art-gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music\",\n                        \"monument\"\n                    ],\n                    \"poi_generic_teal\",\n                    [\n                        \"hospital\",\n                        \"doctor\"\n                    ],\n                    \"poi_generic_red\",\n                    [\n                        \"restaurant-pizza\",\n                        \"restaurant-seafood\",\n                        \"restaurant-noodle\",\n                        \"fast-food\",\n                        \"ice-cream\"\n                    ],\n                    \"poi_restaurant\",\n                    \"poi_generic\"\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-offset\": [\n                    0,\n                    0.5\n                ],\n                \"icon-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.25,\n                    15,\n                    0.32\n                ],\n                \"text-anchor\": \"top\",\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maki\"\n                    ],\n                    [\n                        \"museum\",\n                        \"casino\",\n                        \"castle\",\n                        \"theatre\",\n                        \"art-gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music\",\n                        \"monument\"\n                    ],\n                    \"hsl(186, 78%, 44%)\",\n                    [\n                        \"lodging\"\n                    ],\n                    \"#df7db1\",\n                    [\n                        \"fitness-centre\",\n                        \"golf\",\n                        \"campsite\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic-site\",\n                        \"zoo\",\n                        \"dog-park\",\n                        \"stadium\",\n                        \"bowling-alley\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"hsl(117, 53%, 31%)\",\n                    [\n                        \"restaurant-pizza\",\n                        \"restaurant-seafood\",\n                        \"restaurant\",\n                        \"restaurant-noodle\",\n                        \"bar\",\n                        \"cafe\",\n                        \"fast-food\",\n                        \"bakery\",\n                        \"ice-cream\"\n                    ],\n                    \"#c77d57\",\n                    [\n                        \"shop\",\n                        \"shoe\",\n                        \"alcohol-shop\",\n                        \"convenience\",\n                        \"grocery\",\n                        \"clothing-store\",\n                        \"jewelry-store\"\n                    ],\n                    \"hsl(213, 40%, 48%)\",\n                    [\n                        \"bank\",\n                        \"parking\",\n                        \"parking-garage\"\n                    ],\n                    \"#737b9b\",\n                    [\n                        \"hospital\",\n                        \"doctor\"\n                    ],\n                    \"#a47172\",\n                    \"#67747b\"\n                ],\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1,\n                \"icon-translate\": [\n                    0,\n                    0\n                ],\n                \"text-translate\": [\n                    0,\n                    0\n                ],\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"poi_label_above\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"124a9d7a8e5226775d947c592110dfad\",\n                \"microg:gms-type-element\": \"labels.text\",\n                \"microg:gms-type-feature\": \"poi\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"poi_label\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    [\n                        \"/\",\n                        [\n                            \"zoom\"\n                        ],\n                        3.5\n                    ]\n                ],\n                [\n                    \"!\",\n                    [\n                        \"all\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"maki\"\n                            ],\n                            [\n                                \"park\",\n                                \"cemetery\"\n                            ],\n                            true,\n                            false\n                        ],\n                        [\n                            \"<=\",\n                            [\n                                \"get\",\n                                \"sizerank\"\n                            ],\n                            10\n                        ]\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-optional\": true,\n                \"text-line-height\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    15,\n                    1.2\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    13,\n                    15,\n                    14\n                ],\n                \"icon-offset\": [\n                    0,\n                    -36\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maki\"\n                    ],\n                    [\n                        \"museum\",\n                        \"lodging\",\n                        \"theatre\",\n                        \"grocery\",\n                        \"restaurant\"\n                    ],\n                    [\n                        \"concat\",\n                        \"poi_\",\n                        [\n                            \"get\",\n                            \"maki\"\n                        ]\n                    ],\n                    [\n                        \"fitness-centre\",\n                        \"golf\",\n                        \"campsite\",\n                        \"bowling-alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic-site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog-park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"poi_generic_green\",\n                    [\n                        \"bank\",\n                        \"parking\",\n                        \"parking-garage\"\n                    ],\n                    \"poi_generic_purple\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\"\n                    ],\n                    \"poi_generic_orange\",\n                    [\n                        \"alcohol-shop\",\n                        \"shop\",\n                        \"shoe\",\n                        \"convenience\",\n                        \"clothing-store\",\n                        \"jewelry-store\"\n                    ],\n                    \"poi_generic_blue\",\n                    [\n                        \"casino\",\n                        \"castle\",\n                        \"art-gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music\",\n                        \"monument\"\n                    ],\n                    \"poi_generic_teal\",\n                    [\n                        \"hospital\",\n                        \"doctor\"\n                    ],\n                    \"poi_generic_red\",\n                    [\n                        \"restaurant-pizza\",\n                        \"restaurant-seafood\",\n                        \"restaurant-noodle\",\n                        \"fast-food\",\n                        \"ice-cream\"\n                    ],\n                    \"poi_restaurant\",\n                    \"poi_generic\"\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-offset\": [\n                    0,\n                    -2\n                ],\n                \"icon-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.25,\n                    15,\n                    0.32\n                ],\n                \"text-anchor\": \"bottom\",\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maki\"\n                    ],\n                    [\n                        \"museum\",\n                        \"casino\",\n                        \"castle\",\n                        \"theatre\",\n                        \"art-gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music\",\n                        \"monument\"\n                    ],\n                    \"hsl(186, 78%, 44%)\",\n                    [\n                        \"lodging\"\n                    ],\n                    \"#df7db1\",\n                    [\n                        \"fitness-centre\",\n                        \"golf\",\n                        \"campsite\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic-site\",\n                        \"zoo\",\n                        \"dog-park\",\n                        \"stadium\",\n                        \"bowling-alley\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"hsl(117, 53%, 31%)\",\n                    [\n                        \"restaurant-pizza\",\n                        \"restaurant-seafood\",\n                        \"restaurant\",\n                        \"restaurant-noodle\",\n                        \"bar\",\n                        \"cafe\",\n                        \"fast-food\",\n                        \"bakery\",\n                        \"ice-cream\"\n                    ],\n                    \"#c77d57\",\n                    [\n                        \"shop\",\n                        \"shoe\",\n                        \"alcohol-shop\",\n                        \"convenience\",\n                        \"grocery\",\n                        \"clothing-store\",\n                        \"jewelry-store\"\n                    ],\n                    \"hsl(213, 40%, 48%)\",\n                    [\n                        \"bank\",\n                        \"parking\",\n                        \"parking-garage\"\n                    ],\n                    \"#737b9b\",\n                    [\n                        \"hospital\",\n                        \"doctor\"\n                    ],\n                    \"#a47172\",\n                    \"#67747b\"\n                ],\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1,\n                \"icon-translate\": [\n                    0,\n                    0\n                ],\n                \"text-translate\": [\n                    0,\n                    0\n                ],\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"poi_label_left\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"124a9d7a8e5226775d947c592110dfad\",\n                \"microg:gms-type-element\": \"labels.text\",\n                \"microg:gms-type-feature\": \"poi\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"poi_label\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    [\n                        \"/\",\n                        [\n                            \"zoom\"\n                        ],\n                        3.5\n                    ]\n                ],\n                [\n                    \"!\",\n                    [\n                        \"all\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"maki\"\n                            ],\n                            [\n                                \"park\",\n                                \"cemetery\"\n                            ],\n                            true,\n                            false\n                        ],\n                        [\n                            \"<=\",\n                            [\n                                \"get\",\n                                \"sizerank\"\n                            ],\n                            10\n                        ]\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-line-height\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    15,\n                    1.2\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    13,\n                    15,\n                    14\n                ],\n                \"icon-offset\": [\n                    0,\n                    -36\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maki\"\n                    ],\n                    [\n                        \"museum\",\n                        \"lodging\",\n                        \"theatre\",\n                        \"grocery\",\n                        \"restaurant\"\n                    ],\n                    [\n                        \"concat\",\n                        \"poi_\",\n                        [\n                            \"get\",\n                            \"maki\"\n                        ]\n                    ],\n                    [\n                        \"fitness-centre\",\n                        \"golf\",\n                        \"campsite\",\n                        \"bowling-alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic-site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog-park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"poi_generic_green\",\n                    [\n                        \"bank\",\n                        \"parking\",\n                        \"parking-garage\"\n                    ],\n                    \"poi_generic_purple\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\"\n                    ],\n                    \"poi_generic_orange\",\n                    [\n                        \"alcohol-shop\",\n                        \"shop\",\n                        \"shoe\",\n                        \"convenience\",\n                        \"clothing-store\",\n                        \"jewelry-store\"\n                    ],\n                    \"poi_generic_blue\",\n                    [\n                        \"casino\",\n                        \"castle\",\n                        \"art-gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music\",\n                        \"monument\"\n                    ],\n                    \"poi_generic_teal\",\n                    [\n                        \"hospital\",\n                        \"doctor\"\n                    ],\n                    \"poi_generic_red\",\n                    [\n                        \"restaurant-pizza\",\n                        \"restaurant-seafood\",\n                        \"restaurant-noodle\",\n                        \"fast-food\",\n                        \"ice-cream\"\n                    ],\n                    \"poi_restaurant\",\n                    \"poi_generic\"\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-justify\": \"right\",\n                \"text-offset\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    [\n                        \"literal\",\n                        [\n                            -1.1,\n                            -0.7\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            -1.1,\n                            -0.9\n                        ]\n                    ]\n                ],\n                \"icon-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.25,\n                    15,\n                    0.32\n                ],\n                \"text-anchor\": \"right\",\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maki\"\n                    ],\n                    [\n                        \"museum\",\n                        \"casino\",\n                        \"castle\",\n                        \"theatre\",\n                        \"art-gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music\",\n                        \"monument\"\n                    ],\n                    \"hsl(186, 78%, 44%)\",\n                    [\n                        \"lodging\"\n                    ],\n                    \"#df7db1\",\n                    [\n                        \"fitness-centre\",\n                        \"golf\",\n                        \"campsite\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic-site\",\n                        \"zoo\",\n                        \"dog-park\",\n                        \"stadium\",\n                        \"bowling-alley\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"hsl(117, 53%, 31%)\",\n                    [\n                        \"restaurant-pizza\",\n                        \"restaurant-seafood\",\n                        \"restaurant\",\n                        \"restaurant-noodle\",\n                        \"bar\",\n                        \"cafe\",\n                        \"fast-food\",\n                        \"bakery\",\n                        \"ice-cream\"\n                    ],\n                    \"#c77d57\",\n                    [\n                        \"shop\",\n                        \"shoe\",\n                        \"alcohol-shop\",\n                        \"convenience\",\n                        \"grocery\",\n                        \"clothing-store\",\n                        \"jewelry-store\"\n                    ],\n                    \"hsl(213, 40%, 48%)\",\n                    [\n                        \"bank\",\n                        \"parking\",\n                        \"parking-garage\"\n                    ],\n                    \"#737b9b\",\n                    [\n                        \"hospital\",\n                        \"doctor\"\n                    ],\n                    \"#a47172\",\n                    \"#67747b\"\n                ],\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1,\n                \"icon-translate\": [\n                    0,\n                    0\n                ],\n                \"text-translate\": [\n                    0,\n                    0\n                ],\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"poi_label_right\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"124a9d7a8e5226775d947c592110dfad\",\n                \"microg:gms-type-element\": \"labels.text\",\n                \"microg:gms-type-feature\": \"poi\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"poi_label\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    [\n                        \"/\",\n                        [\n                            \"zoom\"\n                        ],\n                        3.5\n                    ]\n                ],\n                [\n                    \"!\",\n                    [\n                        \"all\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"maki\"\n                            ],\n                            [\n                                \"park\",\n                                \"cemetery\"\n                            ],\n                            true,\n                            false\n                        ],\n                        [\n                            \"<=\",\n                            [\n                                \"get\",\n                                \"sizerank\"\n                            ],\n                            10\n                        ]\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-line-height\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    15,\n                    1.2\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    13,\n                    15,\n                    14\n                ],\n                \"icon-offset\": [\n                    0,\n                    -36\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maki\"\n                    ],\n                    [\n                        \"museum\",\n                        \"lodging\",\n                        \"theatre\",\n                        \"grocery\",\n                        \"restaurant\"\n                    ],\n                    [\n                        \"concat\",\n                        \"poi_\",\n                        [\n                            \"get\",\n                            \"maki\"\n                        ]\n                    ],\n                    [\n                        \"fitness-centre\",\n                        \"golf\",\n                        \"campsite\",\n                        \"bowling-alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic-site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog-park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"poi_generic_green\",\n                    [\n                        \"bank\",\n                        \"parking\",\n                        \"parking-garage\"\n                    ],\n                    \"poi_generic_purple\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\"\n                    ],\n                    \"poi_generic_orange\",\n                    [\n                        \"alcohol-shop\",\n                        \"shop\",\n                        \"shoe\",\n                        \"convenience\",\n                        \"clothing-store\",\n                        \"jewelry-store\"\n                    ],\n                    \"poi_generic_blue\",\n                    [\n                        \"casino\",\n                        \"castle\",\n                        \"art-gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music\",\n                        \"monument\"\n                    ],\n                    \"poi_generic_teal\",\n                    [\n                        \"hospital\",\n                        \"doctor\"\n                    ],\n                    \"poi_generic_red\",\n                    [\n                        \"restaurant-pizza\",\n                        \"restaurant-seafood\",\n                        \"restaurant-noodle\",\n                        \"fast-food\",\n                        \"ice-cream\"\n                    ],\n                    \"poi_restaurant\",\n                    \"poi_generic\"\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-justify\": \"left\",\n                \"text-offset\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    [\n                        \"literal\",\n                        [\n                            1.1,\n                            -0.7\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            1.1,\n                            -0.9\n                        ]\n                    ]\n                ],\n                \"icon-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.25,\n                    15,\n                    0.32\n                ],\n                \"text-anchor\": \"left\",\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maki\"\n                    ],\n                    [\n                        \"museum\",\n                        \"casino\",\n                        \"castle\",\n                        \"theatre\",\n                        \"art-gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music\",\n                        \"monument\"\n                    ],\n                    \"hsl(186, 78%, 44%)\",\n                    [\n                        \"lodging\"\n                    ],\n                    \"#df7db1\",\n                    [\n                        \"fitness-centre\",\n                        \"golf\",\n                        \"campsite\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic-site\",\n                        \"zoo\",\n                        \"dog-park\",\n                        \"stadium\",\n                        \"bowling-alley\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"hsl(117, 53%, 31%)\",\n                    [\n                        \"restaurant-pizza\",\n                        \"restaurant-seafood\",\n                        \"restaurant\",\n                        \"restaurant-noodle\",\n                        \"bar\",\n                        \"cafe\",\n                        \"fast-food\",\n                        \"bakery\",\n                        \"ice-cream\"\n                    ],\n                    \"#c77d57\",\n                    [\n                        \"shop\",\n                        \"shoe\",\n                        \"alcohol-shop\",\n                        \"convenience\",\n                        \"grocery\",\n                        \"clothing-store\",\n                        \"jewelry-store\"\n                    ],\n                    \"hsl(213, 40%, 48%)\",\n                    [\n                        \"bank\",\n                        \"parking\",\n                        \"parking-garage\"\n                    ],\n                    \"#737b9b\",\n                    [\n                        \"hospital\",\n                        \"doctor\"\n                    ],\n                    \"#a47172\",\n                    \"#67747b\"\n                ],\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1,\n                \"icon-translate\": [\n                    0,\n                    0\n                ],\n                \"text-translate\": [\n                    0,\n                    0\n                ],\n                \"text-halo-blur\": 1\n            }\n        }\n    ],\n    \"created\": \"2019-04-15T08:41:40.148Z\",\n    \"modified\": \"2020-09-05T19:42:03.856Z\",\n    \"id\": \"cjui4020201oo1fmca7yuwbor\",\n    \"owner\": \"microg\",\n    \"visibility\": \"public\",\n    \"protected\": false,\n    \"draft\": false\n}\n"
  },
  {
    "path": "artwork/styles/style-microg-normal-openmaptiles.json",
    "content": "{\n    \"version\": 8,\n    \"name\": \"Mountain View Full\",\n    \"metadata\": {\n        \"mapbox:origin\": \"basic-template\",\n        \"mapbox:autocomposite\": true,\n        \"mapbox:type\": \"template\",\n        \"mapbox:sdk-support\": {\n            \"js\": \"0.50.0\",\n            \"android\": \"6.7.0\",\n            \"ios\": \"4.6.0\"\n        },\n        \"mapbox:trackposition\": false,\n        \"mapbox:groups\": {\n            \"f51b507d2a17e572c70a5db74b0fec7e\": {\n                \"name\": \"Base\",\n                \"collapsed\": false\n            },\n            \"3f48b8dc54ff2e6544b9ef9cedbf2990\": {\n                \"name\": \"Streets\",\n                \"collapsed\": true\n            },\n            \"29bb589e8d1b9b402583363648b70302\": {\n                \"name\": \"Buildings\",\n                \"collapsed\": true\n            },\n            \"3c26e9cbc75335c6f0ba8de5439cf1fa\": {\n                \"name\": \"Country borders\",\n                \"collapsed\": true\n            },\n            \"7b44201d7f1682d99f7140188aff23ce\": {\n                \"name\": \"Labels\",\n                \"collapsed\": true\n            },\n            \"24306bdccbff03e2ee08d5d1a4ca7312\": {\n                \"name\": \"Street name\",\n                \"collapsed\": true\n            },\n            \"124a9d7a8e5226775d947c592110dfad\": {\n                \"name\": \"POI\",\n                \"collapsed\": true\n            }\n        },\n        \"mapbox:uiParadigm\": \"layers\",\n        \"maputnik:renderer\": \"mbgljs\"\n    },\n    \"center\": [\n        12.819420849458652,\n        50.03325860617235\n    ],\n    \"zoom\": 3.315829104862067,\n    \"bearing\": 0,\n    \"pitch\": 1.5,\n    \"light\": {\n        \"intensity\": 0.5,\n        \"color\": \"hsl(0, 0%, 100%)\",\n        \"anchor\": \"viewport\"\n    },\n    \"sources\": {\n        \"openmaptiles\": {\n            \"type\": \"vector\",\n            \"url\": \"https://tiles.stadiamaps.com/data/openmaptiles.json\"\n        }\n    },\n    \"sprite\": \"asset://sprites\",\n    \"glyphs\": \"asset://{fontstack}/{range}.pbf\",\n    \"layers\": [\n        {\n            \"id\": \"background\",\n            \"type\": \"background\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"background-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    4,\n                    \"hsl(43, 30%, 91%)\",\n                    5,\n                    \"hsl(0, 0%, 96%)\",\n                    8,\n                    \"hsl(0, 0%, 96%)\",\n                    9,\n                    \"#efeee8\",\n                    16,\n                    \"hsl(0, 0%, 95%)\",\n                    18,\n                    \"#f8f9fb\"\n                ]\n            }\n        },\n        {\n            \"id\": \"grass\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"landcover\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"grass\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    \"hsl(124, 30%, 90%)\",\n                    11,\n                    \"hsl(107, 30%, 94%)\",\n                    12.5,\n                    \"hsl(107, 30%, 94%)\",\n                    13.5,\n                    \"hsl(45, 12%, 93%)\"\n                ]\n            }\n        },\n        {\n            \"id\": \"forrest\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"landcover\",\n            \"filter\": [\n                \"==\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                \"wood\"\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    \"hsl(124, 42%, 86%)\",\n                    11,\n                    \"hsl(107, 47%, 94%)\",\n                    12.5,\n                    \"hsl(107, 47%, 94%)\",\n                    13.5,\n                    \"hsl(45, 12%, 93%)\"\n                ]\n            }\n        },\n        {\n            \"id\": \"national_park\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"park\",\n            \"filter\": [\n                \"all\"\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": \"hsl(106, 58%, 85%)\",\n                \"fill-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    1,\n                    11.5,\n                    0\n                ]\n            }\n        },\n        {\n            \"id\": \"snow\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"landcover\",\n            \"minzoom\": 6,\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"ice\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": \"#f9fafc\"\n            }\n        },\n        {\n            \"id\": \"park\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"poi.park\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"landcover\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"subclass\"\n                ],\n                [\n                    \"scrub\",\n                    \"park\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": \"#c1ecaf\"\n            }\n        },\n        {\n            \"id\": \"pitch\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"landscape.natural.terrain\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"landuse\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"pitch\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": \"#c8efbb\"\n            }\n        },\n        {\n            \"id\": \"landuse\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"landuse\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"school\",\n                    \"hospital\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": \"hsl(202, 26%, 94%)\"\n            }\n        },\n        {\n            \"id\": \"airport\",\n            \"type\": \"fill\",\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"aeroway\",\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": \"hsl(202, 26%, 94%)\"\n            },\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"transit.station.airport\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"path\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\",\n                \"maputnik:comment\": \"unpaved paths\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"minzoom\": 14,\n            \"maxzoom\": 24,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"path\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsl(118, 34%, 66%)\",\n                \"line-dasharray\": [\n                    4,\n                    2\n                ]\n            }\n        },\n        {\n            \"id\": \"waterway-other\",\n            \"type\": \"line\",\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"waterway\",\n            \"filter\": [\n                \"!in\",\n                \"class\",\n                \"canal\",\n                \"river\",\n                \"stream\"\n            ],\n            \"layout\": {\n                \"line-cap\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"hsl(206, 100%, 83%)\",\n                \"line-width\": {\n                    \"base\": 1.3,\n                    \"stops\": [\n                        [\n                            13,\n                            0.5\n                        ],\n                        [\n                            20,\n                            2\n                        ]\n                    ]\n                }\n            },\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"waterway-stream-canal\",\n            \"type\": \"line\",\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"waterway\",\n            \"filter\": [\n                \"in\",\n                \"class\",\n                \"canal\",\n                \"stream\"\n            ],\n            \"layout\": {\n                \"line-cap\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"hsl(206, 100%, 83%)\",\n                \"line-width\": {\n                    \"base\": 1.3,\n                    \"stops\": [\n                        [\n                            13,\n                            0.5\n                        ],\n                        [\n                            20,\n                            6\n                        ]\n                    ]\n                }\n            },\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"waterway-river\",\n            \"type\": \"line\",\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"waterway\",\n            \"filter\": [\n                \"==\",\n                \"class\",\n                \"river\"\n            ],\n            \"layout\": {\n                \"line-cap\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"hsl(206, 100%, 83%)\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            10,\n                            0.8\n                        ],\n                        [\n                            20,\n                            6\n                        ]\n                    ]\n                }\n            },\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"water-offset\",\n            \"type\": \"fill\",\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"water\",\n            \"minzoom\": 6,\n            \"maxzoom\": 8,\n            \"filter\": [\n                \"==\",\n                \"$type\",\n                \"Polygon\"\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": \"hsl(206, 100%, 83%)\",\n                \"fill-opacity\": 1,\n                \"fill-translate\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            6,\n                            [\n                                2,\n                                0\n                            ]\n                        ],\n                        [\n                            8,\n                            [\n                                0,\n                                0\n                            ]\n                        ]\n                    ]\n                }\n            },\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"water\",\n            \"type\": \"fill\",\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"water\",\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": \"hsl(206, 100%, 83%)\"\n            },\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"steps\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"subclass\"\n                ],\n                [\n                    \"steps\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsl(118, 5%, 66%)\",\n                \"line-dasharray\": [\n                    1,\n                    1\n                ],\n                \"line-gap-width\": 1\n            }\n        },\n        {\n            \"id\": \"platform\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"transit.station.rail\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"platform\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"brunnel\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    false,\n                    true\n                ]\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    \"hsl(2, 20%, 92%)\",\n                    16,\n                    \"hsl(2, 95%, 92%)\"\n                ],\n                \"fill-outline-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    \"hsl(1, 10%, 76%)\",\n                    16,\n                    \"hsl(1, 74%, 76%)\"\n                ],\n                \"fill-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0,\n                    16,\n                    1\n                ]\n            }\n        },\n        {\n            \"id\": \"primary_tunnel_border\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"brun\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    7,\n                    0,\n                    8,\n                    1,\n                    12,\n                    4,\n                    14,\n                    6,\n                    16,\n                    10,\n                    22,\n                    64\n                ],\n                \"line-color\": \"#cbcccd\"\n            }\n        },\n        {\n            \"id\": \"primary_tunnel\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"brunnel\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    1,\n                    12,\n                    4,\n                    14,\n                    6,\n                    16,\n                    10,\n                    22,\n                    64\n                ],\n                \"line-color\": \"hsl(0, 0%, 89%)\"\n            }\n        },\n        {\n            \"id\": \"aeroway\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"transit.station.airport\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"aeroway\",\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"line-color\": \"hsla(0, 0%, 0%, 0.1)\"\n            }\n        },\n        {\n            \"id\": \"service_road\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"service\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsla(0, 0%, 0%, 0.1)\"\n            }\n        },\n        {\n            \"id\": \"pedestrian_border\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"pedestrian\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"surface\"\n                    ],\n                    \"paved\"\n                ]\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    13,\n                    1,\n                    16,\n                    4,\n                    22,\n                    32\n                ],\n                \"line-color\": \"#e3e3e3\",\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12.5,\n                    0,\n                    13.5,\n                    1\n                ]\n            }\n        },\n        {\n            \"id\": \"street_border\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"minor\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    1,\n                    16,\n                    6,\n                    22,\n                    40\n                ],\n                \"line-color\": \"#e3e3e3\"\n            }\n        },\n        {\n            \"id\": \"secondary_border\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\",\n                \"maputnik:comment\": \"ok\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"secondary\",\n                    \"tertiary\",\n                    \"trunk\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    10,\n                    1,\n                    17,\n                    10,\n                    22,\n                    48\n                ],\n                \"line-color\": \"#e3e3e3\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    16,\n                    1,\n                    20,\n                    2\n                ]\n            }\n        },\n        {\n            \"id\": \"primary_border\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"brunnel\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    false,\n                    true\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": \"round\"\n            },\n            \"paint\": {\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    1,\n                    16,\n                    8,\n                    22,\n                    64\n                ],\n                \"line-color\": \"#ecd283\"\n            }\n        },\n        {\n            \"id\": \"motorway_border\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"motorway\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    1,\n                    15.5,\n                    8,\n                    22,\n                    78\n                ],\n                \"line-color\": \"#ecd283\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    1,\n                    15,\n                    2\n                ]\n            }\n        },\n        {\n            \"id\": \"railway\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"rail\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"brunnel\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    false,\n                    true\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsl(220, 4%, 85%)\"\n            }\n        },\n        {\n            \"id\": \"pedestrian\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"pedestrian\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"surface\"\n                    ],\n                    \"paved\"\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"#ffffff\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    13,\n                    1,\n                    16,\n                    4,\n                    22,\n                    32\n                ],\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12.5,\n                    0,\n                    13.5,\n                    1\n                ]\n            }\n        },\n        {\n            \"id\": \"street\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"minor\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"#ffffff\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    1,\n                    16,\n                    6,\n                    22,\n                    40\n                ]\n            }\n        },\n        {\n            \"id\": \"secondary\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"secondary\",\n                    \"tertiary\",\n                    \"trunk\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"#ffffff\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    10,\n                    1,\n                    17,\n                    10,\n                    22,\n                    48\n                ]\n            }\n        },\n        {\n            \"id\": \"primary\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"brunnel\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    false,\n                    true\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"hsl(50, 100%, 75%)\",\n                    7,\n                    \"hsl(50, 100%, 85%)\"\n                ],\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    1,\n                    16,\n                    8,\n                    22,\n                    64\n                ]\n            }\n        },\n        {\n            \"id\": \"motorway\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"motorway\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"#ffeba3\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    1,\n                    15.5,\n                    8,\n                    22,\n                    78\n                ]\n            }\n        },\n        {\n            \"id\": \"primary_bridge_border\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"brunnel\"\n                    ],\n                    [\n                        \"bridge\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    1,\n                    16,\n                    8,\n                    22,\n                    64\n                ],\n                \"line-color\": \"hsl(45, 73%, 72%)\"\n            }\n        },\n        {\n            \"id\": \"primary_bridge\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"brunnel\"\n                    ],\n                    [\n                        \"bridge\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"hsl(50, 100%, 75%)\",\n                    7,\n                    \"hsl(50, 100%, 85%)\"\n                ],\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    1,\n                    16,\n                    8,\n                    22,\n                    64\n                ]\n            }\n        },\n        {\n            \"id\": \"building\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"29bb589e8d1b9b402583363648b70302\",\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"building\",\n            \"filter\": [\n                \"all\"\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": \"#ededed\",\n                \"fill-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    0,\n                    17,\n                    1\n                ]\n            }\n        },\n        {\n            \"id\": \"building_border\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"29bb589e8d1b9b402583363648b70302\",\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"geometry.stroke\",\n                \"maputnik:comment\": \"#f8e1c7 for store, retail, church, kiosk, civic, commercial, hotel, supermarket, pub could not be ported (no appropriate metadata in `building` style spec)\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"building\",\n            \"filter\": [\n                \"all\"\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    [\n                        \"store\",\n                        \"retail\",\n                        \"church\",\n                        \"kiosk\",\n                        \"civic\",\n                        \"commercial\",\n                        \"hotel\",\n                        \"supermarket\",\n                        \"pub\"\n                    ],\n                    \"#f8e1c7\",\n                    \"#dcdcdc\"\n                ],\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    0,\n                    17,\n                    1\n                ]\n            }\n        },\n        {\n            \"id\": \"building_3d\",\n            \"type\": \"fill-extrusion\",\n            \"metadata\": {\n                \"mapbox:group\": \"29bb589e8d1b9b402583363648b70302\",\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"building\",\n            \"filter\": [\n                \"!=\",\n                [\n                    \"get\",\n                    \"hide_3d\"\n                ],\n                true\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"fill-extrusion-height\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    0,\n                    16,\n                    [\n                        \"get\",\n                        \"render_height\"\n                    ]\n                ],\n                \"fill-extrusion-opacity\": 0.3,\n                \"fill-extrusion-color\": \"hsl(0, 0%, 93%)\"\n            }\n        },\n        {\n            \"id\": \"admin_0\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3c26e9cbc75335c6f0ba8de5439cf1fa\",\n                \"microg:gms-type-feature\": \"administrative.country\",\n                \"microg:gms-type-element\": \"geometry.stroke\",\n                \"maputnik:comment\": \"maritime=false filter could not be ported due to missing attributes in `boundary` layer\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"boundary\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"admin_level\"\n                    ],\n                    [\n                        2\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"!=\",\n                    [\n                        \"get\",\n                        \"maritime\"\n                    ],\n                    1\n                ]\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"line-color\": [\n                    \"case\",\n                    [\n                        \"==\",\n                        [\n                            \"get\",\n                            \"disputed\"\n                        ],\n                        1\n                    ],\n                    \"hsl(0, 24%, 48%)\",\n                    \"#787a7b\"\n                ]\n            }\n        },\n        {\n            \"id\": \"admin_1\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3c26e9cbc75335c6f0ba8de5439cf1fa\",\n                \"microg:gms-type-feature\": \"administrative.province\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"boundary\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"admin_level\"\n                    ],\n                    [\n                        3,\n                        4\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"!=\",\n                    [\n                        \"get\",\n                        \"maritime\"\n                    ],\n                    1\n                ]\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"line-color\": [\n                    \"case\",\n                    [\n                        \"==\",\n                        [\n                            \"get\",\n                            \"disputed\"\n                        ],\n                        1\n                    ],\n                    \"hsl(0, 24%, 48%)\",\n                    \"#787a7b\"\n                ],\n                \"line-dasharray\": [\n                    1,\n                    1\n                ]\n            }\n        },\n        {\n            \"id\": \"river_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"waterway\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"river\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"symbol-placement\": \"line\",\n                \"symbol-spacing\": 500,\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ]\n            },\n            \"paint\": {\n                \"text-color\": \"#5083c1\",\n                \"text-halo-color\": \"#5083c1\",\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"city_label_right\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"maxzoom\": 8,\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    [\n                        \"*\",\n                        [\n                            \"zoom\"\n                        ],\n                        1.5\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"city\",\n                        \"town\",\n                        \"village\",\n                        \"hamlet\",\n                        \"suburb\",\n                        \"quarter\",\n                        \"neighbourhood\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-optional\": false,\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"-\",\n                        14,\n                        [\n                            \"max\",\n                            0,\n                            [\n                                \"-\",\n                                [\n                                    \"get\",\n                                    \"rank\"\n                                ],\n                                8\n                            ]\n                        ]\n                    ],\n                    22,\n                    [\n                        \"-\",\n                        20,\n                        [\n                            \"/\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            4\n                        ]\n                    ]\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"capital\"\n                    ],\n                    [\n                        2\n                    ],\n                    \"capital\",\n                    \"city\"\n                ],\n                \"text-font\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\"\n                        ]\n                    ],\n                    10,\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Regular\"\n                        ]\n                    ]\n                ],\n                \"text-justify\": \"left\",\n                \"text-offset\": [\n                    0.5,\n                    0.1\n                ],\n                \"icon-size\": [\n                    \"/\",\n                    6,\n                    [\n                        \"+\",\n                        [\n                            \"get\",\n                            \"rank\"\n                        ],\n                        7\n                    ]\n                ],\n                \"text-anchor\": \"left\",\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"*\",\n                                [\n                                    \"get\",\n                                    \"rank\"\n                                ],\n                                2\n                            ],\n                            5\n                        ],\n                        \"%)\"\n                    ],\n                    22,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            25\n                        ],\n                        \"%)\"\n                    ]\n                ],\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"text-halo-color\": \"hsl(0, 0%, 100%)\",\n                \"icon-opacity\": 0.8\n            }\n        },\n        {\n            \"id\": \"city_label_left\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"maxzoom\": 8,\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    [\n                        \"*\",\n                        [\n                            \"zoom\"\n                        ],\n                        1.5\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"city\",\n                        \"town\",\n                        \"village\",\n                        \"hamlet\",\n                        \"suburb\",\n                        \"quarter\",\n                        \"neighbourhood\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"-\",\n                        14,\n                        [\n                            \"max\",\n                            0,\n                            [\n                                \"-\",\n                                [\n                                    \"get\",\n                                    \"rank\"\n                                ],\n                                8\n                            ]\n                        ]\n                    ],\n                    22,\n                    [\n                        \"-\",\n                        20,\n                        [\n                            \"/\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            4\n                        ]\n                    ]\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"capital\"\n                    ],\n                    [\n                        2\n                    ],\n                    \"capital\",\n                    \"city\"\n                ],\n                \"text-font\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\"\n                        ]\n                    ],\n                    10,\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Regular\"\n                        ]\n                    ]\n                ],\n                \"text-justify\": \"right\",\n                \"text-offset\": [\n                    -0.5,\n                    0.1\n                ],\n                \"icon-size\": [\n                    \"/\",\n                    6,\n                    [\n                        \"+\",\n                        [\n                            \"get\",\n                            \"rank\"\n                        ],\n                        7\n                    ]\n                ],\n                \"text-anchor\": \"right\",\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"*\",\n                                [\n                                    \"get\",\n                                    \"rank\"\n                                ],\n                                2\n                            ],\n                            5\n                        ],\n                        \"%)\"\n                    ],\n                    22,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            25\n                        ],\n                        \"%)\"\n                    ]\n                ],\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"text-halo-color\": \"hsl(0, 0%, 100%)\",\n                \"icon-opacity\": 0.8\n            }\n        },\n        {\n            \"id\": \"city_label_below\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"maxzoom\": 8,\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    [\n                        \"/\",\n                        [\n                            \"zoom\"\n                        ],\n                        3\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"city\",\n                        \"town\",\n                        \"village\",\n                        \"hamlet\",\n                        \"suburb\",\n                        \"quarter\",\n                        \"neighbourhood\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"-\",\n                        14,\n                        [\n                            \"max\",\n                            0,\n                            [\n                                \"-\",\n                                [\n                                    \"get\",\n                                    \"rank\"\n                                ],\n                                8\n                            ]\n                        ]\n                    ],\n                    22,\n                    [\n                        \"-\",\n                        20,\n                        [\n                            \"/\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            4\n                        ]\n                    ]\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"capital\"\n                    ],\n                    [\n                        2\n                    ],\n                    \"capital\",\n                    \"city\"\n                ],\n                \"text-font\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\"\n                        ]\n                    ],\n                    10,\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Regular\"\n                        ]\n                    ]\n                ],\n                \"text-offset\": [\n                    0,\n                    0.4\n                ],\n                \"icon-size\": [\n                    \"/\",\n                    6,\n                    [\n                        \"+\",\n                        [\n                            \"get\",\n                            \"rank\"\n                        ],\n                        7\n                    ]\n                ],\n                \"text-anchor\": \"top\",\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"*\",\n                                [\n                                    \"get\",\n                                    \"rank\"\n                                ],\n                                2\n                            ],\n                            5\n                        ],\n                        \"%)\"\n                    ],\n                    22,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            25\n                        ],\n                        \"%)\"\n                    ]\n                ],\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"text-halo-color\": \"hsl(0, 0%, 100%)\",\n                \"icon-opacity\": 0.8\n            }\n        },\n        {\n            \"id\": \"city_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    [\n                        \"*\",\n                        [\n                            \"zoom\"\n                        ],\n                        1.5\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"city\",\n                        \"town\",\n                        \"village\",\n                        \"hamlet\",\n                        \"suburb\",\n                        \"quarter\",\n                        \"neighbourhood\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"-\",\n                        14,\n                        [\n                            \"max\",\n                            0,\n                            [\n                                \"-\",\n                                [\n                                    \"get\",\n                                    \"rank\"\n                                ],\n                                8\n                            ]\n                        ]\n                    ],\n                    22,\n                    [\n                        \"-\",\n                        20,\n                        [\n                            \"/\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            4\n                        ]\n                    ]\n                ],\n                \"icon-image\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"capital\"\n                        ],\n                        [\n                            2\n                        ],\n                        \"capital\",\n                        \"city\"\n                    ],\n                    8,\n                    \"\"\n                ],\n                \"text-transform\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    \"none\",\n                    15,\n                    \"uppercase\"\n                ],\n                \"text-font\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\"\n                        ]\n                    ],\n                    10,\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Regular\"\n                        ]\n                    ]\n                ],\n                \"text-offset\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            0,\n                            -0.2\n                        ]\n                    ],\n                    8,\n                    [\n                        \"literal\",\n                        [\n                            0,\n                            0\n                        ]\n                    ]\n                ],\n                \"icon-size\": [\n                    \"/\",\n                    6,\n                    [\n                        \"+\",\n                        [\n                            \"get\",\n                            \"rank\"\n                        ],\n                        7\n                    ]\n                ],\n                \"text-anchor\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"bottom\",\n                    8,\n                    \"center\"\n                ],\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-letter-spacing\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    0,\n                    0,\n                    8,\n                    0,\n                    12,\n                    0.1,\n                    16,\n                    0.2\n                ],\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"*\",\n                                [\n                                    \"get\",\n                                    \"rank\"\n                                ],\n                                2\n                            ],\n                            5\n                        ],\n                        \"%)\"\n                    ],\n                    22,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            25\n                        ],\n                        \"%)\"\n                    ]\n                ],\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"text-halo-color\": \"hsl(0, 0%, 100%)\",\n                \"icon-opacity\": 0.8\n            }\n        },\n        {\n            \"id\": \"park_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"poi.park\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"poi\",\n            \"minzoom\": 17,\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"park\",\n                        \"cemetery\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    250\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-size\": 14\n            },\n            \"paint\": {\n                \"text-color\": \"#297925\",\n                \"text-halo-color\": \"hsl(0, 0%, 100%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"road-number-shield\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road\",\n                \"microg:gms-type-element\": \"labels.icon\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation_name\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"ref\"\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"ref_length\"\n                    ],\n                    6\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": 9,\n                \"icon-image\": [\n                    \"case\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"network\"\n                        ],\n                        [\n                            \"us-interstate\"\n                        ],\n                        true,\n                        false\n                    ],\n                    [\n                        \"concat\",\n                        \"shield_\",\n                        [\n                            \"get\",\n                            \"network\"\n                        ],\n                        \"_\",\n                        [\n                            \"get\",\n                            \"ref_length\"\n                        ]\n                    ],\n                    [\n                        \"concat\",\n                        \"shield_rectangle-white_\",\n                        [\n                            \"get\",\n                            \"ref_length\"\n                        ]\n                    ]\n                ],\n                \"icon-rotation-alignment\": \"viewport\",\n                \"text-font\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"shield_text_color\"\n                    ],\n                    [\n                        \"white\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Bold\"\n                        ]\n                    ],\n                    [\n                        \"black\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\"\n                        ]\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Bold\"\n                        ]\n                    ]\n                ],\n                \"symbol-placement\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"point\",\n                    11,\n                    \"line\"\n                ],\n                \"text-offset\": [\n                    0,\n                    0.1\n                ],\n                \"text-rotation-alignment\": \"viewport\",\n                \"icon-size\": 0.75,\n                \"text-field\": [\n                    \"get\",\n                    \"ref\"\n                ],\n                \"text-letter-spacing\": 0.05,\n                \"visibility\": \"visible\",\n                \"icon-padding\": 10\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"case\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"network\"\n                        ],\n                        [\n                            \"us-interstate\"\n                        ],\n                        true,\n                        false\n                    ],\n                    \"#ffffff\",\n                    \"#000000\"\n                ]\n            }\n        },\n        {\n            \"id\": \"country_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"administrative.country\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"country\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {\n                \"text-letter-spacing\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    1,\n                    0,\n                    3,\n                    0.15\n                ],\n                \"text-font\": [\n                    \"Roboto Medium\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.2\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    1,\n                    12,\n                    7,\n                    [\n                        \"/\",\n                        30,\n                        [\n                            \"get\",\n                            \"rank\"\n                        ]\n                    ]\n                ],\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(0, 0%, 10%)\",\n                \"text-halo-color\": \"hsl(0, 0%, 100%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"text-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    6,\n                    1,\n                    7,\n                    0\n                ]\n            }\n        },\n        {\n            \"id\": \"pedestrian_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation_name\",\n            \"minzoom\": 16,\n            \"filter\": [\n                \"any\",\n                [\n                    \"all\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"subclass\"\n                        ],\n                        [\n                            \"pedestrian\"\n                        ],\n                        true,\n                        false\n                    ],\n                    [\n                        \"==\",\n                        [\n                            \"get\",\n                            \"surface\"\n                        ],\n                        \"paved\"\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    \"platform\",\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"name\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    17,\n                    10,\n                    22,\n                    14\n                ],\n                \"text-padding\": 5\n            },\n            \"paint\": {\n                \"text-color\": \"#575757\",\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"street_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation_name\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"minor\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"name\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    6,\n                    16,\n                    10\n                ],\n                \"text-padding\": 5\n            },\n            \"paint\": {\n                \"text-color\": \"#575757\",\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"secondary_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation_name\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"secondary\",\n                        \"tertiary\",\n                        \"trunk\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"name\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    8,\n                    16,\n                    13\n                ],\n                \"symbol-spacing\": 300,\n                \"text-padding\": 25\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(196, 0%, 34%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"primary_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation_name\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"name\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    10,\n                    18,\n                    14\n                ],\n                \"symbol-spacing\": 800,\n                \"text-padding\": 50\n            },\n            \"paint\": {\n                \"text-color\": \"#6e481d\",\n                \"text-halo-width\": 1,\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"poi_label_below\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"124a9d7a8e5226775d947c592110dfad\",\n                \"microg:gms-type-element\": \"labels.text\",\n                \"microg:gms-type-feature\": \"poi\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"poi\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"bus\",\n                        \"railway\"\n                    ],\n                    false,\n                    true\n                ],\n                [\n                    \"any\",\n                    [\n                        \"!=\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ],\n                            [\n                                \"park\",\n                                \"cemetery\"\n                            ],\n                            true,\n                            false\n                        ],\n                        [\n                            \"<=\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            250\n                        ]\n                    ],\n                    [\n                        \">=\",\n                        [\n                            \"zoom\"\n                        ],\n                        16\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-optional\": false,\n                \"text-line-height\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    15,\n                    1.2\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    13,\n                    15,\n                    14\n                ],\n                \"icon-offset\": [\n                    0,\n                    -36\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"museum\",\n                        \"theatre\",\n                        \"restaurant\"\n                    ],\n                    [\n                        \"concat\",\n                        \"poi_\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ]\n                    ],\n                    [\n                        \"fitness_centre\",\n                        \"golf_course\",\n                        \"camp_site\",\n                        \"bowling_alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic_site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog_park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"poi_generic_green\",\n                    [\n                        \"bank\",\n                        \"atm\",\n                        \"parking\",\n                        \"toilets\",\n                        \"garages\"\n                    ],\n                    \"poi_generic_purple\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\"\n                    ],\n                    \"poi_generic_orange\",\n                    [\n                        \"casino\",\n                        \"castle\",\n                        \"gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music_venue\",\n                        \"monument\"\n                    ],\n                    \"poi_generic_teal\",\n                    [\n                        \"hospital\",\n                        \"doctors\"\n                    ],\n                    \"poi_generic_red\",\n                    [\n                        \"fast_food\",\n                        \"ice_cream\"\n                    ],\n                    \"poi_restaurant\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"lodging\",\n                            \"grocery\"\n                        ],\n                        [\n                            \"concat\",\n                            \"poi_\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ]\n                        ],\n                        [\n                            \"clothing_store\",\n                            \"shop\"\n                        ],\n                        \"poi_generic_blue\",\n                        \"poi_generic\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-offset\": [\n                    0,\n                    0.5\n                ],\n                \"icon-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.25,\n                    15,\n                    0.32\n                ],\n                \"text-anchor\": \"top\",\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-padding\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    30,\n                    17,\n                    5\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"fitness_centre\",\n                        \"golf_course\",\n                        \"camp_site\",\n                        \"bowling_alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic_site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog_park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"hsl(117, 53%, 31%)\",\n                    [\n                        \"bank\",\n                        \"atm\",\n                        \"parking\",\n                        \"toilets\",\n                        \"garages\"\n                    ],\n                    \"#737b9b\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\",\n                        \"fast_food\",\n                        \"restaurant\",\n                        \"ice_cream\"\n                    ],\n                    \"#c77d57\",\n                    [\n                        \"museum\",\n                        \"theatre\",\n                        \"casino\",\n                        \"castle\",\n                        \"gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music_venue\",\n                        \"monument\"\n                    ],\n                    \"hsl(186, 78%, 44%)\",\n                    [\n                        \"hospital\",\n                        \"doctors\"\n                    ],\n                    \"#a47172\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"lodging\"\n                        ],\n                        \"#df7db1\",\n                        [\n                            \"grocery\",\n                            \"clothing_store\",\n                            \"shop\"\n                        ],\n                        \"hsl(213, 40%, 48%)\",\n                        \"#67747b\"\n                    ]\n                ],\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1,\n                \"icon-translate\": [\n                    0,\n                    0\n                ],\n                \"text-translate\": [\n                    0,\n                    0\n                ],\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"poi_label_above\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"124a9d7a8e5226775d947c592110dfad\",\n                \"microg:gms-type-element\": \"labels.text\",\n                \"microg:gms-type-feature\": \"poi\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"poi\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"bus\",\n                        \"railway\"\n                    ],\n                    false,\n                    true\n                ],\n                [\n                    \"any\",\n                    [\n                        \"!=\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ],\n                            [\n                                \"park\",\n                                \"cemetery\"\n                            ],\n                            true,\n                            false\n                        ],\n                        [\n                            \"<=\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            250\n                        ]\n                    ],\n                    [\n                        \">=\",\n                        [\n                            \"zoom\"\n                        ],\n                        16\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-optional\": false,\n                \"text-line-height\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    15,\n                    1.2\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    13,\n                    15,\n                    14\n                ],\n                \"icon-offset\": [\n                    0,\n                    -36\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"museum\",\n                        \"theatre\",\n                        \"restaurant\"\n                    ],\n                    [\n                        \"concat\",\n                        \"poi_\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ]\n                    ],\n                    [\n                        \"fitness_centre\",\n                        \"golf_course\",\n                        \"camp_site\",\n                        \"bowling_alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic_site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog_park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"poi_generic_green\",\n                    [\n                        \"bank\",\n                        \"atm\",\n                        \"parking\",\n                        \"toilets\",\n                        \"garages\"\n                    ],\n                    \"poi_generic_purple\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\"\n                    ],\n                    \"poi_generic_orange\",\n                    [\n                        \"casino\",\n                        \"castle\",\n                        \"gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music_venue\",\n                        \"monument\"\n                    ],\n                    \"poi_generic_teal\",\n                    [\n                        \"hospital\",\n                        \"doctors\"\n                    ],\n                    \"poi_generic_red\",\n                    [\n                        \"fast_food\",\n                        \"ice_cream\"\n                    ],\n                    \"poi_restaurant\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"lodging\",\n                            \"grocery\"\n                        ],\n                        [\n                            \"concat\",\n                            \"poi_\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ]\n                        ],\n                        [\n                            \"clothing_store\",\n                            \"shop\"\n                        ],\n                        \"poi_generic_blue\",\n                        \"poi_generic\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-offset\": [\n                    0,\n                    -2\n                ],\n                \"icon-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.25,\n                    15,\n                    0.32\n                ],\n                \"text-anchor\": \"bottom\",\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-padding\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    30,\n                    17,\n                    5\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"fitness_centre\",\n                        \"golf_course\",\n                        \"camp_site\",\n                        \"bowling_alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic_site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog_park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"hsl(117, 53%, 31%)\",\n                    [\n                        \"bank\",\n                        \"atm\",\n                        \"parking\",\n                        \"toilets\",\n                        \"garages\"\n                    ],\n                    \"#737b9b\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\",\n                        \"fast_food\",\n                        \"restaurant\",\n                        \"ice_cream\"\n                    ],\n                    \"#c77d57\",\n                    [\n                        \"museum\",\n                        \"theatre\",\n                        \"casino\",\n                        \"castle\",\n                        \"gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music_venue\",\n                        \"monument\"\n                    ],\n                    \"hsl(186, 78%, 44%)\",\n                    [\n                        \"hospital\",\n                        \"doctors\"\n                    ],\n                    \"#a47172\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"lodging\"\n                        ],\n                        \"#df7db1\",\n                        [\n                            \"grocery\",\n                            \"clothing_store\",\n                            \"shop\"\n                        ],\n                        \"hsl(213, 40%, 48%)\",\n                        \"#67747b\"\n                    ]\n                ],\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1,\n                \"icon-translate\": [\n                    0,\n                    0\n                ],\n                \"text-translate\": [\n                    0,\n                    0\n                ],\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"poi_label_left\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"124a9d7a8e5226775d947c592110dfad\",\n                \"microg:gms-type-element\": \"labels.text\",\n                \"microg:gms-type-feature\": \"poi\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"poi\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"bus\",\n                        \"railway\"\n                    ],\n                    false,\n                    true\n                ],\n                [\n                    \"any\",\n                    [\n                        \"!=\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ],\n                            [\n                                \"park\",\n                                \"cemetery\"\n                            ],\n                            true,\n                            false\n                        ],\n                        [\n                            \"<=\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            250\n                        ]\n                    ],\n                    [\n                        \">=\",\n                        [\n                            \"zoom\"\n                        ],\n                        16\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-line-height\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    15,\n                    1.2\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    13,\n                    15,\n                    14\n                ],\n                \"icon-offset\": [\n                    0,\n                    -36\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"museum\",\n                        \"theatre\",\n                        \"restaurant\"\n                    ],\n                    [\n                        \"concat\",\n                        \"poi_\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ]\n                    ],\n                    [\n                        \"fitness_centre\",\n                        \"golf_course\",\n                        \"camp_site\",\n                        \"bowling_alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic_site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog_park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"poi_generic_green\",\n                    [\n                        \"bank\",\n                        \"atm\",\n                        \"parking\",\n                        \"toilets\",\n                        \"garages\"\n                    ],\n                    \"poi_generic_purple\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\"\n                    ],\n                    \"poi_generic_orange\",\n                    [\n                        \"casino\",\n                        \"castle\",\n                        \"gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music_venue\",\n                        \"monument\"\n                    ],\n                    \"poi_generic_teal\",\n                    [\n                        \"hospital\",\n                        \"doctors\"\n                    ],\n                    \"poi_generic_red\",\n                    [\n                        \"fast_food\",\n                        \"ice_cream\"\n                    ],\n                    \"poi_restaurant\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"lodging\",\n                            \"grocery\"\n                        ],\n                        [\n                            \"concat\",\n                            \"poi_\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ]\n                        ],\n                        [\n                            \"clothing_store\",\n                            \"shop\"\n                        ],\n                        \"poi_generic_blue\",\n                        \"poi_generic\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-justify\": \"right\",\n                \"text-offset\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    [\n                        \"literal\",\n                        [\n                            -1.1,\n                            -0.7\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            -1.1,\n                            -0.9\n                        ]\n                    ]\n                ],\n                \"icon-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.25,\n                    15,\n                    0.32\n                ],\n                \"text-anchor\": \"right\",\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-padding\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    30,\n                    17,\n                    5\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"fitness_centre\",\n                        \"golf_course\",\n                        \"camp_site\",\n                        \"bowling_alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic_site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog_park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"hsl(117, 53%, 31%)\",\n                    [\n                        \"bank\",\n                        \"atm\",\n                        \"parking\",\n                        \"toilets\",\n                        \"garages\"\n                    ],\n                    \"#737b9b\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\",\n                        \"fast_food\",\n                        \"restaurant\",\n                        \"ice_cream\"\n                    ],\n                    \"#c77d57\",\n                    [\n                        \"museum\",\n                        \"theatre\",\n                        \"casino\",\n                        \"castle\",\n                        \"gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music_venue\",\n                        \"monument\"\n                    ],\n                    \"hsl(186, 78%, 44%)\",\n                    [\n                        \"hospital\",\n                        \"doctors\"\n                    ],\n                    \"#a47172\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"lodging\"\n                        ],\n                        \"#df7db1\",\n                        [\n                            \"grocery\",\n                            \"clothing_store\",\n                            \"shop\"\n                        ],\n                        \"hsl(213, 40%, 48%)\",\n                        \"#67747b\"\n                    ]\n                ],\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1,\n                \"icon-translate\": [\n                    0,\n                    0\n                ],\n                \"text-translate\": [\n                    0,\n                    0\n                ],\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"poi_label_right\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"124a9d7a8e5226775d947c592110dfad\",\n                \"microg:gms-type-element\": \"labels.text\",\n                \"microg:gms-type-feature\": \"poi\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"poi\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"bus\",\n                        \"railway\"\n                    ],\n                    false,\n                    true\n                ],\n                [\n                    \"any\",\n                    [\n                        \"!=\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ],\n                            [\n                                \"park\",\n                                \"cemetery\"\n                            ],\n                            true,\n                            false\n                        ],\n                        [\n                            \"<=\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            250\n                        ]\n                    ],\n                    [\n                        \">=\",\n                        [\n                            \"zoom\"\n                        ],\n                        16\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-line-height\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    15,\n                    1.2\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    13,\n                    15,\n                    14\n                ],\n                \"icon-offset\": [\n                    0,\n                    -36\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"museum\",\n                        \"theatre\",\n                        \"restaurant\"\n                    ],\n                    [\n                        \"concat\",\n                        \"poi_\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ]\n                    ],\n                    [\n                        \"fitness_centre\",\n                        \"golf_course\",\n                        \"camp_site\",\n                        \"bowling_alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic_site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog_park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"poi_generic_green\",\n                    [\n                        \"bank\",\n                        \"atm\",\n                        \"parking\",\n                        \"toilets\",\n                        \"garages\"\n                    ],\n                    \"poi_generic_purple\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\"\n                    ],\n                    \"poi_generic_orange\",\n                    [\n                        \"casino\",\n                        \"castle\",\n                        \"gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music_venue\",\n                        \"monument\"\n                    ],\n                    \"poi_generic_teal\",\n                    [\n                        \"hospital\",\n                        \"doctors\"\n                    ],\n                    \"poi_generic_red\",\n                    [\n                        \"fast_food\",\n                        \"ice_cream\"\n                    ],\n                    \"poi_restaurant\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"lodging\",\n                            \"grocery\"\n                        ],\n                        [\n                            \"concat\",\n                            \"poi_\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ]\n                        ],\n                        [\n                            \"clothing_store\",\n                            \"shop\"\n                        ],\n                        \"poi_generic_blue\",\n                        \"poi_generic\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-justify\": \"left\",\n                \"text-offset\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    [\n                        \"literal\",\n                        [\n                            1.1,\n                            -0.7\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            1.1,\n                            -0.9\n                        ]\n                    ]\n                ],\n                \"icon-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.25,\n                    15,\n                    0.32\n                ],\n                \"text-anchor\": \"left\",\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-padding\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    30,\n                    17,\n                    5\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"fitness_centre\",\n                        \"golf_course\",\n                        \"camp_site\",\n                        \"bowling_alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic_site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog_park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"hsl(117, 53%, 31%)\",\n                    [\n                        \"bank\",\n                        \"atm\",\n                        \"parking\",\n                        \"toilets\",\n                        \"garages\"\n                    ],\n                    \"#737b9b\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\",\n                        \"fast_food\",\n                        \"restaurant\",\n                        \"ice_cream\"\n                    ],\n                    \"#c77d57\",\n                    [\n                        \"museum\",\n                        \"theatre\",\n                        \"casino\",\n                        \"castle\",\n                        \"gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music_venue\",\n                        \"monument\"\n                    ],\n                    \"hsl(186, 78%, 44%)\",\n                    [\n                        \"hospital\",\n                        \"doctors\"\n                    ],\n                    \"#a47172\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"lodging\"\n                        ],\n                        \"#df7db1\",\n                        [\n                            \"grocery\",\n                            \"clothing_store\",\n                            \"shop\"\n                        ],\n                        \"hsl(213, 40%, 48%)\",\n                        \"#67747b\"\n                    ]\n                ],\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1,\n                \"icon-translate\": [\n                    0,\n                    0\n                ],\n                \"text-translate\": [\n                    0,\n                    0\n                ],\n                \"text-halo-blur\": 1\n            }\n        }\n    ],\n    \"created\": \"2019-04-15T08:41:40.148Z\",\n    \"modified\": \"2020-09-05T19:42:03.856Z\",\n    \"id\": \"cjui4020201oo1fmca7yuwbor\",\n    \"owner\": \"microg\",\n    \"visibility\": \"public\",\n    \"protected\": false,\n    \"draft\": false\n}\n"
  },
  {
    "path": "artwork/styles/style-microg-normal-stadia.json",
    "content": "{\n    \"version\": 8,\n    \"name\": \"Mountain View Full\",\n    \"metadata\": {\n        \"mapbox:origin\": \"basic-template\",\n        \"mapbox:autocomposite\": true,\n        \"mapbox:type\": \"template\",\n        \"mapbox:sdk-support\": {\n            \"js\": \"0.50.0\",\n            \"android\": \"6.7.0\",\n            \"ios\": \"4.6.0\"\n        },\n        \"mapbox:trackposition\": false,\n        \"mapbox:groups\": {\n            \"f51b507d2a17e572c70a5db74b0fec7e\": {\n                \"name\": \"Base\",\n                \"collapsed\": false\n            },\n            \"3f48b8dc54ff2e6544b9ef9cedbf2990\": {\n                \"name\": \"Streets\",\n                \"collapsed\": true\n            },\n            \"29bb589e8d1b9b402583363648b70302\": {\n                \"name\": \"Buildings\",\n                \"collapsed\": true\n            },\n            \"3c26e9cbc75335c6f0ba8de5439cf1fa\": {\n                \"name\": \"Country borders\",\n                \"collapsed\": true\n            },\n            \"7b44201d7f1682d99f7140188aff23ce\": {\n                \"name\": \"Labels\",\n                \"collapsed\": true\n            },\n            \"24306bdccbff03e2ee08d5d1a4ca7312\": {\n                \"name\": \"Street name\",\n                \"collapsed\": true\n            },\n            \"124a9d7a8e5226775d947c592110dfad\": {\n                \"name\": \"POI\",\n                \"collapsed\": true\n            }\n        },\n        \"mapbox:uiParadigm\": \"layers\",\n        \"maputnik:renderer\": \"mbgljs\"\n    },\n    \"center\": [\n        12.819420849458652,\n        50.03325860617235\n    ],\n    \"zoom\": 3.315829104862067,\n    \"bearing\": 0,\n    \"pitch\": 1.5,\n    \"light\": {\n        \"intensity\": 0.5,\n        \"color\": \"hsl(0, 0%, 100%)\",\n        \"anchor\": \"viewport\"\n    },\n    \"sources\": {\n        \"openmaptiles\": {\n            \"type\": \"vector\",\n            \"url\": \"https://tiles.stadiamaps.com/data/openmaptiles.json\"\n        },\n        \"terrain\": {\n            \"type\": \"raster-dem\",\n            \"tiles\": [\n                \"https://tiles.stadiamaps.com/data/terrarium/{z}/{x}/{y}.png\"\n            ],\n            \"minzoom\": 0,\n            \"maxzoom\": 12,\n            \"tileSize\": 256,\n            \"encoding\": \"terrarium\"\n        },\n        \"global\": {\n            \"type\": \"vector\",\n            \"tiles\": [\n                \"https://tiles.stadiamaps.com/data/global_landcover_v1/{z}/{x}/{y}.pbf\"\n            ],\n            \"minzoom\": 0,\n            \"maxzoom\": 6\n        }\n    },\n    \"sprite\": \"asset://sprites\",\n    \"glyphs\": \"asset://{fontstack}/{range}.pbf\",\n    \"layers\": [\n        {\n            \"id\": \"background\",\n            \"type\": \"background\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"background-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    4,\n                    \"hsl(43, 30%, 91%)\",\n                    5,\n                    \"hsl(0, 0%, 96%)\",\n                    8,\n                    \"hsl(0, 0%, 96%)\",\n                    9,\n                    \"#efeee8\",\n                    16,\n                    \"hsl(0, 0%, 95%)\",\n                    18,\n                    \"#f8f9fb\"\n                ]\n            }\n        },\n        {\n            \"id\": \"global_grass\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\",\n                \"maputnik:comment\": \"Stadia specific\"\n            },\n            \"source\": \"global\",\n            \"source-layer\": \"global_landcover\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"grass\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    \"hsl(124, 30%, 90%)\",\n                    11,\n                    \"hsl(107, 30%, 94%)\",\n                    12.5,\n                    \"hsl(107, 30%, 94%)\",\n                    13.5,\n                    \"hsl(45, 12%, 93%)\"\n                ]\n            }\n        },\n        {\n            \"id\": \"grass\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"landcover\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"grass\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    \"hsl(124, 30%, 90%)\",\n                    11,\n                    \"hsl(107, 30%, 94%)\",\n                    12.5,\n                    \"hsl(107, 30%, 94%)\",\n                    13.5,\n                    \"hsl(45, 12%, 93%)\"\n                ]\n            }\n        },\n        {\n            \"id\": \"global_forest\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\",\n                \"maputnik:comment\": \"Stadia specific\"\n            },\n            \"source\": \"global\",\n            \"source-layer\": \"global_landcover\",\n            \"filter\": [\n                \"==\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                \"wood\"\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    \"hsl(124, 42%, 86%)\",\n                    11,\n                    \"hsl(107, 47%, 94%)\",\n                    12.5,\n                    \"hsl(107, 47%, 94%)\",\n                    13.5,\n                    \"hsl(45, 12%, 93%)\"\n                ]\n            }\n        },\n        {\n            \"id\": \"forrest\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"landcover\",\n            \"filter\": [\n                \"==\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                \"wood\"\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    \"hsl(124, 42%, 86%)\",\n                    11,\n                    \"hsl(107, 47%, 94%)\",\n                    12.5,\n                    \"hsl(107, 47%, 94%)\",\n                    13.5,\n                    \"hsl(45, 12%, 93%)\"\n                ]\n            }\n        },\n        {\n            \"id\": \"national_park\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"park\",\n            \"filter\": [\n                \"all\"\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": \"hsl(106, 58%, 85%)\",\n                \"fill-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    1,\n                    11.5,\n                    0\n                ]\n            }\n        },\n        {\n            \"id\": \"global_snow\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"global\",\n            \"source-layer\": \"global_landcover\",\n            \"minzoom\": 0,\n            \"maxzoom\": 6,\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"ice\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": \"#f9fafc\"\n            }\n        },\n        {\n            \"id\": \"snow\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"landcover\",\n            \"minzoom\": 6,\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"ice\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": \"#f9fafc\"\n            }\n        },\n        {\n            \"id\": \"hillshade\",\n            \"type\": \"hillshade\",\n            \"source\": \"terrain\",\n            \"maxzoom\": 12,\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"hillshade-illumination-anchor\": \"viewport\",\n                \"hillshade-exaggeration\": 0.1\n            },\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.natural.terrain\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"park\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"poi.park\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"landcover\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"subclass\"\n                ],\n                [\n                    \"scrub\",\n                    \"park\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": \"#c1ecaf\"\n            }\n        },\n        {\n            \"id\": \"pitch\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"landscape.natural.terrain\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"landuse\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"pitch\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": \"#c8efbb\"\n            }\n        },\n        {\n            \"id\": \"landuse\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"landuse\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"school\",\n                    \"hospital\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": \"hsl(202, 26%, 94%)\"\n            }\n        },\n        {\n            \"id\": \"airport\",\n            \"type\": \"fill\",\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"aeroway\",\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": \"hsl(202, 26%, 94%)\"\n            },\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"transit.station.airport\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"path\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\",\n                \"maputnik:comment\": \"unpaved paths\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"minzoom\": 14,\n            \"maxzoom\": 24,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"path\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsl(118, 34%, 66%)\",\n                \"line-dasharray\": [\n                    4,\n                    2\n                ]\n            }\n        },\n        {\n            \"id\": \"waterway-other\",\n            \"type\": \"line\",\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"waterway\",\n            \"filter\": [\n                \"!in\",\n                \"class\",\n                \"canal\",\n                \"river\",\n                \"stream\"\n            ],\n            \"layout\": {\n                \"line-cap\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"hsl(206, 100%, 83%)\",\n                \"line-width\": {\n                    \"base\": 1.3,\n                    \"stops\": [\n                        [\n                            13,\n                            0.5\n                        ],\n                        [\n                            20,\n                            2\n                        ]\n                    ]\n                }\n            },\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"waterway-stream-canal\",\n            \"type\": \"line\",\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"waterway\",\n            \"filter\": [\n                \"in\",\n                \"class\",\n                \"canal\",\n                \"stream\"\n            ],\n            \"layout\": {\n                \"line-cap\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"hsl(206, 100%, 83%)\",\n                \"line-width\": {\n                    \"base\": 1.3,\n                    \"stops\": [\n                        [\n                            13,\n                            0.5\n                        ],\n                        [\n                            20,\n                            6\n                        ]\n                    ]\n                }\n            },\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"waterway-river\",\n            \"type\": \"line\",\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"waterway\",\n            \"filter\": [\n                \"==\",\n                \"class\",\n                \"river\"\n            ],\n            \"layout\": {\n                \"line-cap\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"hsl(206, 100%, 83%)\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            10,\n                            0.8\n                        ],\n                        [\n                            20,\n                            6\n                        ]\n                    ]\n                }\n            },\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"water-offset\",\n            \"type\": \"fill\",\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"water\",\n            \"minzoom\": 6,\n            \"maxzoom\": 8,\n            \"filter\": [\n                \"==\",\n                \"$type\",\n                \"Polygon\"\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": \"hsl(206, 100%, 83%)\",\n                \"fill-opacity\": 1,\n                \"fill-translate\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            6,\n                            [\n                                2,\n                                0\n                            ]\n                        ],\n                        [\n                            8,\n                            [\n                                0,\n                                0\n                            ]\n                        ]\n                    ]\n                }\n            },\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"water\",\n            \"type\": \"fill\",\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"water\",\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": \"hsl(206, 100%, 83%)\"\n            },\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"steps\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"subclass\"\n                ],\n                [\n                    \"steps\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsl(118, 5%, 66%)\",\n                \"line-dasharray\": [\n                    1,\n                    1\n                ],\n                \"line-gap-width\": 1\n            }\n        },\n        {\n            \"id\": \"platform\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"transit.station.rail\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"platform\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"brunnel\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    false,\n                    true\n                ]\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    \"hsl(2, 20%, 92%)\",\n                    16,\n                    \"hsl(2, 95%, 92%)\"\n                ],\n                \"fill-outline-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    \"hsl(1, 10%, 76%)\",\n                    16,\n                    \"hsl(1, 74%, 76%)\"\n                ],\n                \"fill-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0,\n                    16,\n                    1\n                ]\n            }\n        },\n        {\n            \"id\": \"primary_tunnel_border\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"brun\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    7,\n                    0,\n                    8,\n                    1,\n                    12,\n                    4,\n                    14,\n                    6,\n                    16,\n                    10,\n                    22,\n                    64\n                ],\n                \"line-color\": \"#cbcccd\"\n            }\n        },\n        {\n            \"id\": \"primary_tunnel\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"brunnel\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    1,\n                    12,\n                    4,\n                    14,\n                    6,\n                    16,\n                    10,\n                    22,\n                    64\n                ],\n                \"line-color\": \"hsl(0, 0%, 89%)\"\n            }\n        },\n        {\n            \"id\": \"aeroway\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"transit.station.airport\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"aeroway\",\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"line-color\": \"hsla(0, 0%, 0%, 0.1)\"\n            }\n        },\n        {\n            \"id\": \"service_road\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"service\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsla(0, 0%, 0%, 0.1)\"\n            }\n        },\n        {\n            \"id\": \"pedestrian_border\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"pedestrian\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"surface\"\n                    ],\n                    \"paved\"\n                ]\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    13,\n                    1,\n                    16,\n                    4,\n                    22,\n                    32\n                ],\n                \"line-color\": \"#e3e3e3\",\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12.5,\n                    0,\n                    13.5,\n                    1\n                ]\n            }\n        },\n        {\n            \"id\": \"street_border\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"minor\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    1,\n                    16,\n                    6,\n                    22,\n                    40\n                ],\n                \"line-color\": \"#e3e3e3\"\n            }\n        },\n        {\n            \"id\": \"secondary_border\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\",\n                \"maputnik:comment\": \"ok\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"secondary\",\n                    \"tertiary\",\n                    \"trunk\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    10,\n                    1,\n                    17,\n                    10,\n                    22,\n                    48\n                ],\n                \"line-color\": \"#e3e3e3\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    16,\n                    1,\n                    20,\n                    2\n                ]\n            }\n        },\n        {\n            \"id\": \"primary_border\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"brunnel\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    false,\n                    true\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": \"round\"\n            },\n            \"paint\": {\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    1,\n                    16,\n                    8,\n                    22,\n                    64\n                ],\n                \"line-color\": \"#ecd283\"\n            }\n        },\n        {\n            \"id\": \"motorway_border\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"motorway\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    1,\n                    15.5,\n                    8,\n                    22,\n                    78\n                ],\n                \"line-color\": \"#ecd283\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    1,\n                    15,\n                    2\n                ]\n            }\n        },\n        {\n            \"id\": \"railway\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"any\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"rail\"\n                        ],\n                        true,\n                        false\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"subclass\"\n                        ],\n                        [\n                            \"light_rail\",\n                            \"tram\"\n                        ],\n                        true,\n                        false\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"brunnel\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    false,\n                    true\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsl(220, 4%, 85%)\"\n            }\n        },\n        {\n            \"id\": \"pedestrian\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"pedestrian\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"surface\"\n                    ],\n                    \"paved\"\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"#ffffff\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    13,\n                    1,\n                    16,\n                    4,\n                    22,\n                    32\n                ],\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12.5,\n                    0,\n                    13.5,\n                    1\n                ]\n            }\n        },\n        {\n            \"id\": \"street\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"minor\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"#ffffff\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    1,\n                    16,\n                    6,\n                    22,\n                    40\n                ]\n            }\n        },\n        {\n            \"id\": \"secondary\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"secondary\",\n                    \"tertiary\",\n                    \"trunk\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"#ffffff\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    10,\n                    1,\n                    17,\n                    10,\n                    22,\n                    48\n                ]\n            }\n        },\n        {\n            \"id\": \"primary\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"brunnel\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    false,\n                    true\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"hsl(50, 100%, 75%)\",\n                    7,\n                    \"hsl(50, 100%, 85%)\"\n                ],\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    1,\n                    16,\n                    8,\n                    22,\n                    64\n                ]\n            }\n        },\n        {\n            \"id\": \"motorway\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"motorway\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"#ffeba3\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    1,\n                    15.5,\n                    8,\n                    22,\n                    78\n                ]\n            }\n        },\n        {\n            \"id\": \"primary_bridge_border\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"brunnel\"\n                    ],\n                    [\n                        \"bridge\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    1,\n                    16,\n                    8,\n                    22,\n                    64\n                ],\n                \"line-color\": \"hsl(45, 73%, 72%)\"\n            }\n        },\n        {\n            \"id\": \"primary_bridge\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"brunnel\"\n                    ],\n                    [\n                        \"bridge\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"hsl(50, 100%, 75%)\",\n                    7,\n                    \"hsl(50, 100%, 85%)\"\n                ],\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    1,\n                    16,\n                    8,\n                    22,\n                    64\n                ]\n            }\n        },\n        {\n            \"id\": \"building\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"29bb589e8d1b9b402583363648b70302\",\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"building\",\n            \"filter\": [\n                \"all\"\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": \"#ededed\",\n                \"fill-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    0,\n                    17,\n                    1\n                ]\n            }\n        },\n        {\n            \"id\": \"building_border\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"29bb589e8d1b9b402583363648b70302\",\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"geometry.stroke\",\n                \"maputnik:comment\": \"#f8e1c7 for store, retail, church, kiosk, civic, commercial, hotel, supermarket, pub could not be ported (no appropriate metadata in `building` style spec)\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"building\",\n            \"filter\": [\n                \"all\"\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    [\n                        \"store\",\n                        \"retail\",\n                        \"church\",\n                        \"kiosk\",\n                        \"civic\",\n                        \"commercial\",\n                        \"hotel\",\n                        \"supermarket\",\n                        \"pub\"\n                    ],\n                    \"#f8e1c7\",\n                    \"#dcdcdc\"\n                ],\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    0,\n                    17,\n                    1\n                ]\n            }\n        },\n        {\n            \"id\": \"building_3d\",\n            \"type\": \"fill-extrusion\",\n            \"metadata\": {\n                \"mapbox:group\": \"29bb589e8d1b9b402583363648b70302\",\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"building\",\n            \"filter\": [\n                \"!=\",\n                [\n                    \"get\",\n                    \"hide_3d\"\n                ],\n                true\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"fill-extrusion-height\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    0,\n                    16,\n                    [\n                        \"get\",\n                        \"render_height\"\n                    ]\n                ],\n                \"fill-extrusion-opacity\": 0.3,\n                \"fill-extrusion-color\": \"hsl(0, 0%, 93%)\"\n            }\n        },\n        {\n            \"id\": \"admin_0\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3c26e9cbc75335c6f0ba8de5439cf1fa\",\n                \"microg:gms-type-feature\": \"administrative.country\",\n                \"microg:gms-type-element\": \"geometry.stroke\",\n                \"maputnik:comment\": \"maritime=false filter could not be ported due to missing attributes in `boundary` layer\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"boundary\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"admin_level\"\n                    ],\n                    [\n                        2\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"!=\",\n                    [\n                        \"get\",\n                        \"maritime\"\n                    ],\n                    1\n                ]\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"line-color\": [\n                    \"case\",\n                    [\n                        \"==\",\n                        [\n                            \"get\",\n                            \"disputed\"\n                        ],\n                        1\n                    ],\n                    \"hsl(0, 24%, 48%)\",\n                    \"#787a7b\"\n                ]\n            }\n        },\n        {\n            \"id\": \"admin_1\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3c26e9cbc75335c6f0ba8de5439cf1fa\",\n                \"microg:gms-type-feature\": \"administrative.province\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"boundary\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"admin_level\"\n                    ],\n                    [\n                        3,\n                        4\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"!=\",\n                    [\n                        \"get\",\n                        \"maritime\"\n                    ],\n                    1\n                ]\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"line-color\": [\n                    \"case\",\n                    [\n                        \"==\",\n                        [\n                            \"get\",\n                            \"disputed\"\n                        ],\n                        1\n                    ],\n                    \"hsl(0, 24%, 48%)\",\n                    \"#787a7b\"\n                ],\n                \"line-dasharray\": [\n                    1,\n                    1\n                ]\n            }\n        },\n        {\n            \"id\": \"river_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"waterway\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"river\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"symbol-placement\": \"line\",\n                \"symbol-spacing\": 500,\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ]\n            },\n            \"paint\": {\n                \"text-color\": \"#5083c1\",\n                \"text-halo-color\": \"#5083c1\",\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"city_label_right\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"maxzoom\": 8,\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    [\n                        \"*\",\n                        [\n                            \"zoom\"\n                        ],\n                        1.5\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"city\",\n                        \"town\",\n                        \"village\",\n                        \"hamlet\",\n                        \"suburb\",\n                        \"quarter\",\n                        \"neighbourhood\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-optional\": false,\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"-\",\n                        14,\n                        [\n                            \"max\",\n                            0,\n                            [\n                                \"-\",\n                                [\n                                    \"get\",\n                                    \"rank\"\n                                ],\n                                8\n                            ]\n                        ]\n                    ],\n                    22,\n                    [\n                        \"-\",\n                        20,\n                        [\n                            \"/\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            4\n                        ]\n                    ]\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"capital\"\n                    ],\n                    [\n                        2\n                    ],\n                    \"capital\",\n                    \"city\"\n                ],\n                \"text-font\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\"\n                        ]\n                    ],\n                    10,\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Regular\"\n                        ]\n                    ]\n                ],\n                \"text-justify\": \"left\",\n                \"text-offset\": [\n                    0.5,\n                    0.1\n                ],\n                \"icon-size\": [\n                    \"/\",\n                    6,\n                    [\n                        \"+\",\n                        [\n                            \"get\",\n                            \"rank\"\n                        ],\n                        7\n                    ]\n                ],\n                \"text-anchor\": \"left\",\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"*\",\n                                [\n                                    \"get\",\n                                    \"rank\"\n                                ],\n                                2\n                            ],\n                            5\n                        ],\n                        \"%)\"\n                    ],\n                    22,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            25\n                        ],\n                        \"%)\"\n                    ]\n                ],\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"text-halo-color\": \"hsl(0, 0%, 100%)\",\n                \"icon-opacity\": 0.8\n            }\n        },\n        {\n            \"id\": \"city_label_left\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"maxzoom\": 8,\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    [\n                        \"*\",\n                        [\n                            \"zoom\"\n                        ],\n                        1.5\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"city\",\n                        \"town\",\n                        \"village\",\n                        \"hamlet\",\n                        \"suburb\",\n                        \"quarter\",\n                        \"neighbourhood\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"-\",\n                        14,\n                        [\n                            \"max\",\n                            0,\n                            [\n                                \"-\",\n                                [\n                                    \"get\",\n                                    \"rank\"\n                                ],\n                                8\n                            ]\n                        ]\n                    ],\n                    22,\n                    [\n                        \"-\",\n                        20,\n                        [\n                            \"/\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            4\n                        ]\n                    ]\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"capital\"\n                    ],\n                    [\n                        2\n                    ],\n                    \"capital\",\n                    \"city\"\n                ],\n                \"text-font\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\"\n                        ]\n                    ],\n                    10,\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Regular\"\n                        ]\n                    ]\n                ],\n                \"text-justify\": \"right\",\n                \"text-offset\": [\n                    -0.5,\n                    0.1\n                ],\n                \"icon-size\": [\n                    \"/\",\n                    6,\n                    [\n                        \"+\",\n                        [\n                            \"get\",\n                            \"rank\"\n                        ],\n                        7\n                    ]\n                ],\n                \"text-anchor\": \"right\",\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"*\",\n                                [\n                                    \"get\",\n                                    \"rank\"\n                                ],\n                                2\n                            ],\n                            5\n                        ],\n                        \"%)\"\n                    ],\n                    22,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            25\n                        ],\n                        \"%)\"\n                    ]\n                ],\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"text-halo-color\": \"hsl(0, 0%, 100%)\",\n                \"icon-opacity\": 0.8\n            }\n        },\n        {\n            \"id\": \"city_label_below\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"maxzoom\": 8,\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    [\n                        \"/\",\n                        [\n                            \"zoom\"\n                        ],\n                        3\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"city\",\n                        \"town\",\n                        \"village\",\n                        \"hamlet\",\n                        \"suburb\",\n                        \"quarter\",\n                        \"neighbourhood\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"-\",\n                        14,\n                        [\n                            \"max\",\n                            0,\n                            [\n                                \"-\",\n                                [\n                                    \"get\",\n                                    \"rank\"\n                                ],\n                                8\n                            ]\n                        ]\n                    ],\n                    22,\n                    [\n                        \"-\",\n                        20,\n                        [\n                            \"/\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            4\n                        ]\n                    ]\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"capital\"\n                    ],\n                    [\n                        2\n                    ],\n                    \"capital\",\n                    \"city\"\n                ],\n                \"text-font\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\"\n                        ]\n                    ],\n                    10,\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Regular\"\n                        ]\n                    ]\n                ],\n                \"text-offset\": [\n                    0,\n                    0.4\n                ],\n                \"icon-size\": [\n                    \"/\",\n                    6,\n                    [\n                        \"+\",\n                        [\n                            \"get\",\n                            \"rank\"\n                        ],\n                        7\n                    ]\n                ],\n                \"text-anchor\": \"top\",\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"*\",\n                                [\n                                    \"get\",\n                                    \"rank\"\n                                ],\n                                2\n                            ],\n                            5\n                        ],\n                        \"%)\"\n                    ],\n                    22,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            25\n                        ],\n                        \"%)\"\n                    ]\n                ],\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"text-halo-color\": \"hsl(0, 0%, 100%)\",\n                \"icon-opacity\": 0.8\n            }\n        },\n        {\n            \"id\": \"city_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    [\n                        \"*\",\n                        [\n                            \"zoom\"\n                        ],\n                        1.5\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"city\",\n                        \"town\",\n                        \"village\",\n                        \"hamlet\",\n                        \"suburb\",\n                        \"quarter\",\n                        \"neighbourhood\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"-\",\n                        14,\n                        [\n                            \"max\",\n                            0,\n                            [\n                                \"-\",\n                                [\n                                    \"get\",\n                                    \"rank\"\n                                ],\n                                8\n                            ]\n                        ]\n                    ],\n                    22,\n                    [\n                        \"-\",\n                        20,\n                        [\n                            \"/\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            4\n                        ]\n                    ]\n                ],\n                \"icon-image\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"capital\"\n                        ],\n                        [\n                            2\n                        ],\n                        \"capital\",\n                        \"city\"\n                    ],\n                    8,\n                    \"\"\n                ],\n                \"text-transform\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    \"none\",\n                    15,\n                    \"uppercase\"\n                ],\n                \"text-font\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\"\n                        ]\n                    ],\n                    10,\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Regular\"\n                        ]\n                    ]\n                ],\n                \"text-offset\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            0,\n                            -0.2\n                        ]\n                    ],\n                    8,\n                    [\n                        \"literal\",\n                        [\n                            0,\n                            0\n                        ]\n                    ]\n                ],\n                \"icon-size\": [\n                    \"/\",\n                    6,\n                    [\n                        \"+\",\n                        [\n                            \"get\",\n                            \"rank\"\n                        ],\n                        7\n                    ]\n                ],\n                \"text-anchor\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"bottom\",\n                    8,\n                    \"center\"\n                ],\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-letter-spacing\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    0,\n                    0,\n                    8,\n                    0,\n                    12,\n                    0.1,\n                    16,\n                    0.2\n                ],\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"*\",\n                                [\n                                    \"get\",\n                                    \"rank\"\n                                ],\n                                2\n                            ],\n                            5\n                        ],\n                        \"%)\"\n                    ],\n                    22,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            25\n                        ],\n                        \"%)\"\n                    ]\n                ],\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"text-halo-color\": \"hsl(0, 0%, 100%)\",\n                \"icon-opacity\": 0.8\n            }\n        },\n        {\n            \"id\": \"park_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"poi.park\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"poi\",\n            \"minzoom\": 17,\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"park\",\n                        \"cemetery\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    250\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-size\": 14\n            },\n            \"paint\": {\n                \"text-color\": \"#297925\",\n                \"text-halo-color\": \"hsl(0, 0%, 100%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"road-number-shield\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road\",\n                \"microg:gms-type-element\": \"labels.icon\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation_name\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"ref\"\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"ref_length\"\n                    ],\n                    6\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": 9,\n                \"icon-image\": [\n                    \"case\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"network\"\n                        ],\n                        [\n                            \"us-interstate\"\n                        ],\n                        true,\n                        false\n                    ],\n                    [\n                        \"concat\",\n                        \"shield_\",\n                        [\n                            \"get\",\n                            \"network\"\n                        ],\n                        \"_\",\n                        [\n                            \"get\",\n                            \"ref_length\"\n                        ]\n                    ],\n                    [\n                        \"concat\",\n                        \"shield_rectangle-white_\",\n                        [\n                            \"get\",\n                            \"ref_length\"\n                        ]\n                    ]\n                ],\n                \"icon-rotation-alignment\": \"viewport\",\n                \"text-font\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"shield_text_color\"\n                    ],\n                    [\n                        \"white\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Bold\"\n                        ]\n                    ],\n                    [\n                        \"black\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\"\n                        ]\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Bold\"\n                        ]\n                    ]\n                ],\n                \"symbol-placement\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"point\",\n                    11,\n                    \"line\"\n                ],\n                \"text-offset\": [\n                    0,\n                    0.1\n                ],\n                \"text-rotation-alignment\": \"viewport\",\n                \"icon-size\": 0.75,\n                \"text-field\": [\n                    \"get\",\n                    \"ref\"\n                ],\n                \"text-letter-spacing\": 0.05,\n                \"visibility\": \"visible\",\n                \"icon-padding\": 10\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"case\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"network\"\n                        ],\n                        [\n                            \"us-interstate\"\n                        ],\n                        true,\n                        false\n                    ],\n                    \"#ffffff\",\n                    \"#000000\"\n                ]\n            }\n        },\n        {\n            \"id\": \"country_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"administrative.country\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"country\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {\n                \"text-letter-spacing\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    1,\n                    0,\n                    3,\n                    0.15\n                ],\n                \"text-font\": [\n                    \"Roboto Medium\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.2\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    1,\n                    12,\n                    7,\n                    [\n                        \"/\",\n                        30,\n                        [\n                            \"get\",\n                            \"rank\"\n                        ]\n                    ]\n                ],\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(0, 0%, 10%)\",\n                \"text-halo-color\": \"hsl(0, 0%, 100%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"text-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    6,\n                    1,\n                    7,\n                    0\n                ]\n            }\n        },\n        {\n            \"id\": \"pedestrian_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation_name\",\n            \"minzoom\": 16,\n            \"filter\": [\n                \"any\",\n                [\n                    \"all\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"subclass\"\n                        ],\n                        [\n                            \"pedestrian\"\n                        ],\n                        true,\n                        false\n                    ],\n                    [\n                        \"==\",\n                        [\n                            \"get\",\n                            \"surface\"\n                        ],\n                        \"paved\"\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    \"platform\",\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"name\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    17,\n                    10,\n                    22,\n                    14\n                ],\n                \"text-padding\": 5\n            },\n            \"paint\": {\n                \"text-color\": \"#575757\",\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"street_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation_name\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"minor\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"name\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    6,\n                    16,\n                    10\n                ],\n                \"text-padding\": 5\n            },\n            \"paint\": {\n                \"text-color\": \"#575757\",\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"secondary_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation_name\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"secondary\",\n                        \"tertiary\",\n                        \"trunk\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"name\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    8,\n                    16,\n                    13\n                ],\n                \"symbol-spacing\": 300,\n                \"text-padding\": 25\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(196, 0%, 34%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"primary_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation_name\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"name\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    10,\n                    18,\n                    14\n                ],\n                \"symbol-spacing\": 800,\n                \"text-padding\": 50\n            },\n            \"paint\": {\n                \"text-color\": \"#6e481d\",\n                \"text-halo-width\": 1,\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"poi_label_below\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"124a9d7a8e5226775d947c592110dfad\",\n                \"microg:gms-type-element\": \"labels.text\",\n                \"microg:gms-type-feature\": \"poi\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"poi\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"bus\",\n                        \"railway\"\n                    ],\n                    false,\n                    true\n                ],\n                [\n                    \"any\",\n                    [\n                        \"!=\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ],\n                            [\n                                \"park\",\n                                \"cemetery\"\n                            ],\n                            true,\n                            false\n                        ],\n                        [\n                            \"<=\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            250\n                        ]\n                    ],\n                    [\n                        \">=\",\n                        [\n                            \"zoom\"\n                        ],\n                        16\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-optional\": false,\n                \"text-line-height\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    15,\n                    1.2\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    13,\n                    15,\n                    14\n                ],\n                \"icon-offset\": [\n                    0,\n                    -36\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"museum\",\n                        \"theatre\",\n                        \"restaurant\"\n                    ],\n                    [\n                        \"concat\",\n                        \"poi_\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ]\n                    ],\n                    [\n                        \"fitness_centre\",\n                        \"golf_course\",\n                        \"camp_site\",\n                        \"bowling_alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic_site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog_park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"poi_generic_green\",\n                    [\n                        \"bank\",\n                        \"atm\",\n                        \"parking\",\n                        \"toilets\",\n                        \"garages\"\n                    ],\n                    \"poi_generic_purple\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\"\n                    ],\n                    \"poi_generic_orange\",\n                    [\n                        \"casino\",\n                        \"castle\",\n                        \"gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music_venue\",\n                        \"monument\"\n                    ],\n                    \"poi_generic_teal\",\n                    [\n                        \"hospital\",\n                        \"doctors\"\n                    ],\n                    \"poi_generic_red\",\n                    [\n                        \"fast_food\",\n                        \"ice_cream\"\n                    ],\n                    \"poi_restaurant\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"lodging\",\n                            \"grocery\"\n                        ],\n                        [\n                            \"concat\",\n                            \"poi_\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ]\n                        ],\n                        [\n                            \"clothing_store\",\n                            \"shop\"\n                        ],\n                        \"poi_generic_blue\",\n                        \"poi_generic\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-offset\": [\n                    0,\n                    0.5\n                ],\n                \"icon-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.25,\n                    15,\n                    0.32\n                ],\n                \"text-anchor\": \"top\",\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-padding\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    30,\n                    17,\n                    5\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"fitness_centre\",\n                        \"golf_course\",\n                        \"camp_site\",\n                        \"bowling_alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic_site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog_park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"hsl(117, 53%, 31%)\",\n                    [\n                        \"bank\",\n                        \"atm\",\n                        \"parking\",\n                        \"toilets\",\n                        \"garages\"\n                    ],\n                    \"#737b9b\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\",\n                        \"fast_food\",\n                        \"restaurant\",\n                        \"ice_cream\"\n                    ],\n                    \"#c77d57\",\n                    [\n                        \"museum\",\n                        \"theatre\",\n                        \"casino\",\n                        \"castle\",\n                        \"gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music_venue\",\n                        \"monument\"\n                    ],\n                    \"hsl(186, 78%, 44%)\",\n                    [\n                        \"hospital\",\n                        \"doctors\"\n                    ],\n                    \"#a47172\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"lodging\"\n                        ],\n                        \"#df7db1\",\n                        [\n                            \"grocery\",\n                            \"clothing_store\",\n                            \"shop\"\n                        ],\n                        \"hsl(213, 40%, 48%)\",\n                        \"#67747b\"\n                    ]\n                ],\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1,\n                \"icon-translate\": [\n                    0,\n                    0\n                ],\n                \"text-translate\": [\n                    0,\n                    0\n                ],\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"poi_label_above\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"124a9d7a8e5226775d947c592110dfad\",\n                \"microg:gms-type-element\": \"labels.text\",\n                \"microg:gms-type-feature\": \"poi\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"poi\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"bus\",\n                        \"railway\"\n                    ],\n                    false,\n                    true\n                ],\n                [\n                    \"any\",\n                    [\n                        \"!=\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ],\n                            [\n                                \"park\",\n                                \"cemetery\"\n                            ],\n                            true,\n                            false\n                        ],\n                        [\n                            \"<=\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            250\n                        ]\n                    ],\n                    [\n                        \">=\",\n                        [\n                            \"zoom\"\n                        ],\n                        16\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-optional\": false,\n                \"text-line-height\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    15,\n                    1.2\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    13,\n                    15,\n                    14\n                ],\n                \"icon-offset\": [\n                    0,\n                    -36\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"museum\",\n                        \"theatre\",\n                        \"restaurant\"\n                    ],\n                    [\n                        \"concat\",\n                        \"poi_\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ]\n                    ],\n                    [\n                        \"fitness_centre\",\n                        \"golf_course\",\n                        \"camp_site\",\n                        \"bowling_alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic_site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog_park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"poi_generic_green\",\n                    [\n                        \"bank\",\n                        \"atm\",\n                        \"parking\",\n                        \"toilets\",\n                        \"garages\"\n                    ],\n                    \"poi_generic_purple\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\"\n                    ],\n                    \"poi_generic_orange\",\n                    [\n                        \"casino\",\n                        \"castle\",\n                        \"gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music_venue\",\n                        \"monument\"\n                    ],\n                    \"poi_generic_teal\",\n                    [\n                        \"hospital\",\n                        \"doctors\"\n                    ],\n                    \"poi_generic_red\",\n                    [\n                        \"fast_food\",\n                        \"ice_cream\"\n                    ],\n                    \"poi_restaurant\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"lodging\",\n                            \"grocery\"\n                        ],\n                        [\n                            \"concat\",\n                            \"poi_\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ]\n                        ],\n                        [\n                            \"clothing_store\",\n                            \"shop\"\n                        ],\n                        \"poi_generic_blue\",\n                        \"poi_generic\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-offset\": [\n                    0,\n                    -2\n                ],\n                \"icon-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.25,\n                    15,\n                    0.32\n                ],\n                \"text-anchor\": \"bottom\",\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-padding\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    30,\n                    17,\n                    5\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"fitness_centre\",\n                        \"golf_course\",\n                        \"camp_site\",\n                        \"bowling_alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic_site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog_park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"hsl(117, 53%, 31%)\",\n                    [\n                        \"bank\",\n                        \"atm\",\n                        \"parking\",\n                        \"toilets\",\n                        \"garages\"\n                    ],\n                    \"#737b9b\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\",\n                        \"fast_food\",\n                        \"restaurant\",\n                        \"ice_cream\"\n                    ],\n                    \"#c77d57\",\n                    [\n                        \"museum\",\n                        \"theatre\",\n                        \"casino\",\n                        \"castle\",\n                        \"gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music_venue\",\n                        \"monument\"\n                    ],\n                    \"hsl(186, 78%, 44%)\",\n                    [\n                        \"hospital\",\n                        \"doctors\"\n                    ],\n                    \"#a47172\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"lodging\"\n                        ],\n                        \"#df7db1\",\n                        [\n                            \"grocery\",\n                            \"clothing_store\",\n                            \"shop\"\n                        ],\n                        \"hsl(213, 40%, 48%)\",\n                        \"#67747b\"\n                    ]\n                ],\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1,\n                \"icon-translate\": [\n                    0,\n                    0\n                ],\n                \"text-translate\": [\n                    0,\n                    0\n                ],\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"poi_label_left\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"124a9d7a8e5226775d947c592110dfad\",\n                \"microg:gms-type-element\": \"labels.text\",\n                \"microg:gms-type-feature\": \"poi\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"poi\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"bus\",\n                        \"railway\"\n                    ],\n                    false,\n                    true\n                ],\n                [\n                    \"any\",\n                    [\n                        \"!=\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ],\n                            [\n                                \"park\",\n                                \"cemetery\"\n                            ],\n                            true,\n                            false\n                        ],\n                        [\n                            \"<=\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            250\n                        ]\n                    ],\n                    [\n                        \">=\",\n                        [\n                            \"zoom\"\n                        ],\n                        16\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-line-height\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    15,\n                    1.2\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    13,\n                    15,\n                    14\n                ],\n                \"icon-offset\": [\n                    0,\n                    -36\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"museum\",\n                        \"theatre\",\n                        \"restaurant\"\n                    ],\n                    [\n                        \"concat\",\n                        \"poi_\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ]\n                    ],\n                    [\n                        \"fitness_centre\",\n                        \"golf_course\",\n                        \"camp_site\",\n                        \"bowling_alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic_site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog_park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"poi_generic_green\",\n                    [\n                        \"bank\",\n                        \"atm\",\n                        \"parking\",\n                        \"toilets\",\n                        \"garages\"\n                    ],\n                    \"poi_generic_purple\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\"\n                    ],\n                    \"poi_generic_orange\",\n                    [\n                        \"casino\",\n                        \"castle\",\n                        \"gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music_venue\",\n                        \"monument\"\n                    ],\n                    \"poi_generic_teal\",\n                    [\n                        \"hospital\",\n                        \"doctors\"\n                    ],\n                    \"poi_generic_red\",\n                    [\n                        \"fast_food\",\n                        \"ice_cream\"\n                    ],\n                    \"poi_restaurant\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"lodging\",\n                            \"grocery\"\n                        ],\n                        [\n                            \"concat\",\n                            \"poi_\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ]\n                        ],\n                        [\n                            \"clothing_store\",\n                            \"shop\"\n                        ],\n                        \"poi_generic_blue\",\n                        \"poi_generic\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-justify\": \"right\",\n                \"text-offset\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    [\n                        \"literal\",\n                        [\n                            -1.1,\n                            -0.7\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            -1.1,\n                            -0.9\n                        ]\n                    ]\n                ],\n                \"icon-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.25,\n                    15,\n                    0.32\n                ],\n                \"text-anchor\": \"right\",\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-padding\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    30,\n                    17,\n                    5\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"fitness_centre\",\n                        \"golf_course\",\n                        \"camp_site\",\n                        \"bowling_alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic_site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog_park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"hsl(117, 53%, 31%)\",\n                    [\n                        \"bank\",\n                        \"atm\",\n                        \"parking\",\n                        \"toilets\",\n                        \"garages\"\n                    ],\n                    \"#737b9b\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\",\n                        \"fast_food\",\n                        \"restaurant\",\n                        \"ice_cream\"\n                    ],\n                    \"#c77d57\",\n                    [\n                        \"museum\",\n                        \"theatre\",\n                        \"casino\",\n                        \"castle\",\n                        \"gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music_venue\",\n                        \"monument\"\n                    ],\n                    \"hsl(186, 78%, 44%)\",\n                    [\n                        \"hospital\",\n                        \"doctors\"\n                    ],\n                    \"#a47172\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"lodging\"\n                        ],\n                        \"#df7db1\",\n                        [\n                            \"grocery\",\n                            \"clothing_store\",\n                            \"shop\"\n                        ],\n                        \"hsl(213, 40%, 48%)\",\n                        \"#67747b\"\n                    ]\n                ],\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1,\n                \"icon-translate\": [\n                    0,\n                    0\n                ],\n                \"text-translate\": [\n                    0,\n                    0\n                ],\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"poi_label_right\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"124a9d7a8e5226775d947c592110dfad\",\n                \"microg:gms-type-element\": \"labels.text\",\n                \"microg:gms-type-feature\": \"poi\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"poi\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"bus\",\n                        \"railway\"\n                    ],\n                    false,\n                    true\n                ],\n                [\n                    \"any\",\n                    [\n                        \"!=\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ],\n                            [\n                                \"park\",\n                                \"cemetery\"\n                            ],\n                            true,\n                            false\n                        ],\n                        [\n                            \"<=\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            250\n                        ]\n                    ],\n                    [\n                        \">=\",\n                        [\n                            \"zoom\"\n                        ],\n                        16\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-line-height\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    15,\n                    1.2\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    13,\n                    15,\n                    14\n                ],\n                \"icon-offset\": [\n                    0,\n                    -36\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"museum\",\n                        \"theatre\",\n                        \"restaurant\"\n                    ],\n                    [\n                        \"concat\",\n                        \"poi_\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ]\n                    ],\n                    [\n                        \"fitness_centre\",\n                        \"golf_course\",\n                        \"camp_site\",\n                        \"bowling_alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic_site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog_park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"poi_generic_green\",\n                    [\n                        \"bank\",\n                        \"atm\",\n                        \"parking\",\n                        \"toilets\",\n                        \"garages\"\n                    ],\n                    \"poi_generic_purple\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\"\n                    ],\n                    \"poi_generic_orange\",\n                    [\n                        \"casino\",\n                        \"castle\",\n                        \"gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music_venue\",\n                        \"monument\"\n                    ],\n                    \"poi_generic_teal\",\n                    [\n                        \"hospital\",\n                        \"doctors\"\n                    ],\n                    \"poi_generic_red\",\n                    [\n                        \"fast_food\",\n                        \"ice_cream\"\n                    ],\n                    \"poi_restaurant\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"lodging\",\n                            \"grocery\"\n                        ],\n                        [\n                            \"concat\",\n                            \"poi_\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ]\n                        ],\n                        [\n                            \"clothing_store\",\n                            \"shop\"\n                        ],\n                        \"poi_generic_blue\",\n                        \"poi_generic\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-justify\": \"left\",\n                \"text-offset\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    [\n                        \"literal\",\n                        [\n                            1.1,\n                            -0.7\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            1.1,\n                            -0.9\n                        ]\n                    ]\n                ],\n                \"icon-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.25,\n                    15,\n                    0.32\n                ],\n                \"text-anchor\": \"left\",\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-padding\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    30,\n                    17,\n                    5\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"fitness_centre\",\n                        \"golf_course\",\n                        \"camp_site\",\n                        \"bowling_alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic_site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog_park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"hsl(117, 53%, 31%)\",\n                    [\n                        \"bank\",\n                        \"atm\",\n                        \"parking\",\n                        \"toilets\",\n                        \"garages\"\n                    ],\n                    \"#737b9b\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\",\n                        \"fast_food\",\n                        \"restaurant\",\n                        \"ice_cream\"\n                    ],\n                    \"#c77d57\",\n                    [\n                        \"museum\",\n                        \"theatre\",\n                        \"casino\",\n                        \"castle\",\n                        \"gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music_venue\",\n                        \"monument\"\n                    ],\n                    \"hsl(186, 78%, 44%)\",\n                    [\n                        \"hospital\",\n                        \"doctors\"\n                    ],\n                    \"#a47172\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"lodging\"\n                        ],\n                        \"#df7db1\",\n                        [\n                            \"grocery\",\n                            \"clothing_store\",\n                            \"shop\"\n                        ],\n                        \"hsl(213, 40%, 48%)\",\n                        \"#67747b\"\n                    ]\n                ],\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1,\n                \"icon-translate\": [\n                    0,\n                    0\n                ],\n                \"text-translate\": [\n                    0,\n                    0\n                ],\n                \"text-halo-blur\": 1\n            }\n        }\n    ],\n    \"created\": \"2019-04-15T08:41:40.148Z\",\n    \"modified\": \"2020-09-05T19:42:03.856Z\",\n    \"id\": \"cjui4020201oo1fmca7yuwbor\",\n    \"owner\": \"microg\",\n    \"visibility\": \"public\",\n    \"protected\": false,\n    \"draft\": false\n}\n"
  },
  {
    "path": "artwork/styles/style-microg-satellite-mapbox.json",
    "content": "{\n    \"version\": 8,\n    \"name\": \"Mountain View Satellite\",\n    \"metadata\": {\n        \"mapbox:origin\": \"basic-template\",\n        \"mapbox:autocomposite\": true,\n        \"mapbox:type\": \"template\",\n        \"mapbox:sdk-support\": {\n            \"js\": \"0.50.0\",\n            \"android\": \"6.7.0\",\n            \"ios\": \"4.6.0\"\n        },\n        \"mapbox:trackposition\": false,\n        \"mapbox:groups\": {\n            \"f51b507d2a17e572c70a5db74b0fec7e\": {\n                \"name\": \"Base\",\n                \"collapsed\": true\n            },\n            \"3f48b8dc54ff2e6544b9ef9cedbf2990\": {\n                \"name\": \"Streets\",\n                \"collapsed\": false\n            },\n            \"29bb589e8d1b9b402583363648b70302\": {\n                \"name\": \"Buildings\",\n                \"collapsed\": true\n            },\n            \"3c26e9cbc75335c6f0ba8de5439cf1fa\": {\n                \"name\": \"Country borders\",\n                \"collapsed\": true\n            },\n            \"7b44201d7f1682d99f7140188aff23ce\": {\n                \"name\": \"Labels\",\n                \"collapsed\": true\n            },\n            \"24306bdccbff03e2ee08d5d1a4ca7312\": {\n                \"name\": \"Street name\",\n                \"collapsed\": false\n            },\n            \"124a9d7a8e5226775d947c592110dfad\": {\n                \"name\": \"POI\",\n                \"collapsed\": true\n            }\n        },\n        \"mapbox:uiParadigm\": \"layers\"\n    },\n    \"center\": [\n        12.819420849458652,\n        50.03325860617235\n    ],\n    \"zoom\": 3.315829104862067,\n    \"bearing\": 0,\n    \"pitch\": 1.5,\n    \"light\": {\n        \"intensity\": 0.5,\n        \"color\": \"hsl(0, 0%, 0%)\"\n    },\n    \"sources\": {\n        \"mapbox://mapbox.satellite\": {\n            \"url\": \"mapbox://mapbox.satellite\",\n            \"type\": \"raster\",\n            \"tileSize\": 256\n        },\n        \"composite\": {\n            \"url\": \"mapbox://mapbox.mapbox-streets-v8,mapbox.mapbox-terrain-v2\",\n            \"type\": \"vector\"\n        }\n    },\n    \"sprite\": \"mapbox://sprites/microg/cjxgloted25ap1ct4uex7m6hi/8fkcj5fgn4mftlzuak3guz1f9\",\n    \"glyphs\": \"mapbox://fonts/microg/{fontstack}/{range}.pbf\",\n    \"layers\": [\n        {\n            \"id\": \"background\",\n            \"type\": \"raster\",\n            \"source\": \"mapbox://mapbox.satellite\",\n            \"layout\": {},\n            \"paint\": {},\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"path\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"path\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    [\n                        \"platform\",\n                        \"steps\"\n                    ],\n                    false,\n                    true\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsl(118, 34%, 66%)\",\n                \"line-dasharray\": [\n                    4,\n                    2\n                ],\n                \"line-opacity\": 0.3\n            }\n        },\n        {\n            \"id\": \"steps\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"path\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    [\n                        \"steps\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsl(118, 5%, 66%)\",\n                \"line-dasharray\": [\n                    1,\n                    1\n                ],\n                \"line-gap-width\": 1,\n                \"line-opacity\": 0.3\n            }\n        },\n        {\n            \"id\": \"platform\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"transit.station.rail\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"type\"\n                ],\n                [\n                    \"platform\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    \"hsl(2, 20%, 92%)\",\n                    16,\n                    \"hsl(2, 95%, 92%)\"\n                ],\n                \"fill-outline-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    \"hsl(1, 10%, 76%)\",\n                    16,\n                    \"hsl(1, 74%, 76%)\"\n                ],\n                \"fill-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0,\n                    16,\n                    0.3\n                ]\n            }\n        },\n        {\n            \"id\": \"primary_tunnel\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary_link\",\n                        \"primary\",\n                        \"motorway_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    1,\n                    12,\n                    4,\n                    14,\n                    6,\n                    16,\n                    10,\n                    22,\n                    64\n                ],\n                \"line-color\": \"hsl(0, 0%, 89%)\",\n                \"line-opacity\": 0.3\n            }\n        },\n        {\n            \"id\": \"aeroway\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"transit.station.airport\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"aeroway\",\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsla(0, 0%, 0%, 0.1)\",\n                \"line-opacity\": 0.3\n            }\n        },\n        {\n            \"id\": \"service_road\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"service\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsla(0, 0%, 0%, 0.1)\",\n                \"line-opacity\": 0.3\n            }\n        },\n        {\n            \"id\": \"railway\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"major_rail\",\n                    \"minor_rail\",\n                    \"service_rail\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsl(220, 4%, 85%)\",\n                \"line-opacity\": 0.3\n            }\n        },\n        {\n            \"id\": \"pedestrian\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"pedestrian\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    [\n                        \"platform\"\n                    ],\n                    false,\n                    true\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsl(0, 0%, 100%)\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    13,\n                    1,\n                    16,\n                    4,\n                    22,\n                    32\n                ],\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12.5,\n                    0,\n                    13.5,\n                    0.3\n                ]\n            }\n        },\n        {\n            \"id\": \"street\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"street\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsl(0, 0%, 100%)\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    1,\n                    16,\n                    6,\n                    22,\n                    40\n                ],\n                \"line-opacity\": 0.3\n            }\n        },\n        {\n            \"id\": \"secondary\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"secondary\",\n                    \"secondary_link\",\n                    \"trunk_link\",\n                    \"tertiary\",\n                    \"tertiary_link\",\n                    \"trunk\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsl(0, 0%, 100%)\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    10,\n                    1,\n                    17,\n                    10,\n                    22,\n                    48\n                ],\n                \"line-opacity\": 0.3\n            }\n        },\n        {\n            \"id\": \"primary\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary_link\",\n                        \"primary\",\n                        \"motorway_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    false,\n                    true\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"hsl(50, 100%, 75%)\",\n                    7,\n                    \"hsl(50, 100%, 85%)\"\n                ],\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    1,\n                    16,\n                    8,\n                    22,\n                    64\n                ],\n                \"line-opacity\": 0.3\n            }\n        },\n        {\n            \"id\": \"motorway\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"motorway\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsl(47, 100%, 82%)\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    1,\n                    15.5,\n                    8,\n                    22,\n                    78\n                ],\n                \"line-opacity\": 0.3\n            }\n        },\n        {\n            \"id\": \"admin_0\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3c26e9cbc75335c6f0ba8de5439cf1fa\",\n                \"microg:gms-type-feature\": \"administrative.country\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"admin\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maritime\"\n                    ],\n                    [\n                        \"false\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"admin_level\"\n                    ],\n                    [\n                        0\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": [\n                    \"case\",\n                    [\n                        \"==\",\n                        [\n                            \"get\",\n                            \"disputed\"\n                        ],\n                        true\n                    ],\n                    \"hsl(0, 24%, 85%)\",\n                    \"hsl(200, 1%, 85%)\"\n                ]\n            }\n        },\n        {\n            \"id\": \"admin_1\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3c26e9cbc75335c6f0ba8de5439cf1fa\",\n                \"microg:gms-type-feature\": \"administrative.province\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"admin\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maritime\"\n                    ],\n                    [\n                        \"false\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"admin_level\"\n                    ],\n                    [\n                        1\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": [\n                    \"case\",\n                    [\n                        \"==\",\n                        [\n                            \"get\",\n                            \"disputed\"\n                        ],\n                        true\n                    ],\n                    \"hsl(0, 24%, 85%)\",\n                    \"hsl(200, 1%, 85%)\"\n                ],\n                \"line-dasharray\": [\n                    1,\n                    1\n                ]\n            }\n        },\n        {\n            \"id\": \"river_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"natural_label\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"river\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"symbol-placement\": \"line\",\n                \"symbol-spacing\": 500,\n                \"text-font\": [\n                    \"Roboto Regular\",\n                    \"Arial Unicode MS Regular\"\n                ]\n            },\n            \"paint\": {\n                \"text-color\": \"#5083c1\",\n                \"text-halo-color\": \"#5083c1\",\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"city_label_right\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"place_label\",\n            \"maxzoom\": 8,\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    [\n                        \"/\",\n                        [\n                            \"zoom\"\n                        ],\n                        4\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"settlement\",\n                        \"settlement_subdivision\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-optional\": true,\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"-\",\n                        14,\n                        [\n                            \"max\",\n                            0,\n                            [\n                                \"-\",\n                                [\n                                    \"get\",\n                                    \"symbolrank\"\n                                ],\n                                8\n                            ]\n                        ]\n                    ],\n                    22,\n                    [\n                        \"-\",\n                        20,\n                        [\n                            \"/\",\n                            [\n                                \"get\",\n                                \"symbolrank\"\n                            ],\n                            4\n                        ]\n                    ]\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"capital\"\n                    ],\n                    [\n                        0,\n                        2\n                    ],\n                    \"capital\",\n                    \"city\"\n                ],\n                \"text-font\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"symbolrank\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\",\n                            \"Arial Unicode MS Regular\"\n                        ]\n                    ],\n                    10,\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Regular\",\n                            \"Arial Unicode MS Regular\"\n                        ]\n                    ]\n                ],\n                \"text-justify\": \"left\",\n                \"text-offset\": [\n                    0.5,\n                    0.1\n                ],\n                \"icon-size\": [\n                    \"/\",\n                    5,\n                    [\n                        \"get\",\n                        \"symbolrank\"\n                    ]\n                ],\n                \"text-anchor\": \"left\",\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"-\",\n                            100,\n                            [\n                                \"*\",\n                                [\n                                    \"get\",\n                                    \"symbolrank\"\n                                ],\n                                2\n                            ]\n                        ],\n                        \"%)\"\n                    ],\n                    22,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"-\",\n                                100,\n                                [\n                                    \"get\",\n                                    \"symbolrank\"\n                                ]\n                            ],\n                            5\n                        ],\n                        \"%)\"\n                    ]\n                ],\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"icon-opacity\": 0.8,\n                \"text-halo-color\": \"hsl(0, 1%, 0%)\"\n            }\n        },\n        {\n            \"id\": \"city_label_left\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"place_label\",\n            \"maxzoom\": 8,\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    [\n                        \"/\",\n                        [\n                            \"zoom\"\n                        ],\n                        4\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"settlement\",\n                        \"settlement_subdivision\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"-\",\n                        14,\n                        [\n                            \"max\",\n                            0,\n                            [\n                                \"-\",\n                                [\n                                    \"get\",\n                                    \"symbolrank\"\n                                ],\n                                8\n                            ]\n                        ]\n                    ],\n                    22,\n                    [\n                        \"-\",\n                        20,\n                        [\n                            \"/\",\n                            [\n                                \"get\",\n                                \"symbolrank\"\n                            ],\n                            4\n                        ]\n                    ]\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"capital\"\n                    ],\n                    [\n                        0,\n                        2\n                    ],\n                    \"capital\",\n                    \"city\"\n                ],\n                \"text-font\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"symbolrank\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\",\n                            \"Arial Unicode MS Regular\"\n                        ]\n                    ],\n                    10,\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Regular\",\n                            \"Arial Unicode MS Regular\"\n                        ]\n                    ]\n                ],\n                \"text-justify\": \"right\",\n                \"text-offset\": [\n                    -0.5,\n                    0.1\n                ],\n                \"icon-size\": [\n                    \"/\",\n                    5,\n                    [\n                        \"get\",\n                        \"symbolrank\"\n                    ]\n                ],\n                \"text-anchor\": \"right\",\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"-\",\n                            100,\n                            [\n                                \"*\",\n                                [\n                                    \"get\",\n                                    \"symbolrank\"\n                                ],\n                                2\n                            ]\n                        ],\n                        \"%)\"\n                    ],\n                    22,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"-\",\n                                100,\n                                [\n                                    \"get\",\n                                    \"symbolrank\"\n                                ]\n                            ],\n                            5\n                        ],\n                        \"%)\"\n                    ]\n                ],\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"icon-opacity\": 0.8,\n                \"text-halo-color\": \"hsl(0, 1%, 0%)\"\n            }\n        },\n        {\n            \"id\": \"city_label_below\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"place_label\",\n            \"maxzoom\": 8,\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    [\n                        \"/\",\n                        [\n                            \"zoom\"\n                        ],\n                        4\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"settlement\",\n                        \"settlement_subdivision\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"-\",\n                        14,\n                        [\n                            \"max\",\n                            0,\n                            [\n                                \"-\",\n                                [\n                                    \"get\",\n                                    \"symbolrank\"\n                                ],\n                                8\n                            ]\n                        ]\n                    ],\n                    22,\n                    [\n                        \"-\",\n                        20,\n                        [\n                            \"/\",\n                            [\n                                \"get\",\n                                \"symbolrank\"\n                            ],\n                            4\n                        ]\n                    ]\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"capital\"\n                    ],\n                    [\n                        0,\n                        2\n                    ],\n                    \"capital\",\n                    \"city\"\n                ],\n                \"text-font\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"symbolrank\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\",\n                            \"Arial Unicode MS Regular\"\n                        ]\n                    ],\n                    10,\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Regular\",\n                            \"Arial Unicode MS Regular\"\n                        ]\n                    ]\n                ],\n                \"text-offset\": [\n                    0,\n                    0.4\n                ],\n                \"icon-size\": [\n                    \"/\",\n                    5,\n                    [\n                        \"get\",\n                        \"symbolrank\"\n                    ]\n                ],\n                \"text-anchor\": \"top\",\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"-\",\n                            100,\n                            [\n                                \"*\",\n                                [\n                                    \"get\",\n                                    \"symbolrank\"\n                                ],\n                                2\n                            ]\n                        ],\n                        \"%)\"\n                    ],\n                    22,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"-\",\n                                100,\n                                [\n                                    \"get\",\n                                    \"symbolrank\"\n                                ]\n                            ],\n                            5\n                        ],\n                        \"%)\"\n                    ]\n                ],\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"icon-opacity\": 0.8,\n                \"text-halo-color\": \"hsl(0, 1%, 0%)\"\n            }\n        },\n        {\n            \"id\": \"city_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"place_label\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    [\n                        \"/\",\n                        [\n                            \"zoom\"\n                        ],\n                        4\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"settlement\",\n                        \"settlement_subdivision\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"-\",\n                        14,\n                        [\n                            \"max\",\n                            0,\n                            [\n                                \"-\",\n                                [\n                                    \"get\",\n                                    \"symbolrank\"\n                                ],\n                                8\n                            ]\n                        ]\n                    ],\n                    22,\n                    [\n                        \"-\",\n                        20,\n                        [\n                            \"/\",\n                            [\n                                \"get\",\n                                \"symbolrank\"\n                            ],\n                            4\n                        ]\n                    ]\n                ],\n                \"icon-image\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"capital\"\n                        ],\n                        [\n                            0,\n                            2\n                        ],\n                        \"capital\",\n                        \"city\"\n                    ],\n                    8,\n                    \"\"\n                ],\n                \"text-transform\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"symbolrank\"\n                    ],\n                    \"none\",\n                    15,\n                    \"uppercase\"\n                ],\n                \"text-font\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"symbolrank\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\",\n                            \"Arial Unicode MS Regular\"\n                        ]\n                    ],\n                    10,\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Regular\",\n                            \"Arial Unicode MS Regular\"\n                        ]\n                    ]\n                ],\n                \"text-offset\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            0,\n                            -0.2\n                        ]\n                    ],\n                    8,\n                    [\n                        \"literal\",\n                        [\n                            0,\n                            0\n                        ]\n                    ]\n                ],\n                \"icon-size\": [\n                    \"/\",\n                    5,\n                    [\n                        \"get\",\n                        \"symbolrank\"\n                    ]\n                ],\n                \"text-anchor\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"bottom\",\n                    8,\n                    \"center\"\n                ],\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-letter-spacing\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"get\",\n                        \"symbolrank\"\n                    ],\n                    0,\n                    0,\n                    8,\n                    0,\n                    12,\n                    0.1,\n                    16,\n                    0.2\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"-\",\n                            100,\n                            [\n                                \"*\",\n                                [\n                                    \"get\",\n                                    \"symbolrank\"\n                                ],\n                                2\n                            ]\n                        ],\n                        \"%)\"\n                    ],\n                    22,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"-\",\n                                100,\n                                [\n                                    \"get\",\n                                    \"symbolrank\"\n                                ]\n                            ],\n                            5\n                        ],\n                        \"%)\"\n                    ]\n                ],\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"icon-opacity\": 0.8,\n                \"text-halo-color\": \"hsl(0, 1%, 0%)\"\n            }\n        },\n        {\n            \"id\": \"park_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"poi.park\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"poi_label\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maki\"\n                    ],\n                    [\n                        \"park\",\n                        \"cemetery\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"sizerank\"\n                    ],\n                    10\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-size\": 14\n            },\n            \"paint\": {\n                \"text-color\": \"#297925\",\n                \"text-halo-color\": \"hsl(0, 0%, 100%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"road-number-shield\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"labels.icon\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"ref\"\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"reflen\"\n                    ],\n                    6\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": 9,\n                \"icon-image\": [\n                    \"case\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"shield\"\n                        ],\n                        [\n                            \"de-motorway\",\n                            \"rectangle-green\",\n                            \"rectangle-yellow\",\n                            \"rectangle-white\",\n                            \"rectangle-blue\",\n                            \"rectangle-red\",\n                            \"us-interstate\"\n                        ],\n                        true,\n                        false\n                    ],\n                    [\n                        \"concat\",\n                        \"shield_\",\n                        [\n                            \"get\",\n                            \"shield\"\n                        ],\n                        \"_\",\n                        [\n                            \"get\",\n                            \"reflen\"\n                        ]\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"shield_text_color\"\n                        ],\n                        [\n                            \"white\"\n                        ],\n                        true,\n                        false\n                    ],\n                    [\n                        \"concat\",\n                        \"shield_rectangle-blue_\",\n                        [\n                            \"get\",\n                            \"reflen\"\n                        ]\n                    ],\n                    [\n                        \"concat\",\n                        \"shield_rectangle-white_\",\n                        [\n                            \"get\",\n                            \"reflen\"\n                        ]\n                    ]\n                ],\n                \"icon-rotation-alignment\": \"viewport\",\n                \"text-font\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"shield_text_color\"\n                    ],\n                    [\n                        \"white\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"DIN Offc Pro Bold\",\n                            \"Arial Unicode MS Regular\"\n                        ]\n                    ],\n                    [\n                        \"black\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"DIN Offc Pro Medium\",\n                            \"Arial Unicode MS Regular\"\n                        ]\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"DIN Offc Pro Bold\",\n                            \"Arial Unicode MS Regular\"\n                        ]\n                    ]\n                ],\n                \"symbol-placement\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"point\",\n                    11,\n                    \"line\"\n                ],\n                \"text-rotation-alignment\": \"viewport\",\n                \"icon-size\": 0.75,\n                \"text-field\": [\n                    \"get\",\n                    \"ref\"\n                ],\n                \"text-letter-spacing\": 0.05\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"case\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"shield_text_color\"\n                        ],\n                        [\n                            \"white\"\n                        ],\n                        true,\n                        false\n                    ],\n                    \"#ffffff\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"shield_text_color\"\n                        ],\n                        [\n                            \"black\"\n                        ],\n                        true,\n                        false\n                    ],\n                    \"hsl(0, 0%, 7%)\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"shield_text_color\"\n                        ],\n                        [\n                            \"yellow\"\n                        ],\n                        true,\n                        false\n                    ],\n                    \"hsl(50, 100%, 70%)\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"shield_text_color\"\n                        ],\n                        [\n                            \"orange\"\n                        ],\n                        true,\n                        false\n                    ],\n                    \"hsl(25, 100%, 75%)\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"shield_text_color\"\n                        ],\n                        [\n                            \"blue\"\n                        ],\n                        true,\n                        false\n                    ],\n                    \"hsl(230, 48%, 34%)\",\n                    \"#ffffff\"\n                ]\n            }\n        },\n        {\n            \"id\": \"country_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"administrative.country\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"place_label\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"country\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {\n                \"text-letter-spacing\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    1,\n                    0,\n                    3,\n                    0.15\n                ],\n                \"text-font\": [\n                    \"Roboto Medium\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.2\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    1,\n                    12,\n                    7,\n                    [\n                        \"/\",\n                        100,\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ]\n                    ]\n                ],\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    6,\n                    1,\n                    7,\n                    0\n                ],\n                \"text-color\": \"hsl(0, 0%, 90%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"text-halo-color\": \"hsl(0, 1%, 0%)\"\n            }\n        },\n        {\n            \"id\": \"pedestrian_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 16,\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"pedestrian\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    [\n                        \"platform\"\n                    ],\n                    false,\n                    true\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"name\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-font\": [\n                    \"Roboto Regular\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    17,\n                    10,\n                    22,\n                    14\n                ],\n                \"text-padding\": 5\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(0, 0%, 86%)\",\n                \"text-halo-color\": \"hsl(0, 1%, 0%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"street_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"street\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"name\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-font\": [\n                    \"Roboto Regular\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    6,\n                    16,\n                    10\n                ],\n                \"text-padding\": 5\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(0, 0%, 86%)\",\n                \"text-halo-color\": \"hsl(0, 1%, 0%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"secondary_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"secondary\",\n                        \"secondary_link\",\n                        \"tertiary_link\",\n                        \"tertiary\",\n                        \"trunk_link\",\n                        \"trunk\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"name\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-font\": [\n                    \"Roboto Regular\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    8,\n                    16,\n                    13\n                ],\n                \"symbol-spacing\": 300,\n                \"text-padding\": 25\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(196, 0%, 86%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-color\": \"hsl(0, 1%, 0%)\",\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"primary_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary\",\n                        \"primary_link\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"name\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-font\": [\n                    \"Roboto Regular\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    10,\n                    18,\n                    14\n                ],\n                \"symbol-spacing\": 800,\n                \"text-padding\": 50\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(32, 58%, 93%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-color\": \"hsl(0, 1%, 0%)\",\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"poi_label_below\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"124a9d7a8e5226775d947c592110dfad\",\n                \"microg:gms-type-feature\": \"poi\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"poi_label\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    [\n                        \"/\",\n                        [\n                            \"zoom\"\n                        ],\n                        4\n                    ]\n                ],\n                [\n                    \"!\",\n                    [\n                        \"all\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"maki\"\n                            ],\n                            [\n                                \"park\",\n                                \"cemetery\"\n                            ],\n                            true,\n                            false\n                        ],\n                        [\n                            \"<=\",\n                            [\n                                \"get\",\n                                \"sizerank\"\n                            ],\n                            10\n                        ]\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-optional\": true,\n                \"text-line-height\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    15,\n                    1.2\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    13,\n                    15,\n                    14\n                ],\n                \"icon-offset\": [\n                    0,\n                    -36\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maki\"\n                    ],\n                    [\n                        \"museum\",\n                        \"lodging\",\n                        \"theatre\",\n                        \"grocery\",\n                        \"restaurant\"\n                    ],\n                    [\n                        \"concat\",\n                        \"poi_\",\n                        [\n                            \"get\",\n                            \"maki\"\n                        ]\n                    ],\n                    [\n                        \"fitness-centre\",\n                        \"golf\",\n                        \"campsite\",\n                        \"bowling-alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic-site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog-park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"poi_generic_green\",\n                    [\n                        \"bank\",\n                        \"parking\",\n                        \"parking-garage\"\n                    ],\n                    \"poi_generic_purple\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\"\n                    ],\n                    \"poi_generic_orange\",\n                    [\n                        \"alcohol-shop\",\n                        \"shop\",\n                        \"shoe\",\n                        \"convenience\",\n                        \"clothing-store\",\n                        \"jewelry-store\"\n                    ],\n                    \"poi_generic_blue\",\n                    [\n                        \"casino\",\n                        \"castle\",\n                        \"art-gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music\",\n                        \"monument\"\n                    ],\n                    \"poi_generic_teal\",\n                    [\n                        \"hospital\",\n                        \"doctor\"\n                    ],\n                    \"poi_generic_red\",\n                    [\n                        \"restaurant-pizza\",\n                        \"restaurant-seafood\",\n                        \"restaurant-noodle\",\n                        \"fast-food\",\n                        \"ice-cream\"\n                    ],\n                    \"poi_restaurant\",\n                    \"poi_generic\"\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-offset\": [\n                    0,\n                    0.5\n                ],\n                \"icon-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.25,\n                    15,\n                    0.32\n                ],\n                \"text-anchor\": \"top\",\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maki\"\n                    ],\n                    [\n                        \"museum\",\n                        \"casino\",\n                        \"castle\",\n                        \"theatre\",\n                        \"art-gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music\",\n                        \"monument\"\n                    ],\n                    \"hsl(186, 78%, 65%)\",\n                    [\n                        \"lodging\"\n                    ],\n                    \"#df7db1\",\n                    [\n                        \"fitness-centre\",\n                        \"golf\",\n                        \"campsite\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic-site\",\n                        \"zoo\",\n                        \"dog-park\",\n                        \"stadium\",\n                        \"bowling-alley\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"hsl(117, 53%, 65%)\",\n                    [\n                        \"restaurant-pizza\",\n                        \"restaurant-seafood\",\n                        \"restaurant\",\n                        \"restaurant-noodle\",\n                        \"bar\",\n                        \"cafe\",\n                        \"fast-food\",\n                        \"bakery\",\n                        \"ice-cream\"\n                    ],\n                    \"hsl(20, 50%, 65%)\",\n                    [\n                        \"shop\",\n                        \"shoe\",\n                        \"alcohol-shop\",\n                        \"convenience\",\n                        \"grocery\",\n                        \"clothing-store\",\n                        \"jewelry-store\"\n                    ],\n                    \"hsl(213, 40%, 65%)\",\n                    [\n                        \"bank\",\n                        \"parking\",\n                        \"parking-garage\"\n                    ],\n                    \"hsl(228, 17%, 65%)\",\n                    [\n                        \"hospital\",\n                        \"doctor\"\n                    ],\n                    \"hsl(359, 22%, 65%)\",\n                    \"hsl(201, 9%, 80%)\"\n                ],\n                \"text-halo-color\": \"hsl(0, 1%, 0%)\",\n                \"text-halo-width\": 1,\n                \"icon-translate\": [\n                    0,\n                    0\n                ],\n                \"text-translate\": [\n                    0,\n                    0\n                ],\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"poi_label_above\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"124a9d7a8e5226775d947c592110dfad\",\n                \"microg:gms-type-feature\": \"poi\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"poi_label\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    [\n                        \"/\",\n                        [\n                            \"zoom\"\n                        ],\n                        4\n                    ]\n                ],\n                [\n                    \"!\",\n                    [\n                        \"all\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"maki\"\n                            ],\n                            [\n                                \"park\",\n                                \"cemetery\"\n                            ],\n                            true,\n                            false\n                        ],\n                        [\n                            \"<=\",\n                            [\n                                \"get\",\n                                \"sizerank\"\n                            ],\n                            10\n                        ]\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-optional\": true,\n                \"text-line-height\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    15,\n                    1.2\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    13,\n                    15,\n                    14\n                ],\n                \"icon-offset\": [\n                    0,\n                    -36\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maki\"\n                    ],\n                    [\n                        \"museum\",\n                        \"lodging\",\n                        \"theatre\",\n                        \"grocery\",\n                        \"restaurant\"\n                    ],\n                    [\n                        \"concat\",\n                        \"poi_\",\n                        [\n                            \"get\",\n                            \"maki\"\n                        ]\n                    ],\n                    [\n                        \"fitness-centre\",\n                        \"golf\",\n                        \"campsite\",\n                        \"bowling-alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic-site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog-park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"poi_generic_green\",\n                    [\n                        \"bank\",\n                        \"parking\",\n                        \"parking-garage\"\n                    ],\n                    \"poi_generic_purple\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\"\n                    ],\n                    \"poi_generic_orange\",\n                    [\n                        \"alcohol-shop\",\n                        \"shop\",\n                        \"shoe\",\n                        \"convenience\",\n                        \"clothing-store\",\n                        \"jewelry-store\"\n                    ],\n                    \"poi_generic_blue\",\n                    [\n                        \"casino\",\n                        \"castle\",\n                        \"art-gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music\",\n                        \"monument\"\n                    ],\n                    \"poi_generic_teal\",\n                    [\n                        \"hospital\",\n                        \"doctor\"\n                    ],\n                    \"poi_generic_red\",\n                    [\n                        \"restaurant-pizza\",\n                        \"restaurant-seafood\",\n                        \"restaurant-noodle\",\n                        \"fast-food\",\n                        \"ice-cream\"\n                    ],\n                    \"poi_restaurant\",\n                    \"poi_generic\"\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-offset\": [\n                    0,\n                    -2\n                ],\n                \"icon-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.25,\n                    15,\n                    0.32\n                ],\n                \"text-anchor\": \"bottom\",\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maki\"\n                    ],\n                    [\n                        \"museum\",\n                        \"casino\",\n                        \"castle\",\n                        \"theatre\",\n                        \"art-gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music\",\n                        \"monument\"\n                    ],\n                    \"hsl(186, 78%, 65%)\",\n                    [\n                        \"lodging\"\n                    ],\n                    \"#df7db1\",\n                    [\n                        \"fitness-centre\",\n                        \"golf\",\n                        \"campsite\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic-site\",\n                        \"zoo\",\n                        \"dog-park\",\n                        \"stadium\",\n                        \"bowling-alley\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"hsl(117, 53%, 65%)\",\n                    [\n                        \"restaurant-pizza\",\n                        \"restaurant-seafood\",\n                        \"restaurant\",\n                        \"restaurant-noodle\",\n                        \"bar\",\n                        \"cafe\",\n                        \"fast-food\",\n                        \"bakery\",\n                        \"ice-cream\"\n                    ],\n                    \"hsl(20, 50%, 65%)\",\n                    [\n                        \"shop\",\n                        \"shoe\",\n                        \"alcohol-shop\",\n                        \"convenience\",\n                        \"grocery\",\n                        \"clothing-store\",\n                        \"jewelry-store\"\n                    ],\n                    \"hsl(213, 40%, 65%)\",\n                    [\n                        \"bank\",\n                        \"parking\",\n                        \"parking-garage\"\n                    ],\n                    \"hsl(228, 17%, 65%)\",\n                    [\n                        \"hospital\",\n                        \"doctor\"\n                    ],\n                    \"hsl(359, 22%, 65%)\",\n                    \"hsl(201, 9%, 80%)\"\n                ],\n                \"text-halo-color\": \"hsl(0, 1%, 0%)\",\n                \"text-halo-width\": 1,\n                \"icon-translate\": [\n                    0,\n                    0\n                ],\n                \"text-translate\": [\n                    0,\n                    0\n                ],\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"poi_label_left\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"124a9d7a8e5226775d947c592110dfad\",\n                \"microg:gms-type-feature\": \"poi\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"poi_label\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    [\n                        \"/\",\n                        [\n                            \"zoom\"\n                        ],\n                        4\n                    ]\n                ],\n                [\n                    \"!\",\n                    [\n                        \"all\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"maki\"\n                            ],\n                            [\n                                \"park\",\n                                \"cemetery\"\n                            ],\n                            true,\n                            false\n                        ],\n                        [\n                            \"<=\",\n                            [\n                                \"get\",\n                                \"sizerank\"\n                            ],\n                            10\n                        ]\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-line-height\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    15,\n                    1.2\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    13,\n                    15,\n                    14\n                ],\n                \"icon-offset\": [\n                    0,\n                    -36\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maki\"\n                    ],\n                    [\n                        \"museum\",\n                        \"lodging\",\n                        \"theatre\",\n                        \"grocery\",\n                        \"restaurant\"\n                    ],\n                    [\n                        \"concat\",\n                        \"poi_\",\n                        [\n                            \"get\",\n                            \"maki\"\n                        ]\n                    ],\n                    [\n                        \"fitness-centre\",\n                        \"golf\",\n                        \"campsite\",\n                        \"bowling-alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic-site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog-park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"poi_generic_green\",\n                    [\n                        \"bank\",\n                        \"parking\",\n                        \"parking-garage\"\n                    ],\n                    \"poi_generic_purple\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\"\n                    ],\n                    \"poi_generic_orange\",\n                    [\n                        \"alcohol-shop\",\n                        \"shop\",\n                        \"shoe\",\n                        \"convenience\",\n                        \"clothing-store\",\n                        \"jewelry-store\"\n                    ],\n                    \"poi_generic_blue\",\n                    [\n                        \"casino\",\n                        \"castle\",\n                        \"art-gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music\",\n                        \"monument\"\n                    ],\n                    \"poi_generic_teal\",\n                    [\n                        \"hospital\",\n                        \"doctor\"\n                    ],\n                    \"poi_generic_red\",\n                    [\n                        \"restaurant-pizza\",\n                        \"restaurant-seafood\",\n                        \"restaurant-noodle\",\n                        \"fast-food\",\n                        \"ice-cream\"\n                    ],\n                    \"poi_restaurant\",\n                    \"poi_generic\"\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-justify\": \"right\",\n                \"text-offset\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    [\n                        \"literal\",\n                        [\n                            -1.1,\n                            -0.7\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            -1.1,\n                            -0.9\n                        ]\n                    ]\n                ],\n                \"icon-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.25,\n                    15,\n                    0.32\n                ],\n                \"text-anchor\": \"right\",\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maki\"\n                    ],\n                    [\n                        \"museum\",\n                        \"casino\",\n                        \"castle\",\n                        \"theatre\",\n                        \"art-gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music\",\n                        \"monument\"\n                    ],\n                    \"hsl(186, 78%, 65%)\",\n                    [\n                        \"lodging\"\n                    ],\n                    \"#df7db1\",\n                    [\n                        \"fitness-centre\",\n                        \"golf\",\n                        \"campsite\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic-site\",\n                        \"zoo\",\n                        \"dog-park\",\n                        \"stadium\",\n                        \"bowling-alley\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"hsl(117, 53%, 65%)\",\n                    [\n                        \"restaurant-pizza\",\n                        \"restaurant-seafood\",\n                        \"restaurant\",\n                        \"restaurant-noodle\",\n                        \"bar\",\n                        \"cafe\",\n                        \"fast-food\",\n                        \"bakery\",\n                        \"ice-cream\"\n                    ],\n                    \"hsl(20, 50%, 65%)\",\n                    [\n                        \"shop\",\n                        \"shoe\",\n                        \"alcohol-shop\",\n                        \"convenience\",\n                        \"grocery\",\n                        \"clothing-store\",\n                        \"jewelry-store\"\n                    ],\n                    \"hsl(213, 40%, 65%)\",\n                    [\n                        \"bank\",\n                        \"parking\",\n                        \"parking-garage\"\n                    ],\n                    \"hsl(228, 17%, 65%)\",\n                    [\n                        \"hospital\",\n                        \"doctor\"\n                    ],\n                    \"hsl(359, 22%, 65%)\",\n                    \"hsl(201, 9%, 80%)\"\n                ],\n                \"text-halo-color\": \"hsl(0, 1%, 0%)\",\n                \"text-halo-width\": 1,\n                \"icon-translate\": [\n                    0,\n                    0\n                ],\n                \"text-translate\": [\n                    0,\n                    0\n                ],\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"poi_label_right\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"124a9d7a8e5226775d947c592110dfad\",\n                \"microg:gms-type-feature\": \"poi\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"poi_label\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    [\n                        \"/\",\n                        [\n                            \"zoom\"\n                        ],\n                        4\n                    ]\n                ],\n                [\n                    \"!\",\n                    [\n                        \"all\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"maki\"\n                            ],\n                            [\n                                \"park\",\n                                \"cemetery\"\n                            ],\n                            true,\n                            false\n                        ],\n                        [\n                            \"<=\",\n                            [\n                                \"get\",\n                                \"sizerank\"\n                            ],\n                            10\n                        ]\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-line-height\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    15,\n                    1.2\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    13,\n                    15,\n                    14\n                ],\n                \"icon-offset\": [\n                    0,\n                    -36\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maki\"\n                    ],\n                    [\n                        \"museum\",\n                        \"lodging\",\n                        \"theatre\",\n                        \"grocery\",\n                        \"restaurant\"\n                    ],\n                    [\n                        \"concat\",\n                        \"poi_\",\n                        [\n                            \"get\",\n                            \"maki\"\n                        ]\n                    ],\n                    [\n                        \"fitness-centre\",\n                        \"golf\",\n                        \"campsite\",\n                        \"bowling-alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic-site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog-park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"poi_generic_green\",\n                    [\n                        \"bank\",\n                        \"parking\",\n                        \"parking-garage\"\n                    ],\n                    \"poi_generic_purple\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\"\n                    ],\n                    \"poi_generic_orange\",\n                    [\n                        \"alcohol-shop\",\n                        \"shop\",\n                        \"shoe\",\n                        \"convenience\",\n                        \"clothing-store\",\n                        \"jewelry-store\"\n                    ],\n                    \"poi_generic_blue\",\n                    [\n                        \"casino\",\n                        \"castle\",\n                        \"art-gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music\",\n                        \"monument\"\n                    ],\n                    \"poi_generic_teal\",\n                    [\n                        \"hospital\",\n                        \"doctor\"\n                    ],\n                    \"poi_generic_red\",\n                    [\n                        \"restaurant-pizza\",\n                        \"restaurant-seafood\",\n                        \"restaurant-noodle\",\n                        \"fast-food\",\n                        \"ice-cream\"\n                    ],\n                    \"poi_restaurant\",\n                    \"poi_generic\"\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-justify\": \"left\",\n                \"text-offset\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    [\n                        \"literal\",\n                        [\n                            1.1,\n                            -0.7\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            1.1,\n                            -0.9\n                        ]\n                    ]\n                ],\n                \"icon-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.25,\n                    15,\n                    0.32\n                ],\n                \"text-anchor\": \"left\",\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maki\"\n                    ],\n                    [\n                        \"museum\",\n                        \"casino\",\n                        \"castle\",\n                        \"theatre\",\n                        \"art-gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music\",\n                        \"monument\"\n                    ],\n                    \"hsl(186, 78%, 65%)\",\n                    [\n                        \"lodging\"\n                    ],\n                    \"#df7db1\",\n                    [\n                        \"fitness-centre\",\n                        \"golf\",\n                        \"campsite\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic-site\",\n                        \"zoo\",\n                        \"dog-park\",\n                        \"stadium\",\n                        \"bowling-alley\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"hsl(117, 53%, 65%)\",\n                    [\n                        \"restaurant-pizza\",\n                        \"restaurant-seafood\",\n                        \"restaurant\",\n                        \"restaurant-noodle\",\n                        \"bar\",\n                        \"cafe\",\n                        \"fast-food\",\n                        \"bakery\",\n                        \"ice-cream\"\n                    ],\n                    \"hsl(20, 50%, 65%)\",\n                    [\n                        \"shop\",\n                        \"shoe\",\n                        \"alcohol-shop\",\n                        \"convenience\",\n                        \"grocery\",\n                        \"clothing-store\",\n                        \"jewelry-store\"\n                    ],\n                    \"hsl(213, 40%, 65%)\",\n                    [\n                        \"bank\",\n                        \"parking\",\n                        \"parking-garage\"\n                    ],\n                    \"hsl(228, 17%, 65%)\",\n                    [\n                        \"hospital\",\n                        \"doctor\"\n                    ],\n                    \"hsl(359, 22%, 65%)\",\n                    \"hsl(201, 9%, 80%)\"\n                ],\n                \"text-halo-color\": \"hsl(0, 1%, 0%)\",\n                \"text-halo-width\": 1,\n                \"icon-translate\": [\n                    0,\n                    0\n                ],\n                \"text-translate\": [\n                    0,\n                    0\n                ],\n                \"text-halo-blur\": 1\n            }\n        }\n    ],\n    \"created\": \"2019-06-28T21:20:23.628Z\",\n    \"modified\": \"2020-09-05T20:08:11.990Z\",\n    \"id\": \"cjxgloted25ap1ct4uex7m6hi\",\n    \"owner\": \"microg\",\n    \"visibility\": \"public\",\n    \"protected\": false,\n    \"draft\": false\n}\n"
  },
  {
    "path": "artwork/styles/style-microg-satellite-stadia.json",
    "content": "{\n    \"version\": 8,\n    \"name\": \"Mountain View Full\",\n    \"metadata\": {\n        \"mapbox:origin\": \"basic-template\",\n        \"mapbox:autocomposite\": true,\n        \"mapbox:type\": \"template\",\n        \"mapbox:sdk-support\": {\n            \"js\": \"0.50.0\",\n            \"android\": \"6.7.0\",\n            \"ios\": \"4.6.0\"\n        },\n        \"mapbox:trackposition\": false,\n        \"mapbox:groups\": {\n            \"f51b507d2a17e572c70a5db74b0fec7e\": {\n                \"name\": \"Base\",\n                \"collapsed\": false\n            },\n            \"3f48b8dc54ff2e6544b9ef9cedbf2990\": {\n                \"name\": \"Streets\",\n                \"collapsed\": true\n            },\n            \"29bb589e8d1b9b402583363648b70302\": {\n                \"name\": \"Buildings\",\n                \"collapsed\": true\n            },\n            \"3c26e9cbc75335c6f0ba8de5439cf1fa\": {\n                \"name\": \"Country borders\",\n                \"collapsed\": true\n            },\n            \"7b44201d7f1682d99f7140188aff23ce\": {\n                \"name\": \"Labels\",\n                \"collapsed\": true\n            },\n            \"24306bdccbff03e2ee08d5d1a4ca7312\": {\n                \"name\": \"Street name\",\n                \"collapsed\": true\n            },\n            \"124a9d7a8e5226775d947c592110dfad\": {\n                \"name\": \"POI\",\n                \"collapsed\": true\n            }\n        },\n        \"mapbox:uiParadigm\": \"layers\",\n        \"maputnik:renderer\": \"mbgljs\"\n    },\n    \"center\": [\n        12.819420849458652,\n        50.03325860617235\n    ],\n    \"zoom\": 3.315829104862067,\n    \"bearing\": 0,\n    \"pitch\": 1.5,\n    \"light\": {\n        \"intensity\": 0.5,\n        \"color\": \"hsl(0, 0%, 100%)\",\n        \"anchor\": \"viewport\"\n    },\n    \"sources\": {\n        \"openmaptiles\": {\n            \"type\": \"vector\",\n            \"url\": \"https://tiles.stadiamaps.com/data/openmaptiles.json\"\n        },\n        \"satellite\": {\n            \"attribution\": \"© CNES, Distribution Airbus DS, © Airbus DS, © PlanetObserver (Contains Copernicus Data)\",\n            \"type\": \"raster\",\n            \"tiles\": [\n                \"https://tiles.stadiamaps.com/data/satellite/{z}/{x}/{y}.jpg\"\n            ],\n            \"minzoom\": 0,\n            \"maxzoom\": 24\n        }\n    },\n    \"sprite\": \"asset://sprites\",\n    \"glyphs\": \"asset://{fontstack}/{range}.pbf\",\n    \"layers\": [\n        {\n            \"id\": \"background\",\n            \"type\": \"background\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"background-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    4,\n                    \"hsl(43, 30%, 91%)\",\n                    5,\n                    \"hsl(0, 0%, 96%)\",\n                    8,\n                    \"hsl(0, 0%, 96%)\",\n                    9,\n                    \"#efeee8\",\n                    16,\n                    \"hsl(0, 0%, 95%)\",\n                    18,\n                    \"#f8f9fb\"\n                ]\n            }\n        },\n        {\n            \"id\": \"satellite\",\n            \"type\": \"raster\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"satellite\"\n        },\n        {\n            \"id\": \"path\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\",\n                \"maputnik:comment\": \"unpaved paths\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"minzoom\": 14,\n            \"maxzoom\": 24,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"path\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsl(118, 34%, 66%)\",\n                \"line-dasharray\": [\n                    4,\n                    2\n                ],\n                \"line-opacity\": 0.3\n            }\n        },\n        {\n            \"id\": \"steps\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"subclass\"\n                ],\n                [\n                    \"steps\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsl(118, 5%, 66%)\",\n                \"line-dasharray\": [\n                    1,\n                    1\n                ],\n                \"line-gap-width\": 1,\n                \"line-opacity\": 0.3\n            }\n        },\n        {\n            \"id\": \"platform\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"transit.station.rail\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"platform\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"brunnel\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    false,\n                    true\n                ]\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    \"hsl(2, 20%, 92%)\",\n                    16,\n                    \"hsl(2, 95%, 92%)\"\n                ],\n                \"fill-outline-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    \"hsl(1, 10%, 76%)\",\n                    16,\n                    \"hsl(1, 74%, 76%)\"\n                ],\n                \"fill-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0,\n                    16,\n                    0.3\n                ]\n            }\n        },\n        {\n            \"id\": \"primary_tunnel\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"brunnel\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    1,\n                    12,\n                    4,\n                    14,\n                    6,\n                    16,\n                    10,\n                    22,\n                    64\n                ],\n                \"line-color\": \"hsl(0, 0%, 89%)\",\n                \"line-opacity\": 0.3\n            }\n        },\n        {\n            \"id\": \"aeroway\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"transit.station.airport\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"aeroway\",\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"line-color\": \"hsla(0, 0%, 0%, 0.1)\",\n                \"line-opacity\": 0.3\n            }\n        },\n        {\n            \"id\": \"service_road\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"service\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsla(0, 0%, 0%, 0.1)\",\n                \"line-opacity\": 0.3\n            }\n        },\n        {\n            \"id\": \"railway\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"any\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"rail\"\n                        ],\n                        true,\n                        false\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"subclass\"\n                        ],\n                        [\n                            \"light_rail\",\n                            \"tram\"\n                        ],\n                        true,\n                        false\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"brunnel\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    false,\n                    true\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsl(220, 4%, 85%)\",\n                \"line-opacity\": 0.3\n            }\n        },\n        {\n            \"id\": \"pedestrian\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"pedestrian\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"surface\"\n                    ],\n                    \"paved\"\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"#ffffff\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    13,\n                    1,\n                    16,\n                    4,\n                    22,\n                    32\n                ],\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12.5,\n                    0,\n                    13.5,\n                    0.3\n                ]\n            }\n        },\n        {\n            \"id\": \"street\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"minor\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"#ffffff\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    1,\n                    16,\n                    6,\n                    22,\n                    40\n                ],\n                \"line-opacity\": 0.3\n            }\n        },\n        {\n            \"id\": \"secondary\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"secondary\",\n                    \"tertiary\",\n                    \"trunk\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"#ffffff\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    10,\n                    1,\n                    17,\n                    10,\n                    22,\n                    48\n                ],\n                \"line-opacity\": 0.3\n            }\n        },\n        {\n            \"id\": \"primary\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"brunnel\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    false,\n                    true\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"hsl(50, 100%, 75%)\",\n                    7,\n                    \"hsl(50, 100%, 85%)\"\n                ],\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    1,\n                    16,\n                    8,\n                    22,\n                    64\n                ],\n                \"line-opacity\": 0.3\n            }\n        },\n        {\n            \"id\": \"motorway\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"motorway\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"#ffeba3\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    1,\n                    15.5,\n                    8,\n                    22,\n                    78\n                ],\n                \"line-opacity\": 0.3\n            }\n        },\n        {\n            \"id\": \"admin_0\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3c26e9cbc75335c6f0ba8de5439cf1fa\",\n                \"microg:gms-type-feature\": \"administrative.country\",\n                \"microg:gms-type-element\": \"geometry.stroke\",\n                \"maputnik:comment\": \"maritime=false filter could not be ported due to missing attributes in `boundary` layer\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"boundary\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"admin_level\"\n                    ],\n                    [\n                        2\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"!=\",\n                    [\n                        \"get\",\n                        \"maritime\"\n                    ],\n                    1\n                ]\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"line-color\": [\n                    \"case\",\n                    [\n                        \"==\",\n                        [\n                            \"get\",\n                            \"disputed\"\n                        ],\n                        1\n                    ],\n                    \"hsl(0, 24%, 48%)\",\n                    \"hsl(200, 0%, 80%)\"\n                ]\n            }\n        },\n        {\n            \"id\": \"admin_1\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3c26e9cbc75335c6f0ba8de5439cf1fa\",\n                \"microg:gms-type-feature\": \"administrative.province\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"boundary\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"admin_level\"\n                    ],\n                    [\n                        3,\n                        4\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"!=\",\n                    [\n                        \"get\",\n                        \"maritime\"\n                    ],\n                    1\n                ]\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"line-color\": [\n                    \"case\",\n                    [\n                        \"==\",\n                        [\n                            \"get\",\n                            \"disputed\"\n                        ],\n                        1\n                    ],\n                    \"hsl(0, 24%, 48%)\",\n                    \"hsl(200, 0%, 80%)\"\n                ],\n                \"line-dasharray\": [\n                    1,\n                    1\n                ]\n            }\n        },\n        {\n            \"id\": \"river_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"waterway\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"river\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"symbol-placement\": \"line\",\n                \"symbol-spacing\": 500,\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ]\n            },\n            \"paint\": {\n                \"text-color\": \"#5083c1\",\n                \"text-halo-color\": \"#5083c1\",\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"city_label_right\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"maxzoom\": 8,\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    [\n                        \"*\",\n                        [\n                            \"zoom\"\n                        ],\n                        1.5\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"city\",\n                        \"town\",\n                        \"village\",\n                        \"hamlet\",\n                        \"suburb\",\n                        \"quarter\",\n                        \"neighbourhood\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-optional\": false,\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"-\",\n                        14,\n                        [\n                            \"max\",\n                            0,\n                            [\n                                \"-\",\n                                [\n                                    \"get\",\n                                    \"rank\"\n                                ],\n                                8\n                            ]\n                        ]\n                    ],\n                    22,\n                    [\n                        \"-\",\n                        20,\n                        [\n                            \"/\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            4\n                        ]\n                    ]\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"capital\"\n                    ],\n                    [\n                        2\n                    ],\n                    \"capital\",\n                    \"city\"\n                ],\n                \"text-font\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\"\n                        ]\n                    ],\n                    10,\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Regular\"\n                        ]\n                    ]\n                ],\n                \"text-justify\": \"left\",\n                \"text-offset\": [\n                    0.5,\n                    0.1\n                ],\n                \"icon-size\": [\n                    \"/\",\n                    6,\n                    [\n                        \"+\",\n                        [\n                            \"get\",\n                            \"rank\"\n                        ],\n                        7\n                    ]\n                ],\n                \"text-anchor\": \"left\",\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"-\",\n                            100,\n                            [\n                                \"+\",\n                                [\n                                    \"*\",\n                                    [\n                                        \"get\",\n                                        \"rank\"\n                                    ],\n                                    2\n                                ],\n                                5\n                            ]\n                        ],\n                        \"%)\"\n                    ],\n                    22,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"-\",\n                            100,\n                            [\n                                \"+\",\n                                [\n                                    \"get\",\n                                    \"rank\"\n                                ],\n                                25\n                            ]\n                        ],\n                        \"%)\"\n                    ]\n                ],\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"text-halo-color\": \"hsl(0, 0%, 0%)\",\n                \"icon-opacity\": 0.8\n            }\n        },\n        {\n            \"id\": \"city_label_left\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"maxzoom\": 8,\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    [\n                        \"*\",\n                        [\n                            \"zoom\"\n                        ],\n                        1.5\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"city\",\n                        \"town\",\n                        \"village\",\n                        \"hamlet\",\n                        \"suburb\",\n                        \"quarter\",\n                        \"neighbourhood\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"-\",\n                        14,\n                        [\n                            \"max\",\n                            0,\n                            [\n                                \"-\",\n                                [\n                                    \"get\",\n                                    \"rank\"\n                                ],\n                                8\n                            ]\n                        ]\n                    ],\n                    22,\n                    [\n                        \"-\",\n                        20,\n                        [\n                            \"/\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            4\n                        ]\n                    ]\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"capital\"\n                    ],\n                    [\n                        2\n                    ],\n                    \"capital\",\n                    \"city\"\n                ],\n                \"text-font\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\"\n                        ]\n                    ],\n                    10,\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Regular\"\n                        ]\n                    ]\n                ],\n                \"text-justify\": \"right\",\n                \"text-offset\": [\n                    -0.5,\n                    0.1\n                ],\n                \"icon-size\": [\n                    \"/\",\n                    6,\n                    [\n                        \"+\",\n                        [\n                            \"get\",\n                            \"rank\"\n                        ],\n                        7\n                    ]\n                ],\n                \"text-anchor\": \"right\",\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"-\",\n                            100,\n                            [\n                                \"+\",\n                                [\n                                    \"*\",\n                                    [\n                                        \"get\",\n                                        \"rank\"\n                                    ],\n                                    2\n                                ],\n                                5\n                            ]\n                        ],\n                        \"%)\"\n                    ],\n                    22,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"-\",\n                            100,\n                            [\n                                \"+\",\n                                [\n                                    \"get\",\n                                    \"rank\"\n                                ],\n                                25\n                            ]\n                        ],\n                        \"%)\"\n                    ]\n                ],\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"text-halo-color\": \"hsl(0, 0%, 1%)\",\n                \"icon-opacity\": 0.8\n            }\n        },\n        {\n            \"id\": \"city_label_below\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"maxzoom\": 8,\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    [\n                        \"/\",\n                        [\n                            \"zoom\"\n                        ],\n                        3\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"city\",\n                        \"town\",\n                        \"village\",\n                        \"hamlet\",\n                        \"suburb\",\n                        \"quarter\",\n                        \"neighbourhood\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"-\",\n                        14,\n                        [\n                            \"max\",\n                            0,\n                            [\n                                \"-\",\n                                [\n                                    \"get\",\n                                    \"rank\"\n                                ],\n                                8\n                            ]\n                        ]\n                    ],\n                    22,\n                    [\n                        \"-\",\n                        20,\n                        [\n                            \"/\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            4\n                        ]\n                    ]\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"capital\"\n                    ],\n                    [\n                        2\n                    ],\n                    \"capital\",\n                    \"city\"\n                ],\n                \"text-font\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\"\n                        ]\n                    ],\n                    10,\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Regular\"\n                        ]\n                    ]\n                ],\n                \"text-offset\": [\n                    0,\n                    0.4\n                ],\n                \"icon-size\": [\n                    \"/\",\n                    6,\n                    [\n                        \"+\",\n                        [\n                            \"get\",\n                            \"rank\"\n                        ],\n                        7\n                    ]\n                ],\n                \"text-anchor\": \"top\",\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"-\",\n                            100,\n                            [\n                                \"+\",\n                                [\n                                    \"*\",\n                                    [\n                                        \"get\",\n                                        \"rank\"\n                                    ],\n                                    2\n                                ],\n                                5\n                            ]\n                        ],\n                        \"%)\"\n                    ],\n                    22,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"-\",\n                            100,\n                            [\n                                \"+\",\n                                [\n                                    \"get\",\n                                    \"rank\"\n                                ],\n                                25\n                            ]\n                        ],\n                        \"%)\"\n                    ]\n                ],\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"text-halo-color\": \"hsl(0, 0%, 0%)\",\n                \"icon-opacity\": 0.8\n            }\n        },\n        {\n            \"id\": \"city_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    [\n                        \"*\",\n                        [\n                            \"zoom\"\n                        ],\n                        1.5\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"city\",\n                        \"town\",\n                        \"village\",\n                        \"hamlet\",\n                        \"suburb\",\n                        \"quarter\",\n                        \"neighbourhood\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"-\",\n                        14,\n                        [\n                            \"max\",\n                            0,\n                            [\n                                \"-\",\n                                [\n                                    \"get\",\n                                    \"rank\"\n                                ],\n                                8\n                            ]\n                        ]\n                    ],\n                    22,\n                    [\n                        \"-\",\n                        20,\n                        [\n                            \"/\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            4\n                        ]\n                    ]\n                ],\n                \"icon-image\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"capital\"\n                        ],\n                        [\n                            2\n                        ],\n                        \"capital\",\n                        \"city\"\n                    ],\n                    8,\n                    \"\"\n                ],\n                \"text-transform\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    \"none\",\n                    15,\n                    \"uppercase\"\n                ],\n                \"text-font\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\"\n                        ]\n                    ],\n                    10,\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Regular\"\n                        ]\n                    ]\n                ],\n                \"text-offset\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            0,\n                            -0.2\n                        ]\n                    ],\n                    8,\n                    [\n                        \"literal\",\n                        [\n                            0,\n                            0\n                        ]\n                    ]\n                ],\n                \"icon-size\": [\n                    \"/\",\n                    6,\n                    [\n                        \"+\",\n                        [\n                            \"get\",\n                            \"rank\"\n                        ],\n                        7\n                    ]\n                ],\n                \"text-anchor\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"bottom\",\n                    8,\n                    \"center\"\n                ],\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-letter-spacing\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    0,\n                    0,\n                    8,\n                    0,\n                    12,\n                    0.1,\n                    16,\n                    0.2\n                ],\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"-\",\n                            100,\n                            [\n                                \"+\",\n                                [\n                                    \"*\",\n                                    [\n                                        \"get\",\n                                        \"rank\"\n                                    ],\n                                    2\n                                ],\n                                5\n                            ]\n                        ],\n                        \"%)\"\n                    ],\n                    22,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"-\",\n                            100,\n                            [\n                                \"+\",\n                                [\n                                    \"get\",\n                                    \"rank\"\n                                ],\n                                25\n                            ]\n                        ],\n                        \"%)\"\n                    ]\n                ],\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"text-halo-color\": \"hsl(0, 0%, 0%)\",\n                \"icon-opacity\": 0.8\n            }\n        },\n        {\n            \"id\": \"park_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"poi.park\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"poi\",\n            \"minzoom\": 17,\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"park\",\n                        \"cemetery\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    250\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-size\": 14\n            },\n            \"paint\": {\n                \"text-color\": \"#297925\",\n                \"text-halo-color\": \"hsl(0, 0%, 100%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"road-number-shield\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road\",\n                \"microg:gms-type-element\": \"labels.icon\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation_name\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"ref\"\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"ref_length\"\n                    ],\n                    6\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": 9,\n                \"icon-image\": [\n                    \"case\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"network\"\n                        ],\n                        [\n                            \"us-interstate\"\n                        ],\n                        true,\n                        false\n                    ],\n                    [\n                        \"concat\",\n                        \"shield_\",\n                        [\n                            \"get\",\n                            \"network\"\n                        ],\n                        \"_\",\n                        [\n                            \"get\",\n                            \"ref_length\"\n                        ]\n                    ],\n                    [\n                        \"concat\",\n                        \"shield_rectangle-white_\",\n                        [\n                            \"get\",\n                            \"ref_length\"\n                        ]\n                    ]\n                ],\n                \"icon-rotation-alignment\": \"viewport\",\n                \"text-font\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"shield_text_color\"\n                    ],\n                    [\n                        \"white\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Bold\"\n                        ]\n                    ],\n                    [\n                        \"black\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\"\n                        ]\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Bold\"\n                        ]\n                    ]\n                ],\n                \"symbol-placement\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"point\",\n                    11,\n                    \"line\"\n                ],\n                \"text-offset\": [\n                    0,\n                    0.1\n                ],\n                \"text-rotation-alignment\": \"viewport\",\n                \"icon-size\": 0.75,\n                \"text-field\": [\n                    \"get\",\n                    \"ref\"\n                ],\n                \"text-letter-spacing\": 0.05,\n                \"visibility\": \"visible\",\n                \"icon-padding\": 10\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"case\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"network\"\n                        ],\n                        [\n                            \"us-interstate\"\n                        ],\n                        true,\n                        false\n                    ],\n                    \"#ffffff\",\n                    \"#000000\"\n                ]\n            }\n        },\n        {\n            \"id\": \"country_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"administrative.country\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"country\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {\n                \"text-letter-spacing\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    1,\n                    0,\n                    3,\n                    0.15\n                ],\n                \"text-font\": [\n                    \"Roboto Medium\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.2\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    1,\n                    12,\n                    7,\n                    [\n                        \"/\",\n                        30,\n                        [\n                            \"get\",\n                            \"rank\"\n                        ]\n                    ]\n                ],\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(0, 0%, 90%)\",\n                \"text-halo-color\": \"hsl(0, 0%, 0%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"text-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    6,\n                    1,\n                    7,\n                    0\n                ]\n            }\n        },\n        {\n            \"id\": \"pedestrian_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation_name\",\n            \"minzoom\": 16,\n            \"filter\": [\n                \"any\",\n                [\n                    \"all\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"subclass\"\n                        ],\n                        [\n                            \"pedestrian\"\n                        ],\n                        true,\n                        false\n                    ],\n                    [\n                        \"==\",\n                        [\n                            \"get\",\n                            \"surface\"\n                        ],\n                        \"paved\"\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    \"platform\",\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"name\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    17,\n                    10,\n                    22,\n                    14\n                ],\n                \"text-padding\": 5\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(0, 0%, 86%)\",\n                \"text-halo-color\": \"#000000\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"street_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation_name\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"minor\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"name\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    6,\n                    16,\n                    10\n                ],\n                \"text-padding\": 5\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(0, 0%, 86%)\",\n                \"text-halo-color\": \"#000000\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"secondary_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation_name\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"secondary\",\n                        \"tertiary\",\n                        \"trunk\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"name\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    8,\n                    16,\n                    13\n                ],\n                \"symbol-spacing\": 300,\n                \"text-padding\": 25\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(0, 0%, 86%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-color\": \"#000000\",\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"primary_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation_name\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"name\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    10,\n                    18,\n                    14\n                ],\n                \"symbol-spacing\": 800,\n                \"text-padding\": 50\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(32, 58%, 93%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-color\": \"#000000\",\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"poi_label_below\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"124a9d7a8e5226775d947c592110dfad\",\n                \"microg:gms-type-element\": \"labels.text\",\n                \"microg:gms-type-feature\": \"poi\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"poi\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"bus\",\n                        \"railway\"\n                    ],\n                    false,\n                    true\n                ],\n                [\n                    \"any\",\n                    [\n                        \"!=\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ],\n                            [\n                                \"park\",\n                                \"cemetery\"\n                            ],\n                            true,\n                            false\n                        ],\n                        [\n                            \"<=\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            250\n                        ]\n                    ],\n                    [\n                        \">=\",\n                        [\n                            \"zoom\"\n                        ],\n                        16\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-optional\": false,\n                \"text-line-height\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    15,\n                    1.2\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    13,\n                    15,\n                    14\n                ],\n                \"icon-offset\": [\n                    0,\n                    -36\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"museum\",\n                        \"theatre\",\n                        \"restaurant\"\n                    ],\n                    [\n                        \"concat\",\n                        \"poi_\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ]\n                    ],\n                    [\n                        \"fitness_centre\",\n                        \"golf_course\",\n                        \"camp_site\",\n                        \"bowling_alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic_site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog_park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"poi_generic_green\",\n                    [\n                        \"bank\",\n                        \"atm\",\n                        \"parking\",\n                        \"toilets\",\n                        \"garages\"\n                    ],\n                    \"poi_generic_purple\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\"\n                    ],\n                    \"poi_generic_orange\",\n                    [\n                        \"casino\",\n                        \"castle\",\n                        \"gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music_venue\",\n                        \"monument\"\n                    ],\n                    \"poi_generic_teal\",\n                    [\n                        \"hospital\",\n                        \"doctors\"\n                    ],\n                    \"poi_generic_red\",\n                    [\n                        \"fast_food\",\n                        \"ice_cream\"\n                    ],\n                    \"poi_restaurant\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"lodging\",\n                            \"grocery\"\n                        ],\n                        [\n                            \"concat\",\n                            \"poi_\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ]\n                        ],\n                        [\n                            \"clothing_store\",\n                            \"shop\"\n                        ],\n                        \"poi_generic_blue\",\n                        \"poi_generic\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-offset\": [\n                    0,\n                    0.5\n                ],\n                \"icon-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.25,\n                    15,\n                    0.32\n                ],\n                \"text-anchor\": \"top\",\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-padding\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    30,\n                    17,\n                    5\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"fitness_centre\",\n                        \"golf_course\",\n                        \"camp_site\",\n                        \"bowling_alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic_site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog_park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"hsl(117, 53%, 65%)\",\n                    [\n                        \"bank\",\n                        \"atm\",\n                        \"parking\",\n                        \"toilets\",\n                        \"garages\"\n                    ],\n                    \"hsl(228, 17%, 65%)\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\",\n                        \"fast_food\",\n                        \"restaurant\",\n                        \"ice_cream\"\n                    ],\n                    \"hsl(20, 50%, 65%)\",\n                    [\n                        \"museum\",\n                        \"theatre\",\n                        \"casino\",\n                        \"castle\",\n                        \"gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music_venue\",\n                        \"monument\"\n                    ],\n                    \"hsl(186, 78%, 65%)\",\n                    [\n                        \"hospital\",\n                        \"doctors\"\n                    ],\n                    \"hsl(359, 22%, 65%)\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"lodging\"\n                        ],\n                        \"#df7db1\",\n                        [\n                            \"grocery\",\n                            \"clothing_store\",\n                            \"shop\"\n                        ],\n                        \"hsl(213, 40%, 65%)\",\n                        \"hsl(201, 9%, 80%)\"\n                    ]\n                ],\n                \"text-halo-color\": \"#000000\",\n                \"text-halo-width\": 1,\n                \"icon-translate\": [\n                    0,\n                    0\n                ],\n                \"text-translate\": [\n                    0,\n                    0\n                ],\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"poi_label_above\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"124a9d7a8e5226775d947c592110dfad\",\n                \"microg:gms-type-element\": \"labels.text\",\n                \"microg:gms-type-feature\": \"poi\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"poi\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"bus\",\n                        \"railway\"\n                    ],\n                    false,\n                    true\n                ],\n                [\n                    \"any\",\n                    [\n                        \"!=\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ],\n                            [\n                                \"park\",\n                                \"cemetery\"\n                            ],\n                            true,\n                            false\n                        ],\n                        [\n                            \"<=\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            250\n                        ]\n                    ],\n                    [\n                        \">=\",\n                        [\n                            \"zoom\"\n                        ],\n                        16\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-optional\": false,\n                \"text-line-height\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    15,\n                    1.2\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    13,\n                    15,\n                    14\n                ],\n                \"icon-offset\": [\n                    0,\n                    -36\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"museum\",\n                        \"theatre\",\n                        \"restaurant\"\n                    ],\n                    [\n                        \"concat\",\n                        \"poi_\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ]\n                    ],\n                    [\n                        \"fitness_centre\",\n                        \"golf_course\",\n                        \"camp_site\",\n                        \"bowling_alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic_site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog_park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"poi_generic_green\",\n                    [\n                        \"bank\",\n                        \"atm\",\n                        \"parking\",\n                        \"toilets\",\n                        \"garages\"\n                    ],\n                    \"poi_generic_purple\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\"\n                    ],\n                    \"poi_generic_orange\",\n                    [\n                        \"casino\",\n                        \"castle\",\n                        \"gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music_venue\",\n                        \"monument\"\n                    ],\n                    \"poi_generic_teal\",\n                    [\n                        \"hospital\",\n                        \"doctors\"\n                    ],\n                    \"poi_generic_red\",\n                    [\n                        \"fast_food\",\n                        \"ice_cream\"\n                    ],\n                    \"poi_restaurant\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"lodging\",\n                            \"grocery\"\n                        ],\n                        [\n                            \"concat\",\n                            \"poi_\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ]\n                        ],\n                        [\n                            \"clothing_store\",\n                            \"shop\"\n                        ],\n                        \"poi_generic_blue\",\n                        \"poi_generic\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-offset\": [\n                    0,\n                    -2\n                ],\n                \"icon-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.25,\n                    15,\n                    0.32\n                ],\n                \"text-anchor\": \"bottom\",\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-padding\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    30,\n                    17,\n                    5\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"fitness_centre\",\n                        \"golf_course\",\n                        \"camp_site\",\n                        \"bowling_alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic_site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog_park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"hsl(117, 53%, 65%)\",\n                    [\n                        \"bank\",\n                        \"atm\",\n                        \"parking\",\n                        \"toilets\",\n                        \"garages\"\n                    ],\n                    \"hsl(228, 17%, 65%)\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\",\n                        \"fast_food\",\n                        \"restaurant\",\n                        \"ice_cream\"\n                    ],\n                    \"hsl(20, 50%, 65%)\",\n                    [\n                        \"museum\",\n                        \"theatre\",\n                        \"casino\",\n                        \"castle\",\n                        \"gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music_venue\",\n                        \"monument\"\n                    ],\n                    \"hsl(186, 78%, 65%)\",\n                    [\n                        \"hospital\",\n                        \"doctors\"\n                    ],\n                    \"hsl(359, 22%, 65%)\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"lodging\"\n                        ],\n                        \"#df7db1\",\n                        [\n                            \"grocery\",\n                            \"clothing_store\",\n                            \"shop\"\n                        ],\n                        \"hsl(213, 40%, 65%)\",\n                        \"hsl(201, 9%, 80%)\"\n                    ]\n                ],\n                \"text-halo-color\": \"#000000\",\n                \"text-halo-width\": 1,\n                \"icon-translate\": [\n                    0,\n                    0\n                ],\n                \"text-translate\": [\n                    0,\n                    0\n                ],\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"poi_label_left\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"124a9d7a8e5226775d947c592110dfad\",\n                \"microg:gms-type-element\": \"labels.text\",\n                \"microg:gms-type-feature\": \"poi\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"poi\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"bus\",\n                        \"railway\"\n                    ],\n                    false,\n                    true\n                ],\n                [\n                    \"any\",\n                    [\n                        \"!=\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ],\n                            [\n                                \"park\",\n                                \"cemetery\"\n                            ],\n                            true,\n                            false\n                        ],\n                        [\n                            \"<=\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            250\n                        ]\n                    ],\n                    [\n                        \">=\",\n                        [\n                            \"zoom\"\n                        ],\n                        16\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-line-height\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    15,\n                    1.2\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    13,\n                    15,\n                    14\n                ],\n                \"icon-offset\": [\n                    0,\n                    -36\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"museum\",\n                        \"theatre\",\n                        \"restaurant\"\n                    ],\n                    [\n                        \"concat\",\n                        \"poi_\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ]\n                    ],\n                    [\n                        \"fitness_centre\",\n                        \"golf_course\",\n                        \"camp_site\",\n                        \"bowling_alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic_site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog_park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"poi_generic_green\",\n                    [\n                        \"bank\",\n                        \"atm\",\n                        \"parking\",\n                        \"toilets\",\n                        \"garages\"\n                    ],\n                    \"poi_generic_purple\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\"\n                    ],\n                    \"poi_generic_orange\",\n                    [\n                        \"casino\",\n                        \"castle\",\n                        \"gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music_venue\",\n                        \"monument\"\n                    ],\n                    \"poi_generic_teal\",\n                    [\n                        \"hospital\",\n                        \"doctors\"\n                    ],\n                    \"poi_generic_red\",\n                    [\n                        \"fast_food\",\n                        \"ice_cream\"\n                    ],\n                    \"poi_restaurant\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"lodging\",\n                            \"grocery\"\n                        ],\n                        [\n                            \"concat\",\n                            \"poi_\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ]\n                        ],\n                        [\n                            \"clothing_store\",\n                            \"shop\"\n                        ],\n                        \"poi_generic_blue\",\n                        \"poi_generic\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-justify\": \"right\",\n                \"text-offset\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    [\n                        \"literal\",\n                        [\n                            -1.1,\n                            -0.7\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            -1.1,\n                            -0.9\n                        ]\n                    ]\n                ],\n                \"icon-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.25,\n                    15,\n                    0.32\n                ],\n                \"text-anchor\": \"right\",\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-padding\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    30,\n                    17,\n                    5\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"fitness_centre\",\n                        \"golf_course\",\n                        \"camp_site\",\n                        \"bowling_alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic_site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog_park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"hsl(117, 53%, 65%)\",\n                    [\n                        \"bank\",\n                        \"atm\",\n                        \"parking\",\n                        \"toilets\",\n                        \"garages\"\n                    ],\n                    \"hsl(228, 17%, 65%)\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\",\n                        \"fast_food\",\n                        \"restaurant\",\n                        \"ice_cream\"\n                    ],\n                    \"hsl(20, 50%, 65%)\",\n                    [\n                        \"museum\",\n                        \"theatre\",\n                        \"casino\",\n                        \"castle\",\n                        \"gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music_venue\",\n                        \"monument\"\n                    ],\n                    \"hsl(186, 78%, 65%)\",\n                    [\n                        \"hospital\",\n                        \"doctors\"\n                    ],\n                    \"hsl(359, 22%, 65%)\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"lodging\"\n                        ],\n                        \"#df7db1\",\n                        [\n                            \"grocery\",\n                            \"clothing_store\",\n                            \"shop\"\n                        ],\n                        \"hsl(213, 40%, 65%)\",\n                        \"hsl(201, 9%, 80%)\"\n                    ]\n                ],\n                \"text-halo-color\": \"#000000\",\n                \"text-halo-width\": 1,\n                \"icon-translate\": [\n                    0,\n                    0\n                ],\n                \"text-translate\": [\n                    0,\n                    0\n                ],\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"poi_label_right\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"124a9d7a8e5226775d947c592110dfad\",\n                \"microg:gms-type-element\": \"labels.text\",\n                \"microg:gms-type-feature\": \"poi\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"poi\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"bus\",\n                        \"railway\"\n                    ],\n                    false,\n                    true\n                ],\n                [\n                    \"any\",\n                    [\n                        \"!=\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ],\n                            [\n                                \"park\",\n                                \"cemetery\"\n                            ],\n                            true,\n                            false\n                        ],\n                        [\n                            \"<=\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            250\n                        ]\n                    ],\n                    [\n                        \">=\",\n                        [\n                            \"zoom\"\n                        ],\n                        16\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-line-height\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    15,\n                    1.2\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    13,\n                    15,\n                    14\n                ],\n                \"icon-offset\": [\n                    0,\n                    -36\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"museum\",\n                        \"theatre\",\n                        \"restaurant\"\n                    ],\n                    [\n                        \"concat\",\n                        \"poi_\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ]\n                    ],\n                    [\n                        \"fitness_centre\",\n                        \"golf_course\",\n                        \"camp_site\",\n                        \"bowling_alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic_site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog_park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"poi_generic_green\",\n                    [\n                        \"bank\",\n                        \"atm\",\n                        \"parking\",\n                        \"toilets\",\n                        \"garages\"\n                    ],\n                    \"poi_generic_purple\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\"\n                    ],\n                    \"poi_generic_orange\",\n                    [\n                        \"casino\",\n                        \"castle\",\n                        \"gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music_venue\",\n                        \"monument\"\n                    ],\n                    \"poi_generic_teal\",\n                    [\n                        \"hospital\",\n                        \"doctors\"\n                    ],\n                    \"poi_generic_red\",\n                    [\n                        \"fast_food\",\n                        \"ice_cream\"\n                    ],\n                    \"poi_restaurant\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"lodging\",\n                            \"grocery\"\n                        ],\n                        [\n                            \"concat\",\n                            \"poi_\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ]\n                        ],\n                        [\n                            \"clothing_store\",\n                            \"shop\"\n                        ],\n                        \"poi_generic_blue\",\n                        \"poi_generic\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-justify\": \"left\",\n                \"text-offset\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    [\n                        \"literal\",\n                        [\n                            1.1,\n                            -0.7\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            1.1,\n                            -0.9\n                        ]\n                    ]\n                ],\n                \"icon-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.25,\n                    15,\n                    0.32\n                ],\n                \"text-anchor\": \"left\",\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-padding\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    30,\n                    17,\n                    5\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"fitness_centre\",\n                        \"golf_course\",\n                        \"camp_site\",\n                        \"bowling_alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic_site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog_park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"hsl(117, 53%, 65%)\",\n                    [\n                        \"bank\",\n                        \"atm\",\n                        \"parking\",\n                        \"toilets\",\n                        \"garages\"\n                    ],\n                    \"hsl(228, 17%, 65%)\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\",\n                        \"fast_food\",\n                        \"restaurant\",\n                        \"ice_cream\"\n                    ],\n                    \"hsl(20, 50%, 65%)\",\n                    [\n                        \"museum\",\n                        \"theatre\",\n                        \"casino\",\n                        \"castle\",\n                        \"gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music_venue\",\n                        \"monument\"\n                    ],\n                    \"hsl(186, 78%, 65%)\",\n                    [\n                        \"hospital\",\n                        \"doctors\"\n                    ],\n                    \"hsl(359, 22%, 65%)\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"lodging\"\n                        ],\n                        \"#df7db1\",\n                        [\n                            \"grocery\",\n                            \"clothing_store\",\n                            \"shop\"\n                        ],\n                        \"hsl(213, 40%, 65%)\",\n                        \"hsl(201, 9%, 80%)\"\n                    ]\n                ],\n                \"text-halo-color\": \"#000000\",\n                \"text-halo-width\": 1,\n                \"icon-translate\": [\n                    0,\n                    0\n                ],\n                \"text-translate\": [\n                    0,\n                    0\n                ],\n                \"text-halo-blur\": 1\n            }\n        }\n    ],\n    \"created\": \"2019-04-15T08:41:40.148Z\",\n    \"modified\": \"2020-09-05T19:42:03.856Z\",\n    \"id\": \"cjui4020201oo1fmca7yuwbor\",\n    \"owner\": \"microg\",\n    \"visibility\": \"public\",\n    \"protected\": false,\n    \"draft\": false\n}\n"
  },
  {
    "path": "artwork/styles/style-stadia-outdoors.json",
    "content": "{\n    \"bearing\": 0,\n    \"center\": [\n        8.542,\n        47.372\n    ],\n    \"glyphs\": \"https://tiles.stadiamaps.com/fonts/{fontstack}/{range}.pbf\",\n    \"layers\": [\n        {\n            \"id\": \"background\",\n            \"paint\": {\n                \"background-color\": \"#f9f3ea\"\n            },\n            \"type\": \"background\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"==\",\n                \"subclass\",\n                \"glacier\"\n            ],\n            \"id\": \"landcover-glacier\",\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": \"#fff\",\n                \"fill-opacity\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            0,\n                            0.9\n                        ],\n                        [\n                            10,\n                            0.3\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"landcover\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"==\",\n                \"$type\",\n                \"Polygon\"\n            ],\n            \"id\": \"park\",\n            \"paint\": {\n                \"fill-color\": \"#d8e8c8\",\n                \"fill-opacity\": {\n                    \"base\": 1.8,\n                    \"stops\": [\n                        [\n                            6,\n                            0.5\n                        ],\n                        [\n                            12,\n                            0.2\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"park\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"==\",\n                \"class\",\n                \"cemetery\"\n            ],\n            \"id\": \"landuse-cemetery\",\n            \"paint\": {\n                \"fill-color\": \"#e0e4dd\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"landuse\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"==\",\n                \"class\",\n                \"railway\"\n            ],\n            \"id\": \"landuse-railway\",\n            \"paint\": {\n                \"fill-color\": \"hsla(30, 19%, 90%, 0.4)\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"landuse\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"in\",\n                \"class\",\n                \"public_park\",\n                \"national_park\",\n                \"nature_reserve\"\n            ],\n            \"id\": \"landcover-grass-park\",\n            \"paint\": {\n                \"fill-antialias\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            0,\n                            false\n                        ],\n                        [\n                            9,\n                            true\n                        ]\n                    ]\n                },\n                \"fill-color\": \"#d5e8c2\",\n                \"fill-outline-color\": \"hsla(0, 0%, 0%, 0.1)\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"park\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"poi.park\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"class\",\n                    \"rock\"\n                ]\n            ],\n            \"id\": \"landcover-rock\",\n            \"paint\": {\n                \"fill-color\": \"hsla(0, 0%, 85%, 1)\",\n                \"fill-opacity\": 1,\n                \"fill-outline-color\": \"hsla(0, 0%, 0%, 0.1)\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"landcover\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"class\",\n                    \"sand\"\n                ]\n            ],\n            \"id\": \"landcover-sand\",\n            \"paint\": {\n                \"fill-color\": \"hsla(44, 70%, 87%, 1)\",\n                \"fill-opacity\": 1,\n                \"fill-outline-color\": \"hsla(0, 0%, 0%, 0.1)\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"landcover\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"==\",\n                \"class\",\n                \"wetland\"\n            ],\n            \"id\": \"landcover-wetland\",\n            \"paint\": {\n                \"fill-antialias\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            0,\n                            false\n                        ],\n                        [\n                            9,\n                            true\n                        ]\n                    ]\n                },\n                \"fill-color\": \"#3D85C6\",\n                \"fill-opacity\": 0.075,\n                \"fill-outline-color\": \"hsla(0, 0%, 0%, 0.03)\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"landcover\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"==\",\n                \"class\",\n                \"wood\"\n            ],\n            \"id\": \"landcover-wood\",\n            \"paint\": {\n                \"fill-antialias\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            0,\n                            false\n                        ],\n                        [\n                            9,\n                            true\n                        ]\n                    ]\n                },\n                \"fill-color\": \"#90d86c\",\n                \"fill-opacity\": 0.15,\n                \"fill-outline-color\": \"hsla(0, 0%, 0%, 0.2)\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"landcover\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"==\",\n                \"class\",\n                \"grass\"\n            ],\n            \"id\": \"landcover-grass\",\n            \"paint\": {\n                \"fill-color\": \"#d8e8c8\",\n                \"fill-opacity\": 1\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"landcover\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"!in\",\n                \"class\",\n                \"canal\",\n                \"river\",\n                \"stream\"\n            ],\n            \"id\": \"waterway-other\",\n            \"layout\": {\n                \"line-cap\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#a0c8f0\",\n                \"line-width\": {\n                    \"base\": 1.3,\n                    \"stops\": [\n                        [\n                            13,\n                            0.5\n                        ],\n                        [\n                            20,\n                            2\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"waterway\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"in\",\n                \"class\",\n                \"canal\",\n                \"stream\"\n            ],\n            \"id\": \"waterway-stream-canal\",\n            \"layout\": {\n                \"line-cap\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#a0c8f0\",\n                \"line-width\": {\n                    \"base\": 1.3,\n                    \"stops\": [\n                        [\n                            13,\n                            0.5\n                        ],\n                        [\n                            20,\n                            6\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"waterway\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"==\",\n                \"class\",\n                \"river\"\n            ],\n            \"id\": \"waterway-river\",\n            \"layout\": {\n                \"line-cap\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#a0c8f0\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            10,\n                            0.8\n                        ],\n                        [\n                            20,\n                            6\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"waterway\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"in\",\n                    \"admin_level\",\n                    4\n                ],\n                [\n                    \"!=\",\n                    \"maritime\",\n                    1\n                ]\n            ],\n            \"id\": \"boundary-land-level-4\",\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#9e9cab\",\n                \"line-dasharray\": [\n                    4,\n                    2,\n                    2,\n                    2\n                ],\n                \"line-opacity\": 0.5,\n                \"line-width\": {\n                    \"base\": 1.4,\n                    \"stops\": [\n                        [\n                            4,\n                            0.4\n                        ],\n                        [\n                            5,\n                            0.8\n                        ],\n                        [\n                            12,\n                            2.5\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"boundary\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"administrative.province\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"admin_level\",\n                    2\n                ],\n                [\n                    \"!=\",\n                    \"maritime\",\n                    1\n                ],\n                [\n                    \"!=\",\n                    \"disputed\",\n                    1\n                ]\n            ],\n            \"id\": \"boundary-land-level-2\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"hsl(248, 7%, 66%)\",\n                \"line-width\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            0,\n                            0.6\n                        ],\n                        [\n                            4,\n                            1.4\n                        ],\n                        [\n                            5,\n                            2\n                        ],\n                        [\n                            12,\n                            4\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"boundary\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"administrative.country\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"!=\",\n                    \"maritime\",\n                    1\n                ],\n                [\n                    \"==\",\n                    \"disputed\",\n                    1\n                ]\n            ],\n            \"id\": \"boundary-land-disputed\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"hsl(248, 7%, 70%)\",\n                \"line-dasharray\": [\n                    1,\n                    3\n                ],\n                \"line-width\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            0,\n                            0.6\n                        ],\n                        [\n                            4,\n                            1.4\n                        ],\n                        [\n                            5,\n                            2\n                        ],\n                        [\n                            12,\n                            4\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"boundary\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"administrative.country\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"==\",\n                \"$type\",\n                \"Polygon\"\n            ],\n            \"id\": \"water-offset\",\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"maxzoom\": 8,\n            \"minzoom\": 6,\n            \"paint\": {\n                \"fill-color\": \"#a0c8f0\",\n                \"fill-opacity\": 1,\n                \"fill-translate\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            6,\n                            [\n                                2,\n                                0\n                            ]\n                        ],\n                        [\n                            8,\n                            [\n                                0,\n                                0\n                            ]\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"water\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"water\",\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": \"hsl(210, 60%, 80%)\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"water\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"==\",\n                \"$type\",\n                \"Polygon\"\n            ],\n            \"id\": \"park-outline\",\n            \"layout\": {},\n            \"minzoom\": 6,\n            \"paint\": {\n                \"line-color\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            6,\n                            \"hsla(96, 40%, 49%, 0.36)\"\n                        ],\n                        [\n                            8,\n                            \"hsla(96, 40%, 49%, 0.66)\"\n                        ]\n                    ]\n                },\n                \"line-dasharray\": [\n                    3,\n                    3\n                ]\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"park\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"poi.park\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"==\",\n                \"subclass\",\n                \"ice_shelf\"\n            ],\n            \"id\": \"landcover-ice-shelf\",\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": \"#fff\",\n                \"fill-opacity\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            0,\n                            0.9\n                        ],\n                        [\n                            10,\n                            0.3\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"landcover\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"building\",\n            \"paint\": {\n                \"fill-antialias\": true,\n                \"fill-color\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            15.5,\n                            \"#f2eae2\"\n                        ],\n                        [\n                            16,\n                            \"#dfdbd7\"\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"building\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"building-top\",\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": \"#f2eae2\",\n                \"fill-opacity\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            13,\n                            0\n                        ],\n                        [\n                            16,\n                            1\n                        ]\n                    ]\n                },\n                \"fill-outline-color\": \"#dfdbd7\",\n                \"fill-translate\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            14,\n                            [\n                                0,\n                                0\n                            ]\n                        ],\n                        [\n                            16,\n                            [\n                                -2,\n                                -2\n                            ]\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"building\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"tunnel\"\n                ],\n                [\n                    \"in\",\n                    \"class\",\n                    \"service\",\n                    \"track\"\n                ]\n            ],\n            \"id\": \"tunnel-service-track-casing\",\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#cfcdca\",\n                \"line-dasharray\": [\n                    0.5,\n                    0.25\n                ],\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            15,\n                            1\n                        ],\n                        [\n                            16,\n                            4\n                        ],\n                        [\n                            20,\n                            11\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"tunnel\"\n                ],\n                [\n                    \"==\",\n                    \"class\",\n                    \"minor\"\n                ]\n            ],\n            \"id\": \"tunnel-minor-casing\",\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#cfcdca\",\n                \"line-opacity\": {\n                    \"stops\": [\n                        [\n                            12,\n                            0\n                        ],\n                        [\n                            12.5,\n                            1\n                        ]\n                    ]\n                },\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            12,\n                            0.5\n                        ],\n                        [\n                            13,\n                            1\n                        ],\n                        [\n                            14,\n                            4\n                        ],\n                        [\n                            20,\n                            15\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"tunnel\"\n                ],\n                [\n                    \"in\",\n                    \"class\",\n                    \"secondary\",\n                    \"tertiary\"\n                ]\n            ],\n            \"id\": \"tunnel-secondary-tertiary-casing\",\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#e9ac77\",\n                \"line-opacity\": 1,\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            8,\n                            1.5\n                        ],\n                        [\n                            20,\n                            17\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"tunnel\"\n                ],\n                [\n                    \"in\",\n                    \"class\",\n                    \"primary\",\n                    \"trunk\"\n                ]\n            ],\n            \"id\": \"tunnel-trunk-primary-casing\",\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#e9ac77\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            5,\n                            0.4\n                        ],\n                        [\n                            6,\n                            0.6\n                        ],\n                        [\n                            7,\n                            1.5\n                        ],\n                        [\n                            20,\n                            22\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"tunnel\"\n                ],\n                [\n                    \"==\",\n                    \"class\",\n                    \"motorway\"\n                ]\n            ],\n            \"id\": \"tunnel-motorway-casing\",\n            \"layout\": {\n                \"line-join\": \"round\",\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"line-color\": \"#e9ac77\",\n                \"line-dasharray\": [\n                    0.5,\n                    0.25\n                ],\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            5,\n                            0.4\n                        ],\n                        [\n                            6,\n                            0.6\n                        ],\n                        [\n                            7,\n                            1.5\n                        ],\n                        [\n                            20,\n                            22\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ],\n                [\n                    \"all\",\n                    [\n                        \"==\",\n                        \"brunnel\",\n                        \"tunnel\"\n                    ],\n                    [\n                        \"in\",\n                        \"class\",\n                        \"path\",\n                        \"footway\"\n                    ]\n                ]\n            ],\n            \"id\": \"tunnel-path\",\n            \"paint\": {\n                \"line-color\": \"#cba\",\n                \"line-dasharray\": [\n                    1.5,\n                    0.75\n                ],\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            15,\n                            1.2\n                        ],\n                        [\n                            20,\n                            4\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"tunnel\"\n                ],\n                [\n                    \"in\",\n                    \"class\",\n                    \"service\",\n                    \"track\"\n                ]\n            ],\n            \"id\": \"tunnel-service-track\",\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#fff\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            15.5,\n                            0\n                        ],\n                        [\n                            16,\n                            2\n                        ],\n                        [\n                            20,\n                            7.5\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"tunnel\"\n                ],\n                [\n                    \"==\",\n                    \"class\",\n                    \"minor_road\"\n                ]\n            ],\n            \"id\": \"tunnel-minor\",\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#fff\",\n                \"line-opacity\": 1,\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            13.5,\n                            0\n                        ],\n                        [\n                            14,\n                            2.5\n                        ],\n                        [\n                            20,\n                            11.5\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"tunnel\"\n                ],\n                [\n                    \"in\",\n                    \"class\",\n                    \"secondary\",\n                    \"tertiary\"\n                ]\n            ],\n            \"id\": \"tunnel-secondary-tertiary\",\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#fff4c6\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            6.5,\n                            0\n                        ],\n                        [\n                            7,\n                            0.5\n                        ],\n                        [\n                            20,\n                            10\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"tunnel\"\n                ],\n                [\n                    \"in\",\n                    \"class\",\n                    \"primary\",\n                    \"trunk\"\n                ]\n            ],\n            \"id\": \"tunnel-trunk-primary\",\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#fff4c6\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            6.5,\n                            0\n                        ],\n                        [\n                            7,\n                            0.5\n                        ],\n                        [\n                            20,\n                            18\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"tunnel\"\n                ],\n                [\n                    \"==\",\n                    \"class\",\n                    \"motorway\"\n                ]\n            ],\n            \"id\": \"tunnel-motorway\",\n            \"layout\": {\n                \"line-join\": \"round\",\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"line-color\": \"#ffdaa6\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            6.5,\n                            0\n                        ],\n                        [\n                            7,\n                            0.5\n                        ],\n                        [\n                            20,\n                            18\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"tunnel\"\n                ],\n                [\n                    \"==\",\n                    \"class\",\n                    \"rail\"\n                ]\n            ],\n            \"id\": \"tunnel-railway\",\n            \"paint\": {\n                \"line-color\": \"#bbb\",\n                \"line-dasharray\": [\n                    2,\n                    2\n                ],\n                \"line-width\": {\n                    \"base\": 1.4,\n                    \"stops\": [\n                        [\n                            14,\n                            0.4\n                        ],\n                        [\n                            15,\n                            0.75\n                        ],\n                        [\n                            20,\n                            2\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"in\",\n                    \"class\",\n                    \"ferry\"\n                ]\n            ],\n            \"id\": \"ferry\",\n            \"layout\": {\n                \"line-join\": \"round\",\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"line-color\": \"rgba(108, 159, 182, 1)\",\n                \"line-dasharray\": [\n                    2,\n                    2\n                ],\n                \"line-width\": 1.1\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"in\",\n                    \"class\",\n                    \"taxiway\"\n                ]\n            ],\n            \"id\": \"aeroway-taxiway-casing\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\",\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 12,\n            \"paint\": {\n                \"line-color\": \"rgba(153, 153, 153, 1)\",\n                \"line-opacity\": 1,\n                \"line-width\": {\n                    \"base\": 1.5,\n                    \"stops\": [\n                        [\n                            11,\n                            2\n                        ],\n                        [\n                            17,\n                            12\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"aeroway\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"in\",\n                    \"class\",\n                    \"runway\"\n                ]\n            ],\n            \"id\": \"aeroway-runway-casing\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\",\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 12,\n            \"paint\": {\n                \"line-color\": \"rgba(153, 153, 153, 1)\",\n                \"line-opacity\": 1,\n                \"line-width\": {\n                    \"base\": 1.5,\n                    \"stops\": [\n                        [\n                            11,\n                            5\n                        ],\n                        [\n                            17,\n                            55\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"aeroway\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"transit.station.airport\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"Polygon\"\n                ],\n                [\n                    \"in\",\n                    \"class\",\n                    \"runway\",\n                    \"taxiway\"\n                ]\n            ],\n            \"id\": \"aeroway-area\",\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 4,\n            \"paint\": {\n                \"fill-color\": \"rgba(255, 255, 255, 1)\",\n                \"fill-opacity\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            13,\n                            0\n                        ],\n                        [\n                            14,\n                            1\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"aeroway\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"transit.station.airport\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"in\",\n                    \"class\",\n                    \"taxiway\"\n                ],\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ]\n            ],\n            \"id\": \"aeroway-taxiway\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\",\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 4,\n            \"paint\": {\n                \"line-color\": \"rgba(255, 255, 255, 1)\",\n                \"line-opacity\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            11,\n                            0\n                        ],\n                        [\n                            12,\n                            1\n                        ]\n                    ]\n                },\n                \"line-width\": {\n                    \"base\": 1.5,\n                    \"stops\": [\n                        [\n                            11,\n                            1\n                        ],\n                        [\n                            17,\n                            10\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"aeroway\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"in\",\n                    \"class\",\n                    \"runway\"\n                ],\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ]\n            ],\n            \"id\": \"aeroway-runway\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\",\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 4,\n            \"paint\": {\n                \"line-color\": \"rgba(255, 255, 255, 1)\",\n                \"line-opacity\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            11,\n                            0\n                        ],\n                        [\n                            12,\n                            1\n                        ]\n                    ]\n                },\n                \"line-width\": {\n                    \"base\": 1.5,\n                    \"stops\": [\n                        [\n                            11,\n                            4\n                        ],\n                        [\n                            17,\n                            50\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"aeroway\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"transit.station.airport\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"==\",\n                \"$type\",\n                \"Polygon\"\n            ],\n            \"id\": \"highway-area\",\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-antialias\": false,\n                \"fill-color\": \"hsla(0, 0%, 89%, 0.56)\",\n                \"fill-opacity\": 0.9,\n                \"fill-outline-color\": \"#cfcdca\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"!in\",\n                    \"brunnel\",\n                    \"bridge\",\n                    \"tunnel\"\n                ],\n                [\n                    \"==\",\n                    \"class\",\n                    \"motorway_link\"\n                ]\n            ],\n            \"id\": \"highway-motorway-link-casing\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\"\n            },\n            \"minzoom\": 12,\n            \"paint\": {\n                \"line-color\": \"#e9ac77\",\n                \"line-opacity\": 1,\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            12,\n                            1\n                        ],\n                        [\n                            13,\n                            3\n                        ],\n                        [\n                            14,\n                            4\n                        ],\n                        [\n                            20,\n                            15\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"!in\",\n                    \"brunnel\",\n                    \"bridge\",\n                    \"tunnel\"\n                ],\n                [\n                    \"in\",\n                    \"class\",\n                    \"primary_link\",\n                    \"secondary_link\",\n                    \"tertiary_link\",\n                    \"trunk_link\"\n                ]\n            ],\n            \"id\": \"highway-link-casing\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\",\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 13,\n            \"paint\": {\n                \"line-color\": \"#e9ac77\",\n                \"line-opacity\": 1,\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            12,\n                            1\n                        ],\n                        [\n                            13,\n                            3\n                        ],\n                        [\n                            14,\n                            4\n                        ],\n                        [\n                            20,\n                            15\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ],\n                [\n                    \"all\",\n                    [\n                        \"!=\",\n                        \"brunnel\",\n                        \"tunnel\"\n                    ],\n                    [\n                        \"in\",\n                        \"class\",\n                        \"minor\",\n                        \"service\",\n                        \"track\"\n                    ]\n                ]\n            ],\n            \"id\": \"highway-minor-casing\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#cfcdca\",\n                \"line-opacity\": {\n                    \"stops\": [\n                        [\n                            12,\n                            0\n                        ],\n                        [\n                            12.5,\n                            1\n                        ]\n                    ]\n                },\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            12,\n                            0.5\n                        ],\n                        [\n                            13,\n                            1\n                        ],\n                        [\n                            14,\n                            4\n                        ],\n                        [\n                            20,\n                            15\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"!in\",\n                    \"brunnel\",\n                    \"bridge\",\n                    \"tunnel\"\n                ],\n                [\n                    \"in\",\n                    \"class\",\n                    \"secondary\",\n                    \"tertiary\"\n                ]\n            ],\n            \"id\": \"highway-secondary-tertiary-casing\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\",\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"line-color\": \"#e9ac77\",\n                \"line-opacity\": 1,\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            6,\n                            1.5\n                        ],\n                        [\n                            20,\n                            17\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"!in\",\n                    \"brunnel\",\n                    \"bridge\",\n                    \"tunnel\"\n                ],\n                [\n                    \"in\",\n                    \"class\",\n                    \"primary\"\n                ]\n            ],\n            \"id\": \"highway-primary-casing\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\",\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 5,\n            \"paint\": {\n                \"line-color\": \"#e9ac77\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            5,\n                            0.5\n                        ],\n                        [\n                            8,\n                            0.6\n                        ],\n                        [\n                            9,\n                            1.5\n                        ],\n                        [\n                            20,\n                            22\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"!in\",\n                    \"brunnel\",\n                    \"bridge\",\n                    \"tunnel\"\n                ],\n                [\n                    \"in\",\n                    \"class\",\n                    \"trunk\"\n                ]\n            ],\n            \"id\": \"highway-trunk-casing\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\",\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 5,\n            \"paint\": {\n                \"line-color\": \"#e9ac77\",\n                \"line-opacity\": {\n                    \"stops\": [\n                        [\n                            5,\n                            0\n                        ],\n                        [\n                            6,\n                            1\n                        ]\n                    ]\n                },\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            5,\n                            0\n                        ],\n                        [\n                            6,\n                            0.6\n                        ],\n                        [\n                            7,\n                            1.5\n                        ],\n                        [\n                            20,\n                            22\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"!in\",\n                    \"brunnel\",\n                    \"bridge\",\n                    \"tunnel\"\n                ],\n                [\n                    \"==\",\n                    \"class\",\n                    \"motorway\"\n                ]\n            ],\n            \"id\": \"highway-motorway-casing\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\",\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 4,\n            \"paint\": {\n                \"line-color\": \"#e9ac77\",\n                \"line-opacity\": {\n                    \"stops\": [\n                        [\n                            4,\n                            0\n                        ],\n                        [\n                            5,\n                            1\n                        ]\n                    ]\n                },\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            4,\n                            0\n                        ],\n                        [\n                            5,\n                            0.4\n                        ],\n                        [\n                            6,\n                            0.6\n                        ],\n                        [\n                            7,\n                            1.5\n                        ],\n                        [\n                            20,\n                            22\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ],\n                [\n                    \"all\",\n                    [\n                        \"!in\",\n                        \"brunnel\",\n                        \"bridge\",\n                        \"tunnel\"\n                    ],\n                    [\n                        \"in\",\n                        \"class\",\n                        \"path\",\n                        \"footway\"\n                    ]\n                ]\n            ],\n            \"id\": \"highway-path\",\n            \"paint\": {\n                \"line-color\": \"#cba\",\n                \"line-dasharray\": {\n                    \"stops\": [\n                        [\n                            13,\n                            [\n                                1,\n                                0.5\n                            ]\n                        ],\n                        [\n                            14,\n                            [\n                                2,\n                                1\n                            ]\n                        ],\n                        [\n                            20,\n                            [\n                                3,\n                                1\n                            ]\n                        ]\n                    ]\n                },\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            13,\n                            1\n                        ],\n                        [\n                            14,\n                            2\n                        ],\n                        [\n                            20,\n                            4\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"!in\",\n                    \"brunnel\",\n                    \"bridge\",\n                    \"tunnel\"\n                ],\n                [\n                    \"==\",\n                    \"class\",\n                    \"motorway_link\"\n                ]\n            ],\n            \"id\": \"highway-motorway-link\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\"\n            },\n            \"minzoom\": 12,\n            \"paint\": {\n                \"line-color\": \"#e5b87e\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            12.5,\n                            0\n                        ],\n                        [\n                            13,\n                            1.5\n                        ],\n                        [\n                            14,\n                            2.5\n                        ],\n                        [\n                            20,\n                            11.5\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"!in\",\n                    \"brunnel\",\n                    \"bridge\",\n                    \"tunnel\"\n                ],\n                [\n                    \"in\",\n                    \"class\",\n                    \"primary_link\",\n                    \"secondary_link\",\n                    \"tertiary_link\",\n                    \"trunk_link\"\n                ]\n            ],\n            \"id\": \"highway-link\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\",\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 13,\n            \"paint\": {\n                \"line-color\": \"#e5d7a0\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            12.5,\n                            0\n                        ],\n                        [\n                            13,\n                            1.5\n                        ],\n                        [\n                            14,\n                            2.5\n                        ],\n                        [\n                            20,\n                            11.5\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"in\",\n                    \"class\",\n                    \"downhill\",\n                    \"nordic\"\n                ],\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ]\n            ],\n            \"id\": \"ski-slopes-line\",\n            \"minzoom\": 11,\n            \"paint\": {\n                \"line-blur\": 0.5,\n                \"line-color\": \"rgba(75, 122, 195, 1)\",\n                \"line-dasharray\": [\n                    3,\n                    2\n                ],\n                \"line-width\": {\n                    \"stops\": [\n                        [\n                            10,\n                            1\n                        ],\n                        [\n                            13,\n                            1.5\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"piste\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"poi.sports_complex\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ],\n                [\n                    \"all\",\n                    [\n                        \"!=\",\n                        \"brunnel\",\n                        \"tunnel\"\n                    ],\n                    [\n                        \"in\",\n                        \"class\",\n                        \"minor\",\n                        \"service\",\n                        \"track\"\n                    ]\n                ]\n            ],\n            \"id\": \"highway-minor\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#fff\",\n                \"line-opacity\": 1,\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            13.5,\n                            0\n                        ],\n                        [\n                            14,\n                            2.5\n                        ],\n                        [\n                            20,\n                            11.5\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"!in\",\n                    \"brunnel\",\n                    \"bridge\",\n                    \"tunnel\"\n                ],\n                [\n                    \"in\",\n                    \"class\",\n                    \"secondary\",\n                    \"tertiary\"\n                ]\n            ],\n            \"id\": \"highway-secondary-tertiary\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\",\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"line-color\": \"#e5d7a0\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            6.5,\n                            0\n                        ],\n                        [\n                            8,\n                            0.5\n                        ],\n                        [\n                            20,\n                            13\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ],\n                [\n                    \"all\",\n                    [\n                        \"!in\",\n                        \"brunnel\",\n                        \"bridge\",\n                        \"tunnel\"\n                    ],\n                    [\n                        \"in\",\n                        \"class\",\n                        \"primary\"\n                    ]\n                ]\n            ],\n            \"id\": \"highway-primary\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\",\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"line-color\": \"#e5d7a0\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            5,\n                            0.1\n                        ],\n                        [\n                            9,\n                            0.5\n                        ],\n                        [\n                            20,\n                            18\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ],\n                [\n                    \"all\",\n                    [\n                        \"!in\",\n                        \"brunnel\",\n                        \"bridge\",\n                        \"tunnel\"\n                    ],\n                    [\n                        \"in\",\n                        \"class\",\n                        \"trunk\"\n                    ]\n                ]\n            ],\n            \"id\": \"highway-trunk\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\",\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"line-color\": \"#e5d7a0\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            6.5,\n                            0\n                        ],\n                        [\n                            7,\n                            0.5\n                        ],\n                        [\n                            20,\n                            18\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ],\n                [\n                    \"all\",\n                    [\n                        \"!in\",\n                        \"brunnel\",\n                        \"bridge\",\n                        \"tunnel\"\n                    ],\n                    [\n                        \"==\",\n                        \"class\",\n                        \"motorway\"\n                    ]\n                ]\n            ],\n            \"id\": \"highway-motorway\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\",\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 5,\n            \"paint\": {\n                \"line-color\": \"#e5b87e\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            6.5,\n                            0\n                        ],\n                        [\n                            7,\n                            0.5\n                        ],\n                        [\n                            20,\n                            10\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ],\n                [\n                    \"all\",\n                    [\n                        \"==\",\n                        \"class\",\n                        \"transit\"\n                    ],\n                    [\n                        \"!in\",\n                        \"brunnel\",\n                        \"tunnel\"\n                    ]\n                ]\n            ],\n            \"id\": \"railway-transit\",\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"line-color\": \"hsla(0, 0%, 73%, 0.77)\",\n                \"line-width\": {\n                    \"base\": 1.4,\n                    \"stops\": [\n                        [\n                            14,\n                            0.4\n                        ],\n                        [\n                            20,\n                            1\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ],\n                [\n                    \"all\",\n                    [\n                        \"==\",\n                        \"class\",\n                        \"transit\"\n                    ],\n                    [\n                        \"!in\",\n                        \"brunnel\",\n                        \"tunnel\"\n                    ]\n                ]\n            ],\n            \"id\": \"railway-transit-hatching\",\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"line-color\": \"hsla(0, 0%, 73%, 0.68)\",\n                \"line-dasharray\": [\n                    0.2,\n                    8\n                ],\n                \"line-width\": {\n                    \"base\": 1.4,\n                    \"stops\": [\n                        [\n                            14.5,\n                            0\n                        ],\n                        [\n                            15,\n                            2\n                        ],\n                        [\n                            20,\n                            6\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ],\n                [\n                    \"all\",\n                    [\n                        \"==\",\n                        \"class\",\n                        \"rail\"\n                    ],\n                    [\n                        \"has\",\n                        \"service\"\n                    ]\n                ]\n            ],\n            \"id\": \"railway-service\",\n            \"paint\": {\n                \"line-color\": \"hsla(0, 0%, 73%, 0.77)\",\n                \"line-width\": {\n                    \"base\": 1.4,\n                    \"stops\": [\n                        [\n                            14,\n                            0.4\n                        ],\n                        [\n                            20,\n                            1\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ],\n                [\n                    \"all\",\n                    [\n                        \"==\",\n                        \"class\",\n                        \"rail\"\n                    ],\n                    [\n                        \"has\",\n                        \"service\"\n                    ]\n                ]\n            ],\n            \"id\": \"railway-service-hatching\",\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"line-color\": \"hsla(0, 0%, 73%, 0.68)\",\n                \"line-dasharray\": [\n                    0.2,\n                    8\n                ],\n                \"line-width\": {\n                    \"base\": 1.4,\n                    \"stops\": [\n                        [\n                            14.5,\n                            0\n                        ],\n                        [\n                            15,\n                            2\n                        ],\n                        [\n                            20,\n                            6\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ],\n                [\n                    \"all\",\n                    [\n                        \"!has\",\n                        \"service\"\n                    ],\n                    [\n                        \"!in\",\n                        \"brunnel\",\n                        \"bridge\",\n                        \"tunnel\"\n                    ],\n                    [\n                        \"==\",\n                        \"class\",\n                        \"rail\"\n                    ]\n                ]\n            ],\n            \"id\": \"railway\",\n            \"paint\": {\n                \"line-color\": \"#bbb\",\n                \"line-width\": {\n                    \"base\": 1.4,\n                    \"stops\": [\n                        [\n                            14,\n                            0.4\n                        ],\n                        [\n                            15,\n                            0.75\n                        ],\n                        [\n                            20,\n                            2\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ],\n                [\n                    \"all\",\n                    [\n                        \"!has\",\n                        \"service\"\n                    ],\n                    [\n                        \"!in\",\n                        \"brunnel\",\n                        \"bridge\",\n                        \"tunnel\"\n                    ],\n                    [\n                        \"==\",\n                        \"class\",\n                        \"rail\"\n                    ]\n                ]\n            ],\n            \"id\": \"railway-hatching\",\n            \"paint\": {\n                \"line-color\": \"#bbb\",\n                \"line-dasharray\": [\n                    0.2,\n                    8\n                ],\n                \"line-width\": {\n                    \"base\": 1.4,\n                    \"stops\": [\n                        [\n                            14.5,\n                            0\n                        ],\n                        [\n                            15,\n                            3\n                        ],\n                        [\n                            20,\n                            8\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"bridge\"\n                ],\n                [\n                    \"==\",\n                    \"class\",\n                    \"motorway_link\"\n                ]\n            ],\n            \"id\": \"bridge-motorway-link-casing\",\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#e9ac77\",\n                \"line-opacity\": 1,\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            12,\n                            1\n                        ],\n                        [\n                            13,\n                            3\n                        ],\n                        [\n                            14,\n                            4\n                        ],\n                        [\n                            20,\n                            15\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"bridge\"\n                ],\n                [\n                    \"in\",\n                    \"class\",\n                    \"primary_link\",\n                    \"secondary_link\",\n                    \"tertiary_link\",\n                    \"trunk_link\"\n                ]\n            ],\n            \"id\": \"bridge-link-casing\",\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#e9ac77\",\n                \"line-opacity\": 1,\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            12,\n                            1\n                        ],\n                        [\n                            13,\n                            3\n                        ],\n                        [\n                            14,\n                            4\n                        ],\n                        [\n                            20,\n                            15\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"bridge\"\n                ],\n                [\n                    \"in\",\n                    \"class\",\n                    \"secondary\",\n                    \"tertiary\"\n                ]\n            ],\n            \"id\": \"bridge-secondary-tertiary-casing\",\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#e9ac77\",\n                \"line-opacity\": 1,\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            8,\n                            1.5\n                        ],\n                        [\n                            20,\n                            28\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"bridge\"\n                ],\n                [\n                    \"in\",\n                    \"class\",\n                    \"primary\",\n                    \"trunk\"\n                ]\n            ],\n            \"id\": \"bridge-trunk-primary-casing\",\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"hsl(28, 76%, 67%)\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            5,\n                            0.4\n                        ],\n                        [\n                            6,\n                            0.6\n                        ],\n                        [\n                            7,\n                            1.5\n                        ],\n                        [\n                            20,\n                            26\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"bridge\"\n                ],\n                [\n                    \"==\",\n                    \"class\",\n                    \"motorway\"\n                ]\n            ],\n            \"id\": \"bridge-motorway-casing\",\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#e9ac77\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            5,\n                            0.4\n                        ],\n                        [\n                            6,\n                            0.6\n                        ],\n                        [\n                            7,\n                            1.5\n                        ],\n                        [\n                            20,\n                            22\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ],\n                [\n                    \"all\",\n                    [\n                        \"==\",\n                        \"brunnel\",\n                        \"bridge\"\n                    ],\n                    [\n                        \"in\",\n                        \"class\",\n                        \"path\",\n                        \"footway\"\n                    ]\n                ]\n            ],\n            \"id\": \"bridge-path-casing\",\n            \"paint\": {\n                \"line-color\": \"#f8f4f0\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            15,\n                            1.2\n                        ],\n                        [\n                            20,\n                            18\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ],\n                [\n                    \"all\",\n                    [\n                        \"==\",\n                        \"brunnel\",\n                        \"bridge\"\n                    ],\n                    [\n                        \"in\",\n                        \"class\",\n                        \"path\",\n                        \"footway\"\n                    ]\n                ]\n            ],\n            \"id\": \"bridge-path\",\n            \"paint\": {\n                \"line-color\": \"#cba\",\n                \"line-dasharray\": [\n                    1.5,\n                    0.75\n                ],\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            15,\n                            1.2\n                        ],\n                        [\n                            20,\n                            4\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"bridge\"\n                ],\n                [\n                    \"==\",\n                    \"class\",\n                    \"motorway_link\"\n                ]\n            ],\n            \"id\": \"bridge-motorway-link\",\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#e5b87e\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            12.5,\n                            0\n                        ],\n                        [\n                            13,\n                            1.5\n                        ],\n                        [\n                            14,\n                            2.5\n                        ],\n                        [\n                            20,\n                            11.5\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"bridge\"\n                ],\n                [\n                    \"in\",\n                    \"class\",\n                    \"primary_link\",\n                    \"secondary_link\",\n                    \"tertiary_link\",\n                    \"trunk_link\"\n                ]\n            ],\n            \"id\": \"bridge-link\",\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#e5d7a0\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            12.5,\n                            0\n                        ],\n                        [\n                            13,\n                            1.5\n                        ],\n                        [\n                            14,\n                            2.5\n                        ],\n                        [\n                            20,\n                            11.5\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"bridge\"\n                ],\n                [\n                    \"in\",\n                    \"class\",\n                    \"secondary\",\n                    \"tertiary\"\n                ]\n            ],\n            \"id\": \"bridge-secondary-tertiary\",\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#e5d7a0\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            6.5,\n                            0\n                        ],\n                        [\n                            7,\n                            0.5\n                        ],\n                        [\n                            20,\n                            20\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"bridge\"\n                ],\n                [\n                    \"in\",\n                    \"class\",\n                    \"primary\",\n                    \"trunk\"\n                ]\n            ],\n            \"id\": \"bridge-trunk-primary\",\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#e5d7a0\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            6.5,\n                            0\n                        ],\n                        [\n                            7,\n                            0.5\n                        ],\n                        [\n                            20,\n                            18\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"bridge\"\n                ],\n                [\n                    \"==\",\n                    \"class\",\n                    \"motorway\"\n                ]\n            ],\n            \"id\": \"bridge-motorway\",\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#e5b87e\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            6.5,\n                            0\n                        ],\n                        [\n                            7,\n                            0.5\n                        ],\n                        [\n                            20,\n                            18\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"bridge\"\n                ],\n                [\n                    \"==\",\n                    \"class\",\n                    \"rail\"\n                ]\n            ],\n            \"id\": \"bridge-railway\",\n            \"paint\": {\n                \"line-color\": \"#bbb\",\n                \"line-width\": {\n                    \"base\": 1.4,\n                    \"stops\": [\n                        [\n                            14,\n                            0.4\n                        ],\n                        [\n                            15,\n                            0.75\n                        ],\n                        [\n                            20,\n                            2\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"bridge\"\n                ],\n                [\n                    \"==\",\n                    \"class\",\n                    \"rail\"\n                ]\n            ],\n            \"id\": \"bridge-railway-hatching\",\n            \"paint\": {\n                \"line-color\": \"#bbb\",\n                \"line-dasharray\": [\n                    0.2,\n                    8\n                ],\n                \"line-width\": {\n                    \"base\": 1.4,\n                    \"stops\": [\n                        [\n                            14.5,\n                            0\n                        ],\n                        [\n                            15,\n                            3\n                        ],\n                        [\n                            20,\n                            8\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"==\",\n                \"class\",\n                \"cable_car\"\n            ],\n            \"id\": \"cablecar\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 11,\n            \"paint\": {\n                \"line-color\": \"hsl(0, 0%, 70%)\",\n                \"line-width\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            11,\n                            1\n                        ],\n                        [\n                            19,\n                            2.5\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"==\",\n                \"class\",\n                \"cable_car\"\n            ],\n            \"id\": \"cablecar-dash\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 11,\n            \"paint\": {\n                \"line-color\": \"hsl(0, 0%, 70%)\",\n                \"line-dasharray\": [\n                    2,\n                    3\n                ],\n                \"line-width\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            11,\n                            3\n                        ],\n                        [\n                            19,\n                            5.5\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ],\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"!=\",\n                    \"name\",\n                    \"\"\n                ]\n            ],\n            \"id\": \"waterway-name\",\n            \"layout\": {\n                \"symbol-placement\": \"line\",\n                \"symbol-spacing\": 350,\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"name:latin\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"all\",\n                            [\n                                \"has\",\n                                \"name:nonlatin\"\n                            ],\n                            [\n                                \"is-supported-script\",\n                                [\n                                    \"get\",\n                                    \"name:nonlatin\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"concat\",\n                            \" \",\n                            [\n                                \"get\",\n                                \"name:nonlatin\"\n                            ]\n                        ],\n                        \"\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Stadia Italic\"\n                ],\n                \"text-letter-spacing\": 0.2,\n                \"text-max-width\": 5,\n                \"text-pitch-alignment\": \"viewport\",\n                \"text-rotation-alignment\": \"map\",\n                \"text-size\": 14\n            },\n            \"minzoom\": 13,\n            \"paint\": {\n                \"text-color\": \"#115AA7\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"waterway\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"Point\"\n                ],\n                [\n                    \"!in\",\n                    \"class\",\n                    \"ocean\"\n                ]\n            ],\n            \"id\": \"water-name-other\",\n            \"layout\": {\n                \"symbol-placement\": \"point\",\n                \"symbol-spacing\": 150,\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"name:latin\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"all\",\n                            [\n                                \"has\",\n                                \"name:nonlatin\"\n                            ],\n                            [\n                                \"is-supported-script\",\n                                [\n                                    \"get\",\n                                    \"name:nonlatin\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"concat\",\n                            \"\\n\",\n                            [\n                                \"get\",\n                                \"name:nonlatin\"\n                            ]\n                        ],\n                        \"\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Stadia Italic\"\n                ],\n                \"text-letter-spacing\": 0.2,\n                \"text-line-height\": 1.55,\n                \"text-max-width\": 5,\n                \"text-size\": {\n                    \"stops\": [\n                        [\n                            0,\n                            10\n                        ],\n                        [\n                            6,\n                            14\n                        ]\n                    ]\n                },\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 1,\n            \"paint\": {\n                \"text-color\": \"#115AA7\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"water_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"Point\"\n                ],\n                [\n                    \"==\",\n                    \"class\",\n                    \"ocean\"\n                ]\n            ],\n            \"id\": \"water-name-ocean\",\n            \"layout\": {\n                \"symbol-avoid-edges\": true,\n                \"symbol-placement\": \"point\",\n                \"symbol-spacing\": 350,\n                \"text-field\": \"{name:latin}\",\n                \"text-font\": [\n                    \"Stadia Italic\"\n                ],\n                \"text-letter-spacing\": 0.2,\n                \"text-max-width\": 5,\n                \"text-size\": 14\n            },\n            \"paint\": {\n                \"text-color\": \"#115AA7\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"water_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"Point\"\n                ],\n                [\n                    \">=\",\n                    \"rank\",\n                    25\n                ]\n            ],\n            \"id\": \"poi-level-3\",\n            \"layout\": {\n                \"icon-image\": \"{class}_11\",\n                \"symbol-avoid-edges\": true,\n                \"text-anchor\": \"top\",\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"name:latin\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"all\",\n                            [\n                                \"has\",\n                                \"name:nonlatin\"\n                            ],\n                            [\n                                \"is-supported-script\",\n                                [\n                                    \"get\",\n                                    \"name:nonlatin\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"concat\",\n                            \"\\n\",\n                            [\n                                \"get\",\n                                \"name:nonlatin\"\n                            ]\n                        ],\n                        \"\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Stadia Semibold\"\n                ],\n                \"text-line-height\": 1.55,\n                \"text-max-width\": 9,\n                \"text-offset\": [\n                    0,\n                    0.6\n                ],\n                \"text-padding\": 2,\n                \"text-size\": 12\n            },\n            \"minzoom\": 16,\n            \"paint\": {\n                \"text-color\": \"#666\",\n                \"text-halo-blur\": 0.5,\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"poi\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"poi\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"Point\"\n                ],\n                [\n                    \"<=\",\n                    \"rank\",\n                    24\n                ],\n                [\n                    \">=\",\n                    \"rank\",\n                    15\n                ]\n            ],\n            \"id\": \"poi-level-2\",\n            \"layout\": {\n                \"icon-image\": \"{class}_11\",\n                \"symbol-avoid-edges\": true,\n                \"text-anchor\": \"top\",\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"name:latin\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"all\",\n                            [\n                                \"has\",\n                                \"name:nonlatin\"\n                            ],\n                            [\n                                \"is-supported-script\",\n                                [\n                                    \"get\",\n                                    \"name:nonlatin\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"concat\",\n                            \"\\n\",\n                            [\n                                \"get\",\n                                \"name:nonlatin\"\n                            ]\n                        ],\n                        \"\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Stadia Semibold\"\n                ],\n                \"text-line-height\": 1.55,\n                \"text-max-width\": 9,\n                \"text-offset\": [\n                    0,\n                    0.6\n                ],\n                \"text-padding\": 2,\n                \"text-size\": 12\n            },\n            \"minzoom\": 15,\n            \"paint\": {\n                \"text-color\": \"#666\",\n                \"text-halo-blur\": 0.5,\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"poi\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"poi\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"Point\"\n                ],\n                [\n                    \"<=\",\n                    \"rank\",\n                    14\n                ],\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"!=\",\n                    \"name\",\n                    \"\"\n                ]\n            ],\n            \"id\": \"poi-level-1\",\n            \"layout\": {\n                \"icon-image\": \"{class}_11\",\n                \"symbol-avoid-edges\": true,\n                \"text-anchor\": \"top\",\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"name:latin\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"all\",\n                            [\n                                \"has\",\n                                \"name:nonlatin\"\n                            ],\n                            [\n                                \"is-supported-script\",\n                                [\n                                    \"get\",\n                                    \"name:nonlatin\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"concat\",\n                            \"\\n\",\n                            [\n                                \"get\",\n                                \"name:nonlatin\"\n                            ]\n                        ],\n                        \"\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Stadia Semibold\"\n                ],\n                \"text-line-height\": 1.55,\n                \"text-max-width\": 9,\n                \"text-offset\": [\n                    0,\n                    0.6\n                ],\n                \"text-padding\": 2,\n                \"text-size\": 12\n            },\n            \"minzoom\": 14,\n            \"paint\": {\n                \"text-color\": \"#666\",\n                \"text-halo-blur\": 0.5,\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"poi\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"poi\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"Point\"\n                ],\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"!=\",\n                    \"name\",\n                    \"\"\n                ],\n                [\n                    \"==\",\n                    \"class\",\n                    \"railway\"\n                ],\n                [\n                    \"==\",\n                    \"subclass\",\n                    \"station\"\n                ]\n            ],\n            \"id\": \"poi-railway\",\n            \"layout\": {\n                \"icon-allow-overlap\": false,\n                \"icon-ignore-placement\": false,\n                \"icon-image\": \"{class}_11\",\n                \"icon-optional\": false,\n                \"symbol-avoid-edges\": true,\n                \"text-allow-overlap\": false,\n                \"text-anchor\": \"top\",\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"name:latin\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"all\",\n                            [\n                                \"has\",\n                                \"name:nonlatin\"\n                            ],\n                            [\n                                \"is-supported-script\",\n                                [\n                                    \"get\",\n                                    \"name:nonlatin\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"concat\",\n                            \"\\n\",\n                            [\n                                \"get\",\n                                \"name:nonlatin\"\n                            ]\n                        ],\n                        \"\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Stadia Regular\"\n                ],\n                \"text-ignore-placement\": false,\n                \"text-line-height\": 1.55,\n                \"text-max-width\": 9,\n                \"text-offset\": [\n                    0,\n                    0.6\n                ],\n                \"text-optional\": true,\n                \"text-padding\": 2,\n                \"text-size\": 12\n            },\n            \"minzoom\": 13,\n            \"paint\": {\n                \"text-color\": \"#666\",\n                \"text-halo-blur\": 0.5,\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"poi\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"transit.station\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"in\",\n                \"class\",\n                \"path\",\n                \"footway\"\n            ],\n            \"id\": \"highway-name-path\",\n            \"layout\": {\n                \"symbol-placement\": \"line\",\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"name:latin\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"all\",\n                            [\n                                \"has\",\n                                \"name:nonlatin\"\n                            ],\n                            [\n                                \"is-supported-script\",\n                                [\n                                    \"get\",\n                                    \"name:nonlatin\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"concat\",\n                            \" \",\n                            [\n                                \"get\",\n                                \"name:nonlatin\"\n                            ]\n                        ],\n                        \"\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Stadia Regular\"\n                ],\n                \"text-pitch-alignment\": \"viewport\",\n                \"text-rotation-alignment\": \"map\",\n                \"text-size\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            13,\n                            12\n                        ],\n                        [\n                            14,\n                            13\n                        ]\n                    ]\n                }\n            },\n            \"minzoom\": 15.5,\n            \"paint\": {\n                \"text-color\": \"hsl(30, 23%, 62%)\",\n                \"text-halo-color\": \"#f8f4f0\",\n                \"text-halo-width\": 0.5\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"id\": \"ski-slopes-label\",\n            \"layout\": {\n                \"icon-pitch-alignment\": \"auto\",\n                \"symbol-placement\": \"line-center\",\n                \"text-anchor\": \"bottom\",\n                \"text-field\": \"{name}\",\n                \"text-font\": [\n                    \"Stadia Regular\"\n                ],\n                \"text-keep-upright\": true,\n                \"text-size\": 12\n            },\n            \"minzoom\": 13,\n            \"paint\": {\n                \"text-color\": \"rgba(75, 122, 195, 1)\",\n                \"text-halo-blur\": 0.5,\n                \"text-halo-color\": \"rgba(255, 255, 255, 1)\",\n                \"text-halo-width\": 1\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"piste\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"poi.sports_complex\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ],\n                [\n                    \"in\",\n                    \"class\",\n                    \"minor\",\n                    \"service\",\n                    \"track\"\n                ]\n            ],\n            \"id\": \"highway-name-minor\",\n            \"layout\": {\n                \"symbol-placement\": \"line\",\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"name:latin\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"all\",\n                            [\n                                \"has\",\n                                \"name:nonlatin\"\n                            ],\n                            [\n                                \"is-supported-script\",\n                                [\n                                    \"get\",\n                                    \"name:nonlatin\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"concat\",\n                            \" \",\n                            [\n                                \"get\",\n                                \"name:nonlatin\"\n                            ]\n                        ],\n                        \"\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Stadia Regular\"\n                ],\n                \"text-pitch-alignment\": \"viewport\",\n                \"text-rotation-alignment\": \"map\",\n                \"text-size\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            13,\n                            12\n                        ],\n                        [\n                            14,\n                            13\n                        ]\n                    ]\n                }\n            },\n            \"minzoom\": 15,\n            \"paint\": {\n                \"text-color\": \"#765\",\n                \"text-halo-blur\": 0.5,\n                \"text-halo-width\": 1\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"in\",\n                \"class\",\n                \"primary\",\n                \"secondary\",\n                \"tertiary\",\n                \"trunk\"\n            ],\n            \"id\": \"highway-name-major\",\n            \"layout\": {\n                \"symbol-placement\": \"line\",\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"name:latin\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"all\",\n                            [\n                                \"has\",\n                                \"name:nonlatin\"\n                            ],\n                            [\n                                \"is-supported-script\",\n                                [\n                                    \"get\",\n                                    \"name:nonlatin\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"concat\",\n                            \" \",\n                            [\n                                \"get\",\n                                \"name:nonlatin\"\n                            ]\n                        ],\n                        \"\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Stadia Regular\"\n                ],\n                \"text-pitch-alignment\": \"viewport\",\n                \"text-rotation-alignment\": \"map\",\n                \"text-size\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            13,\n                            12\n                        ],\n                        [\n                            14,\n                            13\n                        ]\n                    ]\n                }\n            },\n            \"minzoom\": 12.2,\n            \"paint\": {\n                \"text-color\": \"#765\",\n                \"text-halo-blur\": 0.5,\n                \"text-halo-width\": 1\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    \"ref_length\",\n                    6\n                ],\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ],\n                [\n                    \"!in\",\n                    \"network\",\n                    \"us-interstate\",\n                    \"us-highway\",\n                    \"us-state\"\n                ]\n            ],\n            \"id\": \"highway-shield-other\",\n            \"layout\": {\n                \"icon-image\": \"road_{ref_length}\",\n                \"icon-rotation-alignment\": \"viewport\",\n                \"icon-size\": 1,\n                \"symbol-avoid-edges\": true,\n                \"symbol-placement\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            10,\n                            \"point\"\n                        ],\n                        [\n                            11,\n                            \"line\"\n                        ]\n                    ]\n                },\n                \"text-field\": \"{ref}\",\n                \"text-font\": [\n                    \"Stadia Semibold\"\n                ],\n                \"text-rotation-alignment\": \"viewport\",\n                \"text-size\": 10\n            },\n            \"minzoom\": 8,\n            \"paint\": {},\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"labels.icon\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    \"ref_length\",\n                    6\n                ],\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ],\n                [\n                    \"in\",\n                    \"network\",\n                    \"us-interstate\"\n                ]\n            ],\n            \"id\": \"highway-shield-us-interstate\",\n            \"layout\": {\n                \"icon-image\": \"{network}_{ref_length}\",\n                \"icon-rotation-alignment\": \"viewport\",\n                \"icon-size\": 1,\n                \"symbol-avoid-edges\": true,\n                \"symbol-placement\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            7,\n                            \"point\"\n                        ],\n                        [\n                            7,\n                            \"line\"\n                        ],\n                        [\n                            8,\n                            \"line\"\n                        ]\n                    ]\n                },\n                \"text-field\": \"{ref}\",\n                \"text-font\": [\n                    \"Stadia Semibold\"\n                ],\n                \"text-rotation-alignment\": \"viewport\",\n                \"text-size\": 10\n            },\n            \"minzoom\": 7,\n            \"paint\": {\n                \"text-color\": \"rgba(0, 0, 0, 1)\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"labels.icon\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    \"ref_length\",\n                    6\n                ],\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ],\n                [\n                    \"in\",\n                    \"network\",\n                    \"us-highway\",\n                    \"us-state\"\n                ]\n            ],\n            \"id\": \"highway-shield-us-other\",\n            \"layout\": {\n                \"icon-image\": \"{network}_{ref_length}\",\n                \"icon-rotation-alignment\": \"viewport\",\n                \"icon-size\": 1,\n                \"symbol-avoid-edges\": true,\n                \"symbol-placement\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            10,\n                            \"point\"\n                        ],\n                        [\n                            11,\n                            \"line\"\n                        ]\n                    ]\n                },\n                \"text-field\": \"{ref}\",\n                \"text-font\": [\n                    \"Stadia Semibold\"\n                ],\n                \"text-rotation-alignment\": \"viewport\",\n                \"text-size\": 10\n            },\n            \"minzoom\": 9,\n            \"paint\": {\n                \"text-color\": \"rgba(0, 0, 0, 1)\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"labels.icon\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"iata\"\n                ]\n            ],\n            \"id\": \"airport-label-major\",\n            \"layout\": {\n                \"icon-image\": \"airport_11\",\n                \"icon-size\": 1,\n                \"text-anchor\": \"top\",\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"name:latin\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"all\",\n                            [\n                                \"has\",\n                                \"name:nonlatin\"\n                            ],\n                            [\n                                \"is-supported-script\",\n                                [\n                                    \"get\",\n                                    \"name:nonlatin\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"concat\",\n                            \"\\n\",\n                            [\n                                \"get\",\n                                \"name:nonlatin\"\n                            ]\n                        ],\n                        \"\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Stadia Regular\"\n                ],\n                \"text-line-height\": 1.55,\n                \"text-max-width\": 9,\n                \"text-offset\": [\n                    0,\n                    0.6\n                ],\n                \"text-optional\": true,\n                \"text-padding\": 2,\n                \"text-size\": 12,\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 10,\n            \"paint\": {\n                \"text-color\": \"#666\",\n                \"text-halo-blur\": 0.5,\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"aerodrome_label\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"transit.station.airport\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"!in\",\n                \"class\",\n                \"city\",\n                \"town\",\n                \"village\",\n                \"country\",\n                \"continent\"\n            ],\n            \"id\": \"place-other\",\n            \"layout\": {\n                \"symbol-avoid-edges\": true,\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"name:latin\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"all\",\n                            [\n                                \"has\",\n                                \"name:nonlatin\"\n                            ],\n                            [\n                                \"is-supported-script\",\n                                [\n                                    \"get\",\n                                    \"name:nonlatin\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"concat\",\n                            \"\\n\",\n                            [\n                                \"get\",\n                                \"name:nonlatin\"\n                            ]\n                        ],\n                        \"\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Stadia Semibold\"\n                ],\n                \"text-letter-spacing\": 0.1,\n                \"text-line-height\": 1.55,\n                \"text-max-width\": 9,\n                \"text-size\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            12,\n                            10\n                        ],\n                        [\n                            15,\n                            14\n                        ]\n                    ]\n                },\n                \"text-transform\": \"uppercase\",\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 12,\n            \"paint\": {\n                \"text-color\": \"#633\",\n                \"text-halo-color\": \"rgba(255,255,255,0.8)\",\n                \"text-halo-width\": 1.2\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"administrative.neighborhood\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"==\",\n                \"class\",\n                \"village\"\n            ],\n            \"id\": \"place-village\",\n            \"layout\": {\n                \"symbol-avoid-edges\": true,\n                \"symbol-spacing\": 350,\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"name:latin\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"all\",\n                            [\n                                \"has\",\n                                \"name:nonlatin\"\n                            ],\n                            [\n                                \"is-supported-script\",\n                                [\n                                    \"get\",\n                                    \"name:nonlatin\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"concat\",\n                            \"\\n\",\n                            [\n                                \"get\",\n                                \"name:nonlatin\"\n                            ]\n                        ],\n                        \"\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Stadia Regular\"\n                ],\n                \"text-line-height\": 1.55,\n                \"text-max-width\": 8,\n                \"text-size\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            10,\n                            12\n                        ],\n                        [\n                            15,\n                            22\n                        ]\n                    ]\n                },\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 11,\n            \"paint\": {\n                \"text-color\": \"#333\",\n                \"text-halo-color\": \"rgba(255,255,255,0.8)\",\n                \"text-halo-width\": 1.2\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"administrative.neighborhood\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"Point\"\n                ],\n                [\n                    \"<=\",\n                    \"rank\",\n                    2\n                ],\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"!=\",\n                    \"name\",\n                    \"\"\n                ]\n            ],\n            \"id\": \"mountain-peaks\",\n            \"layout\": {\n                \"icon-image\": \"mountain_11\",\n                \"symbol-avoid-edges\": true,\n                \"text-anchor\": \"top\",\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"name:latin\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"all\",\n                            [\n                                \"has\",\n                                \"name:nonlatin\"\n                            ],\n                            [\n                                \"is-supported-script\",\n                                [\n                                    \"get\",\n                                    \"name:nonlatin\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"concat\",\n                            \"\\n\",\n                            [\n                                \"get\",\n                                \"name:nonlatin\"\n                            ]\n                        ],\n                        \"\"\n                    ],\n                    \"\\n\",\n                    [\n                        \"to-string\",\n                        [\n                            \"get\",\n                            \"ele\"\n                        ]\n                    ],\n                    \" m\"\n                ],\n                \"text-font\": [\n                    \"Stadia Regular\"\n                ],\n                \"text-line-height\": 1.55,\n                \"text-max-width\": 9,\n                \"text-offset\": [\n                    0,\n                    0.6\n                ],\n                \"text-padding\": 2,\n                \"text-size\": 12\n            },\n            \"minzoom\": 9,\n            \"paint\": {\n                \"text-color\": \"#666\",\n                \"text-halo-blur\": 0.5,\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"mountain_peak\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"Point\"\n                ],\n                [\n                    \">=\",\n                    \"ele\",\n                    2500\n                ],\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"!=\",\n                    \"name\",\n                    \"\"\n                ],\n                [\n                    \"<=\",\n                    \"rank\",\n                    1\n                ]\n            ],\n            \"id\": \"mountain-peaks-important\",\n            \"layout\": {\n                \"icon-image\": \"mountain_11\",\n                \"symbol-avoid-edges\": true,\n                \"text-anchor\": \"top\",\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"name:latin\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"all\",\n                            [\n                                \"has\",\n                                \"name:nonlatin\"\n                            ],\n                            [\n                                \"is-supported-script\",\n                                [\n                                    \"get\",\n                                    \"name:nonlatin\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"concat\",\n                            \"\\n\",\n                            [\n                                \"get\",\n                                \"name:nonlatin\"\n                            ]\n                        ],\n                        \"\"\n                    ],\n                    \"\\n\",\n                    [\n                        \"to-string\",\n                        [\n                            \"get\",\n                            \"ele\"\n                        ]\n                    ],\n                    \" m\"\n                ],\n                \"text-font\": [\n                    \"Stadia Semibold\"\n                ],\n                \"text-line-height\": 1.55,\n                \"text-max-width\": 9,\n                \"text-offset\": [\n                    0,\n                    0.6\n                ],\n                \"text-padding\": 2,\n                \"text-size\": 12\n            },\n            \"maxzoom\": 9,\n            \"minzoom\": 7,\n            \"paint\": {\n                \"text-color\": \"#666\",\n                \"text-halo-blur\": 0.5,\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"mountain_peak\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"==\",\n                \"class\",\n                \"town\"\n            ],\n            \"id\": \"place-town\",\n            \"layout\": {\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"name:latin\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"all\",\n                            [\n                                \"has\",\n                                \"name:nonlatin\"\n                            ],\n                            [\n                                \"is-supported-script\",\n                                [\n                                    \"get\",\n                                    \"name:nonlatin\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"concat\",\n                            \"\\n\",\n                            [\n                                \"get\",\n                                \"name:nonlatin\"\n                            ]\n                        ],\n                        \"\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Stadia Regular\"\n                ],\n                \"text-line-height\": 1.55,\n                \"text-max-width\": 8,\n                \"text-size\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            10,\n                            14\n                        ],\n                        [\n                            15,\n                            22\n                        ]\n                    ]\n                },\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"text-color\": \"#333\",\n                \"text-halo-color\": \"rgba(255,255,255,0.8)\",\n                \"text-halo-width\": 1.2\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"nature_reserve\",\n                        \"protected_area\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"Point\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    1\n                ],\n                [\n                    \"!\",\n                    [\n                        \"any\",\n                        [\n                            \"in\",\n                            \"Open Access Land\",\n                            [\n                                \"get\",\n                                \"name\"\n                            ]\n                        ],\n                        [\n                            \"in\",\n                            \"State Game Land\",\n                            [\n                                \"get\",\n                                \"name\"\n                            ]\n                        ]\n                    ]\n                ]\n            ],\n            \"id\": \"park-reserve\",\n            \"layout\": {\n                \"symbol-avoid-edges\": true,\n                \"symbol-placement\": \"point\",\n                \"text-anchor\": \"center\",\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"name:latin\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"all\",\n                            [\n                                \"has\",\n                                \"name:nonlatin\"\n                            ],\n                            [\n                                \"is-supported-script\",\n                                [\n                                    \"get\",\n                                    \"name:nonlatin\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"concat\",\n                            \"\\n\",\n                            [\n                                \"get\",\n                                \"name:nonlatin\"\n                            ]\n                        ],\n                        \"\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Stadia Italic\"\n                ],\n                \"text-justify\": \"center\",\n                \"text-line-height\": 1.55,\n                \"text-max-width\": 10,\n                \"text-padding\": 2,\n                \"text-size\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            8,\n                            12\n                        ],\n                        [\n                            13,\n                            14\n                        ]\n                    ]\n                },\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 8,\n            \"paint\": {\n                \"text-color\": \"rgba(102, 51, 1, 1)\",\n                \"text-halo-color\": \"rgba(255,255,255,0.8)\",\n                \"text-halo-width\": 1\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"park\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"poi.park\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"class\",\n                    \"national_park\"\n                ],\n                [\n                    \"==\",\n                    \"$type\",\n                    \"Point\"\n                ],\n                [\n                    \"==\",\n                    \"rank\",\n                    1\n                ]\n            ],\n            \"id\": \"park-national\",\n            \"layout\": {\n                \"symbol-avoid-edges\": true,\n                \"symbol-placement\": \"point\",\n                \"text-anchor\": \"center\",\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"name:latin\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"all\",\n                            [\n                                \"has\",\n                                \"name:nonlatin\"\n                            ],\n                            [\n                                \"is-supported-script\",\n                                [\n                                    \"get\",\n                                    \"name:nonlatin\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"concat\",\n                            \"\\n\",\n                            [\n                                \"get\",\n                                \"name:nonlatin\"\n                            ]\n                        ],\n                        \"\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Stadia Italic\"\n                ],\n                \"text-justify\": \"center\",\n                \"text-line-height\": 1.55,\n                \"text-max-width\": 10,\n                \"text-padding\": 2,\n                \"text-size\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            6,\n                            12\n                        ],\n                        [\n                            8,\n                            14\n                        ],\n                        [\n                            12,\n                            16\n                        ]\n                    ]\n                },\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 6,\n            \"paint\": {\n                \"text-color\": \"rgba(102, 51, 1, 1)\",\n                \"text-halo-color\": \"rgba(255,255,255,0.8)\",\n                \"text-halo-width\": 1\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"park\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"poi.park\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"==\",\n                \"$type\",\n                \"LineString\"\n            ],\n            \"id\": \"water-name-lakeline\",\n            \"layout\": {\n                \"symbol-placement\": \"line\",\n                \"symbol-spacing\": 250,\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"name:latin\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"all\",\n                            [\n                                \"has\",\n                                \"name:nonlatin\"\n                            ],\n                            [\n                                \"is-supported-script\",\n                                [\n                                    \"get\",\n                                    \"name:nonlatin\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"concat\",\n                            \" \",\n                            [\n                                \"get\",\n                                \"name:nonlatin\"\n                            ]\n                        ],\n                        \"\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Stadia Italic\"\n                ],\n                \"text-letter-spacing\": 0.2,\n                \"text-line-height\": 1.55,\n                \"text-max-width\": 5,\n                \"text-pitch-alignment\": \"viewport\",\n                \"text-rotation-alignment\": \"map\",\n                \"text-size\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            0,\n                            10\n                        ],\n                        [\n                            14,\n                            14\n                        ]\n                    ]\n                }\n            },\n            \"paint\": {\n                \"text-color\": \"#115AA7\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"water_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"!=\",\n                    \"capital\",\n                    2\n                ],\n                [\n                    \"==\",\n                    \"class\",\n                    \"city\"\n                ]\n            ],\n            \"id\": \"place-city\",\n            \"layout\": {\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"name:latin\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"all\",\n                            [\n                                \"has\",\n                                \"name:nonlatin\"\n                            ],\n                            [\n                                \"is-supported-script\",\n                                [\n                                    \"get\",\n                                    \"name:nonlatin\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"concat\",\n                            \"\\n\",\n                            [\n                                \"get\",\n                                \"name:nonlatin\"\n                            ]\n                        ],\n                        \"\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Stadia Semibold\"\n                ],\n                \"text-line-height\": 1.55,\n                \"text-max-width\": 8,\n                \"text-size\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            7,\n                            14\n                        ],\n                        [\n                            11,\n                            24\n                        ]\n                    ]\n                },\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"text-color\": \"#333\",\n                \"text-halo-color\": \"rgba(255,255,255,0.8)\",\n                \"text-halo-width\": 1.2\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"capital\",\n                    2\n                ],\n                [\n                    \"==\",\n                    \"class\",\n                    \"city\"\n                ]\n            ],\n            \"id\": \"place-city-capital\",\n            \"layout\": {\n                \"icon-image\": \"star_11\",\n                \"icon-size\": 0.8,\n                \"text-anchor\": \"left\",\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"name:latin\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"all\",\n                            [\n                                \"has\",\n                                \"name:nonlatin\"\n                            ],\n                            [\n                                \"is-supported-script\",\n                                [\n                                    \"get\",\n                                    \"name:nonlatin\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"concat\",\n                            \"\\n\",\n                            [\n                                \"get\",\n                                \"name:nonlatin\"\n                            ]\n                        ],\n                        \"\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Stadia Semibold\"\n                ],\n                \"text-line-height\": 1.55,\n                \"text-max-width\": 8,\n                \"text-offset\": [\n                    0.4,\n                    0\n                ],\n                \"text-size\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            7,\n                            14\n                        ],\n                        [\n                            11,\n                            24\n                        ]\n                    ]\n                },\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"text-color\": \"#333\",\n                \"text-halo-color\": \"rgba(255,255,255,0.8)\",\n                \"text-halo-width\": 1.2\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"class\",\n                    \"country\"\n                ],\n                [\n                    \">=\",\n                    \"rank\",\n                    3\n                ],\n                [\n                    \"!has\",\n                    \"iso_a2\"\n                ]\n            ],\n            \"id\": \"place-country-other\",\n            \"layout\": {\n                \"symbol-avoid-edges\": true,\n                \"text-field\": \"{name:latin}\",\n                \"text-font\": [\n                    \"Stadia Italic\"\n                ],\n                \"text-max-width\": 6.25,\n                \"text-size\": {\n                    \"stops\": [\n                        [\n                            3,\n                            11\n                        ],\n                        [\n                            7,\n                            17\n                        ]\n                    ]\n                },\n                \"text-transform\": \"uppercase\",\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 1,\n            \"paint\": {\n                \"text-color\": \"#334\",\n                \"text-halo-blur\": 1,\n                \"text-halo-color\": \"rgba(255,255,255,0.8)\",\n                \"text-halo-width\": 2\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"administrative.province\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"class\",\n                    \"country\"\n                ],\n                [\n                    \">=\",\n                    \"rank\",\n                    3\n                ],\n                [\n                    \"has\",\n                    \"iso_a2\"\n                ]\n            ],\n            \"id\": \"place-country-3\",\n            \"layout\": {\n                \"text-field\": \"{name:latin}\",\n                \"text-font\": [\n                    \"Stadia Bold\"\n                ],\n                \"text-max-width\": 6.25,\n                \"text-size\": {\n                    \"stops\": [\n                        [\n                            3,\n                            11\n                        ],\n                        [\n                            7,\n                            17\n                        ]\n                    ]\n                },\n                \"text-transform\": \"uppercase\",\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 1,\n            \"paint\": {\n                \"text-color\": \"#334\",\n                \"text-halo-blur\": 1,\n                \"text-halo-color\": \"rgba(255,255,255,0.8)\",\n                \"text-halo-width\": 2\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"administrative.province\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"class\",\n                    \"country\"\n                ],\n                [\n                    \"==\",\n                    \"rank\",\n                    2\n                ],\n                [\n                    \"has\",\n                    \"iso_a2\"\n                ]\n            ],\n            \"id\": \"place-country-2\",\n            \"layout\": {\n                \"text-field\": \"{name:latin}\",\n                \"text-font\": [\n                    \"Stadia Bold\"\n                ],\n                \"text-max-width\": 6.25,\n                \"text-size\": {\n                    \"stops\": [\n                        [\n                            2,\n                            11\n                        ],\n                        [\n                            5,\n                            17\n                        ]\n                    ]\n                },\n                \"text-transform\": \"uppercase\",\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 1,\n            \"paint\": {\n                \"text-color\": \"#334\",\n                \"text-halo-blur\": 1,\n                \"text-halo-color\": \"rgba(255,255,255,0.8)\",\n                \"text-halo-width\": 2\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"administrative.province\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"class\",\n                    \"country\"\n                ],\n                [\n                    \"==\",\n                    \"rank\",\n                    1\n                ],\n                [\n                    \"has\",\n                    \"iso_a2\"\n                ]\n            ],\n            \"id\": \"place-country-1\",\n            \"layout\": {\n                \"text-field\": \"{name:latin}\",\n                \"text-font\": [\n                    \"Stadia Bold\"\n                ],\n                \"text-max-width\": 6.25,\n                \"text-size\": {\n                    \"stops\": [\n                        [\n                            1,\n                            11\n                        ],\n                        [\n                            4,\n                            17\n                        ]\n                    ]\n                },\n                \"text-transform\": \"uppercase\",\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 1,\n            \"paint\": {\n                \"text-color\": \"#334\",\n                \"text-halo-blur\": 1,\n                \"text-halo-color\": \"rgba(255,255,255,0.8)\",\n                \"text-halo-width\": 2\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"administrative.country\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"==\",\n                \"class\",\n                \"continent\"\n            ],\n            \"id\": \"place-continent\",\n            \"layout\": {\n                \"text-field\": \"{name:latin}\",\n                \"text-font\": [\n                    \"Stadia Bold\"\n                ],\n                \"text-max-width\": 6.25,\n                \"text-size\": 14,\n                \"text-transform\": \"uppercase\",\n                \"visibility\": \"visible\"\n            },\n            \"maxzoom\": 1,\n            \"paint\": {\n                \"text-color\": \"#334\",\n                \"text-halo-blur\": 1,\n                \"text-halo-color\": \"rgba(255,255,255,0.8)\",\n                \"text-halo-width\": 2\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"administrative.land_parcel\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        }\n    ],\n    \"metadata\": {\n        \"mapbox:autocomposite\": false,\n        \"openmaptiles:version\": \"3.x\"\n    },\n    \"name\": \"Outdoors\",\n    \"pitch\": 0,\n    \"sources\": {\n        \"openmaptiles\": {\n            \"type\": \"vector\",\n            \"url\": \"https://tiles.stadiamaps.com/data/openmaptiles.json\"\n        }\n    },\n    \"sprite\": \"https://tiles.stadiamaps.com/styles/outdoors/sprite\",\n    \"version\": 8,\n    \"zoom\": 11.6\n}\n"
  },
  {
    "path": "build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2013 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\nbuildscript {\n    ext.cronetVersion = '102.5005.125'\n    ext.wearableVersion = '0.1.1'\n\n    ext.kotlinVersion = '1.9.22'\n    ext.coroutineVersion = '1.7.3'\n\n    ext.annotationVersion = '1.7.1'\n    ext.appcompatVersion = '1.6.1'\n    ext.biometricVersion = '1.1.0'\n    ext.coreVersion = '1.12.0'\n    ext.fragmentVersion = '1.6.2'\n    ext.lifecycleVersion = '2.7.0'\n    ext.loaderVersion = '1.1.0'\n    ext.materialVersion = '1.11.0'\n    ext.mediarouterVersion = '1.6.0'\n    ext.multidexVersion = '2.0.1'\n    ext.navigationVersion = '2.7.7'\n    ext.preferenceVersion = '1.2.0'\n    ext.recyclerviewVersion = '1.3.2'\n    ext.webkitVersion = '1.10.0'\n    ext.workVersion = '2.7.0'\n\n    ext.slf4jVersion = '1.7.36'\n    ext.volleyVersion = '1.2.1'\n    ext.okHttpVersion = '4.12.0'\n    ext.ktorVersion = '2.3.12'\n    ext.wireVersion = '4.9.9'\n    ext.tinkVersion = '1.13.0'\n\n    ext.androidBuildGradleVersion = '8.2.2'\n\n    ext.androidBuildVersionTools = '34.0.0'\n\n    ext.androidMinSdk = 19\n    ext.androidTargetSdk = 29\n    ext.androidCompileSdk = 35\n\n    ext.localProperties = new Properties()\n\n    try {\n        var stream = rootProject.file('local.properties').newDataInputStream()\n        ext.localProperties.load(stream)\n        stream.close()\n    } catch (ignored) {\n        // Ignore\n    }\n\n    ext.hasModule = (String name, boolean enabledByDefault) -> {\n        return ext.localProperties.getProperty(\"modules.\" + name, enabledByDefault.toString()).toBoolean()\n    }\n\n    repositories {\n        mavenCentral()\n        google()\n    }\n\n    dependencies {\n        classpath \"com.android.tools.build:gradle:$androidBuildGradleVersion\"\n        classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion\"\n        classpath \"com.squareup.wire:wire-gradle-plugin:$wireVersion\"\n    }\n}\n\ndef execResult(... args) {\n    providers.exec { commandLine args }.standardOutput.asText.get()\n}\n\ndef ignoreGit = providers.environmentVariable('GRADLE_MICROG_VERSION_WITHOUT_GIT').getOrElse('0') == '1'\ndef gmsVersion = \"25.09.32\"\ndef gmsVersionCode = Integer.parseInt(gmsVersion.replaceAll('\\\\.', ''))\ndef vendingVersion = \"40.2.26\"\ndef vendingVersionCode = Integer.parseInt(vendingVersion.replaceAll('\\\\.', ''))\ndef gitVersionBase = !ignoreGit ? execResult('git', 'describe', '--tags', '--abbrev=0', '--match=v[0-9]*').trim().substring(1) : \"v0.0.0.$gmsVersionCode\"\ndef gitCommitCount = !ignoreGit ? Integer.parseInt(execResult('git', 'rev-list', '--count', \"v$gitVersionBase..HEAD\").trim()) : 0\ndef gitCommitId = !ignoreGit ? execResult('git', 'show-ref', '--abbrev=7', '--head', 'HEAD').trim().split(' ')[0] : '0000000'\ndef gitDirty = false\nif (!ignoreGit) {\n  execResult('git', 'status', '--porcelain').lines().each { stat ->\n    def status = stat.substring(0,2)\n    def file = stat.substring(3)\n    if (status == '??') {\n      if (subprojects.any { p -> file.startsWith(p.name + '/') }) {\n        logger.lifecycle('Dirty file: {} (untracked)', file)\n        gitDirty = true\n      } else {\n        logger.info('New file outside module: {} (ignored for dirty check)', file)\n      }\n    } else {\n      logger.lifecycle('Dirty file: {} (changed)', file)\n      gitDirty = true\n    }\n  }\n}\ndef ourVersionBase = gitVersionBase.substring(0, gitVersionBase.lastIndexOf('.'))\ndef ourVersionMinor = Integer.parseInt(ourVersionBase.substring(ourVersionBase.lastIndexOf('.') + 1))\ndef ourGmsVersionCode = gmsVersionCode * 1000 + ourVersionMinor * 2  + (gitCommitCount > 0 || gitDirty ? 1 : 0)\ndef ourGmsVersionName = \"$ourVersionBase.$gmsVersionCode\" + (gitCommitCount > 0 && !gitDirty ? \"-$gitCommitCount\" : \"\") + (gitDirty ? \"-dirty\" : \"\") + (gitCommitCount > 0 && !gitDirty ? \" ($gitCommitId)\" : \"\")\ndef ourVendingVersionCode = 80000000 + vendingVersionCode * 100 + ourVersionMinor * 2  + (gitCommitCount > 0 || gitDirty ? 1 : 0)\ndef ourVendingVersionName = \"$ourVersionBase.$vendingVersionCode\" + (gitCommitCount > 0 && !gitDirty ? \"-$gitCommitCount\" : \"\") + (gitDirty ? \"-dirty\" : \"\") + (gitCommitCount > 0 && !gitDirty ? \" ($gitCommitId)\" : \"\")\nlogger.lifecycle('Starting build for GMS version {} ({})...', ourGmsVersionName, ourGmsVersionCode)\n\nallprojects {\n    apply plugin: 'idea'\n\n    group = 'org.microg.gms'\n    version = ourGmsVersionName\n    ext.vendingAppVersionName = ourVendingVersionName\n    ext.vendingAppVersionCode = ourVendingVersionCode\n    ext.appVersionCode = ourGmsVersionCode\n    ext.isReleaseVersion = false\n}\n\nsubprojects {\n    repositories {\n        mavenCentral()\n        google()\n        if (hasModule(\"hms\", false)) maven {url 'https://developer.huawei.com/repo/'}\n    }\n}\n\n"
  },
  {
    "path": "fake-signature/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\n\nandroid {\n    namespace 'org.microg.signature.fake'\n    compileSdk androidCompileSdk\n\n    defaultConfig {\n        minSdk androidMinSdk\n        targetSdk androidTargetSdk\n    }\n\n    flavorDimensions = ['target']\n    productFlavors {\n        \"default\" {\n            dimension 'target'\n        }\n        \"huawei\" {\n            dimension 'target'\n        }\n    }\n\n    buildFeatures {\n        aidl = true\n    }\n\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n}\n\ndependencies {\n}"
  },
  {
    "path": "fake-signature/src/huawei/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <uses-permission android:name=\"android.permission.RECEIVE_BOOT_COMPLETED\" />\n\n    <application>\n        <receiver\n            android:name=\"com.huawei.signature.diff.InitReceiver\"\n            android:enabled=\"true\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.BOOT_COMPLETED\" />\n                <action android:name=\"android.intent.action.MY_PACKAGE_REPLACED\" />\n                <action android:name=\"android.intent.action.PACKAGE_RESTARTED\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </receiver>\n\n        <provider\n            android:name=\"com.huawei.signature.diff.InitProvider\"\n            android:authorities=\"${applicationId}.signature.diff.init\"\n            android:enabled=\"true\"\n            android:exported=\"false\"\n            android:initOrder=\"1000\" />\n\n        <service\n            android:name=\"com.huawei.signature.diff.SignatureService\"\n            android:process=\":signature\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.huawei.signature.diff\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </service>\n    </application>\n\n</manifest>"
  },
  {
    "path": "fake-signature/src/huawei/aidl/com/huawei/signature/diff/ISignatureService.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.huawei.signature.diff;\n\n/**\n * Interface for Huawei Differentiated Signature Capability\n * See https://forums.developer.huawei.com/forumPortal/en/topic/0202128603315033024\n */\ninterface ISignatureService {\n    String[] querySignature(String packageName, boolean suggested);\n}"
  },
  {
    "path": "fake-signature/src/huawei/java/com/huawei/signature/diff/AppListDatabaseOpenHelper.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.huawei.signature.diff;\n\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.database.sqlite.SQLiteDatabase;\nimport android.database.sqlite.SQLiteOpenHelper;\nimport android.util.Log;\nimport org.microg.signature.fake.R;\n\npublic class AppListDatabaseOpenHelper extends SQLiteOpenHelper {\n    private static final String TAG = AppListDatabaseOpenHelper.class.getSimpleName();\n    private static final String DATABASE_NAME = \"app_list.db\";\n    public static final String TABLE_APPLIST = \"applist\";\n    public static final String COLUMN_NAME = \"name\";\n    public static final String COLUMN_FAKE = \"fake\";\n    private static final int DATABASE_VERSION = 3;\n    private static final String DROP_APP_LIST_TABLE = \"DROP TABLE IF EXISTS \" + TABLE_APPLIST;\n    private static final String CREATE_APP_LIST_TABLE = \"CREATE TABLE IF NOT EXISTS \" + TABLE_APPLIST + \"(\" +\n            COLUMN_NAME + \" VARCHAR(255) PRIMARY KEY, \" +\n            COLUMN_FAKE + \" INTEGER CHECK(\" + COLUMN_FAKE + \" >= 0 and \" + COLUMN_FAKE + \" <= 1)\" +\n            \")\";\n    private final Context context;\n\n    public AppListDatabaseOpenHelper(Context context) {\n        super(context, DATABASE_NAME, null, DATABASE_VERSION);\n        this.context = context;\n    }\n\n    @Override\n    public void onCreate(SQLiteDatabase db) {\n        Log.d(TAG, \"onCreate\");\n        db.execSQL(DROP_APP_LIST_TABLE);\n        db.execSQL(CREATE_APP_LIST_TABLE);\n        initData(db);\n    }\n\n    @Override\n    public void onOpen(SQLiteDatabase db) {\n        super.onOpen(db);\n        if (!db.isReadOnly()) {\n            initData(db);\n        }\n    }\n\n    private void initData(SQLiteDatabase db) {\n        String[] wantFakeApps = context.getResources().getStringArray(R.array.signature_want_fake);\n        String[] neverFakeApps = context.getResources().getStringArray(R.array.signature_never_fake);\n        if (wantFakeApps.length == 0 && neverFakeApps.length == 0) {\n            return;\n        }\n        for (String app : wantFakeApps) {\n            db.insertWithOnConflict(TABLE_APPLIST, null, generateValues(app, true), SQLiteDatabase.CONFLICT_REPLACE);\n        }\n        for (String app : neverFakeApps) {\n            db.insertWithOnConflict(TABLE_APPLIST, null, generateValues(app, false), SQLiteDatabase.CONFLICT_REPLACE);\n        }\n    }\n\n    private ContentValues generateValues(String packageName, boolean fake) {\n        ContentValues contentValues = new ContentValues();\n        contentValues.put(COLUMN_NAME, packageName);\n        contentValues.put(COLUMN_FAKE, fake ? 1 : 0);\n        return contentValues;\n    }\n\n    @Override\n    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {\n        onCreate(db);\n    }\n}"
  },
  {
    "path": "fake-signature/src/huawei/java/com/huawei/signature/diff/InitProvider.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.huawei.signature.diff;\n\nimport android.app.ActivityManager;\nimport android.content.ContentProvider;\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.util.Log;\nimport java.util.List;\n\npublic class InitProvider extends ContentProvider {\n    private static final String TAG = \"InitProvider\";\n\n    @Override\n    public boolean onCreate() {\n        Log.d(TAG, \"onCreate\");\n        if (!isServiceRunning(getContext(), getContext().getPackageName(), SignatureService.class.getName())) {\n            Intent intent = new Intent(getContext(), SignatureService.class);\n            try {\n                getContext().startService(intent);\n            } catch (Exception ignored) {\n            }\n        }\n        return false;\n    }\n\n    private boolean isServiceRunning(Context context, String packageName, String serviceName) {\n        ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);\n        List<ActivityManager.RunningServiceInfo> serviceInfoList = manager.getRunningServices(Integer.MAX_VALUE);\n        if (serviceInfoList == null) {\n            return false;\n        }\n        for (ActivityManager.RunningServiceInfo info : serviceInfoList) {\n            if (info.service.getPackageName().equals(packageName) && info.service.getClassName().equals(serviceName)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    @Override\n    public int delete(Uri uri, String selection, String[] selectionArgs) {\n        return 0;\n    }\n\n    @Override\n    public String getType(Uri uri) {\n        return null;\n    }\n\n    @Override\n    public Uri insert(Uri uri, ContentValues values) {\n        return null;\n    }\n\n    @Override\n    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {\n        return null;\n    }\n\n    @Override\n    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {\n        return 0;\n    }\n}"
  },
  {
    "path": "fake-signature/src/huawei/java/com/huawei/signature/diff/InitReceiver.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.huawei.signature.diff;\n\nimport android.annotation.SuppressLint;\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.util.Log;\n\n/**\n * This is to make sure the process is initialized at boot.\n */\npublic class InitReceiver extends BroadcastReceiver {\n    private static final String TAG = \"InitReceiver\";\n\n    @SuppressLint(\"UnsafeProtectedBroadcastReceiver\")\n    @Override\n    public void onReceive(Context context, Intent intent) {\n        Log.d(TAG, \"onReceive\");\n        try {\n            context.startService(new Intent(context, SignatureService.class));\n        } catch (Exception ignored) {\n        }\n    }\n}\n"
  },
  {
    "path": "fake-signature/src/huawei/java/com/huawei/signature/diff/SignatureService.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.huawei.signature.diff;\n\nimport static com.huawei.signature.diff.AppListDatabaseOpenHelper.COLUMN_NAME;\nimport static com.huawei.signature.diff.AppListDatabaseOpenHelper.TABLE_APPLIST;\n\nimport android.app.Service;\nimport android.content.Intent;\nimport android.database.Cursor;\nimport android.database.sqlite.SQLiteDatabase;\nimport android.os.Binder;\nimport android.os.IBinder;\nimport android.os.Parcel;\nimport android.os.RemoteException;\nimport android.util.Log;\nimport org.microg.signature.fake.R;\n\nimport java.io.FileDescriptor;\nimport java.io.PrintWriter;\nimport java.util.Date;\n\npublic class SignatureService extends Service {\n    private static final String TAG = \"SignatureService\";\n    private SQLiteDatabase database;\n    private AppListDatabaseOpenHelper openHelper;\n    private long start;\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n        this.openHelper = new AppListDatabaseOpenHelper(this);\n        this.database = openHelper.getWritableDatabase();\n        this.start = System.currentTimeMillis();\n    }\n\n    @Override\n    public int onStartCommand(Intent intent, int flags, int startId) {\n        Log.i(TAG, \"onStartCommand\");\n        return START_STICKY;\n    }\n\n\n    @Override\n    public IBinder onBind(Intent intent) {\n        return binder;\n    }\n\n    @Override\n    public void onDestroy() {\n        this.openHelper.close();\n        super.onDestroy();\n    }\n\n    @Override\n    protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {\n        writer.println(\"Started: \" + new Date(start));\n    }\n\n    private final ISignatureService.Stub binder = new ISignatureService.Stub() {\n\n        @Override\n        public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {\n            if (Binder.getCallingUid() > 10000) {\n                Log.w(TAG, \"Illegal access from app\");\n                reply.writeException(new UnsupportedOperationException(\"Illegal\"));\n                return true;\n            }\n            return super.onTransact(code, data, reply, flags);\n        }\n\n        @Override\n        public String[] querySignature(String packageName, boolean suggested) throws RemoteException {\n            try (Cursor cursor = database.query(TABLE_APPLIST, null, COLUMN_NAME + \"=?\",\n                    new String[]{packageName}, null, null, null)) {\n                switch (cursor.getCount()) {\n                    case 0:\n                        return getResult(suggested);\n                    case 1:\n                        if (cursor.moveToFirst()) {\n                            int shouldFake = cursor.getInt(1);\n                            return getResult(shouldFake == 1);\n                        }\n                        break;\n                    default:\n                        throw new IllegalArgumentException(\"result size: \" + cursor.getCount());\n                }\n\n            } catch (Exception e) {\n                Log.w(TAG, e);\n            }\n            return getResult(false);\n        }\n\n        private String[] getResult(boolean useFakeSignature) {\n            if (useFakeSignature) {\n                return new String[]{getString(R.string.fake_signature),};\n            } else {\n                return new String[]{getString(R.string.real_signature),};\n            }\n        }\n    };\n}"
  },
  {
    "path": "fake-signature/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <uses-permission android:name=\"android.permission.FAKE_PACKAGE_SIGNATURE\" />\n\n    <application>\n\n        <meta-data\n            android:name=\"fake-signature\"\n            android:value=\"@string/fake_signature\" />\n\n        <meta-data\n            android:name=\"other-signature\"\n            android:value=\"@string/fake_signature\" />\n\n        <meta-data\n            android:name=\"AAAA100\"\n            android:value=\"E5182720425068E41BAA77AAA36485E3B044813F5F1B9B2F0CAEA14BF75AAA12-5E22451017379222BFD5C05CA7A0112D3F48D1E485F7FFD5F2A57EF16D7673C5\" />\n        <meta-data\n            android:name=\"AAAA101\"\n            android:value=\"6BC560052007DFB4486F378DB708538F170F77123C84987201F47CC30D994169-5E22451017379222BFD5C05CA7A0112D3F48D1E485F7FFD5F2A57EF16D7673C5\" />\n        <meta-data\n            android:name=\"AAAA102\"\n            android:value=\"61F5747032F2D38770C440213C191768346D0F3F2E5A50315ABB0EE3F8CBF677-F0FD6C5B410F25CB25C3B53346C8972FAE30F8EE7411DF910480AD6B2D60DB83\" />\n        <meta-data\n            android:name=\"AAAA103\"\n            android:value=\"8CEB6FA4B77EF06992BFA23433204E44802335132378B16C7416471B3EEA879A-3D7A1223019AA39D9EA0E3436AB7C0896BFB4FB679F4DE5FE7C23F326C8F994A\" />\n        <meta-data\n            android:name=\"AAAA104\"\n            android:value=\"893C6C86BC82B8F63A0BDD7A6995C3A3A2EF529E91E1379CA8DA6C9C2E934F83-F0FD6C5B410F25CB25C3B53346C8972FAE30F8EE7411DF910480AD6B2D60DB83\" />\n        <meta-data\n            android:name=\"AAAA105\"\n            android:value=\"A2F1115AE1C30A897CD323EF0996A2051528F156CB5B038AC42B20C6625F4136-F0FD6C5B410F25CB25C3B53346C8972FAE30F8EE7411DF910480AD6B2D60DB83\" />\n        <meta-data\n            android:name=\"AAAA106\"\n            android:value=\"703365F73A0EA16CD9CBB3436ABC2690F37FD489A126B40170B1DED1A33B317E-2C8989DDAAD2D08353E931AEE01D1A892D9061F3234F44E00D0A848FEE0CBD7C\" />\n        <meta-data\n            android:name=\"AAAA107\"\n            android:value=\"B61CDF16F9042D0CA16C46BEECD10D157FB568203A2623F047D04573B0DB8BBE-AC2059D6EE57B94AF99DF9714F70F0A87EF6F1ED9FF424771C6E1FE96F9556C0\" />\n        <meta-data\n            android:name=\"AAAA108\"\n            android:value=\"FE442C19021F749808DC95BDAF40118476FC2E64F2A35EDFE6221C51D27AF4DA-A2A1AD7BA7F41DFCA4514E2AFEB90691719AF6D0FDBED4B09BBF0ED897701CEB\" />\n        <meta-data\n            android:name=\"AAAA109\"\n            android:value=\"3096D03FD67F8424C607B6922F84B08903C9ABEDAD4EB546791037639CC6C6F1-F0FD6C5B410F25CB25C3B53346C8972FAE30F8EE7411DF910480AD6B2D60DB83\" />\n        <meta-data\n            android:name=\"AAAA110\"\n            android:value=\"4DA81EE0A51BBF12BB790454782B5C8263B0F2E8028A54A4B5BD44B15E5E6A50-C02724F3A37CCED2D34D87B6536D8DB843C6182970FE0C5ED8C8911F150EFDA9\" />\n        <meta-data\n            android:name=\"AAAA111\"\n            android:value=\"1C19E8968F45287C7F8DB5E9460A75C09D443FABCDF628A51CCDE17DD7CCF019-95B5D2574259B91A7A36C1A5F3C8A564DF2471DF76378195473B10967A2B37A7\" />\n        <meta-data\n            android:name=\"AAAA112\"\n            android:value=\"A869CA70EBA8BB5100B3E2F28FCD846ECAF8B2ADF82AF83FD9DC9E636BFBE0FF-3D7A1223019AA39D9EA0E3436AB7C0896BFB4FB679F4DE5FE7C23F326C8F994A\" />\n        <meta-data\n            android:name=\"AAAA113\"\n            android:value=\"4F848BC926B3DA4F967FFF60FF5C2DD6B694DF329EF7F072ED2E5E821F9318EC-3D7A1223019AA39D9EA0E3436AB7C0896BFB4FB679F4DE5FE7C23F326C8F994A\" />\n        <meta-data\n            android:name=\"AAAA114\"\n            android:value=\"42731948C94D51DE27DA0DC712666D4A6209DAB0B8B1BA96B789769DEBF29375-3D7A1223019AA39D9EA0E3436AB7C0896BFB4FB679F4DE5FE7C23F326C8F994A\" />\n        <meta-data\n            android:name=\"AAAA115\"\n            android:value=\"1D0467BF0E3980E89FE023DB4F95108EEEDFA01FBEC18AD1D4CF904B07A7424E-3D7A1223019AA39D9EA0E3436AB7C0896BFB4FB679F4DE5FE7C23F326C8F994A\" />\n        <meta-data\n            android:name=\"AAAA116\"\n            android:value=\"04A1F5DDC4E1C6D0F4B29C1A47E8F0DBF56D3303995BDCE4D6E0311AFEB4D001-3987D043D10AEFAF5A8710B3671418FE57E0E19B653C9DF82558FEB5FFCE5D44\" />\n        <meta-data\n            android:name=\"AAAA117\"\n            android:value=\"8AB3D13027D353C7D6CD2C554336E5E30E0104449FEE256E4942417C8A9AD1FE-E682FE0BCD60907DFED515E0B8A4DE03AA1C281D111A07833986602B6098AFD2\" />\n        <meta-data\n            android:name=\"AAAA118\"\n            android:value=\"CBC142FA73FCE3275A300945AF640183EA3347F63115D4BAF32405B3F9394C4E-3E67A81EFA21CBC7714A4F42BECAFDDD06C4E762A66893A99389EB0E3F55A021\" />\n        <meta-data\n            android:name=\"AAAA119\"\n            android:value=\"C1E488B0862011E9D7FE5C35BF012AFD9A2857FF6E41A153113AF1E982697DE7-F2C78F9B084934097ED94126C015B4FE2F59F3711FEC5E8A51479370DD220FEA\" />\n        <meta-data\n            android:name=\"AAAA120\"\n            android:value=\"F2CEC7BE8A770317E9F810DAB83BB7DE459CEC318568E36E69D6F14163169CE3-6DD2CA3EBBBD9AA2467E5CF2CD6018E2BD26B5FCFEF5EEB1323EC5DA2B8F9E11\" />\n        <meta-data\n            android:name=\"AAAA121\"\n            android:value=\"3966E13AD3D5EB0C6F6A9DF6A4B052E3F4B53C3A2244081D7D78CB6E9B37AE15-F0FD6C5B410F25CB25C3B53346C8972FAE30F8EE7411DF910480AD6B2D60DB83\" />\n        <meta-data\n            android:name=\"AAAA122\"\n            android:value=\"F63807F0530A97962B9A42CACE13EDD013F2BA754E9F94197784579471BE9B75-F0FD6C5B410F25CB25C3B53346C8972FAE30F8EE7411DF910480AD6B2D60DB83\" />\n        <meta-data\n            android:name=\"AAAA123\"\n            android:value=\"1B707952995ACC2FA233C12791F7F15B9ADD64D7B787D89AA78AAC435BA25F32-5F3E50F435583C9AE626302A71F7340044087A7E2C60ADACFC254205A993E305\" />\n        <meta-data\n            android:name=\"AAAA124\"\n            android:value=\"29E4AA19541D6C1C2BFDAE8331183C15790BAB4C13E86AB3FF3ED65738C852CB-E3F9E1E0CF99D0E56A055BA65E241B3399F7CEA524326B0CDD6EC1327ED0FDC1\" />\n        <meta-data\n            android:name=\"AAAA125\"\n            android:value=\"2571A9EFFBD4B3717B1F63BD5A53CE8A0AC64119CF74C707097140C5F98A9805-3D7A1223019AA39D9EA0E3436AB7C0896BFB4FB679F4DE5FE7C23F326C8F994A\" />\n        <meta-data\n            android:name=\"AAAA126\"\n            android:value=\"26DBF852BFF4B183584E17408B7089361AFE637716FAF1652461F862160335C2-03637F6C5D8F604E6FDB79A6FFBFA578DE4E318F8DA22FC6106665247F8807D7\" />\n        <meta-data\n            android:name=\"AAAA127\"\n            android:value=\"E2E7F0DB7F83FDF6E77307C76C52171D99CA13FD8078A04423F7197440310808-0FD9A0CFB07B65950997B4EAEBDC53931392391AA406538A3B04073BC2CE2FE9\" />\n        <meta-data\n            android:name=\"AAAA128\"\n            android:value=\"A7D5AE36B55819C0009BE06274C1B4E835EFCE31AE3645502B6BB294008DC2BD-3D7A1223019AA39D9EA0E3436AB7C0896BFB4FB679F4DE5FE7C23F326C8F994A\" />\n        <meta-data\n            android:name=\"AAAA129\"\n            android:value=\"BE0CA287362158A5AD91BEED9EBD92636EB6442E2E978DE06CDD6FD57807AC75-6505B181933344F93893D586E399B94616183F04349CB572A9E81A3335E28FFD\" />\n        <meta-data\n            android:name=\"AAAA130\"\n            android:value=\"0FB2D5931D5A62804772B25C8912C8D56828517CC7E97CE1C10FABE91DDE1CCB-F0FD6C5B410F25CB25C3B53346C8972FAE30F8EE7411DF910480AD6B2D60DB83\" />\n        <meta-data\n            android:name=\"AAAA131\"\n            android:value=\"2DD38136FB184B8F58728153BD6FBA756C31E85370E76A9708E4F42EDAEC929B-B6DD0562256487FCD6C98CDE137858EF50D9ADB9F9CD2F1CA58C5357EFDF0FAF\" />\n        <meta-data\n            android:name=\"AAAA132\"\n            android:value=\"41BADE45EE0E408A123B83A8246094015E525184ABAB132F99CA30F03CCF27A3-3C39D23CF9367849A5C699395647FE0E5BFEA5A1F1F40D8C717DDC70F8BFA113\" />\n        <meta-data\n            android:name=\"AAAA133\"\n            android:value=\"F66EF52C2021D03BE5B10BF7D5ADC692C67CF31F6B07BE15D4E0FCDE7F514D5F-970B91143813B4C9D5F3634F672C9FCAA5621B4EFAAEDAFD6C235CBBB869736F\" />\n        <meta-data\n            android:name=\"AAAA134\"\n            android:value=\"6583CFB3299AD4C567C1FD8E91E9F743BFE31A8B644B3A75F609BF393990980C-392DB11DDC91594B2BC7C0B05D75175F466C3495C7345A0BCD77DF70380458B0\" />\n        <meta-data\n            android:name=\"AAAA135\"\n            android:value=\"D4AFBBB7C70E15341B14E44A69AC3F9A76127246EA5F468BA3160DB76AEEE050-7CAAB6E6BA700E0DDCF75CCA52B8C3B19A3C7D23308F7EB177A64EB2476197BD\" />\n        <meta-data\n            android:name=\"AAAA136\"\n            android:value=\"AF4D70F26D046891A014AF96BEFBBF2C03FCF7FB306858CB8466200E44861AF5-F0FD6C5B410F25CB25C3B53346C8972FAE30F8EE7411DF910480AD6B2D60DB83\" />\n        <meta-data\n            android:name=\"AAAA137\"\n            android:value=\"315FA1FAD5A32C35A30D043B537177E6CA3D9F76D4DD96D90A6B67D4254DB3A3-FDB00C43DBDE8B51CB312AA81D3B5FA17713ADB94B28F598D77F8EB89DACEEDF\" />\n        <meta-data\n            android:name=\"AAAA138\"\n            android:value=\"263EF4CBB86FB778E117049E8A852A5E94B15D3C1D938D2557F1D5FFEB38E510-F0FD6C5B410F25CB25C3B53346C8972FAE30F8EE7411DF910480AD6B2D60DB83\" />\n        <meta-data\n            android:name=\"AAAA139\"\n            android:value=\"04A557D343921EC2588BFEAA428B57EA64EB5B21030A6161443A4BDDFA9B4214-D29E0251ECF7E15E06AD1874EE1C08213DFEF3D4BCE03032B181667F7389C4D2\" />\n        <meta-data\n            android:name=\"AAAA140\"\n            android:value=\"CE5922D148D9CB50D02C3F119E1D7893C7E87D49F19DD402ED2E9ED2D5BF7D95-31BE40096F931CD7F11D5E262D2B2C437C44385FB4ECBC1013D95A7435816F9C\" />\n        <meta-data\n            android:name=\"AAAA141\"\n            android:value=\"7D312CBE75DAF14066483EBB9AA706DA2675679947603E4A3125A81ED28B3D7C-E21136734BF57372B3A0E4A29D7E1DB5CDD993AA64DA1E1EA9F2CD054B418C56\" />\n        <meta-data\n            android:name=\"AAAA142\"\n            android:value=\"762BF4C3CBFC4CFC375DF04AB77449EA74E827E3E8B411DF1B6C33FEB72B0136-3D7A1223019AA39D9EA0E3436AB7C0896BFB4FB679F4DE5FE7C23F326C8F994A\" />\n        <meta-data\n            android:name=\"AAAA143\"\n            android:value=\"82CF5CCDAAB6A54D656B83F9982DD97FC90F1608F872FC61B7D2B7B7338A5BDD-5BFF7D614E1BA11A566ABB589C863B013F79AA747BD2146733366C5625A5F0D2\" />\n        <meta-data\n            android:name=\"AAAA144\"\n            android:value=\"6B0DB494BBF9C97F6D9331E72302C3737462C1FE1106DE96D273DF6D327C8A2E-3D12CC11F4C4BE82235F70F90469BE0B9C9629AEC5FCB949CB32B1FA375BFC3E\" />\n        <meta-data\n            android:name=\"AAAA145\"\n            android:value=\"E05B73F12128882B6F8BFAF5B0685C1D4B2ECFD12C9481EEA80F224381B28BE2-B2E6BC0C730B88AAFFBD5BF522F792DDA5C82F5FB814E5C3688C32670C28681E\" />\n        <meta-data\n            android:name=\"AAAA146\"\n            android:value=\"341C2F5F3EA01C36F350B917D94813A0D0098690501FEDB3B6DA561BAA6E86AE-2173A248E2B11F9760B9167F398B183C92816CF8FC74AFD3C64B22EDDF50481C\" />\n        <meta-data\n            android:name=\"AAAA147\"\n            android:value=\"6B4BB3E8028A9F57D237DECF06BBB98A98AFB168879BAA100D069CF83B6D3F9C-3D7A1223019AA39D9EA0E3436AB7C0896BFB4FB679F4DE5FE7C23F326C8F994A\" />\n        <meta-data\n            android:name=\"AAAA148\"\n            android:value=\"D65BE7C7B4831B196ECA14F860DD9EDF22EE71B613B799D44E0DEA5B3B57AD8E-944BDA466EAF64BE1C93896D5C8E9A454A07C8D8FCBC4ADEEEFB3545B335E979\" />\n        <meta-data\n            android:name=\"AAAA149\"\n            android:value=\"96B8638D13D3EC2AB7FF4BCCB7DE5F702AF971D8C01B79DFF50E97CF8E2C31CC-07184F6EE5CD6AE54BBE55745E79368BA91104B3CF49012298C77F07C1F4B2EF\" />\n        <meta-data\n            android:name=\"AAAA150\"\n            android:value=\"04C0BDEBAE2968AE9F2AA1022A32CDF9F75BC8BE783BA9B030A4A95FBCB28594-F0FD6C5B410F25CB25C3B53346C8972FAE30F8EE7411DF910480AD6B2D60DB83\" />\n        <meta-data\n            android:name=\"AAAA151\"\n            android:value=\"BD69DC2A9578BEF3F49D3B0C351270A5570D5A076EE43E89F3E69C93F01441E9-C3E0EF6A2F0AB978A9BBEA30AF5E216A8140037AB9349CADADBD34862CF316B9\" />\n        <meta-data\n            android:name=\"AAAA152\"\n            android:value=\"9A652C046E178FDC33F66E316544D1BD23E55F9CEC7116FCBB92EE6C59A7520B-68842530E0C7F9D42B021E148BEE247FA741A063BE39440CC8DAECC9A05F669C\" />\n        <meta-data\n            android:name=\"AAAA153\"\n            android:value=\"0BAD4BE4BAE400DE28EE1E0B9CE78779CC5108CC0059FC7DBC8EA703E35A1EDC-E357F022AB8EDB771E374E586808E268C914EB34DC6C7A068C0E0A05C8128953\" />\n        <meta-data\n            android:name=\"AAAA154\"\n            android:value=\"3F911207AB9D14BB89ABF5E28EE03C3FF8C736182C05D93945878E483B7F0AA3-3D7A1223019AA39D9EA0E3436AB7C0896BFB4FB679F4DE5FE7C23F326C8F994A\" />\n        <meta-data\n            android:name=\"AAAA155\"\n            android:value=\"0D8B6C0040449388E0801FADED3C8A06D6108E8F12EAF40E55ED4574DF43D63D-3D7A1223019AA39D9EA0E3436AB7C0896BFB4FB679F4DE5FE7C23F326C8F994A\" />\n        <meta-data\n            android:name=\"AAAA156\"\n            android:value=\"FC8E4C77D0EF4E194FC985A100F78E9C9356198D4A270E065FE7516857C04481-5F18DDCA47420841325ED54D1AF9484AF92F65AAC70A3B623C4E867F4EF71E20\" />\n        <meta-data\n            android:name=\"AAAA157\"\n            android:value=\"924F9479B29D72054823EB800829218CDB5AAB8FF94405048224879B067AF50E-F0FD6C5B410F25CB25C3B53346C8972FAE30F8EE7411DF910480AD6B2D60DB83\" />\n        <meta-data\n            android:name=\"AAAA158\"\n            android:value=\"0BD748A0C93F52B08AD8FB4B7361726565F26FE575A76065FD455415E61A4795-3D7A1223019AA39D9EA0E3436AB7C0896BFB4FB679F4DE5FE7C23F326C8F994A\" />\n        <meta-data\n            android:name=\"AAAA159\"\n            android:value=\"7649A7DF70C972A6A1C4B935C37DB1630CF607D966DBB88A9CE1398EABCDA2BA-3D7A1223019AA39D9EA0E3436AB7C0896BFB4FB679F4DE5FE7C23F326C8F994A\" />\n        <meta-data\n            android:name=\"AAAA160\"\n            android:value=\"6C25CE366FA32C6A51F882DFBFB65F40B7E5CED717581B165020B60C8CD229C6-DCDDB8C5ADDACABEDF5EDD2EF9E3FF2A0560432C8506F1164141DB1D02DDBB9D\" />\n        <meta-data\n            android:name=\"AAAA161\"\n            android:value=\"1B1433CEA4DC02C3A817C7222B4E80527A87D6A7028A439E2E73C5BC6684648A-F0FD6C5B410F25CB25C3B53346C8972FAE30F8EE7411DF910480AD6B2D60DB83\" />\n        <meta-data\n            android:name=\"AAAA162\"\n            android:value=\"EEC089426319C4E6358E584078CB153A76C40B9FE44FAE11BA3FBDBDF26CFF51-3B943A3A966CB2509653FBB060E2594B832732E7B6558BA18EDA7A1D31D0F2B3\" />\n        <meta-data\n            android:name=\"AAAA163\"\n            android:value=\"5D42FEEA41E25B24493D54F11BDE3EF9EB8092F285BB3719CB3F565DF91B652D-A2A1A9104F5BE8EA638663D6998F4D8B545A55A3450CA67373857ED6CBE9D926\" />\n        <meta-data\n            android:name=\"AAAA164\"\n            android:value=\"5352F863EAC09EAC1FDE85A6AC7767B53791BB65D247D70AB943ECC8E09D3401-83F18797E2FDEA4A546750910C09693AEF764C90350BE4647C2A3DFAE2CB141C\" />\n        <meta-data\n            android:name=\"AAAA165\"\n            android:value=\"31FAAA9F4B38216F0BD39C3900226E514F8472D4FBC43482945E7540014B3BF4-F0FD6C5B410F25CB25C3B53346C8972FAE30F8EE7411DF910480AD6B2D60DB83\" />\n        <meta-data\n            android:name=\"AAAA166\"\n            android:value=\"2FA0FCE9F8EEFC5815C78BD7B59C3D51FFC9240125200D0B7E309028F3A61070-60B75724B34686E52BDE944969DE120F16BD6D959788D54384494CAEDD4E445D\" />\n        <meta-data\n            android:name=\"AAAA167\"\n            android:value=\"DA57F91BD11C53A78EFF0214B10B7D6D3BCB2E78945A759A9F0B40C25E0D988E-D3F1FB1B2C81E096E3F5809A503AFDA0CFAF56B9D39DEDC656EE2660ACEF614C\" />\n        <meta-data\n            android:name=\"AAAA168\"\n            android:value=\"82DA499587E5193CCB9208217B93382716E3FEA941A751673D145D69FD3FDF01-3B6A403CA91D56AB854517720203176640816D3F923F92CCA16138F5CC3D0727\" />\n        <meta-data\n            android:name=\"AAAA169\"\n            android:value=\"5F0D08B2FA4C726D941B95E766E32618E622D78DB0AD288C493871AF4E8684E4-BFFEB14903FBC92FFFE6404A3654098A3F85C81A3513AFD5DCEAC121CD678D1C\" />\n        <meta-data\n            android:name=\"AAAA170\"\n            android:value=\"0D156F554E7E7DE89237BFC7C901A920FA0BA59F87FE4A1E0D32C151110DA99A-4E92275E4F7853F3DF65171071F0B6841B063520EE93D9BB2DB647BAEC695B98\" />\n        <meta-data\n            android:name=\"AAAA171\"\n            android:value=\"68AC28856C5868B6232C7332BA597E3A1681E079070169D48F6A38FF64C5448F-184058684847B151D09A3E08449A23B48C67F1614EF95CAB211FC080DD26E248\" />\n        <meta-data\n            android:name=\"AAAA172\"\n            android:value=\"A7B6A6D4CBBB5EC247FF9746BD9B56D61B6E23008F40E3A649D6A6E6FADDF2E5-B925136F3EA7C0A1951690A1AB313910DA81F40994A85342EC622888F1287051\" />\n        <meta-data\n            android:name=\"AAAA173\"\n            android:value=\"C374E880E69EF21FDF46BB4F345C5B14E0F49B83000E6ECE9F885200A29C3A86-9EA146D935C0BE2E4B576396E6A5E1DE6DCB69A71AF4E417B0A5B8FE8E0D4D9C\" />\n        <meta-data\n            android:name=\"AAAA174\"\n            android:value=\"051648575A400BA807F83519C764BA0077DC52FA739AFBBF70FD2FDC002B3E1F-B925136F3EA7C0A1951690A1AB313910DA81F40994A85342EC622888F1287051\" />\n        <meta-data\n            android:name=\"AAAA175\"\n            android:value=\"EFD9FCF5BEFA32F183CC99B551CC159672BE69FC0C69739D9F6EC2C403FC36E1-A0328A96AC93BE7983B5BEC417BD2C03F129AF6F8AFF39512470E66A18DD964E\" />\n        <meta-data\n            android:name=\"AAAA176\"\n            android:value=\"B5E5BBF1CAF0E3230A1661A95F00A32D08C7B1414FB57C244E38D3D2E2D36572-B925136F3EA7C0A1951690A1AB313910DA81F40994A85342EC622888F1287051\" />\n        <meta-data\n            android:name=\"AAAA177\"\n            android:value=\"6317EB5351F58ED0FD4382489F57C18E59EEF3B7CB1ABAA42AD53E87E93C12A7-A0794215278A567E887AF6CDE015A5E88414EF640F7DAB3855A3E779658BE778\" />\n        <meta-data\n            android:name=\"AAAA178\"\n            android:value=\"B642AE584BD3A331CBFD18C6C68A2B5BDF01ACD1B4F83BF671782BD15302954E-7D539351CA39C27CA706409E5A9B6B062DB9BF8DC3D8CAA6137067AE7F68B5E7\" />\n        <meta-data\n            android:name=\"AAAA179\"\n            android:value=\"7804369A616A1AC45FCEAB333E10F5C68672A184658E9D00D544CDD47A5F223F-496DB0267B93E963AB269AD115BB1C1D65EB2AFF64AF279845A04EC8E282EF57\" />\n        <meta-data\n            android:name=\"AAAA180\"\n            android:value=\"43144618BAC287987073B2A488200B30BDE7C302718A51EB5CFB56B1877F9008-F5F6531CBD8853165E64814F8FD8C92872CEDB85ABAF2985EE54936817219EA6\" />\n        <meta-data\n            android:name=\"AAAA181\"\n            android:value=\"218302009174312FBD0F363C988EF9D4521D3A1B83B91D37BD184EA8235FB426-9C2DB70513515FDBFBBC585B3EDF3D7123D4DC67C94FFD306361C1D79BBF18AC\" />\n        <meta-data\n            android:name=\"AAAA182\"\n            android:value=\"990DAAC31A8E54D4C83E85FEC26A7739DC379623B625FA0DFBE0D89A925312E3-AC7F3B3537E8E6797BE7270FA4F9F6A2414E660F51A86EFD47C75F00603BC328\" />\n        <meta-data\n            android:name=\"AAAA183\"\n            android:value=\"10D0F8636D0D7C502D778DD2B26EDEB5BA1C406CBA847B2B878F2255830A61D1-59EA9DED5F79298A50103D254497CA71CA80332492C749375044879B8F099357\" />\n        <meta-data\n            android:name=\"AAAA184\"\n            android:value=\"500F0CFC6AA65F8978989E9BBE38C07FABC9CF39373860A85BA091B7845AC15C-AA169A9753E2FF6676AC26E4AF3573FB387F05C66DE80DC352CE3324BD9AB08F\" />\n        <meta-data\n            android:name=\"AAAA185\"\n            android:value=\"9385B382F4B44B0DE3B7022DC6FBFBB70F0F5BBCDFC469E6BD2B3555C48B753F-3467B909BE2A577043BB77406388320DF882276C937D09689C4D894193984C01\" />\n        <meta-data\n            android:name=\"AAAA186\"\n            android:value=\"E4428C01E901B36EA846E0A5BC0BD9B8D8E67868B575F148C62CEE5FF4986C2D-EEBD0F16E629AF8B8381BFEDFDD649605FE90F763F5CB7BA473EB9EEF94D9AF1\" />\n        <meta-data\n            android:name=\"AAAA187\"\n            android:value=\"71877A1DA29B39C59EE305327F8E4282D85BCE0A14315974A4A5D3E6504746D4-52586D838E24FE06DD85B495E76421B61222C66589F5D21C0197561D0702CCDB\" />\n        <meta-data\n            android:name=\"AAAA188\"\n            android:value=\"91A3E6517B6E78A08BD19AC886E58BE5957D385BF3E2471E321E43577D8B1BFB-244FD19BC69ACA04262FF8FB40A150BE4176F7BDD1673F82E64205D77D484873\" />\n        <meta-data\n            android:name=\"AAAA189\"\n            android:value=\"E1B5749F752536105DD39045A5579C754653EBB005ED39F2264919F28E31206C-B925136F3EA7C0A1951690A1AB313910DA81F40994A85342EC622888F1287051\" />\n        <meta-data\n            android:name=\"AAAA190\"\n            android:value=\"2CD95CD159ED3E0AF2D4ED848FEEA97EBC183C3C84CD63BB08CF2E4F90D90ABA-B2B90F2F5A3679186FB82A6FB8C07F5E6AB4B55EA01B5625B28A9B5549FC6988\" />\n        <meta-data\n            android:name=\"AAAA191\"\n            android:value=\"8220EC41C32C82C18A707DAB0BD554638C91B1831DCA782ABA90493E907AD2D1-11FD3E05865044295882005535005CFD2B0DE878C2546FC4500763C3E4A5C339\" />\n        <meta-data\n            android:name=\"AAAA192\"\n            android:value=\"B60086045A4EAEE4F456E9408D26441992D491CF4B82D23B5A8DEA9136221EDE-2C4EFABE04EFEB9DD03B02E9FEC98CDA131A23BC1AE9627EDC1D0E7F07E170E2\" />\n        <meta-data\n            android:name=\"AAAA193\"\n            android:value=\"29B1B4C056A074CD1498E1D3A87C96E2308A1012963FF04757402A2F36DB6CE6-EFE2BDC9764610AEBE1CEA210AB4FEC88D6FAE9ED878E9D16E1AFA53DAE8B42A\" />\n        <meta-data\n            android:name=\"AAAA194\"\n            android:value=\"40121B20BBDC90A40FCDA1C15F2F025F67AAEF1C600633D238A4DC5019868646-F487CB84EEFAF8DBD507BF5D31827969901608319C8790D670144F8BAB6B9802\" />\n        <meta-data\n            android:name=\"AAAA195\"\n            android:value=\"D4C6BC2889D50309446B3A914E0C497BE0A7A7F1D6F88B8CEEC89008574BF140-A9AB6BA83559706C7EBAD25A66848F6A251978032A4920F83037D759527E604C\" />\n        <meta-data\n            android:name=\"AAAA196\"\n            android:value=\"550A4594462C66BE9CFC67B9A507CB472113812034D1915FCB401C1C7C68E2F0-1338F9B049893CC70B78432A177582F90BD4BC6296EA4ED35BCC7DF59687AC53\" />\n        <meta-data\n            android:name=\"AAAA197\"\n            android:value=\"23B04A6FCF2EBFC7064F83DC3AC4722905DBE4629D9790EAF261AEA2D724A4CF-FAD6269B06C93A481D23B166A53648AF5C204F1648AF3C8B69F77BFB52A15AB9\" />\n        <meta-data\n            android:name=\"AAAA198\"\n            android:value=\"1829669D17794133EB5485C1D6476F9B401CB032C16CCA67BCF87DB32B68FEAC-088416AC007E7CC70DF1536C72007D330E7B8426CB099E1B64BD900A61B950F8\" />\n        <meta-data\n            android:name=\"AAAA199\"\n            android:value=\"95451A5D9562B8FDE8B92843BBFD248ED26871CF8F5989ADA165901819E62E6A-2407A2FA4B78F69FB10C0301C24E91B9A23BA131278A7F28CF39870804E216A4\" />\n        <meta-data\n            android:name=\"AAAA200\"\n            android:value=\"658EF42E3BE38619809712F904D3184F6C149EEA90FE8E15BBCD8C84D33C9F2E-437B7C9A946C3CE9F249A4308614F542C14D7C7A3BC97789984E0247CD2301FB\" />\n        <meta-data\n            android:name=\"AAAA201\"\n            android:value=\"43898D5B58974356FB21B22C519738E8FDF562E6C6CEE86C7C03E0845A381C27-9757F9B84D0B19ADBC9C5A18AFCCFB38F0973C9A07E9880BDAAF106E1BF30E5E\" />\n        <meta-data\n            android:name=\"AAAA202\"\n            android:value=\"EE7188F5A8F33A70C7FCFE890D8AB1D76171D864ED4485EB2026AE5357047599-C8E79B854BA95CEAEF861C3F70BDE22A8523912D10007C293C1F56BFF9FEE5FF\" />\n        <meta-data\n            android:name=\"AAAA203\"\n            android:value=\"73544CEAD268A36225BAE70FC5FB863C31A30AF2C1393464C3913E740CE051AD-41B3F9D1F10A8D2C6CB3449B848CB701046F908345A38DA8943B7DA697ADD8A2\" />\n        <meta-data\n            android:name=\"AAAA204\"\n            android:value=\"1219C5EDCAFB7F64AA0C43CC0FABD2A6F266ABCAED260F617C3086AFBB5923A2-6723F35D2527A8B1975BF436DF2A6A9DDF9687AA370D98A27C1A03BE17A3C101\" />\n        <meta-data\n            android:name=\"AAAA205\"\n            android:value=\"45FCF41715946F21BE07288079D607D8536B03E933F6C99C7D6772845AEAE50E-E4151E382B51078CAA2E3E0C719A95DF1772E4CAF19496264833AB661D861265\" />\n        <meta-data\n            android:name=\"AAAA206\"\n            android:value=\"B8EF4533C114E2021233599AD0A8E20C5F491D53C5C33D911A809ECD3DA92898-A6FBC39C38152507F5ECFA8D3C77F72CE56D772363F188117D6BBE01D59BE79C\" />\n        <meta-data\n            android:name=\"AAAA207\"\n            android:value=\"13E01692CF9A5E9253BDFB013A54BADE5091F05E659C596115D1E805F6B31A9E-B255437889F6F6FDBB165C43EE661418D4E8336D3A1F6886C3A87C892B514596\" />\n        <meta-data\n            android:name=\"AAAA208\"\n            android:value=\"C6A381AC2B63BEF3094DDD3788A50E3668C3C455147407E3C8374D9E6A1832FA-C2673C2CB30BB8FC14637FD0C7E02831DC26F685BCB4F7948673FCD8CA172F6D\" />\n        <meta-data\n            android:name=\"AAAA209\"\n            android:value=\"913F8E2511D50502BCEBEA8BB50F042ABFD7715C3AA20AA9E2139197E42E09F1-1F3C6481453DFC5F41EDFEE201DDCE476AA0AA605F6D8E3259C252F46A0A092F\" />\n        <meta-data\n            android:name=\"AAAA210\"\n            android:value=\"15015F2C2CDC87B91A2174CDE75E5EA199B762D231D045DA1E0404BFDAE7B241-11D13896CF4756CA2192396735535D74E9E04D3BA2B137C6C0620797D27AAAC7\" />\n        <meta-data\n            android:name=\"AAAA211\"\n            android:value=\"4D87885938C36CE10AD6F6E577C50FE12291941DEC3CA0AE0465CF9070C27F49-8C87A9F6EAA73B18295422B37C4983D051EEF55C28B341AF2381753EA5FBE671\" />\n        <meta-data\n            android:name=\"AAAA212\"\n            android:value=\"4EE6068395783695FFAC379202C451642546008F8F2333FC6DEC91A5513CFF70-86DD00366A4223B72A06662EAC182D52CE020687F70276E2CD1E1D3E0AEC306F\" />\n        <meta-data\n            android:name=\"AAAA213\"\n            android:value=\"463CB436C4410ACD459D73774A9FDDE3871CCFDA1C15FAE8ACC1C97BBB168046-03BD153DE7230800663090D52320EEEBDD5DEE1006AF8E77D73ED1A11B41DC0B\" />\n        <meta-data\n            android:name=\"AAAA214\"\n            android:value=\"C497FFFE3A64B9841E392A58C1B047FB9116E79300D9366FEECE7676DF2389CF-7A7D89BC2CDAB8230FA3DC5C9D1FAAF0014AF864D575ED7AFF774C7178899EAF\" />\n        <meta-data\n            android:name=\"AAAA215\"\n            android:value=\"356E6D499EF150C2BB3DACA1F37B6AA3FCBF3D4EB75581FD0997E50E1CAEB845-7638D2B96471266080C72F8D3BAE76FB8D22FB81DD6D085FB5E07D9DAEE7D109\" />\n        <meta-data\n            android:name=\"AAAA216\"\n            android:value=\"F384AD5803CB7D1DBD80F3F2FFE02CCA8241B5EEF109815361FB9F65EE654DF2-D0B76F8FCB7E977DA4DEFCEF304BE57BD224785D0E047A1F1FD1B072E2EEBF74\" />\n        <meta-data\n            android:name=\"AAAA217\"\n            android:value=\"97B94DF58B36699C6BB1C7A59BDC50492329A87A0C0F0A9D734D1C0469AF4333-3D4E9FA0C5F1D6D4B2213EFD0983A88722E12FF521EC7572B51663B4578A1744\" />\n        <meta-data\n            android:name=\"AAAA218\"\n            android:value=\"DF5753BC39BB6BA7EF1138BF628FE85869013EB4C58F2A8E1BE73EEC17735F5A-7D2006E51979DAFEA6416D73A903507E400071A140FC146AA6668028CEB35FCC\" />\n        <meta-data\n            android:name=\"AAAA219\"\n            android:value=\"1107B2ED0B01853C6F19752F185114513BE0D3C7202A8407C0FDCE4207C38322-FEE97D124D33C3E7AB374D4B4149A28588DA20E61480DDDBF97F04D82802718C\" />\n        <meta-data\n            android:name=\"AAAA220\"\n            android:value=\"D22D0099016512FCBBC58B896895AAB69A71F37752365E828DBA803B0DC3EA50-85CD5973541BE6F477D847A0BCC6AA2527684B819CD5968529664CB07157B6FE\" />\n        <meta-data\n            android:name=\"AAAA221\"\n            android:value=\"5B6774029D69082FA2FD4E4CCA31A79302625B75EEFE7DAD794E80FF91281104-7E957DE70689C538F682E6EE5745C14E3AC1E912BADC2041EE455F6DDA364A52\" />\n        <meta-data\n            android:name=\"AAAA222\"\n            android:value=\"2DB14B7AF9C7D12563D903AF2686726FA07FA70CB8D7A5D2C6B9F36B96231534-4DA029254A58C13C26DFC281B44823BEB8E0F3EF83B0CBB3F6227CA462C85AC0\" />\n        <meta-data\n            android:name=\"AAAA223\"\n            android:value=\"907D88E72257F6AC7F56BCCB624BBE944B2F193FC9D107EB4101A6C3A6EABA89-9423EE17D36509BE226B46F5912B4760EA7F47A838323EBAEB0DEC44E1F07D52\" />\n        <meta-data\n            android:name=\"AAAA224\"\n            android:value=\"CF257A368A93AE86B7006DF572255F7DE3A4391F18FA5F2F7D1DFFB29F74DE75-19039031BB2D461ED1815F8B892230D4BC278768E4AAC7E723F3ADB6D7F00C24\" />\n        <meta-data\n            android:name=\"AAAA225\"\n            android:value=\"75328D5149E2A0F77E36C206ED4AD2475DDBDC953C3C9863AD94EA7A9BAA7AE5-137D3EB741DB5C4E07BC687F05FBBD5A61FF29A2710D8A05C1E546A5A1BFBC63\" />\n        <meta-data\n            android:name=\"AAAA226\"\n            android:value=\"5E89766D7D14CBB450006C2DC939EA7A1ABA725279293497DC3F09C7F200A534-18594DA9DC59EB261CB387540E5C49D971E89AD7690DC9956D2F20C1E173325F\" />\n        <meta-data\n            android:name=\"AAAA227\"\n            android:value=\"EEAE05BEB760D9AB4954EE50C0DDCE83DE3EE91111B1517C3FD2B494EF123724-D1D26EE248FB940352FB028EB7D72AFA5E181175951842BD3895C703416BDBF7\" />\n        <meta-data\n            android:name=\"AAAA228\"\n            android:value=\"094C2E784DB1B2ACE8BE59318FAE551CA99FDADF3C9F48CCBAFC265E02DD0031-CC7D764D7AAED10630805AA7FFB7DB8308B44779F3646D78EC661DF56A682802\" />\n        <meta-data\n            android:name=\"AAAA229\"\n            android:value=\"E0EEBECDE73CFACD599B3EC1F5B416D3BFCB8C95963EA711BBD262CFC138A170-08D7DD9BD7A68ECFA92C397E3D641C0F4564ADB4C010603F240E4FD71BD9945E\" />\n        <meta-data\n            android:name=\"AAAA230\"\n            android:value=\"355AEC95F42F729E0CEB706A228DA61B8CCD350E41C0F5CBCEEB9CDA56C28483-5FD0D52FC14BA01301BBF8930A7B5F1DAE304F661A66EDEEDA31D367B0B32739\" />\n        <meta-data\n            android:name=\"AAAA231\"\n            android:value=\"8153759EE61E5E4C37F310321458FCC2AFA342BF445E8D12EBDD6A8DE0DC9DE1-04EC029E4B15B43AA4A56E69085C65A493EDAC68EC734C9125DB4BB17207B5AD\" />\n        <meta-data\n            android:name=\"AAAA232\"\n            android:value=\"A310B091F7F8E85DE10D502B75EBA249EABAF30BEC0D3731F841651AF74D072D-D7811EC4166FEA6CC720BA66699DC84B584AC9E6986613A76D4E43D8CBE32B27\" />\n        <meta-data\n            android:name=\"AAAA233\"\n            android:value=\"54360B9C0651A3CB73D74C5F19B394B8592353B23ECB179E067625E0C3E81D6D-3D7A1223019AA39D9EA0E3436AB7C0896BFB4FB679F4DE5FE7C23F326C8F994A\" />\n        <meta-data\n            android:name=\"AAAA234\"\n            android:value=\"0E320D72688B841F1714F24344115B448865DAF293899D2019E85616EFB09737-74433F151752ACEB9243A0ABF7A5812FDAD16CE9F12415D6AA208BB632E6CE6D\" />\n        <meta-data\n            android:name=\"AAAA235\"\n            android:value=\"68207823D02B0EA316B5FCA4EE177B936D069BEB0C309003B0410C1C04F2AFF2-A1D66130AA39056A7995F7D154E2E0F3594A7D3CF0655A77AC379150ED175CBC\" />\n        <meta-data\n            android:name=\"AAAA236\"\n            android:value=\"913BDF5CF599346B6851B4031167CD6C620E619122E96B418017AB36FDFF44D2-3987D043D10AEFAF5A8710B3671418FE57E0E19B653C9DF82558FEB5FFCE5D44\" />\n        <meta-data\n            android:name=\"AAAA237\"\n            android:value=\"540F354E6671419849A6CC61FBE285B17B0293CB266A5BC2BFA22C03B04F1C3A-CC7049EBF726391FDE00A953D67E79E9CD72C140076CD9E3DC86CAA751A9DE65\" />\n        <meta-data\n            android:name=\"AAAA238\"\n            android:value=\"D21FC148E331E70BA5123C56790CF8F2A911782B9688F1585FF8DB4FDE3C1FF4-44C0EA55DF8580979682A2240877013A1358FA47DC9572CCD553D3D33148F9E5\" />\n        <meta-data\n            android:name=\"AAAA239\"\n            android:value=\"DC464243AFB36501609D5E35BDCE23EA60C8B0A601611F239F48A18EC2E75F7D-207AF9A133A630C4246A06C79C09946A70840F4702EE5BAA53F3791B537B0F14\" />\n        <meta-data\n            android:name=\"AAAA240\"\n            android:value=\"64CF804DF13D9EF95E5E94664D386D4BAE48DA061C3B8B3787B6DBE0A1983D1D-C17B8E3E427BFCD99CC65EC24FF53AE917424292D723615B74636468E3223C0B\" />\n        <meta-data\n            android:name=\"AAAA241\"\n            android:value=\"87711EACB7FF6167700FD83D17D269202DA218D8B5088577DE0424BC6341CA8A-1D47E51F53EB11C38B699400F518BDB6D6D27A1D61CC51E2A69EA828C3A2DBE8\" />\n        <meta-data\n            android:name=\"AAAA242\"\n            android:value=\"A4933D2EADFAA0999DFED54BC48CD8B443233AC11FC504A7CFCF6BA4CF3FD85F-DEBACCA80BC71AA7DF5F0FFB769F36207EA0AE36180197B61D2667E9B98B4B8E\" />\n        <meta-data\n            android:name=\"AAAA243\"\n            android:value=\"E155687B04610380A100129D3AA5CE2AAEB00F000E84F97DF4363838B48E2E0F-68F72B282EECEFD55F660B88E9E29796D846295D2C2627E800C76E33137105EB\" />\n        <meta-data\n            android:name=\"AAAA244\"\n            android:value=\"1E4DC80D371D3D50049A91DC28571AD0DEFEAF6D2639302B37EDCA4E235A8DF8-B8BE71A9B52D06B98FFE55BFCAC81DAFF88900062D06F34D0FF62348C82BF58C\" />\n        <meta-data\n            android:name=\"AAAA245\"\n            android:value=\"0CCAE271D1CA1B95A5E98EDE600EA2D177B07E39A1548E6B9535752FCBE398C1-917F8719D4C2C892DBF26BBE2BDB179FFF0E0DDBEB8FF9F31A4DD98BB4A4D25D\" />\n        <meta-data\n            android:name=\"AAAA246\"\n            android:value=\"2BC568287DC0C76BA1BAE28FF5D33ACE02AAA598D8C3582ED44D90A69E837BFA-3D7A1223019AA39D9EA0E3436AB7C0896BFB4FB679F4DE5FE7C23F326C8F994A\" />\n        <meta-data\n            android:name=\"AAAA247\"\n            android:value=\"1FA079FAA5A0CFD5A1BE678792F24CB5D2322B7E5CFC63F51F7B5E3300C7BB9A-3D7A1223019AA39D9EA0E3436AB7C0896BFB4FB679F4DE5FE7C23F326C8F994A\" />\n        <meta-data\n            android:name=\"AAAA248\"\n            android:value=\"FD8B1FF00B5BC196CD958BC7055A3FFCDA20868279E41B042DDA20F173548202-7F7AE292E87D103DDE32745209BDE47BA8F9B2F632D4E8C95B63E3243B31203E\" />\n        <meta-data\n            android:name=\"AAAA249\"\n            android:value=\"A6300917943AAAFD0B5EB151E4E1A06694CC201196D5B6A4A1C10327335E954D-99F6CC5308E6F3318A3BF168BF106D5B5DEFE2B4B9C561E5DDD7924A7A2BA1E2\" />\n        <meta-data\n            android:name=\"AAAA250\"\n            android:value=\"C7E1539F6BF78D3E9541830723B4E72AD29E45E014C7E934B79F50F88B00BCE1-7A425040828738D0FC0B93C16F3E4E4AC2AA49026100B2D01AEBBC0B557D356E\" />\n        <meta-data\n            android:name=\"AAAA251\"\n            android:value=\"9147D453D2D0CB2514B751E53B05F7817B980C5C573C4177832EEBEFEDEBDE86-C47EC42D91260A4B3C9FE70997DE1E581B91B007BBBA6159E7AA293EFD54F4DB\" />\n        <meta-data\n            android:name=\"AAAA252\"\n            android:value=\"B723BD6617DF7E35EC962B179BE5361ECC6306235496AA4FCE9A56F1CDBCEC8F-F0FD6C5B410F25CB25C3B53346C8972FAE30F8EE7411DF910480AD6B2D60DB83\" />\n        <meta-data\n            android:name=\"AAAA253\"\n            android:value=\"0ECB9D5A4F9AFEEE665306ED7DB09FE7F8DD6DAFF2CFACDE616A97EA322D1B61-3D7A1223019AA39D9EA0E3436AB7C0896BFB4FB679F4DE5FE7C23F326C8F994A\" />\n        <meta-data\n            android:name=\"AAAA254\"\n            android:value=\"8A15B9EA25CF2952D48B4BBAA4172D91A54753F73003202D7FEBC8B04C5D3EE0-9DB7FF389AB6A30D5F5C92A8629FF0BAA93FA8430F0503C04D72640A1CF323F5\" />\n        <meta-data\n            android:name=\"AAAA255\"\n            android:value=\"8D0E88764854E91DC2DD3455C937D690062348E7D713D8E42A7BE0FC43F382C6-C991989AF90C73275DCD5A60304E7AA8224C5070B21C52DB1046CFB6878AC77E\" />\n        <meta-data\n            android:name=\"AAAA256\"\n            android:value=\"11BDCB5621EAF7F6A1AFBF64DD258CCD9E40BF1F838A26545D79225DBD5BA80E-A5806CCAC0280E904C7A43E94302DB8AA477DFEEC2AE9BCA8CEEB4DB366827B3\" />\n        <meta-data\n            android:name=\"AAAA257\"\n            android:value=\"30E9DD1C6D84670226BE7404B9C79A8B3C5F579319AF726002A571FC8CBE7BE0-F6F7F8801C166B0E24C87C268F6DF4E529E1C4051D3C21B1739245E6555F599F\" />\n        <meta-data\n            android:name=\"AAAA258\"\n            android:value=\"BA9C33D92609B9F710220E03E0AA9ED3ACBB6187FE80A22D0A765606105560AA-AA250A8522017BE9053F8F29F7EC376A609352E0CC37E66D16DF9F8AD158FD27\" />\n        <meta-data\n            android:name=\"AAAA259\"\n            android:value=\"7925C6ACA136312ADCE5B997FEDD83A8BB4B47B7465DE11072B632DAC53CDF56-0439C9A2EBF7BB3A3A20FFD844E2CF958BCEE612194A4490FC008EEC1BF594D9\" />\n        <meta-data\n            android:name=\"AAAA260\"\n            android:value=\"74ABB0EB772C4250FC9049005CBD549ABEDDF7AE36D1D977D6C746EAFCD87793-0131326FE2E78DE96FC84CD0B5866343B90FC2094DF3B7C38DC431BDD6A31B0B\" />\n        <meta-data\n            android:name=\"AAAA261\"\n            android:value=\"598D2F009BA4904B01BB7C8B89E18A06C9854EC95D48AF898C7BB06E596CC353-91CEE23760826348D2D4BA19D1CF0E4DD611DF52F65893AA9B1F0576647D1848\" />\n        <meta-data\n            android:name=\"AAAA262\"\n            android:value=\"1BED78199091E60D6DDA7C5B87D928AAEC951D0BF8F772BFE8C92C33A4CC8743-3D7A1223019AA39D9EA0E3436AB7C0896BFB4FB679F4DE5FE7C23F326C8F994A\" />\n        <meta-data\n            android:name=\"AAAA263\"\n            android:value=\"B3EF0919640C6923611F4AA659E12025FB08A1073AADD20AA2B78D2A20B80B79-3D7A1223019AA39D9EA0E3436AB7C0896BFB4FB679F4DE5FE7C23F326C8F994A\" />\n        <meta-data\n            android:name=\"AAAA264\"\n            android:value=\"1271AFFB5870E2B96174A0BEE4DDDB823256302E105AC820FE8FECAC1148986C-F0FD6C5B410F25CB25C3B53346C8972FAE30F8EE7411DF910480AD6B2D60DB83\" />\n        <meta-data\n            android:name=\"AAAA265\"\n            android:value=\"862DE90D3A066014DAC9BDC0BD5D393A3FF67CAF9144492B129A35B6B72E4507-B925136F3EA7C0A1951690A1AB313910DA81F40994A85342EC622888F1287051\" />\n        <meta-data\n            android:name=\"AAAA266\"\n            android:value=\"0698FCBD974F9CE55B0D664C747F07C66F3CBB850ABE1ED6970B90C3B4F3CBC2-C29E4C4863DFADC0A2673E0BFD94535760B422B1412F1B6EEF6159E7977F31D3\" />\n        <meta-data\n            android:name=\"AAAA267\"\n            android:value=\"090CD2F092B03947C502F0D01212183F6C15C6E8EAE747D0EFA2658926875E06-7D0310523776C7B2550BD41777AA3C695FEA0298E72440E7E2B24958DE051958\" />\n        <meta-data\n            android:name=\"AAAA268\"\n            android:value=\"3599DDAE62DC7B702462F8A24EBD255E36D8A73055E3BE5DC561EA5B8C113F5F-97D81E400BEC80F9B8C8AFE07DF07CCEA749B93FA3454C6097994572F6706E84\" />\n        <meta-data\n            android:name=\"AAAA269\"\n            android:value=\"E05B73F12128882B6F8BFAF5B0685C1D4B2ECFD12C9481EEA80F224381B28BE2-B2E6BC0C730B88AAFFBD5BF522F792DDA5C82F5FB814E5C3688C32670C28681E\" />\n        <meta-data\n            android:name=\"AAAA270\"\n            android:value=\"837059CEDB6C5AC7E28C25106834E1F6B4E9830E0FDF4D0D15537B1DB40C534B-0A5130AD88133E89175185F9E7B2271F00BDE40DCB7B4E0B4E91A72DB80AC9E8\" />\n        <meta-data\n            android:name=\"AAAA271\"\n            android:value=\"DFAEC7C8353783077F153BE3E05969C83E06655E3DA2608CACDEC90AA3BB9C27-918E39B4E77E4E1E03A7C0236C6F473037851069C67B5EBECF60E9B9744E4DC9\" />\n        <meta-data\n            android:name=\"AAAA272\"\n            android:value=\"38DBD337642B3AC5327CF7C6804ED43EA3591F8F343B09EA1BD1670158422B57-F245DB5CF9FB6C4EF69F1C248C0E8D78AA240CA5789919F81B26E2EA46928622\" />\n        <meta-data\n            android:name=\"AAAA273\"\n            android:value=\"086DD442E6BA1BC30F8AE36DF9042155C4EB73378D56F5F2FAFC73681165AC3F-3237DF49F466FD27A49160B0A1CFEE10FC46C1482A4658D0298251EF5A17FFBF\" />\n        <meta-data\n            android:name=\"AAAA274\"\n            android:value=\"0156618CA88BD54E4A07FF6D59F2CC4F62E45AC1C092892E03F217E3A782CF14-DEDC3488E9BFF68E5C5A60874EEA15E2B6B82C4696CEBBB98BB0F2630EFC624E\" />\n        <meta-data\n            android:name=\"AAAA275\"\n            android:value=\"C5444BC206B658E60030FCD4464E730BEA98E3CB15796E94A6485D6C578FF32F-F3CC2CAF0FA6A86DDE14C5E89DA21132F1619A9D95E68E9985F8048AB076E63D\" />\n        <meta-data\n            android:name=\"AAAA276\"\n            android:value=\"FC8E4C77D0EF4E194FC985A100F78E9C9356198D4A270E065FE7516857C04481-5F18DDCA47420841325ED54D1AF9484AF92F65AAC70A3B623C4E867F4EF71E20\" />\n        <meta-data\n            android:name=\"AAAA277\"\n            android:value=\"7218CC56B869343CE82195C6FE8F80D69F2AFD4F96146A4395E58D9DA2D3FD1D-CC1D24A853C20C11A05F75176A2640B1577F44D6BE6C17E39CF872C5B90909C4\" />\n        <meta-data\n            android:name=\"AAAA278\"\n            android:value=\"DFD34364E37373DFAB4470DD91373C29DF126FAD5A5E4D6871CAB3ABAFF6ABCA-93CB6133FE53FBFD8BAA027C64CF5E1717B7CB48E4526247C0FC6E2D0973F1AF\" />\n        <meta-data\n            android:name=\"AAAA279\"\n            android:value=\"EFC4770501004DBD95726BF9EE3A019000379C160BFC4077EB3B6F7330BEF778-E4151E382B51078CAA2E3E0C719A95DF1772E4CAF19496264833AB661D861265\" />\n        <meta-data\n            android:name=\"AAAA280\"\n            android:value=\"FDEA8FDC182F86C5A91E4132D7710543E335EEFF7C3086BA8F7AE22B1B6A80C9-F0CAD7AA153BC8DEAC667C1511D94E2C69A653BC58B0E07235F56F1626C7AA0F\" />\n        <meta-data\n            android:name=\"AAAA281\"\n            android:value=\"CF8397B4CA810DDBDADE6BEBEDF31E67F174EA734032D00F4FCC6D0618B5803B-C820DEB7C9BE7E93042AB41CE16D932FB6399F47B9C7106CDF0474918C1AE0CF\" />\n        <meta-data\n            android:name=\"AAAA282\"\n            android:value=\"99A74C4F70788CE458EF8DD56E4F1518359A923CFB6C0189ABDF119251591CF4-A020B5C50718081D508A0C60891FEFDE19C7460F6468E2515453488EDFB65C7D\" />\n        <meta-data\n            android:name=\"AAAA283\"\n            android:value=\"91863E66910E9E2EFC7125510627EDAA1FE68964F45E659C39C563EED85A519E-4739757E92238F11E7EBCBE843B2C7C556C73C2518FF7CB6B49ADB4F3795BB5C\" />\n        <meta-data\n            android:name=\"AAAA284\"\n            android:value=\"EA9ECF01966F2BA6D736A3EB54554B0E6226A0F27DE96C7331B174559E384EB8-EA6563A53467A6A65C2A66437045F2A6A583FC8F0AFF5868A9FAC26BCFEF5FC8\" />\n        <meta-data\n            android:name=\"AAAA285\"\n            android:value=\"8318BECB571F3384E9079AD322C1CCE7F87C765A905F54CA6F843634CD14B606-2F2A30DBDA6770FF3749F2852FA8C37A79C0BB932E8E5ADC1A7AA4521A18BA00\" />\n        <meta-data\n            android:name=\"AAAA286\"\n            android:value=\"CD8D93CEB97CFC15CB1F1B1333A22521A35FF87CDC8FC088E5505CB9306FA621-1588890BDCECB629FEE472F1FE759EC60B1BFF9FCD597B19974CCD52E0CE4571\" />\n        <meta-data\n            android:name=\"AAAA287\"\n            android:value=\"DB2BB5DF7B8C091EF9F98F7F05140A945D36AB6AAF42B53B5904C24B57C7A14B-F26C8F4DF391460F2184A050A8037E4B50D557C61A49584793117B9F947BA1D2\" />\n        <meta-data\n            android:name=\"AAAA288\"\n            android:value=\"F10F7B351A78431824013A41EA5993BD1D665C2B3E08B0D45AB5E5403A34DEFE-6E21A5F966A7252628CD8F5982D93086A0FCF76C09EDB9D7731964BB1C842897\" />\n        <meta-data\n            android:name=\"AAAA289\"\n            android:value=\"9F6E0E704D382BD1713EBAF1F2457F2E0243ED306470D1A4E2D8AE081F7493F0-F14A5B29DB5C181C119C3482B09EEA80751228869314E8149167A2E863219807\" />\n        <meta-data\n            android:name=\"AAAA290\"\n            android:value=\"4F680CF7175BE092C9E943910DD3C0088EAC428B956D912304526CE09179847D-3530AFEDF24E961533A7655C692B04AB2E1C42C5F535EA1CF7EC718265D820BE\" />\n        <meta-data\n            android:name=\"AAAA291\"\n            android:value=\"F5BEB9027AA1A1AFEDAAAAE15A3879B4B80263361447F508E73750C2A4A0741B-795187C8CA720B9850FC5E161B1DD04BFF68ACD5D9F0BF69D61E5A2201A65456\" />\n        <meta-data\n            android:name=\"AAAA292\"\n            android:value=\"583A6E7C00E50CC909D8565E74931CD74FCF95EF8A51197C5C83069DF8065775-BDC48B404A7042F2C0D1E43BCC22AD3F2656A74791AA9A1A3F5FAFD956387154\" />\n        <meta-data\n            android:name=\"AAAA293\"\n            android:value=\"A7244AAFF4A5EF5C8E3354CF6EB98EB27FA3C6BD0C89F5CBC518E76F145D8652-71749F884A9226018CC6433292CE8A1BE56EF0A2A4B22483C3A45174D48DA48C\" />\n        <meta-data\n            android:name=\"AAAA294\"\n            android:value=\"05BA85DACA61BD887E0915F17394836979160527DEF56128E079837281014A07-44D539844E7F832F442F3F26124855C1882599DF8D0EA177F3B22BB3797256CE\" />\n        <meta-data\n            android:name=\"AAAA295\"\n            android:value=\"40BB1ACCA465CE188DB08D25A5C8C03C02C7CF3A2B836F2FACD93D7E9D04C521-128F00CDBD8A4FB55F663129EC3DFA409C75DA65B76CB3ADD94E16285D67C837\" />\n        <meta-data\n            android:name=\"AAAA296\"\n            android:value=\"7DDA8CBBF094E5B5C664536F7BDFA20D0A8DC408129B3810BE4225F05B2ABF24-291A332525630F847F3BD4376F9359B3A3E04D4CE93C21AB79C4E62281EE2DF4\" />\n        <meta-data\n            android:name=\"AAAA297\"\n            android:value=\"40088D221A1F7893BFE9E5BC931B6AF3DAFFCA00D720D856924DB7CB2E3789E3-89C6BD769960BC4407C54836759FB6ED05A020192A04486B829B8B8BFF0E3EFA\" />\n        <meta-data\n            android:name=\"AAAA298\"\n            android:value=\"B32F81D6F9D3B006EAA5F454C4F73135D872C05443B94644C6D6B3650860CD9B-97279D277BF5D9A46F1759BF7065BAAF5ED045B49DD6DDE775D85C2B6B5D6D9D\" />\n        <meta-data\n            android:name=\"AAAA299\"\n            android:value=\"E3D1922482AA32C3F6E6B01A1444B78F0641B69FA03D60A0D18D00D823820C42-3EAAE68E19EC207838E7F02356B3C7379609323E9CD41390B3A9DB435A2403D3\" />\n        <meta-data\n            android:name=\"AAAA300\"\n            android:value=\"09494F981991C331817880501FD87CEA5C687897F1E822793E1F3A2E489E1B7A-D58B616A75DA66B942F9B680567DCC6E4219590C11471CE344281DCF91914DAC\" />\n        <meta-data\n            android:name=\"AAAA301\"\n            android:value=\"11D61B0BF87D167FE2625540AECDCF421D08095CF541EB47EE62866443B89D8C-A0794215278A567E887AF6CDE015A5E88414EF640F7DAB3855A3E779658BE778\" />\n        <meta-data\n            android:name=\"AAAA302\"\n            android:value=\"C83111FE1B7AB7295429624DA322CB0062FE0672CEC6BFC7470DEB7BC8202E7D-86A71B09ECB5C6DE705DC475C550DBC3A1AC4F4B93733F90197B131B92333E9A\" />\n        <meta-data\n            android:name=\"AAAA303\"\n            android:value=\"C9858F27CE9BCC04A5E32D195E792FC256D7DC53B8DC33A725122A4193B04F7C-910FF992723A6020D1231E2652ABC5BA44FB6B5492714CCEC8AF35A208B923BE\" />\n        <meta-data\n            android:name=\"AAAA304\"\n            android:value=\"2E5D0DF3CBBEEC21E58FA38689092058203349B5BABAAC57D086DDE6A452BA95-5335BC4961580B2E39CFE661355386636840686AD00B8DC16061D22236AA7D13\" />\n        <meta-data\n            android:name=\"AAAA305\"\n            android:value=\"ED90962973464962E18CF5CE404EB129A1EB1967BDA62C7A48DA6F8EB379DCF9-E875D322323250075C0C7327FD8092468EF4EFFC05199D83AED22F80CB3C81AD\" />\n        <meta-data\n            android:name=\"AAAA306\"\n            android:value=\"DAC1326F73271E2770523EA4B52812AC155B783ABB026DEA882B43898D87CF52-57BDBD1EE55EED3A84312B6BD17C4E515614B0DA5AAFEB1A30E20B4C2A8ACFB0\" />\n        <meta-data\n            android:name=\"AAAA307\"\n            android:value=\"3DD8C8EC2E4663527F9A10AE6B8A69E40C3FA0DCF528DF064AEC8733505147C7-7E0C67C34D0271E8C478DF49225F26688FB86B4995CD8A64F71C44BAD68A7871\" />\n        <meta-data\n            android:name=\"AAAA308\"\n            android:value=\"F5BEB9027AA1A1AFEDAAAAE15A3879B4B80263361447F508E73750C2A4A0741B-795187C8CA720B9850FC5E161B1DD04BFF68ACD5D9F0BF69D61E5A2201A65456\" />\n        <meta-data\n            android:name=\"AAAA309\"\n            android:value=\"6E1491E19B7E1CAED342EE20A5BBAC0889E3EEC24B466C6A27E9B9F542FEECAF-E8DEA651C0B725D43F516C6BCF81FBE0B03B0CA4C828DDA1AD8484DB532A34D9\" />\n        <meta-data\n            android:name=\"AAAA310\"\n            android:value=\"91FFF3F1CDD22F89965882D5CE058FAFF52C79EBD7E23B136AD02D2419A4A9C1-D78D7E121950FACDB06C013F185CB0096DEF94EB0E87D784A99D5E6AE03DCA2D\" />\n        <meta-data\n            android:name=\"AAAA311\"\n            android:value=\"E9B7F6A21008F5EBF193E4C88E0BBEBCF37E3B5255BE5DC2DA883A3C7D483308-B7E6D030A066683EC05EAAED8C775E22BF9D95FF9D422623A97407B336F3AD98\" />\n        <meta-data\n            android:name=\"AAAA312\"\n            android:value=\"F07171FC43CE72FAF9B706C1F3F1443346822DDCB6E350915FEA7FF42EDB2D4A-F079296502ED5DE8A6A6CA75A57E6D3F2C2A7E915CF9616AFF89A1A55FA8B748\" />\n        <meta-data\n            android:name=\"AAAA313\"\n            android:value=\"5708483712ED7089E068B18CC32DDF552BEA24B586FC1E3753AB8841A733FE09-0EE714717CFA5E40C727B4FA1EB4CF6D6834C1C44F1FFEBE5BBB8E2CC4FE43CE\" />\n        <meta-data\n            android:name=\"AAAA314\"\n            android:value=\"A6724C222DA55B5F14BF0D3B376ABCFD4607DCE83539AEDB9B3CF09E1BE1727C-1F3C6481453DFC5F41EDFEE201DDCE476AA0AA605F6D8E3259C252F46A0A092F\" />\n        <meta-data\n            android:name=\"AAAA315\"\n            android:value=\"F455B97D8F9C110BF977A0382BA1F0A7F729E65C12FF49201094C9DF92A279FE-46004C03971CFF284702A908324F89A20D537EEE1DE326EDC9B2A5F005F657C7\" />\n        <meta-data\n            android:name=\"AAAA316\"\n            android:value=\"0CF62E48DBAB09CDFA380F6585AF385C76171D3D3EC9E6761D883D033A51565A-E629AB0DC6DF219C8C868B8330D3A43D18D4BD64F6738C4600E883949E99FCE8\" />\n        <meta-data\n            android:name=\"AAAA317\"\n            android:value=\"37AF1D4B04B6AA253C3F50B68DB1CF5CDAD50380143AFD1A72D0317851C4191D-1948762AEA21E2539A5C2FB9CD78B79F1CA552C83039A847F30F3C34353C57B5\" />\n        <meta-data\n            android:name=\"AAAA318\"\n            android:value=\"B61976AC9914592F251DA78FA8A72AAD235B799744D842624A6813FD9A5D207A-79AF5C286ED654BA73442DE76668BD4FA7FC92ECC30031678BECA87C7F610070\" />\n        <meta-data\n            android:name=\"AAAA319\"\n            android:value=\"7180D177FD5D1B46672361AD3997F791BF20255F5BE3BAF0CBBA5B4E9B9A0C6F-3E1EFB8491CAD067937093A48C063758A2258414B46361FAFF494A08FA893058\" />\n        <meta-data\n            android:name=\"AAAA320\"\n            android:value=\"A11DF08C6B021323E43F6C688965D858504C832C778DDD46A6D3D84A0B7B5DCD-5CFE8CCC7B819C16B376EB51A796C48DC7E7A0213663316E169BF17C44A1A0C9\" />\n        <meta-data\n            android:name=\"AAAA321\"\n            android:value=\"E78B61869A23C686F6E4A0D066B0701E317DF8DBEF4610612C61C76A45AAC27D-4648132FA0A6F268717AA3D2436F750A63C5272A50E76DD7189591F83707DFEC\" />\n        <meta-data\n            android:name=\"AAAA322\"\n            android:value=\"7B93ABAEAA575F61A4CA127888F3AF2779C35721663EBD85F71AF215BF04045B-B7E74138840A120C05BD2B2AFE55003801D27AFB79656122EA36585AD29E1663\" />\n        <meta-data\n            android:name=\"AAAA323\"\n            android:value=\"04081AFC6B1616EBC5ED786FE752F2500135A7CF2551C99CC8B876D21ECC9DF4-5D6AFBF87F652AF04647ADA0DF634CF22370900B164B09D50BD23AA2CB5285B8\" />\n        <meta-data\n            android:name=\"AAAA324\"\n            android:value=\"AD9065ECCB1881F79F934B439E3D624DDE44E9A2A274EC4C226C7FEBB86830DD-518AC8BDAF0C767DEB31BAE1EBA826ADBEF793A68F22784CF3E19C67BA87ECB9\" />\n        <meta-data\n            android:name=\"AAAA325\"\n            android:value=\"6930AE1F0074878D213F694A6E8E384E94D9ADD6924B92B9CF850E1C7D95B8A5-E2B659AA0601A3BE1661B4A8D9A12FB46DF5531B8C4FD2EAB213D8AA7F792299\" />\n        <meta-data\n            android:name=\"AAAA326\"\n            android:value=\"5383C45D5D1959E935123CAF6642217A946D082F3923988451D2333645BCAFD3-F0FD6C5B410F25CB25C3B53346C8972FAE30F8EE7411DF910480AD6B2D60DB83\" />\n        <meta-data\n            android:name=\"AAAA327\"\n            android:value=\"AAB9DF37B9C175713DC769B8C2BC51CF7B328271DF135ED1F4DBD8A5B0A5E5D8-5EE87AD2883465B0B3F27E9F08D6CEB5AEA0400004027475A552D20C9CB563AF\" />\n        <meta-data\n            android:name=\"AAAA328\"\n            android:value=\"F34DBC713801A11BA78A5D94B5BFE73A1600519D0D4DA2D9734EEC18A046B9B9-8B33A6B6E9BD64E283BC348DE7741A383A3037D5629BFB89AA27C67DCF2DDC29\" />\n        <meta-data\n            android:name=\"AAAA329\"\n            android:value=\"E2682DA4914F1B6F1665707969A00092D9601B54190C89FB3A9DF04E1AF99A05-8E1B9F03B6BB5AFA74D8EF6F8E9B9F84376F9A7B1B1FF82926CCF9ED75090203\" />\n        <meta-data\n            android:name=\"AAAA330\"\n            android:value=\"B054CCEB860F6BB4D01DC9531B886306163331A57B9766F7D17B9BDB6C8DF204-542217A5D8124A45277E54335632133AFB793095D4345B32A5267C73F9E58DC1\" />\n        <meta-data\n            android:name=\"AAAA331\"\n            android:value=\"ED83C02B63D40B37EB3A966E3731EAA122D1B471FE580A4B5009CEDC470CD803-159DA62821C72BF902831222A51904CB2B6B4A318E41117427FDC57B269D47F1\" />\n        <meta-data\n            android:name=\"AAAA332\"\n            android:value=\"C9E0ED6BC98053A0CE7DBA87798858BF73D5F87DDC715FB25FFAE54BE4A35F97-A2DF886080888151CD0F34FA6169829334D11567E776CBB4D12D37E9EF66B411\" />\n        <meta-data\n            android:name=\"AAAA333\"\n            android:value=\"ACFF1C2DA07C734AE6FFA0F264132805248128B3565542D0CB1905C3AF7AF293-39DA88E21CC0F847800255578603E87BD85DBA6EE9DE7F5C3F084C9611A8DD1E\" />\n        <meta-data\n            android:name=\"AAAA334\"\n            android:value=\"FABCF798C6AADD5F4BF3B8E52551CE9EEE4D2CEB2B962BF330469C6BB29F31C4-3AF87F239AA9F009E6AA1F8F65A5E637B839DD05AF0331A0FE25468128629EF9\" />\n        <meta-data\n            android:name=\"AAAA335\"\n            android:value=\"02A7C21988714E29CF39E521C6B93DA541BBA2953306C31490A73614ACBE7876-0C7AC3D341FE1ADBD8B9D68AC2E5C5A0416B3D5491EE0E536F24C26ECB6E6B02\" />\n        <meta-data\n            android:name=\"AAAA336\"\n            android:value=\"721F44C0A3B2228B31B4E9E1C2F9D5549AFE263AEC5F516B9A8DC4C1AE2FD3EB-8575D97A796E08F9FE8887C3D83AB78C5275BA4A691494ED47F566ABDAC5E495\" />\n        <meta-data\n            android:name=\"AAAA337\"\n            android:value=\"A6CF01A8072B575CE2C41857260D2330906FB43D8034961DF227DAD2CC0102B6-001C7F39CE94F7D5D8A675F089ACEE3CC27EACA3CD543CFB64066876D492B8F9\" />\n        <meta-data\n            android:name=\"AAAA338\"\n            android:value=\"081A41E6C7BF0ED942CD4959343EE0B522411C2BCA81A8ABB85B56EB8B47D69E-7CE04DA7773D41B489F4693A366C36BCD0A11FC39B547168553C285BD7348E23\" />\n        <meta-data\n            android:name=\"AAAA339\"\n            android:value=\"26A22B01FEC40A9DEF0BD3DC580858973DDC7E839E2645449F2D64FA6C678B91-C802F28ADCFBFDC90AC5C967E47831AE1A12520C2A405B423C7D9184C98E8F9F\" />\n        <meta-data\n            android:name=\"AAAA340\"\n            android:value=\"0733E95DE7DB4A7B25D4221CDAFE7020D3CE75F16BB874A2E211E4941B1F3FC0-6EF8BD6C189C4A50412E91F5527E832EA1C8D0BF501714A4936A9ED2AEB3DBFE\" />\n        <meta-data\n            android:name=\"AAAA341\"\n            android:value=\"41242198A420516DC8A055C7F4549444366311130EA481B6D098C2F7213909A0-17593556EEA0F43B6F8C0C293C4DB062702EC2F8B66A070023187F61B3E44C7A\" />\n        <meta-data\n            android:name=\"AAAA342\"\n            android:value=\"FE82CDB583E7BC898EEA6F37789C464A9C1D69005667A8E640263CC6BB32B38E-B7FD57DD2B92D735CD5E84F2BD9D4467CDC6AEFBC2D527FCE06AC78A42594251\" />\n        <meta-data\n            android:name=\"AAAA343\"\n            android:value=\"D2FF1CB902074992E2CB7F2D2F3826619DBBD26FDBD0A6BC1AAF31B457654C43-70B13A5CAB9E722BB9168CF2BCBC7D95133EC22F6128D11956FAB397370EBB51\" />\n        <meta-data\n            android:name=\"AAAA344\"\n            android:value=\"9D98727C4276E9093766E691BA5E16B1165F0D8784515A702F622B1AE1DFBE03-273A3A5E09DC720D3B3945162E724D9A69B21FC542BED7457F115966B145E8BC\" />\n        <meta-data\n            android:name=\"AAAA345\"\n            android:value=\"656FB83A02FF85DFD8789760F7DD24095D9491F60273545FE2D81A9AF3F7906D-11D5525D76147B28FC6D974ABC56710576CF14A7CE78CF8E75FD8A67E312CEC0\" />\n        <meta-data\n            android:name=\"AAAA346\"\n            android:value=\"CDF21F64A3DD59078280AC39AD8F9AB14AAAAE0C1907FD749FFB72FAAACB97AE-5E30146C3BDF327D29CFDBD0791B8A697A635C847D1D1FA58CE6A8EB6635778E\" />\n        <meta-data\n            android:name=\"AAAA347\"\n            android:value=\"CB3E17943850E7C1D573BA532FF55AF0BE6BE8CC6FEE60C33919B31E196838CC-DA9D411D1CD94B5B89C1077C5A9A5AE4170268228AB7266040076123F1369F27\" />\n        <meta-data\n            android:name=\"AAAA348\"\n            android:value=\"1CF1AA02E062A579B92EEB09412A79D8798DE8F123F90002A278C120FD1ECF22-595BCEA074D4EBAA71F1DA72018363F2D786DF227A90BB601834C86B6A72F09D\" />\n        <meta-data\n            android:name=\"AAAA349\"\n            android:value=\"17632E7990BC7D8154AA6DB4E5EE74DCC1D6CD85671A9CCC3AAF817707BA1155-00599677477660BD253C27950B822CF6DED6B2FC7301450F6FC972060C697BC5\" />\n        <meta-data\n            android:name=\"AAAA350\"\n            android:value=\"9FAE3AA691C006D1A4BFF98A1773BDF4854A17E8540B8C716E1A002C57F2226E-A1208337C3ADDA733DCBC1E66B6773370BA2C6C2035CC888455355D233864461\" />\n        <meta-data\n            android:name=\"AAAA351\"\n            android:value=\"DEDB22F5A02F9069EF75F6A96414188EEA3F6E7172B83EE3F1112622D469F198-3AF87F239AA9F009E6AA1F8F65A5E637B839DD05AF0331A0FE25468128629EF9\" />\n        <meta-data\n            android:name=\"AAAA352\"\n            android:value=\"61A368913F6244F61D2C4391A99E19AF7E02C52709402778E4CE6B1F21BC94A3-9FE45917151254A3252CA811086710DB22DCAD818D441DCD599850D296CCC62F\" />\n        <meta-data\n            android:name=\"AAAA353\"\n            android:value=\"C26CE0732FDE4AC0EEEADABA9B1C72027BC06FEFF5828D049004D77ABE338BAD-613870E86821F10EC9E468AEB35FBD8821558CC9719641CAAFB57302F2130F11\" />\n        <meta-data\n            android:name=\"AAAA354\"\n            android:value=\"9AB5209A64DDD041D29E8D25FF018302E6F83F34672B0DE8501C45B9E07F09D2-04F72548E2CF2A99DAB5E2AB2B26084D9746761E9230FAAB391420BB7032C5A8\" />\n        <meta-data\n            android:name=\"AAAA355\"\n            android:value=\"9DFFABFE89A149A6E585F5EFA26099FCAFCB9125F025FEE180175E6F2A63CEDF-B85B145640DBB5078B1CDA3241168B3EE7D6401284ECB784E272681C73F5DACB\" />\n        <meta-data\n            android:name=\"AAAA356\"\n            android:value=\"8476A6C66064958B08FC11E186525880DD47ABAD894F7B2F1F493A779D6293E7-1CE2CF89B42C2C404C4A1F8C29E28FFCE8FD1078BDA50955D7CA76FE4D5C5DEA\" />\n        <meta-data\n            android:name=\"AAAA357\"\n            android:value=\"73E92D79633B20C9C6C93F16FD1560E5F1A53D197D90CF62FAE249BC2EE1F2DF-7B0AA491D03A33329E4F9F71520CE79E8DDF8A0E6569B5CBDF16A24521B00ED4\" />\n        <meta-data\n            android:name=\"AAAA358\"\n            android:value=\"58699B0A1B3D9E18BDE1072FF9C07D7E0BCD4603FC94AD910A99EBB035E6C998-5287FB11A7B7E692D37D3C81B2C42A26A73ED7E0551B8F23E3633B74E2890845\" />\n        <meta-data\n            android:name=\"AAAA359\"\n            android:value=\"E736063D4B1BB20D5967FD6DDB84804C0760FD2122994E88DBFE5FD61B577E16-CB74AFFE259F210455800955A1058DCAC3A3FF69ABD5CBE801CD6E2A31003BD7\" />\n        <meta-data\n            android:name=\"AAAA360\"\n            android:value=\"3FF85AC04CC4CC03C6A0FA8FE89BCC654C8D5C9767B27D966CD6231C3E403C60-813FF740A3DABBE7AA144B355A2C22A4442F1D0CA8B97DE47570CCF79D407E60\" />\n        <meta-data\n            android:name=\"AAAA361\"\n            android:value=\"8536F3D207A9C2D4981E88F415C453C4D58CF49399C340F5AED23F8286896CE9-BCDFCD17AA3A3DEAEBB79B503B1C7D011BA13F8EBA721C89FE8F47EFE52F41CD\" />\n        <meta-data\n            android:name=\"AAAA362\"\n            android:value=\"A8954FBDB3BC1B4EB74E0681939C1ECFD59C66C4718BEE1B86F650551856A7E8-0D5D416B09DB8934FC6F25EB7692B240A1AB9F13C6C52CFEB30684A63009C3E6\" />\n        <meta-data\n            android:name=\"AAAA363\"\n            android:value=\"CE2510BF9142514E47AE15803ED06EC6B8E9C65E76013166DA43962D7093B064-7D52FE4B542F3D5CD01FF1F28D205F54A1B848E9A14DF8228DBAC6A5E3B172FC\" />\n        <meta-data\n            android:name=\"AAAA364\"\n            android:value=\"A5BDBAEBCCC1F45C3410B5099FA01DB2AA1F4A0569DE6956A5CCE6B0C8DC2875-6B88F4B7FFF0BE2B32744FAE23D043E82F14A188E5F338F9858537A54F26A197\" />\n        <meta-data\n            android:name=\"AAAA365\"\n            android:value=\"41F8DCBA52B7304A72AFD73F0EF5C6C6B3181BD3BE7290FE3AC8ABEDE4724EC8-278CFCA85F9B5DB753CF20D64EC526C1289EE84392983BC944155DADBB4CAACE\" />\n        <meta-data\n            android:name=\"AAAA366\"\n            android:value=\"A76BEECDEE678C8E6164CCF623FF180040FA577AD63119CD784EA21202F82260-06CEDE031CD36C1986928FB5A9339C859253C07E06AFF6137503D8385D3291B5\" />\n        <meta-data\n            android:name=\"AAAA367\"\n            android:value=\"80AB3B6E5B60D80E0148320D830697E5C349E49724ACD5876142CAC6967AD421-D1D5B3FEA0452AA7DF2C4EBC5A3A17E0601F3B80C63C4F9A7A1980D3CD1378EF\" />\n        <meta-data\n            android:name=\"AAAA368\"\n            android:value=\"E2628B554819079A93EA9AF94AA36F03355A7BC2B79FD6E38519AB81C6990AE4-AA57A28DBFBBA8C8043F44B4274310C22B4B8C3C8C176EBCD88B50DDB084A917\" />\n        <meta-data\n            android:name=\"AAAA369\"\n            android:value=\"F290A0AC84E90ECA1BABF220F7E13EE6423F27323842C35E24CE1F53CA6A00F4-4E6A16B9CB3300731A311C48D6D176D1026BF40DE28B8138A37446057DD665F3\" />\n        <meta-data\n            android:name=\"AAAA370\"\n            android:value=\"72060DF463D9A8DBC6418B09837918CE95743E1EFDFEDE9FFEC504B61E674449-B3DADD33C7853D17D916D065AE1E2605DF7216F1999DB9D1766FCB9DA6B89ED1\" />\n        <meta-data\n            android:name=\"AAAA371\"\n            android:value=\"5467507B34FCFEC9E387F47E6AFE380C1852FE6F3BA5939333ECD2F70024EBB8-998DC9B0BB751EC134F4248DF58FC5FA930BDD19E61194E5930E4263FD3BD5AA\" />\n        <meta-data\n            android:name=\"AAAA372\"\n            android:value=\"5996C0EFC8A97179E3594A4034369D7EE3D91F54309B34F225DA678206322462-698733D304F954DC07068AA0734A81BB221D21159F04EA82E3D7179BE7ED5543\" />\n        <meta-data\n            android:name=\"AAAA373\"\n            android:value=\"B5ABE914217B715DF62E37544BC4B7E78DD1E675908C309100683FE9AE74D1B5-C152034E61B47E00C0097A35021435D582890E56D80D21F5F3FD3E0A13B2B851\" />\n        <meta-data\n            android:name=\"AAAA374\"\n            android:value=\"A5571DACF803D1030E16B02B3A404F9EC8F9A8F1ADE175EB6DE5826699D0E01E-8459FF691935B87E786D6CE82DAFBB5352ACDB6C074B187E6C9293577265ED7E\" />\n        <meta-data\n            android:name=\"AAAA375\"\n            android:value=\"4E9774A507ECDB1430D29E9985606B9D03C53FC34DFC0CFC7792F6D3DEA94451-5B535964CCF4F670A740D9E475E6B01BE93BE97E17903CC5A9FD6ACAEB7F2AEB\" />\n        <meta-data\n            android:name=\"AAAA376\"\n            android:value=\"45E2C66310A94DF02B730C2FF177E5D5C33C89D405C4829A958D5DB66FD1F908-408979ED08B1FD4AFE11FD3BD2125788376491776A2A579A1D8E18DFFB483213\" />\n        <meta-data\n            android:name=\"AAAA377\"\n            android:value=\"98374C10458DC66551957BDEC95786B6D656B5C7017102DDF56B14E0C2066F1B-F31D80836A33E72A3782B0FE0A9164304C2561ACB07897153890E9BB4452A461\" />\n        <meta-data\n            android:name=\"AAAA378\"\n            android:value=\"A0DFA650F1FE078AC9C08513A55C4CDC0E7F549C1D1EB33BC23819FE1E26CA0B-605E044CA7ECD19187B16FA6A47C71D2F44F8C38B35F03F14BFF4D41FBC4685A\" />\n        <meta-data\n            android:name=\"AAAA379\"\n            android:value=\"1CDCACA5D1CA0CBBCDA6212BD7D76D4A9DC189E5B16E8A4F12B56EB8DDFF0E2B-9A0889144A1985AFE861114572C4935C4CC7566678C862CFD2E115B9CD5B7709\" />\n        <meta-data\n            android:name=\"AAAA380\"\n            android:value=\"94A117FBD39111BEB6B47ED083922444E200A08834166BC2087AAD4D12FA8D5F-0E91448B94B9FD1C223516A748FB2BF7B43D66292789FA8CBE94F0287F45D4D4\" />\n        <meta-data\n            android:name=\"AAAA381\"\n            android:value=\"B20A7B5A57B1BBB5E203FE4E51F2F4F1F442903A07CF282D61F62E84EF5ACE39-2D1D329731C63BF2583777D237D0991982B052592D33505272C2F8F083A4D1E1\" />\n        <meta-data\n            android:name=\"AAAA382\"\n            android:value=\"8D6B75A81C1C59EA9ADE55A56DED9639209BCFA017CD4C966F3DC6093B332E49-D50671FABB867BA9BE213E61F615B1C4C5E1F4A822B75B50C54130DD35056B50\" />\n        <meta-data\n            android:name=\"AAAA383\"\n            android:value=\"07EB79E951F908CB210CABFD26B3392AAA4496C79053E43C0685A18588C285D3-931D969502F3DE01A4C239E4199211EBDC57BB9A7526394B9E3E2D1CC079FF0C\" />\n        <meta-data\n            android:name=\"AAAA384\"\n            android:value=\"2A9FB7F2B79658358BE76CA7403D40528C7949979A2F2B2DCCF54D3A5EF9420F-B6DD0562256487FCD6C98CDE137858EF50D9ADB9F9CD2F1CA58C5357EFDF0FAF\" />\n        <meta-data\n            android:name=\"AAAA385\"\n            android:value=\"421A158311D707987EFBF337DDA892D47734FA61ACAECEABF22C68A4F0757B9F-453D87E749EBDCEC5122F4997B60D98A5564260FFA1D245FF02CC06F52C2A748\" />\n        <meta-data\n            android:name=\"AAAA386\"\n            android:value=\"F97832F13D819A681CE1C44DD8E721CE05E551ABEFCD4A6BF0EAA352AC212935-1448DC9480A27E52B06C886B3F6386F2B122B115B1DF1F156B81B9AEBCC73163\" />\n        <meta-data\n            android:name=\"AAAA387\"\n            android:value=\"4C3DB985C41D63CDD80064B80433A410ADE60AE2DA80BE12DB0A4EAF02CF0D8B-594485A7C4AD16860BF32C08A4BA8C2CAE5EDD761D8E2D899DD4F7D3971FFD19\" />\n        <meta-data\n            android:name=\"AAAA388\"\n            android:value=\"F7C7410F0706E5CC6887B25E8956CA5679C5B0AB02DBF5FD022F160258F73B48-112FD126B77D9C0AA09D6B01CD7AA4FD6C32A8DB3A4E173B5CEB4C553B418FE1\" />\n        <meta-data\n            android:name=\"AAAA389\"\n            android:value=\"F3E45581D2F04025073D0335E965C1C74CE221BF5DC087D47AA010E228956B6D-A6EF817BFD6C083442A149856E51036F6912C2DB6B6009DB8127CDD641E295A9\" />\n        <meta-data\n            android:name=\"AAAA390\"\n            android:value=\"06CDADC790665967BE6B2309BE224DE7AE6467FC15C0AC0143C363316D1D7A3A-5E38142F3DAF425BF19C0CC556112AB2B4D2EF1D669BEE1797BA9C4391AC76FC\" />\n        <meta-data\n            android:name=\"AAAA391\"\n            android:value=\"1907E9E9A6DAAD986761D5D753ADA17E2D9B7227E16C5501D6DE534129BEC1A1-0709BCD4DF38756F3079F62CE44AC91A561B45D3626A79923B04806638E7238F\" />\n        <meta-data\n            android:name=\"AAAA392\"\n            android:value=\"4AB452A5AAA91926AB9BCE97C238AFED04F758BE5885014E5E26C516BED1EEBB-149EFCD0EAF6E30467BEF381DC67F2848F6DBC8599791712DEBA26F17FABFF2B\" />\n        <meta-data\n            android:name=\"AAAA393\"\n            android:value=\"E429DBF162EBB10171AA0081D88D8969A7CD246DCDD8462CC37ABAF5045E23F8-0206ECF0B94FBBA05B5C0CEEE9BADDEE061769CEB1A7FE22EE1722B8301C733D\" />\n        <meta-data\n            android:name=\"AAAA394\"\n            android:value=\"EF45688C330DCD21F41EFCDDAC2E299A9250772ED2D59741F179BC21C005DAC7-384B13CBC6D4F90EBFF9D93C6EBF6E80BBA7BF5134278D567E938119CBF163D5\" />\n        <meta-data\n            android:name=\"AAAA395\"\n            android:value=\"0AEABBEB9905229F78867812292868E0CB735C5D7FE2210EA225C5C746893593-1B24D60D3872512EA51059095B75A707D308D517F0D3A66731EC0E3607677C1B\" />\n        <meta-data\n            android:name=\"AAAA396\"\n            android:value=\"6245157AF4C982DDB8D7C5128D140C673B89DCA986CED21158163B9DAFE9A2CE-AD74088777CEAC9C21C2CA81C36B3B8DAF7559DA64CAF93A327C43B787D1F730\" />\n        <meta-data\n            android:name=\"AAAA397\"\n            android:value=\"7520292D73A8467A3CBBD63CDEE1D13FDFE84AD48C03517602A5438BEC2DC015-B048EB71CFED40FA5979AE74DFDBC7750019FA87543EC899DE4EC2ED672BA582\" />\n        <meta-data\n            android:name=\"AAAA398\"\n            android:value=\"C29CDD8C6AEF40A033EBB684E1A144ACE6115E0DAC031980B9B1A63DA5A37D07-C6092DA3EBB4E1589DA8FAB64DFADDB5E19FE2A96CDFFCC134E9A0469B53779A\" />\n        <meta-data\n            android:name=\"AAAA399\"\n            android:value=\"FA79321D9BE6E153FA741E8F75C9A7A7598A4D4DB018035452AFCDA674B2368D-2E46D54576F4199AB6728A311001E10BAB4E6D98BF2C161B1112D0BCED7EDDA9\" />\n        <meta-data\n            android:name=\"AAAA400\"\n            android:value=\"4A9EB23CEC32A0B31324D2F7AFD98B8B8B2D841E603BF22AD0D92662AECB4DE9-7CFE4069C83914A002BFBBCB0541B50EB5137411426FE094CAE526FA77C030E8\" />\n        <meta-data\n            android:name=\"AAAA401\"\n            android:value=\"43AFFBCA7B55B0A3A59DF1DED75BB6FE245AA834DEDBACB68F5DC9A43EF9B9D4-03BD153DE7230800663090D52320EEEBDD5DEE1006AF8E77D73ED1A11B41DC0B\" />\n        <meta-data\n            android:name=\"AAAA402\"\n            android:value=\"7EA074DEEB09844C7FE2F9884D8E873C8CC0D268C8D46A77B2A2292D7122F62B-5D2EC7845DF1F3E921A3888E9C040874FEFF9B852C6D12A068402BD47697C277\" />\n        <meta-data\n            android:name=\"AAAA403\"\n            android:value=\"1376D5E12BA28D83B5FFF79E03AEE6FB6A2B88B5D633D533B702825D2E91CBE7-382497AA856F5C984C23BCE9A97F4DBCD442F1E39F46A92CA78B23C82CAAEA58\" />\n        <meta-data\n            android:name=\"AAAA404\"\n            android:value=\"E197F7033A5B4BC8F55FA495C8337781EE7A307FB3DAFC984405017FA5A9F081-D2B9D6FD8712B2427199302284D2F1889498C6B61BF6B2EF2CAC730CC09D05A8\" />\n        <meta-data\n            android:name=\"AAAA405\"\n            android:value=\"95C6FD18CF82504801CD574E0A4D9FAB948F8DA278002C6152FB5F01452047D2-BA61B99044C837A8DD334A1B1B271AB8CB286A5765BC777E72B1F7AEEDA11DCC\" />\n        <meta-data\n            android:name=\"AAAA406\"\n            android:value=\"5F0C17EBB924C8AD19F8020F8BB98742C4EF202F4D64468B70BE538BF6F12EC5-CF436094469CA08FCB5C950597E90351400AC733ECBA4071F194DCCEBAAE4CA8\" />\n        <meta-data\n            android:name=\"AAAA407\"\n            android:value=\"A083EE50DF80205A98730EAE0E14E4998DF84B68145F5F9DA03C26E8C0D9A576-01ADDFD0A571DD457D3037111121AA382EE95DE3CFF99DD766B9BABFD96480ED\" />\n        <meta-data\n            android:name=\"AAAA408\"\n            android:value=\"F0126B46210D2AC5C65451D1797D608368814C44A52ADEDE4C82539CBECA7273-D65C23979815B1FDDE2B71DBDE72A62B5DE44D234A762657AF130E68C10E7A7B\" />\n        <meta-data\n            android:name=\"AAAA409\"\n            android:value=\"AC8C2934EDD94694E60B20FA2A2D7C3BB9A0E2663B6760C4A35CD19FFD62DFBA-C8D7E1D0DC5E416328CB35F5829DC6077A268379BAA83B29A8E59EC4B1FB4162\" />\n        <meta-data\n            android:name=\"AAAA410\"\n            android:value=\"4DC7CBC643661184C7BA551C4E3FF30EA2DD4345849D6BC1CE7E933172A0B8A3-13A67059EBCE772C1F8775E2CE909AF4519D8FAD651C2E991525311B85370047\" />\n        <meta-data\n            android:name=\"AAAA411\"\n            android:value=\"4AE63910CACB0D7AF836B850F6D84120F916BF0531738E0748036121F27D1DC7-BF082C278858C0386BD3A72CA4ED231B341FF8ED12CC8C3A623614252997A12C\" />\n        <meta-data\n            android:name=\"AAAA412\"\n            android:value=\"44993E8942A8C33A9E7866B05E93F774A6B30ED8544D7A4B5BE9FB5FBF576AC2-72EB163CB23338FB0687F2E13FB46D7CCD08191B459BE8632E8C495B1ADF7DAB\" />\n        <meta-data\n            android:name=\"AAAA413\"\n            android:value=\"E84904A41A86B81DD4E17E9A9B2BD24B33BE10E6934F5E4B76AF48B74D10D817-C8E5C9AFBF84953903D8F203FECA5C0EA6C322E3DE10E5D2073B9EAA347938D7\" />\n        <meta-data\n            android:name=\"AAAA414\"\n            android:value=\"908651FD1672D12F30F223AAFC3A8FA40E4D7E950027AAF4E09E3B03787D8C53-00EC7667A33F0AC91316F9B40CAEAD707BD5B39DFA63FDD909BB9AA25A7B6CE4\" />\n        <meta-data\n            android:name=\"AAAA415\"\n            android:value=\"C7A63657B42A11AF5A1EADA67EA22281C24F0D917AF52B7F125B5774191555DB-3527AB687E646106B3BDC6EC6E1FE0C55BF7D71A9EFE6B331AB2C110732F1229\" />\n        <meta-data\n            android:name=\"AAAA416\"\n            android:value=\"FA8D85ADAE0A276D17E26B8EFC274778F38D2D9F3C3FECDFE86F06478F77BA5C-E3F9E1E0CF99D0E56A055BA65E241B3399F7CEA524326B0CDD6EC1327ED0FDC1\" />\n        <meta-data\n            android:name=\"AAAA417\"\n            android:value=\"2F1C1C7DE56EC590A4CA78B1B6E2E3DD319361D28CCC252C2E9AE7FE27CC1E04-B031FE98A4DBB0D4D82661787F25DE643182B378E9EF632D8ADEA75AAB58F2D8\" />\n        <meta-data\n            android:name=\"AAAA418\"\n            android:value=\"38071CE84355BE4E5FEF5F0E5C2D99AF4C88721ACFA1476B0FA071041210A24B-55B50B38BBE8C8787249DFC6C073E0B26EAAC000038C33BCF329C88A9C8985D5\" />\n        <meta-data\n            android:name=\"AAAA419\"\n            android:value=\"60A414C3F2ADD6B8B9252F45DAA2E8DDA186954404E56309B8DF3C5F1A016978-9C3624E919D0F9A39F99A6871946AF14C6746A290CAD2747072A71F3741FA83F\" />\n        <meta-data\n            android:name=\"AAAA420\"\n            android:value=\"5C11C0F4A3590510062C08777CC57674DD0D0DCA128A36CF4CD73660A25FC040-F0E548F9BA2648E965DE95F2E13A557D0226A0B2EB95BB02268CD7210B0BD04E\" />\n        <meta-data\n            android:name=\"AAAA421\"\n            android:value=\"11E9C6721B3AA0B60742570A309CF4EDD4FAE59A73D7B58C292534290BF968B7-7447411E29DEFD2A0F3165493AD7858A0F15B4A4A41B7A7A5AA8D7B84230BAC9\" />\n        <meta-data\n            android:name=\"AAAA422\"\n            android:value=\"A972EA600C9A8C6B47AB340D210B4E0BBE084C0BCD20219451D41392F34E767F-2446B1227C5B236DD4E50F892A41F696ADB3BD022E660832FA0EF3053130B43C\" />\n        <meta-data\n            android:name=\"AAAA423\"\n            android:value=\"973483E9E505F521B919092B3114E4847C1813D029C147D2FA564207DA94CCC0-53FE8A984AE0414FB33209AECC919B270CF2D76BD34A511B088A50A771F257CD\" />\n        <meta-data\n            android:name=\"AAAA424\"\n            android:value=\"19D2AFFC291D37FF9E06215505200ADC27AB22589E282BF23C2CBEF5AC424638-4FFD7261F316931206B76966FEF4102B98F95D7A0B6E82D576DBA238A9838B4C\" />\n        <meta-data\n            android:name=\"AAAA425\"\n            android:value=\"E6A8389F24057F987F36BC7B28209C82C734C7C6081601386C5329EEF32C5BE3-FF571F48D61B0606337EF9E74BEA044EFA3AC8A93D0CD36BA1D688D354371746\" />\n        <meta-data\n            android:name=\"AAAA426\"\n            android:value=\"1D28741C6472902E13AB5DAD81497368485946FE031036B84D2E0CD8DBF360E6-956D852F9A539C96D49B1F1FE862E9EBBF7FB89C2ADC16ECDE9402F6739FA81B\" />\n        <meta-data\n            android:name=\"AAAA427\"\n            android:value=\"658D4BE81177B34790C080DCC3FDD068C50381435A633845DF3AD8679D1E13CD-1978E026DA201CAB6F7C610FEF9C609B41F0F7B391F7FCF0F9CB61F4158A12BE\" />\n        <meta-data\n            android:name=\"AAAA428\"\n            android:value=\"E237EB2CB5EC2C4DCEC9DBEAF76BC305A563895EDF93481803103756AC562B99-FB7F109C81CB8956D6A9E744930A8FAF704E71830504E7D34DCF0C075A91C2D9\" />\n        <meta-data\n            android:name=\"AAAA429\"\n            android:value=\"8ECD716914FE525C80A16D82501D9F5DC0B725641BCA01491214CAF0C82F494E-75ADC746C56D84C54B1F9ACC674E8C0069A9401168775FD93DC21B364DBBE035\" />\n        <meta-data\n            android:name=\"AAAA430\"\n            android:value=\"F1E76AA3B309B783666BDB4D18813BFCF7E1FF5B4922582267ACD41A6A00F350-F08FB498B1840A4DDB276292B98BC25EC81F2D4D0343060629E840C69FF5A5ED\" />\n        <meta-data\n            android:name=\"AAAA431\"\n            android:value=\"192EAD87426A57821B0AE73648B9AE3A119BDF4D02A1D81D739DBDA4433F688A-9F5B5908DEC86CC3DD8AC01A29871FAC54349A60DC3EEDCA1610E426358F721B\" />\n        <meta-data\n            android:name=\"AAAA432\"\n            android:value=\"75F451F1EAD2510E8B99B88DB4A2DE2A41B3C703B45A462651C9A48600C680C7-EC0AFD48113A05A9125D17B64A582E868D4C705DA045AA60381FC3D0DDE22547\" />\n        <meta-data\n            android:name=\"AAAA433\"\n            android:value=\"A88AC588D84CCA9D950D998E5EC666CCF05F164F14DE3E5284F4CAE3C7B37649-72B001B20DBB893DA8B0483CD8E6EC531164A7914A8925E3416C89C9238D613C\" />\n        <meta-data\n            android:name=\"AAAA434\"\n            android:value=\"E215C71F4C5E21A85E293CCBB1B88D17B6C130D771E7E1D247AF609CA23C53B5-C2D1BAAF9C1FACA112E21D639D270B5FEAEF4C46022E87B2BA836826DFCBA27A\" />\n        <meta-data\n            android:name=\"AAAA435\"\n            android:value=\"EF77033E8D6F2A70394218AACEAF602F75EE52BF94A3E98021BF05806B783600-4003231AB42FEB8D955E62FDFAA4FAD59567054B9C6BBC3D950299DDFC268392\" />\n        <meta-data\n            android:name=\"AAAA436\"\n            android:value=\"5194503FF269516D83ADA80FB7D7D715783E56A9D7F9C57FB7E0D747A9B4FE9C-2F08A50B4A6B143B8E203B3E7FFBEAA1B92C9D260A8CD6253BCB0941EE8BCC48\" />\n        <meta-data\n            android:name=\"AAAA437\"\n            android:value=\"05BDB9AECF23BACE7B706E1E58E4222869851DFE39763D96B124ED7AA49DB2F1-2692EFE19902450EF7F633E873D4E376F04EB18ADFAD5C29F535CD56DA5682A0\" />\n        <meta-data\n            android:name=\"AAAA438\"\n            android:value=\"47F477C552A83582AFC27E6F915242F62FCD85B10B944B2B7A824C99D6C6936B-52C7A0CCB360284BEDA8E25B8A807CA689B07426093435516B53FFA37E8CD13F\" />\n        <meta-data\n            android:name=\"AAAA439\"\n            android:value=\"E12EEB78C7F125F733AF3B1BC7092927F2A8071A67C0E9E911036B0742CF302C-80CE5216071FAEFB17F5E82A1C79841C864DB02645A8A058AE7FC25EFF317EC9\" />\n        <meta-data\n            android:name=\"AAAA440\"\n            android:value=\"122C854995FECA3A9AA7B27A4BD34058A1A7CA41096D9AE610901062CCA86BBD-1233FF6DE4C70EF4D7DEAE54AF15B167FC7CFD2539517BD2175870F3CB771731\" />\n        <meta-data\n            android:name=\"AAAA441\"\n            android:value=\"C82E4D90EEB781FD1AA0A20C3E684F21A5B100C8E9B1E392B86175F4E3933888-2265E9019D3E0AFC1A05531D14F4FF5346A323F7EDD1F7221671B764C0CC1BAB\" />\n        <meta-data\n            android:name=\"AAAA442\"\n            android:value=\"6562492523398CDAC082B24D9B852E80F798923F6F885748834B0C9B0AF17543-B312A83195920E6731A09A4BEAB5E6D8B3029417C9444623DCA6AB5BB20B432E\" />\n        <meta-data\n            android:name=\"AAAA443\"\n            android:value=\"5F6F85A2258CE84E9958D57D018C28F657CB651C140CFED65DC4113FBAEA2693-7C34EB3CFBDA05FAF56E8890A2ABBAC14B3036E6E4358849B98E8819B6B7B329\" />\n        <meta-data\n            android:name=\"AAAA444\"\n            android:value=\"C12A0CB4D73686B5031303F6076D181E1F6742C89045E7EF0B5E4C9553E624B1-10AB0A12CC0100BCB893FDBC6776D441D1731D441D9A65F2B552F886793D3A9C\" />\n        <meta-data\n            android:name=\"AAAA445\"\n            android:value=\"72E294445D7F576764D48B750FBC9427F764CFBC4F159441BE7D2FAB866B3868-8241C69D196753E009F590FC5FC24AE27AA33D0F24D4D915F333996B2BA30492\" />\n        <meta-data\n            android:name=\"AAAA446\"\n            android:value=\"FEF9C2B44BE86A838F83CA4126F87CF0B50D6DFD14A9A71297737DEEC773EA2A-CDC9962465DD5121CFED2A9D775D7614DF61F635E73AD0946F925B294A46A243\" />\n        <meta-data\n            android:name=\"AAAA447\"\n            android:value=\"6293F06DFC040A726575C0EF2E1157AD8606BE097BAA35528529D53DBAD8911D-4276919680F4ABA6D41924031C20AC2624FEEA5E8EC68A36529B2ACB664D911E\" />\n        <meta-data\n            android:name=\"AAAA448\"\n            android:value=\"ADE4EBF0ED6B5FAF43A0C9EFFF74D613D7386DF8A892765F997277D33D36E2DD-D95242362A7285FC3E0BDFF3E44E30612D1EAF88080FF7F2ECB0F536E1D2BBB4\" />\n        <meta-data\n            android:name=\"AAAA449\"\n            android:value=\"973483E9E505F521B919092B3114E4847C1813D029C147D2FA564207DA94CCC0-53FE8A984AE0414FB33209AECC919B270CF2D76BD34A511B088A50A771F257CD\" />\n        <meta-data\n            android:name=\"AAAA450\"\n            android:value=\"4A5F51491BC1903DAB58799B19E9F6EF25E37EBE312937B33373D171EFAF5B8A-86529206B6F2A6768DF3A653C9A78AEA34106C31CC5E0BD5FDE4ADA724EFC0C1\" />\n        <meta-data\n            android:name=\"AAAA451\"\n            android:value=\"BCA1C64CE928CB7A66CDF88E840082EF81BC3BBCD0E6EBB1F23D4ECF4906DFEB-34DF0E7A9F1CF1892E45C056B4973CD81CCF148A4050D11AEA4AC5A65F900A42\" />\n        <meta-data\n            android:name=\"AAAA452\"\n            android:value=\"038FE6E1E635161A66EA7C9F976246B9FCB00B79BAB856C81692444C05FE3095-4DB7A6944CBB5C1A6F836CAFEBB8166BF877C225B802B18E67BA6F6670F75875\" />\n        <meta-data\n            android:name=\"AAAA453\"\n            android:value=\"1616863C8C09A23FA949EE781190BF8A245AA2D97154DA4C778298690A377613-086850948967CA4CD624CC297DC86BA9187A03D28BB4ECF62E749092720FB15D\" />\n        <meta-data\n            android:name=\"AAAA454\"\n            android:value=\"378B0AB93FC81C28BB14DF07A3519AB0EE4639132186B28AB69ED55BA30AE329-B868CF25E51CE683BE151CB2474260FB6C1980A6FAFDBFD3889E7464CA2914EF\" />\n        <meta-data\n            android:name=\"AAAA455\"\n            android:value=\"7472551F88660CF80CBDB8724EF2B9AB92F99D4B6B0F501267695D8943C15482-8CC1326AF546FA71A721E003AEB2522710CE0A51CA62FBCAB595C708D57C44C6\" />\n        <meta-data\n            android:name=\"AAAA456\"\n            android:value=\"9803187567EA486D2E0ECF5F684F782B9ACE88D007D4088929A2A5580453FDD9-14B69BAFDD9F85DDD4E79E5C405D2C41DCF65DD7B623AB8EC3395D5048723696\" />\n        <meta-data\n            android:name=\"AAAA457\"\n            android:value=\"18F8694020F99F530201B3EF5F8B588F5A359DF0CD7CE4EBB1531FE90546BFB7-363863596EA99241EB71B1A985553AA604DE3EA3C5F0C546742390E682164E6B\" />\n        <meta-data\n            android:name=\"AAAA458\"\n            android:value=\"B49D8A4B1C280A954B71CB989B60F6D68C4888489DFE3F07A95C83FCF9167ED4-A9C3EE740157819F972CF69D0BBD12FA923627AE3EEF7A332088C297E5A02161\" />\n        <meta-data\n            android:name=\"AAAA459\"\n            android:value=\"E78B61869A23C686F6E4A0D066B0701E317DF8DBEF4610612C61C76A45AAC27D-4648132FA0A6F268717AA3D2436F750A63C5272A50E76DD7189591F83707DFEC\" />\n        <meta-data\n            android:name=\"AAAA460\"\n            android:value=\"7FEBF4BB1B5AF54CD4CD9984BCE86022380BCF311F222788C8484A073F5E8F2B-815E2DDA57DCB3B3510628705299DEF71AACF28DE298A6FECBC468878853065C\" />\n        <meta-data\n            android:name=\"AAAA461\"\n            android:value=\"EDA6DF5E0F7BEEAB9C6F34BD4676BFB79904E3CA4F1D869B7A24FCEAC966A0CE-8821C6AACFFC4BE8BE6A71280A39B93F098C6EEA1A665CCA66F3AE009726FA30\" />\n        <meta-data\n            android:name=\"AAAA462\"\n            android:value=\"A92D6CF32DB12C249344EECB346322C6942E84A5E930A77DC8FBC1750383CD36-7A7D89BC2CDAB8230FA3DC5C9D1FAAF0014AF864D575ED7AFF774C7178899EAF\" />\n        <meta-data\n            android:name=\"AAAA463\"\n            android:value=\"3E46BAA26A4AC24381B8AD663A68F3C5C3CF9C6BA3034FAC1D4DB81656D13BA7-6AC8C8A9E6F36E14E52A0A0515A36B7066E720A1B0C8A1B059E0781750A87199\" />\n        <meta-data\n            android:name=\"AAAA464\"\n            android:value=\"DDF440CD121D8D504E26A128AA69A9467654482368A715FFEBB2C95F9D14A36A-8418A19ACDE232B74C1D193353DC9CE624D146650325F9297C8A20552D2CE29A\" />\n        <meta-data\n            android:name=\"AAAA465\"\n            android:value=\"8AADD422ACBBDFAC109FBB1C4D317C01B5A5C8511B28ABB6B15B7A81E4DF6188-D49842AFD29040F7288F467B4890608D2C7CADEC91131F3F95CDF3EE1BB6C961\" />\n        <meta-data\n            android:name=\"AAAA466\"\n            android:value=\"64C9DD9A77D1188D53BFA314720833184942E018BA108D9F0457B99E90B331B2-95CBD9AF718B6F5C0F766CB6FB0EC7D2A5439C5F74FE9FC0AB66823CDEE9E596\" />\n        <meta-data\n            android:name=\"AAAA467\"\n            android:value=\"C4C982A6C114CC9BC82B4F3E08E6A9B5B6DF4FABFAB60AD51B76ECE05F13F8A0-52586D838E24FE06DD85B495E76421B61222C66589F5D21C0197561D0702CCDB\" />\n        <meta-data\n            android:name=\"AAAA468\"\n            android:value=\"3FB7C0466D433308884E5268CFF760364A40ED8D803F359EE6031EFDAF071FA4-D86EFE151E09BF4CA8440CB3BFA0A81BE2544F70C78587DAF0266DFCA2FA25DF\" />\n        <meta-data\n            android:name=\"AAAA469\"\n            android:value=\"4AB452A5AAA91926AB9BCE97C238AFED04F758BE5885014E5E26C516BED1EEBB-149EFCD0EAF6E30467BEF381DC67F2848F6DBC8599791712DEBA26F17FABFF2B\" />\n        <meta-data\n            android:name=\"AAAA470\"\n            android:value=\"E429DBF162EBB10171AA0081D88D8969A7CD246DCDD8462CC37ABAF5045E23F8-0206ECF0B94FBBA05B5C0CEEE9BADDEE061769CEB1A7FE22EE1722B8301C733D\" />\n        <meta-data\n            android:name=\"AAAA471\"\n            android:value=\"43AFFBCA7B55B0A3A59DF1DED75BB6FE245AA834DEDBACB68F5DC9A43EF9B9D4-03BD153DE7230800663090D52320EEEBDD5DEE1006AF8E77D73ED1A11B41DC0B\" />\n        <meta-data\n            android:name=\"AAAA472\"\n            android:value=\"A972EA600C9A8C6B47AB340D210B4E0BBE084C0BCD20219451D41392F34E767F-2446B1227C5B236DD4E50F892A41F696ADB3BD022E660832FA0EF3053130B43C\" />\n        <meta-data\n            android:name=\"AAAA473\"\n            android:value=\"05BDB9AECF23BACE7B706E1E58E4222869851DFE39763D96B124ED7AA49DB2F1-2692EFE19902450EF7F633E873D4E376F04EB18ADFAD5C29F535CD56DA5682A0\" />\n        <meta-data\n            android:name=\"AAAA474\"\n            android:value=\"F1E410DF53F88613B2A546BFFE81A211CB8091A5BD7AE191D942EF4142CFC7A8-D6D29621132D4AF29BA142ACF0A6E587DAAFB38A61D515CA528AD6D2B05BA485\" />\n        <meta-data\n            android:name=\"AAAA475\"\n            android:value=\"9F6E0E704D382BD1713EBAF1F2457F2E0243ED306470D1A4E2D8AE081F7493F0-F14A5B29DB5C181C119C3482B09EEA80751228869314E8149167A2E863219807\" />\n        <meta-data\n            android:name=\"AAAA476\"\n            android:value=\"97C9F24587E4DCD36E38F178677049BF97099C56235A66601129A2457CBB6531-A10D980188B0BED0C7F8F9D49C80BCC0D03121A3EDDD1ADFECAC31D069462127\" />\n\n        <meta-data\n            android:name=\"NAVI100\"\n            android:value=\"4763384BBF445EDB8D3112C15413D96FB1415218F6403DB026699968EDA84491-7712B5F255F2C85B8B164519116AC4381BB9A3582DCDD2B73AC06EE7464913AE\" />\n\n    </application>\n\n</manifest>"
  },
  {
    "path": "fake-signature/src/main/res/values/arrays.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<resources>\n    <string-array name=\"signature_want_fake\">\n        <item>com.google.android.gms</item>\n        <item>com.android.vending</item>\n        <item>com.spotify.music</item>\n        <item>com.getir</item>\n        <item>com.pozitron.iscep</item>\n        <item>com.widgetable.theme.android</item>\n        <item>pro.huobi</item>\n        <item>com.tarparos.phigaea</item>\n        <item>com.artem.scotepio</item>\n        <item>com.sabah.deprembs</item>\n        <item>com.boynergrup.hopi</item>\n        <item>com.belbim.istanbulkart</item>\n        <item>com.a101.plus</item>\n        <item>com.widgetable.theme.android</item>\n        <item>net.wargaming.wot.blitz</item>\n        <item>com.litatom.app</item>\n        <item>com.ataexpress.tiklagelsin</item>\n        <item>tr.com.petrolofisi</item>\n        <item>com.mobisoft.beymen</item>\n        <item>com.unilever.algida</item>\n        <item>com.mobisoft.morhipo</item>\n        <item>com.zzkko</item>\n        <item>com.didilabs.kaavefali</item>\n        <item>com.airbnb.android</item>\n        <item>com.mobillium.papara</item>\n        <item>co.com.fincaraiz.app</item>\n        <item>com.frisby.frisby</item>\n    </string-array>\n    <string-array name=\"signature_never_fake\">\n        <item>com.truecaller</item>\n    </string-array>\n</resources>"
  },
  {
    "path": "fake-signature/src/main/res/values/signature.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2014 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<resources>\n    <string name=\"fake_signature\">\n        308204433082032ba003020102020900c2e08746644a308d300d06092a864886f70d01010405003074310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e205669657731143012060355040a130b476f6f676c6520496e632e3110300e060355040b1307416e64726f69643110300e06035504031307416e64726f6964301e170d3038303832313233313333345a170d3336303130373233313333345a3074310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e205669657731143012060355040a130b476f6f676c6520496e632e3110300e060355040b1307416e64726f69643110300e06035504031307416e64726f696430820120300d06092a864886f70d01010105000382010d00308201080282010100ab562e00d83ba208ae0a966f124e29da11f2ab56d08f58e2cca91303e9b754d372f640a71b1dcb130967624e4656a7776a92193db2e5bfb724a91e77188b0e6a47a43b33d9609b77183145ccdf7b2e586674c9e1565b1f4c6a5955bff251a63dabf9c55c27222252e875e4f8154a645f897168c0b1bfc612eabf785769bb34aa7984dc7e2ea2764cae8307d8c17154d7ee5f64a51a44a602c249054157dc02cd5f5c0e55fbef8519fbe327f0b1511692c5a06f19d18385f5c4dbc2d6b93f68cc2979c70e18ab93866b3bd5db8999552a0e3b4c99df58fb918bedc182ba35e003c1b4b10dd244a8ee24fffd333872ab5221985edab0fc0d0b145b6aa192858e79020103a381d93081d6301d0603551d0e04160414c77d8cc2211756259a7fd382df6be398e4d786a53081a60603551d2304819e30819b8014c77d8cc2211756259a7fd382df6be398e4d786a5a178a4763074310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e205669657731143012060355040a130b476f6f676c6520496e632e3110300e060355040b1307416e64726f69643110300e06035504031307416e64726f6964820900c2e08746644a308d300c0603551d13040530030101ff300d06092a864886f70d010104050003820101006dd252ceef85302c360aaace939bcff2cca904bb5d7a1661f8ae46b2994204d0ff4a68c7ed1a531ec4595a623ce60763b167297a7ae35712c407f208f0cb109429124d7b106219c084ca3eb3f9ad5fb871ef92269a8be28bf16d44c8d9a08e6cb2f005bb3fe2cb96447e868e731076ad45b33f6009ea19c161e62641aa99271dfd5228c5c587875ddb7f452758d661f6cc0cccb7352e424cc4365c523532f7325137593c4ae341f4db41edda0d0b1071a7c440f0fe9ea01cb627ca674369d084bd2fd911ff06cdbf2cfa10dc0f893ae35762919048c7efc64c7144178342f70581c9de573af55b390dd7fdb9418631895d5f759f30112687ff621410c069308a\n    </string>\n    <string name=\"real_signature\">\n        308202ed308201d5a003020102020426ffa009300d06092a864886f70d01010b05003027310b300906035504061302444531183016060355040a130f4e4f47415050532050726f6a656374301e170d3132313030363132303533325a170d3337303933303132303533325a3027310b300906035504061302444531183016060355040a130f4e4f47415050532050726f6a65637430820122300d06092a864886f70d01010105000382010f003082010a02820101009a8d2a5336b0eaaad89ce447828c7753b157459b79e3215dc962ca48f58c2cd7650df67d2dd7bda0880c682791f32b35c504e43e77b43c3e4e541f86e35a8293a54fb46e6b16af54d3a4eda458f1a7c8bc1b7479861ca7043337180e40079d9cdccb7e051ada9b6c88c9ec635541e2ebf0842521c3024c826f6fd6db6fd117c74e859d5af4db04448965ab5469b71ce719939a06ef30580f50febf96c474a7d265bb63f86a822ff7b643de6b76e966a18553c2858416cf3309dd24278374bdd82b4404ef6f7f122cec93859351fc6e5ea947e3ceb9d67374fe970e593e5cd05c905e1d24f5a5484f4aadef766e498adf64f7cf04bddd602ae8137b6eea40722d0203010001a321301f301d0603551d0e04160414110b7aa9ebc840b20399f69a431f4dba6ac42a64300d06092a864886f70d01010b0500038201010007c32ad893349cf86952fb5a49cfdc9b13f5e3c800aece77b2e7e0e9c83e34052f140f357ec7e6f4b432dc1ed542218a14835acd2df2deea7efd3fd5e8f1c34e1fb39ec6a427c6e6f4178b609b369040ac1f8844b789f3694dc640de06e44b247afed11637173f36f5886170fafd74954049858c6096308fc93c1bc4dd5685fa7a1f982a422f2a3b36baa8c9500474cf2af91c39cbec1bc898d10194d368aa5e91f1137ec115087c31962d8f76cd120d28c249cf76f4c70f5baa08c70a7234ce4123be080cee789477401965cfe537b924ef36747e8caca62dfefdd1a6288dcb1c4fd2aaa6131a7ad254e9742022cfd597d2ca5c660ce9e41ff537e5a4041e37\n    </string>\n</resources>"
  },
  {
    "path": "firebase-auth/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\n\nandroid {\n    namespace 'com.google.firebase.auth'\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n}\n\ndependencies {\n    api project(':play-services-basement')\n\n    annotationProcessor project(':safe-parcel-processor')\n}\n"
  },
  {
    "path": "firebase-auth/core/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'kotlin-android'\n\ndependencies {\n    api project(':firebase-auth')\n\n    implementation \"androidx.lifecycle:lifecycle-service:$lifecycleVersion\"\n    implementation \"androidx.lifecycle:lifecycle-runtime-ktx:$lifecycleVersion\"\n\n    implementation \"androidx.appcompat:appcompat:$appcompatVersion\"\n\n    implementation project(':play-services-base-core')\n\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion\"\n    implementation \"org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutineVersion\"\n    implementation \"org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutineVersion\"\n\n    implementation \"com.android.volley:volley:$volleyVersion\"\n}\n\nandroid {\n    namespace \"org.microg.gms.firebase.auth.core\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    sourceSets {\n        main.java.srcDirs += 'src/main/kotlin'\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n\n    kotlinOptions {\n        jvmTarget = 1.8\n    }\n}\n"
  },
  {
    "path": "firebase-auth/core/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n    <uses-permission android:name=\"android.permission.RECEIVE_SMS\" />\n    <uses-permission android:name=\"android.permission.SYSTEM_ALERT_WINDOW\" />\n\n    <application>\n        <service android:name=\"org.microg.gms.firebase.auth.FirebaseAuthService\">\n            <intent-filter>\n                <action android:name=\"com.google.firebase.auth.api.gms.service.START\" />\n            </intent-filter>\n        </service>\n        <activity\n            android:name=\"org.microg.gms.firebase.auth.ReCaptchaActivity\"\n            android:exported=\"false\"\n            android:process=\":ui\"\n            android:theme=\"@style/Theme.AppCompat.Light.Dialog.Alert.NoActionBar\" />\n        <service\n            android:name=\"org.microg.gms.firebase.auth.ReCaptchaOverlayService\"\n            android:exported=\"false\"\n            android:process=\":ui\" />\n    </application>\n</manifest>\n"
  },
  {
    "path": "firebase-auth/core/src/main/assets/recaptcha.html",
    "content": "<!DOCTYPE html>\n<html style=\"margin: 5px\">\n<body style=\"margin: 5px\">\n\n<div id='recaptcha-container'></div>\n<div style=\"padding-top: 150px\">\n    <svg xmlns=\"http://www.w3.org/2000/svg\"\n         style=\"margin: auto; background: none; display: block; shape-rendering: auto;\" width=\"64px\" height=\"64px\"\n         viewBox=\"0 0 100 100\" preserveAspectRatio=\"xMidYMid\">\n        <rect x=\"17.5\" y=\"20.2285\" width=\"15\" height=\"59.543\" fill=\"#000000\">\n            <animate attributeName=\"y\" repeatCount=\"indefinite\" dur=\"1s\" calcMode=\"spline\" keyTimes=\"0;0.5;1\"\n                     values=\"10;30;30\" keySplines=\"0 0.5 0.5 1;0 0.5 0.5 1\" begin=\"-0.2s\"></animate>\n            <animate attributeName=\"height\" repeatCount=\"indefinite\" dur=\"1s\" calcMode=\"spline\" keyTimes=\"0;0.5;1\"\n                     values=\"80;40;40\" keySplines=\"0 0.5 0.5 1;0 0.5 0.5 1\" begin=\"-0.2s\"></animate>\n        </rect>\n        <rect x=\"42.5\" y=\"30\" width=\"15\" height=\"40\" fill=\"#000000\">\n            <animate attributeName=\"y\" repeatCount=\"indefinite\" dur=\"1s\" calcMode=\"spline\" keyTimes=\"0;0.5;1\"\n                     values=\"15;30;30\" keySplines=\"0 0.5 0.5 1;0 0.5 0.5 1\" begin=\"-0.1s\"></animate>\n            <animate attributeName=\"height\" repeatCount=\"indefinite\" dur=\"1s\" calcMode=\"spline\" keyTimes=\"0;0.5;1\"\n                     values=\"70;40;40\" keySplines=\"0 0.5 0.5 1;0 0.5 0.5 1\" begin=\"-0.1s\"></animate>\n        </rect>\n        <rect x=\"67.5\" y=\"30\" width=\"15\" height=\"40\" fill=\"#000000\">\n            <animate attributeName=\"y\" repeatCount=\"indefinite\" dur=\"1s\" calcMode=\"spline\" keyTimes=\"0;0.5;1\"\n                     values=\"15;30;30\" keySplines=\"0 0.5 0.5 1;0 0.5 0.5 1\"></animate>\n            <animate attributeName=\"height\" repeatCount=\"indefinite\" dur=\"1s\" calcMode=\"spline\" keyTimes=\"0;0.5;1\"\n                     values=\"70;40;40\" keySplines=\"0 0.5 0.5 1;0 0.5 0.5 1\"></animate>\n        </rect>\n    </svg>\n</div>\n\n<!-- Firebase App (the core Firebase SDK) is always required and must be listed first -->\n<script src=\"https://www.gstatic.com/firebasejs/7.22.0/firebase-app.js\"></script>\n<script src=\"https://www.gstatic.com/firebasejs/7.22.0/firebase-auth.js\"></script>\n\n<script type=\"text/javascript\">\n    var firebaseConfig = {\n        apiKey: \"%apikey%\"\n    };\n\n    // Initialize Firebase\n    firebase.initializeApp(firebaseConfig);\n    window.onload = () => {\n        window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container', {\n            'size': 'invisible',\n            'callback': function (response) {\n                MyCallback.onReCaptchaToken(response);\n            }\n        });\n        recaptchaVerifier.verify();\n    }\n\n</script>\n</body>\n</html>\n"
  },
  {
    "path": "firebase-auth/core/src/main/kotlin/org/microg/gms/firebase/auth/FirebaseAuthService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.firebase.auth\n\nimport android.content.BroadcastReceiver\nimport android.content.Context\nimport android.content.Intent\nimport android.content.IntentFilter\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.Handler\nimport android.os.Parcel\nimport android.provider.Telephony\nimport android.telephony.SmsMessage\nimport android.util.Log\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.LifecycleOwner\nimport androidx.lifecycle.lifecycleScope\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport com.google.firebase.auth.ActionCodeSettings\nimport com.google.firebase.auth.EmailAuthCredential\nimport com.google.firebase.auth.PhoneAuthCredential\nimport com.google.firebase.auth.UserProfileChangeRequest\nimport com.google.firebase.auth.api.internal.*\nimport org.json.JSONArray\nimport org.json.JSONObject\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.common.PackageUtils\nimport org.microg.gms.utils.digest\nimport org.microg.gms.utils.getCertificates\n\nprivate const val TAG = \"GmsFirebaseAuth\"\n\nfun JSONObject.getStringOrNull(key: String) = if (has(key)) getString(key) else null\nfun JSONObject.getJSONArrayOrNull(key: String) = if (has(key)) getJSONArray(key) else null\nfun JSONArray?.orEmpty() = this ?: JSONArray()\nfun JSONObject.getJSONArrayLength(key: String) = getJSONArrayOrNull(key).orEmpty().length()\n\nprivate val ActionCodeSettings.requestTypeAsString: String\n    get() = when (requestType) {\n        1 -> \"PASSWORD_RESET\"\n        2 -> \"OLD_EMAIL_AGREE\"\n        3 -> \"NEW_EMAIL_ACCEPT\"\n        4 -> \"VERIFY_EMAIL\"\n        5 -> \"RECOVER_EMAIL\"\n        6 -> \"EMAIL_SIGNIN\"\n        7 -> \"VERIFY_AND_CHANGE_EMAIL\"\n        8 -> \"REVERT_SECOND_FACTOR_ADDITION\"\n        else -> \"OOB_REQ_TYPE_UNSPECIFIED\"\n    }\n\nprivate val UserProfileChangeRequest.deleteAttributeList: List<String>\n    get() {\n        val list = arrayListOf<String>()\n        if (shouldRemoveDisplayName) list.add(\"DISPLAY_NAME\")\n        if (shouldRemovePhotoUri) list.add(\"PHOTO_URL\")\n        return list\n    }\n\nprivate fun Intent.getSmsMessages(): Array<SmsMessage> {\n    return if (SDK_INT >= 19) {\n        Telephony.Sms.Intents.getMessagesFromIntent(this)\n    } else {\n        (getSerializableExtra(\"pdus\") as? Array<ByteArray>)?.map { SmsMessage.createFromPdu(it) }.orEmpty().toTypedArray()\n    }\n}\n\nclass FirebaseAuthService : BaseService(TAG, GmsService.FIREBASE_AUTH) {\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService?) {\n        PackageUtils.getAndCheckCallingPackage(this, request.packageName)\n        val apiKey = request.extras?.getString(Constants.EXTRA_API_KEY)\n        val libraryVersion = request.extras?.getString(Constants.EXTRA_LIBRARY_VERSION)\n        if (apiKey == null) {\n            callback.onPostInitComplete(CommonStatusCodes.DEVELOPER_ERROR, null, null)\n        } else {\n            callback.onPostInitComplete(0, FirebaseAuthServiceImpl(this, lifecycle, request.packageName, libraryVersion, apiKey).asBinder(), null)\n        }\n    }\n}\n\nclass FirebaseAuthServiceImpl(private val context: Context, override val lifecycle: Lifecycle, private val packageName: String, private val libraryVersion: String?, private val apiKey: String) : IFirebaseAuthService.Stub(), LifecycleOwner {\n    private val client by lazy { IdentityToolkitClient(context, apiKey, packageName, context.packageManager.getCertificates(packageName).firstOrNull()?.digest(\"SHA1\")) }\n    private var authorizedDomain: String? = null\n\n    private suspend fun getAuthorizedDomain(): String {\n        authorizedDomain?.let { return it }\n        val authorizedDomain = try {\n            client.getProjectConfig().getJSONArray(\"authorizedDomains\").getString(0)\n        } catch (e: Exception) {\n            Log.w(TAG, e)\n            \"localhost\"\n        }\n        this.authorizedDomain = authorizedDomain\n        return authorizedDomain\n    }\n\n    private suspend fun refreshTokenResponse(cachedState: String): GetTokenResponse {\n        var tokenResponse = GetTokenResponse.parseJson(cachedState)\n        if (System.currentTimeMillis() + 300000L < tokenResponse.issuedAt + tokenResponse.expiresIn * 1000) {\n            return tokenResponse\n        }\n        return client.getTokenByRefreshToken(tokenResponse.refreshToken).toGetTokenResponse()\n    }\n\n    private fun JSONObject.toGetTokenResponse() = GetTokenResponse().apply {\n        refreshToken = getStringOrNull(\"refresh_token\")\n        accessToken = getStringOrNull(\"access_token\")\n        expiresIn = getStringOrNull(\"expires_in\")?.toLong()\n        tokenType = getStringOrNull(\"token_type\")\n    }\n\n    private fun JSONObject.toGetAccountInfoUser(): GetAccountInfoUser = GetAccountInfoUser().apply {\n        localId = getStringOrNull(\"localId\")\n        email = getStringOrNull(\"email\")\n        isEmailVerified = optBoolean(\"emailVerified\")\n        displayName = getStringOrNull(\"displayName\")\n        photoUrl = getStringOrNull(\"photoUrl\")\n        for (i in 0 until getJSONArrayLength(\"providerUserInfo\")) {\n            getJSONArray(\"providerUserInfo\").getJSONObject(i).run {\n                providerInfoList.providerUserInfos.add(ProviderUserInfo().apply {\n                    federatedId = getStringOrNull(\"federatedId\")\n                    displayName = getStringOrNull(\"displayName\")\n                    photoUrl = getStringOrNull(\"photoUrl\")\n                    providerId = getStringOrNull(\"providerId\")\n                    phoneNumber = getStringOrNull(\"phoneNumber\")\n                    email = getStringOrNull(\"email\")\n                    rawUserInfo = this@run.toString()\n                })\n            }\n        }\n        password = getStringOrNull(\"rawPassword\")\n        phoneNumber = getStringOrNull(\"phoneNumber\")\n        creationTimestamp = getStringOrNull(\"createdAt\")?.toLong() ?: 0L\n        lastSignInTimestamp = getStringOrNull(\"lastLoginAt\")?.toLong() ?: 0L\n    }\n\n    private fun JSONObject.toCreateAuthUriResponse(): CreateAuthUriResponse = CreateAuthUriResponse().apply {\n        authUri = getStringOrNull(\"authUri\")\n        isRegistered = optBoolean(\"registered\")\n        providerId = getStringOrNull(\"providerId\")\n        isForExistingProvider = optBoolean(\"forExistingProvider\")\n        for (i in 0 until getJSONArrayLength(\"allProviders\")) {\n            stringList.values.add(getJSONArray(\"allProviders\").getString(i))\n        }\n        for (i in 0 until getJSONArrayLength(\"signinMethods\")) {\n            signInMethods.add(getJSONArray(\"signinMethods\").getString(i))\n        }\n    }\n\n    override fun applyActionCode(request: ApplyActionCodeAidlRequest, callbacks: IFirebaseAuthCallbacks) {\n        Log.d(TAG, \"Not yet implemented: applyActionCode\")\n        callbacks.onFailure(Status(CommonStatusCodes.CANCELED, \"Not supported\"))\n    }\n\n    override fun applyActionCodeCompat(code: String?, callbacks: IFirebaseAuthCallbacks) {\n        Log.d(TAG, \"Not yet implemented: applyActionCodeCompat\")\n        callbacks.onFailure(Status(CommonStatusCodes.CANCELED, \"Not supported\"))\n    }\n\n    override fun changeEmail(request: ChangeEmailAidlRequest, callbacks: IFirebaseAuthCallbacks) {\n        Log.d(TAG, \"Not yet implemented: changeEmail\")\n        callbacks.onFailure(Status(CommonStatusCodes.CANCELED, \"Not supported\"))\n    }\n\n    override fun changeEmailCompat(cachedState: String?, email: String?, callbacks: IFirebaseAuthCallbacks) {\n        Log.d(TAG, \"Not yet implemented: changeEmailCompat\")\n        callbacks.onFailure(Status(CommonStatusCodes.CANCELED, \"Not supported\"))\n    }\n\n    override fun changePassword(request: ChangePasswordAidlRequest, callbacks: IFirebaseAuthCallbacks) {\n        Log.d(TAG, \"Not yet implemented: changePassword\")\n        callbacks.onFailure(Status(CommonStatusCodes.CANCELED, \"Not supported\"))\n    }\n\n    override fun changePasswordCompat(cachedState: String?, password: String?, callbacks: IFirebaseAuthCallbacks) {\n        Log.d(TAG, \"Not yet implemented: changePasswordCompat\")\n        callbacks.onFailure(Status(CommonStatusCodes.CANCELED, \"Not supported\"))\n    }\n\n    override fun checkActionCode(request: CheckActionCodeAidlRequest, callbacks: IFirebaseAuthCallbacks) {\n        Log.d(TAG, \"Not yet implemented: checkActionCode\")\n        callbacks.onFailure(Status(CommonStatusCodes.CANCELED, \"Not supported\"))\n    }\n\n    override fun checkActionCodeCompat(code: String?, callbacks: IFirebaseAuthCallbacks) {\n        Log.d(TAG, \"Not yet implemented: checkActionCodeCompat\")\n        callbacks.onFailure(Status(CommonStatusCodes.CANCELED, \"Not supported\"))\n    }\n\n    override fun confirmPasswordReset(request: ConfirmPasswordResetAidlRequest, callbacks: IFirebaseAuthCallbacks) {\n        Log.d(TAG, \"Not yet implemented: confirmPasswordReset\")\n        callbacks.onFailure(Status(CommonStatusCodes.CANCELED, \"Not supported\"))\n    }\n\n    override fun confirmPasswordResetCompat(code: String?, newPassword: String?, callbacks: IFirebaseAuthCallbacks) {\n        Log.d(TAG, \"Not yet implemented: confirmPasswordResetCompat\")\n        callbacks.onFailure(Status(CommonStatusCodes.CANCELED, \"Not supported\"))\n    }\n\n    override fun createUserWithEmailAndPassword(request: CreateUserWithEmailAndPasswordAidlRequest, callbacks: IFirebaseAuthCallbacks) {\n        lifecycleScope.launchWhenStarted {\n            Log.d(TAG, \"createUserWithEmailAndPassword\")\n            try {\n                val tokenResult = client.signupNewUser(email = request.email, password = request.password, tenantId = request.tenantId)\n                val idToken = tokenResult.getString(\"idToken\")\n                val refreshToken = tokenResult.getString(\"refreshToken\")\n                val getTokenResponse = client.getTokenByRefreshToken(refreshToken).toGetTokenResponse()\n                val accountInfoResult = client.getAccountInfo(idToken = idToken).getJSONArray(\"users\").getJSONObject(0).toGetAccountInfoUser().apply { this.isNewUser = true }\n                Log.d(TAG, \"callback: onGetTokenResponseAndUser\")\n                callbacks.onGetTokenResponseAndUser(getTokenResponse, accountInfoResult)\n            } catch (e: Exception) {\n                Log.w(TAG, \"callback: onFailure\", e)\n                callbacks.onFailure(Status(CommonStatusCodes.INTERNAL_ERROR, e.message))\n            }\n        }\n    }\n\n    override fun createUserWithEmailAndPasswordCompat(email: String?, password: String?, callbacks: IFirebaseAuthCallbacks) {\n        createUserWithEmailAndPassword(CreateUserWithEmailAndPasswordAidlRequest().apply { this.email = email; this.password = password }, callbacks)\n    }\n\n    override fun delete(request: DeleteAidlRequest, callbacks: IFirebaseAuthCallbacks) {\n        Log.d(TAG, \"Not yet implemented: delete\")\n        callbacks.onFailure(Status(CommonStatusCodes.CANCELED, \"Not supported\"))\n    }\n\n    override fun deleteCompat(cachedState: String?, callbacks: IFirebaseAuthCallbacks) {\n        Log.d(TAG, \"Not yet implemented: deleteCompat\")\n        callbacks.onFailure(Status(CommonStatusCodes.CANCELED, \"Not supported\"))\n    }\n\n    override fun finalizeMfaEnrollment(request: FinalizeMfaEnrollmentAidlRequest, callbacks: IFirebaseAuthCallbacks) {\n        Log.d(TAG, \"Not yet implemented: finalizeMfaEnrollment\")\n        callbacks.onFailure(Status(CommonStatusCodes.CANCELED, \"Not supported\"))\n    }\n\n    override fun finalizeMfaSignIn(request: FinalizeMfaSignInAidlRequest, callbacks: IFirebaseAuthCallbacks) {\n        Log.d(TAG, \"Not yet implemented: finalizeMfaSignIn\")\n        callbacks.onFailure(Status(CommonStatusCodes.CANCELED, \"Not supported\"))\n    }\n\n    override fun getAccessToken(request: GetAccessTokenAidlRequest, callbacks: IFirebaseAuthCallbacks) {\n        lifecycleScope.launchWhenStarted {\n            Log.d(TAG, \"getAccessToken\")\n            try {\n                callbacks.onGetTokenResponse(client.getTokenByRefreshToken(request.refreshToken).toGetTokenResponse())\n            } catch (e: Exception) {\n                Log.w(TAG, \"callback: onFailure\", e)\n                callbacks.onFailure(Status(CommonStatusCodes.INTERNAL_ERROR, e.message))\n            }\n        }\n    }\n\n    override fun getAccessTokenCompat(refreshToken: String?, callbacks: IFirebaseAuthCallbacks) {\n        getAccessToken(GetAccessTokenAidlRequest().apply { this.refreshToken = refreshToken }, callbacks)\n    }\n\n    override fun getProvidersForEmail(request: GetProvidersForEmailAidlRequest, callbacks: IFirebaseAuthCallbacks) {\n        lifecycleScope.launchWhenStarted {\n            Log.d(TAG, \"getProvidersForEmail\")\n            try {\n                callbacks.onCreateAuthUriResponse(client.createAuthUri(identifier = request.email, tenantId = request.tenantId).toCreateAuthUriResponse())\n            } catch (e: Exception) {\n                Log.w(TAG, \"callback: onFailure\", e)\n                callbacks.onFailure(Status(CommonStatusCodes.INTERNAL_ERROR, e.message))\n            }\n        }\n    }\n\n    override fun getProvidersForEmailCompat(email: String?, callbacks: IFirebaseAuthCallbacks) {\n        getProvidersForEmail(GetProvidersForEmailAidlRequest().apply { this.email = email }, callbacks)\n    }\n\n    override fun linkEmailAuthCredential(request: LinkEmailAuthCredentialAidlRequest, callbacks: IFirebaseAuthCallbacks) {\n        lifecycleScope.launchWhenStarted {\n            Log.d(TAG, \"linkEmailAuthCredential\")\n            try {\n                val getTokenResponse = refreshTokenResponse(request.cachedState)\n                val accountInfoResult = client.getAccountInfo(idToken = getTokenResponse.accessToken).getJSONArray(\"users\").getJSONObject(0).toGetAccountInfoUser()\n                val setAccountInfo = client.setAccountInfo(idToken = getTokenResponse.accessToken, localId = accountInfoResult.localId, email = request.email, password = request.password).toGetAccountInfoUser()\n                accountInfoResult.email = setAccountInfo.email\n                accountInfoResult.isEmailVerified = setAccountInfo.isEmailVerified\n                accountInfoResult.providerInfoList = setAccountInfo.providerInfoList\n                callbacks.onGetTokenResponseAndUser(getTokenResponse, accountInfoResult)\n            } catch (e: Exception) {\n                Log.w(TAG, \"callback: onFailure\", e)\n                callbacks.onFailure(Status(CommonStatusCodes.INTERNAL_ERROR, e.message))\n            }\n        }\n    }\n\n    override fun linkEmailAuthCredentialCompat(email: String?, password: String?, cachedState: String?, callbacks: IFirebaseAuthCallbacks) {\n        linkEmailAuthCredential(LinkEmailAuthCredentialAidlRequest().apply { this.email = email; this.password = password; this.cachedState = cachedState }, callbacks)\n    }\n\n    override fun linkFederatedCredential(request: LinkFederatedCredentialAidlRequest, callbacks: IFirebaseAuthCallbacks) {\n        Log.d(TAG, \"Not yet implemented: linkFederatedCredential\")\n        callbacks.onFailure(Status(CommonStatusCodes.CANCELED, \"Not supported\"))\n    }\n\n    override fun linkFederatedCredentialCompat(cachedState: String?, verifyAssertionRequest: VerifyAssertionRequest, callbacks: IFirebaseAuthCallbacks) {\n        Log.d(TAG, \"Not yet implemented: linkFederatedCredentialCompat\")\n        callbacks.onFailure(Status(CommonStatusCodes.CANCELED, \"Not supported\"))\n    }\n\n    override fun linkPhoneAuthCredential(request: LinkPhoneAuthCredentialAidlRequest, callbacks: IFirebaseAuthCallbacks) {\n        Log.d(TAG, \"Not yet implemented: linkPhoneAuthCredential\")\n        callbacks.onFailure(Status(CommonStatusCodes.CANCELED, \"Not supported\"))\n    }\n\n    override fun linkPhoneAuthCredentialCompat(cachedState: String?, credential: PhoneAuthCredential?, callbacks: IFirebaseAuthCallbacks) {\n        Log.d(TAG, \"Not yet implemented: linkPhoneAuthCredentialCompat\")\n        callbacks.onFailure(Status(CommonStatusCodes.CANCELED, \"Not supported\"))\n    }\n\n    override fun reload(request: ReloadAidlRequest, callbacks: IFirebaseAuthCallbacks) {\n        lifecycleScope.launchWhenStarted {\n            try {\n                Log.d(TAG, \"reload\")\n                val getTokenResponse = refreshTokenResponse(request.cachedState)\n                val accountInfoResult = client.getAccountInfo(idToken = getTokenResponse.accessToken).getJSONArray(\"users\").getJSONObject(0).toGetAccountInfoUser()\n                Log.d(TAG, \"callback: onGetTokenResponseAndUser\")\n                callbacks.onGetTokenResponseAndUser(getTokenResponse, accountInfoResult)\n            } catch (e: Exception) {\n                Log.w(TAG, \"callback: onFailure\", e)\n                callbacks.onFailure(Status(CommonStatusCodes.INTERNAL_ERROR, e.message))\n            }\n        }\n    }\n\n    override fun reloadCompat(cachedState: String?, callbacks: IFirebaseAuthCallbacks) {\n        reload(ReloadAidlRequest().apply { this.cachedState = cachedState }, callbacks)\n    }\n\n    override fun sendEmailVerification(request: SendEmailVerificationWithSettingsAidlRequest, callbacks: IFirebaseAuthCallbacks) {\n        lifecycleScope.launchWhenStarted {\n            try {\n                Log.d(TAG, \"sendEmailVerification\")\n                client.getOobConfirmationCode(\n                        requestType = \"VERIFY_EMAIL\",\n                        idToken = request.token,\n                        iOSBundleId = request.settings?.iOSBundle,\n                        iOSAppStoreId = request.settings?.iOSAppStoreId,\n                        continueUrl = request.settings?.url,\n                        androidInstallApp = request.settings?.androidInstallApp,\n                        androidMinimumVersion = request.settings?.androidMinimumVersion,\n                        androidPackageName = request.settings?.androidPackageName,\n                        canHandleCodeInApp = request.settings?.handleCodeInApp\n                )\n                callbacks.onEmailVerificationResponse()\n            } catch (e: Exception) {\n                Log.w(TAG, \"callback: onFailure\", e)\n                callbacks.onFailure(Status(CommonStatusCodes.INTERNAL_ERROR, e.message))\n            }\n        }\n    }\n\n    override fun sendEmailVerificationCompat(token: String?, actionCodeSettings: ActionCodeSettings?, callbacks: IFirebaseAuthCallbacks) {\n        sendEmailVerification(SendEmailVerificationWithSettingsAidlRequest().apply { this.token = token; this.settings = actionCodeSettings }, callbacks)\n    }\n\n    override fun sendVerificationCode(request: SendVerificationCodeAidlRequest, callbacks: IFirebaseAuthCallbacks) {\n        lifecycleScope.launchWhenStarted {\n            try {\n                Log.d(TAG, \"sendVerificationCode\")\n                val reCaptchaToken = when {\n                    request.request.recaptchaToken != null -> request.request.recaptchaToken\n                    ReCaptchaOverlayService.isSupported(context) -> ReCaptchaOverlayService.awaitToken(context, apiKey, getAuthorizedDomain())\n                    ReCaptchaActivity.isSupported(context) -> ReCaptchaActivity.awaitToken(context, apiKey, getAuthorizedDomain())\n                    else -> throw RuntimeException(\"No recaptcha token available\")\n                }\n                var sessionInfo: String? = null\n                var registered = true\n                val receiver = object : BroadcastReceiver() {\n                    override fun onReceive(context: Context, intent: Intent) {\n                        var smsCode: String? = null\n                        for (message in intent.getSmsMessages()) {\n                            smsCode = Regex(\"\\\\b([0-9]{6})\\\\b\").find(message.messageBody)?.groups?.get(1)?.value\n                                    ?: continue\n                            Log.d(TAG, \"Received SMS verification code: $smsCode\")\n                            break\n                        }\n                        if (smsCode == null) return\n                        registered = false\n                        context.unregisterReceiver(this)\n                        try {\n                            callbacks.onVerificationCompletedResponse(PhoneAuthCredential().apply {\n                                this.phoneNumber = request.request.phoneNumber\n                                this.sessionInfo = sessionInfo\n                                this.smsCode = smsCode\n                            })\n                            Log.d(TAG, \"callback: onVerificationCompletedResponse\")\n                        } catch (e: Exception) {\n                            Log.w(TAG, e)\n                        }\n                    }\n                }\n                context.registerReceiver(receiver, IntentFilter(\"android.provider.Telephony.SMS_RECEIVED\"))\n                var timeout = request.request.timeoutInSeconds * 1000L\n                if (timeout <= 0L) timeout = 120000L\n                Handler().postDelayed({\n                    if (registered) {\n                        Log.d(TAG, \"Waited ${timeout}ms for verification code SMS, timeout.\")\n                        context.unregisterReceiver(receiver)\n                        callbacks.onVerificationAutoTimeOut(sessionInfo)\n                        Log.d(TAG, \"callback: onVerificationAutoTimeOut\")\n                    }\n                }, timeout)\n                sessionInfo = client.sendVerificationCode(phoneNumber = request.request.phoneNumber, reCaptchaToken = reCaptchaToken).getString(\"sessionInfo\")\n                callbacks.onSendVerificationCodeResponse(sessionInfo)\n                Log.d(TAG, \"callback: onSendVerificationCodeResponse\")\n            } catch (e: Exception) {\n                Log.w(TAG, \"callback: onFailure\", e)\n                callbacks.onFailure(Status(CommonStatusCodes.INTERNAL_ERROR, e.message))\n            }\n        }\n    }\n\n    override fun sendVerificationCodeCompat(request: SendVerificationCodeRequest, callbacks: IFirebaseAuthCallbacks) {\n        sendVerificationCode(SendVerificationCodeAidlRequest().apply { this.request = request }, callbacks)\n    }\n\n    override fun sendGetOobConfirmationCodeEmail(request: SendGetOobConfirmationCodeEmailAidlRequest, callbacks: IFirebaseAuthCallbacks) {\n        lifecycleScope.launchWhenStarted {\n            try {\n                Log.d(TAG, \"sendGetOobConfirmationCodeEmail\")\n                client.getOobConfirmationCode(\n                        requestType = request.settings?.requestTypeAsString ?: \"OOB_REQ_TYPE_UNSPECIFIED\",\n                        email = request.email,\n                        iOSBundleId = request.settings?.iOSBundle,\n                        iOSAppStoreId = request.settings?.iOSAppStoreId,\n                        continueUrl = request.settings?.url,\n                        androidInstallApp = request.settings?.androidInstallApp,\n                        androidMinimumVersion = request.settings?.androidMinimumVersion,\n                        androidPackageName = request.settings?.androidPackageName,\n                        canHandleCodeInApp = request.settings?.handleCodeInApp\n                )\n                Log.d(TAG, \"callback: onResetPasswordResponse\")\n                callbacks.onResetPasswordResponse(null)\n            } catch (e: Exception) {\n                Log.w(TAG, \"callback: onFailure\", e)\n                callbacks.onFailure(Status(CommonStatusCodes.INTERNAL_ERROR, e.message))\n            }\n        }\n    }\n\n    override fun sendGetOobConfirmationCodeEmailCompat(email: String?, actionCodeSettings: ActionCodeSettings?, callbacks: IFirebaseAuthCallbacks) {\n        sendGetOobConfirmationCodeEmail(SendGetOobConfirmationCodeEmailAidlRequest().apply { this.email = email; this.settings = actionCodeSettings }, callbacks)\n    }\n\n    override fun setFirebaseUiVersion(request: SetFirebaseUiVersionAidlRequest, callbacks: IFirebaseAuthCallbacks) {\n        Log.d(TAG, \"Not yet implemented: setFirebaseUiVersion\")\n        callbacks.onFailure(Status(CommonStatusCodes.CANCELED, \"Not supported\"))\n    }\n\n    override fun setFirebaseUIVersionCompat(firebaseUiVersion: String?, callbacks: IFirebaseAuthCallbacks) {\n        Log.d(TAG, \"Not yet implemented: setFirebaseUIVersionCompat\")\n        callbacks.onFailure(Status(CommonStatusCodes.CANCELED, \"Not supported\"))\n    }\n\n    override fun signInAnonymously(request: SignInAnonymouslyAidlRequest, callbacks: IFirebaseAuthCallbacks) {\n        lifecycleScope.launchWhenStarted {\n            Log.d(TAG, \"signInAnonymously\")\n            try {\n                val tokenResult = client.signupNewUser(tenantId = request.tenantId)\n                val idToken = tokenResult.getString(\"idToken\")\n                val refreshToken = tokenResult.getString(\"refreshToken\")\n                val getTokenResponse = client.getTokenByRefreshToken(refreshToken).toGetTokenResponse()\n                val accountInfoResult = client.getAccountInfo(idToken = idToken).getJSONArray(\"users\").getJSONObject(0).toGetAccountInfoUser().apply { this.isNewUser = true }\n                Log.d(TAG, \"callback: onGetTokenResponseAndUser\")\n                callbacks.onGetTokenResponseAndUser(getTokenResponse, accountInfoResult)\n            } catch (e: Exception) {\n                Log.w(TAG, \"callback: onFailure\", e)\n                callbacks.onFailure(Status(CommonStatusCodes.INTERNAL_ERROR, e.message))\n            }\n        }\n    }\n\n    override fun signInAnonymouslyCompat(callbacks: IFirebaseAuthCallbacks) {\n        signInAnonymously(SignInAnonymouslyAidlRequest(), callbacks)\n    }\n\n    override fun signInWithCredential(request: SignInWithCredentialAidlRequest, callbacks: IFirebaseAuthCallbacks) {\n        lifecycleScope.launchWhenStarted {\n            Log.d(TAG, \"signInWithCredential request: ${request.request}\")\n            try {\n                val tokenResult = client.verifyAssertion(request.request.requestUri, request.request.postBody, request.request.returnSecureToken, request.request.returnIdpCredential)\n                Log.d(TAG, \"signInWithCredential callback: $tokenResult \")\n                val idToken = tokenResult.getString(\"idToken\")\n                val refreshToken = tokenResult.getString(\"refreshToken\")\n                val getTokenResponse = client.getTokenByRefreshToken(refreshToken).toGetTokenResponse()\n                val accountInfoResult = client.getAccountInfo(idToken = idToken).getJSONArray(\"users\").getJSONObject(0).toGetAccountInfoUser()\n                Log.d(TAG, \"signInWithCredential callback: onGetTokenResponseAndUser\")\n                callbacks.onGetTokenResponseAndUser(getTokenResponse, accountInfoResult)\n            } catch (e: Exception) {\n                Log.w(TAG, \"signInWithCredential callback: onFailure\", e)\n                callbacks.onFailure(Status(CommonStatusCodes.INTERNAL_ERROR, e.message))\n            }\n        }\n    }\n\n    override fun signInWithCredentialCompat(verifyAssertionRequest: VerifyAssertionRequest, callbacks: IFirebaseAuthCallbacks) {\n        Log.d(TAG, \"signInWithCredentialCompat verifyAssertionRequest: $verifyAssertionRequest\")\n        signInWithCredential(SignInWithCredentialAidlRequest(verifyAssertionRequest), callbacks)\n    }\n\n    override fun signInWithCustomToken(request: SignInWithCustomTokenAidlRequest, callbacks: IFirebaseAuthCallbacks) {\n        lifecycleScope.launchWhenStarted {\n            Log.d(TAG, \"signInWithCustomToken\")\n            try {\n                val tokenResult = client.verifyCustomToken(token = request.token)\n                val idToken = tokenResult.getString(\"idToken\")\n                val refreshToken = tokenResult.getString(\"refreshToken\")\n                val isNewUser = tokenResult.optBoolean(\"isNewUser\")\n                val getTokenResponse = client.getTokenByRefreshToken(refreshToken).toGetTokenResponse()\n                val accountInfoResult = client.getAccountInfo(idToken = idToken).getJSONArray(\"users\").getJSONObject(0).toGetAccountInfoUser().apply { this.isNewUser = isNewUser }\n                Log.d(TAG, \"callback: onGetTokenResponseAndUser\")\n                callbacks.onGetTokenResponseAndUser(getTokenResponse, accountInfoResult)\n            } catch (e: Exception) {\n                Log.w(TAG, \"callback: onFailure\", e)\n                callbacks.onFailure(Status(CommonStatusCodes.INTERNAL_ERROR, e.message))\n            }\n        }\n    }\n\n    override fun signInWithCustomTokenCompat(token: String, callbacks: IFirebaseAuthCallbacks) {\n        signInWithCustomToken(SignInWithCustomTokenAidlRequest().apply { this.token = token }, callbacks)\n    }\n\n    override fun signInWithEmailAndPassword(request: SignInWithEmailAndPasswordAidlRequest, callbacks: IFirebaseAuthCallbacks) {\n        lifecycleScope.launchWhenStarted {\n            Log.d(TAG, \"signInWithEmailAndPassword\")\n            try {\n                val tokenResult = client.verifyPassword(email = request.email, password = request.password, tenantId = request.tenantId)\n                val idToken = tokenResult.getString(\"idToken\")\n                val refreshToken = tokenResult.getString(\"refreshToken\")\n                val getTokenResponse = client.getTokenByRefreshToken(refreshToken).toGetTokenResponse()\n                val accountInfoResult = client.getAccountInfo(idToken = idToken).getJSONArray(\"users\").getJSONObject(0).toGetAccountInfoUser()\n                Log.d(TAG, \"callback: onGetTokenResponseAndUser\")\n                callbacks.onGetTokenResponseAndUser(getTokenResponse, accountInfoResult)\n            } catch (e: Exception) {\n                Log.w(TAG, \"callback: onFailure\", e)\n                callbacks.onFailure(Status(CommonStatusCodes.INTERNAL_ERROR, e.message))\n            }\n        }\n    }\n\n    override fun signInWithEmailAndPasswordCompat(email: String?, password: String?, callbacks: IFirebaseAuthCallbacks) {\n        signInWithEmailAndPassword(SignInWithEmailAndPasswordAidlRequest().apply { this.email = email; this.password = password }, callbacks)\n    }\n\n    override fun signInWithEmailLink(request: SignInWithEmailLinkAidlRequest, callbacks: IFirebaseAuthCallbacks) {\n        Log.d(TAG, \"Not yet implemented: signInWithEmailLink\")\n        callbacks.onFailure(Status(CommonStatusCodes.CANCELED, \"Not supported\"))\n    }\n\n    override fun signInWithEmailLinkCompat(credential: EmailAuthCredential?, callbacks: IFirebaseAuthCallbacks) {\n        Log.d(TAG, \"Not yet implemented: signInWithEmailLinkCompat\")\n        callbacks.onFailure(Status(CommonStatusCodes.CANCELED, \"Not supported\"))\n    }\n\n    override fun signInWithPhoneNumber(request: SignInWithPhoneNumberAidlRequest, callbacks: IFirebaseAuthCallbacks) {\n        lifecycleScope.launchWhenStarted {\n            Log.d(TAG, \"signInWithPhoneNumber\")\n            try {\n                val tokenResult = client.verifyPhoneNumber(\n                        phoneNumber = request.credential.phoneNumber,\n                        temporaryProof = request.credential.temporaryProof,\n                        sessionInfo = request.credential.sessionInfo,\n                        code = request.credential.smsCode\n                )\n                val idToken = tokenResult.getString(\"idToken\")\n                val refreshToken = tokenResult.getString(\"refreshToken\")\n                val isNewUser = tokenResult.optBoolean(\"isNewUser\")\n                val getTokenResponse = client.getTokenByRefreshToken(refreshToken).toGetTokenResponse()\n                val accountInfoResult = client.getAccountInfo(idToken).getJSONArray(\"users\").getJSONObject(0).toGetAccountInfoUser().apply { this.isNewUser = isNewUser }\n                Log.d(TAG, \"callback: onGetTokenResponseAndUser\")\n                callbacks.onGetTokenResponseAndUser(getTokenResponse, accountInfoResult)\n            } catch (e: Exception) {\n                Log.w(TAG, \"callback: onFailure\", e)\n                callbacks.onFailure(Status(CommonStatusCodes.INTERNAL_ERROR, e.message))\n            }\n        }\n    }\n\n    override fun signInWithPhoneNumberCompat(credential: PhoneAuthCredential?, callbacks: IFirebaseAuthCallbacks) {\n        signInWithPhoneNumber(SignInWithPhoneNumberAidlRequest().apply { this.credential = credential }, callbacks)\n    }\n\n    override fun startMfaEnrollmentWithPhoneNumber(request: StartMfaPhoneNumberEnrollmentAidlRequest, callbacks: IFirebaseAuthCallbacks) {\n        Log.d(TAG, \"Not yet implemented: startMfaEnrollmentWithPhoneNumber\")\n        callbacks.onFailure(Status(CommonStatusCodes.CANCELED, \"Not supported\"))\n    }\n\n    override fun startMfaSignInWithPhoneNumber(request: StartMfaPhoneNumberSignInAidlRequest, callbacks: IFirebaseAuthCallbacks) {\n        Log.d(TAG, \"Not yet implemented: startMfaSignInWithPhoneNumber\")\n        callbacks.onFailure(Status(CommonStatusCodes.CANCELED, \"Not supported\"))\n    }\n\n    override fun unenrollMfa(request: UnenrollMfaAidlRequest, callbacks: IFirebaseAuthCallbacks) {\n        Log.d(TAG, \"Not yet implemented: unenrollMfa\")\n        callbacks.onFailure(Status(CommonStatusCodes.CANCELED, \"Not supported\"))\n    }\n\n    override fun unlinkEmailCredential(request: UnlinkEmailCredentialAidlRequest, callbacks: IFirebaseAuthCallbacks) {\n        Log.d(TAG, \"Not yet implemented: unlinkEmailCredential\")\n        callbacks.onFailure(Status(CommonStatusCodes.CANCELED, \"Not supported\"))\n    }\n\n    override fun unlinkEmailCredentialCompat(cachedState: String?, callbacks: IFirebaseAuthCallbacks) {\n        Log.d(TAG, \"Not yet implemented: unlinkEmailCredentialCompat\")\n        callbacks.onFailure(Status(CommonStatusCodes.CANCELED, \"Not supported\"))\n    }\n\n    override fun unlinkFederatedCredential(request: UnlinkFederatedCredentialAidlRequest, callbacks: IFirebaseAuthCallbacks) {\n        Log.d(TAG, \"Not yet implemented: unlinkFederatedCredential\")\n        callbacks.onFailure(Status(CommonStatusCodes.CANCELED, \"Not supported\"))\n    }\n\n    override fun unlinkFederatedCredentialCompat(provider: String?, cachedState: String?, callbacks: IFirebaseAuthCallbacks) {\n        Log.d(TAG, \"Not yet implemented: unlinkFederatedCredentialCompat\")\n        callbacks.onFailure(Status(CommonStatusCodes.CANCELED, \"Not supported\"))\n    }\n\n    override fun updateProfile(request: UpdateProfileAidlRequest, callbacks: IFirebaseAuthCallbacks) {\n        lifecycleScope.launchWhenStarted {\n            Log.d(TAG, \"updateProfile\")\n            try {\n                val getTokenResponse = refreshTokenResponse(request.cachedState)\n                val accountInfoResult = client.getAccountInfo(idToken = getTokenResponse.accessToken).getJSONArray(\"users\").getJSONObject(0).toGetAccountInfoUser()\n                val setAccountInfo = client.setAccountInfo(idToken = getTokenResponse.accessToken, localId = accountInfoResult.localId, displayName = request.request.displayName, photoUrl = request.request.photoUrl, deleteAttribute = request.request.deleteAttributeList).toGetAccountInfoUser()\n                accountInfoResult.photoUrl = setAccountInfo.photoUrl\n                accountInfoResult.displayName = setAccountInfo.displayName\n                callbacks.onGetTokenResponseAndUser(getTokenResponse, accountInfoResult)\n            } catch (e: Exception) {\n                Log.w(TAG, \"callback: onFailure\", e)\n                callbacks.onFailure(Status(CommonStatusCodes.INTERNAL_ERROR, e.message))\n            }\n        }\n    }\n\n    override fun updateProfileCompat(cachedState: String?, userProfileChangeRequest: UserProfileChangeRequest, callbacks: IFirebaseAuthCallbacks) {\n        updateProfile(UpdateProfileAidlRequest().apply { this.cachedState = cachedState; this.request = userProfileChangeRequest}, callbacks)\n    }\n\n    override fun verifyBeforeUpdateEmail(request: VerifyBeforeUpdateEmailAidlRequest, callbacks: IFirebaseAuthCallbacks) {\n        Log.d(TAG, \"Not yet implemented: verifyBeforeUpdateEmail\")\n        callbacks.onFailure(Status(CommonStatusCodes.CANCELED, \"Not supported\"))\n    }\n\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean {\n        if (super.onTransact(code, data, reply, flags)) return true\n        Log.d(TAG, \"onTransact: $code, $data, $flags\")\n        return false\n    }\n}\n"
  },
  {
    "path": "firebase-auth/core/src/main/kotlin/org/microg/gms/firebase/auth/IdentityToolkitClient.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.firebase.auth\n\nimport android.content.Context\nimport android.util.Log\nimport com.android.volley.NetworkResponse\nimport com.android.volley.ParseError\nimport com.android.volley.Request.Method.GET\nimport com.android.volley.Request.Method.POST\nimport com.android.volley.Response\nimport com.android.volley.VolleyError\nimport com.android.volley.toolbox.HttpHeaderParser\nimport com.android.volley.toolbox.JsonObjectRequest\nimport com.android.volley.toolbox.JsonRequest\nimport com.android.volley.toolbox.Volley\nimport org.json.JSONArray\nimport org.json.JSONException\nimport org.json.JSONObject\nimport org.microg.gms.utils.singleInstanceOf\nimport org.microg.gms.utils.toHexString\nimport java.io.UnsupportedEncodingException\nimport java.lang.RuntimeException\nimport java.nio.charset.Charset\nimport kotlin.coroutines.resume\nimport kotlin.coroutines.resumeWithException\nimport kotlin.coroutines.suspendCoroutine\n\nprivate const val TAG = \"GmsFirebaseAuthClient\"\n\nclass IdentityToolkitClient(context: Context, private val apiKey: String, private val packageName: String? = null, private val certSha1Hash: ByteArray? = null) {\n    private val queue = singleInstanceOf { Volley.newRequestQueue(context.applicationContext) }\n\n    private fun buildRelyingPartyUrl(method: String) = \"https://www.googleapis.com/identitytoolkit/v3/relyingparty/$method?key=$apiKey\"\n    private fun buildStsUrl(method: String) = \"https://securetoken.googleapis.com/v1/$method?key=$apiKey\"\n\n    private fun getRequestHeaders(): Map<String, String> = hashMapOf<String, String>().apply {\n        if (packageName != null) put(\"X-Android-Package\", packageName)\n        if (certSha1Hash != null) put(\"X-Android-Cert\", certSha1Hash.toHexString().uppercase())\n    }\n\n    private suspend fun request(method: String, data: JSONObject): JSONObject = suspendCoroutine { continuation ->\n        queue.add(object : JsonObjectRequest(POST, buildRelyingPartyUrl(method), data, {\n            continuation.resume(it)\n        }, {\n            Log.d(TAG, \"Error: ${it.networkResponse?.data?.decodeToString() ?: it.message}\")\n            continuation.resumeWithException(RuntimeException(it))\n        }) {\n            override fun getHeaders(): Map<String, String> = getRequestHeaders()\n        })\n    }\n\n    suspend fun createAuthUri(identifier: String? = null, tenantId: String? = null, continueUri: String? = \"http://localhost\"): JSONObject =\n            request(\"createAuthUri\", JSONObject()\n                    .put(\"identifier\", identifier)\n                    .put(\"tenantId\", tenantId)\n                    .put(\"continueUri\", continueUri))\n\n    suspend fun getAccountInfo(idToken: String? = null): JSONObject =\n            request(\"getAccountInfo\", JSONObject()\n                    .put(\"idToken\", idToken))\n\n    suspend fun getProjectConfig(): JSONObject = suspendCoroutine { continuation ->\n        queue.add(JsonObjectRequest(GET, buildRelyingPartyUrl(\"getProjectConfig\"), null, { continuation.resume(it) }, { continuation.resumeWithException(RuntimeException(it)) }))\n    }\n\n    suspend fun getOobConfirmationCode(requestType: String, email: String? = null, newEmail: String? = null, continueUrl: String? = null, idToken: String? = null, iOSBundleId: String? = null, iOSAppStoreId: String? = null, androidMinimumVersion: String? = null, androidInstallApp: Boolean? = null, androidPackageName: String? = null, canHandleCodeInApp: Boolean? = null): JSONObject =\n            request(\"getOobConfirmationCode\", JSONObject()\n                    .put(\"kind\", \"identitytoolkit#relyingparty\")\n                    .put(\"requestType\", requestType)\n                    .put(\"email\", email)\n                    .put(\"newEmail\", newEmail)\n                    .put(\"continueUrl\", continueUrl)\n                    .put(\"idToken\", idToken)\n                    .put(\"iOSBundleId\", iOSBundleId)\n                    .put(\"iOSAppStoreId\", iOSAppStoreId)\n                    .put(\"androidMinimumVersion\", androidMinimumVersion)\n                    .put(\"androidInstallApp\", androidInstallApp)\n                    .put(\"androidPackageName\", androidPackageName)\n                    .put(\"canHandleCodeInApp\", canHandleCodeInApp))\n\n\n    suspend fun sendVerificationCode(phoneNumber: String? = null, reCaptchaToken: String? = null): JSONObject =\n            request(\"sendVerificationCode\", JSONObject()\n                    .put(\"phoneNumber\", phoneNumber)\n                    .put(\"recaptchaToken\", reCaptchaToken))\n\n    suspend fun setAccountInfo(idToken: String? = null, localId: String? = null, email: String? = null, password: String? = null, displayName: String? = null, photoUrl: String? = null, deleteAttribute: List<String> = emptyList()): JSONObject =\n            request(\"setAccountInfo\", JSONObject()\n                    .put(\"idToken\", idToken)\n                    .put(\"localId\", localId)\n                    .put(\"email\", email)\n                    .put(\"password\", password)\n                    .put(\"displayName\", displayName)\n                    .put(\"photoUrl\", photoUrl)\n                    .put(\"deleteAttribute\", JSONArray().apply { deleteAttribute.map { put(it) } }))\n\n    suspend fun signupNewUser(email: String? = null, password: String? = null, tenantId: String? = null): JSONObject =\n            request(\"signupNewUser\", JSONObject()\n                    .put(\"email\", email)\n                    .put(\"password\", password)\n                    .put(\"tenantId\", tenantId))\n\n    suspend fun verifyCustomToken(token: String? = null, returnSecureToken: Boolean = true): JSONObject =\n            request(\"verifyCustomToken\", JSONObject()\n                    .put(\"token\", token)\n                    .put(\"returnSecureToken\", returnSecureToken))\n\n    suspend fun verifyAssertion(requestUri: String? = null, postBody: String? = null, returnSecureToken: Boolean = true, returnIdpCredential: Boolean = true): JSONObject =\n            request(\"verifyAssertion\", JSONObject()\n                    .put(\"requestUri\", requestUri)\n                    .put(\"postBody\", postBody)\n                    .put(\"returnSecureToken\", returnSecureToken)\n                    .put(\"returnIdpCredential\", returnIdpCredential))\n\n    suspend fun verifyPassword(email: String? = null, password: String? = null, tenantId: String? = null, returnSecureToken: Boolean = true): JSONObject =\n            request(\"verifyPassword\", JSONObject()\n                    .put(\"email\", email)\n                    .put(\"password\", password)\n                    .put(\"tenantId\", tenantId)\n                    .put(\"returnSecureToken\", returnSecureToken))\n\n    suspend fun verifyPhoneNumber(phoneNumber: String? = null, sessionInfo: String? = null, code: String? = null, idToken: String? = null, verificationProof: String? = null, temporaryProof: String? = null): JSONObject =\n            request(\"verifyPhoneNumber\", JSONObject()\n                    .put(\"verificationProof\", verificationProof)\n                    .put(\"code\", code)\n                    .put(\"idToken\", idToken)\n                    .put(\"temporaryProof\", temporaryProof)\n                    .put(\"phoneNumber\", phoneNumber)\n                    .put(\"sessionInfo\", sessionInfo))\n\n    suspend fun getTokenByRefreshToken(refreshToken: String): JSONObject = suspendCoroutine { continuation ->\n        queue.add(object : JsonRequest<JSONObject>(POST, buildStsUrl(\"token\"), \"grant_type=refresh_token&refresh_token=$refreshToken\", { continuation.resume(it) }, { continuation.resumeWithException(RuntimeException(it)) }) {\n            override fun parseNetworkResponse(response: NetworkResponse): Response<JSONObject> {\n                return try {\n                    val jsonString = String(response.data, Charset.forName(HttpHeaderParser.parseCharset(response.headers, PROTOCOL_CHARSET)))\n                    Response.success(JSONObject(jsonString), null)\n                } catch (e: UnsupportedEncodingException) {\n                    Response.error(ParseError(e))\n                } catch (je: JSONException) {\n                    Response.error(ParseError(je))\n                }\n            }\n\n            override fun getBodyContentType(): String {\n                return \"application/x-www-form-urlencoded\"\n            }\n\n            override fun getHeaders(): Map<String, String> = getRequestHeaders()\n        })\n    }\n}"
  },
  {
    "path": "firebase-auth/core/src/main/kotlin/org/microg/gms/firebase/auth/ReCaptchaActivity.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.firebase.auth\n\nimport android.annotation.SuppressLint\nimport android.app.Activity\nimport android.content.Context\nimport android.content.Intent\nimport android.content.Intent.*\nimport android.os.Bundle\nimport android.os.ResultReceiver\nimport android.util.Log\nimport android.webkit.JavascriptInterface\nimport android.webkit.WebSettings\nimport android.webkit.WebView\nimport androidx.appcompat.app.AppCompatActivity\nimport org.microg.gms.firebase.auth.core.R\nimport org.microg.gms.profile.Build\nimport org.microg.gms.profile.ProfileManager\nimport kotlin.coroutines.resume\nimport kotlin.coroutines.resumeWithException\nimport kotlin.coroutines.suspendCoroutine\n\nprivate const val TAG = \"GmsFirebaseAuthCaptcha\"\n\nclass ReCaptchaActivity : AppCompatActivity() {\n    private val receiver: ResultReceiver?\n        get() = intent.getParcelableExtra(EXTRA_RESULT_RECEIVER)\n    private val hostname: String\n        get() = intent.getStringExtra(EXTRA_HOSTNAME) ?: \"localhost:5000\"\n    private var finished = false\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        openWebsite()\n    }\n\n    @SuppressLint(\"SetJavaScriptEnabled\", \"AddJavascriptInterface\")\n    private fun openWebsite() {\n        val apiKey = intent.getStringExtra(EXTRA_API_KEY) ?: return finishResult(Activity.RESULT_CANCELED)\n        setContentView(R.layout.activity_recaptcha)\n        val view = findViewById<WebView>(R.id.web)\n        val settings = view.settings\n        settings.javaScriptEnabled = true\n        settings.useWideViewPort = false\n        settings.setSupportZoom(false)\n        settings.displayZoomControls = false\n        settings.cacheMode = WebSettings.LOAD_NO_CACHE\n        ProfileManager.ensureInitialized(this)\n        settings.userAgentString = Build.generateWebViewUserAgentString(settings.userAgentString)\n        view.addJavascriptInterface(ReCaptchaCallback(this), \"MyCallback\")\n        val captcha = assets.open(\"recaptcha.html\").bufferedReader().readText().replace(\"%apikey%\", apiKey)\n        view.loadDataWithBaseURL(\"https://$hostname/\", captcha, null, null, \"https://$hostname/\")\n    }\n\n    fun finishResult(resultCode: Int, token: String? = null) {\n        finished = true\n        setResult(resultCode, token?.let { Intent().apply { putExtra(EXTRA_TOKEN, it) } })\n        receiver?.send(resultCode, token?.let { Bundle().apply { putString(EXTRA_TOKEN, it) } })\n        finish()\n    }\n\n    override fun onDestroy() {\n        super.onDestroy()\n        if (!finished) receiver?.send(Activity.RESULT_CANCELED, null)\n    }\n\n    companion object {\n        class ReCaptchaCallback(val activity: ReCaptchaActivity) {\n            @JavascriptInterface\n            fun onReCaptchaToken(token: String) {\n                Log.d(TAG, \"onReCaptchaToken: $token\")\n                activity.finishResult(Activity.RESULT_OK, token)\n            }\n        }\n\n        fun isSupported(context: Context): Boolean = true\n\n        suspend fun awaitToken(context: Context, apiKey: String, hostname: String? = null) = suspendCoroutine<String> { continuation ->\n            val intent = Intent(context, ReCaptchaActivity::class.java)\n            val resultReceiver = object : ResultReceiver(null) {\n                override fun onReceiveResult(resultCode: Int, resultData: Bundle?) {\n                    try {\n                        if (resultCode == Activity.RESULT_OK) {\n                            continuation.resume(resultData?.getString(EXTRA_TOKEN)!!)\n                        }\n                    } catch (e: Exception) {\n                        continuation.resumeWithException(e)\n                    }\n                }\n            }\n            intent.putExtra(EXTRA_API_KEY, apiKey)\n            intent.putExtra(EXTRA_RESULT_RECEIVER, resultReceiver)\n            intent.putExtra(EXTRA_HOSTNAME, hostname)\n            intent.addFlags(FLAG_ACTIVITY_NEW_TASK)\n            intent.addFlags(FLAG_ACTIVITY_REORDER_TO_FRONT)\n            intent.addFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)\n            context.startActivity(intent)\n        }\n    }\n}\n"
  },
  {
    "path": "firebase-auth/core/src/main/kotlin/org/microg/gms/firebase/auth/ReCaptchaOverlayService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.firebase.auth\n\nimport android.annotation.SuppressLint\nimport android.app.Activity\nimport android.app.Service\nimport android.content.ComponentName\nimport android.content.Context\nimport android.content.Intent\nimport android.content.ServiceConnection\nimport android.graphics.PixelFormat\nimport android.os.Bundle\nimport android.os.IBinder\nimport android.os.ResultReceiver\nimport android.provider.Settings\nimport android.util.DisplayMetrics\nimport android.util.Log\nimport android.view.*\nimport android.webkit.JavascriptInterface\nimport android.webkit.WebSettings\nimport android.webkit.WebView\nimport android.widget.FrameLayout\nimport org.microg.gms.firebase.auth.core.R\nimport org.microg.gms.profile.Build\nimport org.microg.gms.profile.ProfileManager\nimport kotlin.coroutines.resume\nimport kotlin.coroutines.resumeWithException\nimport kotlin.coroutines.suspendCoroutine\n\nprivate const val TAG = \"GmsFirebaseAuthCaptcha\"\n\nclass ReCaptchaOverlayService : Service() {\n\n    private var receiver: ResultReceiver? = null\n    private var hostname: String? = null\n    private var apiKey: String? = null\n\n    private var finished = false\n    private var container: View? = null\n    private var windowManager: WindowManager? = null\n\n    override fun onBind(intent: Intent): IBinder? {\n        init(intent)\n        return null\n    }\n\n    override fun onUnbind(intent: Intent?): Boolean {\n        finishResult(Activity.RESULT_CANCELED)\n        return super.onUnbind(intent)\n    }\n\n    private fun init(intent: Intent) {\n        apiKey = intent.getStringExtra(EXTRA_API_KEY) ?: return finishResult(Activity.RESULT_CANCELED)\n        receiver = intent.getParcelableExtra(EXTRA_RESULT_RECEIVER)\n        hostname = intent.getStringExtra(EXTRA_HOSTNAME) ?: \"localhost:5000\"\n        windowManager = getSystemService(Context.WINDOW_SERVICE) as WindowManager\n        show()\n    }\n\n    @SuppressLint(\"SetJavaScriptEnabled\", \"AddJavascriptInterface\")\n    private fun show() {\n        val layoutParamsType = if (android.os.Build.VERSION.SDK_INT >= 26) {\n            WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY\n        } else {\n            WindowManager.LayoutParams.TYPE_SYSTEM_ALERT\n        }\n\n        val params = WindowManager.LayoutParams(\n                WindowManager.LayoutParams.MATCH_PARENT,\n                WindowManager.LayoutParams.WRAP_CONTENT,\n                layoutParamsType,\n                0,\n                PixelFormat.TRANSLUCENT)\n\n        params.gravity = Gravity.CENTER or Gravity.START\n        params.x = 0\n        params.y = 0\n\n        val interceptorLayout: FrameLayout = object : FrameLayout(this) {\n            override fun dispatchKeyEvent(event: KeyEvent): Boolean {\n                if (event.action == KeyEvent.ACTION_DOWN) {\n                    if (event.keyCode == KeyEvent.KEYCODE_BACK || event.keyCode == KeyEvent.KEYCODE_HOME) {\n                        finishResult(Activity.RESULT_CANCELED)\n                        return true\n                    }\n                }\n                return super.dispatchKeyEvent(event)\n            }\n        }\n\n        val inflater = getSystemService(Context.LAYOUT_INFLATER_SERVICE) as? LayoutInflater?\n        if (inflater != null) {\n            val container = inflater.inflate(R.layout.activity_recaptcha, interceptorLayout)\n            this.container = container\n            container.setBackgroundResource(androidx.appcompat.R.drawable.abc_dialog_material_background)\n            val pad = (5.0 * (resources.displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT)).toInt()\n            container.setOnTouchListener { v, _ ->\n                v.performClick()\n                finishResult(Activity.RESULT_CANCELED)\n                return@setOnTouchListener true\n            }\n            val view = container.findViewById<WebView>(R.id.web)\n            view.setPadding(pad, pad, pad, pad)\n            val settings = view.settings\n            settings.javaScriptEnabled = true\n            settings.useWideViewPort = false\n            settings.setSupportZoom(false)\n            settings.displayZoomControls = false\n            settings.cacheMode = WebSettings.LOAD_NO_CACHE\n            ProfileManager.ensureInitialized(this)\n            settings.userAgentString = Build.generateWebViewUserAgentString(settings.userAgentString)\n            view.addJavascriptInterface(ReCaptchaCallback(this), \"MyCallback\")\n            val captcha = assets.open(\"recaptcha.html\").bufferedReader().readText().replace(\"%apikey%\", apiKey!!)\n            view.loadDataWithBaseURL(\"https://$hostname/\", captcha, null, null, \"https://$hostname/\")\n            windowManager?.addView(container, params)\n        }\n    }\n\n    fun finishResult(resultCode: Int, token: String? = null) {\n        if (!finished) {\n            finished = true\n            receiver?.send(resultCode, token?.let { Bundle().apply { putString(EXTRA_TOKEN, it) } })\n        }\n        container?.let { windowManager?.removeView(it) }\n    }\n\n    companion object {\n\n        private val recaptchaServiceConnection = object : ServiceConnection {\n            override fun onServiceConnected(name: ComponentName?, service: IBinder?) {\n                Log.d(TAG, \"onReCaptchaToken: onServiceConnected: $name\")\n            }\n\n            override fun onServiceDisconnected(name: ComponentName?) {\n                Log.d(TAG, \"onReCaptchaToken: onServiceDisconnected: $name\")\n            }\n        }\n\n        class ReCaptchaCallback(private val overlay: ReCaptchaOverlayService) {\n            @JavascriptInterface\n            fun onReCaptchaToken(token: String) {\n                Log.d(TAG, \"onReCaptchaToken: $token\")\n                overlay.finishResult(Activity.RESULT_OK, token)\n            }\n        }\n\n        fun isSupported(context: Context): Boolean = android.os.Build.VERSION.SDK_INT < 23 || Settings.canDrawOverlays(context)\n\n        suspend fun awaitToken(context: Context, apiKey: String, hostname: String? = null) = suspendCoroutine { continuation ->\n            val intent = Intent(context, ReCaptchaOverlayService::class.java)\n            val resultReceiver = object : ResultReceiver(null) {\n                override fun onReceiveResult(resultCode: Int, resultData: Bundle?) {\n                    context.unbindService(recaptchaServiceConnection)\n                    try {\n                        if (resultCode == Activity.RESULT_OK) {\n                            continuation.resume(resultData?.getString(EXTRA_TOKEN)!!)\n                        }\n                    } catch (e: Exception) {\n                        continuation.resumeWithException(e)\n                    }\n                }\n            }\n            intent.putExtra(EXTRA_API_KEY, apiKey)\n            intent.putExtra(EXTRA_RESULT_RECEIVER, resultReceiver)\n            intent.putExtra(EXTRA_HOSTNAME, hostname)\n            context.bindService(intent, recaptchaServiceConnection, BIND_AUTO_CREATE)\n        }\n    }\n}\n"
  },
  {
    "path": "firebase-auth/core/src/main/kotlin/org/microg/gms/firebase/auth/extensions.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.firebase.auth\n\nconst val EXTRA_TOKEN = \"token\"\nconst val EXTRA_API_KEY = \"api_key\"\nconst val EXTRA_HOSTNAME = \"hostname\"\nconst val EXTRA_RESULT_RECEIVER = \"receiver\""
  },
  {
    "path": "firebase-auth/core/src/main/res/layout/activity_recaptcha.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:minHeight=\"450dp\"\n    android:orientation=\"vertical\">\n\n    <WebView\n        android:id=\"@+id/web\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_gravity=\"center\"\n        android:minHeight=\"450dp\" />\n</FrameLayout>\n"
  },
  {
    "path": "firebase-auth/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<manifest />\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/ActionCodeSettings.aidl",
    "content": "package com.google.firebase.auth;\n\nparcelable ActionCodeSettings;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/EmailAuthCredential.aidl",
    "content": "package com.google.firebase.auth;\n\nparcelable EmailAuthCredential;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/PhoneAuthCredential.aidl",
    "content": "package com.google.firebase.auth;\n\nparcelable PhoneAuthCredential;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/UserProfileChangeRequest.aidl",
    "content": "package com.google.firebase.auth;\n\nparcelable UserProfileChangeRequest;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/api/internal/ApplyActionCodeAidlRequest.aidl",
    "content": "package com.google.firebase.auth.api.internal;\n\nparcelable ApplyActionCodeAidlRequest;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/api/internal/ChangeEmailAidlRequest.aidl",
    "content": "package com.google.firebase.auth.api.internal;\n\nparcelable ChangeEmailAidlRequest;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/api/internal/ChangePasswordAidlRequest.aidl",
    "content": "package com.google.firebase.auth.api.internal;\n\nparcelable ChangePasswordAidlRequest;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/api/internal/CheckActionCodeAidlRequest.aidl",
    "content": "package com.google.firebase.auth.api.internal;\n\nparcelable CheckActionCodeAidlRequest;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/api/internal/ConfirmPasswordResetAidlRequest.aidl",
    "content": "package com.google.firebase.auth.api.internal;\n\nparcelable ConfirmPasswordResetAidlRequest;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/api/internal/CreateAuthUriResponse.aidl",
    "content": "package com.google.firebase.auth.api.internal;\n\nparcelable CreateAuthUriResponse;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/api/internal/CreateUserWithEmailAndPasswordAidlRequest.aidl",
    "content": "package com.google.firebase.auth.api.internal;\n\nparcelable CreateUserWithEmailAndPasswordAidlRequest;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/api/internal/DeleteAidlRequest.aidl",
    "content": "package com.google.firebase.auth.api.internal;\n\nparcelable DeleteAidlRequest;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/api/internal/FinalizeMfaEnrollmentAidlRequest.aidl",
    "content": "package com.google.firebase.auth.api.internal;\n\nparcelable FinalizeMfaEnrollmentAidlRequest;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/api/internal/FinalizeMfaSignInAidlRequest.aidl",
    "content": "package com.google.firebase.auth.api.internal;\n\nparcelable FinalizeMfaSignInAidlRequest;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/api/internal/GetAccessTokenAidlRequest.aidl",
    "content": "package com.google.firebase.auth.api.internal;\n\nparcelable GetAccessTokenAidlRequest;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/api/internal/GetAccountInfoUser.aidl",
    "content": "package com.google.firebase.auth.api.internal;\n\nparcelable GetAccountInfoUser;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/api/internal/GetProvidersForEmailAidlRequest.aidl",
    "content": "package com.google.firebase.auth.api.internal;\n\nparcelable GetProvidersForEmailAidlRequest;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/api/internal/GetTokenResponse.aidl",
    "content": "package com.google.firebase.auth.api.internal;\n\nparcelable GetTokenResponse;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/api/internal/IFirebaseAuthCallbacks.aidl",
    "content": "package com.google.firebase.auth.api.internal;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.firebase.auth.PhoneAuthCredential;\nimport com.google.firebase.auth.api.internal.CreateAuthUriResponse;\nimport com.google.firebase.auth.api.internal.GetAccountInfoUser;\nimport com.google.firebase.auth.api.internal.GetTokenResponse;\nimport com.google.firebase.auth.api.internal.ResetPasswordResponse;\n\ninterface IFirebaseAuthCallbacks {\n    oneway void onGetTokenResponse(in GetTokenResponse response) = 0;\n    oneway void onGetTokenResponseAndUser(in GetTokenResponse response, in GetAccountInfoUser user) = 1;\n    oneway void onCreateAuthUriResponse(in CreateAuthUriResponse response) = 2;\n    oneway void onResetPasswordResponse(in ResetPasswordResponse response) = 3;\n    oneway void onFailure(in Status status) = 4;\n    oneway void onDeleteAccountResponse() = 5;\n    oneway void onEmailVerificationResponse() = 6;\n    //oneway void onSetAccountInfo(String s) = 7\n    oneway void onSendVerificationCodeResponse(String sessionInfo) = 8;\n    oneway void onVerificationCompletedResponse(in PhoneAuthCredential credential) = 9;\n    oneway void onVerificationAutoTimeOut(String sessionInfo) = 10;\n}\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/api/internal/IFirebaseAuthService.aidl",
    "content": "package com.google.firebase.auth.api.internal;\n\nimport com.google.firebase.auth.api.internal.ApplyActionCodeAidlRequest;\nimport com.google.firebase.auth.api.internal.ChangeEmailAidlRequest;\nimport com.google.firebase.auth.api.internal.ChangePasswordAidlRequest;\nimport com.google.firebase.auth.api.internal.CheckActionCodeAidlRequest;\nimport com.google.firebase.auth.api.internal.ConfirmPasswordResetAidlRequest;\nimport com.google.firebase.auth.api.internal.CreateUserWithEmailAndPasswordAidlRequest;\nimport com.google.firebase.auth.api.internal.DeleteAidlRequest;\nimport com.google.firebase.auth.api.internal.FinalizeMfaEnrollmentAidlRequest;\nimport com.google.firebase.auth.api.internal.FinalizeMfaSignInAidlRequest;\nimport com.google.firebase.auth.api.internal.GetAccessTokenAidlRequest;\nimport com.google.firebase.auth.api.internal.GetProvidersForEmailAidlRequest;\nimport com.google.firebase.auth.api.internal.IFirebaseAuthCallbacks;\nimport com.google.firebase.auth.api.internal.LinkEmailAuthCredentialAidlRequest;\nimport com.google.firebase.auth.api.internal.LinkFederatedCredentialAidlRequest;\nimport com.google.firebase.auth.api.internal.LinkPhoneAuthCredentialAidlRequest;\nimport com.google.firebase.auth.api.internal.ReloadAidlRequest;\nimport com.google.firebase.auth.api.internal.SendEmailVerificationWithSettingsAidlRequest;\nimport com.google.firebase.auth.api.internal.SendGetOobConfirmationCodeEmailAidlRequest;\nimport com.google.firebase.auth.api.internal.SendVerificationCodeAidlRequest;\nimport com.google.firebase.auth.api.internal.SendVerificationCodeRequest;\nimport com.google.firebase.auth.api.internal.SetFirebaseUiVersionAidlRequest;\nimport com.google.firebase.auth.api.internal.SignInAnonymouslyAidlRequest;\nimport com.google.firebase.auth.api.internal.SignInWithCredentialAidlRequest;\nimport com.google.firebase.auth.api.internal.SignInWithCustomTokenAidlRequest;\nimport com.google.firebase.auth.api.internal.SignInWithEmailAndPasswordAidlRequest;\nimport com.google.firebase.auth.api.internal.SignInWithEmailLinkAidlRequest;\nimport com.google.firebase.auth.api.internal.SignInWithPhoneNumberAidlRequest;\nimport com.google.firebase.auth.api.internal.StartMfaPhoneNumberEnrollmentAidlRequest;\nimport com.google.firebase.auth.api.internal.StartMfaPhoneNumberSignInAidlRequest;\nimport com.google.firebase.auth.api.internal.UnenrollMfaAidlRequest;\nimport com.google.firebase.auth.api.internal.UnlinkEmailCredentialAidlRequest;\nimport com.google.firebase.auth.api.internal.UnlinkFederatedCredentialAidlRequest;\nimport com.google.firebase.auth.api.internal.UpdateProfileAidlRequest;\nimport com.google.firebase.auth.api.internal.VerifyAssertionRequest;\nimport com.google.firebase.auth.api.internal.VerifyBeforeUpdateEmailAidlRequest;\nimport com.google.firebase.auth.ActionCodeSettings;\nimport com.google.firebase.auth.EmailAuthCredential;\nimport com.google.firebase.auth.PhoneAuthCredential;\nimport com.google.firebase.auth.UserProfileChangeRequest;\n\ninterface IFirebaseAuthService {\n    void getAccessTokenCompat(String refreshToken, IFirebaseAuthCallbacks callbacks) = 0;\n    void signInWithCustomTokenCompat(String token, IFirebaseAuthCallbacks callbacks) = 1;\n    void signInWithCredentialCompat(in VerifyAssertionRequest verifyAssertionRequest, IFirebaseAuthCallbacks callbacks) = 2;\n    void updateProfileCompat(String cachedState, in UserProfileChangeRequest userProfileChangeRequest, IFirebaseAuthCallbacks callbacks) = 3;\n    void changeEmailCompat(String cachedState, String email, IFirebaseAuthCallbacks callbacks) = 4;\n    void changePasswordCompat(String cachedState, String password, IFirebaseAuthCallbacks callbacks) = 5;\n    void createUserWithEmailAndPasswordCompat(String email, String password, IFirebaseAuthCallbacks callbacks) = 6;\n    void signInWithEmailAndPasswordCompat(String email, String password, IFirebaseAuthCallbacks callbacks) = 7;\n    void getProvidersForEmailCompat(String email, IFirebaseAuthCallbacks callbacks) = 8;\n\n    void linkEmailAuthCredentialCompat(String email, String password, String cachedState, IFirebaseAuthCallbacks callbacks) = 10;\n    void linkFederatedCredentialCompat(String cachedState, in VerifyAssertionRequest verifyAssertionRequest, IFirebaseAuthCallbacks callbacks) = 11;\n    void unlinkEmailCredentialCompat(String cachedState, IFirebaseAuthCallbacks callbacks) = 12;\n    void unlinkFederatedCredentialCompat(String provider, String cachedState, IFirebaseAuthCallbacks callbacks) = 13;\n    void reloadCompat(String cachedState, IFirebaseAuthCallbacks callbacks) = 14;\n    void signInAnonymouslyCompat(IFirebaseAuthCallbacks callbacks) = 15;\n    void deleteCompat(String cachedState, IFirebaseAuthCallbacks callbacks) = 16;\n    void checkActionCodeCompat(String code, IFirebaseAuthCallbacks callbacks) = 18;\n    void applyActionCodeCompat(String code, IFirebaseAuthCallbacks callbacks) = 19;\n    void confirmPasswordResetCompat(String code, String newPassword, IFirebaseAuthCallbacks callbacks) = 20;\n    void sendVerificationCodeCompat(in SendVerificationCodeRequest request, IFirebaseAuthCallbacks callbacks) = 21;\n    void signInWithPhoneNumberCompat(in PhoneAuthCredential credential, IFirebaseAuthCallbacks callbacks) = 22;\n    void linkPhoneAuthCredentialCompat(String cachedState, in PhoneAuthCredential credential, IFirebaseAuthCallbacks callbacks) = 23;\n\n    void sendEmailVerificationCompat(String token, in ActionCodeSettings actionCodeSettings, IFirebaseAuthCallbacks callbacks) = 25;\n    void setFirebaseUIVersionCompat(String firebaseUiVersion, IFirebaseAuthCallbacks callbacks) = 26;\n    void sendGetOobConfirmationCodeEmailCompat(String email, in ActionCodeSettings actionCodeSettings, IFirebaseAuthCallbacks callbacks) = 27;\n    void signInWithEmailLinkCompat(in EmailAuthCredential credential, IFirebaseAuthCallbacks callbacks) = 28;\n\n    void getAccessToken(in GetAccessTokenAidlRequest request, IFirebaseAuthCallbacks callbacks) = 100;\n    void signInWithCustomToken(in SignInWithCustomTokenAidlRequest request, IFirebaseAuthCallbacks callbacks) = 101;\n    void signInWithCredential(in SignInWithCredentialAidlRequest request, IFirebaseAuthCallbacks callbacks) = 102;\n    void updateProfile(in UpdateProfileAidlRequest request, IFirebaseAuthCallbacks callbacks) = 103;\n    void changeEmail(in ChangeEmailAidlRequest request, IFirebaseAuthCallbacks callbacks) = 104;\n    void changePassword(in ChangePasswordAidlRequest request, IFirebaseAuthCallbacks callbacks) = 105;\n    void createUserWithEmailAndPassword(in CreateUserWithEmailAndPasswordAidlRequest request, IFirebaseAuthCallbacks callbacks) = 106;\n    void signInWithEmailAndPassword(in SignInWithEmailAndPasswordAidlRequest request, IFirebaseAuthCallbacks callbacks) = 107;\n    void getProvidersForEmail(in GetProvidersForEmailAidlRequest request, IFirebaseAuthCallbacks callbacks) = 108;\n\n    void linkEmailAuthCredential(in LinkEmailAuthCredentialAidlRequest request, IFirebaseAuthCallbacks callbacks) = 110;\n    void linkFederatedCredential(in LinkFederatedCredentialAidlRequest request, IFirebaseAuthCallbacks callbacks) = 111;\n    void unlinkEmailCredential(in UnlinkEmailCredentialAidlRequest request, IFirebaseAuthCallbacks callbacks) = 112;\n    void unlinkFederatedCredential(in UnlinkFederatedCredentialAidlRequest request, IFirebaseAuthCallbacks callbacks) = 113;\n    void reload(in ReloadAidlRequest request, IFirebaseAuthCallbacks callbacks) = 114;\n    void signInAnonymously(in SignInAnonymouslyAidlRequest request, IFirebaseAuthCallbacks callbacks) = 115;\n    void delete(in DeleteAidlRequest request, IFirebaseAuthCallbacks callbacks) = 116;\n    void checkActionCode(in CheckActionCodeAidlRequest request, IFirebaseAuthCallbacks callbacks) = 118;\n    void applyActionCode(in ApplyActionCodeAidlRequest request, IFirebaseAuthCallbacks callbacks) = 119;\n    void confirmPasswordReset(in ConfirmPasswordResetAidlRequest request, IFirebaseAuthCallbacks callbacks) = 120;\n    void sendVerificationCode(in SendVerificationCodeAidlRequest request, IFirebaseAuthCallbacks callbacks) = 121;\n    void signInWithPhoneNumber(in SignInWithPhoneNumberAidlRequest request, IFirebaseAuthCallbacks callbacks) = 122;\n    void linkPhoneAuthCredential(in LinkPhoneAuthCredentialAidlRequest request, IFirebaseAuthCallbacks callbacks) = 123;\n\n    void sendEmailVerification(in SendEmailVerificationWithSettingsAidlRequest request, IFirebaseAuthCallbacks callbacks) = 125;\n    void setFirebaseUiVersion(in SetFirebaseUiVersionAidlRequest request, IFirebaseAuthCallbacks callbacks) = 126;\n    void sendGetOobConfirmationCodeEmail(in SendGetOobConfirmationCodeEmailAidlRequest request, IFirebaseAuthCallbacks callbacks) = 127;\n    void signInWithEmailLink(in SignInWithEmailLinkAidlRequest request, IFirebaseAuthCallbacks callbacks) = 128;\n\n    void startMfaEnrollmentWithPhoneNumber(in StartMfaPhoneNumberEnrollmentAidlRequest request, IFirebaseAuthCallbacks callbacks) = 129;\n    void unenrollMfa(in UnenrollMfaAidlRequest request, IFirebaseAuthCallbacks callbacks) = 130;\n    void finalizeMfaEnrollment(in FinalizeMfaEnrollmentAidlRequest request, IFirebaseAuthCallbacks callbacks) = 131;\n    void startMfaSignInWithPhoneNumber(in StartMfaPhoneNumberSignInAidlRequest request, IFirebaseAuthCallbacks callbacks) = 132;\n    void finalizeMfaSignIn(in FinalizeMfaSignInAidlRequest request, IFirebaseAuthCallbacks callbacks) = 133;\n    void verifyBeforeUpdateEmail(in VerifyBeforeUpdateEmailAidlRequest request, IFirebaseAuthCallbacks callbacks) = 134;\n}\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/api/internal/LinkEmailAuthCredentialAidlRequest.aidl",
    "content": "package com.google.firebase.auth.api.internal;\n\nparcelable LinkEmailAuthCredentialAidlRequest;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/api/internal/LinkFederatedCredentialAidlRequest.aidl",
    "content": "package com.google.firebase.auth.api.internal;\n\nparcelable LinkFederatedCredentialAidlRequest;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/api/internal/LinkPhoneAuthCredentialAidlRequest.aidl",
    "content": "package com.google.firebase.auth.api.internal;\n\nparcelable LinkPhoneAuthCredentialAidlRequest;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/api/internal/ReloadAidlRequest.aidl",
    "content": "package com.google.firebase.auth.api.internal;\n\nparcelable ReloadAidlRequest;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/api/internal/ResetPasswordResponse.aidl",
    "content": "package com.google.firebase.auth.api.internal;\n\nparcelable ResetPasswordResponse;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/api/internal/SendEmailVerificationWithSettingsAidlRequest.aidl",
    "content": "package com.google.firebase.auth.api.internal;\n\nparcelable SendEmailVerificationWithSettingsAidlRequest;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/api/internal/SendGetOobConfirmationCodeEmailAidlRequest.aidl",
    "content": "package com.google.firebase.auth.api.internal;\n\nparcelable SendGetOobConfirmationCodeEmailAidlRequest;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/api/internal/SendVerificationCodeAidlRequest.aidl",
    "content": "package com.google.firebase.auth.api.internal;\n\nparcelable SendVerificationCodeAidlRequest;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/api/internal/SendVerificationCodeRequest.aidl",
    "content": "package com.google.firebase.auth.api.internal;\n\nparcelable SendVerificationCodeRequest;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/api/internal/SetFirebaseUiVersionAidlRequest.aidl",
    "content": "package com.google.firebase.auth.api.internal;\n\nparcelable SetFirebaseUiVersionAidlRequest;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/api/internal/SignInAnonymouslyAidlRequest.aidl",
    "content": "package com.google.firebase.auth.api.internal;\n\nparcelable SignInAnonymouslyAidlRequest;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/api/internal/SignInWithCredentialAidlRequest.aidl",
    "content": "package com.google.firebase.auth.api.internal;\n\nparcelable SignInWithCredentialAidlRequest;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/api/internal/SignInWithCustomTokenAidlRequest.aidl",
    "content": "package com.google.firebase.auth.api.internal;\n\nparcelable SignInWithCustomTokenAidlRequest;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/api/internal/SignInWithEmailAndPasswordAidlRequest.aidl",
    "content": "package com.google.firebase.auth.api.internal;\n\nparcelable SignInWithEmailAndPasswordAidlRequest;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/api/internal/SignInWithEmailLinkAidlRequest.aidl",
    "content": "package com.google.firebase.auth.api.internal;\n\nparcelable SignInWithEmailLinkAidlRequest;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/api/internal/SignInWithPhoneNumberAidlRequest.aidl",
    "content": "package com.google.firebase.auth.api.internal;\n\nparcelable SignInWithPhoneNumberAidlRequest;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/api/internal/StartMfaPhoneNumberEnrollmentAidlRequest.aidl",
    "content": "package com.google.firebase.auth.api.internal;\n\nparcelable StartMfaPhoneNumberEnrollmentAidlRequest;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/api/internal/StartMfaPhoneNumberSignInAidlRequest.aidl",
    "content": "package com.google.firebase.auth.api.internal;\n\nparcelable StartMfaPhoneNumberSignInAidlRequest;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/api/internal/StringList.aidl",
    "content": "package com.google.firebase.auth.api.internal;\n\nparcelable StringList;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/api/internal/UnenrollMfaAidlRequest.aidl",
    "content": "package com.google.firebase.auth.api.internal;\n\nparcelable UnenrollMfaAidlRequest;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/api/internal/UnlinkEmailCredentialAidlRequest.aidl",
    "content": "package com.google.firebase.auth.api.internal;\n\nparcelable UnlinkEmailCredentialAidlRequest;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/api/internal/UnlinkFederatedCredentialAidlRequest.aidl",
    "content": "package com.google.firebase.auth.api.internal;\n\nparcelable UnlinkFederatedCredentialAidlRequest;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/api/internal/UpdateProfileAidlRequest.aidl",
    "content": "package com.google.firebase.auth.api.internal;\n\nparcelable UpdateProfileAidlRequest;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/api/internal/VerifyAssertionRequest.aidl",
    "content": "package com.google.firebase.auth.api.internal;\n\nparcelable VerifyAssertionRequest;\n"
  },
  {
    "path": "firebase-auth/src/main/aidl/com/google/firebase/auth/api/internal/VerifyBeforeUpdateEmailAidlRequest.aidl",
    "content": "package com.google.firebase.auth.api.internal;\n\nparcelable VerifyBeforeUpdateEmailAidlRequest;\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/ActionCodeSettings.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.firebase.auth;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n/**\n * Structure that contains the required continue/state URL with optional Android and iOS bundle identifiers.\n * The stateUrl used to initialize this class is the link/deep link/fallback url used while constructing the Firebase dynamic link.\n */\n@PublicApi\npublic class ActionCodeSettings extends AutoSafeParcelable {\n    @Field(1)\n    @PublicApi(exclude = true)\n    public String url;\n    @Field(2)\n    @PublicApi(exclude = true)\n    public String iOSBundle;\n    @Field(3)\n    @PublicApi(exclude = true)\n    public String iOSAppStoreId;\n    @Field(4)\n    @PublicApi(exclude = true)\n    public String androidPackageName;\n    @Field(5)\n    @PublicApi(exclude = true)\n    public boolean androidInstallApp;\n    @Field(6)\n    @PublicApi(exclude = true)\n    public String androidMinimumVersion;\n    @Field(7)\n    @PublicApi(exclude = true)\n    public boolean handleCodeInApp;\n    @Field(8)\n    @PublicApi(exclude = true)\n    public String localeHeader;\n    @Field(9)\n    @PublicApi(exclude = true)\n    public int requestType;\n    @Field(10)\n    @PublicApi(exclude = true)\n    public String dynamicLinkDomain;\n\n    private ActionCodeSettings() {\n    }\n\n    /**\n     * @return whether the oob code should be handled by the app. See {@link Builder#setHandleCodeInApp(boolean)}\n     */\n    public boolean canHandleCodeInApp() {\n        return handleCodeInApp;\n    }\n\n    /**\n     * @return the preference for whether to attempt to install the app if it is not present. See {@link Builder#setAndroidPackageName(String, boolean, String)}\n     */\n    public boolean getAndroidInstallApp() {\n        return androidInstallApp;\n    }\n\n    /**\n     * @return the minimum Android app version. See {@link Builder#setAndroidPackageName(String, boolean, String)}\n     */\n    public String getAndroidMinimumVersion() {\n        return androidMinimumVersion;\n    }\n\n    /**\n     * @return the Android Package Name. See {@link Builder#setAndroidPackageName(String, boolean, String)}\n     */\n    public String getAndroidPackageName() {\n        return androidPackageName;\n    }\n\n    /**\n     * @return the iOS Bundle. See {@link Builder#setIOSBundleId(String)}\n     */\n    public String getIOSBundle() {\n        return iOSBundle;\n    }\n\n    /**\n     * @return the URL. See {@link Builder#setUrl(String)}\n     */\n    public String getUrl() {\n        return url;\n    }\n\n    /**\n     * @return a new instance of {@link ActionCodeSettings.Builder}.\n     */\n    public static Builder newBuilder() {\n        return new Builder();\n    }\n\n    /**\n     * A Builder class for {@link ActionCodeSettings}. Get an instance of this Builder using {@link #newBuilder()}.\n     */\n    public static class Builder {\n        private String url;\n        private String iOSBundleId;\n        private String androidPackageName;\n        private boolean androidInstallApp;\n        private String androidMinimumVersion;\n        private boolean canHandleCodeInApp;\n        private String dynamicLinkDomain;\n\n        public ActionCodeSettings build() {\n            ActionCodeSettings settings = new ActionCodeSettings();\n            settings.url = url;\n            settings.iOSBundle = iOSBundleId;\n            settings.androidPackageName = androidPackageName;\n            settings.androidInstallApp = androidInstallApp;\n            settings.handleCodeInApp = canHandleCodeInApp;\n            settings.dynamicLinkDomain = dynamicLinkDomain;\n            return settings;\n        }\n\n        /**\n         * Sets the Android package name and returns the current builder instance.\n         * If {@code installIfNotAvailable} is set to true and the link is opened on an android device, it will try to install the app if not already available.\n         * Otherwise the web URL is used.\n         * <p>\n         * A minimum version string is also available. If the installed app is an older version, the user is taken to the Play Store to upgrade the app.\n         */\n        public Builder setAndroidPackageName(String androidPackageName, boolean installIfNotAvailable, String minimumVersion) {\n            this.androidPackageName = androidPackageName;\n            this.androidInstallApp = installIfNotAvailable;\n            this.androidMinimumVersion = minimumVersion;\n            return this;\n        }\n\n        /**\n         * Sets the optional FDL domain, overriding the default FDL domain that would be used.\n         * Must be one of the 5 domains configured in the Firebase console.\n         */\n        public Builder setDynamicLinkDomain(String dynamicLinkDomain) {\n            this.dynamicLinkDomain = dynamicLinkDomain;\n            return this;\n        }\n\n        /**\n         * The default is false. When set to true, the action code link will be sent as a universal link and will be open by the app if installed.\n         * In the false case, the code will be sent to the web widget first and then on continue will redirect to the app if installed.\n         */\n        public Builder setHandleCodeInApp(boolean status) {\n            this.canHandleCodeInApp = status;\n            return this;\n        }\n\n        /**\n         * To be used if the email link that is sent might be opened on an iOS device.\n         * <p>\n         * Sets the iOS bundle Id and returns the current {@link ActionCodeSettings.Builder} instance.\n         */\n        public Builder setIOSBundleId(String iOSBundleId) {\n            this.iOSBundleId = iOSBundleId;\n            return this;\n        }\n\n        /**\n         * Sets the URL, which has different meanings in different contexts. For email actions, this is the state/continue URL.\n         * When the app is not installed, this is the web continue URL with any developer provided state appended (the continueURL query parameter).\n         * When the app is installed, this is contained in the Firebase dynamic link payload.\n         * In the case where the code is sent directly to the app and the app is installed, this is the continueURL query parameter in the dynamic link payload.\n         * Otherwise, when the code is handled by the widget itself, it is the payload itself.\n         */\n        public Builder setUrl(String url) {\n            this.url = url;\n            return this;\n        }\n    }\n\n    public static final Creator<ActionCodeSettings> CREATOR = new AutoCreator<>(ActionCodeSettings.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/AuthCredential.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.firebase.auth;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n/**\n * Represents a credential that the Firebase Authentication server can use to authenticate a user.\n */\n@PublicApi\npublic abstract class AuthCredential extends AutoSafeParcelable {\n    /**\n     * Returns the unique string identifier for the provider type with which the credential is associated.\n     */\n    public abstract String getProvider();\n\n    /**\n     * Returns the unique string identifier for the sign in method with which the credential is associated. Should match that returned by {@link FirebaseAuth#fetchSignInMethodsForEmail(String)} after this user has signed in with this type of credential.\n     */\n    public abstract String getSignInMethod();\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/DefaultOAuthCredential.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.firebase.auth;\n\nimport com.google.firebase.auth.api.internal.VerifyAssertionRequest;\n\nimport org.microg.gms.common.PublicApi;\n\n@PublicApi\npublic class DefaultOAuthCredential extends OAuthCredential {\n    @Field(1)\n    @PublicApi(exclude = true)\n    public String provider;\n    @Field(2)\n    @PublicApi(exclude = true)\n    public String idToken;\n    @Field(3)\n    @PublicApi(exclude = true)\n    public String accessToken;\n    @Field(4)\n    @PublicApi(exclude = true)\n    public VerifyAssertionRequest webSignInToken;\n    @Field(5)\n    @PublicApi(exclude = true)\n    public String pendingToken;\n    @Field(6)\n    @PublicApi(exclude = true)\n    public String secret;\n    @Field(7)\n    @PublicApi(exclude = true)\n    public String rawNonce;\n\n\n    @Override\n    public String getAccessToken() {\n        return accessToken;\n    }\n\n    @Override\n    public String getIdToken() {\n        return idToken;\n    }\n\n    @Override\n    public String getSecret() {\n        return secret;\n    }\n\n    @Override\n    public String getProvider() {\n        return provider;\n    }\n\n    @Override\n    public String getSignInMethod() {\n        return provider;\n    }\n\n    public static final Creator<DefaultOAuthCredential> CREATOR = new AutoCreator<>(DefaultOAuthCredential.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/EmailAuthCredential.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.firebase.auth;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Wraps an email and password tuple for authentication purposes.\n */\n@PublicApi\npublic class EmailAuthCredential extends AuthCredential {\n    @Field(1)\n    @PublicApi(exclude = true)\n    public String email;\n    @Field(2)\n    @PublicApi(exclude = true)\n    public String password;\n    @Field(3)\n    @PublicApi(exclude = true)\n    public String signInLink;\n    @Field(4)\n    @PublicApi(exclude = true)\n    public String cachedState;\n    @Field(5)\n    @PublicApi(exclude = true)\n    public boolean isForLinking;\n\n    /**\n     * Returns the unique string identifier for the provider type with which the credential is associated.\n     */\n    @Override\n    public String getProvider() {\n        return \"password\";\n    }\n\n    /**\n     * Returns either {@link EmailAuthProvider#EMAIL_LINK_SIGN_IN_METHOD} for a credential generated with {@link EmailAuthProvider#getCredentialWithLink(String, String)} or {@link EmailAuthProvider#EMAIL_PASSWORD_SIGN_IN_METHOD} for a credential generated with {@link EmailAuthProvider#getCredential(String, String)}.\n     */\n    @Override\n    public String getSignInMethod() {\n        if (password != null && !password.isEmpty()) {\n            return \"password\";\n        }\n        return \"emailLink\";\n    }\n\n    public static final Creator<EmailAuthCredential> CREATOR = new AutoCreator<>(EmailAuthCredential.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/OAuthCredential.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.firebase.auth;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Holds credentials generated by a sign-in with a credential to an IDP that uses OAuth\n */\n@PublicApi\npublic abstract class OAuthCredential extends AuthCredential {\n    /**\n     * Returns the OAuth access token associated with this credential.\n     */\n    public abstract String getAccessToken();\n\n    /**\n     * Returns the OAuth ID token associated with this credential.\n     */\n    public abstract String getIdToken();\n\n    /**\n     * Returns the OAuth secret associated with this credential. This will be null for OAuth 2.0 providers.\n     */\n    public abstract String getSecret();\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/PhoneAuthCredential.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.firebase.auth;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Wraps phone number and verification information for authentication purposes.\n */\n@PublicApi\npublic class PhoneAuthCredential extends AuthCredential {\n    @Field(1)\n    @PublicApi(exclude = true)\n    public String sessionInfo;\n    @Field(2)\n    @PublicApi(exclude = true)\n    public String smsCode;\n    @Field(3)\n    @PublicApi(exclude = true)\n    public boolean hasVerificationCode;\n    @Field(4)\n    @PublicApi(exclude = true)\n    public String phoneNumber;\n    @Field(5)\n    @PublicApi(exclude = true)\n    public boolean autoCreate;\n    @Field(6)\n    @PublicApi(exclude = true)\n    public String temporaryProof;\n    @Field(7)\n    @PublicApi(exclude = true)\n    public String mfaEnrollmentId;\n\n    /**\n     * Returns the unique string identifier for the provider type with which the credential is associated.\n     */\n    @Override\n    public String getProvider() {\n        return \"phone\";\n    }\n\n    /**\n     * Returns the unique string identifier for the sign in method with which the credential is associated. Should match that returned by {@link FirebaseAuth#fetchSignInMethodsForEmail(String)} after this user has signed in with this type of credential.\n     */\n    @Override\n    public String getSignInMethod() {\n        return \"phone\";\n    }\n\n    /**\n     * Gets the auto-retrieved SMS verification code if applicable. When SMS verification is used, you will be called back first via onCodeSent(String, PhoneAuthProvider.ForceResendingToken), and later onVerificationCompleted(PhoneAuthCredential) with a {@link PhoneAuthCredential} containing a non-null SMS code if auto-retrieval succeeded. If Firebase used another approach to verify the phone number and triggers a callback via onVerificationCompleted(PhoneAuthCredential), then SMS code can be null.\n     */\n    public String getSmsCode() {\n        return smsCode;\n    }\n\n    public static final Creator<PhoneAuthCredential> CREATOR = new AutoCreator<>(PhoneAuthCredential.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/UserProfileChangeRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.firebase.auth;\n\nimport android.net.Uri;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n/**\n * Request used to update user profile information.\n */\n@PublicApi\npublic class UserProfileChangeRequest extends AutoSafeParcelable {\n    @Field(1)\n    @PublicApi(exclude = true)\n    public String displayName;\n    @Field(2)\n    @PublicApi(exclude = true)\n    public String photoUrl;\n    @Field(3)\n    @PublicApi(exclude = true)\n    public boolean shouldRemoveDisplayName;\n    @Field(4)\n    @PublicApi(exclude = true)\n    public boolean shouldRemovePhotoUri;\n\n    private UserProfileChangeRequest() {\n    }\n\n    public String getDisplayName() {\n        return displayName;\n    }\n\n    public Uri getPhotoUri() {\n        return Uri.parse(photoUrl);\n    }\n\n    /**\n     * The request builder.\n     */\n    public static class Builder {\n        private String displayName;\n        private Uri photoUri;\n        private boolean shouldRemoveDisplayName;\n        private boolean shouldRemovePhotoUri;\n\n        /**\n         * Sets the updated display name.\n         * @return the {@link UserProfileChangeRequest.Builder} for chaining\n         */\n        public Builder setDisplayName(String displayName) {\n            this.displayName = displayName;\n            shouldRemoveDisplayName = displayName == null;\n            return this;\n        }\n\n        /**\n         * Sets the updated photo {@link Uri}.\n         * @return the {@link UserProfileChangeRequest.Builder} for chaining\n         */\n        public Builder setPhotoUri(Uri photoUri) {\n            this.photoUri = photoUri;\n            shouldRemovePhotoUri = photoUri == null;\n            return this;\n        }\n\n        /**\n         * Returns a {@link UserProfileChangeRequest} instance\n         */\n        public UserProfileChangeRequest build() {\n            UserProfileChangeRequest request = new UserProfileChangeRequest();\n            request.displayName = displayName;\n            request.photoUrl = photoUri.toString();\n            request.shouldRemoveDisplayName = shouldRemoveDisplayName;\n            request.shouldRemovePhotoUri = shouldRemovePhotoUri;\n            return request;\n        }\n    }\n\n    public static final Creator<UserProfileChangeRequest> CREATOR = new AutoCreator<>(UserProfileChangeRequest.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/ApplyActionCodeAidlRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class ApplyActionCodeAidlRequest extends AutoSafeParcelable {\n    public static final Creator<ApplyActionCodeAidlRequest> CREATOR = new AutoCreator<>(ApplyActionCodeAidlRequest.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/ChangeEmailAidlRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class ChangeEmailAidlRequest extends AutoSafeParcelable {\n    public static final Creator<ChangeEmailAidlRequest> CREATOR = new AutoCreator<>(ChangeEmailAidlRequest.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/ChangePasswordAidlRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class ChangePasswordAidlRequest extends AutoSafeParcelable {\n    public static final Creator<ChangePasswordAidlRequest> CREATOR = new AutoCreator<>(ChangePasswordAidlRequest.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/CheckActionCodeAidlRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class CheckActionCodeAidlRequest extends AutoSafeParcelable {\n    public static final Creator<CheckActionCodeAidlRequest> CREATOR = new AutoCreator<>(CheckActionCodeAidlRequest.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/ConfirmPasswordResetAidlRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class ConfirmPasswordResetAidlRequest extends AutoSafeParcelable {\n    public static final Creator<ConfirmPasswordResetAidlRequest> CREATOR = new AutoCreator<>(ConfirmPasswordResetAidlRequest.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/CreateAuthUriResponse.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class CreateAuthUriResponse extends AutoSafeParcelable {\n    @Field(2)\n    public String authUri;\n    @Field(3)\n    public boolean isRegistered;\n    @Field(4)\n    public String providerId;\n    @Field(5)\n    public boolean isForExistingProvider;\n    @Field(6)\n    public StringList stringList = new StringList();\n    @Field(7)\n    public List<String> signInMethods = new ArrayList<>();\n    public static final Creator<CreateAuthUriResponse> CREATOR = new AutoCreator<>(CreateAuthUriResponse.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/CreateUserWithEmailAndPasswordAidlRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class CreateUserWithEmailAndPasswordAidlRequest extends AutoSafeParcelable {\n    @Field(1)\n    public String email;\n    @Field(2)\n    public String password;\n    @Field(3)\n    public String tenantId;\n\n    public static final Creator<CreateUserWithEmailAndPasswordAidlRequest> CREATOR = new AutoCreator<>(CreateUserWithEmailAndPasswordAidlRequest.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/DeleteAidlRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class DeleteAidlRequest extends AutoSafeParcelable {\n    public static final Creator<DeleteAidlRequest> CREATOR = new AutoCreator<>(DeleteAidlRequest.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/FinalizeMfaEnrollmentAidlRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class FinalizeMfaEnrollmentAidlRequest extends AutoSafeParcelable {\n    public static final Creator<FinalizeMfaEnrollmentAidlRequest> CREATOR = new AutoCreator<>(FinalizeMfaEnrollmentAidlRequest.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/FinalizeMfaSignInAidlRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class FinalizeMfaSignInAidlRequest extends AutoSafeParcelable {\n    public static final Creator<FinalizeMfaSignInAidlRequest> CREATOR = new AutoCreator<>(FinalizeMfaSignInAidlRequest.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/GetAccessTokenAidlRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class GetAccessTokenAidlRequest extends AutoSafeParcelable {\n    @Field(1)\n    public String refreshToken;\n\n    public static final Creator<GetAccessTokenAidlRequest> CREATOR = new AutoCreator<>(GetAccessTokenAidlRequest.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/GetAccountInfoUser.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport com.google.firebase.auth.DefaultOAuthCredential;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\nimport java.util.List;\n\npublic class GetAccountInfoUser extends AutoSafeParcelable {\n    @Field(2)\n    public String localId;\n    @Field(3)\n    public String email;\n    @Field(4)\n    public boolean isEmailVerified;\n    @Field(5)\n    public String displayName;\n    @Field(6)\n    public String photoUrl;\n    @Field(7)\n    public ProviderUserInfoList providerInfoList = new ProviderUserInfoList();\n    @Field(8)\n    public String password;\n    @Field(9)\n    public String phoneNumber;\n    @Field(10)\n    public long creationTimestamp;\n    @Field(11)\n    public long lastSignInTimestamp;\n    @Field(12)\n    public boolean isNewUser;\n    @Field(13)\n    public DefaultOAuthCredential defaultOAuthCredential;\n    @Field(14)\n    public List<MfaInfo> mfaInfoList;\n\n    public static final Creator<GetAccountInfoUser> CREATOR = new AutoCreator<>(GetAccountInfoUser.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/GetProvidersForEmailAidlRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class GetProvidersForEmailAidlRequest extends AutoSafeParcelable {\n    @Field(1)\n    public String email;\n    @Field(2)\n    public String tenantId;\n    public static final Creator<GetProvidersForEmailAidlRequest> CREATOR = new AutoCreator<>(GetProvidersForEmailAidlRequest.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/GetTokenResponse.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class GetTokenResponse extends AutoSafeParcelable {\n    @Field(2)\n    public String refreshToken;\n    @Field(3)\n    public String accessToken;\n    @Field(4)\n    public Long expiresIn;\n    @Field(5)\n    public String tokenType;\n    @Field(6)\n    public Long issuedAt;\n\n    public GetTokenResponse() {\n        issuedAt = System.currentTimeMillis();\n    }\n\n    public static GetTokenResponse parseJson(String json) {\n        try {\n            JSONObject object = new JSONObject(json);\n            GetTokenResponse response = new GetTokenResponse();\n            response.refreshToken = object.optString(\"refresh_token\", null);\n            response.accessToken = object.optString(\"access_token\", null);\n            response.tokenType = object.optString(\"token_type\", null);\n            response.expiresIn = object.optLong(\"expires_in\");\n            response.issuedAt = object.optLong(\"issued_at\");\n            return response;\n        } catch (JSONException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public static final Creator<GetTokenResponse> CREATOR = new AutoCreator<>(GetTokenResponse.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/LinkEmailAuthCredentialAidlRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class LinkEmailAuthCredentialAidlRequest extends AutoSafeParcelable {\n    @Field(1)\n    public String email;\n    @Field(2)\n    public String password;\n    @Field(3)\n    public String cachedState;\n    public static final Creator<LinkEmailAuthCredentialAidlRequest> CREATOR = new AutoCreator<>(LinkEmailAuthCredentialAidlRequest.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/LinkFederatedCredentialAidlRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class LinkFederatedCredentialAidlRequest extends AutoSafeParcelable {\n    public static final Creator<LinkFederatedCredentialAidlRequest> CREATOR = new AutoCreator<>(LinkFederatedCredentialAidlRequest.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/LinkPhoneAuthCredentialAidlRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class LinkPhoneAuthCredentialAidlRequest extends AutoSafeParcelable {\n    public static final Creator<LinkPhoneAuthCredentialAidlRequest> CREATOR = new AutoCreator<>(LinkPhoneAuthCredentialAidlRequest.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/MfaInfo.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class MfaInfo extends AutoSafeParcelable {\n\n\n    public static final Creator<MfaInfo> CREATOR = new AutoCreator<>(MfaInfo.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/ProviderUserInfo.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class ProviderUserInfo extends AutoSafeParcelable {\n    @Field(2)\n    public String federatedId;\n    @Field(3)\n    public String displayName;\n    @Field(4)\n    public String photoUrl;\n    @Field(5)\n    public String providerId;\n    @Field(6)\n    public String rawUserInfo;\n    @Field(7)\n    public String phoneNumber;\n    @Field(8)\n    public String email;\n\n    public static final Creator<ProviderUserInfo> CREATOR = new AutoCreator<>(ProviderUserInfo.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/ProviderUserInfoList.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class ProviderUserInfoList extends AutoSafeParcelable {\n    @Field(2)\n    public List<ProviderUserInfo> providerUserInfos = new ArrayList<>();\n\n\n    public static final Creator<ProviderUserInfoList> CREATOR = new AutoCreator<>(ProviderUserInfoList.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/ReloadAidlRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class ReloadAidlRequest extends AutoSafeParcelable {\n    @Field(1)\n    public String cachedState;\n    public static final Creator<ReloadAidlRequest> CREATOR = new AutoCreator<>(ReloadAidlRequest.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/ResetPasswordResponse.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class ResetPasswordResponse extends AutoSafeParcelable {\n    @Field(2)\n    public String email;\n    @Field(3)\n    public String newEmail;\n    @Field(4)\n    public String requestType;\n    @Field(5)\n    public MfaInfo mfaInfo;\n    public static final Creator<ResetPasswordResponse> CREATOR = new AutoCreator<>(ResetPasswordResponse.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/SendEmailVerificationWithSettingsAidlRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport com.google.firebase.auth.ActionCodeSettings;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class SendEmailVerificationWithSettingsAidlRequest extends AutoSafeParcelable {\n    @Field(1)\n    public String token;\n    @Field(2)\n    public ActionCodeSettings settings;\n    public static final Creator<SendEmailVerificationWithSettingsAidlRequest> CREATOR = new AutoCreator<>(SendEmailVerificationWithSettingsAidlRequest.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/SendGetOobConfirmationCodeEmailAidlRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport com.google.firebase.auth.ActionCodeSettings;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class SendGetOobConfirmationCodeEmailAidlRequest extends AutoSafeParcelable {\n    @Field(1)\n    public String email;\n    @Field(2)\n    public ActionCodeSettings settings;\n    @Field(3)\n    public String tenantId;\n    public static final Creator<SendGetOobConfirmationCodeEmailAidlRequest> CREATOR = new AutoCreator<>(SendGetOobConfirmationCodeEmailAidlRequest.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/SendVerificationCodeAidlRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class SendVerificationCodeAidlRequest extends AutoSafeParcelable {\n    @Field(1)\n    public SendVerificationCodeRequest request;\n    public static final Creator<SendVerificationCodeAidlRequest> CREATOR = new AutoCreator<>(SendVerificationCodeAidlRequest.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/SendVerificationCodeRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class SendVerificationCodeRequest extends AutoSafeParcelable {\n    @Field(1)\n    public String phoneNumber;\n    @Field(2)\n    public Long timeoutInSeconds;\n    @Field(3)\n    public boolean forceNewSmsVerificationSession;\n    @Field(4)\n    public String languageHeader;\n    @Field(5)\n    public String tenantId;\n    @Field(6)\n    public String recaptchaToken;\n\n    public static final Creator<SendVerificationCodeRequest> CREATOR = new AutoCreator<>(SendVerificationCodeRequest.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/SetFirebaseUiVersionAidlRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class SetFirebaseUiVersionAidlRequest extends AutoSafeParcelable {\n    public static final Creator<SetFirebaseUiVersionAidlRequest> CREATOR = new AutoCreator<>(SetFirebaseUiVersionAidlRequest.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/SignInAnonymouslyAidlRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class SignInAnonymouslyAidlRequest extends AutoSafeParcelable {\n    @Field(1)\n    public String tenantId;\n    public static final Creator<SignInAnonymouslyAidlRequest> CREATOR = new AutoCreator<>(SignInAnonymouslyAidlRequest.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/SignInWithCredentialAidlRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class SignInWithCredentialAidlRequest extends AbstractSafeParcelable {\n\n    @Field(1)\n    public VerifyAssertionRequest request;\n\n    public SignInWithCredentialAidlRequest(VerifyAssertionRequest request) {\n        this.request = request;\n    }\n\n    public SignInWithCredentialAidlRequest() {\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<SignInWithCredentialAidlRequest> CREATOR = findCreator(SignInWithCredentialAidlRequest.class);\n\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/SignInWithCustomTokenAidlRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class SignInWithCustomTokenAidlRequest extends AutoSafeParcelable {\n    @Field(1)\n    public String token;\n    @Field(2)\n    public String tenantId;\n\n    public static final Creator<SignInWithCustomTokenAidlRequest> CREATOR = new AutoCreator<>(SignInWithCustomTokenAidlRequest.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/SignInWithEmailAndPasswordAidlRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class SignInWithEmailAndPasswordAidlRequest extends AutoSafeParcelable {\n    @Field(1)\n    public String email;\n    @Field(2)\n    public String password;\n    @Field(3)\n    public String tenantId;\n    public static final Creator<SignInWithEmailAndPasswordAidlRequest> CREATOR = new AutoCreator<>(SignInWithEmailAndPasswordAidlRequest.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/SignInWithEmailLinkAidlRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class SignInWithEmailLinkAidlRequest extends AutoSafeParcelable {\n    public static final Creator<SignInWithEmailLinkAidlRequest> CREATOR = new AutoCreator<>(SignInWithEmailLinkAidlRequest.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/SignInWithPhoneNumberAidlRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport com.google.firebase.auth.PhoneAuthCredential;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class SignInWithPhoneNumberAidlRequest extends AutoSafeParcelable {\n    @Field(1)\n    public PhoneAuthCredential credential;\n    @Field(2)\n    public String tenantId;\n\n    public static final Creator<SignInWithPhoneNumberAidlRequest> CREATOR = new AutoCreator<>(SignInWithPhoneNumberAidlRequest.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/StartMfaPhoneNumberEnrollmentAidlRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class StartMfaPhoneNumberEnrollmentAidlRequest extends AutoSafeParcelable {\n    public static final Creator<StartMfaPhoneNumberEnrollmentAidlRequest> CREATOR = new AutoCreator<>(StartMfaPhoneNumberEnrollmentAidlRequest.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/StartMfaPhoneNumberSignInAidlRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class StartMfaPhoneNumberSignInAidlRequest extends AutoSafeParcelable {\n    public static final Creator<StartMfaPhoneNumberSignInAidlRequest> CREATOR = new AutoCreator<>(StartMfaPhoneNumberSignInAidlRequest.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/StringList.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class StringList extends AutoSafeParcelable {\n    @Field(1)\n    public int versionCode = 1;\n    @Field(2)\n    public List<String> values = new ArrayList<>();\n    public static final Creator<StringList> CREATOR = new AutoCreator<>(StringList.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/UnenrollMfaAidlRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class UnenrollMfaAidlRequest extends AutoSafeParcelable {\n    public static final Creator<UnenrollMfaAidlRequest> CREATOR = new AutoCreator<>(UnenrollMfaAidlRequest.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/UnlinkEmailCredentialAidlRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class UnlinkEmailCredentialAidlRequest extends AutoSafeParcelable {\n    public static final Creator<UnlinkEmailCredentialAidlRequest> CREATOR = new AutoCreator<>(UnlinkEmailCredentialAidlRequest.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/UnlinkFederatedCredentialAidlRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class UnlinkFederatedCredentialAidlRequest extends AutoSafeParcelable {\n    public static final Creator<UnlinkFederatedCredentialAidlRequest> CREATOR = new AutoCreator<>(UnlinkFederatedCredentialAidlRequest.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/UpdateProfileAidlRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport com.google.firebase.auth.UserProfileChangeRequest;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class UpdateProfileAidlRequest extends AutoSafeParcelable {\n    @Field(1)\n    public UserProfileChangeRequest request;\n    @Field(2)\n    public String cachedState;\n    public static final Creator<UpdateProfileAidlRequest> CREATOR = new AutoCreator<>(UpdateProfileAidlRequest.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/VerifyAssertionRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class VerifyAssertionRequest extends AbstractSafeParcelable {\n\n    @Field(2)\n    public String requestUri;\n    @Field(3)\n    public String accessToken;\n    @Field(4)\n    public String idToken;\n    @Field(5)\n    public String instanceId;\n    @Field(6)\n    public String providerId;\n    @Field(7)\n    public String pendingIdToken;\n    @Field(8)\n    public String postBody;\n    @Field(9)\n    public String localId;\n    @Field(10)\n    public boolean returnIdpCredential;\n    @Field(11)\n    public boolean returnSecureToken;\n    @Field(12)\n    public String delegatedProjectNumber;\n    @Field(13)\n    public String sessionId;\n    @Field(14)\n    public String queryParameter;\n    @Field(15)\n    public String tenantId;\n    @Field(16)\n    public boolean returnRefreshToken;\n    @Field(17)\n    public String tenantProjectNumber;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<VerifyAssertionRequest> CREATOR = findCreator(VerifyAssertionRequest.class);\n\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/com/google/firebase/auth/api/internal/VerifyBeforeUpdateEmailAidlRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.auth.api.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class VerifyBeforeUpdateEmailAidlRequest extends AutoSafeParcelable {\n    public static final Creator<VerifyBeforeUpdateEmailAidlRequest> CREATOR = new AutoCreator<>(VerifyBeforeUpdateEmailAidlRequest.class);\n}\n"
  },
  {
    "path": "firebase-auth/src/main/java/org/microg/gms/firebase/auth/Constants.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.firebase.auth;\n\npublic class Constants {\n    public static final String EXTRA_API_KEY = \"com.google.firebase.auth.API_KEY\";\n    public static final String EXTRA_LIBRARY_VERSION = \"com.google.firebase.auth.LIBRARY_VERSION\";\n}\n"
  },
  {
    "path": "firebase-dynamic-links/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2019 e Foundation\n * SPDX-FileCopyrightText: 2020 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\nandroid {\n    namespace \"com.google.firebase.dynamiclinks\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n}\n\ndependencies {\n    // Dependencies from firebase-dynamic-links:21.2.0\n    api 'androidx.annotation:annotation:1.2.0'\n    api project(':play-services-base')\n    api project(':play-services-basement')\n    api project(':play-services-tasks')\n//    api project(':firebase-auth-interop')\n//    api project(':firebase-measurement-connector')\n//    api project(':firebase-common')\n//    api project(':firebase-common-ktx')\n//    api project(':firebase-components')\n    api 'org.jetbrains.kotlin:kotlin-stdlib:1.7.10'\n    annotationProcessor project(':safe-parcel-processor')\n}\n\napply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG API for firebase-dynamic-links'\n\n"
  },
  {
    "path": "firebase-dynamic-links/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2019 e Foundation\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<manifest />\n"
  },
  {
    "path": "firebase-dynamic-links/src/main/aidl/com/google/firebase/dynamiclinks/internal/DynamicLinkData.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2019, e Foundation\n * SPDX-FileCopyrightText: 2021, Google LLC\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.dynamiclinks.internal;\n\nparcelable DynamicLinkData;\n"
  },
  {
    "path": "firebase-dynamic-links/src/main/aidl/com/google/firebase/dynamiclinks/internal/IDynamicLinksCallbacks.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2019, e Foundation\n * SPDX-FileCopyrightText: 2021, Google LLC\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.dynamiclinks.internal;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.firebase.dynamiclinks.internal.DynamicLinkData;\nimport com.google.firebase.dynamiclinks.internal.ShortDynamicLinkImpl;\n\ninterface IDynamicLinksCallbacks {\n    void onStatusDynamicLinkData(in Status status, in DynamicLinkData dldata) = 0;\n    void onStatusShortDynamicLink(in Status status, in ShortDynamicLinkImpl sdlink) = 1;\n}\n"
  },
  {
    "path": "firebase-dynamic-links/src/main/aidl/com/google/firebase/dynamiclinks/internal/IDynamicLinksService.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2019, e Foundation\n * SPDX-FileCopyrightText: 2021, Google LLC\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.dynamiclinks.internal;\n\nimport com.google.firebase.dynamiclinks.internal.IDynamicLinksCallbacks;\nimport android.os.Bundle;\n\ninterface IDynamicLinksService {\n    void getDynamicLink(IDynamicLinksCallbacks callback, String link) = 0;\n    void createShortDynamicLink(IDynamicLinksCallbacks callback, in Bundle extras) = 1;\n}\n"
  },
  {
    "path": "firebase-dynamic-links/src/main/aidl/com/google/firebase/dynamiclinks/internal/ShortDynamicLinkImpl.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2019, e Foundation\n * SPDX-FileCopyrightText: 2021, Google LLC\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.dynamiclinks.internal;\n\nparcelable ShortDynamicLinkImpl;\n"
  },
  {
    "path": "firebase-dynamic-links/src/main/aidl/com/google/firebase/dynamiclinks/internal/WarningImpl.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2019, e Foundation\n * SPDX-FileCopyrightText: 2021, Google LLC\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.dynamiclinks.internal;\n\nparcelable WarningImpl;\n"
  },
  {
    "path": "firebase-dynamic-links/src/main/java/com/google/firebase/dynamiclinks/ShortDynamicLink.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.firebase.dynamiclinks;\n\nimport android.net.Uri;\n\nimport org.microg.gms.common.PublicApi;\n\nimport java.util.List;\n\n/**\n * Response from {@link DynamicLink.Builder#buildShortDynamicLink()} that returns the shortened Dynamic Link, link flow chart, and warnings from the requested Dynamic Link.\n */\n@PublicApi\npublic interface ShortDynamicLink {\n    /**\n     * Gets the preview link to show the link flow chart.\n     */\n    Uri getPreviewLink();\n\n    /**\n     * Gets the short Dynamic Link value.\n     */\n    Uri getShortLink();\n\n    /**\n     * Gets information about potential warnings on link creation.\n     */\n    List<? extends Warning> getWarnings();\n\n    /**\n     * Path generation option for short Dynamic Link length\n     */\n    @interface Suffix {\n        /**\n         * Shorten the path to an unguessable string. Such strings are created by base62-encoding randomly generated\n         * 96-bit numbers, and consist of 17 alphanumeric characters. Use unguessable strings to prevent your Dynamic\n         * Links from being crawled, which can potentially expose sensitive information.\n         */\n        int UNGUESSABLE = 1;\n        /**\n         * Shorten the path to a string that is only as long as needed to be unique, with a minimum length of 4\n         * characters. Use this method if sensitive information would not be exposed if a short Dynamic Link URL were\n         * guessed.\n         */\n        int SHORT = 2;\n    }\n\n    /**\n     * Information about potential warnings on short Dynamic Link creation.\n     */\n    interface Warning {\n        /**\n         * Gets the warning code.\n         *\n         * @deprecated See {@link #getMessage()} for more information on this warning and how to correct it.\n         */\n        @Deprecated\n        String getCode();\n\n        /**\n         * Gets the warning message to help developers improve their requests.\n         */\n        String getMessage();\n    }\n}\n"
  },
  {
    "path": "firebase-dynamic-links/src/main/java/com/google/firebase/dynamiclinks/internal/DynamicLinkData.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2019, e Foundation\n * SPDX-FileCopyrightText: 2021, Google LLC\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.dynamiclinks.internal;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport android.os.Bundle;\nimport android.net.Uri;\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class DynamicLinkData extends AbstractSafeParcelable {\n    @Field(1)\n    public final String dynamicLink;\n\n    @Field(2)\n    public final String deepLink;\n\n    @Field(3)\n    public final int minVersion;\n\n    @Field(4)\n    public final long clickTimestamp;\n\n    @Field(5)\n    public final Bundle extensionBundle;\n\n    @Field(6)\n    public final Uri redirectUrl;\n\n    @Constructor\n    public DynamicLinkData(@Param(1) String dynamicLink, @Param(2) String deepLink, @Param(3) int minVersion, @Param(4) long clickTimestamp, @Param(5) Bundle extensionBundle, @Param(6) Uri redirectUrl) {\n        this.dynamicLink = dynamicLink;\n        this.deepLink = deepLink;\n        this.minVersion = minVersion;\n        this.clickTimestamp = clickTimestamp;\n        this.extensionBundle = extensionBundle;\n        this.redirectUrl = redirectUrl;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"DynamicLinkData\")\n                .field(\"dynamicLink\", dynamicLink)\n                .field(\"deepLink\", deepLink)\n                .field(\"minVersion\", minVersion)\n                .field(\"clickTimestamp\", clickTimestamp)\n                .field(\"extensionBundle\", extensionBundle)\n                .field(\"redirectUrl\", redirectUrl)\n                .end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<DynamicLinkData> CREATOR = findCreator(DynamicLinkData.class);\n}\n"
  },
  {
    "path": "firebase-dynamic-links/src/main/java/com/google/firebase/dynamiclinks/internal/ShortDynamicLinkImpl.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2019, e Foundation\n * SPDX-FileCopyrightText: 2021, Google LLC\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.dynamiclinks.internal;\n\nimport android.net.Uri;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n\npublic class ShortDynamicLinkImpl extends AutoSafeParcelable {\n    @Field(1)\n    public final Uri shortLink;\n\n    @Field(2)\n    public final Uri previewLink;\n\n    @Field(3)\n    public final List<WarningImpl> warnings;\n\n\n    public ShortDynamicLinkImpl() {\n        shortLink = Uri.EMPTY;\n        previewLink = Uri.EMPTY;\n\n        warnings = new ArrayList<>();\n    }\n\n    public ShortDynamicLinkImpl(Uri shortLink, Uri previewLink, List<WarningImpl> warnings) {\n        this.shortLink = shortLink;\n        this.previewLink = previewLink;\n        this.warnings = warnings;\n    }\n\n    public static final Creator<ShortDynamicLinkImpl> CREATOR = new AutoCreator<ShortDynamicLinkImpl>(ShortDynamicLinkImpl.class);\n}\n"
  },
  {
    "path": "firebase-dynamic-links/src/main/java/com/google/firebase/dynamiclinks/internal/WarningImpl.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.firebase.dynamiclinks.internal;\n\nimport com.google.firebase.dynamiclinks.ShortDynamicLink;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class WarningImpl extends AutoSafeParcelable implements ShortDynamicLink.Warning {\n    @Field(1)\n    @Deprecated\n    private int code = 1;\n\n    @Field(2)\n    private final String message;\n\n    private WarningImpl() {\n        this.message = null;\n    }\n\n    public WarningImpl(String message) {\n        this.message = message;\n    }\n\n    @Override\n    public String getCode() {\n        return null;\n    }\n\n    @Override\n    public String getMessage() {\n        return message;\n    }\n\n    public static final Creator<WarningImpl> CREATOR = new AutoCreator<WarningImpl>(WarningImpl.class);\n}\n"
  },
  {
    "path": "gradle/publish-android.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\nandroid {\n    publishing {\n        singleVariant(\"release\") {\n            withSourcesJar()\n            withJavadocJar()\n        }\n    }\n}\n\nafterEvaluate {\n    publishing {\n        publications {\n            release(MavenPublication) {\n                pom {\n                    name = project.name\n                    description = project.description\n                    url = 'https://github.com/microg/GmsCore'\n                    licenses {\n                        license {\n                            name = 'The Apache Software License, Version 2.0'\n                            url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'\n                        }\n                    }\n                    developers {\n                        developer {\n                            id = 'microg'\n                            name = 'microG Team'\n                        }\n                    }\n                    scm {\n                        url = 'https://github.com/microg/GmsCore'\n                        connection = 'scm:git:https://github.com/microg/GmsCore.git'\n                        developerConnection = 'scm:git:ssh://github.com/microg/GmsCore.git'\n                    }\n                }\n\n                from components.release\n            }\n        }\n        if (project.hasProperty('sonatype.username')) {\n            repositories {\n                maven {\n                    name = 'sonatype'\n                    url = 'https://oss.sonatype.org/service/local/staging/deploy/maven2/'\n                    credentials {\n                        username project.getProperty('sonatype.username')\n                        password project.getProperty('sonatype.password')\n                    }\n                }\n            }\n        }\n    }\n    if (project.hasProperty('signing.keyId')) {\n        signing {\n            sign publishing.publications\n        }\n    }\n    tasks.getByPath(\"sourceReleaseJar\").duplicatesStrategy = DuplicatesStrategy.EXCLUDE\n}\n"
  },
  {
    "path": "gradle/publish-java.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\ntask javaSourcesJar(type: Jar) {\n    archiveClassifier.set(\"sources\")\n    from sourceSets.main.allJava\n}\n\njavadoc {\n    classpath = configurations.compileClasspath\n    source = sourceSets.main.allJava\n}\n\ntask javaJavadocsJar(type: Jar) {\n    archiveClassifier.set(\"javadoc\")\n    from javadoc\n}\n\nartifacts {\n    archives javaSourcesJar\n    archives javaJavadocsJar\n}\n\nafterEvaluate {\n    publishing {\n        publications {\n            release(MavenPublication) {\n                pom {\n                    name = project.name\n                    description = project.description\n                    url = 'https://github.com/microg/GmsCore'\n                    licenses {\n                        license {\n                            name = 'The Apache Software License, Version 2.0'\n                            url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'\n                        }\n                    }\n                    developers {\n                        developer {\n                            id = 'microg'\n                            name = 'microG Team'\n                        }\n                    }\n                    scm {\n                        url = 'https://github.com/microg/GmsCore'\n                        connection = 'scm:git:https://github.com/microg/GmsCore.git'\n                        developerConnection = 'scm:git:ssh://github.com/microg/GmsCore.git'\n                    }\n                }\n\n                from components.java\n                artifact javaSourcesJar\n                artifact javaJavadocsJar\n            }\n        }\n        if (project.hasProperty('sonatype.username')) {\n            repositories {\n                maven {\n                    name = 'sonatype'\n                    url = 'https://oss.sonatype.org/service/local/staging/deploy/maven2/'\n                    credentials {\n                        username project.getProperty('sonatype.username')\n                        password project.getProperty('sonatype.password')\n                    }\n                }\n            }\n        }\n    }\n    if (project.hasProperty('signing.keyId')) {\n        signing {\n            sign publishing.publications\n        }\n    }\n}\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "# SPDX-FileCopyrightText: 2015, microG Project Team\n# SPDX-License-Identifier: CC0-1.0\n\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-8.11.1-bin.zip\nnetworkTimeout=10000\nvalidateDistributionUrl=true\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\n"
  },
  {
    "path": "gradle.properties",
    "content": "android.useAndroidX=true\norg.gradle.configuration-cache=true\norg.gradle.caching=true\norg.gradle.jvmargs=-Xmx4096m -XX:+UseParallelGC --add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED\n"
  },
  {
    "path": "gradlew",
    "content": "#!/bin/sh\n\n#\n# Copyright © 2015-2021 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=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\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, 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        org.gradle.wrapper.GradleWrapperMain \\\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=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\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%\" org.gradle.wrapper.GradleWrapperMain %*\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": "play-services/build.gradle",
    "content": "/*\n * Copyright 2013-2015 microG Project Team\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\napply plugin: 'com.android.library'\n\nandroid {\n    namespace \"org.microg.gms\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n\n    lintOptions {\n        disable 'InvalidPackage'\n    }\n}\n\ndependencies {\n    api project(':play-services-base')\n    api project(':play-services-cast')\n    api project(':play-services-gcm')\n    api project(':play-services-location')\n    api project(':play-services-wearable')\n}\n"
  },
  {
    "path": "play-services/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <application />\n</manifest>\n"
  },
  {
    "path": "play-services-ads/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\nandroid {\n    namespace \"com.google.android.gms.ads.impl\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n}\n\napply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG implementation of play-services-ads'\n\ndependencies {\n    implementation 'androidx.browser:browser:1.4.0'\n    implementation 'androidx.collection:collection:1.0.0'\n    implementation 'androidx.core:core:1.0.0'\n    api project(':play-services-ads-base')\n    api project(':play-services-ads-identifier')\n    api project(':play-services-ads-lite')\n//    api project(':play-services-appset')\n    api project(':play-services-basement')\n    api project(':play-services-tasks')\n}\n"
  },
  {
    "path": "play-services-ads/core/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'kotlin-android'\n\ndependencies {\n    api project(':play-services-ads')\n    implementation project(':play-services-base-core')\n\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion\"\n}\n\nandroid {\n    namespace \"org.microg.gms.ads.impl\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    sourceSets {\n        main.java.srcDirs += 'src/main/kotlin'\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n\n    kotlinOptions {\n        jvmTarget = 1.8\n    }\n}\n"
  },
  {
    "path": "play-services-ads/core/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <application>\n        <service android:name=\"org.microg.gms.ads.AdRequestService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.ads.service.START\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </service>\n    </application>\n</manifest>\n"
  },
  {
    "path": "play-services-ads/core/src/main/java/com/google/android/gms/dynamite/descriptors/com/google/android/gms/ads/dynamite/ModuleDescriptor.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.dynamite.descriptors.com.google.android.gms.ads.dynamite;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.content.ContextWrapper;\nimport android.content.SharedPreferences;\nimport android.util.Log;\nimport androidx.annotation.Keep;\n\nimport java.util.Locale;\n\nimport static android.os.Build.DEVICE;\nimport static android.os.Build.DISPLAY;\nimport static android.os.Build.VERSION.RELEASE;\n\n@Keep\npublic class ModuleDescriptor {\n    public static final String MODULE_ID = \"com.google.android.gms.ads.dynamite\";\n    public static final int MODULE_VERSION = 230500001;\n    private static final String TAG = \"AdsDynamiteModule\";\n\n    /**\n     * The ads module might try to access the user agent, requiring initialization on the main thread,\n     * which may result in deadlocks when invoked from any other thread. This only happens with microG,\n     * because we don't use the highly privileged SELinux Sandbox that regular Play Services uses\n     * (which allows apps to read the user-agent from Play Services instead of the WebView). To prevent\n     * the issue we pre-emptively write a user agent in the local storage of the app.\n     */\n    public static void init(Context context) {\n        do {\n            try {\n                injectUserAgentSharedPreference(context);\n            } catch (Exception e) {\n            }\n            if (context instanceof ContextWrapper) {\n                Context baseContext = ((ContextWrapper) context).getBaseContext();\n                if (context == baseContext) break;\n                context = baseContext;\n            } else {\n                break;\n            }\n        } while (context != null);\n    }\n\n    /**\n     * @return A user-agent representing a browser on the current device.\n     */\n    private static String buildDefaultUserAgent() {\n        StringBuilder sb = new StringBuilder();\n        sb.append(\"Mozilla/5.0 (Linux; U; Android\");\n        if (RELEASE != null) sb.append(\" \").append(RELEASE);\n        sb.append(\"; \").append(Locale.getDefault());\n        if (DEVICE != null) {\n            sb.append(\"; \").append(DEVICE);\n            if (DISPLAY != null) sb.append(\" Build/\").append(DISPLAY);\n        }\n        sb.append(\") AppleWebKit/533 Version/4.0 Safari/533\");\n        return sb.toString();\n    }\n\n    @SuppressLint(\"ApplySharedPref\")\n    private static void injectUserAgentSharedPreference(Context context) {\n        SharedPreferences preferences = context.getSharedPreferences(\"admob_user_agent\", Context.MODE_PRIVATE);\n        if (!preferences.contains(\"user_agent\")) {\n            preferences.edit().putString(\"user_agent\", buildDefaultUserAgent()).commit();\n            Log.d(TAG, \"Injected admob_user_agent into package \" + context.getPackageName());\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-ads/core/src/main/kotlin/org/microg/gms/ads/AdRequestService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.ads\n\nimport android.os.Bundle\nimport android.os.Parcel\nimport android.util.Log\nimport com.google.android.gms.ads.internal.ExceptionParcel\nimport com.google.android.gms.ads.internal.NonagonRequestParcel\nimport com.google.android.gms.ads.internal.request.IAdRequestService\nimport com.google.android.gms.ads.internal.request.INonagonStreamingResponseListener\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.common.PackageUtils\nimport org.microg.gms.utils.warnOnTransactionIssues\n\nprivate const val TAG = \"AdRequestService\"\n\nclass AdRequestService : BaseService(TAG, GmsService.ADMOB) {\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        val packageName = PackageUtils.getAndCheckCallingPackage(this, request.packageName)\n            ?: throw IllegalArgumentException(\"Missing package name\")\n        val binder = AdRequestServiceImpl().asBinder()\n        callback.onPostInitComplete(CommonStatusCodes.SUCCESS, binder, Bundle())\n    }\n}\n\nclass AdRequestServiceImpl : IAdRequestService.Stub() {\n    override fun getAdRequest(request: NonagonRequestParcel, listener: INonagonStreamingResponseListener) {\n        Log.d(TAG, \"getAdRequest\")\n        listener.onException(ExceptionParcel().apply {\n            message = \"Not supported\"\n            code = CommonStatusCodes.INTERNAL_ERROR\n        })\n    }\n\n    override fun getSignals(request: NonagonRequestParcel, listener: INonagonStreamingResponseListener) {\n        Log.d(TAG, \"getSignals\")\n        listener.onException(ExceptionParcel().apply {\n            message = \"Not supported\"\n            code = CommonStatusCodes.INTERNAL_ERROR\n        })\n    }\n\n    override fun getUrlAndCacheKey(request: NonagonRequestParcel, listener: INonagonStreamingResponseListener) {\n        Log.d(TAG, \"getUrlAndCacheKey\")\n        listener.onException(ExceptionParcel().apply {\n            message = \"Not supported\"\n            code = CommonStatusCodes.INTERNAL_ERROR\n        })\n    }\n\n    override fun removeCacheUrl(key: String, listener: INonagonStreamingResponseListener) {\n        Log.d(TAG, \"removeCacheUrl\")\n        listener.onException(ExceptionParcel().apply {\n            message = \"Not supported\"\n            code = CommonStatusCodes.INTERNAL_ERROR\n        })\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n}"
  },
  {
    "path": "play-services-ads/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<manifest xmlns:tools=\"http://schemas.android.com/tools\">\n    <uses-sdk tools:overrideLibrary=\"androidx.browser\" />\n</manifest>\n"
  },
  {
    "path": "play-services-ads/src/main/aidl/com/google/android/gms/ads/internal/ExceptionParcel.aidl",
    "content": "package com.google.android.gms.ads.internal;\n\nparcelable ExceptionParcel;"
  },
  {
    "path": "play-services-ads/src/main/aidl/com/google/android/gms/ads/internal/NonagonRequestParcel.aidl",
    "content": "package com.google.android.gms.ads.internal;\n\nparcelable NonagonRequestParcel;"
  },
  {
    "path": "play-services-ads/src/main/aidl/com/google/android/gms/ads/internal/request/IAdRequestService.aidl",
    "content": "package com.google.android.gms.ads.internal.request;\n\nimport com.google.android.gms.ads.internal.NonagonRequestParcel;\nimport com.google.android.gms.ads.internal.request.INonagonStreamingResponseListener;\n\ninterface IAdRequestService {\n    void getAdRequest(in NonagonRequestParcel request, INonagonStreamingResponseListener listener) = 3;\n    void getSignals(in NonagonRequestParcel request, INonagonStreamingResponseListener listener) = 4;\n    void getUrlAndCacheKey(in NonagonRequestParcel request, INonagonStreamingResponseListener listener) = 5;\n    void removeCacheUrl(String key, INonagonStreamingResponseListener listener) = 6;\n}"
  },
  {
    "path": "play-services-ads/src/main/aidl/com/google/android/gms/ads/internal/request/INonagonStreamingResponseListener.aidl",
    "content": "package com.google.android.gms.ads.internal.request;\n\nimport com.google.android.gms.ads.internal.ExceptionParcel;\n\ninterface INonagonStreamingResponseListener {\n    void onSuccess(in ParcelFileDescriptor fd);\n    void onException(in ExceptionParcel exception);\n}"
  },
  {
    "path": "play-services-ads/src/main/java/com/google/android/gms/ads/internal/ExceptionParcel.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.ads.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class ExceptionParcel extends AutoSafeParcelable {\n    @Field(1)\n    public String message;\n    @Field(2)\n    public int code;\n    public static final Creator<ExceptionParcel> CREATOR = new AutoCreator<>(ExceptionParcel.class);\n}\n"
  },
  {
    "path": "play-services-ads/src/main/java/com/google/android/gms/ads/internal/NonagonRequestParcel.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.ads.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class NonagonRequestParcel extends AutoSafeParcelable {\n    public static final Creator<NonagonRequestParcel> CREATOR = new AutoCreator<>(NonagonRequestParcel.class);\n}\n"
  },
  {
    "path": "play-services-ads-base/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\nandroid {\n    namespace \"com.google.android.gms.ads_base\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n}\n\napply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG implementation of play-services-ads-base'\n\ndependencies {\n    api project(':play-services-basement')\n}\n"
  },
  {
    "path": "play-services-ads-base/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<manifest />\n"
  },
  {
    "path": "play-services-ads-identifier/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\nandroid {\n    namespace \"com.google.android.gms.ads.identifier\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n}\n\napply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG implementation of play-services-ads-identifier'\n\ndependencies {\n    api project(':play-services-basement')\n}\n"
  },
  {
    "path": "play-services-ads-identifier/core/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'kotlin-android'\n\ndependencies {\n    api project(':play-services-ads-identifier')\n    implementation project(':play-services-base-core')\n}\n\nandroid {\n    namespace \"org.microg.gms.ads.identifier\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    sourceSets {\n        main.java.srcDirs += 'src/main/kotlin'\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n\n    kotlinOptions {\n        jvmTarget = 1.8\n    }\n\n    lintOptions {\n        disable 'MissingTranslation', 'GetLocales'\n    }\n}\n"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <application>\n        <service android:name=\".AdvertisingIdService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.ads.identifier.service.START\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </service>\n    </application>\n</manifest>\n"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/kotlin/org/microg/gms/ads/identifier/AdvertisingIdService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage org.microg.gms.ads.identifier\n\nimport android.app.Service\nimport android.content.Context\nimport android.content.Intent\nimport android.content.pm.PackageManager\nimport android.os.Binder\nimport android.os.Bundle\nimport android.os.IBinder\nimport android.util.Log\nimport androidx.core.os.bundleOf\nimport com.google.android.gms.ads.identifier.internal.IAdvertisingIdService\nimport org.microg.gms.common.GooglePackagePermission\nimport org.microg.gms.common.PackageUtils\nimport java.util.UUID\n\nconst val TAG = \"AdvertisingId\"\nconst val EMPTY_AD_ID = \"00000000-0000-0000-0000-000000000000\"\n\nclass AdvertisingIdService : Service() {\n    override fun onBind(intent: Intent): IBinder? {\n        return AdvertisingIdServiceImpl(this).asBinder()\n    }\n}\n\nclass MemoryAdvertisingIdConfiguration(context: Context) : AdvertisingIdConfiguration(context) {\n    override val adTrackingLimitedPerApp: MutableMap<Int, Boolean> = hashMapOf()\n    override var adTrackingLimitedGlobally: Boolean = true\n    override var debugLogging: Boolean = false\n    override var adId: String = EMPTY_AD_ID\n    override var debugAdId: String = EMPTY_AD_ID\n\n    init {\n        resetAdvertisingId()\n    }\n}\n\nabstract class AdvertisingIdConfiguration(private val context: Context) {\n    abstract val adTrackingLimitedPerApp: MutableMap<Int, Boolean>\n    abstract var adTrackingLimitedGlobally: Boolean\n    abstract var debugLogging: Boolean\n    abstract var adId: String\n    abstract var debugAdId: String\n\n    fun isAdTrackingLimitedForApp(uid: Int): Boolean {\n        if (adTrackingLimitedGlobally) return true\n        return adTrackingLimitedPerApp[uid] ?: false\n    }\n\n    fun resetAdvertisingId(): String {\n        adId = UUID.randomUUID().toString()\n        debugAdId = UUID.randomUUID().toString().dropLast(12) + \"10ca1ad1abe1\"\n        return if (debugLogging) debugAdId else adId\n    }\n\n    fun getAdvertisingIdForApp(uid: Int): String {\n        if (isAdTrackingLimitedForApp(uid)) return EMPTY_AD_ID\n        try {\n            val packageNames = context.packageManager.getPackagesForUid(uid) ?: return EMPTY_AD_ID\n            for (packageName in packageNames) {\n                val applicationInfo = context.packageManager.getApplicationInfo(packageName, 0)\n                if (applicationInfo.targetSdkVersion > 33) {\n                    if (context.packageManager.checkPermission(\"com.google.android.gms.permission.AD_ID\", packageName) == PackageManager.PERMISSION_DENIED) {\n                        throw SecurityException(\"Permission not granted\")\n                    }\n                }\n            }\n        } catch (e: Exception) {\n            Log.w(TAG, \"Permission check failed\", e)\n            return EMPTY_AD_ID\n        }\n        val adId = if (debugLogging) debugAdId else adId\n        return adId.ifEmpty { resetAdvertisingId() }\n    }\n}\n\nclass AdvertisingIdServiceImpl(private val context: Context) : IAdvertisingIdService.Stub() {\n    private val configuration = MemoryAdvertisingIdConfiguration(context)\n\n    override fun getAdvertisingId(): String {\n        return configuration.getAdvertisingIdForApp(Binder.getCallingUid())\n    }\n\n    override fun isAdTrackingLimited(ignored: Boolean): Boolean {\n        return configuration.isAdTrackingLimitedForApp(Binder.getCallingUid())\n    }\n\n    override fun resetAdvertisingId(packageName: String): String {\n        PackageUtils.checkPackageUid(context, packageName, getCallingUid())\n        PackageUtils.assertGooglePackagePermission(context, GooglePackagePermission.AD_ID)\n        return configuration.resetAdvertisingId()\n    }\n\n    override fun setAdTrackingLimitedGlobally(packageName: String, limited: Boolean) {\n        PackageUtils.checkPackageUid(context, packageName, getCallingUid())\n        PackageUtils.assertGooglePackagePermission(context, GooglePackagePermission.AD_ID)\n        configuration.adTrackingLimitedGlobally = limited\n    }\n\n    override fun setDebugLoggingEnabled(packageName: String, enabled: Boolean): String {\n        PackageUtils.checkPackageUid(context, packageName, getCallingUid())\n        PackageUtils.assertGooglePackagePermission(context, GooglePackagePermission.AD_ID)\n        configuration.debugLogging = enabled\n        return advertisingId\n    }\n\n    override fun isDebugLoggingEnabled(): Boolean {\n        return configuration.debugLogging\n    }\n\n    override fun isAdTrackingLimitedGlobally(): Boolean {\n        PackageUtils.assertGooglePackagePermission(context, GooglePackagePermission.AD_ID)\n        return configuration.adTrackingLimitedGlobally\n    }\n\n    override fun setAdTrackingLimitedForApp(uid: Int, limited: Boolean) {\n        PackageUtils.assertGooglePackagePermission(context, GooglePackagePermission.AD_ID)\n        configuration.adTrackingLimitedPerApp[uid] = limited\n    }\n\n    override fun resetAdTrackingLimitedForApp(uid: Int) {\n        PackageUtils.assertGooglePackagePermission(context, GooglePackagePermission.AD_ID)\n        configuration.adTrackingLimitedPerApp.remove(uid)\n    }\n\n    override fun getAllAppsLimitedAdTrackingConfiguration(): Bundle {\n        PackageUtils.assertGooglePackagePermission(context, GooglePackagePermission.AD_ID)\n        return bundleOf(*configuration.adTrackingLimitedPerApp.map { it.key.toString() to it.value }.toTypedArray())\n    }\n\n    override fun getAdvertisingIdForApp(uid: Int): String {\n        PackageUtils.assertGooglePackagePermission(context, GooglePackagePermission.AD_ID)\n        return configuration.getAdvertisingIdForApp(uid)\n    }\n}\n"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<resources>\n    <string name=\"perm_ad_id_label\">Advertising ID Permission</string>\n    <string name=\"perm_ad_id_description\">Allows a publisher app to access a valid advertising ID directly or indirectly.</string>\n    <string name=\"perm_ad_id_notification_label\">Advertising ID notification</string>\n    <string name=\"perm_ad_id_notification_description\">Allows an app to receive a notification when the advertising ID or limit ad tracking preference of the user is updated.</string>\n</resources>"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-ar/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"perm_ad_id_notification_label\">إشعار مُعَرِّف الإعلان</string>\n    <string name=\"perm_ad_id_label\">إذن مُعَرِّف الإعلان</string>\n    <string name=\"perm_ad_id_notification_description\">يتيح للتطبيق تلقي إشعار عند تحديث مُعَرِّف الإعلان أو تحديد تفضيلات تتبع الإعلانات للمستخدم.</string>\n    <string name=\"perm_ad_id_description\">يتيح لتطبيق الناشر بالوصول إلى مُعَرِّف إعلان صالح بشكل مباشر أو غير مباشر.</string>\n</resources>"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-ast/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"perm_ad_id_notification_description\">Permite qu\\'una aplicación reciba un avisu al anovar la ID de publicidá o al llendar la preferencia de rastrexu publicitariu del usuariu.</string>\n    <string name=\"perm_ad_id_notification_label\">Avisu d\\'ID de publicidá</string>\n    <string name=\"perm_ad_id_description\">Permite que l\\'aplicación d\\'un espublizador acceda in/direutamente a una ID de publicidá.</string>\n    <string name=\"perm_ad_id_label\">Permisu d\\'ID de publicidá</string>\n</resources>\n"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-az/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"perm_ad_id_label\">Reklam ID İcazəsi</string>\n    <string name=\"perm_ad_id_description\">Dərc edici tətbiq birbaşa və ya dolayı yolla etibarlı reklam ID-ə keçid icazəsi verir.</string>\n    <string name=\"perm_ad_id_notification_label\">Reklam ID bildirişi</string>\n    <string name=\"perm_ad_id_notification_description\">İstifadəçinin reklam ID-i və ya reklam izləmə seçiminin məhdudlaşdırılması yeniləndikdə, tətbiqə bildiriş almaq icazəsi verir.</string>\n</resources>"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-be/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"perm_ad_id_label\">Дазвол рэкламнага ідэнтыфікатара</string>\n    <string name=\"perm_ad_id_description\">Дазваляе выдаўцу дадатку прама ці ўскосна атрымліваць доступ да рэкламнага ідэнтыфікатара.</string>\n    <string name=\"perm_ad_id_notification_label\">Апавяшчэнне рэкламнага ідэнтыфікатара</string>\n    <string name=\"perm_ad_id_notification_description\">Дазваляе дадаткам атрымліваць апавяшчэнне калі рэкламны ідэнтыфікатар або перавага аб ліміце рэкламнай сачэння карыстальніка абноўленыя.</string>\n</resources>"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-bn/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n</resources>"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-ca/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"perm_ad_id_label\">Permís d\\'identificador de publicitat</string>\n    <string name=\"perm_ad_id_description\">Permet que una aplicació editorial accedeixi a un identificador de publicitat vàlid directa o indirectament.</string>\n    <string name=\"perm_ad_id_notification_label\">Notificació d\\'identificador de publicitat</string>\n    <string name=\"perm_ad_id_notification_description\">Permet que una aplicació rebi una notificació quan s\\'actualitza l\\'identificador de publicitat o la preferència de limitació del seguiment d\\'anuncis de l\\'usuari.</string>\n</resources>\n"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-cs/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"perm_ad_id_label\">Oprávnění k reklamnímu ID</string>\n    <string name=\"perm_ad_id_description\">Umožní vydavatelské aplikaci přímý nebo nepřímý přístup k platnému reklamnímu ID.</string>\n    <string name=\"perm_ad_id_notification_label\">Oznámení o reklamním ID</string>\n    <string name=\"perm_ad_id_notification_description\">Umožní aplikaci obdržet oznámení při aktualizaci reklamního ID nebo uživatelské předvolby omezení reklamního sledování.</string>\n</resources>"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-de/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"perm_ad_id_notification_description\">Erlaubt einer App, eine Benachrichtigung zu erhalten, wenn sich die Werbe-ID ändert oder der Nutzer das Tracking einschränkt.</string>\n    <string name=\"perm_ad_id_notification_label\">Werbe-ID-Benachrichtigung</string>\n    <string name=\"perm_ad_id_description\">Erlaubt einer App, direkt oder indirekt, auf die Werbe-ID zuzugreifen.</string>\n    <string name=\"perm_ad_id_label\">Werbe-ID-Berechtigung</string>\n</resources>"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-eo/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources></resources>"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-es/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"perm_ad_id_label\">Permiso de identificación publicitaria</string>\n    <string name=\"perm_ad_id_description\">Permite que una aplicación de editor acceda directa o indirectamente a un ID de publicidad válido.</string>\n    <string name=\"perm_ad_id_notification_label\">Notificación del ID de publicidad</string>\n    <string name=\"perm_ad_id_notification_description\">Permite que una aplicación reciba una notificación cuando se actualiza el ID de publicidad o la preferencia de limitar el seguimiento de anuncios del usuario.</string>\n</resources>"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-fa/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"perm_ad_id_label\">مجوز شناسه آگهی</string>\n    <string name=\"perm_ad_id_description\">به یک برنامه ناشر اجازه می‌دهد تا به شیوه مستقیم یا غیرمستقیم به یک شناسه آگهی معتبر دسترسی پیدا کند.</string>\n    <string name=\"perm_ad_id_notification_label\">آگاه‌ساز شناسه آگهی</string>\n    <string name=\"perm_ad_id_notification_description\">به یک برنامه اجازه می‌دهد تا هنگام به‌روزرسانی شناسه آگهی یا تنظیمات ردیابی محدود آگهی کاربر، آگاه‌ساز دریافت کند.</string>\n</resources>\n"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-fi/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"perm_ad_id_notification_description\">Sallii sovelluksen vastaanottaa ilmoituksen, kun käyttäjän mainostunnus tai mainonnan seurantaa rajoittava asetus päivitetään.</string>\n    <string name=\"perm_ad_id_label\">Mainostunnuslupa</string>\n    <string name=\"perm_ad_id_notification_label\">Mainostunnusilmoitus</string>\n    <string name=\"perm_ad_id_description\">Mahdollistaa julkaisijasovellukselle pääsyn voimassa olevaan mainostunnukseen suoraan tai välillisesti.</string>\n</resources>"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-fil/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"perm_ad_id_label\">Pahintulot ng Advertising ID</string>\n    <string name=\"perm_ad_id_description\">Nagbibigay-daan sa isang publisher app na mag-access ng wastong advertising ID nang direkta o hindi direkta.</string>\n    <string name=\"perm_ad_id_notification_label\">Notification ng Advertising ID</string>\n    <string name=\"perm_ad_id_notification_description\">Nagbibigay-daan sa isang app na makatanggap ng notification kapag na-update ang advertising ID o limitahan ang kagustuhan sa pagsubaybay sa ad ng user.</string>\n</resources>"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-fr/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"perm_ad_id_label\">Permission de l\\'identifiant publicitaire</string>\n    <string name=\"perm_ad_id_description\">Autorise une application affichant de la publicité à accéder directement ou indirectement à un identifiant publicitaire valide.</string>\n    <string name=\"perm_ad_id_notification_label\">Notification de l\\'identifiant publicitaire</string>\n    <string name=\"perm_ad_id_notification_description\">Autorise une application à être notifiée de la modification de l\\'identifiant publicitaire ou de la limitation du suivi publicitaire de l\\'utilisateur.</string>\n</resources>"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-ga/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"perm_ad_id_notification_description\">Ligeann sé d’aip fógra a fháil nuair a nuashonraítear an t-aitheantas fógraíochta nó an rogha rianaithe teorann atá ag an úsáideoir.</string>\n    <string name=\"perm_ad_id_notification_label\">Fógra aitheantais fógraíochta</string>\n    <string name=\"perm_ad_id_label\">Cead ID Fógraíochta</string>\n    <string name=\"perm_ad_id_description\">Ligeann sé d’aip foilsitheora rochtain a fháil ar aitheantas bailí fógraíochta go díreach nó go hindíreach.</string>\n</resources>"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-hu/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"perm_ad_id_label\">Hirdetésazonosító engedély</string>\n    <string name=\"perm_ad_id_description\">Engedélyezi a kiadói alkalmazás számára, hogy közvetlenül vagy közvetve hozzáférjen egy érvényes hirdetési azonosítóhoz.</string>\n    <string name=\"perm_ad_id_notification_label\">Hírdetésazonosító értesítés</string>\n</resources>\n"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-in/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"perm_ad_id_description\">Memungkinkan aplikasi penerbit mengakses ID periklanan yang valid secara langsung atau tidak langsung.</string>\n    <string name=\"perm_ad_id_label\">Izin ID Periklanan</string>\n    <string name=\"perm_ad_id_notification_label\">Pemberitahuan ID periklanan</string>\n    <string name=\"perm_ad_id_notification_description\">Memungkinkan aplikasi menerima notifikasi ketika ID periklanan atau batas preferensi pelacakan iklan pengguna diperbarui.</string>\n</resources>\n"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-is/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources></resources>"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-it/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"perm_ad_id_notification_description\">Consente a un\\'app di ricevere una notifica in caso di aggiornamento dell\\'ID pubblicità o della preferenza dell\\'utente relativa alla limitazione del tracciamento degli annunci.</string>\n    <string name=\"perm_ad_id_notification_label\">Notifica sull\\'ID pubblicità</string>\n    <string name=\"perm_ad_id_description\">Consente a un\\'app dell\\'autore di accedere direttamente o indirettamente a un ID pubblicità valido.</string>\n    <string name=\"perm_ad_id_label\">Autorizzazione accesso all\\'ID pubblicità</string>\n</resources>"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-iw/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"perm_ad_id_notification_label\">התראה על מזהה פרסום</string>\n</resources>\n"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-ja/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"perm_ad_id_notification_description\">ユーザーの広告 ID またはトラッキング拒否設定が更新されたときに、アプリが通知を受信できるようにします。</string>\n    <string name=\"perm_ad_id_notification_label\">広告 ID の通知</string>\n    <string name=\"perm_ad_id_description\">外部アプリが有効な広告 ID に直接的または間接的にアクセスできるようにします。</string>\n    <string name=\"perm_ad_id_label\">広告 ID の許可</string>\n</resources>"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-ko/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"perm_ad_id_label\">광고 ID 권한</string>\n    <string name=\"perm_ad_id_description\">퍼블리셔 앱이 유효한 광고 ID에 직접 또는 간접적으로 접근할 수 있도록 합니다.</string>\n    <string name=\"perm_ad_id_notification_label\">광고 ID 알림</string>\n    <string name=\"perm_ad_id_notification_description\">사용자의 광고 ID 또는 광고 추적 제한 설정이 변경되면 앱이 알림을 받을 수 있습니다.</string>\n</resources>\n"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-lv/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"perm_ad_id_label\">Reklāmas identifikatora atļauja</string>\n    <string name=\"perm_ad_id_description\">Ļauj lietotnes izdevējam tieši vai netieši piekļūt derīgam reklāmas identifikatoram.</string>\n    <string name=\"perm_ad_id_notification_label\">Reklāmas identifikatora paziņojums</string>\n    <string name=\"perm_ad_id_notification_description\">Ļauj informēt lietotni, ja mainās reklāmas identifikators vai lietotāja ierobežotie, iestatītie reklāmu izsekošanas iestatījumi.</string>\n</resources>\n"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-lzh/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources></resources>"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-ml/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"perm_ad_id_label\">പരസ്യ ഐഡി അനുമതി</string>\n    <string name=\"perm_ad_id_description\">ഒരു പ്രസാധക ആപ്പിന് സാധുവായ ഒരു പരസ്യ ഐഡി നേരിട്ടോ അല്ലാതെയോ ആക്‌സസ് ചെയ്യാൻ അനുവദിക്കുന്നു.</string>\n    <string name=\"perm_ad_id_notification_label\">പരസ്യ ഐഡി അറിയിപ്പ്</string>\n    <string name=\"perm_ad_id_notification_description\">ഉപയോക്താവിന്റെ പരസ്യ ഐഡി അല്ലെങ്കിൽ പരസ്യ ട്രാക്കിംഗ് മുൻഗണന പരിമിതപ്പെടുത്തുമ്പോൾ ഒരു ആപ്പിന് അറിയിപ്പ് ലഭിക്കാൻ അനുവദിക്കുന്നു.</string>\n</resources>\n"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-nb-rNO/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"perm_ad_id_label\">Tillatelse til reklame-ID</string>\n    <string name=\"perm_ad_id_description\">Lar en app få tilgang til en gyldig reklame-ID direkte eller indirekte.</string>\n    <string name=\"perm_ad_id_notification_label\">Reklame-ID-varsling</string>\n    <string name=\"perm_ad_id_notification_description\">Lar en app bli varslet når reklame-ID-en til brukeren eller innstillingene til denne oppdateres.</string>\n</resources>\n"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-nl/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"perm_ad_id_notification_description\">Staart een app om een bericht te ontvangen wanneer de reclame ID of de beperkte advertentie verkiesbaar is.</string>\n    <string name=\"perm_ad_id_label\">Adverteren van ID Permissie</string>\n    <string name=\"perm_ad_id_description\">Staart een uitgever app toe om toegang te krijgen tot een geldige advertentie ID direct of indirect.</string>\n    <string name=\"perm_ad_id_notification_label\">Adverteren van ID-informatie</string>\n</resources>"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-pl/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"perm_ad_id_notification_description\">Umożliwia aplikacji otrzymywanie powiadomień w przypadku aktualizacji identyfikatora reklamowego lub ograniczenia preferencji śledzenia użytkownika w celach reklamowych.</string>\n    <string name=\"perm_ad_id_notification_label\">Powiadomienie o indentyfikatorze reklamowym</string>\n    <string name=\"perm_ad_id_description\">Umożliwia wydawcy aplikacji na bezpośredni lub pośredni dostęp do ważnego identyfikatora reklamowego.</string>\n    <string name=\"perm_ad_id_label\">Pozwolenie na używanie identyfikatora reklamowego</string>\n</resources>"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-pt/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"perm_ad_id_label\">Permissão do ID de publicidade</string>\n    <string name=\"perm_ad_id_description\">Permite que a app de publicação aceda um ID de publicidade válido direta ou indireto.</string>\n    <string name=\"perm_ad_id_notification_label\">Notificação do ID de publicidade</string>\n    <string name=\"perm_ad_id_notification_description\">Permite que uma app receba uma notificação quando o ID de publicidade muda ou a configuração de limitação de rastreamento de anúncios do utilizador muda.</string>\n</resources>\n"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-pt-rBR/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"perm_ad_id_label\">Permissão do ID de publicidade</string>\n    <string name=\"perm_ad_id_description\">Permite que o app publicante acesse um ID de publicidade válido diretamente ou indiretamente.</string>\n    <string name=\"perm_ad_id_notification_label\">Notificação do ID de publicidade</string>\n    <string name=\"perm_ad_id_notification_description\">Permite que um app receba uma notificação quando o ID de publicidade muda ou a configuração de limitação de rastreamento de anúncios do usuário muda.</string>\n</resources>\n"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-ro/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"perm_ad_id_notification_description\">Permite unei aplicații să primească o notificare atunci când ID-ul de publicitate sau preferința limitată de urmărire a anunțurilor a utilizatorului este actualizată.</string>\n    <string name=\"perm_ad_id_notification_label\">Notificare de identificare publicitară</string>\n    <string name=\"perm_ad_id_description\">Permite unei aplicații de editor să acceseze direct sau indirect un ID de publicitate valid.</string>\n    <string name=\"perm_ad_id_label\">Permisiune de identificare publicitară</string>\n</resources>"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-ru/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"perm_ad_id_notification_description\">Разрешает приложению получать уведомление когда рекламный идентификатор или предпочтение о лимите рекламной слежки пользователя обновлены.</string>\n    <string name=\"perm_ad_id_label\">Разрешение рекламного идентификатора</string>\n    <string name=\"perm_ad_id_description\">Разрешает издателю приложения прямо или косвенно получать доступ к рекламному идентификатору.</string>\n    <string name=\"perm_ad_id_notification_label\">Уведомление рекламного идентификатора</string>\n</resources>"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-sl/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n</resources>"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-sr/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"perm_ad_id_notification_label\">Обавештење за ID оглашавања</string>\n    <string name=\"perm_ad_id_description\">Дозвољава апликацији објављивача да директно или индиректно приступи важећем ID-у оглашавања.</string>\n    <string name=\"perm_ad_id_label\">Дозвола за ID оглашавања</string>\n    <string name=\"perm_ad_id_notification_description\">Дозвољава апликацији да прими обавештење када се ажурира ID оглашавања или ограничење праћења огласа корисника.</string>\n</resources>"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-sv/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"perm_ad_id_notification_description\">Tillåter en app att ta emot ett meddelande när annons-ID eller begränsad annonsspårningsinställning för användaren uppdateras.</string>\n    <string name=\"perm_ad_id_notification_label\">Annons-ID-avisering</string>\n    <string name=\"perm_ad_id_description\">Tillåter en app att få tillgång till ett giltigt annons-ID direkt eller indirekt.</string>\n    <string name=\"perm_ad_id_label\">Behörighet för annons-ID</string>\n</resources>\n"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-ta/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"perm_ad_id_notification_label\">விளம்பர அடையாளம் அறிவிப்பு</string>\n    <string name=\"perm_ad_id_notification_description\">விளம்பர அடையாளம் அல்லது பயனரின் விளம்பர கண்காணிப்பு விருப்பம் புதுப்பிக்கப்படும்போது ஒரு பயன்பாட்டை அறிவிப்பைப் பெற அனுமதிக்கிறது.</string>\n    <string name=\"perm_ad_id_label\">விளம்பர அடையாளம் இசைவு</string>\n    <string name=\"perm_ad_id_description\">சரியான விளம்பர அடையளத்தை நேரடியாகவோ அல்லது மறைமுகமாகவோ அணுக ஒரு வெளியீட்டாளர் பயன்பாட்டை அனுமதிக்கிறது.</string>\n</resources>\n"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-th/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"perm_ad_id_label\">การอนุญาต ID โฆษณา</string>\n    <string name=\"perm_ad_id_notification_label\">การแจ้งเตือน รหัสประจำตัวของโฆษณา</string>\n    <string name=\"perm_ad_id_description\">อนุญาตให้แอปของผู้เผยแพร่เข้าถึง ID โฆษณาที่ถูกต้องได้โดยตรงหรือโดยอ้อม</string>\n    <string name=\"perm_ad_id_notification_description\">อนุญาตให้แอปรับการแจ้งเตือนเมื่อมีการอัปเดต รหัสประจำตัวของโฆษณา หรือ การตั้งค่าการติดตามโฆษณาของผู้ใช้</string>\n</resources>\n"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-tr/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"perm_ad_id_label\">Reklam kimliği izni</string>\n    <string name=\"perm_ad_id_notification_label\">Reklam kimliği bildirimi</string>\n    <string name=\"perm_ad_id_notification_description\">Bir uygulamanın, kullanıcının reklam takibini kısıtlama ayarını veya reklam kimliğini değiştirdiğinde bildirim almasına izin verir.</string>\n    <string name=\"perm_ad_id_description\">Bir uygulamanın geçerli bir reklam kimliğine doğrudan veya dolaylı olarak erişmesine izin verir.</string>\n</resources>"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-ug/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"perm_ad_id_notification_label\">ئېلان كىملىك ئۇقتۇرۇشى</string>\n    <string name=\"perm_ad_id_label\">ئېلان كىملىك ئىجازىتى</string>\n    <string name=\"perm_ad_id_notification_description\">ئەپنىڭ ئىشلەتكۈچى ئېلان كىملىكى ياكى ئېلان ئىزلاشنى چەكلەش مايىللىقى ئۆزگەرگەندە ئۇقتۇرۇش تاپشۇرۇۋېلىشىغا يول قويىدۇ.</string>\n    <string name=\"perm_ad_id_description\">تارقاتقۇچىنىڭ ئەپىنىڭ بىۋاسىتە ياكى ۋاسىتىلىك ھالدا ئېلان كىملىكىنى زىيارەت قىلىشىغا يول قويىدۇ.</string>\n</resources>\n"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-uk/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"perm_ad_id_notification_description\">Дозволяє програмі отримувати сповіщення, коли рекламний ідентифікатор або обмеження налаштувань відстеження реклами користувача оновлюється.</string>\n    <string name=\"perm_ad_id_notification_label\">Сповіщення рекламного ідентифікатора</string>\n    <string name=\"perm_ad_id_description\">Дозволяє застосунку видавця отримувати доступ до дійсного рекламного ідентифікатор прямо або опосередковано.</string>\n    <string name=\"perm_ad_id_label\">Дозвіл на рекламний ідентифікатор</string>\n</resources>"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-vi/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"perm_ad_id_notification_description\">Cho phép một ứng dụng nhận thông báo khi ID quảng cáo hoặc tùy chọn giới hạn theo dõi quảng cáo của người dùng được cập nhật.</string>\n    <string name=\"perm_ad_id_label\">Quyền truy cập ID quảng cáo</string>\n    <string name=\"perm_ad_id_notification_label\">Thông báo về ID quảng cáo</string>\n    <string name=\"perm_ad_id_description\">Cho phép ứng dụng của nhà phát hành truy cập trực tiếp hoặc gián tiếp vào ID quảng cáo hợp lệ.</string>\n</resources>\n"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-zh-rCN/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"perm_ad_id_label\">广告 ID 权限</string>\n    <string name=\"perm_ad_id_description\">允许发布者应用直接或间接地访问广告 ID。</string>\n    <string name=\"perm_ad_id_notification_label\">广告 ID 通知</string>\n    <string name=\"perm_ad_id_notification_description\">允许应用在用户的广告 ID 或限制广告跟踪设置更改时接收通知。</string>\n</resources>"
  },
  {
    "path": "play-services-ads-identifier/core/src/main/res/values-zh-rTW/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"perm_ad_id_label\">廣告 ID 權限</string>\n    <string name=\"perm_ad_id_notification_label\">廣告 ID 通知</string>\n    <string name=\"perm_ad_id_notification_description\">允許應用程式在使用者更新廣告 ID 或限制廣告追蹤設定時收到通知。</string>\n    <string name=\"perm_ad_id_description\">允許發布商應用程式直接或間接存取有效的廣告 ID。</string>\n</resources>"
  },
  {
    "path": "play-services-ads-identifier/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<manifest />\n"
  },
  {
    "path": "play-services-ads-identifier/src/main/aidl/com/google/android/gms/ads/identifier/internal/IAdvertisingIdService.aidl",
    "content": "package com.google.android.gms.ads.identifier.internal;\n\nimport android.os.Bundle;\n\ninterface IAdvertisingIdService {\n    String getAdvertisingId() = 0;\n    boolean isAdTrackingLimited(boolean ignored) = 1;\n    String resetAdvertisingId(String packageName) = 2;\n    void setAdTrackingLimitedGlobally(String packageName, boolean limited) = 3;\n    String setDebugLoggingEnabled(String packageName, boolean enabled) = 4;\n    boolean isDebugLoggingEnabled() = 5;\n    boolean isAdTrackingLimitedGlobally() = 6;\n    void setAdTrackingLimitedForApp(int uid, boolean limited) = 7;\n    void resetAdTrackingLimitedForApp(int uid) = 8;\n    Bundle getAllAppsLimitedAdTrackingConfiguration() = 9; // Map packageName -> Boolean\n    String getAdvertisingIdForApp(int uid) = 10;\n}\n"
  },
  {
    "path": "play-services-ads-identifier/src/main/java/com/google/android/gms/ads/identifier/AdvertisingIdClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.ads.identifier;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.provider.Settings;\nimport com.google.android.gms.common.GooglePlayServicesNotAvailableException;\nimport com.google.android.gms.common.GooglePlayServicesRepairableException;\n\nimport java.io.IOException;\n\n/**\n * Helper library for retrieval of advertising ID and related information such as the limit ad tracking setting.\n * <p>\n * It is intended that the advertising ID completely replace existing usage of other identifiers for ads purposes (such as use\n * of {@code ANDROID_ID} in {@link Settings.Secure}) when Google Play Services is available. Cases where Google Play Services is\n * unavailable are indicated by a {@link GooglePlayServicesNotAvailableException} being thrown by getAdvertisingIdInfo().\n */\npublic class AdvertisingIdClient {\n    /**\n     * Retrieves the user's advertising ID and limit ad tracking preference.\n     * <p>\n     * This method cannot be called in the main thread as it may block leading to ANRs. An {@code IllegalStateException} will be\n     * thrown if this is called on the main thread.\n     *\n     * @param context Current {@link Context} (such as the current {@link Activity}).\n     * @return AdvertisingIdClient.Info with user's advertising ID and limit ad tracking preference.\n     * @throws IOException                             signaling connection to Google Play Services failed.\n     * @throws IllegalStateException                   indicating this method was called on the main thread.\n     * @throws GooglePlayServicesNotAvailableException indicating that Google Play is not installed on this device.\n     * @throws GooglePlayServicesRepairableException   indicating that there was a recoverable error connecting to Google Play Services.\n     */\n    public static Info getAdvertisingIdInfo(Context context) {\n        // We don't actually implement this functionality, but always claim that ad tracking was limited by user preference\n        return new Info(\"00000000-0000-0000-0000-000000000000\", true);\n    }\n\n    /**\n     * Includes both the advertising ID as well as the limit ad tracking setting.\n     */\n    public static class Info {\n        private final String advertisingId;\n        private final boolean limitAdTrackingEnabled;\n\n        /**\n         * Constructs an {@code Info} Object with the specified advertising Id and limit ad tracking setting.\n         *\n         * @param advertisingId          The advertising ID.\n         * @param limitAdTrackingEnabled The limit ad tracking setting. It is true if the user has limit ad tracking enabled. False, otherwise.\n         */\n        public Info(String advertisingId, boolean limitAdTrackingEnabled) {\n            this.advertisingId = advertisingId;\n            this.limitAdTrackingEnabled = limitAdTrackingEnabled;\n        }\n\n        /**\n         * Retrieves the advertising ID.\n         */\n        public String getId() {\n            return advertisingId;\n        }\n\n        /**\n         * Retrieves whether the user has limit ad tracking enabled or not.\n         * <p>\n         * When the returned value is true, the returned value of {@link #getId()} will always be\n         * {@code 00000000-0000-0000-0000-000000000000} starting with Android 12.\n         */\n        public boolean isLimitAdTrackingEnabled() {\n            return limitAdTrackingEnabled;\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-ads-identifier/src/main/java/com/google/android/gms/ads/identifier/package-info.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n/**\n * Contains classes relating to the Android Advertising ID (AAID).\n */\npackage com.google.android.gms.ads.identifier;\n"
  },
  {
    "path": "play-services-ads-lite/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\nandroid {\n    namespace \"com.google.android.gms.ads\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n}\n\napply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG implementation of play-services-ads-lite'\n\ndependencies {\n    api 'androidx.work:work-runtime:2.7.0'\n    api project(':play-services-ads-base')\n    api project(':play-services-basement')\n//    api project(':play-services-measurement-sdk-api')\n//    api project(':user-messaging-platform')\n}\n"
  },
  {
    "path": "play-services-ads-lite/core/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'kotlin-android'\n\ndependencies {\n    api project(':play-services-ads-lite')\n    implementation project(':play-services-base-core')\n}\n\nandroid {\n    namespace \"org.microg.gms.ads\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    sourceSets {\n        main.java.srcDirs += 'src/main/kotlin'\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n\n    kotlinOptions {\n        jvmTarget = 1.8\n    }\n}\n"
  },
  {
    "path": "play-services-ads-lite/core/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n</manifest>\n"
  },
  {
    "path": "play-services-ads-lite/core/src/main/kotlin/com/google/android/gms/ads/AdLoaderBuilderCreatorImpl.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.ads\n\nimport android.os.IBinder\nimport android.os.Parcel\nimport android.util.Log\nimport androidx.annotation.Keep\nimport com.google.android.gms.ads.internal.client.IAdLoaderBuilderCreator\nimport com.google.android.gms.ads.internal.mediation.client.IAdapterCreator\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport org.microg.gms.utils.warnOnTransactionIssues\n\nprivate const val TAG = \"AdLoaderBuilder\"\n\n@Keep\nclass AdLoaderBuilderCreatorImpl : IAdLoaderBuilderCreator.Stub() {\n    override fun newAdLoaderBuilder(context: IObjectWrapper?, adUnitId: String, adapterCreator: IAdapterCreator?, clientVersion: Int): IBinder? {\n        Log.d(TAG, \"newAdLoaderBuilder: adUnitId=$adUnitId clientVersion=$clientVersion\")\n        return null\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n}\n"
  },
  {
    "path": "play-services-ads-lite/core/src/main/kotlin/com/google/android/gms/ads/AdManagerCreatorImpl.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.ads\n\nimport android.os.Parcel\nimport androidx.annotation.Keep\nimport org.microg.gms.utils.warnOnTransactionIssues\n\nprivate const val TAG = \"AdManager\"\n\n@Keep\nclass AdManagerCreatorImpl : AdManagerCreator.Stub() {\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =\n        warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n}\n"
  },
  {
    "path": "play-services-ads-lite/core/src/main/kotlin/com/google/android/gms/ads/MobileAdsSettingManagerCreatorImpl.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.ads\n\nimport android.content.Context\nimport android.os.IBinder\nimport android.os.Parcel\nimport android.util.Log\nimport androidx.annotation.Keep\nimport com.google.android.gms.ads.internal.client.IMobileAdsSettingManagerCreator\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.ObjectWrapper\nimport org.microg.gms.ads.MobileAdsSettingManagerImpl\nimport org.microg.gms.utils.warnOnTransactionIssues\n\nprivate const val TAG = \"AdsSettingManager\"\n\n@Keep\nclass MobileAdsSettingManagerCreatorImpl : IMobileAdsSettingManagerCreator.Stub() {\n    override fun getMobileAdsSettingManager(context: IObjectWrapper?, clientVersion: Int): IBinder {\n        Log.d(TAG, \"getMobileAdsSettingManager($clientVersion)\")\n        return MobileAdsSettingManagerImpl(ObjectWrapper.unwrap(context) as Context)\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n}\n\n"
  },
  {
    "path": "play-services-ads-lite/core/src/main/kotlin/com/google/android/gms/ads/measurement/DynamiteMeasurementManager.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.ads.measurement\n\nimport android.os.Parcel\nimport android.util.Log\nimport androidx.annotation.Keep\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport org.microg.gms.utils.warnOnTransactionIssues\n\nprivate const val TAG = \"DynamiteMeasurement\"\n\n@Keep\nclass DynamiteMeasurementManager : IMeasurementManager.Stub() {\n\n    override fun initialize(context: IObjectWrapper?, proxy: IAppMeasurementProxy?) {\n        Log.d(TAG, \"Not yet implemented: initialize\")\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =\n        warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n}\n"
  },
  {
    "path": "play-services-ads-lite/core/src/main/kotlin/com/google/android/gms/ads/rewarded/ChimeraRewardedAdCreatorImpl.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.ads.rewarded\n\nimport android.content.Context\nimport android.os.IBinder\nimport android.util.Log\nimport androidx.annotation.Keep\nimport com.google.android.gms.ads.internal.mediation.client.IAdapterCreator\nimport com.google.android.gms.ads.internal.rewarded.client.IRewardedAdCreator\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.ObjectWrapper\nimport org.microg.gms.ads.rewarded.RewardedAdImpl\n\nprivate const val TAG = \"RewardedAd\"\n\n@Keep\nclass ChimeraRewardedAdCreatorImpl : IRewardedAdCreator.Stub() {\n    override fun newRewardedAd(context: IObjectWrapper, str: String, adapterCreator: IAdapterCreator, clientVersion: Int): IBinder {\n        Log.d(TAG, \"newRewardedAd($str, $clientVersion)\")\n        return RewardedAdImpl(ObjectWrapper.unwrap(context) as Context?, str, adapterCreator, clientVersion)\n    }\n}\n\n"
  },
  {
    "path": "play-services-ads-lite/core/src/main/kotlin/org/microg/gms/ads/MobileAdsSettingManagerImpl.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage org.microg.gms.ads\n\nimport android.content.Context\nimport android.os.Handler\nimport android.os.Looper\nimport android.os.Parcel\nimport android.os.RemoteException\nimport android.util.Log\nimport com.google.android.gms.ads.internal.AdapterStatusParcel\nimport com.google.android.gms.ads.internal.RequestConfigurationParcel\nimport com.google.android.gms.ads.internal.client.IMobileAdsSettingManager\nimport com.google.android.gms.ads.internal.client.IOnAdInspectorClosedListener\nimport com.google.android.gms.ads.internal.initialization.IInitializationCallback\nimport com.google.android.gms.ads.internal.mediation.client.IAdapterCreator\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport org.microg.gms.utils.warnOnTransactionIssues\n\nprivate const val TAG = \"AdsSettingManager\"\n\nclass MobileAdsSettingManagerImpl(private val context: Context?) : IMobileAdsSettingManager.Stub() {\n    private var initialized = false\n    private val initializationCallbacks = mutableListOf<IInitializationCallback>()\n    private var muted = false\n    private var volume = 1.0f\n\n    override fun initialize() {\n        Log.d(TAG, \"initialize\")\n        if (initialized) return\n        initialized = true\n        for (callback in initializationCallbacks) {\n            runCatching { callback.onInitialized(emptyList()) }\n        }\n    }\n\n    override fun setAppVolume(volume: Float) {\n        this.volume = volume\n    }\n\n    override fun fetchAppSettings(appId: String?) {\n        fetchAppSettingsV2(appId, null)\n    }\n\n    override fun setAppMuted(muted: Boolean) {\n        this.muted = muted\n    }\n\n    override fun openDebugMenu(context: IObjectWrapper?, adUnitId: String?) {\n        Log.d(TAG, \"openDebugMenu($adUnitId)\")\n    }\n\n    override fun fetchAppSettingsV2(appId: String?, runnable: IObjectWrapper?) {\n        Log.d(TAG, \"fetchAppSettings($appId)\")\n    }\n\n    override fun getAdVolume(): Float {\n        return volume\n    }\n\n    override fun isAdMuted(): Boolean {\n        return muted\n    }\n\n    override fun getVersionString(): String {\n        return \"\"\n    }\n\n    override fun registerRtbAdapter(className: String?) {\n        Log.d(TAG, \"registerRtbAdapter($className)\")\n    }\n\n    override fun setAdapterCreator(iAdapterCreator: IAdapterCreator?) {\n        Log.d(TAG, \"Not yet implemented: setAdapterCreator\")\n    }\n\n    override fun addInitializationCallback(callback: IInitializationCallback?) {\n        Log.d(TAG, \"addInitializationCallback\")\n        callback?.let { initializationCallbacks.add(it) }\n    }\n\n    override fun getAdapterStatus(): List<AdapterStatusParcel> {\n        Log.d(TAG, \"getAdapterStatus\")\n        return arrayListOf(AdapterStatusParcel(\"com.google.android.gms.ads.MobileAds\", true, 0, \"Dummy\"))\n    }\n\n    override fun setRequestConfiguration(configuration: RequestConfigurationParcel?) {\n        Log.d(TAG, \"setRequestConfiguration\")\n    }\n\n    override fun disableMediationAdapterInitialization() {\n        Log.d(TAG, \"disableMediationAdapterInitialization\")\n    }\n\n    override fun openAdInspector(listener: IOnAdInspectorClosedListener?) {\n        Log.d(TAG, \"openAdInspector\")\n    }\n\n    override fun enableSameAppKey(enabled: Boolean) {\n        Log.d(TAG, \"enableSameAppKey($enabled)\")\n    }\n\n    override fun setPlugin(plugin: String?) {\n        Log.d(TAG, \"setPlugin($plugin)\")\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n}"
  },
  {
    "path": "play-services-ads-lite/core/src/main/kotlin/org/microg/gms/ads/rewarded/ResponseInfoImpl.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.ads.rewarded\n\nimport android.os.Bundle\nimport android.util.Log\nimport com.google.android.gms.ads.internal.AdapterResponseInfoParcel\nimport com.google.android.gms.ads.internal.client.IResponseInfo\n\nprivate const val TAG = \"RewardedAdResponseInfo\"\n\nclass ResponseInfoImpl : IResponseInfo.Stub() {\n    override fun getMediationAdapterClassName(): String? {\n        Log.d(TAG, \"getMediationAdapterClassName\")\n        return null\n    }\n\n    override fun getResponseId(): String? {\n        Log.d(TAG, \"getResponseId\")\n        return null\n    }\n\n    override fun getAdapterResponseInfo(): List<AdapterResponseInfoParcel> {\n        Log.d(TAG, \"getAdapterResponseInfo\")\n        return arrayListOf()\n    }\n\n    override fun getLoadedAdapterResponse(): AdapterResponseInfoParcel? {\n        Log.d(TAG, \"getLoadedAdapterResponse\")\n        return null\n    }\n\n    override fun getResponseExtras(): Bundle {\n        Log.d(TAG, \"getResponseExtras\")\n        return Bundle()\n    }\n}"
  },
  {
    "path": "play-services-ads-lite/core/src/main/kotlin/org/microg/gms/ads/rewarded/RewardedAdImpl.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.ads.rewarded\n\nimport android.content.Context\nimport android.os.Bundle\nimport android.os.Handler\nimport android.os.Looper\nimport android.os.RemoteException\nimport android.util.Log\nimport com.google.android.gms.ads.internal.AdErrorParcel\nimport com.google.android.gms.ads.internal.AdRequestParcel\nimport com.google.android.gms.ads.internal.ServerSideVerificationOptionsParcel\nimport com.google.android.gms.ads.internal.client.IOnAdMetadataChangedListener\nimport com.google.android.gms.ads.internal.client.IOnPaidEventListener\nimport com.google.android.gms.ads.internal.client.IResponseInfo\nimport com.google.android.gms.ads.internal.mediation.client.IAdapterCreator\nimport com.google.android.gms.ads.internal.rewarded.client.*\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.dynamic.IObjectWrapper\n\nprivate const val TAG = \"RewardedAd\"\n\nclass RewardedAdImpl(context: Context?, str: String?, adapterCreator: IAdapterCreator?, clientVersion: Int) : IRewardedAd.Stub() {\n    private var immersive: Boolean = false\n\n    private fun load(request: AdRequestParcel, callback: IRewardedAdLoadCallback, interstitial: Boolean) {\n        Handler(Looper.getMainLooper()).post {\n            try {\n                callback.onAdLoadError(AdErrorParcel().apply { code = CommonStatusCodes.INTERNAL_ERROR; message = \"Not supported\" })\n            } catch (e: RemoteException) {\n                Log.w(TAG, e)\n            }\n        }\n    }\n\n    override fun load(request: AdRequestParcel, callback: IRewardedAdLoadCallback) {\n        Log.d(TAG, \"load\")\n        load(request, callback, false)\n    }\n\n    override fun setCallback(callback: IRewardedAdCallback) {\n        Log.d(TAG, \"setCallback\")\n    }\n\n    override fun canBeShown(): Boolean {\n        Log.d(TAG, \"canBeShown\")\n        return false\n    }\n\n    override fun getMediationAdapterClassName(): String {\n        Log.d(TAG, \"getMediationAdapterClassName\")\n        return responseInfo.mediationAdapterClassName\n    }\n\n    override fun show(activity: IObjectWrapper) {\n        Log.d(TAG, \"show\")\n        showWithImmersive(activity, immersive)\n    }\n\n    override fun setRewardedAdSkuListener(listener: IRewardedAdSkuListener?) {\n        Log.d(TAG, \"setRewardedAdSkuListener\")\n    }\n\n    override fun setServerSideVerificationOptions(options: ServerSideVerificationOptionsParcel) {\n        Log.d(TAG, \"setServerSideVerificationOptions\")\n    }\n\n    override fun setOnAdMetadataChangedListener(listener: IOnAdMetadataChangedListener) {\n        Log.d(TAG, \"setOnAdMetadataChangedListener\")\n    }\n\n    override fun getAdMetadata(): Bundle {\n        Log.d(TAG, \"getAdMetadata\")\n        return Bundle()\n    }\n\n    override fun showWithImmersive(activity: IObjectWrapper?, immersive: Boolean) {\n        Log.d(TAG, \"showWithBoolean\")\n    }\n\n    override fun getRewardItem(): IRewardItem? {\n        Log.d(TAG, \"getRewardItem\")\n        return null\n    }\n\n    override fun getResponseInfo(): IResponseInfo {\n        Log.d(TAG, \"getResponseInfo\")\n        return ResponseInfoImpl()\n    }\n\n    override fun setOnPaidEventListener(listener: IOnPaidEventListener) {\n        Log.d(TAG, \"setOnPaidEventListener\")\n    }\n\n    override fun loadInterstitial(request: AdRequestParcel, callback: IRewardedAdLoadCallback) {\n        Log.d(TAG, \"loadInterstitial\")\n        load(request, callback, true)\n    }\n\n    override fun setImmersiveMode(enabled: Boolean) {\n        Log.d(TAG, \"setImmersiveMode($enabled)\")\n    }\n}\n\n"
  },
  {
    "path": "play-services-ads-lite/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n    <uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />\n    <uses-permission android:name=\"com.google.android.gms.permission.AD_ID\" />\n\n    <queries>\n        <!-- Website links -->\n        <intent>\n            <action android:name=\"android.intent.action.VIEW\" />\n            <category android:name=\"android.intent.category.BROWSABLE\" />\n            <data android:scheme=\"https\" />\n        </intent>\n        <!-- Custom tabs -->\n        <intent>\n            <action\n                android:name=\"android.support.customtabs.action.CustomTabsService\" />\n        </intent>\n    </queries>\n\n    <application />\n</manifest>\n"
  },
  {
    "path": "play-services-ads-lite/src/main/aidl/com/google/android/gms/ads/AdManagerCreator.aidl",
    "content": "package com.google.android.gms.ads;\n\ninterface AdManagerCreator {\n}"
  },
  {
    "path": "play-services-ads-lite/src/main/aidl/com/google/android/gms/ads/internal/AdErrorParcel.aidl",
    "content": "package com.google.android.gms.ads.internal;\n\nparcelable AdErrorParcel;"
  },
  {
    "path": "play-services-ads-lite/src/main/aidl/com/google/android/gms/ads/internal/AdRequestParcel.aidl",
    "content": "package com.google.android.gms.ads.internal;\n\nparcelable AdRequestParcel;"
  },
  {
    "path": "play-services-ads-lite/src/main/aidl/com/google/android/gms/ads/internal/AdapterResponseInfoParcel.aidl",
    "content": "package com.google.android.gms.ads.internal;\n\nparcelable AdapterResponseInfoParcel;"
  },
  {
    "path": "play-services-ads-lite/src/main/aidl/com/google/android/gms/ads/internal/AdapterStatusParcel.aidl",
    "content": "package com.google.android.gms.ads.internal;\n\nparcelable AdapterStatusParcel;"
  },
  {
    "path": "play-services-ads-lite/src/main/aidl/com/google/android/gms/ads/internal/RequestConfigurationParcel.aidl",
    "content": "package com.google.android.gms.ads.internal;\n\nparcelable RequestConfigurationParcel;"
  },
  {
    "path": "play-services-ads-lite/src/main/aidl/com/google/android/gms/ads/internal/ServerSideVerificationOptionsParcel.aidl",
    "content": "package com.google.android.gms.ads.internal;\n\nparcelable ServerSideVerificationOptionsParcel;"
  },
  {
    "path": "play-services-ads-lite/src/main/aidl/com/google/android/gms/ads/internal/client/IAdLoaderBuilderCreator.aidl",
    "content": "package com.google.android.gms.ads.internal.client;\n\nimport com.google.android.gms.ads.internal.mediation.client.IAdapterCreator;\nimport com.google.android.gms.dynamic.IObjectWrapper;\n\ninterface IAdLoaderBuilderCreator {\n    IBinder newAdLoaderBuilder(IObjectWrapper context, String adUnitId, IAdapterCreator adapterCreator, int clientVersion);\n}"
  },
  {
    "path": "play-services-ads-lite/src/main/aidl/com/google/android/gms/ads/internal/client/IMobileAdsSettingManager.aidl",
    "content": "package com.google.android.gms.ads.internal.client;\n\nimport com.google.android.gms.ads.internal.AdapterStatusParcel;\nimport com.google.android.gms.ads.internal.RequestConfigurationParcel;\nimport com.google.android.gms.ads.internal.client.IOnAdInspectorClosedListener;\nimport com.google.android.gms.ads.internal.initialization.IInitializationCallback;\nimport com.google.android.gms.ads.internal.mediation.client.IAdapterCreator;\nimport com.google.android.gms.dynamic.IObjectWrapper;\n\ninterface IMobileAdsSettingManager {\n    void initialize() = 0;\n    void setAppVolume(float volume) = 1;\n    void fetchAppSettings(String appId) = 2;\n    void setAppMuted(boolean muted) = 3;\n    void openDebugMenu(IObjectWrapper context, String adUnitId) = 4;\n    void fetchAppSettingsV2(String appId, IObjectWrapper runnable) = 5;\n    float getAdVolume() = 6;\n    boolean isAdMuted() = 7;\n    String getVersionString() = 8;\n    void registerRtbAdapter(String className) = 9;\n    void setAdapterCreator(IAdapterCreator iAdapterCreator) = 10;\n    void addInitializationCallback(IInitializationCallback callback) = 11;\n    List<AdapterStatusParcel> getAdapterStatus() = 12;\n    void setRequestConfiguration(in RequestConfigurationParcel configuration) = 13;\n    void disableMediationAdapterInitialization() = 14;\n    void openAdInspector(IOnAdInspectorClosedListener listener) = 15;\n    void enableSameAppKey(boolean enabled) = 16;\n    void setPlugin(String plugin) = 17;\n}"
  },
  {
    "path": "play-services-ads-lite/src/main/aidl/com/google/android/gms/ads/internal/client/IMobileAdsSettingManagerCreator.aidl",
    "content": "package com.google.android.gms.ads.internal.client;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\n\ninterface IMobileAdsSettingManagerCreator {\n    IBinder getMobileAdsSettingManager(IObjectWrapper context, int clientVersion);\n}"
  },
  {
    "path": "play-services-ads-lite/src/main/aidl/com/google/android/gms/ads/internal/client/IOnAdInspectorClosedListener.aidl",
    "content": "package com.google.android.gms.ads.internal.client;\n\nimport com.google.android.gms.ads.internal.AdErrorParcel;\n\ninterface IOnAdInspectorClosedListener {\n    void onAdInspectorClosed(in @nullable AdErrorParcel adErrorParcel);\n}"
  },
  {
    "path": "play-services-ads-lite/src/main/aidl/com/google/android/gms/ads/internal/client/IOnAdMetadataChangedListener.aidl",
    "content": "package com.google.android.gms.ads.internal.client;\n\nimport com.google.android.gms.ads.internal.AdErrorParcel;\n\ninterface IOnAdMetadataChangedListener {\n}"
  },
  {
    "path": "play-services-ads-lite/src/main/aidl/com/google/android/gms/ads/internal/client/IOnPaidEventListener.aidl",
    "content": "package com.google.android.gms.ads.internal.client;\n\nimport com.google.android.gms.ads.internal.AdErrorParcel;\n\ninterface IOnPaidEventListener {\n}"
  },
  {
    "path": "play-services-ads-lite/src/main/aidl/com/google/android/gms/ads/internal/client/IResponseInfo.aidl",
    "content": "package com.google.android.gms.ads.internal.client;\n\nimport com.google.android.gms.ads.internal.AdapterResponseInfoParcel;\n\ninterface IResponseInfo {\n    String getMediationAdapterClassName() = 0;\n    String getResponseId() = 1;\n    List<AdapterResponseInfoParcel> getAdapterResponseInfo() = 2;\n    AdapterResponseInfoParcel getLoadedAdapterResponse() = 3;\n    Bundle getResponseExtras() = 4;\n}"
  },
  {
    "path": "play-services-ads-lite/src/main/aidl/com/google/android/gms/ads/internal/initialization/IInitializationCallback.aidl",
    "content": "package com.google.android.gms.ads.internal.initialization;\n\nimport com.google.android.gms.ads.internal.AdapterStatusParcel;\n\ninterface IInitializationCallback {\n    void onInitialized(in List<AdapterStatusParcel> status);\n}"
  },
  {
    "path": "play-services-ads-lite/src/main/aidl/com/google/android/gms/ads/internal/mediation/client/IAdapterCreator.aidl",
    "content": "package com.google.android.gms.ads.internal.mediation.client;\n\ninterface IAdapterCreator {\n\n}"
  },
  {
    "path": "play-services-ads-lite/src/main/aidl/com/google/android/gms/ads/internal/rewarded/client/IRewardItem.aidl",
    "content": "package com.google.android.gms.ads.internal.rewarded.client;\n\ninterface IRewardItem {\n}"
  },
  {
    "path": "play-services-ads-lite/src/main/aidl/com/google/android/gms/ads/internal/rewarded/client/IRewardedAd.aidl",
    "content": "package com.google.android.gms.ads.internal.rewarded.client;\n\nimport com.google.android.gms.ads.internal.AdRequestParcel;\nimport com.google.android.gms.ads.internal.ServerSideVerificationOptionsParcel;\nimport com.google.android.gms.ads.internal.client.IOnPaidEventListener;\nimport com.google.android.gms.ads.internal.client.IOnAdMetadataChangedListener;\nimport com.google.android.gms.ads.internal.client.IResponseInfo;\nimport com.google.android.gms.ads.internal.rewarded.client.IRewardedAdCallback;\nimport com.google.android.gms.ads.internal.rewarded.client.IRewardedAdLoadCallback;\nimport com.google.android.gms.ads.internal.rewarded.client.IRewardedAdSkuListener;\nimport com.google.android.gms.ads.internal.rewarded.client.IRewardItem;\nimport com.google.android.gms.dynamic.IObjectWrapper;\n\ninterface IRewardedAd {\n    void load(in AdRequestParcel request, IRewardedAdLoadCallback callback) = 0;\n    void setCallback(IRewardedAdCallback callback) = 1;\n    boolean canBeShown() = 2;\n    String getMediationAdapterClassName() = 3;\n    void show(IObjectWrapper activity) = 4;\n    void setRewardedAdSkuListener(IRewardedAdSkuListener listener) = 5;\n    void setServerSideVerificationOptions(in ServerSideVerificationOptionsParcel options) = 6;\n    void setOnAdMetadataChangedListener(IOnAdMetadataChangedListener listener) = 7;\n    Bundle getAdMetadata() = 8;\n    void showWithImmersive(IObjectWrapper activity, boolean immersive) = 9;\n    IRewardItem getRewardItem() = 10;\n    IResponseInfo getResponseInfo() = 11;\n    void setOnPaidEventListener(IOnPaidEventListener listener) = 12;\n    void loadInterstitial(in AdRequestParcel request, IRewardedAdLoadCallback callback) = 13;\n    void setImmersiveMode(boolean enabled) = 14;\n}"
  },
  {
    "path": "play-services-ads-lite/src/main/aidl/com/google/android/gms/ads/internal/rewarded/client/IRewardedAdCallback.aidl",
    "content": "package com.google.android.gms.ads.internal.rewarded.client;\n\ninterface IRewardedAdCallback {\n}"
  },
  {
    "path": "play-services-ads-lite/src/main/aidl/com/google/android/gms/ads/internal/rewarded/client/IRewardedAdCreator.aidl",
    "content": "package com.google.android.gms.ads.internal.rewarded.client;\n\nimport com.google.android.gms.ads.internal.mediation.client.IAdapterCreator;\nimport com.google.android.gms.dynamic.IObjectWrapper;\n\ninterface IRewardedAdCreator {\n    IBinder newRewardedAd(IObjectWrapper context, String str, IAdapterCreator adapterCreator, int clientVersion);\n}"
  },
  {
    "path": "play-services-ads-lite/src/main/aidl/com/google/android/gms/ads/internal/rewarded/client/IRewardedAdLoadCallback.aidl",
    "content": "package com.google.android.gms.ads.internal.rewarded.client;\n\nimport com.google.android.gms.ads.internal.AdErrorParcel;\n\ninterface IRewardedAdLoadCallback {\n    void onAdLoaded() = 0;\n    void onAdLoadErrorCode(int code) = 1;\n    void onAdLoadError(in AdErrorParcel error) = 2;\n}"
  },
  {
    "path": "play-services-ads-lite/src/main/aidl/com/google/android/gms/ads/internal/rewarded/client/IRewardedAdSkuListener.aidl",
    "content": "package com.google.android.gms.ads.internal.rewarded.client;\n\nimport com.google.android.gms.ads.internal.AdErrorParcel;\n\ninterface IRewardedAdSkuListener {\n}"
  },
  {
    "path": "play-services-ads-lite/src/main/aidl/com/google/android/gms/ads/measurement/IAppMeasurementProxy.aidl",
    "content": "package com.google.android.gms.ads.measurement;\n\ninterface IAppMeasurementProxy {\n\n}"
  },
  {
    "path": "play-services-ads-lite/src/main/aidl/com/google/android/gms/ads/measurement/IMeasurementManager.aidl",
    "content": "package com.google.android.gms.ads.measurement;\n\nimport com.google.android.gms.ads.measurement.IAppMeasurementProxy;\nimport com.google.android.gms.dynamic.IObjectWrapper;\n\ninterface IMeasurementManager {\n    void initialize(IObjectWrapper context, IAppMeasurementProxy proxy) = 1;\n}"
  },
  {
    "path": "play-services-ads-lite/src/main/java/com/google/android/gms/ads/admanager/package-info.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n/**\n * Contains classes for Google Ad Manager.\n */\npackage com.google.android.gms.ads.admanager;\n"
  },
  {
    "path": "play-services-ads-lite/src/main/java/com/google/android/gms/ads/h5/package-info.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n/**\n * Contains classes for H5 ads.\n */\npackage com.google.android.gms.ads.h5;\n"
  },
  {
    "path": "play-services-ads-lite/src/main/java/com/google/android/gms/ads/initialization/package-info.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n/**\n * Contains classes related to SDK initialization.\n */\npackage com.google.android.gms.ads.initialization;\n"
  },
  {
    "path": "play-services-ads-lite/src/main/java/com/google/android/gms/ads/internal/AdDataParcel.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.ads.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class AdDataParcel extends AutoSafeParcelable {\n    public static final Creator<AdDataParcel> CREATOR = new AutoCreator<>(AdDataParcel.class);\n}\n"
  },
  {
    "path": "play-services-ads-lite/src/main/java/com/google/android/gms/ads/internal/AdErrorParcel.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.ads.internal;\n\nimport com.google.android.gms.ads.internal.client.IResponseInfo;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class AdErrorParcel extends AutoSafeParcelable {\n    @Field(1)\n    public int code;\n    @Field(2)\n    public String message;\n    @Field(3)\n    public String domain;\n    @Field(4)\n    public AdErrorParcel cause;\n    @Field(5)\n    public IResponseInfo responseInfo;\n    public static final Creator<AdErrorParcel> CREATOR = new AutoCreator<>(AdErrorParcel.class);\n}\n"
  },
  {
    "path": "play-services-ads-lite/src/main/java/com/google/android/gms/ads/internal/AdRequestParcel.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.ads.internal;\n\nimport android.location.Location;\nimport android.os.Bundle;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class AdRequestParcel extends AutoSafeParcelable {\n    @Field(1)\n    private int versionCode = 8;\n    @Field(2)\n    public long birthday;\n    @Field(3)\n    public Bundle adMobNetworkExtras = new Bundle();\n    @Field(4)\n    public int gender;\n    @Field(5)\n    public ArrayList<String> keywords;\n    @Field(6)\n    public boolean isTestDevice;\n    @Field(7)\n    public int taggedForChildDirectedTreatment;\n    @Field(9)\n    public String publisherProvidedId;\n    @Field(10)\n    public SearchAdRequestParcel searchAdRequest;\n    @Field(11)\n    public Location location;\n    @Field(12)\n    public String contentUrl;\n    @Field(13)\n    public Bundle networkExtrasBundles = new Bundle();\n    @Field(14)\n    public Bundle customTargeting;\n    @Field(15)\n    public List<String> categoryExclusion;\n    @Field(16)\n    public String requestAgent;\n    @Field(18)\n    public boolean designedForFamilies;\n    @Field(19)\n    public AdDataParcel adData;\n    @Field(20)\n    public int tagForUnderAgeOfConsent;\n    @Field(21)\n    public String maxAdContentRating;\n    @Field(22)\n    public List<String> neighboringContentUrls;\n    @Field(23)\n    public int httpTimeoutMillis;\n    @Field(24)\n    public String adString;\n\n    public static final Creator<AdRequestParcel> CREATOR = new AutoCreator<>(AdRequestParcel.class);\n}\n"
  },
  {
    "path": "play-services-ads-lite/src/main/java/com/google/android/gms/ads/internal/AdapterResponseInfoParcel.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.ads.internal;\n\nimport android.os.Bundle;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class AdapterResponseInfoParcel extends AutoSafeParcelable {\n    @Field(1)\n    public String adapterClassName;\n    @Field(2)\n    public long latencyMillis;\n    @Field(3)\n    public AdErrorParcel error;\n    @Field(4)\n    public Bundle credentials;\n    @Field(5)\n    public String adSourceName;\n    @Field(6)\n    public String adSourceId;\n    @Field(7)\n    public String adSourceInstanceName;\n    @Field(8)\n    public String adSourceInstanceId;\n\n    public static final Creator<AdapterResponseInfoParcel> CREATOR = new AutoCreator<>(AdapterResponseInfoParcel.class);\n}\n"
  },
  {
    "path": "play-services-ads-lite/src/main/java/com/google/android/gms/ads/internal/AdapterStatusParcel.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.ads.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class AdapterStatusParcel extends AutoSafeParcelable {\n    @Field(1)\n    public String className;\n    @Field(2)\n    public boolean isReady;\n    @Field(3)\n    public int latency;\n    @Field(4)\n    public String description;\n\n    public AdapterStatusParcel() {}\n\n    public AdapterStatusParcel(String className, boolean isReady, int latency, String description) {\n        this.className = className;\n        this.isReady = isReady;\n        this.latency = latency;\n        this.description = description;\n    }\n\n    public static final Creator<AdapterStatusParcel> CREATOR = new AutoCreator<>(AdapterStatusParcel.class);\n}\n"
  },
  {
    "path": "play-services-ads-lite/src/main/java/com/google/android/gms/ads/internal/RequestConfigurationParcel.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.ads.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class RequestConfigurationParcel extends AutoSafeParcelable {\n    public static final Creator<RequestConfigurationParcel> CREATOR = new AutoCreator<>(RequestConfigurationParcel.class);\n}\n"
  },
  {
    "path": "play-services-ads-lite/src/main/java/com/google/android/gms/ads/internal/SearchAdRequestParcel.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.ads.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class SearchAdRequestParcel extends AutoSafeParcelable {\n    @Field(15)\n    public String query;\n    public static final Creator<SearchAdRequestParcel> CREATOR = new AutoCreator<>(SearchAdRequestParcel.class);\n}\n"
  },
  {
    "path": "play-services-ads-lite/src/main/java/com/google/android/gms/ads/internal/ServerSideVerificationOptionsParcel.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.ads.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class ServerSideVerificationOptionsParcel extends AutoSafeParcelable {\n    @Field(1)\n    public String userId;\n    @Field(2)\n    public String customData;\n    public static final Creator<ServerSideVerificationOptionsParcel> CREATOR = new AutoCreator<>(ServerSideVerificationOptionsParcel.class);\n}\n"
  },
  {
    "path": "play-services-ads-lite/src/main/java/com/google/android/gms/ads/interstitial/package-info.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n/**\n * Contains classes for Interstitial Ads.\n */\npackage com.google.android.gms.ads.interstitial;\n"
  },
  {
    "path": "play-services-ads-lite/src/main/java/com/google/android/gms/ads/mediation/customevent/package-info.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n/**\n * Contains classes for Google Mobile Ads mediation custom events.\n */\npackage com.google.android.gms.ads.mediation.customevent;\n"
  },
  {
    "path": "play-services-ads-lite/src/main/java/com/google/android/gms/ads/mediation/package-info.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n/**\n * Contains classes for Google Mobile Ads mediation adapters.\n */\npackage com.google.android.gms.ads.mediation;\n"
  },
  {
    "path": "play-services-ads-lite/src/main/java/com/google/android/gms/ads/mediation/rtb/package-info.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n/**\n * Contains classes for Google Mobile Ads RTB mediation adapters.\n */\npackage com.google.android.gms.ads.mediation.rtb;\n"
  },
  {
    "path": "play-services-ads-lite/src/main/java/com/google/android/gms/ads/nativead/package-info.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n/**\n * Contains classes for native ads functionality within Google Mobile\n          Ads.\n */\npackage com.google.android.gms.ads.nativead;\n"
  },
  {
    "path": "play-services-ads-lite/src/main/java/com/google/android/gms/ads/package-info.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n/**\n * Contains classes for Google Mobile Ads.\n */\npackage com.google.android.gms.ads;\n"
  },
  {
    "path": "play-services-ads-lite/src/main/java/com/google/android/gms/ads/rewarded/package-info.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n/**\n * Contains classes for Rewarded Ads.\n */\npackage com.google.android.gms.ads.rewarded;\n"
  },
  {
    "path": "play-services-ads-lite/src/main/java/com/google/android/gms/ads/rewardedinterstitial/package-info.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n/**\n * Contains classes for Rewarded Interstitial Ads.\n */\npackage com.google.android.gms.ads.rewardedinterstitial;\n"
  },
  {
    "path": "play-services-ads-lite/src/main/java/com/google/android/gms/ads/search/package-info.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n/**\n * Contains classes for Search Ads for Apps.\n */\npackage com.google.android.gms.ads.search;\n"
  },
  {
    "path": "play-services-api/build.gradle",
    "content": "/*\n * Copyright 2013-2015 microG Project Team\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\napply plugin: 'com.android.library'\n\nandroid {\n    namespace \"org.microg.gms.api\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n}\n\ndependencies {\n    api project(':play-services-base')\n    api project(':play-services-location')\n    api project(':play-services-phenotype')\n\n    annotationProcessor project(':safe-parcel-processor')\n}\n"
  },
  {
    "path": "play-services-api/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<manifest />\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/ads/omid/IOmid.aidl",
    "content": "package com.google.android.gms.ads.omid;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\n\ninterface IOmid {\n    boolean initializeOmid(IObjectWrapper context) = 1;\n    IObjectWrapper createHtmlAdSession(String version, IObjectWrapper webView, String customReferenceData, String impressionOwner, String altImpressionOwner) = 2;\n    void startAdSession(IObjectWrapper adSession) = 3;\n    void registerAdView(IObjectWrapper adSession, IObjectWrapper view) = 4;\n    String getVersion() = 5;\n    void finishAdSession(IObjectWrapper adSession) = 6;\n    void addFriendlyObstruction(IObjectWrapper adSession, IObjectWrapper view) = 7;\n    IObjectWrapper createHtmlAdSessionWithPartnerName(String version, IObjectWrapper webView, String customReferenceData, String impressionOwner, String altImpressionOwner, String parterName) = 8;\n    IObjectWrapper createJavascriptAdSessionWithPartnerNameImpressionCreativeType(String version, IObjectWrapper webView, String customReferenceData, String impressionOwner, String altImpressionOwner, String parterName, String impressionType, String creativeType, String contentUrl) = 9;\n    IObjectWrapper createHtmlAdSessionWithPartnerNameImpressionCreativeType(String version, IObjectWrapper webView, String customReferenceData, String impressionOwner, String altImpressionOwner, String parterName, String impressionType, String creativeType, String contentUrl) = 10;\n}"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/appdatasearch/CorpusStatus.aidl",
    "content": "package com.google.android.gms.appdatasearch;\n\nparcelable CorpusStatus;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/appdatasearch/PIMEUpdate.aidl",
    "content": "package com.google.android.gms.appdatasearch;\n\nparcelable PIMEUpdate;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/appdatasearch/PIMEUpdateResponse.aidl",
    "content": "package com.google.android.gms.appdatasearch;\n\nparcelable PIMEUpdateResponse;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/appdatasearch/RequestIndexingSpecification.aidl",
    "content": "package com.google.android.gms.appdatasearch;\n\nparcelable RequestIndexingSpecification;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/appdatasearch/SuggestSpecification.aidl",
    "content": "package com.google.android.gms.appdatasearch;\n\nparcelable SuggestSpecification;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/appdatasearch/SuggestionResults.aidl",
    "content": "package com.google.android.gms.appdatasearch;\n\nparcelable SuggestionResults;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/appdatasearch/UsageInfo.aidl",
    "content": "package com.google.android.gms.appdatasearch;\n\nparcelable UsageInfo;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/appdatasearch/internal/IAppDataSearch.aidl",
    "content": "package com.google.android.gms.appdatasearch.internal;\n\nimport com.google.android.gms.appdatasearch.CorpusStatus;\nimport com.google.android.gms.appdatasearch.PIMEUpdateResponse;\nimport com.google.android.gms.appdatasearch.RequestIndexingSpecification;\nimport com.google.android.gms.appdatasearch.SuggestionResults;\nimport com.google.android.gms.appdatasearch.SuggestSpecification;\n\ninterface IAppDataSearch {\n    SuggestionResults getSuggestions(String var1, String packageName, in String[] accounts, int maxNum, in SuggestSpecification specs) = 1;\n    boolean requestIndexing(String packageName, String accountName, long l, in RequestIndexingSpecification specs) = 3;\n    CorpusStatus getStatus(String packageName, String accountName) = 4;\n    PIMEUpdateResponse requestPIMEUpdate(String s1, String s2, int i, in byte[] bs) = 34;\n}\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/appdatasearch/internal/ILightweightAppDataSearch.aidl",
    "content": "package com.google.android.gms.appdatasearch.internal;\n\nimport com.google.android.gms.appdatasearch.internal.ILightweightAppDataSearchCallbacks;\nimport com.google.android.gms.appdatasearch.UsageInfo;\n\ninterface ILightweightAppDataSearch {\n    void view(ILightweightAppDataSearchCallbacks callbacks, String packageName, in UsageInfo[] usageInfos);\n}\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/appdatasearch/internal/ILightweightAppDataSearchCallbacks.aidl",
    "content": "package com.google.android.gms.appdatasearch.internal;\n\ninterface ILightweightAppDataSearchCallbacks {\n}\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/audit/LogAuditRecordsRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.audit;\n\nparcelable LogAuditRecordsRequest;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/audit/internal/IAuditService.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.audit.internal;\n\nimport com.google.android.gms.common.api.internal.IStatusCallback;\nimport com.google.android.gms.audit.LogAuditRecordsRequest;\n\ninterface IAuditService {\n    void logAuditRecords(in LogAuditRecordsRequest request, IStatusCallback callback);\n}"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/auth/appcert/IAppCertService.aidl",
    "content": "package com.google.android.gms.auth.appcert;\n\ninterface IAppCertService {\n    boolean fetchDeviceKey() = 0;\n    String getSpatulaHeader(String packageName) = 1;\n}\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/checkin/internal/ICheckinService.aidl",
    "content": "package com.google.android.gms.checkin.internal;\n\ninterface ICheckinService {\n    String getDeviceDataVersionInfo();\n    long getLastCheckinSuccessTime();\n    String getLastSimOperator();\n}\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/credential/manager/common/IPendingIntentCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.credential.manager.common;\n\nimport com.google.android.gms.common.api.Status;\n\ninterface IPendingIntentCallback {\n    void onPendingIntent(in Status status, in PendingIntent pendingIntent);\n}"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/credential/manager/common/ISettingsCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.credential.manager.common;\n\nimport com.google.android.gms.common.api.Status;\n\ninterface ISettingsCallback {\n    void onSetting(in Status status, in byte[] value);\n}"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/credential/manager/firstparty/internal/ICredentialManagerService.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.credential.manager.firstparty.internal;\n\nimport com.google.android.gms.common.api.internal.IStatusCallback;\nimport com.google.android.gms.credential.manager.common.IPendingIntentCallback;\nimport com.google.android.gms.credential.manager.common.ISettingsCallback;\nimport com.google.android.gms.credential.manager.invocationparams.CredentialManagerInvocationParams;\n\ninterface ICredentialManagerService {\n    void getCredentialManagerIntent(IPendingIntentCallback callback, in CredentialManagerInvocationParams params) = 0;\n    void getSetting(ISettingsCallback callback, String key) = 1;\n    void setSetting(IStatusCallback callback, String key, in byte[] value) = 2;\n}"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/credential/manager/invocationparams/CredentialManagerInvocationParams.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.credential.manager.invocationparams;\n\nparcelable CredentialManagerInvocationParams;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/facs/cache/FacsCacheCallOptions.aidl",
    "content": "package com.google.android.gms.facs.cache;\n\nparcelable FacsCacheCallOptions;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/facs/cache/ForceSettingsCacheRefreshResult.aidl",
    "content": "package com.google.android.gms.facs.cache;\n\nparcelable ForceSettingsCacheRefreshResult;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/facs/cache/GetActivityControlsSettingsResult.aidl",
    "content": "package com.google.android.gms.facs.cache;\n\nparcelable GetActivityControlsSettingsResult;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/facs/cache/ReadDeviceLevelSettingsResult.aidl",
    "content": "package com.google.android.gms.facs.cache;\n\nparcelable ReadDeviceLevelSettingsResult;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/facs/cache/UpdateActivityControlsSettingsResult.aidl",
    "content": "package com.google.android.gms.facs.cache;\n\nparcelable UpdateActivityControlsSettingsResult;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/facs/cache/internal/IFacsCacheCallbacks.aidl",
    "content": "package com.google.android.gms.facs.cache.internal;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.facs.cache.ForceSettingsCacheRefreshResult;\nimport com.google.android.gms.facs.cache.GetActivityControlsSettingsResult;\nimport com.google.android.gms.facs.cache.ReadDeviceLevelSettingsResult;\nimport com.google.android.gms.facs.cache.UpdateActivityControlsSettingsResult;\n\ninterface IFacsCacheCallbacks {\n    void onForceSettingsCacheRefreshResult(in Status status, in ForceSettingsCacheRefreshResult result) = 0;\n    void onUpdateActivityControlsSettingsResult(in Status status, in UpdateActivityControlsSettingsResult result) = 1;\n    void onGetActivityControlsSettingsResult(in Status status, in GetActivityControlsSettingsResult result) = 2;\n    void onWriteDeviceLevelSettingsResult(in Status status) = 3;\n    void onReadDeviceLevelSettingsResult(in Status status, in ReadDeviceLevelSettingsResult result) = 4;\n}\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/facs/cache/internal/IFacsCacheService.aidl",
    "content": "package com.google.android.gms.facs.cache.internal;\n\nimport com.google.android.gms.facs.cache.FacsCacheCallOptions;\nimport com.google.android.gms.facs.cache.internal.IFacsCacheCallbacks;\n\ninterface IFacsCacheService {\n    void forceSettingsCacheRefresh(IFacsCacheCallbacks callbacks, in FacsCacheCallOptions options) = 0;\n    void updateActivityControlsSettings(IFacsCacheCallbacks callbacks, in byte[] bytes, in FacsCacheCallOptions options) = 1;\n    void getActivityControlsSettings(IFacsCacheCallbacks callbacks, in FacsCacheCallOptions options) = 2;\n    void readDeviceLevelSettings(IFacsCacheCallbacks callbacks) = 3;\n    void writeDeviceLevelSettings(IFacsCacheCallbacks callbacks, in byte[] bytes) = 4;\n}\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/feedback/ErrorReport.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.feedback;\n\nparcelable ErrorReport;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/feedback/FeedbackOptions.aidl",
    "content": "package com.google.android.gms.feedback;\n\nparcelable FeedbackOptions;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/feedback/FileTeleporter.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.feedback;\n\nparcelable FileTeleporter;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/feedback/LogOptions.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.feedback;\n\nparcelable LogOptions;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/feedback/ThemeSettings.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.feedback;\n\nparcelable ThemeSettings;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/feedback/internal/IFeedbackCallbacks.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.feedback.internal;\n\ninterface IFeedbackCallbacks {\n    void onServiceDestroy();\n}\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/feedback/internal/IFeedbackService.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.feedback.internal;\n\nimport com.google.android.gms.feedback.FeedbackOptions;\nimport android.os.IBinder;\nimport android.os.IInterface;\nimport android.os.Parcel;\nimport com.google.android.gms.googlehelp.GoogleHelp;\nimport com.google.android.gms.feedback.ErrorReport;\nimport android.content.Context;\nimport android.os.Bundle;\nimport android.content.Intent;\n\n\ninterface IFeedbackService {\n\n    boolean startFeedbackFlow(in ErrorReport errorReport) = 0;\n\n    boolean silentSendFeedback(in ErrorReport errorReport) = 2;\n\n    void saveFeedbackDataAsync(in Bundle bundle, long id) = 3;\n\n    void saveFeedbackDataAsyncWithOption(in FeedbackOptions options, in Bundle bundle, long id) = 4;\n\n    void startFeedbackFlowAsync(in ErrorReport errorReport, long id) = 5;\n\n    boolean isValidConfiguration(in FeedbackOptions options) = 6;\n\n}"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/gass/internal/GassRequestParcel.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.gass.internal;\n\nparcelable GassRequestParcel;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/gass/internal/GassResponseParcel.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.gass.internal;\n\nparcelable GassResponseParcel;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/gass/internal/IGassService.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.gass.internal;\n\nimport android.os.Bundle;\nimport android.os.IInterface;\nimport com.google.android.gms.gass.internal.GassRequestParcel;\nimport com.google.android.gms.gass.internal.GassResponseParcel;\n\ninterface IGassService {\n    GassResponseParcel getGassResponse(in GassRequestParcel gassRequestParcel) = 0;\n    Bundle getGassBundle(in Bundle bundle, int code) = 3;\n}\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/googlehelp/GoogleHelp.aidl",
    "content": "package com.google.android.gms.googlehelp;\n\nparcelable GoogleHelp;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/googlehelp/InProductHelp.aidl",
    "content": "package com.google.android.gms.googlehelp;\n\nparcelable InProductHelp;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/googlehelp/SupportRequestHelp.aidl",
    "content": "package com.google.android.gms.googlehelp;\n\nparcelable SupportRequestHelp;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/googlehelp/internal/common/IGoogleHelpCallbacks.aidl",
    "content": "package com.google.android.gms.googlehelp.internal.common;\n\nimport android.graphics.Bitmap;\nimport android.os.Bundle;\nimport android.os.IBinder;\nimport android.os.Parcel;\n\nimport com.google.android.gms.googlehelp.GoogleHelp;\nimport com.google.android.gms.googlehelp.InProductHelp;\n\ninterface IGoogleHelpCallbacks {\n    void onProcessGoogleHelpFinished(in GoogleHelp googleHelp) = 0;\n    oneway void onSaveAsyncPsdFinished() = 6;\n    oneway void onSaveAsyncPsbdFinished() = 7;\n    void onRequestChatSupportSuccess(int chatQueuePosition) = 8;\n    void onRequestChatSupportFailed() = 9;\n    void onRequestC2cSupportSuccess() = 10;\n    void onRequestC2cSupportFailed() = 11;\n    void onSuggestions(in byte[] suggestions) = 12;\n    void onNoSuggestions() = 13;\n    void onEscalationOptions(in byte[] options) = 14;\n    void onNoEscalationOptions() = 15;\n    void onProcessInProductHelpFinished(in InProductHelp inProductHelp) = 16;\n    void onRealtimeSupportStatus(in byte[] status) = 17;\n    void onNoRealtimeSupportStatus() = 18;\n}\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/googlehelp/internal/common/IGoogleHelpService.aidl",
    "content": "package com.google.android.gms.googlehelp.internal.common;\n\nimport android.graphics.Bitmap;\nimport android.os.Bundle;\n\nimport com.google.android.gms.feedback.FeedbackOptions;\nimport com.google.android.gms.googlehelp.GoogleHelp;\nimport com.google.android.gms.googlehelp.InProductHelp;\nimport com.google.android.gms.googlehelp.SupportRequestHelp;\nimport com.google.android.gms.googlehelp.internal.common.IGoogleHelpCallbacks;\n\ninterface IGoogleHelpService {\n    void processGoogleHelpAndPip(in GoogleHelp googleHelp, IGoogleHelpCallbacks callbacks) = 0;\n    void processGoogleHelpAndPipWithBitmap(in GoogleHelp googleHelp, in Bitmap bitmap, IGoogleHelpCallbacks callbacks) = 1;\n    oneway void saveAsyncHelpPsd(in Bundle bundle, long timestamp, in GoogleHelp googleHelp, IGoogleHelpCallbacks callbacks) = 7;\n    oneway void saveAsyncFeedbackPsd(in Bundle bundle, long timestamp, in GoogleHelp googleHelp, IGoogleHelpCallbacks callbacks) = 8;\n    oneway void saveAsyncFeedbackPsbd(in FeedbackOptions options, in Bundle bundle, long timestamp, in GoogleHelp googleHelp, IGoogleHelpCallbacks callbacks) = 9;\n    oneway void requestChatSupport(in GoogleHelp googleHelp, String phoneNumber, String s2, IGoogleHelpCallbacks callbacks) = 10;\n    oneway void requestC2cSupport(in GoogleHelp googleHelp, String phoneNumber, String s2, IGoogleHelpCallbacks callbacks) = 11;\n    oneway void getSuggestions(in GoogleHelp googleHelp, IGoogleHelpCallbacks callbacks) = 12;\n    oneway void getEscalationOptions(in GoogleHelp googleHelp, IGoogleHelpCallbacks callbacks) = 13;\n    oneway void requestChatSupportWithSupportRequest(in SupportRequestHelp supportRequestHelp, IGoogleHelpCallbacks callbacks) = 14;\n    oneway void requestC2cSupportWithSupportRequest(in SupportRequestHelp supportRequestHelp, IGoogleHelpCallbacks callbacks) = 15;\n    void processInProductHelpAndPip(in InProductHelp inProductHelp, in Bitmap bitmap, IGoogleHelpCallbacks callbacks) = 16;\n    oneway void getRealtimeSupportStatus(in GoogleHelp googleHelp, IGoogleHelpCallbacks callbacks) = 17;\n}\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/http/IGoogleHttpService.aidl",
    "content": "package com.google.android.gms.http;\n\nimport android.os.Bundle;\n\ninterface IGoogleHttpService {\n    Bundle checkUrl(String url);\n}\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/languageprofile/ClientLanguageSettings.aidl",
    "content": "package com.google.android.gms.languageprofile;\n\nparcelable ClientLanguageSettings;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/languageprofile/LanguageFluency.aidl",
    "content": "package com.google.android.gms.languageprofile;\n\nparcelable LanguageFluency;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/languageprofile/LanguageFluencyParams.aidl",
    "content": "package com.google.android.gms.languageprofile;\n\nparcelable LanguageFluencyParams;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/languageprofile/LanguagePreference.aidl",
    "content": "package com.google.android.gms.languageprofile;\n\nparcelable LanguagePreference;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/languageprofile/LanguagePreferenceParams.aidl",
    "content": "package com.google.android.gms.languageprofile;\n\nparcelable LanguagePreferenceParams;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/languageprofile/internal/ILanguageProfileCallbacks.aidl",
    "content": "package com.google.android.gms.languageprofile.internal;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.languageprofile.LanguageFluency;\nimport com.google.android.gms.languageprofile.LanguagePreference;\n\ninterface ILanguageProfileCallbacks {\n    oneway void onString(in Status status, String s) = 0;\n    oneway void onLanguagePreferences(in Status status, in List<LanguagePreference> preferences) = 1;\n    oneway void onLanguageFluencies(in Status status, in List<LanguageFluency> fluencies) = 2;\n}\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/languageprofile/internal/ILanguageProfileService.aidl",
    "content": "package com.google.android.gms.languageprofile.internal;\n\nimport com.google.android.gms.common.api.internal.IStatusCallback;\nimport com.google.android.gms.languageprofile.ClientLanguageSettings;\nimport com.google.android.gms.languageprofile.LanguageFluencyParams;\nimport com.google.android.gms.languageprofile.LanguagePreferenceParams;\nimport com.google.android.gms.languageprofile.internal.ILanguageProfileCallbacks;\n\ninterface ILanguageProfileService {\n    String fun1(String accountName) = 0;\n    void fun2(String accountName, ILanguageProfileCallbacks callbacks) = 1;\n    void getLanguagePreferences(String accountName, in LanguagePreferenceParams params, ILanguageProfileCallbacks callbacks) = 2;\n    void getLanguageFluencies(String accountName, in LanguageFluencyParams params, ILanguageProfileCallbacks callbacks) = 3;\n    void getLanguageSettings(String accountName, in ClientLanguageSettings settings, IStatusCallback callback) = 4;\n    void removeLanguageSettings(String accountName, IStatusCallback callback) = 5;\n}\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/locationsharingreporter/IneligibilityRationale.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.locationsharingreporter;\n\nparcelable IneligibilityRationale;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/locationsharingreporter/LocationReportingStatus.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.locationsharingreporter;\n\nparcelable LocationReportingStatus;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/locationsharingreporter/LocationShare.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.locationsharingreporter;\n\nparcelable LocationShare;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/locationsharingreporter/LocationUploadRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.locationsharingreporter;\n\nparcelable LocationUploadRequest;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/locationsharingreporter/LocationUploadResponse.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.locationsharingreporter;\n\nparcelable LocationUploadResponse;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/locationsharingreporter/NoticeAckedUpdateRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.locationsharingreporter;\n\nparcelable NoticeAckedUpdateRequest;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/locationsharingreporter/PeriodicLocationReportingIssues.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.locationsharingreporter;\n\nparcelable PeriodicLocationReportingIssues;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/locationsharingreporter/PeriodicLocationUploadRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.locationsharingreporter;\n\nparcelable PeriodicLocationUploadRequest;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/locationsharingreporter/StartLocationReportingRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.locationsharingreporter;\n\nparcelable StartLocationReportingRequest;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/locationsharingreporter/StopLocationReportingRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.locationsharingreporter;\n\nparcelable StopLocationReportingRequest;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/locationsharingreporter/internal/ILocationReportingIssuesCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.locationsharingreporter.internal;\n\nimport com.google.android.gms.common.api.ApiMetadata;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.locationsharingreporter.PeriodicLocationReportingIssues;\n\ninterface ILocationReportingIssuesCallback {\n    void onPeriodicLocationReportingIssues(in Status status, in PeriodicLocationReportingIssues periodicLocationReportingIssues, in ApiMetadata apiMetadata) = 0;\n}"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/locationsharingreporter/internal/ILocationReportingStatusCallbacks.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.locationsharingreporter.internal;\n\nimport com.google.android.gms.common.api.ApiMetadata;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.locationsharingreporter.LocationReportingStatus;\n\ninterface ILocationReportingStatusCallbacks {\n    void onLocationReportingStatus(in Status status, in LocationReportingStatus locationReportingStatus, in ApiMetadata apiMetadata) = 0;\n}"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/locationsharingreporter/internal/ILocationSharingReporterService.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.locationsharingreporter.internal;\n\nimport android.accounts.Account;\nimport com.google.android.gms.common.api.ApiMetadata;\nimport com.google.android.gms.common.api.internal.IStatusCallback;\nimport com.google.android.gms.locationsharingreporter.internal.ILocationReportingIssuesCallback;\nimport com.google.android.gms.locationsharingreporter.internal.ILocationReportingStatusCallbacks;\nimport com.google.android.gms.locationsharingreporter.internal.ILocationUploadCallbacks;\nimport com.google.android.gms.locationsharingreporter.LocationUploadRequest;\nimport com.google.android.gms.locationsharingreporter.PeriodicLocationUploadRequest;\nimport com.google.android.gms.locationsharingreporter.StartLocationReportingRequest;\nimport com.google.android.gms.locationsharingreporter.StopLocationReportingRequest;\nimport com.google.android.gms.locationsharingreporter.NoticeAckedUpdateRequest;\n\ninterface ILocationSharingReporterService {\n    void uploadLocation(ILocationUploadCallbacks callback, in Account account, in LocationUploadRequest request, in ApiMetadata apiMetadata) = 0;\n    void getReportingStatus(ILocationReportingStatusCallbacks callback, in Account account, in ApiMetadata apiMetadata) = 1;\n    void syncReportingStatus(IStatusCallback callback, in Account account, in ApiMetadata apiMetadata) = 2;\n    void periodicLocationUpload(IStatusCallback callback, in Account account, in PeriodicLocationUploadRequest request, in ApiMetadata apiMetadata) = 3;\n    void startLocationReporting(IStatusCallback callback, in Account account, in StartLocationReportingRequest request, in ApiMetadata apiMetadata) = 4;\n    void stopLocationReporting(IStatusCallback callback, in Account account, in StopLocationReportingRequest request, in ApiMetadata apiMetadata) = 5;\n    void updateNoticeState(IStatusCallback callback, in Account account, in NoticeAckedUpdateRequest request, in ApiMetadata apiMetadata) = 6;\n    void getReportingIssues(ILocationReportingIssuesCallback callback, in Account account, in ApiMetadata apiMetadata) = 7;\n}"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/locationsharingreporter/internal/ILocationUploadCallbacks.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.locationsharingreporter.internal;\n\nimport com.google.android.gms.common.api.ApiMetadata;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.locationsharingreporter.LocationUploadResponse;\n\ninterface ILocationUploadCallbacks {\n    void onLocationUploadResponse(in Status status, in LocationUploadResponse locationUploadResponse, in ApiMetadata apiMetadata) = 0;\n}"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/maps/auth/IApiTokenService.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.maps.auth;\n\nimport android.os.Bundle;\n\ninterface IApiTokenService {\n   Bundle requestApiToken(in Bundle params);\n}"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/measurement/internal/AppMetadata.aidl",
    "content": "package com.google.android.gms.measurement.internal;\n\nparcelable AppMetadata;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/measurement/internal/ConditionalUserPropertyParcel.aidl",
    "content": "package com.google.android.gms.measurement.internal;\n\nparcelable ConditionalUserPropertyParcel;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/measurement/internal/EventParcel.aidl",
    "content": "package com.google.android.gms.measurement.internal;\n\nparcelable EventParcel;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/measurement/internal/IMeasurementService.aidl",
    "content": "package com.google.android.gms.measurement.internal;\n\nimport com.google.android.gms.measurement.internal.AppMetadata;\nimport com.google.android.gms.measurement.internal.ConditionalUserPropertyParcel;\nimport com.google.android.gms.measurement.internal.EventParcel;\nimport com.google.android.gms.measurement.internal.UserAttributeParcel;\n\ninterface IMeasurementService {\n    void sendEvent(in EventParcel event, in AppMetadata app) = 0;\n    void sendUserProperty(in UserAttributeParcel attribute, in AppMetadata app) = 1;\n    void sendAppLaunch(in AppMetadata app) = 3;\n//    void f5(in EventParcel event, String p1, String p2) = 4;\n    void sendMeasurementEnabled(in AppMetadata p0) = 5;\n    List<UserAttributeParcel> getAllUserProperties(in AppMetadata app, boolean includeInternal) = 6;\n//    byte[] f9(in EventParcel event, String p1) = 8;\n    void sendCurrentScreen(long id, String name, String referrer, String packageName) = 9;\n    String getAppInstanceId(in AppMetadata app) = 10;\n    void sendConditionalUserProperty(in ConditionalUserPropertyParcel property, in AppMetadata app) = 11;\n//    void f13(ConditionalUserPropertyParcel p0) = 12;\n    List<UserAttributeParcel> getUserProperties(String origin, String propertyNamePrefix, boolean includeInternal, in AppMetadata app) = 13;\n    List<UserAttributeParcel> getUserPropertiesAs(String packageName, String origin, String propertyNamePrefix, boolean includeInternal) = 14;\n    List<ConditionalUserPropertyParcel> getConditionalUserProperties(String origin, String propertyNamePrefix, in AppMetadata app) = 15;\n    List<ConditionalUserPropertyParcel> getConditionalUserPropertiesAs(String packageName, String origin, String propertyNamePrefix) = 16;\n    void reset(in AppMetadata app) = 17;\n    void sendDefaultEventParameters(in Bundle params, in AppMetadata app) = 18;\n    void sendConsentSettings(in AppMetadata app) = 19;\n}\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/measurement/internal/UserAttributeParcel.aidl",
    "content": "package com.google.android.gms.measurement.internal;\n\nparcelable UserAttributeParcel;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/people/internal/IPeopleCallbacks.aidl",
    "content": "package com.google.android.gms.people.internal;\n\nimport android.os.Bundle;\nimport android.os.ParcelFileDescriptor;\n\nimport com.google.android.gms.common.data.DataHolder;\n\ninterface IPeopleCallbacks {\n    void onDataHolder(int code, in Bundle resolution, in DataHolder holder) = 1;\n    void onDataHolders(int code, in Bundle resolution, in DataHolder[] holders) = 3;\n    void onParcelFileDescriptor(int code, in Bundle resolution, in ParcelFileDescriptor fileDescriptor, in Bundle extras) = 4;\n}\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/people/internal/IPeopleService.aidl",
    "content": "package com.google.android.gms.people.internal;\n\nimport android.os.Bundle;\n\nimport com.google.android.gms.people.internal.IPeopleCallbacks;\nimport com.google.android.gms.common.server.FavaDiagnosticsEntity;\nimport com.google.android.gms.common.internal.ICancelToken;\n\ninterface IPeopleService {\n    // void loadOwners1(IPeopleCallbacks var1, boolean var2, boolean var3, String var4, String var5);\n    // void loadCirclesOld(IPeopleCallbacks var1, String var2, String var3, String var4, int var5, String var6);\n    // void loadPeopleOld(IPeopleCallbacks var1, String var2, String var3, String var4, in List<String> var5, int var6, boolean var7, long var8);\n    // void loadAvatarLegacy(IPeopleCallbacks var1, String var2, int var3, int var4);\n    // void loadContactImageLegacy(IPeopleCallbacks var1, long var2, boolean var4);\n    // void blockPerson(IPeopleCallbacks var1, String var2, String var3, String var4, boolean var5);\n    // Bundle syncRawContact(in Uri var1);\n    // void loadPeopleForAggregation8(IPeopleCallbacks var1, String var2, String var3, String var4, boolean var5, int var6);\n    // void setSyncToContactsSettings(IPeopleCallbacks var1, String var2, boolean var3, in String[] var4);\n\n    // Bundle startSync(String var1, String var2);\n    // void requestSync(IPeopleCallbacks var1, String var2, String var3, in Uri var4);\n    // void updatePersonCirclesOld(IPeopleCallbacks var1, String var2, String var3, String var4, in List<String> var5, in List<String> var6);\n    // boolean isSyncToContactsEnabled();\n    // Bundle requestSyncOld(String var1, String var2);\n    // void setAvatar(IPeopleCallbacks var1, String var2, String var3, in Uri var4, boolean var5);\n    // void loadCircles(IPeopleCallbacks var1, String var2, String var3, String var4, int var5, String var6, boolean var7);\n    // Bundle requestSyncOld19(String var1, String var2, long var3);\n    // void loadPeople20(IPeopleCallbacks var1, String var2, String var3, String var4, in List<String> var5, int var6, boolean var7, long var8, String var10, int var11);\n    // void loadPeopleLive(IPeopleCallbacks var1, String var2, String var3, String var4, int var5, String var6);\n    // void updatePersonCircles(IPeopleCallbacks var1, String var2, String var3, String var4, in List<String> var5, in List<String> var6, in FavaDiagnosticsEntity var7);\n    // void loadRemoteImageLegacy(IPeopleCallbacks var1, String var2);\n    // void loadContactsGaiaIds24(IPeopleCallbacks var1, String var2, String var3);\n    // Bundle requestSyncOld25(String var1, String var2, long var3, boolean var5);\n    // void addCircle(IPeopleCallbacks var1, String var2, String var3, String var4, String var5);\n    // void addPeopleToCircle(IPeopleCallbacks var1, String var2, String var3, String var4, in List<String> var5);\n\n    Bundle registerDataChangedListener(IPeopleCallbacks callbacks, boolean register, String var3, String var4, int scopes) = 10;\n    void loadCircles(IPeopleCallbacks callbacks, String account, String pageGaiaId, String circleId, int type, String var6, boolean var7) = 18;\n    Bundle requestSync(String account, String var2, long var3, boolean var5, boolean var6) = 204;\n    void loadOwners(IPeopleCallbacks callbacks, boolean var2, boolean var3, String account, String var5, int sortOrder) = 304;\n    void loadPeopleForAggregation(IPeopleCallbacks callbacks, String account, String var3, String filter, int var5, boolean var6, int var7, int var8, String var9, boolean var10, int var11, int var12) = 401;\n    ICancelToken loadOwnerAvatar(IPeopleCallbacks callbacks, String account, String pageId, int size, int flags) = 504;\n    ICancelToken loadAutocompleteList(IPeopleCallbacks callbacks, String account, String pageId, boolean directorySearch, String var5, String query, int autocompleteType, int var8, int numberOfResults, boolean var10) = 506;\n}\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/phenotype/Configurations.aidl",
    "content": "package com.google.android.gms.phenotype;\n\nparcelable Configurations;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/phenotype/DogfoodsToken.aidl",
    "content": "package com.google.android.gms.phenotype;\n\nparcelable DogfoodsToken;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/phenotype/ExperimentTokens.aidl",
    "content": "package com.google.android.gms.phenotype;\n\nparcelable ExperimentTokens;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/phenotype/Flag.aidl",
    "content": "package com.google.android.gms.phenotype;\n\nparcelable Flag;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/phenotype/FlagOverrides.aidl",
    "content": "package com.google.android.gms.phenotype;\n\nparcelable FlagOverrides;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/phenotype/RegistrationInfo.aidl",
    "content": "package com.google.android.gms.phenotype;\n\nparcelable RegistrationInfo;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/phenotype/internal/IPhenotypeCallbacks.aidl",
    "content": "package com.google.android.gms.phenotype.internal;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.phenotype.Configurations;\nimport com.google.android.gms.phenotype.DogfoodsToken;\nimport com.google.android.gms.phenotype.ExperimentTokens;\nimport com.google.android.gms.phenotype.Flag;\nimport com.google.android.gms.phenotype.FlagOverrides;\n\ninterface IPhenotypeCallbacks {\n    oneway void onRegistered(in Status status) = 0;\n    oneway void onWeakRegistered(in Status status) = 1;\n    oneway void onUnregistered(in Status status) = 2;\n    oneway void onConfiguration(in Status status, in Configurations configurations) = 3;\n    oneway void onCommitedToConfiguration(in Status status) = 4;\n    oneway void onExperimentTokens(in Status status, in ExperimentTokens experimentTokens) = 5;\n    oneway void onDogfoodsToken(in Status status, in DogfoodsToken dogfoodsToken) = 6;\n    oneway void onDogfoodsTokenSet(in Status status) = 7;\n    oneway void onFlag(in Status status, in Flag flag) = 8;\n    oneway void onCommittedConfiguration(in Status status, in Configurations configuration) = 9;\n    oneway void onSyncFinished(in Status status, long p1) = 10;\n    oneway void onFlagOverridesSet(in Status status) = 11;\n    oneway void onFlagOverrides(in Status status, in FlagOverrides overrides) = 12;\n    oneway void onAppSpecificPropertiesSet(in Status status) = 13;\n\n    oneway void onServingVersion(in Status status, long version) = 15;\n}\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/phenotype/internal/IPhenotypeService.aidl",
    "content": "package com.google.android.gms.phenotype.internal;\n\nimport com.google.android.gms.common.api.internal.IStatusCallback;\nimport com.google.android.gms.phenotype.internal.IPhenotypeCallbacks;\nimport com.google.android.gms.phenotype.Flag;\nimport com.google.android.gms.phenotype.RegistrationInfo;\n\ninterface IPhenotypeService {\n    oneway void register(IPhenotypeCallbacks callbacks, String packageName, int version, in String[] p3, in byte[] p4) = 0; // returns via callbacks.onRegistered()\n    oneway void weakRegister(IPhenotypeCallbacks callbacks, String packageName, int version, in String[] p3, in int[] p4, in byte[] p5) = 1; // returns via callbacks.onWeakRegistered()\n    oneway void unregister(IPhenotypeCallbacks callbacks, String packageName) = 2; // returns via callbacks.onUnregistered()\n    oneway void getConfigurationSnapshot(IPhenotypeCallbacks callbacks, String packageName, String user) = 3; // returns via callbacks.onConfiguration()\n    oneway void commitToConfiguration(IPhenotypeCallbacks callbacks, String snapshotToken) = 4; // returns via callbacks.onCommitedToConfiguration()\n    oneway void getExperimentTokens(IPhenotypeCallbacks callbacks, String packageName, String logSourceName) = 5; // returns via callbacks.onExperimentTokens()\n    oneway void getDogfoodsToken(IPhenotypeCallbacks callbacks) = 6; // returns via callbacks.onDogfoodsToken()\n    oneway void setDogfoodsToken(IPhenotypeCallbacks callbacks, in byte[] p1) = 7; // returns via callbacks.onDogfoodsTokenSet()\n    oneway void getFlag(IPhenotypeCallbacks callbacks, String packageName, String name, int type) = 8; // returns via callbacks.onFlag()\n    oneway void getCommitedConfiguration(IPhenotypeCallbacks callbacks, String packageName) = 9; // returns via callbacks.onCommittedConfiguration()\n    oneway void getConfigurationSnapshotWithToken(IPhenotypeCallbacks callbacks, String packageName, String user, String token) = 10; // returns via callbacks.onConfiguration()\n    oneway void syncAfterOperation(IPhenotypeCallbacks callbacks, String packageName, long version) = 11; // returns via callbacks.onSyncFinished()\n    oneway void registerSync(IPhenotypeCallbacks callbacks, String packageName, int version, in String[] p3, in byte[] p4, String p5, String p6) = 12; // returns via callbacks.onConfiguration()\n    oneway void setFlagOverrides(IPhenotypeCallbacks callbacks, String packageName, String user, String flagName, int flagType, int flagDataType, String flagValue) = 13; // returns via callbacks.onFlagOverridesSet()\n    oneway void deleteFlagOverrides(IPhenotypeCallbacks callbacks, String packageName, String user, String flagName) = 14; // returns via callbacks.onFlagOverrides()\n    oneway void listFlagOverrides(IPhenotypeCallbacks callbacks, String packageName, String user, String flagName) = 15; // returns via callbacks.onFlagOverrides()\n\n    oneway void clearFlagOverrides(IPhenotypeCallbacks callbacks, String packageName, String user) = 17; // returns via callbacks.onFlagOverridesSet()\n    oneway void bulkRegister(IPhenotypeCallbacks callbacks, in RegistrationInfo[] infos) = 18; // returns via callbacks.onRegister()\n    oneway void setAppSpecificProperties(IPhenotypeCallbacks callbacks, String packageName, in byte[] p2) = 19; // returns via callbacks.onAppSpecificPropertiesSet()\n\n    oneway void getServingVersion(IPhenotypeCallbacks callbacks) = 21; // returns via callbacks.onServingVersion()\n    oneway void getExperimentTokensForLogging(IPhenotypeCallbacks callbacks, String packageName, String logSourceName, String p3, String clientPackageName) = 22; // returns via callbacks.onExperimentTokens()\n    oneway void syncAllAfterOperation(IPhenotypeCallbacks callbacks, long p1) = 23; // returns via callbacks.onSyncFinished()\n    oneway void setRuntimeProperties(IStatusCallback callbacks, String p1, in byte[] p2) = 24;\n//    oneway void setExternalExperiments(IStatusCallback callbacks, String p1, in List<byte[]> p2) = 25;\n}\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/plus/internal/IPlusOneButtonCreator.aidl",
    "content": "package com.google.android.gms.plus.internal;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\n\ninterface IPlusOneButtonCreator {\n    IObjectWrapper create(IObjectWrapper context, int size, int annotation, String url, int activityRequestCode);\n    IObjectWrapper createForAccount(IObjectWrapper context, int size, int annotation, String url, String account);\n}\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/potokens/PoToken.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.potokens;\n\nparcelable PoToken;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/potokens/internal/IPoTokensService.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.potokens.internal;\n\nimport com.google.android.gms.common.api.internal.IStatusCallback;\nimport com.google.android.gms.potokens.internal.ITokenCallbacks;\n\ninterface IPoTokensService {\n    void responseStatus(IStatusCallback call, int code) = 1;\n    void responseStatusToken(ITokenCallbacks call, int i, in byte[] bArr) = 2;\n}"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/potokens/internal/ITokenCallbacks.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.potokens.internal;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.potokens.PoToken;\n\ninterface ITokenCallbacks {\n    void responseToken(in Status status, in PoToken token) = 1;\n}"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/pseudonymous/PseudonymousIdToken.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.pseudonymous;\n\nparcelable PseudonymousIdToken;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/pseudonymous/internal/IPseudonymousIdCallbacks.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.pseudonymous.internal;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.pseudonymous.PseudonymousIdToken;\n\ninterface IPseudonymousIdCallbacks {\n    void onGetTokenResponse(in Status status, in PseudonymousIdToken token) = 0;\n    void onSetTokenResponse(in Status status) = 1;\n    void onGetLastResetWallTimeMsResponse(in Status status, long time) = 2;\n}\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/pseudonymous/internal/IPseudonymousIdService.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.pseudonymous.internal;\n\nimport com.google.android.gms.pseudonymous.internal.IPseudonymousIdCallbacks;\nimport com.google.android.gms.pseudonymous.PseudonymousIdToken;\n\ninterface IPseudonymousIdService {\n   void getToken(IPseudonymousIdCallbacks call) = 0;\n   void setToken(IPseudonymousIdCallbacks call, in PseudonymousIdToken token) = 1;\n   void getLastResetWallTimeMs(IPseudonymousIdCallbacks callbacks) = 2;\n}\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/reminders/AccountState.aidl",
    "content": "package com.google.android.gms.reminders;\n\nparcelable AccountState;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/reminders/CreateReminderOptionsInternal.aidl",
    "content": "package com.google.android.gms.reminders;\n\nparcelable CreateReminderOptionsInternal;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/reminders/LoadRemindersOptions.aidl",
    "content": "package com.google.android.gms.reminders;\n\nparcelable LoadRemindersOptions;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/reminders/ReindexDueDatesOptions.aidl",
    "content": "package com.google.android.gms.reminders;\n\nparcelable ReindexDueDatesOptions;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/reminders/UpdateRecurrenceOptions.aidl",
    "content": "package com.google.android.gms.reminders;\n\nparcelable UpdateRecurrenceOptions;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/reminders/internal/IRemindersCallbacks.aidl",
    "content": "package com.google.android.gms.reminders.internal;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.common.data.DataHolder;\n\nimport com.google.android.gms.reminders.AccountState;\n\ninterface IRemindersCallbacks {\n    void onDataHolder(in DataHolder data, in Status status) = 0;\n    void onStatus(in Status status) = 1;\n    void onNoStatus() = 2;\n    void onDataHolderNoStatus(in DataHolder data, in Status status) = 3;\n    void onBool(boolean b, in Status status) = 4;\n    void onString(in String s, in Status status) = 5;\n    void onAccountState(in AccountState accountState, in Status status) = 6;\n    void onAsyncDataHolder(in DataHolder data) = 7;\n}"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/reminders/internal/IRemindersListener.aidl",
    "content": "package com.google.android.gms.reminders.internal;\n\ninterface IRemindersListener {\n\n}"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/reminders/internal/IRemindersService.aidl",
    "content": "package com.google.android.gms.reminders.internal;\n\nimport com.google.android.gms.reminders.internal.IRemindersCallbacks;\n\nimport com.google.android.gms.reminders.AccountState;\nimport com.google.android.gms.reminders.CreateReminderOptionsInternal;\nimport com.google.android.gms.reminders.LoadRemindersOptions;\nimport com.google.android.gms.reminders.ReindexDueDatesOptions;\nimport com.google.android.gms.reminders.UpdateRecurrenceOptions;\nimport com.google.android.gms.reminders.model.CustomizedSnoozePresetEntity;\nimport com.google.android.gms.reminders.model.TaskEntity;\nimport com.google.android.gms.reminders.model.TaskIdEntity;\n\ninterface IRemindersService {\n    void loadReminders(IRemindersCallbacks callbacks, in LoadRemindersOptions options) = 0;\n    void addListener(IRemindersCallbacks callbacks) = 1;\n    void createReminder(IRemindersCallbacks callbacks, in TaskEntity task) = 2;\n    void updateReminder(IRemindersCallbacks callbacks, in TaskEntity task) = 3;\n    void deleteReminder(IRemindersCallbacks callbacks, in TaskIdEntity taskId) = 4;\n    void bumpReminder(IRemindersCallbacks callbacks, in TaskIdEntity taskId) = 5;\n    void hasUpcomingReminders(IRemindersCallbacks callbacks) = 6;\n    void createRecurrence(IRemindersCallbacks callbacks, in TaskEntity task) = 7;\n    void updateRecurrence(IRemindersCallbacks callbacks, String s1, in TaskEntity task, in UpdateRecurrenceOptions options) = 8;\n    void deleteRecurrence(IRemindersCallbacks callbacks, String s1, in UpdateRecurrenceOptions options) = 9;\n    void changeRecurrence(IRemindersCallbacks callbacks, String s1, in TaskEntity task, in UpdateRecurrenceOptions options) = 10;\n    void makeTaskRecurring(IRemindersCallbacks callbacks, in TaskEntity task) = 11;\n    void makeRecurrenceSingleInstance(IRemindersCallbacks callbacks, String s1, in TaskEntity task, in UpdateRecurrenceOptions options) = 12;\n    void clearListeners() = 13;\n    void batchUpdateReminders(IRemindersCallbacks callbacks, in List<TaskEntity> tasks) = 14;\n    void createReminderWithOptions(IRemindersCallbacks callbacks, in TaskEntity task, in CreateReminderOptionsInternal options) = 15;\n    void getCustomizedSnoozePreset(IRemindersCallbacks callbacks) = 16;\n    void setCustomizedSnoozePreset(IRemindersCallbacks callbacks, in CustomizedSnoozePresetEntity preset) = 17;\n    void setAccountState(IRemindersCallbacks callbacks, in AccountState accountState) = 18;\n    void getAccountState(IRemindersCallbacks callbacks) = 19;\n    void checkReindexDueDatesNeeded(IRemindersCallbacks callbacks, in ReindexDueDatesOptions options) = 20;\n    void reindexDueDates(IRemindersCallbacks callbacks, in ReindexDueDatesOptions options) = 21;\n}"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/reminders/model/CustomizedSnoozePresetEntity.aidl",
    "content": "package com.google.android.gms.reminders.model;\n\nparcelable CustomizedSnoozePresetEntity;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/reminders/model/TaskEntity.aidl",
    "content": "package com.google.android.gms.reminders.model;\n\nparcelable TaskEntity;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/reminders/model/TaskIdEntity.aidl",
    "content": "package com.google.android.gms.reminders.model;\n\nparcelable TaskIdEntity;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/search/administration/internal/ISearchAdministrationService.aidl",
    "content": "package com.google.android.gms.search.administration.internal;\n\ninterface ISearchAdministrationService {\n\n}\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/search/corpora/ClearCorpusRequest.aidl",
    "content": "package com.google.android.gms.search.corpora;\n\nparcelable ClearCorpusRequest;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/search/corpora/GetCorpusInfoRequest.aidl",
    "content": "package com.google.android.gms.search.corpora;\n\nparcelable GetCorpusInfoRequest;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/search/corpora/GetCorpusStatusRequest.aidl",
    "content": "package com.google.android.gms.search.corpora;\n\nparcelable GetCorpusStatusRequest;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/search/corpora/GetCorpusStatusResponse.aidl",
    "content": "package com.google.android.gms.search.corpora;\n\nparcelable GetCorpusStatusResponse;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/search/corpora/RequestIndexingRequest.aidl",
    "content": "package com.google.android.gms.search.corpora;\n\nparcelable RequestIndexingRequest;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/search/corpora/RequestIndexingResponse.aidl",
    "content": "package com.google.android.gms.search.corpora;\n\nparcelable RequestIndexingResponse;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/search/corpora/internal/ISearchCorporaCallbacks.aidl",
    "content": "package com.google.android.gms.search.corpora.internal;\n\nimport com.google.android.gms.search.corpora.RequestIndexingResponse;\nimport com.google.android.gms.search.corpora.GetCorpusStatusResponse;\n\ninterface ISearchCorporaCallbacks {\n    void onRequestIndexing(in RequestIndexingResponse response) = 1;\n    void onGetCorpusStatus(in GetCorpusStatusResponse response) = 3;\n}\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/search/corpora/internal/ISearchCorporaService.aidl",
    "content": "package com.google.android.gms.search.corpora.internal;\n\nimport com.google.android.gms.search.corpora.ClearCorpusRequest;\nimport com.google.android.gms.search.corpora.GetCorpusStatusRequest;\nimport com.google.android.gms.search.corpora.GetCorpusInfoRequest;\nimport com.google.android.gms.search.corpora.RequestIndexingRequest;\nimport com.google.android.gms.search.corpora.internal.ISearchCorporaCallbacks;\n\ninterface ISearchCorporaService {\n    void requestIndexing(in RequestIndexingRequest request, ISearchCorporaCallbacks callbacks) = 1;\n    void clearCorpus(in ClearCorpusRequest request, ISearchCorporaCallbacks callbacks) = 2;\n    void getCorpusStatus(in GetCorpusStatusRequest request, ISearchCorporaCallbacks callbacks) = 3;\n    void getCorpusInfo(in GetCorpusInfoRequest request, ISearchCorporaCallbacks callbacks) = 4;\n}\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/search/global/GetCurrentExperimentIdsRequest.aidl",
    "content": "package com.google.android.gms.search.global;\n\nparcelable GetCurrentExperimentIdsRequest;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/search/global/GetCurrentExperimentIdsResponse.aidl",
    "content": "package com.google.android.gms.search.global;\n\nparcelable GetCurrentExperimentIdsResponse;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/search/global/GetGlobalSearchSourcesRequest.aidl",
    "content": "package com.google.android.gms.search.global;\n\nparcelable GetGlobalSearchSourcesRequest;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/search/global/GetGlobalSearchSourcesResponse.aidl",
    "content": "package com.google.android.gms.search.global;\n\nparcelable GetGlobalSearchSourcesResponse;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/search/global/GetPendingExperimentIdsRequest.aidl",
    "content": "package com.google.android.gms.search.global;\n\nparcelable GetPendingExperimentIdsRequest;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/search/global/GetPendingExperimentIdsResponse.aidl",
    "content": "package com.google.android.gms.search.global;\n\nparcelable GetPendingExperimentIdsResponse;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/search/global/SetExperimentIdsRequest.aidl",
    "content": "package com.google.android.gms.search.global;\n\nparcelable SetExperimentIdsRequest;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/search/global/SetExperimentIdsResponse.aidl",
    "content": "package com.google.android.gms.search.global;\n\nparcelable SetExperimentIdsResponse;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/search/global/SetIncludeInGlobalSearchRequest.aidl",
    "content": "package com.google.android.gms.search.global;\n\nparcelable SetIncludeInGlobalSearchRequest;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/search/global/SetIncludeInGlobalSearchResponse.aidl",
    "content": "package com.google.android.gms.search.global;\n\nparcelable SetIncludeInGlobalSearchResponse;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/search/global/internal/IGlobalSearchAdminCallbacks.aidl",
    "content": "package com.google.android.gms.search.global.internal;\n\nimport com.google.android.gms.search.global.GetCurrentExperimentIdsResponse;\nimport com.google.android.gms.search.global.GetGlobalSearchSourcesResponse;\nimport com.google.android.gms.search.global.GetPendingExperimentIdsResponse;\nimport com.google.android.gms.search.global.SetExperimentIdsResponse;\nimport com.google.android.gms.search.global.SetIncludeInGlobalSearchResponse;\n\ninterface IGlobalSearchAdminCallbacks {\n    void onGetGlobalSearchSourcesResponse(in GetGlobalSearchSourcesResponse request) = 1;\n    void onSetExperimentIdsResponse(in SetExperimentIdsResponse response) = 2;\n    void onGetCurrentExperimentIdsResponse(in GetCurrentExperimentIdsResponse response) = 3;\n    void onGetPendingExperimentIdsResponse(in GetPendingExperimentIdsResponse response) = 4;\n\n    void onSetIncludeInGlobalSearchResponse(in SetIncludeInGlobalSearchResponse response) = 7;\n}\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/search/global/internal/IGlobalSearchAdminService.aidl",
    "content": "package com.google.android.gms.search.global.internal;\n\nimport com.google.android.gms.search.global.GetCurrentExperimentIdsRequest;\nimport com.google.android.gms.search.global.GetGlobalSearchSourcesRequest;\nimport com.google.android.gms.search.global.GetPendingExperimentIdsRequest;\nimport com.google.android.gms.search.global.SetExperimentIdsRequest;\nimport com.google.android.gms.search.global.SetIncludeInGlobalSearchRequest;\nimport com.google.android.gms.search.global.internal.IGlobalSearchAdminCallbacks;\n\ninterface IGlobalSearchAdminService {\n    void getGlobalSearchSources(in GetGlobalSearchSourcesRequest request, IGlobalSearchAdminCallbacks callbacks) = 1;\n    void setExperimentIds(in SetExperimentIdsRequest request, IGlobalSearchAdminCallbacks callbacks) = 2;\n    void getCurrentExperimentIds(in GetCurrentExperimentIdsRequest request, IGlobalSearchAdminCallbacks callbacks) = 3;\n    void getPendingExperimentIds(in GetPendingExperimentIdsRequest request, IGlobalSearchAdminCallbacks callbacks) = 4;\n\n    void setIncludeInGlobalSearch(in SetIncludeInGlobalSearchRequest request, IGlobalSearchAdminCallbacks callbacks) = 7;\n}\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/search/queries/QueryRequest.aidl",
    "content": "package com.google.android.gms.search.queries;\n\nparcelable QueryRequest;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/search/queries/QueryResponse.aidl",
    "content": "package com.google.android.gms.search.queries;\n\nparcelable QueryResponse;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/search/queries/internal/ISearchQueriesCallbacks.aidl",
    "content": "package com.google.android.gms.search.queries.internal;\n\nimport com.google.android.gms.search.queries.QueryResponse;\n\ninterface ISearchQueriesCallbacks {\n    void onQuery(in QueryResponse response) = 1;\n}\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/search/queries/internal/ISearchQueriesService.aidl",
    "content": "package com.google.android.gms.search.queries.internal;\n\nimport com.google.android.gms.search.queries.QueryRequest;\nimport com.google.android.gms.search.queries.internal.ISearchQueriesCallbacks;\n\ninterface ISearchQueriesService {\n    void query(in QueryRequest request, ISearchQueriesCallbacks callbacks) = 1;\n}\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/semanticlocation/PlaceCandidate.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.semanticlocation;\n\nparcelable PlaceCandidate;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/semanticlocation/SemanticLocationEventRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.semanticlocation;\n\nparcelable SemanticLocationEventRequest;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/semanticlocation/SemanticLocationState.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.semanticlocation;\n\nparcelable SemanticLocationState;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/semanticlocation/internal/ISemanticLocationService.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.semanticlocation.internal;\n\nimport android.app.PendingIntent;\nimport android.os.IInterface;\nimport com.google.android.gms.semanticlocation.SemanticLocationEventRequest;\nimport com.google.android.gms.semanticlocation.internal.SemanticLocationParameters;\nimport com.google.android.gms.common.api.internal.IStatusCallback;\n\ninterface ISemanticLocationService {\n    void registerSemanticLocationEvents(in SemanticLocationParameters params, IStatusCallback callback, in SemanticLocationEventRequest request, in PendingIntent pendingIntent) = 0;\n    void unregisterSemanticLocationEvents(in SemanticLocationParameters params, IStatusCallback callback, in PendingIntent pendingIntent) = 1;\n\n    void setIncognitoMode(in SemanticLocationParameters params, IStatusCallback callback, boolean mode) = 4;\n}"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/semanticlocation/internal/SemanticLocationParameters.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.semanticlocation.internal;\n\nparcelable SemanticLocationParameters;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/semanticlocationhistory/ExperimentVisitsResponse.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.semanticlocationhistory;\n\nparcelable ExperimentVisitsResponse;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/semanticlocationhistory/FieldMask.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.semanticlocationhistory;\n\nparcelable FieldMask;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/semanticlocationhistory/FrequentPlace.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.semanticlocationhistory;\n\nparcelable FrequentPlace;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/semanticlocationhistory/FrequentTrip.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.semanticlocationhistory;\n\nparcelable FrequentTrip;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/semanticlocationhistory/InferredPlace.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.semanticlocationhistory;\n\nparcelable InferredPlace;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/semanticlocationhistory/LocationHistorySegment.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.semanticlocationhistory;\n\nparcelable LocationHistorySegment;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/semanticlocationhistory/LocationHistorySegmentRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.semanticlocationhistory;\n\nparcelable LocationHistorySegmentRequest;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/semanticlocationhistory/LocationHistorySettings.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.semanticlocationhistory;\n\nparcelable LocationHistorySettings;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/semanticlocationhistory/LookupParameters.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.semanticlocationhistory;\n\nparcelable LookupParameters;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/semanticlocationhistory/OdlhBackupSummary.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.semanticlocationhistory;\n\nparcelable OdlhBackupSummary;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/semanticlocationhistory/Persona.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.semanticlocationhistory;\n\nparcelable Persona;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/semanticlocationhistory/RequestCredentials.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.semanticlocationhistory;\n\nparcelable RequestCredentials;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/semanticlocationhistory/SemanticLocationEditInputs.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.semanticlocationhistory;\n\nparcelable SemanticLocationEditInputs;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/semanticlocationhistory/TimeRangeFilter.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.semanticlocationhistory;\n\nparcelable TimeRangeFilter;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/semanticlocationhistory/UserLocationProfile.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.semanticlocationhistory;\n\nparcelable UserLocationProfile;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/semanticlocationhistory/internal/ISemanticLocationHistoryCallbacks.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocationhistory.internal;\n\nimport com.google.android.gms.common.api.ApiMetadata;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.common.data.DataHolder;\nimport com.google.android.gms.semanticlocationhistory.ExperimentVisitsResponse;\nimport com.google.android.gms.semanticlocationhistory.InferredPlace;\nimport com.google.android.gms.semanticlocationhistory.LocationHistorySegment;\nimport com.google.android.gms.semanticlocationhistory.LocationHistorySettings;\nimport com.google.android.gms.semanticlocationhistory.OdlhBackupSummary;\nimport com.google.android.gms.semanticlocationhistory.UserLocationProfile;\n\ninterface ISemanticLocationHistoryCallbacks {\n    void onSegmentListResponse(in Status status, in List<LocationHistorySegment> segments, in ApiMetadata apiMetadata) = 0;\n    void onGetInferredHomeResponse(in Status status, in InferredPlace inferredPlace, in ApiMetadata apiMetadata) = 1;\n    void onGetInferredWorkResponse(in Status status, in InferredPlace inferredPlace, in ApiMetadata apiMetadata) = 2;\n    void onEditSegmentsResponse(in Status status, in ApiMetadata apiMetadata) = 3;\n    void onGetSegmentsResponse(in DataHolder dataHolder, in ApiMetadata apiMetadata) = 4;\n    void onDeleteHistoryResponse(in Status status, in ApiMetadata apiMetadata) = 5;\n    void onGetUserLocationProfileResponse(in Status status, in UserLocationProfile userLocationProfile, in ApiMetadata apiMetadata) = 6;\n    void onGetBackupSummaryResponse(in Status status, in List<OdlhBackupSummary> summaries, in ApiMetadata apiMetadata) = 7;\n    void onLocationHistorySettings(in Status status, in LocationHistorySettings locationHistorySettings, in ApiMetadata apiMetadata) = 8;\n    void onGetExperimentVisitsResponse(in Status status, in ExperimentVisitsResponse response, in ApiMetadata apiMetadata) = 9;\n}"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/semanticlocationhistory/internal/ISemanticLocationHistoryService.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocationhistory.internal;\n\nimport com.google.android.gms.common.api.ApiMetadata;\nimport com.google.android.gms.common.api.internal.IStatusCallback;\nimport com.google.android.gms.semanticlocation.SemanticLocationState;\nimport com.google.android.gms.semanticlocationhistory.LocationHistorySegment;\nimport com.google.android.gms.semanticlocationhistory.LocationHistorySegmentRequest;\nimport com.google.android.gms.semanticlocationhistory.RequestCredentials;\nimport com.google.android.gms.semanticlocationhistory.SemanticLocationEditInputs;\nimport com.google.android.gms.semanticlocationhistory.internal.ISemanticLocationHistoryCallbacks;\n\ninterface ISemanticLocationHistoryService {\n    void getSegments(in ISemanticLocationHistoryCallbacks callback, in RequestCredentials requestCredentials, in LocationHistorySegmentRequest request, in ApiMetadata apiMetadata) = 0;\n    void onDemandBackup(in IStatusCallback callback, in RequestCredentials requestCredentials, in ApiMetadata apiMetadata) = 1;\n    void onDemandRestore(in IStatusCallback callback, in RequestCredentials requestCredentials, in List/*<Long>*/ list, in ApiMetadata apiMetadata) = 2;\n    void getInferredHome(in ISemanticLocationHistoryCallbacks callback, in RequestCredentials requestCredentials, in ApiMetadata apiMetadata) = 3;\n    void getInferredWork(in ISemanticLocationHistoryCallbacks callback, in RequestCredentials requestCredentials, in ApiMetadata apiMetadata) = 4;\n    void editSegments(in ISemanticLocationHistoryCallbacks callback, in List<LocationHistorySegment> list, in RequestCredentials requestCredentials, in ApiMetadata apiMetadata) = 5;\n    void deleteHistory(in ISemanticLocationHistoryCallbacks callback, in RequestCredentials requestCredentials, long startTime, long endTime, in ApiMetadata apiMetadata) = 6;\n    void getUserLocationProfile(in ISemanticLocationHistoryCallbacks callback, in RequestCredentials requestCredentials, in ApiMetadata apiMetadata) = 7;\n    void getBackupSummary(in ISemanticLocationHistoryCallbacks callback, in RequestCredentials requestCredentials, in ApiMetadata apiMetadata) = 8;\n    void deleteBackups(in IStatusCallback callback, in RequestCredentials requestCredentials, in List list, in ApiMetadata apiMetadata) = 9;\n    void getLocationHistorySettings(in ISemanticLocationHistoryCallbacks callback, in RequestCredentials requestCredentials, in ApiMetadata apiMetadata) = 10;\n    void getExperimentVisits(in ISemanticLocationHistoryCallbacks callback, in RequestCredentials requestCredentials, in ApiMetadata apiMetadata) = 11;\n    void editCsl(in IStatusCallback callback, in RequestCredentials requestCredentials, in SemanticLocationEditInputs editInputs, in SemanticLocationState state, in ApiMetadata apiMetadata) = 12;\n}"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/usagereporting/UsageReportingOptInOptions.aidl",
    "content": "package com.google.android.gms.usagereporting;\n\nparcelable UsageReportingOptInOptions;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/usagereporting/internal/IUsageReportingCallbacks.aidl",
    "content": "package com.google.android.gms.usagereporting.internal;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.usagereporting.UsageReportingOptInOptions;\n\ninterface IUsageReportingCallbacks {\n    oneway void onOptInOptions(in Status status, in UsageReportingOptInOptions options) = 1;\n    oneway void onOptInOptionsSet(in Status status) = 2;\n    oneway void onOptInOptionsChangedListenerAdded(in Status status) = 3;\n    oneway void onOptInOptionsChangedListenerRemoved(in Status status) = 4;\n}\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/usagereporting/internal/IUsageReportingOptInOptionsChangedListener.aidl",
    "content": "package com.google.android.gms.usagereporting.internal;\n\ninterface IUsageReportingOptInOptionsChangedListener {\n    oneway void onOptionsChanged() = 1;\n}\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/usagereporting/internal/IUsageReportingService.aidl",
    "content": "package com.google.android.gms.usagereporting.internal;\n\nimport com.google.android.gms.usagereporting.internal.IUsageReportingCallbacks;\nimport com.google.android.gms.usagereporting.internal.IUsageReportingOptInOptionsChangedListener;\nimport com.google.android.gms.usagereporting.UsageReportingOptInOptions;\n\ninterface IUsageReportingService {\n    oneway void getOptInOptions(IUsageReportingCallbacks callbacks) = 1;\n    oneway void setOptInOptions(in UsageReportingOptInOptions options, IUsageReportingCallbacks callbacks) = 2;\n    oneway void addOptInOptionsChangedListener(IUsageReportingOptInOptionsChangedListener listener, IUsageReportingCallbacks callbacks) = 3;\n    oneway void removeOptInOptionsChangedListener(IUsageReportingOptInOptionsChangedListener listener, IUsageReportingCallbacks callbacks) = 4;\n}\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/wallet/GetClientTokenRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.wallet;\n\nparcelable GetClientTokenRequest;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/wallet/GetClientTokenResponse.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.wallet;\n\nparcelable GetClientTokenResponse;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/wallet/IsReadyToPayRequest.aidl",
    "content": "package com.google.android.gms.wallet;\n\nparcelable IsReadyToPayRequest;\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/wallet/internal/IOwService.aidl",
    "content": "package com.google.android.gms.wallet.internal;\n\nimport com.google.android.gms.wallet.internal.IWalletServiceCallbacks;\nimport com.google.android.gms.wallet.IsReadyToPayRequest;\nimport com.google.android.gms.wallet.GetClientTokenRequest;\n\ninterface IOwService {\n    void isReadyToPay(in IsReadyToPayRequest request, in Bundle args, IWalletServiceCallbacks callbacks) = 13;\n    void getClientToken(in GetClientTokenRequest getClientTokenRequest, in Bundle options, IWalletServiceCallbacks callbacks) = 14;\n}\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/android/gms/wallet/internal/IWalletServiceCallbacks.aidl",
    "content": "package com.google.android.gms.wallet.internal;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.wallet.GetClientTokenResponse;\n\ninterface IWalletServiceCallbacks {\n    void onIsReadyToPayResponse(in Status status, boolean result, in Bundle args) = 8;\n    void onClientTokenReceived(in Status status, in GetClientTokenResponse response, in Bundle extras) = 9;\n}\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/firebase/database/connection/idl/CompoundHashParcelable.aidl",
    "content": "package com.google.firebase.database.connection.idl;\n\nparcelable CompoundHashParcelable;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/firebase/database/connection/idl/ConnectionConfig.aidl",
    "content": "package com.google.firebase.database.connection.idl;\n\nparcelable ConnectionConfig;"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/firebase/database/connection/idl/IConnectionAuthTokenProvider.aidl",
    "content": "package com.google.firebase.database.connection.idl;\n\nimport com.google.firebase.database.connection.idl.IGetTokenCallback;\n\ninterface IConnectionAuthTokenProvider {\n    void zero(boolean var1, IGetTokenCallback var2) = 0;\n}"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/firebase/database/connection/idl/IGetTokenCallback.aidl",
    "content": "package com.google.firebase.database.connection.idl;\n\ninterface IGetTokenCallback {\n    void zero(String s) = 0;\n    void onError(String s) = 1;\n}"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/firebase/database/connection/idl/IListenHashProvider.aidl",
    "content": "package com.google.firebase.database.connection.idl;\n\nimport com.google.firebase.database.connection.idl.CompoundHashParcelable;\n\ninterface IListenHashProvider {\n    String zzPY() = 0;\n\n    boolean zzPZ() = 1;\n\n    CompoundHashParcelable zzQF() = 2;\n}"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/firebase/database/connection/idl/IPersistentConnection.aidl",
    "content": "package com.google.firebase.database.connection.idl;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\n\nimport com.google.firebase.database.connection.idl.ConnectionConfig;\nimport com.google.firebase.database.connection.idl.IConnectionAuthTokenProvider;\nimport com.google.firebase.database.connection.idl.IListenHashProvider;\nimport com.google.firebase.database.connection.idl.IPersistentConnectionDelegate;\nimport com.google.firebase.database.connection.idl.IRequestResultCallback;\n\n\ninterface IPersistentConnection {\n    void setup(in ConnectionConfig var1, IConnectionAuthTokenProvider var2, IObjectWrapper var3, IPersistentConnectionDelegate var4) = 0;\n\n    void initialize() = 1;\n\n    void shutdown() = 2;\n\n    void refreshAuthToken() = 3;\n\n    void listen(in List<String> var1, IObjectWrapper var2, IListenHashProvider var3, long var4, IRequestResultCallback var6) = 4;\n\n    void unlisten(in List<String> var1, IObjectWrapper var2) = 5;\n\n    void purgeOutstandingWrites() = 6;\n\n    void put(in List<String> var1, IObjectWrapper var2, IRequestResultCallback var3) = 7;\n\n    void compareAndPut(in List<String> var1, IObjectWrapper var2, String var3, IRequestResultCallback var4) = 8;\n\n    void merge(in List<String> var1, IObjectWrapper var2, IRequestResultCallback var3) = 9;\n\n    void onDisconnectPut(in List<String> var1, IObjectWrapper var2, IRequestResultCallback var3) = 10;\n\n    void onDisconnectMerge(in List<String> var1, IObjectWrapper var2, IRequestResultCallback var3) = 11;\n\n    void onDisconnectCancel(in List<String> var1, IRequestResultCallback var2) = 12;\n\n    void interrupt(String var1) = 13;\n\n    void resume(String var1) = 14;\n\n    boolean isInterrupted(String var1) = 15;\n}\n"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/firebase/database/connection/idl/IPersistentConnectionDelegate.aidl",
    "content": "package com.google.firebase.database.connection.idl;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\n\nimport com.google.firebase.database.connection.idl.RangeParcelable;\n\ninterface IPersistentConnectionDelegate {\n    void zero(in List<String> var1, IObjectWrapper var2, boolean var3, long var4) = 0;\n\n    void one(in List<String> var1, in List<RangeParcelable> var2, IObjectWrapper var3, long var4) = 1;\n\n    void two() = 2;\n\n    void onDisconnect() = 3;\n\n    void four(boolean var1) = 4;\n\n    void five(IObjectWrapper var1) = 5;\n}"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/firebase/database/connection/idl/IRequestResultCallback.aidl",
    "content": "package com.google.firebase.database.connection.idl;\n\ninterface IRequestResultCallback {\n    void zero(String var1, String var2) = 0;\n}"
  },
  {
    "path": "play-services-api/src/main/aidl/com/google/firebase/database/connection/idl/RangeParcelable.aidl",
    "content": "package com.google.firebase.database.connection.idl;\n\nparcelable RangeParcelable;"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/appdatasearch/CorpusStatus.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.appdatasearch;\n\nimport android.os.Bundle;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class CorpusStatus extends AutoSafeParcelable {\n\n    @SafeParceled(1000)\n    private int versionCode;\n    @SafeParceled(1)\n    public boolean found;\n    @SafeParceled(2)\n    public long lastIndexedSeqno;\n    @SafeParceled(3)\n    public long lastCommittedSeqno;\n    @SafeParceled(4)\n    public long committedNumDocuments;\n    @SafeParceled(5)\n    public Bundle counters;\n    @SafeParceled(6)\n    public String g;\n\n    public CorpusStatus() {\n        versionCode = 2;\n    }\n\n    public static final Creator<CorpusStatus> CREATOR = new AutoCreator<CorpusStatus>(CorpusStatus.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/appdatasearch/PIMEUpdate.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.appdatasearch;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class PIMEUpdate extends AutoSafeParcelable {\n\n    public static final Creator<PIMEUpdate> CREATOR = new AutoCreator<PIMEUpdate>(PIMEUpdate.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/appdatasearch/PIMEUpdateResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.appdatasearch;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class PIMEUpdateResponse extends AutoSafeParcelable {\n    @SafeParceled(1000)\n    private int versionCode;\n\n    @SafeParceled(1)\n    private String b;\n\n    @SafeParceled(2)\n    public final byte[] bytes;\n\n    @SafeParceled(3)\n    public final PIMEUpdate[] updates;\n\n    public PIMEUpdateResponse() {\n        versionCode = 1;\n        this.bytes = null;\n        this.updates = new PIMEUpdate[0];\n    }\n\n    public static final Creator<PIMEUpdateResponse> CREATOR = new AutoCreator<PIMEUpdateResponse>(PIMEUpdateResponse.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/appdatasearch/QuerySpecification.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.appdatasearch;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\nimport java.util.List;\n\npublic class QuerySpecification extends AutoSafeParcelable {\n\n    @SafeParceled(1000)\n    private int versionCode = 2;\n    @SafeParceled(1)\n    public final boolean b;\n    //@SafeParceled(value = 2, subType = \"TODO\")\n    public final List c;\n    //@SafeParceled(value = 3, subType = \"TODO\")\n    public final List d;\n    @SafeParceled(4)\n    public final boolean e;\n    @SafeParceled(5)\n    public final int f;\n    @SafeParceled(6)\n    public final int g;\n    @SafeParceled(7)\n    public final boolean h;\n    @SafeParceled(8)\n    public final int i;\n\n    private QuerySpecification() {\n        b = false;\n        c = null;\n        d = null;\n        e = false;\n        f = 0;\n        g = 0;\n        h = false;\n        i = 0;\n    }\n\n    @Override\n    public String toString() {\n        return \"QuerySpecification{\" +\n                \"versionCode=\" + versionCode +\n                \", b=\" + b +\n                \", c=\" + c +\n                \", d=\" + d +\n                \", e=\" + e +\n                \", f=\" + f +\n                \", g=\" + g +\n                \", h=\" + h +\n                \", i=\" + i +\n                '}';\n    }\n\n    public static final Creator<QuerySpecification> CREATOR = new AutoCreator<QuerySpecification>(QuerySpecification.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/appdatasearch/RequestIndexingSpecification.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.appdatasearch;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class RequestIndexingSpecification extends AutoSafeParcelable {\n\n    @SafeParceled(1000)\n    private int versionCode;\n\n    public static final Creator<RequestIndexingSpecification> CREATOR = new AutoCreator<RequestIndexingSpecification>(RequestIndexingSpecification.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/appdatasearch/SearchResults.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.appdatasearch;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class SearchResults extends AutoSafeParcelable {\n    @SafeParceled(1000)\n    private int versionCode = 2;\n\n    public static Creator<SearchResults> CREATOR = new AutoCreator<SearchResults>(SearchResults.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/appdatasearch/SuggestSpecification.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.appdatasearch;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class SuggestSpecification extends AutoSafeParcelable {\n    @SafeParceled(1000)\n    private int versionCode;\n\n    public SuggestSpecification() {\n        versionCode = 2;\n    }\n\n    public static final Creator<SuggestSpecification> CREATOR = new AutoCreator<SuggestSpecification>(SuggestSpecification.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/appdatasearch/SuggestionResults.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.appdatasearch;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class SuggestionResults extends AutoSafeParcelable {\n    @SafeParceled(1000)\n    private int versionCode;\n    @SafeParceled(1)\n    public final String errorMessage;\n\n    @SafeParceled(2)\n    public final String[] s1;\n    @SafeParceled(3)\n    public final String[] s2;\n\n    private SuggestionResults() {\n        versionCode = 2;\n        errorMessage = null;\n        s1 = s2 = null;\n    }\n\n    public SuggestionResults(String errorMessage) {\n        versionCode = 2;\n        this.errorMessage = errorMessage;\n        this.s1 = null;\n        this.s2 = null;\n    }\n\n    public SuggestionResults(String[] s1, String[] s2) {\n        versionCode = 2;\n        this.errorMessage = null;\n        this.s1 = s1;\n        this.s2 = s2;\n    }\n\n    public static final Creator<SuggestionResults> CREATOR = new AutoCreator<SuggestionResults>(SuggestionResults.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/appdatasearch/UsageInfo.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.appdatasearch;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class UsageInfo extends AutoSafeParcelable {\n\n    public static Creator<UsageInfo> CREATOR = new AutoCreator<UsageInfo>(UsageInfo.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/audit/LogAuditRecordsRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.audit;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class LogAuditRecordsRequest extends AbstractSafeParcelable {\n    @Field(1)\n    public int writeMode;\n    @Field(2)\n    public int componentId;\n    @Field(3)\n    public String accountName;\n    @Field(4)\n    public byte[][] auditRecords;\n    @Field(5)\n    public byte[] traceToken;\n    @Field(6)\n    public byte[] auditToken;\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"LogAuditRecordsRequest\")\n                .field(\"writeMode\", writeMode)\n                .field(\"componentId\", componentId)\n                .field(\"accountName\", accountName)\n                .field(\"auditRecords\", auditRecords)\n                .field(\"traceToken\", traceToken)\n                .field(\"auditToken\", auditToken)\n                .end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<LogAuditRecordsRequest> CREATOR = findCreator(LogAuditRecordsRequest.class);\n\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/auth/firstparty/dataservice/AccountRecoveryGuidanceRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.auth.firstparty.dataservice;\n\nimport android.accounts.Account;\n\nimport org.microg.gms.auth.AuthConstants;\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class AccountRecoveryGuidanceRequest extends AutoSafeParcelable {\n\n    @SafeParceled(1)\n    private int versionCode = 1;\n    @SafeParceled(2)\n    @Deprecated\n    public final String accountName;\n    @SafeParceled(3)\n    public final Account account;\n\n    public AccountRecoveryGuidanceRequest(String accountName) {\n        this.accountName = accountName;\n        this.account = new Account(accountName, AuthConstants.DEFAULT_ACCOUNT_TYPE);\n    }\n\n    public AccountRecoveryGuidanceRequest(Account account) {\n        this.accountName = account.name;\n        this.account = account;\n    }\n\n    public static final Creator<AccountRecoveryGuidanceRequest> CREATOR = new AutoCreator<AccountRecoveryGuidanceRequest>(AccountRecoveryGuidanceRequest.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/auth/firstparty/dataservice/AccountRemovalRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.auth.firstparty.dataservice;\n\nimport android.accounts.Account;\n\nimport org.microg.gms.auth.AuthConstants;\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class AccountRemovalRequest extends AutoSafeParcelable {\n\n    @SafeParceled(1)\n    private int versionCode = 1;\n    @SafeParceled(2)\n    @Deprecated\n    public final String accountName;\n    @SafeParceled(3)\n    public final Account account;\n\n    public AccountRemovalRequest(String accountName) {\n        this.accountName = accountName;\n        this.account = new Account(accountName, AuthConstants.DEFAULT_ACCOUNT_TYPE);\n    }\n\n    public AccountRemovalRequest(Account account) {\n        this.accountName = account.name;\n        this.account = account;\n    }\n\n    public static final Creator<AccountRemovalRequest> CREATOR = new AutoCreator<AccountRemovalRequest>(AccountRemovalRequest.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/auth/firstparty/dataservice/ConfirmCredentialsRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.auth.firstparty.dataservice;\n\nimport com.google.android.gms.auth.firstparty.shared.AccountCredentials;\nimport com.google.android.gms.auth.firstparty.shared.CaptchaSolution;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class ConfirmCredentialsRequest extends AutoSafeParcelable {\n    @SafeParceled(1)\n    private int versionCode = 1;\n    @SafeParceled(2)\n    public AccountCredentials accountCredentials;\n    @SafeParceled(3)\n    public CaptchaSolution captchaSolution;\n\n    public static final Creator<ConfirmCredentialsRequest> CREATOR = new AutoCreator<ConfirmCredentialsRequest>(ConfirmCredentialsRequest.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/auth/firstparty/dataservice/FACLConfig.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.firstparty.dataservice;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class FACLConfig extends AutoSafeParcelable {\n    @Field(1)\n    public int versionCode = 1;\n    @Field(2)\n    public boolean allCirclesVisible;\n    @Field(3)\n    public String visibleEdges;\n    @Field(4)\n    public boolean allContactsVisible;\n    @Field(5)\n    public boolean showCircles;\n    @Field(6)\n    public boolean showContacts;\n    @Field(7)\n    public boolean hasShowCircles;\n\n    public static final Creator<FACLConfig> CREATOR = new AutoCreator<FACLConfig>(FACLConfig.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/auth/firstparty/dataservice/PACLConfig.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.firstparty.dataservice;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class PACLConfig extends AutoSafeParcelable {\n    @Field(1)\n    private int versionCode = 1;\n    @Field(2)\n    public String visibleActions;\n    @Field(3)\n    public String data;\n\n    public static final Creator<PACLConfig> CREATOR = new AutoCreator<PACLConfig>(PACLConfig.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/auth/firstparty/dataservice/TokenRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2015 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.firstparty.dataservice;\n\nimport android.accounts.Account;\nimport android.os.Bundle;\n\nimport com.google.android.gms.auth.firstparty.shared.AppDescription;\nimport com.google.android.gms.auth.firstparty.shared.CaptchaSolution;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class TokenRequest extends AutoSafeParcelable {\n    @Field(1)\n    private int versionCode = 8;\n    @Field(2)\n    private String service;\n    @Field(3)\n    public String accountName;\n    @Field(4)\n    public Bundle extras;\n    @Field(5)\n    public FACLConfig faclConfig;\n    @Field(6)\n    public PACLConfig paclConfig;\n    @Field(7)\n    public boolean signingIn;\n    @Field(9)\n    public String consent;\n    @Field(10)\n    public AppDescription callingAppDescription;\n    @Field(11)\n    public CaptchaSolution captchaSolution;\n    @Field(14)\n    public boolean useCache;\n    @Field(15)\n    public String accountType;\n    @Field(16)\n    public int delegationType;\n    @Field(17)\n    public String delegateeUserId;\n    @Field(19)\n    public String consentResult;\n    @Field(24)\n    public int mode;\n\n    public Account getAccount() {\n        return new Account(accountName, accountType);\n    }\n\n    public static final Creator<TokenRequest> CREATOR = new AutoCreator<TokenRequest>(TokenRequest.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/auth/firstparty/dataservice/TokenResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.auth.firstparty.dataservice;\n\npublic class TokenResponse {\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/auth/firstparty/delegate/ConfirmCredentialsWorkflowRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.auth.firstparty.delegate;\n\nimport android.accounts.Account;\nimport android.accounts.AccountAuthenticatorResponse;\nimport android.os.Bundle;\n\nimport com.google.android.gms.auth.firstparty.shared.AppDescription;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class ConfirmCredentialsWorkflowRequest extends AutoSafeParcelable {\n    @SafeParceled(1)\n    private int versionCode = 3;\n    @SafeParceled(2)\n    public String accountName;\n    @SafeParceled(3)\n    public AppDescription appDescription;\n    @SafeParceled(4)\n    public Bundle extras;\n    @SafeParceled(5)\n    public Account account;\n    @SafeParceled(6)\n    public AccountAuthenticatorResponse accountAuthenticatorResponse;\n\n    public static final Creator<ConfirmCredentialsWorkflowRequest> CREATOR = new AutoCreator<ConfirmCredentialsWorkflowRequest>(ConfirmCredentialsWorkflowRequest.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/auth/firstparty/proximity/data/Permit.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.auth.firstparty.proximity.data;\n\npublic class Permit {\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/auth/firstparty/shared/AccountCredentials.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.auth.firstparty.shared;\n\nimport android.accounts.Account;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\n// TODO\npublic class AccountCredentials extends AutoSafeParcelable {\n    @SafeParceled(1)\n    private int versionCode = 2;\n    @SafeParceled(3)\n    public String accountName;\n    @SafeParceled(9)\n    public String accountType;\n\n    public Account getAccount() {\n        return new Account(accountName, accountType);\n    }\n\n    public static final Creator<AccountCredentials> CREATOR = new AutoCreator<AccountCredentials>(AccountCredentials.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/auth/firstparty/shared/AppDescription.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.auth.firstparty.shared;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class AppDescription extends AutoSafeParcelable {\n    @SafeParceled(1)\n    private int versionCode = 1;\n    @SafeParceled(2)\n    public int callingUid;\n    @SafeParceled(3)\n    public String sessiondId;\n    @SafeParceled(4)\n    public String sessiondSig;\n    @SafeParceled(5)\n    public String callingPkg;\n\n    public static final Creator<AppDescription> CREATOR = new AutoCreator<AppDescription>(AppDescription.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/auth/firstparty/shared/CaptchaSolution.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.auth.firstparty.shared;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\n// TODO\npublic class CaptchaSolution extends AutoSafeParcelable {\n\n    @SafeParceled(1)\n    private int versionCode = 1;\n\n    public static final Creator<CaptchaSolution> CREATOR = new AutoCreator<CaptchaSolution>(CaptchaSolution.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/credential/manager/invocationparams/CallerInfo.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.credential.manager.invocationparams;\n\nimport androidx.annotation.NonNull;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class CallerInfo extends AutoSafeParcelable {\n    @Field(1)\n    public String source;\n    @Field(2)\n    public String medium;\n    @Field(3)\n    public String campaign;\n    @Field(4)\n    public String content;\n\n    @NonNull\n    @Override\n    public String toString() {\n        return \"CallerInfo(\" + source + \",\" + medium + \",\" + campaign + \",\" + content + \")\";\n    }\n\n    public static final Creator<CallerInfo> CREATOR = new AutoCreator<>(CallerInfo.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/credential/manager/invocationparams/CredentialManagerAccount.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.credential.manager.invocationparams;\n\nimport androidx.annotation.NonNull;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class CredentialManagerAccount extends AutoSafeParcelable {\n    @Field(1)\n    public String name;\n\n    @NonNull\n    @Override\n    public String toString() {\n        return name;\n    }\n\n    public static final String NAME_LOCAL = \"pwm.constant.LocalAccount\";\n    public static final Creator<CredentialManagerAccount> CREATOR = new AutoCreator<>(CredentialManagerAccount.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/credential/manager/invocationparams/CredentialManagerInvocationParams.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.credential.manager.invocationparams;\n\nimport androidx.annotation.NonNull;\nimport org.microg.gms.utils.ToStringHelper;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class CredentialManagerInvocationParams extends AutoSafeParcelable {\n    @Field(1)\n    public CredentialManagerAccount account;\n    @Field(2)\n    public CallerInfo caller;\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"CredentialManagerInvocationParams\")\n                .field(\"account\", account)\n                .field(\"caller\", caller)\n                .end();\n    }\n\n    public static final Creator<CredentialManagerInvocationParams> CREATOR = new AutoCreator<>(CredentialManagerInvocationParams.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/facs/cache/FacsCacheCallOptions.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.facs.cache;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class FacsCacheCallOptions extends AutoSafeParcelable {\n    @Field(1)\n    public String instanceId;\n    @Field(2)\n    public long version;\n\n    public static final Creator<FacsCacheCallOptions> CREATOR = new AutoCreator<>(FacsCacheCallOptions.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/facs/cache/ForceSettingsCacheRefreshResult.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.facs.cache;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class ForceSettingsCacheRefreshResult extends AutoSafeParcelable {\n\n    public static final Creator<ForceSettingsCacheRefreshResult> CREATOR = new AutoCreator<>(ForceSettingsCacheRefreshResult.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/facs/cache/GetActivityControlsSettingsResult.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.facs.cache;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class GetActivityControlsSettingsResult extends AbstractSafeParcelable {\n    @Field(value = 1)\n    public byte[] bytes;\n\n    @Constructor\n    public GetActivityControlsSettingsResult(@Param(1) byte[] data) {\n        this.bytes = data;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<GetActivityControlsSettingsResult> CREATOR = findCreator(GetActivityControlsSettingsResult.class);\n\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/facs/cache/ReadDeviceLevelSettingsResult.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.facs.cache;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class ReadDeviceLevelSettingsResult extends AutoSafeParcelable {\n\n    public static final Creator<ReadDeviceLevelSettingsResult> CREATOR = new AutoCreator<>(ReadDeviceLevelSettingsResult.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/facs/cache/UpdateActivityControlsSettingsResult.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.facs.cache;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class UpdateActivityControlsSettingsResult extends AutoSafeParcelable {\n\n    public static final Creator<UpdateActivityControlsSettingsResult> CREATOR = new AutoCreator<>(UpdateActivityControlsSettingsResult.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/family/model/MemberDataModel.java",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.family.model;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class MemberDataModel extends AbstractSafeParcelable {\n    @Field(1)\n    public String memberId = \"\";\n    @Field(2)\n    public String email = \"\";\n    @Field(3)\n    public String displayName = \"\";\n    @Field(4)\n    public String hohGivenName = \"\";\n    @Field(5)\n    public String profilePhotoUrl = \"\";\n    @Field(6)\n    public String roleName = \"\";\n    @Field(7)\n    public int role = 0;\n    @Field(8)\n    public boolean isActive = false;\n    @Field(9)\n    public int supervisionType = 0;\n    @Field(10)\n    public long timestamp = 0;\n    @Field(11)\n    public boolean isInviteEntry = false;\n    @Field(12)\n    public int inviteSlots = 0;\n    @Field(13)\n    public boolean isInvited = false;\n    @Field(14)\n    public String invitationId = \"\";\n    @Field(15)\n    public long inviteState = 0;\n    @Field(16)\n    public String inviteSentDate = \"\";\n\n    public static final SafeParcelableCreatorAndWriter<MemberDataModel> CREATOR = findCreator(MemberDataModel.class);\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    @Override\n    public String toString() {\n        return \"MemberDataModel{\" +\n                \"memberId='\" + memberId + '\\'' +\n                \", email='\" + email + '\\'' +\n                \", displayName='\" + displayName + '\\'' +\n                \", hohGivenName='\" + hohGivenName + '\\'' +\n                \", profilePhotoUrl='\" + profilePhotoUrl + '\\'' +\n                \", roleName='\" + roleName + '\\'' +\n                \", role=\" + role +\n                \", isActive=\" + isActive +\n                \", supervisionType=\" + supervisionType +\n                \", timestamp=\" + timestamp +\n                \", isInviteEntry=\" + isInviteEntry +\n                \", inviteSlots=\" + inviteSlots +\n                \", isInvited=\" + isInvited +\n                \", invitationId='\" + invitationId + '\\'' +\n                \", inviteState=\" + inviteState +\n                \", inviteSentDate='\" + inviteSentDate + '\\'' +\n                '}';\n    }\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/family/v2/model/BulletPoint.java",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.family.v2.model;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class BulletPoint implements Parcelable {\n\n    public HashMap<Integer, String> contentMap = new HashMap<>();\n\n    public BulletPoint() {\n    }\n\n    public BulletPoint(HashMap<Integer, String> contentMap) {\n        this.contentMap = contentMap;\n    }\n\n    public BulletPoint(Parcel parcel) {\n        int readInt = parcel.readInt();\n        for (int i = 0; i < readInt; i++) {\n            this.contentMap.put(parcel.readInt(), parcel.readString());\n        }\n    }\n\n    public final boolean equals(Object obj) {\n        return (obj instanceof BulletPoint) && ((BulletPoint) obj).contentMap.equals(this.contentMap);\n    }\n\n    public final int hashCode() {\n        return Arrays.hashCode(new Object[]{this.contentMap});\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.contentMap.size());\n        for (Map.Entry entry : this.contentMap.entrySet()) {\n            dest.writeInt((Integer) entry.getKey());\n            dest.writeString((String) entry.getValue());\n        }\n    }\n\n    public static final Creator<BulletPoint> CREATOR = new Creator<BulletPoint>() {\n        @Override\n        public BulletPoint createFromParcel(Parcel source) {\n            return new BulletPoint(source);\n        }\n\n        @Override\n        public BulletPoint[] newArray(int size) {\n            return new BulletPoint[size];\n        }\n    };\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/family/v2/model/HelpData.java",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.family.v2.model;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class HelpData extends AbstractSafeParcelable {\n    @Field(1)\n    public String linkUrl;\n    @Field(2)\n    public String appContext;\n\n    public HelpData() {\n    }\n\n    public HelpData(String linkUrl, String appContext) {\n        this.linkUrl = linkUrl;\n        this.appContext = appContext;\n    }\n\n    public static final SafeParcelableCreatorAndWriter<HelpData> CREATOR = findCreator(HelpData.class);\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    @Override\n    public String toString() {\n        return \"HelpData{\" +\n                \"linkUrl='\" + linkUrl + '\\'' +\n                \", appContext='\" + appContext + '\\'' +\n                '}';\n    }\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/family/v2/model/PageData.java",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.family.v2.model;\n\nimport android.os.Parcelable;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.Objects;\n\npublic class PageData extends AutoSafeParcelable {\n    @Field(1)\n    public int version = 1;\n    @Field(2)\n    public HashMap<Integer, String> sectionMap = new HashMap<>();\n    @Field(3)\n    public HashMap<String, HelpData> helpMap = new HashMap<>();\n    @Field(4)\n    public ArrayList<BulletPoint> bulletPoints = new ArrayList<>();\n\n    public PageData() {}\n\n    public PageData(HashMap<Integer, String> sectionMap, HashMap<String, HelpData> helpMap, ArrayList<BulletPoint> bulletPoints) {\n        this.sectionMap = sectionMap;\n        this.helpMap = helpMap;\n        this.bulletPoints = bulletPoints;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) return true;\n        if (!(obj instanceof PageData)) return false;\n        PageData other = (PageData) obj;\n        return version == other.version &&\n                Objects.equals(sectionMap, other.sectionMap) &&\n                Objects.equals(helpMap, other.helpMap) &&\n                Objects.equals(bulletPoints, other.bulletPoints);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(version, sectionMap, helpMap, bulletPoints);\n    }\n\n    @Override\n    public String toString() {\n        return \"PageData{\" +\n                \"version=\" + version +\n                \", sectionMap=\" + sectionMap +\n                \", helpMap=\" + helpMap +\n                \", bulletPoints=\" + bulletPoints +\n                '}';\n    }\n\n    public static final Parcelable.Creator<PageData> CREATOR = findCreator(PageData.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/feedback/ErrorReport.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.feedback;\n\nimport android.app.ApplicationErrorReport;\nimport android.graphics.Bitmap;\nimport android.graphics.RectF;\nimport android.os.Bundle;\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.data.BitmapTeleporter;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport java.util.List;\n\n@SafeParcelable.Class\npublic class ErrorReport extends AbstractSafeParcelable {\n    @Field(2)\n    public ApplicationErrorReport applicationErrorReport;\n    @Field(3)\n    public String feedbackMsg;\n    @Field(4)\n    public int versionCode;\n    @Field(5)\n    public String versionName;\n    @Field(6)\n    public String mobileDevice;\n    @Field(7)\n    public String mobileDisplay;\n    @Field(8)\n    public String mobileType;\n    @Field(9)\n    public String mobileModel;\n    @Field(10)\n    public String mobileProduct;\n    @Field(11)\n    public String mobileFingerprint;\n    @Field(12)\n    public int mobileSdkInt;\n    @Field(13)\n    public String mobileRelease;\n    @Field(14)\n    public String mobileIncremental;\n    @Field(15)\n    public String mobileCodeName;\n    @Field(16)\n    public String mobileBoard;\n    @Field(17)\n    public String mobileBrand;\n    @Field(18)\n    public String[] unknownStringArray18;\n    @Field(19)\n    public String[] unknownStringArray19;\n    @Field(20)\n    public String[] unknownStringArray20;\n    @Field(21)\n    public String unknownString21;\n    @Field(22)\n    public String screenshotImgSrc;\n    @Field(23)\n    public byte[] screenshotImgData;\n    @Field(24)\n    public int screenshotHeight;\n    @Field(25)\n    public int screenshotWidth;\n    @Field(26)\n    public int phoneType;\n    @Field(27)\n    public int networkType;\n    @Field(28)\n    public String networkOperatorName;\n    @Field(29)\n    public String email;\n    @Field(30)\n    public String languageTag;\n    @Field(31)\n    public Bundle bundle;\n    @Field(32)\n    public boolean isFixedUri;\n    @Field(33)\n    public int mobileCountryCode;\n    @Field(34)\n    public int mobileNetworkCode;\n    @Field(35)\n    public boolean unknownBool35;\n    @Field(36)\n    public String exceptionClassName;\n    @Field(37)\n    public String throwFileName;\n    @Field(38)\n    public int throwLineNumber;\n    @Field(39)\n    public String throwClassName;\n    @Field(40)\n    public String throwMethodName;\n    @Field(41)\n    public String stackTrace;\n    @Field(42)\n    public String exceptionMessage;\n    @Field(43)\n    public String unknownString43;\n    @Field(44)\n    public String unknownString44;\n    @Field(45)\n    public String packageName;\n    @Field(46)\n    public BitmapTeleporter bitmapTeleporter;\n    @Field(47)\n    public String unknownString47;\n    @Field(48)\n    public FileTeleporter[] files;\n    @Field(49)\n    public String[] unknownByteArray49;\n    @Field(50)\n    public boolean unknownBool50;\n    @Field(51)\n    public String unknownString51;\n    @Field(52)\n    public ThemeSettings themeSettings;\n    @Field(53)\n    public LogOptions logOptions;\n    @Field(54)\n    public String unknownString54;\n    @Field(55)\n    public boolean unknownBool55;\n    @Field(56)\n    public Bundle bundleText;\n    @Field(57)\n    public List<RectF> rectFS;\n    @Field(58)\n    public boolean unknownBool58;\n    @Field(59)\n    public Bitmap bitmap;\n    @Field(60)\n    public String unknownString60;\n    @Field(61)\n    public List<String> camList;\n    @Field(62)\n    public int unknownInt62;\n    @Field(63)\n    public int unknownInt63;\n    @Field(64)\n    public String[] unknownStringArray64;\n    @Field(65)\n    public String[] unknownStringArray65;\n    @Field(66)\n    public String[] unknownStringArray66;\n\n    public static final SafeParcelableCreatorAndWriter<ErrorReport> CREATOR = findCreator(ErrorReport.class);\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/feedback/FeedbackOptions.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.feedback;\n\nimport android.app.ApplicationErrorReport;\nimport android.graphics.Bitmap;\nimport android.os.Bundle;\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.data.BitmapTeleporter;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport java.util.List;\n\n@SafeParcelable.Class\npublic class FeedbackOptions extends AbstractSafeParcelable {\n\n    public static final SafeParcelableCreatorAndWriter<FeedbackOptions> CREATOR = findCreator(FeedbackOptions.class);\n\n    @Field(2)\n    public String unknownString2;\n    @Field(3)\n    public Bundle unknownBundle3;\n    @Field(5)\n    public String unknownString3;\n    @Field(6)\n    public ApplicationErrorReport applicationErrorReport;\n    @Field(7)\n    public String unknownString7;\n    @Field(8)\n    public BitmapTeleporter bitmapTeleporter;\n    @Field(9)\n    public String packageName;\n    @Field(10)\n    public List<FileTeleporter> files;\n    @Field(11)\n    public boolean unknownBoolean11;\n    @Field(12)\n    public ThemeSettings themeSettings;\n    @Field(13)\n    public LogOptions logOptions;\n    @Field(14)\n    public boolean unknownBoolean14;\n    @Field(15)\n    public Bitmap screenshot;\n    @Field(16)\n    public String unknownString16;\n    @Field(17)\n    public boolean unknownBoolean17;\n    @Field(18)\n    public long unknownLong18;\n    @Field(19)\n    public boolean unknownBool19;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/feedback/FileTeleporter.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.feedback;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class FileTeleporter extends AbstractSafeParcelable {\n    @Field(3)\n    public String contentType;\n    @Field(4)\n    public String content;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<FileTeleporter> CREATOR = findCreator(FileTeleporter.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/feedback/LogOptions.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.feedback;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class LogOptions extends AbstractSafeParcelable {\n\n    @Field(2)\n    public String options;\n    @Field(3)\n    public boolean unknownBool3;\n    @Field(4)\n    public boolean unknownBool4;\n    @Field(5)\n    public boolean unknownBool5;\n    @Field(6)\n    public boolean unknownBool6;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<LogOptions> CREATOR = findCreator(LogOptions.class);\n\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/feedback/ThemeSettings.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.feedback;\n\nimport androidx.annotation.NonNull;\nimport org.microg.gms.utils.ToStringHelper;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class ThemeSettings extends AutoSafeParcelable {\n    @Field(2)\n    public int unknownInt2;\n    @Field(3)\n    public int unknownInt3;\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"ThemeSettings\")\n                .field(\"2\", unknownInt2)\n                .field(\"3\", unknownInt3)\n                .end();\n    }\n\n    public static final Creator<ThemeSettings> CREATOR = findCreator(ThemeSettings.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/gass/internal/GassRequestParcel.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.gass.internal;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class GassRequestParcel extends AbstractSafeParcelable {\n\n    @Field(1)\n    public int versionCode;\n    @Field(2)\n    public String packageName;\n    @Field(3)\n    public String appVersionCode;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<GassRequestParcel> CREATOR = findCreator(GassRequestParcel.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/gass/internal/GassResponseParcel.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.gass.internal;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.feedback.ErrorReport;\n\n@SafeParcelable.Class\npublic class GassResponseParcel extends AbstractSafeParcelable {\n\n    @Field(1)\n    public int versionCode;\n\n    @Field(2)\n    public byte[] data;\n\n    public ErrorReport report;\n\n    public GassResponseParcel() {\n    }\n\n    public GassResponseParcel(int i, byte[] bArr) {\n        this.versionCode = i;\n        this.report = null;\n        this.data = bArr;\n    }\n\n    public GassResponseParcel(ErrorReport report) {\n        this.versionCode = 1;\n        this.report = report;\n        this.data = null;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<GassResponseParcel> CREATOR = findCreator(GassResponseParcel.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/googlehelp/FRDProductSpecificDataEntry.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.googlehelp;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class FRDProductSpecificDataEntry extends AutoSafeParcelable {\n    public static final Creator<FRDProductSpecificDataEntry> CREATOR = findCreator(FRDProductSpecificDataEntry.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/googlehelp/GoogleHelp.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.googlehelp;\n\nimport android.accounts.Account;\nimport android.app.PendingIntent;\nimport android.graphics.Bitmap;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.feedback.ErrorReport;\nimport com.google.android.gms.feedback.ThemeSettings;\nimport com.google.android.gms.googlehelp.internal.common.OverflowMenuItem;\nimport com.google.android.gms.googlehelp.internal.common.TogglingData;\nimport org.microg.gms.utils.ToStringHelper;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\nimport java.util.List;\n\npublic class GoogleHelp extends AutoSafeParcelable {\n    @Field(1)\n    private int versionCode;\n    @Field(2)\n    public String appContext;\n    @Field(3)\n    public Account account;\n    @Field(4)\n    public Bundle extras;\n    @Field(5)\n    public boolean unknownBool5;\n    @Field(6)\n    public boolean unknownBool6;\n    @Field(7)\n    public List<String> unknownStringList7;\n    @Field(15)\n    public Uri uri;\n    @Field(16)\n    public List<OverflowMenuItem> overflowMenuItems;\n    @Field(17)\n    public int unknownAlwaysZero17;\n    @Field(18)\n    public List<OfflineSuggestion> offlineSuggestions;\n    @Field(20)\n    public int unknownInt20;\n    @Field(21)\n    public int unknownInt21;\n    @Field(22)\n    public boolean unknownBool22;\n    @Field(23)\n    public ErrorReport errorReport;\n    @Field(25)\n    public ThemeSettings themeSettings;\n    @Field(28)\n    public String appPackageName;\n    @Field(31)\n    public TogglingData togglingData;\n    @Field(32)\n    public int unknownInt32;\n    @Field(33)\n    public PendingIntent customFeedbackPendingIntent;\n    @Field(34)\n    public String title;\n    @Field(35)\n    public Bitmap icon;\n    @Field(36)\n    public int unknownInt36;\n    @Field(37)\n    public boolean unknownBool37;\n    @Field(38)\n    public boolean unknownBool38;\n    @Field(39)\n    public int timeout;\n    @Field(40)\n    public String sessionId;\n    @Field(41)\n    public boolean unknownBool41;\n    @Field(42)\n    public String clientPackageName;\n    @Field(43)\n    public boolean unknownBool43;\n    @Field(44)\n    public ND4CSettings nd4CSettings;\n    @Field(45)\n    public boolean unknownBool45;\n    @Field(46)\n    public List<FRDProductSpecificDataEntry> productSpecificDataEntries;\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"GoogleHelp\")\n                .field(\"appContext\", appContext)\n                .field(\"account\", account)\n                .field(\"extras\", extras)\n                .field(\"5\", unknownBool5)\n                .field(\"6\", unknownBool6)\n                .field(\"7\", unknownStringList7)\n                .field(\"uri\", uri)\n                .field(\"overflowMenuItems\", overflowMenuItems)\n                .field(\"17\", unknownAlwaysZero17)\n                .field(\"offlineSuggestions\", offlineSuggestions)\n                .field(\"20\", unknownInt20)\n                .field(\"21\", unknownInt21)\n                .field(\"22\", unknownBool22)\n                .field(\"errorReport\", errorReport)\n                .field(\"themeSettings\", themeSettings)\n                .field(\"appPackageName\", appPackageName)\n                .field(\"togglingData\", togglingData)\n                .field(\"32\", unknownInt32)\n                .field(\"customFeedbackPendingIntent\", customFeedbackPendingIntent)\n                .field(\"title\", title)\n                .field(\"icon\", icon)\n                .field(\"36\", unknownInt36)\n                .field(\"37\", unknownBool37)\n                .field(\"38\", unknownBool38)\n                .field(\"timeout\", timeout)\n                .field(\"sessionId\", sessionId)\n                .field(\"41\", unknownBool41)\n                .field(\"clientPackageName\", clientPackageName)\n                .field(\"43\", unknownBool43)\n                .field(\"nd4CSettings\", nd4CSettings)\n                .field(\"45\", unknownBool45)\n                .field(\"productSpecificDataEntries\", productSpecificDataEntries)\n                .end();\n    }\n\n    public static final Creator<GoogleHelp> CREATOR = findCreator(GoogleHelp.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/googlehelp/InProductHelp.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.googlehelp;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class InProductHelp extends AutoSafeParcelable {\n    @Field(1)\n    public GoogleHelp googleHelp;\n    public static final Creator<InProductHelp> CREATOR = findCreator(InProductHelp.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/googlehelp/ND4CSettings.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.googlehelp;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class ND4CSettings extends AutoSafeParcelable {\n    public static final Creator<ND4CSettings> CREATOR = findCreator(ND4CSettings.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/googlehelp/OfflineSuggestion.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.googlehelp;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class OfflineSuggestion extends AutoSafeParcelable {\n    public static final Creator<OfflineSuggestion> CREATOR = findCreator(OfflineSuggestion.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/googlehelp/SupportRequestHelp.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.googlehelp;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class SupportRequestHelp extends AutoSafeParcelable {\n    @Field(1)\n    public GoogleHelp googleHelp;\n    @Field(4)\n    public String phoneNumber;\n\n    public static final Creator<SupportRequestHelp> CREATOR = findCreator(SupportRequestHelp.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/googlehelp/internal/common/OverflowMenuItem.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.googlehelp.internal.common;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class OverflowMenuItem extends AutoSafeParcelable {\n    public static final Creator<OverflowMenuItem> CREATOR = findCreator(OverflowMenuItem.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/googlehelp/internal/common/TogglingData.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.googlehelp.internal.common;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class TogglingData extends AutoSafeParcelable {\n    public static final Creator<TogglingData> CREATOR = findCreator(TogglingData.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/identity/accounts/api/AccountData.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.identity.accounts.api;\n\npublic class AccountData {\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/identity/intents/model/CountrySpecification.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.identity.intents.model;\n\npublic class CountrySpecification {\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/identity/intents/model/UserAddress.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.identity.intents.model;\n\npublic class UserAddress {\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/languageprofile/ClientLanguageSettings.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.languageprofile;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class ClientLanguageSettings extends AutoSafeParcelable {\n    public static final Creator<ClientLanguageSettings> CREATOR = new AutoCreator<>(ClientLanguageSettings.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/languageprofile/LanguageFluency.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.languageprofile;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class LanguageFluency extends AutoSafeParcelable {\n    public static final Creator<LanguageFluency> CREATOR = new AutoCreator<>(LanguageFluency.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/languageprofile/LanguageFluencyParams.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.languageprofile;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class LanguageFluencyParams extends AutoSafeParcelable {\n    public static final Creator<LanguageFluencyParams> CREATOR = new AutoCreator<>(LanguageFluencyParams.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/languageprofile/LanguagePreference.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.languageprofile;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class LanguagePreference extends AutoSafeParcelable {\n    public static final Creator<LanguagePreference> CREATOR = new AutoCreator<>(LanguagePreference.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/languageprofile/LanguagePreferenceParams.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.languageprofile;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class LanguagePreferenceParams extends AutoSafeParcelable {\n    public static final Creator<LanguagePreferenceParams> CREATOR = new AutoCreator<>(LanguagePreferenceParams.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/locationsharingreporter/IneligibilityRationale.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.locationsharingreporter;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class IneligibilityRationale extends AbstractSafeParcelable {\n    @Field(1)\n    public final String unknownStr1;\n    @Field(2)\n    public final boolean unknownBool2;\n    @Field(3)\n    public final String unknownStr3;\n    @Field(4)\n    public final boolean unknownBool4;\n    @Field(5)\n    public final boolean unknownBool5;\n    @Field(6)\n    public final boolean unknownBool6;\n\n    @Constructor\n    public IneligibilityRationale(@Param(1) String unknownStr1, @Param(2) boolean unknownBool2, @Param(3) String unknownStr3,\n                                  @Param(4) boolean unknownBool4, @Param(5) boolean unknownBool5, @Param(6) boolean unknownBool6) {\n        this.unknownStr1 = unknownStr1;\n        this.unknownBool2 = unknownBool2;\n        this.unknownStr3 = unknownStr3;\n        this.unknownBool4 = unknownBool4;\n        this.unknownBool5 = unknownBool5;\n        this.unknownBool6 = unknownBool6;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<IneligibilityRationale> CREATOR = findCreator(IneligibilityRationale.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/locationsharingreporter/LocationCollectionReason.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.locationsharingreporter;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n\n@SafeParcelable.Class\npublic class LocationCollectionReason extends AbstractSafeParcelable {\n    @Field(1)\n    public final int locationCollectionReason;\n\n    @Constructor\n    public LocationCollectionReason(@Param(1) int locationCollectionReason) {\n        this.locationCollectionReason = locationCollectionReason;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return \"LocationCollectionReason{\" +\n                \"locationCollectionReason=\" + locationCollectionReason +\n                '}';\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<LocationCollectionReason> CREATOR = findCreator(LocationCollectionReason.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/locationsharingreporter/LocationReportingStatus.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.locationsharingreporter;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n\n@SafeParcelable.Class\npublic class LocationReportingStatus extends AbstractSafeParcelable {\n    @Field(1)\n    public final int unknownInt1;\n    @Field(2)\n    public final int unknownInt2;\n    @Field(3)\n    public final boolean unknownBool3;\n    @Field(4)\n    public final IneligibilityRationale ineligibilityRationale;\n\n    @Constructor\n    public LocationReportingStatus(@Param(1) int unknownInt1, @Param(2) int unknownInt2, @Param(3) boolean unknownBool3, @Param(4) IneligibilityRationale ineligibilityRationale0) {\n        this.unknownInt1 = unknownInt1;\n        this.unknownInt2 = unknownInt2;\n        this.unknownBool3 = unknownBool3;\n        this.ineligibilityRationale = ineligibilityRationale0;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<LocationReportingStatus> CREATOR = findCreator(LocationReportingStatus.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/locationsharingreporter/LocationShare.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.locationsharingreporter;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class LocationShare extends AbstractSafeParcelable {\n    @Field(1)\n    public final int locationShareType;\n    @Field(2)\n    public final String tokenId;\n    @Field(3)\n    public final String obfuscatedGaiaId;\n\n    @Constructor\n    public LocationShare(@Param(1) int locationShareType, @Param(2) String tokenId, @Param(3) String obfuscatedGaiaId) {\n        this.locationShareType = locationShareType;\n        this.tokenId = tokenId;\n        this.obfuscatedGaiaId = obfuscatedGaiaId;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<LocationShare> CREATOR = findCreator(LocationShare.class);\n\n    @Override\n    public String toString() {\n        return \"LocationShare{\" +\n                \"locationShareType=\" + locationShareType +\n                \", tokenId=\" + (tokenId != null ? \"\\\"\" + tokenId + \"\\\"\" : \"null\") +\n                \", obfuscatedGaiaId=\" + (obfuscatedGaiaId != null ? \"\\\"\" + obfuscatedGaiaId + \"\\\"\" : \"null\") +\n                '}';\n    }\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/locationsharingreporter/LocationUploadRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.locationsharingreporter;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class LocationUploadRequest extends AbstractSafeParcelable {\n    @Field(1)\n    public final long accuracyMeters;\n    @Field(2)\n    public final int numberOfFix;\n    @Field(3)\n    public final long intervalMillis;\n    @Field(4)\n    public final long fastIntervalMillis;\n    @Field(5)\n    public final long expirationMillis;\n    @Field(6)\n    public final LocationCollectionReason locationCollectionReason;\n    @Field(7)\n    public final boolean unknownBool7;\n    @Field(8)\n    public final boolean throttleExempt;\n    @Field(9)\n    public final String moduleId;\n    @Field(10)\n    public final String unknownString10;\n    @Field(11)\n    public final long unknownLong11;\n\n    @Constructor\n    public LocationUploadRequest(@Param(1) long accuracyMeters, @Param(2) int numberOfFix, @Param(3) long intervalMillis, @Param(4) long fastIntervalMillis,\n                                 @Param(5) long expirationMillis, @Param(6) LocationCollectionReason locationCollectionReason,\n                                 @Param(7) boolean unknownBool7, @Param(8) boolean throttleExempt, @Param(9) String moduleId, @Param(10) String unknownString10, @Param(11) long unknownLong11) {\n        this.accuracyMeters = accuracyMeters;\n        this.numberOfFix = numberOfFix;\n        this.intervalMillis = intervalMillis;\n        this.fastIntervalMillis = fastIntervalMillis;\n        this.expirationMillis = expirationMillis;\n        this.locationCollectionReason = locationCollectionReason;\n        this.unknownBool7 = unknownBool7;\n        this.throttleExempt = throttleExempt;\n        this.moduleId = moduleId;\n        this.unknownString10 = unknownString10;\n        this.unknownLong11 = unknownLong11;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<LocationUploadRequest> CREATOR = findCreator(LocationUploadRequest.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/locationsharingreporter/LocationUploadResponse.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.locationsharingreporter;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class LocationUploadResponse extends AbstractSafeParcelable {\n    @Field(1)\n    public final int unknownInt1;\n    @Field(2)\n    public final LocationReportingStatus locationReportingStatus;\n\n    @Constructor\n    public LocationUploadResponse(@Param(1) int unknownInt1, @Param(2) LocationReportingStatus locationReportingStatus) {\n        this.unknownInt1 = unknownInt1;\n        this.locationReportingStatus = locationReportingStatus;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<LocationUploadResponse> CREATOR = findCreator(LocationUploadResponse.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/locationsharingreporter/NoticeAckedUpdateRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.locationsharingreporter;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class NoticeAckedUpdateRequest extends AbstractSafeParcelable {\n    @Field(1)\n    public final int isConfirmed;\n\n    @Constructor\n    public NoticeAckedUpdateRequest(@Param(1) int isConfirmed) {\n        this.isConfirmed = isConfirmed;\n    }\n\n    @NonNull\n    @Override\n    public final String toString() {\n        return \"NoticeAckedUpdateRequest{\" +\n                \"isConfirmed=\" + isConfirmed +\n                '}';\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<NoticeAckedUpdateRequest> CREATOR = findCreator(NoticeAckedUpdateRequest.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/locationsharingreporter/PeriodicLocationReportingIssues.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.locationsharingreporter;\n\nimport android.os.Bundle;\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport java.util.Arrays;\n\n@SafeParcelable.Class\npublic class PeriodicLocationReportingIssues extends AbstractSafeParcelable {\n    @Field(1)\n    final int[] generalIssues;\n    @Field(2)\n    final Bundle issuesByAccount;\n    @Field(4)\n    final boolean isCentralizedSharingFlagEnabled;\n\n    @Constructor\n    public PeriodicLocationReportingIssues(@Param(1) int[] generalIssues, @Param(2) Bundle issuesByAccount, @Param(4) boolean isCentralizedSharingFlagEnabled) {\n        this.generalIssues = generalIssues;\n        this.issuesByAccount = issuesByAccount;\n        this.isCentralizedSharingFlagEnabled = isCentralizedSharingFlagEnabled;\n    }\n\n    @NonNull\n    @Override\n    public final String toString() {\n        return \"PeriodicLocationReportingIssues{generalIssues=\" + Arrays.toString(this.generalIssues)\n                + \", issuesByAccount=\" + this.issuesByAccount + \", isCentralizedSharingFlagEnabled=\"\n                + this.isCentralizedSharingFlagEnabled + \"}\";\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<PeriodicLocationReportingIssues> CREATOR = findCreator(PeriodicLocationReportingIssues.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/locationsharingreporter/PeriodicLocationUploadRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.locationsharingreporter;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class PeriodicLocationUploadRequest extends AbstractSafeParcelable {\n    @Field(1)\n    public final LocationCollectionReason locationCollectionReason;\n    @Field(2)\n    public final LocationShare locationShare;\n    @Field(3)\n    public final int makePrimaryOption;\n    @Field(4)\n    public final long duration;\n    @Field(5)\n    public final boolean unknownBool5;\n    @Field(6)\n    public final String unknownStr6;\n    @Field(7)\n    public final boolean unknownBool7;\n\n    @Constructor\n    public PeriodicLocationUploadRequest(@Param(1) LocationCollectionReason locationCollectionReason, @Param(2) LocationShare locationShare,\n                                         @Param(3) int makePrimaryOption, @Param(4) long duration, @Param(5) boolean unknownBool5, @Param(6) String unknownStr6, @Param(7) boolean unknownBool7) {\n        this.locationCollectionReason = locationCollectionReason;\n        this.locationShare = locationShare;\n        this.makePrimaryOption = makePrimaryOption;\n        this.duration = duration;\n        this.unknownBool5 = unknownBool5;\n        this.unknownStr6 = unknownStr6;\n        this.unknownBool7 = unknownBool7;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<PeriodicLocationUploadRequest> CREATOR = findCreator(PeriodicLocationUploadRequest.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/locationsharingreporter/StartLocationReportingRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.locationsharingreporter;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class StartLocationReportingRequest extends AbstractSafeParcelable {\n    @Field(1)\n    public final int makePrimary;\n    @Field(2)\n    public final int reportingType;\n    @Field(3)\n    public final LocationShare locationShare;\n    @Field(4)\n    public final long requestDurationMs;\n    @Field(5)\n    public final NoticeAckedUpdateRequest noticeAckedUpdateRequest;\n\n    @Constructor\n    public StartLocationReportingRequest(@Param(1) int makePrimary, @Param(2) int reportingType, @Param(3) LocationShare locationShare,\n                                         @Param(4) long requestDurationMs, @Param(5) NoticeAckedUpdateRequest noticeAckedUpdateRequest) {\n        this.makePrimary = makePrimary;\n        this.reportingType = reportingType;\n        this.requestDurationMs = requestDurationMs;\n        this.locationShare = locationShare;\n        this.noticeAckedUpdateRequest = noticeAckedUpdateRequest;\n    }\n\n    @NonNull\n    @Override\n    public final String toString() {\n        return \"StartLocationReportingRequest{\" +\n                \"makePrimary=\" + makePrimary +\n                \", reportingType=\" + reportingType +\n                \", locationShare=\" + locationShare +\n                \", requestDurationMs=\" + requestDurationMs +\n                \", noticeAckedUpdateRequest=\" + noticeAckedUpdateRequest +\n                '}';\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<StartLocationReportingRequest> CREATOR = findCreator(StartLocationReportingRequest.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/locationsharingreporter/StopLocationReportingRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.locationsharingreporter;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class StopLocationReportingRequest extends AbstractSafeParcelable {\n    @Field(1)\n    public final LocationShare locationShare;\n    @Constructor\n    public StopLocationReportingRequest(@Param(1) LocationShare locationShare) {\n        this.locationShare = locationShare;\n    }\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<StopLocationReportingRequest> CREATOR = findCreator(StopLocationReportingRequest.class);\n\n    @Override\n    public String toString() {\n        return \"StopLocationReportingRequest{\" +\n                \"locationShare=\" + (locationShare != null ? locationShare.toString() : \"null\") +\n                '}';\n    }\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/measurement/internal/AppMetadata.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.measurement.internal;\n\nimport androidx.annotation.Nullable;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\nimport java.util.List;\n\npublic class AppMetadata extends AutoSafeParcelable {\n    @Field(2)\n    @Nullable\n    public String packageName;\n    @Field(3)\n    @Nullable\n    public String appId;\n    @Field(4)\n    @Nullable\n    public String appVersion;\n    @Field(5)\n    @Nullable\n    public String appStore;\n    @Field(6)\n    public long gmpVersion;\n    @Field(7)\n    public long devCertHash;\n    @Field(8)\n    @Nullable\n    public String healthMonitorSample;\n    @Field(value = 9, defaultValue = \"true\")\n    public boolean measurementEnabled = true;\n    @Field(10)\n    public boolean firstOpen;\n    @Field(value = 11, defaultValue = \"java.lang.Integer.MIN_VALUE\")\n    public long appVersionInt = Integer.MIN_VALUE;\n    @Field(12)\n    @Nullable\n    public String firebaseInstanceId;\n    @Field(13)\n    public long androidId;\n    @Field(14)\n    public long instantiationTime;\n    @Field(15)\n    public int appType;\n    @Field(value = 16, defaultValue = \"true\")\n    public boolean adIdReportingEnabled = true;\n    @Field(value = 17, defaultValue = \"true\")\n    public boolean ssaidCollectionEnabled = true;\n    @Field(18)\n    public boolean deferredAnalyticsCollection;\n    @Field(19)\n    public String admobAppId;\n    @Field(21)\n    @Nullable\n    public Boolean allowAdPersonalization;\n    @Field(22)\n    public long dynamiteVersion;\n    @Field(23)\n    @Nullable\n    public List<String> safelistedEvents;\n    @Field(24)\n    public String gaAppId;\n    @Field(value = 25, defaultValue = \"\\\"\\\"\")\n    public String consentSettings = \"\";\n    @Field(value = 26, defaultValue = \"\\\"\\\"\")\n    public String ephemeralAppInstanceId = \"\";\n    @Field(27)\n    @Nullable\n    public String sessionStitchingToken;\n    @Field(28)\n    public boolean sgtmUploadEnabled = false;\n    @Field(29)\n    public long targetOsVersion;\n    @Field(value = 30, defaultValue = \"100\")\n    public int consentSource = 100;\n    @Field(value = 31, defaultValue = \"\\\"\\\"\")\n    public String dmaConsent = \"\";\n    @Field(32)\n    public int adServicesVersion;\n    @Field(34)\n    public long l34;\n    @Field(35)\n    @Nullable\n    public String sgtmPreviewKey;\n    @Field(value = 36, defaultValue = \"\\\"\\\"\")\n    public String serializedNpaMetadata;\n    @Field(37)\n    public long timestamp;\n    @Field(38)\n    public int clientUploadEligibility;\n\n    public String toString() {\n        return \"AppMetadata[\" + packageName + \"]\";\n    }\n\n    public static final Creator<AppMetadata> CREATOR = new AutoCreator<>(AppMetadata.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/measurement/internal/ConditionalUserPropertyParcel.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.measurement.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class ConditionalUserPropertyParcel extends AutoSafeParcelable {\n    @Field(2)\n    public String appId;\n    @Field(3)\n    public String origin;\n    @Field(4)\n    public UserAttributeParcel userAttribute;\n    @Field(5)\n    public long creationTimestamp;\n    @Field(6)\n    public boolean active;\n    @Field(7)\n    public String triggerEventName;\n    @Field(8)\n    public EventParcel timedOutEvent;\n    @Field(9)\n    public long triggerTimeout;\n    @Field(10)\n    public EventParcel triggerEvent;\n    @Field(11)\n    public long timeToLive;\n    @Field(12)\n    public EventParcel expiredEvent;\n\n    public static final Creator<ConditionalUserPropertyParcel> CREATOR = new AutoCreator<>(ConditionalUserPropertyParcel.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/measurement/internal/EventParams.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.measurement.internal;\n\nimport android.os.Bundle;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class EventParams extends AutoSafeParcelable {\n    @Field(2)\n    public Bundle data;\n\n    public static final Creator<EventParams> CREATOR = new AutoCreator<>(EventParams.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/measurement/internal/EventParcel.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.measurement.internal;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class EventParcel extends AbstractSafeParcelable {\n    @Field(2)\n    public String name;\n    @Field(3)\n    public EventParams params;\n    @Field(4)\n    public String origin;\n    @Field(5)\n    public long timestamp;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<EventParcel> CREATOR = findCreator(EventParcel.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/measurement/internal/UserAttributeParcel.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.measurement.internal;\n\nimport androidx.annotation.Nullable;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class UserAttributeParcel extends AutoSafeParcelable {\n    @Field(1)\n    public int versionCode = 2;\n    @Field(2)\n    public String name;\n    @Field(3)\n    public long timestamp;\n    @Field(4)\n    @Nullable\n    public Long longValue;\n    @Deprecated\n    @Field(5)\n    @Nullable\n    public Float floatValue;\n    @Field(6)\n    @Nullable\n    public String stringValue;\n    @Field(7)\n    public String field7;\n    @Field(8)\n    @Nullable\n    public Double doubleValue;\n\n    public static final Creator<UserAttributeParcel> CREATOR = new AutoCreator<>(UserAttributeParcel.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/people/internal/ParcelableLoadImageOptions.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.people.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class ParcelableLoadImageOptions extends AutoSafeParcelable {\n    @SafeParceled(1000)\n    private int versionCode = 1;\n\n    @SafeParceled(1)\n    public int imageSize;\n\n    @SafeParceled(2)\n    public int avatarOptions;\n\n    @SafeParceled(3)\n    public boolean useLargePictureForCp2Images;\n\n    public static final Creator<ParcelableLoadImageOptions> CREATOR = new AutoCreator<ParcelableLoadImageOptions>(ParcelableLoadImageOptions.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/people/model/AccountMetadata.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.people.model;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class AccountMetadata extends AutoSafeParcelable {\n\n    @SafeParceled(1)\n    private int versionCode = 2;\n\n    @SafeParceled(2)\n    public boolean hasGooglePlus = true;\n\n    @SafeParceled(3)\n    public boolean hasFeature2 = true;\n\n    @SafeParceled(4)\n    public boolean hasFeature3 = true;\n\n    @SafeParceled(5)\n    public boolean hasFeature4 = true;\n\n    public static Creator<AccountMetadata> CREATOR = new AutoCreator<AccountMetadata>(AccountMetadata.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/people/model/AvatarReference.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.people.model;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class AvatarReference extends AutoSafeParcelable {\n\n    @SafeParceled(1000)\n    private int versionCode;\n\n    @SafeParceled(1)\n    public int source;\n\n    @SafeParceled(2)\n    public String location;\n\n    public static final Creator<AvatarReference> CREATOR = new AutoCreator<AvatarReference>(AvatarReference.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/phenotype/Configurations.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.phenotype;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class Configurations extends AutoSafeParcelable {\n    @Field(2)\n    public String snapshotToken;\n    @Field(3)\n    public String serverToken;\n    @Field(4)\n    public Configuration[] field4;\n    @Field(5)\n    public boolean field5;\n    @Field(6)\n    public byte[] field6;\n    @Field(7)\n    public long version;\n\n    public static final Creator<Configurations> CREATOR = new AutoCreator<>(Configurations.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/phenotype/DogfoodsToken.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.phenotype;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class DogfoodsToken extends AutoSafeParcelable {\n    public static final Creator<DogfoodsToken> CREATOR = new AutoCreator<>(DogfoodsToken.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/phenotype/FlagOverrides.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.phenotype;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class FlagOverrides extends AutoSafeParcelable {\n    public static final Creator<FlagOverrides> CREATOR = new AutoCreator<>(FlagOverrides.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/phenotype/RegistrationInfo.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2021 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.phenotype;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class RegistrationInfo extends AutoSafeParcelable {\n    @Field(1)\n    public String packageName;\n    @Field(2)\n    public int version;\n    @Field(3)\n    public String[] field3;\n    @Field(4)\n    public byte[] field4;\n    @Field(5)\n    public boolean weak;\n    @Field(6)\n    public int[] field6;\n    @Field(7)\n    public String clientPackageName;\n\n    public static final Creator<RegistrationInfo> CREATOR = new AutoCreator<>(RegistrationInfo.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/plus/internal/PlusCommonExtras.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.plus.internal;\n\npublic class PlusCommonExtras {\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/plus/internal/PlusSession.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.plus.internal;\n\npublic class PlusSession {\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/plus/internal/model/smart_profile/CardsRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.plus.internal.model.smart_profile;\n\npublic class CardsRequest {\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/plus/internal/model/smart_profile/CardsResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.plus.internal.model.smart_profile;\n\npublic class CardsResponse {\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/plus/internal/model/smart_profile/PeopleForProfilesRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.plus.internal.model.smart_profile;\n\npublic class PeopleForProfilesRequest {\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/plus/internal/model/smart_profile/PeopleForProfilesResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.plus.internal.model.smart_profile;\n\npublic class PeopleForProfilesResponse {\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/plus/model/posts/Comment.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.plus.model.posts;\n\npublic class Comment {\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/plus/model/posts/Post.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.plus.model.posts;\n\npublic class Post {\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/plus/model/posts/Settings.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.plus.model.posts;\n\npublic class Settings {\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/potokens/PoToken.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.potokens;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class PoToken extends AutoSafeParcelable {\n\n    @Field(1)\n    public byte[] data;\n\n    public PoToken(byte[] data) {\n        this.data = data;\n    }\n\n    public static Creator<PoToken> CREATOR = findCreator(PoToken.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/pseudonymous/PseudonymousIdToken.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.pseudonymous;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class PseudonymousIdToken extends AbstractSafeParcelable {\n\n    @Field(2)\n    public String name;\n\n    @Constructor\n    public PseudonymousIdToken(@Param(2) String name) {\n        this.name = name;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<PseudonymousIdToken> CREATOR = findCreator(PseudonymousIdToken.class);\n\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/reminders/AccountState.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.reminders;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class AccountState extends AutoSafeParcelable {\n    public static Creator<AccountState> CREATOR = new AutoCreator<AccountState>(AccountState.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/reminders/CreateReminderOptionsInternal.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.reminders;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class CreateReminderOptionsInternal extends AutoSafeParcelable {\n    public static Creator<CreateReminderOptionsInternal> CREATOR = new AutoCreator<CreateReminderOptionsInternal>(CreateReminderOptionsInternal.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/reminders/LoadRemindersOptions.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.reminders;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class LoadRemindersOptions extends AutoSafeParcelable {\n    public static Creator<LoadRemindersOptions> CREATOR = new AutoCreator<LoadRemindersOptions>(LoadRemindersOptions.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/reminders/ReindexDueDatesOptions.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.reminders;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class ReindexDueDatesOptions extends AutoSafeParcelable {\n    public static Creator<ReindexDueDatesOptions> CREATOR = new AutoCreator<ReindexDueDatesOptions>(ReindexDueDatesOptions.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/reminders/UpdateRecurrenceOptions.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.reminders;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class UpdateRecurrenceOptions extends AutoSafeParcelable {\n    public static Creator<UpdateRecurrenceOptions> CREATOR = new AutoCreator<UpdateRecurrenceOptions>(UpdateRecurrenceOptions.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/reminders/model/CustomizedSnoozePresetEntity.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.reminders.model;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class CustomizedSnoozePresetEntity extends AutoSafeParcelable {\n    public static Creator<CustomizedSnoozePresetEntity> CREATOR = new AutoCreator<CustomizedSnoozePresetEntity>(CustomizedSnoozePresetEntity.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/reminders/model/TaskEntity.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.reminders.model;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class TaskEntity extends AutoSafeParcelable {\n    public static Creator<TaskEntity> CREATOR = new AutoCreator<TaskEntity>(TaskEntity.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/reminders/model/TaskIdEntity.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.reminders.model;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class TaskIdEntity extends AutoSafeParcelable {\n    public static Creator<TaskIdEntity> CREATOR = new AutoCreator<TaskIdEntity>(TaskIdEntity.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/search/corpora/ClearCorpusRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.search.corpora;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class ClearCorpusRequest extends AutoSafeParcelable {\n    public static Creator<ClearCorpusRequest> CREATOR = new AutoCreator<ClearCorpusRequest>(ClearCorpusRequest.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/search/corpora/GetCorpusInfoRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.search.corpora;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class GetCorpusInfoRequest extends AutoSafeParcelable {\n    public static Creator<GetCorpusInfoRequest> CREATOR = new AutoCreator<GetCorpusInfoRequest>(GetCorpusInfoRequest.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/search/corpora/GetCorpusStatusRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.search.corpora;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class GetCorpusStatusRequest extends AutoSafeParcelable {\n\n    @SafeParceled(1000)\n    private int versionCode = 1;\n\n    @SafeParceled(1)\n    public final String packageName;\n\n    @SafeParceled(2)\n    public final String corpus;\n\n    private GetCorpusStatusRequest() {\n        packageName = null;\n        corpus = null;\n    }\n\n    @Override\n    public String toString() {\n        return \"GetCorpusStatusRequest{\" +\n                \"versionCode=\" + versionCode +\n                \", packageName='\" + packageName + '\\'' +\n                \", corpus='\" + corpus + '\\'' +\n                '}';\n    }\n\n    public static Creator<GetCorpusStatusRequest> CREATOR = new AutoCreator<GetCorpusStatusRequest>(GetCorpusStatusRequest.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/search/corpora/GetCorpusStatusResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.search.corpora;\n\nimport com.google.android.gms.appdatasearch.CorpusStatus;\nimport com.google.android.gms.common.api.Status;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class GetCorpusStatusResponse extends AutoSafeParcelable {\n\n    @SafeParceled(1000)\n    private int versionCode;\n\n    @SafeParceled(1)\n    public final Status status;\n\n    @SafeParceled(2)\n    public final CorpusStatus corpusStatus;\n\n    private GetCorpusStatusResponse() {\n        status = null;\n        corpusStatus = null;\n    }\n\n    public GetCorpusStatusResponse(Status status, CorpusStatus corpusStatus) {\n        this.status = status;\n        this.corpusStatus = corpusStatus;\n    }\n\n    public static Creator<GetCorpusStatusResponse> CREATOR = new AutoCreator<GetCorpusStatusResponse>(GetCorpusStatusResponse.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/search/corpora/RequestIndexingRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.search.corpora;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class RequestIndexingRequest extends AutoSafeParcelable {\n\n    @SafeParceled(1000)\n    private int versionCode = 1;\n\n    @SafeParceled(1)\n    public final String packageName;\n\n    @SafeParceled(2)\n    public final String corpus;\n\n    @SafeParceled(3)\n    public final long sequenceNumber;\n\n    private RequestIndexingRequest() {\n        packageName = null;\n        corpus = null;\n        sequenceNumber = 0;\n    }\n\n    @Override\n    public String toString() {\n        return \"RequestIndexingRequest{\" +\n                \"versionCode=\" + versionCode +\n                \", packageName='\" + packageName + '\\'' +\n                \", corpus='\" + corpus + '\\'' +\n                \", sequenceNumber=\" + sequenceNumber +\n                '}';\n    }\n\n    public static Creator<RequestIndexingRequest> CREATOR = new AutoCreator<RequestIndexingRequest>(RequestIndexingRequest.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/search/corpora/RequestIndexingResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.search.corpora;\n\nimport com.google.android.gms.common.api.Status;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class RequestIndexingResponse extends AutoSafeParcelable {\n\n    @SafeParceled(1000)\n    private int versionCode;\n\n    @SafeParceled(1)\n    public final Status status;\n\n    @SafeParceled(2)\n    public final boolean scheduledIndexing;\n\n    private RequestIndexingResponse() {\n        status = null;\n        scheduledIndexing = false;\n    }\n\n    public RequestIndexingResponse(Status status, boolean scheduledIndexing) {\n        this.status = status;\n        this.scheduledIndexing = scheduledIndexing;\n    }\n\n    public static Creator<RequestIndexingResponse> CREATOR = new AutoCreator<RequestIndexingResponse>(RequestIndexingResponse.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/search/global/GetCurrentExperimentIdsRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.search.global;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class GetCurrentExperimentIdsRequest extends AutoSafeParcelable {\n\n    @SafeParceled(1000)\n    private int versionCode = 1;\n\n    public static final Creator<GetCurrentExperimentIdsRequest> CREATOR = new AutoCreator<GetCurrentExperimentIdsRequest>(GetCurrentExperimentIdsRequest.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/search/global/GetCurrentExperimentIdsResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.search.global;\n\nimport com.google.android.gms.common.api.Status;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\nimport java.util.Arrays;\n\npublic class GetCurrentExperimentIdsResponse extends AutoSafeParcelable {\n\n    @SafeParceled(1000)\n    private int versionCode = 1;\n\n    @SafeParceled(1)\n    public final Status status;\n\n    @SafeParceled(2)\n    public final int[] experimentIds;\n\n    private GetCurrentExperimentIdsResponse() {\n        status = null;\n        experimentIds = null;\n    }\n\n    public GetCurrentExperimentIdsResponse(Status status, int[] experimentIds) {\n        this.status = status;\n        this.experimentIds = experimentIds;\n    }\n\n    @Override\n    public String toString() {\n        final StringBuilder sb = new StringBuilder(\"GetCurrentExperimentIdsResponse{\");\n        sb.append(\"status=\").append(status);\n        sb.append(\", experimentIds=\").append(Arrays.toString(experimentIds));\n        sb.append('}');\n        return sb.toString();\n    }\n\n    public static final Creator<GetCurrentExperimentIdsResponse> CREATOR = new AutoCreator<GetCurrentExperimentIdsResponse>(GetCurrentExperimentIdsResponse.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/search/global/GetGlobalSearchSourcesRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.search.global;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class GetGlobalSearchSourcesRequest extends AutoSafeParcelable {\n\n    @SafeParceled(1000)\n    private int versionCode = 1;\n\n    @SafeParceled(1)\n    public boolean bool;\n\n    @Override\n    public String toString() {\n        final StringBuilder sb = new StringBuilder(\"GetGlobalSearchSourcesRequest{\");\n        sb.append(\"bool=\").append(bool);\n        sb.append('}');\n        return sb.toString();\n    }\n\n    public static final Creator<GetGlobalSearchSourcesRequest> CREATOR = new AutoCreator<GetGlobalSearchSourcesRequest>(GetGlobalSearchSourcesRequest.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/search/global/GetGlobalSearchSourcesResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.search.global;\n\nimport android.os.Parcelable;\n\nimport com.google.android.gms.common.api.Status;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\nimport java.util.Arrays;\n\npublic class GetGlobalSearchSourcesResponse extends AutoSafeParcelable {\n\n    @SafeParceled(1000)\n    private int versionCode = 1;\n\n    @SafeParceled(1)\n    public final Status status;\n\n    @SafeParceled(2)\n    public final Parcelable[] sources;\n\n    private GetGlobalSearchSourcesResponse() {\n        status = null;\n        sources = null;\n    }\n\n    public GetGlobalSearchSourcesResponse(Status status, Parcelable[] sources) {\n        this.status = status;\n        this.sources = sources;\n    }\n\n    @Override\n    public String toString() {\n        final StringBuilder sb = new StringBuilder(\"GetGlobalSearchSourcesResponse{\");\n        sb.append(\"status=\").append(status);\n        sb.append(\", sources=\").append(Arrays.toString(sources));\n        sb.append('}');\n        return sb.toString();\n    }\n\n    public static final Creator<GetGlobalSearchSourcesResponse> CREATOR = new AutoCreator<GetGlobalSearchSourcesResponse>(GetGlobalSearchSourcesResponse.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/search/global/GetPendingExperimentIdsRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.search.global;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class GetPendingExperimentIdsRequest extends AutoSafeParcelable {\n\n    @SafeParceled(1000)\n    private int versionCode = 1;\n\n    public static final Creator<GetPendingExperimentIdsRequest> CREATOR = new AutoCreator<GetPendingExperimentIdsRequest>(GetPendingExperimentIdsRequest.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/search/global/GetPendingExperimentIdsResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.search.global;\n\nimport com.google.android.gms.common.api.Status;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\nimport java.util.Arrays;\n\npublic class GetPendingExperimentIdsResponse extends AutoSafeParcelable {\n\n    @SafeParceled(1000)\n    private int versionCode = 1;\n\n    @SafeParceled(1)\n    public final Status status;\n\n    @SafeParceled(2)\n    public final int[] experimentIds;\n\n    private GetPendingExperimentIdsResponse() {\n        status = null;\n        experimentIds = null;\n    }\n\n    public GetPendingExperimentIdsResponse(Status status, int[] experimentIds) {\n        this.status = status;\n        this.experimentIds = experimentIds;\n    }\n\n    @Override\n    public String toString() {\n        final StringBuilder sb = new StringBuilder(\"GetPendingExperimentIdsResponse{\");\n        sb.append(\"status=\").append(status);\n        sb.append(\", experimentIds=\").append(Arrays.toString(experimentIds));\n        sb.append('}');\n        return sb.toString();\n    }\n\n    public static final Creator<GetPendingExperimentIdsResponse> CREATOR = new AutoCreator<GetPendingExperimentIdsResponse>(GetPendingExperimentIdsResponse.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/search/global/SetExperimentIdsRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.search.global;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\nimport java.util.Arrays;\n\npublic class SetExperimentIdsRequest extends AutoSafeParcelable {\n\n    @SafeParceled(1000)\n    private int versionCode = 1;\n\n    @SafeParceled(1)\n    public byte[] experimentIds;\n\n    @SafeParceled(2)\n    public boolean enable;\n\n    @Override\n    public String toString() {\n        final StringBuilder sb = new StringBuilder(\"SetExperimentIdsRequest{\");\n        sb.append(\"experimentIds=\").append(Arrays.toString(experimentIds));\n        sb.append(\", enable=\").append(enable);\n        sb.append('}');\n        return sb.toString();\n    }\n\n    public static final Creator<SetExperimentIdsRequest> CREATOR = new AutoCreator<SetExperimentIdsRequest>(SetExperimentIdsRequest.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/search/global/SetExperimentIdsResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.search.global;\n\nimport com.google.android.gms.common.api.Status;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class SetExperimentIdsResponse extends AutoSafeParcelable {\n\n    @SafeParceled(1000)\n    private int versionCode = 1;\n\n    @SafeParceled(1)\n    public final Status status;\n\n    private SetExperimentIdsResponse() {\n        status = null;\n    }\n\n    public SetExperimentIdsResponse(Status status) {\n        this.status = status;\n    }\n\n    @Override\n    public String toString() {\n        final StringBuilder sb = new StringBuilder(\"SetExperimentIdsResponse{\");\n        sb.append(\"status=\").append(status);\n        sb.append('}');\n        return sb.toString();\n    }\n\n    public static final Creator<SetExperimentIdsResponse> CREATOR = new AutoCreator<SetExperimentIdsResponse>(SetExperimentIdsResponse.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/search/global/SetIncludeInGlobalSearchRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.search.global;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class SetIncludeInGlobalSearchRequest extends AutoSafeParcelable {\n\n    @SafeParceled(1000)\n    private int versionCode = 1;\n\n    @SafeParceled(1)\n    public String packageName;\n\n    @SafeParceled(2)\n    public String source;\n\n    @SafeParceled(3)\n    public boolean enabled;\n\n    @Override\n    public String toString() {\n        final StringBuilder sb = new StringBuilder(\"SetIncludeInGlobalSearchRequest{\");\n        sb.append(\"packageName='\").append(packageName).append('\\'');\n        sb.append(\", source='\").append(source).append('\\'');\n        sb.append(\", enabled=\").append(enabled);\n        sb.append('}');\n        return sb.toString();\n    }\n\n    public static final Creator<SetIncludeInGlobalSearchRequest> CREATOR = new AutoCreator<SetIncludeInGlobalSearchRequest>(SetIncludeInGlobalSearchRequest.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/search/global/SetIncludeInGlobalSearchResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.search.global;\n\nimport com.google.android.gms.common.api.Status;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class SetIncludeInGlobalSearchResponse extends AutoSafeParcelable {\n\n    @SafeParceled(1000)\n    private int versionCode = 1;\n\n    @SafeParceled(1)\n    public final Status status;\n\n    private SetIncludeInGlobalSearchResponse() {\n        status = null;\n    }\n\n    public SetIncludeInGlobalSearchResponse(Status status) {\n        this.status = status;\n    }\n\n    @Override\n    public String toString() {\n        final StringBuilder sb = new StringBuilder(\"SetIncludeInGlobalSearchResponse{\");\n        sb.append(\"status=\").append(status);\n        sb.append('}');\n        return sb.toString();\n    }\n\n    public static final Creator<SetIncludeInGlobalSearchResponse> CREATOR = new AutoCreator<SetIncludeInGlobalSearchResponse>(SetIncludeInGlobalSearchResponse.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/search/queries/QueryRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.search.queries;\n\nimport com.google.android.gms.appdatasearch.QuerySpecification;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\nimport java.util.Arrays;\n\npublic class QueryRequest extends AutoSafeParcelable {\n\n    @SafeParceled(1000)\n    public int versionCode = 1;\n    @SafeParceled(1)\n    public String searchString;\n    @SafeParceled(2)\n    public String packageName;\n    @SafeParceled(3)\n    public String[] corpora;\n    @SafeParceled(4)\n    public int d;\n    @SafeParceled(5)\n    public int e;\n    @SafeParceled(6)\n    public QuerySpecification spec;\n\n    @Override\n    public String toString() {\n        return \"QueryRequest{\" +\n                \"versionCode=\" + versionCode +\n                \", searchString='\" + searchString + '\\'' +\n                \", packageName='\" + packageName + '\\'' +\n                \", corpora=\" + Arrays.toString(corpora) +\n                \", d=\" + d +\n                \", e=\" + e +\n                \", spec=\" + spec +\n                '}';\n    }\n\n    public static Creator<QueryRequest> CREATOR = new AutoCreator<QueryRequest>(QueryRequest.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/search/queries/QueryResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.search.queries;\n\nimport com.google.android.gms.appdatasearch.SearchResults;\nimport com.google.android.gms.common.api.Status;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class QueryResponse extends AutoSafeParcelable {\n\n    @SafeParceled(1000)\n    private int versionCode = 1;\n\n    @SafeParceled(1)\n    public final Status status;\n\n    @SafeParceled(2)\n    public final SearchResults results;\n\n    private QueryResponse() {\n        status = null;\n        results = null;\n    }\n\n    public QueryResponse(Status status, SearchResults results) {\n        this.status = status;\n        this.results = results;\n    }\n\n    public static Creator<QueryResponse> CREATOR = new AutoCreator<QueryResponse>(QueryResponse.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocation/Activity.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocation;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class Activity extends AbstractSafeParcelable {\n    @Field(1)\n    public final PlaceCandidate.Point start;\n    @Field(2)\n    public final PlaceCandidate.Point end;\n    @Field(3)\n    public final float distanceMeters;\n    @Field(4)\n    public final float probability;\n    @Field(5)\n    @Deprecated\n    float f5;\n    @Field(6)\n    public final ActivityCandidate activityCandidate;\n    @Field(7)\n    public final AdditionalActivityCandidates additionalActivityCandidates;\n    @Field(8)\n    public final Parking parking;\n\n    @Constructor\n    public Activity(@Param(1) PlaceCandidate.Point start, @Param(2) PlaceCandidate.Point end, @Param(3) float distanceMeters, @Param(4) float probability, @Param(6) ActivityCandidate activityCandidate, @Param(7) AdditionalActivityCandidates additionalActivityCandidates, @Param(8) Parking parking) {\n        this.start = start;\n        this.end = end;\n        this.distanceMeters = distanceMeters;\n        this.probability = probability;\n        this.activityCandidate = activityCandidate;\n        this.additionalActivityCandidates = additionalActivityCandidates;\n        this.parking = parking;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"Activity\")\n                .field(\"start\", start)\n                .field(\"end\", end)\n                .field(\"distanceMeters\", distanceMeters)\n                .field(\"probability\", probability)\n                .field(\"activityCandidate\", activityCandidate)\n                .field(\"additionalActivityCandidates\", additionalActivityCandidates)\n                .field(\"parking\", parking)\n                .end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<Activity> CREATOR = findCreator(Activity.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocation/ActivityCandidate.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocation;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class ActivityCandidate extends AbstractSafeParcelable {\n    @Field(1)\n    public final int type;\n    @Field(2)\n    public final float probability;\n    @Field(3)\n    @Deprecated\n    float f3;\n\n    @Constructor\n    public ActivityCandidate(@Param(1) int type, @Param(2) float probability) {\n        this.type = type;\n        this.probability = probability;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"ActivityCandidate\")\n                .field(\"type\", type)\n                .field(\"probability\", probability)\n                .end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<ActivityCandidate> CREATOR = findCreator(ActivityCandidate.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocation/ActivityEndEvent.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocation;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class ActivityEndEvent extends AbstractSafeParcelable {\n    @Field(1)\n    public final float probability;\n    @Field(2)\n    @Deprecated\n    float f2;\n    @Field(3)\n    public final ActivityCandidate topCandidate;\n    @Field(4)\n    public final AdditionalActivityCandidates additionalActivityCandidates;\n\n    @Constructor\n    public ActivityEndEvent(@Param(1) float probability, @Param(3) ActivityCandidate topCandidate, @Param(4) AdditionalActivityCandidates additionalActivityCandidates) {\n        this.probability = probability;\n        this.topCandidate = topCandidate;\n        this.additionalActivityCandidates = additionalActivityCandidates;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"ActivityEndEvent\")\n                .field(\"probability\", probability)\n                .field(\"topCandidate\", topCandidate)\n                .field(\"additionalActivityCandidates\", additionalActivityCandidates)\n                .end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<ActivityEndEvent> CREATOR = findCreator(ActivityEndEvent.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocation/ActivityOngoingEvent.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocation;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class ActivityOngoingEvent extends AbstractSafeParcelable {\n    @Field(1)\n    public final float probability;\n    @Field(2)\n    @Deprecated\n    float f2;\n    @Field(3)\n    public final ActivityCandidate topCandidate;\n    @Field(4)\n    public final AdditionalActivityCandidates additionalActivityCandidates;\n\n    @Constructor\n    public ActivityOngoingEvent(@Param(1) float probability, @Param(3) ActivityCandidate topCandidate, @Param(4) AdditionalActivityCandidates additionalActivityCandidates) {\n        this.probability = probability;\n        this.topCandidate = topCandidate;\n        this.additionalActivityCandidates = additionalActivityCandidates;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"ActivityOngoingEvent\")\n                .field(\"probability\", probability)\n                .field(\"topCandidate\", topCandidate)\n                .field(\"additionalActivityCandidates\", additionalActivityCandidates)\n                .end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<ActivityOngoingEvent> CREATOR = findCreator(ActivityOngoingEvent.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocation/ActivityStartEvent.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocation;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class ActivityStartEvent extends AbstractSafeParcelable {\n    @Field(1)\n    public final float probability;\n    @Field(2)\n    @Deprecated\n    float f2;\n    @Field(3)\n    public final ActivityCandidate topCandidate;\n    @Field(4)\n    public final AdditionalActivityCandidates additionalActivityCandidates;\n\n    @Constructor\n    public ActivityStartEvent(@Param(1) float probability, @Param(3) ActivityCandidate topCandidate, @Param(4) AdditionalActivityCandidates additionalActivityCandidates) {\n        this.probability = probability;\n        this.topCandidate = topCandidate;\n        this.additionalActivityCandidates = additionalActivityCandidates;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"ActivityStartEvent\")\n                .field(\"probability\", probability)\n                .field(\"topCandidate\", topCandidate)\n                .field(\"additionalActivityCandidates\", additionalActivityCandidates)\n                .end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<ActivityStartEvent> CREATOR = findCreator(ActivityStartEvent.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocation/ActivityStatistics.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocation;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class ActivityStatistics extends AbstractSafeParcelable {\n    @Field(1)\n    int i1;\n    @Field(2)\n    double d2;\n    @Field(3)\n    long l3;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<ActivityStatistics> CREATOR = findCreator(ActivityStatistics.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocation/AdditionalActivityCandidates.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocation;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.List;\n\n@SafeParcelable.Class\npublic class AdditionalActivityCandidates extends AbstractSafeParcelable {\n    @Field(1)\n    public final List<ActivityCandidate> candidates;\n\n    @Constructor\n    public AdditionalActivityCandidates(@Param(1) List<ActivityCandidate> candidates) {\n        this.candidates = candidates;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"AdditionalActivityCandidates\").value(candidates).end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<AdditionalActivityCandidates> CREATOR = findCreator(AdditionalActivityCandidates.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocation/AdditionalPlaceCandidates.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocation;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.List;\n\n@SafeParcelable.Class\npublic class AdditionalPlaceCandidates extends AbstractSafeParcelable {\n    @Field(1)\n    public final List<PlaceCandidate> candidates;\n\n    @Constructor\n    public AdditionalPlaceCandidates(@Param(1) List<PlaceCandidate> candidates) {\n        this.candidates = candidates;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"AdditionalPlaceCandidates\").value(candidates).end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<AdditionalPlaceCandidates> CREATOR = findCreator(AdditionalPlaceCandidates.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocation/Date.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocation;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class Date extends AbstractSafeParcelable {\n    @Field(1)\n    public final int year;\n    @Field(2)\n    public final int month;\n    @Field(3)\n    public final int day;\n\n    @Constructor\n    public Date(@Param(1) int year, @Param(2) int month, @Param(3) int day) {\n        this.year = year;\n        this.month = month;\n        this.day = day;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"Date\").value(String.format(\"%04d-%02d-%02d\", year, month, day)).end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<Date> CREATOR = findCreator(Date.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocation/DebugData.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocation;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.List;\n\n@SafeParcelable.Class\npublic class DebugData extends AbstractSafeParcelable {\n    @Field(1)\n    public final List<InputSignals> inputSignals;\n    @Field(2)\n    public final int versionNumber;\n    @Field(3)\n    public final List<SemanticSegment> segments;\n    @Field(4)\n    boolean b4;\n    @Field(5)\n    List<String> sl5;\n\n    @Constructor\n    public DebugData(@Param(1) List<InputSignals> inputSignals, @Param(2) int versionNumber, @Param(3) List<SemanticSegment> segments) {\n        this.inputSignals = inputSignals;\n        this.versionNumber = versionNumber;\n        this.segments = segments;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"DebugData\")\n                .field(\"inputSignals\", inputSignals)\n                .field(\"versionNumber\", versionNumber)\n                .field(\"segments\", segments)\n                .end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<DebugData> CREATOR = findCreator(DebugData.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocation/InputSignals.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocation;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class InputSignals extends AbstractSafeParcelable {\n    // TODO\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"InputSignals\").end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<InputSignals> CREATOR = findCreator(InputSignals.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocation/Note.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocation;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class Note extends AbstractSafeParcelable {\n    @Field(1)\n    public final String text;\n\n    @Constructor\n    public Note(@Param(1) String text) {\n        this.text = text;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"Note\").value(text).end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<Note> CREATOR = findCreator(Note.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocation/Parking.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocation;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class Parking extends AbstractSafeParcelable {\n    @Field(1)\n    public final long startTime;\n    @Field(2)\n    public final long endTime;\n    @Field(3)\n    public final PlaceCandidate.Point point;\n    @Field(4)\n    int i4;\n    @Field(5)\n    int i5;\n    @Field(6)\n    int i6;\n    @Field(7)\n    float f7;\n\n    @Constructor\n    public Parking(@Param(1) long startTime, @Param(2) long endTime, @Param(3) PlaceCandidate.Point point) {\n        this.startTime = startTime;\n        this.endTime = endTime;\n        this.point = point;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"Parking\")\n                .field(\"startTime\", startTime)\n                .field(\"endTime\", endTime)\n                .field(\"point\", point)\n                .end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<Parking> CREATOR = findCreator(Parking.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocation/Path.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocation;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.List;\n\n@SafeParcelable.Class\npublic class Path extends AbstractSafeParcelable {\n    @Field(1)\n    public final List<PointWithDetails> points;\n\n    @Constructor\n    public Path(@Param(1) List<PointWithDetails> points) {\n        this.points = points;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"Path\").value(points).end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<Path> CREATOR = findCreator(Path.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocation/PeriodSummary.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocation;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.List;\n\n@SafeParcelable.Class\npublic class PeriodSummary extends AbstractSafeParcelable {\n    @Field(1)\n    public final List<Visit> visits;\n    @Field(2)\n    public final List<ActivityStatistics> activityStatistics;\n    @Field(3)\n    public final Date date;\n\n    @Constructor\n    public PeriodSummary(@Param(1) List<Visit> visits, @Param(2) List<ActivityStatistics> activityStatistics, @Param(3) Date date) {\n        this.visits = visits;\n        this.activityStatistics = activityStatistics;\n        this.date = date;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"PeriodSummary\")\n                .field(\"visits\", visits)\n                .field(\"activityStatistics\", activityStatistics)\n                .field(\"date\", date)\n                .end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<PeriodSummary> CREATOR = findCreator(PeriodSummary.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocation/PlaceCandidate.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocation;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class PlaceCandidate extends AbstractSafeParcelable {\n\n    @Field(1)\n    public final Identifier identifier;\n    @Field(2)\n    public final int semanticType;\n    @Field(3)\n    public final float probability;\n    @Field(4)\n    @Deprecated\n    float f4;\n    @Field(5)\n    public final Point placeLocation;\n    @Field(6)\n    public final boolean isSensitiveForGorUsage;\n    @Field(7)\n    public final boolean isEligibleForGorUsage;\n    @Field(8)\n    public final double semanticTypeConfidenceScore;\n\n    @Constructor\n    public PlaceCandidate(@Param(1) Identifier identifier, @Param(2) int semanticType, @Param(3) float probability, @Param(5) Point placeLocation, @Param(6) boolean isSensitiveForGorUsage, @Param(7) boolean isEligibleForGorUsage, @Param(8) double semanticTypeConfidenceScore){\n        this.identifier = identifier;\n        this.semanticType = semanticType;\n        this.probability = probability;\n        this.placeLocation = placeLocation;\n        this.isSensitiveForGorUsage = isSensitiveForGorUsage;\n        this.isEligibleForGorUsage = isEligibleForGorUsage;\n        this.semanticTypeConfidenceScore = semanticTypeConfidenceScore;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<PlaceCandidate> CREATOR = findCreator(PlaceCandidate.class);\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"PlaceCandidate\")\n                .field(\"placeLocation\", placeLocation)\n                .field(\"isSensitiveForGorUsage\", isSensitiveForGorUsage)\n                .field(\"isEligibleForGorUsage\", isEligibleForGorUsage)\n                .field(\"semanticTypeConfidenceScore\", semanticTypeConfidenceScore)\n                .field(\"probability\", probability)\n                .field(\"identifier\", identifier)\n                .field(\"semanticType\", semanticType)\n                .end();\n    }\n\n    public static class Identifier extends AbstractSafeParcelable {\n        @Field(1)\n        public final long fprint;\n        @Field(2)\n        public final long cellId;\n\n        @Constructor\n        public Identifier(@Param(1) long fprint, @Param(1) long cellId) {\n            this.fprint = fprint;\n            this.cellId = cellId;\n        }\n\n        @Override\n        public void writeToParcel(@NonNull Parcel dest, int flags) {\n            CREATOR.writeToParcel(this, dest, flags);\n        }\n\n        public static final SafeParcelableCreatorAndWriter<Identifier> CREATOR = findCreator(Identifier.class);\n\n        @NonNull\n        @Override\n        public String toString() {\n            return \"0x\" + Long.toHexString(cellId) + \":0x\" + Long.toHexString(fprint);\n        }\n    }\n\n    public static class Point extends AbstractSafeParcelable {\n        @Field(1)\n        public final int latE7;\n        @Field(2)\n        public final int lngE7;\n\n        @Constructor\n        public Point(@Param(1) int latE7, @Param(1) int lngE7) {\n            this.latE7 = latE7;\n            this.lngE7 = lngE7;\n        }\n\n        @Override\n        public void writeToParcel(@NonNull Parcel dest, int flags) {\n            CREATOR.writeToParcel(this, dest, flags);\n        }\n\n        public static final SafeParcelableCreatorAndWriter<Point> CREATOR = findCreator(Point.class);\n\n        @NonNull\n        @Override\n        public String toString() {\n            return ToStringHelper.name(\"Point\")\n                    .field(\"latE7\", latE7)\n                    .field(\"lngE7\", lngE7)\n                    .end();\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocation/PlaceEnterEvent.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocation;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class PlaceEnterEvent extends AbstractSafeParcelable {\n    @Field(1)\n    public final int hierarchyLevel;\n    @Field(2)\n    public final float probability;\n    @Field(3)\n    @Deprecated\n    float f3;\n    @Field(4)\n    public final PlaceCandidate topCandidate;\n    @Field(5)\n    public final AdditionalPlaceCandidates additionalPlaceCandidates;\n\n    @Constructor\n    public PlaceEnterEvent(@Param(1) int hierarchyLevel, @Param(2) float probability, @Param(4) PlaceCandidate topCandidate, @Param(5) AdditionalPlaceCandidates additionalPlaceCandidates) {\n        this.hierarchyLevel = hierarchyLevel;\n        this.probability = probability;\n        this.topCandidate = topCandidate;\n        this.additionalPlaceCandidates = additionalPlaceCandidates;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"PlaceEnterEvent\")\n                .field(\"hierarchyLevel\", hierarchyLevel)\n                .field(\"probability\", probability)\n                .field(\"topCandidate\", topCandidate)\n                .field(\"additionalPlaceCandidates\", additionalPlaceCandidates)\n                .end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<PlaceEnterEvent> CREATOR = findCreator(PlaceEnterEvent.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocation/PlaceExitEvent.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocation;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class PlaceExitEvent extends AbstractSafeParcelable {\n    @Field(1)\n    public final int hierarchyLevel;\n    @Field(2)\n    public final float probability;\n    @Field(3)\n    @Deprecated\n    float f3;\n    @Field(4)\n    public final PlaceCandidate topCandidate;\n    @Field(5)\n    public final AdditionalPlaceCandidates additionalPlaceCandidates;\n\n    @Constructor\n    public PlaceExitEvent(@Param(1) int hierarchyLevel, @Param(2) float probability, @Param(4) PlaceCandidate topCandidate, @Param(5) AdditionalPlaceCandidates additionalPlaceCandidates) {\n        this.hierarchyLevel = hierarchyLevel;\n        this.probability = probability;\n        this.topCandidate = topCandidate;\n        this.additionalPlaceCandidates = additionalPlaceCandidates;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"PlaceExitEvent\")\n                .field(\"hierarchyLevel\", hierarchyLevel)\n                .field(\"probability\", probability)\n                .field(\"topCandidate\", topCandidate)\n                .field(\"additionalPlaceCandidates\", additionalPlaceCandidates)\n                .end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<PlaceExitEvent> CREATOR = findCreator(PlaceExitEvent.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocation/PlaceOngoingEvent.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocation;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class PlaceOngoingEvent extends AbstractSafeParcelable {\n    @Field(1)\n    public final int hierarchyLevel;\n    @Field(2)\n    public final float probability;\n    @Field(3)\n    @Deprecated\n    float f3;\n    @Field(4)\n    public final PlaceCandidate topCandidate;\n    @Field(5)\n    public final AdditionalPlaceCandidates additionalPlaceCandidates;\n\n    @Constructor\n    public PlaceOngoingEvent(@Param(1) int hierarchyLevel, @Param(2) float probability, @Param(4) PlaceCandidate topCandidate, @Param(5) AdditionalPlaceCandidates additionalPlaceCandidates) {\n        this.hierarchyLevel = hierarchyLevel;\n        this.probability = probability;\n        this.topCandidate = topCandidate;\n        this.additionalPlaceCandidates = additionalPlaceCandidates;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"PlaceOngoingEvent\")\n                .field(\"hierarchyLevel\", hierarchyLevel)\n                .field(\"probability\", probability)\n                .field(\"topCandidate\", topCandidate)\n                .field(\"additionalPlaceCandidates\", additionalPlaceCandidates)\n                .end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<PlaceOngoingEvent> CREATOR = findCreator(PlaceOngoingEvent.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocation/PointWithDetails.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocation;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class PointWithDetails extends AbstractSafeParcelable {\n    @Field(1)\n    public final PlaceCandidate.Point point;\n    @Field(2)\n    public final long timeOffset;\n    @Field(3)\n    @Deprecated\n    int i3;\n\n    @Constructor\n    public PointWithDetails(@Param(1) PlaceCandidate.Point point, @Param(2) long timeOffset) {\n        this.point = point;\n        this.timeOffset = timeOffset;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"PointWithDetails\")\n                .field(\"point\", point)\n                .field(\"timeOffset\", timeOffset)\n                .end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<PointWithDetails> CREATOR = findCreator(PointWithDetails.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocation/SemanticLocationEvent.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocation;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class SemanticLocationEvent extends AbstractSafeParcelable {\n    @Field(1)\n    public final long time;\n    @Field(2)\n    @Deprecated\n    String s2;\n    @Field(3)\n    public final int eventType;\n    @Field(4)\n    public final PlaceEnterEvent placeEnterEvent;\n    @Field(5)\n    public final PlaceExitEvent placeExitEvent;\n    @Field(6)\n    public final PlaceOngoingEvent placeOngoingEvent;\n    @Field(7)\n    public final ActivityStartEvent activityStartEvent;\n    @Field(8)\n    public final ActivityEndEvent activityEndEvent;\n    @Field(9)\n    public final ActivityOngoingEvent activityOngoingEvent;\n\n    @Constructor\n    public SemanticLocationEvent(@Param(1) long time, @Param(3) int eventType, @Param(4) PlaceEnterEvent placeEnterEvent, @Param(5) PlaceExitEvent placeExitEvent, @Param(6) PlaceOngoingEvent placeOngoingEvent, @Param(7) ActivityStartEvent activityStartEvent, @Param(8) ActivityEndEvent activityEndEvent, @Param(9) ActivityOngoingEvent activityOngoingEvent) {\n        this.time = time;\n        this.eventType = eventType;\n        this.placeEnterEvent = placeEnterEvent;\n        this.placeExitEvent = placeExitEvent;\n        this.placeOngoingEvent = placeOngoingEvent;\n        this.activityStartEvent = activityStartEvent;\n        this.activityEndEvent = activityEndEvent;\n        this.activityOngoingEvent = activityOngoingEvent;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"SemanticLocationEvent\")\n                .field(\"time\", time)\n                .field(\"eventType\", eventType)\n                .field(\"placeEnterEvent\", placeEnterEvent)\n                .field(\"placeExitEvent\", placeExitEvent)\n                .field(\"placeOngoingEvent\", placeOngoingEvent)\n                .field(\"activityStartEvent\", activityStartEvent)\n                .field(\"activityEndEvent\", activityEndEvent)\n                .field(\"activityOngoingEvent\", activityOngoingEvent)\n                .end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<SemanticLocationEvent> CREATOR = findCreator(SemanticLocationEvent.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocation/SemanticLocationEventRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.semanticlocation;\n\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class SemanticLocationEventRequest extends AbstractSafeParcelable {\n    @Field(1)\n    public final float position;\n\n    @Constructor\n    public SemanticLocationEventRequest(@Param(1) float position) {\n        this.position = position;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<SemanticLocationEventRequest> CREATOR = findCreator(SemanticLocationEventRequest.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocation/SemanticLocationState.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocation;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.List;\n\n@SafeParcelable.Class\npublic class SemanticLocationState extends AbstractSafeParcelable {\n    @Field(1)\n    public final List<SemanticLocationEvent> events;\n    @Field(2)\n    public final long timesamp;\n    @Field(3)\n    public final DebugData debugData;\n    @Field(4)\n    public final String stateId;\n\n    @Constructor\n    public SemanticLocationState(@Param(1) List<SemanticLocationEvent> events, @Param(2) long timesamp, @Param(3) DebugData debugData, @Param(4) String stateId) {\n        this.events = events;\n        this.timesamp = timesamp;\n        this.debugData = debugData;\n        this.stateId = stateId;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"SemanticLocationState\")\n                .field(\"events\", events)\n                .field(\"timestamp\", timesamp)\n                .field(\"debugData\", debugData)\n                .field(\"stateId\", stateId)\n                .end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<SemanticLocationState> CREATOR = findCreator(SemanticLocationState.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocation/SemanticSegment.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocation;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class SemanticSegment extends AbstractSafeParcelable {\n    // TODO\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"SemanticSegment\").end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<SemanticSegment> CREATOR = findCreator(SemanticSegment.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocation/TemporarilyClosedPlaceCandidates.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocation;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.List;\n\n@SafeParcelable.Class\npublic class TemporarilyClosedPlaceCandidates extends AbstractSafeParcelable {\n    @Field(1)\n    public final List<PlaceCandidate> candidates;\n\n    @Constructor\n    public TemporarilyClosedPlaceCandidates(@Param(1) List<PlaceCandidate> candidates) {\n        this.candidates = candidates;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"TemporarilyClosedPlaceCandidates\").value(candidates).end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<TemporarilyClosedPlaceCandidates> CREATOR = findCreator(TemporarilyClosedPlaceCandidates.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocation/TimelineMemory.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocation;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class TimelineMemory extends AbstractSafeParcelable {\n    @Field(1)\n    public final Trip trip;\n    @Field(2)\n    public final Note note;\n\n    @Constructor\n    public TimelineMemory(@Param(1) Trip trip, @Param(2) Note note) {\n        this.trip = trip;\n        this.note = note;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"TimelineMemory\")\n                .field(\"trip\", trip)\n                .field(\"note\", note)\n                .end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<TimelineMemory> CREATOR = findCreator(TimelineMemory.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocation/TimelinePath.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocation;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.List;\n\n@SafeParcelable.Class\npublic class TimelinePath extends AbstractSafeParcelable {\n    @Field(1)\n    @Deprecated\n    List<SegmentPath> paths;\n    @Field(2)\n    public final Path path;\n\n    @Constructor\n    public TimelinePath(@Param(2) Path path) {\n        this.path = path;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"TimelinePath\").value(path).end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<TimelinePath> CREATOR = findCreator(TimelinePath.class);\n\n    public static class SegmentPath extends AbstractSafeParcelable {\n        @Field(1)\n        String s1;\n        @Field(2)\n        public final Path path;\n\n        @Constructor\n        public SegmentPath(@Param(2) Path path) {\n            this.path = path;\n        }\n\n        @Override\n        public void writeToParcel(@NonNull Parcel dest, int flags) {\n            CREATOR.writeToParcel(this, dest, flags);\n        }\n\n        public static final SafeParcelableCreatorAndWriter<SegmentPath> CREATOR = findCreator(SegmentPath.class);\n    }\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocation/Trip.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocation;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.List;\n\n@SafeParcelable.Class\npublic class Trip extends AbstractSafeParcelable {\n    @Field(1)\n    public final long distance;\n    @Field(2)\n    public final List<Destination> destinations;\n    @Field(3)\n    public final NameComponents nameComponents;\n    @Field(4)\n    public final Origin origin;\n    @Field(5)\n    boolean b5;\n\n    @Constructor\n    public Trip(@Param(1) long distance, @Param(2) List<Destination> destinations, @Param(3) NameComponents nameComponents, @Param(4) Origin origin) {\n        this.distance = distance;\n        this.destinations = destinations;\n        this.nameComponents = nameComponents;\n        this.origin = origin;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"Trip\")\n                .field(\"origin\", origin)\n                .field(\"distance\", distance)\n                .field(\"destinations\", destinations)\n                .field(\"nameComponents\", nameComponents)\n                .end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<Trip> CREATOR = findCreator(Trip.class);\n\n    @Class\n    public static class Destination extends AbstractSafeParcelable {\n        @Field(1)\n        public final PlaceCandidate.Identifier identifier;\n\n        @Constructor\n        public Destination(@Param(1) PlaceCandidate.Identifier identifier) {\n            this.identifier = identifier;\n        }\n\n        @NonNull\n        @Override\n        public String toString() {\n            return ToStringHelper.name(\"Destination\").value(identifier).end();\n        }\n\n        @Override\n        public void writeToParcel(@NonNull Parcel dest, int flags) {\n            CREATOR.writeToParcel(this, dest, flags);\n        }\n\n        public static final SafeParcelableCreatorAndWriter<Destination> CREATOR = findCreator(Destination.class);\n    }\n\n    @Class\n    public static class NameComponents extends AbstractSafeParcelable {\n        @Field(1)\n        public final List<Destination> components;\n\n        @Constructor\n        public NameComponents(@Param(1) List<Destination> components) {\n            this.components = components;\n        }\n\n        @NonNull\n        @Override\n        public String toString() {\n            return ToStringHelper.name(\"NameComponents\").value(components).end();\n        }\n\n        @Override\n        public void writeToParcel(@NonNull Parcel dest, int flags) {\n            CREATOR.writeToParcel(this, dest, flags);\n        }\n\n        public static final SafeParcelableCreatorAndWriter<NameComponents> CREATOR = findCreator(NameComponents.class);\n    }\n\n    @Class\n    public static class Origin extends AbstractSafeParcelable {\n        @Field(1)\n        public final PlaceCandidate.Identifier identifier;\n        @Field(2)\n        public final PlaceCandidate.Point point;\n\n        @Constructor\n        public Origin(@Param(1) PlaceCandidate.Identifier identifier, @Param(2) PlaceCandidate.Point point) {\n            this.identifier = identifier;\n            this.point = point;\n        }\n\n        @NonNull\n        @Override\n        public String toString() {\n            return ToStringHelper.name(\"Origin\")\n                    .field(\"identifier\", identifier)\n                    .field(\"point\", point)\n                    .end();\n        }\n\n        @Override\n        public void writeToParcel(@NonNull Parcel dest, int flags) {\n            CREATOR.writeToParcel(this, dest, flags);\n        }\n\n        public static final SafeParcelableCreatorAndWriter<Origin> CREATOR = findCreator(Origin.class);\n    }\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocation/Visit.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocation;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class Visit extends AbstractSafeParcelable {\n    @Field(1)\n    public final int hierarchyLevel;\n    @Field(2)\n    public final float probability;\n    @Field(3)\n    @Deprecated\n    float f3;\n    @Field(4)\n    public final PlaceCandidate place;\n    @Field(5)\n    public final AdditionalPlaceCandidates additionalPlaceCandidates;\n    @Field(6)\n    public final boolean isTimelessVisit;\n    @Field(7)\n    public final TemporarilyClosedPlaceCandidates temporarilyClosedPlaceCandidates;\n    @Field(8)\n    boolean b8;\n\n    @Constructor\n    public Visit(@Param(1) int hierarchyLevel, @Param(2) float probability, @Param(4) PlaceCandidate place, @Param(5) AdditionalPlaceCandidates additionalPlaceCandidates, @Param(6) boolean isTimelessVisit, @Param(7) TemporarilyClosedPlaceCandidates temporarilyClosedPlaceCandidates) {\n        this.hierarchyLevel = hierarchyLevel;\n        this.probability = probability;\n        this.place = place;\n        this.additionalPlaceCandidates = additionalPlaceCandidates;\n        this.isTimelessVisit = isTimelessVisit;\n        this.temporarilyClosedPlaceCandidates = temporarilyClosedPlaceCandidates;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"Visit\")\n                .field(\"hierarchyLevel\", hierarchyLevel)\n                .field(\"probability\", probability)\n                .field(\"place\", place)\n                .field(\"additionalPlaceCandidates\", additionalPlaceCandidates)\n                .field(\"isTimelessVisit\", isTimelessVisit)\n                .field(\"temporarilyClosedPlaceCandidates\", temporarilyClosedPlaceCandidates)\n                .end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<Visit> CREATOR = findCreator(Visit.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocation/internal/SemanticLocationParameters.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.semanticlocation.internal;\n\nimport android.accounts.Account;\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class SemanticLocationParameters extends AbstractSafeParcelable {\n    @Field(1)\n    public final Account account;\n    @Field(2)\n    public final String clientIdentifier;\n    @Field(3)\n    public final String packageName;\n\n    @Constructor\n    public SemanticLocationParameters(@Param(1) Account account, @Param(2) String clientIdentifier, @Param(3) String packageName) {\n        this.account = account;\n        this.clientIdentifier = clientIdentifier;\n        this.packageName = packageName;\n    }\n\n    public static final SafeParcelableCreatorAndWriter<SemanticLocationParameters> CREATOR = findCreator(SemanticLocationParameters.class);\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocationhistory/DeletionRange.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocationhistory;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class DeletionRange extends AbstractSafeParcelable {\n    @Field(1)\n    public final long startTimestampSeconds;\n    @Field(2)\n    public final long endTimestampSeconds;\n\n    @Constructor\n    public DeletionRange(@Param(1) long startTimestampSeconds, @Param(2) long endTimestampSeconds) {\n        this.startTimestampSeconds = startTimestampSeconds;\n        this.endTimestampSeconds = endTimestampSeconds;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<DeletionRange> CREATOR = findCreator(DeletionRange.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocationhistory/DeviceMetadata.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocationhistory;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport java.util.List;\n\n@SafeParcelable.Class\npublic class DeviceMetadata extends AbstractSafeParcelable {\n    @Field(1)\n    public List<String> subIdentifiers;\n    @Field(2)\n    public boolean hasFineLocationPermission;\n    @Field(3)\n    public boolean b3;\n    @Field(4)\n    public List<DeletionRange> deletionRanges;\n    @Field(5)\n    public int deviceTag;\n\n    @Constructor\n    public DeviceMetadata(@Param(1) List<String> subIdentifiers, @Param(2) boolean hasFineLocationPermission, @Param(3) boolean b3, @Param(4) List<DeletionRange> deletionRanges, @Param(5) int deviceTag) {\n        this.subIdentifiers = subIdentifiers;\n        this.hasFineLocationPermission = hasFineLocationPermission;\n        this.b3 = b3;\n        this.deletionRanges = deletionRanges;\n        this.deviceTag = deviceTag;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<DeviceMetadata> CREATOR = findCreator(DeviceMetadata.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocationhistory/ExperimentVisitsResponse.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocationhistory;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.List;\n\n@SafeParcelable.Class\npublic class ExperimentVisitsResponse extends AbstractSafeParcelable {\n    @Field(1)\n    public final List<LocationHistorySegment> segments;\n    @Field(2)\n    public final int lastSubIdentifier;\n    @Field(3)\n    public final DeviceMetadata deviceMetadata;\n\n    @Constructor\n    public ExperimentVisitsResponse(@Param(1) List<LocationHistorySegment> segments, @Param(2) int lastSubIdentifier, @Param(3) DeviceMetadata deviceMetadata) {\n        this.segments = segments;\n        this.lastSubIdentifier = lastSubIdentifier;\n        this.deviceMetadata = deviceMetadata;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<ExperimentVisitsResponse> CREATOR = findCreator(ExperimentVisitsResponse.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocationhistory/FieldMask.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocationhistory;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.List;\n\n@SafeParcelable.Class\npublic class FieldMask extends AbstractSafeParcelable {\n\n    @Field(1)\n    public final List<String> list;\n\n    @Constructor\n    public FieldMask(@Param(1) List<String> list) {\n        this.list = list;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<FieldMask> CREATOR = findCreator(FieldMask.class);\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"FieldMask\").field(\"list\", list).end();\n    }\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocationhistory/FrequentPlace.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocationhistory;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.semanticlocation.PlaceCandidate;\n\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.List;\n\n@SafeParcelable.Class\npublic class FrequentPlace extends AbstractSafeParcelable {\n\n    @Field(1)\n    public PlaceCandidate.Identifier identifier;\n    @Field(2)\n    public PlaceCandidate.Point placeLocation;\n    @Field(3)\n    public int type;\n    @Field(4)\n    @Deprecated\n    FrequentPlaceMetadata metadata;\n    @Field(5)\n    @Deprecated\n    List<String> keys;\n    @Field(6)\n    public final List<Float> weeklyOccupancy;\n    @Field(7)\n    public final int numWeeksSinceLastVisit;\n\n    @Constructor\n    public FrequentPlace(@Param(1) PlaceCandidate.Identifier identifier, @Param(2) PlaceCandidate.Point placeLocation, @Param(3) int type, @Param(6) List<Float> weeklyOccupancy, @Param(7) int numWeeksSinceLastVisit) {\n        this.identifier = identifier;\n        this.placeLocation = placeLocation;\n        this.type = type;\n        this.weeklyOccupancy = weeklyOccupancy;\n        this.numWeeksSinceLastVisit = numWeeksSinceLastVisit;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"FrequentPlace\")\n                .field(\"identifier\", identifier)\n                .field(\"placeLocation\", placeLocation)\n                .field(\"type\", type)\n                .field(\"weeklyOccupancy\", weeklyOccupancy)\n                .field(\"numWeeksSinceLastVisit\", numWeeksSinceLastVisit)\n                .end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<FrequentPlace> CREATOR = findCreator(FrequentPlace.class);\n\n    @Class\n    public static class FrequentPlaceMetadata extends AbstractSafeParcelable {\n        @Field(1)\n        public long timestamp;\n\n        @Constructor\n        public FrequentPlaceMetadata(@Param(1) long timestamp) {\n            this.timestamp = timestamp;\n        }\n\n        @NonNull\n        @Override\n        public String toString() {\n            return ToStringHelper.name(\"FrequentPlaceMetadata\")\n                    .field(\"creationTime\", timestamp)\n                    .end();\n        }\n\n        @Override\n        public void writeToParcel(@NonNull Parcel dest, int flags) {\n            CREATOR.writeToParcel(this, dest, flags);\n        }\n\n        public static final SafeParcelableCreatorAndWriter<FrequentPlace.FrequentPlaceMetadata> CREATOR = findCreator(FrequentPlace.FrequentPlaceMetadata.class);\n    }\n\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocationhistory/FrequentTrip.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocationhistory;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.semanticlocation.PlaceCandidate;\n\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.List;\n\n@SafeParcelable.Class\npublic class FrequentTrip extends AbstractSafeParcelable {\n\n    @Field(1)\n    public final List<PlaceCandidate.Identifier> waypointIds;\n    @Field(2)\n    public final Metadata metadata;\n    @Field(3)\n    public final List<FrequentTrip.ModeDistribution> modeDistributionList;\n    @Field(4)\n    public final int startTimeMinutes;\n    @Field(5)\n    public final int endTimeMinutes;\n    @Field(6)\n    public final int durationMinutes;\n    @Field(7)\n    public final float confidence;\n    @Field(8)\n    public final int commuteDirection;\n    @Field(9)\n    public final int fromType;\n    @Field(10)\n    public final int toType;\n\n    @Constructor\n    public FrequentTrip(@Param(1) List<PlaceCandidate.Identifier> waypointIds, @Param(2) Metadata metadata, @Param(3) List<FrequentTrip.ModeDistribution> modeDistributionList, @Param(4) int startTimeMinutes, @Param(5) int endTimeMinutes, @Param(6) int durationMinutes, @Param(7) float confidence, @Param(8) int commuteDirection, @Param(9) int fromType, @Param(10) int toType) {\n        this.waypointIds = waypointIds;\n        this.metadata = metadata;\n        this.modeDistributionList = modeDistributionList;\n        this.startTimeMinutes = startTimeMinutes;\n        this.endTimeMinutes = endTimeMinutes;\n        this.durationMinutes = durationMinutes;\n        this.confidence = confidence;\n        this.commuteDirection = commuteDirection;\n        this.fromType = fromType;\n        this.toType = toType;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"FrequentTrip\")\n                .field(\"waypointIds\", waypointIds)\n                .field(\"metadata\", metadata)\n                .field(\"modeDistributionList\", modeDistributionList)\n                .field(\"startTimeMinutes\", startTimeMinutes)\n                .field(\"endTimeMinutes\", endTimeMinutes)\n                .field(\"durationMinutes\", durationMinutes)\n                .field(\"confidence\", confidence)\n                .field(\"commuteDirection\", commuteDirection)\n                .field(\"fromType\", fromType)\n                .field(\"toType\", toType)\n                .end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<FrequentTrip> CREATOR = findCreator(FrequentTrip.class);\n\n    @Class\n    public static class Metadata extends AbstractSafeParcelable {\n        @Field(1)\n        public final long creationTime;\n\n        @Constructor\n        public Metadata(@Param(1) long creationTime) {\n            this.creationTime = creationTime;\n        }\n\n        @NonNull\n        @Override\n        public String toString() {\n            return ToStringHelper.name(\"Metadata\")\n                    .field(\"creationTime\", creationTime)\n                    .end();\n        }\n\n        @Override\n        public void writeToParcel(@NonNull Parcel dest, int flags) {\n            CREATOR.writeToParcel(this, dest, flags);\n        }\n\n        public static final SafeParcelableCreatorAndWriter<FrequentTrip.Metadata> CREATOR = findCreator(FrequentTrip.Metadata.class);\n    }\n\n    @Class\n    public static class ModeDistribution extends AbstractSafeParcelable {\n        @Field(1)\n        public final int mode;\n        @Field(2)\n        public final float rate;\n\n        @Constructor\n        public ModeDistribution(@Param(1) int mode, @Param(2) float rate) {\n            this.mode = mode;\n            this.rate = rate;\n        }\n\n        @NonNull\n        @Override\n        public String toString() {\n            return ToStringHelper.name(\"ModeDistribution\")\n                    .field(\"distance\", mode)\n                    .field(\"confidence\", rate)\n                    .end();\n        }\n\n        @Override\n        public void writeToParcel(@NonNull Parcel dest, int flags) {\n            CREATOR.writeToParcel(this, dest, flags);\n        }\n\n        public static final SafeParcelableCreatorAndWriter<FrequentTrip.ModeDistribution> CREATOR = findCreator(FrequentTrip.ModeDistribution.class);\n    }\n\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocationhistory/InferredPlace.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocationhistory;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.semanticlocation.PlaceCandidate;\n\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class InferredPlace extends AbstractSafeParcelable {\n\n    @Field(1)\n    public final PlaceCandidate.Identifier identifier;\n    @Field(2)\n    public final PlaceCandidate.Point point;\n    @Field(3)\n    public final int inferredPlaceType;\n\n    @Constructor\n    public InferredPlace(@Param(1) PlaceCandidate.Identifier identifier, @Param(2) PlaceCandidate.Point point, @Param(3) int inferredPlaceType) {\n        this.identifier = identifier;\n        this.point = point;\n        this.inferredPlaceType = inferredPlaceType;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<InferredPlace> CREATOR = findCreator(InferredPlace.class);\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"InferredPlace\")\n                .field(\"identifier\", identifier)\n                .field(\"point\", point)\n                .field(\"inferredPlaceType\", inferredPlaceType)\n                .end();\n    }\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocationhistory/LocationHistorySegment.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocationhistory;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport com.google.android.gms.semanticlocation.*;\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class LocationHistorySegment extends AbstractSafeParcelable {\n\n    @Field(1)\n    public final long startTimestamp;\n    @Field(2)\n    public final long endTimestamp;\n    @Field(3)\n    public final int startTimeTimezoneUtcOffsetMinutes;\n    @Field(4)\n    public final int endTimeTimezoneUtcOffsetMinutes;\n    @Field(7)\n    public final String segmentId;\n    @Field(8)\n    public final int type;\n    @Field(9)\n    public final Visit visit;\n    @Field(10)\n    public final Activity activity;\n    @Field(11)\n    public final TimelinePath timelinePath;\n    @Field(12)\n    public final int displayMode;\n    @Field(13)\n    public final int finalizationStatus;\n    @Field(14)\n    public final TimelineMemory timelineMemory;\n    @Field(15)\n    public final PeriodSummary periodSummary;\n\n    @Constructor\n    public LocationHistorySegment(@Param(1) long startTimestamp, @Param(2) long endTimestamp, @Param(3) int startTimeTimezoneUtcOffsetMinutes, @Param(4) int endTimeTimezoneUtcOffsetMinutes, @Param(7) String segmentId, @Param(8) int type, @Param(9) Visit visit, @Param(10) Activity activity, @Param(11) TimelinePath timelinePath, @Param(12) int displayMode, @Param(13) int finalizationStatus, @Param(14) TimelineMemory timelineMemory, @Param(15) PeriodSummary periodSummary) {\n        this.startTimestamp = startTimestamp;\n        this.endTimestamp = endTimestamp;\n        this.startTimeTimezoneUtcOffsetMinutes = startTimeTimezoneUtcOffsetMinutes;\n        this.endTimeTimezoneUtcOffsetMinutes = endTimeTimezoneUtcOffsetMinutes;\n        this.segmentId = segmentId;\n        this.type = type;\n        this.visit = visit;\n        this.activity = activity;\n        this.timelinePath = timelinePath;\n        this.displayMode = displayMode;\n        this.finalizationStatus = finalizationStatus;\n        this.timelineMemory = timelineMemory;\n        this.periodSummary = periodSummary;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<LocationHistorySegment> CREATOR = findCreator(LocationHistorySegment.class);\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"LocationHistorySegment\")\n                .field(\"startTime\", startTimestamp)\n                .field(\"endTime\", endTimestamp)\n                .field(\"startTimeTimezoneUtcOffsetMinutes\", startTimeTimezoneUtcOffsetMinutes)\n                .field(\"endTimeTimezoneUtcOffsetMinutes\", endTimeTimezoneUtcOffsetMinutes)\n                .field(\"segmentId\", segmentId)\n                .field(\"type\", type)\n                .field(\"visit\", visit)\n                .field(\"activity\", activity)\n                .field(\"timelinePath\", timelinePath)\n                .field(\"timelineMemory\", timelineMemory)\n                .field(\"periodSummary\", periodSummary)\n                .field(\"displayMode\", displayMode)\n                .field(\"finalizationStatus\", finalizationStatus)\n                .end();\n    }\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocationhistory/LocationHistorySegmentRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocationhistory;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.List;\n\n@SafeParcelable.Class\npublic class LocationHistorySegmentRequest extends AbstractSafeParcelable {\n\n    @Field(1)\n    public final List<LookupParameters> parameters;\n    @Field(2)\n    public final FieldMask fieldMask;\n    @Field(3)\n    public final boolean skipFlush;\n\n    @Constructor\n    public LocationHistorySegmentRequest(@Param(1) List<LookupParameters> parameters, @Param(2) FieldMask fieldMask, @Param(3) boolean skipFlush) {\n        this.parameters = parameters;\n        this.fieldMask = fieldMask;\n        this.skipFlush = skipFlush;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<LocationHistorySegmentRequest> CREATOR = findCreator(LocationHistorySegmentRequest.class);\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"LocationHistorySegmentRequest\")\n                .field(\"parameters\", parameters)\n                .field(\"fieldMask\", fieldMask)\n                .field(\"skipFlush\", skipFlush)\n                .end();\n    }\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocationhistory/LocationHistorySettings.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocationhistory;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.location.reporting.ReportingState;\n\n@SafeParcelable.Class\npublic class LocationHistorySettings extends AbstractSafeParcelable {\n    @Field(1)\n    public final boolean enabled;\n    @Field(2)\n    public final int deviceId;\n    @Field(3)\n    public final ReportingState reportingState;\n\n    @Constructor\n    public LocationHistorySettings(@Param(1) boolean enabled, @Param(2) int deviceId, @Param(3) ReportingState reportingState) {\n        this.enabled = enabled;\n        this.deviceId = deviceId;\n        this.reportingState = reportingState;\n    }\n\n    public static final SafeParcelableCreatorAndWriter<LocationHistorySettings> CREATOR = findCreator(LocationHistorySettings.class);\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocationhistory/LookupParameters.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocationhistory;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class LookupParameters extends AbstractSafeParcelable {\n\n    @Field(1)\n    public final int type;\n    @Field(2)\n    public final String segmentId;\n    @Field(3)\n    public final TimeRangeFilter timeRangeFilter;\n    @Field(4)\n    public final boolean b4;\n    @Field(5)\n    public final Integer i5;\n    @Field(6)\n    public final Integer i6;\n    @Field(7)\n    public final Long fprint;\n\n    @Constructor\n    public LookupParameters(@Param(1) int type, @Param(2) String segmentId, @Param(3) TimeRangeFilter timeRangeFilter, @Param(4) boolean b4, @Param(5) Integer i5, @Param(6) Integer i6, @Param(7) Long fprint){\n        this.type = type;\n        this.segmentId = segmentId;\n        this.timeRangeFilter = timeRangeFilter;\n        this.b4 = b4;\n        this.i5 = i5;\n        this.i6 = i6;\n        this.fprint = fprint;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<LookupParameters> CREATOR = findCreator(LookupParameters.class);\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"LookupParameters\")\n                .field(\"type\", type)\n                .field(\"segmentId\", segmentId)\n                .field(\"timeRangeFilter\", timeRangeFilter)\n                .field(\"fprint\", fprint)\n                .end();\n    }\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocationhistory/OdlhBackupSummary.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocationhistory;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class OdlhBackupSummary extends AbstractSafeParcelable {\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<OdlhBackupSummary> CREATOR = findCreator(OdlhBackupSummary.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocationhistory/Persona.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocationhistory;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.semanticlocation.PlaceCandidate;\n\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.List;\n\n@SafeParcelable.Class\npublic class Persona extends AbstractSafeParcelable {\n    @Field(1)\n    public final PersonaMetadata metadata;\n    @Field(2)\n    public final List<LocationAffinity> locationAffinities;\n    @Field(3)\n    public final List<TravelModeAffinity> travelModeAffinities;\n\n    @Constructor\n    public Persona(@Param(1) PersonaMetadata metadata, @Param(2) List<LocationAffinity> locationAffinities, @Param(3) List<TravelModeAffinity> travelModeAffinities){\n        this.metadata = metadata;\n        this.locationAffinities = locationAffinities;\n        this.travelModeAffinities = travelModeAffinities;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"Persona\")\n                .field(\"metadata\", metadata)\n                .field(\"locationAffinities\", locationAffinities)\n                .field(\"travelModeAffinities\", travelModeAffinities)\n                .end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<Persona> CREATOR = findCreator(Persona.class);\n\n    @Class\n    public static class LocationAffinity extends AbstractSafeParcelable {\n        @Field(1)\n        public final PlaceCandidate.Identifier identifier;\n        @Field(2)\n        public final float averageNumVisitsPerMonth;\n        @Field(3)\n        public final long latestVisitTime;\n        @Field(4)\n        public final float distanceToInferredHomeMeters;\n        @Field(5)\n        public final float distanceToInferredWorkMeters;\n        @Field(6)\n        public final float fractionOfPoiVisits;\n\n        @Constructor\n        public LocationAffinity(@Param(1) PlaceCandidate.Identifier identifier, @Param(2) float averageNumVisitsPerMonth, @Param(3) long latestVisitTime, @Param(4) float distanceToInferredHomeMeters, @Param(5) float distanceToInferredWorkMeters, @Param(6) float fractionOfPoiVisits) {\n            this.identifier = identifier;\n            this.averageNumVisitsPerMonth = averageNumVisitsPerMonth;\n            this.latestVisitTime = latestVisitTime;\n            this.distanceToInferredHomeMeters = distanceToInferredHomeMeters;\n            this.distanceToInferredWorkMeters = distanceToInferredWorkMeters;\n            this.fractionOfPoiVisits = fractionOfPoiVisits;\n        }\n\n        @NonNull\n        @Override\n        public String toString() {\n            return ToStringHelper.name(\"LocationAffinity\")\n                    .field(\"identifier\", identifier)\n                    .field(\"averageNumVisitsPerMonth\", averageNumVisitsPerMonth)\n                    .field(\"latestVisitTime\", latestVisitTime)\n                    .field(\"distanceToInferredHomeMeters\", distanceToInferredHomeMeters)\n                    .field(\"distanceToInferredWorkMeters\", distanceToInferredWorkMeters)\n                    .field(\"fractionOfPoiVisits\", fractionOfPoiVisits)\n                    .end();\n        }\n\n        @Override\n        public void writeToParcel(@NonNull Parcel dest, int flags) {\n            CREATOR.writeToParcel(this, dest, flags);\n        }\n\n        public static final SafeParcelableCreatorAndWriter<LocationAffinity> CREATOR = findCreator(LocationAffinity.class);\n    }\n\n    @Class\n    public static class PersonaMetadata extends AbstractSafeParcelable {\n        @Field(1)\n        public final long creationTime;\n\n        @Constructor\n        public PersonaMetadata(@Param(1) long creationTime) {\n            this.creationTime = creationTime;\n        }\n\n        @NonNull\n        @Override\n        public String toString() {\n            return ToStringHelper.name(\"PersonaMetadata\")\n                    .field(\"creationTime\", creationTime)\n                    .end();\n        }\n\n        @Override\n        public void writeToParcel(@NonNull Parcel dest, int flags) {\n            CREATOR.writeToParcel(this, dest, flags);\n        }\n\n        public static final SafeParcelableCreatorAndWriter<PersonaMetadata> CREATOR = findCreator(PersonaMetadata.class);\n    }\n\n    @Class\n    public static class TravelModeAffinity extends AbstractSafeParcelable {\n        @Field(1)\n        public final int travelMode;\n        @Field(2)\n        public final float affinityScore;\n        @Field(3)\n        public final int totalNumTrips;\n        @Field(4)\n        public final int numTripsPastWeek;\n        @Field(5)\n        public final int numTripsPast4Weeks;\n        @Field(6)\n        public final int numTripsPast12Weeks;\n        @Field(7)\n        public final TripSummary tripSummaryPastWeek;\n        @Field(8)\n        public final TripSummary tripSummaryPast4Weeks;\n        @Field(9)\n        public final TripSummary tripSummaryPast12Weeks;\n\n        @Constructor\n        public TravelModeAffinity(@Param(1) int travelMode, @Param(2) float affinityScore, @Param(3) int totalNumTrips, @Param(4) int numTripsPastWeek, @Param(5) int numTripsPast4Weeks, @Param(6) int numTripsPast12Weeks, @Param(7) TripSummary tripSummaryPastWeek, @Param(8) TripSummary tripSummaryPast4Weeks, @Param(9) TripSummary tripSummaryPast12Weeks) {\n            this.travelMode = travelMode;\n            this.affinityScore = affinityScore;\n            this.totalNumTrips = totalNumTrips;\n            this.numTripsPastWeek = numTripsPastWeek;\n            this.numTripsPast4Weeks = numTripsPast4Weeks;\n            this.numTripsPast12Weeks = numTripsPast12Weeks;\n            this.tripSummaryPastWeek = tripSummaryPastWeek;\n            this.tripSummaryPast4Weeks = tripSummaryPast4Weeks;\n            this.tripSummaryPast12Weeks = tripSummaryPast12Weeks;\n        }\n\n        @NonNull\n        @Override\n        public String toString() {\n            return ToStringHelper.name(\"TravelModeAffinity\")\n                    .field(\"travelMode\", travelMode)\n                    .field(\"affinityScore\", affinityScore)\n                    .field(\"totalNumTrips\", totalNumTrips)\n                    .field(\"numTripsPastWeek\", numTripsPastWeek)\n                    .field(\"numTripsPast4Weeks\", numTripsPast4Weeks)\n                    .field(\"numTripsPast12Weeks\", numTripsPast12Weeks)\n                    .field(\"tripSummaryPastWeek\", tripSummaryPastWeek)\n                    .field(\"tripSummaryPast4Weeks\", tripSummaryPast4Weeks)\n                    .field(\"tripSummaryPast12Weeks\", tripSummaryPast12Weeks)\n                    .end();\n        }\n\n        @Override\n        public void writeToParcel(@NonNull Parcel dest, int flags) {\n            CREATOR.writeToParcel(this, dest, flags);\n        }\n\n        public static final SafeParcelableCreatorAndWriter<TravelModeAffinity> CREATOR = findCreator(TravelModeAffinity.class);\n    }\n\n    @Class\n    public static class TripSummary extends AbstractSafeParcelable {\n        @Field(1)\n        public final float avgSpeedMetersPerSecond;\n        @Field(2)\n        public final float medianSpeedMetersPerSecond;\n        @Field(3)\n        public final long avgDurationSeconds;\n        @Field(4)\n        public final long medianDurationSeconds;\n        @Field(5)\n        public final int avgDistanceMeters;\n        @Field(6)\n        public final int medianDistanceMeters;\n\n        @Constructor\n        public TripSummary(@Param(1) float avgSpeedMetersPerSecond, @Param(2) float medianSpeedMetersPerSecond, @Param(3) long avgDurationSeconds, @Param(4) long medianDurationSeconds, @Param(5) int avgDistanceMeters, @Param(6) int medianDistanceMeters) {\n            this.avgSpeedMetersPerSecond = avgSpeedMetersPerSecond;\n            this.medianSpeedMetersPerSecond = medianSpeedMetersPerSecond;\n            this.avgDurationSeconds = avgDurationSeconds;\n            this.medianDurationSeconds = medianDurationSeconds;\n            this.avgDistanceMeters = avgDistanceMeters;\n            this.medianDistanceMeters = medianDistanceMeters;\n        }\n\n        @NonNull\n        @Override\n        public String toString() {\n            return ToStringHelper.name(\"TripSummary\")\n                    .field(\"avgSpeedMetersPerSecond\", avgSpeedMetersPerSecond)\n                    .field(\"medianSpeedMetersPerSecond\", medianSpeedMetersPerSecond)\n                    .field(\"avgDurationSeconds\", avgDurationSeconds)\n                    .field(\"medianDurationSeconds\", medianDurationSeconds)\n                    .field(\"avgDistanceMeters\", avgDistanceMeters)\n                    .field(\"medianDistanceMeters\", medianDistanceMeters)\n                    .end();\n        }\n\n        @Override\n        public void writeToParcel(@NonNull Parcel dest, int flags) {\n            CREATOR.writeToParcel(this, dest, flags);\n        }\n\n        public static final SafeParcelableCreatorAndWriter<TripSummary> CREATOR = findCreator(TripSummary.class);\n    }\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocationhistory/RequestCredentials.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocationhistory;\n\nimport android.accounts.Account;\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport org.microg.gms.utils.ToStringHelper;\n\n\n@SafeParcelable.Class\npublic class RequestCredentials extends AbstractSafeParcelable {\n\n    @Field(1)\n    public Account account;\n    @Field(2)\n    public String function;\n    @Field(3)\n    public String packageName;\n\n    @Constructor\n    public RequestCredentials(@Param(1) Account account, @Param(2) String function, @Param(3) String packageName) {\n        this.account = account;\n        this.function = function;\n        this.packageName = packageName;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<RequestCredentials> CREATOR = findCreator(RequestCredentials.class);\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"RequestCredentials\").field(\"account\", account.name).field(\"function\", function).field(\"packageName\", packageName).end();\n    }\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocationhistory/SemanticLocationEditInputs.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocationhistory;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.semanticlocation.PlaceCandidate;\n\n@SafeParcelable.Class\npublic class SemanticLocationEditInputs extends AbstractSafeParcelable {\n    @Field(1)\n    public final int editType;\n    @Field(2)\n    public final long timestamp;\n    @Field(3)\n    public final PlaceCandidate.Identifier identifier;\n    @Field(4)\n    String s4;\n\n    @Constructor\n    public SemanticLocationEditInputs(@Param(1) int editType, @Param(2) long timestamp, @Param(3) PlaceCandidate.Identifier identifier) {\n        this.editType = editType;\n        this.timestamp = timestamp;\n        this.identifier = identifier;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<SemanticLocationEditInputs> CREATOR = findCreator(SemanticLocationEditInputs.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocationhistory/TimeRangeFilter.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocationhistory;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class TimeRangeFilter extends AbstractSafeParcelable {\n\n    @Field(1)\n    public Long startTime;\n    @Field(2)\n    public Long endTime;\n\n    @Constructor\n    public TimeRangeFilter(@Param(1) Long startTime, @Param(1) Long endTime) {\n        this.startTime = startTime;\n        this.endTime = endTime;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<TimeRangeFilter> CREATOR = findCreator(TimeRangeFilter.class);\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"TimeRangeFilter\").field(\"startTime\", startTime).field(\"endTime\", endTime).end();\n    }\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/semanticlocationhistory/UserLocationProfile.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocationhistory;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.List;\n\n@SafeParcelable.Class\npublic class UserLocationProfile extends AbstractSafeParcelable {\n\n    @Field(1)\n    public List<FrequentPlace> frequentPlaceList;\n    @Field(2)\n    public List<FrequentTrip> frequentTripList;\n    @Field(3)\n    public Persona persona;\n    @Field(4)\n    public long timestamp;\n\n    @Constructor\n    public UserLocationProfile(@Param(1) List<FrequentPlace> frequentPlaceList, @Param(2) List<FrequentTrip> frequentTripList, @Param(3) Persona persona, @Param(4) long timestamp) {\n        this.frequentPlaceList = frequentPlaceList;\n        this.frequentTripList = frequentTripList;\n        this.persona = persona;\n        this.timestamp = timestamp;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<UserLocationProfile> CREATOR = findCreator(UserLocationProfile.class);\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"UserLocationProfile\")\n                .field(\"frequentPlaceList\", frequentPlaceList)\n                .field(\"frequentTripList\", frequentTripList)\n                .field(\"persona\", persona)\n                .field(\"timestamp\", timestamp)\n                .end();\n    }\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/usagereporting/UsageReportingOptInOptions.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.usagereporting;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class UsageReportingOptInOptions extends AutoSafeParcelable {\n    @Field(2)\n    public int optInUsageReporting;\n\n    public static final Creator<UsageReportingOptInOptions> CREATOR = new AutoCreator<>(UsageReportingOptInOptions.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/wallet/GetClientTokenRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.wallet;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class GetClientTokenRequest extends AbstractSafeParcelable {\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<GetClientTokenRequest> CREATOR = findCreator(GetClientTokenRequest.class);\n\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/wallet/GetClientTokenResponse.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.wallet;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class GetClientTokenResponse extends AbstractSafeParcelable {\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<GetClientTokenResponse> CREATOR = findCreator(GetClientTokenResponse.class);\n\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/wallet/IsReadyToPayRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0 AND CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.wallet;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\n\n/**\n * A Parcelable request that can optionally be passed to {@link PaymentsClient#isReadyToPay(IsReadyToPayRequest)} to specify additional filtering criteria for determining if a user is considered ready to pay.\n */\n@PublicApi\npublic class IsReadyToPayRequest extends AutoSafeParcelable {\n    @Field(value = 2, useDirectList = true)\n    private ArrayList<Integer> allowedCardNetworks;\n    @Field(4)\n    private String unknown4;\n    @Field(5)\n    private String unknown5;\n    @Field(value = 6, useDirectList = true)\n    private ArrayList<Integer> allowedPaymentMethods;\n    @Field(7)\n    private boolean existingPaymentMethodRequired;\n    @Field(8)\n    private String json;\n\n    private IsReadyToPayRequest() {\n    }\n\n    private IsReadyToPayRequest(String json) {\n        this.json = json;\n    }\n\n    /**\n     * Constructs {@link IsReadyToPayRequest} from a JSON object serialized as a string.\n     * <p>\n     * To convert back to a JSON object serialized as string use {@link #toJson()}.\n     * <p>\n     * Note that you shouldn't rely on the values returned by getters in {@link IsReadyToPayRequest} as they will not be populated with the data set in the given JSON.\n     * <p>\n     * For the expected format of this JSON, please see <a href=\"https://developers.google.com/pay/api/android/reference/object/IsReadyToPayRequest\">IsReadyToPayRequest object reference documentation</a>.\n     */\n    public static IsReadyToPayRequest fromJson(String isReadyToPayRequestJson) {\n        return new IsReadyToPayRequest(isReadyToPayRequestJson);\n    }\n\n    /**\n     * @return a builder for constructing the {@link IsReadyToPayRequest} object.\n     * @deprecated Use the JSON request format instead, see {@link #fromJson(String)}.\n     */\n    public static IsReadyToPayRequest.Builder newBuilder() {\n        return new IsReadyToPayRequest().new Builder();\n    }\n\n    /**\n     * Returns {@link IsReadyToPayRequest} in JSON format.\n     * <p>\n     * Note that this will be {@code null} if this request was not constructed using {@link #fromJson(String)}.\n     * <p>\n     * For the expected format of this JSON, please see <a href=\"https://developers.google.com/pay/api/android/reference/object/IsReadyToPayRequest\">IsReadyToPayRequest object reference documentation</a>.\n     */\n    public String toJson() {\n        return json;\n    }\n\n    /**\n     * @return the {@link WalletConstants.CardNetwork} that will be used to filter the instruments deemed acceptable by {@link PaymentsClient#isReadyToPay(IsReadyToPayRequest)}. If not explicitly set, the default supported networks will be {@link WalletConstants#CARD_NETWORK_AMEX}, {@link WalletConstants#CARD_NETWORK_DISCOVER}, {@link WalletConstants#CARD_NETWORK_MASTERCARD}, and {@link WalletConstants#CARD_NETWORK_VISA}.\n     * @deprecated Use the JSON request format instead, see {@link #fromJson(String)}.\n     */\n    public ArrayList<Integer> getAllowedCardNetworks() {\n        return allowedCardNetworks;\n    }\n\n    /**\n     * @return the supported payment credential types defined in {@link WalletConstants.PaymentMethod}, or {@code null} if no restrictions were specified.\n     * @deprecated Use the JSON request format instead, see {@link #fromJson(String)}.\n     */\n    public ArrayList<Integer> getAllowedPaymentMethods() {\n        return allowedPaymentMethods;\n    }\n\n    /**\n     * @return whether or not IsReadyToPay will be determined by the user having an existing payment method that matches the other criteria specified in the IsReadyToPayRequest.\n     * @deprecated Use the JSON request format instead, see {@link #fromJson(String)}.\n     */\n    public boolean isExistingPaymentMethodRequired() {\n        return existingPaymentMethodRequired;\n    }\n\n    /**\n     * Builder for creating an {@link IsReadyToPayRequest}.\n     *\n     * @deprecated Use the JSON request format instead, see {@link #fromJson(String)}.\n     */\n    public class Builder {\n        /**\n         * Adds a card network for cards allowed in the purchase. See {@link WalletConstants.CardNetwork} for available options. If not explicitly set via this or {@link #addAllowedCardNetworks(Collection)}, the default supported networks will be {@link WalletConstants#CARD_NETWORK_AMEX}, {@link WalletConstants#CARD_NETWORK_DISCOVER}, {@link WalletConstants#CARD_NETWORK_MASTERCARD}, and {@link WalletConstants#CARD_NETWORK_VISA}.\n         */\n        public Builder addAllowedCardNetwork(int allowedCardNetwork) {\n            if (allowedCardNetworks == null) allowedCardNetworks = new ArrayList<>();\n            allowedCardNetworks.add(allowedCardNetwork);\n            return this;\n        }\n\n        /**\n         * Adds a collection of card networks for cards allowed in the purchase. See {@link WalletConstants.CardNetwork} for available options. If not explicitly set via this or {@link #addAllowedCardNetwork(int)}, the default supported networks will be {@link WalletConstants#CARD_NETWORK_AMEX}, {@link WalletConstants#CARD_NETWORK_DISCOVER}, {@link WalletConstants#CARD_NETWORK_MASTERCARD}, and {@link WalletConstants#CARD_NETWORK_VISA}.\n         */\n        public Builder addAllowedCardNetworks(Collection<Integer> allowedCardNetworks) {\n            if (IsReadyToPayRequest.this.allowedCardNetworks == null)\n                IsReadyToPayRequest.this.allowedCardNetworks = new ArrayList<>();\n            IsReadyToPayRequest.this.allowedCardNetworks.addAll(allowedCardNetworks);\n            return this;\n        }\n\n        /**\n         * Adds an allowed payment method. See {@link WalletConstants.PaymentMethod} for available options. If not explicitly set via this or {@link #addAllowedPaymentMethods(Collection)}, then the default allowed payment method will be {@link WalletConstants#PAYMENT_METHOD_TOKENIZED_CARD}.\n         */\n        public Builder addAllowedPaymentMethod(int allowedPaymentMethod) {\n            if (allowedPaymentMethods == null) allowedPaymentMethods = new ArrayList<>();\n            allowedPaymentMethods.add(allowedPaymentMethod);\n            return this;\n        }\n\n        /**\n         * Adds a collection of allowed payment methods. See {@link WalletConstants.PaymentMethod} for available options. If not explicitly set via this or {@link #addAllowedPaymentMethod(int)}, then the default allowed payment method will be {@link WalletConstants#PAYMENT_METHOD_TOKENIZED_CARD}.\n         */\n        public Builder addAllowedPaymentMethods(Collection<Integer> allowedPaymentMethods) {\n            if (IsReadyToPayRequest.this.allowedPaymentMethods == null)\n                IsReadyToPayRequest.this.allowedPaymentMethods = new ArrayList<>();\n            IsReadyToPayRequest.this.allowedPaymentMethods.addAll(allowedPaymentMethods);\n            return this;\n        }\n\n        /**\n         * @return The actual {@link IsReadyToPayRequest} created using the data passed to the Builder object.\n         */\n        public IsReadyToPayRequest build() {\n            return IsReadyToPayRequest.this;\n        }\n\n        /**\n         * If set to true, then IsReadyToPay will only return true if the user has an existing payment method that matches the other criteria specified in the IsReadyToPayRequest.\n         * <p>\n         * If you set this to true, make sure to call {@link PaymentsClient#isReadyToPay(IsReadyToPayRequest)} as early as possible in your flow as the call may take longer to resolve due to the extra check for an existing payment method.\n         */\n        public Builder setExistingPaymentMethodRequired(boolean existingPaymentMethodRequired) {\n            IsReadyToPayRequest.this.existingPaymentMethodRequired = existingPaymentMethodRequired;\n            return this;\n        }\n    }\n\n    public static final Creator<IsReadyToPayRequest> CREATOR = new AutoCreator<>(IsReadyToPayRequest.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/wallet/IsReadyToPayResponse.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.wallet;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class IsReadyToPayResponse extends AutoSafeParcelable {\n    @Field(1)\n    public boolean result;\n    @Field(2)\n    public String json;\n\n    private IsReadyToPayResponse() {\n    }\n\n    public IsReadyToPayResponse(boolean result, String json) {\n        this.result = result;\n        this.json = json;\n    }\n\n    public static final Creator<IsReadyToPayResponse> CREATOR = new AutoCreator<>(IsReadyToPayResponse.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/android/gms/wallet/WalletConstants.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0 AND CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.wallet;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Collection of constant values used by the ClientLibrary.\n */\n@PublicApi\npublic class WalletConstants {\n    /**\n     * Credit card networks. Different APIs may support only a subset of these.\n     * <p>\n     * Available options:\n     * <ul>\n     * <li>{@link #CARD_NETWORK_AMEX}</li>\n     * <li>{@link #CARD_NETWORK_DISCOVER}</li>\n     * <li>{@link #CARD_NETWORK_JCB}</li>\n     * <li>{@link #CARD_NETWORK_MASTERCARD}</li>\n     * <li>{@link #CARD_NETWORK_VISA}</li>\n     * <li>{@link #CARD_NETWORK_INTERAC}</li>\n     * <li>{@link #CARD_NETWORK_OTHER}</li>\n     * </ul>\n     * When used with Google Pay, the following networks use EMV cryptograms instead of 3DS cryptograms as part of the payment credentials:\n     * <ul>\n     * <li>{@link #CARD_NETWORK_INTERAC}</li>\n     * </ul>\n     */\n    public @interface CardNetwork {\n        /**\n         * @deprecated Use {@link #CARD_NETWORK_AMEX} instead.\n         */\n        int AMEX = 1;\n        /**\n         * @deprecated Use {@link #CARD_NETWORK_DISCOVER} instead.\n         */\n        int DISCOVER = 2;\n        /**\n         * @deprecated Use {@link #CARD_NETWORK_JCB} instead.\n         */\n        int JCB = 3;\n        /**\n         * @deprecated Use {@link #CARD_NETWORK_MASTERCARD} instead.\n         */\n        int MASTERCARD = 4;\n        /**\n         * @deprecated Use {@link #CARD_NETWORK_VISA} instead.\n         */\n        int VISA = 5;\n        /**\n         * @deprecated Use {@link #CARD_NETWORK_INTERAC} instead.\n         */\n        int INTERAC = 6;\n        /**\n         * @deprecated Use {@link #CARD_NETWORK_OTHER} instead.\n         */\n        int OTHER = 1000;\n    }\n\n    /**\n     * The payment methods you support.\n     * <p>\n     * Available options:\n     * <ul>\n     * <li>{@link #PAYMENT_METHOD_UNKNOWN}</li>\n     * <li>{@link #PAYMENT_METHOD_CARD}</li>\n     * <li>{@link #PAYMENT_METHOD_TOKENIZED_CARD}</li>\n     * </ul>\n     * Note {@link WalletConstants.PaymentMethod} is different from {@link PaymentMethodTokenizationType}, which identifies how you want to receive the returned payment credential.\n     */\n    public @interface PaymentMethod {\n    }\n\n    /**\n     * Payment method tokenization types.\n     * <p>\n     * Available options:\n     * <ul>\n     * <li>{@link #PAYMENT_METHOD_TOKENIZATION_TYPE_PAYMENT_GATEWAY}</li>\n     * <li>{@link #PAYMENT_METHOD_TOKENIZATION_TYPE_NETWORK_TOKEN}</li>\n     * <li>{@link #PAYMENT_METHOD_TOKENIZATION_TYPE_DIRECT}</li>\n     * </ul>\n     * Integrator can configure {@link PaymentDataRequest} to tokenize the credit card selected by the buyer for a transaction using one of the tokenization types listed above. The token for the selected payment method can be retrieved by calling {@link PaymentData#getPaymentMethodToken()}.\n     */\n    public @interface PaymentMethodTokenizationType {\n    }\n\n\n    public static final int CARD_CLASS_CREDIT = 1;\n    public static final int CARD_CLASS_DEBIT = 2;\n    public static final int CARD_CLASS_PREPAID = 3;\n    public static final int CARD_CLASS_UNKNOWN = 0;\n\n    public static final int CARD_NETWORK_AMEX = 1;\n    public static final int CARD_NETWORK_DISCOVER = 2;\n    public static final int CARD_NETWORK_INTERAC = 6;\n    public static final int CARD_NETWORK_JCB = 3;\n    public static final int CARD_NETWORK_MASTERCARD = 4;\n    public static final int CARD_NETWORK_OTHER = 1000;\n    public static final int CARD_NETWORK_VISA = 5;\n\n    public static final int PAYMENT_METHOD_CARD = 1;\n    public static final int PAYMENT_METHOD_TOKENIZED_CARD = 2;\n    public static final int PAYMENT_METHOD_UNKNOWN = 0;\n\n\n    public static final int PAYMENT_METHOD_TOKENIZATION_TYPE_DIRECT = 3;\n    public static final int PAYMENT_METHOD_TOKENIZATION_TYPE_NETWORK_TOKEN = 2;\n    public static final int PAYMENT_METHOD_TOKENIZATION_TYPE_PAYMENT_GATEWAY = 1;\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/firebase/database/connection/idl/CompoundHashParcelable.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.firebase.database.connection.idl;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class CompoundHashParcelable extends AutoSafeParcelable {\n    public static final Creator<CompoundHashParcelable> CREATOR = new AutoCreator<CompoundHashParcelable>(CompoundHashParcelable.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/firebase/database/connection/idl/ConnectionConfig.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.firebase.database.connection.idl;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class ConnectionConfig extends AutoSafeParcelable {\n    public static final Creator<ConnectionConfig> CREATOR = new AutoCreator<ConnectionConfig>(ConnectionConfig.class);\n}\n"
  },
  {
    "path": "play-services-api/src/main/java/com/google/firebase/database/connection/idl/RangeParcelable.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.firebase.database.connection.idl;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class RangeParcelable extends AutoSafeParcelable {\n    public static final Creator<RangeParcelable> CREATOR = new AutoCreator<RangeParcelable>(RangeParcelable.class);\n}\n"
  },
  {
    "path": "play-services-appinvite/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2019 e Foundation\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\n\ngroup = 'org.microg'\n\nandroid {\n    namespace \"com.google.android.gms.appinvite\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n}\n\ndependencies {\n    // Dependencies from play-services-appinvite:18.0.0\n    api project(':play-services-base')\n    api project(':play-services-basement')\n    api project(':play-services-tasks')\n//    api project(':firebase-analytics')\n    api project(':firebase-dynamic-links')\n}\n"
  },
  {
    "path": "play-services-appinvite/core/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'com.squareup.wire'\napply plugin: 'kotlin-android'\n\ndependencies {\n    api project(':play-services-appinvite')\n    implementation project(':play-services-base-core')\n\n    implementation \"androidx.appcompat:appcompat:$appcompatVersion\"\n\n    implementation \"com.android.volley:volley:$volleyVersion\"\n    implementation \"com.squareup.wire:wire-runtime:$wireVersion\"\n}\n\nandroid {\n    namespace \"org.microg.gms.appinvite\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    sourceSets {\n        main.java.srcDirs += 'src/main/kotlin'\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n\n    kotlinOptions {\n        jvmTarget = 1.8\n    }\n}\n\nwire {\n    kotlin {}\n}\n"
  },
  {
    "path": "play-services-appinvite/core/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <application>\n        <service\n            android:name=\"org.microg.gms.appinivite.AppInviteService\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.appinvite.service.START\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </service>\n\n        <activity\n            android:name=\"org.microg.gms.appinivite.AppInviteActivity\"\n            android:excludeFromRecents=\"true\"\n            android:process=\":ui\"\n            android:exported=\"true\"\n            android:theme=\"@style/Theme.AppCompat.Light.Dialog.NoActionBar\">\n            <intent-filter\n                android:priority=\"900\"\n                android:autoVerify=\"true\">\n                <action android:name=\"android.intent.action.VIEW\" />\n                <action android:name=\"android.nfc.action.NDEF_DISCOVERED\" />\n\n                <category android:name=\"android.intent.category.BROWSABLE\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n\n                <data android:scheme=\"https\" />\n                <data android:scheme=\"http\" />\n                <data android:host=\"*.app.goo.gl\" />\n                <data android:pathPrefix=\"/\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"com.google.firebase.dynamiclinks.VIEW_DYNAMIC_LINK\" />\n\n                <category android:name=\"android.intent.category.BROWSABLE\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n\n                <data android:scheme=\"https\" />\n                <data android:scheme=\"http\" />\n            </intent-filter>\n        </activity>\n    </application>\n</manifest>\n"
  },
  {
    "path": "play-services-appinvite/core/src/main/kotlin/org/microg/gms/appinivite/AppInviteActivity.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.appinivite\n\nimport android.content.Intent\nimport android.net.Uri\nimport android.os.Bundle\nimport android.util.Log\nimport android.view.ViewGroup\nimport android.view.Window\nimport android.widget.ProgressBar\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.core.content.pm.PackageInfoCompat\nimport androidx.core.os.bundleOf\nimport androidx.core.view.setPadding\nimport androidx.lifecycle.lifecycleScope\nimport com.android.volley.toolbox.Volley\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableSerializer\nimport com.google.firebase.dynamiclinks.internal.DynamicLinkData\nimport org.microg.gms.appinvite.MutateAppInviteLinkResponse\nimport org.microg.gms.appinivite.utils.DynamicLinkUtils\nimport org.microg.gms.utils.singleInstanceOf\n\nprivate const val TAG = \"AppInviteActivity\"\n\nprivate const val APPINVITE_DEEP_LINK = \"com.google.android.gms.appinvite.DEEP_LINK\"\nprivate const val APPINVITE_INVITATION_ID = \"com.google.android.gms.appinvite.INVITATION_ID\"\nprivate const val APPINVITE_OPENED_FROM_PLAY_STORE = \"com.google.android.gms.appinvite.OPENED_FROM_PLAY_STORE\"\nprivate const val APPINVITE_REFERRAL_BUNDLE = \"com.google.android.gms.appinvite.REFERRAL_BUNDLE\"\nprivate const val DYNAMIC_LINK_DATA = \"com.google.firebase.dynamiclinks.DYNAMIC_LINK_DATA\"\n\nclass AppInviteActivity : AppCompatActivity() {\n    private val queue by lazy { singleInstanceOf { Volley.newRequestQueue(applicationContext) } }\n\n    private val Int.px: Int get() = (this * resources.displayMetrics.density).toInt()\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        requestWindowFeature(Window.FEATURE_NO_TITLE)\n        setContentView(ProgressBar(this).apply {\n            layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)\n            setPadding(20.px)\n            isIndeterminate = true\n        })\n        val extras = intent.extras\n        extras?.keySet()\n        Log.d(TAG, \"Intent: $intent $extras\")\n        if (intent?.data == null) return finish()\n        lifecycleScope.launchWhenStarted {\n            val response = DynamicLinkUtils.requestLinkResponse(intent.data.toString(), queue) ?: return@launchWhenStarted redirectToBrowser()\n            open(response)\n        }\n    }\n\n    private fun redirectToBrowser() {\n        try {\n            startActivity(Intent(Intent.ACTION_VIEW).apply {\n                addCategory(Intent.CATEGORY_DEFAULT)\n                data = intent.data\n            })\n        } catch (e: Exception) {\n            Log.w(TAG, e)\n        }\n        finish()\n    }\n\n    private fun open(appInviteLink: MutateAppInviteLinkResponse) {\n        val minAppVersion = appInviteLink.data_?.app?.minAppVersion\n        val dynamicLinkData = DynamicLinkData(appInviteLink.metadata?.info?.url, appInviteLink.data_?.intentData,\n            (minAppVersion ?: 0).toInt(), System.currentTimeMillis(), null, null)\n        val linkPackageName = appInviteLink.data_?.packageName\n        val intent = Intent(Intent.ACTION_VIEW).apply {\n            addCategory(Intent.CATEGORY_DEFAULT)\n            data = appInviteLink.data_?.intentData?.let { Uri.parse(it) }\n            `package` = linkPackageName\n            flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP\n            putExtra(\n                APPINVITE_REFERRAL_BUNDLE, bundleOf(\n                    APPINVITE_DEEP_LINK to appInviteLink,\n                    APPINVITE_INVITATION_ID to \"\",\n                    APPINVITE_OPENED_FROM_PLAY_STORE to false\n                )\n            )\n            putExtra(DYNAMIC_LINK_DATA, SafeParcelableSerializer.serializeToBytes(dynamicLinkData))\n        }\n        val fallbackIntent = Intent(Intent.ACTION_VIEW).apply {\n            addCategory(Intent.CATEGORY_DEFAULT)\n            data = appInviteLink.data_?.fallbackUrl?.let { Uri.parse(it) }\n        }\n        val installedVersionCode = runCatching {\n            if (linkPackageName != null) {\n                PackageInfoCompat.getLongVersionCode(packageManager.getPackageInfo(linkPackageName, 0))\n            } else {\n                null\n            }\n        }.getOrNull()\n        if (installedVersionCode != null && (minAppVersion == null || installedVersionCode >= minAppVersion)) {\n            val componentName = intent.resolveActivity(packageManager)\n            if (componentName == null) {\n                Log.w(TAG, \"open resolve activity is null\")\n                if (linkPackageName != null) {\n                    val intentLaunch =\n                        packageManager.getLaunchIntentForPackage(linkPackageName)\n                    if (intentLaunch != null) {\n                        intent.setComponent(intentLaunch.component)\n                    }\n                }\n            }\n            startActivity(intent)\n            finish()\n        } else {\n            try {\n                startActivity(fallbackIntent)\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n            }\n            finish()\n        }\n    }\n}"
  },
  {
    "path": "play-services-appinvite/core/src/main/kotlin/org/microg/gms/appinivite/AppInviteService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2019 e Foundation\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage org.microg.gms.appinivite\n\nimport android.app.Activity\nimport android.content.Context\nimport android.os.Bundle\nimport android.os.Parcel\nimport android.os.RemoteException\nimport android.util.Log\nimport com.google.android.gms.appinvite.internal.IAppInviteCallbacks\nimport com.google.android.gms.appinvite.internal.IAppInviteService\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.common.PackageUtils\nimport org.microg.gms.utils.warnOnTransactionIssues\n\nprivate const val TAG = \"AppInviteService\"\n\nclass AppInviteService : BaseService(TAG, GmsService.APP_INVITE) {\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        PackageUtils.getAndCheckCallingPackage(this, request.packageName)\n        callback.onPostInitComplete(0, AppInviteServiceImpl(this, request.packageName, request.extras), null)\n    }\n}\n\n\nclass AppInviteServiceImpl(context: Context?, packageName: String?, extras: Bundle?) : IAppInviteService.Stub() {\n    override fun updateInvitationOnInstall(callback: IAppInviteCallbacks, invitationId: String) {\n        callback.onStatus(Status.SUCCESS)\n    }\n\n    override fun convertInvitation(callback: IAppInviteCallbacks, invitationId: String) {\n        callback.onStatus(Status.SUCCESS)\n    }\n\n    override fun getInvitation(callback: IAppInviteCallbacks) {\n        callback.onStatusIntent(Status(Activity.RESULT_CANCELED), null)\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n}\n"
  },
  {
    "path": "play-services-appinvite/core/src/main/kotlin/org/microg/gms/appinivite/utils/DynamicLinkUtils.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.appinivite.utils\n\nimport android.content.Context\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.LocaleList\nimport com.android.volley.NetworkResponse\nimport com.android.volley.ParseError\nimport com.android.volley.Request\nimport com.android.volley.Request.Method.POST\nimport com.android.volley.RequestQueue\nimport com.android.volley.Response\nimport com.android.volley.VolleyError\nimport com.android.volley.toolbox.HttpHeaderParser\nimport com.android.volley.toolbox.JsonRequest\nimport com.squareup.wire.Message\nimport com.squareup.wire.ProtoAdapter\nimport kotlinx.coroutines.CompletableDeferred\nimport okio.ByteString.Companion.decodeHex\nimport org.json.JSONException\nimport org.json.JSONObject\nimport org.microg.gms.appinvite.ClientIdInfo\nimport org.microg.gms.appinvite.ClientPlatform\nimport org.microg.gms.appinvite.LinkInfo\nimport org.microg.gms.appinvite.MutateAppInviteLinkRequest\nimport org.microg.gms.appinvite.MutateAppInviteLinkResponse\nimport org.microg.gms.appinvite.MutateDataRequest\nimport org.microg.gms.appinvite.MutateDataResponseWithError\nimport org.microg.gms.appinvite.MutateOperation\nimport org.microg.gms.appinvite.MutateOperationId\nimport org.microg.gms.appinvite.SystemInfo\nimport org.microg.gms.common.Constants\nimport org.microg.gms.utils.digest\nimport org.microg.gms.utils.getCertificates\nimport org.microg.gms.utils.toHexString\nimport java.io.UnsupportedEncodingException\nimport java.nio.charset.Charset\nimport java.util.HashMap\nimport java.util.Locale\nimport kotlin.collections.firstOrNull\nimport kotlin.coroutines.resume\nimport kotlin.coroutines.resumeWithException\nimport kotlin.coroutines.suspendCoroutine\n\nobject DynamicLinkUtils {\n\n    suspend fun requestLinkResponse(linkUrl: String, queue: RequestQueue): MutateAppInviteLinkResponse? {\n        val request = ProtobufPostRequest(\n            \"https://datamixer-pa.googleapis.com/v1/mutateonekey?alt=proto&key=AIzaSyAP-gfH3qvi6vgHZbSYwQ_XHqV_mXHhzIk\", MutateOperation(\n                id = MutateOperationId.AppInviteLink, mutateRequest = MutateDataRequest(\n                    appInviteLink = MutateAppInviteLinkRequest(\n                        client = ClientIdInfo(\n                            platform = ClientPlatform.Android,\n                            packageName = Constants.GMS_PACKAGE_NAME,\n                            signature = Constants.GMS_PACKAGE_SIGNATURE_SHA1.decodeHex().base64(),\n                            language = Locale.getDefault().language\n                        ), link = LinkInfo(\n                            invitationId = \"\", uri = linkUrl\n                        ), system = SystemInfo(\n                            gms = SystemInfo.GmsInfo(\n                                versionCode = Constants.GMS_VERSION_CODE\n                            )\n                        )\n                    )\n                )\n            ), MutateDataResponseWithError.ADAPTER\n        )\n        val response = try {\n            request.sendAndAwait(queue)\n        } catch (e: Exception) {\n            return null\n        }\n        if (response.errorStatus != null || response.dataResponse?.appInviteLink == null) return null\n        return response.dataResponse?.appInviteLink\n    }\n\n    suspend fun requestShortLinks(context: Context, packageName: String, apiKey: String, longDynamicLink: String, queue: RequestQueue) = suspendCoroutine<JSONObject> { con ->\n        queue.add(object : JsonRequest<JSONObject>(POST, \"https://firebasedynamiclinks.googleapis.com/v1/shortLinks?key=$apiKey\", JSONObject().apply {\n            put(\"longDynamicLink\", longDynamicLink)\n        }.toString(), {\n            con.resume(it)\n        }, {\n            con.resumeWithException(RuntimeException(it))\n        }) {\n            override fun parseNetworkResponse(response: NetworkResponse): Response<JSONObject> {\n                return try {\n                    val jsonString = String(response.data, Charset.forName(HttpHeaderParser.parseCharset(response.headers, PROTOCOL_CHARSET)))\n                    Response.success(JSONObject(jsonString), null)\n                } catch (e: UnsupportedEncodingException) {\n                    Response.error(ParseError(e))\n                } catch (je: JSONException) {\n                    Response.error(ParseError(je))\n                }\n            }\n\n            override fun getHeaders(): Map<String, String?> = mapOf(\n                \"X-Android-Package\" to packageName,\n                \"X-Android-Cert\" to context.packageManager.getCertificates(packageName).firstOrNull()?.digest(\"SHA1\")?.toHexString()?.uppercase()\n            )\n        })\n    }\n}\n\ninternal class ProtobufPostRequest<I : Message<I, *>, O>(url: String, private val i: I, private val oAdapter: ProtoAdapter<O>) : Request<O>(Method.POST, url, null) {\n    private val deferred = CompletableDeferred<O>()\n\n    override fun getHeaders(): Map<String, String> {\n        val headers = HashMap(super.getHeaders())\n        headers[\"Accept-Language\"] = if (SDK_INT >= 24) LocaleList.getDefault().toLanguageTags() else Locale.getDefault().language\n        headers[\"X-Android-Package\"] = Constants.GMS_PACKAGE_NAME\n        headers[\"X-Android-Cert\"] = Constants.GMS_PACKAGE_SIGNATURE_SHA1\n        return headers\n    }\n\n    override fun getBody(): ByteArray = i.encode()\n\n    override fun getBodyContentType(): String = \"application/x-protobuf\"\n\n    override fun parseNetworkResponse(response: NetworkResponse): Response<O> {\n        return try {\n            Response.success(oAdapter.decode(response.data), null)\n        } catch (e: VolleyError) {\n            Response.error(e)\n        } catch (e: Exception) {\n            Response.error(VolleyError())\n        }\n    }\n\n    override fun deliverResponse(response: O) {\n        deferred.complete(response)\n    }\n\n    override fun deliverError(error: VolleyError) {\n        deferred.completeExceptionally(error)\n    }\n\n    suspend fun await(): O = deferred.await()\n\n    suspend fun sendAndAwait(queue: RequestQueue): O {\n        queue.add(this)\n        return await()\n    }\n}"
  },
  {
    "path": "play-services-appinvite/core/src/main/proto/datamixer.proto",
    "content": "syntax = \"proto2\";\noption java_package = \"org.microg.gms.appinvite\";\n\nenum ClientPlatform {\n    Android = 1;\n    IOS = 2;\n}\n\nmessage ClientIdInfo {\n    optional ClientPlatform platform = 1;\n    optional string packageName = 3; // e.g. com.google.android.gms\n    optional string signature = 4; // Signing certificate sha-1 base64 with padding, e.g. WOHEEz90Qew9LCcCcKFIAtpHug4=\n    optional string language = 6; // e.g. en\n}\n\nmessage LinkInfo {\n    optional string invitationId = 1; // e.g. \"\"\n    optional string uri = 2;\n}\n\nmessage SystemInfo {\n    message GmsInfo {\n        optional uint32 versionCode = 1; // 212423054\n    }\n    optional GmsInfo gms = 1;\n}\n\nmessage MutateAppInviteLinkRequest {\n    optional ClientIdInfo client = 1;\n    optional LinkInfo link = 4;\n    optional SystemInfo system = 5;\n}\n\nmessage MutateDataRequest {\n    oneof request {\n        MutateAppInviteLinkRequest appInviteLink = 84453462;\n    }\n}\n\nmessage AppInviteLinkInfo {\n    optional int32 type = 1;\n    optional string url = 2;\n    optional string name = 3;\n}\n\nmessage AppInviteAppData {\n    optional string packageName = 1; // apn\n    optional uint64 minAppVersion = 2; // amv\n    optional string altPackageName = 3; //apn\n}\n\nmessage AppInviteLinkData {\n    optional string fallbackUrl = 1; // afl\n    optional string packageName = 2; // apn\n    optional string intentData = 3; // link\n    optional AppInviteAppData app = 6;\n}\n\nmessage AppInviteLinkMetadata {\n    optional string source = 2; // utm_source\n    optional string medium = 3; // utm_medium\n    optional string campaign = 4; // utm_campaign\n    optional string id = 5;\n    optional string appCode = 6;\n    optional AppInviteLinkInfo info = 8;\n    optional string sessionId = 9;\n    optional string domainUriPrefix = 10;\n    optional string content = 11; // utm_content\n    optional string term = 12; // utm_term\n}\n\nmessage MutateAppInviteLinkResponse {\n    optional AppInviteLinkData data = 1;\n    optional AppInviteLinkMetadata metadata = 4;\n}\n\nmessage MutateDataResponse {\n    oneof response {\n        MutateAppInviteLinkResponse appInviteLink = 84453462;\n    }\n}\n\nenum MutateOperationId {\n    AppInviteLink = 84453462;\n}\n\nmessage MutateOperation {\n    optional MutateOperationId id = 1; // 84453462\n    optional MutateDataRequest mutateRequest = 2;\n}\n\nmessage StatusProto {\n    optional int32 code = 1;\n}\n\nmessage MutateDataResponseWithError {\n    optional MutateDataResponse dataResponse = 1;\n    optional StatusProto errorStatus = 2;\n}"
  },
  {
    "path": "play-services-appinvite/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2019 e Foundation\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<manifest />\n"
  },
  {
    "path": "play-services-appinvite/src/main/aidl/com/google/android/gms/appinvite/internal/IAppInviteCallbacks.aidl",
    "content": "package com.google.android.gms.appinvite.internal;\n\n\nimport com.google.android.gms.common.api.Status;\nimport android.content.Intent;\n\n\ninterface IAppInviteCallbacks {\n    void onStatus(in Status status) = 0;\n    void onStatusIntent(in Status status, in Intent intent) = 1;\n}\n"
  },
  {
    "path": "play-services-appinvite/src/main/aidl/com/google/android/gms/appinvite/internal/IAppInviteService.aidl",
    "content": "package com.google.android.gms.appinvite.internal;\n\n\nimport com.google.android.gms.appinvite.internal.IAppInviteCallbacks;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.common.api.Status;\n\n\ninterface IAppInviteService {\n    void updateInvitationOnInstall(IAppInviteCallbacks callback, String invitationId) = 0;\n    void convertInvitation(IAppInviteCallbacks callback, String invitationId) = 1;\n    void getInvitation(IAppInviteCallbacks callback) = 2;\n}\n"
  },
  {
    "path": "play-services-appset/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\n\nandroid {\n    namespace \"com.google.android.gms.appset\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n}\n\ndescription = 'microG implementation of play-services-appset'\n\ndependencies {\n    api project(':play-services-base')\n    api project(':play-services-basement')\n\n    annotationProcessor project(':safe-parcel-processor')\n}\n"
  },
  {
    "path": "play-services-appset/core/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'kotlin-android'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\ndependencies {\n    api project(':play-services-appset')\n\n    implementation project(':play-services-base-core')\n\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion\"\n    implementation \"org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutineVersion\"\n    implementation \"org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutineVersion\"\n}\n\nandroid {\n    namespace \"org.microg.gms.appset.core\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    sourceSets {\n        main {\n            java.srcDirs = ['src/main/kotlin']\n        }\n    }\n\n    lintOptions {\n        disable 'MissingTranslation'\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n\n    kotlinOptions {\n        jvmTarget = 1.8\n    }\n}\n\n// Nothing to publish yet\n//apply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG service implementation for play-services-appset'\n"
  },
  {
    "path": "play-services-appset/core/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2024 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <application>\n\n        <service android:name=\"org.microg.gms.appset.AppSetService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.appset.service.START\" />\n            </intent-filter>\n        </service>\n    </application>\n</manifest>\n"
  },
  {
    "path": "play-services-appset/core/src/main/kotlin/org/microg/gms/appset/AppSetService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.appset\n\nimport android.util.Log\nimport com.google.android.gms.appset.AppSetIdInfo\nimport com.google.android.gms.appset.AppSetIdRequestParams\nimport com.google.android.gms.appset.AppSetInfoParcel\nimport com.google.android.gms.appset.internal.IAppSetIdCallback\nimport com.google.android.gms.appset.internal.IAppSetService\nimport com.google.android.gms.common.ConnectionResult\nimport com.google.android.gms.common.Feature\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.internal.ConnectionInfo\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\nimport java.util.UUID\n\nprivate const val TAG = \"AppSetService\"\nprivate val FEATURES = arrayOf(Feature(\"app_set_id\", 1L))\n\nclass AppSetService : BaseService(TAG, GmsService.APP_SET_ID) {\n\n    override fun handleServiceRequest(callback: IGmsCallbacks?, request: GetServiceRequest?, service: GmsService?) {\n        callback?.onPostInitCompleteWithConnectionInfo(\n            ConnectionResult.SUCCESS,\n            AppSetServiceImpl().asBinder(),\n            ConnectionInfo().apply { features = FEATURES }\n        )\n    }\n}\n\nclass AppSetServiceImpl : IAppSetService.Stub() {\n    override fun getAppSetIdInfo(params: AppSetIdRequestParams?, callback: IAppSetIdCallback?) {\n        Log.d(TAG, \"AppSetServiceImp getAppSetIdInfo is called -> ${params?.toString()} \")\n        callback?.onAppSetInfo(Status.SUCCESS, AppSetInfoParcel(UUID.randomUUID().toString(), AppSetIdInfo.SCOPE_APP))\n    }\n}\n"
  },
  {
    "path": "play-services-appset/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n</manifest>\n"
  },
  {
    "path": "play-services-appset/src/main/aidl/com/google/android/gms/appset/AppSetIdRequestParams.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.appset;\n\nparcelable AppSetIdRequestParams;\n"
  },
  {
    "path": "play-services-appset/src/main/aidl/com/google/android/gms/appset/AppSetInfoParcel.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.appset;\n\nparcelable AppSetInfoParcel;\n"
  },
  {
    "path": "play-services-appset/src/main/aidl/com/google/android/gms/appset/internal/IAppSetIdCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.appset.internal;\n\nimport com.google.android.gms.appset.AppSetInfoParcel;\nimport com.google.android.gms.common.api.Status;\n\ninterface IAppSetIdCallback {\n    void onAppSetInfo(in Status status, in AppSetInfoParcel info) = 0;\n}"
  },
  {
    "path": "play-services-appset/src/main/aidl/com/google/android/gms/appset/internal/IAppSetService.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.appset.internal;\n\nimport com.google.android.gms.appset.AppSetIdRequestParams;\nimport com.google.android.gms.appset.internal.IAppSetIdCallback;\n\ninterface IAppSetService {\n    void getAppSetIdInfo(in AppSetIdRequestParams params, in IAppSetIdCallback callback) = 0;\n}\n"
  },
  {
    "path": "play-services-appset/src/main/java/com/google/android/gms/appset/AppSet.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.appset;\n\nimport android.content.Context;\nimport androidx.annotation.NonNull;\n\n/**\n * Entry point of the app set APIs.\n */\npublic class AppSet {\n    /**\n     * Creates a new instance of {@link AppSetIdClient}.\n     */\n    @NonNull\n    public static AppSetIdClient getClient (Context context) {\n        throw new UnsupportedOperationException();\n    }\n}\n"
  },
  {
    "path": "play-services-appset/src/main/java/com/google/android/gms/appset/AppSetIdClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.appset;\n\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.tasks.Task;\n\n/**\n * A client for interacting with the {@link AppSetIdInfo} API.\n */\npublic interface AppSetIdClient {\n    /**\n     * Gets the AppSetIdInfo asynchronously.\n     *\n     * @return a {@link Task} of the returned {@link AppSetIdInfo}.\n     */\n    @NonNull\n    Task<AppSetIdInfo> getAppSetIdInfo();\n}\n"
  },
  {
    "path": "play-services-appset/src/main/java/com/google/android/gms/appset/AppSetIdInfo.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.appset;\n\nimport androidx.annotation.IntDef;\nimport org.microg.gms.common.Hide;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Contains information about app set ID.\n */\npublic class AppSetIdInfo {\n    /**\n     * The app set ID is scoped to the app.\n     */\n    public static final int SCOPE_APP = 1;\n    /**\n     * The app set ID is scoped to a developer account on an app store. All apps from the same developer on a device will have\n     * the same developer scoped app set ID.\n     */\n    public static final int SCOPE_DEVELOPER = 2;\n\n    private final String id;\n    private final @Scope int scope;\n\n    @Hide\n    public AppSetIdInfo(String id, @Scope int scope) {\n        this.id = id;\n        this.scope = scope;\n    }\n\n    /**\n     * Gets the app set ID.\n     *\n     * @return the app set ID.\n     */\n    public String getId() {\n        return id;\n    }\n\n    /**\n     * Returns the {@link AppSetIdInfo.Scope} of the app set ID. Possible values include {@link #SCOPE_APP} and {@link #SCOPE_DEVELOPER}.\n     *\n     * @return the app set ID's {@link AppSetIdInfo.Scope}.\n     */\n    public @Scope int getScope() {\n        return scope;\n    }\n\n    /**\n     * Allowed constants for {@link AppSetIdInfo#getScope()}.\n     * <p>\n     * Supported constants:\n     * <ul>\n     *     <li>{@link #SCOPE_APP}</li>\n     *     <li>{@link #SCOPE_DEVELOPER}</li>\n     * </ul>\n     */\n    @Target({ElementType.TYPE_USE})\n    @Retention(RetentionPolicy.SOURCE)\n    @IntDef({SCOPE_APP, SCOPE_DEVELOPER})\n    public @interface Scope {\n\n    }\n}\n"
  },
  {
    "path": "play-services-appset/src/main/java/com/google/android/gms/appset/AppSetIdRequestParams.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.appset;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\n@Hide\npublic class AppSetIdRequestParams extends AbstractSafeParcelable {\n    @Field(1)\n    public final String version;\n    @Field(2)\n    public final String clientAppPackageName;\n\n    @Constructor\n    public AppSetIdRequestParams(@Param(1) String version, @Param(2) String clientAppPackageName) {\n        this.version = version;\n        this.clientAppPackageName = clientAppPackageName;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"AppSetIdRequestParams\").field(\"version\", version).field(\"clientAppPackageName\", clientAppPackageName).end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<AppSetIdRequestParams> CREATOR = findCreator(AppSetIdRequestParams.class);\n}\n"
  },
  {
    "path": "play-services-appset/src/main/java/com/google/android/gms/appset/AppSetInfoParcel.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.appset;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\n\n@SafeParcelable.Class\n@Hide\npublic class AppSetInfoParcel extends AbstractSafeParcelable {\n    @Field(1)\n    public final String id;\n    @Field(2)\n    public final int scope;\n\n    @Constructor\n    public AppSetInfoParcel(@Param(1) String id, @Param(2) int scope) {\n        this.id = id;\n        this.scope = scope;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<AppSetInfoParcel> CREATOR = findCreator(AppSetInfoParcel.class);\n\n}\n"
  },
  {
    "path": "play-services-appset/src/main/java/com/google/android/gms/appset/package-info.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n/**\n * For analytics or fraud prevention use cases, on a given device you may\n          need to correlate usage or actions across a set of apps owned by your organization.\n */\npackage com.google.android.gms.appset;\n"
  },
  {
    "path": "play-services-auth/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\nandroid {\n    namespace \"com.google.android.gms.auth.api\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n}\n\napply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG implementation of play-services-auth'\n\ndependencies {\n    // Dependencies from play-services-auth:21.4.0\n    api \"androidx.fragment:fragment:1.5.7\"\n    api \"androidx.loader:loader:1.1.0\"\n    api project(':play-services-auth-api-phone')\n    api project(':play-services-auth-base')\n    api project(':play-services-base')\n    api project(':play-services-basement')\n    api project(':play-services-fido')\n    api project(':play-services-tasks')\n\n    annotationProcessor project(':safe-parcel-processor')\n}\n"
  },
  {
    "path": "play-services-auth/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest />"
  },
  {
    "path": "play-services-auth/src/main/aidl/com/google/android/gms/auth/account/data/IAccountDataService.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.account.data;\n\nimport com.google.android.gms.auth.account.data.IDeviceManagementInfoCallback;\nimport android.accounts.Account;\nimport com.google.android.gms.common.api.internal.IStatusCallback;\n\ninterface IAccountDataService {\n    void requestDeviceManagementInfo(in IDeviceManagementInfoCallback callback, in Account account) = 0;\n    void requestAccountInfo(in IStatusCallback callback, in Account account, boolean isPrimary) = 1;\n    void requestProfileInfo(in IStatusCallback callback, String profile) = 2;\n}\n"
  },
  {
    "path": "play-services-auth/src/main/aidl/com/google/android/gms/auth/account/data/IDeviceManagementInfoCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.account.data;\n\nimport com.google.android.gms.auth.firstparty.dataservice.DeviceManagementInfoResponse;\nimport com.google.android.gms.common.api.Status;\n\ninterface IDeviceManagementInfoCallback {\n    void onResult(in Status status, in DeviceManagementInfoResponse response);\n}\n"
  },
  {
    "path": "play-services-auth/src/main/aidl/com/google/android/gms/auth/api/credentials/Credential.aidl",
    "content": "package com.google.android.gms.auth.api.credentials;\n\nparcelable Credential;"
  },
  {
    "path": "play-services-auth/src/main/aidl/com/google/android/gms/auth/api/credentials/CredentialRequest.aidl",
    "content": "package com.google.android.gms.auth.api.credentials;\n\nparcelable CredentialRequest;"
  },
  {
    "path": "play-services-auth/src/main/aidl/com/google/android/gms/auth/api/credentials/internal/DeleteRequest.aidl",
    "content": "package com.google.android.gms.auth.api.credentials.internal;\n\nparcelable DeleteRequest;"
  },
  {
    "path": "play-services-auth/src/main/aidl/com/google/android/gms/auth/api/credentials/internal/GeneratePasswordRequest.aidl",
    "content": "package com.google.android.gms.auth.api.credentials.internal;\n\nparcelable GeneratePasswordRequest;"
  },
  {
    "path": "play-services-auth/src/main/aidl/com/google/android/gms/auth/api/credentials/internal/ICredentialsCallbacks.aidl",
    "content": "package com.google.android.gms.auth.api.credentials.internal;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.auth.api.credentials.Credential;\n\ninterface ICredentialsCallbacks {\n    void onStatusAndCredential(in Status status, in Credential credential) = 0;\n    void onStatus(in Status status) = 1;\n    void onStatusAndString(in Status status, String string) = 2;\n}"
  },
  {
    "path": "play-services-auth/src/main/aidl/com/google/android/gms/auth/api/credentials/internal/ICredentialsService.aidl",
    "content": "package com.google.android.gms.auth.api.credentials.internal;\n\nimport com.google.android.gms.auth.api.credentials.CredentialRequest;\nimport com.google.android.gms.auth.api.credentials.internal.ICredentialsCallbacks;\nimport com.google.android.gms.auth.api.credentials.internal.DeleteRequest;\nimport com.google.android.gms.auth.api.credentials.internal.GeneratePasswordRequest;\nimport com.google.android.gms.auth.api.credentials.internal.SaveRequest;\n\ninterface ICredentialsService {\n    void request(ICredentialsCallbacks callbacks, in CredentialRequest request) = 0;\n    void save(ICredentialsCallbacks callbacks, in SaveRequest request) = 1;\n    void delete(ICredentialsCallbacks callbacks, in DeleteRequest request) = 2;\n    void disableAutoSignIn(ICredentialsCallbacks callbacks) = 3;\n    void generatePassword(ICredentialsCallbacks callbacks, in GeneratePasswordRequest request) = 4;\n}"
  },
  {
    "path": "play-services-auth/src/main/aidl/com/google/android/gms/auth/api/credentials/internal/SaveRequest.aidl",
    "content": "package com.google.android.gms.auth.api.credentials.internal;\n\nparcelable SaveRequest;"
  },
  {
    "path": "play-services-auth/src/main/aidl/com/google/android/gms/auth/api/identity/AuthorizationRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.api.identity;\n\nparcelable AuthorizationRequest;"
  },
  {
    "path": "play-services-auth/src/main/aidl/com/google/android/gms/auth/api/identity/AuthorizationResult.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.api.identity;\n\nparcelable AuthorizationResult;"
  },
  {
    "path": "play-services-auth/src/main/aidl/com/google/android/gms/auth/api/identity/BeginSignInRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.api.identity;\n\nparcelable BeginSignInRequest;"
  },
  {
    "path": "play-services-auth/src/main/aidl/com/google/android/gms/auth/api/identity/BeginSignInResult.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.api.identity;\n\nparcelable BeginSignInResult;"
  },
  {
    "path": "play-services-auth/src/main/aidl/com/google/android/gms/auth/api/identity/ClearTokenRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.api.identity;\n\nparcelable ClearTokenRequest;"
  },
  {
    "path": "play-services-auth/src/main/aidl/com/google/android/gms/auth/api/identity/GetPhoneNumberHintIntentRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.api.identity;\n\nparcelable GetPhoneNumberHintIntentRequest;"
  },
  {
    "path": "play-services-auth/src/main/aidl/com/google/android/gms/auth/api/identity/GetSignInIntentRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.api.identity;\n\nparcelable GetSignInIntentRequest;"
  },
  {
    "path": "play-services-auth/src/main/aidl/com/google/android/gms/auth/api/identity/RevokeAccessRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.api.identity;\n\nparcelable RevokeAccessRequest;"
  },
  {
    "path": "play-services-auth/src/main/aidl/com/google/android/gms/auth/api/identity/SignInCredential.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.api.identity;\n\nparcelable SignInCredential;"
  },
  {
    "path": "play-services-auth/src/main/aidl/com/google/android/gms/auth/api/identity/VerifyWithGoogleRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.api.identity;\n\nparcelable VerifyWithGoogleRequest;"
  },
  {
    "path": "play-services-auth/src/main/aidl/com/google/android/gms/auth/api/identity/VerifyWithGoogleResult.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.api.identity;\n\nparcelable VerifyWithGoogleResult;"
  },
  {
    "path": "play-services-auth/src/main/aidl/com/google/android/gms/auth/api/identity/internal/IAuthorizationCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.api.identity.internal;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.auth.api.identity.AuthorizationResult;\n\ninterface IAuthorizationCallback {\n    void onAuthorized(in Status status, in AuthorizationResult result);\n}"
  },
  {
    "path": "play-services-auth/src/main/aidl/com/google/android/gms/auth/api/identity/internal/IAuthorizationService.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.api.identity.internal;\n\nimport com.google.android.gms.auth.api.identity.internal.IAuthorizationCallback;\nimport com.google.android.gms.auth.api.identity.internal.IVerifyWithGoogleCallback;\nimport com.google.android.gms.auth.api.identity.AuthorizationRequest;\nimport com.google.android.gms.auth.api.identity.VerifyWithGoogleRequest;\nimport com.google.android.gms.auth.api.identity.RevokeAccessRequest;\nimport com.google.android.gms.auth.api.identity.ClearTokenRequest;\nimport com.google.android.gms.common.api.internal.IStatusCallback;\n\ninterface IAuthorizationService {\n    void authorize(in IAuthorizationCallback callback, in AuthorizationRequest request) = 0;\n    void verifyWithGoogle(in IVerifyWithGoogleCallback callback, in VerifyWithGoogleRequest request) = 1;\n    void revokeAccess(in IStatusCallback callback, in RevokeAccessRequest request) = 2;\n    void clearToken(in IStatusCallback callback, in ClearTokenRequest request) = 3;\n}"
  },
  {
    "path": "play-services-auth/src/main/aidl/com/google/android/gms/auth/api/identity/internal/IBeginSignInCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.api.identity.internal;\n\nimport com.google.android.gms.auth.api.identity.BeginSignInResult;\nimport com.google.android.gms.common.api.Status;\n\ninterface IBeginSignInCallback {\n    void onResult(in Status status, in BeginSignInResult beginSignInResult);\n}"
  },
  {
    "path": "play-services-auth/src/main/aidl/com/google/android/gms/auth/api/identity/internal/IGetPhoneNumberHintIntentCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.api.identity.internal;\n\nimport com.google.android.gms.common.api.Status;\n\ninterface IGetPhoneNumberHintIntentCallback {\n    void onResult(in Status status, in PendingIntent pendingIntent);\n}"
  },
  {
    "path": "play-services-auth/src/main/aidl/com/google/android/gms/auth/api/identity/internal/IGetSignInIntentCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.api.identity.internal;\n\nimport com.google.android.gms.common.api.Status;\n\ninterface IGetSignInIntentCallback {\n    void onResult(in Status status, in PendingIntent pendingIntent);\n}"
  },
  {
    "path": "play-services-auth/src/main/aidl/com/google/android/gms/auth/api/identity/internal/ISignInService.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.api.identity.internal;\n\nimport com.google.android.gms.common.api.internal.IStatusCallback;\nimport com.google.android.gms.auth.api.identity.internal.IBeginSignInCallback;\nimport com.google.android.gms.auth.api.identity.internal.IGetSignInIntentCallback;\nimport com.google.android.gms.auth.api.identity.internal.IGetPhoneNumberHintIntentCallback;\nimport com.google.android.gms.auth.api.identity.BeginSignInRequest;\nimport com.google.android.gms.auth.api.identity.GetSignInIntentRequest;\nimport com.google.android.gms.auth.api.identity.GetPhoneNumberHintIntentRequest;\n\ninterface ISignInService {\n    void beginSignIn(in IBeginSignInCallback callback, in BeginSignInRequest request) = 0;\n    void signOut(in IStatusCallback callback, String userId) = 1;\n    void getSignInIntent(in IGetSignInIntentCallback callback, in GetSignInIntentRequest request) = 2;\n    void getPhoneNumberHintIntent(in IGetPhoneNumberHintIntentCallback callback, in GetPhoneNumberHintIntentRequest request) = 3;\n}"
  },
  {
    "path": "play-services-auth/src/main/aidl/com/google/android/gms/auth/api/identity/internal/IVerifyWithGoogleCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.api.identity.internal;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.auth.api.identity.VerifyWithGoogleResult;\n\ninterface IVerifyWithGoogleCallback {\n    void onVerifed(in Status status, in VerifyWithGoogleResult result);\n}"
  },
  {
    "path": "play-services-auth/src/main/aidl/com/google/android/gms/auth/api/signin/internal/ISignInCallbacks.aidl",
    "content": "package com.google.android.gms.auth.api.signin.internal;\n\nimport com.google.android.gms.auth.api.signin.GoogleSignInAccount;\nimport com.google.android.gms.common.api.Status;\n\ninterface ISignInCallbacks {\n    void onSignIn(in GoogleSignInAccount account, in Status status) = 100;\n    void onSignOut(in Status status) = 101;\n    void onRevokeAccess(in Status status) = 102;\n}"
  },
  {
    "path": "play-services-auth/src/main/aidl/com/google/android/gms/auth/api/signin/internal/ISignInService.aidl",
    "content": "package com.google.android.gms.auth.api.signin.internal;\n\nimport com.google.android.gms.auth.api.signin.internal.ISignInCallbacks;\nimport com.google.android.gms.auth.api.signin.GoogleSignInOptions;\n\ninterface ISignInService {\n    void silentSignIn(ISignInCallbacks callbacks, in GoogleSignInOptions options) = 100;\n    void signOut(ISignInCallbacks callbacks, in GoogleSignInOptions options) = 101;\n    void revokeAccess(ISignInCallbacks callbacks, in GoogleSignInOptions options) = 102;\n}"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/Auth.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.api;\n\nimport com.google.android.gms.auth.api.signin.GoogleSignInApi;\nimport com.google.android.gms.auth.api.signin.GoogleSignInClient;\nimport com.google.android.gms.auth.api.signin.GoogleSignInOptions;\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport org.microg.gms.auth.api.signin.GoogleSignInApiImpl;\nimport org.microg.gms.auth.api.signin.GoogleSignInGmsClientImpl;\n\n/**\n * Entry point for Google Auth APIs through GoogleApiClient.\n */\npublic class Auth {\n    /**\n     * Token to pass to {@link GoogleApiClient.Builder#addApi(Api)} to enable the Google Sign In API.\n     */\n    public static final Api<GoogleSignInOptions> GOOGLE_SIGN_IN_API = new Api<>((options, context, looper, clientSettings, callbacks, connectionFailedListener) -> new GoogleSignInGmsClientImpl(context, callbacks, connectionFailedListener));\n\n    /**\n     * Api entry point for Google Sign In.\n     */\n    public static final GoogleSignInApi GoogleSignInApi = new GoogleSignInApiImpl();\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/credentials/Credential.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2016, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.api.credentials;\n\nimport android.net.Uri;\nimport android.text.TextUtils;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Locale;\n\n@PublicApi\npublic class Credential extends AutoSafeParcelable {\n\n    @Field(1000)\n    private int versionCode = 1;\n\n    @Field(1)\n    private String id;\n    @Field(2)\n    private String name;\n    @Field(3)\n    private Uri profilePictureUri;\n    @Field(value = 4, subClass = IdToken.class)\n    private List<IdToken> tokens;\n    @Field(5)\n    private String password;\n    @Field(6)\n    private String accountType;\n    @Field(7)\n    private String generatedPassword;\n\n    private Credential() {\n    }\n\n    /**\n     * Returns the type of federated identity account used to sign in the user. While this may be\n     * any string, it is strongly recommended that values from {@link com.google.android.gms.auth.api.credentials.IdentityProviders}\n     * are used, which are the login domains for common identity providers.\n     *\n     * @return A string identifying the federated identity provider associated with this account,\n     * typically in the form of the identity provider's login domain. null will be returned if the\n     * credential is a password credential.\n     */\n    public String getAccountType() {\n        return accountType;\n    }\n\n    /**\n     * Returns the generated password for an account hint.\n     */\n    public String getGeneratedPassword() {\n        return generatedPassword;\n    }\n\n    /**\n     * Returns the credential identifier, typically an email address or user name, though it may\n     * also be some encoded unique identifier for a federated identity account.\n     */\n    public String getId() {\n        return id;\n    }\n\n    /**\n     * Returns the ID tokens that assert the identity of the user, if available. ID tokens provide\n     * a secure mechanism to verify that the user owns the identity asserted by the credential.\n     * <p/>\n     * This is useful for account hints, where the ID token can replace the need to separately\n     * verify that the user owns their claimed email address - with a valid ID token, it is not\n     * necessary to send an account activation link to the address, simplifying the account\n     * creation process for the user.\n     * <p/>\n     * A signed ID token is returned automatically for credential hints when the credential ID is a\n     * Google account that is authenticated on the device. This ID token can be sent along with\n     * your application's account creation operation, where the signature can be verified.\n     */\n    public List<IdToken> getIdTokens() {\n        return tokens;\n    }\n\n    /**\n     * Returns the display name of the credential, if available. Typically, the display name will\n     * be the name of the user, or some other string which the user can easily recognize and\n     * distinguish from other accounts they may have.\n     */\n    public String getName() {\n        return name;\n    }\n\n    /**\n     * Returns the password used to sign in the user.\n     */\n    public String getPassword() {\n        return password;\n    }\n\n    /**\n     * Returns the URL to an image of the user, if available.\n     */\n    public Uri getProfilePictureUri() {\n        return profilePictureUri;\n    }\n\n    @PublicApi(exclude = true)\n    public String getAsString() {\n        if (TextUtils.isEmpty(accountType)) {\n            return id.toLowerCase(Locale.US) + \"|\";\n        } else {\n            Uri uri = Uri.parse(accountType);\n            return id.toLowerCase(Locale.US) + \"|\" + (TextUtils.isEmpty(uri.getScheme()) ? \"\" : uri.getScheme().toLowerCase(Locale.US)) + \"://\" +\n                    (TextUtils.isEmpty(uri.getHost()) ? \"unknown\" : uri.getHost().toLowerCase(Locale.US)) + \":\" + uri.getPort();\n        }\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || !(o instanceof Credential)) return false;\n\n        Credential that = (Credential) o;\n\n        if (id != null ? !id.equals(that.id) : that.id != null) return false;\n        if (name != null ? !name.equals(that.name) : that.name != null) return false;\n        if (profilePictureUri != null ? !profilePictureUri.equals(that.profilePictureUri) : that.profilePictureUri != null)\n            return false;\n        if (password != null ? !password.equals(that.password) : that.password != null)\n            return false;\n        if (accountType != null ? !accountType.equals(that.accountType) : that.accountType != null)\n            return false;\n        return generatedPassword != null ? generatedPassword.equals(that.generatedPassword) : that.generatedPassword == null;\n\n    }\n\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(new Object[]{id, name, profilePictureUri, password, accountType, generatedPassword});\n    }\n\n    public static class Builder {\n        private String id;\n        private String name;\n        private Uri profilePictureUri;\n        private String password;\n        private String accountType;\n\n        @PublicApi(exclude = true)\n        public List<IdToken> tokens;\n        @PublicApi(exclude = true)\n        private String generatedPassword;\n\n        public Builder(String id) {\n            this.id = id;\n        }\n\n        /**\n         * Copies the information stored in an existing credential, in order to allow that information to be modified.\n         *\n         * @param credential the existing credential\n         */\n        public Builder(Credential credential) {\n            this.id = credential.id;\n            this.name = credential.name;\n            this.profilePictureUri = credential.profilePictureUri;\n            this.password = credential.password;\n            this.accountType = credential.accountType;\n            this.tokens = credential.tokens;\n            this.generatedPassword = credential.generatedPassword;\n        }\n\n        public Credential build() {\n            Credential credential = new Credential();\n            credential.id = id;\n            credential.name = name;\n            credential.profilePictureUri = profilePictureUri;\n            credential.password = password;\n            credential.accountType = accountType;\n            credential.tokens = tokens;\n            credential.generatedPassword = generatedPassword;\n            return credential;\n        }\n\n        /**\n         * Specifies the account type for a federated credential. The value should be set to\n         * identity provider's login domain, such as \"https://accounts.google.com\" for Google\n         * accounts. The login domains for common identity providers are listed in {@link IdentityProviders}.\n         *\n         * @param accountType The type of the account. Typically, one of the values in {@link IdentityProviders}.\n         */\n        public Builder setAccountType(String accountType) {\n            this.accountType = accountType;\n            return this;\n        }\n\n        /**\n         * Sets the display name for the credential, which should be easy for the user to recognize\n         * as associated to the credential, and distinguishable from other credentials they may\n         * have. This string will be displayed more prominently than, or instead of, the account ID\n         * whenever available. In most cases, the name of the user is sufficient.\n         */\n        public Builder setName(String name) {\n            this.name = name;\n            return this;\n        }\n\n        /**\n         * Sets the password for the credential. Either the password or the account type must be\n         * set for a credential, but not both.\n         */\n        public Builder setPassword(String password) {\n            this.password = password;\n            return this;\n        }\n\n        /**\n         * Sets a profile picture associated with the credential, typically a picture the user has\n         * selected to represent the account.\n         */\n        public Builder setProfilePictureUri(Uri profilePictureUri) {\n            this.profilePictureUri = profilePictureUri;\n            return this;\n        }\n    }\n\n    public static final Creator<Credential> CREATOR = new AutoCreator<Credential>(Credential.class);\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/credentials/CredentialPickerConfig.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2016, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.api.credentials;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\n@PublicApi\npublic class CredentialPickerConfig extends AutoSafeParcelable {\n\n    @Field(1000)\n    private int versionCode = 1;\n\n    @Field(1)\n    private boolean showAddAccountButton;\n    @Field(2)\n    private boolean showCancelButton;\n    @Field(3)\n    private boolean forNewAccount;\n\n    private CredentialPickerConfig() {\n    }\n\n    public CredentialPickerConfig(boolean showAddAccountButton, boolean showCancelButton, boolean forNewAccount) {\n        this.showAddAccountButton = showAddAccountButton;\n        this.showCancelButton = showCancelButton;\n        this.forNewAccount = forNewAccount;\n    }\n\n    /**\n     * @deprecated It was determined that this method was not useful for developers.\n     */\n    @Deprecated\n    public boolean isForNewAccount() {\n        return forNewAccount;\n    }\n\n    public boolean shouldShowAddAccountButton() {\n        return showAddAccountButton;\n    }\n\n    public boolean shouldShowCancelButton() {\n        return showCancelButton;\n    }\n\n    @Override\n    public String toString() {\n        return \"CredentialPickerConfig{\" +\n                \"showAddAccountButton=\" + showAddAccountButton +\n                \", showCancelButton=\" + showCancelButton +\n                '}';\n    }\n\n    public class Builder {\n        private boolean showAddAccountButton;\n        private boolean showCancelButton;\n        private boolean forNewAccount;\n\n        public CredentialPickerConfig build() {\n            return new CredentialPickerConfig(showAddAccountButton, showCancelButton, forNewAccount);\n        }\n\n        /**\n         * Sets whether the hint request is for a new account sign-up flow.\n         */\n        public Builder setForNewAccount(boolean forNewAccount) {\n            this.forNewAccount = forNewAccount;\n            return this;\n        }\n\n        /**\n         * Sets whether the add account button should be shown in credential picker dialog.\n         */\n        public Builder setShowAddAccountButton(boolean showAddAccountButton) {\n            this.showAddAccountButton = showAddAccountButton;\n            return this;\n        }\n\n        /**\n         * Sets whether the cancel button should be shown in credential picker dialog.\n         */\n        public Builder setShowCancelButton(boolean showCancelButton) {\n            this.showCancelButton = showCancelButton;\n            return this;\n        }\n    }\n\n    public static final Creator<CredentialPickerConfig> CREATOR = new AutoCreator<CredentialPickerConfig>(CredentialPickerConfig.class);\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/credentials/CredentialRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2016, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.api.credentials;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\n/**\n * Parameters for requesting a Credential, via Auth.CredentialsApi.request(). Instances can be\n * created using CredentialRequest.Builder.\n */\npublic class CredentialRequest extends AutoSafeParcelable {\n\n    @Field(1000)\n    private int versionCode = 1;\n\n    @Field(1)\n    private boolean passwordLoginSupported;\n    @Field(2)\n    private String[] accountTypes;\n    @Field(3)\n    private CredentialPickerConfig credentialPickerConfig;\n    @Field(4)\n    private CredentialPickerConfig credentialHintPickerConfig;\n\n    private CredentialRequest() { }\n\n    public CredentialRequest(boolean passwordLoginSupported, String[] accountTypes, CredentialPickerConfig credentialPickerConfig, CredentialPickerConfig credentialHintPickerConfig) {\n        this.passwordLoginSupported = passwordLoginSupported;\n        this.accountTypes = accountTypes;\n        this.credentialPickerConfig = credentialPickerConfig;\n        this.credentialHintPickerConfig = credentialHintPickerConfig;\n    }\n\n    public String[] getAccountTypes() {\n        return accountTypes;\n    }\n\n    public CredentialPickerConfig getCredentialHintPickerConfig() {\n        return credentialHintPickerConfig;\n    }\n\n    public CredentialPickerConfig getCredentialPickerConfig() {\n        return credentialPickerConfig;\n    }\n\n    /**\n     * @deprecated Use {@link #isPasswordLoginSupported()}\n     */\n    @Deprecated\n    public boolean getSupportsPasswordLogin() {\n        return isPasswordLoginSupported();\n    }\n\n    public boolean isPasswordLoginSupported() {\n        return passwordLoginSupported;\n    }\n\n    public static final Creator<CredentialRequest> CREATOR = new AutoCreator<CredentialRequest>(CredentialRequest.class);\n\n    public static class Builder {\n        private boolean passwordLoginSupported;\n        private String[] accountTypes;\n        private CredentialPickerConfig credentialPickerConfig;\n        private CredentialPickerConfig credentialHintPickerConfig;\n\n        public void setAccountTypes(String... accountTypes) {\n            this.accountTypes = accountTypes.clone();\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/credentials/HintRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.api.credentials;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\nimport java.util.Arrays;\n\n/**\n * Parameters for requesting the display of the hint picker, via {@link CredentalsApi#getHintPickerIntent()}.\n * Instances can be created using {@link HintRequest.Builder}.\n */\n@PublicApi\npublic class HintRequest extends AutoSafeParcelable {\n    @Field(1000)\n    private int versionCode = 2;\n\n    @Field(1)\n    private CredentialPickerConfig hintPickerConfig;\n    @Field(2)\n    private boolean emailAddressIdentifierSupported;\n    @Field(3)\n    private boolean phoneNumberIdentifierSupported;\n    @Field(4)\n    private String[] accountTypes;\n    @Field(5)\n    private boolean idTokenRequested = true;\n    @Field(6)\n    private String serverClientId;\n    @Field(7)\n    private String idTokenNonce;\n\n    private HintRequest() {\n    }\n\n    public HintRequest(CredentialPickerConfig hintPickerConfig, boolean emailAddressIdentifierSupported, boolean phoneNumberIdentifierSupported, String[] accountTypes, boolean idTokenRequested, String serverClientId, String idTokenNonce) {\n        this.hintPickerConfig = hintPickerConfig;\n        this.emailAddressIdentifierSupported = emailAddressIdentifierSupported;\n        this.phoneNumberIdentifierSupported = phoneNumberIdentifierSupported;\n        this.accountTypes = accountTypes;\n        this.idTokenRequested = idTokenRequested;\n        this.serverClientId = serverClientId;\n        this.idTokenNonce = idTokenNonce;\n    }\n\n    public String[] getAccountTypes() {\n        return accountTypes;\n    }\n\n    public CredentialPickerConfig getHintPickerConfig() {\n        return hintPickerConfig;\n    }\n\n    public String getIdTokenNonce() {\n        return idTokenNonce;\n    }\n\n    public String getServerClientId() {\n        return serverClientId;\n    }\n\n    public boolean isEmailAddressIdentifierSupported() {\n        return emailAddressIdentifierSupported;\n    }\n\n    public boolean isPhoneNumberIdentifierSupported() {\n        return phoneNumberIdentifierSupported;\n    }\n\n    public boolean isIdTokenRequested() {\n        return idTokenRequested;\n    }\n\n    public static final Creator<HintRequest> CREATOR = new AutoCreator<>(HintRequest.class);\n\n    @Override\n    public String toString() {\n        return \"HintRequest{\" +\n                \"hintPickerConfig=\" + hintPickerConfig +\n                \", emailAddressIdentifierSupported=\" + emailAddressIdentifierSupported +\n                \", phoneNumberIdentifierSupported=\" + phoneNumberIdentifierSupported +\n                \", accountTypes=\" + Arrays.toString(accountTypes) +\n                \", idTokenRequested=\" + idTokenRequested +\n                \", serverClientId='\" + serverClientId + '\\'' +\n                \", idTokenNonce='\" + idTokenNonce + '\\'' +\n                '}';\n    }\n\n    public static class Builder {\n        private CredentialPickerConfig hintPickerConfig;\n        private boolean emailAddressIdentifierSupported;\n        private boolean phoneNumberIdentifierSupported;\n        private String[] accountTypes;\n        private boolean idTokenRequested = true;\n        private String serverClientId;\n        private String idTokenNonce;\n\n        /**\n         * Builds a {@link HintRequest}.\n         */\n        public HintRequest build() {\n            return new HintRequest(hintPickerConfig, emailAddressIdentifierSupported, phoneNumberIdentifierSupported, accountTypes, idTokenRequested, serverClientId, idTokenNonce);\n        }\n\n        /**\n         * Sets the account types (identity providers) that are accepted by this application.\n         * It is strongly recommended that the strings listed in {@link IdentityProviders} be used for the most common\n         * identity providers, and strings representing the login domain of the identity provider be used for any\n         * others which are not listed.\n         *\n         * @param accountTypes The list of account types (identity providers) supported by the app.\n         *                     typically in the form of the associated login domain for each identity provider.\n         */\n        public void setAccountTypes(String... accountTypes) {\n            this.accountTypes = accountTypes.clone();\n        }\n\n        /**\n         * Enables returning {@link Credential} hints where the identifier is an email address, intended for use with a password chosen by the user.\n         */\n        public void setEmailAddressIdentifierSupported(boolean emailAddressIdentifierSupported) {\n            this.emailAddressIdentifierSupported = emailAddressIdentifierSupported;\n        }\n\n        /**\n         * Sets the configuration for the hint picker dialog.\n         */\n        public void setHintPickerConfig(CredentialPickerConfig hintPickerConfig) {\n            this.hintPickerConfig = hintPickerConfig;\n        }\n\n        /**\n         * Specify a nonce value that should be included in any generated ID token for this request.\n         */\n        public void setIdTokenNonce(String idTokenNonce) {\n            this.idTokenNonce = idTokenNonce;\n        }\n\n        /**\n         * Specify whether an ID token should be acquired for hints, if available for the selected credential identifier.\n         * This is enabled by default; disable this if your app does not use ID tokens as part of authentication to decrease latency in retrieving credentials and credential hints.\n         */\n        public void setIdTokenRequested(boolean idTokenRequested) {\n            this.idTokenRequested = idTokenRequested;\n        }\n\n        /**\n         * Enables returning {@link Credential} hints where the identifier is a phone number, intended for use with a password chosen by the user or SMS verification.\n         */\n        public void setPhoneNumberIdentifierSupported(boolean phoneNumberIdentifierSupported) {\n            this.phoneNumberIdentifierSupported = phoneNumberIdentifierSupported;\n        }\n\n        /**\n         * Specify the server client ID for the backend associated with this app.\n         * If a Google ID token can be generated for a retrieved credential or hint, and the specified server client ID is correctly configured to be associated with the app, then it will be used as the audience of the generated token.\n         * If a null value is specified, the default audience will be used for the generated ID token.\n         */\n        public void setServerClientId(String serverClientId) {\n            this.serverClientId = serverClientId;\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/credentials/IdToken.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2016, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.api.credentials;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\n@PublicApi\npublic class IdToken extends AutoSafeParcelable {\n\n    @Field(1000)\n    private int versionCode = 1;\n\n    @Field(1)\n    private String accountType;\n\n    @Field(2)\n    private String id;\n\n    private IdToken() {\n    }\n\n    public IdToken(String accountType, String id) {\n        this.accountType = accountType;\n        this.id = id;\n    }\n\n    /**\n     * Returns {@code AccountManager} account type for the token.\n     */\n    public String getAccountType() {\n        return accountType;\n    }\n\n    /**\n     * Returns the ID token, formatted according to the rules defined by the account type.\n     */\n    public String getIdToken() {\n        return id;\n    }\n\n    public static final Creator<IdToken> CREATOR = new AutoCreator<IdToken>(IdToken.class);\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/credentials/IdentityProviders.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.api.credentials;\n\nimport android.accounts.Account;\n\n/**\n * Identity provider constants for use with {@link CredentialRequest.Builder#setAccountTypes(String...)}\n */\npublic final class IdentityProviders {\n    public static final String FACEBOOK = \"//www.facebook.com\";\n    public static final String GOOGLE = \"//accounts.google.com\";\n    public static final String LINKEDIN = \"//www.linkedin.com\";\n    public static final String MICROSOFT = \"//login.live.com\";\n    public static final String PAYPAL = \"//www.paypal.com\";\n    public static final String TWITTER = \"//twitter.com\";\n    public static final String YAHOO = \"//login.yahoo.com\";\n\n    /**\n     * Attempts to translate the account type in the provided account into the string that should be used in the credentials API.\n     *\n     * @param account an account on the device.\n     * @return The identity provider string for use with the Credentials API, or {@code null} if the account type is unknown.\n     */\n    public static String getIdentityProviderForAccount(Account account) {\n        return null;\n    }\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/credentials/internal/DeleteRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.auth.api.credentials.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class DeleteRequest extends AutoSafeParcelable {\n    public static final Creator<DeleteRequest> CREATOR = new AutoCreator<DeleteRequest>(DeleteRequest.class);\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/credentials/internal/GeneratePasswordRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.auth.api.credentials.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class GeneratePasswordRequest extends AutoSafeParcelable {\n    public static final Creator<GeneratePasswordRequest> CREATOR = new AutoCreator<GeneratePasswordRequest>(GeneratePasswordRequest.class);\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/credentials/internal/SaveRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.auth.api.credentials.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class SaveRequest extends AutoSafeParcelable {\n    public static final Creator<SaveRequest> CREATOR = new AutoCreator<SaveRequest>(SaveRequest.class);\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/credentials/package-info.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n/**\n * Provides facilities to retrieve and save app login credentials.\n */\npackage com.google.android.gms.auth.api.credentials;\n"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/identity/AuthorizationClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.api.identity;\n\nimport android.app.PendingIntent;\nimport android.content.Intent;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.api.ApiException;\nimport com.google.android.gms.common.api.HasApiKey;\nimport com.google.android.gms.tasks.Task;\n\n/**\n * A client for the authorization API.\n */\npublic interface AuthorizationClient extends HasApiKey<AuthorizationOptions> {\n    /**\n     * Requests authorization to access the Google data associated with a signed-in account on the device.\n     * <p>\n     * If an eligible signed-in account is found for the application, this request will verify that all the requested OAuth 2.0 scopes were previously\n     * granted by the user. If they were, the requested tokens will be returned in the result. If, however, no saved account is found or the required\n     * grants do not exist, the result will contain a {@link PendingIntent} that can be used to launch the authorization flow. During that flow, the user will\n     * be asked to select an account and/or grant the permission for all or a subset of requested scopes. An exception will be set on the returned\n     * {@link Task} if authorization is not available on the device (for example, internal error or Play Services not available).\n     *\n     * @param request configuration for the authorization operation.\n     * @return {@link Task} which contains the result of the operation.\n     */\n    @NonNull\n    Task<AuthorizationResult> authorize(@NonNull AuthorizationRequest request);\n\n    /**\n     * Clears an access token from the local cache.\n     *\n     * @param request configuration for the clear token operation.\n     * @return A Task that may be used to check for failure, success or completion\n     */\n    @NonNull\n    Task<Void> clearToken(@NonNull ClearTokenRequest request);\n\n    /**\n     * Retrieves the {@link AuthorizationResult} from the {@link Intent} returned upon successful authorization, throwing an {@link ApiException} if no result is\n     * present or authorization has failed.\n     *\n     * @throws ApiException\n     */\n    @NonNull\n    AuthorizationResult getAuthorizationResultFromIntent(@Nullable Intent intent) throws ApiException;\n\n    /**\n     * Revokes access given to the current application. Future sign-in or authorization attempts will require the user to re-consent to all requested\n     * scopes. Applications are required to provide users that are signed in with Google the ability to disconnect their Google account from the\n     * app. If the user deletes their account, you must delete the information that your app obtained from the Google APIs.\n     *\n     * @param revokeAccessRequest configuration for the revoke authorization operation.\n     * @return A Task that may be used to check for failure, success or completion\n     */\n    @NonNull\n    Task<Void> revokeAccess(@NonNull RevokeAccessRequest revokeAccessRequest);\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/identity/AuthorizationOptions.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.api.identity;\n\nimport com.google.android.gms.common.api.Api;\nimport org.microg.gms.common.Hide;\n\n@Hide\npublic class AuthorizationOptions implements Api.ApiOptions.Optional {\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/identity/AuthorizationRequest.java",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.api.identity;\n\nimport android.accounts.Account;\nimport android.os.Bundle;\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.api.Scope;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport java.util.List;\n\n@SafeParcelable.Class\npublic class AuthorizationRequest extends AbstractSafeParcelable {\n\n    @Field(1)\n    public List<Scope> requestedScopes;\n    @Field(2)\n    public String serverClientId;\n    @Field(3)\n    public boolean serverAuthCodeRequested;\n    @Field(4)\n    public boolean idTokenRequested;\n    @Field(5)\n    public Account account;\n    @Field(6)\n    public String hostedDomainFilter;\n    @Field(7)\n    public String sessionId;\n    @Field(8)\n    public boolean forceCodeForRefreshToken;\n    @Field(9)\n    public Bundle bundle;\n    @Field(10)\n    public boolean offlineAccess;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<AuthorizationRequest> CREATOR = findCreator(AuthorizationRequest.class);\n\n    @Override\n    public String toString() {\n        return \"AuthorizationRequest{\" +\n                \"requestedScopes=\" + requestedScopes +\n                \", serverClientId='\" + serverClientId + '\\'' +\n                \", serverAuthCodeRequested=\" + serverAuthCodeRequested +\n                \", idTokenRequested=\" + idTokenRequested +\n                \", account=\" + account +\n                \", hostedDomainFilter='\" + hostedDomainFilter + '\\'' +\n                \", sessionId='\" + sessionId + '\\'' +\n                \", forceCodeForRefreshToken=\" + forceCodeForRefreshToken +\n                \", bundle=\" + bundle +\n                \", offlineAccess=\" + offlineAccess +\n                '}';\n    }\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/identity/AuthorizationResult.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.api.identity;\n\nimport android.app.PendingIntent;\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.auth.api.signin.GoogleSignInAccount;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.List;\nimport java.util.Objects;\n\n/**\n * Result returned from a request to authorize\n */\n@SafeParcelable.Class\npublic class AuthorizationResult extends AbstractSafeParcelable {\n\n    @Nullable\n    @Field(value = 1, getterName = \"getServerAuthCode\")\n    private final String serverAuthCode;\n    @Nullable\n    @Field(value = 2, getterName = \"getAccessToken\")\n    private final String accessToken;\n    @Nullable\n    @Field(value = 3, getterName = \"getIdToken\")\n    private final String idToken;\n    @NonNull\n    @Field(value = 4, getterName = \"getGrantedScopes\")\n    private final List<String> grantedScopes;\n    @Nullable\n    @Field(value = 5, getterName = \"toGoogleSignInAccount\")\n    private final GoogleSignInAccount googleSignInAccount;\n    @Nullable\n    @Field(value = 6, getterName = \"getPendingIntent\")\n    private final PendingIntent pendingIntent;\n\n    public static final SafeParcelableCreatorAndWriter<AuthorizationResult> CREATOR = findCreator(AuthorizationResult.class);\n\n    @Constructor\n    public AuthorizationResult(@Nullable @Param(1) String serverAuthCode, @Nullable @Param(2) String accessToken, @Nullable @Param(3) String idToken, @NonNull @Param(4) List<String> grantedScopes, @Nullable @Param(5) GoogleSignInAccount googleSignInAccount, @Nullable @Param(6) PendingIntent pendingIntent) {\n        this.serverAuthCode = serverAuthCode;\n        this.accessToken = accessToken;\n        this.idToken = idToken;\n        this.grantedScopes = grantedScopes;\n        this.googleSignInAccount = googleSignInAccount;\n        this.pendingIntent = pendingIntent;\n    }\n\n    @Override\n    public final boolean equals(Object o) {\n        if (!(o instanceof AuthorizationResult)) return false;\n\n        AuthorizationResult that = (AuthorizationResult) o;\n        return Objects.equals(serverAuthCode, that.serverAuthCode) && Objects.equals(accessToken, that.accessToken) && Objects.equals(idToken, that.idToken) && grantedScopes.equals(that.grantedScopes) && Objects.equals(pendingIntent, that.pendingIntent) && Objects.equals(googleSignInAccount, that.googleSignInAccount);\n    }\n\n    /**\n     * Returns the access token.\n     */\n    @Nullable\n    public String getAccessToken() {\n        return accessToken;\n    }\n\n    /**\n     * Returns the list of scopes that user had granted access to.\n     */\n    @NonNull\n    public List<String> getGrantedScopes() {\n        return grantedScopes;\n    }\n\n    @Hide\n    @Nullable\n    public String getIdToken() {\n        return idToken;\n    }\n\n    /**\n     * Returns the {@link PendingIntent} that can be used to launch the authorization flow.\n     */\n    @Nullable\n    public PendingIntent getPendingIntent() {\n        return pendingIntent;\n    }\n\n    /**\n     * Returns the server authorization code that can be exchanged by the server for a refresh token.\n     */\n    @Nullable\n    public String getServerAuthCode() {\n        return serverAuthCode;\n    }\n\n    /**\n     * Returns {@code true} if this result contains a resolution that needs to be launched.\n     * <p>\n     * Please see {@link #getPendingIntent()} for additional context.\n     */\n    public boolean hasResolution() {\n        return pendingIntent != null;\n    }\n\n    /**\n     * Converts this result to an equivalent {@link GoogleSignInAccount} object, if the authorization operation was successful in returning tokens. If,\n     * instead, a {@link PendingIntent} was provided to launch the authorization flow, this will return {@code null}.\n     *\n     * @return a {@link GoogleSignInAccount} object with the same data contained in this result.\n     */\n    @Nullable\n    public GoogleSignInAccount toGoogleSignInAccount() {\n        return googleSignInAccount;\n    }\n\n    @Hide\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"AuthorizationResult\")\n                .field(\"serverAuthCode\", serverAuthCode)\n                .field(\"accessToken\", accessToken)\n                .field(\"idToken\", idToken)\n                .field(\"grantedScopes\", grantedScopes)\n                .field(\"pendingIntent\", pendingIntent)\n                .field(\"googleSignInAccount\", googleSignInAccount)\n                .end();\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hashCode(new Object[]{serverAuthCode, accessToken, idToken, grantedScopes, pendingIntent, googleSignInAccount});\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/identity/BeginSignInRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.api.identity;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.fido.fido2.api.common.PublicKeyCredentialRequestOptions;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Objects;\n\n/**\n * Configurations that can be used to filter acceptable types of credentials returned from a sign-in attempt.\n */\n@SafeParcelable.Class\npublic class BeginSignInRequest extends AbstractSafeParcelable {\n    @Field(value = 1, getterName = \"getPasswordRequestOptions\")\n    private final PasswordRequestOptions passwordRequestOptions;\n    @Field(value = 2, getterName = \"getGoogleIdTokenRequestOptions\")\n    private final GoogleIdTokenRequestOptions googleIdTokenRequestOptions;\n    @Field(value = 3, getterName = \"getSessionId\")\n    private final String sessionId;\n    @Field(value = 4, getterName = \"isAutoSelectEnabled\")\n    private final boolean autoSelectEnabled;\n    @Field(value = 5, getterName = \"getTheme\")\n    private final int theme;\n    @Field(value = 6, getterName = \"getPasskeysRequestOptions\")\n    private final PasskeysRequestOptions passkeysRequestOptions;\n    @Field(value = 7, getterName = \"getPasskeyJsonRequestOptions\")\n    private final PasskeyJsonRequestOptions passkeyJsonRequestOptions;\n    @Field(value = 8, getterName = \"isPreferImmediatelyAvailableCredentials\")\n    private final boolean preferImmediatelyAvailableCredentials;\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"BeginSignInRequest\")\n                .field(\"PasswordRequestOptions\", passwordRequestOptions)\n                .field(\"GoogleIdTokenRequestOptions\", googleIdTokenRequestOptions)\n                .field(\"sessionId\", sessionId)\n                .field(\"autoSelectEnabled\", autoSelectEnabled)\n                .field(\"theme\", theme)\n                .field(\"PasskeysRequestOptions\", passkeysRequestOptions)\n                .field(\"PasskeyJsonRequestOptions\", passkeyJsonRequestOptions)\n                .field(\"preferImmediatelyAvailableCredentials\", preferImmediatelyAvailableCredentials)\n                .end();\n    }\n\n    @Constructor\n    BeginSignInRequest(@Param(1) PasswordRequestOptions passwordRequestOptions, @Param(2) GoogleIdTokenRequestOptions googleIdTokenRequestOptions, @Param(3) String sessionId, @Param(4) boolean autoSelectEnabled, @Param(5) int theme, @Param(6) PasskeysRequestOptions passkeysRequestOptions, @Param(7) PasskeyJsonRequestOptions passkeyJsonRequestOptions, @Param(8) boolean preferImmediatelyAvailableCredentials) {\n        this.passwordRequestOptions = passwordRequestOptions;\n        this.googleIdTokenRequestOptions = googleIdTokenRequestOptions;\n        this.sessionId = sessionId;\n        this.autoSelectEnabled = autoSelectEnabled;\n        this.theme = theme;\n        this.passkeysRequestOptions = passkeysRequestOptions;\n        this.passkeyJsonRequestOptions = passkeyJsonRequestOptions;\n        this.preferImmediatelyAvailableCredentials = preferImmediatelyAvailableCredentials;\n    }\n\n    @NonNull\n    public static Builder builder() {\n        return new Builder();\n    }\n\n    public GoogleIdTokenRequestOptions getGoogleIdTokenRequestOptions() {\n        return googleIdTokenRequestOptions;\n    }\n\n    public PasskeyJsonRequestOptions getPasskeyJsonRequestOptions() {\n        return passkeyJsonRequestOptions;\n    }\n\n    public PasskeysRequestOptions getPasskeysRequestOptions() {\n        return passkeysRequestOptions;\n    }\n\n    public PasswordRequestOptions getPasswordRequestOptions() {\n        return passwordRequestOptions;\n    }\n\n    @Hide\n    public String getSessionId() {\n        return sessionId;\n    }\n\n    @Hide\n    public int getTheme() {\n        return theme;\n    }\n\n    /**\n     * Returns {@code true} if auto-select is requested, {@code false} otherwise.\n     */\n    public boolean isAutoSelectEnabled() {\n        return autoSelectEnabled;\n    }\n\n    public boolean isPreferImmediatelyAvailableCredentials() {\n        return preferImmediatelyAvailableCredentials;\n    }\n\n    public static class Builder {\n\n    }\n\n    /**\n     * Options for requesting Google ID token-backed credentials during sign-in.\n     */\n    @Class\n    public static class GoogleIdTokenRequestOptions extends AbstractSafeParcelable {\n        @Field(value = 1, getterName = \"isSupported\")\n        private final boolean supported;\n        @Field(value = 2, getterName = \"getServerClientId\")\n        private final String serverClientId;\n        @Field(value = 3, getterName = \"getNonce\")\n        private final String nonce;\n        @Field(value = 4, getterName = \"filterByAuthorizedAccounts\")\n        private final boolean filterByAuthorizedAccounts;\n        @Field(value = 5, getterName = \"getLinkedServiceId\")\n        private final String linkedServiceId;\n        @Field(value = 6, getterName = \"getIdTokenDepositionScopes\")\n        private final List<String> idTokenDepositionScopes;\n        @Field(value = 7, getterName = \"requestVerifiedPhoneNumber\")\n        private final boolean requestVerifiedPhoneNumber;\n\n        @NonNull\n        @Override\n        public String toString() {\n            return ToStringHelper.name(\"GoogleIdTokenRequestOptions\")\n                    .field(\"supported\", supported)\n                    .field(\"serverClientId\", serverClientId)\n                    .field(\"nonce\", nonce)\n                    .field(\"filterByAuthorizedAccounts\", filterByAuthorizedAccounts)\n                    .field(\"linkedServiceId\", linkedServiceId)\n                    .field(\"idTokenDepositionScopes\", idTokenDepositionScopes)\n                    .field(\"requestVerifiedPhoneNumber\", requestVerifiedPhoneNumber)\n                    .end();\n        }\n\n        @Hide\n        @Constructor\n        public GoogleIdTokenRequestOptions(@Param(1) boolean supported, @Param(2) String serverClientId, @Param(3) String nonce, @Param(4) boolean filterByAuthorizedAccounts, @Param(5) String linkedServiceId, @Param(6) List<String> idTokenDepositionScopes, @Param(7) boolean requestVerifiedPhoneNumber) {\n            this.supported = supported;\n            this.serverClientId = serverClientId;\n            this.nonce = nonce;\n            this.filterByAuthorizedAccounts = filterByAuthorizedAccounts;\n            this.linkedServiceId = linkedServiceId;\n            this.idTokenDepositionScopes = idTokenDepositionScopes;\n            this.requestVerifiedPhoneNumber = requestVerifiedPhoneNumber;\n        }\n\n        @NonNull\n        public static Builder builder() {\n            return new Builder();\n        }\n\n        public boolean filterByAuthorizedAccounts() {\n            return filterByAuthorizedAccounts;\n        }\n\n        public List<String> getIdTokenDepositionScopes() {\n            return idTokenDepositionScopes;\n        }\n\n        public String getLinkedServiceId() {\n            return linkedServiceId;\n        }\n\n        public String getNonce() {\n            return nonce;\n        }\n\n        public String getServerClientId() {\n            return serverClientId;\n        }\n\n        public boolean isSupported() {\n            return supported;\n        }\n\n        /**\n         * @deprecated No replacement.\n         */\n        @Deprecated\n        public boolean requestVerifiedPhoneNumber() {\n            return requestVerifiedPhoneNumber;\n        }\n\n        /**\n         * Builder for {@link BeginSignInRequest.GoogleIdTokenRequestOptions}.\n         */\n        public static class Builder {\n            private boolean supported;\n            @Nullable\n            private String serverClientId;\n            @Nullable\n            private String nonce;\n            private boolean filterByAuthorizedAccounts = true;\n            @Nullable\n            private String linkedServiceId;\n            @Nullable\n            private List<String> idTokenDepositionScopes;\n            private boolean requestVerifiedPhoneNumber;\n\n            /**\n             * Sets whether to support sign-in using Google accounts that are linked to your users' accounts.\n             * <p>\n             * When such a credential is selected, a Google ID token for the Google account that the selected account is linked to, will\n             * first be deposited to your server and then returned to you. Similar to the regular sign-in, your backend could use the ID\n             * token to sign the user in. Note that, the ID token deposition will only happen the first time signing in, using this credential.\n             * Subsequent sign-ins will not require a deposition, since the ID token will already have been associated with your user's\n             * account.\n             *\n             * @param linkedServiceId         service ID used when linking accounts to a Google account.\n             * @param idTokenDepositionScopes Oauth scopes that Google will need to deposit a Google ID token to your application's backend server. This\n             *                                is optional and can be set to null. Only required if Google requires particular scopes to be able to deposit\n             *                                the ID token.\n             */\n            public Builder associateLinkedAccounts(@NonNull String linkedServiceId, @Nullable List<String> idTokenDepositionScopes) {\n                this.linkedServiceId = linkedServiceId;\n                this.idTokenDepositionScopes = idTokenDepositionScopes;\n                return this;\n            }\n\n            /**\n             * Returns the built {@link BeginSignInRequest.GoogleIdTokenRequestOptions}.\n             */\n            @NonNull\n            public GoogleIdTokenRequestOptions build() {\n                return new GoogleIdTokenRequestOptions(supported, serverClientId, nonce, filterByAuthorizedAccounts, linkedServiceId, idTokenDepositionScopes, requestVerifiedPhoneNumber);\n            }\n\n            /**\n             * Sets whether to only allow the user to select from Google accounts that are already authorized to sign in to your\n             * application. The default value is true.\n             * <p>\n             * If {@code true}, the user will not be able to select any Google account that would otherwise require explicit authorization to\n             * share basic profile/email data with your application. This may reduce some friction in the sign-in user journey, and\n             * guarantees that the returned credential is for a \"returning user\", but limits the user's freedom to choose among all the\n             * Google accounts on the device.\n             *\n             * @param filterByAuthorizedAccounts whether to only allow the user to select from Google accounts that are already authorized to sign in to\n             *                                   your application\n             */\n            @NonNull\n            public Builder setFilterByAuthorizedAccounts(boolean filterByAuthorizedAccounts) {\n                this.filterByAuthorizedAccounts = filterByAuthorizedAccounts;\n                return this;\n            }\n\n            /**\n             * Sets the nonce to use when generating a Google ID token.\n             *\n             * @param nonce the nonce to use during ID token generation\n             */\n            @NonNull\n            public Builder setNonce(@Nullable String nonce) {\n                this.nonce = nonce;\n                return this;\n            }\n\n            /**\n             * Sets whether to request for a verified phone number during sign-ups.\n             * <p>\n             * In order to use this feature, the\n             * {@link BeginSignInRequest.GoogleIdTokenRequestOptions#filterByAuthorizedAccounts()} field must be explicitly set\n             * to false, because this feature is only available during sign-ups.\n             *\n             * @deprecated No replacement.\n             */\n            @Deprecated\n            @NonNull\n            public Builder setRequestVerifiedPhoneNumber(boolean requestVerifiedPhoneNumber) {\n                this.requestVerifiedPhoneNumber = requestVerifiedPhoneNumber;\n                return this;\n            }\n\n            /**\n             * Sets the server's client ID to use as the audience for Google ID tokens generated during the sign-in.\n             *\n             * @param serverClientId the client ID of the server to which the ID token will be issued\n             */\n            @NonNull\n            public Builder setServerClientId(@NonNull String serverClientId) {\n                this.serverClientId = serverClientId;\n                return this;\n            }\n\n            /**\n             * Sets whether Google ID token-backed credentials should be returned by the API.\n             *\n             * @param supported whether Google ID token-backed credentials should be returned\n             */\n            @NonNull\n            public Builder setSupported(boolean supported) {\n                this.supported = supported;\n                return this;\n            }\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (!(o instanceof GoogleIdTokenRequestOptions)) return false;\n\n            GoogleIdTokenRequestOptions that = (GoogleIdTokenRequestOptions) o;\n\n            if (supported != that.supported) return false;\n            if (filterByAuthorizedAccounts != that.filterByAuthorizedAccounts) return false;\n            if (requestVerifiedPhoneNumber != that.requestVerifiedPhoneNumber) return false;\n            if (!Objects.equals(serverClientId, that.serverClientId)) return false;\n            if (!Objects.equals(nonce, that.nonce)) return false;\n            if (!Objects.equals(linkedServiceId, that.linkedServiceId)) return false;\n            return Objects.equals(idTokenDepositionScopes, that.idTokenDepositionScopes);\n        }\n\n        @Override\n        public int hashCode() {\n            return Arrays.hashCode(new Object[]{supported, serverClientId, nonce, filterByAuthorizedAccounts, linkedServiceId, idTokenDepositionScopes, requestVerifiedPhoneNumber});\n        }\n\n        @Override\n        public void writeToParcel(@NonNull Parcel dest, int flags) {\n            CREATOR.writeToParcel(this, dest, flags);\n        }\n\n        public static final SafeParcelableCreatorAndWriter<GoogleIdTokenRequestOptions> CREATOR = findCreator(GoogleIdTokenRequestOptions.class);\n    }\n\n    /**\n     * Options for requesting passkeys during sign-in.\n     */\n    @Class\n    public static class PasskeyJsonRequestOptions extends AbstractSafeParcelable {\n        @Field(value = 1, getterName = \"isSupported\")\n        private final boolean supported;\n        @Field(value = 2, getterName = \"getRequestJson\")\n        private final String requestJson;\n\n        @NonNull\n        @Override\n        public String toString() {\n            return ToStringHelper.name(\"PasskeyJsonRequestOptions\")\n                    .field(\"supported\", supported)\n                    .field(\"requestJson\", requestJson)\n                    .end();\n        }\n\n        @Constructor\n        @Hide\n        public PasskeyJsonRequestOptions(@Param(1) boolean supported, @Param(2) String requestJson) {\n            this.supported = supported;\n            this.requestJson = requestJson;\n        }\n\n        public static Builder builder() {\n            return new Builder();\n        }\n\n        public String getRequestJson() {\n            return requestJson;\n        }\n\n        public boolean isSupported() {\n            return supported;\n        }\n\n        /**\n         * Builder for {@link BeginSignInRequest.PasskeyJsonRequestOptions}.\n         */\n        public static class Builder {\n            private boolean supported;\n            private String requestJson;\n\n            @NonNull\n            public PasskeyJsonRequestOptions build() {\n                return new PasskeyJsonRequestOptions(supported, requestJson);\n            }\n\n            /**\n             * Sets the {@link PublicKeyCredentialRequestOptions} in JSON format.\n             *\n             * @param requestJson the JSON formatted representation of the WebAuthn request.\n             */\n            @NonNull\n            public Builder setRequestJson(@NonNull String requestJson) {\n                this.requestJson = requestJson;\n                return this;\n            }\n\n            /**\n             * Sets whether passkey credentials should be returned by this API.\n             *\n             * @param supported whether passkey credentials should be returned\n             */\n            @NonNull\n            public Builder setSupported(boolean supported) {\n                this.supported = supported;\n                return this;\n            }\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (!(o instanceof PasskeyJsonRequestOptions)) return false;\n\n            PasskeyJsonRequestOptions that = (PasskeyJsonRequestOptions) o;\n\n            if (supported != that.supported) return false;\n            return Objects.equals(requestJson, that.requestJson);\n        }\n\n        @Override\n        public int hashCode() {\n            return Arrays.hashCode(new Object[]{supported, requestJson});\n        }\n\n        @Override\n        public void writeToParcel(@NonNull Parcel dest, int flags) {\n            CREATOR.writeToParcel(this, dest, flags);\n        }\n\n        public static final SafeParcelableCreatorAndWriter<PasskeyJsonRequestOptions> CREATOR = findCreator(PasskeyJsonRequestOptions.class);\n    }\n\n    /**\n     * Options for requesting passkeys during sign-in.\n     *\n     * @deprecated Use {@link BeginSignInRequest.PasskeyJsonRequestOptions} instead.\n     */\n    @Deprecated\n    @Class\n    public static class PasskeysRequestOptions extends AbstractSafeParcelable {\n        @Field(value = 1, getterName = \"isSupported\")\n        private final boolean supported;\n        @Field(value = 2, getterName = \"getChallenge\")\n        private final byte[] challenge;\n        @Field(value = 3, getterName = \"getRpId\")\n        private final String rpId;\n\n        @NonNull\n        @Override\n        public String toString() {\n            return ToStringHelper.name(\"PasskeysRequestOptions\")\n                    .field(\"supported\", supported)\n                    .field(\"challenge\", challenge)\n                    .field(\"rpId\", rpId)\n                    .end();\n        }\n\n        @Constructor\n        @Hide\n        public PasskeysRequestOptions(@Param(1) boolean supported, @Param(2) byte[] challenge, @Param(3) String rpId) {\n            this.supported = supported;\n            this.challenge = challenge;\n            this.rpId = rpId;\n        }\n\n        public static Builder builder() {\n            return new Builder();\n        }\n\n        public byte[] getChallenge() {\n            return challenge;\n        }\n\n        public String getRpId() {\n            return rpId;\n        }\n\n        public boolean isSupported() {\n            return supported;\n        }\n\n        /**\n         * Builder for {@link BeginSignInRequest.PasskeysRequestOptions}.\n         */\n        public static class Builder {\n            private boolean supported;\n            private byte[] challenge;\n            private String rpId;\n\n            public PasskeysRequestOptions build() {\n                return new PasskeysRequestOptions(supported, challenge, rpId);\n            }\n\n            /**\n             * Sets the nonce value that the authenticator should sign using a private key corresponding to a public key credential that\n             * is acceptable for this authentication session.\n             *\n             * @param challenge the challenge\n             */\n            @NonNull\n            public Builder setChallenge(@NonNull byte[] challenge) {\n                this.challenge = challenge;\n                return this;\n            }\n\n            /**\n             * Sets identifier for a relying party, on whose behalf a given authentication operation is being performed. A public key\n             * credential can only be used for authentication with the same replying party it was registered with.\n             * <p>\n             * Note: the RpId should be an effective domain (without scheme or port).\n             *\n             * @param rpId identifier for a relying party\n             */\n            @NonNull\n            public Builder setRpId(@NonNull String rpId) {\n                this.rpId = rpId;\n                return this;\n            }\n\n            /**\n             * Sets whether passkey credentials should be returned by this API.\n             *\n             * @param supported whether passkey credentials should be returned\n             */\n            @NonNull\n            public Builder setSupported(boolean supported) {\n                this.supported = supported;\n                return this;\n            }\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (!(o instanceof PasskeysRequestOptions)) return false;\n\n            PasskeysRequestOptions that = (PasskeysRequestOptions) o;\n\n            if (supported != that.supported) return false;\n            if (!Arrays.equals(challenge, that.challenge)) return false;\n            return Objects.equals(rpId, that.rpId);\n        }\n\n        @Override\n        public int hashCode() {\n            return Arrays.hashCode(new Object[]{supported, challenge, rpId});\n        }\n\n        @Override\n        public void writeToParcel(@NonNull Parcel dest, int flags) {\n            CREATOR.writeToParcel(this, dest, flags);\n        }\n\n        public static final SafeParcelableCreatorAndWriter<PasskeysRequestOptions> CREATOR = findCreator(PasskeysRequestOptions.class);\n    }\n\n    /**\n     * Options for requesting password-backed credentials during sign-in.\n     */\n    @Class\n    public static class PasswordRequestOptions extends AbstractSafeParcelable {\n        @Field(value = 1, getterName = \"isSupported\")\n        public final boolean supported;\n\n        @NonNull\n        @Override\n        public String toString() {\n            return ToStringHelper.name(\"PasswordRequestOptions\")\n                    .field(\"supported\", supported)\n                    .end();\n        }\n\n        @Constructor\n        @Hide\n        public PasswordRequestOptions(@Param(1) boolean supported) {\n            this.supported = supported;\n        }\n\n        public static Builder builder() {\n            return new Builder();\n        }\n\n        public boolean isSupported() {\n            return supported;\n        }\n\n        /**\n         * Builder for {@link BeginSignInRequest.PasswordRequestOptions}.\n         */\n        public static class Builder {\n            private boolean supported = false;\n\n            /**\n             * Returns the built {@link BeginSignInRequest.PasswordRequestOptions}.\n             */\n            @NonNull\n            public PasswordRequestOptions build() {\n                return new PasswordRequestOptions(supported);\n            }\n\n            /**\n             * Sets whether password-backed credentials should be returned by the API.\n             *\n             * @param supported whether password-backed credentials should be returned\n             */\n            @NonNull\n            public Builder setSupported(boolean supported) {\n                this.supported = supported;\n                return this;\n            }\n        }\n\n        @Override\n        public void writeToParcel(@NonNull Parcel dest, int flags) {\n            CREATOR.writeToParcel(this, dest, flags);\n        }\n\n        public static final SafeParcelableCreatorAndWriter<PasswordRequestOptions> CREATOR = findCreator(PasswordRequestOptions.class);\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof BeginSignInRequest)) return false;\n\n        BeginSignInRequest that = (BeginSignInRequest) o;\n\n        if (autoSelectEnabled != that.autoSelectEnabled) return false;\n        if (theme != that.theme) return false;\n        if (!Objects.equals(passwordRequestOptions, that.passwordRequestOptions)) return false;\n        if (!Objects.equals(googleIdTokenRequestOptions, that.googleIdTokenRequestOptions))\n            return false;\n        if (!Objects.equals(sessionId, that.sessionId)) return false;\n        if (!Objects.equals(passkeysRequestOptions, that.passkeysRequestOptions)) return false;\n        return Objects.equals(passkeyJsonRequestOptions, that.passkeyJsonRequestOptions);\n    }\n\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(new Object[]{passwordRequestOptions, googleIdTokenRequestOptions, sessionId, autoSelectEnabled, theme, passkeysRequestOptions, passkeyJsonRequestOptions});\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<BeginSignInRequest> CREATOR = findCreator(BeginSignInRequest.class);\n\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/identity/BeginSignInResult.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.api.identity;\n\nimport android.app.PendingIntent;\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\n\n/**\n * Result returned from sign-in initiation that includes a {@link PendingIntent} that can be used to continue the sign-in flow.\n */\n@SafeParcelable.Class\npublic class BeginSignInResult extends AbstractSafeParcelable {\n    @Field(value = 1, getterName = \"getPendingIntent\")\n    private final PendingIntent pendingIntent;\n\n    @Constructor\n    @Hide\n    public BeginSignInResult(@Param(1) PendingIntent pendingIntent) {\n        this.pendingIntent = pendingIntent;\n    }\n\n    public PendingIntent getPendingIntent() {\n        return pendingIntent;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<BeginSignInResult> CREATOR = findCreator(BeginSignInResult.class);\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/identity/ClearTokenRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.api.identity;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\n\nimport java.util.Objects;\n\n/**\n * Parameters that configure the Clear token request.\n */\n@SafeParcelable.Class\npublic class ClearTokenRequest extends AbstractSafeParcelable {\n    @NonNull\n    @Field(value = 1, getterName = \"getToken\")\n    private final String token;\n    @Nullable\n    @Field(value = 2, getterName = \"getSessionId\")\n    private final String sessionId;\n\n    public static SafeParcelableCreatorAndWriter<ClearTokenRequest> CREATOR = findCreator(ClearTokenRequest.class);\n\n    @Constructor\n    ClearTokenRequest(@NonNull @Param(1) String token, @Nullable @Param(2) String sessionId) {\n        this.token = token;\n        this.sessionId = sessionId;\n    }\n\n    /**\n     * Returns a new {@link ClearTokenRequest.Builder}.\n     */\n    public static ClearTokenRequest.Builder builder() {\n        return new ClearTokenRequest.Builder() {\n            @Nullable\n            private String token;\n            @Nullable\n            private String sessionId;\n\n            @Override\n            public ClearTokenRequest build() {\n                if (token == null) {\n                    throw new IllegalStateException(\"Missing required properties: token\");\n                }\n                return new ClearTokenRequest(token, sessionId);\n            }\n\n            @Override\n            public ClearTokenRequest.Builder setToken(@NonNull String token) {\n                this.token = token;\n                return this;\n            }\n\n            @Override\n            public ClearTokenRequest.Builder setSessionId(@Nullable String sessionId) {\n                this.sessionId = sessionId;\n                return this;\n            }\n        };\n    }\n\n    @Override\n    public final boolean equals(Object o) {\n        if (!(o instanceof ClearTokenRequest)) return false;\n\n        ClearTokenRequest that = (ClearTokenRequest) o;\n        return token.equals(that.token) && Objects.equals(sessionId, that.sessionId);\n    }\n\n    @NonNull\n    public String getToken() {\n        return token;\n    }\n\n    @Hide\n    @Nullable\n    public String getSessionId() {\n        return sessionId;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hashCode(new Object[]{token, sessionId});\n    }\n\n    /**\n     * Builder for {@link ClearTokenRequest}.\n     */\n    public static abstract class Builder {\n        /**\n         * Builds the {@link ClearTokenRequest}.\n         */\n        public abstract ClearTokenRequest build();\n\n        /**\n         * Sets the token being cleared from the cache.\n         */\n        public abstract ClearTokenRequest.Builder setToken(String token);\n\n        @Hide\n        public abstract ClearTokenRequest.Builder setSessionId(String sessionId);\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel parcel, int flags) {\n        CREATOR.writeToParcel(this, parcel, flags);\n    }\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/identity/CredentialSavingClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.api.identity;\n\nimport android.app.PendingIntent;\nimport android.content.Intent;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.api.HasApiKey;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.tasks.Task;\n\n/**\n * A client for the Credential Saving API.\n */\npublic interface CredentialSavingClient extends HasApiKey<CredentialSavingOptions> {\n    /**\n     * Extracts the {@link Status} from the {@link Intent} object in activity results.\n     */\n    @NonNull\n    Status getStatusFromIntent(@Nullable Intent intent);\n\n    /**\n     * Attempts to save a token for account linking.\n     * <p>\n     * Calling this method will provide a {@link PendingIntent} in the response that can be used to launch the flow to complete the\n     * saving of the account linking token. As part of the request, you need to provide a {@link PendingIntent} for your consent page\n     * that Google Play services will launch in the middle of the flow. The result must then be sent back to the caller following a\n     * certain contract described in {@link SaveAccountLinkingTokenRequest.Builder#setConsentPendingIntent(PendingIntent)}.\n     *\n     * @param saveAccountLinkingTokenRequest the request that contains the parameters to successfully return a response that can be used to\n     *                                       launch the appropriate flow.\n     * @return {@link Task} which may contain the {@link PendingIntent} required to launch the flow. To find out if the response can be used\n     * to start the flow, first call {@link SaveAccountLinkingTokenResult#hasResolution()}.\n     */\n    @NonNull\n    Task<SaveAccountLinkingTokenResult> saveAccountLinkingToken(@NonNull SaveAccountLinkingTokenRequest saveAccountLinkingTokenRequest);\n\n    /**\n     * Initiates the storage of a password-backed credential that can later be used to sign a user in.\n     * <p>\n     * If the request cannot be honored, an exception will be set on the returned {@link Task}. In all other cases, a\n     * {@link SavePasswordResult} will be returned.\n     *\n     * @param savePasswordRequest container for the {@link SignInPassword} for the password-saving flow\n     * @return {@link Task} which eventually contains the result of the initialization\n     */\n    @NonNull\n    Task<SavePasswordResult> savePassword(@NonNull SavePasswordRequest savePasswordRequest);\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/identity/CredentialSavingOptions.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.api.identity;\n\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.api.Api;\n\nimport java.util.Arrays;\n\npublic class CredentialSavingOptions implements Api.ApiOptions.Optional {\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(new Object[]{CredentialSavingOptions.class});\n    }\n\n    @Override\n    public boolean equals(@Nullable Object obj) {\n        return obj instanceof CredentialSavingOptions;\n    }\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/identity/GetPhoneNumberHintIntentRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.api.identity;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\n\n/**\n * Request object used to get an Intent to start the Phone Number Hint flow.\n */\n@SafeParcelable.Class\npublic class GetPhoneNumberHintIntentRequest extends AbstractSafeParcelable {\n    @Field(value = 1, getterName = \"getTheme\")\n    private final int theme;\n\n    @Constructor\n    GetPhoneNumberHintIntentRequest(@Param(1) int theme) {\n        this.theme = theme;\n    }\n\n    @NonNull\n    public static Builder builder() {\n        return new Builder();\n    }\n\n    @Hide\n    public int getTheme() {\n        return theme;\n    }\n\n    /**\n     * Builder for {@link GetPhoneNumberHintIntentRequest}\n     */\n    public static class Builder {\n        private int theme;\n\n        @NonNull\n        public GetPhoneNumberHintIntentRequest build() {\n            return new GetPhoneNumberHintIntentRequest(theme);\n        }\n\n        @Hide\n        @NonNull\n        public Builder setTheme(int theme) {\n            this.theme = theme;\n            return this;\n        }\n    }\n\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<GetPhoneNumberHintIntentRequest> CREATOR = findCreator(GetPhoneNumberHintIntentRequest.class);\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/identity/GetSignInIntentRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.api.identity;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.Arrays;\nimport java.util.Objects;\n\n/**\n * Request to get a Google sign-in intent.\n */\n@SafeParcelable.Class\npublic class GetSignInIntentRequest extends AbstractSafeParcelable {\n    @Field(value = 1, getterName = \"getServerClientId\")\n    private final String serverClientId;\n    @Field(value = 2, getterName = \"getHostedDomainFilter\")\n    private final String hostedDomainFilter;\n    @Field(value = 3, getterName = \"getSessionId\")\n    private final String sessionId;\n    @Field(value = 4, getterName = \"getNonce\")\n    private final String nonce;\n    @Field(value = 5, getterName = \"requestVerifiedPhoneNumber\")\n    private final boolean requestVerifiedPhoneNumber;\n    @Field(value = 6, getterName = \"getTheme\")\n    private final int theme;\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"GetSignInIntentRequest\")\n                .field(\"serverClientId\", serverClientId)\n                .field(\"hostedDomainFilter\", hostedDomainFilter)\n                .field(\"sessionId\", sessionId)\n                .field(\"nonce\", nonce)\n                .field(\"requestVerifiedPhoneNumber\", requestVerifiedPhoneNumber)\n                .field(\"theme\", theme)\n                .end();\n    }\n\n    @Constructor\n    GetSignInIntentRequest(@Param(1) String serverClientId, @Param(2) String hostedDomainFilter, @Param(3) String sessionId, @Param(4) String nonce, @Param(5) boolean requestVerifiedPhoneNumber, @Param(6) int theme) {\n        this.serverClientId = serverClientId;\n        this.hostedDomainFilter = hostedDomainFilter;\n        this.sessionId = sessionId;\n        this.nonce = nonce;\n        this.requestVerifiedPhoneNumber = requestVerifiedPhoneNumber;\n        this.theme = theme;\n    }\n\n    @NonNull\n    public static Builder builder() {\n        return new Builder();\n    }\n\n    /**\n     * Returns the {@code hostedDomainFilter} if it was set in the request, or {@code null} otherwise.\n     */\n    public String getHostedDomainFilter() {\n        return hostedDomainFilter;\n    }\n\n    /**\n     * Returns the nonce that was set in the request.\n     */\n    public String getNonce() {\n        return nonce;\n    }\n\n    /**\n     * Returns the {@code serverClientId} that was set in the request.\n     */\n    public String getServerClientId() {\n        return serverClientId;\n    }\n\n    @Hide\n    public String getSessionId() {\n        return sessionId;\n    }\n\n    @Hide\n    public int getTheme() {\n        return theme;\n    }\n\n    /**\n     * Returns whether a verified phone number is requested.\n     *\n     * @deprecated No replacement.\n     */\n    @Deprecated\n    public boolean requestVerifiedPhoneNumber() {\n        return requestVerifiedPhoneNumber;\n    }\n\n    /**\n     * Builder class for {@link GetSignInIntentRequest}.\n     */\n    public static class Builder {\n        private String serverClientId;\n        private String hostedDomainFilter;\n        private String sessionId;\n        private String nonce;\n        private boolean requestVerifiedPhoneNumber;\n        private int theme;\n\n        @NonNull\n        public GetSignInIntentRequest build() {\n            return new GetSignInIntentRequest(serverClientId, hostedDomainFilter, sessionId, nonce, requestVerifiedPhoneNumber, theme);\n        }\n\n        /**\n         * Sets the hosted domain filter (e.g. myuniveristy.edu). Default is no filter.\n         */\n        @NonNull\n        public Builder filterByHostedDomain(@Nullable String hostedDomainFilter) {\n            this.hostedDomainFilter = hostedDomainFilter;\n            return this;\n        }\n\n        /**\n         * Sets the nonce to use when generating a Google ID token. The values for nonce can be any random string and is used to\n         * prevent replay-attack. Default is no nonce.\n         *\n         * @param nonce the nonce to use during ID token generation\n         */\n        @NonNull\n        public Builder setNonce(@Nullable String nonce) {\n            this.nonce = nonce;\n            return this;\n        }\n\n        /**\n         * Sets whether to prompt the users to share a verified phone number associated with their Google accounts.\n         * <p>\n         * Note that if the user selects a Google account which has previously been used to sign up to your app, they won't be\n         * prompted with the phone number selection.\n         *\n         * @deprecated No replacement.\n         */\n        @Deprecated\n        @NonNull\n        public Builder setRequestVerifiedPhoneNumber(boolean requestsVerifiedPhoneNumber) {\n            this.requestVerifiedPhoneNumber = requestsVerifiedPhoneNumber;\n            return this;\n        }\n\n        /**\n         * Sets the client ID of the server that will verify the integrity of the token. Calling this method to set the {@code serverClientId} is\n         * required.\n         */\n        @NonNull\n        public Builder setServerClientId(@NonNull String serverClientId) {\n            this.serverClientId = serverClientId;\n            return this;\n        }\n\n        @NonNull\n        public Builder setSessionId(@Nullable String sessionId) {\n            this.sessionId = sessionId;\n            return this;\n        }\n\n        @NonNull\n        public Builder setTheme(int theme) {\n            this.theme = theme;\n            return this;\n        }\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof GetSignInIntentRequest)) return false;\n\n        GetSignInIntentRequest that = (GetSignInIntentRequest) o;\n\n        if (requestVerifiedPhoneNumber != that.requestVerifiedPhoneNumber) return false;\n        if (theme != that.theme) return false;\n        if (!Objects.equals(serverClientId, that.serverClientId)) return false;\n        if (!Objects.equals(hostedDomainFilter, that.hostedDomainFilter)) return false;\n        if (!Objects.equals(sessionId, that.sessionId)) return false;\n        return Objects.equals(nonce, that.nonce);\n    }\n\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(new Object[]{serverClientId, hostedDomainFilter, serverClientId, nonce, requestVerifiedPhoneNumber, theme});\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<GetSignInIntentRequest> CREATOR = findCreator(GetSignInIntentRequest.class);\n\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/identity/Identity.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.api.identity;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport androidx.annotation.NonNull;\n\n/**\n * The entry point to the Sign-In APIs.\n */\npublic final class Identity {\n\n//    /**\n//     * Returns a new instance of {@link AuthorizationClient}.\n//     */\n//    @NonNull\n//    public static AuthorizationClient getAuthorizationClient(@NonNull Context context) {\n//        throw new UnsupportedOperationException();\n//    }\n//\n//    /**\n//     * Returns a new instance of {@link AuthorizationClient}.\n//     */\n//    @NonNull\n//    public static AuthorizationClient getAuthorizationClient(@NonNull Activity activity) {\n//        throw new UnsupportedOperationException();\n//    }\n\n    /**\n     * Returns a new instance of {@link CredentialSavingClient}.\n     */\n    @NonNull\n    public static CredentialSavingClient getCredentialSavingClient(@NonNull Activity activity) {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Returns a new instance of {@link CredentialSavingClient}.\n     */\n    @NonNull\n    public static CredentialSavingClient getCredentialSavingClient(@NonNull Context context) {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Returns a new instance of {@link SignInClient}.\n     */\n    @NonNull\n    public static SignInClient getSignInClient(@NonNull Activity activity) {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Returns a new instance of {@link SignInClient}.\n     */\n    @NonNull\n    public static SignInClient getSignInClient(@NonNull Context context) {\n        throw new UnsupportedOperationException();\n    }\n\n    private Identity() {\n    }\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/identity/RevokeAccessRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.api.identity;\n\nimport android.accounts.Account;\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.api.Scope;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\n\nimport java.util.List;\nimport java.util.Objects;\n\n/**\n * Parameters that configure the Revoke Access request.\n */\n@SafeParcelable.Class\npublic class RevokeAccessRequest extends AbstractSafeParcelable {\n    @Field(value = 1, getterName = \"getScopes\")\n    @NonNull\n    private final List<Scope> scopes;\n    @Field(value = 2, getterName = \"getAccount\")\n    @NonNull\n    private final Account account;\n    @Field(value = 3, getterName = \"getSessionId\")\n    @Nullable\n    private final String sessionId;\n\n    @Constructor\n    RevokeAccessRequest(@NonNull @Param(1) List<Scope> scopes, @NonNull @Param(2) Account account, @Nullable @Param(3) String sessionId) {\n        this.scopes = scopes;\n        this.account = account;\n        this.sessionId = sessionId;\n    }\n\n    /**\n     * Returns a new {@link RevokeAccessRequest.Builder}.\n     */\n    @NonNull\n    public static RevokeAccessRequest.Builder builder() {\n        return new Builder() {\n            private List<Scope> scopes;\n            private Account account;\n            private String sessionId;\n\n            @NonNull\n            @Override\n            public RevokeAccessRequest build() {\n                if (scopes == null) throw new IllegalStateException(\"Missing required properties: scopes\");\n                if (account == null) throw new IllegalStateException(\"Missing required properties: account\");\n                return new RevokeAccessRequest(scopes, account, sessionId);\n            }\n\n            @NonNull\n            @Override\n            public Builder setAccount(@NonNull Account account) {\n                this.account = account;\n                return this;\n            }\n\n            @NonNull\n            @Override\n            public Builder setScopes(@NonNull List<Scope> scopes) {\n                this.scopes = scopes;\n                return this;\n            }\n\n            @NonNull\n            @Override\n            public Builder setSessionId(@Nullable String sessionId) {\n                this.sessionId = sessionId;\n                return this;\n            }\n        };\n    }\n\n    /**\n     * Returns the account that the application is revoking access for.\n     */\n    @NonNull\n    public Account getAccount() {\n        return account;\n    }\n\n    /**\n     * Returns the scopes that access is being revoked for.\n     */\n    @NonNull\n    public List<Scope> getScopes() {\n        return scopes;\n    }\n\n    @Hide\n    @Nullable\n    public String getSessionId() {\n        return sessionId;\n    }\n\n    @Override\n    public final boolean equals(Object o) {\n        if (!(o instanceof RevokeAccessRequest)) return false;\n\n        RevokeAccessRequest that = (RevokeAccessRequest) o;\n        return scopes.equals(that.scopes) && account.equals(that.account) && Objects.equals(sessionId, that.sessionId);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hashCode(new Object[]{scopes, account, sessionId});\n    }\n\n    /**\n     * Builder for {@link RevokeAccessRequest}.\n     */\n    public static abstract class Builder {\n        @NonNull\n        public abstract RevokeAccessRequest build();\n\n        @NonNull\n        public abstract Builder setAccount(@NonNull Account account);\n\n        @NonNull\n        public abstract Builder setScopes(@NonNull List<Scope> scopes);\n\n        @NonNull\n        @Hide\n        public abstract Builder setSessionId(@Nullable String sessionId);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<RevokeAccessRequest> CREATOR = findCreator(RevokeAccessRequest.class);\n\n    @Override\n    public void writeToParcel(@NonNull Parcel parcel, int flags) {\n        CREATOR.writeToParcel(this, parcel, flags);\n    }\n\n    @Override\n    public String toString() {\n        return \"RevokeAccessRequest{\" +\n                \"scopes=\" + scopes +\n                \", account=\" + account +\n                \", sessionId='\" + sessionId + '\\'' +\n                '}';\n    }\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/identity/SaveAccountLinkingTokenRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.api.identity;\n\nimport android.app.Activity;\nimport android.app.PendingIntent;\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\n\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Objects;\n\n/**\n * Configurations that allow saving a token to Google for the purpose of account linking.\n */\npublic class SaveAccountLinkingTokenRequest extends AbstractSafeParcelable {\n    public static final String EXTRA_TOKEN = \"extra_token\";\n    /**\n     * A constant to indicate that the type of token that will be saved is an Authorization Code.\n     */\n    public static final String TOKEN_TYPE_AUTH_CODE = \"auth_code\";\n\n    @Field(value = 1, getterName = \"getConsentPendingIntent\")\n    private final PendingIntent consentPendingIntent;\n    @Field(value = 2, getterName = \"getTokenType\")\n    private final String tokenType;\n    @Field(value = 3, getterName = \"getServiceId\")\n    private final String serviceId;\n    @Field(value = 4, getterName = \"getScopes\")\n    private final List<String> scopes;\n    @Field(value = 5, getterName = \"getSessionId\")\n    private final String sessionId;\n    @Field(value = 6, getterName = \"getTheme\")\n    private final int theme;\n\n    @Constructor\n    SaveAccountLinkingTokenRequest(@Param(1) PendingIntent consentPendingIntent, @Param(2) String tokenType, @Param(3) String serviceId, @Param(4) List<String> scopes, @Param(5) String sessionId, @Param(6) int theme) {\n        this.consentPendingIntent = consentPendingIntent;\n        this.tokenType = tokenType;\n        this.serviceId = serviceId;\n        this.scopes = scopes;\n        this.sessionId = sessionId;\n        this.theme = theme;\n    }\n\n    /**\n     * Returns an instance of the {@link SaveAccountLinkingTokenRequest.Builder} that can be used to build an instance of {@link SaveAccountLinkingTokenRequest}.\n     */\n    public static Builder builder() {\n        return new Builder();\n    }\n\n    /**\n     * Returns the {@link PendingIntent} that is set in the request and will be used to launch the consent page by Google Play Services during the flow.\n     */\n    public PendingIntent getConsentPendingIntent() {\n        return consentPendingIntent;\n    }\n\n    /**\n     * Returns the scopes that were set in the request. These are the requested scopes for the token that will be issued by your application.\n     */\n    public List<String> getScopes() {\n        return scopes;\n    }\n\n    /**\n     * Returns the service-id that was set in the request. This service-id can be found in your cloud project.\n     */\n    public String getServiceId() {\n        return serviceId;\n    }\n\n    @Hide\n    public String getSessionId() {\n        return sessionId;\n    }\n\n    @Hide\n    public int getTheme() {\n        return theme;\n    }\n\n    /**\n     * Returns the type of token that is requested.\n     */\n    public String getTokenType() {\n        return tokenType;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof SaveAccountLinkingTokenRequest)) return false;\n\n        SaveAccountLinkingTokenRequest that = (SaveAccountLinkingTokenRequest) o;\n\n        if (theme != that.theme) return false;\n        if (!Objects.equals(consentPendingIntent, that.consentPendingIntent)) return false;\n        if (!Objects.equals(tokenType, that.tokenType)) return false;\n        if (!Objects.equals(serviceId, that.serviceId)) return false;\n        if (!Objects.equals(scopes, that.scopes)) return false;\n        return Objects.equals(sessionId, that.sessionId);\n    }\n\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(new Object[]{consentPendingIntent, tokenType, serviceId, scopes, serviceId, theme});\n    }\n\n    /**\n     * Builder for {@link SaveAccountLinkingTokenRequest}.\n     */\n    public static class Builder {\n        private PendingIntent consentPendingIntent;\n        private String tokenType;\n        private String serviceId;\n        private List<String> scopes;\n        private String sessionId;\n        private int theme;\n\n        /**\n         * Builds an immutable instance of the {@link SaveAccountLinkingTokenRequest}.\n         */\n        @NonNull\n        public SaveAccountLinkingTokenRequest build() {\n            return new SaveAccountLinkingTokenRequest(consentPendingIntent, tokenType, serviceId, scopes, sessionId, theme);\n        }\n\n        /**\n         * Sets the (mandatory) {@link PendingIntent} that can be launched by Google Play services to show the consent page during\n         * the flow. When the launched Activity is finished, it has to provide the appropriate data in the result that it returns to the\n         * caller, based on the following contract:\n         * <ul>\n         *     <li>\n         *         If the user has accepted the consent, the launched Activity must call {@code setResult} with {@link Activity#RESULT_OK}, along with a\n         *         token as a (string) intent extra in the result, with the key {@link SaveAccountLinkingTokenRequest#EXTRA_TOKEN},\n         *         similar to the following snippet:\n         *         <pre>\n         *  Intent intent = new Intent();\n         *  intent.putExtra(SaveAccountLinkingTokenRequest.EXTRA_TOKEN, token);\n         *  setResult(Activity.RESULT_OK, intent);\n         *  finish();\n         *         </pre>\n         *     </li>\n         *     <li>\n         *         If, however, the user has rejected the consent, the Activity has to call {@code setResult} with {@link Activity#RESULT_CANCELED}.\n         *     </li>\n         * </ul>\n         */\n        @NonNull\n        public Builder setConsentPendingIntent(PendingIntent consentPendingIntent) {\n            this.consentPendingIntent = consentPendingIntent;\n            return this;\n        }\n\n        /**\n         * Sets the list of scopes that are associated with the token that will be saved to Google. Calling this method with the\n         * correct scope(s) is required.\n         */\n        @NonNull\n        public Builder setScopes(List<String> scopes) {\n            this.scopes = scopes;\n            return this;\n        }\n\n        /**\n         * Sets the service-id that can be obtained from your Google Cloud project. Calling this method to set {@code serviceId}\n         * is required.\n         */\n        @NonNull\n        public Builder setServiceId(String serviceId) {\n            this.serviceId = serviceId;\n            return this;\n        }\n\n        @Hide\n        @NonNull\n        public Builder setSessionId(String sessionId) {\n            this.sessionId = sessionId;\n            return this;\n        }\n\n        @Hide\n        @NonNull\n        public Builder setTheme(int theme) {\n            this.theme = theme;\n            return this;\n        }\n\n        /**\n         * Sets the type of token that will be saved to Google. Valid options are:\n         * <ul>\n         *     <li>{@link SaveAccountLinkingTokenRequest#TOKEN_TYPE_AUTH_CODE}</li>\n         * </ul>\n         * Calling this method with a valid token type is required.\n         */\n        @NonNull\n        public Builder setTokenType(String tokenType) {\n            this.tokenType = tokenType;\n            return this;\n        }\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<SaveAccountLinkingTokenRequest> CREATOR = findCreator(SaveAccountLinkingTokenRequest.class);\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/identity/SaveAccountLinkingTokenResult.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.api.identity;\n\nimport android.app.PendingIntent;\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\n\nimport java.util.Objects;\n\n/**\n * Result returned from the initial call to save an account linking token that includes a {@link PendingIntent} that can be used to\n * continue the flow.\n */\n@SafeParcelable.Class\npublic class SaveAccountLinkingTokenResult extends AbstractSafeParcelable {\n    @Field(value = 1, getterName = \"getPendingIntent\")\n    private final PendingIntent pendingIntent;\n\n    @Constructor\n    @Hide\n    public SaveAccountLinkingTokenResult(@Param(1) PendingIntent pendingIntent) {\n        this.pendingIntent = pendingIntent;\n    }\n\n    /**\n     * Returns the {@link PendingIntent} that can be used to launch the flow. Note that this method can return a {@code null} value if such\n     * flow cannot be started. It is expected that the caller first calls {@link #hasResolution()} to make sure the flow can be started,\n     * instead of examining the nullness of the result returned by this method.\n     */\n    public PendingIntent getPendingIntent() {\n        return pendingIntent;\n    }\n\n    /**\n     * Returns {@code true} if and only if this result contains a resolution that needs to be launched.\n     */\n    public boolean hasResolution() {\n        return pendingIntent != null;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof SaveAccountLinkingTokenResult)) return false;\n\n        SaveAccountLinkingTokenResult that = (SaveAccountLinkingTokenResult) o;\n\n        return Objects.equals(pendingIntent, that.pendingIntent);\n    }\n\n    @Override\n    public int hashCode() {\n        return pendingIntent != null ? pendingIntent.hashCode() : 0;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<SaveAccountLinkingTokenResult> CREATOR = findCreator(SaveAccountLinkingTokenResult.class);\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/identity/SavePasswordRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.api.identity;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\n\n/**\n * Configurations that allow saving a {@link SignInPassword} to Google.\n */\n@SafeParcelable.Class\npublic class SavePasswordRequest extends AbstractSafeParcelable {\n    @Field(value = 1, getterName = \"getSignInPassword\")\n    private final SignInPassword signInPassword;\n    @Field(value = 2, getterName = \"getSessionId\")\n    @Nullable\n    private final String sessionId;\n    @Field(value = 3, getterName = \"getTheme\")\n    private final int theme;\n\n    @Constructor\n    SavePasswordRequest(@Param(1) SignInPassword signInPassword, @Param(2) @Nullable String sessionId, @Param(3) int theme) {\n        this.signInPassword = signInPassword;\n        this.sessionId = sessionId;\n        this.theme = theme;\n    }\n\n    /**\n     * Returns a new instance of the {@link SavePasswordRequest.Builder}.\n     */\n    public static Builder builder() {\n        return new Builder();\n    }\n\n    @Hide\n    @Nullable\n    public String getSessionId() {\n        return sessionId;\n    }\n\n    public SignInPassword getSignInPassword() {\n        return signInPassword;\n    }\n\n    @Hide\n    public int getTheme() {\n        return theme;\n    }\n\n    /**\n     * Builder for {@link SavePasswordRequest}.\n     */\n    public static class Builder {\n        private SignInPassword signInPassword;\n        @Nullable\n        private String sessionId;\n        private int theme;\n\n        /**\n         * Sets the {@link SignInPassword}\n         */\n        @NonNull\n        public Builder setSignInPassword(@NonNull SignInPassword signInPassword) {\n            this.signInPassword = signInPassword;\n            return this;\n        }\n\n        @Hide\n        @NonNull\n        public Builder setSessionId(@Nullable String sessionId) {\n            this.sessionId = sessionId;\n            return this;\n        }\n\n        @Hide\n        @NonNull\n        public Builder setTheme(int theme) {\n            this.theme = theme;\n            return this;\n        }\n\n        /**\n         * Builds and returns a new instance of {@link SavePasswordRequest}.\n         */\n        @NonNull\n        public SavePasswordRequest build() {\n            return new SavePasswordRequest(signInPassword, sessionId, theme);\n        }\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<SavePasswordRequest> CREATOR = findCreator(SavePasswordRequest.class);\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/identity/SavePasswordResult.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.api.identity;\n\nimport android.app.PendingIntent;\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport java.util.Objects;\n\n/**\n * The result returned from calling {@link CredentialSavingClient#savePassword(SavePasswordRequest)} that includes a\n * {@link PendingIntent} that can be used to launch the password saving flow.\n */\n@SafeParcelable.Class\npublic class SavePasswordResult extends AbstractSafeParcelable {\n    @Field(value = 1, getterName = \"getPendingIntent\")\n    private final PendingIntent pendingIntent;\n\n    @Constructor\n    public SavePasswordResult(@Param(1) PendingIntent pendingIntent) {\n        this.pendingIntent = pendingIntent;\n    }\n\n    /**\n     * Returns the {@link PendingIntent} that should be launched to start the UI flow for saving the password.\n     */\n    public PendingIntent getPendingIntent() {\n        return pendingIntent;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof SavePasswordResult)) return false;\n\n        SavePasswordResult that = (SavePasswordResult) o;\n\n        return Objects.equals(pendingIntent, that.pendingIntent);\n    }\n\n    @Override\n    public int hashCode() {\n        return pendingIntent != null ? pendingIntent.hashCode() : 0;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<SavePasswordResult> CREATOR = findCreator(SavePasswordResult.class);\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/identity/SignInClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.api.identity;\n\nimport android.app.PendingIntent;\nimport android.content.Intent;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.api.ApiException;\nimport com.google.android.gms.common.api.HasApiKey;\nimport com.google.android.gms.tasks.Task;\n\npublic interface SignInClient extends HasApiKey<SignInOptions> {\n    /**\n     * Initiates the retrieval of a credential that can assist the caller in signing a user in to their application.\n     * <p>\n     * If the request cannot be honored, an exception will be set on the returned {@link Task}. In all other cases, a\n     * {@link BeginSignInResult} will be returned.\n     *\n     * @param signInRequest configuration for the sign-in operation\n     * @return {@link Task} which eventually contains the result of the initialization\n     */\n    @NonNull\n    Task<BeginSignInResult> beginSignIn(@NonNull BeginSignInRequest signInRequest);\n\n    /**\n     * Retrieves the Phone Number from the {@link Intent} returned upon a successful Phone Number Hint request, throwing an\n     * {@link ApiException} if no phone number is available or the input {@link Intent} is null.\n     *\n     * @throws ApiException\n     */\n    @NonNull\n    String getPhoneNumberFromIntent(@Nullable Intent data) throws ApiException;\n\n    /**\n     * Gets the {@link PendingIntent} that initiates the Phone Number Hint flow.\n     * <p>\n     * If there is no phone number on the device, an exception will be set on the returned {@link Task}. In all other cases, a\n     * {@link PendingIntent} will be returned.\n     *\n     * @return {@link Task} which can be used to start the Phone Number Hint flow.\n     */\n    @NonNull\n    Task<PendingIntent> getPhoneNumberHintIntent(@NonNull GetPhoneNumberHintIntentRequest getPhoneNumberHintIntentRequest);\n\n    /**\n     * Retrieves the {@link SignInCredential} from the {@link Intent} returned upon successful sign-in, throwing an {@link ApiException} if no\n     * credential is present.\n     *\n     * @throws ApiException\n     */\n    @NonNull\n    SignInCredential getSignInCredentialFromIntent(@Nullable Intent data) throws ApiException;\n\n    /**\n     * Gets the {@link PendingIntent} that initiates the Google Sign-in flow.\n     * <p>\n     * If the request cannot be honored, an exception will be set on the returned {@link Task}. In all other cases, a {@link PendingIntent}\n     * will be returned.\n     *\n     * @param getSignInIntentRequest configuration for Google Sign-in flow\n     * @return {@link Task} which eventually contains the {@link PendingIntent} to start the Google Sign-in flow.\n     */\n    @NonNull\n    Task<PendingIntent> getSignInIntent(@NonNull GetSignInIntentRequest getSignInIntentRequest);\n\n    /**\n     * Resets internal state related to sign-in.\n     * <p>\n     * This method should be invoked when a user signs out of your app.\n     *\n     * @return {@link Task} which eventually terminates in success or failure\n     */\n    @NonNull\n    Task<Void> signOut();\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/identity/SignInCredential.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.api.identity;\n\nimport android.net.Uri;\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.fido.fido2.api.common.PublicKeyCredential;\nimport org.microg.gms.common.Hide;\n\nimport java.util.Arrays;\nimport java.util.Objects;\n\n/**\n * The credential returned as a result of a successful sign-in. Data returned within this object depends on the type of\n * credential that user has selected; for example a password is returned only when a password-backed credential was\n * selected.\n */\n@SafeParcelable.Class\npublic class SignInCredential extends AbstractSafeParcelable {\n    @Field(value = 1, getterName = \"getId\")\n    private final String id;\n    @Field(value = 2, getterName = \"getDisplayName\")\n    private final String displayName;\n    @Field(value = 3, getterName = \"getGivenName\")\n    private final String givenName;\n    @Field(value = 4, getterName = \"getFamilyName\")\n    private final String familyName;\n    @Field(value = 5, getterName = \"getProfilePictureUri\")\n    private final Uri profilePictureUri;\n    @Field(value = 6, getterName = \"getPassword\")\n    private final String password;\n    @Field(value = 7, getterName = \"getGoogleIdToken\")\n    private final String googleIdToken;\n    @Field(value = 8, getterName = \"getPhoneNumber\")\n    private final String phoneNumber;\n    @Field(value = 9, getterName = \"getPublicKeyCredential\")\n    private final PublicKeyCredential publicKeyCredential;\n\n    @Hide\n    @Constructor\n    public SignInCredential(@Param(1) String id, @Param(2) String displayName, @Param(3) String givenName, @Param(4) String familyName, @Param(5) Uri profilePictureUri, @Param(6) String password, @Param(7) String googleIdToken, @Param(8) String phoneNumber, @Param(9) PublicKeyCredential publicKeyCredential) {\n        this.id = id;\n        this.displayName = displayName;\n        this.givenName = givenName;\n        this.familyName = familyName;\n        this.profilePictureUri = profilePictureUri;\n        this.password = password;\n        this.googleIdToken = googleIdToken;\n        this.phoneNumber = phoneNumber;\n        this.publicKeyCredential = publicKeyCredential;\n    }\n\n    public String getDisplayName() {\n        return displayName;\n    }\n\n    public String getFamilyName() {\n        return familyName;\n    }\n\n    public String getGivenName() {\n        return givenName;\n    }\n\n    public String getGoogleIdToken() {\n        return googleIdToken;\n    }\n\n    public String getPassword() {\n        return password;\n    }\n\n    /**\n     * Returns the identifier of the credential. For an ID token credential, this returns the email address of the user's account\n     * and for a password-backed credential, it returns the username for that password.\n     */\n    public String getId() {\n        return id;\n    }\n\n    /**\n     * @deprecated No replacement.\n     */\n    @Deprecated\n    public String getPhoneNumber() {\n        return phoneNumber;\n    }\n\n    public Uri getProfilePictureUri() {\n        return profilePictureUri;\n    }\n\n    /**\n     * Returns {@code publicKeyCredential}.\n     */\n    public PublicKeyCredential getPublicKeyCredential() {\n        return publicKeyCredential;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof SignInCredential)) return false;\n\n        SignInCredential that = (SignInCredential) o;\n\n        if (!Objects.equals(id, that.id)) return false;\n        if (!Objects.equals(displayName, that.displayName)) return false;\n        if (!Objects.equals(givenName, that.givenName)) return false;\n        if (!Objects.equals(familyName, that.familyName)) return false;\n        if (!Objects.equals(profilePictureUri, that.profilePictureUri)) return false;\n        if (!Objects.equals(password, that.password)) return false;\n        if (!Objects.equals(googleIdToken, that.googleIdToken)) return false;\n        if (!Objects.equals(phoneNumber, that.phoneNumber)) return false;\n        return Objects.equals(publicKeyCredential, that.publicKeyCredential);\n    }\n\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(new Object[]{id, displayName, givenName, familyName, profilePictureUri, password, googleIdToken, phoneNumber, publicKeyCredential});\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<SignInCredential> CREATOR = findCreator(SignInCredential.class);\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/identity/SignInOptions.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.api.identity;\n\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.api.Api;\n\nimport java.util.Arrays;\n\npublic class SignInOptions implements Api.ApiOptions.Optional {\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(new Object[]{SignInOptions.class});\n    }\n\n    @Override\n    public boolean equals(@Nullable Object obj) {\n        return obj instanceof SignInOptions;\n    }\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/identity/SignInPassword.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.api.identity;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport java.util.Arrays;\n\n/**\n * An account ID such as a username or an email, and a password that can be used to sign a user in.\n */\n@SafeParcelable.Class\npublic class SignInPassword extends AbstractSafeParcelable {\n    @Field(value = 1, getterName = \"getId\")\n    @NonNull\n    private final String id;\n    @Field(value = 2, getterName = \"getPassword\")\n    @NonNull\n    private final String password;\n\n    @Constructor\n    public SignInPassword(@Param(1) @NonNull String id, @Param(2) @NonNull String password) {\n        this.id = id;\n        this.password = password;\n    }\n\n    @NonNull\n    public String getId() {\n        return id;\n    }\n\n    @NonNull\n    public String getPassword() {\n        return password;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof SignInPassword)) return false;\n\n        SignInPassword that = (SignInPassword) o;\n\n        if (!id.equals(that.id)) return false;\n        return password.equals(that.password);\n    }\n\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(new String[]{id, password});\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<SignInPassword> CREATOR = findCreator(SignInPassword.class);\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/identity/VerifyWithGoogleRequest.java",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.api.identity;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.api.Scope;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport java.util.List;\n\n@SafeParcelable.Class\npublic class VerifyWithGoogleRequest extends AbstractSafeParcelable {\n\n    @Field(1)\n    public List<Scope> requestedScopes;\n    @Field(2)\n    public String serverClientId;\n    @Field(3)\n    public boolean offlineAccess;\n    @Field(4)\n    public String sessionId;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<VerifyWithGoogleRequest> CREATOR = findCreator(VerifyWithGoogleRequest.class);\n\n    @Override\n    public String toString() {\n        return \"VerifyWithGoogleRequest{\" +\n                \"requestedScopes=\" + requestedScopes +\n                \", serverClientId='\" + serverClientId + '\\'' +\n                \", offlineAccess=\" + offlineAccess +\n                \", sessionId='\" + sessionId + '\\'' +\n                '}';\n    }\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/identity/VerifyWithGoogleResult.java",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.api.identity;\n\nimport android.app.PendingIntent;\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.api.Scope;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport java.util.List;\n\n@SafeParcelable.Class\npublic class VerifyWithGoogleResult extends AbstractSafeParcelable {\n\n    @Field(1)\n    public String serverAuthToken;\n    @Field(2)\n    public String idToken;\n    @Field(3)\n    public List<Scope> grantedScopes;\n    @Field(4)\n    public PendingIntent pendingIntent;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<VerifyWithGoogleResult> CREATOR = findCreator(VerifyWithGoogleResult.class);\n\n    @Override\n    public String toString() {\n        return \"VerifyWithGoogleResult{\" +\n                \"serverAuthToken='\" + serverAuthToken + '\\'' +\n                \", idToken='\" + idToken + '\\'' +\n                \", grantedScopes=\" + grantedScopes +\n                \", pendingIntent=\" + pendingIntent +\n                '}';\n    }\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/identity/package-info.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\n/**\n * Provides facilities to retrieve or save credentials that can be used to sign the user into your application or sign up a new user.\n */\npackage com.google.android.gms.auth.api.identity;"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/signin/GoogleSignIn.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.api.signin;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.content.Intent;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.fragment.app.Fragment;\nimport com.google.android.gms.auth.api.signin.internal.Storage;\nimport com.google.android.gms.common.api.ApiException;\nimport com.google.android.gms.common.api.Scope;\nimport com.google.android.gms.tasks.Task;\nimport com.google.android.gms.tasks.Tasks;\nimport org.microg.gms.auth.api.signin.GoogleSignInCommon;\n\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * Entry point for the Google Sign In API. See GoogleSignInClient.\n *\n * @deprecated Use Credential Manager for authentication or Google Identity Services for authorization.\n */\n@Deprecated\npublic class GoogleSignIn {\n    private GoogleSignIn() {\n        // Disallow instantiation\n    }\n\n    /**\n     * Gets a {@link GoogleSignInAccount} object to use with other authenticated APIs. Please specify the additional configurations required by the\n     * authenticated API, e.g. {@link com.google.android.gms.fitness.FitnessOptions} indicating what data types you'd like to access.\n     */\n    @NonNull\n    public static GoogleSignInAccount getAccountForExtension(@NonNull Context context, @NonNull GoogleSignInOptionsExtension extension) {\n        GoogleSignInAccount lastSignedInAccount = getLastSignedInAccount(context);\n        if (lastSignedInAccount == null) lastSignedInAccount = GoogleSignInAccount.createDefault();\n        return lastSignedInAccount.requestExtraScopes(extension.getImpliedScopes().toArray(new Scope[0]));\n    }\n\n    /**\n     * Gets a {@link GoogleSignInAccount} object to use with other authenticated APIs. Please specify the scope(s) required by the authenticated API.\n     */\n    @NonNull\n    public static GoogleSignInAccount getAccountForScopes(@NonNull Context context, @NonNull Scope scope, @NonNull Scope... scopes) {\n        GoogleSignInAccount lastSignedInAccount = getLastSignedInAccount(context);\n        if (lastSignedInAccount == null) lastSignedInAccount = GoogleSignInAccount.createDefault();\n        lastSignedInAccount.requestExtraScopes(scope);\n        lastSignedInAccount.requestExtraScopes(scopes);\n        return lastSignedInAccount;\n    }\n\n    /**\n     * Create a new instance of {@link GoogleSignInClient}\n     * <p>\n     * See also {@link #getClient(Activity, GoogleSignInOptions)} for GoogleSignInOptions configuration.\n     *\n     * @param context A Context used to provide information about the application's environment.\n     */\n    @NonNull\n    public static GoogleSignInClient getClient(@NonNull Context context, @NonNull GoogleSignInOptions options) {\n        return new GoogleSignInClient(context, options);\n    }\n\n    /**\n     * Create a new instance of {@link GoogleSignInClient}\n     *\n     * @param activity An {@link Activity} that will be used to manage the lifecycle of the GoogleSignInClient.\n     * @param options  A {@link GoogleSignInOptions} used to configure the GoogleSignInClient. It is recommended to build out a GoogleSignInOptions starting\n     *                 with {@code new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)}, configuring either ID token or Server Auth Code\n     *                 options if you have a server. Later, in-context incrementally auth to additional scopes for other Google services access.\n     * @return A instance of {@link GoogleSignInClient}\n     */\n    @NonNull\n    public static GoogleSignInClient getClient(@NonNull Activity activity, @NonNull GoogleSignInOptions options) {\n        return new GoogleSignInClient(activity, options);\n    }\n\n    /**\n     * Gets the last account that the user signed in with.\n     *\n     * @return {@link GoogleSignInAccount} from last known successful sign-in. If user has never signed in before or has signed out / revoked\n     * access, {@code null} is returned.\n     */\n    @Nullable\n    public static GoogleSignInAccount getLastSignedInAccount(@NonNull Context context) {\n        return Storage.getInstance(context).getSavedDefaultGoogleSignInAccount();\n    }\n\n    /**\n     * Returns a {@link GoogleSignInAccount} present in the result data for the associated Activity started via\n     * {@link GoogleSignInClient#getSignInIntent()}.\n     *\n     * @param data the {@link Intent} returned via {@link Activity#onActivityResult(int, int, Intent)} when sign in completed.\n     * @return A completed {@link Task} containing a {@link GoogleSignInAccount} object.\n     */\n    @NonNull\n    public static Task<GoogleSignInAccount> getSignedInAccountFromIntent(@Nullable Intent data) {\n        GoogleSignInResult signInResultFromIntent = GoogleSignInCommon.getSignInResultFromIntent(data);\n        GoogleSignInAccount signInAccount = signInResultFromIntent.getSignInAccount();\n        return (!signInResultFromIntent.isSuccess() || signInAccount == null) ? Tasks.forException(new ApiException(signInResultFromIntent.getStatus())) : Tasks.forResult(signInAccount);\n    }\n\n    /**\n     * Determines if the given account has been granted permission to all scopes associated with the given extension.\n     *\n     * @param account   the account to be checked.\n     * @param extension the extension to be checked.\n     * @return {@code true} if the given account has been granted permission to all scopes associated with the given extension.\n     */\n    public static boolean hasPermissions(@Nullable GoogleSignInAccount account, @NonNull GoogleSignInOptionsExtension extension) {\n        return hasPermissions(account, extension.getImpliedScopes().toArray(new Scope[0]));\n    }\n\n    /**\n     * Determines if the given account has been granted permission to all given scopes.\n     *\n     * @param account the account to be checked.\n     * @param scopes  the collection of scopes to be checked.\n     * @return {@code true} if the given account has been granted permission to all given scopes.\n     */\n    public static boolean hasPermissions(@Nullable GoogleSignInAccount account, @NonNull Scope... scopes) {\n        if (account == null) return false;\n        Set<Scope> scopeSet = new HashSet<>();\n        Collections.addAll(scopeSet, scopes);\n        return account.getGrantedScopes().containsAll(scopeSet);\n    }\n\n    private static Intent createRequestPermissionsIntent(@NonNull Activity activity, @Nullable GoogleSignInAccount account, @NonNull Scope... scopes) {\n        GoogleSignInOptions.Builder builder = new GoogleSignInOptions.Builder();\n        if (scopes.length > 0) builder.requestScopes(scopes[0], scopes);\n        if (account != null && account.getEmail() != null && !account.getEmail().isEmpty())\n            builder.setAccountName(account.getEmail());\n        return getClient(activity, builder.build()).getSignInIntent();\n    }\n\n    /**\n     * Requests a collection of permissions to be granted to the given account. If the account does not have the requested permissions the user\n     * will be presented with a UI for accepting them. Once the user has accepted or rejected a response will returned via\n     * {@link Activity#onActivityResult(int, int, Intent)}.\n     *\n     * @param activity    the target activity that will receive the response.\n     * @param requestCode code associated with the request. It will match the {@code requestCode} associated with the response returned via {@link Activity#onActivityResult(int, int, Intent)}.\n     * @param account     the account for which the permissions will be requested. If {@code null} the user may have the option to choose.\n     * @param scopes      the extra collection of scopes to be requested.\n     */\n    public static void requestPermissions(@NonNull Activity activity, int requestCode, @Nullable GoogleSignInAccount account, @NonNull Scope... scopes) {\n        activity.startActivityForResult(createRequestPermissionsIntent(activity, account, scopes), requestCode);\n    }\n\n    /**\n     * Requests a collection of permissions associated with the given extension to be granted to the given account. If the account does not have\n     * the requested permissions the user will be presented with a UI for accepting them. Once the user has accepted or rejected a response will\n     * returned via {@link Activity#onActivityResult(int, int, Intent)}.\n     *\n     * @param activity    the target activity that will receive the response.\n     * @param requestCode code associated with the request. It will match the {@code requestCode} associated with the response returned via {@link Activity#onActivityResult(int, int, Intent)}.\n     * @param account     the account for which the permissions will be requested. If {@code null} the user may have the option to choose.\n     * @param extension   the extension associated with a set of permissions to be requested.\n     */\n    public static void requestPermissions(@NonNull Activity activity, int requestCode, @Nullable GoogleSignInAccount account, @NonNull GoogleSignInOptionsExtension extension) {\n        requestPermissions(activity, requestCode, account, extension.getImpliedScopes().toArray(new Scope[0]));\n    }\n\n    /**\n     * @param fragment the fragment to launch permission resolution Intent from.\n     */\n    public static void requestPermissions(@NonNull Fragment fragment, int requestCode, @Nullable GoogleSignInAccount account, @NonNull GoogleSignInOptionsExtension extension) {\n        requestPermissions(fragment, requestCode, account, extension.getImpliedScopes().toArray(new Scope[0]));\n    }\n\n    /**\n     * @param fragment the fragment to launch permission resolution Intent from.\n     */\n    public static void requestPermissions(@NonNull Fragment fragment, int requestCode, @Nullable GoogleSignInAccount account, @NonNull Scope... scopes) {\n        fragment.startActivityForResult(createRequestPermissionsIntent(fragment.getActivity(), account, scopes), requestCode);\n    }\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/signin/GoogleSignInApi.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.api.signin;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.OptionalPendingResult;\nimport com.google.android.gms.common.api.PendingResult;\nimport com.google.android.gms.common.api.Status;\n\n/**\n * Api interface for Sign In with Google.\n *\n * @deprecated Use Credential Manager for authentication or Google Identity Services for authorization.\n */\n@Deprecated\npublic interface GoogleSignInApi {\n    /**\n     * String {@link Intent} extra key for getting the SignInAccount from the {@link Intent} data returned on {@link Activity#onActivityResult(int, int, Intent)}\n     * when sign-in succeeded.\n     */\n    @NonNull\n    String EXTRA_SIGN_IN_ACCOUNT = \"signInAccount\";\n\n    /**\n     * Gets an {@link Intent} to start the Google Sign In flow by calling {@link Activity#startActivityForResult(Intent, int)}.\n     *\n     * @param client The {@link GoogleApiClient} to service the call.\n     * @return the {@link Intent} used for start the sign-in flow.\n     */\n    @NonNull\n    Intent getSignInIntent(GoogleApiClient client);\n\n    /**\n     * Helper function to extract out {@link GoogleSignInResult} from the {@link Activity#onActivityResult(int, int, Intent)} for Sign In.\n     *\n     * @param data the {@link Intent} returned on {@link Activity#onActivityResult(int, int, Intent)} when sign in completed.\n     * @return The {@link GoogleSignInResult} object. Make sure to pass the {@link Intent} you get back from {@link Activity#onActivityResult(int, int, Intent)\n     * for Sign In, otherwise result will be null.\n     */\n    @Nullable\n    GoogleSignInResult getSignInResultFromIntent(@NonNull Intent data);\n\n    /**\n     * Revokes access given to the current application. Future sign-in attempts will require the user to re-consent to all requested scopes.\n     * Applications are required to provide users that are signed in with Google the ability to disconnect their Google account from the app. If the\n     * user deletes their account, you must delete the information that your app obtained from the Google APIs.\n     *\n     * @param client The connected {@link GoogleApiClient} to service the call.\n     * @return the PendingResult for notification and access to the result when it's available.\n     */\n    @NonNull\n    PendingResult<Status> revokeAccess(@NonNull GoogleApiClient client);\n\n    /**\n     * Signs out the current signed-in user if any. It also clears the account previously selected by the user and a future sign in attempt will require\n     * the user pick an account again.\n     *\n     * @param client The connected {@link GoogleApiClient} to service the call.\n     * @return the PendingResult for notification and access to the result when it's available.\n     */\n    @NonNull\n    PendingResult<Status> signOut(@NonNull GoogleApiClient client);\n\n    /**\n     * Returns the {@link GoogleSignInAccount} information for the user who is signed in to this app. If no user is signed in, try to sign the\n     * user in without displaying any user interface.\n     * <p>\n     * Client activities may call the returned {@link OptionalPendingResult#isDone()} to decide whether to show a loading indicator and set callbacks\n     * to handle an asynchronous result, or directly proceed to the next step.\n     * <p>\n     * The GoogleSignInResult will possibly contain an ID token which may be used to authenticate and identify sessions that you establish with\n     * your application servers. If you use the ID token expiry time to determine your session lifetime, you should retrieve a refreshed ID token, by\n     * calling silentSignIn prior to each API call to your application server.\n     * <p>\n     * Calling silentSignIn can also help you detect user revocation of access to your application on other platforms and you can call\n     * {@link #getSignInIntent(GoogleApiClient)} again to ask the user to re-authorize.\n     * <p>\n     * If your user has never previously signed in to your app on the current device, we can still try to sign them in, without displaying user\n     * interface, if they have signed in on a different device.\n     * <p>\n     * We attempt to sign users in if:\n     * <ul>\n     *     <li>There is one and only one matching account on the device that has previously signed in to your application, and</li>\n     *     <li>the user previously granted all of the scopes your app is requesting for this sign in.</li>\n     * </ul>\n     *\n     * @param client The {@link GoogleApiClient} to service the call.\n     * @return {@link OptionalPendingResult} that will yield a {@link GoogleSignInResult}. Check for an immediate result with\n     * {@link OptionalPendingResult#isDone()}; or set a callback to handle asynchronous results.\n     */\n    @NonNull\n    OptionalPendingResult<GoogleSignInResult> silentSignIn(@NonNull GoogleApiClient client);\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/signin/GoogleSignInClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.api.signin;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.content.Intent;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.auth.api.Auth;\nimport com.google.android.gms.common.api.GoogleApi;\nimport com.google.android.gms.common.internal.PendingResultUtil;\nimport com.google.android.gms.tasks.Task;\nimport org.microg.gms.auth.api.signin.GoogleSignInCommon;\n\n/**\n * A client for interacting with the Google Sign In API.\n *\n * @deprecated Use Credential Manager for authentication or Google Identity Services for authorization.\n */\n@Deprecated\npublic class GoogleSignInClient extends GoogleApi<GoogleSignInOptions> {\n    GoogleSignInClient(@NonNull Context context, GoogleSignInOptions options) {\n        super(context, Auth.GOOGLE_SIGN_IN_API, options);\n    }\n\n    GoogleSignInClient(@NonNull Activity activity, GoogleSignInOptions options) {\n        super(activity, Auth.GOOGLE_SIGN_IN_API, options);\n    }\n\n    private boolean isLocalFallback() {\n        return false;\n    }\n\n    /**\n     * Gets an {@link Intent} to start the Google Sign In flow by calling {@link Activity#startActivityForResult(Intent, int)}.\n     *\n     * @return The {@link Intent} used for start the sign-in flow.\n     */\n    @NonNull\n    public Intent getSignInIntent() {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Revokes access given to the current application. Future sign-in attempts will require the user to re-consent to all requested scopes.\n     * Applications are required to provide users that are signed in with Google the ability to disconnect their Google account from the app. If the\n     * user deletes their account, you must delete the information that your app obtained from the Google APIs.\n     *\n     * @return A {@link Task} that may be used to check for failure, success or completion\n     */\n    @NonNull\n    public Task<Void> revokeAccess() {\n        return PendingResultUtil.toVoidTask(GoogleSignInCommon.revokeAccess(asGoogleApiClient(), getApplicationContext(), isLocalFallback()));\n    }\n\n    /**\n     * Signs out the current signed-in user if any. It also clears the account previously selected by the user and a future sign in attempt will require\n     * the user pick an account again.\n     *\n     * @return A {@link Task} that may be used to check for failure, success or completion\n     */\n    @NonNull\n    public Task<Void> signOut() {\n        return PendingResultUtil.toVoidTask(GoogleSignInCommon.signOut(asGoogleApiClient(), getApplicationContext(), isLocalFallback()));\n    }\n\n    /**\n     * Returns the {@link GoogleSignInAccount} information for the user who is signed in to this app. If no user is signed in, try to sign the\n     * user in without displaying any user interface.\n     * <p>\n     * The GoogleSignInAccount will possibly contain an ID token which may be used to authenticate and identify sessions that you establish with\n     * your application servers. If you use the ID token expiry time to determine your session lifetime, you should retrieve a refreshed ID token, by\n     * calling silentSignIn prior to each API call to your application server.\n     * <p>\n     * Calling silentSignIn can also help you detect user revocation of access to your application on other platforms and you can call\n     * {@link #getSignInIntent()} again to ask the user to re-authorize.\n     * <p>\n     * If your user has never previously signed in to your app on the current device, we can still try to sign them in, without displaying user\n     * interface, if they have signed in on a different device.\n     * <p>\n     * We attempt to sign users in if:\n     * <ul>\n     *     <li>There is one and only one matching account on the device that has previously signed in to your application, and</li>\n     *     <li>the user previously granted all of the scopes your app is requesting for this sign in.</li>\n     * </ul>\n     *\n     * @return A {@link Task} that will yield a {@link GoogleSignInAccount}. Check for an immediate result with {@link Task#isSuccessful()}; or set a\n     * callback to handle asynchronous results.\n     */\n    @NonNull\n    public Task<GoogleSignInAccount> silentSignIn() {\n        return PendingResultUtil.toTask(GoogleSignInCommon.silentSignIn(asGoogleApiClient(), getApplicationContext(), getApiOptions(), isLocalFallback()), (result) -> ((GoogleSignInResult) result).getSignInAccount());\n    }\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/signin/GoogleSignInResult.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.api.signin;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.api.Result;\nimport com.google.android.gms.common.api.Status;\nimport org.microg.gms.common.Hide;\n\n/**\n * GoogleSignInResults are {@link Result} implementations that potentially contain a {@link GoogleSignInAccount}.\n *\n * @deprecated Use Credential Manager for authentication or Google Identity Services for authorization.\n */\n@Deprecated\npublic class GoogleSignInResult implements Result {\n    @Nullable\n    private final GoogleSignInAccount signInAccount;\n    @NonNull\n    private final Status status;\n\n    @Hide\n    public GoogleSignInResult(@Nullable GoogleSignInAccount signInAccount, @NonNull Status status) {\n        this.signInAccount = signInAccount;\n        this.status = status;\n    }\n\n    /**\n     * Returns a {@link GoogleSignInAccount} reflecting the user's sign in information if sign-in completed successfully; or {@code null} when failed.\n     */\n    @Nullable\n    public GoogleSignInAccount getSignInAccount() {\n        return signInAccount;\n    }\n\n    /**\n     * Returns a {@link Status} object indicating the status of the sign in attempt.\n     * <p>\n     * You can use {@link #isSuccess()} to determine quickly if sign-in succeeded. If sign-in failed, you can match the status code retrieved from\n     * {@link Status#getStatusCode()} to consts defined in {@link GoogleSignInStatusCodes} and its parent class.\n     */\n    @NonNull\n    @Override\n    public Status getStatus() {\n        return status;\n    }\n\n    /**\n     * Convenient method to help you tell if sign-in completed successfully.\n     */\n    public boolean isSuccess() {\n        return status.isSuccess();\n    }\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/signin/GoogleSignInStatusCodes.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.api.signin;\n\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.api.CommonStatusCodes;\nimport com.google.android.gms.common.api.Status;\n\n/**\n * Google Sign In specific status codes, for use in {@link Status#getStatusCode()}.\n * <p>\n * In addition to codes defined in this class, you might also want to check:\n * <ul>\n *     <li>{@link CommonStatusCodes#SIGN_IN_REQUIRED}</li>\n *     <li>{@link CommonStatusCodes#NETWORK_ERROR}</li>\n *     <li>{@link CommonStatusCodes#INVALID_ACCOUNT}</li>\n *     <li>{@link CommonStatusCodes#INTERNAL_ERROR}</li>\n * </ul>\n */\n@Deprecated\npublic class GoogleSignInStatusCodes extends CommonStatusCodes {\n    private GoogleSignInStatusCodes() {\n        // Disallow instantiation\n    }\n\n    /**\n     * The sign in attempt didn't succeed with the current account.\n     * <p>\n     * Unlike {@link CommonStatusCodes#SIGN_IN_REQUIRED}. when seeing this error code, there is nothing user can do to recover from the sign in\n     * failure. Switching to another account may or may not help. Check adb log to see details if any.\n     */\n    public static final int SIGN_IN_FAILED = 12500;\n    /**\n     * The sign in was cancelled by the user. i.e. user cancelled some of the sign in resolutions, e.g. account picking or OAuth consent.\n     */\n    public static final int SIGN_IN_CANCELLED = 12501;\n    /**\n     * A sign in process is currently in progress and the current one cannot continue. e.g. the user clicks the SignInButton multiple times and more\n     * than one sign in intent was launched.\n     */\n    public static final int SIGN_IN_CURRENTLY_IN_PROGRESS = 12502;\n\n    /**\n     * Returns an untranslated debug (not user-friendly) string based on the current status code.\n     */\n    @NonNull\n    public static String getStatusCodeString(int statusCode) {\n        switch (statusCode) {\n            case SIGN_IN_FAILED:\n                return \"A non-recoverable sign in failure occurred\";\n            case SIGN_IN_CANCELLED:\n                return \"Sign in action cancelled\";\n            case SIGN_IN_CURRENTLY_IN_PROGRESS:\n                return \"Sign-in in progress\";\n            default:\n                return CommonStatusCodes.getStatusCodeString(statusCode);\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/signin/SignInAccount.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.api.signin;\n\nimport androidx.annotation.NonNull;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.utils.ToStringHelper;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n@Hide\npublic class SignInAccount extends AutoSafeParcelable {\n    @Field(4)\n    public String email;\n    @Field(7)\n    public GoogleSignInAccount googleSignInAccount;\n    @Field(8)\n    public String userId;\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"SignInAccount\").field(\"email\", email).field(\"account\", googleSignInAccount).field(\"userId\", userId).end();\n    }\n\n    public static final Creator<SignInAccount> CREATOR = findCreator(SignInAccount.class);\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/api/signin/internal/SignInConfiguration.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.api.signin.internal;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.auth.api.signin.GoogleSignInOptions;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.Objects;\n\n@Hide\n@SafeParcelable.Class\npublic class SignInConfiguration extends AbstractSafeParcelable {\n    @Field(value = 2, getterName = \"getPackageName\")\n    @NonNull\n    private final String packageName;\n    @Field(value = 5, getterName = \"getOptions\")\n    @NonNull\n    private final GoogleSignInOptions options;\n\n    @Constructor\n    public SignInConfiguration(@Param(2) @NonNull String packageName, @Param(5) @NonNull GoogleSignInOptions options) {\n        this.packageName = packageName;\n        this.options = options;\n    }\n\n    @NonNull\n    public String getPackageName() {\n        return packageName;\n    }\n\n    @NonNull\n    public GoogleSignInOptions getOptions() {\n        return options;\n    }\n\n\n    @Override\n    public final boolean equals(Object o) {\n        if (!(o instanceof SignInConfiguration)) return false;\n\n        SignInConfiguration that = (SignInConfiguration) o;\n        return packageName.equals(that.packageName) && Objects.equals(options, that.options);\n    }\n\n    @Override\n    public int hashCode() {\n        int hash = packageName.hashCode() + 31;\n        hash = Objects.hashCode(options) + (hash * 31);;\n        return hash;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"SignInConfiguration\").field(\"packageName\", packageName).field(\"options\", options).end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<SignInConfiguration> CREATOR = findCreator(SignInConfiguration.class);\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/com/google/android/gms/auth/package-info.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n/**\n * Contains classes for authenticating Google accounts.\n */\npackage com.google.android.gms.auth;\n"
  },
  {
    "path": "play-services-auth/src/main/java/org/microg/gms/auth/api/signin/GoogleSignInApiImpl.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth.api.signin;\n\nimport android.content.Intent;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.auth.api.Auth;\nimport com.google.android.gms.auth.api.signin.GoogleSignInApi;\nimport com.google.android.gms.auth.api.signin.GoogleSignInResult;\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.OptionalPendingResult;\nimport com.google.android.gms.common.api.PendingResult;\nimport com.google.android.gms.common.api.Status;\n\npublic class GoogleSignInApiImpl implements GoogleSignInApi {\n    @NonNull\n    @Override\n    public Intent getSignInIntent(GoogleApiClient client) {\n        throw new UnsupportedOperationException();\n        //return GoogleSignInCommon.getSignInIntent(client.getContext(), client.getClient(Auth.GOOGLE_SIGN_IN_API_CLIENT_KEY).getOptions());\n    }\n\n    @Nullable\n    @Override\n    public GoogleSignInResult getSignInResultFromIntent(@NonNull Intent data) {\n        return GoogleSignInCommon.getSignInResultFromIntent(data);\n    }\n\n    @NonNull\n    @Override\n    public PendingResult<Status> revokeAccess(@NonNull GoogleApiClient client) {\n        return GoogleSignInCommon.revokeAccess(client, client.getContext(), false);\n    }\n\n    @NonNull\n    @Override\n    public PendingResult<Status> signOut(@NonNull GoogleApiClient client) {\n        return GoogleSignInCommon.signOut(client, client.getContext(), false);\n    }\n\n    @NonNull\n    @Override\n    public OptionalPendingResult<GoogleSignInResult> silentSignIn(@NonNull GoogleApiClient client) {\n        throw new UnsupportedOperationException();\n        //return GoogleSignInCommon.silentSignIn(client, client.getContext(), client.getClient(Auth.GOOGLE_SIGN_IN_API_CLIENT_KEY).getOptions());\n    }\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/org/microg/gms/auth/api/signin/GoogleSignInCommon.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth.api.signin;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.auth.api.signin.GoogleSignInAccount;\nimport com.google.android.gms.auth.api.signin.GoogleSignInOptions;\nimport com.google.android.gms.auth.api.signin.GoogleSignInResult;\nimport com.google.android.gms.auth.api.signin.internal.SignInConfiguration;\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.OptionalPendingResult;\nimport com.google.android.gms.common.api.PendingResult;\nimport com.google.android.gms.common.api.Status;\n\npublic class GoogleSignInCommon {\n\n    @NonNull\n    public static Intent getSignInIntent(Context context, GoogleSignInOptions options) {\n        SignInConfiguration configuration = new SignInConfiguration(context.getPackageName(), options);\n        Bundle configurationBundle = new Bundle();\n        configurationBundle.putParcelable(\"config\", configuration);\n        Intent intent = new Intent(\"com.google.android.gms.auth.GOOGLE_SIGN_IN\");\n        intent.setPackage(context.getPackageName());\n        //intent.setClass(context, GoogleSignInHub.class);\n        intent.putExtra(\"config\", configurationBundle);\n        return intent;\n    }\n\n    @NonNull\n    public static GoogleSignInResult getSignInResultFromIntent(@Nullable Intent data) {\n        if (data == null) return new GoogleSignInResult(null, Status.INTERNAL_ERROR);\n        Status status = data.getParcelableExtra(\"googleSignInStatus\");\n        GoogleSignInAccount account = data.getParcelableExtra(\"googleSignInAccount\");\n        if (account != null) return new GoogleSignInResult(account, Status.SUCCESS);\n        if (status == null) status = Status.INTERNAL_ERROR;\n        return new GoogleSignInResult(null, status);\n    }\n\n    public static PendingResult<Status> revokeAccess(GoogleApiClient client, Context context, boolean isLocalFallback) {\n        throw new UnsupportedOperationException();\n    }\n\n    public static PendingResult<Status> signOut(GoogleApiClient client, Context context, boolean isLocalFallback) {\n        throw new UnsupportedOperationException();\n    }\n\n    public static OptionalPendingResult<GoogleSignInResult> silentSignIn(GoogleApiClient client, Context context, GoogleSignInOptions options, boolean isLocalFallback) {\n        throw new UnsupportedOperationException();\n    }\n}\n"
  },
  {
    "path": "play-services-auth/src/main/java/org/microg/gms/auth/api/signin/GoogleSignInGmsClientImpl.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth.api.signin;\n\nimport android.content.Context;\nimport android.os.IBinder;\nimport com.google.android.gms.auth.api.signin.internal.ISignInService;\nimport org.microg.gms.common.GmsClient;\nimport org.microg.gms.common.GmsService;\nimport com.google.android.gms.common.api.internal.ConnectionCallbacks;\nimport com.google.android.gms.common.api.internal.OnConnectionFailedListener;\n\npublic class GoogleSignInGmsClientImpl extends GmsClient<ISignInService> {\n    public GoogleSignInGmsClientImpl(Context context, ConnectionCallbacks callbacks, OnConnectionFailedListener connectionFailedListener) {\n        super(context, callbacks, connectionFailedListener, GmsService.AUTH_GOOGLE_SIGN_IN.ACTION);\n        serviceId = GmsService.AUTH_GOOGLE_SIGN_IN.SERVICE_ID;\n    }\n\n    @Override\n    protected ISignInService interfaceFromBinder(IBinder binder) {\n        return ISignInService.Stub.asInterface(binder);\n    }\n}\n"
  },
  {
    "path": "play-services-auth-api/src/main/java/com/google/android/gms/auth/api/identity/package-info.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n/**\n * Provides facilities to retrieve or save credentials that can be used to\n          sign the user into your application or sign up a new user.\n */\npackage com.google.android.gms.auth.api.identity;\n"
  },
  {
    "path": "play-services-auth-api-phone/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\nandroid {\n    namespace \"com.google.android.gms.auth.api.phone\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n}\n\napply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG implementation of play-services-auth-api-phone'\n\ndependencies {\n    // Dependencies from play-services-auth-api-phone:18.2.0\n    api project(':play-services-base')\n    api project(':play-services-basement')\n    api project(':play-services-tasks')\n    api 'org.jetbrains.kotlin:kotlin-stdlib:1.8.21'\n    api 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.21'\n    api 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.3'\n    // api 'org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.6.0'\n}\n"
  },
  {
    "path": "play-services-auth-api-phone/core/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'kotlin-android'\n\ndependencies {\n    api project(':play-services-auth-api-phone')\n    implementation project(':play-services-base-core')\n\n    implementation \"androidx.appcompat:appcompat:$appcompatVersion\"\n}\n\nandroid {\n    namespace \"org.microg.gms.auth.phone\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    sourceSets {\n        main.java.srcDirs += 'src/main/kotlin'\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n\n    kotlinOptions {\n        jvmTarget = 1.8\n    }\n\n    lintOptions {\n        disable 'MissingTranslation', 'GetLocales'\n    }\n}\n"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <uses-permission android:name=\"android.permission.RECEIVE_SMS\" />\n\n    <application>\n\n        <activity\n            android:name=\"org.microg.gms.auth.phone.UserConsentPromptActivity\"\n            android:exported=\"true\"\n            android:process=\":ui\"\n            android:theme=\"@style/Theme.AppCompat.DayNight.Dialog.Alert.NoActionBar\" />\n\n        <activity\n            android:name=\"org.microg.gms.auth.phone.AskPermissionActivity\"\n            android:excludeFromRecents=\"true\"\n            android:exported=\"false\"\n            android:process=\":ui\"\n            android:theme=\"@style/Theme.Translucent\" />\n\n        <service\n            android:name=\"org.microg.gms.auth.phone.SmsRetrieverService\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.auth.api.phone.service.SmsRetrieverApiService.START\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </service>\n    </application>\n</manifest>\n"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/kotlin/org/microg/gms/auth/phone/AskPermissionActivity.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth.phone\n\nimport android.Manifest\nimport android.content.Intent\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.Bundle\nimport android.os.Message\nimport android.os.Messenger\nimport android.util.Log\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.core.app.ActivityCompat\nimport androidx.core.os.bundleOf\n\nprivate const val TAG = \"AskPermission\"\nprivate const val REQUEST_CODE_PERMISSION = 101\nprivate val ALLOWED_PERMISSIONS = setOf(Manifest.permission.RECEIVE_SMS, Manifest.permission.READ_CONTACTS)\n\nclass AskPermissionActivity : AppCompatActivity() {\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        val permissions = intent.getStringArrayExtra(EXTRA_PERMISSIONS) ?: arrayOf(Manifest.permission.RECEIVE_SMS)\n        Log.d(TAG, \"Requesting permissions: ${permissions.toList()}\")\n        if (SDK_INT < 23 || permissions.any { it !in ALLOWED_PERMISSIONS }) {\n            sendReply(RESULT_CANCELED)\n            finish()\n        } else {\n            ActivityCompat.requestPermissions(this, permissions, REQUEST_CODE_PERMISSION)\n        }\n    }\n\n    private fun sendReply(code: Int = RESULT_OK, extras: Bundle = Bundle.EMPTY) {\n        intent.getParcelableExtra<Messenger>(EXTRA_MESSENGER)?.let {\n            it.send(Message.obtain().apply {\n                what = code\n                data = extras\n            })\n        }\n        setResult(code, Intent().apply { putExtras(extras) })\n    }\n\n    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {\n        if (requestCode == REQUEST_CODE_PERMISSION) {\n            sendReply(extras = bundleOf(EXTRA_GRANT_RESULTS to grantResults))\n            finish()\n        } else {\n            super.onRequestPermissionsResult(requestCode, permissions, grantResults)\n        }\n    }\n}"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/kotlin/org/microg/gms/auth/phone/SmsRetrieverCore.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth.phone\n\nimport android.Manifest.permission.READ_CONTACTS\nimport android.Manifest.permission.RECEIVE_SMS\nimport android.annotation.TargetApi\nimport android.app.Activity\nimport android.app.AlarmManager\nimport android.app.PendingIntent\nimport android.content.BroadcastReceiver\nimport android.content.Context\nimport android.content.Intent\nimport android.content.IntentFilter\nimport android.content.pm.PackageManager.PERMISSION_GRANTED\nimport android.database.Cursor\nimport android.os.*\nimport android.os.Build.VERSION.SDK_INT\nimport android.provider.ContactsContract\nimport android.provider.ContactsContract.CommonDataKinds.Phone\nimport android.provider.Telephony\nimport android.telephony.SmsMessage\nimport android.text.TextUtils\nimport android.util.Base64\nimport android.util.Log\nimport androidx.core.app.PendingIntentCompat\nimport androidx.core.content.ContextCompat\nimport androidx.core.os.bundleOf\nimport androidx.lifecycle.DefaultLifecycleObserver\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.LifecycleOwner\nimport com.google.android.gms.auth.api.phone.SmsRetriever\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.api.Status\nimport kotlinx.coroutines.CompletableDeferred\nimport kotlinx.coroutines.Deferred\nimport kotlinx.coroutines.sync.Mutex\nimport kotlinx.coroutines.sync.withLock\nimport org.microg.gms.auth.phone.SmsRetrieverRequestType.RETRIEVER\nimport org.microg.gms.auth.phone.SmsRetrieverRequestType.USER_CONSENT\nimport org.microg.gms.common.Constants\nimport org.microg.gms.utils.getSignatures\nimport java.nio.charset.StandardCharsets\nimport java.security.MessageDigest\nimport java.util.concurrent.atomic.AtomicInteger\n\n\nprivate const val TAG = \"SmsRetrieverCore\"\n\nprivate const val ACTION_SMS_RETRIEVE_TIMEOUT = \"org.microg.gms.auth.phone.ACTION_SMS_RETRIEVE_TIMEOUT\"\nprivate const val EXTRA_REQUEST_ID = \"requestId\"\nprivate const val TIMEOUT = 1000 * 60 * 5 // 5 minutes\nprivate const val MESSAGE_MAX_LEN = 140\n\nclass SmsRetrieverCore(private val context: Context, override val lifecycle: Lifecycle) : LifecycleOwner, DefaultLifecycleObserver {\n    private val requests: HashMap<Int, SmsRetrieverRequest> = hashMapOf()\n    private val requestIdCounter = AtomicInteger(0)\n    private lateinit var timeoutBroadcastReceiver: BroadcastReceiver\n    private lateinit var smsBroadcastReceiver: BroadcastReceiver\n    private var requestCode = 0\n    private val alarmManager: AlarmManager\n        get() = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager\n\n    init {\n        lifecycle.addObserver(this)\n    }\n\n    @TargetApi(19)\n    private fun configureBroadcastListenersIfNeeded() {\n        synchronized(this) {\n            if (!this::timeoutBroadcastReceiver.isInitialized) {\n                val intentFilter = IntentFilter(ACTION_SMS_RETRIEVE_TIMEOUT)\n                timeoutBroadcastReceiver = TimeoutReceiver()\n                ContextCompat.registerReceiver(context, timeoutBroadcastReceiver, intentFilter, ContextCompat.RECEIVER_NOT_EXPORTED)\n            }\n            if (!this::smsBroadcastReceiver.isInitialized) {\n                val intentFilter = IntentFilter(Telephony.Sms.Intents.SMS_RECEIVED_ACTION)\n                intentFilter.priority = 999\n                smsBroadcastReceiver = SmsReceiver()\n                context.registerReceiver(smsBroadcastReceiver, intentFilter)\n            }\n        }\n    }\n\n    private suspend fun ensureReady(permissions: Array<String>): Boolean {\n        if (SDK_INT < 19) throw RuntimeException(\"Version not supported\")\n        if (!ensurePermission(permissions)) return false\n        configureBroadcastListenersIfNeeded()\n        return true\n    }\n\n    suspend fun startSmsRetriever(packageName: String) {\n        val appHashString = getHashString(packageName)\n\n        if (!ensureReady(arrayOf(RECEIVE_SMS)))\n            throw RuntimeException(\"Initialization failed\")\n        if (anyOtherPackageHasHashString(packageName, appHashString))\n            throw RuntimeException(\"Collision in hash string, can't use SMS Retriever API\")\n        if (requests.values.any { it.packageName == packageName && it.appHashString == appHashString && it.type == RETRIEVER })\n            throw RuntimeException(\"App already listening\")\n\n        val request = SmsRetrieverRequest(\n            id = requestIdCounter.incrementAndGet(),\n            type = RETRIEVER,\n            packageName = packageName,\n            appHashString = appHashString,\n            timeoutPendingIntent = getTimeoutPendingIntent(context, packageName)\n        )\n        requests[request.id] = request\n        alarmManager.set(AlarmManager.RTC, request.creation + TIMEOUT, request.timeoutPendingIntent)\n    }\n\n    suspend fun startWithConsentPrompt(packageName: String, senderPhoneNumber: String?) {\n        if (!ensureReady(arrayOf(RECEIVE_SMS, READ_CONTACTS)))\n            throw RuntimeException(\"Initialization failed\")\n        if (requests.values.any { it.packageName == packageName && it.senderPhoneNumber == senderPhoneNumber && it.type == USER_CONSENT })\n            throw RuntimeException(\"App already listening\")\n\n        val request = SmsRetrieverRequest(\n            id = requestIdCounter.incrementAndGet(),\n            type = USER_CONSENT,\n            packageName = packageName,\n            senderPhoneNumber = senderPhoneNumber,\n            timeoutPendingIntent = getTimeoutPendingIntent(context, packageName)\n        )\n        requests[request.id] = request\n        alarmManager.set(AlarmManager.RTC, request.creation + TIMEOUT, request.timeoutPendingIntent)\n    }\n\n    fun hasOngoingUserConsentRequest(): Boolean {\n        return requests.values.any { it.type == USER_CONSENT }\n    }\n\n    private fun sendRetrieverBroadcast(request: SmsRetrieverRequest, messageBody: String) {\n        sendReply(request, Status.SUCCESS, bundleOf(SmsRetriever.EXTRA_SMS_MESSAGE to messageBody))\n    }\n\n    private fun sendUserConsentBroadcast(request: SmsRetrieverRequest, messageBody: String) {\n        val userConsentIntent = Intent(context, UserConsentPromptActivity::class.java)\n        userConsentIntent.setPackage(Constants.GMS_PACKAGE_NAME)\n        userConsentIntent.putExtra(EXTRA_MESSENGER, Messenger(object : Handler(Looper.getMainLooper()) {\n            override fun handleMessage(msg: Message) {\n                if (Binder.getCallingUid() == Process.myUid()) {\n                    if (msg.what == MSG_REQUEST_MESSAGE_BODY) {\n                        msg.replyTo?.send(Message.obtain().apply {\n                            what = 1\n                            data = bundleOf(\"message\" to messageBody)\n                        })\n                    } else if (msg.what == MSG_CONSUME_MESSAGE) {\n                        finishRequest(request)\n                    }\n                }\n            }\n        }))\n\n        sendReply(request, Status.SUCCESS, bundleOf(SmsRetriever.EXTRA_CONSENT_INTENT to userConsentIntent), false)\n    }\n\n    private fun getTimeoutPendingIntent(context: Context, packageName: String): PendingIntent {\n        val intent = Intent(ACTION_SMS_RETRIEVE_TIMEOUT)\n        intent.setPackage(packageName)\n        return PendingIntentCompat.getBroadcast(context, ++requestCode, intent, 0, false)!!\n    }\n\n    private fun tryHandleIncomingMessageAsRetrieverMessage(messageBody: String): Boolean {\n        for (request in requests.values) {\n            if (request.type == RETRIEVER) {\n                // 11-digit hash code that uniquely identifies your app\n                if (request.appHashString.isNullOrBlank() || !messageBody.contains(request.appHashString)) continue\n\n                sendRetrieverBroadcast(request, messageBody)\n                return true\n            }\n        }\n        return false\n    }\n\n    private fun tryHandleIncomingMessageAsUserConsentMessage(senderPhoneNumber: String?, messageBody: String): Boolean {\n        val senderPhoneNumber = senderPhoneNumber ?: return false\n\n        // 4-10 digit alphanumeric code containing at least one number\n        if (messageBody.split(\"[^A-Za-z0-9]\".toRegex()).none { it.length in 4..10 && it.any(Char::isDigit) }) return false\n\n        // Sender cannot be in the user's Contacts list\n        if (isPhoneNumberInContacts(context, senderPhoneNumber)) return false\n\n        for (request in requests.values) {\n            if (request.type == USER_CONSENT) {\n                if (!request.senderPhoneNumber.isNullOrBlank() && request.senderPhoneNumber != senderPhoneNumber) continue\n\n                sendUserConsentBroadcast(request, messageBody)\n                return true\n            }\n        }\n        return false\n    }\n\n    private fun handleIncomingSmsMessage(senderPhoneNumber: String?, messageBody: String) {\n        Log.d(TAG, \"handleIncomingSmsMessage: senderPhoneNumber:$senderPhoneNumber messageBody: $messageBody\")\n        if (messageBody.isBlank()) return\n\n        if (tryHandleIncomingMessageAsRetrieverMessage(messageBody)) return\n        if (tryHandleIncomingMessageAsUserConsentMessage(senderPhoneNumber, messageBody)) return\n    }\n\n    fun handleTimeout(requestId: Int) {\n        val request = requests[requestId] ?: return\n        sendReply(request, Status(CommonStatusCodes.TIMEOUT))\n    }\n\n    private fun sendReply(request: SmsRetrieverRequest, status: Status, extras: Bundle = Bundle.EMPTY, finish: Boolean = true) {\n        Log.d(TAG, \"Send reply to ${request.packageName} ${CommonStatusCodes.getStatusCodeString(status.statusCode)}\")\n\n        val intent = Intent(SmsRetriever.SMS_RETRIEVED_ACTION)\n        intent.setPackage(request.packageName)\n        intent.putExtras(extras)\n        intent.putExtra(SmsRetriever.EXTRA_STATUS, status)\n        context.sendBroadcast(intent)\n\n        if (finish) finishRequest(request)\n    }\n\n    fun finishRequest(request: SmsRetrieverRequest) {\n        alarmManager.cancel(request.timeoutPendingIntent)\n        requests.remove(request.id)\n    }\n\n    override fun onDestroy(owner: LifecycleOwner) {\n        super.onDestroy(owner)\n\n        if (this::smsBroadcastReceiver.isInitialized) context.unregisterReceiver(smsBroadcastReceiver)\n        if (this::timeoutBroadcastReceiver.isInitialized) context.unregisterReceiver(timeoutBroadcastReceiver)\n\n        for (request in requests.values) {\n            sendReply(request, Status(CommonStatusCodes.TIMEOUT))\n        }\n\n        requests.clear()\n    }\n\n    @TargetApi(19)\n    private inner class SmsReceiver : BroadcastReceiver() {\n        override fun onReceive(context: Context, intent: Intent) {\n            if (Telephony.Sms.Intents.SMS_RECEIVED_ACTION == intent.action) {\n                val messages = Telephony.Sms.Intents.getMessagesFromIntent(intent)\n                val messageBodyBuilder = StringBuilder()\n                var senderPhoneNumber: String? = null\n                for (message in messages) {\n                    messageBodyBuilder.append(message.messageBody)\n                    senderPhoneNumber = message.originatingAddress\n                }\n                try {\n                    handleIncomingSmsMessage(senderPhoneNumber, messageBodyBuilder.toString())\n                } catch (e: Exception) {\n                    Log.w(TAG, \"Error handling incoming SMS\", e)\n                }\n            }\n        }\n    }\n\n    private inner class TimeoutReceiver : BroadcastReceiver() {\n        override fun onReceive(context: Context, intent: Intent) {\n            val requestId = intent.getIntExtra(EXTRA_REQUEST_ID, -1)\n            if (requestId != -1) {\n                handleTimeout(requestId)\n            }\n        }\n    }\n\n    @TargetApi(19)\n    fun getHashString(packageName: String): String {\n        val signature =\n            context.packageManager.getSignatures(packageName).firstOrNull()?.toCharsString() ?: throw RuntimeException(\"No signature found for $packageName\")\n        val appInfo = \"$packageName $signature\"\n        val messageDigest = MessageDigest.getInstance(\"SHA-256\")\n        messageDigest.update(appInfo.toByteArray(StandardCharsets.UTF_8))\n        return Base64.encodeToString(messageDigest.digest(), Base64.NO_PADDING or Base64.NO_WRAP).substring(0, 11)\n    }\n\n    private fun anyOtherPackageHasHashString(packageName: String, hashString: String): Boolean {\n        val collision = context.packageManager.getInstalledPackages(0)\n            .firstOrNull { it.packageName != packageName && getHashString(it.packageName) == hashString } ?: return false\n\n        Log.w(TAG, \"Hash string collision between $packageName and ${collision.packageName} (both are $hashString)\")\n        return true\n    }\n\n    private fun isPhoneNumberInContacts(context: Context, phoneNumber: String): Boolean {\n        fun normalizePhoneNumber(input: String): String {\n            var output = \"\"\n            if (!TextUtils.isEmpty(input)) {\n                // only keep digits\n                val temp = input.replace(\"[^0-9]\".toRegex(), \"\")\n                // trim leading zeroes\n                output = temp.replaceFirst(\"^0*\".toRegex(), \"\")\n            }\n            return output\n        }\n\n        val normalizePhoneNumber = normalizePhoneNumber(phoneNumber)\n        var cursor: Cursor? = null\n        try {\n            cursor = context.contentResolver.query(Phone.CONTENT_URI, arrayOf(Phone.NUMBER), null, null, null) ?: return false\n            while (cursor.moveToNext()) {\n                val addressIndex = cursor.getColumnIndex(Phone.NUMBER)\n                val contactPhoneNumber = normalizePhoneNumber(cursor.getString(addressIndex))\n                if (!TextUtils.isEmpty(normalizePhoneNumber) && !TextUtils.isEmpty(contactPhoneNumber) && normalizePhoneNumber == contactPhoneNumber) {\n                    return true\n                }\n            }\n        } catch (e: Exception) {\n            Log.w(TAG, e)\n        } finally {\n            cursor?.close()\n        }\n        return false\n    }\n\n    private val activePermissionRequestLock = Mutex()\n    private var activePermissionRequest: Deferred<Boolean>? = null\n\n    private suspend fun ensurePermission(permissions: Array<String>): Boolean {\n        if (SDK_INT < 23)\n            return true\n\n        if (permissions.all { ContextCompat.checkSelfPermission(context, it) == PERMISSION_GRANTED })\n            return true\n\n        val (completable, deferred) = activePermissionRequestLock.withLock {\n            if (activePermissionRequest == null) {\n                val completable = CompletableDeferred<Boolean>()\n                activePermissionRequest = completable\n                completable to activePermissionRequest!!\n            } else {\n                null to activePermissionRequest!!\n            }\n        }\n        if (completable != null) {\n            val intent = Intent(context, AskPermissionActivity::class.java)\n            intent.putExtra(EXTRA_MESSENGER, Messenger(object : Handler(Looper.getMainLooper()) {\n                override fun handleMessage(msg: Message) {\n                    if (msg.what == Activity.RESULT_OK) {\n                        val grantResults = msg.data?.getIntArray(EXTRA_GRANT_RESULTS) ?: IntArray(0)\n                        completable.complete(grantResults.size == permissions.size && grantResults.all { it == PERMISSION_GRANTED })\n                    } else {\n                        completable.complete(false)\n                    }\n                }\n            }))\n            intent.putExtra(EXTRA_PERMISSIONS, permissions)\n            intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK\n            context.startActivity(intent)\n        }\n        return deferred.await()\n    }\n}"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/kotlin/org/microg/gms/auth/phone/SmsRetrieverRequest.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth.phone\n\nimport android.app.PendingIntent\n\ndata class SmsRetrieverRequest(\n    val id: Int,\n    val type: SmsRetrieverRequestType,\n    val packageName: String,\n    val timeoutPendingIntent: PendingIntent,\n    val appHashString: String? = null,\n    val creation: Long = System.currentTimeMillis(),\n    val senderPhoneNumber: String? = null\n)\n\nenum class SmsRetrieverRequestType {\n    RETRIEVER, USER_CONSENT\n}"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/kotlin/org/microg/gms/auth/phone/SmsRetrieverService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth.phone\n\nimport android.util.Log\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.LifecycleOwner\nimport androidx.lifecycle.lifecycleScope\nimport com.google.android.gms.auth.api.phone.SmsRetrieverStatusCodes\nimport com.google.android.gms.auth.api.phone.internal.IAutofillPermissionStateCallback\nimport com.google.android.gms.auth.api.phone.internal.IOngoingSmsRequestCallback\nimport com.google.android.gms.auth.api.phone.internal.ISmsRetrieverApiService\nimport com.google.android.gms.auth.api.phone.internal.ISmsRetrieverResultCallback\nimport com.google.android.gms.common.Feature\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.api.internal.IStatusCallback\nimport com.google.android.gms.common.internal.ConnectionInfo\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.common.PackageUtils\n\n\nprivate const val TAG = \"SmsRetrieverService\"\nprivate val FEATURES = arrayOf(\n    Feature(\"sms_retrieve\", 1),\n    Feature(\"user_consent\", 3)\n)\n\nclass SmsRetrieverService : BaseService(TAG, GmsService.SMS_RETRIEVER) {\n    private val smsRetriever = SmsRetrieverCore(this, lifecycle)\n\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        val packageName = PackageUtils.getAndCheckCallingPackage(this, request.packageName)\n            ?: throw IllegalArgumentException(\"Missing package name\")\n        callback.onPostInitCompleteWithConnectionInfo(\n            CommonStatusCodes.SUCCESS,\n            SmsRetrieverServiceImpl(smsRetriever, packageName, lifecycle),\n            ConnectionInfo().apply { features = FEATURES }\n        )\n    }\n}\n\n\nclass SmsRetrieverServiceImpl(private val smsRetriever: SmsRetrieverCore, private val packageName: String, override val lifecycle: Lifecycle) :\n    ISmsRetrieverApiService.Stub(), LifecycleOwner {\n\n    override fun startSmsRetriever(callback: ISmsRetrieverResultCallback) {\n        Log.d(TAG, \"startSmsRetriever()\")\n        lifecycleScope.launchWhenStarted {\n            val status = try {\n                smsRetriever.startSmsRetriever(packageName)\n                Status.SUCCESS\n            } catch (e: Exception) {\n                Status(CommonStatusCodes.INTERNAL_ERROR, e.message)\n            }\n            try {\n                callback.onResult(status)\n            } catch (e: Exception) {\n                Log.w(TAG, \"Failed delivering $status for startSmsRetriever()\", e)\n            }\n        }\n    }\n\n    override fun startWithConsentPrompt(senderPhoneNumber: String?, callback: ISmsRetrieverResultCallback) {\n        Log.d(TAG, \"startWithConsentPrompt($senderPhoneNumber)\")\n        lifecycleScope.launchWhenStarted {\n            val status = try {\n                smsRetriever.startWithConsentPrompt(packageName, senderPhoneNumber)\n                Status.SUCCESS\n            } catch (e: Exception) {\n                Status(CommonStatusCodes.INTERNAL_ERROR, e.message)\n            }\n            try {\n                callback.onResult(status)\n            } catch (e: Exception) {\n                Log.w(TAG, \"Failed delivering $status for startWithConsentPrompt()\", e)\n            }\n        }\n    }\n\n    override fun startSmsCodeAutofill(callback: IStatusCallback) {\n        Log.d(TAG, \"startSmsCodeAutofill()\")\n        try {\n            callback.onResult(Status(SmsRetrieverStatusCodes.API_NOT_AVAILABLE))\n        } catch (e: Exception) {\n            Log.w(TAG, \"Failed delivering result for startSmsCodeAutofill()\", e)\n        }\n    }\n\n    override fun checkAutofillPermissionState(callback: IAutofillPermissionStateCallback) {\n        Log.d(TAG, \"checkAutofillPermissionState()\")\n        try {\n            callback.onCheckPermissionStateResult(Status.SUCCESS, 1)\n        } catch (e: Exception) {\n            Log.w(TAG, \"Failed delivering result for checkAutofillPermissionState()\", e)\n        }\n    }\n\n    override fun checkOngoingSmsRequest(packageName: String?, callback: IOngoingSmsRequestCallback) {\n        Log.d(TAG, \"checkOngoingSmsRequest($packageName)\")\n        lifecycleScope.launchWhenStarted {\n            val result = try {\n                smsRetriever.hasOngoingUserConsentRequest()\n            } catch (e: Exception) {\n                true\n            }\n\n            try {\n                callback.onHasOngoingSmsRequestResult(Status.SUCCESS, result)\n            } catch (e: Exception) {\n                Log.w(TAG, \"Failed delivering $result for checkOngoingSmsRequest()\", e)\n            }\n        }\n    }\n\n\n    override fun startSmsCodeBrowser(callback: IStatusCallback) {\n        Log.d(TAG, \"startSmsCodeBrowser()\")\n        try {\n            callback.onResult(Status(SmsRetrieverStatusCodes.API_NOT_AVAILABLE))\n        } catch (e: Exception) {\n            Log.w(TAG, \"Failed delivering result for startSmsCodeBrowser()\", e)\n        }\n    }\n}"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/kotlin/org/microg/gms/auth/phone/UserConsentPromptActivity.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth.phone\n\nimport android.annotation.TargetApi\nimport android.content.Intent\nimport android.os.*\nimport android.text.Html\nimport android.view.Gravity\nimport android.view.ViewGroup.LayoutParams\nimport android.widget.Button\nimport android.widget.TextView\nimport androidx.appcompat.app.AppCompatActivity\nimport com.google.android.gms.auth.api.phone.SmsRetriever\nimport org.microg.gms.ui.buildAlertDialog\nimport org.microg.gms.utils.getApplicationLabel\n\nprivate const val TAG = \"UserConsentPrompt\"\n\nclass UserConsentPromptActivity : AppCompatActivity() {\n    private val messenger: Messenger?\n        get() = intent.getParcelableExtra(EXTRA_MESSENGER)\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n\n        val callingPackage = callingActivity?.packageName ?: return finish()\n        val messenger = messenger ?: return finish()\n        messenger.send(Message.obtain().apply {\n            what = MSG_REQUEST_MESSAGE_BODY\n            replyTo = Messenger(object : Handler(Looper.getMainLooper()) {\n                override fun handleMessage(msg: Message) {\n                    if (msg.what == MSG_REQUEST_MESSAGE_BODY) {\n                        val message = msg.data.getString(\"message\") ?: return\n                        showConsentDialog(callingPackage, message)\n                    }\n                }\n            })\n        })\n    }\n\n    @TargetApi(16)\n    private fun showConsentDialog(callingPackage: String, message: String) {\n        val view = layoutInflater.inflate(R.layout.dialog_sms_user_consent, null)\n        val dialog = buildAlertDialog()\n            .setCancelable(false)\n            .setView(view)\n            .create()\n        val appName = packageManager.getApplicationLabel(callingPackage)\n\n        view.findViewById<TextView>(android.R.id.title).text = Html.fromHtml(getString(R.string.sms_user_consent_title, Html.escapeHtml(appName)))\n        view.findViewById<TextView>(android.R.id.text1).text = message\n        view.findViewById<Button>(android.R.id.button2).setOnClickListener {\n            dialog.cancel()\n        }\n        dialog.setOnCancelListener {\n            setResult(RESULT_CANCELED)\n            finish()\n        }\n        view.findViewById<Button>(android.R.id.button1).setOnClickListener {\n            dialog.dismiss()\n            setResult(RESULT_OK, Intent().apply {\n                putExtra(SmsRetriever.EXTRA_SMS_MESSAGE, message)\n            })\n            messenger?.send(Message.obtain().apply {\n                what = MSG_CONSUME_MESSAGE\n            })\n            finish()\n        }\n        if (!dialog.isShowing) {\n            dialog.window?.setGravity(Gravity.BOTTOM)\n            dialog.window?.setLayout(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)\n            dialog.show()\n        }\n    }\n}"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/kotlin/org/microg/gms/auth/phone/constants.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth.phone\n\nconst val MSG_REQUEST_MESSAGE_BODY = 1\nconst val MSG_CONSUME_MESSAGE = 2\n\nconst val EXTRA_MESSENGER = \"messenger\"\nconst val EXTRA_PERMISSIONS = \"permissions\"\nconst val EXTRA_GRANT_RESULTS = \"grantResults\""
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/layout/dialog_sms_user_consent.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<LinearLayout 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:layout_gravity=\"bottom\"\n    android:gravity=\"bottom|center\"\n    android:padding=\"24dp\"\n    android:orientation=\"vertical\">\n\n    <TextView\n        android:id=\"@android:id/title\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:textAlignment=\"textStart\"\n        android:gravity=\"start\"\n        style=\"@style/TextAppearance.AppCompat.Title\"\n        tools:text=\"Allow App to read the message below and enter the code?\" />\n\n    <TextView\n        android:id=\"@android:id/text1\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:textAlignment=\"textStart\"\n        android:layout_marginTop=\"10dp\"\n        android:gravity=\"start\"\n        style=\"@style/TextAppearance.AppCompat.Small\"\n        tools:text=\"OTP is 123456 to accept transaction with App. Do not share for security reasons\" />\n\n    <LinearLayout\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"20dp\"\n        android:layout_gravity=\"end\"\n        android:orientation=\"horizontal\">\n\n        <Button\n            android:id=\"@android:id/button2\"\n            android:layout_height=\"wrap_content\"\n            android:layout_width=\"wrap_content\"\n            android:text=\"@string/sms_user_consent_deny\"\n            style=\"@style/Widget.AppCompat.Button.Borderless\" />\n\n        <Button\n            android:id=\"@android:id/button1\"\n            android:layout_height=\"wrap_content\"\n            android:layout_width=\"wrap_content\"\n            android:layout_marginLeft=\"8dp\"\n            android:layout_marginStart=\"8dp\"\n            android:text=\"@string/sms_user_consent_allow\"\n            style=\"@style/Widget.AppCompat.Button.Colored\" />\n    </LinearLayout>\n</LinearLayout>"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<resources>\n    <string name=\"sms_user_consent_title\">Allow <b>%s</b> to read the message below and enter the code?</string>\n    <string name=\"sms_user_consent_allow\">Allow</string>\n    <string name=\"sms_user_consent_deny\">Deny</string>\n</resources>"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-ar/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"sms_user_consent_deny\">رفض</string>\n    <string name=\"sms_user_consent_allow\">سماح</string>\n    <string name=\"sms_user_consent_title\">السماح ل<b>%s</b> بقراءة الرسالة أدناه وإدخال الرمز؟</string>\n</resources>"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-ast/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"sms_user_consent_allow\">Permitir</string>\n    <string name=\"sms_user_consent_title\">¿Quies permitir que l\\'aplicación <b>%s</b> llea\\'l mensaxe d\\'abaxo ya introduza\\'l códigu\\?</string>\n    <string name=\"sms_user_consent_deny\">Negar</string>\n</resources>"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-az/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"sms_user_consent_title\"><b>%s</b>-ə aşağıdakı mesajı oxumağa və kodu daxil etməyə icazə verilsin?</string>\n</resources>"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-be/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"sms_user_consent_title\">Дазволіць <b>%s</b> прачытаць паведамленне і ўвесці код?</string>\n    <string name=\"sms_user_consent_allow\">Дазволіць</string>\n    <string name=\"sms_user_consent_deny\">Адхіліць</string>\n</resources>"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-bn/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n</resources>"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-ca/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"sms_user_consent_title\">Permet que <b>%s</b> llegeixi el missatge següent i introdueixi el codi?</string>\n    <string name=\"sms_user_consent_allow\">Permet</string>\n    <string name=\"sms_user_consent_deny\">Denegar</string>\n</resources>\n"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-cs/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"sms_user_consent_deny\">Zakázat</string>\n    <string name=\"sms_user_consent_title\">Povolit aplikaci <b>%s</b> zobrazit zprávu níže a zadat kód?</string>\n    <string name=\"sms_user_consent_allow\">Povolit</string>\n</resources>"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-de/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"sms_user_consent_allow\">Erlauben</string>\n    <string name=\"sms_user_consent_deny\">Ablehnen</string>\n    <string name=\"sms_user_consent_title\"><b>%s</b> erlauben, die folgende Nachricht zu lesen und den Code einzugeben?</string>\n</resources>"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-eo/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources></resources>"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-es/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"sms_user_consent_title\">¿Permitir que <b>%s</b> lean el mensaje de abajo e introduzcan el código?</string>\n    <string name=\"sms_user_consent_allow\">Permitir</string>\n    <string name=\"sms_user_consent_deny\">Denegar</string>\n</resources>"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-fa/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"sms_user_consent_allow\">پذیرفتن</string>\n    <string name=\"sms_user_consent_deny\">رد کردن</string>\n    <string name=\"sms_user_consent_title\">به <b>%s</b> اجازه دهید پیام زیر را بخواند و کد را وارد کنید؟</string>\n</resources>\n"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-fi/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"sms_user_consent_title\">Sallitaanko <b>%s</b> lukea seuraavan viestin ja syöttää koodin?</string>\n    <string name=\"sms_user_consent_allow\">Salli</string>\n    <string name=\"sms_user_consent_deny\">Kiellä</string>\n</resources>"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-fil/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"sms_user_consent_title\">Payagan ang <b>%s</b> na basahin ang mensahe sa ibaba at ilagay ang code?</string>\n    <string name=\"sms_user_consent_allow\">Payagan</string>\n    <string name=\"sms_user_consent_deny\">Tanggihan</string>\n</resources>"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-fr/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"sms_user_consent_title\">Autoriser <b>%s</b> à lire le message ci-dessous et saisir le code ?</string>\n    <string name=\"sms_user_consent_allow\">Autoriser</string>\n    <string name=\"sms_user_consent_deny\">Refuser</string>\n</resources>"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-ga/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"sms_user_consent_deny\">Diúltaigh</string>\n    <string name=\"sms_user_consent_title\">An bhfuil cead ag <b>%s</b> an teachtaireacht thíos a léamh agus an cód a chur isteach?</string>\n    <string name=\"sms_user_consent_allow\">Ceadaigh</string>\n</resources>"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-hu/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"sms_user_consent_allow\">Engedélyez</string>\n    <string name=\"sms_user_consent_title\">Engedélyezi a(z) <b>%s</b> alkalmazásnak, hogy elolvassa az alábbi üzenetet és beírja a kódot?</string>\n    <string name=\"sms_user_consent_deny\">Megtagad</string>\n</resources>\n"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-in/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"sms_user_consent_allow\">Izinkan</string>\n    <string name=\"sms_user_consent_title\">Izinkan <b>%s</b> untuk membaca pesan di bawah ini dan memasukkan kode?</string>\n    <string name=\"sms_user_consent_deny\">Tolak</string>\n</resources>\n"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-is/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"sms_user_consent_title\">Leyfa <b>%s</b> að lesa skilaboðin hér fyrir neðan og setja inn kóðann?</string>\n    <string name=\"sms_user_consent_deny\">Hafna</string>\n    <string name=\"sms_user_consent_allow\">Leyfa</string>\n</resources>"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-it/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"sms_user_consent_allow\">Consenti</string>\n    <string name=\"sms_user_consent_title\">Consentire a <b>%s</b> di leggere il seguente messaggio e inserire il codice\\?</string>\n    <string name=\"sms_user_consent_deny\">Nega</string>\n</resources>"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-iw/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n</resources>"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-ja/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"sms_user_consent_allow\">許可</string>\n    <string name=\"sms_user_consent_title\"><b>%s</b> に以下のメッセージの読み取りを許可してコードを入力させますか？</string>\n    <string name=\"sms_user_consent_deny\">拒否</string>\n</resources>"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-ko/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"sms_user_consent_title\"><b>%s</b>가 아래의 메시지를 읽고 코드를 입력하도록 허용할까요?</string>\n    <string name=\"sms_user_consent_allow\">허용</string>\n    <string name=\"sms_user_consent_deny\">거부</string>\n</resources>\n"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-lv/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"sms_user_consent_allow\">Atļaut</string>\n    <string name=\"sms_user_consent_deny\">Liegt</string>\n</resources>\n"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-lzh/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources></resources>"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-ml/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"sms_user_consent_title\">താഴെയുള്ള സന്ദേശം വായിച്ച് കോഡ് നൽകാൻ <b>%s</b> നെ അനുവദിക്കണോ?</string>\n    <string name=\"sms_user_consent_allow\">അനുവദിക്കുക</string>\n    <string name=\"sms_user_consent_deny\">നിരസിക്കുക</string>\n</resources>\n"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-nb-rNO/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"sms_user_consent_deny\">Nekt</string>\n    <string name=\"sms_user_consent_title\">La <b>%s</b> lese meldingen under og legge inn koden?</string>\n    <string name=\"sms_user_consent_allow\">Tillat</string>\n</resources>\n"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-nl/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"sms_user_consent_title\"><b>%s</b> toestaan het onderstaande bericht te lezen en de code in te voeren?</string>\n    <string name=\"sms_user_consent_allow\">Toestaan</string>\n    <string name=\"sms_user_consent_deny\">Niet toestaan</string>\n</resources>"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-pl/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"sms_user_consent_allow\">Zezwól</string>\n    <string name=\"sms_user_consent_title\">Zezwolić <b>%s</b> na odczyt poniższej wiadomości i wprowadzenie kodu?</string>\n    <string name=\"sms_user_consent_deny\">Odmów</string>\n</resources>"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-pt/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"sms_user_consent_title\">Permitir que <b>%s</b> leia a mensagem abaixo e insira o código?</string>\n    <string name=\"sms_user_consent_allow\">Permitir</string>\n    <string name=\"sms_user_consent_deny\">Recusar</string>\n</resources>\n"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-pt-rBR/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"sms_user_consent_title\">Permitir que <b>%s</b> leia a mensagem abaixo e insira o código?</string>\n    <string name=\"sms_user_consent_allow\">Permitir</string>\n    <string name=\"sms_user_consent_deny\">Negar</string>\n</resources>"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-ro/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"sms_user_consent_allow\">Permite</string>\n    <string name=\"sms_user_consent_title\">Permiți ca <b>%s</b> să citească mesajul de mai jos și să introducă codul\\?</string>\n    <string name=\"sms_user_consent_deny\">Refuză</string>\n</resources>"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-ru/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"sms_user_consent_title\">Разрешить <b>%s</b> прочитать сообщение ниже и ввести код?</string>\n    <string name=\"sms_user_consent_allow\">Разрешить</string>\n    <string name=\"sms_user_consent_deny\">Отклонить</string>\n</resources>\n"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-sl/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n</resources>"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-sr/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"sms_user_consent_allow\">Дозволи</string>\n    <string name=\"sms_user_consent_title\">Дозволити <b>%s</b> да прочита поруку испод и унесе кôд\\?</string>\n    <string name=\"sms_user_consent_deny\">Одбиј</string>\n</resources>"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-sv/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"sms_user_consent_allow\">Tillåt</string>\n    <string name=\"sms_user_consent_title\">Vill du låta <b>%s</b> läsa meddelandet nedan och ange koden?</string>\n    <string name=\"sms_user_consent_deny\">Neka</string>\n</resources>"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-ta/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"sms_user_consent_title\">கீழே உள்ள செய்தியைப் படித்து குறியீட்டை உள்ளிட <b>%s </b> ஐ அனுமதிக்கவா?</string>\n    <string name=\"sms_user_consent_allow\">இசைவு</string>\n    <string name=\"sms_user_consent_deny\">மறு</string>\n</resources>\n"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-th/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"sms_user_consent_title\">อนุญาตให้ <b>%s</b> อ่านข้อความด้านล่างและกรอกรหัส?</string>\n    <string name=\"sms_user_consent_allow\">อนุญาต</string>\n    <string name=\"sms_user_consent_deny\">ปฏิเสธ</string>\n</resources>"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-tr/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"sms_user_consent_allow\">İzin ver</string>\n    <string name=\"sms_user_consent_title\"><b>%s</b> uygulamasının aşağıdaki mesajı okumasına ve kodu girmesine izin veriyor musunuz?</string>\n    <string name=\"sms_user_consent_deny\">Reddet</string>\n</resources>"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-ug/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"sms_user_consent_title\"><b>%s</b> نىڭ تۆۋەندىكى مەزمۇننى ئوقۇپ ۋە كودنى كىرگۈزۈشىگە يول قويامدۇ؟</string>\n    <string name=\"sms_user_consent_deny\">رەت قىل</string>\n    <string name=\"sms_user_consent_allow\">يول قوي</string>\n</resources>\n"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-uk/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"sms_user_consent_allow\">Дозволити</string>\n    <string name=\"sms_user_consent_title\">Дозволити <b>%s</b> прочитати наведене нижче повідомлення та ввести код?</string>\n    <string name=\"sms_user_consent_deny\">Відхилити</string>\n</resources>"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-vi/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"sms_user_consent_deny\">Từ chối</string>\n    <string name=\"sms_user_consent_title\">Cho phép <b>%s</b> đọc tin nhắn bên dưới và nhập mã?</string>\n    <string name=\"sms_user_consent_allow\">Chấp nhận</string>\n</resources>\n"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-zh-rCN/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"sms_user_consent_title\">允许<b>%s</b>读取以下消息并输入代码？</string>\n    <string name=\"sms_user_consent_allow\">允许</string>\n    <string name=\"sms_user_consent_deny\">拒绝</string>\n</resources>"
  },
  {
    "path": "play-services-auth-api-phone/core/src/main/res/values-zh-rTW/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"sms_user_consent_title\">允許「<b>%s</b>」閱讀以下訊息並輸入代碼？</string>\n    <string name=\"sms_user_consent_deny\">拒絕</string>\n    <string name=\"sms_user_consent_allow\">允許</string>\n</resources>"
  },
  {
    "path": "play-services-auth-api-phone/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest />"
  },
  {
    "path": "play-services-auth-api-phone/src/main/aidl/com/google/android/gms/auth/api/phone/internal/IAutofillPermissionStateCallback.aidl",
    "content": "package com.google.android.gms.auth.api.phone.internal;\n\nimport com.google.android.gms.common.api.Status;\n\ninterface IAutofillPermissionStateCallback {\n    void onCheckPermissionStateResult(in Status status, int result) = 0;\n}\n"
  },
  {
    "path": "play-services-auth-api-phone/src/main/aidl/com/google/android/gms/auth/api/phone/internal/IOngoingSmsRequestCallback.aidl",
    "content": "package com.google.android.gms.auth.api.phone.internal;\n\nimport com.google.android.gms.common.api.Status;\n\ninterface IOngoingSmsRequestCallback {\n    void onHasOngoingSmsRequestResult(in Status status, boolean hasOngoingSmsRequest) = 0;\n}\n"
  },
  {
    "path": "play-services-auth-api-phone/src/main/aidl/com/google/android/gms/auth/api/phone/internal/ISmsRetrieverApiService.aidl",
    "content": "package com.google.android.gms.auth.api.phone.internal;\n\nimport com.google.android.gms.auth.api.phone.internal.IAutofillPermissionStateCallback;\nimport com.google.android.gms.auth.api.phone.internal.IOngoingSmsRequestCallback;\nimport com.google.android.gms.auth.api.phone.internal.ISmsRetrieverResultCallback;\nimport com.google.android.gms.common.api.internal.IStatusCallback;\nimport com.google.android.gms.common.api.Status;\n\nimport java.lang.String;\n\ninterface ISmsRetrieverApiService {\n    void startSmsRetriever(ISmsRetrieverResultCallback callback) = 0;\n    void startWithConsentPrompt(String senderPhoneNumber, ISmsRetrieverResultCallback callback) = 1;\n    void startSmsCodeAutofill(IStatusCallback callback) = 2;\n    void checkAutofillPermissionState(IAutofillPermissionStateCallback callback) = 3;\n    void checkOngoingSmsRequest(String packageName, IOngoingSmsRequestCallback callback) = 4;\n    void startSmsCodeBrowser(IStatusCallback callback) = 5;\n}"
  },
  {
    "path": "play-services-auth-api-phone/src/main/aidl/com/google/android/gms/auth/api/phone/internal/ISmsRetrieverResultCallback.aidl",
    "content": "package com.google.android.gms.auth.api.phone.internal;\n\nimport com.google.android.gms.common.api.Status;\n\ninterface ISmsRetrieverResultCallback {\n    void onResult(in Status status) = 0;\n}\n"
  },
  {
    "path": "play-services-auth-api-phone/src/main/java/com/google/android/gms/auth/api/phone/SmsCodeAutofillClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.api.phone;\n\nimport android.app.Activity;\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.IntentFilter;\nimport android.os.Handler;\nimport androidx.annotation.IntDef;\nimport com.google.android.gms.common.api.*;\nimport com.google.android.gms.tasks.Task;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * The interface for interacting with the SMS Code Autofill API. These methods are only supported on devices running Android P and later.\n * For devices that run versions earlier than Android P, all method calls return {@link SmsRetrieverStatusCodes#PLATFORM_NOT_SUPPORTED}.\n * <p>\n * Note: This interface works only for the current user-designated autofill service.\n * Any calls from non user-designated autofill services or other applications will fail with {@link SmsRetrieverStatusCodes#API_NOT_AVAILABLE}.\n */\npublic interface SmsCodeAutofillClient extends HasApiKey<Api.ApiOptions.NoOptions> {\n    /**\n     * Returns the {@link SmsCodeAutofillClient.PermissionState} of the current user-designated autofill service.\n     * The result could be {@code NONE}, {@code GRANTED}, or {@code DENIED}.\n     * <p>\n     * The autofill service should check its permission state prior to showing the suggestion prompt for retrieving an SMS\n     * verification code, because it will definitely fail on calling {@link #startSmsCodeRetriever()} in permission denied state.\n     */\n    Task<@PermissionState Integer> checkPermissionState();\n\n    /**\n     * Returns {@code true} if there are requests from {@link SmsRetriever} in progress for the given package name.\n     * <p>\n     * The autofill service can check this method to avoid showing a suggestion prompt for retrieving an SMS verification code,\n     * in case that a user app may already be retrieving the SMS verification code through {@link SmsRetriever}.\n     * <p>\n     * Note: This result does not include those requests from {@code SmsCodeAutofillClient}.\n     */\n    Task<Boolean> hasOngoingSmsRequest(String packageName);\n\n    /**\n     * Starts {@code SmsCodeRetriever}, which looks for an SMS verification code from messages recently received (up to 1 minute\n     * prior). If there is no SMS verification code found from the SMS inbox, it waits for new incoming SMS messages until it\n     * finds an SMS verification code or reaches the timeout (about 5 minutes).\n     * <p>\n     * The SMS verification code will be sent via a Broadcast Intent with {@link SmsCodeRetriever#SMS_CODE_RETRIEVED_ACTION}. This Intent contains\n     * Extras with keys {@link SmsCodeRetriever#EXTRA_SMS_CODE} for the retrieved verification code as a {@code String}, and {@link SmsCodeRetriever#EXTRA_STATUS} for {@link Status} to\n     * indicate {@code RESULT_SUCCESS}, {@code RESULT_TIMEOUT} or {@link SmsRetrieverStatusCodes}.\n     * <p>\n     * Note: Add {@link SmsRetriever#SEND_PERMISSION} in {@link Context#registerReceiver(BroadcastReceiver, IntentFilter, String, Handler)} while\n     * registering the receiver to detect that the broadcast intent is from the SMS Retriever.\n     */\n    Task<Void> startSmsCodeRetriever();\n\n    /**\n     * Permission states for the current user-designated autofill service. The initial state is {@code NONE} upon the first time using the\n     * SMS Code Autofill API. This permission can be granted or denied through a consent dialog requested by the current\n     * autofill service, or an explicit change by users within the SMS verification codes settings.\n     */\n    @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})\n    @Retention(RetentionPolicy.SOURCE)\n    @IntDef({PermissionState.NONE, PermissionState.GRANTED, PermissionState.DENIED})\n    @interface PermissionState {\n        /**\n         * Indicates that the current autofill service has not been granted or denied permission by the user. Calling\n         * {@link #startSmsCodeRetriever()} will fail with {@link CommonStatusCodes#RESOLUTION_REQUIRED}. The caller can use\n         * {@link ResolvableApiException#startResolutionForResult(Activity, int)} to show a consent dialog for requesting permission from the user.\n         */\n        int NONE = 0;\n        /**\n         * Indicates that the current autofill service has been granted permission by the user. The user consent is not required for\n         * calling {@link #startSmsCodeRetriever()} in this state.\n         */\n        int GRANTED = 1;\n        /**\n         * Indicates that the current autofill service has been denied permission by the user. Calling {@link #startSmsCodeRetriever()}\n         * will fail with {@link SmsRetrieverStatusCodes#USER_PERMISSION_REQUIRED}. It can only be resolved by the user explicitly turning on the permission\n         * in settings.\n         */\n        int DENIED = 2;\n    }\n}\n"
  },
  {
    "path": "play-services-auth-api-phone/src/main/java/com/google/android/gms/auth/api/phone/SmsCodeBrowserClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.api.phone;\n\nimport android.app.Activity;\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.os.Handler;\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.HasApiKey;\nimport com.google.android.gms.common.api.ResolvableApiException;\nimport com.google.android.gms.tasks.Task;\n\n/**\n * The interface for interacting with the SMS Code Browser API. By using {@link #startSmsCodeRetriever()}, you can retrieve the\n * origin-bound one-time code from SMS messages.\n * <p>\n * The SMS message format should follow the origin-bound one-time code specification:\n * <ul>\n *     <li>Can optionally begin with human-readable explanatory text. This consists of all but the last line of the message.</li>\n *     <li>The last line of the message contains both a host and a code, each prefixed with a sigil: U+0040 (@) before the host, and U+0023 (#) before the code.</li>\n * </ul>\n * <p>\n * Note: This interface works only for the default browser app set by the current user. Any other calls will fail with {@link SmsRetrieverStatusCodes#API_NOT_AVAILABLE}.\n */\npublic interface SmsCodeBrowserClient extends HasApiKey<Api.ApiOptions.NoOptions> {\n    /**\n     * Starts {@code SmsCodeRetriever}, which looks for an origin-bound one-time code from SMS messages recently received (up to\n     * 1 minute prior). If there is no matching message found from the SMS inbox, it waits for new incoming SMS messages\n     * until it finds a matching message or reaches the timeout (about 5 minutes). Calling this method multiple times only\n     * returns one result, but it can extend the timeout period to the last call. Once the result is returned or it reaches\n     * the timeout, SmsCodeRetriever will stop automatically.\n     * <p>\n     * The SMS verification code will be sent via a Broadcast Intent with {@link SmsCodeRetriever#SMS_CODE_RETRIEVED_ACTION}.\n     * This Intent contains Extras with keys:\n     * <ul>\n     *     <li>{@link SmsCodeRetriever#EXTRA_SMS_CODE_LINE} for the retrieved line that contains the origin-bound one-time code and the metadata, or\n     * {@code null} in failed cases.</li>\n     *     <li>{@link SmsCodeRetriever#EXTRA_STATUS} for the Status to indicate {@code RESULT_SUCCESS}, {@code RESULT_TIMEOUT} or other {@link SmsRetrieverStatusCodes}.</li>\n     * </ul>\n     * If the caller has not been granted or denied permission by the user, it will fail with a {@link ResolvableApiException}. The\n     * caller can use {@link ResolvableApiException#startResolutionForResult(Activity, int)} to show a consent dialog for requesting permission from\n     * the user. The dialog result is returned via {@link Activity#onActivityResult(int, int, Intent)}. If the user grants the permission,\n     * the activity result returns with {@code RESULT_OK}. Then you can start the retriever again to retrieve the verification code.\n     * <p>\n     * Note: Add {@link SmsRetriever#SEND_PERMISSION} in {@link Context#registerReceiver(BroadcastReceiver, IntentFilter, String, Handler)} while\n     * registering the receiver to detect that the broadcast intent is from the SMS Retriever.\n     */\n    Task<Void> startSmsCodeRetriever();\n}\n"
  },
  {
    "path": "play-services-auth-api-phone/src/main/java/com/google/android/gms/auth/api/phone/SmsCodeRetriever.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.api.phone;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.api.Status;\nimport org.microg.gms.auth.api.phone.SmsCodeAutofillClientImpl;\nimport org.microg.gms.auth.api.phone.SmsCodeBrowserClientImpl;\n\n/**\n * {@code SmsCodeRetriever} is a variant of {@link SmsRetriever}, and it provides access to Google services that help you retrieve SMS\n * verification codes sent to the user's device, without having to ask for {@code android.permission.READ_SMS} or {@code android.permission.RECEIVE_SMS}.\n * <p>\n * To use {@code SmsCodeRetriever} in the Android autofill service, obtain an instance of {@link SmsCodeAutofillClient} using\n * {@link #getAutofillClient(Context)} or {@link #getAutofillClient(Activity)}, and start SMS Code Retriever service by calling\n * {@link SmsCodeAutofillClient#startSmsCodeRetriever()}. To use it in the browser app, you obtain an instance of {@link SmsCodeBrowserClient} using\n * {@link #getBrowserClient(Context)} or {@link #getBrowserClient(Activity)} instead.\n * <p>\n * The service first looks for an SMS verification code from messages recently received (up to 1 minute prior). If there is no\n * SMS verification code found from the SMS inbox, it waits for new incoming SMS messages until it finds an SMS\n * verification code or reaches the timeout (about 5 minutes).\n */\npublic class SmsCodeRetriever {\n    /**\n     * Intent extra key of the retrieved SMS verification code by the {@link SmsCodeAutofillClient}.\n     */\n    @NonNull\n    public static final String EXTRA_SMS_CODE = \"com.google.android.gms.auth.api.phone.EXTRA_SMS_CODE\";\n    /**\n     * Intent extra key of the retrieved SMS verification code line by the {@link SmsCodeBrowserClient}.\n     */\n    @NonNull\n    public static final String EXTRA_SMS_CODE_LINE = \"com.google.android.gms.auth.api.phone.EXTRA_SMS_CODE_LINE\";\n    /**\n     * Intent extra key of {@link Status}, which indicates {@code RESULT_SUCCESS}, {@code RESULT_TIMEOUT} or {@link SmsRetrieverStatusCodes}.\n     */\n    @NonNull\n    public static final String EXTRA_STATUS = \"com.google.android.gms.auth.api.phone.EXTRA_STATUS\";\n    /**\n     * Intent action when an SMS verification code is retrieved.\n     */\n    @NonNull\n    public static final String SMS_CODE_RETRIEVED_ACTION = \"com.google.android.gms.auth.api.phone.SMS_CODE_RETRIEVED\";\n\n    /**\n     * Creates a new instance of {@link SmsCodeAutofillClient} for use in an {@link Activity}.\n     * This {@link SmsCodeAutofillClient} is intended to be used by the current user-designated autofill service only.\n     */\n    @NonNull\n    public static SmsCodeAutofillClient getAutofillClient(Activity activity) {\n        return new SmsCodeAutofillClientImpl(activity);\n    }\n\n    /**\n     * Creates a new instance of {@link SmsCodeAutofillClient} for use in a {@link Context}.\n     * This {@link SmsCodeAutofillClient} is intended to be used by the current user-designated autofill service only.\n     */\n    @NonNull\n    public static SmsCodeAutofillClient getAutofillClient(Context context) {\n        return new SmsCodeAutofillClientImpl(context);\n    }\n\n    /**\n     * Creates a new instance of {@link SmsCodeBrowserClient} for use in an {@link Activity}.\n     * This {@link SmsCodeBrowserClient} is intended to be used by the default browser app only.\n     */\n    @NonNull\n    public static SmsCodeBrowserClient getBrowserClient(Activity activity) {\n        return new SmsCodeBrowserClientImpl(activity);\n    }\n\n    /**\n     * Creates a new instance of {@link SmsCodeBrowserClient} for use in a {@link Context}.\n     * This {@link SmsCodeBrowserClient} is intended to be used by the default browser app only.\n     */\n    @NonNull\n    public static SmsCodeBrowserClient getBrowserClient(Context context) {\n        return new SmsCodeBrowserClientImpl(context);\n    }\n\n}\n"
  },
  {
    "path": "play-services-auth-api-phone/src/main/java/com/google/android/gms/auth/api/phone/SmsRetriever.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.api.phone;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.api.Status;\nimport org.microg.gms.auth.api.phone.SmsRetrieverClientImpl;\n\n/**\n * {@code SmsRetriever} provides access to Google services that help you retrieve SMS messages sent to your app without\n * having to ask for {@code android.permission.READ_SMS} or {@code android.permission.RECEIVE_SMS}.\n * <p>\n * To use {@code SmsRetriever}, obtain an instance of {@link SmsRetrieverClient} using {@link #getClient(Context)} or\n * {@link #getClient(Activity)}, then start the SMS retriever service by calling {@link SmsRetrieverClient#startSmsRetriever()} or\n * {@link SmsRetrieverClient#startSmsUserConsent(String)}. The service waits for a matching SMS message until timeout (5 minutes).\n */\npublic class SmsRetriever {\n    /**\n     * Intent extra key of the consent intent to be launched from client app.\n     */\n    @NonNull\n    public static final String EXTRA_CONSENT_INTENT = \"com.google.android.gms.auth.api.phone.EXTRA_CONSENT_INTENT\";\n    /**\n     * [Optional] Intent extra key of the retrieved Sim card subscription Id if any, as an {@code int}.\n     */\n    @NonNull\n    public static final String EXTRA_SIM_SUBSCRIPTION_ID = \"com.google.android.gms.auth.api.phone.EXTRA_SIM_SUBSCRIPTION_ID\";\n    /**\n     * Intent extra key of the retrieved SMS message as a {@code String}.\n     */\n    @NonNull\n    public static final String EXTRA_SMS_MESSAGE = \"com.google.android.gms.auth.api.phone.EXTRA_SMS_MESSAGE\";\n    /**\n     * Intent extra key of {@link Status}, which indicates SUCCESS or TIMEOUT.\n     */\n    @NonNull\n    public static final String EXTRA_STATUS = \"com.google.android.gms.auth.api.phone.EXTRA_STATUS\";\n    /**\n     * Permission that's used to register the receiver to detect that the broadcaster is the SMS Retriever.\n     */\n    @NonNull\n    public static final String SEND_PERMISSION = \"com.google.android.gms.auth.api.phone.permission.SEND\";\n    /**\n     * Intent action when SMS message is retrieved.\n     */\n    @NonNull\n    public static final String SMS_RETRIEVED_ACTION = \"com.google.android.gms.auth.api.phone.SMS_RETRIEVED\";\n\n    /**\n     * Create a new instance of {@link SmsRetrieverClient} for use in an {@link Activity}.\n     */\n    @NonNull\n    public static SmsRetrieverClient getClient(Activity activity) {\n        return new SmsRetrieverClientImpl(activity);\n    }\n\n    /**\n     * Create a new instance of {@link SmsRetrieverClient} for use in a {@link Context}.\n     */\n    @NonNull\n    public static SmsRetrieverClient getClient(Context context) {\n        return new SmsRetrieverClientImpl(context);\n    }\n}\n"
  },
  {
    "path": "play-services-auth-api-phone/src/main/java/com/google/android/gms/auth/api/phone/SmsRetrieverApi.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.api.phone;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.tasks.OnCompleteListener;\nimport com.google.android.gms.tasks.Task;\n\n/**\n * API interface for SmsRetriever.\n */\npublic interface SmsRetrieverApi {\n    /**\n     * Starts {@code SmsRetriever}, which waits for a matching SMS message until timeout (5 minutes). The matching SMS message\n     * will be sent via a Broadcast Intent with action {@link SmsRetriever#SMS_RETRIEVED_ACTION}. The Intent contains Extras with keys\n     * {@link SmsRetriever#EXTRA_SMS_MESSAGE} for the retrieved SMS message as a String, and {@link SmsRetriever#EXTRA_STATUS} for {@link Status} to indicate\n     * {@code SUCCESS}, {@code DEVELOPER_ERROR}, {@code ERROR}, or {@code TIMEOUT}.\n     * <p>\n     * Note: Add {@link SmsRetriever#SEND_PERMISSION} while registering the receiver to detect that the broadcast intent is from the SMS Retriever.\n     * <p>\n     * The possible causes for errors are:\n     * <ul>\n     *     <li>DEVELOPER_ERROR: the caller app has incorrect number of certificates. Only one certificate is allowed.</li>\n     *     <li>ERROR: the AppCode collides with other installed apps.</li>\n     * </ul>\n     *\n     * @return a Task for the call. Attach an {@link OnCompleteListener} and then check {@link Task#isSuccessful()} to determine if it was successful.\n     */\n    @NonNull\n    Task<Void> startSmsRetriever();\n\n    /**\n     * Starts {@code SmsUserConsent}, which waits for an OTP-containing SMS message until timeout (5 minutes). OTP-containing\n     * SMS message can be retrieved with two steps.\n     * <p>\n     * Note: Add {@link SmsRetriever#SEND_PERMISSION} while registering the receiver to detect that the broadcast intent is from the SMS Retriever.\n     * <ol>\n     *     <li>[Get consent Intent] While OTP-containing SMS message comes, a consent Intent will be sent via a Broadcast\n     *     Intent with action {@link SmsRetriever#SMS_RETRIEVED_ACTION}. The Intent contains Extras with keys {@link SmsRetriever#EXTRA_CONSENT_INTENT} for the\n     *     consent Intent and {@link SmsRetriever#EXTRA_STATUS} for {@link Status} to indicate {@code SUCCESS} or {@code TIMEOUT}.</li>\n     *     <li>[Get OTP-containing SMS message] Calls {@code startActivityForResult} with consent Intent to launch a consent\n     *     dialog to get user's approval, then the OTP-containing SMS message can be retrieved from the activity result.</li>\n     * </ol>\n     *\n     * @param senderAddress address of desired SMS sender, or {@code null} to retrieve any sender\n     * @return a Task for the call. Attach an {@link OnCompleteListener} and then check {@link Task#isSuccessful()} to determine if it was successful.\n     */\n    @NonNull\n    Task<Void> startSmsUserConsent(@Nullable String senderAddress);\n}\n"
  },
  {
    "path": "play-services-auth-api-phone/src/main/java/com/google/android/gms/auth/api/phone/SmsRetrieverClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.api.phone;\n\nimport android.content.Context;\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.GoogleApi;\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport org.microg.gms.auth.api.phone.SmsRetrieverApiClient;\n\n/**\n * The main entry point for interacting with SmsRetriever.\n * <p>\n * This does not require a {@link GoogleApiClient}. See {@link GoogleApi} for more information.\n */\npublic abstract class SmsRetrieverClient extends GoogleApi<Api.ApiOptions.NoOptions> implements SmsRetrieverApi {\n\n    protected SmsRetrieverClient(Context context) {\n        super(context, SmsRetrieverApiClient.API, Api.ApiOptions.NO_OPTIONS);\n    }\n}\n"
  },
  {
    "path": "play-services-auth-api-phone/src/main/java/com/google/android/gms/auth/api/phone/SmsRetrieverStatusCodes.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.api.phone;\n\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.api.CommonStatusCodes;\nimport com.google.android.gms.common.api.Status;\n\n/**\n * SMS Retriever specific status codes, for use in {@link Status#getStatusCode()}.\n */\npublic class SmsRetrieverStatusCodes extends CommonStatusCodes {\n    /**\n     * The current Android platform does not support this particular API.\n     */\n    public static final int PLATFORM_NOT_SUPPORTED = 36500;\n    /**\n     * The calling application is not eligible to use this particular API.\n     * <p>\n     * Note: For {@link SmsCodeAutofillClient}, this status indicates that the calling application is not the current user-designated\n     * autofill service. For {@link SmsCodeBrowserClient}, it indicates that the caller is not the system default browser app.\n     */\n    public static final int API_NOT_AVAILABLE = 36501;\n    /**\n     * The user has not granted the calling application permission to use this particular API.\n     */\n    public static final int USER_PERMISSION_REQUIRED = 36502;\n\n    /**\n     * Returns an untranslated debug string based on the given status code.\n     */\n    @NonNull\n    public static String getStatusCodeString(int statusCode) {\n        switch (statusCode) {\n            case PLATFORM_NOT_SUPPORTED:\n                return \"PLATFORM_NOT_SUPPORTED\";\n            case API_NOT_AVAILABLE:\n                return \"API_NOT_AVAILABLE\";\n            case USER_PERMISSION_REQUIRED:\n                return \"USER_PERMISSION_REQUIRED\";\n            default:\n                return CommonStatusCodes.getStatusCodeString(statusCode);\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-auth-api-phone/src/main/java/com/google/android/gms/auth/api/phone/package-info.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n/**\n * {@code SmsRetriever} contains two APIs, the SMS Retriever API and the SMS User Consent API, that provide access to Google\n * services that help you retrieve SMS messages directed to your app, without having to ask for\n * {@code android.permission.READ_SMS} or {@code android.permission.RECEIVE_SMS}. The {@code SmsCodeRetriever} is for autofill\n * services and browser apps to retrieve SMS-based verification codes.\n * <p>\n * Many apps use phone numbers to verify the identity of a user. The app sends an SMS message containing an OTP (One\n * Time Passcode) to the user, who then enters the OTP from the received SMS message to prove ownership of the phone number.\n * <p>\n * In Android, to provide a streamlined UX, an app may request the SMS read permission, and retrieve the OTP\n * automatically. This is problematic since this permission allows the app to read other SMS messages which may contain\n * the user's private information. Also, the latest Play Store policy changes restrict access to SMS messages.\n * <p>\n * The SMS Retriever API solves this problem by providing app developers a way to automatically retrieve only the SMS\n * directed to the app without asking for the SMS read permission or gaining the ability to read any other SMS messages on the device.\n * <p>\n * The SMS User Consent API complements the SMS Retriever API by allowing an app to prompt the user to grant access to\n * the content of the next SMS message that contains an OTP. When a user gives consent, the app will then have access to\n * the entire message body to automatically complete SMS verification.\n * <p>\n * The SMS Retriever API completely automates the SMS-based OTP verification process for the user. However, there are\n * situations where you don’t control the format of the SMS message and as a result cannot use the SMS Retriever API.\n * In these situations, you can use the SMS User Consent API to streamline the process.\n * <p>\n * With the SMS Code Autofill API, a user-designated autofill service can retrieve the SMS verification codes from the SMS\n * inbox or new incoming SMS messages, then fill in this code for a user to complete any SMS verification requests in a\n * user app. For browser apps, you can achieve this by using the SMS Code Browser API.\n */\npackage com.google.android.gms.auth.api.phone;\n"
  },
  {
    "path": "play-services-auth-api-phone/src/main/java/org/microg/gms/auth/api/phone/SmsCodeAutofillClientImpl.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth.api.phone;\n\nimport android.content.Context;\nimport com.google.android.gms.auth.api.phone.SmsCodeAutofillClient;\nimport com.google.android.gms.auth.api.phone.internal.IAutofillPermissionStateCallback;\nimport com.google.android.gms.auth.api.phone.internal.IOngoingSmsRequestCallback;\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.ApiException;\nimport com.google.android.gms.common.api.GoogleApi;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.tasks.Task;\nimport org.microg.gms.common.api.PendingGoogleApiCall;\n\npublic class SmsCodeAutofillClientImpl extends GoogleApi<Api.ApiOptions.NoOptions> implements SmsCodeAutofillClient {\n    public SmsCodeAutofillClientImpl(Context context) {\n        super(context, SmsRetrieverApiClient.API, Api.ApiOptions.NO_OPTIONS);\n    }\n\n    @Override\n    public Task<@PermissionState Integer> checkPermissionState() {\n        return scheduleTask((PendingGoogleApiCall<Integer, SmsRetrieverApiClient>) (client, completionSource) -> client.checkAutofillPermissionState(new IAutofillPermissionStateCallback.Stub() {\n            @Override\n            public void onCheckPermissionStateResult(Status status, int result) {\n                if (status.isSuccess()) {\n                    completionSource.trySetResult(result);\n                } else {\n                    completionSource.trySetException(new ApiException(status));\n                }\n            }\n        }));\n    }\n\n    @Override\n    public Task<Boolean> hasOngoingSmsRequest(String packageName) {\n        return scheduleTask((PendingGoogleApiCall<Boolean, SmsRetrieverApiClient>) (client, completionSource) -> client.checkOngoingSmsRequest(packageName, new IOngoingSmsRequestCallback.Stub() {\n            @Override\n            public void onHasOngoingSmsRequestResult(Status status, boolean result) {\n                if (status.isSuccess()) {\n                    completionSource.trySetResult(result);\n                } else {\n                    completionSource.trySetException(new ApiException(status));\n                }\n            }\n        }));\n    }\n\n    @Override\n    public Task<Void> startSmsCodeRetriever() {\n        return scheduleTask((PendingGoogleApiCall<Void, SmsRetrieverApiClient>) (client, completionSource) -> client.startSmsCodeAutofill(new StatusCallbackImpl(completionSource)));\n    }\n}\n"
  },
  {
    "path": "play-services-auth-api-phone/src/main/java/org/microg/gms/auth/api/phone/SmsCodeBrowserClientImpl.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth.api.phone;\n\nimport android.content.Context;\nimport com.google.android.gms.auth.api.phone.SmsCodeBrowserClient;\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.GoogleApi;\nimport com.google.android.gms.tasks.Task;\nimport org.microg.gms.common.api.PendingGoogleApiCall;\n\npublic class SmsCodeBrowserClientImpl extends GoogleApi<Api.ApiOptions.NoOptions> implements SmsCodeBrowserClient {\n    public SmsCodeBrowserClientImpl(Context context) {\n        super(context, SmsRetrieverApiClient.API, Api.ApiOptions.NO_OPTIONS);\n    }\n\n    @Override\n    public Task<Void> startSmsCodeRetriever() {\n        return scheduleTask((PendingGoogleApiCall<Void, SmsRetrieverApiClient>) (client, completionSource) -> client.startSmsCodeBrowser(new StatusCallbackImpl(completionSource)));\n    }\n}\n"
  },
  {
    "path": "play-services-auth-api-phone/src/main/java/org/microg/gms/auth/api/phone/SmsRetrieverApiClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth.api.phone;\n\nimport android.content.Context;\nimport android.os.IBinder;\nimport android.os.RemoteException;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.auth.api.phone.internal.IAutofillPermissionStateCallback;\nimport com.google.android.gms.auth.api.phone.internal.IOngoingSmsRequestCallback;\nimport com.google.android.gms.auth.api.phone.internal.ISmsRetrieverApiService;\nimport com.google.android.gms.auth.api.phone.internal.ISmsRetrieverResultCallback;\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.common.api.internal.IStatusCallback;\nimport org.microg.gms.common.GmsClient;\nimport org.microg.gms.common.GmsService;\nimport com.google.android.gms.common.api.internal.ConnectionCallbacks;\nimport com.google.android.gms.common.api.internal.OnConnectionFailedListener;\n\npublic class SmsRetrieverApiClient extends GmsClient<ISmsRetrieverApiService> {\n    public static final Api<Api.ApiOptions.NoOptions> API = new Api<>((options, context, looper, clientSettings, callbacks, connectionFailedListener) -> new SmsRetrieverApiClient(context, callbacks, connectionFailedListener));\n\n    public SmsRetrieverApiClient(Context context, ConnectionCallbacks callbacks, OnConnectionFailedListener connectionFailedListener) {\n        super(context, callbacks, connectionFailedListener, GmsService.SMS_RETRIEVER.ACTION);\n        serviceId = GmsService.SMS_RETRIEVER.SERVICE_ID;\n    }\n\n    @Override\n    protected ISmsRetrieverApiService interfaceFromBinder(IBinder binder) {\n        return ISmsRetrieverApiService.Stub.asInterface(binder);\n    }\n\n    public void startSmsRetriever(ISmsRetrieverResultCallback callback) {\n        try {\n            getServiceInterface().startSmsRetriever(callback);\n        } catch (RemoteException e) {\n            try {\n                callback.onResult(Status.INTERNAL_ERROR);\n            } catch (RemoteException ignored) {\n            }\n        }\n    }\n\n    public void startWithConsentPrompt(@Nullable String senderAddress, ISmsRetrieverResultCallback callback) {\n        try {\n            getServiceInterface().startWithConsentPrompt(senderAddress, callback);\n        } catch (RemoteException e) {\n            try {\n                callback.onResult(Status.INTERNAL_ERROR);\n            } catch (RemoteException ignored) {\n            }\n        }\n    }\n\n    public void startSmsCodeAutofill(IStatusCallback callback) {\n        try {\n            getServiceInterface().startSmsCodeAutofill(callback);\n        } catch (RemoteException e) {\n            try {\n                callback.onResult(Status.INTERNAL_ERROR);\n            } catch (RemoteException ignored) {\n            }\n        }\n    }\n\n    public void checkAutofillPermissionState(IAutofillPermissionStateCallback callback) {\n        try {\n            getServiceInterface().checkAutofillPermissionState(callback);\n        } catch (RemoteException e) {\n            try {\n                callback.onCheckPermissionStateResult(Status.INTERNAL_ERROR, -1);\n            } catch (RemoteException ignored) {\n            }\n        }\n    }\n\n    public void checkOngoingSmsRequest(String packageName, IOngoingSmsRequestCallback callback) {\n        try {\n            getServiceInterface().checkOngoingSmsRequest(packageName, callback);\n        } catch (RemoteException e) {\n            try {\n                callback.onHasOngoingSmsRequestResult(Status.INTERNAL_ERROR, false);\n            } catch (RemoteException ignored) {\n            }\n        }\n    }\n\n    public void startSmsCodeBrowser(IStatusCallback callback) {\n        try {\n            getServiceInterface().startSmsCodeBrowser(callback);\n        } catch (RemoteException e) {\n            try {\n                callback.onResult(Status.INTERNAL_ERROR);\n            } catch (RemoteException ignored) {\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-auth-api-phone/src/main/java/org/microg/gms/auth/api/phone/SmsRetrieverClientImpl.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth.api.phone;\n\nimport android.content.Context;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.auth.api.phone.SmsRetrieverClient;\nimport com.google.android.gms.tasks.Task;\nimport org.microg.gms.common.api.PendingGoogleApiCall;\n\npublic class SmsRetrieverClientImpl extends SmsRetrieverClient {\n    public SmsRetrieverClientImpl(Context context) {\n        super(context);\n    }\n\n    @NonNull\n    @Override\n    public Task<Void> startSmsRetriever() {\n        return scheduleTask((PendingGoogleApiCall<Void, SmsRetrieverApiClient>) (client, completionSource) -> client.startSmsRetriever(new SmsRetrieverResultCallbackImpl(completionSource)));\n    }\n\n    @NonNull\n    @Override\n    public Task<Void> startSmsUserConsent(@Nullable String senderAddress) {\n        return scheduleTask((PendingGoogleApiCall<Void, SmsRetrieverApiClient>) (client, completionSource) -> client.startWithConsentPrompt(senderAddress, new SmsRetrieverResultCallbackImpl(completionSource)));\n    }\n\n}\n"
  },
  {
    "path": "play-services-auth-api-phone/src/main/java/org/microg/gms/auth/api/phone/SmsRetrieverResultCallbackImpl.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth.api.phone;\n\nimport com.google.android.gms.auth.api.phone.internal.ISmsRetrieverResultCallback;\nimport com.google.android.gms.common.api.ApiException;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.tasks.TaskCompletionSource;\n\nclass SmsRetrieverResultCallbackImpl extends ISmsRetrieverResultCallback.Stub {\n    private final TaskCompletionSource<Void> completionSource;\n\n    public SmsRetrieverResultCallbackImpl(TaskCompletionSource<Void> completionSource) {\n        this.completionSource = completionSource;\n    }\n\n    @Override\n    public void onResult(Status status) {\n        if (status.isSuccess()) {\n            completionSource.trySetResult(null);\n        } else {\n            completionSource.trySetException(new ApiException(status));\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-auth-api-phone/src/main/java/org/microg/gms/auth/api/phone/StatusCallbackImpl.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth.api.phone;\n\nimport com.google.android.gms.common.api.ApiException;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.common.api.internal.IStatusCallback;\nimport com.google.android.gms.tasks.TaskCompletionSource;\n\nclass StatusCallbackImpl extends IStatusCallback.Stub {\n    private final TaskCompletionSource<Void> completionSource;\n\n    public StatusCallbackImpl(TaskCompletionSource<Void> completionSource) {\n        this.completionSource = completionSource;\n    }\n\n    @Override\n    public void onResult(Status status) {\n        if (status.isSuccess()) {\n            completionSource.trySetResult(null);\n        } else {\n            completionSource.trySetException(new ApiException(status));\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-auth-base/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\nandroid {\n    namespace \"com.google.android.gms.auth\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n}\n\napply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG implementation of play-services-auth-base'\n\ndependencies {\n    // Dependencies from play-services-auth-base:18.3.0\n    api 'androidx.collection:collection:1.0.0'\n    api project(':play-services-basement')\n    api project(':play-services-base')\n    api project(':play-services-tasks')\n    api 'org.jetbrains.kotlin:kotlin-stdlib:1.9.0'\n\n    annotationProcessor project(':safe-parcel-processor')\n}\n"
  },
  {
    "path": "play-services-auth-base/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest />"
  },
  {
    "path": "play-services-auth-base/src/main/aidl/com/google/android/auth/IAuthManagerService.aidl",
    "content": "package com.google.android.auth;\n\nimport android.os.Bundle;\nimport android.accounts.Account;\n\nimport com.google.android.gms.auth.AccountChangeEventsResponse;\nimport com.google.android.gms.auth.AccountChangeEventsRequest;\nimport com.google.android.gms.auth.GetHubTokenRequest;\nimport com.google.android.gms.auth.GetHubTokenInternalResponse;\nimport com.google.android.gms.auth.HasCapabilitiesRequest;\n\ninterface IAuthManagerService {\n    Bundle getToken(String accountName, String scope, in Bundle extras) = 0;\n    Bundle clearToken(String token, in Bundle extras) = 1;\n    AccountChangeEventsResponse getChangeEvents(in AccountChangeEventsRequest request) = 2;\n\n    Bundle getTokenWithAccount(in Account account, String scope, in Bundle extras) = 4;\n    Bundle getAccounts(in Bundle extras) = 5;\n    Bundle removeAccount(in Account account) = 6;\n    Bundle requestGoogleAccountsAccess(String packageName) = 7;\n    int hasCapabilities(in HasCapabilitiesRequest request) = 8;\n    GetHubTokenInternalResponse getHubToken(in GetHubTokenRequest request, in Bundle extras) = 9;\n}\n"
  },
  {
    "path": "play-services-auth-base/src/main/aidl/com/google/android/gms/auth/AccountChangeEventsRequest.aidl",
    "content": "package com.google.android.gms.auth;\n\nparcelable AccountChangeEventsRequest;"
  },
  {
    "path": "play-services-auth-base/src/main/aidl/com/google/android/gms/auth/AccountChangeEventsResponse.aidl",
    "content": "package com.google.android.gms.auth;\n\nparcelable AccountChangeEventsResponse;"
  },
  {
    "path": "play-services-auth-base/src/main/aidl/com/google/android/gms/auth/GetAccountsRequest.aidl",
    "content": "package com.google.android.gms.auth;\n\nparcelable GetAccountsRequest;\n"
  },
  {
    "path": "play-services-auth-base/src/main/aidl/com/google/android/gms/auth/GetHubTokenInternalResponse.aidl",
    "content": "package com.google.android.gms.auth;\n\nparcelable GetHubTokenInternalResponse;\n"
  },
  {
    "path": "play-services-auth-base/src/main/aidl/com/google/android/gms/auth/GetHubTokenRequest.aidl",
    "content": "package com.google.android.gms.auth;\n\nparcelable GetHubTokenRequest;\n"
  },
  {
    "path": "play-services-auth-base/src/main/aidl/com/google/android/gms/auth/HasCapabilitiesRequest.aidl",
    "content": "package com.google.android.gms.auth;\n\nparcelable HasCapabilitiesRequest;\n"
  },
  {
    "path": "play-services-auth-base/src/main/aidl/com/google/android/gms/auth/account/data/IBundleCallback.aidl",
    "content": "package com.google.android.gms.auth.account.data;\n\nimport com.google.android.gms.common.api.Status;\n\ninterface IBundleCallback {\n    void onBundle(in Status status, in Bundle bundle) = 1;\n}"
  },
  {
    "path": "play-services-auth-base/src/main/aidl/com/google/android/gms/auth/account/data/IGetAccountChangeEventsCallback.aidl",
    "content": "package com.google.android.gms.auth.account.data;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.auth.AccountChangeEventsResponse;\n\ninterface IGetAccountChangeEventsCallback {\n    void onAccountChangeEventsResponse(in Status status, in AccountChangeEventsResponse response) = 1;\n}"
  },
  {
    "path": "play-services-auth-base/src/main/aidl/com/google/android/gms/auth/account/data/IGetAccountsCallback.aidl",
    "content": "package com.google.android.gms.auth.account.data;\n\nimport com.google.android.gms.common.api.Status;\n\ninterface IGetAccountsCallback {\n    void onBundle(in Status status, in List<Account> bundle) = 1;\n}"
  },
  {
    "path": "play-services-auth-base/src/main/aidl/com/google/android/gms/auth/account/data/IGetHubTokenCallback.aidl",
    "content": "package com.google.android.gms.auth.account.data;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.auth.GetHubTokenInternalResponse;\n\ninterface IGetHubTokenCallback {\n    void onGetHubTokenResponse(in Status status, in GetHubTokenInternalResponse bundle) = 1;\n}"
  },
  {
    "path": "play-services-auth-base/src/main/aidl/com/google/android/gms/auth/account/data/IGetTokenWithDetailsCallback.aidl",
    "content": "package com.google.android.gms.auth.account.data;\n\nimport com.google.android.gms.common.api.Status;\n\ninterface IGetTokenWithDetailsCallback {\n    void onTokenResults(in Status status, in Bundle bundle) = 1;\n}"
  },
  {
    "path": "play-services-auth-base/src/main/aidl/com/google/android/gms/auth/account/data/IGoogleAuthService.aidl",
    "content": "package com.google.android.gms.auth.account.data;\n\nimport android.accounts.Account;\n\nimport com.google.android.gms.auth.AccountChangeEventsRequest;\nimport com.google.android.gms.auth.GetAccountsRequest;\nimport com.google.android.gms.auth.GetHubTokenRequest;\nimport com.google.android.gms.auth.HasCapabilitiesRequest;\nimport com.google.android.gms.auth.account.data.IBundleCallback;\nimport com.google.android.gms.auth.account.data.IGetAccountChangeEventsCallback;\nimport com.google.android.gms.auth.account.data.IGetAccountsCallback;\nimport com.google.android.gms.auth.account.data.IGetHubTokenCallback;\nimport com.google.android.gms.auth.account.data.IGetTokenWithDetailsCallback;\nimport com.google.android.gms.auth.account.data.IHasCapabilitiesCallback;\nimport com.google.android.gms.auth.firstparty.dataservice.ClearTokenRequest;\nimport com.google.android.gms.common.api.internal.IStatusCallback;\n\ninterface IGoogleAuthService {\n    void getTokenWithDetails(IGetTokenWithDetailsCallback callback, in Account account, String service, in Bundle extras) = 0;\n    void clearToken(IStatusCallback callback, in ClearTokenRequest request) = 1;\n    void requestAccountsAccess(IBundleCallback callback, String str) = 2;\n    void getAccountChangeEvents(IGetAccountChangeEventsCallback callback, in AccountChangeEventsRequest request) = 3;\n    void getAccounts(IGetAccountsCallback callback, in GetAccountsRequest request) = 4;\n    void removeAccount(IBundleCallback callback, in Account account) = 5;\n    void hasCapabilities(IHasCapabilitiesCallback callback, in HasCapabilitiesRequest request) = 6;\n    void getHubToken(IGetHubTokenCallback callback, in GetHubTokenRequest request) = 7;\n}"
  },
  {
    "path": "play-services-auth-base/src/main/aidl/com/google/android/gms/auth/account/data/IHasCapabilitiesCallback.aidl",
    "content": "package com.google.android.gms.auth.account.data;\n\nimport com.google.android.gms.common.api.Status;\n\ninterface IHasCapabilitiesCallback {\n    void onHasCapabilities(in Status status, int mode) = 1;\n}"
  },
  {
    "path": "play-services-auth-base/src/main/aidl/com/google/android/gms/auth/api/internal/IAuthCallbacks.aidl",
    "content": "package com.google.android.gms.auth.api.internal;\n\nimport com.google.android.gms.auth.api.proxy.ProxyResponse;\n\ninterface IAuthCallbacks {\n    void onProxyResponse(in ProxyResponse response) = 0;\n    void onSpatulaHeader(String spatulaHeader) = 1;\n}\n"
  },
  {
    "path": "play-services-auth-base/src/main/aidl/com/google/android/gms/auth/api/internal/IAuthService.aidl",
    "content": "package com.google.android.gms.auth.api.internal;\n\nimport com.google.android.gms.auth.api.internal.IAuthCallbacks;\n//import com.google.android.gms.auth.api.proxy.ProxyGrpcRequest;\nimport com.google.android.gms.auth.api.proxy.ProxyRequest;\n\ninterface IAuthService {\n    void performProxyRequest(IAuthCallbacks callbacks, in ProxyRequest request) = 0;\n//    void performProxyGrpcRequest(IAuthCallback callbacks, in ProxyGrpcRequest request) = 1;\n    void getSpatulaHeader(IAuthCallbacks callbacks) = 2;\n}\n"
  },
  {
    "path": "play-services-auth-base/src/main/aidl/com/google/android/gms/auth/api/proxy/ProxyRequest.aidl",
    "content": "package com.google.android.gms.auth.api.proxy;\n\nparcelable ProxyRequest;\n"
  },
  {
    "path": "play-services-auth-base/src/main/aidl/com/google/android/gms/auth/api/proxy/ProxyResponse.aidl",
    "content": "package com.google.android.gms.auth.api.proxy;\n\nparcelable ProxyResponse;\n"
  },
  {
    "path": "play-services-auth-base/src/main/aidl/com/google/android/gms/auth/firstparty/dataservice/ClearTokenRequest.aidl",
    "content": "package com.google.android.gms.auth.firstparty.dataservice;\n\nparcelable ClearTokenRequest;\n"
  },
  {
    "path": "play-services-auth-base/src/main/aidl/com/google/android/gms/auth/firstparty/dataservice/DeviceManagementInfoResponse.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.firstparty.dataservice;\n\nparcelable DeviceManagementInfoResponse;\n"
  },
  {
    "path": "play-services-auth-base/src/main/aidl/com/google/android/gms/auth/folsom/RecoveryRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.folsom;\n\nparcelable RecoveryRequest;"
  },
  {
    "path": "play-services-auth-base/src/main/aidl/com/google/android/gms/auth/folsom/RecoveryResult.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.folsom;\n\nparcelable RecoveryResult;"
  },
  {
    "path": "play-services-auth-base/src/main/aidl/com/google/android/gms/auth/folsom/SharedKey.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.folsom;\n\nparcelable SharedKey;"
  },
  {
    "path": "play-services-auth-base/src/main/aidl/com/google/android/gms/auth/folsom/internal/IBooleanCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.folsom.internal;\n\nimport com.google.android.gms.common.api.Status;\n\ninterface IBooleanCallback {\n    void onResult(in Status status, boolean result);\n}\n"
  },
  {
    "path": "play-services-auth-base/src/main/aidl/com/google/android/gms/auth/folsom/internal/IByteArrayCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.folsom.internal;\n\nimport com.google.android.gms.common.api.Status;\n\ninterface IByteArrayCallback {\n    void onResult(in Status status, in byte[] bArr);\n}\n"
  },
  {
    "path": "play-services-auth-base/src/main/aidl/com/google/android/gms/auth/folsom/internal/IByteArrayListCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.folsom.internal;\n\nimport com.google.android.gms.common.api.Status;\n\ninterface IByteArrayListCallback {\n    void onResult(in Status status, in List list);\n}\n"
  },
  {
    "path": "play-services-auth-base/src/main/aidl/com/google/android/gms/auth/folsom/internal/IKeyRetrievalCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.folsom.internal;\n\nimport com.google.android.gms.common.api.Status;\n\ninterface IKeyRetrievalCallback {\n    void onResult(in Status status);\n}\n"
  },
  {
    "path": "play-services-auth-base/src/main/aidl/com/google/android/gms/auth/folsom/internal/IKeyRetrievalConsentCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.folsom.internal;\n\nimport com.google.android.gms.common.api.Status;\n\ninterface IKeyRetrievalConsentCallback {\n    void onResult(in Status status, boolean consent);\n}\n"
  },
  {
    "path": "play-services-auth-base/src/main/aidl/com/google/android/gms/auth/folsom/internal/IKeyRetrievalService.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.folsom.internal;\n\nimport com.google.android.gms.auth.folsom.RecoveryRequest;\nimport com.google.android.gms.auth.folsom.SharedKey;\nimport com.google.android.gms.common.api.ApiMetadata;\nimport com.google.android.gms.auth.folsom.internal.IKeyRetrievalConsentCallback;\nimport com.google.android.gms.auth.folsom.internal.IKeyRetrievalSyncStatusCallback;\nimport com.google.android.gms.auth.folsom.internal.IKeyRetrievalCallback;\nimport com.google.android.gms.auth.folsom.internal.ISharedKeyCallback;\nimport com.google.android.gms.auth.folsom.internal.IStringListCallback;\nimport com.google.android.gms.auth.folsom.internal.IRecoveryResultCallback;\nimport com.google.android.gms.auth.folsom.internal.IByteArrayListCallback;\nimport com.google.android.gms.auth.folsom.internal.IByteArrayCallback;\nimport com.google.android.gms.auth.folsom.internal.ISecurityDomainMembersCallback;\nimport com.google.android.gms.auth.folsom.internal.IBooleanCallback;\nimport com.google.android.gms.common.api.internal.IStatusCallback;\n\ninterface IKeyRetrievalService {\n    void setConsent(in IKeyRetrievalConsentCallback callback, String accountName, boolean force, in ApiMetadata metadata) = 0;\n    void getConsent(in IKeyRetrievalConsentCallback callback, String accountName, in ApiMetadata metadata) = 1;\n    void getSyncStatus(in IKeyRetrievalSyncStatusCallback callback, String accountName, in ApiMetadata metadata) = 2;\n    void markLocalKeysAsStale(in IKeyRetrievalCallback callback, String accountName, in ApiMetadata metadata) = 3;\n    void getKeyMaterial(in ISharedKeyCallback callback, String accountName, in ApiMetadata metadata) = 4;\n    void setKeyMaterial(in IKeyRetrievalCallback callback, String accountName, in SharedKey[] keys, in ApiMetadata metadata) = 5;\n    void getRecoveredSecurityDomains(in IStringListCallback callback, String accountName, in ApiMetadata metadata) = 6;\n    void startRecoveryOperation(in IRecoveryResultCallback callback, in ApiMetadata metadata, in RecoveryRequest request) = 7;\n    void listVaultsOperation(in IByteArrayListCallback callback, String accountName, in ApiMetadata metadata) = 8;\n    void getProductDetails(in IByteArrayCallback callback, String accountName, in ApiMetadata metadata) = 9;\n    void joinSecurityDomain(in IStatusCallback callback, String accountName, in byte[] bytes, int type, in ApiMetadata metadata) = 10;\n    void startUxFlow(in IKeyRetrievalCallback callback, String accountName, int type, in ApiMetadata metadata) = 11;\n    void promptForLskfConsent(in IKeyRetrievalCallback callback, String accountName, in ApiMetadata metadata) = 12;\n    void resetSecurityDomain(in IStatusCallback callback, String accountName, in ApiMetadata metadata) = 13;\n    void listSecurityDomainMembers(in ISecurityDomainMembersCallback callback, String accountName, in ApiMetadata metadata) = 14;\n    void generateOpenVaultRequestOperation(in IByteArrayCallback callback, in RecoveryRequest request, in ApiMetadata metadata) = 15;\n    void canSilentlyAddGaiaPassword(in IBooleanCallback callback, String accountName, in ApiMetadata metadata) = 16;\n    void addGaiaPasswordMember(in IStatusCallback callback, String accountName, in ApiMetadata metadata) = 17;\n    void getDomainState(in IByteArrayCallback callback, String accountName, in ApiMetadata metadata) = 18;\n}\n"
  },
  {
    "path": "play-services-auth-base/src/main/aidl/com/google/android/gms/auth/folsom/internal/IKeyRetrievalSyncStatusCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.folsom.internal;\n\nimport com.google.android.gms.common.api.Status;\n\ninterface IKeyRetrievalSyncStatusCallback {\n    void onResult(in Status status, boolean sync);\n}\n"
  },
  {
    "path": "play-services-auth-base/src/main/aidl/com/google/android/gms/auth/folsom/internal/IRecoveryResultCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.folsom.internal;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.auth.folsom.RecoveryResult;\n\ninterface IRecoveryResultCallback {\n    void onResult(in Status status, in RecoveryResult recoveryResult);\n}\n"
  },
  {
    "path": "play-services-auth-base/src/main/aidl/com/google/android/gms/auth/folsom/internal/ISecurityDomainMembersCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.folsom.internal;\n\nimport com.google.android.gms.common.api.Status;\n\ninterface ISecurityDomainMembersCallback {\n    void onResult(in Status status, in List list);\n}\n"
  },
  {
    "path": "play-services-auth-base/src/main/aidl/com/google/android/gms/auth/folsom/internal/ISharedKeyCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.folsom.internal;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.auth.folsom.SharedKey;\n\ninterface ISharedKeyCallback {\n    void onResult(in Status status, in SharedKey[] sharedKeyArr);\n}\n"
  },
  {
    "path": "play-services-auth-base/src/main/aidl/com/google/android/gms/auth/folsom/internal/IStringListCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.folsom.internal;\n\nimport com.google.android.gms.common.api.Status;\n\ninterface IStringListCallback {\n    void onResult(in Status status, in String[] strArr);\n}\n"
  },
  {
    "path": "play-services-auth-base/src/main/java/com/google/android/gms/auth/AccountChangeEvent.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.auth;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class AccountChangeEvent extends AutoSafeParcelable {\n    public static Creator<AccountChangeEvent> CREATOR = new AutoCreator<AccountChangeEvent>(AccountChangeEvent.class);\n}\n"
  },
  {
    "path": "play-services-auth-base/src/main/java/com/google/android/gms/auth/AccountChangeEventsRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.auth;\n\nimport static org.microg.gms.auth.AuthConstants.DEFAULT_ACCOUNT_TYPE;\n\nimport android.accounts.Account;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class AccountChangeEventsRequest extends AutoSafeParcelable {\n    @Field(1)\n    private int versionCode = 1;\n    @Field(2)\n    private int since;\n    @Field(3)\n    @Deprecated\n    private String accountName;\n    @Field(4)\n    private Account account;\n\n    public Account getAccount() {\n        if (account != null) return account;\n        if (accountName != null) return new Account(accountName, DEFAULT_ACCOUNT_TYPE);\n        return null;\n    }\n\n    public static Creator<AccountChangeEventsRequest> CREATOR = new AutoCreator<AccountChangeEventsRequest>(AccountChangeEventsRequest.class);\n\n}\n"
  },
  {
    "path": "play-services-auth-base/src/main/java/com/google/android/gms/auth/AccountChangeEventsResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.auth;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class AccountChangeEventsResponse extends AutoSafeParcelable {\n    @SafeParceled(1)\n    private int versionCode = 1;\n    @SafeParceled(value = 2, subClass = AccountChangeEvent.class)\n    private List<AccountChangeEvent> events;\n\n    public AccountChangeEventsResponse() {\n        events = new ArrayList<AccountChangeEvent>();\n    }\n\n    public static Creator<AccountChangeEventsResponse> CREATOR = new AutoCreator<AccountChangeEventsResponse>(AccountChangeEventsResponse.class);\n}\n"
  },
  {
    "path": "play-services-auth-base/src/main/java/com/google/android/gms/auth/GetAccountsRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.auth;\n\nimport org.microg.gms.common.Hide;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n@Hide\npublic class GetAccountsRequest extends AutoSafeParcelable {\n    public static Creator<GetAccountsRequest> CREATOR = findCreator(GetAccountsRequest.class);\n}\n"
  },
  {
    "path": "play-services-auth-base/src/main/java/com/google/android/gms/auth/GetHubTokenInternalResponse.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth;\n\nimport android.accounts.Account;\nimport android.content.Intent;\n\nimport org.microg.gms.common.Hide;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n@Hide\npublic class GetHubTokenInternalResponse extends AutoSafeParcelable {\n    @Field(1)\n    public TokenData tokenData;\n    @Field(2)\n    public String status;\n    @Field(3)\n    public Intent recoveryIntent;\n    public static final Creator<GetHubTokenInternalResponse> CREATOR = new AutoCreator<>(GetHubTokenInternalResponse.class);\n}\n"
  },
  {
    "path": "play-services-auth-base/src/main/java/com/google/android/gms/auth/GetHubTokenRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth;\n\nimport org.microg.gms.common.Hide;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n@Hide\npublic class GetHubTokenRequest extends AutoSafeParcelable {\n    @Field(1)\n    public String accountName;\n    @Field(2)\n    public String service;\n    @Field(3)\n    public String packageName;\n    @Field(4)\n    public int callerUid;\n    public static final Creator<GetHubTokenRequest> CREATOR = new AutoCreator<>(GetHubTokenRequest.class);\n}\n"
  },
  {
    "path": "play-services-auth-base/src/main/java/com/google/android/gms/auth/HasCapabilitiesRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth;\n\nimport android.accounts.Account;\n\nimport org.microg.gms.common.Hide;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n@Hide\npublic class HasCapabilitiesRequest extends AutoSafeParcelable {\n    @Field(1)\n    public Account account;\n    @Field(2)\n    public String[] capabilities;\n    public static final Creator<HasCapabilitiesRequest> CREATOR = new AutoCreator<>(HasCapabilitiesRequest.class);\n}\n"
  },
  {
    "path": "play-services-auth-base/src/main/java/com/google/android/gms/auth/TokenData.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.auth;\n\nimport com.google.android.gms.common.api.Scope;\n\nimport org.microg.gms.common.Hide;\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n@Hide\npublic class TokenData extends AutoSafeParcelable {\n    @Field(value = 1, versionCode = 1)\n    private int versionCode = 1;\n\n    @Field(2)\n    public final String token;\n\n    @Field(3)\n    public final Long expiry;\n\n    @Field(5)\n    public final boolean isOAuth;\n\n    @Field(6)\n    public final List<String> scopes;\n\n    public TokenData() {\n        token = null;\n        expiry = null;\n        isOAuth = false;\n        scopes = null;\n    }\n\n    public TokenData(String token, Long expiry, boolean isOAuth, List<Scope> scopes) {\n        this.token = token;\n        this.expiry = expiry;\n        this.isOAuth = isOAuth;\n        this.scopes = new ArrayList<>();\n        if (scopes != null) {\n            for (Scope scope : scopes) {\n                this.scopes.add(scope.getScopeUri());\n            }\n        }\n    }\n\n    public TokenData(String token, Long expiry) {\n        this.token = token;\n        this.expiry = expiry;\n        this.isOAuth = false;\n        this.scopes = null;\n    }\n\n    public static final Creator<TokenData> CREATOR = new AutoCreator<TokenData>(TokenData.class);\n}\n"
  },
  {
    "path": "play-services-auth-base/src/main/java/com/google/android/gms/auth/api/proxy/ProxyRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.api.proxy;\n\nimport android.os.Bundle;\n\nimport org.microg.gms.common.Hide;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n@Hide\npublic class ProxyRequest extends AutoSafeParcelable {\n    public static final int HTTP_METHOD_GET = 0;\n    public static final int HTTP_METHOD_POST = 1;\n    public static final int HTTP_METHOD_PUT = 2;\n    public static final int HTTP_METHOD_DELETE = 3;\n    public static final int HTTP_METHOD_HEAD = 4;\n    public static final int HTTP_METHOD_OPTIONS = 5;\n    public static final int HTTP_METHOD_TRACE = 6;\n    public static final int HTTP_METHOD_PATCH = 7;\n\n    @Field(1000)\n    private int versionCode = 2;\n    @Field(1)\n    public String url;\n    @Field(2)\n    public int httpMethod;\n    @Field(3)\n    public long timeoutMillis;\n    @Field(4)\n    public byte[] body;\n    @Field(5)\n    public Bundle headers;\n\n    @Override\n    public String toString() {\n        return url;\n    }\n\n    public static final Creator<ProxyRequest> CREATOR = new AutoCreator<>(ProxyRequest.class);\n}\n"
  },
  {
    "path": "play-services-auth-base/src/main/java/com/google/android/gms/auth/api/proxy/ProxyResponse.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.api.proxy;\n\nimport android.app.PendingIntent;\nimport android.os.Bundle;\n\nimport org.microg.gms.common.Hide;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n@Hide\npublic class ProxyResponse extends AutoSafeParcelable {\n    public static final int STATUS_CODE_NO_CONNECTION = -1;\n\n    @Field(1000)\n    private int versionCode = 1;\n    @Field(1)\n    public int gmsStatusCode;\n    @Field(2)\n    public PendingIntent recoveryAction;\n    @Field(3)\n    public int httpStatusCode;\n    @Field(4)\n    public Bundle headers;\n    @Field(5)\n    public byte[] body;\n\n    public static final Creator<ProxyResponse> CREATOR = new AutoCreator<>(ProxyResponse.class);\n}\n"
  },
  {
    "path": "play-services-auth-base/src/main/java/com/google/android/gms/auth/firstparty/dataservice/ClearTokenRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.firstparty.dataservice;\n\nimport org.microg.gms.common.Hide;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n@Hide\npublic class ClearTokenRequest extends AutoSafeParcelable {\n    @Field(1)\n    private int versionCode = 1;\n    @Field(2)\n    public String token;\n\n    public static final Creator<ClearTokenRequest> CREATOR = findCreator(ClearTokenRequest.class);\n}\n"
  },
  {
    "path": "play-services-auth-base/src/main/java/com/google/android/gms/auth/firstparty/dataservice/DeviceManagementInfoResponse.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.firstparty.dataservice;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class DeviceManagementInfoResponse extends AbstractSafeParcelable {\n    @Field(1)\n    public final int versionCode;\n    @Field(2)\n    public final String info;\n    @Field(3)\n    public final boolean status;\n\n\n    @Constructor\n    public DeviceManagementInfoResponse(@Param(1) int versionCode, @Param(2) String info, @Param(3) boolean status) {\n        this.versionCode = versionCode;\n        this.info = info;\n        this.status = status;\n    }\n\n    public DeviceManagementInfoResponse(String info, boolean status) {\n        this(1, info, status);\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<DeviceManagementInfoResponse> CREATOR = findCreator(DeviceManagementInfoResponse.class);\n\n}\n"
  },
  {
    "path": "play-services-auth-base/src/main/java/com/google/android/gms/auth/folsom/RecoveryRequest.java",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.folsom;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class RecoveryRequest extends AbstractSafeParcelable {\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<RecoveryRequest> CREATOR = findCreator(RecoveryRequest.class);\n}\n"
  },
  {
    "path": "play-services-auth-base/src/main/java/com/google/android/gms/auth/folsom/RecoveryResult.java",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.folsom;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class RecoveryResult extends AbstractSafeParcelable {\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<RecoveryResult> CREATOR = findCreator(RecoveryResult.class);\n}\n"
  },
  {
    "path": "play-services-auth-base/src/main/java/com/google/android/gms/auth/folsom/SharedKey.java",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.folsom;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class SharedKey extends AbstractSafeParcelable {\n\n    @Field(1)\n    public int key;\n    @Field(2)\n    public byte[] keyMaterial;\n\n    public SharedKey() {\n    }\n\n    @Constructor\n    public SharedKey(@Param(1) int key, @Param(2) byte[] keyMaterial) {\n        this.key = key;\n        this.keyMaterial = keyMaterial;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<SharedKey> CREATOR = findCreator(SharedKey.class);\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"SharedKey\").field(\"key\", key).end();\n    }\n}\n"
  },
  {
    "path": "play-services-auth-base/src/main/java/com/google/android/gms/auth/package-info.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n/**\n * Contains classes for authenticating Google accounts.\n */\npackage com.google.android.gms.auth;\n"
  },
  {
    "path": "play-services-auth-blockstore/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\n// Metadata derived from play-services-auth-blockstore:16.4.0\n\napply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\nandroid {\n    namespace \"com.google.android.gms.auth.blockstore\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n}\n\napply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG implementation of play-services-auth-blockstore'\n\ndependencies {\n    api project(':play-services-base')\n    api project(':play-services-basement')\n    api project(':play-services-tasks')\n    api 'org.jetbrains.kotlin:kotlin-stdlib:1.9.0'\n\n    annotationProcessor project(':safe-parcel-processor')\n}\n"
  },
  {
    "path": "play-services-auth-blockstore/core/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'kotlin-android'\n\ndependencies {\n    api project(':play-services-auth-blockstore')\n    implementation project(':play-services-base-core')\n}\n\nandroid {\n    namespace \"org.microg.gms.auth.blockstore\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    sourceSets {\n        main.java.srcDirs += 'src/main/kotlin'\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n\n    kotlinOptions {\n        jvmTarget = 1.8\n    }\n\n    lintOptions {\n        disable 'MissingTranslation', 'GetLocales'\n    }\n}\n"
  },
  {
    "path": "play-services-auth-blockstore/core/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2025 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <application>\n\n        <service android:name=\"org.microg.gms.auth.blockstore.BlockstoreApiService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.auth.blockstore.service.START\" />\n            </intent-filter>\n        </service>\n\n    </application>\n</manifest>\n"
  },
  {
    "path": "play-services-auth-blockstore/core/src/main/kotlin/org/microg/gms/auth/blockstore/BlockStoreImpl.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth.blockstore\n\nimport android.content.Context\nimport android.content.SharedPreferences\nimport android.os.Bundle\nimport android.util.Base64\nimport android.util.Log\nimport com.google.android.gms.auth.blockstore.BlockstoreClient\nimport com.google.android.gms.auth.blockstore.BlockstoreStatusCodes\nimport com.google.android.gms.auth.blockstore.DeleteBytesRequest\nimport com.google.android.gms.auth.blockstore.RetrieveBytesRequest\nimport com.google.android.gms.auth.blockstore.RetrieveBytesResponse\nimport com.google.android.gms.auth.blockstore.StoreBytesData\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\nimport org.microg.gms.utils.toBase64\n\nprivate const val SHARED_PREFS_NAME = \"com.google.android.gms.blockstore\"\n\nprivate const val TAG = \"BlockStoreImpl\"\n\nclass BlockStoreImpl(context: Context, val callerPackage: String) {\n\n    private val blockStoreSp: SharedPreferences by lazy {\n        context.getSharedPreferences(SHARED_PREFS_NAME, Context.MODE_PRIVATE)\n    }\n\n    private fun initSpByPackage(): Map<String, *>? {\n        val map = blockStoreSp.all\n        if (map.isNullOrEmpty() || map.all { !it.key.startsWith(callerPackage) }) return null\n        return map.filter { it.key.startsWith(callerPackage) }\n    }\n\n    suspend fun deleteBytesWithRequest(request: DeleteBytesRequest?): Boolean = withContext(Dispatchers.IO) {\n        Log.d(TAG, \"deleteBytesWithRequest: callerPackage: $callerPackage\")\n        val localData = initSpByPackage()\n        if (request == null || localData.isNullOrEmpty()) return@withContext false\n        if (request.deleteAll) {\n            localData.keys.forEach { blockStoreSp.edit()?.remove(it)?.commit() }\n        } else {\n            request.keys.forEach { blockStoreSp.edit()?.remove(\"$callerPackage:$it\")?.commit() }\n        }\n        true\n    }\n\n    suspend fun retrieveBytesWithRequest(request: RetrieveBytesRequest?): RetrieveBytesResponse? = withContext(Dispatchers.IO) {\n        Log.d(TAG, \"retrieveBytesWithRequest: callerPackage: $callerPackage\")\n        val localData = initSpByPackage()\n        if (request == null || localData.isNullOrEmpty()) return@withContext null\n        val data = mutableListOf<RetrieveBytesResponse.BlockstoreData>()\n        val filterKeys = if (request.keys.isNullOrEmpty()) emptyList<String>() else request.keys\n        for (key in localData.keys) {\n            val bytesKey = key.substring(callerPackage.length + 1)\n            if (filterKeys.isNotEmpty() && !filterKeys.contains(bytesKey)) continue\n            val bytes = blockStoreSp.getString(key, null)?.let { Base64.decode(it, Base64.URL_SAFE) } ?: continue\n            data.add(RetrieveBytesResponse.BlockstoreData(bytes, bytesKey))\n        }\n        RetrieveBytesResponse(Bundle.EMPTY, data)\n    }\n\n    suspend fun retrieveBytes(): ByteArray? = withContext(Dispatchers.IO) {\n        Log.d(TAG, \"retrieveBytes: callerPackage: $callerPackage\")\n        val localData = initSpByPackage()\n        if (localData.isNullOrEmpty()) return@withContext null\n        val savedKey = localData.keys.firstOrNull { it == \"$callerPackage:${BlockstoreClient.DEFAULT_BYTES_DATA_KEY}\" } ?: return@withContext null\n        blockStoreSp.getString(savedKey, null)?.let { Base64.decode(it, Base64.URL_SAFE) }\n    }\n\n    suspend fun storeBytes(data: StoreBytesData?): Int = withContext(Dispatchers.IO) {\n        if (data == null || data.bytes == null) return@withContext 0\n        val localData = initSpByPackage()\n        if ((localData?.size ?: 0) >= BlockstoreClient.MAX_ENTRY_COUNT) {\n            return@withContext BlockstoreStatusCodes.TOO_MANY_ENTRIES\n        }\n        val bytes = data.bytes\n        if (bytes.size > BlockstoreClient.MAX_SIZE) {\n            return@withContext BlockstoreStatusCodes.MAX_SIZE_EXCEEDED\n        }\n        val savedKey = \"$callerPackage:${data.key ?: BlockstoreClient.DEFAULT_BYTES_DATA_KEY}\"\n        val base64 = bytes.toBase64(Base64.URL_SAFE)\n        val bool = blockStoreSp.edit()?.putString(savedKey, base64)?.commit()\n        if (bool == true) bytes.size else 0\n    }\n}"
  },
  {
    "path": "play-services-auth-blockstore/core/src/main/kotlin/org/microg/gms/auth/blockstore/BlockstoreApiService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth.blockstore\n\nimport android.os.Bundle\nimport android.util.Log\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.LifecycleOwner\nimport androidx.lifecycle.lifecycleScope\nimport com.google.android.gms.auth.blockstore.AppRestoreInfo\nimport com.google.android.gms.auth.blockstore.BlockstoreStatusCodes\nimport com.google.android.gms.auth.blockstore.DeleteBytesRequest\nimport com.google.android.gms.auth.blockstore.RetrieveBytesRequest\nimport com.google.android.gms.auth.blockstore.RetrieveBytesResponse\nimport com.google.android.gms.auth.blockstore.StoreBytesData\nimport com.google.android.gms.auth.blockstore.internal.IBlockstoreService\nimport com.google.android.gms.auth.blockstore.internal.IDeleteBytesCallback\nimport com.google.android.gms.auth.blockstore.internal.IGetAccessForPackageCallback\nimport com.google.android.gms.auth.blockstore.internal.IGetBlockstoreDataCallback\nimport com.google.android.gms.auth.blockstore.internal.IIsEndToEndEncryptionAvailableCallback\nimport com.google.android.gms.auth.blockstore.internal.IRetrieveBytesCallback\nimport com.google.android.gms.auth.blockstore.internal.ISetBlockstoreDataCallback\nimport com.google.android.gms.auth.blockstore.internal.IStoreBytesCallback\nimport com.google.android.gms.common.Feature\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.api.internal.IStatusCallback\nimport com.google.android.gms.common.internal.ConnectionInfo\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport kotlinx.coroutines.launch\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.common.GmsService.AUTH_BLOCKSTORE\nimport org.microg.gms.common.PackageUtils\n\nprivate const val TAG = \"BlockstoreApiService\"\n\nprivate val FEATURES = arrayOf(\n    Feature(\"auth_blockstore\", 3),\n    Feature(\"blockstore_data_transfer\", 1),\n    Feature(\"blockstore_notify_app_restore\", 1),\n    Feature(\"blockstore_store_bytes_with_options\", 2),\n    Feature(\"blockstore_is_end_to_end_encryption_available\", 1),\n    Feature(\"blockstore_enable_cloud_backup\", 1),\n    Feature(\"blockstore_delete_bytes\", 2),\n    Feature(\"blockstore_retrieve_bytes_with_options\", 3),\n    Feature(\"auth_clear_restore_credential\", 2),\n    Feature(\"auth_create_restore_credential\", 1),\n    Feature(\"auth_get_restore_credential\", 1),\n    Feature(\"auth_get_private_restore_credential_key\", 1),\n    Feature(\"auth_set_private_restore_credential_key\", 1),\n)\n\nclass BlockstoreApiService : BaseService(TAG, AUTH_BLOCKSTORE) {\n\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        try {\n            val packageName = PackageUtils.getAndCheckCallingPackage(this, request.packageName) ?: throw IllegalArgumentException(\"Missing package name\")\n\n            val blockStoreImpl = BlockStoreImpl(this, packageName)\n            callback.onPostInitCompleteWithConnectionInfo(\n                CommonStatusCodes.SUCCESS, BlobstoreServiceImpl(blockStoreImpl, lifecycle).asBinder(), ConnectionInfo().apply { features = FEATURES })\n        } catch (e: Exception) {\n            Log.w(TAG, \"handleServiceRequest\", e)\n            callback.onPostInitComplete(CommonStatusCodes.INTERNAL_ERROR, null, null)\n        }\n    }\n}\n\nclass BlobstoreServiceImpl(val blockStore: BlockStoreImpl, override val lifecycle: Lifecycle) : IBlockstoreService.Stub(), LifecycleOwner {\n\n    override fun retrieveBytes(callback: IRetrieveBytesCallback?) {\n        Log.d(TAG, \"Method (retrieveBytes) called\")\n        lifecycleScope.launch {\n            runCatching {\n                val retrieveBytes = blockStore.retrieveBytes()\n                if (retrieveBytes != null) {\n                    callback?.onBytesResult(Status.SUCCESS, retrieveBytes)\n                } else {\n                    callback?.onBytesResult(Status.INTERNAL_ERROR, null)\n                }\n            }\n        }\n    }\n\n    override fun setBlockstoreData(callback: ISetBlockstoreDataCallback?, data: ByteArray?) {\n        Log.d(TAG, \"Method (setBlockstoreData: ${data?.size}) called but not implemented\")\n    }\n\n    override fun getBlockstoreData(callback: IGetBlockstoreDataCallback?) {\n        Log.d(TAG, \"Method (getBlockstoreData) called but not implemented\")\n    }\n\n    override fun getAccessForPackage(callback: IGetAccessForPackageCallback?, packageName: String?) {\n        Log.d(TAG, \"Method (getAccessForPackage: $packageName) called but not implemented\")\n    }\n\n    override fun setFlagWithPackage(callback: IStatusCallback?, packageName: String?, flag: Int) {\n        Log.d(TAG, \"Method (setFlagWithPackage: $packageName, $flag) called but not implemented\")\n    }\n\n    override fun clearFlagForPackage(callback: IStatusCallback?, packageName: String?) {\n        Log.d(TAG, \"Method (clearFlagForPackage: $packageName) called but not implemented\")\n    }\n\n    override fun updateFlagForPackage(callback: IStatusCallback?, packageName: String?, value: Int) {\n        Log.d(TAG, \"Method (updateFlagForPackage: $packageName, $value) called but not implemented\")\n    }\n\n    override fun reportAppRestore(callback: IStatusCallback?, packages: List<String?>?, code: Int, info: AppRestoreInfo?) {\n        Log.d(TAG, \"Method (reportAppRestore: $packages, $code, $info) called but not implemented\")\n    }\n\n    override fun storeBytes(callback: IStoreBytesCallback?, data: StoreBytesData?) {\n        Log.d(TAG, \"Method (storeBytes: $data) called\")\n        lifecycleScope.launch {\n            runCatching {\n                val storeBytes = blockStore.storeBytes(data)\n                Log.d(TAG, \"storeBytes: size: $storeBytes\")\n                when (storeBytes) {\n                    0 -> callback?.onStoreBytesResult(Status.INTERNAL_ERROR, BlockstoreStatusCodes.FEATURE_NOT_SUPPORTED)\n                    BlockstoreStatusCodes.MAX_SIZE_EXCEEDED -> callback?.onStoreBytesResult(Status.INTERNAL_ERROR, BlockstoreStatusCodes.MAX_SIZE_EXCEEDED)\n                    BlockstoreStatusCodes.TOO_MANY_ENTRIES -> callback?.onStoreBytesResult(Status.INTERNAL_ERROR, BlockstoreStatusCodes.TOO_MANY_ENTRIES)\n                    else -> callback?.onStoreBytesResult(Status.SUCCESS, storeBytes)\n                }\n            }\n        }\n    }\n\n    override fun isEndToEndEncryptionAvailable(callback: IIsEndToEndEncryptionAvailableCallback?) {\n        Log.d(TAG, \"Method (isEndToEndEncryptionAvailable) called\")\n        runCatching { callback?.onCheckEndToEndEncryptionResult(Status.SUCCESS, false) }\n    }\n\n    override fun retrieveBytesWithRequest(callback: IRetrieveBytesCallback?, request: RetrieveBytesRequest?) {\n        Log.d(TAG, \"Method (retrieveBytesWithRequest: $request) called\")\n        lifecycleScope.launch {\n            runCatching {\n                val retrieveBytesResponse = blockStore.retrieveBytesWithRequest(request)\n                Log.d(TAG, \"retrieveBytesWithRequest: retrieveBytesResponse: $retrieveBytesResponse\")\n                if (retrieveBytesResponse != null) {\n                    callback?.onResponseResult(Status.SUCCESS, retrieveBytesResponse)\n                } else {\n                    callback?.onResponseResult(Status.INTERNAL_ERROR, RetrieveBytesResponse(Bundle.EMPTY, emptyList()))\n                }\n            }\n        }\n    }\n\n    override fun deleteBytes(callback: IDeleteBytesCallback?, request: DeleteBytesRequest?) {\n        Log.d(TAG, \"Method (deleteBytes: $request) called\")\n        lifecycleScope.launch {\n            runCatching {\n                val deleted = blockStore.deleteBytesWithRequest(request)\n                callback?.onDeleteBytesResult(Status.SUCCESS, deleted)\n            }\n        }\n    }\n}"
  },
  {
    "path": "play-services-auth-blockstore/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2025 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest />\n"
  },
  {
    "path": "play-services-auth-blockstore/src/main/aidl/com/google/android/gms/auth/blockstore/AppRestoreInfo.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.blockstore;\n\nparcelable AppRestoreInfo;"
  },
  {
    "path": "play-services-auth-blockstore/src/main/aidl/com/google/android/gms/auth/blockstore/DeleteBytesRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.blockstore;\n\nparcelable DeleteBytesRequest;"
  },
  {
    "path": "play-services-auth-blockstore/src/main/aidl/com/google/android/gms/auth/blockstore/RetrieveBytesRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.blockstore;\n\nparcelable RetrieveBytesRequest;"
  },
  {
    "path": "play-services-auth-blockstore/src/main/aidl/com/google/android/gms/auth/blockstore/RetrieveBytesResponse.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.blockstore;\n\nparcelable RetrieveBytesResponse;"
  },
  {
    "path": "play-services-auth-blockstore/src/main/aidl/com/google/android/gms/auth/blockstore/StoreBytesData.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.blockstore;\n\nparcelable StoreBytesData;"
  },
  {
    "path": "play-services-auth-blockstore/src/main/aidl/com/google/android/gms/auth/blockstore/internal/IBlockstoreService.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.blockstore.internal;\n\nimport com.google.android.gms.common.api.Status;\nimport android.os.Bundle;\nimport com.google.android.gms.auth.blockstore.AppRestoreInfo;\nimport com.google.android.gms.auth.blockstore.DeleteBytesRequest;\nimport com.google.android.gms.auth.blockstore.RetrieveBytesRequest;\nimport com.google.android.gms.auth.blockstore.StoreBytesData;\nimport com.google.android.gms.common.api.internal.IStatusCallback;\nimport com.google.android.gms.auth.blockstore.internal.IRetrieveBytesCallback;\nimport com.google.android.gms.auth.blockstore.internal.ISetBlockstoreDataCallback;\nimport com.google.android.gms.auth.blockstore.internal.IGetBlockstoreDataCallback;\nimport com.google.android.gms.auth.blockstore.internal.IGetAccessForPackageCallback;\nimport com.google.android.gms.auth.blockstore.internal.IStoreBytesCallback;\nimport com.google.android.gms.auth.blockstore.internal.IIsEndToEndEncryptionAvailableCallback;\nimport com.google.android.gms.auth.blockstore.internal.IDeleteBytesCallback;\n\ninterface IBlockstoreService {\n    void retrieveBytes(IRetrieveBytesCallback callback) = 1;\n    void setBlockstoreData(ISetBlockstoreDataCallback callback, in byte[] data) = 2;\n    void getBlockstoreData(IGetBlockstoreDataCallback callback) = 3;\n    void getAccessForPackage(IGetAccessForPackageCallback callback, String packageName) = 4;\n    void setFlagWithPackage(IStatusCallback callback, String packageName, int flag) = 5;\n    void clearFlagForPackage(IStatusCallback callback, String packageName) = 6;\n    void updateFlagForPackage(IStatusCallback callback, String packageName, int value) = 7;\n    void reportAppRestore(IStatusCallback callback, in List<String> packages, int code, in AppRestoreInfo info) = 8;\n    void storeBytes(IStoreBytesCallback callback, in StoreBytesData data) = 9;\n    void isEndToEndEncryptionAvailable(IIsEndToEndEncryptionAvailableCallback callback) = 10;\n    void retrieveBytesWithRequest(IRetrieveBytesCallback callback, in RetrieveBytesRequest request) = 11;\n    void deleteBytes(IDeleteBytesCallback callback, in DeleteBytesRequest request) = 12;\n}"
  },
  {
    "path": "play-services-auth-blockstore/src/main/aidl/com/google/android/gms/auth/blockstore/internal/IDeleteBytesCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.blockstore.internal;\n\nimport com.google.android.gms.common.api.Status;\n\ninterface IDeleteBytesCallback {\n    void onDeleteBytesResult(in Status status, boolean deleted);\n}"
  },
  {
    "path": "play-services-auth-blockstore/src/main/aidl/com/google/android/gms/auth/blockstore/internal/IGetAccessForPackageCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.blockstore.internal;\n\nimport com.google.android.gms.common.api.Status;\n\ninterface IGetAccessForPackageCallback {\n    void onGetAccessResult(in Status status, int accessResult);\n}"
  },
  {
    "path": "play-services-auth-blockstore/src/main/aidl/com/google/android/gms/auth/blockstore/internal/IGetBlockstoreDataCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.blockstore.internal;\n\nimport com.google.android.gms.common.api.Status;\n\ninterface IGetBlockstoreDataCallback {\n    void onGetBlockstoreData(in Status status, in byte[] dataBytes);\n}"
  },
  {
    "path": "play-services-auth-blockstore/src/main/aidl/com/google/android/gms/auth/blockstore/internal/IIsEndToEndEncryptionAvailableCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.blockstore.internal;\n\nimport com.google.android.gms.common.api.Status;\n\ninterface IIsEndToEndEncryptionAvailableCallback {\n    void onCheckEndToEndEncryptionResult(in Status status, boolean available);\n}"
  },
  {
    "path": "play-services-auth-blockstore/src/main/aidl/com/google/android/gms/auth/blockstore/internal/IRetrieveBytesCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.blockstore.internal;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.auth.blockstore.RetrieveBytesResponse;\n\ninterface IRetrieveBytesCallback {\n    void onBytesResult(in Status status, in byte[] data);\n    void onResponseResult(in Status status, in RetrieveBytesResponse response);\n}"
  },
  {
    "path": "play-services-auth-blockstore/src/main/aidl/com/google/android/gms/auth/blockstore/internal/ISetBlockstoreDataCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.blockstore.internal;\n\nimport com.google.android.gms.common.api.Status;\n\ninterface ISetBlockstoreDataCallback {\n    void onSetBytesResult(in Status status, int storedSize);\n}"
  },
  {
    "path": "play-services-auth-blockstore/src/main/aidl/com/google/android/gms/auth/blockstore/internal/IStoreBytesCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.blockstore.internal;\n\nimport com.google.android.gms.common.api.Status;\n\ninterface IStoreBytesCallback {\n    void onStoreBytesResult(in Status status, int result);\n}"
  },
  {
    "path": "play-services-auth-blockstore/src/main/java/com/google/android/gms/auth/blockstore/AppRestoreInfo.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.blockstore;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\n@Hide\npublic class AppRestoreInfo extends AbstractSafeParcelable {\n    @Field(value = 1)\n    public String restoreSessionId;\n\n    @Field(value = 2)\n    public String restoreSource;\n\n    @Constructor\n    public AppRestoreInfo(@Param(1) String restoreSessionId, @Param(2) String restoreSource) {\n        this.restoreSessionId = restoreSessionId;\n        this.restoreSource = restoreSource;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"AppRestoreInfo\").field(\"restoreSessionId\", restoreSessionId).field(\"restoreSource\", restoreSource).end();\n    }\n\n    public static final SafeParcelableCreatorAndWriter<AppRestoreInfo> CREATOR = findCreator(AppRestoreInfo.class);\n}\n"
  },
  {
    "path": "play-services-auth-blockstore/src/main/java/com/google/android/gms/auth/blockstore/Blockstore.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.blockstore;\n\nimport android.content.Context;\n\n/**\n * Entry point for Block Store API.\n * <p>\n * Allows apps to transfer small amounts of data via device-to-device restore. This enables a seamless sign-in when users start using a new\n * device.\n */\npublic class Blockstore {\n    /**\n     * Creates a new instance of {@link BlockstoreClient}.\n     */\n    public static BlockstoreClient getClient(Context context) {\n        throw new UnsupportedOperationException();\n    }\n}\n"
  },
  {
    "path": "play-services-auth-blockstore/src/main/java/com/google/android/gms/auth/blockstore/BlockstoreClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.blockstore;\n\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.HasApiKey;\nimport com.google.android.gms.tasks.Task;\n\n/**\n * The interface for clients to access Block Store.\n * <ul>\n *     <li>\n *         Clients should call storeBytes(StoreBytesData) to store authentication credentials byte[] bytes to enable seamless sign-in on\n *         other devices.\n *     </li>\n *     <li>Clients should call retrieveBytes() to fetch the authentication credentials to seamlessly sign in users on a newly setup device.</li>\n * </ul>\n */\npublic interface BlockstoreClient extends HasApiKey<Api.ApiOptions.NoOptions> {\n    /**\n     * The default key with which the bytes are associated when {@link #storeBytes(StoreBytesData)} is called without explicitly setting a {@code key}.\n     */\n    String DEFAULT_BYTES_DATA_KEY = \"com.google.android.gms.auth.blockstore.DEFAULT_BYTES_DATA_KEY\";\n\n    /**\n     * Maximum number of distinct data entries, differentiated by the data keys, that can be stored using {@link BlockstoreClient#storeBytes(StoreBytesData)}.\n     * <p>\n     * The data key is the value provided when storing the data via {@link #storeBytes(StoreBytesData)}, as {@code StoreBytesData.key}.\n     */\n    int MAX_ENTRY_COUNT = 16;\n\n    /**\n     * Maximum allowed size of byte blobs that can be stored using {@link BlockstoreClient#storeBytes(StoreBytesData)}.\n     */\n    int MAX_SIZE = 1024;\n\n    /**\n     * Returns a {@link Task} which asynchronously deletes the bytes matching the filter(s) specified in {@code deleteBytesRequest}, with a Boolean result\n     * representing whether any bytes were actually deleted.\n     * <p>\n     * If no bytes were found to delete, the task succeeds with a {@code false} return value.\n     *\n     * @throws NullPointerException if {@code deleteBytesRequest} is null.\n     */\n    Task<Boolean> deleteBytes(DeleteBytesRequest deleteBytesRequest) throws NullPointerException;\n\n    /**\n     * Returns a {@code Task} which asynchronously determines whether Block Store data backed up to the cloud will be end-to-end encrypted.\n     * <p>\n     * End-to-end encryption is available for Pie and above devices with a lockscreen PIN/pattern.\n     * <p>\n     * The {@code Boolean} return value is whether Block Store data backed up to the cloud will be end-to-end encrypted.\n     */\n    Task<Boolean> isEndToEndEncryptionAvailable();\n\n    /**\n     * Returns a {@code Task} which asynchronously retrieves the previously-stored bytes, if any, matching the filter(s) specified in\n     * {@code retrieveBytesRequest}.\n     * <p>\n     * The returned {@code RetrieveBytesResponse} contains a map from data keys to {@code BlockstoreData}. The data may have been written on the same\n     * device or may have been transferred during the device setup.\n     * <p>\n     * Use this API to seamlessly sign-in users to the apps on a new device.\n     * <p>\n     * If no data is found, returns an empty data map. Note that the data may be cleared by Google Play services on certain user actions, like user\n     * clearing app storage (among others).\n     * <p>\n     * The bytes stored without an explicitly specified {@code StoreBytesData.key} can be requested with, and is returned associated with, the default\n     * key {@link #DEFAULT_BYTES_DATA_KEY}.\n     *\n     * @throws NullPointerException if {@code retrieveBytesRequest} is null.\n     */\n    Task<RetrieveBytesResponse> retrieveBytes(RetrieveBytesRequest retrieveBytesRequest) throws NullPointerException;\n\n    /**\n     * Returns a {@link Task} which asynchronously retrieves the previously-stored bytes that was stored without an explicitly specified\n     * {@code StoreBytesData.key}, if any. The maximum size of the {@code byte[]} is the {@link #MAX_SIZE}.\n     * <p>\n     * The {@code byte[]} may have been written on the same device or may have been transferred during the device setup.\n     * <p>\n     * Use this API to seamlessly sign-in users to the apps on a new device.\n     * <p>\n     * If no data is found, returns an empty byte array. Note that the data may be cleared by Google Play services on certain user actions, like user\n     * clearing app storage (among others).\n     *\n     * @deprecated Use {@link #retrieveBytes(RetrieveBytesRequest)} instead.\n     */\n    @Deprecated\n    Task<byte[]> retrieveBytes();\n\n    /**\n     * Returns a {@link Task} which asynchronously stores the provided {@code byte[] bytes} and associates it with the provided {@code String key}.\n     * <p>\n     * If the {@code key} is not explicitly set, then the {@code bytes} will be associated with the default key {@link #DEFAULT_BYTES_DATA_KEY}.\n     * <p>\n     * The data is stored locally. It is transferred to a new device during the device-to-device restore if a google account is also transferred.\n     * <p>\n     * If in {@link StoreBytesData#shouldBackupToCloud()} is set to {@code true}, the data will also be backed up to the cloud in the next periodic sync.\n     * Cloud backup data is transferred to a new device during the cloud restore using Google's Backup & Restore services.\n     * <p>\n     * The maximum size of {@code String key} and {@code byte[] bytes} combined is {@link #MAX_SIZE}; otherwise, the API fails with\n     * {@link BlockstoreStatusCodes#MAX_SIZE_EXCEEDED} error code.\n     * <p>\n     * The maximum number of data entries allowed is {@link #MAX_ENTRY_COUNT}; otherwise, the API fails with\n     * {@link BlockstoreStatusCodes#TOO_MANY_ENTRIES} error code.\n     * <p>\n     * The {@code Integer} return value is the size of {@code byte[] bytes} successfully stored.\n     * <p>\n     * Use this API to store small data blobs that can enable seamless sign in for your apps. The API may be called periodically (for example, a few\n     * times per day) to refresh the data blob. Successive calls with the same key to this API will overwrite the existing bytes.\n     */\n    Task<Integer> storeBytes(StoreBytesData storeBytesData);\n}\n"
  },
  {
    "path": "play-services-auth-blockstore/src/main/java/com/google/android/gms/auth/blockstore/BlockstoreStatusCodes.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.blockstore;\n\nimport com.google.android.gms.common.api.CommonStatusCodes;\n\n/**\n * Block Store specific status codes.\n * <p>\n * Codes are allocated from the range 40000 to 40499, allocated in {@link CommonStatusCodes}.\n */\npublic class BlockstoreStatusCodes extends CommonStatusCodes {\n\n    /**\n     * The available quota was exceeded.\n     */\n    public static final int MAX_SIZE_EXCEEDED = 40000;\n\n    /**\n     * Attempting to store a new key value pair after reaching the maximum number of entries allowed.\n     */\n    public static final int TOO_MANY_ENTRIES = 40001;\n\n    /**\n     * Attempting to use a Blockstore feature that is not (yet) supported on the given device.\n     */\n    public static final int FEATURE_NOT_SUPPORTED = 40002;\n\n}\n"
  },
  {
    "path": "play-services-auth-blockstore/src/main/java/com/google/android/gms/auth/blockstore/DeleteBytesRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.blockstore;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\n/**\n * A request to delete app data from BlockStore.\n */\n@SafeParcelable.Class\npublic class DeleteBytesRequest extends AbstractSafeParcelable {\n\n    @Field(value = 1, getterName = \"getKeys\")\n    private final List<String> keys;\n\n    @Field(value = 2, getterName = \"getDeleteAll\")\n    private final boolean deleteAll;\n\n    @Constructor\n    DeleteBytesRequest(@Param(1) List<String> keys, @Param(2) boolean deleteAll) {\n        this.keys = keys;\n        this.deleteAll = deleteAll;\n        if (deleteAll && keys != null && !keys.isEmpty()) {\n            throw new IllegalArgumentException(\"deleteAll was set to true but keys were also provided\");\n        }\n        for (String key : keys) {\n            if (key == null || key.isEmpty()) {\n                throw new IllegalArgumentException(\"Element in keys cannot be null or empty\");\n            }\n        }\n    }\n\n    /**\n     * Returns the list of keys whose associated data, if any, should be deleted.\n     * <p>\n     * An empty list means that no key-based filtering will be performed. In other words, no data will be deleted if the key list is empty and no other\n     * criterion is provided.\n     * <p>\n     * Note that the app data that was stored without an explicit key can be deleted with the default key\n     * {@link BlockstoreClient#DEFAULT_BYTES_DATA_KEY}.\n     */\n    @NonNull\n    public List<String> getKeys() {\n        return keys;\n    }\n\n    /**\n     * Returns whether or not all app's Block Store data should be deleted.\n     */\n    public boolean getDeleteAll() {\n        return deleteAll;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    @NonNull\n    @Override\n    @Hide\n    public String toString() {\n        return ToStringHelper.name(\"DeleteBytesRequest\").field(\"deleteAll\", deleteAll).field(\"keys\", keys).end();\n    }\n\n    public static final SafeParcelableCreatorAndWriter<DeleteBytesRequest> CREATOR = findCreator(DeleteBytesRequest.class);\n\n    /**\n     * A builder for {@link DeleteBytesRequest} objects.\n     */\n    public static class Builder {\n        private final List<String> keyList = new ArrayList<>();\n        private boolean deleteAll = false;\n\n        /**\n         * Constructor for the {@link DeleteBytesRequest.Builder} class.\n         */\n        public Builder() {\n        }\n\n        /**\n         * Builds and returns the {@link DeleteBytesRequest} object.\n         */\n        public DeleteBytesRequest build() {\n            if (deleteAll && !keyList.isEmpty()) {\n                throw new IllegalStateException(\"deleteAll=true but keys are provided\");\n            }\n            return new DeleteBytesRequest(new ArrayList<>(keyList), deleteAll);\n        }\n\n        /**\n         * Sets whether or not all app's Block Store data should be deleted.\n         * <p>\n         * The default is {@code false}.\n         * <p>\n         * Note that if {@code deleteAll} is set to true, then you should NOT set any other deletion criterion, e.g. {@code keys} should be empty. Otherwise, an\n         * IllegalStateException will be thrown.\n         */\n        public Builder setDeleteAll(boolean deleteAll) {\n            this.deleteAll = deleteAll;\n            return this;\n        }\n\n        /**\n         * Sets the list of keys whose associated data, if any, should be deleted.\n         * <p>\n         * The default value is an empty list, which means that no key-based filtering will be performed. In other words, no data will be deleted if the\n         * key list is empty and no other criterion is provided.\n         * <p>\n         * Note that the app data that was stored without an explicit key can be deleted with the default key\n         * {@link BlockstoreClient#DEFAULT_BYTES_DATA_KEY}.\n         */\n        public Builder setKeys(List<String> keys) {\n            keyList.clear();\n            keyList.addAll(keys);\n            return this;\n        }\n    }\n}"
  },
  {
    "path": "play-services-auth-blockstore/src/main/java/com/google/android/gms/auth/blockstore/RetrieveBytesRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.blockstore;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\n/**\n * A request to retrieve app data from BlockStore.\n */\n@SafeParcelable.Class\npublic class RetrieveBytesRequest extends AbstractSafeParcelable {\n\n    @Field(value = 1, getterName = \"getKeys\")\n    private final List<String> keys;\n\n    @Field(value = 2, getterName = \"getRetrieveAll\")\n    private final boolean retrieveAll;\n\n    @Constructor\n    RetrieveBytesRequest(@Param(1) List<String> keys, @Param(2) boolean retrieveAll) {\n        if (retrieveAll && keys != null && !keys.isEmpty()) {\n            throw new IllegalArgumentException(\"retrieveAll was set to true but other constraint(s) was also provided: keys\");\n        }\n        this.retrieveAll = retrieveAll;\n\n        List<String> tmp = new ArrayList<>();\n        if (keys != null) {\n            for (String k : keys) {\n                if (k == null || k.isEmpty()) {\n                    throw new IllegalArgumentException(\"Element in keys cannot be null or empty\");\n                }\n                tmp.add(k);\n            }\n        }\n        this.keys = Collections.unmodifiableList(tmp);\n    }\n\n    /**\n     * Returns the list of keys whose associated data, if any, should be retrieved.\n     * <p>\n     * An empty list means that no key-based filtering will be performed. In other words, no data will be returned if the key list is empty and no\n     * other criterion is provided.\n     * <p>\n     * Note that the app data that was stored without an explicit key can be requested with the default key\n     * {@link BlockstoreClient#DEFAULT_BYTES_DATA_KEY}.\n     */\n    public List<String> getKeys() {\n        return keys;\n    }\n\n    /**\n     * Returns whether or not all app's Block Store data should be retrieved.\n     */\n    public boolean getRetrieveAll() {\n        return retrieveAll;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"RetrieveBytesRequest\").field(\"keys\", keys).field(\"retrieveAll\", retrieveAll).end();\n    }\n\n    public static final SafeParcelableCreatorAndWriter<RetrieveBytesRequest> CREATOR = findCreator(RetrieveBytesRequest.class);\n\n    /**\n     * A builder for {@link RetrieveBytesRequest} objects.\n     */\n    public static class Builder {\n        private final List<String> keys = new ArrayList<>();\n        private boolean retrieveAll = false;\n\n        /**\n         * Builds and returns the {@link RetrieveBytesRequest} object.\n         */\n        @NonNull\n        public RetrieveBytesRequest build() {\n            return new RetrieveBytesRequest(new ArrayList<>(keys), retrieveAll);\n        }\n\n        /**\n         * Sets the list of keys whose associated data, if any, should be retrieved.\n         * <p>\n         * The default value is an empty list, which means that no key-based filtering will be performed. In other words, no data will be returned if the\n         * key list is empty and no other criterion is provided.\n         * <p>\n         * Note that the app data that was stored without an explicit key can be requested with the default key\n         * {@link BlockstoreClient#DEFAULT_BYTES_DATA_KEY}.\n         */\n        public Builder setKeys(List<String> keys) {\n            this.keys.clear();\n            this.keys.addAll(keys);\n            return this;\n        }\n\n        /**\n         * Sets whether or not all app's Block Store data should be retrieved.\n         * <p>\n         * The default is {@code false}.\n         * <p>\n         * Note that if {@code retrieveAll} is set to true, then you should NOT set any other retrieval criterion, e.g. {@code keys} should be empty. Otherwise, an\n         * IllegalStateException will be thrown.\n         */\n        public Builder retrieveAll(boolean retrieveAll) {\n            this.retrieveAll = retrieveAll;\n            return this;\n        }\n    }\n}"
  },
  {
    "path": "play-services-auth-blockstore/src/main/java/com/google/android/gms/auth/blockstore/RetrieveBytesResponse.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.blockstore;\n\nimport android.os.Bundle;\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * App data retrieved from BlockStore.\n */\n@SafeParcelable.Class\npublic class RetrieveBytesResponse extends AbstractSafeParcelable {\n\n    @Deprecated\n    @Field(value = 1, getterName = \"getInternalBlockstoreDataBundle\")\n    private final Bundle internalBlockstoreDataBundle;\n\n    @Field(value = 2, getterName = \"getInternalBlockstoreDataList\")\n    private final List<BlockstoreData> internalBlockstoreDataList;\n\n    private final Map<String, BlockstoreData> blockstoreDataMap;\n\n    @Constructor\n    @Hide\n    public RetrieveBytesResponse(@Param(1) Bundle internalBlockstoreDataBundle, @Param(2) List<BlockstoreData> internalBlockstoreDataList) {\n        this.internalBlockstoreDataBundle = internalBlockstoreDataBundle;\n        this.internalBlockstoreDataList = internalBlockstoreDataList;\n        HashMap<String, BlockstoreData> blockstoreDataMap = new HashMap<>();\n        for (BlockstoreData blockstoreData : internalBlockstoreDataList) {\n            blockstoreDataMap.put(blockstoreData.key, blockstoreData);\n        }\n        this.blockstoreDataMap = blockstoreDataMap;\n    }\n\n    /**\n     * A mapping from app data key to {@link RetrieveBytesResponse.BlockstoreData} found based on a {@link RetrieveBytesRequest}.\n     * <p>\n     * The app data key is the value provided when storing the data via {@link BlockstoreClient#storeBytes(StoreBytesData)}, as\n     * {@code StoreBytesData.key}.\n     * <p>\n     * Note that the app data that was stored without an explicit key is associated with the default key\n     * {@link BlockstoreClient#DEFAULT_BYTES_DATA_KEY}.\n     */\n    public Map<String, RetrieveBytesResponse.BlockstoreData> getBlockstoreDataMap() {\n        return blockstoreDataMap;\n    }\n\n    @Hide\n    public Bundle getInternalBlockstoreDataBundle() {\n        return internalBlockstoreDataBundle;\n    }\n\n    @Hide\n    public List<BlockstoreData> getInternalBlockstoreDataList() {\n        return internalBlockstoreDataList;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    @NonNull\n    @Override\n    @Hide\n    public String toString() {\n        return ToStringHelper.name(\"RetrieveBytesResponse\").value(blockstoreDataMap).end();\n    }\n\n    public static final SafeParcelableCreatorAndWriter<RetrieveBytesResponse> CREATOR = findCreator(RetrieveBytesResponse.class);\n\n    /**\n     * A block of app data previously stored to Block Store.\n     */\n    @SafeParcelable.Class\n    public static class BlockstoreData extends AbstractSafeParcelable {\n        @Field(value = 1, getterName = \"getBytes\")\n        @NonNull\n        private final byte[] bytes;\n\n        @Field(value = 2, getterName = \"getKey\")\n        @NonNull\n        private final String key;\n\n        @Constructor\n        @Hide\n        public BlockstoreData(@NonNull @Param(1) byte[] bytes, @NonNull @Param(2) String key) {\n            this.bytes = bytes;\n            this.key = key;\n        }\n\n        /**\n         * Raw bytes passed from the app to Block Store.\n         */\n        @NonNull\n        public byte[] getBytes() {\n            return bytes;\n        }\n\n        @Hide\n        @NonNull\n        public String getKey() {\n            return key;\n        }\n\n        @NonNull\n        @Override\n        @Hide\n        public String toString() {\n            return ToStringHelper.name(\"BlockstoreData\").value(key).field(\"bytes\", bytes, true).end();\n        }\n\n        @Override\n        public void writeToParcel(@NonNull Parcel dest, int flags) {\n            CREATOR.writeToParcel(this, dest, flags);\n        }\n\n        public static final SafeParcelableCreatorAndWriter<BlockstoreData> CREATOR = findCreator(BlockstoreData.class);\n    }\n}"
  },
  {
    "path": "play-services-auth-blockstore/src/main/java/com/google/android/gms/auth/blockstore/StoreBytesData.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.blockstore;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.utils.ToStringHelper;\n\n/**\n * Data passed by apps to Block Store.\n */\n@SafeParcelable.Class\npublic class StoreBytesData extends AbstractSafeParcelable {\n\n    @Field(value = 1, getterName = \"getBytes\")\n    @NonNull\n    private final byte[] bytes;\n\n    @Field(value = 2, getterName = \"shouldBackupToCloud\")\n    private final boolean shouldBackupToCloud;\n\n    @Field(value = 3, getterName = \"getKey\")\n    private final String key;\n\n    @Constructor\n    StoreBytesData(@NonNull @Param(1) byte[] bytes, @Param(2) boolean shouldBackupToCloud, @Param(3) String key) {\n        this.bytes = bytes;\n        this.shouldBackupToCloud = shouldBackupToCloud;\n        this.key = key;\n    }\n\n    /**\n     * Raw bytes passed from apps to Block Store.\n     */\n    @NonNull\n    public byte[] getBytes() {\n        return bytes;\n    }\n\n    /**\n     * The key with which the bytes are associated.\n     * <p>\n     * If the key was never explicitly set when building the {@code StoreBytesData}, then the default key {@link BlockstoreClient#DEFAULT_BYTES_DATA_KEY}\n     * is associated with the {@code bytes} and therefore will be returned.\n     */\n    @NonNull\n    public String getKey() {\n        return key;\n    }\n\n    /**\n     * Whether the bytes to be stored should be backed up to the cloud in the next sync.\n     */\n    public boolean shouldBackupToCloud() {\n        return shouldBackupToCloud;\n    }\n\n    public static final SafeParcelableCreatorAndWriter<StoreBytesData> CREATOR = findCreator(StoreBytesData.class);\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    @NonNull\n    @Override\n    @Hide\n    public String toString() {\n        return ToStringHelper.name(\"StoreBytesData\").field(\"bytes\", bytes != null ? bytes.length : 0).field(\"shouldBackupToCloud\", shouldBackupToCloud).field(\"key\", key).end();\n    }\n\n    /**\n     * A builder for {@link StoreBytesData} objects.\n     */\n    public static class Builder {\n        private byte[] bytes;\n        private boolean shouldBackupToCloud = false;\n        private String key = BlockstoreClient.DEFAULT_BYTES_DATA_KEY;\n\n        /**\n         * Constructor for the {@link StoreBytesData.Builder} class.\n         */\n        public Builder() {\n        }\n\n        /**\n         * Builds and returns the {@link StoreBytesData} object.\n         */\n        public StoreBytesData build() {\n            return new StoreBytesData(bytes, shouldBackupToCloud, key);\n        }\n\n        /**\n         * Sets the raw bytes to be stored with Block Store. See {@link BlockstoreClient#MAX_SIZE} for the maximum size allowed for a key-bytes entry.\n         */\n        public Builder setBytes(byte[] bytes) {\n            this.bytes = bytes;\n            return this;\n        }\n\n        /**\n         * Sets the key with which the {@code bytes} are associated with. See {@link BlockstoreClient#MAX_SIZE} for the maximum size allowed for a key-bytes\n         * entry.\n         * <p>\n         * If {@code setKey} is never invoked, the bytes will be associated with the default key {@link BlockstoreClient#DEFAULT_BYTES_DATA_KEY} when stored\n         * into Block Store.\n         */\n        public Builder setKey(String key) {\n            this.key = key;\n            return this;\n        }\n\n        /**\n         * Sets whether the bytes to be stored should be backed up to the cloud in the next sync.\n         */\n        public Builder setShouldBackupToCloud(boolean shouldBackupToCloud) {\n            this.shouldBackupToCloud = shouldBackupToCloud;\n            return this;\n        }\n    }\n}"
  },
  {
    "path": "play-services-auth-blockstore/src/main/java/com/google/android/gms/auth/blockstore/package-info.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n/**\n * Contains the Block Store API.\n */\npackage com.google.android.gms.auth.blockstore;\n"
  },
  {
    "path": "play-services-auth-workaccount/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\nandroid {\n    namespace \"com.google.android.gms.auth.workaccount\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n\n}\n\napply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG implementation of managed work account support'\n\ndependencies {\n}\n"
  },
  {
    "path": "play-services-auth-workaccount/core/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'kotlin-android'\n\ndependencies {\n    api project(':play-services-auth-workaccount')\n    api project(':play-services-auth')\n    implementation project(':play-services-base-core')\n\n    implementation \"androidx.appcompat:appcompat:$appcompatVersion\"\n}\n\nandroid {\n    namespace \"org.microg.gms.auth.workaccount\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    sourceSets {\n        main.java.srcDirs += 'src/main/kotlin'\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n\n    kotlinOptions {\n        jvmTarget = 1.8\n    }\n\n    lintOptions {\n        disable 'MissingTranslation'\n    }\n}\n"
  },
  {
    "path": "play-services-auth-workaccount/core/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2023 e foundation\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <uses-permission android:name=\"android.permission.AUTHENTICATE_ACCOUNTS\" />\n    <uses-permission android:name=\"android.permission.GET_ACCOUNTS\" />\n    <uses-permission android:name=\"android.permission.MANAGE_ACCOUNTS\" />\n\n    <application>\n\n        <service android:name=\"org.microg.gms.auth.workaccount.WorkAccountService\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.auth.account.workaccount.START\" />\n            </intent-filter>\n        </service>\n\n        <service\n            android:name=\"com.google.android.gms.auth.account.authenticator.WorkAccountAuthenticatorService\"\n            android:process=\":persistent\"\n            android:enabled=\"false\"\n            android:exported=\"false\">\n\n           <intent-filter>\n                <action android:name=\"android.accounts.AccountAuthenticator\"/>\n           </intent-filter>\n\n           <meta-data\n               android:name=\"android.accounts.AccountAuthenticator\"\n               android:resource=\"@xml/auth_work_authenticator\"/>\n\n           <meta-data\n               android:name=\"android.accounts.AccountAuthenticator.customTokens\"\n               android:value=\"1\"/>\n\n        </service>\n\n    </application>\n</manifest>\n"
  },
  {
    "path": "play-services-auth-workaccount/core/src/main/kotlin/com/google/android/gms/auth/account/authenticator/WorkAccountAuthenticator.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.account.authenticator\n\nimport android.accounts.AbstractAccountAuthenticator\nimport android.accounts.Account\nimport android.accounts.AccountAuthenticatorResponse\nimport android.accounts.AccountManager\nimport android.content.Context\nimport android.content.Intent\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.Bundle\nimport android.util.Log\nimport org.microg.gms.auth.workaccount.R\nimport org.microg.gms.auth.AuthConstants\nimport org.microg.gms.common.PackageUtils\nimport org.microg.gms.auth.AuthRequest\nimport org.microg.gms.auth.AuthResponse\nimport org.microg.gms.auth.workaccount.WorkProfileSettings\nimport java.io.IOException\nimport kotlin.jvm.Throws\n\nclass WorkAccountAuthenticator(val context: Context) : AbstractAccountAuthenticator(context) {\n\n    override fun editProperties(\n        response: AccountAuthenticatorResponse,\n        accountType: String?\n    ): Bundle {\n        TODO(\"Not yet implemented: editProperties\")\n    }\n\n    override fun addAccount(\n        response: AccountAuthenticatorResponse,\n        accountType: String,\n        authTokenType: String?,\n        requiredFeatures: Array<out String>?,\n        options: Bundle\n    ): Bundle? {\n\n        if (!WorkProfileSettings(context).allowCreateWorkAccount) {\n            return Bundle().apply {\n                putInt(AccountManager.KEY_ERROR_CODE, AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION)\n                putString(AccountManager.KEY_ERROR_MESSAGE, context.getString(R.string.auth_work_authenticator_disabled_error)\n                )\n            }\n        } else if (\n            !options.containsKey(KEY_ACCOUNT_CREATION_TOKEN)\n            || options.getString(KEY_ACCOUNT_CREATION_TOKEN) == null\n            || options.getInt(AccountManager.KEY_CALLER_UID) != android.os.Process.myUid()) {\n            Log.e(TAG,\n                \"refusing to add account without creation token or from external app: \" +\n                        \"could have been manually initiated by user (not supported) \" +\n                        \"or by unauthorized app (not allowed)\"\n            )\n\n            // TODO: The error message is not automatically displayed by the settings app as of now.\n            // We can consider showing the error message through a popup instead.\n\n            return Bundle().apply {\n                putInt(AccountManager.KEY_ERROR_CODE, AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION)\n                putString(AccountManager.KEY_ERROR_MESSAGE, context.getString(R.string.auth_work_authenticator_add_manual_error)\n                )\n            }\n        }\n\n        val oauthToken: String = options.getString(KEY_ACCOUNT_CREATION_TOKEN)!!\n\n        try {\n            tryAddAccount(oauthToken, response)\n        } catch (exception: Exception) {\n            response.onResult(Bundle().apply {\n                putInt(\n                    AccountManager.KEY_ERROR_CODE,\n                    AccountManager.ERROR_CODE_NETWORK_ERROR\n                )\n                putString(AccountManager.KEY_ERROR_MESSAGE, exception.message)\n            })\n        }\n\n        /* Note: as is not documented, `null` must only be returned after `response.onResult` was\n         * already called, hence forcing the requests to be synchronous. They are still async to\n         * the caller's main thread because AccountManager forces potentially blocking operations,\n         * like waiting for a response upon `addAccount`, not to be on the main thread.\n         */\n        return null\n    }\n\n    @Throws(Exception::class)\n    private fun tryAddAccount(\n        oauthToken: String,\n        response: AccountAuthenticatorResponse\n    ) {\n        val authResponse = AuthRequest().fromContext(context)\n            .appIsGms()\n            .callerIsGms()\n            .service(\"ac2dm\")\n            .token(oauthToken).isAccessToken()\n            .addAccount()\n            .getAccountId()\n            .droidguardResults(null)\n            .response\n\n        val accountManager = AccountManager.get(context)\n        if (accountManager.addAccountExplicitly(\n                Account(authResponse.email, AuthConstants.WORK_ACCOUNT_TYPE),\n                authResponse.token, Bundle().apply {\n                    // Work accounts have no SID / LSID (\"BAD_COOKIE\") and no first/last name.\n                    if (authResponse.accountId.isNotBlank()) {\n                        putString(KEY_GOOGLE_USER_ID, authResponse.accountId)\n                    }\n                    putString(AuthConstants.KEY_ACCOUNT_CAPABILITIES, authResponse.capabilities)\n                    putString(AuthConstants.KEY_ACCOUNT_SERVICES, authResponse.services)\n                    if (authResponse.services != \"android\") {\n                        Log.i(\n                            TAG,\n                            \"unexpected 'services' value ${authResponse.services} (usually 'android')\"\n                        )\n                    }\n                }\n            )\n        ) {\n\n            // Notify vending package\n            context.sendBroadcast(\n                Intent(WORK_ACCOUNT_CHANGED_BOARDCAST).setPackage(\"com.android.vending\")\n            )\n\n            // Report successful creation to caller\n            response.onResult(Bundle().apply {\n                putString(AccountManager.KEY_ACCOUNT_NAME, authResponse.email)\n                putString(AccountManager.KEY_ACCOUNT_TYPE, AuthConstants.WORK_ACCOUNT_TYPE)\n            })\n        }\n    }\n\n    override fun confirmCredentials(\n        response: AccountAuthenticatorResponse?,\n        account: Account?,\n        options: Bundle?\n    ): Bundle {\n        return Bundle().apply {\n            putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true)\n        }\n    }\n\n    override fun getAuthToken(\n        response: AccountAuthenticatorResponse?,\n        account: Account,\n        authTokenType: String?,\n        options: Bundle?\n    ): Bundle {\n        try {\n            val authResponse: AuthResponse =\n                AuthRequest().fromContext(context)\n                    .source(\"android\")\n                    .app(\n                        context.packageName,\n                        PackageUtils.firstSignatureDigest(context, context.packageName)\n                    )\n                    .email(account.name)\n                    .token(AccountManager.get(context).getPassword(account))\n                    .service(authTokenType)\n                    .delegation(0, null)\n//                .oauth2Foreground(oauth2Foreground)\n//                .oauth2Prompt(oauth2Prompt)\n//                .oauth2IncludeProfile(includeProfile)\n//                .oauth2IncludeEmail(includeEmail)\n//                .itCaveatTypes(itCaveatTypes)\n//                .tokenRequestOptions(tokenRequestOptions)\n                    .systemPartition(true)\n                    .hasPermission(true)\n//                .putDynamicFiledMap(dynamicFields)\n                    .appIsGms()\n                    .callerIsApp()\n                    .response\n\n            return Bundle().apply {\n                putString(AccountManager.KEY_ACCOUNT_NAME, account.name)\n                putString(AccountManager.KEY_ACCOUNT_TYPE, account.type)\n                putString(AccountManager.KEY_AUTHTOKEN, authResponse.auth)\n            }\n        } catch (e: IOException) {\n            return Bundle().apply {\n                putInt(AccountManager.KEY_ERROR_CODE, AccountManager.ERROR_CODE_NETWORK_ERROR)\n                putString(AccountManager.KEY_ERROR_MESSAGE, e.message)\n            }\n        }\n    }\n\n    override fun getAuthTokenLabel(authTokenType: String?): String {\n        TODO(\"Not yet implemented: getAuthTokenLabel\")\n    }\n\n    override fun updateCredentials(\n        response: AccountAuthenticatorResponse?,\n        account: Account?,\n        authTokenType: String?,\n        options: Bundle?\n    ): Bundle {\n        TODO(\"Not yet implemented: updateCredentials\")\n    }\n\n    override fun hasFeatures(\n        response: AccountAuthenticatorResponse?,\n        account: Account?,\n        features: Array<out String>\n    ): Bundle {\n        Log.i(TAG, \"Queried features: \" + features.joinToString(\", \"))\n        return Bundle().apply {\n            putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)\n        }\n    }\n\n    /**\n     * Prevent accidental deletion, unlike GMS. The account can only be removed through client apps;\n     * ideally, it would only be removed by the app that requested it to be created / the DPC\n     * manager, though this is not enforced. On API 21, the account can also be removed by hand\n     * because `removeAccountExplicitly` is not available on API 21.\n     */\n    override fun getAccountRemovalAllowed(\n        response: AccountAuthenticatorResponse?,\n        account: Account?\n    ): Bundle {\n        return Bundle().apply {\n            putBoolean(AccountManager.KEY_BOOLEAN_RESULT, SDK_INT < 22)\n        }\n    }\n\n    companion object {\n        const val TAG = \"WorkAccAuthenticator\"\n\n        const val WORK_ACCOUNT_CHANGED_BOARDCAST = \"org.microg.vending.WORK_ACCOUNT_CHANGED\"\n\n        const val KEY_ACCOUNT_CREATION_TOKEN = \"creationToken\"\n        private const val KEY_GOOGLE_USER_ID = AuthConstants.GOOGLE_USER_ID\n    }\n}"
  },
  {
    "path": "play-services-auth-workaccount/core/src/main/kotlin/com/google/android/gms/auth/account/authenticator/WorkAccountAuthenticatorService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.account.authenticator\n\nimport android.accounts.AccountManager\nimport android.app.Service\nimport android.content.Intent\nimport android.os.IBinder\n\nclass WorkAccountAuthenticatorService : Service() {\n    private val authenticator by lazy { WorkAccountAuthenticator(this) }\n\n    override fun onBind(intent: Intent): IBinder? {\n        if (intent.action == AccountManager.ACTION_AUTHENTICATOR_INTENT) {\n            return authenticator.iBinder\n        }\n        return null\n    }\n}"
  },
  {
    "path": "play-services-auth-workaccount/core/src/main/kotlin/org/microg/gms/auth/workaccount/WorkAccountService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth.workaccount\n\nimport android.accounts.Account\nimport android.accounts.AccountManager\nimport android.app.admin.DevicePolicyManager\nimport android.content.ComponentName\nimport android.content.Context\nimport android.content.Intent\nimport android.content.pm.PackageManager\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.Bundle\nimport android.os.Parcel\nimport android.util.Log\nimport com.google.android.gms.auth.account.IWorkAccountCallback\nimport com.google.android.gms.auth.account.IWorkAccountService\nimport com.google.android.gms.auth.account.authenticator.WorkAccountAuthenticator.Companion.KEY_ACCOUNT_CREATION_TOKEN\nimport com.google.android.gms.auth.account.authenticator.WorkAccountAuthenticator.Companion.WORK_ACCOUNT_CHANGED_BOARDCAST\nimport com.google.android.gms.auth.account.authenticator.WorkAccountAuthenticatorService\nimport com.google.android.gms.common.Feature\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.internal.ConnectionInfo\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport org.microg.gms.BaseService\nimport org.microg.gms.auth.AuthConstants\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.common.PackageUtils\n\nprivate const val TAG = \"GmsWorkAccountService\"\n\nclass WorkAccountService : BaseService(TAG, GmsService.WORK_ACCOUNT_API) {\n    override fun handleServiceRequest(\n        callback: IGmsCallbacks,\n        request: GetServiceRequest,\n        service: GmsService\n    ) {\n        val packageName = PackageUtils.getAndCheckCallingPackage(this, request.packageName)\n        val policyManager = getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager\n        val authorized = policyManager.isDeviceAdminApp(packageName)\n\n        if (authorized) {\n            callback.onPostInitCompleteWithConnectionInfo(\n                CommonStatusCodes.SUCCESS,\n                WorkAccountServiceImpl(this),\n                ConnectionInfo().apply {\n                    features = arrayOf(Feature(\"work_account_client_is_whitelisted\", 1))\n                })\n        } else {\n            // Return mock response, don't tell client that it is whitelisted\n            callback.onPostInitCompleteWithConnectionInfo(\n                CommonStatusCodes.SUCCESS,\n                UnauthorizedWorkAccountServiceImpl(),\n                ConnectionInfo().apply {\n                    features = emptyArray()\n                })\n        }\n    }\n}\n\nprivate fun DevicePolicyManager.isDeviceAdminApp(packageName: String?): Boolean {\n    if (packageName == null) return false\n    return if (SDK_INT >= 21) {\n        isDeviceOwnerApp(packageName) || isProfileOwnerApp(packageName)\n    } else {\n        isDeviceOwnerApp(packageName)\n    }\n}\n\nclass WorkAccountServiceImpl(val context: Context) : IWorkAccountService.Stub() {\n\n    val packageManager: PackageManager = context.packageManager\n    val accountManager: AccountManager = AccountManager.get(context)\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean {\n        Log.d(TAG, \"$code, $data, $reply, $flags\")\n        return super.onTransact(code, data, reply, flags)\n    }\n\n    override fun setWorkAuthenticatorEnabled(enabled: Boolean) {\n        Log.d(TAG, \"setWorkAuthenticatorEnabled with $enabled\")\n\n        val componentName = ComponentName(\n            context,\n            WorkAccountAuthenticatorService::class.java\n        )\n        packageManager.setComponentEnabledSetting(\n            componentName,\n            PackageManager.COMPONENT_ENABLED_STATE_ENABLED,\n            PackageManager.DONT_KILL_APP\n        )\n    }\n\n    override fun addWorkAccount(\n        callback: IWorkAccountCallback?,\n        token: String?\n    ) {\n        Log.d(TAG, \"addWorkAccount with token $token\")\n        val future = accountManager.addAccount(\n            AuthConstants.WORK_ACCOUNT_TYPE,\n            null,\n            null,\n            Bundle().apply { putString(KEY_ACCOUNT_CREATION_TOKEN, token) },\n            null,\n            null,\n            null\n        )\n        Thread {\n            try {\n                future.result.let { result ->\n                    callback?.onAccountAdded(\n                        Account(\n                            result.getString(AccountManager.KEY_ACCOUNT_NAME)!!,\n                            result.getString(AccountManager.KEY_ACCOUNT_TYPE)!!\n                        )\n                    )\n                }\n            } catch (e: Exception) {\n                Log.e(TAG, \"could not add work account with error message: ${e.message}\")\n            }\n        }.start()\n    }\n\n    override fun removeWorkAccount(\n        callback: IWorkAccountCallback?,\n        account: Account?\n    ) {\n        Log.d(TAG, \"removeWorkAccount with account ${account?.name}\")\n        account?.let {\n            if (SDK_INT >= 22) {\n\n                val success = accountManager.removeAccountExplicitly(it)\n\n                // Notify vending package\n                context.sendBroadcast(\n                    Intent(WORK_ACCOUNT_CHANGED_BOARDCAST).setPackage(\"com.android.vending\")\n                )\n\n                callback?.onAccountRemoved(success)\n            } else {\n                val future = accountManager.removeAccount(it, null, null)\n                Thread {\n                    future.result.let { result ->\n                        callback?.onAccountRemoved(result)\n                    }\n                }.start()\n            }\n        }\n    }\n}\n\nclass UnauthorizedWorkAccountServiceImpl : IWorkAccountService.Stub() {\n    override fun setWorkAuthenticatorEnabled(enabled: Boolean) {\n        throw SecurityException(\"client not admin, yet tried to enable work authenticator\")\n    }\n\n    override fun addWorkAccount(callback: IWorkAccountCallback?, token: String?) {\n        throw SecurityException(\"client not admin, yet tried to add work account\")\n    }\n\n    override fun removeWorkAccount(callback: IWorkAccountCallback?, account: Account?) {\n        throw SecurityException(\"client not admin, yet tried to remove work account\")\n    }\n}"
  },
  {
    "path": "play-services-auth-workaccount/core/src/main/kotlin/org/microg/gms/auth/workaccount/WorkProfileSettings.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth.workaccount\n\nimport android.content.ContentValues\nimport android.content.Context\nimport android.database.Cursor\nimport org.microg.gms.settings.SettingsContract\n\nclass WorkProfileSettings(private val context: Context) {\n    private fun <T> getSettings(vararg projection: String, f: (Cursor) -> T): T =\n        SettingsContract.getSettings(\n            context,\n            SettingsContract.WorkProfile.getContentUri(context),\n            projection,\n            f\n        )\n\n    private fun setSettings(v: ContentValues.() -> Unit) =\n        SettingsContract.setSettings(context, SettingsContract.WorkProfile.getContentUri(context), v)\n\n    var allowCreateWorkAccount: Boolean\n        get() = getSettings(SettingsContract.WorkProfile.CREATE_WORK_ACCOUNT) { c -> c.getInt(0) != 0 }\n        set(value) = setSettings { put(SettingsContract.WorkProfile.CREATE_WORK_ACCOUNT, value) }\n}"
  },
  {
    "path": "play-services-auth-workaccount/core/src/main/res/drawable/ic_briefcase.xml",
    "content": "<!--\n  ~ SPDX-FileCopyrightText: Android Open Source Project\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\" android:height=\"24dp\" android:tint=\"#4285F4\" android:viewportHeight=\"24\" android:viewportWidth=\"24\" android:width=\"24dp\">\n      \n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M20,6h-4L16,4c0,-1.11 -0.89,-2 -2,-2h-4c-1.11,0 -2,0.89 -2,2v2L4,6c-1.11,0 -1.99,0.89 -1.99,2L2,19c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2L22,8c0,-1.11 -0.89,-2 -2,-2zM14,6h-4L10,4h4v2z\"/>\n    \n</vector>\n"
  },
  {
    "path": "play-services-auth-workaccount/core/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2024 e foundation\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n\n    <string name=\"auth_work_authenticator_label\">Managed Google for Work account</string>\n    <string name=\"auth_work_authenticator_add_manual_error\">This type of account is created automatically by your profile administrator if needed.</string>\n    <string name=\"auth_work_authenticator_disabled_error\">Creating a work account is disabled in microG settings.</string>\n\n</resources>\n"
  },
  {
    "path": "play-services-auth-workaccount/core/src/main/res/xml/auth_work_authenticator.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2024 e foundation\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<account-authenticator xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:label=\"@string/auth_work_authenticator_label\"\n    android:icon=\"@drawable/ic_briefcase\"\n    android:accountType=\"com.google.work\"\n    android:smallIcon=\"@drawable/ic_briefcase\"\n    android:customTokens=\"true\"/>\n"
  },
  {
    "path": "play-services-auth-workaccount/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest />"
  },
  {
    "path": "play-services-auth-workaccount/src/main/aidl/com/google/android/gms/auth/account/IWorkAccountCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.account;\n\nimport android.accounts.Account;\n\ninterface IWorkAccountCallback {\n    void onAccountAdded(in Account account) = 0;\n    void onAccountRemoved(boolean success) = 1;\n}"
  },
  {
    "path": "play-services-auth-workaccount/src/main/aidl/com/google/android/gms/auth/account/IWorkAccountService.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.account;\n\nimport android.accounts.Account;\nimport com.google.android.gms.auth.account.IWorkAccountCallback;\n\ninterface IWorkAccountService {\n\n    void setWorkAuthenticatorEnabled(boolean enabled) = 0;\n\n    void addWorkAccount(IWorkAccountCallback callback, String token) = 1;\n\n    void removeWorkAccount(IWorkAccountCallback callback, in Account account) = 2;\n}"
  },
  {
    "path": "play-services-base/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2015 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\nandroid {\n    namespace \"com.google.android.gms.base\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    aidlPackagedList \"com/google/android/gms/common/data/DataHolder.aidl\"\n    aidlPackagedList \"com/google/android/gms/common/images/WebImage.aidl\"\n    aidlPackagedList \"com/google/android/gms/common/api/internal/IStatusCallback.aidl\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n}\n\napply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG implementation of play-services-base'\n\ndependencies {\n    // Dependencies from play-services-base:18.8.0\n    api 'androidx.collection:collection:1.0.0'\n    api 'androidx.core:core:1.9.0'\n    api 'androidx.fragment:fragment:1.1.0'\n    api project(':play-services-basement')\n    api project(':play-services-tasks')\n\n    annotationProcessor project(':safe-parcel-processor')\n}\n"
  },
  {
    "path": "play-services-base/core/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'kotlin-android'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\ndependencies {\n    api project(':play-services-basement-ktx')\n    implementation project(\":play-services-core-proto\")\n\n    implementation \"androidx.annotation:annotation:$annotationVersion\"\n    implementation \"androidx.appcompat:appcompat:$appcompatVersion\"\n    implementation \"androidx.core:core-ktx:$coreVersion\"\n    implementation \"androidx.lifecycle:lifecycle-service:$lifecycleVersion\"\n    implementation \"androidx.navigation:navigation-fragment-ktx:$navigationVersion\"\n    implementation \"androidx.navigation:navigation-ui-ktx:$navigationVersion\"\n    implementation \"androidx.preference:preference-ktx:$preferenceVersion\"\n\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion\"\n}\n\nandroid {\n    namespace \"org.microg.gms.base.core\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    buildFeatures {\n        dataBinding = true\n        buildConfig = true\n    }\n\n    sourceSets {\n        main.java.srcDirs += 'src/main/kotlin'\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n\n    kotlinOptions {\n        jvmTarget = 1.8\n    }\n\n    lintOptions {\n        disable 'MissingTranslation'\n    }\n}\n\napply from: '../../gradle/publish-android.gradle'\n\ndescription = 'microG service implementation for play-services-base'\n"
  },
  {
    "path": "play-services-base/core/package/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-FileCopyrightText: 2023 e Foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'kotlin-android'\n\ndependencies {\n    implementation project(':play-services-base')\n    implementation project(':play-services-base-core')\n}\n\nandroid {\n    namespace \"org.microg.gms.core.pkg\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    sourceSets {\n        main {\n            java.srcDirs = ['src/main/kotlin']\n        }\n    }\n\n    lintOptions {\n        disable 'MissingTranslation'\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n\n    kotlinOptions {\n        jvmTarget = 1.8\n    }\n}\n"
  },
  {
    "path": "play-services-base/core/package/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <application>\n        <provider\n            android:name=\"org.microg.gms.profile.ProfileProvider\"\n            android:authorities=\"${applicationId}.microg.profile\"\n            android:exported=\"true\"\n            tools:ignore=\"ExportedContentProvider\" />\n        <service\n            android:name=\"org.microg.gms.moduleinstall.ModuleInstallService\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.chimera.container.moduleinstall.ModuleInstallService.START\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </service>\n    </application>\n</manifest>\n"
  },
  {
    "path": "play-services-base/core/package/src/main/kotlin/org/microg/gms/moduleinstall/ModuleInstallService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.moduleinstall\n\nimport android.os.Bundle\nimport android.util.Log\nimport com.google.android.gms.common.Feature\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.api.internal.IStatusCallback\nimport com.google.android.gms.common.internal.ConnectionInfo\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport com.google.android.gms.common.moduleinstall.ModuleAvailabilityResponse\nimport com.google.android.gms.common.moduleinstall.ModuleAvailabilityResponse.AvailabilityStatus.STATUS_ALREADY_AVAILABLE\nimport com.google.android.gms.common.moduleinstall.ModuleInstallIntentResponse\nimport com.google.android.gms.common.moduleinstall.ModuleInstallResponse\nimport com.google.android.gms.common.moduleinstall.internal.ApiFeatureRequest\nimport com.google.android.gms.common.moduleinstall.internal.IModuleInstallCallbacks\nimport com.google.android.gms.common.moduleinstall.internal.IModuleInstallService\nimport com.google.android.gms.common.moduleinstall.internal.IModuleInstallStatusListener\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\n\nprivate const val TAG = \"ModuleInstall\"\n\nclass ModuleInstallService : BaseService(TAG, GmsService.MODULE_INSTALL) {\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        val binder = ModuleInstallServiceImpl().asBinder()\n        callback.onPostInitCompleteWithConnectionInfo(CommonStatusCodes.SUCCESS, binder, ConnectionInfo().apply {\n            features = arrayOf(Feature(\"moduleinstall\", 7))\n        })\n    }\n}\n\nclass ModuleInstallServiceImpl : IModuleInstallService.Stub() {\n    override fun areModulesAvailable(callbacks: IModuleInstallCallbacks?, request: ApiFeatureRequest?) {\n        Log.d(TAG, \"Not yet implemented: areModulesAvailable $request\")\n        runCatching { callbacks?.onModuleAvailabilityResponse(Status.SUCCESS, ModuleAvailabilityResponse(true, STATUS_ALREADY_AVAILABLE)) }\n    }\n\n    override fun installModules(callbacks: IModuleInstallCallbacks?, request: ApiFeatureRequest?, listener: IModuleInstallStatusListener?) {\n        Log.d(TAG, \"Not yet implemented: installModules $request\")\n        runCatching { callbacks?.onModuleInstallResponse(Status.CANCELED, ModuleInstallResponse(0, true)) }\n    }\n\n    override fun getInstallModulesIntent(callbacks: IModuleInstallCallbacks?, request: ApiFeatureRequest?) {\n        Log.d(TAG, \"Not yet implemented: getInstallModulesIntent $request\")\n        runCatching { callbacks?.onModuleInstallIntentResponse(Status.CANCELED, ModuleInstallIntentResponse(null)) }\n    }\n\n    override fun releaseModules(callback: IStatusCallback?, request: ApiFeatureRequest?) {\n        Log.d(TAG, \"Not yet implemented: releaseModules $request\")\n        runCatching { callback?.onResult(Status.SUCCESS) }\n    }\n\n    override fun unregisterListener(callback: IStatusCallback?, listener: IModuleInstallStatusListener?) {\n        Log.d(TAG, \"Not yet implemented: unregisterListener\")\n        runCatching { callback?.onResult(Status.SUCCESS) }\n    }\n\n}"
  },
  {
    "path": "play-services-base/core/package/src/main/kotlin/org/microg/gms/profile/ProfileProvider.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 e Foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.profile\n\nimport android.content.ContentProvider\nimport android.content.ContentValues\nimport android.database.Cursor\nimport android.database.MatrixCursor\nimport android.net.Uri\nimport org.microg.gms.settings.SettingsContract\n\nclass ProfileProvider : ContentProvider() {\n\n    val COLUMN_ID = \"profile_id\"\n    val COLUMN_VALUE = \"profile_value\"\n\n    override fun onCreate(): Boolean {\n        ProfileManager.ensureInitialized(context!!)\n        return true\n    }\n\n    override fun query(\n        uri: Uri,\n        projection: Array<out String>?,\n        selection: String?,\n        selectionArgs: Array<out String>?,\n        sortOrder: String?\n    ): Cursor =\n        MatrixCursor(arrayOf(COLUMN_ID, COLUMN_VALUE)).apply {\n            ProfileManager.getActiveProfileData(context!!).entries\n                .forEach {\n                    addRow(arrayOf(it.key, it.value))\n                }\n        }\n\n    override fun getType(uri: Uri): String {\n        return \"vnd.android.cursor.item/vnd.${SettingsContract.getAuthority(context!!)}.${uri.path}\"\n    }\n\n    override fun insert(uri: Uri, values: ContentValues?): Nothing = throw UnsupportedOperationException()\n\n    override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Nothing =\n        throw UnsupportedOperationException()\n\n    override fun update(\n        uri: Uri, values: ContentValues?, selection: String?, selectionArgs: Array<out String>?\n    ): Nothing = throw UnsupportedOperationException()\n\n}\n"
  },
  {
    "path": "play-services-base/core/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <permission android:name=\"${applicationId}.permission.READ_SETTINGS\"\n        android:protectionLevel=\"signature\" />\n    <permission android:name=\"${applicationId}.permission.WRITE_SETTINGS\"\n        android:protectionLevel=\"signature\" />\n\n    <uses-permission android:name=\"android.permission.INTERACT_ACROSS_PROFILES\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission android:name=\"android.permission.INTERACT_ACROSS_USERS\"\n        tools:ignore=\"ProtectedPermissions\" />\n\n    <application>\n        <provider\n            android:name=\"org.microg.gms.settings.SettingsProvider\"\n            android:authorities=\"${applicationId}.microg.settings\"\n            android:exported=\"true\"\n            android:grantUriPermissions=\"true\"\n            android:readPermission=\"${applicationId}.permission.READ_SETTINGS\"\n            android:writePermission=\"${applicationId}.permission.WRITE_SETTINGS\" />\n\n        <activity\n            android:name=\"org.microg.gms.crossprofile.CrossProfileSendActivity\"\n            android:exported=\"false\"\n            tools:targetApi=\"30\" />\n\n        <activity\n            android:name=\"org.microg.gms.crossprofile.CrossProfileRequestActivity\"\n            android:exported=\"false\"\n            tools:targetApi=\"30\" />\n\n        <receiver android:name=\"org.microg.gms.crossprofile.UserInitReceiver\"\n            android:exported=\"false\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.USER_INITIALIZE\" />\n            </intent-filter>\n        </receiver>\n    </application>\n</manifest>\n"
  },
  {
    "path": "play-services-base/core/src/main/java/org/microg/gms/AbstractGmsServiceBroker.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms;\n\nimport android.accounts.Account;\nimport android.os.Bundle;\nimport android.os.IBinder;\nimport android.os.Parcel;\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport com.google.android.gms.common.api.Scope;\nimport com.google.android.gms.common.internal.*;\n\nimport org.microg.gms.auth.AuthConstants;\nimport org.microg.gms.common.GmsService;\n\nimport java.util.EnumSet;\n\npublic abstract class AbstractGmsServiceBroker extends IGmsServiceBroker.Stub {\n    private static final String TAG = \"GmsServiceBroker\";\n    private final EnumSet<GmsService> supportedServices;\n\n    public AbstractGmsServiceBroker(EnumSet<GmsService> supportedServices) {\n        this.supportedServices = supportedServices;\n    }\n\n    @Deprecated\n    @Override\n    public void getPlusService(IGmsCallbacks callback, int versionCode, String packageName,\n                               String authPackage, String[] scopes, String accountName, Bundle params)\n            throws RemoteException {\n        Bundle extras = params == null ? new Bundle() : params;\n        extras.putString(\"auth_package\", authPackage);\n        callGetService(GmsService.PLUS, callback, versionCode, packageName, extras, accountName, scopes);\n    }\n\n    @Deprecated\n    @Override\n    public void getPanoramaService(IGmsCallbacks callback, int versionCode, String packageName,\n                                   Bundle params) throws RemoteException {\n        callGetService(GmsService.PANORAMA, callback, versionCode, packageName, params);\n    }\n\n    @Deprecated\n    @Override\n    public void getAppDataSearchService(IGmsCallbacks callback, int versionCode, String packageName)\n            throws RemoteException {\n        callGetService(GmsService.APP_DATA_SEARCH, callback, versionCode, packageName);\n    }\n\n    @Deprecated\n    @Override\n    public void getWalletService(IGmsCallbacks callback, int versionCode) throws RemoteException {\n        getWalletServiceWithPackageName(callback, versionCode, null);\n    }\n\n    @Deprecated\n    @Override\n    public void getPeopleService(IGmsCallbacks callback, int versionCode, String packageName,\n                                 Bundle params) throws RemoteException {\n        callGetService(GmsService.PEOPLE, callback, versionCode, packageName, params);\n    }\n\n    @Deprecated\n    @Override\n    public void getReportingService(IGmsCallbacks callback, int versionCode, String packageName,\n                                    Bundle params) throws RemoteException {\n        callGetService(GmsService.REPORTING, callback, versionCode, packageName, params);\n    }\n\n    @Deprecated\n    @Override\n    public void getLocationService(IGmsCallbacks callback, int versionCode, String packageName,\n                                   Bundle params) throws RemoteException {\n        callGetService(GmsService.LOCATION, callback, versionCode, packageName, params);\n    }\n\n    @Deprecated\n    @Override\n    public void getGoogleLocationManagerService(IGmsCallbacks callback, int versionCode,\n                                                String packageName, Bundle params) throws RemoteException {\n        callGetService(GmsService.GOOGLE_LOCATION_MANAGER, callback, versionCode, packageName, params);\n    }\n\n    @Deprecated\n    @Override\n    public void getGamesService(IGmsCallbacks callback, int versionCode, String packageName,\n                                String accountName, String[] scopes, String gamePackageName,\n                                IBinder popupWindowToken, String desiredLocale, Bundle params)\n            throws RemoteException {\n        Bundle extras = params == null ? new Bundle() : params;\n        extras.putString(\"com.google.android.gms.games.key.gamePackageName\", gamePackageName);\n        extras.putString(\"com.google.android.gms.games.key.desiredLocale\", desiredLocale);\n        extras.putParcelable(\"com.google.android.gms.games.key.popupWindowToken\", new BinderWrapper(popupWindowToken));\n        callGetService(GmsService.GAMES, callback, versionCode, packageName, extras, accountName, scopes);\n    }\n\n    @Deprecated\n    @Override\n    public void getAppStateService(IGmsCallbacks callback, int versionCode, String packageName,\n                                   String accountName, String[] scopes) throws RemoteException {\n        callGetService(GmsService.APP_STATE, callback, versionCode, packageName, null, accountName, scopes);\n    }\n\n    @Deprecated\n    @Override\n    public void getPlayLogService(IGmsCallbacks callback, int versionCode, String packageName,\n                                  Bundle params) throws RemoteException {\n        callGetService(GmsService.PLAY_LOG, callback, versionCode, packageName, params);\n    }\n\n    @Deprecated\n    @Override\n    public void getAdMobService(IGmsCallbacks callback, int versionCode, String packageName,\n                                Bundle params) throws RemoteException {\n        callGetService(GmsService.ADMOB, callback, versionCode, packageName, params);\n    }\n\n    @Deprecated\n    @Override\n    public void getDroidGuardService(IGmsCallbacks callback, int versionCode, String packageName,\n                                     Bundle params) throws RemoteException {\n        callGetService(GmsService.DROID_GUARD, callback, versionCode, packageName, params);\n    }\n\n    @Deprecated\n    @Override\n    public void getLockboxService(IGmsCallbacks callback, int versionCode, String packageName,\n                                  Bundle params) throws RemoteException {\n        callGetService(GmsService.LOCKBOX, callback, versionCode, packageName, params);\n    }\n\n    @Deprecated\n    @Override\n    public void getCastMirroringService(IGmsCallbacks callback, int versionCode, String packageName,\n                                        Bundle params) throws RemoteException {\n        callGetService(GmsService.CAST_MIRRORING, callback, versionCode, packageName, params);\n    }\n\n    @Deprecated\n    @Override\n    public void getNetworkQualityService(IGmsCallbacks callback, int versionCode,\n                                         String packageName, Bundle params) throws RemoteException {\n        callGetService(GmsService.NETWORK_QUALITY, callback, versionCode, packageName, params);\n    }\n\n    @Deprecated\n    @Override\n    public void getGoogleIdentityService(IGmsCallbacks callback, int versionCode,\n                                         String packageName, Bundle params) throws RemoteException {\n        callGetService(GmsService.ACCOUNT, callback, versionCode, packageName, params);\n    }\n\n    @Deprecated\n    @Override\n    public void getGoogleFeedbackService(IGmsCallbacks callback, int versionCode,\n                                         String packageName, Bundle params) throws RemoteException {\n        callGetService(GmsService.FEEDBACK, callback, versionCode, packageName, params);\n    }\n\n    @Deprecated\n    @Override\n    public void getCastService(IGmsCallbacks callback, int versionCode, String packageName,\n                               IBinder binder, Bundle params) throws RemoteException {\n        callGetService(GmsService.CAST, callback, versionCode, packageName, params);\n    }\n\n    @Deprecated\n    @Override\n    public void getDriveService(IGmsCallbacks callback, int versionCode, String packageName,\n                                String[] scopes, String accountName, Bundle params) throws RemoteException {\n        callGetService(GmsService.DRIVE, callback, versionCode, packageName, params, accountName, scopes);\n    }\n\n    @Deprecated\n    @Override\n    public void getLightweightAppDataSearchService(IGmsCallbacks callback, int versionCode,\n                                                   String packageName) throws RemoteException {\n        callGetService(GmsService.LIGHT_INDEX, callback, versionCode, packageName);\n    }\n\n    @Deprecated\n    @Override\n    public void getSearchAdministrationService(IGmsCallbacks callback, int versionCode,\n                                               String packageName) throws RemoteException {\n        callGetService(GmsService.SEARCH_ADMINISTRATION, callback, versionCode, packageName);\n    }\n\n    @Deprecated\n    @Override\n    public void getAutoBackupService(IGmsCallbacks callback, int versionCode, String packageName,\n                                     Bundle params) throws RemoteException {\n        callGetService(GmsService.AUTO_BACKUP, callback, versionCode, packageName, params);\n    }\n\n    @Deprecated\n    @Override\n    public void getAddressService(IGmsCallbacks callback, int versionCode, String packageName)\n            throws RemoteException {\n        callGetService(GmsService.ADDRESS, callback, versionCode, packageName);\n    }\n\n    @Deprecated\n    @Override\n    public void getWalletServiceWithPackageName(IGmsCallbacks callback, int versionCode, String packageName) throws RemoteException {\n        callGetService(GmsService.WALLET, callback, versionCode, packageName);\n    }\n\n    private void callGetService(GmsService service, IGmsCallbacks callback, int gmsVersion,\n                                String packageName) throws RemoteException {\n        callGetService(service, callback, gmsVersion, packageName, null);\n    }\n\n    private void callGetService(GmsService service, IGmsCallbacks callback, int gmsVersion,\n                                String packageName, Bundle extras) throws RemoteException {\n        callGetService(service, callback, gmsVersion, packageName, extras, null, null);\n    }\n\n    private void callGetService(GmsService service, IGmsCallbacks callback, int gmsVersion, String packageName, Bundle extras, String accountName, String[] scopes) throws RemoteException {\n        GetServiceRequest request = new GetServiceRequest(service.SERVICE_ID);\n        request.gmsVersion = gmsVersion;\n        request.packageName = packageName;\n        request.extras = extras;\n        request.account = accountName == null ? null : new Account(accountName, AuthConstants.DEFAULT_ACCOUNT_TYPE);\n        request.scopes = scopes == null ? null : scopesFromStringArray(scopes);\n        getService(callback, request);\n    }\n\n    private Scope[] scopesFromStringArray(String[] arr) {\n        Scope[] scopes = new Scope[arr.length];\n        for (int i = 0; i < arr.length; i++) {\n            scopes[i] = new Scope(arr[i]);\n        }\n        return scopes;\n    }\n\n    @Override\n    public void getService(IGmsCallbacks callback, GetServiceRequest request) throws RemoteException {\n        GmsService gmsService = GmsService.byServiceId(request.serviceId);\n        if ((supportedServices.contains(gmsService)) || supportedServices.contains(GmsService.ANY)) {\n            handleServiceRequest(callback, request, gmsService);\n        } else {\n            Log.d(TAG, \"Service not supported: \" + request);\n            throw new IllegalArgumentException(\"Service not supported: \" + request.serviceId);\n        }\n    }\n\n    public abstract void handleServiceRequest(IGmsCallbacks callback, GetServiceRequest request, GmsService service) throws RemoteException;\n\n    @Override\n    public void validateAccount(IGmsCallbacks callback, ValidateAccountRequest request) throws RemoteException {\n        throw new IllegalArgumentException(\"ValidateAccountRequest not supported\");\n    }\n\n    @Override\n    public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {\n        if (super.onTransact(code, data, reply, flags)) return true;\n        Log.d(TAG, \"onTransact [unknown]: \" + code + \", \" + data + \", \" + flags);\n        return false;\n    }\n}\n"
  },
  {
    "path": "play-services-base/core/src/main/java/org/microg/gms/BaseService.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms;\n\nimport android.content.Intent;\nimport android.os.IBinder;\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport androidx.lifecycle.LifecycleService;\n\nimport com.google.android.gms.common.internal.GetServiceRequest;\nimport com.google.android.gms.common.internal.IGmsCallbacks;\nimport com.google.android.gms.common.internal.IGmsServiceBroker;\n\nimport org.microg.gms.common.GmsService;\n\nimport java.io.FileDescriptor;\nimport java.io.PrintWriter;\nimport java.util.Arrays;\nimport java.util.EnumSet;\n\npublic abstract class BaseService extends LifecycleService {\n    private final IGmsServiceBroker broker;\n    private final EnumSet<GmsService> services;\n    protected final String TAG;\n\n    public BaseService(String tag, GmsService supportedService, GmsService... supportedServices) {\n        this.TAG = tag;\n        services = EnumSet.of(supportedService);\n        services.addAll(Arrays.asList(supportedServices));\n        broker = new AbstractGmsServiceBroker(services) {\n            @Override\n            public void handleServiceRequest(IGmsCallbacks callback, GetServiceRequest request, GmsService service) throws RemoteException {\n                try {\n                    request.extras.keySet(); // call to unparcel()\n                } catch (Exception e) {\n                    // Sometimes we need to define the correct ClassLoader before unparcel(). Ignore those.\n                }\n                Log.d(TAG, \"bound by: \" + request);\n                BaseService.this.handleServiceRequest(callback, request, service);\n            }\n        };\n    }\n\n    @Override\n    public IBinder onBind(Intent intent) {\n        super.onBind(intent);\n        Log.d(TAG, \"onBind: \" + intent);\n        return broker.asBinder();\n    }\n\n    @Override\n    protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {\n        writer.println(TAG + \" providing services \" + services.toString());\n    }\n\n    public abstract void handleServiceRequest(IGmsCallbacks callback, GetServiceRequest request, GmsService service) throws RemoteException;\n}\n"
  },
  {
    "path": "play-services-base/core/src/main/java/org/microg/gms/DummyService.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms;\n\nimport android.os.RemoteException;\n\nimport com.google.android.gms.common.ConnectionResult;\nimport com.google.android.gms.common.api.CommonStatusCodes;\nimport com.google.android.gms.common.internal.GetServiceRequest;\nimport com.google.android.gms.common.internal.IGmsCallbacks;\n\nimport org.microg.gms.common.GmsService;\n\npublic class DummyService extends BaseService {\n    public DummyService() {\n        super(\"GmsDummySvc\", GmsService.ANY);\n    }\n\n    @Override\n    public void handleServiceRequest(IGmsCallbacks callback, GetServiceRequest request, GmsService service) throws RemoteException {\n        callback.onPostInitComplete(ConnectionResult.API_DISABLED, null, null);\n    }\n}\n"
  },
  {
    "path": "play-services-base/core/src/main/java/org/microg/gms/auth/AuthRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth;\n\nimport android.content.Context;\n\nimport org.microg.gms.checkin.LastCheckinInfo;\nimport org.microg.gms.profile.Build;\nimport org.microg.gms.common.Constants;\nimport org.microg.gms.common.HttpFormClient;\nimport org.microg.gms.common.Utils;\nimport org.microg.gms.profile.ProfileManager;\n\nimport java.io.IOException;\nimport java.util.Locale;\nimport java.util.Map;\n\nimport static org.microg.gms.common.HttpFormClient.RequestContent;\nimport static org.microg.gms.common.HttpFormClient.RequestHeader;\n\npublic class AuthRequest extends HttpFormClient.Request {\n    private static final String SERVICE_URL = \"https://android.googleapis.com/auth\";\n    private static final String USER_AGENT = \"GoogleAuth/1.4 (%s %s); gzip\";\n\n    @RequestHeader(\"User-Agent\")\n    private String userAgent;\n\n    @RequestHeader(\"app\")\n    @RequestContent(\"app\")\n    public String app;\n    @RequestContent(\"client_sig\")\n    public String appSignature;\n    @RequestContent(\"callerPkg\")\n    public String caller;\n    @RequestContent(\"callerSig\")\n    public String callerSignature;\n    @RequestHeader(value = \"device\", nullPresent = true)\n    @RequestContent(value = \"androidId\", nullPresent = true)\n    public String androidIdHex;\n    @RequestContent(\"sdk_version\")\n    public int sdkVersion;\n    @RequestContent(\"device_country\")\n    public String countryCode;\n    @RequestContent(\"operatorCountry\")\n    public String operatorCountryCode;\n    @RequestContent(\"lang\")\n    public String locale;\n    @RequestContent(\"google_play_services_version\")\n    public int gmsVersion = Constants.GMS_VERSION_CODE;\n    @RequestContent(\"accountType\")\n    public String accountType;\n    @RequestContent(\"Email\")\n    public String email;\n    @RequestContent(\"service\")\n    public String service;\n    @RequestContent(\"source\")\n    public String source;\n    @RequestContent({\"is_called_from_account_manager\", \"_opt_is_called_from_account_manager\"})\n    public boolean isCalledFromAccountManager;\n    @RequestContent(\"Token\")\n    public String token;\n    @RequestContent(\"system_partition\")\n    public boolean systemPartition;\n    @RequestContent(\"get_accountid\")\n    public boolean getAccountId;\n    @RequestContent(\"ACCESS_TOKEN\")\n    public boolean isAccessToken;\n    @RequestContent(\"droidguard_results\")\n    public String droidguardResults;\n    @RequestContent(\"has_permission\")\n    public boolean hasPermission;\n    @RequestContent(\"add_account\")\n    public boolean addAccount;\n    @RequestContent(\"delegation_type\")\n    public String delegationType;\n    @RequestContent(\"delegatee_user_id\")\n    public String delegateeUserId;\n    @RequestContent(\"oauth2_foreground\")\n    public String oauth2Foreground;\n    @RequestContent(\"token_request_options\")\n    public String tokenRequestOptions;\n    @RequestContent(\"it_caveat_types\")\n    public String itCaveatTypes;\n    @RequestContent(\"check_email\")\n    public boolean checkEmail;\n    @RequestContent(\"request_visible_actions\")\n    public String requestVisibleActions;\n    @RequestContent(\"oauth2_prompt\")\n    public String oauth2Prompt;\n    @RequestContent(\"oauth2_include_profile\")\n    public String oauth2IncludeProfile;\n    @RequestContent(\"oauth2_include_email\")\n    public String oauth2IncludeEmail;\n    @HttpFormClient.RequestContentDynamic\n    public Map<Object, Object> dynamicFields;\n\n    public String deviceName;\n    public String buildVersion;\n\n    @Override\n    protected void prepare() {\n        userAgent = String.format(USER_AGENT, deviceName, buildVersion);\n    }\n\n    public AuthRequest build(Context context) {\n        ProfileManager.ensureInitialized(context);\n        sdkVersion = Build.VERSION.SDK_INT;\n        deviceName = Build.DEVICE;\n        buildVersion = Build.ID;\n        return this;\n    }\n\n    public AuthRequest source(String source) {\n        this.source = source;\n        return this;\n    }\n\n    public AuthRequest locale(Locale locale) {\n        this.locale = locale.toString();\n        this.countryCode = locale.getCountry().toLowerCase();\n        this.operatorCountryCode = locale.getCountry().toLowerCase();\n        return this;\n    }\n\n    public AuthRequest fromContext(Context context) {\n        build(context);\n        locale(Utils.getLocale(context));\n        if (AuthPrefs.shouldIncludeAndroidId(context)) {\n            androidIdHex = Long.toHexString(LastCheckinInfo.read(context).getAndroidId());\n        }\n        if (AuthPrefs.shouldStripDeviceName(context)) {\n            deviceName = \"\";\n            buildVersion = \"\";\n        }\n        return this;\n    }\n\n    public AuthRequest email(String email) {\n        this.email = email;\n        return this;\n    }\n\n    public AuthRequest token(String token) {\n        this.token = token;\n        return this;\n    }\n\n    public AuthRequest service(String service) {\n        this.service = service;\n        return this;\n    }\n\n    public AuthRequest app(String app, String appSignature) {\n        this.app = app;\n        this.appSignature = appSignature;\n        return this;\n    }\n\n    public AuthRequest appIsGms() {\n        return app(Constants.GMS_PACKAGE_NAME, Constants.GMS_PACKAGE_SIGNATURE_SHA1);\n    }\n\n    public AuthRequest callerIsGms() {\n        return caller(Constants.GMS_PACKAGE_NAME, Constants.GMS_PACKAGE_SIGNATURE_SHA1);\n    }\n\n    public AuthRequest callerIsApp() {\n        return caller(app, appSignature);\n    }\n\n    public AuthRequest caller(String caller, String callerSignature) {\n        this.caller = caller;\n        this.callerSignature = callerSignature;\n        return this;\n    }\n\n    public AuthRequest calledFromAccountManager() {\n        isCalledFromAccountManager = true;\n        return this;\n    }\n\n    public AuthRequest addAccount() {\n        addAccount = true;\n        return this;\n    }\n\n    public AuthRequest systemPartition(boolean systemPartition) {\n        this.systemPartition = systemPartition;\n        return this;\n    }\n\n    public AuthRequest hasPermission(boolean hasPermission) {\n        this.hasPermission = hasPermission;\n        return this;\n    }\n\n    public AuthRequest getAccountId() {\n        getAccountId = true;\n        return this;\n    }\n\n    public AuthRequest isAccessToken() {\n        isAccessToken = true;\n        return this;\n    }\n\n    public AuthRequest droidguardResults(String droidguardResults) {\n        this.droidguardResults = droidguardResults;\n        return this;\n    }\n\n    public AuthRequest delegation(int delegationType, String delegateeUserId) {\n        this.delegationType = delegationType == 0 ? null : Integer.toString(delegationType);\n        this.delegateeUserId = delegateeUserId;\n        return this;\n    }\n\n    public AuthRequest oauth2Foreground(String oauth2Foreground) {\n        this.oauth2Foreground = oauth2Foreground;\n        return this;\n    }\n\n    public AuthRequest tokenRequestOptions(String tokenRequestOptions) {\n        this.tokenRequestOptions = tokenRequestOptions;\n        return this;\n    }\n\n    public AuthRequest oauth2IncludeProfile(String oauth2IncludeProfile) {\n        this.oauth2IncludeProfile = oauth2IncludeProfile;\n        return this;\n    }\n\n    public AuthRequest oauth2IncludeEmail(String oauth2IncludeEmail) {\n        this.oauth2IncludeEmail = oauth2IncludeEmail;\n        return this;\n    }\n\n    public AuthRequest oauth2Prompt(String oauth2Prompt) {\n        this.oauth2Prompt = oauth2Prompt;\n        return this;\n    }\n\n    public AuthRequest itCaveatTypes(String itCaveatTypes) {\n        this.itCaveatTypes = itCaveatTypes;\n        return this;\n    }\n\n    public AuthRequest putDynamicFiledMap(Map<Object, Object> dynamicFields) {\n        this.dynamicFields = dynamicFields;\n        return this;\n    }\n\n    public AuthResponse getResponse() throws IOException {\n        return HttpFormClient.request(SERVICE_URL, this, AuthResponse.class);\n    }\n\n    public void getResponseAsync(HttpFormClient.Callback<AuthResponse> callback) {\n        HttpFormClient.requestAsync(SERVICE_URL, this, AuthResponse.class, callback);\n    }\n}\n"
  },
  {
    "path": "play-services-base/core/src/main/java/org/microg/gms/auth/AuthResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.auth;\n\nimport android.util.Log;\n\nimport java.lang.reflect.Field;\n\nimport static org.microg.gms.common.HttpFormClient.ResponseField;\n\npublic class AuthResponse {\n    private static final String TAG = \"GmsAuthResponse\";\n\n    @ResponseField(\"SID\")\n    public String Sid;\n    @ResponseField(\"LSID\")\n    public String LSid;\n    @ResponseField(\"Auth\")\n    public String auth;\n    @ResponseField(\"Token\")\n    public String token;\n    @ResponseField(\"Email\")\n    public String email;\n    @ResponseField(\"services\")\n    public String services;\n    @ResponseField(\"GooglePlusUpgrade\")\n    public boolean isGooglePlusUpgrade;\n    @ResponseField(\"PicasaUser\")\n    public String picasaUserName;\n    @ResponseField(\"RopText\")\n    public String ropText;\n    @ResponseField(\"RopRevision\")\n    public int ropRevision;\n    @ResponseField(\"firstName\")\n    public String firstName;\n    @ResponseField(\"lastName\")\n    public String lastName;\n    @ResponseField(\"issueAdvice\")\n    public String issueAdvice;\n    @ResponseField(\"accountId\")\n    public String accountId;\n    @ResponseField(\"Expiry\")\n    public long expiry = -1;\n    @ResponseField(\"storeConsentRemotely\")\n    public boolean storeConsentRemotely = true;\n    @ResponseField(\"Permission\")\n    public String permission;\n    @ResponseField(\"ScopeConsentDetails\")\n    public String scopeConsentDetails;\n    @ResponseField(\"ConsentDataBase64\")\n    public String consentDataBase64;\n    @ResponseField(\"grantedScopes\")\n    public String grantedScopes;\n    @ResponseField(\"itMetadata\")\n    public String itMetadata;\n    @ResponseField(\"ResolutionDataBase64\")\n    public String resolutionDataBase64;\n    @ResponseField(\"it\")\n    public String auths;\n    @ResponseField(\"capabilities\")\n    public String capabilities;\n    @ResponseField(\"ExpiresInDurationSec\")\n    public int expiresInDurationSec;\n\n    public static AuthResponse parse(String result) {\n        AuthResponse response = new AuthResponse();\n        String[] entries = result.split(\"\\n\");\n        for (String s : entries) {\n            String[] keyValuePair = s.split(\"=\", 2);\n            String key = keyValuePair[0].trim();\n            String value = keyValuePair[1].trim();\n            try {\n                for (Field field : AuthResponse.class.getDeclaredFields()) {\n                    if (field.isAnnotationPresent(ResponseField.class) &&\n                            key.equals(field.getAnnotation(ResponseField.class).value())) {\n                        if (field.getType().equals(String.class)) {\n                            field.set(response, value);\n                        } else if (field.getType().equals(boolean.class)) {\n                            field.setBoolean(response, value.equals(\"1\"));\n                        } else if (field.getType().equals(long.class)) {\n                            field.setLong(response, Long.parseLong(value));\n                        } else if (field.getType().equals(int.class)) {\n                            field.setInt(response, Integer.parseInt(value));\n                        }\n                    }\n                }\n            } catch (Exception e) {\n                Log.w(TAG, e);\n            }\n        }\n        return response;\n    }\n\n    @Override\n    public String toString() {\n        final StringBuilder sb = new StringBuilder(\"AuthResponse{\");\n        sb.append(\"auth='\").append(auth).append('\\'');\n        if (Sid != null) sb.append(\", Sid='\").append(Sid).append('\\'');\n        if (LSid != null) sb.append(\", LSid='\").append(LSid).append('\\'');\n        if (token != null) sb.append(\", token='\").append(token).append('\\'');\n        if (email != null) sb.append(\", email='\").append(email).append('\\'');\n        if (services != null) sb.append(\", services='\").append(services).append('\\'');\n        if (isGooglePlusUpgrade) sb.append(\", isGooglePlusUpgrade=\").append(isGooglePlusUpgrade);\n        if (picasaUserName != null) sb.append(\", picasaUserName='\").append(picasaUserName).append('\\'');\n        if (ropText != null) sb.append(\", ropText='\").append(ropText).append('\\'');\n        if (ropRevision != 0) sb.append(\", ropRevision=\").append(ropRevision);\n        if (firstName != null) sb.append(\", firstName='\").append(firstName).append('\\'');\n        if (lastName != null) sb.append(\", lastName='\").append(lastName).append('\\'');\n        if (issueAdvice != null) sb.append(\", issueAdvice='\").append(issueAdvice).append('\\'');\n        if (accountId != null) sb.append(\", accountId='\").append(accountId).append('\\'');\n        if (expiry != -1) sb.append(\", expiry=\").append(expiry);\n        if (!storeConsentRemotely) sb.append(\", storeConsentRemotely=\").append(storeConsentRemotely);\n        if (permission != null) sb.append(\", permission='\").append(permission).append('\\'');\n        if (scopeConsentDetails != null) sb.append(\", scopeConsentDetails='\").append(scopeConsentDetails).append('\\'');\n        if (consentDataBase64 != null) sb.append(\", consentDataBase64='\").append(consentDataBase64).append('\\'');\n        if (auths != null) sb.append(\", auths='\").append(auths).append('\\'');\n        if (itMetadata != null) sb.append(\", itMetadata='\").append(itMetadata).append('\\'');\n        if (resolutionDataBase64 != null) sb.append(\", resolutionDataBase64='\").append(resolutionDataBase64).append('\\'');\n        if (capabilities != null) sb.append(\", capabilitites='\").append(capabilities).append('\\'');\n        if (expiresInDurationSec != 0) sb.append(\", expiresInDurationSec='\").append(expiresInDurationSec).append('\\'');\n        sb.append('}');\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "play-services-base/core/src/main/java/org/microg/gms/common/DeviceConfiguration.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.common;\n\nimport android.annotation.SuppressLint;\nimport android.app.ActivityManager;\nimport android.content.Context;\nimport android.content.pm.ConfigurationInfo;\nimport android.content.pm.FeatureInfo;\nimport android.content.pm.PackageManager;\nimport android.content.res.Configuration;\nimport android.opengl.GLES10;\nimport android.util.DisplayMetrics;\nimport org.microg.gms.profile.Build;\nimport org.microg.gms.profile.ProfileManager;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\nimport javax.microedition.khronos.egl.EGL10;\nimport javax.microedition.khronos.egl.EGLConfig;\nimport javax.microedition.khronos.egl.EGLContext;\nimport javax.microedition.khronos.egl.EGLDisplay;\n\nimport static android.os.Build.VERSION.SDK_INT;\n\npublic class DeviceConfiguration {\n    public List<String> availableFeatures;\n    public int densityDpi;\n    public double diagonalInch;\n    public int glEsVersion;\n    public List<String> glExtensions;\n    public boolean hasFiveWayNavigation;\n    public boolean hasHardKeyboard;\n    public int heightPixels;\n    public int keyboardType;\n    public List<String> locales;\n    public List<String> nativePlatforms;\n    public int navigation;\n    public int screenLayout;\n    public List<String> sharedLibraries;\n    public int touchScreen;\n    public int widthPixels;\n\n    public DeviceConfiguration(Context context) {\n        ProfileManager.ensureInitialized(context);\n        ConfigurationInfo configurationInfo = ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)).getDeviceConfigurationInfo();\n        touchScreen = configurationInfo.reqTouchScreen;\n        keyboardType = configurationInfo.reqKeyboardType;\n        navigation = configurationInfo.reqNavigation;\n        Configuration configuration = context.getResources().getConfiguration();\n        screenLayout = configuration.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK;\n        hasHardKeyboard = (configurationInfo.reqInputFeatures & ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD) > 0;\n        hasFiveWayNavigation = (configurationInfo.reqInputFeatures & ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV) > 0;\n        DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();\n        densityDpi = displayMetrics.densityDpi;\n        glEsVersion = configurationInfo.reqGlEsVersion;\n        PackageManager packageManager = context.getPackageManager();\n        String[] systemSharedLibraryNames = packageManager.getSystemSharedLibraryNames();\n        sharedLibraries = new ArrayList<String>();\n        if (systemSharedLibraryNames != null) sharedLibraries.addAll(Arrays.asList(systemSharedLibraryNames));\n        for (String s : new String[]{\"com.google.android.maps\", \"com.google.android.media.effects\", \"com.google.widevine.software.drm\"}) {\n            if (!sharedLibraries.contains(s)) {\n                sharedLibraries.add(s);\n            }\n        }\n        Collections.sort(sharedLibraries);\n        availableFeatures = new ArrayList<String>();\n        if (packageManager.getSystemAvailableFeatures() != null) {\n            for (FeatureInfo featureInfo : packageManager.getSystemAvailableFeatures()) {\n                if (featureInfo != null && featureInfo.name != null) availableFeatures.add(featureInfo.name);\n            }\n        }\n        Collections.sort(availableFeatures);\n        this.nativePlatforms = getNativePlatforms();\n        widthPixels = displayMetrics.widthPixels;\n        heightPixels = displayMetrics.heightPixels;\n        diagonalInch = Math.sqrt(\n                Math.pow(widthPixels / displayMetrics.xdpi, 2) +\n                        Math.pow(heightPixels / displayMetrics.ydpi, 2)\n        );\n        locales = getLocales(context);\n        Set<String> glExtensions = new HashSet<String>();\n        addEglExtensions(glExtensions);\n        this.glExtensions = new ArrayList<String>(glExtensions);\n        Collections.sort(this.glExtensions);\n    }\n\n    @SuppressLint(\"GetLocales\")\n    private static List<String> getLocales(Context context) {\n        List<String> locales = new ArrayList<String>();\n        if (SDK_INT >= 21) {\n            locales.addAll(Arrays.asList(context.getAssets().getLocales()));\n        } else {\n            locales.add(\"en-US\");\n        }\n        for (int i = 0; i < locales.size(); i++) {\n            locales.set(i, locales.get(i).replace(\"-\", \"_\"));\n        }\n        Collections.sort(locales);\n        return locales;\n    }\n\n    @SuppressWarnings({\"deprecation\", \"InlinedApi\"})\n    private static List<String> getNativePlatforms() {\n        List<String> nativePlatforms;\n        if (Build.VERSION.SDK_INT >= 21) {\n            return Arrays.asList(Build.SUPPORTED_ABIS);\n        } else {\n            nativePlatforms = new ArrayList<String>();\n            nativePlatforms.add(Build.CPU_ABI);\n            if (Build.CPU_ABI2 != null && !Build.CPU_ABI2.equals(\"unknown\"))\n                nativePlatforms.add(Build.CPU_ABI2);\n            return nativePlatforms;\n        }\n    }\n\n    private static void addEglExtensions(Set<String> glExtensions) {\n        EGL10 egl10 = (EGL10) EGLContext.getEGL();\n        if (egl10 != null) {\n            EGLDisplay display = egl10.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);\n            egl10.eglInitialize(display, new int[2]);\n            int cf[] = new int[1];\n            if (egl10.eglGetConfigs(display, null, 0, cf)) {\n                EGLConfig[] configs = new EGLConfig[cf[0]];\n                if (egl10.eglGetConfigs(display, configs, cf[0], cf)) {\n                    int[] a1 =\n                            new int[]{EGL10.EGL_WIDTH, EGL10.EGL_PBUFFER_BIT, EGL10.EGL_HEIGHT, EGL10.EGL_PBUFFER_BIT,\n                                    EGL10.EGL_NONE};\n                    int[] a2 = new int[]{12440, EGL10.EGL_PIXMAP_BIT, EGL10.EGL_NONE};\n                    int[] a3 = new int[1];\n                    for (int i = 0; i < cf[0]; i++) {\n                        egl10.eglGetConfigAttrib(display, configs[i], EGL10.EGL_CONFIG_CAVEAT, a3);\n                        if (a3[0] != EGL10.EGL_SLOW_CONFIG) {\n                            egl10.eglGetConfigAttrib(display, configs[i], EGL10.EGL_SURFACE_TYPE, a3);\n                            if ((1 & a3[0]) != 0) {\n                                egl10.eglGetConfigAttrib(display, configs[i], EGL10.EGL_RENDERABLE_TYPE, a3);\n                                if ((1 & a3[0]) != 0) {\n                                    addExtensionsForConfig(egl10, display, configs[i], a1, null, glExtensions);\n                                }\n                                if ((4 & a3[0]) != 0) {\n                                    addExtensionsForConfig(egl10, display, configs[i], a1, a2, glExtensions);\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n            egl10.eglTerminate(display);\n        }\n    }\n\n    private static void addExtensionsForConfig(EGL10 egl10, EGLDisplay egldisplay, EGLConfig eglconfig, int ai[],\n                                               int ai1[], Set<String> set) {\n        EGLContext eglcontext = egl10.eglCreateContext(egldisplay, eglconfig, EGL10.EGL_NO_CONTEXT, ai1);\n        if (eglcontext != EGL10.EGL_NO_CONTEXT) {\n            javax.microedition.khronos.egl.EGLSurface eglsurface =\n                    egl10.eglCreatePbufferSurface(egldisplay, eglconfig, ai);\n            if (eglsurface == EGL10.EGL_NO_SURFACE) {\n                egl10.eglDestroyContext(egldisplay, eglcontext);\n            } else {\n                egl10.eglMakeCurrent(egldisplay, eglsurface, eglsurface, eglcontext);\n                String s = GLES10.glGetString(7939);\n                if (s != null && !s.isEmpty()) {\n                    String as[] = s.split(\" \");\n                    int i = as.length;\n                    for (int j = 0; j < i; j++) {\n                        set.add(as[j]);\n                    }\n\n                }\n                egl10.eglMakeCurrent(egldisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);\n                egl10.eglDestroySurface(egldisplay, eglsurface);\n                egl10.eglDestroyContext(egldisplay, eglcontext);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-base/core/src/main/java/org/microg/gms/common/DeviceIdentifier.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.common;\n\nimport java.util.Random;\n\npublic class DeviceIdentifier {\n    public String wifiMac = randomMacAddress(); // TODO: static\n    public String meid = randomMeid();\n    public String esn;\n\n\n    private static String randomMacAddress() {\n        String mac = \"b407f9\";\n        Random rand = new Random();\n        for (int i = 0; i < 6; i++) {\n            mac += Integer.toString(rand.nextInt(16), 16);\n        }\n        return mac;\n    }\n\n    private static String randomMeid() {\n        // http://en.wikipedia.org/wiki/International_Mobile_Equipment_Identity\n        // We start with a known base, and generate random MEID\n        String meid = \"35503104\";\n        Random rand = new Random();\n        for (int i = 0; i < 6; i++) {\n            meid += Integer.toString(rand.nextInt(10));\n        }\n\n        // Luhn algorithm (check digit)\n        int sum = 0;\n        for (int i = 0; i < meid.length(); i++) {\n            int c = Integer.parseInt(String.valueOf(meid.charAt(i)));\n            if ((meid.length() - i - 1) % 2 == 0) {\n                c *= 2;\n                c = c % 10 + c / 10;\n            }\n\n            sum += c;\n        }\n        final int check = (100 - sum) % 10;\n        meid += Integer.toString(check);\n\n        return meid;\n    }\n}\n"
  },
  {
    "path": "play-services-base/core/src/main/java/org/microg/gms/common/ForegroundServiceContext.java",
    "content": "package org.microg.gms.common;\n\nimport android.app.Notification;\nimport android.app.NotificationChannel;\nimport android.app.NotificationManager;\nimport android.app.Service;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.ContextWrapper;\nimport android.content.Intent;\nimport android.os.PowerManager;\nimport android.util.Log;\n\nimport androidx.annotation.RequiresApi;\n\nimport org.microg.gms.base.core.R;\n\nimport static android.os.Build.VERSION.SDK_INT;\n\npublic class ForegroundServiceContext extends ContextWrapper {\n    private static final String TAG = \"ForegroundService\";\n    public static final String EXTRA_FOREGROUND = \"foreground\";\n\n    public ForegroundServiceContext(Context base) {\n        super(base);\n    }\n\n    @Override\n    public ComponentName startService(Intent service) {\n        if (SDK_INT >= 26 && !isIgnoringBatteryOptimizations()) {\n            Log.d(TAG, \"Starting in foreground mode.\");\n            service.putExtra(EXTRA_FOREGROUND, true);\n            return super.startForegroundService(service);\n        }\n        return super.startService(service);\n    }\n\n    @RequiresApi(23)\n    private boolean isIgnoringBatteryOptimizations() {\n        PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);\n        return powerManager.isIgnoringBatteryOptimizations(getPackageName());\n    }\n\n    private static String getServiceName(Service service) {\n        String serviceName = null;\n        try {\n            ForegroundServiceInfo annotation = service.getClass().getAnnotation(ForegroundServiceInfo.class);\n            if (annotation != null) {\n                serviceName = annotation.value();\n                if (annotation.res() != 0) {\n                    try {\n                        serviceName = service.getString(annotation.res());\n                    } catch (Exception ignored) {\n                    }\n                }\n                if (!annotation.resName().isEmpty() && !annotation.resPackage().isEmpty()) {\n                    try {\n                        serviceName = service.getString(service.getResources().getIdentifier(annotation.resName(), \"string\", annotation.resPackage()));\n                    } catch (Exception ignored) {\n                    }\n                }\n            }\n        } catch (Exception ignored) {\n        }\n        if (serviceName == null) {\n            serviceName = service.getClass().getSimpleName();\n        }\n        return serviceName;\n    }\n\n    public static void completeForegroundService(Service service, Intent intent, String tag) {\n        if (intent != null && intent.getBooleanExtra(EXTRA_FOREGROUND, false) && SDK_INT >= 26) {\n            String serviceName = getServiceName(service);\n            Log.d(tag, \"Started \" + serviceName + \" in foreground mode.\");\n            try {\n                Notification notification = buildForegroundNotification(service, serviceName);\n                service.startForeground(serviceName.hashCode(), notification);\n                Log.d(tag, \"Notification: \" + notification.toString());\n            } catch (Exception e) {\n                Log.w(tag, e);\n            }\n        }\n    }\n\n    @RequiresApi(26)\n    private static Notification buildForegroundNotification(Context context, String serviceName) {\n        NotificationChannel channel = new NotificationChannel(\"foreground-service\", \"Foreground Service\", NotificationManager.IMPORTANCE_NONE);\n        channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);\n        channel.setShowBadge(false);\n        channel.setVibrationPattern(new long[]{0});\n        context.getSystemService(NotificationManager.class).createNotificationChannel(channel);\n        String appTitle = context.getApplicationInfo().loadLabel(context.getPackageManager()).toString();\n        String notifyTitle = context.getString(R.string.foreground_service_notification_title);\n        String firstLine = context.getString(R.string.foreground_service_notification_text, serviceName);\n        String secondLine = context.getString(R.string.foreground_service_notification_big_text, appTitle);\n        Log.d(TAG, notifyTitle + \" // \" + firstLine + \" // \" + secondLine);\n        return new Notification.Builder(context, channel.getId())\n                .setOngoing(true)\n                .setSmallIcon(R.drawable.ic_background_notify)\n                .setContentTitle(notifyTitle)\n                .setContentText(firstLine)\n                .setStyle(new Notification.BigTextStyle().bigText(firstLine + \"\\n\" + secondLine))\n                .build();\n    }\n\n}\n"
  },
  {
    "path": "play-services-base/core/src/main/java/org/microg/gms/common/ForegroundServiceInfo.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.common;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.TYPE)\npublic @interface ForegroundServiceInfo {\n    String value();\n    @Deprecated\n    int res() default 0;\n    String resName() default \"\";\n    String resPackage() default \"\";\n}\n"
  },
  {
    "path": "play-services-base/core/src/main/java/org/microg/gms/common/HttpFormClient.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.common;\n\nimport android.net.Uri;\nimport android.util.Log;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.lang.reflect.Field;\nimport java.net.HttpURLConnection;\nimport java.net.URL;\nimport java.util.List;\nimport java.util.Map;\n\npublic class HttpFormClient {\n    private static final String TAG = \"GmsHttpFormClient\";\n\n    public static <T> T request(String url, Request request, Class<T> tClass) throws IOException {\n        HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();\n        connection.setRequestMethod(\"POST\");\n        connection.setDoInput(true);\n        connection.setDoOutput(true);\n        connection.setRequestProperty(\"Content-Type\", \"application/x-www-form-urlencoded\");\n        StringBuilder content = new StringBuilder();\n        request.prepare();\n        for (Field field : request.getClass().getDeclaredFields()) {\n            try {\n                field.setAccessible(true);\n                Object objVal = field.get(request);\n                if (field.isAnnotationPresent(RequestContentDynamic.class)) {\n                    Map<String, String> contentParams = (Map<String, String>) objVal;\n                    for (Map.Entry<String, String> param : contentParams.entrySet()) {\n                        appendParam(content, param.getKey(), param.getValue());\n                    }\n                    continue;\n                }\n                String value = objVal != null ? String.valueOf(objVal) : null;\n                Boolean boolVal = null;\n                if (field.getType().equals(boolean.class)) {\n                    boolVal = field.getBoolean(request);\n                }\n                if (field.isAnnotationPresent(RequestHeader.class)) {\n                    RequestHeader annotation = field.getAnnotation(RequestHeader.class);\n                    value = valueFromBoolVal(value, boolVal, annotation.truePresent(), annotation.falsePresent());\n                    if (value != null || annotation.nullPresent()) {\n                        for (String key : annotation.value()) {\n                            connection.setRequestProperty(key, String.valueOf(value));\n                        }\n                    }\n                }\n                if (field.isAnnotationPresent(RequestContent.class)) {\n                    RequestContent annotation = field.getAnnotation(RequestContent.class);\n                    value = valueFromBoolVal(value, boolVal, annotation.truePresent(), annotation.falsePresent());\n                    if (value != null || annotation.nullPresent()) {\n                        for (String key : annotation.value()) {\n                            appendParam(content, key, value);\n                        }\n                    }\n                }\n            } catch (Exception ignored) {\n            }\n        }\n\n        Log.d(TAG, \"-- Request --\\n\" + content);\n        String replace = content.toString().trim().replace(\"\\n\", \"\");\n        OutputStream os = connection.getOutputStream();\n        os.write(replace.trim().getBytes());\n        os.close();\n\n        if (connection.getResponseCode() != 200) {\n            String error = connection.getResponseMessage();\n            try {\n                error = new String(Utils.readStreamToEnd(connection.getErrorStream()));\n            } catch (IOException e) {\n                // Ignore\n            }\n            throw new NotOkayException(error);\n        }\n\n        String result = new String(Utils.readStreamToEnd(connection.getInputStream()));\n        Log.d(TAG, \"-- Response --\\n\" + result);\n        return parseResponse(tClass, connection, result);\n    }\n\n    private static String valueFromBoolVal(String value, Boolean boolVal, boolean truePresent, boolean falsePresent) {\n        if (boolVal != null) {\n            if (boolVal && truePresent) {\n                return \"1\";\n            } else if (!boolVal && falsePresent) {\n                return \"0\";\n            } else {\n                return null;\n            }\n        } else {\n            return value;\n        }\n    }\n\n    private static void appendParam(StringBuilder content, String key, String value) {\n        if (content.length() > 0)\n            content.append(\"&\");\n        if (key.equals(\"token_request_options\")) {\n            content.append(Uri.encode(key)).append(\"=\").append(value);\n        } else {\n            content.append(Uri.encode(key)).append(\"=\").append(Uri.encode(String.valueOf(value)));\n        }\n    }\n\n    private static <T> T parseResponse(Class<T> tClass, HttpURLConnection connection, String result) throws IOException {\n        Map<String, List<String>> headerFields = connection.getHeaderFields();\n        T response;\n        try {\n            response = tClass.getConstructor().newInstance();\n        } catch (Exception e) {\n            return null;\n        }\n        String[] entries = result.split(\"\\n\");\n        for (String s : entries) {\n            String[] keyValuePair = s.split(\"=\", 2);\n            String key = keyValuePair[0].trim();\n            String value = keyValuePair[1].trim();\n            boolean matched = false;\n            try {\n                for (Field field : tClass.getDeclaredFields()) {\n                    if (field.isAnnotationPresent(ResponseField.class) &&\n                            key.equals(field.getAnnotation(ResponseField.class).value())) {\n                        field.setAccessible(true);\n                        matched = true;\n                        if (field.getType().equals(String.class)) {\n                            field.set(response, value);\n                        } else if (field.getType().equals(boolean.class)) {\n                            field.setBoolean(response, value.equals(\"1\"));\n                        } else if (field.getType().equals(long.class)) {\n                            field.setLong(response, Long.parseLong(value));\n                        } else if (field.getType().equals(int.class)) {\n                            field.setInt(response, Integer.parseInt(value));\n                        }\n                    }\n                }\n            } catch (Exception e) {\n                Log.w(TAG, e);\n            }\n            if (!matched) {\n                Log.w(TAG, \"Response line '\" + s + \"' not processed\");\n            }\n        }\n        for (Field field : tClass.getDeclaredFields()) {\n            if (field.isAnnotationPresent(ResponseHeader.class)) {\n                List<String> strings = headerFields.get(field.getAnnotation(ResponseHeader.class).value());\n                if (strings == null || strings.size() != 1) continue;\n                String value = strings.get(0);\n                try {\n                    field.setAccessible(true);\n                    if (field.getType().equals(String.class)) {\n                        field.set(response, value);\n                    } else if (field.getType().equals(boolean.class)) {\n                        field.setBoolean(response, value.equals(\"1\"));\n                    } else if (field.getType().equals(long.class)) {\n                        field.setLong(response, Long.parseLong(value));\n                    } else if (field.getType().equals(int.class)) {\n                        field.setInt(response, Integer.parseInt(value));\n                    }\n                } catch (Exception e) {\n                    Log.w(TAG, e);\n                }\n            }\n            if (field.isAnnotationPresent(ResponseStatusCode.class) && field.getType() == int.class) {\n                try {\n                    field.setAccessible(true);\n                    field.setInt(response, connection.getResponseCode());\n                } catch (IllegalAccessException e) {\n                    Log.w(TAG, e);\n                }\n            }\n            if (field.isAnnotationPresent(ResponseStatusText.class) && field.getType() == String.class) {\n                try {\n                    field.setAccessible(true);\n                    field.set(response, connection.getResponseMessage());\n                } catch (IllegalAccessException e) {\n                    Log.w(TAG, e);\n                }\n            }\n        }\n        return response;\n    }\n\n    public static <T> void requestAsync(final String url, final Request request, final Class<T> tClass,\n                                        final Callback<T> callback) {\n        new Thread(() -> {\n            try {\n                callback.onResponse(request(url, request, tClass));\n            } catch (Exception e) {\n                callback.onException(e);\n            }\n        }).start();\n    }\n\n    public static abstract class Request {\n        protected void prepare() {\n        }\n    }\n\n    public interface Callback<T> {\n        void onResponse(T response);\n\n        void onException(Exception exception);\n    }\n\n    @Retention(RetentionPolicy.RUNTIME)\n    @Target(ElementType.FIELD)\n    public @interface RequestHeader {\n        public String[] value();\n\n        public boolean truePresent() default true;\n\n        public boolean falsePresent() default false;\n\n        public boolean nullPresent() default false;\n    }\n\n    @Retention(RetentionPolicy.RUNTIME)\n    @Target(ElementType.FIELD)\n    public @interface RequestContent {\n        public String[] value();\n\n        public boolean truePresent() default true;\n\n        public boolean falsePresent() default false;\n\n        public boolean nullPresent() default false;\n    }\n\n    @Retention(RetentionPolicy.RUNTIME)\n    @Target(ElementType.FIELD)\n    public @interface RequestContentDynamic {\n    }\n\n    @Retention(RetentionPolicy.RUNTIME)\n    @Target(ElementType.FIELD)\n    public @interface ResponseField {\n        public String value();\n    }\n\n    @Retention(RetentionPolicy.RUNTIME)\n    @Target(ElementType.FIELD)\n    public @interface ResponseHeader {\n        public String value();\n    }\n\n    @Retention(RetentionPolicy.RUNTIME)\n    @Target(ElementType.FIELD)\n    public @interface ResponseStatusCode {\n    }\n\n    @Retention(RetentionPolicy.RUNTIME)\n    @Target(ElementType.FIELD)\n    public @interface ResponseStatusText {\n    }\n}\n"
  },
  {
    "path": "play-services-base/core/src/main/java/org/microg/gms/common/MultiListenerProxy.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.common;\n\nimport android.os.IInterface;\nimport android.util.Log;\n\nimport androidx.annotation.NonNull;\n\nimport java.lang.reflect.InvocationHandler;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Proxy;\nimport java.util.Collection;\nimport java.util.HashSet;\nimport java.util.Iterator;\n\npublic class MultiListenerProxy<T extends IInterface> implements InvocationHandler {\n    private static final String TAG = \"GmsMultiListener\";\n\n    public static <T extends IInterface> T get(Class<T> tClass, final Collection<T> listeners) {\n        return get(tClass, new CollectionListenerPool<T>(listeners));\n    }\n\n    public static <T extends IInterface> T get(Class<T> tClass, final ListenerPool<T> listenerPool) {\n        return (T) Proxy.newProxyInstance(tClass.getClassLoader(), new Class[]{tClass}, new MultiListenerProxy<T>(listenerPool));\n    }\n\n    private final ListenerPool<T> listeners;\n\n    private MultiListenerProxy(ListenerPool<T> listeners) {\n        this.listeners = listeners;\n    }\n\n    @Override\n    public Object invoke(Object proxy, Method method, Object[] args) {\n        for (T listener : new HashSet<T>(listeners)) {\n            try {\n                method.invoke(listener, args);\n            } catch (Exception e) {\n                Log.w(TAG, e);\n                listeners.remove(listener);\n            }\n        }\n        return null;\n    }\n\n    public static abstract class ListenerPool<T> implements Collection<T> {\n        @Override\n        public boolean addAll(Collection<? extends T> collection) {\n            return false;\n        }\n\n        @Override\n        public boolean add(T object) {\n            return false;\n        }\n\n        @Override\n        public boolean containsAll(Collection<?> collection) {\n            for (Object o : collection) {\n                if (!contains(o)) return false;\n            }\n            return true;\n        }\n\n        @Override\n        public boolean removeAll(Collection<?> collection) {\n            boolean x = true;\n            for (Object o : collection) {\n                if (!remove(o)) x = false;\n            }\n            return x;\n        }\n\n        @Override\n        public boolean retainAll(Collection<?> collection) {\n            return false;\n        }\n\n        @NonNull\n        @Override\n        public Object[] toArray() {\n            throw new IllegalArgumentException();\n        }\n\n        @NonNull\n        @Override\n        public <T1> T1[] toArray(T1[] array) {\n            throw new IllegalArgumentException();\n        }\n    }\n\n    private static class CollectionListenerPool<T> extends ListenerPool<T> {\n\n        private Collection<T> listeners;\n\n        public CollectionListenerPool(Collection<T> listeners) {\n            this.listeners = listeners;\n        }\n\n        @Override\n        public void clear() {\n            listeners.clear();\n        }\n\n        @Override\n        public boolean contains(Object object) {\n            return listeners.contains(object);\n        }\n\n        @Override\n        public boolean isEmpty() {\n            return listeners.isEmpty();\n        }\n\n        @NonNull\n        @Override\n        public Iterator<T> iterator() {\n            return listeners.iterator();\n        }\n\n        @Override\n        public boolean remove(Object object) {\n            return listeners.remove(object);\n        }\n\n        @Override\n        public int size() {\n            return listeners.size();\n        }\n    }\n\n    public static class MultiCollectionListenerPool<T> extends ListenerPool<T> {\n        private Collection<? extends Collection<T>> multiCol;\n\n        public MultiCollectionListenerPool(Collection<? extends Collection<T>> multiCol) {\n            this.multiCol = multiCol;\n        }\n\n        @Override\n        public void clear() {\n            for (Collection<T> ts : multiCol) {\n                ts.clear();\n            }\n        }\n\n        @Override\n        public boolean contains(Object object) {\n            for (Collection<T> ts : multiCol) {\n                if (ts.contains(object)) return true;\n            }\n            return false;\n        }\n\n        @Override\n        public boolean isEmpty() {\n            for (Collection<T> ts : multiCol) {\n                if (!ts.isEmpty()) return false;\n            }\n            return true;\n        }\n\n        @NonNull\n        @Override\n        public Iterator<T> iterator() {\n            final Iterator<? extends Collection<T>> interMed = multiCol.iterator();\n            return new Iterator<T>() {\n                private Iterator<T> med;\n\n                @Override\n                public boolean hasNext() {\n                    while ((med == null || !med.hasNext()) && interMed.hasNext()) {\n                        med = interMed.next().iterator();\n                    }\n                    return med != null && med.hasNext();\n                }\n\n                @Override\n                public T next() {\n                    while (med == null || !med.hasNext()) {\n                        med = interMed.next().iterator();\n                    }\n                    return med.next();\n                }\n\n                @Override\n                public void remove() {\n                    med.remove();\n                }\n            };\n        }\n\n        @Override\n        public boolean remove(Object object) {\n            for (Collection<T> ts : multiCol) {\n                if (ts.remove(object)) return true;\n            }\n            return false;\n        }\n\n        @Override\n        public int size() {\n            int sum = 0;\n            for (Collection<T> ts : multiCol) {\n                sum += ts.size();\n            }\n            return sum;\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-base/core/src/main/java/org/microg/gms/common/NonCancelToken.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.common;\n\nimport android.os.RemoteException;\n\nimport com.google.android.gms.common.internal.ICancelToken;\n\npublic class NonCancelToken extends ICancelToken.Stub {\n    @Override\n    public void cancel() throws RemoteException {\n\n    }\n}\n"
  },
  {
    "path": "play-services-base/core/src/main/java/org/microg/gms/common/NotOkayException.java",
    "content": "package org.microg.gms.common;\n\nimport java.io.IOException;\n\npublic class NotOkayException extends IOException {\n    public NotOkayException() {\n    }\n\n    public NotOkayException(String message) {\n        super(message);\n    }\n\n    public NotOkayException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n    public NotOkayException(Throwable cause) {\n        super(cause);\n    }\n}\n"
  },
  {
    "path": "play-services-base/core/src/main/java/org/microg/gms/common/PackageUtils.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.common;\n\nimport android.app.ActivityManager;\nimport android.app.Application;\nimport android.app.PendingIntent;\nimport android.content.Context;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.content.pm.Signature;\nimport android.os.Binder;\nimport android.util.Log;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport org.microg.gms.utils.ExtendedPackageInfo;\n\nimport java.lang.reflect.Method;\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport static android.os.Build.VERSION.SDK_INT;\nimport static org.microg.gms.common.Constants.GMS_PACKAGE_SIGNATURE_SHA1;\nimport static org.microg.gms.common.Constants.GMS_SECONDARY_PACKAGE_SIGNATURE_SHA1;\n\npublic class PackageUtils {\n\n    private static final String GOOGLE_PLATFORM_KEY = GMS_PACKAGE_SIGNATURE_SHA1;\n    private static final String GOOGLE_PLATFORM_KEY_2 = GMS_SECONDARY_PACKAGE_SIGNATURE_SHA1;\n    private static final String GOOGLE_APP_KEY = \"24bb24c05e47e0aefa68a58a766179d9b613a600\";\n    private static final String GOOGLE_LEGACY_KEY = \"58e1c4133f7441ec3d2c270270a14802da47ba0e\"; // Seems to be no longer used.\n    private static final String[] GOOGLE_PRIMARY_KEYS = {GOOGLE_PLATFORM_KEY, GOOGLE_PLATFORM_KEY_2, GOOGLE_APP_KEY};\n\n    @Deprecated\n    public static boolean isGooglePackage(@NonNull Context context, @Nullable String packageName) {\n        if (packageName == null) return false;\n        return new ExtendedPackageInfo(context, packageName).isGoogleOrPlatformPackage();\n    }\n\n    /**\n     * @deprecated Extended access is a deprecated concept\n     */\n    @Deprecated\n    public static boolean callerHasExtendedAccessPermission(@NonNull Context context) {\n        return context.checkCallingPermission(\"org.microg.gms.EXTENDED_ACCESS\") == PackageManager.PERMISSION_GRANTED;\n    }\n\n    public static void assertGooglePackagePermission(@NonNull Context context, GooglePackagePermission permission) {\n        try {\n            if (!callerHasGooglePackagePermission(context, permission))\n                throw new SecurityException(\"Access denied, missing google package permission for \" + permission.name());\n        } catch (SecurityException e) {\n            Log.w(\"ExtendedAccess\", e);\n            throw e;\n        }\n    }\n\n    public static boolean callerHasGooglePackagePermission(@NonNull Context context, GooglePackagePermission permission) {\n        for (String packageCandidate : getCallingPackageCandidates(context)) {\n            if (new ExtendedPackageInfo(context, packageCandidate).hasGooglePackagePermission(permission)) {\n                return true;\n            }\n        }\n\n        // TODO: Replace with explicit permission instead of generic \"extended access\"\n        if (callerHasExtendedAccessPermission(context)) return true;\n\n        return false;\n    }\n\n    public static void checkPackageUid(@NonNull Context context, @NonNull String packageName, int callingUid) {\n        getAndCheckPackage(context, packageName, callingUid, 0);\n    }\n\n    /**\n     * @deprecated We should stop using SHA-1 for certificate fingerprints!\n     */\n    @Deprecated\n    @Nullable\n    public static String firstSignatureDigest(@NonNull Context context, @Nullable String packageName) {\n        return firstSignatureDigest(context, packageName, false);\n    }\n\n    /**\n     * @deprecated We should stop using SHA-1 for certificate fingerprints!\n     */\n    @Deprecated\n    @Nullable\n    public static String firstSignatureDigest(@NonNull Context context, @Nullable String packageName, boolean useSigningInfo) {\n        return firstSignatureDigest(context.getPackageManager(), packageName, useSigningInfo);\n    }\n\n    /**\n     * @deprecated We should stop using SHA-1 for certificate fingerprints!\n     */\n    @Deprecated\n    @Nullable\n    public static String firstSignatureDigest(@NonNull PackageManager packageManager, @Nullable String packageName) {\n        return firstSignatureDigest(packageManager, packageName, false);\n    }\n\n    /**\n     * @deprecated We should stop using SHA-1 for certificate fingerprints!\n     */\n    @Deprecated\n    @Nullable\n    public static String firstSignatureDigest(@NonNull PackageManager packageManager, String packageName, boolean useSigningInfo) {\n        return bytesToSumString(firstSignatureDigestBytes(packageManager, packageName, useSigningInfo));\n    }\n\n    /**\n     * @deprecated We should stop using SHA-1 for certificate fingerprints!\n     */\n    @Deprecated\n    @Nullable\n    public static byte[] firstSignatureDigestBytes(@NonNull Context context, @Nullable String packageName) {\n        return firstSignatureDigestBytes(context.getPackageManager(), packageName);\n    }\n\n    /**\n     * @deprecated We should stop using SHA-1 for certificate fingerprints!\n     */\n    @Deprecated\n    @Nullable\n    public static byte[] firstSignatureDigestBytes(@NonNull PackageManager packageManager, @Nullable String packageName) {\n        return firstSignatureDigestBytes(packageManager, packageName, false);\n    }\n\n    /**\n     * @deprecated We should stop using SHA-1 for certificate fingerprints!\n     */\n    @Deprecated\n    @Nullable\n    public static byte[] firstSignatureDigestBytes(@NonNull PackageManager packageManager, @Nullable String packageName, boolean useSigningInfo) {\n        if (packageName == null) return null;\n        final PackageInfo info;\n        try {\n            info = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES | (useSigningInfo && SDK_INT >= 28 ? PackageManager.GET_SIGNING_CERTIFICATES : 0));\n        } catch (PackageManager.NameNotFoundException e) {\n            return null;\n        }\n        if (info == null) return null;\n        if (SDK_INT >= 28 && useSigningInfo && info.signingInfo != null) {\n            if (!info.signingInfo.hasMultipleSigners()) {\n                for (Signature sig : info.signingInfo.getSigningCertificateHistory()) {\n                    byte[] digest = sha1bytes(sig.toByteArray());\n                    if (digest != null) {\n                        return digest;\n                    }\n                }\n            }\n        }\n        if (info.signatures != null) {\n            for (Signature sig : info.signatures) {\n                byte[] digest = sha1bytes(sig.toByteArray());\n                if (digest != null) {\n                    return digest;\n                }\n            }\n        }\n        return null;\n    }\n\n    @Nullable\n    public static String getCallingPackage(@NonNull Context context) {\n        int callingUid = Binder.getCallingUid(), callingPid = Binder.getCallingPid();\n        String packageName = packageFromProcessId(context, callingPid);\n        if (packageName == null) {\n            packageName = firstPackageFromUserId(context, callingUid);\n        }\n        return packageName;\n    }\n\n    public static String[] getCallingPackageCandidates(@NonNull Context context) {\n        int callingUid = Binder.getCallingUid(), callingPid = Binder.getCallingPid();\n        String packageName = packageFromProcessId(context, callingPid);\n        if (packageName != null) return new String[]{packageName};\n        String[] candidates = context.getPackageManager().getPackagesForUid(callingUid);\n        if (candidates == null) return new String[0];\n        return candidates;\n    }\n\n    @Nullable\n    public static String getAndCheckCallingPackage(@NonNull Context context, @Nullable String suggestedPackageName) {\n        return getAndCheckCallingPackage(context, suggestedPackageName, 0);\n    }\n\n    @Nullable\n    public static String getAndCheckCallingPackageOrImpersonation(@NonNull Context context, @Nullable String suggestedPackageName) {\n        try {\n            return getAndCheckCallingPackage(context, suggestedPackageName, 0);\n        } catch (Exception e) {\n            if (callerHasGooglePackagePermission(context, GooglePackagePermission.IMPERSONATE)) {\n                return suggestedPackageName;\n            }\n            throw e;\n        }\n    }\n\n    @Nullable\n    public static String getAndCheckCallingPackage(@NonNull Context context, int suggestedCallerUid) {\n        return getAndCheckCallingPackage(context, null, suggestedCallerUid);\n    }\n\n    @Nullable\n    public static String getAndCheckCallingPackage(@NonNull Context context, @Nullable String suggestedPackageName, int suggestedCallerUid) {\n        return getAndCheckCallingPackage(context, suggestedPackageName, suggestedCallerUid, 0);\n    }\n\n    @Nullable\n    public static String getAndCheckCallingPackage(@NonNull Context context, @Nullable String suggestedPackageName, int suggestedCallerUid, int suggestedCallerPid) {\n        int callingUid = Binder.getCallingUid(), callingPid = Binder.getCallingPid();\n        if (suggestedCallerUid > 0 && suggestedCallerUid != callingUid) {\n            throw new SecurityException(\"suggested UID [\" + suggestedCallerUid + \"] and real calling UID [\" + callingUid + \"] mismatch!\");\n        }\n        if (suggestedCallerPid > 0 && suggestedCallerPid != callingPid) {\n            throw new SecurityException(\"suggested PID [\" + suggestedCallerPid + \"] and real calling PID [\" + callingPid + \"] mismatch!\");\n        }\n        return getAndCheckPackage(context, suggestedPackageName, callingUid, callingPid);\n    }\n\n    @Nullable\n    public static String getAndCheckPackage(Context context, String suggestedPackageName, int callingUid) {\n        return getAndCheckPackage(context, suggestedPackageName, callingUid, 0);\n    }\n\n    @Nullable\n    public static String getAndCheckPackage(@NonNull Context context, @Nullable String suggestedPackageName, int callingUid, int callingPid) {\n        String packageName = packageFromProcessId(context, callingPid);\n        if (packageName == null) {\n            String[] packagesForUid = context.getPackageManager().getPackagesForUid(callingUid);\n            if (packagesForUid != null && packagesForUid.length != 0) {\n                if (packagesForUid.length == 1) {\n                    packageName = packagesForUid[0];\n                } else if (Arrays.asList(packagesForUid).contains(suggestedPackageName)) {\n                    packageName = suggestedPackageName;\n                } else {\n                    packageName = packagesForUid[0];\n                }\n            }\n        }\n        if (packageName != null && suggestedPackageName != null && !packageName.equals(suggestedPackageName)) {\n            throw new SecurityException(\"UID [\" + callingUid + \"] is not related to packageName [\" + suggestedPackageName + \"] (seems to be \" + packageName + \")\");\n        }\n        return packageName;\n    }\n\n    @Nullable\n    @Deprecated\n    public static String packageFromProcessId(@NonNull Context context, int pid) {\n        ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);\n        if (manager == null) return null;\n        if (pid <= 0) return null;\n        List<ActivityManager.RunningAppProcessInfo> runningAppProcesses = manager.getRunningAppProcesses();\n        if (runningAppProcesses != null) {\n            for (ActivityManager.RunningAppProcessInfo processInfo : runningAppProcesses) {\n                if (processInfo.pid == pid && processInfo.pkgList.length == 1) {\n                    return processInfo.pkgList[0];\n                }\n            }\n        }\n        return null;\n    }\n\n    @Nullable\n    public static String firstPackageFromUserId(@NonNull Context context, int uid) {\n        String[] packagesForUid = context.getPackageManager().getPackagesForUid(uid);\n        if (packagesForUid != null && packagesForUid.length != 0) {\n            return packagesForUid[0];\n        }\n        return null;\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    public static String packageFromPendingIntent(@Nullable PendingIntent pi) {\n        if (pi == null) return null;\n        if (SDK_INT < 17) {\n            return pi.getTargetPackage();\n        } else {\n            return pi.getCreatorPackage();\n        }\n    }\n\n    public static String getProcessName() {\n        if (android.os.Build.VERSION.SDK_INT >= 28)\n            return Application.getProcessName();\n        try {\n            Class<?> activityThread = Class.forName(\"android.app.ActivityThread\");\n            String methodName = android.os.Build.VERSION.SDK_INT >= 18 ? \"currentProcessName\" : \"currentPackageName\";\n            Method getProcessName = activityThread.getDeclaredMethod(methodName);\n            return (String) getProcessName.invoke(null);\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public static boolean isPersistentProcess() {\n        String processName = getProcessName();\n        if (processName == null) {\n            Log.w(\"GmsPackageUtils\", \"Can't determine process name of current process\");\n            return false;\n        }\n        return processName.endsWith(\":persistent\");\n    }\n\n    public static boolean isMainProcess(Context context) {\n        String processName = getProcessName();\n        if (processName == null) {\n            Log.w(\"GmsPackageUtils\", \"Can't determine process name of current process\");\n            return false;\n        }\n        return processName.equals(context.getPackageName());\n    }\n\n    public static void warnIfNotPersistentProcess(Class<?> clazz) {\n        if (!isPersistentProcess()) {\n            Log.w(\"GmsPackageUtils\", clazz.getSimpleName() + \" initialized outside persistent process\", new RuntimeException());\n        }\n    }\n\n    public static void warnIfNotMainProcess(Context context, Class<?> clazz) {\n        if (!isMainProcess(context)) {\n            Log.w(\"GmsPackageUtils\", clazz.getSimpleName() + \" initialized outside main process\", new RuntimeException());\n        }\n    }\n\n    /**\n     * @deprecated We should stop using SHA-1 for certificate fingerprints!\n     */\n    @Deprecated\n    public static String sha1sum(byte[] bytes) {\n        return bytesToSumString(sha1bytes(bytes));\n    }\n\n    @Nullable\n    private static String bytesToSumString(@Nullable byte[] bytes) {\n        if (bytes == null) return null;\n        StringBuilder sb = new StringBuilder(2 * bytes.length);\n        for (byte b : bytes) {\n            sb.append(String.format(\"%02x\", b));\n        }\n        return sb.toString();\n    }\n\n    /**\n     * @deprecated We should stop using SHA-1 for certificate fingerprints!\n     */\n    @Deprecated\n    public static byte[] sha1bytes(byte[] bytes) {\n        MessageDigest md;\n        try {\n            md = MessageDigest.getInstance(\"SHA1\");\n        } catch (final NoSuchAlgorithmException e) {\n            return null;\n        }\n        if (md != null) {\n            return md.digest(bytes);\n        }\n        return null;\n    }\n\n    @Deprecated\n    public static int versionCode(Context context, String packageName) {\n        return new ExtendedPackageInfo(context, packageName).getShortVersionCode();\n    }\n\n    @Deprecated\n    public static String versionName(Context context, String packageName) {\n        return new ExtendedPackageInfo(context, packageName).getVersionName();\n    }\n\n    @Deprecated\n    public static int targetSdkVersion(Context context, String packageName) {\n        return new ExtendedPackageInfo(context, packageName).getTargetSdkVersion();\n    }\n}\n"
  },
  {
    "path": "play-services-base/core/src/main/java/org/microg/gms/common/PhoneInfo.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.common;\n\nimport java.util.Random;\n\npublic class PhoneInfo {\n    public String cellOperator = \"26207\";\n    public String roaming = \"mobile-notroaming\";\n    public String simOperator = \"26207\";\n    public String imsi = randomImsi();\n\n    private String randomImsi() {\n        Random random = new Random();\n        StringBuilder sb = new StringBuilder(simOperator);\n        while (sb.length() < 15) {\n            sb.append(random.nextInt(10));\n        }\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "play-services-base/core/src/main/java/org/microg/gms/common/RemoteListenerProxy.java",
    "content": "/*\n * Copyright (C) 2013-2019 microG Project Team\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 org.microg.gms.common;\n\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.ServiceConnection;\nimport android.content.pm.ResolveInfo;\nimport android.os.IBinder;\nimport android.os.IInterface;\nimport android.util.Log;\n\nimport java.lang.reflect.InvocationHandler;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Proxy;\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class RemoteListenerProxy<T extends IInterface> implements ServiceConnection, InvocationHandler {\n    private static final String TAG = \"GmsRemoteListener\";\n    private final Context context;\n    private final Intent searchIntent;\n    private final String bindAction;\n    private IBinder remote;\n    private boolean connecting;\n    private List<Runnable> waiting = new ArrayList<Runnable>();\n    private Class<T> tClass;\n\n    public static <T extends IInterface> T get(Context context, Intent intent, Class<T> tClass, String bindAction) {\n        return (T) Proxy.newProxyInstance(tClass.getClassLoader(), new Class[]{tClass},\n                new RemoteListenerProxy<T>(context, intent, tClass, bindAction));\n    }\n\n    private RemoteListenerProxy(Context context, Intent intent, Class<T> tClass, String bindAction) {\n        this.context = context;\n        this.searchIntent = intent;\n        this.tClass = tClass;\n        this.bindAction = bindAction;\n    }\n\n    private boolean connect() {\n        synchronized (this) {\n            if (!connecting) {\n                try {\n                    ResolveInfo resolveInfo = context.getPackageManager().resolveService(searchIntent, 0);\n                    if (resolveInfo != null) {\n                        Intent intent = new Intent(bindAction);\n                        intent.setPackage(resolveInfo.serviceInfo.packageName);\n                        intent.setClassName(resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name);\n                        connecting = context.bindService(intent, this, Context.BIND_AUTO_CREATE);\n                        if (!connecting) Log.d(TAG, \"Could not connect to: \" + intent);\n                        return connecting;\n                    }\n                    return false;\n                } catch (Exception e) {\n                    Log.w(TAG, e);\n                }\n            }\n            return true;\n        }\n    }\n\n    private void runOncePossible(Runnable runnable) {\n        synchronized (this) {\n            if (remote == null) {\n                waiting.add(runnable);\n            } else {\n                runnable.run();\n            }\n        }\n    }\n\n    @Override\n    public void onServiceConnected(ComponentName name, IBinder service) {\n        synchronized (this) {\n            remote = service;\n            if (!waiting.isEmpty()) {\n                try {\n                    for (Runnable runnable : waiting) {\n                        runnable.run();\n                    }\n                } catch (Exception e) {\n                }\n                waiting.clear();\n                try {\n                    context.unbindService(RemoteListenerProxy.this);\n                } catch (Exception e) {\n                }\n                connecting = false;\n                remote = null;\n            }\n        }\n    }\n\n    @Override\n    public void onServiceDisconnected(ComponentName name) {\n        synchronized (this) {\n            remote = null;\n        }\n    }\n\n    @Override\n    public Object invoke(Object proxy, final Method method, final Object[] args) throws Throwable {\n        if (method.getDeclaringClass().equals(tClass)) {\n            runOncePossible(new Runnable() {\n                @Override\n                public void run() {\n                    try {\n                        Object asInterface = Class.forName(tClass.getName() + \"$Stub\").getMethod(\"asInterface\", IBinder.class).invoke(null, remote);\n                        method.invoke(asInterface, args);\n                    } catch (Exception e) {\n                        Log.w(TAG, e);\n                    }\n                }\n            });\n            connect();\n            return null;\n        } else if (method.getDeclaringClass().equals(Object.class)) {\n            return method.invoke(this, args);\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "play-services-base/core/src/main/java/org/microg/gms/common/Utils.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.common;\n\nimport android.content.Context;\nimport android.util.Log;\nimport android.widget.Toast;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Locale;\n\nimport static android.content.pm.PackageManager.PERMISSION_GRANTED;\n\npublic class Utils {\n\n    public static Locale getLocale(Context context) {\n        return Locale.getDefault(); // TODO\n    }\n\n    public static DeviceIdentifier getDeviceIdentifier(Context context) {\n        return new DeviceIdentifier();\n    }\n\n    public static PhoneInfo getPhoneInfo(Context context) {\n        return new PhoneInfo();\n    }\n\n    public static boolean hasSelfPermissionOrNotify(Context context, String permission) {\n        if (context.checkCallingOrSelfPermission(permission) != PERMISSION_GRANTED) {\n            Log.w(\"GmsUtils\", \"Lacking permission to \" + permission + \" for pid:\" + android.os.Process.myPid() + \" uid:\" + android.os.Process.myUid());\n            try {\n                //TODO: Toast.makeText(context, context.getString(R.string.lacking_permission_toast, permission), Toast.LENGTH_SHORT).show();\n            } catch (RuntimeException e) {\n            }\n            return false;\n        }\n        return true;\n    }\n\n    public static byte[] readStreamToEnd(final InputStream is) throws IOException {\n        final ByteArrayOutputStream bos = new ByteArrayOutputStream();\n        if (is != null) {\n            final byte[] buff = new byte[1024];\n            int read;\n            do {\n                bos.write(buff, 0, (read = is.read(buff)) < 0 ? 0 : read);\n            } while (read >= 0);\n            is.close();\n        }\n        return bos.toByteArray();\n    }\n}\n"
  },
  {
    "path": "play-services-base/core/src/main/kotlin/org/microg/gms/auth/AuthPrefs.kt",
    "content": "package org.microg.gms.auth\n\nimport android.content.Context\nimport org.microg.gms.settings.SettingsContract\nimport org.microg.gms.settings.SettingsContract.Auth\n\nobject AuthPrefs {\n\n    @JvmStatic\n    fun isTrustGooglePermitted(context: Context): Boolean {\n        return SettingsContract.getSettings(context, Auth.getContentUri(context), arrayOf(Auth.TRUST_GOOGLE)) { c ->\n            c.getInt(0) != 0\n        }\n    }\n\n    @JvmStatic\n    fun isAuthVisible(context: Context): Boolean {\n        return SettingsContract.getSettings(context, Auth.getContentUri(context), arrayOf(Auth.VISIBLE)) { c ->\n            c.getInt(0) != 0\n        }\n    }\n\n    @JvmStatic\n    fun shouldIncludeAndroidId(context: Context): Boolean {\n        return SettingsContract.getSettings(context, Auth.getContentUri(context), arrayOf(Auth.INCLUDE_ANDROID_ID)) { c ->\n            c.getInt(0) != 0\n        }\n    }\n\n    @JvmStatic\n    fun shouldStripDeviceName(context: Context): Boolean {\n        return SettingsContract.getSettings(context, Auth.getContentUri(context), arrayOf(Auth.STRIP_DEVICE_NAME)) { c ->\n            c.getInt(0) != 0\n        }\n    }\n\n    @JvmStatic\n    fun shouldReceiveTwoStepVerification(context: Context): Boolean {\n        return SettingsContract.getSettings(context, Auth.getContentUri(context), arrayOf(Auth.TWO_STEP_VERIFICATION)) { c ->\n            c.getInt(0) != 0\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-base/core/src/main/kotlin/org/microg/gms/checkin/LastCheckinInfo.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.checkin\n\nimport android.content.Context\nimport org.microg.gms.settings.SettingsContract\n\ndata class LastCheckinInfo(\n    val lastCheckin: Long,\n    val androidId: Long,\n    val securityToken: Long,\n    val digest: String,\n    val versionInfo: String,\n    val deviceDataVersionInfo: String,\n) {\n\n    constructor(r: CheckinResponse) : this(\n        lastCheckin = r.timeMs ?: 0L,\n        androidId = r.androidId ?: 0L,\n        securityToken = r.securityToken ?: 0L,\n        digest = r.digest ?: SettingsContract.CheckIn.INITIAL_DIGEST,\n        versionInfo = r.versionInfo ?: \"\",\n        deviceDataVersionInfo = r.deviceDataVersionInfo ?: \"\",\n    )\n\n    companion object {\n        @JvmStatic\n        fun read(context: Context): LastCheckinInfo {\n            val projection = arrayOf(\n                SettingsContract.CheckIn.ANDROID_ID,\n                SettingsContract.CheckIn.DIGEST,\n                SettingsContract.CheckIn.LAST_CHECK_IN,\n                SettingsContract.CheckIn.SECURITY_TOKEN,\n                SettingsContract.CheckIn.VERSION_INFO,\n                SettingsContract.CheckIn.DEVICE_DATA_VERSION_INFO,\n            )\n            return SettingsContract.getSettings(\n                context,\n                SettingsContract.CheckIn.getContentUri(context),\n                projection\n            ) { c ->\n                LastCheckinInfo(\n                    androidId = c.getLong(0),\n                    digest = c.getString(1),\n                    lastCheckin = c.getLong(2),\n                    securityToken = c.getLong(3),\n                    versionInfo = c.getString(4),\n                    deviceDataVersionInfo = c.getString(5),\n                )\n            }\n        }\n\n        @JvmStatic\n        fun clear(context: Context) =\n            SettingsContract.setSettings(context, SettingsContract.CheckIn.getContentUri(context)) {\n                put(SettingsContract.CheckIn.ANDROID_ID, 0L)\n                put(SettingsContract.CheckIn.DIGEST, SettingsContract.CheckIn.INITIAL_DIGEST)\n                put(SettingsContract.CheckIn.LAST_CHECK_IN, 0L)\n                put(SettingsContract.CheckIn.SECURITY_TOKEN, 0L)\n                put(SettingsContract.CheckIn.VERSION_INFO, \"\")\n                put(SettingsContract.CheckIn.DEVICE_DATA_VERSION_INFO, \"\")\n            }\n    }\n\n    fun write(context: Context) =\n        SettingsContract.setSettings(context, SettingsContract.CheckIn.getContentUri(context)) {\n            put(SettingsContract.CheckIn.ANDROID_ID, androidId)\n            put(SettingsContract.CheckIn.DIGEST, digest)\n            put(SettingsContract.CheckIn.LAST_CHECK_IN, lastCheckin)\n            put(SettingsContract.CheckIn.SECURITY_TOKEN, securityToken)\n            put(SettingsContract.CheckIn.VERSION_INFO, versionInfo)\n            put(SettingsContract.CheckIn.DEVICE_DATA_VERSION_INFO, deviceDataVersionInfo)\n        }\n}"
  },
  {
    "path": "play-services-base/core/src/main/kotlin/org/microg/gms/common/AccountUtils.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.common\n\nimport android.accounts.Account\nimport android.annotation.SuppressLint\nimport android.content.Context\nimport android.content.Context.MODE_PRIVATE\nimport androidx.core.content.edit\nimport org.microg.gms.auth.AuthConstants\n\nclass AccountUtils(val context: Context) {\n\n    private val prefs = context.getSharedPreferences(\"common.selected_account_prefs\", MODE_PRIVATE)\n\n    companion object {\n        private const val TYPE = \"selected_account_type:\"\n        @SuppressLint(\"StaticFieldLeak\")\n        @Volatile\n        private var instance: AccountUtils? = null\n        fun get(context: Context): AccountUtils = instance ?: synchronized(this) {\n            instance ?: AccountUtils(context.applicationContext).also { instance = it }\n        }\n    }\n\n    fun saveSelectedAccount(packageName: String, account: Account?) {\n        if (account != null) {\n            prefs.edit(true) {\n                putString(packageName, account.name)\n                putString(TYPE.plus(packageName), account.type)\n            }\n        }\n    }\n\n    fun getSelectedAccount(packageName: String): Account? {\n        val name = prefs.getString(packageName, null) ?: return null\n        val type = prefs.getString(TYPE.plus(packageName), AuthConstants.DEFAULT_ACCOUNT_TYPE) ?: return null\n        return Account(name, type)\n    }\n\n    fun removeSelectedAccount(packageName: String) {\n        prefs.edit {\n            remove(packageName)\n            remove(TYPE.plus(packageName))\n        }\n    }\n}"
  },
  {
    "path": "play-services-base/core/src/main/kotlin/org/microg/gms/common/DeviceConfigProto.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.common\n\nimport org.microg.gms.checkin.DeviceConfig\n\nfun DeviceConfiguration.asProto(): DeviceConfig = DeviceConfig(\n    availableFeature = availableFeatures,\n    densityDpi = densityDpi,\n    glEsVersion = glEsVersion,\n    glExtension = glExtensions,\n    hasFiveWayNavigation = hasFiveWayNavigation,\n    hasHardKeyboard = hasHardKeyboard,\n    heightPixels = heightPixels,\n    keyboardType = keyboardType,\n    locale = locales,\n    nativePlatform = nativePlatforms,\n    navigation = navigation,\n    screenLayout = screenLayout,\n    sharedLibrary = sharedLibraries,\n    touchScreen = touchScreen,\n    widthPixels = widthPixels\n)"
  },
  {
    "path": "play-services-base/core/src/main/kotlin/org/microg/gms/common/KnownGooglePackages.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.common\n\nimport com.google.android.gms.common.internal.CertData\nimport org.microg.gms.common.GooglePackagePermission.*\nimport org.microg.gms.utils.digest\nimport org.microg.gms.utils.toHexString\n\nenum class GooglePackagePermission {\n    ACCOUNT, // Find accounts\n    AD_ID, // Advertising ID\n    APP_CERT, // Receive certificate confirming valid app installation (incl. Spatula)\n    AUTH, // Sign in to Google account without user interface confirmation\n    CREDENTIALS, // Access to credentials\n    GAMES, // Google Play Games first party access\n    IMPERSONATE, // Allow to act as another package\n    OWNER, // Details about own accounts (name, email, photo)\n    PEOPLE, // Details about contacts\n    REPORTING, // Access reporting service\n    SAFETYNET, // Access SafetyNet UUID\n    WALLET,\n}\n\n// These are SHA-256 hashes of the Google privileged signing certificates\nprivate val KNOWN_GOOGLE_PRIVILEGED_CERT_HASHES = listOf(\n    \"f0fd6c5b410f25cb25c3b53346c8972fae30f8ee7411df910480ad6b2d60db83\",\n    \"7ce83c1b71f3d572fed04c8d40c5cb10ff75e6d87d9df6fbd53f0468c2905053\",\n)\n\n// These are the permissions that we grant to apps signed with a Google\n// privileged platform signing certificate. Those could be in the same\n// shared UID on regular Play Services and thus have full access by\n// design, as they could even directly access all private details in GMS.\nprivate val PERMISSIONS_PRIVILEGED = GooglePackagePermission.entries.toSet()\n\n// These are SHA-256 hashes of signing certificates used by official Google apps\n// Signing certificates that are only used for a small number of apps are likely not\n// official Google apps, but either acquisitions or independent teams / projects\n// within Google. We don't put them here, but via KNOWN_GOOGLE_PACKAGES.\nprivate val KNOWN_GOOGLE_APP_CERT_HASHES = listOf(\n    \"3d7a1223019aa39d9ea0e3436ab7c0896bfb4fb679f4de5fe7c23f326c8f994a\"\n)\n\n// This is a subset of permissions that we grant to apps signed with an official\n// Google apps certificate. Note that this has lower priority than the\n// KNOWN_GOOGLE_PACKAGES list, so if any app needs more permissions than this,\n// this can be handled through KNOWN_GOOGLE_PACKAGES.\nprivate val PERMISSIONS_APP = setOf(ACCOUNT, APP_CERT, AUTH, OWNER, PEOPLE, REPORTING, SAFETYNET)\n\nprivate const val SHA1 = \"SHA1\"\nprivate const val SHA256 = \"SHA-256\"\n\ndata class PackageAndCertHash(val packageName: String, val algorithm: String, val certHash: String)\n\nprivate val KNOWN_GOOGLE_PACKAGES = mapOf(\n    // Legacy set\n    // These include all previously KNOWN_GOOGLE_PACKAGES and grant them all google package permissions\n    // Those should be replaced by new entries that\n    // - use SHA-256 instead of SHA-1\n    // - has more accurate permission set (in most cases, ACCOUNT+AUTH+OWNER is sufficient)\n    Pair(\n        PackageAndCertHash(\"com.google.android.apps.classroom\", SHA1, \"46f6c8987311e131f4f558d8e0ae145bebab6da3\"),\n        PERMISSIONS_PRIVILEGED\n    ),\n    Pair(\n        PackageAndCertHash(\"com.google.android.apps.inbox\", SHA1, \"aa87ce1260c008d801197bb4ecea4ab8929da246\"),\n        PERMISSIONS_PRIVILEGED\n    ),\n    Pair(\n        PackageAndCertHash(\"com.google.android.apps.playconsole\", SHA1, \"d6c35e55b481aefddd74152ca7254332739a81d6\"),\n        PERMISSIONS_PRIVILEGED\n    ),\n    Pair(\n        PackageAndCertHash(\"com.google.android.apps.travel.onthego\", SHA1, \"0cbe08032217d45e61c0bc72f294395ee9ecb5d5\"),\n        PERMISSIONS_PRIVILEGED\n    ),\n    Pair(\n        PackageAndCertHash(\"com.google.android.apps.tycho\", SHA1, \"01b844184e360686aa98b48eb16e05c76d4a72ad\"),\n        PERMISSIONS_PRIVILEGED\n    ),\n    Pair(\n        PackageAndCertHash(\"com.google.android.contacts\", SHA1, \"ee3e2b5d95365c5a1ccc2d8dfe48d94eb33b3ebe\"),\n        PERMISSIONS_PRIVILEGED\n    ),\n    Pair(\n        PackageAndCertHash(\"com.google.android.wearable.app\", SHA1, \"a197f9212f2fed64f0ff9c2a4edf24b9c8801c8c\"),\n        PERMISSIONS_PRIVILEGED\n    ),\n    Pair(\n        PackageAndCertHash(\"com.google.android.apps.youtube.music\", SHA1, \"afb0fed5eeaebdd86f56a97742f4b6b33ef59875\"),\n        PERMISSIONS_PRIVILEGED\n    ),\n    Pair(\n        PackageAndCertHash(\"com.google.android.vr.home\", SHA1, \"fc1edc68f7e3e4963c998e95fc38f3de8d1bfc96\"),\n        PERMISSIONS_PRIVILEGED\n    ),\n    Pair(\n        PackageAndCertHash(\"com.google.vr.cyclops\", SHA1, \"188c5ca3863fa121216157a5baa80755ceda70ab\"),\n        PERMISSIONS_PRIVILEGED\n    ),\n    Pair(\n        PackageAndCertHash(\"com.waze\", SHA1, \"35b438fe1bc69d975dc8702dc16ab69ebf65f26f\"),\n        PERMISSIONS_PRIVILEGED\n    ),\n    Pair(\n        PackageAndCertHash(\"com.google.android.apps.wellbeing\", SHA1, \"4ebdd02380f1fa0b6741491f0af35625dba76e9f\"),\n        PERMISSIONS_PRIVILEGED\n    ),\n    Pair(\n        PackageAndCertHash(\"com.google.android.apps.village.boond\", SHA1, \"48e7985b8f901df335b5d5223579c81618431c7b\"),\n        PERMISSIONS_PRIVILEGED\n    ),\n    Pair(\n        PackageAndCertHash(\"com.google.android.apps.subscriptions.red\", SHA1, \"de8304ace744ae4c4e05887a27a790815e610ff0\"),\n        PERMISSIONS_PRIVILEGED\n    ),\n    Pair(\n        PackageAndCertHash(\"com.google.android.apps.meetings\", SHA1, \"47a6936b733dbdb45d71997fbe1d610eca36b8bf\"),\n        PERMISSIONS_PRIVILEGED\n    ),\n    Pair(\n        PackageAndCertHash(\"com.google.android.apps.nbu.paisa.user\", SHA1, \"80df78bb700f9172bc671779b017ddefefcbf552\"),\n        PERMISSIONS_PRIVILEGED\n    ),\n    Pair(\n        PackageAndCertHash(\"com.google.android.apps.dynamite\", SHA1, \"519c5a17a60596e6fe5933b9cb4285e7b0e5eb7b\"),\n        PERMISSIONS_PRIVILEGED\n    ),\n    Pair(\n        PackageAndCertHash(\"com.google.android.projection.gearhead\", SHA1, \"9ca91f9e704d630ef67a23f52bf1577a92b9ca5d\"),\n        PERMISSIONS_PRIVILEGED\n    ),\n    Pair(\n        PackageAndCertHash(\"com.google.stadia.android\", SHA1, \"133aad3b3d3b580e286573c37f20549f9d3d1cce\"),\n        PERMISSIONS_PRIVILEGED\n    ),\n    Pair(\n        PackageAndCertHash(\"com.google.android.apps.kids.familylink\", SHA1, \"88652b8464743e5ce80da0d4b890d13f9b1873df\"),\n        PERMISSIONS_PRIVILEGED\n    ),\n    Pair(\n        PackageAndCertHash(\"com.google.android.apps.walletnfcrel\", SHA1, \"82759e2db43f9ccbafce313bc674f35748fabd7a\"),\n        PERMISSIONS_PRIVILEGED\n    ),\n    Pair(\n        PackageAndCertHash(\"com.google.android.apps.recorder\", SHA1, \"394d84cd2cf89d3453702c663f98ec6554afc3cd\"),\n        PERMISSIONS_PRIVILEGED\n    ),\n    Pair(\n        PackageAndCertHash(\"com.google.android.apps.messaging\", SHA1, \"0980a12be993528c19107bc21ad811478c63cefc\"),\n        PERMISSIONS_PRIVILEGED\n    ),\n    Pair(\n        PackageAndCertHash(\"com.google.android.apps.tachyon\", SHA1, \"a0bc09af527b6397c7a9ef171d6cf76f757becc3\"),\n        PERMISSIONS_PRIVILEGED\n    ),\n    Pair(\n        PackageAndCertHash(\"com.google.android.apps.access.wifi.consumer\", SHA1,\"d850379540d68fbec82a742ab6a8321a3f9a4c7c\"),\n        PERMISSIONS_PRIVILEGED\n    ),\n\n    // Google Jamboard\n    Pair(\n        PackageAndCertHash(\"com.google.android.apps.jam\", SHA256, \"9db7ff389ab6a30d5f5c92a8629ff0baa93fa8430f0503c04d72640a1cf323f5\"),\n        setOf(ACCOUNT, AUTH, OWNER)\n    ),\n\n    // Fitbit\n    Pair(\n        PackageAndCertHash(\"com.fitbit.FitbitMobile\", SHA256, \"fa6a198803aac1939fed6bab9295e5184c00966bf912f8c5faff26576cc770ff\"),\n        setOf(ACCOUNT, AUTH, OWNER)\n    ),\n\n    // Google Tasks\n    Pair(\n        PackageAndCertHash(\"com.google.android.apps.tasks\", SHA256, \"99f6cc5308e6f3318a3bf168bf106d5b5defe2b4b9c561e5ddd7924a7a2ba1e2\"),\n        setOf(ACCOUNT, AUTH, OWNER)\n    ),\n\n    // Google familylink\n    Pair(\n        PackageAndCertHash(\"com.google.android.apps.kids.familylink\", SHA256, \"6b58bb84c1c6d081d950448ff5c051a34769d7fd8d415452c86efeb808716c0e\"),\n        setOf(ACCOUNT, AUTH, OWNER)\n    ),\n\n    // Google Kids home\n    Pair(\n        PackageAndCertHash(\"com.google.android.apps.kids.home\", SHA256, \"8f7bd4c5c0273a1a0dd6b3bfa8cc8e9f980a25108adcfd7be9962e8ae9feeb6f\"),\n        setOf(ACCOUNT, AUTH, OWNER)\n    ),\n\n    // Google GFiber\n    Pair(\n        PackageAndCertHash(\"com.google.android.apps.fiber.myfiber\", SHA256, \"4a853c50adda4406495652fe78f32252757c8dd761f3601a7b2e0df86291429d\"),\n        setOf(ACCOUNT, AUTH, OWNER)\n    ),\n\n    // Google NotebookLM\n    Pair(\n        PackageAndCertHash(\"com.google.android.apps.labs.language.tailwind\", SHA256, \"ba49176908275f83be9ae1034968f0b18e65177a64e5a40b3a621f148dfb6fa2\"),\n        setOf(ACCOUNT, AUTH, OWNER)\n    ),\n\n    // Waymo\n    Pair(\n        PackageAndCertHash(\"com.waymo.carapp\", SHA256, \"c600dafe48f6ee770dd814261bd4b64708bc19dd014322107b58e836d8f2634e\"),\n        setOf(ACCOUNT, AUTH, OWNER)\n    ),\n)\n\nfun isGooglePackage(pkg: PackageAndCertHash): Boolean {\n    if (pkg.algorithm == SHA256 && pkg.certHash in KNOWN_GOOGLE_PRIVILEGED_CERT_HASHES) return true\n    if (pkg.algorithm == SHA256 && pkg.certHash in KNOWN_GOOGLE_APP_CERT_HASHES) return true\n    return KNOWN_GOOGLE_PACKAGES.containsKey(pkg)\n}\nfun getGooglePackagePermissions(pkg: PackageAndCertHash): Set<GooglePackagePermission> {\n    if (KNOWN_GOOGLE_PACKAGES.containsKey(pkg)) return KNOWN_GOOGLE_PACKAGES[pkg].orEmpty()\n    if (pkg.algorithm == SHA256 && pkg.certHash in KNOWN_GOOGLE_PRIVILEGED_CERT_HASHES) return PERMISSIONS_PRIVILEGED\n    if (pkg.algorithm == SHA256 && pkg.certHash in KNOWN_GOOGLE_APP_CERT_HASHES) return PERMISSIONS_APP\n    return emptySet()\n}\nfun hasGooglePackagePermission(pkg: PackageAndCertHash, permission: GooglePackagePermission) = getGooglePackagePermissions(pkg).contains(permission)\n\nfun isGooglePackage(packageName: String, certificate: CertData): Boolean =\n    listOf(SHA1, SHA256).any { isGooglePackage(PackageAndCertHash(packageName, it, certificate.digest(it).toHexString())) }"
  },
  {
    "path": "play-services-base/core/src/main/kotlin/org/microg/gms/crossprofile/CrossProfileRequestActivity.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.crossprofile\n\nimport android.app.Activity\nimport android.content.Intent\nimport android.content.pm.CrossProfileApps\nimport android.os.Bundle\nimport android.os.UserManager\nimport android.util.Log\nimport androidx.annotation.RequiresApi\nimport org.microg.gms.settings.SettingsContract.CROSS_PROFILE_PERMISSION\nimport org.microg.gms.settings.SettingsContract.CROSS_PROFILE_SHARED_PREFERENCES_NAME\nimport androidx.core.content.edit\n\n/**\n * Two-step process:\n *   1. request to hear back from `CrossProfileRequestActivity`\n *   2. receive resulting URI as intent data\n *\n * This dance so complicated because Android platform does not offer better APIs that only need\n * `INTERACT_ACROSS_PROFILES`, an appops permission (and not `INTERACT_ACROSS_USERS`, a\n * privileged|system permission).\n */\n@RequiresApi(30)\nclass CrossProfileRequestActivity : Activity() {\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n\n        // Check that we are work profile\n        val userManager = getSystemService(UserManager::class.java)\n        if (!userManager.isManagedProfile) {\n            Log.w(CrossProfileSendActivity.TAG, \"I was asked to send a cross-profile request, but I am not on a work profile!\")\n            finish()\n            return\n        }\n\n        val crossProfileApps = getSystemService(CrossProfileApps::class.java)\n\n        val targetProfiles = crossProfileApps.targetUserProfiles\n\n        if (!crossProfileApps.canInteractAcrossProfiles() || targetProfiles.isEmpty()) {\n            Log.w(\n                TAG, \"I am supposed to send a cross-profile request, but the prerequisites are not met: \" +\n                        \"can interact = ${crossProfileApps.canInteractAcrossProfiles()}, \" +\n                        \"#targetProfiles = ${targetProfiles.size}\")\n            finish()\n            return\n        }\n\n        val intent = Intent(this, CrossProfileSendActivity::class.java)\n\n        Log.d(TAG, \"asking for cross-profile URI\")\n        crossProfileApps.startActivity(\n            intent,\n            targetProfiles.first(),\n            // if this parameter is provided, it works like `startActivityForResult` (with requestCode 0)\n            this\n        )\n\n        // finish only after receiving result\n    }\n\n    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {\n        Log.d(TAG, data?.data.toString())\n\n        val uri = data?.data\n        if (uri == null) {\n            Log.w(TAG, \"expected to receive data, but intent did not contain any.\")\n            finish()\n            return\n        }\n\n        contentResolver.takePersistableUriPermission(uri, 0)\n\n        val preferences = getSharedPreferences(CROSS_PROFILE_SHARED_PREFERENCES_NAME, MODE_PRIVATE)\n        Log.i(TAG, \"storing work URI\")\n        preferences.edit { putString(CROSS_PROFILE_PERMISSION, uri.toString()) }\n\n        finish()\n    }\n\n    companion object {\n        const val TAG = \"GmsCrossProfileRequest\"\n    }\n}"
  },
  {
    "path": "play-services-base/core/src/main/kotlin/org/microg/gms/crossprofile/CrossProfileSendActivity.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.crossprofile\n\nimport android.app.Activity\nimport android.content.Intent\nimport android.content.Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION\nimport android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION\nimport android.content.pm.CrossProfileApps\nimport android.os.Bundle\nimport android.os.UserManager\nimport android.util.Log\nimport androidx.annotation.RequiresApi\nimport androidx.core.net.toUri\nimport org.microg.gms.settings.SettingsContract.getAuthority\n\n@RequiresApi(30)\nclass CrossProfileSendActivity : Activity() {\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n\n        // Check that we are primary profile\n        val userManager = getSystemService(UserManager::class.java)\n        if (userManager.isManagedProfile) {\n            Log.w(TAG, \"Cross-profile send request was received on work profile!\")\n            finish()\n            return\n        }\n\n        // Check prerequisites\n        val crossProfileApps = getSystemService(CrossProfileApps::class.java)\n        val targetProfiles = crossProfileApps.targetUserProfiles\n\n        if (!crossProfileApps.canInteractAcrossProfiles() || targetProfiles.isEmpty()) {\n            Log.w(\n                TAG, \"received cross-profile request, but I believe I cannot answer, as prerequisites are not met: \" +\n                    \"can interact = ${crossProfileApps.canInteractAcrossProfiles()}, \" +\n                    \"#targetProfiles = ${targetProfiles.size}. Note that this is expected during initial setup of a work profile.\")\n        }\n\n        // Respond\n        Log.d(TAG, \"responding to cross-profile request\")\n\n        setResult(1, Intent().apply {\n            setData(\"content://${getAuthority(this@CrossProfileSendActivity)}\".toUri())\n            addFlags(FLAG_GRANT_READ_URI_PERMISSION or FLAG_GRANT_PERSISTABLE_URI_PERMISSION)\n        })\n        finish()\n    }\n\n    companion object {\n        const val TAG = \"GmsCrossProfileSend\"\n    }\n}"
  },
  {
    "path": "play-services-base/core/src/main/kotlin/org/microg/gms/crossprofile/UserInitReceiver.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.crossprofile\n\nimport android.annotation.SuppressLint\nimport android.content.BroadcastReceiver\nimport android.content.Context\nimport android.content.Intent\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.UserManager\nimport android.util.Log\n\nclass UserInitReceiver : BroadcastReceiver() {\n    @SuppressLint(\"UnsafeProtectedBroadcastReceiver\") // exported=\"false\"\n    override fun onReceive(context: Context, intent: Intent?) {\n\n        // Check that we are work profile\n        if (SDK_INT >= 30) {\n            val userManager = context.getSystemService(UserManager::class.java)\n            if (userManager.isManagedProfile) {\n                Log.d(TAG, \"A new managed profile is being initialized; telling `CrossProfileRequestActivity` to request access to main profile's data.\")\n                // CrossProfileActivity will check whether permissions are present\n                context.startActivity(\n                    Intent(context, CrossProfileRequestActivity::class.java).apply {\n                        addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)\n                    }\n                )\n            } else {\n                Log.d(TAG, \"A new user is being initialized, but it is not a managed profile. Not connecting data\")\n            }\n        }\n    }\n\n    companion object {\n        const val TAG = \"GmsUserInit\"\n    }\n}"
  },
  {
    "path": "play-services-base/core/src/main/kotlin/org/microg/gms/profile/Build.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2021 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.profile\n\nimport android.annotation.TargetApi\n\nobject Build {\n    @JvmField\n    var BOARD: String? = null\n\n    @JvmField\n    var BOOTLOADER: String? = null\n\n    @JvmField\n    var BRAND: String? = null\n\n    @JvmField\n    var CPU_ABI: String? = null\n\n    @JvmField\n    var CPU_ABI2: String? = null\n\n    @JvmField\n    @TargetApi(21)\n    var SUPPORTED_ABIS: Array<String> = emptyArray()\n\n    @JvmField\n    var DEVICE: String? = null\n\n    @JvmField\n    var DISPLAY: String? = null\n\n    @JvmField\n    var FINGERPRINT: String? = null\n\n    @JvmField\n    var HARDWARE: String? = null\n\n    @JvmField\n    var HOST: String? = null\n\n    @JvmField\n    var ID: String? = null\n\n    @JvmField\n    var MANUFACTURER: String? = null\n\n    @JvmField\n    var MODEL: String? = null\n\n    @JvmField\n    var PRODUCT: String? = null\n\n    @JvmField\n    var RADIO: String? = null\n\n    @JvmField\n    var SERIAL: String? = null\n\n    @JvmField\n    var TAGS: String? = null\n\n    @JvmField\n    var TIME: Long = 0L\n\n    @JvmField\n    var TYPE: String? = null\n\n    @JvmField\n    var USER: String? = null\n\n    object VERSION {\n        @JvmField\n        var CODENAME: String? = null\n\n        @JvmField\n        var INCREMENTAL: String? = null\n\n        @JvmField\n        var RELEASE: String? = null\n\n        @JvmField\n        var SDK: String? = null\n\n        @JvmField\n        var SDK_INT: Int = 0\n\n        @JvmField\n        var SECURITY_PATCH: String? = null\n\n        @JvmField\n        var DEVICE_INITIAL_SDK_INT: Int = 0\n    }\n\n    fun generateWebViewUserAgentString(original: String): String {\n        if (!original.startsWith(\"Mozilla/5.0 (\")) return original\n        val closeParen: Int = original.indexOf(')')\n\n        return \"Mozilla/5.0 (Linux; Android ${VERSION.RELEASE}; $MODEL Build/$ID; wv)${original.substring(closeParen + 1)}\"\n    }\n}\n"
  },
  {
    "path": "play-services-base/core/src/main/kotlin/org/microg/gms/profile/ProfileManager.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.profile\n\nimport android.annotation.SuppressLint\nimport android.content.Context\nimport android.content.pm.PackageManager\nimport android.content.res.XmlResourceParser\nimport android.net.Uri\nimport android.os.Bundle\nimport android.util.Log\nimport org.microg.gms.settings.SettingsContract\nimport org.microg.gms.settings.SettingsContract.Profile\nimport org.microg.gms.utils.FileXmlResourceParser\nimport org.xmlpull.v1.XmlPullParser\nimport java.io.File\nimport java.util.*\nimport kotlin.random.Random\n\nobject ProfileManager {\n    private const val TAG = \"ProfileManager\"\n    const val META_DATA_KEY_SOURCE_PACKAGE = \"org.microg.gms.profile:source-package\"\n    const val PROFILE_REAL = \"real\"\n    const val PROFILE_AUTO = \"auto\"\n    const val PROFILE_NATIVE = \"native\"\n    const val PROFILE_USER = \"user\"\n    const val PROFILE_SYSTEM = \"system\"\n    const val PROFILE_REMOTE = \"remote\"\n\n    private var activeProfile: String? = null\n\n    private fun getUserProfileFile(context: Context): File = File(context.filesDir, \"device_profile.xml\")\n    private fun getSystemProfileFile(context: Context): File = File(\"/system/etc/microg_device_profile.xml\")\n    private fun getProfileResId(context: Context, profile: String) = context.resources.getIdentifier(\"${context.packageName}:xml/profile_$profile\".toLowerCase(Locale.US), null, null)\n\n    fun getConfiguredProfile(context: Context): String = SettingsContract.getSettings(context, Profile.getContentUri(context), arrayOf(Profile.PROFILE)) { it.getString(0) } ?: PROFILE_AUTO\n\n    fun getAutoProfile(context: Context): String {\n        if (hasProfile(context, PROFILE_SYSTEM) && isAutoProfile(context, PROFILE_SYSTEM)) return PROFILE_SYSTEM\n        val profile = \"${android.os.Build.PRODUCT}_${android.os.Build.VERSION.SDK_INT}\"\n        if (hasProfile(context, profile) && isAutoProfile(context, profile)) return profile\n        return PROFILE_NATIVE\n    }\n\n    fun hasProfile(context: Context, profile: String): Boolean = when (profile) {\n        PROFILE_AUTO -> hasProfile(context, getAutoProfile(context))\n        PROFILE_NATIVE, PROFILE_REAL -> true\n        PROFILE_USER -> getUserProfileFile(context).exists()\n        PROFILE_SYSTEM -> getSystemProfileFile(context).exists()\n        else -> getProfileResId(context, profile) != 0\n    }\n\n    private fun getProfileXml(context: Context, profile: String): XmlResourceParser? = kotlin.runCatching {\n            when (profile) {\n                PROFILE_AUTO -> getProfileXml(context, getAutoProfile(context))\n                PROFILE_NATIVE, PROFILE_REAL -> null\n                PROFILE_USER -> FileXmlResourceParser(getUserProfileFile(context))\n                PROFILE_SYSTEM -> FileXmlResourceParser(getSystemProfileFile(context))\n                else -> {\n                    val profileResId = getProfileResId(context, profile)\n                    if (profileResId == 0) return@runCatching null\n                    context.resources.getXml(profileResId)\n                }\n            }\n    }.getOrNull()\n\n    fun isAutoProfile(context: Context, profile: String): Boolean = kotlin.runCatching {\n        when (profile) {\n            PROFILE_AUTO -> false\n            PROFILE_REAL -> false\n            PROFILE_NATIVE -> true\n            else -> {\n                val parser = getProfileXml(context, profile)\n                if (parser != null) {\n                    try {\n                        var next = parser.next()\n                        while (next != XmlPullParser.END_DOCUMENT) {\n                            when (next) {\n                                XmlPullParser.START_TAG -> when (parser.name) {\n                                    \"profile\" -> {\n                                        return@runCatching parser.getAttributeBooleanValue(null, \"auto\", false)\n                                    }\n                                }\n                            }\n                            next = parser.next()\n                        }\n                    } finally {\n                        parser.close()\n                    }\n                    false\n                } else {\n                    false\n                }\n            }\n        }\n    }.getOrDefault(false)\n\n    fun getActiveProfileData(context: Context): Map<String, String> =\n        getProfileData(context, getProfile(context), getRealData())\n\n    private fun getProfileData(context: Context, profile: String, realData: Map<String, String>): Map<String, String> {\n        try {\n            if (profile in listOf(PROFILE_REAL, PROFILE_NATIVE)) return realData\n            if (profile !in listOf(PROFILE_USER, PROFILE_SYSTEM) && getProfileResId(context, profile) == 0) return realData\n            val resultData = mutableMapOf<String, String>()\n            resultData.putAll(realData)\n            val parser = getProfileXml(context, profile)\n            if (parser != null) {\n                try {\n                    var next = parser.next()\n                    while (next != XmlPullParser.END_DOCUMENT) {\n                        when (next) {\n                            XmlPullParser.START_TAG -> when (parser.name) {\n                                \"data\" -> {\n                                    val key = parser.getAttributeValue(null, \"key\")\n                                    val value = parser.getAttributeValue(null, \"value\")\n                                    resultData[key] = value\n                                    Log.d(TAG, \"Overwrite from profile: $key = $value\")\n                                }\n                            }\n                        }\n                        next = parser.next()\n                    }\n                } finally {\n                    parser.close()\n                }\n            }\n            return resultData\n        } catch (e: Exception) {\n            Log.w(TAG, e)\n            return realData\n        }\n    }\n\n    private fun getRemoteProfileData(context: Context, packageName: String): Map<String, String> {\n        val data = mutableMapOf<String, String>()\n        val cursor = context.contentResolver.query(Uri.parse(\"content://${packageName}.microg.profile\"), null, null, null, null)\n        cursor?.use {\n            while (cursor.moveToNext()) {\n                data[cursor.getString(0)] = cursor.getString(1)\n            }\n        }\n        return data\n    }\n\n    private fun getProfile(context: Context) = getConfiguredProfile(context).let { if (it != PROFILE_AUTO) it else getAutoProfile(context) }\n    private fun getSerialFromSettings(context: Context): String? = SettingsContract.getSettings(context, Profile.getContentUri(context), arrayOf(Profile.SERIAL)) { it.getString(0) }\n    private fun saveSerial(context: Context, serial: String) = SettingsContract.setSettings(context, Profile.getContentUri(context)) { put(Profile.SERIAL, serial) }\n\n    private fun randomSerial(template: String, prefixLength: Int = (template.length / 2).coerceAtMost(6)): String {\n        val serial = StringBuilder()\n        template.forEachIndexed { index, c ->\n            serial.append(when {\n                index < prefixLength -> c\n                c.isDigit() -> '0' + Random.nextInt(10)\n                c.isLowerCase() && c <= 'f' -> 'a' + Random.nextInt(6)\n                c.isLowerCase() -> 'a' + Random.nextInt(26)\n                c.isUpperCase() && c <= 'F' -> 'A' + Random.nextInt(6)\n                c.isUpperCase() -> 'A' + Random.nextInt(26)\n                else -> c\n            })\n        }\n        return serial.toString()\n    }\n\n    @SuppressLint(\"MissingPermission\")\n    private fun getProfileSerialTemplate(context: Context, profile: String): String {\n        // Native\n        if (profile in listOf(PROFILE_REAL, PROFILE_NATIVE)) {\n            var candidate = try {\n                if (android.os.Build.VERSION.SDK_INT >= 26) {\n                    android.os.Build.getSerial()\n                } else {\n                    android.os.Build.SERIAL\n                }\n            } catch (e: Exception) {\n                android.os.Build.SERIAL\n            }\n            if (candidate != android.os.Build.UNKNOWN) return candidate\n        }\n\n        // From profile\n        try {\n            val parser = getProfileXml(context, profile)\n            if (parser != null) {\n                try {\n                    var next = parser.next()\n                    while (next != XmlPullParser.END_DOCUMENT) {\n                        when (next) {\n                            XmlPullParser.START_TAG -> when (parser.name) {\n                                \"serial\" -> return parser.getAttributeValue(null, \"template\")\n                            }\n                        }\n                        next = parser.next()\n                    }\n                } finally {\n                    parser.close()\n                }\n            }\n        } catch (e: Exception) {\n            Log.w(TAG, e)\n        }\n\n        // Fallback\n        return randomSerial(\"008741A0B2C4D6E8\")\n    }\n\n    @SuppressLint(\"MissingPermission\")\n    fun getSerial(context: Context, profile: String = getProfile(context), local: Boolean = false): String {\n        if (!local) getSerialFromSettings(context)?.let { return it }\n        val serialTemplate = getProfileSerialTemplate(context, profile)\n        val serial = when {\n            profile == PROFILE_REAL && serialTemplate != android.os.Build.UNKNOWN -> serialTemplate\n            else -> randomSerial(serialTemplate)\n        }\n        if (!local) saveSerial(context, serial)\n        return serial\n    }\n\n    @SuppressLint(\"BlockedPrivateApi\")\n    private fun getRealData(): Map<String, String> = mutableMapOf(\n            \"Build.BOARD\" to android.os.Build.BOARD,\n            \"Build.BOOTLOADER\" to android.os.Build.BOOTLOADER,\n            \"Build.BRAND\" to android.os.Build.BRAND,\n            \"Build.CPU_ABI\" to android.os.Build.CPU_ABI,\n            \"Build.CPU_ABI2\" to android.os.Build.CPU_ABI2,\n            \"Build.DEVICE\" to android.os.Build.DEVICE,\n            \"Build.DISPLAY\" to android.os.Build.DISPLAY,\n            \"Build.FINGERPRINT\" to android.os.Build.FINGERPRINT,\n            \"Build.HARDWARE\" to android.os.Build.HARDWARE,\n            \"Build.HOST\" to android.os.Build.HOST,\n            \"Build.ID\" to android.os.Build.ID,\n            \"Build.MANUFACTURER\" to android.os.Build.MANUFACTURER,\n            \"Build.MODEL\" to android.os.Build.MODEL,\n            \"Build.PRODUCT\" to android.os.Build.PRODUCT,\n            \"Build.RADIO\" to android.os.Build.RADIO,\n            \"Build.SERIAL\" to android.os.Build.SERIAL,\n            \"Build.TAGS\" to android.os.Build.TAGS,\n            \"Build.TIME\" to android.os.Build.TIME.toString(),\n            \"Build.TYPE\" to android.os.Build.TYPE,\n            \"Build.USER\" to android.os.Build.USER,\n            \"Build.VERSION.CODENAME\" to android.os.Build.VERSION.CODENAME,\n            \"Build.VERSION.INCREMENTAL\" to android.os.Build.VERSION.INCREMENTAL,\n            \"Build.VERSION.RELEASE\" to android.os.Build.VERSION.RELEASE,\n            \"Build.VERSION.SDK\" to android.os.Build.VERSION.SDK,\n            \"Build.VERSION.SDK_INT\" to android.os.Build.VERSION.SDK_INT.toString()\n    ).apply {\n        if (android.os.Build.VERSION.SDK_INT >= 21) {\n            put(\"Build.SUPPORTED_ABIS\", android.os.Build.SUPPORTED_ABIS.joinToString(\",\"))\n        }\n        if (android.os.Build.VERSION.SDK_INT >= 23) {\n            put(\"Build.VERSION.SECURITY_PATCH\", android.os.Build.VERSION.SECURITY_PATCH)\n        }\n        try {\n            val field = android.os.Build.VERSION::class.java.getDeclaredField(\"DEVICE_INITIAL_SDK_INT\")\n            field.isAccessible = true\n            put(\"Build.VERSION.DEVICE_INITIAL_SDK_INT\", field.getInt(null).toString())\n        } catch (ignored: Exception) {\n        }\n    }\n\n    fun applyProfileData(profileData: Map<String, String>) {\n        fun applyStringField(key: String, valueSetter: (String) -> Unit) = profileData[key]?.let { valueSetter(it) }\n        fun applyIntField(key: String, valueSetter: (Int) -> Unit) = profileData[key]?.toIntOrNull()?.let { valueSetter(it) }\n        fun applyLongField(key: String, valueSetter: (Long) -> Unit) = profileData[key]?.toLongOrNull()?.let { valueSetter(it) }\n\n        applyStringField(\"Build.BOARD\") { Build.BOARD = it }\n        applyStringField(\"Build.BOOTLOADER\") { Build.BOOTLOADER = it }\n        applyStringField(\"Build.BRAND\") { Build.BRAND = it }\n        applyStringField(\"Build.CPU_ABI\") { Build.CPU_ABI = it }\n        applyStringField(\"Build.CPU_ABI2\") { Build.CPU_ABI2 = it }\n        applyStringField(\"Build.DEVICE\") { Build.DEVICE = it }\n        applyStringField(\"Build.DISPLAY\") { Build.DISPLAY = it }\n        applyStringField(\"Build.FINGERPRINT\") { Build.FINGERPRINT = it }\n        applyStringField(\"Build.HARDWARE\") { Build.HARDWARE = it }\n        applyStringField(\"Build.HOST\") { Build.HOST = it }\n        applyStringField(\"Build.ID\") { Build.ID = it }\n        applyStringField(\"Build.MANUFACTURER\") { Build.MANUFACTURER = it }\n        applyStringField(\"Build.MODEL\") { Build.MODEL = it }\n        applyStringField(\"Build.PRODUCT\") { Build.PRODUCT = it }\n        applyStringField(\"Build.RADIO\") { Build.RADIO = it }\n        applyStringField(\"Build.SERIAL\") { Build.SERIAL = it }\n        applyStringField(\"Build.TAGS\") { Build.TAGS = it }\n        applyLongField(\"Build.TIME\") { Build.TIME = it }\n        applyStringField(\"Build.TYPE\") { Build.TYPE = it }\n        applyStringField(\"Build.USER\") { Build.USER = it }\n        applyStringField(\"Build.VERSION.CODENAME\") { Build.VERSION.CODENAME = it }\n        applyStringField(\"Build.VERSION.INCREMENTAL\") { Build.VERSION.INCREMENTAL = it }\n        applyStringField(\"Build.VERSION.RELEASE\") { Build.VERSION.RELEASE = it }\n        applyStringField(\"Build.VERSION.SDK\") { Build.VERSION.SDK = it }\n        applyIntField(\"Build.VERSION.SDK_INT\") { Build.VERSION.SDK_INT = it }\n        applyIntField(\"Build.VERSION.DEVICE_INITIAL_SDK_INT\") { Build.VERSION.DEVICE_INITIAL_SDK_INT = it }\n        if (android.os.Build.VERSION.SDK_INT >= 21) {\n            Build.SUPPORTED_ABIS = profileData[\"Build.SUPPORTED_ABIS\"]?.split(\",\")?.toTypedArray() ?: emptyArray()\n        } else {\n            Build.SUPPORTED_ABIS = emptyArray()\n        }\n        if (android.os.Build.VERSION.SDK_INT >= 23) {\n            Build.VERSION.SECURITY_PATCH = profileData[\"Build.VERSION.SECURITY_PATCH\"]\n        } else {\n            Build.VERSION.SECURITY_PATCH = null\n        }\n    }\n\n    private fun applyProfile(context: Context, profile: String, serial: String = getSerial(context, profile)) {\n        val profileData = getProfileData(context, profile, getRealData())\n        if (Log.isLoggable(TAG, Log.VERBOSE)) {\n            for ((key, value) in profileData) {\n                Log.v(TAG, \"<data key=\\\"$key\\\" value=\\\"$value\\\" />\")\n            }\n        }\n        applyProfileData(profileData)\n        Build.SERIAL = serial\n        Log.d(TAG, \"Using Serial ${Build.SERIAL}\")\n        activeProfile = profile\n    }\n\n    private fun applyRemoteProfile(context: Context, packageName: String) {\n        val profileData = getRemoteProfileData(context, packageName)\n        if (Log.isLoggable(TAG, Log.VERBOSE)) {\n            for ((key, value) in profileData) {\n                Log.v(TAG, \"<data key=\\\"$key\\\" value=\\\"$value\\\" />\")\n            }\n        }\n        if (profileData.isNotEmpty()) {\n            applyProfileData(profileData)\n            activeProfile = PROFILE_REMOTE\n        }\n    }\n\n    fun getProfileName(context: Context, profile: String): String? = getProfileName { getProfileXml(context, profile) }\n\n    private fun getProfileName(parserCreator: () -> XmlResourceParser?): String? {\n        val parser = parserCreator()\n        if (parser != null) {\n            try {\n                var next = parser.next()\n                while (next != XmlPullParser.END_DOCUMENT) {\n                    when (next) {\n                        XmlPullParser.START_TAG -> when (parser.name) {\n                            \"profile\" -> {\n                                return parser.getAttributeValue(null, \"name\")\n                            }\n                        }\n                    }\n                    next = parser.next()\n                }\n            } finally {\n                parser.close()\n            }\n        }\n        return null\n    }\n\n    fun setProfile(context: Context, profile: String?) {\n        val changed = getProfile(context) != profile\n        val newProfile = profile ?: PROFILE_AUTO\n        val newSerial = if (changed) getSerial(context, newProfile, true) else getSerial(context)\n        SettingsContract.setSettings(context, Profile.getContentUri(context)) {\n            put(Profile.PROFILE, newProfile)\n            if (changed) put(Profile.SERIAL, newSerial)\n        }\n        if (changed && activeProfile != null) applyProfile(context, newProfile, newSerial)\n    }\n\n    fun importUserProfile(context: Context, file: File): Boolean {\n        val profileName = getProfileName { FileXmlResourceParser(file) } ?: return false\n        try {\n            Log.d(TAG, \"Importing user profile '$profileName'\")\n            file.copyTo(getUserProfileFile(context), overwrite = true)\n            if (activeProfile == PROFILE_USER) applyProfile(context, PROFILE_USER)\n            return true\n        } catch (e: Exception) {\n            Log.w(TAG, e)\n            return false\n        }\n    }\n\n    @JvmStatic\n    fun resetActiveProfile() {\n        activeProfile = null\n    }\n\n    @JvmStatic\n    fun ensureInitialized(context: Context) {\n        val metaData = runCatching { context.packageManager.getApplicationInfo(context.packageName, PackageManager.GET_META_DATA).metaData }.getOrNull() ?: Bundle.EMPTY\n        synchronized(this) {\n            try {\n                if (metaData.containsKey(META_DATA_KEY_SOURCE_PACKAGE)) {\n                    if (activeProfile != PROFILE_REMOTE) {\n                        val packageName = metaData.getString(META_DATA_KEY_SOURCE_PACKAGE)!!\n                        applyRemoteProfile(context, packageName)\n                    }\n                } else {\n                    val profile = getProfile(context)\n                    if (activeProfile == profile) return\n                    applyProfile(context, profile)\n                }\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n            }\n            Unit\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-base/core/src/main/kotlin/org/microg/gms/settings/MetaDataPreferences.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.settings\n\nimport android.content.Context\nimport android.content.SharedPreferences\nimport android.content.pm.PackageManager.GET_META_DATA\nimport android.os.Bundle\n\nclass MetaDataPreferences(private val context: Context, private val prefix: String = \"\") : SharedPreferences {\n    private val metaData by lazy {\n        runCatching { context.packageManager.getApplicationInfo(context.packageName, GET_META_DATA) }.getOrNull()?.metaData ?: Bundle.EMPTY\n    }\n\n    override fun getAll(): Map<String, *> = metaData.keySet().filter { it.startsWith(prefix) }.associate { it.substring(prefix.length) to metaData.get(it) }\n\n    override fun getString(key: String, defValue: String?): String? = metaData.getString(prefix + key, defValue)\n\n    override fun getStringSet(key: String, defValues: Set<String>?): Set<String>? = metaData.getStringArray(prefix + key)?.toSet() ?: defValues\n\n    override fun getInt(key: String?, defValue: Int): Int = metaData.getInt(prefix + key, defValue)\n\n    override fun getLong(key: String?, defValue: Long): Long = metaData.getLong(prefix + key, defValue)\n\n    override fun getFloat(key: String?, defValue: Float): Float = metaData.getFloat(prefix + key, defValue)\n\n    override fun getBoolean(key: String?, defValue: Boolean): Boolean = metaData.getBoolean(prefix + key, defValue)\n\n    override fun contains(key: String?): Boolean = metaData.containsKey(prefix + key)\n\n    override fun edit(): SharedPreferences.Editor {\n        throw UnsupportedOperationException()\n    }\n\n    override fun registerOnSharedPreferenceChangeListener(listener: SharedPreferences.OnSharedPreferenceChangeListener?) {\n        throw UnsupportedOperationException()\n    }\n\n    override fun unregisterOnSharedPreferenceChangeListener(listener: SharedPreferences.OnSharedPreferenceChangeListener?) {\n        throw UnsupportedOperationException()\n    }\n}"
  },
  {
    "path": "play-services-base/core/src/main/kotlin/org/microg/gms/settings/SettingsContract.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.settings\n\nimport android.content.ContentValues\nimport android.content.Context\nimport android.content.Context.MODE_PRIVATE\nimport android.content.Intent\nimport android.content.Intent.FLAG_ACTIVITY_NEW_TASK\nimport android.content.pm.CrossProfileApps\nimport android.content.pm.PackageManager\nimport android.database.Cursor\nimport android.net.Uri\nimport android.os.Binder\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.Bundle\nimport android.os.UserManager\nimport android.util.Log\nimport androidx.core.net.toUri\nimport org.microg.gms.crossprofile.CrossProfileRequestActivity\nimport org.microg.gms.ui.TAG\n\nobject SettingsContract {\n    const val META_DATA_KEY_SOURCE_PACKAGE = \"org.microg.gms.settings:source-package\"\n\n    /**\n     * Stores keys that are useful only for connecting to the SettingsProvider from\n     * main profile in a managed / work profile\n     */\n    const val CROSS_PROFILE_SHARED_PREFERENCES_NAME = \"crossProfile\"\n    const val CROSS_PROFILE_PERMISSION = \"uri\"\n\n    fun getAuthority(context: Context): String {\n        val metaData = runCatching { context.packageManager.getApplicationInfo(context.packageName, PackageManager.GET_META_DATA).metaData }.getOrNull() ?: Bundle.EMPTY\n        val sourcePackage = metaData.getString(META_DATA_KEY_SOURCE_PACKAGE, context.packageName)\n        return \"${sourcePackage}.microg.settings\"\n    }\n\n    /**\n     * URI for preferences local to this profile\n     */\n    fun getAuthorityUri(context: Context) = \"content://${getAuthority(context)}\".toUri()\n\n    /* Cross-profile interactivity, granting access to same preferences across all profiles of a user:\n     * URI points to our `SettingsProvider` on normal profile and is supposed to point to\n     * _primary_ profile's `SettingsProvider` work / managed profile. If this is not yet established,\n     * we need to start the `CrossProfileRequestActivity`, which asks `CrossProfileSendActivity` to\n     * send it a URI that entitles it to access the primary profile's settings. (This would normally\n     * happen while creating the profile from `UserInitReceiver`.)\n     */\n    fun getCrossProfileSharedAuthorityUri(context: Context): Uri {\n\n        if (SDK_INT < 30) {\n            Log.v(TAG, \"cross-profile interactivity not possible on this Android version\")\n            return \"content://${getAuthority(context)}\".toUri()\n        }\n\n        val userManager = context.getSystemService(UserManager::class.java)\n        val workProfile = userManager.isManagedProfile\n\n        if (!workProfile) {\n            return \"content://${getAuthority(context)}\".toUri()\n        }\n\n        /* Check special shared preferences file if it contains a URI that permits us to access\n         * main profile's settings content provider\n         */\n        val preferences = context.getSharedPreferences(CROSS_PROFILE_SHARED_PREFERENCES_NAME, MODE_PRIVATE)\n        if (preferences.contains(CROSS_PROFILE_PERMISSION)) {\n            Log.v(TAG, \"using work profile stored URI\")\n            return preferences.getString(CROSS_PROFILE_PERMISSION, null)!!.toUri()\n        }\n\n        val crossProfileApps = context.getSystemService(CrossProfileApps::class.java)\n        val targetProfiles = crossProfileApps.targetUserProfiles\n\n        if (!crossProfileApps.canInteractAcrossProfiles() || targetProfiles.isEmpty()) {\n            Log.w(TAG, \"prerequisites for cross-profile interactivity not met: \" +\n                    \"can interact = ${crossProfileApps.canInteractAcrossProfiles()}, \" +\n                    \"#targetProfiles = ${targetProfiles.size}\")\n            return \"content://${getAuthority(context)}\".toUri()\n        } else {\n\n            Log.d(TAG, \"Initiating activity to request storage URI from main profile\")\n            context.startActivity(Intent(context, CrossProfileRequestActivity::class.java).apply {\n                addFlags(FLAG_ACTIVITY_NEW_TASK)\n            })\n\n            // while proper response is not yet available, work on local data :(\n            return \"content://${getAuthority(context)}\".toUri()\n        }\n    }\n\n    object CheckIn {\n        const val ID = \"check-in\"\n        fun getContentUri(context: Context) = Uri.withAppendedPath(getAuthorityUri(context), ID)\n        fun getContentType(context: Context) = \"vnd.android.cursor.item/vnd.${getAuthority(context)}.$ID\"\n\n        const val ENABLED = \"checkin_enable_service\"\n        const val ANDROID_ID = \"androidId\"\n        const val DIGEST = \"digest\"\n        const val LAST_CHECK_IN = \"lastCheckin\"\n        const val SECURITY_TOKEN = \"securityToken\"\n        const val VERSION_INFO = \"versionInfo\"\n        const val DEVICE_DATA_VERSION_INFO = \"deviceDataVersionInfo\"\n\n        val PROJECTION = arrayOf(\n            ENABLED,\n            ANDROID_ID,\n            DIGEST,\n            LAST_CHECK_IN,\n            SECURITY_TOKEN,\n            VERSION_INFO,\n            DEVICE_DATA_VERSION_INFO,\n        )\n        const val PREFERENCES_NAME = \"checkin\"\n        const val INITIAL_DIGEST = \"1-929a0dca0eee55513280171a8585da7dcd3700f8\"\n    }\n\n    object Gcm {\n        const val ID = \"gcm\"\n        fun getContentUri(context: Context) = Uri.withAppendedPath(getAuthorityUri(context), ID)\n        fun getContentType(context: Context) = \"vnd.android.cursor.item/vnd.${getAuthority(context)}.$ID\"\n\n        const val FULL_LOG = \"gcm_full_log\"\n        const val LAST_PERSISTENT_ID = \"gcm_last_persistent_id\"\n        const val CONFIRM_NEW_APPS = \"gcm_confirm_new_apps\"\n        const val ENABLE_GCM = \"gcm_enable_mcs_service\"\n\n        const val NETWORK_MOBILE = \"gcm_network_mobile\"\n        const val NETWORK_WIFI = \"gcm_network_wifi\"\n        const val NETWORK_ROAMING = \"gcm_network_roaming\"\n        const val NETWORK_OTHER = \"gcm_network_other\"\n\n        const val LEARNT_MOBILE = \"gcm_learnt_mobile\"\n        const val LEARNT_WIFI = \"gcm_learnt_wifi\"\n        const val LEARNT_OTHER = \"gcm_learnt_other\"\n\n        val PROJECTION = arrayOf(\n            FULL_LOG,\n            LAST_PERSISTENT_ID,\n            CONFIRM_NEW_APPS,\n            ENABLE_GCM,\n            NETWORK_MOBILE,\n            NETWORK_WIFI,\n            NETWORK_ROAMING,\n            NETWORK_OTHER,\n            LEARNT_MOBILE,\n            LEARNT_WIFI,\n            LEARNT_OTHER,\n        )\n    }\n\n    object Auth {\n        const val ID = \"auth\"\n        fun getContentUri(context: Context) = Uri.withAppendedPath(getAuthorityUri(context), ID)\n        fun getContentType(context: Context) = \"vnd.android.cursor.item/vnd.${getAuthority(context)}.$ID\"\n\n        const val TRUST_GOOGLE = \"auth_manager_trust_google\"\n        const val VISIBLE = \"auth_manager_visible\"\n        const val INCLUDE_ANDROID_ID = \"auth_include_android_id\"\n        const val STRIP_DEVICE_NAME = \"auth_strip_device_name\"\n        const val TWO_STEP_VERIFICATION = \"auth_two_step_verification\"\n\n        val PROJECTION = arrayOf(\n            TRUST_GOOGLE,\n            VISIBLE,\n            INCLUDE_ANDROID_ID,\n            STRIP_DEVICE_NAME,\n            TWO_STEP_VERIFICATION,\n        )\n    }\n\n    object Exposure {\n        const val ID = \"exposureNotification\"\n        fun getContentUri(context: Context) = Uri.withAppendedPath(getAuthorityUri(context), ID)\n        fun getContentType(context: Context) = \"vnd.android.cursor.item/vnd.${getAuthority(context)}.$ID\"\n\n        const val SCANNER_ENABLED = \"exposure_scanner_enabled\"\n        const val LAST_CLEANUP = \"exposure_last_cleanup\"\n\n        val PROJECTION = arrayOf(\n            SCANNER_ENABLED,\n            LAST_CLEANUP,\n        )\n    }\n\n    object SafetyNet {\n        const val ID = \"safety-net\"\n        fun getContentUri(context: Context) = Uri.withAppendedPath(getAuthorityUri(context), ID)\n        fun getContentType(context: Context) = \"vnd.android.cursor.item/vnd.${getAuthority(context)}.$ID\"\n\n        const val ENABLED = \"safetynet_enabled\"\n\n        val PROJECTION = arrayOf(\n            ENABLED\n        )\n    }\n\n    object DroidGuard {\n        const val ID = \"droidguard\"\n        fun getContentUri(context: Context) = Uri.withAppendedPath(getAuthorityUri(context), ID)\n        fun getContentType(context: Context) = \"vnd.android.cursor.item/vnd.${getAuthority(context)}.$ID\"\n\n        const val ENABLED = \"droidguard_enabled\"\n        const val MODE = \"droidguard_mode\"\n        const val NETWORK_SERVER_URL = \"droidguard_network_server_url\"\n        const val FORCE_LOCAL_DISABLED = \"droidguard_force_local_disabled\"\n        const val HARDWARE_ATTESTATION_BLOCKED = \"droidguard_block_hw_attestation\"\n\n        val PROJECTION = arrayOf(\n            ENABLED,\n            MODE,\n            NETWORK_SERVER_URL,\n            FORCE_LOCAL_DISABLED,\n            HARDWARE_ATTESTATION_BLOCKED,\n        )\n    }\n\n    object Profile {\n        const val ID = \"profile\"\n        fun getContentUri(context: Context) = Uri.withAppendedPath(getAuthorityUri(context), ID)\n        fun getContentType(context: Context) = \"vnd.android.cursor.item/vnd.${getAuthority(context)}.$ID\"\n\n        const val PROFILE = \"device_profile\"\n        const val SERIAL = \"device_profile_serial\"\n\n        val PROJECTION = arrayOf(\n            PROFILE,\n            SERIAL\n        )\n    }\n\n    object Location {\n        const val ID = \"location\"\n        fun getContentUri(context: Context) = Uri.withAppendedPath(getAuthorityUri(context), ID)\n        fun getContentType(context: Context) = \"vnd.android.cursor.item/vnd.${getAuthority(context)}.$ID\"\n\n        const val WIFI_ICHNAEA = \"location_wifi_mls\"\n        const val WIFI_MOVING = \"location_wifi_moving\"\n        const val WIFI_LEARNING = \"location_wifi_learning\"\n        const val WIFI_CACHING = \"location_wifi_caching\"\n        const val CELL_ICHNAEA = \"location_cell_mls\"\n        const val CELL_LEARNING = \"location_cell_learning\"\n        const val CELL_CACHING = \"location_cell_caching\"\n        const val GEOCODER_NOMINATIM = \"location_geocoder_nominatim\"\n        const val ICHNAEA_ENDPOINT = \"location_ichnaea_endpoint\"\n        const val ONLINE_SOURCE = \"location_online_source\"\n        const val ICHNAEA_CONTRIBUTE = \"location_ichnaea_contribute\"\n\n        val PROJECTION = arrayOf(\n            WIFI_ICHNAEA,\n            WIFI_MOVING,\n            WIFI_LEARNING,\n            WIFI_CACHING,\n            CELL_ICHNAEA,\n            CELL_LEARNING,\n            CELL_CACHING,\n            GEOCODER_NOMINATIM,\n            ICHNAEA_ENDPOINT,\n            ONLINE_SOURCE,\n            ICHNAEA_CONTRIBUTE,\n        )\n    }\n\n    object Vending {\n        const val ID = \"vending\"\n        fun getContentUri(context: Context) = Uri.withAppendedPath(getAuthorityUri(context), ID)\n        fun getContentType(context: Context) = \"vnd.android.cursor.item/vnd.${getAuthority(context)}.$ID\"\n\n        const val LICENSING = \"vending_licensing\"\n        const val LICENSING_PURCHASE_FREE_APPS = \"vending_licensing_purchase_free_apps\"\n        const val SPLIT_INSTALL = \"vending_split_install\"\n        const val BILLING = \"vending_billing\"\n        const val ASSET_DELIVERY = \"vending_asset_delivery\"\n        const val ASSET_DEVICE_SYNC = \"vending_device_sync\"\n        const val APPS_INSTALL = \"vending_apps_install\"\n        const val APPS_INSTALLER_LIST = \"vending_apps_installer_list\"\n        const val PLAY_INTEGRITY_APP_LIST = \"vending_play_integrity_apps\"\n\n        val PROJECTION = arrayOf(\n            LICENSING,\n            LICENSING_PURCHASE_FREE_APPS,\n            SPLIT_INSTALL,\n            BILLING,\n            ASSET_DELIVERY,\n            ASSET_DEVICE_SYNC,\n            APPS_INSTALL,\n            APPS_INSTALLER_LIST,\n            PLAY_INTEGRITY_APP_LIST\n        )\n    }\n\n    object WorkProfile {\n        const val ID = \"workprofile\"\n        fun getContentUri(context: Context) = Uri.withAppendedPath(getCrossProfileSharedAuthorityUri(context), ID)\n        fun getContentType(context: Context) = \"vnd.android.cursor.item/vnd.${getAuthority(context)}.$ID\"\n\n        const val CREATE_WORK_ACCOUNT = \"workprofile_allow_create_work_account\"\n\n        val PROJECTION = arrayOf(\n            CREATE_WORK_ACCOUNT\n        )\n    }\n\n    object GameProfile {\n        const val ID = \"gameprofile\"\n        fun getContentUri(context: Context) = Uri.withAppendedPath(getCrossProfileSharedAuthorityUri(context), ID)\n        fun getContentType(context: Context) = \"vnd.android.cursor.item/vnd.${getAuthority(context)}.$ID\"\n\n        const val ALLOW_CREATE_PLAYER = \"game_allow_create_player\"\n        const val ALLOW_UPLOAD_GAME_PLAYED = \"allow_upload_game_played\"\n\n        val PROJECTION = arrayOf(\n            ALLOW_CREATE_PLAYER,\n            ALLOW_UPLOAD_GAME_PLAYED\n        )\n    }\n\n    private fun <T> withoutCallingIdentity(f: () -> T): T {\n        val identity = Binder.clearCallingIdentity()\n        try {\n            return f.invoke()\n        } finally {\n            Binder.restoreCallingIdentity(identity)\n        }\n    }\n\n    @JvmStatic\n    fun <T> getSettings(context: Context, uri: Uri, projection: Array<out String>?, f: (Cursor) -> T): T = withoutCallingIdentity {\n        val c = context.contentResolver.query(uri, projection, null, null, null)\n        try {\n            require(c != null) { \"Cursor for query $uri ${projection?.toList()} was null\" }\n            if (!c.moveToFirst()) error(\"Cursor for query $uri ${projection?.toList()} was empty\")\n            f.invoke(c)\n        } finally {\n            c?.close()\n        }\n    }\n\n    @JvmStatic\n    fun setSettings(context: Context, uri: Uri, v: ContentValues.() -> Unit) = withoutCallingIdentity {\n        val values = ContentValues().apply { v.invoke(this) }\n        val affected = context.contentResolver.update(uri, values, null, null)\n        require(affected == 1) { \"Update for $uri with $values affected 0 rows\"}\n    }\n\n}\n"
  },
  {
    "path": "play-services-base/core/src/main/kotlin/org/microg/gms/settings/SettingsProvider.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.settings\n\nimport android.content.ContentProvider\nimport android.content.ContentValues\nimport android.content.Context\nimport android.content.Context.MODE_PRIVATE\nimport android.content.SharedPreferences\nimport android.database.Cursor\nimport android.database.MatrixCursor\nimport android.net.Uri\nimport android.os.Build.VERSION.SDK_INT\nimport android.preference.PreferenceManager\nimport org.microg.gms.common.PackageUtils.warnIfNotMainProcess\nimport org.microg.gms.settings.SettingsContract.Auth\nimport org.microg.gms.settings.SettingsContract.CheckIn\nimport org.microg.gms.settings.SettingsContract.DroidGuard\nimport org.microg.gms.settings.SettingsContract.Exposure\nimport org.microg.gms.settings.SettingsContract.GameProfile\nimport org.microg.gms.settings.SettingsContract.Gcm\nimport org.microg.gms.settings.SettingsContract.Location\nimport org.microg.gms.settings.SettingsContract.Profile\nimport org.microg.gms.settings.SettingsContract.SafetyNet\nimport org.microg.gms.settings.SettingsContract.Vending\nimport org.microg.gms.settings.SettingsContract.WorkProfile\nimport org.microg.gms.settings.SettingsContract.getAuthority\nimport java.io.File\n\n\nprivate const val SETTINGS_PREFIX = \"org.microg.gms.settings.\"\n\n/**\n * All settings access should go through this [ContentProvider],\n * because it provides safe access from different processes which normal [SharedPreferences] don't.\n */\nclass SettingsProvider : ContentProvider() {\n\n    private val preferences: SharedPreferences by lazy {\n        PreferenceManager.getDefaultSharedPreferences(context)\n    }\n    private val checkInPrefs by lazy {\n        context!!.getSharedPreferences(CheckIn.PREFERENCES_NAME, MODE_PRIVATE)\n    }\n    private val unifiedNlpPreferences by lazy {\n        context!!.getSharedPreferences(\"unified_nlp\", MODE_PRIVATE)\n    }\n    private val systemDefaultPreferences: SharedPreferences? by lazy {\n        try {\n            Context::class.java.getDeclaredMethod(\n                \"getSharedPreferences\",\n                File::class.java,\n                Int::class.javaPrimitiveType\n            ).invoke(context, File(\"/system/etc/microg.xml\"), MODE_PRIVATE) as SharedPreferences\n        } catch (ignored: Exception) {\n            null\n        }\n    }\n    private val metaDataPreferences: SharedPreferences by lazy {\n        MetaDataPreferences(context!!, SETTINGS_PREFIX)\n    }\n\n    override fun onCreate(): Boolean {\n        return true\n    }\n\n    override fun query(\n        uri: Uri,\n        projection: Array<out String>?,\n        selection: String?,\n        selectionArgs: Array<out String>?,\n        sortOrder: String?\n    ): Cursor? = when (uri.pathSegments.last()) {\n        CheckIn.ID -> queryCheckIn(projection ?: CheckIn.PROJECTION)\n        Gcm.ID -> queryGcm(projection ?: Gcm.PROJECTION)\n        Auth.ID -> queryAuth(projection ?: Auth.PROJECTION)\n        Exposure.ID -> queryExposure(projection ?: Exposure.PROJECTION)\n        SafetyNet.ID -> querySafetyNet(projection ?: SafetyNet.PROJECTION)\n        DroidGuard.ID -> queryDroidGuard(projection ?: DroidGuard.PROJECTION)\n        Profile.ID -> queryProfile(projection ?: Profile.PROJECTION)\n        Location.ID -> queryLocation(projection ?: Location.PROJECTION)\n        Vending.ID -> queryVending(projection ?: Vending.PROJECTION)\n        WorkProfile.ID -> queryWorkProfile(projection ?: WorkProfile.PROJECTION)\n        GameProfile.ID -> queryGameProfile(projection ?: GameProfile.PROJECTION)\n        else -> null\n    }\n\n    override fun update(\n        uri: Uri,\n        values: ContentValues?,\n        selection: String?,\n        selectionArgs: Array<out String>?\n    ): Int {\n        warnIfNotMainProcess(context, this.javaClass)\n        if (values == null) return 0\n        when (uri.pathSegments.last()) {\n            CheckIn.ID -> updateCheckIn(values)\n            Gcm.ID -> updateGcm(values)\n            Auth.ID -> updateAuth(values)\n            Exposure.ID -> updateExposure(values)\n            SafetyNet.ID -> updateSafetyNet(values)\n            DroidGuard.ID -> updateDroidGuard(values)\n            Profile.ID -> updateProfile(values)\n            Location.ID -> updateLocation(values)\n            Vending.ID -> updateVending(values)\n            WorkProfile.ID -> updateWorkProfile(values)\n            GameProfile.ID -> updateGameProfile(values)\n            else -> return 0\n        }\n        return 1\n    }\n\n    private fun queryCheckIn(p: Array<out String>): Cursor = MatrixCursor(p).addRow(p) { key ->\n        when (key) {\n            CheckIn.ENABLED -> getSettingsBoolean(key, false)\n            CheckIn.ANDROID_ID -> checkInPrefs.getLong(key, 0)\n            CheckIn.DIGEST -> checkInPrefs.getString(key, CheckIn.INITIAL_DIGEST)\n                ?: CheckIn.INITIAL_DIGEST\n            CheckIn.LAST_CHECK_IN -> checkInPrefs.getLong(key, 0)\n            CheckIn.SECURITY_TOKEN -> checkInPrefs.getLong(key, 0)\n            CheckIn.VERSION_INFO -> checkInPrefs.getString(key, \"\") ?: \"\"\n            CheckIn.DEVICE_DATA_VERSION_INFO -> checkInPrefs.getString(key, \"\") ?: \"\"\n            else -> throw IllegalArgumentException()\n        }\n    }\n\n    private fun updateCheckIn(values: ContentValues) {\n        if (values.size() == 0) return\n        if (values.size() == 1 && values.containsKey(CheckIn.ENABLED)) {\n            // special case: only changing enabled state\n            updateCheckInEnabled(values.getAsBoolean(CheckIn.ENABLED))\n            return\n        }\n        val editor = checkInPrefs.edit()\n        values.valueSet().forEach { (key, value) ->\n            if (key == CheckIn.ENABLED) {\n                // special case: not saved in checkInPrefs\n                updateCheckInEnabled(value as Boolean)\n            }\n            when (key) {\n                CheckIn.ANDROID_ID -> editor.putLong(key, value as Long)\n                CheckIn.DIGEST -> editor.putString(key, value as String?)\n                CheckIn.LAST_CHECK_IN -> editor.putLong(key, value as Long)\n                CheckIn.SECURITY_TOKEN -> editor.putLong(key, value as Long)\n                CheckIn.VERSION_INFO -> editor.putString(key, value as String?)\n                CheckIn.DEVICE_DATA_VERSION_INFO -> editor.putString(key, value as String?)\n            }\n        }\n        editor.apply()\n    }\n\n    private fun updateCheckInEnabled(enabled: Boolean) {\n        preferences.edit()\n            .putBoolean(CheckIn.ENABLED, enabled)\n            .apply()\n    }\n\n    private fun queryGcm(p: Array<out String>): Cursor = MatrixCursor(p).addRow(p) { key ->\n        when (key) {\n            Gcm.ENABLE_GCM -> getSettingsBoolean(key, false)\n            Gcm.FULL_LOG -> getSettingsBoolean(key, true)\n            Gcm.CONFIRM_NEW_APPS -> getSettingsBoolean(key, false)\n\n            Gcm.LAST_PERSISTENT_ID -> preferences.getString(key, \"\") ?: \"\"\n\n            Gcm.NETWORK_MOBILE -> Integer.parseInt(preferences.getString(key, \"0\") ?: \"0\")\n            Gcm.NETWORK_WIFI -> Integer.parseInt(preferences.getString(key, \"0\") ?: \"0\")\n            Gcm.NETWORK_ROAMING -> Integer.parseInt(preferences.getString(key, \"0\") ?: \"0\")\n            Gcm.NETWORK_OTHER -> Integer.parseInt(preferences.getString(key, \"0\") ?: \"0\")\n\n            Gcm.LEARNT_MOBILE -> preferences.getInt(key, 300000)\n            Gcm.LEARNT_WIFI -> preferences.getInt(key, 300000)\n            Gcm.LEARNT_OTHER -> preferences.getInt(key, 300000)\n\n            else -> throw IllegalArgumentException(\"Unknown key: $key\")\n        }\n    }\n\n    private fun updateGcm(values: ContentValues) {\n        if (values.size() == 0) return\n        val editor = preferences.edit()\n        values.valueSet().forEach { (key, value) ->\n            when (key) {\n                Gcm.ENABLE_GCM -> editor.putBoolean(key, value as Boolean)\n                Gcm.FULL_LOG -> editor.putBoolean(key, value as Boolean)\n                Gcm.CONFIRM_NEW_APPS -> editor.putBoolean(key, value as Boolean)\n\n                Gcm.LAST_PERSISTENT_ID -> editor.putString(key, value as String?)\n\n                Gcm.NETWORK_MOBILE -> editor.putString(key, (value as Int).toString())\n                Gcm.NETWORK_WIFI -> editor.putString(key, (value as Int).toString())\n                Gcm.NETWORK_ROAMING -> editor.putString(key, (value as Int).toString())\n                Gcm.NETWORK_OTHER -> editor.putString(key, (value as Int).toString())\n\n                Gcm.LEARNT_MOBILE -> editor.putInt(key, value as Int)\n                Gcm.LEARNT_WIFI -> editor.putInt(key, value as Int)\n                Gcm.LEARNT_OTHER -> editor.putInt(key, value as Int)\n\n                else -> throw IllegalArgumentException(\"Unknown key: $key\")\n            }\n        }\n        editor.apply()\n    }\n\n    private fun queryAuth(p: Array<out String>): Cursor = MatrixCursor(p).addRow(p) { key ->\n        when (key) {\n            Auth.TRUST_GOOGLE -> getSettingsBoolean(key, true)\n            Auth.VISIBLE -> getSettingsBoolean(key, false)\n            Auth.INCLUDE_ANDROID_ID -> getSettingsBoolean(key, true)\n            Auth.STRIP_DEVICE_NAME -> getSettingsBoolean(key, false)\n            Auth.TWO_STEP_VERIFICATION -> getSettingsBoolean(key, false)\n            else -> throw IllegalArgumentException(\"Unknown key: $key\")\n        }\n    }\n\n    private fun updateAuth(values: ContentValues) {\n        if (values.size() == 0) return\n        val editor = preferences.edit()\n        values.valueSet().forEach { (key, value) ->\n            when (key) {\n                Auth.TRUST_GOOGLE -> editor.putBoolean(key, value as Boolean)\n                Auth.VISIBLE -> editor.putBoolean(key, value as Boolean)\n                Auth.INCLUDE_ANDROID_ID -> editor.putBoolean(key, value as Boolean)\n                Auth.STRIP_DEVICE_NAME -> editor.putBoolean(key, value as Boolean)\n                Auth.TWO_STEP_VERIFICATION -> editor.putBoolean(key, value as Boolean)\n                else -> throw IllegalArgumentException(\"Unknown key: $key\")\n            }\n        }\n        editor.apply()\n    }\n\n    private fun queryExposure(p: Array<out String>): Cursor = MatrixCursor(p).addRow(p) { key ->\n        when (key) {\n            Exposure.SCANNER_ENABLED -> getSettingsBoolean(key, false)\n            Exposure.LAST_CLEANUP -> preferences.getLong(key, 0L)\n            else -> throw IllegalArgumentException(\"Unknown key: $key\")\n        }\n    }\n\n    private fun updateExposure(values: ContentValues) {\n        if (values.size() == 0) return\n        val editor = preferences.edit()\n        values.valueSet().forEach { (key, value) ->\n            when (key) {\n                Exposure.SCANNER_ENABLED -> editor.putBoolean(key, value as Boolean)\n                Exposure.LAST_CLEANUP -> editor.putLong(key, value as Long)\n                else -> throw IllegalArgumentException(\"Unknown key: $key\")\n            }\n        }\n        editor.apply()\n    }\n\n    private fun querySafetyNet(p: Array<out String>): Cursor = MatrixCursor(p).addRow(p) { key ->\n        when (key) {\n            SafetyNet.ENABLED -> getSettingsBoolean(key, false)\n            else -> throw IllegalArgumentException(\"Unknown key: $key\")\n        }\n    }\n\n    private fun updateSafetyNet(values: ContentValues) {\n        if (values.size() == 0) return\n        val editor = preferences.edit()\n        values.valueSet().forEach { (key, value) ->\n            when (key) {\n                SafetyNet.ENABLED -> editor.putBoolean(key, value as Boolean)\n                else -> throw IllegalArgumentException(\"Unknown key: $key\")\n            }\n        }\n        editor.apply()\n    }\n\n    private fun queryDroidGuard(p: Array<out String>): Cursor = MatrixCursor(p).addRow(p) { key ->\n        when (key) {\n            DroidGuard.ENABLED -> getSettingsBoolean(key, false)\n            DroidGuard.MODE -> getSettingsString(key)\n            DroidGuard.NETWORK_SERVER_URL -> getSettingsString(key)\n            DroidGuard.FORCE_LOCAL_DISABLED -> systemDefaultPreferences?.getBoolean(key, false) ?: false\n            DroidGuard.HARDWARE_ATTESTATION_BLOCKED -> getSettingsBoolean(key, true)\n            else -> throw IllegalArgumentException(\"Unknown key: $key\")\n        }\n    }\n\n    private fun updateDroidGuard(values: ContentValues) {\n        if (values.size() == 0) return\n        val editor = preferences.edit()\n        values.valueSet().forEach { (key, value) ->\n            when (key) {\n                DroidGuard.ENABLED -> editor.putBoolean(key, value as Boolean)\n                DroidGuard.MODE -> editor.putString(key, value as String)\n                DroidGuard.NETWORK_SERVER_URL -> editor.putString(key, value as String)\n                DroidGuard.HARDWARE_ATTESTATION_BLOCKED -> editor.putBoolean(key, value as Boolean)\n                else -> throw IllegalArgumentException(\"Unknown key: $key\")\n            }\n        }\n        editor.apply()\n    }\n\n    private fun queryProfile(p: Array<out String>): Cursor = MatrixCursor(p).addRow(p) { key ->\n        when (key) {\n            Profile.PROFILE -> getSettingsString(key, \"auto\")\n            Profile.SERIAL -> getSettingsString(key)\n            else -> throw IllegalArgumentException(\"Unknown key: $key\")\n        }\n    }\n\n    private fun updateProfile(values: ContentValues) {\n        if (values.size() == 0) return\n        val editor = preferences.edit()\n        values.valueSet().forEach { (key, value) ->\n            when (key) {\n                Profile.PROFILE -> editor.putString(key, value as String?)\n                Profile.SERIAL -> editor.putString(key, value as String?)\n                else -> throw IllegalArgumentException(\"Unknown key: $key\")\n            }\n        }\n        editor.apply()\n    }\n\n    private fun queryLocation(p: Array<out String>): Cursor = MatrixCursor(p).addRow(p) { key ->\n        when (key) {\n            Location.WIFI_ICHNAEA -> getSettingsBoolean(key, hasUnifiedNlpLocationBackend(\"org.microg.nlp.backend.ichnaea\"))\n            Location.WIFI_MOVING -> getSettingsBoolean(key, hasUnifiedNlpLocationBackend(\"de.sorunome.unifiednlp.trains\"))\n            Location.WIFI_LEARNING -> getSettingsBoolean(key, false)\n            Location.WIFI_CACHING -> getSettingsBoolean(key, getSettingsBoolean(Location.WIFI_LEARNING, false) == 1)\n            Location.CELL_ICHNAEA -> getSettingsBoolean(key, hasUnifiedNlpLocationBackend(\"org.microg.nlp.backend.ichnaea\"))\n            Location.CELL_LEARNING -> getSettingsBoolean(key, true)\n            Location.CELL_CACHING -> getSettingsBoolean(key, getSettingsBoolean(Location.CELL_LEARNING, true) == 1)\n            Location.GEOCODER_NOMINATIM -> getSettingsBoolean(key, hasUnifiedNlpGeocoderBackend(\"org.microg.nlp.backend.nominatim\") )\n            Location.ICHNAEA_ENDPOINT -> getSettingsString(key, null)\n            Location.ONLINE_SOURCE -> getSettingsString(key, null)\n            Location.ICHNAEA_CONTRIBUTE -> getSettingsBoolean(key, false)\n            else -> throw IllegalArgumentException(\"Unknown key: $key\")\n        }\n    }\n    private fun hasUnifiedNlpPrefixInStringSet(key: String, vararg prefixes: String) = getUnifiedNlpSettingsStringSetCompat(key, emptySet()).any { entry -> prefixes.any { prefix -> entry.startsWith(prefix)}}\n    private fun hasUnifiedNlpLocationBackend(vararg packageNames: String) = hasUnifiedNlpPrefixInStringSet(\"location_backends\", *packageNames.map { \"$it/\" }.toTypedArray())\n    private fun hasUnifiedNlpGeocoderBackend(vararg packageNames: String) = hasUnifiedNlpPrefixInStringSet(\"geocoder_backends\", *packageNames.map { \"$it/\" }.toTypedArray())\n\n    private fun updateLocation(values: ContentValues) {\n        if (values.size() == 0) return\n        val editor = preferences.edit()\n        values.valueSet().forEach { (key, value) ->\n            when (key) {\n                Location.WIFI_ICHNAEA -> editor.putBoolean(key, value as Boolean)\n                Location.WIFI_MOVING -> editor.putBoolean(key, value as Boolean)\n                Location.WIFI_LEARNING -> editor.putBoolean(key, value as Boolean)\n                Location.CELL_ICHNAEA -> editor.putBoolean(key, value as Boolean)\n                Location.CELL_LEARNING -> editor.putBoolean(key, value as Boolean)\n                Location.GEOCODER_NOMINATIM -> editor.putBoolean(key, value as Boolean)\n                Location.ICHNAEA_ENDPOINT -> (value as String).let { if (it.isBlank()) editor.remove(key) else editor.putString(key, it) }\n                Location.ONLINE_SOURCE -> (value as? String?).let { if (it.isNullOrBlank()) editor.remove(key) else editor.putString(key, it) }\n                Location.ICHNAEA_CONTRIBUTE -> editor.putBoolean(key, value as Boolean)\n                else -> throw IllegalArgumentException(\"Unknown key: $key\")\n            }\n        }\n        editor.apply()\n    }\n\n    private fun queryVending(p: Array<out String>): Cursor = MatrixCursor(p).addRow(p) { key ->\n        when (key) {\n            Vending.LICENSING -> getSettingsBoolean(key, false)\n            Vending.LICENSING_PURCHASE_FREE_APPS -> getSettingsBoolean(key, false)\n            Vending.BILLING -> getSettingsBoolean(key, false)\n            Vending.ASSET_DELIVERY -> getSettingsBoolean(key, false)\n            Vending.ASSET_DEVICE_SYNC -> getSettingsBoolean(key, false)\n            Vending.SPLIT_INSTALL -> getSettingsBoolean(key, false)\n            Vending.APPS_INSTALL -> getSettingsBoolean(key, false)\n            Vending.APPS_INSTALLER_LIST -> getSettingsString(key, \"\")\n            Vending.PLAY_INTEGRITY_APP_LIST -> getSettingsString(key, \"\")\n            else -> throw IllegalArgumentException(\"Unknown key: $key\")\n        }\n    }\n\n    private fun updateVending(values: ContentValues) {\n        if (values.size() == 0) return\n        val editor = preferences.edit()\n        values.valueSet().forEach { (key, value) ->\n            when (key) {\n                Vending.LICENSING -> editor.putBoolean(key, value as Boolean)\n                Vending.LICENSING_PURCHASE_FREE_APPS -> editor.putBoolean(key, value as Boolean)\n                Vending.BILLING -> editor.putBoolean(key, value as Boolean)\n                Vending.SPLIT_INSTALL -> editor.putBoolean(key, value as Boolean)\n                Vending.ASSET_DELIVERY -> editor.putBoolean(key, value as Boolean)\n                Vending.ASSET_DEVICE_SYNC -> editor.putBoolean(key, value as Boolean)\n                Vending.APPS_INSTALL -> editor.putBoolean(key, value as Boolean)\n                Vending.APPS_INSTALLER_LIST -> editor.putString(key, value as String)\n                Vending.PLAY_INTEGRITY_APP_LIST -> editor.putString(key, value as String)\n                else -> throw IllegalArgumentException(\"Unknown key: $key\")\n            }\n        }\n        editor.apply()\n    }\n\n    private fun queryWorkProfile(p: Array<out String>): Cursor = MatrixCursor(p).addRow(p) { key ->\n        when (key) {\n            WorkProfile.CREATE_WORK_ACCOUNT -> getSettingsBoolean(key, false)\n            else -> throw IllegalArgumentException(\"Unknown key: $key\")\n        }\n    }\n\n    private fun updateWorkProfile(values: ContentValues) {\n        if (values.size() == 0) return\n        val editor = preferences.edit()\n        values.valueSet().forEach { (key, value) ->\n            when (key) {\n                WorkProfile.CREATE_WORK_ACCOUNT -> editor.putBoolean(key, value as Boolean)\n                else -> throw IllegalArgumentException(\"Unknown key: $key\")\n            }\n        }\n        editor.apply()\n    }\n\n    private fun queryGameProfile(p: Array<out String>): Cursor = MatrixCursor(p).addRow(p) { key ->\n        when (key) {\n            GameProfile.ALLOW_CREATE_PLAYER -> getSettingsBoolean(key, false)\n            GameProfile.ALLOW_UPLOAD_GAME_PLAYED -> getSettingsBoolean(key, false)\n            else -> throw IllegalArgumentException(\"Unknown key: $key\")\n        }\n    }\n\n    private fun updateGameProfile(values: ContentValues) {\n        if (values.size() == 0) return\n        val editor = preferences.edit()\n        values.valueSet().forEach { (key, value) ->\n            when (key) {\n                GameProfile.ALLOW_CREATE_PLAYER -> editor.putBoolean(key, value as Boolean)\n                GameProfile.ALLOW_UPLOAD_GAME_PLAYED -> editor.putBoolean(key, value as Boolean)\n                else -> throw IllegalArgumentException(\"Unknown key: $key\")\n            }\n        }\n        editor.apply()\n    }\n\n    private fun MatrixCursor.addRow(\n        p: Array<out String>,\n        valueGetter: (String) -> Any?\n    ): MatrixCursor {\n        val row = newRow()\n        for (key in p) row.add(valueGetter.invoke(key))\n        return this\n    }\n\n    override fun getType(uri: Uri): String {\n        return \"vnd.android.cursor.item/vnd.${getAuthority(context!!)}.${uri.path}\"\n    }\n\n    override fun insert(uri: Uri, values: ContentValues?): Uri? {\n        throw UnsupportedOperationException()\n    }\n\n    override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int {\n        throw UnsupportedOperationException()\n    }\n\n    /**\n     * Returns the current setting of the given [key]\n     * using the default value from [systemDefaultPreferences] or [def] if not available.\n     * @return the current setting as [Int], because [ContentProvider] does not support [Boolean].\n     */\n    private fun getSettingsBoolean(key: String, def: Boolean): Int {\n        return listOf(preferences, systemDefaultPreferences, metaDataPreferences).getBooleanAsInt(key, def)\n    }\n\n    private fun getSettingsString(key: String, def: String? = null): String? = listOf(preferences, systemDefaultPreferences, metaDataPreferences).getString(key, def)\n    private fun getSettingsInt(key: String, def: Int): Int = listOf(preferences, systemDefaultPreferences, metaDataPreferences).getInt(key, def)\n    private fun getSettingsLong(key: String, def: Long): Long = listOf(preferences, systemDefaultPreferences, metaDataPreferences).getLong(key, def)\n    private fun getUnifiedNlpSettingsStringSetCompat(key: String, def: Set<String>): Set<String> = listOf(unifiedNlpPreferences, preferences, systemDefaultPreferences).getStringSetCompat(key, def)\n\n    private fun SharedPreferences.getStringSetCompat(key: String, def: Set<String>): Set<String> {\n        if (SDK_INT >= 11) {\n            try {\n                val res = getStringSet(key, null)\n                if (res != null) return res.filter { it.isNotEmpty() }.toSet()\n            } catch (ignored: Exception) {\n                // Ignore\n            }\n        }\n        try {\n            val str = getString(key, null)\n            if (str != null) return str.split(\"\\\\|\".toRegex()).filter { it.isNotEmpty() }.toSet()\n        } catch (ignored: Exception) {\n            // Ignore\n        }\n        return def\n    }\n\n    private fun List<SharedPreferences?>.getStringSetCompat(key: String, def: Set<String>): Set<String> = foldRight(def) { preferences, defValue -> preferences?.getStringSetCompat(key, defValue) ?: defValue }\n    private fun List<SharedPreferences?>.getString(key: String, def: String?): String? = foldRight(def) { preferences, defValue -> preferences?.getString(key, defValue) ?: defValue }\n    private fun List<SharedPreferences?>.getInt(key: String, def: Int): Int = foldRight(def) { preferences, defValue -> preferences?.getInt(key, defValue) ?: defValue }\n    private fun List<SharedPreferences?>.getLong(key: String, def: Long): Long = foldRight(def) { preferences, defValue -> preferences?.getLong(key, defValue) ?: defValue }\n    private fun List<SharedPreferences?>.getBoolean(key: String, def: Boolean): Boolean = foldRight(def) { preferences, defValue -> preferences?.getBoolean(key, defValue) ?: defValue }\n    private fun List<SharedPreferences?>.getBooleanAsInt(key: String, def: Boolean): Int = if (getBoolean(key, def)) 1 else 0\n}\n"
  },
  {
    "path": "play-services-base/core/src/main/kotlin/org/microg/gms/ui/AppHeadingPreference.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.ui\n\nimport android.content.Context\nimport android.content.Intent\nimport android.content.pm.ApplicationInfo\nimport android.net.Uri\nimport android.provider.Settings\nimport android.util.AttributeSet\nimport android.util.Log\nimport android.view.View\nimport android.widget.ImageView\nimport androidx.appcompat.content.res.AppCompatResources\nimport androidx.preference.Preference\nimport androidx.preference.PreferenceViewHolder\nimport org.microg.gms.base.core.R\n\nclass AppHeadingPreference : AppPreference, Preference.OnPreferenceClickListener {\n    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)\n    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)\n    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)\n    constructor(context: Context) : super(context)\n\n    init {\n        layoutResource = R.layout.preference_app_heading\n        onPreferenceClickListener = this\n    }\n\n    override fun onPreferenceClick(preference: Preference): Boolean {\n        if (packageName != null) {\n            val intent = Intent()\n            intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS\n            val uri: Uri = Uri.fromParts(\"package\", packageName, null)\n            intent.data = uri\n            try {\n                context.startActivity(intent)\n            } catch (e: Exception) {\n                Log.w(TAG, \"Failed to launch app\", e)\n            }\n            return true\n        } else {\n            return false\n        }\n    }\n}"
  },
  {
    "path": "play-services-base/core/src/main/kotlin/org/microg/gms/ui/AppIconPreference.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.ui\n\nimport android.content.Context\nimport android.content.pm.ApplicationInfo\nimport android.util.AttributeSet\nimport android.util.DisplayMetrics\nimport android.widget.ImageView\nimport androidx.appcompat.content.res.AppCompatResources\nimport androidx.preference.Preference\nimport androidx.preference.PreferenceViewHolder\n\nclass AppIconPreference : AppPreference {\n    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)\n    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)\n    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)\n    constructor(context: Context) : super(context)\n\n    override fun onBindViewHolder(holder: PreferenceViewHolder) {\n        super.onBindViewHolder(holder)\n        val icon = holder.findViewById(android.R.id.icon)\n        if (icon is ImageView) {\n            icon.adjustViewBounds = true\n            icon.scaleType = ImageView.ScaleType.CENTER_INSIDE\n            icon.maxHeight = (32.0 * context.resources.displayMetrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT).toInt()\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-base/core/src/main/kotlin/org/microg/gms/ui/AppPreference.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.ui\n\nimport android.content.Context\nimport android.content.pm.ApplicationInfo\nimport android.util.AttributeSet\nimport androidx.appcompat.content.res.AppCompatResources\nimport androidx.preference.Preference\n\nabstract class AppPreference : Preference {\n    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)\n    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)\n    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)\n    constructor(context: Context) : super(context)\n\n    init {\n        isPersistent = false\n    }\n\n    private var packageNameField: String? = null\n\n    var applicationInfo: ApplicationInfo?\n        get() = context.packageManager.getApplicationInfoIfExists(packageNameField)\n        set(value) {\n            if (value == null && packageNameField != null) {\n                title = null\n                icon = null\n            } else if (value != null) {\n                val pm = context.packageManager\n                title = value.loadLabel(pm) ?: value.packageName\n                icon = value.loadIcon(pm) ?: AppCompatResources.getDrawable(context, android.R.mipmap.sym_def_app_icon)\n            }\n            packageNameField = value?.packageName\n        }\n\n    var packageName: String?\n        get() = packageNameField\n        set(value) {\n            if (value == null && packageNameField != null) {\n                title = null\n                icon = null\n            } else if (value != null) {\n                val pm = context.packageManager\n                val applicationInfo = pm.getApplicationInfoIfExists(value)\n                title = applicationInfo?.loadLabel(pm)?.toString() ?: value\n                icon = applicationInfo?.loadIcon(pm) ?: AppCompatResources.getDrawable(context, android.R.mipmap.sym_def_app_icon)\n            }\n            packageNameField = value\n        }\n}"
  },
  {
    "path": "play-services-base/core/src/main/kotlin/org/microg/gms/ui/Constants.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.ui\n\nconst val TAG = \"GmsUi\"\n"
  },
  {
    "path": "play-services-base/core/src/main/kotlin/org/microg/gms/ui/FooterPreference.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.ui\n\nimport android.content.Context\nimport android.util.AttributeSet\nimport android.util.TypedValue\nimport android.view.Gravity\nimport android.view.ViewGroup.LayoutParams.MATCH_PARENT\nimport android.widget.LinearLayout\nimport android.widget.TextView\nimport androidx.preference.Preference\nimport androidx.preference.PreferenceViewHolder\nimport org.microg.gms.base.core.R\n\nclass FooterPreference : Preference {\n    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)\n    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)\n    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)\n    constructor(context: Context) : super(context)\n\n    init {\n        layoutResource = R.layout.preference_footer\n        if (icon == null) setIcon(R.drawable.ic_info_outline)\n    }\n}\n"
  },
  {
    "path": "play-services-base/core/src/main/kotlin/org/microg/gms/ui/SwitchBarPreference.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.ui\n\nimport android.content.Context\nimport android.graphics.drawable.Drawable\nimport android.util.AttributeSet\nimport androidx.appcompat.widget.SwitchCompat\nimport androidx.core.content.res.TypedArrayUtils\nimport androidx.preference.PreferenceViewHolder\nimport androidx.preference.TwoStatePreference\nimport org.microg.gms.base.core.R\n\n// TODO\nclass SwitchBarPreference : TwoStatePreference {\n    private val frameId: Int\n    private val backgroundOn: Drawable?\n    private val backgroundOff: Drawable?\n    private val backgroundDisabled: Drawable?\n\n    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {\n        val a = context.obtainStyledAttributes(attrs, R.styleable.SwitchBarPreference, defStyleAttr, defStyleRes)\n        frameId = a.getResourceId(R.styleable.SwitchBarPreference_switchBarFrameId, 0)\n        backgroundOn = a.getDrawable(R.styleable.SwitchBarPreference_switchBarFrameBackgroundOn)\n        backgroundOff = a.getDrawable(R.styleable.SwitchBarPreference_switchBarFrameBackgroundOff)\n        backgroundDisabled = a.getDrawable(R.styleable.SwitchBarPreference_switchBarFrameBackgroundDisabled)\n    }\n    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : this(context, attrs, defStyleAttr, R.style.Preference_SwitchBar)\n    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, R.attr.switchBarPreferenceStyle)\n    constructor(context: Context) : this(context, null)\n\n    override fun onBindViewHolder(holder: PreferenceViewHolder) {\n        super.onBindViewHolder(holder)\n        holder.isDividerAllowedBelow = false\n        holder.isDividerAllowedAbove = false\n        val switch = holder.findViewById(R.id.switch_widget) as SwitchCompat\n        switch.setOnCheckedChangeListener(null)\n        switch.isChecked = isChecked\n        switch.setOnCheckedChangeListener { view, isChecked ->\n            if (!callChangeListener(isChecked)) {\n                view.isChecked = !isChecked\n                return@setOnCheckedChangeListener\n            }\n            this.isChecked = isChecked\n        }\n        val frame = if (frameId == 0) null else holder.findViewById(frameId)\n        val backgroundView = frame ?: holder.itemView\n        val (backgroundDrawable, backgroundColorAttribute) = when {\n            !isEnabled -> Pair(backgroundDisabled, androidx.appcompat.R.attr.colorControlHighlight)\n            isChecked -> Pair(backgroundOn, androidx.appcompat.R.attr.colorControlActivated)\n            else -> Pair(backgroundOff, androidx.appcompat.R.attr.colorButtonNormal)\n        }\n        if (backgroundDrawable != null) {\n            backgroundView.setBackgroundDrawable(backgroundDrawable)\n        } else {\n            backgroundView.setBackgroundColorAttribute(backgroundColorAttribute)\n        }\n    }\n}"
  },
  {
    "path": "play-services-base/core/src/main/kotlin/org/microg/gms/ui/TextPreference.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.ui\n\nimport android.content.Context\nimport android.util.AttributeSet\nimport android.util.TypedValue\nimport android.view.Gravity\nimport android.view.ViewGroup.LayoutParams.MATCH_PARENT\nimport android.widget.LinearLayout\nimport android.widget.TextView\nimport androidx.preference.Preference\nimport androidx.preference.PreferenceViewHolder\n\nclass TextPreference : Preference {\n    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)\n    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)\n    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)\n    constructor(context: Context) : super(context)\n\n\n    override fun onBindViewHolder(holder: PreferenceViewHolder) {\n        super.onBindViewHolder(holder)\n        val iconFrame = holder?.findViewById(androidx.preference.R.id.icon_frame)\n        iconFrame?.layoutParams?.height = MATCH_PARENT\n        (iconFrame as? LinearLayout)?.gravity = Gravity.TOP or Gravity.START\n        val pad = (context.resources.displayMetrics.densityDpi/160f * 20).toInt()\n        iconFrame?.setPadding(0, pad, 0, pad)\n        val textView = holder?.findViewById(android.R.id.summary) as? TextView\n        textView?.maxLines = Int.MAX_VALUE\n    }\n}\n"
  },
  {
    "path": "play-services-base/core/src/main/kotlin/org/microg/gms/ui/Utils.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.ui\n\nimport android.content.Context\nimport android.content.pm.ApplicationInfo\nimport android.content.pm.PackageManager\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.Bundle\nimport android.provider.Settings\nimport android.util.Log\nimport android.util.TypedValue\nimport android.view.View\nimport androidx.annotation.AttrRes\nimport androidx.annotation.ColorInt\nimport androidx.annotation.IdRes\nimport androidx.appcompat.app.AlertDialog\nimport androidx.core.content.ContextCompat\nimport androidx.databinding.BindingAdapter\nimport androidx.navigation.NavController\nimport androidx.navigation.navOptions\nimport androidx.navigation.ui.R\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder\n\nfun PackageManager.getApplicationInfoIfExists(packageName: String?, flags: Int = 0): ApplicationInfo? = packageName?.let {\n    try {\n        getApplicationInfo(it, flags)\n    } catch (e: Exception) {\n        Log.w(TAG, \"Package $packageName not installed.\")\n        null\n    }\n}\n\nfun NavController.navigate(context: Context, @IdRes resId: Int, args: Bundle? = null) {\n    navigate(resId, args, if (context.systemAnimationsEnabled) navOptions {\n        anim {\n            enter = R.anim.nav_default_enter_anim\n            exit = R.anim.nav_default_exit_anim\n            popEnter = R.anim.nav_default_pop_enter_anim\n            popExit = R.anim.nav_default_pop_exit_anim\n        }\n    } else null)\n}\n\nval Context.systemAnimationsEnabled: Boolean\n    get() {\n        val duration: Float\n        val transition: Float\n        if (SDK_INT >= 17) {\n            duration = Settings.Global.getFloat(contentResolver, Settings.Global.ANIMATOR_DURATION_SCALE, 1f)\n            transition = Settings.Global.getFloat(contentResolver, Settings.Global.TRANSITION_ANIMATION_SCALE, 1f)\n        } else {\n            duration = Settings.System.getFloat(contentResolver, Settings.System.ANIMATOR_DURATION_SCALE, 1f)\n            transition = Settings.System.getFloat(contentResolver, Settings.System.TRANSITION_ANIMATION_SCALE, 1f)\n        }\n        return duration != 0f && transition != 0f\n    }\n\nfun Context.buildAlertDialog() = try {\n    // Try material design first\n    MaterialAlertDialogBuilder(this)\n} catch (e: Exception) {\n    AlertDialog.Builder(this)\n}\n\n@ColorInt\nfun Context.resolveColor(@AttrRes resid: Int): Int? {\n    val typedValue = TypedValue()\n    if (!theme.resolveAttribute(resid, typedValue, true)) return null\n    val colorRes = if (typedValue.resourceId != 0) typedValue.resourceId else typedValue.data\n    return ContextCompat.getColor(this, colorRes)\n}\n\n@BindingAdapter(\"app:backgroundColorAttr\")\nfun View.setBackgroundColorAttribute(@AttrRes resId: Int) = context.resolveColor(resId)?.let { setBackgroundColor(it) }\n"
  },
  {
    "path": "play-services-base/core/src/main/kotlin/org/microg/gms/ui/settings/SettingsProvider.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.ui.settings\n\nimport android.content.Context\nimport android.content.Intent\nimport android.content.pm.PackageManager\nimport android.graphics.drawable.Drawable\nimport android.os.Bundle\nimport android.util.Log\nimport androidx.navigation.NavController\n\nprivate const val TAG = \"SettingsProvider\"\n\ninterface SettingsProvider {\n    fun getEntriesStatic(context: Context): List<Entry>\n    suspend fun getEntriesDynamic(context: Context): List<Entry> = getEntriesStatic(context)\n\n    fun preProcessSettingsIntent(intent: Intent)\n\n    fun extendNavigation(navController: NavController)\n\n    companion object {\n        enum class Group {\n            HEADER,\n            GOOGLE,\n            OTHER,\n            FOOTER\n        }\n\n        data class Entry(\n            val key: String,\n            val group: Group,\n            val navigationId: Int,\n            val title: String,\n            val summary: String? = null,\n            val icon: Drawable? = null,\n        )\n    }\n}\n\nfun getAllSettingsProviders(context: Context): List<SettingsProvider> {\n    val metaData = runCatching { context.packageManager.getApplicationInfo(context.packageName, PackageManager.GET_META_DATA).metaData }.getOrNull() ?: Bundle.EMPTY\n    return metaData.keySet().asSequence().filter {\n        it.startsWith(\"org.microg.gms.ui.settings.entry:\")\n    }.mapNotNull {\n        runCatching { metaData.getString(it) }.onFailure { Log.w(TAG, it) }.getOrNull()\n    }.mapNotNull {\n        runCatching { Class.forName(it) }.onFailure { Log.w(TAG, it) }.getOrNull()\n    }.filter {\n        SettingsProvider::class.java.isAssignableFrom(it)\n    }.mapNotNull {\n        runCatching { it.getDeclaredField(\"INSTANCE\").get(null) as SettingsProvider }.onFailure { Log.w(TAG, it) }.getOrNull()\n    }.toList()\n}"
  },
  {
    "path": "play-services-base/core/src/main/kotlin/org/microg/gms/utils/BinderUtils.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.utils\n\nimport android.os.Binder\nimport android.os.IBinder\nimport android.os.Parcel\nimport android.util.Log\n\nprivate const val TAG = \"BinderUtils\"\n\nfun IBinder.warnOnTransactionIssues(code: Int, reply: Parcel?, flags: Int, tag: String = TAG, base: () -> Boolean): Boolean {\n    if (base.invoke()) {\n        if ((flags and Binder.FLAG_ONEWAY) > 0 && (reply?.dataSize() ?: 0) > 0) {\n            Log.w(tag, \"Method $code in $interfaceDescriptor is oneway, but returned data\")\n        }\n        return true\n    }\n    Log.w(tag, \"Unknown method $code in $interfaceDescriptor, skipping\")\n    return (flags and Binder.FLAG_ONEWAY) > 0 // Don't return false on oneway transaction to suppress warning\n}\n"
  },
  {
    "path": "play-services-base/core/src/main/kotlin/org/microg/gms/utils/BitmapUtils.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.utils\n\nimport android.graphics.Bitmap\nimport kotlin.math.sqrt\n\nobject BitmapUtils {\n\n    fun getBitmapSize(bitmap: Bitmap?): Int {\n        if (bitmap != null) {\n            return bitmap.height * bitmap.rowBytes\n        }\n        return 0\n    }\n\n    fun scaledBitmap(bitmap: Bitmap, maxSize: Float): Bitmap {\n        val height: Int = bitmap.getHeight()\n        val width: Int = bitmap.getWidth()\n        val sqrt =\n            sqrt(((maxSize) / ((width.toFloat()) / (height.toFloat()) * ((bitmap.getRowBytes() / width).toFloat()))).toDouble())\n                .toInt()\n        return Bitmap.createScaledBitmap(\n            bitmap,\n            (((sqrt.toFloat()) / (height.toFloat()) * (width.toFloat())).toInt()),\n            sqrt,\n            true\n        )\n    }\n}"
  },
  {
    "path": "play-services-base/core/src/main/kotlin/org/microg/gms/utils/ExtendedPackageInfo.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.utils\n\nimport android.content.Context\nimport android.content.pm.PackageManager\nimport androidx.core.content.pm.PackageInfoCompat\nimport org.microg.gms.common.*\n\nclass ExtendedPackageInfo(private val packageManager: PackageManager, val packageName: String) {\n    constructor(context: Context, packageName: String) : this(context.packageManager, packageName)\n\n    private val basicPackageInfo by lazy { kotlin.runCatching { packageManager.getPackageInfo(packageName, 0) }.getOrNull() }\n    private val basicApplicationInfo by lazy { kotlin.runCatching { packageManager.getApplicationInfo(packageName, 0) }.getOrNull() }\n\n    val isInstalled by lazy { basicPackageInfo != null }\n\n    val certificates by lazy { packageManager.getCertificates(packageName) }\n    private val certificatesHashSha1 by lazy { certificates.map { it.digest(\"SHA1\") } }\n    val firstCertificateSha1 by lazy { certificatesHashSha1.firstOrNull() }\n    val firstCertificateSha1Hex by lazy { firstCertificateSha1?.toHexString() }\n    private val certificatesHashSha256 by lazy { certificates.map { it.digest(\"SHA-256\") } }\n    val firstCertificateSha256 by lazy { certificatesHashSha256.firstOrNull() }\n    private val certificatesHashSha1Strings by lazy { certificatesHashSha1.map { it.toHexString() } }\n    private val certificatesHashSha256Strings by lazy { certificatesHashSha256.map { it.toHexString() } }\n\n    val applicationLabel by lazy { packageManager.getApplicationLabel(packageName) }\n\n    @Deprecated(\"version code is now a long\", replaceWith = ReplaceWith(\"versionCode\"))\n    val shortVersionCode by lazy { basicPackageInfo?.versionCode ?: -1 }\n    val versionCode by lazy { basicPackageInfo?.let { PackageInfoCompat.getLongVersionCode(it) } ?: -1 }\n    val versionName by lazy { basicPackageInfo?.versionName }\n\n    val targetSdkVersion by lazy { basicApplicationInfo?.targetSdkVersion ?: -1 }\n\n    private val packageAndCertHashes by lazy {\n        listOf(\n            certificatesHashSha1Strings.map { PackageAndCertHash(packageName, \"SHA1\", it) },\n            certificatesHashSha256Strings.map { PackageAndCertHash(packageName, \"SHA-256\", it) },\n        ).flatten()\n    }\n    val isGooglePackage by lazy { packageAndCertHashes.any { isGooglePackage(it) } }\n    val isPlatformPackage by lazy {\n        val platformCertificates = packageManager.getPlatformCertificates()\n        certificates.any { it in platformCertificates }\n    }\n    val isGoogleOrPlatformPackage by lazy { isGooglePackage || isPlatformPackage }\n\n    private val googlePackagePermissions by lazy { packageAndCertHashes.flatMap { getGooglePackagePermissions(it) }.toSet() }\n    fun hasGooglePackagePermission(permission: GooglePackagePermission) = permission in googlePackagePermissions\n}"
  },
  {
    "path": "play-services-base/core/src/main/kotlin/org/microg/gms/utils/FileXmlResourceParser.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.utils\n\nimport android.content.res.XmlResourceParser\nimport android.util.Xml\nimport org.xmlpull.v1.XmlPullParser\nimport java.io.Closeable\nimport java.io.File\nimport java.io.FileReader\nimport java.io.Reader\n\nclass FileXmlResourceParser(private val reader: Reader, private val parser: XmlPullParser = Xml.newPullParser()) :\n    XmlResourceParser,\n    XmlPullParser by parser,\n    Closeable by reader {\n    constructor(file: File) : this(FileReader(file))\n\n    init {\n        parser.setInput(reader)\n    }\n\n    override fun getAttributeNameResource(index: Int): Int {\n        return 0\n    }\n\n    override fun getAttributeListValue(\n        namespace: String?, attribute: String?,\n        options: Array<String?>?, defaultValue: Int\n    ): Int {\n        val s = getAttributeValue(namespace, attribute)\n        return s?.toInt() ?: defaultValue\n    }\n\n    override fun getAttributeBooleanValue(\n        namespace: String?, attribute: String?,\n        defaultValue: Boolean\n    ): Boolean {\n\n        val s = getAttributeValue(namespace, attribute)\n        return s?.toBooleanStrictOrNull() ?: defaultValue\n    }\n\n    override fun getAttributeResourceValue(\n        namespace: String?, attribute: String?,\n        defaultValue: Int\n    ): Int {\n        val s = getAttributeValue(namespace, attribute)\n        return s?.toInt() ?: defaultValue\n    }\n\n    override fun getAttributeIntValue(\n        namespace: String?, attribute: String?,\n        defaultValue: Int\n    ): Int {\n        val s = getAttributeValue(namespace, attribute)\n        return s?.toInt() ?: defaultValue\n    }\n\n    override fun getAttributeUnsignedIntValue(\n        namespace: String?, attribute: String?,\n        defaultValue: Int\n    ): Int {\n        val s = getAttributeValue(namespace, attribute)\n        return s?.toInt() ?: defaultValue\n    }\n\n    override fun getAttributeFloatValue(\n        namespace: String?, attribute: String?,\n        defaultValue: Float\n    ): Float {\n        val s = getAttributeValue(namespace, attribute)\n        return s?.toFloat() ?: defaultValue\n    }\n\n    override fun getAttributeListValue(\n        index: Int,\n        options: Array<String?>?, defaultValue: Int\n    ): Int {\n        val s = getAttributeValue(index)\n        return s?.toInt() ?: defaultValue\n    }\n\n    override fun getAttributeBooleanValue(index: Int, defaultValue: Boolean): Boolean {\n        val s = getAttributeValue(index)\n        return s?.toBooleanStrictOrNull() ?: defaultValue\n    }\n\n    override fun getAttributeResourceValue(index: Int, defaultValue: Int): Int {\n        val s = getAttributeValue(index)\n        return s?.toInt() ?: defaultValue\n    }\n\n    override fun getAttributeIntValue(index: Int, defaultValue: Int): Int {\n        val s = getAttributeValue(index)\n        return s?.toInt() ?: defaultValue\n    }\n\n    override fun getAttributeUnsignedIntValue(index: Int, defaultValue: Int): Int {\n        val s = getAttributeValue(index)\n        return s?.toInt() ?: defaultValue\n    }\n\n    override fun getAttributeFloatValue(index: Int, defaultValue: Float): Float {\n        val s = getAttributeValue(index)\n        return s?.toFloat() ?: defaultValue\n    }\n\n    override fun getIdAttribute(): String? {\n        return getAttributeValue(null, \"id\")\n    }\n\n    override fun getClassAttribute(): String? {\n        return getAttributeValue(null, \"class\")\n    }\n\n    override fun getIdAttributeResourceValue(defaultValue: Int): Int {\n        return getAttributeResourceValue(null, \"id\", defaultValue)\n    }\n\n    override fun getStyleAttribute(): Int {\n        return getAttributeResourceValue(null, \"style\", 0)\n    }\n}\n"
  },
  {
    "path": "play-services-base/core/src/main/kotlin/org/microg/gms/utils/IntentCacheManager.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.utils\n\nimport android.app.AlarmManager\nimport android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP\nimport android.app.PendingIntent.FLAG_NO_CREATE\nimport android.app.PendingIntent.FLAG_UPDATE_CURRENT\nimport android.app.Service\nimport android.content.Context\nimport android.content.Intent\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.Parcelable\nimport android.os.SystemClock\nimport android.util.Log\nimport androidx.core.app.PendingIntentCompat\nimport androidx.core.content.getSystemService\nimport java.util.UUID\n\nclass IntentCacheManager<S : Service, T : Parcelable>(private val context: Context, private val clazz: Class<S>, private val type: Int) {\n    private val lock = Any()\n    private lateinit var content: ArrayList<T>\n    private lateinit var id: String\n    private var isReady: Boolean = false\n    private val pendingActions: MutableList<() -> Unit> = arrayListOf()\n\n    init {\n        val pendingIntent = PendingIntentCompat.getService(context, type, getIntent(), 0, true)!!\n        val alarmManager = context.getSystemService<AlarmManager>()\n        if (SDK_INT >= 19) {\n            alarmManager?.setWindow(ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + TEN_YEARS, -1, pendingIntent)\n        } else {\n            alarmManager?.set(ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + TEN_YEARS, pendingIntent)\n        }\n        pendingIntent.send()\n    }\n\n    private fun getIntent() = Intent(context, clazz).apply {\n        action = ACTION\n        putExtra(EXTRA_IS_CACHE, true)\n        putExtra(EXTRA_CACHE_TYPE, this@IntentCacheManager.type)\n    }\n\n    fun add(entry: T, check: (T) -> Boolean = { false }) = runIfReady {\n        val iterator = content.iterator()\n        while (iterator.hasNext()) {\n            if (check(iterator.next())) {\n                iterator.remove()\n            }\n        }\n        content.add(entry)\n        updateIntent()\n    }\n\n    fun remove(entry: T) = runIfReady {\n        if (content.remove(entry)) updateIntent()\n    }\n\n    fun removeIf(check: (T) -> Boolean) = runIfReady {\n        var removed = false\n        val iterator = content.iterator()\n        while (iterator.hasNext()) {\n            if (check(iterator.next())) {\n                iterator.remove()\n                removed = true\n            }\n        }\n        if (removed) updateIntent()\n    }\n\n    fun clear() = runIfReady {\n        content.clear()\n        updateIntent()\n    }\n\n    fun getId(): String? = if (this::id.isInitialized) id else null\n\n    fun getEntries(): List<T> = if (this::content.isInitialized) content else emptyList()\n\n    fun processIntent(intent: Intent) {\n        if (isCache(intent) && getType(intent) == type) {\n            synchronized(lock) {\n                content = intent.getParcelableArrayListExtra(EXTRA_DATA) ?: arrayListOf()\n                id = intent.getStringExtra(EXTRA_ID) ?: UUID.randomUUID().toString()\n                if (!intent.hasExtra(EXTRA_ID)) {\n                    Log.d(TAG, \"Created new intent cache with id $id\")\n                } else if (intent.hasExtra(EXTRA_DATA)) {\n                    Log.d(TAG, \"Recovered data from intent cache with id $id\")\n                }\n                pendingActions.forEach { it() }\n                pendingActions.clear()\n                isReady = true\n                updateIntent()\n            }\n        }\n    }\n\n    private fun runIfReady(action: () -> Unit) {\n        synchronized(lock) {\n            if (isReady) {\n                action()\n            } else {\n                pendingActions.add(action)\n            }\n        }\n    }\n\n    private fun updateIntent() {\n        synchronized(lock) {\n            if (isReady) {\n                val intent = getIntent().apply {\n                    putExtra(EXTRA_ID, id)\n                    putParcelableArrayListExtra(EXTRA_DATA, content)\n                }\n                val pendingIntent = PendingIntentCompat.getService(context, type, intent, FLAG_NO_CREATE or FLAG_UPDATE_CURRENT, true)\n                if (pendingIntent == null) {\n                    Log.w(TAG, \"Failed to update existing pending intent, will likely have a loss of information\")\n                }\n            }\n        }\n    }\n\n    companion object {\n        private const val TAG = \"IntentCacheManager\"\n        private const val TEN_YEARS = 315360000000L\n        private const val ACTION = \"org.microg.gms.ACTION_INTENT_CACHE_MANAGER\"\n        private const val EXTRA_IS_CACHE = \"org.microg.gms.IntentCacheManager.is_cache\"\n        private const val EXTRA_CACHE_TYPE = \"org.microg.gms.IntentCacheManager.cache_type\"\n        private const val EXTRA_ID = \"org.microg.gms.IntentCacheManager.id\"\n        private const val EXTRA_DATA = \"org.microg.gms.IntentCacheManager.data\"\n\n        inline fun<reified S: Service, T: Parcelable> create(context: Context, type: Int) = IntentCacheManager<S, T>(context, S::class.java, type)\n\n        fun isCache(intent: Intent): Boolean = try {\n            intent.getBooleanExtra(EXTRA_IS_CACHE, false)\n        } catch (e: Exception) {\n            false\n        }\n\n        fun getType(intent: Intent): Int {\n            val ret = intent.getIntExtra(EXTRA_CACHE_TYPE, -1)\n            if (ret == -1) throw IllegalArgumentException()\n            return ret\n        }\n    }\n}"
  },
  {
    "path": "play-services-base/core/src/main/kotlin/org/microg/gms/utils/PackageManagerUtils.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.utils\n\nimport android.content.pm.PackageManager\nimport android.content.pm.PackageManager.NameNotFoundException\nimport android.content.pm.Signature\nimport android.util.Base64\nimport com.google.android.gms.common.internal.CertData\nimport java.security.MessageDigest\nimport java.util.*\n\nfun PackageManager.isPlatformCertificate(cert: CertData) = getPlatformCertificates().contains(cert)\nfun PackageManager.getPlatformCertificates() = getCertificates(\"android\")\n\nfun PackageManager.getCertificates(packageName: String): List<CertData> = try {\n    getPackageInfo(packageName, PackageManager.GET_SIGNATURES).signatures?.map { CertData(it.toByteArray()) }\n        ?: emptyList()\n} catch (e: NameNotFoundException) {\n    emptyList()\n}\n\n@Deprecated(\"It's actually a certificate\", ReplaceWith(\"getCertificates\"))\nfun PackageManager.getSignatures(packageName: String): Array<Signature> = try {\n    getPackageInfo(packageName, PackageManager.GET_SIGNATURES).signatures\n        ?: emptyArray()\n} catch (e: NameNotFoundException) {\n    emptyArray()\n}\n\nfun PackageManager.getApplicationLabel(packageName: String): CharSequence = try {\n    getApplicationLabel(getApplicationInfo(packageName, 0))\n} catch (e: Exception) {\n    packageName\n}\n\nfun PackageManager.getExtendedPackageInfo(packageName: String) = ExtendedPackageInfo(this, packageName)\n\nfun ByteArray.toBase64(vararg flags: Int): String = Base64.encodeToString(this, flags.fold(0) { a, b -> a or b })\nfun ByteArray.toHexString(separator: String = \"\"): String = joinToString(separator) { \"%02x\".format(it) }\n\nfun PackageManager.getFirstSignatureDigest(packageName: String, md: String): ByteArray? =\n    getCertificates(packageName).firstOrNull()?.digest(md)\n\nfun ByteArray.digest(md: String): ByteArray = MessageDigest.getInstance(md).digest(this)\n@Deprecated(\"It's actually a certificate\")\nfun Signature.digest(md: String): ByteArray = toByteArray().digest(md)\nfun CertData.digest(md: String): ByteArray = bytes.digest(md)\n"
  },
  {
    "path": "play-services-base/core/src/main/kotlin/org/microg/gms/utils/PackageManagerWrapper.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage org.microg.gms.utils\n\nimport android.annotation.TargetApi\nimport android.content.ComponentName\nimport android.content.Intent\nimport android.content.IntentFilter\nimport android.content.pm.*\nimport android.content.res.Resources\nimport android.content.res.XmlResourceParser\nimport android.graphics.Rect\nimport android.graphics.drawable.Drawable\nimport android.os.Bundle\nimport android.os.UserHandle\nimport androidx.annotation.RequiresApi\n\nopen class PackageManagerWrapper(private val wrapped: PackageManager) : PackageManager() {\n    override fun getPackageInfo(packageName: String, flags: Int): PackageInfo {\n        return wrapped.getPackageInfo(packageName, flags)\n    }\n\n    @TargetApi(26)\n    override fun getPackageInfo(versionedPackage: VersionedPackage, flags: Int): PackageInfo {\n        return wrapped.getPackageInfo(versionedPackage, flags)\n    }\n\n    override fun currentToCanonicalPackageNames(packageNames: Array<out String>): Array<String> {\n        return wrapped.currentToCanonicalPackageNames(packageNames)\n    }\n\n    override fun canonicalToCurrentPackageNames(packageNames: Array<out String>): Array<String> {\n        return wrapped.canonicalToCurrentPackageNames(packageNames)\n    }\n\n    override fun getLaunchIntentForPackage(packageName: String): Intent? {\n        return wrapped.getLaunchIntentForPackage(packageName)\n    }\n\n    @TargetApi(21)\n    override fun getLeanbackLaunchIntentForPackage(packageName: String): Intent? {\n        return wrapped.getLeanbackLaunchIntentForPackage(packageName)\n    }\n\n    override fun getPackageGids(packageName: String): IntArray {\n        return wrapped.getPackageGids(packageName)\n    }\n\n    @TargetApi(24)\n    override fun getPackageGids(packageName: String, flags: Int): IntArray {\n        return wrapped.getPackageGids(packageName, flags)\n    }\n\n    @TargetApi(24)\n    override fun getPackageUid(packageName: String, flags: Int): Int {\n        return wrapped.getPackageUid(packageName, flags)\n    }\n\n    override fun getPermissionInfo(permName: String, flags: Int): PermissionInfo {\n        return wrapped.getPermissionInfo(permName, flags)\n    }\n\n    override fun queryPermissionsByGroup(permissionGroup: String?, flags: Int): MutableList<PermissionInfo> {\n        return wrapped.queryPermissionsByGroup(permissionGroup, flags)\n    }\n\n    override fun getPermissionGroupInfo(permName: String, flags: Int): PermissionGroupInfo {\n        return wrapped.getPermissionGroupInfo(permName, flags)\n    }\n\n    override fun getAllPermissionGroups(flags: Int): MutableList<PermissionGroupInfo> {\n        return wrapped.getAllPermissionGroups(flags)\n    }\n\n    override fun getApplicationInfo(packageName: String, flags: Int): ApplicationInfo {\n        return wrapped.getApplicationInfo(packageName, flags)\n    }\n\n    override fun getActivityInfo(component: ComponentName, flags: Int): ActivityInfo {\n        return wrapped.getActivityInfo(component, flags)\n    }\n\n    override fun getReceiverInfo(component: ComponentName, flags: Int): ActivityInfo {\n        return wrapped.getReceiverInfo(component, flags)\n    }\n\n    override fun getServiceInfo(component: ComponentName, flags: Int): ServiceInfo {\n        return wrapped.getServiceInfo(component, flags)\n    }\n\n    override fun getProviderInfo(component: ComponentName, flags: Int): ProviderInfo {\n        return wrapped.getProviderInfo(component, flags)\n    }\n\n    @RequiresApi(29)\n    override fun getInstalledModules(flags: Int): MutableList<ModuleInfo> {\n        return wrapped.getInstalledModules(flags)\n    }\n\n    override fun getInstalledPackages(flags: Int): MutableList<PackageInfo> {\n        return wrapped.getInstalledPackages(flags)\n    }\n\n    @TargetApi(18)\n    override fun getPackagesHoldingPermissions(permissions: Array<out String>, flags: Int): MutableList<PackageInfo> {\n        return wrapped.getPackagesHoldingPermissions(permissions, flags)\n    }\n\n    override fun checkPermission(permName: String, packageName: String): Int {\n        return wrapped.checkPermission(permName, packageName)\n    }\n\n    @TargetApi(23)\n    override fun isPermissionRevokedByPolicy(permName: String, packageName: String): Boolean {\n        return wrapped.isPermissionRevokedByPolicy(permName, packageName)\n    }\n\n    override fun addPermission(info: PermissionInfo): Boolean {\n        return wrapped.addPermission(info)\n    }\n\n    override fun addPermissionAsync(info: PermissionInfo): Boolean {\n        return wrapped.addPermissionAsync(info)\n    }\n\n    override fun removePermission(permName: String) {\n        return wrapped.removePermission(permName)\n    }\n\n    override fun checkSignatures(packageName1: String, packageName2: String): Int {\n        return wrapped.checkSignatures(packageName1, packageName2)\n    }\n\n    override fun checkSignatures(uid1: Int, uid2: Int): Int {\n        return wrapped.checkSignatures(uid1, uid2)\n    }\n\n    override fun getPackagesForUid(uid: Int): Array<String>? {\n        return wrapped.getPackagesForUid(uid)\n    }\n\n    override fun getNameForUid(uid: Int): String? {\n        return wrapped.getNameForUid(uid)\n    }\n\n    override fun getInstalledApplications(flags: Int): MutableList<ApplicationInfo> {\n        return wrapped.getInstalledApplications(flags)\n    }\n\n    @TargetApi(26)\n    override fun isInstantApp(): Boolean {\n        return wrapped.isInstantApp\n    }\n\n    @TargetApi(26)\n    override fun isInstantApp(packageName: String): Boolean {\n        return wrapped.isInstantApp(packageName)\n    }\n\n    @TargetApi(26)\n    override fun getInstantAppCookieMaxBytes(): Int {\n        return wrapped.instantAppCookieMaxBytes\n    }\n\n    @TargetApi(26)\n    override fun getInstantAppCookie(): ByteArray {\n        return wrapped.instantAppCookie\n    }\n\n    @TargetApi(26)\n    override fun clearInstantAppCookie() {\n        return wrapped.clearInstantAppCookie()\n    }\n\n    @TargetApi(26)\n    override fun updateInstantAppCookie(cookie: ByteArray?) {\n        return wrapped.updateInstantAppCookie(cookie)\n    }\n\n    @TargetApi(26)\n    override fun getSystemSharedLibraryNames(): Array<String>? {\n        return wrapped.systemSharedLibraryNames\n    }\n\n    @TargetApi(26)\n    override fun getSharedLibraries(flags: Int): MutableList<SharedLibraryInfo> {\n        return wrapped.getSharedLibraries(flags)\n    }\n\n    @TargetApi(26)\n    override fun getChangedPackages(sequenceNumber: Int): ChangedPackages? {\n        return wrapped.getChangedPackages(sequenceNumber)\n    }\n\n    override fun getSystemAvailableFeatures(): Array<FeatureInfo> {\n        return wrapped.systemAvailableFeatures\n    }\n\n    override fun hasSystemFeature(featureName: String): Boolean {\n        return wrapped.hasSystemFeature(featureName)\n    }\n\n    @TargetApi(24)\n    override fun hasSystemFeature(featureName: String, version: Int): Boolean {\n        return wrapped.hasSystemFeature(featureName, version)\n    }\n\n    override fun resolveActivity(intent: Intent, flags: Int): ResolveInfo? {\n        return wrapped.resolveActivity(intent, flags)\n    }\n\n    override fun queryIntentActivities(intent: Intent, flags: Int): MutableList<ResolveInfo> {\n        return wrapped.queryIntentActivities(intent, flags)\n    }\n\n    override fun queryIntentActivityOptions(caller: ComponentName?, specifics: Array<out Intent>?, intent: Intent, flags: Int): MutableList<ResolveInfo> {\n        return wrapped.queryIntentActivityOptions(caller, specifics, intent, flags)\n    }\n\n    override fun queryBroadcastReceivers(intent: Intent, flags: Int): MutableList<ResolveInfo> {\n        return wrapped.queryBroadcastReceivers(intent, flags)\n    }\n\n    override fun resolveService(intent: Intent, flags: Int): ResolveInfo? {\n        return wrapped.resolveService(intent, flags)\n    }\n\n    override fun queryIntentServices(intent: Intent, flags: Int): MutableList<ResolveInfo> {\n        return wrapped.queryIntentServices(intent, flags)\n    }\n\n    @TargetApi(19)\n    override fun queryIntentContentProviders(intent: Intent, flags: Int): MutableList<ResolveInfo> {\n        return wrapped.queryIntentContentProviders(intent, flags)\n    }\n\n    override fun resolveContentProvider(authority: String, flags: Int): ProviderInfo? {\n        return wrapped.resolveContentProvider(authority, flags)\n    }\n\n    override fun queryContentProviders(processName: String?, uid: Int, flags: Int): MutableList<ProviderInfo> {\n        return wrapped.queryContentProviders(processName, uid, flags)\n    }\n\n    override fun getInstrumentationInfo(className: ComponentName, flags: Int): InstrumentationInfo {\n        return wrapped.getInstrumentationInfo(className, flags)\n    }\n\n    override fun queryInstrumentation(targetPackage: String, flags: Int): MutableList<InstrumentationInfo> {\n        return wrapped.queryInstrumentation(targetPackage, flags)\n    }\n\n    override fun getDrawable(packageName: String, resid: Int, appInfo: ApplicationInfo?): Drawable? {\n        return wrapped.getDrawable(packageName, resid, appInfo)\n    }\n\n    override fun getActivityIcon(activityName: ComponentName): Drawable {\n        return wrapped.getActivityIcon(activityName)\n    }\n\n    override fun getActivityIcon(intent: Intent): Drawable {\n        return wrapped.getActivityIcon(intent)\n    }\n\n    @TargetApi(20)\n    override fun getActivityBanner(activityName: ComponentName): Drawable? {\n        return wrapped.getActivityBanner(activityName)\n    }\n\n    @TargetApi(20)\n    override fun getActivityBanner(intent: Intent): Drawable? {\n        return wrapped.getActivityBanner(intent)\n    }\n\n    override fun getDefaultActivityIcon(): Drawable {\n        return wrapped.defaultActivityIcon\n    }\n\n    override fun getApplicationIcon(info: ApplicationInfo): Drawable {\n        return wrapped.getApplicationIcon(info)\n    }\n\n    override fun getApplicationIcon(packageName: String): Drawable {\n        return wrapped.getApplicationIcon(packageName)\n    }\n\n    @TargetApi(20)\n    override fun getApplicationBanner(info: ApplicationInfo): Drawable? {\n        return wrapped.getApplicationBanner(info)\n    }\n\n    @TargetApi(20)\n    override fun getApplicationBanner(packageName: String): Drawable? {\n        return wrapped.getApplicationBanner(packageName)\n    }\n\n    override fun getActivityLogo(activityName: ComponentName): Drawable? {\n        return wrapped.getActivityLogo(activityName)\n    }\n\n    override fun getActivityLogo(intent: Intent): Drawable? {\n        return wrapped.getActivityLogo(intent)\n    }\n\n    override fun getApplicationLogo(info: ApplicationInfo): Drawable? {\n        return wrapped.getApplicationLogo(info)\n    }\n\n    override fun getApplicationLogo(packageName: String): Drawable? {\n        return wrapped.getApplicationLogo(packageName)\n    }\n\n    @TargetApi(21)\n    override fun getUserBadgedIcon(drawable: Drawable, user: UserHandle): Drawable {\n        return wrapped.getUserBadgedIcon(drawable, user)\n    }\n\n    @TargetApi(21)\n    override fun getUserBadgedDrawableForDensity(drawable: Drawable, user: UserHandle, badgeLocation: Rect?, badgeDensity: Int): Drawable {\n        return wrapped.getUserBadgedDrawableForDensity(drawable, user, badgeLocation, badgeDensity)\n    }\n\n    @TargetApi(21)\n    override fun getUserBadgedLabel(label: CharSequence, user: UserHandle): CharSequence {\n        return wrapped.getUserBadgedLabel(label, user)\n    }\n\n    override fun getText(packageName: String, resid: Int, appInfo: ApplicationInfo?): CharSequence? {\n        return wrapped.getText(packageName, resid, appInfo)\n    }\n\n    override fun getXml(packageName: String, resid: Int, appInfo: ApplicationInfo?): XmlResourceParser? {\n        return wrapped.getXml(packageName, resid, appInfo)\n    }\n\n    override fun getApplicationLabel(info: ApplicationInfo): CharSequence {\n        return wrapped.getApplicationLabel(info)\n    }\n\n    override fun getResourcesForActivity(activityName: ComponentName): Resources {\n        return wrapped.getResourcesForActivity(activityName)\n    }\n\n    override fun getResourcesForApplication(app: ApplicationInfo): Resources {\n        return wrapped.getResourcesForApplication(app)\n    }\n\n    override fun getResourcesForApplication(packageName: String): Resources {\n        return wrapped.getResourcesForApplication(packageName)\n    }\n\n    override fun verifyPendingInstall(id: Int, verificationCode: Int) {\n        return wrapped.verifyPendingInstall(id, verificationCode)\n    }\n\n    @TargetApi(17)\n    override fun extendVerificationTimeout(id: Int, verificationCodeAtTimeout: Int, millisecondsToDelay: Long) {\n        return wrapped.extendVerificationTimeout(id, verificationCodeAtTimeout, millisecondsToDelay)\n    }\n\n    override fun setInstallerPackageName(targetPackage: String, installerPackageName: String?) {\n        return wrapped.setInstallerPackageName(targetPackage, installerPackageName)\n    }\n\n    override fun getInstallerPackageName(packageName: String): String? {\n        return wrapped.getInstallerPackageName(packageName)\n    }\n\n    override fun addPackageToPreferred(packageName: String) {\n        return wrapped.addPackageToPreferred(packageName)\n    }\n\n    override fun removePackageFromPreferred(packageName: String) {\n        return wrapped.removePackageFromPreferred(packageName)\n    }\n\n    override fun getPreferredPackages(flags: Int): MutableList<PackageInfo> {\n        return wrapped.getPreferredPackages(flags)\n    }\n\n    override fun addPreferredActivity(filter: IntentFilter, match: Int, set: Array<out ComponentName>?, activity: ComponentName) {\n        return wrapped.addPreferredActivity(filter, match, set, activity)\n    }\n\n    override fun clearPackagePreferredActivities(packageName: String) {\n        return wrapped.clearPackagePreferredActivities(packageName)\n    }\n\n    override fun getPreferredActivities(outFilters: MutableList<IntentFilter>, outActivities: MutableList<ComponentName>, packageName: String?): Int {\n        return wrapped.getPreferredActivities(outFilters, outActivities, packageName)\n    }\n\n    override fun setComponentEnabledSetting(componentName: ComponentName, newState: Int, flags: Int) {\n        return wrapped.setComponentEnabledSetting(componentName, newState, flags)\n    }\n\n    override fun getComponentEnabledSetting(componentName: ComponentName): Int {\n        return wrapped.getComponentEnabledSetting(componentName)\n    }\n\n    override fun setApplicationEnabledSetting(packageName: String, newState: Int, flags: Int) {\n        return wrapped.setApplicationEnabledSetting(packageName, newState, flags)\n    }\n\n    override fun getApplicationEnabledSetting(packageName: String): Int {\n        return wrapped.getApplicationEnabledSetting(packageName)\n    }\n\n    override fun isSafeMode(): Boolean {\n        return wrapped.isSafeMode\n    }\n\n    @TargetApi(26)\n    override fun setApplicationCategoryHint(packageName: String, categoryHint: Int) {\n        return wrapped.setApplicationCategoryHint(packageName, categoryHint)\n    }\n\n    @TargetApi(21)\n    override fun getPackageInstaller(): PackageInstaller {\n        return wrapped.packageInstaller\n    }\n\n    @TargetApi(26)\n    override fun canRequestPackageInstalls(): Boolean {\n        return wrapped.canRequestPackageInstalls()\n    }\n\n\n    @TargetApi(29)\n    override fun addWhitelistedRestrictedPermission(packageName: String, permName: String, whitelistFlags: Int): Boolean {\n        return wrapped.addWhitelistedRestrictedPermission(packageName, permName, whitelistFlags)\n    }\n\n    @TargetApi(30)\n    override fun getBackgroundPermissionOptionLabel(): CharSequence {\n        return wrapped.getBackgroundPermissionOptionLabel()\n    }\n\n    @TargetApi(30)\n    override fun getInstallSourceInfo(packageName: String): InstallSourceInfo {\n        return wrapped.getInstallSourceInfo(packageName)\n    }\n\n    @TargetApi(30)\n    override fun getMimeGroup(mimeGroup: String): MutableSet<String> {\n        return wrapped.getMimeGroup(mimeGroup)\n    }\n\n    @TargetApi(29)\n    override fun getModuleInfo(packageName: String, flags: Int): ModuleInfo {\n        return wrapped.getModuleInfo(packageName, flags)\n    }\n\n    override fun getPackageArchiveInfo(archiveFilePath: String, flags: Int): PackageInfo? {\n        return wrapped.getPackageArchiveInfo(archiveFilePath, flags)\n    }\n\n    @TargetApi(28)\n    override fun getSuspendedPackageAppExtras(): Bundle? {\n        return wrapped.suspendedPackageAppExtras\n    }\n\n    @TargetApi(29)\n    override fun getSyntheticAppDetailsActivityEnabled(packageName: String): Boolean {\n        return wrapped.getSyntheticAppDetailsActivityEnabled(packageName)\n    }\n\n    @TargetApi(29)\n    override fun getWhitelistedRestrictedPermissions(packageName: String, whitelistFlag: Int): MutableSet<String> {\n        return wrapped.getWhitelistedRestrictedPermissions(packageName, whitelistFlag)\n    }\n\n    @TargetApi(28)\n    override fun hasSigningCertificate(packageName: String, certificate: ByteArray, type: Int): Boolean {\n        return wrapped.hasSigningCertificate(packageName, certificate, type)\n    }\n\n    @TargetApi(28)\n    override fun hasSigningCertificate(uid: Int, certificate: ByteArray, type: Int): Boolean {\n        return wrapped.hasSigningCertificate(uid, certificate, type)\n    }\n\n    @TargetApi(30)\n    override fun isAutoRevokeWhitelisted(): Boolean {\n        return wrapped.isAutoRevokeWhitelisted\n    }\n\n    @TargetApi(30)\n    override fun isAutoRevokeWhitelisted(packageName: String): Boolean {\n        return wrapped.isAutoRevokeWhitelisted(packageName)\n    }\n\n    @TargetApi(30)\n    override fun isDefaultApplicationIcon(drawable: Drawable): Boolean {\n        return wrapped.isDefaultApplicationIcon(drawable)\n    }\n\n    @TargetApi(29)\n    override fun isDeviceUpgrading(): Boolean {\n        return wrapped.isDeviceUpgrading\n    }\n\n    @TargetApi(28)\n    override fun isPackageSuspended(): Boolean {\n        return wrapped.isPackageSuspended\n    }\n\n    @TargetApi(29)\n    override fun isPackageSuspended(packageName: String): Boolean {\n        return wrapped.isPackageSuspended(packageName)\n    }\n\n    @TargetApi(29)\n    override fun removeWhitelistedRestrictedPermission(packageName: String, permName: String, whitelistFlags: Int): Boolean {\n        return wrapped.removeWhitelistedRestrictedPermission(packageName, permName, whitelistFlags)\n    }\n\n    @TargetApi(30)\n    override fun setAutoRevokeWhitelisted(packageName: String, whitelisted: Boolean): Boolean {\n        return wrapped.setAutoRevokeWhitelisted(packageName, whitelisted)\n    }\n\n    @TargetApi(30)\n    override fun setMimeGroup(mimeGroup: String, mimeTypes: MutableSet<String>) {\n        return wrapped.setMimeGroup(mimeGroup, mimeTypes)\n    }\n}\n"
  },
  {
    "path": "play-services-base/core/src/main/kotlin/org/microg/gms/utils/SingleInstanceUtil.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.utils\n\nprivate val singleInstanceLock = Any()\nprivate val singleInstanceMap: MutableMap<Class<*>, Any> = hashMapOf()\n\nfun <T : Any> singleInstanceOf(tClass: Class<T>, tCreator: () -> T): T {\n    val tVolatileItem = singleInstanceMap[tClass]\n    @Suppress(\"UNCHECKED_CAST\")\n    if (tVolatileItem != null && tClass.isAssignableFrom(tVolatileItem.javaClass)) return tVolatileItem as T\n    val tLock = synchronized(singleInstanceLock) {\n        val tItem = singleInstanceMap[tClass]\n        if (tItem != null) {\n            @Suppress(\"UNCHECKED_CAST\")\n            if (tClass.isAssignableFrom(tItem.javaClass)) return tItem as T\n            tItem\n        } else {\n            val tLock = Any()\n            singleInstanceMap[tClass] = tLock\n            tLock\n        }\n    }\n    synchronized(tLock) {\n        val tItem = synchronized(singleInstanceMap) { singleInstanceMap[tClass] }\n        if (tItem == null) throw IllegalStateException()\n        @Suppress(\"UNCHECKED_CAST\")\n        if (tClass.isAssignableFrom(tItem.javaClass)) return tItem as T\n        if (tItem != tLock) throw IllegalStateException()\n\n        val tNewItem = tCreator()\n        synchronized(singleInstanceMap) {\n            singleInstanceMap[tClass] = tNewItem\n        }\n        return tNewItem\n    }\n}\n\ninline fun <reified T : Any> singleInstanceOf(noinline tCreator: () -> T): T = singleInstanceOf(T::class.java, tCreator)"
  },
  {
    "path": "play-services-base/core/src/main/kotlin/org/microg/gms/vending/InstallerData.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.vending\n\nimport org.json.JSONException\nimport org.json.JSONObject\n\nenum class AllowType(val value: Int) {\n    REJECT_ALWAYS(0),\n    REJECT_ONCE(1),\n    ALLOW_ONCE(2),\n    ALLOW_ALWAYS(3),\n}\n\ndata class InstallerData(val packageName: String, var allowType: Int, val pkgSignSha256: String) {\n\n    override fun toString(): String {\n        return JSONObject()\n            .put(CHANNEL_PACKAGE_NAME, packageName)\n            .put(CHANNEL_ALLOW_TYPE, allowType)\n            .put(CHANNEL_SIGNATURE, pkgSignSha256)\n            .toString()\n    }\n\n    companion object {\n        private const val CHANNEL_PACKAGE_NAME = \"packageName\"\n        private const val CHANNEL_ALLOW_TYPE = \"allowType\"\n        private const val CHANNEL_SIGNATURE = \"signature\"\n\n        private fun parse(jsonString: String): InstallerData? {\n            try {\n                val json = JSONObject(jsonString)\n                return InstallerData(\n                    json.getString(CHANNEL_PACKAGE_NAME),\n                    json.getInt(CHANNEL_ALLOW_TYPE),\n                    json.getString(CHANNEL_SIGNATURE)\n                )\n            } catch (e: JSONException) {\n                return null\n            }\n        }\n\n        fun loadDataSet(content: String): Set<InstallerData> {\n            return content.split(\"|\").mapNotNull { parse(it) }.toSet()\n        }\n\n        fun updateDataSetString(channelList: Set<InstallerData>, channel: InstallerData): String {\n            val channelData = channelList.find { it.packageName == channel.packageName && it.pkgSignSha256 == channel.pkgSignSha256 }\n            val newChannelList = if (channelData != null) {\n                channelData.allowType = channel.allowType\n                channelList\n            } else {\n                channelList + channel\n            }\n            return newChannelList.let { it -> it.joinToString(separator = \"|\") { it.toString() } }\n        }\n    }\n}"
  },
  {
    "path": "play-services-base/core/src/main/kotlin/org/microg/gms/vending/PlayIntegrityData.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.vending\n\nimport org.json.JSONException\nimport org.json.JSONObject\n\nclass PlayIntegrityData(var allowed: Boolean,\n                        val packageName: String,\n                        val pkgSignSha256: String,\n                        var lastTime: Long,\n                        var lastResult: String? = null,\n                        var lastStatus: Boolean = false) {\n\n    override fun toString(): String {\n        return JSONObject()\n            .put(ALLOWED, allowed)\n            .put(PACKAGE_NAME, packageName)\n            .put(SIGNATURE, pkgSignSha256)\n            .put(LAST_VISIT_TIME, lastTime)\n            .put(LAST_VISIT_RESULT, lastResult)\n            .put(LAST_VISIT_STATUS, lastStatus)\n            .toString()\n    }\n\n    companion object {\n        private const val PACKAGE_NAME = \"packageName\"\n        private const val ALLOWED = \"allowed\"\n        private const val SIGNATURE = \"signature\"\n        private const val LAST_VISIT_TIME = \"lastVisitTime\"\n        private const val LAST_VISIT_RESULT = \"lastVisitResult\"\n        private const val LAST_VISIT_STATUS = \"lastVisitStatus\"\n\n        private fun parse(jsonString: String): PlayIntegrityData? {\n            try {\n                val json = JSONObject(jsonString)\n                return PlayIntegrityData(\n                    json.getBoolean(ALLOWED),\n                    json.getString(PACKAGE_NAME),\n                    json.getString(SIGNATURE),\n                    json.getLong(LAST_VISIT_TIME),\n                    json.getString(LAST_VISIT_RESULT),\n                    json.getBoolean(LAST_VISIT_STATUS)\n                )\n            } catch (e: JSONException) {\n                return null\n            }\n        }\n\n        fun loadDataSet(content: String): Set<PlayIntegrityData> {\n            return content.split(\"|\").mapNotNull { parse(it) }.toSet()\n        }\n\n        fun updateDataSetString(channelList: Set<PlayIntegrityData>, channel: PlayIntegrityData): String {\n            val channelData = channelList.find { it.packageName == channel.packageName && it.pkgSignSha256 == channel.pkgSignSha256 }\n            val newChannelList = if (channelData != null) {\n                channelData.allowed = channel.allowed\n                channelData.lastTime = channel.lastTime\n                channelData.lastResult = channel.lastResult\n                channelData.lastStatus = channel.lastStatus\n                channelList\n            } else {\n                channelList + channel\n            }\n            return newChannelList.let { it -> it.joinToString(separator = \"|\") { it.toString() } }\n        }\n    }\n}"
  },
  {
    "path": "play-services-base/core/src/main/res/drawable/ic_background_notify.xml",
    "content": "<!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<vector android:height=\"24dp\" android:viewportHeight=\"24\"\n    android:viewportWidth=\"24\" android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"#000000\" android:pathData=\"M19.51,3.08L3.08,19.51c0.09,0.34 0.27,0.65 0.51,0.9 0.25,0.24 0.56,0.42 0.9,0.51L20.93,4.49c-0.19,-0.69 -0.73,-1.23 -1.42,-1.41zM11.88,3L3,11.88v2.83L14.71,3h-2.83zM5,3c-1.1,0 -2,0.9 -2,2v2l4,-4L5,3zM19,21c0.55,0 1.05,-0.22 1.41,-0.59 0.37,-0.36 0.59,-0.86 0.59,-1.41v-2l-4,4h2zM9.29,21h2.83L21,12.12L21,9.29L9.29,21z\"/>\n</vector>\n"
  },
  {
    "path": "play-services-base/core/src/main/res/drawable/ic_expand_apps.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2019, The Android Open Source Project\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<vector\n    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.0\"\n    android:viewportHeight=\"24.0\">\n    <path\n        android:fillColor=\"#000\"\n        android:pathData=\"M9.71,18.71l-1.42,-1.42l5.3,-5.29l-5.3,-5.29l1.42,-1.42l6.7,6.71z\" />\n</vector>\n"
  },
  {
    "path": "play-services-base/core/src/main/res/drawable/ic_info_outline.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2019, The Android Open Source Project\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\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.0\"\n    android:viewportHeight=\"24.0\">\n    <path\n        android:fillColor=\"#000\"\n        android:pathData=\"M11,17h2v-6h-2v6zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,9h2L13,7h-2v2z\" />\n</vector>\n"
  },
  {
    "path": "play-services-base/core/src/main/res/drawable/ic_open.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2019, The Android Open Source Project\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\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=\"#000\"\n        android:pathData=\"M14,3V5H17.59L7.76,14.83L9.17,16.24L19,6.41V10H21V3M19,19H5V5H12V3H5C3.89,3 3,3.9 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V12H19V19Z\" />\n</vector>\n"
  },
  {
    "path": "play-services-base/core/src/main/res/drawable/ic_radio.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2021 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item\n        android:id=\"@+id/on\"\n        android:drawable=\"@drawable/ic_radio_checked\"\n        android:state_checked=\"true\" />\n    <item\n        android:id=\"@+id/off\"\n        android:drawable=\"@drawable/ic_radio_unchecked\"\n        android:state_checked=\"false\" />\n</selector>\n"
  },
  {
    "path": "play-services-base/core/src/main/res/drawable/ic_radio_checked.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2019 The Android Open Source Project\n  ~ SPDX-FileCopyrightText: 2021 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:tint=\"?attr/colorAccent\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M12,7c-2.76,0 -5,2.24 -5,5s2.24,5 5,5 5,-2.24 5,-5 -2.24,-5 -5,-5zM12,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": "play-services-base/core/src/main/res/drawable/ic_radio_unchecked.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2019 The Android Open Source Project\n  ~ SPDX-FileCopyrightText: 2021 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\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,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": "play-services-base/core/src/main/res/layout/list_no_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013 The Android Open Source Project\n  ~ Copyright (C) 2013-2017 microG Project Team\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<!-- text that appears when the recent app list is empty -->\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n              android:layout_width=\"match_parent\"\n              android:layout_height=\"wrap_content\"\n              android:minHeight=\"?android:attr/listPreferredItemHeight\"\n              android:gravity=\"center_vertical\"\n              android:paddingEnd=\"?android:attr/scrollbarSize\"\n              android:background=\"?attr/selectableItemBackground\"\n              android:paddingRight=\"?android:attr/scrollbarSize\">\n\n    <RelativeLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginStart=\"15dip\"\n        android:layout_marginEnd=\"6dip\"\n        android:layout_marginTop=\"6dip\"\n        android:layout_marginBottom=\"6dip\"\n        android:layout_weight=\"1\"\n        android:layout_marginLeft=\"15dip\"\n        android:layout_marginRight=\"6dip\">\n\n        <TextView android:id=\"@android:id/title\"\n                  android:gravity=\"center\"\n                  android:layout_width=\"match_parent\"\n                  android:layout_height=\"wrap_content\"\n                  android:textAppearance=\"?android:attr/textAppearanceSmall\"\n                  android:textColor=\"?android:attr/textColorSecondary\" />\n\n    </RelativeLayout>\n\n</LinearLayout>\n\n"
  },
  {
    "path": "play-services-base/core/src/main/res/layout/preference_app_heading.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\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=\"wrap_content\"\n    android:paddingStart=\"?attr/listPreferredItemPaddingStart\"\n    android:paddingLeft=\"?attr/listPreferredItemPaddingLeft\"\n    android:paddingTop=\"24dp\"\n    android:paddingEnd=\"?attr/listPreferredItemPaddingEnd\"\n    android:paddingRight=\"?attr/listPreferredItemPaddingRight\"\n    android:paddingBottom=\"16dp\">\n\n    <LinearLayout\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_centerHorizontal=\"true\"\n        android:gravity=\"center_horizontal\"\n        android:orientation=\"vertical\">\n\n        <ImageView\n            android:id=\"@android:id/icon\"\n            android:layout_width=\"48dp\"\n            android:layout_height=\"48dp\"\n            android:antialias=\"true\"\n            android:scaleType=\"fitCenter\"\n            tools:src=\"@android:mipmap/sym_def_app_icon\" />\n\n        <TextView\n            android:id=\"@android:id/title\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"8dp\"\n            android:ellipsize=\"marquee\"\n            android:gravity=\"center\"\n            android:singleLine=\"false\"\n            android:textAppearance=\"@style/TextAppearance.AppCompat.Subhead\"\n            android:textColor=\"?android:attr/textColorPrimary\"\n            android:textSize=\"20sp\"\n            tools:text=\"@tools:sample/lorem\" />\n    </LinearLayout>\n</RelativeLayout>"
  },
  {
    "path": "play-services-base/core/src/main/res/layout/preference_category_no_label.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<View xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"0dp\" />\n"
  },
  {
    "path": "play-services-base/core/src/main/res/layout/preference_footer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2022 The Android Open Source Project\n  ~ SPDX-FileCopyrightText: 2024 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:minHeight=\"?android:attr/listPreferredItemHeight\"\n    android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n    android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"\n    android:background=\"?android:attr/selectableItemBackground\"\n    android:orientation=\"vertical\"\n    android:clipToPadding=\"false\">\n\n    <LinearLayout\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=\"start|top\"\n        android:orientation=\"horizontal\"\n        android:paddingEnd=\"12dp\"\n        android:paddingTop=\"16dp\"\n        android:paddingBottom=\"4dp\">\n        <ImageView\n            android:id=\"@android:id/icon\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"/>\n    </LinearLayout>\n\n    <LinearLayout\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\">\n        <TextView\n            android:id=\"@android:id/title\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"start\"\n            android:textAlignment=\"viewStart\"\n            android:paddingTop=\"16dp\"\n            android:paddingBottom=\"8dp\"\n            android:textColor=\"?android:attr/textColorSecondary\"\n            android:hyphenationFrequency=\"normalFast\"\n            android:lineBreakWordStyle=\"phrase\"\n            android:ellipsize=\"marquee\"/>\n    </LinearLayout>\n\n</LinearLayout>"
  },
  {
    "path": "play-services-base/core/src/main/res/layout/preference_progress_bar.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<LinearLayout 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\n    <ProgressBar\n        style=\"@style/Widget.AppCompat.ProgressBar.Horizontal\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:indeterminate=\"true\" />\n</LinearLayout>\n"
  },
  {
    "path": "play-services-base/core/src/main/res/layout/preference_switch_bar.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2020 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<LinearLayout 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=\"?attr/actionBarSize\"\n    android:gravity=\"center\"\n    android:orientation=\"horizontal\"\n    android:paddingStart=\"?attr/listPreferredItemPaddingStart\"\n    android:paddingLeft=\"?attr/listPreferredItemPaddingLeft\"\n    android:paddingEnd=\"?attr/listPreferredItemPaddingEnd\"\n    android:paddingRight=\"?attr/listPreferredItemPaddingRight\"\n    tools:background=\"?attr/colorControlActivated\">\n\n    <TextView\n        android:id=\"@android:id/title\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center_vertical\"\n        android:layout_weight=\"1\"\n        android:ellipsize=\"end\"\n        android:maxLines=\"2\"\n        android:paddingStart=\"56dp\"\n        android:paddingLeft=\"56dp\"\n        android:textAppearance=\"?attr/textAppearanceListItem\"\n        android:textColor=\"@android:color/white\"\n        tools:text=\"Enabled\" />\n\n    <androidx.appcompat.widget.SwitchCompat\n        android:id=\"@+id/switch_widget\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center_vertical\"\n        android:background=\"@null\"\n        app:thumbTint=\"@android:color/white\"\n        app:trackTint=\"@android:color/darker_gray\"\n        tools:checked=\"true\" />\n</LinearLayout>\n"
  },
  {
    "path": "play-services-base/core/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"foreground_service_notification_title\">Active in background</string>\n    <string name=\"foreground_service_notification_text\"><xliff:g example=\"Exposure Notification\">%1$s</xliff:g> is running in background.</string>\n    <string name=\"foreground_service_notification_big_text\">Exclude <xliff:g example=\"microG Services\">%1$s</xliff:g> from battery optimizations or change notification settings to hide this notification.</string>\n\n    <string name=\"menu_advanced\">Advanced</string>\n    <string name=\"menu_game_managed\">Game Accounts Managed</string>\n\n    <string name=\"list_no_item_none\">None</string>\n    <string name=\"list_item_see_all\">See all</string>\n\n    <string name=\"open_app\">Open</string>\n\n    <string name=\"service_status_disabled\">Disabled</string>\n    <string name=\"service_status_enabled\">Enabled</string>\n    <string name=\"service_status_automatic\">Automatic</string>\n    <string name=\"service_status_manual\">Manual</string>\n    <string name=\"service_status_enabled_short\">On</string>\n    <string name=\"service_status_disabled_short\">Off</string>\n</resources>\n"
  },
  {
    "path": "play-services-base/core/src/main/res/values/themes.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<resources xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <style name=\"Theme.Base.Light.Dialog\" parent=\"Theme.AppCompat.Light.Dialog\" />\n\n    <style name=\"Theme.Base.Light.Dialog.NoActionBar\">\n        <item name=\"windowActionBar\">false</item>\n        <item name=\"windowNoTitle\">true</item>\n    </style>\n\n    <style name=\"Theme.Base.Light.Dialog.Alert\" parent=\"Theme.AppCompat.Light.Dialog.Alert\" />\n\n    <style name=\"Theme.Base.Light.Dialog.Alert.NoActionBar\">\n        <item name=\"windowActionBar\">false</item>\n        <item name=\"windowNoTitle\">true</item>\n    </style>\n\n    <style name=\"Theme.Base.DayNight.Dialog.Alert\" parent=\"Theme.AppCompat.DayNight.Dialog.Alert\" />\n\n    <style name=\"Theme.Base.DayNight.Dialog.Alert.NoActionBar\">\n        <item name=\"windowActionBar\">false</item>\n        <item name=\"windowNoTitle\">true</item>\n    </style>\n\n    <style name=\"Theme.Base.Translucent\" parent=\"Theme.Base.DayNight.Dialog.Alert.NoActionBar\">\n        <item name=\"background\">@android:color/transparent</item>\n        <item name=\"android:background\">@android:color/transparent</item>\n        <item name=\"android:windowNoTitle\">true</item>\n        <item name=\"android:windowBackground\">@android:color/transparent</item>\n        <item name=\"android:colorBackgroundCacheHint\">@null</item>\n        <item name=\"android:backgroundDimEnabled\">false</item>\n        <item name=\"android:windowIsTranslucent\">true</item>\n        <item name=\"android:windowAnimationStyle\">@android:style/Animation</item>\n    </style>\n\n    <style name=\"Theme.App.Translucent\" parent=\"Theme.Base.Translucent\" />\n    <style name=\"Theme.App.DayNight.Dialog.Alert.NoActionBar\" parent=\"Theme.Base.DayNight.Dialog.Alert.NoActionBar\" />\n    <style name=\"Theme.App.Light.Dialog.NoActionBar\" parent=\"Theme.Base.Light.Dialog.NoActionBar\" />\n    <style name=\"Theme.App.Light.Dialog.Alert.NoActionBar\" parent=\"Theme.Base.Light.Dialog.Alert.NoActionBar\" />\n\n    <!-- compatibility -->\n\n    <style name=\"Theme.AppCompat.Light.Dialog.NoActionBar\">\n        <item name=\"windowActionBar\">false</item>\n        <item name=\"windowNoTitle\">true</item>\n    </style>\n\n    <style name=\"Theme.AppCompat.Light.Dialog.Alert.NoActionBar\">\n        <item name=\"windowActionBar\">false</item>\n        <item name=\"windowNoTitle\">true</item>\n    </style>\n\n    <style name=\"Theme.AppCompat.DayNight.Dialog.Alert.NoActionBar\">\n        <item name=\"windowActionBar\">false</item>\n        <item name=\"windowNoTitle\">true</item>\n    </style>\n\n    <style name=\"Theme.Translucent\" parent=\"Theme.AppCompat.DayNight.Dialog.Alert.NoActionBar\">\n        <item name=\"background\">@android:color/transparent</item>\n        <item name=\"android:background\">@android:color/transparent</item>\n        <item name=\"android:windowNoTitle\">true</item>\n        <item name=\"android:windowBackground\">@android:color/transparent</item>\n        <item name=\"android:colorBackgroundCacheHint\">@null</item>\n        <item name=\"android:backgroundDimEnabled\">false</item>\n        <item name=\"android:windowIsTranslucent\">true</item>\n        <item name=\"android:windowAnimationStyle\">@android:style/Animation</item>\n        <!-- Workaround until edge-to-edge is implemented, useful for libraries used in app targeting SDK35 -->\n        <item name=\"android:windowOptOutEdgeToEdgeEnforcement\" tools:targetApi=\"35\">true</item>\n    </style>\n\n    <!-- Switch Bar -->\n\n    <declare-styleable name=\"PreferenceTheme\">\n        <attr format=\"reference\" name=\"switchBarPreferenceStyle\"/>\n    </declare-styleable>\n\n    <declare-styleable name=\"SwitchBarPreference\">\n        <attr format=\"reference\" name=\"switchBarFrameId\" />\n        <attr format=\"reference\" name=\"switchBarFrameBackgroundOn\" />\n        <attr format=\"reference\" name=\"switchBarFrameBackgroundOff\" />\n        <attr format=\"reference\" name=\"switchBarFrameBackgroundDisabled\" />\n    </declare-styleable>\n\n    <style name=\"Preference.SwitchBar\">\n        <item name=\"layout\">@layout/preference_switch_bar</item>\n        <item name=\"switchBarFrameBackgroundOn\">?attr/colorControlActivated</item>\n        <item name=\"switchBarFrameBackgroundOff\">?attr/colorButtonNormal</item>\n        <item name=\"switchBarFrameBackgroundDisabled\">?attr/colorControlHighlight</item>\n    </style>\n</resources>\n"
  },
  {
    "path": "play-services-base/core/src/main/res/values-ar/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"menu_advanced\">إعدادات متقدمة</string>\n    <string name=\"list_no_item_none\">لا يوجد</string>\n    <string name=\"list_item_see_all\">عرض الكل</string>\n    <string name=\"open_app\">فتح</string>\n    <string name=\"service_status_disabled\">غير مفعّل</string>\n    <string name=\"service_status_enabled\">مفعّل</string>\n    <string name=\"service_status_automatic\">تلقائي</string>\n    <string name=\"service_status_manual\">يدوي</string>\n    <string name=\"service_status_enabled_short\">مفعّل</string>\n    <string name=\"service_status_disabled_short\">غير مفعّل</string>\n    <string name=\"foreground_service_notification_title\">نشط في الخلفية</string>\n    <string name=\"foreground_service_notification_big_text\">استثني &lt;xliff:g example=\\\"microG Services\\\"&gt;%1$s&lt;/xliff:g&gt; من توفير شحن البطارية أو غير إعدادات الإشعارات لإخفاء هذا اﻹشعار.</string>\n    <string name=\"foreground_service_notification_text\">&lt;xliff:g example=\\\"Exposure Notification\\\"&gt;%1$s&lt;/xliff:g&gt; يعمل في الخلفية.</string>\n    <string name=\"menu_game_managed\">حسابات الألعاب المدارة</string>\n</resources>\n"
  },
  {
    "path": "play-services-base/core/src/main/res/values-ast/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=\"menu_advanced\">Configuración avanzada</string>\n    <string name=\"service_status_enabled_short\">Sí</string>\n    <string name=\"open_app\">Abrir</string>\n    <string name=\"foreground_service_notification_text\">«<xliff:g example=\"Exposure Notification\">%1$s</xliff:g>» ta executándose en segundu planu.</string>\n    <string name=\"foreground_service_notification_big_text\">Esclúi a <xliff:g example=\"microG Services\">%1$s</xliff:g> de les optimizaciones d\\'enerxía o camuda la configuración de los avisos pa esconder esti avisu.</string>\n    <string name=\"list_item_see_all\">Ver too</string>\n    <string name=\"service_status_disabled_short\">Non</string>\n    <string name=\"list_no_item_none\">Nada</string>\n    <string name=\"service_status_manual\">Manual</string>\n</resources>\n"
  },
  {
    "path": "play-services-base/core/src/main/res/values-az/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=\"foreground_service_notification_title\">Arxa planda işləkdir</string>\n    <string name=\"foreground_service_notification_big_text\">Batareya optimallaşmasından <xliff:g example=\"microG Services\"> %1$s</xliff:g>-i çıxar və ya bu bildirişi gizlətmək üçün bildiriş seçimlərin dəyişdir.</string>\n    <string name=\"menu_advanced\">Qabaqcıl</string>\n    <string name=\"list_item_see_all\">Hamısın gör</string>\n    <string name=\"open_app\">Aç</string>\n    <string name=\"service_status_disabled\">Qeyri-aktiv</string>\n    <string name=\"service_status_enabled\">Aktivdir</string>\n    <string name=\"service_status_automatic\">Avtomatik</string>\n    <string name=\"service_status_manual\">Əl ilə</string>\n    <string name=\"service_status_enabled_short\">Aktiv</string>\n    <string name=\"service_status_disabled_short\">Bağlı</string>\n    <string name=\"list_no_item_none\">Heç biri</string>\n</resources>"
  },
  {
    "path": "play-services-base/core/src/main/res/values-be/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"foreground_service_notification_title\">Фонавая актыўнасць</string>\n    <string name=\"foreground_service_notification_text\"><xliff:g example=\"Exposure Notification\">%1$s</xliff:g> працуе ў фонавым рэжыме.</string>\n    <string name=\"foreground_service_notification_big_text\">Адключыце эканомію выкарыстання акумулятара для <xliff:g example=\"microG Services\">%1$s</xliff:g>, каб ўбраць гэтае паведамленне.</string>\n\n    <string name=\"menu_advanced\">Дадаткова</string>\n\n    <string name=\"list_no_item_none\">Пуста</string>\n    <string name=\"list_item_see_all\">Паказаць усё</string>\n\n    <string name=\"open_app\">Aдкрыць</string>\n\n    <string name=\"service_status_disabled\">Выключана</string>\n    <string name=\"service_status_enabled\">Уключана</string>\n    <string name=\"service_status_automatic\">Аўтаматычна</string>\n    <string name=\"service_status_manual\">Уручную</string>\n    <string name=\"service_status_enabled_short\">Укл.</string>\n    <string name=\"service_status_disabled_short\">Выкл.</string>\n</resources>\n"
  },
  {
    "path": "play-services-base/core/src/main/res/values-bn/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n</resources>"
  },
  {
    "path": "play-services-base/core/src/main/res/values-ca/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=\"foreground_service_notification_title\">Actiu en segon pla</string>\n    <string name=\"foreground_service_notification_text\"><xliff:g example=\"Exposure Notification\">%1$s</xliff:g> s\\'està executant en segon pla.</string>\n    <string name=\"foreground_service_notification_big_text\">Exclou <xliff:g example=\"microG Services\">%1$s</xliff:g> de l\\'optimització de bateria o canvia la configuració de notificacions per tal d\\'amagar aquesta notificació.</string>\n    <string name=\"menu_advanced\">Avançat</string>\n    <string name=\"menu_game_managed\">Comptes de joc gestionats</string>\n    <string name=\"list_no_item_none\">Cap</string>\n    <string name=\"list_item_see_all\">Veure-ho tot</string>\n    <string name=\"open_app\">Obrir</string>\n    <string name=\"service_status_disabled\">Desactivar</string>\n    <string name=\"service_status_enabled\">Activat</string>\n    <string name=\"service_status_automatic\">Automàtic</string>\n    <string name=\"service_status_manual\">Manual</string>\n    <string name=\"service_status_enabled_short\">Encés</string>\n    <string name=\"service_status_disabled_short\">Apagat</string>\n</resources>\n"
  },
  {
    "path": "play-services-base/core/src/main/res/values-cs/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=\"foreground_service_notification_title\">Aktivní na pozadí</string>\n    <string name=\"foreground_service_notification_text\"><xliff:g example=\"Oznámení o možném kontaktu\">%1$s</xliff:g> běží na pozadí.</string>\n    <string name=\"foreground_service_notification_big_text\">Pro skrytí tohoto oznámení vypněte optimalizaci baterie pro <xliff:g example=\"Služby microG\">%1$s</xliff:g> nebo změňte nastavení oznámení.</string>\n    <string name=\"list_no_item_none\">Žádné</string>\n    <string name=\"list_item_see_all\">Zobrazit vše</string>\n    <string name=\"open_app\">Otevřít</string>\n    <string name=\"service_status_disabled\">Zakázáno</string>\n    <string name=\"service_status_enabled\">Povoleno</string>\n    <string name=\"service_status_enabled_short\">Zap</string>\n    <string name=\"menu_advanced\">Pokročilé</string>\n    <string name=\"service_status_automatic\">Automatické</string>\n    <string name=\"service_status_manual\">Ruční</string>\n    <string name=\"service_status_disabled_short\">Vyp</string>\n    <string name=\"menu_game_managed\">Spravované herní účty</string>\n</resources>\n"
  },
  {
    "path": "play-services-base/core/src/main/res/values-de/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"foreground_service_notification_title\">Im Hintergrund aktiv</string>\n    <string name=\"foreground_service_notification_text\"><xliff:g example=\"Exposure Notification\">%1$s</xliff:g> läuft im Hintergrund weiter.</string>\n    <string name=\"foreground_service_notification_big_text\">Füge <xliff:g example=\"microG Services\">%1$s</xliff:g> als Ausnahme zur Batterie-Optimierung hinzu oder verstecke diese Benachrichtigung in den Systemeinstelleungen.</string>\n    <string name=\"menu_advanced\">Erweitert</string>\n    <string name=\"list_no_item_none\">Keine</string>\n    <string name=\"list_item_see_all\">Alle anzeigen</string>\n    <string name=\"open_app\">Öffnen</string>\n    <string name=\"service_status_disabled\">Deaktiviert</string>\n    <string name=\"service_status_enabled\">Aktiviert</string>\n    <string name=\"service_status_automatic\">Automatisch</string>\n    <string name=\"service_status_manual\">Manuell</string>\n    <string name=\"service_status_enabled_short\">Ein</string>\n    <string name=\"service_status_disabled_short\">Aus</string>\n    <string name=\"menu_game_managed\">Verwaltete Spielkonten</string>\n</resources>\n"
  },
  {
    "path": "play-services-base/core/src/main/res/values-eo/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources></resources>"
  },
  {
    "path": "play-services-base/core/src/main/res/values-es/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"menu_advanced\">Avanzado</string>\n    <string name=\"list_no_item_none\">Ninguno</string>\n    <string name=\"list_item_see_all\">Ver todo</string>\n    <string name=\"open_app\">Abrir</string>\n    <string name=\"service_status_disabled\">Desactivado</string>\n    <string name=\"service_status_enabled\">Activado</string>\n    <string name=\"service_status_automatic\">Automático</string>\n    <string name=\"service_status_manual\">Manual</string>\n    <string name=\"service_status_enabled_short\">Encendido</string>\n    <string name=\"service_status_disabled_short\">Apagado</string>\n    <string name=\"foreground_service_notification_title\">Activo en segundo plano</string>\n    <string name=\"foreground_service_notification_text\"><xliff:g example=\"Exposure Notification\">%1$s</xliff:g> se está ejecutando en segundo plano.</string>\n    <string name=\"foreground_service_notification_big_text\">Excluye <xliff:g example=\"microG Services\">%1$s</xliff:g> de las optimizaciones de la batería o cambia la configuración de las notificaciones para ocultar esta notificación.</string>\n    <string name=\"menu_game_managed\">Gestión de Cuentas de Juego</string>\n</resources>\n"
  },
  {
    "path": "play-services-base/core/src/main/res/values-fa/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=\"foreground_service_notification_text\"><xliff:g example=\"آگاه‌سازهای نزدیکی\">%1$s</xliff:g> در پس زمینه اجرا می شود.</string>\n    <string name=\"service_status_manual\">دستی</string>\n    <string name=\"menu_advanced\">پیشرفته</string>\n    <string name=\"list_no_item_none\">هیچکدام</string>\n    <string name=\"list_item_see_all\">دیدن همه</string>\n    <string name=\"foreground_service_notification_title\">در پس‌زمینه روشن است</string>\n    <string name=\"open_app\">بازکردن</string>\n    <string name=\"service_status_disabled\">غیرفعال</string>\n    <string name=\"service_status_enabled\">فعال</string>\n    <string name=\"service_status_automatic\">خودکار</string>\n    <string name=\"service_status_disabled_short\">خاموش</string>\n    <string name=\"service_status_enabled_short\">روشن</string>\n    <string name=\"foreground_service_notification_big_text\"><xliff:g example=\"خدمات میکروجی\">%1$s</xliff:g> را از بهینه‌سازی باتری پاک کنید یا تنظیمات آگاه‌ساز را تغییر دهید تا این آگاه‌ساز پنهان شود.</string>\n    <string name=\"menu_game_managed\">اکانت های بازی مدیریت شد</string>\n</resources>\n"
  },
  {
    "path": "play-services-base/core/src/main/res/values-fi/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_status_automatic\">Automaattinen</string>\n    <string name=\"open_app\">Avaa</string>\n    <string name=\"service_status_disabled\">Poistettu käytöstä</string>\n    <string name=\"service_status_enabled\">Käytössä</string>\n    <string name=\"list_item_see_all\">Näytä kaikki</string>\n    <string name=\"list_no_item_none\">Ei mitään</string>\n    <string name=\"service_status_manual\">Manuaalinen</string>\n    <string name=\"service_status_enabled_short\">Päällä</string>\n    <string name=\"service_status_disabled_short\">Pois päältä</string>\n    <string name=\"foreground_service_notification_title\">Käynnissä taustalla</string>\n    <string name=\"foreground_service_notification_text\"><xliff:g example=\"Exposure Notification\">%1$s</xliff:g> on käynnissä taustalla.</string>\n</resources>\n"
  },
  {
    "path": "play-services-base/core/src/main/res/values-fil/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=\"menu_advanced\">Advanced</string>\n    <string name=\"list_no_item_none\">Wala</string>\n    <string name=\"list_item_see_all\">Tignan lahat</string>\n    <string name=\"open_app\">Buksan</string>\n    <string name=\"service_status_disabled\">Naka-disable</string>\n    <string name=\"service_status_enabled\">Naka-enable</string>\n    <string name=\"service_status_automatic\">Awtomatiko</string>\n    <string name=\"service_status_manual\">Manwal</string>\n    <string name=\"service_status_enabled_short\">Nakabukas</string>\n    <string name=\"service_status_disabled_short\">Nakapatay</string>\n    <string name=\"foreground_service_notification_title\">Aktibo sa background</string>\n    <string name=\"foreground_service_notification_text\">Tumatakbo ang <xliff:g example=\"Exposure Notification\">%1$s</xliff:g> sa background.</string>\n    <string name=\"foreground_service_notification_big_text\">Ibukod ang <xliff:g example=\"microG Services\">%1$s</xliff:g> sa pag-optimize ng baterya o palitan ang mga setting ng notification para itago ang notification na ito.</string>\n    <string name=\"menu_game_managed\">Mga Pinamamahalaang Game Account</string>\n</resources>\n"
  },
  {
    "path": "play-services-base/core/src/main/res/values-fr/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"menu_advanced\">Avancé</string>\n    <string name=\"list_no_item_none\">Aucun</string>\n    <string name=\"service_status_disabled\">Désactivé</string>\n    <string name=\"service_status_enabled\">Activé</string>\n    <string name=\"service_status_automatic\">Automatique</string>\n    <string name=\"service_status_manual\">Manuel</string>\n    <string name=\"foreground_service_notification_title\">Actif en arrière-plan</string>\n    <string name=\"open_app\">Ouvrir</string>\n    <string name=\"foreground_service_notification_big_text\">Exclure <xliff:g example=\"microG Services\">%1$s</xliff:g> de l\\'optimisation de la batterie ou modifier les paramètres des notifications pour désactiver cette notification.</string>\n    <string name=\"service_status_enabled_short\">Activé</string>\n    <string name=\"service_status_disabled_short\">Désactivé</string>\n    <string name=\"list_item_see_all\">Tout voir</string>\n    <string name=\"foreground_service_notification_text\"><xliff:g example=\"Exposure Notification\">%1$s</xliff:g> fonctionne en arrière-plan.</string>\n    <string name=\"menu_game_managed\">Comptes de Jeux Gérés</string>\n</resources>\n"
  },
  {
    "path": "play-services-base/core/src/main/res/values-ga/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=\"foreground_service_notification_title\">Gníomhach sa chúlra</string>\n    <string name=\"menu_advanced\">Casta</string>\n    <string name=\"service_status_enabled\">Cumasaithe</string>\n    <string name=\"service_status_automatic\">Uathoibríoch</string>\n    <string name=\"service_status_manual\">Lámhleabhar</string>\n    <string name=\"foreground_service_notification_big_text\">Fág <xliff:g example=\"MicroG Services\">%1$s</xliff:g> as an mbarrfheabhsú ceallraí nó athraigh socruithe fógra chun an fógra seo a chur i bhfolach.</string>\n    <string name=\"list_no_item_none\">Dada</string>\n    <string name=\"foreground_service_notification_text\"><xliff:g example=\"Fógra Nochta\">%1$s</xliff:g> ag rith sa chúlra.</string>\n    <string name=\"list_item_see_all\">Féach ar fad</string>\n    <string name=\"service_status_enabled_short\">Ar</string>\n    <string name=\"open_app\">Oscail</string>\n    <string name=\"service_status_disabled\">Faoi mhíchumas</string>\n    <string name=\"service_status_disabled_short\">As</string>\n    <string name=\"menu_game_managed\">Cuntais Cluiche Bainistithe</string>\n</resources>\n"
  },
  {
    "path": "play-services-base/core/src/main/res/values-hu/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=\"foreground_service_notification_title\">A háttérben aktív</string>\n    <string name=\"foreground_service_notification_big_text\">Engedélyezze <xliff:g example=\"microG szolgáltatások\">%1$s</xliff:g>nak az akkumulátoroptimalizálás kikapcsolását vagy változtasd meg az értesítési beállításokat hogy elrejtsd ezt az értesítést.</string>\n    <string name=\"menu_advanced\">Haladó</string>\n    <string name=\"menu_game_managed\">Játék fiókok kezelve</string>\n</resources>\n"
  },
  {
    "path": "play-services-base/core/src/main/res/values-in/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=\"list_item_see_all\">Lihat semua</string>\n    <string name=\"service_status_disabled\">Dinonaktifkan</string>\n    <string name=\"service_status_enabled\">Diaktifkan</string>\n    <string name=\"service_status_automatic\">Otomatis</string>\n    <string name=\"service_status_manual\">Manual</string>\n    <string name=\"service_status_enabled_short\">Aktif</string>\n    <string name=\"service_status_disabled_short\">Tidak aktif</string>\n    <string name=\"foreground_service_notification_title\">Aktif di latar belakang</string>\n    <string name=\"foreground_service_notification_text\"><xliff:g example=\"Pemberitahuan Paparan\">%1$s</xliff:g> berjalan di latar belakang.</string>\n    <string name=\"foreground_service_notification_big_text\">Exclude <xliff:g example=\"Layanan microG\">%1$s</xliff:g> dari pengoptimalan baterai atau ubah pengaturan notifikasi untuk menyembunyikan notifikasi ini.</string>\n    <string name=\"menu_advanced\">Lanjutan</string>\n    <string name=\"list_no_item_none\">Tidak ada</string>\n    <string name=\"open_app\">Buka</string>\n    <string name=\"menu_game_managed\">Akun Game yang Dikelola</string>\n</resources>\n"
  },
  {
    "path": "play-services-base/core/src/main/res/values-is/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=\"foreground_service_notification_title\">Virkt í bakgrunni</string>\n    <string name=\"menu_advanced\">Ítarlegt</string>\n    <string name=\"list_no_item_none\">Ekkert</string>\n    <string name=\"foreground_service_notification_text\"><xliff:g example=\"Tilkynning um berskjöldun\">%1$s</xliff:g> er keyrandi í bakgrunni.</string>\n    <string name=\"foreground_service_notification_big_text\">Undanskilja <xliff:g example=\"microG-þjónustur\">%1$s</xliff:g> frá rafhlöðusparnaði eða breyttu stillingum tilkynninga til að fela þessa tilkynningu.</string>\n    <string name=\"service_status_enabled\">Virkt</string>\n    <string name=\"service_status_automatic\">Sjálfvirkt</string>\n    <string name=\"service_status_disabled_short\">Slökkt</string>\n    <string name=\"open_app\">Opna</string>\n    <string name=\"service_status_disabled\">Óvirkt</string>\n    <string name=\"list_item_see_all\">Sjá allt</string>\n    <string name=\"service_status_manual\">Handvirkt</string>\n    <string name=\"service_status_enabled_short\">Kveikt</string>\n    <string name=\"menu_game_managed\">Stjórnaðir leikjareikningar</string>\n</resources>\n"
  },
  {
    "path": "play-services-base/core/src/main/res/values-it/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=\"foreground_service_notification_title\">Esecuzione in background</string>\n    <string name=\"foreground_service_notification_text\"><xliff:g example=\"Exposure Notification\">%1$s</xliff:g> è in esecuzione in background.</string>\n    <string name=\"foreground_service_notification_big_text\">Disabilita le ottimizzazioni della batteria per <xliff:g example=\"microG Services\">%1$s</xliff:g> oppure modifica le impostazioni delle notifiche per nascondere questa notifica.</string>\n    <string name=\"menu_advanced\">Impostazioni avanzate</string>\n    <string name=\"list_no_item_none\">Nessuna</string>\n    <string name=\"list_item_see_all\">Mostra tutte</string>\n    <string name=\"open_app\">Apri</string>\n    <string name=\"service_status_disabled\">Disabilitato</string>\n    <string name=\"service_status_enabled\">Abilitato</string>\n    <string name=\"service_status_automatic\">Automatico</string>\n    <string name=\"service_status_manual\">Manuale</string>\n    <string name=\"service_status_enabled_short\">Abilitato</string>\n    <string name=\"service_status_disabled_short\">Disabilitato</string>\n    <string name=\"menu_game_managed\">Account giochi gestiti</string>\n</resources>\n"
  },
  {
    "path": "play-services-base/core/src/main/res/values-iw/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n</resources>"
  },
  {
    "path": "play-services-base/core/src/main/res/values-ja/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"menu_advanced\">詳細設定</string>\n    <string name=\"list_no_item_none\">なし</string>\n    <string name=\"list_item_see_all\">すべて表示</string>\n    <string name=\"open_app\">開く</string>\n    <string name=\"service_status_disabled\">無効</string>\n    <string name=\"service_status_enabled\">有効</string>\n    <string name=\"service_status_automatic\">自動</string>\n    <string name=\"service_status_manual\">手動</string>\n    <string name=\"service_status_enabled_short\">On</string>\n    <string name=\"service_status_disabled_short\">オフ</string>\n    <string name=\"foreground_service_notification_title\">バックグラウンドで有効</string>\n    <string name=\"foreground_service_notification_text\"><xliff:g example=\"Exposure Notification\">%1$s</xliff:g> をバックグラウンドで実行しています。</string>\n    <string name=\"foreground_service_notification_big_text\"><xliff:g example=\"microG Services\">%1$s</xliff:g> をバッテリー最適化から除外するか、通知設定でこの通知を非表示にしてください。</string>\n    <string name=\"menu_game_managed\">Game アカウントの管理</string>\n</resources>\n"
  },
  {
    "path": "play-services-base/core/src/main/res/values-ko/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=\"foreground_service_notification_title\">백그라운드에서 활성화됨</string>\n    <string name=\"foreground_service_notification_text\"><xliff:g example=\"Exposure Notification\">%1$s</xliff:g>이 백그라운드에서 실행 중입니다.</string>\n    <string name=\"foreground_service_notification_big_text\">이 알림을 숨기려면 <xliff:g example=\"microG Services\">%1$s</xliff:g>를 배터리 최적화 목록에서 제외하거나 알림 설정을 변경하세요.</string>\n    <string name=\"menu_advanced\">고급</string>\n    <string name=\"menu_game_managed\">관리된 게임 계정</string>\n    <string name=\"list_no_item_none\">없음</string>\n    <string name=\"list_item_see_all\">모두 보기</string>\n    <string name=\"open_app\">열기</string>\n    <string name=\"service_status_disabled\">비활성화됨</string>\n    <string name=\"service_status_enabled\">활성화됨</string>\n    <string name=\"service_status_automatic\">자동</string>\n    <string name=\"service_status_manual\">수동</string>\n    <string name=\"service_status_enabled_short\">켜짐</string>\n    <string name=\"service_status_disabled_short\">꺼짐</string>\n</resources>\n"
  },
  {
    "path": "play-services-base/core/src/main/res/values-lv/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources></resources>"
  },
  {
    "path": "play-services-base/core/src/main/res/values-lzh/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources></resources>"
  },
  {
    "path": "play-services-base/core/src/main/res/values-ml/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=\"foreground_service_notification_title\">പശ്ചാത്തലത്തിൽ സജീവമാണ്</string>\n    <string name=\"foreground_service_notification_text\"><xliff:g example=\"Exposure Notification\">%1$s</xliff:g> പശ്ചാത്തലത്തിൽ പ്രവർത്തിക്കുന്നു.</string>\n    <string name=\"foreground_service_notification_big_text\">ബാറ്ററി ഒപ്റ്റിമൈസേഷനുകളിൽ നിന്ന് <xliff:g example=\"microG Services\">%1$s</xliff:g> ഒഴിവാക്കുക അല്ലെങ്കിൽ ഈ അറിയിപ്പ് മറയ്ക്കാൻ അറിയിപ്പ് ക്രമീകരണങ്ങൾ മാറ്റുക.</string>\n    <string name=\"menu_advanced\">വിപുലമായത്</string>\n    <string name=\"menu_game_managed\">ഗെയിം അക്കൗണ്ടുകൾ കൈകാര്യം ചെയ്യുന്നു</string>\n    <string name=\"list_no_item_none\">ഒന്നുമില്ല</string>\n    <string name=\"list_item_see_all\">എല്ലാം കാണുക</string>\n    <string name=\"open_app\">തുറക്കുക</string>\n    <string name=\"service_status_disabled\">അപ്രാപ്തമാക്കി</string>\n    <string name=\"service_status_enabled\">പ്രവർത്തനക്ഷമമാക്കി</string>\n    <string name=\"service_status_automatic\">ഓട്ടോമാറ്റിക്</string>\n    <string name=\"service_status_manual\">മാനുവൽ</string>\n    <string name=\"service_status_enabled_short\">ഓൺ</string>\n    <string name=\"service_status_disabled_short\">ഓഫ്</string>\n</resources>\n"
  },
  {
    "path": "play-services-base/core/src/main/res/values-nb-rNO/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=\"menu_advanced\">Avansert</string>\n    <string name=\"open_app\">Åpne</string>\n    <string name=\"foreground_service_notification_title\">Aktiv i bakgrunnen</string>\n    <string name=\"foreground_service_notification_text\"><xliff:g example=\"Exposure Notification\">%1$s</xliff:g> kjører i bakgrunnen.</string>\n    <string name=\"foreground_service_notification_big_text\">Ekskluder <xliff:g example=\"microG Services\">%1$s</xliff:g> fra batterioptimaliseringer eller endre varselinnstillinger for å gjemme dette varselet.</string>\n    <string name=\"menu_game_managed\">Håndterte spillkontoer</string>\n    <string name=\"list_no_item_none\">Ingen</string>\n    <string name=\"list_item_see_all\">Se alle</string>\n    <string name=\"service_status_disabled\">Deaktivert</string>\n    <string name=\"service_status_enabled\">Aktivert</string>\n    <string name=\"service_status_automatic\">Automatisk</string>\n    <string name=\"service_status_manual\">Manuelt</string>\n    <string name=\"service_status_enabled_short\">På</string>\n    <string name=\"service_status_disabled_short\">Av</string>\n</resources>\n"
  },
  {
    "path": "play-services-base/core/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\">\n    <string name=\"foreground_service_notification_title\">Actief op achtergrond</string>\n    <string name=\"foreground_service_notification_text\"><xliff:g example=\"Blootstelling Melding\">%1$s</xliff:g> draait op de achtergrond.</string>\n    <string name=\"foreground_service_notification_big_text\">Sluit &lt;xliff:g example=“microG Services”&gt;%1$s&lt;/xliff:g&gt; uit van batterijoptimalisaties of wijzig de instellingen voor meldingen om deze melding te verbergen.</string>\n    <string name=\"menu_advanced\">Geavanceerd</string>\n    <string name=\"list_no_item_none\">Geen</string>\n    <string name=\"list_item_see_all\">Zie alles</string>\n    <string name=\"open_app\">Open</string>\n    <string name=\"service_status_disabled\">Uitgeschakeld</string>\n    <string name=\"service_status_enabled\">Ingeschakeld</string>\n    <string name=\"service_status_automatic\">Automatisch</string>\n    <string name=\"service_status_manual\">Manueel</string>\n    <string name=\"service_status_enabled_short\">Aan</string>\n    <string name=\"service_status_disabled_short\">Uit</string>\n</resources>\n"
  },
  {
    "path": "play-services-base/core/src/main/res/values-pl/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"menu_advanced\">Zaawansowane</string>\n    <string name=\"list_no_item_none\">Brak</string>\n    <string name=\"service_status_disabled\">Wyłączona</string>\n    <string name=\"service_status_enabled\">Włączona</string>\n    <string name=\"service_status_automatic\">Automatycznie</string>\n    <string name=\"service_status_manual\">Ręcznie</string>\n    <string name=\"foreground_service_notification_title\">Aktywna w tle</string>\n    <string name=\"service_status_enabled_short\">Wł.</string>\n    <string name=\"open_app\">Otwórz</string>\n    <string name=\"foreground_service_notification_text\"><xliff:g example=\"Powiadomienia o narażeniu\">%1$s</xliff:g> jest uruchomiona w tle.</string>\n    <string name=\"foreground_service_notification_big_text\">Wyłącz optymalizację baterii dla <xliff:g example=\"Usług microG\">%1$s</xliff:g> lub zmień ustawienia powiadomień, aby ukryć to powiadomienie.</string>\n    <string name=\"list_item_see_all\">Wyświetl wszystkie</string>\n    <string name=\"service_status_disabled_short\">Wył.</string>\n    <string name=\"menu_game_managed\">Zarządzane kontami gier</string>\n</resources>\n"
  },
  {
    "path": "play-services-base/core/src/main/res/values-pt/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=\"foreground_service_notification_title\">Ativo em segundo plano</string>\n    <string name=\"foreground_service_notification_text\"><xliff:g example=\"Exposure Notification\">%1$s</xliff:g> está em execução em segundo plano.</string>\n    <string name=\"foreground_service_notification_big_text\">Exclua <xliff:g example=\"microG Services\">%1$s</xliff:g> das configurações de otimizações de pilha ou mude as configurações da notificação para esconder esta notificação.</string>\n    <string name=\"menu_advanced\">Avançado</string>\n    <string name=\"menu_game_managed\">Contas de jogo gerenciadas</string>\n    <string name=\"list_no_item_none\">Nenhum</string>\n    <string name=\"list_item_see_all\">Ver tudo</string>\n    <string name=\"open_app\">Abrir</string>\n    <string name=\"service_status_disabled\">Desativado</string>\n    <string name=\"service_status_enabled\">Ativado</string>\n    <string name=\"service_status_automatic\">Automático</string>\n    <string name=\"service_status_manual\">Manual</string>\n    <string name=\"service_status_enabled_short\">Ligado</string>\n    <string name=\"service_status_disabled_short\">Desligado</string>\n</resources>\n"
  },
  {
    "path": "play-services-base/core/src/main/res/values-pt-rBR/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"menu_advanced\">Avançado</string>\n    <string name=\"list_no_item_none\">Nenhum</string>\n    <string name=\"foreground_service_notification_text\"><xliff:g example=\"Exposure Notification\">%1$s</xliff:g> está em execução em segundo plano.</string>\n    <string name=\"service_status_enabled_short\">Ativado</string>\n    <string name=\"service_status_disabled_short\">Desativado</string>\n    <string name=\"foreground_service_notification_title\">Ativo em segundo plano</string>\n    <string name=\"foreground_service_notification_big_text\">Remova <xliff:g example=\"microG Services\">%1$s</xliff:g> das configurações de otimizações de bateria ou mude as configurações da notificação para esconder esta notificação.</string>\n    <string name=\"list_item_see_all\">Ver tudo</string>\n    <string name=\"open_app\">Abrir</string>\n    <string name=\"service_status_disabled\">Desativado</string>\n    <string name=\"service_status_enabled\">Ativado</string>\n    <string name=\"service_status_automatic\">Automático</string>\n    <string name=\"service_status_manual\">Manual</string>\n    <string name=\"menu_game_managed\">Contas de jogo gerenciadas</string>\n</resources>\n"
  },
  {
    "path": "play-services-base/core/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=\"foreground_service_notification_title\">Activ în fundal</string>\n    <string name=\"menu_advanced\">Avansat</string>\n    <string name=\"service_status_disabled\">Dezactivat</string>\n    <string name=\"service_status_enabled_short\">Pornit</string>\n    <string name=\"service_status_automatic\">Automat</string>\n    <string name=\"service_status_enabled\">Activat</string>\n    <string name=\"open_app\">Deschide</string>\n    <string name=\"foreground_service_notification_text\"><xliff:g example=\"Exposure Notification\">%1$s</xliff:g> rulează în fundal.</string>\n    <string name=\"foreground_service_notification_big_text\">Exclude <xliff:g example=\"microG Services\">%1$s</xliff:g> din optimizările bateriei sau modifică setările de notificare pentru a ascunde această notificare.</string>\n    <string name=\"list_item_see_all\">Arată tot</string>\n    <string name=\"service_status_disabled_short\">Oprit</string>\n    <string name=\"list_no_item_none\">Nimic</string>\n    <string name=\"service_status_manual\">Manual</string>\n    <string name=\"menu_game_managed\">Conturile de joc gestionate</string>\n</resources>\n"
  },
  {
    "path": "play-services-base/core/src/main/res/values-ru/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"foreground_service_notification_title\">Фоновая активность</string>\n    <string name=\"foreground_service_notification_text\"><xliff:g example=\"Exposure Notification\">%1$s</xliff:g> работает в фоновом режиме.</string>\n    <string name=\"foreground_service_notification_big_text\">Отключите экономию заряда батареи для <xliff:g example=\"microG Services\">%1$s</xliff:g>, чтобы убрать это уведомление.</string>\n    <string name=\"menu_advanced\">Дополнительно</string>\n    <string name=\"list_no_item_none\">Пусто</string>\n    <string name=\"list_item_see_all\">Показать всё</string>\n    <string name=\"open_app\">Открыть</string>\n    <string name=\"service_status_disabled\">Выключено</string>\n    <string name=\"service_status_enabled\">Включено</string>\n    <string name=\"service_status_automatic\">Автоматически</string>\n    <string name=\"service_status_manual\">Вручную</string>\n    <string name=\"service_status_enabled_short\">Вкл.</string>\n    <string name=\"service_status_disabled_short\">Выкл.</string>\n    <string name=\"menu_game_managed\">Управление игровыми аккаунтами</string>\n</resources>\n"
  },
  {
    "path": "play-services-base/core/src/main/res/values-sl/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n</resources>"
  },
  {
    "path": "play-services-base/core/src/main/res/values-sr/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"menu_advanced\">Напредно</string>\n    <string name=\"list_no_item_none\">Ниједно</string>\n    <string name=\"foreground_service_notification_title\">Активно у позадини</string>\n    <string name=\"service_status_disabled\">Онемогућено</string>\n    <string name=\"service_status_enabled_short\">Укључено</string>\n    <string name=\"service_status_automatic\">Аутоматски</string>\n    <string name=\"service_status_enabled\">Омогућено</string>\n    <string name=\"open_app\">Отвори</string>\n    <string name=\"foreground_service_notification_text\"><xliff:g example=\"Exposure Notification\">%1$s</xliff:g> ради у позадини.</string>\n    <string name=\"foreground_service_notification_big_text\">Искључите <xliff:g example=\"microG Services\"> %1$s</xliff:g> из оптимизације батерије или промените подешавања обавештења да бисте сакрили ово обавештење.</string>\n    <string name=\"list_item_see_all\">Види све</string>\n    <string name=\"service_status_disabled_short\">Искључено</string>\n    <string name=\"service_status_manual\">Ручно</string>\n    <string name=\"menu_game_managed\">Управљање налозима игара</string>\n</resources>\n"
  },
  {
    "path": "play-services-base/core/src/main/res/values-sv/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=\"foreground_service_notification_title\">Aktiv i bakgrunden</string>\n    <string name=\"menu_advanced\">Avancerat</string>\n    <string name=\"service_status_disabled\">Inaktiverad</string>\n    <string name=\"service_status_enabled_short\">På</string>\n    <string name=\"service_status_automatic\">Automatiskt</string>\n    <string name=\"service_status_enabled\">Aktiverad</string>\n    <string name=\"open_app\">Öppna</string>\n    <string name=\"foreground_service_notification_text\"><xliff:g example=\"Exposure Notification\">%1$s</xliff:g> körs i bakgrunden.</string>\n    <string name=\"foreground_service_notification_big_text\">Exkludera <xliff:g example=\"microG Services\">%1$s</xliff:g> från batterioptimering eller ändra aviseringsinställningar för att dölja detta meddelande.</string>\n    <string name=\"list_item_see_all\">Se alla</string>\n    <string name=\"service_status_disabled_short\">Av</string>\n    <string name=\"list_no_item_none\">Ingen</string>\n    <string name=\"service_status_manual\">Manuell</string>\n    <string name=\"menu_game_managed\">Hanterade spelkonton</string>\n</resources>\n"
  },
  {
    "path": "play-services-base/core/src/main/res/values-ta/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=\"foreground_service_notification_title\">பின்னணியில் செயலில் உள்ளது</string>\n    <string name=\"menu_advanced\">மேம்பட்ட</string>\n    <string name=\"list_no_item_none\">எதுவுமில்லை</string>\n    <string name=\"list_item_see_all\">அனைத்தையும் காண்க</string>\n    <string name=\"open_app\">திற</string>\n    <string name=\"service_status_disabled\">முடக்கப்பட்டது</string>\n    <string name=\"service_status_enabled\">இயக்கப்பட்டது</string>\n    <string name=\"service_status_automatic\">தானியங்கி</string>\n    <string name=\"service_status_manual\">கையேடு</string>\n    <string name=\"service_status_enabled_short\">ஆம்</string>\n    <string name=\"service_status_disabled_short\">அணை</string>\n    <string name=\"foreground_service_notification_text\"><xliff:g example=\"Exposure Notification\">%1$s</xliff:g> பின்னணியில் இயங்குகிறது.</string>\n    <string name=\"foreground_service_notification_big_text\">பேட்டரி மேம்படுத்தல்களிலிருந்து <xliff:g example=\"microG Services\">%1$s</xliff:g>ஐ விலக்கு அல்லது இந்த அறிவிப்பை மறைக்க அறிவிப்பு அமைப்புகளை மாற்றவும்.</string>\n    <string name=\"menu_game_managed\">நிர்வகிக்கப்படும் விளையாட்டு கணக்குகள்</string>\n</resources>\n"
  },
  {
    "path": "play-services-base/core/src/main/res/values-th/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=\"foreground_service_notification_title\">ทำงานในพื้นหลัง</string>\n    <string name=\"foreground_service_notification_text\"><xliff:g example=\"ระบบแจ้งเตือนเมื่อใกล้ชิดผู้ติดเชื้อ\">%1$s</xliff:g> กำลังทำงานอยู่ในพื้นหลัง</string>\n    <string name=\"foreground_service_notification_big_text\">ไม่รวม <xliff:g example=\"บริการ microG\">%1$s</xliff:g> จากการเพิ่มประสิทธิภาพแบตเตอรี่หรือเปลี่ยนการตั้งค่าการแจ้งเตือนเพื่อซ่อนการแจ้งเตือนนี้</string>\n    <string name=\"menu_advanced\">ขั้นสูง</string>\n    <string name=\"list_no_item_none\">ไม่มี</string>\n    <string name=\"list_item_see_all\">ดูทั้งหมด</string>\n    <string name=\"open_app\">เปิด</string>\n    <string name=\"service_status_disabled\">ปิดการทำงาน</string>\n    <string name=\"service_status_enabled\">เปิดใช้งานแล้ว</string>\n    <string name=\"service_status_automatic\">อัตโนมัติ</string>\n    <string name=\"service_status_manual\">คู่มือ</string>\n    <string name=\"service_status_enabled_short\">เปิด</string>\n    <string name=\"service_status_disabled_short\">ปิด</string>\n    <string name=\"menu_game_managed\">จัดการบัญชีเกม</string>\n</resources>\n"
  },
  {
    "path": "play-services-base/core/src/main/res/values-tr/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=\"foreground_service_notification_title\">Arka planda aktif</string>\n    <string name=\"foreground_service_notification_text\"><xliff:g example=\"Maruz Kalma Bildirimi\">%1$s</xliff:g> arka planda çalışıyor.</string>\n    <string name=\"menu_advanced\">Gelişmiş</string>\n    <string name=\"list_no_item_none\">Hiçbiri</string>\n    <string name=\"list_item_see_all\">Hepsini gör</string>\n    <string name=\"service_status_manual\">Manuel</string>\n    <string name=\"service_status_enabled_short\">Açık</string>\n    <string name=\"service_status_disabled_short\">Kapalı</string>\n    <string name=\"foreground_service_notification_big_text\">Bildirimi gizlemek için <xliff:g example=\"microG Servisleri\">%1$s</xliff:g>\\'ni pil optimizasyonlarından hariç tutun veya bildirim ayarlarını değiştirin.</string>\n    <string name=\"open_app\">Aç</string>\n    <string name=\"service_status_disabled\">Devre dışı</string>\n    <string name=\"service_status_enabled\">Etkin</string>\n    <string name=\"service_status_automatic\">Otomatik</string>\n    <string name=\"menu_game_managed\">Yönetilen Oyun Hesapları</string>\n</resources>\n"
  },
  {
    "path": "play-services-base/core/src/main/res/values-ug/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=\"foreground_service_notification_text\"><xliff:g example=\"Exposure Notification\">%1$s</xliff:g> ئارقا سۇپىدا ئىجرا قىلىنىۋاتىدۇ.</string>\n    <string name=\"foreground_service_notification_big_text\"><xliff:g example=\"microG Services\">%1$s</xliff:g> غا توكدان ئەلالاشتۇرۇشقا پەرۋا قىلماسلىق ياكى بۇ ئۇقتۇرۇشنى يوشۇرۇش ئۈچۈن ئۇقتۇرۇش تەڭشىكىنى ئۆزگەرتىش كېرەك.</string>\n    <string name=\"service_status_disabled_short\">تاقاق</string>\n    <string name=\"service_status_automatic\">ئۆزلۈكىدىن</string>\n    <string name=\"service_status_enabled\">قوزغىتىلدى</string>\n    <string name=\"foreground_service_notification_title\">ئارقا سۇپىدا ئاكتىپ</string>\n    <string name=\"menu_advanced\">ئالىي</string>\n    <string name=\"list_no_item_none\">يوق</string>\n    <string name=\"list_item_see_all\">ھەممىنى كۆرسەت</string>\n    <string name=\"open_app\">ئاچ</string>\n    <string name=\"service_status_disabled\">چەكلەندى</string>\n    <string name=\"service_status_manual\">قولدا</string>\n    <string name=\"service_status_enabled_short\">ئوچۇق</string>\n    <string name=\"menu_game_managed\">ئويۇن ھېساباتىنى باشقۇرۇش</string>\n</resources>\n"
  },
  {
    "path": "play-services-base/core/src/main/res/values-uk/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"menu_advanced\">Розширені</string>\n    <string name=\"list_no_item_none\">Порожньо</string>\n    <string name=\"service_status_disabled\">Вимкнуто</string>\n    <string name=\"service_status_enabled\">Увімкнуто</string>\n    <string name=\"service_status_automatic\">Автоматично</string>\n    <string name=\"service_status_manual\">Вручну</string>\n    <string name=\"foreground_service_notification_title\">Активний у фоновому режимі</string>\n    <string name=\"service_status_enabled_short\">Ввімк</string>\n    <string name=\"open_app\">Відкрити</string>\n    <string name=\"foreground_service_notification_text\"><xliff:g example=\"Exposure Notification\">%1$s</xliff:g> працює у фоновому режимі.</string>\n    <string name=\"foreground_service_notification_big_text\">Виключити <xliff:g example=\"microG Services\">%1$s</xliff:g> з оптимізації батареї або змінити налаштування сповіщень, щоб приховати це сповіщення.</string>\n    <string name=\"list_item_see_all\">Показати все</string>\n    <string name=\"service_status_disabled_short\">Вимк</string>\n    <string name=\"menu_game_managed\">Керування ігровими обліковими записами</string>\n</resources>\n"
  },
  {
    "path": "play-services-base/core/src/main/res/values-vi/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=\"foreground_service_notification_big_text\">Để ẩn thông báo này, bạn có thể tắt tối ưu hóa pin cho <xliff:g example=\"microG Services\">%1$s</xliff:g> hoặc điều chỉnh cài đặt thông báo.</string>\n    <string name=\"menu_advanced\">Nâng cao</string>\n    <string name=\"list_item_see_all\">Xem tất cả</string>\n    <string name=\"service_status_automatic\">Tự động</string>\n    <string name=\"list_no_item_none\">Không</string>\n    <string name=\"open_app\">Mở</string>\n    <string name=\"service_status_disabled\">Tắt</string>\n    <string name=\"service_status_enabled\">Bật</string>\n    <string name=\"service_status_disabled_short\">Tắt</string>\n    <string name=\"foreground_service_notification_title\">Hoạt động trong nền</string>\n    <string name=\"service_status_manual\">Thủ công</string>\n    <string name=\"service_status_enabled_short\">Bật</string>\n    <string name=\"foreground_service_notification_text\"><xliff:g example=\"Exposure Notification\">1%1$s</xliff:g> đang hoạt động trong nền.</string>\n    <string name=\"menu_game_managed\">Quản lý tài khoản trò chơi</string>\n</resources>\n"
  },
  {
    "path": "play-services-base/core/src/main/res/values-zh-rCN/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=\"foreground_service_notification_title\">正在后台活动</string>\n    <string name=\"foreground_service_notification_text\"><xliff:g example=\"Exposure Notification\">%1$s</xliff:g> 正在后台运行。</string>\n    <string name=\"foreground_service_notification_big_text\">对 <xliff:g example=\"microG Services\">%1$s</xliff:g> 忽略电池优化，或者修改通知设置以隐藏此通知。</string>\n    <string name=\"menu_advanced\">高级</string>\n    <string name=\"menu_game_managed\">管理游戏账号</string>\n    <string name=\"list_no_item_none\">无</string>\n    <string name=\"list_item_see_all\">全部显示</string>\n    <string name=\"open_app\">打开</string>\n    <string name=\"service_status_disabled\">已禁用</string>\n    <string name=\"service_status_enabled\">已启用</string>\n    <string name=\"service_status_automatic\">自动</string>\n    <string name=\"service_status_manual\">手动</string>\n    <string name=\"service_status_enabled_short\">开</string>\n    <string name=\"service_status_disabled_short\">关</string>\n</resources>"
  },
  {
    "path": "play-services-base/core/src/main/res/values-zh-rTW/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"menu_advanced\">進階</string>\n    <string name=\"list_no_item_none\">無</string>\n    <string name=\"foreground_service_notification_title\">正在背景運作</string>\n    <string name=\"service_status_disabled\">已停用</string>\n    <string name=\"service_status_automatic\">自動</string>\n    <string name=\"service_status_enabled\">已啟用</string>\n    <string name=\"service_status_enabled_short\">開啟</string>\n    <string name=\"service_status_disabled_short\">關閉</string>\n    <string name=\"service_status_manual\">手動</string>\n    <string name=\"open_app\">開啟</string>\n    <string name=\"foreground_service_notification_big_text\">將 <xliff:g example=\"microG Services\">%1$s</xliff:g> 排除在電池最佳化之外，或變更通知設定以隱藏此通知。</string>\n    <string name=\"foreground_service_notification_text\"><xliff:g example=\"暴露通知\">%1$s</xliff:g> 正在後臺運行。</string>\n    <string name=\"list_item_see_all\">顯示全部</string>\n</resources>\n"
  },
  {
    "path": "play-services-base/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2015 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n\n    <application>\n        <activity\n            android:name=\"com.google.android.gms.common.api.GoogleApiActivity\"\n            android:exported=\"false\"\n            android:theme=\"@android:style/Theme.Translucent.NoTitleBar\"/>\n    </application>\n</manifest>\n"
  },
  {
    "path": "play-services-base/src/main/aidl/com/google/android/gms/auth/api/signin/GoogleSignInAccount.aidl",
    "content": "package com.google.android.gms.auth.api.signin;\n\nparcelable GoogleSignInAccount;"
  },
  {
    "path": "play-services-base/src/main/aidl/com/google/android/gms/auth/api/signin/GoogleSignInOptions.aidl",
    "content": "package com.google.android.gms.auth.api.signin;\n\nparcelable GoogleSignInOptions;"
  },
  {
    "path": "play-services-base/src/main/aidl/com/google/android/gms/common/api/internal/IStatusCallback.aidl",
    "content": "package com.google.android.gms.common.api.internal;\n\nimport com.google.android.gms.common.api.Status;\n\ninterface IStatusCallback {\n    void onResult(in Status status);\n}\n"
  },
  {
    "path": "play-services-base/src/main/aidl/com/google/android/gms/common/data/BitmapTeleporter.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.data;\n\nparcelable BitmapTeleporter;\n"
  },
  {
    "path": "play-services-base/src/main/aidl/com/google/android/gms/common/data/DataHolder.aidl",
    "content": "package com.google.android.gms.common.data;\n\nparcelable DataHolder;\n"
  },
  {
    "path": "play-services-base/src/main/aidl/com/google/android/gms/common/images/WebImage.aidl",
    "content": "package com.google.android.gms.common.images;\n\nparcelable WebImage;\n"
  },
  {
    "path": "play-services-base/src/main/aidl/com/google/android/gms/common/internal/AuthAccountRequest.aidl",
    "content": "package com.google.android.gms.common.internal;\n\nparcelable AuthAccountRequest;\n"
  },
  {
    "path": "play-services-base/src/main/aidl/com/google/android/gms/common/internal/IResolveAccountCallbacks.aidl",
    "content": "package com.google.android.gms.common.internal;\n\ninterface IResolveAccountCallbacks {\n\n}\n"
  },
  {
    "path": "play-services-base/src/main/aidl/com/google/android/gms/common/internal/ISignInButtonCreator.aidl",
    "content": "package com.google.android.gms.common.internal;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\n\ninterface ISignInButtonCreator {\n    IObjectWrapper createSignInButton(IObjectWrapper context, int size, int color); // returns View\n}\n"
  },
  {
    "path": "play-services-base/src/main/aidl/com/google/android/gms/common/internal/MethodInvocation.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.internal;\n\nparcelable MethodInvocation;"
  },
  {
    "path": "play-services-base/src/main/aidl/com/google/android/gms/common/internal/ResolveAccountRequest.aidl",
    "content": "package com.google.android.gms.common.internal;\n\nparcelable ResolveAccountRequest;\n"
  },
  {
    "path": "play-services-base/src/main/aidl/com/google/android/gms/common/internal/TelemetryData.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.internal;\n\nparcelable TelemetryData;"
  },
  {
    "path": "play-services-base/src/main/aidl/com/google/android/gms/common/internal/service/IClientTelemetryService.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.internal.service;\n\nimport com.google.android.gms.common.internal.TelemetryData;\n\ninterface IClientTelemetryService {\n    oneway void log(in TelemetryData data) = 0;\n}"
  },
  {
    "path": "play-services-base/src/main/aidl/com/google/android/gms/common/internal/service/ICommonCallbacks.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2026 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.internal.service;\n\ninterface ICommonCallbacks {\n    void onClearDefaultAccountResult(int statusCode);\n}"
  },
  {
    "path": "play-services-base/src/main/aidl/com/google/android/gms/common/internal/service/ICommonService.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2026 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.internal.service;\n\nimport com.google.android.gms.common.internal.service.ICommonCallbacks;\n\ninterface ICommonService {\n    void clearDefaultAccount(in ICommonCallbacks callbacks) = 0;\n}"
  },
  {
    "path": "play-services-base/src/main/aidl/com/google/android/gms/common/moduleinstall/ModuleAvailabilityResponse.aidl",
    "content": "package com.google.android.gms.common.moduleinstall;\n\nparcelable ModuleAvailabilityResponse;\n"
  },
  {
    "path": "play-services-base/src/main/aidl/com/google/android/gms/common/moduleinstall/ModuleInstallIntentResponse.aidl",
    "content": "package com.google.android.gms.common.moduleinstall;\n\nparcelable ModuleInstallIntentResponse;\n"
  },
  {
    "path": "play-services-base/src/main/aidl/com/google/android/gms/common/moduleinstall/ModuleInstallResponse.aidl",
    "content": "package com.google.android.gms.common.moduleinstall;\n\nparcelable ModuleInstallResponse;\n"
  },
  {
    "path": "play-services-base/src/main/aidl/com/google/android/gms/common/moduleinstall/ModuleInstallStatusUpdate.aidl",
    "content": "package com.google.android.gms.common.moduleinstall;\n\nparcelable ModuleInstallStatusUpdate;\n"
  },
  {
    "path": "play-services-base/src/main/aidl/com/google/android/gms/common/moduleinstall/internal/ApiFeatureRequest.aidl",
    "content": "package com.google.android.gms.common.moduleinstall.internal;\n\nparcelable ApiFeatureRequest;\n"
  },
  {
    "path": "play-services-base/src/main/aidl/com/google/android/gms/common/moduleinstall/internal/IModuleInstallCallbacks.aidl",
    "content": "package com.google.android.gms.common.moduleinstall.internal;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.common.moduleinstall.ModuleAvailabilityResponse;\nimport com.google.android.gms.common.moduleinstall.ModuleInstallIntentResponse;\nimport com.google.android.gms.common.moduleinstall.ModuleInstallResponse;\n\ninterface IModuleInstallCallbacks {\n    void onModuleAvailabilityResponse(in Status status, in ModuleAvailabilityResponse response) = 0;\n    void onModuleInstallResponse(in Status status, in ModuleInstallResponse response) = 1;\n    void onModuleInstallIntentResponse(in Status status, in ModuleInstallIntentResponse response) = 2;\n    void onStatus(in Status status) = 3;\n}\n"
  },
  {
    "path": "play-services-base/src/main/aidl/com/google/android/gms/common/moduleinstall/internal/IModuleInstallService.aidl",
    "content": "package com.google.android.gms.common.moduleinstall.internal;\n\nimport com.google.android.gms.common.api.internal.IStatusCallback;\nimport com.google.android.gms.common.moduleinstall.internal.ApiFeatureRequest;\nimport com.google.android.gms.common.moduleinstall.internal.IModuleInstallCallbacks;\nimport com.google.android.gms.common.moduleinstall.internal.IModuleInstallStatusListener;\n\ninterface IModuleInstallService {\n    void areModulesAvailable(IModuleInstallCallbacks callbacks, in ApiFeatureRequest request) = 0;\n    void installModules(IModuleInstallCallbacks callbacks, in ApiFeatureRequest request, IModuleInstallStatusListener listener) = 1;\n    void getInstallModulesIntent(IModuleInstallCallbacks callbacks, in ApiFeatureRequest request) = 2;\n    void releaseModules(IStatusCallback callback, in ApiFeatureRequest request) = 3;\n    void unregisterListener(IStatusCallback callback, IModuleInstallStatusListener listener) = 5;\n}\n"
  },
  {
    "path": "play-services-base/src/main/aidl/com/google/android/gms/common/moduleinstall/internal/IModuleInstallStatusListener.aidl",
    "content": "package com.google.android.gms.common.moduleinstall.internal;\n\nimport com.google.android.gms.common.moduleinstall.ModuleInstallStatusUpdate;\n\ninterface IModuleInstallStatusListener {\n    void onModuleInstallStatusUpdate(in ModuleInstallStatusUpdate statusUpdate) = 0;\n}\n"
  },
  {
    "path": "play-services-base/src/main/aidl/com/google/android/gms/common/server/FavaDiagnosticsEntity.aidl",
    "content": "package com.google.android.gms.common.server;\n\nparcelable FavaDiagnosticsEntity;"
  },
  {
    "path": "play-services-base/src/main/aidl/com/google/android/gms/signin/internal/AuthAccountResult.aidl",
    "content": "package com.google.android.gms.signin.internal;\n\nparcelable AuthAccountResult;"
  },
  {
    "path": "play-services-base/src/main/aidl/com/google/android/gms/signin/internal/CheckServerAuthResult.aidl",
    "content": "package com.google.android.gms.signin.internal;\n\nparcelable CheckServerAuthResult;"
  },
  {
    "path": "play-services-base/src/main/aidl/com/google/android/gms/signin/internal/ISignInCallbacks.aidl",
    "content": "package com.google.android.gms.signin.internal;\n\nimport com.google.android.gms.auth.api.signin.GoogleSignInAccount;\nimport com.google.android.gms.common.ConnectionResult;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.signin.internal.AuthAccountResult;\nimport com.google.android.gms.signin.internal.RecordConsentByConsentResultResponse;\nimport com.google.android.gms.signin.internal.SignInResponse;\n\ninterface ISignInCallbacks {\n    void onAuthAccount(in ConnectionResult connectionResult, in AuthAccountResult result) = 2;\n    void onPutAccount(in Status status) = 3;\n    void onRecordConsent(in Status status) = 5;\n    void onCurrentAccount(in Status status, in GoogleSignInAccount account) = 6;\n    void onSignIn(in SignInResponse response) = 7;\n    void onRecordConsentByConsent(in RecordConsentByConsentResultResponse response) = 8;\n}"
  },
  {
    "path": "play-services-base/src/main/aidl/com/google/android/gms/signin/internal/ISignInService.aidl",
    "content": "package com.google.android.gms.signin.internal;\n\nimport com.google.android.gms.common.internal.AuthAccountRequest;\nimport com.google.android.gms.common.internal.ResolveAccountRequest;\nimport com.google.android.gms.common.internal.IAccountAccessor;\nimport com.google.android.gms.common.internal.IResolveAccountCallbacks;\nimport com.google.android.gms.signin.internal.ISignInCallbacks;\nimport com.google.android.gms.signin.internal.CheckServerAuthResult;\nimport com.google.android.gms.signin.internal.RecordConsentRequest;\nimport com.google.android.gms.signin.internal.RecordConsentByConsentResultRequest;\nimport com.google.android.gms.signin.internal.SignInRequest;\n\ninterface ISignInService {\n    void authAccount(in AuthAccountRequest request, ISignInCallbacks callbacks) = 1;\n    void onCheckServerAuthorization(in CheckServerAuthResult result) = 2;\n    void onUploadServerAuthCode(int sessionId) = 3;\n    void resolveAccount(in ResolveAccountRequest request, IResolveAccountCallbacks callbacks) = 4;\n\n    void clearAccountFromSessionStore(int sessionId) = 6;\n    void putAccount(int sessionId, in Account account, ISignInCallbacks callbacks) = 7;\n    void saveDefaultAccount(IAccountAccessor accountAccessor, int sessionId, boolean crossClient) = 8;\n    void saveConsent(in RecordConsentRequest request, ISignInCallbacks callbacks) = 9;\n    void getCurrentAccount(ISignInCallbacks callbacks) = 10;\n    void signIn(in SignInRequest request, ISignInCallbacks callbacks) = 11;\n    void setGamesHasBeenGreeted(boolean hasGreeted) = 12;\n    void recordConsentByConsentResult(in RecordConsentByConsentResultRequest request, ISignInCallbacks callbacks) = 13;\n}"
  },
  {
    "path": "play-services-base/src/main/aidl/com/google/android/gms/signin/internal/RecordConsentByConsentResultRequest.aidl",
    "content": "package com.google.android.gms.signin.internal;\n\nparcelable RecordConsentByConsentResultRequest;"
  },
  {
    "path": "play-services-base/src/main/aidl/com/google/android/gms/signin/internal/RecordConsentByConsentResultResponse.aidl",
    "content": "package com.google.android.gms.signin.internal;\n\nparcelable RecordConsentByConsentResultResponse;"
  },
  {
    "path": "play-services-base/src/main/aidl/com/google/android/gms/signin/internal/RecordConsentRequest.aidl",
    "content": "package com.google.android.gms.signin.internal;\n\nparcelable RecordConsentRequest;"
  },
  {
    "path": "play-services-base/src/main/aidl/com/google/android/gms/signin/internal/SignInRequest.aidl",
    "content": "package com.google.android.gms.signin.internal;\n\nparcelable SignInRequest;"
  },
  {
    "path": "play-services-base/src/main/aidl/com/google/android/gms/signin/internal/SignInResponse.aidl",
    "content": "package com.google.android.gms.signin.internal;\n\nparcelable SignInResponse;"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/auth/api/signin/GoogleSignInAccount.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.api.signin;\n\nimport android.accounts.Account;\nimport android.net.Uri;\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.Scope;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.json.JSONArray;\nimport org.json.JSONException;\nimport org.json.JSONObject;\nimport org.microg.gms.auth.AuthConstants;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.*;\n\n/**\n * Class that holds the basic account information of the signed in Google user.\n */\n@SafeParcelable.Class\npublic class GoogleSignInAccount extends AbstractSafeParcelable {\n    @Field(value = 1, defaultValue = \"3\")\n    final int versionCode;\n    @Field(value = 2, getterName = \"getId\")\n    @Nullable\n    private final String id;\n    @Field(value = 3, getterName = \"getIdToken\")\n    @Nullable\n    private final String idToken;\n    @Field(value = 4, getterName = \"getEmail\")\n    @Nullable\n    private final String email;\n    @Field(value = 5, getterName = \"getDisplayName\")\n    @Nullable\n    private final String displayName;\n    @Field(value = 6, getterName = \"getPhotoUrl\")\n    @Nullable\n    private final Uri photoUrl;\n    @Field(value = 7, getterName = \"getServerAuthCode\")\n    private final String serverAuthCode;\n    @Field(value = 8, getterName = \"getExpirationTimeSecs\")\n    private final long expirationTimeSecs;\n    @Field(value = 9, getterName = \"getObfuscatedIdentifier\")\n    private final String obfuscatedIdentifier;\n    @Field(value = 10, getter = \"new java.util.ArrayList<>($object.getGrantedScopes())\")\n    private final List<Scope> grantedScopes;\n    @Field(value = 11, getterName = \"getGivenName\")\n    @Nullable\n    private final String givenName;\n    @Field(value = 12, getterName = \"getFamilyName\")\n    @Nullable\n    private final String familyName;\n\n    private Set<Scope> requestedScopes;\n\n    private static final String JSON_ID = \"id\";\n    private static final String JSON_TOKEN_ID = \"tokenId\";\n    private static final String JSON_EMAIL = \"email\";\n    private static final String JSON_DISPLAY_NAME = \"displayName\";\n    private static final String JSON_GIVEN_NAME = \"givenName\";\n    private static final String JSON_FAMILY_NAME = \"familyName\";\n    private static final String JSON_PHOTO_URL = \"photoUrl\";\n    private static final String JSON_SERVER_AUTH_CODE = \"serverAuthCode\";\n    private static final String JSON_EXPIRATION_TIME = \"expirationTime\";\n    private static final String JSON_OBFUSCATED_IDENTIFIER = \"obfuscatedIdentifier\";\n    private static final String JSON_GRANTED_SCOPES = \"grantedScopes\";\n\n    @Hide\n    public GoogleSignInAccount(@Nullable String id, @Nullable String idToken, @Nullable String email, @Nullable String displayName, @Nullable Uri photoUrl, String serverAuthCode, long expirationTimeSecs, String obfuscatedIdentifier, Set<Scope> grantedScopes, @Nullable String givenName, @Nullable String familyName) {\n        this(3, id, idToken, email, displayName, photoUrl, serverAuthCode, expirationTimeSecs, obfuscatedIdentifier, new ArrayList<>(grantedScopes), givenName, familyName);\n    }\n\n    @Constructor\n    GoogleSignInAccount(@Param(1) int versionCode, @Param(2) @Nullable String id, @Param(3) @Nullable String idToken, @Param(4) @Nullable String email, @Param(5) @Nullable String displayName, @Param(6) @Nullable Uri photoUrl, @Param(7) String serverAuthCode, @Param(8) long expirationTimeSecs, @Param(9) String obfuscatedIdentifier, @Param(10) List<Scope> grantedScopes, @Param(11) @Nullable String givenName, @Param(12) @Nullable String familyName) {\n        this.versionCode = versionCode;\n        this.id = id;\n        this.idToken = idToken;\n        this.email = email;\n        this.displayName = displayName;\n        this.photoUrl = photoUrl;\n        this.serverAuthCode = serverAuthCode;\n        this.expirationTimeSecs = expirationTimeSecs;\n        this.obfuscatedIdentifier = obfuscatedIdentifier;\n        this.grantedScopes = grantedScopes;\n        this.givenName = givenName;\n        this.familyName = familyName;\n    }\n\n    @NonNull\n    @Hide\n    public static GoogleSignInAccount createDefault() {\n        return fromAccount(new Account(GoogleApiClient.DEFAULT_ACCOUNT, AuthConstants.DEFAULT_ACCOUNT_TYPE));\n    }\n\n    @NonNull\n    @Hide\n    public static GoogleSignInAccount fromAccount(@NonNull Account account) {\n        return fromAccountAndScopes(account, new HashSet<>());\n    }\n\n    @NonNull\n    @Hide\n    public static GoogleSignInAccount fromAccountAndScopes(@NonNull Account account, @NonNull Scope scope, @NonNull Scope... scopes) {\n        Set<Scope> scopeSet = new HashSet<Scope>();\n        scopeSet.add(scope);\n        Collections.addAll(scopeSet, scopes);\n        return fromAccountAndScopes(account, scopeSet);\n    }\n\n    @NonNull\n    @Hide\n    public static GoogleSignInAccount fromAccountAndScopes(@NonNull Account account, @NonNull Set<Scope> scopes) {\n        return new GoogleSignInAccount(null, null, account.name, null, null, null, 0L, account.name, scopes, null, null);\n    }\n\n    /**\n     * A convenient wrapper for {@link #getEmail()} which returns an android.accounts.Account object. See {@link #getEmail()} doc for details.\n     */\n    public @Nullable Account getAccount() {\n        if (email == null) return null;\n        return new Account(email, AuthConstants.DEFAULT_ACCOUNT_TYPE);\n    }\n\n    /**\n     * Returns the display name of the signed in user if you built your configuration starting from\n     * {@code new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)} or with {@link GoogleSignInOptions.Builder#requestProfile()} configured;\n     * {@code null} otherwise. Not guaranteed to be present for all users, even when configured.\n     */\n    public @Nullable String getDisplayName() {\n        return displayName;\n    }\n\n    /**\n     * Returns the email address of the signed in user if {@link GoogleSignInOptions.Builder#requestEmail()} was configured; {@code null} otherwise.\n     * <p>\n     * Applications should not key users by email address since a Google account's email address can change. Use {@link #getId()} as a key instead.\n     * <p>\n     * Important: Do not use this returned email address to communicate the currently signed in user to your backend server. Instead, send an ID token\n     * ({@link GoogleSignInOptions.Builder#requestIdToken(String)}), which can be securely validated on the server; or send server auth code\n     * ({@link GoogleSignInOptions.Builder#requestServerAuthCode(String)}) which can be in turn exchanged for id token.\n     *\n     * @return\n     */\n    public @Nullable String getEmail() {\n        return email;\n    }\n\n    /**\n     * Returns the family name of the signed in user if you built your configuration starting from\n     * {@code new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)} or with {@link GoogleSignInOptions.Builder#requestProfile()} configured;\n     * {@code null} otherwise. Not guaranteed to be present for all users, even when configured.\n     */\n    public @Nullable String getFamilyName() {\n        return familyName;\n    }\n\n    /**\n     * Returns the given name of the signed in user if you built your configuration starting from\n     * {@code new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)} or with {@link GoogleSignInOptions.Builder#requestProfile()} configured;\n     * {@code null} otherwise. Not guaranteed to be present for all users, even when configured.\n     */\n    public @Nullable String getGivenName() {\n        return givenName;\n    }\n\n    /**\n     * Returns all scopes that have been authorized to your application.\n     * <p>\n     * This can be a larger set than what you have requested via {@link GoogleSignInOptions}. We recommend apps requesting minimum scopes at user sign in time\n     * and later requesting additional scopes incrementally when user is using a certain feature. For those apps following this incremental auth practice,\n     * they can use the returned scope set to determine all authorized scopes (across platforms and app re-installs) to turn on bonus features accordingly.\n     * The returned set can also be larger due to other scope handling logic.\n     */\n    public @NonNull Set<Scope> getGrantedScopes() {\n        return new HashSet<>(grantedScopes);\n    }\n\n    /**\n     * Returns the unique ID for the Google account if you built your configuration starting from\n     * {@code new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)} or with {@link GoogleSignInOptions.Builder#requestId()} configured;\n     * {@code null} otherwise.\n     * <p>\n     * This is the preferred unique key to use for a user record.\n     * <p>\n     * Important: Do not use this returned Google ID to communicate the currently signed in user to your backend server. Instead, send an ID token\n     * ({@link GoogleSignInOptions.Builder#requestIdToken(String)}), which can be securely validated on the server; or send a server auth code\n     * ({@link GoogleSignInOptions.Builder#requestServerAuthCode(String)}) which can be in turn exchanged for id token.\n     */\n    public @Nullable String getId() {\n        return id;\n    }\n\n    /**\n     * Returns an ID token that you can send to your server if {@link GoogleSignInOptions.Builder#requestIdToken(String)} was configured; {@code null} otherwise.\n     * <p>\n     * ID token is a JSON Web Token signed by Google that can be used to identify a user to a backend.\n     */\n    public @Nullable String getIdToken() {\n        return idToken;\n    }\n\n    /**\n     * Returns the photo url of the signed in user if the user has a profile picture and you built your configuration either starting from\n     * {@code new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)} or with {@link GoogleSignInOptions.Builder#requestProfile()} configured;\n     * {@code null} otherwise. Not guaranteed to be present for all users, even when configured.\n     */\n    public @Nullable Uri getPhotoUrl() {\n        return photoUrl;\n    }\n\n    /**\n     * Returns a one-time server auth code to send to your web server which can be exchanged for access token and sometimes refresh token if\n     * {@link GoogleSignInOptions.Builder#requestServerAuthCode(String)} is configured; {@code null} otherwise.\n     */\n    public @Nullable String getServerAuthCode() {\n        return serverAuthCode;\n    }\n\n    @Override\n    public boolean equals(@Nullable Object obj) {\n        if (obj == null) return false;\n        if (obj == this) return true;\n        if (!(obj instanceof GoogleSignInAccount)) return false;\n        return ((GoogleSignInAccount) obj).obfuscatedIdentifier.equals(obfuscatedIdentifier) && ((GoogleSignInAccount) obj).getGrantedScopes().equals(getGrantedScopes());\n    }\n\n    @Hide\n    public long getExpirationTimeSecs() {\n        return expirationTimeSecs;\n    }\n\n    @Hide\n    public String getObfuscatedIdentifier() {\n        return obfuscatedIdentifier;\n    }\n\n    @Hide\n    public Set<Scope> getRequestedScopes() {\n        Set<Scope> requestedScopes = new HashSet<Scope>(this.grantedScopes);\n        requestedScopes.addAll(this.requestedScopes);\n        return requestedScopes;\n    }\n\n    @Hide\n    public boolean isExpired() {\n        return System.currentTimeMillis() / 1000 >= this.expirationTimeSecs - 300;\n    }\n\n    @NonNull\n    @Hide\n    public GoogleSignInAccount requestExtraScopes(@NonNull Scope... scopes) {\n        if (scopes != null) {\n            Collections.addAll(this.requestedScopes, scopes);\n        }\n        return this;\n    }\n\n    @Nullable\n    @Hide\n    public static GoogleSignInAccount fromJson(@Nullable String jsonString) throws JSONException {\n        if (jsonString == null) return null;\n        JSONObject json = new JSONObject(jsonString);\n        Set<Scope> grantedScopes = new HashSet<>();\n        JSONArray jsonGrantedScopes = json.getJSONArray(JSON_GRANTED_SCOPES);\n        for (int i = 0; i < jsonGrantedScopes.length(); i++) {\n            grantedScopes.add(new Scope(jsonGrantedScopes.getString(i)));\n        }\n        return new GoogleSignInAccount(\n                json.optString(JSON_ID),\n                json.has(JSON_TOKEN_ID) ? json.optString(JSON_TOKEN_ID) : null,\n                json.has(JSON_EMAIL) ? json.optString(JSON_EMAIL) : null,\n                json.has(JSON_DISPLAY_NAME) ? json.optString(JSON_DISPLAY_NAME) : null,\n                json.has(JSON_PHOTO_URL) ? Uri.parse(json.optString(JSON_PHOTO_URL)) : null,\n                json.has(JSON_SERVER_AUTH_CODE) ? json.optString(JSON_SERVER_AUTH_CODE) : null,\n                Long.parseLong(json.getString(JSON_EXPIRATION_TIME)),\n                json.getString(JSON_OBFUSCATED_IDENTIFIER),\n                grantedScopes,\n                json.has(JSON_GIVEN_NAME) ? json.optString(JSON_GIVEN_NAME) : null,\n                json.has(JSON_FAMILY_NAME) ? json.optString(JSON_FAMILY_NAME) : null\n        );\n    }\n\n    @Hide\n    @NonNull\n    public String toJson() {\n        JSONObject json = new JSONObject();\n        try {\n            if (id != null) json.put(JSON_ID, id);\n            if (idToken != null) json.put(JSON_TOKEN_ID, idToken);\n            if (email != null) json.put(JSON_EMAIL, email);\n            if (displayName != null) json.put(JSON_DISPLAY_NAME, displayName);\n            if (givenName != null) json.put(JSON_GIVEN_NAME, givenName);\n            if (familyName != null) json.put(JSON_FAMILY_NAME, familyName);\n            if (photoUrl != null) json.put(JSON_PHOTO_URL, photoUrl.toString());\n            if (serverAuthCode != null) json.put(JSON_SERVER_AUTH_CODE, serverAuthCode);\n            json.put(JSON_EXPIRATION_TIME, expirationTimeSecs);\n            json.put(JSON_OBFUSCATED_IDENTIFIER, obfuscatedIdentifier);\n            JSONArray jsonGrantedScopes = new JSONArray();\n            Scope[] grantedScopesArray = grantedScopes.toArray(new Scope[grantedScopes.size()]);\n            Arrays.sort(grantedScopesArray, (s1, s2) -> s1.getScopeUri().compareTo(s2.getScopeUri()));\n            for (Scope grantedScope : grantedScopesArray) {\n                jsonGrantedScopes.put(grantedScope.getScopeUri());\n            }\n            json.put(JSON_GRANTED_SCOPES, jsonGrantedScopes);\n            return json.toString();\n        } catch (JSONException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    @Override\n    public int hashCode() {\n        return (obfuscatedIdentifier.hashCode() + 527) * 31 + getGrantedScopes().hashCode();\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"GoogleSignInAccount\")\n                .field(\"id\", id)\n                .field(\"tokenId\", idToken)\n                .field(\"email\", email)\n                .field(\"displayName\", displayName)\n                .field(\"givenName\", givenName)\n                .field(\"familyName\", familyName)\n                .field(\"photoUrl\", photoUrl)\n                .field(\"serverAuthCode\", serverAuthCode)\n                .field(\"expirationTime\", expirationTimeSecs)\n                .field(\"obfuscatedIdentifier\", obfuscatedIdentifier)\n                .end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel parcel, int flags) {\n        CREATOR.writeToParcel(this, parcel, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<GoogleSignInAccount> CREATOR = findCreator(GoogleSignInAccount.class);\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/auth/api/signin/GoogleSignInOptions.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.api.signin;\n\nimport android.accounts.Account;\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.auth.api.signin.internal.GoogleSignInOptionsExtensionParcelable;\nimport com.google.android.gms.common.Scopes;\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.Scope;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.json.JSONArray;\nimport org.json.JSONException;\nimport org.json.JSONObject;\nimport org.microg.gms.auth.AuthConstants;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.*;\n\n/**\n * {@code GoogleSignInOptions} contains options used to configure the {@link Auth#GOOGLE_SIGN_IN_API}.\n */\n@SafeParcelable.Class\npublic class GoogleSignInOptions extends AbstractSafeParcelable implements Api.ApiOptions.Optional {\n    /**\n     * Default and recommended configuration for Games Sign In.\n     * <ul>\n     * <li>If your app has a server, you can build a configuration via {@code new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN)} and\n     * further configure {@link GoogleSignInOptions.Builder#requestServerAuthCode(String)}.</li>\n     * <li>If you want to customize Games sign-in options, you can build a configuration via {@code new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN)}\n     * and further configure {@link Games.GamesOptions} via {@link GoogleSignInOptions.Builder#addExtension(GoogleSignInOptionsExtension)}.</li>\n     * </ul>\n     * To maximize chance of auto-sign-in, do NOT use {@link GoogleSignInOptions.Builder#requestScopes(Scope, Scope...)} to request additional scopes and do\n     * NOT use {@link GoogleSignInOptions.Builder#requestIdToken(String)} to request user's real Google identity assertion.\n     */\n    @NonNull\n    public static final GoogleSignInOptions DEFAULT_GAMES_SIGN_IN = new Builder().requestScopes(new Scope(Scopes.GAMES_LITE)).build();\n\n    /**\n     * Default configuration for Google Sign In. You can get a stable user ID and basic profile info back via {@link GoogleSignInAccount#getId()} after you\n     * trigger sign in from either {@link GoogleSignInApi#silentSignIn} or {@link GoogleSignInApi#getSignInIntent}. If you require more information for the\n     * sign in result, please build a configuration via {@code new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)}.\n     */\n    @NonNull\n    public static final GoogleSignInOptions DEFAULT_SIGN_IN = new Builder().requestId().requestProfile().build();\n\n    @Field(value = 1, defaultValue = \"3\")\n    final int versionCode;\n    @Field(value = 2, getterName = \"getScopes\")\n    private final List<Scope> scopes;\n    @Field(value = 3, getterName = \"getAccount\")\n    private final Account account;\n    @Field(value = 4, getterName = \"isIdTokenRequested\")\n    private final boolean idTokenRequested;\n    @Field(value = 5, getterName = \"isServerAuthCodeRequested\")\n    private final boolean serverAuthCodeRequested;\n    @Field(value = 6, getterName = \"isForceCodeForRefreshToken\")\n    private final boolean forceCodeForRefreshToken;\n    @Field(value = 7, getterName = \"getServerClientId\")\n    private final String serverClientId;\n    @Field(value = 8, getterName = \"getHostedDomain\")\n    private final String hostedDomain;\n    @Field(value = 9, getterName = \"getExtensions\")\n    private final List<GoogleSignInOptionsExtensionParcelable> extensions;\n    @Field(value = 10, getterName = \"getLogSessionId\")\n    private final String logSessionId;\n\n    @Hide\n    public static final Scope SCOPE_PROFILE = new Scope(Scopes.PROFILE);\n    @Hide\n    public static final Scope SCOPE_EMAIL = new Scope(Scopes.EMAIL);\n    @Hide\n    public static final Scope SCOPE_OPENID = new Scope(Scopes.OPENID);\n    @Hide\n    public static final Scope SCOPE_GAMES_LITE = new Scope(Scopes.GAMES_LITE);\n    @Hide\n    public static final Scope SCOPE_GAMES = new Scope(Scopes.GAMES);\n\n    private GoogleSignInOptions(List<Scope> scopes, Account account, boolean idTokenRequested, boolean serverAuthCodeRequested, boolean forceCodeForRefreshToken, String serverClientId, String hostedDomain, Map<Integer, GoogleSignInOptionsExtensionParcelable> extensions, String logSessionId) {\n        this(3, scopes, account, idTokenRequested, serverAuthCodeRequested, forceCodeForRefreshToken, serverClientId, hostedDomain, new ArrayList<>(extensions.values()), logSessionId);\n    }\n\n    @Constructor\n    GoogleSignInOptions(@Param(1) int versionCode, @Param(2) List<Scope> scopes, @Param(3) Account account, @Param(4) boolean idTokenRequested, @Param(5) boolean serverAuthCodeRequested, @Param(6) boolean forceCodeForRefreshToken, @Param(7) String serverClientId, @Param(8) String hostedDomain, @Param(9) List<GoogleSignInOptionsExtensionParcelable> extensions, @Param(10) String logSessionId) {\n        this.versionCode = versionCode;\n        this.scopes = scopes;\n        this.account = account;\n        this.idTokenRequested = idTokenRequested;\n        this.serverAuthCodeRequested = serverAuthCodeRequested;\n        this.forceCodeForRefreshToken = forceCodeForRefreshToken;\n        this.serverClientId = serverClientId;\n        this.hostedDomain = hostedDomain;\n        this.extensions = extensions;\n        this.logSessionId = logSessionId;\n    }\n\n    /**\n     * Gets an array of all the requested scopes. If you use DEFAULT_SIGN_IN, this array will also include those scopes set by default in DEFAULT_SIGN_IN.\n     * <p>\n     * A usage of this method could be set the scopes for the contextual SignInButton. E.g., {@code signInButton.setScopes(googleSignInOptions.getScopeArray())}\n     */\n    @NonNull\n    public Scope[] getScopeArray() {\n        return scopes.toArray(new Scope[0]);\n    }\n\n    @Hide\n    public List<Scope> getScopes() {\n        return Collections.unmodifiableList(scopes);\n    }\n\n    @Hide\n    public Account getAccount() {\n        return account;\n    }\n\n    @Hide\n    public boolean isIdTokenRequested() {\n        return idTokenRequested;\n    }\n\n    @Hide\n    public boolean isServerAuthCodeRequested() {\n        return serverAuthCodeRequested;\n    }\n\n    @Hide\n    public boolean isForceCodeForRefreshToken() {\n        return forceCodeForRefreshToken;\n    }\n\n    @Hide\n    public String getServerClientId() {\n        return serverClientId;\n    }\n\n    @Hide\n    public String getHostedDomain() {\n        return hostedDomain;\n    }\n\n    @Hide\n    public List<GoogleSignInOptionsExtensionParcelable> getExtensions() {\n        return Collections.unmodifiableList(extensions);\n    }\n\n    @Hide\n    public String getLogSessionId() {\n        return logSessionId;\n    }\n\n    /**\n     * Builder for {@link GoogleSignInOptions}.\n     */\n    public static final class Builder {\n        private final Set<Scope> scopes;\n        private boolean idTokenRequested;\n        private boolean serverAuthCodeRequested;\n        private boolean forceCodeForRefreshToken;\n        @Nullable\n        private String serverClientId;\n        @Nullable\n        private Account account;\n        @Nullable\n        private String hostedDomain;\n        private final Map<Integer, GoogleSignInOptionsExtensionParcelable> extensionMap = new HashMap<>();\n        private String logSessionId;\n\n        public Builder() {\n            this.scopes = new HashSet<>();\n        }\n\n        public Builder(GoogleSignInOptions options) {\n            this.scopes = new HashSet<>(options.scopes);\n            this.idTokenRequested = options.idTokenRequested;\n            this.serverAuthCodeRequested = options.serverAuthCodeRequested;\n            this.forceCodeForRefreshToken = options.forceCodeForRefreshToken;\n            this.serverClientId = options.serverClientId;\n            this.account = options.account;\n            this.hostedDomain = options.hostedDomain;\n            if (options.extensions != null) {\n                for (GoogleSignInOptionsExtensionParcelable extension : options.extensions) {\n                    extensionMap.put(extension.getType(), extension);\n                }\n            }\n        }\n\n        /**\n         * Specifies additional sign-in options via the given extension.\n         *\n         * @param extension A sign-in extension used to further configure API specific sign-in options. Supported values include: {@link Games.GamesOptions}.\n         */\n        @NonNull\n        public Builder addExtension(GoogleSignInOptionsExtension extension) {\n            if (this.extensionMap.containsKey(extension.getExtensionType())) {\n                throw new IllegalStateException(\"Only one extension per type may be added\");\n            }\n            List<Scope> scopes = extension.getImpliedScopes();\n            if (scopes != null) {\n                this.scopes.addAll(scopes);\n            }\n            this.extensionMap.put(extension.getExtensionType(), new GoogleSignInOptionsExtensionParcelable(extension));\n            return this;\n        }\n\n        /**\n         * Specifies that email info is requested by your application. Note that we don't recommend keying user by email address since email address might\n         * change. Keying user by ID is the preferable approach.\n         */\n        @NonNull\n        public Builder requestEmail() {\n            this.scopes.add(new Scope(Scopes.EMAIL));\n            return this;\n        }\n\n        /**\n         * Specifies that user ID is requested by your application.\n         */\n        @NonNull\n        public Builder requestId() {\n            this.scopes.add(new Scope(Scopes.OPENID));\n            return this;\n        }\n\n        /**\n         * Specifies that an ID token for authenticated users is requested. Requesting an ID token requires that the server client ID be specified.\n         *\n         * @param serverClientId The client ID of the server that will verify the integrity of the token.\n         */\n        @NonNull\n        public Builder requestIdToken(@NonNull String serverClientId) {\n            this.idTokenRequested = true;\n            this.serverClientId = serverClientId;\n            return this;\n        }\n\n        /**\n         * Specifies that user's profile info is requested by your application.\n         */\n        @NonNull\n        public Builder requestProfile() {\n            this.scopes.add(new Scope(Scopes.PROFILE));\n            return this;\n        }\n\n        /**\n         * Specifies OAuth 2.0 scopes your application requests. See {@link Scopes} for more information.\n         *\n         * @param scope  An OAuth 2.0 scope requested by your app.\n         * @param scopes More OAuth 2.0 scopes requested by your app.\n         */\n        @NonNull\n        public Builder requestScopes(@NonNull Scope scope, @NonNull Scope... scopes) {\n            this.scopes.add(scope);\n            this.scopes.addAll(Arrays.asList(scopes));\n            return this;\n        }\n\n        /**\n         * Specifies that offline access is requested. Requesting offline access requires that the server client ID be specified.\n         * <p>\n         * You don't need to use {@link #requestIdToken(String)} when you use this option. When your server exchanges the code for tokens, an ID token will be\n         * returned together (as long as you either use {@link #requestEmail()} or {@link #requestProfile()} along with your configuration).\n         * <p>\n         * The first time you retrieve a code, a refresh_token will be granted automatically. Subsequent requests will only return codes that can be exchanged for access token.\n         *\n         * @param serverClientId The client ID of the server that will need the auth code.\n         */\n        public Builder requestServerAuthCode(String serverClientId) {\n            return requestServerAuthCode(serverClientId, false);\n        }\n\n        /**\n         * Specifies that offline access is requested. Requesting offline access requires that the server client ID be specified.\n         * <p>\n         * You don't need to use {@link #requestIdToken(String)} when you use this option. When your server exchanges the code for tokens, an ID token will be\n         * returned together (as long as you either use {@link #requestEmail()} or {@link #requestProfile()} along with this configuration).\n         *\n         * @param serverClientId           The client ID of the server that will need the auth code.\n         * @param forceCodeForRefreshToken If true, the granted code can be exchanged for an access token and a refresh token. The first time you retrieve a\n         *                                 code, a refresh_token will be granted automatically. Subsequent requests will require additional user consent. Use\n         *                                 false by default; only use true if your server has suffered some failure and lost the user's refresh token.\n         */\n        public Builder requestServerAuthCode(String serverClientId, boolean forceCodeForRefreshToken) {\n            this.serverAuthCodeRequested = true;\n            this.forceCodeForRefreshToken = forceCodeForRefreshToken;\n            this.serverClientId = serverClientId;\n            return this;\n\n        }\n\n        /**\n         * Specifies an account name on the device that should be used. If this is never called, the client will use the current default account for this application.\n         *\n         * @param accountName The account name on the device that should be used to sign in.\n         */\n        public GoogleSignInOptions.Builder setAccountName(String accountName) {\n            this.account = new Account(accountName, AuthConstants.DEFAULT_ACCOUNT_TYPE);\n            return this;\n        }\n\n        /**\n         * Specifies a hosted domain restriction. By setting this, sign in will be restricted to accounts of the user in the specified domain.\n         *\n         * @param hostedDomain domain of the user to restrict (for example, \"mycollege.edu\")\n         */\n        public GoogleSignInOptions.Builder setHostedDomain(String hostedDomain) {\n            this.hostedDomain = hostedDomain;\n            return this;\n        }\n\n        @Hide\n        public GoogleSignInOptions.Builder setLogSessionId(String logSessionId) {\n            this.logSessionId = logSessionId;\n            return this;\n        }\n\n        /**\n         * Builds the {@link GoogleSignInOptions} object.\n         *\n         * @return a {@link GoogleSignInOptions} instance.\n         */\n        @NonNull\n        public GoogleSignInOptions build() {\n            if (scopes.contains(SCOPE_GAMES)) {\n                scopes.remove(SCOPE_GAMES_LITE);\n            }\n            if (idTokenRequested && (account == null || !scopes.isEmpty())) {\n                requestId();\n            }\n            return new GoogleSignInOptions(new ArrayList<>(scopes), account, idTokenRequested, serverAuthCodeRequested, forceCodeForRefreshToken, serverClientId, hostedDomain, extensionMap, logSessionId);\n        }\n    }\n\n    private static final String JSON_SCOPES = \"scopes\";\n    private static final String JSON_ACCOUNT_NAME = \"accountName\";\n    private static final String JSON_ID_TOKEN_REQUESTED = \"idTokenRequested\";\n    private static final String JSON_FORCE_CODE_FOR_REFRESH_TOKEN = \"forceCodeForRefreshToken\";\n    private static final String JSON_SERVER_AUTH_REQUESTED = \"serverAuthRequested\";\n    private static final String JSON_SERVER_CLIENT_ID = \"serverClientId\";\n    private static final String JSON_HOSTED_DOMAIN = \"hostedDomain\";\n\n    public static GoogleSignInOptions fromJson(String jsonString) throws JSONException {\n        if (jsonString == null) return null;\n        JSONObject json = new JSONObject(jsonString);\n        List<Scope> scopes = new ArrayList<>();\n        JSONArray jsonScopes = json.getJSONArray(JSON_SCOPES);\n        for (int i = 0; i < jsonScopes.length(); i++) {\n            scopes.add(new Scope(jsonScopes.getString(i)));\n        }\n        return new GoogleSignInOptions(\n                scopes,\n                json.has(JSON_ACCOUNT_NAME) ? new Account(json.optString(JSON_ACCOUNT_NAME), AuthConstants.DEFAULT_ACCOUNT_TYPE) : null,\n                json.getBoolean(JSON_ID_TOKEN_REQUESTED),\n                json.getBoolean(JSON_SERVER_AUTH_REQUESTED),\n                json.getBoolean(JSON_FORCE_CODE_FOR_REFRESH_TOKEN),\n                json.has(JSON_SERVER_CLIENT_ID) ? json.optString(JSON_SERVER_CLIENT_ID) : null,\n                json.has(JSON_HOSTED_DOMAIN) ? json.optString(JSON_HOSTED_DOMAIN) : null,\n                new HashMap<>(),\n                null\n        );\n    }\n\n    @NonNull\n    public String toJson() {\n        JSONObject json = new JSONObject();\n        try {\n            JSONArray jsonScopes = new JSONArray();\n            for (Scope scope : scopes) {\n                jsonScopes.put(scope.getScopeUri());\n            }\n            json.put(JSON_SCOPES, jsonScopes);\n            if (account != null) json.put(JSON_ACCOUNT_NAME, account.name);\n            json.put(JSON_ID_TOKEN_REQUESTED, idTokenRequested);\n            json.put(JSON_FORCE_CODE_FOR_REFRESH_TOKEN, forceCodeForRefreshToken);\n            json.put(JSON_SERVER_AUTH_REQUESTED, serverAuthCodeRequested);\n            if (serverClientId != null) json.put(JSON_SERVER_CLIENT_ID, serverClientId);\n            if (hostedDomain != null) json.put(JSON_HOSTED_DOMAIN, hostedDomain);\n            return json.toString();\n        } catch (JSONException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    @Override\n    public int hashCode() {\n        List<String> sortedScopeStrings = new ArrayList<>();\n        for (Scope scope : scopes) {\n            sortedScopeStrings.add(scope.getScopeUri());\n        }\n        Collections.sort(sortedScopeStrings);\n        int hash = sortedScopeStrings.hashCode() + 31;\n        hash = (account == null ? 0 : account.hashCode()) + (hash * 31);\n        hash = (serverClientId == null ? 0 : serverClientId.hashCode()) + (hash * 31);\n        hash = (forceCodeForRefreshToken ? 1 : 0) + (hash * 31);\n        hash = (idTokenRequested ? 1 : 0) + (hash * 31);\n        hash = (serverAuthCodeRequested ? 1 : 0) + (hash * 31);\n        hash = (logSessionId == null ? 0 : logSessionId.hashCode()) + (hash * 31);\n        return hash;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"GoogleSignInOptions\")\n                .field(\"scopes\", scopes)\n                .field(\"account\", account)\n                .field(\"idTokenRequested\", idTokenRequested)\n                .field(\"forceCodeForRefreshToken\", forceCodeForRefreshToken)\n                .field(\"serverAuthCodeRequested\", serverAuthCodeRequested)\n                .field(\"serverClientId\", serverClientId)\n                .field(\"hostedDomain\", hostedDomain)\n                .end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel parcel, int flags) {\n        CREATOR.writeToParcel(this, parcel, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<GoogleSignInOptions> CREATOR = findCreator(GoogleSignInOptions.class);\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/auth/api/signin/GoogleSignInOptionsExtension.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.auth.api.signin;\n\nimport android.os.Bundle;\nimport com.google.android.gms.common.api.Scope;\nimport org.microg.gms.common.Hide;\n\nimport java.util.List;\n\n/**\n * An interface for API specific extension for {@link GoogleSignInOptions}.\n *\n * @see GoogleSignInOptions.Builder#addExtension(GoogleSignInOptionsExtension).\n */\npublic interface GoogleSignInOptionsExtension {\n    @Hide\n    int GAMES = 1;\n    @Hide\n    int FITNESS = 3;\n\n    @Hide\n    int getExtensionType();\n\n    @Hide\n    Bundle toBundle();\n\n    @Hide\n    List<Scope> getImpliedScopes();\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/auth/api/signin/internal/GoogleSignInOptionsExtensionParcelable.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.api.signin.internal;\n\nimport android.os.Bundle;\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.auth.api.signin.GoogleSignInOptionsExtension;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\n\n@Hide\n@SafeParcelable.Class\npublic class GoogleSignInOptionsExtensionParcelable extends AbstractSafeParcelable {\n    @Field(1)\n    final int versionCode;\n    @Field(value = 2, getterName = \"getType\")\n    private final int type;\n    @Field(value = 3, getterName = \"getBundle\")\n    private final Bundle bundle;\n\n    public GoogleSignInOptionsExtensionParcelable(@NonNull GoogleSignInOptionsExtension extension) {\n        this(1, extension.getExtensionType(), extension.toBundle());\n    }\n\n    @Constructor\n    public GoogleSignInOptionsExtensionParcelable(@Param(1) int versionCode, @Param(2) int type, @Param(3) Bundle bundle) {\n        this.versionCode = versionCode;\n        this.type = type;\n        this.bundle = bundle;\n    }\n\n    public Bundle getBundle() {\n        return bundle;\n    }\n\n    public int getType() {\n        return type;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<GoogleSignInOptionsExtensionParcelable> CREATOR = findCreator(GoogleSignInOptionsExtensionParcelable.class);\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/auth/api/signin/internal/HashAccumulator.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.api.signin.internal;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport org.microg.gms.common.Hide;\n\n/**\n * We keep this mostly for documentary purposes and drop-in compatibility. Usage is highly discouraged.\n *\n * @deprecated Directly compute hash code when needed.\n */\n@Hide\n@Deprecated\npublic class HashAccumulator {\n    private int hash = 1;\n\n    @NonNull\n    @Hide\n    @Deprecated\n    public HashAccumulator addBoolean(boolean bool) {\n        hash = (hash * 31) + (bool ? 1 : 0);\n        return this;\n    }\n\n    @NonNull\n    @Deprecated\n    public HashAccumulator addObject(@Nullable Object object) {\n        hash = (object == null ? 0 : object.hashCode()) + hash * 31;\n        return this;\n    }\n\n    @Deprecated\n    public int hash() {\n        return hash;\n    }\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/auth/api/signin/internal/Storage.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.auth.api.signin.internal;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.content.SharedPreferences;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.auth.api.signin.GoogleSignInAccount;\nimport com.google.android.gms.auth.api.signin.GoogleSignInOptions;\nimport org.microg.gms.common.Hide;\n\n@Hide\n@SuppressLint(\"StaticFieldLeak\")\npublic class Storage {\n    private static final Object LOCK = new Object();\n    private static Storage INSTANCE;\n\n    public static Storage getInstance(Context context) {\n        synchronized (LOCK) {\n            if (INSTANCE == null) {\n                INSTANCE = new Storage(context.getApplicationContext());\n            }\n        }\n        return INSTANCE;\n    }\n\n    private static final String PREF_DEFAULT_ACCOUNT = \"defaultGoogleSignInAccount\";\n    private static final String PREF_PREFIX_ACCOUNT = \"googleSignInAccount:\";\n    private static final String PREF_PREFIX_OPTIONS = \"googleSignInOptions:\";\n    private static final String PREF_REFRESH_TOKEN = \"refreshToken\";\n    private final SharedPreferences sharedPreferences;\n\n    private Storage(Context context) {\n        this.sharedPreferences = context.getSharedPreferences(\"com.google.android.gms.signin\", Context.MODE_PRIVATE);\n    }\n\n    @Nullable\n    public GoogleSignInAccount getSavedDefaultGoogleSignInAccount() {\n        synchronized (sharedPreferences) {\n            String defaultGoogleSignInAccountName = sharedPreferences.getString(PREF_DEFAULT_ACCOUNT, null);\n            if (defaultGoogleSignInAccountName == null) return null;\n            String googleSignInAccountJson = sharedPreferences.getString(PREF_PREFIX_ACCOUNT + defaultGoogleSignInAccountName, null);\n            if (googleSignInAccountJson == null) return null;\n            try {\n                return GoogleSignInAccount.fromJson(googleSignInAccountJson);\n            } catch (Exception e) {\n                return null;\n            }\n        }\n    }\n\n    @Nullable\n    public GoogleSignInOptions getSavedDefaultGoogleSignInOptions() {\n        synchronized (sharedPreferences) {\n            String defaultGoogleSignInAccountName = sharedPreferences.getString(PREF_DEFAULT_ACCOUNT, null);\n            if (defaultGoogleSignInAccountName == null) return null;\n            String googleSignInOptionsJson = sharedPreferences.getString(PREF_PREFIX_OPTIONS + defaultGoogleSignInAccountName, null);\n            if (googleSignInOptionsJson == null) return null;\n            try {\n                return GoogleSignInOptions.fromJson(googleSignInOptionsJson);\n            } catch (Exception e) {\n                return null;\n            }\n        }\n    }\n\n    @Nullable\n    public String getSavedRefreshToken() {\n        synchronized (sharedPreferences) {\n            return sharedPreferences.getString(PREF_REFRESH_TOKEN, null);\n        }\n    }\n\n    public void saveDefaultGoogleSignInAccount(@NonNull GoogleSignInAccount googleSignInAccount, @NonNull GoogleSignInOptions googleSignInOptions) {\n        synchronized (sharedPreferences) {\n            sharedPreferences.edit()\n                    .putString(PREF_DEFAULT_ACCOUNT, googleSignInAccount.getObfuscatedIdentifier())\n                    .putString(PREF_PREFIX_ACCOUNT + googleSignInAccount.getObfuscatedIdentifier(), googleSignInAccount.toJson())\n                    .putString(PREF_PREFIX_OPTIONS + googleSignInAccount.getObfuscatedIdentifier(), googleSignInOptions.toJson())\n                    .apply();\n        }\n    }\n\n    public void unsetDefaultGoogleSignInAccount() {\n        synchronized (sharedPreferences) {\n            String defaultGoogleSignInAccountName = sharedPreferences.getString(PREF_DEFAULT_ACCOUNT, null);\n            if (defaultGoogleSignInAccountName == null) return;\n            sharedPreferences.edit()\n                    .remove(PREF_DEFAULT_ACCOUNT)\n                    .remove(PREF_PREFIX_ACCOUNT + defaultGoogleSignInAccountName)\n                    .remove(PREF_PREFIX_OPTIONS + defaultGoogleSignInAccountName)\n                    .apply();\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/GoogleApiAvailability.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.common;\n\nimport android.app.Activity;\nimport android.app.Dialog;\nimport android.app.PendingIntent;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.os.Bundle;\nimport androidx.fragment.app.FragmentActivity;\nimport android.util.Log;\n\nimport com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;\nimport com.google.android.gms.tasks.Task;\nimport com.google.android.gms.tasks.Tasks;\n\nimport org.microg.gms.common.Constants;\nimport org.microg.gms.common.PublicApi;\n\nimport static com.google.android.gms.common.ConnectionResult.INTERNAL_ERROR;\nimport static com.google.android.gms.common.ConnectionResult.INVALID_ACCOUNT;\nimport static com.google.android.gms.common.ConnectionResult.NETWORK_ERROR;\nimport static com.google.android.gms.common.ConnectionResult.RESOLUTION_REQUIRED;\nimport static com.google.android.gms.common.ConnectionResult.SERVICE_DISABLED;\nimport static com.google.android.gms.common.ConnectionResult.SERVICE_INVALID;\nimport static com.google.android.gms.common.ConnectionResult.SERVICE_MISSING;\nimport static com.google.android.gms.common.ConnectionResult.SERVICE_VERSION_UPDATE_REQUIRED;\nimport static com.google.android.gms.common.ConnectionResult.SIGN_IN_REQUIRED;\nimport static com.google.android.gms.common.ConnectionResult.SUCCESS;\n\n@PublicApi\npublic class GoogleApiAvailability {\n    private static final String TAG = \"GmsApiAvailability\";\n\n    /**\n     * Package name for Google Play services.\n     */\n    public static final String GOOGLE_PLAY_SERVICES_PACKAGE = Constants.GMS_PACKAGE_NAME;\n\n    /**\n     * Google Play services client library version (declared in library's AndroidManifest.xml android:versionCode).\n     */\n    public static final int GOOGLE_PLAY_SERVICES_VERSION_CODE = Constants.GMS_VERSION_CODE;\n\n    private static GoogleApiAvailability instance;\n\n    private GoogleApiAvailability() {\n    }\n\n    /**\n     * Returns the singleton instance of GoogleApiAvailability.\n     */\n    public static GoogleApiAvailability getInstance() {\n        if (instance == null) {\n            synchronized (GoogleApiAvailability.class) {\n                if (instance == null) {\n                    instance = new GoogleApiAvailability();\n                }\n            }\n        }\n        return instance;\n    }\n\n\n    /**\n     * Returns a dialog to address the provided errorCode. The returned dialog displays a localized\n     * message about the error and upon user confirmation (by tapping on dialog) will direct them\n     * to the Play Store if Google Play services is out of date or missing, or to system settings\n     * if Google Play services is disabled on the device.\n     *\n     * @param activity    parent activity for creating the dialog, also used for identifying language to display dialog in.\n     * @param errorCode   error code returned by {@link #isGooglePlayServicesAvailable(Context)} call.\n     *                    If errorCode is {@link ConnectionResult#SUCCESS} then null is returned.\n     * @param requestCode The requestCode given when calling startActivityForResult.\n     */\n    public Dialog getErrorDialog(Activity activity, int errorCode, int requestCode) {\n        return getErrorDialog(activity, errorCode, requestCode, null);\n    }\n\n    /**\n     * Returns a dialog to address the provided errorCode. The returned dialog displays a localized\n     * message about the error and upon user confirmation (by tapping on dialog) will direct them\n     * to the Play Store if Google Play services is out of date or missing, or to system settings\n     * if Google Play services is disabled on the device.\n     *\n     * @param activity       parent activity for creating the dialog, also used for identifying language to display dialog in.\n     * @param errorCode      error code returned by {@link #isGooglePlayServicesAvailable(Context)} call.\n     *                       If errorCode is {@link ConnectionResult#SUCCESS} then null is returned.\n     * @param requestCode    The requestCode given when calling startActivityForResult.\n     * @param cancelListener The {@link DialogInterface.OnCancelListener} to invoke if the dialog is canceled.\n     */\n    public Dialog getErrorDialog(Activity activity, int errorCode, int requestCode, DialogInterface.OnCancelListener cancelListener) {\n        // TODO\n        return null;\n    }\n\n    /**\n     * Returns a PendingIntent to address the provided connection failure.\n     * <p/>\n     * If {@link ConnectionResult#hasResolution()} is true, then {@link ConnectionResult#getResolution()}\n     * will be returned. Otherwise, the returned PendingIntent will direct the user to either the\n     * Play Store if Google Play services is out of date or missing, or system settings if Google\n     * Play services is disabled on the device.\n     *\n     * @param context parent context for creating the PendingIntent.\n     * @param result  the connection failure. If successful or the error is not resolvable by the user, null is returned.\n     */\n    public PendingIntent getErrorResolutionPendingIntent(Context context, ConnectionResult result) {\n        if (result.hasResolution()) {\n            return result.getResolution();\n        }\n        return getErrorResolutionPendingIntent(context, result.getErrorCode(), 0);\n    }\n\n    /**\n     * Returns a PendingIntent to address the provided errorCode. It will direct the user to either\n     * the Play Store if Google Play services is out of date or missing, or system settings if\n     * Google Play services is disabled on the device.\n     *\n     * @param context     parent context for creating the PendingIntent.\n     * @param errorCode   error code returned by {@link #isGooglePlayServicesAvailable(Context)} call.\n     *                    If errorCode is {@link ConnectionResult#SUCCESS} then null is returned.\n     * @param requestCode The requestCode given when calling startActivityForResult.\n     */\n    public PendingIntent getErrorResolutionPendingIntent(Context context, int errorCode, int requestCode) {\n        // TODO\n        return null;\n    }\n\n    /**\n     * Returns a human-readable string of the error code returned from {@link #isGooglePlayServicesAvailable(Context)}.\n     */\n    public final String getErrorString(int errorCode) {\n        return ConnectionResult.getStatusString(errorCode);\n    }\n\n    /**\n     * Verifies that Google Play services is installed and enabled on this device, and that the\n     * version installed on this device is no older than the one required by this client.\n     *\n     * @return status code indicating whether there was an error. Can be one of following in\n     * {@link ConnectionResult}: SUCCESS, SERVICE_MISSING, SERVICE_UPDATING,\n     * SERVICE_VERSION_UPDATE_REQUIRED, SERVICE_DISABLED, SERVICE_INVALID\n     */\n    public int isGooglePlayServicesAvailable(Context context) {\n        Log.d(TAG, \"As we can't know right now if the later desired feature is available, \" +\n                \"we just pretend it to be.\");\n        return SUCCESS;\n    }\n\n    /**\n     * Verifies that Google Play services is installed and enabled on this device, and that the version installed on\n     * this device is no older than the one required by this client or the version is not older than the one specified\n     * in <code>minApkVersion</code>.\n     *\n     * @return status code indicating whether there was an error. Can be one of following in\n     * {@link ConnectionResult}: SUCCESS, SERVICE_MISSING, SERVICE_UPDATING,\n     * SERVICE_VERSION_UPDATE_REQUIRED, SERVICE_DISABLED, SERVICE_INVALID\n     */\n    public int isGooglePlayServicesAvailable(Context context, int minApkVersion) {\n        return isGooglePlayServicesAvailable(context);\n    }\n\n    /**\n     * Determines whether an error can be resolved via user action. If true, proceed by calling\n     * {@link #getErrorDialog(Activity, int, int)} and showing the dialog.\n     *\n     * @param errorCode error code returned by {@link #isGooglePlayServicesAvailable(Context)}, or\n     *                  returned to your application via {@link OnConnectionFailedListener#onConnectionFailed(ConnectionResult)}\n     * @return true if the error is resolvable with {@link #getErrorDialog(Activity, int, int)}\n     */\n    public final boolean isUserResolvableError(int errorCode) {\n        switch (errorCode) {\n            case SERVICE_MISSING:\n            case SERVICE_VERSION_UPDATE_REQUIRED:\n            case SERVICE_DISABLED:\n            case SERVICE_INVALID:\n                return true;\n            case SIGN_IN_REQUIRED:\n            case INVALID_ACCOUNT:\n            case RESOLUTION_REQUIRED:\n            case NETWORK_ERROR:\n            case INTERNAL_ERROR:\n            default:\n                return false;\n        }\n    }\n\n    /**\n     * Attempts to make Google Play services available on this device. If Play Services is already\n     * available, the returned {@link Task} may complete immediately.\n     * <p/>\n     * If it is necessary to display UI in order to complete this request (e.g. sending the user\n     * to the Google Play store) the passed {@link Activity} will be used to display this UI.\n     * <p/>\n     * It is recommended to call this method from {@link Activity#onCreate(Bundle)}.\n     * If the passed {@link Activity} completes before the returned {@link Task} completes, the\n     * Task will fail with a {@link java.util.concurrent.CancellationException}.\n     * <p/>\n     * This method must be called from the main thread.\n     *\n     * @return A {@link Task}. If this Task completes without throwing an exception, Play Services\n     * is available on this device.\n     */\n    public Task<Void> makeGooglePlayServicesAvailable(Activity activity) {\n        int status = isGooglePlayServicesAvailable(activity);\n        if (status == SUCCESS) {\n            return Tasks.forResult(null);\n        }\n        // TODO\n        return Tasks.forResult(null);\n    }\n\n    /**\n     * Displays a DialogFragment for an error code returned by {@link #isGooglePlayServicesAvailable(Context)}.\n     *\n     * @param activity    parent activity for creating the dialog, also used for identifying language to display dialog in.\n     * @param errorCode   error code returned by {@link #isGooglePlayServicesAvailable(Context)} call.\n     *                    If errorCode is {@link ConnectionResult#SUCCESS} then null is returned.\n     * @param requestCode The requestCode given when calling startActivityForResult.\n     * @return true if the dialog is shown, false otherwise\n     * @throws RuntimeException if API level is below 11 and activity is not a {@link FragmentActivity}.\n     * @see ErrorDialogFragment\n     * @see SupportErrorDialogFragmet\n     */\n    public boolean showErrorDialogFragment(Activity activity, int errorCode, int requestCode) {\n        return showErrorDialogFragment(activity, errorCode, requestCode, null);\n    }\n\n    /**\n     * Displays a DialogFragment for an error code returned by {@link #isGooglePlayServicesAvailable(Context)}.\n     *\n     * @param activity       parent activity for creating the dialog, also used for identifying language to display dialog in.\n     * @param errorCode      error code returned by {@link #isGooglePlayServicesAvailable(Context)} call.\n     *                       If errorCode is {@link ConnectionResult#SUCCESS} then null is returned.\n     * @param requestCode    The requestCode given when calling startActivityForResult.\n     * @param cancelListener The {@link DialogInterface.OnCancelListener} to invoke if the dialog is canceled.\n     * @return true if the dialog is shown, false otherwise\n     * @throws RuntimeException if API level is below 11 and activity is not a {@link FragmentActivity}.\n     * @see ErrorDialogFragment\n     * @see SupportErrorDialogFragmet\n     */\n    public boolean showErrorDialogFragment(Activity activity, int errorCode, int requestCode, DialogInterface.OnCancelListener cancelListener) {\n        Dialog dialog = getErrorDialog(activity, errorCode, requestCode, cancelListener);\n        if (dialog == null) {\n            return false;\n        } else {\n            // TODO\n            return false;\n        }\n    }\n\n    /**\n     * Displays a notification for an error code returned from\n     * {@link #isGooglePlayServicesAvailable(Context)}, if it is resolvable by the user.\n     * <p/>\n     * This method is similar to {@link #getErrorDialog(int, android.app.Activity, int)}, but is\n     * provided for background tasks that cannot or should not display dialogs.\n     *\n     * @param errorCode error code returned by {@link #isGooglePlayServicesAvailable(Context)} call.\n     *                  If errorCode is {@link ConnectionResult#SUCCESS} then null is returned.\n     * @param context   used for identifying language to display dialog in as well as accessing the\n     *                  {@link android.app.NotificationManager}.\n     */\n    public void showErrorNotification(Context context, int errorCode) {\n        if (errorCode == RESOLUTION_REQUIRED) {\n            Log.e(TAG, \"showErrorNotification(context, errorCode) is called for RESOLUTION_REQUIRED when showErrorNotification(context, result) should be called\");\n        }\n\n        if (isUserResolvableError(errorCode)) {\n            GooglePlayServicesUtil.showErrorNotification(errorCode, context);\n        }\n    }\n\n    /**\n     * Displays a notification for a connection failure, if it is resolvable by the user.\n     *\n     * @param context The calling context used to display the notification.\n     * @param result  The connection failure. If successful or the error is not resolvable by the\n     *                user, no notification is shown.\n     */\n    public void showErrorNotification(Context context, ConnectionResult result) {\n        PendingIntent pendingIntent = getErrorResolutionPendingIntent(context, result);\n        if (pendingIntent != null) {\n            // TODO\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/GooglePlayServicesClient.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.common;\n\nimport android.os.Bundle;\n\n@Deprecated\npublic interface GooglePlayServicesClient {\n    void connect();\n\n    void disconnect();\n\n    boolean isConnected();\n\n    boolean isConnecting();\n\n    void registerConnectionCallbacks(ConnectionCallbacks listener);\n\n    boolean isConnectionCallbacksRegistered(ConnectionCallbacks listener);\n\n    void unregisterConnectionCallbacks(ConnectionCallbacks listener);\n\n    void registerConnectionFailedListener(OnConnectionFailedListener listener);\n\n    boolean isConnectionFailedListenerRegistered(OnConnectionFailedListener listener);\n\n    void unregisterConnectionFailedListener(OnConnectionFailedListener listener);\n\n    @Deprecated\n    interface OnConnectionFailedListener {\n\n        void onConnectionFailed(ConnectionResult result);\n    }\n\n    @Deprecated\n    interface ConnectionCallbacks {\n\n        void onConnected(Bundle connectionHint);\n\n        void onDisconnected();\n    }\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/GooglePlayServicesUtil.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.common;\n\nimport android.app.Activity;\nimport android.app.Dialog;\nimport android.app.Fragment;\nimport android.app.PendingIntent;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.content.pm.PackageManager;\nimport android.content.res.Resources;\nimport android.util.Log;\n\nimport org.microg.gms.common.Constants;\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Utility class for verifying that the Google Play services APK is available and up-to-date on\n * this device. The same checks are performed if one uses {@link AdvertisingIdClient} or\n * {@link GoogleAuthUtil} to connect to the service.\n * <p/>\n * TODO: methods :)\n */\n@PublicApi\npublic class GooglePlayServicesUtil {\n    private static final String TAG = \"GooglePlayServicesUtil\";\n\n    public static final String GMS_ERROR_DIALOG = \"GooglePlayServicesErrorDialog\";\n\n    /**\n     * Package name for Google Play services.\n     */\n    @Deprecated\n    public static final String GOOGLE_PLAY_SERVICES_PACKAGE = Constants.GMS_PACKAGE_NAME;\n\n    /**\n     * Google Play services client library version (declared in library's AndroidManifest.xml android:versionCode).\n     */\n    @Deprecated\n    public static final int GOOGLE_PLAY_SERVICES_VERSION_CODE = Constants.GMS_VERSION_CODE;\n\n    /**\n     * Package name for Google Play Store.\n     */\n    public static final String GOOGLE_PLAY_STORE_PACKAGE = \"com.android.vending\";\n\n    /**\n     * Returns a dialog to address the provided errorCode. The returned dialog displays a localized\n     * message about the error and upon user confirmation (by tapping on dialog) will direct them\n     * to the Play Store if Google Play services is out of date or missing, or to system settings\n     * if Google Play services is disabled on the device.\n     *\n     * @param errorCode   error code returned by {@link #isGooglePlayServicesAvailable(Context)} call.\n     *                    If errorCode is {@link ConnectionResult#SUCCESS} then null is returned.\n     * @param activity    parent activity for creating the dialog, also used for identifying\n     *                    language to display dialog in.\n     * @param requestCode The requestCode given when calling startActivityForResult.\n     */\n    @Deprecated\n    public static Dialog getErrorDialog(int errorCode, Activity activity, int requestCode) {\n        return getErrorDialog(errorCode, activity, requestCode, null);\n    }\n\n    /**\n     * Returns a dialog to address the provided errorCode. The returned dialog displays a localized\n     * message about the error and upon user confirmation (by tapping on dialog) will direct them\n     * to the Play Store if Google Play services is out of date or missing, or to system settings\n     * if Google Play services is disabled on the device.\n     *\n     * @param errorCode      error code returned by {@link #isGooglePlayServicesAvailable(Context)} call.\n     *                       If errorCode is {@link ConnectionResult#SUCCESS} then null is returned.\n     * @param activity       parent activity for creating the dialog, also used for identifying\n     *                       language to display dialog in.\n     * @param requestCode    The requestCode given when calling startActivityForResult.\n     * @param cancelListener The {@link DialogInterface.OnCancelListener} to invoke if the dialog\n     *                       is canceled.\n     */\n    @Deprecated\n    public static Dialog getErrorDialog(int errorCode, Activity activity, int requestCode, DialogInterface.OnCancelListener cancelListener) {\n        return GoogleApiAvailability.getInstance().getErrorDialog(activity, errorCode, requestCode, cancelListener);\n    }\n\n    /**\n     * Returns a PendingIntent to address the provided errorCode. It will direct them to one of the\n     * following places to either the Play Store if Google Play services is out of date or missing,\n     * or system settings if Google Play services is disabled on the device.\n     *\n     * @param errorCode   error code returned by {@link #isGooglePlayServicesAvailable(Context)} call.\n     *                    If errorCode is {@link ConnectionResult#SUCCESS} then null is returned.\n     * @param activity    parent context for creating the PendingIntent.\n     * @param requestCode The requestCode given when calling startActivityForResult.\n     */\n    @Deprecated\n    public static PendingIntent getErrorPendingIntent(int errorCode, Activity activity,\n                                                      int requestCode) {\n        return null; // TODO\n    }\n\n    /**\n     * Returns a human-readable string of the error code returned from {@link #isGooglePlayServicesAvailable(Context)}.\n     */\n    @Deprecated\n    public static String getErrorString(int errorCode) {\n        return null; // TODO\n    }\n\n    /**\n     * Returns the open source software license information for the Google Play services\n     * application, or null if Google Play services is not available on this device.\n     */\n    @Deprecated\n    public static String getOpenSourceSoftwareLicenseInfo(Context context) {\n        return null; // TODO\n    }\n\n    /**\n     * This gets the Context object of the Buddy APK. This loads the Buddy APK code from the Buddy\n     * APK into memory. This returned context can be used to create classes and obtain resources\n     * defined in the Buddy APK.\n     *\n     * @return The Context object of the Buddy APK or null if the Buddy APK is not installed on the device.\n     */\n    public static Context getRemoteContext(Context context) {\n        try {\n            return context.createPackageContext(Constants.GMS_PACKAGE_NAME, Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);\n        } catch (PackageManager.NameNotFoundException unused) {\n            return null;\n        }\n    }\n\n    /**\n     * This gets the Resources object of the Buddy APK.\n     *\n     * @return The Resources object of the Buddy APK or null if the Buddy APK is not installed on the device.\n     */\n    public static Resources getRemoteResources(Context context) {\n        try {\n            return context.getPackageManager().getResourcesForApplication(Constants.GMS_PACKAGE_NAME);\n        } catch (PackageManager.NameNotFoundException unused) {\n            return null;\n        }\n    }\n\n    /**\n     * Verifies that Google Play services is installed and enabled on this device, and that the\n     * version installed on this device is no older than the one required by this client.\n     *\n     * @return status code indicating whether there was an error. Can be one of following in\n     * {@link ConnectionResult}: SUCCESS, SERVICE_MISSING, SERVICE_VERSION_UPDATE_REQUIRED,\n     * SERVICE_DISABLED, SERVICE_INVALID\n     */\n    @Deprecated\n    public static int isGooglePlayServicesAvailable(Context context) {\n        Log.d(TAG, \"As we can't know right now if the later desired feature is available, \" +\n                \"we just pretend it to be.\");\n        return ConnectionResult.SUCCESS;\n    }\n\n    @Deprecated\n    public static boolean isGoogleSignedUid(PackageManager packageManager, int uid) {\n        return false; // TODO\n    }\n\n    /**\n     * Determines whether an error is user-recoverable. If true, proceed by calling\n     * {@link #getErrorDialog(int, Activity, int)} and showing the dialog.\n     *\n     * @param errorCode error code returned by {@link #isGooglePlayServicesAvailable(Context)}, or\n     *                  returned to your application via {@link com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener#onConnectionFailed(ConnectionResult)}\n     * @return true if the error is recoverable with {@link #getErrorDialog(int, Activity, int)}\n     */\n    @Deprecated\n    public static boolean isUserRecoverableError(int errorCode) {\n        return false; // TODO\n    }\n\n    /**\n     * Display a DialogFragment for an error code returned by {@link #isGooglePlayServicesAvailable(Context)}.\n     *\n     * @param errorCode   error code returned by {@link #isGooglePlayServicesAvailable(Context)} call.\n     *                    If errorCode is {@link ConnectionResult#SUCCESS} then null is returned.\n     * @param activity    parent activity for creating the dialog, also used for identifying\n     *                    language to display dialog in.\n     * @param requestCode The requestCode given when calling startActivityForResult.\n     * @return true if the dialog is shown, false otherwise\n     * @throws RuntimeException if API level is below 11 and activity is not a {@link android.support.v4.app.FragmentActivity}.\n     */\n    @Deprecated\n    public static boolean showErrorDialogFragment(int errorCode, Activity activity, int requestCode) {\n        return showErrorDialogFragment(errorCode, activity, requestCode, null);\n    }\n\n    @Deprecated\n    public static boolean showErrorDialogFragment(int errorCode, Activity activity, Fragment fragment, int requestCode, DialogInterface.OnCancelListener cancelListener) {\n        return false; // TODO\n    }\n\n    /**\n     * @param errorCode      error code returned by {@link #isGooglePlayServicesAvailable(Context)} call.\n     *                       If errorCode is {@link ConnectionResult#SUCCESS} then null is returned.\n     * @param activity       parent activity for creating the dialog, also used for identifying\n     *                       language to display dialog in.\n     * @param requestCode    The requestCode given when calling startActivityForResult.\n     * @param cancelListener The {@link DialogInterface.OnCancelListener} to invoke if the dialog\n     *                       is canceled.\n     * @return true if the dialog is shown, false otherwise.\n     * @throws RuntimeException if API level is below 11 and activity is not a {@link android.support.v4.app.FragmentActivity}.\n     */\n    @Deprecated\n    public static boolean showErrorDialogFragment(int errorCode, Activity activity, int requestCode, DialogInterface.OnCancelListener cancelListener) {\n        return showErrorDialogFragment(errorCode, activity, null, requestCode, cancelListener);\n    }\n\n    /**\n     * Displays a notification relevant to the provided error code. This method is similar to\n     * {@link #getErrorDialog(int, android.app.Activity, int)}, but is provided for background\n     * tasks that cannot or shouldn't display dialogs.\n     *\n     * @param errorCode error code returned by {@link #isGooglePlayServicesAvailable(Context)} call.\n     *                  If errorCode is {@link ConnectionResult#SUCCESS} then null is returned.\n     * @param context   used for identifying language to display dialog in as well as accessing the\n     *                  {@link android.app.NotificationManager}.\n     */\n    @Deprecated\n    public static void showErrorNotification(int errorCode, Context context) {\n        // TODO\n    }\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/api/AccountInfo.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.common.api;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n@Deprecated\npublic class AccountInfo extends AutoSafeParcelable {\n    public static final Creator<AccountInfo> CREATOR = new AutoCreator<AccountInfo>(AccountInfo.class);\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/api/Api.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2013 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.common.api;\n\nimport android.accounts.Account;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.IBinder;\nimport android.os.Looper;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.auth.api.signin.GoogleSignInAccount;\n\nimport com.google.android.gms.auth.api.signin.GoogleSignInOptionsExtension;\nimport com.google.android.gms.common.Feature;\nimport com.google.android.gms.common.api.internal.ConnectionCallbacks;\nimport com.google.android.gms.common.api.internal.OnConnectionFailedListener;\nimport com.google.android.gms.common.internal.BaseGmsClient;\nimport com.google.android.gms.common.internal.ClientSettings;\nimport com.google.android.gms.common.internal.IAccountAccessor;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.common.api.ApiClientBuilder;\n\nimport java.io.FileDescriptor;\nimport java.io.PrintWriter;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * Describes a section of the Google Play Services API that should be made available. Instances of\n * this should be passed into {@link GoogleApiClient.Builder#addApi(Api)} to enable the appropriate\n * parts of Google Play Services.\n * <p/>\n * Google APIs are partitioned into sections which allow your application to configure only the\n * services it requires. Each Google API provides an API object which can be passed to\n * {@link GoogleApiClient.Builder#addApi(Api)} in order to configure and enable that functionality\n * in your {@link GoogleApiClient} instance.\n * <p/>\n * See {@link GoogleApiClient.Builder} for usage examples.\n */\npublic final class Api<O extends Api.ApiOptions> {\n    @NonNull\n    private final String name;\n    @NonNull\n    private final AbstractClientBuilder<? extends Client, O> clientBuilder;\n    @NonNull\n    private final ClientKey<? extends Client> clientKey;\n\n    @Hide\n    @Deprecated\n    public <C extends Client> Api(ApiClientBuilder<O> builder) {\n        this(\"Deprecated \"+builder.getClass().getName(), new AbstractClientBuilder<C, O>() {\n            @NonNull\n            @Override\n            public C buildClient(@NonNull Context context, @NonNull Looper looper, @NonNull ClientSettings clientSettings, @NonNull O options, @NonNull ConnectionCallbacks connectionCallbacks, @NonNull OnConnectionFailedListener onConnectionFailedListener) {\n                return (C) builder.build(options, context, looper, clientSettings, connectionCallbacks, onConnectionFailedListener);\n            }\n        }, new ClientKey<>());\n    }\n\n    public <C extends Client> Api(String name, AbstractClientBuilder<C, O> clientBuilder, ClientKey<C> clientKey) {\n        this.name = name;\n        this.clientBuilder = clientBuilder;\n        this.clientKey = clientKey;\n    }\n\n    @Hide\n    @Deprecated\n    public ApiClientBuilder<O> getBuilder() {\n        return (options, context, looper, clientSettings, callbacks, connectionFailedListener) -> clientBuilder.buildClient(context, looper, clientSettings, options, callbacks, connectionFailedListener);\n    }\n\n    @Hide\n    public static abstract class AbstractClientBuilder<T extends Client, O> extends BaseClientBuilder<T, O> {\n        @NonNull\n        @Deprecated\n        public T buildClient(@NonNull Context context, @NonNull Looper looper, @NonNull ClientSettings clientSettings, @NonNull O options, @NonNull GoogleApiClient.ConnectionCallbacks connectionCallbacks, @NonNull GoogleApiClient.OnConnectionFailedListener onConnectionFailedListener) {\n            return buildClient(context, looper, clientSettings, options, (ConnectionCallbacks) connectionCallbacks, (OnConnectionFailedListener) onConnectionFailedListener);\n        }\n\n        @NonNull\n        public T buildClient(@NonNull Context context, @NonNull Looper looper, @NonNull ClientSettings clientSettings, @NonNull O options, @NonNull ConnectionCallbacks connectionCallbacks, @NonNull OnConnectionFailedListener onConnectionFailedListener) {\n            throw new UnsupportedOperationException();\n        }\n    }\n\n    @Hide\n    public interface AnyClient {\n    }\n\n    @Hide\n    public static class AnyClientKey<C extends AnyClient> {\n    }\n\n    /**\n     * Base interface for API options. These are used to configure specific parameters for\n     * individual API surfaces. The default implementation has no parameters.\n     */\n    public interface ApiOptions {\n        /**\n         * Base interface for {@link ApiOptions} in {@link Api}s that have options.\n         */\n        interface HasOptions extends ApiOptions {\n        }\n\n        /**\n         * Base interface for {@link ApiOptions} that are not required, don't exist.\n         */\n        interface NotRequiredOptions extends ApiOptions {\n        }\n\n        /**\n         * {@link ApiOptions} implementation for {@link Api}s that do not take any options.\n         */\n        final class NoOptions implements NotRequiredOptions {\n        }\n\n        /**\n         * Base interface for {@link ApiOptions} that are optional.\n         */\n        interface Optional extends HasOptions, NotRequiredOptions {\n        }\n\n        /**\n         * An interface for {@link ApiOptions} that include an account.\n         */\n        interface HasAccountOptions extends HasOptions, NotRequiredOptions {\n            @NonNull\n            Account getAccount();\n        }\n\n        /**\n         * An interface for {@link ApiOptions} that includes a {@link GoogleSignInAccount}\n         */\n        interface HasGoogleSignInAccountOptions extends HasOptions {\n            GoogleSignInAccount getGoogleSignInAccount();\n        }\n\n        @NonNull\n        NoOptions NO_OPTIONS = new NoOptions();\n    }\n\n    @Hide\n    public static abstract class BaseClientBuilder<T extends AnyClient, O> {\n        public static final int API_PRIORITY_GAMES = 1;\n        public static final int API_PRIORITY_PLUS = 2;\n        public static final int API_PRIORITY_OTHER = Integer.MAX_VALUE;\n\n        @NonNull\n        public List<Scope> getImpliedScopes(@Nullable O options) {\n            return Collections.emptyList();\n        }\n\n        public int getPriority() {\n            return API_PRIORITY_OTHER;\n        }\n    }\n\n    @Hide\n    public interface Client extends AnyClient {\n        @Deprecated\n        void connect();\n\n        void connect(@NonNull BaseGmsClient.ConnectionProgressReportCallbacks connectionProgressReportCallbacks);\n\n        void disconnect();\n\n        void disconnect(@NonNull String reason);\n\n        void dump(@NonNull String prefix, @Nullable FileDescriptor fd, @NonNull PrintWriter writer, @Nullable String[] args);\n\n        @NonNull\n        Feature[] getAvailableFeatures();\n\n        @NonNull\n        String getEndpointPackageName();\n\n        @Nullable\n        String getLastDisconnectMessage();\n\n        int getMinApkVersion();\n\n        void getRemoteService(@Nullable IAccountAccessor iAccountAccessor, @Nullable Set<Scope> scopes);\n\n        @NonNull\n        Feature[] getRequiredFeatures();\n\n        @NonNull\n        Set<Scope> getScopesForConnectionlessNonSignIn();\n\n        @Nullable\n        IBinder getServiceBrokerBinder();\n\n        @NonNull\n        Intent getSignInIntent();\n\n        boolean isConnected();\n\n        boolean isConnecting();\n\n        void onUserSignOut(@NonNull BaseGmsClient.SignOutCallbacks signOutCallbacks);\n\n        boolean providesSignIn();\n\n        boolean requiresAccount();\n\n        boolean requiresGooglePlayServices();\n\n        boolean requiresSignIn();\n    }\n\n    @Hide\n    public static final class ClientKey<C extends Client> extends AnyClientKey<C> {\n    }\n\n    @Hide\n    @NonNull\n    @Deprecated\n    public BaseClientBuilder<? extends Client, O> getBaseClientBuilder() {\n        return clientBuilder;\n    }\n\n    @Hide\n    @NonNull\n    public AbstractClientBuilder<? extends Client, O> getClientBuilder() {\n        return clientBuilder;\n    }\n\n    @Hide\n    @NonNull\n    public ClientKey<? extends Client> getClientKey() {\n        return clientKey;\n    }\n\n    @Hide\n    @NonNull\n    public String getName() {\n        return name;\n    }\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/api/GoogleApi.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.common.api;\n\nimport android.app.Activity;\nimport android.content.Context;\n\nimport android.os.Looper;\nimport androidx.annotation.MainThread;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.content.ContextCompat;\nimport com.google.android.gms.common.api.internal.ApiExceptionMapper;\nimport com.google.android.gms.common.api.internal.ApiKey;\nimport com.google.android.gms.common.api.internal.StatusExceptionMapper;\nimport com.google.android.gms.tasks.Task;\nimport com.google.android.gms.tasks.TaskCompletionSource;\n\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.common.api.GoogleApiManager;\nimport org.microg.gms.common.api.PendingGoogleApiCall;\n\nimport static android.os.Build.VERSION.SDK_INT;\n\n/**\n * Base class for Google API entry points. API clients based on this class manage the connection between your app and Google Play services\n * (as opposed to {@link GoogleApiClient}-based calls).\n * <p>\n * GoogleApi-based instances enqueue calls until a connection is made to Google Play services, and then execute them in order. The instances\n * are:\n * <ul>\n *     <li>\"Cheap\" to create</li>\n *     <li>Thread-safe</li>\n *     <li>Automatically deduplicated</li>\n *     <li>Automatically timed-out and reconnected when necessary</li>\n * </ul>\n * {@code GoogleApi} abstracts the connection to Play services, so callers do not need to implement {@link GoogleApiClient.ConnectionCallbacks}.\n * <p>\n * If the user needs to install or update Google Play services, {@code GoogleApi} will prompt the user to do so and enqueue API calls until the issue is\n * resolved. If {@code GoogleApi} was initialized with an {@code Activity} it will create a foreground prompt, otherwise it will display a system notification. If\n * the user cancels the resolution or some other issue arises, pending API calls will be fail with an {@link ApiException} and status code\n * {@code CommonStatusCodes.API_NOT_CONNECTED}.\n * <p>\n * If isGooglePlayServicesAvailable returns {@code true}, {@code GoogleApi} instances will not show any UI to resolve connection failures.\n */\n@PublicApi\npublic abstract class GoogleApi<O extends Api.ApiOptions> implements HasApiKey<O> {\n    @NonNull\n    private final GoogleApiManager manager;\n    @Hide\n    @NonNull\n    public final Api<O> api;\n    @Hide\n    @NonNull\n    public final O options;\n    @NonNull\n    private final Context context;\n    @Nullable\n    private final String contextAttributionTag;\n    @NonNull\n    private final Looper looper;\n    @NonNull\n    private final GoogleApiClient apiClient;\n    @NonNull\n    private final StatusExceptionMapper exceptionMapper;\n    private final ApiKey<O> key;\n\n    @Hide\n    public GoogleApi(@NonNull Context context, @NonNull Api<O> api, @NonNull O options, @NonNull Settings settings) {\n        this(context, null, api, options, settings);\n    }\n\n    @Hide\n    @Deprecated\n    public GoogleApi(@NonNull Context context, @NonNull Api<O> api, @NonNull O options, @NonNull StatusExceptionMapper exceptionMapper) {\n        this(context, api, options, new Settings.Builder().setMapper(exceptionMapper).build());\n    }\n\n    @Deprecated\n    public GoogleApi(@NonNull Activity activity, @NonNull Api<O> api, @NonNull O options, @NonNull StatusExceptionMapper exceptionMapper) {\n        this(activity, api, options, new Settings.Builder().setMapper(exceptionMapper).setLooper(activity.getMainLooper()).build());\n    }\n\n    @Hide\n    @MainThread\n    public GoogleApi(@NonNull Activity activity, @NonNull Api<O> api, @NonNull O options, @NonNull Settings settings) {\n        this(activity, activity, api, options, settings);\n    }\n\n    private GoogleApi(@NonNull Context context, @Nullable Activity activity, @NonNull Api<O> api, @NonNull O options, @NonNull Settings settings) {\n        this.context = context.getApplicationContext();\n        if (SDK_INT < 30) {\n            this.contextAttributionTag = getApiFallbackAttributionTag(context);\n        } else {\n            this.contextAttributionTag = ContextCompat.getAttributionTag(context);\n        }\n        this.api = api;\n        this.options = options;\n        this.looper = settings.looper;\n        this.key = ApiKey.getSharedApiKey(api, options, contextAttributionTag);\n        this.apiClient = null; //new ConnectionlessGoogleApiClient(this);\n        this.manager = GoogleApiManager.getInstance(context);\n        this.exceptionMapper = settings.exceptionMapper;\n    }\n\n    @Hide\n    @Deprecated\n    protected GoogleApi(Context context, Api<O> api, O options) {\n        this(context, null, api, options, Settings.DEFAULT_SETTINGS);\n    }\n\n    @NonNull\n    @Hide\n    public GoogleApiClient asGoogleApiClient() {\n        return this.apiClient;\n    }\n\n    /**\n     * This method is only invoked on versions below Android R, where no attribution tag is available. If APIs have some other type of client\n     * identifier they wish to use, they may implement this method in order to provide their own fallback which will be used in place of the\n     * attribution tag (and thus passed through client/module implementations as the attribution tag).\n     * <p>\n     * This method is invoked from the constructor, and should be careful not to reference uninitialized members or allow references to escape.\n     */\n    protected @Nullable String getApiFallbackAttributionTag(Context context) {\n        return null;\n    }\n\n    @Override\n    @NonNull\n    @Hide\n    public ApiKey<O> getApiKey() {\n        return this.key;\n    }\n\n    @NonNull\n    @Hide\n    public O getApiOptions() {\n        return this.options;\n    }\n\n    @NonNull\n    @Hide\n    public Context getApplicationContext() {\n        return this.context;\n    }\n\n    @Nullable\n    @Hide\n    protected String getContextAttributionTag() {\n        return this.contextAttributionTag;\n    }\n\n    @Nullable\n    @Hide\n    @Deprecated\n    protected String getContextFeatureId() {\n        return this.contextAttributionTag;\n    }\n\n    @NonNull\n    @Hide\n    public Looper getLooper() {\n        return this.looper;\n    }\n\n    @Hide\n    protected <R, A extends Api.Client> Task<R> scheduleTask(PendingGoogleApiCall<R, A> apiCall) {\n        TaskCompletionSource<R> completionSource = new TaskCompletionSource<>();\n        manager.scheduleTask(this, apiCall, completionSource);\n        return completionSource.getTask();\n    }\n\n    @Hide\n    public static class Settings {\n        @NonNull\n        public static final Settings DEFAULT_SETTINGS = new Builder().build();\n\n        @NonNull\n        public final StatusExceptionMapper exceptionMapper;\n\n        @NonNull\n        public final Looper looper;\n\n        @Hide\n        public static class Builder {\n            private StatusExceptionMapper exceptionMapper;\n            private Looper looper;\n\n            @NonNull\n            public Settings build() {\n                if (exceptionMapper == null) exceptionMapper = new ApiExceptionMapper();\n                if (looper == null) looper = Looper.getMainLooper();\n                return new Settings(exceptionMapper, looper);\n            }\n\n            @NonNull\n            public Builder setLooper(@NonNull Looper looper) {\n                this.looper = looper;\n                return this;\n            }\n\n            @NonNull\n            public Builder setMapper(@NonNull StatusExceptionMapper exceptionMapper) {\n                this.exceptionMapper = exceptionMapper;\n                return this;\n            }\n        }\n\n        private Settings(@NonNull StatusExceptionMapper exceptionMapper, @NonNull Looper looper) {\n            this.exceptionMapper = exceptionMapper;\n            this.looper = looper;\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/api/GoogleApiActivity.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.common.api;\n\nimport android.app.Activity;\nimport android.content.DialogInterface;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Helper activity used by Google Play services APIs to display resolutions for connection errors.\n */\n@PublicApi\npublic class GoogleApiActivity extends Activity implements DialogInterface.OnCancelListener {\n    @Override\n    @PublicApi(exclude = true)\n    public void onCancel(DialogInterface dialog) {\n\n    }\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/api/GoogleApiClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2013 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.common.api;\n\nimport android.accounts.Account;\nimport android.app.Activity;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.os.Looper;\nimport android.view.Gravity;\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.fragment.app.FragmentActivity;\n\nimport com.google.android.gms.common.ConnectionResult;\n\nimport com.google.android.gms.common.Scopes;\nimport com.google.android.gms.common.api.internal.ListenerHolder;\nimport com.google.android.gms.common.api.internal.SignInConnectionListener;\nimport com.google.android.gms.signin.SignInOptions;\nimport org.microg.gms.auth.AuthConstants;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.common.PublicApi;\nimport com.google.android.gms.common.internal.ClientSettings;\nimport org.microg.gms.common.api.GoogleApiClientImpl;\n\nimport java.io.FileDescriptor;\nimport java.io.PrintWriter;\nimport java.util.*;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * The main entry point for Google Play services integration.\n * <p/>\n * GoogleApiClient is used with a variety of static methods. Some of these methods require that GoogleApiClient be connected, some will\n * queue up calls before GoogleApiClient is connected; check the specific API documentation to determine whether you need to be connected.\n * <p/>\n * Before any operation is executed, the GoogleApiClient must be connected. The simplest way to manage the connection is to use\n * enableAutoManage.\n * <p/>\n * GoogleApiClient instances are not thread-safe. To access Google APIs from multiple threads simultaneously, create a GoogleApiClient on\n * each thread. GoogleApiClient service connections are cached internally, so creating multiple instances is fast.\n *\n * @deprecated Use {@link GoogleApi} based APIs instead.\n */\n@Deprecated\npublic abstract class GoogleApiClient {\n    private static final Set<GoogleApiClient> CLIENTS = Collections.newSetFromMap(new WeakHashMap<>());\n\n    @NonNull\n    @Hide\n    public static String DEFAULT_ACCOUNT = \"<<default account>>\";\n\n    /**\n     * If a required authenticated API fails to connect, the entire GoogleApiClient will fail to connect and a failed {@link ConnectionResult} will be\n     * delivered to {@code OnConnectionFailedListener#onConnectionFailed}. Once a connection has successfully completed the only way to\n     * disconnect the authenticated APIs is to call {@link #disconnect()} on this GoogleApiClient.\n     * <p>\n     * Using this mode is equivalent to calling connect on a GoogleApiClient that contains authenticated APIs.\n     * <p>\n     * It is an error to use this mode if no authenticated APIs have been added to this GoogleApiClient.\n     */\n    public static final int SIGN_IN_MODE_REQUIRED = 1;\n\n    /**\n     * If authenticated APIs are present they will attempt to connect, but failure of an authenticated API will not cause the GoogleApiClient\n     * connection to fail. After {@code ConnectionCallbacks#onConnected} is received, the status of an authenticated API can be checked with\n     * {@link #hasConnectedApi(Api)}.\n     * <p>\n     * A GoogleApiClient using this mode may be transitioned between authenticated and unauthenticated states by adding\n     * {@code GOOGLE_SIGN_IN_API}. To get an Intent that will allow the user to sign-in, call {@code getSignInIntent}. To sign the user out, call\n     * {@code signOut}.\n     * <p>\n     * It is an error to call connect with no arguments on a client in this mode.\n     */\n    public static final int SIGN_IN_MODE_OPTIONAL = 2;\n\n    /**\n     * Connects the client to Google Play services. Blocks until the connection either succeeds or fails.\n     * <p>\n     * Keep in mind this method will cause ANRs if called from the main thread.\n     * <p>\n     * If the client is already connected, this methods returns immediately. If the client is already connecting (for example due to a prior call to\n     * connect), this method blocks until the existing connection attempt completes. If a prior connection attempt has already failed, then a new\n     * connection attempt is started.\n     *\n     * @return the result of the connection\n     */\n    @NonNull\n    public abstract ConnectionResult blockingConnect();\n\n    /**\n     * Connects the client to Google Play services. Blocks until the connection either succeeds or fails, or the timeout is reached.\n     * <p>\n     * Keep in mind this method will cause ANRs if called from the main thread.\n     * <p>\n     * If the client is already connected, this methods returns immediately. If the client is already connecting (for example due to a prior call to\n     * connect), this method blocks until the existing connection attempt completes or the timeout is reached. If a prior connection attempt has\n     * already failed, then a new connection attempt is started.\n     *\n     * @param timeout the maximum time to wait\n     * @param unit    the time unit of the {@code timeout} argument\n     * @return the result of the connection\n     */\n    @NonNull\n    public abstract ConnectionResult blockingConnect(long timeout, @NonNull TimeUnit unit);\n\n    /**\n     * Clears the account selected by the user and reconnects the client asking the user to pick an\n     * account again if {@link Builder#useDefaultAccount()} was set.\n     *\n     * @return the pending result is fired once the default account has been cleared, but before\n     * the client is reconnected - for that {@link ConnectionCallbacks} can be used.\n     */\n    @NonNull\n    public abstract PendingResult<Status> clearDefaultAccountAndReconnect();\n\n    /**\n     * Connects the client to Google Play services. This method returns immediately, and connects\n     * to the service in the background. If the connection is successful,\n     * {@link ConnectionCallbacks#onConnected(Bundle)} is called and enqueued items are executed.\n     * On a failure, {@link OnConnectionFailedListener#onConnectionFailed(ConnectionResult)} is\n     * called.\n     * <p>\n     * If the client is already connected or connecting, this method does nothing.\n     */\n    public abstract void connect();\n\n    /**\n     * Connects the client to Google Play services using the given sign in mode.\n     * <p>\n     * It is an error to make multiple calls to this method passing different modes. Once a mode is selected, all future connect calls must use the\n     * same mode.\n     *\n     * @see #connect()\n     * @see #SIGN_IN_MODE_REQUIRED\n     * @see #SIGN_IN_MODE_OPTIONAL\n     */\n    public abstract void connect(int signInMode);\n\n    /**\n     * Closes the connection to Google Play services. No calls can be made using this client after calling this method. Any method calls that\n     * haven't executed yet will be canceled, and their {@link ResultCallback#onResult(Result)} callbacks won't be called.\n     * <p>\n     * If the connection to the remote service hasn't been established yet, all enqueued calls will be canceled.\n     *\n     * @see #connect()\n     */\n    public abstract void disconnect();\n\n    /**\n     * Prints the GoogleApiClient's state into the given stream.\n     *\n     * @param prefix Desired prefix to prepend at each line of output.\n     * @param fd     The raw file descriptor that the dump is being sent to.\n     * @param writer The PrintWriter to use for writing the dump.\n     * @param args   Additional arguments to the dump request.\n     */\n    public abstract void dump(@NonNull String prefix, @Nullable FileDescriptor fd, @NonNull PrintWriter writer, @Nullable String[] args);\n\n    /**\n     * Prints the state of all GoogleApiClients in the current process into the given stream.\n     * <p>\n     * This can be used to diagnose lifecycle issues where GoogleApiClients may be unintentionally left in the connected state. Note that the\n     * output may include clients that are no longer referenced but have not yet been garbage collected.\n     *\n     * @param prefix Desired prefix to prepend at each line of output.\n     * @param fd     The raw file descriptor that the dump is being sent to.\n     * @param writer The PrintWriter to use for writing the dump.\n     * @param args   Additional arguments to the dump request.\n     */\n    public static void dumpAll(@NonNull String prefix, @NonNull FileDescriptor fd, @NonNull PrintWriter writer, @NonNull String[] args) {\n        synchronized (CLIENTS) {\n            int idx = 0;\n            for (GoogleApiClient client : CLIENTS) {\n                writer.append(prefix).append(\"GoogleApiClient#\").println(idx++);\n                client.dump(prefix + \"  \", fd, writer, args);\n            }\n        }\n    }\n\n    /**\n     * Returns the {@link ConnectionResult} for the GoogleApiClient's connection to the specified API. This method must only be called after connect\n     * has been called and before {@link #disconnect()} is called.\n     * <p>\n     * This method should be used to check the connection result of an API added via addApiIfAvailable in the event that the overall connection\n     * succeeded, but the individual API failed to connect. To check the failure of the overall connection, use {@link Builder#addOnConnectionFailedListener}.\n     * <p>\n     * This method may return stale results if the GoogleApiClient is reconnecting due to a lost network connection. It is guaranteed to return the\n     * most recent ConnectionResult from attempting to connect the given API, but will throw an IllegalStateException if called before calling\n     * connect, after calling disconnect, or after receiving {@link OnConnectionFailedListener#onConnectionFailed(ConnectionResult)}. This method can be used to\n     * easily determine why an API failed to connect if it was not available. To determine whether a given API is currently connected (without\n     * potential stale results) see {@link #hasConnectedApi(Api)}.\n     *\n     * @param api The {@link Api} to retrieve the ConnectionResult of. Passing an API that was not registered with the\n     *            GoogleApiClient results in an IllegalArgumentException.\n     */\n    @NonNull\n    public abstract ConnectionResult getConnectionResult(@NonNull Api<?> api);\n\n    @NonNull\n    @Hide\n    public Context getContext() {\n        throw new UnsupportedOperationException();\n    }\n\n    @NonNull\n    @Hide\n    public Looper getLooper() {\n        throw new UnsupportedOperationException();\n    }\n\n    @Hide\n    public boolean hasApi(@NonNull Api<?> api) {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Returns whether or not this GoogleApiClient has the specified API in a connected state.\n     *\n     * @param api The {@link Api} to test the connection of.\n     */\n    public abstract boolean hasConnectedApi(@NonNull Api<?> api);\n\n    /**\n     * Checks if the client is currently connected to the service, so that requests to other methods will succeed. Applications should guard client\n     * actions caused by the user with a call to this method.\n     *\n     * @return {@code true} if the client is connected to the service.\n     */\n    public abstract boolean isConnected();\n\n    /**\n     * Checks if the client is attempting to connect to the service.\n     *\n     * @return {@code true} if the client is attempting to connect to the service.\n     */\n    public abstract boolean isConnecting();\n\n    /**\n     * Returns {@code true} if the specified listener is currently registered to receive connection\n     * events.\n     *\n     * @param listener The listener to check for.\n     * @return {@code true} if the specified listener is currently registered to receive connection\n     * events.\n     * @see #registerConnectionCallbacks(ConnectionCallbacks)\n     * @see #unregisterConnectionCallbacks(ConnectionCallbacks)\n     */\n    public abstract boolean isConnectionCallbacksRegistered(@NonNull ConnectionCallbacks listener);\n\n    /**\n     * Returns {@code true} if the specified listener is currently registered to receive connection\n     * failed events.\n     *\n     * @param listener The listener to check for.\n     * @return {@code true} if the specified listener is currently registered to receive connection\n     * failed events.\n     * @see #registerConnectionFailedListener(OnConnectionFailedListener)\n     * @see #unregisterConnectionFailedListener(OnConnectionFailedListener)\n     */\n    public abstract boolean isConnectionFailedListenerRegistered(@NonNull OnConnectionFailedListener listener);\n\n    @Hide\n    public boolean maybeSignIn(@NonNull SignInConnectionListener listener) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Hide\n    public void maybeSignOut() {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Closes the current connection to Google Play services and creates a new connection. Equivalent to calling {@link #disconnect()} followed by\n     * connect.\n     * <p/>\n     * This method closes the current connection then returns immediately and reconnects to the\n     * service in the background.\n     * <p/>\n     * After calling this method, your application will receive\n     * {@link ConnectionCallbacks#onConnected(Bundle)} if the connection is successful, or\n     * {@link OnConnectionFailedListener#onConnectionFailed(ConnectionResult)} if the connection\n     * failed.\n     *\n     * @see #connect()\n     * @see #disconnect()\n     */\n    public abstract void reconnect();\n\n    /**\n     * Registers a listener to receive connection events from this {@link GoogleApiClient}. If the\n     * service is already connected, the listener's {@link ConnectionCallbacks#onConnected(Bundle)}\n     * method will be called immediately. Applications should balance calls to this method with\n     * calls to {@link #unregisterConnectionCallbacks(ConnectionCallbacks)} to avoid leaking\n     * resources.\n     * <p/>\n     * If the specified listener is already registered to receive connection events, this method\n     * will not add a duplicate entry for the same listener, but will still call the listener's\n     * {@link ConnectionCallbacks#onConnected(Bundle)} method if currently connected.\n     * <p/>\n     * Note that the order of messages received here may not be stable, so clients should not rely\n     * on the order that multiple listeners receive events in.\n     *\n     * @param listener the listener where the results of the asynchronous {@link #connect()} call\n     *                 are delivered.\n     */\n    public abstract void registerConnectionCallbacks(@NonNull ConnectionCallbacks listener);\n\n    /**\n     * Registers a listener to receive connection failed events from this {@link GoogleApiClient}.\n     * Unlike {@link #registerConnectionCallbacks(ConnectionCallbacks)}, if the service is not\n     * already connected, the listener's\n     * {@link OnConnectionFailedListener#onConnectionFailed(ConnectionResult)} method will not be\n     * called immediately. Applications should balance calls to this method with calls to\n     * {@link #unregisterConnectionFailedListener(OnConnectionFailedListener)} to avoid leaking\n     * resources.\n     * <p/>\n     * If the specified listener is already registered to receive connection failed events, this\n     * method will not add a duplicate entry for the same listener.\n     * <p/>\n     * Note that the order of messages received here may not be stable, so clients should not rely\n     * on the order that multiple listeners receive events in.\n     *\n     * @param listener the listener where the results of the asynchronous {@link #connect()} call\n     *                 are delivered.\n     */\n    public abstract void registerConnectionFailedListener(@NonNull OnConnectionFailedListener listener);\n\n    @NonNull\n    @Hide\n    public <L> ListenerHolder<L> registerListener(@NonNull L listener) {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Disconnects the client and stops automatic lifecycle management. Use this before creating a\n     * new client (which might be necessary when switching accounts, changing the set of used APIs\n     * etc.).\n     * <p/>\n     * This method must be called from the main thread.\n     *\n     * @param lifecycleActivity the activity managing the client's lifecycle.\n     * @throws IllegalStateException if called from outside of the main thread.\n     * @see Builder#enableAutoManage(FragmentActivity, int, OnConnectionFailedListener)\n     */\n    public abstract void stopAutoManage(@NonNull FragmentActivity lifecycleActivity) throws IllegalStateException;\n\n    /**\n     * Removes a connection listener from this {@link GoogleApiClient}. Note that removing a\n     * listener does not generate any callbacks.\n     * <p/>\n     * If the specified listener is not currently registered to receive connection events, this\n     * method will have no effect.\n     *\n     * @param listener the listener to unregister.\n     */\n    public abstract void unregisterConnectionCallbacks(@NonNull ConnectionCallbacks listener);\n\n    /**\n     * Removes a connection failed listener from the {@link GoogleApiClient}. Note that removing a\n     * listener does not generate any callbacks.\n     * <p/>\n     * If the specified listener is not currently registered to receive connection failed events,\n     * this method will have no effect.\n     *\n     * @param listener the listener to unregister.\n     */\n    public abstract void unregisterConnectionFailedListener(@NonNull OnConnectionFailedListener listener);\n\n    /**\n     * Builder to configure a {@link GoogleApiClient}.\n     *\n     * @deprecated Use {@link GoogleApi} based APIs instead.\n     */\n    @Deprecated\n    public static class Builder {\n        private final Context context;\n        private final Map<Api<?>, Api.ApiOptions> apis = new HashMap<>();\n        private final Set<ConnectionCallbacks> connectionCallbacks = new HashSet<>();\n        private final Set<OnConnectionFailedListener> connectionFailedListeners = new HashSet<>();\n        private final Set<Scope> scopes = new HashSet<>();\n        private final Map<Api<?>, Set<Scope>> scopesForOptionalApi = new HashMap<>();\n        private Account account;\n        private int clientId = -1;\n        private FragmentActivity fragmentActivity;\n        private Looper looper;\n        private int gravityForPopups;\n        private OnConnectionFailedListener unresolvedConnectionFailedListener;\n        private View viewForPopups;\n\n        /**\n         * Builder to help construct the {@link GoogleApiClient} object.\n         *\n         * @param context The context to use for the connection.\n         */\n        public Builder(@NonNull Context context) {\n            this.context = context;\n            this.looper = context.getMainLooper();\n        }\n\n        /**\n         * Builder to help construct the {@link GoogleApiClient} object.\n         *\n         * @param context                  The context to use for the connection.\n         * @param connectedListener        The listener where the results of the asynchronous\n         *                                 {@link #connect()} call are delivered.\n         * @param connectionFailedListener The listener which will be notified if the connection\n         *                                 attempt fails.\n         */\n        public Builder(@NonNull Context context, @NonNull ConnectionCallbacks connectedListener, @NonNull OnConnectionFailedListener connectionFailedListener) {\n            this(context);\n            addConnectionCallbacks(connectedListener);\n            addOnConnectionFailedListener(connectionFailedListener);\n        }\n\n        /**\n         * Specify which Apis are requested by your app. See {@link Api} for more information.\n         *\n         * @param api The Api requested by your app.\n         * @see Api\n         */\n        @NonNull\n        public Builder addApi(@NonNull Api<? extends Api.ApiOptions.NotRequiredOptions> api) {\n            apis.put(api, null);\n            scopes.addAll(api.getClientBuilder().getImpliedScopes(null));\n            return this;\n        }\n\n        /**\n         * Specify which Apis are requested by your app. See {@link Api} for more information.\n         *\n         * @param api     The Api requested by your app.\n         * @param options Any additional parameters required for the specific AP\n         * @see Api\n         */\n        @NonNull\n        public <O extends Api.ApiOptions.HasOptions> Builder addApi(@NonNull Api<O> api, @NonNull O options) {\n            apis.put(api, options);\n            scopes.addAll(api.getClientBuilder().getImpliedScopes(options));\n            return this;\n        }\n\n        /**\n         * Specify which Apis should attempt to connect, but are not strictly required for your app. The GoogleApiClient will try to connect to these\n         * Apis, but will not necessarily fail if there are only errors when connecting to an unavailable Api added with this method. See {@link Api} for more\n         * information.\n         *\n         * @param api    The Api requested by your app.\n         * @param scopes Scopes required by this API.\n         * @see Api\n         */\n        @NonNull\n        public Builder addApiIfAvailable(@NonNull Api<? extends Api.ApiOptions.NotRequiredOptions> api, @NonNull Scope... scopes) {\n            apis.put(api, null);\n            Set<Scope> scopeSet = new HashSet<>(api.getClientBuilder().getImpliedScopes(null));\n            Collections.addAll(scopeSet, scopes);\n            scopesForOptionalApi.put(api, scopeSet);\n            return this;\n        }\n\n        /**\n         * Specify which Apis should attempt to connect, but are not strictly required for your app. The GoogleApiClient will try to connect to these\n         * Apis, but will not necessarily fail if there are only errors when connecting to an unavailable Api added with this method. See {@link Api} for more\n         * information.\n         *\n         * @param api    The Api requested by your app.\n         * @param scopes Scopes required by this API.\n         * @see Api\n         */\n        @NonNull\n        public <O extends Api.ApiOptions.HasOptions> GoogleApiClient.Builder addApiIfAvailable(@NonNull Api<O> api, @NonNull O options, @NonNull Scope... scopes) {\n            apis.put(api, options);\n            Set<Scope> scopeSet = new HashSet<>(api.getClientBuilder().getImpliedScopes(options));\n            Collections.addAll(scopeSet, scopes);\n            scopesForOptionalApi.put(api, scopeSet);\n            return this;\n        }\n\n        /**\n         * Registers a listener to receive connection events from this {@code GoogleApiClient}. Applications should balance calls to this method with calls\n         * to {@link #unregisterConnectionCallbacks(ConnectionCallbacks)} to avoid leaking resources.\n         * <p>\n         * If the specified listener is already registered to receive connection events, this method will not add a duplicate entry for the same listener.\n         * <p>\n         * Note that the order of messages received here may not be stable, so clients should not rely on the order that multiple listeners receive\n         * events in.\n         *\n         * @param listener the listener where the results of the asynchronous connect call are delivered.\n         */\n        @NonNull\n        public Builder addConnectionCallbacks(@NonNull ConnectionCallbacks listener) {\n            connectionCallbacks.add(listener);\n            return this;\n        }\n\n        /**\n         * Adds a listener to register to receive connection failed events from this {@code GoogleApiClient}. Applications should balance calls to this\n         * method with calls to {@link #unregisterConnectionFailedListener(OnConnectionFailedListener)} to avoid leaking resources.\n         * <p>\n         * If the specified listener is already registered to receive connection failed events, this method will not add a duplicate entry for the same\n         * listener.\n         * <p>\n         * Note that the order of messages received here may not be stable, so clients should not rely on the order that multiple listeners receive\n         * events in.\n         *\n         * @param listener the listener where the results of the asynchronous connect call are delivered.\n         */\n        @NonNull\n        public Builder addOnConnectionFailedListener(@NonNull OnConnectionFailedListener listener) {\n            connectionFailedListeners.add(listener);\n            return this;\n        }\n\n        /**\n         * Specify the OAuth 2.0 scopes requested by your app. See {@link Scopes} for more information.\n         * <p>\n         * It is an error to call this method when using {@code GOOGLE_SIGN_IN_API}. Use {@code requestScopes} instead.\n         *\n         * @param scope The OAuth 2.0 scopes requested by your app.\n         * @see Scopes\n         */\n        @NonNull\n        public Builder addScope(Scope scope) {\n            scopes.add(scope);\n            return this;\n        }\n\n        /**\n         * Builds a new {@link GoogleApiClient} object for communicating with the Google APIs.\n         *\n         * @return The {@link GoogleApiClient} object.\n         */\n        @NonNull\n        public GoogleApiClient build() {\n            return new GoogleApiClientImpl(context, looper, getClientSettings(), apis, connectionCallbacks, connectionFailedListeners, clientId);\n        }\n\n        /**\n         * Enables automatic lifecycle management in a support library {@link FragmentActivity} that connects the client in {@link FragmentActivity#onStart()} and disconnects it in\n         * {@link FragmentActivity#onStop()}.\n         * <p>\n         * It handles user recoverable errors appropriately and calls {@link OnConnectionFailedListener#onConnectionFailed(ConnectionResult)} on the\n         * {@code unresolvedConnectionFailedListener} if the {@link ConnectionResult} has no resolution. This eliminates most of the boiler plate associated with\n         * using {@link GoogleApiClient}.\n         * <p>\n         * This method can only be used if this GoogleApiClient will be the only auto-managed client in the containing activity. The api client will be\n         * assigned a default client id.\n         * <p>\n         * When using this option, {@link #build()} must be called from the main thread.\n         *\n         * @param fragmentActivity                   The activity that uses the {@link GoogleApiClient}. For lifecycle management to work correctly\n         *                                           the activity must call its parent's {@link Activity#onActivityResult(int, int, Intent)}.\n         * @param unresolvedConnectionFailedListener Called if the connection failed and there was no resolution or the user chose not to complete\n         *                                           the provided resolution. If this listener is called, the client will no longer be auto-managed,\n         *                                           and a new instance must be built. In the event that the user chooses not to complete a\n         *                                           resolution, the will have a status code of {@link ConnectionResult#CANCELED}.\n         */\n        @NonNull\n        public Builder enableAutoManage(@NonNull FragmentActivity fragmentActivity, @Nullable OnConnectionFailedListener unresolvedConnectionFailedListener) {\n            enableAutoManage(fragmentActivity, 0, unresolvedConnectionFailedListener);\n            return this;\n        }\n\n        /**\n         * Enables automatic lifecycle management in a support library {@link FragmentActivity} that connects the client in {@link FragmentActivity#onStart()} and disconnects it in\n         * {@link FragmentActivity#onStop()}.\n         * <p>\n         * It handles user recoverable errors appropriately and calls {@code unresolvedConnectionFailedListener} if the {@link ConnectionResult} has no\n         * resolution. This eliminates most of the boiler plate associated with using {@link GoogleApiClient}.\n         * <p>\n         * When using this option, {@link #build()} must be called from the main thread.\n         *\n         * @param fragmentActivity                   The activity that uses the {@link GoogleApiClient}. For lifecycle management to work correctly\n         *                                           the activity must call its parent's {@link Activity#onActivityResult(int, int, Intent)}.\n         * @param clientId                           A non-negative identifier for this client. At any given time, only one auto-managed client is\n         *                                           allowed per id. To reuse an id you must first call {@link #stopAutoManage(FragmentActivity)} on the previous client.\n         * @param unresolvedConnectionFailedListener Called if the connection failed and there was no resolution or the user chose not to complete\n         *                                           the provided resolution. If this listener is called, the client will no longer be auto-managed,\n         *                                           and a new instance must be built. In the event that the user chooses not to complete a\n         *                                           resolution, the will have a status code of {@link ConnectionResult#CANCELED}.\n         * @throws NullPointerException     if fragmentActivity is null\n         * @throws IllegalArgumentException if clientId is negative.\n         * @throws IllegalStateException    if clientId is already being auto-managed.\n         */\n        @NonNull\n        public Builder enableAutoManage(@NonNull FragmentActivity fragmentActivity, int clientId, @Nullable OnConnectionFailedListener unresolvedConnectionFailedListener) throws NullPointerException, IllegalArgumentException, IllegalStateException {\n            this.fragmentActivity = fragmentActivity;\n            this.clientId = clientId;\n            this.unresolvedConnectionFailedListener = unresolvedConnectionFailedListener;\n            return this;\n        }\n\n        @Hide\n        public ClientSettings getClientSettings() {\n            return new ClientSettings(account, scopes, scopesForOptionalApi, gravityForPopups, viewForPopups, context.getPackageName(), context.getClass().getName(), SignInOptions.DEFAULT);\n        }\n\n        /**\n         * Specify an account name on the device that should be used. If this is never called, the client will use the current default account for Google\n         * Play services for this application.\n         * <p>\n         * It is an error to call this method when using {@code GOOGLE_SIGN_IN_API}. Use {@code #setAccountName(String)} instead.\n         *\n         * @param accountName The account name on the device that should be used by {@link GoogleApiClient}.\n         */\n        @NonNull\n        public Builder setAccountName(@NonNull String accountName) {\n            this.account = new Account(accountName, AuthConstants.DEFAULT_ACCOUNT_TYPE);\n            return this;\n        }\n\n        /**\n         * Specifies the part of the screen at which games service popups (for example, \"welcome back\" or \"achievement unlocked\" popups) will be\n         * displayed using gravity.\n         * <p>\n         * Default value is {@link Gravity#TOP}|{@link Gravity#CENTER_HORIZONTAL}.\n         *\n         * @param gravityForPopups The gravity which controls the placement of games service popups.\n         */\n        @NonNull\n        public Builder setGravityForPopups(int gravityForPopups) {\n            this.gravityForPopups = gravityForPopups;\n            return this;\n        }\n\n        /**\n         * Sets a {@link Handler} to indicate which thread to use when invoking callbacks. Will not be used directly to handle callbacks. If this is not called\n         * then the application's main thread will be used.\n         */\n        @NonNull\n        public Builder setHandler(@NonNull Handler handler) {\n            this.looper = handler.getLooper();\n            return this;\n        }\n\n        /**\n         * Sets the {@link View} to use as a content view for popups.\n         *\n         * @param viewForPopups The view to use as a content view for popups. View cannot be null.\n         */\n        @NonNull\n        public Builder setViewForPopups(@NonNull View viewForPopups) {\n            this.viewForPopups = viewForPopups;\n            return this;\n        }\n\n        /**\n         * Specify that the default account should be used when connecting to services.\n         */\n        public Builder useDefaultAccount() {\n            setAccountName(DEFAULT_ACCOUNT);\n            return this;\n        }\n    }\n\n    /**\n     * Provides callbacks that are called when the client is connected or disconnected from the\n     * service. Most applications implement {@link #onConnected(Bundle)} to start making requests.\n     */\n    @PublicApi\n    @Deprecated\n    public interface ConnectionCallbacks extends com.google.android.gms.common.api.internal.ConnectionCallbacks {\n        /**\n         * A suspension cause informing that the service has been killed.\n         */\n        int CAUSE_SERVICE_DISCONNECTED = 1;\n        /**\n         * A suspension cause informing you that a peer device connection was lost.\n         */\n        int CAUSE_NETWORK_LOST = 2;\n\n        void onConnected(Bundle connectionHint);\n    }\n\n    /**\n     * Provides callbacks for scenarios that result in a failed attempt to connect the client to\n     * the service. See {@link ConnectionResult} for a list of error codes and suggestions for\n     * resolution.\n     */\n    @PublicApi\n    @Deprecated\n    public interface OnConnectionFailedListener extends com.google.android.gms.common.api.internal.OnConnectionFailedListener {\n    }\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/api/HasApiKey.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.api;\n\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.api.internal.ApiKey;\nimport org.microg.gms.common.Hide;\n\npublic interface HasApiKey<O extends Api.ApiOptions> {\n    @NonNull\n    @Hide\n    ApiKey<O> getApiKey();\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/api/OptionalModuleApi.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.api;\n\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.Feature;\nimport org.microg.gms.common.Hide;\n\n/**\n * An API that requires an optional module.\n */\npublic interface OptionalModuleApi {\n    @Hide\n    @NonNull\n    Feature[] getOptionalFeatures();\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/api/OptionalPendingResult.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.common.api;\n\n/**\n * Each {@code OptionalPendingResult} is a {@link PendingResult} with additional support for non-blocking accessors. The result of an\n * {@code OptionalPendingResult} may be available immediately. If the result is available {@link #isDone} will return true.\n *\n * @param <R> Result returned by various accessors.\n */\npublic abstract class OptionalPendingResult<R extends Result> extends PendingResult<R> {\n    /**\n     * Returns the {@link Result} immediately if it is available. If the result is not available, an exception will be thrown. This method should only be\n     * called after checking that {@link #isDone} returns true.\n     * <p>\n     * After the result has been retrieved using {@link #get}, await, or has been delivered to the result callback, it is an error to attempt to retrieve the result\n     * again. It is the responsibility of the caller or callback receiver to release any resources associated with the returned result. Some result types\n     * may implement {@link Releasable}, in which case {@link Releasable#release} should be used to free the associated resources.\n     *\n     * @throws IllegalStateException when the result is not {@link #isDone}.\n     */\n    public abstract R get();\n\n    /**\n     * Returns true if the result is available immediately, false otherwise.\n     */\n    public abstract boolean isDone();\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/api/PendingResult.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2015 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.common.api;\n\nimport android.os.Handler;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.ResultTransform;\nimport com.google.android.gms.common.internal.TransformedResult;\nimport org.microg.gms.common.Hide;\n\nimport java.util.concurrent.TimeUnit;\n\n/**\n * Represents a pending result from calling an API method in Google Play services. The final result object from a PendingResult is of type R,\n * which can be retrieved in one of two ways.\n * <ul>\n * <li>via blocking calls to {@link #await()}, or {@link #await(long, TimeUnit)}, or</li>\n * <li>via a callback by passing in an object implementing interface {@link ResultCallback} to\n * {@link #setResultCallback(ResultCallback)}.</li>\n * </ul>\n * After the result has been retrieved using {@link #await()} or delivered to the result callback, it is an error to attempt to retrieve the result again. It is\n * the responsibility of the caller or callback receiver to release any resources associated with the returned result. Some result types may\n * implement {@link Releasable}, in which case {@link Releasable#release()} should be used to free the associated resources.\n */\npublic abstract class PendingResult<R extends Result> {\n\n    /**\n     * Blocks until the task is completed. This is not allowed on the UI thread. The returned result object can have an additional failure mode of\n     * {@link CommonStatusCodes#INTERRUPTED}.\n     */\n    public abstract R await();\n\n    /**\n     * Blocks until the task is completed or has timed out waiting for the result. This is not allowed on the UI thread. The returned result object can\n     * have an additional failure mode of either {@link CommonStatusCodes#INTERRUPTED} or {@link CommonStatusCodes#TIMEOUT}.\n     */\n    public abstract R await(long time, TimeUnit unit);\n\n    /**\n     * Requests that the PendingResult be canceled. If the result is available, but not consumed it will be released. If the result is set after\n     * cancelation was requested it is immediately released.\n     * <p>\n     * {@link ResultCallback#onResult(Result)} will never be called, {@link #await()}  will return a failed result with {@link CommonStatusCodes#CANCELED}.\n     */\n    public abstract void cancel();\n\n    /**\n     * Indicates whether the pending result has been canceled either due to calling {@link GoogleApiClient#disconnect()}  or calling {@link #cancel()} directly on the pending result\n     * or an enclosing {@link Batch}.\n     */\n    public abstract boolean isCanceled();\n\n    /**\n     * Set the callback here if you want the result to be delivered via a callback when the result is ready.\n     */\n    public abstract void setResultCallback(@NonNull ResultCallback<R> callback);\n\n    /**\n     * Set the callback here if you want the result to be delivered via a callback when the result is ready or has timed out waiting for the result. The\n     * returned result object can have an additional failure mode of {@link CommonStatusCodes#TIMEOUT}.\n     */\n    public abstract void setResultCallback(@NonNull ResultCallback<R> callback, long time, TimeUnit unit);\n\n    /**\n     * Transforms the result by making another API call.\n     * <p>\n     * If the result is successful, then {@link ResultTransform#onSuccess} will be called to make the additional API call that yields the transformed result. If the result is a\n     * failure, then {@link ResultTransform#onFailure} will be called to (optionally) allow modification of failure status.\n     * <p>\n     * If the result implements {@link Releasable}, then {@link Releasable#release} will be called once the transform has been applied.\n     * <p>\n     * Multiple API calls can be chained together by making subsequent calls to {@link TransformedResult#then(ResultTransform)} and the final result can be received by an instance of\n     * specified via {@link TransformedResult#andFinally(ResultCallbacks)}.\n     * <p>\n     * All {@link ResultTransform}s will be run on a worker thread. These transforms therefore must not interact with UI elements, but they may perform\n     * brief background work (not requiring more than a few seconds). If {@link ResultCallbacks} are specified, these will be called on the thread\n     * specified by {@link GoogleApiClient.Builder#setHandler(Handler)} or on the main thread by default.\n     * <p>\n     * If {@link GoogleApiClient#disconnect()} is called before a series of transforms completes the transforms will continue to run in the background until the last one\n     * completes. In this case, {@link ResultCallbacks} will not be called. Note that this may cause memory leaks if background transformations are\n     * long-running.\n     * <p>\n     * Note: it is an error to use multiple {@link GoogleApiClient}s for various API calls within subsequent {@link ResultTransform}s. Behavior is undefined if\n     * calls don't use the same GoogleApiClient.\n     */\n    @NonNull\n    public <S extends Result> TransformedResult<S> then(@NonNull ResultTransform<? super R, ? extends S> resultTransform) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Hide\n    public interface StatusListener {\n        void onComplete(@NonNull Status status);\n    }\n\n    @Hide\n    public void addStatusListener(@NonNull StatusListener statusListener) {\n        throw new UnsupportedOperationException();\n    }\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/api/internal/ApiExceptionMapper.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.api.internal;\n\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.common.internal.ApiExceptionUtil;\nimport org.microg.gms.common.Hide;\n\n@Hide\npublic class ApiExceptionMapper implements StatusExceptionMapper {\n    @NonNull\n    @Override\n    public Exception getException(@NonNull Status status) {\n        return ApiExceptionUtil.fromStatus(status);\n    }\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/api/internal/ApiKey.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.api.internal;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.api.Api;\nimport org.microg.gms.common.Hide;\n\nimport java.util.Objects;\n\n@Hide\npublic class ApiKey<O extends Api.ApiOptions> {\n    private final Api<O> api;\n    @Nullable\n    private final O options;\n    @Nullable\n    private final String attributionTag;\n\n    private ApiKey(Api<O> api, @Nullable O options, @Nullable String attributionTag) {\n        this.api = api;\n        this.options = options;\n        this.attributionTag = attributionTag;\n    }\n\n    @NonNull\n    @Hide\n    public static <O extends Api.ApiOptions> ApiKey<O> getSharedApiKey(@NonNull Api<O> api, @Nullable O o, @Nullable String attributionTag) {\n        return new ApiKey<>(api, o, attributionTag);\n    }\n\n    @Override\n    public final boolean equals(Object o) {\n        if (!(o instanceof ApiKey)) return false;\n\n        ApiKey<?> apiKey = (ApiKey<?>) o;\n        return Objects.equals(api, apiKey.api) && Objects.equals(options, apiKey.options) && Objects.equals(attributionTag, apiKey.attributionTag);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hashCode(new Object[]{api, options, attributionTag});\n    }\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/api/internal/ConnectionCallbacks.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.common.api.internal;\n\nimport android.os.Bundle;\n\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport org.microg.gms.common.Hide;\n\n@Hide\npublic interface ConnectionCallbacks {\n\n    /**\n     * After calling {@link #connect()}, this method will be invoked asynchronously when the\n     * connect request has successfully completed. After this callback, the application can\n     * make requests on other methods provided by the client and expect that no user\n     * intervention is required to call methods that use account and scopes provided to the\n     * client constructor.\n     * <p/>\n     * Note that the contents of the {@code connectionHint} Bundle are defined by the specific\n     * services. Please see the documentation of the specific implementation of\n     * {@link GoogleApiClient} you are using for more information.\n     *\n     * @param connectionHint Bundle of data provided to clients by Google Play services. May\n     *                       be null if no content is provided by the service.\n     */\n    void onConnected(Bundle connectionHint);\n\n    /**\n     * Called when the client is temporarily in a disconnected state. This can happen if there\n     * is a problem with the remote service (e.g. a crash or resource problem causes it to be\n     * killed by the system). When called, all requests have been canceled and no outstanding\n     * listeners will be executed. GoogleApiClient will automatically attempt to restore the\n     * connection. Applications should disable UI components that require the service, and wait\n     * for a call to {@link #onConnected(Bundle)} to re-enable them.\n     *\n     * @param cause The reason for the disconnection. Defined by constants {@code CAUSE_*}.\n     */\n    void onConnectionSuspended(int cause);\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/api/internal/ListenerHolder.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.api.internal;\n\nimport org.microg.gms.common.Hide;\n\n@Hide\npublic class ListenerHolder<L> {\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/api/internal/OnConnectionFailedListener.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.common.api.internal;\n\nimport android.app.Activity;\n\nimport com.google.android.gms.common.ConnectionResult;\nimport org.microg.gms.common.Hide;\n\n@Hide\npublic interface OnConnectionFailedListener {\n    /**\n     * Called when there was an error connecting the client to the service.\n     *\n     * @param result A {@link ConnectionResult} that can be used for resolving the error, and\n     *               deciding what sort of error occurred. To resolve the error, the resolution\n     *               must be started from an activity with a non-negative {@code requestCode}\n     *               passed to {@link ConnectionResult#startResolutionForResult(Activity, int)}.\n     *               Applications should implement {@link Activity#onActivityResult} in their\n     *               Activity to call {@link #connect()} again if the user has resolved the\n     *               issue (resultCode is {@link Activity#RESULT_OK}).\n     */\n    void onConnectionFailed(ConnectionResult result);\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/api/internal/SignInConnectionListener.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.api.internal;\n\nimport org.microg.gms.common.Hide;\n\n@Hide\npublic interface SignInConnectionListener {\n    void onComplete();\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/data/AbstractDataBuffer.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.common.data;\n\nimport org.microg.gms.common.Hide;\n\nimport java.util.Iterator;\n\n/**\n * Default implementation of DataBuffer. An {@code AbstractDataBuffer} wraps data provided across the binder from Google Play services.\n */\npublic abstract class AbstractDataBuffer<T> implements DataBuffer<T> {\n    protected final DataHolder dataHolder;\n\n    @Hide\n    public AbstractDataBuffer(DataHolder dataHolder) {\n        this.dataHolder = dataHolder;\n    }\n\n    /**\n     * Releases the data buffer, for use in try-with-resources.\n     * <p>\n     * Both close and release shall have identical semantics, and are idempotent.\n     */\n    @Override\n    public void close() {\n        release();\n    }\n\n    /**\n     * Get the item at the specified position. Note that the objects returned from subsequent invocations of this method for the\n     * same position may not be identical objects, but will be equal in value. In other words:\n     * <p>\n     * {@code buffer.get(i) == buffer.get(i)} may return false.\n     * <p>\n     * {@code buffer.get(i).equals(buffer.get(i))} will return true.\n     *\n     * @param position The position of the item to retrieve.\n     * @return the item at {@code position} in this buffer.\n     */\n    public abstract T get(int position);\n\n    @Override\n    public int getCount() {\n        if (dataHolder == null) return 0;\n        return dataHolder.getCount();\n    }\n\n    /**\n     * @deprecated {@link #release()} and {@link #close()} are idempotent, and so is safe to call multiple times\n     */\n    @Deprecated\n    @Override\n    public boolean isClosed() {\n        if (dataHolder == null) return true;\n        return dataHolder.isClosed();\n    }\n\n    @Override\n    public Iterator<T> iterator() {\n        return new DataBufferIterator(this);\n    }\n\n    /**\n     * Releases resources used by the buffer. This method is idempotent.\n     */\n    @Override\n    public void release() {\n        if (dataHolder != null) dataHolder.close();\n    }\n\n    /**\n     * In order to use this you should correctly override DataBufferRef.setDataRow(int) in your DataBufferRef implementation.\n     * Be careful: there will be single DataBufferRef while iterating. If you are not sure - DO NOT USE this iterator.\n     *\n     * @see SingleRefDataBufferIterator\n     */\n    @Override\n    public Iterator<T> singleRefIterator() {\n        return new SingleRefDataBufferIterator(this);\n    }\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/data/BitmapTeleporter.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.data;\n\nimport android.graphics.Bitmap;\nimport android.os.Parcel;\nimport android.os.ParcelFileDescriptor;\nimport android.util.Log;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport java.io.Closeable;\nimport java.io.DataInputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\n\n@SafeParcelable.Class\npublic class BitmapTeleporter extends AbstractSafeParcelable {\n\n    @Field(1)\n    public int versionCode;\n    @Field(2)\n    public ParcelFileDescriptor fileDescriptor;\n    @Field(3)\n    public int status;\n    public boolean isParceled;\n    public Bitmap targetBitmap;\n    public File targetDirectory;\n\n    public BitmapTeleporter() {\n    }\n\n    public BitmapTeleporter(int version, ParcelFileDescriptor parcelFileDescriptor, int status) {\n        this.versionCode = version;\n        this.fileDescriptor = parcelFileDescriptor;\n        this.status = status;\n        this.targetBitmap = null;\n        this.isParceled = false;\n    }\n\n    public BitmapTeleporter(Bitmap bitmap) {\n        this.versionCode = 1;\n        this.fileDescriptor = null;\n        this.status = 0;\n        this.targetBitmap = bitmap;\n        this.isParceled = true;\n    }\n\n    public final Bitmap createTargetBitmap() {\n        if (!this.isParceled) {\n            ParcelFileDescriptor parcelFileDescriptor = this.fileDescriptor;\n            if (parcelFileDescriptor == null) {\n                throw new NullPointerException(\"null reference\");\n            }\n            DataInputStream dataInputStream = new DataInputStream(new ParcelFileDescriptor.AutoCloseInputStream(parcelFileDescriptor));\n            try {\n                try {\n                    byte[] bArr = new byte[dataInputStream.readInt()];\n                    int readInt = dataInputStream.readInt();\n                    int readInt2 = dataInputStream.readInt();\n                    Bitmap.Config valueOf = Bitmap.Config.valueOf(dataInputStream.readUTF());\n                    dataInputStream.read(bArr);\n                    close(dataInputStream);\n                    ByteBuffer wrap = ByteBuffer.wrap(bArr);\n                    Bitmap createBitmap = Bitmap.createBitmap(readInt, readInt2, valueOf);\n                    createBitmap.copyPixelsFromBuffer(wrap);\n                    this.targetBitmap = createBitmap;\n                    this.isParceled = true;\n                } catch (IOException e) {\n                    throw new IllegalStateException(\"Could not read from parcel file descriptor\", e);\n                }\n            } catch (Throwable th) {\n                close(dataInputStream);\n                throw th;\n            }\n        }\n        return this.targetBitmap;\n    }\n\n    public final void setTargetDirectory(File file) {\n        if (file == null) {\n            throw new NullPointerException(\"Cannot set null temp directory\");\n        }\n        this.targetDirectory = file;\n    }\n\n    private static void close(Closeable closeable) {\n        try {\n            closeable.close();\n        } catch (IOException e) {\n            Log.w(\"BitmapTeleporter\", \"Could not close stream\", e);\n        }\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<BitmapTeleporter> CREATOR = findCreator(BitmapTeleporter.class);\n\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/data/DataBuffer.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2015 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.common.data;\n\nimport com.google.android.gms.common.api.Releasable;\n\nimport org.microg.gms.common.PublicApi;\n\nimport java.util.Iterator;\n\n/**\n * Interface for a buffer of typed data.\n */\npublic interface DataBuffer<T> extends Releasable, Iterable<T> {\n\n    /**\n     * Releases the data buffer, for use in try-with-resources.\n     * <p>\n     * Both close and release shall have identical semantics, and are idempotent.\n     */\n    void close();\n\n    /**\n     * Returns an element on specified position.\n     */\n    T get(int position);\n\n    int getCount();\n\n    /**\n     * @deprecated {@link #release()} is idempotent, and so is safe to call multiple times\n     */\n    @Deprecated\n    boolean isClosed();\n\n    @Override\n    Iterator<T> iterator();\n\n    /**\n     * Releases resources used by the buffer. This method is idempotent.\n     */\n    @Override\n    void release();\n\n    /**\n     * In order to use this one should correctly override setDataRow(int) in his DataBufferRef\n     * implementation. Be careful: there will be single DataBufferRef while iterating.\n     * If you are not sure - DO NOT USE this iterator.\n     */\n    Iterator<T> singleRefIterator();\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/data/DataBufferIterator.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.data;\n\nimport androidx.annotation.NonNull;\nimport org.microg.gms.common.Hide;\n\nimport java.util.Iterator;\nimport java.util.NoSuchElementException;\n\n@Hide\npublic class DataBufferIterator<T> implements Iterator<T> {\n    protected DataBuffer<T> dataBuffer;\n    protected int position = -1;\n\n    public DataBufferIterator(@NonNull DataBuffer<T> dataBuffer) {\n        this.dataBuffer = dataBuffer;\n    }\n\n    @Override\n    public T next() {\n        if (!hasNext()) {\n            throw new NoSuchElementException(\"Cannot advance the iterator beyond \" + position);\n        }\n        return dataBuffer.get(++position);\n    }\n\n    @Override\n    public void remove() {\n        throw new UnsupportedOperationException(\"Cannot remove elements from a DataBufferIterator\");\n    }\n\n    @Override\n    public boolean hasNext() {\n        return this.position < this.dataBuffer.getCount() - 1;\n    }\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/data/DataBufferRef.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.data;\n\nimport android.database.CharArrayBuffer;\nimport androidx.annotation.NonNull;\nimport org.microg.gms.common.Hide;\n\n@Hide\npublic abstract class DataBufferRef {\n    protected DataHolder dataHolder;\n    protected int dataRow;\n    private int windowIndex;\n\n    public DataBufferRef(DataHolder dataHolder, int dataRow) {\n        this.dataHolder = dataHolder;\n        setDataRow(dataRow);\n    }\n\n    protected void copyToBuffer(@NonNull String column, @NonNull CharArrayBuffer dataOut) {\n        dataHolder.copyToBuffer(column, dataRow, windowIndex, dataOut);\n    }\n\n    protected boolean getBoolean(@NonNull String column) {\n        return dataHolder.getBoolean(column, dataRow, windowIndex);\n    }\n\n    protected byte[] getByteArray(@NonNull String column) {\n        return dataHolder.getByteArray(column, dataRow, windowIndex);\n    }\n\n    protected double getDouble(@NonNull String column) {\n        return dataHolder.getDouble(column, dataRow, windowIndex);\n    }\n\n    protected float getFloat(@NonNull String column) {\n        return dataHolder.getFloat(column, dataRow, windowIndex);\n    }\n\n    protected int getInteger(@NonNull String column) {\n        return dataHolder.getInteger(column, dataRow, windowIndex);\n    }\n\n    protected long getLong(@NonNull String column) {\n        return dataHolder.getLong(column, dataRow, windowIndex);\n    }\n\n    protected String getString(@NonNull String column) {\n        return dataHolder.getString(column, dataRow, windowIndex);\n    }\n\n    protected boolean hasColumn(@NonNull String column) {\n        return dataHolder.hasColumn(column);\n    }\n\n    protected boolean hasNull(@NonNull String column) {\n        return dataHolder.hasNull(column, dataRow, windowIndex);\n    }\n\n    public boolean isDataValid() {\n        return !this.dataHolder.isClosed();\n    }\n\n    public void setDataRow(int dataRow) {\n        this.dataRow = dataRow;\n        this.windowIndex = dataHolder.getWindowIndex(dataRow);\n    }\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/data/DataHolder.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.common.data;\n\nimport android.annotation.SuppressLint;\nimport android.content.ContentValues;\nimport android.database.AbstractWindowedCursor;\nimport android.database.CharArrayBuffer;\nimport android.database.Cursor;\nimport android.database.CursorWindow;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.os.Parcel;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\nimport java.io.Closeable;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport static android.os.Build.VERSION.SDK_INT;\n\n/**\n * Class for accessing collections of data, organized into columns. This provides the backing\n * support for DataBuffer. Much like a cursor, the holder supports the notion of a current\n * position, and has methods for extracting various types of data from named columns.\n */\n@PublicApi(until = \"1\")\npublic class DataHolder extends AutoSafeParcelable implements Closeable {\n    @SafeParceled(1000)\n    private int versionCode = 1;\n\n    @SafeParceled(1)\n    private final String[] columns;\n\n    @SafeParceled(2)\n    private final CursorWindow[] windows;\n\n    @SafeParceled(3)\n    private final int statusCode;\n\n    @SafeParceled(4)\n    private final Bundle metadata;\n\n    private boolean closed = false;\n    private Map<String, Integer> columnIndices;\n    private int[] windowStartPositions;\n    private int count;\n\n    protected static final int FIELD_TYPE_NULL = 0;\n    protected static final int FIELD_TYPE_INTEGER = 1;\n    protected static final int FIELD_TYPE_FLOAT = 2;\n    protected static final int FIELD_TYPE_STRING = 3;\n    protected static final int FIELD_TYPE_BLOB = 4;\n\n    private DataHolder() {\n        columns = null;\n        windows = null;\n        statusCode = 0;\n        metadata = null;\n    }\n\n    /**\n     * Creates a data holder with the specified data.\n     *\n     * @param columns    The column names corresponding to the data in the given windows.\n     * @param windows    The {@link CursorWindow} instances holding the data.\n     * @param statusCode The status code of this {@link DataHolder}.\n     * @param metadata   The metadata associated with this {@link DataHolder} (may be null).\n     */\n    public DataHolder(String[] columns, CursorWindow[] windows, int statusCode, Bundle metadata) {\n        this.columns = columns;\n        this.windows = windows;\n        this.statusCode = statusCode;\n        this.metadata = metadata;\n        validateContents();\n    }\n\n    /**\n     * Creates a data holder wrapping the provided cursor, with provided status code and metadata.\n     *\n     * @param cursor     The cursor containing the data.\n     * @param statusCode The status code of this {@link DataHolder}.\n     * @param metadata   The metadata associated with this {@link DataHolder} (may be null).\n     */\n    public DataHolder(AbstractWindowedCursor cursor, int statusCode, Bundle metadata) {\n        this(cursor.getColumnNames(), createCursorWindows(cursor), statusCode, metadata);\n    }\n\n    /**\n     * Creates a data holder wrapping the provided cursor, with provided status code and metadata.\n     *\n     * @param cursor     The cursor containing the data.\n     * @param statusCode The status code of this {@link DataHolder}.\n     * @param metadata   The metadata associated with this {@link DataHolder} (may be null).\n     */\n    public DataHolder(Cursor cursor, int statusCode, Bundle metadata) {\n        this(cursor.getColumnNames(), createCursorWindows(cursor), statusCode, metadata);\n    }\n\n    /**\n     * Get a {@link DataHolder.Builder} to create a new {@link DataHolder} manually.\n     *\n     * @param columns      The array of column names that the object supports.\n     * @param uniqueColumn The non-null column name that must contain unique values. New rows added to the builder with the same value in this column will replace any older rows.\n     * @return {@link DataHolder.Builder} object to work with.\n     */\n    public static Builder builder(String[] columns, String uniqueColumn) {\n        return new Builder(columns, uniqueColumn);\n    }\n\n    /**\n     * Get a {@link DataHolder.Builder} to create a new {@link DataHolder} manually.\n     *\n     * @param columns The array of column names that the object supports.\n     * @return {@link DataHolder.Builder} object to work with.\n     */\n    public static Builder builder(String[] columns) {\n        return builder(columns, null);\n    }\n\n    /**\n     * @param statusCode The status code of this {@link DataHolder}.\n     * @param metadata   The metadata associated with this {@link DataHolder} (may be null).\n     * @return An empty {@link DataHolder} object with the given status and metadata.\n     */\n    public static DataHolder empty(int statusCode, Bundle metadata) {\n        return new DataHolder(new String[0], new CursorWindow[0], statusCode, metadata);\n    }\n\n    /**\n     * @param statusCode The status code of this {@link DataHolder}.\n     * @return An empty {@link DataHolder} object with the given status and null metadata.\n     */\n    public static DataHolder empty(int statusCode) {\n        return empty(statusCode, null);\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    @SuppressLint({\"NewApi\", \"ObsoleteSdkInt\"})\n    static int getCursorType(Cursor cursor, int i) {\n        if (SDK_INT >= 11) {\n            return cursor.getType(i);\n        }\n        if (cursor instanceof AbstractWindowedCursor) {\n            CursorWindow cursorWindow = ((AbstractWindowedCursor) cursor).getWindow();\n            int pos = cursor.getPosition();\n            int type = -1;\n            if (cursorWindow.isNull(pos, i)) {\n                type = FIELD_TYPE_NULL;\n            } else if (cursorWindow.isLong(pos, i)) {\n                type = FIELD_TYPE_INTEGER;\n            } else if (cursorWindow.isFloat(pos, i)) {\n                type = FIELD_TYPE_FLOAT;\n            } else if (cursorWindow.isString(pos, i)) {\n                type = FIELD_TYPE_STRING;\n            } else if (cursorWindow.isBlob(pos, i)) {\n                type = FIELD_TYPE_BLOB;\n            }\n\n            return type;\n        }\n        throw new RuntimeException(\"Unsupported cursor on this platform!\");\n    }\n\n    /**\n     * Closes the data holder, releasing all of its resources and making it completely invalid.\n     */\n    @Override\n    public void close() {\n        synchronized (this) {\n            if (!closed) {\n                closed = true;\n                for (CursorWindow window : windows) {\n                    window.close();\n                }\n            }\n        }\n    }\n\n    /**\n     * Copies the String content in the given column at the provided position into a {@link CharArrayBuffer}.\n     * This will throw an {@link IllegalArgumentException} if the column does not exist, the\n     * position is invalid, or the data holder has been closed.\n     *\n     * @param column      The column to retrieve.\n     * @param row         The row to retrieve the data from.\n     * @param windowIndex Index of the cursor window to extract the data from.\n     * @param dataOut     The {@link CharArrayBuffer} to copy into.\n     */\n    public void copyToBuffer(String column, int row, int windowIndex, CharArrayBuffer dataOut) {\n        throw new RuntimeException(\"Not yet available\");\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    private static CursorWindow[] createCursorWindows(Builder builder) {\n        if (builder.columns.length == 0) return new CursorWindow[0];\n        List<CursorWindow> windows = new ArrayList<CursorWindow>();\n        try {\n            CursorWindow current = null;\n            for (int rowIndex = 0; rowIndex < builder.rows.size(); rowIndex++) {\n                Map<String, Object> row = builder.rows.get(rowIndex);\n                if (current == null || !current.allocRow()) {\n                    current = new CursorWindow(false);\n                    current.setStartPosition(rowIndex);\n                    current.setNumColumns(builder.columns.length);\n                    windows.add(current);\n                    if (!current.allocRow()) {\n                        windows.remove(current);\n                        return windows.toArray(new CursorWindow[windows.size()]);\n                    }\n                }\n                for (int columnIndex = 0; columnIndex < builder.columns.length; columnIndex++) {\n                    Object val = row.get(builder.columns[columnIndex]);\n                    if (val == null) {\n                        current.putNull(rowIndex, columnIndex);\n                    } else if (val instanceof String) {\n                        current.putString((String) val, rowIndex, columnIndex);\n                    } else if (val instanceof Long) {\n                        current.putLong((Long) val, rowIndex, columnIndex);\n                    } else if (val instanceof Integer) {\n                        current.putLong((Integer) val, rowIndex, columnIndex);\n                    } else if (val instanceof Boolean) {\n                        if ((Boolean) val)\n                            current.putLong(1, rowIndex, columnIndex);\n                    } else if (val instanceof byte[]) {\n                        current.putBlob((byte[]) val, rowIndex, columnIndex);\n                    } else if (val instanceof Double) {\n                        current.putDouble((Double) val, rowIndex, columnIndex);\n                    } else if (val instanceof Float) {\n                        current.putDouble((Float) val, rowIndex, columnIndex);\n                    } else {\n                        throw new IllegalArgumentException(\"Unsupported object for column \" + columnIndex + \": \" + val);\n                    }\n                }\n            }\n        } catch (RuntimeException e) {\n            for (CursorWindow window : windows) {\n                window.close();\n            }\n            throw e;\n        }\n        return windows.toArray(new CursorWindow[windows.size()]);\n    }\n\n    private static CursorWindow[] createCursorWindows(Cursor cursor) {\n        if (cursor.getColumnCount() == 0) return new CursorWindow[0];\n        List<CursorWindow> windows = new ArrayList<CursorWindow>();\n        CursorWindow current = null;\n        int rowIndex = 0;\n        while (cursor.moveToNext()) {\n            if (current == null || !current.allocRow()) {\n                current = new CursorWindow(false);\n                current.setStartPosition(rowIndex);\n                current.setNumColumns(cursor.getColumnCount());\n                windows.add(current);\n                if (!current.allocRow()) {\n                    windows.remove(current);\n                    return windows.toArray(new CursorWindow[windows.size()]);\n                }\n            }\n            for (int i = 0; i < cursor.getColumnCount(); i++) {\n                switch (getCursorType(cursor, i)) {\n                    case FIELD_TYPE_NULL:\n                        current.putNull(rowIndex, i);\n                        break;\n                    case FIELD_TYPE_BLOB:\n                        current.putBlob(cursor.getBlob(i), rowIndex, i);\n                        break;\n                    case FIELD_TYPE_FLOAT:\n                        current.putDouble(cursor.getDouble(i), rowIndex, i);\n                        break;\n                    case FIELD_TYPE_INTEGER:\n                        current.putLong(cursor.getLong(i), rowIndex, i);\n                        break;\n                    case FIELD_TYPE_STRING:\n                        current.putString(cursor.getString(i), rowIndex, i);\n                        break;\n                }\n            }\n            rowIndex++;\n        }\n        cursor.close();\n        return windows.toArray(new CursorWindow[windows.size()]);\n    }\n\n    /**\n     * Retrieves the boolean value for a given column at the provided position.\n     * This will throw an {@link IllegalArgumentException} if the column does not exist, the\n     * position is invalid, or the data holder has been closed.\n     *\n     * @param column      The column to retrieve.\n     * @param row         The row to retrieve the data from.\n     * @param windowIndex Index of the cursor window to extract the data from.\n     * @return The boolean value in that column.\n     */\n    public boolean getBoolean(String column, int row, int windowIndex) {\n        return windows[windowIndex].getLong(row, columnIndices.get(column)) == 1;\n    }\n\n    /**\n     * Retrieves the byte array value for a given column at the provided position.\n     * This will throw an {@link IllegalArgumentException} if the column does not exist, the\n     * position is invalid, or the data holder has been closed.\n     *\n     * @param column      The column to retrieve.\n     * @param row         The row to retrieve the data from.\n     * @param windowIndex Index of the cursor window to extract the data from.\n     * @return The byte array value in that column.\n     */\n    public byte[] getByteArray(String column, int row, int windowIndex) {\n        return windows[windowIndex].getBlob(row, columnIndices.get(column));\n    }\n\n    /**\n     * Gets the number of rows in the data holder.\n     *\n     * @return the number of rows in the data holder.\n     */\n    public int getCount() {\n        return count;\n    }\n\n    public double getDouble(String column, int row, int windowIndex) {\n        return windows[windowIndex].getDouble(row, columnIndices.get(column));\n    }\n\n    public float getFloat(String column, int row, int windowIndex) {\n        return windows[windowIndex].getFloat(row, columnIndices.get(column));\n    }\n\n    /**\n     * Retrieves the integer value for a given column at the provided position.\n     * This will throw an {@link IllegalArgumentException} if the column does not exist, the\n     * position is invalid, or the data holder has been closed.\n     *\n     * @param column      The column to retrieve.\n     * @param row         The row to retrieve the data from.\n     * @param windowIndex Index of the cursor window to extract the data from.\n     * @return The integer value in that column.\n     */\n    public int getInteger(String column, int row, int windowIndex) {\n        return windows[windowIndex].getInt(row, columnIndices.get(column));\n    }\n\n    /**\n     * Retrieves the long value for a given column at the provided position.\n     * This will throw an {@link IllegalArgumentException} if the column does not exist, the\n     * position is invalid, or the data holder has been closed.\n     *\n     * @param column      The column to retrieve.\n     * @param row         The row to retrieve the data from.\n     * @param windowIndex Index of the cursor window to extract the data from.\n     * @return The long value in that column.\n     */\n    public long getLong(String column, int row, int windowIndex) {\n        return windows[windowIndex].getLong(row, columnIndices.get(column));\n    }\n\n    public int getStatusCode() {\n        return statusCode;\n    }\n\n    /**\n     * Retrieves the string value for a given column at the provided position.\n     * This will throw an {@link IllegalArgumentException} if the column does not exist, the\n     * position is invalid, or the data holder has been closed.\n     *\n     * @param column      The column to retrieve.\n     * @param row         The row to retrieve the data from.\n     * @param windowIndex Index of the cursor window to extract the data from.\n     * @return The string value in that column.\n     */\n    public String getString(String column, int row, int windowIndex) {\n        return windows[windowIndex].getString(row, columnIndices.get(column));\n    }\n\n    public boolean hasColumn(String column) {\n        return columnIndices.values().contains(column);\n    }\n\n    /**\n     * Returns whether the given column at the provided position contains null.\n     * This will throw an {@link IllegalArgumentException} if the column does not exist, the\n     * position is invalid, or the data holder has been closed.\n     *\n     * @param column      The column to retrieve.\n     * @param row         The row to retrieve the data from.\n     * @param windowIndex Index of the cursor window to extract the data from.\n     * @return Whether the column value is null at this position.\n     */\n    public boolean hasNull(String column, int row, int windowIndex) {\n        return windows[windowIndex].isNull(row, columnIndices.get(column));\n    }\n\n    public boolean isClosed() {\n        synchronized (this) {\n            return closed;\n        }\n    }\n\n    /**\n     * Retrieves the column data at the provided position as a URI if possible, checking for null values.\n     * This will throw an {@link IllegalArgumentException} if the column does not exist, the\n     * position is invalid, or the data holder has been closed.\n     *\n     * @param column      The column to retrieve.\n     * @param row         The row to retrieve the data from.\n     * @param windowIndex Index of the cursor window to extract the data from.\n     * @return The column data as a URI, or null if not present.\n     */\n    public Uri parseUri(String column, int row, int windowIndex) {\n        String string = getString(column, row, windowIndex);\n        if (string != null) return Uri.parse(string);\n        return null;\n    }\n\n    @Override\n    public String toString() {\n        return \"DataHolder{\" +\n                \"columns=\" + Arrays.toString(columns) +\n                \", windows=\" + Arrays.toString(windows) +\n                \", statusCode=\" + statusCode +\n                \", metadata=\" + metadata +\n                '}';\n    }\n\n    public void validateContents() {\n        columnIndices = new HashMap<String, Integer>();\n        for (int i = 0; i < columns.length; i++) {\n            columnIndices.put(columns[i], i);\n        }\n        windowStartPositions = new int[windows.length];\n        this.count = 0;\n        for (int windowIndex = 0; windowIndex < windows.length; windowIndex++) {\n            this.windowStartPositions[windowIndex] = this.count;\n            this.count += this.windows[windowIndex].getNumRows() - (this.count - windows[windowIndex].getStartPosition());\n        }\n    }\n\n    public int getWindowIndex(int row) {\n        if (row < 0 || row >= count) throw new IllegalArgumentException();\n        int windowIndex = 0;\n        for (; windowIndex < windowStartPositions.length; windowIndex++) {\n            if (row < windowStartPositions[windowIndex]) break;\n        }\n        return windowIndex-1;\n    }\n\n    /**\n     * Helper class to build {@link DataHolder} instances containing arbitrary data.\n     * <p/>\n     * Note that the constructor is private; use DataHolder.builder() to create instances of this class.\n     */\n    public static class Builder {\n        private final String[] columns;\n        private final ArrayList<Map<String, Object>> rows;\n        private final String uniqueColumn;\n        private final Map<Object, Integer> uniqueIndizes;\n\n        private Builder(String[] columns, String uniqueColumn) {\n            this.columns = columns;\n            this.rows = new ArrayList<Map<String, Object>>();\n            this.uniqueColumn = uniqueColumn;\n            this.uniqueIndizes = new HashMap<Object, Integer>();\n        }\n\n        /**\n         * Instantiate an {@link DataHolder} from this {@link DataHolder.Builder} with the given status code and metadata.\n         *\n         * @param statusCode The status code of this {@link DataHolder}.\n         * @param metadata   The metadata associated with this {@link DataHolder} (may be null).\n         * @return {@link DataHolder} representation of this object.\n         */\n        public DataHolder build(int statusCode, Bundle metadata) {\n            return new DataHolder(columns, createCursorWindows(this), statusCode, metadata);\n        }\n\n        /**\n         * Instantiate an {@link DataHolder} from this {@link DataHolder.Builder} with the given status code and null metadata.\n         *\n         * @param statusCode The status code of this {@link DataHolder}.\n         * @return {@link DataHolder} representation of this object.\n         */\n        public DataHolder build(int statusCode) {\n            return build(statusCode, null);\n        }\n\n        /**\n         * @return The number of rows that the resulting DataHolder will contain.\n         */\n        public int getCount() {\n            return rows.size();\n        }\n\n        /**\n         * Sort the rows in this builder based on the standard data type comparisons for the value in the provided column.\n         * Calling this multiple times with the same column will not change the sort order of the builder.\n         * Note that any data which is added after this call will not be sorted.\n         *\n         * @param sortColumn The column to sort the rows in this builder by.\n         * @return {@link DataHolder.Builder} to continue construction.\n         */\n        public Builder sort(String sortColumn) {\n            throw new RuntimeException(\"Not yet implemented\");\n        }\n\n        /**\n         * Add a new row of data to the {@link DataHolder} this {@link DataHolder.Builder} will create. Note that the data must contain an entry for all columns\n         * <p/>\n         * Currently the only supported value types that are supported are String, Long, and Boolean (Integer is also accepted and will be stored as a Long).\n         *\n         * @param values {@link ContentValues} containing row data.\n         * @return {@link DataHolder.Builder} to continue construction.\n         */\n        public Builder withRow(ContentValues values) {\n            HashMap<String, Object> row = new HashMap<String, Object>();\n            for (Map.Entry<String, Object> entry : values.valueSet()) {\n                row.put(entry.getKey(), entry.getValue());\n            }\n            return withRow(row);\n        }\n\n        /**\n         * Add a new row of data to the {@link DataHolder} this {@link DataHolder.Builder} will create. Note that the data must contain an entry for all columns\n         * <p/>\n         * Currently the only supported value types that are supported are String, Long, and Boolean (Integer is also accepted and will be stored as a Long).\n         *\n         * @param row Map containing row data.\n         * @return {@link DataHolder.Builder} to continue construction.\n         */\n        public Builder withRow(HashMap<String, Object> row) {\n            if (uniqueColumn != null) {\n                Object val = row.get(uniqueColumn);\n                if (val != null) {\n                    Integer old = uniqueIndizes.get(val);\n                    if (old != null) {\n                        rows.set(old, row);\n                        return this;\n                    } else {\n                        uniqueIndizes.put(val, rows.size());\n                    }\n                }\n            }\n            rows.add(row);\n            return this;\n        }\n    }\n\n    public static final Creator<DataHolder> CREATOR = new AutoCreator<DataHolder>(DataHolder.class) {\n        @Override\n        public DataHolder createFromParcel(Parcel parcel) {\n            DataHolder res = super.createFromParcel(parcel);\n            res.validateContents();\n            return res;\n        }\n    };\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/data/Freezable.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.common.data;\n\npublic interface Freezable<T> {\n    /**\n     * Freeze a volatile representation into an immutable representation. Objects returned from\n     * this call are safe to cache.\n     * <p/>\n     * Note that the output of {@link #freeze} may not be identical to the parent object, but\n     * should be equal.\n     *\n     * @return A concrete implementation of the data object.\n     */\n    T freeze();\n\n    /**\n     * Check to see if this object is valid for use. If the object is still volatile, this method\n     * will indicate whether or not the object can be safely used.\n     * The output of a call to {@link #freeze()} will always be valid.\n     *\n     * @return whether or not the object is valid for use.\n     */\n    boolean isDataValid();\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/data/SingleRefDataBufferIterator.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.data;\n\nimport androidx.annotation.NonNull;\nimport org.microg.gms.common.Hide;\n\nimport java.util.NoSuchElementException;\n\n@Hide\npublic class SingleRefDataBufferIterator<T> extends DataBufferIterator<T> {\n    private T element;\n\n    public SingleRefDataBufferIterator(@NonNull DataBuffer<T> dataBuffer) {\n        super(dataBuffer);\n    }\n\n    @Override\n    public T next() {\n        if (!hasNext()) {\n            throw new NoSuchElementException(\"Cannot advance the iterator beyond \" + position);\n        }\n        ++position;\n        if (position == 0) {\n            element = dataBuffer.get(position);\n            if (!(element instanceof DataBufferRef)) {\n                throw new IllegalStateException(\"DataBuffer reference of type \" + element.getClass() + \" is not movable\");\n            }\n        } else {\n            ((DataBufferRef) element).setDataRow(position);\n        }\n        return element;\n    }\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/data/package-info.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n/**\n * Contains classes for accessing data from Google Play services.\n */\npackage com.google.android.gms.common.data;\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/images/ImageManager.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.common.images;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.os.Handler;\nimport android.os.Looper;\nimport android.util.Log;\nimport android.widget.ImageView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.WorkerThread;\nimport androidx.collection.LruCache;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.HttpURLConnection;\nimport java.net.URL;\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\n/**\n * This class is used to load images from the network and handles local caching for you.\n */\npublic class ImageManager {\n    /**\n     * Returns a new ImageManager for loading images from the network.\n     *\n     * @param context The context used by the ImageManager.\n     * @return A new ImageManager.\n     */\n    public static ImageManager create(Context context) {\n        if (INSTANCE == null) {\n            synchronized (ImageManager.class) {\n                if (INSTANCE == null) {\n                    INSTANCE = new ImageManager(context);\n                }\n            }\n        }\n        return INSTANCE;\n    }\n\n    public static final String TAG = \"ImageManager\";\n    private static volatile ImageManager INSTANCE;\n    private final LruCache<String, Bitmap> memoryCache;\n    private final ExecutorService executorService;\n    private final Handler handler;\n    private final Context context;\n\n    private ImageManager(Context context) {\n        this.context = context.getApplicationContext();\n        this.handler = new Handler(Looper.getMainLooper());\n        this.executorService = Executors.newFixedThreadPool(4);\n\n        final int cacheSize = (int) (Runtime.getRuntime().maxMemory() / 1024 / 8);\n        this.memoryCache = new LruCache<String, Bitmap>(cacheSize) {\n            @Override\n            protected int sizeOf(@NonNull String key, @NonNull Bitmap bitmap) {\n                return bitmap.getByteCount() / 1024;\n            }\n        };\n    }\n\n    /**\n     * Compress Bitmap\n     */\n    public byte[] compressBitmap(Bitmap bitmap, Bitmap.CompressFormat format, int quality) {\n        Log.d(TAG, \"compressBitmap width: \" + bitmap.getWidth() + \" height:\" + bitmap.getHeight());\n        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();\n        bitmap.compress(format, quality, byteArrayOutputStream);\n        byte[] bitmapBytes = byteArrayOutputStream.toByteArray();\n        bitmap = BitmapFactory.decodeByteArray(bitmapBytes, 0, bitmapBytes.length);\n        Log.d(TAG, \"compressBitmap compress width: \" + bitmap.getWidth() + \" height:\" + bitmap.getHeight());\n        return bitmapBytes;\n    }\n\n    public byte[] compressBitmap(Bitmap original, int newWidth, int newHeight) {\n        Log.d(TAG, \"compressBitmap width: \" + original.getWidth() + \" height:\" + original.getHeight());\n        Bitmap target = Bitmap.createScaledBitmap(original, newWidth, newHeight, true);\n        Log.d(TAG, \"compressBitmap target width: \" + target.getWidth() + \" height:\" + target.getHeight());\n        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();\n        target.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream);\n        return byteArrayOutputStream.toByteArray();\n    }\n\n    public void loadImage(final String url, final ImageView imageView) {\n        if (imageView == null) {\n            Log.d(TAG, \"loadImage: imageView is null\");\n            return;\n        }\n        final Bitmap cachedBitmap = getBitmapFromCache(url);\n        if (cachedBitmap != null) {\n            Log.d(TAG, \"loadImage from cached\");\n            imageView.setImageBitmap(cachedBitmap);\n        } else {\n            Log.d(TAG, \"loadImage from net\");\n            imageView.setTag(url);\n            executorService.submit(() -> {\n                final Bitmap bitmap = downloadBitmap(url);\n                if (bitmap != null) {\n                    addBitmapToCache(url, bitmap);\n                    if (imageView.getTag().equals(url)) {\n                        handler.post(() -> imageView.setImageBitmap(bitmap));\n                    }\n                }\n            });\n        }\n    }\n\n    private Bitmap getBitmapFromCache(String key) {\n        Bitmap bitmap = memoryCache.get(key);\n        if (bitmap == null) {\n            bitmap = getBitmapFromDiskCache(key);\n        }\n        return bitmap;\n    }\n\n    private void addBitmapToCache(String key, Bitmap bitmap) {\n        if (getBitmapFromCache(key) == null) {\n            memoryCache.put(key, bitmap);\n            addBitmapToDiskCache(key, bitmap);\n        }\n    }\n\n    private Bitmap getBitmapFromDiskCache(String key) {\n        File file = getDiskCacheFile(key);\n        if (file.exists()) {\n            return BitmapFactory.decodeFile(file.getAbsolutePath());\n        }\n        return null;\n    }\n\n    private void addBitmapToDiskCache(String key, Bitmap bitmap) {\n        File file = getDiskCacheFile(key);\n        try (FileOutputStream outputStream = new FileOutputStream(file)) {\n            bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);\n        } catch (IOException e) {\n            Log.e(TAG, \"addBitmapToDiskCache: \", e);\n        }\n    }\n\n    private File getDiskCacheFile(String key) {\n        File cacheDir = context.getCacheDir();\n        return new File(cacheDir, md5(key));\n    }\n\n    private String md5(String s) {\n        try {\n            MessageDigest digest = MessageDigest.getInstance(\"MD5\");\n            digest.update(s.getBytes());\n            byte[] messageDigest = digest.digest();\n            StringBuilder hexString = new StringBuilder();\n            for (byte b : messageDigest) {\n                StringBuilder h = new StringBuilder(Integer.toHexString(0xFF & b));\n                while (h.length() < 2) h.insert(0, \"0\");\n                hexString.append(h);\n            }\n            return hexString.toString();\n        } catch (NoSuchAlgorithmException e) {\n            Log.e(TAG, \"md5: \", e);\n        }\n        return \"\";\n    }\n\n    @WorkerThread\n    private Bitmap downloadBitmap(String url) {\n        HttpURLConnection connection = null;\n        try {\n            connection = (HttpURLConnection) new URL(url).openConnection();\n            connection.connect();\n            if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {\n                InputStream inputStream = connection.getInputStream();\n                return BitmapFactory.decodeStream(inputStream);\n            }\n        } catch (IOException e) {\n            Log.d(TAG, \"downloadBitmap: \", e);\n        } finally {\n            if (connection != null) {\n                connection.disconnect();\n            }\n        }\n        return null;\n    }\n\n\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/images/Size.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.common.images;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Immutable class for describing width and height dimensions in pixels.\n */\n@PublicApi\npublic class Size {\n    private int width;\n    private int height;\n\n    /**\n     * Create a new immutable Size instance.\n     *\n     * @param width  The width of the size, in pixels\n     * @param height The height of the size, in pixels\n     */\n    public Size(int width, int height) {\n        this.width = width;\n        this.height = height;\n    }\n\n    /**\n     * Check if this size is equal to another size.\n     * <p>\n     * Two sizes are equal if and only if both their widths and heights are equal.\n     * <p>\n     * A size object is never equal to any other type of object.\n     *\n     * @return {@code true} if the objects were equal, {@code false} otherwise\n     */\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof Size)) return false;\n\n        Size size = (Size) o;\n\n        if (width != size.width) return false;\n        return height == size.height;\n    }\n\n    /**\n     * Get the height of the size (in pixels).\n     *\n     * @return height\n     */\n    public int getHeight() {\n        return height;\n    }\n\n    /**\n     * Get the width of the size (in pixels).\n     *\n     * @return width\n     */\n    public int getWidth() {\n        return width;\n    }\n\n    @Override\n    public int hashCode() {\n        int result = width;\n        result = 31 * result + height;\n        return result;\n    }\n\n    /**\n     * Parses the specified string as a size value.\n     * <p>\n     * The ASCII characters {@code \\}{@code u002a} ('*') and {@code \\}{@code u0078} ('x') are recognized as separators between the width and height.\n     * <p>\n     * For any {@code Size s}: {@code Size.parseSize(s.toString()).equals(s)}. However, the method also handles sizes expressed in the following forms:\n     * <p>\n     * \"width{@code x}height\" or \"width{@code *}height\" => new Size(width, height), where width and height are string integers potentially containing a sign, such as \"-10\", \"+7\" or \"5\".\n     *\n     * @param string the string representation of a size value.\n     * @return the size value represented by {@code string}.\n     * @throws NumberFormatException if {@code string} cannot be parsed as a size value.\n     * @throws NullPointerException  if {@code string} was null\n     */\n    public static Size parseSize(String string) {\n        if (string == null) throw new NullPointerException(\"string must not be null\");\n        int split = string.indexOf('*');\n        if (split < 0) split = string.indexOf('x');\n        if (split < 0) throw new NumberFormatException(\"Invalid Size: \\\"\" + string + \"\\\"\");\n        return new Size(Integer.parseInt(string.substring(0, split)), Integer.parseInt(string.substring(split + 1)));\n    }\n\n    /**\n     * Return the size represented as a string with the format {@code \"WxH\"}\n     * @return string representation of the size\n     */\n    @Override\n    public String toString() {\n        return width + \"x\" + height;\n    }\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/images/WebImage.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2015 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.common.images;\n\nimport java.util.Locale;\n\nimport android.net.Uri;\n\nimport org.microg.gms.common.Hide;\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\n/**\n * A class that represents an image that is located on a web server.\n */\npublic class WebImage extends AutoSafeParcelable {\n    public static final Creator<WebImage> CREATOR = new AutoCreator<WebImage>(WebImage.class);\n\n    @Field(1)\n    private int versionCode = 1;\n\n    @Field(2)\n    private final Uri url;\n\n    @Field(3)\n    private final int width;\n\n    @Field(4)\n    private final int height;\n\n    @Hide\n    private WebImage() {\n        this.url = null;\n        this.width = 0;\n        this.height = 0;\n    }\n\n    /**\n     * Constructs a new {@link WebImage} with the given URL.\n     *\n     * @param url The URL of the image.\n     * @throws IllegalArgumentException If the URL is null or empty.\n     */\n    public WebImage(Uri url) {\n        this(url, 0, 0);\n    }\n\n    /**\n     * Constructs a new {@link WebImage} with the given URL and dimensions.\n     *\n     * @param url    The URL of the image.\n     * @param width  The width of the image, in pixels.\n     * @param height The height of the image, in pixels.\n     * @throws IllegalArgumentException If the URL is null or empty, or the dimensions are invalid.\n     */\n    public WebImage(Uri url, int width, int height) {\n        if (url == null) throw new IllegalArgumentException(\"url cannot be null\");\n        if (width < 0 || height < 0) throw new IllegalArgumentException(\"width and height must not be negative\");\n        this.url = url;\n        this.width = width;\n        this.height = height;\n    }\n\n    /**\n     * Gets the image height, in pixels.\n     */\n    public int getHeight() {\n        return height;\n    }\n\n    /**\n     * Gets the image URL.\n     */\n    public Uri getUrl() {\n        return url;\n    }\n\n    /**\n     * Gets the image width, in pixels.\n     */\n    public int getWidth() {\n        return width;\n    }\n\n    /**\n     * Returns a string representation of this object.\n     */\n    public String toString() {\n        return String.format(Locale.getDefault(), \"Image %dx%d %s\", Integer.valueOf(width), Integer.valueOf(height), url.toString());\n    }\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/images/package-info.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n/**\n * Contains classes for loading images from Google Play services.\n */\npackage com.google.android.gms.common.images;\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/internal/ApiExceptionUtil.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.internal;\n\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.api.ApiException;\nimport com.google.android.gms.common.api.ResolvableApiException;\nimport com.google.android.gms.common.api.Status;\nimport org.microg.gms.common.Hide;\n\n@Hide\npublic class ApiExceptionUtil {\n    @NonNull\n    public static ApiException fromStatus(@NonNull Status status) {\n        return status.hasResolution() ? new ResolvableApiException(status) : new ApiException(status);\n    }\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/internal/AuthAccountRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class AuthAccountRequest extends AutoSafeParcelable {\n    public static final Creator<AuthAccountRequest> CREATOR = new AutoCreator<>(AuthAccountRequest.class);\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/internal/ClientIdentity.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.internal;\n\nimport androidx.annotation.NonNull;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\nimport java.util.Objects;\n\npublic class ClientIdentity extends AutoSafeParcelable {\n    @Field(1)\n    public int uid;\n    @Field(2)\n    public String packageName;\n\n    @Override\n    public int hashCode() {\n        return uid;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return uid + \":\" + packageName;\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        ClientIdentity that = (ClientIdentity) o;\n        return uid == that.uid && Objects.equals(packageName, that.packageName);\n    }\n\n    public static final Creator<ClientIdentity> CREATOR = new AutoCreator<ClientIdentity>(ClientIdentity.class);\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/internal/ClientSettings.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.internal;\n\nimport android.accounts.Account;\nimport android.content.Context;\nimport android.view.View;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.Scope;\nimport com.google.android.gms.signin.SignInOptions;\nimport org.microg.gms.auth.AuthConstants;\nimport org.microg.gms.common.Hide;\n\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\n\n@Hide\npublic class ClientSettings {\n    @Nullable\n    private final Account account;\n    @NonNull\n    private final Set<Scope> requiredScopes;\n    @NonNull\n    private final Set<Scope> allRequestedScopes;\n    @NonNull\n    private final Map<Api<?>, Set<Scope>> scopesForOptionalApi;\n    private final int gravityForPopups;\n    @Nullable\n    private final View viewForPopups;\n    @NonNull\n    private final String realClientPackageName;\n    @Nullable\n    private final String contextClassName;\n    @NonNull\n    private final SignInOptions signInOptions;\n    private Integer sessionId;\n\n    public ClientSettings(@Nullable Account account, @NonNull Set<Scope> requiredScopes, @NonNull Map<Api<?>, Set<Scope>> scopesForOptionalApi, int gravityForPopups, @Nullable View viewForPopups, @NonNull String realClientPackageName, @NonNull String contextClassName, @NonNull SignInOptions signInOptions) {\n        this.account = account;\n        this.requiredScopes = requiredScopes;\n        this.scopesForOptionalApi = scopesForOptionalApi;\n        this.gravityForPopups = gravityForPopups;\n        this.viewForPopups = viewForPopups;\n        this.realClientPackageName = realClientPackageName;\n        this.contextClassName = contextClassName;\n        this.signInOptions = signInOptions;\n\n        allRequestedScopes = new HashSet<>(requiredScopes);\n        for (Set<Scope> scopeSet : scopesForOptionalApi.values()) {\n            allRequestedScopes.addAll(scopeSet);\n        }\n    }\n\n    @NonNull\n    public static ClientSettings createDefault(Context context) {\n        return new GoogleApiClient.Builder(context).getClientSettings();\n    }\n\n    @Nullable\n    public Account getAccount() {\n        return account;\n    }\n\n    @Deprecated\n    @Nullable\n    public String getAccountName() {\n        if (account == null) return null;\n        return account.name;\n    }\n\n    @NonNull\n    public Account getAccountOrDefault() {\n        if (account == null) return new Account(GoogleApiClient.DEFAULT_ACCOUNT, AuthConstants.DEFAULT_ACCOUNT_TYPE);\n        return account;\n    }\n\n    @NonNull\n    public Set<Scope> getAllRequestedScopes() {\n        return allRequestedScopes;\n    }\n\n    @NonNull\n    public Set<Scope> getApplicableScopes(@NonNull Api<?> api) {\n        Set<Scope> scopes = new HashSet<>(requiredScopes);\n        Set<Scope> apiScopes = scopesForOptionalApi.get(api);\n        if (apiScopes != null) scopes.addAll(apiScopes);\n        return scopes;\n    }\n\n    public int getGravityForPopups() {\n        return gravityForPopups;\n    }\n\n    @NonNull\n    public String getRealClientPackageName() {\n        return realClientPackageName;\n    }\n\n    @NonNull\n    public Set<Scope> getRequiredScopes() {\n        return requiredScopes;\n    }\n\n    @Nullable\n    public View getViewForPopups() {\n        return viewForPopups;\n    }\n\n    @NonNull\n    public Map<Api<?>, Set<Scope>> getScopesForOptionalApi() {\n        return scopesForOptionalApi;\n    }\n\n    @Nullable\n    public String getContextClassName() {\n        return contextClassName;\n    }\n\n    @NonNull\n    public SignInOptions getSignInOptions() {\n        return signInOptions;\n    }\n\n    @Nullable\n    public Integer getSessionId() {\n        return sessionId;\n    }\n\n    public void setSessionId(@NonNull Integer sessionId) {\n        this.sessionId = sessionId;\n    }\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/internal/MethodInvocation.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.internal;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class MethodInvocation extends AbstractSafeParcelable {\n\n    @Field(1)\n    final int methodKey;\n    @Field(2)\n    final int resultStatusCode;\n    @Field(3)\n    final int connectionResultStatusCode;\n    @Field(4)\n    final long startTimeMillis;\n    @Field(5)\n    final long endTimeMillis;\n    @Field(6)\n    @Nullable\n    final String callingModuleId;\n    @Field(7)\n    @Nullable\n    final String callingEntryPoint;\n    @Field(8)\n    final int serviceId;\n    @Field(value = 9, defaultValue = \"-1\")\n    final int latencyMillis;\n\n    @Constructor\n    public MethodInvocation(@Param(1) int methodKey, @Param(2) int resultStatusCode, @Param(3) int connectionResultStatusCode, @Param(4) long startTimeMillis, @Param(5) long endTimeMillis, @Param(6) @Nullable String callingModuleId, @Param(7) @Nullable String callingEntryPoint, @Param(8) int serviceId, @Param(9) int latencyMillis) {\n        this.methodKey = methodKey;\n        this.resultStatusCode = resultStatusCode;\n        this.connectionResultStatusCode = connectionResultStatusCode;\n        this.startTimeMillis = startTimeMillis;\n        this.endTimeMillis = endTimeMillis;\n        this.callingModuleId = callingModuleId;\n        this.callingEntryPoint = callingEntryPoint;\n        this.serviceId = serviceId;\n        this.latencyMillis = latencyMillis;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"MethodInvocation\")\n                .field(\"methodKey\", methodKey)\n                .field(\"resultStatusCode\", resultStatusCode)\n                .field(\"connectionResultStatusCode\", connectionResultStatusCode)\n                .field(\"startTimeMillis\", startTimeMillis)\n                .field(\"endTimeMillis\", endTimeMillis)\n                .field(\"callingModuleId\", callingModuleId)\n                .field(\"callingEntryPoint\", callingEntryPoint)\n                .field(\"serviceId\", serviceId)\n                .field(\"latencyMillis\", latencyMillis)\n                .end();\n    }\n\n    public static SafeParcelableCreatorAndWriter<MethodInvocation> CREATOR = findCreator(MethodInvocation.class);\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n}"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/internal/PendingResultUtil.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.internal;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.api.PendingResult;\nimport com.google.android.gms.common.api.Response;\nimport com.google.android.gms.common.api.Result;\nimport com.google.android.gms.tasks.Task;\nimport com.google.android.gms.tasks.TaskCompletionSource;\nimport org.microg.gms.common.Hide;\n\nimport java.util.concurrent.TimeUnit;\n\n@Hide\npublic class PendingResultUtil {\n    public interface ResultConverter<R extends Result, T> {\n        @Nullable\n        T convert(@NonNull R r);\n    }\n\n    @NonNull\n    public static <R extends Result, T> Task<T> toTask(@NonNull PendingResult<R> pendingResult, @NonNull ResultConverter<R, T> resultConverter) {\n        TaskCompletionSource<T> taskCompletionSource = new TaskCompletionSource<>();\n        pendingResult.addStatusListener((status) -> {\n            if (!status.isSuccess()) {\n                taskCompletionSource.setException(ApiExceptionUtil.fromStatus(status));\n            } else {\n                taskCompletionSource.setResult(resultConverter.convert(pendingResult.await(0, TimeUnit.MILLISECONDS)));\n            }\n        });\n        return taskCompletionSource.getTask();\n    }\n\n    @NonNull\n    public static <R extends Result, T extends Response<R>> Task<T> toResponseTask(@NonNull PendingResult<R> pendingResult, @NonNull T t) {\n        return toTask(pendingResult, (result) -> {\n            t.setResult(result);\n            return t;\n        });\n    }\n\n    @NonNull\n    public static <R extends Result> Task<Void> toVoidTask(@NonNull PendingResult<R> pendingResult) {\n        return toTask(pendingResult, (result) -> null);\n    }\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/internal/ResolveAccountRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.internal;\n\nimport android.accounts.Account;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.auth.api.signin.GoogleSignInAccount;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.utils.ToStringHelper;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n@Hide\npublic class ResolveAccountRequest extends AutoSafeParcelable {\n    @Field(1)\n    private int versionCode = 2;\n    @Field(2)\n    public Account account;\n    @Field(3)\n    public int sessionId;\n    @Field(4)\n    @Nullable\n    public GoogleSignInAccount signInAccountHint;\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"ResolveAccountRequest\")\n                .field(\"account\", account)\n                .field(\"sessionId\", sessionId)\n                .field(\"signInAccountHint\", signInAccountHint)\n                .end();\n    }\n\n    public static final Creator<ResolveAccountRequest> CREATOR = new AutoCreator<>(ResolveAccountRequest.class);\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/internal/ResolveAccountResponse.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.internal;\n\nimport android.os.IBinder;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.ConnectionResult;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.utils.ToStringHelper;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n@Hide\npublic class ResolveAccountResponse extends AutoSafeParcelable {\n    @Field(1)\n    private int versionCode = 2;\n    @Field(2)\n    public IBinder accountAccessor;\n    @Field(3)\n    public ConnectionResult connectionResult;\n    @Field(4)\n    public boolean saveDefaultAccount;\n    @Field(5)\n    public boolean fromCrossClientAuth;\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"ResolveAccountResponse\")\n                .field(\"connectionResult\", connectionResult)\n                .field(\"saveDefaultAccount\", saveDefaultAccount)\n                .field(\"fromCrossClientAuth\", fromCrossClientAuth)\n                .end();\n    }\n\n    public static final Creator<ResolveAccountResponse> CREATOR = new AutoCreator<>(ResolveAccountResponse.class);\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/internal/ResultTransform.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.common.internal;\n\nimport android.os.Handler;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.WorkerThread;\nimport com.google.android.gms.common.api.CommonStatusCodes;\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.PendingResult;\nimport com.google.android.gms.common.api.Result;\nimport com.google.android.gms.common.api.Status;\n\n/**\n * Transforms a {@link Result} by making a subsequent API call.\n *\n * @see PendingResult#then(ResultTransform)\n */\npublic abstract class ResultTransform<R extends Result, S extends Result> {\n\n    /**\n     * Creates a failed result with the given {@link Status}. In the event of an error during {@link #onSuccess(Result)}, call this method and return the failed result.\n     * <p>\n     * Note: the {@link PendingResult} generated by this method must be returned directly from {@link #onSuccess(Result)}. It is an error to call any methods on this\n     * {@link PendingResult}.\n     */\n    @NonNull\n    public final PendingResult<S> createFailedResult(@NonNull Status status) {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Called when the PendingResult to be transformed returns a failure. Default implementation simply propagates the failure, but subclasses\n     * may override for custom failure handling. This method is called on the main thread, unless overridden by {@link GoogleApiClient.Builder#setHandler(Handler)}.\n     *\n     * @param status The status of the failure.\n     * @return The status of the result of the transformation. Must not be success or null.\n     */\n    @NonNull\n    public Status onFailure(@NonNull Status status) {\n        return status;\n    }\n\n    /**\n     * Transforms the result of a successful API call. This method is called on a background thread and should not access UI elements.\n     *\n     * @param result The successful result to be transformed. Never null. If this result is it will be automatically\n     *               released after this transform is applied; it is not necessary to release the result inside\n     *               onSuccess. It is an error to set callbacks on this result. Any callbacks set on this result will be\n     *               overridden and will not be called.\n     * @return The result of the transformation. Normally the result of another API call. To shortcut\n     * execution and directly yield a failure, return either:\n     * <ul>\n     *     <li>{@code null}, which is translated into a {@link Status} with code {@link CommonStatusCodes#ERROR}; or</li>\n     *     <li>a specific failure created using {@link #createFailedResult(Status)}.</li>\n     * </ul>\n     */\n    @Nullable\n    @WorkerThread\n    public abstract PendingResult<S> onSuccess(@NonNull R result);\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/internal/TelemetryData.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.internal;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.List;\n\n@SafeParcelable.Class\npublic class TelemetryData extends AbstractSafeParcelable {\n\n    @Field(1)\n    final int telemetryConfigVersion;\n    @Field(2)\n    @Nullable\n    List<MethodInvocation> methodInvocations;\n\n    @Constructor\n    public TelemetryData(@Param(1) int telemetryConfigVersion, @Param(2) @Nullable List<MethodInvocation> methodInvocations) {\n        this.telemetryConfigVersion = telemetryConfigVersion;\n        this.methodInvocations = methodInvocations;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"TelemetryData\")\n                .field(\"telemetryConfigVersion\", telemetryConfigVersion)\n                .field(\"methodInvocations\", methodInvocations)\n                .end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static SafeParcelableCreatorAndWriter<TelemetryData> CREATOR = findCreator(TelemetryData.class);\n\n}"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/internal/TransformedResult.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.common.internal;\n\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.api.*;\n\n/**\n * Represents a pending result that has been transformed by one or more subsequent API calls.\n * <p>\n * The result can either be consumed by callbacks set using {@link #andFinally} or used as input to another API call using {@link #then}. It is an error to call\n * both of these methods, or one of them multiple times, on a single instance.\n *\n * @see PendingResult#then(ResultTransform)\n */\npublic abstract class TransformedResult<R extends Result> {\n    /**\n     * Requests that the supplied callbacks are called when the result is ready.\n     */\n    public abstract void andFinally(@NonNull ResultCallbacks<? super R> callbacks);\n\n    /**\n     * Transforms the result by making another API call.\n     * <p>\n     * If the result is successful, then {@link ResultTransform#onSuccess(Result)} will be called to make the additional API call that yields the transformed result. If the result is a\n     * failure, then {@link ResultTransform#onFailure(Status)} will be called to (optionally) allow modification of failure status.\n     * <p>\n     * If the result implements {@link Releasable}, then {@link Releasable#release()} will be called once the transform has been applied.\n     */\n    @NonNull\n    public abstract <S extends Result> TransformedResult<S> then(@NonNull ResultTransform<? super R, S> transform);\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/moduleinstall/InstallStatusListener.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.common.moduleinstall;\n\n/**\n * Listeners to receive updates of module install requests.\n */\npublic interface InstallStatusListener {\n    /**\n     * Callback triggered whenever the install status has changed.\n     */\n    void onInstallStatusUpdated(ModuleInstallStatusUpdate update);\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/moduleinstall/ModuleAvailabilityResponse.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.common.moduleinstall;\n\nimport android.os.Parcel;\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.api.OptionalModuleApi;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Response returned from {@link ModuleInstallClient#areModulesAvailable(OptionalModuleApi...)} indicating whether the\n * requested modules are already present on device.\n */\n@SafeParcelable.Class\npublic class ModuleAvailabilityResponse extends AbstractSafeParcelable {\n    @Field(value = 1, getterName = \"areModulesAvailable\")\n    private final boolean modulesAvailable;\n    @Field(value = 2, getterName = \"getAvailabilityStatus\", type = \"int\")\n    private final @AvailabilityStatus int availabilityStatus;\n\n    @Constructor\n    @Hide\n    public ModuleAvailabilityResponse(@Param(1) boolean modulesAvailable, @Param(2) @AvailabilityStatus int availabilityStatus) {\n        this.modulesAvailable = modulesAvailable;\n        this.availabilityStatus = availabilityStatus;\n    }\n\n    /**\n     * Returns {@code true} if the requested modules are already present, {@code false} otherwise.\n     */\n    public boolean areModulesAvailable() {\n        return modulesAvailable;\n    }\n\n    /**\n     * Returns the {@link ModuleAvailabilityResponse.AvailabilityStatus} for the requested modules.\n     */\n    public @AvailabilityStatus int getAvailabilityStatus() {\n        return availabilityStatus;\n    }\n\n    @Target({ElementType.TYPE_USE})\n    @Retention(RetentionPolicy.SOURCE)\n    @IntDef({AvailabilityStatus.STATUS_ALREADY_AVAILABLE, AvailabilityStatus.STATUS_READY_TO_DOWNLOAD, AvailabilityStatus.STATUS_UNKNOWN_MODULE})\n    public @interface AvailabilityStatus {\n        /**\n         * All the modules requested are already present on device.\n         */\n        int STATUS_ALREADY_AVAILABLE = 0;\n        /**\n         * There are modules requested not present on device, but they can be downloaded via an install request.\n         */\n        int STATUS_READY_TO_DOWNLOAD = 1;\n        /**\n         * There are modules requested that cannot be recognized. You can still still try to download the modules via an install\n         * request, but it's not guaranteed the modules can be downloaded.\n         */\n        int STATUS_UNKNOWN_MODULE = 2;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<ModuleAvailabilityResponse> CREATOR = findCreator(ModuleAvailabilityResponse.class);\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/moduleinstall/ModuleInstall.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.common.moduleinstall;\n\nimport android.app.Activity;\nimport android.content.Context;\n\n/**\n * The main entry point for module install services.\n */\npublic class ModuleInstall {\n    /**\n     * Creates a new instance of {@link ModuleInstallClient} for use in an {@link Activity}.\n     */\n    public static ModuleInstallClient getClient(Activity activity) {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Creates a new instance of {@link ModuleInstallClient} for use in a non-activity {@link Context}.\n     */\n    public static ModuleInstallClient getClient(Context context) {\n        throw new UnsupportedOperationException();\n    }\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/moduleinstall/ModuleInstallClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.common.moduleinstall;\n\nimport android.app.PendingIntent;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.HasApiKey;\nimport com.google.android.gms.common.api.OptionalModuleApi;\nimport com.google.android.gms.tasks.Task;\n\n/**\n * Interface for module install APIs.\n */\npublic interface ModuleInstallClient extends HasApiKey<Api.ApiOptions.NoOptions> {\n    /**\n     * Checks if the optional modules required by the {@link OptionalModuleApi} are already present on device.\n     * <p>\n     * This method is intended to be used in cases where you don't want to unconditionally trigger an immediate installation if\n     * the modules aren't available already. If you need to trigger an immediate installation, use\n     * {@link #installModules(ModuleInstallRequest)} instead.\n     *\n     * @param apis the {@link OptionalModuleApi}s that require optional modules.\n     * @return a {@link Task} with value {@link ModuleAvailabilityResponse} indicating whether the requested modules are already present.\n     */\n    Task<ModuleAvailabilityResponse> areModulesAvailable(@NonNull OptionalModuleApi... apis);\n\n    /**\n     * Defers installation of optional modules required by the {@link OptionalModuleApi}. When called, Google Play services will\n     * optimize the best time to install those modules in the background.\n     * <p>\n     * If your app requires immediate access to those modules, use {@link #installModules(ModuleInstallRequest)} to install the\n     * optional modules right away.\n     *\n     * @param apis the {@link OptionalModuleApi}s that require optional modules.\n     * @return a successful {@link Task} if the deferred install request is received.\n     */\n    Task<Void> deferredInstall(@NonNull OptionalModuleApi... apis);\n\n    /**\n     * Gets the {@link ModuleInstallIntentResponse} that includes a {@link PendingIntent} to initiate the optional module download\n     * and installation flow.\n     *\n     * @param apis the {@link OptionalModuleApi}s that require optional modules.\n     * @return a {@link Task} with value {@link ModuleInstallIntentResponse} which includes the {@link PendingIntent} that can be used to\n     * launch the UI flow. A null {@link PendingIntent} indicates that the optional modules are already present on device.\n     */\n    Task<ModuleInstallIntentResponse> getInstallModulesIntent(@NonNull OptionalModuleApi... apis);\n\n    /**\n     * Triggers an immediate installation request from a {@link ModuleInstallRequest}.\n     * <p>\n     * The {@link Task} completes once the {@link ModuleInstallRequest} has been initiated. This method does not wait for installation to\n     * complete. To monitor the install/download progress of the request, set a {@link InstallStatusListener} when building the\n     * {@link ModuleInstallRequest} to receive {@link ModuleInstallStatusUpdate}, and make sure to\n     * {@link #unregisterListener(InstallStatusListener)} once the installation completes. The listener is only registered if the\n     * modules requested are not already installed.\n     * <p>\n     * The {@link ModuleInstallResponse} indicates whether the modules are already installed and contains an integer session id\n     * that is corresponding to a unique install request. A session id of 0 and/or\n     * {@link ModuleInstallResponse#areModulesAlreadyInstalled()} returned {@code true} indicate that the optional modules are\n     * already installed. You don't need to interact with session id unless the same {@link InstallStatusListener} object is used in\n     * multiple {@link ModuleInstallRequest}s.\n     *\n     * @param request the {@link ModuleInstallRequest} you build for the install request.\n     * @return a {@link Task} with value {@link ModuleInstallResponse} if the install request is received.\n     */\n    Task<ModuleInstallResponse> installModules(@NonNull ModuleInstallRequest request);\n\n    /**\n     * Initiates a request to release optional modules required by {@link OptionalModuleApi} when they are no longer needed.\n     * <p>\n     * This method notifies Google Play services that the optional modules are no longer needed for this app, but it does not\n     * guarantee the optional modules can be removed. Google Play services will try to clean up the optional modules when\n     * they are not used by any apps.\n     * <p>\n     * If this method is called when an install request with all the specified modules is pending, this method will do the best-\n     * effort to cancel that install request. You can monitor the {@link ModuleInstallStatusUpdate} through\n     * {@link InstallStatusListener} to listen for the {@link ModuleInstallStatusUpdate.InstallState#STATE_CANCELED} state when\n     * the install request is canceled.\n     *\n     * @param apis the {@link OptionalModuleApi}s that require optional modules.\n     * @return a successful {@link Task} if the release modules request is received.\n     */\n    Task<Void> releaseModules(@NonNull OptionalModuleApi... apis);\n\n    /**\n     * Unregisters a listener you previously set in {@link ModuleInstallRequest}.\n     *\n     * @param listener the same {@link InstallStatusListener} that is set in the {@link ModuleInstallRequest}.\n     * @return {@code true} if the given listener was found and unregistered, {@code false} otherwise.\n     */\n    Task<Boolean> unregisterListener(@NonNull InstallStatusListener listener);\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/moduleinstall/ModuleInstallIntentResponse.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.common.moduleinstall;\n\nimport android.app.Activity;\nimport android.app.PendingIntent;\nimport android.content.Intent;\nimport android.content.IntentSender;\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.api.OptionalModuleApi;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\n\n/**\n * Response returned from {@link ModuleInstallClient#getInstallModulesIntent(OptionalModuleApi...)} that includes a\n * {@link PendingIntent} that can be used to launch the module installation flow.\n */\n@SafeParcelable.Class\npublic class ModuleInstallIntentResponse extends AbstractSafeParcelable {\n    @Field(value = 1, getterName = \"getPendingIntent\")\n    private final @Nullable PendingIntent pendingIntent;\n\n    @Constructor\n    @Hide\n    public ModuleInstallIntentResponse(@Param(1) @Nullable PendingIntent pendingIntent) {\n        this.pendingIntent = pendingIntent;\n    }\n\n    /**\n     * Returns the {@link PendingIntent} to launch the module installation flow. This intent can be started with\n     * {@link Activity#startIntentSenderForResult(IntentSender, int, Intent, int, int, int)} to present the UI. A null\n     * {@link PendingIntent} indicates the requested optional modules are already present on device.\n     */\n    public @Nullable PendingIntent getPendingIntent() {\n        return pendingIntent;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<ModuleInstallIntentResponse> CREATOR = findCreator(ModuleInstallIntentResponse.class);\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/moduleinstall/ModuleInstallRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.common.moduleinstall;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.api.OptionalModuleApi;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.Executor;\n\n/**\n * Request object that is used to request installation of optional modules in\n * {@link ModuleInstallClient#installModules(ModuleInstallRequest)}.\n */\npublic class ModuleInstallRequest {\n    private final @NonNull List<OptionalModuleApi> apis;\n    private final @Nullable InstallStatusListener listener;\n    private final @Nullable Executor listenerExecutor;\n\n    private ModuleInstallRequest(@NonNull List<OptionalModuleApi> apis, @Nullable InstallStatusListener listener, @Nullable Executor listenerExecutor) {\n        this.apis = apis;\n        this.listener = listener;\n        this.listenerExecutor = listenerExecutor;\n    }\n\n    /**\n     * Returns the list of APIs that require optional modules.\n     */\n    public @NonNull List<OptionalModuleApi> getApis() {\n        return apis;\n    }\n\n    /**\n     * Returns the listener that is attached to this request.\n     */\n    public @Nullable InstallStatusListener getListener() {\n        return listener;\n    }\n\n    /**\n     * Returns the {@link Executor} to use for the {@link InstallStatusListener}.\n     */\n    public @Nullable Executor getListenerExecutor() {\n        return listenerExecutor;\n    }\n\n    /**\n     * Returns a new {@link Builder} for {@link ModuleInstallRequest}.\n     */\n    public static @NonNull Builder newBuilder() {\n        return new Builder();\n    }\n\n    /**\n     * The builder for creating an instance of {@link ModuleInstallRequest}.\n     */\n    public static class Builder {\n        private final @NonNull List<OptionalModuleApi> apis = new ArrayList<>();\n        private @Nullable InstallStatusListener listener;\n        private @Nullable Executor listenerExecutor;\n\n        /**\n         * Adds an {@link OptionalModuleApi} so that the optional module required by this API can be installed.\n         */\n        public @NonNull Builder addApi(@NonNull OptionalModuleApi api) {\n            this.apis.add(api);\n            return this;\n        }\n\n        /**\n         * Sets an {@link InstallStatusListener} to the {@link ModuleInstallRequest}.\n         * <p>\n         * The listener will be called on the main thread.\n         *\n         * @param listener The {@link InstallStatusListener} to receive {@link ModuleInstallStatusUpdate} to monitor the progress of optional module\n         *                 installation progress.\n         */\n        public @NonNull Builder setListener(@NonNull InstallStatusListener listener) {\n            return setListener(listener, null);\n        }\n\n        /**\n         * Sets an {@link InstallStatusListener} to the {@link ModuleInstallRequest}.\n         *\n         * @param listener         The {@link InstallStatusListener} to receive {@link ModuleInstallStatusUpdate} to monitor the progress of optional module\n         *                         installation progress.\n         * @param listenerExecutor The {@link Executor} to use to call the listener.\n         */\n        public @NonNull Builder setListener(@NonNull InstallStatusListener listener, @Nullable Executor listenerExecutor) {\n            this.listener = listener;\n            this.listenerExecutor = listenerExecutor;\n            return this;\n        }\n\n        /**\n         * Returns a new {@link ModuleInstallRequest} object.\n         */\n        public @NonNull ModuleInstallRequest build() {\n            return new ModuleInstallRequest(apis, listener, listenerExecutor);\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/moduleinstall/ModuleInstallResponse.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.common.moduleinstall;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\n\n/**\n * Response returned from {@link ModuleInstallClient#installModules(ModuleInstallRequest)} which includes an integer\n * session id that is corresponding to a unique install request.\n */\n@SafeParcelable.Class\npublic class ModuleInstallResponse extends AbstractSafeParcelable {\n    @Field(value = 1, getterName = \"getSessionId\")\n    private int sessionId;\n    @Field(2)\n    @Hide\n    public boolean shouldUnregisterListener;\n\n    @Constructor\n    @Hide\n    public ModuleInstallResponse(@Param(1) int sessionId, @Param(2) boolean shouldUnregisterListener) {\n        this.sessionId = sessionId;\n        this.shouldUnregisterListener = shouldUnregisterListener;\n    }\n\n    /**\n     * Returns {@code true} if the requested modules are already installed, {@code false} otherwise.\n     */\n    public boolean areModulesAlreadyInstalled() {\n        return sessionId == 0;\n    }\n\n    /**\n     * Returns the session id corresponding to the {@link ModuleInstallRequest} sent in\n     * {@link ModuleInstallClient#installModules(ModuleInstallRequest)}. A session id of 0 indicates that the optional\n     * modules are already installed.\n     */\n    public int getSessionId() {\n        return sessionId;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<ModuleInstallResponse> CREATOR = findCreator(ModuleInstallResponse.class);\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/moduleinstall/ModuleInstallStatusCodes.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.common.moduleinstall;\n\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.api.CommonStatusCodes;\n\n/**\n * Status code for module install APIs.\n */\npublic class ModuleInstallStatusCodes extends CommonStatusCodes {\n    /**\n     * Status code indicating no error (success).\n     */\n    public static final int SUCCESS = 0;\n    /**\n     * Status code indicating the requested module is not recognized, and will not be available to download. A retry will not\n     * resolve this error, but updating Google Play services may help.\n     */\n    public static final int UNKNOWN_MODULE = 46000;\n    /**\n     * Status code indicating the requested module is not allowed to be installed on this device.\n     */\n    public static final int NOT_ALLOWED_MODULE = 46001;\n    /**\n     * Status code indicating the requested module is not found.\n     */\n    public static final int MODULE_NOT_FOUND = 46002;\n    /**\n     * Status code indicating there is not enough disk space to install the requested module.\n     */\n    public static final int INSUFFICIENT_STORAGE = 46003;\n\n    @NonNull\n    public static String getStatusCodeString(int statusCode) {\n        switch (statusCode) {\n            case UNKNOWN_MODULE /* 46000 */:\n                return \"UNKNOWN_MODULE\";\n            case NOT_ALLOWED_MODULE /* 46001 */:\n                return \"NOT_ALLOWED_MODULE\";\n            case MODULE_NOT_FOUND /* 46002 */:\n                return \"MODULE_NOT_FOUND\";\n            case INSUFFICIENT_STORAGE /* 46003 */:\n                return \"INSUFFICIENT_STORAGE\";\n            default:\n                return CommonStatusCodes.getStatusCodeString(statusCode);\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/moduleinstall/ModuleInstallStatusUpdate.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.common.moduleinstall;\n\nimport android.os.Parcel;\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * The status update of a {@link ModuleInstallRequest}.\n */\n@SafeParcelable.Class\npublic class ModuleInstallStatusUpdate extends AbstractSafeParcelable {\n    @Field(value = 1, getterName = \"getSessionId\")\n    private final int sessionId;\n    @Field(value = 2, getterName = \"getInstallState\", type = \"int\")\n    private final @InstallState int installState;\n    @Field(value = 3, getter = \"$object.getProgressInfo() != null ? $object.getProgressInfo().getBytesDownloaded() : null\")\n    private final Long bytesDownloaded;\n    @Field(value = 4, getter = \"$object.getProgressInfo() != null ? $object.getProgressInfo().getTotalBytesToDownload() : null\")\n    private final Long totalBytesToDownload;\n    @Field(value = 5, getterName = \"getErrorCode\")\n    private final int errorCode;\n    private final @Nullable ProgressInfo progressInfo;\n\n    @Constructor\n    @Hide\n    public ModuleInstallStatusUpdate(@Param(1) int sessionId, @Param(2) int installState, @Param(3) Long bytesDownloaded, @Param(4) Long totalBytesToDownload, @Param(5) int errorCode) {\n        this.sessionId = sessionId;\n        this.installState = installState;\n        this.bytesDownloaded = bytesDownloaded;\n        this.totalBytesToDownload = totalBytesToDownload;\n        this.errorCode = errorCode;\n        if (bytesDownloaded == null || totalBytesToDownload == null || totalBytesToDownload == 0) {\n            this.progressInfo = null;\n        } else {\n            this.progressInfo = new ProgressInfo(bytesDownloaded, totalBytesToDownload);\n        }\n    }\n\n    /**\n     * Returns the error code from {@link ModuleInstallStatusCodes}, or {@link ModuleInstallStatusCodes#SUCCESS} if the install is\n     * successful or in progress.\n     */\n    public int getErrorCode() {\n        return errorCode;\n    }\n\n    /**\n     * Returns the {@link ModuleInstallStatusUpdate.InstallState} of an optional module install session.\n     */\n    public @InstallState int getInstallState() {\n        return installState;\n    }\n\n    /**\n     * Returns the download progress information including the bytes downloaded so far and total bytes to download.\n     * When there are modules to download, the progress info would be provided on the following state:\n     * {@link ModuleInstallStatusUpdate.InstallState#STATE_DOWNLOADING},\n     * {@link ModuleInstallStatusUpdate.InstallState#STATE_DOWNLOAD_PAUSED},\n     * {@link ModuleInstallStatusUpdate.InstallState#STATE_INSTALLING} and\n     * {@link ModuleInstallStatusUpdate.InstallState#STATE_COMPLETED}. Otherwise, this method would return {@code null}.\n     */\n    public @Nullable ProgressInfo getProgressInfo() {\n        return progressInfo;\n    }\n\n    /**\n     * Returns the session id that corresponding to a {@link ModuleInstallRequest}.\n     */\n    public int getSessionId() {\n        return sessionId;\n    }\n\n    /**\n     * The current install state for the install request.\n     */\n    @Target({ElementType.TYPE_USE})\n    @Retention(RetentionPolicy.SOURCE)\n    @IntDef({InstallState.STATE_UNKNOWN, InstallState.STATE_PENDING, InstallState.STATE_DOWNLOADING, InstallState.STATE_CANCELED, InstallState.STATE_COMPLETED, InstallState.STATE_FAILED, InstallState.STATE_INSTALLING, InstallState.STATE_DOWNLOAD_PAUSED})\n    @interface InstallState {\n        int STATE_UNKNOWN = 0;\n        /**\n         * The request is pending and will be processed soon.\n         */\n        int STATE_PENDING = 1;\n        /**\n         * The optional module download is in progress.\n         */\n        int STATE_DOWNLOADING = 2;\n        /**\n         * The optional module download has been canceled.\n         */\n        int STATE_CANCELED = 3;\n        /**\n         * Installation is completed; the optional modules are available to the client app.\n         */\n        int STATE_COMPLETED = 4;\n        /**\n         * The optional module download or installation has failed.\n         */\n        int STATE_FAILED = 5;\n        /**\n         * The optional modules have been downloaded and the installation is in progress.\n         */\n        int STATE_INSTALLING = 6;\n        /**\n         * The optional module download has been paused.\n         * <p>\n         * This usually happens when connectivity requirements can't be met during download. Once the connectivity requirements\n         * are met, the download will be resumed automatically.\n         */\n        int STATE_DOWNLOAD_PAUSED = 7;\n    }\n\n    /**\n     * Download progress information for an {@link ModuleInstallStatusUpdate}.\n     */\n    public static class ProgressInfo {\n        private final long bytesDownloaded;\n        private final long totalBytesToDownload;\n\n        ProgressInfo(long bytesDownloaded, long totalBytesToDownload) {\n            this.bytesDownloaded = bytesDownloaded;\n            this.totalBytesToDownload = totalBytesToDownload;\n        }\n\n        /**\n         * Returns the number of bytes downloaded so far.\n         */\n        public long getBytesDownloaded() {\n            return bytesDownloaded;\n        }\n\n        /**\n         * Returns the total number of bytes to download in this session.\n         * <p>\n         * The total number of bytes to download is guaranteed to be greater than 0.\n         */\n        public long getTotalBytesToDownload() {\n            return totalBytesToDownload;\n        }\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<ModuleInstallStatusUpdate> CREATOR = findCreator(ModuleInstallStatusUpdate.class);\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/moduleinstall/internal/ApiFeatureRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.moduleinstall.internal;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.Feature;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.List;\n\n@SafeParcelable.Class\n@Hide\npublic class ApiFeatureRequest extends AbstractSafeParcelable {\n    @Field(1)\n    public List<Feature> features;\n    @Field(2)\n    public boolean urgent;\n    @Field(3)\n    public String sessionId;\n    @Field(4)\n    public String callingPackage;\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"ApiFeatureRequest\")\n                .field(\"features\", features)\n                .field(\"urgent\", urgent)\n                .field(\"sessionId\", sessionId)\n                .field(\"callingPackage\", callingPackage)\n                .end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<ApiFeatureRequest> CREATOR = findCreator(ApiFeatureRequest.class);\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/package-info.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n/**\n * Contains utility classes for Google Play services.\n */\npackage com.google.android.gms.common;\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/server/FavaDiagnosticsEntity.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.common.server;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class FavaDiagnosticsEntity extends AutoSafeParcelable {\n\n    public static final Creator<FavaDiagnosticsEntity> CREATOR = new AutoCreator<FavaDiagnosticsEntity>(FavaDiagnosticsEntity.class);\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/common/util/IOUtils.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.common.util;\n\nimport android.os.ParcelFileDescriptor;\n\nimport androidx.annotation.NonNull;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.Closeable;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\npublic final class IOUtils {\n    private IOUtils() {\n    }\n\n    public static void closeQuietly(ParcelFileDescriptor parcelFileDescriptor) {\n        if (parcelFileDescriptor != null) {\n            try {\n                parcelFileDescriptor.close();\n            } catch (IOException unused) {\n            }\n        }\n    }\n\n    public static long copyStream(@NonNull InputStream inputStream, @NonNull OutputStream outputStream) throws IOException {\n        return copyStream(inputStream, outputStream, false, 1024);\n    }\n\n    public static boolean isGzipByteBuffer(@NonNull byte[] bArr) {\n        if (bArr.length > 1) {\n            if ((((bArr[1] & 255) << 8) | (bArr[0] & 255)) == 35615) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    public static byte[] readInputStreamFully(@NonNull InputStream inputStream) throws IOException {\n        return readInputStreamFully(inputStream, true);\n    }\n\n    public static byte[] toByteArray(@NonNull InputStream inputStream) throws IOException {\n        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();\n        byte[] bArr = new byte[4096];\n        while (true) {\n            int read = inputStream.read(bArr);\n            if (read == -1) {\n                return byteArrayOutputStream.toByteArray();\n            }\n            byteArrayOutputStream.write(bArr, 0, read);\n        }\n    }\n\n\n    public static void closeQuietly(Closeable closeable) {\n        if (closeable != null) {\n            try {\n                closeable.close();\n            } catch (IOException unused) {\n            }\n        }\n    }\n\n    public static long copyStream(@NonNull InputStream inputStream, @NonNull OutputStream outputStream, boolean z, int i) throws IOException {\n        byte[] bArr = new byte[i];\n        long j = 0;\n        while (true) {\n            try {\n                int read = inputStream.read(bArr, 0, i);\n                if (read == -1) {\n                    break;\n                }\n                j += read;\n                outputStream.write(bArr, 0, read);\n            } catch (Throwable th) {\n                if (z) {\n                    closeQuietly(inputStream);\n                    closeQuietly(outputStream);\n                }\n                throw th;\n            }\n        }\n        if (z) {\n            closeQuietly(inputStream);\n            closeQuietly(outputStream);\n        }\n        return j;\n    }\n\n    public static byte[] readInputStreamFully(@NonNull InputStream inputStream, boolean z) throws IOException {\n        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();\n        copyStream(inputStream, byteArrayOutputStream, z, 1024);\n        return byteArrayOutputStream.toByteArray();\n    }\n\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/dynamic/DeferredLifecycleHelper.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.dynamic;\n\nimport android.app.Activity;\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.FrameLayout;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.util.LinkedList;\n\npublic abstract class DeferredLifecycleHelper<T extends LifecycleDelegate> {\n    private T delegate;\n    private Bundle savedInstanceState;\n    private final LinkedList<PendingStateOperation<T>> pendingStateOperations = new LinkedList<>();\n    private final OnDelegateCreatedListener<T> listener = (delegate) -> {\n        DeferredLifecycleHelper.this.delegate = delegate;\n        for (PendingStateOperation<T> op : pendingStateOperations) {\n            op.apply(delegate);\n        }\n        pendingStateOperations.clear();\n        savedInstanceState = null;\n    };\n\n    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup parent, @Nullable Bundle savedInstanceState) {\n        FrameLayout rootLayout = new FrameLayout(inflater.getContext());\n        startStateOperation(savedInstanceState, new PendingStateOperation<T>(State.VIEW_CREATED) {\n            @Override\n            public void apply(T delegate) {\n                rootLayout.removeAllViews();\n                rootLayout.addView(delegate.onCreateView(inflater, parent, savedInstanceState));\n            }\n        });\n        return rootLayout;\n    }\n\n    public T getDelegate() {\n        return delegate;\n    }\n\n    protected abstract void createDelegate(@NonNull OnDelegateCreatedListener<T> listener);\n\n    public void onCreate(@Nullable Bundle savedInstanceState) {\n        startStateOperation(savedInstanceState, new PendingStateOperation<T>(State.CREATED) {\n            @Override\n            public void apply(T delegate) {\n                delegate.onCreate(savedInstanceState);\n            }\n        });\n    }\n\n    public void onDestroy() {\n        if (delegate != null) {\n            delegate.onDestroy();\n        } else {\n            removePendingStateOperations(State.CREATED);\n        }\n    }\n\n    public void onDestroyView() {\n        if (delegate != null) {\n            delegate.onDestroyView();\n        } else {\n            removePendingStateOperations(State.VIEW_CREATED);\n        }\n    }\n\n    public void onInflate(@NonNull Activity activity, @NonNull Bundle attrs, @Nullable Bundle savedInstanceState) {\n        startStateOperation(savedInstanceState, new PendingStateOperation<T>(State.NONE) {\n            @Override\n            public void apply(T delegate) {\n                delegate.onInflate(activity, attrs, savedInstanceState);\n            }\n        });\n    }\n\n    public void onLowMemory() {\n        if (delegate != null) delegate.onLowMemory();\n    }\n\n    public void onPause() {\n        if (delegate != null) {\n            delegate.onPause();\n        } else {\n            removePendingStateOperations(State.RESUMED);\n        }\n    }\n\n    public void onResume() {\n        startStateOperation(savedInstanceState, new PendingStateOperation<T>(State.RESUMED) {\n            @Override\n            public void apply(T delegate) {\n                delegate.onResume();\n            }\n        });\n    }\n\n    public void onSaveInstanceState(@NonNull Bundle outState) {\n        if (delegate != null) {\n            delegate.onSaveInstanceState(outState);\n        } else if (savedInstanceState != null) {\n            outState.putAll(savedInstanceState);\n        }\n    }\n\n    public void onStart() {\n        startStateOperation(savedInstanceState, new PendingStateOperation<T>(State.STARTED) {\n            @Override\n            public void apply(T delegate) {\n                delegate.onStart();\n            }\n        });\n    }\n\n    public void onStop() {\n        if (delegate != null) {\n            delegate.onStop();\n        } else {\n            removePendingStateOperations(State.STARTED);\n        }\n    }\n\n    private void removePendingStateOperations(State state) {\n        while (!pendingStateOperations.isEmpty() && pendingStateOperations.getLast().state.isAtLeast(state)) {\n            pendingStateOperations.removeLast();\n        }\n    }\n\n    private void startStateOperation(@Nullable Bundle savedInstanceState, PendingStateOperation<T> op) {\n        if (delegate != null) {\n            op.apply(delegate);\n        } else {\n            pendingStateOperations.add(op);\n            if (savedInstanceState != null) {\n                if (this.savedInstanceState == null) this.savedInstanceState = new Bundle();\n                this.savedInstanceState.putAll(savedInstanceState);\n            }\n            createDelegate(listener);\n        }\n    }\n\n    private static abstract class PendingStateOperation<T extends LifecycleDelegate> {\n        public final State state;\n\n        public PendingStateOperation(State state) {\n            this.state = state;\n        }\n\n        public abstract void apply(T delegate);\n    }\n\n    private enum State {\n        NONE, CREATED, VIEW_CREATED, STARTED, RESUMED;\n\n        public boolean isAtLeast(@NonNull State state) {\n            return compareTo(state) >= 0;\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/signin/SignIn.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.signin;\n\nimport com.google.android.gms.common.api.Api;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.signin.SignInClientImpl;\n\n@Hide\npublic class SignIn {\n    public static final Api<SignInOptions> API = new Api<>((options, context, looper, clientSettings, callbacks, connectionFailedListener) -> new SignInClientImpl(context, clientSettings, callbacks, connectionFailedListener));\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/signin/SignInClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.signin;\n\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.internal.IAccountAccessor;\nimport com.google.android.gms.signin.internal.ISignInCallbacks;\n\npublic interface SignInClient extends Api.Client {\n    void clearAccountFromSessionStore();\n    void saveDefaultAccount(@NonNull IAccountAccessor accountAccessor, boolean crossClient);\n    void signIn(@NonNull ISignInCallbacks callbacks);\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/signin/SignInOptions.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.signin;\n\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.api.Api;\nimport org.microg.gms.common.Hide;\n\npublic class SignInOptions implements Api.ApiOptions.Optional {\n    @NonNull\n    @Hide\n    public static SignInOptions DEFAULT = new SignInOptions();\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/signin/internal/AuthAccountResult.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.signin.internal;\n\nimport android.content.Intent;\nimport com.google.android.gms.common.ConnectionResult;\nimport com.google.android.gms.common.api.Result;\nimport com.google.android.gms.common.api.Status;\nimport org.microg.gms.common.Hide;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n@Hide\npublic class AuthAccountResult extends AutoSafeParcelable implements Result {\n    @Field(1)\n    private int versionCode = 2;\n    @Field(2)\n    public int connectionResultCode;\n    @Field(3)\n    public Intent rawAuthResolutionIntent;\n\n    @Override\n    public Status getStatus() {\n        return connectionResultCode == ConnectionResult.SUCCESS ? Status.SUCCESS : Status.CANCELED;\n    }\n\n    public static final Creator<AuthAccountResult> CREATOR = findCreator(AuthAccountResult.class);\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/signin/internal/CheckServerAuthResult.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.signin.internal;\n\nimport com.google.android.gms.common.api.Scope;\nimport org.microg.gms.common.Hide;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\nimport java.util.List;\n\n@Hide\npublic class CheckServerAuthResult extends AutoSafeParcelable {\n    @Field(1)\n    private int versionCode = 1;\n    @Field(2)\n    public boolean newAuthCodeRequired;\n    @Field(3)\n    public List<Scope> additionalScopes;\n\n    public static final Creator<CheckServerAuthResult> CREATOR = findCreator(CheckServerAuthResult.class);\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/signin/internal/RecordConsentByConsentResultRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.signin.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class RecordConsentByConsentResultRequest extends AutoSafeParcelable {\n    public static final Creator<RecordConsentByConsentResultRequest> CREATOR = new AutoCreator<>(RecordConsentByConsentResultRequest.class);\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/signin/internal/RecordConsentByConsentResultResponse.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.signin.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class RecordConsentByConsentResultResponse extends AutoSafeParcelable {\n    public static final Creator<RecordConsentByConsentResultResponse> CREATOR = new AutoCreator<>(RecordConsentByConsentResultResponse.class);\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/signin/internal/RecordConsentRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.signin.internal;\n\nimport android.accounts.Account;\nimport com.google.android.gms.common.api.Scope;\nimport org.microg.gms.common.Hide;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n@Hide\npublic class RecordConsentRequest extends AutoSafeParcelable {\n    @Field(1)\n    private int versionCode = 1;\n    @Field(2)\n    public Account account;\n    @Field(3)\n    public Scope[] scopesToConsent;\n    @Field(4)\n    public String serverClientId;\n\n    public static final Creator<RecordConsentRequest> CREATOR = findCreator(RecordConsentRequest.class);\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/signin/internal/SignInRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.signin.internal;\n\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.ResolveAccountRequest;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.utils.ToStringHelper;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n@Hide\npublic class SignInRequest extends AutoSafeParcelable {\n    @Field(1)\n    private final int versionCode = 1;\n    @Field(2)\n    public ResolveAccountRequest request;\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"SignInRequest\")\n                .field(\"request\", request)\n                .end();\n    }\n\n    public static final Creator<SignInRequest> CREATOR = new AutoCreator<>(SignInRequest.class);\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/com/google/android/gms/signin/internal/SignInResponse.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.signin.internal;\n\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.ConnectionResult;\nimport com.google.android.gms.common.internal.ResolveAccountResponse;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.utils.ToStringHelper;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n@Hide\npublic class SignInResponse extends AutoSafeParcelable {\n    @Field(1)\n    private final int versionCode = 1;\n    @Field(2)\n    public ConnectionResult connectionResult;\n    @Field(3)\n    public ResolveAccountResponse response;\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"SignInResponse\")\n                .field(\"connectionResult\", connectionResult)\n                .field(\"response\", response)\n                .end();\n    }\n\n    public static final Creator<SignInResponse> CREATOR = new AutoCreator<>(SignInResponse.class);\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/org/microg/gms/common/DummyApiClient.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.common;\n\nimport android.content.Intent;\nimport android.os.IBinder;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.Feature;\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.Scope;\nimport com.google.android.gms.common.internal.BaseGmsClient;\nimport com.google.android.gms.common.internal.IAccountAccessor;\n\nimport java.io.FileDescriptor;\nimport java.io.PrintWriter;\nimport java.util.Collections;\nimport java.util.Set;\n\n@Deprecated\npublic class DummyApiClient implements Api.Client {\n    private boolean connected = false;\n\n    @Override\n    public void connect() {\n        connected = true;\n    }\n\n    @Override\n    public void connect(@NonNull BaseGmsClient.ConnectionProgressReportCallbacks connectionProgressReportCallbacks) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void disconnect() {\n        connected = false;\n    }\n\n    @Override\n    public void disconnect(@NonNull String reason) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void dump(@NonNull String prefix, @Nullable FileDescriptor fd, @NonNull PrintWriter writer, @Nullable String[] args) {\n        throw new UnsupportedOperationException();\n    }\n\n    @NonNull\n    @Override\n    public Feature[] getAvailableFeatures() {\n        throw new UnsupportedOperationException();\n    }\n\n    @NonNull\n    @Override\n    public String getEndpointPackageName() {\n        throw new UnsupportedOperationException();\n    }\n\n    @Nullable\n    @Override\n    public String getLastDisconnectMessage() {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public int getMinApkVersion() {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void getRemoteService(@Nullable IAccountAccessor iAccountAccessor, @Nullable Set<Scope> scopes) {\n        throw new UnsupportedOperationException();\n    }\n\n    @NonNull\n    @Override\n    public Feature[] getRequiredFeatures() {\n        throw new UnsupportedOperationException();\n    }\n\n    @NonNull\n    @Override\n    public Set<Scope> getScopesForConnectionlessNonSignIn() {\n        throw new UnsupportedOperationException();\n    }\n\n    @Nullable\n    @Override\n    public IBinder getServiceBrokerBinder() {\n        throw new UnsupportedOperationException();\n    }\n\n    @NonNull\n    @Override\n    public Intent getSignInIntent() {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public boolean isConnected() {\n        return connected;\n    }\n\n    @Override\n    public boolean isConnecting() {\n        return false;\n    }\n\n    @Override\n    public void onUserSignOut(@NonNull BaseGmsClient.SignOutCallbacks signOutCallbacks) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public boolean providesSignIn() {\n        return false;\n    }\n\n    @Override\n    public boolean requiresAccount() {\n        return false;\n    }\n\n    @Override\n    public boolean requiresGooglePlayServices() {\n        return false;\n    }\n\n    @Override\n    public boolean requiresSignIn() {\n        return false;\n    }\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/org/microg/gms/common/ForwardConnectionCallbacks.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.common;\n\nimport android.os.Bundle;\n\nimport com.google.android.gms.common.GooglePlayServicesClient;\nimport com.google.android.gms.common.api.GoogleApiClient;\n\npublic final class ForwardConnectionCallbacks implements GoogleApiClient.ConnectionCallbacks {\n    private final GooglePlayServicesClient.ConnectionCallbacks callbacks;\n\n    public ForwardConnectionCallbacks(GooglePlayServicesClient.ConnectionCallbacks callbacks) {\n        this.callbacks = callbacks;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        return o instanceof ForwardConnectionCallbacks &&\n                callbacks.equals(((ForwardConnectionCallbacks) o).callbacks);\n    }\n\n    @Override\n    public int hashCode() {\n        return callbacks.hashCode();\n    }\n\n    @Override\n    public void onConnected(Bundle connectionHint) {\n        callbacks.onConnected(connectionHint);\n    }\n\n    @Override\n    public void onConnectionSuspended(int cause) {\n        callbacks.onDisconnected();\n    }\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/org/microg/gms/common/ForwardConnectionFailedListener.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.common;\n\nimport com.google.android.gms.common.ConnectionResult;\nimport com.google.android.gms.common.GooglePlayServicesClient;\nimport com.google.android.gms.common.api.GoogleApiClient;\n\npublic final class ForwardConnectionFailedListener\n        implements GoogleApiClient.OnConnectionFailedListener {\n    private final GooglePlayServicesClient.OnConnectionFailedListener listener;\n\n    public ForwardConnectionFailedListener(\n            GooglePlayServicesClient.OnConnectionFailedListener listener) {\n        this.listener = listener;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        return o instanceof ForwardConnectionFailedListener &&\n                listener.equals(((ForwardConnectionFailedListener) o).listener);\n    }\n\n    @Override\n    public int hashCode() {\n        return listener.hashCode();\n    }\n\n    @Override\n    public void onConnectionFailed(ConnectionResult result) {\n        listener.onConnectionFailed(result);\n    }\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/org/microg/gms/common/GmsClient.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.common;\n\nimport android.accounts.Account;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.ServiceConnection;\nimport android.os.Bundle;\nimport android.os.IBinder;\nimport android.os.IInterface;\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.ConnectionResult;\nimport com.google.android.gms.common.Feature;\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.CommonStatusCodes;\nimport com.google.android.gms.common.api.Scope;\nimport com.google.android.gms.common.internal.*;\n\nimport com.google.android.gms.common.api.internal.ConnectionCallbacks;\nimport com.google.android.gms.common.api.internal.OnConnectionFailedListener;\n\nimport java.io.FileDescriptor;\nimport java.io.PrintWriter;\nimport java.util.Set;\n\npublic abstract class GmsClient<I extends IInterface> implements Api.Client {\n    private static final String TAG = \"GmsClient\";\n\n    private final Context context;\n    protected final ConnectionCallbacks callbacks;\n    protected final OnConnectionFailedListener connectionFailedListener;\n    protected ConnectionState state = ConnectionState.NOT_CONNECTED;\n    private ServiceConnection serviceConnection;\n    private I serviceInterface;\n    private final String actionString;\n\n    protected boolean requireMicrog;\n    protected String packageName;\n\n    protected int serviceId = -1;\n    protected Account account = null;\n    protected Bundle extras = new Bundle();\n\n    public GmsClient(Context context, ConnectionCallbacks callbacks, OnConnectionFailedListener connectionFailedListener, String actionString) {\n        this.context = context;\n        this.callbacks = callbacks;\n        this.connectionFailedListener = connectionFailedListener;\n        this.actionString = actionString;\n        this.requireMicrog = false;\n        this.packageName = context.getPackageName();\n    }\n\n    protected void onConnectedToBroker(IGmsServiceBroker broker, GmsCallbacks callbacks) throws RemoteException {\n        if (serviceId == -1) {\n            throw new IllegalStateException(\"Service ID not set in constructor and onConnectedToBroker not implemented\");\n        }\n        GetServiceRequest request = new GetServiceRequest(serviceId);\n        request.packageName = packageName;\n        request.account = account;\n        request.extras = extras;\n        broker.getService(callbacks, request);\n    }\n\n    protected abstract I interfaceFromBinder(IBinder binder);\n\n    @Override\n    public synchronized void connect() {\n        Log.d(TAG, \"connect()\");\n        if (state == ConnectionState.CONNECTED || state == ConnectionState.CONNECTING) {\n            Log.d(TAG, \"Already connected/connecting - nothing to do\");\n        }\n        state = ConnectionState.CONNECTING;\n        if (serviceConnection != null) {\n            MultiConnectionKeeper.getInstance(context).unbind(actionString, serviceConnection);\n        }\n        serviceConnection = new GmsServiceConnection();\n        if (!MultiConnectionKeeper.getInstance(context).bind(actionString, serviceConnection, requireMicrog)) {\n            state = ConnectionState.ERROR;\n            handleConnectionFailed();\n        }\n    }\n\n    public void handleConnectionFailed() {\n        connectionFailedListener.onConnectionFailed(new ConnectionResult(ConnectionResult.API_UNAVAILABLE, null));\n    }\n\n    @Override\n    public synchronized void disconnect() {\n        Log.d(TAG, \"disconnect()\");\n        if (state == ConnectionState.DISCONNECTING) return;\n        if (state == ConnectionState.CONNECTING) {\n            state = ConnectionState.DISCONNECTING;\n            return;\n        }\n        serviceInterface = null;\n        if (serviceConnection != null) {\n            MultiConnectionKeeper.getInstance(context).unbind(actionString, serviceConnection);\n            serviceConnection = null;\n        }\n        state = ConnectionState.NOT_CONNECTED;\n    }\n\n    @Override\n    public synchronized boolean isConnected() {\n        return (state == ConnectionState.CONNECTED && serviceInterface != null && serviceInterface.asBinder().isBinderAlive() ) || state == ConnectionState.PSEUDO_CONNECTED;\n    }\n\n    @Override\n    public synchronized boolean isConnecting() {\n        return state == ConnectionState.CONNECTING;\n    }\n\n    public synchronized boolean hasError() {\n        return state == ConnectionState.ERROR;\n    }\n\n    public Context getContext() {\n        return context;\n    }\n\n    public synchronized I getServiceInterface() {\n        if (isConnecting()) {\n            // TODO: wait for connection to be established and return afterwards.\n            throw new IllegalStateException(\"Waiting for connection\");\n        } else if (!isConnected()) {\n            throw new IllegalStateException(\"interface only available once connected!\");\n        }\n        return serviceInterface;\n    }\n\n    protected enum ConnectionState {\n        NOT_CONNECTED, CONNECTING, CONNECTED, DISCONNECTING, ERROR, PSEUDO_CONNECTED\n    }\n\n    private class GmsServiceConnection implements ServiceConnection {\n\n        @Override\n        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {\n            try {\n                Log.d(TAG, \"ServiceConnection : onServiceConnected(\" + componentName + \")\");\n                onConnectedToBroker(IGmsServiceBroker.Stub.asInterface(iBinder), new GmsCallbacks());\n            } catch (RemoteException e) {\n                disconnect();\n            }\n        }\n\n        @Override\n        public void onServiceDisconnected(ComponentName componentName) {\n            synchronized (GmsClient.this) {\n                state = ConnectionState.NOT_CONNECTED;\n            }\n        }\n    }\n\n    public class GmsCallbacks extends IGmsCallbacks.Stub {\n\n        @Override\n        public void onPostInitComplete(int statusCode, IBinder binder, Bundle params)\n                throws RemoteException {\n            if (statusCode != CommonStatusCodes.SUCCESS) {\n                state = ConnectionState.CONNECTED;\n                disconnect();\n                connectionFailedListener.onConnectionFailed(new ConnectionResult(statusCode));\n            } else {\n                synchronized (GmsClient.this) {\n                    if (state == ConnectionState.DISCONNECTING) {\n                        state = ConnectionState.CONNECTED;\n                        disconnect();\n                        return;\n                    }\n                    state = ConnectionState.CONNECTED;\n                    serviceInterface = interfaceFromBinder(binder);\n                }\n                Log.d(TAG, \"GmsCallbacks : onPostInitComplete(\" + serviceInterface + \")\");\n                callbacks.onConnected(params);\n            }\n        }\n\n        @Override\n        public void onAccountValidationComplete(int statusCode, Bundle params) throws RemoteException {\n            Log.d(TAG, \"GmsCallbacks : onAccountValidationComplete\");\n        }\n\n        @Override\n        public void onPostInitCompleteWithConnectionInfo(int statusCode, IBinder binder, ConnectionInfo info) throws RemoteException {\n            onPostInitComplete(statusCode, binder, info == null ? null : info.params);\n        }\n    }\n\n\n    @Override\n    public void connect(@NonNull BaseGmsClient.ConnectionProgressReportCallbacks connectionProgressReportCallbacks) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void disconnect(@NonNull String reason) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void dump(@NonNull String prefix, @Nullable FileDescriptor fd, @NonNull PrintWriter writer, @Nullable String[] args) {\n        throw new UnsupportedOperationException();\n    }\n\n    @NonNull\n    @Override\n    public Feature[] getAvailableFeatures() {\n        throw new UnsupportedOperationException();\n    }\n\n    @NonNull\n    @Override\n    public String getEndpointPackageName() {\n        throw new UnsupportedOperationException();\n    }\n\n    @Nullable\n    @Override\n    public String getLastDisconnectMessage() {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public int getMinApkVersion() {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void getRemoteService(@Nullable IAccountAccessor iAccountAccessor, @Nullable Set<Scope> scopes) {\n        throw new UnsupportedOperationException();\n    }\n\n    @NonNull\n    @Override\n    public Feature[] getRequiredFeatures() {\n        throw new UnsupportedOperationException();\n    }\n\n    @NonNull\n    @Override\n    public Set<Scope> getScopesForConnectionlessNonSignIn() {\n        throw new UnsupportedOperationException();\n    }\n\n    @Nullable\n    @Override\n    public IBinder getServiceBrokerBinder() {\n        throw new UnsupportedOperationException();\n    }\n\n    @NonNull\n    @Override\n    public Intent getSignInIntent() {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void onUserSignOut(@NonNull BaseGmsClient.SignOutCallbacks signOutCallbacks) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public boolean providesSignIn() {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public boolean requiresAccount() {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public boolean requiresGooglePlayServices() {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public boolean requiresSignIn() {\n        throw new UnsupportedOperationException();\n    }\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/org/microg/gms/common/GmsConnector.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.common;\n\nimport android.os.Looper;\nimport android.os.Message;\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.PendingResult;\nimport com.google.android.gms.common.api.Result;\n\nimport org.microg.gms.common.api.BasePendingResult;\nimport org.microg.gms.common.api.GoogleApiClientImpl;\n\npublic class GmsConnector<C extends Api.Client, R extends Result> {\n    private static final String TAG = \"GmsConnector\";\n\n    private final GoogleApiClientImpl apiClient;\n    private final Api api;\n    private final Callback<C, R> callback;\n\n    public GmsConnector(GoogleApiClient apiClient, Api api, Callback<C, R> callback) {\n        this.apiClient = (GoogleApiClientImpl) apiClient;\n        this.api = api;\n        this.callback = callback;\n    }\n\n    public static <C extends Api.Client, R extends Result> PendingResult<R> call(GoogleApiClient client, Api api, GmsConnector.Callback<C, R> callback) {\n        return new GmsConnector<C, R>(client, api, callback).connect();\n    }\n\n    public BasePendingResult<R> connect() {\n        Log.d(TAG, \"connect()\");\n        apiClient.incrementUsageCounter();\n        apiClient.getApiConnection(api);\n        Looper looper = apiClient.getLooper();\n        final BasePendingResult<R> result = new BasePendingResult<R>(looper);\n        Message msg = new Message();\n        msg.obj = result;\n        new Handler(looper).sendMessage(msg);\n        return result;\n    }\n\n    public interface Callback<C, R> {\n        void onClientAvailable(C client, ResultProvider<R> resultProvider) throws RemoteException;\n\n        interface ResultProvider<R> {\n            void onResultAvailable(R result);\n        }\n    }\n\n    private class Handler extends android.os.Handler {\n        private Handler(Looper looper) {\n            super(looper);\n        }\n\n        @Override\n        public void handleMessage(Message msg) {\n            Log.d(TAG, \"Handler : handleMessage\");\n            final BasePendingResult<R> result = (BasePendingResult<R>) msg.obj;\n            try {\n                C connection = (C) apiClient.getApiConnection(api);\n                callback.onClientAvailable(connection, new GmsConnector.Callback.ResultProvider<R>() {\n                    @Override\n                    public void onResultAvailable(R realResult) {\n                        result.deliverResult(realResult);\n                        apiClient.decrementUsageCounter();\n                    }\n                });\n            } catch (RemoteException ignored) {\n\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/org/microg/gms/common/MultiConnectionKeeper.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.common;\n\nimport android.annotation.SuppressLint;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.ServiceConnection;\nimport android.content.SharedPreferences;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageManager;\nimport android.content.pm.PermissionInfo;\nimport android.content.pm.ResolveInfo;\nimport android.content.pm.Signature;\nimport android.os.IBinder;\nimport android.util.Log;\n\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\n\nimport static android.os.Build.VERSION.SDK_INT;\nimport static org.microg.gms.common.Constants.GMS_PACKAGE_NAME;\nimport static org.microg.gms.common.Constants.USER_MICROG_PACKAGE_NAME;\nimport static org.microg.gms.common.Constants.GMS_PACKAGE_SIGNATURE_SHA1;\nimport static org.microg.gms.common.Constants.GMS_SECONDARY_PACKAGE_SIGNATURE_SHA1;\nimport static org.microg.gms.common.Constants.MICROG_PACKAGE_SIGNATURE_SHA1;\n\npublic class MultiConnectionKeeper {\n    private static final String TAG = \"GmsMultiConKeeper\";\n    private static final String PREF_NAME = \"org.microg.gms_connection\";\n    private static final String PREF_TARGET = \"target\";\n    private static final String[] GOOGLE_PRIMARY_KEYS = {GMS_PACKAGE_SIGNATURE_SHA1, GMS_SECONDARY_PACKAGE_SIGNATURE_SHA1};\n\n    private static final String[] MICROG_PRIMARY_KEYS = {MICROG_PACKAGE_SIGNATURE_SHA1};\n    private static MultiConnectionKeeper INSTANCE;\n\n    private final Context context;\n\n    private final String targetPackage;\n    private final Map<String, Connection> connections = new HashMap<String, Connection>();\n\n    private Boolean isSystem(PackageManager pm, String packageId) throws PackageManager.NameNotFoundException {\n        ApplicationInfo ai = pm.getApplicationInfo(packageId, PackageManager.GET_META_DATA);\n        return (ai.flags & (ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0;\n    }\n\n    private Boolean isGoogleOrMicrogSig(PackageManager pm, String packageId) throws PackageManager.NameNotFoundException {\n        List<String> signatures = new LinkedList<>(Arrays.asList(GOOGLE_PRIMARY_KEYS));\n        signatures.addAll(Arrays.asList(MICROG_PRIMARY_KEYS));\n        return signatureIsIn(pm, packageId, signatures);\n    }\n\n    private Boolean isSystemGoogleOrMicrogSig(PackageManager pm, String packageId) throws PackageManager.NameNotFoundException {\n        return isSystem(pm, packageId) || isGoogleOrMicrogSig(pm, packageId);\n    }\n\n    private Boolean isMicrogSig(PackageManager pm, String packageId) throws PackageManager.NameNotFoundException {\n        List<String> signatures = Arrays.asList(MICROG_PRIMARY_KEYS);\n        return signatureIsIn(pm, packageId, signatures);\n    }\n\n    private Boolean signatureIsIn(PackageManager pm, String packageId, List<String> signatures) throws PackageManager.NameNotFoundException {\n        Signature[] appSignatures = pm.getPackageInfo(packageId, PackageManager.GET_SIGNATURES).signatures;\n        for (Signature sig : appSignatures) {\n            if (sig != null && signatures.contains(sha1sum(sig.toByteArray())))\n                return true;\n        }\n        return false;\n    }\n\n    private String sha1sum(byte[] bytes) {\n        MessageDigest md;\n        try {\n            md = MessageDigest.getInstance(\"SHA1\");\n        } catch (final NoSuchAlgorithmException e) {\n            return null;\n        }\n        if (md != null) {\n            bytes = md.digest(bytes);\n            if (bytes != null) {\n                StringBuilder sb = new StringBuilder(2 * bytes.length);\n                for (byte b : bytes) {\n                    sb.append(String.format(\"%02x\", b));\n                }\n                return sb.toString();\n            }\n        }\n        return null;\n    }\n\n    private String getTargetPackageWithoutPref() {\n        // Pref: gms > microG > self\n        PackageManager pm = context.getPackageManager();\n        try {\n            if (isSystemGoogleOrMicrogSig(pm, GMS_PACKAGE_NAME)) {\n                Log.d(TAG, GMS_PACKAGE_NAME + \" found !\");\n                return GMS_PACKAGE_NAME;\n            } else {\n                Log.w(TAG, GMS_PACKAGE_NAME + \" found with another signature\");\n            }\n        } catch (PackageManager.NameNotFoundException e) {\n            Log.d(TAG, GMS_PACKAGE_NAME + \" not found\");\n        }\n        try {\n            if (isMicrogSig(pm, USER_MICROG_PACKAGE_NAME)) {\n                Log.d(TAG, USER_MICROG_PACKAGE_NAME + \" found !\");\n                return USER_MICROG_PACKAGE_NAME;\n            } else {\n                Log.w(TAG, USER_MICROG_PACKAGE_NAME + \" found with another signature\");\n            }\n        } catch (PackageManager.NameNotFoundException e) {\n            Log.d(TAG, USER_MICROG_PACKAGE_NAME + \" not found\");\n        }\n        return context.getPackageName();\n    }\n\n    private String getTargetPackage() {\n        SharedPreferences prefs = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);\n        String target;\n        if ((target = prefs.getString(PREF_TARGET, null)) != null) {\n            return target;\n        }\n        target = getTargetPackageWithoutPref();\n        prefs.edit().putString(PREF_TARGET, target).apply();\n        return target;\n    }\n\n    public MultiConnectionKeeper(Context context) {\n        this.context = context;\n        targetPackage = getTargetPackage();\n    }\n\n    public synchronized static MultiConnectionKeeper getInstance(Context context) {\n        if (INSTANCE == null)\n            INSTANCE = new MultiConnectionKeeper(context.getApplicationContext());\n        return INSTANCE;\n    }\n\n    public synchronized boolean bind(String action, ServiceConnection connection) {\n        return bind(action, connection, false);\n    }\n\n    public synchronized boolean bind(String action, ServiceConnection connection, boolean requireMicrog) {\n        Connection con = connections.get(action);\n        Log.d(TAG, \"bind(\" + action + \", \" + connection + \", \" + requireMicrog + \") has=\" + (con != null));\n        if (con != null) {\n            if (!con.forwardsConnection(connection)) {\n                con.addConnectionForward(connection);\n                if (!con.isBound())\n                    con.bind();\n            }\n        } else {\n            con = new Connection(action, requireMicrog);\n            con.addConnectionForward(connection);\n            con.bind();\n            connections.put(action, con);\n        }\n        Log.d(TAG, \"bind() : bound=\" + con.isBound());\n        return con.isBound();\n    }\n\n    public synchronized void unbind(String action, ServiceConnection connection) {\n        Log.d(TAG, \"unbind(\" + action + \", \" + connection + \")\");\n        Connection con = connections.get(action);\n        if (con != null) {\n            con.removeConnectionForward(connection);\n            if (con.isBound()) {\n                if (!con.hasForwards()) {\n                    con.unbind();\n                    connections.remove(action);\n                } else {\n                    Log.d(TAG, \"Not unbinding for \" + connection + \": has pending other bindings on action \" + action);\n                }\n            }\n        }\n    }\n\n    public class Connection {\n        private final String actionString;\n        private final boolean requireMicrog;\n        private final Set<ServiceConnection> connectionForwards = new HashSet<ServiceConnection>();\n        private boolean bound = false;\n        private boolean connected = false;\n        private IBinder binder;\n        private ComponentName component;\n        private ServiceConnection serviceConnection = new ServiceConnection() {\n            @Override\n            public void onServiceConnected(ComponentName componentName, IBinder iBinder) {\n                Log.d(TAG, \"Connection(\" + actionString + \") : ServiceConnection : \" +\n                        \"onServiceConnected(\" + componentName + \")\");\n                binder = iBinder;\n                component = componentName;\n                for (ServiceConnection connection : connectionForwards) {\n                    connection.onServiceConnected(componentName, iBinder);\n                }\n                connected = true;\n            }\n\n            @Override\n            public void onServiceDisconnected(ComponentName componentName) {\n                Log.d(TAG, \"Connection(\" + actionString + \") : ServiceConnection : \" +\n                        \"onServiceDisconnected(\" + componentName + \")\");\n                binder = null;\n                component = componentName;\n                for (ServiceConnection connection : connectionForwards) {\n                    connection.onServiceDisconnected(componentName);\n                }\n                connected = false;\n                bound = false;\n            }\n        };\n\n        public Connection(String actionString) {\n            this(actionString, false);\n        }\n\n        public Connection(String actionString, boolean requireMicrog) {\n            this.actionString = actionString;\n            this.requireMicrog = requireMicrog;\n        }\n\n        private Intent getIntent() {\n            Intent intent;\n            ResolveInfo resolveInfo;\n            PackageManager pm = context.getPackageManager();\n            if (!Objects.equals(targetPackage, context.getPackageName())) {\n                intent = new Intent(actionString).setPackage(targetPackage);\n                try {\n                    if ((resolveInfo = context.getPackageManager().resolveService(intent, 0)) != null) {\n                        if (requireMicrog && !isMicrog(resolveInfo)) {\n                            Log.w(TAG, \"GMS service found for \" + actionString + \" but looks not like microG\");\n                        } else {\n                            if (isSystemGoogleOrMicrogSig(pm, targetPackage)){\n                                Log.d(TAG, \"GMS service found for \" + actionString);\n                                return intent;\n                            } else {\n                                Log.w(TAG, \"GMS service found for \" + actionString + \" but is not system, and doesn't have microG or Google signature\");\n                            }\n                        }\n                    }\n                } catch (PackageManager.NameNotFoundException e) {\n                    Log.d(TAG, targetPackage + \" not found\");\n                }\n            }\n            intent = new Intent(actionString).setPackage(context.getPackageName());\n            if (context.getPackageManager().resolveService(intent, 0) != null) {\n                Log.d(TAG, \"Found service for \" + actionString + \" in self package, using it instead\");\n                return intent;\n            }\n            return null;\n        }\n\n        @SuppressLint(\"InlinedApi\")\n        public void bind() {\n            Log.d(TAG, \"Connection(\" + actionString + \") : bind()\");\n            Intent intent;\n            if ((intent = getIntent()) == null) {\n                Log.w(TAG, \"No service found for \" + actionString);\n                return;\n            }\n\n            int flags = Context.BIND_AUTO_CREATE | Context.BIND_DEBUG_UNBIND;\n            if (SDK_INT >= 14) {\n                flags |= Context.BIND_ADJUST_WITH_ACTIVITY;\n            }\n            bound = context.bindService(intent, serviceConnection, flags);\n            Log.d(TAG, \"Connection(\" + actionString + \") :  bind() : bindService=\" + bound);\n            if (!bound) {\n                context.unbindService(serviceConnection);\n            }\n        }\n\n        public boolean isMicrog(ResolveInfo resolveInfo) {\n            if (resolveInfo == null || resolveInfo.serviceInfo == null) return false;\n            if (resolveInfo.serviceInfo.name.startsWith(\"org.microg.\")) return true;\n            try {\n                PermissionInfo info = context.getPackageManager().getPermissionInfo(\"org.microg.gms.EXTENDED_ACCESS\", 0);\n                return info.packageName.equals(resolveInfo.serviceInfo.packageName);\n            } catch (PackageManager.NameNotFoundException e) {\n                return false;\n            }\n        }\n\n        public boolean isBound() {\n            return bound;\n        }\n\n        public IBinder getBinder() {\n            return binder;\n        }\n\n        public void unbind() {\n            Log.d(TAG, \"Connection(\" + actionString + \") : unbind()\");\n            try {\n                context.unbindService(serviceConnection);\n            } catch (IllegalArgumentException e) { // not bound (whatever reason)\n                Log.w(TAG, e);\n            }\n            bound = false;\n        }\n\n        public void addConnectionForward(ServiceConnection connection) {\n            connectionForwards.add(connection);\n            if (connected) {\n                connection.onServiceConnected(component, binder);\n            }\n        }\n\n        public void removeConnectionForward(ServiceConnection connection) {\n            connectionForwards.remove(connection);\n            if (connected) {\n                connection.onServiceDisconnected(component);\n            }\n        }\n\n        public boolean forwardsConnection(ServiceConnection connection) {\n            return connectionForwards.contains(connection);\n        }\n\n        public boolean hasForwards() {\n            return !connectionForwards.isEmpty();\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/org/microg/gms/common/api/AbstractPlayServicesClient.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.common.api;\n\nimport android.util.Log;\n\nimport com.google.android.gms.common.GooglePlayServicesClient;\nimport com.google.android.gms.common.api.GoogleApiClient;\n\nimport org.microg.gms.common.ForwardConnectionCallbacks;\nimport org.microg.gms.common.ForwardConnectionFailedListener;\n\npublic class AbstractPlayServicesClient implements GooglePlayServicesClient {\n    private static final String TAG = \"GmsPlayServicesClient\";\n\n    protected final GoogleApiClient googleApiClient;\n\n    public AbstractPlayServicesClient(GoogleApiClient googleApiClient) {\n        this.googleApiClient = googleApiClient;\n    }\n\n    public void assertConnected() {\n        if (!isConnected()) throw new IllegalStateException(\"Not connected!\");\n    }\n\n    @Override\n    public void connect() {\n        Log.d(TAG, \"connect()\");\n        googleApiClient.connect();\n    }\n\n    @Override\n    public void disconnect() {\n        Log.d(TAG, \"disconnect()\");\n        //TODO googleApiClient.disconnect();\n    }\n\n    @Override\n    public boolean isConnected() {\n        return googleApiClient.isConnected();\n    }\n\n    @Override\n    public boolean isConnecting() {\n        return googleApiClient.isConnecting();\n    }\n\n    @Override\n    public void registerConnectionCallbacks(final ConnectionCallbacks listener) {\n        googleApiClient.registerConnectionCallbacks(new ForwardConnectionCallbacks(listener));\n    }\n\n    @Override\n    public boolean isConnectionCallbacksRegistered(ConnectionCallbacks listener) {\n        return googleApiClient\n                .isConnectionCallbacksRegistered(new ForwardConnectionCallbacks(listener));\n    }\n\n    @Override\n    public void unregisterConnectionCallbacks(\n            ConnectionCallbacks listener) {\n        googleApiClient.unregisterConnectionCallbacks(new ForwardConnectionCallbacks(listener));\n    }\n\n    @Override\n    public void registerConnectionFailedListener(\n            OnConnectionFailedListener listener) {\n        googleApiClient.registerConnectionFailedListener(\n                new ForwardConnectionFailedListener(listener));\n    }\n\n    @Override\n    public boolean isConnectionFailedListenerRegistered(\n            OnConnectionFailedListener listener) {\n        return googleApiClient.isConnectionFailedListenerRegistered(\n                new ForwardConnectionFailedListener(listener));\n    }\n\n    @Override\n    public void unregisterConnectionFailedListener(\n            OnConnectionFailedListener listener) {\n        googleApiClient.unregisterConnectionFailedListener(\n                new ForwardConnectionFailedListener(listener));\n    }\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/org/microg/gms/common/api/ApiClientBuilder.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.common.api;\n\nimport android.content.Context;\nimport android.os.Looper;\n\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.internal.ConnectionCallbacks;\nimport com.google.android.gms.common.api.internal.OnConnectionFailedListener;\nimport com.google.android.gms.common.internal.ClientSettings;\n\n@Deprecated\npublic interface ApiClientBuilder<O extends Api.ApiOptions> {\n    Api.Client build(O options, Context context, Looper looper, ClientSettings clientSettings, ConnectionCallbacks callbacks, OnConnectionFailedListener connectionFailedListener);\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/org/microg/gms/common/api/BasePendingResult.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.common.api;\n\nimport android.os.Looper;\n\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.api.PendingResult;\nimport com.google.android.gms.common.api.Result;\nimport com.google.android.gms.common.api.ResultCallback;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\npublic class BasePendingResult<R extends Result> extends PendingResult<R> {\n    private final Object lock = new Object();\n    private final CountDownLatch countDownLatch = new CountDownLatch(1);\n    private final ResultCallbackHandler<R> handler;\n    private boolean canceled;\n    private R result;\n    private ResultCallback<R> resultCallback;\n\n    public BasePendingResult(Looper looper) {\n        handler = new ResultCallbackHandler<R>(looper);\n    }\n\n    private R getResult() {\n        synchronized (lock) {\n            return result;\n        }\n    }\n\n    @Override\n    public R await() {\n        try {\n            countDownLatch.await();\n        } catch (InterruptedException ignored) {\n        }\n        return getResult();\n    }\n\n    @Override\n    public R await(long time, TimeUnit unit) {\n        try {\n            countDownLatch.await(time, unit);\n        } catch (InterruptedException ignored) {\n        }\n        return getResult();\n    }\n\n    @Override\n    public void cancel() {\n        // TODO\n    }\n\n    @Override\n    public boolean isCanceled() {\n        synchronized (lock) {\n            return canceled;\n        }\n    }\n\n    public boolean isReady() {\n        return this.countDownLatch.getCount() == 0L;\n    }\n\n    @Override\n    public void setResultCallback(@NonNull ResultCallback<R> callback, long time, TimeUnit unit) {\n        synchronized (lock) {\n            if (!isCanceled()) {\n                if (isReady()) {\n                    handler.sendResultCallback(callback, getResult());\n                } else {\n                    handler.sendTimeoutResultCallback(this, unit.toMillis(time));\n                }\n            }\n        }\n    }\n\n    @Override\n    public void setResultCallback(@NonNull ResultCallback<R> callback) {\n        synchronized (lock) {\n            if (!isCanceled()) {\n                if (isReady()) {\n                    handler.sendResultCallback(callback, getResult());\n                } else {\n                    resultCallback = callback;\n                }\n            }\n        }\n    }\n\n    public void deliverResult(R result) {\n        this.result = result;\n        countDownLatch.countDown();\n\n    }\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/org/microg/gms/common/api/GoogleApiClientImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.common.api;\n\nimport android.content.Context;\nimport android.os.Bundle;\nimport android.os.Looper;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.fragment.app.FragmentActivity;\n\nimport android.util.Log;\n\nimport com.google.android.gms.common.ConnectionResult;\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.PendingResult;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.common.internal.ClientSettings;\n\nimport java.io.FileDescriptor;\nimport java.io.PrintWriter;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.TimeUnit;\n\npublic class GoogleApiClientImpl extends GoogleApiClient {\n    private static final String TAG = \"GmsApiClientImpl\";\n\n    private final Context context;\n    private final Looper looper;\n    private final ClientSettings clientSettings;\n    private final Map<Api, Api.ApiOptions> apis = new HashMap<Api, Api.ApiOptions>();\n    private final Map<Api, Api.Client> apiConnections = new HashMap<Api, Api.Client>();\n    private final Set<ConnectionCallbacks> connectionCallbacks = new HashSet<ConnectionCallbacks>();\n    private final Set<OnConnectionFailedListener> connectionFailedListeners = new HashSet<OnConnectionFailedListener>();\n    private final int clientId;\n    private final ConnectionCallbacks baseConnectionCallbacks = new ConnectionCallbacks() {\n        @Override\n        public void onConnected(Bundle connectionHint) {\n            Log.d(TAG, \"ConnectionCallbacks : onConnected()\");\n            for (ConnectionCallbacks callback : connectionCallbacks) {\n                callback.onConnected(connectionHint);\n            }\n        }\n\n        @Override\n        public void onConnectionSuspended(int cause) {\n            Log.d(TAG, \"ConnectionCallbacks : onConnectionSuspended()\");\n            for (ConnectionCallbacks callback : connectionCallbacks) {\n                callback.onConnectionSuspended(cause);\n            }\n        }\n    };\n    private final OnConnectionFailedListener baseConnectionFailedListener = new\n            OnConnectionFailedListener() {\n                @Override\n                public void onConnectionFailed(ConnectionResult result) {\n                    Log.d(TAG, \"OnConnectionFailedListener : onConnectionFailed()\");\n                    for (OnConnectionFailedListener listener : connectionFailedListeners) {\n                        listener.onConnectionFailed(result);\n                    }\n                }\n            };\n    private int usageCounter = 0;\n    private boolean shouldDisconnect = false;\n\n    public GoogleApiClientImpl(Context context, Looper looper, ClientSettings clientSettings,\n                               Map<Api<?>, Api.ApiOptions> apis,\n                               Set<ConnectionCallbacks> connectionCallbacks,\n                               Set<OnConnectionFailedListener> connectionFailedListeners, int clientId) {\n        this.context = context;\n        this.looper = looper;\n        this.clientSettings = clientSettings;\n        this.apis.putAll(apis);\n        this.connectionCallbacks.addAll(connectionCallbacks);\n        this.connectionFailedListeners.addAll(connectionFailedListeners);\n        this.clientId = clientId;\n\n        if (this.clientSettings.getSessionId() == null) {\n            this.clientSettings.setSessionId(hashCode());\n        }\n\n        for (Api api : apis.keySet()) {\n            apiConnections.put(api, api.getClientBuilder().buildClient(context, looper, clientSettings, apis.get(api), baseConnectionCallbacks, baseConnectionFailedListener));\n        }\n    }\n\n    public synchronized void incrementUsageCounter() {\n        usageCounter++;\n    }\n\n    public synchronized void decrementUsageCounter() {\n        usageCounter--;\n        if (shouldDisconnect) disconnect();\n    }\n\n    @NonNull\n    public Looper getLooper() {\n        return looper;\n    }\n\n    @Override\n    public boolean hasConnectedApi(@NonNull Api<?> api) {\n        return getApiConnection(api).isConnected();\n    }\n\n    public Api.Client getApiConnection(Api api) {\n        return apiConnections.get(api);\n    }\n\n    @NonNull\n    @Override\n    public ConnectionResult blockingConnect() {\n        return null;\n    }\n\n    @NonNull\n    @Override\n    public ConnectionResult blockingConnect(long timeout, @NonNull TimeUnit unit) {\n        return null;\n    }\n\n    @NonNull\n    @Override\n    public PendingResult<Status> clearDefaultAccountAndReconnect() {\n        return null;\n    }\n\n    @Override\n    public synchronized void connect() {\n        Log.d(TAG, \"connect()\");\n        if (isConnected() || isConnecting()) {\n            if (shouldDisconnect) {\n                shouldDisconnect = false;\n                return;\n            }\n            Log.d(TAG, \"Already connected/connecting, nothing to do\");\n            return;\n        }\n        for (Api.Client connection : apiConnections.values()) {\n            if (!connection.isConnected()) {\n                connection.connect();\n            }\n        }\n    }\n\n    @Override\n    public void connect(int signInMode) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public synchronized void disconnect() {\n        if (usageCounter > 0) {\n            shouldDisconnect = true;\n        } else {\n            Log.d(TAG, \"disconnect()\");\n            for (Api.Client connection : apiConnections.values()) {\n                if (connection.isConnected()) {\n                    connection.disconnect();\n                }\n            }\n        }\n    }\n\n    @Override\n    public void dump(@NonNull String prefix, @Nullable FileDescriptor fd, @NonNull PrintWriter writer, @Nullable String[] args) {\n        throw new UnsupportedOperationException();\n    }\n\n    @NonNull\n    @Override\n    public ConnectionResult getConnectionResult(@NonNull Api<?> api) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public synchronized boolean isConnected() {\n        for (Api.Client connection : apiConnections.values()) {\n            if (!connection.isConnected()) return false;\n        }\n        return true;\n    }\n\n    @Override\n    public synchronized boolean isConnecting() {\n        for (Api.Client connection : apiConnections.values()) {\n            if (connection.isConnecting()) return true;\n        }\n        return false;\n    }\n\n    @Override\n    public boolean isConnectionCallbacksRegistered(@NonNull ConnectionCallbacks listener) {\n        return connectionCallbacks.contains(listener);\n    }\n\n    @Override\n    public boolean isConnectionFailedListenerRegistered(@NonNull OnConnectionFailedListener listener) {\n        return connectionFailedListeners.contains(listener);\n    }\n\n    @Override\n    public synchronized void reconnect() {\n        Log.d(TAG, \"reconnect()\");\n        disconnect();\n        connect();\n    }\n\n    @Override\n    public void registerConnectionCallbacks(@NonNull GoogleApiClient.ConnectionCallbacks listener) {\n        connectionCallbacks.add(listener);\n    }\n\n    @Override\n    public void registerConnectionFailedListener(@NonNull GoogleApiClient.OnConnectionFailedListener listener) {\n        connectionFailedListeners.add(listener);\n    }\n\n    @Override\n    public void stopAutoManage(@NonNull FragmentActivity lifecycleActivity) throws IllegalStateException {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void unregisterConnectionCallbacks(@NonNull GoogleApiClient.ConnectionCallbacks listener) {\n        connectionCallbacks.remove(listener);\n    }\n\n    @Override\n    public void unregisterConnectionFailedListener(@NonNull GoogleApiClient.OnConnectionFailedListener listener) {\n        connectionFailedListeners.remove(listener);\n    }\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/org/microg/gms/common/api/GoogleApiManager.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.common.api;\n\nimport android.content.Context;\nimport android.os.Bundle;\n\nimport com.google.android.gms.common.ConnectionResult;\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.internal.ConnectionCallbacks;\nimport com.google.android.gms.common.api.GoogleApi;\nimport com.google.android.gms.common.api.internal.OnConnectionFailedListener;\nimport com.google.android.gms.common.internal.ClientSettings;\nimport com.google.android.gms.tasks.TaskCompletionSource;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\npublic class GoogleApiManager {\n    private static GoogleApiManager instance;\n    private Context context;\n    private Map<ApiInstance, Api.Client> clientMap = new HashMap<>();\n    private Map<ApiInstance, List<WaitingApiCall<?>>> waitingApiCallMap = new HashMap<>();\n\n    private GoogleApiManager(Context context) {\n        this.context = context;\n    }\n\n    public synchronized static GoogleApiManager getInstance(Context context) {\n        if (instance == null) instance = new GoogleApiManager(context);\n        return instance;\n    }\n\n    private synchronized <O extends Api.ApiOptions, A extends Api.Client> A clientForApi(GoogleApi<O> api) {\n        ApiInstance apiInstance = new ApiInstance(api);\n        if (clientMap.containsKey(apiInstance)) {\n            return (A) clientMap.get(apiInstance);\n        } else {\n            Api.Client client = api.api.getClientBuilder().buildClient(context, context.getMainLooper(), ClientSettings.createDefault(context), api.getApiOptions(), new ConnectionCallback(apiInstance), new ConnectionFailedListener(apiInstance));\n            clientMap.put(apiInstance, client);\n            waitingApiCallMap.put(apiInstance, new ArrayList<>());\n            return (A) client;\n        }\n    }\n\n    public synchronized <O extends Api.ApiOptions, R, A extends Api.Client> void scheduleTask(GoogleApi<O> api, PendingGoogleApiCall<R, A> apiCall, TaskCompletionSource<R> completionSource) {\n        A client = clientForApi(api);\n        boolean connecting = client.isConnecting();\n        boolean connected = client.isConnected();\n        if (connected) {\n            try {\n                apiCall.execute(client, completionSource);\n            } catch (Exception e) {\n                completionSource.setException(e);\n            }\n        } else {\n            waitingApiCallMap.get(new ApiInstance(api)).add(new WaitingApiCall<R>((PendingGoogleApiCall<R, Api.Client>) apiCall, completionSource));\n            if (!connecting) {\n                client.connect();\n            }\n        }\n    }\n\n    private synchronized void onInstanceConnected(ApiInstance apiInstance, Bundle connectionHint) {\n        List<WaitingApiCall<?>> waitingApiCalls = waitingApiCallMap.get(apiInstance);\n        for (WaitingApiCall<?> waitingApiCall : waitingApiCalls) {\n            try {\n                waitingApiCall.execute(clientMap.get(apiInstance));\n            } catch (Exception e) {\n                waitingApiCall.failed(e);\n            }\n        }\n        waitingApiCalls.clear();\n    }\n\n    private synchronized void onInstanceSuspended(ApiInstance apiInstance, int cause) {\n\n    }\n\n    private synchronized void onInstanceFailed(ApiInstance apiInstance, ConnectionResult result) {\n        List<WaitingApiCall<?>> waitingApiCalls = waitingApiCallMap.get(apiInstance);\n        for (WaitingApiCall<?> waitingApiCall : waitingApiCalls) {\n            waitingApiCall.failed(new RuntimeException(result.getErrorMessage()));\n        }\n        waitingApiCalls.clear();\n    }\n\n    private class ConnectionCallback implements ConnectionCallbacks {\n        private ApiInstance apiInstance;\n\n        public ConnectionCallback(ApiInstance apiInstance) {\n            this.apiInstance = apiInstance;\n        }\n\n        @Override\n        public void onConnected(Bundle connectionHint) {\n            onInstanceConnected(apiInstance, connectionHint);\n        }\n\n        @Override\n        public void onConnectionSuspended(int cause) {\n            onInstanceSuspended(apiInstance, cause);\n        }\n    }\n\n    private class ConnectionFailedListener implements OnConnectionFailedListener {\n        private ApiInstance apiInstance;\n\n        public ConnectionFailedListener(ApiInstance apiInstance) {\n            this.apiInstance = apiInstance;\n        }\n\n        @Override\n        public void onConnectionFailed(ConnectionResult result) {\n            onInstanceFailed(apiInstance, result);\n        }\n    }\n\n    private static class WaitingApiCall<R> {\n        private PendingGoogleApiCall<R, Api.Client> apiCall;\n        private TaskCompletionSource<R> completionSource;\n\n        public WaitingApiCall(PendingGoogleApiCall<R, Api.Client> apiCall, TaskCompletionSource<R> completionSource) {\n            this.apiCall = apiCall;\n            this.completionSource = completionSource;\n        }\n\n        public void execute(Api.Client client) throws Exception {\n            apiCall.execute(client, completionSource);\n        }\n\n        public void failed(Exception e) {\n            completionSource.setException(e);\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            WaitingApiCall<?> that = (WaitingApiCall<?>) o;\n\n            if (apiCall != null ? !apiCall.equals(that.apiCall) : that.apiCall != null) return false;\n            return completionSource != null ? completionSource.equals(that.completionSource) : that.completionSource == null;\n        }\n\n        @Override\n        public int hashCode() {\n            int result = apiCall != null ? apiCall.hashCode() : 0;\n            result = 31 * result + (completionSource != null ? completionSource.hashCode() : 0);\n            return result;\n        }\n    }\n\n    private static class ApiInstance {\n        private Class<?> apiClass;\n        private Api.ApiOptions apiOptions;\n\n        public ApiInstance(Class<?> apiClass, Api.ApiOptions apiOptions) {\n            this.apiClass = apiClass;\n            this.apiOptions = apiOptions;\n        }\n\n        public ApiInstance(GoogleApi<?> api) {\n            this(api.getClass(), api.getApiOptions());\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            ApiInstance that = (ApiInstance) o;\n\n            if (apiClass != null ? !apiClass.equals(that.apiClass) : that.apiClass != null) return false;\n            return apiOptions != null ? apiOptions.equals(that.apiOptions) : that.apiOptions == null;\n        }\n\n        @Override\n        public int hashCode() {\n            int result = apiClass != null ? apiClass.hashCode() : 0;\n            result = 31 * result + (apiOptions != null ? apiOptions.hashCode() : 0);\n            return result;\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/org/microg/gms/common/api/InstantPendingResult.java",
    "content": "/*\n * Copyright (C) 2017 microG Project Team\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 org.microg.gms.common.api;\n\nimport com.google.android.gms.common.api.PendingResult;\nimport com.google.android.gms.common.api.Result;\nimport com.google.android.gms.common.api.ResultCallback;\n\nimport java.util.concurrent.TimeUnit;\n\npublic class InstantPendingResult<R extends Result> extends PendingResult<R> {\n    R value;\n\n    public InstantPendingResult(R value) {\n        this.value = value;\n    }\n\n    @Override\n    public R await() {\n        return value;\n    }\n\n    @Override\n    public R await(long time, TimeUnit unit) {\n        return value;\n    }\n\n    @Override\n    public void cancel() {\n\n    }\n\n    @Override\n    public boolean isCanceled() {\n        return false;\n    }\n\n    @Override\n    public void setResultCallback(ResultCallback<R> callback, long time, TimeUnit unit) {\n        callback.onResult(value);\n    }\n\n    @Override\n    public void setResultCallback(ResultCallback<R> callback) {\n        callback.onResult(value);\n    }\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/org/microg/gms/common/api/PendingGoogleApiCall.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.common.api;\n\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.tasks.TaskCompletionSource;\n\npublic interface PendingGoogleApiCall<R, A extends Api.Client> {\n    void execute(A client, TaskCompletionSource<R> completionSource) throws Exception;\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/org/microg/gms/common/api/ResultCallbackHandler.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.common.api;\n\nimport android.os.Handler;\nimport android.os.Looper;\nimport android.os.Message;\nimport android.util.Log;\n\nimport com.google.android.gms.common.api.Result;\nimport com.google.android.gms.common.api.ResultCallback;\n\nclass ResultCallbackHandler<R extends Result> extends Handler {\n    private static final String TAG = \"GmsResultCbackHandler\";\n    public static final int CALLBACK_ON_COMPLETE = 1;\n    public static final int CALLBACK_ON_TIMEOUT = 2;\n\n    public ResultCallbackHandler(Looper looper) {\n        super(looper);\n    }\n\n    @Override\n    public void handleMessage(Message msg) {\n        switch (msg.what) {\n            case CALLBACK_ON_COMPLETE:\n                OnCompleteObject<R> o = (OnCompleteObject<R>) msg.obj;\n                Log.d(TAG, \"handleMessage() : onResult(\" + o.result + \")\");\n                o.callback.onResult(o.result);\n                break;\n            case CALLBACK_ON_TIMEOUT:\n                // TODO\n                break;\n        }\n    }\n\n    public void sendResultCallback(ResultCallback<R> callback, R result) {\n        Message message = new Message();\n        message.what = CALLBACK_ON_COMPLETE;\n        message.obj = new OnCompleteObject<R>(callback, result);\n        sendMessage(message);\n    }\n\n    public void sendTimeoutResultCallback(BasePendingResult pendingResult, long millis) {\n\n    }\n\n    public static class OnCompleteObject<R extends Result> {\n        public ResultCallback<R> callback;\n        public R result;\n\n        public OnCompleteObject(ResultCallback<R> callback, R result) {\n            this.callback = callback;\n            this.result = result;\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/org/microg/gms/common/api/ReturningGoogleApiCall.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.common.api;\n\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.tasks.TaskCompletionSource;\n\npublic interface ReturningGoogleApiCall<R, A extends Api.Client> extends PendingGoogleApiCall<R, A> {\n    R execute(A client) throws Exception;\n\n    @Override\n    default void execute(A client, TaskCompletionSource<R> completionSource) {\n        try {\n            completionSource.setResult(execute(client));\n        } catch (Exception e) {\n            completionSource.setException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/org/microg/gms/common/api/VoidReturningGoogleApiCall.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.common.api;\n\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.tasks.TaskCompletionSource;\n\npublic interface VoidReturningGoogleApiCall<A extends Api.Client> extends PendingGoogleApiCall<Void, A>{\n    void execute(A client) throws Exception;\n\n    @Override\n    default void execute(A client, TaskCompletionSource<Void> completionSource) {\n        try {\n            execute(client);\n            completionSource.setResult(null);\n        } catch (Exception e) {\n            completionSource.setException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-base/src/main/java/org/microg/gms/signin/SignInClientImpl.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.signin;\n\nimport android.accounts.Account;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.IBinder;\nimport android.util.Log;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.auth.api.signin.internal.Storage;\nimport com.google.android.gms.common.ConnectionResult;\nimport com.google.android.gms.common.Feature;\nimport com.google.android.gms.common.api.Scope;\nimport com.google.android.gms.common.internal.BaseGmsClient;\nimport com.google.android.gms.common.internal.IAccountAccessor;\nimport com.google.android.gms.common.internal.ResolveAccountRequest;\nimport com.google.android.gms.signin.SignInClient;\nimport com.google.android.gms.signin.internal.ISignInCallbacks;\nimport com.google.android.gms.signin.internal.ISignInService;\nimport com.google.android.gms.signin.internal.SignInRequest;\nimport com.google.android.gms.signin.internal.SignInResponse;\nimport org.microg.gms.auth.AuthConstants;\nimport org.microg.gms.common.GmsClient;\nimport org.microg.gms.common.GmsService;\nimport com.google.android.gms.common.internal.ClientSettings;\nimport com.google.android.gms.common.api.internal.ConnectionCallbacks;\nimport com.google.android.gms.common.api.internal.OnConnectionFailedListener;\n\nimport java.io.FileDescriptor;\nimport java.io.PrintWriter;\nimport java.util.Collections;\nimport java.util.Set;\n\npublic class SignInClientImpl extends GmsClient<ISignInService> implements SignInClient {\n    private static final String TAG = \"SignInClientImpl\";\n    private final int sessionId;\n    private final Account account;\n\n    public SignInClientImpl(Context context, ClientSettings clientSettings, ConnectionCallbacks callbacks, OnConnectionFailedListener connectionFailedListener) {\n        super(context, callbacks, connectionFailedListener, GmsService.SIGN_IN.ACTION);\n        serviceId = GmsService.SIGN_IN.SERVICE_ID;\n\n        account = clientSettings.getAccountOrDefault();\n        extras.putParcelable(\"com.google.android.gms.signin.internal.clientRequestedAccount\", account);\n\n        sessionId = clientSettings.getSessionId();\n        extras.putInt(\"com.google.android.gms.common.internal.ClientSettings.sessionId\", sessionId);\n\n        extras.putBoolean(\"com.google.android.gms.signin.internal.offlineAccessRequested\", false);\n        extras.putBoolean(\"com.google.android.gms.signin.internal.idTokenRequested\", false);\n        extras.putString(\"com.google.android.gms.signin.internal.serverClientId\", null);\n        extras.putBoolean(\"com.google.android.gms.signin.internal.usePromptModeForAuthCode\", true);\n        extras.putBoolean(\"com.google.android.gms.signin.internal.forceCodeForRefreshToken\", false);\n        extras.putString(\"com.google.android.gms.signin.internal.hostedDomain\", null);\n        extras.putString(\"com.google.android.gms.signin.internal.logSessionId\", null);\n        extras.putBoolean(\"com.google.android.gms.signin.internal.waitForAccessTokenRefresh\", false);\n\n        if (clientSettings.getRealClientPackageName() != null && !context.getPackageName().equals(clientSettings.getRealClientPackageName())) {\n            extras.putString(\"com.google.android.gms.signin.internal.realClientPackageName\", clientSettings.getRealClientPackageName());\n        }\n    }\n\n    @Override\n    protected ISignInService interfaceFromBinder(IBinder binder) {\n        return ISignInService.Stub.asInterface(binder);\n    }\n\n    @Override\n    public void clearAccountFromSessionStore() {\n        try {\n            getServiceInterface().clearAccountFromSessionStore(sessionId);\n        } catch (Exception e) {\n            Log.w(TAG, e);\n        }\n    }\n\n    @Override\n    public void saveDefaultAccount(@NonNull IAccountAccessor accountAccessor, boolean crossClient) {\n        try {\n            getServiceInterface().saveDefaultAccount(accountAccessor, sessionId, crossClient);\n        } catch (Exception e) {\n            Log.w(TAG, e);\n        }\n    }\n\n    @Override\n    public void signIn(@NonNull ISignInCallbacks callbacks) {\n        try {\n            SignInRequest request = new SignInRequest();\n            request.request = new ResolveAccountRequest();\n            request.request.account = account;\n            request.request.sessionId = sessionId;\n            if (account.name.equals(AuthConstants.DEFAULT_ACCOUNT)) {\n                request.request.signInAccountHint = Storage.getInstance(getContext()).getSavedDefaultGoogleSignInAccount();\n            }\n            getServiceInterface().signIn(request, callbacks);\n        } catch (Exception e) {\n            Log.w(TAG, e);\n            try {\n                SignInResponse response = new SignInResponse();\n                response.connectionResult = new ConnectionResult(ConnectionResult.INTERNAL_ERROR);\n                callbacks.onSignIn(response);\n            } catch (Exception ignored) {\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-basement/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2015 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\nandroid {\n    namespace \"com.google.android.gms.common\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    aidlPackagedList \"com/google/android/gms/common/api/Status.aidl\"\n    aidlPackagedList \"com/google/android/gms/common/ConnectionResult.aidl\"\n    aidlPackagedList \"com/google/android/gms/common/internal/IAccountAccessor.aidl\"\n    aidlPackagedList \"com/google/android/gms/common/internal/ICancelToken.aidl\"\n    aidlPackagedList \"com/google/android/gms/common/server/FavaDiagnosticsEntity.aidl\"\n    aidlPackagedList \"com/google/android/gms/dynamic/IObjectWrapper.aidl\"\n\n    buildFeatures {\n        aidl = true\n        buildConfig = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n        buildConfigField \"int\", \"VERSION_CODE\", \"$appVersionCode\"\n        consumerProguardFile 'consumer-rules.pro'\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n}\n\napply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG implementation of play-services-basement'\n\ndependencies {\n    // Dependencies from play-services-basement:18.8.0\n    api 'androidx.collection:collection:1.0.0'\n    api 'androidx.core:core:1.2.0'\n    api 'androidx.fragment:fragment:1.1.0'\n    // TODO: Dependencies from play-services-stats:17.1.0\n    api 'androidx.legacy:legacy-support-core-utils:1.0.0'\n\n    annotationProcessor project(':safe-parcel-processor')\n}\n"
  },
  {
    "path": "play-services-basement/consumer-rules.pro",
    "content": "# SPDX-FileCopyrightText: 2023 microG Project Team\n# SPDX-License-Identifier: CC0-1.0\n\n# Keep AutoSafeParcelables\n-keep public class * extends org.microg.safeparcel.AutoSafeParcelable {\n    @com.google.android.gms.common.internal.safeparcel.SafeParcelable$Field *;\n    @org.microg.safeparcel.SafeParceled *;\n}\n\n# Keep asInterface method cause it's accessed from SafeParcel\n-keepattributes InnerClasses\n-keep public class * extends android.os.IInterface {\n    public static * asInterface(android.os.IBinder);\n}\n-keep public class * extends android.os.Binder { public static *; }\n\n# Keep name of SafeParcelables and their creators\n-keepnames public class * implements com.google.android.gms.common.internal.safeparcel.SafeParcelable\n-keepnames public class * implements com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter"
  },
  {
    "path": "play-services-basement/ktx/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'kotlin-android'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\ndependencies {\n    api project(\":play-services-basement\")\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion\"\n}\n\nandroid {\n    namespace \"org.microg.gms.basement.ktx\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    sourceSets {\n        main.java.srcDirs += 'src/main/kotlin'\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n\n    kotlinOptions {\n        jvmTarget = 1.8\n    }\n}\n\napply from: '../../gradle/publish-android.gradle'\n\ndescription = 'microG kotlin extensions for play-services-basement'\n"
  },
  {
    "path": "play-services-basement/ktx/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2021, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<manifest />\n"
  },
  {
    "path": "play-services-basement/ktx/src/main/kotlin/com/google/android/gms/dynamic/ObjectWrapper.kt",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 com.google.android.gms.dynamic\n\ninline fun <reified T> IObjectWrapper?.unwrap(): T? = ObjectWrapper.unwrapTyped(this, T::class.java)\n"
  },
  {
    "path": "play-services-basement/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2016 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <application>\n        <meta-data\n                android:name=\"com.google.android.gms.version\"\n                android:value=\"@integer/google_play_services_version\"/>\n    </application>\n</manifest>\n"
  },
  {
    "path": "play-services-basement/src/main/aidl/com/google/android/gms/common/ConnectionResult.aidl",
    "content": "package com.google.android.gms.common;\n\nparcelable ConnectionResult;"
  },
  {
    "path": "play-services-basement/src/main/aidl/com/google/android/gms/common/GoogleCertificatesLookupQuery.aidl",
    "content": "package com.google.android.gms.common;\n\nparcelable GoogleCertificatesLookupQuery;"
  },
  {
    "path": "play-services-basement/src/main/aidl/com/google/android/gms/common/GoogleCertificatesLookupResponse.aidl",
    "content": "package com.google.android.gms.common;\n\nparcelable GoogleCertificatesLookupResponse;"
  },
  {
    "path": "play-services-basement/src/main/aidl/com/google/android/gms/common/GoogleCertificatesQuery.aidl",
    "content": "package com.google.android.gms.common;\n\nparcelable GoogleCertificatesQuery;"
  },
  {
    "path": "play-services-basement/src/main/aidl/com/google/android/gms/common/api/ApiMetadata.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.api;\n\nparcelable ApiMetadata;"
  },
  {
    "path": "play-services-basement/src/main/aidl/com/google/android/gms/common/api/ComplianceOptions.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.api;\n\nparcelable ComplianceOptions;"
  },
  {
    "path": "play-services-basement/src/main/aidl/com/google/android/gms/common/api/Scope.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.api;\n\nparcelable Scope;"
  },
  {
    "path": "play-services-basement/src/main/aidl/com/google/android/gms/common/api/Status.aidl",
    "content": "package com.google.android.gms.common.api;\n\nparcelable Status;"
  },
  {
    "path": "play-services-basement/src/main/aidl/com/google/android/gms/common/internal/ConnectionInfo.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.internal;\nparcelable ConnectionInfo;\n"
  },
  {
    "path": "play-services-basement/src/main/aidl/com/google/android/gms/common/internal/GetServiceRequest.aidl",
    "content": "package com.google.android.gms.common.internal;\n\nparcelable GetServiceRequest;\n"
  },
  {
    "path": "play-services-basement/src/main/aidl/com/google/android/gms/common/internal/IAccountAccessor.aidl",
    "content": "package com.google.android.gms.common.internal;\n\ninterface IAccountAccessor {\n    Account getAccount() = 1;\n}"
  },
  {
    "path": "play-services-basement/src/main/aidl/com/google/android/gms/common/internal/ICancelToken.aidl",
    "content": "package com.google.android.gms.common.internal;\n\ninterface ICancelToken {\n    void cancel();\n}\n"
  },
  {
    "path": "play-services-basement/src/main/aidl/com/google/android/gms/common/internal/ICertData.aidl",
    "content": "package com.google.android.gms.common.internal;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\n\ninterface ICertData {\n    IObjectWrapper getWrappedBytes();\n    int remoteHashCode();\n}"
  },
  {
    "path": "play-services-basement/src/main/aidl/com/google/android/gms/common/internal/IGmsCallbacks.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.internal;\n\nimport android.os.Bundle;\nimport com.google.android.gms.common.internal.ConnectionInfo;\n\ninterface IGmsCallbacks {\n    void onPostInitComplete(int statusCode, IBinder binder, in Bundle params);\n    void onAccountValidationComplete(int statusCode, in Bundle params);\n    void onPostInitCompleteWithConnectionInfo(int statusCode, IBinder binder, in ConnectionInfo info);\n}\n"
  },
  {
    "path": "play-services-basement/src/main/aidl/com/google/android/gms/common/internal/IGmsServiceBroker.aidl",
    "content": "package com.google.android.gms.common.internal;\n\nimport android.os.Bundle;\n\nimport com.google.android.gms.common.internal.IGmsCallbacks;\nimport com.google.android.gms.common.internal.GetServiceRequest;\nimport com.google.android.gms.common.internal.ValidateAccountRequest;\n\ninterface IGmsServiceBroker {\n    void getPlusService(IGmsCallbacks callback, int code, String packageName, String authPackage, in String[] scopes, String accountName, in Bundle params) = 0;\n    void getPanoramaService(IGmsCallbacks callback, int code, String packageName, in Bundle params) = 1;\n    void getAppDataSearchService(IGmsCallbacks callback, int code, String packageName) = 2;\n    void getWalletService(IGmsCallbacks callback, int code) = 3;\n    void getPeopleService(IGmsCallbacks callback, int code, String str, in Bundle params) = 4;\n    void getReportingService(IGmsCallbacks callback, int code, String str, in Bundle params) = 5;\n    void getLocationService(IGmsCallbacks callback, int code, String str, in Bundle params) = 6;\n    void getGoogleLocationManagerService(IGmsCallbacks callback, int code, String str, in Bundle params) = 7;\n    void getGamesService(IGmsCallbacks callback, int code, String packageName, String accountName, in String[] scopes, String gamePackageName, IBinder popupWindowToken, String desiredLocale, in Bundle params) = 8;\n    void getAppStateService(IGmsCallbacks callback, int code, String packageName, String accountName, in String[] scopes) = 9;\n    void getPlayLogService(IGmsCallbacks callback, int code, String packageName, in Bundle params) = 10;\n    void getAdMobService(IGmsCallbacks callback, int code, String packageName, in Bundle params) = 11;\n    void getDroidGuardService(IGmsCallbacks callback, int code, String packageName, in Bundle params) = 12;\n    void getLockboxService(IGmsCallbacks callback, int code, String packageName, in Bundle params) = 13;\n    void getCastMirroringService(IGmsCallbacks callback, int code, String packageName, in Bundle params) = 14;\n    void getNetworkQualityService(IGmsCallbacks callback, int code, String packageName, in Bundle params) = 15;\n    void getGoogleIdentityService(IGmsCallbacks callback, int code, String packageName, in Bundle params) = 16;\n    void getGoogleFeedbackService(IGmsCallbacks callback, int code, String packageName, in Bundle params) = 17;\n    void getCastService(IGmsCallbacks callback, int code, String packageName, IBinder binder, in Bundle params) = 18;\n    void getDriveService(IGmsCallbacks callback, int code, String packageName, in String[] args, String str2, in Bundle params) = 19;\n    void getLightweightAppDataSearchService(IGmsCallbacks callback, int code, String packageName) = 20;\n    void getSearchAdministrationService(IGmsCallbacks callback, int code, String packageName) = 21;\n    void getAutoBackupService(IGmsCallbacks callback, int code, String packageName, in Bundle params) = 22;\n    void getAddressService(IGmsCallbacks callback, int code, String packageName) = 23;\n\n    void getWalletServiceWithPackageName(IGmsCallbacks callback, int code, String packageName) = 41;\n\n    void getService(IGmsCallbacks callback, in GetServiceRequest request) = 45;\n    void validateAccount(IGmsCallbacks callback, in ValidateAccountRequest request) = 46;\n}\n"
  },
  {
    "path": "play-services-basement/src/main/aidl/com/google/android/gms/common/internal/IGoogleCertificatesApi.aidl",
    "content": "package com.google.android.gms.common.internal;\n\nimport com.google.android.gms.common.GoogleCertificatesLookupQuery;\nimport com.google.android.gms.common.GoogleCertificatesLookupResponse;\nimport com.google.android.gms.common.GoogleCertificatesQuery;\nimport com.google.android.gms.dynamic.IObjectWrapper;\n\ninterface IGoogleCertificatesApi {\n    IObjectWrapper getGoogleCertificates() = 0;\n    IObjectWrapper getGoogleReleaseCertificates() = 1;\n    boolean isGoogleReleaseSigned(String packageName, IObjectWrapper certData) = 2;\n    boolean isGoogleSigned(String packageName, IObjectWrapper certData) = 3;\n    boolean isGoogleOrPlatformSigned(in GoogleCertificatesQuery query, IObjectWrapper packageManager) = 4;\n    GoogleCertificatesLookupResponse isPackageGoogleOrPlatformSigned(in GoogleCertificatesLookupQuery query) = 5;\n    boolean isPackageGoogleOrPlatformSignedAvailable() = 6;\n    GoogleCertificatesLookupResponse queryPackageSigned(in GoogleCertificatesLookupQuery query) = 7;\n    boolean isFineGrainedPackageVerificationAvailable() = 8;\n}"
  },
  {
    "path": "play-services-basement/src/main/aidl/com/google/android/gms/common/internal/ValidateAccountRequest.aidl",
    "content": "package com.google.android.gms.common.internal;\n\nparcelable ValidateAccountRequest;\n"
  },
  {
    "path": "play-services-basement/src/main/aidl/com/google/android/gms/dynamic/IObjectWrapper.aidl",
    "content": "package com.google.android.gms.dynamic;\n\n/**\n * The concrete class implementing IObjectWrapper must have exactly one declared private field \n * for the wrapped object.  Preferably, this is an instance of the ObjectWrapper<T> class.\n */\ninterface IObjectWrapper {\n}\n"
  },
  {
    "path": "play-services-basement/src/main/aidl/com/google/android/gms/dynamite/IDynamiteLoader.aidl",
    "content": "package com.google.android.gms.dynamite;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\n\ninterface IDynamiteLoader {\n    int getModuleVersion(IObjectWrapper wrappedContext, String moduleId) = 0;\n    int getModuleVersion2(IObjectWrapper wrappedContext, String moduleId, boolean updateConfigIfRequired) = 2;\n    int getModuleVersionV2(IObjectWrapper wrappedContext, String moduleId, boolean updateConfigIfRequired) = 4;\n    IObjectWrapper getModuleVersionV3(IObjectWrapper wrappedContext, String moduleId, boolean updateConfigIfRequired, long requestStartTime) = 6;\n\n    IObjectWrapper createModuleContext(IObjectWrapper wrappedContext, String moduleId, int minVersion) = 1;\n    IObjectWrapper createModuleContextV2(IObjectWrapper wrappedContext, String moduleId, int minVersion) = 3;\n    IObjectWrapper createModuleContextV3(IObjectWrapper wrappedContext, String moduleId, int minVersion, IObjectWrapper cursorWrapped) = 7;\n\n    int getIDynamiteLoaderVersion() = 5;\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/actions/package-info.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n/**\n * Contains classes for Google Search Actions.\n */\npackage com.google.android.gms.actions;\n"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/common/ConnectionResult.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2016 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.common;\n\nimport android.app.Activity;\nimport android.app.PendingIntent;\nimport android.content.Intent;\nimport android.content.IntentSender;\nimport android.os.Parcel;\nimport android.text.TextUtils;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport java.util.Arrays;\n\n/**\n * Contains all possible error codes for when a client fails to connect to Google Play services.\n * These error codes are used by {@link GoogleApiClient.OnConnectionFailedListener}.\n */\n@SafeParcelable.Class\npublic class ConnectionResult extends AbstractSafeParcelable {\n    /**\n     * The connection was successful.\n     */\n    public static final int SUCCESS = 0;\n    /**\n     * Google Play services is missing on this device. The calling activity should pass this error\n     * code to {@link GooglePlayServicesUtil#getErrorDialog(int, Activity, int)} to get a localized\n     * error dialog that will resolve the error when shown.\n     */\n    public static final int SERVICE_MISSING = 1;\n    /**\n     * The installed version of Google Play services is out of date. The calling activity should\n     * pass this error code to {@link GooglePlayServicesUtil#getErrorDialog(int, Activity, int)} to\n     * get a localized error dialog that will resolve the error when shown.\n     */\n    public static final int SERVICE_VERSION_UPDATE_REQUIRED = 2;\n    /**\n     * The installed version of Google Play services has been disabled on this device. The calling\n     * activity should pass this error code to\n     * {@link GooglePlayServicesUtil#getErrorDialog(int, Activity, int)} to get a localized error\n     * dialog that will resolve the error when shown.\n     */\n    public static final int SERVICE_DISABLED = 3;\n    /**\n     * The client attempted to connect to the service but the user is not signed in. The client may\n     * choose to continue without using the API or it may call\n     * {@link #startResolutionForResult(Activity, int)} to prompt the user to sign in. After the\n     * sign in activity returns with {@link Activity#RESULT_OK} further attempts to connect should\n     * succeed.\n     */\n    public static final int SIGN_IN_REQUIRED = 4;\n    /**\n     * The client attempted to connect to the service with an invalid account name specified.\n     */\n    public static final int INVALID_ACCOUNT = 5;\n    /**\n     * Completing the connection requires some form of resolution. A resolution will be available\n     * to be started with {@link #startResolutionForResult(Activity, int)}. If the result returned\n     * is {@link Activity#RESULT_OK}, then further attempts to connect should either complete or\n     * continue on to the next issue that needs to be resolved.\n     */\n    public static final int RESOLUTION_REQUIRED = 6;\n    /**\n     * A network error occurred. Retrying should resolve the problem.\n     */\n    public static final int NETWORK_ERROR = 7;\n    /**\n     * An internal error occurred. Retrying should resolve the problem.\n     */\n    public static final int INTERNAL_ERROR = 8;\n    /**\n     * The version of the Google Play services installed on this device is not authentic.\n     */\n    public static final int SERVICE_INVALID = 9;\n    /**\n     * The application is misconfigured. This error is not recoverable and will be treated as\n     * fatal. The developer should look at the logs after this to determine more actionable\n     * information.\n     */\n    public static final int DEVELOPER_ERROR = 10;\n    /**\n     * The application is not licensed to the user. This error is not recoverable and will be\n     * treated as fatal.\n     */\n    public static final int LICENSE_CHECK_FAILED = 11;\n    /**\n     * The client canceled the connection by calling {@link GoogleApiClient#disconnect()}.\n     * Only returned by {@link GoogleApiClient#blockingConnect()}.\n     */\n    public static final int CANCELED = 13;\n    /**\n     * The timeout was exceeded while waiting for the connection to complete. Only returned by\n     * {@link GoogleApiClient#blockingConnect()}.\n     */\n    public static final int TIMEOUT = 14;\n    /**\n     * An interrupt occurred while waiting for the connection complete. Only returned by\n     * {@link GoogleApiClient#blockingConnect()}.\n     */\n    public static final int INTERRUPTED = 15;\n    /**\n     * One of the API components you attempted to connect to is not available. The API will not\n     * work on this device, and updating Google Play services will not likely solve the problem.\n     * Using the API on the device should be avoided.\n     */\n    public static final int API_UNAVAILABLE = 16;\n    /**\n     * The client attempted to connect to the service but the user is not signed in. An error may have occurred when signing in the user and the error can not\n     * be recovered with any user interaction. Alternately, the API may have been requested with {@link GoogleApiClient.Builder#addApiIfAvailable(Api, Scope...)}\n     * and it may be the case that no required APIs needed authentication, so authentication did not occur.\n     * <p>\n     * When seeing this error code, there is no resolution for the sign-in failure.\n     */\n    public static final int SIGN_IN_FAILED = 17;\n    /**\n     * Google Play service is currently being updated on this device.\n     */\n    public static final int SERVICE_UPDATING = 18;\n\n    /**\n     * Service doesn't have one or more required permissions.\n     */\n    public static final int SERVICE_MISSING_PERMISSION = 19;\n    /**\n     * The current user profile is restricted and cannot use authenticated features. (Jelly Bean MR2+ Restricted Profiles for Android tablets)\n     */\n    public static final int RESTRICTED_PROFILE = 20;\n    /**\n     * There was a user-resolvable issue connecting to Google Play services, but when attempting to start the resolution, the activity was not found.\n     * <p>\n     * This can occur when attempting to resolve issues connecting to Google Play services on emulators with Google APIs but not Google Play Store.\n     */\n    public static final int RESOLUTION_ACTIVITY_NOT_FOUND = 22;\n    /**\n     * The API being requested is disabled on this device for this application. Trying again at a later time may succeed.\n     */\n    public static final int API_DISABLED = 23;\n    /**\n     * The API being requested is disabled for this connection attempt, but may work for other connections.\n     */\n    public static final int API_DISABLED_FOR_CONNECTION = 24;\n\n    /**\n     * The Drive API requires external storage (such as an SD card), but no external storage is\n     * mounted. This error is recoverable if the user installs external storage (if none is\n     * present) and ensures that it is mounted (which may involve disabling USB storage mode,\n     * formatting the storage, or other initialization as required by the device).\n     * <p/>\n     * This error should never be returned on a device with emulated external storage. On devices\n     * with emulated external storage, the emulated \"external storage\" is always present regardless\n     * of whether the device also has removable storage.\n     */\n    @Deprecated\n    public static final int DRIVE_EXTERNAL_STORAGE_REQUIRED = 1500;\n\n    @Field(1)\n    int versionCode = 1;\n    @Field(value = 2, getterName = \"getErrorCode\")\n    private int statusCode;\n    @Field(value = 3, getterName = \"getResolution\")\n    private PendingIntent resolution;\n    @Field(value = 4, getterName = \"getErrorMessage\")\n    private String message;\n\n    private ConnectionResult() {\n    }\n\n    /**\n     * Creates a connection result.\n     *\n     * @param statusCode The status code.\n     */\n    public ConnectionResult(int statusCode) {\n        this(statusCode, null);\n    }\n\n    /**\n     * Creates a connection result.\n     *\n     * @param statusCode The status code.\n     * @param resolution A pending intent that will resolve the issue when started, or null.\n     */\n    public ConnectionResult(int statusCode, PendingIntent resolution) {\n        this(statusCode, resolution, getStatusString(statusCode));\n    }\n\n    /**\n     * Creates a connection result.\n     *\n     * @param statusCode The status code.\n     * @param resolution A pending intent that will resolve the issue when started, or null.\n     * @param message    An additional error message for the connection result, or null.\n     */\n    @Constructor\n    public ConnectionResult(@Param(2) int statusCode, @Param(3) PendingIntent resolution, @Param(4) String message) {\n        this.statusCode = statusCode;\n        this.resolution = resolution;\n        this.message = message;\n    }\n\n    static String getStatusString(int statusCode) {\n        switch (statusCode) {\n            case -1:\n                return \"UNKNOWN\";\n            case 0:\n                return \"SUCCESS\";\n            case 1:\n                return \"SERVICE_MISSING\";\n            case 2:\n                return \"SERVICE_VERSION_UPDATE_REQUIRED\";\n            case 3:\n                return \"SERVICE_DISABLED\";\n            case 4:\n                return \"SIGN_IN_REQUIRED\";\n            case 5:\n                return \"INVALID_ACCOUNT\";\n            case 6:\n                return \"RESOLUTION_REQUIRED\";\n            case 7:\n                return \"NETWORK_ERROR\";\n            case 8:\n                return \"INTERNAL_ERROR\";\n            case 9:\n                return \"SERVICE_INVALID\";\n            case 10:\n                return \"DEVELOPER_ERROR\";\n            case 11:\n                return \"LICENSE_CHECK_FAILED\";\n            case 13:\n                return \"CANCELED\";\n            case 14:\n                return \"TIMEOUT\";\n            case 15:\n                return \"INTERRUPTED\";\n            case 16:\n                return \"API_UNAVAILABLE\";\n            case 17:\n                return \"SIGN_IN_FAILED\";\n            case 18:\n                return \"SERVICE_UPDATING\";\n            case 19:\n                return \"SERVICE_MISSING_PERMISSION\";\n            case 20:\n                return \"RESTRICTED_PROFILE\";\n            case 21:\n                return \"API_VERSION_UPDATE_REQUIRED\";\n            case 42:\n                return \"UPDATE_ANDROID_WEAR\";\n            case 99:\n                return \"UNFINISHED\";\n            case 1500:\n                return \"DRIVE_EXTERNAL_STORAGE_REQUIRED\";\n            default:\n                return \"UNKNOWN_ERROR_CODE(\" + statusCode + \")\";\n        }\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (o == this) {\n            return true;\n        } else if (!(o instanceof ConnectionResult)) {\n            return false;\n        } else {\n            ConnectionResult r = (ConnectionResult) o;\n            return statusCode == r.statusCode && resolution == null ? r.resolution == null : resolution.equals(r.resolution) && TextUtils.equals(message, r.message);\n        }\n    }\n\n    /**\n     * Indicates the type of error that interrupted connection.\n     *\n     * @return the error code, or {@link #SUCCESS} if no error occurred.\n     */\n    public int getErrorCode() {\n        return statusCode;\n    }\n\n    /**\n     * Returns an error message for connection result.\n     *\n     * @return the message\n     */\n    public String getErrorMessage() {\n        return message;\n    }\n\n    /**\n     * A pending intent to resolve the connection failure. This intent can be started with\n     * {@link Activity#startIntentSenderForResult(IntentSender, int, Intent, int, int, int)} to\n     * present UI to solve the issue.\n     *\n     * @return The pending intent to resolve the connection failure.\n     */\n    public PendingIntent getResolution() {\n        return resolution;\n    }\n\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(new Object[]{statusCode, resolution, message});\n    }\n\n    /**\n     * Returns {@code true} if calling {@link #startResolutionForResult(Activity, int)} will start\n     * any intents requiring user interaction.\n     *\n     * @return {@code true} if there is a resolution that can be started.\n     */\n    public boolean hasResolution() {\n        return statusCode != 0 && resolution != null;\n    }\n\n    /**\n     * Returns {@code true} if the connection was successful.\n     *\n     * @return {@code true} if the connection was successful, {@code false} if there was an error.\n     */\n    public boolean isSuccess() {\n        return statusCode == 0;\n    }\n\n    /**\n     * Resolves an error by starting any intents requiring user interaction. See\n     * {@link #SIGN_IN_REQUIRED}, and {@link #RESOLUTION_REQUIRED}.\n     *\n     * @param activity    An Activity context to use to resolve the issue. The activity's\n     *                    {@link Activity#onActivityResult} method will be invoked after the user\n     *                    is done. If the resultCode is {@link Activity#RESULT_OK}, the application\n     *                    should try to connect again.\n     * @param requestCode The request code to pass to {@link Activity#onActivityResult}.\n     * @throws IntentSender.SendIntentException If the resolution intent has been canceled or is no\n     *                                          longer able to execute the request.\n     */\n    public void startResolutionForResult(Activity activity, int requestCode) throws\n            IntentSender.SendIntentException {\n        if (hasResolution()) {\n            activity.startIntentSenderForResult(resolution.getIntentSender(), requestCode, null, 0, 0, 0);\n        }\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<ConnectionResult> CREATOR = findCreator(ConnectionResult.class);\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/common/Feature.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class Feature extends AbstractSafeParcelable {\n    @Field(value = 1, getterName = \"getName\")\n    private final String name;\n    @Field(value = 2, defaultValue = \"0\")\n    final int oldVersion;\n    @Field(value = 3, getterName = \"getVersion\", defaultValue = \"-1\")\n    private final long version;\n    @Field(value = 4, defaultValue = \"false\")\n    final boolean fullyRolledOut;\n\n    public Feature(String name) {\n        this(name, 1);\n    }\n\n    public Feature(String name, long version) {\n        this(name, version, false);\n    }\n\n    public Feature(String name, long version, boolean fullyRolledOut) {\n        this(name, -1, version, fullyRolledOut);\n    }\n\n    @Constructor\n    Feature(@Param(1) String name, @Param(2) int oldVersion, @Param(3) long version, @Param(4) boolean fullyRolledOut) {\n        this.name = name;\n        this.oldVersion = oldVersion;\n        this.version = version;\n        this.fullyRolledOut = fullyRolledOut;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public long getVersion() {\n        if (version == -1) return oldVersion;\n        return version;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"Feature\").value(name).value(getVersion()).end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<Feature> CREATOR = findCreator(Feature.class);\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/common/GoogleCertificatesLookupQuery.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common;\n\nimport android.content.Context;\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.dynamic.ObjectWrapper;\n\n@SafeParcelable.Class\npublic class GoogleCertificatesLookupQuery extends AbstractSafeParcelable {\n    @Field(value = 1, getterName = \"getCallingPackage\")\n    String callingPackage;\n    @Field(2)\n    boolean allowTestKeys;\n    @Field(3)\n    boolean ignoreTestKeysOverride;\n    @Field(4)\n    IObjectWrapper contextWrapper;\n    private Context context;\n    @Field(5)\n    boolean isChimeraPackage;\n    @Field(6)\n    boolean includeHashesInErrorMessage;\n\n    public String getCallingPackage() {\n        return callingPackage;\n    }\n\n    public Context getContext() {\n        if (context == null && contextWrapper != null) {\n            context = ObjectWrapper.unwrapTyped(contextWrapper, Context.class);\n        }\n        return context;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<GoogleCertificatesLookupQuery> CREATOR = findCreator(GoogleCertificatesLookupQuery.class);\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/common/GoogleCertificatesLookupResponse.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common;\n\nimport android.os.Parcel;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class GoogleCertificatesLookupResponse extends AbstractSafeParcelable {\n    @Field(1)\n    public final boolean result;\n    @Field(2)\n    public final String errorMessage;\n    @Field(3)\n    public final int statusValue;\n    @Field(4)\n    public final int firstPartyStatusValue;\n\n    @Constructor\n    public GoogleCertificatesLookupResponse(@Param(1) boolean result, @Param(2) String errorMessage, @Param(3) int statusValue, @Param(4) int firstPartyStatusValue) {\n        this.result = result;\n        this.errorMessage = errorMessage;\n        this.statusValue = statusValue;\n        this.firstPartyStatusValue = firstPartyStatusValue;\n    }\n\n    @Override\n    public void writeToParcel(Parcel out, int flags) {\n        CREATOR.writeToParcel(this, out, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<GoogleCertificatesLookupResponse> CREATOR = findCreator(GoogleCertificatesLookupResponse.class);\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/common/GoogleCertificatesQuery.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common;\n\nimport android.os.IBinder;\nimport android.os.Parcel;\nimport android.os.RemoteException;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.CertData;\nimport com.google.android.gms.common.internal.ICertData;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.dynamic.ObjectWrapper;\nimport org.microg.gms.common.Hide;\n\n@Hide\n@SafeParcelable.Class\npublic class GoogleCertificatesQuery extends AbstractSafeParcelable {\n    @Field(value = 1, getterName = \"getCallingPackage\")\n    String callingPackage;\n    @Field(2)\n    IBinder certDataBinder;\n    private CertData certData;\n    @Field(3)\n    boolean allowTestKeys;\n    @Field(4)\n    boolean ignoreTestKeysOverride;\n\n    public String getCallingPackage() {\n        return callingPackage;\n    }\n\n    public CertData getCertData() {\n        if (certData == null && certDataBinder != null) {\n            certData = CertData.unwrap(certDataBinder);\n        }\n        return certData;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<GoogleCertificatesQuery> CREATOR = findCreator(GoogleCertificatesQuery.class);\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/common/GooglePlayServicesNotAvailableException.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.common;\n\n/**\n * Indicates Google Play services is not available.\n */\npublic class GooglePlayServicesNotAvailableException extends Exception {\n    /**\n     * The error code returned by {@link GoogleApiAvailability#isGooglePlayServicesAvailable(Context)} call.\n     */\n    public final int errorCode;\n\n    public GooglePlayServicesNotAvailableException(int errorCode) {\n        this.errorCode = errorCode;\n    }\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/common/GooglePlayServicesRepairableException.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.common;\n\nimport android.app.Dialog;\nimport android.content.Intent;\n\n/**\n * {@code GooglePlayServicesRepairableException}s are special instances of {@link UserRecoverableException}s which are\n * thrown when Google Play services is not installed, up-to-date, or enabled. In these cases, client code can use\n * {@link #getConnectionStatusCode()} in conjunction with {@link GoogleApiAvailability#getErrorDialog(android.app.Activity, int, int)}\n * to provide users with a localized {@link Dialog} that will allow users to install, update, or otherwise enable Google Play services.\n */\npublic class GooglePlayServicesRepairableException extends UserRecoverableException {\n    private final int connectionStatusCode;\n\n    /**\n     * Creates a {@link GooglePlayServicesRepairableException}.\n     *\n     * @param connectionStatusCode a code for the {@link ConnectionResult} {@code statusCode} of the exception\n     * @param message              a string message for the exception\n     * @param intent               an intent that may be started to resolve the connection issue with Google Play services\n     */\n    public GooglePlayServicesRepairableException(int connectionStatusCode, String message, Intent intent) {\n        super(message, intent);\n        this.connectionStatusCode = connectionStatusCode;\n    }\n\n    /**\n     * Returns the {@link ConnectionResult} {@code statusCode} of the exception.\n     * <p>\n     * This value may be passed in to {@link GoogleApiAvailability#getErrorDialog(android.app.Activity, int, int)} to\n     * provide users with a localized {@link Dialog} that will allow users to install, update, or otherwise enable Google Play services.\n     */\n    public int getConnectionStatusCode() {\n        return connectionStatusCode;\n    }\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/common/Scopes.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2015 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.common;\n\nimport org.microg.gms.common.Hide;\n\n/**\n * OAuth 2.0 scopes for use with Google Play services. See the specific client methods for details on which scopes are required.\n */\npublic class Scopes {\n    /**\n     * OAuth 2.0 scope for viewing a user's basic profile information.\n     */\n    public static final String PROFILE = \"profile\";\n    @Hide\n    public static final String OPENID = \"openid\";\n    /**\n     * OAuth 2.0 scope for accessing user's Google account email address.\n     */\n    public static final String EMAIL = \"email\";\n    /**\n     * OAuth 2.0 scope for accessing the user's name, basic profile info and Google+ profile info.\n     * <p>\n     * When using this scope, your app will have access to:\n     * <ul>\n     * <li>the user's full name, profile picture, Google+ profile ID, age range, and language</li>\n     * <li>any other publicly available information on the user's Google+ profile</li>\n     * </ul>\n     *\n     * @deprecated We recommend switching to {@link #PROFILE} scope to get the one-tap sign-in experience. Your app will get much higher sign-in completion\n     * rate by switching to profile scopes because of the streamlined user experience. And your existing users with PLUS_LOGIN grant will not be asked to\n     * sign-in again.\n     * If you really need user's age range and locale information (which is the only additional information you can get from PLUS_LOGIN as of\n     * September 2016), use below scopes in addition to PROFILE:<ul>\n     * <li>www.googleapis.com/auth/profile.agerange.read</li>\n     * <li>www.googleapis.com/auth/profile.language.read</li>\n     * </ul>\n     */\n    @Deprecated\n    public static final String PLUS_LOGIN = \"https://www.googleapis.com/auth/plus.login\";\n    /**\n     * This scope was previously named PLUS_PROFILE.\n     * <p>\n     * When using this scope, it does the following:\n     * <ul>\n     * <li>It lets you know who the currently authenticated user is by letting you replace a Google+ user ID with \"me\", which represents the authenticated\n     * user, in any call to the Google+ API.</li>\n     * </ul>\n     */\n    public static final String PLUS_ME = \"https://www.googleapis.com/auth/plus.me\";\n    /**\n     * Scope for accessing data from Google Play Games.\n     */\n    public static final String GAMES = \"https://www.googleapis.com/auth/games\";\n    @Hide\n    public static final String GAMES_LITE = \"https://www.googleapis.com/auth/games_lite\";\n    @Hide\n    public static final String GAMES_FIRSTPARTY = \"https://www.googleapis.com/auth/games.firstparty\";\n    /**\n     * Scope for using the CloudSave service.\n     */\n    public static final String CLOUD_SAVE = \"https://www.googleapis.com/auth/datastoremobile\";\n    /**\n     * Scope for using the App State service.\n     */\n    public static final String APP_STATE = \"https://www.googleapis.com/auth/appstate\";\n    /**\n     * Scope for access user-authorized files from Google Drive.\n     */\n    public static final String DRIVE_FILE = \"https://www.googleapis.com/auth/drive.file\";\n    /**\n     * Scope for accessing appfolder files from Google Drive.\n     */\n    public static final String DRIVE_APPFOLDER = \"https://www.googleapis.com/auth/drive.appdata\";\n    @Hide\n    public static final String FITNESS_ACTIVITY_READ = \"https://www.googleapis.com/auth/fitness.activity.read\";\n    @Hide\n    public static final String FITNESS_ACTIVITY_READ_WRITE = \"https://www.googleapis.com/auth/fitness.activity.write\";\n    @Hide\n    public static final String FITNESS_LOCATION_READ = \"https://www.googleapis.com/auth/fitness.location.read\";\n    @Hide\n    public static final String FITNESS_LOCATION_READ_WRITE = \"https://www.googleapis.com/auth/fitness.location.write\";\n    @Hide\n    public static final String FITNESS_BODY_READ = \"https://www.googleapis.com/auth/fitness.body.read\";\n    @Hide\n    public static final String FITNESS_BODY_READ_WRITE = \"https://www.googleapis.com/auth/fitness.body.write\";\n    @Hide\n    public static final String USERINFO_EMAIL = \"https://www.googleapis.com/auth/userinfo.email\";\n    @Hide\n    public static final String USERINFO_PROFILE = \"https://www.googleapis.com/auth/userinfo.profile\";\n    @Hide\n    public static final String USER_BIRTHDAY_READ = \"https://www.googleapis.com/auth/user.birthday.read\";\n    @Hide\n    public static final String GMAIL_READONLY = \"https://www.googleapis.com/auth/gmail.readonly\";\n    /**\n     * Scope for cryptauthenrollment.googleapis.com (required for certain Google Workspace accounts)\n     */\n    @Hide\n    public static final String CRYPTAUTH = \"https://www.googleapis.com/auth/cryptauth\";\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/common/UserRecoverableException.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.common;\n\nimport android.app.Activity;\nimport android.content.Intent;\n\n/**\n * UserRecoverableExceptions signal errors that can be recovered with user action, such as a user login.\n */\npublic class UserRecoverableException extends Exception {\n    private final Intent intent;\n\n    public UserRecoverableException(String message, Intent intent) {\n        super(message);\n        this.intent = intent;\n    }\n\n    /**\n     * Getter for an {@link Intent} that when supplied to {@link Activity#startActivityForResult(Intent, int)}, will allow user intervention.\n     * @return Intent representing the ameliorating user action.\n     */\n    public Intent getIntent() {\n        return intent;\n    }\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/common/api/ApiException.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.common.api;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Exception to be returned by a Task when a call to Google Play services has failed.\n */\n@PublicApi\npublic class ApiException extends Exception {\n    /**\n     * @deprecated use {@link #getStatus()} instead\n     */\n    @PublicApi\n    protected final Status mStatus;\n\n    /**\n     * Create an ApiException from a {@link com.google.android.gms.common.api.Status}.\n     * @param status the Status instance containing a message and code.\n     */\n    @PublicApi\n    public ApiException(Status status) {\n        mStatus = status;\n    }\n\n    /**\n     * Returns the status of the operation.\n     */\n    @PublicApi\n    public Status getStatus() {\n        return mStatus;\n    }\n\n    /**\n     * Indicates the status of the operation.\n     * @return Status code resulting from the operation.\n     * The value is one of the constants in {@link com.google.android.gms.common.api.CommonStatusCodes} or specific to the API in use.\n     */\n    @PublicApi\n    public int getStatusCode() {\n        return mStatus.getStatusCode();\n    }\n\n    /**\n     * @deprecated use {@link #getMessage()} for a summary of the cause.\n     */\n    @PublicApi\n    public String getStatusMessage() {\n        return getMessage();\n    }\n\n    @Override\n    public String getMessage() {\n        return mStatus.getStatusMessage();\n    }\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/common/api/ApiMetadata.java",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.api;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.utils.ToStringHelper;\n\n@Hide\n@SafeParcelable.Class\npublic class ApiMetadata extends AbstractSafeParcelable {\n\n    public static final ApiMetadata DEFAULT = new ApiMetadata(null, false);\n    public static final ApiMetadata SKIP = new ApiMetadata();\n\n    @Field(1)\n    public final ComplianceOptions complianceOptions;\n    @Field(2)\n    public final boolean b2;\n\n    public final boolean skip;\n\n    @Constructor\n    public ApiMetadata(@Param(1) ComplianceOptions complianceOptions, @Param(2) boolean b2) {\n        this.complianceOptions = complianceOptions;\n        this.b2 = b2;\n        this.skip = false;\n    }\n\n    private ApiMetadata() {\n        this.complianceOptions = null;\n        this.b2 = false;\n        this.skip = true;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<ApiMetadata> CREATOR = new ApiMetadataCreator();\n    private static final SafeParcelableCreatorAndWriter<ApiMetadata> ORIGINAL_CREATOR = findCreator(ApiMetadata.class);\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"ApiMetadata\").field(\"complianceOptions\", complianceOptions).end();\n    }\n\n    private static class ApiMetadataCreator implements SafeParcelableCreatorAndWriter<ApiMetadata> {\n        private static final int METADATA_PRESENT_MAGIC = -204102970;\n\n        @Override\n        public ApiMetadata createFromParcel(Parcel parcel) {\n            int dataPosition = parcel.dataPosition();\n            if (parcel.readInt() != METADATA_PRESENT_MAGIC) {\n                parcel.setDataPosition(dataPosition - 4);\n                return ApiMetadata.SKIP;\n            }\n            return ORIGINAL_CREATOR.createFromParcel(parcel);\n        }\n\n        @Override\n        public ApiMetadata[] newArray(int size) {\n            return new ApiMetadata[size];\n        }\n\n        @Override\n        public void writeToParcel(ApiMetadata object, Parcel parcel, int flags) {\n            if (object.skip) {\n                parcel.setDataPosition(parcel.dataPosition() - 4);\n                parcel.setDataSize(parcel.dataSize() - 4);\n                return;\n            }\n            parcel.writeInt(METADATA_PRESENT_MAGIC);\n            ORIGINAL_CREATOR.writeToParcel(object, parcel, flags);\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/common/api/CommonStatusCodes.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.common.api;\n\nimport androidx.annotation.NonNull;\n\nimport org.microg.gms.common.PublicApi;\n\n@SuppressWarnings({\"deprecation\", \"DeprecatedIsStillUsed\"})\n@PublicApi\npublic class CommonStatusCodes {\n    public static final int SUCCESS_CACHE = -1;\n    public static final int SUCCESS = 0;\n    @Deprecated\n    public static final int SERVICE_MISSING = 1;\n    @Deprecated\n    public static final int SERVICE_VERSION_UPDATE_REQUIRED = 2;\n    @Deprecated\n    public static final int SERVICE_DISABLED = 3;\n    public static final int SIGN_IN_REQUIRED = 4;\n    public static final int INVALID_ACCOUNT = 5;\n    public static final int RESOLUTION_REQUIRED = 6;\n    public static final int NETWORK_ERROR = 7;\n    public static final int INTERNAL_ERROR = 8;\n    public static final int SERVICE_INVALID = 9;\n    public static final int DEVELOPER_ERROR = 10;\n    public static final int LICENSE_CHECK_FAILED = 11;\n    public static final int ERROR = 13;\n    public static final int INTERRUPTED = 14;\n    public static final int TIMEOUT = 15;\n    public static final int CANCELED = 16;\n    public static final int API_NOT_CONNECTED = 17;\n    public static final int DEAD_CLIENT = 18;\n\n    @NonNull\n    public static String getStatusCodeString(int statusCode) {\n        switch (statusCode) {\n            case SUCCESS_CACHE:\n                return \"SUCCESS_CACHE\";\n            case SUCCESS:\n                return \"SUCCESS\";\n            case SERVICE_VERSION_UPDATE_REQUIRED:\n                return \"SERVICE_VERSION_UPDATE_REQUIRED\";\n            case SERVICE_DISABLED:\n                return \"SERVICE_DISABLED\";\n            case SIGN_IN_REQUIRED:\n                return \"SIGN_IN_REQUIRED\";\n            case INVALID_ACCOUNT:\n                return \"INVALID_ACCOUNT\";\n            case RESOLUTION_REQUIRED:\n                return \"RESOLUTION_REQUIRED\";\n            case NETWORK_ERROR:\n                return \"NETWORK_ERROR\";\n            case INTERNAL_ERROR:\n                return \"INTERNAL_ERROR\";\n            case SERVICE_INVALID:\n                return \"SERVICE_INVALID\";\n            case DEVELOPER_ERROR:\n                return \"DEVELOPER_ERROR\";\n            case LICENSE_CHECK_FAILED:\n                return \"LICENSE_CHECK_FAILED\";\n            case ERROR:\n                return \"ERROR\";\n            case INTERRUPTED:\n                return \"INTERRUPTED\";\n            case TIMEOUT:\n                return \"TIMEOUT\";\n            case CANCELED:\n                return \"CANCELED\";\n            case API_NOT_CONNECTED:\n                return \"API_NOT_CONNECTED\";\n            case DEAD_CLIENT:\n                return \"DEAD_CLIENT\";\n            default:\n                return \"unknown status code: \" + statusCode;\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/common/api/ComplianceOptions.java",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.api;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class ComplianceOptions extends AbstractSafeParcelable {\n    @Field(1)\n    public int callerProductId;\n    @Field(2)\n    public int dataOwnerProductId;\n    @Field(3)\n    public int processingReason;\n    @Field(4)\n    public boolean isUserData;\n\n    public ComplianceOptions() {\n    }\n\n    @Constructor\n    public ComplianceOptions(@Param(1) int callerProductId, @Param(2) int dataOwnerProductId, @Param(3) int processingReason, @Param(4) boolean isUserData) {\n        this.callerProductId = callerProductId;\n        this.dataOwnerProductId = dataOwnerProductId;\n        this.processingReason = processingReason;\n        this.isUserData = isUserData;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<ComplianceOptions> CREATOR = findCreator(ComplianceOptions.class);\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"ComplianceOptions\").field(\"callerProductId\", callerProductId).field(\"dataOwnerProductId\", dataOwnerProductId).field(\"processingReason\", processingReason).field(\"isUserData\", isUserData).end();\n    }\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/common/api/Releasable.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.common.api;\n\n/**\n * Represents a resource, or a holder of resources, which may be released once they are no longer needed.\n */\npublic interface Releasable {\n    void release();\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/common/api/ResolvableApiException.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.common.api;\n\nimport android.app.Activity;\nimport android.app.PendingIntent;\nimport android.content.Intent;\nimport android.content.IntentSender;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Exception to be returned by a Task when a call to Google Play services has failed with a\n * possible resolution.\n */\n@PublicApi\npublic class ResolvableApiException extends ApiException {\n    @PublicApi\n    public ResolvableApiException(Status status) {\n        super(status);\n    }\n\n    /**\n     * A pending intent to resolve the failure. This intent can be started with\n     * {@link android.app.Activity#startIntentSenderForResult(IntentSender, int, Intent, int, int, int)}\n     * to present UI to solve the issue.\n     * @return The pending intent to resolve the failure.\n     */\n    @PublicApi\n    public PendingIntent getResolution() {\n        return mStatus.getResolution();\n    }\n\n    /**\n     * Resolves an error by starting any intents requiring user interaction.\n     * See {@link com.google.android.gms.common.api.CommonStatusCodes#SIGN_IN_REQUIRED}, and\n     * {@link com.google.android.gms.common.api.CommonStatusCodes#RESOLUTION_REQUIRED}.\n     * @param activity An Activity context to use to resolve the issue. The activity's\n     *                 onActivityResult method will be invoked after the user is done.\n     *                 If the resultCode is {@link android.app.Activity#RESULT_OK},\n     *                 the application should try to connect again.\n     * @param requestCode The request code to pass to onActivityResult.\n     */\n    @PublicApi\n    public void startResolutionForResult(Activity activity, int requestCode) throws IntentSender.SendIntentException {\n        mStatus.startResolutionForResult(activity, requestCode);\n    }\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/common/api/Response.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.common.api;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Represents the successful result of invoking an API method in Google Play services using a subclass of GoogleApi.\n * Wraps a instance of a {@link Result}.\n */\n@PublicApi\npublic class Response<T extends Result> {\n    private T result;\n\n    public Response() {\n    }\n\n    protected Response(T result) {\n        this.result = result;\n    }\n\n    public T getResult() {\n        return result;\n    }\n\n    public void setResult(T result) {\n        this.result = result;\n    }\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/common/api/Result.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.common.api;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Represents the final result of invoking an API method in Google Play Services.\n */\n@PublicApi\npublic interface Result {\n    public Status getStatus();\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/common/api/ResultCallback.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.common.api;\n\n/**\n * An interface for receiving a {@link Result} from a {@link PendingResult} as an asynchronous\n * callback.\n */\npublic interface ResultCallback<R extends Result> {\n    /**\n     * Called when the {@link Result} is ready. It is the responsibility of each callback to\n     * release any resources associated with the result. Some result types may implement\n     * {@link Releasable}, in which case {@link Releasable#release()} should be used to free the\n     * associated resources.\n     *\n     * @param result The result from the API call. May not be null.\n     */\n    public void onResult(R result);\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/common/api/ResultCallbacks.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.common.api;\n\nimport android.os.Handler;\nimport androidx.annotation.NonNull;\n\n/**\n * Callbacks for receiving a {@link Result} from a as an asynchronous callback. Contains separate callbacks for success and failure.\n * These methods are called on the main thread, unless overridden by {@link GoogleApiClient.Builder#setHandler(Handler)}.\n */\npublic abstract class ResultCallbacks<R extends Result> implements ResultCallback<R> {\n    /**\n     * Called when the {@link Result} is ready and a failure occurred.\n     *\n     * @param result Status resulting from the API call. Guaranteed to be non-null and unsuccessful.\n     */\n    public abstract void onFailure(@NonNull Status result);\n\n    /**\n     * Called when the {@link Result} is ready and was successful.\n     * <p>\n     * It is the responsibility of the callback to release any resources associated with the result if {@link #onSuccess(Result)} is called. Some result types may\n     * implement {@link Releasable}, in which case {@link Releasable#release()} should be used to free the associated resources. If a failure occurs the result will be\n     * released automatically.\n     *\n     * @param result The result from the API call. Never null.\n     */\n    public abstract void onSuccess(@NonNull R result);\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/common/api/Scope.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.common.api;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Describes an OAuth 2.0 scope to request. This has security implications for the user, and\n * requesting additional scopes will result in authorization dialogs.\n */\n@PublicApi\n@SafeParcelable.Class\npublic class Scope extends AbstractSafeParcelable {\n    @Field(1)\n    int versionCode = 1;\n    @Field(value = 2, getterName = \"getScopeUri\")\n    private final String scopeUri;\n\n    private Scope() {\n        scopeUri = null;\n    }\n\n    /**\n     * Creates a new scope with the given URI.\n     */\n    @Constructor\n    public Scope(@Param(2) String scopeUri) {\n        this.scopeUri = scopeUri;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        return this == o || o instanceof Scope && scopeUri.equals(((Scope) o).scopeUri);\n    }\n\n    public String getScopeUri() {\n        return scopeUri;\n    }\n\n    @Override\n    public int hashCode() {\n        return scopeUri.hashCode();\n    }\n\n    @Override\n    public String toString() {\n        return scopeUri;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<Scope> CREATOR = findCreator(Scope.class);\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/common/api/Status.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.common.api;\n\nimport android.app.Activity;\nimport android.app.PendingIntent;\nimport android.content.Intent;\nimport android.content.IntentSender;\nimport android.content.IntentSender.SendIntentException;\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.utils.ToStringHelper;\n\n/**\n * Represents the results of work.\n */\n@PublicApi\n@SafeParcelable.Class\npublic final class Status extends AbstractSafeParcelable implements Result {\n    @PublicApi(exclude = true)\n    public static final Status INTERNAL_ERROR = new Status(CommonStatusCodes.INTERNAL_ERROR, \"Internal error\");\n    @PublicApi(exclude = true)\n    public static final Status CANCELED = new Status(CommonStatusCodes.CANCELED, \"Cancelled\");\n    @PublicApi(exclude = true)\n    public static final Status SUCCESS_CACHE = new Status(CommonStatusCodes.SUCCESS_CACHE, \"Success\");\n    @PublicApi(exclude = true)\n    public static final Status SUCCESS = new Status(CommonStatusCodes.SUCCESS, \"Success\");\n\n    @Field(1000)\n    int versionCode = 1;\n\n    @Field(value = 1, getterName = \"getStatusCode\")\n    private final int statusCode;\n\n    @Field(value = 2, getterName = \"getStatusMessage\")\n    private final String statusMessage;\n\n    @Field(value = 3, getterName = \"getResolution\")\n    private final PendingIntent resolution;\n\n    private Status() {\n        statusCode = 0;\n        statusMessage = null;\n        resolution = null;\n    }\n\n    /**\n     * Creates a representation of the status resulting from a GoogleApiClient operation.\n     *\n     * @param statusCode The status code.\n     */\n    public Status(int statusCode) {\n        this(statusCode, null);\n    }\n\n    /**\n     * Creates a representation of the status resulting from a GoogleApiClient operation.\n     *\n     * @param statusCode    The status code.\n     * @param statusMessage The message associated with this status, or null.\n     */\n    public Status(int statusCode, String statusMessage) {\n        this(statusCode, statusMessage, null);\n    }\n\n    /**\n     * Creates a representation of the status resulting from a GoogleApiClient operation.\n     *\n     * @param statusCode    The status code.\n     * @param statusMessage The message associated with this status, or null.\n     * @param resolution    A pending intent that will resolve the issue when started, or null.\n     */\n    @Constructor\n    public Status(@Param(1) int statusCode, @Param(2) String statusMessage, @Param(3) PendingIntent resolution) {\n        this.statusCode = statusCode;\n        this.statusMessage = statusMessage;\n        this.resolution = resolution;\n    }\n\n    /**\n     * A pending intent to resolve the failure. This intent can be started with\n     * {@link Activity#startIntentSenderForResult(IntentSender, int, Intent, int, int, int)} to\n     * present UI to solve the issue.\n     *\n     * @return The pending intent to resolve the failure.\n     */\n    public PendingIntent getResolution() {\n        return resolution;\n    }\n\n    /**\n     * Returns the status of this result. Use {@link #isSuccess()} to determine whether the call\n     * was successful, and {@link #getStatusCode()} to determine what the error cause was.\n     * <p>\n     * Certain errors are due to failures that can be resolved by launching a particular intent.\n     * The resolution intent is available via {@link #getResolution()}.\n     */\n    @Override\n    public Status getStatus() {\n        return this;\n    }\n\n    /**\n     * Indicates the status of the operation.\n     *\n     * @return Status code resulting from the operation. The value is one of the constants in\n     * {@link CommonStatusCodes} or specific to the APIs added to the GoogleApiClient.\n     */\n    public int getStatusCode() {\n        return statusCode;\n    }\n\n    public String getStatusMessage() {\n        return statusMessage;\n    }\n\n    /**\n     * Returns true if calling {@link #startResolutionForResult(Activity, int)} will start any\n     * intents requiring user interaction.\n     *\n     * @return true if there is a resolution that can be started.\n     */\n    public boolean hasResolution() {\n        return resolution != null;\n    }\n\n    /**\n     * Returns true if the operation was canceled.\n     */\n    public boolean isCanceled() {\n        return statusCode == CommonStatusCodes.CANCELED;\n    }\n\n    /**\n     * Returns true if the operation was interrupted.\n     */\n    public boolean isInterrupted() {\n        return statusCode == CommonStatusCodes.INTERRUPTED;\n    }\n\n    /**\n     * Returns true if the operation was successful.\n     *\n     * @return true if the operation was successful, false if there was an error.\n     */\n    public boolean isSuccess() {\n        return statusCode <= 0;\n    }\n\n    /**\n     * Resolves an error by starting any intents requiring user interaction. See\n     * {@link CommonStatusCodes#SIGN_IN_REQUIRED}, and {@link CommonStatusCodes#RESOLUTION_REQUIRED}.\n     *\n     * @param activity    An Activity context to use to resolve the issue. The activity's\n     *                    onActivityResult method will be invoked after the user is done. If the\n     *                    resultCode is {@link Activity#RESULT_OK}, the application should try to\n     *                    connect again.\n     * @param requestCode The request code to pass to onActivityResult.\n     * @throws SendIntentException If the resolution intent has been canceled or is no longer able\n     *                             to execute the request.\n     */\n    public void startResolutionForResult(Activity activity, int requestCode) throws SendIntentException {\n        if (hasResolution()) {\n            activity.startIntentSenderForResult(resolution.getIntentSender(), requestCode, null, 0, 0, 0);\n        }\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"Status\").field(\"code\", statusCode).field(\"message\", statusMessage).field(\"resolution\", resolution).end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<Status> CREATOR = findCreator(Status.class);\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/common/api/internal/StatusExceptionMapper.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.api.internal;\n\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.api.Status;\nimport org.microg.gms.common.Hide;\n\n@Hide\npublic interface StatusExceptionMapper {\n    @NonNull\n    Exception getException(@NonNull Status status);\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/common/internal/BaseGmsClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.internal;\n\nimport android.os.IInterface;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.ConnectionResult;\nimport org.microg.gms.common.Hide;\n\n@Hide\npublic abstract class BaseGmsClient<T extends IInterface> {\n    public interface ConnectionProgressReportCallbacks {\n        void onReportServiceBinding(@NonNull ConnectionResult connectionResult);\n    }\n\n    public interface SignOutCallbacks {\n        void onSignOutComplete();\n    }\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/common/internal/BinderWrapper.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.common.internal;\n\nimport android.os.IBinder;\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\npublic class BinderWrapper implements Parcelable {\n    public IBinder binder;\n\n    public BinderWrapper(IBinder binder) {\n        this.binder = binder;\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(binder);\n    }\n\n    public static final Creator<BinderWrapper> CREATOR = new Creator<BinderWrapper>() {\n        @Override\n        public BinderWrapper createFromParcel(Parcel source) {\n            return new BinderWrapper(source.readStrongBinder());\n        }\n\n        @Override\n        public BinderWrapper[] newArray(int size) {\n            return new BinderWrapper[size];\n        }\n    };\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/common/internal/CertData.java",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 com.google.android.gms.common.internal;\n\nimport android.os.IBinder;\nimport android.os.RemoteException;\n\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.dynamic.ObjectWrapper;\n\nimport java.util.Arrays;\n\npublic class CertData extends ICertData.Stub {\n    private final byte[] bytes;\n    private final int hashCode;\n\n    public CertData(byte[] bytes) {\n        this.bytes = bytes;\n        if (bytes.length < 25) throw new RuntimeException(\"CertData to small\");\n        hashCode = Arrays.hashCode(Arrays.copyOfRange(bytes, 0, 25));\n    }\n\n    @Override\n    public int hashCode() {\n        return hashCode;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (!(obj instanceof ICertData)) return false;\n        ICertData cert = (ICertData) obj;\n        try {\n            if (cert.remoteHashCode() != hashCode()) return false;\n            return Arrays.equals(ObjectWrapper.unwrapTyped(cert.getWrappedBytes(), byte[].class), getBytes());\n        } catch (RemoteException e) {\n            return false;\n        }\n    }\n\n    public byte[] getBytes() {\n        return bytes;\n    }\n\n    @Override\n    public IObjectWrapper getWrappedBytes() throws RemoteException {\n        return ObjectWrapper.wrap(getBytes());\n    }\n\n    @Override\n    public int remoteHashCode() throws RemoteException {\n        return hashCode();\n    }\n\n    @Nullable\n    public static CertData unwrap(IBinder certDataBinder) {\n        if (certDataBinder instanceof CertData) {\n            return (CertData) certDataBinder;\n        } else if (certDataBinder instanceof IObjectWrapper) {\n            return unwrap((IObjectWrapper) certDataBinder);\n        } else if (certDataBinder instanceof ICertData) {\n            return unwrap((ICertData) certDataBinder);\n        }\n        return null;\n    }\n\n    public static CertData unwrap(IObjectWrapper certDataWrapper) {\n        CertData certData = ObjectWrapper.unwrapTyped(certDataWrapper, CertData.class);\n        if (certData != null) return certData;\n        byte[] bytes = ObjectWrapper.unwrapTyped(certDataWrapper, byte[].class);\n        if (bytes != null) return new CertData(bytes);\n        ICertData iCertData = ObjectWrapper.unwrapTyped(certDataWrapper, ICertData.class);\n        if (iCertData != null) return unwrap(iCertData);\n        return null;\n    }\n\n    public static CertData unwrap(ICertData iCertData) {\n        if (iCertData == null) return null;\n        if (iCertData instanceof CertData) return (CertData) iCertData;\n        try {\n            byte[] bytes = ObjectWrapper.unwrapTyped(iCertData.getWrappedBytes(), byte[].class);\n            if (bytes != null) {\n                return new CertData(bytes);\n            }\n        } catch (RemoteException e) {\n            // Ignore\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/common/internal/ConnectionInfo.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.internal;\n\nimport android.os.Bundle;\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.Feature;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class ConnectionInfo extends AbstractSafeParcelable {\n    @Field(1)\n    public Bundle params;\n    @Field(2)\n    public Feature[] features;\n    @Field(3)\n    public int unknown3;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<ConnectionInfo> CREATOR = findCreator(ConnectionInfo.class);\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/common/internal/GetServiceRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.common.internal;\n\nimport android.accounts.Account;\nimport android.os.Bundle;\nimport android.os.IBinder;\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.Feature;\nimport com.google.android.gms.common.api.Scope;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Constants;\nimport org.microg.gms.common.GmsService;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.Arrays;\n\n@SafeParcelable.Class\npublic class GetServiceRequest extends AbstractSafeParcelable {\n    @Field(1)\n    int versionCode = 6;\n    @Field(2)\n    public final int serviceId;\n    @Field(3)\n    public int gmsVersion;\n    @Field(4)\n    public String packageName;\n    @Field(5)\n    public IBinder accountAccessor;\n    @Field(6)\n    public Scope[] scopes;\n    @Field(7)\n    public Bundle extras;\n    @Field(8)\n    public Account account;\n    @Field(9)\n    @Deprecated\n    long field9;\n    @Field(10)\n    public Feature[] defaultFeatures;\n    @Field(11)\n    public Feature[] apiFeatures;\n    @Field(12)\n    public boolean supportsConnectionInfo;\n    @Field(13)\n    int field13;\n    @Field(14)\n    boolean field14;\n    @Field(15)\n    public String attributionTag;\n\n    private GetServiceRequest() {\n        serviceId = -1;\n        gmsVersion = Constants.GMS_VERSION_CODE;\n    }\n\n    @Constructor\n    public GetServiceRequest(@Param(2) int serviceId) {\n        this.serviceId = serviceId;\n        this.gmsVersion = Constants.GMS_VERSION_CODE;\n        this.supportsConnectionInfo = true;\n    }\n\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"GetServiceRequest\")\n                .value(GmsService.nameFromServiceId(serviceId))\n                .field(\"packageName\", packageName)\n                .field(\"gmsVersion\", gmsVersion)\n                .field(\"scopes\", scopes)\n                .field(\"extras\", extras)\n                .field(\"account\", account)\n                .field(\"defaultFeatures\", defaultFeatures)\n                .field(\"apiFeatures\", apiFeatures)\n                .field(\"supportsConnectionInfo\", supportsConnectionInfo)\n                .field(\"attributionTag\", attributionTag)\n                .end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static SafeParcelableCreatorAndWriter<GetServiceRequest> CREATOR = findCreator(GetServiceRequest.class);\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/common/internal/ValidateAccountRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.common.internal;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class ValidateAccountRequest extends AbstractSafeParcelable {\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static SafeParcelableCreatorAndWriter<ValidateAccountRequest> CREATOR = findCreator(ValidateAccountRequest.class);\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/AbstractSafeParcelable.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.internal.safeparcel;\n\npublic abstract class AbstractSafeParcelable implements SafeParcelable {\n\n    @SuppressWarnings(\"unchecked\")\n    public static <T extends AbstractSafeParcelable> SafeParcelableCreatorAndWriter<T> findCreator(java.lang.Class<T> tClass) {\n        java.lang.Class<?> upmostClass = tClass;\n        while (upmostClass.getEnclosingClass() != null) upmostClass = upmostClass.getEnclosingClass();\n        String upmostClassName = upmostClass.getName();\n        int idx = upmostClassName.lastIndexOf('.');\n        String packagePrefix = idx > 0 ? upmostClassName.substring(0, idx + 1) : \"\";\n        String creatorClassName = packagePrefix + tClass.getSimpleName() + \"$000Creator\";\n        try {\n            return (SafeParcelableCreatorAndWriter<T>) java.lang.Class.forName(creatorClassName).newInstance();\n        } catch (Exception e) {\n            throw new RuntimeException(\"No Creator found for \" + tClass.getName(), e);\n        }\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/SafeParcelReader.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2015, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.internal.safeparcel;\n\nimport android.os.Bundle;\nimport android.os.IBinder;\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\n\n@SuppressWarnings(\"MagicNumber\")\npublic final class SafeParcelReader {\n\n    private SafeParcelReader() {\n    }\n\n    @Deprecated\n    public static int halfOf(int i) {\n        return i & 0xFFFF;\n    }\n\n    public static int getFieldId(int header) {\n        return header & 0xFFFF;\n    }\n\n    @Deprecated\n    public static int readSingleInt(Parcel parcel) {\n        return parcel.readInt();\n    }\n\n    public static int readHeader(Parcel parcel) {\n        return parcel.readInt();\n    }\n\n    private static int readSize(Parcel parcel, int header) {\n        if ((header & 0xFFFF0000) != 0xFFFF0000)\n            return header >> 16 & 0xFFFF;\n        return parcel.readInt();\n    }\n\n    private static void readExpectedSize(Parcel parcel, int header, int expectedSize) {\n        int i = readSize(parcel, header);\n        if (i != expectedSize)\n            throw new ReadException(\"Expected size \" + expectedSize + \" got \" + i + \" (0x\" + Integer.toHexString(i) + \")\", parcel);\n    }\n\n    @Deprecated\n    public static int readStart(Parcel parcel) {\n        return readObjectHeader(parcel);\n    }\n\n    public static int readObjectHeader(Parcel parcel) {\n        int header = readHeader(parcel);\n        int size = readSize(parcel, header);\n        int start = parcel.dataPosition();\n        if (getFieldId(header) != SafeParcelable.SAFE_PARCEL_OBJECT_MAGIC)\n            throw new ReadException(\"Expected object header. Got 0x\" + Integer.toHexString(header), parcel);\n        int end = start + size;\n        if ((end < start) || (end > parcel.dataSize()))\n            throw new ReadException(\"Size read is invalid start=\" + start + \" end=\" + end, parcel);\n        return end;\n    }\n\n    public static int readInt(Parcel parcel, int header) {\n        readExpectedSize(parcel, header, 4);\n        return parcel.readInt();\n    }\n\n    public static byte readByte(Parcel parcel, int header) {\n        readExpectedSize(parcel, header, 4);\n        return (byte) parcel.readInt();\n    }\n\n    public static short readShort(Parcel parcel, int header) {\n        readExpectedSize(parcel, header, 4);\n        return (short) parcel.readInt();\n    }\n\n    public static boolean readBool(Parcel parcel, int header) {\n        readExpectedSize(parcel, header, 4);\n        return parcel.readInt() != 0;\n    }\n\n    public static long readLong(Parcel parcel, int header) {\n        readExpectedSize(parcel, header, 8);\n        return parcel.readLong();\n    }\n\n    public static float readFloat(Parcel parcel, int header) {\n        readExpectedSize(parcel, header, 4);\n        return parcel.readFloat();\n    }\n\n    public static double readDouble(Parcel parcel, int header) {\n        readExpectedSize(parcel, header, 8);\n        return parcel.readDouble();\n    }\n\n    public static String readString(Parcel parcel, int header) {\n        int size = readSize(parcel, header);\n        if (size == 0)\n            return null;\n        int start = parcel.dataPosition();\n        String string = parcel.readString();\n        parcel.setDataPosition(start + size);\n        return string;\n    }\n\n    public static IBinder readBinder(Parcel parcel, int header) {\n        int size = readSize(parcel, header);\n        if (size == 0)\n            return null;\n        int start = parcel.dataPosition();\n        IBinder binder = parcel.readStrongBinder();\n        parcel.setDataPosition(start + size);\n        return binder;\n    }\n\n    public static <T extends Parcelable> T readParcelable(Parcel parcel, int header, Parcelable.Creator<T> creator) {\n        int size = readSize(parcel, header);\n        if (size == 0)\n            return null;\n        int start = parcel.dataPosition();\n        T t = creator.createFromParcel(parcel);\n        parcel.setDataPosition(start + size);\n        return t;\n    }\n\n    public static ArrayList readList(Parcel parcel, int header, ClassLoader classLoader) {\n        int size = readSize(parcel, header);\n        if (size == 0)\n            return null;\n        int start = parcel.dataPosition();\n        ArrayList list = parcel.readArrayList(classLoader);\n        parcel.setDataPosition(start + size);\n        return list;\n    }\n\n    public static HashMap readMap(Parcel parcel, int header, ClassLoader classLoader) {\n        int size = readSize(parcel, header);\n        if (size == 0)\n            return null;\n        int start = parcel.dataPosition();\n        HashMap map = parcel.readHashMap(classLoader);\n        parcel.setDataPosition(start + size);\n        return map;\n    }\n\n    public static <T extends Parcelable> ArrayList<T> readParcelableList(Parcel parcel, int header, Parcelable.Creator<T> creator) {\n        int size = readSize(parcel, header);\n        if (size == 0)\n            return null;\n        int start = parcel.dataPosition();\n        ArrayList<T> list = parcel.createTypedArrayList(creator);\n        parcel.setDataPosition(start + size);\n        return list;\n    }\n\n    public static ArrayList<String> readStringList(Parcel parcel, int header) {\n        int size = readSize(parcel, header);\n        if (size == 0)\n            return null;\n        int start = parcel.dataPosition();\n        ArrayList<String> list = parcel.createStringArrayList();\n        parcel.setDataPosition(start + size);\n        return list;\n    }\n\n    public static ArrayList<Integer> readIntegerList(Parcel parcel, int header) {\n        int size = readSize(parcel, header);\n        if (size == 0)\n            return null;\n        int start = parcel.dataPosition();\n        int length = parcel.readInt();\n        ArrayList<Integer> list = new ArrayList<>(length);\n        for (int i = 0; i < length; i++) {\n            list.add(parcel.readInt());\n        }\n        parcel.setDataPosition(start + size);\n        return list;\n    }\n\n    public static ArrayList<Long> readLongList(Parcel parcel, int header) {\n        int size = readSize(parcel, header);\n        if (size == 0)\n            return null;\n        int start = parcel.dataPosition();\n        int length = parcel.readInt();\n        ArrayList<Long> list = new ArrayList<>(length);\n        for (int i = 0; i < length; i++) {\n            list.add(parcel.readLong());\n        }\n        parcel.setDataPosition(start + size);\n        return list;\n    }\n\n    public static ArrayList<Float> readFloatList(Parcel parcel, int header) {\n        int size = readSize(parcel, header);\n        if (size == 0)\n            return null;\n        int start = parcel.dataPosition();\n        int length = parcel.readInt();\n        ArrayList<Float> list = new ArrayList<>(length);\n        for (int i = 0; i < length; i++) {\n            list.add(parcel.readFloat());\n        }\n        parcel.setDataPosition(start + size);\n        return list;\n    }\n\n    public static ArrayList<Double> readDoubleList(Parcel parcel, int header) {\n        int size = readSize(parcel, header);\n        if (size == 0)\n            return null;\n        int start = parcel.dataPosition();\n        int length = parcel.readInt();\n        ArrayList<Double> list = new ArrayList<>(length);\n        for (int i = 0; i < length; i++) {\n            list.add(parcel.readDouble());\n        }\n        parcel.setDataPosition(start + size);\n        return list;\n    }\n\n    public static ArrayList<Boolean> readBooleanList(Parcel parcel, int header) {\n        int size = readSize(parcel, header);\n        if (size == 0)\n            return null;\n        int start = parcel.dataPosition();\n        int length = parcel.readInt();\n        ArrayList<Boolean> list = new ArrayList<>(length);\n        for (int i = 0; i < length; i++) {\n            list.add(parcel.readInt() != 0);\n        }\n        parcel.setDataPosition(start + size);\n        return list;\n    }\n\n    public static <T extends Parcelable> T[] readParcelableArray(Parcel parcel, int header, Parcelable.Creator<T> creator) {\n        int size = readSize(parcel, header);\n        if (size == 0)\n            return null;\n        int start = parcel.dataPosition();\n        T[] arr = parcel.createTypedArray(creator);\n        parcel.setDataPosition(start + size);\n        return arr;\n    }\n\n    public static String[] readStringArray(Parcel parcel, int header) {\n        int size = readSize(parcel, header);\n        if (size == 0)\n            return null;\n        int start = parcel.dataPosition();\n        String[] arr = parcel.createStringArray();\n        parcel.setDataPosition(start + size);\n        return arr;\n    }\n\n    public static byte[] readByteArray(Parcel parcel, int header) {\n        int size = readSize(parcel, header);\n        if (size == 0)\n            return null;\n        int start = parcel.dataPosition();\n        byte[] arr = parcel.createByteArray();\n        parcel.setDataPosition(start + size);\n        return arr;\n    }\n\n    public static byte[][] readByteArrayArray(Parcel parcel, int header) {\n        int size = readSize(parcel, header);\n        if (size == 0)\n            return null;\n        int start = parcel.dataPosition();\n        int length = parcel.readInt();\n        byte[][] arr = new byte[length][];\n        for (int i = 0; i < length; i++) {\n            arr[i] = parcel.createByteArray();\n        }\n        parcel.setDataPosition(start + size);\n        return arr;\n    }\n\n    public static float[] readFloatArray(Parcel parcel, int header) {\n        int size = readSize(parcel, header);\n        if (size == 0)\n            return null;\n        int start = parcel.dataPosition();\n        float[] arr = parcel.createFloatArray();\n        parcel.setDataPosition(start + size);\n        return arr;\n    }\n\n    public static int[] readIntArray(Parcel parcel, int header) {\n        int size = readSize(parcel, header);\n        if (size == 0)\n            return null;\n        int start = parcel.dataPosition();\n        int[] arr = parcel.createIntArray();\n        parcel.setDataPosition(start + size);\n        return arr;\n    }\n\n    public static Bundle readBundle(Parcel parcel, int header, ClassLoader classLoader) {\n        int size = readSize(parcel, header);\n        if (size == 0)\n            return null;\n        int start = parcel.dataPosition();\n        Bundle bundle = parcel.readBundle(classLoader);\n        parcel.setDataPosition(start + size);\n        return bundle;\n    }\n\n    public static void skip(Parcel parcel, int header) {\n        int size = readSize(parcel, header);\n        parcel.setDataPosition(parcel.dataPosition() + size);\n    }\n\n    public static class ReadException extends RuntimeException {\n        public ReadException(String message, Parcel parcel) {\n            super(message);\n        }\n    }\n}"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/SafeParcelWriter.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2015, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.internal.safeparcel;\n\nimport android.os.Bundle;\nimport android.os.IBinder;\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport java.util.List;\nimport java.util.Map;\n\n@SuppressWarnings(\"MagicNumber\")\npublic final class SafeParcelWriter {\n\n    private SafeParcelWriter() {\n    }\n\n    private static void writeHeader(Parcel parcel, int fieldId, int size) {\n        if (size >= 0xFFFF) {\n            parcel.writeInt(0xFFFF0000 | fieldId);\n            parcel.writeInt(size);\n        } else {\n            parcel.writeInt(size << 16 | fieldId);\n        }\n    }\n\n    @Deprecated\n    public static int writeStart(Parcel parcel) {\n        return writeObjectHeader(parcel);\n    }\n\n    public static int writeObjectHeader(Parcel parcel) {\n        writeHeader(parcel, SafeParcelable.SAFE_PARCEL_OBJECT_MAGIC, 0xFFFF);\n        return parcel.dataPosition();\n    }\n\n    private static int writeObjectHeader(Parcel parcel, int fieldId) {\n        writeHeader(parcel, fieldId, 0xFFFF);\n        return parcel.dataPosition();\n    }\n\n    @Deprecated\n    public static void writeEnd(Parcel parcel, int start) {\n        finishObjectHeader(parcel, start);\n    }\n\n    public static void finishObjectHeader(Parcel parcel, int start) {\n        int end = parcel.dataPosition();\n        int length = end - start;\n        parcel.setDataPosition(start - 4);\n        parcel.writeInt(length);\n        parcel.setDataPosition(end);\n    }\n\n    public static void write(Parcel parcel, int fieldId, Boolean val) {\n        if (val == null) return;\n        writeHeader(parcel, fieldId, 4);\n        parcel.writeInt(val ? 1 : 0);\n    }\n\n    public static void write(Parcel parcel, int fieldId, Byte val) {\n        if (val == null) return;\n        writeHeader(parcel, fieldId, 4);\n        parcel.writeInt(val);\n    }\n\n    public static void write(Parcel parcel, int fieldId, Short val) {\n        if (val == null) return;\n        writeHeader(parcel, fieldId, 4);\n        parcel.writeInt(val);\n    }\n\n    public static void write(Parcel parcel, int fieldId, Integer val) {\n        if (val == null) return;\n        writeHeader(parcel, fieldId, 4);\n        parcel.writeInt(val);\n    }\n\n    public static void write(Parcel parcel, int fieldId, Long val) {\n        if (val == null) return;\n        writeHeader(parcel, fieldId, 8);\n        parcel.writeLong(val);\n    }\n\n    public static void write(Parcel parcel, int fieldId, Float val) {\n        if (val == null) return;\n        writeHeader(parcel, fieldId, 4);\n        parcel.writeFloat(val);\n    }\n\n    public static void write(Parcel parcel, int fieldId, Double val) {\n        if (val == null) return;\n        writeHeader(parcel, fieldId, 8);\n        parcel.writeDouble(val);\n    }\n\n    public static void write(Parcel parcel, int fieldId, String val, boolean mayNull) {\n        if (val == null) {\n            if (mayNull) {\n                writeHeader(parcel, fieldId, 0);\n            }\n        } else {\n            int start = writeObjectHeader(parcel, fieldId);\n            parcel.writeString(val);\n            finishObjectHeader(parcel, start);\n        }\n    }\n\n    public static void write(Parcel parcel, int fieldId, Parcelable val, int flags, boolean mayNull) {\n        if (val == null) {\n            if (mayNull) {\n                writeHeader(parcel, fieldId, 0);\n            }\n        } else {\n            int start = writeObjectHeader(parcel, fieldId);\n            val.writeToParcel(parcel, flags);\n            finishObjectHeader(parcel, start);\n        }\n    }\n\n    public static void write(Parcel parcel, int fieldId, Bundle val, boolean mayNull) {\n        if (val == null) {\n            if (mayNull) {\n                writeHeader(parcel, fieldId, 0);\n            }\n        } else {\n            int start = writeObjectHeader(parcel, fieldId);\n            parcel.writeBundle(val);\n            finishObjectHeader(parcel, start);\n        }\n    }\n\n    public static void write(Parcel parcel, int fieldId, byte[] val, boolean mayNull) {\n        if (val == null) {\n            if (mayNull) {\n                writeHeader(parcel, fieldId, 0);\n            }\n        } else {\n            int start = writeObjectHeader(parcel, fieldId);\n            parcel.writeByteArray(val);\n            finishObjectHeader(parcel, start);\n        }\n    }\n\n    public static void write(Parcel parcel, int fieldId, byte[][] val, boolean mayNull) {\n        if (val == null) {\n            if (mayNull) {\n                writeHeader(parcel, fieldId, 0);\n            }\n        } else {\n            int start = writeObjectHeader(parcel, fieldId);\n            parcel.writeInt(val.length);\n            for (byte[] arr : val) {\n                parcel.writeByteArray(arr);\n            }\n            finishObjectHeader(parcel, start);\n        }\n    }\n\n    public static void write(Parcel parcel, int fieldId, float[] val, boolean mayNull) {\n        if (val == null) {\n            if (mayNull) {\n                writeHeader(parcel, fieldId, 0);\n            }\n        } else {\n            int start = writeObjectHeader(parcel, fieldId);\n            parcel.writeFloatArray(val);\n            finishObjectHeader(parcel, start);\n        }\n    }\n\n    public static void write(Parcel parcel, int fieldId, int[] val, boolean mayNull) {\n        if (val == null) {\n            if (mayNull) {\n                writeHeader(parcel, fieldId, 0);\n            }\n        } else {\n            int start = writeObjectHeader(parcel, fieldId);\n            parcel.writeIntArray(val);\n            finishObjectHeader(parcel, start);\n        }\n    }\n\n    public static void write(Parcel parcel, int fieldId, String[] val, boolean mayNull) {\n        if (val == null) {\n            if (mayNull) {\n                writeHeader(parcel, fieldId, 0);\n            }\n        } else {\n            int start = writeObjectHeader(parcel, fieldId);\n            parcel.writeStringArray(val);\n            finishObjectHeader(parcel, start);\n        }\n    }\n\n    public static void writeStringList(Parcel parcel, int fieldId, List<String> val, boolean mayNull) {\n        if (val == null) {\n            if (mayNull) {\n                writeHeader(parcel, fieldId, 0);\n            }\n        } else {\n            int start = writeObjectHeader(parcel, fieldId);\n            parcel.writeStringList(val);\n            finishObjectHeader(parcel, start);\n        }\n    }\n\n    public static void writeIntegerList(Parcel parcel, int fieldId, List<Integer> val, boolean mayNull) {\n        if (val == null) {\n            if (mayNull) {\n                writeHeader(parcel, fieldId, 0);\n            }\n        } else {\n            int start = writeObjectHeader(parcel, fieldId);\n            parcel.writeInt(val.size());\n            for (Integer i : val) {\n                parcel.writeInt(i);\n            }\n            finishObjectHeader(parcel, start);\n        }\n    }\n\n    public static void writeLongList(Parcel parcel, int fieldId, List<Long> val, boolean mayNull) {\n        if (val == null) {\n            if (mayNull) {\n                writeHeader(parcel, fieldId, 0);\n            }\n        } else {\n            int start = writeObjectHeader(parcel, fieldId);\n            parcel.writeInt(val.size());\n            for (Long l : val) {\n                parcel.writeLong(l);\n            }\n            finishObjectHeader(parcel, start);\n        }\n    }\n\n    public static void writeFloatList(Parcel parcel, int fieldId, List<Float> val, boolean mayNull) {\n        if (val == null) {\n            if (mayNull) {\n                writeHeader(parcel, fieldId, 0);\n            }\n        } else {\n            int start = writeObjectHeader(parcel, fieldId);\n            parcel.writeInt(val.size());\n            for (Float f : val) {\n                parcel.writeFloat(f);\n            }\n            finishObjectHeader(parcel, start);\n        }\n    }\n\n    public static void writeDoubleList(Parcel parcel, int fieldId, List<Double> val, boolean mayNull) {\n        if (val == null) {\n            if (mayNull) {\n                writeHeader(parcel, fieldId, 0);\n            }\n        } else {\n            int start = writeObjectHeader(parcel, fieldId);\n            parcel.writeInt(val.size());\n            for (Double d : val) {\n                parcel.writeDouble(d);\n            }\n            finishObjectHeader(parcel, start);\n        }\n    }\n\n    public static void writeBooleanList(Parcel parcel, int fieldId, List<Boolean> val, boolean mayNull) {\n        if (val == null) {\n            if (mayNull) {\n                writeHeader(parcel, fieldId, 0);\n            }\n        } else {\n            int start = writeObjectHeader(parcel, fieldId);\n            parcel.writeInt(val.size());\n            for (Boolean b : val) {\n                parcel.writeInt(b ? 1 : 0);\n            }\n            finishObjectHeader(parcel, start);\n        }\n    }\n\n    private static <T extends Parcelable> void writeArrayPart(Parcel parcel, T val, int flags) {\n        int before = parcel.dataPosition();\n        parcel.writeInt(1);\n        int start = parcel.dataPosition();\n        val.writeToParcel(parcel, flags);\n        int end = parcel.dataPosition();\n        parcel.setDataPosition(before);\n        parcel.writeInt(end - start);\n        parcel.setDataPosition(end);\n    }\n\n    public static <T extends Parcelable> void write(Parcel parcel, int fieldId, T[] val, int flags, boolean mayNull) {\n        if (val == null) {\n            if (mayNull) {\n                writeHeader(parcel, fieldId, 0);\n            }\n        } else {\n            int start = writeObjectHeader(parcel, fieldId);\n            parcel.writeInt(val.length);\n            for (T t : val) {\n                if (t == null) {\n                    parcel.writeInt(0);\n                } else {\n                    writeArrayPart(parcel, t, flags);\n                }\n            }\n            finishObjectHeader(parcel, start);\n        }\n    }\n\n    public static <T extends Parcelable> void write(Parcel parcel, int fieldId, List<T> val, int flags, boolean mayNull) {\n        if (val == null) {\n            if (mayNull) {\n                writeHeader(parcel, fieldId, 0);\n            }\n        } else {\n            int start = writeObjectHeader(parcel, fieldId);\n            parcel.writeInt(val.size());\n            for (T t : val) {\n                if (t == null) {\n                    parcel.writeInt(0);\n                } else {\n                    writeArrayPart(parcel, t, flags);\n                }\n            }\n            finishObjectHeader(parcel, start);\n        }\n    }\n\n    public static void write(Parcel parcel, int fieldId, Parcel val, boolean mayNull) {\n        if (val == null) {\n            if (mayNull) {\n                writeHeader(parcel, fieldId, 0);\n            }\n        } else {\n            int start = writeObjectHeader(parcel, fieldId);\n            parcel.appendFrom(val, 0, val.dataSize());\n            finishObjectHeader(parcel, start);\n        }\n    }\n\n    public static void write(Parcel parcel, int fieldId, List val, boolean mayNull) {\n        if (val == null) {\n            if (mayNull) {\n                writeHeader(parcel, fieldId, 0);\n            }\n        } else {\n            int start = writeObjectHeader(parcel, fieldId);\n            parcel.writeList(val);\n            finishObjectHeader(parcel, start);\n        }\n    }\n\n    public static void write(Parcel parcel, int fieldId, Map val, boolean mayNull) {\n        if (val == null) {\n            if (mayNull) {\n                writeHeader(parcel, fieldId, 0);\n            }\n        } else {\n            int start = writeObjectHeader(parcel, fieldId);\n            parcel.writeMap(val);\n            finishObjectHeader(parcel, start);\n        }\n    }\n\n    public static void write(Parcel parcel, int fieldId, IBinder val, boolean mayNull) {\n        if (val == null) {\n            if (mayNull) {\n                writeHeader(parcel, fieldId, 0);\n            }\n        } else {\n            int start = writeObjectHeader(parcel, fieldId);\n            parcel.writeStrongBinder(val);\n            finishObjectHeader(parcel, start);\n        }\n    }\n\n}"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/SafeParcelable.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.internal.safeparcel;\n\nimport android.os.Parcelable;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\npublic interface SafeParcelable extends Parcelable {\n    int SAFE_PARCEL_OBJECT_MAGIC = 0x4F45;\n\n    @Target(ElementType.TYPE)\n    @interface Class {\n    }\n\n    @Target(ElementType.CONSTRUCTOR)\n    @interface Constructor {\n\n    }\n\n    @Target(ElementType.PARAMETER)\n    @interface Param {\n        int value();\n    }\n\n    @Retention(RetentionPolicy.RUNTIME)\n    @Target(ElementType.FIELD)\n    @interface Field {\n        int value();\n\n        boolean mayNull() default false;\n\n        java.lang.Class<?> subClass() default SafeParcelable.class;\n\n        boolean useValueParcel() default false;\n\n        boolean useDirectList() default false;\n\n        long versionCode() default -1;\n\n        String defaultValue() default \"\";\n\n        String type() default \"\";\n\n        String getterName() default \"\";\n\n        String getter() default \"\";\n    }\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/SafeParcelableCreatorAndWriter.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.internal.safeparcel;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\npublic interface SafeParcelableCreatorAndWriter<T extends SafeParcelable> extends Parcelable.Creator<T> {\n    void writeToParcel(T object, Parcel parcel, int flags);\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/SafeParcelableSerializer.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.internal.safeparcel;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\npublic class SafeParcelableSerializer {\n    public static <T extends SafeParcelable> T deserializeFromBytes(byte[] bytes, Parcelable.Creator<T> tCreator) {\n        if (bytes == null) return null;\n        Parcel parcel = Parcel.obtain();\n        parcel.unmarshall(bytes, 0, bytes.length);\n        parcel.setDataPosition(0);\n        T parcelable = tCreator.createFromParcel(parcel);\n        parcel.recycle();\n        return parcelable;\n    }\n\n    public static <T extends SafeParcelable> byte[] serializeToBytes(T parcelable) {\n        if (parcelable == null) return null;\n        Parcel parcel = Parcel.obtain();\n        parcelable.writeToParcel(parcel, 0);\n        byte[] bytes = parcel.marshall();\n        parcel.recycle();\n        return bytes;\n    }\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/common/package-info.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n/**\n * Contains utility classes for Google Play services.\n */\npackage com.google.android.gms.common;\n"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/dynamic/LifecycleDelegate.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.dynamic;\n\nimport android.app.Activity;\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\npublic interface LifecycleDelegate {\n    View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup parent, @Nullable Bundle savedInstanceState);\n\n    void onCreate(@Nullable Bundle savedInstanceState);\n\n    void onDestroy();\n\n    void onDestroyView();\n\n    void onInflate(@NonNull Activity activity, @NonNull Bundle options, @Nullable Bundle onInflate);\n\n    void onLowMemory();\n\n    void onPause();\n\n    void onResume();\n\n    void onSaveInstanceState(@NonNull Bundle outState);\n\n    void onStart();\n\n    void onStop();\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/dynamic/ObjectWrapper.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.dynamic;\n\nimport android.os.IBinder;\n\nimport androidx.annotation.Nullable;\n\nimport java.lang.reflect.Field;\n\npublic class ObjectWrapper<T> extends IObjectWrapper.Stub {\n    private final T t;\n\n    public ObjectWrapper(T t) {\n        this.t = t;\n    }\n\n    @Nullable\n    public static Object unwrap(IObjectWrapper obj) {\n        if (obj == null) {\n            return null;\n        }\n\n        if (obj instanceof ObjectWrapper) {\n            return ((ObjectWrapper) obj).t;\n        }\n\n        IBinder binder = obj.asBinder();\n        Field[] fields = binder.getClass().getDeclaredFields();\n\n        if (fields.length < 1) {\n            throw new IllegalArgumentException(\"No fields were found\");\n        }\n\n        // Ignore synthetic field(s) from JaCoCo or elsewhere\n        // https://www.jacoco.org/jacoco/trunk/doc/faq.html\n\n        @Nullable\n        Field field = null;\n\n        for (Field currentField : fields) {\n            if (currentField.isSynthetic()) {\n                continue;\n            }\n\n            if (field == null) {\n                field = currentField;\n            } else {\n                throw new IllegalArgumentException(\"Too many non-synthetic fields were found\");\n            }\n        }\n\n        if (field == null) {\n            throw new IllegalArgumentException(\"No non-synthetic fields were found\");\n        }\n\n        if (!field.isAccessible()) {\n            field.setAccessible(true);\n            try {\n                return field.get(binder);\n            } catch (NullPointerException localNullPointerException) {\n                throw new IllegalArgumentException(\"Binder object is null.\",\n                        localNullPointerException);\n            } catch (IllegalArgumentException localIllegalArgumentException) {\n                throw new IllegalArgumentException(\"remoteBinder is the wrong class.\",\n                        localIllegalArgumentException);\n            } catch (IllegalAccessException localIllegalAccessException) {\n                throw new IllegalArgumentException(\"Could not access the field in remoteBinder.\",\n                        localIllegalAccessException);\n            }\n        } else {\n            throw new IllegalArgumentException();\n        }\n    }\n\n    @Nullable\n    public static <T> T unwrapTyped(IObjectWrapper obj, Class<T> clazz) {\n        try {\n            return clazz.cast(unwrap(obj));\n        } catch (ClassCastException e) {\n            return null;\n        }\n    }\n\n    public static <T> ObjectWrapper<T> wrap(T t) {\n        return new ObjectWrapper<T>(t);\n    }\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/dynamic/OnDelegateCreatedListener.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.dynamic;\n\npublic interface OnDelegateCreatedListener<T extends LifecycleDelegate> {\n    void onDelegateCreated(T delegate);\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/dynamite/DynamiteModule.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.dynamite;\n\nimport android.content.Context;\nimport android.os.IBinder;\nimport android.os.RemoteException;\nimport android.util.Log;\nimport androidx.annotation.NonNull;\n\nimport java.lang.reflect.Field;\nimport java.util.Objects;\n\npublic class DynamiteModule {\n    private static final String TAG = \"DynamiteModule\";\n\n    public static final int NONE = 0;\n    public static final int LOCAL = -1;\n    public static final int REMOTE = 1;\n\n    @NonNull\n    public static final VersionPolicy PREFER_REMOTE = (context, moduleId, versions) -> {\n        VersionPolicy.SelectionResult result = new VersionPolicy.SelectionResult();\n        result.remoteVersion = versions.getRemoteVersion(context, moduleId, true);\n        if (result.remoteVersion != 0) {\n            result.selection = REMOTE;\n        } else {\n            result.localVersion = versions.getLocalVersion(context, moduleId);\n            if (result.localVersion != 0) {\n                result.selection = LOCAL;\n            }\n        }\n        return result;\n    };\n    @NonNull\n    public static final VersionPolicy PREFER_LOCAL = (context, moduleId, versions) -> {\n        VersionPolicy.SelectionResult result = new VersionPolicy.SelectionResult();\n        result.localVersion = versions.getLocalVersion(context, moduleId);\n        if (result.localVersion != 0) {\n            result.selection = LOCAL;\n        } else {\n            result.remoteVersion = versions.getRemoteVersion(context, moduleId, true);\n            if (result.remoteVersion != 0) {\n                result.selection = REMOTE;\n            }\n        }\n        return result;\n    };\n\n    public interface VersionPolicy {\n        interface IVersions {\n            int getLocalVersion(@NonNull Context context, @NonNull String moduleId);\n\n            int getRemoteVersion(@NonNull Context context, @NonNull String moduleId, boolean forceStaging) throws LoadingException;\n\n            IVersions Default = new IVersions() {\n                @Override\n                public int getLocalVersion(@NonNull Context context, @NonNull String moduleId) {\n                    return DynamiteModule.getLocalVersion(context, moduleId);\n                }\n\n                @Override\n                public int getRemoteVersion(@NonNull Context context, @NonNull String moduleId, boolean forceStaging) throws LoadingException {\n                    return DynamiteModule.getRemoteVersion(context, moduleId, forceStaging);\n                }\n            };\n        }\n\n        class SelectionResult {\n            public int localVersion = 0;\n            public int remoteVersion = 0;\n            public int selection = NONE;\n        }\n\n        SelectionResult selectModule(@NonNull Context context, @NonNull String moduleId, @NonNull IVersions versions) throws LoadingException;\n    }\n\n    public static class LoadingException extends Exception {\n        public LoadingException(String message) {\n            super(message);\n        }\n\n        public LoadingException(String message, Throwable cause) {\n            super(message, cause);\n        }\n    }\n\n    private Context moduleContext;\n\n    private DynamiteModule(Context moduleContext) {\n        this.moduleContext = moduleContext;\n    }\n\n    public Context getModuleContext() {\n        return moduleContext;\n    }\n\n    public static int getLocalVersion(@NonNull Context context, @NonNull String moduleId) {\n        try {\n            ClassLoader classLoader = context.getApplicationContext().getClassLoader();\n            Class<?> clazz = classLoader.loadClass(\"com.google.android.gms.dynamite.descriptors.\" + moduleId + \".ModuleDescriptor\");\n            Field moduleIdField = clazz.getDeclaredField(\"MODULE_ID\");\n            Field moduleVersionField = clazz.getDeclaredField(\"MODULE_VERSION\");\n            if (!Objects.equals(moduleIdField.get(null), moduleId)) {\n                Log.e(TAG, \"Module descriptor id '\" + moduleIdField.get(null) + \"' didn't match expected id '\" + moduleId + \"'\");\n                return 0;\n            }\n            return moduleVersionField.getInt(null);\n        } catch (ClassNotFoundException e) {\n            Log.w(TAG, \"Local module descriptor class for\" + moduleId + \" not found.\");\n            return 0;\n        } catch (Exception e) {\n            Log.e(TAG, \"Failed to load module descriptor class.\", e);\n            return 0;\n        }\n    }\n\n    public static int getRemoteVersion(@NonNull Context context, @NonNull String moduleId) {\n        return getRemoteVersion(context, moduleId, false);\n    }\n\n    public static int getRemoteVersion(@NonNull Context context, @NonNull String moduleId, boolean forceStaging) {\n        Log.e(TAG, \"Remote modules not yet supported\");\n        return 0;\n    }\n\n    @NonNull\n    public static DynamiteModule load(@NonNull Context context, @NonNull VersionPolicy policy, @NonNull String moduleId) throws LoadingException {\n        Context applicationContext = context.getApplicationContext();\n        if (applicationContext == null) throw new LoadingException(\"null application Context\", null);\n        try {\n            VersionPolicy.SelectionResult result = policy.selectModule(context, moduleId, VersionPolicy.IVersions.Default);\n            Log.i(TAG, \"Considering local module \" + moduleId + \":\" + result.localVersion + \" and remote module \" + moduleId + \":\" + result.remoteVersion);\n            switch (result.selection) {\n                case NONE:\n                    throw new LoadingException(\"No acceptable module \" + moduleId + \" found. Local version is \" + result.localVersion + \" and remote version is \" + result.remoteVersion + \".\");\n                case LOCAL:\n                    Log.i(TAG, \"Selected local version of \" + moduleId);\n                    return new DynamiteModule(context);\n                case REMOTE:\n                    throw new UnsupportedOperationException();\n                default:\n                    throw new LoadingException(\"VersionPolicy returned invalid code:\" + result.selection);\n            }\n        } catch (LoadingException loadingException) {\n            throw loadingException;\n        } catch (Throwable e) {\n            throw new LoadingException(\"Failed to load remote module.\", e);\n        }\n    }\n\n    @NonNull\n    public IBinder instantiate(@NonNull String className) throws LoadingException {\n        try {\n            return (IBinder) this.moduleContext.getClassLoader().loadClass(className).newInstance();\n        } catch (ClassNotFoundException | IllegalAccessException | InstantiationException | RuntimeException e) {\n            throw new LoadingException(\"Failed to instantiate module class: \" + className, e);\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/security/ProviderInstaller.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.security;\n\nimport android.content.Context;\nimport android.content.Intent;\n\nimport java.security.Provider;\n\n/**\n * A utility class for installing a dynamically updatable {@link Provider} to replace the platform default provider.\n */\npublic class ProviderInstaller {\n    public static final String PROVIDER_NAME = \"GmsCore_OpenSSL\";\n\n    /**\n     * Installs the dynamically updatable security provider, if it's not already installed.\n     *\n     * @throws GooglePlayServicesRepairableException\n     * @throws GooglePlayServicesNotAvailableException\n     */\n    public static void installIfNeeded(Context context) {\n\n    }\n\n    /**\n     * Asynchronously installs the dynamically updatable security provider, if it's not already installed. This method must be called on the UI thread.\n     *\n     * @param context\n     * @param listener called when the installation completes\n     */\n    public static void installIfNeededAsync(Context context, ProviderInstallListener listener) {\n        if (listener != null) listener.onProviderInstalled();\n    }\n\n    /**\n     * Callback for notification of the result of provider installation.\n     */\n    public interface ProviderInstallListener {\n        /**\n         * Called when installing the provider fails. This method is always called on the UI thread.\n         * <p>\n         * Implementers may use {@code errorCode} with the standard UI elements provided by {@link GoogleApiAvailability}; or {@code recoveryIntent} to implement custom UI.\n         *\n         * @param errorCode      error code for the failure, for use with {@link GoogleApiAvailability#showErrorDialogFragment(Activity, int, int)} or {@link GoogleApiAvailability#showErrorNotification(Context, ConnectionResult)}\n         * @param recoveryIntent if non-null, an intent that can be used to install or update Google Play Services such that the provider can be installed\n         */\n        void onProviderInstallFailed(int errorCode, Intent recoveryIntent);\n\n        /**\n         * Called when installing the provider succeeds. This method is always called on the UI thread.\n         */\n        void onProviderInstalled();\n    }\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/com/google/android/gms/stats/GCoreWakefulBroadcastReceiver.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.stats;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.legacy.content.WakefulBroadcastReceiver;\nimport org.microg.gms.common.Hide;\n\n/**\n * TODO: This should end up in play-services-stats eventually\n */\n@Hide\npublic abstract class GCoreWakefulBroadcastReceiver extends WakefulBroadcastReceiver {\n    public static boolean completeWakefulIntent(@NonNull Context context, @Nullable Intent intent) {\n        if (intent == null) return false;\n        return WakefulBroadcastReceiver.completeWakefulIntent(intent);\n    }\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/org/microg/gms/auth/AuthConstants.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.auth;\n\npublic class AuthConstants {\n    public static final String DEFAULT_ACCOUNT = \"<<default account>>\";\n    public static final String SCOPE_GET_ACCOUNT_ID = \"^^_account_id_^^\";\n    public static final String PROVIDER_METHOD_GET_ACCOUNTS = \"get_accounts\";\n    public static final String PROVIDER_METHOD_CLEAR_PASSWORD = \"clear_password\";\n    public static final String PROVIDER_EXTRA_CLEAR_PASSWORD = \"clear_password\";\n    public static final String PROVIDER_EXTRA_ACCOUNTS = \"accounts\";\n    public static final String DEFAULT_ACCOUNT_TYPE = \"com.google\";\n    public static final String WORK_ACCOUNT_TYPE = \"com.google.work\";\n\n    public static final String KEY_ACCOUNT_SERVICES = \"services\";\n    public static final String KEY_ACCOUNT_CAPABILITIES = \"capabilities\";\n\n    public static final String GOOGLE_USER_ID = \"GoogleUserId\";\n    public static final String GOOGLE_SIGN_IN_STATUS = \"googleSignInStatus\";\n    public static final String GOOGLE_SIGN_IN_ACCOUNT = \"googleSignInAccount\";\n    public static final String SIGN_IN_ACCOUNT = \"signInAccount\";\n    public static final String ERROR_CODE = \"errorCode\";\n    public static final String SIGN_IN_CREDENTIAL = \"sign_in_credential\";\n    public static final String STATUS = \"status\";\n    public static final String SCOPE_OAUTH2 = \"oauth2:\";\n    public static final String SCOPE_EM_OP_PRO = \"oauth2:email openid profile\";\n    public static final String GOOGLE_SIGN_IN_AUTHORIZATION_RESULT = \"authorization_result\";\n\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/org/microg/gms/common/Constants.java",
    "content": "/*\n * Copyright (C) 2013-2019 microG Project Team\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 org.microg.gms.common;\n\nimport com.google.android.gms.common.BuildConfig;\n\npublic class Constants {\n    public static final int GMS_VERSION_CODE = (BuildConfig.VERSION_CODE / 1000) * 1000;\n    public static final String GMS_PACKAGE_NAME = \"com.google.android.gms\";\n    public static final String USER_MICROG_PACKAGE_NAME = \"org.microg.gms\";\n    public static final String GSF_PACKAGE_NAME = \"com.google.android.gsf\";\n    public static final String GMS_PACKAGE_SIGNATURE_SHA1 = \"38918a453d07199354f8b19af05ec6562ced5788\";\n    public static final String GMS_SECONDARY_PACKAGE_SIGNATURE_SHA1 = \"bd32424203e0fb25f36b57e5aa356f9bdd1da998\";\n    public static final String MICROG_PACKAGE_SIGNATURE_SHA1 = \"10321bd893f69af97f7573aafe9de1dc0901f3a1\";\n    @Deprecated\n    public static final int MAX_REFERENCE_VERSION = GMS_VERSION_CODE;\n    public static final String VENDING_PACKAGE_NAME = \"com.android.vending\";\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/org/microg/gms/common/GmsService.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.common;\n\npublic enum GmsService {\n    UNKNOWN(-2),\n    ANY(-1),\n    GAMES(1, \"com.google.android.gms.games.service.START\", \"com.google.android.gms.games.internal.connect.service.START\"),\n    PLUS(2, \"com.google.android.gms.plus.service.START\", \"com.google.android.gms.plus.service.internal.START\"),\n    PANORAMA(3, \"com.google.android.gms.panorama.service.START\"),\n    WALLET(4, \"com.google.android.gms.wallet.service.BIND\"),\n    PEOPLE(5, \"com.google.android.gms.people.service.START\"),\n    LOCATION(6),\n    APP_STATE(7, \"com.google.android.gms.appstate.service.START\"),\n    ADMOB(8, \"com.google.android.gms.ads.service.START\"),\n    ACCOUNT(9, \"com.google.android.gms.accounts.ACCOUNT_SERVICE\"),\n    CAST(10, \"com.google.android.gms.cast.service.BIND_CAST_DEVICE_CONTROLLER_SERVICE\"),\n    DRIVE(11, \"com.google.android.gms.drive.ApiService.START\"),\n    ADDRESS(12, \"com.google.android.gms.identity.service.BIND\"),\n    CAR(13, \"com.google.android.gms.car.service.START\"),\n    WEAR(14, \"com.google.android.gms.wearable.BIND\"),\n    AUTH_PROXY(16, \"com.google.android.gms.auth.service.START\"),\n    IDENTITY(15),\n    FITNESS(17, \"com.google.android.gms.fitness.GoogleFitnessService.START\"),\n    REMINDERS(18, \"com.google.android.gms.reminders.service.START\"),\n    LIGHT_INDEX(19, \"com.google.android.gms.icing.LIGHTWEIGHT_INDEX_SERVICE\"),\n    DEVICE_CONNECTIONS(20, \"com.google.android.gms.deviceconnection.service.START\"),\n    APP_DATA_SEARCH(21, \"com.google.android.gms.icing.INDEX_SERVICE\"),\n    REPORTING(22, \"com.google.android.gms.location.reporting.service.START\", \"com.google.android.location.reporting.service.START\"),\n    GOOGLE_LOCATION_MANAGER(23, \"com.google.android.location.internal.GoogleLocationManagerService.START\"),\n    PLAY_LOG(24, \"com.google.android.gms.playlog.service.START\"),\n    DROID_GUARD(25, \"com.google.android.gms.droidguard.service.START\"),\n    LOCKBOX(26, \"com.google.android.gms.lockbox.service.START\"),\n    CAST_MIRRORING(27, \"com.google.android.gms.cast_mirroring.service.START\"),\n    NETWORK_QUALITY(28, \"com.google.android.gms.mdm.services.START\"),\n    FEEDBACK(29, \"com.google.android.gms.feedback.internal.IFeedbackService\"),\n    SEARCH_ADMINISTRATION(30),\n    AUTO_BACKUP(31, \"com.google.android.gms.photos.autobackup.service.START\"),\n    SEARCH_QUERIES(32),\n    GLOBAL_SEARCH_ADMIN(33),\n    CLOUD_SAVE(34),\n    UDC(35, \"com.google.android.gms.udc.service.START\"),\n    SEARCH_CORPORA(36),\n    DEVICE_MANAGER(37, \"com.google.android.gms.mdm.services.DeviceManagerApiService.START\"),\n    PSEUDONYMOUS_ID(38, \"com.google.android.gms.pseudonymous.service.START\"),\n    COMMON(39, \"com.google.android.gms.common.service.START\"),\n    CLEARCUT_LOGGER(40, \"com.google.android.gms.clearcut.service.START\"),\n    USAGE_REPORTING(41, \"com.google.android.gms.usagereporting.service.START\"),\n    KIDS(42, \"com.google.android.gms.kids.service.START\"),\n    DOWNLOAD(43, \"com.google.android.gms.common.download.START\"),\n    SIGN_IN(44, \"com.google.android.gms.signin.service.START\"),\n    SAFETY_NET(45, \"com.google.android.gms.safetynet.service.START\"),\n    ADMOB_GSERVICES_VALUE(46, \"com.google.android.gms.ads.gservice.START\"),\n    CONTEXT_MANAGER(47, \"com.google.android.contextmanager.service.ContextManagerService.START\"),\n    AUDIO_MODEM(48, \"com.google.android.gms.audiomodem.service.AudioModemService.START\"),\n    NEARBY(49, \"com.google.android.gms.nearby.sharing.service.NearbySharingService.START\"),\n    LIGHTWEIGHT_NETWORK_QUALITY(50, \"com.google.android.gms.herrevad.services.LightweightNetworkQualityAndroidService.START\"),\n    PHENOTYPE(51, \"com.google.android.gms.phenotype.service.START\"),\n    VOICE_UNLOCK(52, \"com.google.android.gms.speech.service.START\"),\n\n    NEARBY_CONNECTIONS(54, \"com.google.android.gms.nearby.connection.service.START\"),\n    FIT_SENSORS(55, \"com.google.android.gms.fitness.SensorsApi\"),\n    FIT_RECORDING(56, \"com.google.android.gms.fitness.RecordingApi\"),\n    FIT_HISTORY(57, \"com.google.android.gms.fitness.HistoryApi\"),\n    FIT_SESSIONS(58, \"com.google.android.gms.fitness.SessionsApi\"),\n    FIT_BLE(59, \"com.google.android.gms.fitness.BleApi\"),\n    FIT_CONFIG(60, \"com.google.android.gms.fitness.ConfigApi\"),\n    FIT_INTERNAL(61, \"com.google.android.gms.fitness.InternalApi\"),\n    NEARBY_MESSAGES(62, \"com.google.android.gms.nearby.messages.service.NearbyMessagesService.START\"),\n    GOOGLE_HELP(63, \"com.google.android.gms.googlehelp.service.GoogleHelpService.START\"),\n    CHECKIN_CONFIG(64, \"com.google.android.gms.config.START\"),\n    PLACES_GEO_DATA(65, \"com.google.android.gms.location.places.GeoDataApi\"),\n    IME_UPDATES(66),\n    PLACES_PLACE_DETECTION(67, \"com.google.android.gms.location.places.PlaceDetectionApi\"),\n    AUTH_CREDENTIALS(68, \"com.google.android.gms.auth.api.credentials.service.START\"),\n    NEARBY_BOOTSTRAP(69, \"com.google.android.gms.nearby.bootstrap.service.NearbyBootstrapService.START\"),\n    PLUS_INTERNAL(70),\n    MAPS_API(71),\n    TRUSTAGENT_TRUSTED_DEVICES(72),\n    SEARCH_AUTH(73),\n    ACCOUNT_STATUS(74),\n    SMARTDEVICE_D2D_SOURCE_DEVICE(75, \"com.google.android.gms.smartdevice.d2d.SourceDeviceService.START\"),\n    SMARTDEVICE_D2D_TARGET_DEVICE(76, \"com.google.android.gms.smartdevice.d2d.TargetDeviceService.START\"),\n    APP_INVITE(77, \"com.google.android.gms.appinvite.service.START\"),\n    SEARCH_NATIVE_API(78),\n    WALLET_TAP_AND_PAY(79, \"com.google.android.gms.tapandpay.service.BIND\"),\n    CHROME_SYNC(80, \"com.google.android.gms.chromesync.service.START\"),\n    SMARTDEVICE_SETUP_ACCOUNTS_BOOTSTRAP(81, \"com.google.android.gms.smartdevice.setup.accounts.AccountsService.START\"),\n    GSA(82),\n    CAST_REMOTE_DISPLAY(83, \"com.google.android.gms.cast.remote_display.service.START\"),\n    TRUSTAGENT(85, \"com.google.android.gms.trustagent.StateApi.START\"),\n    TRUSTAGENT_STATE(85),\n    YOUTUBE(86),\n    AUTH_SIGN_IN(87),\n    VISION(88),\n    TRUSTAGENT_BRIDGE(89),\n    BACKUP_STATS(90),\n    AUTH_GOOGLE_SIGN_IN(91, \"com.google.android.gms.auth.api.signin.service.START\"),\n\n    MEASUREMENT(93, \"com.google.android.gms.measurement.START\"),\n    WEAVE_DEVICE(94),\n    AD_MEASUREMENT(95),\n\n\n    FREIGHTER(98, \"com.google.android.gms.freighter.service.START\"),\n    WEAVE_MANAGEMENT(99),\n    WEAVE_COMMAND(100),\n    WEAVE_APP_ACCESS(101),\n    WEAVE_EVENT(102),\n    WEAVE_LOCAL_STATELESS_DEVICE(103),\n    AUTH_AUTHZEN_KEY(104),\n    SCREEN_CAPTURE(105),\n    APP_INVITE_INTERNAL(106),\n    AUTH_AUTHZEN_INTERNAL_DATA(107),\n    AUTH_PROXIMITY(108),\n    ACCOUNT_SETTINGS(109),\n    GUNS(110, \"com.google.android.gms.notifications.service.START\"),\n    BEACON(111, \"com.google.android.gms.beacon.internal.IBleService.START\"),\n    FIREBASE_AUTH(112, \"com.google.firebase.auth.api.gms.service.START\"),\n    APP_INDEXING(113, \"com.google.android.gms.icing.APP_INDEXING_SERVICE\"),\n    WALLET_P2P(114),\n    WALLET_P2P_INTERNAL(115),\n    GASS(116, \"com.google.android.gms.gass.START\"),\n    U2F_API(117),\n    U2F_PRIVILEGED_API(118),\n    U2F_ZERO_PARTY_API(119),\n    WORK_ACCOUNT_API(120, \"com.google.android.gms.auth.account.workaccount.START\"),\n    INSTANT_APPS(121, \"com.google.android.gms.instantapps.START\"),\n    CAST_FIRST_PARTY(122, \"com.google.android.gms.cast.firstparty.START\"),\n    ADMOB_CACHE(123, \"com.google.android.gms.ads.service.CACHE\"),\n    BOOT_COUNT(124, \"com.google.android.gms.clearcut.bootcount.service.START\"),\n    FIT_GOALS(125),\n    SMS_RETRIEVER(126, \"com.google.android.gms.auth.api.phone.service.SmsRetrieverApiService.START\"),\n    MOBILE_DATA_HUB(127),\n    AUTH_ACCOUNT_TRANSFER(128),\n    CRYPTAUTH_API(129, \"com.google.android.gms.auth.cryptauth.cryptauthservice.START\"),\n    CHECKIN_API(130, \"com.google.android.gms.checkin.START\"),\n    DYNAMIC_LINKS_API(131, \"com.google.firebase.dynamiclinks.service.START\"),\n    FONT_API(132, \"com.google.android.gms.fonts.service.START\"),\n    TEST_SUPPORT(133),\n    LOCATION_SHARING(134),\n    ROMANESCO(135, \"com.google.android.gms.romanesco.service.START\"),\n    AUTH_MANAGED_EMM_API(136),\n    NETWORK_SCORER(137),\n    NETWORK_RECOMMENDATION(138),\n    BRELLA(139, \"com.google.android.gms.learning.trainer.START\"),\n    RESTORE_SESSION(140),\n    PEER_DOWNLOAD_MANAGER(141),\n    AUTH_PROXIMITY_DEVICE_SYNC(142),\n    REACHABILITY(143),\n    AUTH_PROXIMITY_SECURE_CHANNEL(144),\n    PREDICT_ON_DEVICE(145),\n    APP_PREVIEW_MESSAGING(146),\n    LOCAL_RESTORE(147),\n    FIDO2_API(148, \"com.google.android.gms.fido.fido2.regular.START\"),\n    FIDO2_PRIVILEGED_API(149, \"com.google.android.gms.fido.fido2.privileged.START\"),\n    TELEPHONY_SPAM(150),\n    AUTH_UNCERTIFIED_DEVICE(151),\n    MOBILE_DATA_DOWNLOAD(152, \"com.google.android.mdd.service.START\"),\n    AUTH_ACCOUNT_DATA(153, \"com.google.android.gms.auth.account.data.service.START\"),\n    AUDIT(154, \"com.google.android.gms.audit.service.START\"),\n    CONSTELLATION(155, \"com.google.android.gms.constellation.service.START\"),\n    GROWTH(156),\n    SYSTEM_UPDATE(157, \"com.google.android.gms.update.START_API_SERVICE\"),\n    MOBILE_DATA_PLAN(158),\n    SMARTDEVICE_WIFI_HELPER(159),\n    MOBSTORE_FILE(160, \"com.google.android.mobstore.service.START\"),\n    CAST_API(161),\n    CURATOR(162),\n    USER_LOCATION(163, \"com.google.android.gms.userlocation.service.START\"),\n    MOBILE_DATA_HUB_LISTENER(164),\n    EXAMPLE(165),\n    ADMOB_HTTP_CLIENT(166, \"com.google.android.gms.ads.service.HTTP\"),\n    LANGUAGE_PROFILE(167, \"com.google.android.gms.languageprofile.service.START\"),\n    MDNS(168, \"com.google.android.gms.mdns.service.START\"),\n    NEARBY_SETUP(169),\n    ANALYTICS(170),\n    SUBSCRIPTIONS(171),\n    FOLSOM(172, \"com.google.android.gms.auth.key.retrieval.service.START\"),\n    SEMANTIC_LOCATION(173, \"com.google.android.gms.semanticlocation.service.START_ODLH\"),\n    VEHICLE(174),\n    BACKUP_NOW(175),\n    AUTH_EARLY_UPDATE(176),\n    AUTOFILL(177),\n    MATCHSTICK(178),\n    AUTH_CREDENTIALS_INTERNAL(179),\n    FIDO2_ZERO_PARTY_API(180, \"com.google.android.gms.fido.fido2.zeroparty.START\"),\n    G1_RESTORE(181, \"com.google.android.gms.backup.G1_RESTORE\"),\n    G1_BACKUP(182, \"com.google.android.gms.backup.G1_BACKUP\"),\n    CODELAB(183),\n    DRIVING_MODE(184),\n    OSS_LICENSES_SERVICE(185, \"com.google.android.gms.oss.licenses.service.START\"),\n    CLEAR_CONTACT_INTERACTIONS_SERVICE(186),\n    AUTH_MANAGED_POLICY_SERVICE(187),\n    PAY_SECURE_ELEMENT_SERVICE(188, \"com.google.android.gms.payse.service.BIND\"),\n    RCS(189, \"com.google.android.gms.rcs.START\"),\n    SMARTDEVICE_POST_SETUP(190),\n    CARRIER_AUTH(191, \"com.google.android.gms.carrierauth.service.START\"),\n    SYSTEM_UPDATE_SINGLE_UESR(192, \"com.google.android.gms.update.START_SINGLE_USER_API_SERVICE\"),\n    APPUSAGE(193, \"com.google.android.gms.appusage.service.START\"),\n    NEARBY_SHARING(194, \"com.google.android.gms.nearby.sharing.START_SERVICE\"),\n    ADMOB_CONSENT_SERVICE(195, \"com.google.android.gms.ads.service.CONSENT_LOOKUP\"),\n    CREDENTIAL_MANAGER(196, \"com.google.android.gms.credential.manager.service.firstparty.START\"),\n    SMS_RETRIEVER_INTERNAL(197, \"com.google.android.gms.auth.api.phone.service.InternalService.START\"),\n    PAY(198, \"com.google.android.gms.pay.service.BIND\", \"com.google.android.gms.pay.service.THIRD_PARTY\"),\n    ASTERISM(199, \"com.google.android.gms.asterism.service.START\"),\n    MOBILE_SUBSCRIPTION(200),\n    GMS_RESTORE(201, \"com.google.android.gms.backup.GMS_MODULE_RESTORE\"),\n    FACS_CACHE(202, \"com.google.android.gms.facs.cache.service.START\"),\n    ADMOB_SDK_SIGNAL(203),\n    PLATFORM_CONFIGURATOR(204),\n    RECAPTCHA(205, \"com.google.android.gms.recaptcha.service.START\"),\n    DUOKIT_SERVICE(206),\n    SYSTEM_UPDATE_TV_API(207),\n    CONTACT_SYNC(208, \"com.google.android.gms.people.contactssync.service.START\"),\n    FEEDBACK_CAR(209),\n    SMARTDEVICE_SOURCE_DIRECT_TRANSFER(210),\n    SMARTDEVICE_TARGET_DIRECT_TRANSFER(211),\n    AUTH_API_IDENTITY_SIGNIN(212, \"com.google.android.gms.auth.api.identity.service.signin.START\"),\n    IDENTITY_GIS_INTERNAL(213),\n    FIDO_CREDENTIAL_STORE(214, \"com.google.android.gms.fido.credentialstore.internal_service.START\"),\n    MDI_SYNC(215, \"com.google.android.gms.mdisync.service.START\"),\n    EVENT_ATTESTATION(216, \"com.google.android.gms.ads.identifier.service.EVENT_ATTESTATION\"),\n    GCONNECT_EXP(217),\n    SCHEDULER(218, \"com.google.android.gms.scheduler.ACTION_PROXY_SCHEDULE\"),\n    AUTH_API_IDENTITY_AUTHORIZATION(219, \"com.google.android.gms.auth.api.identity.service.authorization.START\"),\n    FACS_INTERNAL_SYNC(220, \"com.google.android.gms.facs.internal.service.START\"),\n    AUTH_CONFIG_SYNC(221, \"com.google.android.gms.auth.config.service.START\"),\n    ENTERPRISE(222),\n    AUTH_API_IDENTITY_CREDENTIAL_SAVING(223, \"com.google.android.gms.auth.api.identity.service.credentialsaving.START\"),\n    GOOGLE_AUTH(224, \"com.google.android.gms.auth.account.authapi.START\"),\n    ENTERPRISE_LOADER(225, \"com.google.android.gms.enterprise.loader.service.START\"),\n    THUNDERBIRD(226, \"com.google.android.gms.thunderbird.service.START\"),\n\n\n    BACKUP(229),\n    BUGREPORT(230),\n    CORE(231),\n    CHIMERA_DEBUG(232),\n    CHIMERA_COMPONENTS_TEST(233),\n    AUTH_EASYUNLOCK(234),\n    COMMON_ACCOUNT(235),\n    NEARBY_EXPOSURE_NOTIFICATION(236, \"com.google.android.gms.nearby.exposurenotification.START\"),\n    CONTACT_INTERACTIONS(237),\n    PERMISSION(238),\n    PSEUDONYMOUS(239),\n    SIGNIN(240),\n    SETUP_SERVICES(241),\n    PHONESKY_RECOVERY(242),\n    SMARTDEVICE(243),\n    STATEMENT_SERVICE(244),\n    SMART_PROFILE(245),\n    TRON(246),\n    SECURITY(247),\n\n    GAMES_UPGRADE(249),\n    SUBSCRIBED_FEEDS(250),\n    WESTWORLD(251),\n    OTA(252),\n    PLACES(253),\n    STATS(254),\n    PLATFORM_DATA_INDEXER(255),\n    CONTAINER(256),\n    GMS_COMPLIANCE(257, \"com.google.android.gms.gmscompliance.service.START\"),\n    AUTH_BLOCKSTORE(258, \"com.google.android.gms.auth.blockstore.service.START\"),\n    COMMON_BASE(259),\n    GROWTH_UPGRADEPARTY(260),\n    ADSIDENTITY(261),\n    FIDO_SOURCE_DIRECT_TRANSFER(262, \"com.google.android.gms.fido.sourcedevice.service.START\"),\n    STREAM_PROTECT(263),\n    CHIMERA(264),\n    NEARBY_FAST_PAIR(265, \"com.google.android.gms.nearby.fastpair.START\"),\n\n    COMMON_API(267),\n    LIGHTER_MESSAGING(268, \"com.google.android.gms.matchstick.lighter.service.START\"),\n    FIDO_TARGET_DIRECT_TRANSFER(269, \"com.google.android.gms.fido.targetdevice.internal_service.START\"),\n    CLIENT_TELEMETRY(270, \"com.google.android.gms.common.telemetry.service.START\"),\n\n\n    FIDO_CLIENT_UI(273),\n    FIDO_SHARED_LIBRARY(274),\n    SMARTDEVICE_SECOND_DEVICE_AUTH(275, \"com.google.android.gms.setup.auth.SecondDeviceAuth.START\"),\n    AUTH_MAGICTETHER(276),\n    LOCATION_SHARING_REPORTER(277, \"com.google.android.gms.locationsharingreporter.service.START\"),\n\n    WALLET_OCR(279, \"com.google.android.gms.ocr.service.START\"),\n    ALL(280),\n    WALLET_OCR_INTERNAL(281, \"com.google.android.gms.ocr.service.internal.START\"),\n    GSERVICES_API(282),\n    FIND_MY_DEVICE(283),\n    FIND_MY_DEVICE_SPOT(284),\n    PO_TOKENS(285, \"com.google.android.gms.potokens.service.START\"),\n    EXPOSURE_NOTIFICATION_PROMOS(286),\n    FIDO_AUTHENTICATOR_SERVICE(287),\n    CONNECTED_HOME(288),\n    DIGITAL_CAR_KEYS(289, \"com.google.android.gms.dck.service.START\"),\n\n\n    COMMUNAL(292),\n    PRESENCE_MANAGER(293),\n    TRUSTLET_ONBODY(294),\n    TRUSTLET_PLACE(295),\n    GROWTH_FEATUREDROPS(296),\n    GEO_TIME_ZONE(297),\n    NEARBY_UWB(298),\n    GMSCORE_LOGGER(299),\n    APP_SET_ID(300, \"com.google.android.gms.appset.service.START\"),\n    NNAPI_DRIVER_MANAGER(301),\n    CRED_SYNC(302),\n    CHROME_SYNC_FIRST_PARTY(303),\n    USONIA(304),\n    THREADNETWORK(305, \"com.google.android.gms.threadnetwork.service.START\"),\n    CODELAB_SEPARATE(306),\n    TRUSTAGENT_AUTHENTICATORS(307),\n    MODULE_INSTALL(308, \"com.google.android.gms.chimera.container.moduleinstall.ModuleInstallService.START\"),\n    CHIMERA_BROTLI_STREAM(309),\n    PERSONALSAFETY(310),\n    GAME_PLATFORM(311),\n    DTDI(312),\n    GROWTH_UIFLOW(313),\n    SEMANTIC_LOCATION_HISTORY(314, \"com.google.android.gms.semanticlocationhistory.service.START\", \"com.google.android.gms.semanticlocationhistory.zeroparty.service.START\"),\n    INAPP_REACH(315, \"com.google.android.gms.inappreach.service.START\"),\n    DEVICE_ACCOUNT(316),\n    NEARBY_PRESENCE(317),\n    ENTERPRISE_LOST_MODE(318),\n    HOMEGRAPH(319),\n    AUTH_MANAGED_WORK_PROFILE(320),\n    MDOC_STORE(321, \"com.google.android.gms.mdocstore.service.MDOC_STORE\"),\n    DEVICE_PERFORMANCE(322),\n\n\n    MULTIPACKAGE_DEBUG(325),\n    TIME(326),\n    TRUSTAGENT_ACTIVE_UNLOCK(327),\n    QUICKSTART(328),\n    CORE_SETTINGS(329),\n    PHOTOPICKER(330),\n    SEALEDCOMPUTING(331),\n    APPSEARCH(332),\n    ESIM(333),\n    APP_ERROR(334, \"com.google.android.gms.apperrors.service.START_APP_ERROR\"),\n    ADID(335),\n\n    HOME(336),\n\n    MLBENCHMARK(339),\n    MLBENCHMARK_INSTALLER(340),\n    FACTORY_RESET_PROTECTION(341),\n    NOTIFICATIONS(342),\n    GOOGLE_AUTH_AANG(343, \"com.google.android.gms.auth.aang.events.services.START\"),\n\n    ANTIFINGERPRINTING(345),\n    CALLSTREAMING(346),\n    FIDO2_FIRST_PARTY_API(347),\n    MULTIDEVICE(348),\n    GOOGLESETTINGS(349),\n    HTTPFLAGS(350),\n    SETUP_SERVICES_REMOTE_SETUP(351),\n    IDENTITY_CREDENTIALS(352),\n    AMBIENT_CONTEXT(353),\n    SAFE_BROWSING(354),\n    MULTIDEVICE_API_FEATURE_SETTINGS(355),\n    MULTIDEVICE_API_PROFILE(356),\n    DATA_COMPLIANCE(357),\n    NOTIFICATIONS_REGISTRATION(358),\n    SERVICE_ENTITLEMENT(359),\n    CASTAUTH(360),\n    BLINDAUTH(361),\n    MLKIT_DOCSCAN_UI(362),\n    AUTH_CREDENTIALS_FIDO2_AUTHENTICATOR(363),\n    COBALT(364),\n    TENSORGPS(365),\n    NETWORKTRANSPARENCY(366),\n    COMMUNAL_AUTH(367),\n    CRONET(368),\n\n    PLAY_INTEGRITY_API(370),\n    PLAY_INTEGRITY_AUTOPROTECT(371),\n    AQR(372),\n    AUTH_MANAGED_DEVICE_POSTURE_SERVICE(373),\n\n    CORE_NOTIFICATIONS(375),\n    KIDS_AUTH(376),\n    NUDGES(377),\n    CAMERA_LOW_LIGHT(378),\n    IDENTITY_FIDO_INTERNAL(379),\n    RECAPTCHABASE(380),\n    AUTH_RESTORE_CREDENTIAL(381),\n    CONTACTKEYS(382),\n    HEALTH_CONNECT_BACKUPS(383),\n    SETUP_SERVICES_TOS_ACCEPTANCE(384),\n    LOCATION_NETWORK(385, \"com.google.android.gms.location.network.service.START\"),\n    SPATULA_SETTINGS(386),\n    NOTIFICATIONS_CAPPING(387, \"com.google.android.gms.notifications.capping.api.NotificationsCappingApiService.START\"),\n    CAMERA_FEATURE_COMBINATION_QUERY(388),\n    AUTOMOTIVE_SETUP_SERVICES_INTERNAL(389),\n    CRISISALERTS(390),\n\n    CONTINUITY(392),\n    SETUP_SERVICES_TOS_ACCEPTANCE_STATUS(393),\n    SAMPLESETTINGS(394),\n    MOTION(395),\n    SIGNIFICANT_PLACES(396),\n    SAFETY_CORE(397),\n    MOTION_SICKNESS_ASSIST(398),\n    CRYPTAUTH_AUTO_ENROLLMENT(399),\n    CODELAB_HELLO_WORLD(400),\n    CONTINUITY_API_CROSS_DEVICE(401),\n    AUTH_API_IDENTITY_CREDENTIAL_PROVIDER(402),\n    CORE_CUI_ADVISE(403),\n    IDENTITY_GIS_PERSISTENT(404),\n    EARLY_CHECK_IN_EXAMPLE(405),\n\n    MULTIDEVICE_SYNC(407),\n\n    MANAGESTORAGE(409),\n    NATIVE_SANDBOX(410),\n    MISSED_CALL_RETRIEVER(411),\n    HEALTH_TRACKING(412),\n    FAMILY_CONTEXTUAL_CARD(413),\n    CLEARCUT_LOGGER_SAMPLING(414, \"com.google.android.gms.clearcut.sampler.service.START\"),\n    TRACING(415),\n    DEPENDENCY_INSTALLER(416),\n    ADVANCED_PROTECTION(417),\n\n    ACTION_LEARNER(419),\n    PIXELPREDICTIONS(420),\n    RESTRICTEDNETWORK(421),\n    ACCESSIBILITY_DEEP_LINKS(422),\n    SCREENREACTIONS(423),\n    PERFETTO_PROCESSOR(424),\n    GOOGLEONE(425),\n    DEMO_ACCOUNT(426),\n    IDENTITY_FIDO_FIRST_PARTY(427),\n    PWM(428),\n    FIREBASE_FPNV(429),\n    TENSORGPS_DEBUG(430),\n    THREADNETWORK_ZERO_PARTY_API(431),\n    CAST_INTELLIGENT_DEVICE_SUGGESTIONS(432),\n    SIGNATURE_VERIFICATION(433),\n    WALLET_TAP_AND_PAY_SINGLE_USER(434),\n    BANK_SCAM_WARNING(435),\n    STORAGE_ESCALATION_CARD(436),\n    INTRUSION_DETECTION(437),\n    ACCOUNT_PROFILE(438),\n    BACKUP_STATE(439),\n    FILAMENT_SUPPORT_CHECKER(440),\n    SPOON_PC(441),\n    LOCATION_SHARING_API(442),\n    MEMENTO(443),\n    BUILD_HORIZON(444),\n    CLEARCUT_LOG_MANAGER(445),\n\n    NATIVE_HOTLOADER(447),\n    TELEMETRY_NOTIFICATION(449, \"com.google.android.gms.common.telemetry.notification.service.START\"),\n    ;\n\n    public int SERVICE_ID;\n    public String ACTION;\n    public String[] SECONDARY_ACTIONS;\n\n    GmsService(int serviceId, String... actions) {\n        this.SERVICE_ID = serviceId;\n        this.ACTION = actions.length > 0 ? actions[0] : null;\n        this.SECONDARY_ACTIONS = actions;\n    }\n\n    public interface ADVERTISING_ID {\n        // Has no service id\n        String ACTION = \"com.google.android.gms.ads.identifier.service.START\";\n    }\n\n    public static GmsService byServiceId(int serviceId) {\n        for (GmsService service : values()) {\n            if (service.SERVICE_ID == serviceId) return service;\n        }\n        return UNKNOWN;\n    }\n\n    public static GmsService byAction(String action) {\n        for (GmsService service : values()) {\n            for (String serviceAction : service.SECONDARY_ACTIONS) {\n                if (serviceAction.equals(action)) return service;\n            }\n        }\n        return UNKNOWN;\n    }\n\n    public static String nameFromServiceId(int serviceId) {\n        return byServiceId(serviceId).toString(serviceId);\n    }\n\n    public String toString(int serviceId) {\n        if (this != UNKNOWN) return toString();\n        return \"UNKNOWN(\" + serviceId + \")\";\n    }\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/org/microg/gms/common/Hide.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.common;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Hide the class, method or field from the public API.\n */\n@Retention(RetentionPolicy.SOURCE)\n@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.CONSTRUCTOR})\npublic @interface Hide {\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/org/microg/gms/common/PublicApi.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.common;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * An class, method or field is named public, if it can be used with the original play services\n * client library.\n */\n@Retention(RetentionPolicy.SOURCE)\n@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.CONSTRUCTOR})\npublic @interface PublicApi {\n    /**\n     * @return the first version that contains the given class, method or field\n     */\n    String since() default \"0\";\n\n    /**\n     * @return the last version that contains the given class, method or field\n     */\n    String until() default \"latest\";\n\n    /**\n     * Used on a method or field to exclude it from the public api if the corresponding class was\n     * marked as public api.\n     *\n     * @return true if the method or field is not part of the public api\n     * @deprecated use {@link Hide} instead\n     */\n    @Deprecated\n    boolean exclude() default false;\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/org/microg/gms/gcm/GcmConstants.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.gcm;\n\npublic final class GcmConstants {\n    public static final String ACTION_C2DM_RECEIVE = \"com.google.android.c2dm.intent.RECEIVE\";\n    public static final String ACTION_C2DM_REGISTER = \"com.google.android.c2dm.intent.REGISTER\";\n    public static final String ACTION_C2DM_REGISTRATION = \"com.google.android.c2dm.intent.REGISTRATION\";\n    public static final String ACTION_C2DM_UNREGISTER = \"com.google.android.c2dm.intent.UNREGISTER\";\n    public static final String ACTION_GCM_SEND = \"com.google.android.gcm.intent.SEND\";\n    public static final String ACTION_NOTIFICATION_OPEN = \"com.google.android.gms.gcm.NOTIFICATION_OPEN\";\n    public static final String ACTION_NOTIFICATION_DISMISS = \"com.google.android.gms.gcm.NOTIFICATION_DISMISS\";\n    public static final String ACTION_SCHEDULE = \"com.google.android.gms.gcm.ACTION_SCHEDULE\";\n    public static final String ACTION_TASK_READY = \"com.google.android.gms.gcm.ACTION_TASK_READY\";\n    public static final String ACTION_TASK_INITIALZE = \"com.google.android.gms.gcm.SERVICE_ACTION_INITIALIZE\";\n    public static final String ACTION_INSTANCE_ID = \"com.google.android.gms.iid.InstanceID\";\n\n    public static final String EXTRA_APP = \"app\";\n    public static final String EXTRA_APP_OVERRIDE = \"org.microg.gms.gcm.APP_OVERRIDE\";\n    public static final String EXTRA_APP_ID = \"appid\";\n    public static final String EXTRA_APP_VERSION_CODE = \"app_ver\";\n    public static final String EXTRA_APP_VERSION_NAME = \"app_ver_name\";\n    public static final String EXTRA_CLIENT_VERSION = \"cliv\";\n    public static final String EXTRA_COMPONENT = \"component\";\n    public static final String EXTRA_COLLAPSE_KEY = \"collapse_key\";\n    public static final String EXTRA_DELAY = \"google.delay\";\n    public static final String EXTRA_DELETE = \"delete\";\n    public static final String EXTRA_ERROR = \"error\";\n    public static final String EXTRA_FROM = \"from\";\n    public static final String EXTRA_GSF_INTENT = \"GSF\";\n    public static final String EXTRA_GMS_VERSION = \"gmsv\";\n    public static final String EXTRA_IS_MESSENGER2 = \"messenger2\";\n    public static final String EXTRA_KID = \"kid\";\n    public static final String EXTRA_MESSENGER = \"google.messenger\";\n    public static final String EXTRA_MESSAGE_TYPE = \"message_type\";\n    public static final String EXTRA_MESSAGE_ID = \"google.message_id\";\n    public static final String EXTRA_OS_VERSION = \"osv\";\n    public static final String EXTRA_PENDING_INTENT = \"com.google.android.gms.gcm.PENDING_INTENT\";\n    public static final String EXTRA_PUBLIC_KEY = \"pub2\";\n    public static final String EXTRA_RAWDATA = \"rawData\";\n    public static final String EXTRA_RAWDATA_BASE64 = \"gcm.rawData64\";\n    public static final String EXTRA_REGISTRATION_ID = \"registration_id\";\n    public static final String EXTRA_RETRY_AFTER = \"Retry-After\";\n    public static final String EXTRA_SCHEDULER_ACTION = \"scheduler_action\";\n    public static final String EXTRA_SCOPE = \"scope\";\n    public static final String EXTRA_SENDER = \"sender\";\n    public static final String EXTRA_SENDER_LEGACY = \"legacy.sender\";\n    public static final String EXTRA_SEND_TO = \"google.to\";\n    public static final String EXTRA_SEND_FROM = \"google.from\";\n    public static final String EXTRA_SENT_TIME = \"google.sent_time\";\n    public static final String EXTRA_SIGNATURE = \"sig\";\n    public static final String EXTRA_SUBSCIPTION = \"subscription\";\n    public static final String EXTRA_SUBTYPE = \"subtype\";\n    public static final String EXTRA_USE_GSF = \"useGsf\";\n    public static final String EXTRA_TAG = \"tag\";\n    public static final String EXTRA_TOPIC = \"gcm.topic\";\n    public static final String EXTRA_TTL = \"google.ttl\";\n    public static final String EXTRA_UNREGISTERED = \"unregistered\";\n    public static final String EXTRA_ACCOUNT_NAME = \"a\";\n    public static final String EXTRA_REG_ID = \"id\";\n    public static final String EXTRA_AUTHS_TOKEN = \"t\";\n    public static final String EXTRA_GCM_BODY = \"gcmb\";\n    public static final String EXTRA_GMS_GNOTS_PAYLOAD = \"gms.gnots.payload\";\n\n    public static final String MESSAGE_TYPE_GCM = \"gcm\";\n    public static final String MESSAGE_TYPE_DELETED_MESSAGE = \"deleted_message\";\n    public static final String MESSAGE_TYPE_SEND_ERROR = \"send_error\";\n    public static final String MESSAGE_TYPE_SEND_EVENT = \"send_event\";\n\n    public static final String SCHEDULER_ACTION_CANCEL = \"CANCEL_TASK\";\n    public static final String SCHEDULER_ACTION_CANCEL_ALL = \"CANCEL_ALL\";\n    public static final String SCHEDULER_ACTION_SCHEDULE = \"SCHEDULE_TASK\";\n\n    public static final String PERMISSION_GTALK = \"com.google.android.gtalkservice.permission.GTALK_SERVICE\";\n    public static final String PERMISSION_NETWORK_TASK = \"com.google.android.gms.permission.BIND_NETWORK_TASK_SERVICE\";\n    public static final String PERMISSION_RECEIVE = \"com.google.android.c2dm.permission.RECEIVE\";\n    public static final String PERMISSION_SEND = \"com.google.android.c2dm.permission.SEND\";\n\n    public static final String ERROR_SERVICE_NOT_AVAILABLE = \"SERVICE_NOT_AVAILABLE\";\n\n    public static final String ERROR_INVALID_FID = \"Invalid argument for the given fid\";\n\n    public static final String INSTANCE_ID_SCOPE_GCM = \"GCM\";\n\n    public static final String GCMID_INSTANCE_ID = \"google.com/iid\";\n    public static final String GCMID_REFRESH = \"gcm.googleapis.com/refresh\";\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/org/microg/gms/utils/ToStringHelper.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.utils;\n\nimport android.util.Base64;\n\nimport java.util.Arrays;\n\npublic class ToStringHelper {\n    private StringBuilder sb;\n    private boolean hasField;\n    private boolean hasValue;\n    private boolean hasEnd;\n\n    public ToStringHelper(String name) {\n        this.sb = new StringBuilder(name).append(\"[\");\n    }\n\n    public static ToStringHelper name(String name) {\n        return new ToStringHelper(name);\n    }\n\n    public ToStringHelper value(String val) {\n        if (!hasField) {\n            if (hasValue) sb.append(',');\n            sb.append(val);\n            hasValue = true;\n        }\n        return this;\n    }\n\n    public ToStringHelper value(long val) {\n        return value(Long.toString(val));\n    }\n\n    public ToStringHelper value(double val) {\n        return value(Double.toString(val));\n    }\n\n    public ToStringHelper value(Object val) {\n        if (val instanceof Long) value((long) val);\n        if (val instanceof Double) value((double) val);\n        return value(val, false);\n    }\n\n    public ToStringHelper value(Object val, boolean forceNull) {\n        if (val == null && !forceNull) return this;\n        return value(val == null ? \"null\" : val.toString());\n    }\n\n    public ToStringHelper value(byte[] val) {\n        return value(val, false);\n    }\n\n    public ToStringHelper value(byte[] val, boolean forceNull) {\n        if (val == null && !forceNull) return this;\n        return value(val == null ? \"null\" : Base64.encodeToString(val, Base64.NO_WRAP | Base64.NO_PADDING | Base64.URL_SAFE));\n    }\n\n    private ToStringHelper fieldUnquoted(String name, String val) {\n        if (hasValue || hasField) sb.append(\", \");\n        sb.append(name).append('=').append(val);\n        hasField = true;\n        return this;\n    }\n\n    public ToStringHelper field(String name, String val) {\n        return field(name, val, false);\n    }\n\n    public ToStringHelper field(String name, String val, boolean forceNull) {\n        if (val == null && !forceNull) return this;\n        if (val == null) return fieldUnquoted(name, \"null\");\n        if (hasValue || hasField) sb.append(\", \");\n        sb.append(name).append(\"=\\\"\").append(val.replace(\"\\\"\", \"\\\\\\\"\")).append('\"');\n        hasField = true;\n        return this;\n    }\n\n    public ToStringHelper field(String name, long val) {\n        return fieldUnquoted(name, Long.toString(val));\n    }\n\n    public ToStringHelper field(String name, double val) {\n        return fieldUnquoted(name, Double.toString(val));\n    }\n\n    public ToStringHelper field(String name, boolean val) {\n        return fieldUnquoted(name, Boolean.toString(val));\n    }\n\n    public ToStringHelper field(String name, Object val) {\n        if (val instanceof Long) return field(name, (long) val);\n        if (val instanceof Double) return field(name, (double) val);\n        if (val instanceof Boolean) return field(name, (boolean) val);\n        return field(name, val, false);\n    }\n\n    public ToStringHelper field(String name, Object val, boolean forceNull) {\n        if (val == null && !forceNull) return this;\n        return fieldUnquoted(name, val == null ? \"null\" : val.toString());\n    }\n\n    public ToStringHelper field(String name, byte[] val) {\n        return field(name, val, false);\n    }\n\n    public ToStringHelper field(String name, byte[] val, boolean forceNull) {\n        if (val == null && !forceNull) return this;\n        return fieldUnquoted(name, val == null ? \"null\" : Base64.encodeToString(val, Base64.NO_WRAP | Base64.NO_PADDING | Base64.URL_SAFE));\n    }\n\n    public ToStringHelper field(String name, Object[] val) {\n        return field(name, val, false);\n    }\n\n    public ToStringHelper field(String name, Object[] val, boolean forceNull) {\n        if (val == null && !forceNull) return this;\n        return fieldUnquoted(name, val == null ? \"null\" : Arrays.toString(val));\n    }\n\n    public String end() {\n        if (!hasEnd) sb.append(']');\n        hasEnd = true;\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/org/microg/gms/utils/WorkSourceUtil.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.utils;\n\nimport android.os.WorkSource;\nimport android.util.Log;\n\nimport java.lang.reflect.Method;\n\nimport static android.os.Build.VERSION.SDK_INT;\n\npublic class WorkSourceUtil {\n    private static final String TAG = \"WorkSourceUtil\";\n\n    private static Method getMethod(String name, Class<?>... parameterTypes) throws Exception {\n        Method method = WorkSource.class.getMethod(name, parameterTypes);\n        method.setAccessible(true);\n        return method;\n    }\n\n    private static <T> T invokeMethod(WorkSource workSource, Method method, Object... args) throws Exception {\n        return (T) method.invoke(workSource, args);\n    }\n\n    private static <T> T invokeMethod(WorkSource workSource, String name, Object... args) throws Exception {\n        return invokeMethod(workSource, getMethod(name), args);\n    }\n\n    public static void add(WorkSource workSource, int uid, String packageName) {\n        try {\n            invokeMethod(workSource, getMethod(\"add\", Integer.TYPE, String.class), uid, packageName);\n        } catch (Exception e) {\n            try {\n                invokeMethod(workSource, getMethod(\"add\", Integer.TYPE), uid);\n            } catch (Exception ex) {\n                // Ignore\n            }\n        }\n    }\n\n    public static int size(WorkSource workSource) {\n        try {\n            return invokeMethod(workSource, \"size\");\n        } catch (Exception e) {\n            return 0;\n        }\n    }\n\n    public static boolean isEmpty(WorkSource workSource) {\n        if (SDK_INT >= 28) {\n            try {\n                return invokeMethod(workSource, \"isEmpty\");\n            } catch (Exception e) {\n                // Ignore and fall-through to size()\n            }\n        }\n        return size(workSource) == 0;\n    }\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/org/microg/safeparcel/AutoSafeParcelable.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2015, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.safeparcel;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.util.Log;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\npublic abstract class AutoSafeParcelable extends AbstractSafeParcelable {\n    private static final String TAG = \"SafeParcel\";\n\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        Creator<Parcelable> creator = SafeParcelReflectionUtil.getCreator(this.getClass());\n        if (creator instanceof SafeParcelableCreatorAndWriter) {\n            ((SafeParcelableCreatorAndWriter<AutoSafeParcelable>) (SafeParcelableCreatorAndWriter<?>) creator).writeToParcel(this, dest, flags);\n        } else {\n            Log.w(TAG, \"AutoSafeParcelable is not using SafeParcelableCreatorAndWriter\");\n            SafeParcelReflectionUtil.writeObject(this, dest, flags);\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public static <T extends AbstractSafeParcelable> SafeParcelableCreatorAndWriter<T> findCreator(java.lang.Class<T> tClass) {\n        try {\n            return AbstractSafeParcelable.findCreator(tClass);\n        } catch (Exception e) {\n            if (AutoSafeParcelable.class.isAssignableFrom(tClass)) {\n                return (SafeParcelableCreatorAndWriter<T>) new AutoCreator<>((java.lang.Class<AutoSafeParcelable>) tClass);\n            } else {\n                throw new RuntimeException(\"AutoSafeParcelable.findCreator() invoked with non-AutoSafeParcelable\");\n            }\n        }\n    }\n\n    @Deprecated\n    public static class AutoCreator<T extends AutoSafeParcelable> extends ReflectedSafeParcelableCreatorAndWriter<T> {\n        public AutoCreator(java.lang.Class<T> tClass) {\n            super(tClass);\n        }\n    }\n}"
  },
  {
    "path": "play-services-basement/src/main/java/org/microg/safeparcel/ReflectedSafeParcelableCreatorAndWriter.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.safeparcel;\n\nimport android.os.Parcel;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport java.lang.reflect.Array;\n\npublic class ReflectedSafeParcelableCreatorAndWriter<T extends AutoSafeParcelable> implements SafeParcelableCreatorAndWriter<T> {\n\n    private final SafeParcelReflectionUtil.ClassDescriptor<T> descriptor;\n\n    public ReflectedSafeParcelableCreatorAndWriter(Class<T> tClass) {\n        this.descriptor = new SafeParcelReflectionUtil.ClassDescriptor<>(tClass);\n    }\n\n    @Override\n    public T createFromParcel(Parcel parcel) {\n        return SafeParcelReflectionUtil.createObject(parcel, descriptor);\n    }\n\n    @Override\n    public void writeToParcel(T object, Parcel parcel, int flags) {\n        SafeParcelReflectionUtil.writeObject(object, parcel, flags, descriptor);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public T[] newArray(int i) {\n        return (T[]) Array.newInstance(descriptor.tClass, i);\n    }\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/org/microg/safeparcel/SafeParcelReflectionUtil.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2015, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.safeparcel;\n\nimport android.os.Bundle;\nimport android.os.IBinder;\nimport android.os.IInterface;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.util.Log;\nimport android.util.SparseArray;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelReader;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelWriter;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport org.microg.gms.common.Hide;\n\nimport java.lang.reflect.*;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n@Hide\npublic final class SafeParcelReflectionUtil {\n    private static final String TAG = \"SafeParcel\";\n\n    private SafeParcelReflectionUtil() {\n    }\n\n    @Deprecated\n    public static <T extends AutoSafeParcelable> T createObject(Class<T> tClass, Parcel in) {\n        ClassDescriptor<T> descriptor = new ClassDescriptor<>(tClass);\n        return createObject(in, descriptor);\n    }\n\n    public static <T extends AutoSafeParcelable> T createObject(Parcel in, ClassDescriptor<T> descriptor) {\n        try {\n            Constructor<T> constructor = descriptor.constructor;\n            T t = constructor.newInstance();\n            readObject(t, in, descriptor);\n            return t;\n        } catch (Exception e) {\n            throw new RuntimeException(\"Can't construct object\", e);\n        }\n    }\n\n    @Deprecated\n    public static void writeObject(AutoSafeParcelable object, Parcel parcel, int flags) {\n        if (object == null)\n            throw new NullPointerException();\n        Class<?> clazz = object.getClass();\n        ClassDescriptor<?> descriptor = new ClassDescriptor<>(clazz);\n        writeObject(object, parcel, flags, descriptor);\n    }\n\n    public static <T extends AutoSafeParcelable> void writeObject(T object, Parcel parcel, int flags, ClassDescriptor<?> descriptor) {\n        int start = SafeParcelWriter.writeObjectHeader(parcel);\n        for (ClassDescriptor.FieldDescriptor fieldDescriptor : descriptor.fields.values()) {\n            try {\n                writeField(object, parcel, flags, fieldDescriptor);\n            } catch (Exception e) {\n                Log.w(TAG, \"Error writing field: \" + e);\n            }\n        }\n        SafeParcelWriter.finishObjectHeader(parcel, start);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Deprecated\n    public static <T extends AutoSafeParcelable> void readObject(T object, Parcel parcel) {\n        if (object == null)\n            throw new NullPointerException();\n        Class<T> clazz = (Class<T>) object.getClass();\n        ClassDescriptor<T> descriptor = new ClassDescriptor<>(clazz);\n        readObject(object, parcel, descriptor);\n    }\n\n    public static <T extends AutoSafeParcelable> void readObject(T object, Parcel parcel, ClassDescriptor<T> descriptor) {\n        if (object == null)\n            throw new NullPointerException();\n        int end = SafeParcelReader.readObjectHeader(parcel);\n        while (parcel.dataPosition() < end) {\n            int header = SafeParcelReader.readHeader(parcel);\n            int fieldId = SafeParcelReader.getFieldId(header);\n            ClassDescriptor.FieldDescriptor fieldDescriptor = descriptor.fields.get(fieldId);\n            if (fieldDescriptor == null) {\n                Log.d(TAG, String.format(\"Unknown field id %d in %s, skipping.\", fieldId, descriptor.tClass.getName()));\n                SafeParcelReader.skip(parcel, header);\n            } else {\n                try {\n                    readField(object, parcel, header, fieldDescriptor);\n                } catch (Exception e) {\n                    Log.w(TAG, String.format(\"Error reading field: %d of type %s in %s, skipping.\", fieldId, fieldDescriptor.type, descriptor.tClass.getName()), e);\n                    SafeParcelReader.skip(parcel, header);\n                }\n            }\n        }\n        if (parcel.dataPosition() > end) {\n            throw new RuntimeException(\"Overread allowed size end=\" + end);\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private static Parcelable.Creator<Parcelable> getCreator(Field field) {\n        Class<?> clazz = field.getType();\n        if (clazz.isArray()) {\n            clazz = clazz.getComponentType();\n        }\n        if (clazz != null && Parcelable.class.isAssignableFrom(clazz)) {\n            return getCreator((Class<? extends Parcelable>) clazz);\n        }\n        throw new RuntimeException(clazz + \" is not an Parcelable\");\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public static Parcelable.Creator<Parcelable> getCreator(Class<? extends Parcelable> clazz) {\n        try {\n            Field creatorField = clazz.getDeclaredField(\"CREATOR\");\n            creatorField.setAccessible(true);\n            return (Parcelable.Creator<Parcelable>) creatorField.get(null);\n        } catch (NoSuchFieldException e) {\n            throw new RuntimeException(clazz + \" is an Parcelable without CREATOR\");\n        } catch (IllegalAccessException e) {\n            throw new RuntimeException(\"CREATOR in \" + clazz + \" is not accessible\");\n        }\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    private static Class<?> getSubClass(Field field) {\n        SafeParceled safeParceled = field.getAnnotation(SafeParceled.class);\n        SafeParcelable.Field safeParcelableField = field.getAnnotation(SafeParcelable.Field.class);\n        if (safeParceled != null && safeParceled.subClass() != SafeParceled.class) {\n            return safeParceled.subClass();\n        } else if (safeParceled != null && !\"undefined\".equals(safeParceled.subType())) {\n            try {\n                return Class.forName(safeParceled.subType());\n            } catch (ClassNotFoundException e) {\n                throw new IllegalArgumentException(e);\n            }\n        } else if (safeParcelableField != null && safeParcelableField.subClass() != SafeParcelable.class) {\n            return safeParcelableField.subClass();\n        } else {\n            return null;\n        }\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    private static Class<?> getListItemClass(Field field) {\n        Class<?> subClass = getSubClass(field);\n        if (subClass != null || field.isAnnotationPresent(SafeParceled.class)) return subClass;\n        Type type = field.getGenericType();\n        if (type instanceof ParameterizedType) {\n            ParameterizedType pt = (ParameterizedType) type;\n            if (pt.getActualTypeArguments().length >= 1) {\n                Type t = pt.getActualTypeArguments()[0];\n                if (t instanceof Class) return (Class<?>) t;\n            }\n        }\n        return null;\n    }\n\n    private static ClassLoader getClassLoader(Class<?> clazz) {\n        return clazz == null || clazz.getClassLoader() == null ? ClassLoader.getSystemClassLoader() : clazz.getClassLoader();\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    private static boolean isSafeParceledField(Field field) {\n        return field.isAnnotationPresent(SafeParceled.class) || field.isAnnotationPresent(SafeParcelable.Field.class);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private static void writeField(AutoSafeParcelable object, Parcel parcel, int flags, ClassDescriptor.FieldDescriptor descriptor)\n            throws IllegalAccessException {\n        switch (descriptor.type) {\n            case Parcelable:\n                SafeParcelWriter.write(parcel, descriptor.id, (Parcelable) descriptor.field.get(object), flags, descriptor.mayNull);\n                break;\n            case Binder:\n                SafeParcelWriter.write(parcel, descriptor.id, (IBinder) descriptor.field.get(object), descriptor.mayNull);\n                break;\n            case Interface:\n                IInterface iInterface = ((IInterface) descriptor.field.get(object));\n                IBinder iBinder = iInterface != null ? iInterface.asBinder() : null;\n                SafeParcelWriter.write(parcel, descriptor.id, iBinder, descriptor.mayNull);\n                break;\n            case StringList:\n                SafeParcelWriter.writeStringList(parcel, descriptor.id, ((List<String>) descriptor.field.get(object)), descriptor.mayNull);\n                break;\n            case IntegerList:\n                SafeParcelWriter.writeIntegerList(parcel, descriptor.id, ((List<Integer>) descriptor.field.get(object)), descriptor.mayNull);\n                break;\n            case BooleanList:\n                SafeParcelWriter.writeBooleanList(parcel, descriptor.id, ((List<Boolean>) descriptor.field.get(object)), descriptor.mayNull);\n                break;\n            case LongList:\n                SafeParcelWriter.writeLongList(parcel, descriptor.id, ((List<Long>) descriptor.field.get(object)), descriptor.mayNull);\n                break;\n            case FloatList:\n                SafeParcelWriter.writeFloatList(parcel, descriptor.id, ((List<Float>) descriptor.field.get(object)), descriptor.mayNull);\n                break;\n            case DoubleList:\n                SafeParcelWriter.writeDoubleList(parcel, descriptor.id, ((List<Double>) descriptor.field.get(object)), descriptor.mayNull);\n                break;\n            case List: {\n                Class<?> clazz = descriptor.listItemClass;\n                if (clazz == null || !Parcelable.class.isAssignableFrom(clazz) || descriptor.useValueParcel) {\n                    SafeParcelWriter.write(parcel, descriptor.id, (List<?>) descriptor.field.get(object), descriptor.mayNull);\n                } else {\n                    SafeParcelWriter.write(parcel, descriptor.id, (List<Parcelable>) descriptor.field.get(object), flags, descriptor.mayNull);\n                }\n                break;\n            }\n            case Map:\n                SafeParcelWriter.write(parcel, descriptor.id, (Map) descriptor.field.get(object), descriptor.mayNull);\n                break;\n            case Bundle:\n                SafeParcelWriter.write(parcel, descriptor.id, (Bundle) descriptor.field.get(object), descriptor.mayNull);\n                break;\n            case ParcelableArray:\n                SafeParcelWriter.write(parcel, descriptor.id, (Parcelable[]) descriptor.field.get(object), flags, descriptor.mayNull);\n                break;\n            case StringArray:\n                SafeParcelWriter.write(parcel, descriptor.id, (String[]) descriptor.field.get(object), descriptor.mayNull);\n                break;\n            case ByteArray:\n                SafeParcelWriter.write(parcel, descriptor.id, (byte[]) descriptor.field.get(object), descriptor.mayNull);\n                break;\n            case ByteArrayArray:\n                SafeParcelWriter.write(parcel, descriptor.id, (byte[][]) descriptor.field.get(object), descriptor.mayNull);\n                break;\n            case FloatArray:\n                SafeParcelWriter.write(parcel, descriptor.id, (float[]) descriptor.field.get(object), descriptor.mayNull);\n                break;\n            case IntArray:\n                SafeParcelWriter.write(parcel, descriptor.id, (int[]) descriptor.field.get(object), descriptor.mayNull);\n                break;\n            case Integer:\n                SafeParcelWriter.write(parcel, descriptor.id, (Integer) descriptor.field.get(object));\n                break;\n            case Long:\n                SafeParcelWriter.write(parcel, descriptor.id, (Long) descriptor.field.get(object));\n                break;\n            case Short:\n                SafeParcelWriter.write(parcel, descriptor.id, (Short) descriptor.field.get(object));\n                break;\n            case Boolean:\n                SafeParcelWriter.write(parcel, descriptor.id, (Boolean) descriptor.field.get(object));\n                break;\n            case Float:\n                SafeParcelWriter.write(parcel, descriptor.id, (Float) descriptor.field.get(object));\n                break;\n            case Double:\n                SafeParcelWriter.write(parcel, descriptor.id, (Double) descriptor.field.get(object));\n                break;\n            case String:\n                SafeParcelWriter.write(parcel, descriptor.id, (String) descriptor.field.get(object), descriptor.mayNull);\n                break;\n            case Byte:\n                SafeParcelWriter.write(parcel, descriptor.id, (Byte) descriptor.field.get(object));\n                break;\n        }\n    }\n\n    private static void readField(AutoSafeParcelable object, Parcel parcel, int header, ClassDescriptor.FieldDescriptor descriptor)\n            throws IllegalAccessException {\n        switch (descriptor.type) {\n            case Parcelable:\n                descriptor.field.set(object, SafeParcelReader.readParcelable(parcel, header, descriptor.creator));\n                break;\n            case Binder:\n                descriptor.field.set(object, SafeParcelReader.readBinder(parcel, header));\n                break;\n            case Interface: {\n                boolean hasStub = false;\n                for (Class<?> aClass : descriptor.field.getType().getDeclaredClasses()) {\n                    try {\n                        descriptor.field.set(object, aClass.getDeclaredMethod(\"asInterface\", IBinder.class)\n                                .invoke(null, SafeParcelReader.readBinder(parcel, header)));\n                        hasStub = true;\n                        break;\n                    } catch (Exception ignored) {\n                    }\n                }\n                if (!hasStub) throw new RuntimeException(\"Field has broken interface: \" + descriptor.field);\n                break;\n            }\n            case StringList:\n                descriptor.field.set(object, SafeParcelReader.readStringList(parcel, header));\n                break;\n            case IntegerList:\n                descriptor.field.set(object, SafeParcelReader.readIntegerList(parcel, header));\n                break;\n            case BooleanList:\n                descriptor.field.set(object, SafeParcelReader.readBooleanList(parcel, header));\n                break;\n            case LongList:\n                descriptor.field.set(object, SafeParcelReader.readLongList(parcel, header));\n                break;\n            case FloatList:\n                descriptor.field.set(object, SafeParcelReader.readFloatList(parcel, header));\n                break;\n            case DoubleList:\n                descriptor.field.set(object, SafeParcelReader.readDoubleList(parcel, header));\n                break;\n            case List: {\n                Class<?> clazz = descriptor.listItemClass;\n                Object val;\n                if (clazz == null || !Parcelable.class.isAssignableFrom(clazz) || descriptor.useValueParcel) {\n                    val = SafeParcelReader.readList(parcel, header, getClassLoader(clazz));\n                } else {\n                    val = SafeParcelReader.readParcelableList(parcel, header, descriptor.creator);\n                }\n                descriptor.field.set(object, val);\n                break;\n            }\n            case Map: {\n                Class<?> clazz = descriptor.subClass;\n                Object val = SafeParcelReader.readMap(parcel, header, getClassLoader(clazz));\n                descriptor.field.set(object, val);\n                break;\n            }\n            case Bundle: {\n                Class<?> clazz = descriptor.subClass;\n                Object val;\n                if (clazz == null || !Parcelable.class.isAssignableFrom(clazz) || descriptor.useValueParcel /* should not happen on Bundles */) {\n                    val = SafeParcelReader.readBundle(parcel, header, getClassLoader(descriptor.field.getDeclaringClass()));\n                } else {\n                    val = SafeParcelReader.readBundle(parcel, header, getClassLoader(clazz));\n                }\n                descriptor.field.set(object, val);\n                break;\n            }\n            case ParcelableArray:\n                descriptor.field.set(object, SafeParcelReader.readParcelableArray(parcel, header, descriptor.creator));\n                break;\n            case StringArray:\n                descriptor.field.set(object, SafeParcelReader.readStringArray(parcel, header));\n                break;\n            case ByteArray:\n                descriptor.field.set(object, SafeParcelReader.readByteArray(parcel, header));\n                break;\n            case ByteArrayArray:\n                descriptor.field.set(object, SafeParcelReader.readByteArrayArray(parcel, header));\n                break;\n            case FloatArray:\n                descriptor.field.set(object, SafeParcelReader.readFloatArray(parcel, header));\n                break;\n            case IntArray:\n                descriptor.field.set(object, SafeParcelReader.readIntArray(parcel, header));\n                break;\n            case Integer: {\n                int i = SafeParcelReader.readInt(parcel, header);\n                if (descriptor.versionCode != -1 && i > descriptor.versionCode) {\n                    Log.d(TAG, String.format(\"Version code of %s (%d) is older than object read (%d).\", descriptor.field.getDeclaringClass().getName(), descriptor.versionCode, i));\n                }\n                descriptor.field.set(object, i);\n                break;\n            }\n            case Long: {\n                long l = SafeParcelReader.readLong(parcel, header);\n                if (descriptor.versionCode != -1 && l > descriptor.versionCode) {\n                    Log.d(TAG, String.format(\"Version code of %s (%d) is older than object read (%d).\", descriptor.field.getDeclaringClass().getName(), descriptor.versionCode, l));\n                }\n                descriptor.field.set(object, l);\n                break;\n            }\n            case Short: {\n                short i = SafeParcelReader.readShort(parcel, header);\n                if (descriptor.versionCode != -1 && i > descriptor.versionCode) {\n                    Log.d(TAG, String.format(\"Version code of %s (%d) is older than object read (%d).\", descriptor.field.getDeclaringClass().getName(), descriptor.versionCode, i));\n                }\n                descriptor.field.set(object, i);\n                break;\n            }\n            case Boolean:\n                descriptor.field.set(object, SafeParcelReader.readBool(parcel, header));\n                break;\n            case Float:\n                descriptor.field.set(object, SafeParcelReader.readFloat(parcel, header));\n                break;\n            case Double:\n                descriptor.field.set(object, SafeParcelReader.readDouble(parcel, header));\n                break;\n            case String:\n                descriptor.field.set(object, SafeParcelReader.readString(parcel, header));\n                break;\n            case Byte:\n                descriptor.field.set(object, SafeParcelReader.readByte(parcel, header));\n                break;\n            default:\n                throw new IllegalStateException(\"Unexpected value: \" + descriptor.type);\n        }\n    }\n\n    private enum SafeParcelType {\n        Parcelable, Binder, Interface, Bundle,\n        StringList, IntegerList, BooleanList, LongList, FloatList, DoubleList, List, Map,\n        ParcelableArray, StringArray, ByteArray, ByteArrayArray, FloatArray, IntArray,\n        Integer, Long, Short, Boolean, Float, Double, String, Byte;\n    }\n\n    public static class ClassDescriptor<T> {\n        Class<T> tClass;\n        Constructor<T> constructor;\n        Map<Integer, FieldDescriptor> fields = new HashMap<>();\n\n        public ClassDescriptor(Class<T> tClass) {\n            this.tClass = tClass;\n            try {\n                constructor = tClass.getDeclaredConstructor();\n                constructor.setAccessible(true);\n            } catch (Exception e) {\n                Log.w(TAG, tClass + \" has no default constructor\");\n            }\n            Class<?> clazz = tClass;\n            while (clazz != null) {\n                for (Field field : clazz.getDeclaredFields()) {\n                    if (isSafeParceledField(field)) {\n                        FieldDescriptor fieldDescriptor = new FieldDescriptor(field);\n                        fields.put(fieldDescriptor.id, fieldDescriptor);\n                    }\n                }\n                clazz = clazz.getSuperclass();\n            }\n        }\n\n        public static class FieldDescriptor {\n            Field field;\n            int id;\n            boolean mayNull;\n            SafeParcelable.Field annotation;\n            SafeParceled legacyAnnotation;\n            SafeParcelType type;\n            Parcelable.Creator<? extends Parcelable> creator;\n            long versionCode = -1;\n            Class<?> listItemClass;\n            boolean useValueParcel;\n            Class<?> subClass;\n\n            public FieldDescriptor(Field field) {\n                this.field = field;\n                field.setAccessible(true);\n                try {\n                    Field accessFlagsField = Field.class.getDeclaredField(\"accessFlags\");\n                    accessFlagsField.setAccessible(true);\n                    accessFlagsField.setInt(field, accessFlagsField.getInt(field) & ~Modifier.FINAL);\n                } catch (Exception e) {\n                    // Ignored\n                }\n                this.annotation = field.getAnnotation(SafeParcelable.Field.class);\n                this.legacyAnnotation = field.getAnnotation(SafeParceled.class);\n                if (annotation != null) {\n                    this.id = annotation.value();\n                    this.mayNull = annotation.mayNull();\n                    this.useValueParcel = annotation.useValueParcel();\n                    this.versionCode = annotation.versionCode();\n                } else if (legacyAnnotation != null) {\n                    this.id = legacyAnnotation.value();\n                    this.mayNull = legacyAnnotation.mayNull();\n                    this.useValueParcel = legacyAnnotation.useClassLoader();\n                } else {\n                    throw new IllegalArgumentException();\n                }\n                this.type = getType();\n                switch (type) {\n                    case Parcelable:\n                    case ParcelableArray:\n                        creator = getCreator(field);\n                        break;\n                    case List:\n                        if (listItemClass != null && Parcelable.class.isAssignableFrom(listItemClass)) {\n                            if (!this.useValueParcel) {\n                                creator = getCreator((Class<? extends Parcelable>) listItemClass);\n                            }\n                        }\n                        break;\n                    case Map:\n                    case Bundle:\n                        subClass = getSubClass(field);\n                        break;\n                }\n            }\n\n            private SafeParcelType getType() {\n                Class<?> clazz = field.getType();\n                Class<?> component = clazz.getComponentType();\n                if (clazz.isArray() && component != null) {\n                    if (Parcelable.class.isAssignableFrom(component)) return SafeParcelType.ParcelableArray;\n                    if (String.class.isAssignableFrom(component)) return SafeParcelType.StringArray;\n                    if (byte.class.isAssignableFrom(component)) return SafeParcelType.ByteArray;\n                    if (byte[].class.isAssignableFrom(component)) return SafeParcelType.ByteArrayArray;\n                    if (float.class.isAssignableFrom(component)) return SafeParcelType.FloatArray;\n                    if (int.class.isAssignableFrom(component)) return SafeParcelType.IntArray;\n                }\n                if (Bundle.class.isAssignableFrom(clazz))\n                    return SafeParcelType.Bundle;\n                if (Parcelable.class.isAssignableFrom(clazz))\n                    return SafeParcelType.Parcelable;\n                if (IBinder.class.isAssignableFrom(clazz))\n                    return SafeParcelType.Binder;\n                if (IInterface.class.isAssignableFrom(clazz))\n                    return SafeParcelType.Interface;\n                if (clazz == List.class || clazz == ArrayList.class) {\n                    listItemClass = getListItemClass(field);\n                    if (listItemClass == String.class && !useValueParcel) return SafeParcelType.StringList;\n                    if (listItemClass == Integer.class && annotation.useDirectList()) return SafeParcelType.IntegerList;\n                    if (listItemClass == Boolean.class && annotation.useDirectList()) return SafeParcelType.BooleanList;\n                    if (listItemClass == Long.class && annotation.useDirectList()) return SafeParcelType.LongList;\n                    if (listItemClass == Float.class && annotation.useDirectList()) return SafeParcelType.FloatList;\n                    if (listItemClass == Double.class && annotation.useDirectList()) return SafeParcelType.DoubleList;\n                    return SafeParcelType.List;\n                }\n                if (clazz == Map.class || clazz == HashMap.class)\n                    return SafeParcelType.Map;\n                if (clazz == int.class || clazz == Integer.class)\n                    return SafeParcelType.Integer;\n                if (clazz == short.class || clazz == Short.class)\n                    return SafeParcelType.Short;\n                if (clazz == boolean.class || clazz == Boolean.class)\n                    return SafeParcelType.Boolean;\n                if (clazz == long.class || clazz == Long.class)\n                    return SafeParcelType.Long;\n                if (clazz == float.class || clazz == Float.class)\n                    return SafeParcelType.Float;\n                if (clazz == double.class || clazz == Double.class)\n                    return SafeParcelType.Double;\n                if (clazz == byte.class || clazz == Byte.class)\n                    return SafeParcelType.Byte;\n                if (clazz == java.lang.String.class)\n                    return SafeParcelType.String;\n                throw new RuntimeException(\"Type is not yet usable with SafeParcelReflectionUtil: \" + clazz);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-basement/src/main/java/org/microg/safeparcel/SafeParceled.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2015, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.safeparcel;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.FIELD)\n@Deprecated\npublic @interface SafeParceled {\n    int value();\n\n    boolean mayNull() default false;\n\n    @Deprecated String subType() default \"undefined\";\n\n    Class subClass() default SafeParceled.class;\n\n    boolean useClassLoader() default false;\n}"
  },
  {
    "path": "play-services-basement/src/main/res/values/version.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2015 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<resources>\n    <integer name=\"google_play_services_version\">12451000</integer>\n</resources>\n"
  },
  {
    "path": "play-services-cast/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2015 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\nandroid {\n    namespace \"com.google.android.gms.cast\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    aidlPackagedList \"com/google/android/gms/cast/ApplicationMetadata.aidl\"\n    aidlPackagedList \"com/google/android/gms/cast/LaunchOptions.aidl\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n}\n\napply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG implementation of play-services-cast'\n\ndependencies {\n    // Dependencies from play-services-cast:21.2.0\n    api \"androidx.core:core:1.0.0\"\n    api \"androidx.mediarouter:mediarouter:1.2.2\"\n    api project(':play-services-base')\n    api project(':play-services-basement')\n    //api project(':play-services-flags')\n    api project(':play-services-tasks')\n\n    annotationProcessor project(':safe-parcel-processor')\n}\n"
  },
  {
    "path": "play-services-cast/core/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'kotlin-android'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\ndependencies {\n    implementation project(':play-services-cast')\n    implementation project(':play-services-base-core')\n\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion\"\n    implementation \"org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutineVersion\"\n    implementation \"org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutineVersion\"\n\n    // TODO: Switch to upstream once raw requests are merged\n    // https://github.com/vitalidze/chromecast-java-api-v2/pull/99\n    // implementation \"su.litvak.chromecast:api-v2:0.10.4\"\n    implementation \"info.armills.chromecast-java-api-v2:api-v2-raw-request:0.10.4-raw-request-1\"\n}\n\nandroid {\n    namespace \"org.microg.gms.cast.core\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    buildFeatures {\n        dataBinding = true\n    }\n\n    sourceSets {\n        main.java.srcDirs += 'src/main/kotlin'\n    }\n\n    lintOptions {\n        disable 'MissingTranslation'\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n\n    kotlinOptions {\n        jvmTarget = 1.8\n    }\n}\n\napply from: '../../gradle/publish-android.gradle'\n\ndescription = 'microG service implementation for play-services-cast'\n"
  },
  {
    "path": "play-services-cast/core/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <application>\n        <service android:name=\"com.google.android.gms.cast.media.CastMediaRouteProviderService\">\n            <intent-filter>\n                <action android:name=\"android.media.MediaRouteProviderService\" />\n            </intent-filter>\n        </service>\n\n        <service android:name=\"org.microg.gms.cast.CastDeviceControllerService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.cast.service.BIND_CAST_DEVICE_CONTROLLER_SERVICE\" />\n            </intent-filter>\n        </service>\n    </application>\n</manifest>\n"
  },
  {
    "path": "play-services-cast/core/src/main/java/com/google/android/gms/cast/media/CastMediaRouteProviderService.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.cast.media;\n\nimport org.microg.gms.cast.CastMediaRouteProvider;\n\nimport android.util.Log;\n\nimport androidx.mediarouter.media.MediaRouteProvider;\nimport androidx.mediarouter.media.MediaRouteProviderService;\n\npublic class CastMediaRouteProviderService extends MediaRouteProviderService {\n    private static final String TAG = CastMediaRouteProviderService.class.getSimpleName();\n\n    @Override\n    public MediaRouteProvider onCreateMediaRouteProvider() {\n        return new CastMediaRouteProvider(this);\n    }\n}\n"
  },
  {
    "path": "play-services-cast/core/src/main/java/org/microg/gms/cast/CastDeviceControllerImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.cast;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Collections;\n\nimport android.content.Context;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.os.Parcel;\nimport android.os.RemoteException;\nimport android.util.Base64;\nimport android.util.Log;\n\nimport com.google.android.gms.cast.ApplicationMetadata;\nimport com.google.android.gms.cast.ApplicationStatus;\nimport com.google.android.gms.cast.CastDevice;\nimport com.google.android.gms.cast.CastDeviceStatus;\nimport com.google.android.gms.cast.JoinOptions;\nimport com.google.android.gms.cast.LaunchOptions;\nimport com.google.android.gms.cast.internal.ICastDeviceController;\nimport com.google.android.gms.cast.internal.ICastDeviceControllerListener;\nimport com.google.android.gms.common.api.CommonStatusCodes;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.common.images.WebImage;\nimport com.google.android.gms.common.internal.BinderWrapper;\nimport com.google.android.gms.common.internal.GetServiceRequest;\n\nimport su.litvak.chromecast.api.v2.Application;\nimport su.litvak.chromecast.api.v2.ChromeCast;\nimport su.litvak.chromecast.api.v2.Namespace;\nimport su.litvak.chromecast.api.v2.ChromeCastConnectionEventListener;\nimport su.litvak.chromecast.api.v2.ChromeCastSpontaneousEventListener;\nimport su.litvak.chromecast.api.v2.ChromeCastRawMessageListener;\nimport su.litvak.chromecast.api.v2.ChromeCastConnectionEvent;\nimport su.litvak.chromecast.api.v2.ChromeCastSpontaneousEvent;\nimport su.litvak.chromecast.api.v2.ChromeCastRawMessage;\nimport su.litvak.chromecast.api.v2.AppEvent;\n\npublic class CastDeviceControllerImpl extends ICastDeviceController.Stub implements\n    ChromeCastConnectionEventListener,\n    ChromeCastSpontaneousEventListener,\n    ChromeCastRawMessageListener,\n    ICastDeviceControllerListener\n{\n    private static final String TAG = \"GmsCastDeviceController\";\n\n    private Context context;\n    private String packageName;\n    private CastDevice castDevice;\n    boolean notificationEnabled;\n    long castFlags;\n    ICastDeviceControllerListener listener;\n\n    ChromeCast chromecast;\n\n    String sessionId = null;\n\n    public CastDeviceControllerImpl(Context context, String packageName, Bundle extras) {\n        this.context = context;\n        this.packageName = packageName;\n\n        extras.setClassLoader(BinderWrapper.class.getClassLoader());\n        this.castDevice = CastDevice.getFromBundle(extras);\n        this.notificationEnabled = extras.getBoolean(\"com.google.android.gms.cast.EXTRA_CAST_FRAMEWORK_NOTIFICATION_ENABLED\");\n        this.castFlags = extras.getLong(\"com.google.android.gms.cast.EXTRA_CAST_FLAGS\");\n        BinderWrapper listenerWrapper = (BinderWrapper)extras.get(\"listener\");\n        if (listenerWrapper != null) {\n            this.listener = ICastDeviceControllerListener.Stub.asInterface(listenerWrapper.binder);\n        }\n\n        this.chromecast = new ChromeCast(this.castDevice.getAddress());\n        this.chromecast.registerListener(this);\n        this.chromecast.registerRawMessageListener(this);\n        this.chromecast.registerConnectionListener(this);\n    }\n\n    @Override\n    public void connectionEventReceived(ChromeCastConnectionEvent event) {\n        if (!event.isConnected()) {\n            this.onDisconnected(CommonStatusCodes.SUCCESS);\n        }\n    }\n\n    protected ApplicationMetadata createMetadataFromApplication(Application app) {\n        if (app == null) {\n            return null;\n        }\n        ApplicationMetadata metadata = new ApplicationMetadata();\n        metadata.applicationId = app.id;\n        metadata.name = app.name;\n        Log.d(TAG, \"unimplemented: ApplicationMetadata.images\");\n        Log.d(TAG, \"unimplemented: ApplicationMetadata.senderAppLaunchUri\");\n        metadata.images = new ArrayList<WebImage>();\n        metadata.namespaces = new ArrayList<String>();\n        for(Namespace namespace : app.namespaces) {\n            metadata.namespaces.add(namespace.name);\n        }\n        metadata.senderAppIdentifier = this.context.getPackageName();\n        return metadata;\n    }\n\n    @Override\n    public void spontaneousEventReceived(ChromeCastSpontaneousEvent event) {\n        switch (event.getType()) {\n            case MEDIA_STATUS:\n                break;\n            case STATUS:\n                su.litvak.chromecast.api.v2.Status status = (su.litvak.chromecast.api.v2.Status)event.getData();\n                Application app = status.getRunningApp();\n                ApplicationMetadata metadata = this.createMetadataFromApplication(app);\n                if (app != null) {\n                    this.onApplicationStatusChanged(new ApplicationStatus(app.statusText));\n                }\n                int activeInputState = status.activeInput ? 1 : 0;\n                int standbyState = status.standBy ? 1 : 0;\n                this.onDeviceStatusChanged(new CastDeviceStatus(status.volume.level, status.volume.muted, activeInputState, metadata, standbyState));\n                break;\n            case APPEVENT:\n                break;\n            case CLOSE:\n                this.onApplicationDisconnected(CommonStatusCodes.SUCCESS);\n                break;\n            default:\n                break;\n        }\n    }\n\n    @Override\n    public void rawMessageReceived(ChromeCastRawMessage message, Long requestId) {\n        switch (message.getPayloadType()) {\n            case STRING:\n                String response = message.getPayloadUtf8();\n                if (requestId == null) {\n                    this.onTextMessageReceived(message.getNamespace(), response);\n                } else {\n                    this.onSendMessageSuccess(response, requestId);\n                    this.onTextMessageReceived(message.getNamespace(), response);\n                }\n                break;\n            case BINARY:\n                byte[] payload = message.getPayloadBinary();\n                this.onBinaryMessageReceived(message.getNamespace(), payload);\n                break;\n        }\n    }\n\n    @Override\n    public void disconnect() {\n        try {\n            this.chromecast.disconnect();\n        } catch (IOException e) {\n            Log.e(TAG, \"Error disconnecting chromecast: \" + e.getMessage());\n            return;\n        }\n    }\n\n    @Override\n    public void sendMessage(String namespace, String message, long requestId) {\n        try {\n            this.chromecast.sendRawRequest(namespace, message, requestId);\n        } catch (IOException e) {\n            Log.w(TAG, \"Error sending cast message: \" + e.getMessage());\n            this.onSendMessageFailure(\"\", requestId, CommonStatusCodes.NETWORK_ERROR);\n            return;\n        }\n    }\n\n    @Override\n    public void stopApplication(String sessionId) {\n        try {\n            this.chromecast.stopSession(sessionId);\n        } catch (IOException e) {\n            Log.w(TAG, \"Error sending cast message: \" + e.getMessage());\n            return;\n        }\n        this.sessionId = null;\n    }\n\n    @Override\n    public void registerNamespace(String namespace) {\n        Log.d(TAG, \"unimplemented Method: registerNamespace\");\n    }\n\n    @Override\n    public void unregisterNamespace(String namespace) {\n        Log.d(TAG, \"unimplemented Method: unregisterNamespace\");\n    }\n\n    @Override\n    public void launchApplication(String applicationId, LaunchOptions launchOptions) {\n        Application app = null;\n        try {\n            app = this.chromecast.launchApp(applicationId);\n        } catch (IOException e) {\n            Log.w(TAG, \"Error launching cast application: \" + e.getMessage());\n            this.onApplicationConnectionFailure(CommonStatusCodes.NETWORK_ERROR);\n            return;\n        }\n        this.sessionId = app.sessionId;\n\n        ApplicationMetadata metadata = this.createMetadataFromApplication(app);\n        this.onApplicationConnectionSuccess(metadata, app.statusText, app.sessionId, true);\n    }\n\n    @Override\n    public void joinApplication(String applicationId, String sessionId, JoinOptions joinOptions) {\n        Log.d(TAG, \"unimplemented Method: joinApplication\");\n        this.launchApplication(applicationId, new LaunchOptions());\n    }\n\n    public void onDisconnected(int reason) {\n        if (this.listener != null) {\n            try {\n                this.listener.onDisconnected(reason);\n            } catch (RemoteException ex) {\n                Log.e(TAG, \"Error calling onDisconnected: \" + ex.getMessage());\n            }\n        }\n    }\n\n    public void onApplicationConnectionSuccess(ApplicationMetadata applicationMetadata, String applicationStatus, String sessionId, boolean wasLaunched) {\n        if (this.listener != null) {\n            try {\n                this.listener.onApplicationConnectionSuccess(applicationMetadata, applicationStatus, sessionId, wasLaunched);\n            } catch (RemoteException ex) {\n                Log.e(TAG, \"Error calling onApplicationConnectionSuccess: \" + ex.getMessage());\n            }\n        }\n    }\n\n    public void onApplicationConnectionFailure(int statusCode) {\n        if (this.listener != null) {\n            try {\n                this.listener.onApplicationConnectionFailure(statusCode);\n            } catch (RemoteException ex) {\n                Log.e(TAG, \"Error calling onApplicationConnectionFailure: \" + ex.getMessage());\n            }\n        }\n    }\n\n    public void onTextMessageReceived(String namespace, String message) {\n        if (this.listener != null) {\n            try {\n                this.listener.onTextMessageReceived(namespace, message);\n            } catch (RemoteException ex) {\n                Log.e(TAG, \"Error calling onTextMessageReceived: \" + ex.getMessage());\n            }\n        }\n    }\n\n    public void onBinaryMessageReceived(String namespace, byte[] data) {\n        if (this.listener != null) {\n            try {\n                this.listener.onBinaryMessageReceived(namespace, data);\n            } catch (RemoteException ex) {\n                Log.e(TAG, \"Error calling onBinaryMessageReceived: \" + ex.getMessage());\n            }\n        }\n    }\n\n    public void onApplicationDisconnected(int paramInt) {\n        Log.d(TAG, \"unimplemented Method: onApplicationDisconnected\");\n        if (this.listener != null) {\n            try {\n                this.listener.onApplicationDisconnected(paramInt);\n            } catch (RemoteException ex) {\n                Log.e(TAG, \"Error calling onApplicationDisconnected: \" + ex.getMessage());\n            }\n        }\n    }\n\n    public void onSendMessageFailure(String response, long requestId, int statusCode) {\n        if (this.listener != null) {\n            try {\n                this.listener.onSendMessageFailure(response, requestId, statusCode);\n            } catch (RemoteException ex) {\n                Log.e(TAG, \"Error calling onSendMessageFailure: \" + ex.getMessage());\n            }\n        }\n    }\n\n    public void onSendMessageSuccess(String response, long requestId) {\n        if (this.listener != null) {\n            try {\n                this.listener.onSendMessageSuccess(response, requestId);\n            } catch (RemoteException ex) {\n                Log.e(TAG, \"Error calling onSendMessageSuccess: \" + ex.getMessage());\n            }\n        }\n    }\n\n    public void onApplicationStatusChanged(ApplicationStatus applicationStatus) {\n        if (this.listener != null) {\n            try {\n                this.listener.onApplicationStatusChanged(applicationStatus);\n            } catch (RemoteException ex) {\n                Log.e(TAG, \"Error calling onApplicationStatusChanged: \" + ex.getMessage());\n            }\n        }\n    }\n\n    public void onDeviceStatusChanged(CastDeviceStatus deviceStatus) {\n        if (this.listener != null) {\n            try {\n                this.listener.onDeviceStatusChanged(deviceStatus);\n            } catch (RemoteException ex) {\n                Log.e(TAG, \"Error calling onDeviceStatusChanged: \" + ex.getMessage());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-cast/core/src/main/java/org/microg/gms/cast/CastDeviceControllerService.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.cast;\n\nimport android.os.IBinder;\nimport android.os.RemoteException;\nimport android.os.Parcel;\nimport android.util.ArrayMap;\nimport android.util.Log;\n\nimport com.google.android.gms.cast.CastDevice;\nimport com.google.android.gms.cast.internal.ICastDeviceControllerListener;\nimport com.google.android.gms.common.internal.GetServiceRequest;\nimport com.google.android.gms.common.internal.BinderWrapper;\nimport com.google.android.gms.common.internal.IGmsCallbacks;\n\nimport org.microg.gms.BaseService;\nimport org.microg.gms.common.GmsService;\n\nimport su.litvak.chromecast.api.v2.ChromeCast;\nimport su.litvak.chromecast.api.v2.ChromeCasts;\nimport su.litvak.chromecast.api.v2.Status;\nimport su.litvak.chromecast.api.v2.ChromeCastsListener;\n\npublic class CastDeviceControllerService extends BaseService {\n    private static final String TAG = CastDeviceControllerService.class.getSimpleName();\n\n    public CastDeviceControllerService() {\n        super(\"GmsCastDeviceControllerSvc\", GmsService.CAST);\n    }\n\n    @Override\n    public void handleServiceRequest(IGmsCallbacks callback, GetServiceRequest request, GmsService service) throws RemoteException {\n        callback.onPostInitComplete(0, new CastDeviceControllerImpl(this, request.packageName, request.extras), null);\n    }\n}\n"
  },
  {
    "path": "play-services-cast/core/src/main/java/org/microg/gms/cast/CastMediaRouteController.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.cast;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.os.AsyncTask;\nimport android.os.Handler;\nimport android.util.Log;\n\nimport androidx.mediarouter.media.MediaRouteProvider;\nimport androidx.mediarouter.media.MediaRouter;\n\nimport com.google.android.gms.common.images.WebImage;\nimport com.google.android.gms.cast.CastDevice;\n\nimport java.net.InetAddress;\nimport java.net.InetSocketAddress;\nimport java.net.Inet4Address;\nimport java.net.UnknownHostException;\nimport java.io.IOException;\nimport java.lang.Thread;\nimport java.lang.Runnable;\nimport java.util.ArrayList;\nimport java.util.Map;\nimport java.util.HashMap;\n\nimport su.litvak.chromecast.api.v2.ChromeCast;\nimport su.litvak.chromecast.api.v2.ChromeCasts;\nimport su.litvak.chromecast.api.v2.Status;\nimport su.litvak.chromecast.api.v2.ChromeCastsListener;\n\npublic class CastMediaRouteController extends MediaRouteProvider.RouteController {\n    private static final String TAG = CastMediaRouteController.class.getSimpleName();\n\n    private CastMediaRouteProvider provider;\n    private String routeId;\n    private ChromeCast chromecast;\n\n    public CastMediaRouteController(CastMediaRouteProvider provider, String routeId, String address) {\n        super();\n\n        this.provider = provider;\n        this.routeId = routeId;\n        this.chromecast = new ChromeCast(address);\n    }\n\n    public boolean onControlRequest(Intent intent, MediaRouter.ControlRequestCallback callback) {\n        Log.d(TAG, \"unimplemented Method: onControlRequest: \" + this.routeId);\n        return false;\n    }\n\n    public void onRelease() {\n        Log.d(TAG, \"unimplemented Method: onRelease: \" + this.routeId);\n    }\n\n    public void onSelect() {\n        Log.d(TAG, \"unimplemented Method: onSelect: \" + this.routeId);\n    }\n\n    public void onSetVolume(int volume) {\n        Log.d(TAG, \"unimplemented Method: onSetVolume: \" + this.routeId);\n    }\n\n    public void onUnselect() {\n        Log.d(TAG, \"unimplemented Method: onUnselect: \" + this.routeId);\n    }\n\n    public void onUnselect(int reason) {\n        Log.d(TAG, \"unimplemented Method: onUnselect: \" + this.routeId);\n    }\n\n    public void onUpdateVolume(int delta) {\n        Log.d(TAG, \"unimplemented Method: onUpdateVolume: \" + this.routeId);\n    }\n}\n"
  },
  {
    "path": "play-services-cast/core/src/main/java/org/microg/gms/cast/CastMediaRouteProvider.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.cast;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.content.IntentFilter;\nimport android.net.Uri;\nimport android.net.nsd.NsdManager;\nimport android.net.nsd.NsdServiceInfo;\nimport android.os.Bundle;\nimport android.os.AsyncTask;\nimport android.os.Handler;\nimport android.util.Log;\n\nimport androidx.mediarouter.media.MediaControlIntent;\nimport androidx.mediarouter.media.MediaRouteDescriptor;\nimport androidx.mediarouter.media.MediaRouteDiscoveryRequest;\nimport androidx.mediarouter.media.MediaRouteProvider;\nimport androidx.mediarouter.media.MediaRouteProviderDescriptor;\nimport androidx.mediarouter.media.MediaRouter;\n\nimport com.google.android.gms.common.images.WebImage;\nimport com.google.android.gms.cast.CastDevice;\nimport com.google.android.gms.cast.CastMediaControlIntent;\n\nimport java.net.InetAddress;\nimport java.net.InetSocketAddress;\nimport java.net.Inet4Address;\nimport java.net.UnknownHostException;\nimport java.io.IOException;\nimport java.io.UnsupportedEncodingException;\nimport java.lang.Thread;\nimport java.lang.Runnable;\nimport java.util.List;\nimport java.util.ArrayList;\nimport java.util.Map;\nimport java.util.HashMap;\n\npublic class CastMediaRouteProvider extends MediaRouteProvider {\n    private static final String TAG = CastMediaRouteProvider.class.getSimpleName();\n\n    private Map<String, CastDevice> castDevices = new HashMap<String, CastDevice>();\n    private Map<String, String> serviceCastIds = new HashMap<String, String>();\n\n    private NsdManager mNsdManager;\n    private NsdManager.DiscoveryListener mDiscoveryListener;\n\n    private List<String> customCategories = new ArrayList<String>();\n\n    private enum State {\n        NOT_DISCOVERING,\n        DISCOVERY_REQUESTED,\n        DISCOVERING,\n        DISCOVERY_STOP_REQUESTED,\n    }\n    private State state = State.NOT_DISCOVERING;\n\n    private static final ArrayList<IntentFilter> BASE_CONTROL_FILTERS = new ArrayList<IntentFilter>();\n    static {\n        IntentFilter filter;\n\n        filter = new IntentFilter();\n        filter.addCategory(CastMediaControlIntent.CATEGORY_CAST);\n        BASE_CONTROL_FILTERS.add(filter);\n\n        filter = new IntentFilter();\n        filter.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);\n        filter.addAction(MediaControlIntent.ACTION_PLAY);\n        filter.addDataScheme(\"http\");\n        filter.addDataScheme(\"https\");\n        String[] types = {\n            \"image/jpeg\",\n            \"image/pjpeg\",\n            \"image/jpg\",\n            \"image/webp\",\n            \"image/png\",\n            \"image/gif\",\n            \"image/bmp\",\n            \"image/vnd.microsoft.icon\",\n            \"image/x-icon\",\n            \"image/x-xbitmap\",\n            \"audio/wav\",\n            \"audio/x-wav\",\n            \"audio/mp3\",\n            \"audio/x-mp3\",\n            \"audio/x-m4a\",\n            \"audio/mpeg\",\n            \"audio/webm\",\n            \"audio/ogg\",\n            \"audio/x-matroska\",\n            \"video/mp4\",\n            \"video/x-m4v\",\n            \"video/mp2t\",\n            \"video/webm\",\n            \"video/ogg\",\n            \"video/x-matroska\",\n            \"application/x-mpegurl\",\n            \"application/vnd.apple.mpegurl\",\n            \"application/dash+xml\",\n            \"application/vnd.ms-sstr+xml\",\n        };\n        for (String type : types) {\n            try {\n                filter.addDataType(type);\n            } catch (IntentFilter.MalformedMimeTypeException ex) {\n                Log.e(TAG, \"Error adding filter type \" + type);\n            }\n        }\n        BASE_CONTROL_FILTERS.add(filter);\n\n        filter = new IntentFilter();\n        filter.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);\n        filter.addAction(MediaControlIntent.ACTION_PAUSE);\n        BASE_CONTROL_FILTERS.add(filter);\n\n        filter = new IntentFilter();\n        filter.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);\n        filter.addAction(MediaControlIntent.ACTION_RESUME);\n        BASE_CONTROL_FILTERS.add(filter);\n\n        filter = new IntentFilter();\n        filter.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);\n        filter.addAction(MediaControlIntent.ACTION_STOP);\n        BASE_CONTROL_FILTERS.add(filter);\n\n        filter = new IntentFilter();\n        filter.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);\n        filter.addAction(MediaControlIntent.ACTION_SEEK);\n        BASE_CONTROL_FILTERS.add(filter);\n\n        filter = new IntentFilter();\n        filter.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);\n        filter.addAction(MediaControlIntent.ACTION_GET_STATUS);\n        BASE_CONTROL_FILTERS.add(filter);\n\n        filter = new IntentFilter();\n        filter.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);\n        filter.addAction(MediaControlIntent.ACTION_START_SESSION);\n        BASE_CONTROL_FILTERS.add(filter);\n\n        filter = new IntentFilter();\n        filter.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);\n        filter.addAction(MediaControlIntent.ACTION_GET_SESSION_STATUS);\n        BASE_CONTROL_FILTERS.add(filter);\n\n        filter = new IntentFilter();\n        filter.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);\n        filter.addAction(MediaControlIntent.ACTION_END_SESSION);\n        BASE_CONTROL_FILTERS.add(filter);\n\n        filter = new IntentFilter();\n        filter.addCategory(CastMediaControlIntent.CATEGORY_CAST_REMOTE_PLAYBACK);\n        filter.addAction(CastMediaControlIntent.ACTION_SYNC_STATUS);\n        BASE_CONTROL_FILTERS.add(filter);\n\n        filter = new IntentFilter();\n        filter.addCategory(CastMediaControlIntent.CATEGORY_CAST_REMOTE_PLAYBACK);\n        filter.addAction(CastMediaControlIntent.ACTION_SYNC_STATUS);\n        BASE_CONTROL_FILTERS.add(filter);\n    }\n\n    @SuppressLint(\"NewApi\")\n    public CastMediaRouteProvider(Context context) {\n        super(context);\n\n        if (android.os.Build.VERSION.SDK_INT < 16) {\n            Log.i(TAG, \"Cast discovery disabled. Android SDK version 16 or higher required.\");\n            return;\n        }\n\n        mNsdManager = (NsdManager)context.getApplicationContext().getSystemService(Context.NSD_SERVICE);\n\n        mDiscoveryListener = new NsdManager.DiscoveryListener() {\n\n            @Override\n            public void onDiscoveryStarted(String regType) {\n                CastMediaRouteProvider.this.state = State.DISCOVERING;\n            }\n\n            @Override\n            public void onServiceFound(NsdServiceInfo service) {\n                mNsdManager.resolveService(service, new NsdManager.ResolveListener() {\n                    @Override\n                    public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {\n                        if (errorCode == NsdManager.FAILURE_ALREADY_ACTIVE) {\n                            return;\n                        }\n                        Log.e(TAG, \"DiscoveryListener Resolve failed. Error code \" + errorCode);\n                    }\n\n                    @Override\n                    public void onServiceResolved(NsdServiceInfo serviceInfo) {\n                        String name = serviceInfo.getServiceName();\n                        InetAddress host = serviceInfo.getHost();\n                        int port = serviceInfo.getPort();\n                        Map<String, byte[]> attributes = serviceInfo.getAttributes();\n                        if (attributes == null) {\n                            Log.e(TAG, \"Error getting service attributes from DNS-SD response\");\n                            return;\n                        }\n                        try {\n                            String id = new String(attributes.get(\"id\"), \"UTF-8\");\n                            String deviceVersion = new String(attributes.get(\"ve\"), \"UTF-8\");\n                            String friendlyName = new String(attributes.get(\"fn\"), \"UTF-8\");\n                            String modelName = new String(attributes.get(\"md\"), \"UTF-8\");\n                            String iconPath = new String(attributes.get(\"ic\"), \"UTF-8\");\n                            int status = Integer.parseInt(new String(attributes.get(\"st\"), \"UTF-8\"));\n\n                            onChromeCastDiscovered(id, name, host, port, deviceVersion, friendlyName, modelName, iconPath, status);\n                        } catch (UnsupportedEncodingException | NullPointerException ex) {\n                            Log.e(TAG, \"Error getting cast details from DNS-SD response\", ex);\n                            return;\n                        }\n                    }\n                });\n            }\n\n            @Override\n            public void onServiceLost(NsdServiceInfo serviceInfo) {\n                String name = serviceInfo.getServiceName();\n                onChromeCastLost(name);\n            }\n\n            @Override\n            public void onDiscoveryStopped(String serviceType) {\n                CastMediaRouteProvider.this.state = State.NOT_DISCOVERING;\n            }\n\n            @Override\n            public void onStartDiscoveryFailed(String serviceType, int errorCode) {\n                CastMediaRouteProvider.this.state = State.NOT_DISCOVERING;\n            }\n\n            @Override\n            public void onStopDiscoveryFailed(String serviceType, int errorCode) {\n                CastMediaRouteProvider.this.state = State.DISCOVERING;\n            }\n        };\n    }\n\n    private void onChromeCastDiscovered(\n            String id, String name, InetAddress host, int port, String\n            deviceVersion, String friendlyName, String modelName, String\n            iconPath, int status) {\n        if (!this.castDevices.containsKey(id)) {\n            // TODO: Capabilities\n            int capabilities = CastDevice.CAPABILITY_VIDEO_OUT | CastDevice.CAPABILITY_AUDIO_OUT;\n\n            CastDevice castDevice = new CastDevice(id, name, host, port, deviceVersion, friendlyName, modelName, iconPath, status, capabilities);\n            this.castDevices.put(id, castDevice);\n            this.serviceCastIds.put(name, id);\n        }\n\n        publishRoutesInMainThread();\n    }\n\n    private void onChromeCastLost(String name) {\n        String id = this.serviceCastIds.remove(name);\n        if (id != null) {\n            this.castDevices.remove(id);\n        }\n\n        publishRoutesInMainThread();\n    }\n\n    @SuppressLint(\"NewApi\")\n    @Override\n    public void onDiscoveryRequestChanged(MediaRouteDiscoveryRequest request) {\n        if (android.os.Build.VERSION.SDK_INT < 16) {\n            return;\n        }\n\n        if (request != null && request.isValid() && request.isActiveScan()) {\n            if (request.getSelector() != null) {\n                for (String category : request.getSelector().getControlCategories()) {\n                    if (CastMediaControlIntent.isCategoryForCast(category)) {\n                        this.customCategories.add(category);\n                    }\n                }\n            }\n            if (this.state == State.NOT_DISCOVERING) {\n                mNsdManager.discoverServices(\"_googlecast._tcp.\", NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener);\n                this.state = State.DISCOVERY_REQUESTED;\n            }\n        } else {\n            if (this.state == State.DISCOVERING) {\n                mNsdManager.stopServiceDiscovery(mDiscoveryListener);\n                this.state = State.DISCOVERY_STOP_REQUESTED;\n            }\n        }\n    }\n\n    @Override\n    public RouteController onCreateRouteController(String routeId) {\n        CastDevice castDevice = this.castDevices.get(routeId);\n        if (castDevice == null) {\n            return null;\n        }\n        return new CastMediaRouteController(this, routeId, castDevice.getAddress());\n    }\n\n    private void publishRoutesInMainThread() {\n        Handler mainHandler = new Handler(this.getContext().getMainLooper());\n        mainHandler.post(new Runnable() {\n            @Override\n            public void run() {\n                publishRoutes();\n            }\n        });\n    }\n\n    private void publishRoutes() {\n        MediaRouteProviderDescriptor.Builder builder = new MediaRouteProviderDescriptor.Builder();\n        for (CastDevice castDevice : this.castDevices.values()) {\n            ArrayList<IntentFilter> controlFilters = new ArrayList<IntentFilter>(BASE_CONTROL_FILTERS);\n            // Include any app-specific control filters that have been requested.\n            // TODO: Do we need to check with the device?\n            for (String category : this.customCategories) {\n                IntentFilter filter = new IntentFilter();\n                filter.addCategory(category);\n                controlFilters.add(filter);\n            }\n\n            Bundle extras = new Bundle();\n            castDevice.putInBundle(extras);\n            MediaRouteDescriptor route = new MediaRouteDescriptor.Builder(\n                castDevice.getDeviceId(),\n                castDevice.getFriendlyName())\n                .setDescription(castDevice.getModelName())\n                .addControlFilters(controlFilters)\n                .setDeviceType(MediaRouter.RouteInfo.DEVICE_TYPE_TV)\n                .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE)\n                .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_FIXED)\n                .setVolumeMax(20)\n                .setVolume(0)\n                .setEnabled(true)\n                .setExtras(extras)\n                .setConnectionState(MediaRouter.RouteInfo.CONNECTION_STATE_DISCONNECTED)\n                .build();\n            builder.addRoute(route);\n        }\n        this.setDescriptor(builder.build());\n    }\n}\n"
  },
  {
    "path": "play-services-cast/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<manifest />\n"
  },
  {
    "path": "play-services-cast/src/main/aidl/com/google/android/gms/cast/ApplicationMetadata.aidl",
    "content": "package com.google.android.gms.cast;\n\nparcelable ApplicationMetadata;\n"
  },
  {
    "path": "play-services-cast/src/main/aidl/com/google/android/gms/cast/ApplicationStatus.aidl",
    "content": "package com.google.android.gms.cast;\n\nparcelable ApplicationStatus;\n"
  },
  {
    "path": "play-services-cast/src/main/aidl/com/google/android/gms/cast/CastDeviceStatus.aidl",
    "content": "package com.google.android.gms.cast;\n\nparcelable CastDeviceStatus;\n"
  },
  {
    "path": "play-services-cast/src/main/aidl/com/google/android/gms/cast/JoinOptions.aidl",
    "content": "package com.google.android.gms.cast;\n\nparcelable JoinOptions;\n"
  },
  {
    "path": "play-services-cast/src/main/aidl/com/google/android/gms/cast/LaunchOptions.aidl",
    "content": "package com.google.android.gms.cast;\n\nparcelable LaunchOptions;\n"
  },
  {
    "path": "play-services-cast/src/main/aidl/com/google/android/gms/cast/RequestItem.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.cast;\n\nparcelable RequestItem;\n"
  },
  {
    "path": "play-services-cast/src/main/aidl/com/google/android/gms/cast/internal/IBundleCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.cast.internal;\n\ninterface IBundleCallback {\n  oneway void onBundle(in Bundle bundle);\n}\n"
  },
  {
    "path": "play-services-cast/src/main/aidl/com/google/android/gms/cast/internal/ICastDeviceController.aidl",
    "content": "package com.google.android.gms.cast.internal;\n\nimport com.google.android.gms.cast.LaunchOptions;\nimport com.google.android.gms.cast.JoinOptions;\n\ninterface ICastDeviceController {\n  oneway void disconnect() = 0;\n  oneway void stopApplication(String sessionId) = 4;\n  oneway void sendMessage(String namespace, String message, long requestId) = 8;\n  oneway void registerNamespace(String namespace) = 10;\n  oneway void unregisterNamespace(String namespace) = 11;\n  oneway void launchApplication(String applicationId, in LaunchOptions launchOptions) = 12;\n  oneway void joinApplication(String applicationId, String sessionId, in JoinOptions joinOptions) = 13;\n}\n"
  },
  {
    "path": "play-services-cast/src/main/aidl/com/google/android/gms/cast/internal/ICastDeviceControllerListener.aidl",
    "content": "package com.google.android.gms.cast.internal;\n\nimport com.google.android.gms.cast.ApplicationMetadata;\nimport com.google.android.gms.cast.ApplicationStatus;\nimport com.google.android.gms.cast.CastDeviceStatus;\n\ninterface ICastDeviceControllerListener {\n  void onDisconnected(int reason) = 0;\n  void onApplicationConnectionSuccess(in ApplicationMetadata applicationMetadata, String applicationStatus, String sessionId, boolean wasLaunched) = 1;\n  void onApplicationConnectionFailure(int statusCode) = 2;\n  // Deprecated: void onStatusReceived(String string1, double double1, boolean boolean1) = 3;\n  void onTextMessageReceived(String namespace, String message) = 4;\n  void onBinaryMessageReceived(String namespace, in byte[] data) = 5;\n  // void onStatusChanged(int status) = 6; // TODO\n  // void onStatusChanged2(int status) = 7; // TODO\n  void onApplicationDisconnected(int paramInt) = 8;\n  void onSendMessageFailure(String response, long requestId, int statusCode) = 9;\n  void onSendMessageSuccess(String response, long requestId) = 10;\n  void onApplicationStatusChanged(in ApplicationStatus applicationStatus) = 11;\n  void onDeviceStatusChanged(in CastDeviceStatus deviceStatus) = 12;\n}\n"
  },
  {
    "path": "play-services-cast/src/main/aidl/com/google/android/gms/cast/internal/ICastService.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.cast.internal;\n\nimport com.google.android.gms.common.api.internal.IStatusCallback;\nimport com.google.android.gms.cast.internal.IBundleCallback;\nimport com.google.android.gms.cast.RequestItem;\n\ninterface ICastService {\n    oneway void broadcastPrecacheMessageLegacy(IStatusCallback callback, in String[] arg2, String precacheData) = 0;\n    oneway void broadcastPrecacheMessage(IStatusCallback callback, in String[] arg2, String precacheData, in List<RequestItem> requestItems) = 1;\n    oneway void getCxLessStatus(IStatusCallback callback) = 3;\n    oneway void getFeatureFlags(IBundleCallback callback, in String[] flags) = 4;\n    oneway void getCastStatusCodeDictionary(IBundleCallback callback, in String[] dictionaries) = 5;\n}\n"
  },
  {
    "path": "play-services-cast/src/main/java/com/google/android/gms/cast/ApplicationMetadata.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.cast;\n\nimport android.net.Uri;\n\nimport com.google.android.gms.common.images.WebImage;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\nimport java.util.List;\n\n@PublicApi\npublic class ApplicationMetadata extends AutoSafeParcelable {\n\n    @SafeParceled(1)\n    private int versionCode = 1;\n    @SafeParceled(2)\n    public String applicationId;\n    @SafeParceled(3)\n    public String name;\n    @SafeParceled(value = 4, subClass = WebImage.class)\n    public List<WebImage> images;\n    @SafeParceled(value = 5, subClass = String.class)\n    public List<String> namespaces;\n    @SafeParceled(6)\n    public String senderAppIdentifier;\n    @SafeParceled(7)\n    public Uri senderAppLaunchUri;\n\n    public String getApplicationId() {\n        return applicationId;\n    }\n\n    public List<WebImage> getImages() {\n        return images;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public String getSenderAppIdentifier() {\n        return senderAppIdentifier;\n    }\n\n    public boolean isNamespaceSupported(String namespace) {\n        return namespaces.contains(namespace);\n    }\n\n    @Override\n    public String toString() {\n        final StringBuilder sb = new StringBuilder(\"ApplicationMetadata{\");\n        sb.append(\"applicationId='\").append(applicationId).append(\"'\");\n        sb.append(\", name='\").append(name).append(\"'\");\n        sb.append(\", images=\").append(images.toString());\n        if (namespaces != null) {\n            sb.append(\", namespaces=\").append(namespaces.toString());\n        }\n        sb.append(\", senderAppIdentifier='\").append(senderAppIdentifier).append(\"'\");\n        if (senderAppLaunchUri != null) {\n            sb.append(\", senderAppLaunchUri='\").append(senderAppLaunchUri.toString()).append(\"'\");\n        }\n        sb.append('}');\n        return sb.toString();\n    }\n\n    public static final Creator<ApplicationMetadata> CREATOR = new AutoCreator<ApplicationMetadata>(ApplicationMetadata.class);\n}\n"
  },
  {
    "path": "play-services-cast/src/main/java/com/google/android/gms/cast/ApplicationStatus.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.cast;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class ApplicationStatus extends AutoSafeParcelable {\n\n    public ApplicationStatus() {}\n\n    public ApplicationStatus(String applicationStatus) {\n        this.applicationStatus = applicationStatus;\n    }\n\n    @SafeParceled(1)\n    private int versionCode = 1;\n    @SafeParceled(2)\n    private String applicationStatus;\n\n    public static final Creator<ApplicationStatus> CREATOR = new AutoCreator<ApplicationStatus>(ApplicationStatus.class);\n}\n"
  },
  {
    "path": "play-services-cast/src/main/java/com/google/android/gms/cast/Cast.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.cast;\n\nimport android.os.Bundle;\n\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.PendingResult;\nimport com.google.android.gms.common.api.Result;\nimport com.google.android.gms.common.api.Status;\n\nimport org.microg.gms.cast.CastApiClientBuilder;\nimport org.microg.gms.cast.CastApiImpl;\nimport org.microg.gms.common.PublicApi;\n\nimport java.io.IOException;\n\n@PublicApi\npublic final class Cast {\n\n    /**\n     * A constant indicating that the Google Cast device is not the currently active video input.\n     */\n    public static final int ACTIVE_INPUT_STATE_NO = 0;\n\n    /**\n     * A constant indicating that it is not known (and/or not possible to know) whether the Google Cast device is\n     * the currently active video input. Active input state can only be reported when the Google Cast device is\n     * connected to a TV or AVR with CEC support.\n     */\n    public static final int ACTIVE_INPUT_STATE_UNKNOWN = -1;\n\n    /**\n     * A constant indicating that the Google Cast device is the currently active video input.\n     */\n    public static final int ACTIVE_INPUT_STATE_YES = 1;\n\n    /**\n     * A boolean extra for the connection hint bundle passed to\n     * {@link GoogleApiClient.ConnectionCallbacks#onConnected(Bundle)} that indicates that the connection was\n     * re-established, but the receiver application that was in use at the time of the connection loss is no longer\n     * running on the receiver.\n     */\n    public static final String EXTRA_APP_NO_LONGER_RUNNING = \"com.google.android.gms.cast.EXTRA_APP_NO_LONGER_RUNNING\";\n\n    /**\n     * The maximum raw message length (in bytes) that is supported by a Cast channel.\n     */\n    public static final int MAX_MESSAGE_LENGTH = 65536;\n\n    /**\n     * The maximum length (in characters) of a namespace name.\n     */\n    public static final int MAX_NAMESPACE_LENGTH = 128;\n\n    /**\n     * A constant indicating that the Google Cast device is not currently in standby.\n     */\n    public static final int STANDBY_STATE_NO = 0;\n\n    /**\n     * A constant indicating that it is not known (and/or not possible to know) whether the Google Cast device is\n     * currently in standby. Standby state can only be reported when the Google Cast device is connected to a TV or\n     * AVR with CEC support.\n     */\n    public static final int STANDBY_STATE_UNKNOWN = -1;\n\n    /**\n     * A constant indicating that the Google Cast device is currently in standby.\n     */\n    public static final int STANDBY_STATE_YES = 1;\n\n\n    /**\n     * Token to pass to {@link GoogleApiClient.Builder#addApi(Api)} to enable the Cast features.\n     */\n    public static final Api<CastOptions> API = new Api<CastOptions>(new CastApiClientBuilder());\n\n    /**\n     * An implementation of the CastApi interface. The interface is used to interact with a cast device.\n     */\n    public static final Cast.CastApi CastApi = new CastApiImpl();\n\n    private Cast() {\n    }\n\n    public interface ApplicationConnectionResult extends Result {\n        ApplicationMetadata getApplicationMetadata();\n\n        String getApplicationStatus();\n\n        String getSessionId();\n\n        boolean getWasLaunched();\n    }\n\n    public interface CastApi {\n        int getActiveInputState(GoogleApiClient client);\n\n        ApplicationMetadata getApplicationMetadata(GoogleApiClient client);\n\n        String getApplicationStatus(GoogleApiClient client);\n\n        int getStandbyState(GoogleApiClient client);\n\n        double getVolume(GoogleApiClient client);\n\n        boolean isMute(GoogleApiClient client);\n\n        PendingResult<Cast.ApplicationConnectionResult> joinApplication(GoogleApiClient client);\n\n        PendingResult<Cast.ApplicationConnectionResult> joinApplication(GoogleApiClient client, String applicationId, String sessionId);\n\n        PendingResult<Cast.ApplicationConnectionResult> joinApplication(GoogleApiClient client, String applicationId);\n\n        PendingResult<Cast.ApplicationConnectionResult> launchApplication(GoogleApiClient client, String applicationId, LaunchOptions launchOptions);\n\n        PendingResult<Cast.ApplicationConnectionResult> launchApplication(GoogleApiClient client, String applicationId);\n\n        @Deprecated\n        PendingResult<Cast.ApplicationConnectionResult> launchApplication(GoogleApiClient client, String applicationId, boolean relaunchIfRunning);\n\n        PendingResult<Status> leaveApplication(GoogleApiClient client);\n\n        void removeMessageReceivedCallbacks(GoogleApiClient client, String namespace) throws IOException;\n\n        void requestStatus(GoogleApiClient client) throws IOException;\n\n        PendingResult<Status> sendMessage(GoogleApiClient client, String namespace, String message);\n\n        void setMessageReceivedCallbacks(GoogleApiClient client, String namespace, Cast.MessageReceivedCallback callbacks) throws IOException;\n\n        void setMute(GoogleApiClient client, boolean mute) throws IOException;\n\n        void setVolume(GoogleApiClient client, double volume) throws IOException;\n\n        PendingResult<Status> stopApplication(GoogleApiClient client);\n\n        PendingResult<Status> stopApplication(GoogleApiClient client, String sessionId);\n    }\n\n    public static class CastOptions implements Api.ApiOptions.HasOptions {\n        private final CastDevice castDevice;\n        private final Listener castListener;\n        private final boolean verboseLoggingEnabled;\n\n        public CastOptions(CastDevice castDevice, Listener castListener, boolean verboseLoggingEnabled) {\n            this.castDevice = castDevice;\n            this.castListener = castListener;\n            this.verboseLoggingEnabled = verboseLoggingEnabled;\n        }\n\n        @Deprecated\n        public static Builder builder(CastDevice castDevice, Listener castListener) {\n            return new Builder(castDevice, castListener);\n        }\n\n        public static class Builder {\n            private final CastDevice castDevice;\n            private final Listener castListener;\n            private boolean verboseLoggingEnabled;\n\n            public Builder(CastDevice castDevice, Listener castListener) {\n                this.castDevice = castDevice;\n                this.castListener = castListener;\n            }\n\n            public CastOptions build() {\n                return new CastOptions(castDevice, castListener, verboseLoggingEnabled);\n            }\n\n            public Builder setVerboseLoggingEnabled(boolean verboseLoggingEnabled) {\n                this.verboseLoggingEnabled = verboseLoggingEnabled;\n                return this;\n            }\n        }\n    }\n\n    public static class Listener {\n        public void onActiveInputStateChanged(int activeInputState) {\n\n        }\n\n        public void onApplicationDisconnected(int statusCode) {\n\n        }\n\n        public void onApplicationMetadataChanged(ApplicationMetadata applicationMetadata) {\n\n        }\n\n        public void onApplicationStatusChanged() {\n\n        }\n\n        public void onStandbyStateChanged(int standbyState) {\n\n        }\n\n        public void onVolumeChanged() {\n\n        }\n    }\n\n    public interface MessageReceivedCallback {\n        void onMessageReceived(CastDevice castDevice, String namespace, String message);\n    }\n}\n"
  },
  {
    "path": "play-services-cast/src/main/java/com/google/android/gms/cast/CastDevice.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.cast;\n\nimport android.os.Bundle;\nimport android.net.Uri;\nimport android.text.TextUtils;\n\nimport com.google.android.gms.common.images.WebImage;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\nimport java.net.InetAddress;\nimport java.net.Inet4Address;\nimport java.util.ArrayList;\nimport java.util.List;\n\n@PublicApi\npublic class CastDevice extends AutoSafeParcelable {\n    private static final String EXTRA_CAST_DEVICE = \"com.google.android.gms.cast.EXTRA_CAST_DEVICE\";\n\n    public CastDevice () {\n    }\n\n    public CastDevice (\n            String id, String name, InetAddress host, int port, String\n            deviceVersion, String friendlyName, String modelName, String\n            iconPath, int status, int capabilities) {\n        this.deviceId = id;\n        this.address = host.getHostAddress();\n        this.servicePort = port;\n        this.deviceVersion = deviceVersion;\n        this.friendlyName = friendlyName;\n        this.icons = new ArrayList<WebImage>();\n        this.icons.add(new WebImage(Uri.parse(String.format(\"http://%s:8008%s\", this.address, iconPath))));\n        this.modelName = modelName;\n        this.capabilities = capabilities;\n    }\n\n    /**\n     * Video-output device capability.\n     */\n    public static final int CAPABILITY_VIDEO_OUT = 1;\n\n    /**\n     * Video-input device capability.\n     */\n    public static final int CAPABILITY_VIDEO_IN = 2;\n\n    /**\n     * Audio-output device capability.\n     */\n    public static final int CAPABILITY_AUDIO_OUT = 4;\n\n    /**\n     * Audio-input device capability.\n     */\n    public static final int CAPABILITY_AUDIO_IN = 8;\n\n    @SafeParceled(1)\n    private int versionCode = 3;\n\n    @SafeParceled(2)\n    private String deviceId;\n\n    @SafeParceled(3)\n    private String address;\n\n    @SafeParceled(4)\n    private String friendlyName;\n\n    @SafeParceled(5)\n    private String modelName;\n\n    @SafeParceled(6)\n    private String deviceVersion;\n\n    @SafeParceled(7)\n    private int servicePort;\n\n    @SafeParceled(value = 8, subClass = WebImage.class)\n    private ArrayList<WebImage> icons;\n\n    @SafeParceled(9)\n    private int capabilities;\n\n    @SafeParceled(10)\n    private int status;\n\n    @SafeParceled(11)\n    private String unknown; // TODO: Need to figure this one out\n\n    public String getDeviceId() {\n        return deviceId;\n    }\n\n    public String getDeviceVersion() {\n        return deviceVersion;\n    }\n\n    public String getFriendlyName() {\n        return friendlyName;\n    }\n\n    public static CastDevice getFromBundle(Bundle extras) {\n        if (extras == null) {\n            return null;\n        }\n        extras.setClassLoader(CastDevice.class.getClassLoader());\n        return extras.getParcelable(EXTRA_CAST_DEVICE);\n    }\n\n    public WebImage getIcon(int preferredWidth, int preferredHeight) {\n        return null;\n    }\n\n    public List<WebImage> getIcons() {\n        return icons;\n    }\n\n    public String getAddress() {\n        return address;\n    }\n\n    public String getModelName() {\n        return modelName;\n    }\n\n    public int getServicePort() {\n        return servicePort;\n    }\n\n    public boolean hasCapabilities(int[] capabilities) {\n        for (int capability : capabilities) {\n            if (!this.hasCapability(capability)) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    public boolean hasCapability(int capability) {\n        return (capability & capabilities) == capability;\n    }\n\n    public boolean hasIcons() {\n        return !icons.isEmpty();\n    }\n\n    public boolean isOnLocalNetwork() {\n        return false;\n    }\n\n    public boolean isSameDevice(CastDevice castDevice) {\n        return TextUtils.equals(castDevice.deviceId, deviceId);\n    }\n\n    public void putInBundle(Bundle bundle) {\n        bundle.putParcelable(EXTRA_CAST_DEVICE, this);\n    }\n\n    @Override\n    public String toString() {\n        return \"CastDevice{\" +\n                \"deviceId=\" + this.deviceId +\n                \", address=\" + address +\n                \", friendlyName=\" + friendlyName +\n                \", modelName=\" + modelName +\n                \", deviceVersion=\" + deviceVersion +\n                \", servicePort=\" + servicePort +\n                (icons == null ? \"\" : (\", icons=\" + icons.toString())) +\n                \", capabilities=\" + capabilities +\n                \", status=\" + status +\n                \"}\";\n    }\n\n    public static Creator<CastDevice> CREATOR = new AutoCreator<CastDevice>(CastDevice.class);\n}\n"
  },
  {
    "path": "play-services-cast/src/main/java/com/google/android/gms/cast/CastDeviceStatus.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.cast;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class CastDeviceStatus extends AutoSafeParcelable {\n\n    public CastDeviceStatus() {\n    }\n\n    public CastDeviceStatus(double volume, boolean mute, int activeInputState, ApplicationMetadata applicationMetadata, int standbyState) {\n        this.volume = volume;\n        this.mute = mute;\n        this.activeInputState = activeInputState;\n        this.applicationMetadata = applicationMetadata;\n        this.standbyState = standbyState;\n    }\n\n    @SafeParceled(1)\n    private int versionCode = 1;\n    @SafeParceled(2)\n    private double volume;\n    @SafeParceled(3)\n    private boolean mute;\n    @SafeParceled(4)\n    private int activeInputState;\n    @SafeParceled(5)\n    private ApplicationMetadata applicationMetadata;\n    @SafeParceled(6)\n    private int standbyState;\n\n    public static final Creator<CastDeviceStatus> CREATOR = new AutoCreator<CastDeviceStatus>(CastDeviceStatus.class);\n}\n"
  },
  {
    "path": "play-services-cast/src/main/java/com/google/android/gms/cast/CastMediaControlIntent.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.cast;\n\nimport android.text.TextUtils;\n\nimport java.util.Collection;\nimport java.util.Locale;\n\n/**\n * Intent constants for use with the Cast MediaRouteProvider. This class also contains utility methods for creating\n * a control category for discovering Cast media routes that support a specific app and/or set of namespaces, to be\n * used with MediaRouteSelector.\n */\npublic final class CastMediaControlIntent {\n    @Deprecated\n    public static final String CATEGORY_CAST = \"com.google.android.gms.cast.CATEGORY_CAST\";\n    public static final String ACTION_SYNC_STATUS = \"com.google.android.gms.cast.ACTION_SYNC_STATUS\";\n\n    /**\n     * The application ID for the Cast Default Media Receiver.\n     */\n    public static final String DEFAULT_MEDIA_RECEIVER_APPLICATION_ID = \"CC1AD845\";\n\n    /**\n     * An error code indicating that a Cast request has failed.\n     */\n    public static final int ERROR_CODE_REQUEST_FAILED = 1;\n\n    /**\n     * An error code indicating that the request could not be processed because the session could not be started.\n     */\n    public static final int ERROR_CODE_SESSION_START_FAILED = 2;\n\n    /**\n     * An error code indicating that the connection to the Cast device has been lost, but the system is actively\n     * trying to re-establish the connection.\n     */\n    public static final int ERROR_CODE_TEMPORARILY_DISCONNECTED = 3;\n\n    /**\n     * The extra that contains the ID of the application to launch for an\n     * {@link android.support.v7.media.MediaContolIntent#ACTION_START_SESSION} request.\n     * The value is expected to be a String.\n     */\n    public static final String EXTRA_CAST_APPLICATION_ID = \"com.google.android.gms.cast.EXTRA_CAST_APPLICATION_ID\";\n    public static final String EXTRA_CAST_RELAUNCH_APPLICATION = \"com.google.android.gms.cast.EXTRA_CAST_RELAUNCH_APPLICATION\";\n    public static final String EXTRA_CAST_LANGUAGE_CODE = \"com.google.android.gms.cast.EXTRA_CAST_LANGUAGE_CODE\";\n    public static final String EXTRA_CAST_STOP_APPLICATION_WHEN_SESSION_ENDS = \"com.google.android.gms.cast.EXTRA_CAST_STOP_APPLICATION_WHEN_SESSION_ENDS\";\n    public static final String EXTRA_CUSTOM_DATA = \"com.google.android.gms.cast.EXTRA_CUSTOM_DATA\";\n\n    /**\n     * The extra that indicates whether debug logging should be enabled for the Cast session. The value is expected to be a boolean.\n     */\n    public static final String EXTRA_DEBUG_LOGGING_ENABLED = \"com.google.android.gms.cast.EXTRA_DEBUG_LOGGING_ENABLED\";\n\n    /**\n     * n error bundle extra for the error code. The value is an integer, and will be one of the {@code ERROR_CODE_*}\n     * constants declared in this class.\n     */\n    public static final String EXTRA_ERROR_CODE = \"com.google.android.gms.cast.EXTRA_ERROR_CODE\";\n\n    public static final String CATEGORY_CAST_REMOTE_PLAYBACK = \"com.google.android.gms.cast.CATEGORY_CAST_REMOTE_PLAYBACK\";\n\n    private CastMediaControlIntent() {\n    }\n\n    /**\n     * Returns a custom control category for discovering Cast devices that support running the specified app, independent of whether the app is running or not.\n     *\n     * @param applicationId The application ID of the receiver application.\n     */\n    public static String categoryForCast(String applicationId) {\n        return CATEGORY_CAST + \"/\" + applicationId;\n    }\n\n    /**\n     * Returns true if the given category is a custom control category for cast devices, specific to an application ID.\n     *\n     * @param applicationId The application ID of the receiver application.\n     */\n    public static boolean isCategoryForCast(String category) {\n        if (category == null) {\n            return false;\n        }\n        return category.startsWith(CATEGORY_CAST + \"/\");\n    }\n\n    /**\n     * Returns a custom control category for discovering Cast devices meeting both application ID and namespace\n     * restrictions. See {@link #categoryForCast(Collection)} and {@link #categoryForCast(String)} for more details.\n     */\n    public static String categoryForCast(String applicationId, Collection<String> namespaces) {\n        return CATEGORY_CAST + \"\" + applicationId + \"/\" + TextUtils.join(\",\", namespaces);\n    }\n\n    /**\n     * Returns a custom control category for discovering Cast devices currently running an application which supports the specified namespaces. Apps supporting additional namespaces beyond those specified here are still considered supported.\n     */\n    public static String categoryForCast(Collection<String> namespaces) {\n        return CATEGORY_CAST + \"//\" + TextUtils.join(\",\", namespaces);\n    }\n\n    /**\n     * Returns a custom control category for discovering Cast devices which support the default Android remote\n     * playback actions using the specified Cast player. If the Default Media Receiver is desired, use\n     * {@link #DEFAULT_MEDIA_RECEIVER_APPLICATION_ID} as the applicationId.\n     *\n     * @param applicationId The application ID of the receiver application.\n     */\n    public static String categoryForRemotePlayback(String applicationId) {\n        return CATEGORY_CAST_REMOTE_PLAYBACK + \"/\" + applicationId;\n    }\n\n    /**\n     * Returns a custom control category for discovering Cast devices which support the Default Media Receiver.\n     */\n    public static String categoryForRemotePlayback() {\n        return CATEGORY_CAST_REMOTE_PLAYBACK;\n    }\n\n    /**\n     * Returns an RFC-5646 language tag string fo the given locale.\n     */\n    public static String languageTagForLocale(Locale locale) {\n        StringBuilder sb = new StringBuilder(locale.getLanguage());\n        if (!TextUtils.isEmpty(locale.getCountry())) sb.append('-').append(locale.getCountry());\n        if (!TextUtils.isEmpty(locale.getVariant())) sb.append('-').append(locale.getVariant());\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "play-services-cast/src/main/java/com/google/android/gms/cast/CastPresentation.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.cast;\n\nimport android.annotation.TargetApi;\nimport android.app.Presentation;\nimport android.content.Context;\nimport android.view.Display;\n\n@TargetApi(17)\npublic class CastPresentation extends Presentation {\n    public CastPresentation(Context outerContext, Display display) {\n        super(outerContext, display);\n    }\n\n    public CastPresentation(Context outerContext, Display display, int theme) {\n        super(outerContext, display, theme);\n    }\n}\n"
  },
  {
    "path": "play-services-cast/src/main/java/com/google/android/gms/cast/CastRemoteDisplay.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.cast;\n\nimport android.view.Display;\n\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.Result;\nimport com.google.android.gms.common.api.Status;\n\nimport org.microg.gms.cast.CastRemoteDisplayApiClientBuilder;\nimport org.microg.gms.cast.CastRemoteDisplayApiImpl;\nimport org.microg.gms.common.PublicApi;\n\n@PublicApi\npublic final class CastRemoteDisplay {\n    /**\n     * Token to pass to {@link GoogleApiClient.Builder#addApi(Api)} to enable the CastRemoteDisplay features.\n     */\n    public static final Api<CastRemoteDisplayOptions> API = new Api<CastRemoteDisplayOptions>(new CastRemoteDisplayApiClientBuilder());\n\n    /**\n     * An implementation of the CastRemoteDisplayAPI interface. The interface is used to interact with a cast device.\n     */\n    public static final CastRemoteDisplayApi CastApi = new CastRemoteDisplayApiImpl();\n\n    private CastRemoteDisplay() {\n    }\n\n    public static final class CastRemoteDisplayOptions implements Api.ApiOptions.HasOptions {\n        private CastDevice castDevice;\n        private CastRemoteDisplaySessionCallbacks callbacks;\n\n        private CastRemoteDisplayOptions(CastDevice castDevice, CastRemoteDisplaySessionCallbacks callbacks) {\n            this.castDevice = castDevice;\n            this.callbacks = callbacks;\n        }\n\n        public static final class Builder {\n            private CastDevice castDevice;\n            private CastRemoteDisplaySessionCallbacks callbacks;\n\n            public Builder(CastDevice castDevice, CastRemoteDisplaySessionCallbacks callbacks) {\n                this.castDevice = castDevice;\n                this.callbacks = callbacks;\n            }\n\n            public CastRemoteDisplayOptions build() {\n                return new CastRemoteDisplayOptions(castDevice, callbacks);\n            }\n        }\n    }\n\n    public interface CastRemoteDisplaySessionCallbacks {\n        void onRemoteDisplayEnded(Status status);\n    }\n\n    public interface CastRemoteDisplaySessionResult extends Result {\n        Display getPresentationDisplay();\n    }\n}\n"
  },
  {
    "path": "play-services-cast/src/main/java/com/google/android/gms/cast/CastRemoteDisplayApi.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.cast;\n\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.PendingResult;\n\npublic interface CastRemoteDisplayApi {\n    PendingResult<CastRemoteDisplay.CastRemoteDisplaySessionResult> startRemoteDisplay(GoogleApiClient apiClient, String applicationId);\n\n    PendingResult<CastRemoteDisplay.CastRemoteDisplaySessionResult> stopRemoteDisplay(GoogleApiClient apiClient);\n}\n"
  },
  {
    "path": "play-services-cast/src/main/java/com/google/android/gms/cast/CastRemoteDisplayLocalService.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.cast;\n\nimport android.app.Service;\nimport android.content.Intent;\nimport android.os.IBinder;\n\npublic class CastRemoteDisplayLocalService extends Service {\n    @Override\n    public IBinder onBind(Intent intent) {\n        return null;\n    }\n}\n"
  },
  {
    "path": "play-services-cast/src/main/java/com/google/android/gms/cast/CastStatusCodes.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.cast;\n\npublic final class CastStatusCodes {\n    public static final int APPLICATION_NOT_FOUND = 2004;\n    public static final int APPLICATION_NOT_RUNNING = 2005;\n    public static final int AUTHENTICATION_FAILED = 2000;\n    public static final int CANCELED = 2002;\n    public static final int ERROR_SERVICE_CREATION_FAILED = 2200;\n    public static final int ERROR_SERVICE_DISCONNECTED = 2201;\n    public static final int FAILED = 2100;\n    public static final int INTERNAL_ERROR = 8;\n    public static final int INTERRUPTED = 14;\n    public static final int INVALID_REQUEST = 2001;\n    public static final int MESSAGE_SEND_BUFFER_TOO_FULL = 2007;\n    public static final int MESSAGE_TOO_LARGE = 2006;\n    public static final int NETWORK_ERROR = 7;\n    public static final int NOT_ALLOWED = 2003;\n    public static final int REPLACED = 2103;\n    public static final int SUCCESS = 0;\n    public static final int TIMEOUT = 15;\n    public static final int UNKNOWN_ERROR = 13;\n}\n"
  },
  {
    "path": "play-services-cast/src/main/java/com/google/android/gms/cast/CredentialsData.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.cast;\n\nimport android.os.Parcel;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n/**\n * Credentials data used to identify the credentials of the sender.\n */\n@SafeParcelable.Class\npublic class CredentialsData extends AbstractSafeParcelable {\n    /**\n     * The credentials type indicating it comes from an Android sender.\n     */\n    public static final String CREDENTIALS_TYPE_ANDROID = \"android\";\n    /**\n     * The credentials type indicating it comes from the cloud (i.e. assistant).\n     */\n    public static final String CREDENTIALS_TYPE_CLOUD = \"cloud\";\n    /**\n     * The credentials type indicating it comes from an iOS sender.\n     */\n    public static final String CREDENTIALS_TYPE_IOS = \"ios\";\n    /**\n     * The credentials type indicating it comes from a Web sender.\n     */\n    public static final String CREDENTIALS_TYPE_WEB = \"web\";\n\n    @Field(1)\n    final String credentials;\n    @Field(2)\n    final String credentialsType;\n\n    @Constructor\n    CredentialsData(@Param(1) String credentials, @Param(2) String credentialsType) {\n        this.credentials = credentials;\n        this.credentialsType = credentialsType;\n    }\n\n    /**\n     * Returns the application-specific blob which identifies and possibly authenticates the user that's requesting to launch\n     * or join an receiver app. This field may be {@code null}.\n     * <p>\n     * For requests sent from Assistant, it is an OAuth 2 token.\n     * <p>\n     * For requests sent from mobile senders, it is set by sender apps.\n     */\n    public String getCredentials() {\n        return credentials;\n    }\n\n    /**\n     * Returns the type of the credentials. This field may be {@code null}.\n     * <p>\n     * This could be one of the {@code CREDENTIALS_TYPE_*} constants or custom-defined.\n     */\n    public String getCredentialsType() {\n        return credentialsType;\n    }\n\n    @Override\n    public void writeToParcel(Parcel out, int flags) {\n        CREATOR.writeToParcel(this, out, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<CredentialsData> CREATOR = findCreator(CredentialsData.class);\n}\n"
  },
  {
    "path": "play-services-cast/src/main/java/com/google/android/gms/cast/JoinOptions.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.cast;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class JoinOptions extends AutoSafeParcelable {\n    @SafeParceled(1)\n    private int versionCode = 1;\n    @SafeParceled(2)\n    private int connectionType = 0;\n\n    public static Creator<JoinOptions> CREATOR = new AutoCreator<JoinOptions>(JoinOptions.class);\n}\n"
  },
  {
    "path": "play-services-cast/src/main/java/com/google/android/gms/cast/LaunchOptions.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2015 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.cast;\n\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport org.microg.gms.utils.ToStringHelper;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\nimport java.util.Locale;\n\n/**\n * An object that holds options that affect how a receiver application is launched. See\n * {@link Cast.CastApi#launchApplication(GoogleApiClient, String, LaunchOptions)}.\n */\npublic class LaunchOptions extends AutoSafeParcelable {\n    @Field(1)\n    private int versionCode = 1;\n    @Field(2)\n    private boolean relaunchIfRunning = false;\n    @Field(3)\n    private String language;\n    @Field(4)\n    private boolean androidReceiverCompatible = false;\n    @Field(5)\n    private CredentialsData credentialsData = null;\n\n    /**\n     * The constructor of {@link LaunchOptions}.\n     */\n    public LaunchOptions() {\n        Locale locale = Locale.getDefault();\n        StringBuilder sb = new StringBuilder(locale.getLanguage());\n        if (!locale.getCountry().isEmpty()) {\n            sb.append(\"-\").append(locale.getCountry());\n        }\n        if (!locale.getVariant().isEmpty()) {\n            sb.append(\"-\").append(locale.getVariant());\n        }\n        language = sb.toString();\n    }\n\n    /**\n     * Returns {@code true} if the sender app supports casting to an Android TV app.\n     */\n    public boolean getAndroidReceiverCompatible() {\n        return androidReceiverCompatible;\n    }\n\n    /**\n     * Returns the {@link CredentialsData}.\n     */\n    public CredentialsData getCredentialsData() {\n        return credentialsData;\n    }\n\n    /**\n     * Returns the language, or {@code null} if none was specified.\n     */\n    public String getLanguage() {\n        return language;\n    }\n\n    /**\n     * Returns the \"relaunch if running\" flag.\n     */\n    public boolean getRelaunchIfRunning() {\n        return relaunchIfRunning;\n    }\n\n    /**\n     * Sets the language to be used by the receiver application. If not specified, the sender device's default language is used.\n     *\n     * @param language The language\n     */\n    public void setLanguage(String language) {\n        this.language = language;\n    }\n\n    /**\n     * Sets the \"relaunch if running\" flag. If the flag is set, the receiver application will be relaunched even if it is already running. The flag is not set by default.\n     */\n    public void setRelaunchIfRunning(boolean relaunchIfRunning) {\n        this.relaunchIfRunning = relaunchIfRunning;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"LaunchOptions\")\n                .field(\"relaunchIfRunning\", relaunchIfRunning)\n                .field(\"language\", language)\n                .field(\"androidReceiverCompatible\", androidReceiverCompatible)\n                .end();\n    }\n\n    public static Creator<LaunchOptions> CREATOR = new AutoCreator<LaunchOptions>(LaunchOptions.class);\n}\n"
  },
  {
    "path": "play-services-cast/src/main/java/com/google/android/gms/cast/RequestItem.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.cast;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class RequestItem extends AutoSafeParcelable {\n    @Field(2)\n    public String url;\n    @Field(3)\n    public int protocolType;\n    @Field(4)\n    public int initialTime;\n    @Field(5)\n    public String hlsSegmentFormat;\n\n    public static Creator<RequestItem> CREATOR = new AutoCreator<RequestItem>(RequestItem.class);\n}\n"
  },
  {
    "path": "play-services-cast/src/main/java/com/google/android/gms/cast/package-info.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n/**\n * Contains classes for interacting with Google Cast devices.\n */\npackage com.google.android.gms.cast;\n"
  },
  {
    "path": "play-services-cast/src/main/java/org/microg/gms/cast/CastApiClientBuilder.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.cast;\n\nimport android.content.Context;\nimport android.os.Looper;\n\nimport com.google.android.gms.cast.Cast;\n\nimport com.google.android.gms.common.api.Api;\nimport org.microg.gms.common.api.ApiClientBuilder;\nimport com.google.android.gms.common.internal.ClientSettings;\nimport com.google.android.gms.common.api.internal.ConnectionCallbacks;\nimport com.google.android.gms.common.api.internal.OnConnectionFailedListener;\n\npublic class CastApiClientBuilder implements ApiClientBuilder<Cast.CastOptions> {\n    @Override\n    public Api.Client build(Cast.CastOptions options, Context context, Looper looper, ClientSettings clientSettings, ConnectionCallbacks callbacks, OnConnectionFailedListener connectionFailedListener) {\n        return new CastClientImpl(context, options, callbacks, connectionFailedListener);\n    }\n}\n"
  },
  {
    "path": "play-services-cast/src/main/java/org/microg/gms/cast/CastApiImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.cast;\n\nimport com.google.android.gms.cast.ApplicationMetadata;\nimport com.google.android.gms.cast.Cast;\nimport com.google.android.gms.cast.LaunchOptions;\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.PendingResult;\nimport com.google.android.gms.common.api.Status;\n\nimport java.io.IOException;\n\n// TODO\npublic class CastApiImpl implements Cast.CastApi {\n    @Override\n    public int getActiveInputState(GoogleApiClient client) {\n        return 0;\n    }\n\n    @Override\n    public ApplicationMetadata getApplicationMetadata(GoogleApiClient client) {\n        return null;\n    }\n\n    @Override\n    public String getApplicationStatus(GoogleApiClient client) {\n        return null;\n    }\n\n    @Override\n    public int getStandbyState(GoogleApiClient client) {\n        return 0;\n    }\n\n    @Override\n    public double getVolume(GoogleApiClient client) {\n        return 0;\n    }\n\n    @Override\n    public boolean isMute(GoogleApiClient client) {\n        return false;\n    }\n\n    @Override\n    public PendingResult<Cast.ApplicationConnectionResult> joinApplication(GoogleApiClient client) {\n        return null;\n    }\n\n    @Override\n    public PendingResult<Cast.ApplicationConnectionResult> joinApplication(GoogleApiClient client, String applicationId, String sessionId) {\n        return null;\n    }\n\n    @Override\n    public PendingResult<Cast.ApplicationConnectionResult> joinApplication(GoogleApiClient client, String applicationId) {\n        return null;\n    }\n\n    @Override\n    public PendingResult<Cast.ApplicationConnectionResult> launchApplication(GoogleApiClient client, String applicationId, LaunchOptions launchOptions) {\n        return null;\n    }\n\n    @Override\n    public PendingResult<Cast.ApplicationConnectionResult> launchApplication(GoogleApiClient client, String applicationId) {\n        return null;\n    }\n\n    @Override\n    public PendingResult<Cast.ApplicationConnectionResult> launchApplication(GoogleApiClient client, String applicationId, boolean relaunchIfRunning) {\n        return null;\n    }\n\n    @Override\n    public PendingResult<Status> leaveApplication(GoogleApiClient client) {\n        return null;\n    }\n\n    @Override\n    public void removeMessageReceivedCallbacks(GoogleApiClient client, String namespace) throws IOException {\n\n    }\n\n    @Override\n    public void requestStatus(GoogleApiClient client) throws IOException {\n\n    }\n\n    @Override\n    public PendingResult<Status> sendMessage(GoogleApiClient client, String namespace, String message) {\n        return null;\n    }\n\n    @Override\n    public void setMessageReceivedCallbacks(GoogleApiClient client, String namespace, Cast.MessageReceivedCallback callbacks) throws IOException {\n\n    }\n\n    @Override\n    public void setMute(GoogleApiClient client, boolean mute) throws IOException {\n\n    }\n\n    @Override\n    public void setVolume(GoogleApiClient client, double volume) throws IOException {\n\n    }\n\n    @Override\n    public PendingResult<Status> stopApplication(GoogleApiClient client) {\n        return null;\n    }\n\n    @Override\n    public PendingResult<Status> stopApplication(GoogleApiClient client, String sessionId) {\n        return null;\n    }\n}\n"
  },
  {
    "path": "play-services-cast/src/main/java/org/microg/gms/cast/CastClientImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.cast;\n\nimport android.content.Context;\n\nimport com.google.android.gms.cast.Cast;\n\nimport org.microg.gms.common.DummyApiClient;\nimport com.google.android.gms.common.api.internal.ConnectionCallbacks;\nimport com.google.android.gms.common.api.internal.OnConnectionFailedListener;\n\npublic class CastClientImpl extends DummyApiClient {\n    public CastClientImpl(Context context, Cast.CastOptions options, ConnectionCallbacks callbacks, OnConnectionFailedListener connectionFailedListener) {\n    }\n}\n"
  },
  {
    "path": "play-services-cast/src/main/java/org/microg/gms/cast/CastRemoteDisplayApiClientBuilder.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.cast;\n\nimport android.content.Context;\nimport android.os.Looper;\n\nimport com.google.android.gms.cast.CastRemoteDisplay;\n\nimport com.google.android.gms.common.api.Api;\nimport org.microg.gms.common.DummyApiClient;\nimport org.microg.gms.common.api.ApiClientBuilder;\nimport com.google.android.gms.common.internal.ClientSettings;\nimport com.google.android.gms.common.api.internal.ConnectionCallbacks;\nimport com.google.android.gms.common.api.internal.OnConnectionFailedListener;\n\npublic class CastRemoteDisplayApiClientBuilder implements ApiClientBuilder<CastRemoteDisplay.CastRemoteDisplayOptions> {\n    @Override\n    public Api.Client build(CastRemoteDisplay.CastRemoteDisplayOptions options, Context context, Looper looper, ClientSettings clientSettings, ConnectionCallbacks callbacks, OnConnectionFailedListener connectionFailedListener) {\n        return new DummyApiClient();\n    }\n}\n"
  },
  {
    "path": "play-services-cast/src/main/java/org/microg/gms/cast/CastRemoteDisplayApiImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.cast;\n\nimport com.google.android.gms.cast.CastRemoteDisplay;\nimport com.google.android.gms.cast.CastRemoteDisplayApi;\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.PendingResult;\n\npublic class CastRemoteDisplayApiImpl implements CastRemoteDisplayApi {\n    @Override\n    public PendingResult<CastRemoteDisplay.CastRemoteDisplaySessionResult> startRemoteDisplay(GoogleApiClient apiClient, String applicationId) {\n        return null;\n    }\n\n    @Override\n    public PendingResult<CastRemoteDisplay.CastRemoteDisplaySessionResult> stopRemoteDisplay(GoogleApiClient apiClient) {\n        return null;\n    }\n}\n"
  },
  {
    "path": "play-services-cast-framework/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\nandroid {\n    namespace \"com.google.android.gms.cast.framework\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n}\n\napply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG implementation of play-services-cast-framework'\n\ndependencies {\n    // Dependencies from play-services-cast-framework:21.2.0\n    api 'androidx.appcompat:appcompat:1.0.0'\n    api 'androidx.collection:collection:1.0.0'\n    api 'androidx.concurrent:concurrent-futures:1.1.0'\n    api 'androidx.core:core:1.0.0'\n    api 'androidx.fragment:fragment:1.0.0'\n    api 'androidx.media:media:1.6.0'\n    api 'androidx.mediarouter:mediarouter:1.3.0'\n    api 'androidx.recyclerview:recyclerview:1.0.0'\n    // com.google.android.datatransport:transport-api:3.0.0\n    // com.google.android.datatransport:transport-backend-cct:3.1.3\n    // com.google.android.datatransport:transport-runtime:3.1.3\n    api project(':play-services-base')\n    api project(':play-services-basement')\n    api project(':play-services-cast')\n    api project(':play-services-tasks')\n    api 'com.google.guava:listenablefuture:1.0'\n}\n"
  },
  {
    "path": "play-services-cast-framework/core/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'kotlin-android'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\ndependencies {\n    implementation project(':play-services-cast-framework')\n    implementation project(':play-services-base-core')\n\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion\"\n    implementation \"org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutineVersion\"\n    implementation \"org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutineVersion\"\n}\n\nandroid {\n    namespace \"org.microg.gms.cast.framework.core\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    buildFeatures {\n        dataBinding = true\n    }\n\n    sourceSets {\n        main.java.srcDirs += 'src/main/kotlin'\n    }\n\n    lintOptions {\n        disable 'MissingTranslation'\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n\n    kotlinOptions {\n        jvmTarget = 1.8\n    }\n}\n\napply from: '../../gradle/publish-android.gradle'\n\ndescription = 'microG service implementation for play-services-cast-framework'\n"
  },
  {
    "path": "play-services-cast-framework/core/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <application>\n    </application>\n</manifest>\n"
  },
  {
    "path": "play-services-cast-framework/core/src/main/java/com/google/android/gms/cast/framework/internal/CastContextImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.cast.framework.internal;\n\nimport android.content.Context;\nimport android.os.Bundle;\nimport android.os.IBinder;\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport androidx.mediarouter.media.MediaControlIntent;\nimport androidx.mediarouter.media.MediaRouteSelector;\n\nimport com.google.android.gms.cast.CastMediaControlIntent;\nimport com.google.android.gms.cast.framework.CastOptions;\nimport com.google.android.gms.cast.framework.IAppVisibilityListener;\nimport com.google.android.gms.cast.framework.ICastContext;\nimport com.google.android.gms.cast.framework.IDiscoveryManager;\nimport com.google.android.gms.cast.framework.ISessionManager;\nimport com.google.android.gms.cast.framework.ISessionProvider;\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.dynamic.ObjectWrapper;\n\nimport java.util.Map;\nimport java.util.HashMap;\n\npublic class CastContextImpl extends ICastContext.Stub {\n    private static final String TAG = CastContextImpl.class.getSimpleName();\n\n    private SessionManagerImpl sessionManager;\n    private DiscoveryManagerImpl discoveryManager;\n\n    private Context context;\n    private CastOptions options;\n    private IMediaRouter router;\n    private Map<String, ISessionProvider> sessionProviders = new HashMap<String, ISessionProvider>();\n    public ISessionProvider defaultSessionProvider;\n\n    private MediaRouteSelector mergedSelector;\n\n    public CastContextImpl(IObjectWrapper context, CastOptions options, IMediaRouter router, Map<String, IBinder> sessionProviders) throws RemoteException {\n        this.context = (Context) ObjectWrapper.unwrap(context);\n        this.options = options;\n        this.router = router;\n        for (Map.Entry<String, IBinder> entry : sessionProviders.entrySet()) {\n            this.sessionProviders.put(entry.getKey(), ISessionProvider.Stub.asInterface(entry.getValue()));\n        }\n\n        String receiverApplicationId = options.getReceiverApplicationId();\n        String defaultCategory = CastMediaControlIntent.categoryForCast(receiverApplicationId);\n\n        this.defaultSessionProvider = this.sessionProviders.get(defaultCategory);\n\n        // TODO: This should incorporate passed options\n        this.mergedSelector = new MediaRouteSelector.Builder()\n            .addControlCategory(MediaControlIntent.CATEGORY_LIVE_VIDEO)\n            .addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)\n            .addControlCategory(defaultCategory)\n            .build();\n    }\n\n    @Override\n    public Bundle getMergedSelectorAsBundle() throws RemoteException {\n        return this.mergedSelector.asBundle();\n    }\n\n    @Override\n    public void addVisibilityChangeListener(IAppVisibilityListener listener) {\n        Log.d(TAG, \"unimplemented Method: addVisibilityChangeListener\");\n    }\n\n    @Override\n    public void removeVisibilityChangeListener(IAppVisibilityListener listener) {\n        Log.d(TAG, \"unimplemented Method: removeVisibilityChangeListener\");\n    }\n\n    @Override\n    public boolean isApplicationVisible() throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: isApplicationVisible\");\n        return true;\n    }\n\n    @Override\n    public SessionManagerImpl getSessionManagerImpl() {\n        if (this.sessionManager == null) {\n            this.sessionManager = new SessionManagerImpl(this);\n        }\n        return this.sessionManager;\n    }\n\n    @Override\n    public IDiscoveryManager getDiscoveryManagerImpl() throws RemoteException {\n        if (this.discoveryManager == null) {\n            this.discoveryManager = new DiscoveryManagerImpl(this);\n        }\n        return this.discoveryManager;\n    }\n\n    @Override\n    public void destroy() throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: destroy\");\n    }\n\n    @Override\n    public void onActivityResumed(IObjectWrapper activity) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: onActivityResumed\");\n\n    }\n\n    @Override\n    public void onActivityPaused(IObjectWrapper activity) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: onActivityPaused\");\n    }\n\n    @Override\n    public void setReceiverApplicationId(String receiverApplicationId, Map sessionProvidersByCategory) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: setReceiverApplicationId\");\n    }\n\n    public Context getContext() {\n        return this.context;\n    }\n\n    public IMediaRouter getRouter() {\n        return this.router;\n    }\n\n    public MediaRouteSelector getMergedSelector() {\n        return this.mergedSelector;\n    }\n\n    public CastOptions getOptions() {\n        return this.options;\n    }\n\n    @Override\n    public IObjectWrapper getWrappedThis() throws RemoteException {\n        return ObjectWrapper.wrap(this);\n    }\n}\n"
  },
  {
    "path": "play-services-cast-framework/core/src/main/java/com/google/android/gms/cast/framework/internal/CastDynamiteModuleImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.cast.framework.internal;\n\nimport android.content.Context;\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport com.google.android.gms.cast.framework.CastOptions;\nimport com.google.android.gms.cast.framework.ICastConnectionController;\nimport com.google.android.gms.cast.framework.ICastContext;\nimport com.google.android.gms.cast.framework.ICastSession;\nimport com.google.android.gms.cast.framework.IReconnectionService;\nimport com.google.android.gms.cast.framework.ISession;\nimport com.google.android.gms.cast.framework.ISessionProxy;\nimport com.google.android.gms.cast.framework.media.CastMediaOptions;\nimport com.google.android.gms.cast.framework.internal.CastContextImpl;\nimport com.google.android.gms.cast.framework.internal.CastSessionImpl;\nimport com.google.android.gms.cast.framework.internal.MediaRouterCallbackImpl;\nimport com.google.android.gms.cast.framework.internal.SessionImpl;\nimport com.google.android.gms.cast.framework.media.IMediaNotificationService;\nimport com.google.android.gms.cast.framework.media.internal.IFetchBitmapTask;\nimport com.google.android.gms.cast.framework.media.internal.IFetchBitmapTaskProgressPublisher;\nimport com.google.android.gms.dynamic.IObjectWrapper;\n\nimport java.util.Map;\n\npublic class CastDynamiteModuleImpl extends ICastDynamiteModule.Stub {\n    private static final String TAG = CastDynamiteModuleImpl.class.getSimpleName();\n\n    @Override\n    public ICastContext newCastContextImpl(IObjectWrapper context, CastOptions options, IMediaRouter router, Map sessionProviders) throws RemoteException {\n        return new CastContextImpl(context, options, router, sessionProviders);\n    }\n\n    @Override\n    public ISession newSessionImpl(String category, String sessionId, ISessionProxy proxy) throws RemoteException {\n        return new SessionImpl(category, sessionId, proxy);\n    }\n\n    @Override\n    public ICastSession newCastSessionImpl(CastOptions options, IObjectWrapper session, ICastConnectionController controller) throws RemoteException {\n        return new CastSessionImpl(options, session, controller);\n    }\n\n    @Override\n    public IMediaNotificationService newMediaNotificationServiceImpl(IObjectWrapper service, IObjectWrapper castContext, IObjectWrapper resources, CastMediaOptions options) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: newMediaNotificationServiceImpl\");\n        return null;\n    }\n\n    @Override\n    public IReconnectionService newReconnectionServiceImpl(IObjectWrapper service, IObjectWrapper sessionManager, IObjectWrapper discoveryManager) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: newReconnectionServiceImpl\");\n        return null;\n    }\n\n    @Override\n    public IFetchBitmapTask newFetchBitmapTaskImpl(IObjectWrapper asyncTask, IFetchBitmapTaskProgressPublisher progressPublisher, int i1, int i2, boolean b1, long l1, int i3, int i4, int i5) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: newFetchBitmapTaskImpl\");\n        return null;\n    }\n}\n"
  },
  {
    "path": "play-services-cast-framework/core/src/main/java/com/google/android/gms/cast/framework/internal/CastSessionImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.cast.framework.internal;\n\nimport com.google.android.gms.cast.framework.ICastSession;\n\nimport android.os.Bundle;\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport com.google.android.gms.cast.ApplicationMetadata;\nimport com.google.android.gms.cast.framework.CastOptions;\nimport com.google.android.gms.cast.framework.ICastConnectionController;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.dynamic.ObjectWrapper;\n\npublic class CastSessionImpl extends ICastSession.Stub {\n    private static final String TAG = CastSessionImpl.class.getSimpleName();\n    private CastOptions options;\n    private SessionImpl session;\n    private ICastConnectionController controller;\n\n    public CastSessionImpl(CastOptions options, IObjectWrapper session, ICastConnectionController controller) throws RemoteException {\n        this.options = options;\n        this.session = (SessionImpl) ObjectWrapper.unwrap(session);\n        this.controller = controller;\n\n        this.session.setCastSession(this);\n    }\n\n    public void launchApplication() throws RemoteException {\n        this.controller.launchApplication(this.options.getReceiverApplicationId(), this.options.getLaunchOptions());\n    }\n\n    @Override\n    public void onConnected(Bundle routeInfoExtra) throws RemoteException {\n        this.controller.launchApplication(this.options.getReceiverApplicationId(), this.options.getLaunchOptions());\n    }\n\n    @Override\n    public void onConnectionSuspended(int reason) {\n        Log.d(TAG, \"unimplemented Method: onConnectionSuspended\");\n    }\n\n    @Override\n    public void onConnectionFailed(Status status) {\n        Log.d(TAG, \"unimplemented Method: onConnectionFailed\");\n    }\n\n    @Override\n    public void onApplicationConnectionSuccess(ApplicationMetadata applicationMetadata, String applicationStatus, String sessionId, boolean wasLaunched) {\n        this.session.onApplicationConnectionSuccess(applicationMetadata, applicationStatus, sessionId, wasLaunched);\n    }\n\n    @Override\n    public void onApplicationConnectionFailure(int statusCode) {\n        this.session.onApplicationConnectionFailure(statusCode);\n    }\n\n    @Override\n    public void disconnectFromDevice(boolean boolean1, int int1) {\n        Log.d(TAG, \"unimplemented Method: disconnectFromDevice\");\n    }\n}\n"
  },
  {
    "path": "play-services-cast-framework/core/src/main/java/com/google/android/gms/cast/framework/internal/DiscoveryManagerImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.cast.framework.internal;\n\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport com.google.android.gms.cast.framework.IDiscoveryManager;\nimport com.google.android.gms.cast.framework.IDiscoveryManagerListener;\nimport com.google.android.gms.cast.framework.internal.CastContextImpl;\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.dynamic.ObjectWrapper;\n\nimport java.util.Set;\nimport java.util.HashSet;\n\npublic class DiscoveryManagerImpl extends IDiscoveryManager.Stub {\n    private static final String TAG = DiscoveryManagerImpl.class.getSimpleName();\n\n    private CastContextImpl castContextImpl;\n\n    private Set discoveryManagerListeners = new HashSet();\n\n    public DiscoveryManagerImpl(CastContextImpl castContextImpl) {\n        this.castContextImpl = castContextImpl;\n    }\n\n    @Override\n    public void startDiscovery() {\n        Log.d(TAG, \"unimplemented Method: startDiscovery\");\n    }\n\n    @Override\n    public void stopDiscovery() {\n        Log.d(TAG, \"unimplemented Method: stopDiscovery\");\n    }\n\n    @Override\n    public void addDiscoveryManagerListener(IDiscoveryManagerListener listener) {\n        Log.d(TAG, \"unimplemented Method: addDiscoveryManagerListener\");\n        this.discoveryManagerListeners.add(listener);\n    }\n\n    @Override\n    public void removeDiscoveryManagerListener(IDiscoveryManagerListener listener) {\n        Log.d(TAG, \"unimplemented Method: removeDiscoveryManagerListener\");\n        this.discoveryManagerListeners.remove(listener);\n    }\n\n    @Override\n    public IObjectWrapper getWrappedThis() throws RemoteException {\n        return ObjectWrapper.wrap(this);\n    }\n}\n"
  },
  {
    "path": "play-services-cast-framework/core/src/main/java/com/google/android/gms/cast/framework/internal/MediaRouterCallbackImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.cast.framework.internal;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport com.google.android.gms.cast.CastDevice;\nimport com.google.android.gms.cast.framework.ISession;\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.dynamic.ObjectWrapper;\n\npublic class MediaRouterCallbackImpl extends IMediaRouterCallback.Stub {\n    private static final String TAG = MediaRouterCallbackImpl.class.getSimpleName();\n\n    private CastContextImpl castContext;\n\n    public MediaRouterCallbackImpl(CastContextImpl castContext) {\n        this.castContext = castContext;\n    }\n\n    @Override\n    public void onRouteAdded(String routeId, Bundle extras) {\n        Log.d(TAG, \"unimplemented Method: onRouteAdded\");\n    }\n    @Override\n    public void onRouteChanged(String routeId, Bundle extras) {\n        Log.d(TAG, \"unimplemented Method: onRouteChanged\");\n    }\n    @Override\n    public void onRouteRemoved(String routeId, Bundle extras) {\n        Log.d(TAG, \"unimplemented Method: onRouteRemoved\");\n    }\n    @Override\n    public void onRouteSelected(String routeId, Bundle extras) throws RemoteException {\n        CastDevice castDevice = CastDevice.getFromBundle(extras);\n\n        SessionImpl session = (SessionImpl) ObjectWrapper.unwrap(this.castContext.defaultSessionProvider.getSession(null));\n        Bundle routeInfoExtras = this.castContext.getRouter().getRouteInfoExtrasById(routeId);\n        if (routeInfoExtras != null) {\n            session.start(this.castContext, castDevice, routeId, routeInfoExtras);\n        }\n    }\n    @Override\n    public void unknown(String routeId, Bundle extras) {\n        Log.d(TAG, \"unimplemented Method: unknown\");\n    }\n    @Override\n    public void onRouteUnselected(String routeId, Bundle extras, int reason) {\n        Log.d(TAG, \"unimplemented Method: onRouteUnselected\");\n    }\n}\n"
  },
  {
    "path": "play-services-cast-framework/core/src/main/java/com/google/android/gms/cast/framework/internal/SessionImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.cast.framework.internal;\n\nimport android.os.Bundle;\nimport android.os.RemoteException;\nimport android.util.Log;\n\n\nimport com.google.android.gms.cast.ApplicationMetadata;\nimport com.google.android.gms.cast.CastDevice;\nimport com.google.android.gms.cast.framework.ISession;\nimport com.google.android.gms.cast.framework.ISessionProxy;\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.dynamic.ObjectWrapper;\n\npublic class SessionImpl extends ISession.Stub {\n    private static final String TAG = SessionImpl.class.getSimpleName();\n\n    private String category;\n    private String sessionId;\n    private ISessionProxy proxy;\n\n    private CastSessionImpl castSession;\n\n    private CastContextImpl castContext;\n    private CastDevice castDevice;\n    private Bundle routeInfoExtra;\n\n    private boolean mIsConnecting = false;\n    private boolean mIsConnected = false;\n    private String routeId = null;\n\n    public SessionImpl(String category, String sessionId, ISessionProxy proxy) {\n        this.category = category;\n        this.sessionId = sessionId;\n        this.proxy = proxy;\n    }\n\n    public void start(CastContextImpl castContext, CastDevice castDevice, String routeId, Bundle routeInfoExtra) throws RemoteException {\n        this.castContext = castContext;\n        this.castDevice = castDevice;\n        this.routeInfoExtra = routeInfoExtra;\n        this.routeId = routeId;\n\n        this.mIsConnecting = true;\n        this.mIsConnected = false;\n        this.castContext.getSessionManagerImpl().onSessionStarting(this);\n        this.proxy.start(routeInfoExtra);\n    }\n\n    public void onApplicationConnectionSuccess(ApplicationMetadata applicationMetadata, String applicationStatus, String sessionId, boolean wasLaunched) {\n        this.mIsConnecting = false;\n        this.mIsConnected = true;\n        this.castContext.getSessionManagerImpl().onSessionStarted(this, sessionId);\n        try {\n            this.castContext.getRouter().selectRouteById(this.getRouteId());\n        } catch (RemoteException ex) {\n            Log.e(TAG, \"Error calling selectRouteById: \" + ex.getMessage());\n        }\n    }\n\n    public void onApplicationConnectionFailure(int statusCode) {\n        this.mIsConnecting = false;\n        this.mIsConnected = false;\n        this.routeId = null;\n        this.castContext = null;\n        this.castDevice = null;\n        this.routeInfoExtra = null;\n        this.castContext.getSessionManagerImpl().onSessionStartFailed(this, statusCode);\n        try {\n            this.castContext.getRouter().selectDefaultRoute();\n        } catch (RemoteException ex) {\n            Log.e(TAG, \"Error calling selectDefaultRoute: \" + ex.getMessage());\n        }\n    }\n\n    public void onRouteSelected(Bundle extras) {\n    }\n\n    public CastSessionImpl getCastSession() {\n        return this.castSession;\n    }\n\n    public void setCastSession(CastSessionImpl castSession) {\n        this.castSession = castSession;\n    }\n\n    public ISessionProxy getSessionProxy() {\n        return this.proxy;\n    }\n\n    public IObjectWrapper getWrappedSession() throws RemoteException {\n        if (this.proxy == null) {\n            return ObjectWrapper.wrap(null);\n        }\n        return this.proxy.getWrappedSession();\n    }\n\n    @Override\n    public String getCategory() {\n        return this.category;\n    }\n\n    @Override\n    public String getSessionId() {\n        return this.sessionId;\n    }\n\n    @Override\n    public String getRouteId() {\n        return this.routeId;\n    }\n\n    @Override\n    public boolean isConnected() {\n        return this.mIsConnected;\n    }\n\n    @Override\n    public boolean isConnecting() {\n        return this.mIsConnecting;\n    }\n\n    @Override\n    public boolean isDisconnecting() {\n        Log.d(TAG, \"unimplemented Method: isDisconnecting\");\n        return false;\n    }\n\n    @Override\n    public boolean isDisconnected() {\n        Log.d(TAG, \"unimplemented Method: isDisconnected\");\n        return false;\n    }\n\n    @Override\n    public boolean isResuming() {\n        Log.d(TAG, \"unimplemented Method: isResuming\");\n        return false;\n    }\n\n    @Override\n    public boolean isSuspended() {\n        Log.d(TAG, \"unimplemented Method: isSuspended\");\n        return false;\n    }\n\n    @Override\n    public void notifySessionStarted(String sessionId) {\n        Log.d(TAG, \"unimplemented Method: notifySessionStarted\");\n    }\n\n    @Override\n    public void notifyFailedToStartSession(int error) {\n        Log.d(TAG, \"unimplemented Method: notifyFailedToStartSession\");\n    }\n\n    @Override\n    public void notifySessionEnded(int error) {\n        Log.d(TAG, \"unimplemented Method: notifySessionEnded\");\n    }\n\n    @Override\n    public void notifySessionResumed(boolean wasSuspended) {\n        Log.d(TAG, \"unimplemented Method: notifySessionResumed\");\n    }\n\n    @Override\n    public void notifyFailedToResumeSession(int error) {\n        Log.d(TAG, \"unimplemented Method: notifyFailedToResumeSession\");\n    }\n\n    @Override\n    public void notifySessionSuspended(int reason) {\n        Log.d(TAG, \"unimplemented Method: notifySessionSuspended\");\n    }\n\n    @Override\n    public IObjectWrapper getWrappedObject() {\n        return ObjectWrapper.wrap(this);\n    }\n}\n"
  },
  {
    "path": "play-services-cast-framework/core/src/main/java/com/google/android/gms/cast/framework/internal/SessionManagerImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.cast.framework.internal;\n\nimport android.os.Bundle;\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport com.google.android.gms.cast.framework.CastState;\nimport com.google.android.gms.cast.framework.ICastStateListener;\nimport com.google.android.gms.cast.framework.ISession;\nimport com.google.android.gms.cast.framework.ISessionManager;\nimport com.google.android.gms.cast.framework.ISessionManagerListener;\nimport com.google.android.gms.cast.framework.internal.CastContextImpl;\nimport com.google.android.gms.cast.framework.internal.SessionImpl;\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.dynamic.ObjectWrapper;\n\nimport java.util.Set;\nimport java.util.HashSet;\n\nimport java.util.Map;\nimport java.util.HashMap;\n\npublic class SessionManagerImpl extends ISessionManager.Stub {\n    private static final String TAG = SessionManagerImpl.class.getSimpleName();\n\n    private CastContextImpl castContext;\n\n    private Set<ISessionManagerListener> sessionManagerListeners = new HashSet<ISessionManagerListener>();\n    private Set<ICastStateListener> castStateListeners = new HashSet<ICastStateListener>();\n\n    private Map<String, SessionImpl> routeSessions = new HashMap<String, SessionImpl>();\n\n    private SessionImpl currentSession;\n\n    private int castState = CastState.NO_DEVICES_AVAILABLE;\n\n    public SessionManagerImpl(CastContextImpl castContext) {\n        this.castContext = castContext;\n    }\n\n    @Override\n    public IObjectWrapper getWrappedCurrentSession() throws RemoteException {\n        if (this.currentSession == null) {\n            return ObjectWrapper.wrap(null);\n        }\n        return this.currentSession.getWrappedSession();\n    }\n\n    @Override\n    public void endCurrentSession(boolean b, boolean stopCasting) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: endCurrentSession\");\n    }\n\n    @Override\n    public void addSessionManagerListener(ISessionManagerListener listener) {\n        Log.d(TAG, \"unimplemented Method: addSessionManagerListener\");\n        this.sessionManagerListeners.add(listener);\n    }\n\n    @Override\n    public void removeSessionManagerListener(ISessionManagerListener listener) {\n        Log.d(TAG, \"unimplemented Method: removeSessionManagerListener\");\n        this.sessionManagerListeners.remove(listener);\n    }\n\n    @Override\n    public void addCastStateListener(ICastStateListener listener) {\n        Log.d(TAG, \"unimplemented Method: addCastStateListener\");\n        this.castStateListeners.add(listener);\n    }\n\n    @Override\n    public void removeCastStateListener(ICastStateListener listener) {\n        Log.d(TAG, \"unimplemented Method: removeCastStateListener\");\n        this.castStateListeners.remove(listener);\n    }\n\n    @Override\n    public IObjectWrapper getWrappedThis() throws RemoteException {\n        return ObjectWrapper.wrap(this);\n    }\n\n    @Override\n    public int getCastState() {\n        return this.castState;\n    }\n\n    @Override\n    public void startSession(Bundle params) {\n        Log.d(TAG, \"unimplemented Method: startSession\");\n        String routeId = params.getString(\"CAST_INTENT_TO_CAST_ROUTE_ID_KEY\");\n        String sessionId = params.getString(\"CAST_INTENT_TO_CAST_SESSION_ID_KEY\");\n    }\n\n    public void onRouteSelected(String routeId, Bundle extras) {\n        Log.d(TAG, \"unimplemented Method: onRouteSelected: \" + routeId);\n    }\n\n    private void setCastState(int castState) {\n        this.castState = castState;\n        this.onCastStateChanged();\n    }\n\n    public void onCastStateChanged() {\n        for (ICastStateListener listener : this.castStateListeners) {\n            try {\n                listener.onCastStateChanged(this.castState);\n            } catch (RemoteException e) {\n                Log.d(TAG, \"Remote exception calling onCastStateChanged: \" + e.getMessage());\n            }\n        }\n    }\n\n    public void onSessionStarting(SessionImpl session) {\n        this.setCastState(CastState.CONNECTING);\n        for (ISessionManagerListener listener : this.sessionManagerListeners) {\n            try {\n                listener.onSessionStarting(session.getSessionProxy().getWrappedSession());\n            } catch (RemoteException e) {\n                Log.d(TAG, \"Remote exception calling onSessionStarting: \" + e.getMessage());\n            }\n        }\n    }\n\n    public void onSessionStartFailed(SessionImpl session, int error) {\n        this.currentSession = null;\n        this.setCastState(CastState.NOT_CONNECTED);\n        for (ISessionManagerListener listener : this.sessionManagerListeners) {\n            try {\n                listener.onSessionStartFailed(session.getSessionProxy().getWrappedSession(), error);\n            } catch (RemoteException e) {\n                Log.d(TAG, \"Remote exception calling onSessionStartFailed: \" + e.getMessage());\n            }\n        }\n    }\n\n    public void onSessionStarted(SessionImpl session, String sessionId) {\n        this.currentSession = session;\n        this.setCastState(CastState.CONNECTED);\n        for (ISessionManagerListener listener : this.sessionManagerListeners) {\n            try {\n                listener.onSessionStarted(session.getSessionProxy().getWrappedSession(), sessionId);\n            } catch (RemoteException e) {\n                Log.d(TAG, \"Remote exception calling onSessionStarted: \" + e.getMessage());\n            }\n        }\n    }\n\n    public void onSessionResumed(SessionImpl session, boolean wasSuspended) {\n        this.setCastState(CastState.CONNECTED);\n        for (ISessionManagerListener listener : this.sessionManagerListeners) {\n            try {\n                listener.onSessionResumed(session.getSessionProxy().getWrappedSession(), wasSuspended);\n            } catch (RemoteException e) {\n                Log.d(TAG, \"Remote exception calling onSessionResumed: \" + e.getMessage());\n            }\n        }\n    }\n\n    public void onSessionEnding(SessionImpl session) {\n        for (ISessionManagerListener listener : this.sessionManagerListeners) {\n            try {\n                listener.onSessionEnding(session.getSessionProxy().getWrappedSession());\n            } catch (RemoteException e) {\n                Log.d(TAG, \"Remote exception calling onSessionEnding: \" + e.getMessage());\n            }\n        }\n    }\n\n    public void onSessionEnded(SessionImpl session, int error) {\n        this.currentSession = null;\n        this.setCastState(CastState.NOT_CONNECTED);\n        for (ISessionManagerListener listener : this.sessionManagerListeners) {\n            try {\n                listener.onSessionEnded(session.getSessionProxy().getWrappedSession(), error);\n            } catch (RemoteException e) {\n                Log.d(TAG, \"Remote exception calling onSessionEnded: \" + e.getMessage());\n            }\n        }\n    }\n\n    public void onSessionResuming(SessionImpl session, String sessionId) {\n        for (ISessionManagerListener listener : this.sessionManagerListeners) {\n            try {\n                listener.onSessionResuming(session.getSessionProxy().getWrappedSession(), sessionId);\n            } catch (RemoteException e) {\n                Log.d(TAG, \"Remote exception calling onSessionResuming: \" + e.getMessage());\n            }\n        }\n    }\n\n    public void onSessionResumeFailed(SessionImpl session, int error) {\n        this.currentSession = null;\n        this.setCastState(CastState.NOT_CONNECTED);\n        for (ISessionManagerListener listener : this.sessionManagerListeners) {\n            try {\n                listener.onSessionResumeFailed(session.getSessionProxy().getWrappedSession(), error);\n            } catch (RemoteException e) {\n                Log.d(TAG, \"Remote exception calling onSessionResumeFailed: \" + e.getMessage());\n            }\n        }\n    }\n\n    public void onSessionSuspended(SessionImpl session, int reason) {\n        this.setCastState(CastState.NOT_CONNECTED);\n        for (ISessionManagerListener listener : this.sessionManagerListeners) {\n            try {\n                listener.onSessionSuspended(session.getSessionProxy().getWrappedSession(), reason);\n            } catch (RemoteException e) {\n                Log.d(TAG, \"Remote exception calling onSessionSuspended: \" + e.getMessage());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-cast-framework/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2017 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <uses-permission android:name=\"android.permission.FOREGROUND_SERVICE\"/>\n\n    <queries>\n        <package android:name=\"com.google.android.gms.policy_cast_dynamite\"/>\n    </queries>\n\n    <application>\n        <receiver\n                android:name=\"com.google.android.gms.cast.framework.media.MediaIntentReceiver\"\n                android:exported=\"false\"/>\n\n        <service\n                android:name=\"com.google.android.gms.cast.framework.media.MediaNotificationService\"\n                android:exported=\"false\"\n                android:foregroundServiceType=\"mediaPlayback\"/>\n\n        <service\n                android:name=\"com.google.android.gms.cast.framework.ReconnectionService\"\n                android:exported=\"false\"/>\n    </application>\n\n</manifest>\n"
  },
  {
    "path": "play-services-cast-framework/src/main/aidl/com/google/android/gms/cast/framework/CastOptions.aidl",
    "content": "package com.google.android.gms.cast.framework;\n\nparcelable CastOptions;"
  },
  {
    "path": "play-services-cast-framework/src/main/aidl/com/google/android/gms/cast/framework/IAppVisibilityListener.aidl",
    "content": "package com.google.android.gms.cast.framework;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\n\ninterface IAppVisibilityListener {\n    IObjectWrapper getThisObject() = 0;\n    void onAppEnteredForeground() = 1;\n    void onAppEnteredBackground() = 2;\n    int getSupportedVersion() = 3;\n}"
  },
  {
    "path": "play-services-cast-framework/src/main/aidl/com/google/android/gms/cast/framework/ICastConnectionController.aidl",
    "content": "package com.google.android.gms.cast.framework;\n\nimport com.google.android.gms.cast.LaunchOptions;\n\ninterface ICastConnectionController {\n    void joinApplication(String applicationId, String sessionId) = 0;\n    void launchApplication(String applicationId, in LaunchOptions launchOptions) = 1;\n    void stopApplication(String sessionId) = 2;\n    void closeConnection(int reason) = 3; // Maybe?\n    int getSupportedVersion() = 4;\n}\n"
  },
  {
    "path": "play-services-cast-framework/src/main/aidl/com/google/android/gms/cast/framework/ICastContext.aidl",
    "content": "package com.google.android.gms.cast.framework;\n\nimport com.google.android.gms.cast.framework.IAppVisibilityListener;\nimport com.google.android.gms.cast.framework.ISessionManager;\nimport com.google.android.gms.cast.framework.IDiscoveryManager;\nimport com.google.android.gms.dynamic.IObjectWrapper;\n\ninterface ICastContext {\n    Bundle getMergedSelectorAsBundle() = 0;\n    boolean isApplicationVisible() = 1;\n    void addVisibilityChangeListener(IAppVisibilityListener listener) = 2;\n    void removeVisibilityChangeListener(IAppVisibilityListener listener) = 3;\n    ISessionManager getSessionManagerImpl() = 4;\n    IDiscoveryManager getDiscoveryManagerImpl() = 5;\n    void destroy() = 6; // deprecated?\n    void onActivityResumed(in IObjectWrapper activity) = 7; // deprecated?\n    void onActivityPaused(in IObjectWrapper activity) = 8; // deprecated?\n    IObjectWrapper getWrappedThis() = 9;\n    void setReceiverApplicationId(String receiverApplicationId, in Map/*<String, IBinder>*/ sessionProvidersByCategory) = 10;\n}\n"
  },
  {
    "path": "play-services-cast-framework/src/main/aidl/com/google/android/gms/cast/framework/ICastSession.aidl",
    "content": "package com.google.android.gms.cast.framework;\n\nimport android.os.Bundle;\n\nimport com.google.android.gms.cast.ApplicationMetadata;\nimport com.google.android.gms.common.api.Status;\n\ninterface ICastSession {\n    void onConnected(in Bundle routeInfoExtra) = 0;\n    void onConnectionSuspended(int reason) = 1;\n    void onConnectionFailed(in Status status) = 2;\n    void onApplicationConnectionSuccess(in ApplicationMetadata applicationMetadata, String applicationStatus, String sessionId, boolean wasLaunched) = 3;\n    void onApplicationConnectionFailure(int statusCode) = 4;\n    void disconnectFromDevice(boolean boolean1, int int1) = 5;\n}\n"
  },
  {
    "path": "play-services-cast-framework/src/main/aidl/com/google/android/gms/cast/framework/ICastStateListener.aidl",
    "content": "package com.google.android.gms.cast.framework;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\n\ninterface ICastStateListener {\n    IObjectWrapper getWrappedThis() = 0;\n    void onCastStateChanged(int newState) = 1;\n    int getSupportedVersion() = 2;\n}\n"
  },
  {
    "path": "play-services-cast-framework/src/main/aidl/com/google/android/gms/cast/framework/IDiscoveryManager.aidl",
    "content": "package com.google.android.gms.cast.framework;\n\nimport com.google.android.gms.cast.framework.IDiscoveryManagerListener;\nimport com.google.android.gms.dynamic.IObjectWrapper;\n\ninterface IDiscoveryManager {\n    void startDiscovery() = 0; // Maybe?\n    void stopDiscovery() = 1; // Maybe?\n    void addDiscoveryManagerListener(IDiscoveryManagerListener listener) = 2;\n    void removeDiscoveryManagerListener(IDiscoveryManagerListener listener) = 3;\n    IObjectWrapper getWrappedThis() = 4;\n}\n"
  },
  {
    "path": "play-services-cast-framework/src/main/aidl/com/google/android/gms/cast/framework/IDiscoveryManagerListener.aidl",
    "content": "package com.google.android.gms.cast.framework;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\n\ninterface IDiscoveryManagerListener {\n    IObjectWrapper getWrappedThis() = 0;\n    void onDeviceAvailabilityChanged(boolean deviceAvailable) = 1;\n}\n"
  },
  {
    "path": "play-services-cast-framework/src/main/aidl/com/google/android/gms/cast/framework/IReconnectionService.aidl",
    "content": "package com.google.android.gms.cast.framework;\n\ninterface IReconnectionService {\n    void onCreate() = 0;\n    int onStartCommand(in Intent intent, int flags, int startId) = 1;\n    IBinder onBind(in Intent intent) = 2;\n    void onDestroy() = 3;\n}"
  },
  {
    "path": "play-services-cast-framework/src/main/aidl/com/google/android/gms/cast/framework/ISession.aidl",
    "content": "package com.google.android.gms.cast.framework;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\n\ninterface ISession {\n    IObjectWrapper getWrappedObject() = 0;\n    String getCategory() = 1;\n    String getSessionId() = 2;\n    String getRouteId() = 3;\n    boolean isConnected() = 4;\n    boolean isConnecting() = 5;\n    boolean isDisconnecting() = 6;\n    boolean isDisconnected() = 7;\n    boolean isResuming() = 8;\n    boolean isSuspended() = 9;\n    void notifySessionStarted(String sessionId) = 10;\n    void notifyFailedToStartSession(int error) = 11;\n    void notifySessionEnded(int error) = 12;\n    void notifySessionResumed(boolean wasSuspended) = 13;\n    void notifyFailedToResumeSession(int error) = 14;\n    void notifySessionSuspended(int reason) = 15;\n}\n"
  },
  {
    "path": "play-services-cast-framework/src/main/aidl/com/google/android/gms/cast/framework/ISessionManager.aidl",
    "content": "package com.google.android.gms.cast.framework;\n\nimport android.os.Bundle;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.cast.framework.ISessionManagerListener;\nimport com.google.android.gms.cast.framework.ICastStateListener;\n\ninterface ISessionManager {\n    IObjectWrapper getWrappedCurrentSession() = 0;\n    void addSessionManagerListener(ISessionManagerListener listener) = 1;\n    void removeSessionManagerListener(ISessionManagerListener listener) = 2;\n    void addCastStateListener(ICastStateListener listener) = 3;\n    void removeCastStateListener(ICastStateListener listener) = 4;\n    void endCurrentSession(boolean b, boolean stopCasting) = 5;\n    IObjectWrapper getWrappedThis() = 6;\n    int getCastState() = 7;\n    void startSession(in Bundle options) = 8;\n}\n"
  },
  {
    "path": "play-services-cast-framework/src/main/aidl/com/google/android/gms/cast/framework/ISessionManagerListener.aidl",
    "content": "package com.google.android.gms.cast.framework;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\n\ninterface ISessionManagerListener {\n    IObjectWrapper getWrappedThis() = 0;\n    void onSessionStarting(IObjectWrapper session) = 1;\n    void onSessionStarted(IObjectWrapper session, String sessionId) = 2;\n    void onSessionStartFailed(IObjectWrapper session, int error) = 3;\n    void onSessionEnding(IObjectWrapper session) = 4;\n    void onSessionEnded(IObjectWrapper session, int error) = 5;\n    void onSessionResuming(IObjectWrapper session, String sessionId) = 6;\n    void onSessionResumed(IObjectWrapper session, boolean wasSuspended) = 7;\n    void onSessionResumeFailed(IObjectWrapper session, int error) = 8;\n    void onSessionSuspended(IObjectWrapper session, int reason) = 9;\n    int getSupportedVersion() = 10;\n}\n"
  },
  {
    "path": "play-services-cast-framework/src/main/aidl/com/google/android/gms/cast/framework/ISessionProvider.aidl",
    "content": "package com.google.android.gms.cast.framework;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\n\ninterface ISessionProvider {\n    IObjectWrapper getSession(String sessionId) = 0;\n    boolean isSessionRecoverable() = 1;\n    String getCategory() = 2;\n    int getSupportedVersion() = 3;\n}\n"
  },
  {
    "path": "play-services-cast-framework/src/main/aidl/com/google/android/gms/cast/framework/ISessionProxy.aidl",
    "content": "package com.google.android.gms.cast.framework;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\n\ninterface ISessionProxy {\n    IObjectWrapper getWrappedSession() = 0;\n    void start(in Bundle extras) = 1;\n    void resume(in Bundle extras) = 2;\n    void end(boolean paramBoolean) = 3;\n    long getSessionRemainingTimeMs() = 4;\n    int getSupportedVersion() = 5;\n    void onStarting(in Bundle routeInfoExtra) = 6;\n    void onResuming(in Bundle routeInfoExtra) = 7;\n}\n"
  },
  {
    "path": "play-services-cast-framework/src/main/aidl/com/google/android/gms/cast/framework/internal/ICastDynamiteModule.aidl",
    "content": "package com.google.android.gms.cast.framework.internal;\n\nimport com.google.android.gms.cast.framework.CastOptions;\nimport com.google.android.gms.cast.framework.ICastConnectionController;\nimport com.google.android.gms.cast.framework.ICastContext;\nimport com.google.android.gms.cast.framework.ICastSession;\nimport com.google.android.gms.cast.framework.IReconnectionService;\nimport com.google.android.gms.cast.framework.ISession;\nimport com.google.android.gms.cast.framework.ISessionProxy;\nimport com.google.android.gms.cast.framework.internal.IMediaRouter;\nimport com.google.android.gms.cast.framework.media.CastMediaOptions;\nimport com.google.android.gms.cast.framework.media.IMediaNotificationService;\nimport com.google.android.gms.cast.framework.media.internal.IFetchBitmapTask;\nimport com.google.android.gms.cast.framework.media.internal.IFetchBitmapTaskProgressPublisher;\nimport com.google.android.gms.dynamic.IObjectWrapper;\n\ninterface ICastDynamiteModule {\n    ICastContext newCastContextImpl(in IObjectWrapper context, in CastOptions options, IMediaRouter router, in Map sessionProviders) = 0;\n    ISession newSessionImpl(String category, String sessionId, ISessionProxy proxy) = 1;\n    ICastSession newCastSessionImpl(in CastOptions options, in IObjectWrapper session, ICastConnectionController controller) = 2;\n    IMediaNotificationService newMediaNotificationServiceImpl(in IObjectWrapper service, in IObjectWrapper castContext, in IObjectWrapper resources, in CastMediaOptions options) = 3;\n    IReconnectionService newReconnectionServiceImpl(in IObjectWrapper service, in IObjectWrapper sessionManager, in IObjectWrapper discoveryManager) = 4;\n    IFetchBitmapTask newFetchBitmapTaskImpl(in IObjectWrapper asyncTask, IFetchBitmapTaskProgressPublisher progressPublisher, int i1, int i2, boolean b1, long l1, int i3, int i4, int i5) = 5;\n}\n"
  },
  {
    "path": "play-services-cast-framework/src/main/aidl/com/google/android/gms/cast/framework/internal/IMediaRouter.aidl",
    "content": "package com.google.android.gms.cast.framework.internal;\n\nimport android.os.Bundle;\n\nimport com.google.android.gms.cast.framework.internal.IMediaRouterCallback;\n\ninterface IMediaRouter {\n    void registerMediaRouterCallbackImpl(in Bundle selector, IMediaRouterCallback callback) = 0;\n    void addCallback(in Bundle selector, int flags) = 1;\n    void removeCallback(in Bundle selector) = 2;\n    boolean isRouteAvailable(in Bundle selector, int flags) = 3;\n    void selectRouteById(String routeId) = 4;\n    void selectDefaultRoute() = 5;\n    boolean isDefaultRouteSelected() = 6; // Maybe?\n    Bundle getRouteInfoExtrasById(String routeId) = 7;\n    String getSelectedRouteId() = 8; // Maybe?\n    int getSupportedVersion() = 9;\n    void clearCallbacks() = 10;\n}\n"
  },
  {
    "path": "play-services-cast-framework/src/main/aidl/com/google/android/gms/cast/framework/internal/IMediaRouterCallback.aidl",
    "content": "package com.google.android.gms.cast.framework.internal;\n\nimport android.os.Bundle;\n\ninterface IMediaRouterCallback {\n    void onRouteAdded(String routeId, in Bundle extras) = 0;\n    void onRouteChanged(String routeId, in Bundle extras) = 1;\n    void onRouteRemoved(String routeId, in Bundle extras) = 2;\n    void onRouteSelected(String routeId, in Bundle extras) = 3;\n    void unknown(String routeId, in Bundle extras) = 4;\n    void onRouteUnselected(String routeId, in Bundle extras, int reason) = 5;\n}\n"
  },
  {
    "path": "play-services-cast-framework/src/main/aidl/com/google/android/gms/cast/framework/media/CastMediaOptions.aidl",
    "content": "package com.google.android.gms.cast.framework.media;\n\nparcelable CastMediaOptions;"
  },
  {
    "path": "play-services-cast-framework/src/main/aidl/com/google/android/gms/cast/framework/media/IImagePicker.aidl",
    "content": "package com.google.android.gms.cast.framework.media;\n\nimport com.google.android.gms.common.images.WebImage;\nimport com.google.android.gms.dynamic.IObjectWrapper;\n\ninterface IImagePicker {\n  // WebImage onPickImage(MediaMetadata metadata, int int1) = 0;\n  IObjectWrapper getWrappedClientObject() = 1;\n  int unknown1() = 2;\n  // WebImage onPickImage(MediaMetadata metadata, ImageHints imageHints) = 3;\n}\n"
  },
  {
    "path": "play-services-cast-framework/src/main/aidl/com/google/android/gms/cast/framework/media/IMediaNotificationService.aidl",
    "content": "package com.google.android.gms.cast.framework.media;\n\ninterface IMediaNotificationService {\n\n}"
  },
  {
    "path": "play-services-cast-framework/src/main/aidl/com/google/android/gms/cast/framework/media/INotificationActionsProvider.aidl",
    "content": "package com.google.android.gms.cast.framework.media;\n\ninterface INotificationActionsProvider {\n\n}\n"
  },
  {
    "path": "play-services-cast-framework/src/main/aidl/com/google/android/gms/cast/framework/media/NotificationOptions.aidl",
    "content": "package com.google.android.gms.cast.framework.media;\n\nparcelable NotificationOptions;\n"
  },
  {
    "path": "play-services-cast-framework/src/main/aidl/com/google/android/gms/cast/framework/media/internal/IFetchBitmapTask.aidl",
    "content": "package com.google.android.gms.cast.framework.media.internal;\n\ninterface IFetchBitmapTask {\n\n}"
  },
  {
    "path": "play-services-cast-framework/src/main/aidl/com/google/android/gms/cast/framework/media/internal/IFetchBitmapTaskProgressPublisher.aidl",
    "content": "package com.google.android.gms.cast.framework.media.internal;\n\ninterface IFetchBitmapTaskProgressPublisher {\n\n}"
  },
  {
    "path": "play-services-cast-framework/src/main/java/com/google/android/gms/cast/framework/CastButtonFactory.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.cast.framework;\n\npublic class CastButtonFactory {\n}\n"
  },
  {
    "path": "play-services-cast-framework/src/main/java/com/google/android/gms/cast/framework/CastContext.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.cast.framework;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.content.pm.PackageManager;\nimport android.os.Bundle;\nimport android.os.IBinder;\nimport android.os.RemoteException;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.cast.framework.internal.IMediaRouter;\nimport com.google.android.gms.tasks.Task;\nimport com.google.android.gms.tasks.Tasks;\nimport org.microg.gms.cast.CastDynamiteModule;\nimport org.microg.gms.cast.CastSessionProvider;\nimport org.microg.gms.common.PublicApi;\n\nimport java.lang.reflect.InvocationTargetException;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.Executor;\n\npublic class CastContext {\n    /**\n     * The metadata key to specify the fully qualified name of the {@link OptionsProvider} implementation in the\n     * {@code AndroidManifest.xml}.\n     */\n    public static final String OPTIONS_PROVIDER_CLASS_NAME_KEY = \"com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME\";\n\n    /**\n     * Returns the shared instance of {@link CastContext}. This method must be called after {@link CastContext} is initialized through\n     * {@link #getSharedInstance(Context, Executor)}. Otherwise, this method will return {@code null}.\n     *\n     * @throws IllegalStateException If this method is not called on the main thread.\n     */\n    public static CastContext getSharedInstance() {\n        return sharedInstance;\n    }\n\n    /**\n     * Returns a shared instance of {@link CastContext}. The shared instance will be initialized on the first time this method is called.\n     *\n     * @param context An application {@link Context}. If this is not an application {@link Context}, {@link Context#getApplicationContext()} will be called on\n     *                the given context, to retrieve it.\n     * @throws IllegalStateException If any of the following:\n     *                               <ul>\n     *                                   <li>This method is not called on the main thread.</li>\n     *                                   <li>\n     *                                       The fully qualified name of the {@link OptionsProvider} implementation is not specified as a metadata in the\n     *                                       {@code AndroidManifest.xml} with key {@link #OPTIONS_PROVIDER_CLASS_NAME_KEY}.\n     *                                   </li>\n     *                                   <li>{@code optionsProviderClass} or its nullary constructor is not accessible.</li>\n     *                                   <li>Instantiation of {@link OptionsProvider} fails for some other reason.</li>\n     *                               </ul>\n     * @deprecated Use {@link #getSharedInstance(Context, Executor)} instead to handle the exception when Cast SDK fails to load the internal\n     * Cast module.\n     */\n    @Deprecated\n    public static CastContext getSharedInstance(Context context) {\n        if (sharedInstance == null) {\n            Context appContext = context.getApplicationContext();\n            OptionsProvider optionsProvider = getOptionsProvider(appContext);\n            CastOptions castOptions = optionsProvider.getCastOptions(appContext);\n            try {\n                sharedInstance = new CastContext(appContext, castOptions, optionsProvider.getAdditionalSessionProviders(appContext));\n            } catch (ModuleUnavailableException e) {\n                throw new RuntimeException(e);\n            }\n        }\n        return sharedInstance;\n    }\n\n    /**\n     * Returns an asynchronous Task API call on the shared instance of {@link CastContext}. The shared instance will be initialized\n     * on the first time this method is called.\n     * <p>\n     * Note that {@link #getSharedInstance(Context, Executor)} should be called in the {@link Activity#onCreate(Bundle)} method\n     * of the activities that might display a Cast button. The Cast SDK provides {@link CastButtonFactory} to set up a Cast button.\n     * <p>\n     * Note that {@link ModuleUnavailableException} could be thrown when the SDK fails to load the internal Cast module. The\n     * caller will get the exception from {@link Task#getException()} when the task completes.\n     *\n     * @param context  An application {@link Context}. If this is not an application {@link Context}, {@link Context#getApplicationContext()} will be called on\n     *                 the given context, to retrieve it.\n     * @param executor An {@link Executor} to load the internal Cast module.\n     * @throws IllegalStateException If any of the following:\n     *                               <ul>\n     *                                   <li>This method is not called on the main thread.</li>\n     *                                   <li>\n     *                                       The fully qualified name of the {@link OptionsProvider} implementation is not specified as a metadata in the\n     *                                       {@code AndroidManifest.xml} with key {@link #OPTIONS_PROVIDER_CLASS_NAME_KEY}.\n     *                                   </li>\n     *                                   <li>{@code optionsProviderClass} or its nullary constructor is not accessible.</li>\n     *                                   <li>Instantiation of {@link OptionsProvider} fails for some other reason.</li>\n     *                               </ul>\n     */\n    public static Task<CastContext> getSharedInstance(Context context, Executor executor) {\n        if (sharedInstance != null) {\n            return Tasks.forResult(sharedInstance);\n        }\n        Context appContext = context.getApplicationContext();\n        OptionsProvider optionsProvider = getOptionsProvider(appContext);\n        CastOptions castOptions = optionsProvider.getCastOptions(appContext);\n        return Tasks.call(executor, () -> {\n            sharedInstance = new CastContext(appContext, castOptions, optionsProvider.getAdditionalSessionProviders(appContext));\n            return sharedInstance;\n        });\n    }\n\n    /**\n     * Returns the {@link SessionManager}, never returns {@code null}.\n     *\n     * @throws IllegalStateException If this method is not called on the main thread.\n     */\n    @NonNull\n    public SessionManager getSessionManager() {\n        return sessionManager;\n    }\n\n    private static volatile CastContext sharedInstance;\n    private Context appContext;\n    private CastOptions castOptions;\n    private IMediaRouter mediaRouter;\n    private List<SessionProvider> additionalSessionProviders;\n    private CastSessionProvider castSessionProvider;\n    private ICastContext delegate;\n    private SessionManager sessionManager;\n    private DiscoveryManager discoveryManager;\n\n    private CastContext(Context appContext, CastOptions castOptions, @Nullable List<SessionProvider> additionalSessionProviders) throws ModuleUnavailableException {\n        this.appContext = appContext;\n        this.castOptions = castOptions;\n        this.mediaRouter = null; // TODO\n        this.additionalSessionProviders = additionalSessionProviders;\n        this.castSessionProvider = new CastSessionProvider(appContext, castOptions);\n        try {\n            this.delegate = CastDynamiteModule.newCastContext(appContext, castOptions, mediaRouter, getSessionProviderMap());\n            this.sessionManager = new SessionManager(appContext, delegate.getSessionManagerImpl());\n            this.discoveryManager = new DiscoveryManager(appContext, delegate.getDiscoveryManagerImpl());\n        } catch (RemoteException e) {\n            throw new IllegalStateException(\"Failed to call dynamite module\", e);\n        }\n    }\n\n    private Map<String, IBinder> getSessionProviderMap() {\n        Map<String, IBinder> map = new HashMap<>();\n        if (castSessionProvider != null) {\n            map.put(castSessionProvider.getCategory(), castSessionProvider.asBinder());\n        }\n        List<SessionProvider> list = this.additionalSessionProviders;\n        if (list != null) {\n            for (SessionProvider sessionProvider : list) {\n                if (sessionProvider == null) throw new IllegalArgumentException(\"Additional SessionProvider must not be null.\");\n                if (sessionProvider.getCategory() == null || sessionProvider.getCategory().isEmpty())\n                    throw new IllegalArgumentException(\"Category for SessionProvider must not be null or empty string.\");\n                if (map.containsKey(sessionProvider.getCategory()))\n                    throw new IllegalArgumentException(\"SessionProvider for category \" + sessionProvider.getCategory() + \" already added\");\n                map.put(sessionProvider.getCategory(), sessionProvider.asBinder());\n            }\n        }\n        return map;\n    }\n\n    private static OptionsProvider getOptionsProvider(Context context) {\n        try {\n            Bundle metaData = context.getPackageManager().getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA).metaData;\n            String optionsProviderClassName = metaData.getString(OPTIONS_PROVIDER_CLASS_NAME_KEY);\n            if (optionsProviderClassName != null) {\n                return Class.forName(optionsProviderClassName).asSubclass(OptionsProvider.class).getDeclaredConstructor().newInstance();\n            }\n            throw new IllegalStateException(\"The fully qualified name of the implementation of OptionsProvider must be provided as a metadata in the AndroidManifest.xml with key com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME.\");\n        } catch (PackageManager.NameNotFoundException | ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InstantiationException |\n                 InvocationTargetException | NullPointerException e) {\n            throw new IllegalStateException(\"Failed to initialize CastContext.\", e);\n        }\n    }\n\n    @NonNull\n    DiscoveryManager getDiscoveryManager() {\n        return discoveryManager;\n    }\n}\n"
  },
  {
    "path": "play-services-cast-framework/src/main/java/com/google/android/gms/cast/framework/CastOptions.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2016 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.cast.framework;\n\nimport androidx.annotation.NonNull;\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\nimport com.google.android.gms.cast.framework.media.CastMediaOptions;\nimport com.google.android.gms.cast.LaunchOptions;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Configuration parameters for initializing the {@link CastContext}. The {@link CastOptions.Builder} is used to create an instance of\n * {@link CastOptions}, and so contains the corresponding setter methods.\n */\npublic class CastOptions extends AutoSafeParcelable {\n    @Field(1)\n    private int versionCode = 1;\n    @Field(2)\n    private String receiverApplicationId;\n    @Field(3)\n    private ArrayList<String> supportedNamespaces;\n    @Field(4)\n    private boolean stopReceiverApplicationWhenEndingSession;\n    @Field(5)\n    private LaunchOptions launchOptions;\n    @Field(6)\n    private boolean resumeSavedSession;\n    @Field(7)\n    private CastMediaOptions castMediaOptions;\n    @Field(8)\n    private boolean enableReconnectionService;\n    @Field(9)\n    private double volumeDeltaBeforeIceCreamSandwich;\n    @Field(10)\n    private boolean enableIpv6Support;\n    @Field(11)\n    private boolean outputSwitcherEnabled;\n    @Field(12)\n    private boolean isRemoteToLocalEnabled;\n    @Field(13)\n    private List<String> routeDiscoveryReceiverApplicationIds;\n    @Field(14)\n    private boolean sessionTransferEnabled;\n    @Field(15)\n    private int persistCastButtonEnabled;\n    @Field(16)\n    private boolean resumeSessionAfterTransferEnabled;\n\n    /**\n     * Returns the {@link CastMediaOptions} that is used to configure a media session.\n     */\n    public CastMediaOptions getCastMediaOptions() {\n        return castMediaOptions;\n    }\n\n    /**\n     * Returns {@code true} if {@link ReconnectionService} should be enabled when needed to better handle session recovery.\n     */\n    public boolean getEnableReconnectionService() {\n        return enableReconnectionService;\n    }\n\n    /**\n     * Returns the {@link LaunchOptions}.\n     */\n    public LaunchOptions getLaunchOptions() {\n        return launchOptions;\n    }\n\n    /**\n     * Returns the cast receiver application ID. This ID is used in discovering supported receivers, and launching an application\n     * when starting a new session.\n     */\n    public String getReceiverApplicationId() {\n        return receiverApplicationId;\n    }\n\n    /**\n     * Returns {@code true} if the saved session should be resumed if it was dropped unexpectedly. Returns {@code false} if the saved\n     * session should not be resumed in this case.\n     */\n    public boolean getResumeSavedSession() {\n        return resumeSavedSession;\n    }\n\n    /**\n     * Returns {@code true} if the receiver application should be stopped when the session is ended by the user. Returns {@code false} if the\n     * receiver application should not be stopped in this case.\n     */\n    public boolean getStopReceiverApplicationWhenEndingSession() {\n        return stopReceiverApplicationWhenEndingSession;\n    }\n\n    /**\n     * Returns the list of supported cast namespaces.\n     */\n    @NonNull\n    public List<String> getSupportedNamespaces() {\n        return supportedNamespaces;\n    }\n\n    /**\n     * Returns the amount of receiver device volume to increase or decrease when the physical volume key is pressed on an\n     * Android device older than ICE CREAM SANDWICH. The SDK will call this method to obtain the volume delta when\n     * {@link CastContext#onDispatchVolumeKeyEventBeforeJellyBean(KeyEvent)} is called. The return value is not used on\n     * Android devices running ICE CREAM SANDWICH or newer.\n     */\n    @Deprecated\n    public double getVolumeDeltaBeforeIceCreamSandwich() {\n        return volumeDeltaBeforeIceCreamSandwich;\n    }\n\n    public static Creator<CastOptions> CREATOR = new AutoCreator<CastOptions>(CastOptions.class);\n}\n"
  },
  {
    "path": "play-services-cast-framework/src/main/java/com/google/android/gms/cast/framework/CastSession.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.cast.framework;\n\npublic class CastSession extends Session{\n}\n"
  },
  {
    "path": "play-services-cast-framework/src/main/java/com/google/android/gms/cast/framework/CastState.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.cast.framework;\n\npublic final class CastState {\n    public static final int NO_DEVICES_AVAILABLE = 1;\n    public static final int NOT_CONNECTED = 2;\n    public static final int CONNECTING = 3;\n    public static final int CONNECTED = 4;\n\n    public static String toString(int castState) {\n        switch (castState) {\n            case NO_DEVICES_AVAILABLE:\n                return \"NO_DEVICES_AVAILABLE\";\n            case NOT_CONNECTED:\n                return \"NOT_CONNECTED\";\n            case CONNECTING:\n                return \"CONNECTING\";\n            case CONNECTED:\n                return \"CONNECTED\";\n            default:\n                return \"UNKNOWN\";\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-cast-framework/src/main/java/com/google/android/gms/cast/framework/DiscoveryManager.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.cast.framework;\n\nimport android.content.Context;\nimport android.os.RemoteException;\nimport com.google.android.gms.cast.framework.IDiscoveryManager;\nimport com.google.android.gms.cast.framework.ISessionManager;\nimport com.google.android.gms.dynamic.IObjectWrapper;\n\nclass DiscoveryManager {\n    private Context context;\n    private IDiscoveryManager delegate;\n\n    public DiscoveryManager(Context context, IDiscoveryManager delegate) {\n        this.context = context;\n        this.delegate = delegate;\n    }\n\n    public IObjectWrapper getWrappedThis() {\n        try {\n            return delegate.getWrappedThis();\n        } catch (RemoteException e) {\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-cast-framework/src/main/java/com/google/android/gms/cast/framework/ModuleUnavailableException.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.cast.framework;\n\n/**\n * An exception thrown when the internal Cast module fails to load.\n */\npublic class ModuleUnavailableException extends Exception {\n    public ModuleUnavailableException(Throwable cause) {\n        super(cause);\n    }\n}\n"
  },
  {
    "path": "play-services-cast-framework/src/main/java/com/google/android/gms/cast/framework/OptionsProvider.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.cast.framework;\n\nimport android.content.Context;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.util.List;\n\n/**\n * Developers should implement this interface to provide options needed to create and initialize {@link CastContext}. The\n * implementation class must have a constructor without argument. The SDK will call that constructor to instantiate a new\n * instance.\n */\npublic interface OptionsProvider {\n    /**\n     * Provides a list of custom {@link SessionProvider} instances for non-Cast devices. This is optional.\n     *\n     * @param appContext The application {@link Context}.\n     * @return the list of {@link SessionProvider} instances, may be {@code null}.\n     */\n    @Nullable\n    List<SessionProvider> getAdditionalSessionProviders(@NonNull Context appContext);\n\n    /**\n     * Provides {@link CastOptions}, which affects discovery and session management of a Cast device.\n     *\n     * @param appContext The application {@link Context}.\n     * @return the {@link CastOptions}, must not be {@code null}.\n     */\n    @NonNull\n    CastOptions getCastOptions(@NonNull Context appContext);\n}\n"
  },
  {
    "path": "play-services-cast-framework/src/main/java/com/google/android/gms/cast/framework/ReconnectionService.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.cast.framework;\n\nimport android.app.Service;\nimport android.content.Intent;\nimport android.os.IBinder;\nimport android.os.RemoteException;\nimport androidx.annotation.Nullable;\nimport org.microg.gms.cast.CastDynamiteModule;\n\npublic class ReconnectionService extends Service {\n    private IReconnectionService delegate;\n\n    @Override\n    public void onCreate() {\n        CastContext castContext = CastContext.getSharedInstance(this);\n        delegate = CastDynamiteModule.newReconnectionService(this, castContext.getSessionManager().getWrappedThis(), castContext.getDiscoveryManager().getWrappedThis());\n        if (delegate != null) {\n            try {\n                delegate.onCreate();\n            } catch (RemoteException e) {\n                // Ignore\n            }\n        }\n        super.onCreate();\n    }\n\n    @Override\n    public int onStartCommand(Intent intent, int flags, int startId) {\n        if (delegate != null) {\n            try {\n                delegate.onStartCommand(intent, flags, startId);\n            } catch (RemoteException e) {\n                // Ignore\n            }\n        }\n        return super.onStartCommand(intent, flags, startId);\n    }\n\n    @Nullable\n    @Override\n    public IBinder onBind(Intent intent) {\n        if (delegate != null) {\n            try {\n                return delegate.onBind(intent);\n            } catch (RemoteException e) {\n                // Ignore\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public void onDestroy() {\n        if (delegate != null) {\n            try {\n                delegate.onDestroy();\n            } catch (RemoteException e) {\n                // Ignore\n            }\n        }\n        super.onDestroy();\n    }\n}\n"
  },
  {
    "path": "play-services-cast-framework/src/main/java/com/google/android/gms/cast/framework/Session.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.cast.framework;\n\npublic class Session {\n}\n"
  },
  {
    "path": "play-services-cast-framework/src/main/java/com/google/android/gms/cast/framework/SessionManager.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.cast.framework;\n\nimport android.content.Context;\nimport android.os.RemoteException;\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.dynamic.ObjectWrapper;\n\npublic class SessionManager {\n    private Context context;\n    private ISessionManager delegate;\n\n    SessionManager(Context context, ISessionManager delegate) {\n        this.context = context;\n        this.delegate = delegate;\n    }\n\n    /**\n     * Ends the current session.\n     *\n     * @param stopCasting Should the receiver application be stopped when ending the current Session.\n     * @throws IllegalStateException If this method is not called on the main thread.\n     */\n    public void endCurrentSession(boolean stopCasting) {\n        try {\n            delegate.endCurrentSession(true, stopCasting);\n        } catch (RemoteException e) {\n            // Ignore\n        }\n    }\n\n    /**\n     * Returns the current session if it is an instance of {@link CastSession}, otherwise returns {@code null}.\n     *\n     * @throws IllegalStateException If this method is not called on the main thread.\n     */\n    public CastSession getCurrentCastSession() {\n        Session currentSession = getCurrentSession();\n        if (currentSession instanceof CastSession) {\n            return (CastSession) currentSession;\n        }\n        return null;\n    }\n\n    /**\n     * Returns the currently active session. Returns {@code null} if no session is active.\n     *\n     * @throws IllegalStateException If this method is not called on the main thread.\n     */\n    public Session getCurrentSession() {\n        try {\n            return ObjectWrapper.unwrapTyped(delegate.getWrappedCurrentSession(), Session.class);\n        } catch (RemoteException e) {\n            return null;\n        }\n    }\n\n    IObjectWrapper getWrappedThis() {\n        try {\n            return delegate.getWrappedThis();\n        } catch (RemoteException e) {\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-cast-framework/src/main/java/com/google/android/gms/cast/framework/SessionProvider.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.cast.framework;\n\nimport android.content.Context;\nimport android.os.IBinder;\nimport org.microg.gms.cast.ISessionProviderImpl;\n\n/**\n * An abstract base class for performing session construction. The SDK uses a subclass of {@link SessionProvider} to\n * construct {@link CastSession} internally. If your app wants to support other types of {@link Session} then you should subclass this\n * class. Subclasses must implement {@link #createSession(String)} and {@link #isSessionRecoverable()}, which will be called by\n * the Cast SDK during the lifecycle of the session. All methods must be called from the main thread.\n */\npublic abstract class SessionProvider {\n    private Context context;\n    private String category;\n    private ISessionProvider bindable = new ISessionProviderImpl(this);\n\n    /**\n     * Constructs a {@link SessionProvider} with a category string. The category uniquely identifies a {@link Session} created by this\n     * provider.\n     *\n     * @param applicationContext The application Context of the calling app.\n     * @param category           The category string used to create {@link Session}.\n     */\n    protected SessionProvider(Context applicationContext, String category) {\n        this.context = applicationContext;\n        this.category = category;\n    }\n\n    /**\n     * Constructs a new {@link Session}. This method is called by the SDK to create a new session.\n     */\n    public abstract Session createSession(String sessionId);\n\n    /**\n     * Returns the category string for this {@link SessionProvider}.\n     */\n    public final String getCategory() {\n        return category;\n    }\n\n    /**\n     * Returns the application {@link Context} used to construct this instance.\n     */\n    public final Context getContext() {\n        return context;\n    }\n\n    /**\n     * Returns {@code true} if a previously constructed session can be resumed. Subclasses should check any persisted information\n     * about the previous session, such as a session ID, and return true only if it is possible to resume that session. This\n     * method is called by the SDK when it tries to resume a previously saved session.\n     */\n    public abstract boolean isSessionRecoverable();\n\n    public IBinder asBinder() {\n        return bindable.asBinder();\n    }\n}\n"
  },
  {
    "path": "play-services-cast-framework/src/main/java/com/google/android/gms/cast/framework/media/CastMediaOptions.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.cast.framework.media;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class CastMediaOptions extends AutoSafeParcelable {\n\n    @Field(1)\n    private int versionCode = 1;\n    @Field(2)\n    public String mediaIntentReceiverClassName;\n    @Field(3)\n    public String expandedControllerActivityClassName;\n    @Field(4)\n    public IImagePicker imagePicker;\n    @Field(5)\n    public NotificationOptions notificationOptions;\n    @Field(6)\n    public boolean bool6;\n    @Field(7)\n    public boolean bool7;\n\n    public static Creator<CastMediaOptions> CREATOR = new AutoCreator<CastMediaOptions>(CastMediaOptions.class);\n}\n"
  },
  {
    "path": "play-services-cast-framework/src/main/java/com/google/android/gms/cast/framework/media/MediaIntentReceiver.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.cast.framework.media;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.view.KeyEvent;\nimport com.google.android.gms.cast.framework.CastContext;\nimport com.google.android.gms.cast.framework.CastSession;\nimport com.google.android.gms.cast.framework.Session;\nimport com.google.android.gms.cast.framework.SessionManager;\n\npublic class MediaIntentReceiver extends BroadcastReceiver {\n    /**\n     * The action for ending the current session and disconnecting from the receiver app.\n     */\n    public static final String ACTION_DISCONNECT = \"com.google.android.gms.cast.framework.action.DISCONNECT\";\n    /**\n     * The action for forwarding the current item. When building an Intent with this action, use {@link #EXTRA_SKIP_STEP_MS} to set the\n     * time to forward in milliseconds.\n     */\n    public static final String ACTION_FORWARD = \"com.google.android.gms.cast.framework.action.FORWARD\";\n    /**\n     * The action for rewinding the current item. When building an Intent with this action, use {@link #EXTRA_SKIP_STEP_MS} to set the\n     * time to rewind in milliseconds.\n     */\n    public static final String ACTION_REWIND = \"com.google.android.gms.cast.framework.action.REWIND\";\n    /**\n     * The action for skipping to the next item in the queue.\n     */\n    public static final String ACTION_SKIP_NEXT = \"com.google.android.gms.cast.framework.action.SKIP_NEXT\";\n    /**\n     * The action for skipping to the previous item in the queue.\n     */\n    public static final String ACTION_SKIP_PREV = \"com.google.android.gms.cast.framework.action.SKIP_PREV\";\n    /**\n     * The action for ending the current session and stopping the receiver app.\n     */\n    public static final String ACTION_STOP_CASTING = \"com.google.android.gms.cast.framework.action.STOP_CASTING\";\n    /**\n     * The action for toggling remote media playback.\n     */\n    public static final String ACTION_TOGGLE_PLAYBACK = \"com.google.android.gms.cast.framework.action.TOGGLE_PLAYBACK\";\n    /**\n     * The extra key for specifying how much the currently playing item should be forwarded or rewinded to handle\n     * {@link #ACTION_FORWARD} and {@link #ACTION_REWIND}.\n     */\n    public static final String EXTRA_SKIP_STEP_MS = \"googlecast-extra_skip_step_ms\";\n\n    @Override\n    public void onReceive(Context context, Intent intent) {\n        SessionManager sessionManager = CastContext.getSharedInstance(context).getSessionManager();\n        Session currentSession = sessionManager.getCurrentSession();\n        if (intent.getAction() != null && currentSession != null) {\n            switch (intent.getAction()) {\n                case ACTION_TOGGLE_PLAYBACK:\n                    onReceiveActionTogglePlayback(currentSession);\n                    break;\n                case ACTION_SKIP_NEXT:\n                    onReceiveActionSkipNext(currentSession);\n                    break;\n                case ACTION_SKIP_PREV:\n                    onReceiveActionSkipPrev(currentSession);\n                    break;\n                case ACTION_FORWARD:\n                    onReceiveActionForward(currentSession, intent.getLongExtra(EXTRA_SKIP_STEP_MS, 0));\n                    break;\n                case ACTION_REWIND:\n                    onReceiveActionRewind(currentSession, intent.getLongExtra(EXTRA_SKIP_STEP_MS, 0));\n                    break;\n                case ACTION_STOP_CASTING:\n                    sessionManager.endCurrentSession(true);\n                    break;\n                case ACTION_DISCONNECT:\n                    sessionManager.endCurrentSession(false);\n                    break;\n                case Intent.ACTION_MEDIA_BUTTON:\n                    onReceiveActionMediaButton(currentSession, intent);\n                    break;\n                default:\n                    onReceiveOtherAction(context, intent.getAction(), intent);\n                    break;\n            }\n        }\n    }\n\n    /**\n     * Called when {@link #ACTION_FORWARD} is received. The default implementation forwards the current playing item by\n     * {@code forwardStepMs} if {@code currentSession} is a {@link CastSession}. Subclasses can override this method to change the behavior\n     * or handle other type of {@link Session}. Subclasses should call through to super to let the SDK handle the action if\n     * {@code currentSession} is a {@link CastSession}\n     *\n     * @param currentSession The current {@link Session}.\n     * @param forwardStepMs  Time to forward in milliseconds.\n     */\n    protected void onReceiveActionForward(Session currentSession, long forwardStepMs) {\n        if (!(currentSession instanceof CastSession)) return;\n        // TODO Seek forwardStepMs\n    }\n\n    /**\n     * Called when {@link Intent#ACTION_MEDIA_BUTTON} is received. The default implementation toggles playback state if\n     * {@code currentSession} is a {@link CastSession}. Subclasses can override this method to change the behavior or handle other type\n     * of {@link Session}. Subclasses should call through to super to let the SDK handle the action if {@code currentSession} is a\n     * {@link CastSession}\n     *\n     * @param currentSession The current {@link Session}.\n     * @param intent         The Intent of this action.\n     */\n    protected void onReceiveActionMediaButton(Session currentSession, Intent intent) {\n        if (!(currentSession instanceof CastSession)) return;\n        if (intent.hasExtra(Intent.EXTRA_KEY_EVENT)) {\n            KeyEvent keyEvent = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);\n            if (keyEvent.getAction() == KeyEvent.ACTION_DOWN && keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) {\n                // TODO Toggle Playback\n            }\n        }\n    }\n\n    /**\n     * Called when {@link #ACTION_REWIND} is received. The default implementation forwards the current playing item by\n     * {@code rewindStepMs} if {@code currentSession} is a {@link CastSession}. Subclasses can override this method to change the behavior or\n     * handle other type of {@link Session}. Subclasses should call through to super to let the SDK handle the action if\n     * {@code currentSession} is a {@link CastSession}\n     *\n     * @param currentSession The current {@link Session}.\n     * @param rewindStepMs   Time to rewind in milliseconds.\n     */\n    protected void onReceiveActionRewind(Session currentSession, long rewindStepMs) {\n        if (!(currentSession instanceof CastSession)) return;\n        // TODO Seek -rewindStepMs\n    }\n\n    /**\n     * Called when {@link #ACTION_SKIP_NEXT} is received. The default implementation plays the next item in the queue if\n     * {@code currentSession} is a {@link CastSession} and there is a next item. Subclasses can override this method to change the\n     * behavior or handle other type of {@link Session}. Subclasses should call through to super to let the SDK handle the action if\n     * {@code currentSession} is a {@link CastSession}\n     *\n     * @param currentSession The current {@link Session}.\n     */\n    protected void onReceiveActionSkipNext(Session currentSession) {\n        if (!(currentSession instanceof CastSession)) return;\n        // TODO Queue next\n    }\n\n    /**\n     * Called when {@link #ACTION_SKIP_PREV} is received. The default implementation plays the previous item in the queue if\n     * {@code currentSession} is a {@link CastSession} and there is a previous item. Subclasses can override this method to change the\n     * behavior or handle other type of {@link Session}. Subclasses should call through to super to let the SDK handle the action if\n     * {@code currentSession} is a {@link CastSession}\n     *\n     * @param currentSession The current {@link Session}.\n     */\n    protected void onReceiveActionSkipPrev(Session currentSession) {\n        if (!(currentSession instanceof CastSession)) return;\n        // TODO Queue prev\n    }\n\n    /**\n     * Called when {@link #ACTION_TOGGLE_PLAYBACK} is received. The default implementation toggles playback state if\n     * {@code currentSession} is a {@link CastSession}. Subclasses can override this method to change the\n     * behavior or handle other type of {@link Session}. Subclasses should call through to super to let the SDK handle the action if\n     * {@code currentSession} is a {@link CastSession}\n     *\n     * @param currentSession The current {@link Session}.\n     */\n    protected void onReceiveActionTogglePlayback(Session currentSession) {\n        if (!(currentSession instanceof CastSession)) return;\n        // TODO Toggle Playback\n    }\n\n    /**\n     * @deprecated Override {@link #onReceiveOtherAction(Context, String, Intent)} instead.\n     */\n    @Deprecated\n    protected void onReceiveOtherAction(String action, Intent intent) {\n        onReceiveOtherAction(null, action, intent);\n    }\n\n    /**\n     * Called when other type of actions are received. The default implementation does nothing.\n     *\n     * @param context The Context in which the receiver is running.\n     * @param action  The action.\n     * @param intent  The Intent of this action.\n     */\n    protected void onReceiveOtherAction(Context context, String action, Intent intent) {\n\n    }\n}\n"
  },
  {
    "path": "play-services-cast-framework/src/main/java/com/google/android/gms/cast/framework/media/MediaNotificationService.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.cast.framework.media;\n\nimport android.app.Service;\nimport android.content.Intent;\nimport android.os.IBinder;\nimport androidx.annotation.Nullable;\n\npublic class MediaNotificationService extends Service {\n    @Nullable\n    @Override\n    public IBinder onBind(Intent intent) {\n        return null;\n    }\n}\n"
  },
  {
    "path": "play-services-cast-framework/src/main/java/com/google/android/gms/cast/framework/media/NotificationOptions.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2018 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.cast.framework.media;\n\nimport java.util.List;\n\nimport android.app.Activity;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n/**\n * Configuration parameters for building the media notification. The {@link NotificationOptions.Builder} is used to create an\n * instance of {@link NotificationOptions}, and so contains the corresponding setter methods.\n */\npublic class NotificationOptions extends AutoSafeParcelable {\n    /**\n     * Constant for notification skip step, ten seconds in milliseconds.\n     */\n    public static final long SKIP_STEP_TEN_SECONDS_IN_MS = 10000;\n    /**\n     * Constant for notification skip step, thirty seconds in milliseconds.\n     */\n    public static final long SKIP_STEP_THIRTY_SECONDS_IN_MS = 30000;\n\n    @Field(1)\n    private int versionCode = 1;\n    @Field(2)\n    private List<String> actions;\n    @Field(3)\n    private int[] compatActionIndices;\n    @Field(4)\n    private long skipStepMs;\n    @Field(5)\n    private String targetActivityClassName;\n    @Field(6)\n    private int getSmallIconDrawableResId;\n    @Field(7)\n    private int getStopLiveStreamDrawableResId;\n    @Field(8)\n    private int getPauseDrawableResId;\n    @Field(9)\n    private int getPlayDrawableResId;\n    @Field(10)\n    private int getSkipNextDrawableResId;\n    @Field(11)\n    private int getSkipPrevDrawableResId;\n    @Field(12)\n    private int getForwardDrawableResId;\n    @Field(13)\n    private int getForward10DrawableResId;\n    @Field(14)\n    private int getForward30DrawableResId;\n    @Field(15)\n    private int getRewindDrawableResId;\n    @Field(16)\n    private int getRewind10DrawableResId;\n    @Field(17)\n    private int getRewind30DrawableResId;\n    @Field(18)\n    private int getDisconnectDrawableResId;\n    @Field(19)\n    private int imageSizeDimenResId;\n    @Field(20)\n    private int getCastingToDeviceStringResId;\n    @Field(21)\n    private int getStopLiveStreamTitleResId;\n    @Field(22)\n    private int pauseTitleResId;\n    @Field(23)\n    private int playTitleResId;\n    @Field(24)\n    private int skipNextTitleResId;\n    @Field(25)\n    private int skipPrevTitleResId;\n    @Field(26)\n    private int forwardTitleResId;\n    @Field(27)\n    private int forward10TitleResId;\n    @Field(28)\n    private int forward30TitleResId;\n    @Field(29)\n    private int rewindTitleResId;\n    @Field(30)\n    private int rewind10TitleResId;\n    @Field(31)\n    private int rewind30TitleResId;\n    @Field(32)\n    private int disconnectTitleResId;\n    @Field(33)\n    private INotificationActionsProvider notificationActionsProvider;\n    @Field(34)\n    private boolean skipToPrevSlotReserved;\n    @Field(35)\n    private boolean skipToNextSlotReserved;\n\n    /**\n     * Returns the list of actions to show in the notification.\n     */\n    public List<String> getActions() {\n        return actions;\n    }\n\n    /**\n     * Returns the amount to jump if {@link MediaIntentReceiver#ACTION_FORWARD} or {@link MediaIntentReceiver#ACTION_REWIND}\n     * are included in the notification actions. Any tap on those actions will result in moving the media position forward or\n     * backward by {@code skipStepMs} milliseconds. The default value is {@link #SKIP_STEP_TEN_SECONDS_IN_MS}.\n     */\n    public long getSkipStepMs() {\n        return skipStepMs;\n    }\n\n    /**\n     * Returns the name of the {@link Activity} that will be launched when user taps on the content area of the notification.\n     */\n    public String getTargetActivityClassName() {\n        return targetActivityClassName;\n    }\n\n    public static Creator<NotificationOptions> CREATOR = new AutoCreator<NotificationOptions>(NotificationOptions.class);\n}\n"
  },
  {
    "path": "play-services-cast-framework/src/main/java/org/microg/gms/cast/CastDynamiteModule.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.cast;\n\nimport android.app.Service;\nimport android.content.Context;\nimport android.os.IBinder;\nimport android.os.RemoteException;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.cast.framework.CastOptions;\nimport com.google.android.gms.cast.framework.ICastContext;\nimport com.google.android.gms.cast.framework.IReconnectionService;\nimport com.google.android.gms.cast.framework.ModuleUnavailableException;\nimport com.google.android.gms.cast.framework.internal.ICastDynamiteModule;\nimport com.google.android.gms.cast.framework.internal.IMediaRouter;\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.dynamic.ObjectWrapper;\nimport com.google.android.gms.dynamite.DynamiteModule;\n\nimport java.util.Map;\n\npublic class CastDynamiteModule {\n    public static ICastContext newCastContext(Context context, CastOptions castOptions, IMediaRouter mediaRouter, Map<String, IBinder> sessionProviderMap) throws ModuleUnavailableException, RemoteException {\n        return getInterface(context).newCastContextImpl(ObjectWrapper.wrap(context), castOptions, mediaRouter, sessionProviderMap);\n    }\n\n    public static IReconnectionService newReconnectionService(Service service, IObjectWrapper sessionManager, IObjectWrapper discoveryManager) {\n        try {\n            return getInterface(service.getApplicationContext()).newReconnectionServiceImpl(ObjectWrapper.wrap(service), sessionManager, discoveryManager);\n        } catch (RemoteException | ModuleUnavailableException e) {\n            return null;\n        }\n    }\n\n    @NonNull\n    private static ICastDynamiteModule getInterface(Context context) throws ModuleUnavailableException {\n        try {\n            IBinder binder = DynamiteModule.load(context, DynamiteModule.PREFER_REMOTE, \"com.google.android.gms.cast.framework.dynamite\").instantiate(\"com.google.android.gms.cast.framework.internal.CastDynamiteModuleImpl\");\n            return ICastDynamiteModule.Stub.asInterface(binder);\n        } catch (DynamiteModule.LoadingException e) {\n            throw new ModuleUnavailableException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-cast-framework/src/main/java/org/microg/gms/cast/CastSessionProvider.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.cast;\n\nimport android.content.Context;\nimport com.google.android.gms.cast.CastMediaControlIntent;\nimport com.google.android.gms.cast.framework.CastOptions;\nimport com.google.android.gms.cast.framework.Session;\nimport com.google.android.gms.cast.framework.SessionProvider;\n\npublic class CastSessionProvider extends SessionProvider {\n    private CastOptions castOptions;\n\n    public CastSessionProvider(Context applicationContext, CastOptions castOptions) {\n        super(applicationContext, castOptions.getSupportedNamespaces().isEmpty() ? CastMediaControlIntent.categoryForCast(castOptions.getReceiverApplicationId()) : CastMediaControlIntent.categoryForCast(castOptions.getReceiverApplicationId(), castOptions.getSupportedNamespaces()));\n        this.castOptions = castOptions;\n    }\n\n    @Override\n    public Session createSession(String sessionId) {\n        return null;\n    }\n\n    @Override\n    public boolean isSessionRecoverable() {\n        return false;\n    }\n}\n"
  },
  {
    "path": "play-services-cast-framework/src/main/java/org/microg/gms/cast/ISessionProviderImpl.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.cast;\n\nimport android.os.RemoteException;\nimport com.google.android.gms.cast.framework.ISessionProvider;\nimport com.google.android.gms.cast.framework.SessionProvider;\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.dynamic.ObjectWrapper;\nimport org.microg.gms.common.Constants;\n\npublic class ISessionProviderImpl extends ISessionProvider.Stub {\n    private SessionProvider delegate;\n\n    public ISessionProviderImpl(SessionProvider delegate) {\n        this.delegate = delegate;\n    }\n\n    @Override\n    public IObjectWrapper getSession(String sessionId) throws RemoteException {\n        return ObjectWrapper.wrap(delegate.createSession(sessionId));\n    }\n\n    @Override\n    public boolean isSessionRecoverable() throws RemoteException {\n        return delegate.isSessionRecoverable();\n    }\n\n    @Override\n    public String getCategory() throws RemoteException {\n        return delegate.getCategory();\n    }\n\n    @Override\n    public int getSupportedVersion() throws RemoteException {\n        return Constants.GMS_VERSION_CODE;\n    }\n}\n"
  },
  {
    "path": "play-services-chimera-core/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'kotlin-android'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\ndependencies {\n    api project(':play-services-basement')\n    api \"androidx.lifecycle:lifecycle-service:$lifecycleVersion\"\n\n    implementation \"androidx.annotation:annotation:$annotationVersion\"\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion\"\n}\n\nandroid {\n    namespace \"org.microg.gms.chimera.core\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    sourceSets {\n        main.java.srcDirs += 'src/main/kotlin'\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n\n    kotlinOptions {\n        jvmTarget = 1.8\n    }\n}\n\napply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG chimera implementation'\n"
  },
  {
    "path": "play-services-chimera-core/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2021, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <application />\n</manifest>\n"
  },
  {
    "path": "play-services-chimera-core/src/main/java/com/google/android/chimera/InstanceProvider.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.chimera;\n\npublic interface InstanceProvider {\n    Object getChimeraImpl();\n}\n"
  },
  {
    "path": "play-services-chimera-core/src/main/java/com/google/android/chimera/IntentService.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.chimera;\n\nimport android.content.Intent;\nimport android.os.Handler;\nimport android.os.HandlerThread;\nimport android.os.IBinder;\nimport android.os.Looper;\nimport android.os.Message;\n\npublic abstract class IntentService extends Service {\n    private Looper serviceLooper;\n    private ServiceHandler serviceHandler;\n    private String name;\n    private boolean redelivery;\n\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            onHandleIntent((Intent)msg.obj);\n            stopSelf(msg.arg1);\n        }\n    }\n\n    public IntentService(String name) {\n        this.name = name;\n    }\n\n    /**\n     * Sets intent redelivery preferences.  Usually called from the constructor\n     * with your preferred semantics.\n     *\n     * <p>If enabled is true,\n     * {@link #onStartCommand(Intent, int, int)} will return\n     * {@link Service#START_REDELIVER_INTENT}, so if this process dies before\n     * {@link #onHandleIntent(Intent)} returns, the process will be restarted\n     * and the intent redelivered.  If multiple Intents have been sent, only\n     * the most recent one is guaranteed to be redelivered.\n     *\n     * <p>If enabled is false (the default),\n     * {@link #onStartCommand(Intent, int, int)} will return\n     * {@link Service#START_NOT_STICKY}, and if the process dies, the Intent\n     * dies along with it.\n     */\n    public void setIntentRedelivery(boolean redelivery) {\n        this.redelivery = redelivery;\n    }\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n        HandlerThread thread = new HandlerThread(\"IntentService[\" + name + \"]\");\n        thread.start();\n        serviceLooper = thread.getLooper();\n        serviceHandler = new ServiceHandler(serviceLooper);\n    }\n\n    @Override\n    public void onStart(Intent intent, int startId) {\n        Message msg = this.serviceHandler.obtainMessage();\n        msg.arg1 = startId;\n        msg.obj = intent;\n        this.serviceHandler.sendMessage(msg);\n    }\n\n    /**\n     * You should not override this method for your IntentService. Instead,\n     * override {@link #onHandleIntent}, which the system calls when the IntentService\n     * receives a start request.\n     * @see Service#onStartCommand\n     */\n    @Override\n    public int onStartCommand(Intent intent, int flags, int startId) {\n        onStart(intent, startId);\n        return redelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;\n    }\n\n    @Override\n    public void onDestroy() {\n        serviceLooper.quit();\n    }\n\n    /**\n     * Unless you provide binding for your service, you don't need to implement this\n     * method, because the default implementation returns null.\n     * @see Service#onBind\n     */\n    @Override\n    public IBinder onBind(Intent intent) {\n        return null;\n    }\n\n    /**\n     * This method is invoked on the worker thread with a request to process.\n     * Only one Intent is processed at a time, but the processing happens on a\n     * worker thread that runs independently from other application logic.\n     * So, if this code takes a long time, it will hold up other requests to\n     * the same IntentService, but it will not hold up anything else.\n     * When all requests have been handled, the IntentService stops itself,\n     * so you should not call {@link #stopSelf}.\n     *\n     * @param intent The value passed to {@link\n     *               android.content.Context#startService(Intent)}.\n     *               This may be null if the service is being restarted after\n     *               its process has gone away; see\n     *               {@link Service#onStartCommand}\n     *               for details.\n     */\n    public abstract void onHandleIntent(Intent intent);\n}\n"
  },
  {
    "path": "play-services-chimera-core/src/main/java/com/google/android/chimera/Service.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.chimera;\n\nimport android.app.Application;\nimport android.app.Notification;\nimport android.content.Context;\nimport android.content.ContextWrapper;\nimport android.content.Intent;\nimport android.content.res.Configuration;\nimport android.os.IBinder;\n\nimport java.io.FileDescriptor;\nimport java.io.PrintWriter;\n\npublic abstract class Service extends ContextWrapper implements InstanceProvider {\n    public static final int START_CONTINUATION_MASK = 0xf;\n    public static final int START_FLAG_REDELIVERY = 1;\n    public static final int START_FLAG_RETRY = 2;\n    public static final int START_NOT_STICKY = 2;\n    public static final int START_REDELIVER_INTENT = 3;\n    public static final int START_STICKY = 1;\n    public static final int START_STICKY_COMPATIBILITY = 0;\n\n    private android.app.Service containerService;\n    private ProxyCallbacks callbacks;\n\n    public interface ProxyCallbacks {\n        void superOnCreate();\n\n        void superOnDestroy();\n\n        int superOnStartCommand(Intent intent, int flags, int startId);\n\n        void superStopSelf();\n\n        void superStopSelf(int startId);\n\n        boolean superStopSelfResult(int startId);\n    }\n\n    public Service() {\n        super(null);\n    }\n\n    protected void dump(FileDescriptor fs, PrintWriter writer, String[] args) {\n    }\n\n    public final Application getApplication() {\n        return containerService.getApplication();\n    }\n\n    @Override\n    public Object getChimeraImpl() {\n        return this;\n    }\n\n    public android.app.Service getContainerService() {\n        return containerService;\n    }\n\n    public abstract IBinder onBind(Intent intent);\n\n\n    public void onConfigurationChanged(Configuration configuration) {\n    }\n\n    public void onCreate() {\n        this.callbacks.superOnCreate();\n    }\n\n    public void onDestroy() {\n        this.callbacks.superOnDestroy();\n    }\n\n    public void onLowMemory() {\n    }\n\n    public void onRebind(Intent intent) {\n    }\n\n    public void onStart(Intent intent, int startId) {\n    }\n\n    public int onStartCommand(Intent intent, int flags, int startId) {\n        return this.callbacks.superOnStartCommand(intent, flags, startId);\n    }\n\n    public void onTaskRemoved(Intent rootIntent) {\n    }\n\n    public void onTrimMemory(int level) {\n    }\n\n    public boolean onUnbind(Intent intent) {\n        return false;\n    }\n\n    public void publicDump(FileDescriptor fd, PrintWriter writer, String[] args) {\n        dump(fd, writer, args);\n    }\n\n    public void setProxy(android.app.Service service, Context context) {\n        this.containerService = service;\n        this.callbacks = (ProxyCallbacks) service;\n        attachBaseContext(context);\n    }\n\n    public final void startForeground(int id, Notification notification) {\n        this.containerService.startForeground(id, notification);\n    }\n\n    public final void stopForeground(boolean removeNotification) {\n        this.containerService.stopForeground(removeNotification);\n    }\n\n    public final void stopSelf() {\n        this.callbacks.superStopSelf();\n    }\n\n    public final boolean stopSelfResult(int startId) {\n        return this.callbacks.superStopSelfResult(startId);\n    }\n\n    public final void stopSelf(int startId) {\n        this.callbacks.superStopSelf(startId);\n    }\n}\n"
  },
  {
    "path": "play-services-chimera-core/src/main/kotlin/org/microg/gms/chimera/ServiceLoader.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.chimera\n\nimport android.content.Context\nimport com.google.android.chimera.Service\n\ninterface ServiceLoader {\n    fun loadService(context: Context): Service\n\n    companion object {\n        inline fun <reified T : Service> static() = StaticServiceLoader(T::class.java)\n    }\n}\n\n"
  },
  {
    "path": "play-services-chimera-core/src/main/kotlin/org/microg/gms/chimera/ServiceProxy.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage org.microg.gms.chimera\n\nimport android.content.Context\nimport android.content.Intent\nimport android.content.res.Configuration\nimport com.google.android.chimera.Service.ProxyCallbacks\nimport android.os.IBinder\nimport com.google.android.chimera.Service\nimport java.io.FileDescriptor\nimport java.io.PrintWriter\n\nabstract class ServiceProxy(private val loader: ServiceLoader) : android.app.Service(), ProxyCallbacks {\n    private var actualService: Service? = null\n    override fun attachBaseContext(base: Context) {\n        super.attachBaseContext(base)\n\n        if (actualService == null) {\n            val service = loader.loadService(base)\n            actualService = service\n            service.setProxy(this, this)\n        }\n    }\n\n    override fun dump(fs: FileDescriptor, writer: PrintWriter, args: Array<String>) {\n        if (actualService != null) {\n            actualService!!.publicDump(fs, writer, args)\n        }\n    }\n\n    override fun onBind(intent: Intent): IBinder? {\n        return if (actualService != null) {\n            actualService!!.onBind(intent)\n        } else null\n    }\n\n    override fun onConfigurationChanged(newConfig: Configuration) {\n        if (actualService != null) {\n            actualService!!.onConfigurationChanged(newConfig)\n        }\n    }\n\n    override fun onCreate() {\n        if (actualService != null) {\n            actualService!!.onCreate()\n        }\n    }\n\n    override fun onDestroy() {\n        if (actualService != null) {\n            actualService!!.onDestroy()\n        }\n    }\n\n    override fun onLowMemory() {\n        if (actualService != null) {\n            actualService!!.onLowMemory()\n        }\n    }\n\n    override fun onRebind(intent: Intent?) {\n        if (actualService != null) {\n            intent?.setExtrasClassLoader(actualService!!.classLoader)\n            actualService!!.onRebind(intent)\n        }\n    }\n\n    override fun onStart(intent: Intent?, startId: Int) {\n        if (actualService != null) {\n            intent?.setExtrasClassLoader(actualService!!.classLoader)\n            actualService!!.onStart(intent, startId)\n        } else {\n            stopSelf(startId)\n        }\n    }\n\n    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {\n        return if (actualService != null) {\n            intent?.setExtrasClassLoader(actualService!!.classLoader)\n            actualService!!.onStartCommand(intent, flags, startId)\n        } else {\n            super.onStartCommand(intent, flags, startId)\n        }\n    }\n\n    override fun onTaskRemoved(rootIntent: Intent?) {\n        if (actualService != null) {\n            rootIntent?.setExtrasClassLoader(actualService!!.classLoader)\n            actualService!!.onTaskRemoved(rootIntent)\n        }\n    }\n\n    override fun onTrimMemory(level: Int) {\n        if (actualService != null) {\n            actualService!!.onTrimMemory(level)\n        }\n    }\n\n    override fun onUnbind(intent: Intent?): Boolean {\n        return if (actualService != null) {\n            intent?.setExtrasClassLoader(actualService!!.classLoader)\n            actualService!!.onUnbind(intent)\n        } else {\n            false\n        }\n    }\n\n    override fun superOnCreate() {\n        super.onCreate()\n    }\n\n    override fun superOnDestroy() {\n        super.onDestroy()\n    }\n\n    override fun superOnStartCommand(intent: Intent, flags: Int, startId: Int): Int {\n        return super.onStartCommand(intent, flags, startId)\n    }\n\n    override fun superStopSelf() {\n        super.stopSelf()\n    }\n\n    override fun superStopSelf(startId: Int) {\n        super.stopSelf(startId)\n    }\n\n    override fun superStopSelfResult(startId: Int): Boolean {\n        return super.stopSelfResult(startId)\n    }\n}\n"
  },
  {
    "path": "play-services-chimera-core/src/main/kotlin/org/microg/gms/chimera/StaticServiceLoader.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.chimera\n\nimport android.content.Context\nimport com.google.android.chimera.Service\n\nclass StaticServiceLoader<T : Service>(private val serviceClass: Class<T>) : ServiceLoader {\n    override fun loadService(context: Context): Service {\n        return serviceClass.getDeclaredConstructor().newInstance()\n    }\n}\n"
  },
  {
    "path": "play-services-clearcut/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\nandroid {\n    namespace \"com.google.android.gms.clearcut\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n}\n\napply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG implementation of play-services-clearcut'\n\ndependencies {\n    // Dependencies from play-services-clearcut:17.0.0\n    api \"androidx.core:core:1.0.0\"\n    api project(':play-services-base')\n    api project(':play-services-basement')\n    api project(':play-services-phenotype')\n    api project(':play-services-tasks')\n}\n"
  },
  {
    "path": "play-services-clearcut/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest />"
  },
  {
    "path": "play-services-clearcut/src/main/aidl/com/google/android/gms/clearcut/LogEventParcelable.aidl",
    "content": "package com.google.android.gms.clearcut;\n\nparcelable LogEventParcelable;\n"
  },
  {
    "path": "play-services-clearcut/src/main/aidl/com/google/android/gms/clearcut/internal/IClearcutLoggerCallbacks.aidl",
    "content": "package com.google.android.gms.clearcut.internal;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.common.data.DataHolder;\n\ninterface IClearcutLoggerCallbacks {\n    oneway void onLogResult(in Status status) = 0;\n    oneway void onForceUploadResult(in Status status) = 1;\n    oneway void onStartCollectForDebugResult(in Status status, long l) = 2;\n    oneway void onStopCollectForDebugResult(in Status status) = 3;\n    oneway void onCollectForDebugExpiryTime(in Status status, long l) = 4;\n    oneway void onLogEventParcelables(in DataHolder data) = 6;\n}\n"
  },
  {
    "path": "play-services-clearcut/src/main/aidl/com/google/android/gms/clearcut/internal/IClearcutLoggerService.aidl",
    "content": "package com.google.android.gms.clearcut.internal;\n\nimport com.google.android.gms.clearcut.internal.IClearcutLoggerCallbacks;\nimport com.google.android.gms.clearcut.LogEventParcelable;\n\ninterface IClearcutLoggerService {\n    oneway void log(IClearcutLoggerCallbacks callbacks, in LogEventParcelable event) = 0;\n    oneway void forceUpload(IClearcutLoggerCallbacks callbacks) = 1;\n    oneway void startCollectForDebug(IClearcutLoggerCallbacks callbacks) = 2;\n    oneway void stopCollectForDebug(IClearcutLoggerCallbacks callbacks) = 3;\n    oneway void getCollectForDebugExpiryTime(IClearcutLoggerCallbacks callbacks) = 4;\n    oneway void getLogEventParcelablesLegacy(IClearcutLoggerCallbacks callbacks) = 5;\n    oneway void getLogEventParcelables(IClearcutLoggerCallbacks callbacks) = 6;\n}\n"
  },
  {
    "path": "play-services-clearcut/src/main/aidl/com/google/android/gms/clearcut/internal/PlayLoggerContext.aidl",
    "content": "package com.google.android.gms.clearcut.internal;\n\nparcelable PlayLoggerContext;\n"
  },
  {
    "path": "play-services-clearcut/src/main/aidl/com/google/android/gms/playlog/internal/IPlayLogService.aidl",
    "content": "package com.google.android.gms.playlog.internal;\n\nimport com.google.android.gms.clearcut.internal.PlayLoggerContext;\nimport com.google.android.gms.playlog.internal.LogEvent;\n\n// Deprecated\ninterface IPlayLogService {\n    void onEvent(String packageName, in PlayLoggerContext context, in LogEvent event) = 1;\n    void onMultiEvent(String packageName, in PlayLoggerContext context, in List<LogEvent> events) = 2;\n}\n"
  },
  {
    "path": "play-services-clearcut/src/main/aidl/com/google/android/gms/playlog/internal/LogEvent.aidl",
    "content": "package com.google.android.gms.playlog.internal;\n\nparcelable LogEvent;\n"
  },
  {
    "path": "play-services-clearcut/src/main/java/com/google/android/gms/clearcut/LogEventParcelable.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.clearcut;\n\nimport android.util.Base64;\n\nimport com.google.android.gms.clearcut.internal.LogVerifierResultParcelable;\nimport com.google.android.gms.phenotype.ExperimentTokens;\nimport com.google.android.gms.phenotype.GenericDimension;\nimport com.google.android.gms.clearcut.internal.PlayLoggerContext;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\nimport java.nio.ByteBuffer;\nimport java.nio.CharBuffer;\nimport java.nio.charset.Charset;\nimport java.nio.charset.CharsetDecoder;\nimport java.util.Arrays;\n\npublic class LogEventParcelable extends AutoSafeParcelable {\n    @Field(1)\n    private int versionCode = 1;\n\n    @Field(2)\n    public final PlayLoggerContext context;\n\n    @Field(3)\n    public final byte[] bytes;\n\n    @Field(4)\n    public final int[] testCodes;\n\n    @Field(5)\n    public final String[] mendelPackages;\n\n    @Field(6)\n    public final int[] experimentIds;\n\n    @Field(7)\n    public final byte[][] experimentTokens;\n\n    @Field(8)\n    public final boolean addPhenotypeExperimentTokens;\n\n    @Field(9)\n    public final ExperimentTokens[] experimentTokenParcelables;\n\n    @Field(10)\n    public final GenericDimension[] genericDimensions;\n\n    @Field(11)\n    public final LogVerifierResultParcelable logVerifierResult;\n\n    @Field(12)\n    private String[] mendelPackagesToFilter;\n\n    @Field(13)\n    public int eventCode;\n\n    private LogEventParcelable() {\n        context = null;\n        bytes = null;\n        testCodes = experimentIds = null;\n        mendelPackages = null;\n        experimentTokens = null;\n        addPhenotypeExperimentTokens = true;\n        experimentTokenParcelables = null;\n        genericDimensions = null;\n        logVerifierResult = null;\n    }\n\n    public LogEventParcelable(PlayLoggerContext context, byte[] bytes, int[] testCodes, String[] mendelPackages, int[] experimentIds, byte[][] experimentTokens, boolean addPhenotypeExperimentTokens) {\n        this.context = context;\n        this.bytes = bytes;\n        this.testCodes = testCodes;\n        this.mendelPackages = mendelPackages;\n        this.experimentIds = experimentIds;\n        this.experimentTokens = experimentTokens;\n        this.addPhenotypeExperimentTokens = addPhenotypeExperimentTokens;\n        this.experimentTokenParcelables = null;\n        this.genericDimensions = null;\n        this.logVerifierResult = null;\n    }\n\n    @Override\n    public String toString() {\n        final StringBuilder sb = new StringBuilder(\"LogEventParcelable[\")\n                .append(versionCode).append(\", \").append(context)\n                .append(\", LogEventBytes: \").append(getBytesAsString());\n        if (testCodes != null) sb.append(\", TestCodes: \").append(Arrays.toString(testCodes));\n        if (mendelPackages != null)\n            sb.append(\", MendelPackages: \").append(Arrays.toString(mendelPackages));\n        if (experimentIds != null)\n            sb.append(\", ExperimentIds: \").append(Arrays.toString(experimentIds));\n        if (experimentTokens != null)\n            sb.append(\", ExperimentTokens: \").append(Arrays.toString(experimentTokens));\n        return sb.append(\", AddPhenotypeExperimentTokens: \").append(addPhenotypeExperimentTokens)\n                .append(']').toString();\n    }\n\n    private String getBytesAsString() {\n        if (bytes == null) return \"null\";\n        try {\n            CharsetDecoder d = Charset.forName(\"US-ASCII\").newDecoder();\n            CharBuffer r = d.decode(ByteBuffer.wrap(bytes));\n            return r.toString();\n        } catch (Exception e) {\n            return Base64.encodeToString(bytes, Base64.NO_WRAP);\n        }\n    }\n\n    public static final Creator<LogEventParcelable> CREATOR = new AutoCreator<LogEventParcelable>(LogEventParcelable.class);\n}\n"
  },
  {
    "path": "play-services-clearcut/src/main/java/com/google/android/gms/clearcut/internal/LogVerifierResultParcelable.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.clearcut.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class LogVerifierResultParcelable  extends AutoSafeParcelable {\n    @Field(1)\n    public boolean b;\n\n    public static final Creator<LogVerifierResultParcelable> CREATOR = new AutoCreator<>(LogVerifierResultParcelable.class);\n}\n"
  },
  {
    "path": "play-services-clearcut/src/main/java/com/google/android/gms/clearcut/internal/PlayLoggerContext.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.clearcut.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class PlayLoggerContext extends AutoSafeParcelable {\n\n    @Field(1)\n    private int versionCode = 1;\n\n    @Field(2)\n    public final String packageName;\n\n    @Field(3)\n    public final int packageVersionCode;\n\n    @Field(4)\n    public final int logSource;\n\n    @Field(5)\n    public final String uploadAccount;\n\n    @Field(6)\n    public final String loggingId;\n\n    @Field(7)\n    public final boolean logAndroidId;\n\n    @Field(8)\n    public final String logSourceName;\n\n    @Field(9)\n    public final boolean isAnonymous;\n\n    @Field(10)\n    public final int qosTier;\n\n    @Field(11)\n    public final Integer appMobileSpecId;\n\n    @Field(12)\n    public final boolean scrubMccMnc;\n\n    @Field(13)\n    public final Integer piiLevelset;\n\n    private PlayLoggerContext() {\n        packageName = uploadAccount = logSourceName = loggingId = null;\n        qosTier = packageVersionCode = logSource = appMobileSpecId = piiLevelset = -1;\n        isAnonymous = logAndroidId = scrubMccMnc = false;\n    }\n\n    public PlayLoggerContext(String packageName, int packageVersionCode, int logSource, String logSourceName, String uploadAccount, String loggingId, boolean isAnonymous,  int qosTier, boolean scrubMccMnc, int piiLevelset) {\n        this.packageName = packageName;\n        this.packageVersionCode = packageVersionCode;\n        this.logSource = logSource;\n        this.logSourceName = logSourceName;\n        this.uploadAccount = uploadAccount;\n        this.loggingId = loggingId;\n        this.logAndroidId = !isAnonymous;\n        this.isAnonymous = isAnonymous;\n        this.qosTier = qosTier;\n        this.appMobileSpecId = null;\n        this.scrubMccMnc = scrubMccMnc;\n        this.piiLevelset = piiLevelset;\n    }\n\n    @Override\n    public String toString() {\n        final StringBuilder sb = new StringBuilder(\"PlayLoggerContext[\").append(versionCode);\n        sb.append(\", package=\").append(packageName);\n        sb.append(\", packageVersionCode=\").append(packageVersionCode);\n        sb.append(\", logSource=\").append(logSource);\n        sb.append(\", uploadAccount=\").append(uploadAccount);\n        sb.append(\", loggingId=\").append(loggingId);\n        sb.append(\", logAndroidId=\").append(logAndroidId);\n        sb.append(\", logSourceName=\").append(logSourceName);\n        sb.append(\", isAnonymous=\").append(isAnonymous);\n        sb.append(\", qosTier=\").append(qosTier);\n        sb.append(\", appMobileSpecId=\").append(appMobileSpecId);\n        sb.append(\", scrubMccMnc=\").append(scrubMccMnc);\n        sb.append(\", piiLevelset=\").append(piiLevelset);\n        sb.append(']');\n        return sb.toString();\n    }\n\n    public static Creator<PlayLoggerContext> CREATOR = new AutoCreator<PlayLoggerContext>(PlayLoggerContext.class);\n}\n"
  },
  {
    "path": "play-services-clearcut/src/main/java/com/google/android/gms/playlog/internal/LogEvent.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.playlog.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\nimport java.util.Date;\n\n@Deprecated\npublic class LogEvent extends AutoSafeParcelable {\n\n    @SafeParceled(1)\n    private int versionCode = 1;\n\n    @SafeParceled(2)\n    public final long eventTime;\n\n    @SafeParceled(3)\n    public final String tag;\n\n    @SafeParceled(4)\n    public final byte[] data;\n\n    private LogEvent() {\n        eventTime = -1;\n        tag = null;\n        data = null;\n    }\n\n    @Override\n    public String toString() {\n        return \"LogEvent{\" +\n                \"eventTime=\" + new Date(eventTime) +\n                \", tag='\" + tag + '\\'' +\n                \", data=\" + (data == null ? \"null\" : ('\\'' + new String(data) + '\\'')) +\n                '}';\n    }\n\n    public static Creator<LogEvent> CREATOR = new AutoCreator<LogEvent>(LogEvent.class);\n}\n"
  },
  {
    "path": "play-services-conscrypt-provider-core/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\n\ndependencies {\n    implementation \"org.microg.gms:conscrypt-gmscore:2.5.2\"\n    implementation \"androidx.annotation:annotation:$annotationVersion\"\n    implementation project(\":play-services-base-core\")\n}\n\nandroid {\n    namespace \"org.microg.gms.core.conscrypt\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n}\n"
  },
  {
    "path": "play-services-conscrypt-provider-core/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest>\n\n    <application />\n</manifest>\n"
  },
  {
    "path": "play-services-conscrypt-provider-core/src/main/java/com/google/android/gms/common/security/ProviderInstallerImpl.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.common.security;\n\nimport android.content.Context;\nimport android.content.pm.ApplicationInfo;\nimport android.os.Process;\nimport android.util.Log;\n\nimport androidx.annotation.Keep;\n\nimport com.google.android.gms.org.conscrypt.Conscrypt;\nimport com.google.android.gms.org.conscrypt.NativeCrypto;\n\nimport org.microg.gms.common.PackageUtils;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.security.Provider;\nimport java.security.Security;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipFile;\n\nimport javax.net.ssl.HttpsURLConnection;\nimport javax.net.ssl.SSLContext;\n\nimport static android.os.Build.VERSION.SDK_INT;\nimport static com.google.android.gms.security.ProviderInstaller.PROVIDER_NAME;\n\n/**\n * This is the old entry point, the new one is at {@link com.google.android.gms.providerinstaller.ProviderInstallerImpl}\n */\n@Keep\npublic class ProviderInstallerImpl {\n    private static final String TAG = \"ProviderInstaller\";\n\n    @Keep\n    public static void insertProvider(Context context) {\n        com.google.android.gms.providerinstaller.ProviderInstallerImpl.insertProvider(context);\n    }\n\n    @Keep\n    public void reportRequestStats(Context context, long elapsedRealtimeBeforeLoad, long elapsedRealtimeAfterLoad) {\n        com.google.android.gms.providerinstaller.ProviderInstallerImpl.reportRequestStats(context, elapsedRealtimeBeforeLoad, elapsedRealtimeAfterLoad);\n    }\n}\n"
  },
  {
    "path": "play-services-conscrypt-provider-core/src/main/java/com/google/android/gms/dynamite/descriptors/com/google/android/gms/providerinstaller/dynamite/ModuleDescriptor.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.dynamite.descriptors.com.google.android.gms.providerinstaller.dynamite;\n\nimport androidx.annotation.Keep;\n\n@Keep\npublic class ModuleDescriptor {\n    public static final String MODULE_ID = \"com.google.android.gms.providerinstaller.dynamite\";\n    public static final int MODULE_VERSION = 1;\n}\n"
  },
  {
    "path": "play-services-conscrypt-provider-core/src/main/java/com/google/android/gms/providerinstaller/ProviderInstallerImpl.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.providerinstaller;\n\nimport android.content.Context;\nimport android.content.pm.ApplicationInfo;\nimport android.os.Process;\nimport android.util.Log;\nimport androidx.annotation.Keep;\nimport com.google.android.gms.org.conscrypt.Conscrypt;\nimport com.google.android.gms.org.conscrypt.NativeCrypto;\nimport org.microg.gms.common.PackageUtils;\n\nimport javax.net.ssl.HttpsURLConnection;\nimport javax.net.ssl.SSLContext;\nimport java.io.*;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.security.Provider;\nimport java.security.Security;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipFile;\n\nimport static android.os.Build.VERSION.SDK_INT;\nimport static com.google.android.gms.security.ProviderInstaller.PROVIDER_NAME;\n\n@Keep\npublic class ProviderInstallerImpl {\n    private static final String TAG = \"ProviderInstaller\";\n    private static final List<String> DISABLED = Collections.unmodifiableList(Arrays.asList(\"com.bankid.bus\"));\n\n    private static final Object lock = new Object();\n    private static Provider provider;\n\n    private static String getRealSelfPackageName(Context context) {\n        String packageName = PackageUtils.packageFromProcessId(context, Process.myPid());\n        if (packageName != null && packageName.contains(\".\")) return packageName;\n        try {\n            Method getBasePackageName = Context.class.getDeclaredMethod(\"getBasePackageName\");\n            packageName = (String) getBasePackageName.invoke(context);\n            if (packageName != null) return packageName;\n        } catch (Exception e) {\n\n        }\n        if (SDK_INT >= 29) {\n            return context.getOpPackageName();\n        }\n        Context applicationContext = context.getApplicationContext();\n        if (applicationContext != null) {\n            return applicationContext.getPackageName();\n        }\n        return context.getPackageName();\n    }\n\n    @Keep\n    public static void insertProvider(Context context) {\n        String packageName = getRealSelfPackageName(context);\n        try {\n            if (DISABLED.contains(packageName)) {\n                Log.d(TAG, \"Package \" + packageName + \" is excluded from usage of provider installer\");\n                return;\n            }\n            if (Security.getProvider(PROVIDER_NAME) != null) {\n                Log.d(TAG, \"Provider already inserted in \" + packageName);\n                return;\n            }\n\n            synchronized (lock) {\n                initProvider(context, packageName);\n\n                if (provider == null) {\n                    Log.w(TAG, \"Failed to initialize Conscrypt\");\n                    return;\n                }\n\n                int res = Security.insertProviderAt(provider, 1);\n                if (res == 1) {\n                    Security.setProperty(\"ssl.SocketFactory.provider\", \"com.google.android.gms.org.conscrypt.OpenSSLSocketFactoryImpl\");\n                    Security.setProperty(\"ssl.ServerSocketFactory.provider\", \"com.google.android.gms.org.conscrypt.OpenSSLServerSocketFactoryImpl\");\n\n                    SSLContext sslContext = SSLContext.getInstance(\"Default\");\n                    SSLContext.setDefault(sslContext);\n                    HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());\n\n                    Log.d(TAG, \"Installed default security provider \" + PROVIDER_NAME);\n                } else {\n                    throw new SecurityException(\"Failed to install security provider \" + PROVIDER_NAME + \", result: \" + res);\n                }\n            }\n        } catch (Throwable e) {\n            Log.w(TAG, e);\n        }\n    }\n\n    @Keep\n    public static void reportRequestStats(Context context, long elapsedRealtimeBeforeLoad, long elapsedRealtimeAfterLoad) {\n        Log.d(TAG, \"reportRequestStats: \" + elapsedRealtimeBeforeLoad + \" \" + elapsedRealtimeAfterLoad);\n        // Ignore stats\n    }\n\n    private static void initProvider(Context context, String packageName) {\n        Log.d(TAG, \"Initializing provider for \" + packageName);\n\n        try {\n            provider = Conscrypt.newProviderBuilder().setName(PROVIDER_NAME).defaultTlsProtocol(\"TLSv1.2\").build();\n        } catch (UnsatisfiedLinkError e) {\n            Log.w(TAG, \"Could not link conscrypt via default loader, trying manual loading\");\n\n            try {\n                loadConscryptDirect(context, packageName);\n                provider = Conscrypt.newProviderBuilder().setName(PROVIDER_NAME).defaultTlsProtocol(\"TLSv1.2\").build();\n            } catch (Exception e2) {\n                Log.w(TAG, e2);\n            }\n        }\n    }\n\n    private static void loadConscryptDirect(Context context, String packageName) throws Exception {\n        ApplicationInfo otherAppInfo = context.getPackageManager().getApplicationInfo(packageName, 0);\n\n        // TODO: Move manual loading into helper function (as it is also used in both maps implementations)\n        String primaryCpuAbi = (String) ApplicationInfo.class.getField(\"primaryCpuAbi\").get(otherAppInfo);\n        if (primaryCpuAbi != null) {\n            String path = \"lib/\" + primaryCpuAbi + \"/libconscrypt_gmscore_jni.so\";\n            File cacheFile = new File(context.createPackageContext(packageName, 0).getCacheDir().getAbsolutePath() + \"/.gmscore/\" + path);\n            cacheFile.getParentFile().mkdirs();\n            File apkFile = new File(context.getPackageCodePath());\n            if (!cacheFile.exists() || cacheFile.lastModified() < apkFile.lastModified()) {\n                ZipFile zipFile = new ZipFile(apkFile);\n                ZipEntry entry = zipFile.getEntry(path);\n                if (entry != null) {\n                    copyInputStream(zipFile.getInputStream(entry), new FileOutputStream(cacheFile));\n                } else {\n                    Log.d(TAG, \"Can't load native library: \" + path + \" does not exist in \" + apkFile);\n                }\n            }\n            Log.d(TAG, \"Loading conscrypt_gmscore_jni from \" + cacheFile.getPath());\n            System.load(cacheFile.getAbsolutePath());\n\n            Class<NativeCrypto> clazz = NativeCrypto.class;\n\n            Field loadError = clazz.getDeclaredField(\"loadError\");\n            loadError.setAccessible(true);\n            loadError.set(null, null);\n\n            Method clinit = clazz.getDeclaredMethod(\"clinit\");\n            clinit.setAccessible(true);\n\n            Method get_cipher_names = clazz.getDeclaredMethod(\"get_cipher_names\", String.class);\n            get_cipher_names.setAccessible(true);\n\n            Method cipherSuiteToJava = clazz.getDeclaredMethod(\"cipherSuiteToJava\", String.class);\n            cipherSuiteToJava.setAccessible(true);\n\n            Method EVP_has_aes_hardware = clazz.getDeclaredMethod(\"EVP_has_aes_hardware\");\n            EVP_has_aes_hardware.setAccessible(true);\n\n            Field f = clazz.getDeclaredField(\"SUPPORTED_TLS_1_2_CIPHER_SUITES_SET\");\n            f.setAccessible(true);\n\n            Set<String> SUPPORTED_TLS_1_2_CIPHER_SUITES_SET = (Set<String>) f.get(null);\n            f = clazz.getDeclaredField(\"SUPPORTED_LEGACY_CIPHER_SUITES_SET\");\n            f.setAccessible(true);\n\n            Set<String> SUPPORTED_LEGACY_CIPHER_SUITES_SET = (Set<String>) f.get(null);\n            f = clazz.getDeclaredField(\"SUPPORTED_TLS_1_2_CIPHER_SUITES\");\n            f.setAccessible(true);\n\n            try {\n                clinit.invoke(null);\n\n                String[] allCipherSuites = (String[]) get_cipher_names.invoke(null, \"ALL:!DHE\");\n                int size = allCipherSuites.length;\n\n                String[] SUPPORTED_TLS_1_2_CIPHER_SUITES = new String[size / 2 + 2];\n                for (int i = 0; i < size; i += 2) {\n                    String cipherSuite = (String) cipherSuiteToJava.invoke(null, allCipherSuites[i]);\n\n                    SUPPORTED_TLS_1_2_CIPHER_SUITES[i / 2] = cipherSuite;\n                    SUPPORTED_TLS_1_2_CIPHER_SUITES_SET.add(cipherSuite);\n\n                    SUPPORTED_LEGACY_CIPHER_SUITES_SET.add(allCipherSuites[i + 1]);\n                }\n                SUPPORTED_TLS_1_2_CIPHER_SUITES[size / 2] = \"TLS_EMPTY_RENEGOTIATION_INFO_SCSV\";\n                SUPPORTED_TLS_1_2_CIPHER_SUITES[size / 2 + 1] = \"TLS_FALLBACK_SCSV\";\n                f.set(null, SUPPORTED_TLS_1_2_CIPHER_SUITES);\n\n                f = clazz.getDeclaredField(\"HAS_AES_HARDWARE\");\n                f.setAccessible(true);\n                f.set(null, (int) EVP_has_aes_hardware.invoke(null) == 1);\n\n            } catch (InvocationTargetException inner) {\n                if (inner.getTargetException() instanceof UnsatisfiedLinkError) {\n                    loadError.set(null, inner.getTargetException());\n                }\n            }\n        }\n    }\n\n    private static final void copyInputStream(InputStream in, OutputStream out) throws IOException {\n        byte[] buffer = new byte[1024];\n        int len;\n\n        while ((len = in.read(buffer)) >= 0)\n            out.write(buffer, 0, len);\n\n        in.close();\n        out.close();\n    }\n}\n"
  },
  {
    "path": "play-services-core/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2013 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.application'\napply plugin: 'kotlin-android'\n\nconfigurations {\n    mapboxRuntimeOnly\n    vtmRuntimeOnly\n    if (hasModule(\"hms\", true)) hmsRuntimeOnly\n    defaultRuntimeOnly\n}\n\ndependencies {\n    implementation \"com.squareup.wire:wire-runtime:$wireVersion\"\n    implementation \"de.hdodenhof:circleimageview:1.3.0\"\n\n    implementation project(':fake-signature')\n    implementation project(':firebase-dynamic-links')\n    implementation project(':firebase-auth-core')\n    implementation project(':play-services-ads-core')\n    implementation project(':play-services-ads-identifier-core')\n    implementation project(':play-services-ads-lite-core')\n    implementation project(':play-services-appinvite-core')\n    implementation project(':play-services-appset-core')\n    implementation project(':play-services-auth-api-phone-core')\n    implementation project(':play-services-auth-blockstore-core')\n    implementation project(':play-services-auth-workaccount-core')\n    implementation project(':play-services-base-core')\n    implementation project(':play-services-cast-core')\n    implementation project(':play-services-cast-framework-core')\n    implementation project(':play-services-conscrypt-provider-core')\n    implementation project(':play-services-cronet-core')\n    implementation project(':play-services-droidguard-core')\n    implementation project(':play-services-fido-core')\n    implementation project(':play-services-fitness-core')\n    implementation project(':play-services-gmscompliance-core')\n    implementation project(':play-services-location-core')\n    implementation project(':play-services-location-core-base')\n    implementation project(':play-services-oss-licenses-core')\n    implementation project(':play-services-panorama-core')\n    implementation project(':play-services-pay-core')\n    implementation project(':play-services-recaptcha-core')\n    implementation project(':play-services-safetynet-core')\n    implementation project(':play-services-tapandpay-core')\n    implementation project(':play-services-threadnetwork-core')\n    implementation project(':play-services-vision-core')\n    implementation project(':play-services-wearable-core')\n\n    implementation project(':play-services-core-proto')\n\n    implementation project(':play-services-core:microg-ui-tools') // deprecated\n    implementation project(':play-services-base-core-package')\n    implementation project(':play-services-api')\n\n    implementation project(':play-services-appinvite')\n    implementation project(':play-services-auth-base')\n    implementation project(':play-services-auth')\n    implementation project(':play-services-clearcut')\n    implementation project(':play-services-drive')\n    implementation project(':play-services-games')\n    implementation project(':play-services-maps')\n    implementation project(':play-services-measurement-base')\n    implementation project(':play-services-places')\n    implementation project(':play-services-recaptcha')\n    implementation project(':play-services-safetynet')\n    implementation project(':play-services-tasks-ktx')\n    implementation project(':play-services-fitness')\n\n    mapboxRuntimeOnly project(':play-services-maps-core-mapbox')\n    vtmRuntimeOnly project(':play-services-maps-core-vtm')\n    defaultRuntimeOnly project(':play-services-location-core-provider')\n\n    if (hasModule(\"nearby\", true)) runtimeOnly project(':play-services-nearby-core-package')\n    if (hasModule(\"hms\", false)) hmsRuntimeOnly project(':play-services-maps-core-hms')\n\n    // AndroidX UI\n    implementation \"androidx.multidex:multidex:$multidexVersion\"\n    implementation \"androidx.appcompat:appcompat:$appcompatVersion\"\n    implementation \"androidx.mediarouter:mediarouter:$mediarouterVersion\"\n    implementation \"androidx.preference:preference-ktx:$preferenceVersion\"\n    implementation \"androidx.webkit:webkit:$webkitVersion\"\n\n    // Material Components\n    implementation \"com.google.android.material:material:$materialVersion\"\n\n    // Compose\n    def composeBom = platform('androidx.compose:compose-bom:2024.04.00')\n    implementation composeBom\n    implementation 'androidx.compose.material3:material3'\n    implementation 'androidx.compose.ui:ui-tooling-preview'\n    debugImplementation 'androidx.compose.ui:ui-tooling'\n    implementation 'androidx.activity:activity-compose:1.8.2'\n\n    // Navigation\n    implementation \"androidx.navigation:navigation-fragment-ktx:$navigationVersion\"\n    implementation \"androidx.navigation:navigation-ui-ktx:$navigationVersion\"\n\n    implementation \"com.android.volley:volley:$volleyVersion\"\n\n    implementation \"androidx.lifecycle:lifecycle-service:$lifecycleVersion\"\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion\"\n\n    implementation \"androidx.work:work-runtime-ktx:$workVersion\"\n}\n\nandroid {\n    namespace \"com.google.android.gms\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        buildConfig = true\n        dataBinding = true\n        compose true\n    }\n\n    defaultConfig {\n        versionName version\n        versionCode appVersionCode\n\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n\n        multiDexEnabled true\n        multiDexKeepProguard file('multidex-keep.pro')\n\n        manifestPlaceholders = [appLabel:\"@string/gms_app_name\"]\n        resValue \"string\", \"package_id\", \"com.google.android.gms\"\n\n        buildConfigField \"String\", \"SAFETYNET_KEY\", \"\\\"${localProperties.get(\"safetynet.key\", \"\")}\\\"\"\n        buildConfigField \"String\", \"RECAPTCHA_SITE_KEY\", \"\\\"${localProperties.get(\"recaptcha.siteKey\", \"\")}\\\"\"\n        buildConfigField \"String\", \"RECAPTCHA_SECRET\", \"\\\"${localProperties.get(\"recaptcha.secret\", \"\")}\\\"\"\n        buildConfigField \"String\", \"RECAPTCHA_ENTERPRISE_PROJECT_ID\", \"\\\"${localProperties.get(\"recaptchaEnterpreise.projectId\", \"\")}\\\"\"\n        buildConfigField \"String\", \"RECAPTCHA_ENTERPRISE_SITE_KEY\", \"\\\"${localProperties.get(\"recaptchaEnterpreise.siteKey\", \"\")}\\\"\"\n        buildConfigField \"String\", \"RECAPTCHA_ENTERPRISE_API_KEY\", \"\\\"${localProperties.get(\"recaptchaEnterpreise.apiKey\", \"\")}\\\"\"\n\n        ndk {\n            abiFilters \"armeabi-v7a\", \"arm64-v8a\", \"x86\", \"x86_64\"\n        }\n    }\n\n    composeOptions {\n        kotlinCompilerExtensionVersion = \"1.5.10\"\n    }\n\n    sourceSets {\n        main {\n            java.srcDirs += 'src/main/kotlin'\n        }\n    }\n\n    lintOptions {\n        disable 'MissingTranslation', 'GetLocales', 'InvalidPackage', 'BatteryLife', 'ImpliedQuantity', 'MissingQuantity', 'InvalidWakeLockTag', 'UniquePermission'\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n\n    flavorDimensions = ['maps', 'target']\n    productFlavors {\n        \"default\" {\n            dimension 'target'\n        }\n        \"huawei\" {\n            dimension 'target'\n            versionNameSuffix \"-hw\"\n        }\n        \"huaweilh\" {\n            dimension 'target'\n            versionNameSuffix \"-lh\"\n            versionCode appVersionCode - 1000\n            matchingFallbacks = ['huawei']\n        }\n        \"user\" {\n            dimension 'target'\n            applicationId = \"org.microg.gms\"\n            versionNameSuffix \"-user\"\n            manifestPlaceholders = [appLabel:\"@string/limited_services_app_name\"]\n            matchingFallbacks = ['default']\n            resValue \"string\", \"package_id\", \"org.microg.gms\"\n        }\n        \"hms\" {\n            dimension 'maps'\n        }\n        \"mapbox\" {\n            dimension 'maps'\n        }\n        \"vtm\" {\n            dimension 'maps'\n        }\n    }\n\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n\n    kotlinOptions {\n        jvmTarget = 1.8\n    }\n\n    packagingOptions {\n        exclude 'META-INF/ASL2.0'\n        jniLibs {\n            useLegacyPackaging true\n        }\n    }\n}\n\nif (file('user.gradle').exists()) {\n    apply from: 'user.gradle'\n}\n\nandroid.applicationVariants.all { variant ->\n    variant.outputs.each { output ->\n        output.outputFileName = variant.applicationId + \"-\" + variant.versionCode + variant.versionName.substring(version.length()) + \".apk\"\n    }\n}\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/build.gradle",
    "content": "/*\n * Copyright 2013-2016 microG Project Team\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\napply plugin: 'com.android.library'\n\nandroid {\n    namespace \"org.microg.tools.ui\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n\n    lintOptions {\n        // TODO: Remove MissingTranslation once we have stable strings and proper translations.\n        disable 'MissingTranslation'\n    }\n}\n\ndependencies {\n    implementation \"androidx.appcompat:appcompat:$appcompatVersion\"\n    implementation \"androidx.preference:preference:$preferenceVersion\"\n}\n\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<manifest />\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/java/org/microg/tools/selfcheck/PermissionCheckGroup.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.tools.selfcheck;\n\nimport android.content.Context;\nimport android.content.pm.PackageManager;\nimport android.content.pm.PermissionInfo;\nimport android.util.Log;\n\nimport androidx.annotation.RequiresApi;\nimport org.microg.tools.ui.R;\n\nimport static org.microg.tools.selfcheck.SelfCheckGroup.Result.Negative;\nimport static org.microg.tools.selfcheck.SelfCheckGroup.Result.Positive;\n\n@RequiresApi(23)\npublic class PermissionCheckGroup implements SelfCheckGroup {\n    private static final String TAG = \"SelfCheckPerms\";\n\n    private String[] permissions;\n\n    public PermissionCheckGroup(String... permissions) {\n        this.permissions = permissions;\n    }\n\n    @Override\n    public String getGroupName(Context context) {\n        return context.getString(R.string.self_check_cat_permissions);\n    }\n\n    @Override\n    public void doChecks(Context context, ResultCollector collector) {\n        for (String permission : permissions) {\n            doPermissionCheck(context, collector, permission);\n        }\n    }\n\n    private void doPermissionCheck(Context context, ResultCollector collector, final String permission) {\n        PackageManager pm = context.getPackageManager();\n        try {\n            PermissionInfo info = pm.getPermissionInfo(permission, 0);\n            CharSequence permLabel = info.loadLabel(pm);\n            collector.addResult(context.getString(R.string.self_check_name_permission, permLabel),\n                    context.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED ? Positive : Negative,\n                    context.getString(R.string.self_check_resolution_permission),\n                    fragment -> fragment.requestPermissions(new String[]{permission}, 0));\n        } catch (PackageManager.NameNotFoundException e) {\n            Log.w(TAG, e);\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/java/org/microg/tools/selfcheck/SelfCheckGroup.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.tools.selfcheck;\n\nimport android.content.Context;\n\nimport androidx.fragment.app.Fragment;\n\npublic interface SelfCheckGroup {\n    String getGroupName(Context context);\n\n    void doChecks(Context context, ResultCollector collector);\n\n    interface ResultCollector {\n        void addResult(String name, Result value, String resolution);\n\n        void addResult(String name, Result value, String resolution, CheckResolver resolver);\n    }\n\n    interface CheckResolver {\n        void tryResolve(Fragment fragment);\n    }\n\n    enum Result {\n        Positive, Negative, Unknown\n    }\n}\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/java/org/microg/tools/ui/AbstractAboutFragment.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.tools.ui;\n\nimport android.content.Context;\nimport android.content.pm.PackageManager;\nimport android.graphics.drawable.Drawable;\nimport android.os.Bundle;\nimport android.text.TextUtils;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\nimport android.widget.TextView;\nimport androidx.annotation.Nullable;\nimport androidx.fragment.app.Fragment;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Locale;\n\npublic abstract class AbstractAboutFragment extends Fragment {\n\n    protected abstract void collectLibraries(List<Library> libraries);\n\n    public static Drawable getIcon(Context context) {\n        try {\n            PackageManager pm = context.getPackageManager();\n            return pm.getPackageInfo(context.getPackageName(), 0).applicationInfo.loadIcon(pm);\n        } catch (PackageManager.NameNotFoundException e) {\n            // Never happens, self package always exists!\n            throw new RuntimeException(e);\n        }\n    }\n\n    public static String getAppName(Context context) {\n        try {\n            PackageManager pm = context.getPackageManager();\n            CharSequence label = pm.getPackageInfo(context.getPackageName(), 0).applicationInfo.loadLabel(pm);\n            if (TextUtils.isEmpty(label)) return context.getPackageName();\n            return label.toString().trim();\n        } catch (PackageManager.NameNotFoundException e) {\n            // Never happens, self package always exists!\n            throw new RuntimeException(e);\n        }\n    }\n\n    protected String getAppName() {\n        return getAppName(getContext());\n    }\n\n    public static String getLibVersion(String packageName) {\n        try {\n            String versionName = (String) Class.forName(packageName + \".BuildConfig\").getField(\"VERSION_NAME\").get(null);\n            if (TextUtils.isEmpty(versionName)) return \"\";\n            return versionName.trim();\n        } catch (Exception e) {\n            return \"\";\n        }\n    }\n\n    public static String getSelfVersion(Context context) {\n        return getLibVersion(context.getPackageName());\n    }\n\n    protected String getSelfVersion() {\n        return getSelfVersion(getContext());\n    }\n\n    protected String getSummary() {\n        return null;\n    }\n\n    @Nullable\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n        View aboutRoot = inflater.inflate(R.layout.about_root, container, false);\n        ((ImageView) aboutRoot.findViewById(android.R.id.icon)).setImageDrawable(getIcon(getContext()));\n        ((TextView) aboutRoot.findViewById(android.R.id.title)).setText(getAppName());\n        ((TextView) aboutRoot.findViewById(R.id.about_version)).setText(getString(R.string.about_version_str, getSelfVersion()));\n        String summary = getSummary();\n        if (summary != null) {\n            ((TextView) aboutRoot.findViewById(android.R.id.summary)).setText(summary);\n            aboutRoot.findViewById(android.R.id.summary).setVisibility(View.VISIBLE);\n        }\n\n        List<Library> libraries = new ArrayList<Library>();\n        collectLibraries(libraries);\n        Collections.sort(libraries);\n        ViewGroup list = aboutRoot.findViewById(android.R.id.list);\n        for (Library library : libraries) {\n            View v = inflater.inflate(android.R.layout.simple_list_item_2, list, false);\n            ((TextView) v.findViewById(android.R.id.text1)).setText(getString(R.string.about_name_version_str, library.name, getLibVersion(library.packageName)));\n            ((TextView) v.findViewById(android.R.id.text2)).setText(library.copyright != null ? library.copyright : getString(R.string.about_default_license));\n            list.addView(v);\n        }\n        return aboutRoot;\n    }\n\n    protected static class Library implements Comparable<Library> {\n        private final String packageName;\n        private final String name;\n        private final String copyright;\n\n        public Library(String packageName, String name, String copyright) {\n            this.packageName = packageName;\n            this.name = name;\n            this.copyright = copyright;\n        }\n\n        @Override\n        public String toString() {\n            return name + \", \" + copyright;\n        }\n\n        @Override\n        public int compareTo(Library another) {\n            return name.toLowerCase(Locale.US).compareTo(another.name.toLowerCase(Locale.US));\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/java/org/microg/tools/ui/AbstractDashboardActivity.java",
    "content": "package org.microg.tools.ui;\n\nimport android.os.Bundle;\nimport android.view.ViewGroup;\n\nimport androidx.appcompat.app.AppCompatActivity;\nimport androidx.fragment.app.Fragment;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic abstract class AbstractDashboardActivity extends AppCompatActivity {\n    protected int preferencesResource = 0;\n\n    private final List<Condition> conditions = new ArrayList<Condition>();\n    private ViewGroup conditionContainer;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.dashboard_activity);\n        conditionContainer = (ViewGroup) findViewById(R.id.condition_container);\n\n        getSupportFragmentManager().beginTransaction()\n                .replace(R.id.content_wrapper, getFragment())\n                .commit();\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        forceConditionReevaluation();\n    }\n\n    private synchronized void resetConditionViews() {\n        conditionContainer.removeAllViews();\n        for (Condition condition : conditions) {\n            if (condition.isEvaluated()) {\n                if (condition.isActive(this)) {\n                    addConditionToView(condition);\n                }\n            } else {\n                evaluateConditionAsync(condition);\n            }\n        }\n    }\n\n    private void evaluateConditionAsync(final Condition condition) {\n        if (condition.willBeEvaluating()) {\n            new Thread(new Runnable() {\n                @Override\n                public void run() {\n                    if (condition.isActive(AbstractDashboardActivity.this)) {\n                        runOnUiThread(new Runnable() {\n                            @Override\n                            public void run() {\n                                if (conditions.contains(condition) && condition.isEvaluated()) {\n                                    addConditionToView(condition);\n                                }\n                            }\n                        });\n                    }\n                }\n            }).start();\n        }\n    }\n\n    protected void forceConditionReevaluation() {\n        for (Condition condition : conditions) {\n            condition.resetEvaluated();\n        }\n        resetConditionViews();\n    }\n\n    protected void addAllConditions(Condition[] conditions) {\n        for (Condition condition : conditions) {\n            addCondition(condition);\n        }\n    }\n\n    protected void addCondition(Condition condition) {\n        conditions.add(condition);\n        if (conditionContainer == null) return;\n        if (condition.isEvaluated()) {\n            addConditionToView(condition);\n        } else {\n            evaluateConditionAsync(condition);\n        }\n    }\n\n    private synchronized void addConditionToView(Condition condition) {\n        for (int i = 0; i < conditionContainer.getChildCount(); i++) {\n            if (conditionContainer.getChildAt(i).getTag() == condition) return;\n        }\n        conditionContainer.addView(condition.createView(this, conditionContainer));\n    }\n\n    protected void clearConditions() {\n        conditions.clear();\n        resetConditionViews();\n    }\n\n    protected Fragment getFragment() {\n        if (preferencesResource == 0) {\n            throw new IllegalStateException(\"Neither preferencesResource given, nor overriden getFragment()\");\n        }\n        ResourceSettingsFragment fragment = new ResourceSettingsFragment();\n        Bundle b = new Bundle();\n        b.putInt(ResourceSettingsFragment.EXTRA_PREFERENCE_RESOURCE, preferencesResource);\n        fragment.setArguments(b);\n        return fragment;\n    }\n}\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/java/org/microg/tools/ui/AbstractSelfCheckFragment.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.tools.ui;\n\nimport android.content.Context;\nimport android.os.Bundle;\nimport android.util.Log;\nimport android.view.LayoutInflater;\nimport android.view.MotionEvent;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.CheckBox;\nimport android.widget.TextView;\n\nimport androidx.annotation.Nullable;\nimport androidx.fragment.app.Fragment;\n\nimport org.microg.tools.selfcheck.SelfCheckGroup;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport static android.view.View.GONE;\nimport static android.view.View.INVISIBLE;\nimport static org.microg.tools.selfcheck.SelfCheckGroup.Result.Negative;\nimport static org.microg.tools.selfcheck.SelfCheckGroup.Result.Positive;\nimport static org.microg.tools.selfcheck.SelfCheckGroup.Result.Unknown;\n\npublic abstract class AbstractSelfCheckFragment extends Fragment {\n    private static final String TAG = \"SelfCheck\";\n\n    private ViewGroup root;\n\n    @Nullable\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n        View scrollRoot = inflater.inflate(R.layout.self_check, container, false);\n        root = (ViewGroup) scrollRoot.findViewById(R.id.self_check_root);\n        reset(inflater);\n        return scrollRoot;\n    }\n\n    protected abstract void prepareSelfCheckList(Context context, List<SelfCheckGroup> checks);\n\n    protected void reset(LayoutInflater inflater) {\n        List<SelfCheckGroup> selfCheckGroupList = new ArrayList<SelfCheckGroup>();\n        prepareSelfCheckList(getContext(), selfCheckGroupList);\n\n        root.removeAllViews();\n        for (SelfCheckGroup group : selfCheckGroupList) {\n            View groupView = inflater.inflate(R.layout.self_check_group, root, false);\n            ((TextView) groupView.findViewById(android.R.id.title)).setText(group.getGroupName(getContext()));\n            final ViewGroup viewGroup = (ViewGroup) groupView.findViewById(R.id.group_content);\n            final SelfCheckGroup.ResultCollector collector = new GroupResultCollector(viewGroup);\n            try {\n                group.doChecks(getContext(), collector);\n            } catch (Exception e) {\n                Log.w(TAG, \"Failed during check \" + group.getGroupName(getContext()), e);\n                collector.addResult(\"Self-check failed:\", Negative, \"An exception occurred during self-check. Please report this issue.\");\n            }\n            root.addView(groupView);\n        }\n    }\n\n    private class GroupResultCollector implements SelfCheckGroup.ResultCollector {\n        private final ViewGroup viewGroup;\n\n        public GroupResultCollector(ViewGroup viewGroup) {\n            this.viewGroup = viewGroup;\n        }\n\n        @Override\n        public void addResult(final String name, final SelfCheckGroup.Result result, final String resolution) {\n            addResult(name, result, resolution, null);\n        }\n\n        @Override\n        public void addResult(final String name, final SelfCheckGroup.Result result, final String resolution,\n                              final SelfCheckGroup.CheckResolver resolver) {\n            if (result == null || getActivity() == null) return;\n            getActivity().runOnUiThread(new Runnable() {\n                @Override\n                public void run() {\n                    View resultEntry = LayoutInflater.from(getContext()).inflate(R.layout.self_check_entry, viewGroup, false);\n                    ((TextView) resultEntry.findViewById(R.id.self_check_name)).setText(name);\n                    resultEntry.findViewById(R.id.self_check_result).setOnTouchListener(new View.OnTouchListener() {\n                        @Override\n                        public boolean onTouch(View v, MotionEvent event) {\n                            return true;\n                        }\n                    });\n                    if (result == Positive) {\n                        ((CheckBox) resultEntry.findViewById(R.id.self_check_result)).setChecked(true);\n                        resultEntry.findViewById(R.id.self_check_resolution).setVisibility(GONE);\n                    } else {\n                        ((TextView) resultEntry.findViewById(R.id.self_check_resolution)).setText(resolution);\n                        if (result == Unknown) {\n                            resultEntry.findViewById(R.id.self_check_result).setVisibility(INVISIBLE);\n                        }\n                        if (resolver != null) {\n                            resultEntry.setClickable(true);\n                            resultEntry.setOnClickListener(v ->\n                                    resolver.tryResolve(AbstractSelfCheckFragment.this)\n                            );\n                        } else {\n                            resultEntry.findViewById(R.id.self_check_result).setEnabled(false);\n                        }\n                    }\n                    viewGroup.addView(resultEntry);\n                }\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/java/org/microg/tools/ui/AbstractSettingsActivity.java",
    "content": "package org.microg.tools.ui;\n\nimport android.os.Bundle;\nimport android.view.MenuItem;\nimport android.view.ViewGroup;\n\nimport androidx.appcompat.app.AppCompatActivity;\nimport androidx.appcompat.widget.Toolbar;\nimport androidx.fragment.app.Fragment;\nimport androidx.fragment.app.FragmentTransaction;\n\npublic abstract class AbstractSettingsActivity extends AppCompatActivity {\n    protected boolean showHomeAsUp = false;\n    protected int preferencesResource = 0;\n    private ViewGroup customBarContainer;\n    protected int customBarLayout = 0;\n    protected SwitchBar switchBar;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.settings_activity);\n        setSupportActionBar((Toolbar) findViewById(R.id.toolbar));\n\n        if (showHomeAsUp) {\n            getSupportActionBar().setDisplayHomeAsUpEnabled(true);\n        }\n\n        switchBar = (SwitchBar) findViewById(R.id.switch_bar);\n\n        customBarContainer = (ViewGroup) findViewById(R.id.custom_bar);\n        if (customBarLayout != 0) {\n            customBarContainer.addView(getLayoutInflater().inflate(customBarLayout, customBarContainer, false));\n        }\n\n        getSupportFragmentManager().beginTransaction()\n                .replace(R.id.content_wrapper, getFragment())\n                .commit();\n    }\n\n    public void setCustomBarLayout(int layout) {\n        customBarLayout = layout;\n        if (customBarContainer != null) {\n            customBarContainer.removeAllViews();\n            customBarContainer.addView(getLayoutInflater().inflate(customBarLayout, customBarContainer, false));\n        }\n    }\n\n    public SwitchBar getSwitchBar() {\n        return switchBar;\n    }\n\n    public void replaceFragment(Fragment fragment) {\n        getSupportFragmentManager().beginTransaction()\n                .addToBackStack(\"root\")\n                .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)\n                .replace(R.id.content_wrapper, fragment)\n                .commit();\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        if (item.getItemId() == android.R.id.home) {\n            finish();\n            return true;\n        }\n        return super.onOptionsItemSelected(item);\n    }\n\n    protected Fragment getFragment() {\n        if (preferencesResource == 0) {\n            throw new IllegalStateException(\"Neither preferencesResource given, nor overriden getFragment()\");\n        }\n        ResourceSettingsFragment fragment = new ResourceSettingsFragment();\n        Bundle b = new Bundle();\n        b.putInt(ResourceSettingsFragment.EXTRA_PREFERENCE_RESOURCE, preferencesResource);\n        fragment.setArguments(b);\n        return fragment;\n    }\n}\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/java/org/microg/tools/ui/AbstractSettingsFragment.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.tools.ui;\n\nimport androidx.fragment.app.DialogFragment;\nimport androidx.preference.Preference;\nimport androidx.preference.PreferenceFragmentCompat;\n\npublic abstract class AbstractSettingsFragment extends PreferenceFragmentCompat {\n    private static final String TAG = AbstractSettingsFragment.class.getSimpleName();\n\n    private static final String DIALOG_FRAGMENT_TAG = \"androidx.preference.PreferenceFragment.DIALOG\";\n\n    @Override\n    public void onDisplayPreferenceDialog(Preference preference) {\n        if (preference instanceof DialogPreference) {\n            DialogFragment f = DialogPreference.DialogPreferenceCompatDialogFragment.newInstance(preference.getKey());\n            f.setTargetFragment(this, 0);\n            f.show(getFragmentManager(), DIALOG_FRAGMENT_TAG);\n        } else {\n            super.onDisplayPreferenceDialog(preference);\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/java/org/microg/tools/ui/Condition.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.tools.ui;\n\nimport android.content.Context;\nimport android.graphics.drawable.Drawable;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.Button;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport androidx.annotation.DrawableRes;\nimport androidx.annotation.PluralsRes;\nimport androidx.annotation.StringRes;\nimport androidx.core.content.res.ResourcesCompat;\n\npublic class Condition {\n    @DrawableRes\n    private final int iconRes;\n    private final Drawable icon;\n\n    @StringRes\n    private final int titleRes;\n    @PluralsRes\n    private final int titlePluralsRes;\n    private final CharSequence title;\n\n    @StringRes\n    private final int summaryRes;\n    @PluralsRes\n    private final int summaryPluralsRes;\n    private final CharSequence summary;\n\n    @StringRes\n    private final int firstActionTextRes;\n    @PluralsRes\n    private final int firstActionPluralsRes;\n    private final CharSequence firstActionText;\n    private final View.OnClickListener firstActionListener;\n\n    @StringRes\n    private final int secondActionTextRes;\n    @PluralsRes\n    private final int secondActionPluralsRes;\n    private final CharSequence secondActionText;\n    private final View.OnClickListener secondActionListener;\n\n    private final Evaluation evaluation;\n\n    private boolean evaluated = false;\n    private boolean evaluating = false;\n    private int evaluatedPlurals = -1;\n    private boolean active;\n\n    Condition(Builder builder) {\n        icon = builder.icon;\n        title = builder.title;\n        summary = builder.summary;\n        firstActionText = builder.firstActionText;\n        firstActionListener = builder.firstActionListener;\n        secondActionText = builder.secondActionText;\n        secondActionListener = builder.secondActionListener;\n        summaryRes = builder.summaryRes;\n        iconRes = builder.iconRes;\n        firstActionTextRes = builder.firstActionTextRes;\n        secondActionTextRes = builder.secondActionTextRes;\n        titleRes = builder.titleRes;\n        evaluation = builder.evaluation;\n        titlePluralsRes = builder.titlePluralsRes;\n        summaryPluralsRes = builder.summaryPluralsRes;\n        firstActionPluralsRes = builder.firstActionPluralsRes;\n        secondActionPluralsRes = builder.secondActionPluralsRes;\n    }\n\n    View createView(final Context context, ViewGroup container) {\n        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);\n        View view = inflater.inflate(R.layout.condition_card, container, false);\n        Drawable icon = getIcon(context);\n        if (icon != null)\n            ((ImageView) view.findViewById(android.R.id.icon)).setImageDrawable(icon);\n        ((TextView) view.findViewById(android.R.id.title)).setText(getTitle(context));\n        ((TextView) view.findViewById(android.R.id.summary)).setText(getSummary(context));\n        Button first = (Button) view.findViewById(R.id.first_action);\n        first.setText(getFirstActionText(context));\n        first.setOnClickListener(getFirstActionListener());\n        CharSequence secondActionText = getSecondActionText(context);\n        if (secondActionText != null) {\n            Button second = (Button) view.findViewById(R.id.second_action);\n            second.setText(secondActionText);\n            second.setOnClickListener(getSecondActionListener());\n            second.setVisibility(View.VISIBLE);\n        }\n        final View detailGroup = view.findViewById(R.id.detail_group);\n        final ImageView expandIndicator = (ImageView) view.findViewById(R.id.expand_indicator);\n        View.OnClickListener expandListener = new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                if (detailGroup.getVisibility() == View.VISIBLE) {\n                    expandIndicator.setImageDrawable(ResourcesCompat.getDrawable(context.getResources(), R.drawable.ic_expand_more, context.getTheme()));\n                    detailGroup.setVisibility(View.GONE);\n                } else {\n                    expandIndicator.setImageDrawable(ResourcesCompat.getDrawable(context.getResources(), R.drawable.ic_expand_less, context.getTheme()));\n                    detailGroup.setVisibility(View.VISIBLE);\n                }\n            }\n        };\n        view.findViewById(R.id.collapsed_group).setOnClickListener(expandListener);\n        expandIndicator.setOnClickListener(expandListener);\n        view.setTag(this);\n        return view;\n    }\n\n    public Drawable getIcon(Context context) {\n        if (iconRes != 0) {\n            return ResourcesCompat.getDrawable(context.getResources(), iconRes, context.getTheme());\n        }\n        return icon;\n    }\n\n    public CharSequence getTitle(Context context) {\n        if (titleRes != 0) {\n            return context.getString(titleRes);\n        }\n        if (titlePluralsRes != 0) {\n            return context.getResources().getQuantityString(titlePluralsRes, evaluatedPlurals);\n        }\n        return title;\n    }\n\n    public CharSequence getSummary(Context context) {\n        if (summaryRes != 0) {\n            return context.getString(summaryRes);\n        }\n        if (summaryPluralsRes != 0) {\n            return context.getResources().getQuantityString(summaryPluralsRes, evaluatedPlurals);\n        }\n        return summary;\n    }\n\n    public View.OnClickListener getFirstActionListener() {\n        return firstActionListener;\n    }\n\n    public CharSequence getFirstActionText(Context context) {\n        if (firstActionTextRes != 0) {\n            return context.getString(firstActionTextRes);\n        }\n        if (firstActionPluralsRes != 0) {\n            return context.getResources().getQuantityString(firstActionPluralsRes, evaluatedPlurals);\n        }\n        return firstActionText;\n    }\n\n    public View.OnClickListener getSecondActionListener() {\n        return secondActionListener;\n    }\n\n    public CharSequence getSecondActionText(Context context) {\n        if (secondActionTextRes != 0) {\n            return context.getString(secondActionTextRes);\n        }\n        if (secondActionPluralsRes != 0) {\n            return context.getResources().getQuantityString(secondActionPluralsRes, evaluatedPlurals);\n        }\n        return secondActionText;\n    }\n\n    public synchronized boolean willBeEvaluating() {\n        if (!evaluating && !evaluated && evaluation != null) {\n            return evaluating = true;\n        } else {\n            return false;\n        }\n    }\n\n    public boolean isEvaluated() {\n        return evaluated || evaluation == null;\n    }\n\n    public synchronized void evaluate(Context context) {\n        active = evaluation == null || evaluation.isActive(context);\n        evaluatedPlurals = evaluation.getPluralsCount();\n        evaluated = true;\n        evaluating = false;\n    }\n\n    public boolean isActive(Context context) {\n        if (!evaluated && evaluation != null) evaluate(context);\n        return active;\n    }\n\n    public void resetEvaluated() {\n        this.evaluated = false;\n    }\n\n    public static abstract class Evaluation {\n        public abstract boolean isActive(Context context);\n\n        public int getPluralsCount() {\n            return 1;\n        }\n    }\n\n    public static class Builder {\n\n        @DrawableRes\n        private int iconRes;\n        private Drawable icon;\n        @StringRes\n        private int titleRes;\n        @PluralsRes\n        private int titlePluralsRes;\n        private CharSequence title;\n        @StringRes\n        private int summaryRes;\n        @PluralsRes\n        private int summaryPluralsRes;\n        private CharSequence summary;\n        @StringRes\n        private int firstActionTextRes;\n        @PluralsRes\n        private int firstActionPluralsRes;\n        private CharSequence firstActionText;\n        private View.OnClickListener firstActionListener;\n        @StringRes\n        private int secondActionTextRes;\n        @PluralsRes\n        private int secondActionPluralsRes;\n        private CharSequence secondActionText;\n        private View.OnClickListener secondActionListener;\n        private Evaluation evaluation;\n\n\n        public Builder() {\n        }\n\n        public Builder icon(Drawable val) {\n            icon = val;\n            return this;\n        }\n\n        public Builder icon(@DrawableRes int val) {\n            iconRes = val;\n            return this;\n        }\n\n        public Builder title(CharSequence val) {\n            title = val;\n            return this;\n        }\n\n        public Builder title(@StringRes int val) {\n            titleRes = val;\n            return this;\n        }\n\n        public Builder titlePlurals(@PluralsRes int val) {\n            titlePluralsRes = val;\n            return this;\n        }\n\n        public Builder summary(CharSequence val) {\n            summary = val;\n            return this;\n        }\n\n        public Builder summary(@StringRes int val) {\n            summaryRes = val;\n            return this;\n        }\n\n        public Builder summaryPlurals(@PluralsRes int val) {\n            summaryPluralsRes = val;\n            return this;\n        }\n\n        public Builder firstAction(CharSequence text, View.OnClickListener listener) {\n            firstActionText = text;\n            firstActionListener = listener;\n            return this;\n        }\n\n        public Builder firstAction(@StringRes int val, View.OnClickListener listener) {\n            firstActionTextRes = val;\n            firstActionListener = listener;\n            return this;\n        }\n\n        public Builder firstActionPlurals(@PluralsRes int val, View.OnClickListener listener) {\n            firstActionPluralsRes = val;\n            firstActionListener = listener;\n            return this;\n        }\n\n        public Builder secondAction(CharSequence text, View.OnClickListener listener) {\n            secondActionText = text;\n            secondActionListener = listener;\n            return this;\n        }\n\n        public Builder secondAction(@StringRes int val, View.OnClickListener listener) {\n            secondActionTextRes = val;\n            secondActionListener = listener;\n            return this;\n        }\n\n        public Builder secondActionPlurals(@PluralsRes int val, View.OnClickListener listener) {\n            secondActionPluralsRes = val;\n            secondActionListener = listener;\n            return this;\n        }\n\n        public Builder evaluation(Evaluation evaluation) {\n            this.evaluation = evaluation;\n            return this;\n        }\n\n        public Condition build() {\n            return new Condition(this);\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/java/org/microg/tools/ui/DialogPreference.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.tools.ui;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\nimport android.os.Bundle;\nimport android.util.AttributeSet;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.LinearLayout;\n\nimport androidx.fragment.app.DialogFragment;\nimport androidx.preference.Preference;\nimport androidx.preference.PreferenceDialogFragmentCompat;\nimport androidx.preference.PreferenceFragmentCompat;\nimport androidx.preference.PreferenceViewHolder;\n\npublic class DialogPreference extends androidx.preference.DialogPreference implements PreferenceFragmentCompat.OnPreferenceDisplayDialogCallback {\n\n    private static final String DIALOG_FRAGMENT_TAG =\n            \"android.support.v7.preference.PreferenceFragment.DIALOG\";\n\n    public DialogPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {\n        super(context, attrs, defStyleAttr, defStyleRes);\n    }\n\n    public DialogPreference(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n    }\n\n    public DialogPreference(Context context, AttributeSet attrs) {\n        super(context, attrs);\n    }\n\n    public DialogPreference(Context context) {\n        super(context);\n    }\n\n    protected View onCreateDialogView() {\n        return null;\n    }\n\n    /**\n     * Called when the dialog is dismissed and should be used to save data to\n     * the {@link SharedPreferences}.\n     *\n     * @param positiveResult Whether the positive button was clicked (true), or\n     *                       the negative button was clicked or the dialog was canceled (false).\n     */\n    protected void onDialogClosed(boolean positiveResult) {\n    }\n\n    @Override\n    public boolean onPreferenceDisplayDialog(PreferenceFragmentCompat caller, Preference pref) {\n        DialogPreferenceCompatDialogFragment fragment = new DialogPreferenceCompatDialogFragment();\n        fragment.setTargetFragment(caller, 0);\n        fragment.show(caller.getFragmentManager(), DIALOG_FRAGMENT_TAG);\n        return true;\n    }\n\n    @Override\n    public void onBindViewHolder(PreferenceViewHolder view) {\n        super.onBindViewHolder(view);\n\n        ViewGroup.LayoutParams layoutParams = view.findViewById(R.id.icon_frame).getLayoutParams();\n        if (layoutParams instanceof LinearLayout.LayoutParams) {\n            if (((LinearLayout.LayoutParams) layoutParams).leftMargin < 0) {\n                ((LinearLayout.LayoutParams) layoutParams).leftMargin = 0;\n            }\n        }\n    }\n\n    public static class DialogPreferenceCompatDialogFragment extends PreferenceDialogFragmentCompat {\n\n        @Override\n        protected View onCreateDialogView(Context context) {\n            if (getPreference() instanceof DialogPreference) {\n                View view = ((DialogPreference) getPreference()).onCreateDialogView();\n                if (view != null) return view;\n            }\n            return super.onCreateDialogView(context);\n        }\n\n        @Override\n        public void onDialogClosed(boolean positiveResult) {\n            if (getPreference() instanceof DialogPreference) {\n                ((DialogPreference) getPreference()).onDialogClosed(positiveResult);\n            }\n        }\n\n        public static DialogFragment newInstance(String key) {\n            final DialogPreferenceCompatDialogFragment fragment = new DialogPreferenceCompatDialogFragment();\n            final Bundle b = new Bundle(1);\n            b.putString(ARG_KEY, key);\n            fragment.setArguments(b);\n            return fragment;\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/java/org/microg/tools/ui/LongTextPreference.java",
    "content": "/*\n * Copyright (C) 2017 microG Project Team\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 org.microg.tools.ui;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\nimport android.widget.TextView;\n\nimport androidx.preference.Preference;\nimport androidx.preference.PreferenceViewHolder;\n\npublic class LongTextPreference extends Preference {\n\n    public LongTextPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {\n        super(context, attrs, defStyleAttr, defStyleRes);\n    }\n\n    public LongTextPreference(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n    }\n\n    public LongTextPreference(Context context, AttributeSet attrs) {\n        super(context, attrs);\n    }\n\n    public LongTextPreference(Context context) {\n        super(context);\n    }\n\n    @Override\n    public void onBindViewHolder(PreferenceViewHolder holder) {\n        super.onBindViewHolder(holder);\n        TextView view = (TextView) holder.findViewById(android.R.id.summary);\n        if (view != null) {\n            view.setMaxLines(Integer.MAX_VALUE);\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/java/org/microg/tools/ui/RadioButtonPreference.java",
    "content": "/*\n * Copyright (C) 2017 microG Project Team\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 org.microg.tools.ui;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.util.AttributeSet;\n\nimport androidx.core.content.res.TypedArrayUtils;\nimport androidx.preference.CheckBoxPreference;\n\npublic class RadioButtonPreference extends CheckBoxPreference {\n\n    public RadioButtonPreference(Context context, AttributeSet attrs, int defStyleAttr) {\n        this(context, attrs, defStyleAttr, 0);\n    }\n\n    public RadioButtonPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {\n        super(context, attrs, defStyleAttr, defStyleRes);\n        setWidgetLayoutResource(R.layout.preference_widget_radiobutton);\n    }\n\n    @SuppressLint(\"RestrictedApi\")\n    public RadioButtonPreference(Context context, AttributeSet attrs) {\n        this(context, attrs, TypedArrayUtils.getAttr(context, androidx.preference.R.attr.checkBoxPreferenceStyle,\n                android.R.attr.checkBoxPreferenceStyle));\n    }\n\n    public RadioButtonPreference(Context context) {\n        this(context, null);\n    }\n}\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/java/org/microg/tools/ui/ResourceSettingsFragment.java",
    "content": "/*\n * Copyright (C) 2017 microG Project Team\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 org.microg.tools.ui;\n\nimport android.os.Bundle;\n\nimport androidx.annotation.Nullable;\n\npublic class ResourceSettingsFragment extends AbstractSettingsFragment {\n\n    public static final String EXTRA_PREFERENCE_RESOURCE = \"preferencesResource\";\n\n    protected int preferencesResource;\n\n    @Override\n    public void onCreatePreferences(@Nullable Bundle savedInstanceState, String rootKey) {\n        Bundle b = getArguments();\n        if (b != null) {\n            preferencesResource = b.getInt(EXTRA_PREFERENCE_RESOURCE, preferencesResource);\n        }\n        if (preferencesResource != 0) {\n            addPreferencesFromResource(preferencesResource);\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/java/org/microg/tools/ui/SwitchBar.java",
    "content": "/*\n * Copyright (C) 2014 The Android Open Source Project\n * Copyright (C) 2014-2017 microG Project Team\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 org.microg.tools.ui;\n\nimport android.content.Context;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.text.SpannableStringBuilder;\nimport android.text.TextUtils;\nimport android.text.style.TextAppearanceSpan;\nimport android.util.AttributeSet;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.widget.CompoundButton;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\n\nimport androidx.appcompat.widget.SwitchCompat;\n\nimport java.util.ArrayList;\n\nimport static android.os.Build.VERSION.SDK_INT;\n\npublic class SwitchBar extends LinearLayout implements CompoundButton.OnCheckedChangeListener,\n        View.OnClickListener {\n\n    public static interface OnSwitchChangeListener {\n        /**\n         * Called when the checked state of the Switch has changed.\n         *\n         * @param switchView The Switch view whose state has changed.\n         * @param isChecked  The new checked state of switchView.\n         */\n        void onSwitchChanged(SwitchCompat switchView, boolean isChecked);\n    }\n\n    private final TextAppearanceSpan mSummarySpan;\n\n    private ToggleSwitch mSwitch;\n    private TextView mTextView;\n    private String mLabel;\n    private String mSummary;\n\n    private ArrayList<OnSwitchChangeListener> mSwitchChangeListeners =\n            new ArrayList<OnSwitchChangeListener>();\n\n    public SwitchBar(Context context) {\n        this(context, null);\n    }\n\n    public SwitchBar(Context context, AttributeSet attrs) {\n        super(context, attrs);\n\n        LayoutInflater.from(context).inflate(R.layout.switch_bar, this);\n\n        mTextView = (TextView) findViewById(R.id.switch_text);\n        if (SDK_INT > 16) {\n            mTextView.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);\n        }\n        mLabel = getResources().getString(androidx.appcompat.R.string.abc_capital_off);\n        mSummarySpan = new TextAppearanceSpan(context, androidx.appcompat.R.style.TextAppearance_AppCompat_Widget_Switch);\n        updateText();\n\n        mSwitch = (ToggleSwitch) findViewById(R.id.switch_widget);\n        // Prevent onSaveInstanceState() to be called as we are managing the state of the Switch\n        // on our own\n        mSwitch.setSaveEnabled(false);\n        if (SDK_INT >= 16) {\n            mSwitch.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);\n        }\n\n        addOnSwitchChangeListener(new OnSwitchChangeListener() {\n            @Override\n            public void onSwitchChanged(SwitchCompat switchView, boolean isChecked) {\n                setTextViewLabel(isChecked);\n            }\n        });\n\n        setOnClickListener(this);\n\n        // Default is hide\n        setVisibility(View.GONE);\n    }\n\n    public void setTextViewLabel(boolean isChecked) {\n        mLabel = getResources()\n                .getString(isChecked ? androidx.appcompat.R.string.abc_capital_on : androidx.appcompat.R.string.abc_capital_off);\n        updateText();\n    }\n\n    public void setSummary(String summary) {\n        mSummary = summary;\n        updateText();\n    }\n\n    private void updateText() {\n        if (TextUtils.isEmpty(mSummary)) {\n            mTextView.setText(mLabel);\n            return;\n        }\n        final SpannableStringBuilder ssb = new SpannableStringBuilder(mLabel).append('\\n');\n        final int start = ssb.length();\n        ssb.append(mSummary);\n        ssb.setSpan(mSummarySpan, start, ssb.length(), 0);\n        mTextView.setText(ssb);\n    }\n\n    public void setChecked(boolean checked) {\n        setTextViewLabel(checked);\n        mSwitch.setChecked(checked);\n    }\n\n    public void setCheckedInternal(boolean checked) {\n        setTextViewLabel(checked);\n        mSwitch.setCheckedInternal(checked);\n    }\n\n    public boolean isChecked() {\n        return mSwitch.isChecked();\n    }\n\n    public void setEnabled(boolean enabled) {\n        super.setEnabled(enabled);\n        mTextView.setEnabled(enabled);\n        mSwitch.setEnabled(enabled);\n    }\n\n    public final ToggleSwitch getSwitch() {\n        return mSwitch;\n    }\n\n    public void show() {\n        if (!isShowing()) {\n            setVisibility(View.VISIBLE);\n            mSwitch.setOnCheckedChangeListener(this);\n        }\n    }\n\n    public void hide() {\n        if (isShowing()) {\n            setVisibility(View.GONE);\n            mSwitch.setOnCheckedChangeListener(null);\n        }\n    }\n\n    public boolean isShowing() {\n        return (getVisibility() == View.VISIBLE);\n    }\n\n    @Override\n    public void onClick(View v) {\n        final boolean isChecked = !mSwitch.isChecked();\n        setChecked(isChecked);\n    }\n\n    public void propagateChecked(boolean isChecked) {\n        final int count = mSwitchChangeListeners.size();\n        for (int n = 0; n < count; n++) {\n            mSwitchChangeListeners.get(n).onSwitchChanged(mSwitch, isChecked);\n        }\n    }\n\n    @Override\n    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {\n        propagateChecked(isChecked);\n    }\n\n    public void addOnSwitchChangeListener(OnSwitchChangeListener listener) {\n        if (mSwitchChangeListeners.contains(listener)) {\n            throw new IllegalStateException(\"Cannot add twice the same OnSwitchChangeListener\");\n        }\n        mSwitchChangeListeners.add(listener);\n    }\n\n    public void removeOnSwitchChangeListener(OnSwitchChangeListener listener) {\n        if (!mSwitchChangeListeners.contains(listener)) {\n            throw new IllegalStateException(\"Cannot remove OnSwitchChangeListener\");\n        }\n        mSwitchChangeListeners.remove(listener);\n    }\n\n    static class SavedState extends BaseSavedState {\n        boolean checked;\n        boolean visible;\n\n        SavedState(Parcelable superState) {\n            super(superState);\n        }\n\n        /**\n         * Constructor called from {@link #CREATOR}\n         */\n        private SavedState(Parcel in) {\n            super(in);\n            checked = (Boolean) in.readValue(Boolean.class.getClassLoader());\n            visible = (Boolean) in.readValue(Boolean.class.getClassLoader());\n        }\n\n        @Override\n        public void writeToParcel(Parcel out, int flags) {\n            super.writeToParcel(out, flags);\n            out.writeValue(checked);\n            out.writeValue(visible);\n        }\n\n        @Override\n        public String toString() {\n            return \"SwitchBar.SavedState{\"\n                    + Integer.toHexString(System.identityHashCode(this))\n                    + \" checked=\" + checked\n                    + \" visible=\" + visible + \"}\";\n        }\n\n        public static final Parcelable.Creator<SavedState> CREATOR\n                = new Parcelable.Creator<SavedState>() {\n            public SavedState createFromParcel(Parcel in) {\n                return new SavedState(in);\n            }\n\n            public SavedState[] newArray(int size) {\n                return new SavedState[size];\n            }\n        };\n    }\n\n    @Override\n    public Parcelable onSaveInstanceState() {\n        Parcelable superState = super.onSaveInstanceState();\n\n        SavedState ss = new SavedState(superState);\n        ss.checked = mSwitch.isChecked();\n        ss.visible = isShowing();\n        return ss;\n    }\n\n    @Override\n    public void onRestoreInstanceState(Parcelable state) {\n        SavedState ss = (SavedState) state;\n\n        super.onRestoreInstanceState(ss.getSuperState());\n\n        mSwitch.setCheckedInternal(ss.checked);\n        setTextViewLabel(ss.checked);\n        setVisibility(ss.visible ? View.VISIBLE : View.GONE);\n        mSwitch.setOnCheckedChangeListener(ss.visible ? this : null);\n\n        requestLayout();\n    }\n}\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/java/org/microg/tools/ui/SwitchBarResourceSettingsFragment.java",
    "content": "/*\n * Copyright (C) 2017 microG Project Team\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 org.microg.tools.ui;\n\nimport android.os.Bundle;\n\nimport androidx.appcompat.widget.SwitchCompat;\n\npublic abstract class SwitchBarResourceSettingsFragment extends ResourceSettingsFragment implements SwitchBar.OnSwitchChangeListener {\n    protected SwitchBar switchBar;\n    private SwitchCompat switchCompat;\n    private boolean listenerSetup = false;\n\n    @Override\n    public void onActivityCreated(Bundle savedInstanceState) {\n        super.onActivityCreated(savedInstanceState);\n\n//        switchBar = activity.getSwitchBar();\n//        switchBar.show();\n//        switchCompat = switchBar.getSwitch();\n    }\n\n    @Override\n    public void onDestroyView() {\n        super.onDestroyView();\n//        switchBar.hide();\n    }\n\n    @Override\n    public void onResume() {\n        super.onResume();\n        if (!listenerSetup) {\n//            switchBar.addOnSwitchChangeListener(this);\n            listenerSetup = true;\n        }\n    }\n\n    @Override\n    public void onPause() {\n        if (listenerSetup) {\n//            switchBar.removeOnSwitchChangeListener(this);\n            listenerSetup = false;\n        }\n        super.onPause();\n    }\n\n    @Override\n    public void onSwitchChanged(SwitchCompat switchView, boolean isChecked) {\n        if (switchView == switchCompat) {\n            onSwitchBarChanged(isChecked);\n        }\n    }\n\n    public abstract void onSwitchBarChanged(boolean isChecked);\n}\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/java/org/microg/tools/ui/ToggleSwitch.java",
    "content": "/*\n * Copyright (C) 2014 The Android Open Source Project\n * Copyright (C) 2014-2017 microG Project Team\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 org.microg.tools.ui;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.util.AttributeSet;\n\nimport androidx.appcompat.widget.SwitchCompat;\n\n@SuppressLint(\"NewApi\")\npublic class ToggleSwitch extends SwitchCompat {\n\n    private ToggleSwitch.OnBeforeCheckedChangeListener mOnBeforeListener;\n\n    public interface OnBeforeCheckedChangeListener {\n        boolean onBeforeCheckedChanged(ToggleSwitch toggleSwitch, boolean checked);\n    }\n\n    public ToggleSwitch(Context context) {\n        super(context);\n    }\n\n    public ToggleSwitch(Context context, AttributeSet attrs) {\n        super(context, attrs);\n    }\n\n    public ToggleSwitch(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n    }\n\n    public void setOnBeforeCheckedChangeListener(OnBeforeCheckedChangeListener listener) {\n        mOnBeforeListener = listener;\n    }\n\n    @Override\n    public void setChecked(boolean checked) {\n        if (mOnBeforeListener != null\n                && mOnBeforeListener.onBeforeCheckedChanged(this, checked)) {\n            return;\n        }\n        super.setChecked(checked);\n    }\n\n    public void setCheckedInternal(boolean checked) {\n        super.setChecked(checked);\n    }\n}\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/res/drawable/empty.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<selector/>"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/res/drawable/ic_expand_less.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2015 The Android Open Source Project\n  ~ Copyright (C) 2015-2017 microG Project Team\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=\"24dp\"\n        android:height=\"24dp\"\n        android:tint=\"?attr/colorControlNormal\"\n        android:viewportHeight=\"24\"\n        android:viewportWidth=\"24\">\n\n    <path\n        android:fillColor=\"#ffffff\"\n        android:pathData=\"M12.0,8.0l-6.0,6.0 1.41,1.41L12.0,10.83l4.59,4.58L18.0,14.0z\"/>\n\n</vector>\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/res/drawable/ic_expand_more.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2015 The Android Open Source Project\n  ~ Copyright (C) 2015-2017 microG Project Team\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=\"24dp\"\n        android:height=\"24dp\"\n        android:tint=\"?attr/colorControlNormal\"\n        android:viewportHeight=\"24\"\n        android:viewportWidth=\"24\">\n\n    <path\n        android:fillColor=\"#ffffff\"\n        android:pathData=\"M16.59,8.59L12.0,13.17 7.41,8.59 6.0,10.0l6.0,6.0 6.0,-6.0z\"/>\n\n</vector>\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/res/drawable/switchbar_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<color xmlns:android=\"http://schemas.android.com/apk/res/android\"\n       android:color=\"@color/switchbar_background_color\"/>\n\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/res/drawable-v21/switchbar_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ripple xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:color=\"@color/ripple_material_dark\">\n    <item android:drawable=\"@color/switchbar_background_color\"/>\n</ripple>\n\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/res/layout/about_root.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<LinearLayout 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    <ImageView\n        android:id=\"@android:id/icon\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center_horizontal\"\n        android:padding=\"10dp\"\n        android:src=\"@android:drawable/ic_dialog_alert\"/>\n\n    <TextView\n        android:id=\"@android:id/title\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"center_horizontal\"\n        android:text=\"@string/about_root_title\"\n        android:textAppearance=\"@style/TextAppearance.AppCompat.Headline\"\n        android:textColor=\"?attr/colorAccent\"/>\n\n    <TextView\n        android:id=\"@android:id/summary\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"center_horizontal\"\n        android:visibility=\"gone\"\n        android:text=\"@string/about_root_summary\"\n        android:textAppearance=\"@style/TextAppearance.AppCompat.Subhead\"\n        android:textColor=\"?attr/colorAccent\"/>\n\n    <TextView\n        android:id=\"@+id/about_version\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center_horizontal\"\n        android:text=\"@string/about_root_version\"\n        android:textAppearance=\"@style/TextAppearance.AppCompat.Subhead\"/>\n\n    <TextView\n        android:id=\"@android:id/title\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"16dip\"\n        android:paddingLeft=\"?attr/listPreferredItemPaddingLeft\"\n        android:paddingRight=\"?attr/listPreferredItemPaddingRight\"\n        android:paddingTop=\"16dip\"\n        android:textAppearance=\"@style/TextAppearance.AppCompat.Body2\"\n        android:text=\"@string/about_root_libraries\"\n        android:textColor=\"?attr/colorAccent\"/>\n\n    <LinearLayout\n        android:orientation=\"vertical\"\n        android:id=\"@android:id/list\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"/>\n</LinearLayout>\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/res/layout/app_bar.xml",
    "content": "<!--\n  ~ Copyright (C) 2014 The Android Open Source Project\n  ~ Copyright (C) 2014-2017 microG Project Team\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<RelativeLayout android:id=\"@+id/app_bar\"\n                xmlns:android=\"http://schemas.android.com/apk/res/android\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"?attr/actionBarSize\"\n                android:background=\"@drawable/switchbar_background\"\n                android:clickable=\"true\"\n                android:gravity=\"center_vertical\">\n\n    <ImageView\n        android:id=\"@+id/app_icon\"\n        android:layout_width=\"72dp\"\n        android:layout_height=\"40dp\"\n        android:layout_centerVertical=\"true\"\n        android:gravity=\"end\"/>\n\n    <TextView\n        android:id=\"@+id/app_name\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignParentEnd=\"true\"\n        android:layout_alignParentRight=\"true\"\n        android:layout_alignWithParentIfMissing=\"true\"\n        android:layout_centerVertical=\"true\"\n        android:layout_marginEnd=\"16dp\"\n        android:layout_marginLeft=\"72dp\"\n        android:layout_marginRight=\"16dp\"\n        android:layout_marginStart=\"72dp\"\n        android:gravity=\"start\"\n        android:textAlignment=\"viewStart\"\n        android:textColor=\"?android:attr/textColorPrimaryInverse\"/>\n\n</RelativeLayout>\n\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/res/layout/condition_card.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2015 The Android Open Source Project\n  ~ Copyright (C) 2015-2017 microG Project Team\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<FrameLayout 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=\"wrap_content\"\n    android:layout_marginBottom=\"0.25dp\"\n    android:clipChildren=\"false\"\n    android:clipToPadding=\"false\">\n\n    <LinearLayout\n        android:id=\"@+id/content\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:background=\"?attr/colorAccent\"\n        android:clickable=\"true\"\n        android:elevation=\"2dp\"\n        android:focusable=\"true\"\n        android:orientation=\"vertical\"\n        android:paddingStart=\"16dp\"\n        android:paddingLeft=\"16dp\">\n\n        <LinearLayout\n            android:id=\"@+id/collapsed_group\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"56dp\"\n            android:gravity=\"center\"\n            android:orientation=\"horizontal\">\n\n            <ImageView\n                android:id=\"@android:id/icon\"\n                android:layout_width=\"24dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginEnd=\"36dp\"\n                android:layout_marginRight=\"36dp\"\n                android:src=\"@android:drawable/ic_dialog_alert\"\n                app:tint=\"?android:attr/textColorPrimaryInverse\" />\n\n            <TextView\n                android:id=\"@android:id/title\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:text=\"Test Condition\"\n                android:textAppearance=\"?android:attr/textAppearanceMedium\"\n                android:textColor=\"?android:attr/textColorPrimaryInverse\" />\n\n            <ImageView\n                android:id=\"@+id/expand_indicator\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"match_parent\"\n                android:background=\"?attr/selectableItemBackground\"\n                android:clickable=\"true\"\n                android:focusable=\"true\"\n                android:padding=\"16dp\"\n                android:src=\"@drawable/ic_expand_more\"\n                app:tint=\"?android:attr/textColorPrimaryInverse\" />\n\n        </LinearLayout>\n\n        <LinearLayout\n            android:id=\"@+id/detail_group\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"vertical\"\n            android:paddingStart=\"60dp\"\n            android:paddingLeft=\"60dp\"\n            android:visibility=\"gone\">\n\n            <TextView\n                android:id=\"@android:id/summary\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:alpha=\".7\"\n                android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"\n                android:paddingRight=\"?attr/listPreferredItemPaddingRight\"\n                android:paddingBottom=\"16dp\"\n                android:text=\"This condition just exists for testing. This is a summary describing it.\"\n                android:textAppearance=\"?attr/textAppearanceListItemSmall\"\n                android:textColor=\"?android:attr/textColorPrimaryInverse\" />\n\n            <View\n                android:id=\"@+id/divider\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"0.25dp\"\n                android:background=\"@android:color/white\" />\n\n            <androidx.appcompat.widget.ButtonBarLayout\n                android:id=\"@+id/buttonBar\"\n                style=\"?attr/buttonBarStyle\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:paddingTop=\"8dp\"\n                android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"\n                android:paddingRight=\"?attr/listPreferredItemPaddingRight\"\n                android:paddingBottom=\"8dp\">\n\n                <Button\n                    android:id=\"@+id/first_action\"\n                    style=\"?attr/buttonBarButtonStyle\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:alpha=\"0.8\"\n                    android:paddingStart=\"0dp\"\n                    android:paddingLeft=\"0dp\"\n                    android:text=\"Fix it!\"\n                    android:textColor=\"?android:attr/textColorPrimaryInverse\" />\n\n                <Button\n                    android:id=\"@+id/second_action\"\n                    style=\"?attr/buttonBarButtonStyle\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:alpha=\"0.8\"\n                    android:textColor=\"?android:attr/textColorPrimaryInverse\"\n                    android:visibility=\"gone\" />\n\n            </androidx.appcompat.widget.ButtonBarLayout>\n        </LinearLayout>\n    </LinearLayout>\n</FrameLayout>\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/res/layout/dashboard_activity.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<LinearLayout 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\n    <LinearLayout\n        android:id=\"@+id/condition_container\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"/>\n\n    <FrameLayout\n        android:id=\"@+id/content_wrapper\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_marginTop=\"4dp\"\n        android:layout_weight=\"1\"/>\n\n</LinearLayout>\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/res/layout/preference_widget_radiobutton.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2017 microG Project Team\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<RadioButton android:id=\"@android:id/checkbox\"\n             xmlns:android=\"http://schemas.android.com/apk/res/android\"\n             android:layout_width=\"wrap_content\"\n             android:layout_height=\"wrap_content\"\n             android:layout_gravity=\"center\"\n             android:clickable=\"false\"\n             android:focusable=\"false\"/>"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/res/layout/self_check.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<ScrollView\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\">\n\n    <LinearLayout\n        android:id=\"@+id/self_check_root\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\">\n\n    </LinearLayout>\n</ScrollView>"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/res/layout/self_check_entry.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n              android:layout_width=\"match_parent\"\n              android:layout_height=\"wrap_content\"\n              android:background=\"?attr/selectableItemBackground\"\n              android:gravity=\"center_vertical\"\n              android:orientation=\"horizontal\"\n              android:paddingBottom=\"5dp\"\n              android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"\n              android:paddingLeft=\"?attr/listPreferredItemPaddingLeft\"\n              android:paddingRight=\"?attr/listPreferredItemPaddingRight\"\n              android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\">\n\n    <LinearLayout\n        android:layout_width=\"0dip\"\n        android:layout_height=\"wrap_content\"\n        android:layout_weight=\"1\"\n        android:orientation=\"vertical\">\n\n        <TextView\n            android:id=\"@+id/self_check_name\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:textAppearance=\"?attr/textAppearanceListItem\"\n            android:textColor=\"?android:textColorPrimary\"/>\n\n        <TextView\n            android:id=\"@+id/self_check_resolution\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:textAppearance=\"@style/TextAppearance.AppCompat.Body1\"\n            android:textColor=\"?android:textColorSecondary\"/>\n    </LinearLayout>\n\n    <CheckBox\n        android:id=\"@+id/self_check_result\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:focusable=\"false\"\n        android:gravity=\"right|center_vertical\"\n        android:paddingTop=\"5dp\"/>\n</LinearLayout>"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/res/layout/self_check_group.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<LinearLayout 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\n    <TextView\n        android:id=\"@android:id/title\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"16dip\"\n        android:paddingLeft=\"?attr/listPreferredItemPaddingLeft\"\n        android:paddingRight=\"?attr/listPreferredItemPaddingRight\"\n        android:paddingTop=\"16dip\"\n        android:textAppearance=\"@style/TextAppearance.AppCompat.Body2\"\n        android:textColor=\"?attr/colorAccent\"/>\n\n    <LinearLayout\n        android:id=\"@+id/group_content\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"/>\n\n</LinearLayout>"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/res/layout/settings_activity.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<LinearLayout 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\n    <androidx.appcompat.widget.Toolbar\n        android:id=\"@+id/toolbar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:minHeight=\"?attr/actionBarSize\"\n        android:theme=\"?attr/actionBarTheme\" />\n\n    <org.microg.tools.ui.SwitchBar\n        android:id=\"@+id/switch_bar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"?attr/actionBarSize\"\n        android:background=\"@color/switchbar_background_color\"\n        android:visibility=\"gone\"/>\n\n    <FrameLayout\n        android:id=\"@+id/custom_bar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"/>\n\n    <FrameLayout\n        android:id=\"@+id/content_wrapper\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_weight=\"1\"/>\n\n</LinearLayout>\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/res/layout/switch_bar.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2014 The Android Open Source Project\n  ~ Copyright (C) 2014-2017 microG Project Team\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<merge xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <TextView\n        android:id=\"@+id/switch_text\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"start|center_vertical\"\n        android:layout_marginLeft=\"72dp\"\n        android:layout_marginStart=\"72dp\"\n        android:layout_weight=\"1\"\n        android:ellipsize=\"end\"\n        android:maxLines=\"2\"\n        android:text=\"@string/v7_preference_on\"\n        android:textAppearance=\"@style/TextAppearance.AppCompat.Title.Inverse\"/>\n\n    <org.microg.tools.ui.ToggleSwitch\n        android:id=\"@+id/switch_widget\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center_vertical\"\n        android:layout_marginEnd=\"16dp\"\n        android:layout_marginRight=\"16dp\"\n        android:background=\"@null\"/>\n\n</merge>"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/res/layout/toolbar.xml",
    "content": "<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<androidx.appcompat.widget.Toolbar xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:id=\"@+id/toolbar\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:background=\"?attr/colorPrimary\"\n    android:minHeight=\"?attr/actionBarSize\"\n    android:theme=\"@style/ThemeOverlay.AppCompat.Dark.ActionBar\" />\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/res/layout-v14/preference_category_dashboard.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n              android:layout_width=\"wrap_content\"\n              android:layout_height=\"wrap_content\"\n              android:orientation=\"vertical\">\n\n    <View\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"1dip\"\n        android:background=\"?android:attr/listDivider\"/>\n\n    <TextView android:id=\"@android:id/title\"\n              android:layout_width=\"match_parent\"\n              android:layout_height=\"wrap_content\"\n              android:layout_marginBottom=\"4dip\"\n              android:paddingBottom=\"8dip\"\n              android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"\n              android:paddingLeft=\"?android:attr/listPreferredItemPaddingLeft\"\n              android:paddingRight=\"?android:attr/listPreferredItemPaddingRight\"\n              android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n              android:paddingTop=\"8dip\"\n              android:textAppearance=\"@style/TextAppearance.AppCompat.Body2\"/>\n</LinearLayout>"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/res/layout-v21/preference_material.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2015 The Android Open Source Project\n  ~ Copyright (C) 2015-2017 microG Project Team\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<LinearLayout 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=\"wrap_content\"\n              android:background=\"?android:attr/selectableItemBackground\"\n              android:baselineAligned=\"false\"\n              android:clipToPadding=\"false\"\n              android:focusable=\"true\"\n              android:gravity=\"center_vertical\"\n              android:minHeight=\"?android:attr/listPreferredItemHeightSmall\"\n              android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"\n              android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\">\n\n    <LinearLayout\n        android:id=\"@+id/icon_frame\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"start|center_vertical\"\n        android:minWidth=\"56dp\"\n        android:orientation=\"horizontal\"\n        android:paddingBottom=\"4dp\"\n        android:paddingEnd=\"12dp\"\n        android:paddingTop=\"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            app:maxHeight=\"48dp\"\n            app:maxWidth=\"48dp\"/>\n    </LinearLayout>\n\n    <RelativeLayout\n        android:layout_width=\"0dip\"\n        android:layout_height=\"wrap_content\"\n        android:layout_weight=\"1\"\n        android:paddingBottom=\"16dp\"\n        android:paddingTop=\"16dp\">\n\n        <TextView\n            android:id=\"@android:id/title\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:ellipsize=\"marquee\"\n            android:singleLine=\"true\"\n            android:textAppearance=\"?android:attr/textAppearanceListItem\"/>\n\n        <TextView\n            android:id=\"@android:id/summary\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_alignStart=\"@android:id/title\"\n            android:layout_below=\"@android:id/title\"\n            android:maxLines=\"10\"\n            android:textAppearance=\"?android:attr/textAppearanceListItemSecondary\"\n            android:textColor=\"?android:attr/textColorSecondary\"/>\n\n    </RelativeLayout>\n\n    <!-- Preference should place its actual preference widget here. -->\n    <LinearLayout\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:orientation=\"vertical\"\n        android:paddingStart=\"16dp\"/>\n\n</LinearLayout>\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<resources>\n    <color name=\"settings_theme_primary\">#ff263238</color>\n    <color name=\"settings_theme_primary_dark\">#ff21272b</color>\n    <color name=\"settings_theme_accent\">#ff009688</color>\n\n    <color name=\"switchbar_background_color\">#ff37474f</color>\n    <color name=\"switch_accent_color\">#ff7fcac3</color>\n</resources>\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<resources>\n    <string name=\"lib_name\">microG UI Tools</string>\n    <string name=\"lib_license\">Apache License 2.0, microG Team</string>\n\n    <string name=\"about_version_str\">Version %1$s</string>\n    <string name=\"about_name_version_str\">%1$s %2$s</string>\n    <string name=\"about_default_license\">All rights reserved.</string>\n\n    <string name=\"prefcat_setup\">Setup</string>\n\n    <string name=\"self_check_title\">Self-Check</string>\n    <string name=\"self_check_desc\">Check if the system is correctly set up to use microG.</string>\n\n    <string name=\"self_check_cat_permissions\">Permissions granted</string>\n    <string name=\"self_check_name_permission\">Permission to %1$s:</string>\n    <string name=\"self_check_name_permission_interact_across_profiles\">Permission to interact with work profile:</string>\n    <string name=\"self_check_resolution_permission\">Touch here to grant permission. Not granting the permission can result in misbehaving applications.</string>\n\n    <string name=\"about_root_title\">microG UI Demo</string>\n    <string name=\"about_root_summary\">Summary</string>\n    <string name=\"about_root_version\">Version v0.1.0</string>\n    <string name=\"about_root_libraries\">Included libraries</string>\n\n    <string name=\"about_android_support_v4\">v4 Support Library</string>\n    <string name=\"about_android_support_v7_appcompat\">v7 appcompat Support Library</string>\n    <string name=\"about_android_support_v7_preference\">v7 preference Support Library</string>\n    <string name=\"about_android_support_license\">Apache License 2.0, The Android Open Source Project</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/res/values-be/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2020 microG Project Team\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<resources>\n    <string name=\"lib_name\">microG UI Tools</string>\n    <string name=\"lib_license\">Apache License 2.0, microG Team</string>\n\n    <string name=\"about_version_str\">Версія %1$s</string>\n    <string name=\"about_name_version_str\">%1$s %2$s</string>\n    <string name=\"about_default_license\">Ўсе правы абаронены.</string>\n\n    <string name=\"prefcat_setup\">Ўсталяваць</string>\n\n    <string name=\"self_check_title\">Працаздольнасць</string>\n    <string name=\"self_check_desc\">Праверце, ці правільна настроена сістэма для выкарыстання microG.</string>\n\n    <string name=\"self_check_cat_permissions\">Правы доступу прадастаўленыя</string>\n    <string name=\"self_check_name_permission\">%1$s:</string>\n    <string name=\"self_check_resolution_permission\">Краніце, каб даць дазвол. Адсутны дазвол можа прывесці да некарэктнай працы прыкладання.</string>\n\n    <string name=\"about_root_title\">microG UI Demo</string>\n    <string name=\"about_root_summary\">Падрабязнасці</string>\n    <string name=\"about_root_version\">Версія v0.1.0</string>\n    <string name=\"about_root_libraries\">Выкарыстоўваемыя бібліятэкі</string>\n\n    <string name=\"about_android_support_v4\">v4 Support Library</string>\n    <string name=\"about_android_support_v7_appcompat\">v7 appcompat Support Library</string>\n    <string name=\"about_android_support_v7_preference\">v7 preference Support Library</string>\n    <string name=\"about_android_support_license\">Apache License 2.0, The Android Open Source Project</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/res/values-cs/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<resources>\n    <string name=\"lib_name\">microG UI Tools</string>\n    <string name=\"lib_license\">Apache License 2.0, microG Team</string>\n\n    <string name=\"about_version_str\">Verze %1$s</string>\n    <string name=\"about_name_version_str\">%1$s %2$s</string>\n    <string name=\"about_default_license\">Všechna práva vyhrazena.</string>\n\n    <string name=\"prefcat_setup\">Nastavení</string>\n\n    <string name=\"self_check_title\">Vlastní kontrola</string>\n    <string name=\"self_check_desc\">Zkontrolovat, zda je systém správně nastaven pro používání microG.</string>\n\n    <string name=\"self_check_cat_permissions\">Udělená oprávnění</string>\n    <string name=\"self_check_name_permission\">Oprávnění „%1$s“:</string>\n    <string name=\"self_check_resolution_permission\">Klepěte sem pro udělení oprávnění. Neudělení oprávnění může mít za výsledek nesprávně fungující aplikace.</string>\n\n    <string name=\"about_root_title\">microG UI Demo</string>\n    <string name=\"about_root_summary\">Souhrn</string>\n    <string name=\"about_root_version\">Verze v0.1.0</string>\n    <string name=\"about_root_libraries\">Zahrnuté knihovny</string>\n\n    <string name=\"about_android_support_v4\">v4 Support Library</string>\n    <string name=\"about_android_support_v7_appcompat\">v7 appcompat Support Library</string>\n    <string name=\"about_android_support_v7_preference\">v7 preference Support Library</string>\n    <string name=\"about_android_support_license\">Apache License 2.0, The Android Open Source Project</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/res/values-de/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<resources>\n    <string name=\"lib_name\">microG UI Tools</string>\n    <string name=\"lib_license\">Apache License 2.0, microG Team</string>\n\n    <string name=\"about_version_str\">Version %1$s</string>\n    <string name=\"about_name_version_str\">%1$s %2$s</string>\n    <string name=\"about_default_license\">Alle Rechte vorbehalten.</string>\n\n    <string name=\"prefcat_setup\">Einrichtung</string>\n\n    <string name=\"self_check_title\">Selbstprüfung</string>\n    <string name=\"self_check_desc\">Prüft, ob das System zur Nutzung von microG konfiguriert ist.</string>\n\n    <string name=\"self_check_cat_permissions\">Erteilte Berechtigungen</string>\n    <string name=\"self_check_name_permission\">%1$s:</string>\n    <string name=\"self_check_resolution_permission\">Hier drücken, um die Berechtigung zu erteilen. Verweigern einer Berechtigung kann zu Fehlverhalten in anderen Anwendungen führen.</string>\n\n    <string name=\"about_root_title\">microG UI Demo</string>\n    <string name=\"about_root_summary\">Zusammenfassung</string>\n    <string name=\"about_root_version\">Version v0.1.0</string>\n    <string name=\"about_root_libraries\">Genutzte Bibliotheken</string>\n\n    <string name=\"about_android_support_v4\">v4 Support Library</string>\n    <string name=\"about_android_support_v7_appcompat\">v7 appcompat Support Library</string>\n    <string name=\"about_android_support_v7_preference\">v7 preference Support Library</string>\n    <string name=\"about_android_support_license\">Apache License 2.0, The Android Open Source Project</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/res/values-eo/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<resources>\n    </resources>\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/res/values-es/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2020 microG Project Team\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<resources>\n    <string name=\"lib_name\">Herramientas de IU de microG</string>\n    <string name=\"lib_license\">Apache License 2.0, Equipo de microG</string>\n\n    <string name=\"about_version_str\">Versión %1$s</string>\n    <string name=\"about_name_version_str\">%1$s %2$s</string>\n    <string name=\"about_default_license\">Todos los derechos reservados.</string>\n\n    <string name=\"prefcat_setup\">Configuración</string>\n\n    <string name=\"self_check_title\">Autocomprobación</string>\n    <string name=\"self_check_desc\">Comprueba si el sistema está correctamente configurado para usar microG.</string>\n\n    <string name=\"self_check_cat_permissions\">Permisos concedidos</string>\n    <string name=\"self_check_name_permission\">Permiso para %1$s:</string>\n    <string name=\"self_check_resolution_permission\">Toque aquí para conceder el permiso. No conceder el permiso puede resultar en comportamientos incorrectos de las aplicaciones.</string>\n\n    <string name=\"about_root_title\">Demo de IU de microG</string>\n    <string name=\"about_root_summary\">Resumen</string>\n    <string name=\"about_root_version\">Versión v0.1.0</string>\n    <string name=\"about_root_libraries\">Librerías incluidas</string>\n\n    <string name=\"about_android_support_v4\">v4 Support Library</string>\n    <string name=\"about_android_support_v7_appcompat\">v7 appcompat Support Library</string>\n    <string name=\"about_android_support_v7_preference\">v7 preference Support Library</string>\n    <string name=\"about_android_support_license\">Apache License 2.0, The Android Open Source Project</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/res/values-fil/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<resources>\n    <string name=\"lib_name\">microG UI Tools</string>\n    <string name=\"lib_license\">Apache License 2.0, microG Team</string>\n\n    <string name=\"about_version_str\">Bersyon %1$s</string>\n    <string name=\"about_name_version_str\">%1$s %2$s</string>\n    <string name=\"about_default_license\">Nakalaan ang lahat ng karapatan.</string>\n\n    <string name=\"prefcat_setup\">Setup</string>\n\n    <string name=\"self_check_title\">Sariling Pagsusuri</string>\n    <string name=\"self_check_desc\">Tignan kung tamang na-set up ang system para magamit ang microG</string>\n\n    <string name=\"self_check_cat_permissions\">Mga ibinigay na pahintulot</string>\n    <string name=\"self_check_name_permission\">Pahintulot na %1$s:</string>\n    <string name=\"self_check_name_permission_interact_across_profiles\">Pahintulot na mag-interact sa profile sa trabaho:</string>\n    <string name=\"self_check_resolution_permission\">Pindutin dito para ibigay ang pahintulot. Ang hindi pagbigay ng pahintulot ay maaaring magresulta sa maling pag-uugali ng mga application.</string>\n\n    <string name=\"about_root_title\">microG UI Demo</string>\n    <string name=\"about_root_summary\">Pangkalahatang ideya</string>\n    <string name=\"about_root_version\">Bersyon v0.1.0</string>\n    <string name=\"about_root_libraries\">Mga kasamang library</string>\n\n    <string name=\"about_android_support_v4\">v4 Support Library</string>\n    <string name=\"about_android_support_v7_appcompat\">v7 appcompat Support Library</string>\n    <string name=\"about_android_support_v7_preference\">v7 preference Support Library</string>\n    <string name=\"about_android_support_license\">Apache License 2.0, The Android Open Source Project</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/res/values-fr/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<resources>\n    <string name=\"lib_name\">microG UI Tools</string>\n    <string name=\"lib_license\">Apache License 2.0, microG Team</string>\n\n    <string name=\"about_version_str\">Version %1$s</string>\n    <string name=\"about_name_version_str\">%1$s %2$s</string>\n    <string name=\"about_default_license\">Tous droits réservés.</string>\n\n    <string name=\"prefcat_setup\">Configuration</string>\n\n    <string name=\"self_check_title\">Auto-vérification.</string>\n    <string name=\"self_check_desc\">Vérifier si le système est correctement configuré pour utiliser microG.</string>\n\n    <string name=\"self_check_cat_permissions\">Autorisations accordées</string>\n    <string name=\"self_check_name_permission\">Autorisation à %1$s :</string>\n    <string name=\"self_check_resolution_permission\">Touchez ici pour accorder l’autorisation. Des applications peuvent mal se comporter si vous ne le faites pas.</string>\n\n    <string name=\"about_root_version\">Version v0.1.0</string>\n    <string name=\"about_root_libraries\">Librairies incluses</string>\n\n    <string name=\"about_android_support_v4\">v4 Support Library</string>\n    <string name=\"about_android_support_v7_appcompat\">v7 appcompat Support Library</string>\n    <string name=\"about_android_support_v7_preference\">v7 preference Support Library</string>\n    <string name=\"about_android_support_license\">Apache License 2.0, The Android Open Source Project</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/res/values-it/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<resources>\n    <string name=\"lib_name\">Strumenti interfaccia utente di microG</string>\n    <string name=\"lib_license\">Licenza Apache 2.0, team di microG</string>\n\n    <string name=\"about_version_str\">Versione %1$s</string>\n    <string name=\"about_name_version_str\">%1$s %2$s</string>\n    <string name=\"about_default_license\">Tutti i diritti sono riservati.</string>\n\n    <string name=\"prefcat_setup\">Configurazione</string>\n\n    <string name=\"self_check_title\">Controllo dei problemi</string>\n    <string name=\"self_check_desc\">Verifica se il sistema è correttamente configurato per utilizzare microG.</string>\n\n    <string name=\"self_check_cat_permissions\">Autorizzazioni concesse</string>\n    <string name=\"self_check_name_permission\">%1$s:</string>\n    <string name=\"self_check_resolution_permission\">Tocca qui per concedere l\\'autorizzazione. Negare l\\'autorizzazione può comportare il funzionamento anomalo di altre applicazioni.</string>\n\n    <string name=\"about_root_title\">microG UI Demo</string>\n    <string name=\"about_root_summary\">Riepilogo</string>\n    <string name=\"about_root_version\">Versione v0.1.0</string>\n    <string name=\"about_root_libraries\">Librerie incluse</string>\n\n    <string name=\"about_android_support_v4\">v4 Support Library</string>\n    <string name=\"about_android_support_v7_appcompat\">v7 appcompat Support Library</string>\n    <string name=\"about_android_support_v7_preference\">v7 preference Support Library</string>\n    <string name=\"about_android_support_license\">Licenza Apache 2.0, The Android Open Source Project</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/res/values-ja/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<resources>\n    <string name=\"lib_name\">microG UIツール</string>\n    <string name=\"lib_license\">Apache License 2.0, microGチーム</string>\n\n    <string name=\"about_version_str\">バージョン %1$s</string>\n    <string name=\"about_name_version_str\">%1$s %2$s</string>\n    <string name=\"about_default_license\">All rights reserved.</string>\n\n    <string name=\"prefcat_setup\">設定</string>\n\n    <string name=\"self_check_title\">セルフチェック</string>\n    <string name=\"self_check_desc\">システムがmicroGを使用するよう正しく設定されているか確認します。</string>\n\n    <string name=\"self_check_cat_permissions\">権限付与</string>\n    <string name=\"self_check_name_permission\">%1$sの権限:</string>\n    <string name=\"self_check_name_permission_interact_across_profiles\">仕事用プロファイルを操作する権限:</string>\n    <string name=\"self_check_resolution_permission\">ここをタップして権限を付与してください。 権限を付与しないと、アプリが正しく動作しない可能性があります。</string>\n\n    <string name=\"about_root_title\">microG UIデモ</string>\n    <string name=\"about_root_summary\">概要</string>\n    <string name=\"about_root_version\">バージョン v0.1.0</string>\n    <string name=\"about_root_libraries\">使用されているライブラリ</string>\n\n    <string name=\"about_android_support_v4\">v4 Support Library</string>\n    <string name=\"about_android_support_v7_appcompat\">v7 appcompat Support Library</string>\n    <string name=\"about_android_support_v7_preference\">v7 preference Support Library</string>\n    <string name=\"about_android_support_license\">Apache License 2.0, The Android Open Source Project</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/res/values-pl/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<resources>\n    <string name=\"lib_name\">Narzędzia UI microG</string>\n    <string name=\"lib_license\">Licencja Apache 2.0, Zespół microG</string>\n\n    <string name=\"about_version_str\">Wersja %1$s</string>\n    <string name=\"about_name_version_str\">%1$s %2$s</string>\n    <string name=\"about_default_license\">Wszelkie prawa zastrzeżone.</string>\n\n    <string name=\"prefcat_setup\">Ustawienia</string>\n\n    <string name=\"self_check_title\">Samo-sprawdzenie</string>\n    <string name=\"self_check_desc\">Sprawdza, czy system jest poprawnie skonfigurowany do korzystania z microG.</string>\n\n    <string name=\"self_check_cat_permissions\">Udzielono uprawnień</string>\n    <string name=\"self_check_name_permission\">Uprawnienie do %1$s:</string>\n    <string name=\"self_check_resolution_permission\">Stuknij, aby udzielić uprawnienia. Nieudzielenie uprawnienia może powodować problemy z aplikacjami.</string>\n\n    <string name=\"about_root_title\">Demo microG UI</string>\n    <string name=\"about_root_summary\">Podsumowanie</string>\n    <string name=\"about_root_version\">Wersja v0.1.0</string>\n    <string name=\"about_root_libraries\">Użyte biblioteki</string>\n\n    <string name=\"about_android_support_license\">Licencja Apache 2.0, The Android Open Source Project</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/res/values-pt-rBR/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<resources>\n    <string name=\"lib_name\">Ferramentas de UI do microG</string>\n    <string name=\"lib_license\">Licença \"Apache 2.0\", Equipe do microG</string>\n\n    <string name=\"about_version_str\">Versão %1$s</string>\n    <string name=\"about_name_version_str\">%1$s %2$s</string>\n    <string name=\"about_default_license\">Todos os direitos reservados.</string>\n\n    <string name=\"prefcat_setup\">Configuração</string>\n\n    <string name=\"self_check_title\">Auto-verificação</string>\n    <string name=\"self_check_desc\">Verifique se o sistema está configurado corretamente para usar o microG.</string>\n\n    <string name=\"self_check_cat_permissions\">Permissões concedidas</string>\n    <string name=\"self_check_name_permission\">Permissão para %1$s:</string>\n    <string name=\"self_check_name_permission_interact_across_profiles\">Permissão para interagir com perfil de trabalho:</string>\n    <string name=\"self_check_resolution_permission\">Toque aqui para conceder esta permissão. Não conceder esta permissão pode resultar em aplicativos com mal comportamento.</string>\n\n    <string name=\"about_root_title\">Demo de UI do microG</string>\n    <string name=\"about_root_summary\">Resumo</string>\n    <string name=\"about_root_version\">Versão v0.1.0</string>\n    <string name=\"about_root_libraries\">Bibliotecas inclusas</string>\n\n    <string name=\"about_android_support_v4\">Biblioteca de suporte v4</string>\n    <string name=\"about_android_support_v7_appcompat\">Biblioteca de suporte v7 appcompat</string>\n    <string name=\"about_android_support_v7_preference\">Biblioteca de suporte v7 preferences</string>\n    <string name=\"about_android_support_license\">Licença \"Apache 2.0\", Android Open Source Project</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/res/values-ro/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<resources>\n    <string name=\"lib_name\">Instrumente microG UI</string>\n    <string name=\"lib_license\">Apache License 2.0, Echipa microG</string>\n\n    <string name=\"about_version_str\">Versiune %1$s</string>\n    <string name=\"about_default_license\">Toate drepturile rezervate.</string>\n\n    <string name=\"prefcat_setup\">Configurare</string>\n\n    <string name=\"self_check_title\">Autoverificare</string>\n    <string name=\"self_check_desc\">Verifică dacă sistemul este configurat corect pentru a utiliza microG.</string>\n\n    <string name=\"self_check_cat_permissions\">Permisiunile acordate</string>\n    <string name=\"self_check_name_permission\">Permisiunea %1$s:</string>\n    <string name=\"self_check_name_permission_interact_across_profiles\">Permisiunea de a interacționa cu profilul de serviciu:</string>\n    <string name=\"self_check_resolution_permission\">Atinge aici pentru a acorda permisiunea. Neacordarea permisiunii poate duce la un comportament necorespunzător al aplicațiilor.</string>\n\n    <string name=\"about_root_title\">Demo microG UI</string>\n    <string name=\"about_root_summary\">Sumar</string>\n    <string name=\"about_root_version\">Versiune v0.1.0</string>\n    <string name=\"about_root_libraries\">Biblioteci incluse</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/res/values-ru/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2020 microG Project Team\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<resources>\n    <string name=\"lib_name\">microG UI Tools</string>\n    <string name=\"lib_license\">Apache License 2.0, microG Team</string>\n\n    <string name=\"about_version_str\">Версия %1$s</string>\n    <string name=\"about_name_version_str\">%1$s %2$s</string>\n    <string name=\"about_default_license\">Все права защищены.</string>\n\n    <string name=\"prefcat_setup\">Установить</string>\n\n    <string name=\"self_check_title\">Работоспособность</string>\n    <string name=\"self_check_desc\">Проверьте, правильно ли настроена система для использования microG.</string>\n\n    <string name=\"self_check_cat_permissions\">Права доступа предоставлены</string>\n    <!-- it's better if the next line stays like this -->\n    <string name=\"self_check_name_permission\">%1$s:</string>\n    <string name=\"self_check_resolution_permission\">Коснитесь, чтобы предоставить разрешение. Отсутствующее разрешение может привести к некорректной работе приложения.</string>\n\n    <string name=\"about_root_title\">microG UI Demo</string>\n    <string name=\"about_root_summary\">Подробности</string>\n    <string name=\"about_root_version\">Версия v0.1.0</string>\n    <string name=\"about_root_libraries\">Используемые библиотеки</string>\n\n    <string name=\"about_android_support_v4\">v4 Support Library</string>\n    <string name=\"about_android_support_v7_appcompat\">v7 appcompat Support Library</string>\n    <string name=\"about_android_support_v7_preference\">v7 preference Support Library</string>\n    <string name=\"about_android_support_license\">Apache License 2.0, The Android Open Source Project</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/res/values-sr/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<resources>\n    <string name=\"prefcat_setup\">Поставка</string>\n\n    <string name=\"self_check_title\">микроГ самопровера</string>\n    <string name=\"self_check_desc\">Провера исправности подешавања система за коришћење микроГ услуга.</string>\n\n    <string name=\"self_check_cat_permissions\">Дозволе одобрене</string>\n    <string name=\"self_check_name_permission\">Дозволе за %1$s:</string>\n    <string name=\"self_check_resolution_permission\">Тапните овде да одобрите дозволе. Не одобравање дозвола може да резултира чудним понашањем апликација.</string>\n\n    </resources>\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/res/values-th/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<resources>\n    <string name=\"lib_name\">เครื่องมือส่วนต่อประสานกับผู้ใช้ของ microG</string>\n    <string name=\"lib_license\">Apache License 2.0, ทีม microG</string>\n\n    <string name=\"about_version_str\">เวอร์ชัน %1$s</string>\n    <string name=\"about_name_version_str\">%1$s %2$s</string>\n    <string name=\"about_default_license\">สงวนลิขสิทธิ์ทุกประการ</string>\n\n    <string name=\"prefcat_setup\">ตั้งค่า</string>\n\n    <string name=\"self_check_title\">โมดูลการตรวจสอบด้วยตนเอง</string>\n    <string name=\"self_check_desc\">ตรวจสอบว่าระบบได้รับการตั้งค่าอย่างถูกต้องเพื่อใช้งาน microG หรือไม่</string>\n\n    <string name=\"self_check_cat_permissions\">ได้รับสิทธิ์แล้ว</string>\n    <string name=\"self_check_name_permission\">สิทธิ์ในการเข้าถึง %1$s:</string>\n    <string name=\"self_check_name_permission_interact_across_profiles\">สิทธิ์ในการโต้ตอบกับโปรไฟล์งานของบริษัท:</string>\n    <string name=\"self_check_resolution_permission\">แตะที่นี้เพื่อทำการให้สิทธิ์ การไม่ให้สิทธิ์อาจจะส่งผลให้เกิดพฤติกรรมไม่เหมาะสม</string>\n\n    <string name=\"about_root_title\">สาธิตส่วนต่อประสานกับผู้ใช้ของ microG</string>\n    <string name=\"about_root_summary\">สรุป</string>\n    <string name=\"about_root_version\">เวอร์ชัน v0.1.0</string>\n    <string name=\"about_root_libraries\">ไลบรารีสนับสนุน</string>\n\n    <string name=\"about_android_support_v4\">ไลบรารีสนับสนุนเวอร์ชัน 4</string>\n    <string name=\"about_android_support_v7_appcompat\">ไลบรารีสนับสนุน appcompat เวอร์ชัน 7</string>\n    <string name=\"about_android_support_v7_preference\">ไลบรารีสนับสนุนการตั้งค่า เวอร์ชัน 7</string>\n    <string name=\"about_android_support_license\">Apache License 2.0, The Android Open Source Project</string>\n</resources>"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/res/values-tr/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<resources>\n    <string name=\"lib_name\">microG UI Araçları</string>\n    <string name=\"lib_license\">Apache Lisansı 2.0, microG Ekibi</string>\n\n    <string name=\"about_version_str\">Sürüm %1$s</string>\n    <string name=\"about_name_version_str\">%1$s %2$s</string>\n    <string name=\"about_default_license\">Tüm hakları saklıdır.</string>\n\n    <string name=\"prefcat_setup\">Kurulum</string>\n\n    <string name=\"self_check_title\">Çalışma durumu</string>\n    <string name=\"self_check_desc\">microG\\'yi kullanmak için sistemin doğru şekilde ayarlanıp ayarlanmadığını kontrol edin.</string>\n\n    <string name=\"self_check_cat_permissions\">Verilen izinler</string>\n    <string name=\"self_check_name_permission\">%1$s izni:</string>\n    <string name=\"self_check_resolution_permission\">Buraya dokunarak izin verin. İznin verilmemesi uygulamaların hatalı davranmasına neden olabilir.</string>\n\n    <string name=\"about_root_title\">microG UI Demosu</string>\n    <string name=\"about_root_summary\">Özet</string>\n    <string name=\"about_root_version\">Sürüm v0.1.0</string>\n    <string name=\"about_root_libraries\">Dahil olan kütüphaneler</string>\n\n    <string name=\"about_android_support_v4\">v4 Support Library</string>\n    <string name=\"about_android_support_v7_appcompat\">v7 appcompat Support Library</string>\n    <string name=\"about_android_support_v7_preference\">v7 preference Support Library</string>\n    <string name=\"about_android_support_license\">Apache Lisansı 2.0, Android Open Source Project</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/res/values-uk/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<resources>\n    <string name=\"lib_name\">microG UI Tools</string>\n    <string name=\"lib_license\">Apache License 2.0, microG Team</string>\n\n    <string name=\"about_version_str\">Версія %1$s</string>\n    <string name=\"about_name_version_str\">%1$s %2$s</string>\n    <string name=\"about_default_license\">Всі права захищено.</string>\n\n    <string name=\"prefcat_setup\">Налаштування</string>\n\n    <string name=\"self_check_title\">Само-тестування</string>\n    <string name=\"self_check_desc\">Перевірка, чи належним чином система використовує microG.</string>\n\n    <string name=\"self_check_cat_permissions\">Доступ надано</string>\n    <string name=\"self_check_name_permission\">Доступ до %1$s:</string>\n    <string name=\"self_check_resolution_permission\">Торкніться, аби надати доступ. Без доступу не гарантується робота додатку належним чином.</string>\n\n    <string name=\"about_root_title\">Демонстрація microG UI</string>\n    <string name=\"about_root_summary\">Резюме</string>\n    <string name=\"about_root_version\">Версія v0.1.0</string>\n    <string name=\"about_root_libraries\">Використані бібліотеки</string>\n\n    <string name=\"about_android_support_v4\">v4 Support Library</string>\n    <string name=\"about_android_support_v7_appcompat\">v7 appcompat Support Library</string>\n    <string name=\"about_android_support_v7_preference\">v7 preference Support Library</string>\n    <string name=\"about_android_support_license\">Apache License 2.0, The Android Open Source Project</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/res/values-vi/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<resources>\r\n    <string name=\"lib_name\">Công cụ giao diện microG</string>\r\n    <string name=\"lib_license\">Giấy phép Apache 2.0, nhóm microG</string>\r\n\r\n    <string name=\"about_version_str\">Phiên bản %1$s</string>\r\n    <string name=\"about_name_version_str\">%1$s %2$s</string>\r\n    <string name=\"about_default_license\">Đã đăng ký bản quyền.</string>\r\n\r\n    <string name=\"prefcat_setup\">Thiết lập</string>\r\n\r\n    <string name=\"self_check_title\">Tự kiểm tra</string>\r\n    <string name=\"self_check_desc\">Kiểm tra xem hệ thống của bạn đã sẵn sàng để dùng microG chưa.</string>\r\n\r\n    <string name=\"self_check_cat_permissions\">Cấp quyền</string>\r\n    <string name=\"self_check_name_permission\">Quyền %1$s:</string>\r\n    <string name=\"self_check_name_permission_interact_across_profiles\">Quyền tương tác với hồ sơ công việc:</string>\r\n    <string name=\"self_check_resolution_permission\">Chạm vào đây để cấp quyền. Nếu không, một số ứng dụng có thể chạy không ổn định.</string>\r\n\r\n    <string name=\"about_root_title\">Demo giao diện microG</string>\r\n    <string name=\"about_root_summary\">Giới thiệu</string>\r\n    <string name=\"about_root_version\">Phiên bản v0.1.0</string>\r\n    <string name=\"about_root_libraries\">Thư viện đi kèm</string>\r\n\r\n    <string name=\"about_android_support_v4\">Thư viện hỗ trợ v4</string>\r\n    <string name=\"about_android_support_v7_appcompat\">Thư viện hỗ trợ v7 appcompat</string>\r\n    <string name=\"about_android_support_v7_preference\">Thư viện hỗ trợ v7 preference</string>\r\n    <string name=\"about_android_support_license\">Giấy phép Apache 2.0, Dự án mã nguồn mở Android</string>\r\n</resources>\r\n"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/res/values-zh-rCN/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"lib_name\">microG UI Tools</string>\n    <string name=\"about_version_str\">版本 %1$s</string>\n    <string name=\"about_name_version_str\">%1$s %2$s</string>\n    <string name=\"about_default_license\">保留所有权利。</string>\n    <string name=\"prefcat_setup\">设置</string>\n    <string name=\"self_check_title\">自我检查</string>\n    <string name=\"self_check_desc\">确认系统是否已正确配置成 microG 可正常使用的状态</string>\n    <string name=\"self_check_cat_permissions\">已授予权限</string>\n    <string name=\"self_check_name_permission\">%1$s的权限：</string>\n    <string name=\"self_check_name_permission_interact_across_profiles\">与工作配置文件交互的权限：</string>\n    <string name=\"self_check_resolution_permission\">点击授予权限。不授予权限可能导致应用工作异常。</string>\n    <string name=\"about_root_libraries\">包含的库</string>\n    <string name=\"about_root_summary\">概要</string>\n</resources>"
  },
  {
    "path": "play-services-core/microg-ui-tools/src/main/res/values-zh-rTW/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<resources>\n    <string name=\"lib_name\">microG UI Tools</string>\n    <string name=\"lib_license\">Apache License 2.0, microG 團隊</string>\n\n    <string name=\"about_version_str\">版本 %1$s</string>\n    <string name=\"about_name_version_str\">%1$s %2$s</string>\n    <string name=\"about_default_license\">保留所有權利。</string>\n\n    <string name=\"prefcat_setup\">設定</string>\n\n    <string name=\"self_check_title\">自我檢查</string>\n    <string name=\"self_check_desc\">確認系統是否已正確配置以使用 microG。</string>\n\n    <string name=\"self_check_cat_permissions\">允許權限</string>\n    <string name=\"self_check_name_permission\">允許 %1$s 的權限：</string>\n    <string name=\"self_check_resolution_permission\">點擊這裡以授權。未授權可能影響程式正常運作。</string>\n\n    <string name=\"about_root_title\">microG UI Demo</string>\n    <string name=\"about_root_summary\">大綱</string>\n    <string name=\"about_root_version\">版本 v0.1.0</string>\n    <string name=\"about_root_libraries\">包含的函式庫</string>\n\n    <string name=\"about_android_support_v4\">v4 Support Library</string>\n    <string name=\"about_android_support_v7_appcompat\">v7 appcompat Support Library</string>\n    <string name=\"about_android_support_v7_preference\">v7 preference Support Library</string>\n    <string name=\"about_android_support_license\">Apache License 2.0, The Android Open Source Project</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/multidex-keep.pro",
    "content": "# Make sure maps is in the primary dex file\n-keep class com.google.android.gms.maps.** { *; }\n-keep class org.microg.gms.maps.** { *; }\n-keep class com.mapbox.** { *; }\n-keep class org.oscim.** { *; }\n\n# Keep Dynamite Loader in the primary dex file otherwise it will error out on legacy Android versions\n-keep class com.google.android.gms.chimera.container.DynamiteLoaderImpl { *; }\n\n# Keep Conscrypt in the primary dex file otherwise it will error out on legacy Android versions\n-keep class com.google.android.gms.common.security.ProviderInstallerImpl { *; }\n-keep class com.google.android.gms.org.conscrypt.** { *; }\n"
  },
  {
    "path": "play-services-core/src/huawei/AndroidManifest.xml",
    "content": "<!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <application>\n        <meta-data\n            android:name=\"org.microg.gms.settings.checkin_enable_service\"\n            android:value=\"true\" />\n        <meta-data\n            android:name=\"org.microg.gms.settings.gcm_enable_mcs_service\"\n            android:value=\"true\" />\n        <meta-data\n            android:name=\"org.microg.gms.settings.auth_manager_visible\"\n            android:value=\"true\" />\n        <meta-data\n            android:name=\"org.microg.gms.settings.auth_include_android_id\"\n            android:value=\"false\" />\n        <meta-data\n            android:name=\"org.microg.gms.settings.auth_strip_device_name\"\n            android:value=\"true\" />\n        <meta-data\n            android:name=\"org.microg.gms.settings.auth_two_step_verification\"\n            android:value=\"true\" />\n        <meta-data\n            android:name=\"org.microg.gms.settings.droidguard_enabled\"\n            android:value=\"true\" />\n        <meta-data\n            android:name=\"org.microg.gms.settings.safetynet_enabled\"\n            android:value=\"true\" />\n        <meta-data\n            android:name=\"org.microg.gms.settings.vending_billing\"\n            android:value=\"true\" />\n        <meta-data\n            android:name=\"org.microg.gms.settings.vending_licensing_purchase_free_apps\"\n            android:value=\"true\" />\n        <meta-data\n            android:name=\"org.microg.gms.settings.vending_licensing\"\n            android:value=\"true\" />\n        <meta-data\n            android:name=\"org.microg.gms.settings.vending_asset_delivery\"\n            android:value=\"true\" />\n        <meta-data\n            android:name=\"org.microg.gms.settings.vending_device_sync\"\n            android:value=\"true\" />\n        <meta-data\n            android:name=\"org.microg.gms.settings.vending_split_install\"\n            android:value=\"false\" />\n        <meta-data\n            android:name=\"org.microg.gms.settings.game_allow_create_player\"\n            android:value=\"true\" />\n        <meta-data\n            android:name=\"org.microg.gms.settings.allow_upload_game_played\"\n            android:value=\"true\" />\n        <meta-data\n            android:name=\"org.microg.gms.settings.vending_apps_install\"\n            android:value=\"true\" />\n    </application>\n</manifest>"
  },
  {
    "path": "play-services-core/src/huaweilh/AndroidManifest.xml",
    "content": "<!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <application>\n        <meta-data\n            android:name=\"org.microg.gms.settings.checkin_enable_service\"\n            android:value=\"true\" />\n        <meta-data\n            android:name=\"org.microg.gms.settings.gcm_enable_mcs_service\"\n            android:value=\"true\" />\n        <meta-data\n            android:name=\"org.microg.gms.settings.auth_manager_visible\"\n            android:value=\"true\" />\n        <meta-data\n            android:name=\"org.microg.gms.settings.auth_include_android_id\"\n            android:value=\"false\" />\n        <meta-data\n            android:name=\"org.microg.gms.settings.auth_strip_device_name\"\n            android:value=\"true\" />\n        <meta-data\n            android:name=\"org.microg.gms.settings.auth_two_step_verification\"\n            android:value=\"true\" />\n        <meta-data\n            android:name=\"org.microg.gms.settings.droidguard_enabled\"\n            android:value=\"true\" />\n        <meta-data\n            android:name=\"org.microg.gms.settings.safetynet_enabled\"\n            android:value=\"true\" />\n        <meta-data\n            android:name=\"org.microg.gms.settings.vending_billing\"\n            android:value=\"true\" />\n        <meta-data\n            android:name=\"org.microg.gms.settings.vending_licensing\"\n            android:value=\"true\" />\n\n        <activity-alias\n            android:name=\"org.microg.gms.ui.SettingsActivity\"\n            android:targetActivity=\"org.microg.gms.ui.MainSettingsActivity\"\n            tools:node=\"remove\" />\n\n        <activity-alias\n            android:name=\"org.lighthouse.SettingsActivity\"\n            android:icon=\"@mipmap/ic_app_settings\"\n            android:label=\"@string/gms_settings_name\"\n            android:roundIcon=\"@mipmap/ic_app_settings\"\n            android:process=\":ui\"\n            android:targetActivity=\"org.microg.gms.ui.MainSettingsActivity\"\n            android:taskAffinity=\"org.microg.gms.settings\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity-alias>\n    </application>\n</manifest>"
  },
  {
    "path": "play-services-core/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ Copyright (C) 2013-2019 microG Project Team\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<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <permission\n        android:name=\"com.google.android.providers.gsf.permission.READ_GSERVICES\"\n        android:label=\"@string/perm_gsf_read_gservices_label\"\n        android:protectionLevel=\"normal\" />\n    <permission\n        android:name=\"com.google.android.c2dm.permission.RECEIVE\"\n        android:label=\"@string/perm_c2dm_receive_label\"\n        android:permissionGroup=\"android.permission-group.NETWORK\"\n        android:protectionLevel=\"normal\" />\n    <permission\n        android:name=\"com.google.android.c2dm.permission.SEND\"\n        android:label=\"@string/perm_c2dm_send_label\"\n        android:permissionGroup=\"android.permission-group.NETWORK\"\n        android:protectionLevel=\"privileged|signature\" />\n    <permission\n        android:name=\"com.google.android.gtalkservice.permission.GTALK_SERVICE\"\n        android:label=\"@string/perm_gtalk_svc_label\"\n        android:permissionGroup=\"android.permission-group.MESSAGES\"\n        android:protectionLevel=\"signature\" />\n\n    <permission-tree\n        android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH\"\n        android:icon=\"@drawable/proprietary_auth_ic_scope_icon_default\" />\n\n    <permission\n        android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.cp\"\n        android:description=\"@string/permission_service_cp_description\"\n        android:label=\"@string/permission_service_cp_label\"\n        android:protectionLevel=\"dangerous\" />\n    <permission\n        android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.local\"\n        android:description=\"@string/permission_service_local_description\"\n        android:label=\"@string/permission_service_local_label\"\n        android:protectionLevel=\"dangerous\" />\n    <permission\n        android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.mail\"\n        android:description=\"@string/permission_service_mail_description\"\n        android:label=\"@string/permission_service_mail_label\"\n        android:protectionLevel=\"dangerous\" />\n    <permission\n        android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.writely\"\n        android:description=\"@string/permission_service_writely_description\"\n        android:label=\"@string/permission_service_writely_label\"\n        android:protectionLevel=\"dangerous\" />\n\n    <permission\n        android:name=\"com.google.android.gms.permission.ACTIVITY_RECOGNITION\"\n        android:label=\"@string/perm_activity_recognition_label\"\n        android:description=\"@string/perm_activity_recognition_description\"\n        android:protectionLevel=\"normal\" />\n\n    <permission\n        android:name=\"com.google.android.gms.permission.AD_ID\"\n        android:label=\"@string/perm_ad_id_label\"\n        android:description=\"@string/perm_ad_id_description\"\n        android:protectionLevel=\"normal\" />\n    <permission\n        android:name=\"com.google.android.gms.permission.AD_ID_NOTIFICATION\"\n        android:label=\"@string/perm_ad_id_notification_label\"\n        android:description=\"@string/perm_ad_id_notification_description\"\n        android:protectionLevel=\"normal\" />\n\n\n    <permission\n        android:name=\"com.google.android.gms.auth.api.phone.permission.SEND\"\n        android:protectionLevel=\"signature\" />\n\n    <permission\n        android:name=\"org.microg.gms.STATUS_BROADCAST\"\n        android:label=\"@string/perm_status_broadcast_label\"\n        android:protectionLevel=\"normal\" />\n    <permission\n        android:name=\"org.microg.gms.EXTENDED_ACCESS\"\n        android:label=\"@string/perm_extended_access_label\"\n        android:protectionLevel=\"dangerous\" />\n    <permission\n        android:name=\"org.microg.gms.PROVISION\"\n        android:description=\"@string/perm_provision_description\"\n        android:label=\"@string/perm_provision_label\"\n        android:protectionLevel=\"privileged|signature\" />\n\n    <permission\n        android:name=\"com.google.android.gms.permission.CAR_SPEED\"\n        android:label=\"@string/perm_car_speed_label\"\n        android:description=\"@string/perm_car_speed_description\"\n        android:permissionGroup=\"android.permission-group.LOCATION\"\n        android:protectionLevel=\"dangerous\" />\n\n    <permission-group\n        android:name=\"com.google.android.gms.permission.CAR_INFORMATION\"\n        android:label=\"@string/perm_car_info_label\"\n        android:description=\"@string/perm_car_info_description\" />\n    <permission\n        android:name=\"com.google.android.gms.permission.CAR_FUEL\"\n        android:label=\"@string/perm_car_fuel_label\"\n        android:description=\"@string/perm_car_fuel_description\"\n        android:permissionGroup=\"com.google.android.gms.permission.CAR_INFORMATION\"\n        android:protectionLevel=\"dangerous\" />\n    <permission\n        android:name=\"com.google.android.gms.permission.CAR_MILEAGE\"\n        android:label=\"@string/perm_car_mileage_label\"\n        android:description=\"@string/perm_car_mileage_description\"\n        android:permissionGroup=\"com.google.android.gms.permission.CAR_INFORMATION\"\n        android:protectionLevel=\"dangerous\" />\n    <permission\n        android:name=\"com.google.android.gms.permission.CAR_VENDOR_EXTENSION\"\n        android:label=\"@string/perm_car_vendor_extension_label\"\n        android:description=\"@string/perm_car_vendor_extension_description\"\n        android:permissionGroup=\"com.google.android.gms.permission.CAR_INFORMATION\"\n        android:protectionLevel=\"dangerous\" />\n    <permission\n        android:name=\"com.google.android.gms.locationsharingreporter.periodic.STATUS_UPDATE\"\n        android:protectionLevel=\"signature\"/>\n    <uses-permission android:name=\"com.google.android.gms.locationsharingreporter.periodic.STATUS_UPDATE\"/>\n\n    <permission\n        android:name=\"com.google.android.gms.auth.permission.GOOGLE_ACCOUNT_CHANGE\"\n        android:protectionLevel=\"signature\"/>\n    <uses-permission android:name=\"com.google.android.gms.auth.permission.GOOGLE_ACCOUNT_CHANGE\" />\n\n    <uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n    <uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\" />\n    <uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\" />\n    <uses-permission android:name=\"android.permission.ACCESS_BACKGROUND_LOCATION\" />\n    <uses-permission android:name=\"android.permission.READ_PHONE_STATE\" />\n\n    <uses-permission android:name=\"android.permission.AUTHENTICATE_ACCOUNTS\" />\n    <uses-permission android:name=\"android.permission.GET_ACCOUNTS\" />\n    <uses-permission android:name=\"android.permission.MANAGE_ACCOUNTS\" />\n    <uses-permission android:name=\"android.permission.USE_CREDENTIALS\" />\n    <uses-permission android:name=\"android.permission.WAKE_LOCK\" />\n    <uses-permission android:name=\"android.permission.READ_SYNC_SETTINGS\" />\n    <uses-permission android:name=\"android.permission.WRITE_SYNC_SETTINGS\" />\n    <uses-permission android:name=\"android.permission.READ_SYNC_STATS\" />\n    <uses-permission android:name=\"android.permission.READ_CONTACTS\" />\n    <uses-permission android:name=\"android.permission.POST_NOTIFICATIONS\" />\n\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" />\n    <uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\" />\n\n    <uses-permission android:name=\"com.google.android.c2dm.permission.RECEIVE\" />\n    <uses-permission android:name=\"com.google.android.c2dm.permission.SEND\" />\n    <uses-permission android:name=\"com.google.android.gtalkservice.permission.GTALK_SERVICE\" />\n    <uses-permission android:name=\"com.google.android.gms.auth.api.phone.permission.SEND\" />\n\n    <uses-permission android:name=\"org.microg.gms.STATUS_BROADCAST\" />\n\n    <uses-permission android:name=\"android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS\" />\n    <uses-permission android:name=\"android.permission.RECEIVE_BOOT_COMPLETED\" />\n    <uses-permission android:name=\"android.permission.FOREGROUND_SERVICE\" />\n    <uses-permission\n        android:name=\"android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.UPDATE_APP_OPS_STATS\"\n        tools:ignore=\"ProtectedPermissions\" />\n\n    <uses-permission android:name=\"android.permission.CAMERA\"/>\n    <uses-feature\n        android:name=\"android.hardware.camera\"\n        android:required=\"false\" />\n\n    <uses-sdk\n        tools:overrideLibrary=\"androidx.compose.ui.tooling,\n        androidx.compose.material3,\n        androidx.activity.compose,\n        androidx.compose.material.icons,\n        androidx.compose.material.ripple,\n        androidx.compose.foundation,\n        androidx.compose.animation,\n        androidx.compose.foundation.layout,\n        androidx.compose.animation.core,\n        androidx.compose.ui.unit,\n        androidx.compose.ui.geometry,\n        androidx.compose.ui.tooling.data,\n        androidx.compose.ui.util,\n        androidx.compose.ui.text,\n        androidx.compose.ui.graphics,\n        androidx.compose.ui.geometry,\n        androidx.compose.ui.tooling.preview,\n        androidx.compose.runtime.saveable,\n        org.opencv\"\n        />\n    <application\n        android:allowBackup=\"true\"\n        android:forceQueryable=\"true\"\n        android:fullBackupOnly=\"true\"\n        android:icon=\"@mipmap/ic_app\"\n        android:roundIcon=\"@mipmap/ic_app\"\n        android:label=\"${appLabel}\"\n        android:multiArch=\"true\"\n        android:networkSecurityConfig=\"@xml/network_security_config\"\n        android:theme=\"@style/Theme.App\">\n\n        <library android:name=\"com.google.android.gms\" />\n\n        <!-- Provision -->\n\n        <service\n            android:name=\"org.microg.gms.provision.ProvisionService\"\n            android:exported=\"true\"\n            android:permission=\"org.microg.gms.PROVISION\" />\n\n        <!-- Location -->\n\n        <activity\n            android:name=\"org.microg.gms.ui.PlacePickerActivity\"\n            android:exported=\"true\"\n            android:label=\"@string/pick_place_title\"\n            android:process=\":ui\"\n            android:theme=\"@style/Theme.AppCompat.DayNight.NoActionBar\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.location.places.ui.PICK_PLACE\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </activity>\n\n        <activity\n            android:name=\".locationsharingreporter.service.settings.LocationSharingSettingsActivity\"\n            android:enabled=\"true\"\n            android:process=\":ui\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"org.microg.gms.settings\"\n            android:exported=\"false\" />\n\n        <activity\n            android:name=\".locationsharingreporter.service.settings.LocationShareConfirmActivity\"\n            android:enabled=\"true\"\n            android:process=\":ui\"\n            android:theme=\"@style/ThemeTranslucentCommon\"\n            android:launchMode=\"singleInstance\"\n            android:excludeFromRecents=\"true\"\n            android:exported=\"false\" />\n\n        <service android:name=\"org.microg.gms.places.GeoDataService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.location.places.GeoDataApi\" />\n                <action android:name=\"com.google.android.gms.location.places.PlacesApi\" />\n            </intent-filter>\n        </service>\n\n        <service android:name=\"org.microg.gms.places.PlaceDetectionService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.location.places.PlaceDetectionApi\" />\n            </intent-filter>\n        </service>\n\n        <service android:name=\"org.microg.gms.wearable.location.WearableLocationService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.wearable.MESSAGE_RECEIVED\" />\n                <data\n                    android:host=\"*\"\n                    android:pathPrefix=\"/com/google/android/location/fused/wearable\"\n                    android:scheme=\"wear\" />\n            </intent-filter>\n        </service>\n\n        <!-- Services Framework -->\n\n        <provider\n            android:name=\"org.microg.gms.gservices.GServicesProvider\"\n            android:authorities=\"com.google.android.gsf.gservices\"\n            android:exported=\"true\" />\n        <provider\n            android:name=\"org.microg.gms.settings.GoogleSettingsProvider\"\n            android:authorities=\"com.google.settings\"\n            android:exported=\"true\" />\n        <provider\n            android:name=\"org.microg.gms.feeds.SubscribedFeedsProvider\"\n            android:authorities=\"subscribedfeeds\"\n            android:exported=\"true\"\n            android:multiprocess=\"false\"\n            android:readPermission=\"android.permission.SUBSCRIBED_FEEDS_READ\"\n            android:writePermission=\"android.permission.SUBSCRIBED_FEEDS_WRITE\" />\n        <provider\n            android:authorities=\"com.google.android.gms.fileprovider\"\n            android:name=\"org.microg.gms.settings.GmsFileProvider\"\n            android:exported=\"false\"\n            android:grantUriPermissions=\"true\">\n            <meta-data\n                android:name=\"android.support.FILE_PROVIDER_PATHS\"\n                android:resource=\"@xml/file_provider_paths\"/>\n        </provider>\n\n        <!-- Device Checkin -->\n\n        <service android:name=\"org.microg.gms.checkin.CheckinService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.checkin.BIND_TO_SERVICE\" />\n            </intent-filter>\n        </service>\n\n        <receiver android:name=\"org.microg.gms.checkin.TriggerReceiver\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.BOOT_COMPLETED\" />\n                <action android:name=\"android.intent.action.AIRPLANE_MODE\" />\n\n                <action android:name=\"android.server.checkin.CHECKIN\" />\n\n                <action android:name=\"android.intent.action.MY_PACKAGE_REPLACED\" />\n                <action android:name=\"android.intent.action.PACKAGE_RESTARTED\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"com.google.android.c2dm.intent.RECEIVE\" />\n\n                <category android:name=\"android.server.checkin.CHECKIN\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"android.provider.Telephony.SECRET_CODE\" />\n\n                <data\n                    android:host=\"2432546\"\n                    android:scheme=\"android_secret_code\" />\n            </intent-filter>\n        </receiver>\n\n        <!-- Cloud Messaging -->\n        <service\n            android:name=\"org.microg.gms.gcm.PushRegisterService\"\n            android:process=\":persistent\">\n            <intent-filter>\n                <action android:name=\"com.google.android.c2dm.intent.REGISTER\" />\n                <action android:name=\"com.google.android.c2dm.intent.UNREGISTER\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </service>\n\n        <receiver\n            android:name=\"org.microg.gms.gcm.PushRegisterReceiver\"\n            android:process=\":persistent\">\n            <intent-filter>\n                <action android:name=\"com.google.iid.TOKEN_REQUEST\" />\n            </intent-filter>\n        </receiver>\n\n        <service\n            android:name=\"org.microg.gms.gcm.McsService\"\n            android:process=\":persistent\" />\n\n        <service\n            android:name=\"org.microg.gms.gcm.GcmInGmsService\"\n            android:exported=\"false\"\n            android:process=\":persistent\"/>\n\n        <receiver\n            android:name=\"org.microg.gms.gcm.GcmRegistrationReceiver\"\n            android:exported=\"false\"\n            android:process=\":persistent\">\n            <intent-filter>\n                <action android:name=\"org.microg.gms.gcm.CONNECTED\" />\n                <action android:name=\"org.microg.gms.gcm.REGISTER_ACCOUNT\" />\n                <action android:name=\"org.microg.gms.gcm.REGISTER_ALL_ACCOUNTS\" />\n                <action android:name=\"org.microg.gms.gcm.NOTIFY_COMPLETE\" />\n\n                <action android:name=\"com.google.android.c2dm.intent.RECEIVE\" />\n            </intent-filter>\n        </receiver>\n\n        <receiver\n            android:name=\"org.microg.gms.gcm.SendReceiver\"\n            android:process=\":persistent\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gcm.intent.SEND\" />\n            </intent-filter>\n        </receiver>\n\n        <receiver\n            android:name=\"org.microg.gms.gcm.ServiceInfoReceiver\"\n            android:process=\":persistent\" />\n\n        <receiver\n            android:name=\"org.microg.gms.gcm.TriggerReceiver\"\n            android:process=\":persistent\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.BOOT_COMPLETED\" />\n                <action android:name=\"android.intent.action.AIRPLANE_MODE\" />\n                <action android:name=\"android.net.conn.CONNECTIVITY_CHANGE\" />\n                <action android:name=\"android.net.conn.BACKGROUND_DATA_SETTING_CHANGED\" />\n\n                <action android:name=\"org.microg.gms.gcm.RECONNECT\" />\n\n                <action android:name=\"android.intent.action.MY_PACKAGE_REPLACED\" />\n                <action android:name=\"android.intent.action.PACKAGE_RESTARTED\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"android.provider.Telephony.SECRET_CODE\" />\n\n                <data\n                    android:host=\"42678278\"\n                    android:scheme=\"android_secret_code\" />\n            </intent-filter>\n        </receiver>\n\n        <receiver\n            android:name=\"org.microg.gms.common.PersistentTrustedReceiver\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.PACKAGE_DATA_CLEARED\" />\n                <action android:name=\"android.intent.action.PACKAGE_FULLY_REMOVED\" />\n                <action android:name=\"android.intent.action.PACKAGE_REMOVED\" />\n\n                <data android:scheme=\"package\" />\n            </intent-filter>\n        </receiver>\n\n        <!-- Car -->\n\n        <service android:name=\"org.microg.gms.car.CarService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.car.service.START\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </service>\n\n        <!-- People -->\n\n        <service android:name=\"org.microg.gms.people.PeopleService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.people.service.START\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </service>\n\n        <service\n            android:name=\"org.microg.gms.people.ContactSyncService\"\n            android:exported=\"false\">\n            <intent-filter>\n                <action android:name=\"android.content.SyncAdapter\" />\n            </intent-filter>\n            <meta-data\n                android:name=\"android.content.SyncAdapter\"\n                android:resource=\"@xml/contact_syncadapter\" />\n        </service>\n\n        <!-- Wearable -->\n\n        <service android:name=\"org.microg.gms.wearable.WearableService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.wearable.BIND\" />\n            </intent-filter>\n        </service>\n\n        <activity\n            android:name=\"com.google.android.gms.wearable.consent.TermsOfServiceActivity\"\n            android:process=\":ui\"\n            android:configChanges=\"screenSize|orientation|keyboardHidden\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.wearable.TOS\"/>\n                <category android:name=\"android.intent.category.DEFAULT\"/>\n            </intent-filter>\n        </activity>\n\n        <!-- Auth -->\n\n        <service android:name=\"org.microg.gms.auth.loginservice.GoogleLoginService\">\n            <intent-filter>\n                <action android:name=\"android.accounts.AccountAuthenticator\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"com.google.android.gsf.action.GET_GLS\" />\n            </intent-filter>\n\n            <meta-data\n                android:name=\"android.accounts.AccountAuthenticator\"\n                android:resource=\"@xml/authenticator\" />\n            <meta-data\n                android:name=\"android.accounts.AccountAuthenticator.customTokens\"\n                android:value=\"1\" />\n        </service>\n\n        <activity\n            android:name=\"org.microg.tools.AccountPickerActivity\"\n            android:excludeFromRecents=\"true\"\n            android:exported=\"true\"\n            android:process=\":ui\"\n            android:theme=\"@style/Theme.App.DayNight.Dialog.Alert.NoActionBar\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.common.account.CHOOSE_ACCOUNT\" />\n                <action android:name=\"com.google.android.gms.common.account.CHOOSE_ACCOUNT_USERTILE\"/>\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </activity>\n\n        <activity\n            android:name=\"org.microg.gms.auth.login.LoginActivity\"\n            android:configChanges=\"keyboardHidden|keyboard|orientation|screenSize\"\n            android:exported=\"true\"\n            android:process=\":ui\"\n            android:launchMode=\"singleTask\"\n            android:theme=\"@style/Theme.LoginBlue\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.auth.login.LOGIN\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </activity>\n\n        <activity\n            android:name=\"org.microg.gms.auth.AskPermissionActivity\"\n            android:excludeFromRecents=\"true\"\n            android:exported=\"true\"\n            android:process=\":ui\"\n            android:theme=\"@style/Theme.AppCompat.DayNight.Dialog\" />\n\n        <activity\n            android:name=\"org.microg.gms.auth.AskPackageOverrideActivity\"\n            android:excludeFromRecents=\"true\"\n            android:exported=\"true\"\n            android:process=\":ui\"\n            android:theme=\"@style/Theme.App.Translucent\" />\n\n        <service\n            android:name=\".auth.GetToken\"\n            android:exported=\"true\" />\n\n        <activity\n            android:name=\".auth.TokenActivity\"\n            android:exported=\"true\"\n            android:process=\":ui\" />\n\n        <provider\n            android:name=\"org.microg.gms.auth.AccountContentProvider\"\n            android:authorities=\"com.google.android.gms.auth.accounts\"\n            android:exported=\"true\" />\n\n        <activity\n            android:name=\"org.microg.gms.auth.credentials.CredentialPickerActivity\"\n            android:process=\":ui\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.auth.api.credentials.PICKER\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </activity>\n\n        <service android:name=\"org.microg.gms.auth.credentials.CredentialsService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.auth.api.credentials.service.START\" />\n            </intent-filter>\n        </service>\n\n        <service android:name=\"org.microg.gms.auth.proxy.AuthProxyService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.auth.service.START\" />\n            </intent-filter>\n        </service>\n\n        <service android:name=\"org.microg.gms.auth.appcert.AppCertService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.auth.be.appcert.AppCertService\" />\n            </intent-filter>\n        </service>\n\n        <service android:name=\"org.microg.gms.credential.CredentialManagerService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.credential.manager.service.firstparty.START\" />\n            </intent-filter>\n        </service>\n\n        <activity\n            android:name=\"org.microg.gms.auth.signin.AuthSignInActivity\"\n            android:theme=\"@style/Theme.App.DayNight.Dialog.Alert.NoActionBar\"\n            android:process=\":ui\"\n            android:configChanges=\"keyboardHidden|keyboard|orientation|screenSize\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.auth.GOOGLE_SIGN_IN\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </activity>\n\n        <service android:name=\".locationsharingreporter.service.LocationSharingReporterApiService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.locationsharingreporter.service.START\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </service>\n\n        <service android:name=\"org.microg.gms.signin.SignInService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.signin.service.START\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </service>\n\n        <service android:name=\"org.microg.gms.auth.signin.AuthSignInService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.auth.api.signin.service.START\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </service>\n\n        <service\n            android:name=\"org.microg.gms.auth.signin.SignInConfigurationService\"\n            android:exported=\"false\" />\n\n        <service android:name=\"org.microg.gms.auth.credentials.identity.AuthorizationService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.auth.api.identity.service.authorization.START\" />\n            </intent-filter>\n        </service>\n\n        <service android:name=\"org.microg.gms.auth.credentials.identity.IdentitySignInService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.auth.api.identity.service.signin.START\" />\n            </intent-filter>\n        </service>\n\n        <service android:name=\"org.microg.gms.auth.folsom.KeyRetrievalService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.auth.key.retrieval.service.START\" />\n            </intent-filter>\n        </service>\n\n        <activity android:name=\"org.microg.gms.auth.folsom.ui.GenericActivity\"\n            android:exported=\"false\"\n            android:process=\":ui\"/>\n\n        <activity\n            android:name=\"org.microg.gms.auth.credentials.identity.IdentityFidoProxyActivity\"\n            android:exported=\"false\"\n            android:process=\":ui\"\n            android:theme=\"@style/Theme.App.Translucent\"\n            android:excludeFromRecents=\"true\"/>\n\n        <activity\n            android:theme=\"@style/Theme.AppCompat.Dialog.Alert\"\n            android:name=\"org.microg.gms.auth.signin.AssistedSignInActivity\"\n            android:enabled=\"true\"\n            android:exported=\"true\"\n            android:process=\":ui\"\n            android:configChanges=\"keyboardHidden|keyboard|orientation|screenSize|smallestScreenSize|layoutDirection\"\n            android:launchMode=\"singleTask\"\n            android:excludeFromRecents=\"false\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.auth.api.credentials.ASSISTED_SIGNIN\"/>\n                <category android:name=\"android.intent.category.DEFAULT\"/>\n            </intent-filter>\n        </activity>\n\n        <activity\n            android:name=\"org.microg.gms.auth.consent.ConsentSignInActivity\"\n            android:process=\":ui\"\n            android:exported=\"false\"\n            android:excludeFromRecents=\"true\"\n            android:configChanges=\"keyboardHidden|keyboard|orientation|screenSize\"\n            android:theme=\"@style/Theme.AppCompat.DayNight.Dialog\"/>\n\n        <activity\n            android:name=\"org.microg.gms.accountaction.AccountActionActivity\"\n            android:exported=\"true\"\n            android:theme=\"@style/Theme.LoginBlue\"/>\n\n        <!-- Games -->\n\n        <activity\n            android:name=\"org.microg.gms.games.ui.GamePlayDataActivity\"\n            android:process=\":ui\"\n            android:exported=\"false\"\n            android:theme=\"@style/Theme.AppCompat.Light.NoActionBar\"/>\n\n        <activity\n            android:name=\"org.microg.gms.games.ui.InGameUiActivity\"\n            android:process=\":ui\"\n            android:configChanges=\"keyboardHidden|keyboard|orientation|screenSize|smallestScreenSize|layoutDirection\"\n            android:excludeFromRecents=\"false\"\n            android:exported=\"true\"\n            android:launchMode=\"singleTask\"\n            android:theme=\"@style/Theme.AppCompat.Dialog.Alert\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.games.SHOW_SELECT_SNAPSHOT\"/>\n                <action android:name=\"com.google.android.gms.games.VIEW_ACHIEVEMENTS\" />\n                <action android:name=\"com.google.android.gms.games.VIEW_LEADERBOARDS\" />\n                <action android:name=\"com.google.android.gms.games.VIEW_LEADERBOARD_SCORES\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </activity>\n\n        <activity\n            android:name=\"org.microg.gms.games.GamesSignInActivity\"\n            android:enabled=\"true\"\n            android:exported=\"false\"\n            android:process=\":ui\"\n            android:configChanges=\"keyboardHidden|keyboard|orientation|screenSize\"\n            android:theme=\"@style/Theme.App.Translucent\"/>\n\n        <activity\n            android:name=\"org.microg.gms.games.UpgradeActivity\"\n            android:process=\":ui\"\n            android:theme=\"@style/Theme.AppCompat.DayNight.Dialog\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.games.PLAY_GAMES_UPGRADE\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </activity>\n\n        <service\n            android:name=\"org.microg.gms.games.GamesService\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.games.service.START\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </service>\n\n        <service\n            android:name=\"org.microg.gms.games.GamesConnectService\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.games.internal.connect.service.START\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </service>\n\n        <service\n            android:name=\"org.microg.gms.games.GamesConfigurationService\"\n            android:exported=\"false\" />\n\n        <!-- Chimera -->\n        <provider\n            android:name=\"org.microg.gms.chimera.ServiceProvider\"\n            android:authorities=\"com.google.android.gms.chimera\"\n            android:exported=\"true\" />\n\n        <!-- Fonts -->\n        <provider\n            android:name=\"org.microg.gms.fonts.FontsProvider\"\n            android:authorities=\"com.google.android.gms.fonts\"\n            android:exported=\"true\" />\n\n        <!-- microG Settings activity -->\n        <activity\n            android:name=\"org.microg.gms.ui.MainSettingsActivity\"\n            android:exported=\"true\"\n            android:icon=\"@mipmap/ic_app_settings\"\n            android:label=\"@string/gms_settings_name\"\n            android:process=\":ui\"\n            android:roundIcon=\"@mipmap/ic_app_settings\"\n            android:taskAffinity=\"org.microg.gms.settings\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.VIEW\" />\n                <data android:scheme=\"x-gms-settings\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"android.intent.action.APPLICATION_PREFERENCES\" />\n                <action android:name=\"com.google.android.gms.settings.EXPOSURE_NOTIFICATION_SETTINGS\" />\n                <action android:name=\"org.microg.gms.settings.CHECKIN_SETTINGS\" />\n                <action android:name=\"org.microg.gms.settings.GCM_SETTINGS\" />\n                <action android:name=\"org.microg.gms.settings.MICROG_APP_GCM_SETTINGS\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </activity>\n\n        <!-- microG Settings activity-alias shown in Launcher -->\n        <activity-alias\n            android:name=\"org.microg.gms.ui.SettingsActivity\"\n            android:icon=\"@mipmap/ic_app_settings\"\n            android:label=\"@string/gms_settings_name\"\n            android:roundIcon=\"@mipmap/ic_app_settings\"\n            android:process=\":ui\"\n            android:targetActivity=\"org.microg.gms.ui.MainSettingsActivity\"\n            android:taskAffinity=\"org.microg.gms.settings\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity-alias>\n\n        <activity\n            android:name=\"org.microg.gms.ui.SettingsDashboardActivity\"\n            android:icon=\"@mipmap/ic_app_settings\"\n            android:label=\"Legacy microG Settings\"\n            android:process=\":ui\"\n            android:roundIcon=\"@mipmap/ic_app_settings\"\n            android:taskAffinity=\"org.microg.gms.settings\" />\n\n        <!-- microG Settings embedded in System Settings on SDK 23 and newer -->\n        <activity-alias\n            android:name=\"org.microg.gms.ui.SettingsActivityLink\"\n            android:icon=\"@mipmap/ic_app_settings\"\n            android:label=\"@string/gms_settings_name\"\n            android:process=\":ui\"\n            android:targetActivity=\"org.microg.gms.ui.MainSettingsActivity\"\n            android:taskAffinity=\"org.microg.gms.settings\">\n            <intent-filter>\n                <action android:name=\"com.android.settings.action.EXTRA_SETTINGS\" />\n            </intent-filter>\n\n            <meta-data\n                android:name=\"com.android.settings.category\"\n                android:value=\"com.android.settings.category.device\" />\n            <meta-data\n                android:name=\"com.android.settings.icon\"\n                android:resource=\"@drawable/ic_app_settings_system\" />\n            <meta-data\n                android:name=\"com.android.settings.summary\"\n                android:resource=\"@string/gms_settings_summary\" />\n        </activity-alias>\n\n        <!-- microG Settings activity-alias for Google settings compatibility -->\n        <activity-alias\n            android:name=\"com.google.android.gms.app.settings.GoogleSettingsLink\"\n            android:process=\":ui\"\n            android:exported=\"true\"\n            android:targetActivity=\"org.microg.gms.ui.MainSettingsActivity\"\n            android:taskAffinity=\"org.microg.gms.settings\">\n        </activity-alias>\n\n        <activity\n            android:name=\"org.microg.gms.ui.AskPushPermission\"\n            android:excludeFromRecents=\"true\"\n            android:process=\":ui\"\n            android:theme=\"@style/Theme.App.Translucent\" />\n\n        <activity\n            android:name=\"org.microg.gms.ui.GoogleMoreFragment$AsActivity\"\n            android:label=\"@string/gms_settings_name\"\n            android:process=\":ui\"\n            android:taskAffinity=\"org.microg.gms.settings\" />\n\n        <activity\n            android:name=\"org.microg.gms.ui.SelfCheckFragment$AsActivity\"\n            android:label=\"@string/self_check_title\"\n            android:process=\":ui\"\n            android:taskAffinity=\"org.microg.gms.settings\" />\n\n        <activity\n            android:name=\"org.microg.gms.accountsettings.ui.MainActivity\"\n            android:process=\":ui\"\n            android:exported=\"false\"\n            android:taskAffinity=\"org.microg.gms.settings\"\n            android:theme=\"@style/Theme.AppCompat.Light.NoActionBar\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.accountsettings.MY_ACCOUNT\" />\n                <action android:name=\"com.google.android.gms.accountsettings.ACCOUNT_PREFERENCES_SETTINGS\" />\n                <action android:name=\"com.google.android.gms.accountsettings.PRIVACY_SETTINGS\" />\n                <action android:name=\"com.google.android.gms.accountsettings.SECURITY_SETTINGS\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </activity>\n\n        <activity\n            android:name=\"org.microg.gms.accountsettings.ui.LoaderActivity\"\n            android:process=\":ui\"\n            android:exported=\"true\"\n            android:excludeFromRecents=\"true\"\n            android:theme=\"@style/Theme.App.DayNight.Dialog.Alert.NoActionBar\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.accountsettings.action.VIEW_SETTINGS\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.accountsettings.action.BROWSE_SETTINGS\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.BROWSABLE\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.location.settings.LOCATION_SHARING\"/>\n                <category android:name=\"android.intent.category.DEFAULT\"/>\n            </intent-filter>\n        </activity>\n\n        <activity\n            android:name=\"org.microg.gms.ui.LocationSettingsActivity\"\n            android:process=\":ui\"\n            android:taskAffinity=\"org.microg.gms.settings\">\n            <intent-filter>\n                <action android:name=\"com.google.android.location.settings.LOCATION_REPORTING_SETTINGS\" />\n                <action android:name=\"com.google.android.gms.location.settings.LOCATION_REPORTING_SETTINGS\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </activity>\n\n        <!-- Phenotype -->\n\n        <provider\n            android:name=\"org.microg.gms.phenotype.ConfigurationProvider\"\n            android:authorities=\"com.google.android.gms.phenotype\"\n            android:exported=\"true\" />\n\n        <service android:name=\"org.microg.gms.phenotype.PhenotypeService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.phenotype.service.START\" />\n            </intent-filter>\n        </service>\n\n        <!-- Help -->\n\n        <service\n            android:name=\"org.microg.gms.googlehelp.GoogleHelpService\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.googlehelp.service.GoogleHelpService.START\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </service>\n\n        <activity\n            android:name=\"org.microg.gms.googlehelp.ui.GoogleHelpRedirectActivity\"\n            android:theme=\"@style/Theme.App.Translucent\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.googlehelp.HELP\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n\n            <intent-filter>\n                <action android:name=\"android.intent.action.SEARCH\" />\n            </intent-filter>\n        </activity>\n\n        <!-- PoToken -->\n\n        <service android:name=\"org.microg.gms.potokens.PoTokensService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.potokens.service.START\" />\n            </intent-filter>\n        </service>\n\n        <!-- backup -->\n\n        <activity\n            android:name=\"org.microg.gms.backup.BackupSettingsActivity\"\n            android:theme=\"@android:style/Theme.Translucent.NoTitleBar\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.backup.ACTION_BACKUP_SETTINGS\"/>\n                <category android:name=\"android.intent.category.DEFAULT\"/>\n            </intent-filter>\n        </activity>\n\n        <!-- Other -->\n\n        <service\n            android:name=\"org.microg.gms.measurement.MeasurementService\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.measurement.START\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </service>\n        <service\n            android:name=\"org.microg.gms.languageprofile.LanguageProfileService\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.languageprofile.service.START\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </service>\n        <service android:name=\"org.microg.gms.mdm.NetworkQualityService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.mdm.services.START\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </service>\n        <service android:name=\"org.microg.gms.icing.LightweightIndexService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.icing.LIGHTWEIGHT_INDEX_SERVICE\" />\n            </intent-filter>\n        </service>\n        <service android:name=\"org.microg.gms.icing.IndexService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.icing.INDEX_SERVICE\" />\n            </intent-filter>\n        </service>\n        <service\n            android:name=\".analytics.service.AnalyticsService\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.analytics.service.START\" />\n            </intent-filter>\n        </service>\n        <service android:name=\"org.microg.gms.playlog.PlayLogService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.playlog.service.START\" />\n            </intent-filter>\n        </service>\n        <service\n            android:name=\".gcm.http.GoogleHttpService\"\n            android:exported=\"true\" />\n\n        <service android:name=\"org.microg.gms.ads.GService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.ads.gservice.START\" />\n            </intent-filter>\n        </service>\n\n        <!-- family -->\n\n        <activity\n            android:name=\"com.google.android.gms.family.v2.manage.FamilyManagementActivity\"\n            android:exported=\"true\"\n            android:configChanges=\"screenSize|screenLayout|orientation\"\n            android:process=\":ui\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.family.v2.MANAGE\"/>\n                <category android:name=\"android.intent.category.DEFAULT\"/>\n            </intent-filter>\n        </activity>\n\n        <activity\n            android:name=\"com.google.android.gms.family.v2.manage.DeleteMemberActivity\"\n            android:exported=\"true\"\n            android:configChanges=\"screenSize|screenLayout|orientation\"\n            android:process=\":ui\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.family.v2.DELETE_MEMBER\"/>\n                <category android:name=\"android.intent.category.DEFAULT\"/>\n            </intent-filter>\n        </activity>\n\n        <!-- feedback -->\n\n        <service android:name=\"org.microg.gms.feedback.FeedbackService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.feedback.internal.IFeedbackService\" />\n            </intent-filter>\n        </service>\n\n        <activity\n            android:name=\"com.google.android.gms.feedback.FeedbackActivity\"\n            android:exported=\"true\"\n            android:excludeFromRecents=\"true\"\n            android:theme=\"@style/Theme.App.Translucent\"/>\n\n        <activity\n            android:name=\"com.google.android.gms.credential.manager.PasswordManagerActivity\"\n            android:exported=\"true\"\n            android:process=\":ui\"\n            android:excludeFromRecents=\"true\"\n            android:theme=\"@style/Theme.Translucent\"/>\n\n        <service android:name=\"org.microg.gms.clearcut.ClearcutLoggerService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.clearcut.service.START\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </service>\n        <service android:name=\"org.microg.gms.drive.api.DriveApiService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.drive.ApiService.START\" />\n                <action android:name=\"com.google.android.gms.drive.ApiService.STOP\" />\n                <action android:name=\"com.google.android.gms.drive.ApiService.RESET_AFTER_BOOT\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </service>\n        <service android:name=\"org.microg.gms.reminders.RemindersService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.reminders.service.START\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </service>\n\n        <service android:name=\"org.microg.gms.wallet.PaymentService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.wallet.service.BIND\" />\n            </intent-filter>\n        </service>\n\n        <service android:name=\"org.microg.gms.firebase.dynamiclinks.DynamicLinksService\">\n            <intent-filter>\n                <action android:name=\"com.google.firebase.dynamiclinks.service.START\" />\n            </intent-filter>\n        </service>\n\n        <service android:name=\"org.microg.gms.udc.FacsCacheService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.facs.cache.service.START\" />\n            </intent-filter>\n        </service>\n\n        <service android:name=\"org.microg.gms.usagereporting.UsageReportingService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.usagereporting.service.START\" />\n            </intent-filter>\n        </service>\n\n        <service android:name=\"org.microg.gms.pseudonymous.PseudonymousIdService\" >\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.pseudonymous.service.START\" />\n            </intent-filter>\n        </service>\n\n        <service android:name=\"org.microg.gms.gass.GassService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.gass.START\" />\n            </intent-filter>\n        </service>\n\n        <service android:name=\"org.microg.gms.auth.account.data.AccountDataService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.auth.account.data.service.START\" />\n            </intent-filter>\n        </service>\n\n        <service android:name=\".semanticlocation.SemanticLocationService\" android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.semanticlocation.service.START_ODLH\" />\n            </intent-filter>\n        </service>\n\n        <service android:name=\".semanticlocationhistory.SemanticLocationHistoryService\" android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.semanticlocationhistory.service.START\" />\n            </intent-filter>\n        </service>\n\n        <activity\n            android:name=\"com.google.android.location.settings.LocationHistorySettingsActivity\"\n            android:theme=\"@android:style/Theme.Translucent.NoTitleBar\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.location.settings.LOCATION_HISTORY\"/>\n                <category android:name=\"android.intent.category.DEFAULT\"/>\n            </intent-filter>\n        </activity>\n\n        <service android:name=\"org.microg.gms.audit.AuditService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.audit.service.START\" />\n            </intent-filter>\n        </service>\n\n        <service android:name=\"org.microg.gms.common.ClientTelemetryService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.common.telemetry.service.START\" />\n            </intent-filter>\n        </service>\n\n        <service android:name=\"org.microg.gms.common.GmsCommonService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.common.service.START\" />\n            </intent-filter>\n        </service>\n\n        <activity\n            android:name=\"org.microg.gms.mlkit.BarcodeScanningActivity\"\n            android:exported=\"true\"\n            android:process=\":ui\"\n            android:excludeFromRecents=\"true\"\n            android:theme=\"@style/Theme.AppCompat.DayNight.NoActionBar\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.mlkit.ACTION_SCAN_BARCODE\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </activity>\n\n        <service\n            android:name=\"com.google.android.gms.maps.auth.ApiTokenService\"\n            android:exported=\"true\"/>\n\n        <service android:name=\"org.microg.gms.DummyService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.contextmanager.service.ContextManagerService.START\" />\n                <action android:name=\"com.google.android.gms.accounts.ACCOUNT_SERVICE\" />\n                <action android:name=\"com.google.android.gms.ads.identifier.service.EVENT_ATTESTATION\" />\n                <action android:name=\"com.google.android.gms.ads.service.CACHE\" />\n                <action android:name=\"com.google.android.gms.ads.service.CONSENT_LOOKUP\" />\n                <action android:name=\"com.google.android.gms.ads.service.HTTP\" />\n                <action android:name=\"com.google.android.gms.appstate.service.START\" />\n                <action android:name=\"com.google.android.gms.appusage.service.START\" />\n                <action android:name=\"com.google.android.gms.asterism.service.START\" />\n                <action android:name=\"com.google.android.gms.audiomodem.service.AudioModemService.START\" />\n                <action android:name=\"com.google.android.gms.auth.account.authapi.START\" />\n                <action android:name=\"com.google.android.gms.auth.account.authenticator.auto.service.START\" />\n                <action android:name=\"com.google.android.gms.auth.account.authenticator.chromeos.START\" />\n                <action android:name=\"com.google.android.gms.auth.account.authenticator.tv.service.START\" />\n                <action android:name=\"com.google.android.gms.auth.api.identity.service.credentialsaving.START\" />\n                <action android:name=\"com.google.android.gms.auth.api.phone.service.InternalService.START\" />\n                <action android:name=\"com.google.android.gms.auth.api.signin.service.START\" />\n                <action android:name=\"com.google.android.gms.auth.config.service.START\" />\n                <action android:name=\"com.google.android.gms.auth.cryptauth.cryptauthservice.START\" />\n                <action android:name=\"com.google.android.gms.auth.proximity.devicesyncservice.START\" />\n                <action android:name=\"com.google.android.gms.auth.proximity.securechannelservice.START\" />\n                <action android:name=\"com.google.android.gms.auth.proximity.START\" />\n                <action android:name=\"com.google.android.gms.auth.service.START\" />\n                <action android:name=\"com.google.android.gms.backup.G1_BACKUP\" />\n                <action android:name=\"com.google.android.gms.backup.G1_RESTORE\" />\n                <action android:name=\"com.google.android.gms.backup.GMS_MODULE_RESTORE\" />\n                <action android:name=\"com.google.android.gms.beacon.internal.IBleService.START\" />\n                <action android:name=\"com.google.android.gms.carrierauth.service.START\" />\n                <action android:name=\"com.google.android.gms.cast.firstparty.START\" />\n                <action android:name=\"com.google.android.gms.cast_mirroring.service.START\" />\n                <action android:name=\"com.google.android.gms.cast.remote_display.service.START\" />\n                <action android:name=\"com.google.android.gms.chromesync.service.START\" />\n                <action android:name=\"com.google.android.gms.common.download.START\" />\n                <action android:name=\"com.google.android.gms.config.START\" />\n                <action android:name=\"com.google.android.gms.constellation.service.START\" />\n                <action android:name=\"com.google.android.gms.deviceconnection.service.START\" />\n                <action android:name=\"com.google.android.gms.enterprise.loader.service.START\" />\n                <action android:name=\"com.google.android.gms.facs.internal.service.START\" />\n                <action android:name=\"com.google.android.gms.fido.credentialstore.internal_service.START\" />\n                <action android:name=\"com.google.android.gms.fido.fido2.regular.START\" />\n                <action android:name=\"com.google.android.gms.fido.fido2.zeroparty.START\" />\n                <action android:name=\"com.google.android.gms.fido.sourcedevice.service.START\" />\n                <action android:name=\"com.google.android.gms.fido.targetdevice.internal_service.START\" />\n                <action android:name=\"com.google.android.gms.fido.u2f.privileged.START\" />\n                <action android:name=\"com.google.android.gms.fido.u2f.thirdparty.START\" />\n                <action android:name=\"com.google.android.gms.fido.u2f.zeroparty.START\" />\n                <action android:name=\"com.google.android.gms.fitness.BleApi\" />\n                <action android:name=\"com.google.android.gms.fitness.GoalsApi\" />\n                <action android:name=\"com.google.android.gms.fitness.GoogleFitnessService.START\" />\n                <action android:name=\"com.google.android.gms.fitness.InternalApi\" />\n                <action android:name=\"com.google.android.gms.fitness.SensorsApi\" />\n                <action android:name=\"com.google.android.gms.fonts.service.START\" />\n                <action android:name=\"com.google.android.gms.freighter.service.START\" />\n                <action android:name=\"com.google.android.gms.growth.service.START\" />\n                <action android:name=\"com.google.android.gms.googlehelp.service.GoogleHelpService.START\" />\n                <action android:name=\"com.google.android.gms.herrevad.services.LightweightNetworkQualityAndroidService.START\" />\n                <action android:name=\"com.google.android.gms.identity.service.BIND\" />\n                <action android:name=\"com.google.android.gms.inappreach.service.START\"/>\n                <action android:name=\"com.google.android.gms.instantapps.START\" />\n                <action android:name=\"com.google.android.gms.kids.service.START\" />\n                <action android:name=\"com.google.android.gms.learning.internal.dynamitesupport.START\" />\n                <action android:name=\"com.google.android.gms.learning.intservice.START\" />\n                <action android:name=\"com.google.android.gms.learning.predictor.START\" />\n                <action android:name=\"com.google.android.gms.learning.trainer.START\" />\n                <action android:name=\"com.google.android.gms.learning.training.background.START\" />\n                <action android:name=\"com.google.android.gms.locationsharing.api.START\" />\n                <action android:name=\"com.google.android.gms.locationsharingreporter.service.START\" />\n                <action android:name=\"com.google.android.gms.lockbox.service.START\" />\n                <action android:name=\"com.google.android.gms.matchstick.lighter.service.START\" />\n                <action android:name=\"com.google.android.gms.mdm.services.DeviceManagerApiService.START\" />\n                <action android:name=\"com.google.android.gms.mdns.service.START\" />\n                <action android:name=\"com.google.android.gms.nearby.bootstrap.service.NearbyBootstrapService.START\" />\n                <action android:name=\"com.google.android.gms.nearby.connection.service.START\" />\n                <action android:name=\"com.google.android.gms.nearby.fastpair.START\" />\n                <action android:name=\"com.google.android.gms.nearby.messages.service.NearbyMessagesService.START\" />\n                <action android:name=\"com.google.android.gms.nearby.sharing.service.NearbySharingService.START\" />\n                <action android:name=\"com.google.android.gms.nearby.sharing.START_SERVICE\" />\n                <action android:name=\"com.google.android.gms.notifications.service.START\" />\n                <action android:name=\"com.google.android.gms.ocr.service.internal.START\" />\n                <action android:name=\"com.google.android.gms.ocr.service.START\" />\n                <action android:name=\"com.google.android.gms.payse.service.BIND\" />\n                <action android:name=\"com.google.android.gms.people.contactssync.service.START\" />\n                <action android:name=\"com.google.android.gms.photos.autobackup.service.START\" />\n                <action android:name=\"com.google.android.gms.plus.service.default.INTENT\" />\n                <action android:name=\"com.google.android.gms.plus.service.image.INTENT\" />\n                <action android:name=\"com.google.android.gms.plus.service.internal.START\" />\n                <action android:name=\"com.google.android.gms.plus.service.START\" />\n                <action android:name=\"com.google.android.gms.rcs.START\" />\n                <action android:name=\"com.google.android.gms.romanesco.MODULE_BACKUP_AGENT\" />\n                <action android:name=\"com.google.android.gms.romanesco.service.START\" />\n                <action android:name=\"com.google.android.gms.search.service.SEARCH_AUTH_START\" />\n                <action android:name=\"com.google.android.gms.sesame.service.BIND\" />\n                <action android:name=\"com.google.android.gms.telephonyspam.service.START\" />\n                <action android:name=\"com.google.android.gms.testsupport.service.START\" />\n                <action android:name=\"com.google.android.gms.scheduler.ACTION_PROXY_SCHEDULE\" />\n                <action android:name=\"com.google.android.gms.setup.auth.SecondDeviceAuth.START\" />\n                <action android:name=\"com.google.android.gms.smartdevice.d2d.SourceDeviceService.START\" />\n                <action android:name=\"com.google.android.gms.smartdevice.d2d.TargetDeviceService.START\" />\n                <action android:name=\"com.google.android.gms.smartdevice.directtransfer.SourceDirectTransferService.START\" />\n                <action android:name=\"com.google.android.gms.smartdevice.directtransfer.TargetDirectTransferService.START\" />\n                <action android:name=\"com.google.android.gms.smartdevice.postsetup.PostSetupService.START\" />\n                <action android:name=\"com.google.android.gms.smartdevice.setup.accounts.AccountsService.START\" />\n                <action android:name=\"com.google.android.gms.smartdevice.wifi.START_WIFI_HELPER_SERVICE\" />\n                <action android:name=\"com.google.android.gms.social.location.activity.service.START\" />\n                <action android:name=\"com.google.android.gms.statementservice.EXECUTE\" />\n                <action android:name=\"com.google.android.gms.stats.ACTION_UPLOAD_DROPBOX_ENTRIES\" />\n                <action android:name=\"com.google.android.gms.speech.service.START\" />\n                <action android:name=\"com.google.android.gms.thunderbird.service.START\" />\n                <action android:name=\"com.google.android.gms.trustagent.BridgeApi.START\" />\n                <action android:name=\"com.google.android.gms.trustagent.StateApi.START\" />\n                <action android:name=\"com.google.android.gms.trustagent.trustlet.trustletmanagerservice.BIND\" />\n                <action android:name=\"com.google.android.gms.trustlet.bluetooth.service.BIND\" />\n                <action android:name=\"com.google.android.gms.trustlet.connectionlessble.service.BIND\" />\n                <action android:name=\"com.google.android.gms.trustlet.face.service.BIND\" />\n                <action android:name=\"com.google.android.gms.trustlet.nfc.service.BIND\" />\n                <action android:name=\"com.google.android.gms.trustlet.onbody.service.BIND\" />\n                <action android:name=\"com.google.android.gms.trustlet.place.service.BIND\" />\n                <action android:name=\"com.google.android.gms.trustlet.voiceunlock.service.BIND\" />\n                <action android:name=\"com.google.android.gms.udc.service.START\" />\n                <action android:name=\"com.google.android.gms.update.START_API_SERVICE\" />\n                <action android:name=\"com.google.android.gms.update.START_SERVICE\" />\n                <action android:name=\"com.google.android.gms.update.START_SINGLE_USER_API_SERVICE\" />\n                <action android:name=\"com.google.android.gms.update.START_TV_API_SERVICE\" />\n                <action android:name=\"com.google.android.gms.userlocation.service.START\" />\n                <action android:name=\"com.google.android.gms.vehicle.cabin.service.START\" />\n                <action android:name=\"com.google.android.gms.vehicle.climate.service.START\" />\n                <action android:name=\"com.google.android.gms.vehicle.info.service.START\" />\n                <action android:name=\"com.google.android.gms.walletp2p.service.firstparty.BIND\" />\n                <action android:name=\"com.google.android.gms.walletp2p.service.zeroparty.BIND\" />\n                <action android:name=\"com.google.android.gms.wearable.BIND\" />\n                <action android:name=\"com.google.android.gms.wearable.DATA_CHANGED\" />\n                <action android:name=\"com.google.android.gms.wearable.NODE_CHANGED\" />\n                <action android:name=\"com.google.android.mdd.service.START\" />\n                <action android:name=\"com.google.android.mdh.service.START\" />\n                <action android:name=\"com.google.android.mdh.service.listener.START\" />\n                <action android:name=\"com.google.android.mobstore.service.START\" />\n\n                <action\n                    android:name=\"com.google.android.gms.wearable.BIND_LISTENER\"\n                    tools:ignore=\"WearableBindListener\" />\n            </intent-filter>\n        </service>\n    </application>\n\n</manifest>\n"
  },
  {
    "path": "play-services-core/src/main/java/com/google/android/gms/analytics/service/AnalyticsService.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.analytics.service;\n\nimport android.app.Service;\nimport android.content.Intent;\nimport android.os.IBinder;\nimport android.util.Log;\n\npublic class AnalyticsService extends Service {\n    private static final String TAG = \"GmsAnalyticsSvc\";\n\n    @Override\n    public IBinder onBind(Intent intent) {\n        Log.d(TAG, \"onBind: \" + intent);\n        return null;\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/com/google/android/gms/auth/GetToken.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.auth;\n\nimport android.app.Service;\nimport android.content.Intent;\nimport android.os.IBinder;\n\nimport org.microg.gms.auth.AuthManagerServiceImpl;\n\npublic class GetToken extends Service {\n    @Override\n    public IBinder onBind(Intent intent) {\n        return new AuthManagerServiceImpl(this);\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/com/google/android/gms/auth/TokenActivity.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.auth;\n\nimport android.app.Activity;\nimport android.os.Bundle;\nimport android.util.Log;\n\npublic class TokenActivity extends Activity {\n    private static final String TAG = \"GmsAuthTokenActivity\";\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        Bundle extras = getIntent().getExtras();\n        extras.get(\"KEY\");\n        Log.d(TAG, extras.toString());\n        /*AccountManager accountManager = AccountManager.get(this);\n        accountManager.getAuthToken(new Account(extras.getString(\"authAccount\"), \"com.google\"), extras.getString(\"service\"), extras.getBundle(\"callerExtras\"), this, new AccountManagerCallback<Bundle>() {\n            @Override\n            public void run(AccountManagerFuture<Bundle> future) {\n                try {\n                    Bundle result = future.getResult();\n                    if (result != null) {\n                        result.get(\"KEY\");\n                        Log.d(\"TokenActivity\", result.toString());\n                    } else {\n                        Log.d(\"TokenActivity\", \"null-result\");\n                    }\n                } catch (OperationCanceledException e) {\n                    e.printStackTrace();\n                } catch (IOException e) {\n                    e.printStackTrace();\n                } catch (AuthenticatorException e) {\n                    e.printStackTrace();\n                }\n            }\n        }, new Handler(getMainLooper()));*/\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/com/google/android/gms/chimera/DynamiteContextFactory.java",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.chimera;\n\nimport static android.os.Build.CPU_ABI;\nimport static android.os.Build.SUPPORTED_32_BIT_ABIS;\nimport static android.os.Build.SUPPORTED_64_BIT_ABIS;\nimport static android.os.Build.VERSION.SDK_INT;\n\nimport android.content.Context;\nimport android.content.pm.PackageManager;\nimport android.os.Process;\nimport android.util.Log;\n\nimport com.google.android.gms.chimera.container.DynamiteContext;\nimport com.google.android.gms.chimera.container.DynamiteModuleInfo;\nimport com.google.android.gms.chimera.container.FilteredClassLoader;\n\nimport org.microg.gms.common.Constants;\n\nimport java.io.File;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.WeakHashMap;\n\nimport dalvik.system.PathClassLoader;\n\npublic class DynamiteContextFactory {\n    private static final String TAG = \"DynamiteContextFactory\";\n    private static final Map<String, DynamiteContext> sContextCache = new WeakHashMap<>();\n    // WeakHashMap cannot be used, and there is a high probability that it will be recycled, causing ClassLoader to be rebuilt\n    private static final Map<String, ClassLoader> sClassLoaderCache = new HashMap<>();\n\n    public static DynamiteContext createDynamiteContext(String moduleId, Context originalContext) {\n        if (originalContext == null) {\n            Log.w(TAG, \"create <DynamiteContext> Original context is null\");\n            return null;\n        }\n        String cacheKey = moduleId + \"-\" + originalContext.getPackageName();\n        synchronized (sContextCache) {\n            DynamiteContext cached = sContextCache.get(cacheKey);\n            if (cached != null) {\n                Log.d(TAG, \"Using cached DynamiteContext for cacheKey: \" + cacheKey);\n                return cached;\n            }\n        }\n        try {\n            DynamiteModuleInfo moduleInfo = new DynamiteModuleInfo(moduleId);\n            Context gmsContext = originalContext.createPackageContext(Constants.GMS_PACKAGE_NAME, 0);\n            Context originalAppContext = originalContext.getApplicationContext();\n\n            DynamiteContext dynamiteContext;\n            if (originalAppContext == null || originalAppContext == originalContext) {\n                dynamiteContext = new DynamiteContext(moduleInfo, originalContext, gmsContext, null);\n            } else {\n                dynamiteContext = new DynamiteContext(moduleInfo, originalContext, gmsContext, new DynamiteContext(moduleInfo, originalAppContext, gmsContext, null));\n            }\n            moduleInfo.init(dynamiteContext);\n\n            synchronized (sContextCache) {\n                sContextCache.put(cacheKey, dynamiteContext);\n            }\n            Log.d(TAG, \"Created and cached a new DynamiteContext for cacheKey: \" + cacheKey);\n            return dynamiteContext;\n        } catch (PackageManager.NameNotFoundException e) {\n            Log.w(TAG, e);\n            return null;\n        }\n    }\n\n    public static ClassLoader createClassLoader(DynamiteModuleInfo moduleInfo, Context gmsContext, Context originalContext) {\n        String cacheKey = moduleInfo.getModuleId() + \"-\" + originalContext.getPackageName();\n        synchronized (sClassLoaderCache) {\n            ClassLoader cached = sClassLoaderCache.get(cacheKey);\n            if (cached != null) {\n                Log.d(TAG, \"Using cached ClassLoader for cacheKey: \" + cacheKey + \" cached: \" + cached.hashCode());\n                return cached;\n            }\n        }\n        StringBuilder nativeLoaderDirs = new StringBuilder(gmsContext.getApplicationInfo().nativeLibraryDir);\n        if (SDK_INT >= 23 && Process.is64Bit()) {\n            for (String abi : SUPPORTED_64_BIT_ABIS) {\n                nativeLoaderDirs.append(File.pathSeparator).append(gmsContext.getApplicationInfo().sourceDir).append(\"!/lib/\").append(abi);\n            }\n        } else if (SDK_INT >= 21) {\n            for (String abi : SUPPORTED_32_BIT_ABIS) {\n                nativeLoaderDirs.append(File.pathSeparator).append(gmsContext.getApplicationInfo().sourceDir).append(\"!/lib/\").append(abi);\n            }\n        } else {\n            nativeLoaderDirs.append(File.pathSeparator).append(gmsContext.getApplicationInfo().sourceDir).append(\"!/lib/\").append(CPU_ABI);\n        }\n        ClassLoader classLoader = new PathClassLoader(gmsContext.getApplicationInfo().sourceDir, nativeLoaderDirs.toString(), new FilteredClassLoader(originalContext.getClassLoader(), moduleInfo.getMergedClasses(), moduleInfo.getMergedPackages()));\n        synchronized (sClassLoaderCache) {\n            sClassLoaderCache.put(cacheKey, classLoader);\n        }\n        Log.d(TAG, \"Created and cached a new ClassLoader for cacheKey: \" + cacheKey + \" ClassLoader: \" + classLoader.hashCode());\n        return classLoader;\n    }\n}\n\n"
  },
  {
    "path": "play-services-core/src/main/java/com/google/android/gms/chimera/DynamiteModuleInitializer.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.chimera;\n\nimport android.annotation.SuppressLint;\nimport android.util.Log;\nimport androidx.annotation.Keep;\n\nimport android.content.Context;\n\n@Keep\npublic class DynamiteModuleInitializer {\n    private static final String TAG = \"DynamiteModule\";\n\n    public static void initializeModuleV1(Context context) {\n        initializeModuleV2(context, \"com.google.android.gms\".equals(context.getPackageName()));\n    }\n\n    public static void initializeModuleV2(Context context, boolean withGmsPackage) {\n        Log.d(TAG, \"initializeModuleV2 context: \" + context + \", withGmsPackage: \" + withGmsPackage);\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/com/google/android/gms/chimera/container/DynamiteContext.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.chimera.container;\n\nimport android.content.Context;\nimport android.content.ContextWrapper;\nimport android.content.pm.ApplicationInfo;\n\nimport androidx.annotation.RequiresApi;\n\nimport com.google.android.gms.chimera.DynamiteContextFactory;\n\npublic class DynamiteContext extends ContextWrapper {\n    private static final String TAG = \"DynamiteContext\";\n    private DynamiteModuleInfo moduleInfo;\n    private Context originalContext;\n    private Context gmsContext;\n    private DynamiteContext appContext;\n\n    private ClassLoader classLoader;\n\n    public DynamiteContext(DynamiteModuleInfo moduleInfo, Context base, Context gmsContext, DynamiteContext appContext) {\n        super(base);\n        this.moduleInfo = moduleInfo;\n        this.originalContext = base;\n        this.gmsContext = gmsContext;\n        this.appContext = appContext;\n    }\n\n    @Override\n    public ClassLoader getClassLoader() {\n        if (classLoader == null) {\n            classLoader = DynamiteContextFactory.createClassLoader(moduleInfo, gmsContext, originalContext);\n        }\n        return classLoader;\n    }\n\n    @Override\n    public String getPackageName() {\n        return gmsContext.getPackageName();\n    }\n\n    @Override\n    public ApplicationInfo getApplicationInfo() {\n        return gmsContext.getApplicationInfo();\n    }\n\n    @Override\n    public Context getApplicationContext() {\n        return appContext;\n    }\n\n    @RequiresApi(24)\n    @Override\n    public Context createDeviceProtectedStorageContext() {\n        return new DynamiteContext(moduleInfo, originalContext.createDeviceProtectedStorageContext(), gmsContext.createDeviceProtectedStorageContext(), appContext);\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/com/google/android/gms/chimera/container/DynamiteLoaderImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.chimera.container;\n\nimport android.content.Context;\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport com.google.android.gms.chimera.DynamiteContextFactory;\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.dynamic.ObjectWrapper;\nimport com.google.android.gms.dynamite.IDynamiteLoader;\n\npublic class DynamiteLoaderImpl extends IDynamiteLoader.Stub {\n    private static final String TAG = \"GmsDynamiteLoaderImpl\";\n\n    @Override\n    public IObjectWrapper createModuleContext(IObjectWrapper wrappedContext, String moduleId, int minVersion) throws RemoteException {\n        // We don't have crash utils, so just forward\n        return createModuleContextV2(wrappedContext, moduleId, minVersion);\n    }\n\n    @Override\n    public IObjectWrapper createModuleContextV2(IObjectWrapper wrappedContext, String moduleId, int minVersion) throws RemoteException {\n        Log.d(TAG, \"createModuleContext for \" + moduleId + \" at version \" + minVersion);\n        final Context originalContext = (Context) ObjectWrapper.unwrap(wrappedContext);\n        return ObjectWrapper.wrap(DynamiteContextFactory.createDynamiteContext(moduleId, originalContext));\n    }\n\n    @Override\n    public IObjectWrapper createModuleContextV3(IObjectWrapper wrappedContext, String moduleId, int minVersion, IObjectWrapper wrappedCursor) throws RemoteException {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public int getIDynamiteLoaderVersion() throws RemoteException {\n        return 2;\n    }\n\n    @Override\n    public int getModuleVersion(IObjectWrapper wrappedContext, String moduleId) throws RemoteException {\n        return getModuleVersion2(wrappedContext, moduleId, true);\n    }\n\n    @Override\n    public int getModuleVersion2(IObjectWrapper wrappedContext, String moduleId, boolean updateConfigIfRequired) throws RemoteException {\n        // We don't have crash utils, so just forward\n        return getModuleVersionV2(wrappedContext, moduleId, updateConfigIfRequired);\n    }\n\n    @Override\n    public int getModuleVersionV2(IObjectWrapper wrappedContext, String moduleId, boolean updateConfigIfRequired) throws RemoteException {\n        final Context context = (Context) ObjectWrapper.unwrap(wrappedContext);\n        if (context == null) {\n            Log.w(TAG, \"Invalid client context\");\n            return 0;\n        }\n\n        try {\n            return Class.forName(\"com.google.android.gms.dynamite.descriptors.\" + moduleId + \".ModuleDescriptor\").getDeclaredField(\"MODULE_VERSION\").getInt(null);\n        } catch (Exception e) {\n            Log.w(TAG, \"No such module known: \" + moduleId);\n        }\n\n        if (moduleId.equals(\"com.google.android.gms.firebase_database\")) {\n            Log.d(TAG, \"returning temp fix module version for \" + moduleId + \". Firebase Database will not be functional!\");\n            return com.google.android.gms.dynamite.descriptors.com.google.android.gms.firebase_database.ModuleDescriptor.MODULE_VERSION;\n        }\n        if (moduleId.equals(\"com.google.android.gms.googlecertificates\")) {\n            return com.google.android.gms.dynamite.descriptors.com.google.android.gms.googlecertificates.ModuleDescriptor.MODULE_VERSION;\n        }\n        if (moduleId.equals(\"com.google.android.gms.cast.framework.dynamite\")) {\n            Log.d(TAG, \"returning temp fix module version for \" + moduleId + \". Cast API wil not be functional!\");\n            return 1;\n        }\n\n        if (moduleId.equals(\"com.google.android.gms.maps_dynamite\")) {\n            Log.d(TAG, \"returning v1 for maps\");\n            return 1;\n        }\n\n        Log.d(TAG, \"unimplemented Method: getModuleVersion for \" + moduleId);\n        return 0;\n    }\n\n    @Override\n    public IObjectWrapper getModuleVersionV3(IObjectWrapper wrappedContext, String moduleId, boolean updateConfigIfRequired, long requestStartTime) throws RemoteException {\n        throw new UnsupportedOperationException();\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/com/google/android/gms/chimera/container/DynamiteModuleInfo.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.chimera.container;\n\nimport java.util.Collection;\nimport java.util.Collections;\n\nimport android.content.Context;\n\npublic class DynamiteModuleInfo {\n    private Class<?> descriptor;\n    private String moduleId;\n\n    public DynamiteModuleInfo(String moduleId) {\n        this.moduleId = moduleId;\n        try {\n            this.descriptor = Class.forName(\"com.google.android.gms.dynamite.descriptors.\" + moduleId + \".ModuleDescriptor\");\n        } catch (Exception e) {\n            // Ignore\n        }\n    }\n\n    public String getModuleId() {\n        return moduleId;\n    }\n\n    public int getVersion() {\n        try {\n            return descriptor.getDeclaredField(\"MODULE_VERSION\").getInt(null);\n        } catch (Exception e) {\n            return 0;\n        }\n    }\n\n    public Collection<String> getMergedPackages() {\n        try {\n            return (Collection<String>) descriptor.getDeclaredField(\"MERGED_PACKAGES\").get(null);\n        } catch (Exception e) {\n            return Collections.emptySet();\n        }\n    }\n\n    public Collection<String> getMergedClasses() {\n        try {\n            return (Collection<String>) descriptor.getDeclaredField(\"MERGED_CLASSES\").get(null);\n        } catch (Exception e) {\n            return Collections.emptySet();\n        }\n    }\n\n    public void init(Context dynamiteContext) {\n        try {\n            descriptor.getMethod(\"init\", Context.class).invoke(null, dynamiteContext);\n        } catch (Exception e) {\n            // Ignore\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/com/google/android/gms/chimera/container/FilteredClassLoader.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.chimera.container;\n\nimport android.util.Log;\n\nimport java.util.Collection;\nimport java.util.HashSet;\n\npublic class FilteredClassLoader extends ClassLoader {\n    private static ClassLoader rootClassLoader;\n    private final Collection<String> allowedClasses;\n    private final Collection<String> allowedPackages;\n\n    static {\n        rootClassLoader = ClassLoader.getSystemClassLoader();\n        if (rootClassLoader == null) {\n            rootClassLoader = FilteredClassLoader.class.getClassLoader();\n            while (rootClassLoader.getParent() != null) {\n                rootClassLoader = rootClassLoader.getParent();\n            }\n        }\n    }\n\n    public FilteredClassLoader(ClassLoader parent, Collection<String> allowedClasses, Collection<String> allowedPackages) {\n        super(parent);\n        this.allowedClasses = new HashSet<>(allowedClasses);\n        this.allowedPackages = new HashSet<>(allowedPackages);\n    }\n\n    private String getPackageName(String name) {\n        int lastIndex = name.lastIndexOf(\".\");\n        if (lastIndex <= 0) return \"\";\n        return name.substring(0, lastIndex);\n    }\n\n    private String getClassName(String name) {\n        int lastIndex = name.indexOf(\"$\");\n        if (lastIndex <= 0) return name;\n        return name.substring(0, lastIndex);\n    }\n\n    @Override\n    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {\n        if (name.startsWith(\"java.\")) return rootClassLoader.loadClass(name);\n        if (allowedClasses.contains(name) || allowedClasses.contains(getClassName(name)))\n            return super.loadClass(name, resolve);\n        if (allowedClasses.contains(\"!\" + name) || allowedClasses.contains(\"!\" + getClassName(name)))\n            return rootClassLoader.loadClass(name);\n        if (allowedPackages.contains(getPackageName(name))) return super.loadClass(name, resolve);\n        return rootClassLoader.loadClass(name);\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/com/google/android/gms/common/ui/SignInButtonCreatorImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.common.ui;\n\nimport android.content.Context;\nimport android.view.View;\n\nimport com.google.android.gms.common.internal.ISignInButtonCreator;\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.dynamic.ObjectWrapper;\n\npublic class SignInButtonCreatorImpl extends ISignInButtonCreator.Stub {\n    @Override\n    public IObjectWrapper createSignInButton(IObjectWrapper contextWrapper, int size, int color) {\n        Context context = (Context) ObjectWrapper.unwrap(contextWrapper);\n        // TODO: real view :)\n        return ObjectWrapper.wrap(new View(context));\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/com/google/android/gms/dynamite/descriptors/com/google/android/gms/firebase_database/ModuleDescriptor.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.dynamite.descriptors.com.google.android.gms.firebase_database;\n\npublic class ModuleDescriptor {\n    public static final String MODULE_ID = \"com.google.android.gms.firebase_database\";\n    public static final int MODULE_VERSION = 3;\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/com/google/android/gms/dynamite/descriptors/com/google/android/gms/googlecertificates/ModuleDescriptor.java",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 com.google.android.gms.dynamite.descriptors.com.google.android.gms.googlecertificates;\n\npublic class ModuleDescriptor {\n    public static final String MODULE_ID = \"com.google.android.gms.googlecertificates\";\n    public static final int MODULE_VERSION = 1;\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/com/google/android/gms/dynamite/descriptors/com/google/android/gms/measurement/dynamite/ModuleDescriptor.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.dynamite.descriptors.com.google.android.gms.measurement.dynamite;\n\npublic class ModuleDescriptor {\n    public static final String MODULE_ID = \"com.google.android.gms.measurement.dynamite\";\n    public static final int MODULE_VERSION = 140;\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/com/google/android/gms/gcm/http/GoogleHttpService.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.gcm.http;\n\nimport android.app.Service;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.os.IBinder;\nimport android.os.RemoteException;\n\nimport com.google.android.gms.http.IGoogleHttpService;\n\npublic class GoogleHttpService extends Service {\n    @Override\n    public IBinder onBind(Intent intent) {\n        return new IGoogleHttpService.Stub() {\n            @Override\n            public Bundle checkUrl(String url) throws RemoteException {\n                return null; // allow\n            }\n        }.asBinder();\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/com/google/android/gms/plus/plusone/PlusOneButtonCreatorImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.plus.plusone;\n\nimport android.content.Context;\nimport android.os.RemoteException;\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.dynamic.ObjectWrapper;\nimport com.google.android.gms.plus.internal.IPlusOneButtonCreator;\n\nimport org.microg.gms.auth.AuthConstants;\nimport org.microg.gms.plus.PlusOneButtonImpl;\n\npublic class PlusOneButtonCreatorImpl  extends IPlusOneButtonCreator.Stub {\n\t@Override\n\tpublic IObjectWrapper create(IObjectWrapper context, int size, int annotation, String url, int activityRequestCode) throws RemoteException {\n\t\tContext ctx = (Context) ObjectWrapper.unwrap(context);\n\t\treturn ObjectWrapper.wrap(new PlusOneButtonImpl(ctx, size, annotation, url, AuthConstants.DEFAULT_ACCOUNT));\n\t}\n\n\t@Override\n\tpublic IObjectWrapper createForAccount(IObjectWrapper context, int size, int annotation, String url, String account) throws RemoteException {\n\t\tContext ctx = (Context) ObjectWrapper.unwrap(context);\n\t\treturn ObjectWrapper.wrap(new PlusOneButtonImpl(ctx, size, annotation, url, account));\n\t}\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/com/google/android/gms/recovery/RecoveryService.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.recovery;\n\nimport android.app.Service;\nimport android.content.Intent;\nimport android.os.IBinder;\nimport android.util.Log;\n\npublic class RecoveryService extends Service {\n    private static final String TAG = \"GmsRecoverySvc\";\n\n    @Override\n    public IBinder onBind(Intent intent) {\n        Log.d(TAG, \"onBind: \" + intent);\n        return null;\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/com/google/android/gms/semanticlocation/SemanticLocationService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.semanticlocation\n\nimport android.app.PendingIntent\nimport android.util.Log\nimport com.google.android.gms.common.ConnectionResult\nimport com.google.android.gms.common.Feature\nimport com.google.android.gms.common.api.internal.IStatusCallback\nimport com.google.android.gms.common.internal.ConnectionInfo\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport com.google.android.gms.semanticlocation.internal.ISemanticLocationService\nimport com.google.android.gms.semanticlocation.internal.SemanticLocationParameters\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\n\nprivate const val TAG = \"SemanticLocationService\"\n\nprivate val FEATURES = arrayOf(\n    Feature(\"semanticlocation_events\", 1L),\n)\n\nclass SemanticLocationService : BaseService(TAG, GmsService.SEMANTIC_LOCATION) {\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        val connectionInfo = ConnectionInfo().apply {\n            features = FEATURES\n        }\n        callback.onPostInitCompleteWithConnectionInfo(\n            ConnectionResult.SUCCESS,\n            SemanticLocationServiceImpl().asBinder(),\n            connectionInfo\n        )\n    }\n}\n\nclass SemanticLocationServiceImpl : ISemanticLocationService.Stub() {\n    override fun registerSemanticLocationEvents(\n        params: SemanticLocationParameters,\n        callback: IStatusCallback,\n        request: SemanticLocationEventRequest,\n        pendingIntent: PendingIntent\n    ) {\n        Log.d(TAG, \"registerSemanticLocationEvents: $params\")\n    }\n\n    override fun setIncognitoMode(params: SemanticLocationParameters, callback: IStatusCallback, mode: Boolean) {\n        Log.d(TAG, \"setIncognitoMode: $params\")\n    }\n\n    override fun unregisterSemanticLocationEvents(params: SemanticLocationParameters, callback: IStatusCallback, pendingIntent: PendingIntent) {\n        Log.d(TAG, \"unregisterSemanticLocationEvents: $params\")\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/com/google/android/gms/wallet/dynamite/WalletDynamiteCreatorImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wallet.dynamite;\n\npublic class WalletDynamiteCreatorImpl {\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/com/google/firebase/database/connection/idl/IPersistentConnectionImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.firebase.database.connection.idl;\n\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\n\nimport java.util.List;\n\npublic class IPersistentConnectionImpl extends IPersistentConnection.Stub {\n    private static final String TAG = \"GmsFirebaseDbConImpl\";\n\n    @Override\n    public void setup(ConnectionConfig var1, IConnectionAuthTokenProvider var2, IObjectWrapper var3, IPersistentConnectionDelegate var4) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: setup\");\n\n    }\n\n    @Override\n    public void initialize() throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: initialize\");\n\n    }\n\n    @Override\n    public void shutdown() throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: shutdown\");\n\n    }\n\n    @Override\n    public void refreshAuthToken() throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: refreshAuthToken\");\n\n    }\n\n    @Override\n    public void listen(List<String> var1, IObjectWrapper var2, IListenHashProvider var3, long var4, IRequestResultCallback var6) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: listen\");\n\n    }\n\n    @Override\n    public void unlisten(List<String> var1, IObjectWrapper var2) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: unlisten\");\n\n    }\n\n    @Override\n    public void purgeOutstandingWrites() throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: purgeOutstandingWrites\");\n\n    }\n\n    @Override\n    public void put(List<String> var1, IObjectWrapper var2, IRequestResultCallback var3) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: put\");\n\n    }\n\n    @Override\n    public void compareAndPut(List<String> var1, IObjectWrapper var2, String var3, IRequestResultCallback var4) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: compareAndPut\");\n\n    }\n\n    @Override\n    public void merge(List<String> var1, IObjectWrapper var2, IRequestResultCallback var3) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: merge\");\n\n    }\n\n    @Override\n    public void onDisconnectPut(List<String> var1, IObjectWrapper var2, IRequestResultCallback var3) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: onDisconnectPut\");\n\n    }\n\n    @Override\n    public void onDisconnectMerge(List<String> var1, IObjectWrapper var2, IRequestResultCallback var3) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: onDisconnectMerge\");\n\n    }\n\n    @Override\n    public void onDisconnectCancel(List<String> var1, IRequestResultCallback var2) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: onDisconnectCancel\");\n\n    }\n\n    @Override\n    public void interrupt(String var1) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: interrupt\");\n\n    }\n\n    @Override\n    public void resume(String var1) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: resume\");\n\n    }\n\n    @Override\n    public boolean isInterrupted(String var1) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: isInterrupted\");\n        return false;\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/ads/GService.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.ads;\n\nimport android.os.RemoteException;\nimport com.google.android.gms.common.ConnectionResult;\nimport com.google.android.gms.common.internal.GetServiceRequest;\nimport com.google.android.gms.common.internal.IGmsCallbacks;\n\nimport org.microg.gms.BaseService;\nimport org.microg.gms.common.GmsService;\n\npublic class GService extends BaseService {\n\n    public GService() {\n        super(\"GmsAdsGSvc\", GmsService.ADMOB_GSERVICES_VALUE, GmsService.ADMOB);\n    }\n\n    @Override\n    public void handleServiceRequest(IGmsCallbacks callback, GetServiceRequest request, GmsService service) throws RemoteException {\n        callback.onPostInitComplete(ConnectionResult.API_DISABLED, null, null);\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/auth/AccountContentProvider.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.auth;\n\nimport static android.accounts.AccountManager.VISIBILITY_VISIBLE;\n\nimport android.Manifest;\nimport android.accounts.Account;\nimport android.accounts.AccountManager;\nimport android.content.ContentProvider;\nimport android.content.ContentValues;\nimport android.content.pm.PackageManager;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.os.Binder;\nimport android.os.Bundle;\nimport android.util.Log;\n\nimport androidx.annotation.Nullable;\n\nimport org.microg.gms.common.GooglePackagePermission;\nimport org.microg.gms.common.PackageUtils;\n\nimport java.util.Arrays;\n\nimport static android.os.Build.VERSION.SDK_INT;\nimport static org.microg.gms.auth.AuthConstants.DEFAULT_ACCOUNT_TYPE;\nimport static org.microg.gms.auth.AuthConstants.PROVIDER_EXTRA_ACCOUNTS;\nimport static org.microg.gms.auth.AuthConstants.PROVIDER_EXTRA_CLEAR_PASSWORD;\nimport static org.microg.gms.auth.AuthConstants.PROVIDER_METHOD_CLEAR_PASSWORD;\nimport static org.microg.gms.auth.AuthConstants.PROVIDER_METHOD_GET_ACCOUNTS;\n\npublic class AccountContentProvider extends ContentProvider {\n    private static final String TAG = \"GmsAuthProvider\";\n\n    @Override\n    public boolean onCreate() {\n        return true;\n    }\n\n    @Nullable\n    @Override\n    public Bundle call(String method, String arg, Bundle extras) {\n        String suggestedPackageName = null;\n        if (SDK_INT > 19) {\n            suggestedPackageName = getCallingPackage();\n        }\n        String packageName = PackageUtils.getAndCheckCallingPackage(getContext(), suggestedPackageName);\n        boolean hasGooglePackagePermission = PackageUtils.callerHasGooglePackagePermission(getContext(), GooglePackagePermission.ACCOUNT);\n        if (!hasGooglePackagePermission) {\n            String[] packagesForUid = getContext().getPackageManager().getPackagesForUid(Binder.getCallingUid());\n            if (packagesForUid != null && packagesForUid.length != 0)\n                Log.w(TAG, \"Not granting extended access to \" + Arrays.toString(packagesForUid)\n                        + \", signature: \" + PackageUtils.firstSignatureDigest(getContext(), packagesForUid[0]));\n            if (getContext().checkCallingPermission(Manifest.permission.GET_ACCOUNTS) != PackageManager.PERMISSION_GRANTED)\n                throw new SecurityException(\"Access denied, missing google package permission or GET_ACCOUNTS\");\n        }\n        long identityToken = Binder.clearCallingIdentity();\n        try {\n            if (PROVIDER_METHOD_GET_ACCOUNTS.equals(method)) {\n                Bundle result = new Bundle();\n                Account[] accounts = null;\n                if (arg != null && (arg.equals(DEFAULT_ACCOUNT_TYPE) || arg.startsWith(DEFAULT_ACCOUNT_TYPE + \".\"))) {\n                    AccountManager am = AccountManager.get(getContext());\n                    accounts = am.getAccountsByTypeForPackage(arg, packageName);\n                    if (SDK_INT >= 26 && accounts != null && arg.equals(DEFAULT_ACCOUNT_TYPE)) {\n                        for (Account account : accounts) {\n                            if (am.getAccountVisibility(account, packageName) == AccountManager.VISIBILITY_UNDEFINED &&\n                                    (hasGooglePackagePermission || AuthPrefs.isAuthVisible(getContext()))) {\n                                Log.d(TAG, \"Make account \" + account + \" visible to \" + packageName);\n                                am.setAccountVisibility(account, packageName, VISIBILITY_VISIBLE);\n                            }\n                        }\n                    }\n                }\n                if (accounts == null) {\n                    accounts = new Account[0];\n                }\n\n                result.putParcelableArray(PROVIDER_EXTRA_ACCOUNTS, accounts);\n                return result;\n            } else if (PROVIDER_METHOD_CLEAR_PASSWORD.equals(method) && hasGooglePackagePermission) {\n                Account a = extras.getParcelable(PROVIDER_EXTRA_CLEAR_PASSWORD);\n                AccountManager.get(getContext()).clearPassword(a);\n                return null;\n            }\n            throw new UnsupportedOperationException(String.format(\"Unsupported method call %s(%s).\", method, arg));\n        } finally {\n            Binder.restoreCallingIdentity(identityToken);\n        }\n    }\n\n    @Nullable\n    @Override\n    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Nullable\n    @Override\n    public String getType(Uri uri) {\n        return \"text/plain\";\n    }\n\n    @Nullable\n    @Override\n    public Uri insert(Uri uri, ContentValues values) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public int delete(Uri uri, String selection, String[] selectionArgs) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {\n        throw new UnsupportedOperationException();\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/auth/AskPermissionActivity.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.auth;\n\nimport android.accounts.Account;\nimport android.accounts.AccountAuthenticatorActivity;\nimport android.accounts.AccountManager;\nimport android.app.NotificationManager;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageManager;\nimport android.graphics.Bitmap;\nimport android.graphics.drawable.Drawable;\nimport android.os.Bundle;\nimport android.text.Html;\nimport android.util.Log;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.view.WindowManager;\nimport android.widget.BaseAdapter;\nimport android.widget.ImageView;\nimport android.widget.ListView;\nimport android.widget.TextView;\n\nimport com.google.android.gms.R;\n\nimport org.microg.gms.common.PackageUtils;\nimport org.microg.gms.people.PeopleManager;\n\nimport java.io.IOException;\n\nimport static android.accounts.AccountManager.KEY_ACCOUNT_NAME;\nimport static android.accounts.AccountManager.KEY_ACCOUNT_TYPE;\nimport static android.accounts.AccountManager.KEY_ANDROID_PACKAGE_NAME;\nimport static android.accounts.AccountManager.KEY_AUTHTOKEN;\nimport static android.accounts.AccountManager.KEY_CALLER_PID;\nimport static android.accounts.AccountManager.KEY_CALLER_UID;\nimport static android.view.View.GONE;\nimport static android.view.View.VISIBLE;\n\npublic class AskPermissionActivity extends AccountAuthenticatorActivity {\n    public static final String EXTRA_FROM_ACCOUNT_MANAGER = \"from_account_manager\";\n    public static final String EXTRA_CONSENT_DATA = \"consent_data\";\n\n    private static final String TAG = \"GmsAuthAskPermission\";\n    private AuthManager authManager;\n    private IntentData data;\n\n    private static class IntentData {\n        private String accountName;\n        private String accountType;\n        private Account account;\n\n        private String packageName;\n        private String service;\n\n        private int callerUid;\n        private int callerPid;\n\n        private ConsentData consentData;\n        private boolean fromAccountManager = false;\n\n        private CharSequence appLabel;\n        private Drawable appIcon;\n\n        private IntentData(Intent intent) {\n            if (intent != null) {\n                accountName = intent.getStringExtra(KEY_ACCOUNT_NAME);\n                accountType = intent.getStringExtra(KEY_ACCOUNT_TYPE);\n                packageName = intent.getStringExtra(KEY_ANDROID_PACKAGE_NAME);\n                service = intent.getStringExtra(KEY_AUTHTOKEN);\n                callerUid = intent.getIntExtra(KEY_CALLER_UID, 0);\n                callerPid = intent.getIntExtra(KEY_CALLER_PID, 0);\n                fromAccountManager = intent.hasExtra(EXTRA_FROM_ACCOUNT_MANAGER);\n                if (intent.hasExtra(EXTRA_CONSENT_DATA)) {\n                    try {\n                        consentData = ConsentData.ADAPTER.decode(intent.getByteArrayExtra(EXTRA_CONSENT_DATA));\n                    } catch (Exception e) {\n                        // Ignore\n                    }\n                }\n            }\n            if (accountName != null && accountType != null) {\n                account = new Account(accountName, accountType);\n            }\n        }\n\n        private void verify(Context context) throws Exception {\n            if (accountName == null || accountType == null || account == null) throw new IllegalArgumentException(\"Required account information missing\");\n            if (packageName == null || service == null) throw new IllegalArgumentException(\"Required request information missing\");\n            if (callerUid == 0) throw new IllegalArgumentException(\"Required caller information missing\");\n            PackageUtils.getAndCheckPackage(context, packageName, callerUid, callerPid);\n\n            PackageManager packageManager = context.getPackageManager();\n            ApplicationInfo applicationInfo = packageManager.getApplicationInfo(packageName, 0);\n            appLabel = packageManager.getApplicationLabel(applicationInfo);\n            appIcon = packageManager.getApplicationIcon(applicationInfo);\n        }\n    }\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.ask_permission);\n        data = new IntentData(getIntent());\n        try {\n            data.verify(this);\n        } catch (Exception e) {\n            Log.w(TAG, \"Verification failed\", e);\n            finish();\n            return;\n        }\n\n        // This makes the dialog take up the full width\n        WindowManager.LayoutParams lp = new WindowManager.LayoutParams();\n        lp.copyFrom(getWindow().getAttributes());\n        lp.width = WindowManager.LayoutParams.MATCH_PARENT;\n        lp.height = WindowManager.LayoutParams.WRAP_CONTENT;\n        getWindow().setAttributes(lp);\n\n        NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);\n        nm.cancel(data.packageName.hashCode());\n\n        authManager = new AuthManager(this, data.accountName, data.packageName, data.service);\n\n        Bitmap profileIcon = PeopleManager.getOwnerAvatarBitmap(this, data.accountName, false);\n\n        // receive profile icon\n        if (profileIcon != null) {\n            ((ImageView) findViewById(R.id.account_photo)).setImageBitmap(profileIcon);\n        } else {\n            new Thread(() -> {\n                final Bitmap profileIcon1 = PeopleManager.getOwnerAvatarBitmap(AskPermissionActivity.this, data.accountName, true);\n                runOnUiThread(() -> ((ImageView) findViewById(R.id.account_photo)).setImageBitmap(profileIcon1));\n            }).start();\n        }\n\n        ((ImageView) findViewById(R.id.app_icon)).setImageDrawable(data.appIcon);\n        if (isOAuth()) {\n            ((TextView) findViewById(R.id.title)).setText(getString(R.string.ask_scope_permission_title, data.appLabel));\n        } else {\n            ((TextView) findViewById(R.id.title)).setText(getString(R.string.ask_service_permission_title, data.appLabel));\n        }\n        findViewById(android.R.id.button1).setOnClickListener(v -> onAllow());\n        findViewById(android.R.id.button2).setOnClickListener(v -> onDeny());\n        ((ListView) findViewById(R.id.permissions)).setAdapter(new PermissionAdapter());\n    }\n\n    public void onAllow() {\n        authManager.setPermitted(true);\n        findViewById(android.R.id.button1).setEnabled(false);\n        findViewById(android.R.id.button2).setEnabled(false);\n        findViewById(R.id.progress_bar).setVisibility(VISIBLE);\n        findViewById(R.id.no_progress_bar).setVisibility(GONE);\n        new Thread(() -> {\n            try {\n                AuthResponse response = authManager.requestAuthWithBackgroundResolution(data.fromAccountManager);\n                Bundle result = new Bundle();\n                result.putString(KEY_AUTHTOKEN, response.auth);\n                result.putString(KEY_ACCOUNT_NAME, data.accountName);\n                result.putString(KEY_ACCOUNT_TYPE, data.accountType);\n                result.putString(KEY_ANDROID_PACKAGE_NAME, data.packageName);\n                result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);\n                setAccountAuthenticatorResult(result);\n            } catch (IOException e) {\n                Log.w(TAG, e);\n            }\n            finish();\n        }).start();\n    }\n\n    public void onDeny() {\n        authManager.setPermitted(false);\n        finish();\n    }\n\n    @Override\n    public void finish() {\n        if (data.packageName != null) {\n            NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);\n            nm.cancel(data.packageName.hashCode());\n        }\n        super.finish();\n    }\n\n    private boolean isOAuth() {\n        return data.service.startsWith(\"oauth2:\") || data.service.startsWith(\"oauth:\");\n    }\n\n    private String getScopeLabel(String scope) {\n        if (data.consentData != null) {\n            for (ConsentData.ScopeDetails scopeDetails : data.consentData.scopes) {\n                if (scope.equals(scopeDetails.id)) {\n                    return scopeDetails.title;\n                }\n            }\n        }\n        String labelResourceId = \"permission_scope_\";\n        String escapedScope = scope.replace(\"/\", \"_\").replace(\"-\", \"_\");\n        if (scope.startsWith(\"https://\")) {\n            labelResourceId += escapedScope.substring(8);\n        } else {\n            labelResourceId += escapedScope;\n        }\n        int labelResource = getResources().getIdentifier(labelResourceId, \"string\", getPackageName());\n        if (labelResource != 0) {\n            return getString(labelResource);\n        }\n        return \"unknown\";\n    }\n\n    private String getScopeDescription(String scope) {\n        if (data.consentData != null) {\n            for (ConsentData.ScopeDetails scopeDetails : data.consentData.scopes) {\n                if (scope.equals(scopeDetails.id)) {\n                    return scopeDetails.description;\n                }\n            }\n        }\n        return null;\n    }\n\n    private String getServiceLabel(String service) {\n        int labelResource = getResources().getIdentifier(\"permission_service_\" + service + \"_label\", \"string\", getPackageName());\n        if (labelResource != 0) {\n            return getString(labelResource);\n        }\n        return \"unknown\";\n    }\n\n    private class PermissionAdapter extends BaseAdapter {\n\n        @Override\n        public int getCount() {\n            if (isOAuth()) {\n                return data.service.split(\" \").length;\n            }\n            return 1;\n        }\n\n        @Override\n        public String getItem(int position) {\n            if (isOAuth()) {\n                String tokens = data.service.split(\":\", 2)[1];\n                return tokens.split(\" \")[position];\n            }\n            return data.service;\n        }\n\n        @Override\n        public long getItemId(int position) {\n            return getItem(position).hashCode();\n        }\n\n        @Override\n        public View getView(int position, View convertView, ViewGroup parent) {\n            String item = getItem(position);\n            String label;\n            String description;\n            if (isOAuth()) {\n                label = getScopeLabel(item);\n                description = getScopeDescription(item);\n            } else {\n                label = getServiceLabel(item);\n                description = null;\n            }\n            View view = convertView;\n            if (view == null) {\n                view = LayoutInflater.from(AskPermissionActivity.this)\n                        .inflate(R.layout.ask_permission_list_entry, parent, false);\n            }\n            ((TextView) view.findViewById(android.R.id.text1)).setText(label);\n            TextView textView = (TextView) view.findViewById(android.R.id.text2);\n            if (description != null && !description.isEmpty()) {\n                textView.setText(Html.fromHtml(description.trim().replace(\"\\n\", \"<br>\")));\n                textView.setVisibility(VISIBLE);\n            } else {\n                textView.setVisibility(GONE);\n            }\n            return view;\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/auth/AuthManager.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth;\n\nimport android.accounts.Account;\nimport android.accounts.AccountManager;\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.content.pm.PackageManager;\nimport android.net.Uri;\nimport android.util.Log;\n\nimport androidx.annotation.NonNull;\nimport org.microg.gms.accountaction.ErrorResolverKt;\nimport org.microg.gms.accountaction.Resolution;\nimport org.microg.gms.common.NotOkayException;\nimport org.microg.gms.common.PackageUtils;\nimport org.microg.gms.settings.SettingsContract;\n\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport static android.content.pm.ApplicationInfo.FLAG_SYSTEM;\nimport static android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;\nimport static android.os.Build.VERSION.SDK_INT;\nimport static org.microg.gms.auth.AuthPrefs.isTrustGooglePermitted;\n\npublic class AuthManager {\n\n    private static final String TAG = \"GmsAuthManager\";\n    public static final String PERMISSION_TREE_BASE = \"com.google.android.googleapps.permission.GOOGLE_AUTH.\";\n    public static final String PREF_AUTH_VISIBLE = SettingsContract.Auth.VISIBLE;\n    public static final int ONE_HOUR_IN_SECONDS = 60 * 60;\n    public Map<Object, Object> dynamicFields = new HashMap<>();\n    private final Context context;\n    private final String accountName;\n    private final String packageName;\n    private final String service;\n    private AccountManager accountManager;\n    private Account account;\n    private String packageSignature;\n    private String accountType;\n\n\n    private int delegationType;\n    private String delegateeUserId;\n    private String oauth2Foreground;\n    private String oauth2Prompt;\n    private String itCaveatTypes;\n    private String tokenRequestOptions;\n    public String includeEmail;\n    public String includeProfile;\n    public boolean isGmsApp;\n    public boolean ignoreStoredPermission = false;\n    public boolean forceRefreshToken = false;\n\n    public AuthManager(Context context, String accountName, String packageName, String service) {\n        this.context = context;\n        this.accountName = accountName;\n        this.packageName = packageName;\n        this.service = service;\n    }\n\n    public String getAccountType() {\n        if (accountType == null)\n            accountType = AuthConstants.DEFAULT_ACCOUNT_TYPE;\n        return accountType;\n    }\n\n    public AccountManager getAccountManager() {\n        if (accountManager == null)\n            accountManager = AccountManager.get(context);\n        return accountManager;\n    }\n\n    public Account getAccount() {\n        if (account == null)\n            account = new Account(accountName, getAccountType());\n        return account;\n    }\n\n    public void setPackageSignature(String packageSignature) {\n        this.packageSignature = packageSignature;\n    }\n\n    public String getPackageSignature() {\n        if (packageSignature == null)\n            packageSignature = PackageUtils.firstSignatureDigest(context, packageName);\n        return packageSignature;\n    }\n\n    public String buildTokenKey(String service) {\n        Uri.Builder builder = Uri.EMPTY.buildUpon();\n        if (delegationType != 0 && delegateeUserId != null)\n            builder.appendQueryParameter(\"delegation_type\", Integer.toString(delegationType))\n                    .appendQueryParameter(\"delegatee_user_id\", delegateeUserId);\n        if (tokenRequestOptions != null) builder.appendQueryParameter(\"token_request_options\", tokenRequestOptions);\n        if (includeEmail != null) builder.appendQueryParameter(\"include_email\", includeEmail);\n        if (includeProfile != null) builder.appendQueryParameter(\"include_profile\", includeEmail);\n        String query = builder.build().getEncodedQuery();\n        return packageName + \":\" + getPackageSignature() + \":\" + service + (query != null ? (\"?\" + query) : \"\");\n    }\n\n    public String buildTokenKey() {\n        return buildTokenKey(service);\n    }\n\n    public String buildPermKey() {\n        return \"perm.\" + buildTokenKey();\n    }\n\n    public void setPermitted(boolean value) {\n        setUserData(buildPermKey(), value ? \"1\" : \"0\");\n        if (SDK_INT >= 26 && value && packageName != null) {\n            // Make account persistently visible as we already granted access\n            accountManager.setAccountVisibility(getAccount(), packageName, AccountManager.VISIBILITY_VISIBLE);\n        }\n    }\n\n    public boolean isPermitted() {\n        if (!service.startsWith(\"oauth\")) {\n            if (context.getPackageManager().checkPermission(PERMISSION_TREE_BASE + service, packageName) == PackageManager.PERMISSION_GRANTED) {\n                return true;\n            }\n        }\n        String perm = getUserData(buildPermKey());\n        if (!\"1\".equals(perm)) {\n            return false;\n        }\n        return true;\n    }\n\n    public void setExpiry(long expiry) {\n        setUserData(buildExpireKey(), Long.toString(expiry));\n    }\n\n    public String getUserData(String key) {\n        return getAccountManager().getUserData(getAccount(), key);\n    }\n\n    public void setUserData(String key, String value) {\n        getAccountManager().setUserData(getAccount(), key, value);\n    }\n\n    public void setDelegation(int delegationType, String delegateeUserId) {\n        if (delegationType != 0 && delegateeUserId != null) {\n            this.delegationType = delegationType;\n            this.delegateeUserId = delegateeUserId;\n        } else {\n            this.delegationType = 0;\n            this.delegateeUserId = null;\n        }\n    }\n\n    public void setOauth2Foreground(String oauth2Foreground) {\n        this.oauth2Foreground = oauth2Foreground;\n    }\n\n    public void setOauth2Prompt(String oauth2Prompt) {\n        this.oauth2Prompt = oauth2Prompt;\n    }\n\n    public void setItCaveatTypes(String itCaveatTypes) {\n        this.itCaveatTypes = itCaveatTypes;\n    }\n\n    public void setTokenRequestOptions(String tokenRequestOptions) {\n        this.tokenRequestOptions = tokenRequestOptions;\n    }\n\n    public void putDynamicFiled(Object key, Object value) {\n        this.dynamicFields.put(key, value);\n    }\n\n    public boolean accountExists() {\n        for (Account refAccount : getAccountManager().getAccountsByType(accountType)) {\n            if (refAccount.name.equalsIgnoreCase(accountName)) return true;\n        }\n        return false;\n    }\n\n    public String peekAuthToken() {\n        Log.d(TAG, \"peekAuthToken: \" + buildTokenKey());\n        return getAccountManager().peekAuthToken(getAccount(), buildTokenKey());\n    }\n\n    public String getAuthToken() {\n        if (service.startsWith(\"weblogin:\")) return null;\n        if (System.currentTimeMillis() / 1000L >= getExpiry() - 300L) {\n            Log.d(TAG, \"token present, but expired\");\n            return null;\n        }\n        return peekAuthToken();\n    }\n\n    public String buildExpireKey() {\n        return \"EXP.\" + buildTokenKey();\n    }\n\n    public long getExpiry() {\n        String exp = getUserData(buildExpireKey());\n        if (exp == null) return -1;\n        return Long.parseLong(exp);\n    }\n\n    public void setAuthToken(String auth) {\n        setAuthToken(service, auth);\n    }\n\n    public void setAuthToken(String service, String auth) {\n        getAccountManager().setAuthToken(getAccount(), buildTokenKey(service), auth);\n        if (SDK_INT >= 26 && packageName != null && auth != null) {\n            // Make account persistently visible as we already granted access\n            accountManager.setAccountVisibility(getAccount(), packageName, AccountManager.VISIBILITY_VISIBLE);\n        }\n    }\n\n    public void invalidateAuthToken() {\n        String authToken = peekAuthToken();\n        invalidateAuthToken(authToken);\n    }\n\n    @SuppressLint(\"MissingPermission\")\n    public void invalidateAuthToken(String auth) {\n        getAccountManager().invalidateAuthToken(accountType, auth);\n    }\n\n    public void storeResponse(AuthResponse response) {\n        if (service.startsWith(\"weblogin:\")) return;\n        if (response.accountId != null)\n            setUserData(\"GoogleUserId\", response.accountId);\n        if (response.Sid != null)\n            setAuthToken(\"SID\", response.Sid);\n        if (response.LSid != null)\n            setAuthToken(\"LSID\", response.LSid);\n        if (response.auth != null && (response.expiry != 0 || response.storeConsentRemotely)) {\n            setAuthToken(response.auth);\n            if (response.expiry > 0) {\n                setExpiry(response.expiry);\n            } else {\n                setExpiry(System.currentTimeMillis() / 1000 + ONE_HOUR_IN_SECONDS); // make valid for one hour by default\n            }\n        }\n    }\n\n    private boolean isSystemApp() {\n        try {\n            int flags = context.getPackageManager().getApplicationInfo(packageName, 0).flags;\n            return (flags & FLAG_SYSTEM) > 0 || (flags & FLAG_UPDATED_SYSTEM_APP) > 0;\n        } catch (PackageManager.NameNotFoundException e) {\n            return false;\n        }\n    }\n\n    @NonNull\n    public AuthResponse requestAuthWithBackgroundResolution(boolean legacy) throws IOException {\n        try {\n            return requestAuth(legacy);\n        } catch (NotOkayException e) {\n            if (e.getMessage() != null) {\n                Resolution errorResolution = ErrorResolverKt.resolveAuthErrorMessage(context, e.getMessage());\n                if (errorResolution != null) {\n                    AuthResponse response = ErrorResolverKt.initiateFromBackgroundBlocking(\n                            errorResolution,\n                            context,\n                            getAccount(),\n                            // infinite loop is prevented\n                            () -> requestAuth(legacy)\n                    );\n                    if (response == null) throw new IOException(e);\n                    return response;\n                } else {\n                    throw new IOException(e);\n                }\n            } else {\n                throw new IOException(e);\n            }\n        }\n    }\n\n    @NonNull\n    public AuthResponse requestAuthWithForegroundResolution(boolean legacy) throws IOException {\n        try {\n            return requestAuth(legacy);\n        } catch (NotOkayException e) {\n            if (e.getMessage() != null) {\n                Resolution errorResolution = ErrorResolverKt.resolveAuthErrorMessage(context, e.getMessage());\n                if (errorResolution != null) {\n                    AuthResponse response = ErrorResolverKt.initiateFromForegroundBlocking(\n                            errorResolution,\n                            context,\n                            getAccount(),\n                            // infinite loop is prevented\n                            () -> requestAuth(legacy)\n                    );\n                    if (response == null) throw new IOException(e);\n                    return response;\n                } else {\n                    throw new IOException(e);\n                }\n            } else {\n                throw new IOException(e);\n            }\n        }\n    }\n\n    @NonNull\n    public AuthResponse requestAuth(boolean legacy) throws IOException {\n        if (service.equals(AuthConstants.SCOPE_GET_ACCOUNT_ID)) {\n            AuthResponse response = new AuthResponse();\n            response.accountId = response.auth = getAccountManager().getUserData(getAccount(), \"GoogleUserId\");\n            return response;\n        }\n        if (isPermitted() || isTrustGooglePermitted(context)) {\n            String token = getAuthToken();\n            if (token != null && !forceRefreshToken) {\n                AuthResponse response = new AuthResponse();\n                response.issueAdvice = \"stored\";\n                response.auth = token;\n                if (service.startsWith(\"oauth2:\")) {\n                    response.grantedScopes = service.substring(7);\n                }\n                response.expiry = getExpiry();\n                return response;\n            }\n        }\n        AuthRequest request = new AuthRequest().fromContext(context)\n                .source(\"android\")\n                .app(packageName, getPackageSignature())\n                .email(accountName)\n                .token(getAccountManager().getPassword(getAccount()))\n                .service(service)\n                .delegation(delegationType, delegateeUserId)\n                .oauth2Foreground(oauth2Foreground)\n                .oauth2Prompt(oauth2Prompt)\n                .oauth2IncludeProfile(includeProfile)\n                .oauth2IncludeEmail(includeEmail)\n                .itCaveatTypes(itCaveatTypes)\n                .tokenRequestOptions(tokenRequestOptions)\n                .systemPartition(isSystemApp())\n                .hasPermission(!ignoreStoredPermission && isPermitted())\n                .putDynamicFiledMap(dynamicFields);\n        if (isGmsApp) {\n            request.appIsGms();\n        }\n        if (legacy) {\n            request.callerIsGms().calledFromAccountManager();\n        } else {\n            request.callerIsApp();\n        }\n        AuthResponse response = request.getResponse();\n        if (!isPermitted() && !isTrustGooglePermitted(context)) {\n            response.auth = null;\n        } else {\n            storeResponse(response);\n        }\n        return response;\n    }\n\n    public String getService() {\n        return service;\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/auth/AuthManagerServiceImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.auth;\n\nimport android.accounts.Account;\nimport android.accounts.AccountManager;\nimport android.annotation.SuppressLint;\nimport android.app.NotificationManager;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.os.Bundle;\nimport android.os.Parcel;\nimport android.os.RemoteException;\nimport android.util.Base64;\nimport android.util.Log;\n\nimport androidx.core.app.NotificationCompat;\nimport androidx.core.app.PendingIntentCompat;\n\nimport com.google.android.auth.IAuthManagerService;\nimport com.google.android.gms.R;\nimport com.google.android.gms.auth.AccountChangeEventsRequest;\nimport com.google.android.gms.auth.AccountChangeEventsResponse;\nimport com.google.android.gms.auth.GetHubTokenInternalResponse;\nimport com.google.android.gms.auth.GetHubTokenRequest;\nimport com.google.android.gms.auth.HasCapabilitiesRequest;\nimport com.google.android.gms.auth.TokenData;\nimport com.google.android.gms.common.api.Scope;\n\nimport org.microg.gms.common.GooglePackagePermission;\nimport org.microg.gms.common.PackageUtils;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.concurrent.TimeUnit;\n\nimport static android.accounts.AccountManager.*;\nimport static android.os.Build.VERSION.SDK_INT;\nimport static org.microg.gms.auth.AskPermissionActivity.EXTRA_CONSENT_DATA;\n\npublic class AuthManagerServiceImpl extends IAuthManagerService.Stub {\n    private static final String TAG = \"GmsAuthManagerSvc\";\n\n    public static final String KEY_ACCOUNT_FEATURES = \"account_features\";\n    public static final String KEY_AUTHORITY = \"authority\";\n    public static final String KEY_CALLBACK_INTENT = \"callback_intent\";\n    public static final String KEY_CALLER_UID = \"callerUid\";\n    public static final String KEY_ANDROID_PACKAGE_NAME = \"androidPackageName\";\n    public static final String KEY_CLIENT_PACKAGE_NAME = \"clientPackageName\";\n    public static final String KEY_HANDLE_NOTIFICATION = \"handle_notification\";\n    public static final String KEY_REQUEST_ACTIONS = \"request_visible_actions\";\n    public static final String KEY_REQUEST_VISIBLE_ACTIVITIES = \"request_visible_actions\";\n    public static final String KEY_SUPPRESS_PROGRESS_SCREEN = \"suppressProgressScreen\";\n    public static final String KEY_SYNC_EXTRAS = \"sync_extras\";\n    public static final String KEY_DELEGATION_TYPE = \"delegation_type\";\n    public static final String KEY_DELEGATEE_USER_ID = \"delegatee_user_id\";\n\n    public static final String KEY_ERROR = \"Error\";\n    public static final String KEY_USER_RECOVERY_INTENT = \"userRecoveryIntent\";\n\n    private final Context context;\n\n    public AuthManagerServiceImpl(Context context) {\n        this.context = context;\n    }\n\n    @Override\n    public Bundle getToken(String accountName, String scope, Bundle extras) {\n        return getTokenWithAccount(new Account(accountName, AuthConstants.DEFAULT_ACCOUNT_TYPE), scope, extras);\n    }\n\n    private List<Scope> getScopes(String scope) {\n        if (!scope.startsWith(\"oauth2:\")) return null;\n        String[] strings = scope.substring(7).split(\" \");\n        List<Scope> res = new ArrayList<Scope>();\n        for (String string : strings) {\n            res.add(new Scope(string));\n        }\n        return res;\n    }\n\n    private static CharSequence getPackageLabel(String packageName, PackageManager pm) {\n        try {\n            return pm.getApplicationLabel(pm.getApplicationInfo(packageName, 0));\n        } catch (PackageManager.NameNotFoundException e) {\n            return packageName;\n        }\n    }\n\n    @Override\n    public AccountChangeEventsResponse getChangeEvents(AccountChangeEventsRequest request) {\n        return new AccountChangeEventsResponse();\n    }\n\n    @Override\n    public Bundle getTokenWithAccount(Account account, String scope, Bundle extras) {\n        String packageName = extras.getString(KEY_ANDROID_PACKAGE_NAME);\n        if (packageName == null || packageName.isEmpty())\n            packageName = extras.getString(KEY_CLIENT_PACKAGE_NAME);\n        packageName = PackageUtils.getAndCheckCallingPackage(context, packageName, extras.getInt(KEY_CALLER_UID, 0), extras.getInt(KEY_CALLER_PID, 0));\n        boolean notify = extras.getBoolean(KEY_HANDLE_NOTIFICATION, false);\n\n        scope = Objects.equals(AuthConstants.SCOPE_OAUTH2, scope) ? AuthConstants.SCOPE_EM_OP_PRO : scope;\n\n        if (!AuthConstants.SCOPE_GET_ACCOUNT_ID.equals(scope))\n            Log.d(TAG, \"getToken: account:\" + account.name + \" scope:\" + scope + \" extras:\" + extras + \", notify: \" + notify);\n\n        scope = Objects.equals(AuthConstants.SCOPE_OAUTH2, scope) ? AuthConstants.SCOPE_EM_OP_PRO : scope;\n\n        /*\n         * TODO: This scope seems to be invalid (according to https://developers.google.com/oauthplayground/),\n         * but is used in some applications anyway. Removing it is unlikely a good solution, but works for now.\n         */\n        scope = scope.replace(\"https://www.googleapis.com/auth/identity.plus.page.impersonation \", \"\");\n\n        AuthManager authManager = new AuthManager(context, account.name, packageName, scope);\n        if (extras.containsKey(KEY_DELEGATION_TYPE) && extras.getInt(KEY_DELEGATION_TYPE) != 0 ) {\n            authManager.setDelegation(extras.getInt(KEY_DELEGATION_TYPE), extras.getString(\"delegatee_user_id\"));\n        }\n        authManager.setOauth2Foreground(notify ? \"0\" : \"1\");\n        Bundle result = new Bundle();\n        result.putString(KEY_ACCOUNT_NAME, account.name);\n        result.putString(KEY_ACCOUNT_TYPE, authManager.getAccountType());\n        if (!authManager.accountExists()) {\n            result.putString(KEY_ERROR, \"NetworkError\");\n            return result;\n        }\n        try {\n            AuthResponse res = authManager.requestAuthWithBackgroundResolution(false);\n            if (res.auth != null) {\n                if (!AuthConstants.SCOPE_GET_ACCOUNT_ID.equals(scope))\n                    Log.d(TAG, \"getToken: \" + res);\n                result.putString(KEY_AUTHTOKEN, res.auth);\n                Bundle details = new Bundle();\n                details.putParcelable(\"TokenData\", new TokenData(res.auth, res.expiry, scope.startsWith(\"oauth2:\"), getScopes(res.grantedScopes != null ? res.grantedScopes : scope)));\n                result.putBundle(\"tokenDetails\", details);\n                result.putString(KEY_ERROR, \"OK\");\n            } else {\n                result.putString(KEY_ERROR, \"NeedPermission\");\n                Intent i = new Intent(context, AskPermissionActivity.class);\n                i.putExtras(extras);\n                i.putExtra(KEY_ANDROID_PACKAGE_NAME, packageName);\n                i.putExtra(KEY_ACCOUNT_TYPE, authManager.getAccountType());\n                i.putExtra(KEY_ACCOUNT_NAME, account.name);\n                i.putExtra(KEY_AUTHTOKEN, scope);\n                i.putExtra(KEY_CALLER_UID, getCallingUid());\n                i.putExtra(KEY_CALLER_PID, getCallingPid());\n                try {\n                    if (res.consentDataBase64 != null)\n                        i.putExtra(EXTRA_CONSENT_DATA, Base64.decode(res.consentDataBase64, Base64.URL_SAFE));\n                } catch (Exception e) {\n                    Log.w(TAG, \"Can't decode consent data: \", e);\n                }\n                if (notify) {\n                    NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);\n                    nm.notify(packageName.hashCode(), new NotificationCompat.Builder(context)\n                            .setContentIntent(PendingIntentCompat.getActivity(context, 0, i, 0, false))\n                            .setContentTitle(context.getString(R.string.auth_notification_title))\n                            .setContentText(context.getString(R.string.auth_notification_content, getPackageLabel(packageName, context.getPackageManager())))\n                            .setSmallIcon(android.R.drawable.stat_notify_error)\n                            .build());\n                }\n                result.putParcelable(KEY_USER_RECOVERY_INTENT, i);\n            }\n        } catch (IOException e) {\n            Log.w(TAG, e);\n            result.putString(KEY_ERROR, \"NetworkError\");\n        }\n        return result;\n    }\n\n    @Override\n    public Bundle getAccounts(Bundle extras) {\n        PackageUtils.assertGooglePackagePermission(context, GooglePackagePermission.ACCOUNT);\n        String[] accountFeatures = extras.getStringArray(KEY_ACCOUNT_FEATURES);\n        String accountType = extras.getString(KEY_ACCOUNT_TYPE);\n        Account[] accounts;\n        if (accountFeatures != null) {\n            try {\n                accounts = AccountManager.get(context).getAccountsByTypeAndFeatures(accountType, accountFeatures, null, null).getResult(5, TimeUnit.SECONDS);\n            } catch (Exception e) {\n                Log.w(TAG, e);\n                return null;\n            }\n        } else {\n            accounts = AccountManager.get(context).getAccountsByType(accountType);\n        }\n        Bundle res = new Bundle();\n        res.putParcelableArray(KEY_ACCOUNTS, accounts);\n        return res;\n    }\n\n    @Override\n    public Bundle removeAccount(Account account) {\n        Log.w(TAG, \"Not implemented: removeAccount(\" + account + \")\");\n        return null;\n    }\n\n    @Override\n    public Bundle requestGoogleAccountsAccess(String packageName) throws RemoteException {\n        PackageUtils.assertGooglePackagePermission(context, GooglePackagePermission.ACCOUNT);\n        if (SDK_INT >= 26) {\n            Map<Account, Integer> visibilityForPackage = get(context).getAccountsAndVisibilityForPackage(packageName, AuthConstants.DEFAULT_ACCOUNT_TYPE);\n            for (Account account : get(context).getAccountsByType(AuthConstants.DEFAULT_ACCOUNT_TYPE)) {\n                Integer visibility = visibilityForPackage.get(account);\n                if (visibility != null && visibility != VISIBILITY_VISIBLE) {\n                    get(context).setAccountVisibility(account, packageName, VISIBILITY_VISIBLE);\n                }\n            }\n            Bundle res = new Bundle();\n            res.putString(\"Error\", \"Ok\");\n            return res;\n        } else {\n            Log.w(TAG, \"Not implemented: requestGoogleAccountsAccess(\" + packageName + \")\");\n        }\n        return null;\n    }\n\n    @Override\n    public int hasCapabilities(HasCapabilitiesRequest request) throws RemoteException {\n        PackageUtils.assertGooglePackagePermission(context, GooglePackagePermission.ACCOUNT);\n        List<String> services = Arrays.asList(AccountManager.get(context).getUserData(request.account, \"services\").split(\",\"));\n        for (String capability : request.capabilities) {\n            if (capability.startsWith(\"service_\") && !services.contains(capability.substring(8)) || !services.contains(capability)) {\n                return 6;\n            }\n        }\n        Log.w(TAG, \"Not fully implemented: hasCapabilities(\" + request.account + \", \" + Arrays.toString(request.capabilities) + \")\");\n        return 1;\n    }\n\n    @Override\n    public GetHubTokenInternalResponse getHubToken(GetHubTokenRequest request, Bundle extras) throws RemoteException {\n        Log.w(TAG, \"Not implemented: getHubToken()\");\n        return null;\n    }\n\n    @Override\n    @SuppressLint(\"MissingPermission\") // Workaround bug in Android Linter\n    public Bundle clearToken(String token, Bundle extras) {\n        String packageName = extras.getString(KEY_ANDROID_PACKAGE_NAME);\n        if (packageName == null) packageName = extras.getString(KEY_CLIENT_PACKAGE_NAME);\n        packageName = PackageUtils.getAndCheckCallingPackage(context, packageName, extras.getInt(KEY_CALLER_UID, 0), extras.getInt(KEY_CALLER_PID, 0));\n\n        Log.d(TAG, \"clearToken: token:\" + token + \" extras:\" + extras);\n        AccountManager.get(context).invalidateAuthToken(AuthConstants.DEFAULT_ACCOUNT_TYPE, token);\n\n        Bundle res = new Bundle();\n        res.putString(\"Error\", \"Ok\");\n        res.putBoolean(\"booleanResult\", true);\n        return res;\n    }\n\n    @Override\n    public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {\n        if (super.onTransact(code, data, reply, flags)) return true;\n        Log.d(TAG, \"onTransact [unknown]: \" + code + \", \" + data + \", \" + flags);\n        return false;\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/auth/login/AssistantActivity.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.auth.login;\n\nimport android.annotation.SuppressLint;\nimport android.app.Activity;\nimport android.content.res.Configuration;\nimport android.os.Bundle;\nimport android.util.DisplayMetrics;\nimport android.view.View;\nimport android.widget.Button;\nimport android.widget.RelativeLayout;\nimport android.widget.TextView;\n\nimport androidx.annotation.StringRes;\nimport androidx.appcompat.app.AppCompatActivity;\n\nimport com.google.android.gms.R;\n\npublic abstract class AssistantActivity extends AppCompatActivity {\n    private static final int TITLE_MIN_HEIGHT = 64;\n    private static final double TITLE_WIDTH_FACTOR = (8.0 / 18.0);\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.login_assistant);\n        formatTitle();\n        findViewById(R.id.next_button).setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                onNextButtonClicked();\n            }\n        });\n        findViewById(R.id.back_button).setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                onBackButtonClicked();\n            }\n        });\n    }\n\n    @SuppressLint(\"WrongViewCast\")\n    private void formatTitle() {\n        if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {\n            double widthPixels = (double) (getResources().getDisplayMetrics().widthPixels);\n            findViewById(R.id.title_container).getLayoutParams().height =\n                    (int) (dpToPx(TITLE_MIN_HEIGHT) + (TITLE_WIDTH_FACTOR * widthPixels));\n        } else {\n            findViewById(R.id.title_container).getLayoutParams().height = dpToPx(TITLE_MIN_HEIGHT);\n        }\n    }\n\n    public void setNextButtonText(@StringRes int res) {\n        setNextButtonText(getText(res));\n    }\n\n    public void setNextButtonText(CharSequence text) {\n        if (text == null) {\n            findViewById(R.id.next_button).setVisibility(View.GONE);\n        } else {\n            findViewById(R.id.next_button).setVisibility(View.VISIBLE);\n            ((Button) findViewById(R.id.next_button)).setText(text);\n        }\n    }\n\n    public void setBackButtonText(@StringRes int res) {\n        setBackButtonText(getText(res));\n    }\n\n    public void setBackButtonText(CharSequence text) {\n        if (text == null) {\n            findViewById(R.id.back_button).setVisibility(View.GONE);\n        } else {\n            findViewById(R.id.back_button).setVisibility(View.VISIBLE);\n            ((Button) findViewById(R.id.back_button)).setText(text);\n        }\n    }\n\n    protected void onNextButtonClicked() {\n\n    }\n\n    protected void onBackButtonClicked() {\n\n    }\n\n    @Override\n    public void onConfigurationChanged(Configuration newConfig) {\n        super.onConfigurationChanged(newConfig);\n        formatTitle();\n    }\n\n    @Override\n    protected void onTitleChanged(CharSequence title, int color) {\n        super.onTitleChanged(title, color);\n        ((TextView) findViewById(R.id.title)).setText(title);\n    }\n\n    public int dpToPx(int dp) {\n        DisplayMetrics displayMetrics = getResources().getDisplayMetrics();\n        return Math.round(dp * (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/auth/login/LoginActivity.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.auth.login;\n\nimport android.accounts.Account;\nimport android.accounts.AccountAuthenticatorResponse;\nimport android.accounts.AccountManager;\nimport android.annotation.SuppressLint;\nimport android.annotation.TargetApi;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.graphics.Color;\nimport android.net.ConnectivityManager;\nimport android.net.NetworkInfo;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.text.TextUtils;\nimport android.util.Base64;\nimport android.util.Log;\nimport android.view.KeyEvent;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.view.inputmethod.InputMethodManager;\nimport android.webkit.CookieManager;\nimport android.webkit.JavascriptInterface;\nimport android.webkit.WebSettings;\nimport android.webkit.WebView;\nimport android.widget.RelativeLayout;\nimport android.widget.TextView;\n\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StringRes;\nimport androidx.webkit.WebViewClientCompat;\n\nimport com.google.android.gms.R;\n\nimport org.json.JSONArray;\nimport org.microg.gms.accountaction.AccountNotificationKt;\nimport org.microg.gms.accountsettings.ui.MainActivity;\nimport org.microg.gms.auth.AuthConstants;\nimport org.microg.gms.auth.AuthManager;\nimport org.microg.gms.auth.AuthRequest;\nimport org.microg.gms.auth.AuthResponse;\nimport org.microg.gms.checkin.CheckinManager;\nimport org.microg.gms.checkin.LastCheckinInfo;\nimport org.microg.gms.common.Constants;\nimport org.microg.gms.common.HttpFormClient;\nimport org.microg.gms.common.Utils;\nimport org.microg.gms.people.PeopleManager;\nimport org.microg.gms.profile.Build;\nimport org.microg.gms.profile.ProfileManager;\n\nimport java.io.IOException;\nimport java.security.MessageDigest;\nimport java.util.Locale;\n\nimport static android.accounts.AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE;\nimport static android.accounts.AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;\nimport static android.os.Build.VERSION.SDK_INT;\nimport static android.telephony.TelephonyManager.SIM_STATE_UNKNOWN;\nimport static android.view.KeyEvent.KEYCODE_BACK;\nimport static android.view.View.INVISIBLE;\nimport static android.view.View.VISIBLE;\nimport static android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT;\nimport static org.microg.gms.accountsettings.ui.ExtensionsKt.EXTRA_URL;\nimport static org.microg.gms.auth.AuthPrefs.isAuthVisible;\nimport static org.microg.gms.common.Constants.GMS_PACKAGE_NAME;\nimport static org.microg.gms.common.Constants.GMS_VERSION_CODE;\nimport static org.microg.gms.common.Constants.VENDING_PACKAGE_NAME;\nimport static org.microg.gms.gcm.ExtensionsKt.ACTION_GCM_REGISTER_ACCOUNT;\nimport static org.microg.gms.gcm.ExtensionsKt.KEY_GCM_REGISTER_ACCOUNT_NAME;\n\npublic class LoginActivity extends AssistantActivity {\n    public static final String TMPL_NEW_ACCOUNT = \"new_account\";\n    public static final String EXTRA_TMPL = \"tmpl\";\n    public static final String EXTRA_EMAIL = \"email\";\n    public static final String EXTRA_TOKEN = \"masterToken\";\n    public static final String EXTRA_RE_AUTH_ACCOUNT = \"re_auth_account\";\n    public static final int STATUS_BAR_DISABLE_BACK = 0x00400000;\n\n    private static final String TAG = \"GmsAuthLoginBrowser\";\n    private static final String EMBEDDED_SETUP_URL = \"https://accounts.google.com/EmbeddedSetup\";\n    private static final String EMBEDDED_RE_AUTH_URL = \"https://accounts.google.com/embedded/reauth/v2/android\";\n    private static final String PROGRAMMATIC_AUTH_URL = \"https://accounts.google.com/o/oauth2/programmatic_auth\";\n    private static final String GOOGLE_SUITE_URL = \"https://accounts.google.com/signin/continue\";\n    private static final String GOOGLE_SIGNUP_URL = \"https://accounts.google.com/signup\";\n    private static final String MAGIC_USER_AGENT = \" MinuteMaid\";\n    private static final String COOKIE_OAUTH_TOKEN = \"oauth_token\";\n    private static final String ACTION_UPDATE_ACCOUNT = \"com.google.android.gms.auth.GOOGLE_ACCOUNT_CHANGE\";\n    private static final String PERMISSION_UPDATE_ACCOUNT = \"com.google.android.gms.auth.permission.GOOGLE_ACCOUNT_CHANGE\";\n    private static final int REQUEST_CODE_SIGNUP = 1001;\n\n    private final FidoHandler fidoHandler = new FidoHandler(this);\n    private final DroidGuardHandler dgHandler = new DroidGuardHandler(this);\n\n    private WebView webView;\n    private String accountType;\n    private AccountManager accountManager;\n    private AccountAuthenticatorResponse response;\n    private InputMethodManager inputMethodManager;\n    private ViewGroup authContent;\n    private int state = 0;\n    private boolean isReAuth = false;\n    private Account reAuthAccount;\n\n    @SuppressLint(\"AddJavascriptInterface\")\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        accountType = AuthConstants.DEFAULT_ACCOUNT_TYPE;\n        accountManager = AccountManager.get(LoginActivity.this);\n        inputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);\n        webView = createWebView(this);\n        webView.addJavascriptInterface(new JsBridge(), \"mm\");\n        authContent = (ViewGroup) findViewById(R.id.auth_content);\n        ((ViewGroup) findViewById(R.id.auth_root)).addView(webView);\n        webView.setWebViewClient(new WebViewClientCompat() {\n            @Override\n            public boolean shouldOverrideUrlLoading(WebView view, String url) {\n                Log.d(TAG, \"shouldOverrideUrlLoading: url: \" + url);\n                Uri uri = Uri.parse(url);\n                String uriPath = uri.getPath();\n                if (uriPath != null && uriPath.contains(\"/signup\")) {\n                    String biz = uri.getQueryParameter(\"biz\");\n                    Intent intent = new Intent(LoginActivity.this, MainActivity.class);\n                    intent.setPackage(GMS_PACKAGE_NAME);\n                    intent.putExtra(EXTRA_URL, biz != null ? GOOGLE_SIGNUP_URL + \"?biz=\" + biz : GOOGLE_SIGNUP_URL);\n                    startActivityForResult(intent, REQUEST_CODE_SIGNUP);\n                    return true;\n                }\n                return super.shouldOverrideUrlLoading(view, url);\n            }\n\n            @Override\n            public void onPageFinished(WebView view, String url) {\n                Log.d(TAG, \"pageFinished: \" + view.getUrl());\n                Uri uri = Uri.parse(view.getUrl());\n\n                // Begin login.\n                // Only required if client code does not invoke showView() via JSBridge\n                if (\"identifier\".equals(uri.getFragment()) || uri.getPath().endsWith(\"/identifier\"))\n                    runOnUiThread(() -> webView.setVisibility(VISIBLE));\n\n                // Normal login.\n                if (\"close\".equals(uri.getFragment()))\n                    closeWeb(false);\n\n                // Google Suite login.\n                if (url.startsWith(GOOGLE_SUITE_URL))\n                    closeWeb(false);\n\n                // IDK when this is called.\n                if (url.startsWith(PROGRAMMATIC_AUTH_URL))\n                    closeWeb(true);\n            }\n        });\n        if(getIntent().hasExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE)){\n            Object tempObject = getIntent().getExtras().get(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE);\n            if (tempObject instanceof AccountAuthenticatorResponse) {\n                response = (AccountAuthenticatorResponse) tempObject;\n            }\n        }\n        if (getIntent().hasExtra(EXTRA_RE_AUTH_ACCOUNT)) {\n            reAuthAccount = getIntent().getParcelableExtra(EXTRA_RE_AUTH_ACCOUNT);\n            isReAuth = reAuthAccount != null;\n        }\n        if (getIntent().hasExtra(EXTRA_TOKEN)) {\n            if (getIntent().hasExtra(EXTRA_EMAIL)) {\n                AccountManager accountManager = AccountManager.get(this);\n                Account account = new Account(getIntent().getStringExtra(EXTRA_EMAIL), accountType);\n                accountManager.addAccountExplicitly(account, getIntent().getStringExtra(EXTRA_TOKEN), null);\n                if (isAuthVisible(this) && SDK_INT >= 26) {\n                    accountManager.setAccountVisibility(account, PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE, VISIBILITY_USER_MANAGED_VISIBLE);\n                }\n                retrieveGmsToken(account);\n            } else {\n                retrieveRtToken(getIntent().getStringExtra(EXTRA_TOKEN));\n            }\n        } else if (android.os.Build.VERSION.SDK_INT < 21 || isReAuth) {\n            init();\n        } else {\n            setMessage(R.string.auth_before_connect);\n            setBackButtonText(android.R.string.cancel);\n            setNextButtonText(R.string.auth_sign_in);\n        }\n    }\n\n    @Override\n    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {\n        super.onActivityResult(requestCode, resultCode, data);\n        if (requestCode == REQUEST_CODE_SIGNUP) {\n            webView.reload();\n        }\n    }\n\n    @Override\n    protected void onNextButtonClicked() {\n        super.onNextButtonClicked();\n        state++;\n        if (state == 1) {\n            init();\n        } else if (state == -1) {\n            loginCanceled();\n        }\n    }\n\n    @Override\n    protected void onBackButtonClicked() {\n        super.onBackButtonClicked();\n        state--;\n        if (state == -1) {\n            loginCanceled();\n        }\n    }\n\n    public void loginCanceled() {\n        Log.d(TAG, \"loginCanceled: \");\n        setResult(RESULT_CANCELED);\n        if (response != null) {\n            response.onError(AccountManager.ERROR_CODE_CANCELED, \"Canceled\");\n        }\n        if (SDK_INT >= 21) { finishAndRemoveTask(); } else finish();\n    }\n\n    @Override\n    public void onBackPressed() {\n        super.onBackPressed();\n        loginCanceled();\n    }\n\n    private void init() {\n        setTitle(R.string.just_a_sec);\n        setBackButtonText(null);\n        setNextButtonText(null);\n        View loading = getLayoutInflater().inflate(R.layout.login_assistant_loading, authContent, false);\n        authContent.removeAllViews();\n        authContent.addView(loading);\n        setMessage(R.string.auth_connecting);\n        CookieManager.getInstance().setAcceptCookie(true);\n        if (SDK_INT >= 21) {\n            CookieManager.getInstance().removeAllCookies(value -> start());\n        } else {\n            //noinspection deprecation\n            CookieManager.getInstance().removeAllCookie();\n            start();\n        }\n    }\n\n    private static WebView createWebView(Context context) {\n        WebView webView = new WebView(context);\n        if (SDK_INT < 21) {\n            webView.setVisibility(VISIBLE);\n        } else {\n            webView.setVisibility(INVISIBLE);\n        }\n        webView.setLayoutParams(new RelativeLayout.LayoutParams(\n                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));\n        webView.setBackgroundColor(Color.TRANSPARENT);\n        prepareWebViewSettings(context, webView.getSettings());\n        return webView;\n    }\n\n    @SuppressLint(\"SetJavaScriptEnabled\")\n    private static void prepareWebViewSettings(Context context, WebSettings settings) {\n        ProfileManager.ensureInitialized(context);\n        settings.setUserAgentString(Build.INSTANCE.generateWebViewUserAgentString(settings.getUserAgentString()) + MAGIC_USER_AGENT);\n        settings.setJavaScriptEnabled(true);\n        settings.setSupportMultipleWindows(false);\n        settings.setSaveFormData(false);\n        settings.setAllowFileAccess(false);\n        settings.setDatabaseEnabled(false);\n        settings.setNeedInitialFocus(false);\n        settings.setUseWideViewPort(false);\n        settings.setSupportZoom(false);\n        settings.setJavaScriptCanOpenWindowsAutomatically(false);\n    }\n\n    private void start() {\n        ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);\n        NetworkInfo networkInfo = cm.getActiveNetworkInfo();\n        if (networkInfo != null && networkInfo.isConnected()) {\n            if (LastCheckinInfo.read(this).getAndroidId() == 0) {\n                new Thread(() -> {\n                    Runnable next;\n                    next = checkin(false) ? this::loadLoginPage : () -> showError(R.string.auth_general_error_desc);\n                    LoginActivity.this.runOnUiThread(next);\n                }).start();\n            } else {\n                loadLoginPage();\n            }\n        } else {\n            showError(R.string.no_network_error_desc);\n        }\n    }\n\n    private void showError(int errorRes) {\n        setTitle(R.string.sorry);\n        findViewById(R.id.progress_bar).setVisibility(View.INVISIBLE);\n        setMessage(errorRes);\n    }\n\n    private void setMessage(@StringRes int res) {\n        setMessage(getText(res));\n    }\n\n    private void setMessage(CharSequence text) {\n        ((TextView) findViewById(R.id.description_text)).setText(text);\n    }\n\n    private void loadLoginPage() {\n        String tmpl = getIntent().hasExtra(EXTRA_TMPL) ? getIntent().getStringExtra(EXTRA_TMPL) : TMPL_NEW_ACCOUNT;\n        webView.loadUrl(buildUrl(tmpl, Utils.getLocale(this)));\n    }\n\n    protected void runScript(String js) {\n        runOnUiThread(() -> webView.loadUrl(\"javascript:\" + js));\n    }\n\n    private void closeWeb(boolean programmaticAuth) {\n        setMessage(R.string.auth_finalize);\n        runOnUiThread(() -> webView.setVisibility(INVISIBLE));\n        String cookies = CookieManager.getInstance().getCookie(programmaticAuth ? PROGRAMMATIC_AUTH_URL : EMBEDDED_SETUP_URL);\n        String[] temp = cookies.split(\";\");\n        for (String ar1 : temp) {\n            if (ar1.trim().startsWith(COOKIE_OAUTH_TOKEN + \"=\")) {\n                String[] temp1 = ar1.split(\"=\");\n                retrieveRtToken(temp1[1]);\n                return;\n            }\n        }\n        showError(R.string.auth_general_error_desc);\n    }\n\n    private void retrieveRtToken(String oAuthToken) {\n        new AuthRequest().fromContext(this)\n                .appIsGms()\n                .callerIsGms()\n                .service(\"ac2dm\")\n                .token(oAuthToken).isAccessToken()\n                .addAccount()\n                .getAccountId()\n                .droidguardResults(\"null\" /*TODO*/)\n                .getResponseAsync(new HttpFormClient.Callback<AuthResponse>() {\n                    @Override\n                    public void onResponse(AuthResponse response) {\n                        Account account = new Account(response.email, accountType);\n                        if (isReAuth && reAuthAccount != null && reAuthAccount.name.equals(account.name)) {\n                            accountManager.removeAccount(account, future -> saveAccount(account, response), null);\n                        } else {\n                            saveAccount(account, response);\n                        }\n                    }\n\n                    @Override\n                    public void onException(Exception exception) {\n                        Log.w(TAG, \"onException\", exception);\n                        runOnUiThread(() -> {\n                            showError(R.string.auth_general_error_desc);\n                            setNextButtonText(android.R.string.ok);\n                        });\n                        state = -2;\n                    }\n                });\n    }\n\n    private void saveAccount(Account account, AuthResponse response) {\n        if (accountManager.addAccountExplicitly(account, response.token, null)) {\n            accountManager.setAuthToken(account, \"SID\", response.Sid);\n            accountManager.setAuthToken(account, \"LSID\", response.LSid);\n            accountManager.setUserData(account, \"flags\", \"1\");\n            accountManager.setUserData(account, \"services\", response.services);\n            accountManager.setUserData(account, \"oauthAccessToken\", \"1\");\n            accountManager.setUserData(account, \"firstName\", response.firstName);\n            accountManager.setUserData(account, \"lastName\", response.lastName);\n            if (!TextUtils.isEmpty(response.accountId))\n                accountManager.setUserData(account, \"GoogleUserId\", response.accountId);\n\n            retrieveGmsToken(account);\n            setResult(RESULT_OK);\n        } else {\n            Log.w(TAG, \"Account NOT created!\");\n            runOnUiThread(() -> {\n                showError(R.string.auth_general_error_desc);\n                setNextButtonText(android.R.string.ok);\n            });\n            state = -2;\n        }\n    }\n\n    private void returnSuccessResponse(Account account){\n        if (isReAuth && reAuthAccount != null) {\n            AccountNotificationKt.cancelAccountNotificationChannel(this, reAuthAccount);\n        }\n        if(response != null){\n            Bundle bd = new Bundle();\n            bd.putString(AccountManager.KEY_ACCOUNT_NAME,account.name);\n            bd.putBoolean(\"new_account_created\",false);\n            bd.putString(AccountManager.KEY_ACCOUNT_TYPE,accountType);\n            response.onResult(bd);\n        }\n        Intent intent = new Intent(ACTION_UPDATE_ACCOUNT);\n        intent.setPackage(VENDING_PACKAGE_NAME);\n        intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, account.name);\n        sendBroadcast(intent, PERMISSION_UPDATE_ACCOUNT);\n    }\n    private void retrieveGmsToken(final Account account) {\n        final AuthManager authManager = new AuthManager(this, account.name, GMS_PACKAGE_NAME, \"ac2dm\");\n        authManager.setPermitted(true);\n        new AuthRequest().fromContext(this)\n                .appIsGms()\n                .callerIsGms()\n                .service(authManager.getService())\n                .email(account.name)\n                .token(AccountManager.get(this).getPassword(account))\n                .systemPartition(true)\n                .hasPermission(true)\n                .addAccount()\n                .getAccountId()\n                .droidguardResults(\"null\")\n                .getResponseAsync(new HttpFormClient.Callback<AuthResponse>() {\n                    @Override\n                    public void onResponse(AuthResponse response) {\n                        authManager.storeResponse(response);\n                        String accountId = PeopleManager.loadUserInfo(LoginActivity.this, account);\n                        if (!TextUtils.isEmpty(accountId))\n                            accountManager.setUserData(account, \"GoogleUserId\", accountId);\n                        if (isAuthVisible(LoginActivity.this) && SDK_INT >= 26) {\n                            accountManager.setAccountVisibility(account, PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE, VISIBILITY_USER_MANAGED_VISIBLE);\n                        }\n                        checkin(true);\n                        returnSuccessResponse(account);\n                        notifyGcmGroupUpdate(account.name);\n                        if (SDK_INT >= 21) { finishAndRemoveTask(); } else finish();\n                    }\n\n                    @Override\n                    public void onException(Exception exception) {\n                        Log.w(TAG, \"onException\", exception);\n                        runOnUiThread(() -> {\n                            showError(R.string.auth_general_error_desc);\n                            setNextButtonText(android.R.string.ok);\n                        });\n                        state = -2;\n                    }\n                });\n    }\n\n    private void notifyGcmGroupUpdate(String accountName) {\n        Intent intent = new Intent(ACTION_GCM_REGISTER_ACCOUNT);\n        intent.setPackage(Constants.GMS_PACKAGE_NAME);\n        intent.putExtra(KEY_GCM_REGISTER_ACCOUNT_NAME, accountName);\n        sendBroadcast(intent);\n    }\n\n    private boolean checkin(boolean force) {\n        try {\n            CheckinManager.checkin(LoginActivity.this, force);\n            return true;\n        } catch (IOException e) {\n            Log.w(TAG, \"Checkin failed\", e);\n        }\n        return false;\n    }\n\n    @Override\n    public boolean onKeyDown(int keyCode, KeyEvent event) {\n        if ((keyCode == KEYCODE_BACK) && webView.canGoBack() && (webView.getVisibility() == VISIBLE)) {\n            webView.goBack();\n            return true;\n        }\n        return super.onKeyDown(keyCode, event);\n    }\n\n    private String buildUrl(String tmpl, Locale locale) {\n        String uriString = isReAuth ? EMBEDDED_RE_AUTH_URL : EMBEDDED_SETUP_URL;\n        Uri.Builder builder = Uri.parse(uriString).buildUpon()\n                .appendQueryParameter(\"source\", \"android\")\n                .appendQueryParameter(\"xoauth_display_name\", \"Android Device\")\n                .appendQueryParameter(\"lang\", locale.getLanguage())\n                .appendQueryParameter(\"cc\", locale.getCountry().toLowerCase(Locale.US))\n                .appendQueryParameter(\"langCountry\", locale.toString().toLowerCase(Locale.US))\n                .appendQueryParameter(\"hl\", locale.toString().replace(\"_\", \"-\"))\n                .appendQueryParameter(\"tmpl\", tmpl);\n        if (isReAuth && reAuthAccount != null) {\n            builder.appendQueryParameter(\"Email\", reAuthAccount.name);\n        }\n        return builder.build().toString();\n    }\n\n    private class JsBridge {\n\n        @JavascriptInterface\n        public final void addAccount(String json) {\n            Log.d(TAG, \"JSBridge: addAccount\");\n        }\n\n        @JavascriptInterface\n        public final void attemptLogin(String accountName, String password) {\n            Log.d(TAG, \"JSBridge: attemptLogin\");\n        }\n\n        @JavascriptInterface\n        public void backupSyncOptIn(String accountName) {\n            Log.d(TAG, \"JSBridge: backupSyncOptIn\");\n        }\n\n        @JavascriptInterface\n        public final void cancelFido2SignRequest() {\n            Log.d(TAG, \"JSBridge: cancelFido2SignRequest\");\n            fidoHandler.cancel();\n        }\n\n        @JavascriptInterface\n        public void clearOldLoginAttempts() {\n            Log.d(TAG, \"JSBridge: clearOldLoginAttempts\");\n        }\n\n        @JavascriptInterface\n        public final void closeView() {\n            Log.d(TAG, \"JSBridge: closeView\");\n            closeWeb(false);\n        }\n\n        @JavascriptInterface\n        public void fetchIIDToken(String entity) {\n            Log.d(TAG, \"JSBridge: fetchIIDToken\");\n        }\n\n        @JavascriptInterface\n        public final String fetchVerifiedPhoneNumber() {\n            Log.d(TAG, \"JSBridge: fetchVerifiedPhoneNumber\");\n            return null;\n        }\n\n        @SuppressWarnings(\"MissingPermission\")\n        @JavascriptInterface\n        public final String getAccounts() {\n            Log.d(TAG, \"JSBridge: getAccounts\");\n            Account[] accountsByType = accountManager.getAccountsByType(accountType);\n            JSONArray json = new JSONArray();\n            for (Account account : accountsByType) {\n                json.put(account.name);\n            }\n            return json.toString();\n        }\n\n        @JavascriptInterface\n        public final String getAllowedDomains() {\n            Log.d(TAG, \"JSBridge: getAllowedDomains\");\n            return new JSONArray().toString();\n        }\n\n        @JavascriptInterface\n        public final String getAndroidId() {\n            long androidId = LastCheckinInfo.read(LoginActivity.this).getAndroidId();\n            Log.d(TAG, \"JSBridge: getAndroidId\");\n            if (androidId == 0 || androidId == -1) return null;\n            return Long.toHexString(androidId);\n        }\n\n        @JavascriptInterface\n        public final int getAuthModuleVersionCode() {\n            return GMS_VERSION_CODE;\n        }\n\n        @JavascriptInterface\n        public final int getBuildVersionSdk() {\n            return Build.VERSION.SDK_INT;\n        }\n\n        @JavascriptInterface\n        public int getDeviceContactsCount() {\n            return -1;\n        }\n\n        @JavascriptInterface\n        public final int getDeviceDataVersionInfo() {\n            return 1;\n        }\n\n        @JavascriptInterface\n        public final void getDroidGuardResult(String s) {\n            Log.d(TAG, \"JSBridge: getDroidGuardResult\");\n            try {\n                JSONArray array = new JSONArray(s);\n                StringBuilder sb = new StringBuilder();\n                sb.append(getAndroidId()).append(\":\").append(getBuildVersionSdk()).append(\":\").append(getPlayServicesVersionCode());\n                for (int i = 0; i < array.length(); i++) {\n                    sb.append(\":\").append(array.getString(i));\n                }\n                String dg = Base64.encodeToString(MessageDigest.getInstance(\"SHA1\").digest(sb.toString().getBytes()), 0);\n                dgHandler.start(dg);\n            } catch (Exception e) {\n                // Ignore\n            }\n        }\n\n        @JavascriptInterface\n        public final String getFactoryResetChallenges() {\n            return new JSONArray().toString();\n        }\n\n        @JavascriptInterface\n        public final String getPhoneNumber() {\n            return null;\n        }\n\n        @JavascriptInterface\n        public final int getPlayServicesVersionCode() {\n            return GMS_VERSION_CODE;\n        }\n\n        @JavascriptInterface\n        public final String getSimSerial() {\n            return null;\n        }\n\n        @JavascriptInterface\n        public final int getSimState() {\n            return SIM_STATE_UNKNOWN;\n        }\n\n        @JavascriptInterface\n        public final void goBack() {\n            Log.d(TAG, \"JSBridge: goBack\");\n        }\n\n        @JavascriptInterface\n        public final boolean hasPhoneNumber() {\n            return false;\n        }\n\n        @JavascriptInterface\n        public final boolean hasTelephony() {\n            return false;\n        }\n\n        @JavascriptInterface\n        public final void hideKeyboard() {\n            inputMethodManager.hideSoftInputFromWindow(webView.getWindowToken(), 0);\n        }\n\n        @JavascriptInterface\n        public final boolean isUserOwner() {\n            return true;\n        }\n\n        @JavascriptInterface\n        public final void launchEmergencyDialer() {\n            Log.d(TAG, \"JSBridge: launchEmergencyDialer\");\n        }\n\n        @JavascriptInterface\n        public final void log(String s) {\n            Log.d(TAG, \"JSBridge: log\");\n        }\n\n        @JavascriptInterface\n        public final void notifyOnTermsOfServiceAccepted() {\n            Log.d(TAG, \"JSBridge: notifyOnTermsOfServiceAccepted\");\n        }\n\n        @JavascriptInterface\n        public final void sendFido2SkUiEvent(String event) {\n            Log.d(TAG, \"JSBridge: sendFido2SkUiEvent\");\n            fidoHandler.onEvent(event);\n        }\n\n        @JavascriptInterface\n        public final void setAccountIdentifier(String accountName) {\n            Log.d(TAG, \"JSBridge: setAccountIdentifier\");\n        }\n\n        @JavascriptInterface\n        public void setAllActionsEnabled(boolean z) {\n            Log.d(TAG, \"JSBridge: setAllActionsEnabled\");\n        }\n\n        @JavascriptInterface\n        public final void setBackButtonEnabled(boolean backButtonEnabled) {\n            int visibility = getWindow().getDecorView().getSystemUiVisibility();\n            if (backButtonEnabled)\n                visibility &= -STATUS_BAR_DISABLE_BACK;\n            else\n                visibility |= STATUS_BAR_DISABLE_BACK;\n            getWindow().getDecorView().setSystemUiVisibility(visibility);\n        }\n\n\n        @JavascriptInterface\n        public final void setNewAccountCreated() {\n            Log.d(TAG, \"JSBridge: setNewAccountCreated\");\n        }\n\n        @JavascriptInterface\n        public void setPrimaryActionEnabled(boolean z) {\n            Log.d(TAG, \"JSBridge: setPrimaryActionEnabled\");\n        }\n\n        @JavascriptInterface\n        public void setPrimaryActionLabel(String str, int i) {\n            Log.d(TAG, \"JSBridge: setPrimaryActionLabel: \" + str);\n        }\n\n        @JavascriptInterface\n        public void setSecondaryActionEnabled(boolean z) {\n            Log.d(TAG, \"JSBridge: setSecondaryActionEnabled\");\n        }\n\n        @JavascriptInterface\n        public void setSecondaryActionLabel(String str, int i) {\n            Log.d(TAG, \"JSBridge: setSecondaryActionLabel: \" + str);\n        }\n\n        @JavascriptInterface\n        public final void showKeyboard() {\n            inputMethodManager.showSoftInput(webView, SHOW_IMPLICIT);\n        }\n\n        @JavascriptInterface\n        public final void showView() {\n            runOnUiThread(() -> webView.setVisibility(VISIBLE));\n        }\n\n        @JavascriptInterface\n        public final void skipLogin() {\n            Log.d(TAG, \"JSBridge: skipLogin\");\n            loginCanceled();\n        }\n\n        @JavascriptInterface\n        public final void startAfw() {\n            Log.d(TAG, \"JSBridge: startAfw\");\n        }\n\n        @JavascriptInterface\n        public final void startFido2SignRequest(String request) {\n            Log.d(TAG, \"JSBridge: startFido2SignRequest\");\n            fidoHandler.startSignRequest(request);\n        }\n\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/auth/loginservice/AccountAuthenticator.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.auth.loginservice;\n\nimport android.accounts.AbstractAccountAuthenticator;\nimport android.accounts.Account;\nimport android.accounts.AccountAuthenticatorResponse;\nimport android.accounts.AccountManager;\nimport android.accounts.NetworkErrorException;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.util.Base64;\nimport android.util.Log;\n\nimport com.google.android.gms.common.internal.CertData;\nimport org.microg.gms.auth.*;\nimport org.microg.gms.auth.login.LoginActivity;\nimport org.microg.gms.common.PackageUtils;\nimport org.microg.gms.auth.AuthResponse;\nimport org.microg.gms.utils.PackageManagerUtilsKt;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport static android.accounts.AccountManager.*;\n\npublic class AccountAuthenticator extends AbstractAccountAuthenticator {\n    private static final String TAG = \"GmsAuthenticator\";\n    public static final String KEY_OVERRIDE_PACKAGE = \"overridePackage\";\n    public static final String KEY_OVERRIDE_CERTIFICATE = \"overrideCertificate\";\n    private final Context context;\n    private final String accountType;\n\n    public AccountAuthenticator(Context context) {\n        super(context);\n        this.context = context;\n        this.accountType = AuthConstants.DEFAULT_ACCOUNT_TYPE;\n    }\n\n    @Override\n    public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {\n        Log.d(TAG, \"editProperties: \" + accountType);\n        return null;\n    }\n\n    @Override\n    public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) throws NetworkErrorException {\n        if (accountType.equals(this.accountType)) {\n            final Intent i = new Intent(context, LoginActivity.class);\n            i.putExtras(options);\n            i.putExtra(LoginActivity.EXTRA_TMPL, LoginActivity.TMPL_NEW_ACCOUNT);\n            i.putExtra(KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);\n            final Bundle result = new Bundle();\n            result.putParcelable(KEY_INTENT, i);\n            return result;\n        }\n        return null;\n    }\n\n    @Override\n    public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options) throws NetworkErrorException {\n        Log.d(TAG, \"confirmCredentials: \" + account + \", \" + options);\n        return null;\n    }\n\n    public boolean isPackageOverrideAllowed(Account account, String requestingPackage, String overridePackage, CertData overrideCertificate) {\n        // Always allow for self package\n        if (requestingPackage.equals(context.getPackageName())) return true;\n//        if (requestingPackage.equals(\"org.microg.example.authwithoverride\")) return true;\n        String requestingDigestString = PackageManagerUtilsKt.toHexString(PackageManagerUtilsKt.digest(PackageManagerUtilsKt.getCertificates(context.getPackageManager(), requestingPackage).get(0), \"SHA-256\"), \"\");\n        String overrideCertificateDigestString = PackageManagerUtilsKt.toHexString(PackageManagerUtilsKt.digest(overrideCertificate, \"SHA-256\"), \"\");\n        String overrideUserDataKey = \"override.\" + requestingPackage + \":\" + requestingDigestString + \":\" + overridePackage + \":\" + overrideCertificateDigestString;\n        String hasOverride = AccountManager.get(context).getUserData(account, overrideUserDataKey);\n        return \"1\".equals(hasOverride);\n    }\n\n    @Override\n    public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException {\n        options.keySet();\n        Log.d(TAG, \"getAuthToken: \" + account + \", \" + authTokenType + \", \" + options);\n        String app = options.getString(KEY_ANDROID_PACKAGE_NAME);\n        app = PackageUtils.getAndCheckPackage(context, app, options.getInt(KEY_CALLER_UID), options.getInt(KEY_CALLER_PID));\n        AuthManager authManager;\n        if (app == null) {\n            Bundle result = new Bundle();\n            result.putInt(KEY_ERROR_CODE, ERROR_CODE_BAD_REQUEST);\n            return result;\n        }\n        if (options.containsKey(KEY_OVERRIDE_PACKAGE) || options.containsKey(KEY_OVERRIDE_CERTIFICATE)) {\n            String overridePackage = options.getString(KEY_OVERRIDE_PACKAGE, app);\n            byte[] overrideCertificateBytes = options.getByteArray(KEY_OVERRIDE_CERTIFICATE);\n            CertData overrideCert;\n            if (overrideCertificateBytes != null) {\n                overrideCert = new CertData(overrideCertificateBytes);\n            } else {\n                overrideCert = PackageManagerUtilsKt.getCertificates(context.getPackageManager(), app).get(0);\n            }\n            if (isPackageOverrideAllowed(account, app, overridePackage, overrideCert)) {\n                authManager = new AuthManager(context, account.name, overridePackage, authTokenType);\n                authManager.setPackageSignature(PackageManagerUtilsKt.toHexString(PackageManagerUtilsKt.digest(overrideCert, \"SHA1\"), \"\"));\n            } else {\n                Bundle result = new Bundle();\n                Intent i = new Intent(context, AskPackageOverrideActivity.class);\n                i.putExtra(KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);\n                i.putExtra(KEY_ANDROID_PACKAGE_NAME, app);\n                i.putExtra(KEY_ACCOUNT_TYPE, account.type);\n                i.putExtra(KEY_ACCOUNT_NAME, account.name);\n                i.putExtra(KEY_OVERRIDE_PACKAGE, overridePackage);\n                i.putExtra(KEY_OVERRIDE_CERTIFICATE, overrideCert.getBytes());\n                result.putParcelable(KEY_INTENT, i);\n                return result;\n            }\n        } else {\n            authManager = new AuthManager(context, account.name, app, authTokenType);\n        }\n        try {\n            AuthResponse res = authManager.requestAuthWithBackgroundResolution(true);\n            if (res.auth != null) {\n                Log.d(TAG, \"getAuthToken: \" + res.auth);\n                Bundle result = new Bundle();\n                result.putString(KEY_ACCOUNT_TYPE, account.type);\n                result.putString(KEY_ACCOUNT_NAME, account.name);\n                result.putString(KEY_AUTHTOKEN, res.auth);\n                return result;\n            } else {\n                Bundle result = new Bundle();\n                Intent i = new Intent(context, AskPermissionActivity.class);\n                i.putExtras(options);\n                i.putExtra(KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);\n                i.putExtra(KEY_ANDROID_PACKAGE_NAME, app);\n                i.putExtra(KEY_ACCOUNT_TYPE, account.type);\n                i.putExtra(KEY_ACCOUNT_NAME, account.name);\n                i.putExtra(KEY_AUTHTOKEN, authTokenType);\n                try {\n                    if (res.consentDataBase64 != null)\n                        i.putExtra(AskPermissionActivity.EXTRA_CONSENT_DATA, Base64.decode(res.consentDataBase64, Base64.URL_SAFE));\n                } catch (Exception e) {\n                    Log.w(TAG, \"Can't decode consent data: \", e);\n                }\n                result.putParcelable(KEY_INTENT, i);\n                return result;\n            }\n        } catch (Exception e) {\n            Log.w(TAG, e);\n            return null;\n        }\n    }\n\n    @Override\n    public String getAuthTokenLabel(String authTokenType) {\n        Log.d(TAG, \"getAuthTokenLabel: \" + authTokenType);\n        return null;\n    }\n\n    @Override\n    public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException {\n        Log.d(TAG, \"updateCredentials: \" + account + \", \" + authTokenType + \", \" + options);\n        return null;\n    }\n\n    @Override\n    public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account, String[] features) throws NetworkErrorException {\n        AccountManager accountManager = AccountManager.get(context);\n        String services = accountManager.getUserData(account, \"services\");\n        boolean res = true;\n        if (services != null) {\n            List<String> servicesList = Arrays.asList(services.split(\",\"));\n            for (String feature : features) {\n                if (feature.startsWith(\"service_\") && !servicesList.contains(feature.substring(8))) {\n                    Log.d(TAG, \"Feature \" + feature + \" not supported\");\n                    res = false;\n                } else if (!feature.startsWith(\"service_\") && !servicesList.contains(feature)) {\n                    Log.d(TAG, \"Feature \" + feature + \" not supported\");\n                    res = false;\n                }\n            }\n        } else {\n            res = false;\n        }\n        Bundle result = new Bundle();\n        result.putBoolean(KEY_BOOLEAN_RESULT, res);\n        return result;\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/auth/loginservice/GoogleLoginService.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.auth.loginservice;\n\nimport android.app.Service;\nimport android.content.Intent;\nimport android.os.IBinder;\n\nimport static android.accounts.AccountManager.ACTION_AUTHENTICATOR_INTENT;\n\npublic class GoogleLoginService extends Service {\n    private AccountAuthenticator authenticator;\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n        authenticator = new AccountAuthenticator(this);\n    }\n\n    @Override\n    public IBinder onBind(Intent intent) {\n        if (intent.getAction().equals(ACTION_AUTHENTICATOR_INTENT)) {\n            return authenticator.getIBinder();\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/car/CarService.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.car;\n\nimport com.google.android.gms.common.internal.GetServiceRequest;\nimport com.google.android.gms.common.internal.IGmsCallbacks;\n\nimport org.microg.gms.BaseService;\nimport org.microg.gms.common.GmsService;\n\npublic class CarService extends BaseService {\n    public CarService() {\n        super(\"GmsCarSvc\", GmsService.CAR);\n    }\n\n    @Override\n    public void handleServiceRequest(IGmsCallbacks callback, GetServiceRequest request, GmsService service) {\n        // TODO\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/checkin/CheckinClient.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.checkin;\n\nimport android.content.Context;\nimport android.util.Log;\n\nimport org.microg.gms.common.DeviceConfigProtoKt;\nimport org.microg.gms.common.DeviceConfiguration;\nimport org.microg.gms.common.DeviceIdentifier;\nimport org.microg.gms.common.PhoneInfo;\nimport org.microg.gms.common.Utils;\nimport org.microg.gms.profile.Build;\nimport org.microg.gms.profile.ProfileManager;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.net.HttpURLConnection;\nimport java.net.URL;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Random;\nimport java.util.TimeZone;\nimport java.util.zip.GZIPInputStream;\nimport java.util.zip.GZIPOutputStream;\n\npublic class CheckinClient {\n    private static final String TAG = \"GmsCheckinClient\";\n    private static final Object TODO = null; // TODO\n    private static final List<String> TODO_LIST_STRING = new ArrayList<>(); // TODO\n    private static final List<CheckinRequest.Checkin.Statistic> TODO_LIST_CHECKIN = new ArrayList<>(); // TODO\n    private static final String SERVICE_URL = \"https://android.clients.google.com/checkin\";\n\n    public static CheckinResponse request(CheckinRequest request) throws IOException {\n        HttpURLConnection connection = (HttpURLConnection) new URL(SERVICE_URL).openConnection();\n        connection.setRequestMethod(\"POST\");\n        connection.setDoInput(true);\n        connection.setDoOutput(true);\n        connection.setRequestProperty(\"Content-type\", \"application/x-protobuffer\");\n        connection.setRequestProperty(\"Content-Encoding\", \"gzip\");\n        connection.setRequestProperty(\"Accept-Encoding\", \"gzip\");\n        connection.setRequestProperty(\"User-Agent\", \"Android-Checkin/2.0 (vbox86p JLS36G); gzip\");\n\n        Log.d(TAG, \"-- Request --\\n\" + request);\n        OutputStream os = new GZIPOutputStream(connection.getOutputStream());\n        os.write(request.encode());\n        os.close();\n\n        if (connection.getResponseCode() != 200) {\n            try {\n                throw new IOException(new String(Utils.readStreamToEnd(new GZIPInputStream(connection.getErrorStream()))));\n            } catch (Exception e) {\n                throw new IOException(connection.getResponseMessage(), e);\n            }\n        }\n\n        InputStream is = connection.getInputStream();\n        CheckinResponse response = CheckinResponse.ADAPTER.decode(new GZIPInputStream(is));\n        is.close();\n        return response;\n    }\n\n    public static CheckinRequest makeRequest(Context context, DeviceConfiguration deviceConfiguration,\n                                             DeviceIdentifier deviceIdent, PhoneInfo phoneInfo,\n                                             LastCheckinInfo checkinInfo, Locale locale,\n                                             List<Account> accounts) {\n        ProfileManager.ensureInitialized(context);\n        CheckinRequest.Builder builder = new CheckinRequest.Builder()\n                .accountCookie(new ArrayList<>())\n                .androidId(checkinInfo.getAndroidId())\n                .checkin(new CheckinRequest.Checkin.Builder()\n                        .build(new CheckinRequest.Checkin.Build.Builder()\n                                .bootloader(Build.BOOTLOADER)\n                                .brand(Build.BRAND)\n                                .clientId(\"android-google\")\n                                .device(Build.DEVICE)\n                                .fingerprint(Build.FINGERPRINT)\n                                .hardware(Build.HARDWARE)\n                                .manufacturer(Build.MANUFACTURER)\n                                .model(Build.MODEL)\n                                .otaInstalled(false) // TODO?\n                                //.packageVersionCode(Constants.MAX_REFERENCE_VERSION)\n                                .product(Build.PRODUCT)\n                                .radio(Build.RADIO)\n                                .sdkVersion(Build.VERSION.SDK_INT)\n                                .time(Build.TIME / 1000)\n                                .build())\n                        .cellOperator(phoneInfo.cellOperator)\n                        .event(Collections.singletonList(new CheckinRequest.Checkin.Event.Builder()\n                                .tag(checkinInfo.getAndroidId() == 0 ? \"event_log_start\" : \"system_update\")\n                                .value_(checkinInfo.getAndroidId() == 0 ? null : \"1536,0,-1,NULL\")\n                                .timeMs(new Date().getTime())\n                                .build()))\n                        .lastCheckinMs(checkinInfo.getLastCheckin())\n                        .requestedGroup(TODO_LIST_STRING)\n                        .roaming(phoneInfo.roaming)\n                        .simOperator(phoneInfo.simOperator)\n                        .stat(TODO_LIST_CHECKIN)\n                        .userNumber(0)\n                        .build())\n                .deviceConfiguration(DeviceConfigProtoKt.asProto(deviceConfiguration))\n                .digest(checkinInfo.getDigest())\n                .esn(deviceIdent.esn)\n                .fragment(0)\n                .locale(locale.toString())\n                .loggingId(new Random().nextLong()) // TODO: static\n                .meid(deviceIdent.meid)\n                .otaCert(Collections.singletonList(\"71Q6Rn2DDZl1zPDVaaeEHItd\"))\n                .serial(Build.SERIAL != null && !Build.SERIAL.isEmpty() ? Build.SERIAL : null)\n                .timeZone(TimeZone.getDefault().getID())\n                .userName((String) TODO)\n                .userSerialNumber((Integer) TODO)\n                .version(3);\n        for (Account account : accounts) {\n            builder.accountCookie.add(\"[\" + account.name + \"]\");\n            builder.accountCookie.add(account.authToken);\n        }\n        if (builder.accountCookie.isEmpty()) builder.accountCookie.add(\"\");\n        if (deviceIdent.wifiMac != null) {\n            builder.macAddress(Arrays.asList(deviceIdent.wifiMac))\n                    .macAddressType(Arrays.asList(\"wifi\"));\n        }\n        if (checkinInfo.getSecurityToken() != 0) {\n            builder.securityToken(checkinInfo.getSecurityToken())\n                    .fragment(1);\n        }\n        return builder.build();\n    }\n\n    public static class Account {\n        public final String name;\n        public final String authToken;\n\n        public Account(String accountName, String authToken) {\n            this.name = accountName;\n            this.authToken = authToken;\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/checkin/CheckinManager.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.checkin;\n\nimport android.accounts.Account;\nimport android.accounts.AccountManager;\nimport android.content.ContentResolver;\nimport android.content.Context;\n\nimport org.microg.gms.auth.AuthConstants;\nimport org.microg.gms.auth.AuthRequest;\nimport org.microg.gms.common.Constants;\nimport org.microg.gms.common.DeviceConfiguration;\nimport org.microg.gms.common.Utils;\nimport org.microg.gms.gservices.GServices;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class CheckinManager {\n    private static final long MIN_CHECKIN_INTERVAL = 3 * 60 * 60 * 1000; // 3 hours\n\n    @SuppressWarnings(\"MissingPermission\")\n    public static synchronized LastCheckinInfo checkin(Context context, boolean force) throws IOException {\n        LastCheckinInfo info = LastCheckinInfo.read(context);\n        if (!force && info.getLastCheckin() > System.currentTimeMillis() - MIN_CHECKIN_INTERVAL)\n            return null;\n        if (!CheckinPreferences.isEnabled(context))\n            return null;\n        List<CheckinClient.Account> accounts = new ArrayList<CheckinClient.Account>();\n        AccountManager accountManager = AccountManager.get(context);\n        String accountType = AuthConstants.DEFAULT_ACCOUNT_TYPE;\n        for (Account account : accountManager.getAccountsByType(accountType)) {\n            String token = new AuthRequest()\n                    .email(account.name).token(accountManager.getPassword(account))\n                    .hasPermission(true).service(\"ac2dm\")\n                    .app(\"com.google.android.gsf\", Constants.GMS_PACKAGE_SIGNATURE_SHA1)\n                    .getResponse().LSid;\n            if (token != null) {\n                accounts.add(new CheckinClient.Account(account.name, token));\n            }\n        }\n        CheckinRequest request = CheckinClient.makeRequest(context,\n                new DeviceConfiguration(context), Utils.getDeviceIdentifier(context),\n                Utils.getPhoneInfo(context), info, Utils.getLocale(context), accounts);\n        return handleResponse(context, CheckinClient.request(request));\n    }\n\n    private static LastCheckinInfo handleResponse(Context context, CheckinResponse response) {\n        LastCheckinInfo info = new LastCheckinInfo(response);\n        info.write(context);\n\n        ContentResolver resolver = context.getContentResolver();\n        for (CheckinResponse.GservicesSetting setting : response.setting) {\n            GServices.setString(resolver, setting.name.utf8(), setting.value_.utf8());\n        }\n\n        return info;\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/checkin/CheckinService.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.checkin;\n\nimport android.accounts.Account;\nimport android.accounts.AccountManager;\nimport android.app.Activity;\nimport android.app.AlarmManager;\nimport android.app.IntentService;\nimport android.app.PendingIntent;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.os.IBinder;\nimport android.os.RemoteException;\nimport android.os.ResultReceiver;\nimport android.util.Log;\n\nimport androidx.core.app.PendingIntentCompat;\nimport androidx.legacy.content.WakefulBroadcastReceiver;\n\nimport com.google.android.gms.checkin.internal.ICheckinService;\n\nimport org.microg.gms.auth.AuthConstants;\nimport org.microg.gms.common.ForegroundServiceInfo;\nimport org.microg.gms.common.ForegroundServiceContext;\nimport org.microg.gms.gcm.McsService;\nimport org.microg.gms.people.PeopleManager;\n\n@ForegroundServiceInfo(value = \"Google device registration\", resName = \"service_name_checkin\", resPackage = \"com.google.android.gms\")\npublic class CheckinService extends IntentService {\n    private static final String TAG = \"GmsCheckinSvc\";\n    public static final long MAX_VALID_CHECKIN_AGE = 24 * 60 * 60 * 1000; // 12 hours\n    public static final long REGULAR_CHECKIN_INTERVAL = 12 * 60 * 60 * 1000; // 12 hours\n    public static final long BACKUP_CHECKIN_DELAY = 3 * 60 * 60 * 1000; // 3 hours\n    public static final String BIND_ACTION = \"com.google.android.gms.checkin.BIND_TO_SERVICE\";\n    public static final String EXTRA_FORCE_CHECKIN = \"force\";\n    @Deprecated\n    public static final String EXTRA_CALLBACK_INTENT = \"callback\";\n    public static final String EXTRA_RESULT_RECEIVER = \"receiver\";\n    public static final String EXTRA_NEW_CHECKIN_TIME = \"checkin_time\";\n\n    private ICheckinService iface = new ICheckinService.Stub() {\n        @Override\n        public String getDeviceDataVersionInfo() throws RemoteException {\n            return LastCheckinInfo.read(CheckinService.this).getDeviceDataVersionInfo();\n        }\n\n        @Override\n        public long getLastCheckinSuccessTime() throws RemoteException {\n            return LastCheckinInfo.read(CheckinService.this).getLastCheckin();\n        }\n\n        @Override\n        public String getLastSimOperator() throws RemoteException {\n            return null;\n        }\n    };\n\n    public CheckinService() {\n        super(TAG);\n    }\n\n    @SuppressWarnings(\"MissingPermission\")\n    @Override\n    protected void onHandleIntent(Intent intent) {\n        try {\n            ForegroundServiceContext.completeForegroundService(this, intent, TAG);\n            if (CheckinPreferences.isEnabled(this)) {\n                LastCheckinInfo info = CheckinManager.checkin(this, intent.getBooleanExtra(EXTRA_FORCE_CHECKIN, false));\n                if (info != null) {\n                    Log.d(TAG, \"Checked in as \" + Long.toHexString(info.getAndroidId()));\n                    String accountType = AuthConstants.DEFAULT_ACCOUNT_TYPE;\n                    for (Account account : AccountManager.get(this).getAccountsByType(accountType)) {\n                        PeopleManager.loadUserInfo(this, account);\n                    }\n                    McsService.scheduleReconnect(this);\n                    if (intent.hasExtra(EXTRA_CALLBACK_INTENT)) {\n                        startService((Intent) intent.getParcelableExtra(EXTRA_CALLBACK_INTENT));\n                    }\n                    if (intent.hasExtra(EXTRA_RESULT_RECEIVER)) {\n                        ResultReceiver receiver = intent.getParcelableExtra(EXTRA_RESULT_RECEIVER);\n                        if (receiver != null) {\n                            Bundle bundle = new Bundle();\n                            bundle.putLong(EXTRA_NEW_CHECKIN_TIME, info.getLastCheckin());\n                            receiver.send(Activity.RESULT_OK, bundle);\n                        }\n                    }\n                }\n            }\n        } catch (Exception e) {\n            Log.w(TAG, e);\n        } finally {\n            if (intent != null) {\n                WakefulBroadcastReceiver.completeWakefulIntent(intent);\n            }\n            schedule(this);\n            stopSelf();\n        }\n    }\n\n    @Override\n    public IBinder onBind(Intent intent) {\n        if (BIND_ACTION.equals(intent.getAction())) {\n            return iface.asBinder();\n        } else {\n            return super.onBind(intent);\n        }\n    }\n\n    static void schedule(Context context) {\n        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);\n        PendingIntent pendingIntent = PendingIntentCompat.getService(context, TriggerReceiver.class.getName().hashCode(), new Intent(context, TriggerReceiver.class), PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT, false);\n        alarmManager.set(AlarmManager.RTC, Math.max(LastCheckinInfo.read(context).getLastCheckin() + REGULAR_CHECKIN_INTERVAL, System.currentTimeMillis() + BACKUP_CHECKIN_DELAY), pendingIntent);\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/checkin/TriggerReceiver.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.checkin;\n\nimport android.app.PendingIntent;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.net.ConnectivityManager;\nimport android.net.NetworkInfo;\nimport android.net.NetworkRequest;\nimport android.util.Log;\n\nimport androidx.core.app.PendingIntentCompat;\nimport androidx.legacy.content.WakefulBroadcastReceiver;\n\nimport org.microg.gms.common.ForegroundServiceContext;\n\nimport static android.app.PendingIntent.FLAG_UPDATE_CURRENT;\nimport static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;\nimport static android.os.Build.VERSION.SDK_INT;\nimport static org.microg.gms.checkin.CheckinService.EXTRA_FORCE_CHECKIN;\nimport static org.microg.gms.checkin.CheckinService.REGULAR_CHECKIN_INTERVAL;\n\npublic class TriggerReceiver extends WakefulBroadcastReceiver {\n    private static final String TAG = \"GmsCheckinTrigger\";\n    private static boolean registered = false;\n\n    @Override\n    public void onReceive(Context context, Intent intent) {\n        try {\n            boolean force = \"android.provider.Telephony.SECRET_CODE\".equals(intent.getAction());\n\n            if (CheckinPreferences.isEnabled(context) || force) {\n                if (LastCheckinInfo.read(context).getLastCheckin() > System.currentTimeMillis() - REGULAR_CHECKIN_INTERVAL && !force) {\n                    CheckinService.schedule(context);\n                    return;\n                }\n\n                ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);\n                NetworkInfo networkInfo = cm.getActiveNetworkInfo();\n                if (networkInfo != null && networkInfo.isConnected() || force) {\n                    Intent subIntent = new Intent(context, CheckinService.class);\n                    subIntent.putExtra(EXTRA_FORCE_CHECKIN, force);\n                    startWakefulService(new ForegroundServiceContext(context), subIntent);\n                } else if (SDK_INT >= 23) {\n                    // no network, register a network callback to retry when we have internet\n                    NetworkRequest networkRequest = new NetworkRequest.Builder()\n                            .addCapability(NET_CAPABILITY_INTERNET)\n                            .build();\n                    Intent i = new Intent(context, TriggerReceiver.class);\n                    PendingIntent pendingIntent = PendingIntentCompat.getBroadcast(context, 0, i, FLAG_UPDATE_CURRENT, true);\n                    cm.registerNetworkCallback(networkRequest, pendingIntent);\n                }\n            } else {\n                Log.d(TAG, \"Ignoring \" + intent + \": checkin is disabled\");\n            }\n        } catch (Exception e) {\n            Log.w(TAG, e);\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/drive/api/DriveApiService.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.drive.api;\n\nimport android.os.RemoteException;\n\nimport com.google.android.gms.common.internal.GetServiceRequest;\nimport com.google.android.gms.common.internal.IGmsCallbacks;\n\nimport org.microg.gms.BaseService;\nimport org.microg.gms.common.GmsService;\n\npublic class DriveApiService extends BaseService {\n    private DriveServiceImpl impl = new DriveServiceImpl();\n\n    public DriveApiService() {\n        super(\"GmsDriveApiSvc\", GmsService.DRIVE);\n    }\n\n    @Override\n    public void handleServiceRequest(IGmsCallbacks callback, GetServiceRequest request, GmsService service) throws RemoteException {\n        callback.onPostInitComplete(0, impl.asBinder(), null);\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/drive/api/DriveServiceImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.drive.api;\n\nimport android.content.IntentSender;\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport com.google.android.gms.drive.internal.AddEventListenerRequest;\nimport com.google.android.gms.drive.internal.AddPermissionRequest;\nimport com.google.android.gms.drive.internal.AuthorizeAccessRequest;\nimport com.google.android.gms.drive.internal.CancelPendingActionsRequest;\nimport com.google.android.gms.drive.internal.ChangeResourceParentsRequest;\nimport com.google.android.gms.drive.internal.CheckResourceIdsExistRequest;\nimport com.google.android.gms.drive.internal.CloseContentsAndUpdateMetadataRequest;\nimport com.google.android.gms.drive.internal.CloseContentsRequest;\nimport com.google.android.gms.drive.internal.ControlProgressRequest;\nimport com.google.android.gms.drive.internal.CreateContentsRequest;\nimport com.google.android.gms.drive.internal.CreateFileIntentSenderRequest;\nimport com.google.android.gms.drive.internal.CreateFileRequest;\nimport com.google.android.gms.drive.internal.CreateFolderRequest;\nimport com.google.android.gms.drive.internal.DeleteResourceRequest;\nimport com.google.android.gms.drive.internal.DisconnectRequest;\nimport com.google.android.gms.drive.internal.DriveServiceResponse;\nimport com.google.android.gms.drive.internal.FetchThumbnailRequest;\nimport com.google.android.gms.drive.internal.GetChangesRequest;\nimport com.google.android.gms.drive.internal.GetDriveIdFromUniqueIdRequest;\nimport com.google.android.gms.drive.internal.GetMetadataRequest;\nimport com.google.android.gms.drive.internal.GetPermissionsRequest;\nimport com.google.android.gms.drive.internal.IDriveService;\nimport com.google.android.gms.drive.internal.IDriveServiceCallbacks;\nimport com.google.android.gms.drive.internal.IEventCallback;\nimport com.google.android.gms.drive.internal.ListParentsRequest;\nimport com.google.android.gms.drive.internal.LoadRealtimeRequest;\nimport com.google.android.gms.drive.internal.OpenContentsRequest;\nimport com.google.android.gms.drive.internal.OpenFileIntentSenderRequest;\nimport com.google.android.gms.drive.internal.RealtimeDocumentSyncRequest;\nimport com.google.android.gms.drive.internal.RemoveEventListenerRequest;\nimport com.google.android.gms.drive.internal.RemovePermissionRequest;\nimport com.google.android.gms.drive.internal.SetDrivePreferencesRequest;\nimport com.google.android.gms.drive.internal.SetFileUploadPreferencesRequest;\nimport com.google.android.gms.drive.internal.SetResourceParentsRequest;\nimport com.google.android.gms.drive.internal.StreamContentsRequest;\nimport com.google.android.gms.drive.internal.TrashResourceRequest;\nimport com.google.android.gms.drive.internal.UnsubscribeResourceRequest;\nimport com.google.android.gms.drive.internal.UntrashResourceRequest;\nimport com.google.android.gms.drive.internal.UpdateMetadataRequest;\nimport com.google.android.gms.drive.internal.UpdatePermissionRequest;\n\npublic class DriveServiceImpl extends IDriveService.Stub {\n    private static final String TAG = \"GmsDriveSvcImpl\";\n\n    @Override\n    public void getMetadata(GetMetadataRequest request, IDriveServiceCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: getMetadata\");\n\n    }\n\n    @Override\n    public void updateMetadata(UpdateMetadataRequest request, IDriveServiceCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: updateMetadata\");\n\n    }\n\n    @Override\n    public void createContents(CreateContentsRequest request, IDriveServiceCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: createContents\");\n\n    }\n\n    @Override\n    public void createFile(CreateFileRequest request, IDriveServiceCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: createFile\");\n\n    }\n\n    @Override\n    public void createFolder(CreateFolderRequest request, IDriveServiceCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: createFolder\");\n\n    }\n\n    @Override\n    public DriveServiceResponse openContents(OpenContentsRequest request, IDriveServiceCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: openContents\");\n        return null;\n    }\n\n    @Override\n    public void closeContents(CloseContentsRequest request, IDriveServiceCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: closeContents\");\n\n    }\n\n    @Override\n    public void requestSync(IDriveServiceCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: requestSync\");\n\n    }\n\n    @Override\n    public IntentSender openFileIntentSender(OpenFileIntentSenderRequest request) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: openFileIntentSender\");\n        return null;\n    }\n\n    @Override\n    public IntentSender createFileIntentSender(CreateFileIntentSenderRequest request) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: createFileIntentSender\");\n        return null;\n    }\n\n    @Override\n    public void authorizeAccess(AuthorizeAccessRequest request, IDriveServiceCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: authorizeAccess\");\n\n    }\n\n    @Override\n    public void listParents(ListParentsRequest request, IDriveServiceCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: listParents\");\n\n    }\n\n    @Override\n    public void addEventListener(AddEventListenerRequest request, IEventCallback callback, String unused, IDriveServiceCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: addEventListener\");\n\n    }\n\n    @Override\n    public void removeEventListener(RemoveEventListenerRequest request, IEventCallback callback, String unused, IDriveServiceCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: removeEventListener\");\n\n    }\n\n    @Override\n    public void disconnect(DisconnectRequest request) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: disconnect\");\n\n    }\n\n    @Override\n    public void trashResource(TrashResourceRequest request, IDriveServiceCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: trashResource\");\n\n    }\n\n    @Override\n    public void closeContentsAndUpdateMetadata(CloseContentsAndUpdateMetadataRequest request, IDriveServiceCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: closeContentsAndUpdateMetadata\");\n\n    }\n\n    @Override\n    public void deleteResource(DeleteResourceRequest request, IDriveServiceCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: deleteResource\");\n\n    }\n\n    @Override\n    public void loadRealtime(LoadRealtimeRequest request, IDriveServiceCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: loadRealtime\");\n\n    }\n\n    @Override\n    public void setResourceParents(SetResourceParentsRequest request, IDriveServiceCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: setResourceParents\");\n\n    }\n\n    @Override\n    public void getDriveIdFromUniqueId(GetDriveIdFromUniqueIdRequest request, IDriveServiceCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: getDriveIdFromUniqueId\");\n\n    }\n\n    @Override\n    public void checkResourceIdsExist(CheckResourceIdsExistRequest request, IDriveServiceCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: checkResourceIdsExist\");\n\n    }\n\n    @Override\n    public void completePendingAction(IDriveServiceCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: completePendingAction\");\n\n    }\n\n    @Override\n    public void getDrivePreferences(IDriveServiceCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: getDrivePreferences\");\n\n    }\n\n    @Override\n    public void setDrivePreferences(SetDrivePreferencesRequest request, IDriveServiceCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: setDrivePreferences\");\n\n    }\n\n    @Override\n    public void realtimeDocumentSync(RealtimeDocumentSyncRequest request, IDriveServiceCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: realtimeDocumentSync\");\n\n    }\n\n    @Override\n    public void getDeviceUsagePreferences(IDriveServiceCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: getDeviceUsagePreferences\");\n\n    }\n\n    @Override\n    public void setFileUploadPreferences(SetFileUploadPreferencesRequest request, IDriveServiceCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: setFileUploadPreferences\");\n\n    }\n\n    @Override\n    public void cancelPendingActions(CancelPendingActionsRequest request, IDriveServiceCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: cancelPendingActions\");\n\n    }\n\n    @Override\n    public void untrashResource(UntrashResourceRequest request, IDriveServiceCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: untrashResource\");\n\n    }\n\n    @Override\n    public void isAutoBackupEnabled(IDriveServiceCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: isAutoBackupEnabled\");\n\n    }\n\n    @Override\n    public void fetchThumbnail(FetchThumbnailRequest request, IDriveServiceCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: fetchThumbnail\");\n\n    }\n\n    @Override\n    public void getChanges(GetChangesRequest request, IDriveServiceCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: getChanges\");\n\n    }\n\n    @Override\n    public void unsubscribeResource(UnsubscribeResourceRequest request, IDriveServiceCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: unsubscribeResource\");\n\n    }\n\n    @Override\n    public void getPermissions(GetPermissionsRequest request, IDriveServiceCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: getPermissions\");\n\n    }\n\n    @Override\n    public void addPermission(AddPermissionRequest request, IDriveServiceCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: addPermission\");\n\n    }\n\n    @Override\n    public void updatePermission(UpdatePermissionRequest request, IDriveServiceCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: updatePermission\");\n\n    }\n\n    @Override\n    public void removePermission(RemovePermissionRequest request, IDriveServiceCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: removePermission\");\n\n    }\n\n    @Override\n    public void removeQueryResultListener(IEventCallback callback, IDriveServiceCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: removeQueryResultListener\");\n\n    }\n\n    @Override\n    public void controlProgress(ControlProgressRequest request, IDriveServiceCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: controlProgress\");\n\n    }\n\n    @Override\n    public void changeResourceParents(ChangeResourceParentsRequest request, IDriveServiceCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: changeResourceParents\");\n\n    }\n\n    @Override\n    public DriveServiceResponse streamContents(StreamContentsRequest request, IDriveServiceCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: streamContents\");\n        return null;\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/feeds/SubscribedFeedsProvider.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.feeds;\n\nimport android.content.ContentProvider;\nimport android.content.ContentValues;\nimport android.database.Cursor;\nimport android.database.MatrixCursor;\nimport android.net.Uri;\n\npublic class SubscribedFeedsProvider extends ContentProvider{\n\n    @Override\n    public boolean onCreate() {\n        return false;\n    }\n\n    @Override\n    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {\n        return new MatrixCursor(new String[0]);\n    }\n\n    @Override\n    public String getType(Uri uri) {\n        return null;\n    }\n\n    @Override\n    public Uri insert(Uri uri, ContentValues values) {\n        return null;\n    }\n\n    @Override\n    public int delete(Uri uri, String selection, String[] selectionArgs) {\n        return 0;\n    }\n\n    @Override\n    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {\n        return 0;\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/games/GamesStubService.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.games;\n\nimport android.app.PendingIntent;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.os.RemoteException;\n\nimport androidx.core.app.PendingIntentCompat;\nimport com.google.android.gms.common.api.CommonStatusCodes;\nimport com.google.android.gms.common.internal.GetServiceRequest;\nimport com.google.android.gms.common.internal.IGmsCallbacks;\n\nimport org.microg.gms.BaseService;\nimport org.microg.gms.common.GmsService;\n\nimport static android.app.PendingIntent.FLAG_UPDATE_CURRENT;\nimport static org.microg.gms.common.Constants.GMS_PACKAGE_NAME;\nimport static org.microg.gms.games.UpgradeActivity.ACTION_PLAY_GAMES_UPGRADE;\nimport static org.microg.gms.games.UpgradeActivity.EXTRA_GAME_PACACKE_NAME;\n\npublic class GamesStubService extends BaseService {\n\n    public static final String PARAM_GAME_PACKAGE_NAME = \"com.google.android.gms.games.key.gamePackageName\";\n\n    public GamesStubService() {\n        super(\"GmsGamesSvc\", GmsService.GAMES);\n    }\n\n    @Override\n    public void handleServiceRequest(IGmsCallbacks callback, GetServiceRequest request, GmsService service) throws RemoteException {\n        String packageName = null;\n        if (request.extras != null) {\n            packageName = request.extras.getString(PARAM_GAME_PACKAGE_NAME);\n        }\n        if (packageName == null) packageName = GMS_PACKAGE_NAME;\n        Intent intent = new Intent(ACTION_PLAY_GAMES_UPGRADE);\n        intent.setPackage(GMS_PACKAGE_NAME);\n        intent.putExtra(EXTRA_GAME_PACACKE_NAME, packageName);\n        Bundle bundle = new Bundle();\n        bundle.putParcelable(\"pendingIntent\", PendingIntentCompat.getActivity(this, packageName.hashCode(), intent, FLAG_UPDATE_CURRENT, false));\n        callback.onPostInitComplete(CommonStatusCodes.RESOLUTION_REQUIRED, null, bundle);\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/games/UpgradeActivity.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.games;\n\nimport android.app.Activity;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageManager;\nimport android.graphics.drawable.Drawable;\nimport android.os.Bundle;\nimport android.util.Log;\nimport android.view.View;\nimport android.view.WindowManager;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport com.google.android.gms.R;\n\npublic class UpgradeActivity extends Activity {\n    public static final String ACTION_PLAY_GAMES_UPGRADE = \"com.google.android.gms.games.PLAY_GAMES_UPGRADE\";\n    public static final String EXTRA_GAME_PACACKE_NAME = \"com.google.android.gms.games.GAME_PACKAGE_NAME\";\n\n    private static final String TAG = \"GmsUpgActivity\";\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.games_info);\n\n        WindowManager.LayoutParams lp = new WindowManager.LayoutParams();\n        lp.copyFrom(getWindow().getAttributes());\n        lp.width = WindowManager.LayoutParams.MATCH_PARENT;\n        lp.height = WindowManager.LayoutParams.WRAP_CONTENT;\n        getWindow().setAttributes(lp);\n\n        String packageName = getIntent().getStringExtra(EXTRA_GAME_PACACKE_NAME);\n\n        // receive package info\n        PackageManager packageManager = getPackageManager();\n        ApplicationInfo applicationInfo;\n        try {\n            applicationInfo = packageManager.getApplicationInfo(packageName, 0);\n        } catch (PackageManager.NameNotFoundException e) {\n            Log.w(TAG, e);\n            finish();\n            return;\n        }\n        CharSequence appLabel = packageManager.getApplicationLabel(applicationInfo);\n        Drawable appIcon = packageManager.getApplicationIcon(applicationInfo);\n\n        ((ImageView) findViewById(R.id.app_icon)).setImageDrawable(appIcon);\n        ((TextView) findViewById(R.id.title)).setText(getString(R.string.games_info_title, appLabel));\n        findViewById(android.R.id.button1).setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                finish();\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/gcm/GcmDatabase.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2016, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.gcm;\n\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.database.sqlite.SQLiteDatabase;\nimport android.database.sqlite.SQLiteOpenHelper;\nimport android.text.TextUtils;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport static android.os.Build.VERSION.SDK_INT;\n\npublic class GcmDatabase extends SQLiteOpenHelper {\n    private static final String TAG = GcmDatabase.class.getSimpleName();\n    public static final String DB_NAME = \"gcmstatus\";\n    private static int DB_VERSION = 1;\n    private static final String CREATE_TABLE_APPS = \"CREATE TABLE apps (\" +\n            \"package_name TEXT,\" +\n            \"last_error TEXT DEFAULT '',\" +\n            \"last_message_timestamp INTEGER,\" +\n            \"total_message_count INTEGER,\" +\n            \"total_message_bytes INTEGER,\" +\n            \"allow_register INTEGER DEFAULT 1,\" +\n            \"wake_for_delivery INTEGER DEFAULT 1,\" +\n            \"PRIMARY KEY (package_name));\";\n    private static final String TABLE_APPS = \"apps\";\n    private static final String FIELD_PACKAGE_NAME = \"package_name\";\n    private static final String FIELD_LAST_ERROR = \"last_error\";\n    private static final String FIELD_LAST_MESSAGE_TIMESTAMP = \"last_message_timestamp\";\n    private static final String FIELD_TOTAL_MESSAGE_COUNT = \"total_message_count\";\n    private static final String FIELD_TOTAL_MESSAGE_BYTES = \"total_message_bytes\";\n    private static final String FIELD_ALLOW_REGISTER = \"allow_register\";\n    private static final String FIELD_WAKE_FOR_DELIVERY = \"wake_for_delivery\";\n\n    private static final String CREATE_TABLE_REGISTRATIONS = \"CREATE TABLE registrations (\" +\n            \"package_name TEXT,\" +\n            \"signature TEXT,\" +\n            \"timestamp INTEGER,\" +\n            \"register_id TEXT,\" +\n            \"PRIMARY KEY (package_name, signature));\";\n    private static final String TABLE_REGISTRATIONS = \"registrations\";\n    private static final String FIELD_SIGNATURE = \"signature\";\n    private static final String FIELD_TIMESTAMP = \"timestamp\";\n    private static final String FIELD_REGISTER_ID = \"register_id\";\n\n    private Context context;\n\n    public GcmDatabase(Context context) {\n        super(context, DB_NAME, null, DB_VERSION);\n        this.context = context;\n        if (SDK_INT >= 16) {\n            this.setWriteAheadLoggingEnabled(true);\n        }\n    }\n\n    public static class App {\n        public final String packageName;\n        public final String lastError;\n        public final long lastMessageTimestamp;\n        public final long totalMessageCount;\n        public final long totalMessageBytes;\n        public final boolean allowRegister;\n        public final boolean wakeForDelivery;\n\n        private App(Cursor cursor) {\n            packageName = cursor.getString(cursor.getColumnIndexOrThrow(FIELD_PACKAGE_NAME));\n            lastError = cursor.getString(cursor.getColumnIndexOrThrow(FIELD_LAST_ERROR));\n            lastMessageTimestamp = cursor.getLong(cursor.getColumnIndexOrThrow(FIELD_LAST_MESSAGE_TIMESTAMP));\n            totalMessageCount = cursor.getLong(cursor.getColumnIndexOrThrow(FIELD_TOTAL_MESSAGE_COUNT));\n            totalMessageBytes = cursor.getLong(cursor.getColumnIndexOrThrow(FIELD_TOTAL_MESSAGE_BYTES));\n            allowRegister = cursor.getLong(cursor.getColumnIndexOrThrow(FIELD_ALLOW_REGISTER)) == 1;\n            wakeForDelivery = cursor.getLong(cursor.getColumnIndexOrThrow(FIELD_WAKE_FOR_DELIVERY)) == 1;\n        }\n\n        public boolean hasError() {\n            return !TextUtils.isEmpty(lastError);\n        }\n    }\n\n    public static class Registration {\n        public final String packageName;\n        public final String signature;\n        public final long timestamp;\n        public final String registerId;\n\n        public Registration(Cursor cursor) {\n            packageName = cursor.getString(cursor.getColumnIndexOrThrow(FIELD_PACKAGE_NAME));\n            signature = cursor.getString(cursor.getColumnIndexOrThrow(FIELD_SIGNATURE));\n            timestamp = cursor.getLong(cursor.getColumnIndexOrThrow(FIELD_TIMESTAMP));\n            registerId = cursor.getString(cursor.getColumnIndexOrThrow(FIELD_REGISTER_ID));\n        }\n    }\n\n    @Override\n    public void onCreate(SQLiteDatabase db) {\n        db.execSQL(CREATE_TABLE_APPS);\n        db.execSQL(CREATE_TABLE_REGISTRATIONS);\n        importLegacyData(db);\n    }\n\n    public synchronized List<App> getAppList() {\n        SQLiteDatabase db = getReadableDatabase();\n        Cursor cursor = db.query(TABLE_APPS, null, null, null, null, null, null);\n        if (cursor != null) {\n            List<App> result = new ArrayList<>();\n            while (cursor.moveToNext()) {\n                result.add(new App(cursor));\n            }\n            cursor.close();\n            return result;\n        }\n        return Collections.emptyList();\n    }\n\n    public synchronized List<Registration> getRegistrationList() {\n        SQLiteDatabase db = getReadableDatabase();\n        Cursor cursor = db.query(TABLE_REGISTRATIONS, null, null, null, null, null, null);\n        if (cursor != null) {\n            List<Registration> result = new ArrayList<>();\n            while (cursor.moveToNext()) {\n                result.add(new Registration(cursor));\n            }\n            cursor.close();\n            return result;\n        }\n        return Collections.emptyList();\n    }\n\n\n    public synchronized List<Registration> getRegistrationsByApp(String packageName) {\n        SQLiteDatabase db = getReadableDatabase();\n        Cursor cursor = db.query(TABLE_REGISTRATIONS, null, FIELD_PACKAGE_NAME + \" LIKE ?\", new String[]{packageName}, null, null, null);\n        if (cursor != null) {\n            List<Registration> result = new ArrayList<>();\n            while (cursor.moveToNext()) {\n                result.add(new Registration(cursor));\n            }\n            cursor.close();\n            return result;\n        }\n        return Collections.emptyList();\n    }\n\n    public synchronized void setAppAllowRegister(String packageName, boolean allowRegister) {\n        SQLiteDatabase db = getWritableDatabase();\n        ContentValues cv = new ContentValues();\n        cv.put(FIELD_ALLOW_REGISTER, allowRegister ? 1 : 0);\n        db.update(TABLE_APPS, cv, FIELD_PACKAGE_NAME + \" LIKE ?\", new String[]{packageName});\n    }\n\n    public synchronized void setAppWakeForDelivery(String packageName, boolean wakeForDelivery) {\n        SQLiteDatabase db = getWritableDatabase();\n        ContentValues cv = new ContentValues();\n        cv.put(FIELD_WAKE_FOR_DELIVERY, wakeForDelivery ? 1 : 0);\n        db.update(TABLE_APPS, cv, FIELD_PACKAGE_NAME + \" LIKE ?\", new String[]{packageName});\n    }\n\n\n    public synchronized void removeApp(String packageName) {\n        SQLiteDatabase db = getWritableDatabase();\n        db.delete(TABLE_REGISTRATIONS, FIELD_PACKAGE_NAME + \" LIKE ?\", new String[]{packageName});\n        db.delete(TABLE_APPS, FIELD_PACKAGE_NAME + \" LIKE ?\", new String[]{packageName});\n    }\n\n    public synchronized void noteAppRegistrationError(String packageName, String error) {\n        SQLiteDatabase db = getWritableDatabase();\n        ContentValues cv = new ContentValues();\n        cv.put(FIELD_LAST_ERROR, error);\n        db.update(TABLE_APPS, cv, FIELD_PACKAGE_NAME + \" LIKE ?\", new String[]{packageName});\n    }\n\n    public synchronized void noteAppKnown(String packageName, boolean allowRegister) {\n        SQLiteDatabase db = getWritableDatabase();\n        db.beginTransaction();\n\n        App app = getApp(db, packageName);\n        ContentValues cv = new ContentValues();\n        cv.put(FIELD_ALLOW_REGISTER, allowRegister);\n        if (app == null) {\n            cv.put(FIELD_PACKAGE_NAME, packageName);\n            db.insert(TABLE_APPS, null, cv);\n        } else {\n            db.update(TABLE_APPS, cv, FIELD_PACKAGE_NAME + \" LIKE ?\", new String[]{packageName});\n        }\n\n        db.setTransactionSuccessful();\n        db.endTransaction();\n    }\n\n    public synchronized void noteAppMessage(String packageName, int numBytes) {\n        SQLiteDatabase db = getWritableDatabase();\n        db.beginTransaction();\n\n        App app = getApp(db, packageName);\n        ContentValues cv = new ContentValues();\n        cv.put(FIELD_LAST_MESSAGE_TIMESTAMP, System.currentTimeMillis());\n        if (app == null) {\n            cv.put(FIELD_PACKAGE_NAME, packageName);\n            cv.put(FIELD_TOTAL_MESSAGE_COUNT, 1);\n            cv.put(FIELD_TOTAL_MESSAGE_BYTES, numBytes);\n            db.insert(TABLE_APPS, null, cv);\n        } else {\n            cv.put(FIELD_TOTAL_MESSAGE_COUNT, app.totalMessageCount + 1);\n            cv.put(FIELD_TOTAL_MESSAGE_BYTES, app.totalMessageBytes + numBytes);\n            db.update(TABLE_APPS, cv, FIELD_PACKAGE_NAME + \" LIKE ?\", new String[]{packageName});\n        }\n\n        db.setTransactionSuccessful();\n        db.endTransaction();\n    }\n\n    public synchronized void noteAppRegistered(String packageName, String signature, String registrationId) {\n        SQLiteDatabase db = getWritableDatabase();\n        db.beginTransaction();\n\n        App app = getApp(db, packageName);\n        if (app == null) {\n            ContentValues cv = new ContentValues();\n            cv.put(FIELD_PACKAGE_NAME, packageName);\n            db.insert(TABLE_APPS, null, cv);\n        } else {\n            ContentValues cv = new ContentValues();\n            cv.put(FIELD_LAST_ERROR, \"\");\n            db.update(TABLE_APPS, cv, FIELD_PACKAGE_NAME + \" LIKE ?\", new String[]{packageName});\n        }\n\n        ContentValues cv = new ContentValues();\n        cv.put(FIELD_PACKAGE_NAME, packageName);\n        cv.put(FIELD_SIGNATURE, signature);\n        cv.put(FIELD_REGISTER_ID, registrationId);\n        cv.put(FIELD_TIMESTAMP, System.currentTimeMillis());\n        db.insertWithOnConflict(TABLE_REGISTRATIONS, null, cv, SQLiteDatabase.CONFLICT_REPLACE);\n\n        db.setTransactionSuccessful();\n        db.endTransaction();\n    }\n\n    public synchronized void noteAppUnregistered(String packageName, String signature) {\n        SQLiteDatabase db = getWritableDatabase();\n        db.delete(TABLE_REGISTRATIONS, FIELD_PACKAGE_NAME + \" LIKE ? AND \" + FIELD_SIGNATURE + \" LIKE ?\", new String[]{packageName, signature});\n    }\n\n    public App getApp(String packageName) {\n        return getApp(getReadableDatabase(), packageName);\n    }\n\n    private App getApp(SQLiteDatabase db, String packageName) {\n        Cursor cursor = db.query(TABLE_APPS, null, FIELD_PACKAGE_NAME + \" LIKE ?\", new String[]{packageName}, null, null, null, \"1\");\n        if (cursor != null) {\n            try {\n                if (cursor.moveToNext()) {\n                    return new App(cursor);\n                }\n            } finally {\n                cursor.close();\n            }\n        }\n        return null;\n    }\n\n    public Registration getRegistration(String packageName, String signature) {\n        return getRegistration(getReadableDatabase(), packageName, signature);\n    }\n\n    private Registration getRegistration(SQLiteDatabase db, String packageName, String signature) {\n        Cursor cursor = db.query(TABLE_REGISTRATIONS, null, FIELD_PACKAGE_NAME + \" LIKE ? AND \" + FIELD_SIGNATURE + \" LIKE ?\", new String[]{packageName, signature}, null, null, null, \"1\");\n        if (cursor != null) {\n            try {\n                if (cursor.moveToNext()) {\n                    return new Registration(cursor);\n                }\n            } finally {\n                cursor.close();\n            }\n        }\n        return null;\n    }\n\n\n    @SuppressWarnings(\"deprecation\")\n    private void importLegacyData(SQLiteDatabase db) {\n        db.beginTransaction();\n\n        GcmLegacyData legacyData = new GcmLegacyData(context);\n        for (GcmLegacyData.LegacyAppInfo appInfo : legacyData.getAppsInfo()) {\n            ContentValues cv = new ContentValues();\n            cv.put(FIELD_PACKAGE_NAME, appInfo.app);\n            cv.put(FIELD_TOTAL_MESSAGE_COUNT, legacyData.getAppMessageCount(appInfo.app));\n            cv.put(FIELD_LAST_ERROR, appInfo.hasUnregistrationError() ? \"Unregistration error\" : null);\n            db.insert(TABLE_APPS, null, cv);\n            cv.clear();\n            if (appInfo.isRegistered()) {\n                cv.put(FIELD_PACKAGE_NAME, appInfo.app);\n                cv.put(FIELD_SIGNATURE, appInfo.appSignature);\n                cv.put(FIELD_REGISTER_ID, appInfo.registerID);\n                db.insert(TABLE_REGISTRATIONS, null, cv);\n            }\n        }\n\n        db.setTransactionSuccessful();\n        db.endTransaction();\n    }\n\n    @Override\n    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {\n        throw new IllegalStateException(\"Upgrades not supported\");\n    }\n\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/gcm/GcmLegacyData.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.gcm;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Set;\n\n@Deprecated\npublic class GcmLegacyData {\n    private static final String GCM_REGISTRATION_PREF = \"gcm_registrations\";\n    private static final String GCM_MESSAGES_PREF = \"gcm_messages\";\n\n    static final String REMOVED = \"%%REMOVED%%\";\n    static final String ERROR = \"%%ERROR%%\";\n\n    private Context context;\n\n    public GcmLegacyData(Context context) {\n        this.context = context;\n    }\n\n    @Deprecated\n    public static class LegacyAppInfo implements Comparable<LegacyAppInfo> {\n        public String app = null;\n        public String appSignature = null;\n        public String registerID = null;\n\n        private final int STATE_ERROR = 1;\n        private final int STATE_REMOVED = 2;\n        private final int STATE_REGISTERED = 3;\n        private int state;\n\n        public LegacyAppInfo(String key, String value) {\n            if (ERROR.equals(value)) {\n                state = STATE_ERROR;\n            } else if (REMOVED.equals(value)) {\n                state = STATE_REMOVED;\n            } else {\n                state = STATE_REGISTERED;\n                registerID = value;\n            }\n            String[] splitKey = key.split(\":\");\n            app = splitKey[0];\n            appSignature = splitKey[1];\n        }\n\n        public boolean isRegistered() {\n            return state == STATE_REGISTERED;\n        }\n\n        public boolean isRemoved() {\n            return state == STATE_REMOVED;\n        }\n\n        public boolean hasUnregistrationError() {\n            return state == STATE_ERROR;\n        }\n\n        @Override\n        public int compareTo(LegacyAppInfo another) {\n            return app.compareTo(another.app);\n        }\n    }\n\n    @Deprecated\n    public int getAppMessageCount(String app) {\n        return getStatsSharedPreferences().getInt(app, 0);\n    }\n\n    @Deprecated\n    public List<LegacyAppInfo> getAppsInfo() {\n        ArrayList<LegacyAppInfo> ret = new ArrayList<>();\n        Set<String> keys = getInfoSharedPreferences().getAll().keySet();\n        for (String key : keys) {\n            ret.add(getAppInfo(key));\n        }\n        return ret;\n    }\n\n    @Deprecated\n    private LegacyAppInfo getAppInfo(String key) {\n        return new LegacyAppInfo(key, getInfoSharedPreferences().getString(key, \"\"));\n    }\n\n    private SharedPreferences getInfoSharedPreferences() {\n        return context.getSharedPreferences(GCM_REGISTRATION_PREF, Context.MODE_PRIVATE);\n    }\n\n    private SharedPreferences getStatsSharedPreferences() {\n        return context.getSharedPreferences(GCM_MESSAGES_PREF, Context.MODE_PRIVATE);\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/gcm/McsConstants.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.gcm;\n\npublic final class McsConstants {\n    public static final int MCS_HEARTBEAT_PING_TAG = 0;\n    public static final int MCS_HEARTBEAT_ACK_TAG = 1;\n    public static final int MCS_LOGIN_REQUEST_TAG = 2;\n    public static final int MCS_LOGIN_RESPONSE_TAG = 3;\n    public static final int MCS_CLOSE_TAG = 4;\n    public static final int MCS_IQ_STANZA_TAG = 7;\n    public static final int MCS_DATA_MESSAGE_STANZA_TAG = 8;\n\n    public static final int MCS_VERSION_CODE = 41;\n\n    public static final int MSG_INPUT = 10;\n    public static final int MSG_INPUT_ERROR = 11;\n    public static final int MSG_OUTPUT = 20;\n    public static final int MSG_OUTPUT_ERROR = 21;\n    public static final int MSG_OUTPUT_READY = 22;\n    public static final int MSG_OUTPUT_DONE = 23;\n    public static final int MSG_TEARDOWN = 30;\n    public static final int MSG_CONNECT = 40;\n    public static final int MSG_HEARTBEAT = 41;\n    public static final int MSG_ACK = 42;\n\n    public static String ACTION_CONNECT = \"org.microg.gms.gcm.mcs.CONNECT\";\n    public static String ACTION_RECONNECT = \"org.microg.gms.gcm.mcs.RECONNECT\";\n    public static String ACTION_HEARTBEAT = \"org.microg.gms.gcm.mcs.HEARTBEAT\";\n    public static String ACTION_SEND = \"org.microg.gms.gcm.mcs.SEND\";\n    public static String ACTION_ACK = \"org.microg.gms.gcm.mcs.ACK\";\n    public static String EXTRA_REASON = \"org.microg.gms.gcm.mcs.REASON\";\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/gcm/McsInputStream.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.gcm;\n\nimport android.os.Handler;\nimport android.util.Log;\n\nimport com.squareup.wire.Message;\n\nimport org.microg.gms.gcm.mcs.Close;\nimport org.microg.gms.gcm.mcs.DataMessageStanza;\nimport org.microg.gms.gcm.mcs.HeartbeatAck;\nimport org.microg.gms.gcm.mcs.HeartbeatPing;\nimport org.microg.gms.gcm.mcs.IqStanza;\nimport org.microg.gms.gcm.mcs.LoginRequest;\nimport org.microg.gms.gcm.mcs.LoginResponse;\n\nimport java.io.Closeable;\nimport java.io.IOException;\nimport java.io.InputStream;\n\nimport static org.microg.gms.gcm.McsConstants.MCS_CLOSE_TAG;\nimport static org.microg.gms.gcm.McsConstants.MCS_DATA_MESSAGE_STANZA_TAG;\nimport static org.microg.gms.gcm.McsConstants.MCS_HEARTBEAT_ACK_TAG;\nimport static org.microg.gms.gcm.McsConstants.MCS_HEARTBEAT_PING_TAG;\nimport static org.microg.gms.gcm.McsConstants.MCS_IQ_STANZA_TAG;\nimport static org.microg.gms.gcm.McsConstants.MCS_LOGIN_REQUEST_TAG;\nimport static org.microg.gms.gcm.McsConstants.MCS_LOGIN_RESPONSE_TAG;\nimport static org.microg.gms.gcm.McsConstants.MSG_INPUT;\nimport static org.microg.gms.gcm.McsConstants.MSG_INPUT_ERROR;\nimport static org.microg.gms.gcm.McsConstants.MSG_TEARDOWN;\n\npublic class McsInputStream extends Thread implements Closeable {\n    private static final String TAG = \"GmsGcmMcsInput\";\n\n    private final InputStream is;\n    private final Handler mainHandler;\n\n    private boolean initialized;\n    private int version = -1;\n    private int lastStreamIdReported = -1;\n    private int streamId = 0;\n    private long lastMsgTime = 0;\n\n    private volatile boolean closed = false;\n\n    public McsInputStream(InputStream is, Handler mainHandler) {\n        this(is, mainHandler, false);\n    }\n\n    public McsInputStream(InputStream is, Handler mainHandler, boolean initialized) {\n        this.is = is;\n        this.mainHandler = mainHandler;\n        this.initialized = initialized;\n        setName(\"McsInputStream\");\n    }\n\n    @Override\n    public void run() {\n        try {\n            while (!Thread.currentThread().isInterrupted() && !closed) {\n                android.os.Message msg = read();\n                if (msg != null) {\n                    mainHandler.dispatchMessage(msg);\n                } else {\n                    mainHandler.dispatchMessage(mainHandler.obtainMessage(MSG_TEARDOWN, \"null message\"));\n                    break; // if input is empty, do not continue looping\n                }\n            }\n        } catch (IOException e) {\n            if (closed) {\n                Log.d(TAG, \"We were closed already. Ignoring IOException\");\n            } else {\n                mainHandler.dispatchMessage(mainHandler.obtainMessage(MSG_INPUT_ERROR, e));\n            }\n        }\n        try {\n            is.close();\n        } catch (IOException ignored) {\n        }\n    }\n\n    @Override\n    public void close() {\n        if (!closed) {\n            closed = true;\n            interrupt();\n        }\n    }\n\n    public int getStreamId() {\n        lastStreamIdReported = streamId;\n        return streamId;\n    }\n\n    public boolean newStreamIdAvailable() {\n        return lastStreamIdReported != streamId;\n    }\n\n    public int getVersion() {\n        ensureVersionRead();\n        return version;\n    }\n\n    private synchronized void ensureVersionRead() {\n        if (!initialized) {\n            try {\n                version = is.read();\n                Log.d(TAG, \"Reading from MCS version: \" + version);\n                initialized = true;\n            } catch (IOException e) {\n                Log.w(TAG, \"Error reading version\", e);\n            }\n        }\n    }\n\n    public synchronized android.os.Message read() throws IOException {\n        ensureVersionRead();\n        int mcsTag = is.read();\n        int mcsSize = readVarint();\n        if (mcsTag < 0 || mcsSize < 0) {\n            Log.w(TAG, \"mcsTag: \" + mcsTag + \" mcsSize: \" + mcsSize);\n            return null;\n        }\n        byte[] bytes = new byte[mcsSize];\n        int len = 0, read = 0;\n        while (len < mcsSize && read >= 0) {\n            len += (read = is.read(bytes, len, mcsSize - len)) < 0 ? 0 : read;\n        }\n        Message message = read(mcsTag, bytes, len);\n        if (message == null) return null;\n        Log.d(TAG, \"Incoming message: \" + message);\n        streamId++;\n        return mainHandler.obtainMessage(MSG_INPUT, mcsTag, streamId, message);\n    }\n\n    private static Message read(int mcsTag, byte[] bytes, int len) throws IOException {\n        try {\n            switch (mcsTag) {\n                case MCS_HEARTBEAT_PING_TAG:\n                    return HeartbeatPing.ADAPTER.decode(bytes);\n                case MCS_HEARTBEAT_ACK_TAG:\n                    return HeartbeatAck.ADAPTER.decode(bytes);\n                case MCS_LOGIN_REQUEST_TAG:\n                    return LoginRequest.ADAPTER.decode(bytes);\n                case MCS_LOGIN_RESPONSE_TAG:\n                    return LoginResponse.ADAPTER.decode(bytes);\n                case MCS_CLOSE_TAG:\n                    return Close.ADAPTER.decode(bytes);\n                case MCS_IQ_STANZA_TAG:\n                    return IqStanza.ADAPTER.decode(bytes);\n                case MCS_DATA_MESSAGE_STANZA_TAG:\n                    return DataMessageStanza.ADAPTER.decode(bytes);\n                default:\n                    Log.w(TAG, \"Unknown tag: \" + mcsTag);\n                    return null;\n            }\n        } catch (IllegalStateException e) {\n            Log.w(TAG, \"Error parsing tag: \"+mcsTag, e);\n            return null;\n        }\n    }\n\n    private int readVarint() throws IOException {\n        int res = 0, s = -7, read;\n        do {\n            res |= ((read = is.read()) & 0x7F) << (s += 7);\n        } while (read >= 0 && (read & 0x80) == 0x80 && s < 32);\n        if (read < 0) return -1;\n        return res;\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/gcm/McsOutputStream.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.gcm;\n\nimport android.os.Handler;\nimport android.os.Looper;\nimport android.util.Log;\n\nimport com.squareup.wire.Message;\n\nimport java.io.Closeable;\nimport java.io.IOException;\nimport java.io.OutputStream;\n\nimport static org.microg.gms.gcm.McsConstants.MCS_VERSION_CODE;\nimport static org.microg.gms.gcm.McsConstants.MSG_OUTPUT;\nimport static org.microg.gms.gcm.McsConstants.MSG_OUTPUT_DONE;\nimport static org.microg.gms.gcm.McsConstants.MSG_OUTPUT_ERROR;\nimport static org.microg.gms.gcm.McsConstants.MSG_OUTPUT_READY;\nimport static org.microg.gms.gcm.McsConstants.MSG_TEARDOWN;\n\npublic class McsOutputStream extends Thread implements Handler.Callback, Closeable {\n    private static final String TAG = \"GmsGcmMcsOutput\";\n\n    private final OutputStream os;\n    private boolean initialized;\n    private int version = MCS_VERSION_CODE;\n    private int streamId = 0;\n\n    private final Handler mainHandler;\n    private Handler myHandler;\n\n    private volatile boolean closed = false;\n\n    public McsOutputStream(OutputStream os, Handler mainHandler) {\n        this(os, mainHandler, false);\n    }\n\n    public McsOutputStream(OutputStream os, Handler mainHandler, boolean initialized) {\n        this.os = os;\n        this.mainHandler = mainHandler;\n        this.initialized = initialized;\n        setName(\"McsOutputStream\");\n    }\n\n    public int getStreamId() {\n        return streamId;\n    }\n\n    @Override\n    public void run() {\n        Looper.prepare();\n        myHandler = new Handler(this);\n        mainHandler.dispatchMessage(mainHandler.obtainMessage(MSG_OUTPUT_READY));\n        Looper.loop();\n    }\n\n    @Override\n    public boolean handleMessage(android.os.Message msg) {\n        switch (msg.what) {\n            case MSG_OUTPUT:\n                try {\n                    Log.d(TAG, \"Outgoing message: \" + msg.obj);\n                    writeInternal((Message) msg.obj, msg.arg1);\n                    mainHandler.dispatchMessage(mainHandler.obtainMessage(MSG_OUTPUT_DONE, msg.arg1, msg.arg2, msg.obj));\n                } catch (IOException e) {\n                    if (closed) {\n                        Log.d(TAG, \"We were closed already. Ignoring IOException\");\n                    } else {\n                        mainHandler.dispatchMessage(mainHandler.obtainMessage(MSG_OUTPUT_ERROR, e));\n                    }\n                }\n                return true;\n            case MSG_TEARDOWN:\n                try {\n                    os.close();\n                } catch (IOException ignored) {\n                }\n                try {\n                    Looper.myLooper().quit();\n                } catch (Exception ignored) {\n                }\n                return true;\n        }\n        return false;\n    }\n\n    @Override\n    public void close() {\n        if (!closed) {\n            closed = true;\n            myHandler.getLooper().quit();\n            interrupt();\n        }\n    }\n\n    private synchronized void writeInternal(Message message, int tag) throws IOException {\n        if (!initialized) {\n            Log.d(TAG, \"Write MCS version code: \" + version);\n            os.write(version);\n            initialized = true;\n        }\n        os.write(tag);\n        byte[] bytes = message.encode();\n        writeVarint(os, bytes.length);\n        os.write(bytes);\n        os.flush();\n        streamId++;\n    }\n\n    private void writeVarint(OutputStream os, int value) throws IOException {\n        while (true) {\n            if ((value & ~0x7FL) == 0) {\n                os.write(value);\n                return;\n            } else {\n                os.write((value & 0x7F) | 0x80);\n                value >>>= 7;\n            }\n        }\n    }\n\n    public Handler getHandler() {\n        return myHandler;\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/gcm/McsService.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.gcm;\n\nimport android.annotation.SuppressLint;\nimport android.app.AlarmManager;\nimport android.app.PendingIntent;\nimport android.app.Service;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.content.pm.PermissionInfo;\nimport android.content.pm.ResolveInfo;\nimport android.net.ConnectivityManager;\nimport android.net.NetworkInfo;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.os.IBinder;\nimport android.os.Looper;\nimport android.os.Messenger;\nimport android.os.Parcelable;\nimport android.os.PowerManager;\nimport android.os.SystemClock;\nimport android.os.UserHandle;\nimport android.util.Base64;\nimport android.util.Log;\n\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\nimport androidx.core.app.PendingIntentCompat;\nimport androidx.legacy.content.WakefulBroadcastReceiver;\n\nimport com.squareup.wire.Message;\n\nimport org.microg.gms.checkin.LastCheckinInfo;\nimport org.microg.gms.common.Constants;\nimport org.microg.gms.common.ForegroundServiceContext;\nimport org.microg.gms.common.ForegroundServiceInfo;\nimport org.microg.gms.common.PackageUtils;\nimport org.microg.gms.gcm.mcs.AppData;\nimport org.microg.gms.gcm.mcs.Close;\nimport org.microg.gms.gcm.mcs.DataMessageStanza;\nimport org.microg.gms.gcm.mcs.Extension;\nimport org.microg.gms.gcm.mcs.HeartbeatAck;\nimport org.microg.gms.gcm.mcs.HeartbeatPing;\nimport org.microg.gms.gcm.mcs.IqStanza;\nimport org.microg.gms.gcm.mcs.LoginRequest;\nimport org.microg.gms.gcm.mcs.LoginResponse;\nimport org.microg.gms.gcm.mcs.Setting;\n\nimport java.io.Closeable;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.net.Socket;\nimport java.net.SocketException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport javax.net.ssl.SSLContext;\n\nimport okio.ByteString;\n\nimport static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;\nimport static android.os.Build.VERSION.SDK_INT;\nimport static org.microg.gms.common.PackageUtils.warnIfNotPersistentProcess;\nimport static org.microg.gms.gcm.ExtensionsKt.ACTION_GCM_CONNECTED;\nimport static org.microg.gms.gcm.GcmConstants.*;\nimport static org.microg.gms.gcm.McsConstants.*;\n\n@ForegroundServiceInfo(value = \"Cloud messaging\", resName = \"service_name_mcs\", resPackage = \"com.google.android.gms\")\npublic class McsService extends Service implements Handler.Callback {\n    private static final String TAG = \"GmsGcmMcsSvc\";\n\n    public static final String SELF_CATEGORY = \"com.google.android.gsf.gtalkservice\";\n    public static final String IDLE_NOTIFICATION = \"IdleNotification\";\n    public static final String FROM_FIELD = \"gcm@android.com\";\n\n    public static final String SERVICE_HOST = \"mtalk.google.com\";\n    // A few ports are available: 443, 5228-5230 but also 5222-5223\n    // See https://github.com/microg/GmsCore/issues/408\n    // Likely if the main port 5228 is blocked by a firewall, the other 52xx are blocked as well\n    public static final int[] SERVICE_PORTS = {5228, 443};\n\n    private static final int WAKELOCK_TIMEOUT = 5000;\n    // On bad mobile network a ping can take >60s, so we wait for an ACK for 90s\n    private static final int HEARTBEAT_ACK_AFTER_PING_TIMEOUT_MS = 90000;\n\n    private static long lastHeartbeatPingElapsedRealtime = -1;\n    private static long lastHeartbeatAckElapsedRealtime = -1;\n    private static long lastIncomingNetworkRealtime = 0;\n    private static long startTimestamp = 0;\n    public static String activeNetworkPref = null;\n    private boolean wasTornDown = false;\n    private AtomicInteger nextMessageId = new AtomicInteger(0x1000000);\n\n    private static Socket sslSocket;\n    private static McsInputStream inputStream;\n    private static McsOutputStream outputStream;\n\n    private PendingIntent heartbeatIntent;\n\n    private static HandlerThread handlerThread;\n    private static Handler rootHandler;\n\n    private GcmDatabase database;\n\n    private AlarmManager alarmManager;\n    private PowerManager powerManager;\n    private static PowerManager.WakeLock wakeLock;\n\n    private static long currentDelay = 0;\n\n    private Intent connectIntent;\n\n    private static int maxTtl = 24 * 60 * 60;\n\n    @Nullable\n    private Method getUserIdMethod;\n    @Nullable\n    private Object deviceIdleController;\n    @Nullable\n    private Method addPowerSaveTempWhitelistAppMethod;\n    @Nullable\n    @RequiresApi(31)\n    private Object powerExemptionManager;\n    @Nullable\n    @RequiresApi(31)\n    private Method addToTemporaryAllowListMethod;\n\n    private class HandlerThread extends Thread {\n\n        public HandlerThread() {\n            setName(\"McsHandler\");\n        }\n\n        @Override\n        public void run() {\n            Looper.prepare();\n            wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, \"mcs\");\n            wakeLock.setReferenceCounted(false);\n            synchronized (McsService.class) {\n                rootHandler = new Handler(Looper.myLooper(), McsService.this);\n                if (connectIntent != null) {\n                    rootHandler.sendMessage(rootHandler.obtainMessage(MSG_CONNECT, connectIntent));\n                    WakefulBroadcastReceiver.completeWakefulIntent(connectIntent);\n                }\n            }\n            Looper.loop();\n        }\n    }\n\n    private static void logd(Context context, String msg) {\n        if (context == null || GcmPrefs.get(context).isGcmLogEnabled()) Log.d(TAG, msg);\n    }\n\n    @Override\n    @SuppressLint(\"PrivateApi\")\n    public void onCreate() {\n        super.onCreate();\n        TriggerReceiver.register(this);\n        database = new GcmDatabase(this);\n        heartbeatIntent = PendingIntentCompat.getService(this, 0, new Intent(ACTION_HEARTBEAT, null, this, McsService.class), 0, false);\n        alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);\n        powerManager = (PowerManager) getSystemService(POWER_SERVICE);\n        if (SDK_INT >= 23 && checkSelfPermission(\"android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST\") == PackageManager.PERMISSION_GRANTED) {\n            try {\n                if (SDK_INT >= 31) {\n                    Class<?> powerExemptionManagerClass = Class.forName(\"android.os.PowerExemptionManager\");\n                    powerExemptionManager = getSystemService(powerExemptionManagerClass);\n                    addToTemporaryAllowListMethod =\n                            powerExemptionManagerClass.getMethod(\"addToTemporaryAllowList\", String.class, int.class, String.class, long.class);\n                } else {\n                    String deviceIdleControllerName = \"deviceidle\";\n                    try {\n                        Field field = Context.class.getField(\"DEVICE_IDLE_CONTROLLER\");\n                        deviceIdleControllerName = (String) field.get(null);\n                    } catch (Exception ignored) {\n                    }\n                    IBinder binder = (IBinder) Class.forName(\"android.os.ServiceManager\")\n                            .getMethod(\"getService\", String.class).invoke(null, deviceIdleControllerName);\n                    if (binder != null) {\n                        deviceIdleController = Class.forName(\"android.os.IDeviceIdleController$Stub\")\n                                .getMethod(\"asInterface\", IBinder.class).invoke(null, binder);\n                        getUserIdMethod = UserHandle.class.getMethod(\"getUserId\", int.class);\n                        addPowerSaveTempWhitelistAppMethod = deviceIdleController.getClass()\n                                .getMethod(\"addPowerSaveTempWhitelistApp\", String.class, long.class, int.class, String.class);\n                    }\n                }\n            } catch (Exception e) {\n                Log.w(TAG, e);\n            }\n        }\n        synchronized (McsService.class) {\n            if (handlerThread == null) {\n                handlerThread = new HandlerThread();\n                handlerThread.start();\n            }\n        }\n    }\n\n    public static void stop(Context context) {\n        context.stopService(new Intent(context, McsService.class));\n        closeAll();\n    }\n\n    @Override\n    public void onDestroy() {\n        Log.d(TAG, \"onDestroy\");\n        alarmManager.cancel(heartbeatIntent);\n        closeAll();\n        database.close();\n        super.onDestroy();\n    }\n\n    @Override\n    public IBinder onBind(Intent intent) {\n        return null;\n    }\n\n    public synchronized static boolean isConnected(Context context) {\n        warnIfNotPersistentProcess(McsService.class);\n        if (inputStream == null || !inputStream.isAlive() || outputStream == null || !outputStream.isAlive()) {\n            logd(null, \"Connection is not enabled or dead.\");\n            return false;\n        }\n        // consider connection to be dead if we did not receive an ack within 90s to our ping\n        int heartbeatMs = GcmPrefs.get(context).getHeartbeatMsFor(activeNetworkPref);\n        // if disabled for active network, heartbeatMs will be -1\n        if (heartbeatMs < 0) {\n            closeAll();\n            return false;\n        } else {\n            boolean noAckReceived = lastHeartbeatAckElapsedRealtime < lastHeartbeatPingElapsedRealtime;\n            long timeSinceLastPing = SystemClock.elapsedRealtime() - lastHeartbeatPingElapsedRealtime;\n            if (noAckReceived && timeSinceLastPing > HEARTBEAT_ACK_AFTER_PING_TIMEOUT_MS) {\n                logd(null, \"No heartbeat for \" + timeSinceLastPing / 1000 + \"s, connection assumed to be dead after 90s\");\n                GcmPrefs.get(context).learnTimeout(context, activeNetworkPref);\n                return false;\n            }\n        }\n        return true;\n    }\n\n    public static long getStartTimestamp() {\n        warnIfNotPersistentProcess(McsService.class);\n        return startTimestamp;\n    }\n\n    public static void scheduleReconnect(Context context) {\n        AlarmManager alarmManager = (AlarmManager) context.getSystemService(ALARM_SERVICE);\n        long delay = getCurrentDelay();\n        logd(context, \"Scheduling reconnect in \" + delay / 1000 + \" seconds...\");\n        PendingIntent pi = PendingIntentCompat.getBroadcast(context, 1, new Intent(ACTION_RECONNECT, null, context, TriggerReceiver.class), 0, false);\n        if (SDK_INT >= 23) {\n            alarmManager.setExactAndAllowWhileIdle(ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + delay, pi);\n        } else {\n            alarmManager.set(ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + delay, pi);\n        }\n    }\n\n    public void scheduleHeartbeat(Context context) {\n        AlarmManager alarmManager = (AlarmManager) context.getSystemService(ALARM_SERVICE);\n\n        int heartbeatMs = GcmPrefs.get(this).getHeartbeatMsFor(activeNetworkPref);\n        if (heartbeatMs < 0) {\n            closeAll();\n        }\n        logd(context, \"Scheduling heartbeat in \" + heartbeatMs / 1000 + \" seconds...\");\n        if (SDK_INT >= 23) {\n            // This is supposed to work even when running in idle and without battery optimization disabled\n            alarmManager.setExactAndAllowWhileIdle(ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + heartbeatMs, heartbeatIntent);\n        } else if (SDK_INT >= 19) {\n            // With KitKat, the alarms become inexact by default, but with the newly available setWindow we can get inexact alarms with guarantees.\n            // Schedule the alarm to fire within the interval [heartbeatMs/3*4, heartbeatMs]\n            alarmManager.setWindow(ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + heartbeatMs / 4 * 3, heartbeatMs / 4,\n                    heartbeatIntent);\n        } else {\n            alarmManager.set(ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + heartbeatMs, heartbeatIntent);\n        }\n\n    }\n\n    public synchronized static long getCurrentDelay() {\n        long delay = currentDelay == 0 ? 5000 : currentDelay;\n        if (currentDelay < 60000) currentDelay += 10000;\n        if (currentDelay >= 60000 && currentDelay < 600000) currentDelay += 60000;\n        return delay;\n    }\n\n    public synchronized static void resetCurrentDelay() {\n        currentDelay = 0;\n    }\n\n\n    @Override\n    public int onStartCommand(Intent intent, int flags, int startId) {\n        ForegroundServiceContext.completeForegroundService(this, intent, TAG);\n        synchronized (McsService.class) {\n            if (rootHandler != null) {\n                if (intent == null) return START_REDELIVER_INTENT;\n                wakeLock.acquire(WAKELOCK_TIMEOUT);\n                Object reason = intent.hasExtra(EXTRA_REASON) ? intent.getExtras().get(EXTRA_REASON) : intent;\n                if (ACTION_CONNECT.equals(intent.getAction())) {\n                    rootHandler.sendMessage(rootHandler.obtainMessage(MSG_CONNECT, reason));\n                } else if (ACTION_HEARTBEAT.equals(intent.getAction())) {\n                    rootHandler.sendMessage(rootHandler.obtainMessage(MSG_HEARTBEAT, reason));\n                } else if (ACTION_SEND.equals(intent.getAction())) {\n                    handleSendMessage(intent);\n                } else if (ACTION_ACK.equals(intent.getAction())) {\n                    rootHandler.sendMessage(rootHandler.obtainMessage(MSG_ACK, reason));\n                }\n                WakefulBroadcastReceiver.completeWakefulIntent(intent);\n            } else if (connectIntent == null) {\n                connectIntent = intent;\n            } else if (intent != null) {\n                WakefulBroadcastReceiver.completeWakefulIntent(intent);\n            }\n        }\n        return START_REDELIVER_INTENT;\n    }\n\n    private void handleSendMessage(Intent intent) {\n        String messageId = intent.getStringExtra(EXTRA_MESSAGE_ID);\n        String collapseKey = intent.getStringExtra(EXTRA_COLLAPSE_KEY);\n\n        Messenger messenger = intent.getParcelableExtra(EXTRA_MESSENGER);\n        intent.removeExtra(EXTRA_MESSENGER);\n\n        Parcelable app = intent.getParcelableExtra(EXTRA_APP);\n        String packageName = null;\n        if (app instanceof PendingIntent) {\n            packageName = PackageUtils.packageFromPendingIntent((PendingIntent) app);\n        }\n        if (packageName == null) {\n            Log.w(TAG, \"Failed to send message, missing package name\");\n            return;\n        }\n        if (packageName.equals(getPackageName()) && intent.hasExtra(EXTRA_APP_OVERRIDE)) {\n            packageName = intent.getStringExtra(EXTRA_APP_OVERRIDE);\n            intent.removeExtra(EXTRA_APP_OVERRIDE);\n        }\n        intent.removeExtra(EXTRA_APP);\n\n        int ttl;\n        try {\n            if (intent.hasExtra(EXTRA_TTL)) {\n                ttl = Integer.parseInt(intent.getStringExtra(EXTRA_TTL));\n                if (ttl < 0 || ttl > maxTtl) {\n                    ttl = maxTtl;\n                }\n            } else {\n                ttl = maxTtl;\n            }\n        } catch (NumberFormatException e) {\n            Log.w(TAG, e);\n            ttl = maxTtl;\n        }\n\n        String to = intent.getStringExtra(EXTRA_SEND_TO);\n        if (to == null) {\n            // TODO: error missing_to\n            Log.w(TAG, \"missing to\");\n            return;\n        }\n\n        String from = intent.getStringExtra(EXTRA_SEND_FROM);\n        if (from != null) {\n            intent.removeExtra(EXTRA_SEND_FROM);\n        } else {\n            from = intent.getStringExtra(EXTRA_FROM);\n        }\n        if (from == null) {\n            GcmDatabase.Registration reg = database.getRegistration(packageName, PackageUtils.firstSignatureDigest(this, packageName));\n            if (reg != null) from = reg.registerId;\n        }\n        if (from == null) {\n            Log.e(TAG, \"Can't send message, missing from!\");\n            return;\n        }\n\n        String registrationId = intent.getStringExtra(EXTRA_REGISTRATION_ID);\n        intent.removeExtra(EXTRA_REGISTRATION_ID);\n\n        List<AppData> appData = new ArrayList<>();\n        Bundle extras = intent.getExtras();\n        for (String key : extras.keySet()) {\n            if (!key.startsWith(\"google.\")) {\n                Object val = extras.get(key);\n                if (val instanceof String) {\n                    appData.add(new AppData.Builder().key(key).value_((String) val).build());\n                }\n            }\n        }\n\n        byte[] rawDataArray = intent.getByteArrayExtra(\"rawData\");\n        ByteString rawData = rawDataArray != null ? ByteString.of(rawDataArray) : null;\n\n        try {\n            DataMessageStanza msg = new DataMessageStanza.Builder()\n                    .sent(System.currentTimeMillis() / 1000L)\n                    .id(Integer.toHexString(nextMessageId.incrementAndGet()))\n                    .persistent_id(messageId)\n                    .token(collapseKey)\n                    .from(from)\n                    .reg_id(registrationId)\n                    .to(to)\n                    .category(packageName)\n                    .raw_data(rawData)\n                    .ttl(ttl)\n                    .app_data(appData).build();\n\n            send(MCS_DATA_MESSAGE_STANZA_TAG, msg);\n            if (messenger != null) {\n                messenger.send(android.os.Message.obtain());\n            }\n            database.noteAppMessage(packageName, DataMessageStanza.ADAPTER.encodedSize(msg));\n        } catch (Exception e) {\n            Log.w(TAG, e);\n        }\n    }\n\n    private void connect(int port) throws Exception {\n        this.wasTornDown = false;\n\n        logd(this, \"Starting MCS connection to port \" + port + \"...\");\n        Socket socket = new Socket(SERVICE_HOST, port);\n        logd(this, \"Connected to \" + SERVICE_HOST + \":\" + port);\n        sslSocket = SSLContext.getDefault().getSocketFactory().createSocket(socket, SERVICE_HOST, port, true);\n        logd(this, \"Activated SSL with \" + SERVICE_HOST + \":\" + port);\n        inputStream = new McsInputStream(sslSocket.getInputStream(), rootHandler);\n        outputStream = new McsOutputStream(sslSocket.getOutputStream(), rootHandler);\n        inputStream.start();\n        outputStream.start();\n\n        startTimestamp = System.currentTimeMillis();\n        lastHeartbeatPingElapsedRealtime = SystemClock.elapsedRealtime();\n        lastHeartbeatAckElapsedRealtime = SystemClock.elapsedRealtime();\n        lastIncomingNetworkRealtime = SystemClock.elapsedRealtime();\n        scheduleHeartbeat(this);\n    }\n\n    private synchronized void connect() {\n        closeAll();\n\n        ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);\n        NetworkInfo activeNetworkInfo = cm.getActiveNetworkInfo();\n        activeNetworkPref = GcmPrefs.get(this).getNetworkPrefForInfo(activeNetworkInfo);\n        if (!GcmPrefs.get(this).isEnabledFor(activeNetworkInfo)) {\n            if (activeNetworkInfo != null) {\n                logd(this, \"Don't connect, because disabled for \" + activeNetworkInfo.getTypeName());\n            } else {\n                logd(this, \"Don't connect, no active network\");\n            }\n            scheduleReconnect(this);\n            return;\n        }\n\n        Exception exception = null;\n        for (int port : SERVICE_PORTS) {\n            try {\n                connect(port);\n                return;\n            } catch (Exception e) {\n                exception = e;\n                Log.w(TAG, \"Exception while connecting to \" + SERVICE_HOST + \":\" + port, e);\n                closeAll();\n            }\n        }\n\n        logd(this, \"Unable to connect to all different ports, retrying later\");\n        rootHandler.sendMessage(rootHandler.obtainMessage(MSG_TEARDOWN, exception));\n    }\n\n    private void handleClose(Close close) {\n        throw new RuntimeException(\"Server requested close!\");\n    }\n\n    private void handleLoginResponse(LoginResponse loginResponse) {\n        if (loginResponse.error == null) {\n            GcmPrefs.clearLastPersistedId(this);\n            logd(this, \"Logged in\");\n            notifyGcmConnected();\n            wakeLock.release();\n        } else {\n            throw new RuntimeException(\"Could not login: \" + loginResponse.error);\n        }\n    }\n\n    private void notifyGcmConnected() {\n        Intent intent = new Intent(ACTION_GCM_CONNECTED);\n        intent.setPackage(Constants.GMS_PACKAGE_NAME);\n        sendBroadcast(intent);\n    }\n\n    private void handleCloudMessage(DataMessageStanza message) {\n        if (message.persistent_id != null) {\n            GcmPrefs.get(this).extendLastPersistedId(this, message.persistent_id);\n        }\n        if (SELF_CATEGORY.equals(message.category)) {\n            handleSelfMessage(message);\n        } else {\n            handleAppMessage(message);\n        }\n    }\n\n    private void handleHeartbeatPing(HeartbeatPing ping) {\n        HeartbeatAck.Builder ack = new HeartbeatAck.Builder().status(ping.status);\n        if (inputStream.newStreamIdAvailable()) {\n            ack.last_stream_id_received(inputStream.getStreamId());\n        }\n        send(MCS_HEARTBEAT_ACK_TAG, ack.build());\n    }\n\n    private void handleHeartbeatAck(HeartbeatAck ack) {\n        GcmPrefs.get(this).learnReached(this, activeNetworkPref, SystemClock.elapsedRealtime() - lastIncomingNetworkRealtime);\n        lastHeartbeatAckElapsedRealtime = SystemClock.elapsedRealtime();\n        wakeLock.release();\n    }\n\n    private LoginRequest buildLoginRequest() {\n        LastCheckinInfo info = LastCheckinInfo.read(this);\n        return new LoginRequest.Builder()\n                .adaptive_heartbeat(false)\n                .auth_service(LoginRequest.AuthService.ANDROID_ID)\n                .auth_token(Long.toString(info.getSecurityToken()))\n                .id(\"android-\" + SDK_INT)\n                .domain(\"mcs.android.com\")\n                .device_id(\"android-\" + Long.toHexString(info.getAndroidId()))\n                .network_type(1)\n                .resource(Long.toString(info.getAndroidId()))\n                .user(Long.toString(info.getAndroidId()))\n                .use_rmq2(true)\n                .setting(Collections.singletonList(new Setting.Builder().name(\"new_vc\").value_(\"1\").build()))\n                .received_persistent_id(GcmPrefs.get(this).getLastPersistedIds())\n                .build();\n    }\n\n    private void handleAppMessage(DataMessageStanza msg) {\n        String packageName = msg.category;\n        database.noteAppMessage(packageName, DataMessageStanza.ADAPTER.encodedSize(msg));\n        GcmDatabase.App app = database.getApp(packageName);\n\n        Intent intent = new Intent();\n        intent.setAction(ACTION_C2DM_RECEIVE);\n        intent.putExtra(EXTRA_FROM, msg.from);\n        intent.putExtra(EXTRA_MESSAGE_ID, msg.id);\n        if (msg.sent != null && msg.sent != 0) intent.putExtra(EXTRA_SENT_TIME, msg.sent);\n        if (msg.ttl != null && msg.ttl != 0) intent.putExtra(EXTRA_TTL, msg.ttl);\n        if (msg.persistent_id != null) intent.putExtra(EXTRA_MESSAGE_ID, msg.persistent_id);\n        if (msg.token != null) intent.putExtra(EXTRA_COLLAPSE_KEY, msg.token);\n        if (msg.raw_data != null) {\n            intent.putExtra(EXTRA_RAWDATA_BASE64, Base64.encodeToString(msg.raw_data.toByteArray(), Base64.DEFAULT));\n            intent.putExtra(EXTRA_RAWDATA, msg.raw_data.toByteArray());\n        }\n        if (app.wakeForDelivery) {\n            intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);\n        } else {\n            intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);\n        }\n        for (AppData appData : msg.app_data) {\n            if (appData.key == null) continue;\n            String key = appData.key.toLowerCase(Locale.US);\n            // Some keys are exclusively set by the client and not the app.\n            if (key.equals(EXTRA_FROM) || (key.startsWith(\"google.\") && !key.startsWith(\"google.c.\"))) continue;\n            intent.putExtra(appData.key, appData.value_);\n        }\n\n        String receiverPermission = null;\n        try {\n            String name = packageName + \".permission.C2D_MESSAGE\";\n            PermissionInfo info = getPackageManager().getPermissionInfo(name, 0);\n            if (info.packageName.equals(packageName)) {\n                receiverPermission = name;\n            }\n        } catch (Exception ignored) {\n            // Keep null, no valid permission found\n        }\n\n        if (receiverPermission == null) {\n            // Without receiver permission, we only restrict by package name\n            if (app.wakeForDelivery) addPowerSaveTempWhitelistApp(packageName);\n            logd(this, \"Deliver message to all receivers in package \" + packageName);\n            intent.setPackage(packageName);\n            sendOrderedBroadcast(intent, null);\n        } else {\n            List<ResolveInfo> infos = getPackageManager().queryBroadcastReceivers(intent, PackageManager.GET_RESOLVED_FILTER);\n            if (infos == null || infos.isEmpty()) {\n                logd(this, \"No target for message, wut?\");\n            } else {\n                for (ResolveInfo resolveInfo : infos) {\n                    Intent targetIntent = new Intent(intent);\n                    targetIntent.setComponent(new ComponentName(resolveInfo.activityInfo.packageName, resolveInfo.activityInfo.name));\n                    if (resolveInfo.activityInfo.packageName.equals(packageName)) {\n                        if (app.wakeForDelivery) addPowerSaveTempWhitelistApp(packageName);\n                        // We don't need receiver permission for our own package\n                        logd(this, \"Deliver message to own receiver \" + resolveInfo);\n                        sendOrderedBroadcast(targetIntent, null);\n                    } else if (resolveInfo.filter.hasCategory(packageName)) {\n                        // Permission required\n                        logd(this, \"Deliver message to third-party receiver (with permission check)\" + resolveInfo);\n                        sendOrderedBroadcast(targetIntent, receiverPermission);\n                    }\n                }\n            }\n        }\n    }\n\n    private void addPowerSaveTempWhitelistApp(String packageName) {\n        if (SDK_INT >= 31) {\n            try {\n                if (addToTemporaryAllowListMethod != null && powerExemptionManager != null) {\n                    logd(this, \"Adding app \" + packageName + \" to the temp allowlist\");\n                    addToTemporaryAllowListMethod.invoke(powerExemptionManager, packageName, 0, \"GCM Push\", 10000);\n                }\n            } catch (Exception e) {\n                Log.e(TAG, \"Error adding app\" + packageName + \" to the temp allowlist.\", e);\n            }\n        } else if (SDK_INT >= 23) {\n            try {\n                if (getUserIdMethod != null && addPowerSaveTempWhitelistAppMethod != null && deviceIdleController != null) {\n                    int userId = (int) getUserIdMethod.invoke(null, getPackageManager().getApplicationInfo(packageName, 0).uid);\n                    logd(this, \"Adding app \" + packageName + \" for userId \" + userId + \" to the temp whitelist\");\n                    addPowerSaveTempWhitelistAppMethod.invoke(deviceIdleController, packageName, 10000, userId, \"GCM Push\");\n                }\n            } catch (Exception e) {\n                Log.w(TAG, e);\n            }\n        }\n    }\n\n    private void handleSelfMessage(DataMessageStanza msg) {\n        for (AppData appData : msg.app_data) {\n            if (IDLE_NOTIFICATION.equals(appData.key)) {\n                DataMessageStanza.Builder msgResponse = new DataMessageStanza.Builder()\n                        .id(Integer.toHexString(nextMessageId.incrementAndGet()))\n                        .from(FROM_FIELD)\n                        .sent(System.currentTimeMillis() / 1000)\n                        .ttl(0)\n                        .category(SELF_CATEGORY)\n                        .app_data(Collections.singletonList(new AppData.Builder().key(IDLE_NOTIFICATION).value_(\"false\").build()));\n                if (inputStream.newStreamIdAvailable()) {\n                    msgResponse.last_stream_id_received(inputStream.getStreamId());\n                }\n                send(MCS_DATA_MESSAGE_STANZA_TAG, msgResponse.build());\n            }\n        }\n    }\n\n    private void send(int type, Message message) {\n        rootHandler.sendMessage(rootHandler.obtainMessage(MSG_OUTPUT, type, 0, message));\n    }\n\n    private void sendOutputStream(int what, int arg, Object obj) {\n        McsOutputStream os = outputStream;\n        if (os != null && os.isAlive()) {\n            Handler outputHandler = os.getHandler();\n            if (outputHandler != null)\n                outputHandler.sendMessage(outputHandler.obtainMessage(what, arg, 0, obj));\n        }\n    }\n\n    @Override\n    public boolean handleMessage(android.os.Message msg) {\n        switch (msg.what) {\n            case MSG_INPUT:\n                handleInput(msg.arg1, (Message) msg.obj);\n                return true;\n            case MSG_OUTPUT:\n                sendOutputStream(MSG_OUTPUT, msg.arg1, msg.obj);\n                return true;\n            case MSG_INPUT_ERROR:\n            case MSG_OUTPUT_ERROR:\n                logd(this, \"I/O error: \" + msg.obj);\n                if (msg.obj instanceof SocketException) {\n                    SocketException e = (SocketException) msg.obj;\n                    if (\"Connection reset\".equals(e.getMessage())) {\n                        GcmPrefs.get(this).learnTimeout(this, activeNetworkPref);\n                    }\n                }\n                rootHandler.sendMessage(rootHandler.obtainMessage(MSG_TEARDOWN, msg.obj));\n                return true;\n            case MSG_TEARDOWN:\n                logd(this, \"Teardown initiated, reason: \" + msg.obj);\n                handleTeardown(msg);\n                return true;\n            case MSG_CONNECT:\n                logd(this, \"Connect initiated, reason: \" + msg.obj);\n                if (!isConnected(this)) {\n                    connect();\n                }\n                return true;\n            case MSG_HEARTBEAT:\n                logd(this, \"Heartbeat initiated, reason: \" + msg.obj);\n                if (isConnected(this)) {\n                    HeartbeatPing.Builder ping = new HeartbeatPing.Builder();\n                    if (inputStream.newStreamIdAvailable()) {\n                        ping.last_stream_id_received(inputStream.getStreamId());\n                    }\n                    send(MCS_HEARTBEAT_PING_TAG, ping.build());\n                    lastHeartbeatPingElapsedRealtime = SystemClock.elapsedRealtime();\n                    scheduleHeartbeat(this);\n                } else {\n                    logd(this, \"Ignoring heartbeat, not connected!\");\n                    scheduleReconnect(this);\n                }\n                return true;\n            case MSG_ACK:\n                logd(this, \"Ack initiated, reason: \" + msg.obj);\n                if (isConnected(this)) {\n                    IqStanza.Builder iq = new IqStanza.Builder()\n                            .type(IqStanza.IqType.SET)\n                            .id(\"\")\n                            .extension(new Extension.Builder().id(13).data_(ByteString.EMPTY).build()) // StreamAck\n                            .status(0L);\n                    if (inputStream.newStreamIdAvailable()) {\n                        iq.last_stream_id_received(inputStream.getStreamId());\n                    }\n                    send(MCS_IQ_STANZA_TAG, iq.build());\n                } else {\n                    logd(this, \"Ignoring ack, not connected!\");\n                }\n                return true;\n            case MSG_OUTPUT_READY:\n                logd(this, \"Sending login request...\");\n                send(MCS_LOGIN_REQUEST_TAG, buildLoginRequest());\n                return true;\n            case MSG_OUTPUT_DONE:\n                handleOutputDone(msg);\n                return true;\n        }\n        Log.w(TAG, \"Unknown message (\" + msg.what + \"): \" + msg);\n        return false;\n    }\n\n    private void handleOutputDone(android.os.Message msg) {\n        switch (msg.arg1) {\n            case MCS_HEARTBEAT_PING_TAG:\n                wakeLock.release();\n                break;\n            default:\n        }\n    }\n\n    private void handleInput(int type, Message message) {\n        try {\n            switch (type) {\n                case MCS_DATA_MESSAGE_STANZA_TAG:\n                    handleCloudMessage((DataMessageStanza) message);\n                    break;\n                case MCS_HEARTBEAT_PING_TAG:\n                    handleHeartbeatPing((HeartbeatPing) message);\n                    break;\n                case MCS_HEARTBEAT_ACK_TAG:\n                    handleHeartbeatAck((HeartbeatAck) message);\n                    break;\n                case MCS_CLOSE_TAG:\n                    handleClose((Close) message);\n                    break;\n                case MCS_LOGIN_RESPONSE_TAG:\n                    handleLoginResponse((LoginResponse) message);\n                    break;\n                default:\n                    Log.w(TAG, \"Unknown message: \" + message);\n            }\n            resetCurrentDelay();\n            lastIncomingNetworkRealtime = SystemClock.elapsedRealtime();\n        } catch (Exception e) {\n            Log.w(TAG, \"Exception when handling input: \" + message, e);\n            rootHandler.sendMessage(rootHandler.obtainMessage(MSG_TEARDOWN, e));\n        }\n    }\n\n    private static void tryClose(Closeable closeable) {\n        if (closeable != null) {\n            try {\n                closeable.close();\n            } catch (Exception ignored) {\n            }\n        }\n    }\n\n    private static void closeAll() {\n        logd(null, \"Closing all sockets...\");\n        tryClose(inputStream);\n        tryClose(outputStream);\n        if (sslSocket != null) {\n            try {\n                sslSocket.close();\n            } catch (Exception ignored) {\n            }\n        }\n    }\n\n    private void handleTeardown(android.os.Message msg) {\n        if (wasTornDown) {\n            // This can get called multiple times from different places via MSG_TEARDOWN\n            // this causes the reconnect delay to increase with each call to scheduleReconnect(),\n            // increasing the time we are disconnected.\n            logd(this, \"Was torn down already, not doing it again\");\n            return;\n        }\n        wasTornDown = true;\n        closeAll();\n\n        scheduleReconnect(this);\n\n        alarmManager.cancel(heartbeatIntent);\n        if (wakeLock != null) {\n            try {\n                wakeLock.release();\n            } catch (Exception ignored) {\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/gcm/PushRegisterManager.java",
    "content": "/*\n * Copyright (C) 2018 microG Project Team\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 org.microg.gms.gcm;\n\nimport android.content.Context;\nimport android.os.Bundle;\nimport android.util.Log;\n\nimport org.microg.gms.checkin.LastCheckinInfo;\nimport org.microg.gms.common.HttpFormClient;\nimport org.microg.gms.utils.ExtendedPackageInfo;\n\nimport java.io.IOException;\n\nimport static org.microg.gms.gcm.GcmConstants.ERROR_SERVICE_NOT_AVAILABLE;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_ERROR;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_REGISTRATION_ID;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_RETRY_AFTER;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_UNREGISTERED;\n\npublic class PushRegisterManager {\n    private static final String TAG = \"GmsGcmRegisterMgr\";\n\n    public static RegisterResponse unregister(Context context, String packageName, String pkgSignature, String sender, String info) {\n        GcmDatabase database = new GcmDatabase(context);\n        RegisterResponse response = new RegisterResponse();\n        try {\n            response = new RegisterRequest()\n                    .build(context)\n                    .sender(sender)\n                    .info(info)\n                    .checkin(LastCheckinInfo.read(context))\n                    .app(packageName, pkgSignature)\n                    .delete(true)\n                    .getResponse();\n        } catch (IOException e) {\n            Log.w(TAG, e);\n        }\n        if (!packageName.equals(response.deleted)) {\n            database.noteAppRegistrationError(packageName, response.responseText);\n        } else {\n            database.noteAppUnregistered(packageName, pkgSignature);\n        }\n        database.close();\n        return response;\n    }\n\n    public interface BundleCallback {\n        void onResult(Bundle bundle);\n    }\n\n    public static void completeRegisterRequest(Context context, GcmDatabase database, RegisterRequest request, BundleCallback callback) {\n        completeRegisterRequest(context, database, null, request, callback);\n    }\n\n    public static void completeRegisterRequest(Context context, GcmDatabase database, String requestId, RegisterRequest request, BundleCallback callback) {\n        if (request.app != null) {\n            ExtendedPackageInfo packageInfo = new ExtendedPackageInfo(context, request.app);\n            if (request.appVersion <= 0)\n                request.appVersion = packageInfo.getShortVersionCode();\n            if (!request.delete) {\n                if (request.appSignature == null) {\n                    request.appSignature = packageInfo.getFirstCertificateSha1Hex();\n                }\n                request.sdkVersion = packageInfo.getTargetSdkVersion();\n                if (!request.hasExtraParam(GcmConstants.EXTRA_APP_VERSION_NAME))\n                    request.extraParam(GcmConstants.EXTRA_APP_VERSION_NAME, packageInfo.getVersionName());\n            }\n        }\n\n        GcmDatabase.App app = database.getApp(request.app);\n        GcmPrefs prefs = GcmPrefs.get(context);\n        if (!request.delete) {\n            if (!prefs.isEnabled() ||\n                    (app != null && !app.allowRegister) ||\n                    LastCheckinInfo.read(context).getLastCheckin() <= 0 ||\n                    (app == null && prefs.getConfirmNewApps())) {\n                Bundle bundle = new Bundle();\n                bundle.putString(EXTRA_ERROR, ERROR_SERVICE_NOT_AVAILABLE);\n                callback.onResult(bundle);\n                return;\n            }\n        } else {\n            if (database.getRegistrationsByApp(request.app).isEmpty()) {\n                Bundle bundle = new Bundle();\n                bundle.putString(EXTRA_UNREGISTERED, attachRequestId(request.app, requestId));\n                callback.onResult(bundle);\n                return;\n            }\n        }\n\n        request.getResponseAsync(new HttpFormClient.Callback<RegisterResponse>() {\n            @Override\n            public void onResponse(RegisterResponse response) {\n                callback.onResult(handleResponse(database, request, response, requestId));\n            }\n\n            @Override\n            public void onException(Exception e) {\n                Log.w(TAG, e);\n                callback.onResult(handleResponse(database, request, e, requestId));\n            }\n        });\n    }\n\n\n\n    private static Bundle handleResponse(GcmDatabase database, RegisterRequest request, RegisterResponse response, String requestId) {\n        return handleResponse(database, request, response, null, requestId);\n    }\n\n    private static Bundle handleResponse(GcmDatabase database, RegisterRequest request, Exception e, String requestId) {\n        return handleResponse(database, request, null, e, requestId);\n    }\n\n    private static Bundle handleResponse(GcmDatabase database, RegisterRequest request, RegisterResponse response, Exception e, String requestId) {\n        Bundle resultBundle = new Bundle();\n        if (response == null && e == null) {\n            resultBundle.putString(EXTRA_ERROR, attachRequestId(ERROR_SERVICE_NOT_AVAILABLE, requestId));\n        } else if (e != null) {\n            if (e.getMessage() != null && e.getMessage().startsWith(\"Error=\")) {\n                String errorMessage = e.getMessage().substring(6);\n                database.noteAppRegistrationError(request.app, errorMessage);\n                resultBundle.putString(EXTRA_ERROR, attachRequestId(errorMessage, requestId));\n            } else {\n                resultBundle.putString(EXTRA_ERROR, attachRequestId(ERROR_SERVICE_NOT_AVAILABLE, requestId));\n            }\n        } else {\n            if (!request.delete) {\n                if (response.token == null) {\n                    database.noteAppRegistrationError(request.app, response.responseText);\n                    resultBundle.putString(EXTRA_ERROR, attachRequestId(ERROR_SERVICE_NOT_AVAILABLE, requestId));\n                } else {\n                    database.noteAppRegistered(request.app, request.appSignature, response.token);\n                    resultBundle.putString(EXTRA_REGISTRATION_ID, attachRequestId(response.token, requestId));\n                }\n            } else {\n                if (!request.app.equals(response.deleted) && !request.app.equals(response.token) && !request.sender.equals(response.token) && !\"\".equals(response.token)) {\n                    database.noteAppRegistrationError(request.app, response.responseText);\n                    resultBundle.putString(EXTRA_ERROR, attachRequestId(ERROR_SERVICE_NOT_AVAILABLE, requestId));\n                } else {\n                    database.noteAppUnregistered(request.app, request.appSignature);\n                    resultBundle.putString(EXTRA_UNREGISTERED, attachRequestId(request.app, requestId));\n                }\n            }\n\n            if (response.retryAfter != null && !response.retryAfter.contains(\":\")) {\n                resultBundle.putLong(EXTRA_RETRY_AFTER, Long.parseLong(response.retryAfter));\n            }\n        }\n        return resultBundle;\n    }\n\n    public static String attachRequestId(String msg, String requestId) {\n        if (requestId == null) return msg;\n        return \"|ID|\" + requestId + \"|\" + msg;\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/gcm/RegisterRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.gcm;\n\nimport android.content.Context;\nimport android.os.Bundle;\nimport android.text.TextUtils;\n\nimport org.microg.gms.checkin.LastCheckinInfo;\nimport org.microg.gms.common.HttpFormClient;\nimport org.microg.gms.profile.Build;\nimport org.microg.gms.profile.ProfileManager;\n\nimport java.io.IOException;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport static org.microg.gms.common.HttpFormClient.RequestContent;\nimport static org.microg.gms.common.HttpFormClient.RequestContentDynamic;\nimport static org.microg.gms.common.HttpFormClient.RequestHeader;\n\npublic class RegisterRequest extends HttpFormClient.Request {\n    private static final String SERVICE_URL = \"https://android.clients.google.com/c2dm/register3\";\n    private static final String USER_AGENT = \"Android-GCM/1.5 (%s %s)\";\n\n    @RequestHeader(\"Authorization\")\n    private String auth;\n    @RequestHeader(\"User-Agent\")\n    private String userAgent;\n\n    @RequestHeader(\"app\")\n    @RequestContent(\"app\")\n    public String app;\n    @RequestContent(\"cert\")\n    public String appSignature;\n    @RequestContent(\"app_ver\")\n    public int appVersion;\n    @RequestContent(\"info\")\n    public String info;\n    @RequestContent(\"sender\")\n    public String sender;\n    @RequestContent(\"device\")\n    public long androidId;\n    @RequestContent(\"delete\")\n    public boolean delete;\n    public long securityToken;\n    public String deviceName;\n    public String buildVersion;\n    @RequestContent(\"target_ver\")\n    public Integer sdkVersion;\n    @RequestContentDynamic\n    private Map<String, String> extraParams = new LinkedHashMap<>();\n\n    @Override\n    public void prepare() {\n        userAgent = String.format(USER_AGENT, deviceName, buildVersion);\n        auth = \"AidLogin \" + androidId + \":\" + securityToken;\n    }\n\n    public RegisterRequest checkin(LastCheckinInfo lastCheckinInfo) {\n        androidId = lastCheckinInfo.getAndroidId();\n        securityToken = lastCheckinInfo.getSecurityToken();\n        return this;\n    }\n\n    public RegisterRequest app(String app) {\n        this.app = app;\n        return this;\n    }\n\n    public RegisterRequest app(String app, String appSignature) {\n        this.app = app;\n        this.appSignature = appSignature;\n        return this;\n    }\n\n    public RegisterRequest app(String app, String appSignature, int appVersion) {\n        this.app = app;\n        this.appSignature = appSignature;\n        this.appVersion = appVersion;\n        return this;\n    }\n\n    public RegisterRequest info(String info) {\n        this.info = info;\n        return this;\n    }\n\n    public RegisterRequest sender(String sender) {\n        this.sender = sender;\n        return this;\n    }\n\n    public RegisterRequest build(Context context) {\n        ProfileManager.ensureInitialized(context);\n        deviceName = Build.DEVICE;\n        buildVersion = Build.ID;\n        return this;\n    }\n\n    public RegisterRequest delete() {\n        return delete(true);\n    }\n\n    public RegisterRequest delete(boolean delete) {\n        this.delete = delete;\n        return this;\n    }\n\n    public RegisterRequest extraParams(Bundle extraBundle) {\n        for (String key : extraBundle.keySet()) {\n            if (!key.equals(GcmConstants.EXTRA_SENDER) && !key.equals(GcmConstants.EXTRA_DELETE) && !key.equals(GcmConstants.EXTRA_APP)) {\n                extraParam(key, extraBundle.getString(key));\n            }\n        }\n        return this;\n    }\n\n    public RegisterRequest extraParam(String key, String value) {\n        // Ignore empty registration extras\n        if (!TextUtils.isEmpty(value)) {\n            extraParams.put(extraParamKey(key), value);\n        }\n        return this;\n    }\n\n    public boolean hasExtraParam(String key) {\n        return extraParams.containsKey(extraParamKey(key));\n    }\n\n    private static String extraParamKey(String key) {\n        return \"X-\" + key;\n    }\n\n    public RegisterResponse getResponse() throws IOException {\n        return HttpFormClient.request(SERVICE_URL, this, RegisterResponse.class);\n    }\n\n    public void getResponseAsync(HttpFormClient.Callback<RegisterResponse> callback) {\n        HttpFormClient.requestAsync(SERVICE_URL, this, RegisterResponse.class, callback);\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/gcm/RegisterResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.gcm;\n\nimport org.microg.gms.common.HttpFormClient.ResponseHeader;\nimport org.microg.gms.common.HttpFormClient.ResponseStatusText;\n\nimport static org.microg.gms.common.HttpFormClient.ResponseField;\n\npublic class RegisterResponse {\n    @ResponseField(\"token\")\n    public String token;\n    @ResponseHeader(\"Retry-After\")\n    public String retryAfter;\n    @ResponseField(\"deleted\")\n    public String deleted;\n    @ResponseStatusText\n    public String responseText;\n\n    @Override\n    public String toString() {\n        return \"RegisterResponse{\" +\n                \"token='\" + token + '\\'' +\n                \", retryAfter='\" + retryAfter + '\\'' +\n                \", deleted='\" + deleted + '\\'' +\n                '}';\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/gcm/SendReceiver.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.gcm;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.util.Log;\n\nimport androidx.legacy.content.WakefulBroadcastReceiver;\n\nimport static org.microg.gms.gcm.McsConstants.ACTION_SEND;\n\npublic class SendReceiver extends WakefulBroadcastReceiver {\n    @Override\n    public void onReceive(Context context, Intent intent) {\n        if (intent.getExtras() == null) return;\n        Bundle extras = intent.getExtras();\n        Log.d(\"GmsMcsSendRcvr\", \"original extras: \" + extras);\n        for (String key : extras.keySet()) {\n            if (key.startsWith(\"GOOG.\") || key.startsWith(\"GOOGLE.\")) {\n                extras.remove(key);\n            }\n        }\n        Intent i = new Intent(context, McsService.class);\n        i.setAction(ACTION_SEND);\n        i.putExtras(extras);\n        startWakefulService(context, i);\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/gcm/TriggerReceiver.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.gcm;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.net.ConnectivityManager;\nimport android.net.NetworkInfo;\nimport android.util.Log;\n\nimport androidx.legacy.content.WakefulBroadcastReceiver;\n\nimport org.microg.gms.checkin.CheckinPreferences;\nimport org.microg.gms.checkin.LastCheckinInfo;\nimport org.microg.gms.common.ForegroundServiceContext;\n\nimport static android.os.Build.VERSION.SDK_INT;\nimport static org.microg.gms.gcm.McsConstants.ACTION_CONNECT;\nimport static org.microg.gms.gcm.McsConstants.ACTION_HEARTBEAT;\nimport static org.microg.gms.gcm.McsConstants.EXTRA_REASON;\n\npublic class TriggerReceiver extends WakefulBroadcastReceiver {\n    private static final String TAG = \"GmsGcmTrigger\";\n    public static final String FORCE_TRY_RECONNECT = \"org.microg.gms.gcm.FORCE_TRY_RECONNECT\";\n    private static boolean registered = false;\n\n    /**\n     * \"Project Svelte\" is just there to f**k things up...\n     */\n    public synchronized static void register(Context context) {\n        if (SDK_INT >= 24 && !registered) {\n            IntentFilter intentFilter = new IntentFilter(\"android.net.conn.CONNECTIVITY_CHANGE\");\n            context.getApplicationContext().registerReceiver(new TriggerReceiver(), intentFilter);\n            registered = true;\n        }\n    }\n\n    @Override\n    public void onReceive(Context context, Intent intent) {\n        try {\n            boolean force = \"android.provider.Telephony.SECRET_CODE\".equals(intent.getAction()) || FORCE_TRY_RECONNECT.equals(intent.getAction());\n            ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);\n\n            if (!GcmPrefs.get(context).isEnabled() && !force) {\n                Log.d(TAG, \"Ignoring \" + intent + \": gcm is disabled\");\n                return;\n            }\n\n            if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {\n                McsService.resetCurrentDelay();\n            }\n\n            if (LastCheckinInfo.read(context).getAndroidId() == 0) {\n                Log.d(TAG, \"Ignoring \" + intent + \": need to checkin first.\");\n                if (CheckinPreferences.isEnabled(context)) {\n                    // Do a check-in if we are not actually checked in,\n                    // but should be, e.g. cleared app data\n                    Log.d(TAG, \"Requesting check-in...\");\n                    String action = \"android.server.checkin.CHECKIN\";\n                    Class<?> clazz = org.microg.gms.checkin.TriggerReceiver.class;\n                    context.sendBroadcast(new Intent(action, null, context, clazz));\n                }\n                return;\n            }\n\n            force |= \"android.intent.action.BOOT_COMPLETED\".equals(intent.getAction());\n\n            NetworkInfo networkInfo = cm.getActiveNetworkInfo();\n\n            if (!force) {\n                if (networkInfo == null || !networkInfo.isConnected()) {\n                    Log.d(TAG, \"Ignoring \" + intent + \": network is offline, scheduling new attempt.\");\n                    McsService.scheduleReconnect(context);\n                    return;\n                } else if (!GcmPrefs.get(context).isEnabledFor(networkInfo)) {\n                    Log.d(TAG, \"Ignoring \" + intent + \": gcm is disabled for \" + networkInfo.getTypeName());\n                    return;\n                }\n            }\n\n            if (!McsService.isConnected(context) || force) {\n                Log.d(TAG, \"Not connected to GCM but should be, asking the service to start up. Triggered by: \" + intent);\n                startWakefulService(new ForegroundServiceContext(context), new Intent(ACTION_CONNECT, null, context, McsService.class)\n                        .putExtra(EXTRA_REASON, intent));\n            } else {\n                if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {\n                    Log.d(TAG, \"Ignoring \" + intent + \": service is running. schedule reconnect instead.\");\n                    McsService.scheduleReconnect(context);\n                } else {\n                    Log.d(TAG, \"Ignoring \" + intent + \": service is running. heartbeat instead.\");\n                    startWakefulService(new ForegroundServiceContext(context), new Intent(ACTION_HEARTBEAT, null, context, McsService.class)\n                            .putExtra(EXTRA_REASON, intent));\n                }\n            }\n        } catch (Exception e) {\n            Log.w(TAG, e);\n        }\n    }\n\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/gservices/DatabaseHelper.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.gservices;\n\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.database.sqlite.SQLiteDatabase;\nimport android.database.sqlite.SQLiteOpenHelper;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class DatabaseHelper extends SQLiteOpenHelper {\n    private static final int DB_VERSION = 3;\n    private static final int DB_VERSION_OLD = 1;\n    public static final String DB_NAME = \"gservices.db\";\n\n    public DatabaseHelper(Context context) {\n        super(context, DB_NAME, null, DB_VERSION);\n    }\n\n    @Override\n    public void onCreate(SQLiteDatabase db) {\n        db.execSQL(\"CREATE TABLE main (name TEXT PRIMARY KEY, value TEXT)\");\n        db.execSQL(\"CREATE TABLE overrides (name TEXT PRIMARY KEY, value TEXT)\");\n        db.execSQL(\"CREATE TABLE saved_system (name TEXT PRIMARY KEY, value TEXT)\");\n        db.execSQL(\"CREATE TABLE saved_secure (name TEXT PRIMARY KEY, value TEXT)\");\n    }\n\n    @Override\n    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {\n        if (oldVersion == DB_VERSION_OLD) {\n            db.execSQL(\"DROP TABLE IF EXISTS main\");\n            db.execSQL(\"DROP TABLE IF EXISTS overrides\");\n            onCreate(db);\n        }\n        db.setVersion(newVersion);\n    }\n\n    public String get(String name) {\n        String result = null;\n        Cursor cursor = getReadableDatabase().query(\"overrides\", new String[]{\"value\"}, \"name=?\",\n                new String[]{name}, null, null, null, null);\n        if (cursor != null) {\n            if (cursor.moveToNext()) {\n                result = cursor.getString(0);\n            }\n            cursor.close();\n        }\n        if (result != null) return result;\n        cursor = getReadableDatabase().query(\"main\", new String[]{\"value\"}, \"name=?\",\n                new String[]{name}, null, null, null, null);\n        if (cursor != null) {\n            if (cursor.moveToNext()) {\n                result = cursor.getString(0);\n            }\n            cursor.close();\n        }\n        return result;\n    }\n\n    public Map<String, String> search(String search) {\n        Map<String, String> map = new HashMap<String, String>();\n        Cursor cursor = getReadableDatabase().query(\"overrides\", new String[]{\"name\", \"value\"},\n                \"name LIKE ?\", new String[]{search}, null, null, null, null);\n        if (cursor != null) {\n            while (cursor.moveToNext()) {\n                map.put(cursor.getString(0), cursor.getString(1));\n            }\n            cursor.close();\n        }\n        cursor = getReadableDatabase().query(\"main\", new String[]{\"name\", \"value\"},\n                \"name LIKE ?\", new String[]{search}, null, null, null, null);\n        if (cursor != null) {\n            if (cursor.moveToNext()) {\n                if (!map.containsKey(cursor.getString(0)))\n                    map.put(cursor.getString(0), cursor.getString(1));\n            }\n            cursor.close();\n        }\n        return map;\n\n    }\n\n    public void put(String table, ContentValues values) {\n        getWritableDatabase().insertWithOnConflict(table, null, values, SQLiteDatabase.CONFLICT_REPLACE);\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/gservices/GServices.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.gservices;\n\nimport android.content.ContentResolver;\nimport android.content.ContentValues;\nimport android.database.Cursor;\nimport android.net.Uri;\n\npublic class GServices {\n    public static final Uri CONTENT_URI = Uri.parse(\"content://com.google.android.gsf.gservices\");\n    public static final Uri MAIN_URI = Uri.parse(\"content://com.google.android.gsf.gservices/main\");\n    public static final Uri OVERRIDE_URI = Uri.parse(\"content://com.google.android.gsf.gservices/override\");\n\n    public static int setString(ContentResolver resolver, String key, String value) {\n        ContentValues values = new ContentValues();\n        values.put(\"name\", key);\n        values.put(\"value\", value);\n        return resolver.update(MAIN_URI, values, null, null);\n    }\n\n    public static String getString(ContentResolver resolver, String key) {\n        return getString(resolver, key, null);\n    }\n\n    public static String getString(ContentResolver resolver, String key, String defaultValue) {\n        String result = defaultValue;\n        Cursor cursor = resolver.query(CONTENT_URI, null, null, new String[]{key}, null);\n        if (cursor != null) {\n            if (cursor.moveToNext()) {\n                result = cursor.getString(1);\n            }\n            cursor.close();\n        }\n        return result;\n    }\n\n    public static int getInt(ContentResolver resolver, String key, int defaultValue) {\n        String result = getString(resolver, key);\n        if (result != null) {\n            try {\n                return Integer.parseInt(result);\n            } catch (NumberFormatException ignored) {\n            }\n        }\n        return defaultValue;\n    }\n\n    public static long getLong(ContentResolver resolver, String key, long defaultValue) {\n        String result = getString(resolver, key);\n        if (result != null) {\n            try {\n                return Long.parseLong(result);\n            } catch (NumberFormatException ignored) {\n            }\n        }\n        return defaultValue;\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/gservices/GServicesProvider.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.gservices;\n\nimport android.content.ContentProvider;\nimport android.content.ContentValues;\nimport android.database.Cursor;\nimport android.database.MatrixCursor;\nimport android.net.Uri;\nimport android.util.Log;\n\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.Set;\n\nimport static android.os.Build.VERSION.SDK_INT;\n\n/**\n * Originally found in Google Services Framework (com.google.android.gsf), this provides a generic\n * key-value store, that is written by the checkin service and read from various Google Apps.\n * <p/>\n * Google uses the checkin process to store various device or country specific settings and\n * if certain \"experiments\" are enabled on the device.\n */\npublic class GServicesProvider extends ContentProvider {\n    public static final Uri CONTENT_URI = Uri.parse(\"content://com.google.android.gsf.gservices/\");\n    public static final Uri MAIN_URI = Uri.withAppendedPath(CONTENT_URI, \"main\");\n    public static final Uri OVERRIDE_URI = Uri.withAppendedPath(CONTENT_URI, \"override\");\n    public static final Uri PREFIX_URI = Uri.withAppendedPath(CONTENT_URI, \"prefix\");\n\n    private static final String TAG = \"GmsServicesProvider\";\n\n    private DatabaseHelper databaseHelper;\n    private Map<String, String> cache = new HashMap<String, String>();\n    private Set<String> cachedPrefixes = new HashSet<String>();\n\n    @Override\n    public boolean onCreate() {\n        databaseHelper = new DatabaseHelper(getContext());\n        return true;\n    }\n\n    private String getCallingPackageName() {\n        if (SDK_INT >= 19) {\n            return getCallingPackage();\n        } else {\n            return \"unknown\";\n        }\n    }\n\n    @Override\n    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {\n        MatrixCursor cursor = new MatrixCursor(new String[]{\"name\", \"value\"});\n        if (PREFIX_URI.equals(uri)) {\n            for (String prefix : selectionArgs) {\n                if (!cachedPrefixes.contains(prefix)) {\n                    cache.putAll(databaseHelper.search(prefix + \"%\"));\n                    cachedPrefixes.add(prefix);\n                }\n\n                for (String name : cache.keySet()) {\n                    if (name.startsWith(prefix)) {\n                        String value = cache.get(name);\n                        if (value != null) {\n                            cursor.addRow(new String[]{name, value});\n                        }\n                    }\n                }\n            }\n        } else {\n            for (String name : selectionArgs) {\n                String value;\n                if (cache.containsKey(name)) {\n                    value = cache.get(name);\n                } else {\n                    value = databaseHelper.get(name);\n                    cache.put(name, value);\n                }\n                if (value != null) {\n                    cursor.addRow(new String[]{name, value});\n                }\n            }\n        }\n        if (cursor.getCount() == 0) return null;\n        return cursor;\n    }\n\n    @Override\n    public String getType(Uri uri) {\n        return null;\n    }\n\n    @Override\n    public Uri insert(Uri uri, ContentValues values) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public int delete(Uri uri, String selection, String[] selectionArgs) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {\n        Log.d(TAG, \"update caller=\" + getCallingPackageName() + \" table=\" + uri.getLastPathSegment()\n                + \" name=\" + values.getAsString(\"name\") + \" value=\" + values.getAsString(\"value\"));\n        if (uri.equals(MAIN_URI)) {\n            databaseHelper.put(\"main\", values);\n        } else if (uri.equals(OVERRIDE_URI)) {\n            databaseHelper.put(\"override\", values);\n        }\n        String name = values.getAsString(\"name\");\n        cache.remove(name);\n        Iterator<String> iterator = cachedPrefixes.iterator();\n        while (iterator.hasNext()) if (name.startsWith(iterator.next())) iterator.remove();\n        return 1;\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/icing/AppDataSearchImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.icing;\n\nimport android.os.Parcel;\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport com.google.android.gms.appdatasearch.CorpusStatus;\nimport com.google.android.gms.appdatasearch.PIMEUpdateResponse;\nimport com.google.android.gms.appdatasearch.RequestIndexingSpecification;\nimport com.google.android.gms.appdatasearch.SuggestSpecification;\nimport com.google.android.gms.appdatasearch.SuggestionResults;\nimport com.google.android.gms.appdatasearch.internal.IAppDataSearch;\n\npublic class AppDataSearchImpl extends IAppDataSearch.Stub {\n    private static final String TAG = \"GmsIcingAppDataImpl\";\n\n    @Override\n    public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {\n        if (super.onTransact(code, data, reply, flags)) return true;\n        Log.d(TAG, \"onTransact [unknown]: \" + code + \", \" + data + \", \" + flags);\n        return false;\n    }\n\n    @Override\n    public SuggestionResults getSuggestions(String var1, String packageName, String[] accounts, int maxNum, SuggestSpecification specs) throws RemoteException {\n        return new SuggestionResults(\"Unknown error\");\n    }\n\n    @Override\n    public boolean requestIndexing(String packageName, String accountName, long l, RequestIndexingSpecification specs) throws RemoteException {\n        Log.d(TAG, \"requestIndexing: \" + accountName + \" @ \" + packageName + \", \" + l);\n        return true;\n    }\n\n    @Override\n    public CorpusStatus getStatus(String packageName, String accountName) throws RemoteException {\n        Log.d(TAG, \"getStatus: \" + accountName + \" @ \" + packageName);\n        CorpusStatus status = new CorpusStatus();\n        status.found = true;\n        return status;\n    }\n\n    @Override\n    public PIMEUpdateResponse requestPIMEUpdate(String s1, String s2, int i, byte[] bs) throws RemoteException {\n        Log.d(TAG, \"requestPIMEUpdate: \" + s1 + \", \" + s2 + \", \" + i + \", \" + (bs == null ? \"null\" : new String(bs)));\n        return new PIMEUpdateResponse();\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/icing/GlobalSearchAdminImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.icing;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.search.global.GetCurrentExperimentIdsRequest;\nimport com.google.android.gms.search.global.GetCurrentExperimentIdsResponse;\nimport com.google.android.gms.search.global.GetGlobalSearchSourcesRequest;\nimport com.google.android.gms.search.global.GetGlobalSearchSourcesResponse;\nimport com.google.android.gms.search.global.GetPendingExperimentIdsRequest;\nimport com.google.android.gms.search.global.GetPendingExperimentIdsResponse;\nimport com.google.android.gms.search.global.SetExperimentIdsRequest;\nimport com.google.android.gms.search.global.SetExperimentIdsResponse;\nimport com.google.android.gms.search.global.SetIncludeInGlobalSearchRequest;\nimport com.google.android.gms.search.global.SetIncludeInGlobalSearchResponse;\nimport com.google.android.gms.search.global.internal.IGlobalSearchAdminCallbacks;\nimport com.google.android.gms.search.global.internal.IGlobalSearchAdminService;\n\npublic class GlobalSearchAdminImpl extends IGlobalSearchAdminService.Stub {\n    private static final String TAG = \"GmsIcingGlobalImpl\";\n\n    @Override\n    public void getGlobalSearchSources(GetGlobalSearchSourcesRequest request, IGlobalSearchAdminCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"getGlobalSearchSources: \" + request);\n        callbacks.onGetGlobalSearchSourcesResponse(new GetGlobalSearchSourcesResponse(Status.SUCCESS, new Parcelable[0]));\n    }\n\n    @Override\n    public void setExperimentIds(SetExperimentIdsRequest request, IGlobalSearchAdminCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"setExperimentIds: \" + request);\n        callbacks.onSetExperimentIdsResponse(new SetExperimentIdsResponse(Status.SUCCESS));\n    }\n\n    @Override\n    public void getCurrentExperimentIds(GetCurrentExperimentIdsRequest request, IGlobalSearchAdminCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"getCurrentExperimentIds: \" + request);\n        callbacks.onGetCurrentExperimentIdsResponse(new GetCurrentExperimentIdsResponse(Status.SUCCESS, new int[0]));\n    }\n\n    @Override\n    public void getPendingExperimentIds(GetPendingExperimentIdsRequest request, IGlobalSearchAdminCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"getPendingExperimentIds: \" + request);\n        callbacks.onGetPendingExperimentIdsResponse(new GetPendingExperimentIdsResponse(Status.SUCCESS, new int[0]));\n    }\n\n    @Override\n    public void setIncludeInGlobalSearch(SetIncludeInGlobalSearchRequest request, IGlobalSearchAdminCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"setIncludeInGlobalSearch: \" + request);\n        callbacks.onSetIncludeInGlobalSearchResponse(new SetIncludeInGlobalSearchResponse(Status.SUCCESS));\n    }\n\n    @Override\n    public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {\n        if (super.onTransact(code, data, reply, flags)) return true;\n        Log.d(TAG, \"onTransact [unknown]: \" + code + \", \" + data + \", \" + flags);\n        return false;\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/icing/IndexService.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.icing;\n\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport com.google.android.gms.common.api.CommonStatusCodes;\nimport com.google.android.gms.common.internal.GetServiceRequest;\nimport com.google.android.gms.common.internal.IGmsCallbacks;\n\nimport org.microg.gms.BaseService;\nimport org.microg.gms.common.GmsService;\n\npublic class IndexService extends BaseService {\n    private AppDataSearchImpl appDataSearch = new AppDataSearchImpl();\n    private GlobalSearchAdminImpl globalSearchAdmin = new GlobalSearchAdminImpl();\n    private SearchCorporaImpl searchCorpora = new SearchCorporaImpl();\n    private SearchQueriesImpl searchQueries = new SearchQueriesImpl();\n\n    public IndexService() {\n        super(\"GmsIcingIndexSvc\",\n                GmsService.APP_DATA_SEARCH, GmsService.SEARCH_ADMINISTRATION, GmsService.SEARCH_CORPORA,\n                GmsService.GLOBAL_SEARCH_ADMIN, GmsService.IME_UPDATES, GmsService.SEARCH_QUERIES);\n    }\n\n    @Override\n    public void handleServiceRequest(IGmsCallbacks callback, GetServiceRequest request, GmsService service) throws RemoteException {\n        switch (service) {\n            case APP_DATA_SEARCH:\n                callback.onPostInitComplete(0, appDataSearch.asBinder(), null);\n                break;\n            case SEARCH_ADMINISTRATION:\n                Log.w(TAG, \"Service not yet implemented: \" + service);\n                callback.onPostInitComplete(CommonStatusCodes.ERROR, null, null);\n                break;\n            case SEARCH_QUERIES:\n                callback.onPostInitComplete(0, searchQueries.asBinder(), null);\n                break;\n            case GLOBAL_SEARCH_ADMIN:\n                callback.onPostInitComplete(0, globalSearchAdmin.asBinder(), null);\n                break;\n            case SEARCH_CORPORA:\n                callback.onPostInitComplete(0, searchCorpora.asBinder(), null);\n                break;\n            case IME_UPDATES:\n                Log.w(TAG, \"Service not yet implemented: \" + service);\n                callback.onPostInitComplete(CommonStatusCodes.ERROR, null, null);\n                break;\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/icing/LightweightAppDataSearchImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.icing;\n\nimport android.os.Parcel;\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport com.google.android.gms.appdatasearch.UsageInfo;\nimport com.google.android.gms.appdatasearch.internal.ILightweightAppDataSearch;\nimport com.google.android.gms.appdatasearch.internal.ILightweightAppDataSearchCallbacks;\n\nimport java.util.Arrays;\n\npublic class LightweightAppDataSearchImpl extends ILightweightAppDataSearch.Stub {\n    private static final String TAG = \"GmsIcingLightSearchImpl\";\n\n    public void view(ILightweightAppDataSearchCallbacks callbacks, String packageName, UsageInfo[] usageInfos) {\n        Log.d(TAG, \"view: \" + Arrays.toString(usageInfos));\n    }\n\n    @Override\n    public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {\n        if (super.onTransact(code, data, reply, flags)) return true;\n        Log.d(TAG, \"onTransact [unknown]: \" + code + \", \" + data + \", \" + flags);\n        return false;\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/icing/LightweightIndexService.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.icing;\n\nimport android.os.RemoteException;\n\nimport com.google.android.gms.common.internal.GetServiceRequest;\nimport com.google.android.gms.common.internal.IGmsCallbacks;\n\nimport org.microg.gms.BaseService;\nimport org.microg.gms.common.GmsService;\n\npublic class LightweightIndexService extends BaseService {\n    private LightweightAppDataSearchImpl appDataSearch = new LightweightAppDataSearchImpl();\n\n    public LightweightIndexService() {\n        super(\"GmsIcingLightIndexSvc\", GmsService.LIGHT_INDEX);\n    }\n\n    @Override\n    public void handleServiceRequest(IGmsCallbacks callback, GetServiceRequest request, GmsService service) throws RemoteException {\n        callback.onPostInitComplete(0, appDataSearch.asBinder(), null);\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/icing/SearchCorporaImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.icing;\n\nimport android.os.Parcel;\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport com.google.android.gms.appdatasearch.CorpusStatus;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.search.corpora.ClearCorpusRequest;\nimport com.google.android.gms.search.corpora.GetCorpusInfoRequest;\nimport com.google.android.gms.search.corpora.GetCorpusStatusRequest;\nimport com.google.android.gms.search.corpora.GetCorpusStatusResponse;\nimport com.google.android.gms.search.corpora.RequestIndexingRequest;\nimport com.google.android.gms.search.corpora.RequestIndexingResponse;\nimport com.google.android.gms.search.corpora.internal.ISearchCorporaCallbacks;\nimport com.google.android.gms.search.corpora.internal.ISearchCorporaService;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class SearchCorporaImpl extends ISearchCorporaService.Stub {\n    private static final String TAG = \"GmsIcingCorporaImpl\";\n\n    // We count the sequence number here to make clients happy.\n    private Map<String, Long> corpusSequenceNumbers = new HashMap<String, Long>();\n\n    @Override\n    public void requestIndexing(RequestIndexingRequest request, ISearchCorporaCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"requestIndexing: \" + request);\n        corpusSequenceNumbers.put(request.packageName + \"/\" + request.corpus, request.sequenceNumber);\n        callbacks.onRequestIndexing(new RequestIndexingResponse(Status.SUCCESS, true));\n    }\n\n    @Override\n    public void clearCorpus(ClearCorpusRequest request, ISearchCorporaCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"clearCorpus\");\n    }\n\n    @Override\n    public void getCorpusStatus(GetCorpusStatusRequest request, ISearchCorporaCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"getCorpusStatus: \" + request);\n        CorpusStatus status = new CorpusStatus();\n        String numIndex = request.packageName + \"/\" + request.corpus;\n        if (corpusSequenceNumbers.containsKey(numIndex)) {\n            status.found = true;\n            status.lastIndexedSeqno = corpusSequenceNumbers.get(numIndex);\n            status.lastCommittedSeqno = status.lastIndexedSeqno;\n        }\n        callbacks.onGetCorpusStatus(new GetCorpusStatusResponse(Status.SUCCESS, status));\n    }\n\n    @Override\n    public void getCorpusInfo(GetCorpusInfoRequest request, ISearchCorporaCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"getCorpusInfo\");\n    }\n\n    @Override\n    public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {\n        if (super.onTransact(code, data, reply, flags)) return true;\n        Log.d(TAG, \"onTransact [unknown]: \" + code + \", \" + data + \", \" + flags);\n        return false;\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/icing/SearchQueriesImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.icing;\n\nimport android.os.Parcel;\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.search.queries.QueryRequest;\nimport com.google.android.gms.search.queries.QueryResponse;\nimport com.google.android.gms.search.queries.internal.ISearchQueriesCallbacks;\nimport com.google.android.gms.search.queries.internal.ISearchQueriesService;\n\npublic class SearchQueriesImpl extends ISearchQueriesService.Stub {\n    private static final String TAG = \"GmsIcingQueriesImpl\";\n\n    @Override\n    public void query(QueryRequest request, ISearchQueriesCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"query: \" + request);\n        callbacks.onQuery(new QueryResponse(Status.CANCELED, null));\n    }\n\n    @Override\n    public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {\n        if (super.onTransact(code, data, reply, flags)) return true;\n        Log.d(TAG, \"onTransact [unknown]: \" + code + \", \" + data + \", \" + flags);\n        return false;\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/location/LocationConstants.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.location;\n\npublic class LocationConstants {\n    public static final String KEY_MOCK_LOCATION = \"mockLocation\";\n\n    // Place picker client->service\n    public static final String EXTRA_PRIMARY_COLOR = \"primary_color\";\n    public static final String EXTRA_PRIMARY_COLOR_DARK = \"primary_color_dark\";\n    public static final String EXTRA_CLIENT_VERSION = \"gmscore_client_jar_version\";\n    public static final String EXTRA_BOUNDS = \"latlng_bounds\";\n\n    // Place picker service->client\n    public static final String EXTRA_ATTRIBUTION = \"third_party_attributions\";\n    public static final String EXTRA_FINAL_BOUNDS = \"final_latlng_bounds\";\n    public static final String EXTRA_PLACE = \"selected_place\";\n    public static final String EXTRA_STATUS = \"status\";\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/mdm/NetworkQualityService.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.mdm;\n\nimport android.app.Service;\nimport android.content.Intent;\nimport android.os.IBinder;\nimport android.util.Log;\n\npublic class NetworkQualityService extends Service {\n    private static final String TAG = \"GmsMdmQualitySvc\";\n\n    @Override\n    public IBinder onBind(Intent intent) {\n        Log.d(TAG, \"onBind: \" + intent);\n        return null;\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/people/ContactSyncService.java",
    "content": "/*\n * Copyright (C) 2017 microG Project Team\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 org.microg.gms.people;\n\nimport android.accounts.Account;\nimport android.app.Service;\nimport android.content.AbstractThreadedSyncAdapter;\nimport android.content.ContentProviderClient;\nimport android.content.Intent;\nimport android.content.SyncResult;\nimport android.os.Bundle;\nimport android.os.IBinder;\nimport android.util.Log;\n\nimport androidx.annotation.Nullable;\n\npublic class ContactSyncService extends Service {\n    private static final String TAG = \"GmsContactSync\";\n\n    @Nullable\n    @Override\n    public IBinder onBind(Intent intent) {\n        return (new AbstractThreadedSyncAdapter(this, true) {\n            @Override\n            public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {\n                Log.d(TAG, \"unimplemented Method: onPerformSync\");\n            }\n        }).getSyncAdapterBinder();\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/people/DatabaseHelper.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.people;\n\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.database.sqlite.SQLiteDatabase;\nimport android.database.sqlite.SQLiteOpenHelper;\n\nimport java.util.Set;\n\npublic class DatabaseHelper extends SQLiteOpenHelper {\n    private static final int DB_VERSION = 5;\n    private static final String DB_NAME = \"pluscontacts.db\";\n    private static final String CREATE_OWNERS = \"CREATE TABLE owners (\" +\n            \"_id INTEGER PRIMARY KEY AUTOINCREMENT,\" +\n            \"account_name TEXT NOT NULL UNIQUE,\" + // example@gmail.com\n            \"gaia_id TEXT,\" + // 123456789123456789123\n            \"page_gaia_id TEXT,\" +\n            \"display_name TEXT,\" + // firstName lastName\n            \"avatar TEXT,\" + // url (relative?)\n            \"cover_photo_url TEXT,\" + // cover url (relative?)\n            \"cover_photo_height INTEGER NOT NULL DEFAULT 0,\" +\n            \"cover_photo_width INTEGER NOT NULL DEFAULT 0,\" +\n            \"cover_photo_id TEXT,\" +\n            \"last_sync_start_time INTEGER NOT NULL DEFAULT 0,\" + // timestamp\n            \"last_sync_finish_time INTEGER NOT NULL DEFAULT 0,\" + // timestamp\n            \"last_sync_status INTEGER NOT NULL DEFAULT 0,\" + // eg. 2\n            \"last_successful_sync_time INTEGER NOT NULL DEFAULT 0,\" + // timestamp\n            \"sync_to_contacts INTEGER NOT NULL DEFAULT 0,\" + // 0\n            \"is_dasher INTEGER NOT NULL DEFAULT 0,\" + // 0\n            \"dasher_domain TEXT,\" +\n            \"etag TEXT,\" +\n            \"sync_circles_to_contacts INTEGER NOT NULL DEFAULT 0,\" + // 0\n            \"sync_evergreen_to_contacts INTEGER NOT NULL DEFAULT 0,\" + // 0\n            \"last_full_people_sync_time INTEGER NOT NULL DEFAULT 0,\" + // timestamp\n            \"is_active_plus_account INTEGER NOT NULL DEFAULT 0,\" + // 0\n            \"sync_me_to_contacts INTEGER NOT NULL DEFAULT 0,\" +\n            \"given_name TEXT,\" +\n            \"family_name TEXT,\" +\n            \"contacts_backup_and_sync INTEGER NOT NULL DEFAULT 0);\"; // 0\n    private static final String CREATE_CIRCLES = \"CREATE TABLE circles (\" +\n            \"_id INTEGER PRIMARY KEY AUTOINCREMENT,\" +\n            \"owner_id INTEGER NOT NULL,\" +\n            \"circle_id TEXT NOT NULL,\" +\n            \"name TEXT,sort_key TEXT,\" +\n            \"type INTEGER NOT NULL,\" +\n            \"for_sharing INTEGER NOT NULL DEFAULT 0,\" +\n            \"people_count INTEGER NOT NULL DEFAULT -1,\" +\n            \"client_policies INTEGER NOT NULL DEFAULT 0,\" +\n            \"etag TEXT,last_modified INTEGER NOT NULL DEFAULT 0,\" +\n            \"sync_to_contacts INTEGER NOT NULL DEFAULT 0,\" +\n            \"UNIQUE (owner_id,circle_id),\" +\n            \"FOREIGN KEY (owner_id) REFERENCES owners(_id) ON DELETE CASCADE);\";\n    private static final String ALTER_OWNERS_3_1 = \"ALTER TABLE owners ADD COLUMN is_active_plus_account INTEGER NOT NULL DEFAULT 0;\";\n    private static final String ALTER_OWNERS_3_2 = \"ALTER TABLE owners ADD COLUMN sync_me_to_contacts INTEGER NOT NULL DEFAULT 0;\";\n    private static final String ALTER_OWNERS_4_1 = \"ALTER TABLE owners ADD COLUMN given_name TEXT;\";\n    private static final String ALTER_OWNERS_4_2 = \"ALTER TABLE owners ADD COLUMN family_name TEXT;\";\n    private static final String ALTER_OWNERS_5_1 = \"ALTER TABLE owners ADD COLUMN contacts_backup_and_sync INTEGER NOT NULL DEFAULT 0;\";\n    public static final String OWNERS_TABLE = \"owners\";\n    public static final String CIRCLES_TABLE = \"circles\";\n\n\n    public DatabaseHelper(Context context) {\n        super(context, DB_NAME, null, DB_VERSION);\n    }\n\n    @Override\n    public void onCreate(SQLiteDatabase db) {\n        db.execSQL(CREATE_OWNERS);\n        db.execSQL(CREATE_CIRCLES);\n    }\n\n    @Override\n    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {\n        if (oldVersion < 2) db.execSQL(CREATE_CIRCLES);\n        if (oldVersion < 3) {\n            db.execSQL(ALTER_OWNERS_3_1);\n            db.execSQL(ALTER_OWNERS_3_2);\n        }\n        if (oldVersion < 4) {\n            db.execSQL(ALTER_OWNERS_4_1);\n            db.execSQL(ALTER_OWNERS_4_2);\n        }\n        if (oldVersion < 5) {\n            db.execSQL(ALTER_OWNERS_5_1);\n        }\n    }\n\n    @Override\n    public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {\n        // silently accept\n    }\n\n    public Cursor getOwners() {\n        return getReadableDatabase().query(OWNERS_TABLE, null, null, null, null, null, null);\n    }\n\n    public void putOwner(ContentValues contentValues) {\n        getWritableDatabase().insertWithOnConflict(OWNERS_TABLE, null, contentValues, SQLiteDatabase.CONFLICT_REPLACE);\n        close();\n    }\n\n    public Cursor getOwner(String accountName) {\n        return getReadableDatabase().query(OWNERS_TABLE, null, \"account_name=?\", new String[]{accountName}, null, null, null);\n    }\n\n    public Cursor getCircles(int ownerId, String circleId, int type) {\n        return getReadableDatabase().query(CIRCLES_TABLE, null,\n                \"owner_id=?1 AND (circle_id = ?2 OR ?2 = '') AND (type = ?3 OR ?3 = -999 OR (?3 = -998 AND type = -1))\",\n                new String[]{Integer.toString(ownerId), circleId != null ? circleId : \"\", Integer.toString(type)}, null, null, null);\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/people/PeopleManager.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.people;\n\nimport android.accounts.Account;\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.database.sqlite.SQLiteDatabase;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.util.Log;\n\nimport com.google.android.gms.common.Scopes;\n\nimport org.json.JSONObject;\nimport org.microg.gms.auth.AuthManager;\nimport org.microg.gms.auth.AuthResponse;\nimport org.microg.gms.common.Constants;\nimport org.microg.gms.common.Utils;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.net.URL;\nimport java.net.URLConnection;\n\npublic class PeopleManager {\n    private static final String TAG = \"GmsPeopleManager\";\n    public static final String USERINFO_SCOPE = \"oauth2:\" + Scopes.USERINFO_PROFILE;\n    public static final String USERINFO_URL = \"https://www.googleapis.com/oauth2/v1/userinfo\";\n    public static final String REGEX_SEARCH_USER_PHOTO = \"https?\\\\:\\\\/\\\\/lh([0-9]*)\\\\.googleusercontent\\\\.com/\";\n\n    public static String getDisplayName(Context context, String accountName) {\n        DatabaseHelper databaseHelper = new DatabaseHelper(context);\n        Cursor cursor = databaseHelper.getOwner(accountName);\n        String displayName = null;\n        try {\n            if (cursor.moveToNext()) {\n                int idx = cursor.getColumnIndex(\"display_name\");\n                if (idx >= 0 && !cursor.isNull(idx)) displayName = cursor.getString(idx);\n            }\n        } finally {\n            cursor.close();\n            databaseHelper.close();\n        }\n        return displayName;\n    }\n\n    public static String getGivenName(Context context, String accountName) {\n        DatabaseHelper databaseHelper = new DatabaseHelper(context);\n        Cursor cursor = databaseHelper.getOwner(accountName);\n        String displayName = null;\n        try {\n            if (cursor.moveToNext()) {\n                int idx = cursor.getColumnIndex(\"given_name\");\n                if (idx >= 0 && !cursor.isNull(idx)) displayName = cursor.getString(idx);\n            }\n        } finally {\n            cursor.close();\n            databaseHelper.close();\n        }\n        return displayName;\n    }\n\n    public static File getOwnerAvatarFile(Context context, String accountName, boolean network) {\n        DatabaseHelper databaseHelper = new DatabaseHelper(context);\n        Cursor cursor = databaseHelper.getOwner(accountName);\n        String url = null;\n        if (cursor.moveToNext()) {\n            int idx = cursor.getColumnIndex(\"avatar\");\n            if (idx >= 0 && !cursor.isNull(idx)) url = cursor.getString(idx);\n        }\n        cursor.close();\n        databaseHelper.close();\n        if (url == null) return null;\n        String urlLastPart = url.replaceFirst(REGEX_SEARCH_USER_PHOTO, \"\");\n        File file = new File(context.getCacheDir(), urlLastPart);\n        if (!file.getParentFile().mkdirs() && file.exists()) {\n            return file;\n        }\n        if (!network) return null;\n        try {\n            URLConnection conn = new URL(url).openConnection();\n            conn.setDoInput(true);\n            byte[] bytes = Utils.readStreamToEnd(conn.getInputStream());\n            FileOutputStream outputStream = new FileOutputStream(file);\n            outputStream.write(bytes);\n            outputStream.close();\n            return file;\n        } catch (Exception e) {\n            Log.w(TAG, e);\n            return null;\n        }\n\n    }\n\n    public static Bitmap getOwnerAvatarBitmap(Context context, String accountName, boolean network) {\n        File avaterFile = getOwnerAvatarFile(context, accountName, network);\n        if (avaterFile == null) return null;\n        return BitmapFactory.decodeFile(avaterFile.getPath());\n    }\n\n    public static void updateOwnerAvatar(Context context, String accountName, String newAvatar) {\n        try (DatabaseHelper databaseHelper = new DatabaseHelper(context); SQLiteDatabase db = databaseHelper.getWritableDatabase()) {\n            ContentValues contentValues = new ContentValues();\n            contentValues.put(\"avatar\", newAvatar);\n            int rowsAffected = db.update(DatabaseHelper.OWNERS_TABLE, contentValues, \"account_name = ?\", new String[]{accountName});\n            Log.d(TAG, \"updateOwnerAvatar affected: \" + rowsAffected);\n        } catch (Exception e) {\n            Log.e(TAG, \"Error updating avatar: \" + e.getMessage());\n        }\n    }\n\n    public static String loadUserInfo(Context context, Account account) {\n        try {\n            URLConnection conn = new URL(USERINFO_URL).openConnection();\n            conn.addRequestProperty(\"Authorization\", \"Bearer \" + getUserInfoAuthKey(context, account));\n            conn.setDoInput(true);\n            byte[] bytes = Utils.readStreamToEnd(conn.getInputStream());\n            JSONObject info = new JSONObject(new String(bytes));\n            ContentValues contentValues = new ContentValues();\n            contentValues.put(\"account_name\", account.name);\n            if (info.has(\"id\")) contentValues.put(\"gaia_id\", info.getString(\"id\"));\n            if (info.has(\"picture\")) contentValues.put(\"avatar\", info.getString(\"picture\"));\n            if (info.has(\"name\")) contentValues.put(\"display_name\", info.getString(\"name\"));\n            if (info.has(\"given_name\")) contentValues.put(\"given_name\", info.getString(\"given_name\"));\n            if (info.has(\"family_name\")) contentValues.put(\"family_name\", info.getString(\"family_name\"));\n            contentValues.put(\"last_sync_start_time\", System.currentTimeMillis());\n            contentValues.put(\"last_sync_finish_time\", System.currentTimeMillis());\n            contentValues.put(\"last_successful_sync_time\", System.currentTimeMillis());\n            contentValues.put(\"last_full_people_sync_time\", System.currentTimeMillis());\n            DatabaseHelper databaseHelper = new DatabaseHelper(context);\n            databaseHelper.putOwner(contentValues);\n            databaseHelper.close();\n            return contentValues.getAsString(\"gaia_id\");\n        } catch (Exception e) {\n            Log.w(TAG, e);\n            return null;\n        }\n    }\n\n    public static String getUserInfoAuthKey(Context context, Account account) {\n        AuthManager authManager = new AuthManager(context, account.name, Constants.GMS_PACKAGE_NAME, USERINFO_SCOPE);\n        authManager.setPermitted(true);\n        String result = authManager.getAuthToken();\n        if (result == null) {\n            try {\n                AuthResponse response = authManager.requestAuthWithBackgroundResolution(false);\n                result = response.auth;\n            } catch (IOException e) {\n                Log.w(TAG, e);\n                return null;\n            }\n        }\n        return result;\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/people/PeopleService.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.people;\n\nimport android.os.RemoteException;\n\nimport com.google.android.gms.common.internal.GetServiceRequest;\nimport com.google.android.gms.common.internal.IGmsCallbacks;\n\nimport org.microg.gms.BaseService;\nimport org.microg.gms.common.GmsService;\n\npublic class PeopleService extends BaseService {\n    private PeopleServiceImpl impl = new PeopleServiceImpl(this);\n\n    public PeopleService() {\n        super(\"GmsPeopleSvc\", GmsService.PEOPLE);\n    }\n\n    @Override\n    public void handleServiceRequest(IGmsCallbacks callback, GetServiceRequest request, GmsService service) throws RemoteException {\n        callback.onPostInitComplete(0, impl.asBinder(), null);\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/people/PeopleServiceImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.people;\n\nimport android.Manifest;\nimport android.accounts.Account;\nimport android.accounts.AccountManager;\nimport android.content.Context;\nimport android.content.pm.PackageManager;\nimport android.database.Cursor;\nimport android.os.Bundle;\nimport android.os.Parcel;\nimport android.os.ParcelFileDescriptor;\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport com.google.android.gms.common.data.DataHolder;\nimport com.google.android.gms.common.internal.ICancelToken;\nimport com.google.android.gms.people.internal.IPeopleCallbacks;\nimport com.google.android.gms.people.internal.IPeopleService;\nimport com.google.android.gms.people.model.AccountMetadata;\n\nimport org.microg.gms.auth.AuthConstants;\nimport org.microg.gms.common.GooglePackagePermission;\nimport org.microg.gms.common.NonCancelToken;\nimport org.microg.gms.common.PackageUtils;\n\nimport java.io.File;\n\npublic class PeopleServiceImpl extends IPeopleService.Stub {\n    private static final String TAG = \"GmsPeopleSvcImpl\";\n    private final Context context;\n\n    public PeopleServiceImpl(Context context) {\n        this.context = context;\n    }\n\n    @SuppressWarnings(\"MissingPermission\")\n    @Override\n    public void loadOwners(final IPeopleCallbacks callbacks, boolean var2, boolean var3, final String accountName, String var5, int sortOrder) {\n        Log.d(TAG, \"loadOwners: \" + var2 + \", \" + var3 + \", \" + accountName + \", \" + var5 + \", \" + sortOrder);\n        if (context.checkCallingPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {\n            PackageUtils.assertGooglePackagePermission(context, GooglePackagePermission.OWNER);\n        }\n        AccountManager accountManager = AccountManager.get(context);\n        Bundle accountMetadata = new Bundle();\n        String accountType = AuthConstants.DEFAULT_ACCOUNT_TYPE;\n        for (Account account : accountManager.getAccountsByType(accountType)) {\n            if (accountName == null || account.name.equals(accountName)) {\n                accountMetadata.putParcelable(account.name, new AccountMetadata());\n            }\n        }\n        Bundle extras = new Bundle();\n        extras.putBundle(\"account_metadata\", accountMetadata);\n        try {\n            DatabaseHelper databaseHelper = new DatabaseHelper(context);\n            DataHolder dataHolder = new DataHolder(databaseHelper.getOwners(), 0, extras);\n            Log.d(TAG, \"loadOwners[result]: \" + dataHolder);\n            callbacks.onDataHolder(0, extras, dataHolder);\n            databaseHelper.close();\n        } catch (Exception e) {\n            Log.w(TAG, e);\n        }\n    }\n\n    @Override\n    public void loadPeopleForAggregation(IPeopleCallbacks callbacks, String account, String var3, String filter, int var5, boolean var6, int var7, int var8, String var9, boolean var10, int var11, int var12) throws RemoteException {\n        Log.d(TAG, \"loadPeopleForAggregation: \" + account + \", \" + var3 + \", \" + filter + \", \" + var5 + \", \" + var6 + \", \" + var7 + \", \" + var8 + \", \" + var9 + \", \" + var10 + \", \" + var11 + \", \" + var12);\n        callbacks.onDataHolder(0, new Bundle(), null);\n    }\n\n    @Override\n    public Bundle registerDataChangedListener(IPeopleCallbacks callbacks, boolean register, String var3, String var4, int scopes) throws RemoteException {\n        Log.d(TAG, \"registerDataChangedListener: \" + register + \", \" + var3 + \", \" + var4 + \", \" + scopes);\n        callbacks.onDataHolder(0, new Bundle(), null);\n        return null;\n    }\n\n    @Override\n    public void loadCircles(IPeopleCallbacks callbacks, String account, String pageGaiaId, String circleId, int type, String var6, boolean var7) throws RemoteException {\n        Log.d(TAG, \"loadCircles: \" + account + \", \" + pageGaiaId + \", \" + circleId + \", \" + type + \", \" + var6 + \", \" + var7);\n        PackageUtils.assertGooglePackagePermission(context, GooglePackagePermission.PEOPLE);\n        try {\n            DatabaseHelper databaseHelper = new DatabaseHelper(context);\n            Cursor owner = databaseHelper.getOwner(account);\n            int ownerId = -1;\n            if (owner.moveToNext()) {\n                ownerId = owner.getInt(0);\n            }\n            owner.close();\n            Bundle extras = new Bundle();\n            DataHolder dataHolder = new DataHolder(databaseHelper.getCircles(ownerId, circleId, type), 0, extras);\n            callbacks.onDataHolder(0, new Bundle(), dataHolder);\n            databaseHelper.close();\n        } catch (Exception e) {\n            Log.w(TAG, e);\n        }\n    }\n\n    @Override\n    public Bundle requestSync(String account, String var2, long var3, boolean var5, boolean var6) throws RemoteException {\n        Log.d(TAG, \"requestSync: \" + account + \", \" + var2 + \", \" + var3 + \", \" + var5 + \", \" + var6);\n        return null;\n    }\n\n    @Override\n    public ICancelToken loadOwnerAvatar(final IPeopleCallbacks callbacks, final String account, String pageId, int size, int flags) {\n        Log.d(TAG, \"loadOwnerAvatar: \" + account + \", \" + pageId + \", \" + size + \", \" + flags);\n        PackageUtils.assertGooglePackagePermission(context, GooglePackagePermission.OWNER);\n        final Thread thread = new Thread(new Runnable() {\n            @Override\n            public void run() {\n                Bundle extras = new Bundle();\n                extras.putBoolean(\"rewindable\", false);\n                extras.putInt(\"width\", 0);\n                extras.putInt(\"height\", 0);\n                File avaterFile = PeopleManager.getOwnerAvatarFile(context, account, true);\n                try {\n                    ParcelFileDescriptor fileDescriptor = null;\n                    if (avaterFile != null) {\n                        fileDescriptor = ParcelFileDescriptor.open(avaterFile, ParcelFileDescriptor.MODE_READ_ONLY);\n                    }\n                    callbacks.onParcelFileDescriptor(0, extras, fileDescriptor, extras);\n                } catch (Exception e) {\n                    Log.w(TAG, e);\n                }\n            }\n        });\n        thread.start();\n        return new ICancelToken.Stub() {\n            @Override\n            public void cancel() throws RemoteException {\n                thread.interrupt();\n            }\n        };\n    }\n\n    @Override\n    public ICancelToken loadAutocompleteList(IPeopleCallbacks callbacks, String account, String pageId, boolean directorySearch, String var5, String query, int autocompleteType, int var8, int numberOfResults, boolean var10) throws RemoteException {\n        Log.d(TAG, \"loadAutocompleteList: \" + account + \", \" + pageId + \", \" + directorySearch + \", \" + var5 + \", \" + query + \", \" + autocompleteType + \", \" + var8 + \", \" + numberOfResults + \", \" + var10);\n        callbacks.onDataHolder(0, new Bundle(), null);\n        return new NonCancelToken();\n    }\n\n    @Override\n    public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {\n        if (super.onTransact(code, data, reply, flags)) return true;\n        Log.d(TAG, \"onTransact [unknown]: \" + code + \", \" + data + \", \" + flags);\n        return false;\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/phenotype/ConfigurationProvider.java",
    "content": "/*\n * Copyright (C) 2018 microG Project Team\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 org.microg.gms.phenotype;\n\nimport android.content.ContentProvider;\nimport android.content.ContentValues;\nimport android.database.Cursor;\nimport android.database.MatrixCursor;\nimport android.net.Uri;\nimport android.util.Log;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\npublic class ConfigurationProvider extends ContentProvider {\n    private static final String TAG = \"GmsPhenotypeCfgProvider\";\n    @Override\n    public boolean onCreate() {\n        Log.d(TAG, \"unimplemented Method: onCreate\");\n        return false;\n    }\n\n    @Nullable\n    @Override\n    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {\n        selection = Uri.decode(uri.getLastPathSegment());\n        if (selection == null) return null;\n        return new MatrixCursor(new String[]{\"key\", \"value\"});\n    }\n\n    @Nullable\n    @Override\n    public String getType(@NonNull Uri uri) {\n        return null;\n    }\n\n    @Nullable\n    @Override\n    public Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public int delete(@NonNull Uri uri, @Nullable String s, @Nullable String[] strings) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public int update(@NonNull Uri uri, @Nullable ContentValues contentValues, @Nullable String s, @Nullable String[] strings) {\n        throw new UnsupportedOperationException();\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/places/GeoDataService.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.places;\n\nimport android.os.RemoteException;\n\nimport com.google.android.gms.common.internal.GetServiceRequest;\nimport com.google.android.gms.common.internal.IGmsCallbacks;\n\nimport org.microg.gms.BaseService;\nimport org.microg.gms.common.GmsService;\n\npublic class GeoDataService extends BaseService {\n    public GeoDataService() {\n        super(\"GmsPlcGeoSvc\", GmsService.PLACES_GEO_DATA);\n    }\n\n    @Override\n    public void handleServiceRequest(IGmsCallbacks callback, GetServiceRequest request, GmsService service) throws RemoteException {\n        callback.onPostInitComplete(0, new PlacesServiceImpl().asBinder(), null);\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/places/PlaceDetectionService.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.places;\n\nimport android.os.RemoteException;\n\nimport com.google.android.gms.common.internal.GetServiceRequest;\nimport com.google.android.gms.common.internal.IGmsCallbacks;\n\nimport org.microg.gms.BaseService;\nimport org.microg.gms.common.GmsService;\n\npublic class PlaceDetectionService extends BaseService {\n    public PlaceDetectionService() {\n        super(\"GmsPlcDtctSvc\", GmsService.PLACES_PLACE_DETECTION);\n    }\n\n    @Override\n    public void handleServiceRequest(IGmsCallbacks callback, GetServiceRequest request, GmsService service) throws RemoteException {\n        callback.onPostInitComplete(0, new PlaceDetectionServiceImpl().asBinder(), null);\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/places/PlaceDetectionServiceImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.places;\n\nimport android.os.Parcel;\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport com.google.android.gms.location.places.internal.IGooglePlaceDetectionService;\n\npublic class PlaceDetectionServiceImpl extends IGooglePlaceDetectionService.Stub{\n    private static final String TAG = \"GmsPlcDtctSvcImpl\";\n\n    @Override\n    public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {\n        if (super.onTransact(code, data, reply, flags)) return true;\n        Log.d(TAG, \"onTransact [unknown]: \" + code + \", \" + data + \", \" + flags);\n        return false;\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/places/PlacesServiceImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.places;\n\nimport android.os.Parcel;\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport com.google.android.gms.location.places.internal.IGooglePlacesService;\n\npublic class PlacesServiceImpl extends IGooglePlacesService.Stub {\n    private static final String TAG = \"GmsPlcSvcImpl\";\n\n    @Override\n    public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {\n        if (super.onTransact(code, data, reply, flags)) return true;\n        Log.d(TAG, \"onTransact [unknown]: \" + code + \", \" + data + \", \" + flags);\n        return false;\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/playlog/PlayLogService.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.playlog;\n\nimport android.os.RemoteException;\n\nimport com.google.android.gms.common.internal.GetServiceRequest;\nimport com.google.android.gms.common.internal.IGmsCallbacks;\n\nimport org.microg.gms.BaseService;\nimport org.microg.gms.common.GmsService;\n\n@Deprecated\npublic class PlayLogService extends BaseService {\n\n    private PlayLogServiceImpl playLogService = new PlayLogServiceImpl();\n\n    public PlayLogService() {\n        super(\"GmsPlayLogSvc\", GmsService.PLAY_LOG);\n    }\n\n    @Override\n    public void handleServiceRequest(IGmsCallbacks callback, GetServiceRequest request, GmsService service) throws RemoteException {\n        callback.onPostInitComplete(0, playLogService.asBinder(), null);\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/playlog/PlayLogServiceImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.playlog;\n\nimport android.os.Parcel;\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport com.google.android.gms.playlog.internal.IPlayLogService;\nimport com.google.android.gms.playlog.internal.LogEvent;\nimport com.google.android.gms.clearcut.internal.PlayLoggerContext;\n\nimport java.util.List;\n\n@Deprecated\npublic class PlayLogServiceImpl extends IPlayLogService.Stub {\n    private static final String TAG = \"GmsPlayLogSvcImpl\";\n\n    @Override\n    public void onEvent(String packageName, PlayLoggerContext context, LogEvent event) throws RemoteException {\n        Log.d(TAG, \"onEvent: context[packageName]:\" + context.packageName + \" event[tag]:\" + event.tag);\n    }\n\n    @Override\n    public void onMultiEvent(String packageName, PlayLoggerContext context, List<LogEvent> events) throws RemoteException {\n        for (LogEvent event : events) {\n            onEvent(packageName, context, event);\n        }\n    }\n\n    @Override\n    public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {\n        if (super.onTransact(code, data, reply, flags)) return true;\n        Log.d(TAG, \"onTransact [unknown]: \" + code + \", \" + data + \", \" + flags);\n        return false;\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/plus/PlusOneButtonImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.plus;\n\nimport android.content.Context;\nimport android.view.View;\n\npublic class PlusOneButtonImpl extends View {\n    public PlusOneButtonImpl(Context context, int size, int annotation, String url,\n            String account) {\n        super(context);\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/reminders/RemindersService.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.reminders;\n\nimport android.os.RemoteException;\n\nimport com.google.android.gms.common.internal.GetServiceRequest;\nimport com.google.android.gms.common.internal.IGmsCallbacks;\n\nimport org.microg.gms.BaseService;\nimport org.microg.gms.common.GmsService;\n\npublic class RemindersService extends BaseService {\n\n    public RemindersService() {\n        super(\"GmsRemindSvc\", GmsService.REMINDERS);\n    }\n\n    @Override\n    public void handleServiceRequest(IGmsCallbacks callback, GetServiceRequest request, GmsService service) throws RemoteException {\n        callback.onPostInitComplete(0, new RemindersServiceImpl(), null);\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/reminders/RemindersServiceImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.reminders;\n\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport com.google.android.gms.reminders.AccountState;\nimport com.google.android.gms.reminders.CreateReminderOptionsInternal;\nimport com.google.android.gms.reminders.LoadRemindersOptions;\nimport com.google.android.gms.reminders.ReindexDueDatesOptions;\nimport com.google.android.gms.reminders.UpdateRecurrenceOptions;\nimport com.google.android.gms.reminders.internal.IRemindersCallbacks;\nimport com.google.android.gms.reminders.internal.IRemindersService;\nimport com.google.android.gms.reminders.model.CustomizedSnoozePresetEntity;\nimport com.google.android.gms.reminders.model.TaskEntity;\nimport com.google.android.gms.reminders.model.TaskIdEntity;\n\nimport java.util.List;\n\npublic class RemindersServiceImpl extends IRemindersService.Stub {\n    private static final String TAG = RemindersServiceImpl.class.getSimpleName();\n\n    @Override\n    public void loadReminders(IRemindersCallbacks callbacks, LoadRemindersOptions options) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: loadReminders\");\n\n    }\n\n    @Override\n    public void addListener(IRemindersCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: addListener\");\n\n    }\n\n    @Override\n    public void createReminder(IRemindersCallbacks callbacks, TaskEntity task) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: createReminder\");\n\n    }\n\n    @Override\n    public void updateReminder(IRemindersCallbacks callbacks, TaskEntity task) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: updateReminder\");\n\n    }\n\n    @Override\n    public void deleteReminder(IRemindersCallbacks callbacks, TaskIdEntity taskId) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: deleteReminder\");\n\n    }\n\n    @Override\n    public void bumpReminder(IRemindersCallbacks callbacks, TaskIdEntity taskId) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: bumpReminder\");\n\n    }\n\n    @Override\n    public void hasUpcomingReminders(IRemindersCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: hasUpcomingReminders\");\n\n    }\n\n    @Override\n    public void createRecurrence(IRemindersCallbacks callbacks, TaskEntity task) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: createRecurrence\");\n\n    }\n\n    @Override\n    public void updateRecurrence(IRemindersCallbacks callbacks, String s1, TaskEntity task, UpdateRecurrenceOptions options) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: updateRecurrence\");\n\n    }\n\n    @Override\n    public void deleteRecurrence(IRemindersCallbacks callbacks, String s1, UpdateRecurrenceOptions options) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: deleteRecurrence\");\n\n    }\n\n    @Override\n    public void changeRecurrence(IRemindersCallbacks callbacks, String s1, TaskEntity task, UpdateRecurrenceOptions options) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: changeRecurrence\");\n\n    }\n\n    @Override\n    public void makeTaskRecurring(IRemindersCallbacks callbacks, TaskEntity task) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: makeTaskRecurring\");\n\n    }\n\n    @Override\n    public void makeRecurrenceSingleInstance(IRemindersCallbacks callbacks, String s1, TaskEntity task, UpdateRecurrenceOptions options) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: makeRecurrenceSingleInstance\");\n\n    }\n\n    @Override\n    public void clearListeners() throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: clearListeners\");\n\n    }\n\n    @Override\n    public void batchUpdateReminders(IRemindersCallbacks callbacks, List<TaskEntity> tasks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: batchUpdateReminders\");\n\n    }\n\n    @Override\n    public void createReminderWithOptions(IRemindersCallbacks callbacks, TaskEntity task, CreateReminderOptionsInternal options) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: createReminderWithOptions\");\n\n    }\n\n    @Override\n    public void getCustomizedSnoozePreset(IRemindersCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: getCustomizedSnoozePreset\");\n\n    }\n\n    @Override\n    public void setCustomizedSnoozePreset(IRemindersCallbacks callbacks, CustomizedSnoozePresetEntity preset) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: setCustomizedSnoozePreset\");\n\n    }\n\n    @Override\n    public void setAccountState(IRemindersCallbacks callbacks, AccountState accountState) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: setAccountState\");\n\n    }\n\n    @Override\n    public void getAccountState(IRemindersCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: getAccountState\");\n\n    }\n\n    @Override\n    public void checkReindexDueDatesNeeded(IRemindersCallbacks callbacks, ReindexDueDatesOptions options) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: checkReindexDueDatesNeeded\");\n\n    }\n\n    @Override\n    public void reindexDueDates(IRemindersCallbacks callbacks, ReindexDueDatesOptions options) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: reindexDueDates\");\n\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/settings/GmsFileProvider.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.settings\n\nimport android.content.Context\nimport android.content.pm.ProviderInfo\nimport android.database.Cursor\nimport android.database.MatrixCursor\nimport android.net.Uri\nimport android.os.CancellationSignal\nimport android.os.ParcelFileDescriptor\nimport android.util.Log\nimport androidx.core.content.FileProvider\nimport java.io.FileNotFoundException\n\nprivate const val TAG = \"GmsFileProvider\"\n\nclass GmsFileProvider : FileProvider() {\n    private val emptyProjection = arrayOfNulls<String>(0)\n    private var initializationFailed = false\n\n    override fun attachInfo(context: Context, info: ProviderInfo) {\n        try {\n            super.attachInfo(context, info)\n        } catch (e: Exception) {\n            initializationFailed = true\n            Log.e(TAG, \"attachInfo error:${e.message}\")\n        }\n    }\n\n    override fun onCreate(): Boolean {\n        return true\n    }\n\n    override fun getType(uri: Uri): String? {\n        if (initializationFailed) {\n            return null\n        }\n        return super.getType(uri)\n    }\n\n    override fun openFile(\n        uri: Uri, mode: String, signal: CancellationSignal?\n    ): ParcelFileDescriptor? {\n        if (!initializationFailed) {\n            return super.openFile(uri, mode, signal)\n        }\n        throw FileNotFoundException(\"FileProvider creation failed\")\n    }\n\n    override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int {\n        if (initializationFailed) {\n            return 0\n        }\n        return super.delete(uri, selection, selectionArgs)\n    }\n\n    override fun query(\n        uri: Uri, projection: Array<out String>?, selection: String?, selectionArgs: Array<out String>?, sortOrder: String?\n    ): Cursor {\n        if (initializationFailed) {\n            return MatrixCursor(emptyProjection)\n        }\n        return super.query(uri, projection, selection, selectionArgs, sortOrder)\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/settings/GoogleSettingsProvider.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.settings;\n\nimport android.content.ContentProvider;\nimport android.content.ContentValues;\nimport android.database.Cursor;\nimport android.net.Uri;\n\npublic class GoogleSettingsProvider extends ContentProvider {\n    @Override\n    public boolean onCreate() {\n        return false;\n    }\n\n    @Override\n    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {\n        return null;\n    }\n\n    @Override\n    public String getType(Uri uri) {\n        return null;\n    }\n\n    @Override\n    public Uri insert(Uri uri, ContentValues values) {\n        return null;\n    }\n\n    @Override\n    public int delete(Uri uri, String selection, String[] selectionArgs) {\n        return 0;\n    }\n\n    @Override\n    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {\n        return 0;\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/ui/AboutFragment.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.ui;\n\nimport androidx.fragment.app.Fragment;\n\nimport com.google.android.gms.BuildConfig;\n\nimport org.microg.tools.ui.AbstractAboutFragment;\nimport org.microg.tools.ui.AbstractSettingsActivity;\n\nimport java.util.List;\n\npublic class AboutFragment extends AbstractAboutFragment {\n\n    @Override\n    protected void collectLibraries(List<AbstractAboutFragment.Library> libraries) {\n        if (\"vtm\".equalsIgnoreCase(BuildConfig.FLAVOR_maps)) {\n            libraries.add(new AbstractAboutFragment.Library(\"org.oscim.android\", \"V™\", \"GNU LGPLv3, Hannes Janetzek and devemux86\"));\n            libraries.add(new AbstractAboutFragment.Library(\"org.slf4j\", \"SLF4J\", \"MIT License, QOS.ch\"));\n        } else if (\"mapbox\".equalsIgnoreCase(BuildConfig.FLAVOR_maps) || \"maplibre\".equalsIgnoreCase(BuildConfig.FLAVOR_maps)){\n            libraries.add(new AbstractAboutFragment.Library(\"com.mapbox.mapboxsdk\", \"MapLibre Native for Android\", \"Two-Clause BSD, MapLibre contributors\"));\n        } else if (\"hms\".equalsIgnoreCase(BuildConfig.FLAVOR_maps)) {\n            libraries.add(new AbstractAboutFragment.Library(\"com.huawei.hms.maps.api\", \"Huawei MapKit\", \"Proprietary, Huawei Technologies\"));\n        }\n        libraries.add(new AbstractAboutFragment.Library(\"androidx\", \"Android Jetpack\", \"Apache License 2.0, The Android Open Source Project\"));\n        libraries.add(new AbstractAboutFragment.Library(\"com.upokecenter.cbor\", \"CBOR\", \"Creative Commons Zero, Peter O\"));\n        libraries.add(new AbstractAboutFragment.Library(\"de.hdodenhof.circleimageview\", \"CircleImageView\", \"Apache License 2.0, Henning Dodenhof\"));\n        libraries.add(new AbstractAboutFragment.Library(\"su.litvak.chromecast.api.v2\", \"ChromeCast Java API v2\", \"Apache License 2.0, Vitaly Litvak\"));\n        libraries.add(new AbstractAboutFragment.Library(\"org.conscrypt\", \"Conscrypt\", \"Apache License 2.0, The Android Open Source Project\"));\n        libraries.add(new AbstractAboutFragment.Library(\"org.chromium.net\", \"Cronet\", \"BSD-style License, The Chromium Authors\"));\n        libraries.add(new AbstractAboutFragment.Library(\"org.jetbrains.kotlin\", \"Kotlin\", \"Apache License 2.0, JetBrains s.r.o.\"));\n        libraries.add(new AbstractAboutFragment.Library(\"com.google.android.material\", \"Material Components\", \"Apache License 2.0, The Android Open Source Project\"));\n        libraries.add(new AbstractAboutFragment.Library(\"com.android.volley\", \"Volley\", \"Apache License 2.0, The Android Open Source Project\"));\n        libraries.add(new AbstractAboutFragment.Library(\"com.squareup.wire\", \"Wire Protocol Buffers\", \"Apache License 2.0, Square Inc.\"));\n        libraries.add(new AbstractAboutFragment.Library(\"com.google.zxing\", \"ZXing\", \"Apache License 2.0, ZXing authors\"));\n    }\n\n    public static class AsActivity extends AbstractSettingsActivity {\n        public AsActivity() {\n            showHomeAsUp = true;\n        }\n\n        @Override\n        protected Fragment getFragment() {\n            return new AboutFragment();\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/ui/AskPushPermission.java",
    "content": "package org.microg.gms.ui;\n\nimport android.app.Activity;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageManager;\nimport android.graphics.Typeface;\nimport android.os.Bundle;\nimport android.os.ResultReceiver;\nimport android.text.Spannable;\nimport android.text.SpannableString;\nimport android.text.style.StyleSpan;\nimport android.view.View;\nimport android.widget.TextView;\n\nimport androidx.fragment.app.FragmentActivity;\n\nimport com.google.android.gms.R;\n\nimport org.microg.gms.gcm.GcmDatabase;\n\npublic class AskPushPermission extends FragmentActivity {\n    public static final String EXTRA_REQUESTED_PACKAGE = \"package\";\n    public static final String EXTRA_RESULT_RECEIVER = \"receiver\";\n    public static final String EXTRA_FORCE_ASK = \"force\";\n    public static final String EXTRA_EXPLICIT = \"explicit\";\n\n    private GcmDatabase database;\n\n    private String packageName;\n    private ResultReceiver resultReceiver;\n    private boolean answered;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        database = new GcmDatabase(this);\n\n        packageName = getIntent().getStringExtra(EXTRA_REQUESTED_PACKAGE);\n        resultReceiver = getIntent().getParcelableExtra(EXTRA_RESULT_RECEIVER);\n        boolean forceAsk = getIntent().getBooleanExtra(EXTRA_FORCE_ASK, false);\n        if (packageName == null || (resultReceiver == null && !forceAsk)) {\n            answered = true;\n            finish();\n            return;\n        }\n\n        if (!forceAsk && database.getApp(packageName) != null) {\n            resultReceiver.send(Activity.RESULT_OK, Bundle.EMPTY);\n            answered = true;\n            finish();\n            return;\n        }\n\n        try {\n            View view = getLayoutInflater().inflate(R.layout.ask_gcm, null);\n            PackageManager pm = getPackageManager();\n            final ApplicationInfo info = pm.getApplicationInfo(packageName, 0);\n            String label = pm.getApplicationLabel(info).toString();\n            String raw = getString(R.string.gcm_allow_app_popup, label);\n            SpannableString s = new SpannableString(raw);\n            s.setSpan(new StyleSpan(Typeface.BOLD), raw.indexOf(label), raw.indexOf(label) + label.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);\n\n            ((TextView) view.findViewById(R.id.permission_message)).setText(s);\n            UtilsKt.buildAlertDialog(this)\n                    .setView(view)\n                    .setPositiveButton(R.string.allow, (dialog, which) -> {\n                        if (answered) return;\n                        database.noteAppKnown(packageName, true);\n                        answered = true;\n                        Bundle bundle = new Bundle();\n                        bundle.putBoolean(EXTRA_EXPLICIT, true);\n                        if (resultReceiver != null) resultReceiver.send(Activity.RESULT_OK, bundle);\n                        finish();\n                    })\n                    .setNegativeButton(R.string.deny, (dialog, which) -> {\n                        if (answered) return;\n                        database.noteAppKnown(packageName, false);\n                        answered = true;\n                        Bundle bundle = new Bundle();\n                        bundle.putBoolean(EXTRA_EXPLICIT, true);\n                        if (resultReceiver != null) resultReceiver.send(Activity.RESULT_CANCELED, bundle);\n                        finish();\n                    })\n                    .create()\n                    .show();\n        } catch (PackageManager.NameNotFoundException e) {\n            finish();\n        }\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        if (!answered) {\n            if (resultReceiver != null) resultReceiver.send(Activity.RESULT_CANCELED, Bundle.EMPTY);\n        }\n        database.close();\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/ui/Conditions.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.ui;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.os.PowerManager;\nimport android.provider.Settings;\nimport android.view.View;\n\nimport androidx.core.app.ActivityCompat;\nimport androidx.core.content.ContextCompat;\n\nimport com.google.android.gms.R;\n\nimport org.microg.gms.gcm.GcmPrefs;\nimport org.microg.tools.ui.Condition;\n\nimport static android.Manifest.permission.ACCESS_COARSE_LOCATION;\nimport static android.Manifest.permission.ACCESS_FINE_LOCATION;\nimport static android.Manifest.permission.GET_ACCOUNTS;\nimport static android.Manifest.permission.READ_EXTERNAL_STORAGE;\nimport static android.Manifest.permission.READ_PHONE_STATE;\nimport static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;\nimport static android.content.pm.PackageManager.PERMISSION_GRANTED;\nimport static android.os.Build.VERSION.SDK_INT;\n\npublic class Conditions {\n    public static final Condition GCM_BATTERY_OPTIMIZATIONS = new Condition.Builder()\n            .title(R.string.cond_gcm_bat_title)\n            .summary(R.string.cond_gcm_bat_summary)\n            .evaluation(new Condition.Evaluation() {\n                @Override\n                public boolean isActive(Context context) {\n                    if (SDK_INT < 23) return false;\n                    if (!GcmPrefs.get(context).isEnabled()) return false;\n                    PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);\n                    return !pm.isIgnoringBatteryOptimizations(context.getPackageName());\n                }\n            })\n            .firstAction(R.string.cond_gcm_bat_action, new View.OnClickListener() {\n                @Override\n                public void onClick(View v) {\n                    if (SDK_INT < 23) return;\n                    Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);\n                    intent.setData(Uri.parse(\"package:\" + v.getContext().getPackageName()));\n                    v.getContext().startActivity(intent);\n                }\n            }).build();\n\n    private static final String[] REQUIRED_PERMISSIONS = new String[]{ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION, READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE, GET_ACCOUNTS, READ_PHONE_STATE};\n    public static final Condition PERMISSIONS = new Condition.Builder()\n            .title(R.string.cond_perm_title)\n            .summaryPlurals(R.plurals.cond_perm_summary)\n            .evaluation(new Condition.Evaluation() {\n                int count = 0;\n                @Override\n                public boolean isActive(Context context) {\n                    count = 0;\n                    if (SDK_INT >= 23) {\n                        for (String permission : REQUIRED_PERMISSIONS) {\n                            if (ContextCompat.checkSelfPermission(context, permission) != PERMISSION_GRANTED)\n                                count++;\n                        }\n                    }\n                    return count > 0;\n                }\n\n                @Override\n                public int getPluralsCount() {\n                    return count;\n                }\n            })\n            .firstActionPlurals(R.plurals.cond_perm_action, new View.OnClickListener() {\n                @Override\n                public void onClick(View v) {\n                    if (v.getContext() instanceof Activity) {\n                        ActivityCompat.requestPermissions((Activity) v.getContext(), REQUIRED_PERMISSIONS, 0);\n                    }\n                }\n            }).build();\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/ui/GoogleMoreFragment.java",
    "content": "/*\n * Copyright (C) 2017 microG Project Team\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 org.microg.gms.ui;\n\nimport com.google.android.gms.R;\n\nimport org.microg.tools.ui.AbstractSettingsActivity;\n\npublic class GoogleMoreFragment {\n    public static class AsActivity extends AbstractSettingsActivity {\n        public AsActivity() {\n            showHomeAsUp = true;\n            preferencesResource = R.xml.preferences_google_more;\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/ui/LocationSettingsActivity.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.ui;\n\nimport android.app.Activity;\n\npublic class LocationSettingsActivity extends Activity {\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/ui/MainSettingsActivity.java",
    "content": "package org.microg.gms.ui;\n\nimport android.content.Intent;\nimport android.content.SharedPreferences;\nimport android.os.Bundle;\n\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.AppCompatActivity;\nimport androidx.appcompat.widget.Toolbar;\nimport androidx.navigation.NavController;\nimport androidx.navigation.fragment.NavHostFragment;\nimport androidx.navigation.ui.AppBarConfiguration;\nimport androidx.navigation.ui.NavigationUI;\n\nimport com.google.android.gms.BuildConfig;\nimport com.google.android.gms.R;\nimport com.google.android.material.appbar.CollapsingToolbarLayout;\n\nimport org.microg.gms.common.Constants;\nimport org.microg.gms.ui.settings.SettingsProvider;\n\nimport static org.microg.gms.ui.UtilsKt.buildAlertDialog;\nimport static org.microg.gms.ui.settings.SettingsProviderKt.getAllSettingsProviders;\n\npublic class MainSettingsActivity extends AppCompatActivity {\n    private AppBarConfiguration appBarConfiguration;\n\n    private static final String FIRST_RUN_MASTER = \"org.microg.gms_firstRun\";\n    private static final String FIRST_RUN_PREF = \"as_run\";\n\n    private NavController getNavController() {\n        return ((NavHostFragment)getSupportFragmentManager().findFragmentById(R.id.navhost)).getNavController();\n    }\n\n    private void showDialogIfNeeded() {\n        SharedPreferences prefs = getSharedPreferences(FIRST_RUN_MASTER, MODE_PRIVATE);\n        if (BuildConfig.APPLICATION_ID == Constants.USER_MICROG_PACKAGE_NAME &&\n                prefs.getBoolean(FIRST_RUN_PREF, true)) {\n            buildAlertDialog(this)\n                    .setMessage(R.string.limited_services_dialog_information)\n                    .setTitle(R.string.limited_services_app_name)\n                    .setPositiveButton(R.string.limited_services_dialog_information_ack, (dialog, id) -> {\n                        prefs.edit().putBoolean(FIRST_RUN_PREF, false).apply();\n                    })\n                    .create()\n                    .show();\n        }\n    }\n\n    @Override\n    protected void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        Intent intent = getIntent();\n        for (SettingsProvider settingsProvider : getAllSettingsProviders(this)) {\n            settingsProvider.preProcessSettingsIntent(intent);\n        }\n\n        setContentView(R.layout.settings_root_activity);\n\n        Toolbar toolbar = findViewById(R.id.toolbar);\n        CollapsingToolbarLayout toolbarLayout = findViewById(R.id.collapsing_toolbar);\n        setSupportActionBar(toolbar);\n\n        for (SettingsProvider settingsProvider : getAllSettingsProviders(this)) {\n            settingsProvider.extendNavigation(getNavController());\n        }\n\n        appBarConfiguration = new AppBarConfiguration.Builder(getNavController().getGraph()).build();\n        NavigationUI.setupWithNavController(toolbarLayout, toolbar, getNavController(), appBarConfiguration);\n        showDialogIfNeeded();\n    }\n\n    @Override\n    public boolean onSupportNavigateUp() {\n        return NavigationUI.navigateUp(getNavController(), appBarConfiguration) || super.onSupportNavigateUp();\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/ui/PlacePickerActivity.java",
    "content": "/*\n * Copyright (C) 2013-2019 microG Project Team\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 org.microg.gms.ui;\n\nimport android.content.Intent;\nimport android.location.Address;\nimport android.location.Geocoder;\nimport android.location.Location;\nimport android.location.LocationManager;\nimport android.os.Bundle;\nimport android.text.Html;\nimport android.text.TextUtils;\nimport android.util.Log;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.appcompat.app.AppCompatActivity;\nimport androidx.appcompat.widget.SearchView;\nimport androidx.appcompat.widget.Toolbar;\nimport androidx.core.app.ActivityCompat;\nimport androidx.core.view.MenuItemCompat;\n\nimport com.google.android.gms.R;\nimport com.google.android.gms.common.api.CommonStatusCodes;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableSerializer;\nimport com.google.android.gms.location.places.internal.PlaceImpl;\nimport com.google.android.gms.maps.model.LatLng;\nimport com.google.android.gms.maps.model.LatLngBounds;\n\nimport org.microg.gms.location.LocationConstants;\n//import org.microg.gms.maps.vtm.BackendMapView;\n//import org.microg.gms.maps.vtm.GmsMapsTypeHelper;\n//import org.oscim.core.MapPosition;\n//import org.oscim.event.Event;\n//import org.oscim.map.Map;\n\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport static android.Manifest.permission.ACCESS_COARSE_LOCATION;\nimport static android.Manifest.permission.ACCESS_FINE_LOCATION;\nimport static android.content.pm.PackageManager.PERMISSION_GRANTED;\nimport static android.os.Build.VERSION.SDK_INT;\nimport static org.microg.gms.location.LocationConstants.EXTRA_PRIMARY_COLOR;\nimport static org.microg.gms.location.LocationConstants.EXTRA_PRIMARY_COLOR_DARK;\n//import static org.microg.gms.maps.vtm.GmsMapsTypeHelper.fromLatLngBounds;\n\npublic class\n\n\nPlacePickerActivity extends AppCompatActivity /*implements Map.UpdateListener*/ {\n    private static final String TAG = \"GmsPlacePicker\";\n\n    private PlaceImpl place;\n//    private BackendMapView mapView;\n    private Intent resultIntent;\n    private AtomicBoolean geocoderInProgress = new AtomicBoolean(false);\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        resultIntent = new Intent();\n        place = new PlaceImpl();\n\n        setContentView(R.layout.pick_place);\n\n        Toolbar toolbar = (Toolbar) findViewById(org.microg.tools.ui.R.id.toolbar);\n        setSupportActionBar(toolbar);\n        getSupportActionBar().setDisplayHomeAsUpEnabled(true);\n        getSupportActionBar().setDisplayShowHomeEnabled(true);\n\n        if (getIntent().hasExtra(EXTRA_PRIMARY_COLOR)) {\n            toolbar.setBackgroundColor(getIntent().getIntExtra(EXTRA_PRIMARY_COLOR, 0));\n            if (SDK_INT >= 21)\n                getWindow().setStatusBarColor(getIntent().getIntExtra(EXTRA_PRIMARY_COLOR_DARK, 0));\n            ((TextView) findViewById(R.id.place_picker_title)).setTextColor(getIntent().getIntExtra(EXTRA_PRIMARY_COLOR_DARK, 0));\n        }\n\n//        mapView = (BackendMapView) findViewById(R.id.map);\n//        mapView.map().getEventLayer().enableRotation(false);\n//        mapView.map().getEventLayer().enableTilt(false);\n//        mapView.map().events.bind(this);\n\n        LatLngBounds latLngBounds = getIntent().getParcelableExtra(LocationConstants.EXTRA_BOUNDS);\n        if (latLngBounds != null) {\n            place.viewport = latLngBounds;\n//            MapPosition mp = new MapPosition();\n//            mp.setByBoundingBox(fromLatLngBounds(latLngBounds), mapView.map().getWidth(), mapView.map().getHeight());\n//            mapView.map().getMapPosition(mp);\n        } else {\n            if (ActivityCompat.checkSelfPermission(PlacePickerActivity.this, ACCESS_FINE_LOCATION) != PERMISSION_GRANTED) {\n                ActivityCompat.requestPermissions(PlacePickerActivity.this, new String[]{ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION}, 0);\n            } else {\n                updateMapFromLocationManager();\n            }\n        }\n\n        findViewById(R.id.place_picker_select).setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                resultIntent.putExtra(LocationConstants.EXTRA_STATUS, SafeParcelableSerializer.serializeToBytes(new Status(CommonStatusCodes.SUCCESS)));\n                resultIntent.putExtra(LocationConstants.EXTRA_PLACE, SafeParcelableSerializer.serializeToBytes(place));\n                resultIntent.putExtra(LocationConstants.EXTRA_FINAL_BOUNDS, SafeParcelableSerializer.serializeToBytes(place.viewport));\n                setResult(RESULT_OK, resultIntent);\n                finish();\n            }\n        });\n    }\n\n    @SuppressWarnings(\"MissingPermission\")\n    private void updateMapFromLocationManager() {\n        LocationManager lm = (LocationManager) getSystemService(LOCATION_SERVICE);\n        Location last = null;\n        for (String provider : lm.getAllProviders()) {\n            if (lm.isProviderEnabled(provider)) {\n                Location t = lm.getLastKnownLocation(provider);\n                if (t != null && (last == null || t.getTime() > last.getTime())) {\n                    last = t;\n                }\n            }\n        }\n        Log.d(TAG, \"Set location to \" + last);\n        if (last != null) {\n//            mapView.map().setMapPosition(new MapPosition(last.getLatitude(), last.getLongitude(), 4096));\n        }\n    }\n\n    @Override\n    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {\n        super.onRequestPermissionsResult(requestCode, permissions, grantResults);\n        if (requestCode == 0) {\n            for (int grantResult : grantResults) {\n                if (grantResult != PERMISSION_GRANTED) return;\n            }\n            updateMapFromLocationManager();\n        }\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        super.onCreateOptionsMenu(menu);\n        MenuInflater inflater = getMenuInflater();\n        inflater.inflate(R.menu.pick_place, menu);\n        SearchView searchView = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.menu_action_search));\n        // TODO: search\n        return true;\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n//        mapView.onResume();\n    }\n\n    @Override\n    protected void onPause() {\n//        mapView.onPause();\n        super.onPause();\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(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        super.onDestroy();\n    }\n\n    /*\n    @Override\n    public void onMapEvent(Event event, MapPosition position) {\n//        place.viewport = GmsMapsTypeHelper.toLatLngBounds(mapView.map().viewport().getBBox(null, 0));\n//        resultIntent.putExtra(LocationConstants.EXTRA_FINAL_BOUNDS, place.viewport);\n//        place.latLng = GmsMapsTypeHelper.toLatLng(position.getGeoPoint());\n        place.name = \"\";\n        place.address = \"\";\n        updateInfoText();\n        if (geocoderInProgress.compareAndSet(false, true)) {\n            new Thread(new Runnable() {\n                @Override\n                public void run() {\n                    try {\n                        LatLng ll = null;\n                        while (ll != place.latLng) {\n                            ll = place.latLng;\n                            Thread.sleep(1000);\n                        }\n                        Geocoder geocoder = new Geocoder(PlacePickerActivity.this);\n                        List<Address> addresses = geocoder.getFromLocation(place.latLng.latitude, place.latLng.longitude, 1);\n                        if (addresses != null && !addresses.isEmpty() && addresses.get(0).getMaxAddressLineIndex() > 0) {\n                            Address address = addresses.get(0);\n                            StringBuilder sb = new StringBuilder(address.getAddressLine(0));\n                            for (int i = 1; i < address.getMaxAddressLineIndex(); ++i) {\n                                if (i == 1 && sb.toString().equals(address.getFeatureName())) {\n                                    sb = new StringBuilder(address.getAddressLine(i));\n                                    continue;\n                                }\n                                sb.append(\", \").append(address.getAddressLine(i));\n                            }\n                            if (place.latLng == ll) {\n                                place.address = sb.toString();\n                                place.name = address.getFeatureName();\n                                runOnUiThread(new Runnable() {\n                                    @Override\n                                    public void run() {\n                                        updateInfoText();\n                                    }\n                                });\n                            }\n                        }\n                    } catch (Exception ignored) {\n                        Log.w(TAG, ignored);\n                    } finally {\n                        geocoderInProgress.lazySet(false);\n                    }\n                }\n            }).start();\n        }\n    }*/\n\n    private void updateInfoText() {\n        if (TextUtils.isEmpty(place.address)) {\n            ((TextView) findViewById(R.id.place_picker_info)).setText(getString(R.string.place_picker_location_lat_lng, place.latLng.latitude, place.latLng.longitude));\n        } else if (TextUtils.isEmpty(place.name)) {\n            ((TextView) findViewById(R.id.place_picker_info)).setText(place.address);\n        } else {\n            ((TextView) findViewById(R.id.place_picker_info)).setText(Html.fromHtml(\"<b>\" + place.name + \"</b>, \" + place.address));\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/ui/SafetyNetAdvancedFragment.java",
    "content": "/*\n * Copyright (C) 2017 microG Project Team\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 org.microg.gms.ui;\n\nimport android.os.Bundle;\n\nimport androidx.annotation.Nullable;\nimport androidx.fragment.app.Fragment;\nimport androidx.preference.Preference;\n\nimport com.google.android.gms.R;\n\nimport org.microg.tools.ui.AbstractSettingsActivity;\nimport org.microg.tools.ui.RadioButtonPreference;\nimport org.microg.tools.ui.ResourceSettingsFragment;\n\n//import static org.microg.gms.safetynet.SafetyNetPrefs.PREF_SNET_OFFICIAL;\n//import static org.microg.gms.safetynet.SafetyNetPrefs.PREF_SNET_SELF_SIGNED;\n//import static org.microg.gms.safetynet.SafetyNetPrefs.PREF_SNET_THIRD_PARTY;\n\n//public class SafetyNetAdvancedFragment extends ResourceSettingsFragment {\n//\n//    public SafetyNetAdvancedFragment() {\n//        preferencesResource = R.xml.preferences_snet_advanced;\n//    }\n//\n//    private RadioButtonPreference radioOfficial;\n//    private RadioButtonPreference radioSelfSigned;\n//    private RadioButtonPreference radioThirdParty;\n//\n//    @Override\n//    public void onCreatePreferences(@Nullable Bundle savedInstanceState, String rootKey) {\n//        super.onCreatePreferences(savedInstanceState, rootKey);\n//\n//        radioOfficial = (RadioButtonPreference) findPreference(PREF_SNET_OFFICIAL);\n//        radioSelfSigned = (RadioButtonPreference) findPreference(PREF_SNET_SELF_SIGNED);\n//        radioThirdParty = (RadioButtonPreference) findPreference(PREF_SNET_THIRD_PARTY);\n//    }\n//\n//    @Override\n//    public boolean onPreferenceTreeClick(Preference preference) {\n//        if (preference == radioOfficial) {\n//            radioOfficial.setChecked(true);\n//            radioSelfSigned.setChecked(false);\n//            radioThirdParty.setChecked(false);\n//            return true;\n//        } else if (preference == radioSelfSigned) {\n//            radioOfficial.setChecked(false);\n//            radioSelfSigned.setChecked(true);\n//            radioThirdParty.setChecked(false);\n//            return true;\n//        } else if (preference == radioThirdParty) {\n//            radioOfficial.setChecked(false);\n//            radioSelfSigned.setChecked(false);\n//            radioThirdParty.setChecked(true);\n//            return true;\n//        }\n//        return super.onPreferenceTreeClick(preference);\n//    }\n//\n//    public static class AsActivity extends AbstractSettingsActivity {\n//        public AsActivity() {\n//            showHomeAsUp = true;\n//        }\n//\n//        @Override\n//        protected Fragment getFragment() {\n//            return new SafetyNetAdvancedFragment();\n//        }\n//    }\n//}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/ui/SelfCheckFragment.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.ui;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.CrossProfileApps;\nimport android.content.pm.PackageManager;\nimport android.content.pm.PermissionInfo;\nimport android.net.Uri;\nimport android.provider.Settings;\nimport android.util.Log;\nimport android.view.LayoutInflater;\n\nimport androidx.annotation.NonNull;\nimport androidx.fragment.app.Fragment;\n\nimport org.microg.gms.common.Constants;\nimport org.microg.tools.selfcheck.InstalledPackagesChecks;\n//import org.microg.tools.selfcheck.NlpOsCompatChecks;\n//import org.microg.tools.selfcheck.NlpStatusChecks;\nimport org.microg.tools.selfcheck.PermissionCheckGroup;\nimport org.microg.tools.selfcheck.RomSpoofSignatureChecks;\nimport org.microg.tools.selfcheck.SelfCheckGroup;\nimport org.microg.tools.selfcheck.SystemChecks;\nimport org.microg.tools.ui.AbstractSelfCheckFragment;\nimport org.microg.tools.ui.AbstractSettingsActivity;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Objects;\n\nimport static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION;\nimport static android.Manifest.permission.ACCESS_COARSE_LOCATION;\nimport static android.Manifest.permission.ACCESS_FINE_LOCATION;\nimport static android.Manifest.permission.GET_ACCOUNTS;\nimport static android.Manifest.permission.POST_NOTIFICATIONS;\nimport static android.Manifest.permission.READ_EXTERNAL_STORAGE;\nimport static android.Manifest.permission.READ_PHONE_STATE;\nimport static android.Manifest.permission.RECEIVE_SMS;\nimport static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;\nimport static android.os.Build.VERSION.SDK_INT;\n\npublic class SelfCheckFragment extends AbstractSelfCheckFragment {\n\n    @Override\n    protected void prepareSelfCheckList(Context context, List<SelfCheckGroup> checks) {\n        if (Objects.equals(context.getPackageName(), Constants.GMS_PACKAGE_NAME)) {\n            checks.add(new RomSpoofSignatureChecks());\n        }\n        checks.add(new InstalledPackagesChecks());\n        if (SDK_INT >= 23) {\n            List<String> permissions = new ArrayList<>();\n            permissions.add(ACCESS_COARSE_LOCATION);\n            permissions.add(ACCESS_FINE_LOCATION);\n            if (SDK_INT >= 29) {\n                permissions.add(ACCESS_BACKGROUND_LOCATION);\n            }\n            permissions.add(READ_EXTERNAL_STORAGE);\n            permissions.add(WRITE_EXTERNAL_STORAGE);\n            permissions.add(GET_ACCOUNTS);\n            if (SDK_INT >= 33) {\n                permissions.add(POST_NOTIFICATIONS);\n            }\n            permissions.add(READ_PHONE_STATE);\n            permissions.add(RECEIVE_SMS);\n            checks.add(new PermissionCheckGroup(permissions.toArray(new String[0])) {\n                @Override\n                public void doChecks(Context context, ResultCollector collector) {\n                    super.doChecks(context, collector);\n                    PackageManager pm = context.getPackageManager();\n                    // Add SYSTEM_ALERT_WINDOW appops permission\n                    try {\n                        PermissionInfo info = pm.getPermissionInfo(\"android.permission.SYSTEM_ALERT_WINDOW\", 0);\n                        CharSequence permLabel = info.loadLabel(pm);\n                        collector.addResult(\n                                context.getString(org.microg.tools.ui.R.string.self_check_name_permission, permLabel),\n                                Settings.canDrawOverlays(context) ? Result.Positive : Result.Negative,\n                                context.getString(org.microg.tools.ui.R.string.self_check_resolution_permission),\n                                fragment -> {\n                                    Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse(\"package:\" + context.getPackageName()));\n                                    startActivityForResult(intent, 42);\n                                }\n                        );\n                    } catch (Exception e) {\n                        Log.w(\"SelfCheckPerms\", e);\n                    }\n                    // Add INTERACT_ACROSS_PROFILES appop permission (INTERACT_ACROSS_USERS is superior)\n                    if (SDK_INT >= 30) try {\n                        CrossProfileApps crossProfile = context.getSystemService(CrossProfileApps.class);\n                        collector.addResult(\n                                context.getString(org.microg.tools.ui.R.string.self_check_name_permission_interact_across_profiles),\n                                context.checkSelfPermission(\"android.permission.INTERACT_ACROSS_USERS\") == PackageManager.PERMISSION_GRANTED\n                                        || crossProfile.canInteractAcrossProfiles() ? Result.Positive : Result.Negative,\n                                context.getString(org.microg.tools.ui.R.string.self_check_resolution_permission),\n                                crossProfile.canRequestInteractAcrossProfiles() ? fragment -> {\n                                    Intent intent = crossProfile.createRequestInteractAcrossProfilesIntent();\n                                    startActivityForResult(intent, 43);\n                                } : null\n                        );\n                    } catch (Exception e) {\n                        Log.w(\"SelfCheckPerms\", e);\n                    }\n                }\n            });\n        }\n        if (SDK_INT >= 23) {\n            checks.add(new SystemChecks());\n        }\n//        checks.add(new NlpOsCompatChecks());\n//        checks.add(new NlpStatusChecks());\n    }\n\n    @Override\n    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {\n        reset(LayoutInflater.from(getContext()));\n    }\n\n    @Override\n    public void onActivityResult(int requestCode, int resultCode, Intent data) {\n        reset(LayoutInflater.from(getContext()));\n        super.onActivityResult(requestCode, resultCode, data);\n    }\n\n    public static class AsActivity extends AbstractSettingsActivity {\n        public AsActivity() {\n            showHomeAsUp = true;\n        }\n\n        @Override\n        protected Fragment getFragment() {\n            return new SelfCheckFragment();\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/ui/SettingsDashboardActivity.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.ui;\n\nimport androidx.fragment.app.Fragment;\n\nimport com.google.android.gms.R;\n\n//import org.microg.nlp.Preferences;\nimport org.microg.tools.ui.AbstractDashboardActivity;\n\npublic class SettingsDashboardActivity extends AbstractDashboardActivity {\n\n    public SettingsDashboardActivity() {\n        preferencesResource = R.xml.preferences_start;\n        addCondition(Conditions.GCM_BATTERY_OPTIMIZATIONS);\n        addCondition(Conditions.PERMISSIONS);\n    }\n\n    @Override\n    protected Fragment getFragment() {\n        return new SettingsFragment();\n    }\n\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/wallet/OwServiceImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.wallet;\n\nimport android.content.Context;\nimport android.os.Bundle;\nimport android.os.Parcel;\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.wallet.GetClientTokenRequest;\nimport com.google.android.gms.wallet.GetClientTokenResponse;\nimport com.google.android.gms.wallet.IsReadyToPayRequest;\nimport com.google.android.gms.wallet.internal.IOwService;\nimport com.google.android.gms.wallet.internal.IWalletServiceCallbacks;\n\npublic class OwServiceImpl extends IOwService.Stub {\n    private static final String TAG = \"GmsWalletOwSvc\";\n    private Context context;\n\n    public OwServiceImpl(Context context) {\n        this.context = context;\n    }\n\n    @Override\n    public void isReadyToPay(IsReadyToPayRequest request, Bundle args, IWalletServiceCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"isReadyToPay: \" + request.toJson());\n        try {\n            callbacks.onIsReadyToPayResponse(Status.SUCCESS, false, Bundle.EMPTY);\n        } catch (Exception e) {\n            Log.w(TAG, e);\n        }\n    }\n\n    @Override\n    public void getClientToken(GetClientTokenRequest getClientTokenRequest, Bundle options, IWalletServiceCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"getClientToken: \" + options);\n        try {\n            callbacks.onClientTokenReceived(Status.INTERNAL_ERROR, new GetClientTokenResponse(), Bundle.EMPTY);\n        } catch (Exception e) {\n            Log.w(TAG, e);\n        }\n    }\n\n    @Override\n    public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {\n        if (super.onTransact(code, data, reply, flags)) return true;\n        Log.d(TAG, \"onTransact [unknown]: \" + code + \", \" + data + \", \" + flags);\n        return false;\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/gms/wallet/PaymentService.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.wallet;\n\nimport android.os.RemoteException;\n\nimport com.google.android.gms.common.Feature;\nimport com.google.android.gms.common.api.CommonStatusCodes;\nimport com.google.android.gms.common.internal.ConnectionInfo;\nimport com.google.android.gms.common.internal.GetServiceRequest;\nimport com.google.android.gms.common.internal.IGmsCallbacks;\n\nimport org.microg.gms.BaseService;\nimport org.microg.gms.common.GmsService;\n\npublic class PaymentService extends BaseService {\n\n    public static final Feature[] FEATURES = new Feature[]{\n        new Feature(\"wallet\", 1L),\n        new Feature(\"wallet_biometric_auth_keys\", 1L),\n        new Feature(\"wallet_payment_dynamic_update\", 2L),\n        new Feature(\"wallet_1p_initialize_buyflow\", 1L),\n        new Feature(\"wallet_warm_up_ui_process\", 1L),\n        new Feature(\"wallet_get_setup_wizard_intent\", 4L),\n        new Feature(\"wallet_get_payment_card_recognition_intent\", 1L),\n        new Feature(\"wallet_save_instrument\", 1L)\n    };\n\n    public PaymentService() {\n        super(\"GmsWalletPaySvc\", GmsService.WALLET);\n    }\n\n    @Override\n    public void handleServiceRequest(IGmsCallbacks callback, GetServiceRequest request, GmsService service) throws RemoteException {\n        ConnectionInfo connectionInfo = new ConnectionInfo();\n        connectionInfo.features = FEATURES;\n        callback.onPostInitCompleteWithConnectionInfo(CommonStatusCodes.SUCCESS, new OwServiceImpl(this), connectionInfo);\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/tools/AccountPickerActivity.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.tools;\n\nimport android.content.ComponentName;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport androidx.appcompat.app.AppCompatActivity;\n\n/**\n * This is just an activity that forwards to the systems native account picker\n */\npublic class AccountPickerActivity extends AppCompatActivity {\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        Bundle extras = getIntent().getExtras();\n        Intent intent = new Intent();\n        ComponentName componentName =\n                ComponentName.unflattenFromString(\"android/.accounts.ChooseTypeAndAccountActivity\");\n        intent.setClassName(componentName.getPackageName(), componentName.getClassName());\n        intent.putExtras(extras);\n        intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);\n        startActivity(intent);\n        finish();\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/tools/selfcheck/InstalledPackagesChecks.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.tools.selfcheck;\n\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.util.Log;\n\nimport androidx.fragment.app.Fragment;\n\nimport com.google.android.gms.R;\n\nimport org.microg.gms.common.Constants;\nimport org.microg.gms.common.PackageUtils;\n\nimport static org.microg.tools.selfcheck.SelfCheckGroup.Result.Negative;\nimport static org.microg.tools.selfcheck.SelfCheckGroup.Result.Positive;\n\npublic class InstalledPackagesChecks implements SelfCheckGroup {\n\n    @Override\n    public String getGroupName(Context context) {\n        return context.getString(R.string.self_check_cat_gms_packages);\n    }\n\n    @Override\n    public void doChecks(Context context, ResultCollector collector) {\n        addPackageInstalledAndSignedResult(context, collector, context.getString(R.string.self_check_pkg_gms), Constants.GMS_PACKAGE_NAME, Constants.GMS_PACKAGE_SIGNATURE_SHA1);\n        addPackageInstalledAndSignedResult(context, collector, context.getString(R.string.self_check_pkg_vending), Constants.VENDING_PACKAGE_NAME, Constants.GMS_PACKAGE_SIGNATURE_SHA1);\n        addPackageInstalledResult(context, collector, context.getString(R.string.self_check_pkg_gsf), Constants.GSF_PACKAGE_NAME);\n    }\n\n    private void addPackageInstalledAndSignedResult(Context context, ResultCollector collector, String nicePackageName, String androidPackageName, String signatureHash) {\n        if (addPackageInstalledResult(context, collector, nicePackageName, androidPackageName)) {\n            addPackageSignedResult(context, collector, nicePackageName, androidPackageName, signatureHash);\n        }\n    }\n\n    private boolean addPackageSignedResult(Context context, ResultCollector collector, String nicePackageName, String androidPackageName, String signatureHash) {\n        boolean hashMatches = signatureHash.equals(PackageUtils.firstSignatureDigest(context, androidPackageName, true)) &&\n                signatureHash.equals(PackageUtils.firstSignatureDigest(context, androidPackageName, false));\n        collector.addResult(context.getString(R.string.self_check_name_correct_sig, nicePackageName),\n                hashMatches ? Positive : Negative,\n                context.getString(R.string.self_check_resolution_correct_sig, nicePackageName),\n                fragment -> tryGrantFakeSignaturePermissionActivity(fragment, androidPackageName));\n        return hashMatches;\n    }\n\n    private void tryGrantFakeSignaturePermissionActivity(Fragment fragment, String androidPackageName) {\n        ComponentName grantPermissionActivity = new ComponentName(androidPackageName, androidPackageName + \".GrantFakeSignaturePermissionActivity\");\n        try {\n            Intent intent = new Intent();\n            intent.setPackage(androidPackageName);\n            intent.setComponent(grantPermissionActivity);\n            fragment.startActivityForResult(intent, 1);\n        } catch (Exception e) {\n            Log.w(\"SelfCheck\", e);\n        }\n    }\n\n    private boolean addPackageInstalledResult(Context context, ResultCollector collector, String nicePackageName, String androidPackageName) {\n        boolean packageExists = true;\n        try {\n            context.getPackageManager().getPackageInfo(androidPackageName, 0);\n        } catch (PackageManager.NameNotFoundException e) {\n            packageExists = false;\n        }\n        collector.addResult(context.getString(R.string.self_check_name_app_installed, nicePackageName), packageExists ? Positive : Negative,\n                context.getString(R.string.self_check_resolution_app_installed, nicePackageName));\n        return packageExists;\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/tools/selfcheck/RomSpoofSignatureChecks.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.tools.selfcheck;\n\nimport android.content.Context;\nimport android.content.pm.PackageManager;\n\nimport androidx.core.content.ContextCompat;\nimport androidx.fragment.app.Fragment;\n\nimport com.google.android.gms.R;\n\nimport org.microg.gms.common.Constants;\nimport org.microg.gms.common.PackageUtils;\n\nimport static android.content.pm.PackageManager.PERMISSION_GRANTED;\nimport static org.microg.gms.common.Constants.GMS_PACKAGE_SIGNATURE_SHA1;\nimport static org.microg.tools.selfcheck.SelfCheckGroup.Result.Negative;\nimport static org.microg.tools.selfcheck.SelfCheckGroup.Result.Positive;\nimport static org.microg.tools.selfcheck.SelfCheckGroup.Result.Unknown;\n\npublic class RomSpoofSignatureChecks implements SelfCheckGroup {\n\n    public static final String FAKE_SIGNATURE_PERMISSION = \"android.permission.FAKE_PACKAGE_SIGNATURE\";\n\n    @Override\n    public String getGroupName(Context context) {\n        return context.getString(R.string.self_check_cat_fake_sig);\n    }\n\n    @Override\n    public void doChecks(Context context, ResultCollector collector) {\n        addSystemSpoofsSignature(context, collector);\n    }\n\n    private boolean addSystemSpoofsSignature(Context context, ResultCollector collector) {\n        boolean knowsPermission = true;\n        try {\n            context.getPackageManager().getPermissionInfo(FAKE_SIGNATURE_PERMISSION, 0);\n        } catch (PackageManager.NameNotFoundException e) {\n            knowsPermission = false;\n        }\n        boolean grantsPermission = false;\n        if (knowsPermission) {\n            grantsPermission = ContextCompat.checkSelfPermission(context, FAKE_SIGNATURE_PERMISSION) == PERMISSION_GRANTED;\n        }\n        boolean spoofsSignature = GMS_PACKAGE_SIGNATURE_SHA1.equals(PackageUtils.firstSignatureDigest(context, Constants.GMS_PACKAGE_NAME, true)) &&\n                GMS_PACKAGE_SIGNATURE_SHA1.equals(PackageUtils.firstSignatureDigest(context, Constants.GMS_PACKAGE_NAME, false));\n        if (knowsPermission && !spoofsSignature && !grantsPermission) {\n            collector.addResult(\n                    context.getString(R.string.self_check_name_system_spoofs),\n                    spoofsSignature ? Positive : Negative,\n                    context.getString(org.microg.tools.ui.R.string.self_check_resolution_permission),\n                    fragment -> fragment.requestPermissions(new String[]{FAKE_SIGNATURE_PERMISSION}, 0)\n            );\n        } else {\n            collector.addResult(\n                    context.getString(R.string.self_check_name_system_spoofs),\n                    spoofsSignature ? Positive : Negative,\n                    context.getString(R.string.self_check_resolution_system_spoofs),\n                    fragment -> fragment.requestPermissions(new String[]{FAKE_SIGNATURE_PERMISSION}, 0)\n            );\n        }\n        return spoofsSignature;\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/java/org/microg/tools/selfcheck/SystemChecks.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.tools.selfcheck;\n\nimport android.annotation.TargetApi;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.os.PowerManager;\nimport android.provider.Settings;\n\nimport androidx.fragment.app.Fragment;\n\nimport com.google.android.gms.R;\n\nimport static org.microg.tools.selfcheck.SelfCheckGroup.Result.Negative;\nimport static org.microg.tools.selfcheck.SelfCheckGroup.Result.Positive;\n\n@TargetApi(23)\npublic class SystemChecks implements SelfCheckGroup, SelfCheckGroup.CheckResolver {\n\n    public static final int REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = 417;\n\n    @Override\n    public String getGroupName(Context context) {\n        return context.getString(R.string.self_check_cat_system);\n    }\n\n    @Override\n    public void doChecks(Context context, ResultCollector collector) {\n        isBatterySavingDisabled(context, collector);\n    }\n\n    private void isBatterySavingDisabled(final Context context, ResultCollector collector) {\n        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);\n        collector.addResult(context.getString(R.string.self_check_name_battery_optimizations),\n                pm.isIgnoringBatteryOptimizations(context.getPackageName()) ? Positive : Negative,\n                context.getString(R.string.self_check_resolution_battery_optimizations), this);\n    }\n\n    @Override\n    public void tryResolve(Fragment fragment) {\n        Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);\n        intent.setData(Uri.parse(\"package:\" + fragment.getActivity().getPackageName()));\n        fragment.startActivityForResult(intent, REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/com/google/android/gms/ads/AdActivity.kt",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 */\npackage com.google.android.gms.ads\n\nimport android.app.Activity\n\nclass AdActivity : Activity()\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/com/google/android/gms/ads/omid/AdSession.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.ads.omid\n\nclass AdSession\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/com/google/android/gms/ads/omid/DynamiteOmid.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.ads.omid\n\nimport android.os.RemoteException\nimport android.util.Log\nimport androidx.annotation.Keep\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.ObjectWrapper\n\nprivate const val TAG = \"Omid\"\n\n@Keep\nclass DynamiteOmid : IOmid.Stub() {\n    override fun initializeOmid(context: IObjectWrapper?): Boolean {\n        Log.d(TAG, \"initializeOmid\")\n        return true\n    }\n\n    override fun createHtmlAdSession(version: String, webView: IObjectWrapper?, customReferenceData: String, impressionOwner: String, altImpressionOwner: String): IObjectWrapper {\n        return createHtmlAdSessionWithPartnerName(version, webView, customReferenceData, impressionOwner, altImpressionOwner, \"Google\")\n    }\n\n    override fun startAdSession(adSession: IObjectWrapper?) {\n        Log.d(TAG, \"startAdSession\")\n    }\n\n    override fun registerAdView(adSession: IObjectWrapper?, view: IObjectWrapper?) {\n        Log.d(TAG, \"registerAdView\")\n    }\n\n    override fun getVersion(): String {\n        Log.d(TAG, \"getVersion\")\n        return \"1.5.0\"\n    }\n\n    override fun finishAdSession(adSession: IObjectWrapper?) {\n        Log.d(TAG, \"finishAdSession\")\n    }\n\n    override fun addFriendlyObstruction(adSession: IObjectWrapper?, view: IObjectWrapper?) {\n        Log.d(TAG, \"addFriendlyObstruction\")\n    }\n\n    override fun createHtmlAdSessionWithPartnerName(version: String, webView: IObjectWrapper?, customReferenceData: String, impressionOwner: String, altImpressionOwner: String, partnerName: String): IObjectWrapper {\n        Log.d(TAG, \"createHtmlAdSessionWithPartnerName($version, $customReferenceData, $impressionOwner, $altImpressionOwner, $partnerName)\")\n        return ObjectWrapper.wrap(AdSession())\n    }\n\n    override fun createJavascriptAdSessionWithPartnerNameImpressionCreativeType(version: String, webView: IObjectWrapper?, customReferenceData: String, impressionOwner: String, altImpressionOwner: String, partnerName: String, impressionType: String, creativeType: String, contentUrl: String): IObjectWrapper {\n        Log.d(TAG, \"createJavascriptAdSessionWithPartnerNameImpressionCreativeType($version, $customReferenceData, $impressionOwner, $altImpressionOwner, $partnerName, $impressionType, $creativeType, $contentUrl)\")\n        return ObjectWrapper.wrap(AdSession())\n    }\n\n    override fun createHtmlAdSessionWithPartnerNameImpressionCreativeType(version: String, webView: IObjectWrapper?, customReferenceData: String, impressionOwner: String, altImpressionOwner: String, partnerName: String, impressionType: String, creativeType: String, contentUrl: String): IObjectWrapper {\n        Log.d(TAG, \"createHtmlAdSessionWithPartnerNameImpressionCreativeType($version, $customReferenceData, $impressionOwner, $altImpressionOwner, $partnerName, $impressionType, $creativeType, $contentUrl)\")\n        return ObjectWrapper.wrap(AdSession())\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/com/google/android/gms/common/GoogleCertificatesImpl.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.common\n\nimport android.content.pm.PackageManager\nimport android.os.IBinder\nimport android.os.Parcel\nimport android.util.Log\nimport androidx.annotation.Keep\nimport com.google.android.gms.common.internal.CertData\nimport com.google.android.gms.common.internal.IGoogleCertificatesApi\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.ObjectWrapper\nimport org.microg.gms.common.PackageUtils\nimport org.microg.gms.common.isGooglePackage\nimport org.microg.gms.utils.ExtendedPackageInfo\nimport org.microg.gms.utils.getExtendedPackageInfo\nimport org.microg.gms.utils.isPlatformCertificate\nimport org.microg.gms.utils.warnOnTransactionIssues\n\nprivate const val TAG = \"GoogleCertificates\"\n\n@Keep\nclass GoogleCertificatesImpl : IGoogleCertificatesApi.Stub() {\n    private val googleCertificates = emptySet<CertData>()\n    private val googleReleaseCertificates = emptySet<CertData>()\n\n    override fun getGoogleCertificates(): IObjectWrapper {\n        Log.d(TAG, \"unimplemented Method: getGoogleCertificates\")\n        return ObjectWrapper.wrap(googleCertificates.toTypedArray<IBinder>())\n    }\n\n    override fun getGoogleReleaseCertificates(): IObjectWrapper {\n        Log.d(TAG, \"unimplemented Method: getGoogleReleaseCertificates\")\n        return ObjectWrapper.wrap(googleReleaseCertificates.toTypedArray<IBinder>())\n    }\n\n    override fun isGoogleReleaseSigned(packageName: String, certData: IObjectWrapper): Boolean {\n        return isGooglePackage(packageName, CertData.unwrap(certData) ?: return false)\n    }\n\n    override fun isGoogleSigned(packageName: String, certData: IObjectWrapper): Boolean {\n        return isGooglePackage(packageName, CertData.unwrap(certData) ?: return false)\n    }\n\n    override fun isGoogleOrPlatformSigned(query: GoogleCertificatesQuery?, packageManager: IObjectWrapper): Boolean {\n        val pm = ObjectWrapper.unwrapTyped(packageManager, PackageManager::class.java)\n        return when {\n            query?.callingPackage == null -> false\n            query.certData != null -> {\n                isGooglePackage(query.callingPackage, query.certData) || (pm != null && pm.isPlatformCertificate(query.certData))\n            }\n            pm != null -> pm.getExtendedPackageInfo(query.callingPackage).isGoogleOrPlatformPackage\n            else -> false\n        }\n    }\n\n    override fun isPackageGoogleOrPlatformSigned(query: GoogleCertificatesLookupQuery): GoogleCertificatesLookupResponse {\n        return certificateLookup(query, true)\n    }\n\n    override fun isPackageGoogleOrPlatformSignedAvailable(): Boolean {\n        return true\n    }\n\n    override fun queryPackageSigned(query: GoogleCertificatesLookupQuery): GoogleCertificatesLookupResponse {\n        if (!isFineGrainedPackageVerificationAvailable) throw IllegalStateException(\"API unavailable\")\n        return certificateLookup(query, false)\n    }\n\n    override fun isFineGrainedPackageVerificationAvailable(): Boolean {\n        return true\n    }\n\n    private fun certificateLookup(query: GoogleCertificatesLookupQuery, allowPlatform: Boolean): GoogleCertificatesLookupResponse {\n        val context = query.context\n            ?: return GoogleCertificatesLookupResponse(false, \"context is null\", 5, 1)\n        val packageManager = context.packageManager\n            ?: return GoogleCertificatesLookupResponse(false, \"context has no package manager\", 5, 1)\n        val callingPackage = query.callingPackage\n            ?: return GoogleCertificatesLookupResponse(false, \"callingPackage is null\", 5, 1)\n        val packageInfo = packageManager.getExtendedPackageInfo(callingPackage)\n        if (!packageInfo.isInstalled)\n            return GoogleCertificatesLookupResponse(false, \"callingPackage not found\", 4, 1)\n        return if (packageInfo.isGooglePackage || (allowPlatform && packageInfo.isPlatformPackage)) {\n            GoogleCertificatesLookupResponse(true, null, 1, 3)\n        } else {\n            GoogleCertificatesLookupResponse(false, \"not allowed\", 2, 1)\n        }\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =\n        warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/com/google/android/gms/credential/manager/PasswordManagerActivity.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.credential.manager\n\nimport android.content.Intent\nimport android.net.Uri\nimport android.os.Bundle\nimport android.util.Log\nimport androidx.appcompat.app.AppCompatActivity\n\nconst val PASSWORD_MANAGER_CLASS_NAME = \"com.google.android.gms.credential.manager.PasswordManagerActivity\"\n\nconst val EXTRA_KEY_ACCOUNT_NAME = \"pwm.DataFieldNames.accountName\"\n\nprivate const val TAG = \"PasswordManagerActivity\"\n\nprivate const val PSW_MANAGER_PATH = \"https://passwords.google.com/\"\n\nclass PasswordManagerActivity : AppCompatActivity() {\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        Log.d(TAG, \"onCreate: start\")\n        val targetIntent = Intent(Intent.ACTION_VIEW, Uri.parse(PSW_MANAGER_PATH))\n        val resolveInfoList = packageManager.queryIntentActivities(targetIntent, 0)\n        Log.d(TAG, \"resolveInfoList: $resolveInfoList\")\n        if (resolveInfoList.isNotEmpty()) {\n            startActivity(targetIntent)\n        }\n        finish()\n    }\n\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/com/google/android/gms/family/v2/manage/DeleteMemberActivity.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.family.v2.manage\n\nimport android.os.Bundle\nimport android.view.View\nimport androidx.activity.compose.setContent\nimport androidx.activity.viewModels\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.fragment.app.commit\nimport com.google.android.gms.family.v2.manage.fragment.FamilyDeleteFragment\nimport com.google.android.gms.family.v2.manage.model.FamilyViewModel\nimport com.google.android.gms.family.v2.manage.ui.FamilyActivityScreen\n\nclass DeleteMemberActivity : AppCompatActivity() {\n\n    private val familyViewModel by viewModels<FamilyViewModel>()\n\n    private val themeType: String?\n        get() = intent?.getStringExtra(EXTRA_KEY_PREDEFINED_THEME)\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        val callingPackageName = callingPackage ?: callingActivity?.packageName\n        if (callingPackageName.isNullOrEmpty()) {\n            errorResult(\"DeleteMemberActivity: callingPackageName is empty\", -3)\n            return finish()\n        }\n        val extras = intent.extras\n        if (extras == null) {\n            errorResult(\"DeleteMemberActivity: extras is empty\", -3)\n            return finish()\n        }\n        setContent {\n            FamilyActivityScreen(\n                viewModel = familyViewModel,\n                type = themeType,\n                addFragment = { addDeleteFragment(it, extras) },\n                onBackClick = { onBackPressed() }\n            )\n        }\n    }\n\n    private fun addDeleteFragment(container: View, bundle: Bundle) {\n        val activity = container.context as? AppCompatActivity\n        val fragmentManager = activity?.supportFragmentManager\n        val containerId = container.id\n        fragmentManager?.apply {\n            if (findFragmentByTag(FamilyDeleteFragment.TAG) == null) {\n                val deleteFragment = FamilyDeleteFragment.newInstance(bundle)\n                commit {\n                    setReorderingAllowed(true)\n                    replace(containerId, deleteFragment, FamilyDeleteFragment.TAG)\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/com/google/android/gms/family/v2/manage/FamilyApiClient.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.family.v2.manage\n\nimport android.content.Context\nimport android.util.Log\nimport com.google.android.gms.family.model.MemberDataModel\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\nimport okhttp3.MediaType.Companion.toMediaTypeOrNull\nimport okhttp3.OkHttpClient\nimport okhttp3.Request\nimport okhttp3.RequestBody.Companion.toRequestBody\nimport org.microg.gms.common.Constants\nimport org.microg.gms.family.DeleteOperationRequest\nimport org.microg.gms.family.DeleteOperationResponse\nimport org.microg.gms.family.FamilyRole\nimport org.microg.gms.family.GetFamilyManagementConfigRequest\nimport org.microg.gms.family.GetFamilyManagementConfigResponse\nimport org.microg.gms.family.GetFamilyManagementPageContentResponse\nimport org.microg.gms.family.GetFamilyRequest\nimport org.microg.gms.family.GetFamilyResponse\nimport org.microg.gms.family.MemberInfo\nimport org.microg.gms.family.PlaceHolder\nimport org.microg.gms.family.ReAuthProofTokensRequest\nimport org.microg.gms.profile.Build\n\nobject FamilyApiClient {\n\n    private val FAMILY_RE_AUTH_PROOF_TOKENS_USER_AGENT = \"${Constants.GMS_PACKAGE_NAME}/ ${Constants.GMS_VERSION_CODE} (Linux; Android ${Build.VERSION.RELEASE}; ${Build.MODEL} Build/${Build.ID};)\"\n\n    suspend fun loadFamilyData(\n        context: Context,\n        oauthToken: String?,\n        appId: String,\n        flag: Int\n    ): GetFamilyResponse? = withContext(Dispatchers.IO) {\n        val requestContext = buildRequestContext(appId)\n        val request = GetFamilyRequest.build {\n            context(requestContext)\n            flag(flag)\n        }\n        Log.d(TAG, \"getFamily request: $request\")\n        familyGrpcClient(context, oauthToken).GetFamily().executeBlocking(request)\n    }\n\n    suspend fun loadFamilyManagementPageContent(\n        context: Context,\n        oauthToken: String?,\n        appId: String,\n        memberId: String,\n        currentMember: MemberDataModel,\n        leaveFamily: Boolean = false\n    ): GetFamilyManagementPageContentResponse? = withContext(Dispatchers.IO) {\n        val requestContext = buildRequestContext(appId)\n        val request = GetFamilyRequest.build {\n            val type = if (leaveFamily) {\n                FAMILY_FLAG_PAGE_CONTENT_REMOVE_MEMBER\n            } else if (currentMember.role == FamilyRole.HEAD_OF_HOUSEHOLD.value) {\n                FAMILY_FLAG_PAGE_CONTENT_DELETE_FAMILY\n            } else {\n                FAMILY_FLAG_PAGE_CONTENT_LEAVE_FAMILY\n            }\n            context(requestContext)\n            flag(type)\n            if (leaveFamily && memberId.isNotEmpty()) {\n                memberInfo(MemberInfo.build { memberId(memberId) })\n            } else {\n                placeHolder(PlaceHolder())\n            }\n        }\n        Log.d(TAG, \"getFamilyManagementPageContent request: $request\")\n        familyGrpcClient(context, oauthToken).GetFamilyManagementPageContent().executeBlocking(request)\n    }\n\n    suspend fun loadFamilyManagementConfig(\n        context: Context,\n        oauthToken: String?,\n        appId: String,\n        directAdd: Boolean = false\n    ): GetFamilyManagementConfigResponse? = withContext(Dispatchers.IO) {\n        val requestContext = buildRequestContext(appId)\n        val request = GetFamilyManagementConfigRequest.build {\n            context(requestContext)\n            directAdd(directAdd)\n        }\n        Log.d(TAG, \"getFamilyManagementConfig request: $request\")\n        familyGrpcClient(context, oauthToken).GetFamilyManagementConfig().executeBlocking(request)\n    }\n\n    suspend fun deleteInvitationMember(\n        context: Context,\n        oauthToken: String?,\n        appId: String,\n        memberId: String\n    ): DeleteOperationResponse? = withContext(Dispatchers.IO) {\n        val requestContext = buildRequestContext(appId)\n        val request = DeleteOperationRequest.build {\n            context(requestContext)\n            placeHolder(PlaceHolder())\n            memberId(memberId)\n        }\n        Log.d(TAG, \"deleteInvitation request: $request\")\n        familyGrpcClient(context, oauthToken).DeleteInvitation().executeBlocking(request)\n    }\n\n    suspend fun deleteMember(\n        context: Context,\n        oauthToken: String?,\n        appId: String,\n        memberId: String\n    ): DeleteOperationResponse? = withContext(Dispatchers.IO) {\n        val requestContext = buildRequestContext(appId)\n        val request = DeleteOperationRequest.build {\n            context(requestContext)\n            memberId(memberId)\n        }\n        Log.d(TAG, \"deleteMember request: $request\")\n        familyGrpcClient(context, oauthToken).DeleteMember().executeBlocking(request)\n    }\n\n    suspend fun deleteFamily(\n        context: Context,\n        oauthToken: String?,\n        appId: String,\n    ): DeleteOperationResponse? = withContext(Dispatchers.IO) {\n        val requestContext = buildRequestContext(appId)\n        val request = DeleteOperationRequest.build { context(requestContext) }\n        Log.d(TAG, \"deleteFamily request: $request\")\n        familyGrpcClient(context, oauthToken).DeleteFamily().executeBlocking(request)\n    }\n\n    suspend fun validatePassword(oauthToken: String?, password: String) = withContext(Dispatchers.IO) {\n        runCatching {\n            val client = OkHttpClient()\n            val mediaType = \"application/x-protobuf\".toMediaTypeOrNull()\n            val reAuthRequest = ReAuthProofTokensRequest.build {\n                type(2)\n                password(password)\n            }.encode()\n            val requestBody = reAuthRequest.toRequestBody(mediaType)\n\n            val request = Request.Builder()\n                .url(FAMILY_RE_AUTH_PROOF_TOKENS_URL)\n                .post(requestBody)\n                .addHeader(\"Authorization\", \"Bearer $oauthToken\")\n                .addHeader(\"Content-Type\", \"application/x-protobuf\")\n                .addHeader(\"User-Agent\", FAMILY_RE_AUTH_PROOF_TOKENS_USER_AGENT)\n                .build()\n            val response = client.newCall(request).execute()\n            if (response.code != 200) {\n                throw RuntimeException(\"Invalid response code: ${response.code} body: ${response.body?.string()}\")\n            }\n            true\n        }.onFailure {\n            Log.d(TAG, \"requestReAuthProofTokens: failed \", it)\n        }.getOrDefault(false)\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/com/google/android/gms/family/v2/manage/FamilyExtensions.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.family.v2.manage\n\nimport android.app.Activity\nimport android.content.Context\nimport android.content.Intent\nimport android.os.LocaleList\nimport android.util.Log\nimport android.widget.Toast\nimport androidx.compose.ui.unit.Dp\nimport androidx.core.net.toUri\nimport com.google.android.gms.R\nimport com.google.android.gms.family.model.MemberDataModel\nimport com.google.android.gms.family.v2.model.BulletPoint\nimport com.google.android.gms.family.v2.model.HelpData\nimport com.google.android.gms.family.v2.model.PageData\nimport com.squareup.wire.GrpcClient\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\nimport okhttp3.OkHttpClient\nimport org.microg.gms.auth.AuthConstants\nimport org.microg.gms.auth.AuthManager\nimport org.microg.gms.checkin.LastCheckinInfo\nimport org.microg.gms.common.Constants\nimport org.microg.gms.family.CallerInfo\nimport org.microg.gms.family.DeviceInfo\nimport org.microg.gms.family.FamilyBulletPoint\nimport org.microg.gms.family.FamilyHelpLink\nimport org.microg.gms.family.FamilyPageBody\nimport org.microg.gms.family.FamilyRole\nimport org.microg.gms.family.GetFamilyManagementConfigResponse\nimport org.microg.gms.family.GetFamilyResponse\nimport org.microg.gms.family.GrpcFamilyManagementServiceClient\nimport org.microg.gms.family.RequestContext\nimport org.microg.gms.profile.Build\nimport java.text.DateFormat\nimport java.util.Date\nimport java.util.Locale\n\nconst val TAG = \"FamilyManagement\"\n\nconst val ACTION_FAMILY_MANAGEMENT = \"com.google.android.gms.family.v2.MANAGE\"\n\nconst val EXTRA_KEY_APP_ID = \"appId\"\nconst val EXTRA_KEY_PREDEFINED_THEME = \"predefinedTheme\"\nconst val EXTRA_KEY_ACCOUNT_NAME = \"accountName\"\nconst val EXTRA_KEY_ERROR_CODE = \"errorCode\"\nconst val EXTRA_KEY_FAMILY_CHANGED = \"familyChanged\"\nconst val EXTRA_KEY_CONSISTENCY_TOKEN = \"consistencyToken\"\nconst val EXTRA_KEY_TOKEN_EXPIRATION_TIME_SECS = \"tokenExpirationTimeSecs\"\nconst val EXTRA_KEY_CALLING_PACKAGE_NAME = \"callingPackageName\"\nconst val EXTRA_KEY_MEMBER_MODEL = \"memberDataModel\"\nconst val EXTRA_KEY_MEMBER_ID = \"memberId\"\nconst val EXTRA_KEY_MEMBER_GIVEN_NAME= \"memberGivenName\"\nconst val EXTRA_KEY_MEMBER_LEAVE_FAMILY= \"leaveFamily\"\nconst val EXTRA_KEY_MEMBER_HOH_GIVEN_NAME = \"hohGivenName\"\nconst val EXTRA_KEY_CLIENT_CALLING_PACKAGE = \"clientCallingPackage\"\n\nconst val FAMILY_MANAGEMENT_MODULE_VERSION = \"228\"\nconst val FAMILY_MANAGEMENT_MODULE_DASHBOARD = \"family_module_management_dashboard\"\nconst val FAMILY_MANAGEMENT_BASE_URL = \"https://familymanagement-pa.googleapis.com/\"\nconst val FAMILY_LINK_MEMBER_BASE_URL = \"https://familylink.google.com/member/\"\nconst val FAMILY_MANAGEMENT_DEFAULT_USER_AGENT = \"grpc-java-okhttp/1.66.0-SNAPSHOT\"\n\nconst val FAMILY_PAGE_CONTENT_TEXT_INDEX = 3\nconst val FAMILY_PAGE_CONTENT_POSITIVE_BUTTON_INDEX = 4\nconst val FAMILY_PAGE_CONTENT_NEGATIVE_BUTTON_INDEX = 5\nconst val FAMILY_PAGE_CONTENT_TITLE_INDEX = 28\n\nconst val FAMILY_PAGE_CONTENT_FLAG_MEMBER_LIST = 1\nconst val FAMILY_FLAG_PAGE_CONTENT_DELETE_FAMILY = 9\nconst val FAMILY_FLAG_PAGE_CONTENT_REMOVE_MEMBER = 10\nconst val FAMILY_FLAG_PAGE_CONTENT_LEAVE_FAMILY = 11\n\nconst val FAMILY_OPTION_INVITE_TITLE_ID = 19\nconst val FAMILY_OPTION_INVITE_ID = 20\n\nconst val FAMILY_RE_AUTH_PROOF_TOKENS_URL = \"https://www.googleapis.com/reauth/v1beta/users/me/reauthProofTokens?alt=proto\"\nconst val FAMILY_INVITE_MEMBER_URL = \"https://myaccount.google.com/embedded/family/invitemembers\"\n\nprivate const val FAMILY_SCOPE = \"https://www.googleapis.com/auth/kid.family\"\nval SERVICE_FAMILY_SCOPE: String\n    get() = \"${AuthConstants.SCOPE_OAUTH2}${FAMILY_SCOPE}\"\nprivate const val FAMILY_RE_AUTH_SCOPE = \"https://www.googleapis.com/auth/accounts.reauth\"\nval SERVICE_FAMILY_RE_AUTH_SCOPE: String\n    get() = \"${AuthConstants.SCOPE_OAUTH2}${FAMILY_RE_AUTH_SCOPE}\"\n\nfun Dp.toPx(context: Context): Int = (this.value * context.resources.displayMetrics.density).toInt()\n\nfun familyGrpcClient(context: Context, oauthToken: String?): GrpcFamilyManagementServiceClient {\n    val okHttpClient = OkHttpClient.Builder().addInterceptor { chain ->\n        val original = chain.request()\n        val requestBuilder = original.newBuilder().header(\"te\", \"trailers\").header(\"x-device-id\", LastCheckinInfo.read(context).androidId.toString(16)).header(\"authorization\", \"Bearer $oauthToken\")\n            .header(\"user-agent\", FAMILY_MANAGEMENT_DEFAULT_USER_AGENT)\n            .header(\"accept-language\", if (Build.VERSION.SDK_INT >= 24) LocaleList.getDefault().toLanguageTags() else Locale.getDefault().language).removeHeader(\"grpc-trace-bin\")\n        val request = requestBuilder.build()\n        chain.proceed(request)\n    }.build()\n    val grpcClient = GrpcClient.Builder().client(okHttpClient).baseUrl(FAMILY_MANAGEMENT_BASE_URL).minMessageToCompress(Long.MAX_VALUE).build()\n    return GrpcFamilyManagementServiceClient(grpcClient)\n}\n\nfun buildRequestContext(appId: String): RequestContext {\n    val deviceInfo = DeviceInfo.build {\n        moduleVersion(FAMILY_MANAGEMENT_MODULE_VERSION)\n        clientType(7)\n        moduleInfo(CallerInfo.build { appId(appId) })\n    }\n    return RequestContext.build {\n        deviceInfo(deviceInfo)\n        familyExperimentOverrides(\"\")\n        moduleSet(\"\")\n    }\n}\n\nsuspend fun requestOauthToken(context: Context, accountName: String, service: String): String {\n    val authResponse = withContext(Dispatchers.IO) {\n        AuthManager(\n            context, accountName, Constants.GMS_PACKAGE_NAME, service\n        ).apply { isPermitted = true }.requestAuth(true)\n    }\n    return authResponse.auth ?: throw RuntimeException(\"oauthToken is null\")\n}\n\nfun GetFamilyResponse.parseToMemberDataModels(context: Context, accountName: String, configResponse: GetFamilyManagementConfigResponse?): MutableList<MemberDataModel> {\n    val inviteSlotSize = configResponse?.let {\n        val inviteOption = it.configMain?.familyOption?.find { option -> option.optionId == FAMILY_OPTION_INVITE_ID }\n        val inviteSlotsContent = inviteOption?.optionContents?.find { c -> c.optId == FAMILY_OPTION_INVITE_TITLE_ID }?.content\n        inviteSlotsContent?.let { content -> Regex(\"\\\\d+\").find(content)?.value?.toIntOrNull() ?: 0 } ?: 0\n    } ?: 0\n    val memberDataModels = mutableListOf<MemberDataModel>()\n    memberDataList.map {\n        MemberDataModel().apply {\n            memberId = it.memberId ?: \"\"\n            profilePhotoUrl = it.profile?.profilePhotoUrl ?: it.profile?.defaultPhotoUrl ?: \"\"\n            displayName = it.profile?.displayName ?: it.profile?.email ?: \"\"\n            email = it.profile?.email ?: \"\"\n            hohGivenName = it.hohGivenName ?: \"\"\n            role = it.role?.value ?: FamilyRole.UNCONFIRMED_MEMBER.value\n            roleName = it.role?.name ?: FamilyRole.UNCONFIRMED_MEMBER.name\n        }\n    }.forEach { memberDataModels.add(it) }\n    invitationList.map {\n        MemberDataModel().apply {\n            memberId = it.invitationId ?: \"\"\n            profilePhotoUrl = it.profile?.profilePhotoUrl ?: it.profile?.defaultPhotoUrl ?: \"\"\n            displayName = it.profile?.displayName ?: it.profile?.email ?: \"\"\n            email = it.profile?.email ?: \"\"\n            hohGivenName = context.resources.getString(R.string.family_management_invite_send)\n            role = it.role?.value ?: FamilyRole.UNCONFIRMED_MEMBER.value\n            roleName = it.role?.name ?: FamilyRole.UNCONFIRMED_MEMBER.name\n            isInvited = true\n            invitationId = it.invitationId ?: \"\"\n            inviteState = it.inviteState ?: 0\n            inviteSentDate = when {\n                inviteState <= 0 -> \"\"\n                else -> runCatching {\n                    val locale = if (Build.VERSION.SDK_INT >= 24) {\n                        context.resources.configuration.locales[0]\n                    } else {\n                        context.resources.configuration.locale\n                    }\n                    context.getString(\n                        R.string.family_management_invite_sent_date_format, DateFormat.getDateInstance(DateFormat.MEDIUM, locale).format(Date(inviteState))\n                    )\n                }.getOrDefault(\"\")\n            }\n        }\n    }.forEach { memberDataModels.add(it) }\n    if (memberDataModels.any { it.email == accountName && it.role == FamilyRole.HEAD_OF_HOUSEHOLD.value } && inviteSlotSize > 0) {\n        memberDataModels.add(\n            MemberDataModel().apply {\n                isInviteEntry = true\n                inviteSlots = inviteSlotSize\n            }\n        )\n    }\n    return memberDataModels\n}\n\nfun FamilyPageBody.parseToPageData(): PageData {\n    val sectionMap = HashMap<Int?, String?>()\n    val helpMap = HashMap<String?, HelpData?>()\n    val bps = ArrayList<BulletPoint?>()\n    for (section in sections) {\n        sectionMap.put(section.sectionId, section.content)\n    }\n    for (link in helpLinks) {\n        helpMap.put(link.tag, link.parseToHelpData())\n    }\n    for (bp in bulletPoints) {\n        bps.add(bp.parseToBulletPoint())\n    }\n    return PageData(sectionMap, helpMap, bps)\n}\n\nprivate fun FamilyBulletPoint.parseToBulletPoint(): BulletPoint {\n    val contentMap = HashMap<Int, String>()\n    if (items.isNotEmpty()) {\n        items.filter {\n            it.sectionId != null && it.content != null\n        }.forEach {\n            contentMap.put(it.sectionId!!, it.content!!)\n        }\n    }\n    return BulletPoint(contentMap)\n}\n\nprivate fun FamilyHelpLink.parseToHelpData(): HelpData {\n    return HelpData(url, appContext)\n}\n\nfun buildFamilyInviteUrl(callerAppId: String?): String {\n    return FAMILY_INVITE_MEMBER_URL.toUri().buildUpon()\n        .appendQueryParameter(\"app_id\", callerAppId?.let { (it.transformToInt() - 2).toString() })\n        .appendQueryParameter(\"referrer_flow\", FAMILY_MANAGEMENT_MODULE_DASHBOARD)\n        .build().toString()\n}\n\nprivate fun String.transformToInt() = when (this) {\n    \"ytu\" -> 4\n    \"g1\" -> 5\n    \"pfl\" -> 6\n    \"pfpp\" -> 7\n    \"agsa\" -> 8\n    \"asm\" -> 9\n    \"calendar\" -> 10\n    \"ytm\" -> 11\n    \"ytr\" -> 12\n    \"famlink\" -> 13\n    \"com.google.android.gms\" -> 14\n    \"yt-main\" -> 15\n    \"yt-fc\" -> 17\n    \"yt-tandem\" -> 18\n    else -> 2\n}\n\nfun Activity.showToast(message: String) {\n    Toast.makeText(this, message, Toast.LENGTH_SHORT).show()\n}\n\nfun Activity.errorResult(msg: String, code: Int? = null, accountName: String? = null) {\n    Log.d(TAG, \"errorResult: $msg\")\n    if (code != null) {\n        setResult(4, Intent().apply {\n            putExtra(EXTRA_KEY_ACCOUNT_NAME, accountName)\n            putExtra(EXTRA_KEY_ERROR_CODE, code)\n        })\n    } else setResult(4)\n}\n\nfun Activity.onResult(accountName: String?, consistencyToken: String? = null) {\n    val result = Intent().apply {\n        putExtra(EXTRA_KEY_ACCOUNT_NAME, accountName)\n        putExtra(EXTRA_KEY_FAMILY_CHANGED, true)\n    }\n    consistencyToken?.let {\n        result.putExtra(EXTRA_KEY_CONSISTENCY_TOKEN, it)\n        result.putExtra(EXTRA_KEY_TOKEN_EXPIRATION_TIME_SECS, 300)\n    }\n    setResult(3, result)\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/com/google/android/gms/family/v2/manage/FamilyManagementActivity.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.family.v2.manage\n\nimport android.content.Intent\nimport android.os.Bundle\nimport android.util.Log\nimport android.view.View\nimport androidx.activity.compose.setContent\nimport androidx.activity.result.contract.ActivityResultContracts\nimport androidx.activity.viewModels\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.fragment.app.commit\nimport androidx.lifecycle.lifecycleScope\nimport com.google.android.gms.family.model.MemberDataModel\nimport com.google.android.gms.family.v2.manage.fragment.FamilyManagementFragment\nimport com.google.android.gms.family.v2.manage.fragment.MemberDetailFragment\nimport com.google.android.gms.family.v2.manage.model.FamilyViewModel\nimport com.google.android.gms.family.v2.manage.ui.FamilyActivityScreen\nimport kotlinx.coroutines.launch\nimport org.microg.gms.profile.ProfileManager\n\nclass FamilyManagementActivity : AppCompatActivity() {\n    private val familyViewModel by viewModels<FamilyViewModel>()\n    private var deleteFamily = false\n    private val callerAppId: String?\n        get() = intent?.getStringExtra(EXTRA_KEY_APP_ID)\n    private val accountName: String?\n        get() = intent?.getStringExtra(EXTRA_KEY_ACCOUNT_NAME)\n    private val themeType: String?\n        get() = intent?.getStringExtra(EXTRA_KEY_PREDEFINED_THEME)\n\n    private val deletedLauncher = registerForActivityResult(\n        ActivityResultContracts.StartActivityForResult()\n    ) { result ->\n        val consistencyToken = result.data?.getStringExtra(EXTRA_KEY_CONSISTENCY_TOKEN)\n        Log.d(TAG, \"consistencyToken: $consistencyToken\")\n        if (consistencyToken != null) {\n            if (!deleteFamily && backToManagement()) {\n                familyViewModel.refreshData()\n                return@registerForActivityResult\n            }\n            onResult(accountName, consistencyToken)\n            finish()\n        }\n    }\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        if (intent?.action != null && intent.action != ACTION_FAMILY_MANAGEMENT) {\n            errorResult(\"FamilyManagementActivity: Intent has unexpected action\")\n            return finish()\n        }\n\n        val callingPackageName = callingPackage ?: callingActivity?.packageName\n\n        if (callingPackageName.isNullOrEmpty()) {\n            errorResult(\"FamilyManagementActivity: callingPackageName is empty\", -3)\n            return finish()\n        }\n\n        if (accountName.isNullOrEmpty()) {\n            errorResult(\"FamilyManagementActivity: accountName is empty\", -2)\n            return finish()\n        }\n\n        ProfileManager.ensureInitialized(this)\n        setContent {\n            FamilyActivityScreen(\n                viewModel = familyViewModel,\n                type = themeType,\n                addFragment = { addManagementFragment(it, callingPackageName) },\n                onBackClick = { onBackPressed() },\n                onMoreClick = { currentMember, leave -> executeFamilyGroupByAction(currentMember, callingPackageName, leave) }\n            )\n        }\n        lifecycleScope.launch {\n            familyViewModel.selectedMember.collect {\n                val containerId = it.first\n                val member = it.second\n                if (containerId != null) {\n                    val detailFragment = MemberDetailFragment.newInstance(member, accountName!!, callerAppId!!)\n                    val managementFragment = supportFragmentManager.findFragmentByTag(FamilyManagementFragment.TAG)\n                    val transaction = supportFragmentManager.beginTransaction()\n                    if (managementFragment != null) {\n                        transaction.hide(managementFragment).add(containerId, detailFragment, MemberDetailFragment.TAG)\n                    } else{\n                        transaction.replace(containerId, detailFragment, MemberDetailFragment.TAG)\n                    }\n                    transaction.commit()\n                    return@collect\n                }\n                executeFamilyGroupByAction(member, callingPackageName, true)\n            }\n        }\n    }\n\n    override fun onBackPressed() {\n        if (backToManagement()) {\n            return\n        }\n        super.onBackPressed()\n    }\n\n    private fun backToManagement(): Boolean {\n        try {\n            val memberDetailFragment = supportFragmentManager.findFragmentByTag(MemberDetailFragment.TAG)\n            if (memberDetailFragment != null) {\n                val managementFragment = supportFragmentManager.findFragmentByTag(FamilyManagementFragment.TAG)\n                if (managementFragment != null) {\n                    supportFragmentManager.beginTransaction().show(managementFragment).remove(memberDetailFragment).commit()\n                    return true\n                }\n            }\n        } catch (e: Exception){\n            Log.d(TAG, \"backToManagement: \", e)\n        }\n        return false\n    }\n\n    private fun addManagementFragment(container: View, callingPackage: String) {\n        val activity = container.context as? AppCompatActivity\n        val fragmentManager = activity?.supportFragmentManager\n        val containerId = container.id\n\n        fragmentManager?.apply {\n            if (findFragmentByTag(FamilyManagementFragment.TAG) == null) {\n                val managementFragment = FamilyManagementFragment.newInstance(accountName!!, callerAppId!!, callingPackage)\n                commit {\n                    setReorderingAllowed(true)\n                    replace(containerId, managementFragment, FamilyManagementFragment.TAG)\n                }\n            }\n        }\n    }\n\n    private fun executeFamilyGroupByAction(member: MemberDataModel, callingPackageName: String, leaveFamily: Boolean) {\n        deleteFamily = !leaveFamily\n        deletedLauncher.launch(Intent(this, DeleteMemberActivity::class.java).apply {\n            putExtra(EXTRA_KEY_ACCOUNT_NAME, accountName)\n            putExtra(EXTRA_KEY_APP_ID, callerAppId)\n            putExtra(EXTRA_KEY_PREDEFINED_THEME, themeType)\n            putExtra(EXTRA_KEY_CLIENT_CALLING_PACKAGE, callingPackageName)\n            putExtra(EXTRA_KEY_MEMBER_ID, member.memberId)\n            putExtra(EXTRA_KEY_MEMBER_GIVEN_NAME, member.displayName.ifEmpty { member.email })\n            putExtra(EXTRA_KEY_MEMBER_HOH_GIVEN_NAME, member.hohGivenName.ifEmpty { member.roleName })\n            putExtra(EXTRA_KEY_MEMBER_LEAVE_FAMILY, leaveFamily)\n        })\n    }\n\n}\n\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/com/google/android/gms/family/v2/manage/fragment/FamilyDeleteFragment.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.family.v2.manage.fragment\n\nimport android.accounts.AccountManager\nimport android.content.Intent\nimport android.os.Bundle\nimport android.util.Log\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport androidx.compose.ui.platform.ComposeView\nimport androidx.core.net.toUri\nimport androidx.fragment.app.Fragment\nimport androidx.fragment.app.activityViewModels\nimport androidx.lifecycle.lifecycleScope\nimport com.google.android.gms.R\nimport com.google.android.gms.family.model.MemberDataModel\nimport com.google.android.gms.family.v2.manage.EXTRA_KEY_ACCOUNT_NAME\nimport com.google.android.gms.family.v2.manage.EXTRA_KEY_APP_ID\nimport com.google.android.gms.family.v2.manage.EXTRA_KEY_MEMBER_GIVEN_NAME\nimport com.google.android.gms.family.v2.manage.EXTRA_KEY_MEMBER_ID\nimport com.google.android.gms.family.v2.manage.EXTRA_KEY_MEMBER_LEAVE_FAMILY\nimport com.google.android.gms.family.v2.manage.errorResult\nimport com.google.android.gms.family.v2.manage.model.FamilyChangedState\nimport com.google.android.gms.family.v2.manage.model.FamilyViewModel\nimport com.google.android.gms.family.v2.manage.onResult\nimport com.google.android.gms.family.v2.manage.showToast\nimport com.google.android.gms.family.v2.manage.ui.FamilyDeleteFragmentScreen\nimport com.google.android.gms.family.v2.model.HelpData\nimport com.google.android.gms.googlehelp.GoogleHelp\nimport kotlinx.coroutines.launch\nimport org.microg.gms.auth.AuthConstants\nimport org.microg.gms.family.FamilyRole\nimport org.microg.gms.googlehelp.ui.GoogleHelpRedirectActivity\n\nclass FamilyDeleteFragment : Fragment() {\n    private val familyViewModel by activityViewModels<FamilyViewModel>()\n\n    private val callerAppId: String?\n        get() = arguments?.getString(EXTRA_KEY_APP_ID)\n    private val accountName: String?\n        get() = arguments?.getString(EXTRA_KEY_ACCOUNT_NAME)\n    private val memberId: String?\n        get() = arguments?.getString(EXTRA_KEY_MEMBER_ID)\n    private val memberGivenName: String?\n        get() = arguments?.getString(EXTRA_KEY_MEMBER_GIVEN_NAME)\n    private val leaveFamily: Boolean\n        get() = arguments?.getBoolean(EXTRA_KEY_MEMBER_LEAVE_FAMILY, false) ?: false\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        if (accountName == null) {\n            requireActivity().errorResult(\"FamilyDeleteFragment: accountName is empty\", -2)\n            return requireActivity().finish()\n        }\n        if (AccountManager.get(requireContext()).getAccountsByType(AuthConstants.DEFAULT_ACCOUNT_TYPE).find { it.name == accountName } == null) {\n            requireActivity().errorResult(\"FamilyDeleteFragment: accountName is invalid\", -2)\n            return requireActivity().finish()\n        }\n        if (callerAppId == null) {\n            requireActivity().errorResult(\"FamilyDeleteFragment: callerAppId is empty\", -2)\n            return requireActivity().finish()\n        }\n        if (memberId == null) {\n            requireActivity().errorResult(\"FamilyDeleteFragment: memberId is null\", -2)\n            return requireActivity().finish()\n        }\n        if (memberGivenName.isNullOrEmpty()) {\n            requireActivity().errorResult(\"FamilyDeleteFragment: memberGivenName is empty\", -2)\n            return requireActivity().finish()\n        }\n    }\n\n    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {\n        super.onViewCreated(view, savedInstanceState)\n        lifecycleScope.launch {\n            familyViewModel.familyChangedStateState.collect {\n                when (it) {\n                    is FamilyChangedState.Idle -> Unit\n                    is FamilyChangedState.Changed -> onMemberChanged(it.token)\n                    is FamilyChangedState.Error -> requireActivity().errorResult(it.message, it.code, accountName)\n                }\n            }\n        }\n        lifecycleScope.launch { familyViewModel.refreshing.collect { loadContentData() } }\n    }\n\n    private fun onMemberChanged(consistencyToken: String) {\n        Log.d(TAG, \"onMemberChanged: consistencyToken: $consistencyToken\")\n        requireActivity().onResult(accountName, consistencyToken)\n    }\n\n    private fun loadContentData() {\n        familyViewModel.loadFamilyManagementPageContent(\n            requireContext(), accountName!!, callerAppId!!, memberId!!, leaveFamily\n        )\n    }\n\n    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {\n        return ComposeView(requireContext()).apply {\n            setContent {\n                FamilyDeleteFragmentScreen(\n                    viewModel = familyViewModel,\n                    onHelpClick = ::showHelpPage,\n                    displayName = memberGivenName!!,\n                    leaveFamily = leaveFamily,\n                    onCancelDelete = { requireActivity().onBackPressed() },\n                    onValidatePassword = ::validatePassword,\n                    onCheckPasswordSuccess = ::executeDeleteOperation\n                )\n            }\n        }\n    }\n\n    private fun executeDeleteOperation(currentMember: MemberDataModel) {\n        lifecycleScope.launch {\n            if (leaveFamily) {\n                val deleted = familyViewModel.deleteMember(requireContext(), accountName!!, callerAppId!!, memberId!!)\n                if (deleted) {\n                    requireActivity().also {\n                        val message = getString(R.string.family_management_member_removed_success, memberGivenName)\n                        it.showToast(message)\n                    }.finish()\n                    return@launch\n                }\n                requireActivity().showToast(getString(R.string.family_management_member_remove_failed, memberGivenName))\n                return@launch\n            }\n            if (currentMember.role == FamilyRole.HEAD_OF_HOUSEHOLD.value) {\n                val deleted = familyViewModel.deleteFamily(requireContext(), accountName!!, callerAppId!!)\n                if (deleted) {\n                    requireActivity().also {\n                        it.showToast(getString(R.string.family_management_delete_group_success))\n                    }.finish()\n                    return@launch\n                }\n                requireActivity().showToast(getString(R.string.family_management_delete_group_failure))\n                return@launch\n            }\n            val deleted = familyViewModel.deleteMember(requireContext(), accountName!!, callerAppId!!, memberId!!)\n            if (deleted) {\n                requireActivity().also {\n                    it.showToast(getString(R.string.family_management_exist_group_success))\n                }.finish()\n                return@launch\n            }\n            requireActivity().showToast(getString(R.string.family_management_leave_family_error_message))\n        }\n    }\n\n    private fun showHelpPage(helpData: HelpData) {\n        Intent(requireActivity(), GoogleHelpRedirectActivity::class.java).apply {\n            val googleHelp = GoogleHelp().apply {\n                appContext = helpData.appContext\n                uri = helpData.linkUrl.toUri()\n            }\n            putExtra(GoogleHelpRedirectActivity.GOOGLE_HELP_KEY, googleHelp)\n            putExtra(GoogleHelpRedirectActivity.KEY_PACKAGE_NAME, requireActivity().packageName)\n        }.let { requireActivity().startActivity(it) }\n    }\n\n    private fun validatePassword(password: String, member: MemberDataModel) {\n        familyViewModel.validatePassword(requireContext(), accountName!!, password, member)\n    }\n\n    companion object {\n        const val TAG = \"FamilyDeleteFragment\"\n        fun newInstance(bundle: Bundle): FamilyDeleteFragment {\n            val fragment = FamilyDeleteFragment().apply {\n                arguments = bundle\n            }\n            return fragment\n        }\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/com/google/android/gms/family/v2/manage/fragment/FamilyManagementFragment.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.family.v2.manage.fragment\n\nimport android.content.Intent\nimport android.os.Bundle\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.ImageView\nimport androidx.activity.result.contract.ActivityResultContracts\nimport androidx.compose.ui.platform.ComposeView\nimport androidx.fragment.app.Fragment\nimport androidx.fragment.app.activityViewModels\nimport androidx.lifecycle.lifecycleScope\nimport com.google.android.gms.R\nimport com.google.android.gms.common.images.ImageManager\nimport com.google.android.gms.family.model.MemberDataModel\nimport com.google.android.gms.family.v2.manage.EXTRA_KEY_ACCOUNT_NAME\nimport com.google.android.gms.family.v2.manage.EXTRA_KEY_APP_ID\nimport com.google.android.gms.family.v2.manage.EXTRA_KEY_CALLING_PACKAGE_NAME\nimport com.google.android.gms.family.v2.manage.FAMILY_LINK_MEMBER_BASE_URL\nimport com.google.android.gms.family.v2.manage.buildFamilyInviteUrl\nimport com.google.android.gms.family.v2.manage.model.FamilyViewModel\nimport com.google.android.gms.family.v2.manage.ui.FamilyManagementFragmentScreen\nimport kotlinx.coroutines.launch\nimport org.microg.gms.accountsettings.ui.EXTRA_ACCOUNT_NAME\nimport org.microg.gms.accountsettings.ui.EXTRA_CALLING_PACKAGE_NAME\nimport org.microg.gms.accountsettings.ui.EXTRA_URL\nimport org.microg.gms.accountsettings.ui.MainActivity\nimport org.microg.gms.family.FamilyRole\n\nclass FamilyManagementFragment : Fragment() {\n    private val familyViewModel by activityViewModels<FamilyViewModel>()\n\n    private val callerAppId: String?\n        get() = arguments?.getString(EXTRA_KEY_APP_ID)\n    private val accountName: String?\n        get() = arguments?.getString(EXTRA_KEY_ACCOUNT_NAME)\n    private val callingPackageName: String?\n        get() = arguments?.getString(EXTRA_KEY_CALLING_PACKAGE_NAME)\n\n    private val resultLauncher = registerForActivityResult(\n        ActivityResultContracts.StartActivityForResult()\n    ) { result ->\n        loadFamilyData()\n    }\n\n    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {\n        return ComposeView(requireContext()).apply {\n            setContent {\n                FamilyManagementFragmentScreen(\n                    viewModel = familyViewModel,\n                    onMemberClick = ::onClickFamilyMember,\n                    loadImage = ::loadMemberAvatar\n                )\n            }\n        }\n    }\n\n    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {\n        super.onViewCreated(view, savedInstanceState)\n        lifecycleScope.launch { familyViewModel.refreshing.collect { loadFamilyData() } }\n        familyViewModel.updateUIState(true, getString(R.string.family_management_title))\n    }\n\n    override fun onHiddenChanged(hidden: Boolean) {\n        super.onHiddenChanged(hidden)\n        if (!hidden) {\n            familyViewModel.updateUIState(true, getString(R.string.family_management_title))\n            familyViewModel.refreshData()\n        }\n    }\n\n    private fun loadFamilyData() {\n        familyViewModel.loadFamilyMembers(\n            requireContext(),\n            accountName!!,\n            callerAppId!!\n        )\n    }\n\n    private fun onClickFamilyMember(member: MemberDataModel) {\n        if (member.isInviteEntry) {\n            resultLauncher.launch(Intent(requireContext(), MainActivity::class.java).apply {\n                putExtra(EXTRA_URL, buildFamilyInviteUrl(callerAppId))\n                putExtra(EXTRA_ACCOUNT_NAME, accountName)\n                putExtra(EXTRA_CALLING_PACKAGE_NAME, callingPackageName)\n            })\n            return\n        }\n        if (member.role == FamilyRole.CHILD.value) {\n            resultLauncher.launch(Intent(requireContext(), MainActivity::class.java).apply {\n                putExtra(EXTRA_URL, \"$FAMILY_LINK_MEMBER_BASE_URL${member.memberId}\")\n                putExtra(EXTRA_ACCOUNT_NAME, accountName)\n                putExtra(EXTRA_CALLING_PACKAGE_NAME, callingPackageName)\n            })\n            return\n        }\n        lifecycleScope.launch {\n            familyViewModel.selectMember((view?.parent as View).id, member)\n        }\n    }\n\n    private fun loadMemberAvatar(url: String?, view: ImageView) {\n        runCatching {\n            ImageManager.create(requireContext()).loadImage(url, view)\n        }\n    }\n\n    companion object {\n        const val TAG = \"FamilyManagementFragment\"\n        fun newInstance(accountName: String, appId: String, callingPackageName: String): FamilyManagementFragment {\n            val fragment = FamilyManagementFragment().apply {\n                arguments = Bundle().apply {\n                    putString(EXTRA_KEY_ACCOUNT_NAME, accountName)\n                    putString(EXTRA_KEY_APP_ID, appId)\n                    putString(EXTRA_KEY_CALLING_PACKAGE_NAME, callingPackageName)\n                }\n            }\n            return fragment\n        }\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/com/google/android/gms/family/v2/manage/fragment/MemberDetailFragment.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.family.v2.manage.fragment\n\nimport android.os.Bundle\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.ImageView\nimport androidx.compose.ui.platform.ComposeView\nimport androidx.fragment.app.Fragment\nimport androidx.fragment.app.activityViewModels\nimport androidx.lifecycle.lifecycleScope\nimport com.google.android.gms.R\nimport com.google.android.gms.common.images.ImageManager\nimport com.google.android.gms.family.model.MemberDataModel\nimport com.google.android.gms.family.v2.manage.EXTRA_KEY_ACCOUNT_NAME\nimport com.google.android.gms.family.v2.manage.EXTRA_KEY_APP_ID\nimport com.google.android.gms.family.v2.manage.EXTRA_KEY_MEMBER_MODEL\nimport com.google.android.gms.family.v2.manage.model.FamilyViewModel\nimport com.google.android.gms.family.v2.manage.showToast\nimport com.google.android.gms.family.v2.manage.ui.MemberDetailItem\nimport kotlinx.coroutines.launch\n\nclass MemberDetailFragment : Fragment() {\n    private val familyViewModel by activityViewModels<FamilyViewModel>()\n\n    private val callerAppId: String?\n        get() = arguments?.getString(EXTRA_KEY_APP_ID)\n    private val accountName: String?\n        get() = arguments?.getString(EXTRA_KEY_ACCOUNT_NAME)\n    private val memberModel: MemberDataModel\n        get() = arguments?.getParcelable(EXTRA_KEY_MEMBER_MODEL) ?: MemberDataModel()\n\n    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {\n        return ComposeView(requireContext()).apply {\n            setContent {\n                MemberDetailItem(\n                    viewModel = familyViewModel,\n                    member = memberModel,\n                    onMemberClick = ::onMemberClick,\n                    loadImage = ::loadMemberAvatar\n                )\n            }\n        }\n    }\n\n    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {\n        super.onViewCreated(view, savedInstanceState)\n        familyViewModel.updateUIState(false, memberModel.displayName)\n    }\n\n    private fun onMemberClick(member: MemberDataModel) {\n        if (member.isInvited) {\n            lifecycleScope.launch {\n                val deleteInvitationState = familyViewModel.deleteInvitationMember(\n                    requireContext(),\n                    accountName!!,\n                    callerAppId!!,\n                    member.invitationId\n                )\n                runCatching {\n                    if (deleteInvitationState){\n                        requireActivity().showToast(getString(R.string.family_management_cancel_invite_success))\n                        requireActivity().onBackPressed()\n                        return@launch\n                    }\n                    requireActivity().showToast(getString(R.string.family_management_cancel_invite_error))\n                }\n            }\n            return\n        }\n        lifecycleScope.launch {\n            familyViewModel.selectMember(null, member)\n        }\n    }\n\n    private fun loadMemberAvatar(url: String?, view: ImageView) {\n        runCatching {\n            ImageManager.create(requireContext()).loadImage(url, view)\n        }\n    }\n\n    companion object {\n        const val TAG = \"MemberDetailFragment\"\n        fun newInstance(member: MemberDataModel, accountName: String, appId: String): MemberDetailFragment {\n            val memberDetailFragment = MemberDetailFragment().apply {\n                arguments = Bundle().apply {\n                    putParcelable(EXTRA_KEY_MEMBER_MODEL, member)\n                    putString(EXTRA_KEY_ACCOUNT_NAME, accountName)\n                    putString(EXTRA_KEY_APP_ID, appId)\n                }\n            }\n            return memberDetailFragment\n        }\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/com/google/android/gms/family/v2/manage/model/FamilyViewModel.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.family.v2.manage.model\n\nimport android.content.Context\nimport android.util.Log\nimport androidx.lifecycle.ViewModel\nimport androidx.lifecycle.viewModelScope\nimport com.google.android.gms.R\nimport com.google.android.gms.family.model.MemberDataModel\nimport com.google.android.gms.family.v2.manage.FAMILY_PAGE_CONTENT_FLAG_MEMBER_LIST\nimport com.google.android.gms.family.v2.manage.FAMILY_PAGE_CONTENT_TITLE_INDEX\nimport com.google.android.gms.family.v2.manage.FamilyApiClient\nimport com.google.android.gms.family.v2.manage.SERVICE_FAMILY_RE_AUTH_SCOPE\nimport com.google.android.gms.family.v2.manage.SERVICE_FAMILY_SCOPE\nimport com.google.android.gms.family.v2.manage.TAG\nimport com.google.android.gms.family.v2.manage.parseToMemberDataModels\nimport com.google.android.gms.family.v2.manage.parseToPageData\nimport com.google.android.gms.family.v2.manage.requestOauthToken\nimport com.google.android.gms.family.v2.model.PageData\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.async\nimport kotlinx.coroutines.flow.MutableSharedFlow\nimport kotlinx.coroutines.flow.MutableStateFlow\nimport kotlinx.coroutines.flow.StateFlow\nimport kotlinx.coroutines.flow.asSharedFlow\nimport kotlinx.coroutines.flow.asStateFlow\nimport kotlinx.coroutines.flow.update\nimport kotlinx.coroutines.launch\nimport kotlinx.coroutines.supervisorScope\nimport kotlinx.coroutines.withContext\n\ndata class UiState(\n    val title: String = \"\",\n    val isError: Boolean = false,\n    val isLoading: Boolean = false,\n    val showMoreAction: Boolean = false,\n    val currentMember: MemberDataModel = MemberDataModel(),\n    val memberList: List<MemberDataModel> = emptyList(),\n    val pageData: PageData? = null,\n)\n\nsealed class PasswordCheckState {\n    object Idle : PasswordCheckState()\n    object Checking : PasswordCheckState()\n    data class Success(val member: MemberDataModel) : PasswordCheckState()\n    data class Error(val message: String) : PasswordCheckState()\n}\n\nsealed class FamilyChangedState {\n    object Idle : FamilyChangedState()\n    data class Changed(val token: String, val deleteFamily: Boolean) : FamilyChangedState()\n    data class Error(val message: String, val code: Int) : FamilyChangedState()\n}\n\nclass FamilyViewModel : ViewModel() {\n    private val _uiState = MutableStateFlow(UiState())\n    val uiState: StateFlow<UiState> = _uiState.asStateFlow()\n    private val _passwordCheckState = MutableStateFlow<PasswordCheckState>(PasswordCheckState.Idle)\n    val passwordCheckState: StateFlow<PasswordCheckState> = _passwordCheckState.asStateFlow()\n    private val _familyChangedStateState = MutableStateFlow<FamilyChangedState>(FamilyChangedState.Idle)\n    val familyChangedStateState: StateFlow<FamilyChangedState> = _familyChangedStateState.asStateFlow()\n    private val _refreshData = MutableStateFlow(true)\n    val refreshing: StateFlow<Boolean> = _refreshData.asStateFlow()\n    private val _selectedMember = MutableSharedFlow<Pair<Int?, MemberDataModel>>()\n    val selectedMember = _selectedMember.asSharedFlow()\n\n    suspend fun selectMember(viewId: Int?, member: MemberDataModel) {\n        _selectedMember.emit(Pair(viewId, member))\n    }\n\n    fun updateUIState(showAction: Boolean, title: String = \"\") {\n        _uiState.update { it.copy(showMoreAction = showAction, title = title) }\n    }\n\n    fun refreshData() {\n        _refreshData.value = !_refreshData.value\n    }\n\n    fun resetPasswordState() {\n        _passwordCheckState.value = PasswordCheckState.Idle\n    }\n\n    fun loadFamilyMembers(context: Context, accountName: String, appId: String, flag: Int = FAMILY_PAGE_CONTENT_FLAG_MEMBER_LIST) {\n        viewModelScope.launch {\n            supervisorScope {\n                runCatching {\n                    _uiState.update { it.copy(isLoading = true, isError = false) }\n                    val oauthToken = requestOauthToken(context, accountName, SERVICE_FAMILY_SCOPE)\n                    val familyResponseDeferred = async {\n                        FamilyApiClient.loadFamilyData(context, oauthToken, appId, flag)\n                    }\n                    val configResponseDeferred = async {\n                        FamilyApiClient.loadFamilyManagementConfig(context, oauthToken, appId, false)\n                    }\n                    val familyResponse = familyResponseDeferred.await()\n                    val configResponse = configResponseDeferred.await()\n                    Log.d(TAG, \"loadFamilyMembers: familyResponse: $familyResponse\")\n                    Log.d(TAG, \"loadFamilyMembers: configResponse: $configResponse\")\n                    familyResponse?.parseToMemberDataModels(context, accountName, configResponse)\n                        ?: throw RuntimeException(\"familyResponse is null\")\n                }.onFailure { throwable ->\n                    _familyChangedStateState.value = FamilyChangedState.Error(throwable.message ?: \"\", 4)\n                    _uiState.update { it.copy(isLoading = false, isError = true) }\n                    Log.d(TAG, \"loadFamilyMembers error\", throwable)\n                }.onSuccess { list ->\n                    _uiState.update {\n                        it.copy(\n                            isLoading = false,\n                            memberList = list,\n                            currentMember = list.firstOrNull { m -> m.email == accountName } ?: MemberDataModel()\n                        )\n                    }\n                }\n            }\n        }\n    }\n\n    fun loadFamilyManagementPageContent(\n        context: Context,\n        accountName: String,\n        appId: String,\n        memberId: String,\n        leaveFamily: Boolean = false\n    ) {\n        viewModelScope.launch {\n            runCatching {\n                _uiState.update { it.copy(isLoading = true, isError = false) }\n                val oauthToken = requestOauthToken(context, accountName, SERVICE_FAMILY_SCOPE)\n                val currentMember = getCurrentMember(context, accountName, appId, oauthToken)\n                val pageContent = FamilyApiClient.loadFamilyManagementPageContent(context, oauthToken, appId, memberId, currentMember, leaveFamily)\n                pageContent?.body?.parseToPageData() ?: throw RuntimeException(\"pageContent is null\")\n            }.onFailure { throwable ->\n                _uiState.update { it.copy(isLoading = false, isError = true) }\n                _familyChangedStateState.value = FamilyChangedState.Error(throwable.message ?: \"\", 4)\n                Log.d(TAG, \"loadFamilyManagementPageContent error\", throwable)\n            }.onSuccess { pageData ->\n                _uiState.update {\n                    it.copy(\n                        isLoading = false,\n                        title = pageData.sectionMap.getValue(FAMILY_PAGE_CONTENT_TITLE_INDEX),\n                        pageData = pageData\n                    )\n                }\n            }\n        }\n    }\n\n    fun validatePassword(\n        context: Context,\n        accountName: String,\n        password: String,\n        currentMember: MemberDataModel\n    ) {\n        viewModelScope.launch {\n            _passwordCheckState.value = PasswordCheckState.Checking\n            runCatching {\n                val oauthToken = requestOauthToken(context, accountName, SERVICE_FAMILY_RE_AUTH_SCOPE)\n                FamilyApiClient.validatePassword(oauthToken, password)\n            }.onFailure {\n                _passwordCheckState.value =\n                    PasswordCheckState.Error(context.getString(R.string.family_management_pwd_error))\n                _familyChangedStateState.value = FamilyChangedState.Error(it.message ?: \"\", 4)\n                Log.d(TAG, \"validatePassword error\", it)\n            }.onSuccess { success ->\n                if (success) {\n                    _passwordCheckState.value = PasswordCheckState.Success(currentMember)\n                } else {\n                    _passwordCheckState.value =\n                        PasswordCheckState.Error(context.getString(R.string.family_management_pwd_error))\n                }\n            }\n        }\n    }\n\n    suspend fun deleteInvitationMember(\n        context: Context,\n        accountName: String,\n        appId: String,\n        memberId: String\n    ) = withContext(Dispatchers.IO) {\n        runCatching {\n            val oauthToken = requestOauthToken(context, accountName, SERVICE_FAMILY_SCOPE)\n            val operationResponse =\n                FamilyApiClient.deleteInvitationMember(context, oauthToken, appId, memberId)\n            val consistencyToken = operationResponse?.result?.consistencyToken\n            consistencyToken?.takeIf { it.isNotEmpty() }?.let {\n                _familyChangedStateState.value = FamilyChangedState.Changed(it, false)\n            }\n            Log.d(TAG, \"deleteInvitationMember: operationResponse: $operationResponse\")\n            !consistencyToken.isNullOrEmpty()\n        }.onFailure {\n            _familyChangedStateState.value = FamilyChangedState.Error(it.message ?: \"\", 4)\n            Log.d(TAG, \"deleteInvitationMember error\", it)\n        }.getOrDefault(false)\n    }\n\n\n    suspend fun deleteMember(\n        context: Context,\n        accountName: String,\n        appId: String,\n        memberId: String\n    ) = withContext(Dispatchers.IO) {\n        runCatching {\n            val oauthToken = requestOauthToken(context, accountName, SERVICE_FAMILY_SCOPE)\n            val operationResponse = FamilyApiClient.deleteMember(context, oauthToken, appId, memberId)\n            val consistencyToken = operationResponse?.result?.consistencyToken\n            consistencyToken?.takeIf { it.isNotEmpty() }?.let {\n                _familyChangedStateState.value = FamilyChangedState.Changed(it, false)\n            }\n            Log.d(TAG, \"deleteMember: operationResponse: $operationResponse\")\n            !consistencyToken.isNullOrEmpty()\n        }.onFailure {\n            _familyChangedStateState.value = FamilyChangedState.Error(it.message ?: \"\", 4)\n            Log.d(TAG, \"deleteMember error\", it)\n        }.getOrDefault(false)\n    }\n\n    suspend fun deleteFamily(\n        context: Context,\n        accountName: String,\n        appId: String\n    ) = withContext(Dispatchers.IO) {\n        runCatching {\n            val oauthToken = requestOauthToken(context, accountName, SERVICE_FAMILY_SCOPE)\n            val operationResponse = FamilyApiClient.deleteFamily(context, oauthToken, appId)\n            val consistencyToken = operationResponse?.result?.consistencyToken\n            consistencyToken?.takeIf { it.isNotEmpty() }?.let {\n                _familyChangedStateState.value = FamilyChangedState.Changed(it, true)\n            }\n            Log.d(TAG, \"deleteFamily: operationResponse: $operationResponse\")\n            !consistencyToken.isNullOrEmpty()\n        }.onFailure {\n            _familyChangedStateState.value = FamilyChangedState.Error(it.message ?: \"\", 4)\n            Log.d(TAG, \"deleteFamily error\", it)\n        }.getOrDefault(false)\n    }\n\n    suspend fun getCurrentMember(context: Context, accountName: String, appId: String, oauthToken: String? = null): MemberDataModel {\n        val currentMember = uiState.value.currentMember\n        if (!currentMember.memberId.isNullOrEmpty()) {\n            return currentMember\n        }\n        val memberDataModels = withContext(Dispatchers.IO) {\n            val oauthToken = oauthToken ?: requestOauthToken(context, accountName, SERVICE_FAMILY_SCOPE)\n            val familyResponse = FamilyApiClient.loadFamilyData(context, oauthToken, appId, FAMILY_PAGE_CONTENT_FLAG_MEMBER_LIST)\n            familyResponse?.parseToMemberDataModels(context, accountName, null)\n        }\n        return memberDataModels?.firstOrNull { m -> m.email == accountName }?.also {\n            _uiState.update { state -> state.copy(currentMember = it) }\n        } ?: MemberDataModel()\n    }\n\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/com/google/android/gms/family/v2/manage/ui/DeleteUI.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.family.v2.manage.ui\n\nimport androidx.compose.foundation.layout.Arrangement\nimport androidx.compose.foundation.layout.Box\nimport androidx.compose.foundation.layout.Column\nimport androidx.compose.foundation.layout.Row\nimport androidx.compose.foundation.layout.Spacer\nimport androidx.compose.foundation.layout.fillMaxSize\nimport androidx.compose.foundation.layout.fillMaxWidth\nimport androidx.compose.foundation.layout.height\nimport androidx.compose.foundation.layout.padding\nimport androidx.compose.foundation.layout.size\nimport androidx.compose.foundation.layout.width\nimport androidx.compose.foundation.text.ClickableText\nimport androidx.compose.material3.AlertDialog\nimport androidx.compose.material3.CircularProgressIndicator\nimport androidx.compose.material3.LocalTextStyle\nimport androidx.compose.material3.MaterialTheme\nimport androidx.compose.material3.OutlinedTextField\nimport androidx.compose.material3.Text\nimport androidx.compose.material3.TextButton\nimport androidx.compose.runtime.Composable\nimport androidx.compose.runtime.LaunchedEffect\nimport androidx.compose.runtime.collectAsState\nimport androidx.compose.runtime.getValue\nimport androidx.compose.runtime.mutableStateOf\nimport androidx.compose.runtime.remember\nimport androidx.compose.runtime.setValue\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.graphics.Color\nimport androidx.compose.ui.res.stringResource\nimport androidx.compose.ui.text.SpanStyle\nimport androidx.compose.ui.text.buildAnnotatedString\nimport androidx.compose.ui.text.style.TextDecoration\nimport androidx.compose.ui.unit.dp\nimport androidx.compose.ui.unit.sp\nimport androidx.core.text.HtmlCompat\nimport com.google.android.gms.R\nimport com.google.android.gms.family.model.MemberDataModel\nimport com.google.android.gms.family.v2.manage.FAMILY_PAGE_CONTENT_NEGATIVE_BUTTON_INDEX\nimport com.google.android.gms.family.v2.manage.FAMILY_PAGE_CONTENT_POSITIVE_BUTTON_INDEX\nimport com.google.android.gms.family.v2.manage.FAMILY_PAGE_CONTENT_TEXT_INDEX\nimport com.google.android.gms.family.v2.manage.model.FamilyViewModel\nimport com.google.android.gms.family.v2.manage.model.PasswordCheckState\nimport com.google.android.gms.family.v2.model.HelpData\nimport org.microg.gms.family.FamilyRole\n\n@Composable\nfun FamilyDeleteFragmentScreen(\n    viewModel: FamilyViewModel,\n    displayName: String,\n    leaveFamily: Boolean,\n    onHelpClick: (HelpData) -> Unit,\n    onCancelDelete: () -> Unit,\n    onValidatePassword: (String, MemberDataModel) -> Unit,\n    onCheckPasswordSuccess: (MemberDataModel) -> Unit\n) {\n    val uiState by viewModel.uiState.collectAsState()\n    val passwordState by viewModel.passwordCheckState.collectAsState()\n\n    var showDialog by remember { mutableStateOf(false) }\n    var password by remember { mutableStateOf(\"\") }\n\n    LaunchedEffect(passwordState) {\n        if (passwordState is PasswordCheckState.Success) {\n            onCheckPasswordSuccess((passwordState as PasswordCheckState.Success).member)\n            viewModel.resetPasswordState()\n            showDialog = false\n            password = \"\"\n        }\n    }\n\n    Box(modifier = Modifier.fillMaxSize()) {\n        Column(\n            modifier = Modifier\n                .fillMaxWidth()\n                .padding(16.dp)\n        ) {\n            uiState.pageData?.let { pageData ->\n                HtmlTextWithHelpLinks(\n                    htmlContent = pageData.sectionMap[FAMILY_PAGE_CONTENT_TEXT_INDEX] ?: \"\",\n                    helpMap = pageData.helpMap ?: emptyMap(),\n                    textColor = MaterialTheme.colorScheme.onBackground,\n                    onHelpClick = onHelpClick\n                )\n            }\n\n            Spacer(Modifier.height(24.dp))\n\n            Row(\n                modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.End\n            ) {\n                TextButton(onClick = onCancelDelete) {\n                    Text(text = uiState.pageData?.sectionMap?.get(FAMILY_PAGE_CONTENT_NEGATIVE_BUTTON_INDEX) ?: \"\", fontSize = 13.sp)\n                }\n                Spacer(Modifier.width(12.dp))\n                TextButton(onClick = { showDialog = true }) {\n                    Text(text = uiState.pageData?.sectionMap?.get(FAMILY_PAGE_CONTENT_POSITIVE_BUTTON_INDEX) ?: \"\", fontSize = 13.sp)\n                }\n            }\n        }\n\n        if (showDialog) {\n            PasswordDialog(\n                currentModel = uiState.currentMember,\n                displayName = displayName,\n                leaveFamily = leaveFamily,\n                password = password,\n                isChecking = passwordState is PasswordCheckState.Checking,\n                errorMessage = if (passwordState is PasswordCheckState.Error) (passwordState as PasswordCheckState.Error).message else null,\n                onPasswordChange = { password = it },\n                onConfirm = {\n                    if (password.isNotEmpty()) {\n                        onValidatePassword(password, uiState.currentMember)\n                    }\n                },\n                onCancel = {\n                    viewModel.resetPasswordState()\n                    password = \"\"\n                    showDialog = false\n                })\n        }\n    }\n}\n\n@Composable\nfun HtmlTextWithHelpLinks(\n    htmlContent: String, helpMap: Map<String, HelpData>, textColor: Color, onHelpClick: (HelpData) -> Unit\n) {\n    val annotatedString = remember(htmlContent, helpMap) {\n        buildAnnotatedString {\n            val spanned = HtmlCompat.fromHtml(htmlContent, HtmlCompat.FROM_HTML_MODE_LEGACY)\n\n            val plainText = spanned.toString()\n            append(plainText)\n\n            val regex = Regex(\"<help-(.*?)>(.*?)</help-\\\\1>\", RegexOption.IGNORE_CASE)\n            regex.findAll(htmlContent).forEach { match ->\n                val helpKey = match.groupValues[1]\n                val displayText = match.groupValues[2]\n                val startIndex = plainText.indexOf(displayText)\n                if (startIndex >= 0) {\n                    val endIndex = startIndex + displayText.length\n                    addStyle(\n                        style = SpanStyle(\n                            color = Color.Blue, textDecoration = TextDecoration.None\n                        ), start = startIndex, end = endIndex\n                    )\n                    addStringAnnotation(\n                        tag = \"HELP_TAG\", annotation = helpKey, start = startIndex, end = endIndex\n                    )\n                }\n            }\n        }\n    }\n\n    ClickableText(\n        text = annotatedString,\n        style = LocalTextStyle.current.copy(\n            color = textColor,\n            fontSize = 14.sp,\n            lineHeight = 24.sp,\n            letterSpacing = 0.5.sp\n        ),\n        onClick = { offset ->\n            annotatedString.getStringAnnotations(\"HELP_TAG\", offset, offset).firstOrNull()?.let { annotation ->\n                helpMap[annotation.item]?.let { helpData ->\n                    onHelpClick(helpData)\n                }\n            }\n        })\n}\n\n@Composable\nprivate fun PasswordDialog(\n    currentModel: MemberDataModel,\n    displayName: String,\n    password: String,\n    leaveFamily: Boolean,\n    isChecking: Boolean,\n    errorMessage: String?,\n    onPasswordChange: (String) -> Unit,\n    onConfirm: () -> Unit,\n    onCancel: () -> Unit\n) {\n    AlertDialog(\n        onDismissRequest = onCancel,\n        title = {\n            val title = if (leaveFamily) {\n                stringResource(id = R.string.family_management_remove_member_password_title, displayName)\n            } else if (currentModel.role == FamilyRole.HEAD_OF_HOUSEHOLD.value) {\n                stringResource(id = R.string.family_management_delete_family_password_title)\n            } else {\n                stringResource(id = R.string.family_management_leave_family_password_title)\n            }\n            Text(text = title)\n        },\n        text = {\n            Column {\n                Text(currentModel.email)\n                Spacer(Modifier.height(8.dp))\n                OutlinedTextField(\n                    value = password,\n                    onValueChange = onPasswordChange,\n                    placeholder = { Text(stringResource(R.string.family_management_input_pwd)) },\n                    isError = errorMessage != null,\n                    supportingText = {\n                        errorMessage?.let { Text(it, color = Color.Red) }\n                    })\n            }\n        },\n        confirmButton = {\n            TextButton(\n                onClick = onConfirm, enabled = !isChecking\n            ) {\n                if (isChecking) {\n                    CircularProgressIndicator(\n                        modifier = Modifier.size(16.dp), strokeWidth = 2.dp\n                    )\n                } else {\n                    Text(stringResource(id = R.string.family_management_delete_group_confirm), fontSize = 13.sp)\n                }\n            }\n        },\n        dismissButton = {\n            TextButton(onClick = onCancel) {\n                Text(stringResource(id = R.string.family_management_delete_group_cancel), fontSize = 13.sp)\n            }\n        })\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/com/google/android/gms/family/v2/manage/ui/FamilyUI.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.family.v2.manage.ui\n\nimport android.app.Activity\nimport android.view.View\nimport android.widget.FrameLayout\nimport androidx.compose.foundation.background\nimport androidx.compose.foundation.isSystemInDarkTheme\nimport androidx.compose.foundation.layout.Box\nimport androidx.compose.foundation.layout.Column\nimport androidx.compose.foundation.layout.fillMaxSize\nimport androidx.compose.foundation.layout.padding\nimport androidx.compose.material3.CircularProgressIndicator\nimport androidx.compose.material3.ColorScheme\nimport androidx.compose.material3.DropdownMenu\nimport androidx.compose.material3.DropdownMenuItem\nimport androidx.compose.material3.ExperimentalMaterial3Api\nimport androidx.compose.material3.Icon\nimport androidx.compose.material3.IconButton\nimport androidx.compose.material3.MaterialTheme\nimport androidx.compose.material3.Scaffold\nimport androidx.compose.material3.Snackbar\nimport androidx.compose.material3.SnackbarHost\nimport androidx.compose.material3.SnackbarHostState\nimport androidx.compose.material3.Text\nimport androidx.compose.material3.TextButton\nimport androidx.compose.material3.TopAppBar\nimport androidx.compose.material3.TopAppBarDefaults\nimport androidx.compose.runtime.Composable\nimport androidx.compose.runtime.LaunchedEffect\nimport androidx.compose.runtime.SideEffect\nimport androidx.compose.runtime.collectAsState\nimport androidx.compose.runtime.getValue\nimport androidx.compose.runtime.mutableStateOf\nimport androidx.compose.runtime.remember\nimport androidx.compose.runtime.rememberCoroutineScope\nimport androidx.compose.runtime.setValue\nimport androidx.compose.ui.Alignment\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.graphics.Color\nimport androidx.compose.ui.graphics.RectangleShape\nimport androidx.compose.ui.graphics.toArgb\nimport androidx.compose.ui.platform.LocalContext\nimport androidx.compose.ui.platform.LocalView\nimport androidx.compose.ui.res.painterResource\nimport androidx.compose.ui.res.stringResource\nimport androidx.compose.ui.unit.sp\nimport androidx.compose.ui.viewinterop.AndroidView\nimport androidx.core.view.WindowCompat\nimport com.google.android.gms.R\nimport com.google.android.gms.family.model.MemberDataModel\nimport com.google.android.gms.family.v2.manage.model.FamilyViewModel\nimport com.google.android.gms.family.v2.manage.model.UiState\nimport kotlinx.coroutines.launch\nimport org.microg.gms.family.FamilyRole\nimport org.microg.gms.profile.Build\n\n@Composable\nfun FamilyActivityScreen(\n    viewModel: FamilyViewModel,\n    type: String?,\n    addFragment: (View) -> Unit,\n    onBackClick: () -> Unit,\n    onMoreClick: ((MemberDataModel, Boolean) -> Unit)? = null\n) {\n    val uiState by viewModel.uiState.collectAsState()\n    val snackHostState = remember { SnackbarHostState() }\n    val scope = rememberCoroutineScope()\n    val context = LocalContext.current\n\n    FamilyTheme(familyThemeType = FamilyThemeType.from(type)) {\n        Scaffold(\n            snackbarHost = {\n                SnackbarHost(hostState = snackHostState) { data ->\n                    Snackbar(\n                        shape = RectangleShape,\n                        action = {\n                            TextButton(onClick = {\n                                scope.launch {\n                                    snackHostState.currentSnackbarData?.dismiss()\n                                    viewModel.refreshData()\n                                }\n                            }) {\n                                Text(stringResource(R.string.family_management_retry))\n                            }\n                        }\n                    ) {\n                        Text(data.visuals.message)\n                    }\n                }\n            }\n        ) { padding ->\n            Column(\n                modifier = Modifier\n                    .fillMaxSize()\n                    .padding(padding)\n            ) {\n                FamilyToolbar(\n                    uiState = uiState,\n                    currentMember = uiState.currentMember,\n                    onBackClick = onBackClick,\n                    onMoreClick = onMoreClick\n                )\n                Box(modifier = Modifier.fillMaxSize()) {\n                    val containerId = remember { View.generateViewId() }\n                    AndroidView(\n                        factory = { context -> FrameLayout(context).apply { id = containerId } },\n                        update = { addFragment(it) }\n                    )\n                    if (uiState.isLoading) {\n                        Box(\n                            modifier = Modifier\n                                .fillMaxSize()\n                                .background(Color.Black.copy(alpha = 0.3f)),\n                            contentAlignment = Alignment.Center\n                        ) {\n                            CircularProgressIndicator()\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    LaunchedEffect(uiState.isError) {\n        if (uiState.isError) {\n            snackHostState.showSnackbar(context.getString(R.string.family_management_load_error))\n        }\n    }\n}\n\n@OptIn(ExperimentalMaterial3Api::class)\n@Composable\nprivate fun FamilyToolbar(\n    uiState: UiState,\n    currentMember: MemberDataModel?,\n    onBackClick: () -> Unit,\n    onMoreClick: ((MemberDataModel, Boolean) -> Unit)? = null\n) {\n    val title = uiState.title\n    val showMore = uiState.showMoreAction\n    TopAppBar(\n        title = { Text(title, color = MaterialTheme.colorScheme.onPrimary, fontSize = 18.sp) },\n        navigationIcon = {\n            IconButton(onClick = onBackClick) {\n                Icon(\n                    painter = painterResource(id = R.drawable.ic_arrow_back),\n                    contentDescription = stringResource(id = R.string.family_management_toolbar_back),\n                    tint = MaterialTheme.colorScheme.onPrimary\n                )\n            }\n        },\n        actions = {\n            currentMember?.let { member ->\n                onMoreClick?.let { moreClick ->\n                    val action = when (member.role) {\n                        FamilyRole.HEAD_OF_HOUSEHOLD.value -> stringResource(R.string.family_management_delete_family_group)\n                        FamilyRole.MEMBER.value -> stringResource(R.string.family_management_exit_family_group)\n                        else -> null\n                    }\n                    action?.let { text ->\n                        if (showMore) {\n                            MoreOptionsMenu(\n                                menuItems = listOf(text),\n                                member = member,\n                                onMenuClick = moreClick\n                            )\n                        }\n                    }\n                }\n            }\n        },\n        colors = TopAppBarDefaults.topAppBarColors(\n            containerColor = MaterialTheme.colorScheme.primary\n        )\n    )\n}\n\n@Composable\nprivate fun MoreOptionsMenu(\n    menuItems: List<String>,\n    member: MemberDataModel,\n    onMenuClick: (MemberDataModel, Boolean) -> Unit\n) {\n    var expanded by remember { mutableStateOf(false) }\n\n    Box {\n        IconButton(onClick = { expanded = true }) {\n            Icon(\n                painter = painterResource(id = R.drawable.ic_more_vert),\n                contentDescription = stringResource(id = R.string.family_management_toolbar_more),\n                tint = MaterialTheme.colorScheme.onPrimary\n            )\n        }\n        DropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) {\n            menuItems.forEach { title ->\n                DropdownMenuItem(\n                    text = { Text(title) },\n                    onClick = {\n                        onMenuClick(member, member.role != FamilyRole.HEAD_OF_HOUSEHOLD.value)\n                        expanded = false\n                    }\n                )\n            }\n        }\n    }\n}\n\nprivate data class ThemeColors(\n    val primary: Color,\n    val onPrimary: Color,\n    val background: Color,\n    val onBackground: Color,\n)\n\nprivate enum class FamilyThemeType(\n    val typeName: String, val lightColorScheme: ThemeColors, val darkColorScheme: ThemeColors? = null\n) {\n    FAMILY_MANAGEMENT(\n        \"family_management\", lightColorScheme = ThemeColors(\n            primary = Color(0xFF1A73E8),\n            onPrimary = Color.White,\n            background = Color.White,\n            onBackground = Color(0xFF5F6368),\n        ), darkColorScheme = ThemeColors(\n            primary = Color(0xFF89B4F8),\n            onPrimary = Color.Black,\n            background = Color(0xFF202124),\n            onBackground = Color(0xFFEEEEEE),\n        )\n    ),\n\n    PLAY_PASS(\n        \"play_pass\", lightColorScheme = ThemeColors(\n            primary = Color(0xFF01875F),\n            onPrimary = Color.White,\n            background = Color.White,\n            onBackground = Color.Black,\n        ), darkColorScheme = ThemeColors(\n            primary = Color(0xFF00A173),\n            onPrimary = Color.Black,\n            background = Color(0xFF202124),\n            onBackground = Color(0xFFEEEEEE),\n        )\n    ),\n\n    PLAY_MUSIC(\n        \"play_music\", lightColorScheme = ThemeColors(\n            primary = Color(0xFFEF6C00),\n            onPrimary = Color.White,\n            background = Color.White,\n            onBackground = Color.Black,\n        )\n    ),\n\n    YOUTUBE(\n        \"youtube\", lightColorScheme = ThemeColors(\n            primary = Color(0xFFE62117),\n            onPrimary = Color.White,\n            background = Color.White,\n            onBackground = Color.Black,\n        )\n    ),\n\n    ASSISTANT(\n        \"assistant\", lightColorScheme = ThemeColors(\n            primary = Color(0xFFFFFFFF),\n            onPrimary = Color.Black,\n            background = Color.White,\n            onBackground = Color.Black,\n        )\n    ),\n\n    G1(\n        \"g1\", lightColorScheme = ThemeColors(\n            primary = Color(0xFFFFFFFF),\n            onPrimary = Color.Black,\n            background = Color.White,\n            onBackground = Color.Black,\n        )\n    ),\n\n    PLAY(\n        \"play\", lightColorScheme = ThemeColors(\n            primary = Color(0xFF455A64), onPrimary = Color.White, background = Color.White, onBackground = Color.Black\n        )\n    );\n\n    companion object {\n        fun from(type: String?) = FamilyThemeType.entries.firstOrNull {\n            it.typeName.equals(type, ignoreCase = true)\n        } ?: FAMILY_MANAGEMENT\n    }\n}\n\n@Composable\nprivate fun FamilyTheme(\n    familyThemeType: FamilyThemeType, darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit\n) {\n    val colors = if (darkTheme && familyThemeType.darkColorScheme != null) {\n        familyThemeType.darkColorScheme\n    } else {\n        familyThemeType.lightColorScheme\n    }\n\n    val colorScheme = ColorScheme(\n        primary = colors.primary,\n        onPrimary = colors.onPrimary,\n        background = colors.background,\n        onBackground = colors.onBackground,\n        surface = colors.background,\n        onSurface = colors.onBackground,\n        primaryContainer = colors.primary.copy(alpha = 0.2f),\n        onPrimaryContainer = colors.onPrimary,\n        secondary = colors.primary,\n        onSecondary = colors.onPrimary,\n        secondaryContainer = colors.primary.copy(alpha = 0.2f),\n        onSecondaryContainer = colors.onPrimary,\n        error = Color(0xFFB00020),\n        onError = Color.White,\n        errorContainer = Color(0xFFCF6679),\n        onErrorContainer = Color.White,\n        outline = Color.Gray,\n        inverseOnSurface = Color.White,\n        inverseSurface = Color.DarkGray,\n        inversePrimary = colors.primary,\n        surfaceVariant = colors.background,\n        onSurfaceVariant = colors.onBackground,\n        scrim = Color.Black.copy(alpha = 0.5f),\n        tertiary = colors.primary,\n        onTertiary = colors.onPrimary,\n        tertiaryContainer = colors.primary,\n        onTertiaryContainer = colors.onPrimary,\n        surfaceTint = Color.White,\n        outlineVariant = Color.White\n    )\n\n    val view = LocalView.current\n    val activity = view.context as? Activity\n\n    SideEffect {\n        activity?.window?.apply {\n            if (Build.VERSION.SDK_INT >= 21) {\n                statusBarColor = colorScheme.primary.toArgb()\n                navigationBarColor = colorScheme.primary.toArgb()\n            }\n            WindowCompat.getInsetsController(this, decorView).isAppearanceLightStatusBars = !darkTheme\n        }\n    }\n\n    MaterialTheme(\n        colorScheme = colorScheme, typography = MaterialTheme.typography, shapes = MaterialTheme.shapes, content = content\n    )\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/com/google/android/gms/family/v2/manage/ui/ManagementUI.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.family.v2.manage.ui\n\nimport android.view.ViewGroup\nimport android.widget.ImageView\nimport androidx.compose.foundation.Image\nimport androidx.compose.foundation.clickable\nimport androidx.compose.foundation.layout.Column\nimport androidx.compose.foundation.layout.Row\nimport androidx.compose.foundation.layout.fillMaxSize\nimport androidx.compose.foundation.layout.fillMaxWidth\nimport androidx.compose.foundation.layout.height\nimport androidx.compose.foundation.layout.padding\nimport androidx.compose.foundation.layout.size\nimport androidx.compose.foundation.lazy.LazyColumn\nimport androidx.compose.foundation.lazy.items\nimport androidx.compose.material3.HorizontalDivider\nimport androidx.compose.material3.MaterialTheme\nimport androidx.compose.material3.Text\nimport androidx.compose.runtime.Composable\nimport androidx.compose.runtime.collectAsState\nimport androidx.compose.runtime.getValue\nimport androidx.compose.ui.Alignment\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.graphics.Color\nimport androidx.compose.ui.res.painterResource\nimport androidx.compose.ui.res.stringResource\nimport androidx.compose.ui.unit.dp\nimport androidx.compose.ui.unit.sp\nimport androidx.compose.ui.viewinterop.AndroidView\nimport com.google.android.gms.R\nimport com.google.android.gms.family.model.MemberDataModel\nimport com.google.android.gms.family.v2.manage.model.FamilyViewModel\nimport com.google.android.gms.family.v2.manage.toPx\nimport de.hdodenhof.circleimageview.CircleImageView\nimport org.microg.gms.family.FamilyRole\n\n@Composable\nfun FamilyManagementFragmentScreen(\n    viewModel: FamilyViewModel,\n    onMemberClick: (MemberDataModel) -> Unit,\n    loadImage: (String?, ImageView) -> Unit\n) {\n    val uiState by viewModel.uiState.collectAsState()\n\n    LazyColumn(modifier = Modifier.fillMaxSize()) {\n        items(uiState.memberList, key = { it.memberId }) { member ->\n            if (member.isInviteEntry) {\n                InviteItem(\n                    member = member,\n                    onMemberClick = onMemberClick\n                )\n            } else {\n                MemberItem(\n                    member = member,\n                    currentMember = uiState.currentMember,\n                    onMemberClick = onMemberClick,\n                    imageLoader = loadImage\n                )\n            }\n        }\n    }\n}\n\n@Composable\nfun MemberDetailItem(\n    viewModel: FamilyViewModel,\n    member: MemberDataModel,\n    onMemberClick: (MemberDataModel) -> Unit,\n    loadImage: (String?, ImageView) -> Unit\n) {\n    val uiState by viewModel.uiState.collectAsState()\n\n    val isHeadOfHousehold = uiState.currentMember.role == FamilyRole.HEAD_OF_HOUSEHOLD.value\n    val actionTextId = if (member.isInvited) R.string.family_management_cancel_invite else R.string.family_management_remove_member\n\n    Column(\n        modifier = Modifier.fillMaxWidth()\n    ) {\n        MemberItem(\n            member = member,\n            currentMember = uiState.currentMember,\n            imageLoader = loadImage,\n            isDetail = true\n        )\n\n        HorizontalDivider(\n            modifier = Modifier.fillMaxWidth(),\n            thickness = 0.5.dp,\n            color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.3f)\n        )\n\n        Text(\n            text = stringResource(id = actionTextId),\n            fontSize = 14.sp,\n            color = MaterialTheme.colorScheme.primary,\n            modifier = Modifier\n                .padding(16.dp)\n                .clickable(isHeadOfHousehold) { onMemberClick.invoke(member) }\n        )\n    }\n}\n\n@Composable\nfun MemberItem(\n    member: MemberDataModel,\n    currentMember: MemberDataModel,\n    onMemberClick: ((MemberDataModel) -> Unit)? = null,\n    imageLoader: (String?, ImageView) -> Unit,\n    isDetail: Boolean = false\n) {\n    val isSame = member.memberId == currentMember.memberId\n    val isHeadOfHousehold = currentMember.role == FamilyRole.HEAD_OF_HOUSEHOLD.value\n    val isInvited = member.isInvited\n    var roleColor = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.6f)\n    val roleName = if (isInvited && !member.inviteSentDate.isNullOrEmpty()) {\n        if (isDetail) member.inviteSentDate else member.hohGivenName.also { roleColor = Color.Green }\n    } else member.hohGivenName\n\n    Row(\n        modifier = Modifier\n            .fillMaxWidth()\n            .height(66.dp)\n            .padding(horizontal = 16.dp)\n            .clickable(enabled = isHeadOfHousehold && !isSame && onMemberClick != null) {\n                onMemberClick?.invoke(member)\n            },\n        verticalAlignment = Alignment.CenterVertically\n    ) {\n        AndroidView(\n            factory = { context ->\n                CircleImageView(context).apply {\n                    layoutParams = ViewGroup.LayoutParams(36.dp.toPx(context), 36.dp.toPx(context))\n                    scaleType = ImageView.ScaleType.CENTER_CROP\n                }\n            },\n            modifier = Modifier.size(36.dp),\n            update = { imageView ->\n                if (member.profilePhotoUrl.isNullOrEmpty()) {\n                    imageView.setImageResource(R.drawable.ic_generic_man)\n                } else {\n                    imageLoader.invoke(member.profilePhotoUrl, imageView)\n                }\n            }\n        )\n\n        Column(\n            modifier = Modifier\n                .weight(1f)\n                .padding(start = 16.dp)\n        ) {\n            Text(\n                text = if (isDetail) member.email else member.displayName,\n                color = MaterialTheme.colorScheme.onBackground,\n                fontSize = 14.sp,\n            )\n            if (!roleName.isNullOrEmpty()) {\n                Text(\n                    text = roleName,\n                    color = roleColor,\n                    fontSize = 12.sp,\n                )\n            }\n        }\n    }\n}\n\n@Composable\nprivate fun InviteItem(\n    member: MemberDataModel,\n    onMemberClick: (MemberDataModel) -> Unit,\n    modifier: Modifier = Modifier,\n    iconRes: Int = android.R.drawable.ic_menu_add,\n    title: String = stringResource(id = R.string.family_management_invite_family_member),\n    subTitle: String = stringResource(id = R.string.family_management_invite_slots_left, member.inviteSlots)\n) {\n    Row(\n        modifier = modifier\n            .fillMaxWidth()\n            .height(66.dp)\n            .padding(horizontal = 16.dp)\n            .clickable { onMemberClick(member) },\n        verticalAlignment = Alignment.CenterVertically\n    ) {\n        Image(\n            painter = painterResource(id = iconRes),\n            contentDescription = title,\n            modifier = Modifier.size(36.dp)\n        )\n        Column(\n            modifier = Modifier\n                .weight(1f)\n                .padding(start = 16.dp)\n        ) {\n            Text(\n                text = title,\n                fontSize = 16.sp,\n                color = MaterialTheme.colorScheme.onBackground\n            )\n            Text(\n                text = subTitle,\n                fontSize = 13.sp,\n                color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.6f)\n            )\n        }\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/com/google/android/gms/feedback/FeedbackActivity.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.feedback\n\nimport android.os.Bundle\nimport android.widget.Toast\nimport androidx.appcompat.app.AppCompatActivity\nimport com.google.android.gms.R\n\nclass FeedbackActivity: AppCompatActivity() {\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        val content = resources.getString(R.string.feedback_disabled)\n        Toast.makeText(this, content, Toast.LENGTH_SHORT).show()\n        finish()\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/com/google/android/gms/locationsharingreporter/service/LocationShareIssue.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.locationsharingreporter.service\n\nenum class LocationShareIssue(val code: Int) {\n\n    UNKNOWN(0),\n    SHARE_ENDED(1),\n    UPLOAD_REQUEST_EXPIRED(2),\n    CLIENT_PERMISSION_LOST(3),\n    BATTERY_SAVER_ENABLED(4),\n    NOT_PRIMARY_DEVICE(5),\n    LOCATION_DISABLED_IN_SETTINGS(6),\n    CLIENT_NO_LOCATION_ACCESS(7),\n    NOT_SHARING_LOCATION(8),\n    INELIGIBLE(9),\n    MALFORMED_LOCATION_SHARE(10),\n    ACCOUNT_REMOVED(11),\n    NOT_SERVING_LOCATIONS(12),\n    SHARING_DISABLED(13),\n    CENTRAL_NOTICE_NOT_ACKED(14);\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/com/google/android/gms/locationsharingreporter/service/LocationSharingReporterApiService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.locationsharingreporter.service\n\nimport android.accounts.Account\nimport android.content.Context\nimport android.content.Intent\nimport android.os.Bundle\nimport android.os.Handler\nimport android.os.Looper\nimport android.os.Message\nimport android.os.Messenger\nimport android.util.Log\nimport androidx.appcompat.app.AppCompatActivity.RESULT_OK\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.LifecycleOwner\nimport androidx.lifecycle.lifecycleScope\nimport com.google.android.gms.common.Feature\nimport com.google.android.gms.common.api.ApiMetadata\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.api.internal.IStatusCallback\nimport com.google.android.gms.common.internal.ConnectionInfo\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport com.google.android.gms.locationsharingreporter.LocationUploadRequest\nimport com.google.android.gms.locationsharingreporter.NoticeAckedUpdateRequest\nimport com.google.android.gms.locationsharingreporter.PeriodicLocationReportingIssues\nimport com.google.android.gms.locationsharingreporter.PeriodicLocationUploadRequest\nimport com.google.android.gms.locationsharingreporter.StartLocationReportingRequest\nimport com.google.android.gms.locationsharingreporter.StopLocationReportingRequest\nimport com.google.android.gms.locationsharingreporter.internal.ILocationReportingIssuesCallback\nimport com.google.android.gms.locationsharingreporter.internal.ILocationReportingStatusCallbacks\nimport com.google.android.gms.locationsharingreporter.internal.ILocationSharingReporterService\nimport com.google.android.gms.locationsharingreporter.internal.ILocationUploadCallbacks\nimport com.google.android.gms.locationsharingreporter.service.LocationSharingUpdate.Companion.startUpdateLocation\nimport com.google.android.gms.locationsharingreporter.service.LocationSharingUpdate.Companion.stopUpdateLocation\nimport com.google.android.gms.locationsharingreporter.service.ReportingRequestStoreFile.isLocationSharingEnabled\nimport com.google.android.gms.locationsharingreporter.service.settings.EXTRA_MESSENGER\nimport com.google.android.gms.locationsharingreporter.service.settings.LocationShareConfirmActivity\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.launch\nimport kotlinx.coroutines.suspendCancellableCoroutine\nimport kotlinx.coroutines.sync.Mutex\nimport kotlinx.coroutines.sync.withLock\nimport kotlinx.coroutines.withContext\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.common.GooglePackagePermission\nimport org.microg.gms.common.PackageUtils\nimport org.microg.gms.profile.ProfileManager\nimport java.util.concurrent.ExecutionException\nimport kotlin.coroutines.resume\n\nprivate const val TAG = \"LocationSharingReporter\"\nval FEATURES = arrayOf(\n        Feature(\"LOCATION_SHARING_REPORTER\", 2),\n        Feature(\"LOCATION_SHARING_REPORTER_SYNC\", 1),\n        Feature(\"PERIODIC_LOCATION_SHARING_REPORTER\", 1),\n        Feature(\"START_LOCATION_REPORTING\", 1),\n        Feature(\"STOP_LOCATION_REPORTING\", 1),\n        Feature(\"GET_REPORTING_ISSUES\", 1),\n        Feature(\"UPDATE_NOTICE_STATE\", 1),\n        Feature(\"LOCATION_SHARING\", 1),\n)\n\nclass LocationSharingReporterApiService : BaseService(TAG, GmsService.LOCATION_SHARING_REPORTER) {\n\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService?) {\n        Log.d(TAG, \"handleServiceRequest: $request\")\n        val callingPackageName = PackageUtils.getAndCheckCallingPackage(this, request.packageName)\n                ?: throw IllegalArgumentException(\"Missing package name\")\n        PackageUtils.assertGooglePackagePermission(this, GooglePackagePermission.REPORTING)\n        ProfileManager.ensureInitialized(this)\n        callback.onPostInitCompleteWithConnectionInfo(\n                CommonStatusCodes.SUCCESS,\n                LocationSharingReporterApiServiceImpl(this, lifecycle).asBinder(),\n                ConnectionInfo().apply { features = FEATURES }\n        )\n    }\n\n    override fun onDestroy() {\n        Log.d(TAG, \"onDestroy: \")\n        super.onDestroy()\n    }\n}\n\nclass LocationSharingReporterApiServiceImpl(\n        val context: Context,\n        override val lifecycle: Lifecycle\n) : ILocationSharingReporterService.Stub(), LifecycleOwner {\n    private val activePermissionRequestLock = Mutex()\n\n    override fun uploadLocation(callback: ILocationUploadCallbacks, account: Account, request: LocationUploadRequest, apiMetadata: ApiMetadata?) {\n        Log.d(TAG, \"Not yet implemented: uploadLocation called with account: ${account.name}\")\n    }\n\n    override fun getReportingStatus(callback: ILocationReportingStatusCallbacks, account: Account, apiMetadata: ApiMetadata?) {\n        Log.d(TAG, \"Not yet implemented: getReportingStatus called with account: ${account.name}\")\n    }\n\n    override fun syncReportingStatus(callback: IStatusCallback, account: Account, apiMetadata: ApiMetadata?) {\n        Log.d(TAG, \"Not yet implemented: syncReportingStatus called with account: ${account.name}\")\n    }\n\n    override fun periodicLocationUpload(callback: IStatusCallback, account: Account, request: PeriodicLocationUploadRequest, apiMetadata: ApiMetadata?) {\n        Log.d(TAG, \"Not yet implemented: periodicLocationUpload called with account: ${account.name}, request: $request\")\n    }\n\n    override fun startLocationReporting(callback: IStatusCallback, account: Account, request: StartLocationReportingRequest, apiMetadata: ApiMetadata?) {\n        Log.d(TAG, \"startLocationReporting called with account: ${account.name}, request: $request\")\n        try {\n            validateGoogleAccount(account)\n            validateMakePrimaryOption(request.makePrimary)\n            validateReportingType(request.reportingType)\n\n            if (request.reportingType == ReportingType.SINGLE_SHARE_REPORTING_ENABLED.value) {\n                val locationShare = request.locationShare\n                        ?: return callback.onResult(Status.INTERNAL_ERROR.also {\n                            Log.w(TAG, \"Location share is null for SINGLE_SHARE_REPORTING\")\n                        })\n                validateLocationShare(locationShare)\n                require(request.requestDurationMs > 0L) {\n                    \"Request duration must be non-zero for SINGLE_SHARE_REPORTING\"\n                }\n            } else {\n                require(request.locationShare == null) {\n                    \"Location share must not be specified for ONGOING_REPORTING\"\n                }\n                require(request.requestDurationMs == 0L) {\n                    \"Request duration must not be specified for ONGOING_REPORTING\"\n                }\n            }\n\n            Log.d(TAG, \"Adding new start reporting request\")\n            if (request.noticeAckedUpdateRequest == null) {\n                Log.w(TAG, \"Notice acked update request is null\")\n                callback.onResult(Status.SUCCESS)\n                return\n            }\n\n            //startUpdateLocation(account, context)\n            lifecycleScope.launch {\n                val userConfirmed = activePermissionRequestLock.withLock {\n                    val locationSharingEnabled = isLocationSharingEnabled(context, account.name)\n                    Log.d(TAG, \"startLocationReporting locationSharingEnabled: $locationSharingEnabled\")\n                    if (!locationSharingEnabled) {\n                        requestUserConfirmation(context, account)\n                    } else {\n                        true\n                    }\n                }\n                Log.d(TAG, \"startLocationReporting userConfirmed: $userConfirmed\")\n                if (userConfirmed) {\n                    val reportingRequestStore = withContext(Dispatchers.IO) {\n                        val readSharesResponse = requestReadShares(context, account)\n                        readSharesResponseDetail(readSharesResponse, context, account)\n                    }\n                    if (reportingRequestStore.accountLocationSharingMap.isNotEmpty()) {\n                        startUpdateLocation(account, context)\n                    }\n                }\n                callback.onResult(Status.SUCCESS)\n            }\n        } catch (e: NullPointerException) {\n            Log.w(TAG, \"Internal error while handling new start location reporting request.\", e)\n            callback.onResult(Status.INTERNAL_ERROR)\n        } catch (e: IllegalArgumentException) {\n            Log.w(TAG, \"Error while handling new start location reporting request.\", e)\n            callback.onResult(Status(CommonStatusCodes.ERROR, \"Error while handling new start location reporting request.\"))\n        }\n    }\n\n    private suspend fun requestUserConfirmation(context: Context, account: Account): Boolean = suspendCancellableCoroutine { cont ->\n        val messenger = Messenger(object : Handler(Looper.getMainLooper()) {\n            override fun handleMessage(msg: Message) {\n                if (msg.what == RESULT_OK) {\n                    sendLocationSharingEnable(true, account, context)\n                }\n                cont.resume(msg.what == RESULT_OK)\n            }\n        })\n        val intent = Intent(context, LocationShareConfirmActivity::class.java)\n        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)\n        intent.putExtra(\"messenger\", messenger)\n        context.startActivity(intent)\n    }\n\n    override fun stopLocationReporting(callback: IStatusCallback?, account: Account, request: StopLocationReportingRequest, apiMetadata: ApiMetadata?) {\n        Log.d(TAG, \"stopLocationReporting called with account: ${account.name}, request: $request\")\n\n        lifecycleScope.launch(Dispatchers.IO) {\n            try {\n                val readSharesResponse = requestReadShares(context, account)\n                val reportingRequestStore = readSharesResponseDetail(readSharesResponse, context, account)\n                val locationShareListEmpty = reportingRequestStore.accountLocationSharingMap.isEmpty()\n                if (locationShareListEmpty) {\n                    stopUpdateLocation()\n                }\n                callback?.onResult(Status.SUCCESS)\n            } catch (e: NullPointerException) {\n                Log.w(TAG, \"Internal error while handling stop location reporting request.\", e)\n                callback?.onResult(Status.INTERNAL_ERROR)\n            } catch (e: IllegalArgumentException) {\n                Log.w(TAG, \"Error while handling stop location reporting request.\", e)\n                callback?.onResult(Status.INTERNAL_ERROR)\n            }\n        }\n    }\n\n    override fun updateNoticeState(callback: IStatusCallback?, account: Account, request: NoticeAckedUpdateRequest, apiMetadata: ApiMetadata?) {\n        Log.d(TAG, \"updateNoticeState called with account: ${account.name}, request: $request\")\n        try {\n            callback?.onResult(Status.SUCCESS)\n        } catch (e: NullPointerException) {\n            Log.w(TAG, \"Internal error while handling update notice state request.\")\n        } catch (e: IllegalArgumentException) {\n            Log.w(TAG, \"Error while handling update notice state request.\")\n        } catch (e: Exception) {\n            Log.w(TAG, \"Error while updateNoticeState $e\")\n        }\n    }\n\n    override fun getReportingIssues(callback: ILocationReportingIssuesCallback, account: Account, apiMetadata: ApiMetadata?) {\n        Log.d(TAG, \"getReportingIssues called with account: ${account.name}\")\n        try {\n            updateDeviceLocationSettingState(context)\n            updateDeviceBatterySaverState(context)\n            val (generalIssues, accountIssues) = getLocationReportingStatus(context)\n\n            val item = accountIssues[account.name] ?: emptySet()\n\n            val issuesByAccount = if (item.isNotEmpty()) {\n                Bundle().apply {\n                    putIntArray(account.name, item.toIntArray())\n                }\n            } else {\n                val isLocationSharingEnabled = isLocationSharingEnabled(context, account.name)\n                val issues = if (!isLocationSharingEnabled) {\n                    mutableSetOf(LocationShareIssue.SHARING_DISABLED.code)\n                } else {\n                    emptySet()\n                }\n                Bundle().apply {\n                    putIntArray(account.name, issues.toIntArray())\n                }\n            }\n\n            lifecycleScope.launch {\n                val reportingRequestStore = withContext(Dispatchers.IO) {\n                    val readSharesResponse = requestReadShares(context, account)\n                    readSharesResponseDetail(readSharesResponse, context, account)\n                }\n                val locationSharingEnabled = isLocationSharingEnabled(context, account.name)\n                if (reportingRequestStore.accountLocationSharingMap.isNotEmpty() && locationSharingEnabled) {\n                    startUpdateLocation(account, context)\n                }\n            }\n\n            val issues = PeriodicLocationReportingIssues(\n                    generalIssues.toIntArray(),\n                    issuesByAccount,\n                    true)\n            Log.d(TAG, \"getReportingIssues called with account: ${account.name}, issues: $issues\")\n            callback.onPeriodicLocationReportingIssues(Status.SUCCESS, issues, ApiMetadata.DEFAULT)\n        } catch (e: NullPointerException) {\n            Log.w(TAG, \"Internal error while handling getReportingIssues request.\", e)\n            callback.onPeriodicLocationReportingIssues(Status.INTERNAL_ERROR, null, ApiMetadata.SKIP)\n        } catch (e: ExecutionException) {\n            Log.w(TAG, \"Error while handling getReportingIssues request.\", e)\n            callback.onPeriodicLocationReportingIssues(Status(CommonStatusCodes.ERROR), null, ApiMetadata.SKIP)\n        } catch (e: Exception) {\n            Log.w(TAG, \"Error while handling getReportingIssues request.1\", e)\n            callback.onPeriodicLocationReportingIssues(Status.INTERNAL_ERROR, null, ApiMetadata.SKIP)\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/com/google/android/gms/locationsharingreporter/service/LocationSharingReporterExtensions.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.locationsharingreporter.service\n\nimport android.accounts.Account\nimport android.accounts.AccountManager\nimport android.content.Context\nimport android.content.ContextWrapper\nimport android.content.Intent\nimport android.content.IntentFilter\nimport android.content.pm.PackageManager\nimport android.location.Location\nimport android.location.LocationManager\nimport android.os.BatteryManager\nimport android.os.Bundle\nimport android.os.PowerManager\nimport android.util.Log\nimport android.os.Build.VERSION.SDK_INT\nimport androidx.core.location.LocationManagerCompat\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableSerializer\nimport com.google.android.gms.locationsharingreporter.LocationShare\nimport com.google.android.gms.locationsharingreporter.PeriodicLocationReportingIssues\nimport com.google.android.gms.locationsharingreporter.service.LocationSharingUpdate.Companion.stopUpdateLocation\nimport com.google.android.gms.locationsharingreporter.service.ReportingRequestStoreFile.getReportingRequestStore\nimport com.google.android.gms.locationsharingreporter.service.ReportingRequestStoreFile.setLocationSharingEnabled\nimport com.squareup.wire.GrpcClient\nimport com.squareup.wire.Service\nimport okhttp3.Interceptor\nimport okhttp3.OkHttpClient\nimport okhttp3.Response\nimport org.microg.gms.auth.AuthConstants\nimport org.microg.gms.profile.Build\nimport social.userlocation.frontend.BatteryInfo\nimport social.userlocation.frontend.ClientEnvironment\nimport social.userlocation.frontend.DeviceLocationMessage\nimport social.userlocation.frontend.DeviceLocationRecord\nimport social.userlocation.frontend.GeoPoint\nimport social.userlocation.frontend.GeofenceReportingConfig\nimport social.userlocation.frontend.ReadSharesRequest\nimport social.userlocation.frontend.ReadSharesResponse\nimport social.userlocation.frontend.UploadConfig\nimport social.userlocation.frontend.UploadLocationRequest\nimport social.userlocation.frontend.UploadLocationResponse\nimport social.userlocation.frontend.UploadPolicy\nimport social.userlocation.frontend.UserLocationFrontendServiceClient\nimport social.userlocation.frontend.WearOsAccountAndLocationConfig\nimport social.userlocation.frontend.hflh\nimport java.util.Collections\n\nprivate const val TAG = \"LocationSharingReporter\"\nprivate const val AUTH_TOKEN_SCOPE: String = \"oauth2:https://www.googleapis.com/auth/social.userlocation\"\nprivate const val STATE_ENABLED = 1\nprivate const val STATE_DISABLED = 2\n\n\nprivate class HeaderInterceptor(\n        private val oauthToken: String,\n) : Interceptor {\n    override fun intercept(chain: Interceptor.Chain): Response {\n        val original = chain.request().newBuilder().header(\"authorization\", \"Bearer $oauthToken\")\n        return chain.proceed(original.build())\n    }\n}\n\nprivate inline fun <reified S : Service> grpcClient(\n        account: Account,\n        accountManager: AccountManager\n): S {\n    val token = accountManager.blockingGetAuthToken(account, AUTH_TOKEN_SCOPE, true)\n    val client = OkHttpClient().newBuilder()\n            .addInterceptor(HeaderInterceptor(token))\n            .build()\n    val grpcClient = GrpcClient.Builder()\n            .client(client)\n            .baseUrl(\"https://socialuserlocation.googleapis.com\")\n            .minMessageToCompress(Long.MAX_VALUE)\n            .build()\n    return grpcClient.create(S::class)\n}\n\nfun sendLocationSharingEnable(isChecked: Boolean, account: Account, context: Context) {\n    setLocationSharingEnabled(context, isChecked, account.name)\n    val issues = if (!isChecked) {\n        mutableSetOf(LocationShareIssue.SHARING_DISABLED.code)\n    } else {\n        emptySet()\n    }\n    val issuesByAccount = Bundle().apply {\n        putIntArray(account.name, issues.toIntArray())\n    }\n    val periodicLocationReportingIssues = PeriodicLocationReportingIssues(intArrayOf(), issuesByAccount, true)\n    Log.d(TAG, \"sendLocationSharingEnable : $periodicLocationReportingIssues\")\n    val intent = Intent(\"com.google.android.gms.locationsharingreporter.PERIODIC_LOCATION_REPORTING_STATUS_DID_CHANGE\")\n    intent.putExtra(\"com.google.android.gms.locationsharingreporter.issues\", SafeParcelableSerializer.serializeToBytes(periodicLocationReportingIssues))\n    intent.`package` = \"com.google.android.apps.maps\"\n    context.sendBroadcast(intent)\n}\n\nfun requestReadShares(\n        context: Context,\n        account: Account\n): ReadSharesResponse? {\n    try {\n        val accountManager = AccountManager.get(context)\n        val geofenceReportingConfig = GeofenceReportingConfig.Builder()\n                .protocol(GeofenceReportingConfig.ReportingProtocol.REPORTING_PROTOCOL_MULTI_DEVICE_WITH_PRIMARY_DETECTION)\n                .build()\n\n        val config = WearOsAccountAndLocationConfig.Builder()\n                .isLocationReportingEnabled(true)\n                .build()\n\n        val readSharesRequest = ReadSharesRequest.Builder()\n                .config(config)\n                .geofenceReportingConfig(geofenceReportingConfig)\n                .build()\n\n        val grpcClient = grpcClient<UserLocationFrontendServiceClient>(account, accountManager)\n        return grpcClient.ReadShares().executeBlocking(readSharesRequest)\n    } catch (e: Exception) {\n        Log.w(TAG, \"Error reading shares from server\", e)\n        return null\n    }\n}\n\nfun readSharesResponseDetail(readSharesResponse: ReadSharesResponse?, context: Context, account: Account): ReportingRequestStore {\n    return ReportingRequestStoreFile.loadReportingRequestStore(context) { store ->\n        if (readSharesResponse != null) {\n            val updatedMap = if (readSharesResponse.pinpointLocationSharesList.isEmpty()) {\n                store.accountLocationSharingMap - account.name\n            } else {\n                val existingLocationSharingInfo = store.accountLocationSharingMap[account.name]\n                if (existingLocationSharingInfo == null) {\n                    val newSharingInfo = LocationSharingInfo.Builder().apply {\n                        createdTimestamp = readSharesResponse.locationReportingParameters?.serverTimestamp\n                                ?: System.currentTimeMillis()\n                    }.build()\n                    store.accountLocationSharingMap + (account.name to newSharingInfo)\n                } else {\n                    val updatedSharingInfo = existingLocationSharingInfo.newBuilder().apply {\n                        createdTimestamp = readSharesResponse.locationReportingParameters?.serverTimestamp\n                                ?: System.currentTimeMillis()\n                    }.build()\n                    store.accountLocationSharingMap + (account.name to updatedSharingInfo)\n                }\n            }\n\n            store.newBuilder()\n                    .startReportingTimestamp(System.currentTimeMillis())\n                    .accountLocationSharingMap(updatedMap)\n                    .build()\n        } else {\n            store\n        }\n    }\n}\n\nfun requestUploadLocation(\n        context: Context,\n        account: Account,\n        request: UploadLocationRequest\n): UploadLocationResponse? {\n    return runCatching {\n        val grpcClient: UserLocationFrontendServiceClient = grpcClient(account, AccountManager.get(context))\n        grpcClient.UploadLocation().executeBlocking(request)\n    }.onFailure { exception ->\n        Log.e(TAG, \"Upload location failed\", exception)\n    }.getOrNull()\n}\n\nfun validateGoogleAccount(account: Account) {\n    require(account.type == AuthConstants.DEFAULT_ACCOUNT_TYPE) {\n        \"Invalid account type, not a Google account\"\n    }\n}\n\nfun validateMakePrimaryOption(option: Int) {\n    val validOptions = listOf(\n            ReportingType.ONGOING_REPORTING_ENABLED.value,\n            ReportingType.SINGLE_SHARE_REPORTING_ENABLED.value,\n    )\n    require(option in validOptions) { \"Invalid MakePrimaryOption\" }\n}\n\nfun validateReportingType(type: Int) {\n    val validTypes = listOf(\n            ReportingType.SINGLE_SHARE_REPORTING_ENABLED.value,\n            ReportingType.ONGOING_REPORTING_ENABLED.value,\n    )\n    require(type in validTypes) {\n        \"Invalid ReportingType, valid reporting types are: SINGLE_SHARE_REPORTING_ENABLED, ONGOING_REPORTING_ENABLED.\"\n    }\n}\n\nfun validateLocationShare(locationShare: LocationShare?) {\n    require(locationShare?.obfuscatedGaiaId != null || locationShare?.tokenId != null) {\n        \"Invalid location share, neither obfuscated gaia ID nor token ID are specified in it.\"\n    }\n}\n\nfun updateDeviceBatterySaverState(context: Context) {\n    val powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager\n    val isPowerSaveMode = if (SDK_INT >= 21) {\n        powerManager.isPowerSaveMode\n    } else {\n        false\n    }\n    Log.i(TAG, \"Updating device battery saver state, isEnabled: $isPowerSaveMode\")\n\n    ReportingRequestStoreFile.updateReportingRequestStore(context) { requestStore ->\n        val state = if (isPowerSaveMode) STATE_ENABLED else STATE_DISABLED\n        return@updateReportingRequestStore requestStore.newBuilder().batterySaverState(state).build()\n    }\n}\n\nfun updateDeviceLocationSettingState(context: Context) {\n    val locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager\n    val isEnabled = LocationManagerCompat.isLocationEnabled(locationManager)\n    Log.i(TAG, \"Updating device location setting state, isEnabled: $isEnabled\")\n\n    ReportingRequestStoreFile.updateReportingRequestStore(context) { requestStore ->\n        val state = if (isEnabled) STATE_ENABLED else STATE_DISABLED\n        return@updateReportingRequestStore requestStore.newBuilder().locationSettingState(state).build()\n    }\n}\n\nfun getLocationReportingStatus(context: Context) : Pair<Set<Int>, Map<String, Set<Int>>>  {\n    val reportingRequestStore = getReportingRequestStore(context)\n    val generalIssues = mutableSetOf<Int>()\n    if (reportingRequestStore.batterySaverState == STATE_ENABLED) {\n        generalIssues.add(LocationShareIssue.BATTERY_SAVER_ENABLED.code)\n    }\n    if (reportingRequestStore.locationSettingState == STATE_ENABLED) {\n        generalIssues.add(LocationShareIssue.LOCATION_DISABLED_IN_SETTINGS.code)\n    }\n\n    val issuesByAccount = mutableMapOf<String, Set<Int>>()\n    val account = AccountManager.get(context).getAccountsByType(AuthConstants.DEFAULT_ACCOUNT_TYPE)[0]\n    if (account != null) {\n        if (reportingRequestStore.accountLocationSharingMap[account.name] == null) {\n            issuesByAccount[account.name] = HashSet(13)\n        }\n    }\n    return generalIssues to issuesByAccount\n}\n\nfun refreshAndUploadLocation(context: Context, account: Account, location: Location) {\n    Log.d(TAG, \"Refreshing periodic location reporting state\")\n    val gmscoreVersion = try {\n        context.packageManager.getPackageInfo(\"com.google.android.gms\", 0).versionName\n    } catch (e: PackageManager.NameNotFoundException) {\n        \"Unknown\"\n    }\n\n    val uploadLocationRequestBuilder = UploadLocationRequest().newBuilder()\n    uploadLocationRequestBuilder.requestCreationTime = System.currentTimeMillis()\n    uploadLocationRequestBuilder.isUserReportingDisabled = true// todo\n    uploadLocationRequestBuilder.geofenceReportingConfig(GeofenceReportingConfig().newBuilder()\n             .protocol(GeofenceReportingConfig.ReportingProtocol.REPORTING_PROTOCOL_MULTI_DEVICE_WITH_PRIMARY_DETECTION)\n             .build())\n    uploadLocationRequestBuilder.shouldEnableGeofencingOptimization(false)\n    uploadLocationRequestBuilder.uploadConfig(UploadConfig().newBuilder()\n            .unknowInt1(5).uploadPolicy(UploadPolicy().newBuilder()\n                    .allowNonOvenfreshUploads(true).build()).build())\n    uploadLocationRequestBuilder.clientEnvironment = ClientEnvironment().newBuilder()\n            .androidVersion(\"Android: ${Build.VERSION.SDK_INT}\")\n            .gmscoreVersion(\"Gmscore: $gmscoreVersion\")\n            .build()\n\n    val deviceLocationMessage =DeviceLocationMessage().newBuilder()\n        .deviceLocationRecord(\n            DeviceLocationRecord().newBuilder()\n                .eventTimestampMillis(System.currentTimeMillis())\n                .geoPoint(GeoPoint().newBuilder().altitude(location.altitude).longitude(location.longitude).latitude(location.latitude).build())\n                .accuracy(location.accuracy.toDouble())\n                .batteryInfo(getBatteryInfo(context))\n                .unKnownMessage5(Collections.singletonList(hflh().newBuilder().unknowInt1(30).build()))\n                .build()).build()\n    uploadLocationRequestBuilder.deviceLocationMessageList(Collections.singletonList(deviceLocationMessage))\n\n\n    val uploadLocationResponse = requestUploadLocation(context, account, uploadLocationRequestBuilder.build())\n    Log.d(TAG, \"UploadLocationResponse: $uploadLocationResponse\")\n\n    if (uploadLocationResponse?.locationReportingParameters?.isReportingEnabled == false) {\n        stopUpdateLocation()\n    }\n}\n\nprivate fun getBatteryInfo(context: Context) : BatteryInfo {\n    val intent = ContextWrapper(context).registerReceiver(null, IntentFilter(Intent.ACTION_BATTERY_CHANGED))\n    if (intent != null) {\n        val status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1)\n        val isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING\n\n        val level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)\n        val scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1)\n        if (level >= 0 && scale > 0) {\n            Log.d(TAG, \"getBatteryInfo isCharging: $isCharging battery level:${level * 100 / scale}\")\n            return BatteryInfo().newBuilder().isCharging(isCharging).batteryLevelPercent(level * 100 / scale).build()\n        }\n    }\n    return BatteryInfo()\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/com/google/android/gms/locationsharingreporter/service/LocationSharingUpdate.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.locationsharingreporter.service\n\nimport android.accounts.Account\nimport android.content.Context\nimport android.os.Binder\nimport android.os.Looper\nimport android.util.Log\nimport com.google.android.gms.location.LocationAvailability\nimport com.google.android.gms.location.LocationCallback\nimport com.google.android.gms.location.LocationRequest\nimport com.google.android.gms.location.LocationResult\nimport com.google.android.gms.location.LocationServices\nimport com.google.android.gms.location.Priority\nimport com.google.android.gms.locationsharingreporter.service.ReportingRequestStoreFile.isLocationSharingEnabled\nimport kotlinx.coroutines.CoroutineScope\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.launch\n\nclass LocationSharingUpdate {\n    companion object {\n        private var locationCallback: LocationCallback? = null\n        private var accountInfo: Account? = null\n        private const val TAG = \"LocationSharingUpdate\"\n        @Volatile\n        private var appContext: Context? = null\n\n        fun startUpdateLocation(account: Account, context: Context) {\n            Log.d(TAG, \"startUpdateLocation: \")\n            accountInfo = account\n            if (locationCallback == null) {\n                locationCallback = createLocationUpdatesCallback(context)\n                locationCallback?.let {\n                    val locationRequest = LocationRequest.Builder(5_000)\n                            .setPriority(Priority.PRIORITY_HIGH_ACCURACY)\n                            .setMinUpdateIntervalMillis(5_000)\n                            .setMaxUpdateDelayMillis(5_000)\n                            .setMaxUpdates(5_000)\n                            .setMaxUpdateAgeMillis(5_000)\n                            .build()\n                    val identity = Binder.clearCallingIdentity()\n                    LocationServices.getFusedLocationProviderClient(context.applicationContext).requestLocationUpdates(locationRequest, it, Looper.getMainLooper())\n                    Binder.restoreCallingIdentity(identity)\n                }\n            } else {\n                Log.d(TAG, \"startUpdateLocation locationCallback is not null\")\n            }\n        }\n\n        fun stopUpdateLocation() {\n            Log.d(TAG, \"stopUpdateLocation callback: $locationCallback\")\n            if (locationCallback != null) {\n                Log.w(TAG, \"stopUpdateLocation remove location callback\")\n                LocationServices.getFusedLocationProviderClient(appContext).removeLocationUpdates(locationCallback!!)\n                locationCallback = null\n            }\n        }\n\n        private fun createLocationUpdatesCallback(context: Context) : LocationCallback {\n            Log.d(TAG, \"createLocationUpdatesCallback: \")\n            appContext = context.applicationContext\n            val locationCallback = object : LocationCallback() {\n                override fun onLocationResult(locationResult: LocationResult?) {\n                    locationResult ?: return\n                    val location = locationResult.lastLocation\n                    Log.d(TAG, \"Location update: ${location.latitude}, ${location.longitude}}\")\n                    if (accountInfo != null && location != null && appContext != null) {\n                        val locationSharingEnabled = isLocationSharingEnabled(appContext!!, accountInfo!!.name)\n                        if (locationSharingEnabled) {\n                            CoroutineScope(Dispatchers.IO).launch {\n                                refreshAndUploadLocation(appContext!!, accountInfo!!, location)\n                            }\n                        } else {\n                            Log.w(TAG, \"onLocationResult location sharing turn off\")\n                            LocationServices.getFusedLocationProviderClient(appContext).removeLocationUpdates(locationCallback!!)\n                            locationCallback = null\n                        }\n                    }\n                }\n\n                override fun onLocationAvailability(availability: LocationAvailability?) {\n                    super.onLocationAvailability(availability)\n                }\n            }\n            return locationCallback\n        }\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/com/google/android/gms/locationsharingreporter/service/RefreshPolicy.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.locationsharingreporter.service\n\nenum class RefreshPolicy {\n    FORCE,\n    IF_CHANGED,\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/com/google/android/gms/locationsharingreporter/service/ReportingRequestStoreFile.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.locationsharingreporter.service\n\nimport android.content.Context\nimport android.util.Log\nimport java.io.File\nimport java.io.IOException\n\nobject ReportingRequestStoreFile {\n    private const val TAG = \"ReportingStoreFile\"\n    private const val REPORTING_REQUEST_STORE_FILE = \"Reporting.RequestStore.pb\"\n    private const val FILE_PREFIX = \"location_sharing_\"\n\n\n    fun setLocationSharingEnabled(context: Context, enabled: Boolean, accountName: String) {\n        val file = File(getLocationSharingReporterDir(context), FILE_PREFIX + accountName)\n        file.writeText(if (enabled) \"true\" else \"false\")\n    }\n\n\n    fun isLocationSharingEnabled(context: Context, accountName: String): Boolean {\n        val file = File(getLocationSharingReporterDir(context), FILE_PREFIX + accountName)\n        return if (file.exists()) {\n            file.readText() == \"true\"\n        } else {\n            false\n        }\n    }\n\n    private fun getLocationSharingReporterDir(context: Context) : File {\n        val dir = File(context.filesDir, \"locationsharingreporter\")\n        if (!dir.exists()) {\n            dir.mkdirs()\n        }\n        return dir\n    }\n\n    private fun getReportingRequestStoreFile(context: Context): File {\n        return File(getLocationSharingReporterDir(context), REPORTING_REQUEST_STORE_FILE)\n    }\n\n    fun getReportingRequestStore(context: Context): ReportingRequestStore {\n        synchronized(this) {\n            try {\n                val reportingRequestStoreFile = getReportingRequestStoreFile(context)\n                if (!reportingRequestStoreFile.exists()) {\n                    reportingRequestStoreFile.createNewFile()\n                }\n\n                return ReportingRequestStore.ADAPTER.decode(reportingRequestStoreFile.readBytes())\n            } catch (e: IOException) {\n                Log.w(TAG, \"Returning empty ReportingRequestStore due to file access error\", e)\n                return ReportingRequestStore()\n            }\n        }\n    }\n\n    fun updateReportingRequestStore(context: Context, callback: (requestStore: ReportingRequestStore) -> ReportingRequestStore) {\n        synchronized(this) {\n            val currentStore = getReportingRequestStore(context)\n            val newStore = callback(currentStore)\n\n            if (currentStore != newStore) {\n                try {\n                    getReportingRequestStoreFile(context).writeBytes(newStore.encode())\n                    Log.i(TAG, \"ReportingRequestStore updated successfully\")\n                } catch (e: IOException) {\n                    Log.w(TAG, \"Failed to update ReportingRequestStore\", e)\n                }\n            } else {\n                Log.d(TAG, \"No changes detected in ReportingRequestStore\")\n            }\n        }\n    }\n\n    fun loadReportingRequestStore(\n        context: Context,\n        transform: (ReportingRequestStore) -> ReportingRequestStore = { it }\n    ): ReportingRequestStore {\n        return synchronized(this) {\n            try {\n                val file = getReportingRequestStoreFile(context)\n                if (!file.exists()) {\n                    file.createNewFile()\n                    return@synchronized ReportingRequestStore()\n                }\n\n                val bytes = file.readBytes()\n                if (bytes.isEmpty()) return@synchronized ReportingRequestStore()\n\n                val reportingRequestStore = ReportingRequestStore.ADAPTER.decode(bytes)\n\n                val newReportingRequestStore = transform(reportingRequestStore)\n\n                if (reportingRequestStore != newReportingRequestStore) {\n                    file.writeBytes(newReportingRequestStore.encode())\n                }\n\n                newReportingRequestStore\n            } catch (e: IOException) {\n                Log.w(TAG, \"Returning empty ReportingRequestStore due to file access error\", e)\n                ReportingRequestStore()\n            }\n        }\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/com/google/android/gms/locationsharingreporter/service/settings/LocationShareConfirmActivity.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.locationsharingreporter.service.settings\n\nimport android.os.Bundle\nimport android.os.Message\nimport android.os.Messenger\nimport androidx.appcompat.app.AppCompatActivity\nimport com.google.android.gms.R\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder\n\nconst val EXTRA_MESSENGER = \"messenger\"\nclass LocationShareConfirmActivity : AppCompatActivity() {\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        val messenger = intent.getParcelableExtra<Messenger>(EXTRA_MESSENGER)\n        val builder = MaterialAlertDialogBuilder(this)\n        builder.setTitle(R.string.location_sharing_confirm_dialog_title)\n            .setCancelable(false)\n            .setMessage(R.string.location_sharing_confirm_dialog_text)\n            .setPositiveButton(android.R.string.ok) { _, _ ->\n\n                messenger?.send(Message.obtain().apply { what = RESULT_OK })\n                finish()\n            }\n            .setNegativeButton(android.R.string.cancel) { _, _ ->\n                messenger?.send(Message.obtain().apply { what = RESULT_CANCELED })\n                finish()\n            }\n        builder.show()\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/com/google/android/gms/locationsharingreporter/service/settings/LocationSharingSettingsActivity.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.locationsharingreporter.service.settings\n\nimport android.accounts.Account\nimport android.accounts.AccountManager\nimport android.content.Intent\nimport android.content.Intent.FLAG_ACTIVITY_FORWARD_RESULT\nimport android.graphics.Bitmap\nimport android.os.Bundle\nimport android.text.SpannableString\nimport android.text.Spanned\nimport android.text.style.UnderlineSpan\nimport android.util.Log\nimport android.view.View\nimport android.widget.ImageView\nimport android.widget.ProgressBar\nimport android.widget.TextView\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.appcompat.widget.SwitchCompat\nimport androidx.appcompat.widget.Toolbar\nimport androidx.cardview.widget.CardView\nimport androidx.core.graphics.drawable.RoundedBitmapDrawableFactory\nimport androidx.core.graphics.scale\nimport androidx.core.net.toUri\nimport androidx.lifecycle.lifecycleScope\nimport com.google.android.gms.R\nimport com.google.android.gms.locationsharingreporter.service.ReportingRequestStore\nimport com.google.android.gms.locationsharingreporter.service.ReportingRequestStoreFile\nimport com.google.android.gms.locationsharingreporter.service.readSharesResponseDetail\nimport com.google.android.gms.locationsharingreporter.service.requestReadShares\nimport com.google.android.gms.locationsharingreporter.service.sendLocationSharingEnable\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.launch\nimport kotlinx.coroutines.withContext\nimport org.microg.gms.accountsettings.ui.EXTRA_ACCOUNT_NAME\nimport org.microg.gms.accountsettings.ui.EXTRA_URL\nimport org.microg.gms.accountsettings.ui.MainActivity\nimport org.microg.gms.auth.AuthConstants\nimport org.microg.gms.people.PeopleManager\n\nclass LocationSharingSettingsActivity : AppCompatActivity() {\n    companion object {\n        private val TAG = LocationSharingSettingsActivity::class.simpleName\n        private const val LOCATION_SHARING_URL = \"https://myaccount.google.com/locationsharing\"\n        private const val LEARN_MORE_LOCATION_SHARING_URL = \"https://support.google.com/accounts/answer/9363497?co=GENIE.Platform=Android&visit_id=638923749787833764-2515936560&rd=1\"\n    }\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        setContentView(R.layout.activity_location_sharing_settings)\n        val toolbar = findViewById<Toolbar>(R.id.toolbar)\n        setSupportActionBar(toolbar)\n        supportActionBar?.setDisplayHomeAsUpEnabled(true)\n        supportActionBar?.setDisplayHomeAsUpEnabled(true)\n\n        toolbar.setNavigationOnClickListener {\n            onBackPressed()\n        }\n\n        val accountName = intent.getStringExtra(\"account_name\")\n        Log.d(TAG, \"account name: $accountName\")\n        if (accountName.isNullOrEmpty()) {\n            Log.w(TAG, \"Missing account name\")\n            finish()\n        }\n        val ivAvatar = findViewById<ImageView>(R.id.avatar_iv)\n        if (accountName != null) {\n            lifecycleScope.launchWhenStarted {\n                withContext(Dispatchers.IO) {\n                    PeopleManager.getOwnerAvatarBitmap(this@LocationSharingSettingsActivity, accountName, true)\n                }?.let { ivAvatar.setImageDrawable(getCircleBitmapDrawable(it)) }\n            }\n        }\n\n        findViewById<TextView>(R.id.account_email_tv).text = accountName\n\n        val currentAccount = AccountManager.get(this).getAccountsByType(AuthConstants.DEFAULT_ACCOUNT_TYPE).firstOrNull { it.name == accountName }\n\n        if (currentAccount == null) {\n            Log.w(TAG, \"Missing account\")\n            finish()\n        }\n\n        val locationSharingLayout = findViewById<View>(R.id.location_sharing_layout)\n        val progressBar = findViewById<ProgressBar>(R.id.progress_bar)\n\n        lifecycleScope.launch {\n            val reportingRequestStore = withContext(Dispatchers.IO) {\n                val readSharesResponse = requestReadShares(this@LocationSharingSettingsActivity, currentAccount!!)\n                readSharesResponseDetail(readSharesResponse, this@LocationSharingSettingsActivity, currentAccount)\n            }\n            Log.d(TAG, \"readSharesResponse: $reportingRequestStore\")\n            updateUI(reportingRequestStore, currentAccount!!)\n            locationSharingLayout.visibility = View.VISIBLE\n            progressBar.visibility = View.INVISIBLE\n        }\n    }\n\n\n    private fun updateUI(reportingRequestStore: ReportingRequestStore, account: Account) {\n        val switchShare = findViewById<SwitchCompat>(R.id.location_share_switch)\n        val locationShareListEmpty = reportingRequestStore.accountLocationSharingMap.isEmpty()\n        val locationSharingEnabled = ReportingRequestStoreFile.isLocationSharingEnabled(this, account.name)\n        switchShare.isChecked = !locationShareListEmpty && locationSharingEnabled\n        switchShare.isEnabled = !locationShareListEmpty\n        switchShare.setOnCheckedChangeListener { _, isChecked ->\n            if (isChecked) {\n                sendLocationSharingEnable(isChecked, account,  this)\n            } else {\n                showDialog(switchShare, account)\n            }\n        }\n\n        findViewById<View>(R.id.location_sharing_desc_tv).visibility = if (locationShareListEmpty) View.GONE else View.VISIBLE\n\n        val locationSharingLinkView = findViewById<CardView>(R.id.location_sharing_link_view)\n        locationSharingLinkView.visibility = if (locationShareListEmpty) View.GONE else View.VISIBLE\n        locationSharingLinkView.setOnClickListener {\n            val intent = Intent(this, MainActivity::class.java).apply {\n                action = \"android.intent.action.VIEW\"\n                putExtra(EXTRA_ACCOUNT_NAME, account.name)\n                putExtra(EXTRA_URL, LOCATION_SHARING_URL)\n            }\n            startActivity(intent)\n        }\n        val locationSharePrimaryHintTv = findViewById<TextView>(R.id.location_share_primary_hint_tv)\n        val locationShareSecondaryHintTv = findViewById<TextView>(R.id.location_share_secondary_hint_tv)\n        val locationShareWebLinkTv =findViewById<TextView>(R.id.location_share_web_lint_tv)\n        if (locationShareListEmpty) {\n            locationSharePrimaryHintTv.text = getString(R.string.location_sharing_disabled)\n            locationShareSecondaryHintTv.text = getString(R.string.location_sharing_turn_on_hint)\n            locationShareWebLinkTv.visibility = View.GONE\n        } else {\n            locationSharePrimaryHintTv.text = getString(R.string.location_sharing_turn_off_notify_hint)\n            locationShareSecondaryHintTv.text = getString(R.string.location_sharing_off_previous_hint)\n            locationShareWebLinkTv.visibility = View.VISIBLE\n        }\n        val moreAboutStr = getString(R.string.location_sharing_learn_more)\n        val spannable = SpannableString(moreAboutStr)\n        spannable.setSpan(\n                UnderlineSpan(),\n                0,\n                moreAboutStr.length,\n                Spanned.SPAN_EXCLUSIVE_EXCLUSIVE\n        )\n\n        locationShareWebLinkTv.text = spannable\n        locationShareWebLinkTv.setOnClickListener {\n            val intent = Intent(Intent.ACTION_VIEW, LEARN_MORE_LOCATION_SHARING_URL.toUri())\n            intent.addFlags(FLAG_ACTIVITY_FORWARD_RESULT)\n            startActivity(intent)\n        }\n    }\n\n\n    private fun showDialog(switchShare: SwitchCompat, account: Account) {\n        MaterialAlertDialogBuilder(this)\n                .setTitle(R.string.location_sharing_turn_off_title)\n                .setMessage(R.string.location_sharing_turn_off_hint)\n                .setCancelable(false)\n                .setPositiveButton(R.string.location_sharing_turn_off_confirm) { dialog, _ ->\n                    dialog.dismiss()\n                    sendLocationSharingEnable(false, account, this)\n                }\n                .setNegativeButton(R.string.location_sharing_turn_off_cancel) { dialog, _ ->\n                    dialog.dismiss()\n                    switchShare.isChecked = true\n                }\n                .show()\n    }\n\n\n    private fun getCircleBitmapDrawable(bitmap: Bitmap?) =\n        if (bitmap != null) RoundedBitmapDrawableFactory.create(resources, bitmap.let {\n            bitmap.scale(100, 100)\n        }).also { it.isCircular = true } else null\n\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/com/google/android/gms/maps/auth/ApiTokenService.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.maps.auth\n\nimport android.content.Context\nimport android.content.Intent\nimport android.os.Bundle\nimport android.os.IBinder\nimport android.text.TextUtils\nimport android.util.Log\nimport androidx.core.os.bundleOf\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.LifecycleOwner\nimport androidx.lifecycle.LifecycleService\nimport com.squareup.wire.GrpcClient\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.runBlocking\nimport kotlinx.coroutines.withContext\nimport kotlinx.coroutines.withTimeout\nimport okhttp3.OkHttpClient\nimport org.microg.gms.common.Constants\nimport org.microg.gms.common.PackageUtils\n\nprivate const val TAG = \"ApiTokenService\"\n\nprivate const val KEY_PACKAGE_NAME = \"PACKAGE_NAME\"\nprivate const val KEY_API_KEY = \"API_KEY\"\n\nprivate const val DEFAULT_TIME_OUT = 10 * 1000L\nprivate const val DEFAULT_VALIDITY_DURATION = 5 * 24 * 60 * 60 * 1000L\nprivate const val X_GMM_CLIENT_BIN = \"kAIF8gICCgA\"\nprivate const val X_GOOGLE_API_KEY = \"AIzaSyDgmW4ZMvNblSXqMOgsbY8uRrTnfR3E7pY\"\nprivate const val API_BASE_URL = \"https://mapsmobilesdks-pa.googleapis.com/\"\n\nprivate const val HEADER_GMM_CLIENT_BIN = \"X-Gmm-Client-bin\"\nprivate const val HEADER_GOOGLE_API_KEY = \"X-Goog-Api-Key\"\n\nclass ApiTokenService : LifecycleService() {\n\n    override fun onBind(intent: Intent): IBinder? {\n        super.onBind(intent)\n        Log.d(TAG, \"onBind\")\n        return ApiTokenServiceImpl(this, lifecycle).asBinder()\n    }\n\n    override fun onUnbind(intent: Intent?): Boolean {\n        Log.d(TAG, \"onUnbind\")\n        return super.onUnbind(intent)\n    }\n}\n\nclass ApiTokenServiceImpl(private val context: Context, override val lifecycle: Lifecycle) : IApiTokenService.Stub(), LifecycleOwner {\n\n    private fun errorBundle(code: Short) = bundleOf(\"ERROR_CODE\" to code)\n    private fun resultBundle(token: String?, expiryTime: Long?, validityDuration: Long?) = bundleOf(\n        \"EXPIRY_TIME\" to (expiryTime ?: (System.currentTimeMillis() + DEFAULT_VALIDITY_DURATION)),\n        \"VALIDITY_DURATION\" to (validityDuration ?: DEFAULT_VALIDITY_DURATION),\n        \"API_TOKEN\" to token\n    )\n\n    override fun requestApiToken(params: Bundle?): Bundle {\n        params?.keySet()\n        Log.d(TAG, \"Method requestApiToken is called. Thread:${Thread.currentThread().name} Params: $params\")\n        var callerPackageName = params?.getString(KEY_PACKAGE_NAME)\n        val packagesForUid = context.applicationContext.packageManager.getPackagesForUid(getCallingUid())\n        if (callerPackageName == null || packagesForUid.isNullOrEmpty() || (!packagesForUid.contains(callerPackageName) && !packagesForUid.contains(Constants.GMS_PACKAGE_NAME))) {\n            Log.d(TAG, \"error: ${String.format(ApiError.ERROR_INVALID_PACKAGE.value, callerPackageName)}\")\n            return errorBundle(ApiError.ERROR_INVALID_PACKAGE.code)\n        }\n        val signatureDigest = PackageUtils.firstSignatureDigest(context, callerPackageName)\n        if (TextUtils.isEmpty(signatureDigest)) {\n            Log.d(TAG, \"error: ${String.format(ApiError.ERROR_CERT_NOT_FOUND.value, callerPackageName)}\")\n            return errorBundle(ApiError.ERROR_CERT_NOT_FOUND.code)\n        }\n        val requestApiKey = params?.getString(KEY_API_KEY)\n        if (TextUtils.isEmpty(requestApiKey)) {\n            Log.d(TAG, \"error: ${ApiError.ERROR_API_KEY_NOT_FOUND.value}\")\n            return errorBundle(ApiError.ERROR_API_KEY_NOT_FOUND.code)\n        }\n        return runBlocking {\n            try {\n                val apiTokenRequest = ApiTokenRequest.build {\n                    apiKey = requestApiKey\n                    fingerprint = signatureDigest\n                    packageName = callerPackageName\n                    expiryTimeMillis = System.currentTimeMillis() + DEFAULT_VALIDITY_DURATION\n                }\n                val response = withTimeout(DEFAULT_TIME_OUT) {\n                    withContext(Dispatchers.IO) {\n                        grpcClient().CreateAndroidApiToken().executeBlocking(ApiTokenRequestWrapper.build { request = apiTokenRequest })\n                    }\n                }\n                if (TextUtils.isEmpty(response.apiToken)) {\n                    Log.d(TAG, \"error: ${ApiError.ERROR_API_TOKEN_EMPTY.value}\")\n                    errorBundle(ApiError.ERROR_API_TOKEN_EMPTY.code)\n                } else {\n                    Log.d(TAG, \"requestApiToken success. response: $response\")\n                    resultBundle(response.apiToken, response.expiryTime, response.durationTime)\n                }\n            } catch (e: Exception) {\n                Log.d(TAG, \"error: ${String.format(ApiError.ERROR_API_REQUEST.value, e.message)}\")\n                errorBundle(ApiError.ERROR_API_REQUEST.code)\n            }\n        }\n    }\n\n    private fun grpcClient(): MapsMobileSDKsServiceClient {\n        val client = OkHttpClient().newBuilder().addInterceptor { chain ->\n            val original = chain.request()\n            val requestBuilder = original.newBuilder().header(HEADER_GMM_CLIENT_BIN, X_GMM_CLIENT_BIN).header(HEADER_GOOGLE_API_KEY, X_GOOGLE_API_KEY)\n            val request = requestBuilder.build()\n            chain.proceed(request)\n        }.build()\n        val grpcClient = GrpcClient.Builder().client(client).baseUrl(API_BASE_URL).minMessageToCompress(Long.MAX_VALUE).build()\n        return grpcClient.create(MapsMobileSDKsServiceClient::class)\n    }\n\n}\n\nprivate enum class ApiError(val code: Short, val value: String) {\n    ERROR_INVALID_PACKAGE(1, \"Package name %s doesn't match any process executed with the caller's UID.\"),\n    ERROR_CERT_NOT_FOUND(2, \"Certificate footprint was not found for the package: %s.\"),\n    ERROR_API_KEY_NOT_FOUND(3, \"API key was not found in the request.\"),\n    ERROR_API_TOKEN_EMPTY(4, \"Received empty API token response.\"),\n    ERROR_API_REQUEST(5, \"Error requesting API token. message: %s.\")\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/com/google/android/gms/measurement/internal/AppMeasurementDynamiteService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.measurement.internal\n\nimport android.content.Intent\nimport android.os.Bundle\nimport android.os.Parcel\nimport android.util.Log\nimport androidx.annotation.Keep\nimport androidx.core.os.bundleOf\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.ObjectWrapper\nimport com.google.android.gms.measurement.api.internal.*\nimport org.microg.gms.utils.toHexString\nimport org.microg.gms.utils.warnOnTransactionIssues\nimport kotlin.random.Random\n\nprivate const val TAG = \"AppMeasurementService\"\n\n@Keep\nclass AppMeasurementDynamiteService : IAppMeasurementDynamiteService.Stub() {\n    private var initialized: Boolean = false\n    private var savedUserProperties: Bundle = Bundle()\n\n    private fun returnBundle(receiver: IBundleReceiver?, bundle: Bundle?) = runCatching { receiver?.onBundle(bundle) }\n    private fun returnResult(receiver: IBundleReceiver?, value: Any?) = returnBundle(receiver, bundleOf(\"r\" to value))\n\n    private fun generateSessionId(): Long {\n        val min = 1_000_000_000L\n        val max = 9_999_999_999L\n        return (min..max).random()\n    }\n\n    private fun requireInitialized() {\n        require(initialized) { \"Attempting to perform action before initialize.\" }\n    }\n\n    override fun initialize(context: IObjectWrapper?, params: InitializationParams?, eventTimeMillis: Long) {\n        Log.d(TAG, \"Not yet implemented: initialize\")\n        initialized = true\n    }\n\n    override fun logEvent(origin: String?, name: String?, params: Bundle?, z: Boolean, z2: Boolean, eventTimeMillis: Long) {\n        requireInitialized()\n        Log.d(TAG, \"Not yet implemented: logEvent\")\n    }\n\n    override fun logEventAndBundle(origin: String?, name: String?, params: Bundle?, receiver: IBundleReceiver?, eventTimeMillis: Long) {\n        requireInitialized()\n        Log.d(TAG, \"Not yet implemented: logEventAndBundle\")\n        returnResult(receiver, ByteArray(0))\n    }\n\n    override fun setUserProperty(origin: String?, name: String?, value: IObjectWrapper?, z: Boolean, eventTimeMillis: Long) {\n        requireInitialized()\n        setUserProperty(origin, name, ObjectWrapper.unwrap(value), z, eventTimeMillis)\n    }\n\n    private fun setUserProperty(origin: String?, name: String?, value: Any?, z: Boolean, eventTimeMillis: Long) {\n        Log.d(TAG, \"Not yet implemented: setUserProperty($origin, $name, $value, $z)\")\n        if (name == null) return  // Skip if name is null\n        when (value) {\n            null -> savedUserProperties.remove(name)\n            is String -> savedUserProperties.putString(name, value)\n            is Int -> savedUserProperties.putInt(name, value)\n            is Long -> savedUserProperties.putLong(name, value)\n            is Float -> savedUserProperties.putFloat(name, value)\n            is Boolean -> savedUserProperties.putBoolean(name, value)\n            is Double -> savedUserProperties.putDouble(name, value.toDouble())\n            else -> savedUserProperties.putString(name, value.toString())\n        }\n    }\n\n    override fun getUserProperties(origin: String?, prefix: String?, includeInternal: Boolean, receiver: IBundleReceiver?) {\n        requireInitialized()\n        Log.d(TAG, \"Not yet implemented: getUserProperties($origin, $prefix, $includeInternal)\")\n        returnBundle(receiver, savedUserProperties)\n    }\n\n    override fun getMaxUserProperties(origin: String?, receiver: IBundleReceiver?) {\n        requireInitialized()\n        returnResult(receiver, 25)\n    }\n\n    override fun setUserId(userId: String?, eventTimeMillis: Long) {\n        if (userId != null && userId.isEmpty()) {\n            Log.w(TAG, \"User ID must be non-empty or null\")\n        } else {\n            Log.d(TAG, \"Not yet implemented: setUserId($userId)\")\n            setUserProperty(null, \"_id\", userId, true, eventTimeMillis)\n        }\n    }\n\n    override fun setConditionalUserProperty(bundle: Bundle?, eventTimeMillis: Long) {\n        Log.d(TAG, \"Not yet implemented: setConditionalUserProperty\")\n    }\n\n    override fun clearConditionalUserProperty(name: String?, eventName: String?, bundle: Bundle?) {\n        Log.d(TAG, \"Not yet implemented: clearConditionalUserProperty($name, $eventName)\")\n    }\n\n    override fun getConditionalUserProperties(origin: String?, prefix: String?, receiver: IBundleReceiver?) {\n        Log.d(TAG, \"Not yet implemented: getConditionalUserProperties($origin, $prefix)\")\n        returnResult(receiver, arrayListOf<Bundle>())\n    }\n\n    override fun setMeasurementEnabled(measurementEnabled: Boolean, eventTimeMillis: Long) {\n        Log.d(TAG, \"Not yet implemented: setMeasurementEnabled($measurementEnabled)\")\n    }\n\n    override fun resetAnalyticsData(eventTimeMillis: Long) {\n        Log.d(TAG, \"Not yet implemented: resetAnalyticsData\")\n    }\n\n    override fun setMinimumSessionDuration(minimumSessionDuration: Long) {\n        Log.d(TAG, \"Not yet implemented: setMinimumSessionDuration($minimumSessionDuration)\")\n    }\n\n    override fun setSessionTimeoutDuration(sessionTimeoutDuration: Long) {\n        Log.d(TAG, \"Not yet implemented: setSessionTimeoutDuration($sessionTimeoutDuration)\")\n    }\n\n    override fun setCurrentScreen(obj: IObjectWrapper?, screenName: String?, className: String?, eventTimeMillis: Long) {\n        Log.d(TAG, \"Not yet implemented: setCurrentScreen($screenName, $className)\")\n    }\n\n    override fun getCurrentScreenName(receiver: IBundleReceiver?) {\n        Log.d(TAG, \"Not yet implemented: getCurrentScreenName\")\n        returnResult(receiver, null)\n    }\n\n    override fun getCurrentScreenClass(receiver: IBundleReceiver?) {\n        Log.d(TAG, \"Not yet implemented: getCurrentScreenClass\")\n        returnResult(receiver, null)\n    }\n\n    override fun setInstanceIdProvider(provider: IStringProvider?) {\n        Log.d(TAG, \"Not yet implemented: setInstanceIdProvider\")\n    }\n\n    override fun getCachedAppInstanceId(receiver: IBundleReceiver?) {\n        Log.d(TAG, \"Not yet implemented: getCachedAppInstanceId\")\n        returnResult(receiver, null)\n    }\n\n    override fun getAppInstanceId(receiver: IBundleReceiver?) {\n        Log.d(TAG, \"Not yet implemented: getAppInstanceId\")\n        // Generate a random ID -> equivalent to ephemeral app instance id\n        // Correct behavior would be to generate appropriate AppMetadata and call IMeasurementService.getAppInstanceId\n        val ephemeralAppInstanceId = Random.nextBytes(16).toHexString(\"\")\n        returnResult(receiver, ephemeralAppInstanceId)\n    }\n\n    override fun getGmpAppId(receiver: IBundleReceiver?) {\n        Log.d(TAG, \"Not yet implemented: getGmpAppId\")\n        returnResult(receiver, null)\n    }\n\n    override fun generateEventId(receiver: IBundleReceiver?) {\n        Log.d(TAG, \"Not yet implemented: generateEventId\")\n        returnResult(receiver, 1L)\n    }\n\n    override fun beginAdUnitExposure(adUnitId: String?, eventElapsedRealtime: Long) {\n        Log.d(TAG, \"Not yet implemented: beginAdUnitExposure\")\n    }\n\n    override fun endAdUnitExposure(adUnitId: String?, eventElapsedRealtime: Long) {\n        Log.d(TAG, \"Not yet implemented: endAdUnitExposure\")\n    }\n\n    override fun onActivityStarted(activity: IObjectWrapper?, eventElapsedRealtime: Long) {\n        Log.d(TAG, \"Not yet implemented: onActivityStarted\")\n    }\n\n    override fun onActivityStopped(activity: IObjectWrapper?, eventElapsedRealtime: Long) {\n        Log.d(TAG, \"Not yet implemented: onActivityStopped\")\n    }\n\n    override fun onActivityCreated(activity: IObjectWrapper?, savedInstanceState: Bundle?, eventElapsedRealtime: Long) {\n        Log.d(TAG, \"Not yet implemented: onActivityCreated\")\n    }\n\n    override fun onActivityDestroyed(activity: IObjectWrapper?, eventElapsedRealtime: Long) {\n        Log.d(TAG, \"Not yet implemented: onActivityDestroyed\")\n    }\n\n    override fun onActivityPaused(activity: IObjectWrapper?, eventElapsedRealtime: Long) {\n        Log.d(TAG, \"Not yet implemented: onActivityPaused\")\n    }\n\n    override fun onActivityResumed(activity: IObjectWrapper?, eventElapsedRealtime: Long) {\n        Log.d(TAG, \"Not yet implemented: onActivityResumed\")\n    }\n\n    override fun onActivitySaveInstanceState(activity: IObjectWrapper?, receiver: IBundleReceiver?, eventElapsedRealtime: Long) {\n        Log.d(TAG, \"Not yet implemented: onActivitySaveInstanceState\")\n        returnBundle(receiver, Bundle())\n    }\n\n    override fun performAction(bundle: Bundle?, receiver: IBundleReceiver?, eventTimeMillis: Long) {\n        requireInitialized()\n        returnBundle(receiver, null)\n    }\n\n    override fun logHealthData(i: Int, str: String?, obj: IObjectWrapper?, obj2: IObjectWrapper?, obj3: IObjectWrapper?) {\n        Log.d(TAG, \"Not yet implemented: logHealthData\")\n    }\n\n    override fun setEventInterceptor(proxy: IEventHandlerProxy?) {\n        Log.d(TAG, \"Not yet implemented: setEventInterceptor\")\n    }\n\n    override fun registerOnMeasurementEventListener(proxy: IEventHandlerProxy?) {\n        Log.d(TAG, \"Not yet implemented: registerOnMeasurementEventListener\")\n    }\n\n    override fun unregisterOnMeasurementEventListener(proxy: IEventHandlerProxy?) {\n        Log.d(TAG, \"Not yet implemented: unregisterOnMeasurementEventListener\")\n    }\n\n    override fun initForTests(map: MutableMap<Any?, Any?>?) {\n        Log.d(TAG, \"Not yet implemented: initForTests\")\n    }\n\n    override fun getTestFlag(receiver: IBundleReceiver?, i: Int) {\n        Log.d(TAG, \"Not yet implemented: getTestFlag\")\n        when(i) {\n            0 -> returnResult(receiver, \"---\")\n            1 -> returnResult(receiver, -1L)\n            2 -> returnResult(receiver, 3.0)\n            3 -> returnResult(receiver, -2)\n            4 -> returnResult(receiver, false)\n        }\n    }\n\n    override fun setDataCollectionEnabled(dataCollectionEnabled: Boolean) {\n        Log.d(TAG, \"Not yet implemented: setDataCollectionEnabled\")\n    }\n\n    override fun isDataCollectionEnabled(receiver: IBundleReceiver?) {\n        Log.d(TAG, \"Not yet implemented: isDataCollectionEnabled\")\n        returnResult(receiver, false)\n    }\n\n    override fun setDefaultEventParameters(bundle: Bundle?) {\n        Log.d(TAG, \"Not yet implemented: setDefaultEventParameters\")\n    }\n\n    override fun clearMeasurementEnabled(eventTimeMillis: Long) {\n        Log.d(TAG, \"Not yet implemented: clearMeasurementEnabled\")\n    }\n\n    override fun setConsent(bundle: Bundle?, eventTimeMillis: Long) {\n        Log.d(TAG, \"Not yet implemented: setConsent\")\n    }\n\n    override fun setConsentThirdParty(bundle: Bundle?, eventTimeMillis: Long) {\n        Log.d(TAG, \"Not yet implemented: setConsentThirdParty\")\n    }\n\n    override fun getSessionId(receiver: IBundleReceiver?) {\n        Log.d(TAG, \"Not yet implemented: getSessionId\")\n        returnResult(receiver, generateSessionId())\n    }\n\n    override fun setSgtmDebugInfo(intent: Intent?) {\n        Log.d(TAG, \"Not yet implemented: setSgtmDebugInfo\")\n    }\n\n    override fun setCurrentScreenByScionActivityInfo(info: ScionActivityInfo?, screenName: String?, className: String?, eventElapsedRealtime: Long) {\n        Log.d(TAG, \"Not yet implemented: setCurrentScreenByScionActivityInfo\")\n    }\n\n    override fun onActivityStartedByScionActivityInfo(info: ScionActivityInfo?, eventElapsedRealtime: Long) {\n        Log.d(TAG, \"Not yet implemented: onActivityStartedByScionActivityInfo\")\n    }\n\n    override fun onActivityStoppedByScionActivityInfo(info: ScionActivityInfo?, eventElapsedRealtime: Long) {\n        Log.d(TAG, \"Not yet implemented: onActivityStoppedByScionActivityInfo\")\n    }\n\n    override fun onActivityCreatedByScionActivityInfo(info: ScionActivityInfo?, savedInstanceState: Bundle?, eventElapsedRealtime: Long) {\n        Log.d(TAG, \"Not yet implemented: onActivityCreatedByScionActivityInfo\")\n    }\n\n    override fun onActivityDestroyedByScionActivityInfo(info: ScionActivityInfo?, eventElapsedRealtime: Long) {\n        Log.d(TAG, \"Not yet implemented: onActivityDestroyedByScionActivityInfo\")\n    }\n\n    override fun onActivityPausedByScionActivityInfo(info: ScionActivityInfo?, eventElapsedRealtime: Long) {\n        Log.d(TAG, \"Not yet implemented: onActivityPausedByScionActivityInfo\")\n    }\n\n    override fun onActivityResumedByScionActivityInfo(info: ScionActivityInfo?, eventElapsedRealtime: Long) {\n        Log.d(TAG, \"Not yet implemented: onActivityResumedByScionActivityInfo\")\n    }\n\n    override fun onActivitySaveInstanceStateByScionActivityInfo(info: ScionActivityInfo?, receiver: IBundleReceiver?, eventElapsedRealtime: Long) {\n        Log.d(TAG, \"Not yet implemented: onActivitySaveInstanceStateByScionActivityInfo\")\n        returnBundle(receiver, Bundle())\n    }\n\n    override fun retrieveAndUploadBatches(callback: IDynamiteUploadBatchesCallback?) {\n        Log.d(TAG, \"Not yet implemented: retrieveAndUploadBatches\")\n        runCatching { callback?.onUploadBatches() }\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/com/google/android/gms/semanticlocationhistory/SemanticLocationHistoryService.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.semanticlocationhistory\n\nimport android.content.ContentValues\nimport android.os.Parcel\nimport android.util.Log\nimport com.google.android.gms.common.ConnectionResult\nimport com.google.android.gms.common.Feature\nimport com.google.android.gms.common.api.ApiMetadata\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.api.internal.IStatusCallback\nimport com.google.android.gms.common.data.DataHolder\nimport com.google.android.gms.common.internal.ConnectionInfo\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableSerializer\nimport com.google.android.gms.location.reporting.ReportingState\nimport com.google.android.gms.semanticlocation.SemanticLocationState\nimport com.google.android.gms.semanticlocationhistory.internal.ISemanticLocationHistoryCallbacks\nimport com.google.android.gms.semanticlocationhistory.internal.ISemanticLocationHistoryService\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.utils.warnOnTransactionIssues\n\nprivate const val TAG = \"LocationHistoryService\"\n\nprivate val FEATURES = arrayOf(\n    Feature(\"semantic_location_history\", 12),\n    Feature(\"odlh_get_backup_summary\", 2),\n    Feature(\"odlh_delete_backups\", 1),\n    Feature(\"odlh_delete_history\", 1),\n    Feature(\"read_api_fprint_filter\", 1),\n    Feature(\"get_location_history_settings\", 1),\n    Feature(\"get_experiment_visits\", 1),\n    Feature(\"edit_csl\", 1),\n)\n\nclass SemanticLocationHistoryService : BaseService(TAG, GmsService.SEMANTIC_LOCATION_HISTORY) {\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        Log.d(TAG, \"handleServiceRequest: packageName: ${request.packageName}\")\n        callback.onPostInitCompleteWithConnectionInfo(\n            ConnectionResult.SUCCESS, SemanticLocationHistoryServiceImpl().asBinder(), ConnectionInfo().apply {\n                features = FEATURES\n            }\n        )\n    }\n}\n\nclass SemanticLocationHistoryServiceImpl : ISemanticLocationHistoryService.Stub() {\n\n    override fun getSegments(\n        callback: ISemanticLocationHistoryCallbacks?,\n        requestCredentials: RequestCredentials?,\n        request: LocationHistorySegmentRequest?,\n        apiMetadata: ApiMetadata?\n    ) {\n        Log.d(TAG, \"Not yet implemented: getSegments requestCredentials:$requestCredentials request:$request\")\n        val holder = DataHolder.empty(CommonStatusCodes.SUCCESS)\n        callback?.onGetSegmentsResponse(holder, ApiMetadata.SKIP)\n    }\n\n    override fun onDemandBackup(\n        callback: IStatusCallback?,\n        requestCredentials: RequestCredentials?,\n        apiMetadata: ApiMetadata?\n    ) {\n        Log.d(TAG, \"Not yet implemented: onDemandBackup requestCredentials:$requestCredentials\")\n        callback?.onResult(Status.SUCCESS)\n    }\n\n    override fun onDemandRestore(\n        callback: IStatusCallback?,\n        requestCredentials: RequestCredentials?,\n        list: List<*>?,\n        apiMetadata: ApiMetadata?\n    ) {\n        Log.d(TAG, \"Not yet implemented: onDemandRestore requestCredentials:$requestCredentials list:$list\")\n        callback?.onResult(Status.SUCCESS)\n    }\n\n    override fun getInferredHome(\n        callback: ISemanticLocationHistoryCallbacks?,\n        requestCredentials: RequestCredentials?,\n        apiMetadata: ApiMetadata?\n    ) {\n        Log.d(TAG, \"Not yet implemented: getInferredHome requestCredentials:$requestCredentials\")\n        callback?.onGetInferredHomeResponse(Status.SUCCESS, null, ApiMetadata.SKIP)\n    }\n\n    override fun getInferredWork(\n        callback: ISemanticLocationHistoryCallbacks?,\n        requestCredentials: RequestCredentials?,\n        apiMetadata: ApiMetadata?\n    ) {\n        Log.d(TAG, \"Not yet implemented: getInferredWork requestCredentials:$requestCredentials\")\n        callback?.onGetInferredWorkResponse(Status.SUCCESS, null, ApiMetadata.SKIP)\n    }\n\n    override fun editSegments(\n        callback: ISemanticLocationHistoryCallbacks?,\n        list: List<LocationHistorySegment>?,\n        requestCredentials: RequestCredentials?,\n        apiMetadata: ApiMetadata?\n    ) {\n        Log.d(TAG, \"Not yet implemented: editSegments requestCredentials:$requestCredentials list:$list\")\n        callback?.onEditSegmentsResponse(Status.SUCCESS, ApiMetadata.SKIP)\n    }\n\n    override fun deleteHistory(\n        callback: ISemanticLocationHistoryCallbacks?,\n        requestCredentials: RequestCredentials,\n        startTime: Long,\n        endTime: Long,\n        apiMetadata: ApiMetadata?\n    ) {\n        Log.d(TAG, \"Not yet implemented: deleteHistory requestCredentials:$requestCredentials startTime:$startTime endTime:$endTime\")\n        callback?.onDeleteHistoryResponse(Status.SUCCESS, ApiMetadata.SKIP)\n    }\n\n    override fun getUserLocationProfile(\n        callback: ISemanticLocationHistoryCallbacks?,\n        requestCredentials: RequestCredentials?,\n        apiMetadata: ApiMetadata?\n    ) {\n        Log.d(TAG, \"Not yet implemented: getUserLocationProfile requestCredentials:$requestCredentials\")\n        callback?.onGetUserLocationProfileResponse(Status.SUCCESS, null, ApiMetadata.SKIP)\n    }\n\n    override fun getBackupSummary(\n        callback: ISemanticLocationHistoryCallbacks?,\n        requestCredentials: RequestCredentials?,\n        apiMetadata: ApiMetadata?\n    ) {\n        Log.d(TAG, \"Not yet implemented: getBackupSummary requestCredentials:$requestCredentials\")\n        callback?.onGetBackupSummaryResponse(Status.SUCCESS, emptyList<OdlhBackupSummary>(), ApiMetadata.SKIP)\n    }\n\n    override fun deleteBackups(\n        callback: IStatusCallback?,\n        requestCredentials: RequestCredentials?,\n        list: List<*>?,\n        apiMetadata: ApiMetadata?\n    ) {\n        Log.d(TAG, \"Not yet implemented: deleteBackups requestCredentials:$requestCredentials list:$list\")\n        callback?.onResult(Status.SUCCESS)\n    }\n\n    override fun getLocationHistorySettings(\n        callback: ISemanticLocationHistoryCallbacks?,\n        requestCredentials: RequestCredentials?,\n        apiMetadata: ApiMetadata?\n    ) {\n        Log.d(TAG, \"Not yet implemented: getLocationHistorySettings requestCredentials:$requestCredentials\")\n        callback?.onLocationHistorySettings(\n            Status.SUCCESS,\n            LocationHistorySettings(false, 0, ReportingState(-1, -1, false, false, 1, 1, 0, false, true)),\n            ApiMetadata.SKIP\n        )\n    }\n\n    override fun getExperimentVisits(\n        callback: ISemanticLocationHistoryCallbacks?,\n        requestCredentials: RequestCredentials?,\n        apiMetadata: ApiMetadata?\n    ) {\n        Log.d(TAG, \"Not yet implemented: getExperimentVisits requestCredentials:$requestCredentials\")\n        val deviceMetadata = DeviceMetadata(listOf(\"0\"), false, false, emptyList<DeletionRange>(), 0)\n        val response = ExperimentVisitsResponse(emptyList<LocationHistorySegment>(), 0, deviceMetadata)\n        callback?.onGetExperimentVisitsResponse(Status.SUCCESS, response, ApiMetadata.SKIP)\n    }\n\n    override fun editCsl(\n        callback: IStatusCallback?,\n        requestCredentials: RequestCredentials?,\n        editInputs: SemanticLocationEditInputs?,\n        state: SemanticLocationState?,\n        apiMetadata: ApiMetadata?\n    ) {\n        Log.d(TAG, \"Not yet implemented: editCsl editInputs:$editInputs state:$state\")\n        callback?.onResult(Status.SUCCESS)\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean {\n        return warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n    }\n\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/com/google/android/gms/wearable/consent/TermsOfServiceActivity.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.wearable.consent\n\nimport android.os.Bundle\nimport androidx.appcompat.app.AppCompatActivity\n\nclass TermsOfServiceActivity : AppCompatActivity() {\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        setResult(RESULT_CANCELED)\n        finish()\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/accountaction/AccountActionActivity.kt",
    "content": "package org.microg.gms.accountaction\n\nimport android.accounts.Account\nimport android.content.Context\nimport android.content.Intent\nimport android.os.Bundle\nimport androidx.activity.ComponentActivity\nimport androidx.activity.compose.setContent\nimport androidx.annotation.RequiresApi\nimport androidx.compose.foundation.layout.Column\nimport androidx.compose.foundation.layout.fillMaxHeight\nimport androidx.compose.foundation.layout.padding\nimport androidx.compose.foundation.rememberScrollState\nimport androidx.compose.foundation.verticalScroll\nimport androidx.compose.material3.Button\nimport androidx.compose.material3.ButtonDefaults\nimport androidx.compose.material3.HorizontalDivider\nimport androidx.compose.material3.MaterialTheme\nimport androidx.compose.material3.Surface\nimport androidx.compose.material3.Text\nimport androidx.compose.runtime.Composable\nimport androidx.compose.runtime.mutableStateListOf\nimport androidx.compose.ui.Alignment\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.res.colorResource\nimport androidx.compose.ui.res.stringResource\nimport androidx.compose.ui.tooling.preview.Preview\nimport androidx.compose.ui.unit.dp\nimport com.google.android.gms.R\n\ninternal const val INTENT_KEY_USER_ACTION = \"userAction\"\ninternal const val INTENT_KEY_ACCOUNT_NAME = \"accountName\"\n\n@RequiresApi(21)\nclass AccountActionActivity : ComponentActivity() {\n\n    // mutableStateMapOf() returns an unordered map\n    private val taskMap: MutableList<Pair<Requirement, Boolean>> = mutableStateListOf()\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n\n        if (savedInstanceState == null) {\n            val requirements = intent.getSerializableExtra(INTENT_KEY_USER_ACTION) as Array<Requirement>\n            taskMap.addAll(requirements.map { it to false })\n        }\n\n        val accountName = intent.getStringExtra(INTENT_KEY_ACCOUNT_NAME) ?: \"<?>\"\n\n        setContent {\n            Content(accountName, taskMap.toMap()) {\n                finish()\n            }\n        }\n    }\n\n    override fun onResume() {\n        super.onResume()\n\n        for ((index, task) in taskMap.withIndex()) {\n            taskMap[index] = task.component1() to checkRequirementSatisfied(task.component1())\n        }\n    }\n\n    companion object {\n        fun createIntent(context: Context, account: Account, action: UserSatisfyRequirements) =\n            Intent(context, AccountActionActivity::class.java).apply {\n                putExtra(INTENT_KEY_USER_ACTION, action.actions.toTypedArray())\n                putExtra(INTENT_KEY_ACCOUNT_NAME, account.name)\n            }\n    }\n}\n\n@Composable\nfun Content(accountName: String, taskMap: Map<Requirement, Boolean>, finish: () -> Unit) {\n    Column {\n        Column {\n            Text(\n                text = stringResource(id = R.string.auth_action_activity_header),\n                modifier = Modifier.padding(top = 32.dp, start = 16.dp, end = 16.dp),\n                style = MaterialTheme.typography.headlineLarge\n            )\n            Text(\n                text = stringResource(id = R.string.auth_action_activity_explanation, accountName),\n                modifier = Modifier.padding(16.dp),\n                style = MaterialTheme.typography.bodyMedium\n            )\n            HorizontalDivider()\n        }\n        Surface(Modifier.fillMaxHeight()) {\n            Column(Modifier.verticalScroll(rememberScrollState())) {\n                UserInterventionComponents(userActions = taskMap)\n\n                Button(\n                    onClick = finish,\n                    enabled = !taskMap.containsValue(false),\n                    colors = ButtonDefaults.buttonColors(\n                        containerColor = colorResource(\n                            id = R.color.login_blue_theme_primary\n                        )\n                    ),\n                    modifier = Modifier\n                        .align(Alignment.End)\n                        .padding(16.dp)\n                ) {\n                    Text(text = stringResource(id = R.string.auth_action_activity_finish))\n                }\n            }\n        }\n    }\n}\n\n@Preview\n@Composable\nfun Preview() {\n    Content(\n        \"admin@example.com\",\n        mapOf(\n            Requirement.ENABLE_CHECKIN to true,\n            Requirement.ENABLE_GCM to true,\n            Requirement.ALLOW_MICROG_GCM to false,\n            Requirement.ENABLE_LOCKSCREEN to false\n        )\n    ) {}\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/accountaction/AccountNotification.kt",
    "content": "package org.microg.gms.accountaction\n\nimport android.Manifest\nimport android.accounts.Account\nimport android.app.Notification\nimport android.app.NotificationChannel\nimport android.app.NotificationManager\nimport android.app.PendingIntent\nimport android.content.Context\nimport android.content.Intent\nimport android.content.pm.PackageManager\nimport android.os.Build.VERSION.SDK_INT\nimport android.util.Log\nimport androidx.annotation.RequiresApi\nimport androidx.core.app.ActivityCompat\nimport androidx.core.app.NotificationCompat\nimport androidx.core.app.NotificationManagerCompat\nimport androidx.core.app.PendingIntentCompat\nimport com.google.android.gms.R\nimport org.microg.gms.auth.login.LoginActivity\n\nprivate const val CHANNEL_ID = \"AccountNotification\"\n\n@RequiresApi(21)\nfun Context.sendAccountReAuthNotification(account: Account) {\n    Log.d(TAG, \"sendAccountReAuthNotification: account: ${account.name}\")\n\n    registerAccountNotificationChannel()\n\n    val intent = Intent(this, LoginActivity::class.java).apply {\n        putExtra(LoginActivity.EXTRA_RE_AUTH_ACCOUNT, account)\n    }.let {\n        PendingIntentCompat.getActivity(\n            this, account.hashCode(), it, PendingIntent.FLAG_CANCEL_CURRENT, false\n        )\n    }\n\n    val notification: Notification =\n        NotificationCompat.Builder(this, CHANNEL_ID)\n            .setSmallIcon(R.drawable.ic_manage_accounts)\n            .setSound(null)\n            .setContentTitle(getString(R.string.auth_action_reauth_notification_title))\n            .setContentText(account.name)\n            .setOnlyAlertOnce(true)\n            .setContentIntent(intent)\n            .setAutoCancel(true)\n            .build()\n\n    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) ==\n        PackageManager.PERMISSION_GRANTED\n    ) {\n        NotificationManagerCompat.from(this).notify(account.hashCode(), notification)\n    }\n}\n\n@RequiresApi(21)\nfun Context.sendAccountActionNotification(account: Account, action: UserSatisfyRequirements) {\n\n    registerAccountNotificationChannel()\n\n    val intent: PendingIntent? = AccountActionActivity.createIntent(this, account, action).let {\n        PendingIntentCompat.getActivity(\n            this,\n            account.hashCode(),\n            it,\n            PendingIntent.FLAG_CANCEL_CURRENT,\n            false\n        )\n    }\n\n    val notification: Notification =\n        NotificationCompat.Builder(this, CHANNEL_ID)\n            .setSmallIcon(R.drawable.ic_manage_accounts)\n            .setSound(null)\n            .setOnlyAlertOnce(true)\n            .setContentTitle(getString(R.string.auth_action_notification_title))\n            .setContentText(getString(R.string.auth_action_notification_content))\n            .setSubText(account.name)\n            .setOnlyAlertOnce(true)\n            .setContentIntent(intent)\n            .setAutoCancel(true)\n            .build()\n\n    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) ==\n        PackageManager.PERMISSION_GRANTED\n    ) {\n        NotificationManagerCompat.from(this).notify(account.hashCode(), notification)\n    }\n\n}\n\nfun Context.registerAccountNotificationChannel() {\n    if (SDK_INT >= 26) {\n        val channel = NotificationChannel(\n            CHANNEL_ID,\n            getString(R.string.auth_action_notification_channel_name),\n            NotificationManager.IMPORTANCE_HIGH\n        ).apply {\n            description = getString(R.string.auth_action_notification_channel_description)\n            setSound(null, null)\n        }\n        getSystemService(NotificationManager::class.java)\n            .createNotificationChannel(channel)\n    }\n}\n\nfun Context.cancelAccountNotificationChannel(account: Account) {\n    NotificationManagerCompat.from(this).cancel(account.hashCode())\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/accountaction/ErrorResolver.kt",
    "content": "package org.microg.gms.accountaction\n\nimport android.accounts.Account\nimport android.content.Context\nimport android.content.Intent\nimport android.os.Build.VERSION.SDK_INT\nimport android.util.Log\nimport kotlinx.coroutines.runBlocking\nimport org.microg.gms.auth.login.LoginActivity\nimport org.microg.gms.common.Constants\nimport org.microg.gms.cryptauth.isLockscreenConfigured\nimport org.microg.gms.cryptauth.sendDeviceScreenlockState\nimport org.microg.gms.gcm.GcmDatabase\nimport org.microg.gms.gcm.GcmPrefs\nimport org.microg.gms.settings.SettingsContract\nimport java.io.IOException\n\n\n/**\n * High-level resolution: tell server that user has configured a lock screen\n */\nconst val DEVICE_MANAGEMENT_SCREENLOCK_REQUIRED = \"DeviceManagementScreenlockRequired\"\n\n/**\n * Indicates that the user is using an enterprise account that is set up to use Advanced\n * device management features, for which it is required to install a device manager.\n * This is not supported by microG.\n */\nconst val DEVICE_MANAGEMENT_REQUIRED = \"DeviceManagementRequired\"\n\n/**\n * Indicates that the user is using an enterprise account that is set up to use Advanced\n * device management features, for which it is required to install a device manager,\n * and that the device also needs manual admin approval.\n * This is not supported by microG.\n */\nconst val DEVICE_MANAGEMENT_ADMIN_PENDING_APPROVAL = \"DeviceManagementAdminPendingApproval\"\n\n/**\n * Indicates that the token stored on the device is no longer valid.\n */\nconst val BAD_AUTHENTICATION = \"BadAuthentication\"\n\nconst val SERVER_ERROR = \"Error 500\"\n\nconst val TAG = \"GmsAccountErrorResolve\"\n\n/**\n * @return `null` if it is unknown how to resolve the problem, an\n * appropriate `Resolution` otherwise\n */\nfun Context.resolveAuthErrorMessage(s: String): Resolution? = if (s.startsWith(\"Error=\")) {\n    resolveAuthErrorMessage(s.drop(\"Error=\".length))\n} else if (s.contains(SERVER_ERROR)) {\n    Reauthenticate\n} else when (s) {\n    DEVICE_MANAGEMENT_SCREENLOCK_REQUIRED -> listOf(\n        Requirement.ENABLE_CHECKIN,\n        Requirement.ENABLE_GCM,\n        Requirement.ALLOW_MICROG_GCM,\n        Requirement.ENABLE_LOCKSCREEN\n    )\n        .associateWith { checkRequirementSatisfied(it) }\n        .filterValues { satisfied -> !satisfied }.let {\n            if (it.isEmpty()) {\n                // all requirements are satisfied, crypt auth sync keys can be run\n                CryptAuthSyncKeys\n            } else {\n                // prompt user to satisfy missing requirements\n                UserSatisfyRequirements(it.keys)\n            }\n        }\n\n    DEVICE_MANAGEMENT_ADMIN_PENDING_APPROVAL, DEVICE_MANAGEMENT_REQUIRED ->\n        NoResolution(NoResolutionReason.ADVANCED_DEVICE_MANAGEMENT_NOT_SUPPORTED)\n\n    BAD_AUTHENTICATION -> Reauthenticate\n\n    else -> null\n}.also { Log.d(TAG, \"Error was: $s. Diagnosis: $it.\") }\n\nfun Context.checkRequirementSatisfied(requirement: Requirement): Boolean = when (requirement) {\n    Requirement.ENABLE_CHECKIN -> isCheckinEnabled()\n    Requirement.ENABLE_GCM -> isGcmEnabled()\n    Requirement.ALLOW_MICROG_GCM -> isMicrogAppGcmAllowed()\n    Requirement.ENABLE_LOCKSCREEN -> isLockscreenConfigured()\n}\n\nfun Context.isCheckinEnabled(): Boolean {\n    val settingsProjection = arrayOf(\n        SettingsContract.CheckIn.ENABLED,\n        SettingsContract.CheckIn.LAST_CHECK_IN\n    )\n    return SettingsContract.getSettings(this, SettingsContract.CheckIn.getContentUri(this), settingsProjection) { cursor ->\n        val checkInEnabled = cursor.getInt(0) != 0\n        val lastCheckIn = cursor.getLong(1)\n\n        // user is also asked to enable checkin if there had never been a successful checkin (network errors?)\n        lastCheckIn > 0 && checkInEnabled\n    }\n}\n\nfun Context.isGcmEnabled(): Boolean = GcmPrefs.get(this).isEnabled\n\nfun Context.isMicrogAppGcmAllowed(): Boolean {\n    val gcmPrefs = GcmPrefs.get(this)\n    val gcmDatabaseEntry = GcmDatabase(this).use {\n        it.getApp(Constants.GMS_PACKAGE_NAME)\n    }\n    return !(gcmDatabaseEntry != null &&\n            !gcmDatabaseEntry.allowRegister ||\n            gcmDatabaseEntry == null &&\n            gcmPrefs.confirmNewApps)\n\n}\n\nfun <T> Resolution.initiateFromBackgroundBlocking(context: Context, account: Account, retryFunction: RetryFunction<T>): T? {\n    when (this) {\n        CryptAuthSyncKeys -> {\n            Log.d(TAG, \"Resolving account error by performing cryptauth sync keys call.\")\n            runBlocking {\n                context.sendDeviceScreenlockState(account)\n            }\n            return retryFunction.run()\n        }\n        is NoResolution -> {\n            Log.w(TAG, \"This account cannot be used with microG due to $reason\")\n            return null\n        }\n        is UserSatisfyRequirements -> {\n            Log.w(TAG, \"User intervention required! You need to ${actions.joinToString(\", \")}.\")\n            if (SDK_INT >= 21) {\n                context.sendAccountActionNotification(account, this)\n            }\n            return null\n        }\n        Reauthenticate -> {\n            Log.w(TAG, \"Your account credentials have expired! Please remove the account, then sign in again.\")\n            if (SDK_INT >= 21) {\n                context.sendAccountReAuthNotification(account)\n            }\n            return null\n        }\n    }\n}\n\nfun <T> Resolution.initiateFromForegroundBlocking(context: Context, account: Account, retryFunction: RetryFunction<T>): T? {\n    when (this) {\n        CryptAuthSyncKeys -> {\n            Log.d(TAG, \"Resolving account error by performing cryptauth sync keys call.\")\n            runBlocking {\n                context.sendDeviceScreenlockState(account)\n            }\n            return retryFunction.run()\n        }\n        is NoResolution -> {\n            Log.w(TAG, \"This account cannot be used with microG due to $reason\")\n            return null\n        }\n        is UserSatisfyRequirements -> {\n            Log.w(TAG, \"User intervention required! You need to ${actions.joinToString(\", \")}.\")\n            if (SDK_INT >= 21) {\n                AccountActionActivity.createIntent(context, account, this).let {\n                    context.startActivity(it)\n                }\n            }\n            return null\n        }\n        Reauthenticate -> {\n            Log.w(TAG, \"Your account credentials have expired! Please remove the account, then sign in again.\")\n            Intent(context, LoginActivity::class.java).apply {\n                putExtra(LoginActivity.EXTRA_RE_AUTH_ACCOUNT, account)\n            }.let {\n                context.startActivity(it)\n            }\n            return null\n        }\n    }\n}\n\ninterface RetryFunction<T> {\n    @Throws(IOException::class)\n    fun run(): T\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/accountaction/Resolution.kt",
    "content": "package org.microg.gms.accountaction\n\nimport java.io.Serializable\n\nsealed class Resolution\n\n/**\n * In this situation, sending a CryptAuth \"sync keys\" query is sufficient\n * to resolve the problem. This is the case for enterprise accounts that\n * mandate device screenlocks after users enabled checkin, GCM, and\n * configured a lockscreen.\n */\ndata object CryptAuthSyncKeys : Resolution()\n\n/**\n * Represents a situation in which user actions are required to satisfy\n * the requirements that need to be fulfilled before the problem can be\n * fixed.\n */\ndata class UserSatisfyRequirements(val actions: Set<Requirement>) : Resolution(), Serializable\n\nenum class Requirement {\n    ENABLE_CHECKIN,\n    ENABLE_GCM,\n    ALLOW_MICROG_GCM,\n    ENABLE_LOCKSCREEN\n}\n\n/**\n * Represents a situation in which the user's authentication has become\n * invalid, and they need to enter their credentials again.\n */\ndata object Reauthenticate : Resolution()\n\n/**\n * Represents a situation that is known to be unsupported by microG.\n * Advise the user to remove the account.\n */\ndata class NoResolution(val reason: NoResolutionReason) : Resolution()\n\nenum class NoResolutionReason {\n    ADVANCED_DEVICE_MANAGEMENT_NOT_SUPPORTED\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/accountaction/UserInterventionComponents.kt",
    "content": "package org.microg.gms.accountaction\n\nimport android.app.Activity\nimport android.content.Intent\nimport androidx.compose.foundation.Canvas\nimport androidx.compose.foundation.layout.Box\nimport androidx.compose.foundation.layout.Column\nimport androidx.compose.foundation.layout.Row\nimport androidx.compose.foundation.layout.Spacer\nimport androidx.compose.foundation.layout.fillMaxSize\nimport androidx.compose.foundation.layout.padding\nimport androidx.compose.foundation.layout.size\nimport androidx.compose.foundation.layout.width\nimport androidx.compose.material.icons.Icons\nimport androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight\nimport androidx.compose.material.icons.filled.Check\nimport androidx.compose.material3.HorizontalDivider\nimport androidx.compose.material3.Icon\nimport androidx.compose.material3.LocalTextStyle\nimport androidx.compose.material3.MaterialTheme\nimport androidx.compose.material3.Surface\nimport androidx.compose.material3.Text\nimport androidx.compose.runtime.Composable\nimport androidx.compose.ui.Alignment\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.graphics.Color\nimport androidx.compose.ui.platform.LocalContext\nimport androidx.compose.ui.res.colorResource\nimport androidx.compose.ui.res.stringResource\nimport androidx.compose.ui.tooling.preview.Preview\nimport androidx.compose.ui.unit.dp\nimport com.google.android.gms.R\nimport org.microg.gms.accountaction.Requirement.*\nimport org.microg.gms.common.Constants\nimport org.microg.gms.ui.AskPushPermission\n\nconst val ACTION_CHECKIN = \"org.microg.gms.settings.CHECKIN_SETTINGS\"\nconst val ACTION_GCM = \"org.microg.gms.settings.GCM_SETTINGS\"\n\n@Composable\nfun UserInterventionComponents(userActions: Map<Requirement, Boolean>) {\n    for ((index, action) in userActions.entries.withIndex()) {\n        val context = LocalContext.current as Activity\n        val displayIndex = if (userActions.size > 1) index + 1 else null\n        when (action.component1()) {\n            ENABLE_CHECKIN -> UserInterventionCommonComponent(\n                title = stringResource(id = R.string.auth_action_step_enable_checkin),\n                description = stringResource(id = R.string.auth_action_step_enable_checkin_description),\n                sequenceNumber = displayIndex,\n                completed = action.component2()\n            ) {\n                Intent(ACTION_CHECKIN).let { context.startActivityForResult(it, 0) }\n            }\n            ENABLE_GCM -> UserInterventionCommonComponent(\n                title = stringResource(id = R.string.auth_action_step_enable_gcm),\n                description = stringResource(id = R.string.auth_action_step_enable_gcm_description),\n                sequenceNumber = displayIndex,\n                completed = action.component2()\n            ) {\n                Intent(ACTION_GCM).let { context.startActivityForResult(it, 1) }\n            }\n            ALLOW_MICROG_GCM -> UserInterventionCommonComponent(\n                title = stringResource(id = R.string.auth_action_step_allow_microg_gcm),\n                description = stringResource(id = R.string.auth_action_step_allow_microg_gcm_description),\n                sequenceNumber = displayIndex,\n                completed = action.component2()\n            ) {\n                Intent(context, AskPushPermission::class.java).apply {\n                    putExtra(AskPushPermission.EXTRA_REQUESTED_PACKAGE, Constants.GMS_PACKAGE_NAME)\n                    putExtra(AskPushPermission.EXTRA_FORCE_ASK, true)\n                    addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)\n                    addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)\n                    addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT)\n                }.let { context.startActivity(it) }\n            }\n            ENABLE_LOCKSCREEN -> UserInterventionCommonComponent(\n                title = stringResource(id = R.string.auth_action_step_enable_lockscreen),\n                description = stringResource(id = R.string.auth_action_step_enable_lockscreen_description),\n                sequenceNumber = displayIndex,\n                completed = action.component2()\n            ) {\n                runCatching {\n                    Intent(android.provider.Settings.ACTION_SECURITY_SETTINGS).let { context.startActivity(it) }\n                }.onFailure {\n                    Intent(android.provider.Settings.ACTION_SETTINGS).let { context.startActivity(it) }\n                }\n\n            }\n        }\n    }\n}\n\n@Composable\nfun UserInterventionCommonComponent(title: String, description: String, sequenceNumber: Int?, completed: Boolean, onClick: () -> Unit) {\n    Surface(onClick = onClick, enabled = !completed) {\n\n        val color = if (completed) {\n            colorResource(id = R.color.material_success)\n        } else {\n            colorResource(id = R.color.login_blue_theme_primary)\n        }\n\n        Column(\n            Modifier\n                .padding(top = 16.dp, start = 16.dp, end = 16.dp, bottom = 16.dp)\n        ) {\n\n            Row {\n                Box(Modifier.size(32.dp)) {\n                    Canvas(modifier = Modifier.fillMaxSize()) {\n                        drawCircle(\n                            color = color\n                        )\n                    }\n\n                    if (completed) {\n                        Icon(\n                            imageVector = Icons.Default.Check,\n                            contentDescription = stringResource(R.string.auth_action_step_completed_content_description),\n                            modifier = Modifier.align(Alignment.Center),\n                            tint = Color.White\n                        )\n                    } else {\n                        if (sequenceNumber == null) {\n                            Canvas(modifier = Modifier.size(12.dp).align(Alignment.Center)) {\n                                drawCircle(\n                                    color = Color.White\n                                )\n                            }\n                        } else {\n                            Text(\n                                text = sequenceNumber.toString(),\n                                modifier = Modifier.align(Alignment.Center),\n                                style = LocalTextStyle.current.copy(color = Color.White)\n                            )\n                        }\n                    }\n                }\n                Spacer(Modifier.width(16.dp))\n                Text(\n                    text = title,\n                    modifier = Modifier\n                        .align(Alignment.CenterVertically)\n                        .weight(1f),\n                    style = MaterialTheme.typography.labelLarge\n                )\n                Spacer(Modifier.width(16.dp))\n                if (!completed) {\n                    Icon(\n                        imageVector = Icons.AutoMirrored.Filled.KeyboardArrowRight,\n                        contentDescription = stringResource(id = R.string.auth_action_step_perform_content_description),\n                        modifier = Modifier.align(Alignment.CenterVertically)\n                    )\n                }\n            }\n            if (!completed) {\n                Text(\n                    text = description,\n                    modifier = Modifier.padding(top = 16.dp)\n                )\n            }\n        }\n    }\n}\n\n@Preview\n@Composable\nfun PreviewInterventionComponent() {\n    Column {\n        UserInterventionComponents(\n            userActions = mapOf(\n                ENABLE_CHECKIN to true,\n                ENABLE_GCM to true,\n                ALLOW_MICROG_GCM to false,\n                ENABLE_LOCKSCREEN to false\n            )\n        )\n        HorizontalDivider()\n        UserInterventionComponents(\n            userActions = mapOf(ENABLE_LOCKSCREEN to false)\n        )\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/LoaderActivity.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.accountsettings.ui\n\nimport android.accounts.AccountManager\nimport android.content.Intent\nimport android.content.Intent.*\nimport android.net.Uri\nimport android.os.Bundle\nimport android.util.Log\nimport androidx.appcompat.app.AppCompatActivity\nimport com.google.android.gms.locationsharingreporter.service.settings.LocationSharingSettingsActivity\nimport org.microg.gms.auth.AuthConstants.DEFAULT_ACCOUNT_TYPE\nimport org.microg.gms.common.PackageUtils\nimport org.microg.tools.AccountPickerActivity\n\nprivate const val TAG = \"AccountSettingsLoader\"\n\nprivate val ALLOWED_FALLBACK_PREFIXES = setOf(\"https://myaccount.google.com/\", \"https://takeout.google.com/\")\nprivate val BROWSABLE_SCREEN_IDS = setOf(1, 200, 400, 502, 527, 10003, 10050, 12700, 12701)\nprivate val ACCOUNT_CHOOSER_URI = Uri.parse(\"https://accounts.google.com/AccountChooser\")\n\nprivate const val QUERY_PARAM_CONTINUE = \"continue\"\nprivate const val QUERY_PARAM_LANG = \"hl\"\nprivate const val QUERY_PARAM_EMAIL = \"Email\"\n\nprivate const val EXTRA_ALLOWABLE_ACCOUNT_TYPES = \"allowableAccountTypes\"\n\nprivate const val REQUEST_ACCOUNT_PICKER = 1\n\nclass LoaderActivity : AppCompatActivity() {\n    private var canAskForAccount = false\n\n    private fun launchFallback() {\n        val fallbackUrl = intent?.getStringExtra(EXTRA_FALLBACK_URL)\n\n        if (fallbackUrl == null) {\n            Log.d(TAG, \"No fallback\")\n            finishResult(RESULT_CANCELED)\n        } else if (fallbackUrl in ALLOWED_FALLBACK_PREFIXES) {\n            // TODO: Error screen?\n            Log.d(TAG, \"Illegal fallback url\")\n            finishResult(RESULT_CANCELED)\n        } else {\n            val fallbackAuth = intent?.getBooleanExtra(EXTRA_FALLBACK_AUTH, false) ?: false\n            val uri = if (fallbackAuth) {\n                val builder = ACCOUNT_CHOOSER_URI.buildUpon().appendQueryParameter(QUERY_PARAM_CONTINUE, fallbackUrl)\n                val accountName = intent?.getStringExtra(EXTRA_ACCOUNT_NAME)\n                if (!accountName.isNullOrBlank()) {\n                    builder.appendQueryParameter(QUERY_PARAM_EMAIL, accountName)\n                }\n                val lang = Uri.parse(fallbackUrl).getQueryParameter(QUERY_PARAM_LANG)\n                if (lang != null) {\n                    builder.appendQueryParameter(QUERY_PARAM_LANG, lang)\n                }\n                builder.build()\n            } else {\n                Uri.parse(fallbackUrl)\n            }\n            Log.d(TAG, \"Opening fallback $fallbackUrl\")\n            // noinspection UnsafeImplicitIntentLaunch\n            val intent = Intent(ACTION_VIEW, uri).apply { addCategory(CATEGORY_BROWSABLE) }\n            startActivity(intent)\n            finishResult(RESULT_OK)\n        }\n    }\n\n    private fun launchMain() {\n        val requestedAccountName = intent.getStringExtra(EXTRA_ACCOUNT_NAME)\n        val ignoreAccount = intent?.getBooleanExtra(EXTRA_IGNORE_ACCOUNT, false) ?: false\n        val accounts = AccountManager.get(this).getAccountsByType(DEFAULT_ACCOUNT_TYPE)\n        val account = if (requestedAccountName != null) {\n            val account = accounts.find { it.name == requestedAccountName }\n            if (account == null) {\n                // TODO: Error screen?\n                Log.d(TAG, \"Account not found: $requestedAccountName\")\n                return finishResult(RESULT_CANCELED)\n            }\n            account\n        } else if (accounts.isEmpty()) {\n            if (intent?.getStringExtra(EXTRA_FALLBACK_URL) != null) {\n                return launchFallback()\n            } else {\n                // TODO: Error screen?\n                Log.d(TAG, \"No account configured\")\n                return finishResult(RESULT_CANCELED)\n            }\n        } else if (accounts.size > 1) {\n            if (canAskForAccount) {\n                val intent = Intent(this, AccountPickerActivity::class.java)\n                intent.putExtra(EXTRA_ALLOWABLE_ACCOUNT_TYPES, arrayOf(DEFAULT_ACCOUNT_TYPE))\n                startActivityForResult(intent, REQUEST_ACCOUNT_PICKER)\n                canAskForAccount = false\n                return\n            } else {\n                return finishResult(RESULT_CANCELED)\n            }\n        } else {\n            accounts.first()\n        }\n\n        val intent = Intent(this, MainActivity::class.java).apply {\n            action = intent.action\n            if (intent.hasExtra(EXTRA_THEME_CHOICE)) putExtra(EXTRA_THEME_CHOICE, intent.getIntExtra(EXTRA_THEME_CHOICE, 0))\n            putExtra(EXTRA_ACCOUNT_NAME, account.name)\n            if (ignoreAccount) putExtra(EXTRA_IGNORE_ACCOUNT, true)\n            putExtra(EXTRA_SCREEN_ID, intent.getIntExtra(EXTRA_SCREEN_ID, 1))\n            for (it in intent.extras?.keySet().orEmpty()) {\n                if (it.startsWith(EXTRA_SCREEN_OPTIONS_PREFIX)) putExtra(it, intent.getStringExtra(it))\n            }\n            putExtra(EXTRA_CALLING_PACKAGE_NAME, callingActivity?.packageName)\n            if (intent.action != ACTION_BROWSE_SETTINGS) {\n                addFlags(FLAG_ACTIVITY_FORWARD_RESULT)\n            }\n        }\n\n        startActivity(intent)\n\n        if (!isFinishing && !isChangingConfigurations) {\n            finishResult(RESULT_OK)\n        }\n    }\n\n    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {\n        if (requestCode == REQUEST_ACCOUNT_PICKER) {\n            if (resultCode == RESULT_OK && data?.hasExtra(AccountManager.KEY_ACCOUNT_NAME) == true) {\n                intent.putExtra(EXTRA_ACCOUNT_NAME, data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME))\n                launchMain()\n            } else {\n                finishResult(resultCode)\n            }\n        } else {\n            super.onActivityResult(requestCode, resultCode, data)\n        }\n    }\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        canAskForAccount = true\n        val extras = intent?.extras?.also { it.keySet() }\n        Log.d(TAG, \"Invoked with ${intent.action} and extras $extras\")\n\n        super.onCreate(savedInstanceState)\n\n        val isMainAllowed = if (intent == null || intent.action != ACTION_BROWSE_SETTINGS)\n            PackageUtils.isGooglePackage(this, callingActivity?.packageName)\n        else\n            extras?.getInt(EXTRA_SCREEN_ID, -1) in BROWSABLE_SCREEN_IDS\n\n        if (!isMainAllowed) {\n            launchFallback()\n        } else if (!isFinishing && !isChangingConfigurations){\n            if (intent.action == ACTION_LOCATION_SHARING) {\n                val intent = Intent(this, LocationSharingSettingsActivity::class.java).apply {\n                    addFlags(FLAG_ACTIVITY_FORWARD_RESULT)\n                    putExtras(intent)\n                }\n                startActivity(intent)\n                if (!isFinishing && !isChangingConfigurations) {\n                    finishResult(RESULT_OK)\n                }\n            } else {\n                launchMain()\n            }\n        }\n    }\n\n    private fun finishResult(resultCode: Int) {\n        setResult(resultCode)\n        finish()\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/MainActivity.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.accountsettings.ui\n\nimport android.accounts.Account\nimport android.accounts.AccountManager\nimport android.content.Intent\nimport android.graphics.Color\nimport android.graphics.Typeface\nimport android.net.Uri\nimport android.os.Bundle\nimport android.text.TextUtils\nimport android.util.Log\nimport android.view.Gravity\nimport android.view.View\nimport android.webkit.ValueCallback\nimport android.webkit.WebChromeClient.FileChooserParams\nimport android.webkit.WebView\nimport android.widget.ProgressBar\nimport android.widget.RelativeLayout\nimport android.widget.RelativeLayout.LayoutParams.MATCH_PARENT\nimport android.widget.RelativeLayout.LayoutParams.WRAP_CONTENT\nimport android.widget.TextView\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.appcompat.widget.Toolbar\nimport androidx.core.content.ContextCompat\nimport androidx.core.graphics.drawable.DrawableCompat\nimport com.google.android.gms.R\nimport org.microg.gms.accountsettings.ui.bridge.OcAdvertisingIdBridge\nimport org.microg.gms.accountsettings.ui.bridge.OcAndroidIdBridge\nimport org.microg.gms.accountsettings.ui.bridge.OcAppBarBridge\nimport org.microg.gms.accountsettings.ui.bridge.OcAppPermissionsBridge\nimport org.microg.gms.accountsettings.ui.bridge.OcClientInfoBridge\nimport org.microg.gms.accountsettings.ui.bridge.OcConsistencyBridge\nimport org.microg.gms.accountsettings.ui.bridge.OcContactsBridge\nimport org.microg.gms.accountsettings.ui.bridge.OcFido2Bridge\nimport org.microg.gms.accountsettings.ui.bridge.OcFidoU2fBridge\nimport org.microg.gms.accountsettings.ui.bridge.OcFilePickerBridge\nimport org.microg.gms.accountsettings.ui.bridge.OcFolsomBridge\nimport org.microg.gms.accountsettings.ui.bridge.OcPermissionsBridge\nimport org.microg.gms.accountsettings.ui.bridge.OcPlayProtectBridge\nimport org.microg.gms.accountsettings.ui.bridge.OcTelephonyBridge\nimport org.microg.gms.accountsettings.ui.bridge.OcTrustAgentBridge\nimport org.microg.gms.accountsettings.ui.bridge.OcUdcBridge\nimport org.microg.gms.accountsettings.ui.bridge.OcUiBridge\nimport org.microg.gms.auth.AuthConstants\nimport org.microg.gms.common.Constants\nimport org.microg.gms.common.Constants.GMS_PACKAGE_NAME\nimport org.microg.gms.gcm.ACTION_GCM_NOTIFY_COMPLETE\nimport org.microg.gms.gcm.EXTRA_NOTIFICATION_ACCOUNT\nimport org.microg.gms.people.PeopleManager\nimport org.microg.gms.profile.Build.VERSION.SDK_INT\nimport org.microg.gms.profile.ProfileManager\nimport java.util.concurrent.ExecutorService\nimport java.util.concurrent.Executors\n\nprivate const val TAG = \"AccountSettings\"\n\n// TODO: There likely is some API to figure those out...\nprivate val SCREEN_ID_TO_URL = hashMapOf(\n    1 to \"https://myaccount.google.com\",\n    200 to \"https://myaccount.google.com/privacycheckup\",\n    203 to \"https://myaccount.google.com/email\",\n    204 to \"https://myaccount.google.com/phone\",\n    205 to \"https://myaccount.google.com/birthday\",\n    206 to \"https://myaccount.google.com/gender\",\n    210 to \"https://myaccount.google.com/locationsharing\",\n    214 to \"https://myaccount.google.com/dashboard\",\n    215 to \"https://takeout.google.com\",\n    216 to \"https://myaccount.google.com/inactive\",\n    217 to \"https://myaccount.google.com/blocklist\",\n    218 to \"https://myaccount.google.com/profile-picture?interop=o\",\n    219 to \"https://myactivity.google.com/myactivity\",\n    220 to \"https://www.google.com/maps/timeline\",\n    224 to \"https://myactivity.google.com/activitycontrols?settings=search\",\n    227 to \"https://myactivity.google.com/activitycontrols?settings=location\",\n    231 to \"https://myactivity.google.com/activitycontrols?settings=youtube\",\n    235 to \"https://myactivity.google.com/activitycontrols/youtube\",\n    238 to \"https://www.google.com/setting/search/privateresults/\",\n    241 to \"https://myaccount.google.com/communication-preferences\",\n    242 to \"https://myadcenter.google.com/controls\",\n    300 to \"https://myaccount.google.com/language\",\n    301 to \"https://drive.google.com/settings/storage\",\n    302 to \"https://myaccount.google.com/deleteservices\",\n    303 to \"https://myaccount.google.com/deleteaccount\",\n    307 to \"https://payments.google.com/payments/home\",\n    308 to \"https://myaccount.google.com/subscriptions\",\n    309 to \"https://myaccount.google.com/purchases\",\n    310 to \"https://myaccount.google.com/reservations\",\n    312 to \"https://myaccount.google.com/accessibility\",\n    313 to \"https://myaccount.google.com/inputtools\",\n    400 to \"https://myaccount.google.com/security-checkup\",\n    401 to \"https://myaccount.google.com/signinoptions/password\",\n    403 to \"https://myaccount.google.com/signinoptions/two-step-verification\",\n    406 to \"https://myaccount.google.com/signinoptions/rescuephone\",\n    407 to \"https://myaccount.google.com/recovery/email\",\n    409 to \"https://myaccount.google.com/notifications\",\n    410 to \"https://myaccount.google.com/device-activity\",\n    417 to \"https://myaccount.google.com/find-your-phone\",\n    425 to \"https://myaccount.google.com/account-enhanced-safe-browsing\",\n    426 to \"https://myaccount.google.com/two-step-verification/authenticator\",\n    427 to \"https://myaccount.google.com/two-step-verification/backup-codes\",\n    429 to \"https://myaccount.google.com/two-step-verification/security-keys\",\n    430 to \"https://myaccount.google.com/two-step-verification/prompt\",\n    431 to \"https://myaccount.google.com/connections\",\n    432 to \"https://myaccount.google.com/two-step-verification/phone-numbers\",\n    433 to \"https://myaccount.google.com/signinoptions/passkeys\",\n    437 to \"https://myaccount.google.com/signinoptions/passwordoptional\",\n    500 to \"https://policies.google.com/privacy\",\n    503 to \"https://policies.google.com/terms\",\n    519 to \"https://myaccount.google.com/yourdata/maps\",\n    520 to \"https://myaccount.google.com/yourdata/search\",\n    530 to \"https://fit.google.com/privacy/settings\",\n    547 to \"https://myactivity.google.com/product/search\",\n    562 to \"https://myaccount.google.com/yourdata/youtube\",\n    580 to \"https://families.google.com/kidonboarding\",\n    10003 to \"https://myaccount.google.com/personal-info\",\n    10004 to \"https://myaccount.google.com/data-and-privacy\",\n    10005 to \"https://myaccount.google.com/people-and-sharing\",\n    10006 to \"https://myaccount.google.com/security\",\n    10007 to \"https://myaccount.google.com/payments-and-subscriptions\",\n    10015 to \"https://support.google.com/accounts\",\n    10050 to \"https://myaccount.google.com/profile\",\n    10052 to \"https://myaccount.google.com/family/details\",\n    10090 to \"https://myaccount.google.com/profile/name\",\n    10704 to \"https://www.google.com/account/about\",\n    10706 to \"https://myaccount.google.com/profile/profiles-summary\",\n    10728 to \"https://myaccount.google.com/data-and-privacy/how-data-improves-experience\",\n    10729 to \"https://myaccount.google.com/data-and-privacy/data-visibility\",\n    10731 to \"https://myaccount.google.com/embedded/family/createconfirmation\",\n    10759 to \"https://myaccount.google.com/address/home\",\n    10760 to \"https://myaccount.google.com/address/work\",\n    14500 to \"https://profilewidgets.google.com/alternate-profile/edit?interop=o&opts=sb\",\n)\n\nprivate val ALLOWED_WEB_PREFIXES = setOf(\n    \"https://accounts.google.com/\",\n    \"https://myaccount.google.com/\",\n    \"https://one.google.com/\",\n    \"https://myactivity.google.com/\",\n    \"https://timeline.google.com/\",\n    \"https://takeout.google.com/\",\n    \"https://www.google.com/maps/\",\n    \"https://www.google.com/setting/\",\n    \"https://drive.google.com/settings/\",\n    \"https://drive.google.com/accounts/\",\n    \"https://drive.google.com/u/1/settings/\",\n    \"https://payments.google.com/\",\n    \"https://policies.google.com/\",\n    \"https://fit.google.com/privacy/settings\",\n    \"https://maps.google.com/maps/timeline\",\n    \"https://myadcenter.google.com/controls\",\n    \"https://families.google.com/kidonboarding\",\n    \"https://profilewidgets.google.com/alternate-profile/edit\",\n    \"https://workspace.google.com/\",\n)\n\nprivate val ACTION_TO_SCREEN_ID = hashMapOf(\n    ACTION_SECURITY_SETTINGS to 10006,\n    ACTION_PRIVACY_SETTINGS to 10004,\n    ACTION_LOCATION_SHARING to 210,\n)\n\nclass MainActivity : AppCompatActivity() {\n    private lateinit var webView: WebView\n    private val executor: ExecutorService = Executors.newSingleThreadExecutor()\n\n    private fun getSelectedAccountName(): String? = null\n\n    private var filePathCallback: ValueCallback<Array<Uri>>? = null\n    private val pickerUtils = PicturePickerUtils(this, {\n        filePathCallback?.onReceiveValue(if (it != null) arrayOf(it) else emptyArray())\n        filePathCallback = null\n    }, {\n        Log.d(TAG, \"Picker error : ${it.name}<${it.value}>\")\n        filePathCallback?.onReceiveValue(emptyArray<Uri>())\n        filePathCallback = null\n    })\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        val extras = intent?.extras?.also { it.keySet() }\n        Log.d(TAG, \"Invoked with ${intent.action} and extras $extras\")\n        super.onCreate(savedInstanceState)\n\n        val screenId = ACTION_TO_SCREEN_ID[intent.action] ?: intent?.getIntExtra(EXTRA_SCREEN_ID, -1)?.takeIf { it > 0 } ?: 1\n        val product = intent?.getStringExtra(EXTRA_SCREEN_MY_ACTIVITY_PRODUCT)\n        val kidOnboardingParams = intent?.getStringExtra(EXTRA_SCREEN_KID_ONBOARDING_PARAMS)\n        val screenUrl = intent?.getStringExtra(EXTRA_URL)\n        val familyAppId = intent?.getStringExtra(EXTRA_SCREEN_FAMILY_APP_ID)\n\n        val screenOptions = intent.extras?.keySet().orEmpty()\n            .filter { it.startsWith(EXTRA_SCREEN_OPTIONS_PREFIX) }\n            .map { it.substring(EXTRA_SCREEN_OPTIONS_PREFIX.length) to intent.getStringExtra(it) }\n            .toMap()\n\n        val callingPackage = intent?.getStringExtra(EXTRA_CALLING_PACKAGE_NAME) ?: callingActivity?.packageName ?: Constants.GMS_PACKAGE_NAME\n\n        val ignoreAccount = intent?.getBooleanExtra(EXTRA_IGNORE_ACCOUNT, false) ?: false\n        val accountName = if (ignoreAccount) null else {\n            val accounts = AccountManager.get(this).getAccountsByType(AuthConstants.DEFAULT_ACCOUNT_TYPE)\n            val accountName = intent.getStringExtra(EXTRA_ACCOUNT_NAME) ?: intent.getParcelableExtra<Account>(\"account\")?.name ?: getSelectedAccountName()\n            accounts.find { it.name.equals(accountName) }?.name\n        }\n\n        if (accountName == null) {\n            Log.w(TAG, \"No account, going without!\")\n        }\n\n        if (screenId in SCREEN_ID_TO_URL) {\n            val screenUrl = screenUrl ?: SCREEN_ID_TO_URL[screenId]?.run {\n                if (screenId == 547 && !product.isNullOrEmpty()) {\n                    replace(\"search\", product)\n                } else if (screenId == 580 && !kidOnboardingParams.isNullOrEmpty()){\n                    \"$this?params=$kidOnboardingParams\"\n                } else if (screenId == 10731 && !familyAppId.isNullOrEmpty()) {\n                    \"$this?app_id=$familyAppId\"\n                } else { this }\n            }\n            val layout = RelativeLayout(this)\n            val titleView = TextView(this).apply {\n                text = ContextCompat.getString(context, R.string.pref_accounts_title)\n                textSize = 20f\n                setTextColor(if(isNightMode()) Color.WHITE else Color.BLACK)\n                maxLines = 1\n                ellipsize = TextUtils.TruncateAt.END\n                setTypeface(Typeface.create(\"sans-serif\", Typeface.NORMAL))\n                layoutParams = Toolbar.LayoutParams(MATCH_PARENT, WRAP_CONTENT, Gravity.START)\n            }\n            val toolbar = Toolbar(this).apply {\n                id = View.generateViewId()\n                setBackgroundColor(if(isNightMode()) Color.BLACK else Color.WHITE)\n                if (SDK_INT >= 21) {\n                    backgroundTintList = null\n                }\n                layoutParams = RelativeLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT).apply {\n                    addRule(RelativeLayout.ALIGN_PARENT_TOP)\n                }\n                val wrappedDrawable = ContextCompat.getDrawable(context, R.drawable.ic_arrow_close)?.let { DrawableCompat.wrap(it) }?.apply {\n                    DrawableCompat.setTint(this, if (isNightMode()) Color.WHITE else Color.BLACK)\n                }\n                navigationIcon = wrappedDrawable ?: ContextCompat.getDrawable(context, R.drawable.ic_arrow_close)\n                setNavigationOnClickListener { finishActivity() }\n                addView(titleView)\n            }\n            val progressBar = ProgressBar(this).apply {\n                id = View.generateViewId()\n                layoutParams = RelativeLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).apply {\n                    addRule(RelativeLayout.CENTER_IN_PARENT)\n                }\n                isIndeterminate = true\n            }\n            webView = WebView(this).apply {\n                id = View.generateViewId()\n                layoutParams = RelativeLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT).apply {\n                    addRule(RelativeLayout.BELOW, toolbar.id)\n                }\n                visibility = View.INVISIBLE\n                loadJsBridge(accountName, toolbar)\n            }\n            layout.addView(toolbar)\n            layout.addView(progressBar)\n            layout.addView(webView)\n            setContentView(layout)\n            WebViewHelper(this, webView, ALLOWED_WEB_PREFIXES).openWebView(screenUrl, accountName, callingPackage)\n            setResult(RESULT_OK)\n        } else {\n            Log.w(TAG, \"Unknown screen id, can't open corresponding web page\")\n            setResult(RESULT_CANCELED)\n            finish()\n        }\n    }\n\n    override fun onDestroy() {\n        super.onDestroy()\n        if (!executor.isShutdown) {\n            executor.shutdown()\n        }\n    }\n\n    override fun onBackPressed() {\n        if (this::webView.isInitialized && webView.canGoBack()) {\n            webView.goBack()\n        } else {\n            super.onBackPressed()\n        }\n    }\n\n    private fun WebView.loadJsBridge(accountName: String?, toolbar: Toolbar) {\n        ProfileManager.ensureInitialized(this@MainActivity)\n        addJavascriptInterface(OcUiBridge(this@MainActivity, accountName, this), OcUiBridge.NAME)\n        addJavascriptInterface(OcConsistencyBridge(), OcConsistencyBridge.NAME)\n        addJavascriptInterface(OcAppBarBridge(toolbar, this), OcAppBarBridge.NAME)\n        addJavascriptInterface(OcPlayProtectBridge(this), OcPlayProtectBridge.NAME)\n        addJavascriptInterface(OcTrustAgentBridge(this), OcTrustAgentBridge.NAME)\n        addJavascriptInterface(OcPermissionsBridge(this), OcPermissionsBridge.NAME)\n        addJavascriptInterface(OcFido2Bridge(this), OcFido2Bridge.NAME)\n        addJavascriptInterface(OcClientInfoBridge(), OcClientInfoBridge.NAME)\n        addJavascriptInterface(OcTelephonyBridge(), OcTelephonyBridge.NAME)\n        addJavascriptInterface(OcUdcBridge(this), OcUdcBridge.NAME)\n        addJavascriptInterface(OcAdvertisingIdBridge(this@MainActivity), OcAdvertisingIdBridge.NAME)\n        addJavascriptInterface(OcAndroidIdBridge(this@MainActivity), OcAndroidIdBridge.NAME)\n        addJavascriptInterface(OcAppPermissionsBridge(this), OcAppPermissionsBridge.NAME)\n        addJavascriptInterface(OcFolsomBridge(), OcFolsomBridge.NAME)\n        addJavascriptInterface(OcFidoU2fBridge(this), OcFidoU2fBridge.NAME)\n        addJavascriptInterface(OcContactsBridge(this), OcContactsBridge.NAME)\n        addJavascriptInterface(OcFilePickerBridge(this@MainActivity, this, executor), OcFilePickerBridge.NAME)\n    }\n\n    fun showFileChooser(fileChooserParams: FileChooserParams, targetFilePathCallback: ValueCallback<Array<Uri>>): Boolean {\n        if (SDK_INT < 21) {\n            return false\n        }\n        filePathCallback?.onReceiveValue(null)\n        filePathCallback = targetFilePathCallback\n        pickerUtils.launchChooser(fileChooserParams.acceptTypes?.joinToString() ?: \"*/*\")\n        return true\n    }\n\n    fun updateLocalAccountAvatar(newAvatarUrl: String?, accountName: String?) {\n        if (TextUtils.isEmpty(newAvatarUrl) || accountName == null) {\n            return\n        }\n        executor.submit {\n            PeopleManager.updateOwnerAvatar(this, accountName, newAvatarUrl)\n        }\n    }\n    \n    fun updateVerifyNotification(accountName: String) {\n        val notificationId = intent.getIntExtra(KEY_NOTIFICATION_ID, -1)\n        Log.d(TAG, \"updateVerifyNotification: notificationId: $notificationId\")\n        if (notificationId == -1) return\n        Intent(ACTION_GCM_NOTIFY_COMPLETE).apply {\n            setPackage(GMS_PACKAGE_NAME)\n            putExtra(EXTRA_NOTIFICATION_ACCOUNT, accountName)\n        }.let { sendBroadcast(it) }\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/PicturePickerUtils.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.accountsettings.ui\n\nimport android.Manifest\nimport android.app.Activity\nimport android.content.Intent\nimport android.content.pm.PackageManager\nimport android.net.Uri\nimport android.provider.MediaStore\nimport android.util.Log\nimport androidx.activity.result.ActivityResultLauncher\nimport androidx.activity.result.contract.ActivityResultContracts\nimport androidx.core.content.ContextCompat\nimport androidx.core.content.FileProvider\nimport java.io.File\n\nprivate const val CAMERA_TEMP_DIR = \"octa_camera_temp\"\nprivate const val TAG = \"PicturePickerUtils\"\n\nclass PicturePickerUtils(private val activity: MainActivity, private val resultCallback: (Uri?) -> Unit, private val errorCallback: (ResultStatus) -> Unit) {\n    private lateinit var fileChooserLauncher: ActivityResultLauncher<Intent>\n    private var currentPhotoUri: Uri? = null\n\n    init {\n        initializeChooserLauncher()\n    }\n\n    private fun initializeChooserLauncher() {\n        fileChooserLauncher = activity.registerForActivityResult(\n            ActivityResultContracts.StartActivityForResult()\n        ) { result ->\n            if (result.resultCode == Activity.RESULT_OK) {\n                val uri = result.data?.data\n                if (uri != null) {\n                    resultCallback(uri)\n                } else if (currentPhotoUri != null) {\n                    resultCallback(currentPhotoUri)\n                } else {\n                    errorCallback(ResultStatus.FAILED)\n                }\n            } else {\n                errorCallback(ResultStatus.USER_CANCEL)\n            }\n        }\n    }\n\n    fun launchChooser(mimeType: String) {\n        if (mimeType.startsWith(\"image/\") || mimeType == \"image/*\" || mimeType == \"*/*\") {\n            when {\n                ContextCompat.checkSelfPermission(activity, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED -> {\n                    launchChooserInternal(mimeType)\n                }\n\n                else -> {\n                    launchFilePickerOnly(mimeType)\n                }\n            }\n        } else {\n            launchFilePickerOnly(mimeType)\n        }\n    }\n\n    private fun launchFilePickerOnly(mimeType: String) {\n        val getContentIntent = Intent(Intent.ACTION_GET_CONTENT).apply {\n            type = mimeType\n            addCategory(Intent.CATEGORY_OPENABLE)\n        }\n        fileChooserLauncher.launch(getContentIntent)\n    }\n\n    private fun launchChooserInternal(mimeType: String) {\n        val getContentIntent = Intent(Intent.ACTION_GET_CONTENT).apply {\n            type = mimeType\n            addCategory(Intent.CATEGORY_OPENABLE)\n        }\n        val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)\n        if (takePictureIntent.resolveActivity(activity.packageManager) != null) {\n            currentPhotoUri = createImageUri()\n            if (currentPhotoUri != null) {\n                takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, currentPhotoUri)\n                val chooserIntent = Intent.createChooser(getContentIntent, \"Choose\")\n                chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, arrayOf(takePictureIntent))\n                fileChooserLauncher.launch(chooserIntent)\n            } else {\n                fileChooserLauncher.launch(getContentIntent)\n            }\n        } else {\n            fileChooserLauncher.launch(getContentIntent)\n        }\n    }\n\n    private fun createImageUri(): Uri? {\n        try {\n            val cacheDir = activity.cacheDir\n            val cameraDir = File(cacheDir, CAMERA_TEMP_DIR)\n            if (!cameraDir.exists()) {\n                cameraDir.mkdirs()\n            }\n            val photoFile = File(cameraDir, \"camera_temp.jpg\")\n            if (photoFile.exists()) {\n                photoFile.delete()\n            }\n            photoFile.createNewFile()\n            return FileProvider.getUriForFile(activity, \"${activity.packageName}.fileprovider\", photoFile)\n        } catch (e: Exception) {\n            Log.w(TAG, \"createImageUri: \", e)\n            return null\n        }\n    }\n\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/WebViewHelper.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.accountsettings.ui\n\nimport android.content.Intent\nimport android.content.Intent.URI_INTENT_SCHEME\nimport android.net.Uri\nimport android.os.Build.VERSION.SDK_INT\nimport android.provider.Settings\nimport android.util.Log\nimport android.view.View\nimport android.webkit.CookieManager\nimport android.webkit.ValueCallback\nimport android.webkit.WebChromeClient\nimport android.webkit.WebResourceRequest\nimport android.webkit.WebResourceResponse\nimport android.webkit.WebSettings\nimport android.webkit.WebView\nimport androidx.lifecycle.lifecycleScope\nimport androidx.webkit.WebResourceErrorCompat\nimport androidx.webkit.WebViewClientCompat\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.launch\nimport kotlinx.coroutines.withContext\nimport org.json.JSONObject\nimport org.microg.gms.auth.AuthConstants\nimport org.microg.gms.auth.AuthManager\nimport org.microg.gms.auth.login.LoginActivity\nimport org.microg.gms.common.Constants.GMS_PACKAGE_NAME\nimport org.microg.gms.common.PackageUtils\nimport java.net.URLEncoder\nimport java.util.Locale\nimport androidx.core.net.toUri\n\nprivate const val TAG = \"AccountSettingsWebView\"\n\nclass WebViewHelper(private val activity: MainActivity, private val webView: WebView, private val allowedPrefixes: Set<String> = emptySet<String>()) {\n    private var saveUserAvatar = false\n    fun openWebView(url: String?, accountName: String?, callingPackage: String? = null) {\n        prepareWebViewSettings(webView.settings, callingPackage)\n        webView.webChromeClient = object : WebChromeClient() {\n            override fun onShowFileChooser(\n                view: WebView?,\n                filePathCallback: ValueCallback<Array<Uri>>,\n                fileChooserParams: FileChooserParams\n            ): Boolean {\n                return activity.showFileChooser(fileChooserParams, filePathCallback)\n            }\n        }\n        webView.webViewClient = object : WebViewClientCompat() {\n            override fun onReceivedError(view: WebView, request: WebResourceRequest, error: WebResourceErrorCompat) {\n                Log.w(TAG, \"Error loading: $error\")\n            }\n\n            override fun onPageFinished(view: WebView?, url: String?) {\n                super.onPageFinished(view, url)\n                webView.visibility = View.VISIBLE\n            }\n\n            override fun shouldInterceptRequest(view: WebView?, request: WebResourceRequest?): WebResourceResponse? {\n                if (SDK_INT >= 21) {\n                    val requestUrl = request?.url?.toString() ?: return super.shouldInterceptRequest(view, request)\n                    try {\n                        if (saveUserAvatar && isGoogleAvatarUrl(requestUrl)) {\n                            activity.updateLocalAccountAvatar(requestUrl, accountName)\n                            saveUserAvatar = false\n                        }\n                        val overrideUri = requestUrl.toUri()\n                        if (overrideUri.getQueryParameter(\"source-path\") == \"/profile-picture/updating\") {\n                            saveUserAvatar = true\n                        }\n                    } catch (e: Exception) {\n                        Log.d(TAG, \"shouldInterceptRequest: error\", e)\n                    }\n                }\n                return super.shouldInterceptRequest(view, request)\n            }\n\n            override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {\n                Log.d(TAG, \"Navigating to $url\")\n                if (url.startsWith(\"intent:\")) {\n                    try {\n                        val intent = Intent.parseUri(url, URI_INTENT_SCHEME)\n                        if (intent.`package` == GMS_PACKAGE_NAME || PackageUtils.isGooglePackage(activity, intent.`package`)) {\n                            // Only allow to start Google packages\n                            activity.startActivity(intent)\n                            return true\n                        } else {\n                            Log.w(TAG, \"Ignoring request to start non-Google app\")\n                        }\n                    } catch (e: Exception) {\n                        Log.w(TAG, \"Error invoking intent\", e)\n                    }\n                    return false\n                }\n                if (url.startsWith(\"sms:\")) {\n                    try {\n                        val fixedUrl = url.replaceFirst(\"sms://\", \"sms:\")\n                        val intent = Intent(Intent.ACTION_VIEW, fixedUrl.toUri())\n                        activity.startActivity(intent)\n                        return true\n                    } catch (e: Exception) {\n                        Log.w(TAG, \"Failed to open SMS\", e)\n                    }\n                    return false\n                }\n                val overrideUri = url.toUri()\n                if (overrideUri.path?.endsWith(\"/signin/identifier\") == true) {\n                    val intent = Intent(activity, LoginActivity::class.java).apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) }\n                    activity.startActivity(intent)\n                    return true\n                }\n                if (overrideUri.path?.endsWith(\"/Logout\") == true) {\n                    val intent = Intent(Settings.ACTION_SYNC_SETTINGS).apply { putExtra(Settings.EXTRA_ACCOUNT_TYPES, arrayOf(AuthConstants.DEFAULT_ACCOUNT_TYPE)) }\n                    activity.startActivity(intent)\n                    return true\n                }\n                if (overrideUri.getQueryParameter(QUERY_GNOTS_ACTION) == ACTION_CLOSE || overrideUri.getQueryParameter(QUERY_WC_ACTION) == ACTION_CLOSE) {\n                    accountName?.let { activity.updateVerifyNotification(it) }\n                    activity.finishActivity()\n                    return true\n                }\n                if (allowedPrefixes.isNotEmpty() && allowedPrefixes.none { url.startsWith(it) }) {\n                    try {\n                        // noinspection UnsafeImplicitIntentLaunch\n                        val intent = Intent(Intent.ACTION_VIEW, overrideUri).apply { addCategory(Intent.CATEGORY_BROWSABLE) }\n                        if (callingPackage?.let { PackageUtils.isGooglePackage(activity, it) } == true) {\n                            try {\n                                intent.`package` = GMS_PACKAGE_NAME\n                                activity.startActivity(intent)\n                            } catch (e: Exception) {\n                                Log.w(TAG, \"Error forwarding to GMS \", e)\n                                intent.`package` = null\n                                activity.startActivity(intent)\n                            }\n                        } else activity.startActivity(intent)\n                    } catch (e: Exception) {\n                        Log.w(TAG, \"Error forwarding to browser\", e)\n                    }\n                    activity.finishActivity()\n                    return true\n                }\n                if (overrideUri.getQueryParameter(\"hl\").isNullOrEmpty()) {\n                    val urlWithLanguage = addLanguageParam(url)\n                    if (urlWithLanguage != null) {\n                        view.loadUrl(urlWithLanguage)\n                        return true\n                    }\n                }\n                return false\n            }\n        }\n\n        val urlWithLanguage: String? = addLanguageParam(url)\n        if (accountName != null) {\n            activity.lifecycleScope.launch {\n                withContext(Dispatchers.IO) {\n                    openWebWithAccount(accountName, urlWithLanguage)\n                }\n            }\n        } else {\n            loadWebViewUrl(urlWithLanguage)\n        }\n    }\n\n    private fun loadWebViewUrl(url: String?) {\n        if (url != null) {\n            webView.loadUrl(url)\n        } else {\n            activity.finishActivity()\n        }\n    }\n\n    private fun addLanguageParam(url: String?): String? {\n        val language = Locale.getDefault().language\n        return if (language.isNotEmpty()) {\n            url?.toUri()?.buildUpon()?.appendQueryParameter(\"hl\", language)?.toString()\n        } else {\n            url\n        }\n    }\n\n    private fun openWebWithAccount(accountName: String, url: String?) {\n        try {\n            val service = \"weblogin:continue=\" + URLEncoder.encode(url, \"utf-8\")\n            val authManager = AuthManager(activity, accountName, GMS_PACKAGE_NAME, service)\n            val authUrl = authManager.requestAuthWithForegroundResolution(false)?.auth\n            if (authUrl?.contains(\"WILL_NOT_SIGN_IN\") == true) {\n                throw RuntimeException(\"Would not sign in\")\n            }\n            Log.d(TAG, \"Opening $authUrl\")\n            webView.post {\n                if (SDK_INT >= 21) {\n                    CookieManager.getInstance().removeAllCookies {\n                        loadWebViewUrl(authUrl)\n                    }\n                } else {\n                    CookieManager.getInstance().removeAllCookie()\n                    loadWebViewUrl(authUrl)\n                }\n            }\n        } catch (e: Exception) {\n            Log.w(TAG, \"Failed to get weblogin auth.\", e)\n            activity.finishActivity()\n        }\n    }\n\n    private fun prepareWebViewSettings(settings: WebSettings, callingPackage:String?) {\n        settings.javaScriptEnabled = true\n        settings.setSupportMultipleWindows(false)\n        settings.allowFileAccess = false\n        settings.databaseEnabled = false\n        settings.setNeedInitialFocus(false)\n        settings.useWideViewPort = false\n        settings.setSupportZoom(false)\n        settings.javaScriptCanOpenWindowsAutomatically = false\n        settings.userAgentString = \"${settings.userAgentString} ${\n            String.format(Locale.getDefault(), \"OcIdWebView (%s)\", JSONObject().apply {\n                put(\"os\", \"Android\")\n                put(\"osVersion\", SDK_INT)\n                put(\"app\", GMS_PACKAGE_NAME)\n                put(\"callingAppId\", callingPackage ?: \"\")\n                put(\"isDarkTheme\", activity.isNightMode())\n            }.toString())\n        }\"\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/bridge/OcAdvertisingIdBridge.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.accountsettings.ui.bridge\n\nimport android.content.Context\nimport android.util.Log\nimport android.webkit.JavascriptInterface\nimport com.google.android.gms.ads.identifier.AdvertisingIdClient\n\nclass OcAdvertisingIdBridge(val context: Context) {\n\n    companion object {\n        const val NAME = \"ocAdvertisingId\"\n        private const val TAG = \"JS_$NAME\"\n    }\n\n    @JavascriptInterface\n    fun getAdvertisingId(): String? {\n        Log.d(TAG, \"getAdvertisingId: \")\n        return AdvertisingIdClient.getAdvertisingIdInfo(context).id\n    }\n\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/bridge/OcAndroidIdBridge.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.accountsettings.ui.bridge\n\nimport android.content.Context\nimport android.util.Log\nimport android.webkit.JavascriptInterface\nimport org.microg.gms.checkin.LastCheckinInfo\n\nclass OcAndroidIdBridge(val context: Context) {\n\n    companion object {\n        const val NAME = \"ocAndroidId\"\n        private const val TAG = \"JS_$NAME\"\n    }\n\n    @JavascriptInterface\n    fun getAndroidId(): String? {\n        Log.d(TAG, \"getAndroidId: \")\n        val androidId = LastCheckinInfo.read(context).androidId\n        return if (androidId != 0L) androidId.toString(16) else null\n    }\n\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/bridge/OcAppBarBridge.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.accountsettings.ui.bridge\n\nimport android.text.TextUtils\nimport android.util.Log\nimport android.webkit.JavascriptInterface\nimport android.webkit.WebView\nimport android.widget.TextView\nimport androidx.appcompat.widget.Toolbar\nimport androidx.core.content.ContextCompat\nimport com.google.android.gms.R\nimport org.microg.gms.accountsettings.ui.runOnMainLooper\n\nclass OcAppBarBridge(val toolBar: Toolbar, val webView: WebView) {\n\n    companion object {\n        const val NAME = \"ocAppBar\"\n        private const val TAG = \"JS_$NAME\"\n    }\n\n    @JavascriptInterface\n    fun clear() {\n        Log.d(TAG, \"clear: \")\n        setTitleText(null)\n        setTitleType(1)\n        setTitleFontFamily(0)\n        setStyle(1)\n        setAccountDisplay(1)\n        setUpButtonAction(1)\n        setHelpContext(null)\n        setActionMenu(null)\n        setShadowVisible(true)\n        setUpButtonVisible(true)\n        setPullToRefreshEnabled(true)\n    }\n\n    @JavascriptInterface\n    fun commitChanges() {\n        Log.d(TAG, \"commitChanges: \")\n    }\n\n    @JavascriptInterface\n    fun show(id: Double?) {\n        Log.d(TAG, \"show: id: $id\")\n    }\n\n    @JavascriptInterface\n    fun hide(id: Double?) {\n        Log.d(TAG, \"hide: id: $id\")\n    }\n\n    @JavascriptInterface\n    fun isNewAppBarFeaturesSupported(): Boolean {\n        Log.d(TAG, \"isNewAppBarFeaturesSupported: \")\n        return true\n    }\n\n    @JavascriptInterface\n    fun setAccountDisplay(displayId: Int?) {\n        Log.d(TAG, \"setAccountDisplay: displayId: $displayId\")\n    }\n\n    @JavascriptInterface\n    fun setActionMenu(base64Str: String?) {\n        Log.d(TAG, \"setActionMenu: base64Str: $base64Str\")\n    }\n\n    @JavascriptInterface\n    fun setHelpContext(url: String?) {\n        Log.d(TAG, \"setHelpContext: url: $url\")\n    }\n\n    @JavascriptInterface\n    fun setPullToRefreshEnabled(enable: Boolean?) {\n        Log.d(TAG, \"setPullToRefreshEnabled: enable: $enable\")\n    }\n\n    @JavascriptInterface\n    fun setShadowVisible(visible: Boolean?) {\n        Log.d(TAG, \"setShadowVisible: visible: $visible\")\n    }\n\n    @JavascriptInterface\n    fun setStyle(style: Int?) {\n        Log.d(TAG, \"setStyle: style: $style\")\n    }\n\n    @JavascriptInterface\n    fun setTitleFontFamily(family: Int?) {\n        Log.d(TAG, \"setTitleFontFamily: family: $family\")\n    }\n\n    @JavascriptInterface\n    fun setTitleText(title: String?) {\n        Log.d(TAG, \"setTitleText: title: $title\")\n        runOnMainLooper {\n            val text = if (TextUtils.isEmpty(title)) {\n                ContextCompat.getString(toolBar.context, R.string.pref_accounts_title)\n            } else title\n            toolBar.setCustomTitleText(text)\n        }\n    }\n\n    @JavascriptInterface\n    fun setTitleType(type: Int?) {\n        Log.d(TAG, \"setTitleType: type: $type\")\n    }\n\n    @JavascriptInterface\n    fun setUpButtonAction(action: Int?) {\n        Log.d(TAG, \"setUpButtonAction: action: $action\")\n    }\n\n    @JavascriptInterface\n    fun setUpButtonVisible(visible: Boolean?) {\n        Log.d(TAG, \"setUpButtonVisible: visible: $visible\")\n    }\n\n    private fun Toolbar.setCustomTitleText(text: String?) {\n        for (i in 0 until childCount) {\n            val child = getChildAt(i)\n            if (child is TextView) {\n                child.text = text\n                break\n            }\n        }\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/bridge/OcAppPermissionsBridge.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.accountsettings.ui.bridge\n\nimport android.util.Log\nimport android.webkit.JavascriptInterface\nimport android.webkit.WebView\nimport org.microg.gms.accountsettings.ui.evaluateJavascriptCallback\nimport java.util.Locale\n\nclass OcAppPermissionsBridge(val webView: WebView) {\n\n    companion object {\n        const val NAME = \"ocAppPermissions\"\n        private const val TAG = \"JS_$NAME\"\n    }\n\n    @JavascriptInterface\n    fun getAppPermissionsData(eventId: Int?) {\n        Log.d(TAG, \"getAppPermissionsData: eventId: $eventId\")\n        ocAppPermissionsCallbackError(eventId)\n    }\n\n    @JavascriptInterface\n    fun getSupportedPermissionsDescription(eventId: Int?) {\n        Log.d(TAG, \"getSupportedPermissionsDescription: eventId: $eventId\")\n        ocAppPermissionsCallbackError(eventId)\n    }\n\n    private fun ocAppPermissionsCallbackError(eventId: Int?) {\n        val format = String.format(Locale.ROOT, \"window.ocAppPermissionsCallback(%s, %s, %s)\", eventId, null, true)\n        evaluateJavascriptCallback(webView, format)\n    }\n\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/bridge/OcClientInfoBridge.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.accountsettings.ui.bridge\n\nimport org.microg.gms.profile.Build\nimport android.util.Log\nimport android.webkit.JavascriptInterface\nimport org.microg.gms.common.Constants\n\nclass OcClientInfoBridge() {\n\n    companion object {\n        const val NAME = \"ocClientInfo\"\n        private const val TAG = \"JS_$NAME\"\n    }\n\n    @JavascriptInterface\n    fun getGmsCoreModuleApkVersionName(): String? {\n        Log.d(TAG, \"getGmsCoreModuleApkVersionName: \")\n        return null\n    }\n\n    @JavascriptInterface\n    fun getGmsCoreModuleVersion(): Int {\n        Log.d(TAG, \"getGmsCoreModuleVersion: \")\n        return 0\n    }\n\n    @JavascriptInterface\n    fun getGmsCoreVersion(): Int {\n        Log.d(TAG, \"getGmsCoreVersion: \")\n        return Constants.GMS_VERSION_CODE\n    }\n\n    @JavascriptInterface\n    fun getOsVersion(): String? {\n        Log.d(TAG, \"getOsVersion: \")\n        return Build.VERSION.RELEASE\n    }\n\n    @JavascriptInterface\n    fun getSdkVersion(): Int {\n        Log.d(TAG, \"getSdkVersion: \")\n        return Build.VERSION.SDK_INT\n    }\n\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/bridge/OcConsistencyBridge.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.accountsettings.ui.bridge\n\nimport android.util.Log\nimport android.webkit.JavascriptInterface\n\nclass OcConsistencyBridge() {\n\n    companion object {\n        const val NAME = \"ocConsistency\"\n        private const val TAG = \"JS_$NAME\"\n    }\n\n    @JavascriptInterface\n    fun accountWasDeleted() {\n        Log.d(TAG, \"accountWasDeleted: \")\n    }\n\n    @JavascriptInterface\n    fun accountWasRenamed() {\n        Log.d(TAG, \"accountWasRenamed: \")\n    }\n\n    @JavascriptInterface\n    fun verifyActualAccountId(accountId: String?) {\n        Log.d(TAG, \"verifyActualAccountId: accountId: $accountId\")\n    }\n\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/bridge/OcContactsBridge.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.accountsettings.ui.bridge\n\nimport android.util.Log\nimport android.webkit.JavascriptInterface\nimport android.webkit.WebView\nimport org.microg.gms.accountsettings.ui.evaluateJavascriptCallback\nimport java.util.Locale\n\nclass OcContactsBridge(val webView: WebView) {\n\n    companion object {\n        const val NAME = \"ocContacts\"\n        private const val TAG = \"JS_$NAME\"\n    }\n\n    @JavascriptInterface\n    fun readContacts() {\n        Log.d(TAG, \"readContacts: \")\n        val format = String.format(Locale.ROOT, \"window.ocContactsReadContactsCallback(%s, %s)\", null, true)\n        evaluateJavascriptCallback(webView, format)\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/bridge/OcFido2Bridge.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.accountsettings.ui.bridge\n\nimport android.util.Log\nimport android.webkit.JavascriptInterface\nimport android.webkit.WebView\nimport org.microg.gms.accountsettings.ui.evaluateJavascriptCallback\nimport java.util.Locale\n\nclass OcFido2Bridge(val webView: WebView) {\n\n    companion object {\n        const val NAME = \"ocFido2\"\n        private const val TAG = \"JS_$NAME\"\n    }\n\n    @JavascriptInterface\n    fun startBuiltInAuthenticatorAssertionRequest(json: String?) {\n        Log.d(TAG, \"startBuiltInAuthenticatorAssertionRequest: json: $json\")\n        val format = String.format(Locale.ROOT, \"window.ocFido2BuiltInAuthenticatorAssertionResponse(%s)\", null)\n        evaluateJavascriptCallback(webView, format)\n    }\n\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/bridge/OcFidoU2fBridge.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.accountsettings.ui.bridge\n\nimport android.util.Log\nimport android.webkit.JavascriptInterface\nimport android.webkit.WebView\nimport org.microg.gms.accountsettings.ui.evaluateJavascriptCallback\nimport java.util.Locale\n\nclass OcFidoU2fBridge(val webView: WebView) {\n\n    companion object {\n        const val NAME = \"mm\"\n        private const val TAG = \"JS_$NAME\"\n    }\n\n    @JavascriptInterface\n    fun sendSkUiEvent(eventJsonStr: String?) {\n        Log.d(TAG, \"sendSkUiEvent: eventJsonStr: $eventJsonStr\")\n    }\n\n    @JavascriptInterface\n    fun startSecurityKeyAssertionRequest(requestJsonStr: String?) {\n        Log.d(TAG, \"startSecurityKeyAssertionRequest: requestJsonStr: $requestJsonStr\")\n        val format = String.format(Locale.ROOT, \"window.setSkResult(%s);\", null)\n        evaluateJavascriptCallback(webView, format)\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/bridge/OcFilePickerBridge.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.accountsettings.ui.bridge\n\nimport android.net.Uri\nimport android.util.Base64\nimport android.util.Log\nimport android.webkit.JavascriptInterface\nimport android.webkit.WebView\nimport org.microg.gms.accountsettings.ui.MainActivity\nimport org.microg.gms.accountsettings.ui.PicturePickerUtils\nimport org.microg.gms.accountsettings.ui.ResultStatus\nimport org.microg.gms.accountsettings.ui.evaluateJavascriptCallback\nimport org.microg.gms.accountsettings.ui.runOnMainLooper\nimport java.lang.RuntimeException\nimport java.util.concurrent.ExecutorService\n\nclass OcFilePickerBridge(val activity: MainActivity, val webView: WebView, val executor: ExecutorService) {\n\n    companion object {\n        const val NAME = \"ocFilePicker\"\n        private const val TAG = \"JS_$NAME\"\n    }\n\n    private var currentRequestId: Int = 0\n    private var pendingRequestId: Int? = null\n    private var lastResult: Triple<Int, String?, String?>? = null\n\n    private val pickerUtils = PicturePickerUtils(activity, ::handleResult, ::handleError)\n\n    @JavascriptInterface\n    fun pick(requestId: Int, mimeType: String?) {\n        Log.d(TAG, \"pick: requestId = $requestId, mimeType = $mimeType\")\n        currentRequestId = requestId\n        val type = mimeType ?: \"*/*\"\n\n        runOnMainLooper {\n            try {\n                pickerUtils.launchChooser(type)\n            } catch (e: Exception) {\n                Log.w(TAG, \"pick: launchChooser error\", e)\n                notifyJavascript(requestId, ResultStatus.FAILED.value, \"\", \"\")\n            }\n        }\n    }\n\n    @JavascriptInterface\n    fun resume(requestId: Int) {\n        Log.d(TAG, \"resume: requestId: $requestId lastResult:$lastResult\")\n        val lastResult = this.lastResult\n\n        runOnMainLooper {\n            if (lastResult != null) {\n                val (status, mimeType, data) = lastResult\n                notifyJavascript(requestId, status, mimeType ?: \"\", data ?: \"\")\n                this.lastResult = null\n            } else if (pendingRequestId != null) {\n                pendingRequestId = requestId\n            } else {\n                notifyJavascript(requestId, ResultStatus.NO_OP.value, \"\", \"\")\n            }\n        }\n    }\n\n    private fun handleResult(uri: Uri?) {\n        if (uri == null) {\n            notifyJavascript(currentRequestId, ResultStatus.USER_CANCEL.value, \"\", \"\")\n            return\n        }\n        pendingRequestId = currentRequestId\n        executor.submit {\n            try {\n                val contentResolver = activity.contentResolver\n                val mimeType = contentResolver.getType(uri) ?: \"image/jpeg\"\n                val inputStream = contentResolver.openInputStream(uri)\n\n                if (inputStream != null) {\n                    val bytes = inputStream.readBytes()\n                    val encodedData = Base64.encodeToString(bytes, Base64.NO_WRAP)\n                    inputStream.close()\n\n                    runOnMainLooper {\n                        val pendingId = pendingRequestId\n                        if (pendingId != null) {\n                            notifyJavascript(pendingId, ResultStatus.SUCCESS.value, mimeType, encodedData)\n                            pendingRequestId = null\n                        } else {\n                            lastResult = Triple(ResultStatus.SUCCESS.value, mimeType, encodedData)\n                        }\n                    }\n                } else {\n                    throw RuntimeException(\"Failed to open input stream\")\n                }\n            } catch (e: Exception) {\n                Log.w(TAG, \"handleResult: \", e)\n                runOnMainLooper {\n                    val pendingId = pendingRequestId\n                    if (pendingId != null) {\n                        notifyJavascript(pendingId, ResultStatus.FAILED.value, \"\", \"\")\n                        pendingRequestId = null\n                    }\n                }\n            }\n        }\n    }\n\n    private fun handleError(status: ResultStatus) {\n        notifyJavascript(currentRequestId, status.value, \"\", \"\")\n    }\n\n    private fun notifyJavascript(requestId: Int, status: Int, mimeType: String, data: String) {\n        Log.d(TAG, \"notifyJavascript: requestId: $requestId status: $status mimeType: $mimeType, data: $data\")\n        val escapedData = data.replace(\"\\\\\", \"\\\\\\\\\").replace(\"'\", \"\\\\'\")\n        val script = \"window.ocFilePickerCallback($requestId, $status, '$mimeType', '$escapedData')\"\n        evaluateJavascriptCallback(webView, script)\n    }\n\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/bridge/OcFolsomBridge.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.accountsettings.ui.bridge\n\nimport android.util.Log\nimport android.webkit.JavascriptInterface\n\nclass OcFolsomBridge() {\n\n    companion object {\n        const val NAME = \"ocFolsom\"\n        private const val TAG = \"JS_$NAME\"\n    }\n\n    @JavascriptInterface\n    fun addEncryptionRecoveryMethod(key: String?, jsonArray: String?, jsonObject: String?, eventId: Int?) {\n        Log.d(TAG, \"addEncryptionRecoveryMethod: key: $key, jsonArray: $jsonArray, jsonObject: $jsonObject, eventId: $eventId\")\n    }\n\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/bridge/OcPermissionsBridge.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.accountsettings.ui.bridge\n\nimport android.util.Log\nimport android.webkit.JavascriptInterface\nimport android.webkit.WebView\nimport org.microg.gms.accountsettings.ui.evaluateJavascriptCallback\nimport java.util.Locale\n\nclass OcPermissionsBridge(val webView: WebView) {\n\n    companion object {\n        const val NAME = \"ocPermissions\"\n        private const val TAG = \"JS_$NAME\"\n    }\n\n    @JavascriptInterface\n    fun checkPermissions(permissionBase64: String?): String? {\n        Log.d(TAG, \"checkPermissions: permissionBase64: $permissionBase64\")\n        return null\n    }\n\n    @JavascriptInterface\n    fun ensurePermissions(permissionBase64: String?) {\n        Log.d(TAG, \"ensurePermissions: permissionBase64: $permissionBase64\")\n        val format = String.format(Locale.ROOT, \"window.ocPermissionsEnsurePermissionsCallback(%s, %s)\", null, true)\n        evaluateJavascriptCallback(webView, format)\n    }\n\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/bridge/OcPlayProtectBridge.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.accountsettings.ui.bridge\n\nimport android.util.Log\nimport android.webkit.JavascriptInterface\nimport android.webkit.WebView\nimport org.microg.gms.accountsettings.ui.evaluateJavascriptCallback\nimport java.util.Locale\n\nclass OcPlayProtectBridge(val webView: WebView) {\n\n    companion object {\n        const val NAME = \"ocPlayProtect\"\n        private const val TAG = \"JS_$NAME\"\n    }\n\n    @JavascriptInterface\n    fun enablePlayProtect(protectId: Int?) {\n        Log.d(TAG, \"enablePlayProtect: protectId: $protectId\")\n        ocPlayProtectCallback(protectId)\n    }\n\n    @JavascriptInterface\n    fun getHarmfulAppsCount(protectId: Int?) {\n        Log.d(TAG, \"getHarmfulAppsCount: protectId: $protectId\")\n        ocPlayProtectCallback(protectId)\n    }\n\n    @JavascriptInterface\n    fun getLastScanTimeMs(protectId: Int?) {\n        Log.d(TAG, \"getLastScanTimeMs: protectId: $protectId\")\n        ocPlayProtectCallback(protectId)\n    }\n\n    @JavascriptInterface\n    fun isPlayProtectEnabled(protectId: Int?) {\n        Log.d(TAG, \"isPlayProtectEnabled: protectId: $protectId\")\n        ocPlayProtectCallback(protectId)\n    }\n\n    @JavascriptInterface\n    fun isPlayStoreVersionValid(protectId: Int?) {\n        Log.d(TAG, \"isPlayStoreVersionValid: protectId: $protectId\")\n        ocPlayProtectCallback(protectId, true)\n    }\n\n    @JavascriptInterface\n    fun startPlayProtectActivity(protectId: Int?) {\n        Log.d(TAG, \"startPlayProtectActivity: protectId: $protectId\")\n        ocPlayProtectCallbackV2(protectId)\n    }\n\n    private fun ocPlayProtectCallback(protectId: Int?, valid: Boolean) {\n        val format = String.format(Locale.ROOT, \"window.ocPlayProtectCallback(%s, %s)\", protectId, valid)\n        evaluateJavascriptCallback(webView, format)\n    }\n\n    private fun ocPlayProtectCallback(protectId: Int?) {\n        val format = String.format(Locale.ROOT, \"window.ocPlayProtectCallback(%s, %s, %s)\", protectId, null, true)\n        evaluateJavascriptCallback(webView, format)\n    }\n\n    private fun ocPlayProtectCallbackV2(protectId: Int?) {\n        val format = String.format(Locale.ROOT, \"window.ocPlayProtectCallback(%s)\", protectId)\n        evaluateJavascriptCallback(webView, format)\n    }\n\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/bridge/OcTelephonyBridge.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.accountsettings.ui.bridge\n\nimport android.util.Log\nimport android.webkit.JavascriptInterface\n\nclass OcTelephonyBridge() {\n\n    companion object {\n        const val NAME = \"ocTelephony\"\n        private const val TAG = \"JS_$NAME\"\n    }\n\n    @JavascriptInterface\n    fun getPhoneNumber(): String? {\n        Log.d(TAG, \"getPhoneNumber: \")\n        return null\n    }\n\n    @JavascriptInterface\n    fun getSimCountryIso(): String? {\n        Log.d(TAG, \"getSimCountryIso: \")\n        return null\n    }\n\n    @JavascriptInterface\n    fun getSimState(): Int {\n        Log.d(TAG, \"getSimState: \")\n        return 0\n    }\n\n    @JavascriptInterface\n    fun hasPhoneNumber(): Boolean {\n        Log.d(TAG, \"hasPhoneNumber: \")\n        return false\n    }\n\n    @JavascriptInterface\n    fun hasTelephony(): Boolean {\n        Log.d(TAG, \"hasTelephony: \")\n        return false\n    }\n\n    @JavascriptInterface\n    fun listenForSmsCodes() {\n        Log.d(TAG, \"listenForSmsCodes: \")\n    }\n\n    @JavascriptInterface\n    fun sendSms(type: Int, contentBase64: String) {\n        Log.d(TAG, \"sendSms: type: $type, contentBase64: $contentBase64\")\n    }\n\n    @JavascriptInterface\n    fun sendSmsSupportedByBridge(): Boolean {\n        Log.d(TAG, \"sendSmsSupportedByBridge: \")\n        return false\n    }\n\n    @JavascriptInterface\n    fun stopListeningForSmsCodes() {\n        Log.d(TAG, \"stopListeningForSmsCodes: \")\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/bridge/OcTrustAgentBridge.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.accountsettings.ui.bridge\n\nimport android.util.Log\nimport android.webkit.JavascriptInterface\nimport android.webkit.WebView\nimport org.microg.gms.accountsettings.ui.evaluateJavascriptCallback\nimport java.util.Locale\n\nclass OcTrustAgentBridge(val webView: WebView) {\n\n    companion object {\n        const val NAME = \"ocTrustAgent\"\n        private const val TAG = \"JS_$NAME\"\n    }\n\n    @JavascriptInterface\n    fun isScreenLockSet(agentId: Int?) {\n        Log.d(TAG, \"isScreenLockSet: agentId: $agentId\")\n        ocTrustAgentCallback(agentId, false)\n    }\n\n    @JavascriptInterface\n    fun isSmartLockSet(agentId: Int?) {\n        Log.d(TAG, \"isSmartLockSet: agentId: $agentId\")\n        ocTrustAgentCallback(agentId)\n    }\n\n    @JavascriptInterface\n    fun isSmartLockSupported(agentId: Int?) {\n        Log.d(TAG, \"isSmartLockSupported: agentId: $agentId\")\n        ocTrustAgentCallback(agentId, false)\n    }\n\n    @JavascriptInterface\n    fun isTrustletSet(config: String?, agentId: Int?) {\n        Log.d(TAG, \"isTrustletSet: agentId: $agentId\")\n        ocTrustAgentCallback(agentId)\n    }\n\n    @JavascriptInterface\n    fun isTrustletSupported(agentId: Int?) {\n        Log.d(TAG, \"isTrustletSupported: agentId: $agentId\")\n        ocTrustAgentCallback(agentId)\n    }\n\n    @JavascriptInterface\n    fun startScreenLockSmartLockFlow(agentId: Int?) {\n        Log.d(TAG, \"startScreenLockSmartLockFlow: agentId: $agentId\")\n        ocTrustAgentCallbackV2(agentId)\n    }\n\n    private fun ocTrustAgentCallback(agentId: Int?, valid: Boolean) {\n        val format = String.format(Locale.ROOT, \"window.ocTrustAgentCallback(%s, %s)\", agentId, valid)\n        evaluateJavascriptCallback(webView, format)\n    }\n\n    private fun ocTrustAgentCallback(agentId: Int?) {\n        val format = String.format(Locale.ROOT, \"window.ocTrustAgentCallback(%s, %s, %s)\", agentId, false, true)\n        evaluateJavascriptCallback(webView, format)\n    }\n\n    private fun ocTrustAgentCallbackV2(agentId: Int?) {\n        val format = String.format(Locale.ROOT, \"window.ocTrustAgentCallback(%s)\", agentId)\n        evaluateJavascriptCallback(webView, format)\n    }\n\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/bridge/OcUdcBridge.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.accountsettings.ui.bridge\n\nimport android.accounts.Account\nimport android.util.Log\nimport android.webkit.JavascriptInterface\nimport android.webkit.WebView\nimport org.microg.gms.accountsettings.ui.evaluateJavascriptCallback\nimport java.util.Locale\n\nclass OcUdcBridge(val webView: WebView) {\n\n    companion object {\n        const val NAME = \"ocUdc\"\n        private const val TAG = \"JS_$NAME\"\n    }\n\n    @JavascriptInterface\n    fun canGetUlrDeviceInformation(): Boolean {\n        Log.d(TAG, \"canGetUlrDeviceInformation: \")\n        return false\n    }\n\n    @JavascriptInterface\n    fun canOpenUlrSettingsUi(account: Account?): Boolean {\n        Log.d(TAG, \"canOpenUlrSettingsUi: account: ${account?.name}\")\n        return account != null\n    }\n\n    @JavascriptInterface\n    fun getDeviceSettingsStates(iArray: IntArray, eventId: Int?) {\n        Log.d(TAG, \"getDeviceSettingsStates: eventId: $eventId\")\n        ocUdcCallbackError(eventId)\n    }\n\n    @JavascriptInterface\n    fun getSupportedDeviceSettings(eventId: Int?) {\n        Log.d(TAG, \"getSupportedDeviceSettings: eventId: $eventId\")\n        ocUdcCallbackError(eventId)\n    }\n\n    @JavascriptInterface\n    fun getUlrDeviceInformation(eventId: Int?) {\n        Log.d(TAG, \"getUlrDeviceInformation: eventId: $eventId\")\n    }\n\n    @JavascriptInterface\n    fun openUlrSettingsUi(): Boolean {\n        Log.d(TAG, \"openUlrSettingsUi: \")\n        return false\n    }\n\n    @JavascriptInterface\n    fun setDeviceSetting(settingId: Int?, flag: Boolean?, eventId: Int?) {\n        Log.d(TAG, \"setDeviceSetting: settingId: $settingId, flag: $flag, eventId: $eventId\")\n        ocUdcCallbackError(eventId)\n    }\n\n    private fun ocUdcCallbackError(eventId: Int?) {\n        val format = String.format(Locale.ROOT, \"window.ocUdcCallback(%s, %s, %s)\", eventId, null, true)\n        evaluateJavascriptCallback(webView, format)\n    }\n\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/bridge/OcUiBridge.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.accountsettings.ui.bridge\n\nimport android.app.Activity.RESULT_OK\nimport android.content.Intent\nimport android.os.Bundle\nimport android.util.Log\nimport android.webkit.JavascriptInterface\nimport android.webkit.WebView\nimport org.json.JSONException\nimport org.json.JSONObject\nimport org.microg.gms.accountsettings.ui.EXTRA_ACCOUNT_NAME\nimport org.microg.gms.accountsettings.ui.EXTRA_SCREEN_ID\nimport org.microg.gms.accountsettings.ui.KEY_UPDATED_PHOTO_URL\nimport org.microg.gms.accountsettings.ui.MainActivity\nimport org.microg.gms.accountsettings.ui.finishActivity\nimport org.microg.gms.accountsettings.ui.runOnMainLooper\n\nclass OcUiBridge(val activity: MainActivity, val accountName:String?, val webView: WebView?) {\n\n    companion object{\n        const val NAME = \"ocUi\"\n        private const val TAG = \"JS_$NAME\"\n    }\n\n    private var resultBundle: Bundle? = null\n\n    @JavascriptInterface\n    fun close() {\n        Log.d(TAG, \"close: \")\n        val intent = Intent()\n        if (resultBundle != null) {\n            intent.putExtras(resultBundle!!)\n        }\n        accountName?.let { activity.updateVerifyNotification(it) }\n        activity.setResult(RESULT_OK, intent)\n        activity.finishActivity()\n    }\n\n    @JavascriptInterface\n    fun closeWithResult(resultJsonStr: String?) {\n        Log.d(TAG, \"closeWithResult: resultJsonStr -> $resultJsonStr\")\n        setResult(resultJsonStr)\n        close()\n    }\n\n    @JavascriptInterface\n    fun goBackOrClose() {\n        Log.d(TAG, \"goBackOrClose: \")\n        activity.onBackPressed()\n    }\n\n    @JavascriptInterface\n    fun hideKeyboard() {\n        Log.d(TAG, \"hideKeyboard: \")\n    }\n\n    @JavascriptInterface\n    fun isCloseWithResultSupported(): Boolean {\n        Log.d(TAG, \"isCloseWithResultSupported: \")\n        return true\n    }\n\n    @JavascriptInterface\n    fun isOpenHelpEnabled(): Boolean {\n        Log.d(TAG, \"isOpenHelpEnabled: \")\n        return true\n    }\n\n    @JavascriptInterface\n    fun isOpenScreenEnabled(): Boolean {\n        Log.d(TAG, \"isOpenScreenEnabled: \")\n        return true\n    }\n\n    @JavascriptInterface\n    fun isSetResultSupported(): Boolean {\n        Log.d(TAG, \"isSetResultSupported: \")\n        return true\n    }\n\n    @JavascriptInterface\n    fun open(str: String?) {\n        Log.d(TAG, \"open: str -> $str\")\n    }\n\n    @JavascriptInterface\n    fun openHelp(str: String?) {\n        Log.d(TAG, \"openHelp: str -> $str\")\n    }\n\n    @JavascriptInterface\n    fun openScreen(screenId: Int, str: String?) {\n        Log.d(TAG, \"openScreen: screenId -> $screenId str -> $str accountName -> $accountName\")\n        val intent = Intent(activity, MainActivity::class.java).apply {\n            putExtra(EXTRA_SCREEN_ID, screenId)\n            putExtra(EXTRA_ACCOUNT_NAME, accountName)\n        }\n        activity.startActivity(intent)\n    }\n\n    @JavascriptInterface\n    fun setBackStop() {\n        Log.d(TAG, \"setBackStop: \")\n        runOnMainLooper { webView?.clearHistory() }\n    }\n\n    @JavascriptInterface\n    fun setResult(resultJsonStr: String?) {\n        Log.d(TAG, \"setResult: resultJsonStr -> $resultJsonStr\")\n        val map = jsonToMap(resultJsonStr) ?: return\n        if (map.containsKey(KEY_UPDATED_PHOTO_URL)) {\n            activity.updateLocalAccountAvatar(map[KEY_UPDATED_PHOTO_URL], accountName)\n        }\n        resultBundle = Bundle().apply {\n            for ((key, value) in map) {\n                putString(\"result.$key\", value)\n            }\n        }\n    }\n\n    private fun jsonToMap(jsonStr: String?): Map<String, String>? {\n        val hashMap = HashMap<String, String>()\n        if (!jsonStr.isNullOrEmpty()) {\n            try {\n                val jSONObject = JSONObject(jsonStr)\n                val keys = jSONObject.keys()\n                while (keys.hasNext()) {\n                    val next = keys.next()\n                    val obj = jSONObject[next]\n                    hashMap[next] = obj as String\n                }\n            } catch (e: JSONException) {\n                Log.d(TAG, \"Unable to parse result JSON string\", e)\n                return null\n            }\n        }\n        return hashMap\n    }\n\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/extensions.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.accountsettings.ui\n\nimport android.app.Activity\nimport android.content.Context\nimport android.content.res.Configuration\nimport android.net.Uri\nimport android.os.Handler\nimport android.os.Looper\nimport android.webkit.WebView\nimport org.microg.gms.profile.Build.VERSION.SDK_INT\n\nconst val ACTION_BROWSE_SETTINGS = \"com.google.android.gms.accountsettings.action.BROWSE_SETTINGS\"\nconst val ACTION_MY_ACCOUNT = \"com.google.android.gms.accountsettings.MY_ACCOUNT\"\nconst val ACTION_ACCOUNT_PREFERENCES_SETTINGS = \"com.google.android.gms.accountsettings.ACCOUNT_PREFERENCES_SETTINGS\"\nconst val ACTION_PRIVACY_SETTINGS = \"com.google.android.gms.accountsettings.PRIVACY_SETTINGS\"\nconst val ACTION_SECURITY_SETTINGS = \"com.google.android.gms.accountsettings.SECURITY_SETTINGS\"\nconst val ACTION_LOCATION_SHARING = \"com.google.android.gms.location.settings.LOCATION_SHARING\"\n\nconst val EXTRA_CALLING_PACKAGE_NAME = \"extra.callingPackageName\"\nconst val EXTRA_IGNORE_ACCOUNT = \"extra.ignoreAccount\"\nconst val EXTRA_ACCOUNT_NAME = \"extra.accountName\"\nconst val EXTRA_SCREEN_ID = \"extra.screenId\"\nconst val EXTRA_SCREEN_OPTIONS_PREFIX = \"extra.screen.\"\nconst val EXTRA_FALLBACK_URL = \"extra.fallbackUrl\"\nconst val EXTRA_FALLBACK_AUTH = \"extra.fallbackAuth\"\nconst val EXTRA_THEME_CHOICE = \"extra.themeChoice\"\nconst val EXTRA_SCREEN_MY_ACTIVITY_PRODUCT = \"extra.screen.myactivityProduct\"\nconst val EXTRA_SCREEN_KID_ONBOARDING_PARAMS = \"extra.screen.kidOnboardingParams\"\nconst val EXTRA_SCREEN_FAMILY_APP_ID = \"extra.screen.family-app_id\"\nconst val EXTRA_URL = \"extra.url\"\n\nconst val QUERY_WC_ACTION = \"wv_action\"\nconst val QUERY_GNOTS_ACTION = \"gnotswvaction\"\nconst val ACTION_CLOSE = \"close\"\nconst val KEY_NOTIFICATION_ID = \"notificationId\"\n\nconst val KEY_UPDATED_PHOTO_URL = \"updatedPhotoUrl\"\n\nconst val OPTION_SCREEN_FLAVOR = \"screenFlavor\"\n\nenum class ResultStatus(val value: Int) {\n    USER_CANCEL(1), FAILED(2), SUCCESS(3), NO_OP(4)\n}\n\nfun evaluateJavascriptCallback(webView: WebView, script: String) {\n    runOnMainLooper {\n        webView.evaluateJavascript(script, null)\n    }\n}\n\nfun runOnMainLooper(method: () -> Unit) {\n    if (Looper.myLooper() == Looper.getMainLooper()) {\n        method()\n    } else {\n        Handler(Looper.getMainLooper()).post {\n            method()\n        }\n    }\n}\n\nfun isGoogleAvatarUrl(url: String?): Boolean {\n    if (url.isNullOrBlank()) return false\n    return try {\n        val uri = Uri.parse(url)\n        val isGoogleHost = uri.host == \"lh3.googleusercontent.com\"\n        val isAvatarPath = uri.path?.startsWith(\"/a/\") == true\n        val hasSizeParam = url.matches(Regex(\".*=s\\\\d+-c-no$\"))\n        isGoogleHost && isAvatarPath && hasSizeParam\n    } catch (e: Exception) {\n        false\n    }\n}\n\nfun Context.isNightMode(): Boolean {\n    val nightMode = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK\n    return nightMode == Configuration.UI_MODE_NIGHT_YES\n}\n\nfun Activity.finishActivity() {\n    if (SDK_INT >= 21) finishAndRemoveTask() else finish()\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/audit/AuditService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.audit\n\nimport android.util.Log\nimport com.google.android.gms.audit.LogAuditRecordsRequest\nimport com.google.android.gms.audit.internal.IAuditService\nimport com.google.android.gms.common.ConnectionResult\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.api.internal.IStatusCallback\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\n\nprivate const val TAG = \"AuditApiService\"\n\nclass AuditService : BaseService(TAG, GmsService.AUDIT) {\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        callback.onPostInitComplete(ConnectionResult.SUCCESS, AuditServiceImpl().asBinder(), null)\n    }\n\n}\n\nclass AuditServiceImpl : IAuditService.Stub() {\n\n    override fun logAuditRecords(request: LogAuditRecordsRequest?, callback: IStatusCallback) {\n        Log.d(TAG, \"method 'logAuditRecords' not fully implemented, only return Status.SUCCESS\")\n        when (request?.writeMode) {\n            1 -> {\n                callback.onResult(Status.SUCCESS)\n            }\n            2 -> {\n                callback.onResult(Status.SUCCESS_CACHE)\n            }\n            else -> {\n                callback.onResult(Status.SUCCESS)\n            }\n        }\n    }\n\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/auth/AskPackageOverrideActivity.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth\n\nimport android.accounts.Account\nimport android.accounts.AccountAuthenticatorResponse\nimport android.accounts.AccountManager\nimport android.content.DialogInterface\nimport android.content.DialogInterface.OnCancelListener\nimport android.content.DialogInterface.OnClickListener\nimport android.content.Intent\nimport android.os.Bundle\nimport android.text.Html\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.core.os.BundleCompat\nimport androidx.core.text.HtmlCompat\nimport com.google.android.gms.R\nimport com.google.android.gms.common.internal.CertData\nimport org.microg.gms.auth.loginservice.AccountAuthenticator\nimport org.microg.gms.ui.buildAlertDialog\nimport org.microg.gms.utils.digest\nimport org.microg.gms.utils.getApplicationLabel\nimport org.microg.gms.utils.getCertificates\nimport org.microg.gms.utils.toHexString\nimport java.security.cert.CertificateFactory\nimport java.security.cert.X509Certificate\n\nprivate const val TAG = \"AuthPackageOverride\"\n\nclass AskPackageOverrideActivity : AppCompatActivity(), OnCancelListener, OnClickListener {\n    private lateinit var requestingPackage: String\n    private lateinit var requestingPackageCertificate: CertData\n\n    private lateinit var accountName: String\n    private lateinit var accountType: String\n\n    private lateinit var overridePackage: String\n    private lateinit var overrideCertificate: CertData\n\n    private var response: AccountAuthenticatorResponse? = null\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        requestingPackage = intent.extras?.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME) ?: return finishResult(RESULT_CANCELED)\n        requestingPackageCertificate = packageManager.getCertificates(requestingPackage).firstOrNull() ?: return finishResult(RESULT_CANCELED)\n        accountName = intent.extras?.getString(AccountManager.KEY_ACCOUNT_NAME) ?: return finishResult(RESULT_CANCELED)\n        accountType = intent.extras?.getString(AccountManager.KEY_ACCOUNT_TYPE) ?: return finishResult(RESULT_CANCELED)\n        overridePackage = intent.extras?.getString(AccountAuthenticator.KEY_OVERRIDE_PACKAGE) ?: return finishResult(RESULT_CANCELED)\n        overrideCertificate =\n            intent.extras?.getByteArray(AccountAuthenticator.KEY_OVERRIDE_CERTIFICATE)?.let { CertData(it) } ?: return finishResult(RESULT_CANCELED)\n        response =\n            intent.extras?.let { BundleCompat.getParcelable(it, AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, AccountAuthenticatorResponse::class.java) }\n        showDialog()\n    }\n\n    private fun finishResult(resultCode: Int, resultData: Intent? = null) {\n        setResult(resultCode, resultData)\n        if (resultCode == RESULT_OK && resultData != null && resultData.extras != null) {\n            response?.onResult(resultData.extras)\n        } else if (resultCode == RESULT_CANCELED){\n            response?.onError(AccountManager.ERROR_CODE_CANCELED, \"Cancelled\")\n        }\n        finish()\n    }\n\n    fun showDialog() {\n        val overridePackageLabel = when {\n            overridePackage == \"com.android.vending\" -> \"Play Store\"\n            overridePackage == \"com.google.android.youtube\" -> \"YouTube\"\n            else -> runCatching { packageManager.getApplicationLabel(overridePackage) }.getOrNull() ?: overridePackage\n        }\n        val overridePackageVendor = runCatching {\n            val principal = (CertificateFactory.getInstance(\"X.509\")\n                .generateCertificate(overrideCertificate.bytes.inputStream()) as X509Certificate).subjectX500Principal.name\n            val sections = principal.split(\",\")\n            var proc = sections.indexOfFirst { it.startsWith(\"O=\") }\n            var organization = sections[proc].substring(2)\n            while (organization.last() == '\\\\') organization = organization.substring(0, organization.length - 1) + \",\" + sections[++proc]\n            while ((organization.count { it == '\"' } % 2) != 0) organization += \",\" + sections[++proc]\n            if (organization.startsWith('\"')) organization = organization.substring(1, organization.length - 1).replace(\"\\\"\\\"\", \"\\\"\")\n            organization.trim().trimEnd('.')\n        }.getOrNull() ?: return finishResult(RESULT_CANCELED)\n        val requestingPackageLabel = runCatching { packageManager.getApplicationLabel(requestingPackage) }.getOrNull() ?: requestingPackage\n        val alertDialog = buildAlertDialog()\n            .setOnCancelListener(this)\n            .setPositiveButton(R.string.allow, this)\n            .setNegativeButton(R.string.deny, this)\n            .setIcon(R.drawable.ic_manage_accounts)\n            .setTitle(HtmlCompat.fromHtml(getString(R.string.auth_package_override_request_title, Html.escapeHtml(requestingPackageLabel), Html.escapeHtml(accountName)), HtmlCompat.FROM_HTML_MODE_COMPACT))\n            .setMessage(HtmlCompat.fromHtml(getString(R.string.auth_package_override_request_message, Html.escapeHtml(requestingPackageLabel), Html.escapeHtml(overridePackageLabel), Html.escapeHtml(overridePackageVendor)), HtmlCompat.FROM_HTML_MODE_COMPACT))\n            .create()\n        alertDialog.setCanceledOnTouchOutside(false)\n        alertDialog.show()\n        response?.onRequestContinued()\n    }\n\n    override fun onCancel(dialog: DialogInterface?) {\n        finishResult(RESULT_CANCELED)\n    }\n\n    override fun onClick(dialog: DialogInterface?, which: Int) {\n        if (which == DialogInterface.BUTTON_POSITIVE) {\n            val requestingDigestString = requestingPackageCertificate.digest(\"SHA-256\").toHexString(\"\")\n            val overrideCertificateDigestString = overrideCertificate.digest(\"SHA-256\").toHexString(\"\")\n            val overrideUserDataKey = \"override.$requestingPackage:$requestingDigestString:$overridePackage:$overrideCertificateDigestString\"\n            AccountManager.get(this).setUserData(Account(accountName, accountType), overrideUserDataKey, \"1\")\n            finishResult(RESULT_OK, Intent().apply { putExtra(\"retry\", true) })\n        } else {\n            finishResult(RESULT_CANCELED)\n        }\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/auth/account/data/AccountDataService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth.account.data\n\nimport android.accounts.Account\nimport android.util.Log\nimport com.google.android.gms.auth.account.data.IAccountDataService\nimport com.google.android.gms.auth.account.data.IDeviceManagementInfoCallback\nimport com.google.android.gms.auth.firstparty.dataservice.DeviceManagementInfoResponse\nimport com.google.android.gms.common.ConnectionResult\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.api.internal.IStatusCallback\nimport com.google.android.gms.common.internal.ConnectionInfo\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\n\nprivate const val TAG = \"AccountDataService\"\n\nclass AccountDataService : BaseService(TAG, GmsService.AUTH_ACCOUNT_DATA) {\n\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        callback.onPostInitCompleteWithConnectionInfo(\n            ConnectionResult.SUCCESS,\n            AccountDataServiceImpl().asBinder(),\n            ConnectionInfo().apply { features = FEATURES }\n        )\n    }\n\n}\n\nclass AccountDataServiceImpl : IAccountDataService.Stub() {\n    override fun requestDeviceManagementInfo(callback: IDeviceManagementInfoCallback, account: Account?) {\n        Log.d(TAG, \"requestDeviceManagementInfo is called \")\n        callback.onResult(Status.SUCCESS, DeviceManagementInfoResponse(null, false))\n    }\n\n    override fun requestAccountInfo(callback: IStatusCallback, account: Account?, isPrimary: Boolean) {\n        Log.d(TAG, \"requestAccountInfo is called \")\n        callback.onResult(Status.SUCCESS)\n    }\n\n    override fun requestProfileInfo(callback: IStatusCallback, profile: String?) {\n        Log.d(TAG, \"requestProfileInfo is called \")\n        callback.onResult(Status.SUCCESS)\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/auth/account/data/GoogleAuthService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth.account.data\n\nimport android.accounts.Account\nimport android.os.Bundle\nimport android.os.Parcel\nimport android.util.Log\nimport com.google.android.gms.auth.*\nimport com.google.android.gms.auth.account.data.*\nimport com.google.android.gms.auth.firstparty.dataservice.ClearTokenRequest\nimport com.google.android.gms.common.Feature\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.api.internal.IStatusCallback\nimport com.google.android.gms.common.internal.ConnectionInfo\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.utils.warnOnTransactionIssues\n\nprivate const val TAG = \"GoogleAuthService\"\n\nval FEATURES = arrayOf(\n    Feature(\"auth_suw\", 224516000),\n    Feature(\"account_capability_api\", 1),\n    Feature(\"account_data_service\", 6),\n    Feature(\"account_data_service_legacy\", 1),\n    Feature(\"account_data_service_token\", 8),\n    Feature(\"account_data_service_visibility\", 1),\n    Feature(\"config_sync\", 1),\n    Feature(\"device_account_api\", 1),\n    Feature(\"device_account_jwt_creation\", 1),\n    Feature(\"gaiaid_primary_email_api\", 1),\n    Feature(\"google_auth_service_accounts\", 2),\n    Feature(\"google_auth_service_token\", 3),\n    Feature(\"hub_mode_api\", 1),\n    Feature(\"user_service_account_management\", 1),\n    Feature(\"work_account_client_is_whitelisted\", 1),\n)\n\nclass GoogleAuthService : BaseService(TAG, GmsService.GOOGLE_AUTH){\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        val binder = GoogleAuthServiceImpl().asBinder()\n        callback.onPostInitCompleteWithConnectionInfo(CommonStatusCodes.SUCCESS, binder, ConnectionInfo().apply { features = FEATURES })\n    }\n}\n\nclass GoogleAuthServiceImpl : IGoogleAuthService.Stub() {\n    override fun getTokenWithDetails(callback: IGetTokenWithDetailsCallback?, account: Account?, service: String?, extras: Bundle?) {\n        Log.d(TAG, \"Not yet implemented: getTokenWithDetails($account, $service, $extras)\")\n        callback?.onTokenResults(Status.INTERNAL_ERROR, Bundle.EMPTY)\n    }\n\n    override fun clearToken(callback: IStatusCallback?, request: ClearTokenRequest?) {\n        Log.d(TAG, \"Not yet implemented: clearToken($request)\")\n        callback?.onResult(Status.INTERNAL_ERROR)\n    }\n\n    override fun requestAccountsAccess(callback: IBundleCallback?, str: String?) {\n        Log.d(TAG, \"Not yet implemented: requestAccountsAccess($str)\")\n        callback?.onBundle(Status.INTERNAL_ERROR, Bundle.EMPTY)\n    }\n\n    override fun getAccountChangeEvents(callback: IGetAccountChangeEventsCallback?, request: AccountChangeEventsRequest?) {\n        Log.d(TAG, \"Not yet implemented: getAccountChangeEvents($request)\")\n        callback?.onAccountChangeEventsResponse(Status.INTERNAL_ERROR, AccountChangeEventsResponse())\n    }\n\n    override fun getAccounts(callback: IGetAccountsCallback?, request: GetAccountsRequest?) {\n        Log.d(TAG, \"Not yet implemented: getAccounts($request)\")\n        callback?.onBundle(Status.INTERNAL_ERROR, emptyList())\n    }\n\n    override fun removeAccount(callback: IBundleCallback?, account: Account?) {\n        Log.d(TAG, \"Not yet implemented: removeAccount($account)\")\n        callback?.onBundle(Status.INTERNAL_ERROR, Bundle.EMPTY)\n    }\n\n    override fun hasCapabilities(callback: IHasCapabilitiesCallback?, request: HasCapabilitiesRequest?) {\n        Log.d(TAG, \"Not yet implemented: hasCapabilities($request)\")\n        callback?.onHasCapabilities(Status.INTERNAL_ERROR, 1)\n    }\n\n    override fun getHubToken(callback: IGetHubTokenCallback?, request: GetHubTokenRequest?) {\n        Log.d(TAG, \"Not yet implemented: getHubToken($request)\")\n        callback?.onGetHubTokenResponse(Status.INTERNAL_ERROR, GetHubTokenInternalResponse())\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = warnOnTransactionIssues(code, reply, flags, TAG) {\n        super.onTransact(code, data, reply, flags)\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/auth/appcert/AppCertManager.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth.appcert\n\nimport android.content.Context\nimport android.database.Cursor\nimport android.util.Base64\nimport android.util.Log\nimport com.android.volley.NetworkResponse\nimport com.android.volley.Request\nimport com.android.volley.Response\nimport com.android.volley.VolleyError\nimport com.android.volley.toolbox.Volley\nimport com.google.android.gms.BuildConfig\nimport com.google.android.gms.droidguard.DroidGuardClient\nimport com.google.android.gms.tasks.await\nimport kotlinx.coroutines.CompletableDeferred\nimport kotlinx.coroutines.sync.Mutex\nimport kotlinx.coroutines.sync.withLock\nimport okio.ByteString.Companion.of\nimport org.microg.gms.checkin.LastCheckinInfo\nimport org.microg.gms.common.Constants\nimport org.microg.gms.gcm.GcmConstants\nimport org.microg.gms.gcm.GcmDatabase\nimport org.microg.gms.gcm.RegisterRequest\nimport org.microg.gms.gcm.completeRegisterRequest\nimport org.microg.gms.profile.Build\nimport org.microg.gms.profile.ProfileManager\nimport org.microg.gms.settings.SettingsContract.CheckIn\nimport org.microg.gms.settings.SettingsContract.getSettings\nimport org.microg.gms.utils.digest\nimport org.microg.gms.utils.getCertificates\nimport org.microg.gms.utils.singleInstanceOf\nimport org.microg.gms.utils.toBase64\nimport javax.crypto.Mac\nimport javax.crypto.spec.SecretKeySpec\nimport kotlin.random.Random\n\nclass AppCertManager(private val context: Context) {\n    private val queue = singleInstanceOf { Volley.newRequestQueue(context.applicationContext) }\n\n    private fun readDeviceKey() {\n        try {\n            if (context.getFileStreamPath(\"device_key\").exists()) {\n                deviceKey = context.openFileInput(\"device_key\").use { DeviceKey.ADAPTER.decode(it) }\n                deviceKeyCacheTime = context.getFileStreamPath(\"device_key\").lastModified()\n            } else {\n                deviceKeyCacheTime = -1\n            }\n        } catch (e: Exception) {\n            deviceKeyCacheTime = -1\n        }\n    }\n\n    suspend fun fetchDeviceKey(): Boolean {\n        ProfileManager.ensureInitialized(context)\n        if (deviceKeyCacheTime == 0L) readDeviceKey()\n        deviceKeyLock.withLock {\n            try {\n                val currentTime = System.currentTimeMillis()\n                if (deviceKeyCacheTime > 0 && currentTime - deviceKeyCacheTime < DEVICE_KEY_TIMEOUT) {\n                    return deviceKey != null\n                }\n                Log.w(TAG, \"DeviceKeys for app certifications are experimental\")\n                deviceKeyCacheTime = currentTime\n                val lastCheckinInfo = LastCheckinInfo.read(context)\n                val androidId = lastCheckinInfo.androidId\n                val sessionId = Random.nextLong()\n                val data = hashMapOf(\n                        \"dg_androidId\" to androidId.toString(16),\n                        \"dg_session\" to sessionId.toString(16),\n                        \"dg_gmsCoreVersion\" to BuildConfig.VERSION_CODE.toString(),\n                        \"dg_sdkVersion\" to Build.VERSION.SDK_INT.toString()\n                )\n                val droidGuardResult = try {\n                    DroidGuardClient.getResults(context, \"devicekey\", data).await()\n                } catch (e: Exception) {\n                    null\n                }\n                val token = completeRegisterRequest(context, GcmDatabase(context), RegisterRequest().build(context)\n                        .checkin(lastCheckinInfo)\n                        .app(\"com.google.android.gms\", Constants.GMS_PACKAGE_SIGNATURE_SHA1, BuildConfig.VERSION_CODE)\n                        .sender(REGISTER_SENDER)\n                        .extraParam(\"subscription\", REGISTER_SUBSCRIPTION)\n                        .extraParam(\"X-subscription\", REGISTER_SUBSCRIPTION)\n                        .extraParam(\"subtype\", REGISTER_SUBTYPE)\n                        .extraParam(\"X-subtype\", REGISTER_SUBTYPE)\n                        .extraParam(\"scope\", REGISTER_SCOPE))\n                        .getString(GcmConstants.EXTRA_REGISTRATION_ID)\n                val request = DeviceKeyRequest(\n                        droidGuardResult = droidGuardResult,\n                        androidId = lastCheckinInfo.androidId,\n                        sessionId = sessionId,\n                        versionInfo = DeviceKeyRequest.VersionInfo(Build.VERSION.SDK_INT, BuildConfig.VERSION_CODE),\n                        token = token\n                )\n                Log.d(TAG, \"Request: ${request.toString().chunked(128).joinToString(\"\\n\")}\")\n                val deferredResponse = CompletableDeferred<ByteArray?>()\n                queue.add(object : Request<ByteArray?>(Method.POST, \"https://android.googleapis.com/auth/devicekey\", null) {\n                    override fun getBody(): ByteArray = request.encode()\n\n                    override fun getBodyContentType(): String = \"application/octet-stream\"\n\n                    override fun parseNetworkResponse(response: NetworkResponse): Response<ByteArray?> {\n                        return if (response.statusCode == 200) {\n                            Response.success(response.data, null)\n                        } else {\n                            Response.success(null, null)\n                        }\n                    }\n\n                    override fun deliverError(error: VolleyError) {\n                        if (error.networkResponse != null) {\n                            Log.d(TAG, \"Error: ${Base64.encodeToString(error.networkResponse.data, 2)}\")\n                        } else {\n                            Log.d(TAG, \"Error: ${error.message}\")\n                        }\n                        deviceKeyCacheTime = 0\n                        deferredResponse.complete(null)\n                    }\n\n                    override fun deliverResponse(response: ByteArray?) {\n                        deferredResponse.complete(response)\n                    }\n\n                    override fun getHeaders(): Map<String, String> {\n                        return mapOf(\n                                \"User-Agent\" to \"GoogleAuth/1.4 (${Build.DEVICE} ${Build.ID}); gzip\",\n                                \"content-type\" to \"application/octet-stream\",\n                                \"app\" to \"com.google.android.gms\",\n                                \"device\" to androidId.toString(16)\n                        )\n                    }\n                })\n                val deviceKeyBytes = deferredResponse.await() ?: return false\n                context.openFileOutput(\"device_key\", Context.MODE_PRIVATE).use {\n                    it.write(deviceKeyBytes)\n                }\n                context.getFileStreamPath(\"device_key\").setLastModified(currentTime)\n                deviceKey = DeviceKey.ADAPTER.decode(deviceKeyBytes)\n                return true\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n                return false\n            }\n        }\n    }\n\n    suspend fun getSpatulaHeader(packageName: String): String? {\n        val deviceKey = deviceKey ?: if (fetchDeviceKey()) deviceKey else null\n        val packageCertificateHash = context.packageManager.getCertificates(packageName).firstOrNull()?.digest(\"SHA1\")?.toBase64(Base64.NO_WRAP)\n        val proto = if (deviceKey != null) {\n            val macSecret = deviceKey.macSecret?.toByteArray()\n            if (macSecret == null) {\n                Log.w(TAG, \"Invalid device key: $deviceKey\")\n                return null\n            }\n            val mac = Mac.getInstance(\"HMACSHA256\")\n            mac.init(SecretKeySpec(macSecret, \"HMACSHA256\"))\n            val hmac = mac.doFinal(\"$packageName$packageCertificateHash\".toByteArray())\n            SpatulaHeaderProto(\n                    packageInfo = SpatulaHeaderProto.PackageInfo(packageName, packageCertificateHash),\n                    hmac = of(*hmac),\n                    deviceId = deviceKey.deviceId,\n                    keyId = deviceKey.keyId,\n                    keyCert = deviceKey.keyCert ?: of()\n            )\n        } else {\n            Log.d(TAG, \"Using fallback spatula header based on Android ID\")\n            val androidId = getSettings(context, CheckIn.getContentUri(context), arrayOf(CheckIn.ANDROID_ID)) { cursor: Cursor -> cursor.getLong(0) }\n            SpatulaHeaderProto(\n                    packageInfo = SpatulaHeaderProto.PackageInfo(packageName, packageCertificateHash),\n                    deviceId = androidId\n            )\n            return null // TODO\n        }\n        Log.d(TAG, \"Spatula Header: $proto\")\n        return Base64.encodeToString(proto.encode(), Base64.NO_WRAP)\n    }\n\n    companion object {\n        private const val TAG = \"AppCertManager\"\n        private const val DEVICE_KEY_TIMEOUT = 60 * 60 * 1000L\n        private const val REGISTER_SENDER = \"745476177629\"\n        private const val REGISTER_SUBTYPE = \"745476177629\"\n        private const val REGISTER_SUBSCRIPTION = \"745476177629\"\n        private const val REGISTER_SCOPE = \"DeviceKeyRequest\"\n        private val deviceKeyLock = Mutex()\n        private var deviceKey: DeviceKey? = null\n        private var deviceKeyCacheTime = 0L\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/auth/appcert/AppCertService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth.appcert\n\nimport android.app.Service\nimport android.content.Context\nimport android.content.Intent\nimport android.os.IBinder\nimport android.os.Parcel\nimport android.util.Log\nimport com.google.android.gms.auth.appcert.IAppCertService\nimport kotlinx.coroutines.runBlocking\nimport org.microg.gms.common.GooglePackagePermission\nimport org.microg.gms.common.PackageUtils\nimport org.microg.gms.utils.warnOnTransactionIssues\n\nprivate const val TAG = \"AppCertService\"\n\nclass AppCertService : Service() {\n    override fun onBind(intent: Intent): IBinder {\n        Log.d(TAG, \"onBind: $intent\")\n        return AppCertServiceImpl(this).asBinder()\n    }\n}\n\nclass AppCertServiceImpl(private val context: Context) : IAppCertService.Stub() {\n    private val manager = AppCertManager(context)\n\n    override fun fetchDeviceKey(): Boolean {\n        PackageUtils.assertGooglePackagePermission(context, GooglePackagePermission.APP_CERT)\n        return runBlocking { manager.fetchDeviceKey() }\n    }\n\n    override fun getSpatulaHeader(packageName: String): String? {\n        PackageUtils.assertGooglePackagePermission(context, GooglePackagePermission.APP_CERT)\n        return runBlocking { manager.getSpatulaHeader(packageName) }\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/auth/consent/ConsentSignInActivity.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth.consent\n\nimport android.annotation.SuppressLint\nimport android.app.Activity\nimport android.content.res.Configuration\nimport android.graphics.Bitmap\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.Bundle\nimport android.os.Message\nimport android.os.Messenger\nimport android.util.Log\nimport android.view.View\nimport android.view.WindowManager\nimport android.webkit.CookieManager\nimport android.webkit.JavascriptInterface\nimport android.webkit.WebView\nimport android.webkit.WebViewClient\nimport android.widget.ProgressBar\nimport androidx.core.os.bundleOf\nimport com.google.android.gms.R\nimport org.microg.gms.profile.Build.generateWebViewUserAgentString\nimport org.microg.gms.profile.ProfileManager\n\nprivate const val TAG = \"ConsentSignInActivity\"\nconst val CONSENT_KEY_COOKIE = \"cookie-\"\nconst val CONSENT_URL = \"consentUrl\"\nconst val CONSENT_MESSENGER = \"messenger\"\nconst val CONSENT_RESULT = \"consent_result\"\n\nclass ConsentSignInActivity : Activity() {\n\n    private var webView: WebView? = null\n    private var progressBar: ProgressBar? = null\n    private var sendSuccessResult = false\n\n    private val consentUrl: String?\n        get() = runCatching {\n            intent?.getStringExtra(CONSENT_URL)\n        }.getOrNull()\n\n    private val messenger: Messenger?\n        get() = runCatching {\n            intent?.getParcelableExtra<Messenger>(CONSENT_MESSENGER)\n        }.getOrNull()\n\n    @SuppressLint(\"SetJavaScriptEnabled\")\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        setContentView(R.layout.activity_consent_sign_in)\n        ProfileManager.ensureInitialized(this)\n        progressBar = findViewById(R.id.progressBar)\n        webView = findViewById<WebView>(R.id.consent_sign)\n\n        if (consentUrl == null || messenger == null) {\n            finish()\n            return\n        }\n        initLayout()\n        initWebView()\n        initCookieManager()\n    }\n\n    private fun initLayout() {\n        val layoutParams = window.attributes as WindowManager.LayoutParams\n        layoutParams.width = (resources.displayMetrics.widthPixels * 0.8).toInt()\n        layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT\n        window.attributes = layoutParams\n    }\n\n    private fun initWebView() {\n        webView?.settings?.apply {\n            userAgentString = generateWebViewUserAgentString(userAgentString)\n            javaScriptEnabled = true\n            setSupportMultipleWindows(false)\n            saveFormData = false\n            allowFileAccess = false\n            databaseEnabled = false\n            setNeedInitialFocus(false)\n            useWideViewPort = false\n            setSupportZoom(false)\n            javaScriptCanOpenWindowsAutomatically = false\n        }\n        webView?.addJavascriptInterface(OAuthConsentInterface(), \"OAuthConsent\")\n        webView?.webViewClient = object : WebViewClient() {\n            override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) {\n                super.onPageStarted(view, url, favicon)\n                progressBar?.visibility = View.VISIBLE\n            }\n\n            override fun onPageFinished(view: WebView, url: String) {\n                super.onPageFinished(view, url)\n                progressBar?.visibility = View.GONE\n            }\n        }\n    }\n\n    private fun initCookieManager() {\n        val cookieManager = CookieManager.getInstance()\n        if (SDK_INT >= 21) {\n            cookieManager.removeAllCookies { _ ->\n                setCookiesAndLoadUrl(consentUrl!!, cookieManager)\n            }\n        } else {\n            cookieManager.removeAllCookie()\n            setCookiesAndLoadUrl(consentUrl!!, cookieManager)\n        }\n    }\n\n    private fun setCookiesAndLoadUrl(consentUrl: String, cookieManager: CookieManager) {\n        val extras = intent.extras\n        if (extras != null && extras.size() > 0) {\n            for (i in 0 until extras.size()) {\n                val cookie = extras.getString(CONSENT_KEY_COOKIE + i)\n                if (cookie != null) {\n                    cookieManager.setCookie(consentUrl, cookie)\n                }\n            }\n            webView?.loadUrl(consentUrl)\n        } else {\n            finish()\n        }\n    }\n\n    private fun sendReplay(result: String?) {\n        try {\n            Log.d(TAG, \"sendReplay result -> $result\")\n            val obtain = Message.obtain()\n            obtain.data = bundleOf(Pair(CONSENT_RESULT, result))\n            messenger?.send(obtain)\n            sendSuccessResult = true\n        } catch (e: Exception) {\n            Log.w(TAG, \"sendReplay Exception -> \", e)\n        }\n    }\n\n    override fun onDestroy() {\n        Log.d(TAG, \"ConsentSignInActivity onDestroy \")\n        super.onDestroy()\n        if (!sendSuccessResult) {\n            sendReplay(null)\n        }\n    }\n\n    private inner class OAuthConsentInterface {\n        @JavascriptInterface\n        fun cancel() {\n            Log.d(TAG, \"consent cancel: sendReplay \")\n            finish()\n        }\n\n        @get:JavascriptInterface\n        val moduleVersion: Unit\n            get() {\n                Log.d(TAG, \"getModuleVersion: \")\n            }\n\n        @JavascriptInterface\n        fun setConsentResult(result: String) {\n            Log.d(TAG, \"consent success: sendReplay  -> $result\")\n            if (\"CAA\" != result) {\n                sendReplay(result)\n            }\n            finish()\n        }\n\n        @JavascriptInterface\n        fun showView() {\n            Log.d(TAG, \"consent showView: \")\n        }\n    }\n\n    override fun onStop() {\n        super.onStop()\n        if (SDK_INT >= 21) {\n            CookieManager.getInstance().removeAllCookies(null)\n        } else {\n            CookieManager.getInstance().removeAllCookie()\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/auth/credentials/CredentialPickerActivity.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth.credentials\n\nimport android.app.Activity\nimport android.os.Bundle\nimport android.os.Parcel\nimport android.os.Parcelable\nimport android.util.Log\nimport com.google.android.gms.auth.api.credentials.CredentialRequest\nimport com.google.android.gms.auth.api.credentials.HintRequest\n\nfun <T> Parcelable.Creator<T>.createFromBytes(bytes: ByteArray): T {\n    val parcel = Parcel.obtain()\n    parcel.unmarshall(bytes, 0, bytes.size)\n    parcel.setDataPosition(0)\n    try {\n        return createFromParcel(parcel)\n    } finally {\n        parcel.recycle()\n    }\n}\n\nclass CredentialPickerActivity : Activity() {\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        val extras = intent.extras ?: Bundle()\n        val callingPackage = callingActivity?.packageName?.takeIf { extras.getString(\"claimedCallingPackage\", it) == it }\n        val logSessionId = extras.getString(\"logSessionId\")\n        val credentialRequest = extras.getByteArray(\"credentialRequest\")?.let { CredentialRequest.CREATOR.createFromBytes(it) }\n        val hintRequest = extras.getByteArray(\"com.google.android.gms.credentials.HintRequest\")?.let { HintRequest.CREATOR.createFromBytes(it) }\n        Log.d(\"GmsCredentialPicker\", \"Not implemented. callingPackage=$callingPackage, logSessionId=$logSessionId, credentialsRequest=$credentialRequest, hintRequest=$hintRequest\")\n        finish()\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/auth/credentials/CredentialsService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth.credentials\n\nimport android.os.Parcel\nimport android.util.Log\nimport com.google.android.gms.auth.api.credentials.CredentialRequest\nimport com.google.android.gms.auth.api.credentials.internal.*\nimport com.google.android.gms.common.Feature\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.internal.ConnectionInfo\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.common.PackageUtils\nimport org.microg.gms.utils.warnOnTransactionIssues\n\nprivate const val TAG = \"CredentialService\"\n\nval FEATURES = arrayOf(\n    Feature(\"auth_api_credentials_begin_sign_in\", 9),\n    Feature(\"auth_api_credentials_sign_out\", 2),\n    Feature(\"auth_api_credentials_authorize\", 1),\n    Feature(\"auth_api_credentials_revoke_access\", 1),\n    Feature(\"auth_api_credentials_save_password\", 4),\n    Feature(\"auth_api_credentials_get_sign_in_intent\", 6),\n    Feature(\"auth_api_credentials_save_account_linking_token\", 3),\n    Feature(\"auth_api_credentials_get_phone_number_hint_intent\", 3),\n    Feature(\"auth_api_credentials_verify_with_google\", 1)\n)\n\nclass CredentialsService : BaseService(TAG, GmsService.AUTH_CREDENTIALS) {\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        val packageName = PackageUtils.getAndCheckCallingPackage(this, request.packageName)\n            ?: throw IllegalArgumentException(\"Missing package name\")\n        val binder = CredentialsServiceImpl(packageName).asBinder()\n        callback.onPostInitCompleteWithConnectionInfo(CommonStatusCodes.SUCCESS, binder, ConnectionInfo().apply { features = FEATURES })\n    }\n}\n\nclass CredentialsServiceImpl(private val packageName: String) : ICredentialsService.Stub() {\n    override fun request(callbacks: ICredentialsCallbacks, request: CredentialRequest) {\n        Log.d(TAG, \"request($request)\")\n        callbacks.onStatus(Status.CANCELED)\n    }\n\n    override fun save(callbacks: ICredentialsCallbacks, request: SaveRequest) {\n        Log.d(TAG, \"save($request)\")\n        callbacks.onStatus(Status.CANCELED)\n    }\n\n    override fun delete(callbacks: ICredentialsCallbacks, request: DeleteRequest) {\n        Log.d(TAG, \"delete($request)\")\n        callbacks.onStatus(Status.CANCELED)\n    }\n\n    override fun disableAutoSignIn(callbacks: ICredentialsCallbacks) {\n        Log.d(TAG, \"disableAutoSignIn()\")\n        callbacks.onStatus(Status.SUCCESS)\n    }\n\n    override fun generatePassword(callbacks: ICredentialsCallbacks, request: GeneratePasswordRequest) {\n        Log.d(TAG, \"generatePassword($request)\")\n        callbacks.onStatus(Status.SUCCESS)\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =\n        warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/auth/credentials/identity/AuthorizationService.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth.credentials.identity\n\nimport android.accounts.AccountManager\nimport android.app.PendingIntent\nimport android.app.PendingIntent.FLAG_IMMUTABLE\nimport android.app.PendingIntent.FLAG_UPDATE_CURRENT\nimport android.content.Context\nimport android.content.Intent\nimport android.util.Log\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.LifecycleOwner\nimport androidx.lifecycle.lifecycleScope\nimport com.google.android.gms.auth.api.identity.AuthorizationRequest\nimport com.google.android.gms.auth.api.identity.AuthorizationResult\nimport com.google.android.gms.auth.api.identity.ClearTokenRequest\nimport com.google.android.gms.auth.api.identity.RevokeAccessRequest\nimport com.google.android.gms.auth.api.identity.VerifyWithGoogleRequest\nimport com.google.android.gms.auth.api.identity.VerifyWithGoogleResult\nimport com.google.android.gms.auth.api.identity.internal.IAuthorizationCallback\nimport com.google.android.gms.auth.api.identity.internal.IAuthorizationService\nimport com.google.android.gms.auth.api.identity.internal.IVerifyWithGoogleCallback\nimport com.google.android.gms.auth.api.signin.GoogleSignInOptions\nimport com.google.android.gms.auth.api.signin.internal.SignInConfiguration\nimport com.google.android.gms.common.ConnectionResult\nimport com.google.android.gms.common.api.Scope\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.api.internal.IStatusCallback\nimport com.google.android.gms.common.internal.ConnectionInfo\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\nimport org.microg.gms.BaseService\nimport org.microg.gms.auth.AuthConstants\nimport org.microg.gms.auth.credentials.FEATURES\nimport org.microg.gms.auth.signin.AuthSignInActivity\nimport org.microg.gms.auth.signin.SignInConfigurationService\nimport org.microg.gms.auth.signin.getOAuthManager\nimport org.microg.gms.auth.signin.getServerAuthTokenManager\nimport org.microg.gms.auth.signin.performSignIn\nimport org.microg.gms.auth.signin.scopeUris\nimport org.microg.gms.common.AccountUtils\nimport org.microg.gms.common.Constants\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.common.PackageUtils\nimport java.util.concurrent.atomic.AtomicInteger\n\nprivate const val TAG = \"AuthorizationService\"\n\nclass AuthorizationService : BaseService(TAG, GmsService.AUTH_API_IDENTITY_AUTHORIZATION) {\n\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        Log.d(TAG, \"handleServiceRequest start \")\n        val packageName = PackageUtils.getAndCheckCallingPackage(this, request.packageName)\n                ?: throw IllegalArgumentException(\"Missing package name\")\n        val connectionInfo = ConnectionInfo()\n        connectionInfo.features = FEATURES\n        callback.onPostInitCompleteWithConnectionInfo(\n            ConnectionResult.SUCCESS, AuthorizationServiceImpl(this, packageName, this.lifecycle).asBinder(), connectionInfo\n        )\n    }\n}\n\nclass AuthorizationServiceImpl(val context: Context, val packageName: String, override val lifecycle: Lifecycle) : IAuthorizationService.Stub(), LifecycleOwner {\n\n    companion object{\n        private val nextRequestCode = AtomicInteger(0)\n    }\n\n    override fun authorize(callback: IAuthorizationCallback?, request: AuthorizationRequest?) {\n        Log.d(TAG, \"Method: authorize called, packageName:$packageName request:$request\")\n        lifecycleScope.launchWhenStarted {\n            val requestAccount = request?.account\n            val account = requestAccount ?: AccountUtils.get(context).getSelectedAccount(packageName)\n            val googleSignInOptions = GoogleSignInOptions.Builder().apply {\n                request?.requestedScopes?.forEach { requestScopes(it) }\n                if (request?.idTokenRequested == true && request.serverClientId != null) {\n                    if (account?.name != requestAccount?.name) {\n                        requestEmail().requestProfile()\n                    }\n                    requestIdToken(request.serverClientId)\n                }\n                if (request?.serverAuthCodeRequested == true && request.serverClientId != null) requestServerAuthCode(request.serverClientId, request.forceCodeForRefreshToken)\n            }.build()\n            Log.d(TAG, \"authorize: account: ${account?.name}\")\n            val result = if (account != null) {\n                val (accessToken, signInAccount) = performSignIn(context, packageName, googleSignInOptions, account, false)\n                if (requestAccount != null) {\n                    AccountUtils.get(context).saveSelectedAccount(packageName, requestAccount)\n                }\n                AuthorizationResult(\n                    signInAccount?.serverAuthCode,\n                    accessToken,\n                    signInAccount?.idToken,\n                    signInAccount?.grantedScopes?.toList().orEmpty().map { it.scopeUri },\n                    signInAccount,\n                    null\n                )\n            } else {\n                val options = GoogleSignInOptions.Builder(googleSignInOptions).apply {\n                    val defaultAccount = SignInConfigurationService.getDefaultAccount(context, packageName)\n                    defaultAccount?.name?.let { setAccountName(it) }\n                }.build()\n                val intent = Intent(context, AuthSignInActivity::class.java).apply {\n                    `package` = Constants.GMS_PACKAGE_NAME\n                    putExtra(\"config\", SignInConfiguration(packageName, options))\n                }\n                AuthorizationResult(\n                    null,\n                    null,\n                    null,\n                    request?.requestedScopes.orEmpty().map { it.scopeUri },\n                    null,\n                    PendingIntent.getActivity(context, nextRequestCode.incrementAndGet(), intent, FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE)\n                )\n            }\n            runCatching {\n                callback?.onAuthorized(Status.SUCCESS, result.also { Log.d(TAG, \"authorize: result:$it\") })\n            }\n        }\n    }\n\n    override fun verifyWithGoogle(callback: IVerifyWithGoogleCallback?, request: VerifyWithGoogleRequest?) {\n        Log.d(TAG, \"unimplemented Method: verifyWithGoogle: request:$request\")\n        lifecycleScope.launchWhenStarted {\n            val account = AccountUtils.get(context).getSelectedAccount(packageName) ?: SignInConfigurationService.getDefaultAccount(context, packageName)\n            if (account == null) {\n                Log.d(TAG, \"Method: authorize called, but account is null\")\n                callback?.onVerifed(Status.CANCELED, null)\n                return@launchWhenStarted\n            }\n            if (request?.offlineAccess == true && request.serverClientId != null) {\n                val googleSignInOptions = GoogleSignInOptions.Builder().apply {\n                    request.requestedScopes?.forEach { requestScopes(it) }\n                    requestServerAuthCode(request.serverClientId)\n                }.build()\n                val authResponse = getServerAuthTokenManager(context, packageName, googleSignInOptions, account)?.let {\n                    withContext(Dispatchers.IO) { it.requestAuth(true) }\n                }\n                callback?.onVerifed(Status.SUCCESS, VerifyWithGoogleResult().apply {\n                    serverAuthToken = authResponse?.auth\n                    grantedScopes = authResponse?.grantedScopes?.split(\" \")?.map { Scope(it) }?.toList() ?: googleSignInOptions.scopeUris.toList()\n                })\n                return@launchWhenStarted\n            }\n            callback?.onVerifed(Status.CANCELED, null)\n        }\n    }\n\n    override fun revokeAccess(callback: IStatusCallback?, request: RevokeAccessRequest?) {\n        Log.d(TAG, \"Method: revokeAccess called, request:$request\")\n        lifecycleScope.launchWhenStarted {\n            val authOptions = SignInConfigurationService.getAuthOptions(context, packageName)\n            val authAccount = request?.account\n            if (authOptions.isNotEmpty() && authAccount != null) {\n                val authManager = getOAuthManager(context, packageName, authOptions.first(), authAccount)\n                val token = authManager.peekAuthToken()\n                if (token != null) {\n                    // todo \"https://oauth2.googleapis.com/revoke\"\n                    authManager.invalidateAuthToken(token)\n                    authManager.isPermitted = false\n                }\n            }\n            AccountUtils.get(context).removeSelectedAccount(packageName)\n            runCatching { callback?.onResult(Status.SUCCESS) }\n        }\n    }\n\n    override fun clearToken(callback: IStatusCallback?, request: ClearTokenRequest?) {\n        Log.d(TAG, \"Method: clearToken called, request:$request\")\n        request?.token?.let {\n            AccountManager.get(context).invalidateAuthToken(AuthConstants.DEFAULT_ACCOUNT_TYPE, it)\n        }\n        runCatching { callback?.onResult(Status.SUCCESS) }\n    }\n\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/auth/credentials/identity/IdentityFidoProxyActivity.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth.credentials.identity\n\nimport android.content.Intent\nimport android.os.Bundle\nimport androidx.appcompat.app.AppCompatActivity\nimport com.google.android.gms.auth.api.identity.SignInCredential\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableSerializer\nimport com.google.android.gms.fido.Fido.FIDO2_KEY_CREDENTIAL_EXTRA\nimport com.google.android.gms.fido.fido2.api.common.AuthenticatorErrorResponse\nimport com.google.android.gms.fido.fido2.api.common.PublicKeyCredential\nimport org.microg.gms.auth.AuthConstants\nimport org.microg.gms.fido.core.ui.AuthenticatorActivity.Companion.KEY_CALLER\n\nprivate const val REQUEST_CODE = 1586077619\n\nclass IdentityFidoProxyActivity : AppCompatActivity() {\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        startActivityForResult(Intent(\"org.microg.gms.fido.AUTHENTICATE\").apply {\n            `package` = packageName\n            putExtras(intent.extras ?: Bundle())\n            putExtra(KEY_CALLER, callingActivity?.packageName)\n        }, REQUEST_CODE)\n    }\n\n    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {\n        if (requestCode == REQUEST_CODE) {\n            if (resultCode == RESULT_OK) {\n                val publicKeyCredential = PublicKeyCredential.deserializeFromBytes(data?.getByteArrayExtra(FIDO2_KEY_CREDENTIAL_EXTRA))\n                if (publicKeyCredential.response is AuthenticatorErrorResponse) {\n                    val errorResponse = publicKeyCredential.response as AuthenticatorErrorResponse\n                    setResult(RESULT_OK, Intent().apply {\n                        putExtra(AuthConstants.STATUS, SafeParcelableSerializer.serializeToBytes(Status(CommonStatusCodes.ERROR, errorResponse.errorMessage)))\n                    })\n                } else {\n                    setResult(RESULT_OK, Intent().apply {\n                        putExtra(\n                            AuthConstants.SIGN_IN_CREDENTIAL, SafeParcelableSerializer.serializeToBytes(\n                                SignInCredential(\n                                    publicKeyCredential.id,\n                                    null, null, null, null, null, null, null,\n                                    publicKeyCredential\n                                )\n                            )\n                        )\n                        putExtra(AuthConstants.STATUS, SafeParcelableSerializer.serializeToBytes(Status.SUCCESS))\n                    })\n                }\n            } else {\n                setResult(resultCode)\n            }\n            finish()\n        } else {\n            super.onActivityResult(requestCode, resultCode, data)\n        }\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/auth/credentials/identity/IdentitySignInService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth.credentials.identity\n\nimport android.app.PendingIntent\nimport android.content.Context\nimport android.content.Intent\nimport android.os.Bundle\nimport android.util.Base64\nimport android.util.Log\nimport androidx.core.app.PendingIntentCompat\nimport androidx.core.os.bundleOf\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.LifecycleOwner\nimport androidx.lifecycle.lifecycleScope\nimport com.google.android.gms.auth.api.identity.BeginSignInRequest\nimport com.google.android.gms.auth.api.identity.BeginSignInResult\nimport com.google.android.gms.auth.api.identity.GetPhoneNumberHintIntentRequest\nimport com.google.android.gms.auth.api.identity.GetSignInIntentRequest\nimport com.google.android.gms.auth.api.identity.internal.IBeginSignInCallback\nimport com.google.android.gms.auth.api.identity.internal.IGetPhoneNumberHintIntentCallback\nimport com.google.android.gms.auth.api.identity.internal.IGetSignInIntentCallback\nimport com.google.android.gms.auth.api.identity.internal.ISignInService\nimport com.google.android.gms.auth.api.signin.GoogleSignInOptions\nimport com.google.android.gms.common.ConnectionResult\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.api.internal.IStatusCallback\nimport com.google.android.gms.common.internal.ConnectionInfo\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableSerializer\nimport com.google.android.gms.fido.common.Transport\nimport com.google.android.gms.fido.fido2.api.common.PublicKeyCredentialDescriptor\nimport com.google.android.gms.fido.fido2.api.common.PublicKeyCredentialRequestOptions\nimport com.google.android.gms.fido.fido2.api.common.UserVerificationRequirement\nimport kotlinx.coroutines.launch\nimport org.json.JSONArray\nimport org.json.JSONObject\nimport org.microg.gms.BaseService\nimport org.microg.gms.auth.signin.ACTION_ASSISTED_SIGN_IN\nimport org.microg.gms.auth.signin.BEGIN_SIGN_IN_REQUEST\nimport org.microg.gms.auth.signin.GET_SIGN_IN_INTENT_REQUEST\nimport org.microg.gms.auth.credentials.FEATURES\nimport org.microg.gms.auth.signin.CLIENT_PACKAGE_NAME\nimport org.microg.gms.auth.signin.GOOGLE_SIGN_IN_OPTIONS\nimport org.microg.gms.auth.signin.SignInConfigurationService\nimport org.microg.gms.auth.signin.performSignOut\nimport org.microg.gms.common.AccountUtils\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.fido.core.Database\nimport org.microg.gms.fido.core.ui.AuthenticatorActivity.Companion.KEY_OPTIONS\nimport org.microg.gms.fido.core.ui.AuthenticatorActivity.Companion.KEY_SERVICE\nimport org.microg.gms.fido.core.ui.AuthenticatorActivity.Companion.KEY_SOURCE\nimport org.microg.gms.fido.core.ui.AuthenticatorActivity.Companion.KEY_TYPE\n\nprivate const val TAG = \"IdentitySignInService\"\n\nclass IdentitySignInService : BaseService(TAG, GmsService.AUTH_API_IDENTITY_SIGNIN) {\n\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        Log.d(TAG, \"handleServiceRequest start \")\n        val connectionInfo = ConnectionInfo()\n        connectionInfo.features = FEATURES\n        callback.onPostInitCompleteWithConnectionInfo(\n            ConnectionResult.SUCCESS, IdentitySignInServiceImpl(this, request.packageName, lifecycle).asBinder(), connectionInfo\n        )\n    }\n}\n\nclass IdentitySignInServiceImpl(private val context: Context, private val clientPackageName: String, override val lifecycle: Lifecycle) :\n    ISignInService.Stub(), LifecycleOwner {\n\n    private val requestMap = mutableMapOf<String, GoogleSignInOptions>()\n\n    override fun beginSignIn(callback: IBeginSignInCallback, request: BeginSignInRequest) {\n        Log.d(TAG, \"method 'beginSignIn' called\")\n        Log.d(TAG, \"request-> $request\")\n        if (request.googleIdTokenRequestOptions.isSupported) {\n            if (request.googleIdTokenRequestOptions.serverClientId.isNullOrEmpty()) {\n                Log.d(TAG, \"serverClientId is empty, return CANCELED \")\n                callback.onResult(Status.CANCELED, null)\n                return\n            }\n            val bundle = Bundle().apply {\n                val options = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)\n                    .requestEmail()\n                    .requestIdToken(request.googleIdTokenRequestOptions.serverClientId).build()\n                putByteArray(BEGIN_SIGN_IN_REQUEST, SafeParcelableSerializer.serializeToBytes(request))\n                putByteArray(GOOGLE_SIGN_IN_OPTIONS, SafeParcelableSerializer.serializeToBytes(options))\n                putString(CLIENT_PACKAGE_NAME, clientPackageName)\n                requestMap[request.sessionId] = options\n            }\n            callback.onResult(Status.SUCCESS, BeginSignInResult(performGoogleSignIn(bundle)))\n        } else if (request.passkeyJsonRequestOptions.isSupported) {\n            fun JSONObject.getArrayOrNull(key: String) = if (has(key)) getJSONArray(key) else null\n            fun <T> JSONArray.map(fn: (JSONObject) -> T): List<T> =  (0 until length()).map { fn(getJSONObject(it)) }\n            fun <T> JSONArray.map(fn: (String) -> T): List<T> =  (0 until length()).map { fn(getString(it)) }\n            val json = JSONObject(request.passkeyJsonRequestOptions.requestJson)\n            val rpId = json.getString(\"rpId\")\n            val options = PublicKeyCredentialRequestOptions.Builder()\n                .setAllowList(json.getArrayOrNull(\"allowCredentials\")?.let { allowCredentials -> allowCredentials.map { credential: JSONObject ->\n                    PublicKeyCredentialDescriptor(\n                        credential.getString(\"type\"),\n                        Base64.decode(credential.getString(\"id\"), Base64.URL_SAFE),\n                        credential.getArrayOrNull(\"transports\")?.let { transports -> transports.map { transportString: String ->\n                            Transport.fromString(transportString)\n                        } }.orEmpty()\n                    )\n                } })\n                .setChallenge(Base64.decode(json.getString(\"challenge\"), Base64.URL_SAFE))\n                .setRequireUserVerification(json.optString(\"userVerification\").takeIf { it.isNotBlank() }?.let { UserVerificationRequirement.fromString(it) })\n                .setRpId(rpId)\n                .setTimeoutSeconds(json.optDouble(\"timeout\", -1.0).takeIf { it > 0 })\n                .build()\n            if (request.isPreferImmediatelyAvailableCredentials && Database(context).getKnownRegistrationInfo(rpId).isEmpty()) {\n                Log.d(TAG, \"need available Credential\")\n                callback.onResult(Status.CANCELED, null)\n                return\n            }\n            val bundle = bundleOf(\n                KEY_SERVICE to GmsService.AUTH_API_IDENTITY_SIGNIN.SERVICE_ID,\n                KEY_SOURCE to \"app\",\n                KEY_TYPE to \"sign\",\n                KEY_OPTIONS to options.serializeToBytes()\n            )\n            callback.onResult(Status.SUCCESS, BeginSignInResult(performFidoSignIn(bundle)))\n        } else {\n            callback.onResult(Status.INTERNAL_ERROR, null)\n        }\n    }\n\n    override fun signOut(callback: IStatusCallback, requestTag: String) {\n        Log.d(TAG, \"method signOut called, requestTag=$requestTag\")\n        lifecycleScope.launch {\n            val signInAccount = SignInConfigurationService.getDefaultAccount(context, clientPackageName)\n            val authOptions = SignInConfigurationService.getAuthOptions(context, clientPackageName).plus(requestMap[requestTag])\n            if (signInAccount != null && authOptions.isNotEmpty()) {\n                authOptions.forEach {\n                    performSignOut(context, clientPackageName, it, signInAccount)\n                }\n            }\n            AccountUtils.get(context).removeSelectedAccount(clientPackageName)\n        }\n        callback.onResult(Status.SUCCESS)\n    }\n\n    override fun getSignInIntent(\n        callback: IGetSignInIntentCallback, request: GetSignInIntentRequest\n    ) {\n        Log.d(TAG, \"method 'getSignInIntent' called\")\n        Log.d(TAG, \"request-> $request\")\n        if (request.serverClientId.isNullOrEmpty()) {\n            Log.d(TAG, \"serverClientId is empty, return CANCELED \")\n            callback.onResult(Status.CANCELED, null)\n            return\n        }\n        val bundle = Bundle().apply {\n            val options =\n                GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)\n                    .requestEmail()\n                    .requestIdToken(request.serverClientId)\n                    .build()\n            putByteArray(GET_SIGN_IN_INTENT_REQUEST, SafeParcelableSerializer.serializeToBytes(request))\n            putByteArray(GOOGLE_SIGN_IN_OPTIONS, SafeParcelableSerializer.serializeToBytes(options))\n            putString(CLIENT_PACKAGE_NAME, clientPackageName)\n            requestMap[request.sessionId] = options\n        }\n        callback.onResult(Status.SUCCESS, performGoogleSignIn(bundle))\n    }\n\n    override fun getPhoneNumberHintIntent(\n        callback: IGetPhoneNumberHintIntentCallback, request: GetPhoneNumberHintIntentRequest\n    ) {\n        Log.w(TAG, \"method 'getPhoneNumberHintIntent' not fully implemented, return status is CANCELED.\")\n        callback.onResult(Status.CANCELED, null)\n    }\n\n    private fun performGoogleSignIn(bundle: Bundle): PendingIntent {\n        val intent = Intent(ACTION_ASSISTED_SIGN_IN).apply {\n            `package` = context.packageName\n            putExtras(bundle)\n        }\n        val flags = PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_UPDATE_CURRENT\n        return PendingIntentCompat.getActivity(context, 0, intent, flags, false)!!\n    }\n\n    private fun performFidoSignIn(bundle: Bundle): PendingIntent {\n        val intent = Intent(context, IdentityFidoProxyActivity::class.java).apply {\n            putExtras(bundle)\n        }\n        val flags = PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_UPDATE_CURRENT\n        return PendingIntentCompat.getActivity(context, 0, intent, flags, false)!!\n    }\n\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/auth/folsom/KeyRetrievalService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth.folsom\n\nimport android.app.PendingIntent.FLAG_UPDATE_CURRENT\nimport android.content.Context\nimport android.content.Intent\nimport android.os.Parcel\nimport android.util.Log\nimport androidx.core.app.PendingIntentCompat\nimport com.google.android.gms.auth.folsom.RecoveryRequest\nimport com.google.android.gms.auth.folsom.RecoveryResult\nimport com.google.android.gms.auth.folsom.SharedKey\nimport com.google.android.gms.auth.folsom.internal.IBooleanCallback\nimport com.google.android.gms.auth.folsom.internal.IByteArrayCallback\nimport com.google.android.gms.auth.folsom.internal.IByteArrayListCallback\nimport com.google.android.gms.auth.folsom.internal.IKeyRetrievalCallback\nimport com.google.android.gms.auth.folsom.internal.IKeyRetrievalConsentCallback\nimport com.google.android.gms.auth.folsom.internal.IKeyRetrievalService\nimport com.google.android.gms.auth.folsom.internal.IKeyRetrievalSyncStatusCallback\nimport com.google.android.gms.auth.folsom.internal.IRecoveryResultCallback\nimport com.google.android.gms.auth.folsom.internal.ISecurityDomainMembersCallback\nimport com.google.android.gms.auth.folsom.internal.ISharedKeyCallback\nimport com.google.android.gms.auth.folsom.internal.IStringListCallback\nimport com.google.android.gms.common.Feature\nimport com.google.android.gms.common.api.ApiMetadata\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.api.internal.IStatusCallback\nimport com.google.android.gms.common.internal.ConnectionInfo\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport org.microg.gms.BaseService\nimport org.microg.gms.auth.folsom.ui.GenericActivity\nimport org.microg.gms.common.Constants.GMS_PACKAGE_NAME\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.utils.warnOnTransactionIssues\n\nprivate const val TAG = \"KeyRetrievalService\"\n\nprivate val FEATURES = arrayOf(\n    Feature(\"key_retrieval\", 2L),\n    Feature(\"list_recovered_security_domains\", 1L),\n    Feature(\"start_recovery\", 3L),\n    Feature(\"recoverability_fix\", 2L),\n    Feature(\"lskf_consent\", 1L),\n    Feature(\"reset_security_domain\", 2L),\n    Feature(\"generate_open_vault_request\", 1L),\n    Feature(\"silently_add_gaia_password_member\", 1L),\n    Feature(\"get_domain_state\", 1),\n    Feature(\"get_product_keys\", 1),\n    Feature(\"create_prf_member\", 1),\n    Feature(\"add_recovery_contact_to_dependent_keychain\", 1),\n    Feature(\"create_retrieval_packet\", 1),\n    Feature(\"set_claimant_key\", 1),\n)\n\nclass KeyRetrievalService : BaseService(TAG, GmsService.FOLSOM) {\n\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        Log.d(TAG, \"handleServiceRequest: packageName: ${request.packageName}\")\n        callback.onPostInitCompleteWithConnectionInfo(CommonStatusCodes.SUCCESS, KeyRetrievalServiceImpl(this), ConnectionInfo().apply { features = FEATURES })\n    }\n}\n\nclass KeyRetrievalServiceImpl(val context: Context) : IKeyRetrievalService.Stub() {\n\n    override fun setConsent(\n        callback: IKeyRetrievalConsentCallback?, accountName: String?, force: Boolean, metadata: ApiMetadata?\n    ) {\n        Log.d(TAG, \"Not implemented setConsent accountName:$accountName force:$force metadata:$metadata\")\n        callback?.onResult(Status.SUCCESS, true)\n    }\n\n    override fun getConsent(\n        callback: IKeyRetrievalConsentCallback?, accountName: String?, metadata: ApiMetadata?\n    ) {\n        Log.d(TAG, \"Not implemented getConsent accountName:$accountName metadata:$metadata\")\n        callback?.onResult(Status.SUCCESS, true)\n    }\n\n    override fun getSyncStatus(\n        callback: IKeyRetrievalSyncStatusCallback?, accountName: String?, metadata: ApiMetadata?\n    ) {\n        Log.d(TAG, \"Not implemented getSyncStatus accountName:$accountName metadata:$metadata\")\n        callback?.onResult(Status.SUCCESS, true)\n    }\n\n    override fun markLocalKeysAsStale(\n        callback: IKeyRetrievalCallback?, accountName: String?, metadata: ApiMetadata?\n    ) {\n        Log.d(TAG, \"Not implemented markLocalKeysAsStale accountName:$accountName metadata:$metadata\")\n        callback?.onResult(Status.SUCCESS)\n    }\n\n    override fun getKeyMaterial(\n        callback: ISharedKeyCallback?, accountName: String?, metadata: ApiMetadata?\n    ) {\n        Log.d(TAG, \"Not implemented getKeyMaterial accountName:$accountName metadata:$metadata\")\n        callback?.onResult(Status.INTERNAL_ERROR, emptyArray<SharedKey>())\n    }\n\n    override fun setKeyMaterial(\n        callback: IKeyRetrievalCallback?, accountName: String?, keys: Array<out SharedKey?>?, metadata: ApiMetadata?\n    ) {\n        Log.d(TAG, \"Not implemented setKeyMaterial accountName:$accountName keys:$keys metadata:$metadata\")\n        callback?.onResult(Status.INTERNAL_ERROR)\n    }\n\n    override fun getRecoveredSecurityDomains(\n        callback: IStringListCallback?, accountName: String?, metadata: ApiMetadata?\n    ) {\n        Log.d(TAG, \"Not implemented getRecoveredSecurityDomains accountName:$accountName metadata:$metadata\")\n        callback?.onResult(Status.SUCCESS, emptyArray<String>())\n    }\n\n    override fun startRecoveryOperation(\n        callback: IRecoveryResultCallback?, metadata: ApiMetadata?, request: RecoveryRequest?\n    ) {\n        Log.d(TAG, \"Not implemented startRecoveryOperation request:$request metadata:$metadata\")\n        callback?.onResult(Status.SUCCESS, RecoveryResult())\n    }\n\n    override fun listVaultsOperation(\n        callback: IByteArrayListCallback?, accountName: String?, metadata: ApiMetadata?\n    ) {\n        Log.d(TAG, \"Not implemented listVaultsOperation accountName:$accountName metadata:$metadata\")\n        callback?.onResult(Status.SUCCESS, emptyList<ByteArray>())\n    }\n\n    override fun getProductDetails(\n        callback: IByteArrayCallback?, accountName: String?, metadata: ApiMetadata?\n    ) {\n        Log.d(TAG, \"Not implemented getProductDetails accountName:$accountName metadata:$metadata\")\n        callback?.onResult(Status.SUCCESS, byteArrayOf())\n    }\n\n    override fun joinSecurityDomain(\n        callback: IStatusCallback?, accountName: String?, bytes: ByteArray?, type: Int, metadata: ApiMetadata?\n    ) {\n        Log.d(TAG, \"Not implemented joinSecurityDomain accountName:$accountName type:$type metadata:$metadata\")\n        callback?.onResult(Status.SUCCESS)\n    }\n\n    override fun startUxFlow(\n        callback: IKeyRetrievalCallback?, accountName: String?, type: Int, metadata: ApiMetadata?\n    ) {\n        Log.d(TAG, \"Not implemented startUxFlow accountName:$accountName type:$type metadata:$metadata\")\n        val intent = Intent().apply { setClassName(GMS_PACKAGE_NAME, GenericActivity::class.java.name) }\n        val pendingIntent = PendingIntentCompat.getActivity(context, 0, intent, FLAG_UPDATE_CURRENT, false)\n        val states = Status(CommonStatusCodes.SUCCESS, \"UX flow PendingIntent retrieved.\", pendingIntent)\n        callback?.onResult(states)\n    }\n\n    override fun promptForLskfConsent(\n        callback: IKeyRetrievalCallback?, accountName: String?, metadata: ApiMetadata?\n    ) {\n        Log.d(TAG, \"Not implemented promptForLskfConsent accountName:$accountName metadata:$metadata\")\n        callback?.onResult(Status.SUCCESS)\n    }\n\n    override fun resetSecurityDomain(\n        callback: IStatusCallback?, accountName: String?, metadata: ApiMetadata?\n    ) {\n        Log.d(TAG, \"Not implemented resetSecurityDomain accountName:$accountName metadata:$metadata\")\n        callback?.onResult(Status.SUCCESS)\n    }\n\n    override fun listSecurityDomainMembers(\n        callback: ISecurityDomainMembersCallback?, accountName: String?, metadata: ApiMetadata?\n    ) {\n        Log.d(TAG, \"Not implemented listSecurityDomainMembers accountName:$accountName metadata:$metadata\")\n        callback?.onResult(Status.SUCCESS, emptyList<Int>())\n    }\n\n    override fun generateOpenVaultRequestOperation(\n        callback: IByteArrayCallback?, request: RecoveryRequest?, metadata: ApiMetadata?\n    ) {\n        Log.d(TAG, \"Not implemented generateOpenVaultRequestOperation request:$request metadata:$metadata\")\n        callback?.onResult(Status.SUCCESS, byteArrayOf())\n    }\n\n    override fun canSilentlyAddGaiaPassword(\n        callback: IBooleanCallback?, accountName: String?, metadata: ApiMetadata?\n    ) {\n        Log.d(TAG, \"Not implemented canSilentlyAddGaiaPassword accountName:$accountName metadata:$metadata\")\n        callback?.onResult(Status.SUCCESS, true)\n    }\n\n    override fun addGaiaPasswordMember(\n        callback: IStatusCallback?, accountName: String?, metadata: ApiMetadata?\n    ) {\n        Log.d(TAG, \"Not implemented addGaiaPasswordMember accountName:$accountName metadata:$metadata\")\n        callback?.onResult(Status.SUCCESS)\n    }\n\n    override fun getDomainState(\n        callback: IByteArrayCallback?,\n        accountName: String?,\n        metadata: ApiMetadata?\n    ) {\n        Log.d(TAG, \"Not yet implemented: getDomainState\")\n        callback?.onResult(Status.SUCCESS, byteArrayOf())\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean {\n        return warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/auth/folsom/ui/GenericActivity.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth.folsom.ui\n\nimport android.os.Bundle\nimport android.widget.Toast\nimport androidx.appcompat.app.AppCompatActivity\nimport com.google.android.gms.R\n\nclass GenericActivity : AppCompatActivity() {\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        Toast.makeText(this, getString(R.string.backup_disabled), Toast.LENGTH_SHORT).show()\n        finish()\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/auth/login/DroidGuardHandler.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth.login\n\nimport androidx.lifecycle.lifecycleScope\nimport com.google.android.gms.droidguard.DroidGuardClient\nimport com.google.android.gms.tasks.await\nimport java.util.*\n\nclass DroidGuardHandler(private val activity: LoginActivity) {\n    fun start(dg: String) {\n        activity.lifecycleScope.launchWhenStarted {\n            try {\n                val result = DroidGuardClient.getResults(activity, \"minute_maid\", Collections.singletonMap(\"dg_minutemaid\", dg)).await()\n                activity.runScript(\"window.setDgResult('$result')\")\n            } catch (e: Exception) {\n                // Ignore\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/auth/login/FidoHandler.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth.login\n\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.Bundle\nimport android.util.Base64\nimport android.util.Log\nimport androidx.lifecycle.lifecycleScope\nimport com.google.android.gms.fido.fido2.api.common.*\nimport kotlinx.coroutines.CancellationException\nimport org.json.JSONArray\nimport org.json.JSONObject\nimport org.microg.gms.fido.core.RequestHandlingException\nimport org.microg.gms.fido.core.transport.Transport\nimport org.microg.gms.fido.core.transport.TransportHandlerCallback\nimport org.microg.gms.fido.core.transport.bluetooth.BluetoothTransportHandler\nimport org.microg.gms.fido.core.transport.nfc.NfcTransportHandler\nimport org.microg.gms.fido.core.transport.screenlock.ScreenLockTransportHandler\nimport org.microg.gms.fido.core.transport.usb.UsbTransportHandler\nimport org.microg.gms.utils.toBase64\n\nfun JSONObject.getStringOrNull(key: String) = if (has(key)) getString(key) else null\nfun JSONObject.getIntOrNull(key: String) = if (has(key)) getInt(key) else null\nfun JSONObject.getDoubleOrNull(key: String) = if (has(key)) getDouble(key) else null\nfun JSONObject.getArrayOrNull(key: String) = if (has(key)) getJSONArray(key) else null\n\nclass FidoHandler(private val activity: LoginActivity) : TransportHandlerCallback {\n    private lateinit var requestOptions: PublicKeyCredentialRequestOptions\n    private val transportHandlers by lazy {\n        setOfNotNull(\n            BluetoothTransportHandler(activity, this),\n            NfcTransportHandler(activity, this),\n            if (SDK_INT >= 21) UsbTransportHandler(activity, this) else null,\n            if (SDK_INT >= 23) ScreenLockTransportHandler(activity, this) else null\n        )\n    }\n\n    override fun onStatusChanged(transport: Transport, status: String, extras: Bundle?) {\n        Log.d(TAG, \"onStatusChanged: $transport, $status\")\n    }\n\n    private fun sendEvent(type: String, data: JSONObject, extras: JSONObject? = null) {\n        val event = JSONObject(extras?.toString() ?: \"{}\")\n        event.put(\"type\", type)\n        event.put(\"data\", data)\n        activity.runScript(\"window.setFido2SkUiEvent($event)\")\n    }\n\n    private fun sendResult(result: JSONObject) {\n        activity.runScript(\"window.setFido2SkResult($result)\")\n    }\n\n    private fun sendSelectView(viewName: String, extras: JSONObject? = null) {\n        val data = JSONObject(extras?.toString() ?: \"{}\")\n        data.put(\"viewName\", viewName)\n        sendEvent(\"select_view\", data)\n    }\n\n    private fun sendErrorResult(errorCode: ErrorCode, errorMessage: String?) {\n        Log.d(TAG, \"Finish with error: $errorMessage ($errorCode)\")\n        sendResult(JSONObject().apply {\n            put(\"errorCode\", errorCode.code)\n            if (errorMessage != null) put(\"errorMessage\", errorMessage)\n        })\n    }\n\n    private fun sendSuccessResult(response: AuthenticatorResponse, transport: Transport) {\n        Log.d(TAG, \"Finish with success response: $response\")\n        if (response is AuthenticatorAssertionResponse) {\n            sendResult(JSONObject().apply {\n                val base64Flags = Base64.NO_PADDING + Base64.NO_WRAP + Base64.URL_SAFE\n                put(\"keyHandle\", response.keyHandle?.toBase64(base64Flags))\n                put(\"clientDataJSON\", response.clientDataJSON?.toBase64(base64Flags))\n                put(\"authenticatorData\", response.authenticatorData?.toBase64(base64Flags))\n                put(\"signature\", response.signature?.toBase64(base64Flags))\n                if (response.userHandle != null) {\n                    put(\"userHandle\", response.userHandle?.toBase64(base64Flags))\n                }\n            })\n        }\n    }\n\n    private val availableTransports: List<String>\n        get() {\n            val list = mutableListOf<String>()\n            val transports = transportHandlers.filter { it.isSupported }.map { it.transport }\n            if (Transport.BLUETOOTH in transports) {\n                list.add(\"bt\")\n                list.add(\"ble\")\n            }\n            if (Transport.USB in transports) list.add(\"usb\")\n            if (Transport.NFC in transports) list.add(\"nfc\")\n            if (Transport.SCREEN_LOCK in transports) list.add(\"internal\")\n            return list\n        }\n\n    fun startSignRequest(request: String) {\n        try {\n            val requestObject = JSONObject(request)\n            requestOptions = PublicKeyCredentialRequestOptions.Builder().apply {\n                val base64Flags = Base64.NO_PADDING + Base64.NO_WRAP + Base64.URL_SAFE\n                requestObject.getStringOrNull(\"challenge\")?.let { setChallenge(Base64.decode(it, base64Flags)) }\n                requestObject.getDoubleOrNull(\"timeoutSeconds\")?.let { setTimeoutSeconds(it) }\n                requestObject.getStringOrNull(\"rpId\")?.let { setRpId(it) }\n                requestObject.getArrayOrNull(\"allowList\")?.let {\n                    val allowList = mutableListOf<PublicKeyCredentialDescriptor>()\n                    for (i in 0 until it.length()) {\n                        val obj = it.getJSONObject(i)\n                        allowList.add(\n                            PublicKeyCredentialDescriptor(\n                                obj.getStringOrNull(\"type\") ?: \"public-key\",\n                                Base64.decode(obj.getString(\"id\"), base64Flags),\n                                emptyList()\n                            )\n                        )\n                    }\n                    setAllowList(allowList)\n                }\n                requestObject.getIntOrNull(\"requestId\")?.let { setRequestId(it) }\n            }.build()\n            Log.d(TAG, \"sign: $requestOptions\")\n            sendSelectView(\"multiple_transports\", JSONObject().apply {\n                put(\"transports\", JSONArray(availableTransports))\n            })\n        } catch (e: Exception) {\n            Log.w(TAG, e)\n        }\n    }\n\n    fun onEvent(event: String) {\n        try {\n            val eventObject = JSONObject(event)\n            Log.d(TAG, \"event: $eventObject\")\n            when (eventObject.getString(\"type\")) {\n                \"user_selected_view_for_transport\" -> {\n                    val transport = when (eventObject.getJSONObject(\"data\").getString(\"transport\")) {\n                        \"bt\" -> Transport.BLUETOOTH\n                        \"ble\" -> Transport.BLUETOOTH\n                        \"nfc\" -> Transport.NFC\n                        \"usb\" -> Transport.USB\n                        \"internal\" -> Transport.SCREEN_LOCK\n                        else -> return\n                    }\n                    val transportHandler = transportHandlers.firstOrNull { it.transport == transport && it.isSupported } ?: return\n                    activity.lifecycleScope.launchWhenStarted {\n                        val options = requestOptions\n                        try {\n                            sendSuccessResult(transportHandler.start(options, activity.packageName), transport)\n                        } catch (e: CancellationException) {\n                            Log.w(TAG, e)\n                            // Ignoring cancellation here\n                        } catch (e: RequestHandlingException) {\n                            Log.w(TAG, e)\n                            sendErrorResult(e.errorCode, e.message)\n                        } catch (e: Exception) {\n                            Log.w(TAG, e)\n                            sendErrorResult(ErrorCode.UNKNOWN_ERR, e.message)\n                        }\n                    }\n                    val extras = JSONObject().apply {\n                        put(\"alternateAvailableTransports\", JSONArray(availableTransports))\n                    }\n                    val viewName = when (transport) {\n                        Transport.NFC -> {\n                            extras.put(\"deviceRemovedTooSoon\", false)\n                            extras.put(\"recommendUsb\", false)\n                            \"nfc_instructions\"\n                        }\n                        Transport.USB -> \"usb_instructions\"\n                        Transport.BLUETOOTH -> \"ble_instructions\"\n                        else -> return\n                    }\n                    sendSelectView(viewName, extras)\n                }\n            }\n        } catch (e: Exception) {\n            Log.w(TAG, e)\n        }\n    }\n\n    fun cancel() {\n        Log.d(TAG, \"cancel\")\n    }\n\n    companion object {\n        private const val TAG = \"AuthFidoHandler\"\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/auth/proxy/AuthProxyService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth.proxy\n\nimport android.content.Context\nimport android.os.Bundle\nimport android.os.Parcel\nimport android.util.Log\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.LifecycleOwner\nimport androidx.lifecycle.lifecycleScope\nimport com.google.android.gms.auth.api.internal.IAuthCallbacks\nimport com.google.android.gms.auth.api.internal.IAuthService\nimport com.google.android.gms.auth.api.proxy.ProxyRequest\nimport com.google.android.gms.auth.api.proxy.ProxyResponse\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\nimport org.microg.gms.BaseService\nimport org.microg.gms.auth.appcert.AppCertManager\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.common.GooglePackagePermission\nimport org.microg.gms.common.PackageUtils\nimport org.microg.gms.utils.warnOnTransactionIssues\n\nprivate const val TAG = \"AuthProxyService\"\n\nclass AuthProxyService : BaseService(TAG, GmsService.AUTH_PROXY) {\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        val packageName = PackageUtils.getAndCheckCallingPackage(this, request.packageName)\n                ?: throw IllegalArgumentException(\"Missing package name\")\n        PackageUtils.assertGooglePackagePermission(this, GooglePackagePermission.APP_CERT)\n        val consumerPackageName = request.extras.getString(\"consumerPkg\")\n        if (consumerPackageName != null) PackageUtils.assertGooglePackagePermission(this, GooglePackagePermission.IMPERSONATE)\n        val serviceImpl = AuthServiceImpl(this, lifecycle, consumerPackageName ?: packageName)\n        callback.onPostInitComplete(CommonStatusCodes.SUCCESS, serviceImpl, Bundle())\n    }\n}\n\nclass AuthServiceImpl(private val context: Context, override val lifecycle: Lifecycle, private val packageName: String) : IAuthService.Stub(), LifecycleOwner {\n    override fun performProxyRequest(callbacks: IAuthCallbacks, request: ProxyRequest) {\n        Log.d(TAG, \"performProxyRequest($packageName, $request)\")\n        lifecycleScope.launchWhenStarted {\n            callbacks.onProxyResponse(ProxyResponse().apply { gmsStatusCode = CommonStatusCodes.CANCELED })\n        }\n    }\n\n    override fun getSpatulaHeader(callbacks: IAuthCallbacks) {\n        Log.d(TAG, \"getSpatulaHeader($packageName)\")\n        lifecycleScope.launchWhenStarted {\n            val result = withContext(Dispatchers.IO) { AppCertManager(context).getSpatulaHeader(packageName) }\n            Log.d(TAG, \"Result: $result\")\n            callbacks.onSpatulaHeader(result)\n        }\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/auth/signin/AssistedSignInActivity.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth.signin\n\nimport android.content.Intent\nimport android.os.Bundle\nimport android.util.Log\nimport androidx.appcompat.app.AppCompatActivity\nimport com.google.android.gms.R\nimport com.google.android.gms.auth.api.identity.BeginSignInRequest\nimport com.google.android.gms.auth.api.identity.GetSignInIntentRequest\nimport com.google.android.gms.auth.api.identity.SignInCredential\nimport com.google.android.gms.auth.api.signin.GoogleSignInAccount\nimport com.google.android.gms.auth.api.signin.GoogleSignInOptions\nimport com.google.android.gms.auth.api.signin.internal.SignInConfiguration\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableSerializer\nimport org.microg.gms.auth.AuthConstants\nimport org.microg.gms.common.Constants\n\nconst val ACTION_ASSISTED_SIGN_IN = \"com.google.android.gms.auth.api.credentials.ASSISTED_SIGNIN\"\nconst val GET_SIGN_IN_INTENT_REQUEST = \"get_sign_in_intent_request\"\nconst val BEGIN_SIGN_IN_REQUEST = \"begin_sign_in_request\"\nconst val CLIENT_PACKAGE_NAME = \"client_package_name\"\nconst val GOOGLE_SIGN_IN_OPTIONS = \"google_sign_in_options\"\n\nprivate const val TAG = \"AssistedSignInActivity\"\nprivate const val REQUEST_CODE_SIGN_IN = 120\n\nclass AssistedSignInActivity : AppCompatActivity() {\n\n    private val googleSignInOptions: GoogleSignInOptions?\n        get() = runCatching {\n            intent?.extras?.takeIf { it.containsKey(GOOGLE_SIGN_IN_OPTIONS) }?.getByteArray(GOOGLE_SIGN_IN_OPTIONS)\n                ?.let {\n                    return SafeParcelableSerializer.deserializeFromBytes(it, GoogleSignInOptions.CREATOR)\n                }\n        }.getOrNull()\n\n    private val signInIntentRequest: GetSignInIntentRequest?\n        get() = runCatching {\n            intent?.extras?.takeIf { it.containsKey(GET_SIGN_IN_INTENT_REQUEST) }\n                ?.getByteArray(GET_SIGN_IN_INTENT_REQUEST)?.let {\n                    return SafeParcelableSerializer.deserializeFromBytes(it, GetSignInIntentRequest.CREATOR)\n                }\n        }.getOrNull()\n\n    private val beginSignInRequest: BeginSignInRequest?\n        get() = runCatching {\n            intent?.extras?.takeIf { it.containsKey(BEGIN_SIGN_IN_REQUEST) }?.getByteArray(BEGIN_SIGN_IN_REQUEST)?.let {\n                return SafeParcelableSerializer.deserializeFromBytes(it, BeginSignInRequest.CREATOR)\n            }\n        }.getOrNull()\n\n    private val clientPackageName: String?\n        get() = runCatching {\n            intent?.extras?.takeIf { it.containsKey(CLIENT_PACKAGE_NAME) }?.getString(CLIENT_PACKAGE_NAME)\n        }.getOrNull()\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        setTheme(R.style.ThemeTranslucentCommon)\n        Log.d(TAG, \"onCreate: clientPackageName:$clientPackageName\")\n        if (clientPackageName == null) return errorResult(\n            Status(\n                CommonStatusCodes.ERROR, \"Invalid calling package.\"\n            )\n        )\n        if (googleSignInOptions == null) return errorResult(Status(CommonStatusCodes.ERROR, \"request params invalid.\"))\n\n        if (signInIntentRequest != null) {\n            Log.d(TAG, \"signInIntentRequest start\")\n            prepareSignIn()\n            return\n        }\n\n        if (beginSignInRequest != null) {\n            Log.d(TAG, \"beginSignInRequest start\")\n            val fragment = supportFragmentManager.findFragmentByTag(AssistedSignInFragment.TAG)\n            if (fragment != null) {\n                val assistedSignInFragment = fragment as AssistedSignInFragment\n                assistedSignInFragment.cancelLogin(true)\n            } else {\n                AssistedSignInFragment.newInstance(clientPackageName!!, googleSignInOptions!!, beginSignInRequest!!)\n                    .show(supportFragmentManager, AssistedSignInFragment.TAG)\n            }\n            return\n        }\n\n        errorResult(Status(CommonStatusCodes.ERROR, \"Intent data corrupted.\"))\n    }\n\n    private fun prepareSignIn() {\n        Log.d(TAG, \"prepareSignIn options:$googleSignInOptions\")\n        val signInConfiguration = SignInConfiguration(clientPackageName!!, googleSignInOptions!!)\n        val intent = Intent(this, AuthSignInActivity::class.java).apply {\n            `package` = Constants.GMS_PACKAGE_NAME\n            putExtra(\"config\", signInConfiguration)\n            putExtra(\"nonce\", signInIntentRequest?.nonce)\n        }\n        startActivityForResult(intent, REQUEST_CODE_SIGN_IN)\n    }\n\n    fun errorResult(status: Status) {\n        Log.d(TAG, \"errorResult: $status\")\n        setResult(RESULT_CANCELED, Intent().apply {\n            putExtra(AuthConstants.STATUS, SafeParcelableSerializer.serializeToBytes(status))\n        })\n        finish()\n    }\n\n    fun loginResult(googleSignInAccount: GoogleSignInAccount?) {\n        if (googleSignInAccount == null) {\n            errorResult(Status(CommonStatusCodes.CANCELED, \"User cancelled.\"))\n            return\n        }\n        Log.d(TAG, \"loginResult: googleSignInAccount: $googleSignInAccount\")\n        val credential = SignInCredential(\n            googleSignInAccount.email,\n            googleSignInAccount.displayName,\n            googleSignInAccount.givenName,\n            googleSignInAccount.familyName,\n            null,\n            null,\n            googleSignInAccount.idToken,\n            null,\n            null\n        )\n        setResult(RESULT_OK, Intent().apply {\n            putExtra(AuthConstants.SIGN_IN_CREDENTIAL, SafeParcelableSerializer.serializeToBytes(credential))\n            putExtra(AuthConstants.STATUS, SafeParcelableSerializer.serializeToBytes(Status.SUCCESS))\n        })\n        finish()\n    }\n\n    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {\n        if (requestCode == REQUEST_CODE_SIGN_IN) {\n            val googleSignInAccount =\n                data?.getParcelableExtra<GoogleSignInAccount>(AuthConstants.GOOGLE_SIGN_IN_ACCOUNT)\n            loginResult(googleSignInAccount)\n        } else {\n            super.onActivityResult(requestCode, resultCode, data)\n        }\n    }\n\n    override fun onNewIntent(intent: Intent?) {\n        super.onNewIntent(intent)\n        Log.d(TAG, \"onNewIntent intent:$intent\")\n        val fragment = supportFragmentManager.findFragmentByTag(AssistedSignInFragment.TAG)\n        if (fragment != null) {\n            val assistedSignInFragment = fragment as AssistedSignInFragment\n            assistedSignInFragment.cancelLogin(true)\n        }\n    }\n\n    override fun onResume() {\n        super.onResume()\n        Log.d(TAG, \"onResume\")\n        val fragment = supportFragmentManager.findFragmentByTag(AssistedSignInFragment.TAG)\n        if (fragment != null) {\n            val assistedSignInFragment = fragment as AssistedSignInFragment\n            assistedSignInFragment.initView()\n        }\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/auth/signin/AssistedSignInFragment.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth.signin\n\nimport android.accounts.Account\nimport android.accounts.AccountManager\nimport android.app.Dialog\nimport android.content.DialogInterface\nimport android.content.Intent\nimport android.graphics.Color\nimport android.os.Bundle\nimport android.util.Log\nimport android.view.KeyEvent\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.FrameLayout\nimport android.widget.ImageView\nimport android.widget.LinearLayout\nimport android.widget.ProgressBar\nimport android.widget.TextView\nimport androidx.collection.ArraySet\nimport androidx.collection.arraySetOf\nimport androidx.core.content.getSystemService\nimport androidx.lifecycle.lifecycleScope\nimport com.google.android.gms.R\nimport com.google.android.gms.auth.api.identity.BeginSignInRequest\nimport com.google.android.gms.auth.api.signin.GoogleSignInAccount\nimport com.google.android.gms.auth.api.signin.GoogleSignInOptions\nimport com.google.android.gms.common.api.Status\nimport com.google.android.material.bottomsheet.BottomSheetBehavior\nimport com.google.android.material.bottomsheet.BottomSheetDialog\nimport com.google.android.material.bottomsheet.BottomSheetDialogFragment\nimport com.google.android.material.button.MaterialButton\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.Job\nimport kotlinx.coroutines.delay\nimport kotlinx.coroutines.launch\nimport kotlinx.coroutines.withContext\nimport org.microg.gms.auth.AuthConstants\nimport org.microg.gms.auth.login.LoginActivity\nimport org.microg.gms.common.AccountUtils\nimport org.microg.gms.people.PeopleManager\nimport org.microg.gms.utils.getApplicationLabel\n\nclass AssistedSignInFragment : BottomSheetDialogFragment() {\n\n    companion object {\n        const val TAG = \"AssistedSignInFragment\"\n        private const val KEY_PACKAGE_NAME = \"clientPackageName\"\n        private const val KEY_GOOGLE_SIGN_IN_OPTIONS = \"googleSignInOptions\"\n        private const val KEY_BEGIN_SIGN_IN_REQUEST = \"beginSignInRequest\"\n\n        fun newInstance(clientPackageName: String, options: GoogleSignInOptions, request: BeginSignInRequest): AssistedSignInFragment {\n            val fragment = AssistedSignInFragment()\n            val args = Bundle().apply {\n                putString(KEY_PACKAGE_NAME, clientPackageName)\n                putParcelable(KEY_GOOGLE_SIGN_IN_OPTIONS, options)\n                putParcelable(KEY_BEGIN_SIGN_IN_REQUEST, request)\n            }\n            fragment.arguments = args\n            return fragment\n        }\n    }\n\n    private lateinit var clientPackageName: String\n    private lateinit var options: GoogleSignInOptions\n    private lateinit var beginSignInRequest: BeginSignInRequest\n    private lateinit var accounts: Array<Account>\n    private lateinit var accountManager: AccountManager\n\n    private var cancelBtn: ImageView? = null\n    private var container: FrameLayout? = null\n    private var loginJob: Job? = null\n    private var isSigningIn = false\n    private var signInBack = false\n    private val authStatusList = arraySetOf<Pair<String, Boolean?>>()\n\n    private var lastChooseAccount: Account? = null\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        Log.d(TAG, \"onCreate start\")\n        clientPackageName = arguments?.getString(KEY_PACKAGE_NAME) ?: return errorResult()\n        options = arguments?.getParcelable(KEY_GOOGLE_SIGN_IN_OPTIONS) ?: return errorResult()\n        beginSignInRequest = arguments?.getParcelable(KEY_BEGIN_SIGN_IN_REQUEST) ?: return errorResult()\n        accountManager = activity?.getSystemService<AccountManager>() ?: return errorResult()\n    }\n\n    fun initView() {\n        accounts = accountManager.getAccountsByType(AuthConstants.DEFAULT_ACCOUNT_TYPE)\n        lifecycleScope.launch {\n            runCatching {\n                if (accounts.isEmpty()) {\n                    addGoogleAccount()\n                } else {\n                    filterAccountsLogin({\n                        prepareMultiSignIn(it)\n                    }, { accountName, permitted ->\n                        autoSingleSignIn(accountName, permitted)\n                    })\n                }\n            }.onFailure {\n                errorResult()\n            }\n        }\n    }\n\n    private fun addGoogleAccount() {\n        notifyCancelBtn(true)\n        container?.removeAllViews()\n        val chooseView = LayoutInflater.from(requireContext()).inflate(R.layout.assisted_signin_hint_login, null)\n        val addAccountBtn = chooseView.findViewById<TextView>(R.id.add_google_account_btn)\n        val clientAppLabel = requireContext().packageManager.getApplicationLabel(clientPackageName)\n        chooseView.findViewById<TextView>(R.id.add_account_subtitle_tv).text = String.format(\n            getString(R.string.credentials_assisted_choose_account_subtitle), clientAppLabel\n        )\n        addAccountBtn.setOnClickListener {\n            val intent = Intent(activity, LoginActivity::class.java).apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)}\n            startActivity(intent)\n        }\n        container?.addView(chooseView)\n    }\n\n    private fun autoSingleSignIn(accountName: String, permitted: Boolean = false) {\n        if (beginSignInRequest.isAutoSelectEnabled && permitted) {\n            prepareSignInLoading(accountName) { cancelLogin(true) }\n        } else {\n            prepareChooseLogin(accountName, permitted)\n        }\n    }\n\n    private suspend fun filterAccountsLogin(multiMethod: (ArraySet<Pair<String, Boolean?>>) -> Unit, loginMethod: (String, Boolean) -> Unit) {\n        accounts.forEach { account ->\n            val authStatus = try {\n                checkAccountAuthStatus(requireContext(), clientPackageName, options.scopes, account)\n            } catch (e: Exception) {\n                Log.d(TAG, \"checkAccountAuthStatus: account:${account.name} auth error \", e)\n                null\n            }\n            authStatusList.add(Pair(account.name, authStatus))\n        }\n        Log.d(TAG, \"filterAccountsLogin: authStatusList: $authStatusList\")\n        val checkAccounts = authStatusList.filter { it.second != null }\n        if (checkAccounts.size == 1) {\n            val pair = checkAccounts[0]\n            loginMethod(pair.first, pair.second!!)\n            return\n        }\n        val filterByAuthorizedAccounts = beginSignInRequest.googleIdTokenRequestOptions.filterByAuthorizedAccounts()\n        val authorizedAccounts = authStatusList.filter { it.second == true }\n        if (filterByAuthorizedAccounts && authorizedAccounts.isNotEmpty()) {\n            loginMethod(checkAccounts.first().first, true)\n            return\n        }\n        multiMethod(authStatusList)\n    }\n\n    private fun prepareMultiSignIn(authorizedAccounts: ArraySet<Pair<String, Boolean?>>) {\n        lifecycleScope.launch {\n            notifyCancelBtn(true)\n            container?.removeAllViews()\n            val chooseView = LayoutInflater.from(requireContext()).inflate(R.layout.assisted_signin_choose_layout, null)\n            val clientAppLabel = requireContext().packageManager.getApplicationLabel(clientPackageName)\n            chooseView.findViewById<TextView>(R.id.sign_multi_description).text =\n                String.format(getString(R.string.credentials_assisted_choose_account_subtitle), clientAppLabel)\n            val accountViews = chooseView.findViewById<LinearLayout>(R.id.sign_multi_account_container)\n            val progress = chooseView.findViewById<ProgressBar>(R.id.sign_multi_progress)\n            authorizedAccounts.forEachIndexed { index, pair ->\n                val accountName = pair.first\n                val accountView = LayoutInflater.from(requireContext()).inflate(R.layout.assisted_signin_multi_layout, null)\n                accountView.findViewById<TextView>(R.id.account_email).text = accountName\n                withContext(Dispatchers.IO) {\n                    PeopleManager.getDisplayName(requireContext(), accountName)\n                }.let { accountView.findViewById<TextView>(R.id.account_display_name).text = it }\n                withContext(Dispatchers.IO) {\n                    PeopleManager.getOwnerAvatarBitmap(requireContext(), accountName, false)\n                        ?: PeopleManager.getOwnerAvatarBitmap(requireContext(), accountName, true)\n                }.let { accountView.findViewById<ImageView>(R.id.account_photo).setImageBitmap(it) }\n                if (pair.second != null) {\n                    accountView.findViewById<TextView>(R.id.account_description).text =\n                        getString(R.string.credentials_assisted_signin_button_text_long)\n                    accountView.setOnClickListener {\n                        progress.visibility = View.VISIBLE\n                        prepareChooseLogin(accountName, pair.second!!)\n                    }\n                } else {\n                    accountView.findViewById<TextView>(R.id.account_description).apply {\n                        text = getString(R.string.credentials_assisted_choose_account_error_tips)\n                        setTextColor(Color.RED)\n                    }\n                    accountView.setOnClickListener(null)\n                }\n                if (index == accounts.size - 1) {\n                    accountView.findViewById<View>(R.id.multi_account_line).visibility = View.GONE\n                }\n                accountViews.addView(accountView)\n            }\n            container?.addView(chooseView)\n        }\n    }\n\n    private fun prepareSignInLoading(accountName: String, cancelBlock: (() -> Unit)? = null) {\n        lifecycleScope.launch {\n            notifyCancelBtn(false)\n            container?.removeAllViews()\n            val loadingView =\n                LayoutInflater.from(requireContext()).inflate(R.layout.assisted_signin_loading_layout, null)\n            loadingView.findViewById<TextView>(R.id.sign_account_email).text = accountName\n            withContext(Dispatchers.IO) {\n                PeopleManager.getDisplayName(requireContext(), accountName)\n            }.let { loadingView.findViewById<TextView>(R.id.sign_account_display_name).text = it }\n            withContext(Dispatchers.IO) {\n                PeopleManager.getOwnerAvatarBitmap(requireContext(), accountName, false)\n                    ?: PeopleManager.getOwnerAvatarBitmap(requireContext(), accountName, true)\n            }.let { loadingView.findViewById<ImageView>(R.id.sign_account_photo).setImageBitmap(it) }\n            if (cancelBlock != null) {\n                loadingView.findViewById<TextView>(R.id.sign_cancel).visibility = View.VISIBLE\n                loadingView.findViewById<TextView>(R.id.sign_cancel).setOnClickListener {\n                    cancelBlock()\n                }\n            }\n            container?.addView(loadingView)\n            startLogin(accountName)\n        }\n    }\n\n    private fun prepareChooseLogin(accountName: String, permitted: Boolean = false) {\n        lifecycleScope.launch {\n            notifyCancelBtn(visible = true, backToMulti = authStatusList.size > 1)\n            container?.removeAllViews()\n            val reloadView =\n                LayoutInflater.from(requireContext()).inflate(R.layout.assisted_signin_back_consent_layout, null)\n            reloadView.findViewById<TextView>(R.id.sign_account_email).text = accountName\n            withContext(Dispatchers.IO) {\n                PeopleManager.getDisplayName(requireContext(), accountName)\n            }.let { reloadView.findViewById<TextView>(R.id.sign_account_display_name).text = it }\n            withContext(Dispatchers.IO) {\n                PeopleManager.getOwnerAvatarBitmap(requireContext(), accountName, false)\n                    ?: PeopleManager.getOwnerAvatarBitmap(requireContext(), accountName, true)\n            }.let { reloadView.findViewById<ImageView>(R.id.sign_account_photo).setImageBitmap(it) }\n            withContext(Dispatchers.IO) {\n                PeopleManager.getGivenName(requireContext(), accountName)\n            }.let {\n                reloadView.findViewById<MaterialButton>(R.id.sign_reloading_back).text =\n                    if (it.isNullOrEmpty()) getString(R.string.credentials_assisted_continue) else String.format(\n                        getString(R.string.credentials_assisted_continue_as_user_button_label), it\n                    )\n            }\n            reloadView.findViewById<MaterialButton>(R.id.sign_reloading_back).setOnClickListener {\n                reloadView.findViewById<ProgressBar>(R.id.sign_reloading_progress).visibility = View.VISIBLE\n                prepareSignInLoading(accountName)\n            }\n            val clientAppLabel = requireContext().packageManager.getApplicationLabel(clientPackageName)\n            reloadView.findViewById<TextView>(R.id.sign_reloading_title).text = if (!permitted) String.format(\n                getString(R.string.credentials_assisted_signin_consent_header), clientAppLabel\n            ) else String.format(getString(R.string.credentials_assisted_sign_back_title), clientAppLabel)\n            val consentTextView = reloadView.findViewById<TextView>(R.id.sign_reloading_consent)\n            consentTextView.text =\n                String.format(getString(R.string.credentials_assisted_signin_consent), clientAppLabel)\n            consentTextView.visibility = if (!permitted) View.VISIBLE else View.GONE\n            container?.addView(reloadView)\n        }\n    }\n\n    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {\n        val dialog = super.onCreateDialog(savedInstanceState) as BottomSheetDialog\n        dialog.setOnShowListener {\n            dialog.behavior.state = BottomSheetBehavior.STATE_EXPANDED\n            dialog.behavior.skipCollapsed = true\n            dialog.setCanceledOnTouchOutside(false)\n        }\n        dialog.setOnKeyListener { _, keyCode, event ->\n            if (keyCode == KeyEvent.KEYCODE_BACK && event.action == KeyEvent.ACTION_UP) {\n                if (isSigningIn) {\n                    cancelLogin(true)\n                } else dialog.dismiss()\n                return@setOnKeyListener true\n            }\n            return@setOnKeyListener false\n        }\n        return dialog\n    }\n\n    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {\n        Log.d(TAG, \"onCreateView\")\n        return layoutInflater.inflate(R.layout.assisted_signin_google_dialog, container, false);\n    }\n\n    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {\n        super.onViewCreated(view, savedInstanceState)\n        Log.d(TAG, \"onViewCreated\")\n        cancelBtn = view.findViewById(R.id.cancel)\n        container = view.findViewById(R.id.google_sign_in_container)\n    }\n\n    override fun onDismiss(dialog: DialogInterface) {\n        if (!signInBack) {\n            cancelLogin()\n            errorResult(Status.CANCELED)\n        }\n        super.onDismiss(dialog)\n    }\n\n    private fun notifyCancelBtn(visible: Boolean, backToMulti: Boolean = false) {\n        cancelBtn?.visibility = if (visible) View.VISIBLE else View.GONE\n        cancelBtn?.isClickable = visible\n        cancelBtn?.setOnClickListener {\n            if (backToMulti) {\n                prepareMultiSignIn(authStatusList)\n                return@setOnClickListener\n            }\n            dismiss()\n        }\n    }\n\n    private fun startLogin(accountName: String) {\n        loginJob = lifecycleScope.launch {\n            lastChooseAccount = accounts.find { it.name == accountName } ?: throw RuntimeException(\"account not found\")\n            isSigningIn = true\n            delay(3000)\n            runCatching {\n                val (_, googleSignInAccount) = withContext(Dispatchers.IO) {\n                    performSignIn(requireContext(), clientPackageName, options, lastChooseAccount!!, true, beginSignInRequest.googleIdTokenRequestOptions.nonce)\n                }\n                loginResult(googleSignInAccount)\n            }.onFailure {\n                Log.d(TAG, \"startLogin: error\", it)\n                errorResult()\n            }\n        }\n    }\n\n    fun cancelLogin(showChoose: Boolean = false) {\n        Log.d(TAG, \"cancelLogin\")\n        isSigningIn = false\n        loginJob?.cancel()\n        if (showChoose && lastChooseAccount != null) {\n            prepareChooseLogin(lastChooseAccount!!.name, true)\n        }\n    }\n\n    private fun errorResult(status: Status = Status.INTERNAL_ERROR) {\n        if (activity != null && activity is AssistedSignInActivity) {\n            val assistedSignInActivity = activity as AssistedSignInActivity\n            assistedSignInActivity.errorResult(status)\n        }\n        activity?.finish()\n    }\n\n    private fun loginResult(googleSignInAccount: GoogleSignInAccount?) {\n        if (activity != null && activity is AssistedSignInActivity) {\n            signInBack = true\n            runCatching {\n                val assistedSignInActivity = activity as AssistedSignInActivity\n                AccountUtils.get(requireContext()).saveSelectedAccount(clientPackageName, googleSignInAccount?.account)\n                assistedSignInActivity.loginResult(googleSignInAccount)\n            }\n        }\n        activity?.finish()\n    }\n\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/auth/signin/AuthSignInActivity.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth.signin\n\nimport android.accounts.Account\nimport android.accounts.AccountManager\nimport android.content.Intent\nimport android.content.res.Configuration\nimport android.graphics.Bitmap\nimport android.os.Bundle\nimport android.util.Log\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.ArrayAdapter\nimport android.widget.ImageView\nimport android.widget.TextView\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.core.content.getSystemService\nimport androidx.lifecycle.lifecycleScope\nimport com.google.android.gms.R\nimport com.google.android.gms.auth.api.identity.AuthorizationResult\nimport com.google.android.gms.auth.api.identity.SignInCredential\nimport com.google.android.gms.auth.api.signin.GoogleSignInAccount\nimport com.google.android.gms.auth.api.signin.GoogleSignInApi\nimport com.google.android.gms.auth.api.signin.SignInAccount\nimport com.google.android.gms.auth.api.signin.internal.SignInConfiguration\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableSerializer\nimport com.google.android.gms.databinding.SigninConfirmBinding\nimport com.google.android.gms.databinding.SigninPickerBinding\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\nimport org.microg.gms.auth.AuthConstants\nimport org.microg.gms.auth.AuthConstants.DEFAULT_ACCOUNT\nimport org.microg.gms.auth.AuthConstants.DEFAULT_ACCOUNT_TYPE\nimport org.microg.gms.auth.login.LoginActivity\nimport org.microg.gms.people.PeopleManager\nimport org.microg.gms.utils.getApplicationLabel\n\nprivate const val TAG = \"AuthSignInActivity\"\nprivate const val REQUEST_CODE_ADD_ACCOUNT = 100\n\n/**\n * TODO: Get privacy policy / terms of service links via\n *       https://clientauthconfig.googleapis.com/google.identity.clientauthconfig.v1.ClientAuthConfig/GetDisplayBrand\n */\nclass AuthSignInActivity : AppCompatActivity() {\n    private val config: SignInConfiguration?\n        get() = runCatching {\n            intent?.extras?.also { it.classLoader = SignInConfiguration::class.java.classLoader }?.getParcelable<SignInConfiguration>(\"config\")\n        }.getOrNull()\n\n    private val idNonce: String?\n        get() = runCatching { intent?.extras?.getString(\"nonce\") }.getOrNull()\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        setResult(CommonStatusCodes.CANCELED)\n\n        Log.d(TAG, \"Request: $config\")\n\n        val packageName = config?.packageName\n        if (packageName == null || (packageName != callingActivity?.packageName && callingActivity?.packageName != this.packageName))\n            return finishResult(CommonStatusCodes.DEVELOPER_ERROR, \"package name mismatch\")\n\n        initView(packageName)\n    }\n\n    private fun initView(packageName: String) {\n        val accountManager = getSystemService<AccountManager>() ?: return finishResult(CommonStatusCodes.INTERNAL_ERROR, \"No account manager\")\n        val accounts = accountManager.getAccountsByType(DEFAULT_ACCOUNT_TYPE)\n        if (accounts.isNotEmpty()) {\n            val account = config?.options?.account\n            if (account != null) {\n                if (account in accounts) {\n                    showSignInConfirm(packageName, account)\n                } else {\n                    finishResult(CommonStatusCodes.INVALID_ACCOUNT)\n                }\n            } else {\n                openAccountPicker(packageName)\n            }\n        } else {\n            openAddAccount()\n        }\n    }\n\n    private fun openAddAccount() {\n        startActivityForResult(Intent(this, LoginActivity::class.java), REQUEST_CODE_ADD_ACCOUNT)\n    }\n\n    private fun bindAccountRow(root: View, account: Account, updateAction: (ImageView, Bitmap) -> Unit) {\n        val photoView = root.findViewById<ImageView>(R.id.account_photo)\n        val displayNameView = root.findViewById<TextView>(R.id.account_display_name)\n        val emailView = root.findViewById<TextView>(R.id.account_email)\n        if (account.name != DEFAULT_ACCOUNT) {\n            val photo = PeopleManager.getOwnerAvatarBitmap(this@AuthSignInActivity, account.name, false)\n            if (photo == null) {\n                lifecycleScope.launchWhenStarted {\n                    withContext(Dispatchers.IO) {\n                        PeopleManager.getOwnerAvatarBitmap(this@AuthSignInActivity, account.name, true)\n                    }?.let {\n                        updateAction(photoView, it)\n                    }\n                }\n            }\n            val displayName = PeopleManager.getDisplayName(this@AuthSignInActivity, account.name)\n            photoView.setImageBitmap(photo)\n            if (displayName != null) {\n                displayNameView.text = displayName\n                emailView.text = account.name\n                emailView.visibility = View.VISIBLE\n            } else {\n                displayNameView.text = account.name\n                emailView.visibility = View.GONE\n            }\n        } else {\n            photoView.setImageResource(R.drawable.ic_add_account_alt)\n            displayNameView.setText(R.string.signin_picker_add_account_label)\n            emailView.visibility = View.GONE\n        }\n    }\n\n    private fun openAccountPicker(packageName: String) {\n        val binding = SigninPickerBinding.inflate(layoutInflater)\n        binding.appName = packageManager.getApplicationLabel(packageName).toString()\n        binding.appIcon = packageManager.getApplicationIcon(packageName)\n        val accounts = getSystemService<AccountManager>()!!.getAccountsByType(DEFAULT_ACCOUNT_TYPE) + Account(DEFAULT_ACCOUNT, DEFAULT_ACCOUNT_TYPE)\n        binding.pickerList.adapter = object : ArrayAdapter<Account>(this, 0, accounts) {\n            override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {\n                val v = convertView ?: layoutInflater.inflate(R.layout.signin_account_row, parent, false)\n                getItem(position)?.let { bindAccountRow(v, it) { _, _ -> notifyDataSetChanged() } }\n                return v\n            }\n        }\n        binding.pickerList.setOnItemClickListener { parent, view, position, id ->\n            binding.listProgressSpinner = true\n            if (accounts[position].name == DEFAULT_ACCOUNT) {\n                openAddAccount()\n            } else {\n                lifecycleScope.launchWhenStarted {\n                    try {\n                        signIn(accounts[position])\n                    } catch (e: Exception) {\n                        Log.w(TAG, e)\n                        finishResult(CommonStatusCodes.INTERNAL_ERROR)\n                    }\n                }\n            }\n        }\n        setContentView(binding.root)\n    }\n\n    private fun showSignInConfirm(packageName: String, account: Account) {\n        val binding = SigninConfirmBinding.inflate(layoutInflater)\n        binding.appName = packageManager.getApplicationLabel(packageName).toString()\n        binding.appIcon = packageManager.getApplicationIcon(packageName)\n        bindAccountRow(binding.root, account) { view, bitmap -> view.setImageBitmap(bitmap) }\n        binding.button2.setOnClickListener {\n            finishResult(CommonStatusCodes.CANCELED)\n        }\n        binding.button1.setOnClickListener {\n            binding.button1.isEnabled = false\n            binding.button2.isEnabled = false\n            lifecycleScope.launchWhenStarted {\n                try {\n                    signIn(account)\n                } catch (e: Exception) {\n                    Log.w(TAG, e)\n                    finishResult(CommonStatusCodes.INTERNAL_ERROR)\n                }\n            }\n        }\n        setContentView(binding.root)\n    }\n\n    private suspend fun signIn(account: Account) {\n        val (_, googleSignInAccount) = performSignIn(this, config?.packageName!!, config?.options, account, true, idNonce)\n        if (googleSignInAccount != null) {\n            finishResult(CommonStatusCodes.SUCCESS, account = account, googleSignInAccount = googleSignInAccount)\n        } else {\n            finishResult(CommonStatusCodes.INTERNAL_ERROR, \"Sign in failed\")\n        }\n    }\n\n    private fun finishResult(statusCode: Int, message: String? = null, account: Account? = null, googleSignInAccount: GoogleSignInAccount? = null) {\n        val data = Intent()\n        if (statusCode != CommonStatusCodes.SUCCESS) data.putExtra(AuthConstants.ERROR_CODE, statusCode)\n        data.putExtra(AuthConstants.GOOGLE_SIGN_IN_STATUS, Status(statusCode, message))\n        data.putExtra(AuthConstants.GOOGLE_SIGN_IN_ACCOUNT, googleSignInAccount)\n        val bundle = Bundle()\n        if (googleSignInAccount != null) {\n            val authorizationResult = AuthorizationResult(\n                googleSignInAccount.serverAuthCode,\n                googleSignInAccount.idToken,\n                googleSignInAccount.idToken,\n                googleSignInAccount.grantedScopes.map { it.scopeUri },\n                googleSignInAccount,\n                null\n            )\n            data.putExtra(AuthConstants.GOOGLE_SIGN_IN_AUTHORIZATION_RESULT, SafeParcelableSerializer.serializeToBytes(authorizationResult))\n            val signInAccount = SignInAccount().apply {\n                email = googleSignInAccount.email ?: account?.name\n                this.googleSignInAccount = googleSignInAccount\n                userId = googleSignInAccount.id ?: getSystemService<AccountManager>()?.getUserData(\n                    account,\n                    AuthConstants.GOOGLE_USER_ID\n                )\n            }\n            data.putExtra(GoogleSignInApi.EXTRA_SIGN_IN_ACCOUNT, signInAccount)\n            val credential = SignInCredential(\n                googleSignInAccount.email,\n                googleSignInAccount.displayName,\n                googleSignInAccount.familyName,\n                googleSignInAccount.givenName,\n                null, null,\n                googleSignInAccount.idToken,\n                null, null\n            )\n            val credentialToBytes = SafeParcelableSerializer.serializeToBytes(credential)\n            bundle.putByteArray(AuthConstants.SIGN_IN_CREDENTIAL, credentialToBytes)\n            bundle.putByteArray(AuthConstants.STATUS, SafeParcelableSerializer.serializeToBytes(Status.SUCCESS))\n        } else {\n            bundle.putByteArray(AuthConstants.STATUS, SafeParcelableSerializer.serializeToBytes(Status.CANCELED))\n        }\n        data.putExtras(bundle)\n        Log.d(TAG, \"Result: ${data.extras?.also { it.keySet() }}\")\n        setResult(RESULT_OK, data)\n        finish()\n    }\n\n    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {\n        super.onActivityResult(requestCode, resultCode, data)\n        if (requestCode == REQUEST_CODE_ADD_ACCOUNT) {\n            val accountManager = getSystemService<AccountManager>() ?: return finish()\n            val accounts = accountManager.getAccountsByType(DEFAULT_ACCOUNT_TYPE)\n            if (accounts.isNotEmpty()) {\n                openAccountPicker(config?.packageName!!)\n            } else {\n                finishResult(CommonStatusCodes.CANCELED, \"No account and creation cancelled\")\n            }\n        }\n    }\n\n    override fun onConfigurationChanged(newConfig: Configuration) {\n        super.onConfigurationChanged(newConfig)\n        config?.packageName?.let { initView(it) }\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/auth/signin/AuthSignInService.kt",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 */\npackage org.microg.gms.auth.signin\n\nimport android.accounts.Account\nimport android.content.Context\nimport android.os.Bundle\nimport android.os.Parcel\nimport android.util.Log\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.LifecycleOwner\nimport androidx.lifecycle.lifecycleScope\nimport com.android.volley.toolbox.JsonObjectRequest\nimport com.android.volley.toolbox.Volley\nimport com.google.android.gms.auth.api.signin.GoogleSignInAccount\nimport com.google.android.gms.auth.api.signin.GoogleSignInOptions\nimport com.google.android.gms.auth.api.signin.internal.ISignInCallbacks\nimport com.google.android.gms.auth.api.signin.internal.ISignInService\nimport com.google.android.gms.common.Feature\nimport com.google.android.gms.common.Scopes\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.api.Scope\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.internal.ConnectionInfo\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport org.microg.gms.BaseService\nimport org.microg.gms.auth.AuthPrefs\nimport org.microg.gms.common.AccountUtils\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.common.PackageUtils\nimport org.microg.gms.games.GAMES_PACKAGE_NAME\nimport org.microg.gms.games.GamesConfigurationService\nimport org.microg.gms.utils.singleInstanceOf\nimport org.microg.gms.utils.warnOnTransactionIssues\nimport kotlin.coroutines.resume\nimport kotlin.coroutines.resumeWithException\nimport kotlin.coroutines.suspendCoroutine\n\nprivate const val TAG = \"AuthSignInService\"\n\nclass AuthSignInService : BaseService(TAG, GmsService.AUTH_GOOGLE_SIGN_IN) {\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        val packageName = PackageUtils.getAndCheckCallingPackage(this, request.packageName)\n            ?: throw IllegalArgumentException(\"Missing package name\")\n        val binder = AuthSignInServiceImpl(this, lifecycle, packageName, request.account, request.scopes.asList(), request.extras).asBinder()\n        callback.onPostInitCompleteWithConnectionInfo(CommonStatusCodes.SUCCESS, binder, ConnectionInfo().apply {\n            features = arrayOf(Feature(\"user_service_account_management\", 1))\n        })\n    }\n}\n\nclass AuthSignInServiceImpl(\n    private val context: Context,\n    override val lifecycle: Lifecycle,\n    private val packageName: String,\n    private val account: Account?,\n    private val scopes: List<Scope>,\n    private val extras: Bundle\n) : ISignInService.Stub(), LifecycleOwner {\n    private val queue = singleInstanceOf { Volley.newRequestQueue(context.applicationContext) }\n\n    override fun silentSignIn(callbacks: ISignInCallbacks, options: GoogleSignInOptions?) {\n        Log.d(TAG, \"$packageName:silentSignIn($options)\")\n        fun sendResult(account: GoogleSignInAccount?, status: Status) {\n            Log.d(TAG, \"Result[$status]: $account\")\n            runCatching { callbacks.onSignIn(account, status) }\n        }\n        lifecycleScope.launchWhenStarted {\n            try {\n                var currentAccount = account ?: options?.account\n                if (options?.scopes?.any { it.scopeUri.contains(Scopes.GAMES) } == true) {\n                    currentAccount = currentAccount ?: GamesConfigurationService.getDefaultAccount(context, packageName)\n                    if (currentAccount == null && GamesConfigurationService.loadPlayedGames(context)?.any { it == packageName } == false) {\n                        currentAccount = GamesConfigurationService.getDefaultAccount(context, GAMES_PACKAGE_NAME)\n                    }\n                    if (currentAccount == null) {\n                        sendResult(null, Status(CommonStatusCodes.SIGN_IN_REQUIRED))\n                        return@launchWhenStarted\n                    }\n                }\n                val account = currentAccount ?: SignInConfigurationService.getDefaultAccount(context, packageName)\n                Log.d(TAG, \"silentSignIn: account -> ${account?.name}\")\n                if (account != null && options?.isForceCodeForRefreshToken != true) {\n                    if (getOAuthManager(context, packageName, options, account).isPermitted || AuthPrefs.isTrustGooglePermitted(context)) {\n                        val (_, googleSignInAccount) = performSignIn(context, packageName, options, account)\n                        if (googleSignInAccount != null) {\n                            sendResult(googleSignInAccount, Status(CommonStatusCodes.SUCCESS))\n                        } else {\n                            sendResult(null, Status(CommonStatusCodes.DEVELOPER_ERROR))\n                        }\n                    } else {\n                        sendResult(null, Status(CommonStatusCodes.SIGN_IN_REQUIRED))\n                    }\n                } else {\n                    sendResult(null, Status(CommonStatusCodes.SIGN_IN_REQUIRED))\n                }\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n                sendResult(null, Status.INTERNAL_ERROR)\n            }\n        }\n    }\n\n    override fun signOut(callbacks: ISignInCallbacks, options: GoogleSignInOptions?) {\n        Log.d(TAG, \"$packageName:signOut($options)\")\n        lifecycleScope.launchWhenStarted {\n            try {\n                val account = account ?: options?.account ?: SignInConfigurationService.getDefaultAccount(context, packageName)\n                if (account != null) {\n                    SignInConfigurationService.getAuthOptions(context, packageName).forEach {\n                        Log.d(TAG, \"$packageName:signOut authOption:($it)\")\n                        performSignOut(context, packageName, it, account)\n                    }\n                }\n                if (options?.scopes?.any { it.scopeUri.contains(Scopes.GAMES) } == true) {\n                    GamesConfigurationService.setDefaultAccount(context, packageName, null)\n                }\n                AccountUtils.get(context).removeSelectedAccount(packageName)\n                SignInConfigurationService.setAuthInfo(context, packageName, null, null)\n                runCatching { callbacks.onSignOut(Status.SUCCESS) }\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n                runCatching { callbacks.onSignIn(null, Status.INTERNAL_ERROR) }\n            }\n        }\n    }\n\n    override fun revokeAccess(callbacks: ISignInCallbacks, options: GoogleSignInOptions?) {\n        Log.d(TAG, \"$packageName:revokeAccess($options)\")\n        lifecycleScope.launchWhenStarted {\n            val account = account ?: options?.account ?: SignInConfigurationService.getDefaultAccount(context, packageName)\n            if (account != null) {\n                try {\n                    val authManager = getOAuthManager(context, packageName, options, account)\n                    val token = authManager.peekAuthToken()\n                    if (token != null) {\n                        suspendCoroutine { continuation ->\n                            queue.add(object : JsonObjectRequest(\n                                \"https://accounts.google.com/o/oauth2/revoke?token=$token\",\n                                { continuation.resume(it) },\n                                { continuation.resumeWithException(it) }) {\n                                override fun getHeaders(): MutableMap<String, String> {\n                                    return hashMapOf(\n                                        \"Authorization\" to \"OAuth $token\"\n                                    )\n                                }\n                            })\n                        }\n                        authManager.invalidateAuthToken(token)\n                        authManager.isPermitted = false\n                    }\n                    SignInConfigurationService.setAuthInfo(context, packageName, account, options?.toJson())\n                    runCatching { callbacks.onRevokeAccess(Status.SUCCESS) }\n                } catch (e: Exception) {\n                    Log.w(TAG, e)\n                    runCatching { callbacks.onRevokeAccess(Status.INTERNAL_ERROR) }\n                }\n            } else {\n                runCatching { callbacks.onRevokeAccess(Status.SUCCESS) }\n            }\n        }\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =\n        warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/auth/signin/SignInConfigurationService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth.signin\n\nimport android.accounts.Account\nimport android.accounts.AccountManager\nimport android.app.Service\nimport android.content.*\nimport android.os.*\nimport androidx.core.content.getSystemService\nimport androidx.core.os.bundleOf\nimport com.google.android.gms.auth.api.signin.GoogleSignInOptions\nimport org.microg.gms.auth.AuthConstants\nimport org.microg.gms.common.PackageUtils\nimport kotlin.coroutines.resume\nimport kotlin.coroutines.resumeWithException\nimport kotlin.coroutines.suspendCoroutine\n\nprivate const val PREFERENCES_NAME = \"google_account_cache\"\nprivate const val DEFAULT_ACCOUNT_PREFIX = \"default_google_account_\"\nprivate const val DEFAULT_SIGN_IN_OPTIONS_PREFIX = \"default_sign_in_options_\"\n\nprivate const val MSG_GET_DEFAULT_ACCOUNT = 1\nprivate const val MSG_SET_DEFAULT_SIGN_IN_INFO = 2\nprivate const val MSG_GET_DEFAULT_OPTIONS = 3\n\nprivate const val MSG_DATA_PACKAGE_NAME = \"package_name\"\nprivate const val MSG_DATA_ACCOUNT = \"account\"\nprivate const val MSG_DATA_SIGN_IN_OPTIONS = \"google_sign_in_options\"\n\nclass SignInConfigurationService : Service() {\n    private val preferences: SharedPreferences\n        get() = getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE)\n    private val accountManager: AccountManager\n        get() = getSystemService<AccountManager>()!!\n\n    override fun onBind(intent: Intent?): IBinder {\n        return Messenger(object : Handler(Looper.getMainLooper()) {\n            override fun handleMessage(msg: Message) {\n                val data = when (msg.what) {\n                    MSG_GET_DEFAULT_ACCOUNT -> {\n                        val packageName = msg.data?.getString(MSG_DATA_PACKAGE_NAME)\n                        val account = packageName?.let { getDefaultAccount(it) }\n                        bundleOf(\n                            MSG_DATA_PACKAGE_NAME to packageName,\n                            MSG_DATA_ACCOUNT to account\n                        )\n                    }\n\n                    MSG_SET_DEFAULT_SIGN_IN_INFO -> {\n                        val packageName = msg.data?.getString(MSG_DATA_PACKAGE_NAME)\n                        val account = msg.data?.getParcelable<Account>(MSG_DATA_ACCOUNT)\n                        val googleSignInOptions = msg.data?.getString(MSG_DATA_SIGN_IN_OPTIONS)\n                        packageName?.let { setAuthInfo(it, account, googleSignInOptions) }\n                        bundleOf(\n                            MSG_DATA_PACKAGE_NAME to packageName,\n                            MSG_DATA_ACCOUNT to account,\n                            MSG_DATA_SIGN_IN_OPTIONS to googleSignInOptions,\n                        )\n                    }\n\n                    MSG_GET_DEFAULT_OPTIONS -> {\n                        val packageName = msg.data?.getString(MSG_DATA_PACKAGE_NAME)\n                        val googleSignInOptions = packageName?.let { getAuthOptions(it) }\n                        bundleOf(\n                            MSG_DATA_PACKAGE_NAME to packageName,\n                            MSG_DATA_SIGN_IN_OPTIONS to googleSignInOptions?.toTypedArray()\n                        )\n                    }\n\n                    else -> Bundle.EMPTY\n                }\n                msg.replyTo?.send(Message.obtain().also {\n                    it.what = msg.what\n                    it.data = data\n                })\n            }\n        }).binder\n    }\n\n    private fun getPackageNameSuffix(packageName: String): String {\n        return packageName + \":\" + PackageUtils.firstSignatureDigest(this, packageName)\n    }\n\n    private fun getDefaultAccount(packageName: String): Account? {\n        val name = preferences.getString(DEFAULT_ACCOUNT_PREFIX + getPackageNameSuffix(packageName), null)\n        if (name.isNullOrBlank()) return null\n        val accounts: Array<Account> = accountManager.getAccountsByType(AuthConstants.DEFAULT_ACCOUNT_TYPE)\n        for (account in accounts) {\n            if (account.name.equals(name)) return account\n        }\n        return null\n    }\n\n    private fun getAuthOptions(packageName: String): Set<String>? {\n        val data = preferences.getStringSet(DEFAULT_SIGN_IN_OPTIONS_PREFIX + getPackageNameSuffix(packageName), null)\n        if (data.isNullOrEmpty()) return null\n        return data\n    }\n\n    private fun setAuthInfo(packageName: String, account: Account?, optionsJson: String?) {\n        val editor: SharedPreferences.Editor = preferences.edit()\n        val accountPrefix = DEFAULT_ACCOUNT_PREFIX + getPackageNameSuffix(packageName)\n        val optionsPrefix = DEFAULT_SIGN_IN_OPTIONS_PREFIX + getPackageNameSuffix(packageName)\n        if (account == null || account.name == AuthConstants.DEFAULT_ACCOUNT) {\n            editor.remove(accountPrefix)\n            editor.remove(optionsPrefix)\n        } else {\n            editor.putString(accountPrefix, account.name)\n        }\n        if (optionsJson != null) {\n            val oldOptions = runCatching { preferences.getString(optionsPrefix, null) }.getOrNull()\n            if (oldOptions != null) {\n                editor.putStringSet(optionsPrefix, setOf(oldOptions, optionsJson))\n            } else {\n                val savedOptions = preferences.getStringSet(optionsPrefix, emptySet()) ?: emptySet()\n                val newSet = HashSet(savedOptions)\n                newSet.add(optionsJson)\n                editor.putStringSet(optionsPrefix, newSet)\n            }\n        }\n        editor.apply()\n    }\n\n    companion object {\n\n        private suspend fun singleRequest(context: Context, message: Message) = suspendCoroutine { continuation ->\n            val connection = object : ServiceConnection {\n                override fun onServiceConnected(name: ComponentName?, service: IBinder?) {\n                    val connection = this\n                    message.replyTo = Messenger(object : Handler(Looper.myLooper() ?: Looper.getMainLooper()) {\n                        override fun handleMessage(msg: Message) {\n                            runCatching { continuation.resume(msg) }\n                            runCatching { context.unbindService(connection) }\n                        }\n                    })\n                    try {\n                        Messenger(service).send(message)\n                    } catch (e: Exception) {\n                        runCatching { continuation.resumeWithException(e) }\n                        runCatching { context.unbindService(connection) }\n                    }\n                }\n\n                override fun onServiceDisconnected(name: ComponentName?) {\n                    runCatching { continuation.resumeWithException(RuntimeException(\"Disconnected\")) }\n                }\n            }\n            val connected = context.bindService(Intent(context, SignInConfigurationService::class.java), connection, BIND_AUTO_CREATE or BIND_ABOVE_CLIENT)\n            if (!connected) {\n                runCatching { continuation.resumeWithException(RuntimeException(\"Connection failed\")) }\n                runCatching { context.unbindService(connection) }\n            }\n        }\n\n        suspend fun getDefaultAccount(context: Context, packageName: String): Account? {\n            return singleRequest(context, Message.obtain().apply {\n                what = MSG_GET_DEFAULT_ACCOUNT\n                data = bundleOf(\n                    MSG_DATA_PACKAGE_NAME to packageName\n                )\n            }).data?.getParcelable(MSG_DATA_ACCOUNT)\n        }\n\n        suspend fun getAuthOptions(context: Context, packageName: String): Set<GoogleSignInOptions> {\n            return singleRequest(context, Message.obtain().apply {\n                what = MSG_GET_DEFAULT_OPTIONS\n                data = bundleOf(\n                    MSG_DATA_PACKAGE_NAME to packageName\n                )\n            }).data?.getStringArray(MSG_DATA_SIGN_IN_OPTIONS)?.map { GoogleSignInOptions.fromJson(it) }?.toSet() ?: emptySet()\n        }\n\n        suspend fun setAuthInfo(context: Context, packageName: String, account: Account?, optionsJson: String?) {\n            singleRequest(context, Message.obtain().apply {\n                what = MSG_SET_DEFAULT_SIGN_IN_INFO\n                data = bundleOf(\n                    MSG_DATA_PACKAGE_NAME to packageName,\n                    MSG_DATA_ACCOUNT to account,\n                    MSG_DATA_SIGN_IN_OPTIONS to optionsJson\n                )\n            })\n        }\n\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/auth/signin/extensions.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.auth.signin\n\nimport android.accounts.Account\nimport android.content.Context\nimport android.content.Intent\nimport android.net.Uri\nimport android.os.Handler\nimport android.os.Looper\nimport android.os.Message\nimport android.os.Messenger\nimport android.util.Base64\nimport android.util.Log\nimport com.google.android.gms.auth.api.signin.GoogleSignInAccount\nimport com.google.android.gms.auth.api.signin.GoogleSignInOptions\nimport com.google.android.gms.common.Scopes\nimport com.google.android.gms.common.api.Scope\nimport kotlinx.coroutines.CompletableDeferred\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\nimport org.microg.gms.auth.AuthManager\nimport org.microg.gms.auth.ConsentCookiesResponse\nimport org.microg.gms.auth.ConsentUrlResponse\nimport org.microg.gms.auth.NonceWrapper\nimport org.microg.gms.auth.RequestOptions\nimport org.microg.gms.auth.consent.CONSENT_KEY_COOKIE\nimport org.microg.gms.auth.consent.CONSENT_MESSENGER\nimport org.microg.gms.auth.consent.CONSENT_RESULT\nimport org.microg.gms.auth.consent.CONSENT_URL\nimport org.microg.gms.auth.consent.ConsentSignInActivity\nimport org.microg.gms.games.GamesConfigurationService\nimport org.microg.gms.people.DatabaseHelper\nimport org.microg.gms.utils.toHexString\nimport java.security.MessageDigest\nimport java.security.SecureRandom\nimport kotlin.math.min\n\nprivate const val TAG = \"AuthSignInExtensions\"\n\nprivate val ACCEPTABLE_SCOPES = setOf(Scopes.OPENID, Scopes.EMAIL, Scopes.PROFILE, Scopes.USERINFO_EMAIL, Scopes.USERINFO_PROFILE, Scopes.GAMES_LITE)\n\nprivate fun Long?.orMaxIfNegative() = this?.takeIf { it >= 0L } ?: Long.MAX_VALUE\n\nval GoogleSignInOptions.scopeUris\n    get() = scopes.orEmpty().sortedBy { it.scopeUri }\n\nval GoogleSignInOptions.includeId\n    get() = scopeUris.any { it.scopeUri == Scopes.OPENID } || scopeUris.any { it.scopeUri == Scopes.GAMES_LITE }\n\nval GoogleSignInOptions.includeEmail\n    get() = scopeUris.any { it.scopeUri == Scopes.EMAIL } || scopeUris.any { it.scopeUri == Scopes.GAMES_LITE }\n\nval GoogleSignInOptions.includeProfile\n    get() = scopeUris.any { it.scopeUri == Scopes.PROFILE }\n\nval GoogleSignInOptions.includeUnacceptableScope\n    get() = scopeUris.any { it.scopeUri !in ACCEPTABLE_SCOPES }\n\nval GoogleSignInOptions.includeGame\n    get() = scopeUris.any { it.scopeUri.contains(Scopes.GAMES) }\n\nval consentRequestOptions: String?\n    get() = runCatching {\n        val sessionId = Base64.encodeToString(ByteArray(16).also { SecureRandom().nextBytes(it) }, Base64.NO_WRAP).trim()\n        val requestOptions = RequestOptions().newBuilder().remote(1).version(3).sessionId(sessionId).build()\n        Base64.encodeToString(requestOptions.encode(), Base64.DEFAULT)\n    }.getOrNull()\n\nfun getOAuthManager(context: Context, packageName: String, options: GoogleSignInOptions?, account: Account): AuthManager {\n    val scopes = options?.scopes.orEmpty().sortedBy { it.scopeUri }\n    return AuthManager(context, account.name, packageName, \"oauth2:${scopes.joinToString(\" \")}\")\n}\n\nfun getCookiesManager(context: Context, packageName: String, account: Account): AuthManager {\n    return AuthManager(context, account.name, packageName, \"weblogin:url=https://accounts.google.com\")\n}\n\nfun getIdTokenManager(context: Context, packageName: String, options: GoogleSignInOptions?, account: Account): AuthManager? {\n    if (options?.isIdTokenRequested != true || options.serverClientId == null) return null\n\n    val idTokenManager = AuthManager(context, account.name, packageName, \"audience:server:client_id:${options.serverClientId}\")\n    idTokenManager.includeEmail = if (options.includeEmail) \"1\" else \"0\"\n    idTokenManager.includeProfile = if (options.includeProfile) \"1\" else \"0\"\n    return idTokenManager\n}\n\nfun getServerAuthTokenManager(context: Context, packageName: String, options: GoogleSignInOptions?, account: Account): AuthManager? {\n    if (options?.isServerAuthCodeRequested != true || options.serverClientId == null) return null\n\n    val serverAuthTokenManager = AuthManager(context, account.name, packageName, \"oauth2:server:client_id:${options.serverClientId}:api_scope:${options.scopeUris.joinToString(\" \")}\")\n    serverAuthTokenManager.includeEmail = if (options.includeEmail) \"1\" else \"0\"\n    serverAuthTokenManager.includeProfile = if (options.includeProfile) \"1\" else \"0\"\n    serverAuthTokenManager.forceRefreshToken = options.isForceCodeForRefreshToken\n    serverAuthTokenManager.setOauth2Prompt(\"auto\")\n    serverAuthTokenManager.setItCaveatTypes(\"2\")\n    return serverAuthTokenManager\n}\n\nsuspend fun checkAccountAuthStatus(context: Context, packageName: String, scopeList: List<Scope>?, account: Account): Boolean {\n    val scopes = scopeList.orEmpty().sortedBy { it.scopeUri }\n    val authManager = AuthManager(context, account.name, packageName, \"oauth2:${scopes.joinToString(\" \")}\")\n    authManager.ignoreStoredPermission = true\n    return withContext(Dispatchers.IO) { authManager.requestAuth(true) }.auth != null\n}\n\nsuspend fun performSignIn(context: Context, packageName: String, options: GoogleSignInOptions?, account: Account, permitted: Boolean = false, idNonce: String? = null): Pair<String?, GoogleSignInAccount?> {\n    val authManager = getOAuthManager(context, packageName, options, account)\n    val authResponse = withContext(Dispatchers.IO) {\n        if (options?.includeUnacceptableScope == true || !permitted) {\n            authManager.setTokenRequestOptions(consentRequestOptions)\n        }\n        if (permitted) authManager.isPermitted = true\n        authManager.requestAuth(true)\n    }\n    var consentResult:String ?= null\n    if (\"remote_consent\" == authResponse.issueAdvice && authResponse.resolutionDataBase64 != null){\n        consentResult = performConsentView(context, packageName, account, authResponse.resolutionDataBase64)\n        if (consentResult == null) return Pair(null, null)\n    } else {\n        if (authResponse.auth == null) return Pair(null, null)\n    }\n    Log.d(TAG, \"id token requested: ${options?.isIdTokenRequested == true}, serverClientId = ${options?.serverClientId}, permitted = ${authManager.isPermitted}\")\n    val idTokenResponse = getIdTokenManager(context, packageName, options, account)?.let {\n        if (idNonce != null) {\n            it.setTokenRequestOptions(Base64.encodeToString(RequestOptions.build {\n                remote = 1\n                version = 6\n                nonceWrapper = NonceWrapper.build { nonce = idNonce }\n            }.encode(), Base64.DEFAULT))\n        }\n        it.isPermitted = authResponse.auth != null\n        consentResult?.let { result -> it.putDynamicFiled(CONSENT_RESULT, result) }\n        withContext(Dispatchers.IO) { it.requestAuth(true) }\n    }\n    val serverAuthTokenResponse = getServerAuthTokenManager(context, packageName, options, account)?.let {\n        it.isPermitted = authResponse.auth != null\n        consentResult?.let { result -> it.putDynamicFiled(CONSENT_RESULT, result) }\n        withContext(Dispatchers.IO) { it.requestAuth(true) }\n    }\n    val googleUserId = authManager.getUserData(\"GoogleUserId\")\n    val id = if (options?.includeId == true) googleUserId else null\n    val tokenId = if (options?.isIdTokenRequested == true) idTokenResponse?.auth else null\n    val serverAuthCode: String? = if (options?.isServerAuthCodeRequested == true) serverAuthTokenResponse?.auth else null\n    val expirationTime = min(authResponse.expiry.orMaxIfNegative(), idTokenResponse?.expiry.orMaxIfNegative())\n    val obfuscatedIdentifier: String = MessageDigest.getInstance(\"MD5\").digest(\"$googleUserId:$packageName\".encodeToByteArray()).toHexString().uppercase()\n    val grantedScopeList = authResponse.grantedScopes ?: idTokenResponse?.grantedScopes ?: serverAuthTokenResponse?.grantedScopes\n    val grantedScopes = grantedScopeList?.split(\" \")?.map { Scope(it) }?.toSet() ?: options?.scopeUris?.toSet() ?: emptySet()\n    val (givenName, familyName, displayName, photoUrl) = if (options?.includeProfile == true) {\n        val databaseHelper = DatabaseHelper(context)\n        val cursor = databaseHelper.getOwner(account.name)\n        try {\n            if (cursor.moveToNext()) {\n                listOf(\n                    cursor.getColumnIndex(\"given_name\").takeIf { it >= 0 }?.let { cursor.getString(it) },\n                    cursor.getColumnIndex(\"family_name\").takeIf { it >= 0 }?.let { cursor.getString(it) },\n                    cursor.getColumnIndex(\"display_name\").takeIf { it >= 0 }?.let { cursor.getString(it) },\n                    cursor.getColumnIndex(\"avatar\").takeIf { it >= 0 }?.let { cursor.getString(it) },\n                )\n            } else listOf(null, null, null, null)\n        } finally {\n            cursor.close()\n            databaseHelper.close()\n        }\n    } else listOf(null, null, null, null)\n    if (options?.includeGame == true) {\n        GamesConfigurationService.setDefaultAccount(context, packageName, account)\n    }\n    SignInConfigurationService.setAuthInfo(context, packageName, account, options?.toJson())\n    val googleSignInAccount = GoogleSignInAccount(\n        id,\n        tokenId,\n        account.name,\n        displayName,\n        photoUrl?.let { Uri.parse(it) },\n        serverAuthCode,\n        expirationTime,\n        obfuscatedIdentifier,\n        grantedScopes,\n        givenName,\n        familyName\n    )\n    return Pair(authResponse.auth, googleSignInAccount)\n}\n\nsuspend fun performConsentView(context: Context, packageName: String, account: Account, dataBase64: String): String? {\n    Log.d(TAG, \"performConsentView: $dataBase64\")\n    val consentResponse = ConsentUrlResponse.ADAPTER.decode(Base64.decode(dataBase64, Base64.URL_SAFE))\n    Log.d(TAG, \"performConsentView: consentResponse -> $consentResponse \")\n    val response = getCookiesManager(context, packageName, account).let {\n        it.isGmsApp = true\n        withContext(Dispatchers.IO) { it.requestAuth(true) }\n    }\n    val cookiesAuth = response.auth ?: return null\n    val cookiesResponse = ConsentCookiesResponse.ADAPTER.decode(Base64.decode(cookiesAuth, Base64.URL_SAFE))\n    val cookies = arrayListOf(consentResponse.cookie).apply {\n        cookiesResponse.consentCookies?.cookies?.filter { \".google.com\" == it.domain || \"accounts.google.com\" == it.path }?.forEach { add(it) }\n    }\n    return withContext(Dispatchers.IO) {\n        val deferred = CompletableDeferred<String?>()\n        val intent = Intent(context, ConsentSignInActivity::class.java).apply {\n            flags = Intent.FLAG_ACTIVITY_NEW_TASK\n            putExtra(CONSENT_URL, consentResponse.consentUrl)\n            putExtra(CONSENT_MESSENGER, Messenger(object : Handler(Looper.getMainLooper()) {\n                override fun handleMessage(msg: Message) {\n                    val content = msg.data.getString(CONSENT_RESULT)\n                    Log.d(TAG, \"performConsentView: ConsentSignInActivity deferred content: $content\")\n                    deferred.complete(content)\n                }\n            }))\n            cookies.forEachIndexed { index, cookie ->\n                putExtra(CONSENT_KEY_COOKIE + index, \"${cookie?.cookieName}=${cookie?.cookieValue};\")\n            }\n        }\n        Log.d(TAG, \"performConsentView: start ConsentSignInActivity\")\n        withContext(Dispatchers.Main) { context.startActivity(intent) }\n        deferred.await()\n    }\n}\n\nfun performSignOut(context: Context, packageName: String, options: GoogleSignInOptions?, account: Account) {\n    val authManager = getOAuthManager(context, packageName, options, account)\n    authManager.isPermitted = false\n    authManager.invalidateAuthToken()\n\n    getIdTokenManager(context, packageName, options, account)?.let {\n        it.isPermitted = false\n        it.invalidateAuthToken()\n    }\n    getServerAuthTokenManager(context, packageName, options, account)?.let {\n        it.isPermitted = false\n        it.invalidateAuthToken()\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/backup/BackupSettingsActivity.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage org.microg.gms.backup\n\nimport android.app.Activity\nimport android.os.Bundle\nimport android.widget.Toast\nimport com.google.android.gms.R\n\nclass BackupSettingsActivity : Activity() {\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        Toast.makeText(this, getString(R.string.backup_disabled), Toast.LENGTH_SHORT).show()\n        finish()\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/checkin/CheckinPreferences.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage org.microg.gms.checkin\n\nimport android.content.Context\nimport android.content.Intent\nimport org.microg.gms.settings.SettingsContract\nimport org.microg.gms.settings.SettingsContract.CheckIn\n\nobject CheckinPreferences {\n\n    @JvmStatic\n    fun isEnabled(context: Context): Boolean {\n        val projection = arrayOf(CheckIn.ENABLED)\n        return SettingsContract.getSettings(context, CheckIn.getContentUri(context), projection) { c ->\n            c.getInt(0) != 0\n        }\n    }\n\n    @JvmStatic\n    fun setEnabled(context: Context, enabled: Boolean) {\n        SettingsContract.setSettings(context, CheckIn.getContentUri(context)) {\n            put(CheckIn.ENABLED, enabled)\n        }\n        if (enabled) {\n            context.sendOrderedBroadcast(Intent(context, TriggerReceiver::class.java), null)\n        }\n    }\n\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/checkin/ServiceInfo.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.checkin\n\nimport android.content.Context\nimport android.content.Intent\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\nimport org.microg.gms.settings.SettingsContract.CheckIn\nimport org.microg.gms.settings.SettingsContract.getSettings\nimport org.microg.gms.settings.SettingsContract.setSettings\nimport java.io.Serializable\n\ndata class ServiceInfo(val configuration: ServiceConfiguration, val lastCheckin: Long, val androidId: Long) : Serializable\n\ndata class ServiceConfiguration(val enabled: Boolean) : Serializable\n\nsuspend fun getCheckinServiceInfo(context: Context): ServiceInfo = withContext(Dispatchers.IO) {\n    val projection = arrayOf(CheckIn.ENABLED, CheckIn.LAST_CHECK_IN, CheckIn.ANDROID_ID)\n    getSettings(context, CheckIn.getContentUri(context), projection) { c ->\n        ServiceInfo(\n            configuration = ServiceConfiguration(c.getInt(0) != 0),\n            lastCheckin = c.getLong(1),\n            androidId = c.getLong(2),\n        )\n    }\n}\n\nsuspend fun setCheckinServiceConfiguration(context: Context, configuration: ServiceConfiguration) = withContext(Dispatchers.IO) {\n    val serviceInfo = getCheckinServiceInfo(context)\n    if (serviceInfo.configuration == configuration) return@withContext\n    // enabled state is not already set, setting it now\n    setSettings(context, CheckIn.getContentUri(context)) {\n        put(CheckIn.ENABLED, configuration.enabled)\n    }\n    if (configuration.enabled) {\n        context.sendOrderedBroadcast(Intent(context, TriggerReceiver::class.java), null)\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/chimera/ServiceProvider.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.chimera\n\nimport android.content.ContentProvider\nimport android.content.ContentValues\nimport android.content.Context\nimport android.content.Intent\nimport android.database.Cursor\nimport android.database.MatrixCursor\nimport android.net.Uri\nimport android.os.Bundle\nimport android.util.Log\nimport androidx.core.os.bundleOf\nimport org.microg.gms.DummyService\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.common.RemoteListenerProxy\n\nclass ServiceProvider : ContentProvider() {\n\n    override fun onCreate(): Boolean {\n        Log.d(TAG, \"onCreate\")\n        return true\n    }\n\n    override fun call(method: String, arg: String?, extras: Bundle?): Bundle? {\n        when (method) {\n            \"serviceIntentCall\" -> {\n                val serviceAction = extras?.getString(\"serviceActionBundleKey\") ?: return null\n                val context = context!!\n                var intent = Intent(serviceAction).apply { `package` = context.packageName }\n                var resolveInfo = context.packageManager.resolveService(intent, 0)\n                if (resolveInfo == null && GmsService.byAction(serviceAction).ACTION != null) {\n                    // Try again with action as defined in GmsService\n                    val overrideAction = GmsService.byAction(serviceAction).ACTION\n                    val overrideActionIntent = Intent(overrideAction).apply { `package` = context.packageName }\n                    resolveInfo = context.packageManager.resolveService(overrideActionIntent, 0)\n                }\n                if (resolveInfo != null) {\n                    intent.setClassName(resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name)\n                } else {\n                    intent.setClass(context, DummyService::class.java)\n                }\n                Log.d(TAG, \"$method: $serviceAction -> $intent\")\n                return bundleOf(\n                        \"serviceResponseIntentKey\" to intent\n                )\n            }\n            else -> {\n                Log.d(TAG, \"$method: $arg, $extras\")\n                return super.call(method, arg, extras)\n            }\n        }\n    }\n\n    override fun query(uri: Uri, projection: Array<out String>?, selection: String?, selectionArgs: Array<out String>?, sortOrder: String?): Cursor? {\n        val cursor = MatrixCursor(COLUMNS)\n        Log.d(TAG, \"query: $uri\")\n        return cursor\n    }\n\n    override fun insert(uri: Uri, values: ContentValues?): Uri? {\n        Log.d(TAG, \"insert: $uri, $values\")\n        return uri\n    }\n\n    override fun update(uri: Uri, values: ContentValues?, selection: String?, selectionArgs: Array<out String>?): Int {\n        Log.d(TAG, \"update: $uri, $values, $selection, $selectionArgs\")\n        return 0\n    }\n\n    override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int {\n        Log.d(TAG, \"delete: $uri, $selection, $selectionArgs\")\n        return 0\n    }\n\n    override fun getType(uri: Uri): String {\n        Log.d(TAG, \"getType: $uri\")\n        return \"vnd.android.cursor.item/com.google.android.gms.chimera\"\n    }\n\n    companion object {\n        private const val TAG = \"ChimeraServiceProvider\"\n        private val COLUMNS = arrayOf(\"version\", \"apkPath\", \"loaderPath\", \"apkDescStr\")\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/clearcut/ClearcutLoggerService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage org.microg.gms.clearcut\n\nimport android.os.Parcel\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.LifecycleOwner\nimport androidx.lifecycle.lifecycleScope\nimport com.google.android.gms.clearcut.LogEventParcelable\nimport com.google.android.gms.clearcut.internal.IClearcutLoggerCallbacks\nimport com.google.android.gms.clearcut.internal.IClearcutLoggerService\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.data.DataHolder\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.utils.warnOnTransactionIssues\n\nprivate const val TAG = \"ClearcutLoggerService\"\nprivate const val COLLECT_FOR_DEBUG_DURATION = 24L * 60 * 60 * 1000\n\nclass ClearcutLoggerService : BaseService(TAG, GmsService.CLEARCUT_LOGGER) {\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        callback.onPostInitComplete(0, ClearcutLoggerServiceImpl(lifecycle), null)\n    }\n}\n\nclass ClearcutLoggerServiceImpl(override val lifecycle: Lifecycle) : IClearcutLoggerService.Stub(), LifecycleOwner {\n    private var collectForDebugExpiryTime: Long = 0\n\n    override fun log(callbacks: IClearcutLoggerCallbacks, event: LogEventParcelable) {\n        lifecycleScope.launchWhenStarted {\n            runCatching { callbacks.onLogResult(Status.SUCCESS) }\n        }\n    }\n\n    override fun forceUpload(callbacks: IClearcutLoggerCallbacks) {\n        lifecycleScope.launchWhenStarted {\n            runCatching { callbacks.onLogResult(Status.SUCCESS) }\n        }\n    }\n\n    override fun startCollectForDebug(callbacks: IClearcutLoggerCallbacks) {\n        lifecycleScope.launchWhenStarted {\n            collectForDebugExpiryTime = System.currentTimeMillis() + COLLECT_FOR_DEBUG_DURATION\n            runCatching { callbacks.onStartCollectForDebugResult(Status.SUCCESS, collectForDebugExpiryTime) }\n        }\n    }\n\n    override fun stopCollectForDebug(callbacks: IClearcutLoggerCallbacks) {\n        lifecycleScope.launchWhenStarted {\n            runCatching { callbacks.onStopCollectForDebugResult(Status.SUCCESS) }\n        }\n    }\n\n    override fun getCollectForDebugExpiryTime(callbacks: IClearcutLoggerCallbacks) {\n        lifecycleScope.launchWhenStarted {\n            runCatching { callbacks.onCollectForDebugExpiryTime(Status.SUCCESS, collectForDebugExpiryTime) }\n        }\n    }\n\n    override fun getLogEventParcelablesLegacy(callbacks: IClearcutLoggerCallbacks) {\n        getLogEventParcelables(callbacks)\n    }\n\n    override fun getLogEventParcelables(callbacks: IClearcutLoggerCallbacks) {\n        lifecycleScope.launchWhenStarted {\n            runCatching { callbacks.onLogEventParcelables(DataHolder.empty(CommonStatusCodes.SUCCESS)) }\n        }\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/common/ClientTelemetryService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.common\n\nimport android.util.Log\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.LifecycleOwner\nimport com.google.android.gms.common.ConnectionResult\nimport com.google.android.gms.common.Feature\nimport com.google.android.gms.common.internal.ConnectionInfo\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport com.google.android.gms.common.internal.TelemetryData\nimport com.google.android.gms.common.internal.service.IClientTelemetryService\nimport org.microg.gms.BaseService\n\nprivate const val TAG = \"ClientTelemetryService\"\n\nclass ClientTelemetryService : BaseService(TAG, GmsService.CLIENT_TELEMETRY) {\n    override fun handleServiceRequest(callback: IGmsCallbacks?, request: GetServiceRequest?, service: GmsService?) {\n        callback?.onPostInitCompleteWithConnectionInfo(\n            ConnectionResult.SUCCESS,\n            ClientTelemetryServiceImpl(lifecycle).asBinder(),\n            ConnectionInfo().apply {\n                features = arrayOf(Feature(\"CLIENT_TELEMETRY\", 1))\n            }\n        )\n    }\n}\n\nclass ClientTelemetryServiceImpl(override val lifecycle: Lifecycle) : IClientTelemetryService.Stub(), LifecycleOwner {\n\n    override fun log(data: TelemetryData?) {\n        Log.d(TAG, \"log: $data\")\n    }\n\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/common/GmsCommonService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2026 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.common\n\nimport android.content.Context\nimport android.util.Log\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.LifecycleOwner\nimport androidx.lifecycle.lifecycleScope\nimport com.google.android.gms.common.ConnectionResult\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport com.google.android.gms.common.internal.service.ICommonCallbacks\nimport com.google.android.gms.common.internal.service.ICommonService\nimport org.microg.gms.BaseService\nimport org.microg.gms.auth.signin.SignInConfigurationService\n\nprivate const val TAG = \"GmsCommonService\"\n\nclass GmsCommonService : BaseService(TAG, GmsService.COMMON) {\n    override fun handleServiceRequest(callback: IGmsCallbacks?, request: GetServiceRequest, service: GmsService?) {\n        val packageName = PackageUtils.getAndCheckCallingPackage(this, request.packageName) ?: throw IllegalArgumentException(\"Missing package name\")\n        Log.d(TAG, \"handleServiceRequest: start: $packageName\")\n        callback?.onPostInitComplete(ConnectionResult.SUCCESS, GmsCommonServiceImpl(this, packageName, lifecycle).asBinder(), null)\n    }\n}\n\nclass GmsCommonServiceImpl(val context: Context, val packageName: String, override val lifecycle: Lifecycle) : ICommonService.Stub(), LifecycleOwner {\n    override fun clearDefaultAccount(callbacks: ICommonCallbacks?) {\n        Log.d(TAG, \"clearDefaultAccount: packageName: $packageName\")\n        lifecycleScope.launchWhenStarted {\n            AccountUtils.get(context).removeSelectedAccount(packageName)\n            SignInConfigurationService.setAuthInfo(context, packageName, null, null)\n            runCatching { callbacks?.onClearDefaultAccountResult(0) }\n        }\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/common/PackageIntentOpWorker.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.common\n\nimport android.content.Context\nimport android.util.Log\nimport androidx.work.CoroutineWorker\nimport androidx.work.WorkerParameters\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\nimport org.microg.gms.auth.signin.SignInConfigurationService\nimport org.microg.gms.auth.signin.performSignOut\nimport org.microg.gms.gcm.GcmDatabase\nimport org.microg.gms.gcm.PushRegisterManager\n\nclass PackageIntentOpWorker(\n    val appContext: Context,\n    params: WorkerParameters\n) : CoroutineWorker(appContext, params) {\n\n    companion object {\n        private const val TAG = \"PackageIntentOpWorker\"\n        const val PACKAGE_NAME = \"packageName\"\n    }\n\n    override suspend fun doWork(): Result {\n        val packageName = inputData.getString(PACKAGE_NAME) ?: return Result.failure()\n        Log.d(TAG, \"doWork: $packageName clearing.\")\n\n        clearGcmData(packageName)\n        clearAuthInfo(packageName)\n\n        Log.d(TAG, \"doWork: $packageName cleared.\")\n        return Result.success()\n    }\n\n    private suspend fun clearGcmData(packageName: String) = withContext(Dispatchers.IO) {\n        val database = GcmDatabase(appContext)\n        val app = database.getApp(packageName)\n        if (app != null) {\n            val registrations = database.getRegistrationsByApp(packageName)\n            var deletedAll = true\n            for (registration in registrations) {\n                deletedAll = deletedAll and (PushRegisterManager.unregister(appContext, registration.packageName, registration.signature, null, null).deleted != null)\n            }\n            if (deletedAll) {\n                database.removeApp(packageName)\n            }\n            database.close()\n        } else {\n            database.close()\n        }\n    }\n\n    private suspend fun clearAuthInfo(packageName: String) = withContext(Dispatchers.IO) {\n        val authOptions = SignInConfigurationService.getAuthOptions(appContext, packageName)\n        val authAccount = SignInConfigurationService.getDefaultAccount(appContext, packageName)\n        if (authOptions.isNotEmpty() && authAccount != null) {\n            authOptions.forEach {\n                Log.d(TAG, \"$packageName:clear authAccount: ${authAccount.name} authOption:($it)\")\n                performSignOut(appContext, packageName, it, authAccount)\n            }\n        }\n        SignInConfigurationService.setAuthInfo(appContext, packageName, null, null)\n        AccountUtils.get(appContext).removeSelectedAccount(packageName)\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/common/PersistentTrustedReceiver.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.common\n\nimport android.content.BroadcastReceiver\nimport android.content.Context\nimport android.content.Intent\nimport android.util.Log\nimport androidx.work.Data\nimport androidx.work.OneTimeWorkRequestBuilder\nimport androidx.work.WorkManager\n\nclass PersistentTrustedReceiver : BroadcastReceiver() {\n\n    companion object {\n        private const val TAG = \"TrustedReceiver\"\n    }\n\n    override fun onReceive(context: Context, intent: Intent?) {\n        Log.d(TAG, \"Package changed: $intent\")\n        val action = intent?.action ?: return\n        val pkg = intent.data?.schemeSpecificPart ?: return\n\n        if ((Intent.ACTION_PACKAGE_REMOVED.contains(action)\n                    && intent.getBooleanExtra(Intent.EXTRA_DATA_REMOVED, false)\n                    && !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false))\n            || Intent.ACTION_PACKAGE_FULLY_REMOVED.contains(action)\n            || Intent.ACTION_PACKAGE_DATA_CLEARED.contains(action)\n        ) {\n            Log.d(TAG, \"Package removed or data cleared: $pkg\")\n            val data = Data.Builder()\n                .putString(PackageIntentOpWorker.PACKAGE_NAME, pkg)\n                .build()\n            val request = OneTimeWorkRequestBuilder<PackageIntentOpWorker>()\n                .setInputData(data)\n                .build()\n            WorkManager.getInstance(context).enqueue(request)\n        }\n    }\n\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/credential/CredentialManagerService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.credential\n\nimport android.app.PendingIntent\nimport android.content.Context\nimport android.content.Intent\nimport android.os.Parcel\nimport android.util.Base64\nimport android.util.Log\nimport androidx.core.app.PendingIntentCompat\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.LifecycleOwner\nimport androidx.lifecycle.lifecycleScope\nimport com.google.android.gms.common.ConnectionResult\nimport com.google.android.gms.common.Feature\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.api.internal.IStatusCallback\nimport com.google.android.gms.common.internal.ConnectionInfo\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport com.google.android.gms.credential.manager.EXTRA_KEY_ACCOUNT_NAME\nimport com.google.android.gms.credential.manager.PASSWORD_MANAGER_CLASS_NAME\nimport com.google.android.gms.credential.manager.common.IPendingIntentCallback\nimport com.google.android.gms.credential.manager.common.ISettingsCallback\nimport com.google.android.gms.credential.manager.firstparty.internal.ICredentialManagerService\nimport com.google.android.gms.credential.manager.invocationparams.CredentialManagerInvocationParams\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.Constants\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.common.GooglePackagePermission\nimport org.microg.gms.common.PackageUtils\nimport org.microg.gms.utils.toBase64\nimport org.microg.gms.utils.warnOnTransactionIssues\n\nprivate const val TAG = \"CredentialManager\"\n\nclass CredentialManagerService : BaseService(TAG, GmsService.CREDENTIAL_MANAGER) {\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        if (!PackageUtils.callerHasGooglePackagePermission(this, GooglePackagePermission.CREDENTIALS)) {\n            Log.d(TAG, \"No access to ${request.packageName}, lacks permission.\")\n            callback.onPostInitComplete(ConnectionResult.API_DISABLED_FOR_CONNECTION, null, null)\n            return\n        }\n        callback.onPostInitCompleteWithConnectionInfo(ConnectionResult.SUCCESS, CredentialManagerServiceImpl(this, lifecycle), ConnectionInfo().apply {\n            features = arrayOf(\n                Feature(\"credential_manager_first_party_api\", 1),\n                Feature(\"password_checkup_first_party_api\", 1),\n                Feature(\"user_service_security\", 1),\n            )\n        })\n    }\n\n}\n\nprivate class CredentialManagerServiceImpl(private val context: Context, override val lifecycle: Lifecycle) : ICredentialManagerService.Stub(), LifecycleOwner {\n\n    override fun getCredentialManagerIntent(callback: IPendingIntentCallback?, params: CredentialManagerInvocationParams) {\n        Log.d(TAG, \"Method getCredentialManagerIntent $params called\")\n        lifecycleScope.launchWhenStarted {\n            runCatching {\n                val intent = Intent().apply {\n                    setClassName(Constants.GMS_PACKAGE_NAME, PASSWORD_MANAGER_CLASS_NAME)\n                    putExtra(EXTRA_KEY_ACCOUNT_NAME, params.account.name)\n                    addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)\n                }\n                val pendingIntent = PendingIntentCompat.getActivity(context, 0, intent, 0, false)\n                callback?.onPendingIntent(Status.SUCCESS, pendingIntent)\n            }.onFailure {\n                Log.d(TAG, \"getCredentialManagerIntent error\", it)\n                callback?.onPendingIntent(Status.INTERNAL_ERROR, null)\n            }\n        }\n    }\n\n    override fun getSetting(callback: ISettingsCallback?, key: String?) {\n        Log.d(TAG, \"Not yet implemented: getSetting $key\")\n        lifecycleScope.launchWhenStarted {\n            try {\n                callback?.onSetting(Status.INTERNAL_ERROR, null)\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n            }\n        }\n    }\n\n    override fun setSetting(callback: IStatusCallback?, key: String?, value: ByteArray?) {\n        Log.d(TAG, \"Not yet implemented: setSetting $key ${value?.toBase64(Base64.NO_WRAP)}\")\n        lifecycleScope.launchWhenStarted {\n            try {\n                callback?.onResult(Status.INTERNAL_ERROR)\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n            }\n        }\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/cryptauth/CryptAuthFlow.kt",
    "content": "package org.microg.gms.cryptauth\n\nimport android.accounts.Account\nimport android.app.KeyguardManager\nimport android.content.Context\nimport android.os.Bundle\nimport android.util.Base64\nimport android.util.Log\nimport com.google.android.gms.BuildConfig\nimport com.google.android.gms.common.Scopes\nimport cryptauthv2.ApplicationSpecificMetadata\nimport cryptauthv2.ClientAppMetadata\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.delay\nimport kotlinx.coroutines.withContext\nimport okio.ByteString.Companion.toByteString\nimport org.json.JSONArray\nimport org.json.JSONObject\nimport org.microg.gms.auth.AuthConstants\nimport org.microg.gms.auth.AuthManager\nimport org.microg.gms.checkin.LastCheckinInfo\nimport org.microg.gms.common.Constants\nimport org.microg.gms.common.DeviceConfiguration\nimport org.microg.gms.common.Utils\nimport org.microg.gms.gcm.GcmConstants\nimport org.microg.gms.gcm.GcmDatabase\nimport org.microg.gms.gcm.RegisterRequest\nimport org.microg.gms.gcm.completeRegisterRequest\nimport org.microg.gms.profile.Build\nimport java.io.IOException\nimport java.net.HttpURLConnection\nimport java.net.URL\nimport java.security.KeyPairGenerator\nimport java.security.MessageDigest\nimport kotlin.math.roundToInt\n\nprivate const val TAG = \"CryptAuthFlow\"\n\nprivate const val GCM_REGISTER_SENDER = \"16502139086\"\nprivate const val GCM_REGISTER_SUBTYPE = \"16502139086\"\nprivate const val GCM_REGISTER_SUBSCRIPTION = \"16502139086\"\nprivate const val GCM_REGISTER_SCOPE = \"GCM\"\nprivate const val GCM_REGISTER_CLIV = \"iid-202414000\"\nprivate const val GCM_REGISTER_INFO = \"0wqs6iYsl_URQEb1aBJ6XhzCbHSr-hg\"\n\nprivate const val RSA_KEY_SIZE = 2048\n\nprivate const val AFTER_REQUEST_DELAY = 5000L\n\nsuspend fun Context.sendDeviceScreenlockState(account: Account): Boolean = sendDeviceScreenlockState(account.name)\n\nsuspend fun Context.sendDeviceScreenlockState(accountName: String): Boolean {\n\n    // Ensure that device is checked in\n    val checkinInfo = LastCheckinInfo.read(this)\n    if (checkinInfo.androidId == 0L) {\n        Log.w(TAG, \"Device is not checked in, as it doesn't have an Android ID. Cannot perform cryptauth flow.\")\n        return false\n    }\n\n    // Instance ID token for use in CryptAuth query\n    val instanceId = generateAppId()\n    val instanceToken = registerForCryptAuth(checkinInfo, instanceId).getString(GcmConstants.EXTRA_REGISTRATION_ID)\n    if (instanceToken == null) {\n        Log.w(TAG, \"No instance ID was gathered. Is GCM enabled, has there been a checkin?\")\n        return false\n    }\n\n    // Auth token for use in CryptAuth query\n    val authToken = authenticateForCryptAuth(accountName)\n    if (authToken == null) {\n        Log.w(TAG, \"Authentication failed. Cannot perform cryptauth flow.\")\n        return false\n    }\n\n    val cryptAuthSyncKeysResult = cryptAuthSyncKeys(authToken, instanceId, instanceToken, checkinInfo.androidId)\n    if (cryptAuthSyncKeysResult == null\n        || !cryptAuthSyncKeysResult.has(CRYPTAUTH_FIELD_SESSION_ID)\n        || cryptAuthSyncKeysResult.get(CRYPTAUTH_FIELD_SESSION_ID) !is String\n    ) {\n        Log.w(TAG, \"CryptAuth syncKeys failed. Cannot complete flow.\")\n        return false\n    }\n\n    val session: String = cryptAuthSyncKeysResult.get(CRYPTAUTH_FIELD_SESSION_ID) as String\n    val cryptAuthEnrollKeysResult = cryptAuthEnrollKeys(authToken, session)\n\n    return if (cryptAuthEnrollKeysResult != null) {\n        /* Give Google server some time to process the new information.\n         * This leads to higher success rate compared to sending\n         * the next query immediately after this one. Tests show that it\n         * makes sense to wait multiple seconds.\n         */\n        delay(AFTER_REQUEST_DELAY)\n        true\n    } else {\n        false\n    }\n}\n\nprivate suspend fun Context.registerForCryptAuth(checkinInfo: LastCheckinInfo, instanceId: String): Bundle = completeRegisterRequest(\n    context = this,\n    database = GcmDatabase(this),\n    request = RegisterRequest().build(this)\n        .checkin(checkinInfo)\n        .app(\"com.google.android.gms\", CERTIFICATE.lowercase(), BuildConfig.VERSION_CODE)\n        .sender(GCM_REGISTER_SENDER)\n        .extraParam(\"subscription\", GCM_REGISTER_SUBSCRIPTION)\n        .extraParam(\"X-subscription\", GCM_REGISTER_SUBSCRIPTION)\n        .extraParam(\"subtype\", GCM_REGISTER_SUBTYPE)\n        .extraParam(\"X-subtype\", GCM_REGISTER_SUBTYPE)\n        .extraParam(\"app_ver\", BuildConfig.VERSION_CODE.toString())\n        .extraParam(\"osv\", \"29\")\n        .extraParam(\"cliv\", GCM_REGISTER_CLIV)\n        .extraParam(\"gmsv\", BuildConfig.VERSION_CODE.toString())\n        .extraParam(\"appid\", instanceId)\n        .extraParam(\"scope\", GCM_REGISTER_SCOPE)\n        .extraParam(\"app_ver_name\",\"%09d\".format(BuildConfig.VERSION_CODE).let {\n            \"${it.substring(0, 2)}.${it.substring(2, 4)}.${it.substring(4, 6)} (190800-{{cl}})\"\n        })\n        .info(GCM_REGISTER_INFO)\n)\n\nprivate suspend fun Context.authenticateForCryptAuth(accountName: String): String? {\n    val cryptAuthServiceOauth2 = AuthConstants.SCOPE_OAUTH2 + Scopes.CRYPTAUTH\n    val authManager = AuthManager(this, accountName, Constants.GMS_PACKAGE_NAME, cryptAuthServiceOauth2)\n    return withContext(Dispatchers.IO) { authManager.requestAuth(false).auth }\n}\n\n/**\n * Generates an app / instance ID based on the hash of the public key of an RSA keypair.\n * The key itself is never used.\n */\nfun generateAppId(): String {\n    val rsaGenerator = KeyPairGenerator.getInstance(\"RSA\")\n    rsaGenerator.initialize(RSA_KEY_SIZE)\n    val keyPair = rsaGenerator.generateKeyPair()\n\n    val digest = MessageDigest.getInstance(\"SHA1\").digest(keyPair.public.encoded)\n    digest[0] = ((112 + (0xF and digest[0].toInt())) and 0xFF).toByte()\n    return Base64.encodeToString(\n        digest, 0, 8, Base64.URL_SAFE or Base64.NO_WRAP or Base64.NO_PADDING\n    )\n}\n\nfun Context.isLockscreenConfigured(): Boolean {\n    val service: KeyguardManager = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager\n    return if (android.os.Build.VERSION.SDK_INT >= 23) {\n        service.isDeviceSecure\n    } else {\n        service.isKeyguardSecure\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/cryptauth/CryptAuthRequests.kt",
    "content": "package org.microg.gms.cryptauth\n\nimport android.content.Context\nimport android.util.Log\nimport com.google.android.gms.BuildConfig\nimport cryptauthv2.ApplicationSpecificMetadata\nimport cryptauthv2.ClientAppMetadata\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\nimport okio.ByteString.Companion.toByteString\nimport org.json.JSONArray\nimport org.json.JSONObject\nimport org.microg.gms.common.Constants\nimport org.microg.gms.common.DeviceConfiguration\nimport org.microg.gms.common.Utils\nimport org.microg.gms.profile.Build\nimport java.io.IOException\nimport java.net.HttpURLConnection\nimport java.net.URL\nimport kotlin.math.roundToInt\n\nprivate const val TAG = \"CryptAuthRequests\"\n\nprivate const val CRYPTAUTH_BASE_URL = \"https://cryptauthenrollment.googleapis.com/\"\nprivate const val CRYPTAUTH_METHOD_SYNC_KEYS = \"v1:syncKeys\"\nprivate const val CRYPTAUTH_METHOD_ENROLL_KEYS = \"v1:enrollKeys\"\n\nprivate const val API_KEY = \"AIzaSyAP-gfH3qvi6vgHZbSYwQ_XHqV_mXHhzIk\"\ninternal const val CERTIFICATE = \"58E1C4133F7441EC3D2C270270A14802DA47BA0E\"\n\ninternal const val CRYPTAUTH_FIELD_SESSION_ID = \"randomSessionId\"\n\n\ninternal suspend fun Context.cryptAuthSyncKeys(authToken: String, instanceId: String, instanceToken: String, androidId: Long): JSONObject? {\n    // CryptAuth sync request tells server whether or not screenlock is enabled\n\n    val deviceConfig = DeviceConfiguration(this)\n    val clientAppMetadata = ClientAppMetadata(\n        application_specific_metadata = listOf(\n            ApplicationSpecificMetadata(\n                gcm_registration_id = instanceToken.toByteArray().toByteString(),\n                notification_enabled = true,\n                device_software_version = \"%09d\".format(BuildConfig.VERSION_CODE).let {\n                    \"${it.substring(0, 2)}.${it.substring(2, 4)}.${it.substring(4, 6)} (190800-{{cl}})\"\n                },\n                device_software_version_code = BuildConfig.VERSION_CODE.toLong(),\n                device_software_package = Constants.GMS_PACKAGE_NAME\n            )\n        ),\n        instance_id = instanceId,\n        instance_id_token = instanceToken,\n        android_device_id = androidId,\n        locale = Utils.getLocale(this).toString().replace(\"_\", \"-\"),\n        device_os_version = Build.DISPLAY ?: \"\",\n        device_os_version_code = Build.VERSION.SDK_INT.toLong(),\n        device_os_release = Build.VERSION.CODENAME?: \"\",\n        device_display_diagonal_mils = (deviceConfig.diagonalInch / 1000).roundToInt(),\n        device_model = Build.MODEL ?: \"\",\n        device_manufacturer = Build.MANUFACTURER ?: \"\",\n        device_type = ClientAppMetadata.DeviceType.ANDROID,\n        using_secure_screenlock = isLockscreenConfigured(),\n        bluetooth_radio_supported = true, // TODO actual value? doesn't seem relevant\n        // bluetooth_radio_enabled = false,\n        ble_radio_supported = true, // TODO: actual value? doesn't seem relevant\n        mobile_data_supported = true, // TODO: actual value? doesn't seem relevant\n        // droid_guard_response = \"…\"\n    )\n        .encodeByteString()\n        .base64Url()\n\n    val jsonBody = jsonObjectOf(\n        \"applicationName\" to Constants.GMS_PACKAGE_NAME,\n        \"clientVersion\" to \"1.0.0\",\n        \"syncSingleKeyRequests\" to jsonArrayOf(\n            jsonObjectOf(\n                \"keyName\" to \"PublicKey\",\n                \"keyHandles\" to \"ZGV2aWNlX2tleQo=\" // base64 for `device_key`\n            )\n        ),\n        \"clientMetadata\" to jsonObjectOf(\n            \"invocationReason\" to \"NEW_ACCOUNT\"\n        ),\n        \"clientAppMetadata\" to clientAppMetadata,\n    )\n\n    return cryptAuthQuery(CRYPTAUTH_BASE_URL + CRYPTAUTH_METHOD_SYNC_KEYS, authToken, jsonBody)\n}\n\ninternal suspend fun Context.cryptAuthEnrollKeys(authToken: String, session: String): JSONObject? {\n    val jsonBody = jsonObjectOf(\n        CRYPTAUTH_FIELD_SESSION_ID to session,\n        \"clientEphemeralDh\" to \"\",\n        \"enrollSingleKeyRequests\" to JSONArray(),\n    )\n\n    return cryptAuthQuery(CRYPTAUTH_BASE_URL + CRYPTAUTH_METHOD_ENROLL_KEYS, authToken, jsonBody)\n}\n\nprivate suspend fun Context.cryptAuthQuery(url: String, authToken: String, requestBody: JSONObject) = withContext(\n    Dispatchers.IO) {\n    val connection = (URL(url).openConnection() as HttpURLConnection).apply {\n        setRequestMethod(\"POST\")\n        setDoInput(true)\n        setDoOutput(true)\n        setRequestProperty(\"x-goog-api-key\", API_KEY)\n        setRequestProperty(\"x-android-package\", Constants.GMS_PACKAGE_NAME)\n        setRequestProperty(\"x-android-cert\", CERTIFICATE)\n        setRequestProperty(\"Authorization\", \"Bearer $authToken\")\n        setRequestProperty(\"Content-Type\", \"application/json\")\n    }\n\n    Log.d(TAG, \"-- Request --\\n$requestBody\")\n    val os = connection.outputStream\n    os.write(requestBody.toString().toByteArray())\n    os.close()\n\n    if (connection.getResponseCode() != 200) {\n        var error = connection.getResponseMessage()\n        try {\n            error = String(Utils.readStreamToEnd(connection.errorStream))\n        } catch (e: IOException) {\n            // Ignore\n        }\n        throw IOException(error)\n    }\n\n    val result = String(Utils.readStreamToEnd(connection.inputStream))\n    Log.d(TAG, \"-- Response --\\n$result\")\n    try {\n        JSONObject(result)\n\n    } catch (e: Exception) {\n        null\n    }\n}\n\nfun <K, V> jsonObjectOf(vararg pairs: Pair<K, V>): JSONObject = JSONObject(mapOf(*pairs))\ninline fun <reified T> jsonArrayOf(vararg elements: T): JSONArray = JSONArray(arrayOf(*elements))"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/feedback/FeedbackService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.feedback\n\nimport android.content.Context\nimport android.content.Intent\nimport android.os.Bundle\nimport android.util.Log\nimport androidx.lifecycle.LifecycleCoroutineScope\nimport androidx.lifecycle.lifecycleScope\nimport com.google.android.gms.common.Feature\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.internal.ConnectionInfo\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport com.google.android.gms.feedback.ErrorReport\nimport com.google.android.gms.feedback.FeedbackOptions\nimport com.google.android.gms.feedback.internal.IFeedbackService\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.profile.ProfileManager\n\nprivate const val TAG = \"FeedbackService\"\n\nclass FeedbackService : BaseService(TAG, GmsService.FEEDBACK) {\n\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        Log.d(TAG, \"handleServiceRequest start \")\n        ProfileManager.ensureInitialized(this)\n        callback.onPostInitCompleteWithConnectionInfo(\n            CommonStatusCodes.SUCCESS,\n            FeedbackServiceImpl(this, lifecycleScope),\n            ConnectionInfo().apply {\n                features = arrayOf(Feature(\"new_send_silent_feedback\", 1))\n            })\n    }\n\n}\n\nclass FeedbackServiceImpl(private val context: Context, private val lifecycleScope: LifecycleCoroutineScope) :\n    IFeedbackService.Stub() {\n\n    override fun startFeedbackFlow(errorReport: ErrorReport): Boolean {\n        Log.d(TAG, \"startFeedbackFlow: \")\n        showFeedbackDisabledToast()\n        return false\n    }\n\n    override fun silentSendFeedback(errorReport: ErrorReport): Boolean {\n        Log.d(TAG, \"Not impl silentSendFeedback: \")\n        return false\n    }\n\n    override fun saveFeedbackDataAsync(bundle: Bundle, id: Long) {\n        Log.d(TAG, \"Not impl saveFeedbackDataAsync: \")\n    }\n\n    override fun saveFeedbackDataAsyncWithOption(options: FeedbackOptions, bundle: Bundle, id: Long) {\n        Log.d(TAG, \"Not impl saveFeedbackDataAsyncWithOption: $options\")\n    }\n\n    override fun startFeedbackFlowAsync(errorReport: ErrorReport, id: Long) {\n        Log.d(TAG, \"startFeedbackFlowAsync errorReport:$errorReport\")\n        showFeedbackDisabledToast()\n    }\n\n    override fun isValidConfiguration(options: FeedbackOptions): Boolean {\n        Log.d(TAG, \"Not impl isValidConfiguration: $options\")\n        return false\n    }\n\n    private fun showFeedbackDisabledToast() {\n        lifecycleScope.launchWhenStarted {\n            withContext(Dispatchers.Main){\n                val intent: Intent = Intent().apply {\n                    setClassName(context, \"com.google.android.gms.feedback.FeedbackActivity\")\n                    flags = Intent.FLAG_ACTIVITY_NEW_TASK\n                }\n                context.startActivity(intent)\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/firebase/dynamiclinks/DynamicLinksService.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.firebase.dynamiclinks\n\nimport android.content.Context\nimport android.net.Uri\nimport android.os.Bundle\nimport android.os.Parcel\nimport android.util.Log\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.LifecycleOwner\nimport androidx.lifecycle.lifecycleScope\nimport com.android.volley.toolbox.Volley\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport com.google.firebase.dynamiclinks.internal.DynamicLinkData\nimport com.google.firebase.dynamiclinks.internal.IDynamicLinksCallbacks\nimport com.google.firebase.dynamiclinks.internal.IDynamicLinksService\nimport com.google.firebase.dynamiclinks.internal.ShortDynamicLinkImpl\nimport com.google.firebase.dynamiclinks.internal.WarningImpl\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.common.PackageUtils\nimport org.microg.gms.fido.core.map\nimport org.microg.gms.appinivite.utils.DynamicLinkUtils\nimport org.microg.gms.utils.singleInstanceOf\nimport org.microg.gms.utils.warnOnTransactionIssues\nimport java.net.URLEncoder\n\nprivate const val TAG = \"DynamicLinksService\"\n\nclass DynamicLinksService : BaseService(TAG, GmsService.DYNAMIC_LINKS_API) {\n\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        val callingPackage = PackageUtils.getAndCheckCallingPackage(this, request.packageName) ?: throw IllegalArgumentException(\"Missing package name\")\n        callback.onPostInitComplete(0, DynamicLinksServiceImpl(this, callingPackage, lifecycle, request.extras), null)\n    }\n\n}\n\nclass DynamicLinksServiceImpl(private val context: Context, private val callingPackageName: String, override val lifecycle: Lifecycle, extras: Bundle?) : IDynamicLinksService.Stub(), LifecycleOwner {\n\n    private val queue = singleInstanceOf { Volley.newRequestQueue(context) }\n\n    override fun getDynamicLink(callback: IDynamicLinksCallbacks, link: String?) {\n        Log.d(TAG, \"getDynamicLink: callingPackageName: $callingPackageName link: $link\")\n        lifecycleScope.launchWhenCreated {\n            try {\n                if (link == null) {\n                    throw RuntimeException(\"Missing link\")\n                }\n                val linkUri = Uri.parse(link)\n                if (\"http\" == linkUri.scheme || \"https\" == linkUri.scheme) {\n                    val response = runCatching { withContext(Dispatchers.IO) { DynamicLinkUtils.requestLinkResponse(link, queue) } }.getOrNull()\n                        ?: throw RuntimeException(\"requestLinkResponse failed\")\n                    val data = DynamicLinkData(link, response.data_?.intentData, (response.data_?.app?.minAppVersion ?: 0).toInt(), System.currentTimeMillis(), null, null)\n                    Log.d(TAG, \"getDynamicLink: $link -> $data\")\n                    callback.onStatusDynamicLinkData(Status.SUCCESS, data)\n                    return@launchWhenCreated\n                }\n                val deepLink = linkUri.getQueryParameter(\"link\")\n                if (!deepLink.isNullOrEmpty()) {\n                    val packageName = linkUri.getQueryParameter(\"apn\")\n                    val amvParameter = linkUri.getQueryParameter(\"amv\")\n                    if (packageName == null) {\n                        throw RuntimeException(\"Missing package name\")\n                    } else if (callingPackageName != packageName) {\n                        throw RuntimeException(\"Registered package name:$callingPackageName does not match link package name: $packageName\")\n                    }\n                    var amv = amvParameter?.takeIf { it !== \"\" }?.toInt() ?: 0\n                    val data = DynamicLinkData(link, deepLink, amv, 0, null, null)\n                    Log.d(TAG, \"getDynamicLink: $link -> $data\")\n                    callback.onStatusDynamicLinkData(Status.SUCCESS, data)\n                    return@launchWhenCreated\n                }\n                throw RuntimeException(\"$link is not a valid dynamic link\")\n            } catch (e: Exception) {\n                Log.d(TAG, \"getDynamicLink: error : ${e.message}\")\n                callback.onStatusDynamicLinkData(Status.SUCCESS, null)\n            }\n        }\n    }\n\n    override fun createShortDynamicLink(callback: IDynamicLinksCallbacks, extras: Bundle) {\n        extras.keySet() // Unparcel\n        Log.d(TAG, \"createShortDynamicLink: $extras\")\n        val domainUriPrefix = extras.getString(\"domainUriPrefix\")\n        val parameters = extras.getBundle(\"parameters\")\n        var longDynamicLink: String? = null\n        if (!domainUriPrefix.isNullOrEmpty() && parameters != null) {\n            val params = parameters.keySet().mapNotNull { key ->\n                parameters[key]?.toString()?.let { value ->\n                    val encodedValue = URLEncoder.encode(value, \"UTF-8\").replace(\"%21\", \"!\").replace(\"+\", \"%20\")\n                    \"$key=$encodedValue\"\n                }\n            }.joinToString(\"&\")\n            longDynamicLink = \"$domainUriPrefix?$params\"\n        }\n        val apikey = extras.getString(\"apiKey\")\n        if (apikey != null && longDynamicLink != null) {\n            lifecycleScope.launchWhenCreated {\n                val jsonResult = withContext(Dispatchers.IO) {\n                    runCatching {\n                        DynamicLinkUtils.requestShortLinks(context, callingPackageName, apikey, longDynamicLink, queue)\n                    }.onFailure {\n                        Log.d(TAG, \"createShortDynamicLink: \", it)\n                    }.getOrNull()\n                }\n                if (jsonResult == null) {\n                    callback.onStatusShortDynamicLink(Status.SUCCESS, ShortDynamicLinkImpl())\n                    return@launchWhenCreated\n                }\n                val shortLink = jsonResult.optString(\"shortLink\")\n                val previewLink = jsonResult.optString(\"previewLink\")\n                val warningList = jsonResult.optJSONArray(\"warning\")?.map {\n                    val warningMessage = getJSONObject(it).optString(\"warningMessage\")\n                    WarningImpl(warningMessage)\n                } ?: emptyList()\n                callback.onStatusShortDynamicLink(Status.SUCCESS, ShortDynamicLinkImpl(shortLink.let { Uri.parse(it) }, previewLink.let { Uri.parse(it) }, warningList))\n            }\n            return\n        }\n        callback.onStatusShortDynamicLink(Status.SUCCESS, ShortDynamicLinkImpl())\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int) = warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/fonts/FontsProvider.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fonts\n\nimport android.content.ContentProvider\nimport android.content.ContentValues\nimport android.database.Cursor\nimport android.database.MatrixCursor\nimport android.net.Uri\nimport android.os.Bundle\nimport android.os.ParcelFileDescriptor\nimport android.os.ParcelFileDescriptor.MODE_READ_ONLY\nimport android.util.Log\nimport java.io.File\n\nclass FontsProvider : ContentProvider() {\n\n    override fun onCreate(): Boolean {\n        Log.d(TAG, \"onCreate\")\n        return true\n    }\n\n    override fun call(method: String, arg: String?, extras: Bundle?): Bundle? {\n        Log.d(TAG, \"call $method $arg $extras\")\n        return null\n    }\n\n    override fun query(\n        uri: Uri,\n        projection: Array<out String>?,\n        selection: String?,\n        selectionArgs: Array<out String>?,\n        sortOrder: String?\n    ): Cursor {\n        Log.e(TAG, \"query: $uri ${projection?.toList()} $selection ${selectionArgs?.joinToString(prefix = \"[\", postfix = \"]\")}\")\n        val cursor = MatrixCursor(COLUMNS)\n        // We could also return an empty cursor here, but some apps have been reported to crash\n        // when their expected font is not returned by Google's font provider.\n        cursor.addRow(\n            arrayOf(\n                1337L, // file_id\n                0, // font_ttc_index\n                null, // font_variation_settings\n                400, // font_weight\n                0, // font_italic\n                0, // result_code: RESULT_CODE_OK\n            )\n        )\n        return cursor\n    }\n\n    override fun insert(uri: Uri, values: ContentValues?): Uri {\n        Log.d(TAG, \"insert: $uri, $values\")\n        return uri\n    }\n\n    override fun update(\n        uri: Uri,\n        values: ContentValues?,\n        selection: String?,\n        selectionArgs: Array<out String>?\n    ): Int {\n        Log.d(TAG, \"update: $uri, $values, $selection, $selectionArgs\")\n        return 0\n    }\n\n    override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int {\n        Log.d(TAG, \"delete: $uri, $selection, $selectionArgs\")\n        return 0\n    }\n\n    override fun getType(uri: Uri): String {\n        Log.d(TAG, \"getType: $uri\")\n        return \"font/ttf\"\n    }\n\n    override fun openFile(uri: Uri, mode: String): ParcelFileDescriptor? {\n        Log.d(TAG, \"openFile: $uri mode: $mode\")\n        val file = File(\"/system/fonts/Roboto-Regular.ttf\")\n        return ParcelFileDescriptor.open(file, MODE_READ_ONLY)\n    }\n\n    companion object {\n        private const val TAG = \"FontsProvider\"\n        private val COLUMNS = arrayOf(\n            \"file_id\",\n            \"font_ttc_index\",\n            \"font_variation_settings\",\n            \"font_weight\",\n            \"font_italic\",\n            \"result_code\"\n        )\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/games/FirstPartyGamesService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.games\n\nimport android.content.Context\nimport android.os.Parcel\nimport android.util.Log\nimport androidx.lifecycle.Lifecycle\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.data.DataHolder\nimport com.google.android.gms.common.internal.ConnectionInfo\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport com.google.android.gms.games.client.IPlayGamesCallbacks\nimport com.google.android.gms.games.client.IPlayGamesService\nimport com.google.android.gms.games.client.PlayGamesConsistencyTokens\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.Constants\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.common.GooglePackagePermission\nimport org.microg.gms.common.PackageUtils\nimport org.microg.gms.utils.warnOnTransactionIssues\n\nprivate const val TAG = \"PlayGamesService\"\nprivate val FIRST_PARTY_PACKAGES = setOf(Constants.GMS_PACKAGE_NAME, GAMES_PACKAGE_NAME)\n\nclass FirstPartyGamesService : BaseService(TAG, GmsService.GAMES) {\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        val packageName = PackageUtils.getAndCheckCallingPackageOrImpersonation(this, request.packageName)\n            ?: throw IllegalArgumentException(\"Missing package name\")\n        val callingPackageName = PackageUtils.getCallingPackage(this) ?: packageName\n        if (!PackageUtils.callerHasGooglePackagePermission(this, GooglePackagePermission.GAMES))\n            throw IllegalArgumentException(\"$callingPackageName does not have google games access\")\n        if (callingPackageName !in FIRST_PARTY_PACKAGES) throw IllegalArgumentException(\"$callingPackageName is not first-party\")\n        callback.onPostInitCompleteWithConnectionInfo(\n            CommonStatusCodes.SUCCESS,\n            PlayGamesServiceImpl(this, lifecycle, packageName),\n            ConnectionInfo()\n        )\n    }\n}\n\nclass PlayGamesServiceImpl(val context: Context, val lifecycle: Lifecycle, val packageName: String) : IPlayGamesService.Stub() {\n\n    override fun getGameCollection(callbacks: IPlayGamesCallbacks?, maxResults: Int, gameCollectionType: Int, z: Boolean, forceReload: Boolean) {\n        Log.d(TAG, \"Not yet implemented: getGameCollection($maxResults, $gameCollectionType, $z, $forceReload)\")\n        callbacks?.onData(DataHolder.empty(CommonStatusCodes.SUCCESS))\n    }\n\n    override fun loadGames(callbacks: IPlayGamesCallbacks?, playerId: String?, maxResults: Int, z: Boolean, forceReload: Boolean) {\n        Log.d(TAG, \"Not yet implemented: loadGames($playerId, $maxResults, $z, $forceReload)\")\n        callbacks?.onData(DataHolder.empty(CommonStatusCodes.SUCCESS))\n    }\n\n    override fun getConsistencyTokens(): PlayGamesConsistencyTokens {\n        Log.d(TAG, \"Not yet implemented: getConsistencyTokens\")\n        return PlayGamesConsistencyTokens(null, null)\n    }\n\n    override fun updateConsistencyTokens(tokens: PlayGamesConsistencyTokens?) {\n        Log.d(TAG, \"Not yet implemented: updateConsistencyTokens($tokens)\")\n    }\n\n    override fun fun5041(callbacks: IPlayGamesCallbacks?) {\n        callbacks?.onStatus5028(Status.SUCCESS)\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =\n        warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/games/GameProfileSettings.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.games\n\nimport android.content.ContentValues\nimport android.content.Context\nimport android.database.Cursor\nimport org.microg.gms.settings.SettingsContract\n\nobject GameProfileSettings {\n    private fun <T> getSettings(context: Context, vararg projection: String, f: (Cursor) -> T): T = SettingsContract.getSettings(\n        context, SettingsContract.GameProfile.getContentUri(context), projection, f\n    )\n\n    private fun setSettings(context: Context, v: ContentValues.() -> Unit) = SettingsContract.setSettings(context, SettingsContract.GameProfile.getContentUri(context), v)\n\n    @JvmStatic\n    fun setAllowCreatePlayer(context: Context, enabled: Boolean) {\n        setSettings(context) { put(SettingsContract.GameProfile.ALLOW_CREATE_PLAYER, enabled) }\n    }\n\n    @JvmStatic\n    fun setAllowUploadGamePlayed(context: Context, enabled: Boolean) {\n        setSettings(context) { put(SettingsContract.GameProfile.ALLOW_UPLOAD_GAME_PLAYED, enabled) }\n    }\n\n    @JvmStatic\n    fun getAllowCreatePlayer(context: Context): Boolean = getSettings(context, SettingsContract.GameProfile.ALLOW_CREATE_PLAYER) { c -> c.getInt(0) != 0 }\n\n    @JvmStatic\n    fun getAllowUploadGamePlayed(context: Context): Boolean = getSettings(context, SettingsContract.GameProfile.ALLOW_UPLOAD_GAME_PLAYED) { c -> c.getInt(0) != 0 }\n\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/games/GamesConfigurationService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.games\n\nimport android.accounts.Account\nimport android.accounts.AccountManager\nimport android.app.Service\nimport android.content.*\nimport android.os.*\nimport androidx.core.content.getSystemService\nimport androidx.core.os.bundleOf\nimport org.microg.gms.auth.AuthConstants\nimport org.microg.gms.common.PackageUtils\nimport kotlin.coroutines.resume\nimport kotlin.coroutines.resumeWithException\nimport kotlin.coroutines.suspendCoroutine\n\nprivate const val PREFERENCES_NAME = \"games.config\"\nprivate const val PREF_ACCOUNT_GLOBAL = \"account_global\"\nprivate const val PREF_ACCOUNT_PREFIX = \"account_\"\nprivate const val PREF_PLAYER_PREFIX = \"player_\"\n\nprivate const val MSG_GET_DEFAULT_ACCOUNT = 1\nprivate const val MSG_SET_DEFAULT_ACCOUNT = 2\nprivate const val MSG_GET_PLAYER = 3\nprivate const val MSG_SET_PLAYER = 4\nprivate const val MSG_GET_PLAYED_GAMES = 5\n\nprivate const val MSG_DATA_PACKAGE_NAME = \"package_name\"\nprivate const val MSG_DATA_ACCOUNT = \"account\"\nprivate const val MSG_DATA_PLAYER = \"player\"\nprivate const val MSG_DATA_PLAYED_GAMES = \"played_games\"\n\nclass GamesConfigurationService : Service() {\n    private val preferences: SharedPreferences\n        get() = getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE)\n    private val accountManager: AccountManager\n        get() = getSystemService<AccountManager>()!!\n\n    override fun onBind(intent: Intent?): IBinder {\n        return Messenger(object : Handler(Looper.getMainLooper()) {\n            override fun handleMessage(msg: Message) {\n                val data = when (msg.what) {\n                    MSG_GET_DEFAULT_ACCOUNT -> {\n                        val packageName = msg.data?.getString(MSG_DATA_PACKAGE_NAME)\n                        val account = getDefaultAccount(packageName)\n                        bundleOf(\n                            MSG_DATA_PACKAGE_NAME to packageName,\n                            MSG_DATA_ACCOUNT to account\n                        )\n                    }\n\n                    MSG_SET_DEFAULT_ACCOUNT -> {\n                        val packageName = msg.data?.getString(MSG_DATA_PACKAGE_NAME)\n                        val account = msg.data?.getParcelable<Account>(MSG_DATA_ACCOUNT)\n                        setDefaultAccount(packageName, account)\n                        bundleOf(\n                            MSG_DATA_PACKAGE_NAME to packageName,\n                            MSG_DATA_ACCOUNT to account\n                        )\n                    }\n\n                    MSG_GET_PLAYER -> {\n                        val account = msg.data?.getParcelable<Account>(MSG_DATA_ACCOUNT)\n                        val player = if (account != null) getPlayer(account) else null\n                        bundleOf(\n                            MSG_DATA_ACCOUNT to account,\n                            MSG_DATA_PLAYER to player\n                        )\n                    }\n\n                    MSG_SET_PLAYER -> {\n                        val account = msg.data?.getParcelable<Account>(MSG_DATA_ACCOUNT)\n                        val player = msg.data?.getString(MSG_DATA_PLAYER)\n                        if (account != null) setPlayer(account, player)\n                        bundleOf(\n                            MSG_DATA_ACCOUNT to account,\n                            MSG_DATA_PLAYER to player\n                        )\n                    }\n\n                    MSG_GET_PLAYED_GAMES -> {\n                        bundleOf(\n                            MSG_DATA_PLAYED_GAMES to loadPlayedGames()\n                        )\n                    }\n\n                    else -> Bundle.EMPTY\n                }\n                msg.replyTo?.send(Message.obtain().also {\n                    it.what = msg.what\n                    it.data = data\n                })\n            }\n        }).binder\n    }\n\n    private fun getPackageNameSuffix(packageName: String): String {\n        return packageName + \":\" + PackageUtils.firstSignatureDigest(this, packageName)\n    }\n\n    private fun getGlobalDefaultAccount(): Account? {\n        val name = preferences.getString(PREF_ACCOUNT_GLOBAL, null)\n        val accounts: Array<Account> = accountManager.getAccountsByType(AuthConstants.DEFAULT_ACCOUNT_TYPE)\n        for (account in accounts) {\n            if (account.name.equals(name)) return account\n        }\n        return null\n    }\n\n    private fun getDefaultAccount(packageName: String?): Account? {\n        if (packageName == null) return getGlobalDefaultAccount()\n        val name = preferences.getString(PREF_ACCOUNT_PREFIX + getPackageNameSuffix(packageName), null)\n        if (name.isNullOrBlank()) return getGlobalDefaultAccount()\n        val accounts: Array<Account> = accountManager.getAccountsByType(AuthConstants.DEFAULT_ACCOUNT_TYPE)\n        for (account in accounts) {\n            if (account.name.equals(name)) return account\n        }\n        return getGlobalDefaultAccount()\n    }\n\n    private fun setDefaultAccount(packageName: String?, account: Account?) {\n        if (account?.name == getDefaultAccount(packageName)?.name) return\n        val key = if (packageName == null) PREF_ACCOUNT_GLOBAL else (PREF_ACCOUNT_PREFIX + getPackageNameSuffix(packageName))\n        val editor: SharedPreferences.Editor = preferences.edit()\n        if (account?.name == AuthConstants.DEFAULT_ACCOUNT) {\n            val defaultAccount = getDefaultAccount(GAMES_PACKAGE_NAME)\n            editor.putString(key, defaultAccount?.name ?: \"\")\n        } else {\n            editor.putString(key, account?.name ?: \"\")\n        }\n        editor.apply()\n    }\n\n    private fun getPackageAndAccountSuffix(packageName: String, account: Account): String {\n        return getPackageNameSuffix(packageName) + \":\" + account.name\n    }\n\n    private fun getPlayer(account: Account): String? {\n        val player = preferences.getString(PREF_PLAYER_PREFIX + getPackageAndAccountSuffix(GAMES_PACKAGE_NAME, account), null)\n        if (player.isNullOrBlank()) return null\n        return player\n    }\n\n    private fun setPlayer(account: Account, player: String?) {\n        val editor: SharedPreferences.Editor = preferences.edit()\n        if (player.isNullOrBlank()) {\n            editor.remove(PREF_PLAYER_PREFIX + getPackageAndAccountSuffix(GAMES_PACKAGE_NAME, account))\n        } else {\n            editor.putString(PREF_PLAYER_PREFIX + getPackageAndAccountSuffix(GAMES_PACKAGE_NAME, account), player)\n        }\n        editor.apply()\n    }\n\n    private fun loadPlayedGames(): ArrayList<String>? {\n        val packageNames = ArrayList<String>()\n        for (key in preferences.all.keys) {\n            if (key.startsWith(PREF_ACCOUNT_PREFIX)) {\n                val packageName = key.removePrefix(PREF_ACCOUNT_PREFIX).substringBefore(':')\n                if (packageName != GAMES_PACKAGE_NAME) {\n                    packageNames.add(packageName)\n                }\n            }\n        }\n        return packageNames\n    }\n\n    companion object {\n\n        private suspend fun singleRequest(context: Context, message: Message) = suspendCoroutine { continuation ->\n            val connection = object : ServiceConnection {\n                override fun onServiceConnected(name: ComponentName?, service: IBinder?) {\n                    val connection = this\n                    message.replyTo = Messenger(object : Handler(Looper.myLooper() ?: Looper.getMainLooper()) {\n                        override fun handleMessage(msg: Message) {\n                            runCatching { continuation.resume(msg) }\n                            runCatching { context.unbindService(connection) }\n                        }\n                    })\n                    try {\n                        Messenger(service).send(message)\n                    } catch (e: Exception) {\n                        runCatching { continuation.resumeWithException(e) }\n                        runCatching { context.unbindService(connection) }\n                    }\n                }\n\n                override fun onServiceDisconnected(name: ComponentName?) {\n                    runCatching { continuation.resumeWithException(RuntimeException(\"Disconnected\")) }\n                }\n            }\n            val connected = context.bindService(Intent(context, GamesConfigurationService::class.java), connection, BIND_AUTO_CREATE or BIND_ABOVE_CLIENT)\n            if (!connected) {\n                runCatching { continuation.resumeWithException(RuntimeException(\"Connection failed\")) }\n                runCatching { context.unbindService(connection) }\n            }\n        }\n\n        suspend fun getDefaultAccount(context: Context, packageName: String?): Account? {\n            return singleRequest(context, Message.obtain().apply {\n                what = MSG_GET_DEFAULT_ACCOUNT\n                data = bundleOf(\n                    MSG_DATA_PACKAGE_NAME to packageName\n                )\n            }).data?.getParcelable(MSG_DATA_ACCOUNT)\n        }\n\n        suspend fun setDefaultAccount(context: Context, packageName: String?, account: Account?) {\n            singleRequest(context, Message.obtain().apply {\n                what = MSG_SET_DEFAULT_ACCOUNT\n                data = bundleOf(\n                    MSG_DATA_PACKAGE_NAME to packageName,\n                    MSG_DATA_ACCOUNT to account\n                )\n            })\n        }\n\n        suspend fun getPlayer(context: Context, account: Account): String? {\n            return singleRequest(context, Message.obtain().apply {\n                what = MSG_GET_PLAYER\n                data = bundleOf(\n                    MSG_DATA_ACCOUNT to account\n                )\n            }).data?.getString(MSG_DATA_PLAYER)\n        }\n\n        suspend fun setPlayer(context: Context, account: Account, player: String?) {\n            singleRequest(context, Message.obtain().apply {\n                what = MSG_SET_PLAYER\n                data = bundleOf(\n                    MSG_DATA_ACCOUNT to account,\n                    MSG_DATA_PLAYER to player\n                )\n            })\n        }\n\n        suspend fun loadPlayedGames(context: Context): ArrayList<String>? {\n            return singleRequest(context, Message.obtain().apply {\n                what = MSG_GET_PLAYED_GAMES\n            }).data?.getStringArrayList(MSG_DATA_PLAYED_GAMES)\n        }\n\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/games/GamesConnectService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.games\n\nimport android.accounts.Account\nimport android.accounts.AccountManager\nimport android.app.PendingIntent\nimport android.content.Context\nimport android.content.Intent\nimport android.os.Parcel\nimport android.util.Log\nimport androidx.core.app.PendingIntentCompat\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.LifecycleOwner\nimport androidx.lifecycle.lifecycleScope\nimport com.google.android.gms.common.Scopes\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.api.Scope\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.internal.ConnectionInfo\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport com.google.android.gms.games.internal.connect.GamesSignInRequest\nimport com.google.android.gms.games.internal.connect.GamesSignInResponse\nimport com.google.android.gms.games.internal.connect.IGamesConnectCallbacks\nimport com.google.android.gms.games.internal.connect.IGamesConnectService\nimport org.microg.gms.BaseService\nimport org.microg.gms.auth.AuthConstants\nimport org.microg.gms.auth.AuthManager\nimport org.microg.gms.auth.AuthPrefs\nimport org.microg.gms.auth.signin.checkAccountAuthStatus\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.common.PackageUtils\nimport org.microg.gms.utils.warnOnTransactionIssues\nimport java.util.UUID\n\nprivate const val TAG = \"GamesConnectService\"\n\nclass GamesConnectService : BaseService(TAG, GmsService.GAMES) {\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        val packageName = PackageUtils.getAndCheckCallingPackage(this, request.packageName)\n            ?: throw IllegalArgumentException(\"Missing package name\")\n        callback.onPostInitCompleteWithConnectionInfo(\n            CommonStatusCodes.SUCCESS,\n            GamesConnectServiceImpl(this, lifecycle, packageName),\n            ConnectionInfo()\n        )\n    }\n}\n\nclass GamesConnectServiceImpl(val context: Context, override val lifecycle: Lifecycle, val packageName: String) : IGamesConnectService.Stub(), LifecycleOwner {\n\n    override fun signIn(callback: IGamesConnectCallbacks?, request: GamesSignInRequest?) {\n        Log.d(TAG, \"signIn($request)\")\n        suspend fun sendSignInRequired() {\n            val resolution = PendingIntentCompat.getActivity(context, packageName.hashCode(), Intent(context, GamesSignInActivity::class.java).apply {\n                putExtra(EXTRA_GAME_PACKAGE_NAME, packageName)\n                putExtra(EXTRA_ACCOUNT, GamesConfigurationService.getDefaultAccount(context, packageName))\n                putExtra(EXTRA_SCOPES, arrayOf(Scope(Scopes.GAMES_LITE)))\n            }, PendingIntent.FLAG_UPDATE_CURRENT, false)\n            when (request?.signInType) {\n                0 -> { // Manual sign in, provide resolution\n                    callback?.onSignIn(Status(CommonStatusCodes.SIGN_IN_REQUIRED, null, resolution), null)\n                }\n\n                1 -> { // Automatically try to log in with a supported account at startup,\n                    // and provide an account selection solution if verification fails\n                    callback?.onSignIn(Status(CommonStatusCodes.SIGN_IN_REQUIRED, null, resolution), null)\n                }\n\n                else -> {\n                    callback?.onSignIn(Status(CommonStatusCodes.SIGN_IN_REQUIRED), null)\n                }\n            }\n        }\n        lifecycleScope.launchWhenStarted {\n            val status = autoSelectLogin(request)\n            if (status) {\n                Log.d(TAG, \"signIn success\")\n                callback?.onSignIn(Status.SUCCESS, GamesSignInResponse().apply { gameRunToken = UUID.randomUUID().toString() })\n            } else {\n                sendSignInRequired()\n            }\n        }\n    }\n\n    private suspend fun autoSelectLogin(request: GamesSignInRequest?): Boolean {\n        runCatching {\n            var account = request?.previousStepResolutionResult?.resultData?.getParcelableExtra<Account>(EXTRA_ACCOUNT)\n                    ?: GamesConfigurationService.getDefaultAccount(context, packageName)\n            if (account == null && GamesConfigurationService.loadPlayedGames(context)?.any { it == packageName } == true) {\n                Log.d(TAG, \"autoSelectLogin account is null but game is played\")\n                return false\n            }\n            Log.d(TAG, \"autoSelectLogin signInType: ${request?.signInType} account: $account\")\n            if (account == null && request?.signInType == 1) {\n                account = GamesConfigurationService.getDefaultAccount(context, GAMES_PACKAGE_NAME)\n                    ?: AccountManager.get(context).getAccountsByType(AuthConstants.DEFAULT_ACCOUNT_TYPE).find { targetAccount ->\n                        checkAccountAuthStatus(context, packageName, arrayListOf(Scope(Scopes.GAMES_LITE)), targetAccount)\n                    }\n            }\n            if (account == null) {\n                Log.d(TAG, \"autoSelectLogin Accounts is Empty\")\n                return false\n            }\n            Log.d(TAG, \"autoSelectLogin: account: ${account.name}\")\n            val authManager = AuthManager(context, account.name, packageName, \"oauth2:${Scopes.GAMES_LITE}\")\n            if (!authManager.isPermitted && !AuthPrefs.isTrustGooglePermitted(context)) return false\n            val performGamesSignInStatus = performGamesSignIn(context, packageName, account)\n            if (performGamesSignInStatus) {\n                GamesConfigurationService.setDefaultAccount(context, packageName, account)\n            }\n            return performGamesSignInStatus\n        }.onFailure {\n            Log.d(TAG, \"autoSelectLogin fail\", it)\n        }\n        return false\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =\n        warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/games/GamesService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.games\n\nimport android.accounts.Account\nimport android.accounts.AccountManager\nimport android.app.PendingIntent\nimport android.content.Context\nimport android.content.Intent\nimport android.net.Uri\nimport android.os.Bundle\nimport android.os.IBinder\nimport android.os.Parcel\nimport android.os.ParcelFileDescriptor\nimport android.text.TextUtils\nimport android.util.Log\nimport androidx.core.app.PendingIntentCompat\nimport androidx.core.os.bundleOf\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.LifecycleOwner\nimport androidx.lifecycle.lifecycleScope\nimport com.google.android.gms.common.ConnectionResult\nimport com.google.android.gms.common.Scopes\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.api.Scope\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.data.DataHolder\nimport com.google.android.gms.common.internal.ConnectionInfo\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport com.google.android.gms.drive.Contents\nimport com.google.android.gms.drive.DriveId\nimport com.google.android.gms.games.GameColumns\nimport com.google.android.gms.games.GamesStatusCodes\nimport com.google.android.gms.games.Player\nimport com.google.android.gms.games.PlayerColumns\nimport com.google.android.gms.games.PlayerEntity\nimport com.google.android.gms.games.internal.IGamesCallbacks\nimport com.google.android.gms.games.internal.IGamesClient\nimport com.google.android.gms.games.internal.IGamesService\nimport com.google.android.gms.games.snapshot.SnapshotColumns\nimport com.google.android.gms.games.snapshot.SnapshotMetadataChangeEntity\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\nimport org.json.JSONObject\nimport org.microg.gms.BaseService\nimport org.microg.gms.auth.AuthConstants\nimport org.microg.gms.auth.AuthManager\nimport org.microg.gms.auth.AuthPrefs\nimport org.microg.gms.auth.signin.checkAccountAuthStatus\nimport org.microg.gms.common.Constants\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.common.PackageUtils\nimport org.microg.gms.games.achievements.AchievementsApiClient\nimport org.microg.gms.games.snapshot.SnapshotsDataClient\nimport org.microg.gms.games.utils.AccountPromptManager\nimport org.microg.gms.utils.warnOnTransactionIssues\nimport java.io.File\nimport java.io.FileOutputStream\nimport java.util.regex.Pattern\n\nprivate const val TAG = \"GamesService\"\n\nclass GamesService : BaseService(TAG, GmsService.GAMES) {\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        val packageName = PackageUtils.getAndCheckCallingPackageOrImpersonation(this, request.packageName)\n            ?: throw IllegalArgumentException(\"Missing package name\")\n\n        fun sendSignInRequired(account: Account? = null) {\n            Log.d(TAG, \"Sending SIGN_IN_REQUIRED to $packageName\")\n            callback.onPostInitCompleteWithConnectionInfo(ConnectionResult.SIGN_IN_REQUIRED, null, ConnectionInfo().apply {\n                params = bundleOf(\n                    \"pendingIntent\" to PendingIntentCompat.getActivity(\n                        this@GamesService,\n                        packageName.hashCode(),\n                        Intent(this@GamesService, GamesSignInActivity::class.java).apply {\n                            putExtra(EXTRA_GAME_PACKAGE_NAME, request.packageName)\n                            putExtra(EXTRA_ACCOUNT, account)\n                            putExtra(EXTRA_SCOPES, request.scopes)\n                        },\n                        PendingIntent.FLAG_UPDATE_CURRENT,\n                        false\n                    )\n                )\n            })\n        }\n\n        lifecycleScope.launchWhenStarted {\n            try {\n                val scopes = request.scopes.toList().realScopes\n                Log.d(TAG, \"handleServiceRequest scopes to ${scopes.joinToString(\" \")}\")\n\n                Log.d(TAG, \"handleServiceRequest request.account ${request.account?.name}\")\n                var currentAccount = if (request.account?.name == AuthConstants.DEFAULT_ACCOUNT) {\n                    GamesConfigurationService.getDefaultAccount(this@GamesService, packageName)\n                } else {\n                    request.account\n                }\n\n                Log.d(TAG, \"handleServiceRequest currentAccount to ${currentAccount?.name}\")\n                val account = currentAccount\n                    ?: GamesConfigurationService.getDefaultAccount(this@GamesService, GAMES_PACKAGE_NAME)\n                    ?: AccountManager.get(this@GamesService).getAccountsByType(AuthConstants.DEFAULT_ACCOUNT_TYPE).find { targetAccount ->\n                        checkAccountAuthStatus(this@GamesService, packageName, arrayListOf(Scope(Scopes.GAMES_LITE)), targetAccount) }\n                    ?: return@launchWhenStarted sendSignInRequired()\n\n                Log.d(TAG, \"handleServiceRequest account to ${account.name}\")\n\n                val authManager = AuthManager(this@GamesService, account.name, packageName, \"oauth2:${scopes.joinToString(\" \")}\")\n                if (!authManager.isPermitted && !AuthPrefs.isTrustGooglePermitted(this@GamesService)) {\n                    Log.d(TAG, \"Not permitted to use $account for ${scopes.toList()}, sign in required\")\n                    return@launchWhenStarted sendSignInRequired(account)\n                }\n\n                if (!performGamesSignIn(this@GamesService, packageName, account, scopes = scopes)) {\n                    Log.d(TAG, \"performGamesSignIn fail, sign in required\")\n                    return@launchWhenStarted sendSignInRequired(account)\n                }\n\n                GamesConfigurationService.setDefaultAccount(this@GamesService, packageName, account)\n\n                val player = JSONObject(GamesConfigurationService.getPlayer(this@GamesService, account)).toPlayer()\n\n                var showConnectingPopup = request.extras.getBoolean(EXTRA_SHOW_CONNECTING_POPUP, false)\n                if (showConnectingPopup) {\n                    Log.d(TAG, \"handleServiceRequest: showConnectingPopup\")\n                    AccountPromptManager.getInstance(this@GamesService).show(player.displayName, player.iconImageUrl)\n                }\n\n                callback.onPostInitCompleteWithConnectionInfo(\n                    CommonStatusCodes.SUCCESS,\n                    GamesServiceImpl(this@GamesService, lifecycle, packageName, account, player),\n                    ConnectionInfo()\n                )\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n                runCatching { callback.onPostInitCompleteWithConnectionInfo(ConnectionResult.INTERNAL_ERROR, null, null) }\n            }\n        }\n    }\n}\n\nclass GamesServiceImpl(val context: Context, override val lifecycle: Lifecycle, val packageName: String, val account: Account, val player: Player) :\n    IGamesService.Stub(), LifecycleOwner {\n\n    private val pattern: Pattern = Pattern.compile(\"[0-9a-zA-Z-._~]{1,100}\")\n    private var saveName: String? = null\n\n    override fun clientDisconnecting(clientId: Long) {\n        Log.d(TAG, \"Not yet implemented: clientDisconnecting($clientId)\")\n    }\n\n    override fun signOut(callbacks: IGamesCallbacks?) {\n        Log.d(TAG, \"signOut called\")\n        lifecycleScope.launchWhenStarted {\n            GamesConfigurationService.setDefaultAccount(context, packageName, null)\n            callbacks?.onSignOutComplete()\n        }\n    }\n\n    override fun getAppId(): String? {\n        Log.d(TAG, \"Not yet implemented: getAppId\")\n        return null\n    }\n\n    override fun getConnectionHint(): Bundle? {\n        return null\n    }\n\n    override fun showWelcomePopup(windowToken: IBinder?, extraArgs: Bundle?) {\n        runCatching { extraArgs?.keySet() }\n        Log.d(TAG, \"Not yet implemented: showWelcomePopup($windowToken, $extraArgs)\")\n    }\n\n    override fun cancelPopups() {\n        Log.d(TAG, \"Not yet implemented: cancelPopups\")\n    }\n\n    override fun getCurrentAccountName(): String? {\n        Log.d(TAG, \"getCurrentAccountName called: ${account.name}\")\n        return account.name\n    }\n\n    override fun loadGameplayAclInternal(callbacks: IGamesCallbacks?, gameId: String?) {\n        Log.d(TAG, \"Not yet implemented: loadGameplayAclInternal($gameId)\")\n    }\n\n    override fun updateGameplayAclInternal(callbacks: IGamesCallbacks?, gameId: String?, aclData: String?) {\n        Log.d(TAG, \"Not yet implemented: updateGameplayAclInternal($gameId, $aclData)\")\n    }\n\n    override fun loadFAclInternal(callbacks: IGamesCallbacks?, gameId: String?) {\n        Log.d(TAG, \"Not yet implemented: loadFAclInternal($gameId)\")\n    }\n\n    override fun updateFAclInternal(callbacks: IGamesCallbacks?, gameId: String?, allCirclesVisible: Boolean, circleIds: LongArray?) {\n        Log.d(TAG, \"Not yet implemented: updateFAclInternal($gameId, $allCirclesVisible, $circleIds)\")\n    }\n\n    override fun getCurrentPlayerId(): String? {\n        Log.d(TAG, \"getCurrentPlayerId called: ${player.playerId}\")\n        return player.playerId\n    }\n\n    override fun getCurrentPlayer(): DataHolder? {\n        return if (player is PlayerEntity) {\n            DataHolder.builder(PlayerColumns.CURRENT_PLAYER_COLUMNS.toTypedArray()).withRow(player.toContentValues()).build(CommonStatusCodes.SUCCESS)\n        } else {\n            DataHolder.builder(PlayerColumns.CURRENT_PLAYER_COLUMNS.toTypedArray()).build(CommonStatusCodes.SIGN_IN_REQUIRED)\n        }\n    }\n\n    override fun loadPlayer(callbacks: IGamesCallbacks?, playerId: String?) {\n        Log.d(TAG, \"Not yet implemented: loadPlayer($playerId)\")\n    }\n\n    override fun loadInvitablePlayers(callbacks: IGamesCallbacks?, pageSize: Int, expandCachedData: Boolean, forceReload: Boolean) {\n        Log.d(TAG, \"Not yet implemented: loadInvitablePlayers($pageSize, $expandCachedData, $forceReload)\")\n    }\n\n    override fun submitScore(callbacks: IGamesCallbacks?, leaderboardId: String?, score: Long) {\n        Log.d(TAG, \"Not yet implemented: submitScore($leaderboardId, $score)\")\n    }\n\n    override fun loadLeaderboards(callbacks: IGamesCallbacks?) {\n        Log.d(TAG, \"Not yet implemented: loadLeaderboards\")\n    }\n\n    override fun loadLeaderboard(callbacks: IGamesCallbacks?, leaderboardId: String?) {\n        Log.d(TAG, \"Not yet implemented: loadLeaderboard($leaderboardId)\")\n    }\n\n    override fun loadTopScores(\n        callbacks: IGamesCallbacks?,\n        leaderboardId: String?,\n        span: Int,\n        leaderboardCollection: Int,\n        maxResults: Int,\n        forceReload: Boolean\n    ) {\n        Log.d(TAG, \"Not yet implemented: loadTopScores($leaderboardId, $span, $leaderboardCollection, $maxResults, $forceReload)\")\n    }\n\n    override fun loadPlayerCenteredScores(\n        callbacks: IGamesCallbacks?,\n        leaderboardId: String?,\n        span: Int,\n        leaderboardCollection: Int,\n        maxResults: Int,\n        forceReload: Boolean\n    ) {\n        Log.d(TAG, \"Not yet implemented: loadPlayerCenteredScores($leaderboardId, $span, $leaderboardCollection, $maxResults, $forceReload)\")\n    }\n\n    override fun loadMoreScores(callbacks: IGamesCallbacks?, previousheader: Bundle?, maxResults: Int, pageDirection: Int) {\n        runCatching { previousheader?.keySet() }\n        Log.d(TAG, \"Not yet implemented: loadMoreScores($previousheader, $maxResults, $pageDirection)\")\n    }\n\n    override fun loadAchievements(callbacks: IGamesCallbacks?) {\n        loadAchievementsV2(callbacks, false)\n    }\n\n    override fun revealAchievement(callbacks: IGamesCallbacks?, achievementId: String, windowToken: IBinder?, extraArgs: Bundle?) {\n        Log.d(TAG, \"Method revealAchievement($achievementId, $windowToken, $extraArgs) Called\")\n        lifecycleScope.launchWhenStarted {\n            runCatching {\n                val authResponse = withContext(Dispatchers.IO) {\n                    AuthManager(context, account.name, packageName, SERVICE_GAMES_LITE).apply { isPermitted = true }.requestAuth(true)\n                }\n                var oauthToken: String? = null\n                if (authResponse.auth?.let { oauthToken = it } == null) {\n                    throw RuntimeException(\"oauthToken is null\")\n                }\n                AchievementsApiClient.revealAchievement(context, oauthToken!!, achievementId)\n                callbacks?.onAchievementUpdated(Status.SUCCESS.statusCode, achievementId)\n            }.onFailure {\n                Log.d(TAG, \"revealAchievement: error\", it)\n                callbacks?.onAchievementUpdated(Status.INTERNAL_ERROR.statusCode, achievementId)\n            }\n        }\n    }\n\n    override fun unlockAchievement(callbacks: IGamesCallbacks?, achievementId: String, windowToken: IBinder?, extraArgs: Bundle?) {\n        Log.d(TAG, \"Method unlockAchievement($achievementId, $windowToken, $extraArgs) Called\")\n        lifecycleScope.launchWhenStarted {\n            runCatching {\n                val authResponse = withContext(Dispatchers.IO) {\n                    AuthManager(context, account.name, packageName, SERVICE_GAMES_LITE).apply { isPermitted = true }.requestAuth(true)\n                }\n                var oauthToken: String? = null\n                if (authResponse.auth?.let { oauthToken = it } == null) {\n                    throw RuntimeException(\"oauthToken is null\")\n                }\n                AchievementsApiClient.unlockAchievement(context, oauthToken!!, achievementId)\n                callbacks?.onAchievementUpdated(Status.SUCCESS.statusCode, achievementId)\n            }.onFailure {\n                Log.d(TAG, \"unlockAchievement: error\", it)\n                callbacks?.onAchievementUpdated(Status.INTERNAL_ERROR.statusCode, achievementId)\n            }\n        }\n    }\n\n    override fun incrementAchievement(callbacks: IGamesCallbacks?, achievementId: String, numSteps: Int, windowToken: IBinder?, extraArgs: Bundle?) {\n        Log.d(TAG, \"Method: incrementAchievement($achievementId, $numSteps, $windowToken, $extraArgs) Called\")\n        lifecycleScope.launchWhenStarted {\n            runCatching {\n                val authResponse = withContext(Dispatchers.IO) {\n                    AuthManager(context, account.name, packageName, SERVICE_GAMES_LITE).apply { isPermitted = true }.requestAuth(true)\n                }\n                var oauthToken: String? = null\n                if (authResponse.auth?.let { oauthToken = it } == null) {\n                    throw RuntimeException(\"oauthToken is null\")\n                }\n                AchievementsApiClient.incrementAchievement(context, oauthToken!!, achievementId, numSteps)\n                callbacks?.onAchievementUpdated(Status.SUCCESS.statusCode, achievementId)\n            }.onFailure {\n                Log.d(TAG, \"incrementAchievement: error\", it)\n                callbacks?.onAchievementUpdated(Status.INTERNAL_ERROR.statusCode, achievementId)\n            }\n        }\n    }\n\n    override fun loadGame(callbacks: IGamesCallbacks?) {\n        Log.d(TAG, \"Not yet implemented: loadGame\")\n    }\n\n    override fun loadInvitations(callbacks: IGamesCallbacks?) {\n        Log.d(TAG, \"Not yet implemented: loadInvitations\")\n    }\n\n    override fun declineInvitation(invitationId: String?, invitationType: Int) {\n        Log.d(TAG, \"Not yet implemented: declineInvitation($invitationId, $invitationType)\")\n    }\n\n    override fun dismissInvitation(invitationId: String?, invitationType: Int) {\n        Log.d(TAG, \"Not yet implemented: dismissInvitation($invitationId, $invitationType)\")\n    }\n\n    override fun createRoom(\n        callbacks: IGamesCallbacks?,\n        processBinder: IBinder?,\n        variant: Int,\n        invitedPlayerIds: Array<out String>?,\n        autoMatchCriteria: Bundle?,\n        enableSockets: Boolean,\n        clientId: Long\n    ) {\n        Log.d(TAG, \"Not yet implemented: createRoom($variant, $invitedPlayerIds, $autoMatchCriteria, $enableSockets, $clientId)\")\n    }\n\n    override fun joinRoom(callbacks: IGamesCallbacks?, processBinder: IBinder?, matchId: String?, enableSockets: Boolean, clientId: Long) {\n        Log.d(TAG, \"Not yet implemented: joinRoom($matchId, $enableSockets, $clientId)\")\n    }\n\n    override fun leaveRoom(callbacks: IGamesCallbacks?, matchId: String?) {\n        Log.d(TAG, \"Not yet implemented: leaveRoom($matchId)\")\n    }\n\n    override fun sendReliableMessage(callbacks: IGamesCallbacks?, messageData: ByteArray?, matchId: String?, recipientParticipantId: String?): Int {\n        Log.d(TAG, \"Not yet implemented: sendReliableMessage($messageData, $matchId, $recipientParticipantId)\")\n        return 0\n    }\n\n    override fun sendUnreliableMessage(messageData: ByteArray?, matchId: String?, recipientParticipantIds: Array<out String>?): Int {\n        Log.d(TAG, \"Not yet implemented: sendUnreliableMessage($messageData, $matchId, $recipientParticipantIds)\")\n        return 0\n    }\n\n    override fun createSocketConnection(participantId: String?): String? {\n        Log.d(TAG, \"Not yet implemented: createSocketConnection($participantId)\")\n        return null\n    }\n\n    override fun clearNotifications(notificationTypes: Int) {\n        Log.d(TAG, \"Not yet implemented: clearNotifications($notificationTypes)\")\n    }\n\n    override fun loadLeaderboardsFirstParty(callbacks: IGamesCallbacks?, gameId: String?) {\n        Log.d(TAG, \"Not yet implemented: loadLeaderboardsFirstParty($gameId)\")\n    }\n\n    override fun loadLeaderboardFirstParty(callbacks: IGamesCallbacks?, gameId: String?, leaderboardId: String?) {\n        Log.d(TAG, \"Not yet implemented: loadLeaderboardFirstParty($gameId, $leaderboardId)\")\n    }\n\n    override fun loadTopScoresFirstParty(\n        callbacks: IGamesCallbacks?,\n        gameId: String?,\n        leaderboardId: String?,\n        span: Int,\n        leaderboardCollection: Int,\n        maxResults: Int,\n        forceReload: Boolean\n    ) {\n        Log.d(TAG, \"Not yet implemented: loadTopScoresFirstParty($gameId, $leaderboardId, $span, $leaderboardCollection, $maxResults, $forceReload)\")\n    }\n\n    override fun loadPlayerCenteredScoresFirstParty(\n        callbacks: IGamesCallbacks?,\n        gameId: String?,\n        leaderboardId: String?,\n        span: Int,\n        leaderboardCollection: Int,\n        maxResults: Int,\n        forceReload: Boolean\n    ) {\n        Log.d(TAG, \"Not yet implemented: loadPlayerCenteredScoresFirstParty($gameId, $leaderboardId, $span, $leaderboardCollection, $maxResults, $forceReload)\")\n    }\n\n    override fun loadAchievementsFirstParty(callbacks: IGamesCallbacks?, playerId: String?, gameId: String?) {\n        Log.d(TAG, \"Not yet implemented: loadAchievementsFirstParty($playerId, $gameId)\")\n    }\n\n    override fun loadGameFirstParty(callbacks: IGamesCallbacks?, gameId: String?) {\n        Log.d(TAG, \"Not yet implemented: loadGameFirstParty($gameId)\")\n    }\n\n    override fun loadGameInstancesFirstParty(callbacks: IGamesCallbacks?, gameId: String?) {\n        Log.d(TAG, \"Not yet implemented: loadGameInstancesFirstParty($gameId)\")\n    }\n\n    override fun loadGameCollectionFirstParty(\n        callbacks: IGamesCallbacks?,\n        pageSize: Int,\n        collectionType: Int,\n        expandCachedData: Boolean,\n        forceReload: Boolean\n    ) {\n        Log.d(TAG, \"Not yet implemented: loadGameCollectionFirstParty($pageSize, $collectionType, $expandCachedData, $forceReload)\")\n    }\n\n    override fun loadRecentlyPlayedGamesFirstParty(\n        callbacks: IGamesCallbacks?,\n        externalPlayerId: String?,\n        pageSize: Int,\n        expandCachedData: Boolean,\n        forceReload: Boolean\n    ) {\n        Log.d(TAG, \"Not yet implemented: loadRecentlyPlayedGamesFirstParty($externalPlayerId, $pageSize, $expandCachedData, $forceReload)\")\n    }\n\n    override fun loadInvitablePlayersFirstParty(callbacks: IGamesCallbacks?, pageSize: Int, expandCachedData: Boolean, forceReload: Boolean) {\n        Log.d(TAG, \"Not yet implemented: loadInvitablePlayersFirstParty($pageSize, $expandCachedData, $forceReload)\")\n    }\n\n    override fun loadRecentPlayersFirstParty(callbacks: IGamesCallbacks?) {\n        Log.d(TAG, \"Not yet implemented: loadRecentPlayersFirstParty\")\n    }\n\n    override fun loadCircledPlayersFirstParty(callbacks: IGamesCallbacks?, pageSize: Int, expandCachedData: Boolean, forceReload: Boolean) {\n        Log.d(TAG, \"Not yet implemented: loadCircledPlayersFirstParty($pageSize, $expandCachedData, $forceReload)\")\n    }\n\n    override fun loadSuggestedPlayersFirstParty(callbacks: IGamesCallbacks?) {\n        Log.d(TAG, \"Not yet implemented: loadSuggestedPlayersFirstParty\")\n    }\n\n    override fun dismissPlayerSuggestionFirstParty(playerIdToDismiss: String?) {\n        Log.d(TAG, \"Not yet implemented: dismissPlayerSuggestionFirstParty($playerIdToDismiss)\")\n    }\n\n    override fun declineInvitationFirstParty(gameId: String?, invitationId: String?, invitationType: Int) {\n        Log.d(TAG, \"Not yet implemented: declineInvitationFirstParty($gameId, $invitationId, $invitationType)\")\n    }\n\n    override fun loadInvitationsFirstParty(callbacks: IGamesCallbacks?, gameId: String?) {\n        Log.d(TAG, \"Not yet implemented: loadInvitationsFirstParty($gameId)\")\n    }\n\n    override fun registerWaitingRoomListenerRestricted(callbacks: IGamesCallbacks?, roomId: String?): Int {\n        Log.d(TAG, \"Not yet implemented: registerWaitingRoomListenerRestricted($roomId)\")\n        return 0\n    }\n\n    override fun setGameMuteStatusInternal(callbacks: IGamesCallbacks?, gameId: String?, muted: Boolean) {\n        Log.d(TAG, \"Not yet implemented: setGameMuteStatusInternal($gameId, $muted)\")\n    }\n\n    override fun clearNotificationsFirstParty(gameId: String?, notificationTypes: Int) {\n        Log.d(TAG, \"Not yet implemented: clearNotificationsFirstParty($gameId, $notificationTypes)\")\n    }\n\n    override fun loadNotifyAclInternal(callbacks: IGamesCallbacks?) {\n        Log.d(TAG, \"Not yet implemented: loadNotifyAclInternal\")\n    }\n\n    override fun updateNotifyAclInternal(callbacks: IGamesCallbacks?, aclData: String?) {\n        Log.d(TAG, \"Not yet implemented: updateNotifyAclInternal($aclData)\")\n    }\n\n    override fun registerInvitationListener(callbacks: IGamesCallbacks?, clientId: Long) {\n        Log.d(TAG, \"Not yet implemented: registerInvitationListener($clientId)\")\n    }\n\n    override fun unregisterInvitationListener(clientId: Long) {\n        Log.d(TAG, \"Not yet implemented: unregisterInvitationListener($clientId)\")\n    }\n\n    override fun unregisterWaitingRoomListenerRestricted(roomId: String?): Int {\n        Log.d(TAG, \"Not yet implemented: unregisterWaitingRoomListenerRestricted($roomId)\")\n        return 0\n    }\n\n    override fun isGameMutedInternal(callbacks: IGamesCallbacks?, gameId: String?) {\n        Log.d(TAG, \"Not yet implemented: isGameMutedInternal($gameId)\")\n    }\n\n    override fun loadContactSettingsInternal(callbacks: IGamesCallbacks?) {\n        Log.d(TAG, \"Not yet implemented: loadContactSettingsInternal\")\n    }\n\n    override fun updateContactSettingsInternal(callbacks: IGamesCallbacks?, enableMobileNotifications: Boolean) {\n        Log.d(TAG, \"Not yet implemented: updateContactSettingsInternal($enableMobileNotifications)\")\n    }\n\n    override fun getSelectedAccountForGameFirstParty(gamePackageName: String?): String? {\n        Log.d(TAG, \"Not yet implemented: getSelectedAccountForGameFirstParty($gamePackageName)\")\n        return null\n    }\n\n    override fun updateSelectedAccountForGameFirstParty(gamePackageName: String?, accountName: String?) {\n        Log.d(TAG, \"Not yet implemented: updateSelectedAccountForGameFirstParty($gamePackageName, $accountName)\")\n    }\n\n    override fun getGamesContentUriRestricted(gameId: String?): Uri? {\n        Log.d(TAG, \"Not yet implemented: getGamesContentUriRestricted($gameId)\")\n        return null\n    }\n\n    override fun shouldUseNewPlayerNotificationsFirstParty(): Boolean {\n        Log.d(TAG, \"Not yet implemented: shouldUseNewPlayerNotificationsFirstParty\")\n        return false\n    }\n\n    override fun setUseNewPlayerNotificationsFirstParty(newPlayerStyle: Boolean) {\n        Log.d(TAG, \"Not yet implemented: setUseNewPlayerNotificationsFirstParty($newPlayerStyle)\")\n    }\n\n    override fun searchForPlayersFirstParty(callbacks: IGamesCallbacks?, query: String?, pageSize: Int, expandCachedData: Boolean, forceReload: Boolean) {\n        Log.d(TAG, \"Not yet implemented: searchForPlayersFirstParty($query, $pageSize, $expandCachedData, $forceReload)\")\n    }\n\n    override fun getCurrentGame(): DataHolder? {\n        Log.d(TAG, \"Not yet implemented: getCurrentGame\")\n        return null\n    }\n\n    override fun loadAchievementsV2(callbacks: IGamesCallbacks?, forceReload: Boolean) {\n        Log.d(TAG, \"Not yet implemented: loadAchievementsV2($forceReload)\")\n        callbacks?.onAchievementsLoaded(DataHolder.empty(CommonStatusCodes.SUCCESS))\n    }\n\n    override fun submitLeaderboardScore(callbacks: IGamesCallbacks?, leaderboardId: String?, score: Long, scoreTag: String?) {\n        Log.d(TAG, \"Not yet implemented: submitLeaderboardScore($leaderboardId, $score, $scoreTag)\")\n    }\n\n    override fun setAchievementSteps(callbacks: IGamesCallbacks?, achievementId: String, numSteps: Int, windowToken: IBinder?, extras: Bundle?) {\n        Log.d(TAG, \"Method setAchievementSteps($achievementId, $numSteps, $windowToken, $extras) called\")\n        lifecycleScope.launchWhenStarted {\n            runCatching {\n                val authResponse = withContext(Dispatchers.IO) {\n                    AuthManager(context, account.name, packageName, SERVICE_GAMES_LITE).apply { isPermitted = true }.requestAuth(true)\n                }\n                var oauthToken: String? = null\n                if (authResponse.auth?.let { oauthToken = it } == null) {\n                    throw RuntimeException(\"oauthToken is null\")\n                }\n                AchievementsApiClient.setStepsAtLeast(context, oauthToken!!, achievementId, numSteps)\n                callbacks?.onAchievementUpdated(Status.SUCCESS.statusCode, achievementId)\n            }.onFailure {\n                Log.d(TAG, \"setAchievementSteps: error\", it)\n                callbacks?.onAchievementUpdated(Status.INTERNAL_ERROR.statusCode, achievementId)\n            }\n        }\n    }\n\n    private fun getGamesIntent(action: String, block: Intent.() -> Unit = {}) = Intent(action).apply {\n        // Jump to internal page implementation\n        setPackage(Constants.GMS_PACKAGE_NAME)\n        putExtra(EXTRA_ACCOUNT_KEY, Integer.toHexString(account.name.hashCode()))\n        putExtra(EXTRA_GAME_PACKAGE_NAME, packageName)\n        addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)\n        block()\n    }\n\n    override fun getAllLeaderboardsIntent(): Intent = getGamesIntent(ACTION_VIEW_LEADERBOARDS)\n\n    override fun getAchievementsIntent(): Intent = getGamesIntent(ACTION_VIEW_ACHIEVEMENTS)\n\n    override fun getPlayerSearchIntent(): Intent = getGamesIntent(ACTION_PLAYER_SEARCH)\n\n    override fun getSelectSnapshotIntent(\n        title: String?,\n        allowAddButton: Boolean,\n        allowDelete: Boolean,\n        maxSnapshots: Int\n    ): Intent {\n        Log.d(TAG, \"Method getSelectSnapshotIntent($title, $allowAddButton, $allowDelete, $maxSnapshots) called\")\n        return getGamesIntent(ACTION_VIEW_SNAPSHOTS) {\n            putExtra(EXTRA_TITLE, title)\n            putExtra(EXTRA_ALLOW_CREATE_SNAPSHOT, allowAddButton)\n            putExtra(EXTRA_ALLOW_DELETE_SNAPSHOT, allowDelete)\n            putExtra(EXTRA_MAX_SNAPSHOTS, maxSnapshots)\n        }\n    }\n\n    override fun loadSnapshots(callbacks: IGamesCallbacks?, forceReload: Boolean) {\n        Log.d(TAG, \"Method loadSnapshots(forceReload:$forceReload) called\")\n    }\n\n    override fun commitSnapshot(\n        callbacks: IGamesCallbacks?,\n        str: String?,\n        change: SnapshotMetadataChangeEntity?,\n        contents: Contents?\n    ) {\n        Log.d(TAG, \"Method commitSnapshot(str:$str, change:$change, dvd:$contents)\")\n        lifecycleScope.launchWhenStarted {\n            if (change != null && contents?.parcelFileDescriptor != null) {\n                runCatching {\n                    val authResponse = withContext(Dispatchers.IO) {\n                        AuthManager(context, account.name, packageName, \"$SERVICE_GAMES_LITE ${Scopes.DRIVE_APPFOLDER}\").apply { isPermitted = true }.requestAuth(true)\n                    }\n                    var oauthToken: String? = null\n                    if (authResponse.auth?.let { oauthToken = it } == null) {\n                        throw RuntimeException(\"oauthToken is null\")\n                    }\n                    val result = SnapshotsDataClient.get(context).commitSnapshot(oauthToken!!, saveName, change, contents, maxCoverImageSize)\n                    if (result == true) {\n                        callbacks?.commitSnapshotResult(DataHolder.empty(GamesStatusCodes.OK.code))\n                    } else {\n                        callbacks?.commitSnapshotResult(DataHolder.empty(GamesStatusCodes.SNAPSHOT_COMMIT_FAILED.code))\n                    }\n                }.onFailure {\n                    Log.w(TAG, \"commitSnapshot: error\", it)\n                    callbacks?.commitSnapshotResult(DataHolder.empty(GamesStatusCodes.SNAPSHOT_COMMIT_FAILED.code))\n                }\n            } else {\n                callbacks?.commitSnapshotResult(DataHolder.empty(GamesStatusCodes.SNAPSHOT_COMMIT_FAILED.code))\n            }\n        }\n    }\n\n    override fun loadEvents(callbacks: IGamesCallbacks?, forceReload: Boolean) {\n        Log.d(TAG, \"Not yet implemented: loadEvents($forceReload)\")\n    }\n\n    override fun incrementEvent(eventId: String?, incrementAmount: Int) {\n        Log.d(TAG, \"Not yet implemented: incrementEvent($eventId, $incrementAmount)\")\n    }\n\n    override fun discardAndCloseSnapshot(contents: Contents?) {\n        Log.d(TAG, \"discardAndCloseSnapshot: $contents\")\n    }\n\n    override fun loadEventsById(callbacks: IGamesCallbacks?, forceReload: Boolean, eventsIds: Array<out String>?) {\n        Log.d(TAG, \"Not yet implemented: loadEventsById($forceReload, $eventsIds)\")\n    }\n\n    override fun getMaxDataSize(): Int {\n        Log.d(TAG, \"getMaxDataSize: \")\n        return 3 * 1024 * 1024\n    }\n\n    override fun getMaxCoverImageSize(): Int {\n        Log.d(TAG, \"getMaxCoverImageSize: \")\n        return 800 * 1024\n    }\n\n    override fun resolveSnapshotHead(callbacks: IGamesCallbacks, saveName: String?, i: Int) {\n        Log.d(TAG, \"Method resolveSnapshotHead $saveName, $i\")\n        if (TextUtils.isEmpty(saveName)) {\n            Log.w(TAG, \"resolveSnapshotHead: Must provide a non empty fileName!\")\n            return\n        }\n        if (!pattern.matcher(saveName).matches()) {\n            Log.w(TAG, \"resolveSnapshotHead: Must provide a valid file name!\")\n            return\n        }\n        val driveId = DriveId(null, 30, 0, DriveId.RESOURCE_TYPE_FILE)\n        val file = File.createTempFile(\"blob\", \".tmp\", context.filesDir)\n        this.saveName = saveName\n        lifecycleScope.launchWhenStarted {\n            runCatching {\n                val authResponse = withContext(Dispatchers.IO) {\n                    AuthManager(context, account.name, packageName, SERVICE_GAMES_LITE).apply { isPermitted = true }.requestAuth(true)\n                }\n                var oauthToken: String? = null\n                if (authResponse.auth?.let { oauthToken = it } == null) {\n                    throw RuntimeException(\"oauthToken is null\")\n                }\n                val resolveSnapshotHeadRequest = ResolveSnapshotHeadRequest.Builder().apply {\n                    this.snapshotName = saveName\n                    unknownFileInt2 = 5\n                    unknownFileInt3 = 3\n                }.build()\n                val resolveSnapshotHeadResponse = SnapshotsDataClient.get(context).resolveSnapshotHead(oauthToken!!, resolveSnapshotHeadRequest)\n                val contentUrl = resolveSnapshotHeadResponse?.snapshotMetadata?.snapshot?.snapshotContentInfo?.url\n                if (contentUrl != null) {\n                    val contentByteArray = SnapshotsDataClient.get(context).getDataFromDrive(oauthToken!!, contentUrl)\n                    val fileOutputStream = FileOutputStream(file)\n                    fileOutputStream.write(contentByteArray)\n                }\n                val columns = PlayerColumns.CURRENT_PLAYER_COLUMNS.toTypedArray() +\n                        GameColumns.CURRENT_GAME_COLUMNS.toTypedArray() +\n                        SnapshotColumns.CURRENT_GAME_COLUMNS.toTypedArray()\n                val dataHolder = if (player is PlayerEntity) {\n                    DataHolder.builder(columns)\n                        .withRow(player.toContentValues()).build(CommonStatusCodes.SUCCESS)\n                } else {\n                    DataHolder.builder(columns).build(CommonStatusCodes.SIGN_IN_REQUIRED)\n                }\n                callbacks.onResolveSnapshotHead(dataHolder, Contents(ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_WRITE), 1, ParcelFileDescriptor.MODE_READ_WRITE, driveId, true, null))\n            }.onFailure {\n                callbacks.onResolveSnapshotHead(DataHolder.empty(GamesStatusCodes.SNAPSHOT_COMMIT_FAILED.code), null)\n            }\n        }\n    }\n\n    override fun registerEventClient(callback: IGamesClient?, clientId: Long) {\n        Log.d(TAG, \"Not yet implemented: registerEventClient($clientId)\")\n    }\n\n    private fun getCompareProfileIntent(playerId: String, block: Intent.() -> Unit = {}): Intent = getGamesIntent(ACTION_VIEW_PROFILE) {\n        putExtra(EXTRA_IS_SELF, playerId == currentPlayerId)\n        putExtra(EXTRA_ACCOUNT, currentAccount)\n        block()\n    }\n\n    override fun getCompareProfileIntentForPlayer(player: PlayerEntity): Intent = getCompareProfileIntent(player.playerId) {\n        putExtra(EXTRA_PLAYER, player)\n    }\n\n    override fun loadPlayerStats(callbacks: IGamesCallbacks?, forceReload: Boolean) {\n        Log.d(TAG, \"Not yet implemented: loadPlayerStats($forceReload)\")\n    }\n\n    override fun getLeaderboardsScoresIntent(leaderboardId: String?, timeSpan: Int, collection: Int): Intent {\n        Log.d(TAG, \"Method getLeaderboardsScoresIntent Called: timeSpan:$timeSpan collection:$collection\")\n        return getGamesIntent(ACTION_VIEW_LEADERBOARDS_SCORES) {\n            putExtra(EXTRA_LEADERBOARD_ID, leaderboardId)\n            putExtra(EXTRA_LEADERBOARD_TIME_SPAN, timeSpan)\n            putExtra(EXTRA_LEADERBOARD_COLLECTION, collection)\n        }\n    }\n\n    override fun getCurrentAccount(): Account? {\n        Log.d(TAG, \"Not yet implemented: getCurrentAccount\")\n        return account\n    }\n\n    override fun isTelevision(): Boolean {\n        Log.d(TAG, \"Not yet implemented: isTelevision\")\n        return false\n    }\n\n    override fun getCompareProfileIntentWithAlternativeNameHints(\n        otherPlayerId: String,\n        otherPlayerInGameName: String?,\n        currentPlayerInGameName: String?\n    ): Intent = getCompareProfileIntent(otherPlayerId) {\n        putExtra(EXTRA_PLAYER_ID, otherPlayerId)\n        putExtra(EXTRA_OTHER_PLAYER_IN_GAME_NAME, otherPlayerInGameName)\n        putExtra(EXTRA_SELF_IN_GAME_NAME, currentPlayerInGameName)\n    }\n\n    override fun requestServerSideAccess(callbacks: IGamesCallbacks, serverClientId: String, forceRefreshToken: Boolean) {\n        lifecycleScope.launchWhenStarted {\n            try {\n                val serverAuthTokenResponse = withContext(Dispatchers.IO) {\n                    val serverAuthTokenManager = AuthManager(context, account.name, packageName, \"oauth2:server:client_id:${serverClientId}:api_scope:${Scopes.GAMES_LITE}\")\n                    serverAuthTokenManager.setOauth2Prompt(if (forceRefreshToken) \"consent\" else \"auto\")\n                    serverAuthTokenManager.setItCaveatTypes(\"2\")\n                    serverAuthTokenManager.isPermitted = true\n                    serverAuthTokenManager.invalidateAuthToken()\n                    serverAuthTokenManager.requestAuthWithBackgroundResolution(true)\n                }\n                if (serverAuthTokenResponse.auth != null) {\n                    callbacks.onServerAuthCode(Status(CommonStatusCodes.SUCCESS), serverAuthTokenResponse.auth)\n                } else {\n                    callbacks.onServerAuthCode(Status(CommonStatusCodes.SIGN_IN_REQUIRED), null)\n                }\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n                runCatching { callbacks.onServerAuthCode(Status(CommonStatusCodes.INTERNAL_ERROR), null) }\n            }\n        }\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =\n        warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/games/GamesSignInActivity.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.games\n\nimport android.accounts.Account\nimport android.content.Intent\nimport android.os.Bundle\nimport android.util.Log\nimport android.view.Gravity\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.core.content.IntentCompat\nimport androidx.lifecycle.lifecycleScope\nimport com.google.android.gms.auth.api.signin.GoogleSignInAccount\nimport com.google.android.gms.auth.api.signin.GoogleSignInOptions\nimport com.google.android.gms.auth.api.signin.internal.SignInConfiguration\nimport com.google.android.gms.common.api.Scope\nimport com.google.android.gms.common.api.Status\nimport org.microg.gms.auth.AuthConstants\nimport org.microg.gms.auth.signin.AuthSignInActivity\n\nprivate const val TAG = \"GamesSignIn\"\n\nprivate const val REQUEST_CODE_GOOGLE_SIGN_IN = 200\n\nclass GamesSignInActivity : AppCompatActivity() {\n    val gamePackageName: String?\n        get() = intent?.getStringExtra(EXTRA_GAME_PACKAGE_NAME)\n    val account: Account?\n        get() = IntentCompat.getParcelableExtra(intent, EXTRA_ACCOUNT, Account::class.java)\n    val popupGravity: Int\n        get() = intent?.getIntExtra(EXTRA_POPUP_GRAVITY, Gravity.TOP or Gravity.CENTER_HORIZONTAL) ?: (Gravity.TOP or Gravity.CENTER_HORIZONTAL)\n    val scopes: List<Scope>\n        get() = IntentCompat.getParcelableArrayExtra(intent, EXTRA_SCOPES, Scope::class.java)?.filterIsInstance<Scope>().orEmpty().realScopes\n\n    private val Int.px: Int get() = (this * resources.displayMetrics.density).toInt()\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n\n        if (gamePackageName == null || (gamePackageName != callingActivity?.packageName && callingActivity?.packageName != packageName)) return finish()\n\n        window.setGravity(popupGravity)\n        startActivityForResult(Intent(this, AuthSignInActivity::class.java).apply {\n            Log.d(TAG, \"Sign in for $gamePackageName account:${account?.name} scopes:$scopes\")\n            putExtra(\"config\", SignInConfiguration(gamePackageName!!, GoogleSignInOptions.Builder().apply {\n                for (scope in scopes) {\n                    requestScopes(scope)\n                }\n                account?.name?.takeIf { it != AuthConstants.DEFAULT_ACCOUNT }?.let { setAccountName(it) }\n            }.build()))\n            Log.d(TAG, \"Redirect to GOOGLE_SIGN_IN using $this\")\n        }, REQUEST_CODE_GOOGLE_SIGN_IN)\n    }\n\n    private suspend fun signIn(account: Account) {\n        Log.d(TAG, \"Sign in as ${account.name}\")\n        if (performGamesSignIn(this, gamePackageName!!, account, permitted = true, scopes = scopes)) {\n            if (GameProfileSettings.getAllowUploadGamePlayed(this)) {\n                runCatching { notifyGamePlayed(this, gamePackageName!!, account) }\n            }\n            GamesConfigurationService.setDefaultAccount(this, gamePackageName, account)\n        }\n        setResult(RESULT_OK, Intent().apply {\n            putExtra(EXTRA_ACCOUNT, account)\n        })\n        finish()\n    }\n\n    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {\n        super.onActivityResult(requestCode, resultCode, data)\n        if (requestCode == REQUEST_CODE_GOOGLE_SIGN_IN) {\n            val status = data?.extras?.also { it.classLoader = Status::class.java.classLoader }?.getParcelable<Status>(\"googleSignInStatus\")\n            if (status?.isSuccess == true) {\n                val account = data.extras?.also { it.classLoader = GoogleSignInAccount::class.java.classLoader }\n                        ?.getParcelable<GoogleSignInAccount>(\"googleSignInAccount\")?.account\n                if (account != null) {\n                    lifecycleScope.launchWhenStarted {\n                        signIn(account)\n                    }\n                    return\n                }\n            }\n            finish()\n        }\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/games/achievements/AchievementResponseKt.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.games.achievements\n\nimport org.json.JSONObject\n\ndata class AchievementDefinitionsListResponse<T>(\n    val items: List<T>, val kind: String?, val nextPageToken: String?\n) {\n    override fun toString(): String {\n        return \"AchievementDefinitionsListResponse(items=$items, kind='$kind', nextPageToken='$nextPageToken')\"\n    }\n}\n\ndata class AchievementDefinition(\n    val achievementType: Int,\n    val description: String?,\n    val experiencePoints: String,\n    val formattedTotalSteps: String?,\n    val id: String?,\n    var initialState: Int,\n    val isRevealedIconUrlDefault: Boolean?,\n    val isUnlockedIconUrlDefault: Boolean?,\n    val kind: String?,\n    val name: String?,\n    val revealedIconUrl: String?,\n    val totalSteps: Int,\n    val unlockedIconUrl: String?\n) {\n\n    constructor(name: String, type: Int) : this(type, null, \"\", \"\", \"\", 0, null, null, null, name, null, 0, null)\n\n    override fun toString(): String {\n        return \"AchievementDefinition(achievementType=$achievementType, description='$description', experiencePoints='$experiencePoints', formattedTotalSteps='$formattedTotalSteps', id='$id', initialState=$initialState, isRevealedIconUrlDefault=$isRevealedIconUrlDefault, isUnlockedIconUrlDefault=$isUnlockedIconUrlDefault, kind='$kind', name='$name', revealedIconUrl='$revealedIconUrl', totalSteps=$totalSteps, unlockedIconUrl='$unlockedIconUrl')\"\n    }\n}\n\ndata class PlayerAchievement(\n    val kind: String?,\n    val id: String?,\n    val currentSteps: Int,\n    val formattedCurrentStepsString: String?,\n    val achievementState: String,\n    val lastUpdatedTimestamp: String?,\n    val experiencePoints: String?\n) {\n    override fun toString(): String {\n        return \"PlayerAchievement(kind=$kind, id=$id, currentSteps=$currentSteps, formattedCurrentStepsString=$formattedCurrentStepsString, achievementState=$achievementState, lastUpdatedTimestamp=$lastUpdatedTimestamp, experiencePoints=$experiencePoints)\"\n    }\n}\n\ndata class AchievementIncrementResponse(\n    val kind: String?, val currentSteps: Int, val newlyUnlocked: Boolean\n) {\n    override fun toString(): String {\n        return \"AchievementIncrementResponse(kind=$kind, currentSteps=$currentSteps, newlyUnlocked=$newlyUnlocked)\"\n    }\n}\n\ndata class AchievementRevealResponse(\n    val kind: String?,\n    val currentState: String,\n) {\n    override fun toString(): String {\n        return \"AchievementRevealResponse(kind=$kind, currentState=$currentState)\"\n    }\n}\n\ndata class AchievementUnlockResponse(\n    val kind: String?,\n    val newlyUnlocked: Boolean,\n) {\n    override fun toString(): String {\n        return \"AchievementUnlockResponse(kind=$kind, newlyUnlocked=$newlyUnlocked)\"\n    }\n}\n\nfun JSONObject.toUnlockResponse(): AchievementUnlockResponse {\n    return AchievementUnlockResponse(\n        optString(\"kind\"), optBoolean(\"newlyUnlocked\")\n    )\n}\n\nfun JSONObject.toIncrementResponse(): AchievementIncrementResponse {\n    return AchievementIncrementResponse(\n        optString(\"kind\"), optInt(\"currentSteps\"), optBoolean(\"newlyUnlocked\")\n    )\n}\n\nfun JSONObject.toRevealResponse(): AchievementRevealResponse {\n    return AchievementRevealResponse(\n        optString(\"kind\"), optString(\"currentState\")\n    )\n}\n\nfun JSONObject.toAllAchievementListResponse(): AchievementDefinitionsListResponse<AchievementDefinition> {\n    val items = optJSONArray(\"items\")\n    val achievements = ArrayList<AchievementDefinition>()\n    if (items != null) {\n        for (i in 0..<items.length()) {\n            val jsonObject = items.getJSONObject(i)\n            val achievementDefinition = AchievementDefinition(\n                getAchievementType(jsonObject.optString(\"achievementType\")),\n                jsonObject.optString(\"description\"),\n                jsonObject.optString(\"experiencePoints\"),\n                jsonObject.optString(\"formattedTotalSteps\"),\n                jsonObject.optString(\"id\"),\n                getAchievementState(jsonObject.optString(\"initialState\")),\n                jsonObject.optBoolean(\"isRevealedIconUrlDefault\"),\n                jsonObject.optBoolean(\"isUnlockedIconUrlDefault\"),\n                jsonObject.optString(\"kind\"),\n                jsonObject.optString(\"name\"),\n                jsonObject.optString(\"revealedIconUrl\"),\n                jsonObject.optInt(\"totalSteps\"),\n                jsonObject.optString(\"unlockedIconUrl\")\n            )\n            achievements.add(achievementDefinition)\n        }\n    }\n    return AchievementDefinitionsListResponse(achievements, optString(\"kind\"), optString(\"nextPageToken\"))\n}\n\nfun JSONObject.toPlayerAchievementListResponse(): AchievementDefinitionsListResponse<PlayerAchievement> {\n    val items = optJSONArray(\"items\")\n    val achievements = ArrayList<PlayerAchievement>()\n    if (items != null) {\n        for (i in 0..<items.length()) {\n            val jsonObject = items.getJSONObject(i)\n            val playerAchievement = PlayerAchievement(\n                jsonObject.optString(\"kind\"),\n                jsonObject.optString(\"id\"),\n                jsonObject.optInt(\"currentSteps\"),\n                jsonObject.optString(\"formattedCurrentStepsString\"),\n                jsonObject.optString(\"achievementState\"),\n                jsonObject.optString(\"lastUpdatedTimestamp\"),\n                jsonObject.optString(\"experiencePoints\"),\n            )\n            achievements.add(playerAchievement)\n        }\n    }\n    return AchievementDefinitionsListResponse(achievements, optString(\"kind\"), optString(\"nextPageToken\"))\n}\n\nfun getAchievementType(type: String): Int {\n    return if (type == \"STANDARD\") {\n        AchievementType.TYPE_STANDARD\n    } else AchievementType.TYPE_INCREMENTAL\n}\n\nfun getAchievementState(state: String?): Int {\n    if (state == \"UNLOCKED\") {\n        return AchievementState.STATE_UNLOCKED\n    }\n    return if (state == \"REVEALED\") {\n        AchievementState.STATE_REVEALED\n    } else AchievementState.STATE_HIDDEN\n}\n\n\nclass AchievementState {\n    companion object {\n        /**\n         * Constant indicating an unlocked achievement.\n         */\n        const val STATE_UNLOCKED = 0\n\n        /**\n         * Constant indicating a revealed achievement.\n         */\n        const val STATE_REVEALED = 1\n\n        /**\n         * Constant indicating a hidden achievement.\n         */\n        const val STATE_HIDDEN = 2\n    }\n}\n\nclass AchievementType {\n    companion object {\n        /**\n         * Constant indicating a standard achievement.\n         */\n        const val TYPE_STANDARD = 0\n\n        /**\n         * Constant indicating an incremental achievement.\n         */\n        const val TYPE_INCREMENTAL = 1\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/games/achievements/AchievementsAdapter.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.games.achievements\n\nimport android.annotation.SuppressLint\nimport android.content.Context\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.ImageView\nimport android.widget.TextView\nimport androidx.recyclerview.widget.RecyclerView\n\nimport com.google.android.gms.R\nimport com.google.android.gms.common.images.ImageManager\n\nclass AchievementsAdapter(\n    private val mContext: Context,\n    private val achievements: List<AchievementDefinition>\n) :\n    RecyclerView.Adapter<AchievementsHolder>() {\n\n    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AchievementsHolder {\n        val itemView = if (viewType == -1) {\n            LayoutInflater.from(mContext).inflate(R.layout.item_achievement_header_layout, null)\n        } else {\n            LayoutInflater.from(mContext).inflate(R.layout.item_achievement_data_layout, null)\n        }\n        return AchievementsHolder(itemView, viewType)\n    }\n\n    override fun getItemCount(): Int {\n        return achievements.size\n    }\n\n    @SuppressLint(\"SetTextI18n\")\n    override fun onBindViewHolder(holder: AchievementsHolder, position: Int) {\n        val definition = achievements[position]\n        if (definition.achievementType == -1) {\n            holder.headerView?.text = definition.name\n        } else {\n            holder.achievementTitle?.text = definition.name\n            holder.achievementDesc?.text = definition.description\n            holder.achievementContent?.text = mContext.getString(\n                R.string.games_achievement_extra_text,\n                definition.experiencePoints\n            )\n            val imageUrl =\n                if (definition.initialState == AchievementState.STATE_UNLOCKED) {\n                    definition.unlockedIconUrl\n                } else {\n                    definition.revealedIconUrl\n                }\n            if (imageUrl != null) {\n                ImageManager.create(mContext).loadImage(imageUrl, holder.achievementLogo)\n            } else {\n                val logoId = if (definition.initialState == AchievementState.STATE_UNLOCKED) {\n                    R.drawable.ic_achievement_unlocked\n                } else {\n                    R.drawable.ic_achievement_locked\n                }\n                holder.achievementLogo?.setImageResource(logoId)\n            }\n        }\n    }\n\n    /**\n     * There are two display types.\n     * Now only the unlock display type is displayed, and the progress display type is not displayed yet.\n     */\n    override fun getItemViewType(position: Int): Int {\n        val definition = achievements[position]\n        return definition.achievementType\n    }\n\n}\n\nclass AchievementsHolder(itemView: View, viewType: Int) : RecyclerView.ViewHolder(itemView) {\n\n    var headerView: TextView? = null\n\n    var achievementLogo: ImageView? = null\n    var achievementTitle: TextView? = null\n    var achievementContent: TextView? = null\n    var achievementDesc: TextView? = null\n\n    init {\n        if (viewType == -1) {\n            headerView = itemView.findViewById(R.id.achievements_header_title)\n        } else {\n            achievementLogo = itemView.findViewById(R.id.achievement_logo)\n            achievementTitle = itemView.findViewById(R.id.achievement_title)\n            achievementContent = itemView.findViewById(R.id.achievement_content)\n            achievementDesc = itemView.findViewById(R.id.achievement_desc)\n        }\n    }\n\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/games/achievements/AchievementsApiClient.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.games.achievements\n\nimport android.content.Context\nimport com.android.volley.Request.Method\nimport org.microg.gms.games.requestGamesInfo\nimport java.util.Locale\n\n/**\n * https://developers.google.com/games/services/web/api/rest#rest-resource:-achievementdefinitions\n * https://developers.google.com/games/services/web/api/rest#rest-resource:-achievements\n */\nobject AchievementsApiClient {\n\n    /**\n     * Lists all the achievement definitions for your application.\n     */\n    suspend fun requestGameAllAchievements(mContext: Context, oauthToken: String, pageToken: String? = null) = requestGamesInfo(mContext,\n        Method.GET,\n        oauthToken,\n        \"https://games.googleapis.com/games/v1/achievements\",\n        HashMap<String, String>().apply {\n            put(\"language\", Locale.getDefault().language)\n            if (pageToken != null) {\n                put(\"pageToken\", pageToken)\n            }\n        }).toAllAchievementListResponse()\n\n    /**\n     * Lists the progress for all your application's achievements for the currently authenticated player.\n     */\n    suspend fun requestPlayerAllAchievements(mContext: Context, oauthToken: String, pageToken: String? = null) = requestGamesInfo(mContext,\n        Method.GET,\n        oauthToken,\n        \"https://games.googleapis.com/games/v1/players/me/achievements\",\n        HashMap<String, String>().apply {\n            put(\"language\", Locale.getDefault().language)\n            if (pageToken != null) {\n                put(\"pageToken\", pageToken)\n            }\n        }).toPlayerAchievementListResponse()\n\n    /**\n     * Increments the steps of the achievement with the given ID for the currently authenticated player.\n     */\n    suspend fun incrementAchievement(mContext: Context, oauthToken: String, achievementId: String, numSteps: Int) = requestGamesInfo(\n        mContext,\n        Method.POST,\n        oauthToken,\n        \"https://games.googleapis.com/games/v1/achievements/$achievementId/increment\",\n        HashMap<String, String>().apply {\n            put(\"requestId\", achievementId.hashCode().toString())\n            put(\"stepsToIncrement\", if (numSteps <= 0) \"1\" else numSteps.toString())\n        }).toIncrementResponse()\n\n    /**\n     * Sets the state of the achievement with the given ID to REVEALED for the currently authenticated player.\n     */\n    suspend fun revealAchievement(mContext: Context, oauthToken: String, achievementId: String) = requestGamesInfo(\n        mContext,\n        Method.POST,\n        oauthToken,\n        \"https://games.googleapis.com/games/v1/achievements/$achievementId/reveal\",\n        null\n    ).toRevealResponse()\n\n    /**\n     * Sets the steps for the currently authenticated player towards unlocking an achievement.\n     * If the steps parameter is less than the current number of steps that the player already gained for the achievement, the achievement is not modified.\n     */\n    suspend fun setStepsAtLeast(mContext: Context, oauthToken: String, achievementId: String, steps: Int) = requestGamesInfo(mContext,\n        Method.POST,\n        oauthToken,\n        \"https://games.googleapis.com/games/v1/achievements/$achievementId/setStepsAtLeast\",\n        HashMap<String, String>().apply {\n            put(\"steps\", if (steps <= 0) \"1\" else steps.toString())\n        }).toIncrementResponse()\n\n    /**\n     * Unlocks this achievement for the currently authenticated player.\n     */\n    suspend fun unlockAchievement(mContext: Context, oauthToken: String, achievementId: String) = requestGamesInfo(\n        mContext,\n        Method.POST,\n        oauthToken,\n        \"https://games.googleapis.com/games/v1/achievements/$achievementId/unlock\",\n        null\n    ).toUnlockResponse()\n\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/games/extensions.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.games\n\nimport android.accounts.Account\nimport android.accounts.AccountManager\nimport android.content.ContentValues\nimport android.content.Context\nimport android.database.Cursor\nimport android.net.Uri\nimport androidx.core.content.contentValuesOf\nimport androidx.core.net.toUri\nimport com.android.volley.NetworkResponse\nimport com.android.volley.Request\nimport com.android.volley.RequestQueue\nimport com.android.volley.Response\nimport com.android.volley.Response.success\nimport com.android.volley.VolleyError\nimport com.android.volley.toolbox.JsonObjectRequest\nimport com.android.volley.toolbox.Volley\nimport com.google.android.gms.common.BuildConfig\nimport com.google.android.gms.common.Scopes\nimport com.google.android.gms.common.api.Scope\nimport com.google.android.gms.games.CurrentPlayerInfoEntity\nimport com.google.android.gms.games.Player\nimport com.google.android.gms.games.PlayerColumns\nimport com.google.android.gms.games.PlayerEntity\nimport com.google.android.gms.games.PlayerLevel\nimport com.google.android.gms.games.PlayerLevelInfo\nimport com.google.android.gms.games.PlayerRelationshipInfoEntity\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\nimport okhttp3.Interceptor\nimport org.json.JSONObject\nimport org.microg.gms.auth.AuthConstants\nimport org.microg.gms.auth.AuthManager\nimport org.microg.gms.auth.consent.CONSENT_RESULT\nimport org.microg.gms.auth.signin.consentRequestOptions\nimport org.microg.gms.auth.signin.performConsentView\nimport org.microg.gms.auth.signin.performSignIn\nimport org.microg.gms.checkin.LastCheckinInfo\nimport org.microg.gms.common.Constants\nimport org.microg.gms.common.Utils\nimport org.microg.gms.profile.Build\nimport org.microg.gms.settings.SettingsContract.CheckIn\nimport org.microg.gms.settings.SettingsContract.getSettings\nimport org.microg.gms.utils.singleInstanceOf\nimport kotlin.coroutines.resume\nimport kotlin.coroutines.resumeWithException\nimport kotlin.coroutines.suspendCoroutine\n\nconst val SERVICE_GAMES_LITE = \"oauth2:https://www.googleapis.com/auth/games_lite\"\n\nconst val ACTION_START_1P = \"com.google.android.play.games.service.START_1P\"\nconst val ACTION_VIEW_LEADERBOARDS = \"com.google.android.gms.games.VIEW_LEADERBOARDS\"\nconst val ACTION_VIEW_LEADERBOARDS_SCORES = \"com.google.android.gms.games.VIEW_LEADERBOARD_SCORES\"\nconst val ACTION_VIEW_ACHIEVEMENTS = \"com.google.android.gms.games.VIEW_ACHIEVEMENTS\"\nconst val ACTION_VIEW_SNAPSHOTS = \"com.google.android.gms.games.SHOW_SELECT_SNAPSHOT\"\nconst val ACTION_PLAYER_SEARCH = \"com.google.android.gms.games.PLAYER_SEARCH\"\nconst val ACTION_VIEW_PROFILE = \"com.google.android.gms.games.VIEW_PROFILE\"\nconst val ACTION_ADD_FRIEND = \"com.google.android.gms.games.ADD_FRIEND\"\n\nconst val EXTRA_GAME_PACKAGE_NAME = \"com.google.android.gms.games.GAME_PACKAGE_NAME\"\nconst val EXTRA_GAME_ID = \"com.google.android.gms.games.GAME_ID\"\nconst val EXTRA_PLAYER = \"com.google.android.gms.games.PLAYER\"\nconst val EXTRA_PLAYER_ID = \"com.google.android.gms.games.PLAYER_ID\"\nconst val EXTRA_IS_SELF = \"com.google.android.gms.games.IS_SELF\"\nconst val EXTRA_ACCOUNT = \"com.google.android.gms.games.ACCOUNT\"\nconst val EXTRA_SCOPES = \"com.google.android.gms.games.SCOPES\"\nconst val EXTRA_POPUP_GRAVITY = \"com.google.android.gms.games.key.connectingPopupGravity\"\nconst val EXTRA_SELF_IN_GAME_NAME = \"com.google.android.gms.games.EXTRA_SELF_IN_GAME_NAME\"\nconst val EXTRA_OTHER_PLAYER_IN_GAME_NAME = \"com.google.android.gms.games.EXTRA_OTHER_PLAYER_IN_GAME_NAME\"\n\nconst val EXTRA_MAX_SNAPSHOTS = \"com.google.android.gms.games.MAX_SNAPSHOTS\"\nconst val EXTRA_ALLOW_CREATE_SNAPSHOT = \"com.google.android.gms.games.ALLOW_CREATE_SNAPSHOT\"\nconst val EXTRA_TITLE = \"com.google.android.gms.games.TITLE\"\nconst val EXTRA_ALLOW_DELETE_SNAPSHOT = \"com.google.android.gms.games.ALLOW_DELETE_SNAPSHOT\"\nconst val EXTRA_SNAPSHOT_NEW = \"com.google.android.gms.games.SNAPSHOT_NEW\"\nconst val EXTRA_SNAPSHOT_METADATA = \"com.google.android.gms.games.SNAPSHOT_METADATA\"\n\nconst val EXTRA_LEADERBOARD_ID = \"com.google.android.gms.games.LEADERBOARD_ID\"\nconst val EXTRA_LEADERBOARD_TIME_SPAN = \"com.google.android.gms.games.LEADERBOARD_TIME_SPAN\"\nconst val EXTRA_LEADERBOARD_COLLECTION = \"com.google.android.gms.games.LEADERBOARD_COLLECTION\"\n\nconst val EXTRA_SHOW_CONNECTING_POPUP = \"com.google.android.gms.games.key.showConnectingPopup\"\nconst val EXTRA_ACCOUNT_KEY = \"com.google.android.gms.games.ACCOUNT_KEY\"\nconst val GAMES_PACKAGE_NAME = \"com.google.android.play.games\"\n\nval List<Scope>.realScopes\n    get() = if (any { it.scopeUri == Scopes.GAMES }) {\n        this\n    } else {\n        this.toSet() + Scope(Scopes.GAMES_LITE)\n    }.toList().sortedBy { it.scopeUri }\n\nfun PlayerEntity.toContentValues(): ContentValues = contentValuesOf(\n    PlayerColumns.externalPlayerId to playerId,\n    PlayerColumns.profileName to displayName,\n    PlayerColumns.gamerTag to gamerTag,\n    PlayerColumns.realName to name,\n    PlayerColumns.profileIconImageUri to iconImageUri?.toString(),\n    PlayerColumns.profileIconImageUrl to iconImageUrl,\n    PlayerColumns.profileHiResImageUri to hiResImageUri?.toString(),\n    PlayerColumns.profileHiResImageUrl to hiResImageUrl,\n    PlayerColumns.bannerImageLandscapeUri to bannerImageLandscapeUri?.toString(),\n    PlayerColumns.bannerImageLandscapeUrl to bannerImageLandscapeUrl,\n    PlayerColumns.bannerImagePortraitUri to bannerImagePortraitUri?.toString(),\n    PlayerColumns.bannerImagePortraitUrl to bannerImagePortraitUrl,\n    PlayerColumns.lastUpdated to retrievedTimestamp,\n    PlayerColumns.isInCircles to isInCircles,\n    PlayerColumns.playedWithTimestamp to lastPlayedWithTimestamp,\n    PlayerColumns.playerTitle to title,\n    PlayerColumns.isProfileVisible to isProfileVisible,\n    PlayerColumns.hasDebugAccess to hasDebugAccess,\n    PlayerColumns.gamerFriendStatus to 0,\n    PlayerColumns.gamerFriendUpdateTimestamp to 0L,\n    PlayerColumns.isMuted to false,\n    PlayerColumns.totalUnlockedAchievements to totalUnlockedAchievement,\n    PlayerColumns.alwaysAutoSignIn to isAlwaysAutoSignIn,\n    PlayerColumns.hasAllPublicAcls to isProfileVisible,\n\n    PlayerColumns.currentLevel to levelInfo?.currentLevel?.levelNumber,\n    PlayerColumns.currentLevelMinXp to levelInfo?.currentLevel?.minXp,\n    PlayerColumns.currentLevelMaxXp to levelInfo?.currentLevel?.maxXp,\n    PlayerColumns.nextLevel to levelInfo?.nextLevel?.levelNumber,\n    PlayerColumns.nextLevelMaxXp to levelInfo?.nextLevel?.maxXp,\n    PlayerColumns.lastLevelUpTimestamp to (levelInfo?.lastLevelUpTimestamp ?: -1),\n    PlayerColumns.currentXpTotal to (levelInfo?.currentXpTotal ?: -1L),\n\n    PlayerColumns.mostRecentExternalGameId to mostRecentGameInfo?.gameId,\n    PlayerColumns.mostRecentGameName to mostRecentGameInfo?.gameName,\n    PlayerColumns.mostRecentActivityTimestamp to mostRecentGameInfo?.activityTimestampMillis,\n    PlayerColumns.mostRecentGameIconUri to mostRecentGameInfo?.gameIconImageUri?.toString(),\n    PlayerColumns.mostRecentGameHiResUri to mostRecentGameInfo?.gameHiResImageUri?.toString(),\n    PlayerColumns.mostRecentGameFeaturedUri to mostRecentGameInfo?.gameFeaturedImageUri?.toString(),\n\n    PlayerColumns.playTogetherFriendStatus to relationshipInfo?.friendStatus,\n    PlayerColumns.playTogetherNickname to (relationshipInfo as? PlayerRelationshipInfoEntity)?.nickname,\n    PlayerColumns.playTogetherInvitationNickname to (relationshipInfo as? PlayerRelationshipInfoEntity)?.invitationNickname,\n    PlayerColumns.nicknameAbuseReportToken to (relationshipInfo as? PlayerRelationshipInfoEntity)?.nicknameAbuseReportToken,\n\n    PlayerColumns.friendsListVisibility to currentPlayerInfo?.friendsListVisibilityStatus\n)\n\nfun JSONObject.toPlayer() = PlayerEntity(\n    getString(\"playerId\"),\n    getString(\"displayName\"),\n    optString(\"avatarImageUrl\").takeIf { it.isNotBlank() }?.toUri(),\n    optString(\"avatarImageUrl\").takeIf { it.isNotBlank() }?.toUri(),\n    System.currentTimeMillis(),\n    0, 0,\n    optString(\"avatarImageUrl\").takeIf { it.isNotBlank() },\n    optString(\"avatarImageUrl\").takeIf { it.isNotBlank() },\n    getString(\"title\"),\n    null,\n    getJSONObject(\"experienceInfo\")?.let {\n        PlayerLevelInfo(\n            it.optLong(\"currentExperiencePoints\"),\n            0,\n            it.getJSONObject(\"currentLevel\")?.let {\n                PlayerLevel(it.getInt(\"level\"), it.optLong(\"minExperiencePoints\"), it.optLong(\"maxExperiencePoints\"))\n            },\n            it.getJSONObject(\"nextLevel\")?.let {\n                PlayerLevel(it.getInt(\"level\"), it.optLong(\"minExperiencePoints\"), it.optLong(\"maxExperiencePoints\"))\n            }\n        )\n    },\n    optJSONObject(\"profileSettings\")?.optBoolean(\"profileVisible\") ?: false,\n    false,\n    null, null,\n    optString(\"bannerUrlLandscape\").takeIf { it.isNotBlank() }?.toUri(),\n    optString(\"bannerUrlLandscape\").takeIf { it.isNotBlank() },\n    optString(\"bannerUrlPortrait\").takeIf { it.isNotBlank() }?.toUri(),\n    optString(\"bannerUrlPortrait\").takeIf { it.isNotBlank() },\n    0, null,\n    optJSONObject(\"profileSettings\")?.optString(\"friendsListVisibility\")?.takeIf { it.isNotBlank() }?.let {\n        CurrentPlayerInfoEntity(\n            when (it) {\n                \"VISIBLE\" -> Player.FriendsListVisibilityStatus.VISIBLE\n                \"REQUEST_REQUIRED\" -> Player.FriendsListVisibilityStatus.REQUEST_REQUIRED\n                \"FEATURE_UNAVAILABLE\" -> Player.FriendsListVisibilityStatus.FEATURE_UNAVAILABLE\n                else -> Player.FriendsListVisibilityStatus.UNKNOWN\n            }\n        )\n    },\n    false,\n    null\n)\n\nsuspend fun requestGamesInfo(\n    context: Context,\n    method: Int,\n    oauthToken: String,\n    url: String,\n    params: HashMap<String, String>?,\n    requestBody: JSONObject? = null,\n    queue: RequestQueue = singleInstanceOf { Volley.newRequestQueue(context.applicationContext) }\n): JSONObject = suspendCoroutine { continuation ->\n    val uriBuilder = Uri.parse(url).buildUpon().apply {\n        if (!params.isNullOrEmpty()) {\n            for (key in params.keys) {\n                appendQueryParameter(key, params[key])\n            }\n        }\n    }\n    queue.add(object : JsonObjectRequest(method, uriBuilder.build().toString(), requestBody, {\n        continuation.resume(it)\n    }, {\n        continuation.resumeWithException(RuntimeException(it))\n    }) {\n        override fun getHeaders(): Map<String, String> = hashMapOf<String, String>().apply {\n            put(\"Authorization\", \"OAuth $oauthToken\")\n        }\n    })\n}\n\nsuspend fun registerForGames(context: Context, account: Account, queue: RequestQueue = singleInstanceOf { Volley.newRequestQueue(context.applicationContext) }) {\n    val authManager = AuthManager(context, account.name, Constants.GMS_PACKAGE_NAME, \"oauth2:${Scopes.GAMES_FIRSTPARTY}\")\n    authManager.setOauth2Foreground(\"1\")\n    val authToken = withContext(Dispatchers.IO) { authManager.requestAuthWithBackgroundResolution(false).auth }\n    val androidId = getSettings(context, CheckIn.getContentUri(context), arrayOf(CheckIn.ANDROID_ID)) { cursor: Cursor -> cursor.getLong(0) }\n    val result = suspendCoroutine<JSONObject> { continuation ->\n        queue.add(\n            object : JsonObjectRequest(\n                \"https://www.googleapis.com/games/v1whitelisted/players/me/profilesettings?requestRandomGamerTag=true&language=${Utils.getLocale(context)}\",\n                { continuation.resume(it) },\n                { continuation.resumeWithException(RuntimeException(it)) }) {\n                override fun getHeaders(): MutableMap<String, String> {\n                    return mutableMapOf(\n                        \"Authorization\" to \"OAuth $authToken\",\n                        \"X-Device-ID\" to androidId.toString(16)\n                    )\n                }\n            }\n        )\n    }\n    suspendCoroutine<JSONObject> { continuation ->\n        queue.add(\n            object : JsonObjectRequest(\n                Method.PUT,\n                \"https://www.googleapis.com/games/v1whitelisted/players/me/profilesettings?language=${Utils.getLocale(context)}\",\n                JSONObject().apply {\n                    put(\"alwaysAutoSignIn\", false)\n                    put(\"autoSignIn\", false)\n                    put(\"gamerTagIsDefault\", true)\n                    put(\"gamerTagIsExplicitlySet\", false)\n                    put(\"gamesLitePlayerStatsEnabled\", false)\n                    put(\"profileDiscoverableViaGoogleAccount\", false)\n                    put(\"profileVisibilityWasChosenByPlayer\", false)\n                    put(\"profileVisible\", false)\n                    put(\"gamerTag\", result.getString(\"gamerTag\"))\n                    if (result.has(\"stockGamerAvatarUrl\")) put(\"stockGamerAvatarUrl\", result.getString(\"stockGamerAvatarUrl\"))\n                },\n                { continuation.resume(it) },\n                { continuation.resumeWithException(RuntimeException(it)) }) {\n                override fun getHeaders(): MutableMap<String, String> {\n                    return mutableMapOf(\n                        \"Content-Type\" to \"application/json; charset=utf-8\",\n                        \"Authorization\" to \"OAuth $authToken\",\n                        \"X-Device-ID\" to androidId.toString(16)\n                    )\n                }\n            }\n        )\n    }\n}\n\nsuspend fun performGamesSignIn(\n    context: Context,\n    packageName: String,\n    account: Account,\n    permitted: Boolean = false,\n    scopes: List<Scope> = emptyList(),\n    queue: RequestQueue = singleInstanceOf { Volley.newRequestQueue(context.applicationContext) }\n): Boolean {\n    val realScopes = scopes.realScopes\n    val authManager = AuthManager(context, account.name, packageName, \"oauth2:${realScopes.joinToString(\" \")}\")\n    if (realScopes.size == 1) authManager.setItCaveatTypes(\"2\")\n    if (permitted) {\n        authManager.isPermitted = true\n    } else {\n        authManager.setTokenRequestOptions(consentRequestOptions)\n    }\n    var authResponse = withContext(Dispatchers.IO) { authManager.requestAuthWithBackgroundResolution(true) }\n    if (\"remote_consent\" == authResponse.issueAdvice && authResponse.resolutionDataBase64 != null) {\n        val consentResult = performConsentView(context, packageName, account, authResponse.resolutionDataBase64)\n        if (consentResult == null) return false\n        authManager.putDynamicFiled(CONSENT_RESULT, consentResult)\n        authResponse = withContext(Dispatchers.IO) { authManager.requestAuthWithBackgroundResolution(true) }\n    }\n    if (authResponse.auth == null) return false\n    if (authResponse.issueAdvice != \"stored\" || GamesConfigurationService.getPlayer(context, account) == null) {\n        val result = try {\n            fetchSelfPlayer(context, authResponse.auth, queue)\n        } catch (e: Exception) {\n            if (e is VolleyError) {\n                val statusCode = e.networkResponse?.statusCode\n                when (statusCode) {\n                    404 -> {\n                        try {\n                            if (!GameProfileSettings.getAllowCreatePlayer(context)) {\n                                return false\n                            }\n                            registerForGames(context, account, queue)\n                            fetchSelfPlayer(context, authResponse.auth, queue)\n                        } catch (e : Exception){\n                            requestGameToken(context, account, scopes, authManager.isPermitted)?.let {\n                                fetchSelfPlayer(context, it, queue)\n                            } ?: return false\n                        }\n                    }\n                    403 -> {\n                        requestGameToken(context, account, scopes, authManager.isPermitted)?.let {\n                            fetchSelfPlayer(context, it, queue)\n                        } ?: return false\n                    }\n                    else -> throw e\n                }\n            } else {\n                throw e\n            }\n        }\n        val defaultAccount = GamesConfigurationService.getDefaultAccount(context, GAMES_PACKAGE_NAME)\n        if (defaultAccount == null) {\n            GamesConfigurationService.setDefaultAccount(context, GAMES_PACKAGE_NAME, account)\n        }\n        GamesConfigurationService.setPlayer(context, account, result.toString())\n    }\n    return true\n}\n\nsuspend fun fetchSelfPlayer(\n    context: Context,\n    authToken: String,\n    queue: RequestQueue = singleInstanceOf { Volley.newRequestQueue(context.applicationContext) }\n) = suspendCoroutine<JSONObject> { continuation ->\n    queue.add(\n        object : JsonObjectRequest(\n            \"https://www.googleapis.com/games/v1/players/me\",\n            { continuation.resume(it) },\n            { continuation.resumeWithException(it) }) {\n            override fun getHeaders(): MutableMap<String, String> {\n                return mutableMapOf(\n                    \"Authorization\" to \"OAuth $authToken\"\n                )\n            }\n        }\n    )\n}\n\nsuspend fun requestGameToken(\n    context: Context,\n    account: Account,\n    scopes: List<Scope> = arrayListOf(Scope(Scopes.GAMES_LITE)),\n    isPermitted: Boolean = false,\n): String? {\n    val realScopes = scopes.realScopes\n    val gameAuthManager = AuthManager(context, account.name, GAMES_PACKAGE_NAME, \"oauth2:${realScopes.joinToString(\" \")}\")\n    if (gameAuthManager.packageSignature == null) gameAuthManager.packageSignature = Constants.GMS_PACKAGE_SIGNATURE_SHA1\n    gameAuthManager.isPermitted = isPermitted\n    val authResponse = withContext(Dispatchers.IO) { gameAuthManager.requestAuth(true) }\n    if (authResponse.auth == null) return null\n    return authResponse.auth\n}\n\nsuspend fun fetchAllSelfPlayers(context: Context): List<Pair<Account, String>> {\n    val googleAccounts = AccountManager.get(context).getAccountsByType(AuthConstants.DEFAULT_ACCOUNT_TYPE)\n    return googleAccounts.mapNotNull { account ->\n        val playerStr = GamesConfigurationService.getPlayer(context, account)\n        val playerJSONObject = if (playerStr == null) {\n            withContext(Dispatchers.IO) {\n                requestGameToken(context, account)?.let {\n                    runCatching { fetchSelfPlayer(context, it) }.getOrNull()\n                }\n            }?.also { GamesConfigurationService.setPlayer(context, account, it.toString()) }\n        } else {\n            JSONObject(playerStr)\n        }\n        playerJSONObject?.toPlayer()?.displayName?.let { Pair(account, it) }\n    }\n}\n\nsuspend fun notifyGamePlayed(\n    context: Context,\n    packageName: String,\n    account: Account,\n    permitted: Boolean = false,\n    queue: RequestQueue = singleInstanceOf { Volley.newRequestQueue(context.applicationContext) }\n) {\n    val authManager = AuthManager(context, account.name, packageName, SERVICE_GAMES_LITE)\n    if (permitted) authManager.isPermitted = true\n    var authResponse = withContext(Dispatchers.IO) { authManager.requestAuthWithBackgroundResolution(true) }\n    if (authResponse.auth == null) throw RuntimeException(\"authToken is null\")\n    return suspendCoroutine { continuation ->\n        queue.add(object : Request<Unit>(Method.POST, \"https://www.googleapis.com/games/v1/applications/played\", {\n            continuation.resumeWithException(it)\n        }) {\n            override fun parseNetworkResponse(response: NetworkResponse): Response<Unit> {\n                if (response.statusCode == 204) return success(Unit, null)\n                return Response.error(VolleyError(response))\n            }\n\n            override fun deliverResponse(response: Unit) {\n                continuation.resume(response)\n            }\n\n            override fun getHeaders(): MutableMap<String, String> {\n                return mutableMapOf(\n                    \"Authorization\" to \"OAuth ${authResponse.auth}\"\n                )\n            }\n        })\n    }\n}\n\nclass HeaderInterceptor(\n    private val context: Context,\n    private val oauthToken: String,\n) : Interceptor {\n    override fun intercept(chain: Interceptor.Chain): okhttp3.Response {\n        val original = chain.request()\n        val requestBuilder = original.newBuilder()\n            .header(\"authorization\", \"Bearer $oauthToken\")\n            .header(\"te\", \"trailers\")\n            .header(\"x-play-games-agent\", createPlayGamesAgent())\n            .header(\"x-device-id\", LastCheckinInfo.read(context).androidId.toString(16))\n            .header(\"user-agent\", \"grpc-java-okhttp/1.66.0-SNAPSHOT\")\n        val request = requestBuilder.build()\n        return chain.proceed(request)\n    }\n\n    private fun createPlayGamesAgent(): String {\n        var playGamesAgent =\n            \"Mozilla/5.0 (Linux; Android ${Build.VERSION.RELEASE}; ${Build.MODEL} Build/${Build.ID};\"\n        playGamesAgent += context.packageName + \"/\" + BuildConfig.VERSION_CODE + \";\"\n        playGamesAgent += \"FastParser/1.1; Games Android SDK/1.0-1052947;\"\n        playGamesAgent += \"com.google.android.play.games/517322040; (gzip); Games module/242632000\"\n        return playGamesAgent\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/games/leaderboards/LeaderboardResponseKt.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.games.leaderboards\n\nimport com.google.android.gms.games.PlayerEntity\nimport org.json.JSONArray\nimport org.json.JSONObject\nimport org.microg.gms.games.toPlayer\n\ndata class LeaderboardListResponse(\n    val items: List<LeaderboardDefinition>, val kind: String?, val nextPageToken: String?\n) {\n    override fun toString(): String {\n        return \"LeaderboardListResponse(items=$items, kind='$kind', nextPageToken='$nextPageToken')\"\n    }\n}\n\ndata class LeaderboardDefinition(\n    val kind: String?,\n    val id: String?,\n    val name: String?,\n    val iconUrl: String?,\n    val isIconUrlDefault: Boolean,\n    val order: String?\n) {\n    override fun toString(): String {\n        return \"LeaderboardDefinition(kind=$kind, id=$id, name=$name, iconUrl=$iconUrl, isIconUrlDefault=$isIconUrlDefault, order=$order)\"\n    }\n}\n\ndata class GetLeaderboardScoresResponse(\n    val kind: String?, val nextPageToken: String?, val player: PlayerEntity?, val items: List<LeaderboardScore>?\n) {\n    override fun toString(): String {\n        return \"GetLeaderboardScoresResponse(kind=$kind, nextPageToken=$nextPageToken, player=$player, items=$items)\"\n    }\n}\n\ndata class LeaderboardScore(\n    val kind: String?,\n    val leaderboardId: String?,\n    val scoreValue: String?,\n    val scoreString: String?,\n    val publicRank: LeaderboardScoreRank?,\n    val socialRank: LeaderboardScoreRank?,\n    val friendsRank: LeaderboardScoreRank?,\n    val timeSpan: String,\n    val writeTimestamp: String,\n    val scoreTag: String\n) {\n    override fun toString(): String {\n        return \"LeaderboardScore(kind=$kind, leaderboardId=$leaderboardId, scoreValue=$scoreValue, scoreString=$scoreString, publicRank=$publicRank, socialRank=$socialRank, friendsRank=$friendsRank, timeSpan=$timeSpan, writeTimestamp='$writeTimestamp', scoreTag='$scoreTag')\"\n    }\n}\n\ndata class LeaderboardScoreRank(\n    val kind: String?,\n    val rank: String?,\n    val formattedRank: String?,\n    val numScores: String?,\n    val formattedNumScores: String?,\n) {\n    override fun toString(): String {\n        return \"LeaderboardScoreRank(kind=$kind, rank=$rank, formattedRank=$formattedRank, numScores=$numScores, formattedNumScores=$formattedNumScores)\"\n    }\n}\n\ndata class ListLeaderboardScoresResponse(\n    val kind: String?,\n    val nextPageToken: String?,\n    val prevPageToken: String?,\n    val numScores: String?,\n    val playerScore: LeaderboardEntry?,\n    val items: ArrayList<LeaderboardEntry>,\n) {\n    override fun toString(): String {\n        return \"ListLeaderboardScoresResponse(kind=$kind, nextPageToken=$nextPageToken, prevPageToken=$prevPageToken, numScores=$numScores, playerScore=$playerScore, items=$items)\"\n    }\n}\n\ndata class LeaderboardEntry(\n    val kind: String?,\n    val player: PlayerEntity?,\n    val scoreRank: String?,\n    val formattedScoreRank: String?,\n    val scoreValue: String?,\n    val formattedScore: String?,\n    val timeSpan: String?,\n    val writeTimestampMillis: String?,\n    val scoreTag: String?,\n) {\n    constructor(leaderboardTitle: String?, leaderboardLogoUrl: String?) : this(\n        null, null, null, null, leaderboardTitle, null, null, null, leaderboardLogoUrl\n    )\n\n    override fun toString(): String {\n        return \"LeaderboardEntry(kind=$kind, player=$player, scoreRank=$scoreRank, formattedScoreRank=$formattedScoreRank, scoreValue=$scoreValue, formattedScore=$formattedScore, timeSpan=$timeSpan, writeTimestampMillis=$writeTimestampMillis, scoreTag=$scoreTag)\"\n    }\n}\n\ndata class SubmitLeaderboardScoreListResponse(\n    val kind: String?,\n    val submittedScores: List<SubmitLeaderboardScoreResponse>?,\n) {\n    override fun toString(): String {\n        return \"SubmitLeaderboardScoreListResponse(kind=$kind, submittedScores=$submittedScores)\"\n    }\n}\n\ndata class SubmitLeaderboardScoreResponse(\n    val kind: String?,\n    val beatenScoreTimeSpans: List<String>?,\n    val unbeatenScores: List<PlayerScore>?,\n    val formattedScore: String?,\n    val leaderboardId: String?,\n    val scoreTag: String?,\n) {\n    override fun toString(): String {\n        return \"SubmitLeaderboardScoreResponse(kind=$kind, beatenScoreTimeSpans=$beatenScoreTimeSpans, unbeatenScores=$unbeatenScores, formattedScore=$formattedScore, leaderboardId=$leaderboardId, scoreTag=$scoreTag)\"\n    }\n}\n\ndata class PlayerScore(\n    val kind: String?, val timeSpan: String?, val score: String?, val formattedScore: String?, val scoreTag: String?\n) {\n    override fun toString(): String {\n        return \"PlayerScore(kind=$kind, timeSpan=$timeSpan, score=$score, formattedScore=$formattedScore, scoreTag=$scoreTag)\"\n    }\n}\n\ndata class PlayerScoreSubmissionList(\n    val kind: String?, val scores: List<ScoreSubmission>\n) {\n    override fun toString(): String {\n        return \"PlayerScoreSubmissionList(kind=$kind, scores=$scores)\"\n    }\n}\n\ndata class ScoreSubmission(\n    val kind: String?,\n    val leaderboardId: String?,\n    val score: String?,\n    val scoreTag: String?,\n    val signature: String?,\n) {\n    override fun toString(): String {\n        return \"ScoreSubmission(kind=$kind, leaderboardId=$leaderboardId, score=$score, scoreTag=$scoreTag, signature=$signature)\"\n    }\n}\n\nfun PlayerScoreSubmissionList.toJSONObject() = JSONObject().apply {\n    put(\"kind\", kind)\n    put(\"scores\", JSONArray().apply {\n        for (score in scores) {\n            put(score.toJSONObject())\n        }\n    })\n}\n\nfun ScoreSubmission.toJSONObject() = JSONObject().apply {\n    put(\"kind\", kind)\n    put(\"leaderboardId\", leaderboardId)\n    put(\"score\", score)\n    put(\"scoreTag\", scoreTag)\n    put(\"signature\", signature)\n}\n\nfun JSONObject.toSubmitLeaderboardScoreListResponse() = SubmitLeaderboardScoreListResponse(\n    optString(\"kind\"),\n    optJSONArray(\"submittedScores\")?.toSubmitLeaderboardScoreResponseList(),\n)\n\nfun JSONArray.toSubmitLeaderboardScoreResponseList(): List<SubmitLeaderboardScoreResponse> {\n    val list = arrayListOf<SubmitLeaderboardScoreResponse>()\n    for (i in 0..<length()) {\n        val jsonObject = optJSONObject(i)\n        list.add(jsonObject.toSubmitLeaderboardScoreResponse())\n    }\n    return list\n}\n\nfun JSONObject.toSubmitLeaderboardScoreResponse() = SubmitLeaderboardScoreResponse(\n    optString(\"kind\"),\n    optJSONArray(\"beatenScoreTimeSpans\")?.toTimeSpans(),\n    optJSONArray(\"unbeatenScores\")?.toPlayerScore(),\n    optString(\"formattedScore\"),\n    optString(\"leaderboardId\"),\n    optString(\"scoreTag\"),\n)\n\nfun JSONArray.toTimeSpans(): List<String> {\n    val list = arrayListOf<String>()\n    for (i in 0..<length()) {\n        list.add(optString(i))\n    }\n    return list\n}\n\nfun JSONArray.toPlayerScore(): List<PlayerScore> {\n    val list = arrayListOf<PlayerScore>()\n    for (i in 0..<length()) {\n        val jsonObject = optJSONObject(i)\n        list.add(\n            PlayerScore(\n                jsonObject.optString(\"kind\"),\n                jsonObject.optString(\"timeSpan\"),\n                jsonObject.optString(\"score\"),\n                jsonObject.optString(\"formattedScore\"),\n                jsonObject.optString(\"scoreTag\"),\n            )\n        )\n    }\n    return list\n}\n\nfun JSONObject.toListLeaderboardScoresResponse() = ListLeaderboardScoresResponse(\n    optString(\"kind\"),\n    optString(\"nextPageToken\"),\n    optString(\"prevPageToken\"),\n    optString(\"numScores\"),\n    optJSONObject(\"playerScore\")?.toLeaderboardEntry(),\n    getJSONArray(\"items\").toLeaderboardEntryList(),\n)\n\nfun JSONArray.toLeaderboardEntryList(): ArrayList<LeaderboardEntry> {\n    val list = arrayListOf<LeaderboardEntry>()\n    for (i in 0..<length()) {\n        val jsonObject = optJSONObject(i)\n        list.add(jsonObject.toLeaderboardEntry())\n    }\n    return list\n}\n\nfun JSONObject.toLeaderboardEntry() = LeaderboardEntry(\n    optString(\"kind\"),\n    optJSONObject(\"player\")?.toPlayer(),\n    optString(\"scoreRank\"),\n    optString(\"formattedScoreRank\"),\n    optString(\"scoreValue\"),\n    optString(\"formattedScore\"),\n    optString(\"timeSpan\"),\n    optString(\"writeTimestampMillis\"),\n    optString(\"scoreTag\"),\n)\n\nfun JSONObject.toGetLeaderboardScoresResponse() = GetLeaderboardScoresResponse(\n    optString(\"kind\"),\n    optString(\"nextPageToken\"),\n    optJSONObject(\"player\")?.toPlayer(),\n    optJSONArray(\"items\")?.toLeaderboardScoreList()\n)\n\nfun JSONArray.toLeaderboardScoreList(): List<LeaderboardScore> {\n    val list = arrayListOf<LeaderboardScore>()\n    for (i in 0..<length()) {\n        val jsonObject = optJSONObject(i)\n        list.add(\n            LeaderboardScore(\n                jsonObject.optString(\"kind\"),\n                jsonObject.optString(\"leaderboard_id\"),\n                jsonObject.optString(\"scoreValue\"),\n                jsonObject.optString(\"scoreString\"),\n                jsonObject.optJSONObject(\"publicRank\")?.toLeaderboardScoreRank(),\n                jsonObject.optJSONObject(\"socialRank\")?.toLeaderboardScoreRank(),\n                jsonObject.optJSONObject(\"friendsRank\")?.toLeaderboardScoreRank(),\n                jsonObject.optString(\"timeSpan\"),\n                jsonObject.optString(\"writeTimestamp\"),\n                jsonObject.optString(\"scoreTag\"),\n            )\n        )\n    }\n    return list\n}\n\nfun JSONObject.toLeaderboardScoreRank() = LeaderboardScoreRank(\n    optString(\"kind\"),\n    optString(\"rank\"),\n    optString(\"formattedRank\"),\n    optString(\"numScores\"),\n    optString(\"formattedNumScores\"),\n)\n\nfun JSONObject.toLeaderboardResponse(): LeaderboardDefinition {\n    return LeaderboardDefinition(\n        optString(\"kind\"),\n        optString(\"id\"),\n        optString(\"name\"),\n        optString(\"iconUrl\"),\n        optBoolean(\"isIconUrlDefault\"),\n        optString(\"order\")\n    )\n}\n\nfun JSONObject.toLeaderboardListResponse(): LeaderboardListResponse {\n    val items = optJSONArray(\"items\")\n    val leaderboardDefinitions = ArrayList<LeaderboardDefinition>()\n    if (items != null) {\n        for (i in 0..<items.length()) {\n            val jsonObject = items.getJSONObject(i)\n            val achievementDefinition = LeaderboardDefinition(\n                jsonObject.optString(\"kind\"),\n                jsonObject.optString(\"id\"),\n                jsonObject.optString(\"name\"),\n                jsonObject.optString(\"iconUrl\"),\n                jsonObject.optBoolean(\"isIconUrlDefault\"),\n                jsonObject.optString(\"order\")\n            )\n            leaderboardDefinitions.add(achievementDefinition)\n        }\n    }\n    return LeaderboardListResponse(leaderboardDefinitions, optString(\"kind\"), optString(\"nextPageToken\"))\n}\n\nenum class ScoreTimeSpan {\n    ALL, ALL_TIME, WEEKLY, DAILY\n}\n\nenum class IncludeRankType {\n    ALL, PUBLIC, FRIENDS\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/games/leaderboards/LeaderboardScoresAdapter.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.games.leaderboards\n\nimport android.annotation.SuppressLint\nimport android.content.Context\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.ImageView\nimport android.widget.TextView\nimport androidx.recyclerview.widget.RecyclerView\nimport com.google.android.gms.R\nimport com.google.android.gms.common.images.ImageManager\n\nclass LeaderboardScoresAdapter(\n    private val mContext: Context,\n    private val leaderboards: List<LeaderboardEntry>,\n) : RecyclerView.Adapter<LeaderboardScoresHolder>() {\n\n    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LeaderboardScoresHolder {\n        val view = if (viewType == -1) {\n            LayoutInflater.from(mContext).inflate(R.layout.item_leaderboard_score_header_layout, parent, false)\n        } else {\n            LayoutInflater.from(mContext).inflate(R.layout.item_leaderboard_score_data_layout, parent, false)\n        }\n        return LeaderboardScoresHolder(view, viewType)\n    }\n\n    override fun getItemCount(): Int {\n        return leaderboards.size\n    }\n\n    override fun getItemViewType(position: Int): Int {\n        val leaderboardEntry = leaderboards[position]\n        return if (leaderboardEntry.kind == null) -1 else 0\n    }\n\n    @SuppressLint(\"SetTextI18n\")\n    override fun onBindViewHolder(holder: LeaderboardScoresHolder, position: Int) {\n        val leaderboardEntry = leaderboards[position]\n        if (leaderboardEntry.kind == null) {\n            val scoreTag = leaderboardEntry.scoreTag\n            if (scoreTag != null) {\n                ImageManager.create(mContext).loadImage(scoreTag, holder.leaderboardLogo)\n            } else {\n                holder.leaderboardLogo?.setImageResource(R.drawable.ic_leaderboard_placeholder)\n            }\n            holder.leaderboardTitle?.text = leaderboardEntry.scoreValue\n            return\n        }\n        val player = leaderboardEntry.player\n        val iconUrl = leaderboardEntry.player?.iconImageUrl\n        if (iconUrl != null) {\n            ImageManager.create(mContext).loadImage(iconUrl, holder.leaderboardPlayerLogo)\n        } else {\n            holder.leaderboardPlayerLogo?.setImageResource(R.drawable.ic_leaderboard_placeholder)\n        }\n        holder.leaderboardPlayerName?.text = player?.displayName\n        holder.leaderboardPlayerScore?.text = mContext.getString(R.string.games_leaderboards_score_label, leaderboardEntry.formattedScore)\n        holder.leaderboardPlayerRank?.text = leaderboardEntry.formattedScoreRank\n        if (position == leaderboards.size - 1) {\n            holder.leaderboardScoreLine?.visibility = View.INVISIBLE\n        }\n    }\n}\n\nclass LeaderboardScoresHolder(itemView: View, viewType: Int) : RecyclerView.ViewHolder(itemView) {\n\n    var leaderboardPlayerLogo: ImageView? = null\n    var leaderboardPlayerName: TextView? = null\n    var leaderboardPlayerScore: TextView? = null\n    var leaderboardPlayerRank: TextView? = null\n    var leaderboardScoreLine: View? = null\n\n    var leaderboardTitle: TextView? = null\n    var leaderboardLogo: ImageView? = null\n\n    init {\n        if (viewType == -1) {\n            leaderboardTitle = itemView.findViewById(R.id.leaderboard_header_title)\n            leaderboardLogo = itemView.findViewById(R.id.leaderboard_header_logo)\n        } else {\n            leaderboardPlayerLogo = itemView.findViewById(R.id.leaderboard_player_logo)\n            leaderboardPlayerName = itemView.findViewById(R.id.leaderboard_player_name)\n            leaderboardPlayerScore = itemView.findViewById(R.id.leaderboard_player_score)\n            leaderboardPlayerRank = itemView.findViewById(R.id.leaderboard_player_rank)\n            leaderboardScoreLine = itemView.findViewById(R.id.leaderboard_score_line)\n        }\n    }\n\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/games/leaderboards/LeaderboardsAdapter.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.games.leaderboards\n\nimport android.annotation.SuppressLint\nimport android.content.Context\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.ImageView\nimport android.widget.TextView\nimport androidx.recyclerview.widget.RecyclerView\nimport com.google.android.gms.R\nimport com.google.android.gms.common.images.ImageManager\n\nclass LeaderboardsAdapter(\n    private val mContext: Context, private val leaderboards: List<LeaderboardDefinition>, private val dealClick: (LeaderboardDefinition) -> Unit\n) : RecyclerView.Adapter<LeaderboardHolder>() {\n\n    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LeaderboardHolder {\n        val view = LayoutInflater.from(mContext).inflate(R.layout.item_leaderboard_data_layout, parent, false)\n        return LeaderboardHolder(view)\n    }\n\n    override fun getItemCount(): Int {\n        return leaderboards.size\n    }\n\n    @SuppressLint(\"SetTextI18n\")\n    override fun onBindViewHolder(holder: LeaderboardHolder, position: Int) {\n        val leaderboardDefinition = leaderboards[position]\n        val iconUrl = leaderboardDefinition.iconUrl\n        if (iconUrl != null) {\n            ImageManager.create(mContext).loadImage(iconUrl, holder.leaderboardLogo)\n        } else {\n            holder.leaderboardLogo?.setImageResource(R.drawable.ic_leaderboard_placeholder)\n        }\n        holder.leaderboardTitle?.text = leaderboardDefinition.name\n        if (position == leaderboards.size - 1) {\n            holder.leaderboardLine?.visibility = View.INVISIBLE\n        }\n        holder.itemView.setOnClickListener { dealClick(leaderboardDefinition) }\n    }\n}\n\nclass LeaderboardHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {\n\n    var leaderboardLogo: ImageView? = null\n    var leaderboardTitle: TextView? = null\n    var leaderboardLine: View? = null\n\n    init {\n        leaderboardLogo = itemView.findViewById(R.id.leaderboard_logo)\n        leaderboardTitle = itemView.findViewById(R.id.leaderboard_title)\n        leaderboardLine = itemView.findViewById(R.id.leaderboard_line)\n    }\n\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/games/leaderboards/LeaderboardsApiClient.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.games.leaderboards\n\nimport android.content.Context\nimport com.android.volley.Request\nimport org.microg.gms.games.requestGamesInfo\nimport java.util.Locale\nimport java.util.UUID\n\n/**\n * https://developers.google.com/games/services/web/api/rest#rest-resource:-leaderboards\n * https://developers.google.com/games/services/web/api/rest#rest-resource:-scores\n */\nobject LeaderboardsApiClient {\n\n    /**\n     * Lists all the leaderboard metadata for your application.\n     */\n    suspend fun requestAllLeaderboards(mContext: Context, oauthToken: String, pageToken: String? = null) =\n        requestGamesInfo(mContext, Request.Method.GET, oauthToken, \"https://games.googleapis.com/games/v1/leaderboards\", HashMap<String, String>().apply {\n            put(\"language\", Locale.getDefault().language)\n            if (pageToken != null) {\n                put(\"pageToken\", pageToken)\n            }\n        }).toLeaderboardListResponse()\n\n    /**\n     * Retrieves the metadata of the leaderboard with the given ID.\n     */\n    suspend fun getLeaderboardById(mContext: Context, oauthToken: String, leaderboardId: String) = requestGamesInfo(mContext,\n        Request.Method.GET,\n        oauthToken,\n        \"https://games.googleapis.com/games/v1/leaderboards/${leaderboardId}\",\n        HashMap<String, String>().apply {\n            put(\"language\", Locale.getDefault().language)\n        }).toLeaderboardResponse()\n\n    /**\n     * Get high scores, and optionally ranks, in leaderboards for the currently authenticated player.\n     * For a specific time span, leaderboardId can be set to ALL to retrieve data for all leaderboards in a given time span.\n     * `NOTE: You cannot ask for 'ALL' leaderboards and 'ALL' timeSpans in the same request; only one parameter may be set to 'ALL'.\n     */\n    suspend fun getLeaderboardScoresById(\n        mContext: Context, oauthToken: String, leaderboardId: String, timeSpan: ScoreTimeSpan, pageToken: String? = null\n    ) = requestGamesInfo(mContext,\n        Request.Method.GET,\n        oauthToken,\n        \"https://games.googleapis.com/games/v1/players/me/leaderboards/$leaderboardId/scores/$timeSpan\",\n        HashMap<String, String>().apply {\n            put(\"language\", Locale.getDefault().language)\n            put(\"includeRankType\", IncludeRankType.PUBLIC.toString())\n            if (pageToken != null) {\n                put(\"pageToken\", pageToken)\n            }\n        }).toGetLeaderboardScoresResponse()\n\n    /**\n     * Lists the scores in a leaderboard, starting from the top.\n     */\n    suspend fun requestLeaderboardScoresById(\n        mContext: Context, oauthToken: String, leaderboardId: String, pageToken: String? = null\n    ) = requestGamesInfo(mContext,\n        Request.Method.GET,\n        oauthToken,\n        \"https://games.googleapis.com/games/v1/leaderboards/$leaderboardId/scores/${IncludeRankType.PUBLIC}\",\n        HashMap<String, String>().apply {\n            put(\"language\", Locale.getDefault().language)\n            put(\"timeSpan\", ScoreTimeSpan.ALL_TIME.toString())\n            if (pageToken != null) {\n                put(\"pageToken\", pageToken)\n            }\n        }).toListLeaderboardScoresResponse()\n\n    /**\n     * Lists the scores in a leaderboard around (and including) a player's score.\n     */\n    suspend fun requestLeaderboardScoresListWindowById(\n        mContext: Context, oauthToken: String, leaderboardId: String, collection: IncludeRankType, timeSpan: ScoreTimeSpan, pageToken: String? = null\n    ) = requestGamesInfo(mContext,\n        Request.Method.GET,\n        oauthToken,\n        \"https://games.googleapis.com/games/v1/leaderboards/$leaderboardId/window/$collection\",\n        HashMap<String, String>().apply {\n            put(\"language\", Locale.getDefault().language)\n            put(\"timeSpan\", timeSpan.toString())\n            put(\"returnTopIfAbsent\", \"true\")\n            if (pageToken != null) {\n                put(\"pageToken\", pageToken)\n            }\n        }).toListLeaderboardScoresResponse()\n\n    /**\n     * Submits a score to the specified leaderboard.\n     */\n    suspend fun submitLeaderboardScores(mContext: Context, oauthToken: String, leaderboardId: String, score: String) = requestGamesInfo(\n        mContext,\n        Request.Method.POST,\n        oauthToken,\n        \"https://games.googleapis.com/games/v1/leaderboards/$leaderboardId/scores\",\n        HashMap<String, String>().apply {\n            put(\"language\", Locale.getDefault().language)\n            put(\"score\", score)\n            put(\"scoreTag\", UUID.fromString(leaderboardId + score).toString())\n        }).toSubmitLeaderboardScoreResponse()\n\n    /**\n     * Submits multiple scores to leaderboards.\n     */\n    suspend fun submitMultipleLeaderboardScores(\n        mContext: Context, oauthToken: String, list: PlayerScoreSubmissionList\n    ) = requestGamesInfo(\n        mContext, Request.Method.POST, oauthToken, \"https://games.googleapis.com/games/v1/leaderboards/scores\", HashMap<String, String>().apply {\n            put(\"language\", Locale.getDefault().language)\n        }, list.toJSONObject()\n    ).toSubmitLeaderboardScoreListResponse()\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/games/snapshot/SnapshotResponseKt.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.games.snapshot\n\nimport org.json.JSONArray\nimport org.json.JSONObject\nimport org.microg.gms.games.GameSnapshot\n\ndata class SnapshotsResponse(\n    val kind: String?, val nextPageToken: String?, val items: List<Snapshot>?\n) {\n    override fun toString(): String {\n        return \"SnapshotsResponse(kind=$kind, nextPageToken=$nextPageToken, items=$items)\"\n    }\n}\n\ndata class Snapshot(\n    val id: String?,\n    val driveId: String?,\n    val kind: String?,\n    val type: String?,\n    val title: String?,\n    val description: String?,\n    val lastModifiedMillis: String?,\n    val durationMillis: String?,\n    val coverImage: SnapshotImage?,\n    val uniqueName: String?,\n    val progressValue: String?,\n) {\n\n    constructor(\n        id: String?,\n        title: String?,\n        description: String?,\n        lastModifiedMillis: String?,\n        coverImage: SnapshotImage?\n    ) : this(\n        id, null, null, null, title, description, lastModifiedMillis, null, coverImage, null, null\n    )\n\n    override fun toString(): String {\n        return \"Snapshot(id=$id, driveId=$driveId, kind=$kind, type=$type, title=$title, description=$description, lastModifiedMillis=$lastModifiedMillis, durationMillis=$durationMillis, coverImage=$coverImage, uniqueName=$uniqueName, progressValue=$progressValue)\"\n    }\n}\n\ndata class SnapshotImage(\n    val width: Int?,\n    val height: Int?,\n    val mimeType: String?,\n    val url: String?,\n    val kind: String?,\n) {\n    override fun toString(): String {\n        return \"SnapshotImage(width=$width, height=$height, mimeType='$mimeType', url='$url', kind='$kind')\"\n    }\n}\n\nfun JSONObject.toSnapshotsResponse() = SnapshotsResponse(\n    optString(\"kind\"),\n    optString(\"nextPageToken\"),\n    optJSONArray(\"items\")?.toSnapshot()\n)\n\nfun JSONArray.toSnapshot(): List<Snapshot> {\n    val snapshots = arrayListOf<Snapshot>()\n    for (i in 0..<length()) {\n        val jsonObject = optJSONObject(i)\n        snapshots.add(\n            Snapshot(\n                jsonObject.optString(\"id\"),\n                jsonObject.optString(\"driveId\"),\n                jsonObject.optString(\"kind\"),\n                jsonObject.optString(\"type\"),\n                jsonObject.optString(\"title\"),\n                jsonObject.optString(\"description\"),\n                jsonObject.optString(\"lastModifiedMillis\"),\n                jsonObject.optString(\"durationMillis\"),\n                jsonObject.optJSONObject(\"coverImage\")?.toSnapshotImage(),\n                jsonObject.optString(\"uniqueName\"),\n                jsonObject.optString(\"progressValue\"),\n            )\n        )\n    }\n    return snapshots\n}\n\nfun JSONObject.toSnapshotImage() = SnapshotImage(\n    optInt(\"width\"),\n    optInt(\"height\"),\n    optString(\"mime_type\"),\n    optString(\"url\"),\n    optString(\"kind\")\n)\n\nfun GameSnapshot.toSnapshot() = Snapshot(\n    metadata?.snapshot?.snapshotId,\n    metadata?.snapshotName,\n    metadata?.snapshot?.content?.description,\n    metadata?.snapshot?.content?.snapshotTimeInfo?.timestamp?.toString(),\n    SnapshotImage(\n        metadata?.snapshot?.coverImage?.width,\n        metadata?.snapshot?.coverImage?.height,\n        metadata?.snapshot?.coverImage?.mimeType,\n        metadata?.snapshot?.coverImage?.imageUrl,\n        null\n    )\n)"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/games/snapshot/SnapshotsAdapter.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.games.snapshot\n\nimport android.annotation.SuppressLint\nimport android.content.Context\nimport android.content.Intent\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.ImageView\nimport android.widget.TextView\nimport androidx.recyclerview.widget.RecyclerView\nimport com.google.android.gms.R\nimport com.google.android.gms.common.images.ImageManager\nimport org.microg.gms.games.EXTRA_ALLOW_DELETE_SNAPSHOT\nimport java.text.SimpleDateFormat\nimport java.util.Date\n\nclass SnapshotsAdapter(\n    private val mContext: Context,\n    private val callIntent: Intent,\n    snapshots: List<Snapshot>,\n    private val dealClick: (Snapshot, Int) -> Unit\n) :\n    RecyclerView.Adapter<SnapshotHolder>() {\n\n    private val snapshotDataList = arrayListOf<Snapshot>()\n    private val allowDelete = callIntent.getBooleanExtra(EXTRA_ALLOW_DELETE_SNAPSHOT, false)\n\n    init {\n        snapshotDataList.addAll(snapshots)\n    }\n\n    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SnapshotHolder {\n        val view = LayoutInflater.from(mContext).inflate(R.layout.item_snapshot_data_layout, parent, false)\n        return SnapshotHolder(view)\n    }\n\n    override fun getItemCount(): Int {\n        return snapshotDataList.size\n    }\n\n    @SuppressLint(\"SetTextI18n\")\n    override fun onBindViewHolder(holder: SnapshotHolder, position: Int) {\n        val snapshot = snapshotDataList[position]\n        val imageUrl = snapshot.coverImage?.url\n        if (imageUrl != null) {\n            ImageManager.create(mContext).loadImage(imageUrl, holder.snapshotImage)\n        } else {\n            holder.snapshotImage?.setImageResource(R.drawable.ic_snapshot_load_error_image)\n        }\n        holder.snapshotTime?.text = snapshot.lastModifiedMillis?.let {\n            var timestamp = it.toLong()\n            //Check if the timestamp is greater than 10-digit threshold, indicating milliseconds\n            timestamp = if (timestamp > 10000000000L) timestamp else timestamp * 1000\n            SimpleDateFormat(\"yyyy/MM/dd HH:mm\").format(Date(timestamp))\n        }\n        holder.snapshotDesc?.text = snapshot.description\n        if (allowDelete) {\n            holder.snapshotDeleteBtn?.visibility = View.VISIBLE\n            holder.snapshotDeleteBtn?.setOnClickListener { dealClick(snapshot, 1) }\n        } else{\n            holder.snapshotDeleteBtn?.visibility = View.GONE\n        }\n        holder.snapshotChooseBtn?.setOnClickListener { dealClick(snapshot, 0) }\n    }\n\n    fun update(snapshots: List<Snapshot>) {\n        snapshotDataList.clear()\n        snapshotDataList.addAll(snapshots)\n        notifyDataSetChanged()\n    }\n\n}\n\nclass SnapshotHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {\n\n    var snapshotImage: ImageView? = null\n    var snapshotTime: TextView? = null\n    var snapshotDesc: TextView? = null\n    var snapshotChooseBtn: TextView? = null\n    var snapshotDeleteBtn: TextView? = null\n\n    init {\n        snapshotImage = itemView.findViewById(R.id.snapshot_image)\n        snapshotTime = itemView.findViewById(R.id.snapshot_time)\n        snapshotDesc = itemView.findViewById(R.id.snapshot_desc)\n        snapshotChooseBtn = itemView.findViewById(R.id.snapshot_choose_btn)\n        snapshotDeleteBtn = itemView.findViewById(R.id.snapshot_delete_btn)\n    }\n\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/games/snapshot/SnapshotsApiClient.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.games.snapshot\n\nimport android.content.Context\nimport android.util.Log\nimport com.android.volley.DefaultRetryPolicy\nimport com.android.volley.NetworkResponse\nimport com.android.volley.Request\nimport com.android.volley.RequestQueue\nimport com.android.volley.Response\nimport com.android.volley.VolleyError\nimport com.android.volley.toolbox.HttpHeaderParser\nimport com.google.android.gms.common.BuildConfig\nimport com.squareup.wire.GrpcClient\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\nimport okhttp3.Interceptor\nimport okhttp3.OkHttpClient\nimport org.json.JSONObject\nimport org.microg.gms.checkin.LastCheckinInfo\nimport org.microg.gms.games.CommitSnapshotRevisionRequest\nimport org.microg.gms.games.DeleteSnapshotInfo\nimport org.microg.gms.games.EmptyResult\nimport org.microg.gms.games.GetSnapshotRequest\nimport org.microg.gms.games.SnapshotsExtendedClient\nimport org.microg.gms.games.GetSnapshotResponse\nimport org.microg.gms.games.HeaderInterceptor\nimport org.microg.gms.games.PrepareSnapshotRevisionRequest\nimport org.microg.gms.games.PrepareSnapshotRevisionResponse\nimport org.microg.gms.games.ResolveSnapshotHeadRequest\nimport org.microg.gms.games.ResolveSnapshotHeadResponse\nimport org.microg.gms.games.requestGamesInfo\nimport org.microg.gms.profile.Build\nimport java.util.Locale\nimport kotlin.coroutines.resume\nimport kotlin.coroutines.resumeWithException\nimport kotlin.coroutines.suspendCoroutine\n\nprivate const val TAG = \"SnapshotsApiClient\"\n\n/**\n * https://developers.google.com/games/services/web/api/rest#rest-resource:-snapshots\n *\n * Google Play Games Services can only support obtaining snapshot lists.\n * There is no interface for saving or deleting snapshots.\n */\nobject SnapshotsApiClient {\n\n    private const val POST_TIMEOUT = 15000\n    const val SNAPSHOT_UPLOAD_LINK_DATA = 1\n    const val SNAPSHOT_UPLOAD_LINK_IMAGE = 2\n\n    suspend fun prepareSnapshotRevision(context: Context, oauthToken: String,\n                                        prepareSnapshotRevisionRequest: PrepareSnapshotRevisionRequest) : PrepareSnapshotRevisionResponse {\n        val snapshotClient = getGrpcClient(context, oauthToken)\n        return withContext(Dispatchers.IO) { snapshotClient.PrepareSnapshotRevision().execute(prepareSnapshotRevisionRequest) }\n    }\n\n    suspend fun uploadDataByUrl(oauthToken: String, url: String, requestQueue: RequestQueue, body: ByteArray): String = suspendCoroutine { continuation ->\n        requestQueue.add(object : Request<String>(Method.PUT, url, null) {\n\n            override fun deliverResponse(response: String) {\n                Log.d(TAG, \"deliverResponse: $response\")\n                continuation.resume(response)\n            }\n\n            override fun deliverError(error: VolleyError?) {\n                error?.let {\n                    continuation.resumeWithException(error)\n                }\n            }\n\n            override fun getBody(): ByteArray {\n                return body\n            }\n\n            override fun parseNetworkResponse(response: NetworkResponse): Response<String> {\n                var result = \"\"\n                try {\n                    val json = JSONObject(response.data.toString(Charsets.UTF_8))\n                    result = json.getString(\"resourceId\")\n                } catch (e: Exception) {\n                    Log.w(TAG, \"parseNetworkResponse: \", e)\n                }\n                return Response.success(result, HttpHeaderParser.parseCacheHeaders(response))\n            }\n\n            override fun getHeaders(): MutableMap<String, String> {\n                val headers = HashMap<String, String>()\n                headers[\"authorization\"] = \"OAuth $oauthToken\"\n                headers[\"x-goog-upload-command\"] = \"upload, finalize\"\n                headers[\"x-goog-upload-protocol\"] = \"resumable\"\n                headers[\"Content-Type\"] = \"application/x-www-form-urlencoded\"\n                headers[\"x-goog-upload-offset\"] = \"0\"\n                headers[\"User-Agent\"]  = \"Mozilla/5.0 (Linux; Android ${Build.VERSION.RELEASE}; ${Build.MODEL} Build/${Build.ID};\"\n                return headers\n            }\n        }.setRetryPolicy(DefaultRetryPolicy(POST_TIMEOUT, 0, 0.0F)))\n    }\n\n    suspend fun getDataFromDrive(oauthToken: String, url: String, requestQueue: RequestQueue) : ByteArray = suspendCoroutine { continuation ->\n        requestQueue.add(object : Request<ByteArray>(Method.GET, url, null) {\n            override fun parseNetworkResponse(response: NetworkResponse): Response<ByteArray> {\n                return Response.success(response.data, HttpHeaderParser.parseCacheHeaders(response))\n            }\n\n            override fun deliverResponse(response: ByteArray) {\n                Log.d(TAG, \"deliverResponse: $response\")\n                continuation.resume(response)\n            }\n\n            override fun deliverError(error: VolleyError?) {\n                error?.let {\n                    continuation.resumeWithException(error)\n                }\n            }\n\n            override fun getHeaders(): MutableMap<String, String> {\n                val headers = HashMap<String, String>()\n                headers[\"authorization\"] = \"OAuth $oauthToken\"\n                headers[\"User-Agent\"]  = \"Mozilla/5.0 (Linux; Android ${Build.VERSION.RELEASE}; ${Build.MODEL} Build/${Build.ID};\"\n                return headers\n            }\n\n        }.setRetryPolicy(DefaultRetryPolicy(POST_TIMEOUT, 0, 0.0F)))\n    }\n\n    suspend fun getRealUploadUrl(oauthToken: String, url: String, requestQueue: RequestQueue) : String = suspendCoroutine { continuation ->\n        requestQueue.add(object : Request<String>(Method.POST, url, null) {\n            override fun parseNetworkResponse(response: NetworkResponse): Response<String> {\n                val responseHeaders = response.headers\n                return Response.success(responseHeaders?.get(\"X-Goog-Upload-URL\"), HttpHeaderParser.parseCacheHeaders(response))\n            }\n\n            override fun deliverResponse(response: String?) {\n                Log.d(TAG, \"deliverResponse: $response\")\n                continuation.resume(response?:\"\")\n            }\n\n            override fun deliverError(error: VolleyError?) {\n                error?.let {\n                    continuation.resumeWithException(error)\n                }\n            }\n\n            override fun getHeaders(): MutableMap<String, String> {\n                val headers = HashMap<String, String>()\n                headers[\"authorization\"] = \"OAuth $oauthToken\"\n                headers[\"x-goog-upload-command\"] = \"start\"\n                headers[\"x-goog-upload-protocol\"] = \"resumable\"\n                headers[\"Content-Type\"] = \"application/x-www-form-urlencoded\"\n                headers[\"User-Agent\"]  = \"Mozilla/5.0 (Linux; Android ${Build.VERSION.RELEASE}; ${Build.MODEL} Build/${Build.ID};\"\n                return headers\n            }\n\n        }.setRetryPolicy(DefaultRetryPolicy(POST_TIMEOUT, 0, 0.0F)))\n    }\n\n    /**\n     *  Get the request content by capturing the packet.\n     *  Currently only supports getting list data.\n     */\n    /**\n     *  Get the request content by capturing the packet.\n     *  Currently only supports getting list data.\n     */\n    suspend fun requestSnapshotList(context: Context, oauthToken: String): GetSnapshotResponse {\n        val snapshotClient = getGrpcClient(context, oauthToken)\n        val snapshotRequestBody = GetSnapshotRequest.Builder().apply {\n            unknownFileIntList3 = listOf(2, 3, 1)\n            unknownFileInt4 = 25\n            unknownFileInt6 = 3\n        }.build()\n        return withContext(Dispatchers.IO) { snapshotClient.SyncSnapshots().execute(snapshotRequestBody) }\n    }\n\n    suspend fun deleteSnapshot(context: Context, oauthToken: String, snapshot: Snapshot): EmptyResult {\n        val snapshotClient = getGrpcClient(context, oauthToken)\n        val deleteSnapshotInfo = DeleteSnapshotInfo.Builder().apply {\n            snapshotName = snapshot.title\n            snapshotId = snapshot.id\n        }.build()\n        return withContext(Dispatchers.IO) { snapshotClient.DeleteSnapshot().execute(deleteSnapshotInfo) }\n    }\n\n    suspend fun resolveSnapshotHead(context: Context, oauthToken: String, resolveSnapshotHeadRequest: ResolveSnapshotHeadRequest): ResolveSnapshotHeadResponse {\n        val snapshotClient = getGrpcClient(context, oauthToken)\n        return withContext(Dispatchers.IO) { snapshotClient.ResolveSnapshotHead().execute(resolveSnapshotHeadRequest) }\n    }\n\n    suspend fun commitSnapshotRevision(context: Context, oauthToken: String,\n                                       commitSnapshotRevisionRequest: CommitSnapshotRevisionRequest): EmptyResult {\n        val snapshotClient = getGrpcClient(context, oauthToken)\n        return withContext(Dispatchers.IO) { snapshotClient.CommitSnapshotRevision().execute(commitSnapshotRevisionRequest) }\n    }\n\n    private fun getGrpcClient(context: Context, oauthToken: String) : SnapshotsExtendedClient {\n        val client = OkHttpClient().newBuilder().addInterceptor(\n            HeaderInterceptor(context, oauthToken)\n        ).build()\n        val grpcClient = GrpcClient.Builder().client(client).baseUrl(\"https://games.googleapis.com\").build()\n        return grpcClient.create(SnapshotsExtendedClient::class)\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/games/snapshot/SnapshotsDataClient.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.games.snapshot\n\nimport android.annotation.SuppressLint\nimport android.content.Context\nimport android.graphics.Bitmap\nimport android.text.TextUtils\nimport android.util.Log\nimport com.android.volley.toolbox.Volley\nimport com.google.android.gms.common.util.IOUtils\nimport com.google.android.gms.drive.Contents\nimport com.google.android.gms.games.snapshot.SnapshotMetadataChangeEntity\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.async\nimport kotlinx.coroutines.withContext\nimport org.microg.gms.games.CommitSnapshotRevisionRequest\nimport org.microg.gms.games.PrepareSnapshotRevisionRequest\nimport org.microg.gms.games.ResolveSnapshotHeadRequest\nimport org.microg.gms.games.SnapshotContent\nimport org.microg.gms.games.SnapshotContentInfo\nimport org.microg.gms.games.SnapshotTimeInfo\nimport org.microg.gms.games.snapshot.SnapshotsApiClient.SNAPSHOT_UPLOAD_LINK_DATA\nimport org.microg.gms.games.snapshot.SnapshotsApiClient.SNAPSHOT_UPLOAD_LINK_IMAGE\nimport org.microg.gms.games.ukq\nimport org.microg.gms.profile.Build\nimport org.microg.gms.utils.BitmapUtils\nimport org.microg.gms.utils.singleInstanceOf\nimport java.io.BufferedInputStream\nimport java.io.ByteArrayOutputStream\nimport java.io.IOException\nimport java.util.UUID\n\nclass SnapshotsDataClient(val context: Context) {\n\n    private val requestQueue = singleInstanceOf { Volley.newRequestQueue(context.applicationContext) }\n\n    suspend fun loadSnapshotData(oauthToken: String) = withContext(Dispatchers.IO) {\n        val snapshots = arrayListOf<Snapshot>()\n        val snapshotsResponse = runCatching { SnapshotsApiClient.requestSnapshotList(context, oauthToken) }.getOrNull()\n        snapshotsResponse?.gameSnapshot?.forEach {\n            snapshots.add(it.toSnapshot())\n        }\n        return@withContext snapshots\n    }\n\n    private suspend fun uploadDataByUrl(oauthToken: String, url: String, body: ByteArray) = withContext(Dispatchers.IO) {\n        runCatching { SnapshotsApiClient.uploadDataByUrl(oauthToken, url, requestQueue, body) }\n    }\n\n    suspend fun getDataFromDrive(oauthToken: String, url: String) = withContext(Dispatchers.IO) {\n        runCatching { SnapshotsApiClient.getDataFromDrive(oauthToken, url, requestQueue) }.getOrNull()\n    }\n\n    private suspend fun getRealUploadUrl(oauthToken: String, url: String) = withContext(Dispatchers.IO) {\n        runCatching { SnapshotsApiClient.getRealUploadUrl(oauthToken, url, requestQueue) }.getOrNull()\n    }\n\n    suspend fun resolveSnapshotHead(oauthToken: String, resolveSnapshotHeadRequest: ResolveSnapshotHeadRequest) = withContext(Dispatchers.IO) {\n        runCatching { SnapshotsApiClient.resolveSnapshotHead(context, oauthToken, resolveSnapshotHeadRequest) }.getOrNull()\n    }\n\n    private suspend fun prepareSnapshotRevision(oauthToken: String, prepareSnapshotRevisionRequest: PrepareSnapshotRevisionRequest) =\n        withContext(Dispatchers.IO) {\n            runCatching { SnapshotsApiClient.prepareSnapshotRevision(context, oauthToken, prepareSnapshotRevisionRequest) }.getOrNull()\n        }\n\n    private suspend fun commitSnapshotRevision(oauthToken: String, commitSnapshotRevisionRequest: CommitSnapshotRevisionRequest) = withContext(Dispatchers.IO) {\n        runCatching { SnapshotsApiClient.commitSnapshotRevision(context, oauthToken, commitSnapshotRevisionRequest) }.getOrNull()\n    }\n\n    suspend fun deleteSnapshotData(oauthToken: String, snapshot: Snapshot) = withContext(Dispatchers.IO) {\n        runCatching { SnapshotsApiClient.deleteSnapshot(context, oauthToken, snapshot) }.getOrNull()\n    }\n\n    suspend fun commitSnapshot(\n        oauthToken: String, snapshotTitle: String?, change: SnapshotMetadataChangeEntity, contents: Contents, maxCoverImageSize: Int\n    ) = withContext(Dispatchers.IO) {\n        runCatching {\n            if (TextUtils.isEmpty(snapshotTitle)) {\n                return@runCatching false\n            }\n\n            //Get data upload link\n            val ret = prepareSnapshotRevision(oauthToken, createPrepareSnapshotRevisionRequest(change, snapshotTitle!!))\n            Log.d(TAG, \"commitSnapshot ret: $ret\")\n            if (ret != null && ret.uploadLinkInfos.isNotEmpty()) {\n                val imageUploadTempUrl = ret.uploadLinkInfos.firstOrNull { it.id == SNAPSHOT_UPLOAD_LINK_IMAGE }?.url\n\n                val snapshotDataUploadTempUrl = ret.uploadLinkInfos.firstOrNull { it.id == SNAPSHOT_UPLOAD_LINK_DATA }?.url\n                if (snapshotDataUploadTempUrl == null) {\n                    Log.w(TAG, \"commitSnapshot data upload temp url is null\")\n                    return@runCatching false\n                }\n\n                val deferredGetImageRealUploadUrl = async {\n                    Log.w(TAG, \"commitSnapshot image upload temp url is null\")\n                    if (imageUploadTempUrl == null) {\n                        null\n                    } else {\n                        getRealUploadUrl(oauthToken, imageUploadTempUrl)\n                    }\n                }\n                val deferredGetDataRealUploadUrl = async {\n                    getRealUploadUrl(oauthToken, snapshotDataUploadTempUrl)\n                }\n\n\n                val deferredUploadSnapshotImage = async {\n                    val snapshotImageUploadUrl = deferredGetImageRealUploadUrl.await()\n                    if (snapshotImageUploadUrl == null) {\n                        Log.w(TAG, \"commitSnapshot image upload url is null\")\n                        Triple(0, 0, null)\n                    } else {\n                        uploadSnapshotImage(\n                            change!!.coverImageTeleporter!!.createTargetBitmap(), maxCoverImageSize, oauthToken, snapshotImageUploadUrl\n                        )\n                    }\n\n                }\n\n                val deferredUploadSnapshotData = async {\n                    val snapshotDataUploadUrl = deferredGetDataRealUploadUrl.await()\n                    if (snapshotDataUploadUrl == null) {\n                        Log.w(TAG, \"commitSnapshot data upload url is null\")\n                        return@async null\n                    }\n                    uploadSnapshotData(contents, oauthToken, snapshotDataUploadUrl)\n                }\n\n                val deferredCommit = async {\n                    val (imageWidth, imageHeight, snapShotImageResourceId: String?) = deferredUploadSnapshotImage.await()\n                    val snapshotDataResourceId = deferredUploadSnapshotData.await()\n                    if (snapshotDataResourceId != null) {\n                        commitSnapshotRevision(\n                            oauthToken, createCommitSnapshotRequest(\n                                change, snapshotDataResourceId, snapShotImageResourceId, imageWidth, imageHeight, snapshotTitle\n                            )\n                        )\n                    } else {\n                        return@async false\n                    }\n                }\n                deferredCommit.await()\n                return@runCatching true\n            } else {\n                return@runCatching false\n            }\n        }.getOrNull()\n    }\n\n    private fun createPrepareSnapshotRevisionRequest(change: SnapshotMetadataChangeEntity, snapshotTitle: String): PrepareSnapshotRevisionRequest {\n        val snapshotUpDateLink = mutableListOf<ukq>()\n        snapshotUpDateLink.add(ukq.Builder().apply {\n            unknownFileInt1 = SNAPSHOT_UPLOAD_LINK_DATA\n            unknownFileInt2 = 1\n        }.build())\n        if (change.coverImageTeleporter != null) {\n            snapshotUpDateLink.add(ukq.Builder().apply {\n                unknownFileInt1 = SNAPSHOT_UPLOAD_LINK_IMAGE\n                unknownFileInt2 = 1\n            }.build())\n        }\n        val prepareSnapshotRevisionRequest = PrepareSnapshotRevisionRequest.Builder().apply {\n            title = snapshotTitle\n            c = snapshotUpDateLink\n            randomUUID = UUID.randomUUID().toString()\n        }.build()\n        return prepareSnapshotRevisionRequest\n    }\n\n    private fun createCommitSnapshotRequest(\n        change: SnapshotMetadataChangeEntity,\n        snapshotDataResourceId: String,\n        snapShotImageResourceId: String?,\n        imageWidth: Int,\n        imageHeight: Int,\n        snapshotTitle: String\n    ): CommitSnapshotRevisionRequest {\n        Log.d(TAG, \"createCommitSnapshotRequest: \")\n        val snapshotTimeInfo = getSnapshotTimeInfo()\n        val snapshotContent = SnapshotContent.Builder().apply {\n            description = change.description\n            this.snapshotTimeInfo = snapshotTimeInfo\n            progressValue = change.progressValue ?: -1\n            this.deviceName = Build.DEVICE\n            duration = change.progressValue ?: -1\n        }.build()\n        val snapshotContentInfo = SnapshotContentInfo.Builder().apply {\n            token = snapshotDataResourceId\n        }.build()\n\n        val snapshotImage: org.microg.gms.games.SnapshotImage? = if (!TextUtils.isEmpty(snapShotImageResourceId)) {\n            org.microg.gms.games.SnapshotImage.Builder().apply {\n                this.token = snapShotImageResourceId\n                this.width = imageWidth\n                this.height = imageHeight\n            }.build()\n        } else {\n            null\n        }\n\n        val snapshotBuilder = org.microg.gms.games.Snapshot.Builder().apply {\n            content = snapshotContent\n            this.snapshotContentInfo = snapshotContentInfo\n        }\n        if (snapshotImage != null) {\n            snapshotBuilder.coverImage = snapshotImage\n        }\n        val commitSnapshotRevisionRequest = CommitSnapshotRevisionRequest.Builder().apply {\n            this.snapshotName = snapshotTitle\n            this.snapshot = snapshotBuilder.build()\n            this.randomUUID = UUID.randomUUID().toString()\n            this.unknownFileInt7 = 3\n        }.build()\n        return commitSnapshotRevisionRequest\n    }\n\n    private suspend fun uploadSnapshotData(contents: Contents, oauthToken: String, snapshotDataUploadUrl: String): String? {\n        Log.d(TAG, \"uploadSnapshotData: $snapshotDataUploadUrl\")\n        val readInputStreamFully: ByteArray\n        val fileInputStream = contents.inputStream\n        val bufferedInputStream = BufferedInputStream(fileInputStream)\n        var snapshotDataResourceId: String? = null\n        try {\n            fileInputStream.channel.position(0L)\n            readInputStreamFully = IOUtils.readInputStreamFully(bufferedInputStream, false)\n            fileInputStream.channel.position(0L)\n            snapshotDataResourceId = uploadDataByUrl(oauthToken, snapshotDataUploadUrl, readInputStreamFully).getOrNull()\n            fileInputStream.close()\n        } catch (e: IOException) {\n            Log.w(\"SnapshotContentsEntity\", \"Failed to read snapshot data\", e)\n        }\n        return snapshotDataResourceId\n    }\n\n    private suspend fun uploadSnapshotImage(bitmap: Bitmap, maxCoverImageSize: Int, oauthToken: String, imageUploadUrl: String): Triple<Int, Int, String?> {\n        Log.d(TAG, \"uploadSnapshotImage imageUploadUrl: $imageUploadUrl\")\n        var snapshotBitmap = bitmap\n        val bitmapSize = BitmapUtils.getBitmapSize(snapshotBitmap)\n        if (bitmapSize > maxCoverImageSize) {\n            Log.w(TAG, \"commitSnapshot Snapshot cover image is too large. Currently at $bitmapSize bytes; max is $maxCoverImageSize Image will be scaled\")\n            snapshotBitmap = BitmapUtils.scaledBitmap(snapshotBitmap, maxCoverImageSize.toFloat())\n            Log.d(TAG, \"commitSnapshot scaledBitmap: ${snapshotBitmap.width} ${snapshotBitmap.height}\")\n        }\n        Log.d(TAG, \"commitSnapshot snapshotBitmap: $snapshotBitmap\")\n        val byteArrayOutputStream = ByteArrayOutputStream()\n        snapshotBitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream)\n        val snapShotImageResourceId = uploadDataByUrl(oauthToken, imageUploadUrl, byteArrayOutputStream.toByteArray()).getOrNull()\n        snapshotBitmap.recycle()\n        bitmap.recycle()\n        withContext(Dispatchers.IO) {\n            byteArrayOutputStream.close()\n        }\n        var imageWidth = snapshotBitmap.width\n        var imageHeight = snapshotBitmap.height\n        if (imageWidth > imageHeight) {\n            val temp = imageWidth\n            imageWidth = imageHeight\n            imageHeight = temp\n        }\n        Log.d(TAG, \"commitSnapshot $imageWidth: $imageHeight\")\n        return Triple(imageWidth, imageHeight, snapShotImageResourceId)\n    }\n\n    private fun getSnapshotTimeInfo(): SnapshotTimeInfo {\n        val timestamp = System.currentTimeMillis()\n        return SnapshotTimeInfo.Builder().apply {\n            this.timestamp = timestamp / 1000\n            this.playedTime = ((timestamp % 1000) * 1000000).toInt()\n        }.build()\n    }\n\n    companion object {\n        private const val TAG = \"SnapshotsDataClient\"\n\n        @SuppressLint(\"StaticFieldLeak\")\n        @Volatile\n        private var instance: SnapshotsDataClient? = null\n        fun get(context: Context): SnapshotsDataClient = instance ?: synchronized(this) {\n            instance ?: SnapshotsDataClient(context.applicationContext).also { instance = it }\n        }\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/games/ui/GameAccountChangeAdapter.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.games.ui\n\nimport android.graphics.drawable.Drawable\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.Button\nimport android.widget.ImageView\nimport android.widget.TextView\nimport androidx.recyclerview.widget.RecyclerView\nimport com.google.android.gms.R\n\nclass GameAccountChangeAdapter(\n    private val items: List<GameItem>, private val onChangeClick: (GameItem) -> Unit\n) : RecyclerView.Adapter<GameAccountChangeAdapter.GameAccountChangeViewHolder>() {\n\n    inner class GameAccountChangeViewHolder(view: View) : RecyclerView.ViewHolder(view) {\n        val icon: ImageView = view.findViewById(R.id.img_game_icon)\n        val name: TextView = view.findViewById(R.id.tv_game_name)\n        val tips: TextView = view.findViewById(R.id.tv_game_tips)\n        val btn: Button = view.findViewById(R.id.btn_click)\n    }\n\n    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GameAccountChangeViewHolder {\n        val view = LayoutInflater.from(parent.context).inflate(R.layout.item_game_account_data, parent, false)\n        return GameAccountChangeViewHolder(view)\n    }\n\n    override fun onBindViewHolder(holder: GameAccountChangeViewHolder, position: Int) {\n        val item = items[position]\n        holder.icon.setImageDrawable(item.icon)\n        holder.name.text = item.gameName\n        holder.tips.text = item.defaultAccount ?: holder.itemView.context.getString(R.string.games_state_description_signed_out)\n        holder.btn.text = holder.itemView.context.getString(R.string.games_change_button_text)\n        holder.btn.setOnClickListener { onChangeClick(item) }\n    }\n\n    override fun getItemCount(): Int = items.size\n}\n\ndata class GameItem(\n    val icon: Drawable?, val gameName: String?, val defaultAccount: String?, val gamePackageName: String? = null\n)\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/games/ui/GameChangeAccountFragment.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.games.ui\n\nimport android.accounts.Account\nimport android.content.Context\nimport android.os.Bundle\nimport android.util.Log\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.Button\nimport android.widget.ImageView\nimport android.widget.LinearLayout\nimport android.widget.TextView\nimport androidx.appcompat.app.AlertDialog\nimport androidx.appcompat.widget.AppCompatRadioButton\nimport androidx.fragment.app.Fragment\nimport androidx.lifecycle.lifecycleScope\nimport androidx.recyclerview.widget.LinearLayoutManager\nimport androidx.recyclerview.widget.RecyclerView\nimport com.google.android.gms.R\nimport com.google.android.material.bottomsheet.BottomSheetDialog\nimport com.google.android.material.snackbar.Snackbar\nimport org.json.JSONObject\nimport org.microg.gms.games.GAMES_PACKAGE_NAME\nimport org.microg.gms.games.GamesConfigurationService\nimport org.microg.gms.games.fetchAllSelfPlayers\nimport org.microg.gms.games.toPlayer\n\nclass GameChangeAccountFragment : Fragment() {\n\n    companion object {\n        const val TAG = \"GameChangeAccount\"\n\n        fun newInstance(): GameChangeAccountFragment {\n            val fragment = GameChangeAccountFragment()\n            return fragment\n        }\n    }\n\n    private lateinit var defaultAccountText: TextView\n    private lateinit var recyclerView: RecyclerView\n    private lateinit var changeDefaultBtn: Button\n\n    private var currentPlayer: Pair<Account, String>? = null\n    private var allPlayers: List<Pair<Account, String>> = emptyList()\n    private var playedGames: List<String> = emptyList()\n\n    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {\n        return layoutInflater.inflate(R.layout.fragment_game_change_account, container, false);\n    }\n\n    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {\n        super.onViewCreated(view, savedInstanceState)\n        defaultAccountText = view.findViewById(R.id.change_default_account) ?: defaultAccountText\n        recyclerView = view.findViewById(R.id.recycler_view_games) ?: recyclerView\n        changeDefaultBtn = view.findViewById(R.id.btn_change_default) ?: changeDefaultBtn\n\n        lifecycleScope.launchWhenCreated {\n            allPlayers = fetchAllSelfPlayers(requireContext())\n            if (allPlayers.isEmpty()) {\n                requireActivity().finish()\n                return@launchWhenCreated\n            }\n            recyclerView.layoutManager = LinearLayoutManager(requireContext())\n            changeDefaultBtn.setOnClickListener { showChangeCurrentConfirmationDialog() }\n            initDefaultAccount()\n            loadPlayedGames()\n        }\n    }\n\n    override fun onResume() {\n        super.onResume()\n        lifecycleScope.launchWhenResumed {\n            loadPlayedGames()\n        }\n    }\n\n    private suspend fun loadPlayedGames() {\n        GamesConfigurationService.loadPlayedGames(requireContext())?.let { playedGames = ArrayList(it) }\n        Log.d(TAG, \"loadPlayedGames: $playedGames\")\n        fun getGameInfo(context: Context, packageName: String) = runCatching {\n            val packageManager = context.packageManager\n            val appInfo = packageManager.getApplicationInfo(packageName, 0)\n            val appName = packageManager.getApplicationLabel(appInfo).toString()\n            val appIcon = packageManager.getApplicationIcon(appInfo)\n            Pair(appName, appIcon)\n        }.getOrNull()\n\n        val gameItems = playedGames.mapNotNull {\n            val defaultAccount = GamesConfigurationService.getDefaultAccount(requireContext(), it)\n            val gameInfo = getGameInfo(requireContext(), it)\n            val playerName = allPlayers.find { it.first.name == defaultAccount?.name }?.second\n            val name = if (defaultAccount != null && playerName != null) \"${defaultAccount.name} (${playerName})\" else null\n            if (gameInfo != null) {\n                GameItem(gameInfo.second, gameInfo.first, name, it)\n            } else null\n        }\n        if (gameItems.isEmpty()) {\n            return\n        }\n        recyclerView.adapter = GameAccountChangeAdapter(gameItems.sortedBy { it.gameName }) { item ->\n            showChangeCurrentConfirmationDialog(item)\n        }\n    }\n\n    private suspend fun initDefaultAccount() {\n        var defaultAccount = GamesConfigurationService.getDefaultAccount(requireContext(), GAMES_PACKAGE_NAME)\n        currentPlayer = if (defaultAccount == null) {\n            (allPlayers.find { it.first.name == currentPlayer?.first?.name } ?: allPlayers.first()).also {\n                GamesConfigurationService.setDefaultAccount(requireContext(), GAMES_PACKAGE_NAME, it.first)\n            }\n        } else {\n            val player = GamesConfigurationService.getPlayer(requireContext(), defaultAccount)\n            JSONObject(player).toPlayer().displayName?.let { Pair(defaultAccount, it) }\n        }\n        defaultAccountText.text = String.format(\n            requireContext().getString(R.string.games_change_default_account_description), \"${currentPlayer?.first?.name} (${currentPlayer?.second})\"\n        )\n        defaultAccountText.visibility = View.VISIBLE\n    }\n\n    private fun showChangeCurrentConfirmationDialog(gameItem: GameItem? = null) {\n        val dialogView = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_game_account_change_confirmation, null)\n\n        val dialog = BottomSheetDialog(requireContext())\n        dialog.setContentView(dialogView)\n        dialog.setOnDismissListener {\n            lifecycleScope.launchWhenStarted { loadPlayedGames() }\n        }\n        dialog.show()\n\n        val gameInfoContainer = dialog.findViewById<LinearLayout>(R.id.game_info_container)\n        val dialogSecondTitle = dialogView.findViewById<TextView>(R.id.tv_dialog_second_title)\n        val dialogTitle = dialogView.findViewById<TextView>(R.id.tv_dialog_title)\n        val radioChooseContainer = dialogView.findViewById<LinearLayout>(R.id.llt_radio_choose_container)\n\n        if (gameItem != null) {\n            gameInfoContainer?.visibility = View.VISIBLE\n            dialogView.findViewById<TextView>(R.id.tv_game_name).text = gameItem.gameName\n            dialogView.findViewById<TextView>(R.id.tv_game_account).text = gameItem.defaultAccount ?: requireContext().getString(R.string.games_state_description_signed_out)\n            dialogView.findViewById<ImageView>(R.id.img_game_icon).setImageDrawable(gameItem.icon)\n\n            dialogTitle.text = requireContext().getString(R.string.games_change_per_game_dialog_title)\n            dialogSecondTitle.text = requireContext().getString(R.string.games_change_per_game_dialog_description)\n\n            allPlayers.filter { gameItem.defaultAccount == null || gameItem.defaultAccount.contains(it.first.name) == false }.forEach {\n                buildRadioItem(\n                    String.format(requireContext().getString(R.string.games_change_per_game_dialog_option_use_player), \"${it.first.name} (${it.second})\"),\n                ) {\n                    lifecycleScope.launchWhenStarted {\n                        GamesConfigurationService.setDefaultAccount(requireContext(), gameItem.gamePackageName, it.first)\n                        dialog.dismiss()\n                        Snackbar.make(\n                            requireView(),\n                            String.format(requireContext().getString(R.string.games_change_per_game_dialog_option_use_player_snackbar_success_message), \"${it.first.name} (${it.second})\"),\n                            Snackbar.LENGTH_SHORT\n                        ).show()\n                    }\n                }.also { radioChooseContainer.addView(it) }\n            }\n\n            if (gameItem.defaultAccount != null) {\n                buildRadioItem(\n                    requireContext().getString(R.string.games_change_per_game_dialog_option_sign_out),\n                ) {\n                    lifecycleScope.launchWhenStarted {\n                        GamesConfigurationService.setDefaultAccount(requireContext(), gameItem.gamePackageName, null)\n                        dialog.dismiss()\n                        Snackbar.make(\n                            requireView(), requireContext().getString(R.string.games_change_per_game_dialog_option_sign_out_snackbar_success_message), Snackbar.LENGTH_SHORT\n                        ).show()\n                    }\n                }.also { radioChooseContainer.addView(it) }\n            }\n        } else {\n            gameInfoContainer?.visibility = View.GONE\n            dialogTitle.text = requireContext().getString(R.string.games_change_default_account_for_all_games_dialog_title)\n            dialogSecondTitle.text = String.format(\n                requireContext().getString(R.string.games_change_default_account_for_all_games_dialog_description), \"${currentPlayer?.first?.name} (${currentPlayer?.second})\"\n            )\n            buildRadioItem(\n                requireContext().getString(R.string.games_change_default_account_for_all_games_dialog_option_only_for_new_games_title),\n                requireContext().getString(R.string.games_change_default_account_for_all_games_dialog_option_only_for_new_games_description)\n            ) {\n                dialog.dismiss()\n                chooseAccountDialog(false)\n            }.also { radioChooseContainer.addView(it) }\n            buildRadioItem(\n                requireContext().getString(R.string.games_change_default_account_for_all_games_dialog_option_for_all_games_title),\n                requireContext().getString(R.string.games_change_default_account_for_all_games_dialog_option_for_all_games_description)\n            ) {\n                dialog.dismiss()\n                chooseAccountDialog(true)\n            }.also { radioChooseContainer.addView(it) }\n            buildRadioItem(\n                requireContext().getString(R.string.games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_title),\n                requireContext().getString(R.string.games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_description)\n            ) {\n                lifecycleScope.launchWhenStarted {\n                    playedGames.forEach { GamesConfigurationService.setDefaultAccount(requireContext(), it, null) }\n                    dialog.dismiss()\n                    Snackbar.make(\n                        requireView(), requireContext().getString(R.string.games_change_sign_out_of_all_games_snackbar_success_message), Snackbar.LENGTH_SHORT\n                    ).show()\n                }\n            }.also { radioChooseContainer.addView(it) }\n        }\n\n        dialogView.findViewById<Button>(R.id.btn_change_cancel).setOnClickListener {\n            dialog.dismiss()\n        }\n    }\n\n    private fun chooseAccountDialog(changeAllGames: Boolean) {\n        AlertDialog.Builder(requireContext()).setTitle(requireContext().getString(R.string.credentials_assisted_choose_account_label)).setItems(allPlayers.map {\n            \"${it.first.name} (${it.second})\"\n        }.toTypedArray()) { _, which ->\n            lifecycleScope.launchWhenStarted {\n                currentPlayer = allPlayers[which]\n                GamesConfigurationService.setDefaultAccount(requireContext(), GAMES_PACKAGE_NAME, currentPlayer?.first)\n                val tips = if (changeAllGames) {\n                    playedGames.forEach { GamesConfigurationService.setDefaultAccount(requireContext(), it, currentPlayer?.first) }\n                    String.format(requireContext().getString(R.string.games_change_default_account_for_all_games_snackbar_success_message), \"${currentPlayer?.first?.name} (${currentPlayer?.second})\")\n                } else {\n                    String.format(requireContext().getString(R.string.games_change_default_account_for_new_games_snackbar_success_message), \"${currentPlayer?.first?.name} (${currentPlayer?.second})\")\n                }\n                Snackbar.make(requireView(), tips, Snackbar.LENGTH_SHORT).show()\n                initDefaultAccount()\n                loadPlayedGames()\n            }\n        }.setNegativeButton(requireContext().getString(R.string.games_delete_snapshot_dialog_cancel), null).show()\n    }\n\n    private fun buildRadioItem(btnTitle: String, btnDescription: String? = null, onItemClick: () -> Unit): View {\n        val radioRoot = LayoutInflater.from(requireContext()).inflate(R.layout.item_game_account_radio_root, null)\n        radioRoot.findViewById<AppCompatRadioButton>(R.id.game_radio_button_title).text = btnTitle\n        radioRoot.findViewById<TextView>(R.id.game_radio_button_tips).apply {\n            visibility = if (btnDescription.isNullOrEmpty()) View.GONE else View.VISIBLE\n            text = btnDescription\n        }\n        radioRoot.setOnClickListener { onItemClick() }\n        return radioRoot\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/games/ui/GameDataDeleteAdapter.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.games.ui\n\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.Button\nimport android.widget.ImageView\nimport android.widget.TextView\nimport androidx.recyclerview.widget.RecyclerView\nimport com.google.android.gms.common.images.ImageManager\nimport com.google.android.gms.R\n\nclass GameDataDeleteAdapter(\n    private val items: List<GameDataDeleteItem>, private val onChangeClick: (GameDataDeleteItem) -> Unit\n) : RecyclerView.Adapter<GameDataDeleteAdapter.GameDataDeleteViewHolder>() {\n\n    inner class GameDataDeleteViewHolder(view: View) : RecyclerView.ViewHolder(view) {\n        val icon: ImageView = view.findViewById(R.id.img_game_icon)\n        val name: TextView = view.findViewById(R.id.tv_game_name)\n        val tips: TextView = view.findViewById(R.id.tv_game_tips)\n        val btn: Button = view.findViewById(R.id.btn_click)\n    }\n\n    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GameDataDeleteViewHolder {\n        val view = LayoutInflater.from(parent.context).inflate(R.layout.item_game_account_data, parent, false)\n        return GameDataDeleteViewHolder(view)\n    }\n\n    override fun onBindViewHolder(holder: GameDataDeleteViewHolder, position: Int) {\n        val item = items[position]\n        ImageManager.create(holder.icon.context).loadImage(item.iconUrl, holder.icon)\n        holder.name.text = item.gameName\n        holder.tips.text = item.tips\n        holder.btn.text = holder.itemView.context.getString(R.string.games_state_description_delete)\n        holder.btn.setOnClickListener { onChangeClick(item) }\n    }\n\n    override fun getItemCount(): Int = items.size\n}\n\ndata class GameDataDeleteItem(\n    val iconUrl: String?, val gameName: String?, val gameId: String?, val tips: String?\n)"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/games/ui/GameDeletePlayAccountFragment.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.games.ui\n\nimport android.accounts.Account\nimport android.content.Context\nimport android.os.Bundle\nimport android.util.Log\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.Button\nimport android.widget.ProgressBar\nimport android.widget.TextView\nimport android.widget.Toast\nimport androidx.appcompat.app.AlertDialog\nimport androidx.core.text.HtmlCompat\nimport androidx.fragment.app.Fragment\nimport androidx.lifecycle.lifecycleScope\nimport androidx.recyclerview.widget.RecyclerView\nimport com.google.android.gms.R\nimport com.google.android.gms.common.Scopes\nimport com.google.android.gms.common.api.Scope\nimport com.google.android.material.bottomsheet.BottomSheetDialog\nimport com.squareup.wire.GrpcClient\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\nimport okhttp3.OkHttpClient\nimport org.microg.gms.games.ApplicationsFirstPartyClient\nimport org.microg.gms.games.DeletePlayerRequest\nimport org.microg.gms.games.GamesConfigurationService\nimport org.microg.gms.games.HeaderInterceptor\nimport org.microg.gms.games.ListApplicationsWithUserDataRequest\nimport org.microg.gms.games.PlayersFirstPartyClient\nimport org.microg.gms.games.requestGameToken\nimport java.lang.RuntimeException\nimport android.os.Build.VERSION.SDK_INT\nimport androidx.recyclerview.widget.LinearLayoutManager\nimport org.microg.gms.games.DeleteApplicationDataRequest\nimport org.microg.gms.games.GAMES_PACKAGE_NAME\nimport org.microg.gms.games.fetchAllSelfPlayers\nimport java.util.Locale\n\nclass GameDeletePlayAccountFragment : Fragment() {\n\n    companion object {\n        const val TAG = \"GameDeletePlayAccount\"\n\n        fun newInstance(): GameDeletePlayAccountFragment {\n            val fragment = GameDeletePlayAccountFragment()\n            return fragment\n        }\n    }\n\n    private var lastChoosePlayer: Pair<Account, String>? = null\n    private var isDeleteRefreshState = false\n    private lateinit var currentAccountText: TextView\n    private lateinit var currentChooseBtn: Button\n    private lateinit var currentDeleteBtn: Button\n    private lateinit var loadingBar: ProgressBar\n    private lateinit var individualGameRecyclerView: RecyclerView\n\n    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {\n        return layoutInflater.inflate(R.layout.fragment_game_delete_data, container, false);\n    }\n\n    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {\n        super.onViewCreated(view, savedInstanceState)\n        currentAccountText = view.findViewById<TextView>(R.id.delete_current_account) ?: currentAccountText\n        currentChooseBtn = view.findViewById<Button>(R.id.btn_choose) ?: currentChooseBtn\n        currentDeleteBtn = view.findViewById<Button>(R.id.btn_delete) ?: currentDeleteBtn\n        loadingBar = view.findViewById<ProgressBar>(R.id.loading_progress) ?: loadingBar\n        individualGameRecyclerView = view.findViewById<RecyclerView>(R.id.recycler_view_games) ?: individualGameRecyclerView\n\n        lifecycleScope.launchWhenStarted {\n            initPlayers()\n            deletePlayer()\n            loadIndividualGames()\n        }\n    }\n\n    private fun loadIndividualGames() {\n        lifecycleScope.launchWhenStarted {\n            val response = withContext(Dispatchers.IO) {\n                val scopes = arrayListOf(Scope(Scopes.GAMES_LITE), Scope(Scopes.GAMES_FIRSTPARTY))\n                val authToken = requestGameToken(requireContext(), lastChoosePlayer!!.first, scopes) ?: throw RuntimeException(\"authToken is null\")\n                getApplicationsFirstPartyClient(requireContext(), authToken).ListApplicationsWithUserDataFirstParty().execute(ListApplicationsWithUserDataRequest.build {\n                    locale = Locale.getDefault().language\n                    androidSdk = \"android:${SDK_INT}\"\n                })\n            }\n            val dataList = response.firstPartyApplication.map {\n                GameDataDeleteItem(\n                    iconUrl = it.application?.gameIcon?.url,\n                    gameName = it.application?.gameName,\n                    gameId = it.application?.gameId,\n                    tips = \"${it.unlockAchievementsNum} / ${it.application?.achievementsNum} ${requireContext().getString(R.string.games_achievement_list_title)}\"\n                )\n            }\n            individualGameRecyclerView.layoutManager = LinearLayoutManager(requireContext())\n            individualGameRecyclerView.adapter = GameDataDeleteAdapter(dataList) { item ->\n                showDeleteConfirmationDialog(item)\n            }\n            individualGameRecyclerView.visibility = View.VISIBLE\n            loadingBar.visibility = View.GONE\n        }\n    }\n\n    private fun deleteGameDataByGameId(itemGameId: String?) {\n        try {\n            if (lastChoosePlayer == null) throw RuntimeException(\"player is null\")\n            val applicationId = itemGameId ?: throw RuntimeException(\"gameId is null\")\n            lifecycleScope.launchWhenStarted {\n                individualGameRecyclerView.visibility = View.INVISIBLE\n                loadingBar.visibility = View.VISIBLE\n                withContext(Dispatchers.IO) {\n                    val scopes = arrayListOf(Scope(Scopes.GAMES_LITE), Scope(Scopes.GAMES_FIRSTPARTY))\n                    val authToken = requestGameToken(requireContext(), lastChoosePlayer!!.first, scopes) ?: throw RuntimeException(\"authToken is null\")\n                    getPlayersFirstPartyClient(requireContext(), authToken).DeleteApplicationDataFirstParty().execute(DeleteApplicationDataRequest.build {\n                        gameId = applicationId\n                        status = 0\n                    })\n                }\n                loadIndividualGames()\n            }\n        } catch (e: Exception) {\n            Log.d(TAG, \"deleteGameDataByGameId: \", e)\n            Toast.makeText(requireContext(), requireContext().getString(R.string.games_delete_profile_fail), Toast.LENGTH_SHORT).show()\n        }\n    }\n\n    private fun deletePlayer() {\n        currentDeleteBtn.setOnClickListener {\n            showDeleteConfirmationDialog()\n        }\n    }\n\n    private fun showDeleteConfirmationDialog(item: GameDataDeleteItem? = null) {\n        val dialogView = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_game_account_delete_confirmation, null)\n\n        val dialog = BottomSheetDialog(requireContext())\n        dialog.setContentView(dialogView)\n        dialog.show()\n\n        if (item != null) {\n            dialogView.findViewById<TextView>(R.id.textDeleteProfileTitle).text = String.format(\n                requireContext().getString(R.string.games_delete_game_data_confirm_dialog_title), item.gameName\n            )\n            dialogView.findViewById<TextView>(R.id.textDeleteProfileExplanation).text = String.format(\n                requireContext().getString(R.string.games_delete_game_data_confirm_dialog_message), item.gameName\n            )\n        } else if (lastChoosePlayer != null) {\n            dialogView.findViewById<TextView>(R.id.textDeleteProfileExplanation).text = HtmlCompat.fromHtml(\n                String.format(\n                    requireContext().getString(R.string.games_delete_profile_explanation_with_gamer_name), lastChoosePlayer?.second, lastChoosePlayer?.first?.name\n                ), HtmlCompat.FROM_HTML_MODE_LEGACY\n            )\n        }\n\n        dialogView.findViewById<Button>(R.id.btnConfirmDelete).setOnClickListener {\n            if (item != null) {\n                deleteGameDataByGameId(item.gameId)\n            } else if (lastChoosePlayer != null) {\n                deleteAccountData(lastChoosePlayer?.first!!)\n            }\n            dialog.dismiss()\n        }\n\n        dialogView.findViewById<Button>(R.id.btnCancel).setOnClickListener {\n            dialog.dismiss()\n        }\n    }\n\n    private fun deleteAccountData(account: Account) {\n        lifecycleScope.launchWhenStarted {\n            try {\n                withContext(Dispatchers.IO) {\n                    val scopes = arrayListOf(Scope(Scopes.GAMES_LITE), Scope(Scopes.GAMES_FIRSTPARTY))\n                    val authToken = requestGameToken(requireContext(), account, scopes) ?: throw RuntimeException(\"authToken is null\")\n                    getPlayersFirstPartyClient(requireContext(), authToken).DeletePlayerFirstParty().execute(DeletePlayerRequest())\n                }\n                val defaultAccount = GamesConfigurationService.getDefaultAccount(requireContext(), GAMES_PACKAGE_NAME)\n                if (account.name == defaultAccount?.name) {\n                    GamesConfigurationService.setDefaultAccount(requireContext(), GAMES_PACKAGE_NAME, null)\n                }\n                GamesConfigurationService.setPlayer(requireContext(), account, null)\n                isDeleteRefreshState = true\n                initPlayers()\n                loadIndividualGames()\n            } catch (e: Exception) {\n                Log.d(TAG, \"deleteAccountData: \", e)\n                Toast.makeText(requireContext(), requireContext().getString(R.string.games_delete_profile_fail), Toast.LENGTH_SHORT).show()\n            }\n        }\n    }\n\n    private suspend fun initPlayers() {\n        val players = fetchAllSelfPlayers(requireContext())\n        if (players.isEmpty()) {\n            requireActivity().finish()\n            return\n        } else if (players.size > 1) {\n            handleMultiPlayer(players)\n        } else {\n            currentChooseBtn.visibility = View.GONE\n        }\n        val currentPlayer = players.find { it.first.name == lastChoosePlayer?.first?.name } ?: players.first()\n        currentAccountText.visibility = View.VISIBLE\n        currentAccountText.text = String.format(\n            requireContext().getString(R.string.games_account_display_content), \"${currentPlayer.first.name} (${currentPlayer.second})\"\n        )\n        lastChoosePlayer = currentPlayer\n        isDeleteRefreshState = false\n    }\n\n    private fun handleMultiPlayer(players: List<Pair<Account, String>>) {\n        currentChooseBtn.visibility = View.VISIBLE\n        currentChooseBtn.setOnClickListener {\n            AlertDialog.Builder(requireContext()).setTitle(requireContext().getString(R.string.credentials_assisted_choose_account_label)).setItems(players.map {\n                \"${it.first.name} (${it.second})\"\n            }.toTypedArray()) { _, which ->\n                loadingBar.visibility = View.VISIBLE\n                individualGameRecyclerView.visibility = View.INVISIBLE\n                lastChoosePlayer = players[which]\n                val (account, playName) = players[which]\n                currentAccountText.text = String.format(requireContext().getString(R.string.games_account_display_content), \"${account.name} (${playName})\")\n                loadIndividualGames()\n            }.setNegativeButton(requireContext().getString(R.string.games_delete_snapshot_dialog_cancel), null).show()\n        }\n    }\n\n    private fun getPlayersFirstPartyClient(context: Context, oauthToken: String): PlayersFirstPartyClient {\n        val client = OkHttpClient().newBuilder().addInterceptor(\n            HeaderInterceptor(context, oauthToken)\n        ).build()\n        val grpcClient = GrpcClient.Builder().client(client).baseUrl(\"https://gameswhitelisted.googleapis.com\").build()\n        return grpcClient.create(PlayersFirstPartyClient::class)\n    }\n\n    private fun getApplicationsFirstPartyClient(context: Context, oauthToken: String): ApplicationsFirstPartyClient {\n        val client = OkHttpClient().newBuilder().addInterceptor(\n            HeaderInterceptor(context, oauthToken)\n        ).build()\n        val grpcClient = GrpcClient.Builder().client(client).baseUrl(\"https://gameswhitelisted.googleapis.com\").build()\n        return grpcClient.create(ApplicationsFirstPartyClient::class)\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/games/ui/GamePlayDataActivity.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.games.ui\n\nimport android.annotation.SuppressLint\nimport android.content.Context\nimport android.content.Intent\nimport android.os.Bundle\nimport android.util.Log\nimport android.view.View\nimport android.view.ViewGroup.LayoutParams.MATCH_PARENT\nimport android.view.ViewGroup.LayoutParams.WRAP_CONTENT\nimport android.widget.FrameLayout\nimport android.widget.RelativeLayout\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.appcompat.widget.Toolbar\nimport androidx.core.content.ContextCompat\nimport com.google.android.gms.R\n\nclass GamePlayDataActivity : AppCompatActivity() {\n\n    private val operationType: String?\n        get() = runCatching {\n            intent?.extras?.getString(OPERATION_TYPE)\n        }.getOrNull()\n\n    @SuppressLint(\"CommitTransaction\")\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        Log.d(TAG, \"onCreate: operationType: $operationType\")\n        if (operationType == null) {\n            finish()\n            return\n        }\n\n        var toolbarTitle = \"\"\n        val fragment = if (TYPE_DELETED == operationType) {\n            Log.d(TAG, \"add GameDeletePlayAccountFragment\")\n            toolbarTitle = getString(R.string.pref_delete_game_account_data)\n            GameDeletePlayAccountFragment.newInstance()\n        } else {\n            Log.d(TAG, \"add GameChangeAccountFragment\")\n            toolbarTitle = getString(R.string.pref_change_default_game_player)\n            GameChangeAccountFragment.newInstance()\n        }\n\n        val layout = RelativeLayout(this)\n        val toolbar = Toolbar(this).apply {\n            id = View.generateViewId()\n            layoutParams = RelativeLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT).apply {\n                addRule(RelativeLayout.ALIGN_PARENT_TOP)\n            }\n            navigationIcon = ContextCompat.getDrawable(context, R.drawable.ic_close_btn)\n            setNavigationOnClickListener { finish() }\n            title = toolbarTitle\n        }\n        val container = FrameLayout(this).apply {\n            id = View.generateViewId()\n            layoutParams = RelativeLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT).apply {\n                addRule(RelativeLayout.BELOW, toolbar.id)\n            }\n        }\n        layout.addView(toolbar)\n        layout.addView(container)\n        setContentView(layout)\n\n        supportFragmentManager.beginTransaction().add(container.id, fragment, GameChangeAccountFragment.TAG).commitAllowingStateLoss()\n    }\n\n    companion object {\n        private const val TAG = \"GamePlayDataActivity\"\n        private const val OPERATION_TYPE = \"operation_type\"\n        const val TYPE_CHANGED = \"type_changed\"\n        const val TYPE_DELETED = \"type_deleted\"\n\n        fun createIntent(context: Context, type: String, data: Bundle? = null) {\n            Intent(context, GamePlayDataActivity::class.java).apply {\n                putExtra(OPERATION_TYPE, type)\n                data?.let { putExtras(it) }\n            }.let {\n                context.startActivity(it)\n            }\n        }\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/games/ui/GamesUiFragment.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.games.ui\n\nimport android.accounts.Account\nimport android.accounts.AccountManager\nimport android.app.Activity.RESULT_OK\nimport android.app.Dialog\nimport android.content.Context\nimport android.content.DialogInterface\nimport android.content.Intent\nimport android.os.Bundle\nimport android.util.Log\nimport android.view.KeyEvent\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.view.ViewStub\nimport android.widget.FrameLayout\nimport android.widget.ImageView\nimport android.widget.RelativeLayout\nimport android.widget.TextView\nimport android.widget.Toast\nimport androidx.appcompat.app.AlertDialog\nimport androidx.lifecycle.lifecycleScope\nimport androidx.recyclerview.widget.LinearLayoutManager\nimport androidx.recyclerview.widget.RecyclerView\nimport com.google.android.gms.R\nimport com.google.android.gms.common.Scopes\nimport com.google.android.gms.games.snapshot.SnapshotMetadataEntity\nimport com.google.android.material.bottomsheet.BottomSheetBehavior\nimport com.google.android.material.bottomsheet.BottomSheetDialog\nimport com.google.android.material.bottomsheet.BottomSheetDialogFragment\nimport com.google.android.material.floatingactionbutton.FloatingActionButton\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.launch\nimport kotlinx.coroutines.withContext\nimport org.microg.gms.auth.AuthConstants\nimport org.microg.gms.auth.AuthManager\nimport org.microg.gms.auth.signin.SignInConfigurationService\nimport org.microg.gms.common.Constants\nimport org.microg.gms.games.ACTION_VIEW_ACHIEVEMENTS\nimport org.microg.gms.games.ACTION_VIEW_LEADERBOARDS\nimport org.microg.gms.games.ACTION_VIEW_LEADERBOARDS_SCORES\nimport org.microg.gms.games.ACTION_VIEW_SNAPSHOTS\nimport org.microg.gms.games.EXTRA_ACCOUNT_KEY\nimport org.microg.gms.games.EXTRA_ALLOW_CREATE_SNAPSHOT\nimport org.microg.gms.games.EXTRA_GAME_PACKAGE_NAME\nimport org.microg.gms.games.EXTRA_LEADERBOARD_ID\nimport org.microg.gms.games.EXTRA_MAX_SNAPSHOTS\nimport org.microg.gms.games.EXTRA_SNAPSHOT_METADATA\nimport org.microg.gms.games.EXTRA_SNAPSHOT_NEW\nimport org.microg.gms.games.EXTRA_TITLE\nimport org.microg.gms.games.GamesConfigurationService\nimport org.microg.gms.games.SERVICE_GAMES_LITE\nimport org.microg.gms.games.achievements.AchievementDefinition\nimport org.microg.gms.games.achievements.AchievementState\nimport org.microg.gms.games.achievements.AchievementsAdapter\nimport org.microg.gms.games.achievements.AchievementsApiClient\nimport org.microg.gms.games.achievements.PlayerAchievement\nimport org.microg.gms.games.achievements.getAchievementState\nimport org.microg.gms.games.leaderboards.LeaderboardDefinition\nimport org.microg.gms.games.leaderboards.LeaderboardEntry\nimport org.microg.gms.games.leaderboards.LeaderboardScoresAdapter\nimport org.microg.gms.games.leaderboards.LeaderboardsAdapter\nimport org.microg.gms.games.leaderboards.LeaderboardsApiClient\nimport org.microg.gms.games.snapshot.Snapshot\nimport org.microg.gms.games.snapshot.SnapshotsAdapter\nimport org.microg.gms.games.snapshot.SnapshotsDataClient\nimport org.microg.gms.people.PeopleManager\nimport org.microg.gms.profile.ProfileManager\n\nclass GamesUiFragment : BottomSheetDialogFragment() {\n\n    companion object {\n        const val TAG = \"GamesUiFragment\"\n        private const val KEY_PACKAGE_NAME = \"clientPackageName\"\n        private const val KEY_ACCOUNT_KEY = \"accountKey\"\n        private const val KEY_CALLER_INTENT = \"callerIntent\"\n\n        fun newInstance(clientPackageName: String, accountKey: String, intent: Intent): GamesUiFragment {\n            val fragment = GamesUiFragment()\n            val args = Bundle().apply {\n                putString(KEY_PACKAGE_NAME, clientPackageName)\n                putString(KEY_ACCOUNT_KEY, accountKey)\n                putParcelable(KEY_CALLER_INTENT, intent)\n            }\n            fragment.arguments = args\n            return fragment\n        }\n    }\n\n    private lateinit var clientPackageName: String\n    private lateinit var callerIntent: Intent\n    private var account: Account? = null\n\n    private var playerLogo: ImageView? = null\n    private var uiTitle: TextView? = null\n    private var actionBtn: FloatingActionButton? = null\n    private var refreshBtn: ImageView? = null\n    private var cancelBtn: ImageView? = null\n    private var recyclerView: RecyclerView? = null\n    private var loadingView: FrameLayout? = null\n    private var errorView: TextView? = null\n    private var contentVb: ViewStub? = null\n\n    private var currentAccount: Account? = null\n    private var snapshotsAdapter: SnapshotsAdapter? = null\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        Log.d(TAG, \"onCreate start\")\n        kotlin.runCatching {\n            clientPackageName = arguments?.getString(KEY_PACKAGE_NAME)!!\n            callerIntent = arguments?.getParcelable(KEY_CALLER_INTENT)!!\n            account = AccountManager.get(context).accounts.filter {\n                it.type == AuthConstants.DEFAULT_ACCOUNT_TYPE && Integer.toHexString(it.name.hashCode()) == arguments?.getString(KEY_ACCOUNT_KEY)\n            }.getOrNull(0)\n        }.onFailure {\n            activity?.finish()\n        }\n    }\n\n    override fun onActivityCreated(savedInstanceState: Bundle?) {\n        super.onActivityCreated(savedInstanceState)\n        Log.d(TAG, \"onActivityCreated start \")\n        kotlin.runCatching {\n            loadData(requireContext())\n        }.onFailure {\n            activity?.finish()\n        }\n    }\n\n    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {\n        val dialog = super.onCreateDialog(savedInstanceState) as BottomSheetDialog\n        dialog.setOnShowListener {\n            dialog.behavior.state = BottomSheetBehavior.STATE_EXPANDED\n            dialog.behavior.skipCollapsed = true\n            dialog.setCanceledOnTouchOutside(false)\n        }\n        dialog.setOnKeyListener { _, keyCode, event ->\n            if (keyCode == KeyEvent.KEYCODE_BACK && event.action == KeyEvent.ACTION_UP) {\n                dialog.dismiss()\n                return@setOnKeyListener true\n            }\n            return@setOnKeyListener false\n        }\n        return dialog\n    }\n\n    override fun onCreateView(\n        inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?\n    ): View? {\n        Log.d(TAG, \"onCreateView\")\n        return layoutInflater.inflate(R.layout.fragment_games_ui_layout, container, false)\n    }\n\n    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {\n        super.onViewCreated(view, savedInstanceState)\n        Log.d(TAG, \"onViewCreated\")\n        uiTitle = view.findViewById(R.id.games_ui_title)\n        actionBtn = view.findViewById(R.id.games_ui_action_button)\n        refreshBtn = view.findViewById(R.id.games_ui_refresh)\n        cancelBtn = view.findViewById(R.id.games_ui_cancel)\n        cancelBtn?.setOnClickListener { dismiss() }\n        recyclerView = view.findViewById(R.id.games_ui_recyclerview)\n        loadingView = view.findViewById(R.id.games_ui_loading)\n        playerLogo = view.findViewById(R.id.games_ui_player_logo)\n        errorView = view.findViewById(R.id.games_ui_error_tips)\n        contentVb = view.findViewById(R.id.games_ui_achievements_vb)\n    }\n\n    override fun onDismiss(dialog: DialogInterface) {\n        activity?.finish()\n        super.onDismiss(dialog)\n    }\n\n    private fun showErrorMsg(error: String) {\n        loadingView?.visibility = View.GONE\n        recyclerView?.visibility = View.GONE\n        errorView?.visibility = View.VISIBLE\n        errorView?.text = error\n    }\n\n    private fun loadData(context: Context) {\n        ProfileManager.ensureInitialized(context)\n        lifecycleScope.launch {\n            currentAccount = account ?: GamesConfigurationService.getDefaultAccount(context, clientPackageName) ?: SignInConfigurationService.getDefaultAccount(\n                context, clientPackageName\n            )\n\n            if (currentAccount == null) {\n                showErrorMsg(context.getString(R.string.games_api_access_denied))\n                return@launch\n            }\n\n            withContext(Dispatchers.IO) {\n                PeopleManager.getOwnerAvatarBitmap(\n                    context, currentAccount!!.name, false\n                )\n            }?.also {\n                playerLogo?.setImageBitmap(it)\n            }\n\n            val authResponse = withContext(Dispatchers.IO) {\n                AuthManager(context, currentAccount!!.name, clientPackageName, \"$SERVICE_GAMES_LITE ${Scopes.DRIVE_APPFOLDER}\").apply { isPermitted = true }\n                    .requestAuth(true)\n            }\n            var oauthToken: String? = null\n            if (authResponse.auth?.let { oauthToken = it } == null) {\n                showErrorMsg(context.getString(R.string.games_achievements_empty_text))\n                return@launch\n            }\n\n            runCatching {\n                when (callerIntent.action) {\n                    ACTION_VIEW_ACHIEVEMENTS -> loadLocalAchievements(context, oauthToken!!)\n                    ACTION_VIEW_LEADERBOARDS -> loadLocalLeaderboards(context, oauthToken!!)\n                    ACTION_VIEW_SNAPSHOTS -> loadSnapshots(context, oauthToken!!)\n                    ACTION_VIEW_LEADERBOARDS_SCORES -> loadLocalLeaderboardScores(context, oauthToken!!)\n                    else -> showErrorMsg(\"Not yet implemented\")\n                }\n            }.onFailure {\n                Log.d(TAG, \"show error: \", it)\n                activity?.finish()\n            }\n        }\n    }\n\n    private suspend fun loadSnapshots(context: Context, oauthToken: String) {\n        uiTitle?.text = callerIntent.getStringExtra(EXTRA_TITLE)\n        refreshBtn?.visibility = View.VISIBLE\n        refreshBtn?.setOnClickListener {\n            errorView?.visibility = View.GONE\n            loadingView?.visibility = View.VISIBLE\n            lifecycleScope.launchWhenCreated {\n                val snapshots = withContext(Dispatchers.IO) {\n                    SnapshotsDataClient.get(context).loadSnapshotData(oauthToken)\n                }\n                if (snapshots.isEmpty()) {\n                    showErrorMsg(context.getString(R.string.games_snapshot_empty_text))\n                } else {\n                    snapshotsAdapter?.update(snapshots)\n                }\n                addSnapshotBtnDetail(snapshots)\n            }\n        }\n        val snapshots = withContext(Dispatchers.IO) {\n            SnapshotsDataClient.get(context).loadSnapshotData(oauthToken)\n        }\n        addSnapshotBtnDetail(snapshots)\n        if (snapshots.isEmpty()) {\n            showErrorMsg(context.getString(R.string.games_snapshot_empty_text))\n            return\n        }\n        recyclerView?.apply {\n            layoutManager = LinearLayoutManager(context)\n            addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->\n                errorView?.visibility = View.GONE\n                loadingView?.visibility = View.GONE\n            }\n        }?.adapter = snapshotsAdapter ?: SnapshotsAdapter(context, callerIntent, snapshots) { snapshot, i ->\n            lifecycleScope.launch {\n                if (i == 0) {\n                    val intent = Intent()\n                    val snapshotMetadataEntity = SnapshotMetadataEntity(\n                        null,\n                        null,\n                        snapshot.id,\n                        null,\n                        snapshot.coverImage?.url,\n                        snapshot.title,\n                        snapshot.description,\n                        snapshot.lastModifiedMillis?.toLong() ?: 0,\n                        0,\n                        1f,\n                        snapshot.title,\n                        false,\n                        0,\n                        \"\"\n                    )\n                    intent.putExtra(EXTRA_SNAPSHOT_METADATA, snapshotMetadataEntity)\n                    activity?.setResult(RESULT_OK, intent)\n                    activity?.finish()\n                } else {\n                    AlertDialog.Builder(context).apply {\n                        setTitle(getString(R.string.games_delete_snapshot_dialog_title))\n                        setMessage(getString(R.string.games_delete_snapshot_dialog_message))\n                    }.setNegativeButton(getString(R.string.games_delete_snapshot_dialog_cancel)) { dialog, _ ->\n                        dialog.dismiss()\n                    }.setPositiveButton(getString(R.string.games_delete_snapshot_dialog_ok)) { dialog, _ ->\n                        dialog.dismiss()\n                        lifecycleScope.launchWhenCreated {\n                            val snapshotData = SnapshotsDataClient.get(context).deleteSnapshotData(oauthToken, snapshot)\n                            if (snapshotData != null) {\n                                refreshBtn?.performClick()\n                            } else {\n                                Toast.makeText(context, getString(R.string.games_delete_snapshot_error), Toast.LENGTH_SHORT).show()\n                            }\n                        }\n                    }.show()\n                }\n            }\n        }.also {\n            snapshotsAdapter = it\n        }\n    }\n\n    private fun addSnapshotBtnDetail(snapshots: List<Snapshot>) {\n        val allowCreate = callerIntent.getBooleanExtra(EXTRA_ALLOW_CREATE_SNAPSHOT, true)\n        val maxSnapshot = callerIntent.getIntExtra(EXTRA_MAX_SNAPSHOTS, -1)\n        if (allowCreate && (maxSnapshot != -1 && snapshots.size < maxSnapshot)) {\n            actionBtn?.visibility = View.VISIBLE\n            actionBtn?.setOnClickListener {\n                val resultIntent = Intent()\n                resultIntent.putExtra(EXTRA_SNAPSHOT_NEW, true)\n                activity?.setResult(RESULT_OK, resultIntent)\n                activity?.finish()\n            }\n        } else {\n            actionBtn?.visibility = View.INVISIBLE\n        }\n    }\n\n    private suspend fun loadLocalLeaderboards(context: Context, oauthToken: String) {\n        uiTitle?.text = context.getString(R.string.games_leaderboard_list_title)\n        val loadLeaderboards = withContext(Dispatchers.IO) {\n            ArrayList<LeaderboardDefinition>().apply {\n                var playerPageToken: String? = null\n                do {\n                    val response = LeaderboardsApiClient.requestAllLeaderboards(context, oauthToken, playerPageToken)\n                    addAll(response.items)\n                    playerPageToken = response.nextPageToken\n                } while (!playerPageToken.isNullOrEmpty())\n            }\n        }\n        if (loadLeaderboards.isEmpty()) {\n            showErrorMsg(context.getString(R.string.games_leaderboard_empty_text))\n            return\n        }\n        recyclerView?.apply {\n            layoutManager = LinearLayoutManager(context)\n            addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->\n                loadingView?.visibility = View.GONE\n            }\n        }?.adapter = LeaderboardsAdapter(context, loadLeaderboards) { leaderboard ->\n            val intent = Intent(ACTION_VIEW_LEADERBOARDS_SCORES)\n            intent.setPackage(Constants.GMS_PACKAGE_NAME)\n            intent.putExtra(EXTRA_GAME_PACKAGE_NAME, clientPackageName)\n            intent.putExtra(EXTRA_ACCOUNT_KEY, Integer.toHexString(currentAccount?.name.hashCode()))\n            intent.putExtra(EXTRA_LEADERBOARD_ID, leaderboard.id)\n            activity?.startActivity(intent)\n        }\n    }\n\n    private suspend fun loadLocalLeaderboardScores(context: Context, oauthToken: String) {\n        val leaderboardId = callerIntent.getStringExtra(EXTRA_LEADERBOARD_ID)\n        val leaderboardScores = withContext(Dispatchers.IO) {\n            ArrayList<LeaderboardEntry>().apply {\n                val response = LeaderboardsApiClient.requestLeaderboardScoresById(\n                    context, oauthToken, leaderboardId!!, null\n                )\n                addAll(response.items)\n            }\n        }\n        if (leaderboardScores.isEmpty()) {\n            showErrorMsg(context.getString(R.string.games_leaderboard_empty_text))\n            return\n        }\n        val leaderboardDefinition = withContext(Dispatchers.IO) {\n            LeaderboardsApiClient.getLeaderboardById(context, oauthToken, leaderboardId!!)\n        }\n        val leaderboardEntries = arrayListOf<LeaderboardEntry>()\n        leaderboardEntries.add(LeaderboardEntry(leaderboardDefinition.name, leaderboardDefinition.iconUrl))\n        leaderboardEntries.addAll(leaderboardScores)\n        recyclerView?.apply {\n            layoutManager = LinearLayoutManager(context)\n            addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->\n                loadingView?.visibility = View.GONE\n            }\n            addOnScrollListener(object : RecyclerView.OnScrollListener() {\n                override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {\n                    super.onScrolled(recyclerView, dx, dy)\n                    val layoutManager = recyclerView.layoutManager\n                    if (layoutManager is LinearLayoutManager) {\n                        val firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition()\n                        uiTitle?.text = if (firstVisibleItemPosition != 0) leaderboardDefinition.name else \"\"\n                    }\n                }\n            })\n        }?.adapter = LeaderboardScoresAdapter(context, leaderboardEntries)\n    }\n\n    private suspend fun loadLocalAchievements(context: Context, oauthToken: String) {\n        uiTitle?.text = context.getString(R.string.games_achievement_list_title)\n        val allAchievements = withContext(Dispatchers.IO) {\n            ArrayList<AchievementDefinition>().apply {\n                val playerAchievements = ArrayList<PlayerAchievement>()\n                var playerPageToken: String? = null\n                do {\n                    val response = AchievementsApiClient.requestPlayerAllAchievements(context, oauthToken, playerPageToken)\n                    playerAchievements.addAll(response.items)\n                    playerPageToken = response.nextPageToken\n                } while (!playerPageToken.isNullOrEmpty())\n\n                var pageToken: String? = null\n                do {\n                    val response = AchievementsApiClient.requestGameAllAchievements(context, oauthToken, pageToken)\n                    response.items.forEach { item ->\n                        if (playerAchievements.any { it.id == item.id }) {\n                            item.initialState = getAchievementState(playerAchievements.find { it.id == item.id }?.achievementState)\n                        }\n                        add(item)\n                    }\n                    pageToken = response.nextPageToken\n                } while (!pageToken.isNullOrEmpty())\n            }\n        }\n        if (allAchievements.isEmpty()) {\n            showErrorMsg(context.getString(R.string.games_achievements_empty_text))\n            return\n        }\n        val targetList = ArrayList<AchievementDefinition>()\n        val unlockList = ArrayList<AchievementDefinition>()\n        val revealedList = ArrayList<AchievementDefinition>()\n        for (definition in allAchievements) {\n            when (definition.initialState) {\n                AchievementState.STATE_REVEALED -> {\n                    revealedList.add(definition)\n                }\n\n                AchievementState.STATE_UNLOCKED -> {\n                    unlockList.add(definition)\n                }\n            }\n        }\n        if (unlockList.isNotEmpty()) {\n            targetList.add(AchievementDefinition(context.getString(R.string.games_achievement_unlocked_content_description), -1))\n            targetList.addAll(unlockList)\n        }\n        if (revealedList.isNotEmpty()) {\n            targetList.add(AchievementDefinition(context.getString(R.string.games_achievement_locked_content_description), -1))\n            targetList.addAll(revealedList)\n        }\n        val inflatedView = contentVb?.inflate()\n        inflatedView?.findViewById<TextView>(R.id.achievements_counter_text)?.text =\n            String.format(\"${unlockList.size} / ${unlockList.size + revealedList.size}\")\n        recyclerView?.apply {\n            layoutManager = LinearLayoutManager(context)\n            inflatedView?.id?.let {\n                val layoutParams = layoutParams as RelativeLayout.LayoutParams\n                layoutParams.addRule(RelativeLayout.BELOW, it)\n                setLayoutParams(layoutParams)\n            }\n            addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->\n                loadingView?.visibility = View.GONE\n            }\n        }?.adapter = AchievementsAdapter(context, targetList)\n    }\n\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/games/ui/InGameUiActivity.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.games.ui\n\nimport android.annotation.SuppressLint\nimport android.os.Bundle\nimport android.util.Log\nimport androidx.appcompat.app.AppCompatActivity\nimport com.google.android.gms.R\nimport org.microg.gms.games.EXTRA_ACCOUNT_KEY\nimport org.microg.gms.games.EXTRA_GAME_PACKAGE_NAME\n\nprivate const val TAG = \"InGameUiActivity\"\n\nclass InGameUiActivity : AppCompatActivity() {\n\n    private val clientPackageName: String?\n        get() = runCatching {\n            intent?.extras?.getString(EXTRA_GAME_PACKAGE_NAME)\n        }.getOrNull()\n    private val accountKey: String?\n        get() = runCatching {\n            intent.getStringExtra(EXTRA_ACCOUNT_KEY)\n        }.getOrNull()\n\n    @SuppressLint(\"CommitTransaction\")\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        setTheme(R.style.ThemeTranslucentCommon)\n        Log.d(TAG, \"InGameUiActivity onCreate: clientPackageName:$clientPackageName\")\n        if (clientPackageName == null || accountKey == null) {\n            Log.d(TAG, \"InGameUiActivity finishResult: params invalid\")\n            finish()\n            return\n        }\n\n        val fragment = supportFragmentManager.findFragmentByTag(GamesUiFragment.TAG)\n        if (fragment == null) {\n            Log.d(TAG, \"supportFragmentManager show\")\n            val gamesUiFragment = GamesUiFragment.newInstance(clientPackageName!!, accountKey!!, intent)\n            supportFragmentManager.beginTransaction()\n                .add(gamesUiFragment, GamesUiFragment.TAG)\n                .commitAllowingStateLoss()\n        }\n    }\n\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/games/utils/AccountPromptManager.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.games.utils\n\nimport android.content.Context\nimport android.graphics.PixelFormat\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.Handler\nimport android.os.Looper\nimport android.util.Log\nimport android.view.Gravity\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.WindowManager\nimport android.widget.ImageView\nimport android.widget.LinearLayout\nimport android.widget.TextView\nimport com.google.android.gms.R\nimport com.google.android.gms.common.images.ImageManager\nimport java.lang.ref.WeakReference\n\nclass AccountPromptManager private constructor(context: Context) {\n\n    private val appContextRef = WeakReference(context.applicationContext)\n    private val handler = Handler(Looper.getMainLooper())\n\n    private var windowManagerRef: WeakReference<WindowManager>? = null\n    private var promptViewRef: WeakReference<View>? = null\n    private val removeRunnable = Runnable { remove() }\n\n    companion object {\n        private const val TAG = \"AccountPromptManager\"\n\n        @Volatile\n        private var instance: AccountPromptManager? = null\n\n        fun getInstance(context: Context): AccountPromptManager {\n            return instance ?: synchronized(this) {\n                instance ?: AccountPromptManager(context).also { instance = it }\n            }\n        }\n    }\n\n    fun show(username: String, avatarUrl: String) {\n        Log.d(TAG, \"show: username=$username, avatarUrl=$avatarUrl\")\n        if (promptViewRef?.get() != null) return\n        val context = appContextRef.get() ?: return\n        val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager\n        windowManagerRef = WeakReference(windowManager)\n\n        val view = LayoutInflater.from(context).inflate(R.layout.item_view_game_account_prompt, null)\n        promptViewRef = WeakReference(view)\n\n        val promptRoot = view.findViewById<LinearLayout>(R.id.account_prompt_root)\n        val logo = view.findViewById<ImageView>(R.id.game_logo)\n        val avatar = view.findViewById<ImageView>(R.id.player_avatar)\n        val usernameView = view.findViewById<TextView>(R.id.player_name)\n        val infoContainer = view.findViewById<View>(R.id.account_info_container)\n\n        usernameView.text = String.format(context.getString(R.string.games_popup_signin_welcome), username)\n\n        ImageManager.create(context).loadImage(avatarUrl, avatar)\n\n        val layoutParams = WindowManager.LayoutParams(\n            WindowManager.LayoutParams.WRAP_CONTENT,\n            WindowManager.LayoutParams.WRAP_CONTENT,\n            if (SDK_INT >= 26) WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY\n            else WindowManager.LayoutParams.TYPE_PHONE,\n            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,\n            PixelFormat.TRANSLUCENT\n        ).apply {\n            gravity = Gravity.TOP or Gravity.CENTER_HORIZONTAL\n            y = 80\n        }\n\n        try {\n            windowManager.addView(view, layoutParams)\n        } catch (e: Exception) {\n            Log.w(TAG, \"windowManager addView failed \", e)\n        }\n\n        fun prepare() {\n            Log.d(TAG, \"prepare\")\n            promptRoot.visibility = View.VISIBLE\n            infoContainer.visibility = View.GONE\n        }\n\n        fun showPlayer() {\n            Log.d(TAG, \"showPlayer\")\n            logo.visibility = View.GONE\n            infoContainer.visibility = View.VISIBLE\n            infoContainer.alpha = 0f\n            infoContainer.animate().alpha(1f).setDuration(500).start()\n        }\n\n        fun hidePlayer() {\n            Log.d(TAG, \"hidePlayer\")\n            infoContainer.animate().setDuration(500).withEndAction {\n                infoContainer.visibility = View.GONE\n                logo.visibility = View.VISIBLE\n            }.start()\n        }\n\n        fun hidePromptRoot() {\n            Log.d(TAG, \"hidePromptRoot\")\n            promptRoot.animate().scaleX(0f).scaleY(0f).setDuration(300).withEndAction {\n                promptRoot.visibility = View.GONE\n                handler.post(removeRunnable)\n            }.start()\n        }\n\n        handler.postDelayed({ prepare() }, 1000)\n        handler.postDelayed({ showPlayer() }, 1500)\n        handler.postDelayed({ hidePlayer() }, 3500)\n        handler.postDelayed({ hidePromptRoot() }, 4500)\n    }\n\n    fun remove() {\n        Log.d(TAG, \"remove\")\n        handler.removeCallbacksAndMessages(null)\n\n        promptViewRef?.get()?.let { view ->\n            try {\n                windowManagerRef?.get()?.removeView(view)\n            } catch (_: Exception) {\n            }\n        }\n\n        promptViewRef?.clear()\n        windowManagerRef?.clear()\n        promptViewRef = null\n        windowManagerRef = null\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/gass/GassService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage org.microg.gms.gass\n\nimport android.os.Bundle\nimport android.util.Log\nimport com.google.android.gms.common.ConnectionResult\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport com.google.android.gms.gass.internal.GassRequestParcel\nimport com.google.android.gms.gass.internal.GassResponseParcel\nimport com.google.android.gms.gass.internal.IGassService\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\n\nprivate const val TAG = \"GassService\"\n\nclass GassService : BaseService(TAG, GmsService.GASS) {\n\n    override fun handleServiceRequest(callback: IGmsCallbacks?, request: GetServiceRequest?, service: GmsService?) {\n        callback?.onPostInitComplete(ConnectionResult.SUCCESS, GassServiceImpl().asBinder(), null)\n    }\n\n}\n\nclass GassServiceImpl : IGassService.Stub() {\n    override fun getGassBundle(bundle: Bundle?, code: Int): Bundle? {\n        Log.d(TAG, \"GassServiceImpl getGassBundle is Called\")\n        return null\n    }\n\n    override fun getGassResponse(gassRequestParcel: GassRequestParcel?): GassResponseParcel? {\n        Log.d(TAG, \"GassServiceImpl getGassResponse is Called\")\n        return null\n    }\n\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/gcm/GcmInGmsService.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.gcm\n\nimport android.Manifest\nimport android.accounts.Account\nimport android.accounts.AccountManager\nimport android.app.NotificationChannel\nimport android.app.NotificationManager\nimport android.app.PendingIntent\nimport android.content.Context\nimport android.content.Intent\nimport android.content.SharedPreferences\nimport android.content.pm.PackageManager\nimport android.os.Binder\nimport android.os.Bundle\nimport android.os.Handler\nimport android.os.Looper\nimport android.os.Message\nimport android.os.Messenger\nimport android.os.Process\nimport android.util.Base64\nimport android.util.DisplayMetrics\nimport android.util.Log\nimport androidx.core.app.ActivityCompat\nimport androidx.core.app.NotificationCompat\nimport androidx.core.app.NotificationManagerCompat\nimport androidx.core.app.PendingIntentCompat\nimport androidx.legacy.content.WakefulBroadcastReceiver\nimport androidx.lifecycle.LifecycleService\nimport androidx.lifecycle.lifecycleScope\nimport com.google.android.gms.BuildConfig\nimport com.google.android.gms.R\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.delay\nimport kotlinx.coroutines.withContext\nimport okio.ByteString\nimport org.microg.gms.accountsettings.ui.KEY_NOTIFICATION_ID\nimport org.microg.gms.accountsettings.ui.MainActivity\nimport org.microg.gms.auth.AuthConstants\nimport org.microg.gms.auth.AuthManager\nimport org.microg.gms.auth.AuthPrefs\nimport org.microg.gms.auth.AuthResponse\nimport org.microg.gms.auth.ItAuthData\nimport org.microg.gms.auth.ItMetadataData\nimport org.microg.gms.auth.OAuthAuthorization\nimport org.microg.gms.auth.OAuthTokenData\nimport org.microg.gms.auth.TokenField\nimport org.microg.gms.checkin.LastCheckinInfo\nimport org.microg.gms.common.Constants\nimport org.microg.gms.common.ForegroundServiceContext\nimport org.microg.gms.gcm.registeration.ChimeGmsRegistrationHelper\nimport org.microg.gms.profile.Build.VERSION.SDK_INT\nimport org.microg.gms.profile.ProfileManager\nimport java.util.Locale\nimport java.util.TimeZone\nimport java.util.concurrent.atomic.AtomicInteger\nimport javax.crypto.Mac\nimport javax.crypto.spec.SecretKeySpec\nimport kotlin.coroutines.resume\nimport kotlin.coroutines.resumeWithException\nimport kotlin.coroutines.suspendCoroutine\nimport kotlin.math.min\n\nprivate const val TAG = \"GcmInGmsService\"\n\nprivate const val KEY_GCM_ANDROID_ID = \"androidId\"\nprivate const val KEY_GCM_REG_ID = \"regId\"\nprivate const val KEY_GCM_REG_SENDER = \"sender\"\nprivate const val KEY_GCM_REG_TIME = \"reg_time\"\nprivate const val KEY_GCM_REG_ACCOUNT_LIST = \"accountList\"\n\nprivate const val GMS_GCM_REGISTER_SCOPE = \"GCM\"\nprivate const val GMS_GCM_REGISTER_SENDER = \"745476177629\"\nprivate const val GMS_GCM_REGISTER_SUBTYPE = \"745476177629\"\nprivate const val GMS_GCM_REGISTER_SUBSCRIPTION = \"745476177629\"\nprivate const val GCM_GROUP_SENDER = \"google.com\"\nprivate const val GCM_GMS_REG_REFRESH_S = 604800L\n\nprivate const val DEFAULT_FLAGS = Base64.URL_SAFE or Base64.NO_WRAP or Base64.NO_PADDING\nprivate const val AUTHS_TOKEN_PREFIX = \"ya29.m.\"\nprivate const val GMS_GCM_OAUTH_SERVICE = \"oauth2:https://www.googleapis.com/auth/gcm\"\n\nprivate const val CHANNEL_ID = \"gcm_notification\"\nprivate const val CHANNEL_NAME = \"gnots\"\nprivate const val GMS_GCM_NOTIFICATIONS = \"notifications\"\nprivate const val NOTIFICATION_STATUS_READY = 2\nprivate const val NOTIFICATION_STATUS_COMPLETE = 5\nprivate const val NOTIFICATION_REPEAT_NUM = 3\nprivate const val NOTIFICATION_DELAY_TIME = 500L\n\nclass GcmInGmsService : LifecycleService() {\n    companion object {\n        private val accountNotificationMap = HashMap<String, MutableList<Pair<Int, NotificationData>>>()\n        private val notificationIdGenerator = AtomicInteger(0)\n    }\n    private var sp: SharedPreferences? = null\n    private var accountManager: AccountManager? = null\n    private val chimeGmsRegistrationHelper by lazy { ChimeGmsRegistrationHelper(this) }\n\n    override fun onCreate() {\n        super.onCreate()\n        ProfileManager.ensureInitialized(this)\n        sp = getSharedPreferences(\"com.google.android.gcm\", MODE_PRIVATE) ?: throw RuntimeException(\"sp get error\")\n        accountManager = getSystemService(ACCOUNT_SERVICE) as AccountManager? ?: throw RuntimeException(\"accountManager is null\")\n        if (SDK_INT >= 26) {\n            val channel = NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH)\n            val notificationManager: NotificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager\n            notificationManager.createNotificationChannel(channel)\n        }\n    }\n\n    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {\n        if (intent != null) {\n            ForegroundServiceContext.completeForegroundService(this, intent, TAG)\n            Log.d(TAG, \"onStartCommand: $intent\")\n            lifecycleScope.launchWhenStarted {\n                if (checkGcmStatus()) {\n                    handleIntent(intent)\n                } else {\n                    val intent = Intent(ACTION_GCM_RECONNECT).apply {\n                        setPackage(Constants.GMS_PACKAGE_NAME)\n                    }\n                    sendBroadcast(intent)\n                }\n            }\n        }\n        return super.onStartCommand(intent, flags, startId)\n    }\n\n    private fun checkGcmStatus(): Boolean {\n        if (McsService.isConnected(this)) {\n            Log.d(TAG, \"checkGcmStatus: gcm isConnected\")\n            return true\n        }\n        Log.d(TAG, \"checkGcmStatus: gcm need reconnect\")\n        return false\n    }\n\n    private suspend fun handleIntent(intent: Intent) {\n        val action = intent.action\n        if (checkGmsGcmStatus()) {\n            Log.d(TAG, \"handleIntent: checkGmsGcmStatus -> reset\")\n            runCatching { registerGcmInGms(this, intent) }.onFailure {\n                Log.w(TAG, \"handleIntent: registerGcmInGms error\", it)\n            }\n            return\n        }\n        Log.d(TAG, \"handleIntent: action: $action\")\n        when (action) {\n            GcmConstants.ACTION_C2DM_RECEIVE -> {\n                Log.d(TAG, \"start handle gcm message\")\n                intent.extras?.let { notifyVerificationInfo(it) }\n            }\n            ACTION_GCM_REGISTER_ALL_ACCOUNTS,\n            ACTION_GCM_CONNECTED -> {\n                updateLocalAccountGroups()\n            }\n            ACTION_GCM_REGISTER_ACCOUNT -> {\n                val accountName = intent.getStringExtra(KEY_GCM_REGISTER_ACCOUNT_NAME) ?: return\n                Log.d(TAG, \"GCM groups update account name: $accountName\")\n                val account = accountManager?.getAccountsByType(AuthConstants.DEFAULT_ACCOUNT_TYPE)?.find { it.name == accountName } ?: return\n                updateLocalAccountGroups(account)\n            }\n            ACTION_GCM_NOTIFY_COMPLETE -> {\n                val accountName = intent.getStringExtra(EXTRA_NOTIFICATION_ACCOUNT) ?: return\n                val notificationList = accountNotificationMap[accountName] ?: return\n                notificationList.forEach {\n                    val notificationId = it.first\n                    val notificationData = it.second\n                    updateNotificationReadState(accountName, notificationData, NOTIFICATION_STATUS_COMPLETE)\n                    NotificationManagerCompat.from(this).cancel(notificationId)\n                    Log.d(TAG, \"Notification with $accountName updateNotificationReadState <$notificationId> to Completed.\")\n                }\n                accountNotificationMap.remove(accountName)\n            }\n        }\n    }\n\n    private fun getCurrentLanguageTag(): String {\n        return runCatching {\n            if (SDK_INT >= 24) {\n                resources.configuration.locales[0].toLanguageTag()\n            } else {\n                val locale = resources.configuration.locale\n                locale.language + (if (locale.country.isEmpty()) \"\" else \"-\" + locale.country)\n            }\n        }.getOrDefault(Locale.getDefault().language)\n    }\n\n    private fun getDensityQualifier(): DeviceInfo.DensityQualifier {\n        val dpi = resources.displayMetrics.densityDpi\n        return when {\n            dpi >= DisplayMetrics.DENSITY_XXHIGH -> DeviceInfo.DensityQualifier.XXHDPI\n            dpi >= DisplayMetrics.DENSITY_XHIGH -> DeviceInfo.DensityQualifier.XHDPI\n            dpi >= DisplayMetrics.DENSITY_HIGH -> DeviceInfo.DensityQualifier.HDPI\n            dpi >= DisplayMetrics.DENSITY_TV -> DeviceInfo.DensityQualifier.TVDPI\n            dpi >= DisplayMetrics.DENSITY_MEDIUM -> DeviceInfo.DensityQualifier.MDPI\n            else -> DeviceInfo.DensityQualifier.LDPI\n        }\n    }\n\n    private suspend fun requestNotificationInfo(account: Account, notificationData: NotificationData) = suspendCoroutine { sup ->\n        try {\n            val response = getGunsApiServiceClient(account, accountManager!!).GmsGnotsFetchByIdentifier().executeBlocking(FetchByIdentifierRequest.Builder().apply {\n                config(GmsConfig.Builder().apply {\n                    versionInfo(GmsConfig.GmsVersionInfo(Constants.GMS_VERSION_CODE))\n                }.build())\n                identifiers(NotificationIdentifierList.Builder().apply {\n                    deviceInfo(DeviceInfo.Builder().apply {\n                        densityQualifier(getDensityQualifier())\n                        localeTag(getCurrentLanguageTag())\n                        sdkVersion(SDK_INT)\n                        density(resources.displayMetrics.density)\n                        timeZoneId(TimeZone.getDefault().id)\n                    }.build())\n                    notifications(notificationData.identifier?.let { listOf(it) } ?: emptyList())\n                }.build())\n            }.build())\n            sup.resume(response)\n        } catch (e: Exception) {\n            sup.resumeWithException(e)\n        }\n    }\n\n    private suspend fun notifyVerificationInfo(data: Bundle) {\n        Log.d(TAG, \"notifyVerificationInfo: from: ${data.getString(GcmConstants.EXTRA_FROM)} data: $data\")\n        val gcmBodyType = data.getString(GcmConstants.EXTRA_GCM_BODY) ?: return\n        if (GMS_GCM_NOTIFICATIONS != gcmBodyType) return\n        val payloadData = data.getString(GcmConstants.EXTRA_GMS_GNOTS_PAYLOAD) ?: return\n        val notificationData = NotificationData.ADAPTER.decode(Base64.decode(payloadData, DEFAULT_FLAGS))\n        Log.w(TAG, \"notifyVerificationInfo: $notificationData\")\n        if (notificationData.isActive == true) return\n        val account = notificationData.userInfo?.userId?.let { id ->\n            accountManager?.getAccountsByType(AuthConstants.DEFAULT_ACCOUNT_TYPE)?.find {\n                accountManager?.getUserData(it, AuthConstants.GOOGLE_USER_ID) == id\n            }\n        } ?: return\n        Log.d(TAG, \"notifyVerificationInfo: account: ${account.name}\")\n        val identifierResponse = withContext(Dispatchers.IO) {\n            repeat(NOTIFICATION_REPEAT_NUM) { attempt ->\n                try {\n                    val notificationInfo = requestNotificationInfo(account, notificationData)\n                    if (notificationInfo.notifications?.notificationDataList.isNullOrEmpty()) {\n                        throw RuntimeException(\"Notification not found\")\n                    }\n                    return@withContext notificationInfo\n                } catch (e: Exception) {\n                    Log.w(TAG, \"Attempt ${attempt + 1} failed: ${e.message}\")\n                }\n                delay(NOTIFICATION_DELAY_TIME)\n            }\n            return@withContext null\n        }\n        Log.d(TAG, \"notifyVerificationInfo: identifierResponse: $identifierResponse\")\n        val notifications = identifierResponse?.notifications?.notificationDataList ?: return\n        notifications.forEachIndexed { index, it ->\n            Log.d(TAG, \"notifyVerificationInfo: notifications: index:$index it: $it\")\n            updateNotificationReadState(account.name, it, NOTIFICATION_STATUS_READY)\n            sendNotification(account, notificationIdGenerator.incrementAndGet(), it)\n            updateNotificationReadState(account.name, it, NOTIFICATION_STATUS_COMPLETE)\n        }\n    }\n\n    private fun sendNotification(account: Account, notificationId: Int, notificationData: NotificationData) {\n        if (notificationData.isActive == true) return\n        val content = notificationData.content ?: return\n        val intentExtras = notificationData.intentActions?.primaryPayload?.extras ?: return\n        val intent = Intent(this, MainActivity::class.java).apply {\n            `package` = Constants.GMS_PACKAGE_NAME\n            flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK\n            intentExtras.forEach { putExtra(it.key, it.value_) }\n            putExtra(KEY_NOTIFICATION_ID, notificationId)\n        }\n        val pendingIntent = PendingIntentCompat.getActivity(this, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT, false)\n        val builder = NotificationCompat.Builder(this, CHANNEL_ID)\n            .setContentTitle(content.accountName)\n            .setContentText(content.description)\n            .setStyle(NotificationCompat.BigTextStyle().bigText(content.description))\n            .setPriority(NotificationCompat.PRIORITY_DEFAULT)\n            .setContentIntent(pendingIntent)\n            .setAutoCancel(true)\n            .setSmallIcon(R.drawable.ic_google_logo)\n        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) ==\n            PackageManager.PERMISSION_GRANTED\n        ) {\n            NotificationManagerCompat.from(this).notify(notificationId, builder.build())\n        }\n        runCatching { startActivity(intent) }\n        accountNotificationMap.getOrPut(account.name) { mutableListOf() }.add(Pair(notificationId, notificationData))\n    }\n\n    private suspend fun updateGroupsWithAccount(account: Account, regId: String) {\n        Log.d(TAG, \"updateGroupsWithAccount: account: ${account.name}\")\n        val authManager = AuthManager(this, account.name, Constants.GMS_PACKAGE_NAME, GMS_GCM_OAUTH_SERVICE).apply {\n            setItCaveatTypes(\"2\")\n        }\n        val authsToken = runCatching { withContext(Dispatchers.IO) { authManager.requestAuth(true) }.parseAuthsToken() }.getOrNull() ?: return\n        val extras = Bundle().apply {\n            putString(GcmConstants.EXTRA_ACCOUNT_NAME, account.name)\n            putString(GcmConstants.EXTRA_REG_ID, regId)\n            putString(GcmConstants.EXTRA_AUTHS_TOKEN, authsToken)\n            putString(GcmConstants.EXTRA_SEND_TO, GCM_GROUP_SENDER)\n            putString(GcmConstants.EXTRA_SEND_FROM, GCM_GROUP_SENDER)\n            putString(GcmConstants.EXTRA_MESSAGE_ID, \"${System.currentTimeMillis() / 1000}-0\")\n        }\n        Log.d(TAG, \"updateGroupsWithAccount extras: $extras\")\n        val intent = Intent(GcmConstants.ACTION_GCM_SEND).apply {\n            setPackage(Constants.GMS_PACKAGE_NAME)\n            putExtras(extras)\n            putExtra(GcmConstants.EXTRA_APP, Intent().apply { setPackage(Constants.GMS_PACKAGE_NAME) }.let { PendingIntentCompat.getBroadcast(this@GcmInGmsService, 0, it, 0, false) })\n        }.also {\n            it.putExtra(GcmConstants.EXTRA_MESSENGER, Messenger(object : Handler(Looper.getMainLooper()) {\n                override fun handleMessage(msg: Message) {\n                    if (Binder.getCallingUid() == Process.myUid()) {\n                        val history = sp?.getString(KEY_GCM_REG_ACCOUNT_LIST, \"\")\n                        if (history?.contains(account.name) == true) {\n                            Log.d(TAG, \"updateGroupsWithAccount handleMessage history<$history> contains: ${account.name}\")\n                            return\n                        }\n                        val saveStr = if (history.isNullOrEmpty()) account.name else \"${account.name}/$history\"\n                        sp?.edit()?.putString(KEY_GCM_REG_ACCOUNT_LIST, saveStr)?.apply()\n                        Log.d(TAG, \"updateGroupsWithAccount handleMessage save: $saveStr\")\n                    }\n                }\n            }))\n        }\n        sendOrderedBroadcast(intent, null)\n    }\n\n    private suspend fun updateLocalAccountGroups(account: Account? = null) {\n        Log.d(TAG, \"GMS $GMS_GCM_REGISTER_SENDER already registered, start updateLocalAccount\")\n        val regId = sp?.getString(KEY_GCM_REG_ID, null) ?: return\n        val accounts = chimeGmsRegistrationHelper.handleRegistration(regId)\n        if (accounts.isNotEmpty()) {\n            Log.d(TAG, \"updateLocalAccountGroups: handleRegistration done\")\n            accounts.forEach { updateGroupsWithAccount(it, regId) }\n            return\n        }\n        val localGoogleAccounts = accountManager?.getAccountsByType(AuthConstants.DEFAULT_ACCOUNT_TYPE) ?: return\n        val accountList = sp?.getString(KEY_GCM_REG_ACCOUNT_LIST, null)\n        if (account != null && accountList?.contains(account.name) != true) {\n            Log.d(TAG, \"updateLocalAccountGroups: single account: ${account.name}\")\n            updateGroupsWithAccount(account, regId)\n            return\n        }\n        Log.d(TAG, \"updateLocalAccountGroups: registrationAccountList: $accountList\")\n        val needRegisterAccounts = if (accountList == null) localGoogleAccounts.toList() else localGoogleAccounts.filter { !accountList.contains(it.name) }\n        Log.d(TAG, \"updateLocalAccountGroups: needRegisterAccounts: ${needRegisterAccounts.joinToString(\"|\") { it.name }}\")\n        if (needRegisterAccounts.isEmpty()) return\n        needRegisterAccounts.forEach { updateGroupsWithAccount(it, regId) }\n    }\n\n    private suspend fun registerGcmInGms(context: Context, intent: Intent) {\n        Log.i(TAG, \"Registering GMS $GMS_GCM_REGISTER_SENDER\")\n        val regId = withContext(Dispatchers.IO) {\n            val request = RegisterRequest().build(context)\n                .checkin(LastCheckinInfo.read(context))\n                .app(Constants.GMS_PACKAGE_NAME, Constants.GMS_PACKAGE_SIGNATURE_SHA1, BuildConfig.VERSION_CODE)\n                .sender(GMS_GCM_REGISTER_SENDER)\n                .extraParam(\"subscription\", GMS_GCM_REGISTER_SUBSCRIPTION)\n                .extraParam(\"X-subscription\", GMS_GCM_REGISTER_SUBSCRIPTION)\n                .extraParam(\"subtype\", GMS_GCM_REGISTER_SUBTYPE)\n                .extraParam(\"X-subtype\", GMS_GCM_REGISTER_SUBTYPE)\n                .extraParam(\"scope\", GMS_GCM_REGISTER_SCOPE)\n            val gcmDatabase = GcmDatabase(context)\n            ensureAppRegistrationAllowed(context, gcmDatabase, request.app)\n            completeRegisterRequest(context, gcmDatabase, request).getString(GcmConstants.EXTRA_REGISTRATION_ID)\n        }\n        Log.d(TAG, \"GCM IN GMS regId: $regId\")\n        if (regId == null) {\n            Log.w(TAG, \"registerGcmInGms reg id is null\")\n            return\n        }\n        val sharedPreferencesEditor = sp?.edit()\n        sharedPreferencesEditor?.putLong(KEY_GCM_ANDROID_ID, LastCheckinInfo.read(context).androidId)\n        sharedPreferencesEditor?.putString(KEY_GCM_REG_ID, regId)\n        sharedPreferencesEditor?.putString(KEY_GCM_REG_SENDER, GMS_GCM_REGISTER_SENDER)\n        sharedPreferencesEditor?.putLong(KEY_GCM_REG_TIME, System.currentTimeMillis())\n        sharedPreferencesEditor?.remove(KEY_GCM_REG_ACCOUNT_LIST)\n        chimeGmsRegistrationHelper.resetAllData()\n        if (sharedPreferencesEditor?.commit() == false) {\n            Log.d(TAG, \"Failed to write GMS registration\")\n        } else {\n            Log.d(TAG, \"registerGcmInGms: sendBroadcast: ${intent.action}\")\n            Intent(intent.action).apply {\n                setPackage(Constants.GMS_PACKAGE_NAME)\n                putExtras(intent)\n            }.let { sendBroadcast(it) }\n        }\n    }\n\n    private suspend fun updateNotificationReadState(accountName: String, notificationData: NotificationData, readState: Int) {\n        if (accountName.isEmpty() || notificationData.identifier?.uniqueId?.isEmpty() == true) {\n            return\n        }\n        try {\n            val identifier = notificationData.identifier\n            val readStateList = when {\n                readState == NOTIFICATION_STATUS_COMPLETE -> {\n                    listOf(\n                            ReadStateItem.Builder().apply {\n                                this.notification = identifier\n                                this.state = null\n                                this.status = readState\n                            }.build()\n                    )\n                }\n                notificationData.content?.actionButtons.isNullOrEmpty() -> {\n                    Log.w(TAG, \"No action buttons found, skipping read state update.\")\n                    return\n                }\n                else -> {\n                    notificationData.content!!.actionButtons.map {\n                        ReadStateItem.Builder().apply {\n                            this.notification = identifier\n                            this.state = it.icon\n                            this.status = readState\n                        }.build()\n                    }\n                }\n            }\n            withContext(Dispatchers.IO) {\n                sendNotificationReadState(accountName, ReadStateList.Builder().apply { items = readStateList }.build())\n            }\n            Log.i(TAG, \"Notification read state updated successfully for account: $accountName\")\n        } catch (e: Exception) {\n            Log.w(TAG, \"Failed to update the notification(s) read state.\", e)\n        }\n    }\n\n    private fun sendNotificationReadState(accountName: String, readStateList: ReadStateList) {\n        val account = accountManager?.getAccountsByType(AuthConstants.DEFAULT_ACCOUNT_TYPE)?.find { it.name == accountName } ?: return\n        getGunsApiServiceClient(account, accountManager!!).GmsGnotsSetReadStates().executeBlocking(\n            GmsGnotsSetReadStatesRequest.Builder().apply {\n                config = GmsConfig.Builder().apply {\n                    versionInfo(GmsConfig.GmsVersionInfo(Constants.GMS_VERSION_CODE))\n                }.build()\n                readStates = readStateList\n            }.build()\n        )\n    }\n\n    private fun checkGmsGcmStatus(): Boolean {\n        val targetId = LastCheckinInfo.read(this).androidId\n        val regSender = sp?.getString(KEY_GCM_REG_SENDER, null)\n        val regId = sp?.getString(KEY_GCM_REG_ID, null)\n        val androidId = sp?.getLong(KEY_GCM_ANDROID_ID, 0)\n        val regTime = sp?.getLong(KEY_GCM_REG_TIME, 0) ?: 0L\n        return targetId != androidId || regSender == null || regId == null || regTime + GCM_GMS_REG_REFRESH_S * 1000 < System.currentTimeMillis()\n    }\n\n    private fun AuthResponse.parseAuthsToken(): String? {\n        Log.d(TAG, \"parseAuthsToken start: auths: $auths itMetadata: $itMetadata\")\n        if (auths.isNullOrEmpty() || itMetadata.isNullOrEmpty()) return null\n        if (!auths.startsWith(AUTHS_TOKEN_PREFIX)) return null\n        try {\n            val tokenBase64 = auths.substring(AUTHS_TOKEN_PREFIX.length)\n            val authData = ItAuthData.ADAPTER.decode(Base64.decode(tokenBase64, DEFAULT_FLAGS))\n            val metadata = ItMetadataData.ADAPTER.decode(Base64.decode(itMetadata, DEFAULT_FLAGS))\n            val authorization = OAuthAuthorization.Builder().apply {\n                effectiveDurationSeconds(min(metadata.liveTime ?: Int.MAX_VALUE, expiresInDurationSec))\n                if (metadata.field_?.types?.contains(TokenField.FieldType.SCOPE) == true) {\n                    val scopeIds = metadata.entries.flatMap { entry ->\n                        entry.name.map { scope -> entry to scope }\n                    }.filter { (_, scope) ->\n                        scope in grantedScopes\n                    }.mapNotNull { (entry, _) ->\n                        entry.id\n                    }.toSet()\n                    scopeIds(scopeIds.toList())\n                }\n            }.build()\n            val oAuthTokenData = OAuthTokenData.Builder().apply {\n                fieldType(TokenField.FieldType.SCOPE.value)\n                authorization(authorization.encodeByteString())\n                durationMillis(0)\n            }.build()\n            val tokenDataBytes = oAuthTokenData.encode()\n            val secretKey: ByteArray? = authData.signature?.toByteArray()\n            val mac = Mac.getInstance(\"HmacSHA256\").apply { init(SecretKeySpec(secretKey, \"HmacSHA256\")) }\n            val bytes: ByteArray = mac.doFinal(tokenDataBytes)\n            val newAuthData = authData.newBuilder().apply {\n                tokens(arrayListOf(oAuthTokenData.encodeByteString()))\n                signature(ByteString.of(*bytes))\n            }.build()\n            return AUTHS_TOKEN_PREFIX + Base64.encodeToString(newAuthData.encode(), DEFAULT_FLAGS)\n        } catch (e: Exception) {\n            Log.w(TAG, \"parseAuthsToken: \", e);\n            return null;\n        }\n    }\n\n    private fun getGunsApiServiceClient(account: Account, accountManager: AccountManager): GunsGmscoreApiServiceClient {\n        val oauthToken = accountManager.blockingGetAuthToken(account, GMS_NOTS_OAUTH_SERVICE, true)\n        return createGrpcClient<GunsGmscoreApiServiceClient>(baseUrl = GMS_NOTS_BASE_URL, oauthToken = oauthToken)\n    }\n}\n\nclass GcmRegistrationReceiver : WakefulBroadcastReceiver() {\n    override fun onReceive(context: Context, intent: Intent) {\n        val shouldReceiveTwoStepVerification = AuthPrefs.shouldReceiveTwoStepVerification(context)\n        if (!shouldReceiveTwoStepVerification) {\n            Log.d(TAG, \"GcmRegistrationReceiver onReceive: <Two-Step> Switch not allowed \")\n            return\n        }\n        Log.d(TAG, \"GcmRegistrationReceiver onReceive: action: ${intent.action}\")\n        val callIntent = Intent(context, GcmInGmsService::class.java)\n        callIntent.action = intent.action\n        if (ACTION_GCM_REGISTER_ACCOUNT == intent.action || ACTION_GCM_NOTIFY_COMPLETE == intent.action || GcmConstants.ACTION_C2DM_RECEIVE == intent.action) {\n            callIntent.putExtras(intent.extras!!)\n        }\n        ForegroundServiceContext(context).startService(callIntent)\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/gcm/GcmPrefs.kt",
    "content": "package org.microg.gms.gcm\n\nimport android.content.Context\nimport android.content.Intent\nimport android.net.ConnectivityManager\nimport android.net.NetworkInfo\nimport android.util.Log\nimport org.microg.gms.gcm.TriggerReceiver.FORCE_TRY_RECONNECT\nimport org.microg.gms.settings.SettingsContract\nimport org.microg.gms.settings.SettingsContract.Gcm\nimport org.microg.gms.settings.SettingsContract.setSettings\nimport kotlin.math.max\nimport kotlin.math.min\n\ndata class GcmPrefs(\n    val isGcmLogEnabled: Boolean,\n    val lastPersistedId: String?,\n    val confirmNewApps: Boolean,\n    val gcmEnabled: Boolean,\n    val networkMobile: Int,\n    val networkWifi: Int,\n    val networkRoaming: Int,\n    val networkOther: Int,\n    val learntMobileInterval: Int,\n    val learntWifiInterval: Int,\n    val learntOtherInterval: Int,\n) {\n\n    val isEnabled: Boolean get() = gcmEnabled\n\n    val lastPersistedIds: List<String>\n        get() = if (lastPersistedId.isNullOrEmpty()) emptyList() else lastPersistedId.split(\"\\\\|\")\n\n    companion object {\n        const val PREF_CONFIRM_NEW_APPS = Gcm.CONFIRM_NEW_APPS\n        const val PREF_NETWORK_MOBILE = Gcm.NETWORK_MOBILE\n        const val PREF_NETWORK_WIFI = Gcm.NETWORK_WIFI\n        const val PREF_NETWORK_ROAMING = Gcm.NETWORK_ROAMING\n        const val PREF_NETWORK_OTHER = Gcm.NETWORK_OTHER\n\n        private const val MIN_INTERVAL = 5 * 60 * 1000 // 5 minutes\n        private const val MAX_INTERVAL = 15 * 60 * 1000 // 15 minutes\n\n        @JvmStatic\n        fun get(context: Context): GcmPrefs {\n            return SettingsContract.getSettings(context, Gcm.getContentUri(context), Gcm.PROJECTION) { c ->\n                GcmPrefs(\n                    isGcmLogEnabled = c.getInt(0) != 0,\n                    lastPersistedId = c.getString(1),\n                    confirmNewApps = c.getInt(2) != 0,\n                    gcmEnabled = c.getInt(3) != 0,\n                    networkMobile = c.getInt(4),\n                    networkWifi = c.getInt(5),\n                    networkRoaming = c.getInt(6),\n                    networkOther = c.getInt(7),\n                    learntMobileInterval = c.getInt(8),\n                    learntWifiInterval = c.getInt(9),\n                    learntOtherInterval = c.getInt(10),\n                )\n            }\n        }\n\n        fun write(context: Context, config: ServiceConfiguration) {\n            val gcmPrefs = get(context)\n            setSettings(context, Gcm.getContentUri(context)) {\n                put(Gcm.ENABLE_GCM, config.enabled)\n                put(Gcm.CONFIRM_NEW_APPS, config.confirmNewApps)\n                put(Gcm.NETWORK_MOBILE, config.mobile)\n                put(Gcm.NETWORK_WIFI, config.wifi)\n                put(Gcm.NETWORK_ROAMING, config.roaming)\n                put(Gcm.NETWORK_OTHER, config.other)\n            }\n            gcmPrefs.setEnabled(context, config.enabled)\n        }\n\n        fun setEnabled(context: Context, enabled: Boolean) {\n            val prefs = get(context)\n            setSettings(context, Gcm.getContentUri(context)) {\n                put(Gcm.ENABLE_GCM, enabled)\n            }\n            prefs.setEnabled(context, enabled)\n        }\n\n        @JvmStatic\n        fun clearLastPersistedId(context: Context) {\n            setSettings(context, Gcm.getContentUri(context)) {\n                put(Gcm.LAST_PERSISTENT_ID, \"\")\n            }\n        }\n    }\n\n    /**\n     * Call this whenever the enabled state of GCM has changed.\n     */\n    private fun setEnabled(context: Context, enabled: Boolean) {\n        if (gcmEnabled == enabled) return\n        if (enabled) {\n            val i = Intent(FORCE_TRY_RECONNECT, null, context, TriggerReceiver::class.java)\n            context.sendBroadcast(i)\n        } else {\n            McsService.stop(context)\n        }\n    }\n\n    @Suppress(\"DEPRECATION\")\n    fun getNetworkPrefForInfo(info: NetworkInfo?): String {\n        if (info == null) return PREF_NETWORK_OTHER\n        return if (info.isRoaming) PREF_NETWORK_ROAMING else when (info.type) {\n            ConnectivityManager.TYPE_MOBILE -> PREF_NETWORK_MOBILE\n            ConnectivityManager.TYPE_WIFI -> PREF_NETWORK_WIFI\n            else -> PREF_NETWORK_OTHER\n        }\n    }\n\n    @Suppress(\"DEPRECATION\")\n    fun getHeartbeatMsFor(info: NetworkInfo?): Int {\n        return getHeartbeatMsFor(getNetworkPrefForInfo(info))\n    }\n\n    fun getHeartbeatMsFor(pref: String): Int {\n        return if (PREF_NETWORK_ROAMING == pref) {\n            if (networkRoaming != 0) networkRoaming * 60000 else learntMobileInterval\n        } else if (PREF_NETWORK_MOBILE == pref) {\n            if (networkMobile != 0) networkMobile * 60000 else learntMobileInterval\n        } else if (PREF_NETWORK_WIFI == pref) {\n            if (networkWifi != 0) networkWifi * 60000 else learntWifiInterval\n        } else {\n            if (networkOther != 0) networkOther * 60000 else learntOtherInterval\n        }\n    }\n\n    fun learnTimeout(context: Context, pref: String) {\n        Log.d(\"GmsGcmPrefs\", \"learnTimeout: $pref\")\n        when (pref) {\n            PREF_NETWORK_MOBILE, PREF_NETWORK_ROAMING -> setSettings(context, Gcm.getContentUri(context)) {\n                val newInterval = (learntMobileInterval * 0.95).toInt()\n                put(Gcm.LEARNT_MOBILE, max(MIN_INTERVAL, min(newInterval, MAX_INTERVAL)))\n            }\n            PREF_NETWORK_WIFI -> setSettings(context, Gcm.getContentUri(context)) {\n                val newInterval = (learntWifiInterval * 0.95).toInt()\n                put(Gcm.LEARNT_WIFI, max(MIN_INTERVAL, min(newInterval, MAX_INTERVAL)))\n            }\n            else -> setSettings(context, Gcm.getContentUri(context)) {\n                val newInterval = (learntOtherInterval * 0.95).toInt()\n                put(Gcm.LEARNT_OTHER, max(MIN_INTERVAL, min(newInterval, MAX_INTERVAL)))\n            }\n        }\n    }\n\n    fun learnReached(context: Context, pref: String, time: Long) {\n        Log.d(\"GmsGcmPrefs\", \"learnReached: $pref / $time\")\n        when (pref) {\n            PREF_NETWORK_MOBILE, PREF_NETWORK_ROAMING -> {\n                if (time > learntMobileInterval / 4 * 3) {\n                    val newInterval = (learntMobileInterval * 1.02).toInt()\n                    setSettings(context, Gcm.getContentUri(context)) {\n                        put(Gcm.LEARNT_MOBILE, max(MIN_INTERVAL, min(newInterval, MAX_INTERVAL)))\n                    }\n                }\n            }\n            PREF_NETWORK_WIFI -> {\n                if (time > learntWifiInterval / 4 * 3) {\n                    val newInterval = (learntWifiInterval * 1.02).toInt()\n                    setSettings(context, Gcm.getContentUri(context)) {\n                        put(Gcm.LEARNT_WIFI, max(MIN_INTERVAL, min(newInterval, MAX_INTERVAL)))\n                    }\n                }\n            }\n            else -> {\n                if (time > learntOtherInterval / 4 * 3) {\n                    val newInterval = (learntOtherInterval * 1.02).toInt()\n                    setSettings(context, Gcm.getContentUri(context)) {\n                        put(Gcm.LEARNT_OTHER, max(MIN_INTERVAL, min(newInterval, MAX_INTERVAL)))\n                    }\n                }\n            }\n        }\n    }\n\n    @Suppress(\"DEPRECATION\")\n    fun isEnabledFor(info: NetworkInfo?): Boolean {\n        return isEnabled && info != null && getHeartbeatMsFor(info) >= 0\n    }\n\n    fun extendLastPersistedId(context: Context, id: String) {\n        val newId = if (lastPersistedId.isNullOrEmpty()) id else \"$lastPersistedId|$id\"\n        setSettings(context, Gcm.getContentUri(context)) {\n            put(Gcm.LAST_PERSISTENT_ID, newId)\n        }\n    }\n\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/gcm/PushRegisterService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage org.microg.gms.gcm\n\nimport android.app.Activity\nimport android.app.PendingIntent\nimport android.content.Context\nimport android.content.Intent\nimport android.os.*\nimport android.util.Log\nimport androidx.core.app.PendingIntentCompat\nimport androidx.legacy.content.WakefulBroadcastReceiver\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.LifecycleOwner\nimport androidx.lifecycle.LifecycleService\nimport androidx.lifecycle.lifecycleScope\nimport org.microg.gms.checkin.CheckinPreferences\nimport org.microg.gms.checkin.CheckinService\nimport org.microg.gms.checkin.LastCheckinInfo\nimport org.microg.gms.common.ForegroundServiceContext\nimport org.microg.gms.common.PackageUtils\nimport org.microg.gms.gcm.GcmConstants.*\nimport org.microg.gms.ui.AskPushPermission\nimport java.util.concurrent.atomic.AtomicBoolean\nimport kotlin.coroutines.resume\nimport kotlin.coroutines.suspendCoroutine\n\nprivate const val TAG = \"GmsGcmRegister\"\n\nprivate suspend fun ensureCheckinIsUpToDate(context: Context) {\n    if (!CheckinPreferences.isEnabled(context)) throw RuntimeException(\"Checkin disabled\")\n    val lastCheckin = LastCheckinInfo.read(context).lastCheckin\n    if (lastCheckin < System.currentTimeMillis() - CheckinService.MAX_VALID_CHECKIN_AGE) {\n        val resultData: Bundle = suspendCoroutine { continuation ->\n            val intent = Intent(context, CheckinService::class.java)\n            val continued = AtomicBoolean(false)\n            intent.putExtra(CheckinService.EXTRA_RESULT_RECEIVER, object : ResultReceiver(null) {\n                override fun onReceiveResult(resultCode: Int, resultData: Bundle?) {\n                    if (continued.compareAndSet(false, true)) continuation.resume(resultData ?: Bundle.EMPTY)\n                }\n            })\n            ForegroundServiceContext(context).startService(intent)\n            Handler().postDelayed({\n                if (continued.compareAndSet(false, true)) continuation.resume(Bundle.EMPTY)\n            }, 10000L)\n        }\n        if (resultData.getLong(CheckinService.EXTRA_NEW_CHECKIN_TIME, 0L) + lastCheckin == 0L) {\n            throw RuntimeException(\"No checkin available\")\n        }\n    }\n}\n\nsuspend fun ensureAppRegistrationAllowed(context: Context, database: GcmDatabase, packageName: String) {\n    if (!GcmPrefs.get(context).isEnabled) throw RuntimeException(\"GCM disabled\")\n    val app = database.getApp(packageName)\n    if (app == null && GcmPrefs.get(context).confirmNewApps) {\n        val accepted: Boolean = suspendCoroutine { continuation ->\n            val i = Intent(context, AskPushPermission::class.java)\n            i.putExtra(AskPushPermission.EXTRA_REQUESTED_PACKAGE, packageName)\n            i.putExtra(AskPushPermission.EXTRA_RESULT_RECEIVER, object : ResultReceiver(null) {\n                override fun onReceiveResult(resultCode: Int, resultData: Bundle?) {\n                    continuation.resume(resultCode == Activity.RESULT_OK)\n                }\n            })\n            i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)\n            i.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)\n            i.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT)\n            context.startActivity(i)\n        }\n        if (!accepted) {\n            throw RuntimeException(\"Push permission not granted to $packageName\")\n        }\n    } else if (app?.allowRegister == false) {\n        throw RuntimeException(\"Push permission not granted to $packageName\")\n    }\n}\n\nsuspend fun completeRegisterRequest(context: Context, database: GcmDatabase, request: RegisterRequest, requestId: String? = null): Bundle = suspendCoroutine { continuation ->\n    PushRegisterManager.completeRegisterRequest(context, database, requestId, request) {\n        val errorMsg = it.getString(EXTRA_ERROR)\n        Log.w(TAG, \"completeRegisterRequest error: $errorMsg\")\n        if (errorMsg == PushRegisterManager.attachRequestId(ERROR_INVALID_FID, requestId) && !request.delete) {\n            Log.d(TAG, \"completeRegisterRequest register error, You need to call delete first before you can re-register\")\n            request.delete = true\n            request.response\n            request.delete = false\n            PushRegisterManager.completeRegisterRequest(context, database, requestId, request) { result ->\n                continuation.resume(result)\n            }\n        } else {\n            continuation.resume(it)\n        }\n    }\n}\n\nprivate val Intent.requestId: String?\n    get() {\n        val kidString = getStringExtra(GcmConstants.EXTRA_KID) ?: return null\n        if (kidString.startsWith(\"|\")) {\n            val kid = kidString.split(\"\\\\|\".toRegex()).toTypedArray()\n            if (kid.size >= 3 && \"ID\" == kid[1]) {\n                return kid[2]\n            }\n        }\n        return null\n    }\n\nprivate val Intent.app: PendingIntent?\n    get() = getParcelableExtra(EXTRA_APP)\n\nprivate val Intent.appPackageName: String?\n    get() = PackageUtils.packageFromPendingIntent(app)\n\nclass PushRegisterService : LifecycleService() {\n    private lateinit var database: GcmDatabase\n    override fun onCreate() {\n        super.onCreate()\n        database = GcmDatabase(this)\n    }\n\n    override fun onDestroy() {\n        super.onDestroy()\n        database.close()\n    }\n\n    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {\n        if (intent != null) {\n            WakefulBroadcastReceiver.completeWakefulIntent(intent)\n            Log.d(TAG, \"onStartCommand: $intent\")\n            lifecycleScope.launchWhenStarted {\n                handleIntent(intent)\n            }\n        }\n        return super.onStartCommand(intent, flags, startId)\n    }\n\n    private suspend fun handleIntent(intent: Intent) {\n        try {\n            ensureCheckinIsUpToDate(this)\n            if (ACTION_C2DM_UNREGISTER == intent.action || ACTION_C2DM_REGISTER == intent.action && \"1\" == intent.getStringExtra(EXTRA_DELETE)) {\n                unregister(intent)\n            } else if (ACTION_C2DM_REGISTER == intent.action) {\n                register(intent)\n            }\n        } catch (e: Exception) {\n            Log.w(TAG, e)\n            replyNotAvailable(intent)\n        }\n    }\n\n    private fun replyNotAvailable(intent: Intent) {\n        val outIntent = Intent(ACTION_C2DM_REGISTRATION)\n        outIntent.putExtra(EXTRA_ERROR, PushRegisterManager.attachRequestId(ERROR_SERVICE_NOT_AVAILABLE, intent.requestId))\n        sendReply(intent, intent.appPackageName, outIntent)\n    }\n\n    private suspend fun register(intent: Intent) {\n        val packageName = intent.appPackageName ?: throw RuntimeException(\"No package provided\")\n        ensureAppRegistrationAllowed(this, database, packageName)\n        Log.d(TAG, \"register[req]: \" + intent.toString() + \" extras=\" + intent!!.extras)\n        val bundle = completeRegisterRequest(this, database,\n                RegisterRequest()\n                        .build(this)\n                        .sender(intent.getStringExtra(EXTRA_SENDER))\n                        .checkin(LastCheckinInfo.read(this))\n                        .app(packageName)\n                        .extraParams(intent.extras))\n\n        val outIntent = Intent(ACTION_C2DM_REGISTRATION)\n        outIntent.putExtras(bundle)\n        Log.d(TAG, \"register[res]: \" + outIntent.toString() + \" extras=\" + outIntent.extras)\n        sendReply(intent, packageName, outIntent)\n    }\n\n    private suspend fun unregister(intent: Intent) {\n        val packageName = intent.appPackageName ?: throw RuntimeException(\"No package provided\")\n        Log.d(TAG, \"unregister[req]: \" + intent.toString() + \" extras=\" + intent.extras)\n        val bundle = completeRegisterRequest(this, database, RegisterRequest()\n                .build(this)\n                .sender(intent.getStringExtra(EXTRA_SENDER))\n                .checkin(LastCheckinInfo.read(this))\n                .app(packageName)\n                .extraParams(intent.extras)\n        )\n        val outIntent = Intent(ACTION_C2DM_REGISTRATION)\n        outIntent.putExtras(bundle)\n        Log.d(TAG, \"unregister[res]: \" + outIntent.toString() + \" extras=\" + outIntent.extras)\n        sendReply(intent, packageName, outIntent)\n    }\n\n    private fun sendReply(intent: Intent, packageName: String?, outIntent: Intent) {\n        if (sendReplyToMessenger(intent, outIntent)) return\n        outIntent.setPackage(packageName)\n        sendOrderedBroadcast(outIntent, null)\n    }\n\n    private fun sendReplyToMessenger(intent: Intent, outIntent: Intent): Boolean {\n        try {\n            val messenger = intent.getParcelableExtra<Messenger>(EXTRA_MESSENGER) ?: return false\n            val message = Message.obtain()\n            message.obj = outIntent\n            messenger.send(message)\n            return true\n        } catch (e: Exception) {\n            Log.w(TAG, e)\n            return false\n        }\n    }\n\n    override fun onBind(intent: Intent): IBinder? {\n        Log.d(TAG, \"onBind: $intent\")\n        super.onBind(intent)\n        if (ACTION_C2DM_REGISTER == intent.action) {\n            val messenger = Messenger(PushRegisterHandler(this, database, lifecycle))\n            return messenger.binder\n        }\n        return null\n    }\n}\n\ninternal class PushRegisterHandler(private val context: Context, private val database: GcmDatabase, override val lifecycle: Lifecycle) : Handler(), LifecycleOwner {\n\n    private var callingUid = 0\n    override fun sendMessageAtTime(msg: Message, uptimeMillis: Long): Boolean {\n        callingUid = Binder.getCallingUid()\n        return super.sendMessageAtTime(msg, uptimeMillis)\n    }\n\n    private fun sendReplyViaMessage(what: Int, id: Int, replyTo: Messenger, messageData: Bundle) {\n        val response = Message.obtain()\n        response.what = what\n        response.arg1 = id\n        response.data = messageData\n        try {\n            replyTo.send(response)\n        } catch (e: RemoteException) {\n            Log.w(TAG, e)\n        }\n    }\n\n    private fun sendReplyViaIntent(outIntent: Intent, replyTo: Messenger) {\n        val message = Message.obtain()\n        message.obj = outIntent\n        try {\n            replyTo.send(message)\n        } catch (e: RemoteException) {\n            Log.w(TAG, e)\n        }\n    }\n\n    private fun sendReply(what: Int, id: Int, replyTo: Messenger, data: Bundle, oneWay: Boolean) {\n        if (what == 0) {\n            val outIntent = Intent(ACTION_C2DM_REGISTRATION)\n            outIntent.putExtras(data)\n            sendReplyViaIntent(outIntent, replyTo)\n            return\n        }\n        val messageData = Bundle()\n        messageData.putBundle(\"data\", data)\n        sendReplyViaMessage(what, id, replyTo, messageData)\n    }\n\n    private fun replyError(what: Int, id: Int, replyTo: Messenger, errorMessage: String, oneWay: Boolean) {\n        val bundle = Bundle()\n        bundle.putString(EXTRA_ERROR, errorMessage)\n        sendReply(what, id, replyTo, bundle, oneWay)\n    }\n\n    private fun replyNotAvailable(what: Int, id: Int, replyTo: Messenger) {\n        replyError(what, id, replyTo, ERROR_SERVICE_NOT_AVAILABLE, false)\n    }\n\n    private val selfAuthIntent: PendingIntent\n        private get() {\n            val intent = Intent()\n            intent.setPackage(\"com.google.example.invalidpackage\")\n            return PendingIntentCompat.getBroadcast(context, 0, intent, 0, false)!!\n        }\n\n    override fun handleMessage(msg: Message) {\n        var msg = msg\n        val obj = msg.obj\n        if (msg.what == 0) {\n            if (obj is Intent) {\n                val nuMsg = Message.obtain()\n                nuMsg.what = msg.what\n                nuMsg.arg1 = 0\n                nuMsg.replyTo = null\n                val packageName = obj.appPackageName\n                val data = Bundle()\n                data.putBoolean(\"oneWay\", false)\n                data.putString(\"pkg\", packageName)\n                data.putBundle(\"data\", msg.data)\n                nuMsg.data = data\n                msg = nuMsg\n            } else {\n                return\n            }\n        }\n        val what = msg.what\n        val id = msg.arg1\n        val replyTo = msg.replyTo\n        if (replyTo == null) {\n            Log.w(TAG, \"replyTo is null\")\n            return\n        }\n        val data = msg.data\n        val packageName = data.getString(\"pkg\") ?: return\n        val subdata = data.getBundle(\"data\")\n        try {\n            PackageUtils.checkPackageUid(context, packageName, callingUid)\n        } catch (e: SecurityException) {\n            Log.w(TAG, e)\n            return\n        }\n        Log.d(TAG, \"handleMessage: package=$packageName what=$what id=$id\")\n        val oneWay = data.getBoolean(\"oneWay\", false)\n        when (what) {\n            0, 1 -> {\n                lifecycleScope.launchWhenStarted {\n                    try {\n                        val sender = subdata?.getString(\"sender\")\n                        val delete = subdata?.get(\"delete\") != null\n                        ensureCheckinIsUpToDate(context)\n                        if (!delete) ensureAppRegistrationAllowed(context, database, packageName)\n                        val bundle = completeRegisterRequest(context, database,\n                                RegisterRequest()\n                                        .build(context)\n                                        .sender(sender)\n                                        .checkin(LastCheckinInfo.read(context))\n                                        .app(packageName)\n                                        .delete(delete)\n                                        .extraParams(subdata))\n                        sendReply(what, id, replyTo, bundle, oneWay)\n                    } catch (e: Exception) {\n                        Log.w(TAG, e)\n                        replyNotAvailable(what, id, replyTo)\n                    }\n                }\n            }\n            2 -> {\n                val messageId = subdata!!.getString(\"google.message_id\")\n                Log.d(TAG, \"Ack $messageId for $packageName\")\n                val i = Intent(context, McsService::class.java)\n                i.action = McsConstants.ACTION_ACK\n                i.putExtra(EXTRA_APP, selfAuthIntent)\n                ForegroundServiceContext(context).startService(i)\n            }\n            else -> {\n                val bundle = Bundle()\n                bundle.putBoolean(\"unsupported\", true)\n                sendReplyViaMessage(what, id, replyTo, bundle)\n                return\n            }\n        }\n        if (oneWay) {\n            val bundle = Bundle()\n            bundle.putBoolean(\"ack\", true)\n            sendReplyViaMessage(what, id, replyTo, bundle)\n        }\n    }\n}\n\nclass PushRegisterReceiver : WakefulBroadcastReceiver() {\n    override fun onReceive(context: Context, intent: Intent) {\n        val intent2 = Intent(context, PushRegisterService::class.java)\n        if (intent.extras!!.get(\"delete\") != null) {\n            intent2.action = ACTION_C2DM_UNREGISTER\n        } else {\n            intent2.action = ACTION_C2DM_REGISTER\n        }\n        intent2.putExtras(intent.extras!!)\n        startWakefulService(context, intent2)\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/gcm/ServiceInfo.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.gcm\n\nimport android.content.BroadcastReceiver\nimport android.content.Context\nimport android.content.Intent\nimport android.content.IntentFilter\nimport android.util.Log\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\nimport java.io.Serializable\nimport kotlin.coroutines.resume\nimport kotlin.coroutines.resumeWithException\nimport kotlin.coroutines.suspendCoroutine\n\nprivate const val ACTION_SERVICE_INFO_REQUEST = \"org.microg.gms.gcm.SERVICE_INFO_REQUEST\"\nprivate const val ACTION_SERVICE_INFO_RESPONSE = \"org.microg.gms.gcm.SERVICE_INFO_RESPONSE\"\nprivate const val EXTRA_SERVICE_INFO = \"org.microg.gms.gcm.SERVICE_INFO\"\nprivate const val TAG = \"GmsGcmStatusInfo\"\n\ndata class ServiceInfo(val configuration: ServiceConfiguration, val connected: Boolean, val startTimestamp: Long, val learntMobileInterval: Int, val learntWifiInterval: Int, val learntOtherInterval: Int) : Serializable\n\ndata class ServiceConfiguration(val enabled: Boolean, val confirmNewApps: Boolean, val mobile: Int, val wifi: Int, val roaming: Int, val other: Int) : Serializable\n\nprivate fun GcmPrefs.toConfiguration(): ServiceConfiguration = ServiceConfiguration(isEnabled, confirmNewApps, networkMobile, networkWifi, networkRoaming, networkOther)\n\nclass ServiceInfoReceiver : BroadcastReceiver() {\n    override fun onReceive(context: Context, intent: Intent) {\n        try {\n            context.sendOrderedBroadcast(Intent(ACTION_SERVICE_INFO_RESPONSE).apply {\n                setPackage(context.packageName)\n                val prefs = GcmPrefs.get(context)\n                val info = ServiceInfo(\n                    configuration = prefs.toConfiguration(),\n                    connected = McsService.isConnected(context),\n                    startTimestamp = McsService.getStartTimestamp(),\n                    learntMobileInterval = prefs.learntMobileInterval,\n                    learntWifiInterval = prefs.learntWifiInterval,\n                    learntOtherInterval = prefs.learntOtherInterval\n                )\n                putExtra(EXTRA_SERVICE_INFO, info)\n            }, null)\n        } catch (e: Exception) {\n            Log.w(TAG, e)\n        }\n    }\n}\n\nprivate suspend fun sendToServiceInfoReceiver(intent: Intent, context: Context): ServiceInfo = suspendCoroutine {\n    context.registerReceiver(object : BroadcastReceiver() {\n        override fun onReceive(context: Context, intent: Intent) {\n            context.unregisterReceiver(this)\n            val serviceInfo = try {\n                intent.getSerializableExtra(EXTRA_SERVICE_INFO) as ServiceInfo\n            } catch (e: Exception) {\n                it.resumeWithException(e)\n                return\n            }\n            try {\n                it.resume(serviceInfo)\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n            }\n        }\n    }, IntentFilter(ACTION_SERVICE_INFO_RESPONSE))\n    try {\n        context.sendOrderedBroadcast(intent, null)\n    } catch (e: Exception) {\n        it.resumeWithException(e)\n    }\n}\n\nsuspend fun getGcmServiceInfo(context: Context): ServiceInfo = sendToServiceInfoReceiver(\n    // this is still using a broadcast, because it calls into McsService in the persistent process\n        Intent(context, ServiceInfoReceiver::class.java).apply {\n            action = ACTION_SERVICE_INFO_REQUEST\n        }, context)\n\nsuspend fun setGcmServiceConfiguration(context: Context, configuration: ServiceConfiguration) = withContext(Dispatchers.IO) {\n    GcmPrefs.write(context, configuration)\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/gcm/extensions.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.gcm\n\nimport com.squareup.wire.GrpcClient\nimport com.squareup.wire.Service\nimport okhttp3.Interceptor\nimport okhttp3.OkHttpClient\nimport okhttp3.Response\n\nconst val ACTION_GCM_RECONNECT = \"org.microg.gms.gcm.RECONNECT\"\nconst val ACTION_GCM_CONNECTED = \"org.microg.gms.gcm.CONNECTED\"\nconst val ACTION_GCM_REGISTER_ACCOUNT = \"org.microg.gms.gcm.REGISTER_ACCOUNT\"\nconst val ACTION_GCM_REGISTER_ALL_ACCOUNTS = \"org.microg.gms.gcm.REGISTER_ALL_ACCOUNTS\"\nconst val ACTION_GCM_NOTIFY_COMPLETE = \"org.microg.gms.gcm.NOTIFY_COMPLETE\"\nconst val KEY_GCM_REGISTER_ACCOUNT_NAME = \"register_account_name\"\nconst val EXTRA_NOTIFICATION_ACCOUNT = \"notification_account\"\n\nconst val GMS_NOTS_OAUTH_SERVICE = \"oauth2:https://www.googleapis.com/auth/notifications\"\nconst val GMS_NOTS_BASE_URL = \"https://notifications-pa.googleapis.com\"\n\nclass AuthHeaderInterceptor(\n    private val oauthToken: String,\n) : Interceptor {\n    override fun intercept(chain: Interceptor.Chain): Response {\n        val original = chain.request().newBuilder().header(\"Authorization\", \"Bearer $oauthToken\")\n        return chain.proceed(original.build())\n    }\n}\n\ninline fun <reified S : Service> createGrpcClient(\n    baseUrl: String,\n    oauthToken: String,\n    minMessageToCompress: Long = Long.MAX_VALUE\n): S {\n    val client = OkHttpClient.Builder().apply {\n        addInterceptor(AuthHeaderInterceptor(oauthToken))\n    }.build()\n    val grpcClient = GrpcClient.Builder()\n        .client(client)\n        .baseUrl(baseUrl)\n        .minMessageToCompress(minMessageToCompress)\n        .build()\n    return grpcClient.create(S::class)\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/gcm/registeration/ChimeGmsAccount.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.gcm.registeration\n\nimport google.internal.notifications.v1.RegistrationStatus\nimport org.json.JSONObject\n\ndata class ChimeGmsAccount(\n    val id: String,\n    val accountName: String,\n    val representativeTargetId: String?,\n    val registrationStatus: RegistrationStatus?,\n    val obfuscatedGaiaId: String?\n) {\n\n    fun toJson(): String {\n        return JSONObject().apply {\n            put(KEY_ID, id)\n            put(KEY_ACCOUNT_NAME, accountName)\n            put(KEY_REPRESENTATIVE_TARGET_ID, representativeTargetId)\n            put(KEY_REGISTRATION_STATUS, registrationStatus?.value)\n            put(KEY_OBFUSCATED_GAIA_ID, obfuscatedGaiaId)\n        }.toString()\n    }\n\n    companion object {\n        private const val KEY_ID = \"id\"\n        private const val KEY_ACCOUNT_NAME = \"accountName\"\n        private const val KEY_REPRESENTATIVE_TARGET_ID = \"representativeTargetId\"\n        private const val KEY_REGISTRATION_STATUS = \"registrationStatus\"\n        private const val KEY_OBFUSCATED_GAIA_ID = \"obfuscatedGaiaId\"\n\n        fun parseJson(json: String): ChimeGmsAccount {\n            val jsonObject = JSONObject(json)\n            return ChimeGmsAccount(\n                id = jsonObject.optString(KEY_ID),\n                accountName = jsonObject.optString(KEY_ACCOUNT_NAME),\n                representativeTargetId = jsonObject.optString(KEY_REPRESENTATIVE_TARGET_ID),\n                registrationStatus = RegistrationStatus.fromValue(jsonObject.optInt(KEY_REGISTRATION_STATUS)),\n                obfuscatedGaiaId = jsonObject.optString(KEY_OBFUSCATED_GAIA_ID)\n            )\n        }\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/gcm/registeration/ChimeGmsRegistrationHelper.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.gcm.registeration\n\nimport android.accounts.Account\nimport android.accounts.AccountManager\nimport android.content.Context\nimport android.os.LocaleList\nimport android.util.Log\nimport androidx.core.app.NotificationManagerCompat\nimport androidx.core.content.edit\nimport google.internal.notifications.v1.AppBlockState\nimport google.internal.notifications.v1.AppRegistration\nimport google.internal.notifications.v1.AppRegistrationContainer\nimport google.internal.notifications.v1.AuthWrapper\nimport google.internal.notifications.v1.Channel\nimport google.internal.notifications.v1.DeviceRequest\nimport google.internal.notifications.v1.DeviceType\nimport google.internal.notifications.v1.FeatureBitmapList\nimport google.internal.notifications.v1.GmsDeviceContext\nimport google.internal.notifications.v1.GmsDeviceProfile\nimport google.internal.notifications.v1.NotificationsApiServiceClient\nimport google.internal.notifications.v1.RegistrationPayload\nimport google.internal.notifications.v1.RegistrationReason\nimport google.internal.notifications.v1.RegistrationRequest\nimport google.internal.notifications.v1.RegistrationStatus\nimport google.internal.notifications.v1.SdkType\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\nimport org.microg.gms.auth.AuthConstants\nimport org.microg.gms.checkin.LastCheckinInfo\nimport org.microg.gms.common.Constants\nimport org.microg.gms.common.Utils\nimport org.microg.gms.gcm.GMS_NOTS_BASE_URL\nimport org.microg.gms.gcm.GMS_NOTS_OAUTH_SERVICE\nimport org.microg.gms.gcm.createGrpcClient\nimport org.microg.gms.profile.Build\nimport org.microg.gms.profile.Build.VERSION.SDK_INT\nimport org.microg.gms.utils.toBase64\nimport java.util.Locale\nimport java.util.TimeZone\n\nprivate const val TAG = \"ChimeGmsRegistration\"\nprivate const val DEFAULT_TTL = 15_552_000\nprivate const val DEFAULT_CHANNEL_NUMBER = \"-1\"\n\nclass ChimeGmsRegistrationHelper(val context: Context) {\n    private val chimeAccountsStore = context.getSharedPreferences(\"chime_gms_accounts\", Context.MODE_PRIVATE)\n\n    suspend fun handleRegistration(regId: String, reason: RegistrationReason = RegistrationReason.ACCOUNT_CHANGED): List<Account> {\n        Log.d(TAG, \"handle Account Registration regId:$regId\")\n        clearDeletedAccountRegistration()\n        val accounts = AccountManager.get(context).getAccountsByType(AuthConstants.DEFAULT_ACCOUNT_TYPE).filter {\n            val accountRegistration = getAccountRegistration(it.name)\n            accountRegistration == null || accountRegistration.registrationStatus != RegistrationStatus.STATUS_REGISTERED\n        }\n        Log.d(TAG, \"handleRegistration: needRegistration: ${accounts.joinToString(\"|\") { it.name }}\")\n        if (accounts.isEmpty()) return emptyList()\n        val authTokens = withContext(Dispatchers.IO) {\n            accounts.map {\n                val authToken = AccountManager.get(context).blockingGetAuthToken(it, GMS_NOTS_OAUTH_SERVICE, true)\n                Pair(it.name, authToken)\n            }\n        }\n        Log.d(TAG, \"authTokens: $authTokens\")\n        val response = withContext(Dispatchers.IO) {\n            val request = buildRegistrationRequest(authTokens, reason, regId)\n            Log.d(TAG, \"Registration request: ${request.encode().toBase64()}\")\n            val api = createGrpcClient<NotificationsApiServiceClient>(\n                baseUrl = GMS_NOTS_BASE_URL,\n                oauthToken = authTokens.first().second\n            )\n            runCatching { api.MultiLoginUpdate().executeBlocking(request) }.onFailure {\n                Log.d(TAG, \"handleRegistration: failed!\", it)\n            }.getOrNull()\n        }\n        Log.d(TAG, \"Registration response: $response\")\n        if (response == null) return emptyList()\n        accounts.map {\n            val accountId = it.name.hashCode().toString()\n            val result = response.registrationResults.find { data -> accountId == data.id }\n            ChimeGmsAccount(\n                id = accountId,\n                accountName = it.name,\n                representativeTargetId = result?.payload?.representativeTargetId,\n                registrationStatus = if (result?.success == true) RegistrationStatus.STATUS_REGISTERED else RegistrationStatus.STATUS_UNREGISTERED,\n                obfuscatedGaiaId = result?.obfuscatedGaiaId\n            )\n        }.forEach { saveAccountRegistration(it) }\n        Log.d(TAG, \"Registration success : ${accounts.joinToString(\"|\") { it.name }}\")\n        return accounts\n    }\n\n    private fun buildRegistrationRequest(authTokens: List<Pair<String, String?>>, reason: RegistrationReason, gmsRegId: String): RegistrationRequest {\n        val devices = authTokens.map {\n            DeviceRequest.build {\n                id = it.first.hashCode().toString()\n                auth = AuthWrapper.build {\n                    authTokenWrapper = AuthWrapper.AuthToken.build { authToken = it.second }\n                }\n                gmsDeviceContext = buildDeviceContext()\n                ttl = DEFAULT_TTL\n            }\n        }\n        return RegistrationRequest.Builder()\n            .chimeGmsClientId(\"fcm\")\n            .reason(reason)\n            .registrationPayload(buildRegistrationPayload(gmsRegId))\n            .devices(devices)\n            .build()\n    }\n\n    private fun buildRegistrationPayload(gmsRegId: String) =\n        RegistrationPayload.build {\n            channel = Channel.GCM_DEVICE_PUSH\n            appRegistrationContainer = AppRegistrationContainer.build {\n                appRegistration = AppRegistration.build {\n                    packageName = Constants.GMS_PACKAGE_NAME\n                    androidId = LastCheckinInfo.read(context).androidId\n                    regId = gmsRegId\n                }\n            }\n        }\n\n    private fun buildDeviceContext() = GmsDeviceContext.build {\n        languageTag = if (SDK_INT >= 24) LocaleList.getDefault().get(0).toLanguageTag() else Locale.getDefault().language\n        gmsDeviceProfile = GmsDeviceProfile.build {\n            val packageInfo = context.packageManager.getPackageInfo(Constants.GMS_PACKAGE_NAME, 0)\n            density = context.resources.displayMetrics.density\n            versionName = packageInfo.versionName\n            release = Build.VERSION.RELEASE\n            id = Build.ID\n            model = Build.MODEL\n            sdkVersion = SDK_INT\n            manufacturer = Build.MANUFACTURER\n            sdkType = SdkType.RAW_FCM_GMSCORE\n            channelNumber = DEFAULT_CHANNEL_NUMBER\n            deviceModel = \"${Build.BRAND} ${Build.MODEL}\"\n            appBlockState = if (NotificationManagerCompat.from(context).areNotificationsEnabled()) {\n                AppBlockState.ALLOWED\n            } else {\n                AppBlockState.BANNED\n            }\n            deviceCountry = Utils.getLocale(context).country.lowercase()\n            featureBitmapList = FeatureBitmapList(listOf(0x40))\n            deviceType = DeviceType.DEVICE_TYPE_DEFAULT\n        }\n        timeZoneId = TimeZone.getDefault().id\n    }\n\n    private fun saveAccountRegistration(chimeGmsAccount: ChimeGmsAccount) {\n        chimeAccountsStore.edit {\n            putString(chimeGmsAccount.accountName, chimeGmsAccount.toJson())\n        }\n    }\n\n    private fun getAccountRegistration(accountName: String): ChimeGmsAccount? {\n        val json = chimeAccountsStore.getString(accountName, null) ?: return null\n        return ChimeGmsAccount.parseJson(json)\n    }\n\n    private fun clearDeletedAccountRegistration() {\n        val accounts = AccountManager.get(context).getAccountsByType(AuthConstants.DEFAULT_ACCOUNT_TYPE)\n        if (accounts.isEmpty() || chimeAccountsStore.all.isNullOrEmpty()) return\n        chimeAccountsStore.all?.forEach {\n            if (accounts.all { account -> account.name != it.key }) {\n                chimeAccountsStore.edit { remove(it.key) }\n            }\n        }\n    }\n\n    fun resetAllData() {\n        chimeAccountsStore.edit { clear() }\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/googlehelp/GoogleHelpService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.googlehelp\n\nimport android.graphics.Bitmap\nimport android.os.Bundle\nimport android.util.Log\nimport com.google.android.gms.common.Feature\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.internal.ConnectionInfo\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport com.google.android.gms.feedback.FeedbackOptions\nimport com.google.android.gms.googlehelp.GoogleHelp\nimport com.google.android.gms.googlehelp.InProductHelp\nimport com.google.android.gms.googlehelp.SupportRequestHelp\nimport com.google.android.gms.googlehelp.internal.common.IGoogleHelpCallbacks\nimport com.google.android.gms.googlehelp.internal.common.IGoogleHelpService\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.common.PackageUtils\n\nprivate const val TAG = \"GoogleHelp\"\n\nval FEATURES = arrayOf(\n    Feature(\"user_service_support\", 1)\n)\n\nclass GoogleHelpService : BaseService(TAG, GmsService.GOOGLE_HELP) {\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        val packageName = PackageUtils.getAndCheckCallingPackage(this, request.packageName)\n            ?: throw IllegalArgumentException(\"Missing package name\")\n        val binder = GoogleHelpServiceImpl(packageName).asBinder()\n        callback.onPostInitCompleteWithConnectionInfo(CommonStatusCodes.SUCCESS, binder, ConnectionInfo().apply { features = FEATURES })\n    }\n}\n\nclass GoogleHelpServiceImpl(val packageName: String) : IGoogleHelpService.Stub() {\n    override fun processGoogleHelpAndPip(googleHelp: GoogleHelp?, callbacks: IGoogleHelpCallbacks?) {\n        Log.d(TAG, \"Not yet implemented: processGoogleHelpAndPip($googleHelp)\")\n        // Strip error report, can be too big\n        googleHelp?.errorReport = null\n        callbacks?.onProcessGoogleHelpFinished(googleHelp)\n    }\n\n    override fun processGoogleHelpAndPipWithBitmap(googleHelp: GoogleHelp?, bitmap: Bitmap?, callbacks: IGoogleHelpCallbacks?) {\n        processGoogleHelpAndPip(googleHelp, callbacks)\n    }\n\n    override fun saveAsyncHelpPsd(bundle: Bundle?, timestamp: Long, googleHelp: GoogleHelp?, callbacks: IGoogleHelpCallbacks?) {\n        Log.d(TAG, \"Not yet implemented: saveAsyncHelpPsd\")\n        callbacks?.onSaveAsyncPsdFinished()\n    }\n\n    override fun saveAsyncFeedbackPsd(bundle: Bundle?, timestamp: Long, googleHelp: GoogleHelp?, callbacks: IGoogleHelpCallbacks?) {\n        Log.d(TAG, \"Not yet implemented: saveAsyncFeedbackPsd\")\n        callbacks?.onSaveAsyncPsdFinished()\n    }\n\n    override fun saveAsyncFeedbackPsbd(options: FeedbackOptions?, bundle: Bundle?, timestamp: Long, googleHelp: GoogleHelp?, callbacks: IGoogleHelpCallbacks?) {\n        Log.d(TAG, \"Not yet implemented: saveAsyncFeedbackPsbd\")\n        callbacks?.onSaveAsyncPsbdFinished()\n    }\n\n    override fun requestChatSupport(googleHelp: GoogleHelp?, phoneNumber: String?, s2: String?, callbacks: IGoogleHelpCallbacks?) {\n        requestChatSupportWithSupportRequest(SupportRequestHelp().also { it.googleHelp = googleHelp; it.phoneNumber = phoneNumber }, callbacks)\n    }\n\n    override fun requestC2cSupport(googleHelp: GoogleHelp?, phoneNumber: String?, s2: String?, callbacks: IGoogleHelpCallbacks?) {\n        requestC2cSupportWithSupportRequest(SupportRequestHelp().also { it.googleHelp = googleHelp; it.phoneNumber = phoneNumber }, callbacks)\n    }\n\n    override fun getSuggestions(googleHelp: GoogleHelp?, callbacks: IGoogleHelpCallbacks?) {\n        Log.d(TAG, \"Not yet implemented: getSuggestions\")\n        callbacks?.onNoSuggestions()\n    }\n\n    override fun getEscalationOptions(googleHelp: GoogleHelp?, callbacks: IGoogleHelpCallbacks?) {\n        Log.d(TAG, \"Not yet implemented: getEscalationOptions\")\n        callbacks?.onNoEscalationOptions()\n    }\n\n    override fun requestChatSupportWithSupportRequest(supportRequestHelp: SupportRequestHelp?, callbacks: IGoogleHelpCallbacks?) {\n        Log.d(TAG, \"Not yet implemented: requestChatSupport\")\n        callbacks?.onRequestChatSupportFailed()\n    }\n\n    override fun requestC2cSupportWithSupportRequest(supportRequestHelp: SupportRequestHelp?, callbacks: IGoogleHelpCallbacks?) {\n        Log.d(TAG, \"Not yet implemented: requestC2cSupport\")\n        callbacks?.onRequestC2cSupportFailed()\n    }\n\n    override fun processInProductHelpAndPip(inProductHelp: InProductHelp?, bitmap: Bitmap?, callbacks: IGoogleHelpCallbacks?) {\n        Log.d(TAG, \"Not yet implemented: processInProductHelpAndPip\")\n        callbacks?.onProcessInProductHelpFinished(inProductHelp)\n    }\n\n    override fun getRealtimeSupportStatus(googleHelp: GoogleHelp?, callbacks: IGoogleHelpCallbacks?) {\n        Log.d(TAG, \"Not yet implemented: getRealtimeSupportStatus\")\n        callbacks?.onNoRealtimeSupportStatus()\n    }\n\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/googlehelp/ui/GoogleHelpRedirectActivity.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.googlehelp.ui\n\nimport android.content.Intent\nimport android.net.Uri\nimport android.os.Bundle\nimport android.os.Parcel\nimport android.os.Parcelable.Creator\nimport android.util.Log\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.lifecycle.lifecycleScope\nimport com.android.volley.NetworkResponse\nimport com.android.volley.Request\nimport com.android.volley.Response\nimport com.android.volley.VolleyError\nimport com.android.volley.toolbox.Volley\nimport com.google.android.gms.googlehelp.GoogleHelp\nimport com.google.android.gms.googlehelp.InProductHelp\nimport org.microg.gms.googlehelp.CallerAppInfo\nimport org.microg.gms.googlehelp.DeviceInfo\nimport org.microg.gms.googlehelp.RequestBody\nimport org.microg.gms.googlehelp.RequestContent\nimport org.microg.gms.googlehelp.ResponseContentWarp\nimport java.util.Locale\nimport kotlin.coroutines.resume\nimport kotlin.coroutines.resumeWithException\nimport kotlin.coroutines.suspendCoroutine\n\nprivate const val TAG = \"GoogleHelpRedirect\"\nprivate const val PRODUCT_HELP_KEY = \"EXTRA_IN_PRODUCT_HELP\"\n\nprivate const val HELP_URL = \"https://www.google.com/tools/feedback/mobile/help-suggestions\"\n\nclass GoogleHelpRedirectActivity : AppCompatActivity() {\n\n    companion object {\n        const val GOOGLE_HELP_KEY = \"EXTRA_GOOGLE_HELP\"\n        const val KEY_PACKAGE_NAME = \"EXTRA_PACKAGE\"\n    }\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        Log.d(TAG, \"onCreate begin\")\n        if (intent == null) {\n            Log.d(TAG, \"onCreate intent is null\")\n            finish()\n            return\n        }\n        val callingPackage = intent.getStringExtra(KEY_PACKAGE_NAME) ?: callingPackage ?: callingActivity?.packageName ?: return finish()\n        Log.d(TAG, \"onCreate callingPackage: $callingPackage\")\n        val googleHelp = intent.getParcelableExtra<GoogleHelp>(GOOGLE_HELP_KEY)\n        var inProductHelp: InProductHelp? = null\n        if (googleHelp == null) {\n            inProductHelp = getParcelableFromIntent<InProductHelp>(intent, PRODUCT_HELP_KEY, InProductHelp.CREATOR)\n        }\n\n        lifecycleScope.launchWhenCreated {\n            Log.d(TAG, \"onCreate: googleHelp: ${googleHelp ?: inProductHelp?.googleHelp}\")\n            val searchId = googleHelp?.appContext ?: inProductHelp?.googleHelp?.appContext\n            val answerUrl = runCatching { requestHelpLink(callingPackage, searchId).content?.info?.answerUrl }.getOrNull()\n            Log.d(TAG, \"requestHelpLink answerUrl: $answerUrl\")\n            val url = answerUrl ?: googleHelp?.uri?.toString() ?: inProductHelp?.googleHelp?.uri?.toString() ?: return@launchWhenCreated finish()\n            Log.d(TAG, \"Open $url for $callingPackage in Browser\")\n            val targetIntent = Intent(Intent.ACTION_VIEW, Uri.parse(url))\n            val resolveInfoList = packageManager.queryIntentActivities(targetIntent, 0)\n            Log.d(TAG, \"resolveInfoList: $resolveInfoList\")\n            if (resolveInfoList.isNotEmpty()) {\n                startActivity(targetIntent)\n            }\n            finish()\n        }\n    }\n\n    private fun <T> getParcelableFromIntent(intent: Intent, key: String?, creator: Creator<T>): T? {\n        try {\n            val data = intent.getByteArrayExtra(key)\n            if (data != null) {\n                val parcel = Parcel.obtain()\n                parcel.unmarshall(data, 0, data.size)\n                parcel.setDataPosition(0)\n                val result = creator.createFromParcel(parcel)\n                parcel.recycle()\n                return result\n            }\n        } catch (e: Exception) {\n            Log.e(TAG, \"Error deserializing InProductHelp\", e)\n        }\n        return null\n    }\n\n    private suspend fun requestHelpLink(callingPackage: String, searchId: String?) = suspendCoroutine { sus ->\n        Volley.newRequestQueue(this.applicationContext).add(object : Request<ResponseContentWarp>(Method.POST, HELP_URL, {\n            Log.d(TAG, \"requestHelpLink: \", it)\n            sus.resumeWithException(it)\n        }) {\n\n            override fun deliverResponse(response: ResponseContentWarp) {\n                Log.d(TAG, \"requestHelpLink response: $response\")\n                sus.resume(response)\n            }\n\n            override fun getBody(): ByteArray {\n                return RequestContent.Builder().apply {\n                    appInfo = CallerAppInfo.Builder().apply { packageName = callingPackage }.build()\n                    deviceInfo = DeviceInfo.Builder().apply { language = Locale.getDefault().language }.build()\n                    body = RequestBody.Builder().apply { appContext = searchId }.build()\n                }.build().also {\n                    Log.d(TAG, \"requestBody: $it\")\n                }.encode()\n            }\n\n            override fun getBodyContentType(): String = \"application/x-protobuf\"\n\n            override fun parseNetworkResponse(response: NetworkResponse): Response<ResponseContentWarp> {\n                return try {\n                    Response.success(ResponseContentWarp.ADAPTER.decode(response.data), null)\n                } catch (e: Exception) {\n                    Response.error(VolleyError(e))\n                }\n            }\n        })\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/languageprofile/LanguageProfileService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.languageprofile\n\nimport android.os.Bundle\nimport android.util.Log\nimport com.google.android.gms.common.Feature\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.api.internal.IStatusCallback\nimport com.google.android.gms.common.internal.ConnectionInfo\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport com.google.android.gms.languageprofile.ClientLanguageSettings\nimport com.google.android.gms.languageprofile.LanguageFluencyParams\nimport com.google.android.gms.languageprofile.LanguagePreferenceParams\nimport com.google.android.gms.languageprofile.internal.ILanguageProfileCallbacks\nimport com.google.android.gms.languageprofile.internal.ILanguageProfileService\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\n\nprivate const val TAG = \"LanguageProfileService\"\nprivate val FEATURES = arrayOf(\n    Feature(\"get_application_locale_suggestions_api\", 1L),\n    Feature(\"get_language_preferences_for_product_id_api\", 1L),\n    Feature(\"set_language_settings_api\", 1L),\n)\n\nclass LanguageProfileService : BaseService(TAG, GmsService.LANGUAGE_PROFILE) {\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        callback.onPostInitCompleteWithConnectionInfo(CommonStatusCodes.SUCCESS, LanguageProfileServiceImpl(), ConnectionInfo().apply {\n            features = FEATURES\n        })\n    }\n}\n\n\nclass LanguageProfileServiceImpl : ILanguageProfileService.Stub() {\n    override fun fun1(accountName: String?): String? {\n        return null\n    }\n\n    override fun fun2(accountName: String?, callbacks: ILanguageProfileCallbacks?) {\n        Log.d(TAG, \"fun2($accountName)\")\n        callbacks?.onString(Status.SUCCESS, \"ULP not available.\")\n    }\n\n    override fun getLanguagePreferences(\n        accountName: String?,\n        params: LanguagePreferenceParams?,\n        callbacks: ILanguageProfileCallbacks?\n    ) {\n        Log.d(TAG, \"getLanguagePreferences($accountName, $params)\")\n        callbacks?.onLanguagePreferences(Status.SUCCESS, emptyList())\n    }\n\n    override fun getLanguageFluencies(\n        accountName: String?,\n        params: LanguageFluencyParams?,\n        callbacks: ILanguageProfileCallbacks?\n    ) {\n        Log.d(TAG, \"getLanguageFluencies($accountName, $params)\")\n        callbacks?.onLanguageFluencies(Status.SUCCESS, emptyList())\n    }\n\n    override fun getLanguageSettings(\n        accountName: String?,\n        settings: ClientLanguageSettings?,\n        callback: IStatusCallback?\n    ) {\n        Log.d(TAG, \"getLanguageSettings($accountName, $settings)\")\n        callback?.onResult(Status.SUCCESS)\n    }\n\n    override fun removeLanguageSettings(accountName: String?, callback: IStatusCallback?) {\n        Log.d(TAG, \"removeLanguageSettings($accountName)\")\n        callback?.onResult(Status.SUCCESS)\n    }\n\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/measurement/MeasurementService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.measurement\n\nimport android.os.Bundle\nimport android.os.Parcel\nimport android.util.Log\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport com.google.android.gms.measurement.internal.*\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.utils.warnOnTransactionIssues\n\nprivate const val TAG = \"MeasurementService\"\n\nclass MeasurementService : BaseService(TAG, GmsService.MEASUREMENT) {\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        callback.onPostInitComplete(CommonStatusCodes.SUCCESS, MeasurementServiceImpl(), Bundle())\n    }\n}\n\nclass MeasurementServiceImpl : IMeasurementService.Stub() {\n    override fun sendEvent(event: EventParcel, app: AppMetadata) {\n        Log.d(TAG, \"sendEvent($event) for $app\")\n    }\n\n    override fun sendUserProperty(attribute: UserAttributeParcel?, app: AppMetadata) {\n        Log.d(TAG, \"sendUserProperty($attribute) for $app\")\n    }\n\n    override fun sendAppLaunch(app: AppMetadata?) {\n        Log.d(TAG, \"sendAppLaunch() for $app\")\n    }\n\n    override fun sendMeasurementEnabled(app: AppMetadata) {\n        Log.d(TAG, \"sendMeasurementEnabled() for $app\")\n    }\n\n    override fun getAllUserProperties(app: AppMetadata?, includeInternal: Boolean): List<UserAttributeParcel> {\n        Log.d(TAG, \"getAllUserProperties($includeInternal) for $app\")\n        return emptyList()\n    }\n\n    override fun sendCurrentScreen(id: Long, name: String?, referrer: String?, packageName: String?) {\n        Log.d(TAG, \"sendCurrentScreen($id, $name, $referrer, $packageName)\")\n    }\n\n    override fun getAppInstanceId(app: AppMetadata): String? {\n        Log.d(TAG, \"getAppInstanceId() for $app\")\n        return app.ephemeralAppInstanceId ?: app.firebaseInstanceId\n    }\n\n    override fun sendConditionalUserProperty(property: ConditionalUserPropertyParcel, app: AppMetadata) {\n        Log.d(TAG, \"sendConditionalUserProperty($property) for $app\")\n    }\n\n    override fun getUserProperties(origin: String?, propertyNamePrefix: String?, includeInternal: Boolean, app: AppMetadata?): List<UserAttributeParcel> {\n        Log.d(TAG, \"getUserProperties($origin, $propertyNamePrefix, $includeInternal) for $app\")\n        return emptyList()\n    }\n\n    override fun getUserPropertiesAs(packageName: String?, origin: String?, propertyNamePrefix: String?, includeInternal: Boolean): List<UserAttributeParcel> {\n        Log.d(TAG, \"getUserPropertiesAs($packageName, $origin, $propertyNamePrefix, $includeInternal)\")\n        return emptyList()\n    }\n\n    override fun getConditionalUserProperties(origin: String?, propertyNamePrefix: String?, app: AppMetadata?): List<ConditionalUserPropertyParcel> {\n        Log.d(TAG, \"getConditionalUserProperties($origin, $propertyNamePrefix) for $app\")\n        return emptyList()\n    }\n\n    override fun getConditionalUserPropertiesAs(packageName: String?, origin: String?, propertyNamePrefix: String?): List<ConditionalUserPropertyParcel> {\n        Log.d(TAG, \"getConditionalUserPropertiesAs($packageName, $origin, $propertyNamePrefix)\")\n        return emptyList()\n    }\n\n    override fun reset(app: AppMetadata) {\n        Log.d(TAG, \"reset() for $app\")\n    }\n\n    override fun sendDefaultEventParameters(params: Bundle, app: AppMetadata) {\n        Log.d(TAG, \"sendDefaultEventParameters($params) for $app\")\n    }\n\n    override fun sendConsentSettings(app: AppMetadata) {\n        Log.d(TAG, \"sendConsentSettings() for $app\")\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/mlkit/BarcodeScanningActivity.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.mlkit\n\nimport android.Manifest.permission\nimport android.content.Intent\nimport android.content.pm.PackageManager\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.Bundle\nimport android.widget.ImageView\nimport android.widget.TextView\nimport androidx.activity.result.contract.ActivityResultContracts\nimport androidx.appcompat.app.AlertDialog\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.core.content.ContextCompat\nimport androidx.lifecycle.lifecycleScope\nimport com.google.android.gms.R\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableSerializer\nimport org.microg.gms.vision.barcode.QRCodeScannerView\n\nprivate const val KEY_CALLING_APP_NAME = \"extra_calling_app_name\"\nprivate const val KEY_BARCODE_RESULT = \"extra_barcode_result\"\n\nclass BarcodeScanningActivity : AppCompatActivity() {\n\n    private val clientPackageName: String?\n        get() = runCatching {\n            intent?.extras?.takeIf { it.containsKey(KEY_CALLING_APP_NAME) }?.getString(KEY_CALLING_APP_NAME)\n        }.getOrNull()\n\n    private val requestPermissionLauncher =\n        registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted: Boolean ->\n            if (isGranted) {\n                startScanning()\n            } else {\n                showPermissionDialog(clientPackageName)\n            }\n        }\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        if (SDK_INT < 21) {\n            finish()\n            return\n        }\n        setContentView(R.layout.activity_barcode_scanning)\n        findViewById<ImageView>(R.id.barcode_scanning_cancel).setOnClickListener {\n            finish()\n        }\n        if (clientPackageName != null) {\n            findViewById<TextView>(R.id.barcode_scanning_tips).text = String.format(getString(R.string.barcode_scanner_brand), clientPackageName)\n        }\n        if (ContextCompat.checkSelfPermission(this, permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {\n            requestPermissionLauncher.launch(permission.CAMERA)\n        } else {\n            startScanning()\n        }\n    }\n\n    private fun startScanning(){\n        lifecycleScope.launchWhenCreated {\n            if (SDK_INT >= 21) {\n                val scannerView = findViewById<QRCodeScannerView>(R.id.scannerView)\n                scannerView.startScanner { result ->\n                    if (result != null) {\n                        val resultIntent = Intent().apply {\n                            putExtra(KEY_BARCODE_RESULT, SafeParcelableSerializer.serializeToBytes(result))\n                        }\n                        setResult(RESULT_OK, resultIntent)\n                        finish()\n                    }\n                }\n            }\n        }\n    }\n\n    private fun showPermissionDialog(callingApp: String?) {\n        AlertDialog.Builder(this).apply {\n            setTitle(getString(R.string.camera_permission_dialog_title))\n            setMessage(String.format(getString(R.string.camera_permission_dialog_message), callingApp))\n            setPositiveButton(getString(R.string.camera_permission_dialog_button)){ dialog, _ ->\n                dialog.dismiss()\n                finish()\n            }\n        }.show()\n    }\n\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/phenotype/PhenotypeService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.phenotype\n\nimport android.os.Parcel\nimport android.util.Log\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.api.internal.IStatusCallback\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport com.google.android.gms.phenotype.*\nimport com.google.android.gms.phenotype.internal.IPhenotypeCallbacks\nimport com.google.android.gms.phenotype.internal.IPhenotypeService\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.common.PackageUtils\nimport org.microg.gms.utils.warnOnTransactionIssues\n\nprivate const val TAG = \"PhenotypeService\"\n\nclass PhenotypeService : BaseService(TAG, GmsService.PHENOTYPE) {\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest?, service: GmsService?) {\n        val packageName = PackageUtils.getAndCheckCallingPackage(this, request?.packageName)\n        callback.onPostInitComplete(0, PhenotypeServiceImpl(packageName).asBinder(), null)\n    }\n}\n\nprivate val CONFIGURATION_OPTIONS = mapOf(\n    \"com.google.android.apps.search.assistant.mobile.user#com.google.android.googlequicksearchbox\" to arrayOf(\n        // Enable Gemini voice input for all devices\n        Flag(\"45477527\", true, 0),\n        // Enable Gemini AI chat auto-reply\n        Flag(\"45628155\", false, 0),\n        Flag(\"45627469\", true, 0),\n        Flag(\"45627893\", byteArrayOf(0x0A, 0x01, 0x2A), 0),\n        Flag(\"45622089\", true, 0),\n        // Enable Gemini optional models\n        Flag(\"45681308\", true, 0),\n        Flag(\"45688209\", true, 0),\n        Flag(\"45682144\", true, 0),\n        // Enable Gemini sharing and video features\n        Flag(\"45638955\", true, 0),\n        Flag(\"45621205\", true, 0),\n        Flag(\"45616812\", true, 0)\n    ),\n    \"com.google.android.inputmethod.latin#com.google.android.inputmethod.latin\" to arrayOf(\n        // Enable Gboard supports voice input in other languages\n        Flag(\"enable_voice_in_chinese\", true, 0),\n        Flag(\"enable_voice_in_japanese\", true, 0),\n        Flag(\"enable_voice_in_korean\", true, 0),\n        Flag(\"enable_voice_in_handwriting\", true, 0),\n    ),\n    \"com.google.android.libraries.communications.conference.device#com.google.android.apps.tachyon\" to arrayOf(\n        // Enable Google Meet calling using mobile phone number\n        Flag(\"45428442\", true, 0),\n        Flag(\"45620216\", true, 0),\n        // Start a Video Call\n        Flag(\"45692241\", true, 0),\n        Flag(\"45680977\", true, 0),\n        Flag(\"45620220\", true, 0),\n        // Show Audio Call Button\n        Flag(\"45613814\", true, 0),\n        // Show Group Call Button\n        Flag(\"45620498\", true, 0),\n    ),\n    \"com.google.apps_mobile.common.services.gmail.android#com.google.android.gm\" to arrayOf(\n        Flag(\"45661535\", encodeSupportedLanguageList(), 0),\n        Flag(\"45700179\", encodeSupportedLanguageList(), 0)\n    ),\n    \"gmail_android.user#com.google.android.gm\" to arrayOf(\n        Flag(\"45624002\", true, 0),\n        Flag(\"45668769\", true, 0),\n        Flag(\"45633067\", true, 0),\n    ),\n    \"com.google.android.apps.photos\" to arrayOf(\n        Flag(\"45617431\", true, 0),\n    ),\n)\n\nclass PhenotypeServiceImpl(val packageName: String?) : IPhenotypeService.Stub() {\n    override fun register(callbacks: IPhenotypeCallbacks, packageName: String?, version: Int, p3: Array<out String>?, p4: ByteArray?) {\n        Log.d(TAG, \"register($packageName, $version, $p3, $p4)\")\n        callbacks.onRegistered(if (version != 0) Status.SUCCESS else Status.CANCELED)\n    }\n\n    override fun weakRegister(callbacks: IPhenotypeCallbacks, packageName: String?, version: Int, p3: Array<out String>?, p4: IntArray?, p5: ByteArray?) {\n        Log.d(TAG, \"weakRegister($packageName, $version, $p3, $p4, $p5)\")\n        callbacks.onWeakRegistered(Status.SUCCESS)\n    }\n\n    override fun unregister(callbacks: IPhenotypeCallbacks, packageName: String?) {\n        Log.d(TAG, \"unregister($packageName)\")\n        callbacks.onUnregistered(Status.SUCCESS)\n    }\n\n    override fun getConfigurationSnapshot(callbacks: IPhenotypeCallbacks, packageName: String?, user: String?) {\n        getConfigurationSnapshotWithToken(callbacks, packageName, user, null)\n    }\n\n    override fun commitToConfiguration(callbacks: IPhenotypeCallbacks, snapshotToken: String?) {\n        Log.d(TAG, \"commitToConfiguration($snapshotToken)\")\n        callbacks.onCommitedToConfiguration(Status.SUCCESS)\n    }\n\n    override fun getExperimentTokens(callbacks: IPhenotypeCallbacks, packageName: String?, logSourceName: String?) {\n        getExperimentTokensForLogging(callbacks, packageName, logSourceName, null, this.packageName)\n    }\n\n    override fun getDogfoodsToken(callbacks: IPhenotypeCallbacks) {\n        Log.d(TAG, \"getDogfoodsToken()\")\n        callbacks.onDogfoodsToken(Status.SUCCESS, DogfoodsToken())\n    }\n\n    override fun setDogfoodsToken(callbacks: IPhenotypeCallbacks, p1: ByteArray?) {\n        Log.d(TAG, \"setDogfoodsToken($p1)\")\n        callbacks.onDogfoodsTokenSet(Status.SUCCESS)\n    }\n\n    override fun getFlag(callbacks: IPhenotypeCallbacks, packageName: String?, name: String?, type: Int) {\n        Log.d(TAG, \"getFlag($packageName, $name, $type)\")\n        callbacks.onFlag(Status.SUCCESS, null)\n    }\n\n    override fun getCommitedConfiguration(callbacks: IPhenotypeCallbacks, packageName: String?) {\n        Log.d(TAG, \"getCommitedConfiguration($packageName)\")\n        callbacks.onCommittedConfiguration(Status.SUCCESS, configurationsResult())\n    }\n\n    override fun getConfigurationSnapshotWithToken(callbacks: IPhenotypeCallbacks, packageName: String?, user: String?, p3: String?) {\n        Log.d(TAG, \"getConfigurationSnapshotWithToken($packageName, $user, $p3)\")\n        if (packageName in CONFIGURATION_OPTIONS.keys) {\n            callbacks.onConfiguration(Status.SUCCESS, configurationsResult(arrayOf(Configuration().apply {\n                id = 0\n                flags = CONFIGURATION_OPTIONS[packageName]\n                removeNames = emptyArray()\n            })))\n        } else {\n            callbacks.onConfiguration(Status.SUCCESS, configurationsResult())\n        }\n    }\n\n    override fun syncAfterOperation(callbacks: IPhenotypeCallbacks, packageName: String?, version: Long) {\n        Log.d(TAG, \"syncAfterOperation($packageName, $version)\")\n        callbacks.onSyncFinished(Status.SUCCESS, version)\n    }\n\n    override fun registerSync(callbacks: IPhenotypeCallbacks, packageName: String?, version: Int, p3: Array<out String>?, p4: ByteArray?, p5: String?, p6: String?) {\n        Log.d(TAG, \"registerSync($packageName, $version, $p3, $p4, $p5, $p6)\")\n        callbacks.onConfiguration(Status.SUCCESS, configurationsResult())\n    }\n\n    override fun setFlagOverrides(callbacks: IPhenotypeCallbacks, packageName: String?, user: String?, flagName: String?, flagType: Int, flagDataType: Int, flagValue: String?) {\n        Log.d(TAG, \"setFlagOverrides($packageName, $user, $flagName, $flagDataType, $flagType, $flagDataType, $flagValue)\")\n        callbacks.onFlagOverridesSet(Status.SUCCESS)\n    }\n\n    override fun deleteFlagOverrides(callbacks: IPhenotypeCallbacks, packageName: String?, user: String?, flagName: String?) {\n        Log.d(TAG, \"deleteFlagOverrides($packageName, $user, $flagName)\")\n        callbacks.onFlagOverrides(Status.SUCCESS, FlagOverrides())\n    }\n\n    override fun listFlagOverrides(callbacks: IPhenotypeCallbacks, packageName: String?, user: String?, flagName: String?) {\n        Log.d(TAG, \"listFlagOverrides($packageName, $user, $flagName)\")\n        callbacks.onFlagOverrides(Status.SUCCESS, FlagOverrides())\n    }\n\n    override fun clearFlagOverrides(callbacks: IPhenotypeCallbacks, packageName: String?, user: String?) {\n        Log.d(TAG, \"clearFlagOverrides($packageName, $user)\")\n        callbacks.onFlagOverridesSet(Status.SUCCESS)\n    }\n\n    override fun bulkRegister(callbacks: IPhenotypeCallbacks, infos: Array<out RegistrationInfo>?) {\n        Log.d(TAG, \"bulkRegister($infos)\")\n        callbacks.onRegistered(Status.SUCCESS)\n    }\n\n    override fun setAppSpecificProperties(callbacks: IPhenotypeCallbacks, packageName: String?, p2: ByteArray?) {\n        Log.d(TAG, \"setAppSpecificProperties($packageName, $p2)\")\n        callbacks.onAppSpecificPropertiesSet(Status.SUCCESS)\n    }\n\n    override fun getServingVersion(callbacks: IPhenotypeCallbacks) {\n        Log.d(TAG, \"getServingVersion()\")\n        callbacks.onServingVersion(Status.SUCCESS, 1)\n    }\n\n    override fun getExperimentTokensForLogging(callbacks: IPhenotypeCallbacks, packageName: String?, user: String?, p3: String?, clientPackageName: String?) {\n        Log.d(TAG, \"getExperimentTokens($packageName, $user, $p3, $clientPackageName)\")\n        callbacks.onExperimentTokens(Status.SUCCESS, ExperimentTokens().apply {\n            field2 = \"\"\n        })\n    }\n\n    override fun syncAllAfterOperation(callbacks: IPhenotypeCallbacks?, p1: Long) {\n        Log.d(TAG, \"Not yet implemented: syncAllAfterOperation\")\n    }\n\n    override fun setRuntimeProperties(callbacks: IStatusCallback?, p1: String?, p2: ByteArray?) {\n        Log.d(TAG, \"Not yet implemented: setRuntimeProperties\")\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =\n        warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/phenotype/extensions.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.phenotype\n\nimport com.google.android.gms.phenotype.Configuration\nimport com.google.android.gms.phenotype.Configurations\n\nprivate val supportedLanguages = listOf(\n    \"bs\", \"pt\", \"ja\", \"ko\", \"fr\", \"it\", \"de\", \"zh\", \"nl\",\n    \"iw\", \"he\", \"tr\", \"cs\", \"id\", \"in\", \"sv\", \"da\", \"no\",\n    \"nb\", \"pl\", \"vi\", \"th\", \"fi\", \"uk\", \"ar\", \"el\", \"ru\",\n    \"hu\", \"ro\", \"ca\"\n)\n\nfun encodeSupportedLanguageList(): ByteArray {\n    return supportedLanguages.flatMap { lang ->\n        listOf(0x0A.toByte(), 0x02.toByte()) + lang.toByteArray(Charsets.UTF_8).toList()\n    }.toByteArray()\n}\n\nfun configurationsResult(configurations: Array<Configuration> = emptyArray()) = Configurations().apply {\n    serverToken = \"unknown\"\n    snapshotToken = \"unknown\"\n    version = System.currentTimeMillis() / 1000\n    field4 = configurations\n    field5 = false\n    field6 = byteArrayOf()\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/potokens/PoTokenHelper.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.potokens\n\nimport android.content.Context\nimport android.text.TextUtils\nimport android.util.Base64\nimport android.util.Log\nimport com.android.volley.NetworkResponse\nimport com.android.volley.Request\nimport com.android.volley.Response\nimport com.android.volley.VolleyError\nimport com.android.volley.toolbox.RequestFuture\nimport com.android.volley.toolbox.Volley\nimport com.google.android.gms.droidguard.DroidGuard\nimport com.google.android.gms.droidguard.internal.DroidGuardResultsRequest\nimport com.google.android.gms.potokens.CipherKey\nimport com.google.android.gms.potokens.GetPoIntegrityTokenRequest\nimport com.google.android.gms.potokens.GetPoIntegrityTokenResponse\nimport com.google.android.gms.potokens.Key\nimport com.google.android.gms.potokens.KeyData\nimport com.google.android.gms.potokens.KeySet\nimport com.google.android.gms.potokens.PoTokenInfo\nimport com.google.android.gms.potokens.PoTokenResult\nimport com.google.android.gms.potokens.PoTokenResultWrap\nimport com.google.android.gms.tasks.Tasks\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\nimport okio.ByteString.Companion.toByteString\nimport org.microg.gms.common.Constants\nimport org.microg.gms.profile.Build\nimport org.microg.gms.utils.getFirstSignatureDigest\nimport org.microg.gms.utils.singleInstanceOf\nimport java.nio.ByteBuffer\nimport java.security.SecureRandom\nimport java.util.Random\nimport java.util.concurrent.TimeUnit\nimport javax.crypto.Cipher\nimport javax.crypto.spec.IvParameterSpec\nimport javax.crypto.spec.SecretKeySpec\nimport kotlin.math.abs\n\nclass PoTokenHelper(val context: Context) {\n    private var accessTokenLimitCount = 0\n    private var accessTokenLimitIntervalCount = 0\n    private val volleyQueue = singleInstanceOf { Volley.newRequestQueue(context.applicationContext) }\n    private val poTokenStore = singleInstanceOf { PoTokenStore(context.applicationContext) }\n\n    private fun buildKeySet(): KeySet {\n        val keyId = abs(Random().nextInt())\n        val byteString = ByteArray(16).also { SecureRandom().nextBytes(it) }.toByteString()\n        return KeySet(\n            keyId = keyId,\n            keyList = listOf(\n                Key(\n                    data_ = KeyData(\n                        typeUrl = TYPE_URL,\n                        keyMaterialType = 1,\n                        value_ = CipherKey(value_ = byteString)\n                    ),\n                    keyId = keyId,\n                    status = 1,\n                    outputPrefixType = 1,\n                )\n            )\n        )\n    }\n\n    private fun concatCipherIdentifier(keyId: Int, data: ByteArray): ByteArray {\n        val output = ByteArray(5 + data.size)\n        output[0] = 1\n        val identifier = ByteBuffer.allocate(5).put(1.toByte()).putInt(keyId).array()\n        System.arraycopy(identifier, 0, output, 0, identifier.size)\n        System.arraycopy(data, 0, output, identifier.size, data.size)\n        return output\n    }\n\n    private fun aesEncrypt(key: ByteArray?, iv: ByteArray, data: ByteArray): ByteArray {\n        try {\n            val output = ByteArray(data.size + 28)\n            System.arraycopy(iv, 0, output, 0, 12)\n            val keySpec = SecretKeySpec(key, \"AES\")\n            val cipher = Cipher.getInstance(\"AES/GCM/NoPadding\")\n            cipher.init(Cipher.ENCRYPT_MODE, keySpec, IvParameterSpec(iv))\n            cipher.doFinal(data, 0, data.size, output, 12)\n            return output\n        } catch (e: Throwable) {\n            Log.w(TAG, \"PoTokenHelper aesEncrypt exception: $e\")\n        }\n        return ByteArray(0)\n    }\n\n    private fun getDroidGuardResult(\n        context: Context,\n        request: DroidGuardResultsRequest,\n        map: Map<String, String>\n    ): String? {\n        try {\n            val resultTask = DroidGuard.getClient(context).getResults(KEY_TOKEN, map, request)\n            return Tasks.await(resultTask, 15, TimeUnit.SECONDS)\n        } catch (e: Throwable) {\n            Log.w(TAG, \"PoTokenHelper getDroidGuardResult exception: $e\")\n        }\n        return null\n    }\n\n    private fun getPoIntegrityToken(keySet: KeySet): GetPoIntegrityTokenResponse? {\n        try {\n            val droidGuardResultsRequest = DroidGuardResultsRequest().apply {\n                bundle.putByteArray(KEY_FAST, keySet.encode())\n                bundle.putStringArrayList(KEY_FALLBACK, arrayListOf(KEY_FAST))\n            }\n            val randKeyBuf = ByteArray(0x20).also { SecureRandom().nextBytes(it) }\n            val randKey = Base64.encodeToString(randKeyBuf, Base64.NO_WRAP)\n            val map: MutableMap<String, String> = HashMap()\n            map[\"b\"] = randKey\n            val dgResult =\n                getDroidGuardResult(context, droidGuardResultsRequest, map)?.encodeToByteArray()?.toByteString()\n            val tokenRequest =\n                GetPoIntegrityTokenRequest(dgResult = dgResult, dgRandKey = randKeyBuf.toByteString(), mode = 1)\n            return postPoTokenForGms(tokenRequest)\n        } catch (e: Throwable) {\n            Log.w(TAG, \"PoTokenHelper getPoIntegrityToken exception: $e\")\n        }\n        return null\n    }\n\n    private fun postPoTokenForGms(request: GetPoIntegrityTokenRequest): GetPoIntegrityTokenResponse? {\n        val future = RequestFuture.newFuture<GetPoIntegrityTokenResponse>()\n        volleyQueue.add(object : Request<GetPoIntegrityTokenResponse>(\n            Method.POST, PO_INTEGRITY_TOKEN_SERVER_URL, future\n        ) {\n\n            override fun deliverResponse(response: GetPoIntegrityTokenResponse?) {\n                Log.d(TAG, \"PoTokenHelper postPoTokenForGms response: $response\")\n                future.onResponse(response)\n            }\n\n            override fun getHeaders(): Map<String, String> {\n                return mapOf(\"User-Agent\" to \"GmsCore/${Constants.GMS_VERSION_CODE} (${Build.DEVICE} ${Build.ID}); gzip\")\n            }\n\n            override fun getBody(): ByteArray {\n                return request.encode()\n            }\n\n            override fun getBodyContentType(): String = \"application/x-protobuf\"\n\n            override fun parseNetworkResponse(response: NetworkResponse): Response<GetPoIntegrityTokenResponse> {\n                return try {\n                    Response.success(GetPoIntegrityTokenResponse.ADAPTER.decode(response.data), null)\n                } catch (e: Exception) {\n                    Response.error(VolleyError(e))\n                }\n            }\n        })\n        return future.get()\n    }\n\n    suspend fun callPoToken(packageName: String, inputData: ByteArray): ByteArray {\n        var tokenInfo = poTokenStore.loadUsedIntegrityTokenInfo()\n        val lastUpdateTime = poTokenStore.getLastUpdateTime()\n        val flag = poTokenStore.getIntervalFlag()\n        Log.d(TAG, \"callPoToken start lastUpdateTime: $lastUpdateTime\")\n        if (flag || accessTokenLimitIntervalCount > PO_TOKEN_ACCESS_LIMIT_COUNT) {\n            poTokenStore.updateIntervalFlag(true)\n            val intervalTime = System.currentTimeMillis() - lastUpdateTime\n            Log.d(TAG, \"callPoToken run Interval: $intervalTime\")\n            if (intervalTime > PO_TOKEN_ACCESS_INTERVAL_TIME) {\n                poTokenStore.updateIntervalFlag(false)\n                accessTokenLimitIntervalCount = 0\n                tokenInfo = null\n                Log.d(TAG, \"callPoToken run Interval over\")\n            }\n        } else {\n            Log.d(TAG, \"callPoToken run Limit: $accessTokenLimitCount\")\n            if (System.currentTimeMillis() - lastUpdateTime < PO_TOKEN_ACCESS_LIMIT_TIME) {\n                if (accessTokenLimitCount < PO_TOKEN_ACCESS_LIMIT_COUNT) {\n                    accessTokenLimitCount++\n                } else {\n                    accessTokenLimitIntervalCount++\n                    accessTokenLimitCount = 0\n                    tokenInfo = null\n                }\n            } else {\n                accessTokenLimitCount = 0\n            }\n            poTokenStore.updateLastUpdateTime()\n        }\n\n        return try {\n            poTokenStore.buildPoToken(tokenInfo, packageName, inputData)\n        } catch (e: Exception) {\n            Log.d(TAG, \"callPoToken: error: \", e)\n            return PoTokenResultWrap().encode()\n        }\n    }\n\n    suspend fun PoTokenStore.buildPoToken(tokenInfo: IntegrityTokenInfo?, packageName: String, inputData: ByteArray): ByteArray {\n        var tokenDesc: String? = tokenInfo?.token\n        var tokenBackup: String? = tokenInfo?.tokenBackUp\n        var keySetStr: String? = tokenInfo?.key\n\n        val keySet = if (TextUtils.isEmpty(tokenDesc) || TextUtils.isEmpty(tokenBackup) || TextUtils.isEmpty(keySetStr)) {\n            buildKeySet().also {\n                Log.d(TAG, \"buildPoToken postPoTokenForGms start\")\n                val response = withContext(Dispatchers.IO) { getPoIntegrityToken(it) }\n                if (response == null || response.desc == null || response.backup == null) {\n                    throw RuntimeException(\"buildPoToken -> response is null\")\n                }\n                tokenDesc = Base64.encodeToString(response.desc?.toByteArray(), Base64.DEFAULT)\n                tokenBackup = Base64.encodeToString(response.backup?.toByteArray(), Base64.DEFAULT)\n                keySetStr = Base64.encodeToString(it.encode(), Base64.DEFAULT)\n                saveUsedTokenInfo(IntegrityTokenInfo(keySetStr, tokenDesc, tokenBackup, System.currentTimeMillis()))\n                clearOldTokenInfo()\n                Log.d(TAG, \"buildPoToken postPoTokenForGms end\")\n            }\n        } else {\n            val result = Base64.decode(keySetStr, Base64.DEFAULT)\n            Log.d(TAG, \"PoTokenHelper buildPoToken used old keySet\")\n            KeySet.ADAPTER.decode(result)\n        }\n\n        Log.d(TAG, \"buildPoToken: keySetStr: $keySetStr tokenDesc: $tokenDesc tokenBackup: $tokenBackup\")\n        if (TextUtils.isEmpty(tokenDesc) || TextUtils.isEmpty(tokenBackup)) {\n            throw RuntimeException(\"buildPoToken -> tokenDesc or tokenBackup is null\")\n        }\n\n        val poTokenInfoData: ByteArray = PoTokenInfo(\n            inputData = inputData.toByteString(),\n            pkgName = packageName,\n            pkgSignSha256 = context.packageManager.getFirstSignatureDigest(packageName, \"SHA-256\")?.toByteString(),\n            tokenData = Base64.decode(tokenDesc, Base64.DEFAULT).toByteString()\n        ).encode()\n\n        val keyObj: Key = keySet.keyList[0]\n        val keyId: Int? = keyObj.keyId\n        val key: ByteArray? = keyObj.data_?.value_?.value_?.toByteArray()\n        val iv = ByteArray(12).also { SecureRandom().nextBytes(it) }\n\n        var data = aesEncrypt(key, iv, poTokenInfoData)\n        keyId?.let { data = concatCipherIdentifier(it, data) }\n\n        val poTokenResult = PoTokenResult(\n            encryptData = data.toByteString(),\n            tokenData = Base64.decode(tokenBackup, Base64.DEFAULT).toByteString()\n        )\n\n        return PoTokenResultWrap(poTokenResult).encode()\n    }\n\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/potokens/PoTokenStore.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.potokens\n\nimport android.content.Context\nimport android.content.SharedPreferences\n\nclass PoTokenStore(context: Context) {\n\n    private val sp: SharedPreferences =\n        context.getSharedPreferences(\"com.google.android.gms.potokens\", Context.MODE_PRIVATE)\n\n    fun getString(key: String, defValue: String?): String? {\n        return sp.getString(key, defValue)\n    }\n\n    fun getInt(key: String, defValue: Int): Int {\n        return sp.getInt(key, defValue)\n    }\n\n    fun saveUsedTokenInfo(info: IntegrityTokenInfo) {\n        sp.edit().putString(KEY_USED_INTEGRITY_TOKEN_INFO, info.toJsonStr()).apply()\n    }\n\n    fun loadUsedIntegrityTokenInfo(): IntegrityTokenInfo? {\n        var tokenDesc = getString(KEY_DESC, \"\")\n        var tokenBackup = getString(KEY_BACKUP, \"\")\n        var keySetStr = getString(KEY_SET_STR, \"\")\n        return if (tokenDesc.isNullOrEmpty() || tokenBackup.isNullOrEmpty() || keySetStr.isNullOrEmpty()) {\n            val json = sp.getString(KEY_USED_INTEGRITY_TOKEN_INFO, null) ?: return null\n            parseToIntegrityTokenInfo(json)\n        } else{\n            IntegrityTokenInfo(keySetStr, tokenDesc, tokenBackup, System.currentTimeMillis())\n        }\n    }\n\n    fun updateLastUpdateTime() {\n        sp.edit().putLong(KEY_PO_TOKEN_ACCESSED_TIME, System.currentTimeMillis()).apply()\n    }\n\n    fun getLastUpdateTime(): Long {\n        return sp.getLong(KEY_PO_TOKEN_ACCESSED_TIME, 0)\n    }\n\n    fun updateIntervalFlag(flag: Boolean) {\n        sp.edit().putBoolean(KEY_PO_TOKEN_INTERVAL_FLAG, flag).apply()\n    }\n\n    fun getIntervalFlag(): Boolean {\n        return sp.getBoolean(KEY_PO_TOKEN_INTERVAL_FLAG, false)\n    }\n\n    fun clearOldTokenInfo() {\n        if (!sp.contains(KEY_DESC)) {\n            return\n        }\n        val edit = sp.edit()\n        edit.remove(KEY_DESC).apply()\n        edit.remove(KEY_BACKUP).apply()\n        edit.remove(KEY_SET_STR).apply()\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/potokens/PoTokensService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.potokens\n\nimport android.util.Log\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.LifecycleOwner\nimport androidx.lifecycle.lifecycleScope\nimport com.google.android.gms.common.Feature\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.api.internal.IStatusCallback\nimport com.google.android.gms.common.internal.ConnectionInfo\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport com.google.android.gms.potokens.PoToken\nimport com.google.android.gms.potokens.internal.IPoTokensService\nimport com.google.android.gms.potokens.internal.ITokenCallbacks\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.profile.ProfileManager\n\nprivate val FEATURES = arrayOf(Feature(\"PO_TOKENS\", 1))\n\nclass PoTokensService : BaseService(TAG, GmsService.PO_TOKENS) {\n\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        Log.d(TAG, \"PoTokensApiService handleServiceRequest\")\n        ProfileManager.ensureInitialized(this)\n        callback.onPostInitCompleteWithConnectionInfo(\n            CommonStatusCodes.SUCCESS,\n            PoTokensServiceImpl(request.packageName, PoTokenHelper(this), lifecycle),\n            ConnectionInfo().apply { features = FEATURES }\n        )\n    }\n}\n\n\nclass PoTokensServiceImpl(\n    private val packageName: String,\n    private val helper: PoTokenHelper,\n    override val lifecycle: Lifecycle\n) : IPoTokensService.Stub(), LifecycleOwner {\n\n    override fun responseStatus(call: IStatusCallback, code: Int) {\n        Log.e(TAG, \"responseStatus success\")\n        call.onResult(Status.SUCCESS)\n    }\n\n    override fun responseStatusToken(call: ITokenCallbacks, i: Int, bArr: ByteArray) {\n        Log.d(TAG, \"responseStatusToken packageName: $packageName\")\n        lifecycleScope.launchWhenStarted {\n            Log.d(TAG, \"responseStatusToken start\")\n            runCatching {\n                val bytes = helper.callPoToken(packageName, bArr)\n                Log.d(TAG, \"responseStatusToken result: ${bytes.size}\")\n                call.responseToken(Status.SUCCESS, PoToken(bytes))\n            }\n            Log.d(TAG, \"responseStatusToken end\")\n        }\n    }\n\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/potokens/extensions.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.potokens\n\nimport org.json.JSONObject\n\nconst val TAG = \"PoTokens\"\n\nprivate const val GMS_PO_TOKENS_SERVER_URL = \"https://deviceintegritytokens-pa.googleapis.com\"\nprivate const val GMS_PO_TOKENS_API = \"AIzaSyBtL0AK6Hzgr69rQyeyhi-V1lmtsPGZd1M\"\n\nconst val PO_INTEGRITY_TOKEN_SERVER_URL = \"$GMS_PO_TOKENS_SERVER_URL/v1/getPoIntegrityToken?alt=proto&key=$GMS_PO_TOKENS_API\"\n\nconst val TYPE_URL = \"type.googleapis.com/google.crypto.tink.AesGcmKey\"\nconst val KEY_TOKEN = \"po-token-fast\"\nconst val KEY_FAST = \"po-fast-key\"\nconst val KEY_FALLBACK = \"extraKeysRetainedInFallback\"\nconst val KEY_PO_TOKEN_ACCESSED_TIME = \"po_token_access_time\"\nconst val KEY_PO_TOKEN_INTERVAL_FLAG = \"po_token_interval_flag\"\n\nconst val KEY_DESC = \"tokenDesc\"\nconst val KEY_BACKUP = \"tokenBackup\"\nconst val KEY_SET_STR = \"keySetStr\"\nconst val KEY_UPDATE_TIME = \"update_time\"\n\nconst val KEY_USED_INTEGRITY_TOKEN_INFO = \"used_integrity_token_info\"\n\nconst val PO_TOKEN_ACCESS_LIMIT_TIME = 15 * 1000L\nconst val PO_TOKEN_ACCESS_LIMIT_COUNT = 2\n\nconst val PO_TOKEN_ACCESS_INTERVAL_TIME = 6 * 60 * 60 * 1000L // 6 hour\n\ndata class IntegrityTokenInfo(val key: String?, val token: String?, val tokenBackUp: String?, val updateTime: Long) {\n    fun toJsonStr(): String {\n        return JSONObject()\n            .put(KEY_SET_STR, key)\n            .put(KEY_DESC, token)\n            .put(KEY_BACKUP, tokenBackUp)\n            .put(KEY_UPDATE_TIME, updateTime)\n            .toString()\n    }\n\n    override fun toString(): String {\n        return \"IntegrityTokenInfo(key='$key', token='$token', tokenBackUp='$tokenBackUp', updateTime=$updateTime\"\n    }\n}\n\nfun parseToIntegrityTokenInfo(json: String): IntegrityTokenInfo {\n    val jsonObject = JSONObject(json)\n    return IntegrityTokenInfo(\n        jsonObject.optString(KEY_SET_STR),\n        jsonObject.optString(KEY_DESC),\n        jsonObject.optString(KEY_BACKUP),\n        jsonObject.optLong(KEY_UPDATE_TIME)\n    )\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/provision/ProvisionService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.provision\n\nimport android.app.Service\nimport android.content.Intent\nimport android.os.Bundle\nimport android.util.Log\nimport androidx.lifecycle.LifecycleService\nimport androidx.lifecycle.lifecycleScope\nimport kotlinx.coroutines.delay\nimport org.microg.gms.checkin.getCheckinServiceInfo\nimport org.microg.gms.checkin.setCheckinServiceConfiguration\nimport org.microg.gms.droidguard.core.DroidGuardPreferences\nimport org.microg.gms.gcm.getGcmServiceInfo\nimport org.microg.gms.gcm.setGcmServiceConfiguration\nimport org.microg.gms.location.LocationSettings\nimport org.microg.gms.safetynet.SafetyNetPreferences\n\nclass ProvisionService : LifecycleService() {\n    private fun Bundle.getBooleanOrNull(key: String): Boolean? {\n        return if (containsKey(key)) getBoolean(key) else null\n    }\n\n    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {\n        super.onStartCommand(intent, flags, startId)\n        lifecycleScope.launchWhenStarted {\n            intent?.extras?.let {\n                val s = it.keySet().map { key -> \"$key = ${it[key]}\" }.joinToString(\", \")\n                Log.d(TAG, \"Provisioning: $s\")\n            }\n\n            intent?.extras?.getBooleanOrNull(\"checkin_enabled\")?.let { setCheckinServiceConfiguration(this@ProvisionService, getCheckinServiceInfo(this@ProvisionService).configuration.copy(enabled = it)) }\n            intent?.extras?.getBooleanOrNull(\"gcm_enabled\")?.let { setGcmServiceConfiguration(this@ProvisionService, getGcmServiceInfo(this@ProvisionService).configuration.copy(enabled = it)) }\n            intent?.extras?.getBooleanOrNull(\"safetynet_enabled\")?.let {\n                SafetyNetPreferences.setEnabled(this@ProvisionService, it)\n                DroidGuardPreferences.setEnabled(this@ProvisionService, it)\n            }\n            LocationSettings(this@ProvisionService).apply {\n                intent?.extras?.getBooleanOrNull(\"wifi_mls\")?.let { wifiIchnaea = it }\n                intent?.extras?.getBooleanOrNull(\"wifi_ichnaea\")?.let { wifiIchnaea = it }\n                intent?.extras?.getBooleanOrNull(\"cell_mls\")?.let { cellIchnaea = it }\n                intent?.extras?.getBooleanOrNull(\"cell_ichnaea\")?.let { cellIchnaea = it }\n                intent?.extras?.getString(\"ichnaea_endpoint\")?.let { customEndpoint = it }\n                intent?.extras?.getBooleanOrNull(\"ichnaea_contribute\")?.let { ichnaeaContribute = it }\n                intent?.extras?.getBooleanOrNull(\"wifi_learning\")?.let { wifiLearning = it }\n                intent?.extras?.getBooleanOrNull(\"cell_learning\")?.let { cellLearning = it }\n                intent?.extras?.getBooleanOrNull(\"wifi_moving\")?.let { wifiMoving = it }\n                intent?.extras?.getBooleanOrNull(\"nominatim_enabled\")?.let {\n                    geocoderNominatim = it\n                }\n            }\n            // What else?\n\n            delay(2 * 1000) // Wait 2 seconds to give provisioning some extra time\n            stopSelfResult(startId)\n        }\n        return Service.START_NOT_STICKY\n    }\n\n    companion object {\n        private const val TAG = \"GmsProvision\"\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/pseudonymous/PseudonymousIdService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.pseudonymous\n\nimport android.util.Log\nimport com.google.android.gms.common.Feature\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.internal.ConnectionInfo\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport com.google.android.gms.pseudonymous.PseudonymousIdToken\nimport com.google.android.gms.pseudonymous.internal.IPseudonymousIdCallbacks\nimport com.google.android.gms.pseudonymous.internal.IPseudonymousIdService\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\n\nprivate const val TAG = \"PseudonymousIdService\"\nprivate val FEATURES = arrayOf(Feature(\"get_last_reset_time_api\", 1L))\n\nclass PseudonymousIdService : BaseService(TAG, GmsService.PSEUDONYMOUS_ID) {\n\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        callback.onPostInitCompleteWithConnectionInfo(\n            CommonStatusCodes.SUCCESS,\n            PseudonymousIdServiceImpl().asBinder(),\n            ConnectionInfo().apply { features = FEATURES }\n        )\n    }\n}\n\nclass PseudonymousIdServiceImpl : IPseudonymousIdService.Stub() {\n\n    override fun getToken(call: IPseudonymousIdCallbacks) {\n        Log.d(TAG, \"getToken is called\")\n        call.onGetTokenResponse(Status.SUCCESS, PseudonymousIdToken(null))\n    }\n\n    override fun setToken(call: IPseudonymousIdCallbacks, token: PseudonymousIdToken?) {\n        Log.d(TAG, \"setToken is called\")\n        call.onSetTokenResponse(Status.SUCCESS)\n    }\n\n    override fun getLastResetWallTimeMs(callbacks: IPseudonymousIdCallbacks?) {\n        Log.d(TAG, \"Not yet implemented: getLastResetWallTimeMs\")\n    }\n\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/signin/SignInService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.signin\n\nimport android.accounts.Account\nimport android.accounts.AccountManager\nimport android.content.Context\nimport android.os.Bundle\nimport android.os.Parcel\nimport android.util.Log\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.LifecycleOwner\nimport androidx.lifecycle.lifecycleScope\nimport com.google.android.gms.common.ConnectionResult\nimport com.google.android.gms.common.Scopes\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.api.Scope\nimport com.google.android.gms.common.internal.*\nimport com.google.android.gms.signin.internal.*\nimport org.microg.gms.BaseService\nimport org.microg.gms.auth.AuthConstants\nimport org.microg.gms.auth.signin.SignInConfigurationService\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.common.PackageUtils\nimport org.microg.gms.games.GamesConfigurationService\nimport org.microg.gms.utils.warnOnTransactionIssues\n\nprivate const val TAG = \"SignInService\"\n\nclass SignInService : BaseService(TAG, GmsService.SIGN_IN) {\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        val packageName = PackageUtils.getAndCheckCallingPackage(this, request.packageName)\n            ?: throw IllegalArgumentException(\"Missing package name\")\n        val binder = SignInServiceImpl(this, lifecycle, packageName, request.scopes).asBinder()\n        callback.onPostInitComplete(CommonStatusCodes.SUCCESS, binder, Bundle())\n    }\n}\n\nclass SignInServiceImpl(val context: Context, override val lifecycle: Lifecycle, val packageName: String, val scopes: Array<Scope>) : ISignInService.Stub(),\n    LifecycleOwner {\n\n    override fun clearAccountFromSessionStore(sessionId: Int) {\n        Log.d(TAG, \"Not yet implemented: clearAccountFromSessionStore $sessionId\")\n    }\n\n    override fun putAccount(sessionId: Int, account: Account?, callbacks: ISignInCallbacks?) {\n        Log.d(TAG, \"Not yet implemented: putAccount\")\n    }\n\n    override fun saveDefaultAccount(accountAccessor: IAccountAccessor?, sessionId: Int, crossClient: Boolean) {\n        Log.d(TAG, \"Not yet implemented: saveDefaultAccount $sessionId $crossClient\")\n    }\n\n    override fun saveConsent(request: RecordConsentRequest?, callbacks: ISignInCallbacks?) {\n        Log.d(TAG, \"Not yet implemented: saveConsent\")\n    }\n\n    override fun getCurrentAccount(callbacks: ISignInCallbacks?) {\n        Log.d(TAG, \"Not yet implemented: getCurrentAccount\")\n    }\n\n    override fun signIn(request: SignInRequest?, callbacks: ISignInCallbacks?) {\n        Log.d(TAG, \"signIn($request)\")\n        runCatching {\n            lifecycleScope.launchWhenStarted {\n                val defaultAccount = if (scopes.any { it.scopeUri.contains(Scopes.GAMES) }) {\n                    GamesConfigurationService.getDefaultAccount(context, packageName)\n                } else {\n                    SignInConfigurationService.getDefaultAccount(context, packageName)\n                }\n                val accountManager = AccountManager.get(context)\n                val account = request?.request?.account?.let { if (it.name == AuthConstants.DEFAULT_ACCOUNT) defaultAccount else it }\n                val result = if (account == null || !accountManager.getAccountsByType(account.type).contains(account)){\n                    ConnectionResult(ConnectionResult.SIGN_IN_REQUIRED)\n                } else if (defaultAccount != null && account.name != defaultAccount.name) {\n                    ConnectionResult(ConnectionResult.INVALID_ACCOUNT)\n                } else ConnectionResult(ConnectionResult.SUCCESS)\n                Log.d(TAG, \"signIn: account -> ${account?.name} result: ${result.errorMessage}\")\n                callbacks?.onSignIn(SignInResponse().apply {\n                    connectionResult = result\n                    response = ResolveAccountResponse().apply {\n                        connectionResult = result\n                        if (account != null) {\n                            accountAccessor = object : IAccountAccessor.Stub() {\n                                override fun getAccount(): Account {\n                                    return account\n                                }\n                            }\n                        }\n                    }\n                })\n            }\n        }\n//        fun sendError() {\n//            runCatching {\n//                callbacks?.onSignIn(SignInResponse().apply {\n//                    connectionResult = ConnectionResult(ConnectionResult.INTERNAL_ERROR)\n//                    response = ResolveAccountResponse().apply {\n//                        connectionResult = ConnectionResult(ConnectionResult.INTERNAL_ERROR)\n//                    }\n//                })\n//            }\n//        }\n//        Log.d(TAG, \"Not yet implemented: signIn $request with $scopes\")\n//        val account = request?.request?.account ?: return sendError()\n//        val authManager = AuthManager(context, account.name, packageName, \"oauth2:${scopes.joinToString(\" \") { it.scopeUri }}\")\n//        authManager.setItCaveatTypes(\"2\")\n//        if (!authManager.isPermitted && !AuthPrefs.isTrustGooglePermitted(context)) return sendError()\n//        lifecycleScope.launchWhenStarted {\n//            val authResponse = withContext(Dispatchers.IO) {\n//                authManager.requestAuth(true)\n//            }\n//            if (authResponse.auths == null) return@launchWhenStarted sendError()\n//            runCatching {\n//                callbacks?.onSignIn(SignInResponse().apply {\n//                    connectionResult = ConnectionResult(ConnectionResult.SUCCESS)\n//                    response = ResolveAccountResponse().apply {\n//                        connectionResult = ConnectionResult(ConnectionResult.SUCCESS)\n//                    }\n//                })\n//            }\n//        }\n    }\n\n    override fun setGamesHasBeenGreeted(hasGreeted: Boolean) {\n        Log.d(TAG, \"Not yet implemented: setGamesHasBeenGreeted\")\n    }\n\n    override fun recordConsentByConsentResult(request: RecordConsentByConsentResultRequest?, callbacks: ISignInCallbacks?) {\n        Log.d(TAG, \"Not yet implemented: recordConsentByConsentResult\")\n    }\n\n    override fun authAccount(request: AuthAccountRequest?, callbacks: ISignInCallbacks?) {\n        Log.d(TAG, \"Not yet implemented: authAccount\")\n    }\n\n    override fun onCheckServerAuthorization(result: CheckServerAuthResult?) {\n        Log.d(TAG, \"Not yet implemented: onCheckServerAuthorization\")\n    }\n\n    override fun onUploadServerAuthCode(sessionId: Int) {\n        Log.d(TAG, \"Not yet implemented: onUploadServerAuthCode\")\n    }\n\n    override fun resolveAccount(request: ResolveAccountRequest?, callbacks: IResolveAccountCallbacks?) {\n        Log.d(TAG, \"Not yet implemented: resolveAccount\")\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =\n        warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/udc/ActivityControlSettings.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.udc\n\nprivate enum class Controls(val id: Int) {\n    APP_USAGE_TIME(1),\n    SCREEN_TIME_LIMIT(2),\n    APP_INSTALL(3),\n    IN_APP_PURCHASE(4),\n    LOCATION_SHARING(5),\n    CALL_LOG(6),\n    CONTACT(9),\n    CALENDAR(10),\n    CAMERA(15),\n    MICROPHONE(17),\n    STORAGE(18),\n    NOTIFICATION(44),\n    ACCESSIBILITY_SERVICE(45),\n    DEVICE_ADMIN(46),\n    SYSTEM_WINDOW_OVERLAY(48),\n    SYSTEM_ALERT_WINDOW(61),\n    FLOATING_WINDOW(80),\n    PICTURE_IN_PICTURE(94),\n    SYSTEM_UI_VISIBILITY(95),\n    BACKGROUND_APP_RESTRICTION(101),\n    BATTERY_OPTIMIZATION(102)\n}\n\nprivate val ALLOW_CONTROLS_PACKAGES = mapOf(\n    Pair(\"com.google.android.googlequicksearchbox\", setOf(Controls.STORAGE, Controls.MICROPHONE, Controls.SYSTEM_WINDOW_OVERLAY)),\n)\n\nfun getAllowControlsByPackage(packageName: String) : ByteArray? {\n    val controls = ALLOW_CONTROLS_PACKAGES[packageName] ?: return null\n    return ActivityControlsSettings.build {\n        items(controls.map { controls -> ActivityControlItem(controls.id, 1, 1, 1) })\n        global(GlobalSettings(1, 1))\n    }.encode()\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/udc/FacsCacheService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.udc\n\nimport android.content.Context\nimport android.os.Parcel\nimport android.util.Log\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport com.google.android.gms.facs.cache.FacsCacheCallOptions\nimport com.google.android.gms.facs.cache.GetActivityControlsSettingsResult\nimport com.google.android.gms.facs.cache.internal.IFacsCacheCallbacks\nimport com.google.android.gms.facs.cache.internal.IFacsCacheService\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.common.PackageUtils\nimport org.microg.gms.utils.warnOnTransactionIssues\n\nprivate const val TAG = \"GmsFacsCache\"\n\nclass FacsCacheService : BaseService(TAG, GmsService.FACS_CACHE) {\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest?, service: GmsService?) {\n        Log.d(TAG, \"handleServiceRequest request=${request} \")\n        val packageName = PackageUtils.getAndCheckCallingPackage(this, request?.packageName)\n            ?: throw IllegalArgumentException(\"Missing package name\")\n        callback.onPostInitComplete(0, FacsCacheServiceImpl(this, packageName).asBinder(), null)\n    }\n}\n\nclass FacsCacheServiceImpl(val context: Context, val packageName: String) : IFacsCacheService.Stub() {\n\n    override fun forceSettingsCacheRefresh(callbacks: IFacsCacheCallbacks, options: FacsCacheCallOptions) {\n        Log.d(TAG, \"forceSettingsCacheRefresh\")\n        callbacks.onForceSettingsCacheRefreshResult(Status.CANCELED, null)\n    }\n\n    override fun updateActivityControlsSettings(callbacks: IFacsCacheCallbacks, bytes: ByteArray, options: FacsCacheCallOptions) {\n        Log.d(TAG, \"updateActivityControlsSettings\")\n        callbacks.onUpdateActivityControlsSettingsResult(Status.CANCELED, null)\n    }\n\n    override fun getActivityControlsSettings(callbacks: IFacsCacheCallbacks, options: FacsCacheCallOptions) {\n        Log.d(TAG, \"getActivityControlsSettings requestPackageName: $packageName, options: $options\")\n        getAllowControlsByPackage(packageName)?.let {\n            callbacks.onGetActivityControlsSettingsResult(Status.SUCCESS, GetActivityControlsSettingsResult(it))\n        } ?: callbacks.onGetActivityControlsSettingsResult(Status.CANCELED, null)\n    }\n\n    override fun readDeviceLevelSettings(callbacks: IFacsCacheCallbacks) {\n        Log.d(TAG, \"readDeviceLevelSettings\")\n        callbacks.onReadDeviceLevelSettingsResult(Status.CANCELED, null)\n    }\n\n    override fun writeDeviceLevelSettings(callbacks: IFacsCacheCallbacks, bytes: ByteArray) {\n        Log.d(TAG, \"writeDeviceLevelSettings\")\n        callbacks.onWriteDeviceLevelSettingsResult(Status.CANCELED)\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/ui/AccountsFragment.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.ui\n\nimport android.accounts.Account\nimport android.accounts.AccountManager\nimport android.content.Intent\nimport android.graphics.Bitmap\nimport android.os.Bundle\nimport android.provider.Settings\nimport android.view.Menu\nimport android.view.MenuInflater\nimport android.view.MenuItem\nimport androidx.core.graphics.drawable.RoundedBitmapDrawableFactory\nimport androidx.lifecycle.lifecycleScope\nimport androidx.navigation.fragment.findNavController\nimport androidx.preference.Preference\nimport androidx.preference.PreferenceCategory\nimport androidx.preference.PreferenceFragmentCompat\nimport androidx.preference.TwoStatePreference\nimport com.google.android.gms.R\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\nimport org.microg.gms.auth.AuthConstants\nimport org.microg.gms.common.Constants\nimport org.microg.gms.gcm.ACTION_GCM_CONNECTED\nimport org.microg.gms.gcm.ACTION_GCM_REGISTER_ALL_ACCOUNTS\nimport org.microg.gms.people.DatabaseHelper\nimport org.microg.gms.people.PeopleManager\nimport org.microg.gms.settings.SettingsContract\nimport org.microg.gms.settings.SettingsContract.Auth\n\nconst val PREF_ACCOUNTS_NONE = \"pref_current_accounts_none\"\nconst val PREF_ACCOUNTS_ADD = \"pref_current_accounts_add\"\nconst val PREFCAT_ACCOUNTS = \"prefcat_current_accounts\"\nval TWO_STATE_SETTINGS = listOf(\n    Auth.TRUST_GOOGLE,\n    Auth.VISIBLE,\n    Auth.INCLUDE_ANDROID_ID,\n    Auth.STRIP_DEVICE_NAME,\n    Auth.TWO_STEP_VERIFICATION,\n)\n\nclass AccountsFragment : PreferenceFragmentCompat() {\n\n    // TODO: This should use some better means of accessing the database\n    private fun getDisplayName(account: Account): String? {\n        val databaseHelper = DatabaseHelper(context)\n        val cursor = databaseHelper.getOwner(account.name)\n        return try {\n            if (cursor.moveToNext()) {\n                cursor.getColumnIndex(\"display_name\").takeIf { it >= 0 }?.let { cursor.getString(it) }.takeIf { !it.isNullOrBlank() }\n            } else null\n        } finally {\n            cursor.close()\n            databaseHelper.close()\n        }\n    }\n\n    private fun getCircleBitmapDrawable(bitmap: Bitmap?) =\n        if (bitmap != null) RoundedBitmapDrawableFactory.create(resources, bitmap.let {\n            Bitmap.createScaledBitmap(bitmap, 100, 100, true)\n        }).also { it.isCircular = true } else null\n\n    private fun registerGcmInGms() {\n        Intent(ACTION_GCM_REGISTER_ALL_ACCOUNTS).apply {\n            `package` = Constants.GMS_PACKAGE_NAME\n        }.let { requireContext().sendBroadcast(it) }\n    }\n\n    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {\n        addPreferencesFromResource(R.xml.preferences_accounts)\n        updateSettings()\n        for (setting in TWO_STATE_SETTINGS) {\n            findPreference<TwoStatePreference>(setting)?.setOnPreferenceChangeListener { preference, newValue ->\n                if (newValue is Boolean && preference.key in TWO_STATE_SETTINGS) {\n                    SettingsContract.setSettings(requireContext(), Auth.getContentUri(requireContext())) { put(preference.key, newValue) }\n                    updateSettings()\n                    if (preference.key == Auth.TWO_STEP_VERIFICATION && newValue) registerGcmInGms()\n                    true\n                } else false\n            }\n        }\n    }\n\n    override fun onResume() {\n        super.onResume()\n        updateSettings()\n    }\n\n    private fun updateSettings() {\n        val context = requireContext()\n\n        val accountManager = AccountManager.get(context)\n        val accounts = accountManager.getAccountsByType(AuthConstants.DEFAULT_ACCOUNT_TYPE)\n\n        findPreference<Preference>(PREF_ACCOUNTS_NONE)?.isVisible = accounts.isEmpty()\n        val preferenceCategory = findPreference<PreferenceCategory>(PREFCAT_ACCOUNTS) ?: return\n        // Keep the add and none\n        while (preferenceCategory.preferenceCount > 2) {\n            preferenceCategory.removePreference(preferenceCategory.getPreference(0))\n        }\n        accounts.map { account ->\n            val photo = PeopleManager.getOwnerAvatarBitmap(context, account.name, false)\n            val preference = Preference(context).apply {\n                title = getDisplayName(account)\n                summary = account.name\n                icon = getCircleBitmapDrawable(photo)\n                key = \"account:${account.name}\"\n                order = 0\n                if (photo == null) {\n                    lifecycleScope.launchWhenStarted {\n                        withContext(Dispatchers.IO) {\n                            PeopleManager.getOwnerAvatarBitmap(context, account.name, true)\n                        }?.let { icon = getCircleBitmapDrawable(it) }\n                    }\n                }\n                setOnPreferenceClickListener {\n                    startActivity(Intent(Settings.ACTION_SYNC_SETTINGS).apply {\n                        putExtra(Settings.EXTRA_ACCOUNT_TYPES, arrayOf(AuthConstants.DEFAULT_ACCOUNT_TYPE))\n                    })\n                    false\n                }\n            }\n            preference\n        }.sorted().forEach { preferenceCategory.addPreference(it) }\n\n        for (setting in TWO_STATE_SETTINGS) {\n            findPreference<TwoStatePreference>(setting)?.isChecked =\n                SettingsContract.getSettings(context, Auth.getContentUri(context), arrayOf(setting)) { c -> c.getInt(0) != 0 }\n        }\n    }\n\n    init {\n        setHasOptionsMenu(true)\n    }\n\n    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {\n        menu.add(0, MENU_GAMES_MANAGED, 0, org.microg.gms.base.core.R.string.menu_game_managed)\n        super.onCreateOptionsMenu(menu, inflater)\n    }\n\n    override fun onOptionsItemSelected(item: MenuItem): Boolean {\n        return when (item.itemId) {\n            MENU_GAMES_MANAGED -> {\n                findNavController().navigate(requireContext(), R.id.openGameManagerSettings)\n                true\n            }\n\n            else -> super.onOptionsItemSelected(item)\n        }\n    }\n\n    companion object {\n        private const val MENU_GAMES_MANAGED = Menu.FIRST\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/ui/DeviceRegistrationFragment.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.ui\n\nimport android.annotation.SuppressLint\nimport android.net.Uri\nimport android.os.Bundle\nimport android.os.Handler\nimport android.text.format.DateUtils\nimport android.util.Log\nimport androidx.activity.result.ActivityResultLauncher\nimport androidx.activity.result.contract.ActivityResultContracts\nimport androidx.lifecycle.lifecycleScope\nimport androidx.preference.ListPreference\nimport androidx.preference.Preference\nimport androidx.preference.PreferenceCategory\nimport androidx.preference.PreferenceFragmentCompat\nimport com.google.android.gms.R\nimport org.microg.gms.checkin.CheckinPreferences\nimport org.microg.gms.checkin.getCheckinServiceInfo\nimport org.microg.gms.profile.ProfileManager\nimport org.microg.gms.profile.ProfileManager.PROFILE_AUTO\nimport org.microg.gms.profile.ProfileManager.PROFILE_NATIVE\nimport org.microg.gms.profile.ProfileManager.PROFILE_REAL\nimport org.microg.gms.profile.ProfileManager.PROFILE_SYSTEM\nimport org.microg.gms.profile.ProfileManager.PROFILE_USER\nimport java.io.File\nimport java.io.FileOutputStream\n\nclass DeviceRegistrationFragment : PreferenceFragmentCompat() {\n    private lateinit var switchBarPreference: SwitchBarPreference\n    private lateinit var deviceProfile: ListPreference\n    private lateinit var importProfile: Preference\n    private lateinit var serial: Preference\n    private lateinit var statusCategory: PreferenceCategory\n    private lateinit var status: Preference\n    private lateinit var androidId: Preference\n    private val handler = Handler()\n    private val updateRunnable = Runnable { updateStatus() }\n    private lateinit var profileFileImport: ActivityResultLauncher<String>\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        profileFileImport = registerForActivityResult(ActivityResultContracts.GetContent(), this::onFileSelected)\n    }\n\n    private fun onFileSelected(uri: Uri?) {\n        if (uri == null) return\n        try {\n            val context = requireContext()\n            val file = File.createTempFile(\"profile_\", \".xml\", context.cacheDir)\n            context.contentResolver.openInputStream(uri)?.use { inputStream ->\n                FileOutputStream(file).use { inputStream.copyTo(it) }\n            }\n            val success = ProfileManager.importUserProfile(context, file)\n            file.delete()\n            if (success && ProfileManager.isAutoProfile(context, PROFILE_USER)) {\n                ProfileManager.setProfile(context, PROFILE_USER)\n            }\n            updateStatus()\n        } catch (e: Exception) {\n            Log.w(TAG, e)\n        }\n    }\n\n    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {\n        addPreferencesFromResource(R.xml.preferences_device_registration)\n    }\n\n    @SuppressLint(\"RestrictedApi\")\n    override fun onBindPreferences() {\n        switchBarPreference = preferenceScreen.findPreference(\"pref_checkin_enabled\") ?: switchBarPreference\n        deviceProfile = preferenceScreen.findPreference(\"pref_device_profile\") ?: deviceProfile\n        importProfile = preferenceScreen.findPreference(\"pref_device_profile_import\") ?: importProfile\n        serial = preferenceScreen.findPreference(\"pref_device_serial\") ?: serial\n        statusCategory = preferenceScreen.findPreference(\"prefcat_device_registration_status\") ?: statusCategory\n        status = preferenceScreen.findPreference(\"pref_device_registration_status\") ?: status\n        androidId = preferenceScreen.findPreference(\"pref_device_registration_android_id\") ?: androidId\n\n        deviceProfile.setOnPreferenceChangeListener { _, newValue ->\n            ProfileManager.setProfile(requireContext(), newValue as String? ?: PROFILE_AUTO)\n            updateStatus()\n            true\n        }\n        importProfile.setOnPreferenceClickListener {\n            profileFileImport.launch(\"text/xml\")\n            true\n        }\n        switchBarPreference.setOnPreferenceChangeListener { _, newValue ->\n            val newStatus = newValue as Boolean\n            CheckinPreferences.setEnabled(requireContext(), newStatus)\n            true\n        }\n    }\n\n    private fun configureProfilePreference() {\n        val context = requireContext()\n        val configuredProfile = ProfileManager.getConfiguredProfile(context)\n        val autoProfile = ProfileManager.getAutoProfile(context)\n        val autoProfileName = when (autoProfile) {\n            PROFILE_NATIVE -> getString(R.string.profile_name_native)\n            PROFILE_REAL -> getString(R.string.profile_name_real)\n            else -> ProfileManager.getProfileName(context, autoProfile)\n        }\n        val profiles =\n            mutableListOf(PROFILE_AUTO, PROFILE_NATIVE, PROFILE_REAL)\n        val profileNames = mutableListOf(getString(R.string.profile_name_auto, autoProfileName), getString(R.string.profile_name_native), getString(R.string.profile_name_real))\n        if (ProfileManager.hasProfile(context, PROFILE_SYSTEM)) {\n            profiles.add(PROFILE_SYSTEM)\n            profileNames.add(getString(R.string.profile_name_system, ProfileManager.getProfileName(context, PROFILE_SYSTEM)))\n        }\n        if (ProfileManager.hasProfile(context, PROFILE_USER)) {\n            profiles.add(PROFILE_USER)\n            profileNames.add(getString(R.string.profile_name_user, ProfileManager.getProfileName(context, PROFILE_USER)))\n        }\n        for (profile in R.xml::class.java.declaredFields.map { it.name }\n            .filter { it.startsWith(\"profile_\") }\n            .map { it.substring(8) }\n            .sorted()) {\n            val profileName = ProfileManager.getProfileName(context, profile)\n            if (profileName != null) {\n                profiles.add(profile)\n                profileNames.add(profileName)\n            }\n        }\n        deviceProfile.entryValues = profiles.toTypedArray()\n        deviceProfile.entries = profileNames.toTypedArray()\n        deviceProfile.value = configuredProfile\n        deviceProfile.summary =\n            profiles.indexOf(configuredProfile).takeIf { it >= 0 }?.let { profileNames[it] } ?: \"Unknown\"\n    }\n\n    override fun onResume() {\n        super.onResume()\n\n        switchBarPreference.isChecked = CheckinPreferences.isEnabled(requireContext())\n\n        updateStatus()\n    }\n\n    override fun onPause() {\n        super.onPause()\n        handler.removeCallbacks(updateRunnable)\n    }\n\n    private fun updateStatus() {\n        handler.removeCallbacks(updateRunnable)\n        handler.postDelayed(updateRunnable, UPDATE_INTERVAL)\n        val appContext = requireContext().applicationContext\n        lifecycleScope.launchWhenResumed {\n            configureProfilePreference()\n            serial.summary = ProfileManager.getSerial(appContext)\n            val serviceInfo = getCheckinServiceInfo(appContext)\n            statusCategory.isVisible = serviceInfo.configuration.enabled\n            if (serviceInfo.lastCheckin > 0) {\n                status.summary = getString(\n                    R.string.checkin_last_registration,\n                    DateUtils.getRelativeTimeSpanString(serviceInfo.lastCheckin, System.currentTimeMillis(), 0)\n                )\n                androidId.isVisible = true\n                androidId.summary = serviceInfo.androidId.toString(16)\n            } else {\n                status.summary = getString(R.string.checkin_not_registered)\n                androidId.isVisible = false\n            }\n        }\n    }\n\n    companion object {\n        private const val UPDATE_INTERVAL = 1000L\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/ui/GameProfileFragment.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.ui\n\nimport android.accounts.AccountManager\nimport android.annotation.SuppressLint\nimport android.os.Bundle\nimport androidx.lifecycle.lifecycleScope\nimport androidx.preference.Preference\nimport androidx.preference.PreferenceFragmentCompat\nimport androidx.preference.SwitchPreferenceCompat\nimport com.google.android.gms.R\nimport org.microg.gms.auth.AuthConstants\nimport org.microg.gms.games.GameProfileSettings\nimport org.microg.gms.games.GamesConfigurationService\nimport org.microg.gms.games.ui.GamePlayDataActivity\nimport org.microg.gms.settings.SettingsContract\n\nclass GameProfileFragment : PreferenceFragmentCompat() {\n\n    private lateinit var autoCreatePlayerEnabled: SwitchBarPreference\n    private lateinit var allowUploadGamePlayed: SwitchPreferenceCompat\n    private lateinit var changeDefaultAccountPreference: Preference\n    private lateinit var deletePlayGamesAccountPreference: Preference\n\n    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {\n        addPreferencesFromResource(R.xml.preferences_game_profile)\n    }\n\n    @SuppressLint(\"RestrictedApi\")\n    override fun onBindPreferences() {\n\n        autoCreatePlayerEnabled = preferenceScreen.findPreference(SettingsContract.GameProfile.ALLOW_CREATE_PLAYER) ?: autoCreatePlayerEnabled\n        autoCreatePlayerEnabled.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->\n            lifecycleScope.launchWhenResumed {\n                if (newValue is Boolean) {\n                    GameProfileSettings.setAllowCreatePlayer(requireContext(), newValue)\n                }\n                updateContent()\n            }\n            true\n        }\n\n        allowUploadGamePlayed = preferenceScreen.findPreference(SettingsContract.GameProfile.ALLOW_UPLOAD_GAME_PLAYED) ?: allowUploadGamePlayed\n        allowUploadGamePlayed.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->\n            lifecycleScope.launchWhenResumed {\n                if (newValue is Boolean) {\n                    GameProfileSettings.setAllowUploadGamePlayed(requireContext(), newValue)\n                }\n                updateContent()\n            }\n            true\n        }\n\n        changeDefaultAccountPreference = preferenceScreen.findPreference(PREF_CHANGE_DEFAULT_ACCOUNT) ?: changeDefaultAccountPreference\n        changeDefaultAccountPreference.setOnPreferenceClickListener {\n            GamePlayDataActivity.createIntent(requireContext(), GamePlayDataActivity.TYPE_CHANGED)\n            true\n        }\n\n        deletePlayGamesAccountPreference = preferenceScreen.findPreference(PREF_DELETE_GAME_ACCOUNT) ?: deletePlayGamesAccountPreference\n        deletePlayGamesAccountPreference.setOnPreferenceClickListener {\n            GamePlayDataActivity.createIntent(requireContext(), GamePlayDataActivity.TYPE_DELETED)\n            true\n        }\n\n        updateContent()\n    }\n\n    override fun onResume() {\n        super.onResume()\n        updateContent()\n    }\n\n    private fun updateContent() {\n        lifecycleScope.launchWhenResumed {\n            autoCreatePlayerEnabled.isChecked = GameProfileSettings.getAllowCreatePlayer(requireContext())\n            allowUploadGamePlayed.isChecked = GameProfileSettings.getAllowUploadGamePlayed(requireContext())\n\n            val hasGamePlayAccount = runCatching {\n                AccountManager.get(requireContext()).getAccountsByType(AuthConstants.DEFAULT_ACCOUNT_TYPE)\n            }.getOrNull()?.any { GamesConfigurationService.getPlayer(requireContext(), it) != null }\n            deletePlayGamesAccountPreference.isVisible = hasGamePlayAccount == true\n            changeDefaultAccountPreference.isVisible = hasGamePlayAccount == true\n        }\n    }\n\n    companion object {\n        private const val PREF_CHANGE_DEFAULT_ACCOUNT = \"pref_change_default_account\"\n        private const val PREF_DELETE_GAME_ACCOUNT = \"pref_delete_game_account\"\n    }\n\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationAdvancedFragment.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage org.microg.gms.ui\n\nimport android.annotation.SuppressLint\nimport android.os.Bundle\nimport androidx.lifecycle.lifecycleScope\nimport androidx.preference.ListPreference\nimport androidx.preference.Preference\nimport androidx.preference.PreferenceFragmentCompat\nimport androidx.preference.TwoStatePreference\nimport com.google.android.gms.R\nimport org.microg.gms.gcm.*\n\nclass PushNotificationAdvancedFragment : PreferenceFragmentCompat() {\n    private lateinit var confirmNewApps: TwoStatePreference\n    private lateinit var networkMobile: ListPreference\n    private lateinit var networkWifi: ListPreference\n    private lateinit var networkRoaming: ListPreference\n    private lateinit var networkOther: ListPreference\n\n    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {\n        addPreferencesFromResource(R.xml.preferences_gcm_advanced)\n    }\n\n    @SuppressLint(\"RestrictedApi\")\n    override fun onBindPreferences() {\n        confirmNewApps = preferenceScreen.findPreference(GcmPrefs.PREF_CONFIRM_NEW_APPS) ?: confirmNewApps\n        networkMobile = preferenceScreen.findPreference(GcmPrefs.PREF_NETWORK_MOBILE) ?: networkMobile\n        networkWifi = preferenceScreen.findPreference(GcmPrefs.PREF_NETWORK_WIFI) ?: networkWifi\n        networkRoaming = preferenceScreen.findPreference(GcmPrefs.PREF_NETWORK_ROAMING) ?: networkRoaming\n        networkOther = preferenceScreen.findPreference(GcmPrefs.PREF_NETWORK_OTHER) ?: networkOther\n\n        confirmNewApps.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->\n            val appContext = requireContext().applicationContext\n            lifecycleScope.launchWhenResumed {\n                if (newValue is Boolean) {\n                    setGcmServiceConfiguration(appContext, getGcmServiceInfo(appContext).configuration.copy(confirmNewApps = newValue))\n                }\n                updateContent()\n            }\n            true\n        }\n        networkMobile.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->\n            val appContext = requireContext().applicationContext\n            lifecycleScope.launchWhenResumed {\n                (newValue as? String)?.toIntOrNull()?.let {\n                    setGcmServiceConfiguration(appContext, getGcmServiceInfo(appContext).configuration.copy(mobile = it))\n                }\n                updateContent()\n            }\n            true\n        }\n        networkWifi.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->\n            val appContext = requireContext().applicationContext\n            lifecycleScope.launchWhenResumed {\n                (newValue as? String)?.toIntOrNull()?.let {\n                    setGcmServiceConfiguration(appContext, getGcmServiceInfo(appContext).configuration.copy(wifi = it))\n                }\n                updateContent()\n            }\n            true\n        }\n        networkRoaming.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->\n            val appContext = requireContext().applicationContext\n            lifecycleScope.launchWhenResumed {\n                (newValue as? String)?.toIntOrNull()?.let {\n                    setGcmServiceConfiguration(appContext, getGcmServiceInfo(appContext).configuration.copy(roaming = it))\n                }\n                updateContent()\n            }\n            true\n        }\n        networkOther.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->\n            val appContext = requireContext().applicationContext\n            lifecycleScope.launchWhenResumed {\n                (newValue as? String)?.toIntOrNull()?.let {\n                    setGcmServiceConfiguration(appContext, getGcmServiceInfo(appContext).configuration.copy(other = it))\n                }\n                updateContent()\n            }\n            true\n        }\n    }\n\n    override fun onResume() {\n        super.onResume()\n        updateContent()\n    }\n\n    private fun updateContent() {\n        val appContext = requireContext().applicationContext\n        lifecycleScope.launchWhenResumed {\n            val serviceInfo = getGcmServiceInfo(appContext)\n            confirmNewApps.isChecked = serviceInfo.configuration.confirmNewApps\n            networkMobile.value = serviceInfo.configuration.mobile.toString()\n            networkMobile.summary = getSummaryString(serviceInfo.configuration.mobile, serviceInfo.learntMobileInterval)\n            networkWifi.value = serviceInfo.configuration.wifi.toString()\n            networkWifi.summary = getSummaryString(serviceInfo.configuration.wifi, serviceInfo.learntWifiInterval)\n            networkRoaming.value = serviceInfo.configuration.roaming.toString()\n            networkRoaming.summary = getSummaryString(serviceInfo.configuration.roaming, serviceInfo.learntMobileInterval)\n            networkOther.value = serviceInfo.configuration.other.toString()\n            networkOther.summary = getSummaryString(serviceInfo.configuration.other, serviceInfo.learntOtherInterval)\n        }\n    }\n\n    private fun getSummaryString(value: Int, learnt: Int): String = when (value) {\n        -1 -> getString(R.string.push_notifications_summary_off)\n        0 -> getString(R.string.push_notifications_summary_automatic, getHeartbeatString(learnt))\n        else -> getString(R.string.push_notifications_summary_manual, getHeartbeatString(value * 60000))\n    }\n\n    private fun getHeartbeatString(heartbeatMs: Int): String {\n        return if (heartbeatMs < 120000) {\n            getString(R.string.push_notifications_summary_values_seconds, (heartbeatMs / 1000).toString())\n        } else getString(R.string.push_notifications_summary_values_minutes, (heartbeatMs / 60000).toString())\n    }\n\n    companion object {\n        private val HEARTBEAT_PREFS = arrayOf(GcmPrefs.PREF_NETWORK_MOBILE, GcmPrefs.PREF_NETWORK_ROAMING, GcmPrefs.PREF_NETWORK_WIFI, GcmPrefs.PREF_NETWORK_OTHER)\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationAllAppsFragment.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.ui\n\nimport android.os.Bundle\nimport android.text.format.DateUtils\nimport androidx.appcompat.content.res.AppCompatResources\nimport androidx.core.os.bundleOf\nimport androidx.lifecycle.lifecycleScope\nimport androidx.navigation.fragment.findNavController\nimport androidx.preference.Preference\nimport androidx.preference.PreferenceCategory\nimport androidx.preference.PreferenceFragmentCompat\nimport com.google.android.gms.R\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\nimport org.microg.gms.gcm.GcmDatabase\n\nclass PushNotificationAllAppsFragment : PreferenceFragmentCompat() {\n    private lateinit var database: GcmDatabase\n    private lateinit var registered: PreferenceCategory\n    private lateinit var unregistered: PreferenceCategory\n    private lateinit var registeredNone: Preference\n    private lateinit var unregisteredNone: Preference\n    private lateinit var progress: Preference\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        database = GcmDatabase(context)\n    }\n\n    override fun onResume() {\n        super.onResume()\n        updateContent()\n    }\n\n    override fun onPause() {\n        super.onPause()\n        database.close()\n    }\n\n    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {\n        addPreferencesFromResource(R.xml.preferences_push_notifications_all_apps)\n        registered = preferenceScreen.findPreference(\"prefcat_push_apps_registered\") ?: registered\n        unregistered = preferenceScreen.findPreference(\"prefcat_push_apps_unregistered\") ?: unregistered\n        registeredNone = preferenceScreen.findPreference(\"pref_push_apps_registered_none\") ?: registeredNone\n        unregisteredNone = preferenceScreen.findPreference(\"pref_push_apps_unregistered_none\") ?: unregisteredNone\n        progress = preferenceScreen.findPreference(\"pref_push_apps_all_progress\") ?: progress\n    }\n\n    private fun updateContent() {\n        val context = requireContext()\n        lifecycleScope.launchWhenResumed {\n            val apps = withContext(Dispatchers.IO) {\n                val res = database.appList.map { app ->\n                    val pref = AppIconPreference(context)\n                    pref.packageName = app.packageName\n                    pref.summary = when {\n                        app.lastMessageTimestamp > 0 -> getString(R.string.gcm_last_message_at, DateUtils.getRelativeTimeSpanString(app.lastMessageTimestamp))\n                        else -> null\n                    }\n                    pref.onPreferenceClickListener = Preference.OnPreferenceClickListener {\n                        findNavController().navigate(requireContext(), R.id.openGcmAppDetailsFromAll, bundleOf(\n                                \"package\" to app.packageName\n                        ))\n                        true\n                    }\n                    pref.key = \"pref_push_app_\" + app.packageName\n                    pref to (database.getRegistrationsByApp(app.packageName))\n                }.sortedBy {\n                    it.first.title.toString().toLowerCase()\n                }.mapIndexed { idx, pair ->\n                    pair.first.order = idx\n                    pair\n                }\n                database.close()\n                res\n            }\n            registered.removeAll()\n            registered.isVisible = true\n            unregistered.removeAll()\n            unregistered.isVisible = true\n\n            var hadRegistered = false\n            var hadUnregistered = false\n\n            for (pair in apps) {\n                if (pair.second.isEmpty()) {\n                    unregistered.addPreference(pair.first)\n                    hadUnregistered = true\n                } else {\n                    registered.addPreference(pair.first)\n                    hadRegistered = true\n                }\n            }\n\n            registeredNone.isVisible = !hadRegistered\n            unregisteredNone.isVisible = !hadUnregistered\n            if (!hadRegistered) registered.addPreference(registeredNone)\n            if (!hadUnregistered) unregistered.addPreference(unregisteredNone)\n            progress.isVisible = false\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationAppFragment.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.ui\n\nimport android.annotation.SuppressLint\nimport android.os.Bundle\nimport android.text.format.DateUtils\nimport androidx.appcompat.app.AlertDialog\nimport androidx.lifecycle.lifecycleScope\nimport androidx.preference.Preference\nimport androidx.preference.PreferenceCategory\nimport androidx.preference.PreferenceFragmentCompat\nimport androidx.preference.TwoStatePreference\nimport com.google.android.gms.R\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\nimport org.microg.gms.gcm.GcmDatabase\nimport org.microg.gms.gcm.PushRegisterManager\n\nclass PushNotificationAppFragment : PreferenceFragmentCompat() {\n    private lateinit var appHeadingPreference: AppHeadingPreference\n    private lateinit var wakeForDelivery: TwoStatePreference\n    private lateinit var allowRegister: TwoStatePreference\n    private lateinit var status: Preference\n    private lateinit var unregister: Preference\n    private lateinit var unregisterCat: PreferenceCategory\n\n    private lateinit var database: GcmDatabase\n    private val packageName: String?\n        get() = arguments?.getString(\"package\")\n\n    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {\n        addPreferencesFromResource(R.xml.preferences_push_notifications_app)\n    }\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        database = GcmDatabase(context)\n    }\n\n    @SuppressLint(\"RestrictedApi\")\n    override fun onBindPreferences() {\n        appHeadingPreference = preferenceScreen.findPreference(\"pref_push_app_heading\") ?: appHeadingPreference\n        wakeForDelivery = preferenceScreen.findPreference(\"pref_push_app_wake_for_delivery\") ?: wakeForDelivery\n        allowRegister = preferenceScreen.findPreference(\"pref_push_app_allow_register\") ?: allowRegister\n        unregister = preferenceScreen.findPreference(\"pref_push_app_unregister\") ?: unregister\n        unregisterCat = preferenceScreen.findPreference(\"prefcat_push_app_unregister\") ?: unregisterCat\n        status = preferenceScreen.findPreference(\"pref_push_app_status\") ?: status\n        wakeForDelivery.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->\n            database.setAppWakeForDelivery(packageName, newValue as Boolean)\n            database.close()\n            true\n        }\n        allowRegister.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->\n            val enabled = newValue as? Boolean ?: return@OnPreferenceChangeListener false\n            if (!enabled) {\n                val registrations = packageName?.let { database.getRegistrationsByApp(it) } ?: emptyList()\n                if (registrations.isNotEmpty()) {\n                    showUnregisterConfirm(R.string.gcm_unregister_after_deny_message)\n                }\n            }\n            database.setAppAllowRegister(packageName, enabled)\n            database.close()\n            true\n        }\n        unregister.onPreferenceClickListener = Preference.OnPreferenceClickListener {\n            showUnregisterConfirm(R.string.gcm_unregister_confirm_message)\n            true\n        }\n    }\n\n\n    private fun showUnregisterConfirm(unregisterConfirmDesc: Int) {\n        val pm = requireContext().packageManager\n        val applicationInfo = pm.getApplicationInfoIfExists(packageName)\n        requireContext().buildAlertDialog()\n                .setTitle(getString(R.string.gcm_unregister_confirm_title, applicationInfo?.loadLabel(pm)\n                        ?: packageName))\n                .setMessage(unregisterConfirmDesc)\n                .setPositiveButton(android.R.string.yes) { _, _ -> unregister() }\n                .setNegativeButton(android.R.string.no) { _, _ -> }\n                .show()\n    }\n\n    private fun unregister() {\n        lifecycleScope.launchWhenResumed {\n            withContext(Dispatchers.IO) {\n                for (registration in database.getRegistrationsByApp(packageName)) {\n                    PushRegisterManager.unregister(context, registration.packageName, registration.signature, null, null)\n                }\n            }\n            updateDetails()\n        }\n    }\n\n    override fun onResume() {\n        super.onResume()\n        updateDetails()\n    }\n\n    private fun updateDetails() {\n        lifecycleScope.launchWhenResumed {\n            appHeadingPreference.packageName = packageName\n            val app = packageName?.let { database.getApp(it) }\n            wakeForDelivery.isChecked = app?.wakeForDelivery ?: true\n            allowRegister.isChecked = app?.allowRegister ?: true\n            val registrations = packageName?.let { database.getRegistrationsByApp(it) } ?: emptyList()\n            unregisterCat.isVisible = registrations.isNotEmpty()\n\n            val sb = StringBuilder()\n            if ((app?.totalMessageCount ?: 0L) == 0L) {\n                sb.append(getString(R.string.gcm_no_message_yet))\n            } else {\n                sb.append(getString(R.string.gcm_messages_counter, app?.totalMessageCount, app?.totalMessageBytes))\n                if (app?.lastMessageTimestamp != 0L) {\n                    sb.append(\"\\n\").append(getString(R.string.gcm_last_message_at, DateUtils.getRelativeDateTimeString(context, app?.lastMessageTimestamp ?: 0L, DateUtils.MINUTE_IN_MILLIS, DateUtils.WEEK_IN_MILLIS, DateUtils.FORMAT_SHOW_TIME)))\n                }\n            }\n            for (registration in registrations) {\n                sb.append(\"\\n\")\n                if (registration.timestamp == 0L) {\n                    sb.append(getString(R.string.gcm_registered))\n                } else {\n                    sb.append(getString(R.string.gcm_registered_since, DateUtils.getRelativeDateTimeString(context, registration.timestamp, DateUtils.MINUTE_IN_MILLIS, DateUtils.WEEK_IN_MILLIS, DateUtils.FORMAT_SHOW_TIME)))\n                }\n            }\n            status.summary = sb.toString()\n\n            database.close()\n        }\n    }\n\n    override fun onPause() {\n        super.onPause()\n        database.close()\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationFragment.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.ui\n\nimport android.annotation.SuppressLint\nimport android.os.Bundle\nimport android.os.Handler\nimport android.text.format.DateUtils\nimport android.view.Menu\nimport android.view.MenuInflater\nimport android.view.MenuItem\nimport androidx.core.os.bundleOf\nimport androidx.lifecycle.lifecycleScope\nimport androidx.navigation.fragment.findNavController\nimport androidx.preference.Preference\nimport androidx.preference.PreferenceCategory\nimport androidx.preference.PreferenceFragmentCompat\nimport com.google.android.gms.R\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\nimport org.microg.gms.checkin.CheckinPreferences\nimport org.microg.gms.gcm.GcmDatabase\nimport org.microg.gms.gcm.GcmPrefs\nimport org.microg.gms.gcm.getGcmServiceInfo\n\nclass PushNotificationFragment : PreferenceFragmentCompat() {\n    private lateinit var switchBarPreference: SwitchBarPreference\n    private lateinit var pushStatusCategory: PreferenceCategory\n    private lateinit var pushStatus: Preference\n    private lateinit var pushApps: PreferenceCategory\n    private lateinit var pushAppsAll: Preference\n    private lateinit var pushAppsNone: Preference\n    private lateinit var database: GcmDatabase\n    private val handler = Handler()\n    private val updateRunnable = Runnable { updateStatus() }\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        database = GcmDatabase(context)\n    }\n\n    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {\n        addPreferencesFromResource(R.xml.preferences_push_notifications)\n    }\n\n    @SuppressLint(\"RestrictedApi\")\n    override fun onBindPreferences() {\n        switchBarPreference = preferenceScreen.findPreference(\"pref_push_enabled\") ?: switchBarPreference\n        pushStatusCategory = preferenceScreen.findPreference(\"prefcat_push_status\") ?: pushStatusCategory\n        pushStatus = preferenceScreen.findPreference(\"pref_push_status\") ?: pushStatus\n        pushApps = preferenceScreen.findPreference(\"prefcat_push_apps\") ?: pushApps\n        pushAppsAll = preferenceScreen.findPreference(\"pref_push_apps_all\") ?: pushAppsAll\n        pushAppsNone = preferenceScreen.findPreference(\"pref_push_apps_none\") ?: pushAppsNone\n        pushAppsAll.setOnPreferenceClickListener {\n            findNavController().navigate(requireContext(), R.id.openAllGcmApps)\n            true\n        }\n        switchBarPreference.setOnPreferenceChangeListener { _, newValue ->\n            val newStatus = newValue as Boolean\n            GcmPrefs.setEnabled(requireContext(), newStatus)\n            true\n        }\n    }\n\n    override fun onResume() {\n        super.onResume()\n\n        switchBarPreference.isEnabled = CheckinPreferences.isEnabled(requireContext())\n        switchBarPreference.isChecked = GcmPrefs.get(requireContext()).isEnabled\n\n        updateStatus()\n        updateContent()\n    }\n\n    override fun onPause() {\n        super.onPause()\n        database.close()\n        handler.removeCallbacks(updateRunnable)\n    }\n\n    private fun updateStatus() {\n        handler.postDelayed(updateRunnable, UPDATE_INTERVAL)\n        val appContext = requireContext().applicationContext\n        lifecycleScope.launchWhenStarted {\n            val statusInfo = getGcmServiceInfo(appContext)\n            switchBarPreference.isChecked = statusInfo.configuration.enabled\n            pushStatusCategory.isVisible = statusInfo != null && statusInfo.configuration.enabled\n            pushStatus.summary = if (statusInfo != null && statusInfo.connected) {\n                appContext.getString(R.string.gcm_network_state_connected, DateUtils.getRelativeTimeSpanString(statusInfo.startTimestamp, System.currentTimeMillis(), 0))\n            } else {\n                appContext.getString(R.string.gcm_network_state_disconnected)\n            }\n        }\n    }\n\n    private fun updateContent() {\n        lifecycleScope.launchWhenResumed {\n            val context = requireContext()\n            val (apps, showAll) = withContext(Dispatchers.IO) {\n                val apps = database.appList.sortedByDescending { it.lastMessageTimestamp }\n                val res = apps.map { app ->\n                    app to context.packageManager.getApplicationInfoIfExists(app.packageName)\n                }.mapNotNull { (app, info) ->\n                    if (info == null) null else app to info\n                }.take(3).mapIndexed { idx, (app, applicationInfo) ->\n                    val pref = AppIconPreference(context)\n                    pref.order = idx\n                    pref.applicationInfo = applicationInfo\n                    pref.onPreferenceClickListener = Preference.OnPreferenceClickListener {\n                        findNavController().navigate(requireContext(), R.id.openGcmAppDetails, bundleOf(\n                                \"package\" to app.packageName\n                        ))\n                        true\n                    }\n                    pref.key = \"pref_push_app_\" + app.packageName\n                    pref\n                }.let { it to (it.size < apps.size) }\n                database.close()\n                res\n            }\n            pushAppsAll.isVisible = showAll\n            pushApps.removeAll()\n            for (app in apps) {\n                pushApps.addPreference(app)\n            }\n            if (showAll) {\n                pushApps.addPreference(pushAppsAll)\n            } else if (apps.isEmpty()) {\n                pushApps.addPreference(pushAppsNone)\n            }\n        }\n    }\n\n    init {\n        setHasOptionsMenu(true)\n    }\n\n    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {\n        menu.add(0, MENU_ADVANCED, 0, org.microg.gms.base.core.R.string.menu_advanced)\n        super.onCreateOptionsMenu(menu, inflater)\n    }\n\n    override fun onOptionsItemSelected(item: MenuItem): Boolean {\n        return when (item.itemId) {\n            MENU_ADVANCED -> {\n                findNavController().navigate(requireContext(), R.id.openGcmAdvancedSettings)\n                true\n            }\n            else -> super.onOptionsItemSelected(item)\n        }\n    }\n\n    companion object {\n        private const val UPDATE_INTERVAL = 1000L\n        private const val MENU_ADVANCED = Menu.FIRST\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/ui/SafetyNetAdvancedFragment.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2021 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.ui\n\nimport androidx.fragment.app.Fragment\nimport com.google.android.gms.R\n\nclass SafetyNetAdvancedFragment : Fragment(R.layout.safety_net_advanced_fragment) {\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/ui/SafetyNetAllAppsFragment.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.ui\n\nimport android.os.Bundle\nimport android.text.format.DateUtils\nimport androidx.appcompat.content.res.AppCompatResources\nimport androidx.core.os.bundleOf\nimport androidx.lifecycle.lifecycleScope\nimport androidx.navigation.fragment.findNavController\nimport androidx.preference.Preference\nimport androidx.preference.PreferenceCategory\nimport androidx.preference.PreferenceFragmentCompat\nimport com.google.android.gms.R\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\nimport org.microg.gms.safetynet.SafetyNetDatabase\nimport org.microg.gms.vending.PlayIntegrityData\nimport org.microg.gms.vending.VendingPreferences\n\nclass SafetyNetAllAppsFragment : PreferenceFragmentCompat() {\n    private lateinit var database: SafetyNetDatabase\n    private lateinit var apps: PreferenceCategory\n    private lateinit var appsNone: Preference\n    private lateinit var progress: Preference\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        database = SafetyNetDatabase(requireContext())\n    }\n\n    override fun onResume() {\n        super.onResume()\n        updateContent()\n    }\n\n    override fun onPause() {\n        super.onPause()\n        database.close()\n    }\n\n    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {\n        addPreferencesFromResource(R.xml.preferences_safetynet_all_apps)\n        apps = preferenceScreen.findPreference(\"prefcat_safetynet_apps_all\") ?: apps\n        appsNone = preferenceScreen.findPreference(\"pref_safetynet_apps_all_none\") ?: appsNone\n        progress = preferenceScreen.findPreference(\"pref_safetynet_apps_all_progress\") ?: progress\n    }\n\n    private fun updateContent() {\n        val context = requireContext()\n        lifecycleScope.launchWhenResumed {\n            val playIntegrityData = VendingPreferences.getPlayIntegrityAppList(context)\n            val apps = withContext(Dispatchers.IO) {\n                val playPairs = PlayIntegrityData.loadDataSet(playIntegrityData).map { it.packageName to it.lastTime }\n                val res = (database.recentApps + playPairs).map { app ->\n                    val pref = AppIconPreference(context)\n                    pref.packageName = app.first\n                    pref.summary = when {\n                        app.second > 0 -> getString(R.string.safetynet_last_run_at, DateUtils.getRelativeTimeSpanString(app.second))\n                        else -> null\n                    }\n                    pref.onPreferenceClickListener = Preference.OnPreferenceClickListener {\n                        findNavController().navigate(\n                            requireContext(), R.id.openSafetyNetAppDetailsFromAll, bundleOf(\n                                \"package\" to app.first\n                            )\n                        )\n                        true\n                    }\n                    pref.key = \"pref_safetynet_app_\" + app.first\n                    pref\n                }.sortedBy {\n                    it.title.toString().lowercase()\n                }\n                database.close()\n                res\n            }\n            this@SafetyNetAllAppsFragment.apps.removeAll()\n            this@SafetyNetAllAppsFragment.apps.isVisible = true\n\n            var hadRegistered = false\n            var hadUnregistered = false\n\n            for (app in apps) {\n                this@SafetyNetAllAppsFragment.apps.addPreference(app)\n            }\n\n            appsNone.isVisible = apps.isEmpty()\n            if (apps.isEmpty()) this@SafetyNetAllAppsFragment.apps.addPreference(appsNone)\n            progress.isVisible = false\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/ui/SafetyNetAppFragment.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.ui\n\nimport android.annotation.SuppressLint\nimport android.os.Bundle\nimport android.text.format.DateUtils\nimport androidx.core.content.ContextCompat\nimport androidx.lifecycle.lifecycleScope\nimport androidx.preference.Preference\nimport androidx.preference.PreferenceCategory\nimport androidx.preference.PreferenceFragmentCompat\nimport androidx.preference.SwitchPreferenceCompat\nimport androidx.preference.isEmpty\nimport com.google.android.gms.R\nimport org.microg.gms.safetynet.SafetyNetDatabase\nimport org.microg.gms.safetynet.SafetyNetRequestType.ATTESTATION\nimport org.microg.gms.safetynet.SafetyNetRequestType.RECAPTCHA\nimport org.microg.gms.safetynet.SafetyNetRequestType.RECAPTCHA_ENTERPRISE\nimport org.microg.gms.vending.PlayIntegrityData\nimport org.microg.gms.vending.VendingPreferences\n\nclass SafetyNetAppFragment : PreferenceFragmentCompat() {\n    private lateinit var appHeadingPreference: AppHeadingPreference\n    private lateinit var recents: PreferenceCategory\n    private lateinit var recentsNone: Preference\n    private lateinit var allowRequests: SwitchPreferenceCompat\n    private val packageName: String?\n        get() = arguments?.getString(\"package\")\n\n    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {\n        addPreferencesFromResource(R.xml.preferences_safetynet_app)\n    }\n\n    @SuppressLint(\"RestrictedApi\")\n    override fun onBindPreferences() {\n        appHeadingPreference = preferenceScreen.findPreference(\"pref_safetynet_app_heading\") ?: appHeadingPreference\n        recents = preferenceScreen.findPreference(\"prefcat_safetynet_recent_list\") ?: recents\n        recentsNone = preferenceScreen.findPreference(\"pref_safetynet_recent_none\") ?: recentsNone\n        allowRequests = preferenceScreen.findPreference(\"pref_device_attestation_app_allow_requests\") ?: allowRequests\n        allowRequests.setOnPreferenceChangeListener { _, newValue ->\n            val playIntegrityDataSet = loadPlayIntegrityData()\n            val integrityData = packageName?.let { packageName -> playIntegrityDataSet.find { packageName == it.packageName } }\n            if (newValue is Boolean && integrityData != null) {\n                val content = PlayIntegrityData.updateDataSetString(playIntegrityDataSet, integrityData.apply { this.allowed = newValue })\n                VendingPreferences.setPlayIntegrityAppList(requireContext(), content)\n            }\n            true\n        }\n    }\n\n    override fun onResume() {\n        super.onResume()\n        updateContent()\n    }\n\n    private fun loadPlayIntegrityData(): Set<PlayIntegrityData> {\n        val playIntegrityData = VendingPreferences.getPlayIntegrityAppList(requireContext())\n        return PlayIntegrityData.loadDataSet(playIntegrityData)\n    }\n\n    fun updateContent() {\n        lifecycleScope.launchWhenResumed {\n            appHeadingPreference.packageName = packageName\n            val context = requireContext()\n            val summaries =\n                packageName?.let { packageName ->\n                    val db = SafetyNetDatabase(context)\n                    try {\n                        db.getRecentRequests(packageName)\n                    } finally {\n                        db.close()\n                    }\n                }.orEmpty()\n            recents.removeAll()\n            recents.addPreference(recentsNone)\n            for (summary in summaries) {\n                val preference = Preference(requireContext())\n                preference.onPreferenceClickListener = Preference.OnPreferenceClickListener {\n                    SafetyNetRecentDialogFragment().apply {\n                        arguments = Bundle().apply { putParcelable(\"summary\", summary) }\n                    }.show(requireFragmentManager(), null)\n                    true\n                }\n                val date = DateUtils.getRelativeDateTimeString(\n                    context,\n                    summary.timestamp,\n                    DateUtils.MINUTE_IN_MILLIS,\n                    DateUtils.WEEK_IN_MILLIS,\n                    DateUtils.FORMAT_SHOW_TIME\n                )\n                preference.title = date\n                formatSummaryForSafetyNetResult(\n                    context,\n                    summary.responseData,\n                    summary.responseStatus,\n                    summary.requestType\n                ).let { (text, icon) ->\n                    preference.summary = when (summary.requestType) {\n                        ATTESTATION -> getString(R.string.pref_safetynet_recent_attestation_summary, text)\n                        RECAPTCHA -> getString(R.string.pref_safetynet_recent_recaptcha_summary, text)\n                        RECAPTCHA_ENTERPRISE -> getString(R.string.pref_safetynet_recent_recaptcha_enterprise_summary, text)\n                    }\n                    preference.icon = icon\n                }\n                recents.addPreference(preference)\n            }\n            val piContent = packageName?.let { packageName -> loadPlayIntegrityData().find { packageName == it.packageName } }\n            if (piContent != null) {\n                val preference = Preference(requireContext())\n                val date = DateUtils.getRelativeDateTimeString(\n                    context,\n                    piContent.lastTime,\n                    DateUtils.MINUTE_IN_MILLIS,\n                    DateUtils.WEEK_IN_MILLIS,\n                    DateUtils.FORMAT_SHOW_TIME\n                )\n                preference.title = date\n                preference.summary = piContent.lastResult\n                preference.icon = if (piContent.lastStatus) ContextCompat.getDrawable(context, R.drawable.ic_circle_check) else ContextCompat.getDrawable(context, R.drawable.ic_circle_warn)\n                recents.addPreference(preference)\n            }\n            recentsNone.isVisible = summaries.isEmpty() && piContent == null\n            allowRequests.isChecked = piContent?.allowed == true\n        }\n\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/ui/SafetyNetFragment.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.ui\n\nimport android.os.Bundle\nimport android.util.Base64\nimport android.util.Log\nimport android.view.Menu\nimport android.view.MenuInflater\nimport android.view.MenuItem\nimport androidx.core.content.ContextCompat\nimport androidx.core.os.bundleOf\nimport androidx.lifecycle.lifecycleScope\nimport androidx.navigation.fragment.findNavController\nimport androidx.preference.Preference\nimport androidx.preference.PreferenceCategory\nimport androidx.preference.PreferenceFragmentCompat\nimport com.android.volley.Request\nimport com.android.volley.toolbox.JsonObjectRequest\nimport com.android.volley.toolbox.Volley\nimport com.google.android.gms.BuildConfig\nimport com.google.android.gms.R\nimport com.google.android.gms.recaptcha.Recaptcha\nimport com.google.android.gms.recaptcha.RecaptchaAction\nimport com.google.android.gms.recaptcha.RecaptchaActionType\nimport com.google.android.gms.safetynet.SafetyNet\nimport com.google.android.gms.tasks.await\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\nimport org.json.JSONObject\nimport org.microg.gms.checkin.CheckinPreferences\nimport org.microg.gms.droidguard.core.DroidGuardPreferences\nimport org.microg.gms.safetynet.SafetyNetDatabase\nimport org.microg.gms.safetynet.SafetyNetPreferences\nimport org.microg.gms.safetynet.SafetyNetRequestType.*\nimport org.microg.gms.utils.singleInstanceOf\nimport org.microg.gms.vending.PlayIntegrityData\nimport org.microg.gms.vending.VendingPreferences\nimport java.net.URLEncoder\nimport kotlin.coroutines.resume\nimport kotlin.coroutines.resumeWithException\nimport kotlin.coroutines.suspendCoroutine\nimport kotlin.random.Random\n\nclass SafetyNetFragment : PreferenceFragmentCompat() {\n    private lateinit var switchBarPreference: SwitchBarPreference\n    private lateinit var runAttest: Preference\n    private lateinit var runReCaptcha: Preference\n    private lateinit var runReCaptchaEnterprise: Preference\n    private lateinit var apps: PreferenceCategory\n    private lateinit var appsAll: Preference\n    private lateinit var appsNone: Preference\n    private lateinit var droidguardUnsupported: Preference\n\n    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {\n        addPreferencesFromResource(R.xml.preferences_safetynet)\n\n        switchBarPreference = preferenceScreen.findPreference(\"pref_safetynet_enabled\") ?: switchBarPreference\n        runAttest = preferenceScreen.findPreference(\"pref_safetynet_run_attest\") ?: runAttest\n        runReCaptcha = preferenceScreen.findPreference(\"pref_recaptcha_run_test\") ?: runReCaptcha\n        runReCaptchaEnterprise = preferenceScreen.findPreference(\"pref_recaptcha_enterprise_run_test\") ?: runReCaptchaEnterprise\n        apps = preferenceScreen.findPreference(\"prefcat_safetynet_apps\") ?: apps\n        appsAll = preferenceScreen.findPreference(\"pref_safetynet_apps_all\") ?: appsAll\n        appsNone = preferenceScreen.findPreference(\"pref_safetynet_apps_none\") ?: appsNone\n        droidguardUnsupported = preferenceScreen.findPreference(\"pref_droidguard_unsupported\") ?: droidguardUnsupported\n\n        runAttest.isVisible = SAFETYNET_API_KEY != null\n        runReCaptcha.isVisible = RECAPTCHA_SITE_KEY != null\n        runReCaptchaEnterprise.isVisible = RECAPTCHA_ENTERPRISE_SITE_KEY != null\n\n        runAttest.setOnPreferenceClickListener { runSafetyNetAttest(); true }\n        runReCaptcha.setOnPreferenceClickListener { runReCaptchaAttest(); true }\n        runReCaptchaEnterprise.setOnPreferenceClickListener { runReCaptchaEnterpriseAttest();true }\n        appsAll.setOnPreferenceClickListener { findNavController().navigate(requireContext(), R.id.openAllSafetyNetApps);true }\n        switchBarPreference.setOnPreferenceChangeListener { _, newValue ->\n            val newStatus = newValue as Boolean\n            SafetyNetPreferences.setEnabled(requireContext(), newStatus)\n            DroidGuardPreferences.setEnabled(requireContext(), newStatus)\n            droidguardUnsupported.isVisible = newStatus && !DroidGuardPreferences.isAvailable(requireContext())\n            true\n        }\n    }\n\n    private fun runSafetyNetAttest() {\n        val context = context ?: return\n        runAttest.setIcon(R.drawable.ic_circle_pending)\n        runAttest.setSummary(R.string.pref_test_summary_running)\n        lifecycleScope.launchWhenResumed {\n            try {\n                val response = SafetyNet.getClient(requireActivity())\n                    .attest(Random.nextBytes(32), SAFETYNET_API_KEY).await()\n                val (_, payload, _) = try {\n                    response.jwsResult.split(\".\")\n                } catch (e: Exception) {\n                    listOf(null, null, null)\n                }\n                formatSummaryForSafetyNetResult(\n                    context,\n                    payload?.let { Base64.decode(it, Base64.URL_SAFE).decodeToString() },\n                    response.result.status,\n                    ATTESTATION\n                )\n                    .let { (summary, icon) ->\n                        runAttest.summary = summary\n                        runAttest.icon = icon\n                    }\n            } catch (e: Exception) {\n                runAttest.summary = getString(R.string.pref_test_summary_failed, e.message)\n                runAttest.icon = ContextCompat.getDrawable(context, R.drawable.ic_circle_warn)\n            }\n            updateContent()\n        }\n    }\n\n    private fun runReCaptchaAttest() {\n        val context = context ?: return\n        runReCaptcha.setIcon(R.drawable.ic_circle_pending)\n        runReCaptcha.setSummary(R.string.pref_test_summary_running)\n        lifecycleScope.launchWhenResumed {\n            try {\n                val response = SafetyNet.getClient(requireActivity())\n                    .verifyWithRecaptcha(RECAPTCHA_SITE_KEY).await()\n                val result = if (response.tokenResult != null) {\n                    val queue = singleInstanceOf { Volley.newRequestQueue(context.applicationContext) }\n                    val json =\n                        if (RECAPTCHA_SECRET != null) {\n                            suspendCoroutine { continuation ->\n                                queue.add(object : JsonObjectRequest(\n                                    Method.POST,\n                                    \"https://www.google.com/recaptcha/api/siteverify\",\n                                    null,\n                                    { continuation.resume(it) },\n                                    { continuation.resumeWithException(it) }\n                                ) {\n                                    override fun getBodyContentType(): String = \"application/x-www-form-urlencoded; charset=UTF-8\"\n                                    override fun getBody(): ByteArray =\n                                        \"secret=$RECAPTCHA_SECRET&response=${URLEncoder.encode(response.tokenResult, \"UTF-8\")}\".encodeToByteArray()\n                                })\n                            }\n                        } else {\n                            // Can't properly verify, everything becomes a success\n                            JSONObject(mapOf(\"success\" to true))\n                        }\n                    Log.d(TAG, \"Result: $json\")\n                    json.toString()\n                } else {\n                    null\n                }\n                formatSummaryForSafetyNetResult(context, result, response.result.status, RECAPTCHA)\n                    .let { (summary, icon) ->\n                        runReCaptcha.summary = summary\n                        runReCaptcha.icon = icon\n                    }\n            } catch (e: Exception) {\n                runReCaptcha.summary = getString(R.string.pref_test_summary_failed, e.message)\n                runReCaptcha.icon = ContextCompat.getDrawable(context, R.drawable.ic_circle_warn)\n            }\n            updateContent()\n        }\n    }\n\n    private fun runReCaptchaEnterpriseAttest() {\n        val context = context ?: return\n        runReCaptchaEnterprise.setIcon(R.drawable.ic_circle_pending)\n        runReCaptchaEnterprise.setSummary(R.string.pref_test_summary_running)\n        lifecycleScope.launchWhenResumed {\n            try {\n                val client = Recaptcha.getClient(requireActivity())\n                val handle = client.init(RECAPTCHA_ENTERPRISE_SITE_KEY).await()\n                val actionType = RecaptchaActionType.SIGNUP\n                val response = client.execute(handle, RecaptchaAction(RecaptchaActionType(actionType))).await()\n                Log.d(TAG, \"Recaptcha Token: \" + response.tokenResult)\n                client.close(handle).await()\n                val result = if (response.tokenResult != null) {\n                    val queue = singleInstanceOf { Volley.newRequestQueue(context.applicationContext) }\n                    val json = if (RECAPTCHA_ENTERPRISE_API_KEY != null) {\n                        suspendCoroutine { continuation ->\n                            queue.add(JsonObjectRequest(\n                                Request.Method.POST,\n                                \"https://recaptchaenterprise.googleapis.com/v1/projects/$RECAPTCHA_ENTERPRISE_PROJECT_ID/assessments?key=$RECAPTCHA_ENTERPRISE_API_KEY\",\n                                JSONObject(\n                                    mapOf(\n                                        \"event\" to JSONObject(\n                                            mapOf(\n                                                \"token\" to response.tokenResult,\n                                                \"siteKey\" to RECAPTCHA_ENTERPRISE_SITE_KEY,\n                                                \"expectedAction\" to actionType\n                                            )\n                                        )\n                                    )\n                                ),\n                                { continuation.resume(it) },\n                                { continuation.resumeWithException(it) }\n                            ))\n                        }\n                    } else {\n                        // Can't properly verify, everything becomes a success\n                        JSONObject(mapOf(\"tokenProperties\" to JSONObject(mapOf(\"valid\" to true)), \"riskAnalysis\" to JSONObject(mapOf(\"score\" to \"unknown\"))))\n                    }\n                    Log.d(TAG, \"Result: $json\")\n                    json.toString()\n                } else {\n                    null\n                }\n                formatSummaryForSafetyNetResult(context, result, null, RECAPTCHA_ENTERPRISE)\n                    .let { (summary, icon) ->\n                        runReCaptchaEnterprise.summary = summary\n                        runReCaptchaEnterprise.icon = icon\n                    }\n            } catch (e: Exception) {\n                runReCaptchaEnterprise.summary = getString(R.string.pref_test_summary_failed, e.message)\n                runReCaptchaEnterprise.icon = ContextCompat.getDrawable(context, R.drawable.ic_circle_warn)\n            }\n            updateContent()\n        }\n    }\n\n    override fun onResume() {\n        super.onResume()\n\n        switchBarPreference.isEnabled = CheckinPreferences.isEnabled(requireContext())\n        switchBarPreference.isChecked = SafetyNetPreferences.isEnabled(requireContext()) && DroidGuardPreferences.isEnabled(requireContext())\n        droidguardUnsupported.isVisible = switchBarPreference.isChecked && !DroidGuardPreferences.isAvailable(requireContext())\n\n        updateContent()\n    }\n\n    fun updateContent() {\n        lifecycleScope.launchWhenResumed {\n            val context = requireContext()\n            val (apps, showAll) = withContext(Dispatchers.IO) {\n                val playIntegrityData = VendingPreferences.getPlayIntegrityAppList(context)\n                val db = SafetyNetDatabase(context)\n                val apps = try {\n                    db.recentApps + PlayIntegrityData.loadDataSet(playIntegrityData).map { it.packageName to it.lastTime }\n                } finally {\n                    db.close()\n                }\n                apps.sortedByDescending { it.second }.map { app ->\n                    app to context.packageManager.getApplicationInfoIfExists(app.first)\n                }.mapNotNull { (app, info) ->\n                    if (info == null) null else app to info\n                }.take(3).mapIndexed { idx, (app, applicationInfo) ->\n                    val pref = AppIconPreference(context)\n                    pref.order = idx\n                    pref.applicationInfo = applicationInfo\n                    pref.onPreferenceClickListener = Preference.OnPreferenceClickListener {\n                        findNavController().navigate(\n                            requireContext(), R.id.openSafetyNetAppDetails, bundleOf(\n                                \"package\" to app.first\n                            )\n                        )\n                        true\n                    }\n                    pref.key = \"pref_safetynet_app_\" + app.first\n                    pref\n                }.let { it to (it.size < apps.size) }\n            }\n            appsAll.isVisible = showAll\n            this@SafetyNetFragment.apps.removeAll()\n            for (app in apps) {\n                this@SafetyNetFragment.apps.addPreference(app)\n            }\n            if (showAll) {\n                this@SafetyNetFragment.apps.addPreference(appsAll)\n            } else if (apps.isEmpty()) {\n                this@SafetyNetFragment.apps.addPreference(appsNone)\n            }\n\n        }\n    }\n\n    init {\n        setHasOptionsMenu(true)\n    }\n\n    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {\n        menu.add(0, MENU_ADVANCED, 0, org.microg.gms.base.core.R.string.menu_advanced)\n        menu.add(0, MENU_CLEAR_REQUESTS, 0, R.string.menu_clear_recent_requests)\n        super.onCreateOptionsMenu(menu, inflater)\n    }\n\n    override fun onOptionsItemSelected(item: MenuItem): Boolean {\n        return when (item.itemId) {\n            MENU_ADVANCED -> {\n                findNavController().navigate(requireContext(), R.id.openSafetyNetAdvancedSettings)\n                true\n            }\n            MENU_CLEAR_REQUESTS -> {\n                val db = SafetyNetDatabase(requireContext())\n                db.clearAllRequests()\n                db.close()\n                updateContent()\n                true\n            }\n            else -> super.onOptionsItemSelected(item)\n        }\n    }\n\n    companion object {\n        private val SAFETYNET_API_KEY: String? = BuildConfig.SAFETYNET_KEY.takeIf { it.isNotBlank() }\n        private val RECAPTCHA_SITE_KEY: String? = BuildConfig.RECAPTCHA_SITE_KEY.takeIf { it.isNotBlank() }\n        private val RECAPTCHA_SECRET: String? = BuildConfig.RECAPTCHA_SECRET.takeIf { it.isNotBlank() }\n        private val RECAPTCHA_ENTERPRISE_PROJECT_ID: String? = BuildConfig.RECAPTCHA_ENTERPRISE_PROJECT_ID.takeIf { it.isNotBlank() }\n        private val RECAPTCHA_ENTERPRISE_SITE_KEY: String? = BuildConfig.RECAPTCHA_ENTERPRISE_SITE_KEY.takeIf { it.isNotBlank() }\n        private val RECAPTCHA_ENTERPRISE_API_KEY: String? = BuildConfig.RECAPTCHA_ENTERPRISE_API_KEY.takeIf { it.isNotBlank() }\n        private const val MENU_ADVANCED = Menu.FIRST\n        private const val MENU_CLEAR_REQUESTS = Menu.FIRST + 1\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/ui/SafetyNetRecentAttestationPreferencesFragment.kt",
    "content": "package org.microg.gms.ui\n\nimport android.annotation.SuppressLint\nimport android.content.ClipData\nimport android.content.ClipboardManager\nimport android.content.Context\nimport android.os.Bundle\nimport android.text.format.DateUtils\nimport android.widget.Toast\nimport androidx.preference.Preference\nimport androidx.preference.PreferenceFragmentCompat\nimport com.google.android.gms.R\nimport org.json.JSONException\nimport org.json.JSONObject\nimport org.microg.gms.firebase.auth.getStringOrNull\nimport org.microg.gms.safetynet.SafetyNetSummary\nimport org.microg.gms.utils.toHexString\n\n\nclass SafetyNetRecentAttestationPreferencesFragment : PreferenceFragmentCompat() {\n\n    lateinit var snetSummary: SafetyNetSummary\n\n    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {\n        addPreferencesFromResource(R.xml.preferences_snet_recent_attestation)\n        snetSummary = arguments?.get(\"summary\") as SafetyNetSummary\n    }\n\n    @SuppressLint(\"RestrictedApi\")\n    override fun onBindPreferences() {\n        val requestType: Preference = preferenceScreen.findPreference(\"pref_request_type\")!!\n        val time : Preference = preferenceScreen.findPreference(\"pref_time\")!!\n        val nonce : Preference = preferenceScreen.findPreference(\"pref_nonce\")!!\n        val status : Preference = preferenceScreen.findPreference(\"pref_status\")!!\n        val evalType : Preference = preferenceScreen.findPreference(\"pref_eval_type\")!!\n        val advice : Preference = preferenceScreen.findPreference(\"pref_advice\")!!\n        val copyResult : Preference = preferenceScreen.findPreference(\"pref_copy_result\")!!\n\n        requestType.summary = \"ATTESTATION\"\n\n        time.summary = DateUtils.getRelativeDateTimeString(context, snetSummary.timestamp, DateUtils.MINUTE_IN_MILLIS, DateUtils.WEEK_IN_MILLIS, DateUtils.FORMAT_SHOW_TIME)\n\n\n        snetSummary.nonce?.toHexString().let {\n            if (it == null) {\n                nonce.summary = \"None\"\n            } else {\n                nonce.summary = it\n            }\n        }\n\n        val snetResponseStatus = snetSummary.responseStatus\n        if (snetResponseStatus == null) {\n            status.summary = getString(R.string.pref_safetynet_test_not_completed)\n        } else if (snetResponseStatus.isSuccess) {\n            try {\n                val json = JSONObject(snetSummary.responseData!!)\n                evalType.summary = json.getString(\"evaluationType\")\n                advice.summary = json.getStringOrNull(\"advice\") ?: \"None\"\n\n                val basicIntegrity = json.getBoolean(\"basicIntegrity\")\n                val ctsProfileMatch = json.getBoolean(\"ctsProfileMatch\")\n\n                status.summary = when {\n                    basicIntegrity && ctsProfileMatch -> getString(R.string.pref_safetynet_test_integrity_cts_passed)\n                    basicIntegrity -> getString(R.string.pref_safetynet_test_cts_failed)\n                    else -> getString(R.string.pref_safetynet_test_integrity_failed)\n                }\n            } catch (e: JSONException) {\n                e.printStackTrace()\n                status.summary = getString(R.string.pref_safetynet_test_invalid_json)\n            }\n        } else {\n            status.summary = snetResponseStatus.statusMessage\n        }\n\n        copyResult.setOnPreferenceClickListener {\n            val clipboard = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager\n            val clip = ClipData.newPlainText(\"JSON JWS data\", snetSummary.responseData)\n            clipboard.setPrimaryClip(clip)\n\n            Toast.makeText(context, R.string.pref_safetynet_recent_copied, Toast.LENGTH_SHORT).show()\n\n            true\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/ui/SafetyNetRecentDialogFragment.kt",
    "content": "package org.microg.gms.ui\n\nimport android.content.Context\nimport android.os.Bundle\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.view.WindowManager.LayoutParams\nimport android.widget.ListView\nimport android.widget.Toast\nimport androidx.fragment.app.DialogFragment\nimport androidx.fragment.app.Fragment\nimport androidx.fragment.app.add\nimport androidx.fragment.app.commit\nimport com.google.android.gms.R\nimport com.google.android.gms.databinding.SafetyNetRecentFragmentBinding\nimport org.microg.gms.safetynet.SafetyNetRequestType\nimport org.microg.gms.safetynet.SafetyNetRequestType.*\nimport org.microg.gms.safetynet.SafetyNetSummary\n\nclass SafetyNetRecentDialogFragment : DialogFragment(R.layout.safety_net_recent_fragment) {\n\n    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {\n        binding = SafetyNetRecentFragmentBinding.inflate(inflater, container, false)\n        return binding.root\n    }\n\n    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {\n        super.onViewCreated(view, savedInstanceState)\n\n        val summary = arguments?.get(\"summary\") as SafetyNetSummary\n\n        if (savedInstanceState == null) {\n            childFragmentManager.commit {\n                setReorderingAllowed(true)\n                when (summary.requestType) {\n                    ATTESTATION -> add<SafetyNetRecentAttestationPreferencesFragment>(\n                        R.id.actual_content,\n                        args = arguments\n                    )\n                    RECAPTCHA -> add<SafetyNetRecentRecaptchaPreferencesFragment>(\n                        R.id.actual_content,\n                        args = arguments\n                    )\n                    RECAPTCHA_ENTERPRISE -> add<SafetyNetRecentRecaptchaPreferencesFragment>(\n                        R.id.actual_content,\n                        args = arguments\n                    )\n                }\n            }\n        }\n\n        dialog?.window?.apply {\n            attributes = attributes.apply {\n                width = LayoutParams.MATCH_PARENT\n            }\n        }\n    }\n\n    lateinit var binding: SafetyNetRecentFragmentBinding\n\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/ui/SafetyNetRecentRecaptchaEnterprisePreferencesFragment.kt",
    "content": "package org.microg.gms.ui\n\nimport android.annotation.SuppressLint\nimport android.os.Bundle\nimport android.text.format.DateUtils\nimport androidx.preference.Preference\nimport androidx.preference.PreferenceFragmentCompat\nimport com.google.android.gms.R\nimport org.microg.gms.safetynet.SafetyNetSummary\n\n\nclass SafetyNetRecentRecaptchaEnterprisePreferencesFragment : PreferenceFragmentCompat() {\n\n    lateinit var snetSummary: SafetyNetSummary\n\n    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {\n        addPreferencesFromResource(R.xml.preferences_snet_recent_recaptcha)\n        snetSummary = arguments?.get(\"summary\") as SafetyNetSummary\n    }\n\n    @SuppressLint(\"RestrictedApi\")\n    override fun onBindPreferences() {\n        val requestType: Preference = preferenceScreen.findPreference(\"pref_request_type\")!!\n        val time : Preference = preferenceScreen.findPreference(\"pref_time\")!!\n        val status : Preference = preferenceScreen.findPreference(\"pref_status\")!!\n        val token : Preference = preferenceScreen.findPreference(\"pref_token\")!!\n\n        requestType.summary = \"RECAPTCHA_ENTERPRISE\"\n\n        time.summary = DateUtils.getRelativeDateTimeString(context, snetSummary.timestamp, DateUtils.MINUTE_IN_MILLIS, DateUtils.WEEK_IN_MILLIS, DateUtils.FORMAT_SHOW_TIME)\n\n\n        val snetResponseStatus = snetSummary.responseStatus\n        if (snetResponseStatus == null) {\n            status.summary = getString(R.string.pref_safetynet_test_not_completed)\n        } else {\n            status.summary = snetResponseStatus.statusMessage\n            token.summary = snetSummary.responseData\n        }\n    }\n\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/ui/SafetyNetRecentRecaptchaPreferencesFragment.kt",
    "content": "package org.microg.gms.ui\n\nimport android.annotation.SuppressLint\nimport android.os.Bundle\nimport android.text.format.DateUtils\nimport androidx.preference.Preference\nimport androidx.preference.PreferenceFragmentCompat\nimport com.google.android.gms.R\nimport org.microg.gms.safetynet.SafetyNetSummary\n\n\nclass SafetyNetRecentRecaptchaPreferencesFragment : PreferenceFragmentCompat() {\n\n    lateinit var snetSummary: SafetyNetSummary\n\n    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {\n        addPreferencesFromResource(R.xml.preferences_snet_recent_recaptcha)\n        snetSummary = arguments?.get(\"summary\") as SafetyNetSummary\n    }\n\n    @SuppressLint(\"RestrictedApi\")\n    override fun onBindPreferences() {\n        val requestType: Preference = preferenceScreen.findPreference(\"pref_request_type\")!!\n        val time : Preference = preferenceScreen.findPreference(\"pref_time\")!!\n        val status : Preference = preferenceScreen.findPreference(\"pref_status\")!!\n        val token : Preference = preferenceScreen.findPreference(\"pref_token\")!!\n\n        requestType.summary = \"RECAPTCHA\"\n\n        time.summary = DateUtils.getRelativeDateTimeString(context, snetSummary.timestamp, DateUtils.MINUTE_IN_MILLIS, DateUtils.WEEK_IN_MILLIS, DateUtils.FORMAT_SHOW_TIME)\n\n\n        val snetResponseStatus = snetSummary.responseStatus\n        if (snetResponseStatus == null) {\n            status.summary = getString(R.string.pref_safetynet_test_not_completed)\n        } else {\n            status.summary = snetResponseStatus.statusMessage\n            token.summary = snetSummary.responseData\n        }\n    }\n\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/ui/SafetyNetUtils.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.ui\n\nimport android.content.Context\nimport android.graphics.drawable.Drawable\nimport android.util.Log\nimport androidx.core.content.ContextCompat\nimport com.google.android.gms.R\nimport com.google.android.gms.common.api.Status\nimport org.json.JSONObject\nimport org.microg.gms.fido.core.map\nimport org.microg.gms.safetynet.SafetyNetRequestType\n\nfun formatSummaryForSafetyNetResult(context: Context, result: String?, status: Status?, type: SafetyNetRequestType): Pair<String, Drawable?> {\n    when (type) {\n        SafetyNetRequestType.ATTESTATION -> {\n            if (status?.isSuccess != true) {\n                return context.getString(R.string.pref_test_summary_failed, status?.statusMessage) to\n                        ContextCompat.getDrawable(context, R.drawable.ic_circle_error)\n            }\n            if (result == null) {\n                return context.getString(R.string.pref_test_summary_failed, context.getString(R.string.pref_safetynet_test_no_result)) to\n                        ContextCompat.getDrawable(context, R.drawable.ic_circle_warn)\n            }\n            val (basicIntegrity, ctsProfileMatch, advice) = try {\n                JSONObject(result).let {\n                    Triple(\n                        it.optBoolean(\"basicIntegrity\", false),\n                        it.optBoolean(\"ctsProfileMatch\", false),\n                        it.optString(\"advice\", \"\")\n                    )\n                }\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n                return context.getString(\n                    R.string.pref_test_summary_failed,\n                    context.getString(R.string.pref_safetynet_test_invalid_json)\n                ) to ContextCompat.getDrawable(context, R.drawable.ic_circle_error)\n            }\n            val adviceText = if (advice == \"\") \"\" else \"\\n\" + advice.split(\",\").map {\n                when (it) {\n                    \"LOCK_BOOTLOADER\" -> \"Bootloader is not locked\"\n                    \"RESTORE_TO_FACTORY_ROM\" -> \"ROM is not clean\"\n                    else -> it\n                }\n            }.joinToString(\"\\n\")\n            return when {\n                basicIntegrity && ctsProfileMatch -> {\n                    context.getString(R.string.pref_test_summary_passed) to ContextCompat.getDrawable(context, R.drawable.ic_circle_check)\n                }\n                basicIntegrity -> {\n                    context.getString(\n                        R.string.pref_test_summary_warn,\n                        \"CTS profile does not match$adviceText\"\n                    ) to ContextCompat.getDrawable(context, R.drawable.ic_circle_warn)\n                }\n                else -> {\n                    context.getString(\n                        R.string.pref_test_summary_failed,\n                        \"integrity check failed$adviceText\"\n                    ) to ContextCompat.getDrawable(context, R.drawable.ic_circle_error)\n                }\n            }\n        }\n        SafetyNetRequestType.RECAPTCHA -> {\n            if (status?.isSuccess != true) {\n                return context.getString(R.string.pref_test_summary_failed, status?.statusMessage) to\n                        ContextCompat.getDrawable(context, R.drawable.ic_circle_error)\n            }\n            if (result == null) {\n                return context.getString(R.string.pref_test_summary_failed, context.getString(R.string.pref_safetynet_test_no_result)) to\n                        ContextCompat.getDrawable(context, R.drawable.ic_circle_warn)\n            }\n            val (success, errorCodes) = try {\n                JSONObject(result).let {\n                        it.optBoolean(\"success\", false) to\n                        it.optJSONArray(\"error-codes\")?.map { getString(it) }.orEmpty()\n                }\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n                true to emptyList()\n            }\n            return when {\n                success && errorCodes.isEmpty() -> {\n                    context.getString(R.string.pref_test_summary_passed) to ContextCompat.getDrawable(context, R.drawable.ic_circle_check)\n                }\n                success -> {\n                    context.getString(\n                        R.string.pref_test_summary_warn,\n                        errorCodes.joinToString()\n                    ) to ContextCompat.getDrawable(context, R.drawable.ic_circle_warn)\n                }\n                else -> {\n                    context.getString(\n                        R.string.pref_test_summary_failed,\n                        errorCodes.joinToString()\n                    ) to ContextCompat.getDrawable(context, R.drawable.ic_circle_error)\n                }\n            }\n        }\n        SafetyNetRequestType.RECAPTCHA_ENTERPRISE -> {\n            if (result == null) {\n                return context.getString(R.string.pref_test_summary_failed, context.getString(R.string.pref_safetynet_test_no_result)) to\n                        ContextCompat.getDrawable(context, R.drawable.ic_circle_warn)\n            }\n            val (valid, score, invalidReason) = try {\n                JSONObject(result).let {\n                    Triple(it.optJSONObject(\"tokenProperties\")?.optBoolean(\"valid\", false) ?: false,\n                            it.optJSONObject(\"riskAnalysis\")?.optString(\"score\", \"unknown\") ?: \"unknown\",\n                            it.optJSONObject(\"tokenProperties\")?.optString(\"invalidReason\"))\n                }\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n                Triple(true, \"unknown\", null)\n            }\n            return when {\n                valid && (score == \"unknown\" || score.toDoubleOrNull()?.let { it > 0.5 } == true)  -> {\n                    context.getString(R.string.pref_test_summary_passed) to ContextCompat.getDrawable(context, R.drawable.ic_circle_check)\n                }\n                valid && score.toDoubleOrNull()?.let { it > 0.1 } == true -> {\n                    context.getString(\n                        R.string.pref_test_summary_warn,\n                        \"score = $score\"\n                    ) to ContextCompat.getDrawable(context, R.drawable.ic_circle_warn)\n                }\n                else -> {\n                    context.getString(\n                        R.string.pref_test_summary_failed,\n                        invalidReason ?: \"score = $score\"\n                    ) to ContextCompat.getDrawable(context, R.drawable.ic_circle_error)\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/ui/SettingsFragment.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.ui\n\nimport android.os.Bundle\nimport android.util.Log\nimport androidx.lifecycle.lifecycleScope\nimport androidx.navigation.fragment.findNavController\nimport androidx.preference.Preference\nimport androidx.preference.PreferenceCategory\nimport com.google.android.gms.R\nimport org.microg.gms.checkin.CheckinPreferences\nimport org.microg.gms.gcm.GcmDatabase\nimport org.microg.gms.gcm.GcmPrefs\nimport org.microg.gms.safetynet.SafetyNetPreferences\nimport org.microg.gms.ui.settings.SettingsProvider\nimport org.microg.gms.ui.settings.getAllSettingsProviders\nimport org.microg.tools.ui.ResourceSettingsFragment\n\nclass SettingsFragment : ResourceSettingsFragment() {\n    private val createdPreferences = mutableListOf<Preference>()\n\n    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {\n        super.onCreatePreferences(savedInstanceState, rootKey)\n\n        findPreference<Preference>(PREF_ACCOUNTS)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener {\n            findNavController().navigate(requireContext(), R.id.accountManagerFragment)\n            true\n        }\n        findPreference<Preference>(PREF_CHECKIN)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener {\n            findNavController().navigate(requireContext(), R.id.openCheckinSettings)\n            true\n        }\n        findPreference<Preference>(PREF_GCM)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener {\n            findNavController().navigate(requireContext(), R.id.openGcmSettings)\n            true\n        }\n        findPreference<Preference>(PREF_SNET)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener {\n            findNavController().navigate(requireContext(), R.id.openSafetyNetSettings)\n            true\n        }\n        findPreference<Preference>(PREF_LOCATION)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener {\n            findNavController().navigate(requireContext(), R.id.openLocationSettings)\n            true\n        }\n        findPreference<Preference>(PREF_VENDING)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener {\n            findNavController().navigate(requireContext(), R.id.openVendingSettings)\n            true\n        }\n        findPreference<Preference>(PREF_WORK_PROFILE)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener {\n            findNavController().navigate(requireContext(), R.id.openWorkProfileSettings)\n            true\n        }\n\n        findPreference<Preference>(PREF_ABOUT)!!.apply {\n            onPreferenceClickListener = Preference.OnPreferenceClickListener {\n                findNavController().navigate(requireContext(), R.id.openAbout)\n                true\n            }\n            summary = getString(org.microg.tools.ui.R.string.about_version_str, AboutFragment.getSelfVersion(context))\n        }\n\n        for (entry in getAllSettingsProviders(requireContext()).flatMap { it.getEntriesStatic(requireContext()) }) {\n            entry.createPreference()\n        }\n    }\n\n    private fun SettingsProvider.Companion.Entry.createPreference(): Preference? {\n        val preference = Preference(requireContext()).fillFromEntry(this)\n        try {\n            if (findPreference<PreferenceCategory>(when (group) {\n                    SettingsProvider.Companion.Group.HEADER -> \"prefcat_header\"\n                    SettingsProvider.Companion.Group.GOOGLE -> \"prefcat_google_services\"\n                    SettingsProvider.Companion.Group.OTHER -> \"prefcat_other_services\"\n                    SettingsProvider.Companion.Group.FOOTER -> \"prefcat_footer\"\n                })?.addPreference(preference) == true) {\n                createdPreferences.add(preference)\n                return preference\n            } else {\n                Log.w(TAG, \"Preference not added $key\")\n            }\n        } catch (e: Exception) {\n            Log.w(TAG, \"Failed adding preference $key\", e)\n        }\n        return null\n    }\n\n    private fun Preference.fillFromEntry(entry: SettingsProvider.Companion.Entry): Preference {\n        key = entry.key\n        title = entry.title\n        summary = entry.summary\n        icon = entry.icon\n        isPersistent = false\n        isVisible = true\n        setOnPreferenceClickListener {\n            findNavController().navigate(requireContext(), entry.navigationId)\n            true\n        }\n        return this\n    }\n\n    override fun onResume() {\n        super.onResume()\n        val context = requireContext()\n        if (GcmPrefs.get(requireContext()).isEnabled) {\n            val database = GcmDatabase(context)\n            val regCount = database.registrationList.size\n            database.close()\n            findPreference<Preference>(PREF_GCM)!!.summary = context.getString(org.microg.gms.base.core.R.string.service_status_enabled_short) + \" - \" + context.resources.getQuantityString(R.plurals.gcm_registered_apps_counter, regCount, regCount)\n        } else {\n            findPreference<Preference>(PREF_GCM)!!.setSummary(org.microg.gms.base.core.R.string.service_status_disabled_short)\n        }\n\n        findPreference<Preference>(PREF_CHECKIN)!!.setSummary(if (CheckinPreferences.isEnabled(requireContext())) org.microg.gms.base.core.R.string.service_status_enabled_short else org.microg.gms.base.core.R.string.service_status_disabled_short)\n        findPreference<Preference>(PREF_SNET)!!.setSummary(if (SafetyNetPreferences.isEnabled(requireContext())) org.microg.gms.base.core.R.string.service_status_enabled_short else org.microg.gms.base.core.R.string.service_status_disabled_short)\n\n        lifecycleScope.launchWhenResumed {\n            val entries = getAllSettingsProviders(requireContext()).flatMap { it.getEntriesDynamic(requireContext()) }\n            for (preference in createdPreferences) {\n                if (!entries.any { it.key == preference.key }) preference.isVisible = false\n            }\n            for (entry in entries) {\n                val preference = createdPreferences.find { it.key == entry.key }\n                if (preference != null) preference.fillFromEntry(entry)\n                else entry.createPreference()\n            }\n        }\n    }\n\n    companion object {\n        const val PREF_ABOUT = \"pref_about\"\n        const val PREF_GCM = \"pref_gcm\"\n        const val PREF_SNET = \"pref_snet\"\n        const val PREF_LOCATION = \"pref_location\"\n        const val PREF_CHECKIN = \"pref_checkin\"\n        const val PREF_VENDING = \"pref_vending\"\n        const val PREF_WORK_PROFILE = \"pref_work_profile\"\n        const val PREF_ACCOUNTS = \"pref_accounts\"\n    }\n\n    init {\n        preferencesResource = R.xml.preferences_start\n    }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/ui/VendingFragment.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023, e Foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.ui\n\nimport android.annotation.SuppressLint\nimport android.os.Bundle\nimport android.view.Menu\nimport android.view.MenuInflater\nimport android.view.MenuItem\nimport androidx.lifecycle.lifecycleScope\nimport androidx.navigation.fragment.findNavController\nimport androidx.preference.Preference\nimport androidx.preference.PreferenceFragmentCompat\nimport androidx.preference.TwoStatePreference\nimport com.google.android.gms.R\nimport org.microg.gms.vending.VendingPreferences\n\nclass VendingFragment : PreferenceFragmentCompat() {\n    private lateinit var licensingEnabled: TwoStatePreference\n    private lateinit var licensingPurchaseFreeAppsEnabled: TwoStatePreference\n    private lateinit var licensingSplitInstallEnabled: TwoStatePreference\n    private lateinit var iapEnable: TwoStatePreference\n    private lateinit var assetDeliveryEnabled: TwoStatePreference\n    private lateinit var deviceSyncEnabled: TwoStatePreference\n\n    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {\n        addPreferencesFromResource(R.xml.preferences_vending)\n    }\n\n    @SuppressLint(\"RestrictedApi\")\n    override fun onBindPreferences() {\n        licensingEnabled = preferenceScreen.findPreference(PREF_LICENSING_ENABLED) ?: licensingEnabled\n        licensingEnabled.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->\n            val appContext = requireContext().applicationContext\n            lifecycleScope.launchWhenResumed {\n                if (newValue is Boolean) {\n                    VendingPreferences.setLicensingEnabled(appContext, newValue)\n                }\n                updateContent()\n            }\n            true\n        }\n\n        licensingPurchaseFreeAppsEnabled = preferenceScreen.findPreference(PREF_LICENSING_PURCHASE_FREE_APPS_ENABLED) ?: licensingPurchaseFreeAppsEnabled\n        licensingPurchaseFreeAppsEnabled.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->\n            val appContext = requireContext().applicationContext\n            lifecycleScope.launchWhenResumed {\n                if (newValue is Boolean) {\n                    VendingPreferences.setLicensingPurchaseFreeAppsEnabled(appContext, newValue)\n                }\n                updateContent()\n            }\n            true\n        }\n\n        licensingSplitInstallEnabled = preferenceScreen.findPreference(PREF_SPLIT_INSTALL_ENABLED) ?: licensingSplitInstallEnabled\n        licensingSplitInstallEnabled.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->\n            val appContext = requireContext().applicationContext\n            lifecycleScope.launchWhenResumed {\n                if (newValue is Boolean) {\n                    VendingPreferences.setSplitInstallEnabled(appContext, newValue)\n                }\n                updateContent()\n            }\n            true\n        }\n\n        iapEnable = preferenceScreen.findPreference(PREF_IAP_ENABLED) ?: iapEnable\n        iapEnable.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->\n            val appContext = requireContext().applicationContext\n            lifecycleScope.launchWhenResumed {\n                if (newValue is Boolean) {\n                    VendingPreferences.setBillingEnabled(appContext, newValue)\n                }\n                updateContent()\n            }\n            true\n        }\n\n        assetDeliveryEnabled = preferenceScreen.findPreference(PREF_ASSET_DELIVERY_ENABLED) ?: assetDeliveryEnabled\n        assetDeliveryEnabled.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->\n            val appContext = requireContext().applicationContext\n            lifecycleScope.launchWhenResumed {\n                if (newValue is Boolean) {\n                    VendingPreferences.setAssetDeliveryEnabled(appContext, newValue)\n                }\n                updateContent()\n            }\n            true\n        }\n\n        deviceSyncEnabled = preferenceScreen.findPreference(PREF_DEVICE_SYNC_ENABLED) ?: deviceSyncEnabled\n        deviceSyncEnabled.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->\n            val appContext = requireContext().applicationContext\n            lifecycleScope.launchWhenResumed {\n                if (newValue is Boolean) {\n                    VendingPreferences.setDeviceSyncEnabled(appContext, newValue)\n                }\n                updateContent()\n            }\n            true\n        }\n    }\n\n    override fun onResume() {\n        super.onResume()\n        updateContent()\n    }\n\n    private fun updateContent() {\n        val appContext = requireContext().applicationContext\n        lifecycleScope.launchWhenResumed {\n            licensingEnabled.isChecked = VendingPreferences.isLicensingEnabled(appContext)\n            licensingPurchaseFreeAppsEnabled.isChecked = VendingPreferences.isLicensingPurchaseFreeAppsEnabled(appContext)\n            licensingSplitInstallEnabled.isChecked = VendingPreferences.isLicensingSplitInstallEnabled(appContext)\n            iapEnable.isChecked = VendingPreferences.isBillingEnabled(appContext)\n            assetDeliveryEnabled.isChecked = VendingPreferences.isAssetDeliveryEnabled(appContext)\n            deviceSyncEnabled.isChecked = VendingPreferences.isDeviceSyncEnabled(appContext)\n        }\n    }\n\n    init {\n        setHasOptionsMenu(true)\n    }\n\n    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {\n        menu.add(0, MENU_INSTALL_MANAGED, 0, R.string.pref_app_install_settings_title)\n        super.onCreateOptionsMenu(menu, inflater)\n    }\n\n    override fun onOptionsItemSelected(item: MenuItem): Boolean {\n        return when (item.itemId) {\n            MENU_INSTALL_MANAGED -> {\n                findNavController().navigate(requireContext(), R.id.openVendingInstallSettings)\n                true\n            }\n\n            else -> super.onOptionsItemSelected(item)\n        }\n    }\n    companion object {\n        private const val MENU_INSTALL_MANAGED = Menu.FIRST\n        const val PREF_LICENSING_ENABLED = \"vending_licensing\"\n        const val PREF_LICENSING_PURCHASE_FREE_APPS_ENABLED = \"vending_licensing_purchase_free_apps\"\n        const val PREF_SPLIT_INSTALL_ENABLED = \"vending_split_install\"\n        const val PREF_IAP_ENABLED = \"vending_iap\"\n        const val PREF_ASSET_DELIVERY_ENABLED = \"vending_asset_delivery\"\n        const val PREF_DEVICE_SYNC_ENABLED = \"vending_device_sync\"\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/ui/VendingInstallSettingsFragment.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.ui\n\nimport android.os.Bundle\nimport androidx.lifecycle.lifecycleScope\nimport androidx.preference.Preference\nimport androidx.preference.PreferenceCategory\nimport androidx.preference.PreferenceFragmentCompat\nimport androidx.preference.SwitchPreference\nimport com.google.android.gms.R\nimport org.microg.gms.utils.getApplicationLabel\nimport org.microg.gms.vending.AllowType\nimport org.microg.gms.vending.InstallerData\nimport org.microg.gms.vending.VendingPreferences\n\nclass VendingInstallSettingsFragment : PreferenceFragmentCompat() {\n    private lateinit var switchBarPreference: SwitchBarPreference\n    private lateinit var installers: PreferenceCategory\n    private lateinit var none: Preference\n\n    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {\n        addPreferencesFromResource(R.xml.preferences_vending_installer_settings)\n\n        switchBarPreference = preferenceScreen.findPreference(\"pref_vending_allow_install_apps\") ?: switchBarPreference\n        installers = preferenceScreen.findPreference(\"pref_permission_installer_settings\") ?: installers\n        none = preferenceScreen.findPreference(\"pref_permission_installer_none\") ?: none\n\n        switchBarPreference.setOnPreferenceChangeListener { _, newValue ->\n            val appContext = requireContext().applicationContext\n            lifecycleScope.launchWhenResumed {\n                if (newValue is Boolean) {\n                    VendingPreferences.setInstallEnabled(appContext, newValue)\n                }\n                updateContent()\n            }\n            true\n        }\n    }\n\n    override fun onResume() {\n        super.onResume()\n        updateContent()\n    }\n\n    fun updateContent() {\n        val appContext = requireContext().applicationContext\n        lifecycleScope.launchWhenResumed {\n            installers.isVisible = VendingPreferences.isInstallEnabled(appContext)\n            switchBarPreference.isChecked = VendingPreferences.isInstallEnabled(appContext)\n            val installerList = VendingPreferences.getInstallerList(appContext)\n            val installerDataSet = InstallerData.loadDataSet(installerList)\n            val installerViews = installerDataSet.mapNotNull {\n                runCatching {\n                    SwitchPreference(appContext).apply {\n                        key = \"pref_permission_channels_${it.packageName}\"\n                        title = appContext.packageManager.getApplicationLabel(it.packageName)\n                        icon = appContext.packageManager.getApplicationIcon(it.packageName)\n                        isChecked = it.allowType == AllowType.ALLOW_ALWAYS.value\n                        setOnPreferenceChangeListener { _, newValue ->\n                            lifecycleScope.launchWhenResumed {\n                                if (newValue is Boolean) {\n                                    val allowType = if (newValue) AllowType.ALLOW_ALWAYS.value else AllowType.REJECT_ALWAYS.value\n                                    val content = InstallerData.updateDataSetString(installerDataSet, it.apply { this.allowType = allowType })\n                                    VendingPreferences.setInstallerList(appContext, content)\n                                }\n                            }\n                            true\n                        }\n                    }\n                }.getOrNull()\n            }\n            installers.removeAll()\n            for (installerView in installerViews) {\n                installers.addPreference(installerView)\n            }\n            if (installerViews.isEmpty()) {\n                installers.addPreference(none)\n            }\n        }\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/ui/WorkProfileFragment.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023, e Foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.ui\n\nimport android.annotation.SuppressLint\nimport android.os.Bundle\nimport androidx.lifecycle.lifecycleScope\nimport androidx.preference.Preference\nimport androidx.preference.PreferenceFragmentCompat\nimport androidx.preference.TwoStatePreference\nimport com.google.android.gms.R\nimport org.microg.gms.vending.VendingPreferences\nimport org.microg.gms.workprofile.WorkProfilePreferences\n\nclass WorkProfileFragment : PreferenceFragmentCompat() {\n    private lateinit var workProfileEnabled: SwitchBarPreference\n\n    private lateinit var workProfilePreferences: WorkProfilePreferences\n\n    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {\n        addPreferencesFromResource(R.xml.preferences_work_profile)\n    }\n\n    @SuppressLint(\"RestrictedApi\")\n    override fun onBindPreferences() {\n\n        workProfilePreferences = WorkProfilePreferences(requireContext().applicationContext)\n\n        workProfileEnabled = preferenceScreen.findPreference(PREF_CREATE_ACCOUNT) ?: workProfileEnabled\n        workProfileEnabled.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->\n            lifecycleScope.launchWhenResumed {\n                if (newValue is Boolean) {\n                    workProfilePreferences.allowCreateWorkAccount = newValue\n                }\n                updateContent()\n            }\n            true\n        }\n    }\n\n    override fun onResume() {\n        super.onResume()\n        updateContent()\n    }\n\n    private fun updateContent() {\n        lifecycleScope.launchWhenResumed {\n            workProfileEnabled.isChecked = workProfilePreferences.allowCreateWorkAccount\n        }\n    }\n\n    companion object {\n        const val PREF_CREATE_ACCOUNT = \"workprofile_allow_create_work_account\"\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/usagereporting/UsageReportingService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.usagereporting\n\nimport android.os.Bundle\nimport android.os.Parcel\nimport android.util.Log\nimport com.google.android.gms.common.Feature\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.internal.ConnectionInfo\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport com.google.android.gms.usagereporting.UsageReportingOptInOptions\nimport com.google.android.gms.usagereporting.internal.IUsageReportingCallbacks\nimport com.google.android.gms.usagereporting.internal.IUsageReportingOptInOptionsChangedListener\nimport com.google.android.gms.usagereporting.internal.IUsageReportingService\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.utils.warnOnTransactionIssues\n\nprivate const val TAG = \"UsageReportingService\"\n\nclass UsageReportingService : BaseService(TAG, GmsService.USAGE_REPORTING) {\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        callback.onPostInitCompleteWithConnectionInfo(CommonStatusCodes.SUCCESS, UsageReportingServiceImpl(), ConnectionInfo().apply {\n            features = arrayOf(\n                Feature(\"usage_and_diagnostics_listener\", 1),\n                Feature(\"usage_and_diagnostics_consents\", 1)\n            )\n        })\n    }\n}\n\nclass UsageReportingServiceImpl : IUsageReportingService.Stub() {\n    override fun getOptInOptions(callbacks: IUsageReportingCallbacks) {\n        // Don't log to prevent log spam\n        callbacks.onOptInOptions(Status.SUCCESS, UsageReportingOptInOptions().apply { optInUsageReporting = 2 })\n    }\n\n    override fun setOptInOptions(options: UsageReportingOptInOptions, callbacks: IUsageReportingCallbacks) {\n        Log.d(TAG, \"setOptInOptions($options)\")\n        callbacks.onOptInOptionsSet(Status.SUCCESS)\n    }\n\n    override fun addOptInOptionsChangedListener(listener: IUsageReportingOptInOptionsChangedListener, callbacks: IUsageReportingCallbacks) {\n        Log.d(TAG, \"addOptInOptionsChangedListener($listener)\")\n        callbacks.onOptInOptionsChangedListenerAdded(Status.SUCCESS)\n    }\n\n    override fun removeOptInOptionsChangedListener(listener: IUsageReportingOptInOptionsChangedListener, callbacks: IUsageReportingCallbacks) {\n        Log.d(TAG, \"removeOptInOptionsChangedListener($listener)\")\n        callbacks.onOptInOptionsChangedListenerRemoved(Status.SUCCESS)\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n}\n"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/vending/VendingPreferences.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023, e Foundation\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.vending\n\nimport android.content.Context\nimport org.microg.gms.settings.SettingsContract\n\nobject VendingPreferences {\n    @JvmStatic\n    fun isLicensingEnabled(context: Context): Boolean {\n        val projection = arrayOf(SettingsContract.Vending.LICENSING)\n        return SettingsContract.getSettings(context, SettingsContract.Vending.getContentUri(context), projection) { c ->\n            c.getInt(0) != 0\n        }\n    }\n\n    @JvmStatic\n    fun setLicensingEnabled(context: Context, enabled: Boolean) {\n        SettingsContract.setSettings(context, SettingsContract.Vending.getContentUri(context)) {\n            put(SettingsContract.Vending.LICENSING, enabled)\n        }\n    }\n\n    @JvmStatic\n    fun isLicensingPurchaseFreeAppsEnabled(context: Context): Boolean {\n        val projection = arrayOf(SettingsContract.Vending.LICENSING_PURCHASE_FREE_APPS)\n        return SettingsContract.getSettings(context, SettingsContract.Vending.getContentUri(context), projection) { c ->\n            c.getInt(0) != 0\n        }\n    }\n\n    @JvmStatic\n    fun setLicensingPurchaseFreeAppsEnabled(context: Context, enabled: Boolean) {\n        SettingsContract.setSettings(context, SettingsContract.Vending.getContentUri(context)) {\n            put(SettingsContract.Vending.LICENSING_PURCHASE_FREE_APPS, enabled)\n        }\n    }\n\n    @JvmStatic\n    fun isLicensingSplitInstallEnabled(context: Context): Boolean {\n        val projection = arrayOf(SettingsContract.Vending.SPLIT_INSTALL)\n        return SettingsContract.getSettings(context, SettingsContract.Vending.getContentUri(context), projection) { c ->\n            c.getInt(0) != 0\n        }\n    }\n\n    @JvmStatic\n    fun setSplitInstallEnabled(context: Context, enabled: Boolean) {\n        SettingsContract.setSettings(context, SettingsContract.Vending.getContentUri(context)) {\n            put(SettingsContract.Vending.SPLIT_INSTALL, enabled)\n        }\n    }\n\n    @JvmStatic\n    fun isBillingEnabled(context: Context): Boolean {\n        val projection = arrayOf(SettingsContract.Vending.BILLING)\n        return SettingsContract.getSettings(context, SettingsContract.Vending.getContentUri(context), projection) { c ->\n            c.getInt(0) != 0\n        }\n    }\n\n    @JvmStatic\n    fun setBillingEnabled(context: Context, enabled: Boolean) {\n        SettingsContract.setSettings(context, SettingsContract.Vending.getContentUri(context)) {\n            put(SettingsContract.Vending.BILLING, enabled)\n        }\n    }\n\n    @JvmStatic\n    fun isAssetDeliveryEnabled(context: Context): Boolean {\n        val projection = arrayOf(SettingsContract.Vending.ASSET_DELIVERY)\n        return SettingsContract.getSettings(context, SettingsContract.Vending.getContentUri(context), projection) { c ->\n            c.getInt(0) != 0\n        }\n    }\n\n    @JvmStatic\n    fun setAssetDeliveryEnabled(context: Context, enabled: Boolean) {\n        SettingsContract.setSettings(context, SettingsContract.Vending.getContentUri(context)) {\n            put(SettingsContract.Vending.ASSET_DELIVERY, enabled)\n        }\n    }\n\n    @JvmStatic\n    fun isDeviceSyncEnabled(context: Context): Boolean {\n        val projection = arrayOf(SettingsContract.Vending.ASSET_DEVICE_SYNC)\n        return SettingsContract.getSettings(context, SettingsContract.Vending.getContentUri(context), projection) { c ->\n            c.getInt(0) != 0\n        }\n    }\n\n    @JvmStatic\n    fun setDeviceSyncEnabled(context: Context, enabled: Boolean) {\n        SettingsContract.setSettings(context, SettingsContract.Vending.getContentUri(context)) {\n            put(SettingsContract.Vending.ASSET_DEVICE_SYNC, enabled)\n        }\n    }\n\n    @JvmStatic\n    fun isInstallEnabled(context: Context): Boolean {\n        val projection = arrayOf(SettingsContract.Vending.APPS_INSTALL)\n        return SettingsContract.getSettings(context, SettingsContract.Vending.getContentUri(context), projection) { c ->\n            c.getInt(0) != 0\n        }\n    }\n\n    @JvmStatic\n    fun setInstallEnabled(context: Context, enabled: Boolean) {\n        SettingsContract.setSettings(context, SettingsContract.Vending.getContentUri(context)) {\n            put(SettingsContract.Vending.APPS_INSTALL, enabled)\n        }\n    }\n\n    @JvmStatic\n    fun getInstallerList(context: Context): String {\n        val projection = arrayOf(SettingsContract.Vending.APPS_INSTALLER_LIST)\n        return SettingsContract.getSettings(context, SettingsContract.Vending.getContentUri(context), projection) { c ->\n            c.getString(0)\n        }\n    }\n\n    @JvmStatic\n    fun setInstallerList(context: Context, content: String) {\n        SettingsContract.setSettings(context, SettingsContract.Vending.getContentUri(context)) {\n            put(SettingsContract.Vending.APPS_INSTALLER_LIST, content)\n        }\n    }\n\n    @JvmStatic\n    fun getPlayIntegrityAppList(context: Context): String {\n        val projection = arrayOf(SettingsContract.Vending.PLAY_INTEGRITY_APP_LIST)\n        return SettingsContract.getSettings(context, SettingsContract.Vending.getContentUri(context), projection) { c ->\n            c.getString(0)\n        }\n    }\n\n    @JvmStatic\n    fun setPlayIntegrityAppList(context: Context, content: String) {\n        SettingsContract.setSettings(context, SettingsContract.Vending.getContentUri(context)) {\n            put(SettingsContract.Vending.PLAY_INTEGRITY_APP_LIST, content)\n        }\n    }\n}"
  },
  {
    "path": "play-services-core/src/main/kotlin/org/microg/gms/workprofile/WorkProfilePreferences.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.workprofile\n\nimport android.content.ContentValues\nimport android.content.Context\nimport android.database.Cursor\nimport org.microg.gms.settings.SettingsContract\nimport org.microg.gms.settings.SettingsContract.CheckIn\n\nclass WorkProfilePreferences(private val context: Context) {\n    private fun <T> getSettings(vararg projection: String, f: (Cursor) -> T): T =\n        SettingsContract.getSettings(\n            context,\n            SettingsContract.WorkProfile.getContentUri(context),\n            projection,\n            f\n        )\n\n    private fun setSettings(v: ContentValues.() -> Unit) =\n        SettingsContract.setSettings(context, SettingsContract.WorkProfile.getContentUri(context), v)\n\n    var allowCreateWorkAccount: Boolean\n        get() = getSettings(SettingsContract.WorkProfile.CREATE_WORK_ACCOUNT) { c -> c.getInt(0) != 0 }\n        set(value) = setSettings { put(SettingsContract.WorkProfile.CREATE_WORK_ACCOUNT, value) }\n\n}"
  },
  {
    "path": "play-services-core/src/main/res/color/material_switch_bar_text_color.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2024 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_enabled=\"false\" android:color=\"?attr/colorOnSecondaryContainer\" android:alpha=\"?android:attr/disabledAlpha\" />\n    <item android:color=\"?attr/colorOnSecondaryContainer\" />\n</selector>"
  },
  {
    "path": "play-services-core/src/main/res/color/preference_material_switch_color.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:color=\"@android:color/white\" android:state_checked=\"true\" />\n    <item android:color=\"@android:color/darker_gray\"/>\n</selector>\n"
  },
  {
    "path": "play-services-core/src/main/res/drawable/circle_shape_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"oval\">\n    <solid android:color=\"@color/dialog_border_color\" />\n</shape>"
  },
  {
    "path": "play-services-core/src/main/res/drawable/dots_horizontal.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2019, The Android Open Source Project\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\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=\"#000000\"\n        android:pathData=\"M16,12A2,2 0 0,1 18,10A2,2 0 0,1 20,12A2,2 0 0,1 18,14A2,2 0 0,1 16,12M10,12A2,2\n0 0,1 12,10A2,2 0 0,1 14,12A2,2 0 0,1 12,14A2,2 0 0,1 10,12M4,12A2,2 0 0,1\n6,10A2,2 0 0,1 8,12A2,2 0 0,1 6,14A2,2 0 0,1 4,12Z\" />\n</vector>\n"
  },
  {
    "path": "play-services-core/src/main/res/drawable/ic_achievement_locked.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\" android:height=\"56dp\" android:width=\"56dp\" android:viewportWidth=\"56\" android:viewportHeight=\"56\">\n    <path android:fillColor=\"#f8f9fa\" android:pathData=\"M 8 0.3 L 48 0.3 Q 55.7 0.3 55.7 8 L 55.7 48 Q 55.7 55.7 48 55.7 L 8 55.7 Q 0.3 55.7 0.3 48 L 0.3 8 Q 0.3 0.3 8 0.3 Z\" android:strokeColor=\"#dadce0\" android:strokeWidth=\"0.6\" android:fillType=\"evenOdd\"/>\n    <path android:fillColor=\"#9aa0a6\" android:pathData=\"M39.3968,15.6826 L16.5397,15.6826 C15.1429,15.6826 14,16.8254 14,18.2222 L14,22.0318 C14,23.4286 15.1429,24.5714 16.5397,24.5714 L19.0794,24.5714 L19.0794,28.381 C19.0794,31.1873 21.3524,33.4603 24.1587,33.4603 L25.4286,33.4603 L25.4286,38.5397 L21.619,38.5397 L21.619,41.0794 L34.3175,41.0794 L34.3175,38.5397 L30.5079,38.5397 L30.5079,33.4603 L31.7778,33.4603 C34.5841,33.4603 36.8571,31.1873 36.8571,28.381 L36.8571,24.5714 L39.3968,24.5714 C40.7937,24.5714 41.9365,23.4286 41.9365,22.0318 L41.9365,18.2222 C41.9365,16.8254 40.7937,15.6826 39.3968,15.6826 Z M16.5397,22.0318 L16.5397,18.2222 L19.0794,18.2222 L19.0794,22.0318 L16.5397,22.0318 Z M36.8571,22.0318 L39.3968,22.0318 L39.3968,18.2222 L36.8571,18.2222 L36.8571,22.0318 Z\" android:strokeWidth=\"1\" android:fillType=\"evenOdd\"/>\n</vector>"
  },
  {
    "path": "play-services-core/src/main/res/drawable/ic_achievement_logo.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\" android:height=\"284dp\" android:width=\"277dp\" android:viewportWidth=\"277\" android:viewportHeight=\"284\">\n    <path android:fillColor=\"#fdd835\" android:pathData=\"M 132.349537 153.415868 L 154.59016 145.373655 L 174.591978 200.688388 L 152.351355 208.730601 Z\" android:strokeWidth=\"1\" android:fillType=\"evenOdd\"/>\n    <path android:fillColor=\"#fdd835\" android:pathData=\"M100.033951,171.280456 C73.4064296,180.901092 44.0184898,167.135704 34.363951,140.520456 L32.933951,136.570456 L129.363951,101.710456 L130.793951,105.660456 C140.381728,132.273285 126.622532,161.625639 100.033951,171.280456 Z M44.0244105,141.42119 C53.5333097,161.294506 76.5471759,170.737754 97.2744105,163.27119 C117.99741,155.769966 129.6683,133.78979 124.27441,112.42119 L44.0244105,141.42119 Z\" android:strokeWidth=\"1\"/>\n    <path android:fillColor=\"#fdd835\" android:pathData=\"M190.14457,138.482873 C163.517049,148.103508 134.129109,134.33812 124.47457,107.722873 L123.04457,103.772873 L219.47457,68.9128728 L220.90457,72.8628728 C230.492347,99.4757021 216.733152,128.828056 190.14457,138.482873 Z M134.13503,108.623607 C143.643929,128.496922 166.657795,137.940171 187.38503,130.473607 C208.10803,122.972383 219.77892,100.992206 214.38503,79.623607 L134.13503,108.623607 Z\" android:strokeWidth=\"1\"/>\n    <path android:fillColor=\"#fbbc04\" android:pathData=\"M 136.280505 164.330441 L 158.521128 156.288228 L 166.485129 178.312557 L 144.244506 186.354771 Z\" android:strokeWidth=\"1\" android:fillType=\"evenOdd\"/>\n    <path android:fillColor=\"#fdd835\" android:pathData=\"M60.8775401,111.340688 L182.566191,67.3380485 L189.867093,87.5285843 C202.018086,121.131977 184.62748,158.223236 151.024087,170.374229 C117.420694,182.525223 80.3294349,165.134617 68.1784417,131.531223 L60.8775401,111.340688 Z\" android:strokeWidth=\"1\" android:fillType=\"evenOdd\"/>\n    <path android:fillColor=\"#fdd835\" android:pathData=\"M 135.179512 209.299963 L 188.143228 190.148273 L 193.233796 204.226164 L 140.27008 223.377854 Z\" android:strokeWidth=\"1\" android:fillType=\"evenOdd\"/>\n    <path android:fillColor=\"#fdd835\" android:pathData=\"M 121.431985 225.640814 L 209.15314 193.920828 L 214.243708 207.998719 L 126.522553 239.718705 Z\" android:strokeWidth=\"1\" android:fillType=\"evenOdd\"/>\n    <path android:fillColor=\"#fffde7\" android:pathData=\"M 124.284569 226.766172 L 152.475348 216.505568 L 154.527469 222.143723 L 126.33669 232.404328 Z\" android:strokeWidth=\"1\"/>\n    <path android:fillColor=\"#fdd835\" android:pathData=\"M 99.857656 259.815435 L 102.602334 261.611304 L 88.4823336 283.191304 L 85.737656 281.395435 Z\" android:strokeWidth=\"1\"/>\n    <path android:fillColor=\"#fdd835\" android:pathData=\"M 97.7522612 26.2256827 L 94.6677283 27.3410556 L 85.4577283 1.87105562 L 88.5422612 0.755682712 Z\" android:strokeWidth=\"1\"/>\n    <path android:fillColor=\"#fdd835\" android:pathData=\"M 25.7005087 94.6653429 L 24.7394808 97.8013954 L 0.0694808444 90.2413954 L 1.0305087 87.1053429 Z\" android:strokeWidth=\"1\"/>\n    <path android:fillColor=\"#fdd835\" android:pathData=\"M 198.512524 35.5410123 L 195.767465 33.7457261 L 209.887465 12.1557261 L 212.632524 13.9510123 Z\" android:strokeWidth=\"1\"/>\n    <path android:fillColor=\"#fdd835\" android:pathData=\"M 240.699481 211.681395 L 241.660509 208.545343 L 266.330509 216.105343 L 265.369481 219.241395 Z\" android:strokeWidth=\"1\"/>\n    <path android:fillColor=\"#fdd835\" android:pathData=\"M 36.2927128 197.100957 L 37.4072767 200.185782 L 11.6672767 209.485782 L 10.5527128 206.400957 Z\" android:strokeWidth=\"1\"/>\n    <path android:fillColor=\"#fdd835\" android:pathData=\"M 275.802713 110.500957 L 276.917277 113.585782 L 251.177277 122.885782 L 250.062713 119.800957 Z\" android:strokeWidth=\"1\"/>\n    <path android:fillColor=\"#fff59d\" android:pathData=\"M 156.015859 82.9851453 L 157.464131 82.461593 L 172.394131 123.761593 L 170.945859 124.285145 Z\" android:strokeWidth=\"1\"/>\n    <path android:fillColor=\"#fff59d\" android:pathData=\"M 143.821827 111.557485 L 143.298163 110.109253 L 184.588163 95.1792532 L 185.111827 96.6274851 Z\" android:strokeWidth=\"1\"/>\n    <path android:fillColor=\"#fff59d\" android:pathData=\"M 144.003077 94.7505241 L 144.656912 93.3562142 L 184.406912 111.996214 L 183.753077 113.390524 Z\" android:strokeWidth=\"1\"/>\n    <path android:fillColor=\"#fff59d\" android:pathData=\"M 155.577114 123.580363 L 154.182876 122.926375 L 172.832876 83.1663754 L 174.227114 83.8203629 Z\" android:strokeWidth=\"1\"/>\n    <path android:fillColor=\"#fff59d\" android:pathData=\"M 140.545547 132.260667 L 141.194442 132.026072 L 147.904442 150.586072 L 147.255547 150.820667 Z\" android:strokeWidth=\"1\"/>\n    <path android:pathData=\"M134.939995,144.783369 L153.509995,138.073369\" android:strokeColor=\"#fff59d\" android:strokeWidth=\"0.69\" android:fillType=\"evenOdd\"/>\n    <path android:fillColor=\"#fff59d\" android:pathData=\"M 135.057237 145.107837 L 134.822753 144.458901 L 153.392753 137.748901 L 153.627237 138.397837 Z\" android:strokeWidth=\"1\"/>\n    <path android:fillColor=\"#fff59d\" android:pathData=\"M 135.143516 137.545729 L 135.436474 136.921009 L 153.306474 145.301009 L 153.013516 145.925729 Z\" android:strokeWidth=\"1\"/>\n    <path android:fillColor=\"#fff59d\" android:pathData=\"M 140.342355 150.509848 L 139.717635 150.21689 L 148.097635 132.34689 L 148.722355 132.639848 Z\" android:strokeWidth=\"1\"/>\n    <path android:fillColor=\"#fffde7\" android:pathData=\"M 93.0544119 121.255951 L 99.9855777 118.750788 L 107.745578 140.220788 L 100.814412 142.725951 Z\" android:strokeWidth=\"1\"/>\n</vector>"
  },
  {
    "path": "play-services-core/src/main/res/drawable/ic_achievement_unlocked.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\" android:height=\"56dp\" android:width=\"56dp\" android:viewportWidth=\"56\" android:viewportHeight=\"56\">\n    <path android:fillColor=\"#ffffff\" android:pathData=\"M 8 0.3 L 48 0.3 Q 55.7 0.3 55.7 8 L 55.7 48 Q 55.7 55.7 48 55.7 L 8 55.7 Q 0.3 55.7 0.3 48 L 0.3 8 Q 0.3 0.3 8 0.3 Z\" android:strokeWidth=\"1\" android:fillType=\"evenOdd\"/>\n    <path android:fillColor=\"#ffee58\" android:pathData=\"M 8 0.3 L 48 0.3 Q 55.7 0.3 55.7 8 L 55.7 48 Q 55.7 55.7 48 55.7 L 8 55.7 Q 0.3 55.7 0.3 48 L 0.3 8 Q 0.3 0.3 8 0.3 Z\" android:strokeWidth=\"1\" android:strokeAlpha=\"0.05\" android:fillAlpha=\"0.05\" android:fillType=\"evenOdd\"/>\n    <path android:pathData=\"M 8 0.3 L 48 0.3 Q 55.7 0.3 55.7 8 L 55.7 48 Q 55.7 55.7 48 55.7 L 8 55.7 Q 0.3 55.7 0.3 48 L 0.3 8 Q 0.3 0.3 8 0.3 Z\" android:strokeColor=\"#ffee58\" android:strokeWidth=\"0.6\" android:fillType=\"evenOdd\"/>\n    <path android:fillColor=\"#ffee58\" android:pathData=\"M28,15.6826 L28,41.0794 L21.619,41.0794 L21.619,38.5397 L25.4286,38.5397 L25.4286,33.4603 L24.1587,33.4603 C21.3524,33.4603 19.0794,31.1873 19.0794,28.381 L19.0794,24.5714 L16.5397,24.5714 C15.1429,24.5714 14,23.4286 14,22.0318 L14,18.2222 C14,16.8254 15.1429,15.6826 16.5397,15.6826 L28,15.6826 Z M16.5397,22.0318 L19.0794,22.0318 L19.0794,18.2222 L16.5397,18.2222 L16.5397,22.0318 Z\" android:strokeWidth=\"1\" android:fillType=\"evenOdd\"/>\n    <path android:fillColor=\"#fdd835\" android:pathData=\"M28,15.6826 L39.4603,15.6826 C40.8571,15.6826 42,16.8254 42,18.2222 L42,22.0318 C42,23.4286 40.8571,24.5714 39.4603,24.5714 L36.9206,24.5714 L36.9206,28.381 C36.9206,31.1873 34.6476,33.4603 31.8413,33.4603 L30.5714,33.4603 L30.5714,38.5397 L34.381,38.5397 L34.381,41.0794 L28,41.0794 L28,15.6826 Z M39.4603,22.0318 L39.4603,18.2222 L36.9206,18.2222 L36.9206,22.0318 L39.4603,22.0318 Z\" android:strokeWidth=\"1\" android:fillType=\"evenOdd\"/>\n</vector>"
  },
  {
    "path": "play-services-core/src/main/res/drawable/ic_add.xml",
    "content": "<!--\n  ~ SPDX-FileCopyrightText: 2019 The Android Open Source Project\n  ~ SPDX-FileCopyrightText: 2024 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<vector android:height=\"24dp\"\n    android:tint=\"?attr/colorControlNormal\"\n    android:viewportHeight=\"24\"\n    android:viewportWidth=\"24\"\n    android:width=\"24dp\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path\n        android:fillColor=\"#000\"\n        android:pathData=\"M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z\" />\n</vector>\n"
  },
  {
    "path": "play-services-core/src/main/res/drawable/ic_add_account.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2019, The Android Open Source Project\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\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=\"#000\"\n        android:pathData=\"M15,12 C17.21,12,19,10.21,19,8 S17.21,4,15,4 S11,5.79,11,8 S12.79,12,15,12 Z M6,10 L6,7 L4,7 L4,10 L1,10 L1,12 L4,12 L4,15 L6,15 L6,12 L9,12 L9,10 L6,10 Z M15,14 C12.33,14,7,15.34,7,18 L7,20 L23,20 L23,18 C23,15.34,17.67,14,15,14 Z\" />\n</vector>\n"
  },
  {
    "path": "play-services-core/src/main/res/drawable/ic_add_account_alt.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"?attr/color\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <group\n        android:scaleX=\"0.75\"\n        android:scaleY=\"0.75\"\n        android:translateX=\"4\"\n        android:translateY=\"4\">\n        <path android:fillColor=\"#050505\" android:pathData=\"M13,8c0,-2.21 -1.79,-4 -4,-4S5,5.79 5,8s1.79,4 4,4S13,10.21 13,8zM11,8c0,1.1 -0.9,2 -2,2S7,9.1 7,8s0.9,-2 2,-2S11,6.9 11,8zM1,18v2h16v-2c0,-2.66 -5.33,-4 -8,-4S1,15.34 1,18zM3,18c0.2,-0.71 3.3,-2 6,-2c2.69,0 5.78,1.28 6,2H3zM20,15v-3h3v-2h-3V7h-2v3h-3v2h3v3H20z\"/>\n    </group>\n</vector>\n"
  },
  {
    "path": "play-services-core/src/main/res/drawable/ic_arrow_back.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\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    <path\n        android:fillColor=\"#FFFFFF\"\n        android:pathData=\"M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z\" />\n</vector>"
  },
  {
    "path": "play-services-core/src/main/res/drawable/ic_arrow_close.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\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    <path\n        android:fillColor=\"#FF000000\"\n        android:pathData=\"M18,7.41L16.59,6 12,10.59 7.41,6 6,7.41 10.59,12 6,16.59 7.41,18 12,13.41 16.59,18 18,16.59 13.41,12z\"/>\n</vector>"
  },
  {
    "path": "play-services-core/src/main/res/drawable/ic_arrow_right.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\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    <path\n        android:fillColor=\"#000000\"\n        android:pathData=\"M8.59,16.59L13.17,12 8.59,7.41 10,6l6,6-6,6z\"/>\n</vector>"
  },
  {
    "path": "play-services-core/src/main/res/drawable/ic_bg_circle_gray.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"oval\">\n    <solid android:color=\"#F0F0F0\" />\n    <stroke android:width=\"1dp\" android:color=\"#DDDDDD\" />\n</shape>"
  },
  {
    "path": "play-services-core/src/main/res/drawable/ic_bg_prompt.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item>\n        <shape android:shape=\"rectangle\">\n            <solid android:color=\"#20000000\" />\n            <corners android:radius=\"90dp\" />\n        </shape>\n    </item>\n    <item android:top=\"2dp\" android:left=\"2dp\" android:right=\"2dp\" android:bottom=\"2dp\">\n        <shape android:shape=\"rectangle\">\n            <solid android:color=\"#F9FFFFFF\" />\n            <corners android:radius=\"90dp\" />\n        </shape>\n    </item>\n</layer-list>"
  },
  {
    "path": "play-services-core/src/main/res/drawable/ic_certificate.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, Simran\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\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=\"#000\"\n        android:pathData=\"M4,3C2.89,3 2,3.89 2,5V15A2,2 0 0,0 4,17H12V22L15,19L18,22V17H20A2,2 0 0,0\n22,15V8L22,6V5A2,2 0 0,0\n20,3H16V3H4M12,5L15,7L18,5V8.5L21,10L18,11.5V15L15,13L12,15V11.5L9,10L12,8.5V5M4,5H9V7H4V5M4,9H7V11H4V9M4,13H9V15H4V13Z\" />\n</vector>\n"
  },
  {
    "path": "play-services-core/src/main/res/drawable/ic_check_list.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2019 The Android Open Source Project\n  ~ SPDX-FileCopyrightText: 2020 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\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=\"#000\"\n        android:pathData=\"M14,10H2V12H14V10M14,6H2V8H14V6M2,16H10V14H2V16M21.5,11.5L23,13L16,20L11.5,15.5L13,14L16,17L21.5,11.5Z\" />\n</vector>\n"
  },
  {
    "path": "play-services-core/src/main/res/drawable/ic_choose_rounded_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\" android:shape=\"rectangle\">\n    <solid android:color=\"#10000000\" />\n    <corners android:radius=\"24dp\"/>\n</shape>"
  },
  {
    "path": "play-services-core/src/main/res/drawable/ic_circle_check.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2019, The Android Open Source Project\n  ~ SPDX-FileCopyrightText: 2021, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\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=\"#000\"\n        android:pathData=\"M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM10,17l-5,-5 1.41,-1.41L10,14.17l7.59,-7.59L19,8l-9,9z\" />\n</vector>\n"
  },
  {
    "path": "play-services-core/src/main/res/drawable/ic_circle_error.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2019, Austin Andrews\n  ~ SPDX-FileCopyrightText: 2021, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\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=\"#000\"\n        android:pathData=\"M12,2C17.53,2 22,6.47 22,12C22,17.53 17.53,22 12,22C6.47,22 2,17.53 2,12C2,6.47 6.47,2 12,2M15.59,7L12,10.59L8.41,7L7,8.41L10.59,12L7,15.59L8.41,17L12,13.41L15.59,17L17,15.59L13.41,12L17,8.41L15.59,7Z\" />\n</vector>\n"
  },
  {
    "path": "play-services-core/src/main/res/drawable/ic_circle_pending.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=\"#000\"\n      android:pathData=\"M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10s10,-4.48 10,-10C22,6.48 17.52,2 12,2zM12,20c-4.42,0 -8,-3.58 -8,-8c0,-4.42 3.58,-8 8,-8s8,3.58 8,8C20,16.42 16.42,20 12,20z\"/>\n  <path\n      android:fillColor=\"#000\"\n      android:pathData=\"M7,12m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0\"/>\n  <path\n      android:fillColor=\"#000\"\n      android:pathData=\"M12,12m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0\"/>\n  <path\n      android:fillColor=\"#000\"\n      android:pathData=\"M17,12m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0\"/>\n</vector>\n"
  },
  {
    "path": "play-services-core/src/main/res/drawable/ic_circle_warn.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2019, The Android Open Source Project\n  ~ SPDX-FileCopyrightText: 2021, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:tint=\"?attr/colorError\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n    <path\n        android:fillColor=\"#000\"\n        android:pathData=\"M11,15h2v2h-2zM11,7h2v6h-2zM11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,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": "play-services-core/src/main/res/drawable/ic_close_btn.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\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=\"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,12 19,6.41z\" />\n</vector>"
  },
  {
    "path": "play-services-core/src/main/res/drawable/ic_cloud_bell.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2019, The Android Open Source Project\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\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=\"#000\"\n        android:pathData=\"M 12 4 C 9.11 4 6.5996094 5.6392969 5.3496094 8.0292969 C 2.3396094 8.3592969 0 10.9 0 14 A 6 6 0 0 0 6 20 L 19 20 A 5 5 0 0 0 24 15 C 24 12.36 21.949609 10.219297 19.349609 10.029297 C 18.669609 6.5892969 15.64 4 12 4 z M 12 7.5 A 0.5 0.5 0 0 1 12.5 8 L 12.5 8.5390625 C 13.92 8.7790625 15 10.015 15 11.5 L 15 14.5 L 16.5 16 L 7.5 16 L 9 14.5 L 9 11.5 C 9 10.015 10.08 8.7790625 11.5 8.5390625 L 11.5 8 A 0.5 0.5 0 0 1 12 7.5 z M 11 16.5 L 13 16.5 A 1 1 0 0 1 12 17.5 A 1 1 0 0 1 11 16.5 z\" />\n</vector>\n"
  },
  {
    "path": "play-services-core/src/main/res/drawable/ic_device_login.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2019, Austin Andrews\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\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=\"#000\"\n        android:pathData=\"M10,17.25V14H3V10H10V6.75L15.25,12L10,17.25M8,2H17A2,2 0 0,1 19,4V20A2,2 0 0,1 17,22H8A2,2 0 0,1 6,20V16H8V20H17V4H8V8H6V4A2,2 0 0,1 8,2Z\" />\n</vector>\n"
  },
  {
    "path": "play-services-core/src/main/res/drawable/ic_google_logo.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"48dp\"\n    android:height=\"48dp\"\n    android:viewportWidth=\"48\"\n    android:viewportHeight=\"48\">\n    <path\n        android:fillColor=\"#4285f4\"\n        android:pathData=\"M46.98,24.55c0,-1.57 -0.15,-3.09 -0.38,-4.55H24v9.02h12.94c-0.58,2.96 -2.26,5.48 -4.78,7.18v6h7.73c4.51,-4.18 7.09,-10.36 7.09,-17.65z\" />\n    <path\n        android:fillColor=\"#34a853\"\n        android:pathData=\"M24,48c6.48,0 11.93,-2.13 15.89,-5.81l-7.73,-6c-2.15,1.45 -4.92,2.3 -8.16,2.3 -6.26,0 -11.57,-4.22 -13.47,-9.91H2.56v6.19C6.51,42.62 14.62,48 24,48z\" />\n    <path\n        android:fillColor=\"#fbbc05\"\n        android:pathData=\"M10.53,28.59c-0.48,-1.45 -0.76,-2.99 -0.76,-4.59s0.27,-3.14 0.76,-4.59v-6.19H2.56C0.92,16.46 0,20.12 0,24c0,3.88 0.92,7.54 2.56,10.78l7.97,-6.19z\" />\n    <path\n        android:fillColor=\"#ea4335\"\n        android:pathData=\"M24,9.5c3.54,0 6.71,1.22 9.21,3.6l6.85,-6.85C35.9,2.38 30.47,0 24,0 14.62,0 6.51,5.38 2.56,13.22l7.98,6.19C12.43,13.72 17.74,9.5 24,9.5z\" />\n</vector>"
  },
  {
    "path": "play-services-core/src/main/res/drawable/ic_leaderboard_placeholder.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\" android:height=\"40dp\" android:width=\"40dp\" android:viewportWidth=\"72\" android:viewportHeight=\"72\">\n    <path android:fillColor=\"@android:color/holo_green_dark\" android:pathData=\"M36,36m-36,0a36,36 0,1 1,72 0a36,36 0,1 1,-72 0\" android:strokeColor=\"#00000000\" android:strokeWidth=\"1\"/>\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M35.98,19.58L26.95,33.52L18,26.12L22.9,47.37L35.98,47.37L49.05,47.37L53.96,26.12L45.01,33.52L35.98,19.58ZM32.71,37.56L35.98,32.66L39.25,37.56L36.07,42.46L32.71,37.56Z\" android:strokeColor=\"#00000000\" android:strokeWidth=\"1\"/>\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M23.11,49l0.78,3.28l24.01,0l0.76,-3.28z\" android:strokeColor=\"#00000000\" android:strokeWidth=\"1\"/>\n</vector>"
  },
  {
    "path": "play-services-core/src/main/res/drawable/ic_link.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"48dp\"\n    android:height=\"48dp\"\n    android:viewportWidth=\"48\"\n    android:viewportHeight=\"48\">\n    <path\n        android:fillColor=\"#40000000\"\n        android:pathData=\"M24,4a20,20 0 1,0 0,40a20,20 0 1,0 0,-40\"/>\n    <path\n        android:fillColor=\"#000000\"\n        android:strokeWidth=\"0\"\n        android:pathData=\"M18.5,24c0,-1.38 1.12,-2.5 2.5,-2.5h6c1.38,0 2.5,1.12 2.5,2.5s-1.12,2.5 -2.5,2.5h-2M20,26h-2c-2.21,0 -4,-1.79 -4,-4s1.79,-4 4,-4h6c2.21,0 4,1.79 4,4 0,1.1 -0.45,2.1 -1.17,2.83M28,22h2c2.21,0 4,1.79 4,4s-1.79,4 -4,4h-6c-2.21,0 -4,-1.79 -4,-4 0,-1.1 0.45,-2.1 1.17,-2.83\"/>\n</vector>"
  },
  {
    "path": "play-services-core/src/main/res/drawable/ic_manage_accounts.xml",
    "content": "<!--\n  ~ SPDX-FileCopyrightText: 2019 The Android Open Source Project\n  ~ SPDX-FileCopyrightText: 2024 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<vector android:height=\"24dp\"\n    android:tint=\"?attr/colorControlNormal\"\n    android:viewportHeight=\"24\"\n    android:viewportWidth=\"24\"\n    android:width=\"24dp\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path\n        android:fillColor=\"#000\"\n        android:pathData=\"M10,8m-4,0a4,4 0,1 1,8 0a4,4 0,1 1,-8 0\" />\n    <path\n        android:fillColor=\"#000\"\n        android:pathData=\"M10.67,13.02C10.45,13.01 10.23,13 10,13c-2.42,0 -4.68,0.67 -6.61,1.82C2.51,15.34 2,16.32 2,17.35V20h9.26C10.47,18.87 10,17.49 10,16C10,14.93 10.25,13.93 10.67,13.02z\" />\n    <path\n        android:fillColor=\"#000\"\n        android:pathData=\"M20.75,16c0,-0.22 -0.03,-0.42 -0.06,-0.63l1.14,-1.01l-1,-1.73l-1.45,0.49c-0.32,-0.27 -0.68,-0.48 -1.08,-0.63L18,11h-2l-0.3,1.49c-0.4,0.15 -0.76,0.36 -1.08,0.63l-1.45,-0.49l-1,1.73l1.14,1.01c-0.03,0.21 -0.06,0.41 -0.06,0.63s0.03,0.42 0.06,0.63l-1.14,1.01l1,1.73l1.45,-0.49c0.32,0.27 0.68,0.48 1.08,0.63L16,21h2l0.3,-1.49c0.4,-0.15 0.76,-0.36 1.08,-0.63l1.45,0.49l1,-1.73l-1.14,-1.01C20.72,16.42 20.75,16.22 20.75,16zM17,18c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2s2,0.9 2,2S18.1,18 17,18z\" />\n</vector>\n"
  },
  {
    "path": "play-services-core/src/main/res/drawable/ic_map_marker.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2019, The Android Open Source Project\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\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=\"#000\"\n        android:pathData=\"M12,11.5A2.5,2.5 0 0,1 9.5,9A2.5,2.5 0 0,1 12,6.5A2.5,2.5 0 0,1 14.5,9A2.5,2.5 0 0,1 12,11.5M12,2A7,7 0 0,0 5,9C5,14.25 12,22 12,22C12,22 19,14.25 19,9A7,7 0 0,0 12,2Z\" />\n</vector>\n"
  },
  {
    "path": "play-services-core/src/main/res/drawable/ic_more_vert.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\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    <path\n        android:fillColor=\"#FFFFFF\"\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>"
  },
  {
    "path": "play-services-core/src/main/res/drawable/ic_plusone_medium.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<selector />"
  },
  {
    "path": "play-services-core/src/main/res/drawable/ic_plusone_small.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<selector />"
  },
  {
    "path": "play-services-core/src/main/res/drawable/ic_plusone_standard.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<selector />"
  },
  {
    "path": "play-services-core/src/main/res/drawable/ic_plusone_tall.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<selector />"
  },
  {
    "path": "play-services-core/src/main/res/drawable/ic_refresh.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:tint=\"#ff80868b\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n\n    <path\n        android:fillColor=\"#ff80868b\"\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\n</vector>"
  },
  {
    "path": "play-services-core/src/main/res/drawable/ic_shop.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020 Google Inc.\n  ~ SPDX-FileCopyrightText: 2023 e Foundation\n  ~ SPDX-FileCopyrightText: 2024 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\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=\"#000\"\n      android:pathData=\"M16,6L16,4c0,-1.11 -0.89,-2 -2,-2h-4c-1.11,0 -2,0.89 -2,2v2L2,6v13c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2L22,6h-6zM10,4h4v2h-4L10,4zM9,18L9,9l7.5,4L9,18z\"/>\n</vector>\n"
  },
  {
    "path": "play-services-core/src/main/res/drawable/ic_snapshot_choose_fill.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\" android:shape=\"rectangle\">\n    <solid android:color=\"@android:color/holo_green_dark\" />\n    <corners android:radius=\"2dp\"/>\n</shape>"
  },
  {
    "path": "play-services-core/src/main/res/drawable/ic_snapshot_choose_stroke.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\" android:shape=\"rectangle\">\n    <corners android:radius=\"2dp\"/>\n    <stroke android:color=\"@android:color/darker_gray\" android:width=\"1dp\"/>\n</shape>"
  },
  {
    "path": "play-services-core/src/main/res/drawable/ic_snapshot_load_error_image.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\" android:height=\"500dp\" android:width=\"1024dp\" android:viewportWidth=\"1024\" android:viewportHeight=\"500\">\n    <path android:fillColor=\"#f8f9fa\" android:pathData=\"M757,288.2m-88.2,0a88.2,88.2 0,1 1,176.4 0a88.2,88.2 0,1 1,-176.4 0\"/>\n    <path android:fillColor=\"#f8f9fa\" android:pathData=\"M296.6,331.4c-59.1,0 -107.1,-48 -107.1,-107.1s48,-107.1 107.1,-107.1h315.8c59.1,0 107.1,48 107.1,107.1s-48,107.1 -107.1,107.1H296.6z\"/>\n    <path android:fillColor=\"#f8f9fa\" android:pathData=\"M382.4,83.3m-69,0a69,69 0,1 1,138 0a69,69 0,1 1,-138 0\"/>\n    <path android:fillColor=\"#f8f9fa\" android:pathData=\"M622.1,191.4m-103,0a103,103 0,1 1,206 0a103,103 0,1 1,-206 0\"/>\n    <path android:fillColor=\"#f8f9fa\" android:pathData=\"M142.6,365.1m-93.9,0a93.9,93.9 0,1 1,187.8 0a93.9,93.9 0,1 1,-187.8 0\"/>\n    <path android:fillColor=\"#80868b\" android:pathData=\"M525.6,297.8l-61.4,0l23.5,-23.4l61.4,0z\" android:strokeColor=\"#80868b\" android:strokeWidth=\"5\" android:strokeLineCap=\"round\" android:strokeLineJoin=\"round\"/>\n    <path android:fillColor=\"#e8eaed\" android:pathData=\"M551.6,365.9l-61.5,0l-25.9,-68.1l61.4,0z\" android:strokeColor=\"#80868b\" android:strokeWidth=\"5\" android:strokeLineCap=\"round\" android:strokeLineJoin=\"round\"/>\n    <path android:fillColor=\"#80868b\" android:pathData=\"M524.9,364.2h-14.4v-4.6c0,-2.1 1.6,-3.7 3.7,-3.7h6.9c2.1,0 3.7,1.6 3.7,3.7L524.9,364.2L524.9,364.2z\"/>\n    <path android:fillColor=\"#e8eaed\" android:pathData=\"M566.5,345m-7,0a7,7 0,1 1,14 0a7,7 0,1 1,-14 0\" android:strokeColor=\"#80868b\" android:strokeWidth=\"5\" android:strokeLineCap=\"round\" android:strokeLineJoin=\"round\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M566.5,352L566.5,365.9\" android:strokeColor=\"#80868b\" android:strokeWidth=\"5\" android:strokeLineCap=\"round\" android:strokeLineJoin=\"round\"/>\n    <path android:fillColor=\"#ffffff\" android:pathData=\"M530.4,365.9h61.4v94.5h-61.4z\" android:strokeColor=\"#bdc1c6\" android:strokeWidth=\"5\" android:strokeLineCap=\"round\" android:strokeLineJoin=\"round\"/>\n    <path android:fillColor=\"#bdc1c6\" android:pathData=\"M487.7,250.2l-30.4,0l-26.7,26.7l0,183.4l99.8,0l0,-94.4l-40.3,0l-25.9,-68.1l23.5,-23.4z\" android:strokeColor=\"#bdc1c6\" android:strokeWidth=\"5\" android:strokeLineCap=\"round\" android:strokeLineJoin=\"round\"/>\n    <path android:fillColor=\"#ffffff\" android:pathData=\"M487.7,250.2h61.4v24.2h-61.4z\" android:strokeColor=\"#bdc1c6\" android:strokeWidth=\"5\" android:strokeLineCap=\"round\" android:strokeLineJoin=\"round\"/>\n    <path android:fillColor=\"#ffffff\" android:pathData=\"M504,330.2c2.2,5.7 -0.7,10.4 -6.4,10.4s-12.3,-4.7 -14.5,-10.4c-2.2,-5.7 0.7,-10.4 6.4,-10.4C495.4,319.8 501.8,324.5 504,330.2z\"/>\n    <path android:fillColor=\"#80868b\" android:pathData=\"M498.2,330.2c0.9,2.6 -0.4,4.6 -2.8,4.6c-2.6,0 -5.4,-2.1 -6.3,-4.6c-0.9,-2.6 0.4,-4.6 2.8,-4.6S497.2,327.6 498.2,330.2z\"/>\n    <path android:fillColor=\"#ffffff\" android:pathData=\"M531.5,330.2c2.2,5.7 -0.7,10.4 -6.4,10.4s-12.3,-4.7 -14.5,-10.4c-2.2,-5.7 0.7,-10.4 6.4,-10.4C522.8,319.8 529.2,324.5 531.5,330.2z\"/>\n    <path android:fillColor=\"#80868b\" android:pathData=\"M525.6,330.2c0.9,2.6 -0.4,4.6 -2.8,4.6c-2.6,0 -5.4,-2.1 -6.3,-4.6c-0.9,-2.6 0.4,-4.6 2.8,-4.6C521.8,325.6 524.7,327.6 525.6,330.2z\"/>\n    <path android:fillColor=\"#e8eaed\" android:pathData=\"M255.1,341.4m-93.9,0a93.9,93.9 0,1 1,187.8 0a93.9,93.9 0,1 1,-187.8 0\"/>\n    <path android:fillColor=\"#e8eaed\" android:pathData=\"M140.2,397.7m-56.6,0a56.6,56.6 0,1 1,113.2 0a56.6,56.6 0,1 1,-113.2 0\"/>\n    <path android:fillColor=\"#e8eaed\" android:pathData=\"M602.87,460.27a93.9,93.9 0,1 0,132.79 -132.79a93.9,93.9 0,1 0,-132.79 132.79z\"/>\n    <path android:fillColor=\"#e8eaed\" android:pathData=\"M782,341.4m-93.9,0a93.9,93.9 0,1 1,187.8 0a93.9,93.9 0,1 1,-187.8 0\"/>\n    <path android:fillColor=\"#e8eaed\" android:pathData=\"M924.4,388.3m-71.5,0a71.5,71.5 0,1 1,143 0a71.5,71.5 0,1 1,-143 0\"/>\n    <path android:fillColor=\"#f8f9fa\" android:pathData=\"M574,0.1H469c-24.3,16.7 -40.3,44.8 -40.3,76.5c0,51.3 41.5,92.8 92.8,92.8s92.8,-41.5 92.8,-92.8C614.3,44.8 598.3,16.8 574,0.1z\"/>\n    <path android:fillColor=\"#e8eaed\" android:pathData=\"M345.6,499.9h58.9c37.4,-12.4 64.5,-47.6 64.5,-89.2c0,-51.9 -42,-93.9 -93.9,-93.9c-51.9,0 -93.9,42 -93.9,93.9C281.2,452.3 308.2,487.5 345.6,499.9z\"/>\n    <path android:fillColor=\"#e8eaed\" android:pathData=\"M1023.9,499.9c0,-0.4 0,-0.9 0,-1.3c0,-53.1 -42.9,-96 -96,-96H641.5l-29.2,97.3H1023.9z\"/>\n    <path android:fillColor=\"#e8eaed\" android:pathData=\"M497.3,499.9c0,-0.4 0,-0.9 0,-1.3c0,-53.1 -42.9,-96 -96,-96H96c-53.1,0 -96,42.9 -96,96c0,0.4 0,0.9 0,1.3H497.3z\"/>\n    <path android:fillColor=\"#f8f9fa\" android:pathData=\"M520.4,446.8m-47.7,0a47.7,47.7 0,1 1,95.4 0a47.7,47.7 0,1 1,-95.4 0\"/>\n    <path android:fillColor=\"#f8f9fa\" android:pathData=\"M492.1,499.9c5.1,-10.3 7.9,-21.9 7.9,-34.2c0,-42.9 -34.8,-77.7 -77.7,-77.7s-77.7,34.8 -77.7,77.7c0,12.3 2.9,23.9 7.9,34.2H492.1z\"/>\n    <path android:fillColor=\"#f8f9fa\" android:pathData=\"M656.7,499.9c-8.6,-32.1 -37.9,-55.7 -72.6,-55.7H344.9c-34.8,0 -64,23.6 -72.6,55.7H656.7z\"/>\n</vector>"
  },
  {
    "path": "play-services-core/src/main/res/drawable/ic_work.xml",
    "content": "<!--\n  ~ SPDX-FileCopyrightText: Android Open Source Project\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\" android:height=\"24dp\" android:tint=\"?attr/colorControlNormal\" android:viewportHeight=\"24\" android:viewportWidth=\"24\" android:width=\"24dp\">\n      \n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M20,6h-4L16,4c0,-1.11 -0.89,-2 -2,-2h-4c-1.11,0 -2,0.89 -2,2v2L4,6c-1.11,0 -1.99,0.89 -1.99,2L2,19c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2L22,8c0,-1.11 -0.89,-2 -2,-2zM14,6h-4L10,4h4v2z\"/>\n    \n</vector>\n"
  },
  {
    "path": "play-services-core/src/main/res/drawable-anydpi-v21/microg_light_color_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\" xmlns:aapt=\"http://schemas.android.com/aapt\"\n    android:viewportWidth=\"256\"\n    android:viewportHeight=\"256\"\n    android:width=\"256dp\"\n    android:height=\"256dp\">\n    <path\n        android:fillColor=\"#ffffffff\" android:pathData=\"M207.03481 139.53168c0.42667 -3.41333 0.74667 -6.82666 0.74667 -10.45333 0 -3.62667 -0.32 -7.04 -0.74667 -10.45333l22.50667 -17.6c2.02667 -1.599996 2.56 -4.479996 1.28 -6.826666L209.48815 57.291687c-1.28 -2.346666 -4.16 -3.2 -6.50667 -2.346666l-26.56 10.666666c-5.54667 -4.266666 -11.52 -7.786666 -18.02667 -10.453333l-4.05333 -28.266667c-0.32 -2.56 -2.56 -4.48 -5.22667 -4.48h-42.66666c-2.66667 0 -4.90667 1.92 -5.22667 4.48l-4.053331 28.266667c-6.50667 2.666667 -12.48 6.293333 -18.02667 10.453333l-26.56 -10.666666c-2.45333 -0.96 -5.22667 0 -6.50667 2.346666l-21.33333 36.906667c-1.38667 2.34667 -0.74667 5.22667 1.28 6.826666l22.50667 17.6c-0.42667 3.41333 -0.74667 6.93333 -0.74667 10.45333 0 3.52 0.32 7.04 0.74667 10.45333l-22.50667 17.6c-2.02667 1.6 -2.56 4.48 -1.28 6.82667l21.33333 36.90667c1.28 2.34666 4.16 3.2 6.50667 2.34666l26.56 -10.66666c5.54667 4.26666 11.52 7.78666 18.02667 10.45333l4.053331 28.26667c0.32 2.56 2.56 4.48 5.22667 4.48h42.66666c2.66667 0 4.90667 -1.92 5.22667 -4.48l4.05333 -28.26667c6.50667 -2.66667 12.48 -6.29333 18.02667 -10.45333l26.56 10.66666c2.45333 0.96 5.22667 0 6.50667 -2.34666l21.33333 -36.90667c1.28 -2.34667 0.74667 -5.22667 -1.28 -6.82667z\">\n    </path>\n</vector>\n"
  },
  {
    "path": "play-services-core/src/main/res/drawable-v21/ic_app_foreground.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: CC-BY-SA-4.0\n  -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"225.27\"\n    android:viewportHeight=\"225.27\">\n    <group\n        android:scaleX=\"0.50\"\n        android:scaleY=\"0.50\"\n        android:translateX=\"56.3175\"\n        android:translateY=\"56.3175\">\n        <path\n            android:pathData=\"M112.64,112.64m-105.55,0a105.55,105.55 0,1 1,211.1 0a105.55,105.55 0,1 1,-211.1 0\"\n            android:strokeWidth=\"30.57332802\"\n            android:fillColor=\"#ffffff\"\n            android:strokeColor=\"#00000000\"\n            android:strokeLineCap=\"butt\" />\n        <path\n            android:pathData=\"m151.55,151.53a55,55 0,0 1,-66.39 8.74\"\n            android:strokeWidth=\"30\"\n            android:fillColor=\"#00000000\"\n            android:strokeColor=\"#e91e63\"\n            android:strokeLineCap=\"butt\" />\n        <path\n            android:pathData=\"M85.16,160.27A55,55 0,0 1,59.53 98.4\"\n            android:strokeWidth=\"30\"\n            android:fillColor=\"#00000000\"\n            android:strokeColor=\"#ff9800\"\n            android:strokeLineCap=\"butt\" />\n        <path\n            android:pathData=\"m59.53,98.4a55,55 0,0 1,25.63 -33.4\"\n            android:strokeWidth=\"30\"\n            android:fillColor=\"#00000000\"\n            android:strokeColor=\"#cddc39\"\n            android:strokeLineCap=\"butt\" />\n        <path\n            android:pathData=\"m85.16,65.01a55,55 0,0 1,66.39 8.74\"\n            android:strokeWidth=\"30\"\n            android:fillColor=\"#00000000\"\n            android:strokeColor=\"#009688\"\n            android:strokeLineCap=\"butt\" />\n    </group>\n</vector>\n"
  },
  {
    "path": "play-services-core/src/main/res/drawable-v21/ic_app_foreground_mono.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: CC-BY-SA-4.0\n  -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"225.27\"\n    android:viewportHeight=\"225.27\">\n    <group\n        android:scaleX=\"0.50\"\n        android:scaleY=\"0.50\"\n        android:translateX=\"56.3175\"\n        android:translateY=\"56.3175\">\n        <path\n            android:pathData=\"M112.64,112.64m-105.55,0a105.55,105.55 0,1 1,211.1 0a105.55,105.55 0,1 1,-211.1 0\"\n            android:strokeWidth=\"30.57332802\"\n            android:fillColor=\"#000000\"\n            android:strokeColor=\"#00000000\"\n            android:fillAlpha=\"0.2\"\n            android:strokeLineCap=\"butt\" />\n        <path\n            android:pathData=\"m151.55,151.53a55,55 0,0 1,-66.39 8.74\"\n            android:strokeAlpha=\"0.8\"\n            android:strokeWidth=\"30\"\n            android:fillColor=\"#00000000\"\n            android:strokeColor=\"#000000\"\n            android:fillAlpha=\"0.8\"\n            android:strokeLineCap=\"butt\" />\n        <path\n            android:pathData=\"M85.16,160.27A55,55 0,0 1,59.53 98.4\"\n            android:strokeAlpha=\"0.6\"\n            android:strokeWidth=\"30\"\n            android:fillColor=\"#00000000\"\n            android:strokeColor=\"#000000\"\n            android:fillAlpha=\"0.6\"\n            android:strokeLineCap=\"butt\" />\n        <path\n            android:pathData=\"m59.53,98.4a55,55 0,0 1,25.63 -33.4\"\n            android:strokeAlpha=\"0.5\"\n            android:strokeWidth=\"30\"\n            android:fillColor=\"#00000000\"\n            android:strokeColor=\"#000000\"\n            android:fillAlpha=\"0.5\"\n            android:strokeLineCap=\"butt\" />\n        <path\n            android:pathData=\"m85.16,65.01a55,55 0,0 1,66.39 8.74\"\n            android:strokeAlpha=\"0.7\"\n            android:strokeWidth=\"30\"\n            android:fillColor=\"#00000000\"\n            android:strokeColor=\"#000000\"\n            android:fillAlpha=\"0.7\"\n            android:strokeLineCap=\"butt\" />\n    </group>\n</vector>\n"
  },
  {
    "path": "play-services-core/src/main/res/drawable-v21/ic_app_settings_foreground.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: CC-BY-SA-4.0\n  -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"225.27\"\n    android:viewportHeight=\"225.27\">\n    <group\n        android:translateX=\"40.635\"\n        android:translateY=\"40.635\"\n        android:scaleX=\"6.0\"\n        android:scaleY=\"6.0\">\n        <path\n            android:fillColor=\"#ffffff\"\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.94z\" />\n    </group>\n    <group\n        android:scaleX=\"0.40\"\n        android:scaleY=\"0.40\"\n        android:translateX=\"67.581\"\n        android:translateY=\"67.581\">\n        <path\n            android:pathData=\"m151.55,151.53a55,55 0,0 1,-66.39 8.74\"\n            android:strokeWidth=\"36\"\n            android:fillColor=\"#00000000\"\n            android:strokeColor=\"#e91e63\"\n            android:strokeLineCap=\"butt\" />\n        <path\n            android:pathData=\"M85.16,160.27A55,55 0,0 1,59.53 98.4\"\n            android:strokeWidth=\"36\"\n            android:fillColor=\"#00000000\"\n            android:strokeColor=\"#ff9800\"\n            android:strokeLineCap=\"butt\" />\n        <path\n            android:pathData=\"m59.53,98.4a55,55 0,0 1,25.63 -33.4\"\n            android:strokeWidth=\"36\"\n            android:fillColor=\"#00000000\"\n            android:strokeColor=\"#cddc39\"\n            android:strokeLineCap=\"butt\" />\n        <path\n            android:pathData=\"m85.16,65.01a55,55 0,0 1,66.39 8.74\"\n            android:strokeWidth=\"36\"\n            android:fillColor=\"#00000000\"\n            android:strokeColor=\"#009688\"\n            android:strokeLineCap=\"butt\" />\n    </group>\n</vector>\n"
  },
  {
    "path": "play-services-core/src/main/res/drawable-v21/ic_app_settings_foreground_mono.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: CC-BY-SA-4.0\n  -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"225.27\"\n    android:viewportHeight=\"225.27\">\n    <group\n        android:translateX=\"40.635\"\n        android:translateY=\"40.635\"\n        android:scaleX=\"6.0\"\n        android:scaleY=\"6.0\">\n        <path\n            android:fillColor=\"#000000\"\n            android:fillAlpha=\"0.2\"\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.94z\" />\n    </group>\n    <group\n        android:scaleX=\"0.40\"\n        android:scaleY=\"0.40\"\n        android:translateX=\"67.581\"\n        android:translateY=\"67.581\">\n        <path\n            android:pathData=\"m151.55,151.53a55,55 0,0 1,-66.39 8.74\"\n            android:strokeAlpha=\"0.8\"\n            android:strokeWidth=\"36\"\n            android:fillColor=\"#00000000\"\n            android:strokeColor=\"#000000\"\n            android:fillAlpha=\"0.8\"\n            android:strokeLineCap=\"butt\" />\n        <path\n            android:pathData=\"M85.16,160.27A55,55 0,0 1,59.53 98.4\"\n            android:strokeAlpha=\"0.6\"\n            android:strokeWidth=\"36\"\n            android:fillColor=\"#00000000\"\n            android:strokeColor=\"#000000\"\n            android:fillAlpha=\"0.6\"\n            android:strokeLineCap=\"butt\" />\n        <path\n            android:pathData=\"m59.53,98.4a55,55 0,0 1,25.63 -33.4\"\n            android:strokeAlpha=\"0.5\"\n            android:strokeWidth=\"36\"\n            android:fillColor=\"#00000000\"\n            android:strokeColor=\"#000000\"\n            android:fillAlpha=\"0.5\"\n            android:strokeLineCap=\"butt\" />\n        <path\n            android:pathData=\"m85.16,65.01a55,55 0,0 1,66.39 8.74\"\n            android:strokeAlpha=\"0.7\"\n            android:strokeWidth=\"36\"\n            android:fillColor=\"#00000000\"\n            android:strokeColor=\"#000000\"\n            android:fillAlpha=\"0.7\"\n            android:strokeLineCap=\"butt\" />\n    </group>\n</vector>\n"
  },
  {
    "path": "play-services-core/src/main/res/drawable-v21/ic_app_settings_system.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: CC-BY-SA-4.0\n  -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"225.27\"\n    android:viewportHeight=\"225.27\"\n    android:tint=\"?android:attr/colorControlNormal\">\n    <group>\n        <path\n            android:pathData=\"m151.55,151.53a55,55 0,0 1,-66.39 8.74\"\n            android:strokeAlpha=\"0.8\"\n            android:strokeWidth=\"36\"\n            android:fillColor=\"#00ffffff\"\n            android:strokeColor=\"#ffffff\"\n            android:fillAlpha=\"0.9\"\n            android:strokeLineCap=\"butt\" />\n        <path\n            android:pathData=\"M85.16,160.27A55,55 0,0 1,59.53 98.4\"\n            android:strokeAlpha=\"0.6\"\n            android:strokeWidth=\"36\"\n            android:fillColor=\"#00ffffff\"\n            android:strokeColor=\"#ffffff\"\n            android:fillAlpha=\"0.7\"\n            android:strokeLineCap=\"butt\" />\n        <path\n            android:pathData=\"m59.53,98.4a55,55 0,0 1,25.63 -33.4\"\n            android:strokeAlpha=\"0.5\"\n            android:strokeWidth=\"36\"\n            android:fillColor=\"#00ffffff\"\n            android:strokeColor=\"#ffffff\"\n            android:fillAlpha=\"0.6\"\n            android:strokeLineCap=\"butt\" />\n        <path\n            android:pathData=\"m85.16,65.01a55,55 0,0 1,66.39 8.74\"\n            android:strokeAlpha=\"0.7\"\n            android:strokeWidth=\"36\"\n            android:fillColor=\"#00ffffff\"\n            android:strokeColor=\"#ffffff\"\n            android:fillAlpha=\"0.8\"\n            android:strokeLineCap=\"butt\" />\n    </group>\n</vector>\n"
  },
  {
    "path": "play-services-core/src/main/res/drawable-v23/material_switch_bar_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2024 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<ripple xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:color=\"?attr/colorControlHighlight\">\n    <item>\n        <shape android:shape=\"rectangle\">\n            <solid android:color=\"?attr/colorSecondaryContainer\"/>\n            <corners android:radius=\"28dp\"/>\n        </shape>\n    </item>\n</ripple>"
  },
  {
    "path": "play-services-core/src/main/res/drawable-v23/material_switch_bar_background_disabled.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2024 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<ripple xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:color=\"?attr/colorControlHighlight\">\n    <item>\n        <shape android:shape=\"rectangle\">\n            <solid android:color=\"?attr/colorSurfaceContainer\"/>\n            <corners android:radius=\"28dp\"/>\n        </shape>\n    </item>\n</ripple>"
  },
  {
    "path": "play-services-core/src/main/res/layout/activity_consent_sign_in.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <WebView\n        android:id=\"@+id/consent_sign\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\" />\n\n    <ProgressBar\n        android:id=\"@+id/progressBar\"\n        style=\"?android:attr/progressBarStyle\"\n        android:layout_width=\"wrap_content\"\n        android:visibility=\"gone\"\n        android:layout_centerInParent=\"true\"\n        android:layout_height=\"wrap_content\" />\n</RelativeLayout>"
  },
  {
    "path": "play-services-core/src/main/res/layout/activity_location_sharing_settings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout\n    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    \n    <androidx.appcompat.widget.Toolbar\n        android:id=\"@+id/toolbar\"\n        android:layout_width=\"match_parent\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:title=\"@string/service_name_google_location_sharing\"\n        android:layout_height=\"?attr/actionBarSize\"/>\n\n    <androidx.appcompat.widget.AppCompatImageView\n        android:id=\"@+id/avatar_iv\"\n        android:layout_width=\"40dp\"\n        android:layout_height=\"40dp\"\n        app:layout_constraintTop_toBottomOf=\"@id/toolbar\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        android:layout_marginTop=\"32dp\"\n        android:layout_marginStart=\"24dp\"/>\n\n    <TextView\n        android:id=\"@+id/account_email_tv\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        android:textSize=\"18sp\"\n        android:textColor=\"?attr/colorOnBackground\"\n        android:layout_marginEnd=\"24dp\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toEndOf=\"@+id/avatar_iv\"\n        app:layout_constraintLeft_toRightOf=\"@id/avatar_iv\"\n        app:layout_constraintTop_toTopOf=\"@id/avatar_iv\"\n        app:layout_constraintBottom_toBottomOf=\"@id/avatar_iv\"\n        android:layout_marginStart=\"12dp\"/>\n\n    <ProgressBar\n        android:id=\"@+id/progress_bar\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:indeterminate=\"true\"\n        android:layout_marginTop=\"8dp\"\n        app:layout_constraintTop_toBottomOf=\"@id/avatar_iv\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintRight_toRightOf=\"parent\"\n        style=\"?android:attr/progressBarStyleHorizontal\"/>\n\n\n    <LinearLayout\n        android:id=\"@+id/location_sharing_layout\"\n        android:layout_width=\"match_parent\"\n        android:orientation=\"vertical\"\n        android:visibility=\"gone\"\n        app:layout_constraintTop_toBottomOf=\"@id/progress_bar\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintRight_toRightOf=\"parent\"\n        android:layout_height=\"wrap_content\">\n\n        <TextView\n            android:id=\"@+id/location_sharing_desc_tv\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/location_sharing_description\"\n            android:textSize=\"14sp\"\n            android:textColor=\"?attr/colorOnBackground\"\n            app:layout_constraintTop_toBottomOf=\"@id/avatar_iv\"\n            android:layout_marginTop=\"12dp\"\n            android:layout_marginLeft=\"24dp\"\n            android:layout_marginRight=\"24dp\"/>\n\n\n        <androidx.cardview.widget.CardView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"70dp\"\n            app:cardCornerRadius=\"20dp\"\n            android:layout_margin=\"24dp\">\n\n            <androidx.appcompat.widget.SwitchCompat\n                android:id=\"@+id/location_share_switch\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:checked=\"true\"\n                android:padding=\"20dp\"\n                android:text=\"@string/location_sharing_switch_text\"\n                android:textSize=\"16sp\"\n                android:background=\"@null\" />\n        </androidx.cardview.widget.CardView>\n\n\n        <androidx.cardview.widget.CardView\n            android:id=\"@+id/location_sharing_link_view\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"70dp\"\n            app:cardCornerRadius=\"20dp\"\n            android:layout_marginTop=\"12dp\"\n            android:layout_marginLeft=\"24dp\"\n            android:layout_marginRight=\"24dp\">\n\n            <androidx.constraintlayout.widget.ConstraintLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\">\n\n                <androidx.appcompat.widget.AppCompatImageView\n                    android:layout_width=\"32dp\"\n                    android:layout_height=\"32dp\"\n                    android:src=\"@drawable/ic_link\"\n                    app:tint=\"?attr/colorAccent\"\n                    app:layout_constraintLeft_toLeftOf=\"parent\"\n                    app:layout_constraintTop_toTopOf=\"parent\"\n                    app:layout_constraintBottom_toBottomOf=\"parent\"\n                    android:layout_marginStart=\"20dp\"/>\n\n                <androidx.appcompat.widget.AppCompatImageView\n                    android:layout_width=\"24dp\"\n                    android:layout_height=\"24dp\"\n                    android:src=\"@drawable/ic_arrow_right\"\n                    app:layout_constraintRight_toRightOf=\"parent\"\n                    app:layout_constraintTop_toTopOf=\"parent\"\n                    app:layout_constraintBottom_toBottomOf=\"parent\"\n                    app:tint=\"?attr/colorAccent\"\n                    android:layout_marginEnd=\"20dp\"/>\n            </androidx.constraintlayout.widget.ConstraintLayout>\n        </androidx.cardview.widget.CardView>\n\n\n        <TextView\n            android:id=\"@+id/location_share_primary_hint_tv\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/location_sharing_turn_off_notify_hint\"\n            android:textSize=\"14sp\"\n            android:textColor=\"?attr/colorOnBackground\"\n            android:layout_marginTop=\"24dp\"\n            android:layout_marginLeft=\"24dp\"\n            android:layout_marginRight=\"24dp\"/>\n\n        <TextView\n            android:id=\"@+id/location_share_secondary_hint_tv\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/location_sharing_off_previous_hint\"\n            android:textSize=\"14sp\"\n            android:textColor=\"?attr/colorOnBackground\"\n            android:layout_marginTop=\"16dp\"\n            android:layout_marginLeft=\"24dp\"\n            android:layout_marginRight=\"24dp\"/>\n\n        <TextView\n            android:id=\"@+id/location_share_web_lint_tv\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/location_sharing_learn_more\"\n            android:textSize=\"14sp\"\n            android:textColor=\"?attr/colorAccent\"\n            app:layout_constraintLeft_toLeftOf=\"parent\"\n            android:layout_marginTop=\"16dp\"\n            android:layout_marginStart=\"24dp\"/>\n\n    </LinearLayout>\n\n\n\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "play-services-core/src/main/res/layout/ask_gcm.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!-- Copyright (C) 2015 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<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:minWidth=\"240dp\"\n    tools:theme=\"@style/Theme.App.DayNight.Dialog.Alert.NoActionBar\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"center\"\n        android:orientation=\"vertical\"\n        android:paddingLeft=\"24dp\"\n        android:paddingTop=\"18dp\"\n        android:paddingRight=\"24dp\"\n        android:paddingBottom=\"24dp\">\n\n        <ImageView\n            android:id=\"@+id/permission_icon\"\n            android:layout_width=\"24dp\"\n            android:layout_height=\"24dp\"\n            android:layout_marginBottom=\"12dp\"\n            android:scaleType=\"fitCenter\"\n            android:src=\"@drawable/ic_cloud_bell\"\n            app:tint=\"?attr/colorAccent\"></ImageView>\n\n        <TextView\n            android:id=\"@+id/permission_message\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:gravity=\"center\"\n            android:text=\"@string/gcm_allow_app_popup\"\n            android:textSize=\"18sp\"></TextView>\n\n    </LinearLayout>\n\n</ScrollView>\n"
  },
  {
    "path": "play-services-core/src/main/res/layout/ask_permission.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<LinearLayout 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=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <TextView\n        android:gravity=\"center_horizontal\"\n        android:paddingTop=\"10dp\"\n        android:text=\"@string/account_manager_title\"\n        android:textColor=\"?attr/colorPrimary\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\" />\n\n    <View\n        android:id=\"@+id/no_progress_bar\"\n        android:layout_marginTop=\"10dp\"\n        android:layout_marginBottom=\"10dp\"\n        android:background=\"@color/dialog_border_color\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"1dp\" />\n\n    <ProgressBar\n        android:id=\"@+id/progress_bar\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:indeterminate=\"true\"\n        android:layout_marginTop=\"2dp\"\n        android:layout_marginBottom=\"3dp\"\n        android:visibility=\"gone\"\n        style=\"?android:attr/progressBarStyleHorizontal\" />\n\n    <LinearLayout\n        android:paddingTop=\"15dp\"\n        android:layout_gravity=\"center_horizontal\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\">\n\n        <FrameLayout\n            android:background=\"@drawable/circle_shape_background\"\n            android:layout_marginEnd=\"-3dp\"\n            android:layout_marginRight=\"-3dp\"\n            android:layout_width=\"64dp\"\n            android:layout_height=\"64dp\"\n            android:padding=\"10dp\">\n\n            <de.hdodenhof.circleimageview.CircleImageView\n                android:src=\"@drawable/ic_generic_man\"\n                android:id=\"@+id/account_photo\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\" />\n        </FrameLayout>\n\n        <FrameLayout\n            android:background=\"@drawable/circle_shape_background\"\n            android:layout_marginStart=\"-3dp\"\n            android:layout_marginLeft=\"-3dp\"\n            android:layout_width=\"64dp\"\n            android:layout_height=\"64dp\"\n            android:padding=\"10dp\">\n\n            <ImageView\n                tools:src=\"@mipmap/ic_app\"\n                android:id=\"@+id/app_icon\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\" />\n        </FrameLayout>\n    </LinearLayout>\n\n    <TextView\n        android:id=\"@+id/title\"\n        android:padding=\"15dp\"\n        android:gravity=\"center_horizontal\"\n        android:textSize=\"18sp\"\n        android:textColor=\"?attr/colorAccent\"\n        android:text=\"@string/ask_scope_permission_title\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\" />\n\n    <ListView\n        android:padding=\"5dp\"\n        android:id=\"@+id/permissions\"\n        android:layout_weight=\"1\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dip\" />\n\n    <TextView\n        android:padding=\"10dp\"\n        android:textColor=\"?attr/colorPrimary\"\n        android:textSize=\"12sp\"\n        android:text=\"@string/ask_permission_tos\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\" />\n\n    <LinearLayout\n        android:layout_gravity=\"end\"\n        android:orientation=\"horizontal\"\n        android:paddingRight=\"10dp\"\n        android:paddingLeft=\"10dp\"\n        android:paddingBottom=\"5dp\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\">\n\n        <Button\n            android:id=\"@android:id/button2\"\n            style=\"?attr/buttonBarButtonStyle\"\n            android:text=\"@string/deny\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\" />\n\n        <Button\n            android:id=\"@android:id/button1\"\n            style=\"?attr/buttonBarButtonStyle\"\n            android:text=\"@string/allow\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\" />\n    </LinearLayout>\n\n</LinearLayout>"
  },
  {
    "path": "play-services-core/src/main/res/layout/ask_permission_list_entry.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"horizontal\"\n    android:padding=\"5dp\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\">\n\n    <ImageView\n        android:src=\"@drawable/proprietary_auth_ic_scope_icon_default\"\n        android:id=\"@android:id/icon\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\" />\n\n    <LinearLayout\n        android:padding=\"6dp\"\n        android:orientation=\"vertical\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\">\n\n        <TextView\n            android:textSize=\"16sp\"\n            android:id=\"@android:id/text1\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\" />\n\n        <TextView\n            android:textSize=\"12sp\"\n            android:visibility=\"gone\"\n            android:id=\"@android:id/text2\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\" />\n    </LinearLayout>\n</LinearLayout>"
  },
  {
    "path": "play-services-core/src/main/res/layout/assisted_signin_back_consent_layout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout 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    <ProgressBar\n        android:id=\"@+id/sign_reloading_progress\"\n        style=\"?android:attr/progressBarStyleHorizontal\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"3dp\"\n        android:indeterminate=\"true\"\n        android:visibility=\"invisible\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintRight_toRightOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\" />\n\n    <TextView\n        android:id=\"@+id/sign_reloading_title\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"center\"\n        android:paddingVertical=\"20dp\"\n        android:text=\"@string/credentials_assisted_sign_back_title\"\n        android:textAppearance=\"?attr/textAppearanceListItem\"\n        android:textSize=\"20sp\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintRight_toRightOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@id/sign_reloading_progress\" />\n\n    <TextView\n        android:id=\"@+id/sign_reloading_consent\"\n        style=\"@style/GISDescriptionStyle\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"6dp\"\n        android:paddingHorizontal=\"24dp\"\n        android:text=\"@string/credentials_assisted_signin_consent\"\n        android:textSize=\"14sp\"\n        android:visibility=\"gone\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintRight_toRightOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@id/sign_reloading_title\" />\n\n    <TextView\n        android:id=\"@+id/sign_reloading_description\"\n        style=\"@style/GISDescriptionStyle\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"6dp\"\n        android:paddingHorizontal=\"24dp\"\n        android:text=\"@string/credentials_assisted_signin_description\"\n        android:textSize=\"14sp\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintRight_toRightOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@id/sign_reloading_consent\" />\n\n    <LinearLayout\n        android:id=\"@+id/sign_reloading_account_llt\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"center_vertical\"\n        android:orientation=\"horizontal\"\n        android:paddingHorizontal=\"24dp\"\n        android:paddingVertical=\"16dp\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintRight_toRightOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@id/sign_reloading_description\">\n\n        <de.hdodenhof.circleimageview.CircleImageView\n            android:id=\"@+id/sign_account_photo\"\n            android:layout_width=\"32dp\"\n            android:layout_height=\"32dp\"\n            android:layout_marginVertical=\"12dp\" />\n\n        <LinearLayout\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginHorizontal=\"12dp\"\n            android:layout_weight=\"1\"\n            android:orientation=\"vertical\">\n\n            <TextView\n                android:id=\"@+id/sign_account_display_name\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:textAppearance=\"?attr/textAppearanceListItem\" />\n\n            <TextView\n                android:id=\"@+id/sign_account_email\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\" />\n        </LinearLayout>\n\n    </LinearLayout>\n\n    <com.google.android.material.button.MaterialButton\n        android:id=\"@+id/sign_reloading_back\"\n        style=\"@style/Widget.Material3.Button\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginHorizontal=\"24dp\"\n        android:text=\"@string/credentials_assisted_continue_as_user_button_label\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintRight_toRightOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@id/sign_reloading_account_llt\" />\n\n    <Space\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"24dp\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintRight_toRightOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@id/sign_reloading_back\" />\n\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "play-services-core/src/main/res/layout/assisted_signin_choose_layout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout 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\n    <ProgressBar\n        android:id=\"@+id/sign_multi_progress\"\n        style=\"?android:attr/progressBarStyleHorizontal\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"3dp\"\n        android:indeterminate=\"true\"\n        android:visibility=\"invisible\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintRight_toRightOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n         />\n\n    <TextView\n        android:id=\"@+id/sign_multi_title\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"center\"\n        android:paddingTop=\"24dp\"\n        android:text=\"@string/credentials_assisted_choose_account_label\"\n        android:textAppearance=\"?attr/textAppearanceListItem\"\n        android:textSize=\"20sp\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintRight_toRightOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@id/sign_multi_progress\" />\n\n    <TextView\n        android:id=\"@+id/sign_multi_description\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/credentials_assisted_choose_account_subtitle\"\n        android:textSize=\"14sp\"\n        android:gravity=\"center\"\n        android:layout_marginTop=\"6dp\"\n        android:paddingHorizontal=\"24dp\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintRight_toRightOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@id/sign_multi_title\" />\n\n    <androidx.core.widget.NestedScrollView\n        android:id=\"@+id/sign_multi_account_container_scroll\"\n        android:layout_width=\"match_parent\"\n        android:layout_marginHorizontal=\"24dp\"\n        android:layout_marginTop=\"24dp\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintRight_toRightOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@id/sign_multi_description\"\n        android:layout_height=\"wrap_content\">\n\n        <LinearLayout\n            android:id=\"@+id/sign_multi_account_container\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"vertical\"\n            android:background=\"@drawable/ic_choose_rounded_background\" />\n\n    </androidx.core.widget.NestedScrollView>\n\n    <Space\n        app:layout_constraintTop_toBottomOf=\"@id/sign_multi_account_container_scroll\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintRight_toRightOf=\"parent\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"24dp\"/>\n\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "play-services-core/src/main/res/layout/assisted_signin_google_dialog.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout 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=\"wrap_content\"\n    android:orientation=\"vertical\">\n\n    <RelativeLayout\n        android:id=\"@+id/header_with_logo\"\n        android:layout_width=\"match_parent\"\n        android:layout_marginHorizontal=\"24dp\"\n        android:layout_marginTop=\"24dp\"\n        android:layout_height=\"wrap_content\">\n\n        <ImageView\n            android:layout_width=\"32dp\"\n            android:layout_height=\"32dp\"\n            android:layout_alignParentStart=\"true\"\n            android:contentDescription=\"@null\"\n            android:src=\"@drawable/ic_google_logo\" />\n\n        <ImageView\n            android:id=\"@+id/cancel\"\n            android:layout_width=\"32dp\"\n            android:layout_height=\"32dp\"\n            android:layout_alignParentEnd=\"true\"\n            android:clickable=\"true\"\n            android:contentDescription=\"@android:string/cancel\"\n            android:focusable=\"true\"\n            android:scaleType=\"centerInside\"\n            android:src=\"@drawable/ic_close_btn\" />\n    </RelativeLayout>\n\n    <FrameLayout\n        android:id=\"@+id/google_sign_in_container\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\">\n\n        <ProgressBar\n            android:paddingVertical=\"55dp\"\n            android:layout_width=\"wrap_content\"\n            android:layout_gravity=\"center\"\n            android:layout_height=\"wrap_content\"/>\n\n    </FrameLayout>\n\n</LinearLayout>"
  },
  {
    "path": "play-services-core/src/main/res/layout/assisted_signin_hint_login.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout 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\n    <TextView\n        android:id=\"@+id/add_account_title\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        android:layout_marginTop=\"16dp\"\n        android:layout_width=\"wrap_content\"\n        android:text=\"@string/credentials_assisted_signin_add_account\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        android:textSize=\"18sp\"\n        android:textStyle=\"bold\"\n        android:textColor=\"#303030\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        android:layout_height=\"wrap_content\"/>\n\n    <TextView\n        android:id=\"@+id/add_account_subtitle_tv\"\n        app:layout_constraintTop_toBottomOf=\"@+id/add_account_title\"\n        android:layout_width=\"wrap_content\"\n        android:layout_marginTop=\"8dp\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        android:text=\"@string/credentials_assisted_choose_account_subtitle\"\n        android:textColor=\"#979697\"\n        android:layout_height=\"wrap_content\"/>\n\n    <com.google.android.material.button.MaterialButton\n        android:id=\"@+id/add_google_account_btn\"\n        style=\"@style/Widget.Material3.Button\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_margin=\"24dp\"\n        android:textColor=\"@android:color/white\"\n        app:backgroundTint=\"#303030\"\n        app:layout_constraintTop_toBottomOf=\"@+id/add_account_subtitle_tv\"\n        android:text=\"@string/pref_add_account_summary\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintRight_toRightOf=\"parent\" />\n\n    <Space\n        app:layout_constraintTop_toBottomOf=\"@id/add_google_account_btn\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintRight_toRightOf=\"parent\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"24dp\"/>\n\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "play-services-core/src/main/res/layout/assisted_signin_loading_layout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout 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\n    <TextView\n        android:id=\"@+id/sign_loading_title\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintRight_toRightOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        android:text=\"@string/credentials_assisted_confirmation_header\"\n        android:textAppearance=\"?attr/textAppearanceListItem\"\n        android:gravity=\"center\"\n        android:textSize=\"20sp\"\n        android:paddingVertical=\"20dp\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"/>\n\n    <ProgressBar\n        android:id=\"@+id/sign_loading_progress\"\n        app:layout_constraintTop_toBottomOf=\"@id/sign_loading_title\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintRight_toRightOf=\"parent\"\n        style=\"?android:attr/progressBarStyleHorizontal\"\n        android:indeterminate=\"true\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"3dp\"/>\n\n    <LinearLayout\n        app:layout_constraintTop_toBottomOf=\"@id/sign_loading_progress\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintRight_toRightOf=\"parent\"\n        android:paddingVertical=\"24dp\"\n        android:paddingHorizontal=\"24dp\"\n        android:layout_width=\"match_parent\"\n        android:orientation=\"horizontal\"\n        android:gravity=\"center_vertical\"\n        android:layout_height=\"wrap_content\">\n\n        <de.hdodenhof.circleimageview.CircleImageView\n            android:id=\"@+id/sign_account_photo\"\n            android:layout_marginVertical=\"12dp\"\n            android:layout_width=\"32dp\"\n            android:layout_height=\"32dp\" />\n\n        <LinearLayout\n            android:layout_marginHorizontal=\"12dp\"\n            android:layout_width=\"0dp\"\n            android:layout_weight=\"1\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"vertical\">\n\n            <TextView\n                android:id=\"@+id/sign_account_display_name\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:textAppearance=\"?attr/textAppearanceListItem\" />\n\n            <TextView\n                android:id=\"@+id/sign_account_email\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\" />\n        </LinearLayout>\n\n        <TextView\n            android:id=\"@+id/sign_cancel\"\n            android:layout_width=\"wrap_content\"\n            android:text=\"@string/credentials_assisted_cancel\"\n            android:visibility=\"gone\"\n            android:textColor=\"?colorPrimary\"\n            android:paddingVertical=\"4dp\"\n            android:paddingHorizontal=\"10dp\"\n            android:layout_height=\"wrap_content\"/>\n\n    </LinearLayout>\n\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "play-services-core/src/main/res/layout/assisted_signin_multi_layout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<LinearLayout 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\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"center_vertical\"\n        android:layout_marginVertical=\"12dp\"\n        android:layout_marginHorizontal=\"24dp\"\n        android:orientation=\"horizontal\">\n\n        <de.hdodenhof.circleimageview.CircleImageView\n            android:layout_gravity=\"center_vertical\"\n            android:id=\"@+id/account_photo\"\n            android:layout_width=\"32dp\"\n            android:layout_height=\"32dp\" />\n\n        <LinearLayout\n            android:layout_marginStart=\"12dp\"\n            android:layout_gravity=\"center_vertical\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"vertical\">\n\n            <TextView\n                android:id=\"@+id/account_display_name\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:textSize=\"14sp\" />\n\n            <TextView\n                android:id=\"@+id/account_email\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:textSize=\"12sp\" />\n\n            <TextView\n                android:id=\"@+id/account_description\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:textSize=\"12sp\" />\n        </LinearLayout>\n    </LinearLayout>\n\n    <View\n        android:id=\"@+id/multi_account_line\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"2dp\"\n        android:background=\"@android:color/white\" />\n</LinearLayout>"
  },
  {
    "path": "play-services-core/src/main/res/layout/dialog_game_account_change_confirmation.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout 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\n    <LinearLayout\n        android:id=\"@+id/game_info_container\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"64dp\"\n        android:orientation=\"horizontal\"\n        android:paddingHorizontal=\"16dp\"\n        android:paddingTop=\"16dp\"\n        android:visibility=\"gone\">\n\n        <ImageView\n            android:id=\"@+id/img_game_icon\"\n            android:layout_width=\"48dp\"\n            android:layout_height=\"48dp\"\n            android:layout_marginEnd=\"12dp\"\n            android:scaleType=\"centerCrop\" />\n\n        <LinearLayout\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            <TextView\n                android:id=\"@+id/tv_game_name\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:textColor=\"@android:color/black\"\n                android:textSize=\"14dp\" />\n\n            <TextView\n                android:id=\"@+id/tv_game_account\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"2dp\"\n                android:textSize=\"12dp\" />\n        </LinearLayout>\n\n    </LinearLayout>\n\n    <TextView\n        android:id=\"@+id/tv_dialog_title\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:padding=\"16dp\"\n        android:text=\"@string/games_change_default_account_for_all_games_dialog_title\"\n        android:textColor=\"@android:color/black\"\n        android:textSize=\"15dp\" />\n\n    <TextView\n        android:id=\"@+id/tv_dialog_second_title\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:paddingHorizontal=\"16dp\"\n        android:paddingBottom=\"12dp\"\n        android:text=\"@string/games_change_default_account_for_all_games_dialog_description\"\n        android:textSize=\"14dp\" />\n\n    <View\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"1dp\"\n        android:background=\"#cccccc\" />\n\n    <LinearLayout\n        android:id=\"@+id/llt_radio_choose_container\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        android:paddingTop=\"12dp\"\n        android:paddingHorizontal=\"16dp\" />\n\n    <Button\n        android:id=\"@+id/btn_change_cancel\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"35dp\"\n        android:layout_marginHorizontal=\"16dp\"\n        android:layout_marginTop=\"12dp\"\n        android:layout_marginBottom=\"32dp\"\n        android:background=\"@drawable/ic_snapshot_choose_fill\"\n        android:text=\"@string/credentials_assisted_cancel\"\n        android:textColor=\"@android:color/white\"\n        android:textSize=\"12dp\" />\n\n</LinearLayout>"
  },
  {
    "path": "play-services-core/src/main/res/layout/dialog_game_account_delete_confirmation.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout\n    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\n    <TextView\n        android:id=\"@+id/textDeleteProfileTitle\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/games_delete_profile_dialog_title\"\n        android:textSize=\"18dp\"\n        android:padding=\"16dp\"\n        android:textColor=\"@android:color/black\"/>\n\n    <View\n        android:layout_width=\"match_parent\"\n        android:background=\"@android:color/darker_gray\"\n        android:layout_height=\"1dp\"/>\n\n    <TextView\n        android:id=\"@+id/textDeleteProfileExplanation\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:padding=\"16dp\"\n        android:lineSpacingMultiplier=\"1.3\"\n        android:text=\"@string/games_delete_profile_explanation\" />\n\n    <TextView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:paddingHorizontal=\"16dp\"\n        android:text=\"@string/games_delete_profile_dialog_message\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:padding=\"16dp\"\n        android:orientation=\"horizontal\"\n        android:gravity=\"end\">\n\n        <Button\n            android:id=\"@+id/btnCancel\"\n            android:layout_width=\"120dp\"\n            android:layout_height=\"35dp\"\n            android:textColor=\"@android:color/holo_green_dark\"\n            android:textSize=\"12dp\"\n            android:background=\"@drawable/ic_snapshot_choose_stroke\"\n            android:text=\"@string/credentials_assisted_cancel\" />\n\n        <Button\n            android:id=\"@+id/btnConfirmDelete\"\n            android:layout_width=\"0dp\"\n            android:layout_weight=\"1\"\n            android:layout_height=\"35dp\"\n            android:text=\"@string/games_delete_profile_button\"\n            android:paddingVertical=\"8dp\"\n            android:textColor=\"@android:color/white\"\n            android:textSize=\"12dp\"\n            android:layout_marginStart=\"10dp\"\n            android:background=\"@drawable/ic_snapshot_choose_fill\" />\n    </LinearLayout>\n</LinearLayout>"
  },
  {
    "path": "play-services-core/src/main/res/layout/fragment_game_change_account.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.core.widget.NestedScrollView 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    android:scrollbars=\"none\"\n    android:paddingBottom=\"16dp\"\n    android:paddingHorizontal=\"16dp\">\n\n    <LinearLayout\n        android:orientation=\"vertical\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\">\n\n        <TextView\n            android:text=\"@string/games_change_default_account_section_title\"\n            android:textSize=\"16dp\"\n            android:textColor=\"@android:color/black\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\" />\n\n        <TextView\n            android:id=\"@+id/change_default_account\"\n            android:text=\"@string/games_change_default_account_description\"\n            android:textSize=\"14dp\"\n            android:layout_marginTop=\"12dp\"\n            android:visibility=\"gone\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\" />\n\n        <TextView\n            android:text=\"@string/games_change_default_account_explanation\"\n            android:textSize=\"14dp\"\n            android:lineSpacingMultiplier=\"1.3\"\n            android:layout_marginTop=\"10dp\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\" />\n\n        <Button\n            android:id=\"@+id/btn_change_default\"\n            android:text=\"@string/games_change_button_text\"\n            android:textColor=\"@android:color/white\"\n            android:background=\"@drawable/ic_snapshot_choose_fill\"\n            android:layout_gravity=\"end\"\n            android:layout_marginTop=\"32dp\"\n            android:textSize=\"12dp\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:minHeight=\"0dp\"\n            android:minWidth=\"0dp\"\n            android:paddingVertical=\"8dp\"\n            android:paddingHorizontal=\"30dp\"\n            android:includeFontPadding=\"false\"\n            app:backgroundTint=\"@null\"/>\n\n        <TextView\n            android:text=\"@string/games_change_per_game_title\"\n            android:textSize=\"16dp\"\n            android:textColor=\"@android:color/black\"\n            android:layout_marginTop=\"32dp\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\" />\n\n        <TextView\n            android:text=\"@string/games_change_per_game_description\"\n            android:textSize=\"14dp\"\n            android:layout_marginTop=\"12dp\"\n            android:lineSpacingMultiplier=\"1.3\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\" />\n\n        <androidx.recyclerview.widget.RecyclerView\n            android:id=\"@+id/recycler_view_games\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"16dp\" />\n\n    </LinearLayout>\n\n</androidx.core.widget.NestedScrollView>"
  },
  {
    "path": "play-services-core/src/main/res/layout/fragment_game_delete_data.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.core.widget.NestedScrollView 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    android:paddingHorizontal=\"16dp\"\n    android:paddingBottom=\"16dp\"\n    android:scrollbars=\"none\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\">\n\n        <TextView\n            android:id=\"@+id/delete_current_account\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/games_account_display_content\"\n            android:textColor=\"@android:color/black\"\n            android:visibility=\"gone\"\n            android:textSize=\"16dp\" />\n\n        <Button\n            android:id=\"@+id/btn_choose\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"end\"\n            android:layout_marginTop=\"32dp\"\n            android:background=\"@drawable/ic_snapshot_choose_fill\"\n            android:includeFontPadding=\"false\"\n            android:minWidth=\"0dp\"\n            android:minHeight=\"0dp\"\n            android:paddingHorizontal=\"30dp\"\n            android:paddingVertical=\"8dp\"\n            android:text=\"@string/games_change_button_text\"\n            android:textColor=\"@android:color/white\"\n            android:textSize=\"12dp\"\n            android:visibility=\"gone\"\n            app:backgroundTint=\"@null\" />\n\n        <TextView\n            android:layout_marginTop=\"32dp\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/games_delete_profile_header\"\n            android:textColor=\"@android:color/black\"\n            android:textSize=\"16dp\" />\n\n        <TextView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"12dp\"\n            android:lineSpacingMultiplier=\"1.3\"\n            android:text=\"@string/games_delete_profile_explanation\"\n            android:textSize=\"14dp\" />\n\n        <Button\n            android:id=\"@+id/btn_delete\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"end\"\n            android:layout_marginTop=\"32dp\"\n            android:background=\"@drawable/ic_snapshot_choose_fill\"\n            android:includeFontPadding=\"false\"\n            android:minWidth=\"0dp\"\n            android:minHeight=\"0dp\"\n            android:paddingHorizontal=\"30dp\"\n            android:paddingVertical=\"8dp\"\n            android:text=\"@string/games_delete_profile_button\"\n            android:textColor=\"@android:color/white\"\n            android:textSize=\"12dp\"\n            app:backgroundTint=\"@null\" />\n\n        <TextView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"32dp\"\n            android:text=\"@string/games_delete_game_data_header\"\n            android:textColor=\"@android:color/black\"\n            android:textSize=\"16dp\" />\n\n        <TextView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"12dp\"\n            android:lineSpacingMultiplier=\"1.3\"\n            android:text=\"@string/games_delete_game_data_explanation\"\n            android:textSize=\"14dp\" />\n\n        <FrameLayout\n            android:layout_width=\"match_parent\"\n            android:paddingVertical=\"8dp\"\n            android:layout_height=\"match_parent\">\n\n            <androidx.recyclerview.widget.RecyclerView\n                android:id=\"@+id/recycler_view_games\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:visibility=\"invisible\" />\n\n            <ProgressBar\n                android:id=\"@+id/loading_progress\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center_horizontal\" />\n\n        </FrameLayout>\n\n    </LinearLayout>\n</androidx.core.widget.NestedScrollView>"
  },
  {
    "path": "play-services-core/src/main/res/layout/fragment_games_ui_layout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\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    <RelativeLayout\n        android:layout_width=\"match_parent\"\n        android:layout_marginHorizontal=\"24dp\"\n        android:layout_marginTop=\"24dp\"\n        android:layout_height=\"wrap_content\">\n\n        <de.hdodenhof.circleimageview.CircleImageView\n            android:layout_width=\"32dp\"\n            android:layout_height=\"32dp\"\n            android:layout_alignParentStart=\"true\"\n            android:contentDescription=\"@null\"\n            android:id=\"@+id/games_ui_player_logo\"\n            android:src=\"@drawable/ic_google_logo\" />\n\n        <TextView\n            android:id=\"@+id/games_ui_title\"\n            android:layout_width=\"wrap_content\"\n            android:textSize=\"18sp\"\n            android:fontFamily=\"sans-serif-medium\"\n            android:layout_centerInParent=\"true\"\n            android:layout_height=\"wrap_content\"/>\n\n        <ImageView\n            android:id=\"@+id/games_ui_cancel\"\n            android:layout_width=\"36dp\"\n            android:layout_height=\"36dp\"\n            android:layout_alignParentEnd=\"true\"\n            android:contentDescription=\"@android:string/cancel\"\n            android:scaleType=\"centerInside\"\n            android:src=\"@drawable/ic_close_btn\" />\n\n        <ImageView\n            android:id=\"@+id/games_ui_refresh\"\n            android:layout_width=\"36dp\"\n            android:layout_height=\"36dp\"\n            android:layout_toStartOf=\"@id/games_ui_cancel\"\n            android:layout_marginEnd=\"12dp\"\n            android:scaleType=\"centerInside\"\n            android:visibility=\"gone\"\n            android:src=\"@drawable/ic_refresh\" />\n    </RelativeLayout>\n\n    <RelativeLayout\n        android:layout_width=\"match_parent\"\n        android:paddingHorizontal=\"12dp\"\n        android:layout_height=\"wrap_content\">\n\n        <ViewStub\n            android:id=\"@+id/games_ui_achievements_vb\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout=\"@layout/item_achievements_counter\"/>\n\n        <androidx.recyclerview.widget.RecyclerView\n            android:layout_below=\"@id/games_ui_achievements_vb\"\n            android:id=\"@+id/games_ui_recyclerview\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"/>\n\n        <FrameLayout\n            android:layout_width=\"match_parent\"\n            android:id=\"@+id/games_ui_loading\"\n            android:layout_centerInParent=\"true\"\n            android:layout_height=\"match_parent\">\n\n            <ProgressBar\n                android:layout_width=\"wrap_content\"\n                android:layout_gravity=\"center\"\n                android:layout_height=\"wrap_content\"/>\n\n        </FrameLayout>\n\n        <TextView\n            android:id=\"@+id/games_ui_error_tips\"\n            android:textColor=\"@android:color/black\"\n            android:textSize=\"20sp\"\n            android:gravity=\"center\"\n            android:visibility=\"gone\"\n            android:layout_alignBottom=\"@id/games_ui_loading\"\n            android:layout_alignTop=\"@id/games_ui_loading\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"/>\n\n        <com.google.android.material.floatingactionbutton.FloatingActionButton\n            android:id=\"@+id/games_ui_action_button\"\n            style=\"@style/Widget.Design.FloatingActionButton\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_alignParentEnd=\"true\"\n            android:layout_alignParentBottom=\"true\"\n            android:layout_margin=\"12dp\"\n            android:visibility=\"gone\"\n            app:backgroundTint=\"#ffffffff\"\n            android:src=\"@drawable/ic_add\"\n            app:tint=\"#027e5a\" />\n\n    </RelativeLayout>\n\n</LinearLayout>"
  },
  {
    "path": "play-services-core/src/main/res/layout/games_info.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<LinearLayout 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    android:orientation=\"vertical\">\n\n    <TextView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"center_horizontal\"\n        android:paddingTop=\"10dp\"\n        android:text=\"@string/games_title\"\n        android:textColor=\"?attr/colorPrimary\"/>\n\n    <View\n        android:id=\"@+id/no_progress_bar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"1dp\"\n        android:layout_marginBottom=\"10dp\"\n        android:layout_marginTop=\"10dp\"\n        android:background=\"@color/dialog_border_color\"/>\n\n    <LinearLayout\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center_horizontal\"\n        android:paddingTop=\"15dp\">\n\n        <FrameLayout\n            android:layout_width=\"64dp\"\n            android:layout_height=\"64dp\"\n            android:layout_marginEnd=\"-3dp\"\n            android:layout_marginRight=\"-3dp\"\n            android:background=\"@drawable/circle_shape_background\"\n            android:padding=\"10dp\">\n\n            <ImageView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:src=\"@drawable/ic_gamepad\"/>\n        </FrameLayout>\n\n        <FrameLayout\n            android:layout_width=\"64dp\"\n            android:layout_height=\"64dp\"\n            android:layout_marginLeft=\"-3dp\"\n            android:layout_marginStart=\"-3dp\"\n            android:background=\"@drawable/circle_shape_background\"\n            android:padding=\"10dp\">\n\n            <ImageView\n                android:id=\"@+id/app_icon\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                tools:src=\"@mipmap/ic_app\"/>\n        </FrameLayout>\n    </LinearLayout>\n\n    <TextView\n        android:id=\"@+id/title\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"center_horizontal\"\n        android:padding=\"15dp\"\n        android:text=\"@string/games_info_title\"\n        android:textColor=\"?attr/colorAccent\"\n        android:textSize=\"18sp\"/>\n\n    <TextView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:padding=\"10dp\"\n        android:text=\"@string/games_info_content\"/>\n\n    <LinearLayout\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"end\"\n        android:orientation=\"horizontal\"\n        android:paddingBottom=\"5dp\"\n        android:paddingLeft=\"10dp\"\n        android:paddingRight=\"10dp\">\n\n        <Button\n            android:id=\"@android:id/button1\"\n            style=\"?attr/buttonBarButtonStyle\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@android:string/ok\"/>\n    </LinearLayout>\n</LinearLayout>"
  },
  {
    "path": "play-services-core/src/main/res/layout/item_achievement_data_layout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:orientation=\"vertical\"\n    android:gravity=\"center_vertical\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\">\n\n    <ImageView\n        android:id=\"@+id/achievement_logo\"\n        android:layout_marginTop=\"12dp\"\n        android:layout_width=\"56dp\"\n        android:layout_height=\"56dp\" />\n\n    <TextView\n        android:id=\"@+id/achievement_title\"\n        android:layout_alignTop=\"@id/achievement_logo\"\n        android:layout_marginStart=\"12dp\"\n        android:layout_toEndOf=\"@id/achievement_logo\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:textSize=\"16sp\" />\n\n    <TextView\n        android:id=\"@+id/achievement_content\"\n        android:layout_marginStart=\"12dp\"\n        android:layout_toEndOf=\"@id/achievement_logo\"\n        android:layout_alignBottom=\"@id/achievement_logo\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:textSize=\"10sp\"\n        android:textColor=\"@android:color/darker_gray\" />\n\n    <TextView\n        android:id=\"@+id/achievement_desc\"\n        android:layout_marginStart=\"12dp\"\n        android:layout_below=\"@id/achievement_title\"\n        android:layout_above=\"@id/achievement_content\"\n        android:layout_toEndOf=\"@id/achievement_logo\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:textSize=\"12sp\"\n        android:textColor=\"#808080\" />\n\n    <View\n        android:layout_marginTop=\"12dp\"\n        android:layout_alignStart=\"@id/achievement_title\"\n        android:layout_below=\"@id/achievement_logo\"\n        android:layout_width=\"match_parent\"\n        android:background=\"#E6E6E6\"\n        android:layout_height=\"1dp\"/>\n\n</RelativeLayout>"
  },
  {
    "path": "play-services-core/src/main/res/layout/item_achievement_header_layout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:paddingVertical=\"10dp\"\n    android:background=\"@android:color/white\"\n    android:layout_height=\"wrap_content\">\n\n    <TextView\n        android:id=\"@+id/achievements_header_title\"\n        android:textSize=\"12sp\"\n        android:textColor=\"#808080\"\n        android:layout_width=\"wrap_content\"\n        android:layout_centerVertical=\"true\"\n        android:layout_height=\"wrap_content\"/>\n\n</RelativeLayout>"
  },
  {
    "path": "play-services-core/src/main/res/layout/item_achievements_counter.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/achievements_counter_llt\"\n    android:layout_width=\"match_parent\"\n    android:orientation=\"horizontal\"\n    android:paddingVertical=\"10dp\"\n    android:gravity=\"center\"\n    android:layout_height=\"wrap_content\">\n\n    <ImageView\n        android:layout_width=\"55dp\"\n        android:src=\"@drawable/ic_achievement_logo\"\n        android:layout_height=\"55dp\"/>\n\n    <TextView\n        android:id=\"@+id/achievements_counter_text\"\n        android:layout_marginStart=\"16dp\"\n        android:textSize=\"22sp\"\n        android:typeface=\"sans\"\n        android:textColor=\"@android:color/black\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"/>\n\n</LinearLayout>"
  },
  {
    "path": "play-services-core/src/main/res/layout/item_game_account_data.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:paddingVertical=\"8dp\"\n    android:orientation=\"horizontal\"\n    android:gravity=\"center_vertical\">\n\n    <ImageView\n        android:id=\"@+id/img_game_icon\"\n        android:layout_width=\"36dp\"\n        android:layout_height=\"36dp\"\n        android:scaleType=\"centerCrop\"\n        android:layout_marginEnd=\"12dp\" />\n\n    <LinearLayout\n        android:layout_weight=\"1\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\">\n\n        <TextView\n            android:id=\"@+id/tv_game_name\"\n            android:textSize=\"12dp\"\n            android:textColor=\"@android:color/black\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\" />\n\n        <TextView\n            android:layout_marginTop=\"2dp\"\n            android:id=\"@+id/tv_game_tips\"\n            android:textSize=\"10dp\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\" />\n    </LinearLayout>\n\n    <Button\n        android:id=\"@+id/btn_click\"\n        android:textSize=\"12dp\"\n        android:background=\"@drawable/ic_snapshot_choose_stroke\"\n        android:textColor=\"@android:color/holo_green_dark\"\n        android:layout_width=\"72dp\"\n        android:layout_height=\"30dp\" />\n\n</LinearLayout>"
  },
  {
    "path": "play-services-core/src/main/res/layout/item_game_account_radio_root.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\">\n\n    <androidx.appcompat.widget.AppCompatRadioButton\n        android:id=\"@+id/game_radio_button_title\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:clickable=\"false\"\n        android:paddingVertical=\"12dp\"\n        android:paddingStart=\"10dp\"\n        android:textColor=\"@android:color/black\"\n        android:textSize=\"14dp\" />\n\n    <TextView\n        android:id=\"@+id/game_radio_button_tips\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginStart=\"42dp\"\n        android:lineSpacingMultiplier=\"1.3\"\n        android:textSize=\"14dp\" />\n\n</LinearLayout>"
  },
  {
    "path": "play-services-core/src/main/res/layout/item_leaderboard_data_layout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:gravity=\"center_vertical\"\n    android:layout_width=\"match_parent\"\n    android:paddingStart=\"18dp\"\n    android:layout_height=\"wrap_content\">\n\n    <de.hdodenhof.circleimageview.CircleImageView\n        android:id=\"@+id/leaderboard_logo\"\n        android:layout_marginTop=\"12dp\"\n        android:layout_width=\"42dp\"\n        android:layout_height=\"42dp\" />\n\n    <TextView\n        android:id=\"@+id/leaderboard_title\"\n        android:layout_alignTop=\"@id/leaderboard_logo\"\n        android:layout_marginStart=\"12dp\"\n        android:layout_toEndOf=\"@id/leaderboard_logo\"\n        android:layout_alignBottom=\"@id/leaderboard_logo\"\n        android:gravity=\"center_vertical\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:textSize=\"16sp\" />\n\n    <View\n        android:id=\"@+id/leaderboard_line\"\n        android:layout_marginTop=\"12dp\"\n        android:layout_alignStart=\"@id/leaderboard_title\"\n        android:layout_below=\"@id/leaderboard_logo\"\n        android:layout_width=\"match_parent\"\n        android:background=\"#E6E6E6\"\n        android:layout_height=\"1dp\"/>\n\n</RelativeLayout>"
  },
  {
    "path": "play-services-core/src/main/res/layout/item_leaderboard_score_data_layout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:gravity=\"center_vertical\"\n    android:layout_width=\"match_parent\"\n    android:paddingStart=\"18dp\"\n    android:layout_height=\"wrap_content\">\n\n    <de.hdodenhof.circleimageview.CircleImageView\n        android:id=\"@+id/leaderboard_player_logo\"\n        android:layout_marginTop=\"12dp\"\n        android:layout_width=\"42dp\"\n        android:layout_height=\"42dp\" />\n\n    <TextView\n        android:layout_marginTop=\"2dp\"\n        android:id=\"@+id/leaderboard_player_name\"\n        android:layout_alignTop=\"@id/leaderboard_player_logo\"\n        android:layout_marginStart=\"12dp\"\n        android:layout_toEndOf=\"@id/leaderboard_player_logo\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:textSize=\"13sp\" />\n\n    <TextView\n        android:id=\"@+id/leaderboard_player_score\"\n        android:layout_below=\"@id/leaderboard_player_name\"\n        android:layout_marginStart=\"12dp\"\n        android:layout_toEndOf=\"@id/leaderboard_player_logo\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:textColor=\"@android:color/darker_gray\"\n        android:textSize=\"11sp\" />\n\n    <TextView\n        android:id=\"@+id/leaderboard_player_rank\"\n        android:layout_alignTop=\"@id/leaderboard_player_logo\"\n        android:layout_alignBottom=\"@id/leaderboard_player_logo\"\n        android:layout_alignParentEnd=\"true\"\n        android:gravity=\"center_vertical\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginEnd=\"12dp\"\n        android:textColor=\"@android:color/darker_gray\"\n        android:textSize=\"11sp\" />\n\n    <View\n        android:id=\"@+id/leaderboard_score_line\"\n        android:layout_marginTop=\"12dp\"\n        android:layout_alignStart=\"@id/leaderboard_player_name\"\n        android:layout_below=\"@id/leaderboard_player_logo\"\n        android:layout_width=\"match_parent\"\n        android:background=\"#E6E6E6\"\n        android:layout_height=\"1dp\"/>\n\n</RelativeLayout>"
  },
  {
    "path": "play-services-core/src/main/res/layout/item_leaderboard_score_header_layout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:paddingVertical=\"10dp\"\n    android:orientation=\"vertical\"\n    android:gravity=\"center_horizontal\"\n    android:background=\"@android:color/white\"\n    android:layout_height=\"wrap_content\">\n\n    <de.hdodenhof.circleimageview.CircleImageView\n        android:layout_width=\"55dp\"\n        android:layout_height=\"55dp\"\n        android:contentDescription=\"@null\"\n        android:id=\"@+id/leaderboard_header_logo\" />\n\n    <TextView\n        android:layout_marginTop=\"10dp\"\n        android:id=\"@+id/leaderboard_header_title\"\n        android:layout_width=\"wrap_content\"\n        android:textSize=\"18sp\"\n        android:fontFamily=\"sans-serif-medium\"\n        android:layout_height=\"wrap_content\"/>\n\n</LinearLayout>"
  },
  {
    "path": "play-services-core/src/main/res/layout/item_snapshot_data_layout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout\n    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:paddingVertical=\"10dp\"\n    android:layout_height=\"wrap_content\">\n\n    <androidx.cardview.widget.CardView\n        android:id=\"@+id/snapshot_card\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        app:layout_constraintWidth_percent=\"0.65\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:cardCornerRadius=\"8dp\">\n\n        <androidx.constraintlayout.widget.ConstraintLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\">\n\n            <ImageView\n                android:id=\"@+id/snapshot_image\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"0dp\"\n                android:scaleType=\"centerCrop\"\n                app:layout_constraintDimensionRatio=\"H,1024:500\"\n                app:layout_constraintTop_toTopOf=\"parent\"\n                app:layout_constraintEnd_toEndOf=\"parent\"\n                app:layout_constraintStart_toStartOf=\"parent\" />\n\n            <TextView\n                android:id=\"@+id/snapshot_time\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_margin=\"10dp\"\n                android:textSize=\"12sp\"\n                android:textColor=\"@android:color/darker_gray\"\n                app:layout_constraintTop_toBottomOf=\"@id/snapshot_image\"\n                app:layout_constraintStart_toStartOf=\"@id/snapshot_image\"/>\n\n            <TextView\n                android:id=\"@+id/snapshot_desc\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_margin=\"10dp\"\n                android:textSize=\"14sp\"\n                android:textColor=\"@android:color/black\"\n                app:layout_constraintTop_toBottomOf=\"@id/snapshot_time\"\n                app:layout_constraintStart_toStartOf=\"@id/snapshot_image\"/>\n\n            <TextView\n                android:id=\"@+id/snapshot_choose_btn\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_margin=\"10dp\"\n                android:paddingVertical=\"4dp\"\n                android:paddingHorizontal=\"20dp\"\n                android:text=\"@string/games_snapshot_choose_btn_text\"\n                android:textSize=\"13sp\"\n                android:textColor=\"@android:color/white\"\n                android:background=\"@drawable/ic_snapshot_choose_fill\"\n                app:layout_constraintTop_toBottomOf=\"@id/snapshot_desc\"\n                app:layout_constraintEnd_toEndOf=\"@id/snapshot_image\"/>\n\n            <TextView\n                android:id=\"@+id/snapshot_delete_btn\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_margin=\"10dp\"\n                android:paddingVertical=\"4dp\"\n                android:paddingHorizontal=\"20dp\"\n                android:text=\"@string/games_snapshot_delete_btn_text\"\n                android:textSize=\"13sp\"\n                android:textColor=\"@android:color/holo_green_dark\"\n                android:background=\"@drawable/ic_snapshot_choose_stroke\"\n                app:layout_constraintTop_toBottomOf=\"@id/snapshot_desc\"\n                app:layout_constraintEnd_toStartOf=\"@id/snapshot_choose_btn\"/>\n\n            <View\n                app:layout_constraintTop_toBottomOf=\"@id/snapshot_choose_btn\"\n                app:layout_constraintEnd_toEndOf=\"@id/snapshot_image\"\n                app:layout_constraintStart_toStartOf=\"@id/snapshot_image\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"10dp\"/>\n\n        </androidx.constraintlayout.widget.ConstraintLayout>\n\n    </androidx.cardview.widget.CardView>\n\n    <View\n        app:layout_constraintTop_toBottomOf=\"@id/snapshot_card\"\n        app:layout_constraintEnd_toEndOf=\"@id/snapshot_card\"\n        app:layout_constraintStart_toStartOf=\"@id/snapshot_card\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"2dp\"/>\n\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "play-services-core/src/main/res/layout/item_view_game_account_prompt.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/account_prompt_root\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:background=\"@drawable/ic_bg_prompt\"\n    android:orientation=\"horizontal\"\n    android:padding=\"8dp\"\n    android:visibility=\"gone\"\n    android:gravity=\"center_vertical\">\n\n    <ImageView\n        android:id=\"@+id/game_logo\"\n        android:layout_width=\"40dp\"\n        android:layout_height=\"40dp\"\n        android:src=\"@drawable/ic_gamepad\"\n        android:scaleType=\"centerCrop\" />\n\n    <LinearLayout\n        android:id=\"@+id/account_info_container\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"horizontal\"\n        android:gravity=\"center_vertical\"\n        android:paddingEnd=\"50dp\"\n        android:visibility=\"gone\">\n\n        <de.hdodenhof.circleimageview.CircleImageView\n            android:id=\"@+id/player_avatar\"\n            android:layout_width=\"40dp\"\n            android:layout_height=\"40dp\"\n            android:scaleType=\"centerCrop\" />\n\n        <TextView\n            android:id=\"@+id/player_name\"\n            android:layout_width=\"0dp\"\n            android:layout_weight=\"1\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginStart=\"10dp\"\n            android:textSize=\"14dp\"\n            android:textColor=\"@android:color/black\" />\n    </LinearLayout>\n</LinearLayout>"
  },
  {
    "path": "play-services-core/src/main/res/layout/login_assistant.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<RelativeLayout\n    android:id=\"@+id/auth_root\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"fill_parent\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\">\n\n        <RelativeLayout\n            android:id=\"@+id/title_container\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"64dp\"\n            android:background=\"?attr/colorPrimary\">\n\n            <TextView\n                android:id=\"@+id/title\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_alignParentBottom=\"true\"\n                android:layout_marginLeft=\"20dp\"\n                android:layout_marginRight=\"20dp\"\n                android:text=\"@string/just_a_sec\"\n                android:textColor=\"@color/primary_text_default_material_dark\"\n                android:textSize=\"24sp\"\n                android:paddingLeft=\"18dp\" />\n        </RelativeLayout>\n\n        <FrameLayout\n            android:id=\"@+id/auth_content\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"0dip\"\n            android:layout_weight=\"1\">\n\n            <TextView\n                android:id=\"@+id/description_text\"\n                style=\"?attr/textAppearanceListItem\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginLeft=\"20dp\"\n                android:layout_marginRight=\"20dp\"\n                android:padding=\"20dp\"/>\n        </FrameLayout>\n\n        <RelativeLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"54dip\"\n            android:background=\"#e4e7e9\">\n\n            <Button\n                android:id=\"@+id/back_button\"\n                style=\"?attr/buttonBarNegativeButtonStyle\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"48dip\"\n                android:layout_alignParentLeft=\"true\"\n                android:layout_alignParentStart=\"true\"\n                android:layout_centerVertical=\"true\"\n                android:paddingLeft=\"38dp\"\n                android:paddingRight=\"38dp\"\n                android:textAllCaps=\"true\"\n                android:textAppearance=\"@style/TextAppearance.AppCompat.Body1\"\n                android:textSize=\"16sp\"/>\n\n            <Button\n                android:id=\"@+id/next_button\"\n                style=\"?attr/buttonBarPositiveButtonStyle\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"48dip\"\n                android:layout_alignParentEnd=\"true\"\n                android:layout_alignParentRight=\"true\"\n                android:layout_centerVertical=\"true\"\n                android:paddingLeft=\"38dp\"\n                android:paddingRight=\"38dp\"\n                android:textAllCaps=\"true\"\n                android:textAppearance=\"@style/TextAppearance.AppCompat.Body1\"\n                android:textSize=\"16sp\"/>\n        </RelativeLayout>\n    </LinearLayout>\n\n</RelativeLayout>"
  },
  {
    "path": "play-services-core/src/main/res/layout/login_assistant_loading.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"fill_parent\">\n\n    <ProgressBar\n        android:id=\"@+id/progress_bar\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"-8dp\"\n        android:indeterminate=\"true\"\n        style=\"?android:attr/progressBarStyleHorizontal\" />\n\n    <TextView\n        android:padding=\"20dp\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginLeft=\"20dp\"\n        android:layout_marginRight=\"20dp\"\n        android:id=\"@+id/description_text\"\n        style=\"?attr/textAppearanceListItem\" />\n</LinearLayout>"
  },
  {
    "path": "play-services-core/src/main/res/layout/pick_place.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<LinearLayout 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\n    <include layout=\"@layout/toolbar\"/>\n\n    <RelativeLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dip\"\n        android:layout_weight=\"1\">\n\n<!--        <org.microg.gms.maps.vtm.BackendMapView\n            android:id=\"@+id/map\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"/>\n\n        <ImageView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_centerInParent=\"true\"\n            android:paddingBottom=\"41dip\"\n            android:src=\"@drawable/maps_default_marker\"/>-->\n    </RelativeLayout>\n\n    <LinearLayout\n        android:id=\"@+id/place_picker_select\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"72dp\"\n        android:background=\"?attr/selectableItemBackground\"\n        android:clickable=\"true\"\n        android:orientation=\"horizontal\">\n\n        <ImageView\n            android:id=\"@+id/place_picker_icon\"\n            android:layout_width=\"32.0dip\"\n            android:layout_height=\"72dp\"\n            android:layout_gravity=\"top\"\n            android:layout_marginEnd=\"16.0dip\"\n            android:layout_marginLeft=\"16.0dip\"\n            android:layout_marginRight=\"16.0dip\"\n            android:layout_marginStart=\"16.0dip\"\n            android:src=\"@drawable/ic_map_marker\"/>\n\n        <FrameLayout\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"fill_parent\">\n\n            <TextView\n                android:id=\"@+id/place_picker_title\"\n                android:layout_width=\"fill_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"top\"\n                android:layout_marginTop=\"12.0dip\"\n                android:ellipsize=\"end\"\n                android:maxLines=\"1\"\n                android:text=\"@string/place_picker_select_title\"\n                android:textAppearance=\"?android:textAppearanceMedium\"\n                android:textColor=\"?attr/colorAccent\"/>\n\n            <TextView\n                android:id=\"@+id/place_picker_info\"\n                android:layout_width=\"fill_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"top\"\n                android:layout_marginTop=\"36.0dip\"\n                android:ellipsize=\"end\"\n                android:lines=\"1\"\n                android:text=\"(0.0000000, 0.0000000)\"\n                android:textAppearance=\"?android:textAppearanceSmall\"/>\n        </FrameLayout>\n    </LinearLayout>\n\n    <View\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"2dp\"\n        android:background=\"#7f7f7f7f\"/>\n\n    <LinearLayout\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:background=\"#fff1f1f1\"\n        android:focusable=\"false\"\n        android:orientation=\"vertical\"\n        android:paddingLeft=\"8.0dip\"\n        android:paddingRight=\"8.0dip\">\n\n        <TextView\n            android:id=\"@id/title\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"40.0dip\"\n            android:gravity=\"center_vertical\"\n            android:paddingLeft=\"8.0dip\"\n            android:text=\"@string/place_picker_nearby_places\"\n            android:textAllCaps=\"true\"\n            android:textAppearance=\"?android:textAppearanceSmall\"\n            android:textColor=\"#ff7f7f7f\"\n            android:textStyle=\"bold\"/>\n\n        <RelativeLayout\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center_horizontal\">\n\n            <TextView\n                android:id=\"@+id/hint\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:padding=\"16.0dip\"\n                android:text=\"Can't load nearby places.\"\n                android:textAppearance=\"?android:textAppearanceLarge\"\n                android:textColor=\"#ff7f7f7f\"/>\n        </RelativeLayout>\n    </LinearLayout>\n\n</LinearLayout>\n"
  },
  {
    "path": "play-services-core/src/main/res/layout/preference_material_switch.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Derived from https://github.com/androidx/androidx/blob/8cb282cc/preference/preference/res/layout/preference_widget_switch_compat.xml -->\n<com.google.android.material.materialswitch.MaterialSwitch xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:id=\"@+id/switchWidget\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:background=\"@null\"\n    android:clickable=\"false\"\n    android:focusable=\"false\" />\n"
  },
  {
    "path": "play-services-core/src/main/res/layout/preference_material_switch_bar.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2024 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<LinearLayout 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    android:background=\"@android:color/transparent\"\n    android:minHeight=\"?attr/listPreferredItemHeight\"\n    android:paddingStart=\"?attr/listPreferredItemPaddingStart\"\n    android:paddingLeft=\"?attr/listPreferredItemPaddingLeft\"\n    android:paddingEnd=\"?attr/listPreferredItemPaddingEnd\"\n    android:paddingRight=\"?attr/listPreferredItemPaddingRight\"\n    android:paddingTop=\"16dp\"\n    android:paddingBottom=\"16dp\">\n\n    <LinearLayout\n        android:id=\"@+id/frame\"\n        android:minHeight=\"72dp\"\n        android:layout_height=\"wrap_content\"\n        android:layout_width=\"match_parent\"\n        android:paddingStart=\"20dp\"\n        android:paddingLeft=\"20dp\"\n        android:paddingEnd=\"20dp\"\n        android:paddingRight=\"20dp\"\n        android:paddingHorizontal=\"20dp\">\n\n        <TextView\n            android:id=\"@android:id/title\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center_vertical\"\n            android:layout_marginEnd=\"24dp\"\n            android:layout_marginRight=\"24dp\"\n            android:layout_marginVertical=\"24dp\"\n            android:layout_weight=\"1\"\n            android:ellipsize=\"end\"\n            android:textAppearance=\"?attr/textAppearanceListItem\"\n            android:textSize=\"20sp\"\n            android:textColor=\"@color/material_switch_bar_text_color\"\n            tools:text=\"Enabled\"\n            style=\"@style/TextAppearance.AppCompat.Widget.ActionBar.Title.Inverse\"/>\n\n        <com.google.android.material.materialswitch.MaterialSwitch\n            android:id=\"@+id/switch_widget\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"48dp\"\n            android:layout_gravity=\"center_vertical\"\n            android:focusable=\"false\"\n            android:clickable=\"false\"\n            tools:checked=\"true\" />\n\n    </LinearLayout>\n</LinearLayout>\n"
  },
  {
    "path": "play-services-core/src/main/res/layout/safety_net_advanced_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2021 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n    <androidx.fragment.app.FragmentContainerView\n        android:id=\"@+id/droidguard_sub_preferences\"\n        android:name=\"org.microg.gms.droidguard.core.ui.DroidGuardPreferencesFragment\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_weight=\"1\"/>\n</LinearLayout>\n"
  },
  {
    "path": "play-services-core/src/main/res/layout/safety_net_recent_card.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<LinearLayout 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:padding=\"16dp\"\n    android:orientation=\"horizontal\">\n\n    <ImageView\n        android:id=\"@+id/snet_recent_appicon\"\n\n        android:layout_width=\"48dp\"\n        android:layout_height=\"48dp\"\n        android:antialias=\"true\"\n        tools:src=\"@android:mipmap/sym_def_app_icon\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:paddingStart=\"8dp\"\n        android:paddingEnd=\"8dp\"\n        android:orientation=\"vertical\">\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"0dp\"\n            android:layout_weight=\"1\"\n            android:orientation=\"horizontal\">\n\n            <TextView\n                android:id=\"@+id/snet_recent_type\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                tools:text=\"Request type\" />\n\n            <TextView\n                android:id=\"@+id/snet_recent_date\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"end\"\n                tools:text=\"Date\" />\n        </LinearLayout>\n\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"horizontal\">\n\n            <TextView\n                android:id=\"@+id/snet_recent_package\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                tools:text=\"Package name\" />\n\n            <TextView\n                android:id=\"@+id/snet_recent_infomsg\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"end\"\n                tools:text=\"Info msg\" />\n\n        </LinearLayout>\n    </LinearLayout>\n\n</LinearLayout>"
  },
  {
    "path": "play-services-core/src/main/res/layout/safety_net_recent_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<layout 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\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\">\n\n        <androidx.fragment.app.FragmentContainerView\n            android:id=\"@+id/actual_content\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"0dp\"\n            android:layout_weight=\"1\"/>\n\n    </LinearLayout>\n\n</layout>\n"
  },
  {
    "path": "play-services-core/src/main/res/layout/safety_net_recents_list_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <androidx.recyclerview.widget.RecyclerView\n        android:id=\"@+id/snet_recent_recyclerview\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n    </androidx.recyclerview.widget.RecyclerView>\n\n\n</LinearLayout>\n"
  },
  {
    "path": "play-services-core/src/main/res/layout/settings_root_activity.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\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    android:orientation=\"vertical\"\n    android:fitsSystemWindows=\"true\">\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\n        <com.google.android.material.appbar.CollapsingToolbarLayout\n            android:id=\"@+id/collapsing_toolbar\"\n            style=\"?attr/collapsingToolbarLayoutLargeStyle\"\n            android:layout_width=\"match_parent\"\n            app:layout_scrollFlags=\"scroll|exitUntilCollapsed|snap\"\n            android:layout_height=\"?attr/collapsingToolbarLayoutLargeSize\">\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:layout_collapseMode=\"pin\" />\n\n        </com.google.android.material.appbar.CollapsingToolbarLayout>\n\n    </com.google.android.material.appbar.AppBarLayout>\n\n    <androidx.core.widget.NestedScrollView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:fillViewport=\"true\"\n        app:layout_behavior=\"@string/appbar_scrolling_view_behavior\">\n\n        <androidx.fragment.app.FragmentContainerView\n            android:id=\"@+id/navhost\"\n            android:name=\"androidx.navigation.fragment.NavHostFragment\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            app:defaultNavHost=\"true\"\n            app:navGraph=\"@navigation/nav_settings\" />\n    </androidx.core.widget.NestedScrollView>\n</androidx.coordinatorlayout.widget.CoordinatorLayout>\n"
  },
  {
    "path": "play-services-core/src/main/res/layout/signin_account_row.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\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    xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginHorizontal=\"24dp\"\n        android:orientation=\"horizontal\">\n\n        <de.hdodenhof.circleimageview.CircleImageView\n            android:layout_gravity=\"center_vertical\"\n            android:src=\"@drawable/ic_generic_man\"\n            android:id=\"@+id/account_photo\"\n            android:layout_marginVertical=\"12dp\"\n            android:layout_width=\"32dp\"\n            android:layout_height=\"32dp\" />\n\n        <LinearLayout\n            android:layout_marginVertical=\"12dp\"\n            android:layout_marginLeft=\"12dp\"\n            android:layout_marginStart=\"12dp\"\n            android:layout_gravity=\"center_vertical\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"vertical\">\n\n            <TextView\n                android:id=\"@+id/account_display_name\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:textAppearance=\"?attr/textAppearanceListItem\"\n                tools:text=\"Ada Lovelace\" />\n\n            <TextView\n                android:id=\"@+id/account_email\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                tools:text=\"example@gmail.com\" />\n        </LinearLayout>\n    </LinearLayout>\n\n    <View\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"1dp\"\n        android:layout_marginHorizontal=\"24dp\"\n        android:background=\"?attr/dividerHorizontal\" />\n</LinearLayout>"
  },
  {
    "path": "play-services-core/src/main/res/layout/signin_confirm.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<layout 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    <data>\n\n        <variable\n            name=\"appName\"\n            type=\"String\" />\n\n        <variable\n            name=\"appIcon\"\n            type=\"android.graphics.drawable.Drawable\" />\n\n        <variable\n            name=\"policySpanned\"\n            type=\"android.text.Spanned\" />\n\n        <variable\n            name=\"listProgressSpinner\"\n            type=\"boolean\" />\n\n        <import type=\"android.view.View\" />\n\n    </data>\n\n    <androidx.core.widget.NestedScrollView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\">\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:background=\"@android:color/white\"\n            android:orientation=\"vertical\">\n\n            <ImageView\n                android:layout_width=\"48dp\"\n                android:layout_height=\"48dp\"\n                android:layout_gravity=\"center_horizontal\"\n                android:layout_marginHorizontal=\"16dp\"\n                android:layout_marginTop=\"32dp\"\n                android:layout_marginBottom=\"16dp\"\n                app:imageDrawable=\"@{appIcon}\"\n                tools:src=\"@mipmap/ic_app\" />\n\n            <TextView\n                style=\"@style/TextAppearance.AppCompat.Title\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center_horizontal\"\n                android:layout_margin=\"2dp\"\n                android:gravity=\"center_horizontal\"\n                android:maxLines=\"2\"\n                android:text=\"@{@string/signin_confirm_title(appName)}\"\n                tools:text=\"@string/signin_confirm_title\" />\n\n            <FrameLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"24dp\">\n\n                <include layout=\"@layout/signin_account_row\" />\n            </FrameLayout>\n\n            <TextView\n                android:id=\"@+id/picker_subtext\"\n                style=\"@style/TextAppearance.AppCompat.Small\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_margin=\"24dp\"\n                android:maxLines=\"6\"\n                android:text='@{@string/signin_subtext_sharing(appName) + (policySpanned != null ? \" \" + policySpanned : \"\")}'\n                tools:text=\"To continue, microG will share name, email address and profile picture of your Google Account with Test App. Before using this app, review its privacy policy and terms of service.\" />\n\n            <LinearLayout\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"end\"\n                android:layout_margin=\"24dp\"\n                android:orientation=\"horizontal\">\n\n                <Button\n                    android:id=\"@android:id/button2\"\n                    style=\"@style/Widget.AppCompat.Button.Borderless\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:text=\"@android:string/cancel\" />\n\n                <Button\n                    android:id=\"@android:id/button1\"\n                    style=\"@style/Widget.AppCompat.Button.Colored\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginStart=\"8dp\"\n                    android:layout_marginLeft=\"8dp\"\n                    android:text=\"@string/signin_confirm_button_text\" />\n            </LinearLayout>\n        </LinearLayout>\n    </androidx.core.widget.NestedScrollView>\n</layout>"
  },
  {
    "path": "play-services-core/src/main/res/layout/signin_picker.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<layout 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\n    <data>\n\n        <variable\n            name=\"appName\"\n            type=\"String\" />\n\n        <variable\n            name=\"appIcon\"\n            type=\"android.graphics.drawable.Drawable\" />\n\n        <variable\n            name=\"policySpanned\"\n            type=\"android.text.Spanned\" />\n\n        <variable\n            name=\"listProgressSpinner\"\n            type=\"boolean\" />\n\n        <import type=\"android.view.View\" />\n\n    </data>\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\">\n\n        <ImageView\n            android:layout_marginTop=\"32dp\"\n            android:layout_marginBottom=\"16dp\"\n            android:layout_marginHorizontal=\"16dp\"\n            android:layout_width=\"48dp\"\n            android:layout_height=\"48dp\"\n            android:layout_gravity=\"center_horizontal\"\n            app:imageDrawable=\"@{appIcon}\"\n            tools:src=\"@mipmap/ic_app\" />\n\n        <TextView\n            android:layout_margin=\"2dp\"\n            android:layout_gravity=\"center_horizontal\"\n            android:gravity=\"center_horizontal\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/signin_picker_title\"\n            android:maxLines=\"2\"\n            style=\"@style/TextAppearance.AppCompat.Title\" />\n\n        <TextView\n            android:id=\"@+id/picker_subtitle\"\n            android:layout_margin=\"2dp\"\n            android:layout_gravity=\"center_horizontal\"\n            android:gravity=\"center_horizontal\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@{@string/signin_picker_subtitle(appName)}\"\n            tools:text=\"@string/signin_picker_subtitle\"\n            style=\"@style/TextAppearance.AppCompat.Medium\" />\n\n        <FrameLayout\n            android:layout_marginTop=\"24dp\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"0dip\"\n            android:layout_weight=\"1\">\n\n            <ListView\n                android:id=\"@+id/picker_list\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                app:alpha=\"@{listProgressSpinner ? 0.6f : 1.0f}\"\n                tools:listitem=\"@layout/signin_account_row\" />\n\n            <ProgressBar\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center\"\n                tools:visibility=\"invisible\"\n                app:visibility='@{listProgressSpinner ? View.VISIBLE : View.INVISIBLE}' />\n\n        </FrameLayout>\n\n        <TextView\n            android:id=\"@+id/picker_subtext\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_margin=\"24dp\"\n            android:maxLines=\"6\"\n            android:text='@{@string/signin_subtext_sharing(appName) + (policySpanned != null ? \" \" + policySpanned : \"\")}'\n            style=\"@style/TextAppearance.AppCompat.Small\"\n            tools:text=\"To continue, microG will share name, email address and profile picture of your Google Account with Test App. Before using this app, review its privacy policy and terms of service.\" />\n    </LinearLayout>\n</layout>"
  },
  {
    "path": "play-services-core/src/main/res/layout-v21/activity_barcode_scanning.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <org.microg.gms.vision.barcode.QRCodeScannerView\n        android:id=\"@+id/scannerView\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"/>\n\n    <ImageView\n        android:id=\"@+id/barcode_scanning_cancel\"\n        android:layout_width=\"32dp\"\n        android:layout_height=\"32dp\"\n        android:layout_gravity=\"start\"\n        android:contentDescription=\"@android:string/cancel\"\n        android:scaleType=\"centerCrop\"\n        android:layout_margin=\"20dp\"\n        android:src=\"@drawable/ic_close_btn\" />\n\n    <TextView\n        android:id=\"@+id/barcode_scanning_tips\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_margin=\"20dp\"\n        android:textSize=\"16dp\"\n        android:textColor=\"@android:color/darker_gray\"\n        android:layout_gravity=\"bottom|center\"/>\n\n</FrameLayout>"
  },
  {
    "path": "play-services-core/src/main/res/layout-w600dp/signin_picker.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<layout 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\n    <data>\n\n        <variable\n            name=\"appName\"\n            type=\"String\" />\n\n        <variable\n            name=\"appIcon\"\n            type=\"android.graphics.drawable.Drawable\" />\n\n        <variable\n            name=\"policySpanned\"\n            type=\"android.text.Spanned\" />\n\n        <variable\n            name=\"listProgressSpinner\"\n            type=\"boolean\" />\n\n        <import type=\"android.view.View\" />\n\n    </data>\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:orientation=\"horizontal\"\n        android:layout_height=\"match_parent\">\n\n        <LinearLayout\n            android:layout_width=\"0dp\"\n            android:layout_weight=\"1\"\n            android:layout_height=\"match_parent\"\n            android:orientation=\"vertical\">\n\n            <ImageView\n                android:layout_marginTop=\"32dp\"\n                android:layout_marginBottom=\"16dp\"\n                android:layout_marginHorizontal=\"16dp\"\n                android:layout_width=\"48dp\"\n                android:layout_height=\"48dp\"\n                android:layout_gravity=\"center_horizontal\"\n                app:imageDrawable=\"@{appIcon}\"\n                tools:src=\"@mipmap/ic_app\" />\n\n            <TextView\n                android:layout_margin=\"2dp\"\n                android:layout_gravity=\"center_horizontal\"\n                android:gravity=\"center_horizontal\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"@string/signin_picker_title\"\n                android:maxLines=\"2\"\n                style=\"@style/TextAppearance.AppCompat.Title\" />\n\n            <TextView\n                android:id=\"@+id/picker_subtitle\"\n                android:layout_margin=\"2dp\"\n                android:layout_gravity=\"center_horizontal\"\n                android:gravity=\"center_horizontal\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"@{@string/signin_picker_subtitle(appName)}\"\n                tools:text=\"@string/signin_picker_subtitle\"\n                style=\"@style/TextAppearance.AppCompat.Medium\" />\n\n            <TextView\n                android:id=\"@+id/picker_subtext\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_margin=\"24dp\"\n                android:maxLines=\"6\"\n                android:text='@{@string/signin_subtext_sharing(appName) + (policySpanned != null ? \" \" + policySpanned : \"\")}'\n                style=\"@style/TextAppearance.AppCompat.Small\"\n                tools:text=\"To continue, microG will share name, email address and profile picture of your Google Account with Test App. Before using this app, review its privacy policy and terms of service.\" />\n        </LinearLayout>\n\n        <FrameLayout\n            android:layout_width=\"0dp\"\n            android:layout_height=\"match_parent\"\n            android:layout_weight=\"1\">\n\n            <ListView\n                android:id=\"@+id/picker_list\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center\"\n                app:alpha=\"@{listProgressSpinner ? 0.6f : 1.0f}\"\n                tools:listitem=\"@layout/signin_account_row\" />\n\n            <ProgressBar\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center\"\n                tools:visibility=\"invisible\"\n                app:visibility='@{listProgressSpinner ? View.VISIBLE : View.INVISIBLE}' />\n\n        </FrameLayout>\n\n    </LinearLayout>\n</layout>"
  },
  {
    "path": "play-services-core/src/main/res/menu/pick_place.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<menu xmlns:tools=\"http://schemas.android.com/tools\"\n      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/menu_action_search\"\n        android:icon=\"@drawable/ic_magnify\"\n        android:title=\"@android:string/search_go\"\n        app:actionViewClass=\"android.support.v7.widget.SearchView\"\n        app:showAsAction=\"ifRoom|collapseActionView\"\n        tools:ignore=\"AppCompatResource\"/>\n</menu>"
  },
  {
    "path": "play-services-core/src/main/res/mipmap-anydpi-v26/ic_app.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: CC-BY-SA-4.0\n  -->\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@color/ic_app_background\"/>\n    <foreground android:drawable=\"@drawable/ic_app_foreground\"/>\n    <monochrome android:drawable=\"@drawable/ic_app_foreground_mono\" />\n</adaptive-icon>"
  },
  {
    "path": "play-services-core/src/main/res/mipmap-anydpi-v26/ic_app_settings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: CC-BY-SA-4.0\n  -->\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@color/ic_app_background\"/>\n    <foreground android:drawable=\"@drawable/ic_app_settings_foreground\"/>\n    <monochrome android:drawable=\"@drawable/ic_app_settings_foreground_mono\" />\n</adaptive-icon>"
  },
  {
    "path": "play-services-core/src/main/res/navigation/nav_settings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<navigation 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/nav_settings\"\n    app:startDestination=\"@id/settingsFragment\">\n\n    <!-- Start -->\n\n    <fragment\n        android:id=\"@+id/settingsFragment\"\n        android:name=\"org.microg.gms.ui.SettingsFragment\"\n        android:label=\"@string/gms_settings_name\">\n        <action\n            android:id=\"@+id/openSelfcheck\"\n            app:destination=\"@id/selfcheckFragment\" />\n        <action\n            android:id=\"@+id/openCheckinSettings\"\n            app:destination=\"@id/checkinFragment\" />\n        <action\n            android:id=\"@+id/openGcmSettings\"\n            app:destination=\"@id/gcmFragment\" />\n        <action\n            android:id=\"@+id/openSafetyNetSettings\"\n            app:destination=\"@id/safetyNetFragment\" />\n        <action\n            android:id=\"@+id/openVendingSettings\"\n            app:destination=\"@id/vendingFragment\" />\n        <action\n            android:id=\"@+id/openWorkProfileSettings\"\n            app:destination=\"@id/workProfileFragment\" />\n        <action\n            android:id=\"@+id/openMoreGoogleSettings\"\n            app:destination=\"@id/googleMoreFragment\" />\n        <action\n            android:id=\"@+id/openLocationSettings\"\n            app:destination=\"@id/nav_location\" />\n        <action\n            android:id=\"@+id/openAbout\"\n            app:destination=\"@id/aboutFragment\" />\n    </fragment>\n\n    <!-- Self-Check -->\n\n    <fragment\n        android:id=\"@+id/selfcheckFragment\"\n        android:name=\"org.microg.gms.ui.SelfCheckFragment\"\n        android:label=\"@string/self_check_title\" />\n\n    <!-- Account -->\n\n    <fragment\n        android:id=\"@+id/accountManagerFragment\"\n        android:name=\"org.microg.gms.ui.AccountsFragment\"\n        android:label=\"@string/pref_accounts_title\">\n        <action\n            android:id=\"@+id/openGameManagerSettings\"\n            app:destination=\"@id/gameManagerFragment\" />\n    </fragment>\n\n    <fragment\n        android:id=\"@+id/gameManagerFragment\"\n        android:name=\"org.microg.gms.ui.GameProfileFragment\"\n        android:label=\"@string/pref_game_accounts_title\"/>\n\n    <!-- Device registration -->\n\n    <fragment\n        android:id=\"@+id/checkinFragment\"\n        android:name=\"org.microg.gms.ui.DeviceRegistrationFragment\"\n        android:label=\"@string/service_name_checkin\"\n        tools:layout=\"@layout/device_registration_fragment\">\n        <deepLink\n            app:uri=\"x-gms-settings://checkin\"\n            app:action=\"org.microg.gms.settings.CHECKIN_SETTINGS\" />\n    </fragment>\n\n    <!-- Push Notifications -->\n\n    <fragment\n        android:id=\"@+id/gcmFragment\"\n        android:name=\"org.microg.gms.ui.PushNotificationFragment\"\n        android:label=\"@string/service_name_mcs\"\n        tools:layout=\"@layout/push_notification_fragment\">\n        <action\n            android:id=\"@+id/openGcmAppDetails\"\n            app:destination=\"@id/gcmAppFragment\" />\n        <action\n            android:id=\"@+id/openAllGcmApps\"\n            app:destination=\"@id/gcmAllAppsFragment\" />\n        <action\n            android:id=\"@+id/openGcmAdvancedSettings\"\n            app:destination=\"@id/gcmAdvancedFragment\" />\n        <deepLink\n            app:uri=\"x-gms-settings://gcm\"\n            app:action=\"org.microg.gms.settings.GCM_SETTINGS\" />\n    </fragment>\n\n    <fragment\n        android:id=\"@+id/gcmAllAppsFragment\"\n        android:name=\"org.microg.gms.ui.PushNotificationAllAppsFragment\"\n        android:label=\"@string/prefcat_push_apps_title\">\n        <action\n            android:id=\"@+id/openGcmAppDetailsFromAll\"\n            app:destination=\"@id/gcmAppFragment\" />\n    </fragment>\n\n    <fragment\n        android:id=\"@+id/gcmAppFragment\"\n        android:name=\"org.microg.gms.ui.PushNotificationAppFragment\"\n        android:label=\"@string/service_name_mcs\"\n        tools:layout=\"@layout/push_notification_app_fragment\">\n        <argument\n            android:name=\"package\"\n            app:argType=\"string\" />\n    </fragment>\n\n    <fragment\n        android:id=\"@+id/gcmAdvancedFragment\"\n        android:name=\"org.microg.gms.ui.PushNotificationAdvancedFragment\"\n        android:label=\"@string/service_name_mcs\" />\n\n    <!-- Device Attestation -->\n\n    <fragment\n        android:id=\"@+id/safetyNetFragment\"\n        android:name=\"org.microg.gms.ui.SafetyNetFragment\"\n        android:label=\"@string/service_name_device_attestation\"\n        tools:layout=\"@layout/safety_net_fragment\">\n        <action\n            android:id=\"@+id/openSafetyNetAppDetails\"\n            app:destination=\"@id/safetyNetAppFragment\" />\n        <action\n            android:id=\"@+id/openAllSafetyNetApps\"\n            app:destination=\"@id/safetyNetAllAppsFragment\" />\n        <action\n            android:id=\"@+id/openSafetyNetAdvancedSettings\"\n            app:destination=\"@id/safetyNetAdvancedFragment\" />\n    </fragment>\n\n    <fragment\n        android:id=\"@+id/safetyNetAdvancedFragment\"\n        android:name=\"org.microg.gms.ui.SafetyNetAdvancedFragment\"\n        android:label=\"@string/service_name_device_attestation\"\n        tools:layout=\"@layout/safety_net_advanced_fragment\" />\n\n    <fragment\n        android:id=\"@+id/safetyNetAllAppsFragment\"\n        android:name=\"org.microg.gms.ui.SafetyNetAllAppsFragment\"\n        android:label=\"@string/prefcat_device_attestation_apps_title\">\n        <action\n            android:id=\"@+id/openSafetyNetAppDetailsFromAll\"\n            app:destination=\"@id/safetyNetAppFragment\" />\n    </fragment>\n\n    <fragment\n        android:id=\"@+id/safetyNetAppFragment\"\n        android:name=\"org.microg.gms.ui.SafetyNetAppFragment\"\n        android:label=\"@string/service_name_device_attestation\"\n        tools:layout=\"@layout/safety_net_app_fragment\">\n        <argument\n            android:name=\"package\"\n            app:argType=\"string\" />\n    </fragment>\n\n    <!-- Play Store services -->\n\n    <fragment\n        android:id=\"@+id/vendingFragment\"\n        android:name=\"org.microg.gms.ui.VendingFragment\"\n        android:label=\"@string/service_name_vending\">\n        <action\n            android:id=\"@+id/openVendingInstallSettings\"\n            app:destination=\"@id/vendingInstallSettingsFragment\"/>\n    </fragment>\n\n    <!-- Install Settings -->\n\n    <fragment\n        android:id=\"@+id/vendingInstallSettingsFragment\"\n        android:name=\"org.microg.gms.ui.VendingInstallSettingsFragment\"\n        android:label=\"@string/pref_app_install_settings_title\" />\n\n    <!-- Work profile -->\n\n    <fragment\n        android:id=\"@+id/workProfileFragment\"\n        android:name=\"org.microg.gms.ui.WorkProfileFragment\"\n        android:label=\"@string/service_name_work_profile\" />\n\n    <!-- More -->\n\n    <fragment\n        android:id=\"@+id/googleMoreFragment\"\n        android:name=\"org.microg.gms.ui.GoogleMoreFragment\"\n        android:label=\"@string/gms_settings_name\" />\n\n    <!-- About -->\n\n    <fragment\n        android:id=\"@+id/aboutFragment\"\n        android:name=\"org.microg.gms.ui.AboutFragment\"\n        android:label=\"@string/prefcat_about\"\n        tools:layout=\"@layout/about_root\" />\n\n    <!-- Included -->\n\n    <include app:graph=\"@navigation/nav_location\" />\n</navigation>\n"
  },
  {
    "path": "play-services-core/src/main/res/values/arrays.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<resources>\n    <string-array name=\"network_types\" translatable=\"false\">\n        <item>mobile</item>\n        <item>wifi</item>\n        <item>roaming</item>\n        <item>other</item>\n    </string-array>\n\n    <string-array name=\"network_types_names\" translatables=\"false\">\n        <item>@string/network_type_mobile</item>\n        <item>@string/network_type_wifi</item>\n        <item>@string/network_type_roaming</item>\n        <item>@string/network_type_other</item>\n    </string-array>\n\n    <string-array name=\"gcm_network_config_values\" translatables=\"false\">\n        <item>-1</item>\n        <item>0</item>\n        <item>1</item>\n        <item>2</item>\n        <item>5</item>\n        <item>10</item>\n        <item>15</item>\n        <item>20</item>\n        <item>30</item>\n    </string-array>\n\n    <string-array name=\"gcm_network_config_names\" translatables=\"false\">\n        <item>@string/service_status_disabled</item>\n        <item>@string/service_status_automatic</item>\n\n        <!-- These will be automatically generated from the OS, no need to translate them -->\n        <item>Ping interval: 60 seconds</item>\n        <item>Ping interval: 2 minutes</item>\n        <item>Ping interval: 5 minutes</item>\n        <item>Ping interval: 10 minutes</item>\n        <item>Ping interval: 15 minutes</item>\n        <item>Ping interval: 20 minutes</item>\n        <item>Ping interval: 30 minutes</item>\n    </string-array>\n</resources>"
  },
  {
    "path": "play-services-core/src/main/res/values/bools.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<resources>\n    <bool name=\"is_gmscore\">true</bool>\n</resources>"
  },
  {
    "path": "play-services-core/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<resources>\n    <color name=\"login_blue_theme_primary\">#ff4285f4</color>\n    <color name=\"login_blue_theme_primary_dark\">#ff3367d6</color>\n    <color name=\"login_blue_theme_accent\">#ffFFAB40</color>\n\n    <color name=\"dialog_border_color\">#88CCCCCC</color>\n    <color name=\"material_error\">#fff44336</color>\n    <color name=\"material_success\">#34a853</color>\n\n    <color name=\"gm3_ref_palette_error10\">#ff410e0b</color>\n    <color name=\"gm3_ref_palette_error100\">#ffffffff</color>\n    <color name=\"gm3_ref_palette_error20\">#ff601410</color>\n    <color name=\"gm3_ref_palette_error30\">#ff8c1d18</color>\n    <color name=\"gm3_ref_palette_error40\">#ffb3261e</color>\n    <color name=\"gm3_ref_palette_error60\">#ffe46962</color>\n    <color name=\"gm3_ref_palette_error80\">#fff2b8b5</color>\n    <color name=\"gm3_ref_palette_error90\">#fff9dedc</color>\n    <color name=\"gm3_ref_palette_grey30\">#ff474747</color>\n    <color name=\"gm3_ref_palette_grey50\">#ff757575</color>\n    <color name=\"gm3_ref_palette_neutral10\">#ff1f1f1f</color>\n    <color name=\"gm3_ref_palette_neutral100\">#ffffffff</color>\n    <color name=\"gm3_ref_palette_neutral20\">#ff303030</color>\n    <color name=\"gm3_ref_palette_neutral6\">#ff131314</color>\n    <color name=\"gm3_ref_palette_neutral90\">#ffe3e3e3</color>\n    <color name=\"gm3_ref_palette_neutral95\">#fff2f2f2</color>\n    <color name=\"gm3_ref_palette_neutral_variant20\">#ff2d312f</color>\n    <color name=\"gm3_ref_palette_neutral_variant30\">#ff444746</color>\n    <color name=\"gm3_ref_palette_neutral_variant40\">#ff5c5f5e</color>\n    <color name=\"gm3_ref_palette_neutral_variant50\">#ff747775</color>\n    <color name=\"gm3_ref_palette_neutral_variant60\">#ff8e918f</color>\n    <color name=\"gm3_ref_palette_neutral_variant70\">#ffa9acaa</color>\n    <color name=\"gm3_ref_palette_neutral_variant80\">#ffc4c7c5</color>\n    <color name=\"gm3_ref_palette_neutral_variant90\">#ffe1e3e1</color>\n    <color name=\"gm3_ref_palette_primary10\">#ff041e49</color>\n    <color name=\"gm3_ref_palette_primary100\">#ffffffff</color>\n    <color name=\"gm3_ref_palette_primary20\">#ff062e6f</color>\n    <color name=\"gm3_ref_palette_primary30\">#ff0842a0</color>\n    <color name=\"gm3_ref_palette_primary40\">#ff0b57d0</color>\n    <color name=\"gm3_ref_palette_primary70\">#ff7cacf8</color>\n    <color name=\"gm3_ref_palette_primary80\">#ffa8c7fa</color>\n    <color name=\"gm3_ref_palette_primary90\">#ffd3e3fd</color>\n    <color name=\"gm3_ref_palette_secondary10\">#ff001d35</color>\n    <color name=\"gm3_ref_palette_secondary100\">#ffffffff</color>\n    <color name=\"gm3_ref_palette_secondary20\">#ff003355</color>\n    <color name=\"gm3_ref_palette_secondary30\">#ff004a77</color>\n    <color name=\"gm3_ref_palette_secondary40\">#ff00639b</color>\n    <color name=\"gm3_ref_palette_secondary70\">#ff5ab3f0</color>\n    <color name=\"gm3_ref_palette_secondary80\">#ff7fcfff</color>\n    <color name=\"gm3_ref_palette_secondary90\">#ffc2e7ff</color>\n    <color name=\"gm3_ref_palette_tertiary10\">#ff072711</color>\n    <color name=\"gm3_ref_palette_tertiary100\">#ffffffff</color>\n    <color name=\"gm3_ref_palette_tertiary20\">#ff0a3818</color>\n    <color name=\"gm3_ref_palette_tertiary30\">#ff0f5223</color>\n    <color name=\"gm3_ref_palette_tertiary40\">#ff146c2e</color>\n    <color name=\"gm3_ref_palette_tertiary80\">#ff6dd58c</color>\n    <color name=\"gm3_ref_palette_tertiary90\">#ffc4eed0</color>\n    <color name=\"gm3_ref_palette_white\">#ffffffff</color>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values/dimens.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<resources>\n    <dimen name=\"maps_watermark_margin\">5.0dip</dimen>\n</resources>"
  },
  {
    "path": "play-services-core/src/main/res/values/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<resources>\n    <string name=\"permission_service_all_label\">All Google services</string>\n    <string name=\"permission_service_all_description\">Allows app to access all Google services through any associated Google account.</string>\n\n    <string name=\"permission_service_android_label\">Android services</string>\n    <string name=\"permission_service_android_description\">Allows app to access Android services through any associated Google account.</string>\n    <string name=\"permission_service_adsense_label\">AdSense</string>\n    <string name=\"permission_service_adsense_description\">Allows app to access AdSense through any associated Google account.</string>\n    <string name=\"permission_service_adwords_label\">AdWords</string>\n    <string name=\"permission_service_adwords_description\">Allows app to access AdWords through any associated Google account.</string>\n    <string name=\"permission_service_ah_label\">Google App Engine</string>\n    <string name=\"permission_service_ah_description\">Allows app to access Google App Engine through any associated Google account.</string>\n    <string name=\"permission_service_blogger_label\">Blogger</string>\n    <string name=\"permission_service_blogger_description\">Allows app to access Blogger through any associated Google account.</string>\n    <string name=\"permission_service_cl_label\">Google Calendar</string>\n    <string name=\"permission_service_cl_description\">Allows app to access Google Calendar through any associated Google account.</string>\n    <string name=\"permission_service_cp_label\">Contacts</string>\n    <string name=\"permission_service_cp_description\">Allows app to access Contacts through any associated Google account.</string>\n    <string name=\"permission_service_dodgeball_label\">Dodgeball</string>\n    <string name=\"permission_service_dodgeball_description\">Allows app to access Dodgeball through any associated Google account.</string>\n    <string name=\"permission_service_finance_label\">Google Finance</string>\n    <string name=\"permission_service_finance_description\">Allows app to access Google Finance through any associated Google account.</string>\n    <string name=\"permission_service_gbase_label\">Google Base</string>\n    <string name=\"permission_service_gbase_description\">Allows app to access Google Base through any associated Google account.</string>\n    <string name=\"permission_service_grandcentral_label\">Google Voice</string>\n    <string name=\"permission_service_grandcentral_description\">Allows app to access Google Voice through any associated Google account.</string>\n    <string name=\"permission_service_groups2_label\">Google Groups</string>\n    <string name=\"permission_service_groups2_description\">Allows app to access Google Groups through any associated Google account.</string>\n    <string name=\"permission_service_health_label\">Google Health</string>\n    <string name=\"permission_service_health_description\">Allows app to access Google Health through any associated Google account.</string>\n    <string name=\"permission_service_ig_label\">iGoogle</string>\n    <string name=\"permission_service_ig_description\">Allows app to access iGoogle through any associated Google account.</string>\n    <string name=\"permission_service_jotspot_label\">JotSpot</string>\n    <string name=\"permission_service_jotspot_description\">Allows app to access JotSpot through any associated Google account.</string>\n    <string name=\"permission_service_knol_label\">Knol</string>\n    <string name=\"permission_service_knol_description\">Allows app to access Knol through any associated Google account.</string>\n    <string name=\"permission_service_lh2_label\">Picasa Web Albums</string>\n    <string name=\"permission_service_lh2_description\">Allows app to access Picasa Web Albums through any associated Google account.</string>\n    <string name=\"permission_service_local_label\">Google Maps</string>\n    <string name=\"permission_service_local_description\">Allows app to access Google Maps through any associated Google account.</string>\n    <string name=\"permission_service_mail_label\">Google Mail</string>\n    <string name=\"permission_service_mail_description\">Allows app to access Google Mail through any associated Google account.</string>\n    <string name=\"permission_service_news_label\">Google News</string>\n    <string name=\"permission_service_news_description\">Allows app to access Google News through any associated Google account.</string>\n    <string name=\"permission_service_notebook_label\">Google Notebook</string>\n    <string name=\"permission_service_notebook_description\">Allows app to access Google Notebook through any associated Google account.</string>\n    <string name=\"permission_service_orkut_label\">Orkut</string>\n    <string name=\"permission_service_orkut_description\">Allows app to access Orkut through any associated Google account.</string>\n    <string name=\"permission_service_print_label\">Google Book Search</string>\n    <string name=\"permission_service_print_description\">Allows app to access Google Book Search through any associated Google account.</string>\n    <string name=\"permission_service_sierra_label\">Google Checkout accounts</string>\n    <string name=\"permission_service_sierra_description\">Allows app to access Google Checkout accounts through any associated Google account.</string>\n    <string name=\"permission_service_sierraqa_label\">Google Checkout QA accounts</string>\n    <string name=\"permission_service_sierraqa_description\">Allows app to access Google Checkout QA accounts through any associated Google account.</string>\n    <string name=\"permission_service_sierrasandbox_label\">Google Checkout Sandbox accounts</string>\n    <string name=\"permission_service_sierrasandbox_description\">Allows app to access Google Checkout Sandbox accounts through any associated Google account.</string>\n    <string name=\"permission_service_sitemaps_label\">Google Webmaster Tools</string>\n    <string name=\"permission_service_sitemaps_description\">Allows app to access Google Webmaster Tools through any associated Google account.</string>\n    <string name=\"permission_service_speech_label\">Voice Search</string>\n    <string name=\"permission_service_speech_description\">Allows app to access Voice Search through any associated Google account.</string>\n    <string name=\"permission_service_speechpersonalization_label\">Personalized Speech Recognition</string>\n    <string name=\"permission_service_speechpersonalization_description\">Allows app to access Personalized Speech Recognition through any associated Google account.</string>\n    <string name=\"permission_service_talk_label\">Google Talk</string>\n    <string name=\"permission_service_talk_description\">Allows app to access Google Talk through any associated Google account.</string>\n    <string name=\"permission_service_wifi_label\">Google Wi-Fi</string>\n    <string name=\"permission_service_wifi_description\">Allows app to access Google Wi-Fi through any associated Google account.</string>\n    <string name=\"permission_service_wise_label\">Google Spreadsheets</string>\n    <string name=\"permission_service_wise_description\">Allows app to access Google Spreadsheets through any associated Google account.</string>\n    <string name=\"permission_service_writely_label\">Google Docs</string>\n    <string name=\"permission_service_writely_description\">Allows app to access Google Docs through any associated Google account.</string>\n    <string name=\"permission_service_youtube_label\">YouTube</string>\n    <string name=\"permission_service_youtube_description\">Allows app to access YouTube through any associated Google account.</string>\n    <string name=\"permission_service_YouTubeUser_label\">YouTube usernames</string>\n    <string name=\"permission_service_YouTubeUser_description\">Allows app to access YouTube username(s) used with any associated Google account.</string>\n\n    <string name=\"perm_activity_recognition_label\">Activity recognition</string>\n    <string name=\"perm_activity_recognition_description\">Allows an app to receive periodic updates of your activity level from Google, for example, if you are walking, driving, cycling, or stationary.</string>\n\n    <string name=\"permission_scope_www.googleapis.com_auth_activity\">View the activity history of your Google Apps</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.buyer\">Manage your Ad Exchange buyer account configuration</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller.readonly\">View your Ad Exchange data</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller\">View and manage your Ad Exchange data</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsensehost\">View and manage your AdSense host data and associated accounts</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense.readonly\">View your AdSense data</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense\">View and manage your AdSense data</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics.readonly\">View your Google Analytics data</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics\">View and manage your Google Analytics data</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_androidpublisher\">Access to the Google Play Android Developer</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appengine.admin\">App engine admin scope.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.migration\">Read and write access to Groups Migration API.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.settings\">View and manage the settings of a Google Apps Group</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.licensing\">Read/write access to License Manager API.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order\">For reseller administrators and users read/write access when testing in the API\\'s sandbox, or read/write access when calling an API operation directly.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order.readonly\">In addition to the overall read/write OAuth scope, use the read only OAuth scope when retrieving the customer\\'s data.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps_reporting_audit.readonly\">Access to the Admin Audit API ReadOnly</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appstate\">Scope for using the App State service.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery.readonly\">View your data in Google BigQuery</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery\">View and manage your data in Google BigQuery</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger\">Manage your Blogger account</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger.readonly\">View your Blogger account</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_books\">Manage your books</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar\">Manage your calendars</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar.readonly\">View your calendars</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_cloudprint\">View and manage your google cloud print data</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute.readonly\">View your Google Compute Engine resources</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute\">View and manage your Google Compute Engine resources</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate.readonly\">View your Google Coordinate jobs</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate\">View and manage your Google Maps Coordinate jobs</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.full_control\">Manage your data and permissions in Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_only\">View your data in Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_write\">Manage your data in Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_dfareporting\">View and manage DoubleClick for Advertisers reports</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.appdata\">Allows access to the Application Data folder</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.apps.readonly\">View your Google Drive apps</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.file\">View and manage Google Drive files that you have opened or created with this app</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.install\">Special scope used to let users approve installation of an app</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.metadata.readonly\">View metadata for files and documents in your Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.readonly\">View the files and documents in your Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.scripts\">Modify your Google Apps Script scripts\\' behavior</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive\">View and manage the files and documents in your Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase.readonly\">view your Freebase account</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase\">Sign in to Freebase with your account</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables\">Manage your Fusion Tables</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables.readonly\">View your Fusion Tables</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_games\">Scope for accessing data from Google Play Games.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan\">Manage your GAN data</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan.readonly\">View your GAN data</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gcm_for_chrome\">CloudMessaging for chrome</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_glass.timeline\">Glass timeline scope</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.compose\">Create, read, update, and delete drafts. Send messages and drafts.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.modify\">All read/write operations except immediate, permanent deletion of threads and messages, bypassing Trash.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.readonly\">Read all resources and their metadata—no write operations.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.best\">Manage your best-available location and location history</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.city\">Manage your city-level location and location history</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.best\">Manage your best-available location</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.city\">Manage your city-level location</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine\">View and manage your Google Maps Engine data</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine.readonly\">View your Google Maps Engine data</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mobilemaps.firstparty\">View and manage your Google Maps for mobile experience</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut\">Manage your Orkut activity</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut.readonly\">View your Orkut data</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.login\">Know your name, basic info, and list of people you\\'re connected to on Google+</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.me\">Know who you are on Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_prediction\">Manage your data in the Google Prediction API</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_shoppingapi\">View your product data</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification\">Manage the list of sites and domains you control</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification.verify_only\">Manage your new site verifications with Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_structuredcontent\">Read/write access to Shopping Content API.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue.consumer\">Consume Tasks from your Taskqueues</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue\">Manage your Tasks</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks\">Manage your tasks</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks.readonly\">View your tasks</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tracks\">Google Maps Tracks API, This scope allows read and write access to your project\\'s data.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_urlshortener\">Manage your goo.gl short URLs</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.email\">View your email address</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.profile\">View basic information about your account</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube\">Manage your YouTube account</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtubepartner\">View and manage your assets and associated content on YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.readonly\">View your YouTube account</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.upload\">Manage your YouTube videos</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics_monetary.readonly\">View YouTube Analytics monetary reports for your YouTube content</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics.readonly\">View YouTube Analytics reports for your YouTube content</string>\n\n</resources>"
  },
  {
    "path": "play-services-core/src/main/res/values/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2017 microG Project Team\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<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <plurals name=\"pref_unifiednlp_summary\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> backend configured</item>\n        <item quantity=\"other\"><xliff:g example=\"3\">%1$d</xliff:g> backends configured</item>\n    </plurals>\n    <plurals name=\"gcm_registered_apps_counter\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> registered App</item>\n        <item quantity=\"other\"><xliff:g example=\"123\">%1$d</xliff:g> registered Apps</item>\n    </plurals>\n    <plurals name=\"cond_perm_summary\">\n        <item quantity=\"one\">A permission required for proper functionality of microG Services is not granted.</item>\n        <item quantity=\"other\">Permissions required for proper functionality of microG Services are not granted.</item>\n    </plurals>\n    <plurals name=\"cond_perm_action\">\n        <item quantity=\"one\">Request missing permission</item>\n        <item quantity=\"other\">Request missing permissions</item>\n    </plurals>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2017 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"gms_app_name\">microG Services</string>\n    <string name=\"limited_services_app_name\">microG Limited Services</string>\n    <string name=\"gms_settings_name\">microG Settings</string>\n    <string name=\"gms_settings_summary\">Setup microG services.</string>\n\n    <string name=\"just_a_sec\">Just a sec…</string>\n    <string name=\"google_account_label\">Google</string>\n    <string name=\"ask_permission_tos\">By continuing, you allow this app and Google to use your information in accordance with their respective terms of service and privacy policies.</string>\n    <string name=\"ask_scope_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> would like to:</string>\n    <string name=\"ask_service_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> would like to use:</string>\n    <string name=\"account_manager_title\">Google Account Manager</string>\n    <string name=\"sorry\">Sorry…</string>\n    <string name=\"auth_before_connect\">\"An app on your device is trying to sign in to a Google account.\n\nIf this was intentional, use the <b>Sign in</b> button to connect to Google’s sign-in page, if not, press <b>Cancel</b> to go back to the application that caused this dialog to show up.\"</string>\n    <string name=\"auth_sign_in\">Sign in</string>\n    <string name=\"auth_connecting\">\"Your device is establishing a connection to Google’s servers to sign you in.\n\nThis can take a few seconds.\"</string>\n    <string name=\"no_network_error_desc\">\"You don’t have a network connection.\n\nThis could be a temporary problem or your Android device may not be provisioned for data services. Try again when connected to a mobile network, or connect to a Wi-Fi network.\"</string>\n    <string name=\"auth_general_error_desc\">\"There was a problem communicating with Google servers.\n\nTry again later.\"</string>\n    <string name=\"auth_finalize\">\"Your device is contacting Google to save information to your account.\n\nThis can take a couple of minutes.\"</string>\n    <string name=\"allow\">Allow</string>\n    <string name=\"deny\">Deny</string>\n    <string name=\"auth_notification_title\">Authentication required</string>\n    <string name=\"auth_notification_content\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> requires your authorization to access your Google account.</string>\n    <string name=\"auth_package_override_request_title\">\"Allow <b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> privileged access to <xliff:g example=\"account@example.com\">%2$s</xliff:g>?\"</string>\n    <string name=\"auth_package_override_request_message\">\"<b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> wants to access your account as if it was <b><xliff:g example=\"F-Droid\">%2$s</xliff:g> by <xliff:g example=\"F-Droid Inc.\">%3$s</xliff:g></b>. This might grant it privileged access to your account.\"</string>\n    <string name=\"auth_action_notification_channel_name\">Google account alerts</string>\n    <string name=\"auth_action_notification_channel_description\">Notifies when one of your Google accounts requires additional setup before it can be used or when an account is incompatible with microG.</string>\n    <string name=\"auth_action_notification_title\">Account action required</string>\n    <string name=\"auth_action_notification_content\">Your Google account needs additional setup.</string>\n\n    <string name=\"auth_action_reauth_notification_title\">Account action required</string>\n    <string name=\"auth_action_activity_header\">Finish setting up your Google account</string>\n    <string name=\"auth_action_activity_explanation\">Complete the following steps to be able to use your Google account %s on this device.</string>\n    <string name=\"auth_action_step_enable_checkin\">Enable device registration</string>\n    <string name=\"auth_action_step_enable_checkin_description\">\"Your device needs to register to Google at least once.\n\nYou can disable Google device registration after account setup is complete.</string>\n    <string name=\"auth_action_step_enable_gcm\">Enable Cloud Messaging</string>\n    <string name=\"auth_action_step_enable_gcm_description\">You can disable Cloud Messaging after account setup is complete.</string>\n    <string name=\"auth_action_step_allow_microg_gcm\">Allow Cloud Messaging for microG</string>\n    <string name=\"auth_action_step_allow_microg_gcm_description\">According to your preferences, microG needs permission from you before it can register itself for Cloud Messaging.</string>\n    <string name=\"auth_action_step_enable_lockscreen\">Configure secure screen lock</string>\n    <string name=\"auth_action_step_enable_lockscreen_description\">\"Your Google account is managed by your workplace or educational institution. Your administrator decided that devices need a secure screen lock before they can access account data.\n\nPlease set up a password, PIN, or pattern lock screen.\"</string>\n    <string name=\"auth_action_step_perform_content_description\">Click to perform step</string>\n    <string name=\"auth_action_step_completed_content_description\">Step completed</string>\n    <string name=\"auth_action_activity_finish\">Finish</string>\n\n    <string name=\"signin_picker_title\">Choose an account</string>\n    <string name=\"signin_picker_subtitle\">to continue to <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"signin_picker_add_account_label\">Add another account</string>\n    <string name=\"signin_confirm_title\">Allow to sign you in to <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"signin_confirm_button_text\">Allow and share</string>\n    <string name=\"signin_subtext_sharing\">To continue, microG will share name, email address and profile picture of your Google Account with <xliff:g example=\"F-Droid\">%1$s</xliff:g>.</string>\n    <string name=\"signin_subtext_policy\">Before using this app, review its %1$s and %2$s.</string>\n    <string name=\"signin_subtext_policy_privacy\">privacy policy</string>\n    <string name=\"signin_subtext_policy_terms\">terms of service</string>\n\n    <string name=\"perm_status_broadcast_label\">listen to internal status broadcasts</string>\n    <string name=\"perm_gsf_read_gservices_label\">read Google service configuration</string>\n    <string name=\"perm_c2dm_receive_label\">listen to C2DM messages</string>\n    <string name=\"perm_c2dm_send_label\">send C2DM messages to other apps</string>\n    <string name=\"perm_gtalk_svc_label\">exchange messages and receive sync notifications from Google servers</string>\n    <string name=\"perm_extended_access_label\">Extended access to Google services</string>\n    <string name=\"perm_provision_label\">provision microG services</string>\n    <string name=\"perm_provision_description\">Allows the app to configure microG services without user interaction</string>\n\n    <string name=\"perm_car_speed_label\">Car speed</string>\n    <string name=\"perm_car_speed_description\">\"Access your car's speed\"</string>\n\n    <string name=\"perm_car_info_label\">Car information</string>\n    <string name=\"perm_car_info_description\">\"Access your car's information\"</string>\n    <string name=\"perm_car_fuel_label\">Car fuel level</string>\n    <string name=\"perm_car_fuel_description\">\"Access your car's fuel level information\"</string>\n    <string name=\"perm_car_mileage_label\">Car mileage</string>\n    <string name=\"perm_car_mileage_description\">\"Access your car's mileage information\"</string>\n    <string name=\"perm_car_vendor_extension_label\">Car vendor channel</string>\n    <string name=\"perm_car_vendor_extension_description\">\"Access your car's vendor channel to exchange car-specific information\"</string>\n\n    <string name=\"service_name_checkin\">Google device registration</string>\n    <string name=\"service_name_mcs\">Cloud Messaging</string>\n    <string name=\"service_name_snet\">Google SafetyNet</string>\n    <string name=\"service_name_device_attestation\">Device Attestation</string>\n    <string name=\"service_name_vending\">Play Store services</string>\n    <string name=\"service_name_work_profile\">Work profile</string>\n\n    <string name=\"games_title\">Google Play Games</string>\n    <string name=\"games_info_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> would like to use Play Games</string>\n    <string name=\"games_info_content\">To use Play Games it is required to install the Google Play Games app. The application might continue without Play Games, but it is possible that it will behave unexpectedly.</string>\n\n    <string name=\"pick_place_title\">Pick a place</string>\n    <string name=\"pick_place_desc\">Place picker is not yet available.</string>\n    <string name=\"place_picker_select_title\">Select this location</string>\n    <string name=\"place_picker_nearby_places\">Nearby places</string>\n    <string name=\"place_picker_location_lat_lng\">(%1$.7f, %2$.7f)</string>\n\n    <string name=\"lacking_permission_toast\">microG Services: Lacking permission to <xliff:g example=\"have full network acccess\">%1$s</xliff:g></string>\n\n    <string name=\"network_type_mobile\">Mobile network</string>\n    <string name=\"network_type_wifi\">Wi-Fi</string>\n    <string name=\"network_type_roaming\">Roaming</string>\n    <string name=\"network_type_other\">Other networks</string>\n\n    <!-- Self check -->\n\n    <string name=\"self_check_cat_fake_sig\">Signature spoofing support</string>\n    <string name=\"self_check_cat_gms_packages\">Installed packages</string>\n    <string name=\"self_check_cat_system\">System</string>\n\n    <string name=\"self_check_name_fake_sig_perm\">System has signature spoofing support: </string>\n    <string name=\"self_check_resolution_fake_sig_perm\">Your ROM has no native support for signature spoofing. You can still use Xposed or other systems to spoof signature. Please check the documentation on which ROMs do support signature spoofing and how to use microG on ROMs that do not.</string>\n    <string name=\"self_check_name_perm_granted\">System grants signature spoofing permission: </string>\n    <string name=\"self_check_resolution_perm_granted\">This is a strong indicator that the ROM does support signature spoofing, but requires further action to activate it. Please check the documentation on which steps might be required.</string>\n    <string name=\"self_check_name_system_spoofs\">System spoofs signature: </string>\n    <string name=\"self_check_resolution_system_spoofs\">Please check the documentation on which steps might be required.</string>\n\n    <string name=\"self_check_pkg_gms\">microG Services</string>\n    <string name=\"self_check_pkg_vending\">microG Companion / Play Store</string>\n    <string name=\"self_check_pkg_gsf\">microG Services Framework</string>\n    <string name=\"self_check_name_app_installed\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> installed: </string>\n    <string name=\"self_check_resolution_app_installed\">Install the application <xliff:g example=\"F-Droid\">%1$s</xliff:g> or a compatible one. Please check the documentation on which applications are compatible.</string>\n    <string name=\"self_check_name_correct_sig\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> has correct signature: </string>\n    <string name=\"self_check_resolution_correct_sig\">Either the installed <xliff:g example=\"F-Droid\">%1$s</xliff:g> is not compatible or signature spoofing is not active for it. Please check the documentation on which applications and ROMs are compatible.</string>\n\n    <string name=\"self_check_name_battery_optimizations\">Battery optimizations ignored:</string>\n    <string name=\"self_check_resolution_battery_optimizations\">Touch here to disable battery optimizations. Not doing this may result in misbehaving applications.</string>\n\n    <!-- Settings strings -->\n\n    <string name=\"prefcat_about\">About</string>\n    <string name=\"prefcat_components\">Components</string>\n    <string name=\"prefcat_configuration\">Configuration</string>\n    <string name=\"prefcat_google_services\">Google Services</string>\n    <string name=\"prefcat_location_service\">Location service</string>\n    <string name=\"prefcat_services\">Services</string>\n    <string name=\"prefcat_test\">Test</string>\n\n    <string name=\"cond_gcm_bat_title\">Battery optimizations enabled</string>\n    <string name=\"cond_gcm_bat_summary\">You enabled Cloud Messaging but have battery optimizations active for microG Services. For push notifications to arrive you should ignore battery optimizations.</string>\n    <string name=\"cond_gcm_bat_action\">Ignore optimizations</string>\n    <string name=\"cond_perm_title\">Permission missing</string>\n\n    <string name=\"prefs_account\">Account preferences</string>\n    <string name=\"prefs_account_privacy\">Personal info &amp; privacy</string>\n    <string name=\"prefs_account_security\">Sign-in &amp; security</string>\n\n    <string name=\"pref_auth_trust_google_title\">Trust Google for app permissions</string>\n    <string name=\"pref_auth_trust_google_summary\">When disabled, the user is asked before an app\\'s authorization request is sent to Google. Some applications will fail to use the Google account if this is disabled.</string>\n    <string name=\"pref_auth_visible_title\">Allow apps to find accounts</string>\n    <string name=\"pref_auth_visible_summary\">When enabled, all applications on this device will be able to see email address of your Google Accounts without prior authorization.</string>\n    <string name=\"pref_auth_include_android_id_title\">Authenticate with device registration</string>\n    <string name=\"pref_auth_include_android_id_summary\">When disabled, authentication requests won\\'t be linked to the device registration, which may allow unauthorized devices to sign in, but may have unforeseen consequences.</string>\n    <string name=\"pref_auth_strip_device_name_title\">Strip device name for authentication</string>\n    <string name=\"pref_auth_strip_device_name_summary\">When enabled, authentication requests won\\'t include the device\\'s name, which may allow unauthorized devices to sign in, but may have unforeseen consequences.</string>\n    <string name=\"pref_auth_two_step_verification_title\">Receive two-step verification prompts</string>\n    <string name=\"pref_auth_two_step_verification_summary\">When enabled, the device can receive two-step verification prompts from Google (Cloud Messaging is required).</string>\n\n    <string name=\"pref_checkin_enable_summary\">Registers your device to Google services and creates a unique device identifier. microG strips identifying bits other than your Google account name from registration data.</string>\n    <string name=\"pref_device_registration_android_id\">Android ID</string>\n\n    <string name=\"checkin_not_registered\">Not registered</string>\n    <string name=\"checkin_last_registration\">Last registration: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"checkin_enable_switch\">Register device</string>\n\n    <string name=\"pref_info_status\">Status</string>\n    <string name=\"pref_more_settings\">More</string>\n\n    <string name=\"pref_accounts_title\">Google Accounts</string>\n    <string name=\"pref_game_accounts_title\">Google Game Accounts</string>\n    <string name=\"pref_accounts_summary\">Add and manage Google accounts</string>\n    <string name=\"prefcat_accounts_settings_title\">Settings</string>\n    <string name=\"prefcat_accounts_current_accounts_title\">Accounts</string>\n    <string name=\"pref_add_account_title\">Account</string>\n    <string name=\"pref_add_account_summary\">Add Google account</string>\n\n    <string name=\"pref_gcm_enable_mcs_summary\">Cloud Messaging is a push notification provider used by many third-party applications. To use it you must enable device registration.</string>\n    <string name=\"pref_gcm_heartbeat_title\">Cloud Messaging heartbeat interval</string>\n    <string name=\"pref_gcm_heartbeat_summary\">The interval in seconds for the system to heartbeat the Google servers. Increasing this number will reduce battery consumption, but might cause delays on push messages.\\nDeprecated, will be replaced in future release.</string>\n    <string name=\"pref_gcm_apps_title\">Apps using Cloud Messaging</string>\n    <string name=\"pref_gcm_apps_summary\">List of apps currently registered for Cloud Messaging.</string>\n    <string name=\"pref_gcm_confirm_new_apps_title\">Confirm new apps</string>\n    <string name=\"pref_gcm_confirm_new_apps_summary\">Ask before registering a new app to receive push notifications</string>\n    <string name=\"pref_gcm_ping_interval\">Ping interval: <xliff:g example=\"10 minutes\">%1$s</xliff:g></string>\n\n    <string name=\"pref_about_title\">About microG Services</string>\n    <string name=\"pref_about_summary\">Version information and used libraries</string>\n\n    <string name=\"gcm_app_error_unregistering\">Error unregistering</string>\n    <string name=\"gcm_app_not_installed_anymore\">No longer installed</string>\n    <string name=\"gcm_unregister_app\">Unregister</string>\n    <string name=\"gcm_not_registered\">Not registered</string>\n    <string name=\"gcm_no_message_yet\">No messages received so far</string>\n    <string name=\"gcm_last_message_at\">Last message: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_registered\">Registered</string>\n    <string name=\"gcm_registered_since\">Registered since: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_unregister_confirm_title\">Unregister <xliff:g example=\"F-Droid\">%1$s</xliff:g>?</string>\n    <string name=\"gcm_unregister_confirm_message\">Some apps do not automatically re-register and/or do not provide an option to do so manually. These apps might not work correctly after unregistering.\\nContinue?</string>\n    <string name=\"gcm_unregister_after_deny_message\">You denied an app to register for push notifications that is already registered.\\nDo you want to unregister it now so it does not receive push messages in the future?</string>\n    <string name=\"gcm_messages_counter\">Messages: <xliff:g example=\"123\">%1$d</xliff:g> (<xliff:g example=\"12345\">%2$d</xliff:g> bytes)</string>\n    <string name=\"gcm_network_state_disconnected\">Disconnected</string>\n    <string name=\"gcm_network_state_connected\">Connected since <xliff:g example=\"2 hours ago\">%1$s</xliff:g></string>\n    <string name=\"gcm_enable_switch\">Receive push notifications</string>\n    <string name=\"gcm_allow_app_popup\">Allow <xliff:g example=\"F-Droid\">%1$s</xliff:g> to register for push notifications?</string>\n\n    <string name=\"pref_push_app_allow_register_title\">Allow registration</string>\n    <string name=\"pref_push_app_allow_register_summary\">Allow the app to register for push notifications.</string>\n    <string name=\"pref_push_app_wake_for_delivery_title\">Start app on push message</string>\n    <string name=\"pref_push_app_wake_for_delivery_summary\">Start the app while in background to receive the incoming push messages.</string>\n    <string name=\"prefcat_push_apps_title\">Apps using push notifications</string>\n    <string name=\"prefcat_push_apps_registered_title\">Registered apps</string>\n    <string name=\"prefcat_push_apps_unregistered_title\">Unregistered apps</string>\n    <string name=\"prefcat_push_networks_title\">Networks to use for push notifications</string>\n\n    <string name=\"safetynet_intro\">Google SafetyNet is a device certification system, ensuring that the device is properly secured and compatible with Android CTS. Some applications use SafetyNet for security reasons or as a prerequisite for tamper-protection.\\n\\nmicroG GmsCore contains a free implementation of SafetyNet, but the official server requires SafetyNet requests to be signed using the proprietary DroidGuard system.</string>\n    <string name=\"safetynet_enable_switch\">Allow device attestation</string>\n\n    <string name=\"pref_safetynet_test_title\">Test SafetyNet attestation</string>\n    <string name=\"pref_recaptcha_test_title\">Test ReCAPTCHA</string>\n    <string name=\"pref_recaptcha_enterprise_test_title\">Test ReCAPTCHA Enterprise</string>\n    <string name=\"pref_test_summary_passed\">Passed all tests</string>\n    <string name=\"pref_test_summary_failed\">Failed: %s</string>\n    <string name=\"pref_test_summary_warn\">Warning: %s</string>\n    <string name=\"pref_test_summary_running\">Running…</string>\n    <string name=\"pref_droidguard_operation_mode\">Operation mode</string>\n    <string name=\"pref_droidguard_unsupported_summary\">DroidGuard execution is unsupported on this device. SafetyNet services may misbehave.</string>\n    <string name=\"prefcat_safetynet_apps_title\">Apps using SafetyNet</string>\n    <string name=\"prefcat_device_attestation_apps_title\">Apps using Device Attestation</string>\n    <string name=\"pref_device_attestation_app_allow_requests_title\">Allow requests</string>\n    <string name=\"pref_device_attestation_app_allow_requests_summary\">Allow the app to request device attestation</string>\n    <string name=\"menu_clear_recent_requests\">Clear recent requests</string>\n    <string name=\"safetynet_last_run_at\">Last use: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n\n    <string name=\"profile_name_native\">Native</string>\n    <string name=\"profile_name_real\">Real</string>\n    <string name=\"profile_name_user\">Custom: %s</string>\n    <string name=\"profile_name_auto\">Automatic: %s</string>\n    <string name=\"profile_name_system\">System: %s</string>\n    <string name=\"pref_device_registration_import_custom_profile_title\">Import custom profile</string>\n    <string name=\"pref_device_registration_serial_title\">Serial</string>\n    <string name=\"pref_device_registration_import_custom_profile_summary\">Import device profile from file</string>\n    <string name=\"pref_device_registration_select_profile_title\">Select profile</string>\n    <string name=\"pref_device_registration_device_profile_category\">Device profile</string>\n\n    <string name=\"pref_safetynet_recent_uses\">Recent uses</string>\n    <string name=\"pref_safetynet_recent_attestation_summary\">Attestation: %s</string>\n    <string name=\"pref_safetynet_recent_recaptcha_summary\">ReCaptcha: %s</string>\n    <string name=\"pref_safetynet_recent_recaptcha_enterprise_summary\">ReCaptcha Enterprise: %s</string>\n    <string name=\"pref_safetynet_recent_copy_json\">Copy JSON JWS data</string>\n    <string name=\"pref_safetynet_recent_advice\">Advice</string>\n    <string name=\"pref_safetynet_recent_eval_type\">Evaluation type</string>\n    <string name=\"pref_safetynet_recent_response_status\">Response status</string>\n    <string name=\"pref_safetynet_recent_cat_response\">Response data</string>\n    <string name=\"pref_safetynet_recent_cat_request\">Request data</string>\n    <string name=\"pref_safetynet_recent_nonce\">Nonce (Hex)</string>\n    <string name=\"pref_safetynet_recent_request_time\">Time of request</string>\n    <string name=\"pref_safetynet_recent_request_type\">Request type</string>\n    <string name=\"pref_safetynet_recent_cat_basic\">Basic data</string>\n    <string name=\"pref_safetynet_recent_token\">Token</string>\n    <string name=\"pref_safetynet_recent_copied\">Copied to clipboard!</string>\n    <string name=\"pref_safetynet_test_integrity_cts_passed\">Integrity and CTS passed</string>\n    <string name=\"pref_safetynet_test_cts_failed\">CTS failed</string>\n    <string name=\"pref_safetynet_test_integrity_failed\">Integrity failed</string>\n    <string name=\"pref_safetynet_test_not_completed\">Not completed yet</string>\n    <string name=\"pref_safetynet_test_no_result\">No result</string>\n    <string name=\"pref_safetynet_test_invalid_json\">Invalid JSON</string>\n\n    <string name=\"push_notifications_summary_off\">OFF</string>\n    <string name=\"push_notifications_summary_automatic\">ON / Automatic: %s</string>\n    <string name=\"push_notifications_summary_manual\">ON / Manual: %s</string>\n    <string name=\"push_notifications_summary_values_seconds\">%s seconds</string>\n    <string name=\"push_notifications_summary_values_minutes\">%s minutes</string>\n\n    <string name=\"pref_vending_summary_licensing_off\">Licensing off</string>\n    <string name=\"pref_vending_summary_licensing_on\">Licensing on</string>\n    <string name=\"pref_vending_licensing_category\">Google Play Licensing</string>\n    <string name=\"pref_vending_licensing_enable_switch\">Answer license verification requests</string>\n    <string name=\"pref_vending_license_enable_summary\">Some apps require verification that you have purchased them on Google Play. When requested by an app, microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored.</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_switch\">Automatically add free apps to library</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_summary\">Free apps may check whether they had been downloaded from Google Play. Automatically add free apps to your account library to always pass the check for all free apps currently available to you.</string>\n    <string name=\"pref_vending_feature_delivery\">Google Play Feature Delivery</string>\n    <string name=\"pref_vending_split_install_switch\">On-demand component installation</string>\n    <string name=\"pref_vending_licensing_split_install_summary\">Allow apps to download and install additional components</string>\n\n    <string name=\"feedback_disabled\">Feedback currently not possible</string>\n    <string name=\"backup_disabled\">Backup currently not possible</string>\n\n    <string name=\"pref_vending_billing_category\">Google Play Billing</string>\n    <string name=\"pref_vending_billing_enable_switch\">Handle billing requests</string>\n    <string name=\"pref_vending_billing_enable_summary\">Once enabled, some apps can complete purchases or start subscriptions through Google\\'s Play Billing service.</string>\n    <string name=\"pref_vending_billing_note_experimental\">This feature is experimental and may lead to loss of money. You have been warned.</string>\n    <string name=\"pref_vending_billing_note_licensing\">Some apps may require you to also enable license verification to verify your purchases.</string>\n\n    <string name=\"pref_vending_asset_delivery_category\">Google Play Asset Delivery</string>\n    <string name=\"pref_vending_asset_delivery_switch\">Enable on-demand asset delivery</string>\n    <string name=\"pref_vending_asset_delivery_summary\">Download additional assets when requested by apps that use Play Asset Delivery</string>\n    <string name=\"pref_vending_asset_device_sync_summary\">Applications using Play Asset Delivery will download additional assets based on the information of the device currently in use.</string>\n    <string name=\"pref_vending_asset_device_sync_switch\">Enable device information sync</string>\n\n    <string name=\"pref_workprofile_create_account\">Allow work account setup</string>\n    <string name=\"pref_workprofile_intro\">When setting up a work profile for your workplace or educational institution,\n        setup may attempt to connect to Google to enable downloading apps to that profile.</string>\n    <string name=\"pref_workprofile_disclaimer\">It is your responsibility to ensure that your usage of microG is in line with corporate policies.\n        microG is provided on a best-effort basis and cannot guarantee to behave exactly as expected.</string>\n\n    <string name=\"pref_auto_create_player\">Allow Play Games account registration</string>\n    <string name=\"pref_auto_create_player_intro\">When playing games, you need to use a Play Games account to log in and record game-related functions, such as achievements, leaderboards, archives, etc. After disabling, Google accounts that are not bound to a Play Games account will not be automatically registered, and the game will not be able to log in and play.</string>\n    <string name=\"pref_allow_upload_game_played\">Allow uploading of game played</string>\n    <string name=\"pref_allow_upload_game_played_summary\">When disabled, the game will not report the game played status after logging into the game, and some games may not be able to log in.</string>\n    <string name=\"pref_change_default_game_player\">Change account for games</string>\n    <string name=\"pref_change_default_game_player_summary\">Change the default account for games &amp; Change the account by game.</string>\n    <string name=\"pref_delete_game_account_data\">Delete Play Games data</string>\n    <string name=\"pref_delete_game_account_data_summary\">Delete Play Games account &amp; all data &amp; Delete individual game data.</string>\n\n    <string name=\"credentials_assisted_cancel\">Cancel</string>\n    <string name=\"credentials_assisted_continue\">Continue</string>\n    <string name=\"credentials_assisted_confirmation_header\">Signing you in</string>\n    <string name=\"credentials_assisted_continue_as_user_button_label\">Continue as %1$s</string>\n    <string name=\"credentials_assisted_sign_back_title\">Sign back in to %1$s with Google</string>\n    <string name=\"credentials_assisted_signin_consent_header\">Signing as %1$s</string>\n    <string name=\"credentials_assisted_signin_consent\">By continuing, Google will share your name, email address, and profile picture with %1$s. See %1$s\\'s Privacy Policy and Terms of Service.</string>\n    <string name=\"credentials_assisted_signin_description\">You can manage Sign in with Google in your Google Accounts.</string>\n    <string name=\"credentials_assisted_choose_account_label\">Choose account</string>\n    <string name=\"credentials_assisted_choose_account_subtitle\">to continue to %1$s</string>\n    <string name=\"credentials_assisted_choose_account_error_tips\">Account abnormality</string>\n    <string name=\"credentials_assisted_signin_button_text_long\">Sign in with Google</string>\n    <string name=\"credentials_assisted_signin_add_account\">Add Account</string>\n\n    <string name=\"limited_services_dialog_information\">You are using the microG Limited Services. Unlike the usual microG Services, this flavor only works with apps using microG libraries, not those on Google Play. This means that most applications will ignore these services.</string>\n    <string name=\"limited_services_dialog_information_ack\">I understand</string>\n\n    <string name=\"games_achievement_list_title\">Achievements</string>\n    <string name=\"games_achievements_empty_text\">No achievements for this game</string>\n    <string name=\"games_api_access_denied\">No account on this device can access the Games APIs</string>\n    <string name=\"games_achievement_locked_content_description\">locked</string>\n    <string name=\"games_achievement_unlocked_content_description\">unlocked</string>\n    <string name=\"games_achievement_extra_text\">%1$s XP</string>\n    <string name=\"games_leaderboard_empty_text\">No leaderboards for this game</string>\n    <string name=\"games_leaderboard_score_empty_text\">Unbelievable! There are no public high scores for this game.</string>\n    <string name=\"games_leaderboard_list_title\">Rankings</string>\n    <string name=\"games_leaderboards_score_label\">Score: %1$s</string>\n    <string name=\"games_snapshot_empty_text\">No game saves have been saved yet</string>\n    <string name=\"games_snapshot_choose_btn_text\">select</string>\n    <string name=\"games_snapshot_delete_btn_text\">delete</string>\n    <string name=\"games_delete_snapshot_dialog_title\">Delete saved game</string>\n    <string name=\"games_delete_snapshot_dialog_message\">Are you sure you want to delete this saved game?</string>\n    <string name=\"games_delete_snapshot_dialog_cancel\">Cancel</string>\n    <string name=\"games_delete_snapshot_dialog_ok\">OK</string>\n    <string name=\"games_delete_snapshot_error\">Deletion failed, please try again later</string>\n\n    <string name=\"games_state_description_signed_out\">Signed out</string>\n    <string name=\"games_state_description_delete\">Delete</string>\n    <string name=\"games_change_button_text\">Change</string>\n    <string name=\"games_change_default_account_section_title\">Change the default account for games</string>\n    <string name=\"games_change_default_account_description\">Default account: %1$s</string>\n    <string name=\"games_change_default_account_explanation\">This account is used to automatically sign you in to games, save your game progress, and save your settings. Changing the default account or signing out might reset your progress and settings for games you’ve played.</string>\n    <string name=\"games_change_per_game_title\">Change the account by game</string>\n    <string name=\"games_change_per_game_description\">Changing the account for a selected game or signing out of it might reset your progress and settings for the game.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_title\">Select an option for the new default account</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_description\">Current default account: %1$s</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_title\">Change the default account only for new games </string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_description\">You won\\'t lose access to progress and settings for games you\\'ve played. But your progress will be split between accounts.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_title\"> Change the default account for all games </string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_description\">You might lose access to progress and settings for games you’ve played. We’ll restart the game to apply your changes.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_title\"> Sign out of all games </string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_description\">You might lose access to progress and settings for games you’ve played. We’ll restart the game to apply your changes.</string>\n    <string name=\"games_change_per_game_dialog_title\">Select an option for this game</string>\n    <string name=\"games_change_per_game_dialog_description\">Changing the account or signing out might reset your progress and settings for the game</string>\n    <string name=\"games_change_per_game_dialog_option_use_player\">Use %1$s</string>\n    <string name=\"games_change_per_game_dialog_option_use_player_snackbar_success_message\">You\\'ll be signed in to this game with %1$s</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out\">Sign out</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out_snackbar_success_message\">You\\'re now signed out of this game</string>\n    <string name=\"games_change_sign_out_of_all_games_snackbar_success_message\">You\\'re now signed out of all games</string>\n    <string name=\"games_change_default_account_for_all_games_snackbar_success_message\">You\\'ll be signed in to all games with %1$s</string>\n    <string name=\"games_change_default_account_for_new_games_snackbar_success_message\">You\\'ll be signed in to new games with %1$s</string>\n    <string name=\"games_account_display_content\">Current account: %1$s</string>\n    <string name=\"games_delete_profile_header\">Delete Play Games account &amp; all data</string>\n    <string name=\"games_delete_profile_explanation\">Permanently delete your Google Play Games account, XP, and all profile data. This action might also delete your scores, progress (saved games), and settings in games you\\'ve played.</string>\n    <string name=\"games_delete_profile_button\">Permanently delete</string>\n    <string name=\"games_delete_game_data_header\">Delete individual game data</string>\n    <string name=\"games_delete_game_data_explanation\">You can permanently delete individual data for games you\\'ve played using Google Play Games. This action deletes your scores, progress (saved games), and settings for the game you select.</string>\n    <string name=\"games_delete_profile_dialog_title\">Are you sure you want to delete this account?</string>\n    <string name=\"games_delete_profile_explanation_with_gamer_name\">Permanently delete your Google Play Games account for gamer name &lt;b&gt;%1$s&lt;/b&gt; (&lt;b&gt;%2$s&lt;/b&gt;), XP, and all profile data. This action might also delete your scores, progress (saved games), and settings in games you\\'ve played.</string>\n    <string name=\"games_delete_profile_dialog_message\">This action can\\'t be undone.</string>\n    <string name=\"games_delete_profile_fail\">Couldn\\'t delete your profile. Try again later.</string>\n    <string name=\"games_delete_game_data_confirm_dialog_title\">Delete data for %1$s</string>\n    <string name=\"games_delete_game_data_confirm_dialog_message\">Permanently deleting your data for %1$s will remove your scores, progress (saved games), and game settings in Google Play Games.</string>\n    <string name=\"games_popup_signin_welcome\">Hey there, %1$s</string>\n\n    <string name=\"family_management_title\">Family</string>\n    <string name=\"family_management_retry\">Retry</string>\n    <string name=\"family_management_load_error\">Content loading failed</string>\n    <string name=\"family_management_toolbar_back\">Back</string>\n    <string name=\"family_management_toolbar_more\">More</string>\n    <string name=\"family_management_exit_family_group\">Leave the family group</string>\n    <string name=\"family_management_delete_family_group\">Delete a family group</string>\n    <string name=\"family_management_leave_family_password_title\">Confirm password to leave the family group</string>\n    <string name=\"family_management_delete_family_password_title\">Confirm password to delete a family group</string>\n    <string name=\"family_management_remove_member_password_title\">Confirm password to remove \"%s\"</string>\n    <string name=\"family_management_invite_family_member\">Invite family members</string>\n    <string name=\"family_management_invite_slots_left\">%1$d invitations remaining</string>\n    <string name=\"family_management_cancel_invite\">Cancel invitation</string>\n    <string name=\"family_management_cancel_invite_success\">Cancel invitation successfully</string>\n    <string name=\"family_management_cancel_invite_error\">Trouble cancelling invitation. Try again.</string>\n    <string name=\"family_management_remove_member\">Remove Member</string>\n    <string name=\"family_management_member_removed_success\">%s was removed from your family group</string>\n    <string name=\"family_management_member_remove_failed\">Trouble removing %s. Try again.</string>\n    <string name=\"family_management_leave_family_error_message\">Trouble leaving the family group. Try again.</string>\n    <string name=\"family_management_exist_group_success\">You have left your family group…</string>\n    <string name=\"family_management_delete_group_success\">Family group deleted</string>\n    <string name=\"family_management_delete_group_failure\">Failed to delete home group</string>\n    <string name=\"family_management_delete_group_cancel\">Cancel</string>\n    <string name=\"family_management_delete_group_confirm\">OK</string>\n    <string name=\"family_management_input_pwd\">Please enter your password</string>\n    <string name=\"family_management_invite_sent_date_format\">Invitation sent on %s</string>\n    <string name=\"family_management_invite_send\">Invitation sent</string>\n    <string name=\"family_management_pwd_error\">Wrong password, please re-enter</string>\n\n    <string name=\"barcode_scanner_brand\">Scanned by microG on behalf of %1$s</string>\n    <string name=\"camera_permission_dialog_button\">OK</string>\n    <string name=\"camera_permission_dialog_message\">microG services needs to access your device\\'s camera to scan a code for %1$s.\\n\\nTo enable, please grant camera permission to microG services in Settings.</string>\n    <string name=\"camera_permission_dialog_title\">Camera permission required</string>\n\n    <string name=\"pref_app_install_settings_title\">App Installer Settings</string>\n    <string name=\"pref_app_install_switch_title\">Allow App Installation</string>\n    <string name=\"pref_app_install_other_apps_note\">Authorization allows installation of apps provided from other sources.</string>\n    <string name=\"pref_app_install_permission_instruction\">To ensure that your installed apps work properly, please authorize microG Companion to install apps downloaded from other sources.</string>\n    <string name=\"prefcat_app_install_list_title\">Apps using App Installer</string>\n\n    <string name=\"service_name_google_location_sharing\">Google Location Sharing</string>\n    <string name=\"location_sharing_description\">Manage your real-time Location sharing across Google apps and services from this device</string>\n    <string name=\"location_sharing_learn_more\">Learn more about &quot;Location Sharing&quot;</string>\n    <string name=\"location_sharing_switch_text\">Use Location Sharing</string>\n    <string name=\"location_sharing_turn_off_notify_hint\">If you turn off Location Sharing for this device, people you\\'re sharing with will not be notified.</string>\n    <string name=\"location_sharing_off_previous_hint\">Only your last shared location will be available until you turn it back on.</string>\n    <string name=\"location_sharing_disabled\">No active location shares for this account</string>\n    <string name=\"location_sharing_turn_on_hint\">Once you start sharing your location from a Google app or service, you can manage Location Sharing from here.\\n\\nTo start sharing your location, go to Google Maps or Family Link.</string>\n    <string name=\"location_sharing_turn_off_title\">Turn off Location Sharing</string>\n    <string name=\"location_sharing_turn_off_hint\">You could still be sharing your location from other devices signed in to the same Google Account or from non-Google apps. Make sure to check your location sharing settings anywhere it may apply.\\n\\nPeople you share with will continue to see your last shared location.</string>\n    <string name=\"location_sharing_turn_off_cancel\">Keep on</string>\n    <string name=\"location_sharing_turn_off_confirm\">Turn off</string>\n    <string name=\"location_sharing_confirm_dialog_title\">Enable Location Sharing</string>\n    <string name=\"location_sharing_confirm_dialog_text\">People you share your location with can always see:\\n·Your name and photo\\n·Your device\\'s recent location,even when you\\'re not using a Google service\\n·Your device\\'s battery power,and if it\\'s charging\\n·Your arrival and departure time,if they add a Location Sharing notification</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values/themes.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2015 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<resources xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <!-- Base application theme -->\n    <style name=\"Theme.Base\" parent=\"Theme.Material3.DynamicColors.DayNight\">\n        <item name=\"preferenceTheme\">@style/Theme.Base.PreferenceThemeOverlay</item>\n    </style>\n\n    <style name=\"Theme.Base.DayNight\" parent=\"Theme.Base.Light\" />\n\n    <style name=\"Theme.Base.DayNight.NoActionBar\" parent=\"Theme.Base.Light.NoActionBar\" />\n\n    <style name=\"Theme.Base.Dark\" />\n\n    <style name=\"Theme.Base.Dark.NoActionBar\">\n        <item name=\"windowActionBar\">false</item>\n        <item name=\"windowNoTitle\">true</item>\n    </style>\n\n    <style name=\"Theme.Base.Light\" />\n\n    <style name=\"Theme.Base.Light.NoActionBar\">\n        <item name=\"windowActionBar\">false</item>\n        <item name=\"windowNoTitle\">true</item>\n    </style>\n\n    <style name=\"Theme.Base.DayNight.Dialog.Alert\" parent=\"Theme.Material3.DayNight.Dialog.Alert\" />\n\n    <!-- Preference theme -->\n    <style name=\"Theme.Base.PreferenceThemeOverlay\" parent=\"@style/PreferenceThemeOverlay\">\n        <item name=\"switchPreferenceCompatStyle\">@style/Theme.Base.Preference.SwitchPreferenceCompat</item>\n    </style>\n\n    <style name=\"Theme.Base.Preference.SwitchPreferenceCompat\" parent=\"@style/Preference.SwitchPreferenceCompat.Material\">\n        <item name=\"widgetLayout\">@layout/preference_material_switch</item>\n        <item name=\"singleLineTitle\">false</item>\n    </style>\n\n    <!-- Application theme (< API23) -->\n    <style name=\"Theme.App\" parent=\"Theme.Base.DayNight.NoActionBar\">\n        <item name=\"colorPrimary\">@color/gm3_ref_palette_primary40</item>\n        <item name=\"colorOnPrimary\">@color/gm3_ref_palette_primary100</item>\n        <item name=\"colorPrimaryContainer\">@color/gm3_ref_palette_primary90</item>\n        <item name=\"colorOnPrimaryContainer\">@color/gm3_ref_palette_primary10</item>\n        <item name=\"colorPrimaryInverse\">@color/gm3_ref_palette_primary80</item>\n        <item name=\"colorPrimaryFixed\">@color/gm3_ref_palette_primary90</item>\n        <item name=\"colorPrimaryFixedDim\">@color/gm3_ref_palette_primary80</item>\n        <item name=\"colorOnPrimaryFixed\">@color/gm3_ref_palette_primary10</item>\n        <item name=\"colorOnPrimaryFixedVariant\">@color/gm3_ref_palette_primary30</item>\n        <item name=\"colorSecondary\">@color/gm3_ref_palette_secondary40</item>\n        <item name=\"colorOnSecondary\">@color/gm3_ref_palette_secondary100</item>\n        <item name=\"colorSecondaryContainer\">@color/gm3_ref_palette_secondary90</item>\n        <item name=\"colorOnSecondaryContainer\">@color/gm3_ref_palette_secondary10</item>\n        <item name=\"colorSecondaryFixed\">@color/gm3_ref_palette_secondary90</item>\n        <item name=\"colorSecondaryFixedDim\">@color/gm3_ref_palette_secondary80</item>\n        <item name=\"colorOnSecondaryFixed\">@color/gm3_ref_palette_secondary10</item>\n        <item name=\"colorOnSecondaryFixedVariant\">@color/gm3_ref_palette_secondary30</item>\n        <item name=\"colorTertiary\">@color/gm3_ref_palette_tertiary40</item>\n        <item name=\"colorOnTertiary\">@color/gm3_ref_palette_tertiary100</item>\n        <item name=\"colorTertiaryContainer\">@color/gm3_ref_palette_tertiary90</item>\n        <item name=\"colorOnTertiaryContainer\">@color/gm3_ref_palette_tertiary10</item>\n        <item name=\"colorTertiaryFixed\">@color/gm3_ref_palette_tertiary90</item>\n        <item name=\"colorTertiaryFixedDim\">@color/gm3_ref_palette_tertiary80</item>\n        <item name=\"colorOnTertiaryFixed\">@color/gm3_ref_palette_tertiary10</item>\n        <item name=\"colorOnTertiaryFixedVariant\">@color/gm3_ref_palette_tertiary30</item>\n\n        <item name=\"colorError\">@color/gm3_ref_palette_error40</item>\n        <item name=\"colorOnError\">@color/gm3_ref_palette_error100</item>\n        <item name=\"colorErrorContainer\">@color/gm3_ref_palette_error90</item>\n        <item name=\"colorOnErrorContainer\">@color/gm3_ref_palette_error10</item>\n        <item name=\"colorOutline\">@color/gm3_ref_palette_neutral_variant50</item>\n        <item name=\"colorOutlineVariant\">@color/gm3_ref_palette_neutral_variant80</item>\n        <item name=\"android:colorBackground\">@color/gm3_ref_palette_neutral100</item>\n        <item name=\"colorOnBackground\">@color/gm3_ref_palette_neutral10</item>\n        <item name=\"colorSurface\">@color/gm3_ref_palette_neutral100</item>\n        <item name=\"colorOnSurface\">@color/gm3_ref_palette_neutral10</item>\n        <item name=\"colorSurfaceVariant\">@color/gm3_ref_palette_neutral_variant90</item>\n        <item name=\"colorOnSurfaceVariant\">@color/gm3_ref_palette_neutral_variant30</item>\n        <item name=\"colorSurfaceInverse\">@color/gm3_ref_palette_neutral20</item>\n        <item name=\"colorOnSurfaceInverse\">@color/gm3_ref_palette_neutral90</item>\n        <item name=\"colorSurfaceBright\">@color/gm3_ref_palette_neutral100</item>\n        <item name=\"colorSurfaceDim\">#ffd3dbe5</item>\n        <item name=\"colorSurfaceContainer\">#fff0f4f9</item>\n        <item name=\"colorSurfaceContainerLow\">#fff8fafd</item>\n        <item name=\"colorSurfaceContainerLowest\">@color/gm3_ref_palette_primary100</item>\n        <item name=\"colorSurfaceContainerHigh\">#ffe9eef6</item>\n        <item name=\"colorSurfaceContainerHighest\">#ffdde3ea</item>\n    </style>\n\n    <!-- TODO: Heavy duplication -->\n    <style name=\"Theme.App.Translucent\" parent=\"Theme.Base.Translucent\">\n        <item name=\"colorPrimary\">@color/gm3_ref_palette_primary40</item>\n        <item name=\"colorOnPrimary\">@color/gm3_ref_palette_primary100</item>\n        <item name=\"colorPrimaryContainer\">@color/gm3_ref_palette_primary90</item>\n        <item name=\"colorOnPrimaryContainer\">@color/gm3_ref_palette_primary10</item>\n        <item name=\"colorPrimaryInverse\">@color/gm3_ref_palette_primary80</item>\n        <item name=\"colorPrimaryFixed\">@color/gm3_ref_palette_primary90</item>\n        <item name=\"colorPrimaryFixedDim\">@color/gm3_ref_palette_primary80</item>\n        <item name=\"colorOnPrimaryFixed\">@color/gm3_ref_palette_primary10</item>\n        <item name=\"colorOnPrimaryFixedVariant\">@color/gm3_ref_palette_primary30</item>\n        <item name=\"colorSecondary\">@color/gm3_ref_palette_secondary40</item>\n        <item name=\"colorOnSecondary\">@color/gm3_ref_palette_secondary100</item>\n        <item name=\"colorSecondaryContainer\">@color/gm3_ref_palette_secondary90</item>\n        <item name=\"colorOnSecondaryContainer\">@color/gm3_ref_palette_secondary10</item>\n        <item name=\"colorSecondaryFixed\">@color/gm3_ref_palette_secondary90</item>\n        <item name=\"colorSecondaryFixedDim\">@color/gm3_ref_palette_secondary80</item>\n        <item name=\"colorOnSecondaryFixed\">@color/gm3_ref_palette_secondary10</item>\n        <item name=\"colorOnSecondaryFixedVariant\">@color/gm3_ref_palette_secondary30</item>\n        <item name=\"colorTertiary\">@color/gm3_ref_palette_tertiary40</item>\n        <item name=\"colorOnTertiary\">@color/gm3_ref_palette_tertiary100</item>\n        <item name=\"colorTertiaryContainer\">@color/gm3_ref_palette_tertiary90</item>\n        <item name=\"colorOnTertiaryContainer\">@color/gm3_ref_palette_tertiary10</item>\n        <item name=\"colorTertiaryFixed\">@color/gm3_ref_palette_tertiary90</item>\n        <item name=\"colorTertiaryFixedDim\">@color/gm3_ref_palette_tertiary80</item>\n        <item name=\"colorOnTertiaryFixed\">@color/gm3_ref_palette_tertiary10</item>\n        <item name=\"colorOnTertiaryFixedVariant\">@color/gm3_ref_palette_tertiary30</item>\n\n        <item name=\"colorError\">@color/gm3_ref_palette_error40</item>\n        <item name=\"colorOnError\">@color/gm3_ref_palette_error100</item>\n        <item name=\"colorErrorContainer\">@color/gm3_ref_palette_error90</item>\n        <item name=\"colorOnErrorContainer\">@color/gm3_ref_palette_error10</item>\n        <item name=\"colorOutline\">@color/gm3_ref_palette_neutral_variant50</item>\n        <item name=\"colorOutlineVariant\">@color/gm3_ref_palette_neutral_variant80</item>\n        <item name=\"android:colorBackground\">@color/gm3_ref_palette_neutral100</item>\n        <item name=\"colorOnBackground\">@color/gm3_ref_palette_neutral10</item>\n        <item name=\"colorSurface\">@color/gm3_ref_palette_neutral100</item>\n        <item name=\"colorOnSurface\">@color/gm3_ref_palette_neutral10</item>\n        <item name=\"colorSurfaceVariant\">@color/gm3_ref_palette_neutral_variant90</item>\n        <item name=\"colorOnSurfaceVariant\">@color/gm3_ref_palette_neutral_variant30</item>\n        <item name=\"colorSurfaceInverse\">@color/gm3_ref_palette_neutral20</item>\n        <item name=\"colorOnSurfaceInverse\">@color/gm3_ref_palette_neutral90</item>\n        <item name=\"colorSurfaceBright\">@color/gm3_ref_palette_neutral100</item>\n        <item name=\"colorSurfaceDim\">#ffd3dbe5</item>\n        <item name=\"colorSurfaceContainer\">#fff0f4f9</item>\n        <item name=\"colorSurfaceContainerLow\">#fff8fafd</item>\n        <item name=\"colorSurfaceContainerLowest\">@color/gm3_ref_palette_primary100</item>\n        <item name=\"colorSurfaceContainerHigh\">#ffe9eef6</item>\n        <item name=\"colorSurfaceContainerHighest\">#ffdde3ea</item>\n    </style>\n\n    <style name=\"Theme.LoginBlue\" parent=\"Theme.LoginBlue.Base\" />\n\n    <style name=\"Theme.LoginBlue.Base\" parent=\"Theme.AppCompat.Light.NoActionBar\">\n        <item name=\"colorPrimary\">@color/login_blue_theme_primary</item>\n        <item name=\"colorPrimaryDark\">@color/login_blue_theme_primary_dark</item>\n        <item name=\"colorAccent\">@color/login_blue_theme_accent</item>\n    </style>\n\n    <style name=\"ThemeTranslucentCommon\" parent=\"@style/Theme.Material3.DayNight.NoActionBar\">\n        <item name=\"android:windowBackground\">@android:color/transparent</item>\n        <item name=\"android:windowNoTitle\">true</item>\n        <item name=\"android:windowIsFloating\">true</item>\n        <item name=\"android:windowIsTranslucent\">true</item>\n        <item name=\"android:windowContentOverlay\">@null</item>\n        <item name=\"android:windowAnimationStyle\">@null</item>\n        <item name=\"android:backgroundDimEnabled\">true</item>\n        <item name=\"android:colorBackgroundCacheHint\">@null</item>\n        <item name=\"bottomSheetDialogTheme\">@style/AppBottomSheetDialogDayNightTheme</item>\n        <item name=\"colorControlNormal\">?attr/colorOnSurfaceVariant</item>\n        <item name=\"windowActionBar\">false</item>\n        <item name=\"windowNoTitle\">true</item>\n    </style>\n\n    <style name=\"AppBottomSheetDialogDayNightTheme\" parent=\"@style/ThemeOverlay.Material3.BottomSheetDialog\">\n        <item name=\"bottomSheetStyle\">@style/GISBottomSheetStyle</item>\n    </style>\n\n    <style name=\"GISBottomSheetStyle\" parent=\"@style/Widget.Material3.BottomSheet.Modal\">\n        <item name=\"backgroundTint\">@android:color/white</item>\n    </style>\n\n    <style name=\"GISDescriptionStyle\" parent=\"@style/TextAppearance.Material3.BodyMedium\">\n        <item name=\"android:textColor\">?attr/colorOnSurfaceVariant</item>\n        <item name=\"android:letterSpacing\" tools:targetApi=\"lollipop\">0.014</item>\n    </style>\n\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-ar/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"permission_service_all_label\">جميع خدمات جوجل</string>\n    <string name=\"permission_service_adsense_description\">يتيح للتطبيق الوصول إلى أدسنس من خلال أي حساب جوجل مرتبط.</string>\n    <string name=\"permission_service_adwords_label\">أدوردز</string>\n    <string name=\"permission_service_adwords_description\">يتيح للتطبيق الوصول إلى أدوردز من خلال أي حساب جوجل مرتبط.</string>\n    <string name=\"permission_service_ah_label\">محرك تطبيقات جوجل</string>\n    <string name=\"permission_service_ah_description\">يتيح للتطبيق الوصول إلى محرك تطبيقات جوجل من خلال أي حساب جوجل مرتبط.</string>\n    <string name=\"permission_service_blogger_label\">بلوجر</string>\n    <string name=\"permission_service_cl_label\">تقويم جوجل</string>\n    <string name=\"permission_service_cl_description\">يتيح للتطبيق الوصول إلى تقويم جوجل من خلال أي حساب جوجل مرتبط.</string>\n    <string name=\"permission_service_cp_label\">جهات الاتصال</string>\n    <string name=\"permission_service_cp_description\">يتيح للتطبيق الوصول إلى جهات الاتصال من خلال أي حساب جوجل مرتبط.</string>\n    <string name=\"permission_service_finance_label\">جوجل فاينانس</string>\n    <string name=\"permission_service_finance_description\">يتيح للتطبيق الوصول إلى جوجل فاينانس من خلال أي حساب جوجل مرتبط.</string>\n    <string name=\"permission_service_gbase_label\">قاعدة جوجل</string>\n    <string name=\"permission_service_gbase_description\">يتيح للتطبيق الوصول إلى قاعدة جوجل من خلال أي حساب جوجل مرتبط.</string>\n    <string name=\"permission_service_grandcentral_label\">صوت جوجل</string>\n    <string name=\"permission_service_groups2_label\">مجموعات جوجل</string>\n    <string name=\"permission_service_groups2_description\">يتيح للتطبيق الوصول إلى مجموعات جوجل من خلال أي حساب جوجل مرتبط.</string>\n    <string name=\"permission_service_health_label\">جوجل الطبي</string>\n    <string name=\"permission_service_health_description\">يتيح للتطبيق الوصول إلى جوجل الطبي من خلال أي حساب جوجل مرتبط.</string>\n    <string name=\"permission_service_ig_label\">آي جوجل</string>\n    <string name=\"permission_service_ig_description\">يتيح للتطبيق الوصول إلى آي جوجل من خلال أي حساب جوجل مرتبط.</string>\n    <string name=\"permission_service_jotspot_label\">جوت سبوت</string>\n    <string name=\"permission_service_knol_label\">جوجل نول</string>\n    <string name=\"permission_service_lh2_label\">ألبومات الويب بيكاسا</string>\n    <string name=\"permission_service_lh2_description\">يتيح للتطبيق الوصول إلى ألبومات الويب بيكاسا من خلال أي حساب جوجل مرتبط.</string>\n    <string name=\"permission_service_news_label\">أخبار جوجل</string>\n    <string name=\"permission_service_news_description\">يتيح للتطبيق الوصول إلى أخبار جوجل من خلال أي حساب جوجل مرتبط.</string>\n    <string name=\"permission_service_notebook_label\">مفكرة جوجل</string>\n    <string name=\"permission_service_orkut_label\">أوركوت</string>\n    <string name=\"permission_service_orkut_description\">يتيح للتطبيق الوصول إلى أوركوت من خلال أي حساب جوجل مرتبط.</string>\n    <string name=\"permission_service_sierra_label\">حسابات جوجل تشك أوت</string>\n    <string name=\"permission_service_sierrasandbox_label\">حسابات جوجل تشك أوت (ملعب)</string>\n    <string name=\"permission_service_sierraqa_label\">حسابات جوجل تشك أوت (ضمان الجودة)</string>\n    <string name=\"permission_service_sitemaps_label\">أدوات مشرفي محركات البحث جوجل</string>\n    <string name=\"permission_service_speech_label\">البحث الصوتي</string>\n    <string name=\"permission_service_speechpersonalization_label\">التعرف على الكلام الشخصي</string>\n    <string name=\"permission_service_speech_description\">يتيح للتطبيق الوصول إلى ميزة البحث الصوتي من خلال أي حساب جوجل مرتبط.</string>\n    <string name=\"permission_service_wifi_label\">جوجل Wi-Fi</string>\n    <string name=\"permission_service_wifi_description\">يتيح للتطبيق الوصول إلى جوجل Wi-Fi من خلال أي حساب جوجل مرتبط.</string>\n    <string name=\"permission_service_YouTubeUser_label\">اسم المستخدم على يوتيوب</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_activity\">عرض سِجِل أنشطة تطبيقات جوجل</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense.readonly\">عرض بياناتك في أدسنس</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense\">عرض وإدارة بياناتك في أدسنس</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics.readonly\">عرض بياناتك في تحليلات جوجل</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics\">عرض وإدارة بياناتك في تحليلات جوجل</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_androidpublisher\">الوصول إلى مطور جوجل بلاي على أندرويد</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appengine.admin\">نطاق إدارة محرك التطبيقات.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.migration\">إذن قراءة وكتابة API ترحيل المجموعات.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.settings\">عرض وإدارة إعداداتك في مجموعة تطبيقات جوجل</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.licensing\">إذن القراءة والكتابة لـ API إدارة التراخيص.</string>\n    <string name=\"permission_service_all_description\">يتيح للتطبيق الوصول إلى جميع خدمات جوجل من خلال أي حساب جوجل مرتبط.</string>\n    <string name=\"permission_service_android_label\">خدمات أندرويد</string>\n    <string name=\"permission_service_android_description\">يتيح للتطبيق الوصول إلى خدمات أندرويد من خلال أي حساب جوجل مرتبط.</string>\n    <string name=\"permission_service_adsense_label\">أدسنس</string>\n    <string name=\"permission_service_blogger_description\">يتيح للتطبيق الوصول إلى بلوجر من خلال أي حساب جوجل مرتبط.</string>\n    <string name=\"permission_service_dodgeball_label\">دودج بول</string>\n    <string name=\"permission_service_dodgeball_description\">يتيح للتطبيق الوصول إلى خدمة دودج بول من خلال أي حساب جوجل مرتبط.</string>\n    <string name=\"permission_service_grandcentral_description\">يتيح للتطبيق الوصول إلى صوت جوجل من خلال أي حساب جوجل مرتبط.</string>\n    <string name=\"permission_service_jotspot_description\">يتيح للتطبيق الوصول إلى جوت سبوت من خلال أي حساب جوجل مرتبط.</string>\n    <string name=\"permission_service_knol_description\">يتيح للتطبيق الوصول إلى جوجل نول من خلال أي حساب جوجل مرتبط.</string>\n    <string name=\"permission_service_local_label\">خرائط جوجل</string>\n    <string name=\"permission_service_local_description\">يتيح للتطبيق الوصول إلى خرائط جوجل من خلال أي حساب جوجل مرتبط.</string>\n    <string name=\"permission_service_mail_description\">يتيح للتطبيق الوصول إلى بريد جوجل من خلال أي حساب جوجل مرتبط.</string>\n    <string name=\"permission_service_mail_label\">بريد جوجل</string>\n    <string name=\"permission_service_notebook_description\">يتيح للتطبيق الوصول إلى مفكرة جوجل من خلال أي حساب جوجل مرتبط.</string>\n    <string name=\"permission_service_sierra_description\">يتيح للتطبيق الوصول إلى حسابات جوجل تشك أوت من خلال أي حساب جوجل مرتبط.</string>\n    <string name=\"permission_service_print_label\">كتب جوجل</string>\n    <string name=\"permission_service_print_description\">يتيح للتطبيق الوصول إلى كتب جوجل من خلال أي حساب جوجل مرتبط.</string>\n    <string name=\"permission_service_sierrasandbox_description\">يتيح للتطبيق الوصول إلى حسابات جوجل تشك أوت (ملعب) من خلال أي حساب جوجل مرتبط.</string>\n    <string name=\"permission_service_sierraqa_description\">يتيح للتطبيق الوصول إلى حسابات جوجل تشك أوت (ضمان الجودة) من خلال أي حساب جوجل مرتبط.</string>\n    <string name=\"permission_service_sitemaps_description\">يتيح للتطبيق الوصول إلى أدوات مشرفي محركات البحث جوجل من خلال أي حساب جوجل مرتبط.</string>\n    <string name=\"permission_service_talk_label\">جوجل توك</string>\n    <string name=\"permission_service_talk_description\">يتيح للتطبيق الوصول إلى جوجل توك من خلال أي حساب جوجل مرتبط.</string>\n    <string name=\"permission_service_speechpersonalization_description\">يتيح للتطبيق الوصول إلى ميزة التعرف على الكلام الشخصي من خلال أي حساب جوجل مرتبط.</string>\n    <string name=\"permission_service_wise_label\">جداول بيانات جوجل</string>\n    <string name=\"permission_service_youtube_label\">يوتيوب</string>\n    <string name=\"permission_service_wise_description\">يتيح للتطبيق الوصول إلى جداول بيانات جوجل من خلال أي حساب جوجل مرتبط.</string>\n    <string name=\"permission_service_writely_label\">مستندات جوجل</string>\n    <string name=\"permission_service_writely_description\">يتيح للتطبيق الوصول إلى مستندات جوجل من خلال أي حساب جوجل مرتبط.</string>\n    <string name=\"permission_service_youtube_description\">يتيح للتطبيق الوصول إلى يوتيوب من خلال أي حساب جوجل مرتبط.</string>\n    <string name=\"permission_service_YouTubeUser_description\">يتيح للتطبيق الوصول إلى اسم المستخدم على يوتيوب من خلال أي حساب جوجل مرتبط.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.buyer\">إدارة إعدادات حساب المشتري في منصة التبادلات الإعلانية</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsensehost\">عرض وإدارة بياناتك في أدسنس الخاصة بالاستضافة والحسابات المرتبطة</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller.readonly\">عرض بياناتك في منصة التبادلات الإعلانية</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller\">عرض وإدارة بياناتك في منصة التبادلات الإعلانية</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order\">بالنسبة لمسؤولي ومستخدمي البائعين المعتمدين، إذن القراءة والكتابة عند الاختبار في وضع الملعب للـ API، أو إذن القراءة والكتابة عند استدعاء عملية API مباشرة.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order.readonly\">بالإضافة إلى نطاق بروتوكول أوث للقراءة والكتابة بشكل عام، استخدم نطاق بروتوكول أوث للقراءة فقط عند استرجاع بيانات العميل.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps_reporting_audit.readonly\">الوصول إلى API لتدقيق الإدارة بصلاحية القراءة فقط</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appstate\">النطاق لاستخدام خدمة حالة التطبيق.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery.readonly\">عرض بياناتك في جوجل بيج كويري</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery\">عرض وإدارة بياناتك في جوجل بيج كويري</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger\">إدارة حساب بلوجر</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger.readonly\">عرض حساب بلوجر</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_books\">إدارة كتبك</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar\">إدارة تقاويمك</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar.readonly\">عرض تقاويمك</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_cloudprint\">عرض وإدارة بيانات الطباعة سحابية من جوجل</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute.readonly\">عرض مواردك في محرك حساب جوجل</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute\">عرض وإدارة مواردك في محرك حساب جوجل</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate\">عرض وإدارة وظائف جوجل كووردينيت</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate.readonly\">عرض وظائف جوجل كووردينيت</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.full_control\">إدارة بياناتك وأذوناتك في خدمة التخزين السحابي من جوجل</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_only\">عرض بياناتك في خدمة التخزين السحابي من جوجل</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_write\">إدارة بياناتك في خدمة التخزين السحابي من جوجل</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_dfareporting\">عرض وإدارة تقارير دبل كلك للمعلنين</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.appdata\">يتيح الوصول إلى مجلد بيانات التطبيقات</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.apps.readonly\">عرض تطبيقات جوجل درايف الخاصة بك</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.file\">عرض وإدارة ملفات جوجل درايف التي قمت بفتحها أو إنشائها باستخدام هذا التطبيق</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.install\">نطاق خاص يستخدم للسماح للمستخدمين بالموافقة على تثبيت التطبيقات</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.metadata.readonly\">عرض البيانات الوصفية للملفات والمستندات في جوجل درايف</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.readonly\">عرض الملفات والمستندات في جوجل درايف</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.scripts\">تعديل سلوك النصوص البرمجية النصية لتطبيقات جوجل</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive\">عرض وإدارة الملفات والمستندات في جوجل درايف</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase.readonly\">عرض حساب فريبيس</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase\">سَجِّل الدخول إلى فريبيس بحسابك</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables\">إدارة جداول الدمج من جوجل</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables.readonly\">عرض جداول الدمج من جوجل</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_games\">نطاق للوصول إلى بيانات ألعاب جوجل بلاي.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan\">إدارة بيانات GAN الخاص بك</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan.readonly\">عرض بيانات GAN الخاص بك</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_glass.timeline\">نطاق الجدول الزمني الزجاجي</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.compose\">إنشاء، قراءة، تحديث، وحذف المسودات. إرسال الرسائل والمسودات.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.readonly\">قراءة جميع الموارد وبياناتها الوصفية - لا توجد عمليات كتابة.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.best\">إدارة أفضل موقع متاح لك وسِجِل مواقعك</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.city\">إدارة موقعك على مستوى المدينة وسِجِل مواقعك</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.best\">إدارة أفضل موقع متاح لك</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.city\">إدارة موقعك على مستوى المدينة</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine\">عرض وإدارة بيانات محرك خرائط جوجل</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine.readonly\">عرض بيانات محرك خرائط جوجل</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mobilemaps.firstparty\">عرض خرائط جوحل وإدارتها لتجربة الجوال</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut.readonly\">عرض بياناتك في أوركوت</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut\">إدارة نشاطك في أوركوت</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.me\">اعرف من أنت على جوجل</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gcm_for_chrome\">المراسلة السحابية للكروم</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.modify\">جميع عمليات القراءة/الكتابة باستثناء عمليات الحذف الفوري والدائم للمواضيع والرسائل، متجاوزًا سلة المهملات.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.login\">تعرف على اسمك ومعلوماتك الأساسية وقائمة الأشخاص الذين تتواصل معهم على جوجل+</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_prediction\">إدارة بياناتك في واجهة برمجة تطبيقات التنبؤ من جوجل</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_shoppingapi\">عرض بيانات منتجاتك</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification\">إدارة قائمة المواقع والنطاقات التي تتحكم فيها</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_structuredcontent\">الوصول للقراءة/الكتابة إلى واجهة برمجة تطبيقات محتوى التسوق.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue.consumer\">استهلاك المهام من قوائم مهامك</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue\">إدارة مهامك</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks\">إدارة مهامك</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks.readonly\">عرض مهامك</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tracks\">واجهة برمجة تطبيقات التتبع للخرائط جوجل، يسمح هذا النطاق بالوصول للقراءة والكتابة إلى بيانات مشروعك.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_urlshortener\">إدارة عناوين goo.gl الخاصة بك</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.profile\">عرض المعلومات الأساسية حول حسابك</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube\">إدارة حسابك في يوتيوب</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.readonly\">عرض حسابك في يوتيوب</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.upload\">إدارة فيديوهاتك في يوتيوب</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics_monetary.readonly\">عرض التقارير النقدية لمحتواك على يوتيوب</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics.readonly\">عرض تحليلات يوتيوب لقناتك</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.email\">عرض عنوان بريدك الإلكتروني</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtubepartner\">عرض وإدارة أصولك والمحتوى المرتبط على يوتيوب</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification.verify_only\">إدارة عمليات التحقق من موقعك الجديد مع جوجل</string>\n    <string name=\"perm_activity_recognition_label\">التعرف على نشاطك</string>\n    <string name=\"perm_activity_recognition_description\">يتيح للتطبيق بتلقي تحديثات دورية لمستوى نشاطك من جوجل، على سبيل المثال، إذا كنت تمشي أو تقود السيارة أو تركب الدراجة أو كنت واقفًا.</string>\n</resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-ar/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <plurals name=\"pref_unifiednlp_summary\">\n        <item quantity=\"zero\">لا توجد خلفية مهيئة</item>\n        <item quantity=\"one\">خلفية واحدة مهيئة</item>\n        <item quantity=\"two\">خلفيتان مهيئتان</item>\n        <item quantity=\"few\"><xliff:g example=\"3\">%1$d</xliff:g> خلفيات مهيئات</item>\n        <item quantity=\"many\"><xliff:g example=\"11\">%1$d</xliff:g> خلفية مهيئة</item>\n        <item quantity=\"other\"><xliff:g example=\"100\">%1$d</xliff:g> خلفية مهيئة</item>\n    </plurals>\n    <plurals name=\"cond_perm_action\">\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=\"gcm_registered_apps_counter\">\n        <item quantity=\"zero\">لا يوجد تطبيق مسجّل</item>\n        <item quantity=\"one\">تطبيق واحد مسجّل</item>\n        <item quantity=\"two\">تطبيقان مسجّلان</item>\n        <item quantity=\"few\"><xliff:g example=\"3\">%1$d</xliff:g> تطبيقات مسجّلة</item>\n        <item quantity=\"many\"><xliff:g example=\"11\">%1$d</xliff:g> تطبيقًا مسجّلًا</item>\n        <item quantity=\"other\"><xliff:g example=\"3\">%1$d</xliff:g> تطبيق مسجّل</item>\n    </plurals>\n    <plurals name=\"cond_perm_summary\">\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</resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-ar/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=\"gms_app_name\">خدمات مايكرو-جي</string>\n    <string name=\"gms_settings_name\">إعدادات مايكرو-جي</string>\n    <string name=\"ask_permission_tos\">مع المتابعة، أنت تسمح لهذا التطبيق وجوجل باستخدام معلوماتك وفقًا لشروط الخدمة وسياسات الخصوصية الخاصة بهما.</string>\n    <string name=\"ask_scope_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> يريد أن:</string>\n    <string name=\"ask_service_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> يريد أن يستخدم:</string>\n    <string name=\"account_manager_title\">مدير حساب جوجل</string>\n    <string name=\"sorry\">آسف…</string>\n    <string name=\"auth_sign_in\">تسجيل الدخول</string>\n    <string name=\"auth_connecting\">جهازك يقوم بإقامة اتصال بخوادم Google لتسجيل دخولك.\n\\n\n\\nقد يستغرق ذلك بضع ثوانٍ.</string>\n    <string name=\"no_network_error_desc\">لست متصلَا بالشبكة.\n\\n\n\\nقد تكون هذه مشكلة مؤقتة أو قد لا يكون جهاز الأندرويد الخاص بك مهيئًا لخدمات البيانات. حاول مرة أخرى عندما تكون متصلًا بشبكة خلوية، أو اتصل بشبكة Wi-Fi.</string>\n    <string name=\"auth_general_error_desc\">كانت هناك مشكلة في التواصل مع خوادم جوجل.\n\\n\n\\nحاول مرة أخرى لاحقًا.</string>\n    <string name=\"auth_finalize\">جهازك يتصل بجوجل لحفظ المعلومات في حسابك.\\n\\nقد يستغرق ذلك بضع دقائق.</string>\n    <string name=\"allow\">سماح</string>\n    <string name=\"deny\">رفض</string>\n    <string name=\"auth_notification_title\">المصادقة مطلوبة</string>\n    <string name=\"auth_package_override_request_title\">أتسمح &lt;b&gt;لـ&lt;xliff:g example=\\\"F-Droid\\\"&gt;%1$s&lt;/xliff:g&gt;&lt;/b&gt; بالحصول على وصول مميز إلى &lt;xliffexample=\\\"account@example.com\\\"&gt;%2$s&lt;/xliff&gt;؟</string>\n    <string name=\"signin_picker_title\">اختر حسابًا</string>\n    <string name=\"signin_picker_subtitle\">للمتابعة إلى <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"signin_picker_add_account_label\">أضف حسابًا آخر</string>\n    <string name=\"signin_confirm_title\">السماح بتسجيل دخولك إلى <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"signin_confirm_button_text\">السماح والمشاركة</string>\n    <string name=\"signin_subtext_sharing\">للمتابعة، سيقوم مايكرو-جي بمشاركة الاسم، عنوان البريد الإلكتروني وصورة الملف الشخصي لحساب جوجل الخاص بك مع <xliff:g example=\"F-Droid\">%1$s</xliff:g>.</string>\n    <string name=\"signin_subtext_policy\">قبل استخدام هذا التطبيق، راجع %1$s و %2$s.</string>\n    <string name=\"signin_subtext_policy_privacy\">سياسة الخصوصية</string>\n    <string name=\"signin_subtext_policy_terms\">شروط الخدمة</string>\n    <string name=\"perm_status_broadcast_label\">استمع إلى عمليات بث الحالة الداخلية</string>\n    <string name=\"perm_gsf_read_gservices_label\">اقرأ ضبط خدمات جوجل</string>\n    <string name=\"perm_gtalk_svc_label\">تبادل الرسائل وتلقي إشعارات المزامنة من خوادم جوجل</string>\n    <string name=\"perm_extended_access_label\">وصول موسع إلى خدمات جوجل</string>\n    <string name=\"perm_provision_label\">توفير خدمات مايكرو-جي</string>\n    <string name=\"perm_provision_description\">يتيح للتطبيق ضبط خدمات مايكرو-جي دون تفاعل من المستخدم</string>\n    <string name=\"perm_car_speed_label\">سرعة السيارة</string>\n    <string name=\"perm_car_speed_description\">الوصول إلى سرعة سيارتك</string>\n    <string name=\"perm_car_info_label\">معلومات السيارة</string>\n    <string name=\"perm_car_info_description\">الوصول إلى معلومات سيارتك</string>\n    <string name=\"perm_car_fuel_label\">الوقود المتبقي</string>\n    <string name=\"perm_car_mileage_description\">الوصول إلى معلومة المسافة المقطوعة لسيارتك</string>\n    <string name=\"perm_car_vendor_extension_label\">قناة مورد السيارة</string>\n    <string name=\"service_name_checkin\">تسجيل الجهاز عند جوجل</string>\n    <string name=\"service_name_mcs\">الرسائل السحابية</string>\n    <string name=\"service_name_snet\">جوجل سيفتي-نت</string>\n    <string name=\"games_title\">ألعاب جوجل بلاي</string>\n    <string name=\"service_name_vending\">خدمات متجر جوجل بلاي</string>\n    <string name=\"pick_place_title\">اختر مكانًا</string>\n    <string name=\"pick_place_desc\">أداة اختيار المكان غير متاحة بعد.</string>\n    <string name=\"place_picker_select_title\">حدد هذا الموقع</string>\n    <string name=\"lacking_permission_toast\">خدمات مايكرو-جي: بحاجة إذن ل<xliff:g example=\"have full network acccess\">%1$s</xliff:g></string>\n    <string name=\"place_picker_location_lat_lng\">‭(%1$.7f, %2$.7f)</string>\n    <string name=\"network_type_mobile\">الشبكة الخلوية</string>\n    <string name=\"network_type_wifi\">Wi-Fi</string>\n    <string name=\"network_type_roaming\">تجوال</string>\n    <string name=\"self_check_cat_gms_packages\">الحزم المثبتة</string>\n    <string name=\"self_check_cat_system\">النظام</string>\n    <string name=\"self_check_name_fake_sig_perm\">النظام يدعم تزوير التوقيع الرقمي:</string>\n    <string name=\"self_check_resolution_fake_sig_perm\">نظامك لا يدعم تزوير التوقيع بشكل طبعي. يمكنك استخدام Xposed أو برامج أخرى لتزوير التوقيع الرقمي. يرجى مراجعة المستندات لمعرفة الأنظمة التي تدعم تزوير التوقيع الرقمي وكيفية استخدام مايكرو-جي على الأنظمة التي لا تدعمه.</string>\n    <string name=\"self_check_name_system_spoofs\">\\\"النظام يُزوِّر التوقيع الرقمي:</string>\n    <string name=\"self_check_resolution_system_spoofs\">يرجى مراجعة المستندات لمعرفة الخطوات التي قد تكون مطلوبة.</string>\n    <string name=\"self_check_pkg_gms\">خدمات مايكرو-جي</string>\n    <string name=\"self_check_pkg_vending\">مرافق مايكرو-جي / متجر جوجل بلاي</string>\n    <string name=\"self_check_pkg_gsf\">إطار الخدمات مايكرو-جي</string>\n    <string name=\"self_check_name_app_installed\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> مثبت: </string>\n    <string name=\"self_check_resolution_app_installed\">ثبت تطبيق <xliff:g example=\"F-Droid\">%1$s</xliff:g> أو تطبيق متوافق. يرجى مراجعة المستندات لمعرفة التطبيقات المتوافقة.</string>\n    <string name=\"self_check_name_correct_sig\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> يحمل التوقيع الرقمي الصحيح: </string>\n    <string name=\"gms_settings_summary\">إعداد خدمات مايكرو-جي.</string>\n    <string name=\"just_a_sec\">اصبر قليلًا…</string>\n    <string name=\"google_account_label\">جوجل</string>\n    <string name=\"auth_before_connect\">يحاول تطبيق على جهازك تسجيل الدخول إلى حساب جوجل.\\n\\nإن كان هذا مقصودًا، استخدم زر <b>تسجيل الدخول</b> للاتصال بصفحة تسجيل الدخول الخاصة بجوجل. إن لم يكن الأمر كذلك، اضغط على <b>إلغاء</b> للعودة إلى التطبيق الذي تسبب في ظهور هذه الرسالة.</string>\n    <string name=\"auth_notification_content\">يحتاج <xliff:g example=\"F-Droid\">%1$s</xliff:g> إذنك للوصول إلى حسابك على جوجل.</string>\n    <string name=\"auth_package_override_request_message\">يريد <b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> الوصول إلى حسابك وكأنه <b><xliff:g example=\"F-Droid\">%2$s</xliff:g> من <xliff:g example=\"F-Droid Inc.\">%3$s</xliff:g></b>. هذه قد يمنحه وصولًا مميزًا إلى حسابك.</string>\n    <string name=\"perm_c2dm_receive_label\">استمع إلى رسائل C2DM</string>\n    <string name=\"perm_c2dm_send_label\">ارسل رسائل C2DM إلى تطبيقات أخرى</string>\n    <string name=\"perm_car_fuel_description\">الوصول إلى معلومة الوقود المتبقي</string>\n    <string name=\"perm_car_mileage_label\">المسافة المقطوعة للسيارة</string>\n    <string name=\"perm_car_vendor_extension_description\">الوصول إلى قناة مورد سيارتك لتبادل المعلومات الخاصة بالسيارة</string>\n    <string name=\"games_info_title\">يريد <xliff:g example=\"F-Droid\">%1$s</xliff:g> أن يستخدم ألعاب جوجل بلاي</string>\n    <string name=\"games_info_content\">لاستخدام ألعاب جوجل بلاي، من الضروري تثبيت تطبيق ألعاب جوجل بلاي. قد يواصل التطبيق العمل من دون ألعاب جوجل بلاي، لكن من الممكن أن يتصرف بشكل غير متوقع.</string>\n    <string name=\"network_type_other\">شبكات أخرى</string>\n    <string name=\"place_picker_nearby_places\">أماكن قريبة</string>\n    <string name=\"self_check_cat_fake_sig\">دعم تزوير التوقيع الرقمي</string>\n    <string name=\"self_check_name_perm_granted\">النظام يمنح إذن تزوير التوقيع الرقمي:</string>\n    <string name=\"self_check_resolution_perm_granted\">هذه علامة قوية على أن النظام يدعم تزوير التوقيع الرقمي، ولكن يتطلب إجراءات إضافية لتفعيله. يرجى مراجعة المستندات لمعرفة الخطوات التي قد تكون مطلوبة.</string>\n    <string name=\"self_check_resolution_correct_sig\">إما أن تطبيق <xliff:g example=\"F-Droid\">%1$s</xliff:g> المثبت غير متوافق أو أن توقيع التزوير الرقمي غير مفعل له. يرجى مراجعة المستندات لمعرفة التطبيقات واﻷنظمة المتوافقة.</string>\n    <string name=\"self_check_name_battery_optimizations\">تم تجاهل توفير شحن البطارية:</string>\n    <string name=\"self_check_resolution_battery_optimizations\">اضغط هنا ﻹيقاف توفير شحن البطارية. عدم القيام بذلك قد يؤدي إلى تصرفات غير متوقعة للتطبيقات.</string>\n    <string name=\"prefcat_about\">نبذة عن</string>\n    <string name=\"prefcat_components\">مكونات</string>\n    <string name=\"prefcat_configuration\">ضبط</string>\n    <string name=\"prefcat_google_services\">خدمات جوجل</string>\n    <string name=\"prefcat_location_service\">خدمة الموقع</string>\n    <string name=\"prefcat_services\">خدمات</string>\n    <string name=\"prefcat_test\">اختبار</string>\n    <string name=\"cond_gcm_bat_title\">توفير شحن البطارية مفعل</string>\n    <string name=\"cond_gcm_bat_action\">تجاهل تحسينات البطارية</string>\n    <string name=\"cond_perm_title\">إذنٌ مفقود</string>\n    <string name=\"prefs_account\">خيارات الحساب</string>\n    <string name=\"prefs_account_privacy\">المعلومات الشخصية والخصوصية</string>\n    <string name=\"prefs_account_security\">تسجيل الدخول والأمان</string>\n    <string name=\"pref_auth_trust_google_title\">ثق بجوجل لإدارة أذونات التطبيقات</string>\n    <string name=\"cond_gcm_bat_summary\">لقد فعّلت الرسائل السحابية لكن توفير شحن البطارية مفعّلٌ لخدمات مايكرو-جي. لكي تصل إشعارات الدفع، يجب عليك إيقاف توفير شحن البطارية لمايكرو-جي.</string>\n    <string name=\"pref_auth_trust_google_summary\">عند تعطيل هذا الخيار، يُطلب من المستخدم الموافقة قبل إرسال طلب إذن التطبيق إلى جوجل. قد تفشل بعض التطبيقات في استخدام حساب جوجل إن عُطِّل هذا الخيار.</string>\n    <string name=\"pref_auth_visible_title\">السماح للتطبيقات بالعثور على الحسابات</string>\n    <string name=\"pref_auth_include_android_id_title\">المصادقة بتسجيل الجهاز</string>\n    <string name=\"pref_auth_include_android_id_summary\">عند تعطيل هذا الخيار، لن ترتبط طلبات المصادقة بتسجيل الجهاز، مما قد يسمح للأجهزة غير المصرح بها بتسجيل الدخول، لكن قد يؤدي ذلك إلى عواقب غير متوقعة.</string>\n    <string name=\"pref_auth_strip_device_name_title\">إزالة اسم الجهاز من المصادقة</string>\n    <string name=\"pref_auth_strip_device_name_summary\">عند تفعيل هذا الخيار، لن تتضمن طلبات المصادقة اسم الجهاز، مما قد يسمح للأجهزة غير المصرح بها بتسجيل الدخول، لكن قد يؤدي ذلك إلى عواقب غير متوقعة.</string>\n    <string name=\"pref_auth_visible_summary\">عند تفعيل هذا الخيار، ستتمكن جميع التطبيقات من رؤية عنوان البريد الإلكتروني لحسابات جوجل الخاصة بك دون الحصول على إذن مسبق.</string>\n    <string name=\"pref_device_registration_android_id\">مُعَرِّف أندرويد</string>\n    <string name=\"pref_checkin_enable_summary\">يُسَجِلُ جهازك عند خدمات جوجل ويُنشئ معرّفًا فريدًا للجهاز. سيقوم مايكرو-جي بإزالة الأجزاء المُمَيِزة لك باستثناء اسم حساب جوجل الخاص بك في بيانات التسجيل.</string>\n    <string name=\"checkin_not_registered\">ليس مسجَّلًا</string>\n    <string name=\"checkin_last_registration\">آخر تسجيل: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"checkin_enable_switch\">تسجيل الجهاز</string>\n    <string name=\"pref_info_status\">الحالة</string>\n    <string name=\"pref_more_settings\">المزيد</string>\n    <string name=\"pref_accounts_title\">حسابات جوجل</string>\n    <string name=\"pref_accounts_summary\">إضافة وإدارة حسابات جوجل</string>\n    <string name=\"prefcat_accounts_settings_title\">اﻹعدادات</string>\n    <string name=\"prefcat_accounts_current_accounts_title\">حسابات</string>\n    <string name=\"pref_add_account_title\">حساب</string>\n    <string name=\"pref_add_account_summary\">إضافة حساب جوجل</string>\n    <string name=\"pref_gcm_enable_mcs_summary\">الرسائل السحابية هي مزوّدٌ لإشعارات الدفع الذي تستخدمه العديد من التطبيقات الخارجية. لاستخدامه، يجب عليك تفعيل تسجيل الجهاز.</string>\n    <string name=\"pref_gcm_heartbeat_title\">فترة التحقق الدوري للرسائل السحابية</string>\n    <string name=\"pref_gcm_confirm_new_apps_summary\">طلب التأكيد قبل تسجيل تطبيق جديد لاستقبال إشعارات الدفع</string>\n    <string name=\"pref_gcm_confirm_new_apps_title\">تأكيد التطبيقات الجديدة</string>\n    <string name=\"pref_gcm_ping_interval\">فترة التحقق: <xliff:g example=\"10 minutes\">%1$s</xliff:g></string>\n    <string name=\"pref_about_title\">نبذه عن خدمات مايكرو-جي</string>\n    <string name=\"pref_about_summary\">معلومات اﻹصدار والمكتبات الرمجية المستخدمة</string>\n    <string name=\"gcm_app_error_unregistering\">حدث خطأ أثناء إلغاء التسجيل</string>\n    <string name=\"gcm_app_not_installed_anymore\">لم يعد مثبَّتًا</string>\n    <string name=\"gcm_unregister_app\">إلغاء التسجيل</string>\n    <string name=\"gcm_no_message_yet\">لم تصل رسائل بعد</string>\n    <string name=\"gcm_last_message_at\">آخر رسالة: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_registered\">مسجَّل</string>\n    <string name=\"gcm_not_registered\">غير مسجَّل</string>\n    <string name=\"gcm_registered_since\">مسجَّل منذ: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_unregister_confirm_title\">إلغاء تسجيل <xliff:g example=\"F-Droid\">%1$s</xliff:g>؟</string>\n    <string name=\"pref_gcm_heartbeat_summary\">الفترة بالثواني التي يقوم فيها النظام بإرسال إشارات دورية إلى خوادم جوجل. زيادة هذا الرقم سيقلل من استهلاك البطارية، لكن قد يسبب تأخرًا في الرسائل الدفعية.\n\\nهذه الميزة أصبحت قديمة وستستبدل في الإصدارات القادمة.</string>\n    <string name=\"pref_gcm_apps_title\">التطبيقات التي تستخدم الرسائل السحابية</string>\n    <string name=\"pref_gcm_apps_summary\">قائمة التطبيقات المسجَّلة حاليًا لاستخدام الرسائل السحابية.</string>\n    <string name=\"gcm_unregister_confirm_message\">بعض التطبيقات لا تعيد التسجيل تلقائيًا و/أو لا توفر خيارًا للقيام بذلك يدويًا. قد لا تعمل هذه التطبيقات بشكل صحيح بعد إلغاء التسجيل.\n\\nهل تريد المتابعة؟</string>\n    <string name=\"gcm_unregister_after_deny_message\">لقد رفضت تسجيل تطبيق لتلقي إشعارات الدفع وهو مسجَّلٌ بالفعل.\n\\nهل تريد إلغاء تسجيله الآن حتى لا يتلقى رسائل الدفع في المستقبل؟</string>\n    <string name=\"gcm_messages_counter\">الرسائل: <xliff:g id=\"count\" example=\"123\">%1$d</xliff:g> (<xliff:g id=\"size\" example=\"12345\">%2$d</xliff:g> بايت)</string>\n    <string name=\"gcm_network_state_disconnected\">منقطع اﻹتصال</string>\n    <string name=\"gcm_network_state_connected\">متصل منذ <xliff:g example=\"2 hours ago\">%1$s</xliff:g></string>\n    <string name=\"gcm_enable_switch\">تلقي إشعارات الدفع</string>\n    <string name=\"gcm_allow_app_popup\">السماح ل<xliff:g example=\"F-Droid\">%1$s</xliff:g> بالتسجيل لتلقي إشعارات الدفع؟</string>\n    <string name=\"pref_push_app_allow_register_summary\">السماح للتطبيق بالتسجيل لتلقي إشعارات الدفع.</string>\n    <string name=\"pref_push_app_wake_for_delivery_title\">تشغيل التطبيق عند تلقي رسالة دفع</string>\n    <string name=\"pref_push_app_allow_register_title\">السماح بالتسجيل</string>\n    <string name=\"pref_push_app_wake_for_delivery_summary\">تشغيل التطبيق في الخلفية لتلقي رسائل الدفع الواردة.</string>\n    <string name=\"prefcat_push_apps_title\">التطبيقات المستخدمة لإشعارات الدفع</string>\n    <string name=\"prefcat_push_apps_registered_title\">التطبيقات المسجّلة</string>\n    <string name=\"prefcat_push_apps_unregistered_title\">التطبيقات غير المسجّلة</string>\n    <string name=\"prefcat_push_networks_title\">الشبكات المستخدمة لإشعارات الدفع</string>\n    <string name=\"limited_services_app_name\">خدمات مايكرو-جي المحدودة</string>\n    <string name=\"auth_action_notification_channel_name\">تنبيهات حساب جوجل</string>\n    <string name=\"pref_vending_split_install_switch\">تثبيت المكونات عند الطلب</string>\n    <string name=\"pref_vending_licensing_split_install_summary\">السماح للتطبيقات بتنزيل مكونات إضافية وتثبيتها</string>\n    <string name=\"service_name_work_profile\">ملف العمل</string>\n    <string name=\"auth_action_notification_title\">إجراء الحساب مطلوب</string>\n    <string name=\"auth_action_notification_content\">يحتاج حسابك في جوجل إعدادًا إضافيًا.</string>\n    <string name=\"auth_action_activity_header\">إنهاء إعداد حساب جوجل</string>\n    <string name=\"auth_action_step_enable_checkin\">تفعيل تسجيل الجهاز</string>\n    <string name=\"auth_action_step_enable_gcm\">تفعيل المراسلة السحابية</string>\n    <string name=\"auth_action_step_allow_microg_gcm_description\">وفقًا لتفضيلاتك، يحتاج مايكرو-جي إلى إذن منك قبل أن يتمكن من تسجيل نفسه في المراسلة السحابية.</string>\n    <string name=\"auth_action_activity_finish\">إنهاء</string>\n    <string name=\"auth_action_step_enable_gcm_description\">يمكنك تعطيل المراسلة السحابية بعد اكمال إعداد الحساب.</string>\n    <string name=\"auth_action_notification_channel_description\">يتم تنبيهك عندما تطلب أحد حسابات جوجل إعدادًا إضافيًا قبل استخدامه أو عندما يكون حساب غير متوافق مع مايكرو-جي.</string>\n    <string name=\"auth_action_activity_explanation\">أكمل الخطوات التالية لتتمكن من استخدام حساب جوجل (%s) على هذا الجهاز.</string>\n    <string name=\"auth_action_step_allow_microg_gcm\">السماح بالمراسلة السحابية لمايكرو-جي</string>\n    <string name=\"auth_action_step_completed_content_description\">تم الانتهاء من الخطوة</string>\n    <string name=\"auth_action_step_enable_lockscreen\">تهيئة قفل الشاشة الآمن</string>\n    <string name=\"auth_action_step_enable_checkin_description\">يحتاج جهازك إلى التسجيل في جوجل مرة واحدة على الأقل.\\n\\nيمكنك تعطيل تسجيل جهاز جوجل بعد اكمال إعداد الحساب.</string>\n    <string name=\"auth_action_step_perform_content_description\">انقر لتنفيذ الخطوة</string>\n    <string name=\"auth_action_step_enable_lockscreen_description\">تتم إدارة حسابك على جوجل بواسطة مكان عملك أو مؤسستك التعليمية. قرر مسؤولك أن الأجهزة تحتاج إلى قفل شاشة آمن قبل أن تتمكن من الوصول إلى بيانات الحساب.\\n\\nيُرجى إعداد كلمة مرور أو رقم تعريف شخصي أو قفل شاشة بنمط معين.</string>\n    <string name=\"safetynet_intro\">نظام جوجل سيفتي-نت هو نظام اعتماد للجهاز، يضمن أن الجهاز مؤَمْن بشكل صحيح ومتوافق مع نظام اندرويد CTS. تستخدم بعض التطبيقات سيفتي-نت لأسباب أمنية أو كشرط أساسي للحماية من العبث.\\n\\nيحتوي مايكرو-جي GmsCore على تطبيق مجاني لسيفتي-نت، لكن الخادم الرسمي يتطلب توقيع طلبات سيفتي-نت باستخدام نظام درويد-جارد الإحتكاري.</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-ast/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"permission_service_blogger_label\">Blogger</string>\n    <string name=\"permission_service_blogger_description\">Permite que l\\'aplicación acceda a Blogger pente cualesquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_adwords_label\">AdWords</string>\n    <string name=\"permission_service_gbase_description\">Permite que l\\'aplicación acceda a Google Base pente cualesquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_youtube_label\">YouTube</string>\n    <string name=\"permission_service_news_label\">Google News</string>\n    <string name=\"permission_service_all_label\">Tolos servicios de Google</string>\n    <string name=\"permission_service_finance_description\">Permite que l\\'aplicación acceda a Google Finance pente cualesquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_orkut_label\">Orkut</string>\n    <string name=\"permission_service_youtube_description\">Permite que l\\'aplicación acceda a YouTube pente cualesquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_knol_description\">Permite que l\\'aplicación acceda a Knol pente cualesquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_wifi_label\">Google Wi-Fi</string>\n    <string name=\"permission_service_health_label\">Google Health</string>\n    <string name=\"permission_service_android_label\">Servicios d\\'Android</string>\n    <string name=\"permission_service_health_description\">Permite que l\\'aplicación acceda a Google Health pente cualesquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_jotspot_description\">Permite que l\\'aplicación acceda a JotSpot pente cualesquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_notebook_label\">Google Notebook</string>\n    <string name=\"permission_service_cp_label\">Contautos</string>\n    <string name=\"permission_service_local_description\">Permite que l\\'aplicación acceda a Google Maps pente cualesquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_groups2_description\">Permite que l\\'aplicación acceda a Google Groups pente cualesquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_local_label\">Google Maps</string>\n    <string name=\"permission_service_adsense_description\">Permite que l\\'aplicación acceda a AdSense pente cualesquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_grandcentral_description\">Permite que l\\'aplicación acceda a Google Voice pente cualesquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_cl_description\">Permite que l\\'aplicación acceda a Google Calendar pente cualesquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_cl_label\">Google Calendar</string>\n    <string name=\"permission_service_talk_label\">Google Talk</string>\n    <string name=\"permission_service_ig_label\">iGoogle</string>\n    <string name=\"permission_service_android_description\">Permite que l\\'aplicación acceda a los servicios d\\'Android pente cualesquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_ig_description\">Permite que l\\'aplicación acceda a iGoogle pente cualesquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_adsense_label\">AdSense</string>\n    <string name=\"permission_service_orkut_description\">Permite que l\\'aplicación acceda a Orkut pente cualesquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_sierra_description\">Permite que l\\'aplicación acceda a les cuentes de Google Checkout pente cualesquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_lh2_description\">Permite que l\\'aplicación acceda a los álbumes web de Picasa pente cualesquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_wifi_description\">Permite que l\\'aplicación acceda a Google Wi-Fi pente cualesquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_all_description\">Permite que l\\'aplicación acceda a tolos servicios de Google pente cualesquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_notebook_description\">Permite que l\\'aplicación acceda a Google Notebook pente cualesquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_mail_label\">Google Mail</string>\n    <string name=\"permission_service_dodgeball_label\">Dodgeball</string>\n    <string name=\"permission_service_adwords_description\">Permite que l\\'aplicación acceda a AdWords pente cualesquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_news_description\">Permite que l\\'aplicación acceda a Google News pente cualesquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_gbase_label\">Google Base</string>\n    <string name=\"permission_service_print_description\">Permite que l\\'aplicación acceda a la busca de Google Llibros pente cualesquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_mail_description\">Permite que l\\'aplicación acceda a Google Mail pente cualesquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_jotspot_label\">JotSpot</string>\n    <string name=\"permission_service_lh2_label\">Álbumes web de Picasa</string>\n    <string name=\"permission_service_groups2_label\">Google Groups</string>\n    <string name=\"permission_service_ah_description\">Permite que l\\'aplicación acceda a Google App Engine pente cualesquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_ah_label\">Google App Engine</string>\n    <string name=\"permission_service_sierra_label\">Cuentes de Google Checkout</string>\n    <string name=\"permission_service_talk_description\">Permite que l\\'aplicación acceda a Google Talk pente cualesquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_dodgeball_description\">Permite que l\\'aplicación acceda a Dodgeball pente cualesquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_cp_description\">Permite que l\\'aplicación acceda a los contautos pente cualesquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_grandcentral_label\">Google Voice</string>\n    <string name=\"permission_service_print_label\">Busca de Google Llibros</string>\n    <string name=\"permission_service_finance_label\">Google Finance</string>\n    <string name=\"permission_service_knol_label\">Knol</string>\n</resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-ast/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <plurals name=\"gcm_registered_apps_counter\">\n        <item quantity=\"one\">Rexistróse <xliff:g example=\"1\">%1$d</xliff:g> aplicación</item>\n        <item quantity=\"other\">Rexistráronse <xliff:g example=\"1\">%1$d</xliff:g> aplicaciones</item>\n    </plurals>\n    <plurals name=\"cond_perm_action\">\n        <item quantity=\"one\">Solicitar el permisu que falta</item>\n        <item quantity=\"other\">Solicitar los permisos que falten</item>\n    </plurals>\n    <plurals name=\"pref_unifiednlp_summary\">\n        <item quantity=\"one\">Configuróse <xliff:g example=\"1\">%1$d</xliff:g> back-end</item>\n        <item quantity=\"other\">Configuráronse <xliff:g example=\"1\">%1$d</xliff:g> back-ends</item>\n    </plurals>\n    <plurals name=\"cond_perm_summary\">\n        <item quantity=\"one\">Nun se concedió un permisu riquíu pal funcionamientu correutu de los servicios de microG.</item>\n        <item quantity=\"other\">Nun se concedieron los permisos riquíos pal funcionamientu correutu de los servicios de microG.</item>\n    </plurals>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-ast/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=\"auth_sign_in\">Aniciar la sesión</string>\n    <string name=\"just_a_sec\">Un segundín…</string>\n    <string name=\"google_account_label\">Google</string>\n    <string name=\"sorry\">Sentímoslo…</string>\n    <string name=\"ask_permission_tos\">Al siguir, permites qu\\'esta aplicación ya Google usen la to información d\\'acuerdu colos sos términos de serviciu ya polítiques de privacidá respeutivos.</string>\n    <string name=\"ask_scope_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> quier:</string>\n    <string name=\"gms_settings_name\">Configuración de microG</string>\n    <string name=\"account_manager_title\">Xestor de cuentes de Google</string>\n    <string name=\"gms_app_name\">Servicios de microG</string>\n    <string name=\"auth_before_connect\">Hai una aplicación del preséu que tenta d\\'aniciar la sesión nuna cuenta de Google \\n \\nSi esta solicitú foi intencionada, usa\\'l botón <b>Aniciar la sesión</b> pa conectate a la páxina d\\'aniciu de sesión de Google, si non primi <b>Encaboxar</b> pa volver a l\\'aplicación que fexo qu\\'esti diálogu apaeciere.</string>\n    <string name=\"gms_settings_summary\">Configura los servicios de microG.</string>\n    <string name=\"ask_service_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> quier usar:</string>\n    <string name=\"credentials_assisted_continue\">Siguir</string>\n    <string name=\"self_check_cat_system\">Sistema</string>\n    <string name=\"prefcat_services\">Servicios</string>\n    <string name=\"prefs_account_privacy\">Información personal y privacidá</string>\n    <string name=\"games_snapshot_delete_btn_text\">desaniciar</string>\n    <string name=\"games_delete_snapshot_dialog_cancel\">Encaboxar</string>\n    <string name=\"prefcat_push_apps_registered_title\">Aplicaciones rexistraes</string>\n    <string name=\"prefcat_push_apps_unregistered_title\">Aplicaciones non rexistraes</string>\n    <string name=\"credentials_assisted_signin_add_account\">Amestar cuenta</string>\n    <string name=\"pref_accounts_title\">Cuentes de Google</string>\n    <string name=\"pref_info_status\">Estáu</string>\n    <string name=\"pref_more_settings\">Más</string>\n    <string name=\"prefcat_accounts_current_accounts_title\">Cuentes</string>\n    <string name=\"pref_add_account_title\">Cuenta</string>\n    <string name=\"pref_add_account_summary\">Amestar cuenta de Google</string>\n    <string name=\"credentials_assisted_choose_account_error_tips\">Anormalidá na cuenta</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-az/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"permission_service_android_label\">Android xidmətləri</string>\n    <string name=\"permission_service_android_description\">Tətbiqə istənilən əlaqəli Google hesabından Android xidmətlərinə daxil olmaq icazəsi verir.</string>\n    <string name=\"permission_service_adsense_label\">AdSense</string>\n    <string name=\"permission_service_adsense_description\">Tətbiqə istənilən əlaqəli Google hesabından AdSense-ə daxil olmaq icazəsi verir.</string>\n    <string name=\"permission_service_adwords_description\">Tətbiqə istənilən əlaqəli Google hesabından AdWords-ə daxil olmaq icazəsi verir.</string>\n    <string name=\"permission_service_ah_label\">Google Tətbiq Mühərriki</string>\n    <string name=\"permission_service_blogger_label\">Blogger</string>\n    <string name=\"permission_service_blogger_description\">Tətbiqə istənilən əlaqəli Google hesabından Blogger-ə daxil olmaq icazəsi verir.</string>\n    <string name=\"permission_service_cl_description\">Tətbiqə istənilən əlaqəli Google hesabından Google Təqvimə daxil olmaq icazəsi verir.</string>\n    <string name=\"permission_service_cp_label\">Kontaktlar</string>\n    <string name=\"permission_service_cp_description\">Tətbiqə istənilən əlaqəli Google hesabından Kontaktlara daxil olmaq icazəsi verir.</string>\n    <string name=\"permission_service_dodgeball_label\">Dodgeball</string>\n    <string name=\"permission_service_dodgeball_description\">Tətbiqə istənilən əlaqəli Google hesabından Dodgeball-a daxil olmaq icazəsi verir.</string>\n    <string name=\"permission_service_finance_label\">Google Finance</string>\n    <string name=\"permission_service_ah_description\">Tətbiqə istənilən əlaqəli Google hesabından Google Tətbiq Mühərrikinə daxil olmaq icazəsi verir.</string>\n    <string name=\"permission_service_cl_label\">Google Təqvim</string>\n    <string name=\"permission_service_all_label\">Bütün Google Xidmətləri</string>\n    <string name=\"permission_service_all_description\">Tətbiqə istənilən əlaqəli Google hesabından bütün Google xidmətlərinə daxil olmaq icazəsi verir.</string>\n    <string name=\"permission_service_adwords_label\">AdWords</string>\n    <string name=\"permission_service_finance_description\">Tətbiqə hər hansı əlaqəli Google hesabıyla Google Finance-yə daxil olmaq imkanı verir.</string>\n</resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-az/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <plurals name=\"cond_perm_action\">\n        <item quantity=\"one\">Çatışmayan icazəni tələb edir</item>\n        <item quantity=\"other\">Çatışmayan icazələri tələb edir</item>\n    </plurals>\n    <plurals name=\"pref_unifiednlp_summary\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> arxa uc konfiqurasiya edilmişdir</item>\n        <item quantity=\"other\"><xliff:g example=\"3\">%1$d</xliff:g> arxa uc konfiqurasiya edilmişdir</item>\n    </plurals>\n    <plurals name=\"cond_perm_summary\">\n        <item quantity=\"one\">MicroG Xidmətlərinin düzgün işləməsi üçün tələb olunan icazə verilmir.</item>\n        <item quantity=\"other\">MicroG Xidmətlərinin düzgün işləməsi üçün tələb olunan icazələr verilmir.</item>\n    </plurals>\n    <plurals name=\"gcm_registered_apps_counter\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> qeydiyyatdan keçmiş tətbiq</item>\n        <item quantity=\"other\"><xliff:g example=\"123\">%1$d</xliff:g> qeydiyyatdan keçmiş tətbiq</item>\n    </plurals>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-az/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=\"gms_app_name\">microG Xidmətləri</string>\n    <string name=\"gms_settings_name\">microG Tənzimləmələri</string>\n    <string name=\"gms_settings_summary\">microG xidmətlərini quraşdırın.</string>\n    <string name=\"just_a_sec\">Bir saniyə…</string>\n    <string name=\"google_account_label\">Google</string>\n    <string name=\"ask_permission_tos\">Davam etməklə, bu tətbiqə və Google-a məlumatınızı müvafiq xidmət şərtləri və məxfilik siyasətlərinə uyğun istifadə etməyə icazə verirsiniz.</string>\n    <string name=\"ask_scope_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> istəyirəm:</string>\n    <string name=\"auth_sign_in\">Daxil ol</string>\n    <string name=\"auth_connecting\">Sizi daxil etmək üçün cihazınız Google serverləri ilə əlaqə qurur. \\n\\nBu, bir neçə saniyə çəkə bilər.</string>\n    <string name=\"no_network_error_desc\">Şəbəkə bağlantınız yoxdur.\n\\n\n\\nBu müvəqqəti problem ola bilər və ya Android cihazınız məlumat xidmətləri üçün təmin olunmaya bilər. Mobil şəbəkəyə qoşulduqda təkrar cəhd edin və ya Wi-Fi şəbəkəsinə qoşulun.</string>\n    <string name=\"auth_general_error_desc\">Google serverləri ilə əlaqə qurarkən problem yarandı. \n\\n\n\\nBiraz sonra təkrar cəhd edin.</string>\n    <string name=\"allow\">İcazə ver</string>\n    <string name=\"deny\">İmtina et</string>\n    <string name=\"account_manager_title\">Google Hesab Meneceri</string>\n    <string name=\"ask_service_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> istifadə etmək istərdim:</string>\n    <string name=\"sorry\">Bağışlayın…</string>\n    <string name=\"auth_before_connect\">Cihazınızdakı tətbiq Google hesabına daxil olmağa çalışır. \\n\\nƏgər bu məqsədlə edilibsə, Google-un daxil olma səhifəsinə qoşulmaq üçün <b>Daxil ol</b> düyməsini istifadə edin, deyilsə, bu dialoqun görünməsinə səbəb olan tətbiqə qayıtmaq üçün <b>Ləğv et düyməsini</b> basın.</string>\n    <string name=\"auth_finalize\">Cihazınız məlumatı hesabınızda saxlamaq üçün Google ilə əlaqə saxlayır.\n\\n\n\\nBu bir neçə dəqiqə çəkə bilər.</string>\n    <string name=\"auth_notification_title\">Təsdiqləmə tələb olundu</string>\n    <string name=\"auth_notification_content\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> Google hesabınıza daxil olmaq üçün icazənizi tələb edir.</string>\n    <string name=\"auth_package_override_request_title\">İcazə verin &lt;b&gt;&lt;xliff:g example=\\\"F-Droid\\\"&gt; &lt;b&gt;%1$s&lt;/b&gt;&lt;/xliff:g&gt; imtiyazlı giriş&lt;xliff:g example=\\\"account@example.com\\\"&gt; %2$s&lt;/xliff:g&gt; ?</string>\n    <string name=\"auth_package_override_request_message\"><b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> hesabınıza daxil olmaq istəyir <b><xliff:g example=\"F-Droid\">%2$s</xliff:g> by <xliff:g example=\"F-Droid Inc.\">%3$s</xliff:g></b>. Bu, hesabınıza imtiyazlı giriş icazəsi verə bilər.</string>\n    <string name=\"signin_picker_title\">Hesab seç</string>\n    <string name=\"signin_picker_subtitle\">davam etmək<xliff:g example=\"F-Droid\"> %1$s</xliff:g></string>\n    <string name=\"signin_picker_add_account_label\">Başqa hesab əlavə et</string>\n    <string name=\"signin_confirm_title\">Daxil olmağa icazə verin <xliff:g example=\"F-Droid\"> %1$s</xliff:g></string>\n    <string name=\"signin_confirm_button_text\">İcazə ver və paylaş</string>\n    <string name=\"signin_subtext_sharing\">Davam etmək üçün microG Google Hesabınızın adını, e-poçt ünvanını və profil şəklini paylaşacaq<xliff:g example=\"F-Droid\"> %1$s</xliff:g> .</string>\n    <string name=\"signin_subtext_policy\">Bu tətbiqi istifadə etməzdən əvvəl onun %1$s və %2$s-a nəzər salın.</string>\n    <string name=\"signin_subtext_policy_privacy\">Məxfilik Siyasəti</string>\n    <string name=\"signin_subtext_policy_terms\">xidmət şərtləri</string>\n    <string name=\"perm_status_broadcast_label\">daxili status yayımların dinlə</string>\n    <string name=\"perm_gsf_read_gservices_label\">Google xidmət konfiqurasiyasını oxu</string>\n    <string name=\"perm_c2dm_receive_label\">C2DM məlumatların dinlə</string>\n    <string name=\"perm_gtalk_svc_label\">məlumat mübadiləsi və Google serverlərindən sinxronizasiya bildirişləri al</string>\n    <string name=\"perm_extended_access_label\">Google xidmətlərinə artırılmış giriş</string>\n    <string name=\"perm_provision_description\">Tətbiqə istifadəçi əlaqəsi olmadan microG xidmətlərini konfiqurasiya etməyə imkan verir</string>\n    <string name=\"perm_car_speed_label\">Avtomobil sürəti</string>\n    <string name=\"perm_car_speed_description\">Avtomobilinizin sürətinə keçin</string>\n    <string name=\"perm_car_info_description\">Avtomobilinizin məlumatına keçid edin</string>\n    <string name=\"perm_car_fuel_label\">Avtomobil yanacaq səviyyəsi</string>\n    <string name=\"perm_car_mileage_description\">Avtomobilinizin yürüş məlumatına keçid edin</string>\n    <string name=\"perm_car_vendor_extension_label\">Avtomobil satıcı kanalı</string>\n    <string name=\"service_name_snet\">Google SafetyNet</string>\n    <string name=\"service_name_mcs\">Simsiz Məlumatlandırma</string>\n    <string name=\"service_name_vending\">Play Store xidmətləri</string>\n    <string name=\"games_title\">Google Play Oyunlar</string>\n    <string name=\"games_info_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> Play Oyunları istifadə etmək istərdim</string>\n    <string name=\"games_info_content\">Play Oyunları istifadə etmək üçün Google Play Oyunlar tətbiqin quraşdırmaq tələb olunur. Tətbiq Play Oyunlar-sız davam edə bilər, lakin onun gözlənilməz fəaliyyəti mümkündür.</string>\n    <string name=\"pick_place_title\">Məkan seç</string>\n    <string name=\"pick_place_desc\">Məkan seçici hələ mövcud deyil.</string>\n    <string name=\"place_picker_select_title\">Bu məkanı seçin</string>\n    <string name=\"place_picker_nearby_places\">Yaxındakı məkanlar</string>\n    <string name=\"place_picker_location_lat_lng\">(%1$.7f, %2$.7f)</string>\n    <string name=\"lacking_permission_toast\">microG Xidmətləri: icazə yoxdur<xliff:g example=\"tam şəbəkə girişi var\"> %1$s</xliff:g></string>\n    <string name=\"self_check_name_fake_sig_perm\">Sistemin imza saxtakarlığı dəstəyi var:</string>\n    <string name=\"self_check_resolution_fake_sig_perm\">ROM-unuzun imza saxtakarlığı üçün yerli dəstəyi yoxdur. Siz hələ də imzanı saxtalaşdırmaq üçün Xposed və ya digər sistemləri istifadə edə bilərsiniz. Zəhmət olmasa, hansı ROM-ların imza saxtakarlığını dəstəklədiyi və olmayan ROM-larda microG-dən necə istifadə olunacağı ilə bağlı sənədləri yoxlayın.</string>\n    <string name=\"self_check_name_perm_granted\">Sistem imza saxtakarlığına icazə verir:</string>\n    <string name=\"self_check_name_system_spoofs\">Sistem saxta imzaları:</string>\n    <string name=\"self_check_resolution_system_spoofs\">Hansı addımların tələb oluna biləcəyi ilə bağlı sənədləri yoxla.</string>\n    <string name=\"self_check_pkg_gms\">microG Xidmətləri</string>\n    <string name=\"self_check_pkg_vending\">microG yoldaşı/Play Market</string>\n    <string name=\"self_check_resolution_app_installed\">Tətbiqi quraşdırın<xliff:g example=\"F-Droid\"> %1$s</xliff:g> və ya uyğun olanı. Hansı tətbiqlərin uyğun olduğuna dair sənədləri yoxlayın.</string>\n    <string name=\"self_check_name_correct_sig\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> düzgün imzası var: </string>\n    <string name=\"self_check_name_battery_optimizations\">Batareya optimallaşmasın istəmə :</string>\n    <string name=\"self_check_resolution_battery_optimizations\">Batareya optimallaşmasını qeyri-aktiv etmək üçün bura toxun. Bunu etməmək, tətbiqlərdə səhv ilə nəticələnə bilər.</string>\n    <string name=\"prefcat_about\">Haqqında</string>\n    <string name=\"prefcat_services\">Xidmətlər</string>\n    <string name=\"prefcat_test\">Sınaq</string>\n    <string name=\"cond_gcm_bat_title\">Batareya optimallaşması aktivdir</string>\n    <string name=\"cond_gcm_bat_summary\">Simsiz Məlumatlandırmanı aktiv etmisiniz, lakin microG Xidmətləri üçün batareya optimallaşması aktivdir. Təkan bildirişləri almaq üçün batareya optimallaşmasın bağlamalısız.</string>\n    <string name=\"cond_gcm_bat_action\">Optimallaşmalara məhəl qoyma</string>\n    <string name=\"cond_perm_title\">İcazə yoxdur</string>\n    <string name=\"prefs_account\">Hesab seçimləri</string>\n    <string name=\"prefs_account_privacy\">Şəxsi məlumat &amp; məxfilik</string>\n    <string name=\"prefs_account_security\">Giriş &amp; təhlükəsizlik</string>\n    <string name=\"pref_auth_trust_google_title\">Tətbiq icazələri üçün Google-a etibar et</string>\n    <string name=\"pref_auth_visible_title\">Tətbiqlərə hesabları tapmağa icazə ver</string>\n    <string name=\"pref_auth_include_android_id_title\">Cihaz qeydiyyatı ilə təsdiqlə</string>\n    <string name=\"pref_auth_include_android_id_summary\">İşlək deyilsə, təsdiqləmə sorğuları cihaz qeydiyyatı ilə əlaqələndirilməyəcək, icazəsiz cihazların daxil olmasına icazə verə bilər, lakin gözlənilməz nəticələr ola bilər.</string>\n    <string name=\"pref_auth_strip_device_name_title\">Təsdiqləmə üçün cihazın adını ayır</string>\n    <string name=\"pref_auth_strip_device_name_summary\">Aktiv edildikdə, təsdiqləmə sorğuları cihaz adın ehtiva etməyəcək, icazəsiz cihazlara daxil olmağa icazə verə bilər, lakin gözlənilməz nəticələr ola bilər.</string>\n    <string name=\"pref_checkin_enable_summary\">Cihazınızı Google xidmətlərində qeydiyyatdan keçirir və nadir cihaz təsdiqləyici yaradır. microG qeydiyyat məlumatından, Google hesabınızın adından başqa eyni hissələri ayırır.</string>\n    <string name=\"checkin_not_registered\">Qeydiyyat yoxdur</string>\n    <string name=\"checkin_last_registration\">Son qeydiyyat:<xliff:g example=\"Dünən, 02:20 PM\"> %1$s</xliff:g></string>\n    <string name=\"checkin_enable_switch\">Cihazı qeydiyyatdan keçir</string>\n    <string name=\"pref_info_status\">Vəziyyət</string>\n    <string name=\"pref_more_settings\">Daha çox</string>\n    <string name=\"pref_accounts_title\">Google Hesabları</string>\n    <string name=\"pref_accounts_summary\">Google hesabların əlavə et və idarə et</string>\n    <string name=\"prefcat_accounts_settings_title\">Tənzimləmələr</string>\n    <string name=\"pref_add_account_title\">Hesab</string>\n    <string name=\"pref_add_account_summary\">Google hesabı əlavə et</string>\n    <string name=\"pref_gcm_heartbeat_title\">Simsiz Məlumatlandırma sıx işləmə intervalı</string>\n    <string name=\"pref_gcm_apps_title\">Simsiz Məlumatlandırma istifadə edən tətbiqlər</string>\n    <string name=\"pref_gcm_confirm_new_apps_title\">Yeni tətbiqləri təsdiqlə</string>\n    <string name=\"pref_gcm_confirm_new_apps_summary\">Təkan bildirişləri almaq üçün yeni tətbiq qeydiyyatdan keçirməzdən əvvəl soruş</string>\n    <string name=\"pref_gcm_ping_interval\">Siqnal intervalı:<xliff:g example=\"10 dəqiqə\"> %1$s</xliff:g></string>\n    <string name=\"pref_about_title\">MicroG Xidmətləri Haqqında</string>\n    <string name=\"pref_about_summary\">Versiya məlumatı və istifadə olunan kitabxanalar</string>\n    <string name=\"gcm_app_error_unregistering\">Qeydiyyatdan çıxma xətası</string>\n    <string name=\"gcm_app_not_installed_anymore\">Artıq quraşdırılmayıb</string>\n    <string name=\"gcm_unregister_app\">Qeydiyyatdan çıxar</string>\n    <string name=\"gcm_not_registered\">Qeydiyyatdan keçməyib</string>\n    <string name=\"gcm_no_message_yet\">İndiyə kimi məlumat alınmadı</string>\n    <string name=\"gcm_last_message_at\">Son məlumat:<xliff:g example=\"Dünən, 02:20 PM\"> %1$s</xliff:g></string>\n    <string name=\"gcm_registered_since\">Qeydiyyatdan keçib:<xliff:g example=\"Dünən, 02:20 PM\"> %1$s</xliff:g></string>\n    <string name=\"gcm_messages_counter\">Məlumatlar: <xliff:g example=\"123\"> %1$d</xliff:g> (<xliff:g example=\"12345\"> %2$d</xliff:g> bayt)</string>\n    <string name=\"gcm_network_state_disconnected\">Əlaqə kəsildi</string>\n    <string name=\"gcm_network_state_connected\">Bu vaxtdan qoşulub <xliff:g example=\"2 saat öncə\"> %1$s</xliff:g></string>\n    <string name=\"gcm_enable_switch\">Təkan bildirişləri qəbul et</string>\n    <string name=\"gcm_allow_app_popup\">İcazə verilsin <xliff:g example=\"F-Droid\"> %1$s</xliff:g> təkan bildirişlərində qeydiyyatdan keçmək üçün?</string>\n    <string name=\"pref_push_app_allow_register_title\">Qeydiyyata icazə ver</string>\n    <string name=\"pref_push_app_wake_for_delivery_title\">Təkan məlumatında tətbiqi başlat</string>\n    <string name=\"pref_push_app_wake_for_delivery_summary\">Gələn təkan məlumatını qəbul etmək üçün tətbiqi fonda işə salın.</string>\n    <string name=\"prefcat_push_apps_title\">Təkan bildirişlərin istifadə edən tətbiqlər</string>\n    <string name=\"prefcat_push_apps_registered_title\">Qeydiyyatdan keçmiş tətbiqlər</string>\n    <string name=\"prefcat_push_apps_unregistered_title\">Qeydiyyatdan keçməmiş tətbiqlər</string>\n    <string name=\"safetynet_intro\">Google SafetyNet cihazın düzgün mühafizəsini və Android CTS ilə uyuşmasını təmin edən cihazın sertifikatlaşdırma sistemidir. Bəzi tətbiqlər SafetyNet-i təhlükəsizlik səbəbləri və ya müdaxilədən qorunmaq üçün ilkin şərt kimi istifadə edir. \n\\n\n\\nMicroG GmsCore SafetyNet-in pulsuz tətbiqini ehtiva edir, lakin rəsmi server xüsusi DroidGuard sistemin istifadə edərək SafetyNet sorğularının imzalanmasını tələb edir.</string>\n    <string name=\"safetynet_enable_switch\">Cihaz təsdiqləməsinə icazə ver</string>\n    <string name=\"pref_recaptcha_enterprise_test_title\">ReCAPTCHA Enterprise-ı Yoxla</string>\n    <string name=\"pref_test_summary_passed\">Bütün yoxlamadan keçdi</string>\n    <string name=\"menu_clear_recent_requests\">Son sorğuları təmizlə</string>\n    <string name=\"safetynet_last_run_at\">Son istifadə: <xliff:g example=\"Dünən, 02:20 PM\"> %1$s</xliff:g></string>\n    <string name=\"profile_name_native\">Yerli</string>\n    <string name=\"profile_name_real\">Həqiqi</string>\n    <string name=\"profile_name_user\">Fərdi: %s</string>\n    <string name=\"profile_name_auto\">Avtomatik: %s</string>\n    <string name=\"profile_name_system\">Sistem: %s</string>\n    <string name=\"pref_device_registration_import_custom_profile_title\">Fərdi profili idxal et</string>\n    <string name=\"pref_device_registration_serial_title\">Seriya</string>\n    <string name=\"pref_device_registration_import_custom_profile_summary\">Fayldan cihaz profilini idxal et</string>\n    <string name=\"pref_device_registration_select_profile_title\">Profil seç</string>\n    <string name=\"pref_device_registration_device_profile_category\">Cihaz profili</string>\n    <string name=\"pref_safetynet_recent_copy_json\">JSON JWS məlumatını köçür</string>\n    <string name=\"pref_safetynet_recent_advice\">Tövsiyə</string>\n    <string name=\"pref_safetynet_recent_eval_type\">Qiymətləndirmə növü</string>\n    <string name=\"pref_safetynet_recent_response_status\">Cavab vəziyyəti</string>\n    <string name=\"pref_safetynet_recent_cat_response\">Cavab məlumatı</string>\n    <string name=\"pref_safetynet_recent_cat_request\">Sorğu məlumatı</string>\n    <string name=\"pref_safetynet_recent_nonce\">Nonce (Hex)</string>\n    <string name=\"pref_safetynet_recent_request_time\">Sorğu vaxtı</string>\n    <string name=\"pref_safetynet_recent_request_type\">Sorğu növü</string>\n    <string name=\"pref_safetynet_recent_cat_basic\">Əsas məlumat</string>\n    <string name=\"pref_safetynet_recent_token\">Token</string>\n    <string name=\"pref_safetynet_test_not_completed\">Hələ tamamlanmayıb</string>\n    <string name=\"pref_safetynet_test_no_result\">Nəticə yoxdur</string>\n    <string name=\"pref_safetynet_test_invalid_json\">Etibarsız JSON</string>\n    <string name=\"push_notifications_summary_automatic\">Aç / Avtomatik: %s</string>\n    <string name=\"push_notifications_summary_manual\">Aç / Əl ilə: %s</string>\n    <string name=\"pref_vending_summary_licensing_off\">Lisenziya yoxdur</string>\n    <string name=\"pref_vending_summary_licensing_on\">Lisenziya aktivdir</string>\n    <string name=\"pref_vending_licensing_category\">Google Play Lisenziyası</string>\n    <string name=\"pref_vending_licensing_enable_switch\">Lisenziya yoxlama sorğularına cavab ver</string>\n    <string name=\"feedback_disabled\">Əlaqə hazırda mümkün deyil</string>\n    <string name=\"backup_disabled\">Nüsxələmə hazırda mümkün deyil</string>\n    <string name=\"pref_vending_billing_category\">Google Play Faturalandırma</string>\n    <string name=\"pref_vending_billing_enable_switch\">Ödəniş sorğuların idarə et</string>\n    <string name=\"pref_vending_billing_enable_summary\">Aktivləşdirildikdən sonra bəzi tətbiqlər Google Play Billing xidməti vasitəsilə alışları tamamlaya və ya abunəlikləri başlada bilər.</string>\n    <string name=\"pref_vending_billing_note_experimental\">Bu xüsusiyyət təcrübidir və pul itkisinə səbəb ola bilər. Sizin xəbəriniz oldu.</string>\n    <string name=\"credentials_assisted_cancel\">Ləğv et</string>\n    <string name=\"perm_c2dm_send_label\">digər tətbiqlərə C2DM məlumatların göndər</string>\n    <string name=\"perm_provision_label\">microG xidmətləri təmin edir</string>\n    <string name=\"perm_car_info_label\">Avtomobil məlumatı</string>\n    <string name=\"perm_car_fuel_description\">Avtomobilinizin yanacaq səviyyə məlumatına keçid edin</string>\n    <string name=\"perm_car_mileage_label\">Avtomobil yürüşü</string>\n    <string name=\"perm_car_vendor_extension_description\">Avtomobilə aid məlumat mübadiləsi üçün avtomobilinizin satıcı kanalına daxil olun</string>\n    <string name=\"service_name_checkin\">Google cihaz qeydiyyatı</string>\n    <string name=\"network_type_wifi\">Wi-Fi</string>\n    <string name=\"network_type_other\">Digər şəbəkələr</string>\n    <string name=\"self_check_cat_gms_packages\">Quraşdırılan paketlər</string>\n    <string name=\"network_type_mobile\">Mobil şəbəkə</string>\n    <string name=\"network_type_roaming\">Səyahət</string>\n    <string name=\"self_check_cat_system\">Sistem</string>\n    <string name=\"self_check_name_app_installed\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> quraşdırılmış: </string>\n    <string name=\"self_check_pkg_gsf\">microG Xidmətlər Quruluşu</string>\n    <string name=\"self_check_resolution_perm_granted\">Bu, ROM-un imza saxtakarlığını dəstəklədiyinin canlı göstəricisidir, lakin bunu aktivləşdirmək əlavə tədbirlər tələb edir. Hansı addımların tələb oluna biləcəyi ilə bağlı sənədləri yoxlayın.</string>\n    <string name=\"self_check_cat_fake_sig\">İmza saxtakarlığına dəstək</string>\n    <string name=\"self_check_resolution_correct_sig\">Ya quraşdırılmış<xliff:g example=\"F-Droid\"> %1$s</xliff:g> uyğun deyil və ya imza saxtakarlığı onun üçün aktiv deyil. Hansı tətbiqlərin və ROM-ların uyğun olduğuna dair sənədləri yoxlayın.</string>\n    <string name=\"prefcat_components\">Elementlər</string>\n    <string name=\"prefcat_google_services\">Google Xidmətləri</string>\n    <string name=\"prefcat_location_service\">Məkan xidməti</string>\n    <string name=\"prefcat_configuration\">Qurulma</string>\n    <string name=\"pref_auth_trust_google_summary\">İşlək deyilsə, tətbiq icazə sorğusu Google-a göndərilməzdən əvvəl istifadəçidən soruşulur. Bu bağlansa, bəzi tətbiqlər Google hesabını istifadə edə bilməyəcək.</string>\n    <string name=\"pref_auth_visible_summary\">Aktivləşdirildikdə, bu cihazdakı bütün tətbiqlər əvvəlcədən icazə olmadan Google Hesablarınızın e-poçt ünvanlarını görə biləcək.</string>\n    <string name=\"pref_device_registration_android_id\">Android ID</string>\n    <string name=\"prefcat_accounts_current_accounts_title\">Hesablar</string>\n    <string name=\"pref_gcm_enable_mcs_summary\">Simsiz Məlumatlandırma bir çox üçüncü tərəf tətbiqləri tərəfindən istifadə edilən təkan bildirişi təminatçısıdır. Bunu istifadə etmək üçün cihaz qeydiyyatını aktivləşdirməlisiniz.</string>\n    <string name=\"pref_gcm_apps_summary\">Hazırda Simsiz Məlumatlandırma üçün qeydiyyatdan keçmiş tətbiqlərin siyahısı.</string>\n    <string name=\"pref_gcm_heartbeat_summary\">Sistemin Google serverlərini zorlaması üçün saniyələrlə interval. Bu rəqəmin artırılması batareya istehlakını azaldacaq, lakin təkan bildirişlərində gecikmələrə səbəb ola bilər.\n\\nKöhnəlmişdir, gələcək buraxılışda dəyişdiriləcək.</string>\n    <string name=\"gcm_registered\">Qeydiyyatdan keçib</string>\n    <string name=\"gcm_unregister_confirm_title\">Qeydiyyatdan çıxar<xliff:g example=\"F-Droid\"> %1$s</xliff:g> ?</string>\n    <string name=\"gcm_unregister_confirm_message\">Bəzi tətbiqlər avtomatik olaraq yenidən qeydiyyatdan keçmir və seçimi əl ilə yaratmaq imkanı vermir. Bu tətbiqlər qeydiyyatdan çıxarıldıqdan sonra düzgün işləməyə bilər.\n\\n Davam edilsin?</string>\n    <string name=\"gcm_unregister_after_deny_message\">Siz artıq göstərilən təkan bildirişləri üçün qeydiyyatdan keçmək üçün tətbiqdən imtina etdiniz.\n\\nGələcəkdə təkan məlumatı almaması üçün bunu indi qeydiyyatdan çıxarmaq istəyirsiniz?</string>\n    <string name=\"pref_push_app_allow_register_summary\">Tətbiqə təkan bildirişlərində qeydiyyatdan keçməyə icazə verin.</string>\n    <string name=\"prefcat_push_networks_title\">Təkan bildirişlərində istifadə ediləcək şəbəkələr</string>\n    <string name=\"pref_safetynet_test_title\">SafetyNet təsdiqləməni yoxla</string>\n    <string name=\"pref_recaptcha_test_title\">ReCAPTCHA-nı yoxla</string>\n    <string name=\"pref_test_summary_failed\">Uğursuz: %s</string>\n    <string name=\"pref_test_summary_warn\">Xəbərdarlıq: %s</string>\n    <string name=\"pref_test_summary_running\">Emal edilir…</string>\n    <string name=\"pref_droidguard_operation_mode\">İş rejimi</string>\n    <string name=\"pref_droidguard_unsupported_summary\">DroidGuard icrası bu cihazda dəstəklənmir. SafetyNet xidmətləri səhv işləyə bilər.</string>\n    <string name=\"prefcat_safetynet_apps_title\">SafetyNet istifadə edən tətbiqlər</string>\n    <string name=\"pref_safetynet_recent_uses\">Son istifadələr</string>\n    <string name=\"pref_safetynet_recent_recaptcha_summary\">ReCaptcha: %s</string>\n    <string name=\"pref_safetynet_recent_attestation_summary\">Təsdiqləmə: %s</string>\n    <string name=\"pref_safetynet_recent_recaptcha_enterprise_summary\">ReCaptcha Enterprise: %s</string>\n    <string name=\"pref_safetynet_recent_copied\">Buferə köçürüldü!</string>\n    <string name=\"pref_safetynet_test_integrity_cts_passed\">Təmizlik və CTS keçdi</string>\n    <string name=\"pref_safetynet_test_cts_failed\">CTS uğursuz oldu</string>\n    <string name=\"pref_safetynet_test_integrity_failed\">Təmizlik uğursuz oldu</string>\n    <string name=\"push_notifications_summary_off\">Bağla</string>\n    <string name=\"push_notifications_summary_values_seconds\">%s saniyə</string>\n    <string name=\"push_notifications_summary_values_minutes\">%s dəqiqə</string>\n    <string name=\"pref_vending_license_enable_summary\">Bəzi tətbiqlər onları Google Play-də satın aldığınıza dair təsdiq tələb edir. Tətbiq tərəfindən tələb edildikdə, microG Google-dan satınalma sübutun yükləyə bilər. Əgər işlək deyilsə və ya Google hesabı əlavə edilməyibsə, lisenziya yoxlanılması sorğularına məhəl qoyulmur.</string>\n    <string name=\"pref_vending_billing_note_licensing\">Bəzi tətbiqlər satınalmalarınızı təsdiqləmək üçün lisenziya yoxlamasını aktiv etməyinizi də tələb edə bilər.</string>\n    <string name=\"credentials_assisted_sign_back_title\">Google ilə %1$s hesabına təkrar daxil ol</string>\n    <string name=\"credentials_assisted_continue\">Davam et</string>\n    <string name=\"credentials_assisted_confirmation_header\">Daxil olursunuz</string>\n    <string name=\"credentials_assisted_continue_as_user_button_label\">%1$s olaraq davam et</string>\n    <string name=\"credentials_assisted_signin_consent_header\">%1$s kimi giriş edilir</string>\n    <string name=\"credentials_assisted_signin_description\">Siz Google Hesablarınızda Google ilə Girişi idarə edə bilərsiniz.</string>\n    <string name=\"credentials_assisted_signin_consent\">Davam etməklə, Google adınızı, e-poçt ünvanınızı və profil şəklinizi %1$s ilə paylaşacaq. %1$s-ın Məxfilik Siyasətinə və Xidmət Şərtlərinə baxın.</string>\n    <string name=\"credentials_assisted_choose_account_subtitle\">%1$s ilə davam etmək üçün</string>\n    <string name=\"credentials_assisted_choose_account_label\">Hesab seçin</string>\n    <string name=\"credentials_assisted_signin_button_text_long\">Google ilə daxil olun</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_switch\">Pulsuz tətbiqləri birbaşa kitabxanaya əlavə et</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_summary\">Pulsuz tətbiqlərin Google Play-dən endirilib-endirilmədiyini yoxlaya bilər. Hazırda sizin üçün mövcud olan bütün pulsuz tətbiqlərin yoxlanışın həmişə ötürmək üçün pulsuz tətbiqləri birbaşa hesab kitabxananıza əlavə edin.</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-be/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2020 microG Project Team\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  --><resources>\n    <string name=\"permission_service_all_label\">Усе сэрвісы Google</string>\n    <string name=\"permission_service_all_description\">Дае прыкладанню доступ да сэрвісаў Google праз любы звязаны уліковы запіс Google.</string>\n    <string name=\"permission_service_android_label\">Сэрвісы Android</string>\n    <string name=\"permission_service_android_description\">Дае прыкладанню доступ да сэрвісаў Android праз любы звязаны уліковы запіс Google.</string>\n    <string name=\"permission_service_adsense_label\">AdSense</string>\n    <string name=\"permission_service_adsense_description\">Дае прыкладанню доступ да Adsense праз любы звязаны уліковы запіс Google.</string>\n    <string name=\"permission_service_adwords_label\">AdWords</string>\n    <string name=\"permission_service_adwords_description\">Дае прыкладанню доступ да AdWords праз любы звязаны уліковы запіс Google.</string>\n    <string name=\"permission_service_ah_label\">Google App Engine</string>\n    <string name=\"permission_service_ah_description\">Дае прыкладанню доступ да Google App Engine праз любы звязаны уліковы запіс Google.</string>\n    <string name=\"permission_service_blogger_label\">Blogger</string>\n    <string name=\"permission_service_blogger_description\">Дае прыкладанню доступ да Blogger праз любы звязаны уліковы запіс Google.</string>\n    <string name=\"permission_service_cl_label\">Google Календарь</string>\n    <string name=\"permission_service_cl_description\">Дае прыкладанню доступ да Google Календара праз любы звязаны уліковы запіс Google.</string>\n    <string name=\"permission_service_cp_label\">Контакты</string>\n    <string name=\"permission_service_cp_description\">Дае прыкладанню доступ да Кантактаў праз любы звязаны уліковы запіс Google.</string>\n    <string name=\"permission_service_dodgeball_label\">Dodgeball</string>\n    <string name=\"permission_service_dodgeball_description\">Дае прыкладанню доступ да Dodgeball праз любы звязаны уліковы запіс Google.</string>\n    <string name=\"permission_service_finance_label\">Google Finance</string>\n    <string name=\"permission_service_finance_description\">Дае прыкладанню доступ да Google Finance праз любы звязаны уліковы запіс Google.</string>\n    <string name=\"permission_service_gbase_label\">Google Base</string>\n    <string name=\"permission_service_gbase_description\">Дае прыкладанню доступ да Google Base праз любы звязаны уліковы запіс Google.</string>\n    <string name=\"permission_service_grandcentral_label\">Google Voice</string>\n    <string name=\"permission_service_grandcentral_description\">Дае прыкладанню доступ да Google Voice праз любы звязаны уліковы запіс Google.</string>\n    <string name=\"permission_service_groups2_label\">Групы Google</string>\n    <string name=\"permission_service_groups2_description\">Дае прыкладанню доступ да Google Groups праз любы звязаны уліковы запіс Google.</string>\n    <string name=\"permission_service_health_label\">Google Health</string>\n    <string name=\"permission_service_health_description\">Дае прыкладанню доступ да Google Health праз любы звязаны уліковы запіс Google.</string>\n    <string name=\"permission_service_ig_label\">iGoogle</string>\n    <string name=\"permission_service_ig_description\">Дае прыкладанню доступ да iGoogle праз любы звязаны уліковы запіс Google.</string>\n    <string name=\"permission_service_jotspot_label\">JotSpot</string>\n    <string name=\"permission_service_jotspot_description\">Дае прыкладанню доступ да JotSpot праз любы звязаны уліковы запіс Google.</string>\n    <string name=\"permission_service_knol_label\">Knol</string>\n    <string name=\"permission_service_knol_description\">Дае прыкладанню доступ да Knol праз любы звязаны уліковы запіс Google.</string>\n    <string name=\"permission_service_lh2_label\">Picasa Web Albums</string>\n    <string name=\"permission_service_lh2_description\">Дае прыкладанню доступ да Picasa Web Albums праз любы звязаны уліковы запіс Google.</string>\n    <string name=\"permission_service_local_label\">Google Карты</string>\n    <string name=\"permission_service_local_description\">Дае прыкладанню доступ да Google Maps праз любы звязаны уліковы запіс Google.</string>\n    <string name=\"permission_service_mail_label\">Google Mail</string>\n    <string name=\"permission_service_mail_description\">Дае прыкладанню доступ да Google Mail праз любы звязаны уліковы запіс Google.</string>\n    <string name=\"permission_service_news_label\">Google Навіны</string>\n    <string name=\"permission_service_news_description\">Дае прыкладанню доступ да Google News праз любы звязаны уліковы запіс Google.</string>\n    <string name=\"permission_service_notebook_label\">Google Notebook</string>\n    <string name=\"permission_service_notebook_description\">Дае прыкладанню доступ да Google Notebook праз любы звязаны уліковы запіс Google.</string>\n    <string name=\"permission_service_orkut_label\">Orkut</string>\n    <string name=\"permission_service_orkut_description\">Дае прыкладанню доступ да Orkut праз любы звязаны уліковы запіс Google.</string>\n    <string name=\"permission_service_print_label\">Google Кнігі</string>\n    <string name=\"permission_service_print_description\">Дае прыкладанню доступ да Google Book Search праз любы звязаны уліковы запіс Google.</string>\n    <string name=\"permission_service_sierra_label\">Аккаунты Google Checkout</string>\n    <string name=\"permission_service_sierra_description\">Дае прыкладанню доступ да акаўнтаў Google Checkout праз любы звязаны уліковы запіс Google.</string>\n    <string name=\"permission_service_sierraqa_label\">Аккаунты Google Checkout QA</string>\n    <string name=\"permission_service_sierraqa_description\">Дае прыкладанню доступ да акаўнтаў Google Checkout QA праз любы звязаны уліковы запіс Google.</string>\n    <string name=\"permission_service_sierrasandbox_label\">Аккаунты Google Checkout Sandbox</string>\n    <string name=\"permission_service_sierrasandbox_description\">Дае прыкладанню доступ да акаўнтаў Google Checkout Sandbox праз любы звязаны уліковы запіс Google.</string>\n    <string name=\"permission_service_sitemaps_label\">Google Webmaster Tools</string>\n    <string name=\"permission_service_sitemaps_description\">Дае прыкладанню доступ да Google Webmaster Tools праз любы звязаны уліковы запіс Google.</string>\n    <string name=\"permission_service_speech_label\">Галасавы пошук</string>\n    <string name=\"permission_service_speech_description\">Дае прыкладанню доступ да Voice Search праз любы звязаны уліковы запіс Google.</string>\n    <string name=\"permission_service_speechpersonalization_label\">Персаналізаванае распазнанне маўлення</string>\n    <string name=\"permission_service_speechpersonalization_description\">Дае прыкладанню доступ да Personalized Speech Recognition праз любы звязаны уліковы запіс Google.</string>\n    <string name=\"permission_service_talk_label\">Google Talk</string>\n    <string name=\"permission_service_talk_description\">Дае прыкладанню доступ да Google Talk праз любы звязаны уліковы запіс Google.</string>\n    <string name=\"permission_service_wifi_label\">Google Wi-Fi</string>\n    <string name=\"permission_service_wifi_description\">Дае прыкладанню доступ да Google Wi-Fi праз любы звязаны уліковы запіс Google.</string>\n    <string name=\"permission_service_wise_label\">Google Табліцы</string>\n    <string name=\"permission_service_wise_description\">Дае прыкладанню доступ да Google Spreadsheets праз любы звязаны уліковы запіс Google.</string>\n    <string name=\"permission_service_writely_label\">Google Docs</string>\n    <string name=\"permission_service_writely_description\">Дае прыкладанню доступ да Google Docs праз любы звязаны уліковы запіс Google.</string>\n    <string name=\"permission_service_youtube_label\">YouTube</string>\n    <string name=\"permission_service_youtube_description\">Дае прыкладанню доступ да YouTube праз любы звязаны уліковы запіс Google.</string>\n    <string name=\"permission_service_YouTubeUser_label\">Имена пользователей YouTube</string>\n    <string name=\"permission_service_YouTubeUser_description\">Дазваляе прыкладанню атрымаць доступ да імя карыстальніка(аў) YouTube, які звязаны з акаунтам Google.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_activity\">Праглядзець гісторыю актыўнасці вашых прыкладанняў Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.buyer\">Кіраванне сваім уліковым запісам пакупніка Ad Exchange</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller.readonly\">Прагляд вашых Ad Exchange дадзеных</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller\">Прагляд і кіраванне вашымі дадзенымі Ad Exchange</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsensehost\">Прагляд і кіраванне вашымі дадзенымі AdSense хостынгаў і звязанымі акаўнтамі</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense.readonly\">Прагляд вашых дадзеных AdSense</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense\">Прагляд і кіраванне вашымі дадзенымі AdSense</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics.readonly\">Прагляд вашых дадзеных Google Analytics</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics\">Прагляд і кіраванне вашымі дадзенымі Google Analytics</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_androidpublisher\">Доступ да крамы Google Play для Android распрацоўніка</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appengine.admin\">Рухавік прыкладання сферы адміністравання.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.migration\">Доступ на чытанне і запіс для Groups Migration API.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.settings\">Прагляд і кіраванне наладамі Google Apps Group</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.licensing\">Правы на чытанне/запіс для License Manager API.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order\">\"Доступ для чытання/запісу адміністратарам і карыстальнікам пры тэставанні ў пясочніцы API або доступ для чытання/запісу пры звароце да API-аперацыях напрамую.\"</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order.readonly\">\"Акрамя агульнага чытання/запісу па пратаколе OAuth, варта выкарыстоўваць толькі для чытання пратакол OAuth пры выманні дадзеных кліента.\"</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps_reporting_audit.readonly\">Доступ да API аўдыту адміністратара толькі для чытання</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appstate\">Вобласць выкарыстання сэрвісу App State.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery.readonly\">Прагляд сваіх дадзеных у Google BigQuery</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery\">Прагляд і кіраванне сваімі дадзенымі ў Google BigQuery</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger\">Кіраванне сваім ўліковым запісам блогера</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger.readonly\">Прагляд свайго ўліковага запісу блогера</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_books\">Кіраванне сваімі кнігамі</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar\">Кіраванне сваімі календарамі</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar.readonly\">Прагляд сваіх календароў</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_cloudprint\">Прагляд і кіраванне сваімі дадзенымі Google Cloud Print</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute.readonly\">Прагляд сваіх рэсурсаў Google Compute Engine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute\">Прагляд і кіраванне сваімі рэсурсамі Google Compute Engine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate.readonly\">Прагляд сваіх мэтаў Google Coordinate</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate\">Прагляд і кіраванне сваімі зададзенымі каардынатамі Google Maps</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.full_control\">Кіраванне сваімі дадзенымі і дазволамі ў Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_only\">Прагляд сваіх дадзеных у Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_write\">Кіраванне сваімі дадзенымі ў Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_dfareporting\">Прагляд і кіраванне DoubleClick справаздач рэкламадаўцаў</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.appdata\">Падаць доступ да папкі дадзеных прыкладання</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.apps.readonly\">Посмотреть свои приложения Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.file\">Прагляд і кіраванне файламі Google Drive, якія вы адкрылі або стварылі ў гэтым прыкладанні</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.install\">Асаблівыя магчымасці, якія дазваляюць карыстальнікам зацвердзіць ўсталяванне прыкладання</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.metadata.readonly\">Прагляд метададзеных для файлаў і дакументаў Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.readonly\">Прагляд файлаў і дакументаў Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.scripts\">Змяненне паводзін сваіх сцэнарыяў Google Apps Script</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive\">Прагляд і кіраванне файламі і дакументамі Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase.readonly\">Прагляд свайго ўліковага запісу Freebase</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase\">Зарэгістравацца ў Freebase з вашым уліковым запісам</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables\">Кіраванне зліццём табліц</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables.readonly\">Прагляд табліцы Fusion</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_games\">Доступ да дадзеных Google Play Гульні.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan\">Кіраванне дадзенымі GAN</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan.readonly\">Прагляд дадзеных GAN</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gcm_for_chrome\">CloudMessaging для Chrome</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_glass.timeline\">Glass timeline scope</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.compose\">Стварэнне, чытанне, абнаўленне і выдаленне чарнавікоў. Адпраўка паведамленняў і чарнавікоў.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.modify\">Усе аперацыі чытання/запісу адбываюцца неадкладна, акрамя выдалення тэмаў  і паведамленняў, мінаючых кошык.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.readonly\">Чытанне ўсіх рэсурсаў і іх метададзеных, якія не выкарыстоўваюць аперацыі запісу.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.best\">Выбраць ваша найбольш дакладнае месцазнаходжанне і гісторыю</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.city\">Выбраць ваш горад і гісторыю месцазнаходжаннў</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.best\">Выбраць ваша самае дакладнае месцазнаходжанне</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.city\">Выберыце свой горад</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine\">Прагляд вашых дадзеных Google Maps Engine і кіраванне імі</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine.readonly\">Прагляд вашых дадзеных Google Maps Engine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mobilemaps.firstparty\">Прагляд і кіраванне вашымі Google Картамі для мабільных прылад</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut\">Кіраванне сваімі дзеяннямі Orkut</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut.readonly\">Прагляд сваіх дадзеных Orkut</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.login\">\"Даведацца ваша імя, базавую інфармацыю, і спіс людзей, з якімі вы маеце зносіны ў Google+\"</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.me\">Даведацца хто вы ў Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_prediction\">Кіраванне сваімі дадзенымі ў Google Prediction API</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_shoppingapi\">Прагляд дадзеных прадукту</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification\">Кіраванне вашым спісам сайтаў і даменаў</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification.verify_only\">Кіраванне верыфікацяй вашых сайтаў у Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_structuredcontent\">Доступ на запіс/чытанне для Shopping Content API.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue.consumer\">Выкананне задач з вашага TaskQueue</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue\">Кіраванне вашымі задачамі</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks\">Кіраванне задачамі</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks.readonly\">Праглядзець свае задачы</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tracks\">\"Google Maps Tracks API, гэтая сфера якая прадстаўляе доступ на чытанне і запіс вашых праектаў.\"</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_urlshortener\">Кіраванне вашымі кароткімі URL-адрасамі goo.gl</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.email\">Паглядзець свой адрас электроннай пошты</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.profile\">Прагляд асноўнай інфармацыі аб акаўнце</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube\">Кіраванне акаўнтам YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtubepartner\">Прагляд і кіраванне сваімі аб\\'ектамі і кантэнтам на YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.readonly\">Прагляд свайго акаўнта YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.upload\">Кіраванне вашымі відэа на YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics_monetary.readonly\">Прагляд грашовых справаздачаў YouTube Analytics для вашага кантэнту на YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics.readonly\">Прагляд на YouTube аналітычных справаздач для вашага кантэнту YouTube</string>\n</resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-be/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2020 microG Project Team\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  --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <plurals name=\"pref_unifiednlp_summary\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> навігацыйны модуль наладжаны</item>\n        <item quantity=\"few\"><xliff:g example=\"3\">%1$d</xliff:g> навігацыйных модуля наладжана</item>\n        <item quantity=\"many\"><xliff:g example=\"5\">%1$d</xliff:g> навігацыйных модуляў наладжана</item>\n        <item quantity=\"other\"><xliff:g example=\"5\">%1$d</xliff:g> навігацыйных модуляў наладжана</item>\n    </plurals>\n    <plurals name=\"gcm_registered_apps_counter\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> прывязанае прыкладанне</item>\n        <item quantity=\"few\"><xliff:g example=\"3\">%1$d</xliff:g> прывязаных прыкладання</item>\n        <item quantity=\"many\"><xliff:g example=\"5\">%1$d</xliff:g> прывязаных прыкладанняў</item>\n        <item quantity=\"other\"><xliff:g example=\"5\">%1$d</xliff:g> прывязаных прыкладанняў</item>\n    </plurals>\n    <plurals name=\"cond_perm_summary\">\n        <item quantity=\"one\">Не прадастаўлены дазвол, які патрабуецца для правільнага функцыянавання microG Services.</item>\n        <item quantity=\"few\">Не прадастаўлены дазволы, якія патрабуюцца для правільнага функцыянавання microG Services.</item>\n        <item quantity=\"other\">Не прадастаўлены дазволы, якія патрабуюцца для правільнага функцыянавання microG Services.</item>\n    </plurals>\n    <plurals name=\"cond_perm_action\">\n        <item quantity=\"one\">Запрасіць адсутны дазвол</item>\n        <item quantity=\"few\">Запрасіць адсутныя дазволы</item>\n        <item quantity=\"other\">Запрасіць адсутныя дазволы</item>\n    </plurals>\n</resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-be/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2017 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"gms_app_name\">microG Services</string>\n    <string name=\"gms_settings_name\">Налады microG</string>\n    <string name=\"gms_settings_summary\">Налады сэрвісаў microG</string>\n    <string name=\"just_a_sec\">Калі ласка, пачакайце…</string>\n    <string name=\"google_account_label\">Google</string>\n    <string name=\"ask_permission_tos\">Працягваючы, вы дазваляеце гэтаму прыкладанню і Google выкарыстоўваць сваю інфармацыю ў адпаведнасці з іх ўмовамі прадастаўлення паслуг і палітыкамі прыватнасці.</string>\n    <string name=\"ask_scope_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> хацеў бы:</string>\n    <string name=\"ask_service_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> хацеў бы выкарыстаць:</string>\n    <string name=\"account_manager_title\">Менеджэр уліковых запісаў Google</string>\n    <string name=\"sorry\">Выбачайце…</string>\n    <string name=\"auth_before_connect\">\"Прыкладанне на вашай прыладзе спрабуе ўвайсці ў ўліковы запіс Google.\n\nКалі гэта было наўмысна, націсніце кнопку <b>Увайсці</b>, каб падключыцца да старонкі ўваходу ў Google, калі не, націсніце <b>Адмена</b>, каб вярнуцца да прыкладання, якое выклікала гэта дыялогавае акно.\"</string>\n    <string name=\"auth_sign_in\">Увайсці</string>\n    <string name=\"auth_connecting\">\"Ваша прылада ўсталёўвае злучэнне з серверамі Google для ўваходу ў сістэму.\n\nГэта можа заняць некалькі секунд.\"</string>\n    <string name=\"no_network_error_desc\">\"У вас няма падлучэння да сеткі.\n\nГэта можа быць часовай праблемай, або ваша Android прылада не можа выкарыстоўваць перадачу дадзеных. Паспрабуйце яшчэ раз, калі з'явіцца злучэнне з мабільнай сеткай або далучыцеся да сеткі Wi-Fi.\"</string>\n    <string name=\"auth_general_error_desc\">\"Не ўдаецца злучыцца з серверамі Google.\n\nПаспрабуйце пазней.\"</string>\n    <string name=\"auth_finalize\">\"Ваша прылада злучаецца з Google, каб захаваць інфармацыю ў ваш уліковы запіс.\n\nГэта можа заняць некалькі хвілін.\"</string>\n    <string name=\"allow\">Дазволіць</string>\n    <string name=\"deny\">Адмовіць</string>\n    <string name=\"auth_notification_title\">Патрабуецца аўтэнтыфікацыя</string>\n    <string name=\"auth_notification_content\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> патрабуецца аўтарызацыя каб атрымаць доступ да вашай ўліковага запісу Google.</string>\n    <string name=\"perm_status_broadcast_label\">сачыць за унутраным станам статусу</string>\n    <string name=\"perm_c2dm_receive_label\">выкарыстоўваць C2DM паведамленні</string>\n    <string name=\"perm_c2dm_send_label\">адпраўляць C2DM паведамленні іншым прыкладанням</string>\n    <string name=\"perm_gtalk_svc_label\">абменьвацца паведамленнямі і атрымліваць апавяшчэнні аб сінхранізацыі ад сервераў Google</string>\n    <string name=\"perm_extended_access_label\">Пашыраны доступ да сэрвісаў Google</string>\n    <string name=\"perm_provision_label\">падрыхтоўка сэрвісаў microG</string>\n    <string name=\"perm_provision_description\">Дазволіць прыкладанню настраіваць сэрвісы microG без ўмяшання карыстальніка</string>\n    <string name=\"service_name_checkin\">Рэгістрацыя прылады</string>\n    <string name=\"service_name_mcs\">Воблачныя паведамленні</string>\n    <string name=\"service_name_snet\">Google SafetyNet</string>\n    <string name=\"games_title\">Google Play Гульні</string>\n    <string name=\"games_info_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> хоча выкарыстоўваць Play Гульні</string>\n    <string name=\"games_info_content\">Каб выкарыстоўваць магчымасці Play Гульні, трэба ўсталяваць прыкладанне Google Play Гульні. Прыкладанне можа працаваць і без яго, але магчымыя праблемы у яго рабоце.</string>\n    <string name=\"pick_place_title\">Вылучыце месца</string>\n    <string name=\"pick_place_desc\">Сродак выбару месца часова недаступны.</string>\n    <string name=\"place_picker_select_title\">Выберыце гэта месцазнаходжанне</string>\n    <string name=\"place_picker_nearby_places\">Бліжэйшыя месцы</string>\n    <string name=\"place_picker_location_lat_lng\">(%1$.7f, %2$.7f)</string>\n    <string name=\"lacking_permission_toast\">microG Services: Адсутнічае дазвол для <xliff:g example=\"have full network acccess\">%1$s</xliff:g></string>\n    <string name=\"network_type_mobile\">Мабільная сетка</string>\n    <string name=\"network_type_wifi\">Wi-Fi</string>\n    <string name=\"network_type_roaming\">Роўмінг</string>\n    <string name=\"network_type_other\">Іншыя сеткі</string>\n    <!-- Self check -->\n\n    <string name=\"self_check_cat_fake_sig\">Падтрымка падмены подпісу</string>\n    <string name=\"self_check_cat_gms_packages\">Устаноўленыя пакеты</string>\n    <string name=\"self_check_cat_system\">Сістэма</string>\n    <string name=\"self_check_name_fake_sig_perm\">Сістэма падтрымлівае падмену подпісу:</string>\n    <string name=\"self_check_resolution_fake_sig_perm\">Ваша прашыўка не мае натыўнай падтрымкі падмены подпісу. Вы можаце выкарыстаць Xposed або іншыя метады, каб актываваць падмену подпісу. Калі ласка, азнаёмцеся з дакументацыяй, якая прашыўка падтрымлівае падмену подпісу і як выкарыстоўваць microG ў прашыўцы, якая не падтрымлівае.</string>\n    <string name=\"self_check_name_perm_granted\">Сістэма дазваляе падмену подпісу:</string>\n    <string name=\"self_check_resolution_perm_granted\">Ваша прашыўка падтрымлівае падмену подпісу, але патрабуе дадатковых дзеянняў для яе актывацыі. Калі ласка, азнаёмцеся з дакументацыяй, дзе апісана што трэба зрабіць.</string>\n    <string name=\"self_check_name_system_spoofs\">Сістэма падмяняе подпісы:</string>\n    <string name=\"self_check_resolution_system_spoofs\">Калі ласка, азнаёмцеся з дакументацыяй, дзе апісана што трэба зрабіць.</string>\n    <string name=\"self_check_pkg_gms\">Play Services (GmsCore)</string>\n    <string name=\"self_check_pkg_vending\">Play Store (Phonesky)</string>\n    <string name=\"self_check_pkg_gsf\">Services Framework (GSF)</string>\n    <string name=\"self_check_name_app_installed\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> усталяваны: </string>\n    <string name=\"self_check_resolution_app_installed\">Усталюйце прыкладанне <xliff:g example=\"F-Droid\">%1$s</xliff:g> або сумяшчальнае. Калі ласка, азнаёмцеся з дакументацыяй, дзе апісана якія прыкладанні сумяшчальныя.</string>\n    <string name=\"self_check_name_correct_sig\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> мае правільны подпіс: </string>\n    <string name=\"self_check_resolution_correct_sig\">Альбо усталяваны <xliff:g example=\"F-Droid\">%1$s</xliff:g> не сумяшчальны, альбо падмена подпісу не актыўная для яго. Калі ласка, азнаёмцеся з дакументацыяй, дзе апісана якія прыкладанні або прашыўкі сумяшчальныя.</string>\n    <string name=\"self_check_name_battery_optimizations\">Аптымізацыя энергаспажывання адключаная:</string>\n    <string name=\"self_check_resolution_battery_optimizations\">Націсніце тут, каб дазволіць прыкладанням працаваць у фоне. Без гэтага некаторыя праграмы могуць працаваць са збоямі.</string>\n    <!-- Settings strings -->\n\n    <string name=\"prefcat_about\">Аб праграме</string>\n    <string name=\"prefcat_components\">Кампоненты</string>\n    <string name=\"prefcat_configuration\">Канфігурацыя</string>\n    <string name=\"prefcat_google_services\">Google сэрвісы</string>\n    <string name=\"prefcat_location_service\">Служба вызначэння месцазнаходжання</string>\n    <string name=\"prefcat_services\">Сэрвісы</string>\n    <string name=\"prefcat_test\">Тэст</string>\n    <string name=\"cond_gcm_bat_title\">Актыўная аптымізацыя энергаспажывання</string>\n    <string name=\"cond_gcm_bat_summary\">Вы ўключылі воблачны абмен паведамленнямі, але ў вас актыўная аптымізацыя энергаспажывання для microG Services. Каб атрымліваць push-паведамленні вам неабходна дазволіць прыкладанню працаваць у фонавым рэжыме.</string>\n    <string name=\"cond_gcm_bat_action\">Дазволіць работу ў фоне</string>\n    <string name=\"cond_perm_title\">Адсутнічаюць дазволы</string>\n    <string name=\"prefs_account\">Настройкі акаўнта</string>\n    <string name=\"prefs_account_privacy\">Персанальная інфармацыя і прыватнасць</string>\n    <string name=\"prefs_account_security\">Аўтарызацыя і бяспека</string>\n    <string name=\"pref_auth_trust_google_title\">Аўтаматычна ўваходзіць з Google</string>\n    <string name=\"pref_auth_trust_google_summary\">Калі параметр адключаны, то ў карыстальніка запытваецца дазвол на аўтарызацыю прыкладання ў Google. Некаторыя праграмы не змогуць выкарыстоўваць уліковы запіс Google, калі гэтая магчымасць адключаная.</string>\n    <string name=\"pref_auth_visible_title\">Доступ да прыкладанняў да акаўнтаў</string>\n    <string name=\"pref_auth_visible_summary\">Калі ўключана, усе прыкладанні на гэтай прыладзе змогуць бачыць адрасы электроннай пошты вашых уліковых запісаў Google без папярэдняга дазволу.</string>\n    <string name=\"pref_checkin_enable_summary\">Рэгіструе вашу прыладу ў сэрвісах Google і стварае унікальны ідэнтыфікатар прылады. MicroG выдаляе ўсе ідэнтыфікуючыя біты, акрамя імя вашага акаўнта Google.</string>\n    <string name=\"pref_device_registration_android_id\">Android ID</string>\n    <string name=\"checkin_not_registered\">Не зарэгістравана</string>\n    <string name=\"checkin_last_registration\">Апошняя рэгістрацыя: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"checkin_enable_switch\">Зарэгістраваць прыладу ў Google</string>\n    <string name=\"pref_info_status\">Стан</string>\n    <string name=\"pref_more_settings\">Яшчэ</string>\n    <string name=\"pref_add_account_title\">Уліковы запіс</string>\n    <string name=\"pref_add_account_summary\">Дадаць уліковы запіс Google</string>\n    <string name=\"pref_gcm_enable_mcs_summary\">Воблачны абмен паведамленнямі прадастаўляе push-паведамленні, якія выкарыстоўваюцца ў многіх у іншых прыкладаннях. Каб выкарыстоўваць іх, вы павінны ўключыць рэгістрацыю прылады.</string>\n    <string name=\"pref_gcm_heartbeat_title\">Інтэрвал злучэння воблачных паведамленняў</string>\n    <string name=\"pref_gcm_heartbeat_summary\">\"Інтэрвал у секундах, для выкарыстання сервераў Google. Павелічэнне гэтага ліку скароціць спажыванне батарэі, але можа прывесці да затрымак push-паведамленняў.\\nСастарэла, будзе зменена ў наступным рэлізе.\"</string>\n    <string name=\"pref_gcm_apps_title\">Прыкладанні, якія выкарыстоўваюць воблачны абмен паведамленнямі</string>\n    <string name=\"pref_gcm_apps_summary\">Спіс прыкладанняў, якія прывязаныя да воблачнага абмену паведамленнямі.</string>\n    <string name=\"pref_gcm_confirm_new_apps_title\">Пацверджваць новыя прыкладанні</string>\n    <string name=\"pref_gcm_confirm_new_apps_summary\">Пытаць дазвол перад прывязкай новых прыкладанняў для атрымання push-паведамленняў</string>\n    <string name=\"pref_gcm_ping_interval\">Інтэрвал праверкі: <xliff:g example=\"10 минут\">%1$s</xliff:g></string>\n    <string name=\"pref_about_title\">Аб сэрвісах microG</string>\n    <string name=\"pref_about_summary\">Інфармацыя аб версіі і выкарыстоўваныя бібліятэкі</string>\n    <string name=\"gcm_app_error_unregistering\">Не атрымалася адвязаць</string>\n    <string name=\"gcm_app_not_installed_anymore\">Прыкладанне больш не ўсталявана</string>\n    <string name=\"gcm_unregister_app\">Адвязаць</string>\n    <string name=\"gcm_not_registered\">Не прывязана</string>\n    <string name=\"gcm_no_message_yet\">Паведамленні яшчэ не былі атрыманы</string>\n    <string name=\"gcm_last_message_at\">Апошняе паведамленне: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_registered\">Прывязана</string>\n    <string name=\"gcm_registered_since\">Прывязана: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_unregister_confirm_title\">Адвязаць <xliff:g example=\"F-Droid\">%1$s</xliff:g>?</string>\n    <string name=\"gcm_unregister_confirm_message\">\"Некаторыя прыкладанне аўтаматычна не перапрывязваюцца і/або не даюць магчымасці зрабіць гэта ўручную. Такія праграмы могуць працаваць некарэктна пасля адвязкі.\\nПрацягнуць?\"</string>\n    <string name=\"gcm_unregister_after_deny_message\">Вы забаранілі push-паведамленні для прыкладання, якое ўжо прывязана.\\nВы жадаеце адвязаць яго зараз каб больш не атрымліваць ад яго push-паведамленняў?</string>\n    <string name=\"gcm_messages_counter\">Пведамленняў: <xliff:g example=\"123\">%1$d</xliff:g> (<xliff:g example=\"12345\">%2$d</xliff:g> байт)</string>\n    <string name=\"gcm_network_state_disconnected\">Аадключана</string>\n    <string name=\"gcm_network_state_connected\">Падключана <xliff:g example=\"2 hours ago\">%1$s</xliff:g></string>\n    <string name=\"gcm_enable_switch\">Прымаць push-паведамленні</string>\n    <string name=\"gcm_allow_app_popup\">Дазволіць <xliff:g example=\"F-Droid\">%1$s</xliff:g> рэгістравацца для атрымання push-паведамленняў?</string>\n    <string name=\"pref_push_app_allow_register_title\">Дазволіць рэгістрацыю</string>\n    <string name=\"pref_push_app_allow_register_summary\">Дазволіць прыкладанню рэгістравацца для атрымання push-паведамленняў.</string>\n    <string name=\"pref_push_app_wake_for_delivery_title\">Запускаць прыкладанне</string>\n    <string name=\"pref_push_app_wake_for_delivery_summary\">Запускаць прыкладанне ў фонавым рэжыме пры атрыманні ўваходнага push-паведамлення.</string>\n    <string name=\"prefcat_push_apps_title\">Прыкладанні выкарыстоўваюць push-паведамленні</string>\n    <string name=\"prefcat_push_apps_registered_title\">Зарэгістраваныя прыкладанні</string>\n    <string name=\"prefcat_push_apps_unregistered_title\">Незарэгістраваныя прыкладанні</string>\n    <string name=\"prefcat_push_networks_title\">Сеткі для прыёму push-паведамленняў</string>\n    <string name=\"safetynet_intro\">Google SafetyNet гэта сістэма сертыфікацыі прылады, якая гарантуе, што прылада карэктна абаронена і сумяшчальна з Android CTS. Пэўныя праграмы выкарыстоўваюць SafetyNet з меркаванняў бяспекі або ў якасці папярэдняй сістэмы абароны ад узлому.\\n\\nmicroG GmsCore змяшчае свабодную рэалізацыю SafetyNet, але афіцыйны сервер патрабуе, каб запыты былі падпісаны з дапамогай прапрыетарнай сістэмы DroidGuard.</string>\n    <string name=\"safetynet_enable_switch\">Дазволіць праверку статусу прылады</string>\n    <string name=\"pref_safetynet_test_title\">Праверка атэстацыі SafetyNet</string>\n    <string name=\"pref_recaptcha_test_title\">Тэст ReCAPTCHA</string>\n    <string name=\"pref_test_summary_passed\">Усе праверкі пройдзены</string>\n    <string name=\"pref_test_summary_failed\">: %s</string>\n    <string name=\"pref_test_summary_warn\">Папярэджанне: %s</string>\n    <string name=\"pref_test_summary_running\">Выкананне…</string>\n    <string name=\"pref_droidguard_operation_mode\">Рэжым работы</string>\n    <string name=\"prefcat_safetynet_apps_title\">Прыкладанні якія выкарыстоўваюць SafetyNet</string>\n    <string name=\"menu_clear_recent_requests\">Ачысціць нядаўнія запыты</string>\n    <string name=\"safetynet_last_run_at\">Апошняе выкарыстанне: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"profile_name_native\">Прылада</string>\n    <string name=\"profile_name_real\">Рэальны</string>\n    <string name=\"profile_name_user\">Карыстальніцкі: %s</string>\n    <string name=\"profile_name_auto\">Аўтаматычны: %s</string>\n    <string name=\"profile_name_system\">Сістэмны: %s</string>\n    <string name=\"pref_device_registration_import_custom_profile_title\">Імпарт профілю</string>\n    <string name=\"pref_device_registration_serial_title\">Серыйны нумар</string>\n    <string name=\"pref_device_registration_import_custom_profile_summary\">Імпартаваць карыстальніцкі профіль прылады з файла</string>\n    <string name=\"pref_device_registration_select_profile_title\">Абраць профіль</string>\n    <string name=\"pref_device_registration_device_profile_category\">Профіль прылады</string>\n    <string name=\"pref_safetynet_recent_copy_json\">Скапіяваць дадзеныя JSON JWS</string>\n    <string name=\"pref_safetynet_recent_advice\">Парада</string>\n    <string name=\"pref_safetynet_recent_eval_type\">Метад праверкі</string>\n    <string name=\"pref_safetynet_recent_response_status\">Статус адказу</string>\n    <string name=\"pref_safetynet_recent_cat_response\">Дадзеныя адказу</string>\n    <string name=\"pref_safetynet_recent_cat_request\">Дадзеныя запыту</string>\n    <string name=\"pref_safetynet_recent_nonce\">Аднаразовы код (Hex)</string>\n    <string name=\"pref_safetynet_recent_request_time\">Час запыту</string>\n    <string name=\"pref_safetynet_recent_request_type\">Тып запыту</string>\n    <string name=\"pref_safetynet_recent_cat_basic\">Асноўныя дадзеныя</string>\n    <string name=\"pref_safetynet_recent_token\">Токен</string>\n    <string name=\"pref_auth_include_android_id_title\">Адпраўка інфармацыі аб прыладзе</string>\n    <string name=\"pref_recaptcha_enterprise_test_title\">Тэст ReCAPTCHA Enterprise</string>\n    <string name=\"pref_droidguard_unsupported_summary\">Запуск DroidGuard не падтрымліваюцца на гэтай прыладзе. Сэрвісы SafetyNet могуць не працаваць.</string>\n    <string name=\"pref_safetynet_recent_recaptcha_summary\">ReCaptcha: %s</string>\n    <string name=\"pref_safetynet_recent_recaptcha_enterprise_summary\">ReCaptcha Enterprise: %s</string>\n    <string name=\"pref_safetynet_recent_copied\">Скапіявана ў буфер абмену!</string>\n    <string name=\"pref_safetynet_test_cts_failed\">Тэст CTS не пройдзены</string>\n    <string name=\"pref_safetynet_test_integrity_failed\">Праверка цэласнасці правалена</string>\n    <string name=\"pref_safetynet_test_no_result\">Няма выніку</string>\n    <string name=\"push_notifications_summary_off\">ВЫКЛ</string>\n    <string name=\"push_notifications_summary_automatic\">УКЛ / Аўтаматычна: %s</string>\n    <string name=\"push_notifications_summary_manual\">УКЛ / Уручную: %s</string>\n    <string name=\"push_notifications_summary_values_seconds\">%s секунд</string>\n    <string name=\"push_notifications_summary_values_minutes\">%s хвілін</string>\n    <string name=\"pref_vending_summary_licensing_off\">Апрацоўка ліцэнзій Выкл.</string>\n    <string name=\"pref_vending_summary_licensing_on\">Апрацоўка ліцэнзій Укл.</string>\n    <string name=\"pref_vending_license_enable_summary\">Некаторыя прыкладанні патрабуюць пацверджання таго, што вы набылі іх у Google Play. Па запыце прыкладання microG можа загрузіць пацверджанне пакупкі ад Google. Калі адключана або ўліковы запіс Google не дададзены, запыты на праверку ліцэнзіі ігнаруюцца.</string>\n    <string name=\"signin_confirm_title\">Дазволіць <xliff:g example=\"F-Droid\">%1$s</xliff:g> увайсці ў акаўнт</string>\n    <string name=\"feedback_disabled\">Адпраўка водгукаў у цяперашні час немагчымая</string>\n    <string name=\"signin_picker_subtitle\">каб працягнуць у <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"signin_subtext_sharing\">Каб працягнуць, microG падзеліцца вашым імем, адрасам электроннай пошты, і выявай профіля вашага акаўнта Google з <xliff:g example=\"F-Droid\">%1$s</xliff:g>.</string>\n    <string name=\"pref_auth_include_android_id_summary\">Калі адключана, запыты аўтэнтыфікацыі не будуць прывязаны да рэгістрацыі прылады, што дазваляе неаўтарызаваным прыладам ўваходзіць у ва ўліковы запіс, але гэта можа прывесці да непрадбачаных наступстваў.</string>\n    <string name=\"pref_safetynet_recent_uses\">Нядаўнія выкарыстання</string>\n    <string name=\"pref_safetynet_recent_attestation_summary\">Атэстацыя: %s</string>\n    <string name=\"pref_safetynet_test_integrity_cts_passed\">Тэсты цэласнасці і CTS пройдзены</string>\n    <string name=\"pref_safetynet_test_not_completed\">Яшчэ не завершаны</string>\n    <string name=\"pref_safetynet_test_invalid_json\">Няверны JSON</string>\n    <string name=\"pref_vending_licensing_enable_switch\">Апрацоўваць ліцэнзіі</string>\n    <string name=\"service_name_vending\">Сэрвісы Play Store</string>\n    <string name=\"signin_picker_title\">Выберыце ўліковы запіс</string>\n    <string name=\"signin_picker_add_account_label\">Дадаць іншы акаўнт</string>\n    <string name=\"signin_confirm_button_text\">Дазволіць і падзяліцца</string>\n    <string name=\"signin_subtext_policy\">Перш чым выкарыстоўваць гэта дадатак, праверце яго %1$s and %2$s.</string>\n    <string name=\"signin_subtext_policy_privacy\">палітыка прыватнасці</string>\n    <string name=\"signin_subtext_policy_terms\">умовы выкарыстання</string>\n    <string name=\"perm_gsf_read_gservices_label\">чытаць канфігурацыю сэрвісу Google</string>\n    <string name=\"pref_auth_strip_device_name_title\">Выдаляць імя прылады</string>\n    <string name=\"pref_auth_strip_device_name_summary\">Калі ўключана, запыты аўтэнтыфікацыі не будуць уключаць імя прылады, што можа дазволіць неаўтарызаваным прыладам ўваходзіць ва ўліковы запіс, але гэта можа мець непрадбачаныя наступствы.</string>\n    <string name=\"perm_car_info_label\">Інфармацыя пра машыну</string>\n    <string name=\"perm_car_fuel_description\">Атрыманне доступу да інфармацыі аб узроўні паліва вашага аўтамабіля</string>\n    <string name=\"perm_car_mileage_description\">Атрыманне доступу да інфармацыі аб прабегу вашага аўтамабіля</string>\n    <string name=\"perm_car_vendor_extension_label\">Канал пастаўшчыка аўтамабіля</string>\n    <string name=\"perm_car_speed_label\">Хуткасць машыны</string>\n    <string name=\"perm_car_speed_description\">Атрыманне доступу да хуткасці вашага аўтамабіля</string>\n    <string name=\"perm_car_info_description\">Атрыманне доступу да інфармацыі аб вашым аўтамабілі</string>\n    <string name=\"perm_car_fuel_label\">Узровень паліва ў машыне</string>\n    <string name=\"perm_car_mileage_label\">Прабег аўтамабіля</string>\n    <string name=\"perm_car_vendor_extension_description\">Атрыманне доступу да канала пастаўшчыка вашага аўтамабіля для абмену інфармацыяй, якая датычыцца канкрэтнага аўтамабіля</string>\n    <string name=\"backup_disabled\">Рэзервовае капіраванне недаступна</string>\n    <string name=\"pref_accounts_title\">Акаўнты Google</string>\n    <string name=\"prefcat_accounts_current_accounts_title\">Акаўнты</string>\n    <string name=\"pref_accounts_summary\">Даданне і кіраванне ўліковымі запісамі Google</string>\n    <string name=\"prefcat_accounts_settings_title\">Налады</string>\n    <string name=\"pref_vending_billing_note_experimental\">Гэтая функцыя эксперыментальная і можа прывесці да страты грошай.</string>\n    <string name=\"pref_vending_licensing_category\">Ліцэнзаванне Google Play</string>\n    <string name=\"pref_vending_billing_category\">Плацяжы Google Play</string>\n    <string name=\"pref_vending_billing_enable_summary\">Калі ўключана, некаторыя прыкладанні змогуць здзяйсняць пакупкі ці падпіскі праз службу Google Play Billing.</string>\n    <string name=\"pref_vending_billing_enable_switch\">Апрацоўваць плацяжы</string>\n    <string name=\"pref_vending_billing_note_licensing\">Некаторым прыкладанням можа спатрэбіцца, каб вы ўключылі праверку ліцэнзіі для праверкі вашых плацяжоў.</string>\n    <string name=\"credentials_assisted_confirmation_header\">Уваход у сістэму</string>\n    <string name=\"credentials_assisted_continue_as_user_button_label\">Працягнуць як %1$s</string>\n    <string name=\"credentials_assisted_signin_consent_header\">Увайсці як %1$s</string>\n    <string name=\"credentials_assisted_signin_description\">Вы можаце кіраваць аўтарызацыяй у сваіх уліковых запісах Google.</string>\n    <string name=\"credentials_assisted_choose_account_label\">Абярыце акаўнт</string>\n    <string name=\"credentials_assisted_choose_account_subtitle\">каб працягваць карыстацца %1$s</string>\n    <string name=\"credentials_assisted_signin_button_text_long\">Уваход з акаўнтам Google</string>\n    <string name=\"credentials_assisted_cancel\">Адмена</string>\n    <string name=\"credentials_assisted_continue\">Працягнуць</string>\n    <string name=\"credentials_assisted_sign_back_title\">Зноў увайсьці ў %1$s з акаўнтам Google</string>\n    <string name=\"credentials_assisted_signin_consent\">Калі працягнеце, Google прадаставіць %1$s ваша імя, адрас электроннай пошты і фатаграфію профіля. Азнаёмцеся з палітыкай прыватнасці і з умовамі выкарыстання %1$s.</string>\n    <string name=\"auth_package_override_request_title\">Дазволіць <b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> прывілеяваны доступ да <xliff:g example=\"account@example.com\">%2$s</xliff:g>\\?</string>\n    <string name=\"auth_package_override_request_message\"><b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> спрабуе атрымаць доступ да ўліковага запісу пад выглядам <b><xliff:g example=\"F-Droid\">%2$s</xliff:g> ад <xliff:g example=\"F-Droid Inc.\">%3$s</xliff:g></b>. Гэта дасць прывілеяваны доступ да вашага ўліковага запісу.</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_switch\">Аўтаматычна дабаўляць бясплатныя прыкладанні ў бібліятэку</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_summary\">Бясплатныя прыкладанні могуць правяраць, ці загружаліся яны з Google Play. Аўтаматычнае даданне бясплатных дадаткаў у бібліятэку вашага акаўнта дазваляе заўсёды праходзіць праверку для ўсіх даступных вам бясплатных прыкладанняў.</string>\n    <string name=\"pref_vending_split_install_switch\">Уключыць спампоўванне пэўных функцый прыкладання па патрабаванні.</string>\n    <string name=\"pref_vending_licensing_split_install_summary\">Выкарыстоўваючы падзеленую ўстаноўку, прыкладанне будзе спампоўваць пэўныя модулі функцый у залежнасці ад бягучага выкарыстання.</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-bn/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n</resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-bn/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n</resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-bn/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n</resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-ca/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"permission_service_all_label\">Tots els serveis de Google</string>\n    <string name=\"permission_service_all_description\">Permet que l\\'aplicació accedeixi als serveis de Google amb qualsevol compte de Google associat.</string>\n    <string name=\"permission_service_android_label\">Serveis d\\'Android</string>\n    <string name=\"permission_service_android_description\">Permet que l\\'aplicació accedeixi als serveis d\\'Android amb qualsevol compte de Google associat.</string>\n    <string name=\"permission_service_adsense_label\">AdSense</string>\n    <string name=\"permission_service_adsense_description\">Permet que l\\'aplicació accedeixi a AdSense amb qualsevol compte de Google associat.</string>\n    <string name=\"permission_service_adwords_label\">AdWords</string>\n    <string name=\"permission_service_adwords_description\">Permet que l\\'aplicació accedeixi a AdWords amb qualsevol compte de Google associat.</string>\n    <string name=\"permission_service_ah_label\">Motor d\\'aplicacions de Google</string>\n    <string name=\"permission_service_ah_description\">Permet que l\\'aplicació accedeixi al motor d\\'aplicacions de Google amb qualsevol compte de Google associat.</string>\n    <string name=\"permission_service_blogger_label\">Blogger</string>\n    <string name=\"permission_service_blogger_description\">Permet que l\\'aplicació accedeixi a Blogger amb qualsevol compte de Google associat.</string>\n    <string name=\"permission_service_cl_label\">Google Calendar</string>\n    <string name=\"permission_service_cl_description\">Permet que l\\'aplicació accedeixi al Google Calendar amb qualsevol compte de Google associat.</string>\n    <string name=\"permission_service_cp_label\">Contactes</string>\n    <string name=\"permission_service_finance_label\">Google Finance</string>\n    <string name=\"permission_service_finance_description\">Permet que l\\'aplicació accedeixi a Google Finance amb qualsevol compte de Google associat.</string>\n    <string name=\"permission_service_gbase_label\">Google Base</string>\n    <string name=\"permission_service_gbase_description\">Permet que l\\'aplicació accedeixi a Google Base amb qualsevol compte de Google associat.</string>\n    <string name=\"permission_service_grandcentral_label\">Google Voice</string>\n    <string name=\"permission_service_grandcentral_description\">Permet que l\\'aplicació accedeixi a Google Voice amb qualsevol compte de Google associat.</string>\n    <string name=\"permission_service_groups2_label\">Google Groups</string>\n    <string name=\"permission_service_groups2_description\">Permet que l\\'aplicació accedeixi a Google Groups amb qualsevol compte de Google associat.</string>\n    <string name=\"permission_service_health_label\">Google Health</string>\n    <string name=\"permission_service_health_description\">Permet que l\\'aplicació accedeixi a Google Health amb qualsevol compte de Google associat.</string>\n    <string name=\"permission_service_ig_label\">iGoogle</string>\n    <string name=\"permission_service_ig_description\">Permet que l\\'aplicació accedeixi a iGoogle amb qualsevol compte de Google associat.</string>\n    <string name=\"permission_service_jotspot_label\">JotSpot</string>\n    <string name=\"permission_service_jotspot_description\">Permet que l\\'aplicació accedeixi a JotSpot amb qualsevol compte de Google associat.</string>\n    <string name=\"permission_service_knol_label\">Knol</string>\n    <string name=\"permission_service_knol_description\">Permet que l\\'aplicació accedeixi a Knol amb qualsevol compte de Google associat.</string>\n    <string name=\"permission_service_cp_description\">Permet l\\'accés a contactes amb qualsevol compte de Google associat.</string>\n    <string name=\"permission_service_dodgeball_label\">Dodgeball</string>\n    <string name=\"permission_service_dodgeball_description\">Permet que l\\'aplicació accedeixi a Dodgeball amb qualsevol compte de Google associat.</string>\n    <string name=\"permission_service_lh2_label\">Picasa Web Albums</string>\n    <string name=\"permission_service_lh2_description\">Permet a l\\'aplicació accedir a Picasa Web Albums amb qualsevol compte de Google associat.</string>\n    <string name=\"permission_service_local_label\">Google Maps</string>\n    <string name=\"permission_service_local_description\">Permet que l\\'aplicació accedeixi a Google Maps amb qualsevol compte de Google associat.</string>\n    <string name=\"permission_service_mail_label\">Google Mail</string>\n    <string name=\"permission_service_mail_description\">Permet que l\\'aplicació accedeixi a Google Mail amb qualsevol compte de Google associat.</string>\n    <string name=\"permission_service_news_label\">Google News</string>\n    <string name=\"permission_service_news_description\">Permet que l\\'aplicació accedeixi a Google News amb qualsevol compte de Google associat.</string>\n    <string name=\"permission_service_notebook_label\">Google Notebook</string>\n    <string name=\"permission_service_notebook_description\">Permet que l\\'aplicació accedeixi a Google Notebook amb qualsevol compte de Google associat.</string>\n    <string name=\"permission_service_orkut_label\">Orkut</string>\n    <string name=\"permission_service_orkut_description\">Permet que l\\'aplicació accedeixi a Orkut amb qualsevol compte de Google associat.</string>\n    <string name=\"permission_service_print_label\">Google Book Search</string>\n    <string name=\"permission_service_print_description\">Permet que l\\'aplicació accedeixi a Google Book Search amb qualsevol compte de Google associat.</string>\n    <string name=\"permission_service_sierra_label\">Comptes de Google Checkout</string>\n    <string name=\"permission_service_sierra_description\">Permet a l\\'aplicació accedir als comptes de Google Checkout amb qualsevol compte de Google associat.</string>\n    <string name=\"permission_service_sierraqa_label\">Comptes de Google Checkout QA</string>\n    <string name=\"permission_service_sierraqa_description\">Permet que l\\'aplicació accedeixi als comptes de Google Checkout QA amb qualsevol compte de Google associat.</string>\n    <string name=\"permission_service_sierrasandbox_label\">Comptes de Google Checkout Sandbox</string>\n    <string name=\"permission_service_sierrasandbox_description\">Permet que l\\'aplicació accedeixi als comptes de Google Checkout Sandbox amb qualsevol compte de Google associat.</string>\n    <string name=\"permission_service_sitemaps_label\">Google Webmaster Tools</string>\n    <string name=\"permission_service_sitemaps_description\">Permet que l\\'aplicació accedeixi a Google Webmaster Tools amb qualsevol compte de Google associat.</string>\n    <string name=\"permission_service_speech_label\">Cerca de veu</string>\n    <string name=\"permission_service_speech_description\">Permet que l\\'aplicació accedeixi a la cerca de veu amb qualsevol compte de Google associat.</string>\n    <string name=\"permission_service_speechpersonalization_label\">Reconeixement de veu personalitzat</string>\n    <string name=\"permission_service_speechpersonalization_description\">Permet que l\\'aplicació accedeixi al reconeixement de veu personalitzat amb qualsevol compte de Google associat.</string>\n    <string name=\"permission_service_talk_label\">Google Talk</string>\n    <string name=\"permission_service_talk_description\">Permet que l\\'aplicació accedeixi a Google Talk amb qualsevol compte de Google associat.</string>\n    <string name=\"permission_service_wifi_label\">Google Wi-Fi</string>\n    <string name=\"permission_service_wifi_description\">Permet que l\\'aplicació accedeixi a Google Wi-Fi amb qualsevol compte de Google associat.</string>\n    <string name=\"permission_service_wise_label\">Google Spreadsheets</string>\n    <string name=\"permission_service_wise_description\">Permet que l\\'aplicació accedeixi a Google Spreadsheets amb qualsevol compte de Google associat.</string>\n    <string name=\"permission_service_writely_label\">Google Docs</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_androidpublisher\">Accés al desenvolupador d\\'Android de Google Play</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appengine.admin\">Àmbit d\\'administrador d\\'App Engine.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.migration\">Accés de lectura i escriptura a l\\'API de migració de grups.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.settings\">Veure i gestionar la configuració d\\'un grup de Google Apps</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.licensing\">Accés de lectura i escriptura a l\\'API del gestor de llicències.</string>\n    <string name=\"permission_service_writely_description\">Permet que l\\'aplicació accedeixi a Google Docs amb qualsevol compte de Google associat.</string>\n    <string name=\"permission_service_youtube_label\">YouTube</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-ca/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <plurals name=\"pref_unifiednlp_summary\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> backend configurat</item>\n        <item quantity=\"many\"><xliff:g example=\"3\">%1$d</xliff:g> backends configurats</item>\n        <item quantity=\"other\"><xliff:g example=\"3\">%1$d</xliff:g> backends configurats</item>\n    </plurals>\n    <plurals name=\"gcm_registered_apps_counter\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> aplicació registrada</item>\n        <item quantity=\"many\"><xliff:g example=\"123\">%1$d</xliff:g> aplicacions registrades</item>\n        <item quantity=\"other\"><xliff:g example=\"123\">%1$d</xliff:g> aplicacions registrades</item>\n    </plurals>\n    <plurals name=\"cond_perm_summary\">\n        <item quantity=\"one\">Un permís requerit per al correcte funcionament dels serveis microG no s\\'ha garantit.</item>\n        <item quantity=\"many\">Permisos requerits per al correcte funcionament dels serveis microG no s\\'han garantit.</item>\n        <item quantity=\"other\">Permisos requerits per al correcte funcionament dels serveis microG no s\\'han garantit.</item>\n    </plurals>\n    <plurals name=\"cond_perm_action\">\n        <item quantity=\"one\">Sol·licita el permís que falta</item>\n        <item quantity=\"many\">Sol·licita els permisos que falten</item>\n        <item quantity=\"other\">Sol·licita els permisos que falten</item>\n    </plurals>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-ca/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=\"gms_app_name\">Serveis del microG</string>\n    <string name=\"limited_services_app_name\">Serveis limitats del microG</string>\n    <string name=\"gms_settings_name\">Configuració del microG</string>\n    <string name=\"gms_settings_summary\">Configurar els serveis del microG.</string>\n    <string name=\"just_a_sec\">Un segon…</string>\n    <string name=\"google_account_label\">Google</string>\n    <string name=\"ask_permission_tos\">En continuar, permeteu que aquesta aplicació i Google utilitzin la vostra informació d\\'acord amb els seus respectius termes de servei i polítiques de privacitat.</string>\n    <string name=\"ask_scope_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> vol:</string>\n    <string name=\"ask_service_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> vol utilitzar:</string>\n    <string name=\"account_manager_title\">Gestor de comptes de Google</string>\n    <string name=\"sorry\">Ho sentim…</string>\n    <string name=\"auth_before_connect\">Una aplicació del dispositiu intenta iniciar sessió en un compte de Google.\\n\\nSi ha estat intencionat, utilitzeu el botó <b>Iniciar sessió</b> per anar a la pàgina d\\'inici de sessió de Google. Si no, premeu <b>Cancel·lar</b> per tornar a l\\'aplicació que ha fet mostrar-se aquest quadre de diàleg.</string>\n    <string name=\"auth_sign_in\">Iniciar sessió</string>\n    <string name=\"auth_connecting\">El vostre dispositiu s\\'està connectant als servidors de Google per iniciar la sessió.\\n\\nAixò pot trigar uns segons.</string>\n    <string name=\"no_network_error_desc\">No teniu connexió de xarxa.\\n\\nPot ser un problema temporal o que el vostre dispositiu Android no estigui configurat per als serveis de dades. Torneu-ho a provar quan estigueu connectat a una xarxa mòbil o connecteu-vos a una xarxa Wi-Fi.</string>\n    <string name=\"deny\">Denegar</string>\n    <string name=\"auth_notification_title\">Es requereix autenticació</string>\n    <string name=\"auth_notification_content\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> necessita la vostra autorització per accedir al compte de Google.</string>\n    <string name=\"auth_package_override_request_title\">Permetre a <xliff:g example=\"F-Droid\">%1$s</xliff:g> l\\'accés privilegiat a <xliff:g example=\"account@example.com\">%2$s</xliff:g>\\?</string>\n    <string name=\"auth_package_override_request_message\"><b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> vol accedir al teu compte com si fos <b><xliff:g example=\"F-Droid\">%2$s</xliff:g> de <xliff:g example=\"F-Droid Inc.\">%3$s</xliff:g></b>. Això podria concedir-li accés privilegiat al vostre compte.</string>\n    <string name=\"auth_action_notification_channel_name\">Alertes del compte de Google</string>\n    <string name=\"auth_action_notification_channel_description\">Informa quan un dels vostres comptes de Google requereix una configuració addicional abans de poder-lo utilitzar o quan un compte és incompatible amb microG.</string>\n    <string name=\"auth_action_notification_title\">Es requereix una acció al compte</string>\n    <string name=\"auth_action_notification_content\">El vostre compte de Google necessita configuració addicional.</string>\n    <string name=\"auth_action_reauth_notification_title\">Es requereix una acció al compte</string>\n    <string name=\"auth_action_activity_header\">Acabeu de configurar el vostre compte de Google</string>\n    <string name=\"auth_action_activity_explanation\">Completeu els passos següents per poder utilitzar el vostre compte de Google %s en aquest dispositiu.</string>\n    <string name=\"auth_action_step_enable_checkin\">Activa el registre de dispositius</string>\n    <string name=\"auth_action_step_enable_checkin_description\">El dispositiu s\\'ha de registrar a Google almenys una vegada.\\n\\nPodeu desactivar el registre de dispositius de Google en completar la configuració del compte.</string>\n    <string name=\"auth_action_step_enable_gcm\">Activa la missatgeria al núvol</string>\n    <string name=\"auth_action_step_enable_gcm_description\">Podeu desactivar la missatgeria al núvol en completar la configuració del compte.</string>\n    <string name=\"auth_action_step_allow_microg_gcm\">Permet la missatgeria al núvol per a microG</string>\n    <string name=\"auth_general_error_desc\">Hi ha un problema en comunicar-se amb els servidors de Google.\\n\\nProveu-ho més tard.</string>\n    <string name=\"auth_finalize\">El vostre dispositiu està en contacte amb Google per desar informació al vostre compte.\\n\\nAixò por trigar un parell de minuts.</string>\n    <string name=\"allow\">Permet</string>\n    <string name=\"auth_action_step_allow_microg_gcm_description\">Segons les vostres preferències, microG necessita el vostre permís abans de poder-se registrar en la missatgeria al núvol.</string>\n    <string name=\"auth_action_step_enable_lockscreen\">Configureu el bloqueig de pantalla segur</string>\n    <string name=\"auth_action_step_enable_lockscreen_description\">El vostre compte de Google el gestiona el vostre lloc de treball o institució educativa. El vostre administrador ha decidit que els dispositius necessiten un bloqueig de pantalla segur abans de poder accedir a les dades del compte.\\n\\nSi us plau, configureu una contrasenya, un PIN o un patró de bloqueig de pantalla.</string>\n    <string name=\"auth_action_step_perform_content_description\">Feu clic per donar el pas</string>\n    <string name=\"auth_action_step_completed_content_description\">Pas completat</string>\n    <string name=\"auth_action_activity_finish\">Finalitzar</string>\n    <string name=\"signin_picker_title\">Trieu un compte</string>\n    <string name=\"signin_picker_subtitle\">per continuar a <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"signin_picker_add_account_label\">Afegiu altre compte</string>\n    <string name=\"signin_confirm_title\">Permetre que inicieu la sessió a <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"signin_confirm_button_text\">Permetre i compartir</string>\n    <string name=\"signin_subtext_sharing\">Per continuar, microG compartirà el nom, l\\'adreça de correu electrònic i la imatge de perfil del vostre compte de Google amb <xliff:g example=\"F-Droid\">%1$s</xliff:g>.</string>\n    <string name=\"signin_subtext_policy\">Abans d\\'utilitzar aquesta aplicació, reviseu la seua %1$s i %2$s.</string>\n    <string name=\"signin_subtext_policy_privacy\">política de privacitat</string>\n    <string name=\"signin_subtext_policy_terms\">condicions del servei</string>\n    <string name=\"perm_status_broadcast_label\">escoltar les emissions de l\\'estat intern</string>\n    <string name=\"perm_gsf_read_gservices_label\">llegiu la configuració del servei Google</string>\n    <string name=\"perm_c2dm_receive_label\">escolteu missatges C2DM</string>\n    <string name=\"perm_c2dm_send_label\">envieu missatges C2DM a altres aplicacions</string>\n    <string name=\"perm_gtalk_svc_label\">intercanvieu missatges i rebeu notificacions de sincronització des dels servidors de Google</string>\n    <string name=\"perm_extended_access_label\">Accés ampliat als serveis de Google</string>\n    <string name=\"perm_provision_label\">provisió de serveis microG</string>\n    <string name=\"perm_provision_description\">Permet que l\\'aplicació configuri els serveis de microG sense interacció de l\\'usuari</string>\n    <string name=\"perm_car_speed_label\">Velocitat del cotxe</string>\n    <string name=\"perm_car_speed_description\">Accediu a la velocitat del vostre cotxe</string>\n    <string name=\"perm_car_info_label\">Informació del cotxe</string>\n    <string name=\"perm_car_info_description\">Accediu a la informació del vostre cotxe</string>\n    <string name=\"perm_car_fuel_label\">Nivell de combustible del cotxe</string>\n    <string name=\"perm_car_fuel_description\">Accediu a la informació del nivell de combustible del vostre cotxe</string>\n    <string name=\"perm_car_mileage_label\">Quilometratge</string>\n    <string name=\"perm_car_mileage_description\">Accediu a la informació de quilometratge del vostre cotxe</string>\n    <string name=\"perm_car_vendor_extension_label\">Canal de proveïdors automobilístics</string>\n    <string name=\"perm_car_vendor_extension_description\">Accediu al canal del proveïdor del vostre cotxe per intercanviar informació específica del vehicle</string>\n    <string name=\"network_type_wifi\">Wi-Fi</string>\n    <string name=\"network_type_roaming\">Itinerància</string>\n    <string name=\"network_type_other\">Altres xarxes</string>\n    <string name=\"self_check_cat_fake_sig\">Suport per a la falsificació de signatures</string>\n    <string name=\"self_check_cat_gms_packages\">Paquets instal·lats</string>\n    <string name=\"self_check_cat_system\">Sistema</string>\n    <string name=\"service_name_checkin\">Registre del dispositiu a Google</string>\n    <string name=\"service_name_mcs\">Missatgeria al núvol</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-cs/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"permission_service_all_label\">Všechny služby Google</string>\n    <string name=\"permission_service_android_label\">Služby Android</string>\n    <string name=\"permission_service_adwords_label\">AdWords</string>\n    <string name=\"permission_service_ah_label\">Google App Engine</string>\n    <string name=\"permission_service_ah_description\">Povolí aplikaci přístup ke službe Google App Engine skrze jakýkoli připojený účet Google.</string>\n    <string name=\"permission_service_adsense_description\">Povolí aplikaci přístup ke službě AdSense skrze jakýkoli připojený účet Google.</string>\n    <string name=\"permission_service_adwords_description\">Povolí aplikaci přístup ke službě AdWords skrze jakýkoli připojený účet Google.</string>\n    <string name=\"permission_service_cl_description\">Povolí aplikaci přístup ke Kalendáři Google skrze jakýkoli připojený účet Google.</string>\n    <string name=\"permission_service_cp_label\">Kontakty</string>\n    <string name=\"permission_service_cp_description\">Povolí aplikaci přístup ke kontaktům skrze jakýkoli připojený účet Google.</string>\n    <string name=\"permission_service_dodgeball_label\">Dodgeball</string>\n    <string name=\"permission_service_dodgeball_description\">Povolí aplikaci přístup ke službě Dodgeball skrze jakýkoli připojený účet Google.</string>\n    <string name=\"permission_service_finance_label\">Google Finance</string>\n    <string name=\"permission_service_finance_description\">Povolí aplikaci přístup ke službě Google Finance skrze jakýkoli připojený účet Google.</string>\n    <string name=\"permission_service_gbase_label\">Google Base</string>\n    <string name=\"permission_service_gbase_description\">Povolí aplikaci přístup ke službě Google Base skrze jakýkoli připojený účet Google.</string>\n    <string name=\"permission_service_grandcentral_label\">Google Voice</string>\n    <string name=\"permission_service_grandcentral_description\">Povolí aplikaci přístup ke službě Google Voice skrze jakýkoli připojený účet Google.</string>\n    <string name=\"permission_service_groups2_label\">Skupiny Google</string>\n    <string name=\"permission_service_groups2_description\">Povolí aplikaci přístup ke Skupinám Google skrze jakýkoli připojený účet Google.</string>\n    <string name=\"permission_service_health_label\">Google Health</string>\n    <string name=\"permission_service_jotspot_label\">JotSpot</string>\n    <string name=\"permission_service_jotspot_description\">Povolí aplikaci přístup ke službě JotSpot skrze jakýkoli připojený účet Google.</string>\n    <string name=\"permission_service_knol_label\">Knol</string>\n    <string name=\"permission_service_all_description\">Povolí aplikaci přístup ke všem službám Google skrze jakýkoli připojený účet Google.</string>\n    <string name=\"permission_service_android_description\">Povolí aplikaci přístup ke službám systému Android skrze jakýkoli připojený účet Google.</string>\n    <string name=\"permission_service_blogger_label\">Blogger</string>\n    <string name=\"permission_service_blogger_description\">Povolí aplikaci přístup ke službě Blogger skrze jakýkoli připojený účet Google.</string>\n    <string name=\"permission_service_adsense_label\">AdSense</string>\n    <string name=\"permission_service_cl_label\">Kalendář Google</string>\n    <string name=\"permission_service_health_description\">Povolí aplikaci přístup ke službě Google Health skrze jakýkoli připojený účet Google.</string>\n    <string name=\"permission_service_ig_description\">Povolí aplikaci přístup ke službě iGoogle skrze jakýkoli připojený účet Google.</string>\n    <string name=\"permission_service_ig_label\">iGoogle</string>\n    <string name=\"permission_service_knol_description\">Povolí aplikaci přístup ke službě Knol skrze jakýkoli připojený účet Google.</string>\n    <string name=\"permission_service_lh2_label\">Picasa</string>\n    <string name=\"permission_service_lh2_description\">Povolí aplikaci přístup ke službě Picasa skrze jakýkoli připojený účet Google.</string>\n    <string name=\"permission_service_local_label\">Mapy Google</string>\n    <string name=\"permission_service_local_description\">Povolí aplikaci přístup k Mapám Google skrze jakýkoli připojený účet Google.</string>\n    <string name=\"permission_service_news_label\">Zprávy Google</string>\n    <string name=\"permission_service_notebook_description\">Povolí aplikaci přístup k Poznámkovému bloku Google skrze jakýkoli připojený účet Google.</string>\n    <string name=\"permission_service_orkut_label\">Orkut</string>\n    <string name=\"permission_service_orkut_description\">Povolí aplikaci přístup ke službě Orkut skrze jakýkoli připojený účet Google.</string>\n    <string name=\"permission_service_print_label\">Knihy Google</string>\n    <string name=\"permission_service_mail_label\">Gmail</string>\n    <string name=\"permission_service_mail_description\">Povolí aplikaci přístup ke službě Gmail skrze jakýkoli připojený účet Google.</string>\n    <string name=\"permission_service_print_description\">Povolí aplikaci přístup ke Knihám Google skrze jakýkoli připojený účet Google.</string>\n    <string name=\"permission_service_sierra_label\">Účty Google Checkout</string>\n    <string name=\"permission_service_sierra_description\">Povolí aplikaci přístup k účtům Google Checkout skrze jakýkoli připojený účet Google.</string>\n    <string name=\"permission_service_sierraqa_label\">Účty Google Checkout QA</string>\n    <string name=\"permission_service_sierraqa_description\">Povolí aplikaci přístup k účtům Google Checkout QA skrze jakýkoli připojený účet Google.</string>\n    <string name=\"permission_service_sierrasandbox_label\">Účty Google Checkout Sandbox</string>\n    <string name=\"permission_service_sierrasandbox_description\">Povolí aplikaci přístup k účtům Google Checkout Sandbox skrze jakýkoli připojený účet Google.</string>\n    <string name=\"permission_service_sitemaps_label\">Google Search Console</string>\n    <string name=\"permission_service_sitemaps_description\">Povolí aplikaci přístup ke službě Google Search Console skrze jakýkoli připojený účet Google.</string>\n    <string name=\"permission_service_speech_label\">Hlasové vyhledávání</string>\n    <string name=\"permission_service_speech_description\">Povolí aplikaci přístup ke Hlasovému vyhledávání skrze jakýkoli připojený účet Google.</string>\n    <string name=\"permission_service_speechpersonalization_label\">Přizpůsobené rozpoznávání řeči</string>\n    <string name=\"permission_service_speechpersonalization_description\">Povolí aplikaci přístup k Přizpůsobenému rozpoznávání řeči skrze jakýkoli připojený účet Google.</string>\n    <string name=\"permission_service_talk_description\">Povolí aplikaci přístup ke službě Google Talk skrze jakýkoli připojený účet Google.</string>\n    <string name=\"permission_service_wise_label\">Tabulky Google</string>\n    <string name=\"permission_service_wise_description\">Povolí aplikaci přístup k Tabulkám Google skrze jakýkoli připojený účet Google.</string>\n    <string name=\"permission_service_youtube_label\">YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.buyer\">Správa nastavení vašeho účtu kupujícího na Ad Exchange</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller.readonly\">Zobrazení vašich dat na Ad Exchange</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller\">Zobrazení a správa vašich dat na Ad Exchange</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsensehost\">Zobrazení a správa vašich hostitelských dat AdSense a připojených účtů</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense.readonly\">Zobrazení vašich dat AdSense</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense\">Zobrazení a správa vašich dat AdSense</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics\">Zobrazení a správa vašich dat Google Analytics</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_androidpublisher\">Přístup ke službě Google Play Console</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appengine.admin\">Administrátorská oprávnění služby App Engine.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.migration\">Přístup ke čtení a zápisu v migračním API Skupin.</string>\n    <string name=\"permission_service_news_description\">Povolí aplikaci přístup ke Zprávám Google skrze jakýkoli připojený účet Google.</string>\n    <string name=\"permission_service_notebook_label\">Poznámkový blok Google</string>\n    <string name=\"permission_service_YouTubeUser_label\">Uživatelská jména YouTube</string>\n    <string name=\"permission_service_talk_label\">Google Talk</string>\n    <string name=\"permission_service_wifi_description\">Povolí aplikaci přístup ke službě Google Wi-Fi skrze jakýkoli připojený účet Google.</string>\n    <string name=\"permission_service_wifi_label\">Google Wi-Fi</string>\n    <string name=\"permission_service_writely_label\">Dokumenty Google</string>\n    <string name=\"permission_service_writely_description\">Povolí aplikaci přístup k Dokumentům Google skrze jakýkoli připojený účet Google.</string>\n    <string name=\"permission_service_youtube_description\">Povolí aplikaci přístup ke službě YouTube skrze jakýkoli připojený účet Google.</string>\n    <string name=\"permission_service_YouTubeUser_description\">Povolí aplikaci přístup k uživatelským jménům YouTube používaným s jakýmkoli připojeným účtem Google.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_activity\">Zobrazení historie vašich Aplikací Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics.readonly\">Zobrazení vašich dat Google Analytics</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.settings\">Zobrazení a správa nastavení skupiny Aplikací Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.licensing\">Přístup ke čtení/zápisu do License Manager API.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order\">Pro správce a uživatele, kteří jsou přeprodejci, přístup ke čtení/zápisu při testování v sandboxu API nebo přístup ke čtení/zápisu při přímém volání operace API.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order.readonly\">Kromě celkového rozsahu OAuth pro čtení a zápis použít při načítání dat zákazníka také rozsah OAuth pouze pro čtení.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps_reporting_audit.readonly\">Přístup k Admin Audit API ReadOnly</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appstate\">Rozsah pro použití služby App State.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery.readonly\">Zobrazit vaše údaje ve službě Google BigQuery</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery\">Zobrazení a správa vašich dat ve službě Google BigQuery</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger\">Správa vašeho účtu Blogger</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger.readonly\">Zobrazení vašeho účtu Blogger</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_books\">Správa vašich knih</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar\">Správa vašich kalendářů</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar.readonly\">Zobrazení vašich kalendářů</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_cloudprint\">Zobrazení a správa vašich dat ve službě Google Cloud Print</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute.readonly\">Zobrazení vašich zdrojů ve službě Google Compute Engine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute\">Zobrazení a správa vašich zdrojů ve službě Google Compute Engine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate.readonly\">Zobrazení vašich úloh ve službě Google Coordinate</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate\">Zobrazení a správa vašich úloh ve službě Google Maps Coordinate</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.full_control\">Správa vašich dat a oprávnění ve službě Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_only\">Zobrazení vašich dat ve službě Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_dfareporting\">Zobrazení a správa hlášení ve službě DoubleClick for Advertisers</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.apps.readonly\">Zobrazení vašich aplikací v Disku Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.file\">Zobrazení a správa souborů v Disku Google, které jste otevřili nebo vytvořili v této aplikaci</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.install\">Zvláštní rozsah používaný pro umožnění uživatelům schválit instalaci aplikace</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.readonly\">Zobrazení souborů a dokumentů ve vašem Disku Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.scripts\">Správa chování vašich skriptů ve službě Google Apps Script</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase.readonly\">Zobrazení vašeho účtu Freebase</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase\">Přihlásit se do služby Freebase s vaším účtem</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables\">Správa vašich Fusion Tables</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables.readonly\">Zobrazení vašich Fusion Tables</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_games\">Rozsah pro přístup k datům z Her Google Play.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan\">Správa vašich dat GAN</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan.readonly\">Zobrazení vašich dat GAN</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.compose\">Vytváření, čtení, úprava a mazání návrhů. Odesílání zpráv a návrhů.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.modify\">Všechny operace čtení/zápisu mimo okamžitého, permanentního smazání vláken a zpráv, což by obešlo Koš.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.readonly\">Číst všechny zdroje a jejich metadata – žádné operace zápisu.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.city\">Správa vaší polohy na úrovni města a historie polohy</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.city\">Správa vaší polohy na úrovni města</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine\">Správa a zobrazení vašich dat ve službě Google Maps Platform</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine.readonly\">Zobrazení vašich dat ve službě Google Maps Platform</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mobilemaps.firstparty\">Zobrazení a správa vašich Map Google pro mobilní zážitek</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut\">Správa vaší aktivity ve službě Orkut</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut.readonly\">Zobrazení vašich dat ve službě Orkut</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.login\">Znát vaše jméno, základní informace a seznam lidí, se kterými jste se spojili na Google+</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.me\">Znát, kdo jste na Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_shoppingapi\">Zobrazení vašich produktových dat</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification.verify_only\">Správa vašich nových ověřování webů s Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_structuredcontent\">Přístup ke čtení/zápisu ve službě Shopping Content API.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue.consumer\">Spotřebovávat úkoly z vaší fronty úkolů</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue\">Správa vašich úkolů</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks\">Správa vašich úkolů</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks.readonly\">Zobrazení vašich úkolů</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tracks\">Google Maps Tracks API, tento rozsah umožňuje přístup ke čtení/zápisu ve vašich projektových datech.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_urlshortener\">Správa vašich krátkých adres ve službě goo.gl</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.email\">Zobrazení vaší e-mailové adresy</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.profile\">Zobrazení základních informací o vašem účtu</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube\">Správa vašeho účtu YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtubepartner\">Zobrazení a správa vašich zdrojů a přidruženého obsahu ve službě YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.readonly\">Zobrazení vašeho účtu YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.upload\">Správa vašich videí ve službě YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics_monetary.readonly\">Zobrazení finančních hlášení pro váš obsah na YouTube ve službě YouTube Analytics</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics.readonly\">Zobrazení hlášení pro váš obsah na YouTube ve službě YouTube Analytics</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_write\">Správa vašich dat ve službě Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.appdata\">Umožňuje přístup ke složce Application Data</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.metadata.readonly\">Zobrazení metadat souborů a dokumentů ve vašem Disku Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive\">Zobrazení a správa souborů a dokumentů ve vašem Disku Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gcm_for_chrome\">Cloudové zprávy pro Chrome</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_glass.timeline\">Rozsah pro časovou osu produktu Glass</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.best\">Správa vašich nejlépe dostupných poloh a historie polohy</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.best\">Správa vaší nejlépe dostupné polohy</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_prediction\">Správa vašich dat ve službě Google Prediction API</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification\">Správa seznamu webů a domén, které ovládáte</string>\n    <string name=\"perm_activity_recognition_description\">Umožňuje aplikaci přijímat pravidelné aktualizace úrovně vaší aktivity od společnosti Google, například pokud jdete, řídíte, jedete na kole nebo stojíte.</string>\n    <string name=\"perm_activity_recognition_label\">Rozpoznávání aktivit</string>\n</resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-cs/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <plurals name=\"pref_unifiednlp_summary\">\n        <item quantity=\"one\">Nastaven <xliff:g example=\"1\">%1$d</xliff:g> backend</item>\n        <item quantity=\"few\">Nastaveny <xliff:g example=\"3\">%1$d</xliff:g> backendy</item>\n        <item quantity=\"other\">Nastaveno <xliff:g example=\"5\">%1$d</xliff:g> backendů</item>\n    </plurals>\n    <plurals name=\"gcm_registered_apps_counter\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> registrovaná aplikace</item>\n        <item quantity=\"few\"><xliff:g example=\"3\">%1$d</xliff:g> registrované aplikace</item>\n        <item quantity=\"other\"><xliff:g example=\"5\">%1$d</xliff:g> registrovaných aplikací</item>\n    </plurals>\n    <plurals name=\"cond_perm_summary\">\n        <item quantity=\"one\">Oprávnění požadované pro správné fungování Služeb microG nebylo uděleno.</item>\n        <item quantity=\"few\">Oprávnění požadovaná pro správné fungování Služeb microG nebyla udělena.</item>\n        <item quantity=\"other\">Oprávnění požadovaná pro správné fungování Služeb microG nebyla udělena.</item>\n    </plurals>\n    <plurals name=\"cond_perm_action\">\n        <item quantity=\"one\">Vyžádat chybějící oprávnění</item>\n        <item quantity=\"few\">Vyžádat chybějící oprávnění</item>\n        <item quantity=\"other\">Vyžádat chybějící oprávnění</item>\n    </plurals>\n</resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-cs/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=\"gms_settings_name\">Nastavení microG</string>\n    <string name=\"gms_settings_summary\">Nastavit služby microG.</string>\n    <string name=\"google_account_label\">Google</string>\n    <string name=\"ask_scope_permission_title\">Aplikace <xliff:g example=\"F-Droid\">%1$s</xliff:g> požaduje:</string>\n    <string name=\"ask_service_permission_title\">Aplikace <xliff:g example=\"F-Droid\">%1$s</xliff:g> požaduje používat:</string>\n    <string name=\"account_manager_title\">Správce účtu Google</string>\n    <string name=\"sorry\">Omlouváme se…</string>\n    <string name=\"auth_sign_in\">Přihlásit se</string>\n    <string name=\"auth_connecting\">Vaše zařízení navazuje spojení se servery společnosti Google, abychom vás mohli přihlásit.\n\\n\n\\nMůže to zabrat několik sekund.</string>\n    <string name=\"auth_general_error_desc\">Při komunikaci se servery společnosti Google došlo k chybě.\n\\n\n\\nZkuste to znovu později.</string>\n    <string name=\"auth_finalize\">Vaše zařízení kontaktujte společnost Google pro uložení informací o vašem účtu.\n\\n\n\\nMůže to zabrat několik minut.</string>\n    <string name=\"allow\">Povolit</string>\n    <string name=\"deny\">Zakázat</string>\n    <string name=\"auth_notification_title\">Vyžadováno ověření</string>\n    <string name=\"auth_notification_content\">Aplikace <xliff:g example=\"F-Droid\">%1$s</xliff:g> požaduje vaše ověření pro přístup k vašemu účtu Google.</string>\n    <string name=\"signin_picker_title\">Vyberte účet</string>\n    <string name=\"signin_picker_subtitle\">a pokračujte do aplikace <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"signin_picker_add_account_label\">Přidat jiný účet</string>\n    <string name=\"signin_confirm_title\">Povolit přihlášení do aplikace <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"signin_confirm_button_text\">Povolit a sdílet</string>\n    <string name=\"signin_subtext_policy\">Před použitím této aplikace zkontrolujte její %1$s a %2$s.</string>\n    <string name=\"signin_subtext_policy_privacy\">zásady ochrany osobních údajů</string>\n    <string name=\"signin_subtext_policy_terms\">smluvní podmínky</string>\n    <string name=\"perm_status_broadcast_label\">poslouchat interní vysílání stavu</string>\n    <string name=\"perm_gsf_read_gservices_label\">číst konfiguraci zařízení Google</string>\n    <string name=\"perm_c2dm_send_label\">posílat zprávy C2DM ostatním aplikacím</string>\n    <string name=\"perm_gtalk_svc_label\">vyměňovat zprávy a získávat oznámení o synchronizaci ze serverů Google</string>\n    <string name=\"perm_extended_access_label\">Rozšířený přístup ke službám Google</string>\n    <string name=\"perm_provision_label\">úprava služeb microG</string>\n    <string name=\"perm_provision_description\">Umožňuje aplikaci nastavovat služby microG bez uživatelské interakce</string>\n    <string name=\"perm_car_speed_description\">Přístup k rychlosti vašeho auta</string>\n    <string name=\"perm_car_info_label\">Informace o autě</string>\n    <string name=\"perm_car_info_description\">Přístup k informacím o vašem autě</string>\n    <string name=\"perm_car_fuel_label\">Hladina paliva v autě</string>\n    <string name=\"perm_car_mileage_label\">Počet najetých kilometrů</string>\n    <string name=\"perm_car_vendor_extension_description\">Přístup ke kanálu prodejce vašeho automobilu pro výměnu specifických informací o autě</string>\n    <string name=\"service_name_checkin\">Registrace zařízení Google</string>\n    <string name=\"service_name_mcs\">Cloudové zprávy</string>\n    <string name=\"service_name_snet\">Google SafetyNet</string>\n    <string name=\"games_title\">Hry Google Play</string>\n    <string name=\"games_info_title\">Aplikace <xliff:g example=\"F-Droid\">%1$s</xliff:g> požaduje používání Her Play</string>\n    <string name=\"pick_place_title\">Vyberte místo</string>\n    <string name=\"pick_place_desc\">Výběr místa zatím není dostupný.</string>\n    <string name=\"place_picker_select_title\">Vybrat toto umístění</string>\n    <string name=\"place_picker_nearby_places\">Místa v okolí</string>\n    <string name=\"place_picker_location_lat_lng\">(%1$.7f, %2$.7f)</string>\n    <string name=\"lacking_permission_toast\">Služby microG: chybějící oprávnění <xliff:g example=\"plný přístup k síti\">%1$s</xliff:g></string>\n    <string name=\"network_type_mobile\">Mobilní síť</string>\n    <string name=\"network_type_other\">Další sítě</string>\n    <string name=\"self_check_cat_fake_sig\">Podpora falšování podpisu</string>\n    <string name=\"self_check_cat_gms_packages\">Nainstalované balíčky</string>\n    <string name=\"self_check_name_fake_sig_perm\">Systém má podporu falšování podpisu:</string>\n    <string name=\"self_check_resolution_fake_sig_perm\">Vaše ROM nemá nativní podporu falšování podpisu. Pro falšování podpisů stále můžete použít Xposed nebo jiné systémy. Navštivte dokumentaci pro informace o tom, které ROM podporují falšování podpisu a jak používat microG na těch, které jej nepodporují.</string>\n    <string name=\"self_check_resolution_perm_granted\">Toto je silný indikátor, že ROM podporuje falšování podpisu, ale vyžaduje další akci pro jeho aktivaci. Pro více informací o požadovaných krocích navštivte dokumentaci.</string>\n    <string name=\"self_check_resolution_system_spoofs\">Navštivte dokumentaci pro informace o požadovaných krocích.</string>\n    <string name=\"self_check_pkg_gms\">Služby microG</string>\n    <string name=\"self_check_pkg_vending\">Doprovod microG / Obchod Play</string>\n    <string name=\"self_check_pkg_gsf\">Framework Služeb microG</string>\n    <string name=\"self_check_name_app_installed\">Balíček <xliff:g example=\"F-Droid\">%1$s</xliff:g> nainstalován: </string>\n    <string name=\"self_check_name_correct_sig\">Balíček <xliff:g example=\"F-Droid\">%1$s</xliff:g> má správný podpis: </string>\n    <string name=\"self_check_resolution_correct_sig\">Buď není nainstalovaný balíček <xliff:g example=\"F-Droid\">%1$s</xliff:g> kompatibilní, nebo pro něj není aktivní falšování podpisu. Navštivte prosím dokumentaci pro informace o tom, které aplikace a ROM jsou kompatibilní.</string>\n    <string name=\"self_check_resolution_battery_optimizations\">Klepněte sem pro zakázání optimalizací baterie. Pokud tento krok neučiníte, aplikace nemusí fungovat správně.</string>\n    <string name=\"prefcat_about\">O aplikaci</string>\n    <string name=\"prefcat_services\">Služby</string>\n    <string name=\"prefcat_test\">Test</string>\n    <string name=\"cond_gcm_bat_title\">Optimalizace baterie povoleny</string>\n    <string name=\"cond_gcm_bat_summary\">Povolili jste cloudové zprávy, ale nepovolili jste ignorování optimalizací baterie pro Služby microG. Aby vám mohla všechna oznámení správně dorazit, doporučujeme povolit ignorování optimalizací baterie.</string>\n    <string name=\"pref_auth_trust_google_title\">Věřit společnosti Google u oprávnění aplikací</string>\n    <string name=\"pref_auth_trust_google_summary\">Pokud je tato možnost zakázána, bude uživatel dotázán před odesláním ověřovacího požadavku společnosti Google. Při zakázání se nemusí některým aplikacím podařit použít účet Google.</string>\n    <string name=\"pref_auth_visible_title\">Umožnit aplikacím hledat účty</string>\n    <string name=\"pref_auth_visible_summary\">Pokud je tato možnost povolena, všechny aplikace na tomto zařízení budou moci vidět e-mailové adresy vašich účtů Google bez dodatečné autorizace.</string>\n    <string name=\"pref_auth_include_android_id_title\">Ověření registrací zařízení</string>\n    <string name=\"pref_auth_include_android_id_summary\">Pokud je tato možnost zakázána, požadavky na ověření nebudou propojeny s registrací zařízení, čímž můžete umožnit přihlášení neautorizovaným zařízením, mohou ale nastat nepředvídatelné následky.</string>\n    <string name=\"pref_auth_strip_device_name_summary\">Pokud je tato možnost povolena, požadavky na ověření nebudou zahrnovat název zařízení, čímž můžete umožnit přihlášení neautorizovaným zařízením, mohou ale nastat nepředvídatelné následky.</string>\n    <string name=\"pref_device_registration_android_id\">Android ID</string>\n    <string name=\"checkin_not_registered\">Není registrováno</string>\n    <string name=\"checkin_last_registration\">Poslední registrace: <xliff:g example=\"včera v 14:20\">%1$s</xliff:g></string>\n    <string name=\"checkin_enable_switch\">Registrovat zařízení</string>\n    <string name=\"pref_gcm_enable_mcs_summary\">Cloudové zprávy jsou poskytovatel oznámení používaný množstvím aplikací třetích stran. Pro jejich použití musíte povolit registraci zařízení.</string>\n    <string name=\"pref_gcm_heartbeat_title\">Interval dotazování cloudových zpráv</string>\n    <string name=\"pref_gcm_heartbeat_summary\">Interval v sekundách, ve kterém se systém dotazuje na servery Google. Zvýšením tohoto čísla snížíte využití baterie, ale můžete způsobit zpoždění doručování zpráv.\n\\nTato možnost je zastaralá a bude v budoucnu nahrazena.</string>\n    <string name=\"pref_gcm_apps_title\">Aplikace používající cloudové zprávy</string>\n    <string name=\"pref_gcm_apps_summary\">Seznam aplikací aktuálně registrovaných pro cloudové zprávy.</string>\n    <string name=\"pref_gcm_confirm_new_apps_title\">Potvrzovat nové aplikace</string>\n    <string name=\"pref_gcm_confirm_new_apps_summary\">Ptát se před registrací nové aplikace k získávání oznámení</string>\n    <string name=\"pref_about_summary\">Informace o verzi a použitých knihovnách</string>\n    <string name=\"gcm_unregister_confirm_title\">Zrušit registraci aplikace <xliff:g example=\"F-Droid\">%1$s</xliff:g>\\?</string>\n    <string name=\"gcm_unregister_confirm_message\">Některé aplikace se automaticky opětovně neregistrují a/nebo neposkytují možnost tak učinit ručně. Tyto aplikace nemusí po zrušení registrace správně fungovat.\n\\nChcete pokračovat?</string>\n    <string name=\"gcm_unregister_after_deny_message\">Zamítli jste aplikaci, která je již registrovaná, registrovat se pro posílání oznámení.\n\\nChcete pro ni nyní zrušit registraci, aby v budoucnu již nemohla posílat oznámení?</string>\n    <string name=\"gcm_messages_counter\">Zprávy: <xliff:g example=\"123\">%1$d</xliff:g> (<xliff:g example=\"12345\">%2$d</xliff:g> bajtů)</string>\n    <string name=\"gcm_network_state_disconnected\">Odpojeno</string>\n    <string name=\"gcm_network_state_connected\">Připojeno <xliff:g example=\"před 2 hodinami\">%1$s</xliff:g></string>\n    <string name=\"gcm_enable_switch\">Získávat oznámení</string>\n    <string name=\"gcm_allow_app_popup\">Umožnit aplikaci <xliff:g example=\"F-Droid\">%1$s</xliff:g> registrovat se pro posílání oznámení?</string>\n    <string name=\"pref_push_app_allow_register_title\">Povolit registraci</string>\n    <string name=\"pref_push_app_allow_register_summary\">Povolit aplikaci se registrovat pro posílání oznámení.</string>\n    <string name=\"pref_push_app_wake_for_delivery_title\">Spustit aplikaci při oznámení</string>\n    <string name=\"pref_push_app_wake_for_delivery_summary\">Spustit aplikaci na pozadí pro získávání oznámení.</string>\n    <string name=\"prefcat_push_apps_title\">Aplikace používající oznámení</string>\n    <string name=\"prefcat_push_apps_registered_title\">Registrované aplikace</string>\n    <string name=\"prefcat_push_networks_title\">Sítě používané pro oznámení</string>\n    <string name=\"safetynet_enable_switch\">Povolit atestaci zařízení</string>\n    <string name=\"pref_safetynet_test_title\">Otestovat atestaci SafetyNet</string>\n    <string name=\"pref_recaptcha_test_title\">Otestovat reCAPTCHA</string>\n    <string name=\"pref_recaptcha_enterprise_test_title\">Otestovat reCAPTCHA Enterprise</string>\n    <string name=\"pref_test_summary_passed\">Všechny testy splněny</string>\n    <string name=\"pref_test_summary_failed\">Selhání: %s</string>\n    <string name=\"pref_test_summary_warn\">Varování: %s</string>\n    <string name=\"pref_test_summary_running\">Probíhá…</string>\n    <string name=\"pref_droidguard_operation_mode\">Režim operace</string>\n    <string name=\"pref_droidguard_unsupported_summary\">Spuštění DroidGuard není v tomto zařízení podporováno. Služby SafetyNet se mohou chovat nesprávně.</string>\n    <string name=\"menu_clear_recent_requests\">Vymazat nedávné požadavky</string>\n    <string name=\"safetynet_last_run_at\">Naposledy použito: <xliff:g example=\"včera v 14:20\">%1$s</xliff:g></string>\n    <string name=\"profile_name_auto\">Automatický: %s</string>\n    <string name=\"profile_name_system\">Systémový: %s</string>\n    <string name=\"pref_device_registration_import_custom_profile_title\">Importovat vlastní profil</string>\n    <string name=\"pref_device_registration_import_custom_profile_summary\">Importovat profil zařízení ze souboru</string>\n    <string name=\"pref_device_registration_select_profile_title\">Vybrat profil</string>\n    <string name=\"pref_safetynet_recent_recaptcha_enterprise_summary\">reCAPTCHA Enterprise: %s</string>\n    <string name=\"pref_safetynet_recent_copy_json\">Kopírovat data JSON JWS</string>\n    <string name=\"pref_safetynet_recent_advice\">Tip</string>\n    <string name=\"pref_safetynet_recent_eval_type\">Typ vyhodnocování</string>\n    <string name=\"pref_safetynet_recent_response_status\">Stav odpovědi</string>\n    <string name=\"pref_safetynet_recent_cat_response\">Data odpovědi</string>\n    <string name=\"pref_safetynet_recent_cat_request\">Data požadavku</string>\n    <string name=\"pref_safetynet_recent_nonce\">Nonce (Hex)</string>\n    <string name=\"pref_safetynet_recent_request_time\">Čas požadavku</string>\n    <string name=\"pref_safetynet_recent_request_type\">Typ požadavku</string>\n    <string name=\"pref_safetynet_recent_cat_basic\">Základní data</string>\n    <string name=\"pref_safetynet_recent_token\">Token</string>\n    <string name=\"pref_safetynet_recent_copied\">Zkopírováno do schránky!</string>\n    <string name=\"pref_safetynet_test_integrity_cts_passed\">Integrita a CTS splněny</string>\n    <string name=\"pref_safetynet_test_cts_failed\">CTS selhalo</string>\n    <string name=\"pref_safetynet_test_invalid_json\">Neplatné JSON</string>\n    <string name=\"push_notifications_summary_off\">VYP</string>\n    <string name=\"push_notifications_summary_automatic\">ZAP / Automatické: %s</string>\n    <string name=\"push_notifications_summary_manual\">ZAP / Ruční: %s</string>\n    <string name=\"push_notifications_summary_values_seconds\">%s sekund</string>\n    <string name=\"push_notifications_summary_values_minutes\">%s minut</string>\n    <string name=\"pref_vending_summary_licensing_off\">Licencování vypnuto</string>\n    <string name=\"pref_vending_summary_licensing_on\">Licencování zapnuto</string>\n    <string name=\"pref_vending_licensing_category\">Licencování Google Play</string>\n    <string name=\"pref_vending_licensing_enable_switch\">Odpovídat na požadavky ověření licence</string>\n    <string name=\"pref_vending_license_enable_summary\">Některé aplikace požadují ověření, že byly zakoupeny v Obchodě Google Play. Při požádání aplikací může microG stáhnout důkaz o zakoupení ze serverů Google. Pokud je tato možnost zakázána, nebo pokud nebyl přidán žádný účet Google, budou požadavky na ověření licence ignorovány.</string>\n    <string name=\"feedback_disabled\">Zpětná vazba momentálně není k dispozici</string>\n    <string name=\"backup_disabled\">Záloha momentálně není k dispozici</string>\n    <string name=\"pref_vending_billing_category\">Platby Google Play</string>\n    <string name=\"pref_vending_billing_enable_switch\">Zpracovávat žádosti o platby</string>\n    <string name=\"pref_vending_billing_enable_summary\">Po povolení této možnosti mohou některé aplikace dokončovat platby nebo vytvářet předplatná skrze platební službu Google Play.</string>\n    <string name=\"pref_vending_billing_note_licensing\">Některé aplikace také mohou požadovat povolení ověřování licencí pro ověření vašich nákupů.</string>\n    <string name=\"credentials_assisted_cancel\">Zrušit</string>\n    <string name=\"credentials_assisted_signin_consent_header\">Přihlašování jako %1$s</string>\n    <string name=\"credentials_assisted_signin_consent\">Pokračováním bude Google sdílet vaše jméno, e-mailovou adresu a profilový obrázek s aplikací %1$s. Viz zásady ochrany osobních údajů a smluvní podmínky aplikace %1$s.</string>\n    <string name=\"credentials_assisted_signin_description\">Přihlašování pomocí Googlu můžete spravovat ve vašich účtech Google.</string>\n    <string name=\"credentials_assisted_choose_account_label\">Vyberte účet</string>\n    <string name=\"credentials_assisted_choose_account_subtitle\">a pokračujte do aplikace %1$s</string>\n    <string name=\"credentials_assisted_signin_button_text_long\">Přihlásit se pomocí Googlu</string>\n    <string name=\"gms_app_name\">Služby microG</string>\n    <string name=\"just_a_sec\">Vteřinku…</string>\n    <string name=\"ask_permission_tos\">Pokračováním umožníte této aplikaci a společnosti Google používat vaše informace v souladu s jejich příslušnými smluvními podmínkami a zásadami ochrany osobních údajů.</string>\n    <string name=\"auth_before_connect\">Aplikace ve vašem zařízení se pokouší přihlásit k účtu Google.\\n\\nPokud to byl záměr, použijte tlačítko <b>Přihlásit se</b> pro připojení se na přihlašovací stránku společnosti Google. Pokud ne, klepněte na tlačítko <b>Zrušit</b> pro návrat zpět do aplikace, která vyvolala tento dialog.</string>\n    <string name=\"no_network_error_desc\">Nemáte přístup k síti.\n\\n\n\\nMůže se jednat o dočasný problém nebo vaše zařízení Android nemá přístup k mobilním datům. Zkuste to znovu, až budete připojeni k mobilní síti, nebo se připojte k síti Wi-Fi.</string>\n    <string name=\"signin_subtext_sharing\">Pro pokračování bude microG sdílet jméno, e-mailovou adresu a profilový obrázek vašeho účtu Google s aplikací <xliff:g example=\"F-Droid\">%1$s</xliff:g>.</string>\n    <string name=\"perm_c2dm_receive_label\">poslouchat zprávy C2DM</string>\n    <string name=\"perm_car_speed_label\">Rychlost auta</string>\n    <string name=\"perm_car_fuel_description\">Přístup k informaci o hladině paliva ve vašem autě</string>\n    <string name=\"perm_car_mileage_description\">Přístup k počtu najetých kilometrů vašeho auta</string>\n    <string name=\"perm_car_vendor_extension_label\">Kanál prodejce automobilů</string>\n    <string name=\"service_name_vending\">Služby Obchodu Play</string>\n    <string name=\"games_info_content\">Pro používání Her Play je třeba nainstalovat aplikaci Hry Google Play. Aplikace může fungovat i bez Her Play, ale je možné, že se bude chovat nepředvídatelně.</string>\n    <string name=\"network_type_wifi\">Wi-Fi</string>\n    <string name=\"network_type_roaming\">Roaming</string>\n    <string name=\"self_check_resolution_app_installed\">Nainstalujte aplikaci <xliff:g example=\"F-Droid\">%1$s</xliff:g> nebo jinou kompatibilní. Pro informace o kompatibilních aplikacích navštivte dokumentaci.</string>\n    <string name=\"self_check_name_battery_optimizations\">Optimalizace baterie ignorovány:</string>\n    <string name=\"prefcat_location_service\">Služba polohy</string>\n    <string name=\"prefcat_components\">Součásti</string>\n    <string name=\"self_check_name_perm_granted\">Systém uděluje oprávnění k falšování podpisu:</string>\n    <string name=\"self_check_name_system_spoofs\">Systém falšuje podpis:</string>\n    <string name=\"prefcat_configuration\">Nastavení</string>\n    <string name=\"prefcat_google_services\">Služby Google</string>\n    <string name=\"self_check_cat_system\">Systém</string>\n    <string name=\"pref_auth_strip_device_name_title\">Odstranit název zařízení při ověřování</string>\n    <string name=\"pref_info_status\">Stav</string>\n    <string name=\"prefcat_push_apps_unregistered_title\">Neregistrované aplikace</string>\n    <string name=\"pref_safetynet_test_integrity_failed\">Integrita selhala</string>\n    <string name=\"pref_vending_billing_note_experimental\">Tato funkce je experimentální a může vést ke ztrátě peněz. Byli jste varováni.</string>\n    <string name=\"cond_gcm_bat_action\">Ignorovat optimalizace</string>\n    <string name=\"pref_checkin_enable_summary\">Zaregistruje vaše zařízení do služeb Google a vytvoří unikátní identifikátor zařízení. microG odstraní z registračních dat všechny identifikační prvky kromě názvu vašeho účtu Google.</string>\n    <string name=\"pref_more_settings\">Další</string>\n    <string name=\"pref_accounts_summary\">Přidat a spravovat účty Google</string>\n    <string name=\"prefcat_accounts_current_accounts_title\">Účty</string>\n    <string name=\"pref_add_account_summary\">Přidat účet Google</string>\n    <string name=\"pref_safetynet_test_not_completed\">Ještě není dokončeno</string>\n    <string name=\"credentials_assisted_continue\">Pokračovat</string>\n    <string name=\"credentials_assisted_sign_back_title\">Přihlásit se zpět do aplikace %1$s s účtem Google</string>\n    <string name=\"cond_perm_title\">Chybějící oprávnění</string>\n    <string name=\"prefs_account\">Nastavení účtu</string>\n    <string name=\"pref_accounts_title\">Účty Google</string>\n    <string name=\"prefcat_safetynet_apps_title\">Aplikace používající SafetyNet</string>\n    <string name=\"pref_safetynet_test_no_result\">Žádný výsledek</string>\n    <string name=\"credentials_assisted_confirmation_header\">Přihlašování</string>\n    <string name=\"prefs_account_privacy\">Osobní údaje a soukromí</string>\n    <string name=\"prefcat_accounts_settings_title\">Nastavení</string>\n    <string name=\"safetynet_intro\">Google SafetyNet je systém registrace zařízení, který zajišťuje, že je zařízení správně zabezpečeno a že je kompatibilní s Android CTS. Některé aplikace vyžadují SafetyNet z bezpečnostních důvodů nebo jako předpoklad pro ochranu proti neoprávněné manipulaci.\n\\n\n\\nmicroG GmsCore obsahuje svobodnou implementaci systému SafetyNet, oficiální servery ale vyžadují podepsání požadavků SafetyNet proprietárním systémem DroidGuard.</string>\n    <string name=\"profile_name_native\">Nativní</string>\n    <string name=\"profile_name_real\">Reálný</string>\n    <string name=\"credentials_assisted_continue_as_user_button_label\">Pokračovat jako %1$s</string>\n    <string name=\"prefs_account_security\">Přihlášení a zabezpečení</string>\n    <string name=\"pref_add_account_title\">Účet</string>\n    <string name=\"profile_name_user\">Vlastní: %s</string>\n    <string name=\"pref_gcm_ping_interval\">Interval dotazu: <xliff:g example=\"10 minut\">%1$s</xliff:g></string>\n    <string name=\"pref_device_registration_serial_title\">Sériové číslo</string>\n    <string name=\"pref_device_registration_device_profile_category\">Profil zařízení</string>\n    <string name=\"pref_about_title\">O Službách microG</string>\n    <string name=\"pref_safetynet_recent_uses\">Nedávná použití</string>\n    <string name=\"gcm_app_error_unregistering\">Chyba při rušení registrace</string>\n    <string name=\"gcm_not_registered\">Nejste registrováni</string>\n    <string name=\"pref_safetynet_recent_attestation_summary\">Atestace: %s</string>\n    <string name=\"gcm_app_not_installed_anymore\">Již není nainstalováno</string>\n    <string name=\"gcm_unregister_app\">Zrušit registraci</string>\n    <string name=\"gcm_no_message_yet\">Zatím nebyly obdrženy žádné zprávy</string>\n    <string name=\"gcm_registered_since\">Registrováno od: <xliff:g example=\"včera v 14:20\">%1$s</xliff:g></string>\n    <string name=\"pref_safetynet_recent_recaptcha_summary\">reCAPTCHA: %s</string>\n    <string name=\"gcm_last_message_at\">Poslední zpráva: <xliff:g example=\"včera v 14:20\">%1$s</xliff:g></string>\n    <string name=\"gcm_registered\">Registrováno</string>\n    <string name=\"auth_package_override_request_title\">Povolit aplikaci <b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> privilegovaný přístup k účtu <xliff:g example=\"account@example.com\">%2$s</xliff:g>\\?</string>\n    <string name=\"auth_package_override_request_message\">Aplikace <b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> žádá o přístup k vašemu účtu, jako by byla aplikací <b><xliff:g example=\"F-Droid\">%2$s</xliff:g> od vývojáře <xliff:g example=\"F-Droid Inc.\">%3$s</xliff:g></b>. Tímto jí můžete udělit privilegovaný přístup k vašemu účtu.</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_switch\">Automaticky přidávat bezplatné aplikace do knihovny</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_summary\">Bezplatné aplikace mohou kontrolovat, zda byly staženy z Google Play. Automaticky přidávat bezplatné aplikace do knihovny vašeho účtu, abyste vždy prošli kontrolou u všech bezplatných aplikací, které máte aktuálně k dispozici.</string>\n    <string name=\"limited_services_app_name\">Omezené služby microG</string>\n    <string name=\"limited_services_dialog_information\">Používáte Omezené služby microG. Na rozdíl od klasických Služeb microG funguje tato varianta pouze s aplikacemi, které používají knihovny microG, nikoli ale s těmi, které používají Google Play. To znamená, že většina aplikací bude tyto služby ignorovat.</string>\n    <string name=\"limited_services_dialog_information_ack\">Rozumím</string>\n    <string name=\"auth_action_notification_channel_name\">Upozornění účtu Google</string>\n    <string name=\"auth_action_step_enable_gcm\">Povolte cloudové zprávy</string>\n    <string name=\"auth_action_step_enable_gcm_description\">Po dokončení nastavení účtu můžete cloudové zprávy zakázat.</string>\n    <string name=\"auth_action_step_allow_microg_gcm\">Povolte cloudové zprávy pro microG</string>\n    <string name=\"auth_action_step_enable_checkin_description\">Vaše zařízení se musí alespoň jednou zaregistrovat u společnosti Google.\\n\\nPo dokončení nastavení účtu můžete registraci zařízení Google zakázat.</string>\n    <string name=\"auth_action_notification_title\">Vyžadována akce účtu</string>\n    <string name=\"auth_action_activity_explanation\">Dokončete následující kroky, abyste mohli používat účet Google %s na tomto zařízení.</string>\n    <string name=\"auth_action_step_enable_checkin\">Povolte registrace zařízení</string>\n    <string name=\"auth_action_notification_content\">Váš účet Google potřebuje další nastavení.</string>\n    <string name=\"auth_action_notification_channel_description\">Upozorní vás, pokud některý z účtů Google vyžaduje před použitím další nastavení nebo když účet není kompatibilní s microG.</string>\n    <string name=\"auth_action_activity_header\">Dokončete nastavení svého účtu Google</string>\n    <string name=\"auth_action_activity_finish\">Dokončit</string>\n    <string name=\"auth_action_step_completed_content_description\">Krok dokončen</string>\n    <string name=\"auth_action_step_allow_microg_gcm_description\">V závislosti na vašich předvolbách od vás potřebuje microG oprávnění, aby se mohl zaregistrovat do služby cloudových zpráv.</string>\n    <string name=\"auth_action_step_enable_lockscreen_description\">Váš účet Google spravuje vaše pracoviště nebo vzdělávací instituce. Váš správce rozhodl, že zařízení musí mít před přístupem k datům účtu bezpečný zámek obrazovky.\\n\\nNastavte zámek obrazovky s heslem, kódem PIN nebo vzorem.</string>\n    <string name=\"auth_action_step_perform_content_description\">Klepněte pro provedení kroku</string>\n    <string name=\"auth_action_step_enable_lockscreen\">Nastavte bezpečný zámek obrazovky</string>\n    <string name=\"pref_vending_asset_delivery_switch\">Povolit dodávání prostředků na vyžádání</string>\n    <string name=\"pref_vending_asset_delivery_category\">Dodávání prostředků Google Play</string>\n    <string name=\"pref_vending_asset_delivery_summary\">Stáhnout další prostředky na žádost aplikací používajících službu Play Asset Delivery</string>\n    <string name=\"pref_vending_asset_device_sync_summary\">Aplikace využívající službu Play Asset Delivery budou stahovat další prostředky na základě informací o aktuálně používaném zařízení.</string>\n    <string name=\"pref_vending_asset_device_sync_switch\">Povolit synchronizaci informací o zařízení</string>\n    <string name=\"games_achievement_list_title\">Úspěchy</string>\n    <string name=\"games_api_access_denied\">Žádný účet v tomto zařízení nemá přístup k hernímu rozhraní API</string>\n    <string name=\"games_achievement_locked_content_description\">uzamčený</string>\n    <string name=\"games_achievement_unlocked_content_description\">odemčený</string>\n    <string name=\"games_leaderboard_score_empty_text\">Neuvěřitelné! Tato hra nemá žádné nejvyšší skóre.</string>\n    <string name=\"games_leaderboard_list_title\">Žebříčky</string>\n    <string name=\"games_leaderboards_score_label\">Skóre: %1$s</string>\n    <string name=\"games_snapshot_empty_text\">Zatím nebyly uloženy žádné hry</string>\n    <string name=\"games_snapshot_choose_btn_text\">vybrat</string>\n    <string name=\"games_snapshot_delete_btn_text\">smazat</string>\n    <string name=\"games_delete_snapshot_dialog_title\">Smazat uloženou hru</string>\n    <string name=\"games_delete_snapshot_dialog_message\">Opravdu chcete smazat tuto uloženou hru?</string>\n    <string name=\"games_delete_snapshot_dialog_cancel\">Zrušit</string>\n    <string name=\"games_delete_snapshot_dialog_ok\">OK</string>\n    <string name=\"games_delete_snapshot_error\">Při mazání došlo k chybě, zkuste to prosím později</string>\n    <string name=\"games_leaderboard_empty_text\">Tato hra nemá žádné žebříčky</string>\n    <string name=\"games_achievements_empty_text\">Žádné úspěchy v této hře</string>\n    <string name=\"games_achievement_extra_text\">%1$s XP</string>\n    <string name=\"service_name_work_profile\">Pracovní profil</string>\n    <string name=\"pref_workprofile_intro\">Při nastavování pracovního účtu pro pracoviště nebo vzdělávací instituci se může instalátor pokusit připojit ke společnosti Google pro povolení stahování aplikací do daného profilu.</string>\n    <string name=\"camera_permission_dialog_button\">OK</string>\n    <string name=\"camera_permission_dialog_title\">Vyžadováno oprávnění k použití fotoaparátu</string>\n    <string name=\"barcode_scanner_brand\">Naskenováno službou microG jménem %1$s</string>\n    <string name=\"pref_workprofile_disclaimer\">Je vaší odpovědností zajistit, aby používání microG bylo v souladu s firemními zásadami. microG je poskytováno s vynaložením veškerého úsilí a nemůžeme zaručit, že se bude chovat přesně podle očekávání.</string>\n    <string name=\"pref_vending_feature_delivery\">Dodávání funkcí Google Play</string>\n    <string name=\"camera_permission_dialog_message\">Služby microG potřebují přístup k fotoaparátu vašeho zařízení, aby mohly naskenovat kód pro %1$s.\\n\\nPro povolení udělte Službám microG oprávnění k použití fotoaparátu v Nastavení.</string>\n    <string name=\"pref_vending_split_install_switch\">Instalace součástí na vyžádání</string>\n    <string name=\"pref_workprofile_create_account\">Povolit nastavení pracovního účtu</string>\n    <string name=\"pref_vending_licensing_split_install_summary\">Povolit aplikacím stahovat a instalovat dodatečné součásti</string>\n    <string name=\"credentials_assisted_choose_account_error_tips\">Anomálie účtu</string>\n    <string name=\"credentials_assisted_signin_add_account\">Přidat účet</string>\n    <string name=\"auth_action_reauth_notification_title\">Vyžadována akce účtu</string>\n    <string name=\"pref_game_accounts_title\">Herní účty Google</string>\n    <string name=\"pref_auto_create_player\">Povolit registraci účtu Her Play</string>\n    <string name=\"pref_auto_create_player_intro\">Během hraní her potřebujete účet Her Play pro přihlášení a záznam funkcí týkajících se hry, jako jsou úspěchy, žebříčky, archivy atd. Po zakázání nebudou účty Google, které nejsou připojeny k účtu Her Google, automaticky registrovány, a do hry se nepůjde přihlásit a hrát ji.</string>\n    <string name=\"pref_allow_upload_game_played\">Povolit nahrání odehrané hry</string>\n    <string name=\"pref_allow_upload_game_played_summary\">Po zakázání nebude hra hlásit stav odehrání hry po přihlášení do ní, a do některých her se nepůjde přihlásit.</string>\n    <string name=\"pref_change_default_game_player\">Změnit účet pro hry</string>\n    <string name=\"pref_change_default_game_player_summary\">Změnit výchozí účet pro hry a změnit účet podle hry.</string>\n    <string name=\"pref_delete_game_account_data\">Smazat data Her Play</string>\n    <string name=\"pref_delete_game_account_data_summary\">Smazat účet a všechna data Her Play a smazat osobní herní data.</string>\n    <string name=\"games_state_description_signed_out\">Odhlášeni</string>\n    <string name=\"games_state_description_delete\">Smazat</string>\n    <string name=\"games_change_button_text\">Změnit</string>\n    <string name=\"games_change_default_account_section_title\">Změnit výchozí účet pro hry</string>\n    <string name=\"games_change_default_account_description\">Výchozí účet: %1$s</string>\n    <string name=\"games_change_default_account_explanation\">Tento účet je použit k automatickému přihlašování do her a ukládání postupu a vašich nastavení. Změnou výchozího účtu nebo odhlášením se může resetovat váš postup a nastavení hraných her.</string>\n    <string name=\"games_change_per_game_title\">Změnit účet podle hry</string>\n    <string name=\"games_change_per_game_description\">Změnou účtu pro zvolenou hru nebo odhlášením se může resetovat váš postup a nastavení v dané hře.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_title\">Vyberte možnost pro nový výchozí účet</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_description\">Aktuální výchozí účet: %1$s</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_title\">Změnit výchozí účet pouze pro nové hry</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_description\">Neztratíte přístup k postupu ve hrách a k nastavením v hraných hrách. Váš postup ale bude rozdělen mezi účty.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_title\">Změnit výchozí účet pro všechny hry</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_description\">Můžete ztratit přístup k postupu a nastavením ve hrách, které jste hráli. Pro použití vašich změn hru restartujeme.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_title\">Odhlásit se ze všech her</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_description\">Můžete ztratit přístup k postupu a nastavením v hraných hrách. Pro použití vašich změn hru restartujeme.</string>\n    <string name=\"games_change_per_game_dialog_title\">Vyberte možnost pro tuto hru</string>\n    <string name=\"games_change_per_game_dialog_description\">Změnou účtu nebo odhlášením se může resetovat váš postup a nastavení hry</string>\n    <string name=\"games_change_per_game_dialog_option_use_player\">Použít %1$s</string>\n    <string name=\"games_change_per_game_dialog_option_use_player_snackbar_success_message\">Do této hry budete přihlášeni pomocí účtu %1$s</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out\">Odhlásit se</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out_snackbar_success_message\">Nyní jste z této hry odhlášeni</string>\n    <string name=\"games_change_sign_out_of_all_games_snackbar_success_message\">Nyní jste ze všech her odhlášeni</string>\n    <string name=\"games_change_default_account_for_all_games_snackbar_success_message\">Budete přihlášeni do všech her pomocí účtu %1$s</string>\n    <string name=\"games_change_default_account_for_new_games_snackbar_success_message\">Budete přihlášeni do nových her pomocí účtu %1$s</string>\n    <string name=\"games_account_display_content\">Aktuální účet: %1$s</string>\n    <string name=\"games_delete_profile_header\">Odstranit účet Her Play a všechna data</string>\n    <string name=\"games_delete_profile_explanation\">Trvale odstranit váš účet Her Google Play, body XP a všechna data profilu. Tato akce také může vymazat vaše skóre, postup (uložené hry) a nastavení her, které jste hráli.</string>\n    <string name=\"games_delete_profile_button\">Trvale odstranit</string>\n    <string name=\"games_delete_game_data_header\">Odstranit data jednotlivých her</string>\n    <string name=\"games_delete_game_data_explanation\">Můžete trvale odstranit data jednotlivých her, které jste hráli pomocí Her Google Play. Tato akce vymaže vaše skóre, postup (uložené hry) a nastavení vybrané hry.</string>\n    <string name=\"games_delete_profile_dialog_title\">Opravdu chcete odstranit tento účet?</string>\n    <string name=\"games_delete_profile_explanation_with_gamer_name\">Trvale odstranit váš účet Her Google Play pro hráče jménem <b>%1$s</b> (<b>%2$s</b>), body XP a všechna profilová data. Tato akce může také vymazat vaše skóre, postup (uložené hry) a nastavení her, které jste hráli.</string>\n    <string name=\"games_delete_profile_dialog_message\">Tato akce je nevratná.</string>\n    <string name=\"games_delete_profile_fail\">Nepodařilo se odstranit váš profil. Zkuste to znovu později.</string>\n    <string name=\"games_delete_game_data_confirm_dialog_title\">Odstranit data účtu %1$s</string>\n    <string name=\"games_delete_game_data_confirm_dialog_message\">Trvalým odstraněním vašich dat v účtu %1$s se vymaže vaše skóre, postup (uložené hry) a nastavení her v Hrách Google Play.</string>\n    <string name=\"games_popup_signin_welcome\">Zdravíme, %1$s</string>\n    <string name=\"pref_auth_two_step_verification_title\">Dostávat výzvy k dvoufázovému ověření</string>\n    <string name=\"pref_auth_two_step_verification_summary\">Pokud je tato možnost povolena, bude moci zařízení dostávat výzvyk dvoufázovému ověření od Googlu (vyžadovány cloudové zprávy).</string>\n    <string name=\"service_name_google_location_sharing\">Sdílení polohy Google</string>\n    <string name=\"location_sharing_description\">Spravujte sdílení své polohy v reálném čase napříč aplikacemi a službami Google z tohoto zařízení</string>\n    <string name=\"location_sharing_learn_more\">Zjistěte více o sdílení polohy</string>\n    <string name=\"location_sharing_switch_text\">Použít sdílení polohy</string>\n    <string name=\"location_sharing_turn_off_notify_hint\">Pokud vypnete sdílení polohy tohoto zařízení, nebudou lidé, se kterými ji sdílíte, upozorněni.</string>\n    <string name=\"location_sharing_off_previous_hint\">Dokud ji znovu nezapnete, bude k dispozici pouze vaše poslední sdílená poloha.</string>\n    <string name=\"location_sharing_disabled\">Tento účet nemá žádnou aktivní sdílenou polohu</string>\n    <string name=\"location_sharing_turn_on_hint\">Jakmile začnete sdílet svou polohu z aplikace nebo služby Google, budete jej odsud moci spravovat.\\n\\nPro spuštění sdílení přejděte do Map Google nebo Family Linku.</string>\n    <string name=\"location_sharing_turn_off_title\">Vypnout sdílení polohy</string>\n    <string name=\"location_sharing_turn_off_cancel\">Ponechat zapnuté</string>\n    <string name=\"location_sharing_turn_off_confirm\">Vypnout</string>\n    <string name=\"location_sharing_confirm_dialog_title\">Povolit sdílení polohy</string>\n    <string name=\"location_sharing_confirm_dialog_text\">Lidé, se kterými sdílíte svou polohu, budou moci vždy vidět:\\n· Vaše jméno a fotografii\\n· Nedávnou polohu vašeho zařízení, i když nepoužíváte službu Google\\n· Nabití baterie vašeho zařízení, a zda se nabíjí\\n· Váš čas odjezdu a příjezdu, pokud přidá oznámení o sdílení polohy</string>\n    <string name=\"location_sharing_turn_off_hint\">Je možné, že stále sdílíte svou polohu z jiných zařízení přihlášených do stejného účtu Google nebo z aplikací nepatřících společnosti Google. Nezapomeňte zkontrolovat nastavení sdílení polohy kdekoli, kde může platit.\\n\\nLidé, se kterými polohu sdílíte, nadále uvidí vaši poslední sdílenou polohu.</string>\n    <string name=\"family_management_title\">Rodina</string>\n    <string name=\"family_management_retry\">Zkusit znovu</string>\n    <string name=\"family_management_load_error\">Nepodařilo se načíst obsah</string>\n    <string name=\"family_management_toolbar_back\">Zpět</string>\n    <string name=\"family_management_toolbar_more\">Více</string>\n    <string name=\"family_management_exit_family_group\">Opustit rodinnou skupinu</string>\n    <string name=\"family_management_delete_family_group\">Odstranit rodinnou skupinu</string>\n    <string name=\"family_management_leave_family_password_title\">Potvrďte heslo pro opuštění rodinné skupiny</string>\n    <string name=\"family_management_delete_family_password_title\">Potvrďte heslo pro odstranění rodinné skupiny</string>\n    <string name=\"family_management_remove_member_password_title\">Potvrďte heslo pro odstranění %s</string>\n    <string name=\"family_management_invite_family_member\">Pozvat členy rodiny</string>\n    <string name=\"family_management_invite_slots_left\">Zbývá %1$d pozvánek</string>\n    <string name=\"family_management_cancel_invite\">Zrušit pozvánku</string>\n    <string name=\"family_management_cancel_invite_success\">Pozvánka úspěšně zrušena</string>\n    <string name=\"family_management_cancel_invite_error\">Chyba při rušení pozvánky. Zkuste to znovu.</string>\n    <string name=\"family_management_remove_member\">Odebrat člena</string>\n    <string name=\"family_management_member_removed_success\">Člen %s byl odebrán z vaší rodinné skupiny</string>\n    <string name=\"family_management_member_remove_failed\">Nepodařilo se odebrat člena %s. Zkuste to znovu.</string>\n    <string name=\"family_management_leave_family_error_message\">Nepodařilo se opustit rodinnou skupinu. Zkuste to znovu.</string>\n    <string name=\"family_management_exist_group_success\">Opustili jste svou rodinnou skupinu…</string>\n    <string name=\"family_management_delete_group_success\">Rodinná skupina odstraněna</string>\n    <string name=\"family_management_delete_group_failure\">Nepodařilo se odstranit domovskou skupinu</string>\n    <string name=\"family_management_delete_group_cancel\">Zrušit</string>\n    <string name=\"family_management_delete_group_confirm\">OK</string>\n    <string name=\"family_management_input_pwd\">Zadejte prosím své heslo</string>\n    <string name=\"family_management_invite_sent_date_format\">Pozvánka odeslána uživateli %s</string>\n    <string name=\"family_management_invite_send\">Pozvánka odeslána</string>\n    <string name=\"family_management_pwd_error\">Nesprávné heslo, zadejte jej prosím znovu</string>\n    <string name=\"pref_app_install_settings_title\">Nastavení instalátoru aplikací</string>\n    <string name=\"pref_app_install_switch_title\">Povolit instalaci aplikací</string>\n    <string name=\"pref_app_install_other_apps_note\">Autorizace umožňuje instalaci aplikací poskytovaných jinými zdroji.</string>\n    <string name=\"pref_app_install_permission_instruction\">Aby vaše nainstalované aplikace fungovaly správně, povolte prosím Doprovodné aplikaci microG instalaci aplikací stažených z jiných zdrojů.</string>\n    <string name=\"prefcat_app_install_list_title\">Aplikace používající instalátor aplikací</string>\n    <string name=\"service_name_device_attestation\">Atestace zařízení</string>\n    <string name=\"prefcat_device_attestation_apps_title\">Aplikace využívající atestaci zařízení</string>\n    <string name=\"pref_device_attestation_app_allow_requests_title\">Povolit žádosti</string>\n    <string name=\"pref_device_attestation_app_allow_requests_summary\">Povolit aplikaci požádat o atestaci zařízení</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-de/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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  --><resources>\n    <string name=\"permission_service_all_label\">Alle Google-Dienste</string>\n    <string name=\"permission_service_android_label\">Android-Dienste</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase.readonly\">dein Freebase-Konto ansehen</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.readonly\">Dateien und Dokumente in deinem Google Drive ansehen</string>\n    <string name=\"permission_service_speechpersonalization_label\">Personalisierte Spracherkennung</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive\">Dateien und Dokumente in deinem Google Drive ansehen und verwalten</string>\n    <string name=\"permission_service_wise_label\">Google-Tabellen</string>\n    <string name=\"permission_service_wifi_label\">Google WLAN</string>\n    <string name=\"permission_service_health_label\">Google-Gesundheit</string>\n    <string name=\"permission_service_cp_label\">Kontakte</string>\n    <string name=\"permission_service_speech_label\">Sprachsuche</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_write\">Deine Daten im Google-Cloudspeicher verwalten</string>\n    <string name=\"permission_service_cl_label\">Google-Kalender</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_only\">Deine Daten im Google-Cloudspeicher ansehen</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar.readonly\">Meine Kalender ansehen</string>\n    <string name=\"permission_service_YouTubeUser_label\">YouTube-Benutzernamen</string>\n    <string name=\"permission_service_groups2_label\">Google-Gruppen</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar\">Meine Kalender verwalten</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_books\">Meine Bücher verwalten</string>\n    <string name=\"permission_service_finance_label\">Google-Finanzen</string>\n    <string name=\"permission_service_blogger_label\">Blogger</string>\n    <string name=\"permission_service_all_description\">Ermöglicht der App den Zugriff auf alle Google-Dienste über ein beliebiges verbundenes Google-Konto.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.best\">Deinen bestverfügbaren Standort und den Standortverlauf verwalten</string>\n    <string name=\"permission_service_adwords_label\">AdWords</string>\n    <string name=\"permission_service_cl_description\">Ermöglicht der App den Zugriff auf den Google-Kalender über ein beliebiges verbundenes Google-Konto.</string>\n    <string name=\"permission_service_finance_description\">Ermöglicht der App den Zugriff auf Google-Finanzen über ein beliebiges verbundenes Google-Konto.</string>\n    <string name=\"permission_service_lh2_description\">Ermöglicht der App den Zugriff auf Picasa-Webalben über ein beliebiges verbundenes Google-Konto.</string>\n    <string name=\"permission_service_talk_description\">Ermöglicht der App den Zugriff auf Google Talk über ein beliebiges verbundenes Google-Konto.</string>\n    <string name=\"permission_service_writely_description\">Ermöglicht der App den Zugriff auf Google Docs über ein beliebiges verbundenes Google-Konto.</string>\n    <string name=\"permission_service_youtube_label\">YouTube</string>\n    <string name=\"permission_service_youtube_description\">Ermöglicht der App den Zugriff auf YouTube über ein beliebiges verbundenes Google-Konto.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.licensing\">Lese-/Schreibzugriff auf die Lizenzmanager-API.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.appdata\">Ermöglicht den Zugriff auf den Ordner Anwendungsdaten</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.install\">Spezieller Bereich, in dem Benutzer die Installation einer App genehmigen können</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.modify\">Alle Lese-/Schreiboperationen außer dem sofortigen, endgültigen Löschen von Threads und Nachrichten, wobei der Papierkorb umgangen wird.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.readonly\">Alle Ressourcen und ihre Metadaten lesen – keine Schreiboperationen.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics.readonly\">YouTube-Analytics-Berichte für deine YouTube-Inhalte anzeigen</string>\n    <string name=\"permission_service_dodgeball_label\">Dodgeball</string>\n    <string name=\"permission_service_dodgeball_description\">Ermöglicht der App den Zugriff auf Dodgeball über ein beliebiges verbundenes Google-Konto.</string>\n    <string name=\"permission_service_gbase_description\">Ermöglicht der App den Zugriff auf Google Base über ein beliebiges verbundenes Google-Konto.</string>\n    <string name=\"permission_service_knol_description\">Ermöglicht der App den Zugriff auf Knol über ein beliebiges verbundenes Google-Konto.</string>\n    <string name=\"permission_service_local_label\">Google Maps</string>\n    <string name=\"permission_service_local_description\">Ermöglicht der App den Zugriff auf Google Maps über ein beliebiges verbundenes Google-Konto.</string>\n    <string name=\"permission_service_mail_label\">Google Mail</string>\n    <string name=\"permission_service_mail_description\">Ermöglicht der App den Zugriff auf Google Mail über ein beliebiges verbundenes Google-Konto.</string>\n    <string name=\"permission_service_news_label\">Google News</string>\n    <string name=\"permission_service_news_description\">Ermöglicht der App den Zugriff auf Google News über ein beliebiges verbundenes Google-Konto.</string>\n    <string name=\"permission_service_writely_label\">Google Docs</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_androidpublisher\">Zugriff auf Google Play Android Developer</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut\">Deine Orkut-Aktivitäten verwalten</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut.readonly\">Deine Orkut-Daten anzeigen</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.login\">Kenne deinen Namen, grundlegende Informationen und die Liste der Personen, mit denen du auf Google+ verbunden bist</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks\">Deine Aufgaben verwalten</string>\n    <string name=\"permission_service_android_description\">Ermöglicht der App den Zugriff auf Android-Dienste über ein beliebiges verbundenes Google-Konto.</string>\n    <string name=\"permission_service_adsense_label\">AdSense</string>\n    <string name=\"permission_service_adsense_description\">Ermöglicht der App den Zugriff auf AdSense über ein beliebiges verbundenes Google-Konto.</string>\n    <string name=\"permission_service_adwords_description\">Ermöglicht der App den Zugriff auf AdWords über ein beliebiges verbundenes Google-Konto.</string>\n    <string name=\"permission_service_blogger_description\">Ermöglicht der App den Zugriff auf Blogger über ein beliebiges verbundenes Google-Konto.</string>\n    <string name=\"permission_service_cp_description\">Ermöglicht der App den Zugriff auf Kontakte über ein beliebiges verbundenes Google-Konto.</string>\n    <string name=\"permission_service_ig_description\">Ermöglicht der App den Zugriff auf iGoogle über ein beliebiges verbundenes Google-Konto.</string>\n    <string name=\"permission_service_jotspot_description\">Ermöglicht der App den Zugriff auf JotSpot über ein beliebiges verbundenes Google-Konto.</string>\n    <string name=\"permission_service_lh2_label\">Picasa-Webalben</string>\n    <string name=\"permission_service_orkut_label\">Orkut</string>\n    <string name=\"permission_service_orkut_description\">Ermöglicht der App den Zugriff auf Orkut über ein beliebiges verbundenes Google-Konto.</string>\n    <string name=\"permission_service_print_label\">Google-Buchsuche</string>\n    <string name=\"permission_service_print_description\">Ermöglicht der App den Zugriff auf Google-Buchsuche über ein beliebiges verbundenes Google-Konto.</string>\n    <string name=\"permission_service_gbase_label\">Google Base</string>\n    <string name=\"permission_service_grandcentral_label\">Google Voice</string>\n    <string name=\"permission_service_grandcentral_description\">Ermöglicht der App den Zugriff auf Google Voice über ein beliebiges verbundenes Google-Konto.</string>\n    <string name=\"permission_service_groups2_description\">Ermöglicht der App den Zugriff auf Google Groups über ein beliebiges verbundenes Google-Konto.</string>\n    <string name=\"permission_service_ig_label\">iGoogle</string>\n    <string name=\"permission_service_jotspot_label\">JotSpot</string>\n    <string name=\"permission_service_knol_label\">Knol</string>\n    <string name=\"permission_service_YouTubeUser_description\">Ermöglicht der App den Zugriff auf den/die YouTube-Benutzernamen, der/die mit einem beliebigen verbundenen Google-Konto verwendet wird/werden.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_activity\">Aktivitätsverlauf deiner Google-Apps anzeigen</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsensehost\">Deine AdSense-Hostdaten und zugehörigen Konten anzeigen und verwalten</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense.readonly\">Deine AdSense-Daten anzeigen</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense\">Deine AdSense-Daten anzeigen und verwalten</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics.readonly\">Deine Google-Analytics-Daten anzeigen</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics\">Deine Google-Analytics-Daten anzeigen und verwalten</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.migration\">Lese- und Schreibzugriff auf die Gruppenmigrations-API.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger\">Dein Blogger-Konto verwalten</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger.readonly\">Dein Blogger-Konto anzeigen</string>\n    <string name=\"permission_service_talk_label\">Google Talk</string>\n    <string name=\"permission_service_wifi_description\">Ermöglicht der App den Zugriff auf Google Wi-Fi über ein beliebiges verbundenes Google-Konto.</string>\n    <string name=\"permission_service_wise_description\">Ermöglicht der App den Zugriff auf Google-Tabellen über ein beliebiges verbundenes Google-Konto.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.metadata.readonly\">Metadaten für Dateien und Dokumente in deinem Google Drive anzeigen</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase\">Bei Freebase mit deinem Konto anmelden</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan\">Deine GAN-Daten verwalten</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan.readonly\">Deine GAN-Daten anzeigen</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gcm_for_chrome\">CloudMessaging für Chrome</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.compose\">Entwürfe erstellen, lesen, aktualisieren und löschen. Nachrichten und Entwürfe senden.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.city\">Deinen Standort auf Stadtebene und den Standortverlauf verwalten</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.best\">Deinen bestverfügbaren Standort verwalten</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.city\">Deinen Standort auf Stadtebene verwalten</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.me\">Wissen, wer du bei Google bist</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_prediction\">Deine Daten in der Google-Vorhersage-API verwalten</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_shoppingapi\">Deine Produktdaten anzeigen</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification\">Liste der von dir kontrollierten Webseiten und Domains verwalten</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification.verify_only\">Deine Verifizierungen für neue Webseiten mit Google verwalten</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue\">Deine Aufgaben verwalten</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks.readonly\">Deine Aufgaben anzeigen</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.email\">Deine E-Mail-Adresse anzeigen</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.profile\">Grundlegende Informationen über dein Konto anzeigen</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube\">Dein YouTube-Konto verwalten</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtubepartner\">Deine Assets und zugehörigen Inhalte auf YouTube anzeigen und verwalten</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.readonly\">Dein YouTube-Konto anzeigen</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.upload\">Deine YouTube-Videos verwalten</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.file\">Ansehen und Verwalten von Google-Drive-Dateien, die du mit dieser App geöffnet oder erstellt hast</string>\n    <string name=\"permission_service_ah_description\">Ermöglicht der App den Zugriff auf die Google App Engine über ein beliebiges verbundenes Google-Konto.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.apps.readonly\">Ansehen deiner Google-Drive-Apps</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.scripts\">Ändere das Verhalten deiner Skripte für Google Apps Script</string>\n    <string name=\"permission_service_ah_label\">Google App Engine</string>\n    <string name=\"permission_service_notebook_label\">Google Notebook</string>\n    <string name=\"permission_service_sierra_label\">Google-Checkout-Konten</string>\n    <string name=\"permission_service_sierra_description\">Ermöglicht der App den Zugriff auf die Google-Checkout-Konten über ein beliebiges verbundenes Google-Konto.</string>\n    <string name=\"permission_service_sierraqa_label\">Google-Checkout-QA-Konten</string>\n    <string name=\"permission_service_sierraqa_description\">Ermöglicht der App den Zugriff auf die Google-Checkout-QA-Konten über ein beliebiges verbundenes Google-Konto.</string>\n    <string name=\"permission_service_sierrasandbox_label\">Google-Checkout-Sandbox-Konten</string>\n    <string name=\"permission_service_sitemaps_label\">Google Webmaster Tools</string>\n    <string name=\"permission_service_sitemaps_description\">Ermöglicht der App den Zugriff auf die Google Webmaster Tools über ein beliebiges verbundenes Google-Konto.</string>\n    <string name=\"permission_service_speech_description\">Ermöglicht der App den Zugriff auf die Sprachsuche über ein beliebiges verbundenes Google-Konto.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller.readonly\">Lies deine Ad-Exchange-Daten</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appengine.admin\">Umfang des App-Engine-Administrators.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.settings\">Lese und verwalte die Einstellungen einer Google-Apps-Gruppe</string>\n    <string name=\"permission_service_health_description\">Erlaubt App, durch jedes verbundene Google-Konto auf Google Health zuzugreifen.</string>\n    <string name=\"permission_service_notebook_description\">Ermöglicht der App den Zugriff auf Google Notebook über ein beliebiges verbundenes Google-Konto.</string>\n    <string name=\"permission_service_sierrasandbox_description\">Ermöglicht der App den Zugriff auf die Google-Checkout-Sandbox-Konten über ein beliebiges verbundenes Google-Konto.</string>\n    <string name=\"permission_service_speechpersonalization_description\">Ermöglicht der App den Zugriff auf die personalisierte Spracherkennung über ein beliebiges verbundenes Google-Konto.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller\">Lies und verwalte deine Ad-Exchange-Daten</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.full_control\">Verwalte deine Daten und Berechtigungen in Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order\">Für den Lese-/Schreibzugriff von Wiederverkäufer-Administratoren und Benutzer beim Testen in der API-Sandbox oder dem Lese-/Schreibzugriff beim direkten Aufruf einer API-Operation.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order.readonly\">Zusätzlich zum allgemeinen OAuth-Lese-/Schreibbereich solltest du den OAuth-Lesebereich verwenden, wenn du die Daten des Kunden abrufst.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_urlshortener\">Verwalte deine goo.gl-Kurz-URLs</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.buyer\">Verwalte die Konfiguration deines Käuferkontos auf Ad Exchange</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appstate\">Umfang für die Verwendung des App-State-Dienstes.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery.readonly\">Einsehen deiner Daten in Google BigQuery</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery\">Deine Daten in Google BigQuery einsehen und verwalten</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps_reporting_audit.readonly\">Zugriff auf die Admin-Audit-API ReadOnly</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables\">Verwalte deine Fusion Tables</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables.readonly\">Deine Fusion Tables ansehen</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_games\">Umfang für den Zugriff aus Daten von Google-Play-Spielen.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine\">Deine Google-Maps-Engine-Daten einsehen und verwalten</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_dfareporting\">Deine DoubleClick-for-Advertisers-Berichte einsehen und verwalten</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate.readonly\">Deine Google-Coordinate-Jobs einsehen</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute.readonly\">Deine Google-Compute-Engine-Ressourcen einsehen</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute\">Deine Google-Compute-Engine-Ressourcen einsehen und verwalten</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine.readonly\">Deine Google-Maps-Engine-Daten einsehen</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mobilemaps.firstparty\">Deine Erfahrung mit Google Maps für unterwegs einsehen und verwalten</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_structuredcontent\">Lese-/Schreibzugriff auf die Shopping-Content-API.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue.consumer\">Aufgaben aus deinen Taskqueues verarbeiten</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tracks\">Google-Maps-Tracks-API, dieser Umfang erlaubt Lese- und Schreibzugriff auf deine Projektdaten.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics_monetary.readonly\">Sieh dir eine YouTube-Analytics-Finanzberichte zu deinen YouTube-Inhalten an</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_glass.timeline\">Umfang des Glass-Verlaufs</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate\">Deine Google-Maps-Coordinate-Jobs einsehen und verwalten</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_cloudprint\">Deine Google-Cloud-Print-Daten einsehen und verwalten</string>\n    <string name=\"perm_activity_recognition_description\">Ermöglicht es einer App, regelmäßige Aktualisierungen deines Aktivitätsniveaus von Google zu erhalten, z. B. ob du gehst, fährst, radelst oder stehst.</string>\n    <string name=\"perm_activity_recognition_label\">Aktivitätserkennung</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-de/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2017 microG Project Team\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  --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <plurals name=\"pref_unifiednlp_summary\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> Backend eingestellt</item>\n        <item quantity=\"other\"><xliff:g example=\"3\">%1$d</xliff:g> Backends eingestellt</item>\n    </plurals>\n    <plurals name=\"gcm_registered_apps_counter\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> registrierte App</item>\n        <item quantity=\"other\"><xliff:g example=\"123\">%1$d</xliff:g> registrierte Apps</item>\n    </plurals>\n    <plurals name=\"cond_perm_summary\">\n        <item quantity=\"one\">Eine Berechtigung, die für die ordnungsgemäße Funktionalität der microG-Dienste benötigt wird, ist nicht erteilt worden.</item>\n        <item quantity=\"other\">Berechtigungen, die für die ordnungsgemäße Funktionalität der microG-Dienste benötigt werden, sind nicht erteilt worden.</item>\n    </plurals>\n    <plurals name=\"cond_perm_action\">\n        <item quantity=\"one\">Fehlende Berechtigung anfragen</item>\n        <item quantity=\"other\">Fehlende Berechtigungen anfragen</item>\n    </plurals>\n</resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-de/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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  --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"gms_app_name\">microG-Dienste</string>\n    <string name=\"gms_settings_name\">microG-Einstellungen</string>\n    <string name=\"gms_settings_summary\">microG-Dienste einrichten.</string>\n    <string name=\"just_a_sec\">Einen kurzen Moment…</string>\n    <string name=\"google_account_label\">Google</string>\n    <string name=\"ask_permission_tos\">Durch Fortsetzen erlaubst du dieser App und Google, deine Informationen nach ihren entsprechenden AGB und Datenschutzrichtlinien zu nutzen.</string>\n    <string name=\"ask_scope_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> versucht:</string>\n    <string name=\"ask_service_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> versucht zu nutzen:</string>\n    <string name=\"account_manager_title\">Google-Konto-Manager</string>\n    <string name=\"sorry\">Entschuldigung…</string>\n    <string name=\"auth_before_connect\">Eine App auf Ihrem Gerät versucht, sich bei einem Google-Konto anzumelden.\\n\\nWenn dies beabsichtigt war, verwenden Sie die Schaltfläche <b>Anmelden</b>, um zur Anmeldeseite von Google zu gelangen. Andernfalls drücken Sie <b>Abbrechen</b>, um zur Anwendung zurückzukehren, die diesen Dialog verursacht hat.</string>\n    <string name=\"auth_sign_in\">Einloggen</string>\n    <string name=\"auth_connecting\">\"Dein Gerät verbindet sich mit den Google-Servern, um dich einzuloggen\n\nDies kann etwas dauern.\"</string>\n    <string name=\"no_network_error_desc\">Du hast keine Netzwerkverbindung. \\n \\nDies könnte ein temporäres Problem sein, oder dein Android-Gerät hat keine bestehende Datenverbindung. Versuche es noch einmal, wenn du mit einem Datennetz oder WLAN verbunden bist.</string>\n    <string name=\"auth_general_error_desc\">Es ist ein Problem bei der Kommunikation mit den Google-Servern aufgetreten.\\n\\nVersuche es später noch einmal.</string>\n    <string name=\"auth_finalize\">Dein Gerät verbindet sich mit Google, um Informationen in deinem Konto zu speichern. \\n \\nDies kann einige Minuten dauern.</string>\n    <string name=\"allow\">Erlauben</string>\n    <string name=\"deny\">Ablehnen</string>\n    <string name=\"auth_notification_title\">Authentifizierung erforderlich</string>\n    <string name=\"auth_notification_content\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> erfordert deine Autorisierung, um auf dein Google-Konto zuzugreifen.</string>\n    <string name=\"perm_status_broadcast_label\">Empfange interne Statusmeldungen</string>\n    <string name=\"perm_c2dm_receive_label\">Empfange C2DM-Nachrichten</string>\n    <string name=\"perm_c2dm_send_label\">Sende C2DM-Nachrichten an andere Apps</string>\n    <string name=\"perm_gtalk_svc_label\">Sende Nachrichten an und empfange Benachrichtigungen von Google-Servern</string>\n    <string name=\"perm_extended_access_label\">Erweiterter Zugriff zu Google-Diensten</string>\n    <string name=\"perm_provision_label\">Stelle microG-Dienste bereit</string>\n    <string name=\"perm_provision_description\">Erlaubt der app, microG-Dienste ohne Benutzerinteraktion zu konfigurieren</string>\n    <string name=\"service_name_checkin\">Google-Geräte-Registrierung</string>\n    <string name=\"service_name_mcs\">Cloud-Messaging</string>\n    <string name=\"service_name_snet\">Google SafetyNet</string>\n    <string name=\"games_title\">Google-Play-Spiele</string>\n    <string name=\"games_info_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> möchte Play Games benutzen</string>\n    <string name=\"games_info_content\">Um Play Games zu nutzen, ist die Installation der Google-Play-Games-App erforderlich. Diese App funktioniert eventuell auch ohne Play Games, verhält sich dabei unter Umständen aber ungewöhnlich.</string>\n    <string name=\"pick_place_title\">Ort auswählen</string>\n    <string name=\"pick_place_desc\">Ortsauswahl ist noch nicht verfügbar.</string>\n    <string name=\"place_picker_select_title\">Diesen Ort auswählen</string>\n    <string name=\"place_picker_nearby_places\">Orte in der Nähe</string>\n    <string name=\"place_picker_location_lat_lng\">(%1$.7f, %2$.7f)</string>\n    <string name=\"lacking_permission_toast\">microG Services: Berechtigung für \"<xliff:g example=\"Auf alle Netzwerke zugreifen\">%1$s</xliff:g>\" fehlt</string>\n    <string name=\"network_type_mobile\">Mobiles Internet</string>\n    <string name=\"network_type_wifi\">WLAN</string>\n    <string name=\"network_type_roaming\">Roaming</string>\n    <string name=\"network_type_other\">Sonstige Netwerke</string>\n    <!-- Self check -->\n    <string name=\"self_check_cat_fake_sig\">Signaturtäuschungs-Unterstützung</string>\n    <string name=\"self_check_cat_gms_packages\">Installierte Pakete</string>\n    <string name=\"self_check_cat_system\">System</string>\n    <string name=\"self_check_name_fake_sig_perm\">System unterstützt Signaturtäuschung:</string>\n    <string name=\"self_check_resolution_fake_sig_perm\">Dein ROM hat keine integrierte Unterstützung für Signaturtäuschung. Du kannst aber auch externe Systeme zur Signaturtäuschung nutzen. Bitte schaue in die Dokumentation für Informationen zur Signaturtäuschung und wie du microG auf ROMs nutzt, die sie nicht unterstützen.</string>\n    <string name=\"self_check_name_perm_granted\">Berechtigung zur Signaturtäuschung erteilt:</string>\n    <string name=\"self_check_resolution_perm_granted\">Dies ist ein guter Hinweis darauf, dass dein ROM Signaturtäuschung unterstützt, jedoch zunächst eine Aktion notwendig ist, um sie zu aktivieren. Bitte lies die Dokumentation, um herauszufinden, welche Aktion dies ist.</string>\n    <string name=\"self_check_name_system_spoofs\">System täuscht Signatur:</string>\n    <string name=\"self_check_resolution_system_spoofs\">Bitte lies die Dokumentation für weitere Anweisungen.</string>\n    <string name=\"self_check_pkg_gms\">microG-Dienste</string>\n    <string name=\"self_check_pkg_vending\">microG Companion / Play Store</string>\n    <string name=\"self_check_pkg_gsf\">microG-Dienste-Framework</string>\n    <string name=\"self_check_name_app_installed\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> installiert:</string>\n    <string name=\"self_check_resolution_app_installed\">Installiere die App <xliff:g example=\"F-Droid\">%1$s</xliff:g> oder eine kompatible. Bitte schaue in der Dokumentation nach, um herauszufinden, welche Apps kompatibel sind.</string>\n    <string name=\"self_check_name_correct_sig\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> hat die richtige Signatur:</string>\n    <string name=\"self_check_resolution_correct_sig\">Entweder ist das installierte <xliff:g example=\"F-Droid\">%1$s</xliff:g> nicht mit microG kompatibel oder Signaturtäuschung wurde dafür nicht aktiviert. Mehr Infos in der Dokumentation.</string>\n    <string name=\"self_check_name_battery_optimizations\">Batterieoptimierung deaktiviert:</string>\n    <string name=\"self_check_resolution_battery_optimizations\">Hier drücken, um Batterieoptimierungen für microG zu deaktivieren. Wenn das nicht geschieht, funktionieren einige Apps nicht ordnungsgemäß.</string>\n    <!-- Settings strings -->\n    <string name=\"prefcat_about\">Infos</string>\n    <string name=\"prefcat_components\">Komponenten</string>\n    <string name=\"prefcat_configuration\">Konfiguration</string>\n    <string name=\"prefcat_google_services\">Google-Dienste</string>\n    <string name=\"prefcat_location_service\">Standortdienst</string>\n    <string name=\"prefcat_services\">Dienste</string>\n    <string name=\"prefcat_test\">Test</string>\n    <string name=\"cond_gcm_bat_title\">Batterieoptimierung aktiv</string>\n    <string name=\"cond_gcm_bat_summary\">Cloud Messaging ist aktiv, aber Batterieoptimierungen wurden für microG nicht deaktiviert. Damit Push-Nachrichten zugestellt werden können, muss Batterieoptimierung deaktiviert werden.</string>\n    <string name=\"cond_gcm_bat_action\">Batterieoptimierung deaktivieren</string>\n    <string name=\"cond_perm_title\">Berechtigung fehlt</string>\n    <string name=\"prefs_account\">Kontoeinstellungen</string>\n    <string name=\"prefs_account_privacy\">Persönliche Daten &amp; Privatsphäre</string>\n    <string name=\"prefs_account_security\">Anmeldung &amp; Sicherheit</string>\n    <string name=\"pref_auth_trust_google_title\">Vertraue Google bei App-Berechtigungen</string>\n    <string name=\"pref_auth_trust_google_summary\">Wenn deaktiviert, wird der Nutzer gefragt, bevor die Autorisierungsanfrage einer App an Google gesendet wird. Einige Apps können das Google-Konto nicht verwenden, wenn dies deaktiviert ist.</string>\n    <string name=\"pref_auth_visible_title\">Apps erlauben, Konten zu finden</string>\n    <string name=\"pref_auth_visible_summary\">Wenn aktiviert, können alle Apps auf diesem Gerät die E-Mail-Adressen deiner Google-Konten ohne vorherige Autorisierung einsehen.</string>\n    <string name=\"pref_checkin_enable_summary\">Registriert dein Gerät bei den Google-Diensten und erstellt eine eindeutige Gerätekennung. microG entfernt andere identifizierende Elemente außer deinem Google-Kontonamen aus den Registrierungsdaten.</string>\n    <string name=\"checkin_not_registered\">Nicht registiert</string>\n    <string name=\"checkin_last_registration\">Letzte Registierung: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"checkin_enable_switch\">Gerät registrieren</string>\n    <!-- test -->\n    <string name=\"pref_info_status\">Status</string>\n    <string name=\"pref_more_settings\">Mehr</string>\n    <string name=\"pref_add_account_title\">Konto</string>\n    <string name=\"pref_add_account_summary\">Google-Konto hinzufügen</string>\n    <string name=\"pref_gcm_enable_mcs_summary\">Cloud Messaging ist ein Push-Nachrichten-Dienst, der von vielen Apps genutzt wird. Zur Benutzung muss die Geräte-Registrierung aktiviert werden.</string>\n    <string name=\"pref_gcm_heartbeat_title\">Cloud-Messaging-Hearbeat-Intervall</string>\n    <string name=\"pref_gcm_heartbeat_summary\">Das Intervall in Sekunden, in dem das System die Google-Server kontaktiert. Ein höheres Intervall wird die Akkunutzung reduzieren, kann jedoch Push-Nachrichten verzögern.\\nVeraltet, wird in zukünftiger Version ersetzt.</string>\n    <string name=\"pref_gcm_apps_title\">Apps die Cloud Messaging benutzen</string>\n    <string name=\"pref_gcm_apps_summary\">Liste der für Cloud Messaging registierten Apps.</string>\n    <string name=\"pref_gcm_confirm_new_apps_title\">Neue Apps bestätigen</string>\n    <string name=\"pref_gcm_confirm_new_apps_summary\">Frage nach, bevor neue Apps sich für Push-Nachrichten registrieren</string>\n    <string name=\"pref_gcm_ping_interval\">Abfrage-Intervall: <xliff:g example=\"10 minutes\">%1$s</xliff:g></string>\n    <string name=\"pref_about_title\">Über microG Services</string>\n    <string name=\"pref_about_summary\">Versionsinformation und genutzte Bibliotheken</string>\n    <string name=\"gcm_app_error_unregistering\">Fehler bei der Abmeldung</string>\n    <string name=\"gcm_app_not_installed_anymore\">Nicht mehr installiert</string>\n    <string name=\"gcm_unregister_app\">Deregistrieren</string>\n    <string name=\"gcm_not_registered\">Nicht registriert</string>\n    <string name=\"gcm_no_message_yet\">Bisher keine Nachrichten erhalten</string>\n    <string name=\"gcm_last_message_at\">Letzte Nachricht: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_registered\">Registriert</string>\n    <string name=\"gcm_registered_since\">Registriert seit: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_unregister_confirm_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> abmelden?</string>\n    <string name=\"gcm_unregister_confirm_message\">Einige Apps registrieren sich nicht automatisch erneut und haben keine Möglichkeit, dies manuell anzustoßen. Diese Apps funktionieren eventuell nach dem Abmelden nicht mehr richtig.\n\\nFortsetzen?</string>\n    <string name=\"gcm_unregister_after_deny_message\">Du hast einer App die Erlaubnis der Registrierung entzogen, die bereits registriert ist.\n\\nWillst du diese App jetzt auch abmelden, damit sie zukünftig keine Push-Nachrichten erhält?</string>\n    <string name=\"gcm_messages_counter\">Nachrichten: <xliff:g example=\"123\">%1$d</xliff:g> (<xliff:g example=\"12345\">%2$d</xliff:g> bytes)</string>\n    <string name=\"gcm_network_state_disconnected\">Nicht verbunden</string>\n    <string name=\"gcm_network_state_connected\">Verbunden seit <xliff:g example=\"2 hours ago\">%1$s</xliff:g></string>\n    <string name=\"gcm_enable_switch\">Push-Nachrichten erhalten</string>\n    <string name=\"pref_push_app_allow_register_title\">Registrierung erlauben</string>\n    <string name=\"pref_push_app_allow_register_summary\">Erlaubt es der App, sich für Push-Nachrichten zu registrieren.</string>\n    <string name=\"pref_push_app_wake_for_delivery_title\">App beim Erhalt einer Push-Nachricht starten</string>\n    <string name=\"pref_push_app_wake_for_delivery_summary\">App starten, während im Hintergrund die eingehenden Nachrichten abgerufen werden.</string>\n    <string name=\"prefcat_push_apps_title\">Apps, die Push-Nachrichten benutzen</string>\n    <string name=\"prefcat_push_apps_registered_title\">Registrierte Apps</string>\n    <string name=\"prefcat_push_apps_unregistered_title\">Nicht-registrierte Apps</string>\n    <string name=\"prefcat_push_networks_title\">Für Push-Benachrichtigungen zu verwendende Netzwerke</string>\n    <string name=\"safetynet_intro\">Google SafetyNet ist ein System, um Geräte zu zertifizieren und so sicherzustellen, dass sie ausreichend geschützt und kompatibel mit Android sind. Einige Anwendungen benutzen SafetyNet aus Sicherheitsgründen oder um einen Kopierschutz zu erzwingen.\\n\\nmicroG GmsCore enthält eine freie Implementierung von SafetyNet, jedoch verlangen die Google-Server, dass die Anfragen durch das proprietäre DroidGuard signiert sind.</string>\n    <string name=\"safetynet_enable_switch\">Geräte-Zertifizierung erlauben</string>\n    <string name=\"pref_safetynet_test_title\">SafetyNet-Zertifizierung testen</string>\n    <string name=\"pref_droidguard_operation_mode\">Betriebsmodus</string>\n    <string name=\"signin_picker_add_account_label\">Weiteres Konto hinzufügen</string>\n    <string name=\"signin_confirm_button_text\">Erlauben und teilen</string>\n    <string name=\"pref_auth_include_android_id_title\">Authentifizierung mit Geräteregistrierung</string>\n    <string name=\"pref_auth_include_android_id_summary\">Wenn deaktiviert, werden Authentifizierungsanfragen nicht mit der Geräteregistrierung verknüpft, was nicht autorisierten Geräten die Anmeldung ermöglicht, aber auch unvorhergesehene Folgen haben kann.</string>\n    <string name=\"pref_test_summary_passed\">Alle Tests bestanden</string>\n    <string name=\"pref_test_summary_failed\">Fehlgeschlagen: %s</string>\n    <string name=\"pref_test_summary_warn\">Warnung: %s</string>\n    <string name=\"pref_test_summary_running\">Läuft…</string>\n    <string name=\"prefcat_safetynet_apps_title\">Apps, die SafetyNet verwenden</string>\n    <string name=\"safetynet_last_run_at\">Letzte Nutzung: <xliff:g example=\"Gestern, 14:20\">%1$s</xliff:g></string>\n    <string name=\"profile_name_native\">Nativ</string>\n    <string name=\"profile_name_real\">Real</string>\n    <string name=\"profile_name_user\">Benutzerdefiniert: %s</string>\n    <string name=\"profile_name_system\">System: %s</string>\n    <string name=\"pref_device_registration_import_custom_profile_title\">Benutzerdefiniertes Profil importieren</string>\n    <string name=\"pref_device_registration_serial_title\">Seriennummer</string>\n    <string name=\"pref_device_registration_select_profile_title\">Profil auswählen</string>\n    <string name=\"pref_safetynet_recent_uses\">Kürzliche Verwendungen</string>\n    <string name=\"pref_safetynet_recent_attestation_summary\">Attestierung: %s</string>\n    <string name=\"pref_safetynet_recent_eval_type\">Evaluationstyp</string>\n    <string name=\"pref_safetynet_recent_response_status\">Antwortstatus</string>\n    <string name=\"pref_safetynet_recent_cat_response\">Antwortdaten</string>\n    <string name=\"pref_safetynet_recent_cat_request\">Daten anfordern</string>\n    <string name=\"pref_safetynet_recent_nonce\">Nonce (Hex)</string>\n    <string name=\"pref_safetynet_recent_request_time\">Uhrzeit der Anfrage</string>\n    <string name=\"pref_safetynet_recent_request_type\">Anfragetyp</string>\n    <string name=\"push_notifications_summary_values_minutes\">%s Minuten</string>\n    <string name=\"pref_vending_licensing_enable_switch\">Lizenzprüfungsanfragen beantworten</string>\n    <string name=\"pref_vending_summary_licensing_on\">Lizenzvergabe ein</string>\n    <string name=\"pref_vending_summary_licensing_off\">Lizenzvergabe aus</string>\n    <string name=\"gcm_allow_app_popup\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> die Registrierung für Push-Benachrichtigungen erlauben?</string>\n    <string name=\"service_name_vending\">Play-Store-Dienste</string>\n    <string name=\"menu_clear_recent_requests\">Kürzlich gestellte Anfragen löschen</string>\n    <string name=\"pref_droidguard_unsupported_summary\">Die Ausführung von DroidGuard wird auf diesem Gerät nicht unterstützt. SafetyNet-Dienste verhalten sich möglicherweise fehlerhaft.</string>\n    <string name=\"profile_name_auto\">Automatisch: %s</string>\n    <string name=\"pref_device_registration_import_custom_profile_summary\">Geräteprofil aus Datei importieren</string>\n    <string name=\"pref_safetynet_recent_advice\">Hinweis</string>\n    <string name=\"pref_device_registration_device_profile_category\">Geräteprofil</string>\n    <string name=\"pref_safetynet_recent_recaptcha_summary\">ReCaptcha: %s</string>\n    <string name=\"pref_safetynet_recent_cat_basic\">Grundlegende Daten</string>\n    <string name=\"pref_safetynet_test_cts_failed\">CTS fehlgeschlagen</string>\n    <string name=\"pref_safetynet_test_integrity_failed\">Integrität fehlgeschlagen</string>\n    <string name=\"pref_safetynet_test_not_completed\">Noch nicht abgeschlossen</string>\n    <string name=\"pref_safetynet_test_no_result\">Kein Ergebnis</string>\n    <string name=\"pref_safetynet_test_invalid_json\">Ungültiges JSON</string>\n    <string name=\"push_notifications_summary_off\">AUS</string>\n    <string name=\"push_notifications_summary_automatic\">EIN / Automatisch: %s</string>\n    <string name=\"pref_safetynet_recent_token\">Token</string>\n    <string name=\"pref_safetynet_test_integrity_cts_passed\">Integrität und CTS bestanden</string>\n    <string name=\"push_notifications_summary_manual\">EIN / Manuell: %s</string>\n    <string name=\"pref_safetynet_recent_copy_json\">JSON-JWS-Daten kopieren</string>\n    <string name=\"pref_safetynet_recent_copied\">In die Zwischenablage kopiert!</string>\n    <string name=\"push_notifications_summary_values_seconds\">%s Sekunden</string>\n    <string name=\"signin_picker_subtitle\">weiter zu <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"signin_subtext_sharing\">Um fortzufahren, wird microG Name, E-Mail-Adresse und Profilbild deines Google-Kontos mit <xliff:g example=\"F-Droid\">%1$s</xliff:g> teilen.</string>\n    <string name=\"pref_vending_license_enable_summary\">Einige Apps erfordern einen Nachweis, dass du sie auf Google Play gekauft hast. Wenn dies von einer App verlangt wird, kann microG einen Kaufnachweis von Google herunterladen. Wenn deaktiviert oder kein Google-Konto hinzugefügt wurde, werden Anfragen zur Lizenzverifizierung ignoriert.</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_switch\">Kostenfreie Apps automatisch zur Mediathek hinzufügen</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_summary\">Kostenfreie Apps können prüfen, ob sie aus dem Google-Play-Store bezogen wurden. Wenn du kostenfreie Apps automatisch zur Konto-Mediathek hinzufügst, wird dieser Test für alle Apps bestanden, die kostenlos und für dich derzeit verfügbar sind.</string>\n    <string name=\"pref_recaptcha_test_title\">ReCAPTCHA testen</string>\n    <string name=\"signin_picker_title\">Ein Konto auswählen</string>\n    <string name=\"signin_subtext_policy_privacy\">Datenschutzerklärung</string>\n    <string name=\"signin_confirm_title\">Anmeldung bei <xliff:g example=\"F-Droid\">%1$s</xliff:g> zulassen</string>\n    <string name=\"signin_subtext_policy\">Bevor du diese App benutzt, solltest du %1$s und %2$s überprüfen.</string>\n    <string name=\"signin_subtext_policy_terms\">Nutzungsbedingungen</string>\n    <string name=\"perm_gsf_read_gservices_label\">Google-Dienstkonfiguration lesen</string>\n    <string name=\"perm_car_speed_label\">Geschwindigkeit des Autos</string>\n    <string name=\"perm_car_speed_description\">Zugriff auf die Geschwindigkeit deines Autos</string>\n    <string name=\"perm_car_info_label\">Informationen zum Auto</string>\n    <string name=\"perm_car_info_description\">Zugriff auf die Informationen deines Autos</string>\n    <string name=\"perm_car_fuel_label\">Kraftstoffstand des Autos</string>\n    <string name=\"perm_car_fuel_description\">Zugriff auf die Informationen zum Kraftstoffstand deines Autos</string>\n    <string name=\"perm_car_mileage_label\">Kilometerstand des Autos</string>\n    <string name=\"perm_car_mileage_description\">Zugriff auf die Informationen zum Kilometerstand deines Autos</string>\n    <string name=\"perm_car_vendor_extension_label\">Kanal für Autoverkäufer</string>\n    <string name=\"perm_car_vendor_extension_description\">Zugriff auf den Kanal für Autoverkäufer zum Austausch fahrzeugspezifischer Informationen</string>\n    <string name=\"credentials_assisted_sign_back_title\">Melde dich wieder bei %1$s mit Google an</string>\n    <string name=\"credentials_assisted_continue\">Fortsetzen</string>\n    <string name=\"credentials_assisted_cancel\">Abbrechen</string>\n    <string name=\"credentials_assisted_continue_as_user_button_label\">Als %1$s fortfahren</string>\n    <string name=\"credentials_assisted_signin_consent\">Wenn du fortfährst, wird Google deinen Namen, deine E-Mail-Adresse und dein Profilbild mit %1$s teilen. Siehe die Datenschutzbestimmungen und Nutzungsbedingungen von %1$s.</string>\n    <string name=\"credentials_assisted_signin_description\">„Über Google anmelden“ kannst du in deinen Google-Konten verwalten.</string>\n    <string name=\"credentials_assisted_choose_account_label\">Konto auswählen</string>\n    <string name=\"credentials_assisted_signin_button_text_long\">Über Google anmelden</string>\n    <string name=\"pref_accounts_title\">Google-Konten</string>\n    <string name=\"pref_accounts_summary\">Google-Konten hinzufügen und verwalten</string>\n    <string name=\"prefcat_accounts_settings_title\">Einstellungen</string>\n    <string name=\"prefcat_accounts_current_accounts_title\">Konten</string>\n    <string name=\"feedback_disabled\">Rückmeldung derzeit nicht möglich</string>\n    <string name=\"pref_vending_licensing_category\">Google-Play-Lizenzierung</string>\n    <string name=\"pref_vending_billing_category\">Google-Play-Abrechnung</string>\n    <string name=\"pref_vending_billing_note_experimental\">Diese Funktion ist experimentell und kann zu finanziellem Schaden führen. Du wurdest gewarnt.</string>\n    <string name=\"pref_vending_billing_note_licensing\">Bei einigen Apps musst du möglicherweise auch die Lizenzverifizierung aktivieren, um deine Einkäufe zu verifizieren.</string>\n    <string name=\"pref_vending_billing_enable_summary\">Sobald aktiviert, können einige Apps Käufe oder Abonnements über den Google-Play-Abrechnungsdienst abschließen.</string>\n    <string name=\"backup_disabled\">Datensicherung derzeit nicht möglich</string>\n    <string name=\"pref_device_registration_android_id\">Android-ID</string>\n    <string name=\"pref_recaptcha_enterprise_test_title\">ReCAPTCHA Enterprise testen</string>\n    <string name=\"pref_safetynet_recent_recaptcha_enterprise_summary\">ReCaptcha Enterprise: %s</string>\n    <string name=\"pref_auth_strip_device_name_title\">Gerätename zur Authentifizierung entfernen</string>\n    <string name=\"pref_auth_strip_device_name_summary\">Wenn aktiviert, enthalten die Authentifizierungsanfragen nicht den Gerätenamen, wodurch sich nicht autorisierte Geräte anmelden können, was jedoch unvorhergesehene Folgen haben kann.</string>\n    <string name=\"credentials_assisted_signin_consent_header\">Anmelden als %1$s</string>\n    <string name=\"credentials_assisted_confirmation_header\">Du wirst angemeldet</string>\n    <string name=\"credentials_assisted_choose_account_subtitle\">weiter zu %1$s</string>\n    <string name=\"auth_package_override_request_message\"><b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> möchte auf Ihr Konto zugreifen, als wäre es <b><xliff:g example=\"F-Droid\">%2$s</xliff:g> von <xliff:g example=\"F-Droid Inc.\">%3$s</xliff:g></b>. Dadurch erhält es möglicherweise privilegierten Zugriff auf Ihr Konto.</string>\n    <string name=\"auth_package_override_request_title\"><b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> privilegierten Zugriff auf <xliff:g example=\"account@example.com\">%2$s</xliff:g> erlauben?</string>\n    <string name=\"pref_vending_billing_enable_switch\">Rechnungsanfragen abwickeln</string>\n    <string name=\"limited_services_app_name\">Limitierte microG-Dienste</string>\n    <string name=\"auth_action_step_enable_lockscreen_description\">Dein Google-Konto wird von deinem Arbeitsplatz oder deiner Bildungseinrichtung verwaltet. Dein Administrator hat entschieden, dass Geräte eine sichere Bildschirmsperre benötigen, bevor sie auf Kontodaten zugreifen können.\\n\\nBitte richte eine Passwort-, PIN- oder Muster-Bildschirmsperre ein.</string>\n    <string name=\"auth_action_notification_channel_name\">Google-Konto-Warnungen</string>\n    <string name=\"auth_action_notification_title\">Kontoaktion erforderlich</string>\n    <string name=\"auth_action_notification_channel_description\">Benachrichtigt dich, wenn eines deiner Google-Konten zusätzliche Einrichtung erfordert, bevor es verwendet werden kann, oder wenn ein Konto nicht mit microG kompatibel ist.</string>\n    <string name=\"auth_action_notification_content\">Dein Google-Konto muss zusätzlich eingerichtet werden.</string>\n    <string name=\"auth_action_activity_header\">Beende das Einrichten deines Google-Kontos</string>\n    <string name=\"auth_action_activity_explanation\">Führe die folgenden Schritte aus, um dein Google-Konto %s auf diesem Gerät verwenden zu können.</string>\n    <string name=\"auth_action_step_enable_checkin\">Geräteregistrierung aktivieren</string>\n    <string name=\"auth_action_step_enable_gcm\">Cloud-Messaging aktivieren</string>\n    <string name=\"auth_action_step_enable_gcm_description\">Du kannst Cloud-Messaging nach Abschluss der Kontoeinrichtung deaktivieren.</string>\n    <string name=\"auth_action_step_allow_microg_gcm\">Cloud-Messaging für microG zulassen</string>\n    <string name=\"auth_action_step_enable_checkin_description\">Dein Gerät muss sich mindestens einmal bei Google registrieren.\\n\\nDu kannst die Google-Geräteregistrierung deaktivieren, nachdem die Kontoeinrichtung abgeschlossen ist.</string>\n    <string name=\"auth_action_step_allow_microg_gcm_description\">Gemäß deinen Einstellungen benötigt microG eine Erlaubnis von dir, bevor es sich für Cloud-Messaging registrieren kann.</string>\n    <string name=\"auth_action_step_enable_lockscreen\">Sichere Bildschirmsperre konfigurieren</string>\n    <string name=\"auth_action_step_perform_content_description\">Zum Ausführen des Schritts anklicken</string>\n    <string name=\"auth_action_step_completed_content_description\">Schritt abgeschlossen</string>\n    <string name=\"auth_action_activity_finish\">Fertigstellen</string>\n    <string name=\"limited_services_dialog_information\">Du verwendest die begrenzten microG-Dienste. Im Gegensatz zu den normalen microG-Diensten funktioniert diese Variante nur mit Apps, die microG-Bibliotheken verwenden, nicht mit denen von Google Play. Das bedeutet, dass die meisten Anwendungen diese Dienste ignorieren werden.</string>\n    <string name=\"limited_services_dialog_information_ack\">Ich habe es verstanden</string>\n    <string name=\"pref_vending_asset_device_sync_switch\">Synchronisierung von Geräteinformationen aktivieren</string>\n    <string name=\"pref_vending_asset_device_sync_summary\">Anwendungen, die die Play-Asset-Bereitstellung verwenden, laden zusätzliche Assets auf der Grundlage der Informationen des aktuell verwendeten Geräts herunter.</string>\n    <string name=\"games_achievement_list_title\">Errungenschaften</string>\n    <string name=\"games_achievements_empty_text\">Keine Errungenschaften für dieses Spiel</string>\n    <string name=\"games_achievement_locked_content_description\">gesperrt</string>\n    <string name=\"games_api_access_denied\">Kein Konto auf diesem Gerät kann auf die Spiele-APIs zugreifen</string>\n    <string name=\"games_achievement_unlocked_content_description\">entsperrt</string>\n    <string name=\"games_achievement_extra_text\">%1$s XP</string>\n    <string name=\"games_leaderboard_empty_text\">Keine Bestenlisten für dieses Spiel</string>\n    <string name=\"games_leaderboard_score_empty_text\">Unglaublich! Es gibt keine öffentlichen Highscores für dieses Spiel.</string>\n    <string name=\"games_leaderboard_list_title\">Ranglisten</string>\n    <string name=\"games_leaderboards_score_label\">Punktestand: %1$s</string>\n    <string name=\"games_snapshot_empty_text\">Es wurden noch keine Spielstände gespeichert</string>\n    <string name=\"games_snapshot_choose_btn_text\">auswählen</string>\n    <string name=\"games_snapshot_delete_btn_text\">löschen</string>\n    <string name=\"games_delete_snapshot_dialog_title\">Gespeicherten Spielstand löschen</string>\n    <string name=\"games_delete_snapshot_dialog_cancel\">Abbrechen</string>\n    <string name=\"games_delete_snapshot_error\">Löschung fehlgeschlagen, bitte versuche es später noch einmal</string>\n    <string name=\"games_delete_snapshot_dialog_ok\">OK</string>\n    <string name=\"games_delete_snapshot_dialog_message\">Bist du sicher, dass du diesen Spielstand löschen möchtest?</string>\n    <string name=\"pref_vending_asset_delivery_category\">Bereitstellung von Google Play Assets</string>\n    <string name=\"pref_vending_asset_delivery_switch\">Asset-Bereitstellung auf Abruf aktivieren</string>\n    <string name=\"pref_vending_asset_delivery_summary\">Herunterladen zusätzlicher Assets, wenn diese von Apps, die die Play-Asset-Bereitstellung verwenden, angefordert werden</string>\n    <string name=\"camera_permission_dialog_title\">Kameraberechtigung erforderlich</string>\n    <string name=\"pref_workprofile_create_account\">Einrichtung eines Arbeitskontos zulassen</string>\n    <string name=\"camera_permission_dialog_button\">OK</string>\n    <string name=\"service_name_work_profile\">Arbeitsprofil</string>\n    <string name=\"camera_permission_dialog_message\">microG-Dienste müssen auf die Kamera deines Geräts zugreifen, um einen Code für %1$s zu scannen.\\n\\nBitte erteile den microG-Diensten in den Einstellungen die Kameraberechtigung, um dies zu ermöglichen.</string>\n    <string name=\"pref_vending_licensing_split_install_summary\">Apps erlauben, zusätzliche Komponenten herunterzuladen und zu installieren</string>\n    <string name=\"pref_vending_split_install_switch\">Komponenteninstallation auf Abruf</string>\n    <string name=\"pref_workprofile_intro\">Wenn du ein Arbeitsprofil für deinen Arbeitsplatz oder deine Bildungseinrichtung einrichtest, könnte die Einrichtung versuchen, eine Verbindung zu Google herzustellen, um das Herunterladen von Apps auf dieses Profil zu ermöglichen.</string>\n    <string name=\"pref_workprofile_disclaimer\">Es liegt in deiner Verantwortung sicherzustellen, dass deine Nutzung von microG mit den Unternehmensrichtlinien übereinstimmt. microG wird nach bestem Wissen und Gewissen bereitgestellt und kann nicht garantieren, dass es sich genau wie erwartet verhält.</string>\n    <string name=\"barcode_scanner_brand\">Gescannt von microG im Auftrag von %1$s</string>\n    <string name=\"pref_vending_feature_delivery\">Google Play Feature Delivery</string>\n    <string name=\"credentials_assisted_choose_account_error_tips\">Kontoanomalie</string>\n    <string name=\"credentials_assisted_signin_add_account\">Konto hinzufügen</string>\n    <string name=\"auth_action_reauth_notification_title\">Kontoaktion erforderlich</string>\n    <string name=\"pref_auth_two_step_verification_title\">Zweistufige Verifizierungsaufforderungen erhalten</string>\n    <string name=\"pref_auth_two_step_verification_summary\">Wenn aktiviert, kann das Gerät zweistufige Verifizierungsaufforderungen von Google erhalten (Cloud Messaging ist erforderlich).</string>\n    <string name=\"pref_game_accounts_title\">Google-Spielkonten</string>\n    <string name=\"pref_auto_create_player\">Play-Games-Kontoregistrierung zulassen</string>\n    <string name=\"pref_auto_create_player_intro\">Wenn du Spiele spielst, musst du dich mit einem Play-Games-Konto anmelden, um spielbezogene Funktionen wie Erfolge, Bestenlisten, Archive usw. aufzuzeichnen. Nach der Deaktivierung werden Google-Konten, die nicht mit einem Play-Games-Konto verknüpft sind, nicht automatisch registriert, und das Spiel kann sich nicht anmelden und spielen.</string>\n    <string name=\"pref_allow_upload_game_played\">Hochladen von gespielten Spielen zulassen</string>\n    <string name=\"pref_allow_upload_game_played_summary\">Wenn deaktiviert, meldet das Spiel nach dem Anmelden nicht den Status des gespielten Spiels, und manche Spiele können sich unter Umständen nicht anmelden.</string>\n    <string name=\"pref_change_default_game_player\">Konto für Spiele ändern</string>\n    <string name=\"pref_change_default_game_player_summary\">Das Standardkonto für Spiele ändern und das Konto für jedes Spiel einzeln ändern.</string>\n    <string name=\"pref_delete_game_account_data\">Play-Games-Daten löschen</string>\n    <string name=\"pref_delete_game_account_data_summary\">Play-Games-Konto und alle Daten sowie individuelle Spieldaten löschen.</string>\n    <string name=\"games_state_description_signed_out\">Abgemeldet</string>\n    <string name=\"games_state_description_delete\">Löschen</string>\n    <string name=\"games_change_button_text\">Ändern</string>\n    <string name=\"games_change_default_account_section_title\">Standardkonto für Spiele ändern</string>\n    <string name=\"games_change_default_account_description\">Standardkonto: %1$s</string>\n    <string name=\"games_change_default_account_explanation\">Dieses Konto wird verwendet, um dich automatisch bei Spielen anzumelden, deinen Spielfortschritt und deine Einstellungen zu speichern. Wenn du das Standardkonto änderst oder dich abmeldest, werden möglicherweise dein Fortschritt und deine Einstellungen für die von dir gespielten Spiele zurückgesetzt.</string>\n    <string name=\"games_change_per_game_title\">Konto für jedes Spiel einzeln ändern</string>\n    <string name=\"games_change_per_game_description\">Das Ändern des Kontos für ein ausgewähltes Spiel oder das Abmelden davon könnte deinen Fortschritt und deine Einstellungen für das Spiel zurücksetzen.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_title\">Wähle eine Option für das neue Standardkonto aus</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_description\">Aktuelles Standardkonto: %1$s</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_title\">Standardkonto nur für neue Spiele ändern</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_description\">Du verlierst nicht den Zugriff auf deinen Spielfortschritt und deine Einstellungen für gespielte Spiele. Allerdings wird dein Spielfortschritt auf mehrere Konten aufgeteilt.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_title\">Standardkonto für alle Spiele ändern</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_description\">Du könntest den Zugriff auf deinen Fortschritt und deine Einstellungen für gespielte Spiele verlieren. Wir starten das Spiel neu, um deine Änderungen zu übernehmen.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_title\">Von allen Spielen abmelden</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_description\">Du könntest den Zugriff auf deinen Fortschritt und deine Einstellungen für gespielte Spiele verlieren. Wir starten das Spiel neu, um deine Änderungen zu übernehmen.</string>\n    <string name=\"games_change_per_game_dialog_title\">Wähle eine Option für dieses Spiel aus</string>\n    <string name=\"games_change_per_game_dialog_description\">Das Ändern des Kontos oder das Abmelden kann deinen Fortschritt und deine Einstellungen für das Spiel zurücksetzen</string>\n    <string name=\"games_change_per_game_dialog_option_use_player\">%1$s verwenden</string>\n    <string name=\"games_change_per_game_dialog_option_use_player_snackbar_success_message\">Du wirst mit %1$s bei diesem Spiel angemeldet</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out\">Abmelden</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out_snackbar_success_message\">Du bist jetzt von diesem Spiel abgemeldet</string>\n    <string name=\"games_change_sign_out_of_all_games_snackbar_success_message\">Du bist jetzt von allen Spielen abgemeldet</string>\n    <string name=\"games_change_default_account_for_all_games_snackbar_success_message\">Du wirst bei allen Spielen mit %1$s angemeldet</string>\n    <string name=\"games_change_default_account_for_new_games_snackbar_success_message\">Du wirst bei neuen Spielen mit %1$s angemeldet</string>\n    <string name=\"games_account_display_content\">Aktuelles Konto: %1$s</string>\n    <string name=\"games_delete_profile_header\">Play-Games-Konto und alle Daten löschen</string>\n    <string name=\"games_delete_profile_explanation\">Dein Google-Play-Games-Konto, XP und alle Profildaten werden endgültig gelöscht. Bei dieser Aktion werden möglicherweise auch deine Spielstände, Fortschritte (gespeicherte Spiele) und Einstellungen in Spielen, die du gespielt hast, gelöscht.</string>\n    <string name=\"games_delete_profile_button\">Endgültig löschen</string>\n    <string name=\"games_delete_game_data_header\">Individuelle Spieldaten löschen</string>\n    <string name=\"games_delete_game_data_explanation\">Du kannst einzelne Daten für Spiele, die du mit Google Play Games gespielt hast, endgültig löschen. Diese Aktion löscht deine Spielstände, Fortschritte (gespeicherte Spiele) und Einstellungen für das von dir ausgewählte Spiel.</string>\n    <string name=\"games_delete_profile_dialog_title\">Bist du sicher, dass du dieses Konto löschen willst?</string>\n    <string name=\"games_delete_profile_dialog_message\">Diese Aktion kann nicht rückgängig gemacht werden.</string>\n    <string name=\"games_delete_profile_fail\">Dein Profil konnte nicht gelöscht werden. Versuche es später noch einmal.</string>\n    <string name=\"games_delete_game_data_confirm_dialog_title\">Daten für %1$s löschen</string>\n    <string name=\"games_delete_game_data_confirm_dialog_message\">Das endgültige Löschen deiner Daten für %1$s entfernt deine Spielstände, Fortschritte (gespeicherte Spiele) und Spieleinstellungen in Google Play Games.</string>\n    <string name=\"games_popup_signin_welcome\">Hallo, %1$s</string>\n    <string name=\"games_delete_profile_explanation_with_gamer_name\">Dein Google-Play-Games-Konto für den Spielernamen <b>%1$s</b> (<b>%2$s</b>), XP und alle Profildaten werden endgültig gelöscht. Bei dieser Aktion werden unter Umständen auch deine Spielstände, dein Fortschritt (gespeicherte Spiele) und deine Einstellungen in den Spielen, die du gespielt hast, gelöscht.</string>\n    <string name=\"family_management_title\">Familie</string>\n    <string name=\"family_management_retry\">Erneut versuchen</string>\n    <string name=\"family_management_load_error\">Laden des Inhalts fehlgeschlagen</string>\n    <string name=\"family_management_toolbar_back\">Zurück</string>\n    <string name=\"family_management_toolbar_more\">Mehr</string>\n    <string name=\"family_management_exit_family_group\">Familiengruppe verlassen</string>\n    <string name=\"family_management_delete_family_group\">Familiengruppe löschen</string>\n    <string name=\"family_management_leave_family_password_title\">Passwort bestätigen, um die Familiengruppe zu verlassen</string>\n    <string name=\"family_management_delete_family_password_title\">Passwort bestätigen, um eine Familiengruppe zu löschen</string>\n    <string name=\"family_management_remove_member_password_title\">Passwort bestätigen, um %s zu entfernen</string>\n    <string name=\"family_management_invite_family_member\">Familienmitglieder einladen</string>\n    <string name=\"family_management_invite_slots_left\">%1$d Einladungen verbleiben</string>\n    <string name=\"family_management_cancel_invite\">Einladung stornieren</string>\n    <string name=\"family_management_cancel_invite_success\">Einladung erfolgreich storniert</string>\n    <string name=\"family_management_cancel_invite_error\">Problem beim Stornieren der Einladung. Versuche es erneut.</string>\n    <string name=\"family_management_remove_member\">Mitglied entfernen</string>\n    <string name=\"family_management_member_removed_success\">%s wurde aus deiner Familiengruppe entfernt</string>\n    <string name=\"family_management_member_remove_failed\">Problem beim Entfernen von %s. Versuche es erneut.</string>\n    <string name=\"family_management_leave_family_error_message\">Probleme beim Verlassen der Familiengruppe. Versuche es erneut.</string>\n    <string name=\"family_management_exist_group_success\">Du hast deine Familiengruppe verlassen…</string>\n    <string name=\"family_management_delete_group_success\">Familiengruppe gelöscht</string>\n    <string name=\"family_management_delete_group_failure\">Heimatgruppe konnte nicht gelöscht werden</string>\n    <string name=\"family_management_delete_group_cancel\">Abbrechen</string>\n    <string name=\"family_management_delete_group_confirm\">OK</string>\n    <string name=\"family_management_input_pwd\">Gib bitte dein Passwort ein</string>\n    <string name=\"family_management_invite_sent_date_format\">Einladung gesendet am %s</string>\n    <string name=\"family_management_invite_send\">Einladung gesendet</string>\n    <string name=\"family_management_pwd_error\">Falsches Passwort, bitte erneut eingeben</string>\n    <string name=\"pref_app_install_settings_title\">Einstellungen des App-Installationsprogramms</string>\n    <string name=\"pref_app_install_switch_title\">App-Installation zulassen</string>\n    <string name=\"pref_app_install_other_apps_note\">Die Autorisierung ermöglicht die Installation von Apps aus anderen Quellen.</string>\n    <string name=\"pref_app_install_permission_instruction\">Um sicherzustellen, dass deine installierten Apps ordnungsgemäß funktionieren, autorisiere bitte microG Companion, Apps zu installieren, die aus anderen Quellen heruntergeladen wurden.</string>\n    <string name=\"location_sharing_turn_off_cancel\">Eingeschaltet lassen</string>\n    <string name=\"location_sharing_turn_off_confirm\">Ausschalten</string>\n    <string name=\"prefcat_app_install_list_title\">Apps, die das App-Installationsprogramm verwenden</string>\n    <string name=\"service_name_google_location_sharing\">Google-Standortfreigabe</string>\n    <string name=\"location_sharing_description\">Verwalte die Echtzeit-Standortfreigabe für Google-Apps und -Dienste von diesem Gerät aus</string>\n    <string name=\"location_sharing_learn_more\">Mehr über die Standortfreigabe erfahren</string>\n    <string name=\"location_sharing_switch_text\">Standortfreigabe verwenden</string>\n    <string name=\"location_sharing_turn_off_notify_hint\">Wenn du die Standortfreigabe für dieses Gerät deaktivierst, werden die Personen, mit denen du deinen Standort teilst, nicht benachrichtigt.</string>\n    <string name=\"location_sharing_off_previous_hint\">Nur dein zuletzt geteilter Standort ist verfügbar, bis du die Funktion wieder aktivierst.</string>\n    <string name=\"location_sharing_disabled\">Keine aktiven Standortfreigaben für dieses Konto</string>\n    <string name=\"location_sharing_turn_on_hint\">Sobald du beginnst, deinen Standort über eine Google-App oder einen Google-Dienst zu teilen, kannst du die Standortfreigabe von hier aus verwalten.\\n\\nUm mit der Standortfreigabe zu beginnen, rufe Google Maps oder Family Link auf.</string>\n    <string name=\"location_sharing_turn_off_title\">Standortfreigabe ausschalten</string>\n    <string name=\"location_sharing_turn_off_hint\">Du könntest deinen Standort immer noch von anderen Geräten aus teilen, die mit demselben Google-Konto angemeldet sind, oder von Nicht-Google-Apps. Überprüfe deine Einstellungen für die Standortfreigabe überall dort, wo dies zutreffen könnte.\\n\\nPersonen, mit denen du deinen Standort teilst, sehen weiterhin deinen zuletzt geteilten Standort.</string>\n    <string name=\"location_sharing_confirm_dialog_title\">Standortfreigabe aktivieren</string>\n    <string name=\"location_sharing_confirm_dialog_text\">Personen, denen du deinen Standort mitteilst, können jederzeit Folgendes sehen:\\n·Deinen Namen und dein Foto\\n·Den aktuellen Standort deines Geräts, auch wenn du keinen Google-Dienst nutzt\\n·Den Akkustand deines Geräts und ob es gerade aufgeladen wird\\n·Deine Ankunfts- und Abfahrtszeit, wenn sie eine Standortfreigabe-Benachrichtigung hinzufügen</string>\n    <string name=\"service_name_device_attestation\">Geräteattestierung</string>\n    <string name=\"prefcat_device_attestation_apps_title\">Apps, die Geräteattestierung verwenden</string>\n    <string name=\"pref_device_attestation_app_allow_requests_title\">Anfragen zulassen</string>\n    <string name=\"pref_device_attestation_app_allow_requests_summary\">Zulassen, dass die App eine Geräteattestierung anfordert</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-eo/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<resources>\n    </resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-eo/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2017 microG Project Team\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<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    </resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-eo/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    </resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-es/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2020 microG Project Team\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  --><resources>\n    <string name=\"permission_service_all_label\">Todos los servicios de Google</string>\n    <string name=\"permission_service_all_description\">Permite a la aplicación acceder a todos los servicios de Google a través de cualquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_android_label\">Servicios de Android</string>\n    <string name=\"permission_service_android_description\">Permite que la aplicación acceda a los servicios de Android a través de cualquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_adsense_label\">AdSense</string>\n    <string name=\"permission_service_adsense_description\">Permite a la aplicación acceder a todos los servicios de AdSense a través de cualquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_adwords_label\">AdWords</string>\n    <string name=\"permission_service_adwords_description\">Permite a la aplicación acceder a todos los servicios de AdWords a través de cualquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_ah_label\">Google App Engine</string>\n    <string name=\"permission_service_ah_description\">Permite a la aplicación acceder a todos los servicios de Google App Engine a través de cualquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_blogger_label\">Blogger</string>\n    <string name=\"permission_service_blogger_description\">Permite a la aplicación acceder a todos los servicios de Blogger a través de cualquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_cl_label\">Calendario de Google</string>\n    <string name=\"permission_service_cl_description\">Permite a la aplicación acceder a todos los servicios de Google Calendar a través de cualquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_cp_label\">Contactos</string>\n    <string name=\"permission_service_cp_description\">Permite a la aplicación acceder a todos los servicios de Contactos a través de cualquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_dodgeball_label\">Dodgeball</string>\n    <string name=\"permission_service_dodgeball_description\">Permite a la aplicación acceder a todos los servicios de Dodgeball a través de cualquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_finance_label\">Google Finance</string>\n    <string name=\"permission_service_finance_description\">Permite a la aplicación acceder a todos los servicios de Google Finance a través de cualquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_gbase_label\">Google Base</string>\n    <string name=\"permission_service_gbase_description\">Permite a la aplicación acceder a todos los servicios de Google Base a través de cualquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_grandcentral_label\">Google Voice</string>\n    <string name=\"permission_service_grandcentral_description\">Permite a la aplicación acceder a todos los servicios de Google Voice a través de cualquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_groups2_label\">Grupos de Google</string>\n    <string name=\"permission_service_groups2_description\">Permite a la aplicación acceder a todos los servicios de Grupos de Google a través de cualquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_health_label\">Google Health</string>\n    <string name=\"permission_service_health_description\">Permite a la aplicación acceder a todos los servicios de Google Health a través de cualquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_ig_label\">iGoogle</string>\n    <string name=\"permission_service_ig_description\">Permite a la aplicación acceder a todos los servicios de iGoogle a través de cualquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_jotspot_label\">JotSpot</string>\n    <string name=\"permission_service_jotspot_description\">Permite a la aplicación acceder a todos los servicios de JotSpot a través de cualquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_knol_label\">Knol</string>\n    <string name=\"permission_service_knol_description\">Permite a la aplicación acceder a todos los servicios de Knol a través de cualquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_lh2_label\">Picasa Web Albums</string>\n    <string name=\"permission_service_lh2_description\">Permite a la aplicación acceder a todos los servicios de Picasa Web Albums a través de cualquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_local_label\">Google Maps</string>\n    <string name=\"permission_service_local_description\">Permite a la aplicación acceder a todos los servicios de Google Maps a través de cualquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_mail_label\">Google Mail</string>\n    <string name=\"permission_service_mail_description\">Permite a la aplicación acceder a todos los servicios de Google Mail a través de cualquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_news_label\">Google Noticias</string>\n    <string name=\"permission_service_news_description\">Permite a la aplicación acceder a todos los servicios de Google Noticias a través de cualquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_notebook_label\">Google Notebook</string>\n    <string name=\"permission_service_notebook_description\">Permite a la aplicación acceder a todos los servicios de Google Notebook a través de cualquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_orkut_label\">Orkut</string>\n    <string name=\"permission_service_orkut_description\">Permite a la aplicación acceder a todos los servicios de Orkut a través de cualquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_print_label\">Búsqueda de libros de Google</string>\n    <string name=\"permission_service_print_description\">Permite a la aplicación acceder a todos los servicios de Búsqueda de libros de Google a través de cualquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_sierra_label\">Cuentas de Google Checkout</string>\n    <string name=\"permission_service_sierra_description\">Permite a la aplicación acceder a todos los servicios de Cuentas de Google Checkout a través de cualquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_sierraqa_label\">Cuentas de QA de Google Checkout</string>\n    <string name=\"permission_service_sierraqa_description\">Permite a la aplicación acceder a todos los servicios de Cuentas de QA de Google Checkout a través de cualquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_sierrasandbox_label\">Cuentas de Sandbox de Google Checkout</string>\n    <string name=\"permission_service_sierrasandbox_description\">Permite a la aplicación acceder a todos los servicios de Cuentas de Sandbox de Google Checkout a través de cualquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_sitemaps_label\">Herramientas de Google Webmaster</string>\n    <string name=\"permission_service_sitemaps_description\">Permite a la aplicación acceder a todos los servicios de Herramientas de Google Webmaster a través de cualquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_speech_label\">Búsqueda por voz</string>\n    <string name=\"permission_service_speech_description\">Permite a la aplicación acceder a todos los servicios de Búsqueda por voz a través de cualquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_speechpersonalization_label\">Reconocimiento de Voz Personalizado</string>\n    <string name=\"permission_service_speechpersonalization_description\">Permite a la aplicación acceder a todos los servicios de Personalized Speech Recognition a través de cualquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_talk_label\">Google Talk</string>\n    <string name=\"permission_service_talk_description\">Permite a la aplicación acceder a todos los servicios de Google Talk a través de cualquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_wifi_label\">Google Wi-Fi</string>\n    <string name=\"permission_service_wifi_description\">Permite a la aplicación acceder a todos los servicios de Google Wi-Fi a través de cualquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_wise_label\">Hojas de cálculo de Google</string>\n    <string name=\"permission_service_wise_description\">Permite a la aplicación acceder a todos los servicios de Hojas de cálculo de Google a través de cualquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_writely_label\">Documentos de Google</string>\n    <string name=\"permission_service_writely_description\">Permite a la aplicación acceder a todos los servicios de Documentos de Google a través de cualquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_youtube_label\">YouTube</string>\n    <string name=\"permission_service_youtube_description\">Permite a la aplicación acceder a todos los servicios de YouTube a través de cualquier cuenta de Google asociada.</string>\n    <string name=\"permission_service_YouTubeUser_label\">Nombres de usuario de YouTube</string>\n    <string name=\"permission_service_YouTubeUser_description\">Permite a la aplicación acceder a todos los servicios de nombres de usuario(s) de YouTube a través de cualquier cuenta de Google asociada.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_activity\">Ver el historial de actividad de sus aplicaciones de Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.buyer\">Gestionar la configuración de su cuenta de comprador de Ad Exchange</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller.readonly\">Ver sus datos de Ad Exchange</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller\">Ver y gestionar sus datos de Ad Exchange</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsensehost\">Ver y gestionar sus datos de anfitrión de AdSense y las cuentas asociadas</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense.readonly\">Ver sus datos de AdSense</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense\">Ver y gestionar sus datos de AdSense</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics.readonly\">Ver sus datos de Google Analytics</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics\">Ver y gestionar sus datos de Google Analytics</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_androidpublisher\">Acceder a Google Play Android Developer</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appengine.admin\">Alcance de la administración del motor de la aplicación.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.migration\">Acceso de lectura y escritura a la API de Groups Migration.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.settings\">Ver y gestionar la configuración de un grupo de Google Apps</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.licensing\">Acceso de lectura y escritura a la API de License Manager.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order\">Para administradores de revendedores y usuarios acceso de lectura/escritura cuando se realizan pruebas en la API de la sandbox, o acceso de lectura/escritura cuando se llama directamente a una operación de la API.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order.readonly\">Además del alcance general de lectura/escritura de OAuth, utilizar el alcance de solo lectura de OAuth al recuperar los datos del cliente.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps_reporting_audit.readonly\">Acceder a la Admin Audit API ReadOnly</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appstate\">Posibilidad de utilizar el servicio de App State.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery.readonly\">Ver sus datos en Google BigQuery</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery\">Ver y gestionar sus datos en Google BigQuery</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger\">Gestionar su cuenta de Blogger</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger.readonly\">Ver su cuenta de Blogger</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_books\">Gestionar sus libros</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar\">Gestionar sus calendarios</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar.readonly\">Ver sus calendarios</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_cloudprint\">Ver y gestionar sus datos de Google Cloud Print</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute.readonly\">Ver sus recursos de Google Compute Engine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute\">Ver y gestionar sus recursos de Google Compute Engine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate.readonly\">Ver sus trabajos de Google Coordinate</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate\">Ver y gestionar sus trabajos de Google Maps Coordinate</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.full_control\">Gestionar sus datos y permisos en Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_only\">Ver sus datos en Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_write\">Gestionar sus datos en Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_dfareporting\">Ver y gestionar los informes de DoubleClick para Advertisers</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.appdata\">Permite el acceso a la carpeta de Application Data</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.apps.readonly\">Ver sus aplicaciones de Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.file\">Ver y gestionar los archivos de Google Drive que ha abierto o creado con esta aplicación</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.install\">Ámbito especial utilizado para que los usuarios aprueben la instalación de una aplicación</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.metadata.readonly\">Ver metadatos de archivos y documentos en su Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.readonly\">Ver archivos y documentos en su Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.scripts\">Modificar el comportamiento de sus secuencias de órdenes de Google Apps Script</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive\">Ver y gestionar archivos y documentos en su Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase.readonly\">ver su cuenta de Freebase</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase\">Acceder a Freebase con su cuenta</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables\">Gestionar sus Fusion Tables</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables.readonly\">Ver sus Fusion Tables</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_games\">Ámbito para acceder a los datos de Google Play Juegos.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan\">Gestionar sus datos de GAN</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan.readonly\">Ver sus datos de GAN</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gcm_for_chrome\">CloudMessaging para Chrome</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_glass.timeline\">Ámbito de la cronología de Glass</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.compose\">Cree, lea, actualice y elimine borradores. Envíe mensajes y borradores.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.modify\">Todas las operaciones de lectura/escritura salvo la eliminación inmediata y permanente de hilos y mensajes, evitando la papelera.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.readonly\">Leer todos los recursos y sus metadatos, sin operaciones de escritura.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.best\">Gestionar su mejor ubicación disponible y su historial de ubicaciones</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.city\">Gestionar la ubicación de la ciudad y el historial de ubicaciones</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.best\">Gestionar su mejor ubicación disponible</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.city\">Gestionar su ubicación en la ciudad</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine\">Ver y gestionar los datos de Google Maps Engine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine.readonly\">Ver sus datos de Google Maps Engine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mobilemaps.firstparty\">Ver y gestionar su experiencia móvil de Google Maps</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut\">Gestionar su actividad de Orkut</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut.readonly\">Ver sus datos de Orkut</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.login\">Conocer su nombre, información básica y la lista de personas con las que se ha conectado en Google+</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.me\">Conocer quién es en Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_prediction\">Gestionar sus datos en la API de Google Prediction</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_shoppingapi\">Ver los datos de su producto</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification\">Gestionar la lista de sitios y dominios que controla</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification.verify_only\">Gestionar las verificaciones de su sitio nuevo con Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_structuredcontent\">Acceso de lectura y escritura a la API de Shopping Content.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue.consumer\">Consumir las tareas de sus Taskqueues</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue\">Gestionar sus tareas</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks\">Gestionar sus tareas</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks.readonly\">Ver sus tareas</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tracks\">API de Google Maps Tracks, Este alcance permite el acceso de lectura y escritura a los datos de su proyecto.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_urlshortener\">Gestionar sus URL cortos de goo.gl</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.email\">Ver su dirección de correo electrónico</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.profile\">Ver información básica sobre su cuenta</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube\">Gestionar su cuenta de YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtubepartner\">Ver y gestionar sus activos y contenido asociado en YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.readonly\">Ver su cuenta de YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.upload\">Gestionar sus vídeos de YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics_monetary.readonly\">Ver los informes monetarios de YouTube Analytics para su contenido de YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics.readonly\">Ver los informes de YouTube Analytics para su contenido de YouTube</string>\n    <string name=\"perm_activity_recognition_label\">Reconocimiento de la actividad</string>\n    <string name=\"perm_activity_recognition_description\">Permite que una aplicación reciba actualizaciones periódicas de su nivel de actividad desde Google, por ejemplo, si está caminando, conduciendo, montando en bicicleta o parado.</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-es/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2017-2020 microG Project Team\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  --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <plurals name=\"pref_unifiednlp_summary\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> backend configurado</item>\n        <item quantity=\"many\"><xliff:g example=\"3\">%1$d</xliff:g> backends configurados</item>\n        <item quantity=\"other\"><xliff:g example=\"3\">%1$d</xliff:g> backends configurados</item>\n    </plurals>\n    <plurals name=\"gcm_registered_apps_counter\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> aplicación registrada</item>\n        <item quantity=\"many\"><xliff:g example=\"123\">%1$d</xliff:g> aplicaciones registradas</item>\n        <item quantity=\"other\"><xliff:g example=\"123\">%1$d</xliff:g> aplicaciones registradas</item>\n    </plurals>\n    <plurals name=\"cond_perm_summary\">\n        <item quantity=\"one\">No se concede el permiso necesario para el correcto funcionamiento de los servicios de microG.</item>\n        <item quantity=\"many\">No se conceden los permisos necesarios para el correcto funcionamiento de los servicios microG.</item>\n        <item quantity=\"other\">No se conceden los permisos necesarios para el correcto funcionamiento de los de servicios de microG.</item>\n    </plurals>\n    <plurals name=\"cond_perm_action\">\n        <item quantity=\"one\">Solicitar el permiso que falta</item>\n        <item quantity=\"many\">Solicitar los permisos que faltan</item>\n        <item quantity=\"other\">Solicitar los permisos que faltan</item>\n    </plurals>\n</resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-es/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2020 microG Project Team\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  --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"gms_app_name\">Servicios de microG</string>\n    <string name=\"gms_settings_name\">Configuración de microG</string>\n    <string name=\"gms_settings_summary\">Configurar los servicios de microG.</string>\n    <string name=\"just_a_sec\">Un momento…</string>\n    <string name=\"google_account_label\">Google</string>\n    <string name=\"ask_permission_tos\">Al continuar, permitirás a esta aplicación y a Google usar tu información de acuerdo con sus respectivos términos de servicio y política de privacidad.</string>\n    <string name=\"ask_scope_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> quiere:</string>\n    <string name=\"ask_service_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> quiere usar:</string>\n    <string name=\"account_manager_title\">Gestor de cuentas de Google</string>\n    <string name=\"sorry\">Lo sentimos…</string>\n    <string name=\"auth_before_connect\">Una aplicación en tu dispositivo está intentando iniciar sesión en una cuenta de Google.\\n\\nSi esto fue intencional, usa el botón <b>Iniciar sesión</b> para conectar con la página de inicio de sesión de Google. Si no, presiona <b>Cancelar</b> para volver a la aplicación que causó que apareciera este mensaje.</string>\n    <string name=\"auth_sign_in\">Iniciar sesión</string>\n    <string name=\"auth_connecting\">Tu dispositivo está estableciendo una conexión con los servidores de Google para iniciar sesión.\\n\\nEsto puede tardar unos segundos.</string>\n    <string name=\"no_network_error_desc\">No tiene ninguna conexión de red.\\n\\nEsto podría ser un problema temporal o su dispositivo Android no está configurado para los servicios de datos. Pruebe otra vez cuando se haya conectado a una red móvil o wifi.</string>\n    <string name=\"auth_general_error_desc\">\"Hubo un problema comunicándose con los servidores de Google.\n\nInténtalo otra vez mas tarde.\"</string>\n    <string name=\"auth_finalize\">Su dispositivo está contactando a Google para guardar información en su cuenta.\\n\\nEsto podría tardar algunos minutos.</string>\n    <string name=\"allow\">Permitir</string>\n    <string name=\"deny\">Denegar</string>\n    <string name=\"auth_notification_title\">Autenticación requerida</string>\n    <string name=\"auth_notification_content\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> requiere su autorización para acceder a su cuenta de Google.</string>\n    <string name=\"perm_status_broadcast_label\">escuchar las emisiones de estado interno</string>\n    <string name=\"perm_c2dm_receive_label\">escuchar los mensajes C2DM</string>\n    <string name=\"perm_c2dm_send_label\">enviar mensajes C2DM a otras aplicaciones</string>\n    <string name=\"perm_gtalk_svc_label\">intercambiar mensajes y recibir notificaciones de sincronización de los servidores de Google</string>\n    <string name=\"perm_extended_access_label\">Acceso extendido a los servicios de Google</string>\n    <string name=\"perm_provision_label\">prestación de servicios de microG</string>\n    <string name=\"perm_provision_description\">Permite a la aplicación configurar los servicios de microG sin la interacción del usuario</string>\n    <string name=\"service_name_checkin\">Registro del dispositivo de Google</string>\n    <string name=\"service_name_mcs\">Servicios en la nube</string>\n    <string name=\"service_name_snet\">Google SafetyNet</string>\n    <string name=\"games_title\">Google Play Juegos</string>\n    <string name=\"games_info_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> quiere usar Play Juegos</string>\n    <string name=\"games_info_content\">Para usar Play Juegos es necesario instalar la aplicación Google Play Juegos. La aplicación puede continuar sin Play Juegos, pero es posible que funcione inesperadamente.</string>\n    <string name=\"pick_place_title\">Elija un lugar</string>\n    <string name=\"pick_place_desc\">El selector de lugares no está disponible aún.</string>\n    <string name=\"place_picker_select_title\">Seleccionar esta ubicación</string>\n    <string name=\"place_picker_nearby_places\">Lugares cercanos</string>\n    <string name=\"place_picker_location_lat_lng\">(%1$.7f, %2$.7f)</string>\n    <string name=\"lacking_permission_toast\">Servicios de microG: Sin permiso para <xliff:g example=\"acceso completo a la red\">%1$s</xliff:g></string>\n    <string name=\"network_type_mobile\">Red móvil</string>\n    <string name=\"network_type_wifi\">Wifi</string>\n    <string name=\"network_type_roaming\">Itinerancia</string>\n    <string name=\"network_type_other\">Otras redes</string>\n    <!-- Self check -->\n    <string name=\"self_check_cat_fake_sig\">Compatibilidad con suplantación de firmas</string>\n    <string name=\"self_check_cat_gms_packages\">Paquetes instalados</string>\n    <string name=\"self_check_cat_system\">Sistema</string>\n    <string name=\"self_check_name_fake_sig_perm\">El sistema admite la suplantación de firmas:</string>\n    <string name=\"self_check_resolution_fake_sig_perm\">Su ROM no admite nativamente la suplantación de firmas. Todavía puede usar Xposed u otros sistemas para conseguirlo. Revise la documentación para saber qué ROM permiten suplantar firmas y cómo usar microG en las que no.</string>\n    <string name=\"self_check_name_perm_granted\">El sistema concede el permiso de suplantación de firmas:</string>\n    <string name=\"self_check_resolution_perm_granted\">Este es un fuerte indicador de que la ROM sí permite suplantar firmas, pero requiere otra acción para activarlo. Revise la documentación para conocer los pasos que se deben seguir.</string>\n    <string name=\"self_check_name_system_spoofs\">El sistema suplanta la firma:</string>\n    <string name=\"self_check_resolution_system_spoofs\">Revise la documentación sobre los pasos a seguir.</string>\n    <string name=\"self_check_pkg_gms\">Servicios de microG</string>\n    <string name=\"self_check_pkg_vending\">Acompañante de microG / Play Store</string>\n    <string name=\"self_check_pkg_gsf\">Marco de servicios de microG</string>\n    <string name=\"self_check_name_app_installed\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> instalado: </string>\n    <string name=\"self_check_resolution_app_installed\">Instale la aplicación <xliff:g example=\"F-Droid\">%1$s</xliff:g> o una compatible. Compruebe la documentación para saber qué aplicaciones son compatibles.</string>\n    <string name=\"self_check_name_correct_sig\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> tiene una firma correcta: </string>\n    <string name=\"self_check_resolution_correct_sig\">Puede que el <xliff:g example=\"F-Droid\">%1$s</xliff:g> instalado no sea compatible o la suplantación de firmas no esté activada. Revise la documentación para conocer las aplicaciones y ROM compatibles.</string>\n    <string name=\"self_check_name_battery_optimizations\">Optimizaciones de la batería ignoradas:</string>\n    <string name=\"self_check_resolution_battery_optimizations\">Toca aquí para desactivar las optimizaciones de la batería. Si no lo haces, puede que las aplicaciones se comporten incorrectamente.</string>\n    <!-- Settings strings -->\n    <string name=\"prefcat_about\">Acerca</string>\n    <string name=\"prefcat_components\">Componentes</string>\n    <string name=\"prefcat_configuration\">Configuración</string>\n    <string name=\"prefcat_google_services\">Servicios de Google</string>\n    <string name=\"prefcat_location_service\">Servicio de localización</string>\n    <string name=\"prefcat_services\">Servicios</string>\n    <string name=\"prefcat_test\">Prueba</string>\n    <string name=\"cond_gcm_bat_title\">Optimizaciones de la batería activadas</string>\n    <string name=\"cond_gcm_bat_summary\">Ha activado Cloud Messaging pero tiene las optimizaciones de la batería activas para los servicios de microG. Para que las notificaciones automáticas lleguen, debe ignorar las optimizaciones de la batería.</string>\n    <string name=\"cond_gcm_bat_action\">Ignorar optimizaciones</string>\n    <string name=\"cond_perm_title\">Falta el permiso</string>\n    <string name=\"prefs_account\">Preferencias de la cuenta</string>\n    <string name=\"prefs_account_privacy\">Información personal &amp; privacidad</string>\n    <string name=\"prefs_account_security\">Inicio de sesión &amp; seguridad</string>\n    <string name=\"pref_auth_trust_google_title\">Confiar en Google para los permisos de las aplicaciones</string>\n    <string name=\"pref_auth_trust_google_summary\">Cuando está desactivada, se pregunta al usuario antes de enviar a Google la solicitud de autorización de una aplicación. Algunas aplicaciones no podrán utilizar la cuenta de Google si esta opción está desactivada.</string>\n    <string name=\"pref_auth_visible_title\">Permitir que las aplicaciones encuentren cuentas</string>\n    <string name=\"pref_auth_visible_summary\">Cuando se active, todas las aplicaciones de este dispositivo podrán ver la dirección de correo electrónico de sus cuentas de Google sin necesidad de autorización previa.</string>\n    <string name=\"pref_checkin_enable_summary\">Registra el dispositivo en los servicios de Google y crea un identificador único. microG quita de estos datos la información identificativa salvo el nombre en su cuenta de Google.</string>\n    <string name=\"pref_device_registration_android_id\">Identificador de Android</string>\n    <string name=\"checkin_not_registered\">No registrado</string>\n    <string name=\"checkin_last_registration\">Último registro: <xliff:g example=\"Ayer, 14:20\">%1$s</xliff:g></string>\n    <string name=\"checkin_enable_switch\">Registrar el dispositivo</string>\n    <string name=\"pref_info_status\">Estado</string>\n    <string name=\"pref_more_settings\">Más</string>\n    <string name=\"pref_add_account_title\">Cuenta</string>\n    <string name=\"pref_add_account_summary\">Añadir cuenta de Google</string>\n    <string name=\"pref_gcm_enable_mcs_summary\">Cloud Messaging es un proveedor de notificaciones automáticas usado por muchas aplicaciones. Para usarlo debe activar el registro del dispositivo.</string>\n    <string name=\"pref_gcm_heartbeat_title\">Intervalo del Cloud Messaging heartbeat</string>\n    <string name=\"pref_gcm_heartbeat_summary\">El intervalo en segundos para que el sistema realice un heartbeat a los servidores de Google. Aumentar este número reducirá el consumo de batería, pero puede causar retrasos en los mensajes push.\\nObsoleto, será reemplazado en futuras versiones.</string>\n    <string name=\"pref_gcm_apps_title\">Aplicaciones que usan Cloud Messaging</string>\n    <string name=\"pref_gcm_apps_summary\">Lista de aplicaciones registradas actualmente para Cloud Messagging.</string>\n    <string name=\"pref_gcm_confirm_new_apps_title\">Confirmar nuevas aplicaciones</string>\n    <string name=\"pref_gcm_confirm_new_apps_summary\">Preguntar antes de registrar una nueva aplicación para recibir notificaciones push</string>\n    <string name=\"pref_gcm_ping_interval\">Intervalo de ping: <xliff:g example=\"10 minutos\">%1$s</xliff:g></string>\n    <string name=\"pref_about_title\">Acerca de los Servicios de microG</string>\n    <string name=\"pref_about_summary\">Información de la versión y librerías usadas</string>\n    <string name=\"gcm_app_error_unregistering\">Error al cancelar el registro</string>\n    <string name=\"gcm_app_not_installed_anymore\">Ya no está instalada</string>\n    <string name=\"gcm_unregister_app\">Cancelar el registro</string>\n    <string name=\"gcm_not_registered\">No registrado</string>\n    <string name=\"gcm_no_message_yet\">No se han recibido mensajes hasta ahora</string>\n    <string name=\"gcm_last_message_at\">Último mensaje: <xliff:g example=\"Ayer, 14:20\">%1$s</xliff:g></string>\n    <string name=\"gcm_registered\">Registrado</string>\n    <string name=\"gcm_registered_since\">Registrado desde: <xliff:g example=\"Ayer, 14:20\">%1$s</xliff:g></string>\n    <string name=\"gcm_unregister_confirm_title\">¿Cancelar el registro <xliff:g example=\"F-Droid\">%1$s</xliff:g>?</string>\n    <string name=\"gcm_unregister_confirm_message\">Algunas aplicaciones no se vuelven a registrar automáticamente y/o no ofrecen la opción de hacerlo manualmente. Es posible que estas aplicaciones no funcionen correctamente después de anular el registro.\\n¿Desea continuar?</string>\n    <string name=\"gcm_unregister_after_deny_message\">Has denegado el registro de una aplicación para recibir notificaciones push que ya está registrada.\\n¿Quieres anular el registro ahora para que no reciba mensajes push en el futuro?</string>\n    <string name=\"gcm_messages_counter\">Mensajes: <xliff:g example=\"123\">%1$d</xliff:g> (<xliff:g example=\"12345\">%2$d</xliff:g> bytes)</string>\n    <string name=\"gcm_network_state_disconnected\">Desconectado</string>\n    <string name=\"gcm_network_state_connected\">Conectado desde <xliff:g example=\"hace 2 horas\">%1$s</xliff:g></string>\n    <string name=\"gcm_enable_switch\">Recibir notificaciones push</string>\n    <string name=\"pref_push_app_allow_register_title\">Permitir el registro</string>\n    <string name=\"pref_push_app_allow_register_summary\">Permite que la aplicación se registre para las notificaciones push.</string>\n    <string name=\"pref_push_app_wake_for_delivery_title\">Iniciar la aplicación en el mensaje push</string>\n    <string name=\"pref_push_app_wake_for_delivery_summary\">Inicie la aplicación en segundo plano para recibir los mensajes entrantes.</string>\n    <string name=\"prefcat_push_apps_title\">Aplicaciones que utilizan notificaciones push</string>\n    <string name=\"prefcat_push_apps_registered_title\">Aplicaciones registradas</string>\n    <string name=\"prefcat_push_apps_unregistered_title\">Aplicaciones no registradas</string>\n    <string name=\"prefcat_push_networks_title\">Redes a utilizar para las notificaciones push</string>\n    <string name=\"safetynet_intro\">Google SafetyNet es un sistema de certificación de dispositivos, que garantiza que el dispositivo está correctamente asegurado y es compatible con Android CTS. Algunas aplicaciones utilizan SafetyNet por razones de seguridad o como un prerrequisito para la protección contra manipulaciones.\\n\\nmicroG GmsCore contiene una implementación gratuita de SafetyNet, pero el servidor oficial requiere que las solicitudes de SafetyNet sean firmadas utilizando el sistema propietario DroidGuard.</string>\n    <string name=\"safetynet_enable_switch\">Permitir la certificación del dispositivo</string>\n    <string name=\"pref_safetynet_test_title\">Probar el certificado de SafetyNet</string>\n    <string name=\"pref_droidguard_operation_mode\">Modo de operación</string>\n    <string name=\"signin_confirm_button_text\">Permitir y compartir</string>\n    <string name=\"signin_subtext_sharing\">Para continuar, microG compartirá el nombre, la dirección de correo electrónico y la foto de perfil de su cuenta de Google con <xliff:g example=\"F-Droid\">%1$s</xliff:g>.</string>\n    <string name=\"perm_gsf_read_gservices_label\">leer la configuración del servicio de Google</string>\n    <string name=\"pref_auth_include_android_id_summary\">Si se desactiva, las solicitudes de autenticación no se vincularán al registro del dispositivo, lo que puede permitir el inicio de sesión de dispositivos no autorizados, pero puede tener consecuencias imprevistas.</string>\n    <string name=\"pref_test_summary_passed\">Superadas todas las pruebas</string>\n    <string name=\"pref_test_summary_warn\">Atención: %s</string>\n    <string name=\"pref_droidguard_unsupported_summary\">La ejecución de DroidGuard no es compatible con este dispositivo. Los servicios de SafetyNet pueden comportarse mal.</string>\n    <string name=\"pref_device_registration_import_custom_profile_summary\">Importar el perfil del dispositivo desde un archivo</string>\n    <string name=\"signin_subtext_policy\">Antes de utilizar esta aplicación, revise sus %1$s y %2$s.</string>\n    <string name=\"signin_subtext_policy_privacy\">política de privacidad</string>\n    <string name=\"signin_subtext_policy_terms\">condiciones del servicio</string>\n    <string name=\"service_name_vending\">Servicios de la Play Store</string>\n    <string name=\"pref_test_summary_running\">Ejecutando…</string>\n    <string name=\"signin_picker_subtitle\">para continuar con <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"prefcat_safetynet_apps_title\">Aplicaciones que utilizan SafetyNet</string>\n    <string name=\"menu_clear_recent_requests\">Borrar las peticiones recientes</string>\n    <string name=\"pref_safetynet_recent_attestation_summary\">Certificado: %s</string>\n    <string name=\"pref_auth_include_android_id_title\">Autenticarse con el registro del dispositivo</string>\n    <string name=\"pref_safetynet_recent_cat_response\">Datos de la respuesta</string>\n    <string name=\"pref_safetynet_recent_nonce\">Nonce (Hex)</string>\n    <string name=\"pref_safetynet_recent_cat_basic\">Información básica</string>\n    <string name=\"pref_safetynet_recent_copied\">¡Copiado al portapapeles!</string>\n    <string name=\"pref_safetynet_test_not_completed\">Aún no se ha completado</string>\n    <string name=\"pref_safetynet_recent_recaptcha_summary\">ReCaptcha: %s</string>\n    <string name=\"pref_safetynet_recent_recaptcha_enterprise_summary\">ReCaptcha Enterprise: %s</string>\n    <string name=\"push_notifications_summary_values_seconds\">%s segundos</string>\n    <string name=\"signin_confirm_title\">Permitir iniciar sesión en <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"safetynet_last_run_at\">Último uso: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"profile_name_native\">Nativo</string>\n    <string name=\"profile_name_real\">Real</string>\n    <string name=\"profile_name_user\">Personalizado: %s</string>\n    <string name=\"profile_name_auto\">Automático: %s</string>\n    <string name=\"profile_name_system\">Sistema: %s</string>\n    <string name=\"pref_device_registration_import_custom_profile_title\">Importar perfil personalizado</string>\n    <string name=\"pref_vending_license_enable_summary\">Algunas aplicaciones requieren la verificación de que las has comprado en Google Play. Cuando una aplicación lo solicita, microG puede descargar una prueba de compra de Google. Si se desactiva, o si no se añade ninguna cuenta de Google, se ignoran las solicitudes de verificación de licencia.</string>\n    <string name=\"gcm_allow_app_popup\">¿Permitir que <xliff:g example=\"F-Droid\">%1$s</xliff:g> se registre para recibir notificaciones push?</string>\n    <string name=\"pref_recaptcha_test_title\">Probar ReCAPTCHA</string>\n    <string name=\"pref_recaptcha_enterprise_test_title\">Probar ReCAPTCHA Enterprise</string>\n    <string name=\"pref_test_summary_failed\">Falló: %s</string>\n    <string name=\"pref_device_registration_serial_title\">Número de serie</string>\n    <string name=\"pref_device_registration_select_profile_title\">Seleccionar perfil</string>\n    <string name=\"pref_device_registration_device_profile_category\">Perfil del dispositivo</string>\n    <string name=\"pref_safetynet_recent_uses\">Usos recientes</string>\n    <string name=\"pref_safetynet_recent_copy_json\">Copiar los datos JSON y JWS</string>\n    <string name=\"pref_safetynet_recent_advice\">Consejos</string>\n    <string name=\"pref_safetynet_recent_eval_type\">Tipo de evaluación</string>\n    <string name=\"pref_safetynet_recent_response_status\">Estado de la respuesta</string>\n    <string name=\"pref_safetynet_recent_cat_request\">Solicitud de datos</string>\n    <string name=\"pref_safetynet_recent_request_time\">Hora de la solicitud</string>\n    <string name=\"pref_safetynet_recent_request_type\">Tipo de solicitud</string>\n    <string name=\"pref_safetynet_recent_token\">Token</string>\n    <string name=\"pref_safetynet_test_integrity_cts_passed\">Integridad y CTS aprobados</string>\n    <string name=\"pref_safetynet_test_cts_failed\">CTS fallido</string>\n    <string name=\"pref_safetynet_test_integrity_failed\">Integridad fallida</string>\n    <string name=\"pref_safetynet_test_no_result\">Sin resultado</string>\n    <string name=\"pref_safetynet_test_invalid_json\">JSON incorrecto</string>\n    <string name=\"push_notifications_summary_off\">APAGADO</string>\n    <string name=\"push_notifications_summary_automatic\">ENCENDIDO / Automático: %s</string>\n    <string name=\"push_notifications_summary_manual\">ENCENDIDO / Manual: %s</string>\n    <string name=\"push_notifications_summary_values_minutes\">%s minutos</string>\n    <string name=\"pref_vending_summary_licensing_on\">La licencia está habilitada</string>\n    <string name=\"pref_vending_summary_licensing_off\">La licencia está deshabilitada</string>\n    <string name=\"pref_vending_licensing_enable_switch\">Responder a las solicitudes de verificación de licencias</string>\n    <string name=\"signin_picker_title\">Elija una cuenta</string>\n    <string name=\"signin_picker_add_account_label\">Añadir otra cuenta</string>\n    <string name=\"feedback_disabled\">Actualmente no es posible recibir comentarios</string>\n    <string name=\"pref_auth_strip_device_name_title\">Eliminar el nombre del dispositivo para la autenticación</string>\n    <string name=\"pref_auth_strip_device_name_summary\">Cuando está activada, las solicitudes de autenticación no incluyen el nombre del dispositivo, lo que puede permitir que dispositivos no autorizados inicien sesión, pero puede tener consecuencias imprevistas.</string>\n    <string name=\"perm_car_speed_label\">Velocidad del coche</string>\n    <string name=\"perm_car_speed_description\">Acceder a la velocidad del coche</string>\n    <string name=\"perm_car_info_label\">Información del coche</string>\n    <string name=\"perm_car_info_description\">Acceder a la información del coche</string>\n    <string name=\"perm_car_fuel_label\">Nivel de combustible del coche</string>\n    <string name=\"perm_car_fuel_description\">Acceder a la información sobre el nivel de combustible del coche</string>\n    <string name=\"perm_car_mileage_label\">Kilometraje del coche</string>\n    <string name=\"perm_car_mileage_description\">Acceder a la información sobre el kilometraje del coche</string>\n    <string name=\"perm_car_vendor_extension_label\">Canal de proveedores de automóviles</string>\n    <string name=\"perm_car_vendor_extension_description\">Acceder al canal de proveedores del coche para intercambiar información específica sobre él</string>\n    <string name=\"backup_disabled\">Actualmente no es posible realizar copias de seguridad</string>\n    <string name=\"pref_accounts_title\">Cuenta de Google</string>\n    <string name=\"pref_accounts_summary\">Añadir y gestionar cuentas de Google</string>\n    <string name=\"pref_vending_billing_note_experimental\">Esta característica es experimental y puede provocar pérdidas de dinero. Usted ha sido advertido.</string>\n    <string name=\"pref_vending_billing_note_licensing\">Es posible que algunas aplicaciones requieran que también habilites la verificación de licencia para verificar tus compras.</string>\n    <string name=\"prefcat_accounts_current_accounts_title\">Cuentas</string>\n    <string name=\"pref_vending_licensing_category\">Licencia de Google Play</string>\n    <string name=\"prefcat_accounts_settings_title\">Configuración</string>\n    <string name=\"pref_vending_billing_category\">Facturación de Google Play</string>\n    <string name=\"pref_vending_billing_enable_switch\">Procesar la facturación</string>\n    <string name=\"pref_vending_billing_enable_summary\">Una vez habilitadas, algunas aplicaciones pueden completar compras o iniciar suscripciones a través del servicio Play Billing de Google.</string>\n    <string name=\"credentials_assisted_signin_consent\">Al continuar, Google compartirá su nombre, dirección de correo electrónico y foto de perfil con %1$s . Ver Política de privacidad y términos de servicio de %1$s .</string>\n    <string name=\"credentials_assisted_signin_description\">Puede gestionar Iniciar sesión con Google en sus cuentas de Google.</string>\n    <string name=\"credentials_assisted_choose_account_label\">Elija una cuenta</string>\n    <string name=\"credentials_assisted_choose_account_subtitle\">para continuar a %1$s</string>\n    <string name=\"credentials_assisted_signin_button_text_long\">Acceder con Google</string>\n    <string name=\"credentials_assisted_cancel\">Cancelar</string>\n    <string name=\"credentials_assisted_signin_consent_header\">Accediendo como %1$s</string>\n    <string name=\"credentials_assisted_continue\">Continuar</string>\n    <string name=\"credentials_assisted_confirmation_header\">Accediendo</string>\n    <string name=\"credentials_assisted_continue_as_user_button_label\">Continuar como %1$s</string>\n    <string name=\"credentials_assisted_sign_back_title\">Vuelve a iniciar sesión en %1$s con Google</string>\n    <string name=\"auth_package_override_request_title\">¿Quiere permitir a <b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> el acceso privilegiado a <xliff:g example=\"account@example.com\">%2$s</xliff:g>\\?</string>\n    <string name=\"auth_package_override_request_message\"><b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> quiere acceder a tu cuenta como si fuera <b><xliff:g example=\"F-Droid\">%2$s</xliff:g> de <xliff:g example=\"F-Droid Inc.\">%3$s</xliff:g></b>. Esto podría otorgarle acceso privilegiado a su cuenta.</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_switch\">Agregar automáticamente aplicaciones gratuitas a la biblioteca</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_summary\">Las aplicaciones gratuitas pueden comprobar si se han descargado de Google Play. Añada aplicaciones gratuitas automáticamente a la biblioteca de su cuenta para que siempre pasen la comprobación todas las aplicaciones gratuitas que estén disponibles actualmente.</string>\n    <string name=\"limited_services_app_name\">Servicios limitados de microG</string>\n    <string name=\"limited_services_dialog_information_ack\">Entiendo</string>\n    <string name=\"limited_services_dialog_information\">Está utilizando los Servicios Limitados de microG. A diferencia de los Servicios microG habituales, esta variedad solo funciona con aplicaciones que utilizan bibliotecas microG, no con las de Google Play. Esto significa que la mayoría de las aplicaciones ignorarán estos servicios.</string>\n    <string name=\"auth_action_notification_title\">Acción en la cuenta requerida</string>\n    <string name=\"auth_action_notification_content\">Su cuenta de Google necesita configuración adicional.</string>\n    <string name=\"auth_action_step_enable_gcm\">Activar Cloud Messaging</string>\n    <string name=\"auth_action_step_allow_microg_gcm_description\">De acuerdo con sus preferencias, microG necesita permiso de usted antes de que pueda registrarse para Cloud Messaging.</string>\n    <string name=\"auth_action_step_allow_microg_gcm\">Permitir Cloud Messaging para microG</string>\n    <string name=\"auth_action_step_enable_lockscreen\">Configurar bloqueo de pantalla seguro</string>\n    <string name=\"auth_action_step_perform_content_description\">Haga clic para realizar el paso</string>\n    <string name=\"auth_action_step_completed_content_description\">Paso completado</string>\n    <string name=\"auth_action_notification_channel_name\">Alertas de la cuenta de Google</string>\n    <string name=\"auth_action_notification_channel_description\">Notifica cuando una de sus cuentas de Google requiere una configuración adicional antes de poder usarse o cuando una cuenta es incompatible con microG.</string>\n    <string name=\"auth_action_activity_explanation\">Complete los siguientes pasos para poder usar su cuenta de Google %s en este dispositivo.</string>\n    <string name=\"auth_action_activity_header\">Finalizar la configuración de su cuenta de Google</string>\n    <string name=\"auth_action_step_enable_checkin_description\">Su dispositivo debe registrarse en Google al menos una vez.\\n\\nPuede desactivar el registro de dispositivos de Google después de que se complete la configuración de la cuenta.</string>\n    <string name=\"auth_action_step_enable_checkin\">Activar registro del dispositivo</string>\n    <string name=\"auth_action_step_enable_gcm_description\">Puede desactivar Cloud Messaging después de que se complete la configuración de la cuenta.</string>\n    <string name=\"auth_action_activity_finish\">Finalizar</string>\n    <string name=\"auth_action_step_enable_lockscreen_description\">Su cuenta de Google la administra su lugar de trabajo o institución educativa. Su administrador decidió que los dispositivos necesitan un bloqueo de pantalla seguro antes de poder acceder a los datos de la cuenta.\\n\\nConfigure una contraseña, PIN o patrón de bloqueo de pantalla.</string>\n    <string name=\"pref_vending_asset_delivery_category\">Entrega de recursos de Google Play</string>\n    <string name=\"pref_vending_asset_delivery_switch\">Activar entrega de recursos bajo demanda</string>\n    <string name=\"pref_vending_asset_delivery_summary\">Descargar recursos adicionales cuando lo soliciten aplicaciones que utilicen Play Asset Delivery</string>\n    <string name=\"service_name_work_profile\">Perfil de trabajo</string>\n    <string name=\"pref_vending_feature_delivery\">Entrega de funcionalidades de Google Play</string>\n    <string name=\"pref_vending_split_install_switch\">Instalación de componentes bajo demanda</string>\n    <string name=\"pref_vending_licensing_split_install_summary\">Permitir que las aplicaciones descarguen e instalen componentes adicionales</string>\n    <string name=\"pref_workprofile_create_account\">Permitir configurar cuenta laboral</string>\n    <string name=\"pref_workprofile_disclaimer\">Es responsabilidad suya asegurarse de que su uso de microG cumpla con las disposiciones de la organización. microG se brinda como parte de un esfuerzo voluntario y no puede garantizar su comportamiento.</string>\n    <string name=\"games_achievement_list_title\">Logros</string>\n    <string name=\"games_achievements_empty_text\">Este juego no tiene logros</string>\n    <string name=\"games_achievement_locked_content_description\">bloqueado</string>\n    <string name=\"games_achievement_unlocked_content_description\">desbloqueado</string>\n    <string name=\"games_achievement_extra_text\">%1$s XP</string>\n    <string name=\"games_delete_snapshot_dialog_message\">¿Confirma que quiere eliminar esta partida guardada?</string>\n    <string name=\"games_delete_snapshot_dialog_title\">Eliminar partida guardada</string>\n    <string name=\"games_snapshot_delete_btn_text\">eliminar</string>\n    <string name=\"games_snapshot_empty_text\">Aún no se ha guardado ninguna partida</string>\n    <string name=\"camera_permission_dialog_button\">Aceptar</string>\n    <string name=\"games_delete_snapshot_dialog_ok\">Aceptar</string>\n    <string name=\"games_delete_snapshot_error\">Falló la eliminación; inténtelo de nuevo más tarde</string>\n    <string name=\"camera_permission_dialog_title\">Se requiere el permiso de la cámara</string>\n    <string name=\"pref_vending_asset_device_sync_switch\">Activar sincronización de información del dispositivo</string>\n    <string name=\"games_snapshot_choose_btn_text\">seleccionar</string>\n    <string name=\"games_delete_snapshot_dialog_cancel\">Cancelar</string>\n    <string name=\"games_api_access_denied\">Ninguna cuenta en este dispositivo puede acceder a las API de juegos</string>\n    <string name=\"pref_vending_asset_device_sync_summary\">Las aplicaciones que usan Play Asset Delivery descargarán recursos adicionales acorde a la información del dispositivo en uso.</string>\n    <string name=\"credentials_assisted_signin_add_account\">Añadir cuenta</string>\n    <string name=\"credentials_assisted_choose_account_error_tips\">Anormalidad en la cuenta</string>\n    <string name=\"pref_workprofile_intro\">Al configurar un perfil de trabajo para su lugar de trabajo o institución educativa, es posible que el programa de configuración intente conectarse a Google para habilitar la descarga de aplicaciones a ese perfil.</string>\n    <string name=\"games_leaderboard_empty_text\">No hay tablas de clasificación para este juego</string>\n    <string name=\"games_leaderboards_score_label\">Puntuación: %1$s</string>\n    <string name=\"games_leaderboard_list_title\">Puntuaciones</string>\n    <string name=\"games_leaderboard_score_empty_text\">¡Increíble! No hay puntuaciones máximas públicas para este juego.</string>\n    <string name=\"barcode_scanner_brand\">Escaneado por microG en nombre de %1$s</string>\n    <string name=\"camera_permission_dialog_message\">Los servicios de microG necesitan acceder a la cámara de su dispositivo para escanear un código para %1$s.\\n\\nPara habilitarlo, otorgue permiso de cámara a los servicios de microG en Configuración.</string>\n    <string name=\"auth_action_reauth_notification_title\">Se requiere acción en la cuenta</string>\n    <string name=\"pref_auth_two_step_verification_title\">Recibir indicaciones de verificación en dos pasos</string>\n    <string name=\"pref_auth_two_step_verification_summary\">Cuando está habilitado, el dispositivo puede recibir indicaciones de verificación de dos pasos de Google (se requiere Cloud Messaging).</string>\n    <string name=\"pref_game_accounts_title\">Cuentas de Google Game</string>\n    <string name=\"pref_auto_create_player\">Permitir el registro de cuentas de Play Games</string>\n    <string name=\"pref_auto_create_player_intro\">Al jugar, debes usar una cuenta de Play Games para iniciar sesión y registrar funciones relacionadas con el juego, como logros, tablas de clasificación, archivos, etc. Después de deshabilitarlo, las cuentas de Google que no estén vinculadas a una cuenta de Play Games no se registrarán automáticamente y el juego no podrá iniciar sesión ni jugar.</string>\n    <string name=\"pref_allow_upload_game_played\">Permitir la carga del juego jugado</string>\n    <string name=\"pref_change_default_game_player\">Cambiar cuenta para juegos</string>\n    <string name=\"pref_allow_upload_game_played_summary\">Si se desactiva esta opción, el juego no informará el estado de juego después de iniciar sesión, y algunos juegos pueden no permitir el inicio de sesión.</string>\n    <string name=\"pref_change_default_game_player_summary\">Cambiar la cuenta predeterminada para juegos y cambiar la cuenta por juego.</string>\n    <string name=\"pref_delete_game_account_data\">Eliminar los datos de Play Juegos</string>\n    <string name=\"pref_delete_game_account_data_summary\">Eliminar la cuenta de Play Juegos y todos los datos, y borrar los datos de juegos individuales.</string>\n    <string name=\"games_state_description_signed_out\">Sesión cerrada</string>\n    <string name=\"games_state_description_delete\">Eliminar</string>\n    <string name=\"games_change_button_text\">Cambiar</string>\n    <string name=\"games_change_default_account_section_title\">Cambiar la cuenta predeterminada para juegos</string>\n    <string name=\"games_change_default_account_description\">Cuenta predeterminada: %1$s</string>\n    <string name=\"games_change_default_account_explanation\">Esta cuenta se utiliza para iniciar sesión en los juegos, guardar tu progreso y tus ajustes. Cambiar la cuenta predeterminada o cerrar sesión puede restablecer el progreso y la configuración de los juegos que ya has jugado.</string>\n    <string name=\"games_change_per_game_title\">Cambiar la cuenta por juego</string>\n    <string name=\"games_change_per_game_description\">Si cambias la cuenta de un juego o cierras sesión, el progreso y los ajustes del juego podrían restablecerse.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_title\">Selecciona una opción para la nueva cuenta predeterminada</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_description\">Cuenta predeterminada actual: %1$s</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_title\">Cambiar la cuenta predeterminada solo para nuevos juegos</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_description\">No perderás el acceso al progreso ni a la configuración de los juegos que has jugado, pero tu progreso se dividirá entre las cuentas.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_title\">Cambiar la cuenta predeterminada para todos los juegos</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_description\">Es posible que pierdas el progreso y la configuración de los juegos que has jugado. El juego se reiniciará para aplicar los cambios.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_title\">Cerrar sesión en todos los juegos</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_description\">Es posible que pierdas el progreso y la configuración de los juegos que has jugado. El juego se reiniciará para aplicar los cambios.</string>\n    <string name=\"games_change_per_game_dialog_title\">Selecciona una opción para este juego</string>\n    <string name=\"games_change_per_game_dialog_description\">Cambiar la cuenta o cerrar sesión podría restablecer el progreso y la configuración del juego</string>\n    <string name=\"games_change_per_game_dialog_option_use_player\">Usar %1$s</string>\n    <string name=\"games_change_per_game_dialog_option_use_player_snackbar_success_message\">Se iniciará sesión en este juego con %1$s</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out\">Cerrar sesión</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out_snackbar_success_message\">Has cerrado sesión en este juego</string>\n    <string name=\"games_change_sign_out_of_all_games_snackbar_success_message\">Has cerrado sesión en todos los juegos</string>\n    <string name=\"games_change_default_account_for_all_games_snackbar_success_message\">Se iniciará sesión en todos los juegos con %1$s</string>\n    <string name=\"games_change_default_account_for_new_games_snackbar_success_message\">Se iniciará sesión en los juegos nuevos con %1$s</string>\n    <string name=\"games_account_display_content\">Cuenta actual: %1$s</string>\n    <string name=\"games_delete_profile_header\">Eliminar la cuenta de Play Juegos y todos sus datos</string>\n    <string name=\"games_delete_profile_explanation\">Eliminar permanentemente tu cuenta de Google Play Games, XP y todos los datos de perfil. Esta acción también podría eliminar tus puntajes, progreso (juegos guardados) y configuraciones en los juegos que hayas jugado.</string>\n    <string name=\"games_delete_profile_button\">Eliminar permanentemente</string>\n    <string name=\"games_delete_game_data_header\">Eliminar los datos individuales del juego</string>\n    <string name=\"games_delete_game_data_explanation\">Puedes eliminar permanentemente los datos individuales de los juegos que hayas jugado usando Google Play Games. Esta acción elimina tus puntajes, progreso (juegos guardados) y configuraciones del juego que selecciones.</string>\n    <string name=\"games_delete_profile_dialog_title\">¿Estás seguro de que quieres eliminar esta cuenta?</string>\n    <string name=\"games_delete_profile_explanation_with_gamer_name\">Eliminar permanentemente tu cuenta de Google Play Games para el nombre de jugador <b>%1$s</b> (<b>%2$s</b>), XP y todos los datos de perfil. Esta acción también podría eliminar tus puntajes, progreso (juegos guardados) y configuraciones en los juegos que has jugado.</string>\n    <string name=\"games_delete_profile_dialog_message\">Esta acción no se puede deshacer.</string>\n    <string name=\"games_delete_profile_fail\">No se pudo eliminar tu perfil. Intenta nuevamente más tarde.</string>\n    <string name=\"games_delete_game_data_confirm_dialog_title\">Eliminar los datos de %1$s</string>\n    <string name=\"games_delete_game_data_confirm_dialog_message\">Eliminar permanentemente tus datos de %1$s eliminará tus puntajes, progreso (juegos guardados) y configuraciones del juego en Google Play Games.</string>\n    <string name=\"games_popup_signin_welcome\">Hola, %1$s</string>\n    <string name=\"family_management_title\">Familia</string>\n    <string name=\"family_management_retry\">Reintentar</string>\n    <string name=\"family_management_load_error\">Error al cargar el contenido</string>\n    <string name=\"family_management_toolbar_back\">Atrás</string>\n    <string name=\"family_management_toolbar_more\">Más</string>\n    <string name=\"family_management_exit_family_group\">Dejar el grupo familiar</string>\n    <string name=\"family_management_delete_family_group\">Eliminar un grupo familiar</string>\n    <string name=\"family_management_leave_family_password_title\">Confirma la contraseña para dejar el grupo familiar</string>\n    <string name=\"family_management_delete_family_password_title\">Confirma la contraseña para eliminar el grupo familiar</string>\n    <string name=\"family_management_remove_member_password_title\">Confirma la contraseña para eliminar %s</string>\n    <string name=\"family_management_invite_family_member\">Invitar a los miembros de la familia</string>\n    <string name=\"family_management_invite_slots_left\">Quedan %1$d invitaciones</string>\n    <string name=\"family_management_cancel_invite\">Cancelar invitación</string>\n    <string name=\"family_management_cancel_invite_success\">Invitación cancelada con éxito</string>\n    <string name=\"family_management_cancel_invite_error\">Problema al cancelar la invitación. Intenta nuevamente.</string>\n    <string name=\"family_management_remove_member\">Eliminar miembro</string>\n    <string name=\"family_management_member_removed_success\">%s fue eliminado de tu grupo familiar</string>\n    <string name=\"family_management_member_remove_failed\">Problema al eliminar a %s. Intenta nuevamente.</string>\n    <string name=\"family_management_leave_family_error_message\">Problema al dejar el grupo familiar. Intenta nuevamente.</string>\n    <string name=\"family_management_exist_group_success\">Has dejado tu grupo familiar…</string>\n    <string name=\"family_management_delete_group_success\">Grupo familiar eliminado</string>\n    <string name=\"family_management_delete_group_failure\">Error al eliminar el grupo familiar</string>\n    <string name=\"family_management_delete_group_cancel\">Cancelar</string>\n    <string name=\"family_management_delete_group_confirm\">OK</string>\n    <string name=\"family_management_input_pwd\">Por favor, ingresa tu contraseña</string>\n    <string name=\"family_management_invite_sent_date_format\">Invitación enviada el %s</string>\n    <string name=\"family_management_invite_send\">Invitación enviada</string>\n    <string name=\"family_management_pwd_error\">Contraseña incorrecta, por favor vuelve a ingresarla</string>\n    <string name=\"pref_app_install_settings_title\">Configuración del instalador de aplicaciones</string>\n    <string name=\"pref_app_install_switch_title\">Permitir la instalación de aplicaciones</string>\n    <string name=\"pref_app_install_other_apps_note\">La autorización permite la instalación de aplicaciones proporcionadas desde otras fuentes.</string>\n    <string name=\"pref_app_install_permission_instruction\">Para asegurarte de que tus aplicaciones instaladas funcionen correctamente, por favor autoriza al acompañante de microG a instalar aplicaciones descargadas de otras fuentes.</string>\n    <string name=\"prefcat_app_install_list_title\">Aplicaciones que utilizan el instalador de aplicaciones</string>\n    <string name=\"service_name_google_location_sharing\">Compartir ubicación de Google</string>\n    <string name=\"location_sharing_description\">Gestiona el uso compartido de tu ubicación en tiempo real a través de las aplicaciones y servicios de Google desde este dispositivo</string>\n    <string name=\"location_sharing_learn_more\">Obtén más información sobre el uso compartido de ubicación</string>\n    <string name=\"location_sharing_switch_text\">Usar compartir ubicación</string>\n    <string name=\"location_sharing_turn_off_notify_hint\">Si desactivas el uso compartido de ubicación en este dispositivo, las personas con las que compartes no serán notificadas.</string>\n    <string name=\"location_sharing_off_previous_hint\">Solo tu última ubicación compartida estará disponible hasta que lo actives nuevamente.</string>\n    <string name=\"location_sharing_disabled\">No hay ubicaciones compartidas activas para esta cuenta</string>\n    <string name=\"location_sharing_turn_on_hint\">Una vez que empieces a compartir tu ubicación desde una aplicación o servicio de Google, podrás gestionar el uso compartido de ubicación desde aquí.\\n\\nPara empezar a compartir tu ubicación, ve a Google Maps o Family Link.</string>\n    <string name=\"location_sharing_turn_off_title\">Desactivar el uso compartido de ubicación</string>\n    <string name=\"location_sharing_turn_off_hint\">Aún podrías estar compartiendo tu ubicación desde otros dispositivos conectados a la misma cuenta de Google o desde aplicaciones que no sean de Google. Asegúrate de revisar la configuración de uso compartido de ubicación donde sea que aplique.\\n\\nLas personas con las que compartes seguirán viendo tu última ubicación compartida.</string>\n    <string name=\"location_sharing_turn_off_cancel\">Mantener encendido</string>\n    <string name=\"location_sharing_turn_off_confirm\">Desactivar</string>\n    <string name=\"location_sharing_confirm_dialog_title\">Habilitar el uso compartido de ubicación</string>\n    <string name=\"location_sharing_confirm_dialog_text\">Las personas con las que compartes tu ubicación siempre podrán ver:\\n·Tu nombre y foto\\n·La ubicación reciente de tu dispositivo, incluso cuando no estés usando un servicio de Google\\n·El nivel de batería de tu dispositivo y si está cargando\\n·Tu hora de llegada y salida, si agregan una notificación de uso compartido de ubicación</string>\n    <string name=\"service_name_device_attestation\">Certificación del dispositivo</string>\n    <string name=\"prefcat_device_attestation_apps_title\">Apps con certificación del dispositivo</string>\n    <string name=\"pref_device_attestation_app_allow_requests_title\">Permitir solicitudes</string>\n    <string name=\"pref_device_attestation_app_allow_requests_summary\">Permitir que la app solicite la certificación del dispositivo</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-fa/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"permission_service_adsense_description\">به برنامه اجازه می‌دهد با هر حساب گوگل مرتبط به ادسنس دسترسی داشته باشد.</string>\n    <string name=\"permission_service_all_description\">به برنامه اجازه می‌دهد با هر حساب گوگل مرتبط به همه خدمات گوگل دسترسی داشته باشد.</string>\n    <string name=\"permission_service_adwords_label\">ادوردز</string>\n    <string name=\"permission_service_adwords_description\">به برنامه اجازه می‌دهد با هر حساب گوگل مرتبط به ادوردز دسترسی داشته باشد.</string>\n    <string name=\"permission_service_ah_description\">به برنامه اجازه می‌دهد با هر حساب گوگل مرتبط به موتور برنامه گوگل دسترسی داشته باشد.</string>\n    <string name=\"permission_service_blogger_description\">به برنامه اجازه می‌دهد با هر حساب گوگل مرتبط به بلاگر دسترسی داشته باشد.</string>\n    <string name=\"permission_service_cl_label\">تقویم گوگل</string>\n    <string name=\"permission_service_cl_description\">به برنامه اجازه می‌دهد با هر حساب گوگل مرتبط به تقویم گوگل دسترسی داشته باشد.</string>\n    <string name=\"permission_service_dodgeball_label\">داج‌بال</string>\n    <string name=\"permission_service_dodgeball_description\">به برنامه اجازه می‌دهد با هر حساب گوگل مرتبط به داج‌بال دسترسی داشته باشد.</string>\n    <string name=\"permission_service_finance_label\">مالی گوگل</string>\n    <string name=\"permission_service_grandcentral_label\">صدا گوگل</string>\n    <string name=\"permission_service_finance_description\">به برنامه اجازه می‌دهد با هر حساب گوگل مرتبط به مالی گوگل دسترسی داشته باشد.</string>\n    <string name=\"permission_service_gbase_label\">پایگاه گوگل</string>\n    <string name=\"permission_service_gbase_description\">به برنامه اجازه می‌دهد با هر حساب گوگل مرتبط به پایگاه گوگل دسترسی داشته باشد.</string>\n    <string name=\"permission_service_grandcentral_description\">به برنامه اجازه می‌دهد با هر حساب گوگل مرتبط به صدا گوگل دسترسی داشته باشد.</string>\n    <string name=\"permission_service_groups2_label\">گروه‌های گوگل</string>\n    <string name=\"permission_service_groups2_description\">به برنامه اجازه می‌دهد با هر حساب گوگل مرتبط به گروه‌های گوگل دسترسی داشته باشد.</string>\n    <string name=\"permission_service_health_label\">سلامت گوگل</string>\n    <string name=\"permission_service_health_description\">به برنامه اجازه می‌دهد با هر حساب گوگل مرتبط به سلامت گوگل دسترسی داشته باشد.</string>\n    <string name=\"permission_service_lh2_description\">به برنامه اجازه می‌دهد با هر حساب گوگل مرتبط به آلبوم‌های وب پیکاسا دسترسی داشته باشد.</string>\n    <string name=\"permission_service_all_label\">همه خدمات گوگل</string>\n    <string name=\"permission_service_local_description\">به برنامه اجازه می‌دهد با هر حساب گوگل مرتبط به نقشه‌های گوگل دسترسی داشته باشد.</string>\n    <string name=\"permission_service_mail_label\">رایانامه گوگل</string>\n    <string name=\"permission_service_mail_description\">به برنامه اجازه می‌دهد با هر حساب گوگل مرتبط به رایانامه گوگل دسترسی داشته باشد.</string>\n    <string name=\"permission_service_news_label\">اخبار گوگل</string>\n    <string name=\"permission_service_news_description\">به برنامه اجازه می‌دهد با هر حساب گوگل مرتبط به اخبار گوگل دسترسی داشته باشد.</string>\n    <string name=\"permission_service_notebook_label\">یادداشت گوگل</string>\n    <string name=\"permission_service_notebook_description\">به برنامه اجازه می‌دهد با هر حساب گوگل مرتبط به یادداشت گوگل دسترسی داشته باشد.</string>\n    <string name=\"permission_service_orkut_label\">اورکات</string>\n    <string name=\"permission_service_orkut_description\">به برنامه اجازه می‌دهد با هر حساب گوگل مرتبط به اورکات دسترسی داشته باشد.</string>\n    <string name=\"permission_service_print_description\">به برنامه اجازه می‌دهد با هر حساب گوگل مرتبط به جستجوی کتاب گوگل دسترسی داشته باشد.</string>\n    <string name=\"permission_service_sierra_label\">حساب‌های پرداخت گوگل</string>\n    <string name=\"permission_service_sierra_description\">به برنامه اجازه می‌دهد با هر حساب گوگل مرتبط به حساب‌های پرداخت گوگل دسترسی داشته باشد.</string>\n    <string name=\"permission_service_sierraqa_description\">به برنامه اجازه می‌دهد با هر حساب گوگل مرتبط به حساب‌های آزمایشی پرداخت گوگل دسترسی داشته باشد.</string>\n    <string name=\"permission_service_sierrasandbox_label\">حساب‌های آزمایشی سندباکس پرداخت گوگل</string>\n    <string name=\"permission_service_speechpersonalization_label\">تشخیص گفتار شخصی‌سازی‌شده</string>\n    <string name=\"permission_service_sierrasandbox_description\">به برنامه اجازه می‌دهد با هر حساب گوگل مرتبط به حساب‌های آزمایشی سندباکس پرداخت گوگل دسترسی داشته باشد.</string>\n    <string name=\"permission_service_sitemaps_label\">ابزارهای وب‌مستر گوگل</string>\n    <string name=\"permission_service_sitemaps_description\">به برنامه اجازه می‌دهد با هر حساب گوگل مرتبط به ابزارهای وب‌مستر گوگل دسترسی داشته باشد.</string>\n    <string name=\"permission_service_speech_label\">جستجوی صوتی</string>\n    <string name=\"permission_service_speech_description\">به برنامه اجازه می‌دهد با هر حساب گوگل مرتبط به جستجوی صوتی دسترسی داشته باشد.</string>\n    <string name=\"permission_service_speechpersonalization_description\">به برنامه اجازه می‌دهد با هر حساب گوگل مرتبط به تشخیص گفتار شخصی‌سازی‌شده دسترسی داشته باشد.</string>\n    <string name=\"permission_service_talk_label\">گفتگوی گوگل</string>\n    <string name=\"permission_service_wise_description\">به برنامه اجازه می‌دهد با هر حساب گوگل مرتبط به صفحه‌گسترده‌های گوگل دسترسی داشته باشد.</string>\n    <string name=\"permission_service_talk_description\">به برنامه اجازه می‌دهد با هر حساب گوگل مرتبط به گفتگوی گوگل دسترسی داشته باشد.</string>\n    <string name=\"permission_service_wifi_label\">وای‌فای گوگل</string>\n    <string name=\"permission_service_wifi_description\">به برنامه اجازه می‌دهد با هر حساب گوگل مرتبط به وای‌فای گوگل دسترسی داشته باشد.</string>\n    <string name=\"permission_service_wise_label\">صفحه‌گسترده‌های گوگل</string>\n    <string name=\"permission_service_writely_description\">به برنامه اجازه می‌دهد با هر حساب گوگل مرتبط به سندهای گوگل دسترسی داشته باشد.</string>\n    <string name=\"permission_service_youtube_label\">یوتوب</string>\n    <string name=\"permission_service_youtube_description\">به برنامه اجازه می‌دهد با هر حساب گوگل مرتبط به یوتوب دسترسی داشته باشد.</string>\n    <string name=\"permission_service_YouTubeUser_label\">نام‌های کاربری یوتوب</string>\n    <string name=\"permission_service_YouTubeUser_description\">به برنامه اجازه می‌دهد با هر حساب گوگل مرتبط به نام‌های کاربری یوتوب دسترسی داشته باشد.</string>\n    <string name=\"perm_activity_recognition_label\">تشخیص فعالیت</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute.readonly\">مشاهده منابع موتور محاسباتی گوگل شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute\">مشاهده و مدیریت منابع موتور محاسباتی گوگل شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate\">مشاهده و مدیریت کارهای مختصات نقشه‌های گوگل شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_only\">مشاهده داده‌های شما در ذخیره‌سازی ابری گوگل</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_write\">مدیریت داده‌های شما در ذخیره‌سازی ابری گوگل</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate.readonly\">مشاهده کارهای مختصات گوگل شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.appdata\">دسترسی به پوشه داده‌های برنامه</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.apps.readonly\">مشاهده برنامه‌های درایو گوگل شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.file\">مشاهده و مدیریت پرونده‌های درایو گوگل که با این برنامه باز یا ساخته شده‌اند</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.metadata.readonly\">مشاهده فراداده‌های پرونده‌ها و سندها در درایو گوگل شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.readonly\">مشاهده پرونده‌ها و سندهای درایو گوگل شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase.readonly\">مشاهده حساب فری‌بیس شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase\">ورود به فری‌بیس با حساب شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.install\">دامنه ویژه برای اجازه به کاربران برای تأیید نصب برنامه</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_games\">دامنه برای دسترسی به داده‌های بازی‌های گوگل پلی.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan\">مدیریت داده‌های GAN شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan.readonly\">مشاهده داده‌های GAN شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gcm_for_chrome\">پیام‌رسانی ابری برای کروم</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables\">مدیریت جدول‌های فیوژن شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables.readonly\">مشاهده جدول‌های فیوژن شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_glass.timeline\">دامنه جدول زمانی گلاس</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.best\">مدیریت مکان با بهترین دقت و تاریخچه مکان شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.city\">مدیریت مکان در سطح شهر و تاریخچه مکان شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.best\">مدیریت مکان با بهترین دقت شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.compose\">ساخت، خواندن، به‌روزرسانی و پاک کردن پیش‌نویس‌ها. فرستادن پیام‌ها و پیش‌نویس‌ها.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.modify\">همه عملیات خواندن/نوشتن به جز حذف فوری و دائمی نخ‌ها و پیام‌ها، بدون گذر از زباله‌دان.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.readonly\">خواندن همه منابع و فراداده‌های آن‌ها—بدون عملیات نوشتن.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.city\">مدیریت مکان در سطح شهر شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine.readonly\">مشاهده داده‌های موتور نقشه‌های گوگل شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mobilemaps.firstparty\">مشاهده و مدیریت تجربه نقشه‌های گوگل برای همراه شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut\">مدیریت فعالیت اورکات شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine\">مشاهده و مدیریت داده‌های موتور نقشه‌های گوگل شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut.readonly\">مشاهده داده‌های اورکات شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.login\">دانستن نام، اطلاعات پایه و فهرست افرادی که در گوگل‌پلاس با آن‌ها مرتبط هستید</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.me\">دانستن هویت شما در گوگل</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_prediction\">مدیریت داده‌های شما در API پیش‌بینی گوگل</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue\">مدیریت وظایف شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_shoppingapi\">مشاهده داده‌های محصول شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks.readonly\">مشاهده کارهای شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification\">مدیریت فهرست وبگاه‌ها و دامنه‌هایی که کنترل می‌کنید</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification.verify_only\">مدیریت تأیید وبگاه‌های جدید شما با گوگلJwt</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_structuredcontent\">دسترسی خواندن/نوشتن به API محتوای ساخت‌یافته.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue.consumer\">مصرف وظایف از صف وظایف شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tracks\">API مسیرهای نقشه‌های گوگل، این دامنه اجازه دسترسی خواندن و نوشتن به داده‌های پروژه شما را می‌دهد.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_urlshortener\">مدیریت نشانی‌های کوتاه goo.gl شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.email\">مشاهده نشانی رایانامه شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube\">مدیریت حساب یوتوب شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.profile\">مشاهده اطلاعات پایه درباره حساب شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtubepartner\">مشاهده و مدیریت دارایی‌ها و محتوای مرتبط شما در یوتوب</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.readonly\">مشاهده حساب یوتوب شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.upload\">مدیریت ویدیوهای یوتوب شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics_monetary.readonly\">مشاهده گزارش‌های مالی آنالیتیکس یوتوب برای محتوای یوتوب شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics.readonly\">مشاهده گزارش‌های آنالیتیکس یوتوب برای محتوای یوتوب شما</string>\n    <string name=\"permission_service_android_label\">خدمات اندروید</string>\n    <string name=\"permission_service_android_description\">به برنامه اجازه می‌دهد با هر حساب گوگل مرتبط به خدمات اندروید دسترسی داشته باشد.</string>\n    <string name=\"permission_service_adsense_label\">ادسنس</string>\n    <string name=\"permission_service_ah_label\">موتور برنامه گوگل</string>\n    <string name=\"permission_service_blogger_label\">بلاگر</string>\n    <string name=\"permission_service_cp_label\">مخاطبین</string>\n    <string name=\"permission_service_cp_description\">به برنامه اجازه می‌دهد با هر حساب گوگل مرتبط به مخاطبین دسترسی داشته باشد.</string>\n    <string name=\"permission_service_ig_label\">آی‌گوگل</string>\n    <string name=\"permission_service_ig_description\">به برنامه اجازه می‌دهد با هر حساب گوگل مرتبط به آی‌گوگل دسترسی داشته باشد.</string>\n    <string name=\"permission_service_jotspot_label\">جات‌اسپات</string>\n    <string name=\"permission_service_jotspot_description\">به برنامه اجازه می‌دهد با هر حساب گوگل مرتبط به جات‌اسپات دسترسی داشته باشد.</string>\n    <string name=\"permission_service_knol_label\">نول</string>\n    <string name=\"permission_service_knol_description\">به برنامه اجازه می‌دهد با هر حساب گوگل مرتبط به نول دسترسی داشته باشد.</string>\n    <string name=\"permission_service_lh2_label\">آلبوم‌های وب پیکاسا</string>\n    <string name=\"permission_service_local_label\">نقشه‌های گوگل</string>\n    <string name=\"permission_service_print_label\">جستجوی کتاب گوگل</string>\n    <string name=\"permission_service_sierraqa_label\">حساب‌های آزمایشی پرداخت گوگل</string>\n    <string name=\"permission_service_writely_label\">سندهای گوگل</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.licensing\">دسترسی خواندن/نوشتن به API مدیریت مجوز.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.full_control\">مدیریت داده‌ها و دسترسی‌ها در ذخیره‌سازی ابری گوگل</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_dfareporting\">مشاهده و مدیریت گزارش‌های دابل‌کلیک برای تبلیغ‌کنندگان</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.scripts\">تغییر رفتار اسکریپت‌های برنامه‌های گوگل شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive\">مشاهده و مدیریت پرونده‌ها و سندهای درایو گوگل شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks\">مدیریت کارهای شما</string>\n    <string name=\"perm_activity_recognition_description\">به برنامه اجازه می‌دهد به‌روزرسانی‌های دوره‌ای سطح فعالیت شما را از گوگل دریافت کند، برای نمونه، اگر در حال پیاده‌روی، رانندگی، دوچرخه‌سواری یا ثابت هستید.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_activity\">مشاهده تاریخچه فعالیت برنامه‌های گوگل شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.buyer\">مدیریت پیکربندی حساب خریدار اداکسچنج شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller.readonly\">مشاهده داده‌های اداکسچنج شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller\">مشاهده و مدیریت داده‌های اداکسچنج شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsensehost\">مشاهده و مدیریت داده‌های میزبان ادسنس و حساب‌های مرتبط</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense.readonly\">مشاهده داده‌های ادسنس شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense\">مشاهده و مدیریت داده‌های ادسنس شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics.readonly\">مشاهده داده‌های آنالیتیکس گوگل شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics\">مشاهده و مدیریت داده‌های آنالیتیکس گوگل شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_androidpublisher\">دسترسی به توسعه‌دهنده اندروید گوگل پلی</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appengine.admin\">دامنه مدیریت موتور برنامه.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.migration\">دسترسی خواندن و نوشتن به API مهاجرت گروه‌ها.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.settings\">مشاهده و مدیریت تنظیمات گروه برنامه‌های گوگل</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order\">برای مدیران و کاربران فروشنده دسترسی خواندن/نوشتن هنگام آزمایش در سندباکس API یا دسترسی خواندن/نوشتن هنگام فراخوانی مستقیم یک عملیات API.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order.readonly\">علاوه بر دامنه کلی خواندن/نوشتن OAuth، از دامنه فقط خواندن OAuth هنگام بازیابی داده‌های مشتری استفاده کنید.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps_reporting_audit.readonly\">دسترسی به API بازرسی مدیریت فقط خواندن</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appstate\">دامنه برای استفاده از خدمت حالت برنامه.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery.readonly\">مشاهده داده‌های شما در گوگل بیگ‌کوئری</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery\">مشاهده و مدیریت داده‌های شما در گوگل بیگ‌کوئری</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger\">مدیریت حساب بلاگر شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger.readonly\">مشاهده حساب بلاگر شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_books\">مدیریت کتاب‌های شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar\">مدیریت تقویم‌های شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar.readonly\">مشاهده تقویم‌های شما</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_cloudprint\">مشاهده و مدیریت داده‌های چاپ ابری گوگل شما</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-fa/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <plurals name=\"pref_unifiednlp_summary\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> زیرساخت پیکربندی شده</item>\n        <item quantity=\"other\"><xliff:g example=\"3\">%1$d</xliff:g> زیرساخت پیکربندی شده</item>\n    </plurals>\n    <plurals name=\"gcm_registered_apps_counter\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> برنامه ثبت شده</item>\n        <item quantity=\"other\"><xliff:g example=\"123\">%1$d</xliff:g> برنامه ثبت شده</item>\n    </plurals>\n    <plurals name=\"cond_perm_summary\">\n        <item quantity=\"one\">مجوز لازم برای عملکرد صحیح حدمات میکروجی داده نمی شود.</item>\n        <item quantity=\"other\">مجوزهای لازم برای عملکرد صحیح حدمات میکروجی داده نمی شود.</item>\n    </plurals>\n    <plurals name=\"cond_perm_action\">\n        <item quantity=\"one\">درخواست مجوز از دست رفته</item>\n        <item quantity=\"other\">درخواست مجوزهای از دست رفته</item>\n    </plurals>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-fa/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=\"gms_settings_summary\">پیکربندی خدمات میکروجی.</string>\n    <string name=\"just_a_sec\">یک لحظه…</string>\n    <string name=\"google_account_label\">گوگل</string>\n    <string name=\"ask_permission_tos\">با ادامه، به این برنامه و گوگل اجازه می‌دهید داده‌های شما را با شرایط خدمت و سیاست‌های حریم خصوصی خود به‌کار گیرند.</string>\n    <string name=\"ask_scope_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> مایل است:</string>\n    <string name=\"ask_service_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> مایل به استفاده از:</string>\n    <string name=\"sorry\">پوزش…</string>\n    <string name=\"auth_action_step_enable_lockscreen\">پیکربندی قفل امن صفحه</string>\n    <string name=\"games_info_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> مایل به استفاده از بازی‌های پلی است</string>\n    <string name=\"place_picker_nearby_places\">مکان‌های نزدیک</string>\n    <string name=\"place_picker_location_lat_lng\">(%1$.7f، %2$.7f)</string>\n    <string name=\"lacking_permission_toast\">خدمات میکروجی: فقدان دسترسی برای <xliff:g example=\"have full network acccess\">%1$s</xliff:g></string>\n    <string name=\"network_type_mobile\">شبکه همراه</string>\n    <string name=\"network_type_wifi\">وای‌فای</string>\n    <string name=\"network_type_roaming\">فراگردی(رومینگ)</string>\n    <string name=\"network_type_other\">شبکه‌های دیگر</string>\n    <string name=\"self_check_cat_gms_packages\">بسته‌های نصب‌شده</string>\n    <string name=\"self_check_cat_system\">سامانه</string>\n    <string name=\"self_check_name_fake_sig_perm\">سامانه از جعل امضا پشتیبانی می‌کند:</string>\n    <string name=\"self_check_resolution_fake_sig_perm\">رام شما پشتیبانی بومی از جعل امضا ندارد. همچنان می‌توانید از Xposed یا سامانه‌های دیگر برای جعل امضا استفاده کنید. لطفاً مستندات را بررسی کنید تا ببینید کدام رام‌ها از جعل امضا پشتیبانی می‌کنند و چگونه از میکروجی در رام‌هایی که پشتیبانی نمی‌کنند استفاده کنید.</string>\n    <string name=\"self_check_name_perm_granted\">سامانه دسترسی جعل امضا را اعطا می‌کند:</string>\n    <string name=\"self_check_resolution_system_spoofs\">لطفاً مستندات را بررسی کنید تا ببینید چه مراحلی ممکن است لازم باشد.</string>\n    <string name=\"self_check_name_system_spoofs\">سامانه امضا را جعل می‌کند:</string>\n    <string name=\"self_check_pkg_gms\">خدمات پلی (microG)</string>\n    <string name=\"self_check_pkg_vending\">فروشگاه پلی / پیوست (microG)</string>\n    <string name=\"self_check_pkg_gsf\">چارچوب خدمات (microG)</string>\n    <string name=\"self_check_name_app_installed\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> نصب‌شده:</string>\n    <string name=\"gcm_allow_app_popup\">اجازه به <xliff:g example=\"F-Droid\">%1$s</xliff:g> برای ثبت آگاه‌سازهای فشاری؟</string>\n    <string name=\"pref_push_app_allow_register_title\">اجازه ثبت</string>\n    <string name=\"pref_push_app_allow_register_summary\">اجازه به برنامه برای ثبت آگاه‌سازهای فشاری.</string>\n    <string name=\"pref_push_app_wake_for_delivery_title\">آغاز برنامه هنگام پیام فشاری</string>\n    <string name=\"pref_push_app_wake_for_delivery_summary\">آغاز برنامه در پس‌زمینه برای دریافت پیام‌های فشاری ورودی.</string>\n    <string name=\"prefcat_push_apps_title\">برنامه‌های استفاده‌کننده از آگاه‌سازهای فشاری</string>\n    <string name=\"prefcat_push_apps_registered_title\">برنامه‌های ثبت‌شده</string>\n    <string name=\"prefcat_push_apps_unregistered_title\">برنامه‌های ثبت‌نشده</string>\n    <string name=\"prefcat_push_networks_title\">شبکه‌های مورد استفاده برای آگاه‌سازهای فشاری</string>\n    <string name=\"pref_vending_summary_licensing_off\">مجوز خاموش</string>\n    <string name=\"pref_vending_summary_licensing_on\">مجوز روشن</string>\n    <string name=\"pref_vending_feature_delivery\">تحویل ویژگی گوگل پلی</string>\n    <string name=\"pref_vending_licensing_split_install_summary\">اجازه به برنامه‌ها برای بارگیری و نصب اجزای افزوده</string>\n    <string name=\"pref_vending_licensing_category\">مجوز گوگل پلی</string>\n    <string name=\"pref_vending_licensing_enable_switch\">پاسخ به درخواست‌های پذیرش مجوز</string>\n    <string name=\"pref_vending_license_enable_summary\">برخی برنامه‌ها نیاز به پذیرش خرید از گوگل پلی دارند. وقتی برنامه‌ای درخواست کند، میکروجی می‌تواند مدرک خرید را از گوگل بارگیری کند. اگر غیرفعال باشد یا حساب گوگل افزوده نشده باشد، درخواست‌های پذیرش مجوز نادیده گرفته می‌شوند.</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_summary\">برنامه‌های رایگان ممکن است بررسی کنند که آیا از گوگل پلی بارگیری شده‌اند. برنامه‌های رایگان را به‌شیوه خودکار به کتابخانه حساب شما می‌افزاید تا همیشه بررسی برای همه برنامه‌های رایگان در دسترس شما گذرانده شود.</string>\n    <string name=\"backup_disabled\">پشتیبان‌گیری هم‌اکنون ممکن نیست</string>\n    <string name=\"pref_vending_billing_category\">صورت‌حساب گوگل پلی</string>\n    <string name=\"pref_vending_billing_enable_switch\">مدیریت درخواست‌های صورت‌حساب</string>\n    <string name=\"pref_vending_billing_note_experimental\">این ویژگی آزمایشی است و ممکن است به از دست دادن پول منجر شود. هشدار داده شد.</string>\n    <string name=\"pref_vending_billing_note_licensing\">برخی برنامه‌ها ممکن است برای پذیرش خریدهای شما نیاز به فعال‌سازی پذیرش مجوز داشته باشند.</string>\n    <string name=\"pref_vending_billing_enable_summary\">وقتی فعال باشد، برخی برنامه‌ها می‌توانند خریدها یا اشتراک‌ها را از طریق خدمت صورت‌حساب پلی گوگل کامل کنند.</string>\n    <string name=\"pref_vending_asset_delivery_category\">تحویل دارایی گوگل پلی</string>\n    <string name=\"pref_vending_asset_device_sync_summary\">برنامه‌های استفاده‌کننده از تحویل دارایی پلی دارایی‌های افزوده را بر اساس داده‌های دستگاه در حال استفاده بارگیری خواهند کرد.</string>\n    <string name=\"pref_vending_asset_device_sync_switch\">فعال‌سازی همگام‌سازی داده‌های دستگاه</string>\n    <string name=\"pref_workprofile_create_account\">اجازه پیکربندی حساب کاری</string>\n    <string name=\"games_delete_snapshot_dialog_title\">پاک کردن بازی نگه‌داری شده</string>\n    <string name=\"games_delete_snapshot_dialog_message\">آیا مطمئن هستید که می‌خواهید این بازی نگه‌داری شده را پاک کنید؟</string>\n    <string name=\"games_delete_snapshot_dialog_cancel\">رد کردن</string>\n    <string name=\"games_delete_snapshot_dialog_ok\">پذیرش</string>\n    <string name=\"games_delete_snapshot_error\">پاک کردن ناموفق بود، لطفاً بعداً دوباره امتحان کنید</string>\n    <string name=\"barcode_scanner_brand\">پویش‌شده توسط میکروجی به نمایندگی از %1$s</string>\n    <string name=\"camera_permission_dialog_button\">پذیرش</string>\n    <string name=\"auth_connecting\">دستگاه شما در حال برقراری ارتباط با سرورهای گوگل برای ورود است.\\n\\nاین کار ممکن است چند ثانیه طول بکشد.</string>\n    <string name=\"gms_app_name\">خدمات میکروجی</string>\n    <string name=\"limited_services_app_name\">خدمات محدود میکروجی</string>\n    <string name=\"gms_settings_name\">تنظیمات میکروجی</string>\n    <string name=\"account_manager_title\">مدیریت حساب گوگل</string>\n    <string name=\"auth_sign_in\">ورود</string>\n    <string name=\"auth_general_error_desc\">مشکلی در ارتباط با سرورهای گوگل رخ داد.\\n\\nبعداً دوباره امتحان کنید.</string>\n    <string name=\"auth_action_notification_title\">نیاز به کنش حساب</string>\n    <string name=\"signin_confirm_button_text\">پذیرفتن و هم‌رسانی</string>\n    <string name=\"perm_extended_access_label\">دسترسی گسترده به خدمات گوگل</string>\n    <string name=\"service_name_snet\">شبکه ایمنی</string>\n    <string name=\"games_info_content\">برای استفاده از بازی‌های پلی، نصب برنامه بازی‌های گوگل پلی لازم است. برنامه ممکن است بدون بازی‌های پلی ادامه دهد، اما ممکن است رفتار غیرمنتظره‌ای داشته باشد.</string>\n    <string name=\"pick_place_title\">انتخاب مکان</string>\n    <string name=\"pick_place_desc\">انتخاب‌گر مکان هنوز در دسترس نیست.</string>\n    <string name=\"place_picker_select_title\">انتخاب این مکان</string>\n    <string name=\"self_check_cat_fake_sig\">پشتیبانی از جعل امضا</string>\n    <string name=\"self_check_resolution_perm_granted\">این نشانه قوی است که رام از جعل امضا پشتیبانی می‌کند، اما نیاز به کنش بیشتری برای فعال‌سازی دارد. لطفاً مستندات را بررسی کنید تا ببینید چه مراحلی ممکن است لازم باشد.</string>\n    <string name=\"prefcat_about\">درباره</string>\n    <string name=\"prefcat_components\">اجزا</string>\n    <string name=\"pref_auth_include_android_id_title\">پذیرش هویت با ثبت دستگاه</string>\n    <string name=\"pref_device_registration_android_id\">شناسه اندروید</string>\n    <string name=\"checkin_not_registered\">ثبت‌نشده</string>\n    <string name=\"pref_info_status\">وضعیت</string>\n    <string name=\"pref_gcm_apps_summary\">فهرست برنامه‌هایی که هم‌اکنون برای پیام‌رسانی ابری ثبت شده‌اند.</string>\n    <string name=\"pref_gcm_confirm_new_apps_title\">پذیرش برنامه‌های جدید</string>\n    <string name=\"pref_gcm_ping_interval\">بازه پینگ: <xliff:g example=\"10 minutes\">%1$s</xliff:g></string>\n    <string name=\"gcm_no_message_yet\">هنوز پیامی دریافت نشده است</string>\n    <string name=\"gcm_messages_counter\">پیام‌ها: <xliff:g example=\"123\">%1$d</xliff:g> (<xliff:g example=\"12345\">%2$d</xliff:g> بایت)</string>\n    <string name=\"gcm_network_state_connected\">متصل از <xliff:g example=\"2 hours ago\">%1$s</xliff:g></string>\n    <string name=\"safetynet_enable_switch\">اجازه گواهی دستگاه</string>\n    <string name=\"pref_safetynet_test_title\">آزمایش گواهی شبکه ایمنی</string>\n    <string name=\"prefcat_safetynet_apps_title\">برنامه‌های استفاده‌کننده از شبکه ایمنی</string>\n    <string name=\"profile_name_native\">بومی</string>\n    <string name=\"profile_name_user\">سفارشی: %s</string>\n    <string name=\"profile_name_auto\">خودکار: %s</string>\n    <string name=\"pref_device_registration_import_custom_profile_summary\">وارد کردن نمایه دستگاه از پرونده</string>\n    <string name=\"pref_device_registration_select_profile_title\">انتخاب نمایه</string>\n    <string name=\"pref_safetynet_recent_cat_response\">داده‌های پاسخ</string>\n    <string name=\"pref_safetynet_recent_cat_request\">داده‌های درخواست</string>\n    <string name=\"pref_safetynet_recent_copied\">در بریده‌دان رونویسی شد!</string>\n    <string name=\"pref_safetynet_test_integrity_cts_passed\">یکپارچگی و CTS گذرانده شد</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_switch\">افزودن خودکار برنامه‌های رایگان به کتابخانه</string>\n    <string name=\"pref_vending_split_install_switch\">نصب اجزای درخواستی</string>\n    <string name=\"feedback_disabled\">بازخورد هم‌اکنون ممکن نیست</string>\n    <string name=\"pref_vending_asset_delivery_switch\">فعال‌سازی تحویل دارایی درخواستی</string>\n    <string name=\"pref_vending_asset_delivery_summary\">بارگیری دارایی‌های افزوده وقتی توسط برنامه‌هایی که از تحویل دارایی پلی استفاده می‌کنند درخواست شود</string>\n    <string name=\"limited_services_dialog_information_ack\">درک کردم</string>\n    <string name=\"camera_permission_dialog_title\">نیاز به دسترسی دوربین</string>\n    <string name=\"signin_picker_title\">انتخاب بک حساب</string>\n    <string name=\"auth_action_step_enable_checkin_description\">دستگاه شما باید دست کم یک‌بار در گوگل ثبت شود.\\n\\nمی‌توانید ثبت دستگاه گوگل را پس از تکمیل پیکربندی حساب غیرفعال کنید.</string>\n    <string name=\"service_name_work_profile\">نمایه کاری</string>\n    <string name=\"games_title\">بازی‌های گوگل پلی</string>\n    <string name=\"push_notifications_summary_values_seconds\">%s ثانیه</string>\n    <string name=\"allow\">پذیرفتن</string>\n    <string name=\"deny\">رد کردن</string>\n    <string name=\"auth_notification_title\">نیاز به پذیرش هویت</string>\n    <string name=\"auth_notification_content\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> برای دسترسی به حساب گوگل شما نیاز به پذیرش شما دارد.</string>\n    <string name=\"auth_package_override_request_title\">آیا به <b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> دسترسی ویژه به <xliff:g example=\"account@example.com\">%2$s</xliff:g> داده شود؟</string>\n    <string name=\"auth_package_override_request_message\"><b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> می‌خواهد به حساب شما به‌گونه‌ای دسترسی یابد که گویی <b><xliff:g example=\"F-Droid\">%2$s</xliff:g> توسط <xliff:g example=\"F-Droid Inc.\">%3$s</xliff:g></b> است. این ممکن است دسترسی ویژه‌ای به حساب شما بدهد.</string>\n    <string name=\"auth_action_notification_channel_name\">هشدارهای حساب گوگل</string>\n    <string name=\"auth_action_notification_channel_description\">هنگامی که یکی از حساب‌های گوگل شما نیاز به تنظیمات افزوده داشته باشد یا با میکروجی سازگار نباشد، آگاه‌سازی می‌کند.</string>\n    <string name=\"auth_action_notification_content\">حساب گوگل شما نیاز به تنظیمات افزوده دارد.</string>\n    <string name=\"auth_action_activity_header\">تکمیل پیکربندی حساب گوگل</string>\n    <string name=\"auth_action_activity_explanation\">برای به‌کار بردن حساب گوگل %s روی این دستگاه، مراحل زیر را کامل کنید.</string>\n    <string name=\"auth_action_step_enable_checkin\">فعال‌سازی ثبت دستگاه</string>\n    <string name=\"auth_action_step_enable_gcm\">فعال‌سازی پیام‌رسانی ابری</string>\n    <string name=\"auth_action_step_enable_gcm_description\">می‌توانید پیام‌رسانی ابری را پس از تکمیل پیکربندی حساب غیرفعال کنید.</string>\n    <string name=\"auth_action_step_allow_microg_gcm\">اجازه پیام‌رسانی ابری برای میکروجی</string>\n    <string name=\"auth_action_step_allow_microg_gcm_description\">بر پایه تنظیمات شما، میکروجی پیش از ثبت برای پیام‌رسانی ابری نیاز به اجازه شما دارد.</string>\n    <string name=\"auth_finalize\">دستگاه شما در حال تماس با گوگل برای نگه‌داری داده‌ها در حساب شما است.\\n\\nاین کار ممکن است چند دقیقه طول بکشد.</string>\n    <string name=\"auth_action_step_perform_content_description\">برای انجام گام کلیک کنید</string>\n    <string name=\"auth_action_step_completed_content_description\">گام تکمیل شد</string>\n    <string name=\"auth_action_activity_finish\">پایان</string>\n    <string name=\"signin_picker_subtitle\">برای ادامه به <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"signin_picker_add_account_label\">افزودن حساب دیگر</string>\n    <string name=\"signin_confirm_title\">اجازه ورود به <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"signin_subtext_sharing\">برای ادامه، میکروجی نام، نشانی رایانامه و تصویر نمایه حساب گوگل شما را با <xliff:g example=\"F-Droid\">%1$s</xliff:g> هم‌رسانی خواهد کرد.</string>\n    <string name=\"signin_subtext_policy\">پیش از به‌کارگیری این برنامه، %1$s و %2$s آن را بررسی کنید.</string>\n    <string name=\"signin_subtext_policy_privacy\">سیاست حریم خصوصی</string>\n    <string name=\"signin_subtext_policy_terms\">شرایط خدمت</string>\n    <string name=\"perm_status_broadcast_label\">گوش دادن به پخش‌های داخلی وضعیت</string>\n    <string name=\"perm_gsf_read_gservices_label\">خواندن پیکربندی خدمت گوگل</string>\n    <string name=\"perm_c2dm_receive_label\">گوش دادن به پیام‌های C2DM</string>\n    <string name=\"perm_c2dm_send_label\">فرستادن پیام‌های C2DM به برنامه‌های دیگر</string>\n    <string name=\"perm_gtalk_svc_label\">دادوستد پیام‌ها و دریافت آگاه‌سازهای همگام‌سازی از سرورهای گوگل</string>\n    <string name=\"perm_provision_label\">تدارک خدمات میکروجی</string>\n    <string name=\"perm_provision_description\">به برنامه اجازه می‌دهد خدمات میکروجی را بدون تعامل کاربر پیکربندی کند</string>\n    <string name=\"perm_car_speed_label\">سرعت خودرو</string>\n    <string name=\"perm_car_speed_description\">دسترسی به سرعت خودروی شما</string>\n    <string name=\"perm_car_info_label\">داده‌های خودرو</string>\n    <string name=\"perm_car_info_description\">دسترسی به داده‌های خودروی شما</string>\n    <string name=\"perm_car_fuel_label\">سطح سوخت خودرو</string>\n    <string name=\"perm_car_fuel_description\">دسترسی به داده‌های سطح سوخت خودروی شما</string>\n    <string name=\"perm_car_mileage_label\">مسافت خودرو</string>\n    <string name=\"perm_car_mileage_description\">دسترسی به داده‌های مسافت خودروی شما</string>\n    <string name=\"perm_car_vendor_extension_label\">کانال فروشنده خودرو</string>\n    <string name=\"perm_car_vendor_extension_description\">دسترسی به کانال فروشنده خودروی شما برای دادوستد داده‌های خاص خودرو</string>\n    <string name=\"service_name_checkin\">ثبت دستگاه گوگل</string>\n    <string name=\"service_name_mcs\">پیام‌رسانی ابری</string>\n    <string name=\"service_name_vending\">خدمات فروشگاه پلی</string>\n    <string name=\"self_check_resolution_app_installed\">برنامه <xliff:g example=\"F-Droid\">%1$s</xliff:g> یا یک برنامه سازگار را نصب کنید. لطفاً مستندات را بررسی کنید تا ببینید کدام برنامه‌ها سازگار هستند.</string>\n    <string name=\"self_check_name_correct_sig\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> امضای درست دارد:</string>\n    <string name=\"self_check_resolution_correct_sig\">یا <xliff:g example=\"F-Droid\">%1$s</xliff:g> نصب‌شده سازگار نیست یا جعل امضا برای آن فعال نیست. لطفاً مستندات را بررسی کنید تا ببینید کدام برنامه‌ها و رام‌ها سازگار هستند.</string>\n    <string name=\"self_check_name_battery_optimizations\">بهینه‌سازی‌های باتری نادیده گرفته شده:</string>\n    <string name=\"self_check_resolution_battery_optimizations\">اینجا بزنید تا بهینه‌سازی‌های باتری غیرفعال شوند. انجام ندادن این کار ممکن است باعث رفتار نادرست برنامه‌ها شود.</string>\n    <string name=\"prefcat_configuration\">پیکربندی</string>\n    <string name=\"prefcat_google_services\">خدمات گوگل</string>\n    <string name=\"prefcat_location_service\">خدمت مکان‌یابی</string>\n    <string name=\"prefcat_services\">خدمات</string>\n    <string name=\"prefcat_test\">آزمایش</string>\n    <string name=\"cond_gcm_bat_title\">بهینه‌سازی‌های باتری فعال است</string>\n    <string name=\"cond_gcm_bat_summary\">شما پیام‌رسانی ابری را فعال کرده‌اید اما بهینه‌سازی‌های باتری برای خدمات میکروجی فعال است. برای دریافت آگاه‌سازهای فشاری، باید بهینه‌سازی‌های باتری را نادیده بگیرید.</string>\n    <string name=\"cond_gcm_bat_action\">نادیده گرفتن بهینه‌سازی‌ها</string>\n    <string name=\"cond_perm_title\">فقدان دسترسی</string>\n    <string name=\"prefs_account\">ترجیحات حساب</string>\n    <string name=\"prefs_account_privacy\">داده‌های شخصی و حریم خصوصی</string>\n    <string name=\"prefs_account_security\">ورود و امنیت</string>\n    <string name=\"pref_auth_trust_google_title\">اعتماد به گوگل برای دسترسی‌های برنامه</string>\n    <string name=\"pref_auth_trust_google_summary\">وقتی غیرفعال باشد، پیش از ارسال درخواست پذیرش برنامه به گوگل از کاربر پرسیده می‌شود. برخی برنامه‌ها در صورت غیرفعال بودن این گزینه نمی‌توانند از حساب گوگل استفاده کنند.</string>\n    <string name=\"pref_auth_visible_title\">اجازه به برنامه‌ها برای یافتن حساب‌ها</string>\n    <string name=\"pref_auth_visible_summary\">وقتی فعال باشد، همه برنامه‌های روی این دستگاه می‌توانند نشانی رایانامه حساب‌های گوگل شما را بدون پذیرش پیشین ببینند.</string>\n    <string name=\"pref_auth_include_android_id_summary\">وقتی غیرفعال باشد، درخواست‌های پذیرش هویت به ثبت دستگاه مرتبط نمی‌شوند، که ممکن است به دستگاه‌های غیرمجاز اجازه ورود دهد، اما ممکن است پیامدهای غیرمنتظره‌ای داشته باشد.</string>\n    <string name=\"pref_auth_strip_device_name_title\">پاک کردن نام دستگاه برای پذیرش هویت</string>\n    <string name=\"pref_auth_strip_device_name_summary\">وقتی فعال باشد، درخواست‌های پذیرش هویت شامل نام دستگاه نمی‌شوند، که ممکن است به دستگاه‌های غیرمجاز اجازه ورود دهد، اما ممکن است پیامدهای غیرمنتظره‌ای داشته باشد.</string>\n    <string name=\"pref_checkin_enable_summary\">دستگاه شما را به خدمات گوگل ثبت می‌کند و یک شناسه دستگاه یکتا می‌سازد. میکروجی بیت‌های شناسایی غیر از نام حساب گوگل شما را از داده‌های ثبت پاک می‌کند.</string>\n    <string name=\"checkin_last_registration\">آخرین ثبت: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"checkin_enable_switch\">ثبت دستگاه</string>\n    <string name=\"pref_more_settings\">بیشتر</string>\n    <string name=\"pref_accounts_title\">حساب‌های گوگل</string>\n    <string name=\"pref_accounts_summary\">افزودن و مدیریت حساب‌های گوگل</string>\n    <string name=\"prefcat_accounts_settings_title\">تنظیمات</string>\n    <string name=\"prefcat_accounts_current_accounts_title\">حساب‌ها</string>\n    <string name=\"pref_add_account_title\">حساب</string>\n    <string name=\"pref_add_account_summary\">افزودن حساب گوگل</string>\n    <string name=\"pref_gcm_enable_mcs_summary\">پیام‌رسانی ابری یک فراهم‌کننده آگاه‌ساز فشاری است که توسط بسیاری از برنامه‌های شخص ثالث استفاده می‌شود. برای استفاده از آن باید ثبت دستگاه را فعال کنید.</string>\n    <string name=\"pref_gcm_heartbeat_title\">بازه زمانی ضربان پیام‌رسانی ابری</string>\n    <string name=\"pref_gcm_heartbeat_summary\">بازه زمانی به ثانیه برای ضربان سامانه به سرورهای گوگل. افزایش این عدد مصرف باتری را کاهش می‌دهد، اما ممکن است باعث تأخیر در پیام‌های فشاری شود.\\nمنسوخ شده، در نگارش آینده جایگزین خواهد شد.</string>\n    <string name=\"pref_gcm_apps_title\">برنامه‌های استفاده‌کننده از پیام‌رسانی ابری</string>\n    <string name=\"pref_gcm_confirm_new_apps_summary\">پیش از ثبت برنامه جدید برای دریافت آگاه‌سازهای فشاری پرس‌وجو کنید</string>\n    <string name=\"pref_about_title\">درباره خدمات میکروجی</string>\n    <string name=\"pref_about_summary\">داده‌های نگارش و کتابخانه‌های استفاده‌شده</string>\n    <string name=\"gcm_app_error_unregistering\">خطا در رد کردن ثبت</string>\n    <string name=\"gcm_app_not_installed_anymore\">دیگر نصب نیست</string>\n    <string name=\"gcm_unregister_app\">رد کردن ثبت</string>\n    <string name=\"gcm_not_registered\">ثبت‌نشده</string>\n    <string name=\"gcm_last_message_at\">آخرین پیام: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_registered\">ثبت‌شده</string>\n    <string name=\"gcm_registered_since\">ثبت‌شده از: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_unregister_confirm_title\">رد کردن ثبت <xliff:g example=\"F-Droid\">%1$s</xliff:g>؟</string>\n    <string name=\"gcm_unregister_confirm_message\">برخی برنامه‌ها به‌شیوه خودکار دوباره ثبت نمی‌شوند و/یا گزینه‌ای برای ثبت دستی ندارند. این برنامه‌ها ممکن است پس از رد کردن ثبت به‌درستی کار نکنند.\\nادامه؟</string>\n    <string name=\"gcm_unregister_after_deny_message\">شما ثبت یک برنامه برای آگاه‌سازهای فشاری را که قبلاً ثبت شده رد کردید.\\nآیا می‌خواهید آن را اکنون رد کردن ثبت کنید تا در آینده پیام‌های فشاری دریافت نکند؟</string>\n    <string name=\"gcm_network_state_disconnected\">جداشده</string>\n    <string name=\"gcm_enable_switch\">دریافت آگاه‌سازهای فشاری</string>\n    <string name=\"push_notifications_summary_values_minutes\">%s دقیقه</string>\n    <string name=\"safetynet_intro\">شبکه ایمنی گوگل(SafetyNet) یک سامانه گواهی دستگاه است که اطمینان می‌دهد دستگاه به‌درستی ایمن شده و با CTS اندروید سازگار است. برخی برنامه‌ها از شبکه ایمنی برای دلایل امنیتی یا به‌عنوان پیش‌نیاز برای حفاظت در برابر دستکاری استفاده می‌کنند.\\n\\nهسته میکروجی شامل پیاده‌سازی رایگانی از شبکه ایمنی است، اما سرور رسمی نیاز دارد که درخواست‌های شبکه ایمنی با سامانه اختصاصی DroidGuard امضا شوند.</string>\n    <string name=\"pref_recaptcha_test_title\">آزمایش ری‌کپچا</string>\n    <string name=\"pref_recaptcha_enterprise_test_title\">آزمایش ری‌کپچا سازمانی</string>\n    <string name=\"pref_test_summary_passed\">همه آزمایش‌ها را گذراند</string>\n    <string name=\"pref_test_summary_failed\">ناموفق: %s</string>\n    <string name=\"pref_test_summary_warn\">هشدار: %s</string>\n    <string name=\"pref_test_summary_running\">در حال اجرا…</string>\n    <string name=\"pref_droidguard_operation_mode\">حالت عملکرد</string>\n    <string name=\"pref_droidguard_unsupported_summary\">اجرای DroidGuard در این دستگاه پشتیبانی نمی‌شود. خدمات شبکه ایمنی ممکن است رفتار نادرستی داشته باشند.</string>\n    <string name=\"menu_clear_recent_requests\">پاک کردن درخواست‌های اخیر</string>\n    <string name=\"safetynet_last_run_at\">آخرین استفاده: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"profile_name_real\">واقعی</string>\n    <string name=\"profile_name_system\">سامانه: %s</string>\n    <string name=\"pref_device_registration_import_custom_profile_title\">وارد کردن نمایه سفارشی</string>\n    <string name=\"pref_device_registration_serial_title\">سریال</string>\n    <string name=\"pref_device_registration_device_profile_category\">نمایه دستگاه</string>\n    <string name=\"pref_safetynet_recent_uses\">استفاده‌های اخیر</string>\n    <string name=\"pref_safetynet_recent_attestation_summary\">گواهی: %s</string>\n    <string name=\"pref_safetynet_recent_recaptcha_summary\">ری‌کپچا: %s</string>\n    <string name=\"pref_safetynet_recent_recaptcha_enterprise_summary\">ری‌کپچا سازمانی: %s</string>\n    <string name=\"pref_safetynet_recent_copy_json\">رونوشت داده‌های JSON JWS</string>\n    <string name=\"pref_safetynet_recent_advice\">توصیه</string>\n    <string name=\"pref_safetynet_recent_eval_type\">نوع ارزیابی</string>\n    <string name=\"pref_safetynet_recent_response_status\">وضعیت پاسخ</string>\n    <string name=\"pref_safetynet_recent_nonce\">نانس (هگز)</string>\n    <string name=\"pref_safetynet_recent_request_time\">زمان درخواست</string>\n    <string name=\"pref_safetynet_recent_request_type\">نوع درخواست</string>\n    <string name=\"pref_safetynet_recent_cat_basic\">داده‌های پایه</string>\n    <string name=\"pref_safetynet_recent_token\">توکن</string>\n    <string name=\"pref_safetynet_test_cts_failed\">CTS ناموفق</string>\n    <string name=\"pref_safetynet_test_integrity_failed\">یکپارچگی ناموفق</string>\n    <string name=\"pref_safetynet_test_not_completed\">هنوز تکمیل نشده</string>\n    <string name=\"pref_safetynet_test_no_result\">بدون نتیجه</string>\n    <string name=\"pref_safetynet_test_invalid_json\">JSON نامعتبر</string>\n    <string name=\"push_notifications_summary_off\">خاموش</string>\n    <string name=\"push_notifications_summary_automatic\">روشن / خودکار: %s</string>\n    <string name=\"push_notifications_summary_manual\">روشن / دستی: %s</string>\n    <string name=\"pref_workprofile_intro\">هنگام تنظیم نمایه کاری برای محل کار یا مؤسسه آموزشی شما، تنظیم ممکن است تلاش کند به گوگل متصل شود تا امکان بارگیری برنامه‌ها به آن نمایه فراهم شود.</string>\n    <string name=\"pref_workprofile_disclaimer\">مسئولیت شماست که اطمینان حاصل کنید استفاده شما از میکروجی با سیاست‌های شرکتی هم‌خوانی دارد. میکروجی با بهترین‌ تلاش ساخته می‌شود و نمی‌تواند تضمین کند که دقیقاً بر پایه انتظار رفتار کند.</string>\n    <string name=\"credentials_assisted_cancel\">رد کردن</string>\n    <string name=\"credentials_assisted_continue\">ادامه</string>\n    <string name=\"credentials_assisted_confirmation_header\">ورود شما</string>\n    <string name=\"credentials_assisted_continue_as_user_button_label\">ادامه به‌عنوان %1$s</string>\n    <string name=\"credentials_assisted_sign_back_title\">ورود مجدد به %1$s با گوگل</string>\n    <string name=\"credentials_assisted_signin_consent_header\">ورود به‌عنوان %1$s</string>\n    <string name=\"credentials_assisted_signin_consent\">با ادامه، گوگل نام، نشانی رایانامه و تصویر نمایه شما را با %1$s هم‌رسانی خواهد کرد. سیاست حریم خصوصی و شرایط خدمت %1$s را ببینید.</string>\n    <string name=\"credentials_assisted_signin_description\">می‌توانید ورود با گوگل را در حساب‌های گوگل خود مدیریت کنید.</string>\n    <string name=\"credentials_assisted_choose_account_label\">انتخاب حساب</string>\n    <string name=\"credentials_assisted_choose_account_subtitle\">برای ادامه به %1$s</string>\n    <string name=\"credentials_assisted_choose_account_error_tips\">ناهنجاری حساب</string>\n    <string name=\"credentials_assisted_signin_button_text_long\">ورود با گوگل</string>\n    <string name=\"credentials_assisted_signin_add_account\">افزودن حساب</string>\n    <string name=\"limited_services_dialog_information\">شما از خدمات محدود میکروجی استفاده می‌کنید. برخلاف خدمات گسترده میکروجی، این نسخه تنها با برنامه‌هایی که از کتابخانه‌های میکروجی استفاده می‌کنند کار می‌کند، نه با برنامه‌های گوگل پلی. این یعنی اکثر برنامه‌ها این خدمات را نادیده می‌گیرند.</string>\n    <string name=\"games_achievement_list_title\">دستاوردها</string>\n    <string name=\"games_achievements_empty_text\">بدون دستاورد برای این بازی</string>\n    <string name=\"games_api_access_denied\">هیچ حسابی روی این دستگاه نمی‌تواند به APIهای بازی دسترسی داشته باشد</string>\n    <string name=\"games_achievement_locked_content_description\">قفل‌شده</string>\n    <string name=\"games_achievement_unlocked_content_description\">بازشده</string>\n    <string name=\"games_achievement_extra_text\">%1$s XP</string>\n    <string name=\"games_leaderboard_empty_text\">بدون جدول رتبه‌بندی برای این بازی</string>\n    <string name=\"games_leaderboard_score_empty_text\">باورنکردنی! هیچ امتیاز بالایی عمومی برای این بازی وجود ندارد.</string>\n    <string name=\"games_leaderboard_list_title\">رتبه‌بندی‌ها</string>\n    <string name=\"games_leaderboards_score_label\">امتیاز: %1$s</string>\n    <string name=\"games_snapshot_empty_text\">هنوز هیچ ذخیره بازی‌ای ذخیره نشده است</string>\n    <string name=\"games_snapshot_choose_btn_text\">انتخاب</string>\n    <string name=\"games_snapshot_delete_btn_text\">پاک کردن</string>\n    <string name=\"camera_permission_dialog_message\">خدمات میکروجی برای پویش کد برای %1$s نیاز به دسترسی به دوربین دستگاه شما دارد.\\n\\nبرای فعال‌سازی، لطفاً دسترسی دوربین را به خدمات میکروجی در تنظیمات اعطا کنید.</string>\n    <string name=\"auth_before_connect\">یک برنامه روی دستگاه شما در حال تلاش برای ورود به حساب گوگل است.\\n\\nاگر این عمدی بود، از دکمه <b>ورود</b> برای اتصال به صفحه ورود گوگل استفاده کنید، در غیر این صورت، <b>رد کردن</b> را فشار دهید تا به برنامه‌ای که این گفتگو را نمایش داده بازگردید.</string>\n    <string name=\"no_network_error_desc\">شما به شبکه متصل نیستید.\\n\\nاین ممکن است یک مشکل گذرا باشد یا دستگاه اندرویدی شما برای خدمات داده تنظیم نشده باشد. وقتی به شبکه همراه یا شبکه وای‌فای متصل شدید دوباره امتحان کنید.</string>\n    <string name=\"auth_action_step_enable_lockscreen_description\">حساب گوگل شما توسط محل کار یا مؤسسه آموزشی شما مدیریت می‌شود. مدیر شما تصمیم گرفته است که دستگاه‌ها پیش از دسترسی به داده‌های حساب نیاز به قفل امن صفحه داشته باشند.\\n\\nلطفاً یک گذرواژه، رمز کوتاه یا الگوی قفل صفحه تنظیم کنید.</string>\n    <string name=\"auth_action_reauth_notification_title\">نیاز به کنش حساب</string>\n    <string name=\"pref_auth_two_step_verification_title\">دریافت پیام‌های تأیید دو مرحله‌ای</string>\n    <string name=\"pref_auth_two_step_verification_summary\">وقتی فعال است، دستگاه میتواند پیام‌های تأیید دو مرحله‌ای را از گوگل دریافت کند (پیام رسانی ابری نیاز است).</string>\n    <string name=\"pref_game_accounts_title\">حساب های بازی گوگل</string>\n    <string name=\"pref_auto_create_player\">اجازه بده حساب بازی پلی ثبت شود</string>\n    <string name=\"games_change_button_text\">تغییر بده</string>\n    <string name=\"games_state_description_delete\">حذف کن</string>\n    <string name=\"games_state_description_signed_out\">از حساب خارج شده</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_title\">از همه بازی ها خارج شو</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_description\">ممکن است پیشرفت و تنظیماتی را که برای بازی ها انجام داده اید از دست بدهید. ما برای اعمال تغییرات بازی را شروع مجدد می کنیم.</string>\n    <string name=\"games_change_per_game_dialog_title\">یک گزینه برای این بازی انتخاب کنید</string>\n    <string name=\"games_change_per_game_dialog_description\">تغییر یا خروج از حساب ممکن است پیشرفت و تنظیماتتان در این بازی را به شرایط اولیه برگرداند</string>\n    <string name=\"games_change_per_game_dialog_option_use_player\">از %1$s استفاده کن</string>\n    <string name=\"games_change_per_game_dialog_option_use_player_snackbar_success_message\">برای این بازی با %1$s واد خواهید شد</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out\">خروج از حساب</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out_snackbar_success_message\">اکنون برای این بازی از حساب خارج شدید</string>\n    <string name=\"games_change_sign_out_of_all_games_snackbar_success_message\">اکنون از حساب برای همه بازی ها خارج شدید</string>\n    <string name=\"games_change_default_account_for_all_games_snackbar_success_message\">برای همه بازی ها با %1$s وارد خواهید شد</string>\n    <string name=\"games_change_default_account_for_new_games_snackbar_success_message\">برای بازی های جدید با %1$s وارد خواهید شد</string>\n    <string name=\"games_account_display_content\">حساب فعلی : %1$s</string>\n    <string name=\"games_delete_profile_header\">حساب بازی پلی و تمام داده ها را حذف کن</string>\n    <string name=\"games_delete_profile_explanation\">حساب بازی گوگل پلی و XP و اطلاعات حساب را برای همیشه حذف کن. این کار ممکن است تمایم امتیازات، رکورد ها، پیشرفت (بازی های ذخیره شده) و تمام تنظیمات را در بازی هایی که بازی کرده اید پاک کند.</string>\n    <string name=\"games_delete_profile_button\">حذف برای همیشه</string>\n    <string name=\"games_delete_game_data_header\">حذف اطلاعات فقط برای یک بازی</string>\n    <string name=\"games_delete_game_data_explanation\">میتوانید اطلاعات را برای همیشه فقط برای بازی هایی که با بازی های گوگل پلی انجام داده اید حذف کنید. این عمل باعث می شود امتیازات، پیشرفت (بازی های ذخیره شده) و تنظیمات شما برای بازی انتخاب شده حذف شود.</string>\n    <string name=\"games_delete_profile_dialog_title\">آیا از حذف این حساب اطمینان دارید؟</string>\n    <string name=\"games_delete_profile_fail\">پروفایل شما حذف نشد. لطفا بعدا امتحان کنید.</string>\n    <string name=\"games_delete_game_data_confirm_dialog_title\">اطلاعات %1$s را حذق کن</string>\n    <string name=\"games_popup_signin_welcome\">سلام، %1$s</string>\n    <string name=\"pref_change_default_game_player\">تغییر حساب برای بازی ها</string>\n    <string name=\"pref_change_default_game_player_summary\">حساب پیش فرض را برای بازی ها تغییر بده و حساب را برای بازی تغییر بده.</string>\n    <string name=\"pref_delete_game_account_data\">اطلاعات بازی های پلی را حذف کن</string>\n    <string name=\"pref_delete_game_account_data_summary\">حساب بازی های پلی و تمام اطلاعات را حذف کن و اطلاعات فردی بازی را حذف کن.</string>\n    <string name=\"games_change_default_account_section_title\">حساب پیش فرض برای بازی ها را تغییر بده</string>\n    <string name=\"games_change_default_account_description\">حساب پیش فرض: %1$s</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_description\">جساب پیش فرض فعلی: %1$s</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_title\">حساب پیش فرض را فقط برای بازی های جدید تغییر بده</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_description\">ییشرفت و تنظیمات را برای بازی هایی که انجام داده اید از دست نمی دهید. اما پیشرفتتان بین حساب ها تقسیم می شود.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_title\">حساب پیش فرض را برای همه بازی ها تغییر بده</string>\n    <string name=\"pref_allow_upload_game_played\">اجازه بده بازی های انجام شده آپلود شود</string>\n    <string name=\"games_change_per_game_title\">حساب را بازی به بازی تغییر بده</string>\n    <string name=\"games_delete_profile_dialog_message\">این کار غیر قابل بازگشت است.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_title\">یک گزینه برا یجساب پیش فرض جدید انتخاب کنید</string>\n    <string name=\"pref_auto_create_player_intro\">زمانی که بازی میکنید، باید از حساب بازی های پلی استفاده کنید تا وارد شوید و عملکردهای مربوط به بازی را ضبط کنید، مانند دستاورد ها، جدول برترین ها، آرشیو ها و ... . پس از غیرفعال سازی، حساب های گوگل که به حساب بازی های پلی وصل نیستند به طور خودکار ثبت نخواهند شد، و بازی قادر به ورود و اجرا نخواهد بود.</string>\n    <string name=\"pref_allow_upload_game_played_summary\">وقتی غیرفعال است، بازی نمیتواند وضعیت بازی انجام شده را پس از ورود باری گزارش کند، و برخی بازی ها نمیتوانند ورود کنند.</string>\n    <string name=\"games_change_default_account_explanation\">این حساب برای ورود خودکار شما به بازی ها، ذخیره پیشرفت شما در بازی، و ذخیره تنظیمات شما استفاده خواهد شد. تغییر حساب پیش فرض یا خروج از حساب میتواند باعث شود تنظیمات و پیشرفت شما برای بازی هایی که قبلا بازی کرده اید به حالت اولیه برگردد.</string>\n    <string name=\"games_change_per_game_description\">تغییر حساب برای بازی انتخاب شده و یا خروج از حساب میتواند پیشرفت و تنظیمات شما را برای آن بازی به حالت اولیه برگرداند.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_description\">ممکن است دسترسی به پیشرفت و تنظیمات را برای بازی هایی که قبلا بازی کرده اید از دست بدهید. ما بازی را برای اعمال تغییرات شروع مجدد می کنیم.</string>\n    <string name=\"games_delete_profile_explanation_with_gamer_name\">حساب بازی های گوگل پلی شما را برای بازیکن با نام <b>%1$s</b> (<b>%2$s</b>) ، XP و تمام اطلاعات پروفایل برای همیشه حذف می کند. این عمل ممکن است باعث شود تمامی امتیازات، پیشرفت (بازی های ذخیره شده) و تنظیمات در بازی هایی که قبلا بازی کرده اید حذف شوند.</string>\n    <string name=\"games_delete_game_data_confirm_dialog_message\">حذف اطلاعاتتان در %1$s برای همیشه، باعث می شود همه امتیازات، پیشرفت (بازی های ذخیره شده) و تنظیماتتان در بازی های گوگل پلی حذف شوند.</string>\n    <string name=\"family_management_title\">خانواده</string>\n    <string name=\"family_management_retry\">تلاش دوباره</string>\n    <string name=\"family_management_toolbar_back\">عقبگرد</string>\n    <string name=\"family_management_toolbar_more\">بیشتر</string>\n    <string name=\"family_management_exit_family_group\">خروج از گروه خانواده</string>\n    <string name=\"family_management_delete_family_group\">حذف یک گروه خانواده</string>\n    <string name=\"family_management_invite_family_member\">دعوت اعضای خانواده</string>\n    <string name=\"family_management_cancel_invite\">لغو دعوت</string>\n    <string name=\"family_management_cancel_invite_success\">لغو دعوت انجام شد</string>\n    <string name=\"family_management_remove_member\">حذف عضو</string>\n    <string name=\"family_management_delete_group_success\">گروه خانواده حذف شد</string>\n    <string name=\"family_management_delete_group_cancel\">لغو</string>\n    <string name=\"family_management_delete_group_confirm\">باشه</string>\n    <string name=\"family_management_input_pwd\">لطفا رمز خود را وارد کنید</string>\n    <string name=\"family_management_invite_sent_date_format\">دعوت در %s فرستاده شد</string>\n    <string name=\"family_management_invite_send\">دعوت فرستاده شد</string>\n    <string name=\"family_management_pwd_error\">رمز اشتباه، لطفا دوباره وارد کنید</string>\n    <string name=\"pref_app_install_settings_title\">تنظیمات نصب کننده برنامه</string>\n    <string name=\"service_name_google_location_sharing\">اشتراک مکان گوگل</string>\n    <string name=\"location_sharing_switch_text\">استفاده از اشتراک مکان</string>\n    <string name=\"location_sharing_turn_off_title\">خاموش کردن اشتراک مکان</string>\n    <string name=\"location_sharing_turn_off_cancel\">ادامه</string>\n    <string name=\"location_sharing_turn_off_confirm\">خاموش کردن</string>\n    <string name=\"location_sharing_confirm_dialog_title\">فعالسازی اشتراک مکان</string>\n    <string name=\"family_management_load_error\">اشکال دریافت محتوی</string>\n    <string name=\"family_management_leave_family_password_title\">تأیید رمزعبور برای خروج از گروه خانوادگی</string>\n    <string name=\"family_management_delete_family_password_title\">تأیید رمزعبور برای حذف گروه خانوادگی</string>\n    <string name=\"family_management_remove_member_password_title\">تأیید رمزعبور برای حذف %s</string>\n    <string name=\"family_management_invite_slots_left\">%1$d دعوت‌نامه باقی مانده</string>\n    <string name=\"family_management_cancel_invite_error\">لغو دعوت با مشکل مواجه شد. دوباره تلاش کن.</string>\n    <string name=\"family_management_member_removed_success\">%s از گروه خانوادگی شما اخراج شد</string>\n    <string name=\"family_management_member_remove_failed\">اخراج %s با مشکل مواجه شد. دوباره تلاش کن.</string>\n    <string name=\"family_management_leave_family_error_message\">خروج از گروه خانوادگی با مشکل مواجه شد. دوباره تلاش کن.</string>\n    <string name=\"family_management_exist_group_success\">شما از گروه خانوادگی خود خارج شدید…</string>\n    <string name=\"family_management_delete_group_failure\">خطا در حذف گروه خانه</string>\n    <string name=\"pref_app_install_switch_title\">اجازه‌ی نصب کردن برنامه</string>\n    <string name=\"pref_app_install_other_apps_note\">اجازه دادن نصب برنامه‌های دریافتی از منابع متفرقه را آزاد می‌کند.</string>\n    <string name=\"pref_app_install_permission_instruction\">برای اطمینان از عملکرد برنامه‌های نصب شده، لطفاً به دستیار میکروجی اجازه دهید تا برنامه‌های دریافتی از منابع دیگر را نصب کند.</string>\n    <string name=\"prefcat_app_install_list_title\">برنامه‌هایی که از نصب‌کننده‌ی برنامه استفاده می‌کنند</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-fi/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"permission_service_all_label\">Kaikki Googlen palvelut</string>\n    <string name=\"permission_service_all_description\">Sovellus voi käyttää kaikkia Googlen palveluita minkä tahansa Google-tilin kautta.</string>\n    <string name=\"permission_service_android_label\">Android-palvelut</string>\n    <string name=\"permission_service_android_description\">Sovellus voi käyttää Android-palveluja minkä tahansa Google-tilin kautta.</string>\n    <string name=\"permission_service_adsense_label\">AdSense</string>\n    <string name=\"permission_service_adsense_description\">Sallii ohjelmalle pääsyn AdSenseen minkä tahansa Google-tilin kautta.</string>\n    <string name=\"permission_service_adwords_label\">AdWords</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-fi/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <plurals name=\"gcm_registered_apps_counter\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> rekisteröity sovellus</item>\n        <item quantity=\"other\"><xliff:g example=\"123\">%1$d</xliff:g> rekisteröityä sovellusta</item>\n    </plurals>\n    <plurals name=\"cond_perm_summary\">\n        <item quantity=\"one\">microG Palvelut ohjelman edellyttämää lupaa asianmukaiseen toimintaan ei myönnetä.</item>\n        <item quantity=\"other\">microG Palvelut ohjelman edellyttämiä lupia asianmukaiseen toimintaan ei myönnetä.</item>\n    </plurals>\n    <plurals name=\"cond_perm_action\">\n        <item quantity=\"one\">Pyydä puuttuva lupa</item>\n        <item quantity=\"other\">Pyydä puuttuvat luvat</item>\n    </plurals>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-fi/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"gms_app_name\">microG Palvelut</string>\n    <string name=\"limited_services_app_name\">microG Rajoitetut Palvelut</string>\n    <string name=\"gms_settings_name\">microG Asetukset</string>\n    <string name=\"just_a_sec\">Pieni hetki…</string>\n    <string name=\"google_account_label\">Google</string>\n    <string name=\"ask_permission_tos\">Jatkamalla sallit tämän sovelluksen ja Googlen käyttää tietojasi palvelu- ja tietosuojakäytäntöjensä mukaisesti.</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-fil/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"permission_service_all_label\">Lahat ng mga serbisyo ng Google</string>\n    <string name=\"permission_service_all_description\">Nagbibigay-daan sa app na i-access ang lahat ng serbisyo ng Google sa pamamagitan ng anumang nauugnay na Google account.</string>\n    <string name=\"permission_service_android_label\">Mga serbisyo ng Android</string>\n    <string name=\"permission_service_android_description\">Nagbibigay-daan sa app na i-access ang serbisyo ng Android sa pamamagitan ng anumang nauugnay na Google account.</string>\n    <string name=\"permission_service_adsense_label\">AdSense</string>\n    <string name=\"permission_service_adsense_description\">Nagbibigay-daan sa app na i-access ang AdSense sa pamamagitan ng anumang nauugnay na Google account.</string>\n    <string name=\"permission_service_adwords_label\">AdWords</string>\n    <string name=\"permission_service_adwords_description\">Nagbibigay-daan sa app na i-access ang AdWords sa pamamagitan ng anumang nauugnay na Google account.</string>\n    <string name=\"permission_service_ah_description\">Nagbibigay-daan sa app na i-access ang App Engine ng Google sa pamamagitan ng anumang nauugnay na Google account.</string>\n    <string name=\"permission_service_blogger_label\">Blogger</string>\n    <string name=\"permission_service_blogger_description\">Nagbibigay-daan sa app na i-access ang Blogger sa pamamagitan ng anumang nauugnay na Google account.</string>\n    <string name=\"permission_service_cl_label\">Google Calendar</string>\n    <string name=\"permission_service_cl_description\">Nagbibigay-daan sa app na i-access ang Google Calendar sa pamamagitan ng anumang nauugnay na Google account.</string>\n    <string name=\"permission_service_cp_label\">Mga Contact</string>\n    <string name=\"permission_service_ah_label\">App Engine ng Google</string>\n</resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-fil/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <plurals name=\"pref_unifiednlp_summary\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> backend na naka-configure</item>\n        <item quantity=\"other\"><xliff:g example=\"123\">%1$d</xliff:g> mga backend na naka-configure</item>\n    </plurals>\n    <plurals name=\"gcm_registered_apps_counter\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> nakarehistro na App</item>\n        <item quantity=\"other\"><xliff:g example=\"123\">%1$d</xliff:g> mga nakarehistro na App</item>\n    </plurals>\n    <plurals name=\"cond_perm_summary\">\n        <item quantity=\"one\">Ang isang pahintulot para sa wastong pagsasaayos ng Mga Serbisyo ng microG ay hindi nabigyan.</item>\n        <item quantity=\"other\">Ang mga pahintulot para sa wastong pagsasaayos ng Mga Serbisyo ng microG ay hindi nabigyan.</item>\n    </plurals>\n    <plurals name=\"cond_perm_action\">\n        <item quantity=\"one\">Ihiling ang nawawalang pahintulot</item>\n        <item quantity=\"other\">Ihiling ang mga nawawalang pahintulot</item>\n    </plurals>\n</resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-fil/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=\"ask_permission_tos\">Sa pamamagitan ng pagpatuloy, pinapayagan mo ang app na ito at ang Google na gamitin ang iyong impormasyon alinsunod sa kani-kanilang mga tuntunin ng serbisyo at patakaran sa privacy.</string>\n    <string name=\"ask_scope_permission_title\">Gusto ng <xliff:g example=\"F-Droid\">%1$s</xliff:g> na:</string>\n    <string name=\"auth_sign_in\">Mag-sign in</string>\n    <string name=\"auth_connecting\">Ang iyong device ay gumagawa ng koneksyon sa server ng Google para i-sign in ka. \\n \\nMaaari ito tumagal ng ilang segundo.</string>\n    <string name=\"auth_general_error_desc\">Nagkaroon ng problema sa pakikipag-ugnayan sa mga server ng Google.\n\\n\n\\nSubukan muli sa ibang pagkakataon.</string>\n    <string name=\"auth_finalize\">Nakikipag-ugnayan ang iyong device sa Google para mag-save ng impormasyon sa iyong account. \\n \\nMaaari itong tumagal ng ilang minuto.</string>\n    <string name=\"allow\">Payagan</string>\n    <string name=\"deny\">Tanggihan</string>\n    <string name=\"auth_notification_title\">Kinakailangan ng authentication</string>\n    <string name=\"auth_notification_content\">Kinakailangan ng <xliff:g example=\"F-Droid\">%1$s</xliff:g> ang iyong awtorisasyon para i-access ang iyong Google account.</string>\n    <string name=\"signin_picker_title\">Pumili ng account</string>\n    <string name=\"signin_picker_subtitle\">para tumuloy sa <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"signin_confirm_title\">Payagan na i-sign in ka sa <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"signin_confirm_button_text\">Payagan at ibahagi</string>\n    <string name=\"signin_subtext_sharing\">Para magpatuloy, ibabahagi ng microG ang iyong pangalan, email address, at larawan ng profile ng iyong Google Account sa <xliff:g example=\"F-Droid\">%1$s</xliff:g>.</string>\n    <string name=\"signin_subtext_policy\">Bago gamitin ang app na ito, suriin ang %1$s at %2$s nito.</string>\n    <string name=\"signin_subtext_policy_privacy\">patakaran sa privacy</string>\n    <string name=\"signin_subtext_policy_terms\">mga tuntunin ng serbisyo</string>\n    <string name=\"perm_c2dm_receive_label\">makinig sa mga C2DM na mensahe</string>\n    <string name=\"perm_c2dm_send_label\">magpadala ng mga C2DM na mensahe sa ibang mga app</string>\n    <string name=\"perm_gtalk_svc_label\">ipagpalit ang mga mensahe at tumanggap ng mga sync notification galing sa mga server ng Google</string>\n    <string name=\"perm_extended_access_label\">Palawakin ang access sa mga serbisyo ng Google</string>\n    <string name=\"perm_provision_label\">i-provision ang mga serbisyo ng microG</string>\n    <string name=\"perm_provision_description\">Pinapayagan ng app na i-configure ang mga serbisyo ng microG ng walang user interaction</string>\n    <string name=\"perm_car_speed_label\">Bilis ng kotse</string>\n    <string name=\"perm_car_speed_description\">I-access ang bilis ng iyong kotse</string>\n    <string name=\"perm_car_info_label\">Impormasyon ng kotse</string>\n    <string name=\"perm_car_info_description\">I-access ang impormasyon ng iyong kotse</string>\n    <string name=\"perm_car_fuel_label\">Level ng fuel ng kotse</string>\n    <string name=\"perm_car_fuel_description\">I-access ang impormasyon ng level ng fuel ng iyong kotse</string>\n    <string name=\"perm_car_mileage_label\">Mileage ng kotse</string>\n    <string name=\"perm_car_mileage_description\">I-access ang impormasyon ng mileage ng iyong kotse</string>\n    <string name=\"service_name_checkin\">Pagrehistro ng device sa Google</string>\n    <string name=\"service_name_mcs\">Cloud na Pagmemensahe</string>\n    <string name=\"service_name_snet\">Google SafetyNet</string>\n    <string name=\"service_name_vending\">Mga serbisyo ng Play Store</string>\n    <string name=\"games_title\">Google Play Games</string>\n    <string name=\"games_info_title\">Gusto ng <xliff:g example=\"F-Droid\">%1$s</xliff:g> na gamitin ang Play Games</string>\n    <string name=\"games_info_content\">Para gamitin ang Play Games kinakailangan na i-install ang Google Play Games app. Maaaring magpatuloy ang application ng walang Play Games, pero posible na kumilos nang hindi inaasahan.</string>\n    <string name=\"place_picker_select_title\">Piliin ang lokasyon na ito</string>\n    <string name=\"network_type_mobile\">Network ng mobile</string>\n    <string name=\"network_type_wifi\">Wi-Fi</string>\n    <string name=\"network_type_roaming\">Pag-roam</string>\n    <string name=\"network_type_other\">Ibang mga network</string>\n    <string name=\"self_check_cat_fake_sig\">Support sa panggagaya ng signature</string>\n    <string name=\"self_check_cat_gms_packages\">Mga naka-install na package</string>\n    <string name=\"self_check_cat_system\">Sistema</string>\n    <string name=\"self_check_name_fake_sig_perm\">Mayroong support ang sistema sa paggagaya ng signature:</string>\n    <string name=\"self_check_resolution_fake_sig_perm\">Ang iyong ROM ay walang native na support sa paggagaya ng signature. Pwede mo pa rin gamitin ang Xposed o ibang mga sistema para gayahin ang signature. Mangyaring suriin ang dokumentasyon sa kung anong mga ROM ay sinusuportahan ang paggagaya ng signatjre at paano gamitin ang microG sa mga ROM na hindi sinusuportahan.</string>\n    <string name=\"self_check_name_perm_granted\">Pinayagan ng sistema ang paggaya ng signature na pahintulot:</string>\n    <string name=\"self_check_name_system_spoofs\">Ginagaya ng sistema ang signature:</string>\n    <string name=\"self_check_resolution_system_spoofs\">Mangyaring suriin ang dokumentasyon kung anong mga step ang maaring kinakailangan.</string>\n    <string name=\"self_check_pkg_gms\">Mga Serbisyo ng microG</string>\n    <string name=\"self_check_pkg_vending\">Kasamahan ng microG / Play Store</string>\n    <string name=\"self_check_pkg_gsf\">microG Services Framework (GSF)</string>\n    <string name=\"self_check_name_app_installed\">Naka-install ang <xliff:g example=\"F-Droid\">%1$s</xliff:g>: </string>\n    <string name=\"self_check_name_correct_sig\">Tama ang signature ng <xliff:g example=\"F-Droid\">%1$s</xliff:g>: </string>\n    <string name=\"self_check_resolution_correct_sig\">Ang naka-inatall na <xliff:g example=\"F-Droid\">%1$s</xliff:g> ay alinman hindi compatible o hindi aktibo ang paggaya ng signature para dito. Mangyaring suriin ang dokumentasyon kung anong mga application at ROM ang compatible.</string>\n    <string name=\"self_check_resolution_battery_optimizations\">Pindutin dito para i-disable ang pag-optimize ng baterya. Ang hindi paggawa nito ay maaring magresulta sa mga maling pag-uugali ng mga application.</string>\n    <string name=\"prefcat_components\">Mga component</string>\n    <string name=\"prefcat_google_services\">Mga Serbisyo ng Google</string>\n    <string name=\"prefcat_location_service\">Serbisyo ng lokasyon</string>\n    <string name=\"prefcat_services\">Mga serbisyo</string>\n    <string name=\"prefcat_test\">Pagsubok</string>\n    <string name=\"cond_gcm_bat_title\">Naka-enable ang pag-optimize ng baterya</string>\n    <string name=\"cond_gcm_bat_summary\">Na-enable mo ang Cloud na Pagmemensahe pero aktibo ang pag-optimize ng baterya para sa Mga Serbisyo ng microG. Para makatanggap ng mga notification kailangan mong hindi pansinin ang pag-optimize ng baterya.</string>\n    <string name=\"cond_gcm_bat_action\">Huwag pansinin ang mga optimization</string>\n    <string name=\"cond_perm_title\">Nawawalang pahintulot</string>\n    <string name=\"prefs_account\">Mga kagustuhan ng account</string>\n    <string name=\"prefs_account_privacy\">Personal na impormasyon at privacy</string>\n    <string name=\"prefs_account_security\">Pag-sign in at seguridad</string>\n    <string name=\"pref_auth_visible_title\">Payagan ang app na maghanap ng mga account</string>\n    <string name=\"pref_auth_visible_summary\">Kapag naka-enable, ang lahat ng mga application sa device na ito ay makakakita ng email address ng iyong mga Google Account nang walang priyor na awtorisasyon.</string>\n    <string name=\"pref_auth_include_android_id_title\">Mag-authenticate sa pamamagitan ng device registration</string>\n    <string name=\"pref_auth_strip_device_name_title\">Alisin ang pangalan ng device para sa authentication</string>\n    <string name=\"pref_auth_strip_device_name_summary\">Kapag na-enable, ang mga kahilingan ng authorization ay hindi sasamahan ang pangalan ng device, na maaring magpapahintulot sa mga hindi awtorisadong device na mag-sign in, ngunit maaring magkaroon ng mga hindi inaasahang kahihinatan.</string>\n    <string name=\"pref_device_registration_android_id\">Android ID</string>\n    <string name=\"checkin_not_registered\">Hindi nakarehistro</string>\n    <string name=\"checkin_last_registration\">Huling pagrehistro: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"checkin_enable_switch\">I-rehistro ang device</string>\n    <string name=\"pref_gcm_enable_mcs_summary\">Ang Cloud na Pagmemensahe ay isang provider ng push notification na ginagamit ng maraming third-party na application. Para gamitin kailangan mo i-enable ang pagrehistro ng device.</string>\n    <string name=\"pref_add_account_title\">Account</string>\n    <string name=\"prefcat_accounts_current_accounts_title\">Mga Account</string>\n    <string name=\"prefcat_accounts_settings_title\">Mga Setting</string>\n    <string name=\"pref_accounts_summary\">Magdagdag at ipamahala ang mga Google account</string>\n    <string name=\"pref_accounts_title\">Mga Google Account</string>\n    <string name=\"pref_info_status\">Status</string>\n    <string name=\"pref_gcm_heartbeat_summary\">Ang pagitan sa segundo para sa sistema para i-heartbeat ang mga Google server. Ang pagtaas ng numero na ito ay babawasan ang pagkonsumo ng baterya ngunit maaaring magdulot ng pagkaantala sa mga push message.\n\\nHindi na ginagamit, papalitan sa hinaharap na release.</string>\n    <string name=\"pref_about_title\">Tungkol sa Mga Serbisyo ng microG</string>\n    <string name=\"pref_about_summary\">Impormasyon ng beryson at mga ginamit na library</string>\n    <string name=\"gcm_app_error_unregistering\">Error sa pag-unregister</string>\n    <string name=\"gcm_app_not_installed_anymore\">Hindi na naka-install</string>\n    <string name=\"gcm_unregister_app\">I-unregister</string>\n    <string name=\"gcm_not_registered\">Hindi nakarehistro</string>\n    <string name=\"gcm_no_message_yet\">Walang natanggap na mensahe sa ngayon</string>\n    <string name=\"gcm_last_message_at\">Huling mensahe: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_registered\">Nakarehistro</string>\n    <string name=\"gcm_registered_since\">Nakarehistro noong: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_unregister_confirm_title\">I-unregister ang <xliff:g example=\"F-Droid\">%1$s</xliff:g>\\?</string>\n    <string name=\"gcm_unregister_confirm_message\">Ang ibang mga app ay hindi awtomatikong magrerehistro muli at/o hindi nagbibigay-daan ng opsyon para gawin ng manwal. Ang mga app na ito ay maaring hindi gumana ng mabuti pagkatapos i-unregister.\n\\nMagpatuloy?</string>\n    <string name=\"gcm_unregister_after_deny_message\">Tinanggihan mo ang app na magrehistro para sa mga push notification na nakarehistro na.\n\\nGusto mo ba i-unregister ngayon para hindi ito makatanggap ng mga push message sa hinaharap?</string>\n    <string name=\"gcm_messages_counter\">Mga mensahe: <xliff:g example=\"123\">%1$d</xliff:g> (<xliff:g example=\"12345\">%2$d</xliff:g> bytes)</string>\n    <string name=\"gcm_network_state_disconnected\">Nadiskonekta</string>\n    <string name=\"gcm_network_state_connected\">Nakakonekta noong <xliff:g example=\"2 hours ago\">%1$s</xliff:g></string>\n    <string name=\"gcm_enable_switch\">Tumanggap ng mga push notification</string>\n    <string name=\"gcm_allow_app_popup\">Payagan ang <xliff:g example=\"F-Droid\">%1$s</xliff:g> na magrehistro para sa mga push notification?</string>\n    <string name=\"pref_push_app_allow_register_title\">Payagan ang pagrehistro</string>\n    <string name=\"pref_push_app_allow_register_summary\">Payagan ang app na magrehistro para sa mga push notification.</string>\n    <string name=\"pref_push_app_wake_for_delivery_title\">Simulan ang app sa push message</string>\n    <string name=\"safetynet_enable_switch\">Payagan ang pagpapatunay ng device</string>\n    <string name=\"pref_safetynet_test_title\">Subukan ang pagpapatunay ng SafetyNet</string>\n    <string name=\"pref_recaptcha_test_title\">Subukan ang ReCAPTCHA</string>\n    <string name=\"pref_recaptcha_enterprise_test_title\">Subukan ang ReCAPTCHA Enterprise</string>\n    <string name=\"pref_test_summary_passed\">Pinasa ang lahat ng mga pagsubok</string>\n    <string name=\"pref_test_summary_failed\">Nabigo: %s</string>\n    <string name=\"pref_test_summary_warn\">Babala: %s</string>\n    <string name=\"pref_test_summary_running\">Tumatakbo…</string>\n    <string name=\"pref_droidguard_operation_mode\">Mode ng operasyon</string>\n    <string name=\"pref_droidguard_unsupported_summary\">Ang DroidGuard execution ay hindi sinusuportan sa device na ito. Ang mga serbisyo ng SafetyNet ay maaring magluko.</string>\n    <string name=\"prefcat_safetynet_apps_title\">Mga app na ginagamit ang SafetyNet</string>\n    <string name=\"menu_clear_recent_requests\">I-clear ang mga kamakailan na hiling</string>\n    <string name=\"safetynet_last_run_at\">Huling paggamit: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"profile_name_native\">Native</string>\n    <string name=\"profile_name_real\">Totoo</string>\n    <string name=\"profile_name_user\">Pasadya: %s</string>\n    <string name=\"profile_name_auto\">Awtomatiko: %s</string>\n    <string name=\"profile_name_system\">Sistema: %s</string>\n    <string name=\"pref_device_registration_import_custom_profile_title\">Mag-import ng custom na profile</string>\n    <string name=\"pref_device_registration_serial_title\">Serial</string>\n    <string name=\"pref_safetynet_recent_copy_json\">Kopyahin ang JSON JWS data</string>\n    <string name=\"pref_safetynet_recent_advice\">Payo</string>\n    <string name=\"pref_safetynet_recent_eval_type\">Uri ng pagsusuri</string>\n    <string name=\"pref_safetynet_recent_response_status\">Status ng tugon</string>\n    <string name=\"pref_safetynet_recent_cat_response\">Data ng tugon</string>\n    <string name=\"pref_safetynet_recent_cat_request\">Data ng hiling</string>\n    <string name=\"pref_safetynet_recent_nonce\">Nonce (Hex)</string>\n    <string name=\"pref_safetynet_recent_request_time\">Oras ng hiling</string>\n    <string name=\"pref_safetynet_recent_request_type\">Uri ng hiling</string>\n    <string name=\"pref_safetynet_recent_cat_basic\">Basic na data</string>\n    <string name=\"pref_safetynet_recent_token\">Token</string>\n    <string name=\"pref_safetynet_recent_copied\">Kinopya sa clipboard!</string>\n    <string name=\"pref_safetynet_test_integrity_cts_passed\">Pumasa ang Integrity at CTS</string>\n    <string name=\"pref_safetynet_test_cts_failed\">Nabigo ang CTS</string>\n    <string name=\"pref_safetynet_test_integrity_failed\">Nabigo ang integrity</string>\n    <string name=\"pref_safetynet_test_not_completed\">Hindi pa nakumpleto</string>\n    <string name=\"pref_safetynet_test_no_result\">Walang resulta</string>\n    <string name=\"pref_safetynet_test_invalid_json\">Hindi wastong JSON</string>\n    <string name=\"push_notifications_summary_off\">NAKAPATAY</string>\n    <string name=\"push_notifications_summary_automatic\">NAKABUKAS / Awtomatiko: %s</string>\n    <string name=\"push_notifications_summary_manual\">NAKABUKAS / Manwal: %s</string>\n    <string name=\"push_notifications_summary_values_seconds\">%s segundo</string>\n    <string name=\"push_notifications_summary_values_minutes\">%s minuto</string>\n    <string name=\"pref_vending_summary_licensing_off\">Nakapatay ang paglilisensya</string>\n    <string name=\"pref_vending_summary_licensing_on\">Nakabukas ang paglilisensya</string>\n    <string name=\"pref_vending_licensing_category\">Paglilisensya ng Google Play</string>\n    <string name=\"pref_vending_licensing_enable_switch\">Sagutin ang mga hiling ng pagpapatunay ng lisensya</string>\n    <string name=\"pref_vending_license_enable_summary\">Ang ibang mga app ay nangangailangan ng pagpapatunay na binili mo sila sa Google Play. Kapag hiniling ng app, da-download ang microG ng patunay ng pagbili galing sa Google. Kapag naka-disable, o walang nadagdag na Google account, ang mga hiling para sa pagpapatunay ng lisensya ay hindi papansinin.</string>\n    <string name=\"feedback_disabled\">Kasalukuyang hindi pa posible ang pagpuna</string>\n    <string name=\"backup_disabled\">Kasalukuyang hindi pa posible ang pag-back up</string>\n    <string name=\"pref_vending_billing_category\">Billing ng Google Play</string>\n    <string name=\"pref_vending_billing_enable_switch\">Ipamahala ang mga hiling ng billing</string>\n    <string name=\"pref_vending_billing_enable_summary\">Kapag na-enable, ang ibang app ay maaring magkumpleto ng mga pagbili o magsimula ng mga subscription sa pamamagitan ng serbisyo ng Play Billing ng Google.</string>\n    <string name=\"pref_vending_billing_note_experimental\">Pang-eksperimento ang feature na ito at maaring humatong sa pagkawalan ng pera. Ikaw ay binigyan ng babala.</string>\n    <string name=\"pref_vending_billing_note_licensing\">Ang ibang mga app ay maaring kailangananin na i-enable din ang pagpatunay ng lisenya para patunayin ang iyong mga pagbili.</string>\n    <string name=\"gms_app_name\">Mga Serbisyo ng microG</string>\n    <string name=\"gms_settings_name\">Mga Setting ng microG</string>\n    <string name=\"gms_settings_summary\">I-set up ang mga serbisyo ng microG.</string>\n    <string name=\"just_a_sec\">Sandali lang…</string>\n    <string name=\"google_account_label\">Google</string>\n    <string name=\"ask_service_permission_title\">Gusto gamitin ng <xliff:g example=\"F-Droid\">%1$s</xliff:g> ang:</string>\n    <string name=\"account_manager_title\">Pamahalaan ng Google Account</string>\n    <string name=\"sorry\">Paumanhin…</string>\n    <string name=\"no_network_error_desc\">Wala kang koneksyon sa network. \\n \\nMaaari ito isang pansamantalang problema o ang iyong Android device ay maaring hindi naka-provision para sa mga serbisyo ng data. Subukan muli kapag nakakonekta sa mobile network, o kumonekta sa Wi-Fi network.</string>\n    <string name=\"signin_picker_add_account_label\">Magdagdag ng isa pang account</string>\n    <string name=\"auth_before_connect\">Ang isang app sa device mo ay sinusubukang mag-sign in sa isang Google Account.\\n\\nKung sinasadya ito, gamitin ang <b>Mag-sign in</b> na button para kumonekta sa sign-in page ng Google, kung hindi, pindutin ang <b>Kanselahin</b> para bumalik sa application na naging sanhi ng pagpakita ng dialog na ito.</string>\n    <string name=\"perm_status_broadcast_label\">makinig sa mga internal status broadcast</string>\n    <string name=\"pick_place_title\">Pumili ng lugar</string>\n    <string name=\"place_picker_nearby_places\">Mga malapit na lugar</string>\n    <string name=\"pick_place_desc\">Hindi pa available ang pagpili ng lugar.</string>\n    <string name=\"place_picker_location_lat_lng\">(%1$.7f, %2$.7f)</string>\n    <string name=\"perm_gsf_read_gservices_label\">basahin ang configuration ng serbisyo ng Google</string>\n    <string name=\"lacking_permission_toast\">Mga serbisyo ng microG: Kulang ng pahintulot na <xliff:g example=\"have full network acccess\">%1$s</xliff:g></string>\n    <string name=\"self_check_resolution_perm_granted\">Ito ang pinakamalakas na indikasyon na ang ROM ay sumusuporta ng paggaya ng signature, pero nangangailangan ng higit pang aksyon para paganahin. Mangyaring suriin ang dokumentasyon kung anong mga step ang maaring kinakilangan.</string>\n    <string name=\"self_check_resolution_app_installed\">I-install ang application na <xliff:g example=\"F-Droid\">%1$s</xliff:g> o isang compatible. Mangyaring suriin ang dokumentasyon kung anong mga application ang sinusuportahan.</string>\n    <string name=\"self_check_name_battery_optimizations\">Hindi pinapansin ang pag-optimize ng baterya:</string>\n    <string name=\"prefcat_about\">Tungkol sa</string>\n    <string name=\"prefcat_configuration\">Configuration</string>\n    <string name=\"pref_auth_include_android_id_summary\">Kapag na-disable, hindi mali-link ang mga kahilingan sa pag-authenticate sa pagpaparehistro ng device, na maaaring magpapahintulot sa mga hindi awtorisadong device na mag-sign in, ngunit maaaring magkaroon ng mga hindi inaasahang kahihinatnan.</string>\n    <string name=\"pref_auth_trust_google_title\">Pagkatiwalaan ang Google para sa mga pahintulot ng app</string>\n    <string name=\"pref_auth_trust_google_summary\">Kapag naka-disable, ang user ay tinatanong bago ang awtorisasyon ng app na hiling ay ipapadala sa Google. Ang ibang mga application ay mabibigong gamitin ang Google account kapag naka-disable ito.</string>\n    <string name=\"pref_checkin_enable_summary\">Nirerehistro ang iyong device sa mga serbisyo ng Google at gagawa ng kakaibang device identitfier. Tinatanggal ng microG ang mga nakakakilalang bahagi maliban sa pangalan ng iyong Google account at data ng pagrehistro.</string>\n    <string name=\"pref_add_account_summary\">Magdagdag ng Google account</string>\n    <string name=\"pref_more_settings\">Higit pa</string>\n    <string name=\"pref_gcm_heartbeat_title\">Pagitan ng heartbeat ng Cloud na Pagmemensahe</string>\n    <string name=\"pref_gcm_apps_title\">Mga app na ginagamit ang Cloud na Pagmemensahe</string>\n    <string name=\"pref_gcm_apps_summary\">Listahan ng mga app na kasalukuyang nakarehistro sa Cloud na Pagmemensahe.</string>\n    <string name=\"pref_gcm_confirm_new_apps_title\">Kumpirmahin ang mga bagong app</string>\n    <string name=\"pref_gcm_confirm_new_apps_summary\">Magtanong bago i-rehistro ang isang app upang magkaroon ng mga push notification</string>\n    <string name=\"pref_gcm_ping_interval\">Pagitan ng ping: <xliff:g example=\"10 minutes\">%1$s</xliff:g></string>\n    <string name=\"pref_device_registration_import_custom_profile_summary\">Mag-import ng device profile galing sa file</string>\n    <string name=\"pref_device_registration_select_profile_title\">Pumili ng profile</string>\n    <string name=\"pref_device_registration_device_profile_category\">Profile ng device</string>\n    <string name=\"pref_safetynet_recent_uses\">Mga kamakailan na paggamit</string>\n    <string name=\"pref_push_app_wake_for_delivery_summary\">Simulan ang app habang nasa background upang matanggap ang mga papasok na push message.</string>\n    <string name=\"pref_safetynet_recent_attestation_summary\">Pagpapatunay: %s</string>\n    <string name=\"prefcat_push_apps_title\">Mga app na gumagamit ng push notification</string>\n    <string name=\"prefcat_push_apps_registered_title\">Mga nakarehistro na app</string>\n    <string name=\"pref_safetynet_recent_recaptcha_summary\">ReCaptcha: %s</string>\n    <string name=\"pref_safetynet_recent_recaptcha_enterprise_summary\">ReCaptcha Enterprise: %s</string>\n    <string name=\"prefcat_push_apps_unregistered_title\">Mga hindi nakarehistro na app</string>\n    <string name=\"prefcat_push_networks_title\">Mga network na gagamitin para sa push notification</string>\n    <string name=\"safetynet_intro\">Ang Google SafetyNet ay isang sistema ng sertipikason ng device, na sinisigurado na ang device ay maayos na na-secure at compatible sa Android CTS. Ang ibang mga application ay gumagamit ng SafetyNet para sa mga kadahilanang pangseguridad o isang kinakailangan para sa tamper-protection.\n\\n\n\\nAng microG GmsCore ay naglalaman ng libreng implementasyon ng SafetyNet, pero ang opisyal na server ay nangangailangan na ang mga hiling ng SafetyNet ay naka-sign gamit ang proprietary na sistema ng DroidGuard.</string>\n    <string name=\"perm_car_vendor_extension_label\">Channel ng vendor ng kotse</string>\n    <string name=\"perm_car_vendor_extension_description\">I-access ang channel ng vendor ng iyong kotse para ipagpalit ang impormasyon sa kotse</string>\n    <string name=\"credentials_assisted_continue\">Magpatuloy</string>\n    <string name=\"credentials_assisted_confirmation_header\">Sina-sign in ka namin</string>\n    <string name=\"credentials_assisted_cancel\">Kanselahin</string>\n    <string name=\"credentials_assisted_continue_as_user_button_label\">Magpatuloy bilang %1$s</string>\n    <string name=\"credentials_assisted_sign_back_title\">Mag-sign in muli sa %1$s gamit ang Google</string>\n    <string name=\"credentials_assisted_signin_consent_header\">Nagsa-sign in bilang %1$s</string>\n    <string name=\"credentials_assisted_signin_consent\">Sa pamamagitan ng pagpatuloy, ibabahagi ng Google ang iyong pangalan, email address, at larawan ng profile sa %1$s. Tignan ang Patakaran sa Privacy at Mga Tuntunin ng Serbisyo ng %1$s.</string>\n    <string name=\"credentials_assisted_signin_description\">Maaari mong ipamahala ang Pag-sign in gamit ang Google sa iyong mga Google Account.</string>\n    <string name=\"credentials_assisted_choose_account_label\">Pumili ng account</string>\n    <string name=\"credentials_assisted_choose_account_subtitle\">upang magpatuloy sa %1$s</string>\n    <string name=\"credentials_assisted_signin_button_text_long\">Mag-sign in gamit ang Google</string>\n    <string name=\"auth_package_override_request_title\">Payagan ang <b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> na magkaroon ng pribilehiyong pag-access sa <xliff:g example=\"account@example.com\">%2$s</xliff:g>\\?</string>\n    <string name=\"auth_package_override_request_message\">Gustong i-access ng <b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> ang iyong account na kung ito ay <b><xliff:g example=\"F-Droid\">%2$s</xliff:g> ni/ng <xliff:g example=\"F-Droid Inc.\">%3$s</xliff:g></b>. Maaaring bigyan ito ng pribilehiyong pag-access sa iyong account.</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_switch\">Awtomatikong idagdag ang mga libreng app sa library</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_summary\">Maaaring suriin ng mga libreng app kapag na-download sila sa Google Play. Awtomatikong dagdagan ang mga libreng app sa iyong account library para palaging mapasa ang pagsuri para sa lahat ng mga libreng app na available sa iyo.</string>\n    <string name=\"limited_services_app_name\">Mga Limitadong Serbisyo ng microG</string>\n    <string name=\"auth_action_notification_title\">Nangangailangan ng aksyon sa account</string>\n    <string name=\"auth_action_notification_content\">Nangangailangan ng iyong Google account ng karagdagang setup.</string>\n    <string name=\"auth_action_step_enable_checkin\">Buksan ang pagrehistro ng device</string>\n    <string name=\"auth_action_step_enable_gcm\">Buksan ang Cloud na Pagmemensahe</string>\n    <string name=\"auth_action_step_enable_gcm_description\">Maaari mong i-disable ang Cloud na Pagmemensahe pagkatapos ng pag-set up ng account.</string>\n    <string name=\"auth_action_step_allow_microg_gcm\">Payagan ang Cloud na Pagmemensahe para sa microG</string>\n    <string name=\"auth_action_step_allow_microg_gcm_description\">Batay sa iyong mga kagustuhan, kinakailangan ng microG ang iyong pahintulot bago ito irehistro ang sarili para sa Cloud na Pagmemensahe.</string>\n    <string name=\"auth_action_step_enable_lockscreen\">Mag-configure ng secure na lock ng screen</string>\n    <string name=\"auth_action_step_enable_lockscreen_description\">Ang iyong Google account ay ipinamamahala ng iyong lugar ng trabaho o ang iyong institusyong pang-edukasyon. Nagpasya ang iyong tagapangasiwa na ang mga device ay kailangan ng secure na screen lock bago nila ma-access ang data ng account.\\n\\nPaki-set up ang password, PIN, o pattern na lock screen.</string>\n    <string name=\"auth_action_step_perform_content_description\">I-click para isagawa ang hakbang</string>\n    <string name=\"auth_action_step_completed_content_description\">Tapos na ang hakbang</string>\n    <string name=\"auth_action_activity_finish\">Tapos na</string>\n    <string name=\"limited_services_dialog_information_ack\">Naiintindihan ko</string>\n    <string name=\"auth_action_notification_channel_name\">Mga alerto sa Google account</string>\n    <string name=\"auth_action_activity_header\">Tapusing i-set up ang iyong Google account</string>\n    <string name=\"auth_action_notification_channel_description\">Inaabisuhan kapag ang isa sa iyong mga Google account ay nangangailangan ng karagdagang setup bago ito magamit o kapag ang account ay hindi compatible sa microG.</string>\n    <string name=\"auth_action_activity_explanation\">Kumpletuhin ang mga sumusunod na hakbang upang magamit ang Google account na %s sa device na ito.</string>\n    <string name=\"auth_action_step_enable_checkin_description\">Kailangang i-rehistro ang iyong device sa Google kahit isang beses.\\n\\nMaaari mong i-disable ang pagrehistro ng device sa Google pagkatapos ng pag-set up ng account.</string>\n    <string name=\"limited_services_dialog_information\">Ginagamit mo ang Mga Limitadong Serbisyo ng microG. Hindi tulad ng nakasanayan na Mga Serbisyo ng microG, ang flavor na ito ay gumagana para sa mga app ba gumagamit ng mga library ng microG, hindi ang mula sa Google Play. Nangangahulugan nito na hindi papansinin ng mga karamihang application ang mga serbisyo na ito.</string>\n    <string name=\"pref_vending_asset_delivery_category\">Asset Delivery ng Google Play</string>\n    <string name=\"pref_vending_asset_delivery_summary\">I-download ang mga karagdagang asset kapag hiniling ng mga app na gumagamit ng Play Asset Delivery</string>\n    <string name=\"pref_vending_asset_delivery_switch\">I-enable ang on-demand na pag-deliver ng asset</string>\n    <string name=\"pref_vending_asset_device_sync_switch\">I-enable ang pag-sync ng impormasyon ng device</string>\n    <string name=\"games_achievement_list_title\">Mga achievement</string>\n    <string name=\"games_achievements_empty_text\">Walang mga achievement para sa larong ito</string>\n    <string name=\"games_api_access_denied\">Walang mga account sa device na ito ang makaka-access ng Games API</string>\n    <string name=\"games_achievement_locked_content_description\">naka-lock</string>\n    <string name=\"games_achievement_unlocked_content_description\">naka-unlock</string>\n    <string name=\"games_leaderboard_empty_text\">Walang mga leaderboard para sa larong ito</string>\n    <string name=\"games_leaderboard_score_empty_text\">Hindi kapani-paniwala! Walang pampublikong mga high score para sa larong ito.</string>\n    <string name=\"games_leaderboard_list_title\">Mga ranking</string>\n    <string name=\"games_leaderboards_score_label\">Iskor: %1$s</string>\n    <string name=\"games_snapshot_empty_text\">Wala pang mga game save na naka-save sa ngayon</string>\n    <string name=\"games_snapshot_choose_btn_text\">piliin</string>\n    <string name=\"games_snapshot_delete_btn_text\">burahin</string>\n    <string name=\"games_delete_snapshot_dialog_title\">Burahin ang naka-save na laro</string>\n    <string name=\"games_delete_snapshot_dialog_message\">Sigurado ka ba gusto mong burahin ang naka-save na larong ito?</string>\n    <string name=\"games_delete_snapshot_dialog_cancel\">Kanselahin</string>\n    <string name=\"games_delete_snapshot_dialog_ok\">OK</string>\n    <string name=\"games_delete_snapshot_error\">Nabigo ang pagbura, mangyaring subukan muli mamaya</string>\n    <string name=\"pref_vending_asset_device_sync_summary\">Ang mga application na gumagamit ng Play Asset Delivery ay magda-download ng mga karagdagang asset base sa impormasyon ng device na kasalukuyang ginagamit.</string>\n    <string name=\"games_achievement_extra_text\">%1$s XP</string>\n    <string name=\"service_name_work_profile\">Profile sa trabaho</string>\n    <string name=\"pref_vending_feature_delivery\">Pag-deliver ng Feature ng Google Play</string>\n    <string name=\"pref_vending_split_install_switch\">On-demand na pag-install ng component</string>\n    <string name=\"pref_vending_licensing_split_install_summary\">Payagan ang mga app na mag-download at mag-install ng mga karagdagang component</string>\n    <string name=\"pref_workprofile_create_account\">Payagan ang pag-setup ng account sa trabaho</string>\n    <string name=\"barcode_scanner_brand\">Na-scan ng microG sa ngalan ng %1$s</string>\n    <string name=\"camera_permission_dialog_button\">OK</string>\n    <string name=\"camera_permission_dialog_message\">Kailangan i-access ng mga serbisyo ng microG ang camera ng iyong device para mag-scan ng code para sa %1$s.\\n\\nUpang paganahin, pakibigay ang pahintulot ng camera sa mga serbisyo ng microG sa Mga Setting.</string>\n    <string name=\"camera_permission_dialog_title\">Kinakailangan ang pahintulot ng Camera</string>\n    <string name=\"pref_workprofile_disclaimer\">Responsibilidad mong tiyakin na ang iyong paggamit ng microG ay naaayon sa mga patakaran ng korporasyon. Ibinibigay ang microG sa batayan ng pinakamahusay na pagsisikap at hindi magagarantiya na kumilos nang eksakto tulad ng inaasahan.</string>\n    <string name=\"pref_workprofile_intro\">Kapag nagse-set up ng profile sa trabaho para sa iyong lugar ng pag-trabaho o institusyong pang-edukasyon, maaaring subukan ng setup na kumonekta sa Google para i-enable ang pag-download mga app sa profile na iyan.</string>\n    <string name=\"credentials_assisted_choose_account_error_tips\">Abnormalidad ng account</string>\n    <string name=\"credentials_assisted_signin_add_account\">Magdagdag ng Account</string>\n    <string name=\"auth_action_reauth_notification_title\">Kinakailangan ang aksyon sa account</string>\n    <string name=\"pref_auth_two_step_verification_title\">Makatanggap ng mga prompt ng 2-step na pag-verify</string>\n    <string name=\"pref_auth_two_step_verification_summary\">Kapag naka-enable, makakatanggap ang device na ito ng mga 2-step na pag-verify na prompt mula sa Google (kinakailangan ang Cloud na Pagmemensahe).</string>\n    <string name=\"pref_game_accounts_title\">Mga Google Game Account</string>\n    <string name=\"pref_auto_create_player\">Payagan ang pagrehistro ng account sa Play Games</string>\n    <string name=\"pref_auto_create_player_intro\">Kapag naglalaro ng mga laro, kailangan mong gumamit ng Play Games na account para mag-log in at i-record ang mga function na kaugnay sa mga laro, tulad ng mga achievement, leaderboard, archive, atbp. Pagkatapos i-disable, hindi awtomatikong irerehistro ang mga Google Account na hindi nauugnay sa isang Play Games account, at hindi makakapag-log in at makakapaglaro ang laro.</string>\n    <string name=\"pref_allow_upload_game_played\">Payagan ang pag-upload ng nilarong laro</string>\n    <string name=\"pref_allow_upload_game_played_summary\">Kapag naka-disable, hindi iuulat ng laro ang status ng nilaro ang laro pagkatapos mag-log in sa laro, at maaaring hindi maka-log in ang mga laro.</string>\n    <string name=\"pref_change_default_game_player\">Palitan ang account para sa mga laro</string>\n    <string name=\"pref_change_default_game_player_summary\">Palitan ang default na account para sa mga laro at palitan ang account ayon sa laro.</string>\n    <string name=\"pref_delete_game_account_data\">Burahin ang data ng Play Games</string>\n    <string name=\"pref_delete_game_account_data_summary\">Burahin ang Play Games account at lahat ng mga data at burahin ang indibidwal na data ng laro.</string>\n    <string name=\"games_state_description_signed_out\">Naka-sign out</string>\n    <string name=\"games_state_description_delete\">Burahin</string>\n    <string name=\"games_change_button_text\">Palitan</string>\n    <string name=\"games_change_default_account_section_title\">Palitan ang default na account para sa mga laro</string>\n    <string name=\"games_change_default_account_description\">Default na account: %1$s</string>\n    <string name=\"games_change_default_account_explanation\">Ginagamit ang account na ito para awtomatiko kang i-sign in sa mga laro, i-save ang iyong progreso sa laro, at i-save ang iyong mga setting. Baka mag-reset ang iyong progreso at mga setting sa mga larong nilaro mo kung palitan mo ang default na account.</string>\n    <string name=\"games_change_per_game_title\">Baguhin ang account ayon sa laro</string>\n    <string name=\"games_change_per_game_description\">Ang pagpalit ng account para sa piniling laro o pag-sign out nito ay maaaring i-reset ang iyong progreso at mga setting para sa laro.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_title\">Pumili ng opsyon para sa bagong default account</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_description\">Kasalukuyang default na account: %1$s</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_title\">Palitan ang default account sa mga bagong laro lamang</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_description\">Hindi ka mawawalan ng progreso at mga setting sa mga larong nilaro mo, ngunit mahahati ang iyong progreso sa pagitan ng mga account.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_title\">Palitan ang default account para sa lahat ng mga laro</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_description\">Baka mawalan ka ng access sa iyong progreso at mga setting sa mga larong nilaro mo. Ire-restart namin ang iyong laro para i-apply ang mga pagbabago.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_title\">Mag-sign out sa lahat ng mga laro</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_description\">Baka mawalan ka ng access sa iyong progreso at mga setting sa mga larong nilaro mo. Ire-restart namin ang iyong laro para i-apply ang mga pagbabago.</string>\n    <string name=\"games_change_per_game_dialog_title\">Piliin ang opsyon na ito para sa larong ito</string>\n    <string name=\"games_change_per_game_dialog_description\">Ang pagpalit ng account o pag-sign out ay maaaring i-reset ang iyong progresibo at mga setting para sa laro</string>\n    <string name=\"games_change_per_game_dialog_option_use_player\">Gamitin ang %1$s</string>\n    <string name=\"games_change_per_game_dialog_option_use_player_snackbar_success_message\">Masa-sign in ka sa larong ito gamit ang %1$s</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out\">Mag-sign out</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out_snackbar_success_message\">Na-sign out ka na sa larong ito</string>\n    <string name=\"games_change_sign_out_of_all_games_snackbar_success_message\">Na-sign out ka na sa lahat ng mga laro</string>\n    <string name=\"games_change_default_account_for_all_games_snackbar_success_message\">Masa-sign in ka sa lahat ng mga laro gamit ang %1$s</string>\n    <string name=\"games_change_default_account_for_new_games_snackbar_success_message\">Masa-sign in ka sa mga bagong laro gamit ang %1$s</string>\n    <string name=\"games_account_display_content\">Kasalukuyang account: %1$s</string>\n    <string name=\"games_delete_profile_header\">Burahin ang Play Games account at lahat ng data</string>\n    <string name=\"games_delete_profile_explanation\">Permanenteng burahin ang iyong Google Play Games account, XP, at lahat ng data ng profile. Ang aksyon na ito ay maaaring burahin rin ang iyong mga iskor, progreso (mga nai-save na laro), at mga setting sa mga larong nilaro mo.</string>\n    <string name=\"games_delete_profile_button\">Permanenteng burahin</string>\n    <string name=\"games_delete_game_data_header\">Burahin ang indibidwal na data ng laro</string>\n    <string name=\"games_delete_game_data_explanation\">Maaari mong permanenteng burahin ang indibidwal na data para sa mga larong nilaro mo gamit ang Google Play Games. Buburahin ang mga iskor, progreso (mga nai-save na laro), at mga setting para sa larong pinili mo ang aksyong ito.</string>\n    <string name=\"games_delete_profile_dialog_title\">Sigurado ka gusto mong burahin ang account na ito?</string>\n    <string name=\"games_delete_profile_explanation_with_gamer_name\">Permanenteng burahin ang iyong Google Play Games account para sa gamer name na <b>%1$s</b> (<b>%2$s</b>), XP, at lahat ng mga data ng profile. Ang aksyon na ito ay maaari ring burahin ang iyong mga iskor, progreso (mga nai-save na laro), at mga setting sa mga larong nilaro mo.</string>\n    <string name=\"games_delete_profile_dialog_message\">Hindi mababawi ang aksyon na ito.</string>\n    <string name=\"games_delete_profile_fail\">Hindi mabura ang iyong profile. Subukan muli mamaya.</string>\n    <string name=\"games_delete_game_data_confirm_dialog_title\">Burahin ang data para sa %1$s</string>\n    <string name=\"games_delete_game_data_confirm_dialog_message\">Ang permanenteng pagbura ng iyong data para sa %1$s ay mag-aalis ng iyong mga iskor, progreso (mga naka-save na laro), at mga setting ng laro sa Google Play Games.</string>\n    <string name=\"games_popup_signin_welcome\">Kamusta, %1$s</string>\n    <string name=\"family_management_title\">Pamilya</string>\n    <string name=\"family_management_retry\">Subukan muli</string>\n    <string name=\"family_management_load_error\">Nabigo ang pag-load ng nilalaman</string>\n    <string name=\"family_management_toolbar_back\">Bumalik</string>\n    <string name=\"family_management_toolbar_more\">Higit pa</string>\n    <string name=\"family_management_exit_family_group\">Umalis sa grupo ng pamilya</string>\n    <string name=\"family_management_delete_family_group\">Magbura ng isang grupo ng pamilya</string>\n    <string name=\"family_management_leave_family_password_title\">Kumpirmahin ang password para umalis sa grupo ng pamilya</string>\n    <string name=\"family_management_delete_family_password_title\">Kumpirmahin ang password para burahin ang grupo ng pamilya</string>\n    <string name=\"family_management_remove_member_password_title\">Kumpirmahin ang password para tanggalin si/ang %s</string>\n    <string name=\"family_management_invite_family_member\">Mag-imbita ng mga miyembro ng pamilya</string>\n    <string name=\"family_management_invite_slots_left\">%1$d mga imbitasyon ang natitira</string>\n    <string name=\"family_management_cancel_invite\">Kanselahin ang imbitasyon</string>\n    <string name=\"family_management_cancel_invite_success\">Matagumpay na kinansela ang imbitasyon</string>\n    <string name=\"family_management_cancel_invite_error\">Hindi makansela ang imbitasyon. Subukan muli.</string>\n    <string name=\"family_management_remove_member\">Tanggalin ang Miyembro</string>\n    <string name=\"family_management_member_removed_success\">Tinanggal sina %s mula sa iyong grupo ng pamilya</string>\n    <string name=\"family_management_member_remove_failed\">Nagkaproblema sa pagtanggal kay %s. Subukan muli.</string>\n    <string name=\"family_management_leave_family_error_message\">Nagkaproblema sa pag-alis ng grupo ng pamilya. Subukan muli.</string>\n    <string name=\"family_management_exist_group_success\">Umalis ka sa iyong grupo ng pamilya…</string>\n    <string name=\"family_management_delete_group_success\">Binura ang grupo ng pamilya</string>\n    <string name=\"family_management_delete_group_failure\">Nabigong burahin ang grupo</string>\n    <string name=\"family_management_delete_group_cancel\">Kanselahin</string>\n    <string name=\"family_management_delete_group_confirm\">OK</string>\n    <string name=\"family_management_input_pwd\">Pakilagay ang iyong password</string>\n    <string name=\"family_management_invite_sent_date_format\">Ipinadala ang imbitasyon sa %s</string>\n    <string name=\"family_management_invite_send\">Ipinadala ang imbitasyon</string>\n    <string name=\"family_management_pwd_error\">Maling password, pakilagay ulit</string>\n    <string name=\"pref_app_install_settings_title\">Mga Setting ng App Installer</string>\n    <string name=\"pref_app_install_switch_title\">Payagan ang Pag-install ng App</string>\n    <string name=\"pref_app_install_other_apps_note\">Pinapayagan ng awtorisasyon ang pag-install ng mga app na ibinigay mula sa iba pang mga pinagmulan.</string>\n    <string name=\"pref_app_install_permission_instruction\">Para masigurado na gumagana nang mabuti ang iyong mga naka-install na app, mangyaring pahintulutan ang Kasamahan ng microG na mag-install ng mga app na na-download ng mga ibang pinagmulan.</string>\n    <string name=\"prefcat_app_install_list_title\">Mga app na gumagamit ng App Installer</string>\n    <string name=\"service_name_google_location_sharing\">Google Location Sharing</string>\n    <string name=\"location_sharing_description\">Ipamahala ang iyong real-time na pagbabahagi ng lokasyon sa mga Google app at serbisyo mula sa device na ito</string>\n    <string name=\"location_sharing_learn_more\">Matuto pa tungkol sa Location Sharing</string>\n    <string name=\"location_sharing_switch_text\">Gamitin ang Location Sharing</string>\n    <string name=\"location_sharing_turn_off_notify_hint\">Kapag patayin mo ang Location Sharing sa device na ito, hindi aabisuhan ang mga taong binabahagian mo.</string>\n    <string name=\"location_sharing_off_previous_hint\">Magiging available lamang ang iyong huling binahaging lokasyon hanggang sa buksan mo ito ulit.</string>\n    <string name=\"location_sharing_disabled\">Walang mga aktibong pagbabahagi ng lokasyon para sa account na ito</string>\n    <string name=\"location_sharing_turn_on_hint\">Sa sandaling magsimula kang ibahagi ang iyong lokasyon mula sa isang Google app o serbisyo, maaari mong ipamahala ang Location Sharing dito.\\n\\nPara magsimulang ibahagi ang iyong lokasyon, pumunta sa Google Maps o Family Link.</string>\n    <string name=\"location_sharing_turn_off_title\">Patayin ang Location Sharing</string>\n    <string name=\"location_sharing_turn_off_hint\">Baka binabahagi mo pa rin ang iyong lokasyon mula sa iba pang mga device na naka-sign in sa parehong Google Account o mula sa non-Google na app. Siguraduhin na suriin ang iyong mga setting sa pagbabahagi ng lokasyon kahit saan itong maaaring mag-apply.\\n\\nAng mga taong binahagian mo ay patuloy na makikita ang iyong huling ibinahaging lokasyon.</string>\n    <string name=\"location_sharing_turn_off_cancel\">Panatilihing bukas</string>\n    <string name=\"location_sharing_turn_off_confirm\">Patayin</string>\n    <string name=\"location_sharing_confirm_dialog_title\">Paganahin ang Location Sharing</string>\n    <string name=\"location_sharing_confirm_dialog_text\">Makikita palagi ng mga taong binabahagian mo ng lokasyon ang:\\n· Iyong pangalan at larawan ng profile\\n· Kamakailang lokasyon ng iyong device, kahit na hindi ka gumagamit ng isang serbisyo ng Google\\n· Baterya ng iyong device, at kung ito ay nagcha-charge\\n· Iyong oras ng pagdating at pagalis, kapag nagdagdag sila ng abiso ng Location Sharing</string>\n    <string name=\"service_name_device_attestation\">Pagpapatunay sa Device</string>\n    <string name=\"prefcat_device_attestation_apps_title\">Mga app na gumagamit ng Device Attestation</string>\n    <string name=\"pref_device_attestation_app_allow_requests_title\">Payagan ang mga hiling</string>\n    <string name=\"pref_device_attestation_app_allow_requests_summary\">Payagan ang app na humiling ng pagpapatunay sa device</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-fr/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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  --><resources>\n    <string name=\"permission_service_all_label\">Tous les services Google</string>\n    <string name=\"permission_service_all_description\">accéder à tous les services Google par le biais de tout compte Google associé.</string>\n    <string name=\"permission_service_android_label\">Services Android</string>\n    <string name=\"permission_service_android_description\">accéder aux services Android par le biais de tout compte Google associé.</string>\n    <string name=\"permission_service_adsense_label\">Google AdSense - Pub</string>\n    <string name=\"permission_service_adsense_description\">accéder à AdSense par le biais de tout compte Google associé.</string>\n    <string name=\"permission_service_adwords_label\">Google AdWords - Pub</string>\n    <string name=\"permission_service_adwords_description\">accéder à AdWords par le biais de tout compte Google associé.</string>\n    <string name=\"permission_service_ah_label\">Google App Engine - conception et hébergement d\\'applications web basé sur les serveurs de Google</string>\n    <string name=\"permission_service_ah_description\">accéder à Google App Engine par le biais de tout compte Google associé.</string>\n    <string name=\"permission_service_blogger_label\">Google Blogger - Blogueur</string>\n    <string name=\"permission_service_blogger_description\">accéder à Blogger par le biais de tout compte Google associé.</string>\n    <string name=\"permission_service_cl_label\">Calendrier Google</string>\n    <string name=\"permission_service_cl_description\">accéder au Calendrier Google par le biais de tout compte Google associé.</string>\n    <string name=\"permission_service_cp_label\">Contacts Google</string>\n    <string name=\"permission_service_cp_description\">accéder à Contacts Google par le biais de tout compte Google associé.</string>\n    <string name=\"permission_service_dodgeball_label\">Dodgeball - Fournisseur de logiciels de réseaux sociaux basé sur l\\'emplacement des fournisseurs de téléphonie mobile</string>\n    <string name=\"permission_service_dodgeball_description\">accéder à Dodgeball par le biais de tout compte Google associé.</string>\n    <string name=\"permission_service_finance_label\">Google Finance - Service en ligne publié par Google permettant de suivre le cours des actions et des devises</string>\n    <string name=\"permission_service_finance_description\">accéder à Google Finance par le biais de tout compte Google associé.</string>\n    <string name=\"permission_service_gbase_label\">Google Base - service permettant de mettre en ligne et de référencer tout type de contenu en termes d\\'information</string>\n    <string name=\"permission_service_gbase_description\">accéder à Google Base par le biais de tout compte Google associé.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_androidpublisher\">accéder à Google Play Développeur Android</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order\">Pour les utilisateurs et administrateurs revendeurs, accès lecture/écriture lors de tests dans la sandbox de l\\'API, ou accès lecture/écriture lors d\\'un appel direct pour une opération API.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.migration\">Accès lecture/écriture à l\\'API Groups Migration.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar\">Gérer vos calendriers</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan\">Gérer vos données GAN</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar.readonly\">Voir vos calendriers</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_cloudprint\">Voir et gérer vos données d\\'impression Google Cloud</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute\">Voir et gérer vos ressources Google Compute Engine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute.readonly\">Voir vos ressources Google Compute Engine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_only\">Voir vos données dans Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate\">Voir et gérer vos jobs Google Maps Coordinate</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.full_control\">Gérer vos données et permissions dans Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_write\">Gérer vos données dans Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_dfareporting\">Voir et gérer les rapports DoubleClick for Advertisers</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.appdata\">Autoriser l\\'accès au dossier Application Data</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.apps.readonly\">Voir vos applications Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.file\">Voir et gérer les fichiers que vous avez ouvert ou créé avec l\\'application Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.install\">Cadre spécial utilisé pour permettre aux utilisateurs d\\'approuver l\\'installation d\\'une application</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.metadata.readonly\">Voir les métadonnées pour les fichiers et documents dans votre Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.readonly\">Voir les fichiers et documents dans votre Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.scripts\">Modifier le comportement de vos scripts Google Apps Script</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive\">Voir et gérer les fichiers et documents dans votre Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase.readonly\">voir votre compte Freebase</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase\">Se connecter à votre compte Freebase</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables\">Gérer vos Tables Fusion</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables.readonly\">Voir vos Tables Fusion</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_games\">Cadre pour accéder aux données de Google Play Games.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan.readonly\">Voir vos données GAN</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_glass.timeline\">Étendue de la chronologie Glass</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gcm_for_chrome\">CloudMessaging pour Chrome</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.compose\">Créer, lire, modifier et supprimer des brouillons. Envoyer des messages et brouillons.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.modify\">Toutes les opérations de lecture/écriture excepté les suppressions immédiates et permanentes de conversations et messages, sans passer par la corbeille.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.readonly\">Lire toutes les ressources et leurs métadonnées - pas d\\'opération d\\'écriture.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.best\">Gérer votre meilleure position disponible et historique de localisation</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.city\">Gérer votre localisation approximative (nom de la ville) et historique de localisation</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.best\">Gérer votre meilleur position disponible</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.city\">Gérer votre localisation (ville)</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine\">Voir et gérer vos données Google Maps Engine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine.readonly\">Voir vos données Google Maps Engine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut.readonly\">Voir vos données Orkut</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mobilemaps.firstparty\">Voir et gérer votre expérience mobile Google Maps</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut\">Gérer votre activité Orkut</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.login\">Identifier vos nom, informations basiques et liste de personnes auxquelles vous êtes connectées sur Google+</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.me\">Identifier qui vous êtes sur Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_prediction\">Gérer vos données dans l\\'API Google Prediction</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_shoppingapi\">Voir vos données produit</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification\">Gérer la liste des sites et domaines que vous contrôlez</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification.verify_only\">Gérer les vérifications de votre nouveau site avec Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue.consumer\">Consommer les tâches de vos listes de tâches</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_structuredcontent\">Accès lecture/écriture à l\\'API Shopping Content.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue\">Gérer vos tâches</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.email\">Voir votre adresse mail</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tracks\">API Google Maps Tracks, ce cadre permet un accès lecture/écriture aux données de votre projet.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_urlshortener\">Gérer vos URLs raccourcies goo.gl</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.profile\">Voir les informations de base sur votre compte</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube\">Gérer votre compte YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.upload\">Gérer vos vidéos YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtubepartner\">Voir et gérer vos actifs et contenus associés sur YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.readonly\">Voir votre compte YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics_monetary.readonly\">Voir les rapports monétaires YouTube Analytics pour votre contenu YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics.readonly\">Voir les rapports YouTube Analytics pour votre contenu YouTube</string>\n    <string name=\"permission_service_grandcentral_label\">Google Voice - Voix Google</string>\n    <string name=\"permission_service_jotspot_description\">accéder à JotSpot par le biais de tout compte Google associé.</string>\n    <string name=\"permission_service_ig_description\">accéder à iGoogle par le biais de tout compte Google associé.</string>\n    <string name=\"permission_service_jotspot_label\">JotSpot</string>\n    <string name=\"permission_service_knol_label\">Knol</string>\n    <string name=\"permission_service_knol_description\">accéder à Knol par le biais de tout compte Google associé.</string>\n    <string name=\"permission_service_lh2_label\">Picasa Web Albums - Albums Web Picasa</string>\n    <string name=\"permission_service_lh2_description\">accéder à Picasa Web Albums par le biais de tout compte Google associé.</string>\n    <string name=\"permission_service_news_label\">Google Actualités</string>\n    <string name=\"permission_service_local_label\">Google Maps</string>\n    <string name=\"permission_service_local_description\">accéder à Google Maps par le biais de tout compte Google associé.</string>\n    <string name=\"permission_service_mail_label\">Mail Google</string>\n    <string name=\"permission_service_mail_description\">accéder à Google Mail par le biais de tout compte Google associé.</string>\n    <string name=\"permission_service_news_description\">accéder à Google Actualités par le biais de tout compte Google associé.</string>\n    <string name=\"permission_service_notebook_label\">Google Notebook</string>\n    <string name=\"permission_service_notebook_description\">accéder à Google Notebook par le biais de tout compte Google associé.</string>\n    <string name=\"permission_service_orkut_label\">Orkut</string>\n    <string name=\"permission_service_orkut_description\">accéder à Orkut par le biais de tout compte Google associé.</string>\n    <string name=\"permission_service_print_label\">Google Livres</string>\n    <string name=\"permission_service_print_description\">accéder à Google Livres par le biais de tout compte Google associé.</string>\n    <string name=\"permission_service_sierra_label\">Google Checkout accounts - Déconnexion comptes Google</string>\n    <string name=\"permission_service_sierraqa_label\">Google Checkout QA accounts _ Déconnexion comptes Google QA</string>\n    <string name=\"permission_service_sierrasandbox_label\">Google Checkout Sandbox accounts - Déconnexion comptes Google Sandbox</string>\n    <string name=\"permission_service_sierraqa_description\">accéder à Google Checkout QA accounts par le biais de tout compte Google associé.</string>\n    <string name=\"permission_service_sierra_description\">accéder à Google Checkout accounts par le biais de tout compte Google associé.</string>\n    <string name=\"permission_service_sierrasandbox_description\">accéder à Google Checkout Sandbox accounts par le biais de tout compte Google associé.</string>\n    <string name=\"permission_service_sitemaps_description\">accéder à Google Webmaster Tools par le biais de tout compte Google associé.</string>\n    <string name=\"permission_service_sitemaps_label\">Google Webmaster Tools - Outils Google Webmaster</string>\n    <string name=\"permission_service_speech_description\">accéder à la recherche vocale par le biais de tout compte Google associé.</string>\n    <string name=\"permission_service_speech_label\">Recherche Vocale</string>\n    <string name=\"permission_service_YouTubeUser_description\">accéder aux noms d\\'utilisateurs YouTube par le biais de tout compte Google associé.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller\">voir et gérer vos données Ad Exchange</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks\">Gérer vos tâches</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks.readonly\">Voir vos tâches</string>\n    <string name=\"permission_service_groups2_label\">Google Groups - Groupes Google</string>\n    <string name=\"permission_service_grandcentral_description\">accéder à Google Voice par le biais de tout compte Google associé.</string>\n    <string name=\"permission_service_groups2_description\">accéder à Google Groups par le biais de tout compte Google associé.</string>\n    <string name=\"permission_service_health_label\">Google Health - Santé Google</string>\n    <string name=\"permission_service_health_description\">accéder à Google Health par le biais de tout compte Google associé.</string>\n    <string name=\"permission_service_ig_label\">iGoogle</string>\n    <string name=\"permission_service_speechpersonalization_label\">Reconnaissance Vocale personnalisée</string>\n    <string name=\"permission_service_speechpersonalization_description\">accéder à la reconnaissance vocale personnalisée par le biais de tout compte Google associé.</string>\n    <string name=\"permission_service_talk_label\">Google Talk</string>\n    <string name=\"permission_service_talk_description\">accéder à Google Talk par le biais de tout compte Google associé.</string>\n    <string name=\"permission_service_wifi_label\">Google Wi-Fi</string>\n    <string name=\"permission_service_wifi_description\">accéder à Google Wi-Fi par le biais de tout compte Google associé.</string>\n    <string name=\"permission_service_wise_label\">Google Spreadsheets</string>\n    <string name=\"permission_service_wise_description\">accéder à Google Spreadsheets par le biais de tout compte Google associé.</string>\n    <string name=\"permission_service_writely_label\">Google Docs</string>\n    <string name=\"permission_service_writely_description\">accéder à Google Docs par le biais de tout compte Google associé.</string>\n    <string name=\"permission_service_youtube_label\">YouTube</string>\n    <string name=\"permission_service_youtube_description\">accéder à YouTube par le biais de tout compte Google associé.</string>\n    <string name=\"permission_service_YouTubeUser_label\">noms d\\'utilisateurs YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_activity\">voir l\\'historique d\\'activité de vos applications Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.buyer\">gérer votre configuration de compte acheteur Ad Exchange</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller.readonly\">Voir vos données Ad Exchange</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense.readonly\">voir vos données AdSense</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsensehost\">voir et gérer vos données hôte AdSense et comptes associés</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense\">voir et gérer vos données AdSense</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics.readonly\">voir vos données Google Analytics</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics\">voir et gérer vos données Google Analytics</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appengine.admin\">Périmètre App Engine Admin.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.settings\">voir et gérer les paramètres d\\'un Groupe Google Apps</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order.readonly\">En plus du cadre global lecture/écriture OAuth, utiliser le contexte lecture seule OAuth lors de la récupération des données du client.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.licensing\">Accès lecture/écriture à l\\'API License Manager.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps_reporting_audit.readonly\">Accès à l\\'API Admin Audit en lecture seule</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appstate\">Cadre pour l\\'utilisation du service App State.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery.readonly\">Voir vos données dans Google BigQuery</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery\">Voir et gérer vos données dans Google BigQuery</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger\">Gérer votre compte Blogger</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger.readonly\">Voir votre compte Blogger</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_books\">Gérer vos livres</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate.readonly\">Voir vos jobs Google Coordinate</string>\n    <string name=\"perm_activity_recognition_description\">recevoir périodiquement l\\'état de votre activité depuis Google, comme par exemple, si vous marchez, conduisez, faites du vélo ou êtes immobile.</string>\n    <string name=\"perm_activity_recognition_label\">Reconnaissance de l\\'activité</string>\n</resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-fr/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2017 microG Project Team\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  --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <plurals name=\"pref_unifiednlp_summary\">\n        <item quantity=\"one\"><xliff:g example=\"3\">%1$d</xliff:g> fournisseur configuré</item>\n        <item quantity=\"many\"><xliff:g example=\"3\">%1$d</xliff:g> fournisseurs configurés</item>\n        <item quantity=\"other\"><xliff:g example=\"3\">%1$d</xliff:g> fournisseurs configurés</item>\n    </plurals>\n    <plurals name=\"gcm_registered_apps_counter\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> application enregistrée</item>\n        <item quantity=\"many\"><xliff:g example=\"123\">%1$d</xliff:g> applications enregistrées</item>\n        <item quantity=\"other\"><xliff:g example=\"123\">%1$d</xliff:g> applications enregistrées</item>\n    </plurals>\n    <plurals name=\"cond_perm_summary\">\n        <item quantity=\"one\">Une autorisation requise pour le bon fonctionnement des services microG est manquante.</item>\n        <item quantity=\"many\">Plusieurs autorisations requises pour le bon fonctionnement des services microG sont manquantes.</item>\n        <item quantity=\"other\">Plusieurs autorisations requises pour le bon fonctionnement des services microG sont manquantes.</item>\n    </plurals>\n    <plurals name=\"cond_perm_action\">\n        <item quantity=\"one\">Demander l\\'autorisation manquante</item>\n        <item quantity=\"many\">Demander les autorisations manquantes</item>\n        <item quantity=\"other\">Demander les autorisations manquantes</item>\n    </plurals>\n</resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-fr/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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  --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"gms_app_name\">Services microG</string>\n    <string name=\"gms_settings_name\">Paramètres de microG</string>\n    <string name=\"just_a_sec\">Juste une seconde…</string>\n    <string name=\"google_account_label\">Google</string>\n    <string name=\"ask_permission_tos\">En poursuivant, vous autorisez cette application et Google à utiliser vos informations en accord avec leurs termes de service et politiques de vie privée respectifs.</string>\n    <string name=\"ask_scope_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> voudrait :</string>\n    <string name=\"ask_service_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> voudrait utiliser :</string>\n    <string name=\"account_manager_title\">Gestionnaire du compte Google</string>\n    <string name=\"sorry\">Désolé…</string>\n    <string name=\"no_network_error_desc\">\"Vous n’avez pas de connexion réseau.\n\nIl peut s’agir d’un problème temporaire ou bien votre terminal Android n’est pas actuellement relié à un réseau de données. Essayez de nouveau une fois connecté à un réseau mobile, ou connectez-vous à un réseau Wi-Fi.\"</string>\n    <string name=\"auth_general_error_desc\">\"Un problème a été rencontré en tentant de communiquer avec les serveurs de Google.\n\nRéessayez ultérieurement.\"</string>\n    <string name=\"auth_finalize\">\"Votre terminal est en train de contacter Google pour enregistrer des informations dans votre compte.\n\nCeci peut prendre plusieurs minutes.\"</string>\n    <string name=\"allow\">Autoriser</string>\n    <string name=\"deny\">Refuser</string>\n    <string name=\"auth_notification_title\">Authentification requise</string>\n    <string name=\"auth_notification_content\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> requiert votre autorisation pour accéder à votre compte Google.</string>\n    <string name=\"perm_status_broadcast_label\">écouter les diffusions de status internes</string>\n    <string name=\"perm_c2dm_receive_label\">écouter les messages C2DM</string>\n    <string name=\"perm_c2dm_send_label\">envoyer des messages C2DM aux autres applications</string>\n    <string name=\"perm_gtalk_svc_label\">échanger des messages et recevoir des notifications de synchronisation de la part des serveurs de Google</string>\n    <string name=\"perm_extended_access_label\">Accès étendu aux services Google</string>\n    <string name=\"service_name_checkin\">Enregistrement du terminal</string>\n    <string name=\"service_name_mcs\">Cloud Messaging</string>\n    <string name=\"service_name_snet\">Google SafetyNet</string>\n    <string name=\"games_title\">Google Play Jeux</string>\n    <string name=\"games_info_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> voudrait utiliser Google Play Jeux</string>\n    <string name=\"games_info_content\">Pour utiliser Play Jeux il est requis d’installer l’application Google Play Jeux. L’application peut poursuivre sans Play Jeux, mais il est possible qu’elle se comporte de manière imprévue.</string>\n    <string name=\"pick_place_title\">Sélectionner un emplacement</string>\n    <string name=\"pick_place_desc\">La sélection d’emplacement n’est pas encore disponible.</string>\n    <string name=\"place_picker_select_title\">Sélectionner cette position</string>\n    <string name=\"place_picker_nearby_places\">Lieux environnants</string>\n    <string name=\"place_picker_location_lat_lng\">(%1$.7f, %2$.7f)</string>\n    <string name=\"lacking_permission_toast\">Services microG : L\\'autorisation <xliff:g example=\"have full network acccess\">%1$s</xliff:g> est manquante</string>\n    <string name=\"network_type_mobile\">Réseau mobile</string>\n    <string name=\"network_type_wifi\">Wi-Fi</string>\n    <string name=\"network_type_roaming\">Itinérance</string>\n    <string name=\"network_type_other\">Autres réseaux</string>\n    <!-- Self check -->\n\n    <string name=\"self_check_cat_fake_sig\">Support de l’usurpation de signature</string>\n    <string name=\"self_check_cat_gms_packages\">Paquets installés</string>\n    <string name=\"self_check_cat_system\">Système</string>\n    <string name=\"self_check_name_fake_sig_perm\">Le système supporte l’usurpation de signature : </string>\n    <string name=\"self_check_resolution_fake_sig_perm\">Votre ROM ne supporte pas nativement l’usurpation de signature. Vous pouvez néanmoins utiliser Xposed ou d’autres mécanismes pour usurper les signatures. Merci de consulter la documentation sur les ROMs supportant l’usurpation de signature et comment utiliser microG sur les autres.</string>\n    <string name=\"self_check_name_perm_granted\">Le système autorise l’usurpation de signature : </string>\n    <string name=\"self_check_resolution_perm_granted\">C’est une indication forte que la ROM supporte l’usurpation de signature mais que celle-ci requiert une action supplémentaire pour être activée. Merci de consulter la documentation sur les éventuelles étapes nécessaires.</string>\n    <string name=\"self_check_name_system_spoofs\">Le système usurpe la signature : </string>\n    <string name=\"self_check_resolution_system_spoofs\">Merci de consulter la documentation sur les éventuelles étapes nécessaires.</string>\n    <string name=\"self_check_pkg_gms\">Services microG</string>\n    <string name=\"self_check_pkg_vending\">Compagnon microG / Play Store</string>\n    <string name=\"self_check_pkg_gsf\">Framework microG Services</string>\n    <string name=\"self_check_name_app_installed\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> installé : </string>\n    <string name=\"self_check_resolution_app_installed\">Installez l’application <xliff:g example=\"F-Droid\">%1$s</xliff:g> ou tout autre compatible. Merci de consulter la documentation pour obtenir la liste des applications compatibles.</string>\n    <string name=\"self_check_name_correct_sig\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> dispose de la bonne signature : </string>\n    <string name=\"self_check_resolution_correct_sig\">Soit l’application <xliff:g example=\"F-Droid\">%1$s</xliff:g> installée n’est pas compatible, soit l’usurpation de signature n’est pas active pour celle-ci. Merci de consulter la documentation sur les applications et ROMs compatibles.</string>\n    <string name=\"self_check_name_battery_optimizations\">Optimisations de la batterie ignorées : </string>\n    <string name=\"self_check_resolution_battery_optimizations\">Appuyez ici pour désactiver les optimisations de la batterie. Des applications peuvent mal fonctionner si vous ne le faites pas.</string>\n    <!-- Settings strings -->\n\n    <string name=\"prefcat_about\">À propos</string>\n    <string name=\"prefcat_components\">Composants</string>\n    <string name=\"prefcat_configuration\">Configuration</string>\n    <string name=\"prefcat_google_services\">Services Google</string>\n    <string name=\"prefcat_location_service\">Service de localisation</string>\n    <string name=\"prefcat_services\">Services</string>\n    <string name=\"prefcat_test\">Test</string>\n    <string name=\"cond_gcm_bat_title\">Optimisations de la batterie activées</string>\n    <string name=\"cond_gcm_bat_summary\">Vous avez activé Cloud Messaging mais l’optimisation de la batterie est activée pour les services microG. Afin de recevoir les notifications poussées vous devriez désactiver les optimisations de la batterie.</string>\n    <string name=\"cond_gcm_bat_action\">Désactiver les optimisations de la batterie</string>\n    <string name=\"cond_perm_title\">Autorisations manquantes</string>\n    <string name=\"prefs_account\">Préférences du compte</string>\n    <string name=\"prefs_account_privacy\">Informations personnelles &amp; vie privée</string>\n    <string name=\"prefs_account_security\">Connexion &amp; sécurité</string>\n    <string name=\"pref_auth_trust_google_title\">Faire confiance à Google pour les autorisations des applications</string>\n    <string name=\"pref_auth_trust_google_summary\">Si désactivé, l’utilisateur est interrogé avant que la demande d’autorisation d’une application soit envoyée à Google. Certaines applications échoueront à utiliser le compte Google si ceci est désactivé.</string>\n    <string name=\"pref_checkin_enable_summary\">Enregistre votre terminal auprès des services Google et crée un identifiant unique. microG retire les identifiants autres que le nom de votre compte Google des informations d’enregistrement.</string>\n    <string name=\"pref_more_settings\">Plus</string>\n    <string name=\"pref_gcm_enable_mcs_summary\">Cloud Messaging est un fournisseur de notifications poussées utilisé par beaucoup d’applications tierces. Pour l’utiliser vous devez activer l’enregistrement du terminal.</string>\n    <string name=\"pref_gcm_heartbeat_title\">Intervalle des signaux de présence Cloud Messaging</string>\n    <string name=\"pref_gcm_heartbeat_summary\">L’intervalle en secondes auquel le système signale sa présence aux serveurs de Google. Augmenter ce nombre réduira la consommation de batterie mais peu induire un délai dans la réception des messages poussées.\n\\nDéprécié, sera remplacé dans une prochaine version.</string>\n    <string name=\"pref_gcm_apps_title\">Applications utilisant Cloud Messaging</string>\n    <string name=\"pref_gcm_apps_summary\">Liste des applications actuellement enregistrées auprès de Cloud Messaging.</string>\n    <string name=\"pref_gcm_confirm_new_apps_title\">Confirmation pour les nouvelles applications</string>\n    <string name=\"pref_gcm_confirm_new_apps_summary\">Demander avant d’enregistrer une nouvelle application auprès de Cloud Messaging</string>\n    <string name=\"pref_gcm_ping_interval\">Intervalle de ping : <xliff:g example=\"10 minutes\">%1$s</xliff:g></string>\n    <string name=\"pref_about_title\">À propos des services microG</string>\n    <string name=\"pref_about_summary\">Informations de version et librairies utilisées</string>\n    <string name=\"gcm_app_error_unregistering\">Erreur lors du désenregistrement</string>\n    <string name=\"gcm_app_not_installed_anymore\">Cette application n’est plus installée</string>\n    <string name=\"gcm_unregister_app\">Désenregistrer</string>\n    <string name=\"gcm_not_registered\">Non enregistrée</string>\n    <string name=\"gcm_no_message_yet\">Aucun message reçu pour l’instant</string>\n    <string name=\"gcm_last_message_at\">Dernier message : <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_registered\">Enregistrée</string>\n    <string name=\"gcm_registered_since\">Enregistrée depuis : <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_unregister_confirm_title\">Désenregistrer <xliff:g example=\"F-Droid\">%1$s</xliff:g> ?</string>\n    <string name=\"gcm_unregister_confirm_message\">Certaines applications ne se réenregistrent pas et/ou ne fournissent pas de moyen de le faire manuellement. Ces applications peuvent ne plus fonctionner correctement après le désenregistrement.\\nContinuer ?</string>\n    <string name=\"gcm_unregister_after_deny_message\">Vous avez empêché une application déjà enregistrée de s’enregistrer pour recevoir des notifications poussées.\n\\nVoulez-vous la désenregistrer maintenant pour qu’elle ne reçoive plus de notifications poussées à l’avenir ?</string>\n    <string name=\"gcm_messages_counter\">Messages : <xliff:g example=\"123\">%1$d</xliff:g> (<xliff:g example=\"12345\">%2$d</xliff:g> octets)</string>\n    <string name=\"gcm_network_state_disconnected\">Déconnecté</string>\n    <string name=\"gcm_network_state_connected\">Connecté depuis <xliff:g example=\"2 hours ago\">%1$s</xliff:g></string>\n    <string name=\"safetynet_intro\">Google SafetyNet est un système de certification du terminal, assurant que celui-ci est correctement sécurisé et compatible avec Android CTS. Certaines applications utilisent SafetyNet pour des raisons de sécurité ou comme prérequis anti-altérations.\n\\n\n\\nLes services microG contiennent une implantation libre de SafetyNet, mais les serveurs officiels requièrent que les requêtes SafetyNet soient signées par le système propriétaire DroidGuard.</string>\n    <string name=\"pref_safetynet_test_title\">Tester la certification SafetyNet</string>\n    <string name=\"pref_droidguard_operation_mode\">Mode d’opération</string>\n    <string name=\"gms_settings_summary\">Paramétrer les services microG.</string>\n    <string name=\"auth_sign_in\">Se connecter</string>\n    <string name=\"perm_car_speed_label\">Vitesse du véhicule</string>\n    <string name=\"perm_car_speed_description\">accéder à la vitesse de votre véhicule</string>\n    <string name=\"perm_car_fuel_description\">accéder aux informations relatives au niveau de carburant de votre véhicule</string>\n    <string name=\"perm_car_mileage_label\">Kilométrage du véhicule</string>\n    <string name=\"pref_add_account_title\">Compte</string>\n    <string name=\"pref_add_account_summary\">Ajouter un compte Google</string>\n    <string name=\"pref_test_summary_passed\">Tous les tests passés avec succès</string>\n    <string name=\"pref_test_summary_failed\">Échec : %s</string>\n    <string name=\"pref_device_registration_device_profile_category\">Profil appareil</string>\n    <string name=\"pref_accounts_summary\">Ajouter et gérer vos comptes Google</string>\n    <string name=\"pref_test_summary_warn\">Alerte : %s</string>\n    <string name=\"pref_test_summary_running\">En cours…</string>\n    <string name=\"profile_name_real\">Réel</string>\n    <string name=\"push_notifications_summary_off\">Désactivé</string>\n    <string name=\"profile_name_auto\">Automatique : %s</string>\n    <string name=\"pref_safetynet_recent_recaptcha_summary\">ReCaptcha : %s</string>\n    <string name=\"pref_safetynet_recent_copy_json\">Copier les données JSON JWS</string>\n    <string name=\"pref_safetynet_recent_advice\">Recommandation</string>\n    <string name=\"auth_package_override_request_message\"><b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> souhaite accéder à votre compte comme s\\'il appartenait à <b><xliff:g example=\"F-Droid\">%2$s</xliff:g> de <xliff:g example=\"F-Droid Inc.\">%3$s</xliff:g></b>. Cela pourrait lui accorder un accès privilégié à votre compte.</string>\n    <string name=\"signin_picker_title\">Choisir un compte</string>\n    <string name=\"signin_picker_add_account_label\">Ajouter un autre compte</string>\n    <string name=\"signin_subtext_policy\">Avant d\\'utiliser cette appli, revoir ses %1$s et %2$s.</string>\n    <string name=\"perm_car_info_description\">accéder aux informations de votre véhicule</string>\n    <string name=\"perm_car_vendor_extension_description\">accéder à la chaine de la marque du véhicule pour échanger des informations spécifiques à celui-ci</string>\n    <string name=\"pref_auth_strip_device_name_title\">Retirer le nom du terminal lors de l\\'authentification</string>\n    <string name=\"pref_auth_strip_device_name_summary\">Si activé, les requêtes d\\'authentification n’incluront pas le nom du terminal, ce qui peut permettre à des appareils non autorisés à se connecter, mais peut aussi avoir des conséquences imprévisibles.</string>\n    <string name=\"pref_accounts_title\">Comptes Google</string>\n    <string name=\"prefcat_accounts_settings_title\">Paramètres</string>\n    <string name=\"prefcat_accounts_current_accounts_title\">Comptes</string>\n    <string name=\"pref_safetynet_recent_attestation_summary\">Attestation : %s</string>\n    <string name=\"pref_safetynet_recent_recaptcha_enterprise_summary\">ReCaptcha Enterprise : %s</string>\n    <string name=\"pref_safetynet_recent_eval_type\">Type d\\'évaluation</string>\n    <string name=\"prefcat_safetynet_apps_title\">Applis utilisant SafetyNet</string>\n    <string name=\"menu_clear_recent_requests\">Effacer les requêtes récentes</string>\n    <string name=\"profile_name_system\">Système : %s</string>\n    <string name=\"pref_safetynet_recent_cat_response\">Données de la réponse</string>\n    <string name=\"pref_safetynet_recent_cat_request\">Donnés de la requête</string>\n    <string name=\"gcm_enable_switch\">Recevoir des notifications poussées</string>\n    <string name=\"limited_services_app_name\">Services limités microG</string>\n    <string name=\"auth_package_override_request_title\">Autoriser l\\'accès privilégié à &lt;xliff:g example=\\\"F-Droid\\\"&gt;%1$s&lt;/xliff:g&gt;&lt;/b&gt; à &lt;xliff:g example=\\\"account@example.com\\\"&gt;%2$s&lt;/xliff:g&gt; ?</string>\n    <string name=\"signin_picker_subtitle\">pour continuer vers <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"signin_confirm_title\">Autoriser à vous connecter vers <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"signin_confirm_button_text\">Autoriser et partager</string>\n    <string name=\"signin_subtext_policy_terms\">conditions générales</string>\n    <string name=\"signin_subtext_sharing\">Pour continuer, microG va fournir à <xliff:g example=\"F-Droid\">%1$s</xliff:g> les éléments suivants de votre compte Google : nom, adresse mail et image de profil.</string>\n    <string name=\"signin_subtext_policy_privacy\">politique de confidentialité</string>\n    <string name=\"perm_gsf_read_gservices_label\">lire la configuration des services Google</string>\n    <string name=\"perm_provision_label\">provision des services microG</string>\n    <string name=\"perm_provision_description\">Autorise l\\'appli à configurer les services microG sans interaction de l’utilisateur</string>\n    <string name=\"perm_car_info_label\">Informations du véhicule</string>\n    <string name=\"perm_car_fuel_label\">Niveau de carburant du véhicule</string>\n    <string name=\"perm_car_mileage_description\">accéder au informations relatives au kilométrage de votre véhicule</string>\n    <string name=\"perm_car_vendor_extension_label\">Chaine de la marque du véhicule</string>\n    <string name=\"pref_push_app_wake_for_delivery_summary\">Démarrer l\\'application en arrière-plan pour recevoir les messages poussés arrivants.</string>\n    <string name=\"prefcat_push_apps_title\">Applis utilisant les notifications poussées</string>\n    <string name=\"prefcat_push_apps_registered_title\">Applis enregistrées</string>\n    <string name=\"pref_recaptcha_enterprise_test_title\">Test ReCAPTCHA Enterprise</string>\n    <string name=\"pref_droidguard_unsupported_summary\">L’exécution de DroidGuard n\\'est pas supportée sur cet appareil. Les services SafetyNet pourraient mal fonctionner.</string>\n    <string name=\"profile_name_native\">Natif</string>\n    <string name=\"pref_device_registration_import_custom_profile_title\">Importer un profil spécifique</string>\n    <string name=\"profile_name_user\">Spécifique : %s</string>\n    <string name=\"pref_auth_visible_summary\">Si activé, toutes les applications de cet appareil auront la possibilité d\\'accéder aux adresses mail de vos comptes Google sans autorisation préalable.</string>\n    <string name=\"pref_auth_include_android_id_title\">Authentification via l\\'enregistrement du terminal</string>\n    <string name=\"pref_auth_visible_title\">Autoriser les applis à accéder aux comptes</string>\n    <string name=\"checkin_not_registered\">Non enregistré</string>\n    <string name=\"checkin_last_registration\">Dernier enregistrement : <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"checkin_enable_switch\">Enregistrer l\\'appareil</string>\n    <string name=\"pref_device_registration_android_id\">Android ID</string>\n    <string name=\"pref_safetynet_recent_response_status\">Statut de la réponse</string>\n    <string name=\"pref_safetynet_test_cts_failed\">Échec CTS</string>\n    <string name=\"push_notifications_summary_values_minutes\">%s minutes</string>\n    <string name=\"auth_before_connect\">Une application sur votre appareil tente de se connecter à un compte Google.\\n\\nSi cela est intentionnel, utilisez le bouton <b>Connexion</b> pour vous connecter à la page de connexion de Google. Sinon, appuyez sur <b>Annuler</b> pour revenir à l\\'application à l\\'origine de cette boîte de dialogue.</string>\n    <string name=\"safetynet_last_run_at\">Dernière utilisation : <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"service_name_vending\">Services Play Store</string>\n    <string name=\"pref_auth_include_android_id_summary\">Si désactivé, les requêtes d\\'authentification ne seront pas liées à l\\'enregistrement du terminal, ce qui peut permettre à des appareils non autorisés à se connecter, mais peut aussi avoir des conséquences imprévisibles.</string>\n    <string name=\"gcm_allow_app_popup\">Autoriser <xliff:g example=\"F-Droid\">%1$s</xliff:g> à s\\'enregistrer pour recevoir des notifications poussées ?</string>\n    <string name=\"pref_push_app_allow_register_title\">Autoriser l\\'enregistrement</string>\n    <string name=\"pref_push_app_allow_register_summary\">Autoriser l\\'appli à s’enregistrer pour recevoir des notifications poussées.</string>\n    <string name=\"pref_push_app_wake_for_delivery_title\">Démarrer l\\'appli sur un message poussé</string>\n    <string name=\"prefcat_push_apps_unregistered_title\">Applis désenregistrées</string>\n    <string name=\"prefcat_push_networks_title\">Réseaux à utiliser pour les messages poussés</string>\n    <string name=\"safetynet_enable_switch\">Autoriser l\\'attestation du terminal</string>\n    <string name=\"pref_recaptcha_test_title\">Test ReCAPTCHA</string>\n    <string name=\"pref_device_registration_import_custom_profile_summary\">Importer un profil spécifique depuis un fichier</string>\n    <string name=\"pref_device_registration_serial_title\">Numéro d\\'enregistrement</string>\n    <string name=\"pref_device_registration_select_profile_title\">Choisir le profil</string>\n    <string name=\"pref_safetynet_recent_uses\">Utilisations récentes</string>\n    <string name=\"pref_safetynet_recent_nonce\">Nonce (Hex)</string>\n    <string name=\"pref_safetynet_recent_request_type\">Type de requête</string>\n    <string name=\"pref_safetynet_recent_request_time\">Date de la requête</string>\n    <string name=\"pref_safetynet_recent_cat_basic\">Données de base</string>\n    <string name=\"pref_safetynet_recent_token\">Jeton</string>\n    <string name=\"pref_safetynet_recent_copied\">Copié dans le presse-papiers !</string>\n    <string name=\"pref_safetynet_test_integrity_cts_passed\">Intégrité et CTS passés avec succès</string>\n    <string name=\"pref_safetynet_test_integrity_failed\">Échec Intégrité</string>\n    <string name=\"pref_safetynet_test_not_completed\">Pas encore complété</string>\n    <string name=\"pref_safetynet_test_no_result\">Pas de résultat</string>\n    <string name=\"pref_safetynet_test_invalid_json\">JSON invalide</string>\n    <string name=\"push_notifications_summary_automatic\">Activé / Automatique : %s</string>\n    <string name=\"push_notifications_summary_manual\">Activé / Manuel : %s</string>\n    <string name=\"push_notifications_summary_values_seconds\">%s secondes</string>\n    <string name=\"auth_connecting\">Votre appareil est en train d\\'établir une connexion avec les serveurs de Google pour vous authentifier.\n\\n\n\\nCela peut prendre quelques secondes.</string>\n    <string name=\"pref_info_status\">Statut</string>\n    <string name=\"credentials_assisted_cancel\">Annuler</string>\n    <string name=\"credentials_assisted_continue\">Continuer</string>\n    <string name=\"credentials_assisted_choose_account_label\">Choisir un compte</string>\n    <string name=\"credentials_assisted_choose_account_subtitle\">pour continuer vers %1$s</string>\n    <string name=\"credentials_assisted_signin_button_text_long\">Se connecter avec Google</string>\n    <string name=\"pref_vending_billing_note_experimental\">Cette fonctionnalité est expérimentale et peut causer des pertes d\\'argent. Vous êtes prévenus.</string>\n    <string name=\"credentials_assisted_confirmation_header\">En cours de connexion</string>\n    <string name=\"pref_vending_summary_licensing_on\">Récupération de licences activée</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_switch\">Ajouter automatiquement les applis gratuites à la bibliothèque</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_summary\">Certaines applis gratuites vérifient si elles ont été téléchargées depuis Google Play. Ajouter automatiquement à la bibliothèque de votre compte toutes les applis gratuites à votre disposition afin qu\\'elles passent systématiquement ces vérifications.</string>\n    <string name=\"credentials_assisted_continue_as_user_button_label\">Continuer en tant que %1$s</string>\n    <string name=\"credentials_assisted_sign_back_title\">Se reconnecter à %1$s avec Google</string>\n    <string name=\"limited_services_dialog_information_ack\">Je comprends</string>\n    <string name=\"pref_vending_licensing_category\">Récupération de licences Google Play</string>\n    <string name=\"backup_disabled\">Sauvegarde actuellement impossible</string>\n    <string name=\"pref_vending_billing_category\">Facturation Google Play</string>\n    <string name=\"pref_vending_billing_enable_switch\">Gérer les requêtes de facturation</string>\n    <string name=\"pref_vending_billing_enable_summary\">Si activé, certaines applis pourront effectuer des achats ou initier des abonnements via le service de facturation Google Play.</string>\n    <string name=\"pref_vending_billing_note_licensing\">Certaines applis peuvent aussi nécessiter d\\'activer la récupération de licences pour vérifier vos achats.</string>\n    <string name=\"pref_vending_license_enable_summary\">Certaines applis exigent de vérifier que vous les avez achetées sur Google Play. Quand exigé par une appli, microG peut télécharger une preuve d\\'achat en provenance de Google. Si désactivé ou si aucun compte Google sur l\\'appareil, ces requêtes de vérification de licence seront ignorées.</string>\n    <string name=\"limited_services_dialog_information\">Vous utilisez les services limités microG. Contrairement aux services microG standard, cette version fonctionne uniquement avec les librairies microG, et non celles de Google Play. Cela signifie que la plupart des applications ignoreront ces services.</string>\n    <string name=\"feedback_disabled\">Feedback actuellement impossible</string>\n    <string name=\"pref_vending_summary_licensing_off\">Récupération de licences désactivée</string>\n    <string name=\"credentials_assisted_signin_consent_header\">En cours de connexion en tant que %1$s</string>\n    <string name=\"credentials_assisted_signin_consent\">En continuant, Google partagera avec %1$s votre nom, adresse mail et image de profil. Consultez la politique de confidentialité et les conditions générales de %1$s.</string>\n    <string name=\"pref_vending_licensing_enable_switch\">Gérer les requêtes de vérification de licence</string>\n    <string name=\"credentials_assisted_signin_description\">Vous pouvez gérer Se Connecter avec Google dans votre compte Google.</string>\n    <string name=\"auth_action_notification_channel_name\">Alertes de compte Google</string>\n    <string name=\"auth_action_notification_title\">Action requise sur le compte</string>\n    <string name=\"auth_action_notification_content\">Votre compte Google nécessite un paramètrage additionnel.</string>\n    <string name=\"auth_action_activity_header\">Terminez la configuration de votre compte Google</string>\n    <string name=\"auth_action_activity_explanation\">Complétez les étapes suivantes pour pouvoir utiliser votre compte Google %s sur cet appareil.</string>\n    <string name=\"auth_action_step_enable_checkin\">Activer l\\'enregistrement du terminal</string>\n    <string name=\"auth_action_step_enable_gcm\">Activer Cloud Messaging</string>\n    <string name=\"auth_action_step_enable_gcm_description\">Vous pouvez désactiver Cloud Messaging une fois la configuration du compte terminée.</string>\n    <string name=\"auth_action_step_allow_microg_gcm\">Autoriser Cloud Messaging pour microG</string>\n    <string name=\"auth_action_step_allow_microg_gcm_description\">En accord avec votre choix, microG nécessite votre permission avant de pouvoir s\\'enregistrer pour Cloud Messaging.</string>\n    <string name=\"auth_action_step_enable_lockscreen\">Configurer le verrouillage de sécurité de l\\'écran</string>\n    <string name=\"auth_action_step_perform_content_description\">Appuyez pour effectuer l\\'action</string>\n    <string name=\"auth_action_notification_channel_description\">Indique lorsqu\\'un de vos comptes Google requiert un paramètrage additionnel avant utilisation ou quand un compte est incompatible avec microG.</string>\n    <string name=\"auth_action_step_enable_checkin_description\">Votre appareil nécessite de s\\'enregistrer à Google au moins une fois.\\n\\nVous pouvez désactiver l\\'enregistrement de l\\'appareil à Google une fois la configuration du compte terminée.</string>\n    <string name=\"auth_action_step_enable_lockscreen_description\">Votre compte Google est géré par votre entreprise ou votre établissement. Votre administrateur a établi que cet appareil nécessite un verrouillage d\\'écran sécurisé avant de pouvoir accéder aux données du compte.\\n\\nVeuillez configurer un mot de passe, un code PIN ou un modèle de verrouillage écran.</string>\n    <string name=\"auth_action_step_completed_content_description\">Étape complétée</string>\n    <string name=\"auth_action_activity_finish\">Terminer</string>\n    <string name=\"pref_vending_asset_delivery_category\">Google Play Asset Delivery</string>\n    <string name=\"pref_vending_asset_delivery_switch\">Activer la distribution des packs d\\'éléments à la demande</string>\n    <string name=\"pref_vending_asset_delivery_summary\">Télécharger les packs d\\'éléments additionnels quand requis par les applis utilisant Play Asset Delivery</string>\n    <string name=\"pref_vending_asset_device_sync_switch\">Activer la synchronisation des information sur l\\'appareil</string>\n    <string name=\"pref_vending_asset_device_sync_summary\">Les applis utilisant Play Asset Delivery téléchargeront du contenu additionnel en se basant sur les informations de l\\'appareil actuellement utilisé.</string>\n    <string name=\"games_achievement_list_title\">Réussites</string>\n    <string name=\"games_achievements_empty_text\">Pas de réussites pour ce jeu</string>\n    <string name=\"games_api_access_denied\">Pas de compte sur cet appareil pouvant accéder aux APIs Games</string>\n    <string name=\"games_achievement_unlocked_content_description\">déverrouillée</string>\n    <string name=\"games_achievement_extra_text\">%1$s XP</string>\n    <string name=\"games_leaderboard_empty_text\">Pas de classements pour ce jeu</string>\n    <string name=\"games_leaderboard_list_title\">Classements</string>\n    <string name=\"games_leaderboards_score_label\">Score : %1$s</string>\n    <string name=\"games_snapshot_empty_text\">Aucune sauvegarde de jeu enregistrée</string>\n    <string name=\"games_snapshot_delete_btn_text\">supprimer</string>\n    <string name=\"games_snapshot_choose_btn_text\">choisir</string>\n    <string name=\"games_delete_snapshot_dialog_title\">Supprimer la sauvegarde de jeu</string>\n    <string name=\"games_delete_snapshot_dialog_cancel\">Annuler</string>\n    <string name=\"games_delete_snapshot_dialog_ok\">OK</string>\n    <string name=\"games_delete_snapshot_error\">Échec de la suppression, veuillez réessayer plus tard</string>\n    <string name=\"games_delete_snapshot_dialog_message\">Êtes vous sur de vouloir supprimer cette sauvegarde de jeu ?</string>\n    <string name=\"games_achievement_locked_content_description\">verrouillée</string>\n    <string name=\"games_leaderboard_score_empty_text\">Incroyable ! Il n\\'y a pas de meilleurs scores publics pour ce jeu.</string>\n    <string name=\"pref_vending_licensing_split_install_summary\">Autoriser les applis à télécharger et installer des composants additionnels</string>\n    <string name=\"camera_permission_dialog_title\">Accès à la caméra nécessaire</string>\n    <string name=\"pref_vending_split_install_switch\">Installation à la demande de composants</string>\n    <string name=\"pref_vending_feature_delivery\">Google Play Feature Delivery</string>\n    <string name=\"service_name_work_profile\">Profil professionnel</string>\n    <string name=\"pref_workprofile_intro\">La création d\\'un profil professionnel pour votre entreprise ou établissement peut nécessiter de se connecter à Google pour activer le téléchargement d\\'applis pour ce profil.</string>\n    <string name=\"pref_workprofile_create_account\">Autoriser la configuration d\\'un profil professionnel</string>\n    <string name=\"pref_workprofile_disclaimer\">Il est de votre responsabilité d\\'assurer que votre utilisation de microG est conforme aux politiques d\\'entreprise. Les fonctionnalités de microG sont fournies du mieux possible sans pouvoir garantir le résultat attendu.</string>\n    <string name=\"barcode_scanner_brand\">Scanné par microG pour %1$s</string>\n    <string name=\"camera_permission_dialog_button\">OK</string>\n    <string name=\"camera_permission_dialog_message\">Les services microG ont besoin d\\'accéder à votre caméra pour scanner un code pour %1$s.\\n\\nPour cela, accordez aux services microG la permission d\\'accéder à votre caméra dans Paramètres.</string>\n    <string name=\"credentials_assisted_signin_add_account\">Ajouter compte</string>\n    <string name=\"credentials_assisted_choose_account_error_tips\">Anomalie dans le compte</string>\n    <string name=\"auth_action_reauth_notification_title\">Action requise sur le compte</string>\n    <string name=\"pref_auth_two_step_verification_title\">Recevoir les prompts de vérification en deux étapes</string>\n    <string name=\"pref_auth_two_step_verification_summary\">Quand activé, l\\'appareil peut recevoir les prompts de vérification en deux étapes de Google (Cloud Messaging est requis).</string>\n    <string name=\"pref_game_accounts_title\">Comptes Google Jeux</string>\n    <string name=\"pref_auto_create_player\">Autoriser l\\'enregistrement de comptes Play Jeux</string>\n    <string name=\"games_change_per_game_title\">Changer le compte en fonction du jeu</string>\n    <string name=\"games_change_per_game_description\">Changer de compte pour un jeu ou se déconnecter peut effacer votre progression et les paramètres du jeu.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_title\">Choisir une option pour le nouveau compte par défaut</string>\n    <string name=\"games_state_description_signed_out\">Déconnecté</string>\n    <string name=\"games_state_description_delete\">Supprimer</string>\n    <string name=\"games_change_button_text\">Changer</string>\n    <string name=\"games_change_default_account_section_title\">Changer le compte par défaut pour les jeux</string>\n    <string name=\"games_change_default_account_description\">Compte par défaut : %1$s</string>\n    <string name=\"games_change_default_account_explanation\">Ce compte est utilisé pour vous connecter automatiquement, enregistrer votre progression et vos paramètres. Changer le compte par défaut ou se déconnecter peut effacer votre progression et vos paramètres pour les jeux auxquels vous avez joué.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_description\">Compte par défaut actuel :%1$s</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_title\">Changer le compte par défaut seulement pour les nouveaux jeux</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_description\">Vous ne perdrez pas l\\'accès aux progressions et paramètres des jeux auxquels vous avez joué. Mais vos progressions seront réparties sur plusieurs comptes.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_title\">Changer le compte par défaut pour tous les jeux</string>\n    <string name=\"pref_delete_game_account_data\">Supprimer les données Play Jeux</string>\n    <string name=\"pref_delete_game_account_data_summary\">Supprimer le compte Play Jeux et toutes les données &amp; Supprimer les données individuelles des jeux.</string>\n    <string name=\"pref_change_default_game_player\">Changer de compte pour les jeux</string>\n    <string name=\"pref_change_default_game_player_summary\">Changer le compte par défaut pour les jeux &amp; Changer de compte en fonction du jeu.</string>\n    <string name=\"pref_allow_upload_game_played\">Autoriser l\\'envoi du statut \\\"en cours de jeu\\\"</string>\n    <string name=\"pref_allow_upload_game_played_summary\">Si désactivé, le jeu ne rapportera pas le statut \\\"en cours de jeu\\\" après connexion, et certains jeux pourraient échouer à se connecter.</string>\n    <string name=\"games_popup_signin_welcome\">Salut, %1$s</string>\n    <string name=\"pref_auto_create_player_intro\">Lorsque vous jouez à des jeux, vous devez utiliser un compte Play Jeux pour vous connecter et enregistrer les fonctions liées au jeu, telles que les réalisations, les classements, les archives, etc. Après la désactivation, les comptes Google qui ne sont pas liés à un compte Play Jeux ne seront pas automatiquement enregistrés et le jeu ne pourra pas se connecter et jouer.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_description\">Vous risquez de perdre l\\'accès à votre progression et aux paramètres des jeux auxquels vous avez joué. Nous redémarrerons le jeu pour appliquer vos modifications.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_title\">Déconnectez-vous de tous les jeux</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_description\">Vous risquez de perdre l\\'accès à votre progression et aux paramètres des jeux auxquels vous avez joué. Nous redémarrerons le jeu pour appliquer vos modifications.</string>\n    <string name=\"games_change_per_game_dialog_title\">Sélectionnez une option pour ce jeu</string>\n    <string name=\"games_change_per_game_dialog_description\">Changer de compte ou se déconnecter peut réinitialiser votre progression et vos paramètres du jeu</string>\n    <string name=\"games_change_per_game_dialog_option_use_player\">Utilisez %1$s</string>\n    <string name=\"games_change_per_game_dialog_option_use_player_snackbar_success_message\">Vous serez connecté à ce jeu avec %1$s</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out\">Se déconnecter</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out_snackbar_success_message\">Vous êtes maintenant déconnecté de ce jeu</string>\n    <string name=\"games_change_sign_out_of_all_games_snackbar_success_message\">Vous êtes maintenant déconnecté de tous les jeux</string>\n    <string name=\"games_change_default_account_for_all_games_snackbar_success_message\">Vous serez connecté à tous les jeux avec %1$s</string>\n    <string name=\"games_change_default_account_for_new_games_snackbar_success_message\">Vous serez connecté à de nouveaux jeux avec %1$s</string>\n    <string name=\"games_account_display_content\">Compte courant : %1$s</string>\n    <string name=\"games_delete_profile_header\">Supprimer le compte Play Jeux et toutes les données</string>\n    <string name=\"games_delete_profile_explanation\">Supprimez définitivement votre compte Google Play Jeux, vos XP et toutes les données de votre profil. Cette action pourrait également supprimer vos scores, votre progression (parties sauvegardées) et les paramètres des jeux auxquels vous avez joué.</string>\n    <string name=\"games_delete_profile_button\">Supprimer définitivement</string>\n    <string name=\"games_delete_game_data_header\">Supprimer les données de jeu individuelles</string>\n    <string name=\"games_delete_game_data_explanation\">Vous pouvez supprimer définitivement les données individuelles des jeux auxquels vous avez joué sur Google Play Jeux. Cette action supprime vos scores, votre progression (parties sauvegardées) et les paramètres du jeu sélectionné.</string>\n    <string name=\"games_delete_profile_dialog_title\">Êtes-vous sûr de vouloir supprimer ce compte ?</string>\n    <string name=\"games_delete_profile_explanation_with_gamer_name\">Supprimez définitivement votre compte Google Play Jeux pour le joueur <b>%1$s</b> (<b>%2$s</b>), vos XP et toutes les données de profil. Cette action peut également supprimer vos scores, votre progression (parties sauvegardées) et les paramètres des jeux auxquels vous avez joué.</string>\n    <string name=\"games_delete_profile_dialog_message\">Cette action ne peut pas être annulée.</string>\n    <string name=\"games_delete_profile_fail\">Impossible de supprimer votre profil. Veuillez réessayer ultérieurement.</string>\n    <string name=\"games_delete_game_data_confirm_dialog_title\">Supprimer les données pour %1$s</string>\n    <string name=\"games_delete_game_data_confirm_dialog_message\">La suppression définitive de vos données pour %1$s supprimera vos scores, votre progression (parties sauvegardées) et vos paramètres de jeu dans Google Play Jeux.</string>\n    <string name=\"service_name_google_location_sharing\">Partage de position Google</string>\n    <string name=\"location_sharing_description\">Gérez votre partage de position en temps réel sur les applications et services Google à partir de cet appareil</string>\n    <string name=\"location_sharing_learn_more\">En savoir plus sur le partage de localisation</string>\n    <string name=\"location_sharing_switch_text\">Utiliser le partage de localisation</string>\n    <string name=\"location_sharing_turn_off_notify_hint\">Si vous désactivez le partage de position pour cet appareil, les personnes avec lesquelles vous partagez ne seront pas averties.</string>\n    <string name=\"location_sharing_off_previous_hint\">Seul votre dernier emplacement partagé sera disponible jusqu\\'à ce que vous le réactiviez.</string>\n    <string name=\"location_sharing_disabled\">Aucun partage de localisation actif pour ce compte</string>\n    <string name=\"location_sharing_turn_on_hint\">Une fois que vous avez commencé à partager votre position depuis une application ou un service Google, vous pouvez gérer le partage de position ici.\\n\\nPour commencer à partager votre position, accédez à Google Maps ou Family Link.</string>\n    <string name=\"location_sharing_turn_off_title\">Désactiver le partage de position</string>\n    <string name=\"location_sharing_turn_off_hint\">Vous pourriez continuer à partager votre position depuis d\\'autres appareils connectés au même compte Google ou depuis des applications autres que Google. Vérifiez vos paramètres de partage de position, le cas échéant.\\n\\nLes personnes avec lesquelles vous partagez vos données continueront de voir votre dernière position partagée.</string>\n    <string name=\"location_sharing_turn_off_cancel\">Continuer</string>\n    <string name=\"location_sharing_turn_off_confirm\">Éteindre</string>\n    <string name=\"location_sharing_confirm_dialog_title\">Activer le partage de localisation</string>\n    <string name=\"location_sharing_confirm_dialog_text\">Les personnes avec lesquelles vous partagez votre position peuvent toujours voir :\\n· Votre nom et votre photo\\n· La position récente de votre appareil, même lorsque vous n\\'utilisez pas de service Google\\n· Le niveau de batterie de votre appareil et s\\'il est en charge\\n· Vos heures d\\'arrivée et de départ, si elles ajoutent une notification de partage de position</string>\n    <string name=\"family_management_title\">Famille</string>\n    <string name=\"family_management_retry\">Réessayer</string>\n    <string name=\"family_management_load_error\">Le chargement du contenu a échoué</string>\n    <string name=\"family_management_toolbar_back\">Retour</string>\n    <string name=\"family_management_toolbar_more\">Plus</string>\n    <string name=\"family_management_exit_family_group\">Quitter le groupe familial</string>\n    <string name=\"family_management_delete_family_group\">Supprimer un groupe familial</string>\n    <string name=\"family_management_leave_family_password_title\">Confirmer le mot de passe pour quitter le groupe familial</string>\n    <string name=\"family_management_delete_family_password_title\">Confirmer le mot de passe pour supprimer un groupe familial</string>\n    <string name=\"family_management_remove_member_password_title\">Confirmer le mot de passe pour supprimer %s</string>\n    <string name=\"family_management_invite_family_member\">Inviter les membres de la famille</string>\n    <string name=\"family_management_invite_slots_left\">%1$d invitations restantes</string>\n    <string name=\"family_management_cancel_invite\">Annuler l\\'invitation</string>\n    <string name=\"family_management_cancel_invite_success\">Annuler l\\'invitation avec succès</string>\n    <string name=\"family_management_cancel_invite_error\">Problème lors de l\\'annulation de l\\'invitation. Veuillez réessayer.</string>\n    <string name=\"family_management_remove_member\">Supprimer un membre</string>\n    <string name=\"family_management_member_removed_success\">%s a été supprimé de votre groupe familial</string>\n    <string name=\"family_management_member_remove_failed\">Problème lors de la suppression de %s. Veuillez réessayer.</string>\n    <string name=\"family_management_leave_family_error_message\">Problème lors de la sortie du groupe familial. Veuillez réessayer.</string>\n    <string name=\"family_management_exist_group_success\">Vous avez quitté votre groupe familial…</string>\n    <string name=\"family_management_delete_group_success\">Groupe familial supprimé</string>\n    <string name=\"family_management_delete_group_failure\">Échec de la suppression du groupe résidentiel</string>\n    <string name=\"family_management_delete_group_cancel\">Annuler</string>\n    <string name=\"family_management_delete_group_confirm\">OK</string>\n    <string name=\"family_management_input_pwd\">Veuillez entrer votre mot de passe</string>\n    <string name=\"family_management_invite_sent_date_format\">Invitation envoyée le %s</string>\n    <string name=\"family_management_invite_send\">Invitation envoyée</string>\n    <string name=\"family_management_pwd_error\">Mot de passe incorrect, veuillez le saisir à nouveau</string>\n    <string name=\"pref_app_install_settings_title\">Paramètres du programme d\\'installation de l\\'application</string>\n    <string name=\"pref_app_install_switch_title\">Autoriser l\\'installation de l\\'application</string>\n    <string name=\"pref_app_install_other_apps_note\">L\\'autorisation permet l\\'installation d\\'applications fournies à partir d\\'autres sources.</string>\n    <string name=\"pref_app_install_permission_instruction\">Pour garantir que vos applications installées fonctionnent correctement, veuillez autoriser microG Companion à installer des applications téléchargées à partir d\\'autres sources.</string>\n    <string name=\"prefcat_app_install_list_title\">Applications utilisant App Installer</string>\n    <string name=\"service_name_device_attestation\">Certification de l\\'appareil</string>\n    <string name=\"prefcat_device_attestation_apps_title\">Applis utilisant la certification de l\\'appareil</string>\n    <string name=\"pref_device_attestation_app_allow_requests_title\">Autoriser requêtes</string>\n    <string name=\"pref_device_attestation_app_allow_requests_summary\">Autorise l\\'appli à demander la certification de l\\'appareil</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-ga/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"permission_service_all_label\">Gach seirbhís Google</string>\n    <string name=\"permission_service_all_description\">Ligeann sé don aip rochtain a fháil ar gach seirbhís Google trí aon chuntas Google a bhaineann leis.</string>\n    <string name=\"permission_service_android_label\">Seirbhísí Android</string>\n    <string name=\"permission_service_android_description\">Ligeann sé don aip rochtain a fháil ar sheirbhísí Android trí aon chuntas Google a bhaineann leis.</string>\n    <string name=\"permission_service_adsense_label\">AdSense</string>\n    <string name=\"permission_service_adsense_description\">Ligeann sé don aip rochtain a fháil ar AdSense trí aon chuntas Google a bhaineann leis.</string>\n    <string name=\"permission_service_adwords_label\">AdWords</string>\n    <string name=\"permission_service_adwords_description\">Ligeann sé don aip rochtain a fháil ar AdWords trí aon chuntas Google a bhaineann leis.</string>\n    <string name=\"permission_service_ah_label\">Google App Engine</string>\n    <string name=\"permission_service_blogger_label\">Bhlagadóir</string>\n    <string name=\"permission_service_ah_description\">Ligeann sé don aip rochtain a fháil ar Google App Engine trí aon chuntas Google a bhaineann leis.</string>\n    <string name=\"permission_service_cl_label\">Google Calendar</string>\n    <string name=\"permission_service_cp_label\">Teagmhálaithe</string>\n    <string name=\"permission_service_cp_description\">Ligeann sé don aip rochtain a fháil ar Theagmhálaithe trí aon chuntas Google a bhaineann leis.</string>\n    <string name=\"permission_service_dodgeball_label\">Dodgeball</string>\n    <string name=\"permission_service_finance_label\">Google Finance</string>\n    <string name=\"permission_service_finance_description\">Ligeann sé don aip rochtain a fháil ar Google Finance trí aon chuntas Google a bhaineann leis.</string>\n    <string name=\"permission_service_groups2_description\">Ligeann sé don aip rochtain a fháil ar Ghrúpaí Google trí aon chuntas Google a bhaineann leis.</string>\n    <string name=\"permission_service_knol_label\">Knol</string>\n    <string name=\"permission_service_knol_description\">Ligeann sé don aip rochtain a fháil ar Knol trí aon chuntas Google a bhaineann leis.</string>\n    <string name=\"permission_service_lh2_label\">Picasa albam gréasáin</string>\n    <string name=\"permission_service_lh2_description\">Ligeann sé don aip rochtain a fháil ar Picasa Web Albums trí aon chuntas Google a bhaineann leis.</string>\n    <string name=\"permission_service_local_label\">Google Maps</string>\n    <string name=\"permission_service_local_description\">Ligeann sé don aip rochtain a fháil ar Google Maps trí aon chuntas Google a bhaineann leis.</string>\n    <string name=\"permission_service_mail_label\">Google Mail</string>\n    <string name=\"permission_service_mail_description\">Ligeann sé don aip rochtain a fháil ar Google Mail trí aon chuntas Google a bhaineann leis.</string>\n    <string name=\"permission_service_news_label\">Google News</string>\n    <string name=\"permission_service_news_description\">Ligeann sé don aip rochtain a fháil ar Google News trí aon chuntas Google a bhaineann leis.</string>\n    <string name=\"permission_service_notebook_label\">Google Notebook</string>\n    <string name=\"permission_service_notebook_description\">Ligeann sé don aip rochtain a fháil ar Google Notebook trí aon chuntas Google a bhaineann leis.</string>\n    <string name=\"permission_service_print_description\">Ligeann sé don aip Cuardach Leabhar Google a rochtain trí aon chuntas Google a bhaineann leis.</string>\n    <string name=\"permission_service_sierra_label\">Cuntais Google Checkout</string>\n    <string name=\"permission_service_sierra_description\">Ligeann sé don aip rochtain a fháil ar chuntais Google Checkout trí aon chuntas Google a bhaineann leis.</string>\n    <string name=\"permission_service_sierraqa_label\">Cuntais QA Google Checkout</string>\n    <string name=\"permission_service_sierraqa_description\">Ligeann sé don aip rochtain a fháil ar chuntais Google Checkout QA trí aon chuntas Google a bhaineann leis.</string>\n    <string name=\"permission_service_sierrasandbox_label\">Cuntais Bhosca Gainimh Google Checkout</string>\n    <string name=\"permission_service_sierrasandbox_description\">Ligeann sé don aip rochtain a fháil ar chuntais Bhosca Gainimh Google Checkout trí aon chuntas Google a bhaineann leis.</string>\n    <string name=\"permission_service_sitemaps_label\">Uirlisí Stiúrthóir Gréasáin Google</string>\n    <string name=\"permission_service_speech_label\">Cuardach Gutha</string>\n    <string name=\"permission_service_speech_description\">Ligeann sé don aip Cuardach Gutha a rochtain trí aon chuntas Google a bhaineann leis.</string>\n    <string name=\"permission_service_speechpersonalization_description\">Ligeann sé don aip rochtain a fháil ar Aitheantas Urlabhra Pearsantaithe trí aon chuntas Google bainteach.</string>\n    <string name=\"permission_service_wifi_label\">Google Wi-Fi</string>\n    <string name=\"permission_service_wifi_description\">Ligeann sé don aip rochtain a fháil ar Google Wi-Fi trí aon chuntas Google a bhaineann leis.</string>\n    <string name=\"permission_service_wise_label\">Google Spreadsheets</string>\n    <string name=\"permission_service_wise_description\">Ligeann sé don aip rochtain a fháil ar Scarbhileoga Google trí aon chuntas Google a bhaineann leis.</string>\n    <string name=\"permission_service_writely_label\">Google Docs</string>\n    <string name=\"permission_service_writely_description\">Ligeann sé don aip rochtain a fháil ar Google Docs trí aon chuntas Google a bhaineann leis.</string>\n    <string name=\"permission_service_youtube_label\">YouTube</string>\n    <string name=\"permission_service_youtube_description\">Ligeann sé don aip rochtain a fháil ar YouTube trí aon chuntas Google a bhaineann leis.</string>\n    <string name=\"permission_service_YouTubeUser_label\">Ainmneacha úsáideora YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_activity\">Féach ar stair ghníomhaíochta do Google Apps</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.buyer\">Bainistigh do chumraíocht chuntais cheannaitheora Ad Exchange</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller.readonly\">Féach ar do shonraí Ad Exchange</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller\">Féach ar agus bainistigh do shonraí Ad Exchange</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsensehost\">Féach ar agus bainistigh do shonraí óstaigh AdSense agus cuntais ghaolmhara</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense.readonly\">Féach ar do shonraí AdSense</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense\">Féach ar agus bainistigh do shonraí AdSense</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics.readonly\">Féach ar do shonraí Google Analytics</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics\">Féach ar agus bainistigh do shonraí Google Analytics</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_androidpublisher\">Rochtain ar Fhorbróir Android Google Play</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appengine.admin\">Raon feidhme admin inneall aip.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order.readonly\">Chomh maith leis an raon feidhme OAuth léite/scríobh iomlán, bain úsáid as an raon feidhme OAuth inléite amháin agus sonraí an chustaiméara á aisghabháil.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps_reporting_audit.readonly\">Rochtain ar an Admin Audit API ReadOnly</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appstate\">Scóip chun an tseirbhís App State a úsáid.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery.readonly\">Féach ar do shonraí in Google BigQuery</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery\">Féach ar agus bainistigh do shonraí in Google BigQuery</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger\">Bainistigh do chuntas Blogger</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger.readonly\">Féach ar do chuntas Blogger</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_books\">Bainistigh do leabhair</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate\">Féach ar agus bainistigh do phoist Google Maps Coordinate</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.full_control\">Bainistigh do shonraí agus ceadanna in Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_only\">Féach ar do shonraí in Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_write\">Bainistigh do shonraí in Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_dfareporting\">Féach ar agus bainistigh tuairiscí DoubleClick for Advertisers</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.metadata.readonly\">Féach ar mheiteashonraí le haghaidh comhad agus doiciméad i do Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.readonly\">Féach ar na comhaid agus na doiciméid i do Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.scripts\">Athraigh iompar do scripteanna Google Apps Script</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive\">Féach ar agus bainistigh na comhaid agus na doiciméid i do Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables\">Bainistigh do Táblaí Comhleá</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables.readonly\">Féach ar do Táblaí Comhleá</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan\">Bainistigh do shonraí GAN</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gcm_for_chrome\">CloudMessaging le haghaidh chrome</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_glass.timeline\">Scóip amlíne gloine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.modify\">Gach oibríocht léite/scríofa ach amháin snáitheanna agus teachtaireachtaí a scriosadh go buan láithreach, ag seachaint Bruscar.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.readonly\">Léigh na hacmhainní go léir agus a meiteashonraí - gan aon oibríochtaí scríbhneoireachta.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.best\">Bainistigh do shuíomh agus do stair suímh is fearr atá ar fáil</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.city\">Bainistigh do shuíomh ar leibhéal na cathrach agus do stair suímh</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.best\">Bainistigh do shuíomh is fearr atá ar fáil</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.city\">Bainistigh do shuíomh ar leibhéal na cathrach</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine\">Féach ar agus bainistigh do shonraí Google Maps Engine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine.readonly\">Féach ar do shonraí Google Maps Engine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mobilemaps.firstparty\">Féach ar agus bainistigh do Google Maps le haghaidh eispéireas soghluaiste</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut\">Bainistigh do ghníomhaíocht Orkut</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut.readonly\">Féach ar do shonraí Orkut</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.login\">Bíodh d\\'ainm, faisnéis bhunúsach agus liosta de na daoine a bhfuil tú nasctha leo ar Google+ ar eolas agat</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.me\">Bíodh a fhios agat cé tú féin ar Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_prediction\">Bainistigh do shonraí san Google Prediction API</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_shoppingapi\">Féach ar shonraí do tháirge</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification\">Bainistigh liosta na suíomhanna agus na bhfearann a rialaíonn tú</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification.verify_only\">Bainistigh do fhíoruithe suímh nua le Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_structuredcontent\">Léigh/scríobh rochtain ar Shopping Content API.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue.consumer\">Ith Tascanna ó do Thascanna</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue\">Bainistigh do Thascanna</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks\">Bainistigh do thascanna</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks.readonly\">Féach ar do thascanna</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_urlshortener\">Bainistigh do URLanna gearra goo.gl</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.profile\">Féach ar fhaisnéis bhunúsach faoi do chuntas</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.readonly\">Féach ar do chuntas YouTube</string>\n    <string name=\"permission_service_blogger_description\">Ligeann sé don aip rochtain a fháil ar Blogger trí aon chuntas Google a bhaineann leis.</string>\n    <string name=\"permission_service_cl_description\">Ligeann sé don aip rochtain a fháil ar Google Calendar trí aon chuntas Google a bhaineann leis.</string>\n    <string name=\"permission_service_dodgeball_description\">Ligeann sé don aip rochtain a fháil ar Dodgeball trí aon chuntas Google a bhaineann leis.</string>\n    <string name=\"permission_service_health_label\">Sláinte Google</string>\n    <string name=\"permission_service_health_description\">Ligeann sé don aip rochtain a fháil ar Google Health trí aon chuntas Google a bhaineann leis.</string>\n    <string name=\"permission_service_gbase_label\">Google Base</string>\n    <string name=\"permission_service_ig_label\">iGoogle</string>\n    <string name=\"permission_service_grandcentral_label\">Google Voice</string>\n    <string name=\"permission_service_grandcentral_description\">Ligeann sé don aip rochtain a fháil ar Google Voice trí aon chuntas Google a bhaineann leis.</string>\n    <string name=\"permission_service_ig_description\">Ligeann sé don aip rochtain a fháil ar iGoogle trí aon chuntas Google a bhaineann leis.</string>\n    <string name=\"permission_service_gbase_description\">Ligeann sé don aip rochtain a fháil ar Google Base trí aon chuntas Google a bhaineann leis.</string>\n    <string name=\"permission_service_jotspot_label\">JotSpot</string>\n    <string name=\"permission_service_jotspot_description\">Ligeann sé don aip rochtain a fháil ar JotSpot trí aon chuntas Google a bhaineann leis.</string>\n    <string name=\"permission_service_orkut_label\">Orkut</string>\n    <string name=\"permission_service_orkut_description\">Ligeann sé don aip rochtain a fháil ar Orkut trí aon chuntas Google a bhaineann leis.</string>\n    <string name=\"permission_service_print_label\">Cuardach Leabhar Google</string>\n    <string name=\"permission_service_sitemaps_description\">Ligeann sé don aip rochtain a fháil ar Google Webmaster Tools trí aon chuntas Google a bhaineann leis.</string>\n    <string name=\"permission_service_speechpersonalization_label\">Aitheantas Urlabhra Pearsanta</string>\n    <string name=\"permission_service_talk_description\">Ligeann sé don aip rochtain a fháil ar Google Talk trí aon chuntas Google a bhaineann leis.</string>\n    <string name=\"permission_service_talk_label\">Google Talk</string>\n    <string name=\"permission_service_YouTubeUser_description\">Ligeann sé don aip rochtain a fháil ar ainm(neacha) úsáideora YouTube a úsáidtear le haon chuntas Google a bhaineann leis.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.migration\">Léigh agus scríobh rochtain ar Groups Migration API.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.licensing\">Léigh/scríobh rochtain ar Ceadúnas Bainisteoir API.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.settings\">Féach ar agus bainistigh socruithe Grúpa Aipeanna Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order\">I gcás riarthóirí athdhíoltóirí agus úsáideoirí, léann/scríobh rochtain agus iad ag tástáil i mbosca gainimh an API, nó léigh/scríobh rochtain agus iad ag glaoch go díreach ar oibríocht API.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan.readonly\">Féach ar do shonraí GAN</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute.readonly\">Féach ar d\\'acmhainní Google Compute Engine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar\">Bainistigh d\\'fhéilirí</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate.readonly\">Féach ar do phoist Google Coordinate</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.apps.readonly\">Féach ar d\\'aipeanna Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar.readonly\">Féach ar d\\'fhéilirí</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.file\">Féach ar agus bainistigh comhaid Google Drive a d\\'oscail nó a chruthaigh tú leis an aip seo</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_cloudprint\">Féach ar agus bainistigh do shonraí priontála scamall Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute\">Féach ar agus bainistigh d\\'acmhainní Google Compute Engine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.install\">Scóip speisialta a úsáidtear chun ligean d\\'úsáideoirí suiteáil app a cheadú</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.appdata\">Ceadaíonn rochtain ar an bhfillteán Sonraí Feidhmchláir</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase.readonly\">Féach ar do chuntas Freebase</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase\">Sínigh isteach ar Freebase le do chuntas</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_games\">Scóip chun sonraí a rochtain ó Google Play Games.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.compose\">Cruthaigh, léigh, nuashonraigh agus scrios dréachtaí. Seol teachtaireachtaí agus dréachtaí.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube\">Bainistigh do chuntas YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tracks\">Google Maps Tracks API, Ceadaíonn an raon feidhme seo rochtain a léamh agus a scríobh ar shonraí do thionscadail.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.email\">Féach ar do sheoladh ríomhphoist</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtubepartner\">Féach ar agus bainistigh do shócmhainní agus inneachar gaolmhar ar YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.upload\">Bainistigh d\\'fhíseáin YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics_monetary.readonly\">Féach ar thuairiscí airgeadaíochta YouTube Analytics do d’inneachar YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics.readonly\">Féach ar thuairiscí YouTube Analytics do d’inneachar YouTube</string>\n    <string name=\"permission_service_groups2_label\">Google Groups</string>\n    <string name=\"perm_activity_recognition_description\">Ligeann sé d’aip nuashonruithe tréimhsiúla ar do leibhéal gníomhaíochta a fháil ó Google, mar shampla, má tá tú ag siúl, ag tiomáint, ag rothaíocht nó ar do stad.</string>\n    <string name=\"perm_activity_recognition_label\">Aitheantas gníomhaíochta</string>\n</resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-ga/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <plurals name=\"pref_unifiednlp_summary\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> inneall cumraithe</item>\n        <item quantity=\"two\"><xliff:g example=\"3\">%1$d</xliff:g> cúláin cumraithe</item>\n        <item quantity=\"few\"><xliff:g example=\"3\">%1$d</xliff:g> cúláin cumraithe</item>\n        <item quantity=\"many\"><xliff:g example=\"3\">%1$d</xliff:g> cúláin cumraithe</item>\n        <item quantity=\"other\"><xliff:g example=\"3\">%1$d</xliff:g> cúláin cumraithe</item>\n    </plurals>\n    <plurals name=\"gcm_registered_apps_counter\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> Aip chláraithe</item>\n        <item quantity=\"two\"><xliff:g example=\"123\">%1$d</xliff:g> Aipeanna cláraithe</item>\n        <item quantity=\"few\"><xliff:g example=\"123\">%1$d</xliff:g> Aipeanna cláraithe</item>\n        <item quantity=\"many\"><xliff:g example=\"123\">%1$d</xliff:g> Aipeanna cláraithe</item>\n        <item quantity=\"other\"><xliff:g example=\"123\">%1$d</xliff:g> Aipeanna cláraithe</item>\n    </plurals>\n    <plurals name=\"cond_perm_summary\">\n        <item quantity=\"one\">Ní thugtar cead a theastaíonn le haghaidh feidhmiúlacht cheart Sheirbhísí MicroG.</item>\n        <item quantity=\"two\">Ní dheonaítear na ceadanna a theastaíonn le haghaidh feidhmiúlacht cheart Sheirbhísí MicroG.</item>\n        <item quantity=\"few\">Ní dheonaítear na ceadanna a theastaíonn le haghaidh feidhmiúlacht cheart Sheirbhísí MicroG.</item>\n        <item quantity=\"many\">Ní dheonaítear na ceadanna a theastaíonn le haghaidh feidhmiúlacht cheart Sheirbhísí MicroG.</item>\n        <item quantity=\"other\">Ní dheonaítear na ceadanna a theastaíonn le haghaidh feidhmiúlacht cheart Sheirbhísí MicroG.</item>\n    </plurals>\n    <plurals name=\"cond_perm_action\">\n        <item quantity=\"one\">Iarr cead ar iarraidh</item>\n        <item quantity=\"two\">Iarr ceadanna in easnamh</item>\n        <item quantity=\"few\">Iarr ceadanna in easnamh</item>\n        <item quantity=\"many\">Iarr ceadanna in easnamh</item>\n        <item quantity=\"other\">Iarr ceadanna in easnamh</item>\n    </plurals>\n</resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-ga/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=\"gms_app_name\">Seirbhísí microG</string>\n    <string name=\"gms_settings_name\">Socruithe microG</string>\n    <string name=\"gms_settings_summary\">Socraigh seirbhísí microG.</string>\n    <string name=\"account_manager_title\">Bainisteoir Cuntais Google</string>\n    <string name=\"ask_scope_permission_title\">Ba mhaith le <xliff:g example=\"F-Droid\">%1$s</xliff:g>:</string>\n    <string name=\"ask_service_permission_title\">Ba mhaith le <xliff:g example=\"F-Droid\">%1$s</xliff:g> úsáid a bhaint as:</string>\n    <string name=\"auth_sign_in\">Sínigh isteach</string>\n    <string name=\"auth_connecting\">Tá do ghléas ag bunú nasc le freastalaithe Google chun tú a shíniú isteach.\n\\n\n\\nD\\'fhéadfadh sé seo cúpla soicind a thógáil.</string>\n    <string name=\"auth_before_connect\">Tá aip ar do ghléas ag iarraidh síniú isteach i gcuntas Google.\\n\\nMás rud é gur d\\'aon ghnó a rinneadh é seo, bain úsáid as an gcnaipe <b>Sínigh isteach</b> chun ceangal le leathanach síniú isteach Google, mura ndearna, brúigh <b>Cealaigh</b> chun filleadh ar an aip a chuir an dialóg seo faoi deara.</string>\n    <string name=\"signin_picker_title\">Roghnaigh cuntas</string>\n    <string name=\"signin_picker_add_account_label\">Cuir cuntas eile leis</string>\n    <string name=\"auth_package_override_request_message\">Tá <b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> ag iarraidh rochtain a fháil ar do chuntas amhail is dá mba le <b><xliff:g example=\"F-Droid\">%2$s</xliff:g> <xliff:g example=\"F-Droid Inc.\">%3$s</xliff:g></b> a bhí sé. D’fhéadfadh sé seo rochtain phribhléideach a thabhairt dó ar do chuntas.</string>\n    <string name=\"signin_confirm_title\">Lig duit síniú isteach ar <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"signin_subtext_sharing\">Chun leanúint ar aghaidh, roinnfidh microG ainm, seoladh ríomhphoist agus pictiúr próifíle do Chuntas Google le <xliff:g example=\"F-Droid\">%1$s</xliff:g>.</string>\n    <string name=\"service_name_vending\">Seirbhísí Play Store</string>\n    <string name=\"games_title\">Cluichí Google Play</string>\n    <string name=\"games_info_content\">Chun Cluichí Súgartha a úsáid ní mór an aip Google Play Games a shuiteáil. D\\'fhéadfadh an t-iarratas leanúint ar aghaidh gan Cluichí Imeartha, ach is féidir go n-iompródh sé é féin gan choinne.</string>\n    <string name=\"games_info_title\">Ba mhaith le <xliff:g example=\"F-Droid\">%1$s</xliff:g> Play Games a úsáid</string>\n    <string name=\"pick_place_title\">Roghnaigh áit</string>\n    <string name=\"pick_place_desc\">Níl roghnóir áite ar fáil go fóill.</string>\n    <string name=\"lacking_permission_toast\">Seirbhísí microG: Níl cead <xliff:g example=\"rochtain iomlán líonra a bheith agat\">%1$s</xliff:g></string>\n    <string name=\"self_check_cat_gms_packages\">Pacáistí suiteáilte</string>\n    <string name=\"self_check_cat_system\">Córas</string>\n    <string name=\"self_check_name_fake_sig_perm\">Tá tacaíocht spoofing sínithe ag an gcóras:</string>\n    <string name=\"self_check_name_app_installed\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> suiteáilte: </string>\n    <string name=\"self_check_resolution_app_installed\">Suiteáil an feidhmchlár <xliff:g example=\"F-Droid\">%1$s</xliff:g> nó feidhmchlár comhoiriúnach. Seiceáil le do thoil na doiciméid a bhfuil feidhmchláir ag luí orthu.</string>\n    <string name=\"self_check_name_correct_sig\">Tá síniú ceart ag <xliff:g example=\"F-Droid\">%1$s</xliff:g>: </string>\n    <string name=\"self_check_resolution_correct_sig\">Níl an suiteáil <xliff:g example=\"F-Droid\">%1$s</xliff:g> comhoiriúnach nó níl smúdáil sínithe gníomhach dó. Seiceáil na doiciméid ar a bhfuil feidhmchláir agus ROManna comhoiriúnach.</string>\n    <string name=\"prefs_account_privacy\">Faisnéis phearsanta &amp; príobháideacht</string>\n    <string name=\"pref_auth_trust_google_title\">Iontaobhas Google le haghaidh ceadanna app</string>\n    <string name=\"pref_auth_visible_title\">Ceadaigh d\\'fheidhmchláir cuntais a aimsiú</string>\n    <string name=\"prefs_account_security\">Síniú isteach &amp; slándáil</string>\n    <string name=\"pref_auth_strip_device_name_title\">Ainm an ghléis stiallacha le haghaidh fíordheimhnithe</string>\n    <string name=\"checkin_last_registration\">Clárúchán is déanaí: <xliff:g example=\"Inné, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"pref_gcm_confirm_new_apps_summary\">Fiafraigh sula gcláraíonn tú feidhmchlár nua chun fógraí brú a fháil</string>\n    <string name=\"pref_about_title\">Maidir le Seirbhísí microG</string>\n    <string name=\"pref_about_summary\">Eolas leagain agus leabharlanna úsáidte</string>\n    <string name=\"gcm_app_error_unregistering\">Earráid agus tú ag díchlárú</string>\n    <string name=\"pref_gcm_ping_interval\">Eatramh ping: <xliff:g shampla=\"10 nóiméad\">%1$s</xliff:g></string>\n    <string name=\"gcm_app_not_installed_anymore\">Níl sé suiteáilte a thuilleadh</string>\n    <string name=\"gcm_unregister_app\">Neamhchlárú</string>\n    <string name=\"gcm_last_message_at\">An teachtaireacht dheireanach: <xliff:g example=\"Inné, 02:20 PM\"> %1$s</xliff:g></string>\n    <string name=\"gcm_registered_since\">Cláraithe ó: <xliff:g example=\"Inné, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_unregister_confirm_title\">Díchláraigh <xliff:g example=\"F-Droid\">%1$s</xliff:g>\\?</string>\n    <string name=\"gcm_messages_counter\">Teachtaireachtaí: <xliff:g example=\"123\">%1$d</xliff:g> (<xliff:g sampla=\"12345\">%2$d</xliff:g> beart)</string>\n    <string name=\"gcm_network_state_connected\">Ceangailte ó <xliff:g example=\"2 uair ó shin\">%1$s</xliff:g></string>\n    <string name=\"gcm_allow_app_popup\">Ceadaigh do <xliff:g example=\"F-Droid\">%1$s</xliff:g> clárú le haghaidh fógraí brú?</string>\n    <string name=\"prefcat_safetynet_apps_title\">Feidhmchláir ag baint úsáide as SafetyNet</string>\n    <string name=\"menu_clear_recent_requests\">Glan iarratais le déanaí</string>\n    <string name=\"profile_name_native\">Dúchasach</string>\n    <string name=\"profile_name_real\">Fíor</string>\n    <string name=\"profile_name_user\">Saincheaptha: %s</string>\n    <string name=\"profile_name_auto\">Uathoibríoch: %s</string>\n    <string name=\"profile_name_system\">Córas: %s</string>\n    <string name=\"safetynet_last_run_at\">Úsáid dheireanach: <xliff:g example=\"Inné, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"pref_device_registration_serial_title\">Sraithuimhir</string>\n    <string name=\"pref_device_registration_import_custom_profile_summary\">Iompórtáil próifíl gléis ó chomhad</string>\n    <string name=\"pref_device_registration_select_profile_title\">Roghnaigh próifíl</string>\n    <string name=\"pref_device_registration_device_profile_category\">Próifíl gléis</string>\n    <string name=\"pref_safetynet_recent_uses\">Úsáidí le déanaí</string>\n    <string name=\"pref_safetynet_recent_attestation_summary\">Fianú: %s</string>\n    <string name=\"pref_safetynet_recent_recaptcha_summary\">ReCaptcha: %s</string>\n    <string name=\"pref_safetynet_recent_recaptcha_enterprise_summary\">Fiontar ReCaptcha: %s</string>\n    <string name=\"pref_safetynet_recent_copy_json\">Cóipeáil sonraí JSON JWS</string>\n    <string name=\"pref_safetynet_recent_advice\">Comhairle</string>\n    <string name=\"pref_safetynet_recent_eval_type\">Cineál meastóireachta</string>\n    <string name=\"pref_safetynet_recent_response_status\">Stádas freagartha</string>\n    <string name=\"pref_safetynet_recent_cat_response\">Sonraí freagartha</string>\n    <string name=\"credentials_assisted_signin_description\">Is féidir leat Sínigh isteach le Google a bhainistiú i do Chuntais Google.</string>\n    <string name=\"credentials_assisted_choose_account_label\">Roghnaigh cuntas</string>\n    <string name=\"credentials_assisted_choose_account_subtitle\">le leanúint ar aghaidh go %1$s</string>\n    <string name=\"credentials_assisted_signin_button_text_long\">Sínigh isteach le Google</string>\n    <string name=\"just_a_sec\">Just a sec …</string>\n    <string name=\"google_account_label\">Google</string>\n    <string name=\"ask_permission_tos\">Trí leanúint ar aghaidh, ligeann tú don aip seo agus do Google do chuid faisnéise a úsáid de réir a dtéarmaí seirbhíse agus a bpolasaithe príobháideachais faoi seach.</string>\n    <string name=\"sorry\">Tá brón orm…</string>\n    <string name=\"no_network_error_desc\">Níl nasc líonra agat.\n\\n\n\\nD\\'fhéadfadh sé seo a bheith ina fhadhb shealadach nó b\\'fhéidir nach gcuirfí do ghléas Android ar fáil le haghaidh seirbhísí sonraí. Bain triail eile as nuair atá tú ceangailte le líonra soghluaiste, nó ceangail le líonra Wi-Fi.</string>\n    <string name=\"auth_general_error_desc\">Bhí fadhb ann cumarsáid a dhéanamh le freastalaithe Google.\n\\n\n\\nBain triail eile as níos déanaí.</string>\n    <string name=\"perm_extended_access_label\">Rochtain bhreisithe ar sheirbhísí Google</string>\n    <string name=\"auth_finalize\">Tá do ghléas ag dul i dteagmháil le Google chun faisnéis a shábháil ar do chuntas.\n\\n\n\\nD\\'fhéadfadh sé seo cúpla nóiméad a thógáil.</string>\n    <string name=\"allow\">Ceadaigh</string>\n    <string name=\"deny\">Diúltaigh</string>\n    <string name=\"auth_notification_title\">Fíordheimhniú de dhíth</string>\n    <string name=\"signin_confirm_button_text\">Ceadaigh agus roinn</string>\n    <string name=\"signin_subtext_policy\">Sula n-úsáideann tú an feidhmchlár seo, déan athbhreithniú ar a %1$s agus %2$s.</string>\n    <string name=\"signin_subtext_policy_privacy\">Beartas príobháideachais</string>\n    <string name=\"signin_subtext_policy_terms\">téarmaí seirbhíse</string>\n    <string name=\"perm_status_broadcast_label\">éisteacht le craoltaí stádas inmheánach</string>\n    <string name=\"perm_gsf_read_gservices_label\">léigh cumraíocht seirbhíse Google</string>\n    <string name=\"perm_c2dm_receive_label\">éist le teachtaireachtaí C2DM</string>\n    <string name=\"perm_c2dm_send_label\">teachtaireachtaí C2DM a sheoladh chuig feidhmchláir eile</string>\n    <string name=\"perm_gtalk_svc_label\">teachtaireachtaí a mhalartú agus fógraí sioncronaithe a fháil ó fhreastalaithe Google</string>\n    <string name=\"perm_provision_label\">seirbhísí micreaG a sholáthar</string>\n    <string name=\"perm_provision_description\">Ceadaíonn sé don fheidhmchlár seirbhísí microG a chumrú gan idirghníomhaíocht úsáideora</string>\n    <string name=\"perm_car_speed_label\">Luas an chairr</string>\n    <string name=\"perm_car_speed_description\">Rochtain a fháil ar luas do chairr</string>\n    <string name=\"perm_car_fuel_label\">Leibhéal breosla gluaisteáin</string>\n    <string name=\"perm_car_info_label\">Eolas faoi charranna</string>\n    <string name=\"perm_car_info_description\">Rochtain a fháil ar fhaisnéis do chairr</string>\n    <string name=\"perm_car_fuel_description\">Rochtain a fháil ar fhaisnéis faoi leibhéal breosla do chairr</string>\n    <string name=\"perm_car_mileage_label\">Míleáiste cairr</string>\n    <string name=\"perm_car_mileage_description\">Rochtain a fháil ar fhaisnéis míleáiste do chairr</string>\n    <string name=\"perm_car_vendor_extension_label\">Cainéal díoltóir gluaisteán</string>\n    <string name=\"service_name_checkin\">Clárú gléas Google</string>\n    <string name=\"service_name_mcs\">Teachtaireachtaí Scamall</string>\n    <string name=\"perm_car_vendor_extension_description\">Rochtain a fháil ar chainéal díoltóra do ghluaisteáin chun faisnéis a bhaineann go sonrach le carr a mhalartú</string>\n    <string name=\"service_name_snet\">Google SafetyNet</string>\n    <string name=\"place_picker_select_title\">Roghnaigh an suíomh seo</string>\n    <string name=\"place_picker_nearby_places\">Áiteanna in aice láimhe</string>\n    <string name=\"network_type_mobile\">Líonra soghluaiste</string>\n    <string name=\"network_type_wifi\">Wi-Fi</string>\n    <string name=\"network_type_roaming\">Fánaíocht</string>\n    <string name=\"network_type_other\">Líonraí eile</string>\n    <string name=\"self_check_cat_fake_sig\">Tacaíocht spoofing síniú</string>\n    <string name=\"self_check_resolution_fake_sig_perm\">Níl aon tacaíocht dhúchasach ag do ROM le haghaidh spoofing sínithe. Is féidir leat Xposed nó córais eile a úsáid fós chun síniú a mhilleadh. Seiceáil le do thoil na doiciméid ar a dtacaíonn ROManna le spoofing sínithe agus conas microG a úsáid ar ROManna nach bhfuil.</string>\n    <string name=\"self_check_name_system_spoofs\">Síniú spoofs an chórais:</string>\n    <string name=\"self_check_resolution_system_spoofs\">Seiceáil na doiciméid ar a bhféadfadh céimeanna a bheith ag teastáil.</string>\n    <string name=\"self_check_pkg_gms\">Seirbhísí microG</string>\n    <string name=\"self_check_pkg_vending\">microG Compánach / Play Store</string>\n    <string name=\"self_check_pkg_gsf\">Creat Seirbhísí microG</string>\n    <string name=\"self_check_name_battery_optimizations\">Optimizations Battery neamhaird:</string>\n    <string name=\"self_check_name_perm_granted\">Deonaíonn an córas cead spoofing sínithe:</string>\n    <string name=\"self_check_resolution_perm_granted\">Is táscaire láidir é seo go dtacaíonn an ROM le spoofing sínithe, ach éilíonn sé gníomh breise chun é a ghníomhachtú. Seiceáil na doiciméid ar a bhféadfadh céimeanna a bheith ag teastáil.</string>\n    <string name=\"self_check_resolution_battery_optimizations\">Déan teagmháil anseo chun optimizations ceallraí a dhíchumasú. D\\'fhéadfadh iarratais mhí-iompair a bheith mar thoradh ar gan é seo a dhéanamh.</string>\n    <string name=\"prefcat_about\">Maidir</string>\n    <string name=\"prefcat_components\">Comhpháirteanna</string>\n    <string name=\"prefcat_configuration\">Cumraíocht</string>\n    <string name=\"prefcat_google_services\">Seirbhísí Google</string>\n    <string name=\"cond_gcm_bat_title\">Optamaithe ceallraí cumasaithe</string>\n    <string name=\"cond_gcm_bat_summary\">Chumasaigh tú Cloud Messaging ach tá optimizations ceallraí gníomhach le haghaidh Seirbhísí microG. Le haghaidh fógraí brú chun teacht ba chóir duit neamhaird a dhéanamh optimizations ceallraí.</string>\n    <string name=\"cond_gcm_bat_action\">Déan neamhaird de bharrfheabhsuithe</string>\n    <string name=\"cond_perm_title\">Cead ar iarraidh</string>\n    <string name=\"prefs_account\">Sainroghanna cuntais</string>\n    <string name=\"pref_auth_trust_google_summary\">Nuair atá sé díchumasaithe, iarrtar ar an úsáideoir sula seoltar iarratas údaraithe feidhmchláir chuig Google. Teipfidh ar roinnt feidhmchlár an cuntas Google a úsáid má tá sé seo díchumasaithe.</string>\n    <string name=\"prefcat_location_service\">Seirbhís suímh</string>\n    <string name=\"prefcat_services\">Seirbhísí</string>\n    <string name=\"prefcat_test\">Tástáil</string>\n    <string name=\"pref_auth_visible_summary\">Nuair a chumasaítear é, beidh gach feidhmchlár ar an ngléas seo in ann seoladh ríomhphoist do Chuntais Google a fheiceáil gan údarú roimh ré.</string>\n    <string name=\"pref_auth_include_android_id_title\">Fíordheimhnigh le clárú gléis</string>\n    <string name=\"pref_auth_include_android_id_summary\">Nuair a bheidh siad díchumasaithe, ní bheidh iarratais fíordheimhnithe nasctha le clárú an ghléis, rud a d\\'fhéadfadh ligean do ghléasanna neamhúdaraithe síniú isteach, ach d\\'fhéadfadh iarmhairtí gan choinne a bheith acu.</string>\n    <string name=\"pref_checkin_enable_summary\">Cláraíonn sé do ghléas chuig seirbhísí Google agus cruthaíonn sé aitheantóir uathúil gléis. stiallacha microG a aithníonn giotáin seachas d\\'ainm cuntais Google ó shonraí clárúcháin.</string>\n    <string name=\"pref_auth_strip_device_name_summary\">Nuair a chumasaítear é, ní áireofar ainm an ghléis in iarratais fíordheimhnithe, a d\\'fhéadfadh ligean do ghléasanna neamhúdaraithe síniú isteach, ach d\\'fhéadfadh iarmhairtí gan choinne a bheith acu.</string>\n    <string name=\"pref_device_registration_android_id\">Android ID</string>\n    <string name=\"checkin_not_registered\">Gan a bheith cláraithe</string>\n    <string name=\"checkin_enable_switch\">Cláraigh an gléas</string>\n    <string name=\"pref_info_status\">Stádas</string>\n    <string name=\"pref_more_settings\">Níos mó</string>\n    <string name=\"pref_accounts_title\">Cuntais Google</string>\n    <string name=\"pref_accounts_summary\">Cuir cuntais Google leis agus bainistigh iad</string>\n    <string name=\"prefcat_accounts_settings_title\">Socruithe</string>\n    <string name=\"prefcat_accounts_current_accounts_title\">Cuntais</string>\n    <string name=\"pref_add_account_title\">Cuntas</string>\n    <string name=\"pref_add_account_summary\">Cuir cuntas Google leis</string>\n    <string name=\"pref_gcm_enable_mcs_summary\">Is soláthraí fógra brú é Cloud Messaging a úsáideann go leor feidhmchlár tríú páirtí. Chun é a úsáid, ní mór duit clárú gléis a chumasú.</string>\n    <string name=\"pref_gcm_heartbeat_title\">Eatramh buille croí Cloud Messaging</string>\n    <string name=\"pref_gcm_confirm_new_apps_title\">Deimhnigh feidhmchláir nua</string>\n    <string name=\"gcm_not_registered\">Gan a bheith cláraithe</string>\n    <string name=\"gcm_no_message_yet\">Ní bhfuarthas aon teachtaireachtaí go dtí seo</string>\n    <string name=\"gcm_registered\">Cláraithe</string>\n    <string name=\"gcm_unregister_confirm_message\">Ní athchláraíonn roinnt feidhmchlár go huathoibríoch agus/nó ní thugann siad rogha é sin a dhéanamh de láimh. B\\'fhéidir nach n-oibreoidh na feidhmchláir seo i gceart tar éis díchlárú.\n\\nLean ar aghaidh?</string>\n    <string name=\"gcm_unregister_after_deny_message\">Shéan tú aip chun clárú le haghaidh brúfhógraí atá cláraithe cheana féin.\n\\nAr mhaith leat é a dhíchlárú anois ionas nach bhfaighidh sé teachtaireachtaí brú amach anseo?</string>\n    <string name=\"pref_gcm_heartbeat_summary\">An t-eatramh i soicindí don chóras chun na freastalaithe Google a bhualadh. Laghdóidh méadú ar an líon seo tomhaltas ceallraí, ach d\\'fhéadfadh sé moill a chur ar bhrútheachtaireachtaí.\n\\nDeprecated, a chur in ionad scaoileadh amach anseo.</string>\n    <string name=\"pref_gcm_apps_title\">Feidhmchláir ag baint úsáide as Cloud Messaging</string>\n    <string name=\"pref_gcm_apps_summary\">Liosta na bhfeidhmchlár atá cláraithe faoi láthair le haghaidh Cloud Messaging.</string>\n    <string name=\"gcm_enable_switch\">Faigh fógraí brú</string>\n    <string name=\"gcm_network_state_disconnected\">Dícheangailte</string>\n    <string name=\"pref_push_app_allow_register_title\">Ceadaigh clárú</string>\n    <string name=\"pref_push_app_allow_register_summary\">Lig don aip clárú le haghaidh fógraí brú.</string>\n    <string name=\"pref_push_app_wake_for_delivery_title\">Tosaigh feidhmchlár ar bhrútheachtaireacht</string>\n    <string name=\"pref_push_app_wake_for_delivery_summary\">Tosaigh an aip agus tú sa chúlra chun na teachtaireachtaí brú isteach a fháil.</string>\n    <string name=\"prefcat_push_apps_title\">Feidhmchláir ag baint úsáide as brúfhógraí</string>\n    <string name=\"prefcat_push_apps_registered_title\">Feidhmchláir chláraithe</string>\n    <string name=\"prefcat_push_networks_title\">Líonraí le húsáid le haghaidh fógraí brú</string>\n    <string name=\"prefcat_push_apps_unregistered_title\">Feidhmchláir neamhchláraithe</string>\n    <string name=\"safetynet_intro\">Is córas deimhniúcháin feiste é Google SafetyNet, ag cinntiú go bhfuil an gléas daingnithe i gceart agus comhoiriúnach le Android CTS. Úsáideann roinnt feidhmchlár SafetyNet ar chúiseanna slándála nó mar réamhriachtanas le haghaidh cosaint tamper.\n\\n\n\\nTá cur i bhfeidhm saor in aisce de SafetyNet ag microG GmsCore, ach éilíonn an freastalaí oifigiúil iarratais SafetyNet a shíniú ag baint úsáide as an gcóras DroidGuard dílseánaigh.</string>\n    <string name=\"safetynet_enable_switch\">Ceadaigh fianú gléis</string>\n    <string name=\"pref_safetynet_test_title\">Fianú SafetyNet Tástála</string>\n    <string name=\"pref_recaptcha_test_title\">Tástáil ReCAPTCHA</string>\n    <string name=\"pref_recaptcha_enterprise_test_title\">Tástáil ReCAPTCHA Enterprise</string>\n    <string name=\"pref_test_summary_passed\">D\\'éirigh leis na trialacha go léir</string>\n    <string name=\"pref_test_summary_failed\">Teip: %s</string>\n    <string name=\"pref_test_summary_warn\">Rabhadh: %s</string>\n    <string name=\"pref_test_summary_running\">Ag rith…</string>\n    <string name=\"pref_droidguard_operation_mode\">Mód oibríochta</string>\n    <string name=\"pref_droidguard_unsupported_summary\">Ní thacaítear le forghníomhú DroidGuard ar an ngléas seo. D\\'fhéadfadh seirbhísí SafetyNet mí-iompar a dhéanamh.</string>\n    <string name=\"pref_device_registration_import_custom_profile_title\">Iompórtáil próifíl shaincheaptha</string>\n    <string name=\"pref_safetynet_recent_cat_request\">Sonraí a iarraidh</string>\n    <string name=\"pref_safetynet_recent_nonce\">Nonce (Heics)</string>\n    <string name=\"pref_safetynet_recent_request_time\">Tráth an iarratais</string>\n    <string name=\"pref_safetynet_recent_request_type\">Cineál iarratais</string>\n    <string name=\"pref_safetynet_recent_cat_basic\">Sonraí bunúsacha</string>\n    <string name=\"pref_safetynet_recent_token\">Comhartha</string>\n    <string name=\"pref_safetynet_recent_copied\">Cóipeáladh go dtí an ghearrthaisce!</string>\n    <string name=\"pref_safetynet_test_integrity_cts_passed\">Ionracas agus CTS a ritheadh</string>\n    <string name=\"pref_safetynet_test_cts_failed\">Theip ar CTS</string>\n    <string name=\"pref_safetynet_test_integrity_failed\">Theip ar ionracas</string>\n    <string name=\"pref_safetynet_test_not_completed\">Níl sé críochnaithe fós</string>\n    <string name=\"pref_safetynet_test_no_result\">Gan toradh</string>\n    <string name=\"pref_safetynet_test_invalid_json\">JSON neamhbhailí</string>\n    <string name=\"push_notifications_summary_off\">AS</string>\n    <string name=\"push_notifications_summary_automatic\">AR / Uathoibríoch: %s</string>\n    <string name=\"push_notifications_summary_manual\">AR / Lámhleabhar: %s</string>\n    <string name=\"push_notifications_summary_values_seconds\">%s soicind</string>\n    <string name=\"push_notifications_summary_values_minutes\">%s nóiméad</string>\n    <string name=\"pref_vending_summary_licensing_off\">Ceadúnú as</string>\n    <string name=\"pref_vending_summary_licensing_on\">Ceadúnú ar</string>\n    <string name=\"pref_vending_licensing_category\">Ceadúnú Google Play</string>\n    <string name=\"pref_vending_license_enable_summary\">Éilíonn roinnt aipeanna fíorú gur cheannaigh tú iad ar Google Play. Nuair a iarrann aip é, is féidir le microG cruthúnas ceannaigh a íoslódáil ó Google. Má tá tú díchumasaithe, nó mura gcuirtear aon chuntas Google leis, déantar neamhaird ar iarratais ar fhíorú ceadúnais.</string>\n    <string name=\"pref_vending_licensing_enable_switch\">Freagair iarratais ar fhíorú ceadúnais</string>\n    <string name=\"feedback_disabled\">Ní féidir aiseolas a fháil faoi láthair</string>\n    <string name=\"backup_disabled\">Ní féidir cúltaca a dhéanamh faoi láthair</string>\n    <string name=\"pref_vending_billing_category\">Google Seinn Billeála</string>\n    <string name=\"pref_vending_billing_enable_switch\">Déileáil le hiarratais bhilleála</string>\n    <string name=\"pref_vending_billing_enable_summary\">Nuair a bheidh sé cumasaithe, is féidir le roinnt feidhmchlár ceannacháin a chomhlánú nó síntiúis a thosú trí sheirbhís Billeála Súgartha Google.</string>\n    <string name=\"pref_vending_billing_note_experimental\">Tá an ghné seo turgnamhach agus d\\'fhéadfadh caillteanas airgid a bheith mar thoradh air. Tugadh rabhadh duit.</string>\n    <string name=\"pref_vending_billing_note_licensing\">D\\'fhéadfadh sé go n-iarrfadh roinnt feidhmchlár ort fíorú ceadúnais a chumasú chun do cheannacháin a fhíorú.</string>\n    <string name=\"credentials_assisted_cancel\">Cuir ar ceal</string>\n    <string name=\"credentials_assisted_continue\">Lean ar aghaidh</string>\n    <string name=\"credentials_assisted_confirmation_header\">Tú a shíniú isteach</string>\n    <string name=\"credentials_assisted_signin_consent_header\">Ag síniú mar %1$s</string>\n    <string name=\"credentials_assisted_signin_consent\">Trí leanúint ar aghaidh, roinnfidh Google d\\'ainm, do sheoladh ríomhphoist, agus do phictiúr próifíle le %1$s. Féach Polasaí Príobháideachais agus Téarmaí Seirbhíse %1$s.</string>\n    <string name=\"auth_notification_content\">Tá d\\'údarú ag teastáil ó <xliff:g example=\"F-Droid\">%1$s</xliff:g> chun rochtain a fháil ar do Chuntas Google.</string>\n    <string name=\"auth_package_override_request_title\">Ceadaigh rochtain phribhléideach do <b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> ar <xliff:g example=\"account@example.com\">%2$s</xliff:g>\\?</string>\n    <string name=\"signin_picker_subtitle\">chun leanúint ar aghaidh chuig <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"place_picker_location_lat_lng\">(%1$.7f, %2$.7f)</string>\n    <string name=\"credentials_assisted_sign_back_title\">Sínigh isteach arís i %1$s le Google</string>\n    <string name=\"credentials_assisted_continue_as_user_button_label\">Lean ar aghaidh mar %1$s</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_switch\">Cuir aipeanna saor in aisce leis an leabharlann go huathoibríoch</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_summary\">Féadfaidh aipeanna saor in aisce a sheiceáil cibé an ndearnadh iad a íoslódáil ó Google Play. Cuir aipeanna saor in aisce le do leabharlann chuntais go huathoibríoch chun an tseic ar gach aip saor in aisce atá ar fáil duit faoi láthair a chur ar aghaidh i gcónaí.</string>\n    <string name=\"limited_services_dialog_information\">Tá tú ag úsáid Seirbhísí Teoranta MicroG. Murab ionann agus na gnáthsheirbhísí microG, ní oibríonn an blas seo ach le haipeanna a úsáideann leabharlanna microG, ní iad siúd ar Google Play. Ciallaíonn sé seo go ndéanfaidh formhór na n-iarratas neamhaird ar na seirbhísí seo.</string>\n    <string name=\"limited_services_app_name\">Seirbhísí Teoranta microG</string>\n    <string name=\"limited_services_dialog_information_ack\">Tuigim</string>\n    <string name=\"auth_action_notification_channel_name\">Foláirimh chuntas Google</string>\n    <string name=\"auth_action_notification_title\">Gníomh cuntais ag teastáil</string>\n    <string name=\"auth_action_activity_header\">Críochnaigh do chuntas Google a shocrú</string>\n    <string name=\"auth_action_step_allow_microg_gcm_description\">De réir do shainroghanna, teastaíonn cead uait ó microG sular féidir leis é féin a chlárú le haghaidh Cloud Messaging.</string>\n    <string name=\"auth_action_step_enable_lockscreen\">Cumraigh glas scáileáin slán</string>\n    <string name=\"auth_action_step_perform_content_description\">Cliceáil chun céim a dhéanamh</string>\n    <string name=\"auth_action_step_completed_content_description\">Céim críochnaithe</string>\n    <string name=\"auth_action_notification_content\">Tá socruithe breise de dhíth ar do Chuntas Google.</string>\n    <string name=\"auth_action_activity_explanation\">Comhlánaigh na céimeanna seo a leanas le bheith in ann do Chuntas Google %s a úsáid ar an ngléas seo.</string>\n    <string name=\"auth_action_step_enable_checkin_description\">Ní mór le do ghléas clárú le Google uair amháin ar a laghad.\\n\\nIs féidir leat clárú gléas Google a dhíchumasú tar éis socrú an chuntais a bheith críochnaithe.</string>\n    <string name=\"auth_action_notification_channel_description\">Tugtar fógra nuair a bhíonn socruithe breise de dhíth ar cheann de do chuntais Google sular féidir é a úsáid nó nuair nach bhfuil cuntas ag luí le microG.</string>\n    <string name=\"auth_action_step_enable_checkin\">Cumasaigh clárú gléas</string>\n    <string name=\"auth_action_step_enable_lockscreen_description\">Tá do chuntas Google á bhainistiú ag d\\'ionad oibre nó institiúid oideachais. Chinn do riarthóir go bhfuil glas scáileáin slán de dhíth ar ghléasanna sular féidir leo rochtain a fháil ar shonraí cuntais.\\n\\nSocraigh pasfhocal, UAP, nó scáileán glas patrún.</string>\n    <string name=\"auth_action_step_enable_gcm\">Cumasaigh Cloud Messaging</string>\n    <string name=\"auth_action_step_enable_gcm_description\">Is féidir leat Cloud Messaging a dhíchumasú nuair a bhíonn socrú an chuntais críochnaithe.</string>\n    <string name=\"auth_action_step_allow_microg_gcm\">Ceadaigh Cloud Messaging le haghaidh microG</string>\n    <string name=\"auth_action_activity_finish\">Críochnaigh</string>\n    <string name=\"pref_vending_asset_delivery_summary\">Íoslódáil sócmhainní breise nuair a iarrann apps a úsáideann Seachadadh Sócmhainní Súgartha</string>\n    <string name=\"pref_vending_asset_delivery_switch\">Cumasaigh seachadadh sócmhainní ar éileamh</string>\n    <string name=\"pref_vending_asset_delivery_category\">Seachadadh Sócmhainní Google Play</string>\n    <string name=\"pref_vending_asset_device_sync_switch\">Cumasaigh sioncronú faisnéise gléis</string>\n    <string name=\"games_achievement_list_title\">Éachtaí</string>\n    <string name=\"games_api_access_denied\">Ní féidir le cuntas ar bith ar an ngléas seo rochtain a fháil ar APIanna na gCluichí</string>\n    <string name=\"games_achievement_locked_content_description\">faoi ghlas</string>\n    <string name=\"games_achievement_extra_text\">%1$s XP</string>\n    <string name=\"games_leaderboard_list_title\">Ranguithe</string>\n    <string name=\"games_leaderboards_score_label\">Scór: %1$s</string>\n    <string name=\"games_snapshot_choose_btn_text\">roghnaigh</string>\n    <string name=\"games_snapshot_delete_btn_text\">scrios</string>\n    <string name=\"games_delete_snapshot_dialog_title\">Scrios an cluiche sábháilte</string>\n    <string name=\"games_delete_snapshot_dialog_message\">An bhfuil tú cinnte gur mhaith leat an cluiche sábháilte seo a scriosadh?</string>\n    <string name=\"games_delete_snapshot_dialog_cancel\">Cealaigh</string>\n    <string name=\"games_delete_snapshot_dialog_ok\">Ceart go leor</string>\n    <string name=\"games_delete_snapshot_error\">Theip ar an scriosadh, bain triail eile as ar ball</string>\n    <string name=\"games_leaderboard_empty_text\">Gan aon cheannairí don chluiche seo</string>\n    <string name=\"games_achievement_unlocked_content_description\">díghlasáilte</string>\n    <string name=\"games_achievements_empty_text\">Níl aon éachtaí don chluiche seo</string>\n    <string name=\"games_snapshot_empty_text\">Níl aon sábhálann cluiche sábháilte fós</string>\n    <string name=\"games_leaderboard_score_empty_text\">Dochreidte! Níl aon scóir arda poiblí don chluiche seo.</string>\n    <string name=\"pref_vending_asset_device_sync_summary\">Déanfaidh feidhmchláir a úsáideann Seachadadh Sócmhainní Súgartha sócmhainní breise a íoslódáil bunaithe ar fhaisnéis an fheiste atá in úsáid faoi láthair.</string>\n    <string name=\"service_name_work_profile\">Próifíl oibre</string>\n    <string name=\"pref_vending_feature_delivery\">Seachadadh Gné Google Play</string>\n    <string name=\"pref_vending_split_install_switch\">Suiteáil comhpháirteanna ar éileamh</string>\n    <string name=\"pref_workprofile_create_account\">Ceadaigh cuntas oibre a shocrú</string>\n    <string name=\"pref_workprofile_intro\">Agus próifíl oibre á socrú agat do d’ionad oibre nó d’institiúid oideachais, seans go ndéanfaidh an socrú iarracht nascadh le Google chun aipeanna a íoslódáil chuig an bpróifíl sin a chumasú.</string>\n    <string name=\"pref_workprofile_disclaimer\">Is ortsa atá an fhreagracht a chinntiú go bhfuil an úsáid a bhaineann tú as microG ag teacht le polasaithe corparáideacha. Cuirtear microG ar fáil ar bhonn na hiarrachta is fearr agus ní féidir ráthaíocht a thabhairt go n-iompróidh sé díreach mar a bhíothas ag súil leis.</string>\n    <string name=\"camera_permission_dialog_button\">Ceart go leor</string>\n    <string name=\"camera_permission_dialog_title\">Teastaíonn cead ceamara</string>\n    <string name=\"camera_permission_dialog_message\">Ní mór do sheirbhísí microG ceamara do ghléis a rochtain chun cód %1$s a scanadh.\\n\\nChun é a chumasú, tabhair cead ceamara do sheirbhísí microG sna Socruithe.</string>\n    <string name=\"barcode_scanner_brand\">Scanadh ag microG ar son %1$s</string>\n    <string name=\"pref_vending_licensing_split_install_summary\">Lig do aipeanna comhpháirteanna breise a íoslódáil agus a shuiteáil</string>\n    <string name=\"credentials_assisted_signin_add_account\">Cuir Cuntas leis</string>\n    <string name=\"credentials_assisted_choose_account_error_tips\">Neamhghnáchaíocht chuntais</string>\n    <string name=\"auth_action_reauth_notification_title\">Gníomh cuntais ag teastáil</string>\n    <string name=\"pref_game_accounts_title\">Cuntais Cluiche Google</string>\n    <string name=\"pref_auto_create_player\">Ceadaigh clárú cuntais Play Games</string>\n    <string name=\"pref_auto_create_player_intro\">Agus cluichí á n-imirt agat, ní mór duit cuntas Play Games a úsáid chun logáil isteach agus feidhmeanna a bhaineann leis an gcluiche a thaifeadadh, amhail éachtaí, cláir cheannaireachta, cartlanna, srl. Tar éis iad a dhíchumasú, ní chlárófar cuntais Google nach bhfuil ceangailte le cuntas Play Games go huathoibríoch, agus ní bheidh an cluiche in ann logáil isteach agus imirt.</string>\n    <string name=\"pref_allow_upload_game_played\">Ceadaigh uaslódáil cluiche a imríodh</string>\n    <string name=\"pref_allow_upload_game_played_summary\">Nuair a bhíonn sé díchumasaithe, ní thabharfaidh an cluiche tuairisc ar stádas an chluiche imeartha tar éis logáil isteach sa chluiche, agus b\\'fhéidir nach mbeidh roinnt cluichí in ann logáil isteach.</string>\n    <string name=\"pref_change_default_game_player\">Athraigh cuntas le haghaidh cluichí</string>\n    <string name=\"pref_change_default_game_player_summary\">Athraigh an cuntas réamhshocraithe do chluichí &amp; Athraigh an cuntas de réir cluiche.</string>\n    <string name=\"pref_delete_game_account_data\">Scrios sonraí Play Games</string>\n    <string name=\"pref_delete_game_account_data_summary\">Scrios cuntas Play Games &amp; na sonraí go léir agus Scrios sonraí cluichí aonair.</string>\n    <string name=\"games_state_description_signed_out\">Sínithe amach</string>\n    <string name=\"games_state_description_delete\">Scrios</string>\n    <string name=\"games_change_button_text\">Athraigh</string>\n    <string name=\"games_change_default_account_section_title\">Athraigh an cuntas réamhshocraithe le haghaidh cluichí</string>\n    <string name=\"games_change_default_account_description\">Cuntas réamhshocraithe: %1$s</string>\n    <string name=\"games_change_default_account_explanation\">Úsáidtear an cuntas seo chun tú a shíniú isteach go huathoibríoch i gcluichí, chun do dhul chun cinn sa chluiche a shábháil, agus chun do shocruithe a shábháil. D’fhéadfadh athrú ar an gcuntas réamhshocraithe nó chun síniú amach do dhul chun cinn agus do shocruithe a athshocrú le haghaidh cluichí atá imeartha agat.</string>\n    <string name=\"games_change_per_game_title\">Athraigh an cuntas de réir cluiche</string>\n    <string name=\"games_change_per_game_description\">D’fhéadfadh sé go ndéanfadh athrú ar an gcuntas le haghaidh cluiche roghnaithe nó síniú amach as do dhul chun cinn agus do shocruithe don chluiche a athshocrú.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_title\">Roghnaigh rogha don chuntas réamhshocraithe nua</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_description\">Cuntas réamhshocraithe reatha: %1$s</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_title\">Athraigh an cuntas réamhshocraithe le haghaidh cluichí nua amháin</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_description\">Ní chaillfidh tú rochtain ar dhul chun cinn agus socruithe do chluichí atá imeartha agat. Ach roinnfear do dhul chun cinn idir cuntais.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_title\">Athraigh an cuntas réamhshocraithe do gach cluiche</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_description\">D’fhéadfá rochtain ar dhul chun cinn agus socruithe cluichí atá imeartha agat a chailleadh. Atosóimid an cluiche chun do chuid athruithe a chur i bhfeidhm.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_title\">Sínigh amach as gach cluiche</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_description\">D’fhéadfá rochtain ar dhul chun cinn agus socruithe cluichí atá imeartha agat a chailleadh. Atosóimid an cluiche chun do chuid athruithe a chur i bhfeidhm.</string>\n    <string name=\"games_change_per_game_dialog_title\">Roghnaigh rogha don chluiche seo</string>\n    <string name=\"games_change_per_game_dialog_description\">D’fhéadfadh athrú cuntais nó síniú amach do dhul chun cinn agus do shocruithe don chluiche a athshocrú</string>\n    <string name=\"games_change_per_game_dialog_option_use_player\">Úsáid %1$s</string>\n    <string name=\"games_change_per_game_dialog_option_use_player_snackbar_success_message\">Beidh tú logáilte isteach sa chluiche seo le %1$s</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out\">Sínigh amach</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out_snackbar_success_message\">Tá tú sínithe amach as an gcluiche seo anois</string>\n    <string name=\"games_change_sign_out_of_all_games_snackbar_success_message\">Tá tú sínithe amach as na cluichí go léir anois</string>\n    <string name=\"games_change_default_account_for_all_games_snackbar_success_message\">Beidh tú sínithe isteach i ngach cluiche le %1$s</string>\n    <string name=\"games_change_default_account_for_new_games_snackbar_success_message\">Beidh tú sínithe isteach i gcluichí nua le %1$s</string>\n    <string name=\"games_account_display_content\">Cuntas reatha: %1$s</string>\n    <string name=\"games_delete_profile_header\">Scrios cuntas Play Games &amp; na sonraí go léir</string>\n    <string name=\"games_delete_profile_explanation\">Scrios do chuntas Google Play Games, XP, agus na sonraí próifíle go léir go buan. D’fhéadfadh an gníomh seo do scóir, do dhul chun cinn (cluichí sábháilte), agus do shocruithe i gcluichí atá imeartha agat a scriosadh freisin.</string>\n    <string name=\"games_delete_profile_button\">Scrios go buan</string>\n    <string name=\"games_delete_game_data_header\">Scrios sonraí cluiche aonair</string>\n    <string name=\"games_delete_game_data_explanation\">Is féidir leat sonraí aonair a scriosadh go buan le haghaidh cluichí a d’imir tú ag baint úsáide as Google Play Games. Scriosann an gníomh seo do scóir, do dhul chun cinn (cluichí sábháilte), agus do shocruithe don chluiche a roghnaíonn tú.</string>\n    <string name=\"games_delete_profile_dialog_title\">An bhfuil tú cinnte gur mian leat an cuntas seo a scriosadh?</string>\n    <string name=\"games_delete_profile_explanation_with_gamer_name\">Scrios go buan d’ainm an imreora <b>%1$s</b> (<b>%2$s</b>), XP, agus na sonraí próifíle go léir. D’fhéadfadh an gníomh seo do scóir, do dhul chun cinn (cluichí sábháilte), agus do shocruithe i gcluichí atá imeartha agat a scriosadh freisin.</string>\n    <string name=\"games_delete_profile_dialog_message\">Ní féidir an gníomh seo a chealú.</string>\n    <string name=\"games_delete_profile_fail\">Níorbh fhéidir do phróifíl a scriosadh. Bain triail eile as ar ball.</string>\n    <string name=\"games_delete_game_data_confirm_dialog_title\">Scrios sonraí le haghaidh %1$s</string>\n    <string name=\"games_delete_game_data_confirm_dialog_message\">Má scriostar do shonraí go buan le haghaidh %1$s, bainfear do scóir, do dhul chun cinn (cluichí sábháilte), agus do shocruithe cluiche i Google Play Games.</string>\n    <string name=\"games_popup_signin_welcome\">Haigh, %1$s</string>\n    <string name=\"pref_auth_two_step_verification_title\">Faigh leideanna fíoraithe dhá chéim</string>\n    <string name=\"pref_auth_two_step_verification_summary\">Nuair a bhíonn sé cumasaithe, is féidir leis an bhfeiste leideanna fíoraithe dhá chéim a fháil ó Google (tá Cloud Messenger ag teastáil).</string>\n    <string name=\"service_name_google_location_sharing\">Comhroinnt Suímh Google</string>\n    <string name=\"location_sharing_description\">Bainistigh do chomhroinnt Suímh fíor-ama ar fud aipeanna agus seirbhísí Google ón ngléas seo</string>\n    <string name=\"location_sharing_learn_more\">Foghlaim tuilleadh faoi Chomhroinnt Suímh</string>\n    <string name=\"location_sharing_switch_text\">Úsáid Comhroinnt Suímh</string>\n    <string name=\"location_sharing_turn_off_notify_hint\">Mura múchfaidh tú Comhroinnt Suímh don ghléas seo, ní chuirfear na daoine a bhfuil tú ag roinnt leo ar an eolas.</string>\n    <string name=\"location_sharing_off_previous_hint\">Ní bheidh ar fáil ach an suíomh comhroinnte deireanach a bhí agat go dtí go gcuirfidh tú air arís é.</string>\n    <string name=\"location_sharing_disabled\">Níl aon chomhroinnt suímh ghníomhacha don chuntas seo</string>\n    <string name=\"location_sharing_turn_on_hint\">Nuair a thosaíonn tú ag roinnt do shuíomh ó aip nó seirbhís Google, is féidir leat Comhroinnt Suímh a bhainistiú as seo.\\n\\nChun tús a chur le do shuíomh a roinnt, téigh chuig Google Maps nó Family Link.</string>\n    <string name=\"location_sharing_turn_off_title\">Múch Comhroinnt Suímh</string>\n    <string name=\"location_sharing_turn_off_hint\">D’fhéadfá a bheith ag roinnt do shuíomh fós ó ghléasanna eile atá sínithe isteach sa Chuntas Google céanna nó ó aipeanna nach de chuid Google iad. Déan cinnte go seiceálann tú do shocruithe comhroinnte suímh in aon áit a bhféadfadh sé a bheith i bhfeidhm.\\n\\nLeanfaidh daoine a roinneann tú leo de do shuíomh comhroinnte deireanach a fheiceáil.</string>\n    <string name=\"location_sharing_turn_off_cancel\">Coinnigh ar aghaidh</string>\n    <string name=\"location_sharing_turn_off_confirm\">Múch</string>\n    <string name=\"location_sharing_confirm_dialog_title\">Cumasaigh Comhroinnt Suímh</string>\n    <string name=\"location_sharing_confirm_dialog_text\">Is féidir le daoine a roinneann tú do shuíomh leo na nithe seo a leanas a fheiceáil i gcónaí:\\n·D’ainm agus do ghrianghraf\\n·Suíomh le déanaí do ghléis, fiú nuair nach bhfuil tú ag úsáid seirbhís Google\\n·Cumhacht ceallraí do ghléis, agus an bhfuil sé á mhuirearú\\n·D’am teachta agus imeachta, má chuireann siad fógra Comhroinnte Suímh leis</string>\n    <string name=\"family_management_title\">Teaghlach</string>\n    <string name=\"family_management_retry\">Déan iarracht eile</string>\n    <string name=\"family_management_load_error\">Theip ar luchtú ábhair</string>\n    <string name=\"family_management_toolbar_back\">Ar ais</string>\n    <string name=\"family_management_toolbar_more\">Tuilleadh</string>\n    <string name=\"family_management_exit_family_group\">Fág an grúpa teaghlaigh</string>\n    <string name=\"family_management_delete_family_group\">Scrios grúpa teaghlaigh</string>\n    <string name=\"family_management_leave_family_password_title\">Deimhnigh an focal faire chun an grúpa teaghlaigh a fhágáil</string>\n    <string name=\"family_management_delete_family_password_title\">Deimhnigh pasfhocal chun grúpa teaghlaigh a scriosadh</string>\n    <string name=\"family_management_remove_member_password_title\">Deimhnigh an focal faire chun %s a bhaint</string>\n    <string name=\"family_management_invite_family_member\">Tabhair cuireadh do bhaill teaghlaigh</string>\n    <string name=\"family_management_invite_slots_left\">%1$d cuireadh fágtha</string>\n    <string name=\"family_management_cancel_invite\">Cealaigh an cuireadh</string>\n    <string name=\"family_management_cancel_invite_success\">Cealaigh an cuireadh go rathúil</string>\n    <string name=\"family_management_cancel_invite_error\">Fadhb ag cealú an chuireadh. Bain triail eile as.</string>\n    <string name=\"family_management_remove_member\">Bain Comhalta</string>\n    <string name=\"family_management_member_removed_success\">Baineadh %s as do ghrúpa teaghlaigh</string>\n    <string name=\"family_management_member_remove_failed\">Fadhb ag baint %s. Déan iarracht arís.</string>\n    <string name=\"family_management_leave_family_error_message\">Trioblóid ag imeacht ón ngrúpa teaghlaigh. Bain triail eile as.</string>\n    <string name=\"family_management_exist_group_success\">D’fhág tú do ghrúpa teaghlaigh…</string>\n    <string name=\"family_management_delete_group_success\">Grúpa teaghlaigh scriosta</string>\n    <string name=\"family_management_delete_group_failure\">Theip ar an ngrúpa baile a scriosadh</string>\n    <string name=\"family_management_delete_group_cancel\">Cealaigh</string>\n    <string name=\"family_management_delete_group_confirm\">Ceart go leor</string>\n    <string name=\"family_management_input_pwd\">Cuir isteach do phasfhocal le do thoil</string>\n    <string name=\"family_management_invite_sent_date_format\">Cuireadh seolta ar %s</string>\n    <string name=\"family_management_invite_send\">Cuireadh seolta</string>\n    <string name=\"family_management_pwd_error\">Pasfhocal mícheart, cuir isteach arís é le do thoil</string>\n    <string name=\"pref_app_install_settings_title\">Socruithe Suiteálaí Aipeanna</string>\n    <string name=\"pref_app_install_switch_title\">Ceadaigh Suiteáil Aipeanna</string>\n    <string name=\"pref_app_install_other_apps_note\">Ceadaíonn údarú suiteáil aipeanna a chuirtear ar fáil ó fhoinsí eile.</string>\n    <string name=\"pref_app_install_permission_instruction\">Chun a chinntiú go n-oibríonn do chuid aipeanna suiteáilte i gceart, údaraigh microG Companion chun aipeanna a shuiteáil atá íoslódáilte ó fhoinsí eile.</string>\n    <string name=\"prefcat_app_install_list_title\">Aipeanna ag baint úsáide as Suiteálaí Aipeanna</string>\n    <string name=\"service_name_device_attestation\">Deimhniú Gléas</string>\n    <string name=\"prefcat_device_attestation_apps_title\">Aipeanna a úsáideann Deimhniú Gléas</string>\n    <string name=\"pref_device_attestation_app_allow_requests_title\">Ceadaigh iarratais</string>\n    <string name=\"pref_device_attestation_app_allow_requests_summary\">Lig don aip dearbhú gléis a iarraidh</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-hu/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"permission_service_all_label\">Minden Google szolgáltatás</string>\n    <string name=\"permission_service_all_description\">Engedélyezi az alkalmazásnak, hogy hozzáférjen minden Google szolgáltatáshoz bármely kapcsolódó Google fiókon keresztül.</string>\n    <string name=\"permission_service_android_label\">Android szolgáltatások</string>\n    <string name=\"permission_service_android_description\">Engedélyezi az alkalmazásoknak hogy hozzáférjenek Android szolgáltatásokhoz bármely társított Google fiókon keresztül.</string>\n    <string name=\"permission_service_adsense_label\">AdSense</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-hu/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <plurals name=\"pref_unifiednlp_summary\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> végpont konfigurálva</item>\n        <item quantity=\"other\"><xliff:g example=\"3\">%1$d</xliff:g> végpont konfigurálva</item>\n    </plurals>\n    <plurals name=\"gcm_registered_apps_counter\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> regisztrált app</item>\n        <item quantity=\"other\"><xliff:g example=\"123\">%1$d</xliff:g> regisztrált app</item>\n    </plurals>\n    <plurals name=\"cond_perm_summary\">\n        <item quantity=\"one\">Egy engedély, mely szükséges a microG helyes működéséhez nincs megadva.</item>\n        <item quantity=\"other\">Több engedély, mely szükséges a microG helyes működéséhez nincs megadva.</item>\n    </plurals>\n    <plurals name=\"cond_perm_action\">\n        <item quantity=\"one\">Hiányzó engedély kérése</item>\n        <item quantity=\"other\">Hiányzó engedélyek kérése</item>\n    </plurals>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-hu/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"gms_app_name\">microG szolgáltatások</string>\n    <string name=\"location_sharing_turn_off_hint\">Lehet hogy még mindig megosztod a helyedet másik eszközödről, ahol be vagy jelentkezve Google fiókodba, vagy nem Google appokból. Ellenőrizd a helymegosztási beállításaidat mindenhol ahol szükséges.\\n\\nAzok, akikkel megosztottad a helyedet továbbra is látni fogják az utolsó elküldött pozíciót.</string>\n    <string name=\"location_sharing_turn_off_title\">Helymegosztás kikapcsolása</string>\n    <string name=\"limited_services_app_name\">microG korlátolt szolgáltatások</string>\n    <string name=\"gms_settings_name\">microG beállítások</string>\n    <string name=\"gms_settings_summary\">microG szolgáltatások beállítása.</string>\n    <string name=\"just_a_sec\">Egy pillanat…</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-in/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"permission_service_local_description\">Mengizinkan aplikasi untuk mengakses Google Maps melalui akun Google yang terhubung.</string>\n    <string name=\"permission_service_adsense_label\">AdSense</string>\n    <string name=\"permission_service_adsense_description\">Mengizinkan aplikasi untuk mengakses AdSense melalui akun Google yang terhubung.</string>\n    <string name=\"permission_service_knol_description\">Mengizinkan aplikasi untuk mengakses Knol melalui akun Google yang terhubung.</string>\n    <string name=\"permission_service_all_label\">Semua layanan Google</string>\n    <string name=\"permission_service_all_description\">Mengizinkan aplikasi untuk mengakses semua layanan Google melalui akun Google yang terhubung.</string>\n    <string name=\"permission_service_android_label\">Layanan Android</string>\n    <string name=\"permission_service_android_description\">Mengizinkan aplikasi untuk mengakses layanan Android melalui akun Google yang terhubung.</string>\n    <string name=\"permission_service_adwords_label\">AdWords</string>\n    <string name=\"permission_service_ah_description\">Mengizinkan aplikasi untuk mengakses Google App Engine melalui akun Google yang terhubung.</string>\n    <string name=\"permission_service_blogger_label\">Blogger</string>\n    <string name=\"permission_service_blogger_description\">Mengizinkan aplikasi untuk mengakses Blogger melalui akun Google yang terhubung.</string>\n    <string name=\"permission_service_cp_label\">Kontak</string>\n    <string name=\"permission_service_cp_description\">Mengizinkan aplikasi untuk mengakses Kontak melalui akun Google yang terhubung.</string>\n    <string name=\"permission_service_cl_description\">Mengizinkan aplikasi untuk mengakses Google Kalender melalui akun Google yang terhubung.</string>\n    <string name=\"permission_service_cl_label\">Google Kalender</string>\n    <string name=\"permission_service_dodgeball_label\">Dodgeball</string>\n    <string name=\"permission_service_dodgeball_description\">Mengizinkan aplikasi untuk mengakses Dodgeball melalui akun Google yang terhubung.</string>\n    <string name=\"permission_service_finance_label\">Google Finance</string>\n    <string name=\"permission_service_finance_description\">Mengizinkan aplikasi untuk mengakses Google Finance melalui akun Google yang terhubung.</string>\n    <string name=\"permission_service_gbase_label\">Google Base</string>\n    <string name=\"permission_service_grandcentral_label\">Google Suara</string>\n    <string name=\"permission_service_grandcentral_description\">Mengizinkan aplikasi untuk mengakses Google Suara melalui akun Google yang terhubung.</string>\n    <string name=\"permission_service_groups2_label\">Google Grup</string>\n    <string name=\"permission_service_groups2_description\">Mengizinkan aplikasi untuk mengakses Google Grup melalui akun Google yang terhubung.</string>\n    <string name=\"permission_service_health_label\">Google Kesehatan</string>\n    <string name=\"permission_service_health_description\">Mengizinkan aplikasi untuk mengakses Google Kesehatan melalui akun Google yang terhubung.</string>\n    <string name=\"permission_service_ig_label\">iGoogle</string>\n    <string name=\"permission_service_jotspot_label\">JotSpot</string>\n    <string name=\"permission_service_jotspot_description\">Mengizinkan aplikasi untuk mengakses JotSpot melalui akun Google yang terhubung.</string>\n    <string name=\"permission_service_knol_label\">Knol</string>\n    <string name=\"permission_service_lh2_label\">Album Web Picasa</string>\n    <string name=\"permission_service_mail_description\">Mengizinkan aplikasi untuk mengakses Google Mail melalui akun Google yang terhubung.</string>\n    <string name=\"permission_service_news_label\">Google Berita</string>\n    <string name=\"permission_service_news_description\">Mengizinkan aplikasi untuk mengakses Google Berita melalui akun Google yang terhubung.</string>\n    <string name=\"permission_service_notebook_label\">Google Notebook</string>\n    <string name=\"permission_service_adwords_description\">Mengizinkan aplikasi untuk mengakses AdWords melalui akun Google yang terhubung.</string>\n    <string name=\"permission_service_ah_label\">Google App Engine</string>\n    <string name=\"permission_service_gbase_description\">Mengizinkan aplikasi untuk mengakses Google Base melalui akun Google yang terhubung.</string>\n    <string name=\"permission_service_mail_label\">Google Mail</string>\n    <string name=\"permission_service_ig_description\">Mengizinkan aplikasi mengakses iGoogle melalui akun Google yang terhubung.</string>\n    <string name=\"permission_service_lh2_description\">Mengizinkan aplikasi untuk mengakses Album Web Picasa melalui akun Google yang terhubung.</string>\n    <string name=\"permission_service_local_label\">Google Maps</string>\n    <string name=\"permission_service_notebook_description\">Mengizinkan aplikasi untuk mengakses Google Notebook melalui akun Google yang terhubung.</string>\n    <string name=\"permission_service_orkut_label\">Orkut</string>\n    <string name=\"permission_service_orkut_description\">Mengizinkan aplikasi untuk mengakses Orkut melalui akun Google yang terkait.</string>\n    <string name=\"permission_service_print_label\">Google Book Search</string>\n    <string name=\"permission_service_print_description\">Mengizinkan aplikasi untuk mengakses Google Book Search melalui akun Google yang terkait.</string>\n    <string name=\"permission_service_sierra_label\">Akun Google Checkout</string>\n    <string name=\"permission_service_sierra_description\">Mengizinkan aplikasi untuk mengakses akun Google Checkout melalui akun Google yang terkait.</string>\n    <string name=\"permission_service_sierraqa_label\">Akun QA Google Checkout</string>\n    <string name=\"permission_service_sierraqa_description\">Mengizinkan aplikasi untuk mengakses akun Google Checkout QA melalui akun Google yang terkait.</string>\n    <string name=\"permission_service_sierrasandbox_label\">Akun Sandbox Google Checkout</string>\n    <string name=\"permission_service_sierrasandbox_description\">Mengizinkan aplikasi untuk mengakses akun Google Checkout Sandbox melalui akun Google yang terkait.</string>\n    <string name=\"permission_service_sitemaps_label\">Alat Webmaster Google</string>\n    <string name=\"permission_service_sitemaps_description\">Mengizinkan aplikasi untuk mengakses Google Webmaster Tools melalui akun Google yang terkait.</string>\n    <string name=\"permission_service_speech_label\">Pencarian Suara</string>\n    <string name=\"permission_service_speech_description\">Mengizinkan aplikasi untuk mengakses Pencarian Suara melalui akun Google yang terkait.</string>\n    <string name=\"permission_service_speechpersonalization_label\">Pengenalan Suara yang Disesuaikan</string>\n    <string name=\"permission_service_speechpersonalization_description\">Mengizinkan aplikasi untuk mengakses Pengenalan Suara yang Disesuaikan melalui akun Google yang terkait.</string>\n    <string name=\"permission_service_talk_label\">Google Talk</string>\n    <string name=\"permission_service_talk_description\">Mengizinkan aplikasi untuk mengakses Google Talk melalui akun Google yang terkait.</string>\n    <string name=\"permission_service_wifi_label\">Google Wi-Fi</string>\n    <string name=\"permission_service_wifi_description\">Mengizinkan aplikasi untuk mengakses Google Wi-Fi melalui akun Google yang terhubung.</string>\n    <string name=\"permission_service_wise_label\">Google Spreadsheets</string>\n    <string name=\"permission_service_wise_description\">Mengizinkan aplikasi untuk mengakses Google Spreadsheets melalui akun Google yang terkait.</string>\n    <string name=\"permission_service_writely_label\">Dokumen Google</string>\n    <string name=\"permission_service_writely_description\">Mengizinkan aplikasi untuk mengakses Google Docs melalui akun Google yang terkait.</string>\n    <string name=\"permission_service_youtube_label\">YouTube</string>\n    <string name=\"permission_service_youtube_description\">Mengizinkan aplikasi untuk mengakses YouTube melalui akun Google yang terkait.</string>\n    <string name=\"permission_service_YouTubeUser_label\">Nama pengguna YouTube</string>\n    <string name=\"permission_service_YouTubeUser_description\">Mengizinkan aplikasi untuk mengakses nama pengguna YouTube yang digunakan dengan akun Google yang terkait.</string>\n    <string name=\"perm_activity_recognition_label\">Pengenalan aktivitas</string>\n    <string name=\"perm_activity_recognition_description\">Memungkinkan aplikasi untuk menerima pembaruan berkala tentang tingkat aktivitas Anda dari Google, misalnya, jika Anda sedang berjalan kaki, mengemudi, bersepeda, atau diam di tempat.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_activity\">Lihat riwayat aktivitas Google Apps Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.buyer\">Kelola konfigurasi akun pembeli Ad Exchange Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller.readonly\">Lihat data Ad Exchange Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller\">Lihat dan kelola data Ad Exchange Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsensehost\">Lihat dan kelola data host AdSense Anda dan akun terkait</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense.readonly\">Lihat data AdSense Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense\">Lihat dan kelola data AdSense Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics.readonly\">Lihat data Google Analytics Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics\">Lihat dan kelola data Google Analytics Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_androidpublisher\">Akses ke Google Play untuk Pengembang Android</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appengine.admin\">Ruang lingkup admin App Engine.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.migration\">Akses baca dan tulis ke API Migrasi Grup.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.settings\">Lihat dan kelola pengaturan Grup Google Apps</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.licensing\">Akses baca/tulis ke API Pengelola Lisensi.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order\">Bagi administrator dan pengguna reseller, akses baca/tulis saat melakukan pengujian di sandbox API, atau akses baca/tulis saat memanggil operasi API secara langsung.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order.readonly\">Selain ruang lingkup OAuth baca/tulis secara keseluruhan, gunakan ruang lingkup OAuth baca saja saat mengambil data pelanggan.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps_reporting_audit.readonly\">Akses ke API Audit Admin (Hanya Baca)</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appstate\">Ruang lingkup penggunaan layanan App State.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery.readonly\">Lihat data Anda di Google BigQuery</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery\">Lihat dan kelola data Anda di Google BigQuery</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger\">Kelola akun Blogger Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger.readonly\">Lihat akun Blogger Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_books\">Kelola buku-buku Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar\">Kelola kalender Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar.readonly\">Lihat kalender Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_cloudprint\">Lihat dan kelola data Google Cloud Print Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute.readonly\">Lihat sumber daya Google Compute Engine Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute\">Lihat dan kelola sumber daya Google Compute Engine Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate.readonly\">Lihat pekerjaan koordinat Google Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate\">Lihat dan kelola pekerjaan koordinat Google Maps Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.full_control\">Kelola data dan izin Anda di Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_only\">Lihat data Anda di Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_write\">Kelola data Anda di Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_dfareporting\">Lihat dan kelola laporan DoubleClick for Advertisers</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.appdata\">Mengizinkan akses ke folder Data Aplikasi</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.apps.readonly\">Lihat aplikasi Google Drive Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.file\">Lihat dan kelola file Google Drive yang telah Anda buka atau buat menggunakan aplikasi ini</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.install\">Ruang lingkup khusus yang digunakan untuk memungkinkan pengguna menyetujui instalasi aplikasi</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.metadata.readonly\">Lihat metadata untuk file dan dokumen di Google Drive Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.readonly\">Lihat file dan dokumen di Google Drive Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.scripts\">Ubah perilaku skrip Google Apps Script Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive\">Lihat dan kelola file dan dokumen di Google Drive Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase.readonly\">lihat akun Freebase Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase\">Masuk ke Freebase dengan akun Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables\">Kelola Fusion Tables Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables.readonly\">Lihat Fusion Tables Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_games\">Izin untuk mengakses data dari Google Play Games.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan\">Kelola data GAN Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan.readonly\">Lihat data GAN Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gcm_for_chrome\">CloudMessaging untuk Chrome</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_glass.timeline\">Rentang waktu kaca</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.compose\">Buat, baca, perbarui, dan hapus draf. Kirim pesan dan draf.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.modify\">Semua operasi baca/tulis kecuali penghapusan langsung dan permanen thread dan pesan, melewati folder Sampah.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.readonly\">Baca semua sumber daya dan metadata mereka—tanpa operasi penulisan.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.best\">Kelola lokasi terbaik yang tersedia dan riwayat lokasi Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.city\">Kelola lokasi tingkat kota dan riwayat lokasi Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.best\">Kelola lokasi terbaik yang tersedia</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.city\">Kelola lokasi tingkat kota Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine\">Lihat dan kelola data Google Maps Engine Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine.readonly\">Lihat data Google Maps Engine Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mobilemaps.firstparty\">Lihat dan kelola pengalaman Google Maps Anda di perangkat seluler</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut\">Kelola aktivitas Orkut Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut.readonly\">Lihat data Orkut Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.login\">Ketahui nama Anda, informasi dasar, dan daftar orang yang terhubung dengan Anda di Google+</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.me\">Kenali diri Anda di Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_prediction\">Kelola data Anda di Google Prediction API</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_shoppingapi\">Lihat data produk Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification\">Kelola daftar situs dan domain yang Anda kendalikan</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification.verify_only\">Kelola verifikasi situs baru Anda dengan Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_structuredcontent\">Akses baca/tulis ke Shopping Content API.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue.consumer\">Mengambil tugas dari antrian tugas Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue\">Kelola Tugas Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks\">Kelola tugas Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks.readonly\">Lihat tugas Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tracks\">Google Maps Tracks API, Ruang lingkup ini memungkinkan akses baca dan tulis ke data proyek Anda.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_urlshortener\">Kelola URL pendek goo.gl Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.email\">Lihat alamat email Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.profile\">Lihat informasi dasar tentang akun Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube\">Kelola akun YouTube Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtubepartner\">Lihat dan kelola aset Anda dan konten terkait di YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.readonly\">Lihat akun YouTube Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.upload\">Kelola video YouTube Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics_monetary.readonly\">Lihat laporan keuangan YouTube Analytics untuk konten YouTube Anda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics.readonly\">Lihat laporan YouTube Analytics untuk konten YouTube Anda</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-in/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <plurals name=\"pref_unifiednlp_summary\">\n        <item quantity=\"other\"><xliff:g example=\"1\">%1$d</xliff:g> konfigurasi backend selesai</item>\n    </plurals>\n    <plurals name=\"gcm_registered_apps_counter\">\n        <item quantity=\"other\"><xliff:g example=\"1\">%1$d</xliff:g> Aplikasi Terdaftar</item>\n    </plurals>\n    <plurals name=\"cond_perm_summary\">\n        <item quantity=\"other\">Izin yang diperlukan untuk fungsionalitas Layanan microG yang tepat tidak diberikan.</item>\n    </plurals>\n    <plurals name=\"cond_perm_action\">\n        <item quantity=\"other\">Minta izin yang hilang</item>\n    </plurals>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-in/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=\"gms_app_name\">Layanan microG</string>\n    <string name=\"limited_services_app_name\">Layanan Terbatas microG</string>\n    <string name=\"gms_settings_name\">Pengaturan microG</string>\n    <string name=\"gms_settings_summary\">Konfigurasikan layanan microG.</string>\n    <string name=\"just_a_sec\">Tunggu sebentar…</string>\n    <string name=\"google_account_label\">Google</string>\n    <string name=\"ask_permission_tos\">Dengan melanjutkan, Anda memberikan izin kepada aplikasi ini dan Google untuk menggunakan informasi Anda sesuai dengan syarat dan ketentuan serta kebijakan privasi masing-masing.</string>\n    <string name=\"ask_scope_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> ingin:</string>\n    <string name=\"ask_service_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> ingin menggunakan:</string>\n    <string name=\"account_manager_title\">Manajer Akun Google</string>\n    <string name=\"sorry\">Maaf…</string>\n    <string name=\"auth_before_connect\">Sebuah aplikasi di perangkat Anda mencoba masuk ke akun Google.\\n\\nJika ini disengaja, gunakan tombol <b>Masuk</b> untuk terhubung ke halaman masuk Google, jika tidak, tekan <b>Batal</b> untuk kembali ke aplikasi yang menyebabkan dialog ini muncul.</string>\n    <string name=\"auth_sign_in\">Masuk</string>\n    <string name=\"auth_connecting\">Perangkat Anda sedang terhubung ke server Google untuk masuk.\\n\\nProses ini dapat memakan waktu beberapa detik.</string>\n    <string name=\"no_network_error_desc\">Anda tidak terhubung ke jaringan.\\n\\nIni mungkin masalah sementara atau perangkat Android Anda mungkin belum diaktifkan untuk layanan data. Coba lagi saat terhubung ke jaringan seluler, atau sambungkan ke jaringan Wi-Fi.</string>\n    <string name=\"auth_general_error_desc\">Ada masalah dalam berkomunikasi dengan server Google.\\n\\nCoba lagi nanti.</string>\n    <string name=\"auth_finalize\">Perangkat Anda sedang terhubung ke Google untuk menyimpan informasi ke akun Anda.\\n\\nProses ini dapat memakan waktu beberapa menit.</string>\n    <string name=\"allow\">Izinkan</string>\n    <string name=\"deny\">Tolak</string>\n    <string name=\"auth_notification_title\">Otentikasi diperlukan</string>\n    <string name=\"auth_notification_content\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> memerlukan izin Anda untuk mengakses akun Google Anda.</string>\n    <string name=\"auth_package_override_request_title\">Izinkan <b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> akses istimewa ke <xliff:g example=\"account@example.com\">%2$s</xliff:g>\\?</string>\n    <string name=\"auth_package_override_request_message\"><b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> ingin mengakses akun Anda seolah-olah itu adalah <b><xliff:g example=\"F-Droid\">%2$s</xliff:g> oleh <xliff:g example=\"F-Droid Inc.\">%3$s</xliff:g></b>. Hal ini mungkin memberikan akses istimewa ke akun Anda.</string>\n    <string name=\"auth_action_notification_channel_name\">Pemberitahuan akun Google</string>\n    <string name=\"auth_action_notification_channel_description\">Memberikan pemberitahuan ketika salah satu akun Google Anda memerlukan pengaturan tambahan sebelum dapat digunakan atau ketika akun tersebut tidak kompatibel dengan microG.</string>\n    <string name=\"auth_action_notification_title\">Tindakan akun diperlukan</string>\n    <string name=\"auth_action_notification_content\">Akun Google Anda memerlukan pengaturan tambahan.</string>\n    <string name=\"auth_action_reauth_notification_title\">Tindakan akun diperlukan</string>\n    <string name=\"auth_action_activity_header\">Selesaikan pengaturan akun Google Anda</string>\n    <string name=\"auth_action_activity_explanation\">Lakukan langkah-langkah berikut untuk dapat menggunakan akun Google Anda %s di perangkat ini.</string>\n    <string name=\"auth_action_step_enable_checkin\">Aktifkan pendaftaran perangkat</string>\n    <string name=\"auth_action_step_enable_checkin_description\">Perangkat Anda perlu mendaftar ke Google setidaknya sekali.\\n\\nAnda dapat menonaktifkan pendaftaran perangkat Google setelah pengaturan akun selesai.</string>\n    <string name=\"auth_action_step_enable_gcm\">Aktifkan Cloud Messaging</string>\n    <string name=\"auth_action_step_enable_gcm_description\">Anda dapat menonaktifkan Cloud Messaging setelah proses pengaturan akun selesai.</string>\n    <string name=\"auth_action_step_allow_microg_gcm\">Izinkan Cloud Messaging untuk microG</string>\n    <string name=\"auth_action_step_allow_microg_gcm_description\">Sesuai dengan preferensi Anda, microG memerlukan izin dari Anda sebelum dapat mendaftarkan dirinya untuk Cloud Messaging.</string>\n    <string name=\"auth_action_step_enable_lockscreen\">Konfigurasikan kunci layar aman</string>\n    <string name=\"auth_action_step_enable_lockscreen_description\">Akun Google Anda dikelola oleh tempat kerja atau institusi pendidikan Anda. Administrator Anda telah memutuskan bahwa perangkat memerlukan kunci layar yang aman sebelum dapat mengakses data akun.\\n\\nSilakan atur kata sandi, PIN, atau pola kunci layar.</string>\n    <string name=\"auth_action_step_perform_content_description\">Klik untuk melakukan langkah</string>\n    <string name=\"auth_action_step_completed_content_description\">Langkah selesai</string>\n    <string name=\"auth_action_activity_finish\">Selesai</string>\n    <string name=\"signin_picker_title\">Pilih akun</string>\n    <string name=\"signin_picker_subtitle\">untuk melanjutkan ke <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"signin_picker_add_account_label\">Tambahkan akun lain</string>\n    <string name=\"signin_confirm_title\">Izinkan untuk masuk ke <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"signin_confirm_button_text\">Izinkan dan bagikan</string>\n    <string name=\"signin_subtext_sharing\">Untuk melanjutkan, microG akan membagikan nama, alamat email, dan foto profil Akun Google Anda dengan <xliff:g example=\"F-Droid\">%1$s</xliff:g>.</string>\n    <string name=\"signin_subtext_policy\">Sebelum menggunakan aplikasi ini, periksa %1$s dan %2$s.</string>\n    <string name=\"signin_subtext_policy_privacy\">kebijakan privasi</string>\n    <string name=\"signin_subtext_policy_terms\">syarat dan ketentuan</string>\n    <string name=\"perm_status_broadcast_label\">dengarkan siaran status internal</string>\n    <string name=\"perm_gsf_read_gservices_label\">baca konfigurasi layanan Google</string>\n    <string name=\"perm_c2dm_receive_label\">mendengarkan pesan C2DM</string>\n    <string name=\"perm_c2dm_send_label\">kirim pesan C2DM ke aplikasi lain</string>\n    <string name=\"perm_gtalk_svc_label\">bertukar pesan dan menerima pemberitahuan sinkronisasi dari server Google</string>\n    <string name=\"perm_extended_access_label\">Akses yang diperluas ke layanan Google</string>\n    <string name=\"perm_provision_label\">penyediaan layanan microG</string>\n    <string name=\"perm_provision_description\">mengizinkan aplikasi untuk mengonfigurasi layanan microG tanpa interaksi pengguna</string>\n    <string name=\"perm_car_speed_label\">Kecepatan mobil</string>\n    <string name=\"perm_car_speed_description\">Periksa kecepatan mobil Anda</string>\n    <string name=\"perm_car_info_label\">Informasi mobil</string>\n    <string name=\"perm_car_info_description\">Akses informasi mobil Anda</string>\n    <string name=\"perm_car_fuel_label\">Tingkat bahan bakar mobil</string>\n    <string name=\"perm_car_fuel_description\">Akses informasi tingkat bahan bakar mobil Anda</string>\n    <string name=\"perm_car_mileage_label\">Jarak tempuh mobil</string>\n    <string name=\"perm_car_mileage_description\">Akses informasi jarak tempuh mobil Anda</string>\n    <string name=\"perm_car_vendor_extension_label\">Saluran penjualan mobil</string>\n    <string name=\"perm_car_vendor_extension_description\">Akses saluran vendor mobil Anda untuk bertukar informasi yang spesifik tentang mobil</string>\n    <string name=\"service_name_checkin\">Pendaftaran perangkat Google</string>\n    <string name=\"service_name_mcs\">Cloud Messaging</string>\n    <string name=\"service_name_snet\">Google SafetyNet</string>\n    <string name=\"service_name_vending\">Play Store services</string>\n    <string name=\"service_name_work_profile\">Profil pekerjaan</string>\n    <string name=\"games_title\">Google Play Games</string>\n    <string name=\"games_info_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> ingin menggunakan Play Games</string>\n    <string name=\"games_info_content\">Untuk menggunakan Play Games, Anda perlu menginstal aplikasi Google Play Games. Aplikasi tersebut mungkin tetap dapat digunakan tanpa Play Games, tetapi ada kemungkinan aplikasi tersebut akan berperilaku tidak terduga.</string>\n    <string name=\"pick_place_title\">Pilih tempat</string>\n    <string name=\"pick_place_desc\">Pemilih lokasi belum tersedia.</string>\n    <string name=\"place_picker_select_title\">Pilih lokasi ini</string>\n    <string name=\"place_picker_nearby_places\">Tempat-tempat terdekat</string>\n    <string name=\"place_picker_location_lat_lng\">(%1$.7f, %2$.7f)</string>\n    <string name=\"lacking_permission_toast\">Layanan microG: Tidak memiliki izin untuk <xliff:g example=\"memiliki akses jaringan penuh\">%1$s</xliff:g></string>\n    <string name=\"network_type_mobile\">Jaringan seluler</string>\n    <string name=\"network_type_wifi\">Wi-Fi</string>\n    <string name=\"network_type_roaming\">Roaming</string>\n    <string name=\"network_type_other\">Jaringan lain</string>\n    <string name=\"self_check_cat_fake_sig\">Dukungan pemalsuan tanda tangan</string>\n    <string name=\"self_check_cat_gms_packages\">Paket yang diinstal</string>\n    <string name=\"self_check_cat_system\">Sistem</string>\n    <string name=\"self_check_name_fake_sig_perm\">Sistem mendukung pemalsuan tanda tangan:</string>\n    <string name=\"self_check_resolution_fake_sig_perm\">ROM Anda tidak memiliki dukungan bawaan untuk pemalsuan tanda tangan. Anda masih dapat menggunakan Xposed atau sistem lain untuk memalsukan tanda tangan. Silakan periksa dokumentasi mengenai ROM mana yang mendukung pemalsuan tanda tangan dan cara menggunakan microG pada ROM yang tidak mendukungnya.</string>\n    <string name=\"self_check_name_perm_granted\">Sistem memberikan izin untuk memalsukan tanda tangan:</string>\n    <string name=\"self_check_resolution_perm_granted\">Ini merupakan indikasi kuat bahwa ROM memang mendukung pemalsuan tanda tangan, namun memerlukan tindakan lebih lanjut untuk mengaktifkannya. Silakan periksa dokumentasi untuk mengetahui langkah-langkah yang mungkin diperlukan.</string>\n    <string name=\"self_check_name_system_spoofs\">Sistem memalsukan tanda tangan:</string>\n    <string name=\"self_check_resolution_system_spoofs\">Silakan periksa dokumentasi untuk mengetahui langkah-langkah apa saja yang mungkin diperlukan.</string>\n    <string name=\"self_check_pkg_gms\">Layanan microG</string>\n    <string name=\"self_check_pkg_vending\">microG Companion / Toko Play</string>\n    <string name=\"self_check_pkg_gsf\">Kerangka Kerja Layanan microG</string>\n    <string name=\"self_check_name_app_installed\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> terpasang:</string>\n    <string name=\"self_check_resolution_app_installed\">Instal aplikasi <xliff:g example=\"F-Droid\">%1$s</xliff:g> atau aplikasi yang kompatibel. Silakan periksa dokumentasi untuk mengetahui aplikasi mana yang kompatibel.</string>\n    <string name=\"self_check_name_correct_sig\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> memiliki tanda tangan yang benar:</string>\n    <string name=\"self_check_resolution_correct_sig\">Baik file terinstal <xliff:g example=\"F-Droid\">%1$s</xliff:g> tidak kompatibel atau fitur spoofing tanda tangan tidak aktif untuknya. Silakan periksa dokumentasi untuk mengetahui aplikasi dan ROM mana yang kompatibel.</string>\n    <string name=\"self_check_name_battery_optimizations\">Optimasi baterai diabaikan:</string>\n    <string name=\"self_check_resolution_battery_optimizations\">Ketuk di sini untuk menonaktifkan pengoptimalan baterai. Jika tidak dilakukan, hal ini dapat menyebabkan aplikasi bermasalah.</string>\n    <string name=\"prefcat_about\">Tentang</string>\n    <string name=\"prefcat_components\">Komponen</string>\n    <string name=\"prefcat_configuration\">Konfigurasi</string>\n    <string name=\"prefcat_google_services\">Layanan Google</string>\n    <string name=\"prefcat_location_service\">Layanan lokasi</string>\n    <string name=\"prefcat_services\">Layanan</string>\n    <string name=\"prefcat_test\">Uji</string>\n    <string name=\"cond_gcm_bat_title\">Optimasi baterai diaktifkan</string>\n    <string name=\"cond_gcm_bat_summary\">Anda telah mengaktifkan Cloud Messaging, tetapi pengoptimalan baterai untuk microG Services masih aktif. Agar notifikasi push dapat diterima, Anda harus menonaktifkan pengoptimalan baterai.</string>\n    <string name=\"cond_gcm_bat_action\">Abaikan optimasi</string>\n    <string name=\"cond_perm_title\">Izin tidak ada</string>\n    <string name=\"prefs_account\">Pengaturan akun</string>\n    <string name=\"prefs_account_privacy\">Informasi pribadi &amp; privasi</string>\n    <string name=\"prefs_account_security\">Masuk &amp; Keamanan</string>\n    <string name=\"pref_auth_trust_google_title\">Percayalah pada Google untuk izin aplikasi</string>\n    <string name=\"pref_auth_trust_google_summary\">Ketika fitur ini dinonaktifkan, pengguna akan diminta persetujuan sebelum permintaan otorisasi aplikasi dikirim ke Google. Beberapa aplikasi mungkin tidak dapat menggunakan akun Google jika fitur ini dinonaktifkan.</string>\n    <string name=\"pref_auth_visible_title\">Izinkan aplikasi untuk menemukan akun</string>\n    <string name=\"pref_auth_visible_summary\">Jika diaktifkan, semua aplikasi di perangkat ini akan dapat melihat alamat email Akun Google Anda tanpa persetujuan sebelumnya.</string>\n    <string name=\"pref_auth_include_android_id_title\">Otentikasi dengan pendaftaran perangkat</string>\n    <string name=\"pref_auth_include_android_id_summary\">Ketika dinonaktifkan, permintaan otentikasi tidak akan terhubung dengan pendaftaran perangkat, yang mungkin memungkinkan perangkat yang tidak sah untuk masuk, tetapi dapat menimbulkan konsekuensi yang tidak terduga.</string>\n    <string name=\"pref_auth_strip_device_name_title\">Hapus nama perangkat untuk otentikasi</string>\n    <string name=\"pref_auth_strip_device_name_summary\">Ketika diaktifkan, permintaan otentikasi tidak akan menyertakan nama perangkat, yang bisa memungkinkan perangkat yang tidak berwenang untuk masuk, tetapi hal ini mungkin memiliki konsekuensi yang tidak terduga.</string>\n    <string name=\"pref_auth_two_step_verification_title\">Menerima permintaan verifikasi dua langkah</string>\n    <string name=\"pref_auth_two_step_verification_summary\">Saat diaktifkan, perangkat dapat menerima permintaan verifikasi dua langkah dari Google (Cloud Messaging diperlukan).</string>\n    <string name=\"pref_checkin_enable_summary\">Mendaftarkan perangkat Anda ke layanan Google dan membuat identifikasi perangkat unik. microG menghapus bagian identifikasi selain nama akun Google Anda dari data pendaftaran.</string>\n    <string name=\"pref_device_registration_android_id\">ID Android</string>\n    <string name=\"checkin_not_registered\">Belum terdaftar</string>\n    <string name=\"checkin_last_registration\">Pendaftaran terakhir: <xliff:g example=\"Kemarin, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"checkin_enable_switch\">Daftarkan perangkat</string>\n    <string name=\"pref_info_status\">Status</string>\n    <string name=\"pref_more_settings\">Lebih banyak</string>\n    <string name=\"pref_accounts_title\">Akun Google</string>\n    <string name=\"pref_game_accounts_title\">Akun Game Google</string>\n    <string name=\"pref_accounts_summary\">Tambahkan dan kelola akun Google</string>\n    <string name=\"prefcat_accounts_settings_title\">Pengaturan</string>\n    <string name=\"prefcat_accounts_current_accounts_title\">Akun</string>\n    <string name=\"pref_add_account_title\">Akun</string>\n    <string name=\"pref_add_account_summary\">Tambahkan akun Google</string>\n    <string name=\"pref_gcm_enable_mcs_summary\">Cloud Messaging adalah penyedia notifikasi push yang digunakan oleh banyak aplikasi pihak ketiga. Untuk menggunakannya, Anda harus mengaktifkan pendaftaran perangkat.</string>\n    <string name=\"pref_gcm_heartbeat_title\">Interval detak jantung pesan cloud</string>\n    <string name=\"pref_gcm_heartbeat_summary\">Interval dalam detik untuk sistem melakukan heartbeat ke server Google. Meningkatkan angka ini akan mengurangi konsumsi baterai, tetapi mungkin menyebabkan penundaan pada pesan push.\\nSudah tidak digunakan lagi, akan diganti pada rilis mendatang.</string>\n    <string name=\"pref_gcm_apps_title\">Aplikasi yang menggunakan Layanan Cloud Messaging</string>\n    <string name=\"pref_gcm_apps_summary\">Daftar aplikasi yang saat ini terdaftar untuk Cloud Messaging.</string>\n    <string name=\"pref_gcm_confirm_new_apps_title\">Konfirmasi aplikasi baru</string>\n    <string name=\"pref_gcm_confirm_new_apps_summary\">Mohon konfirmasi terlebih dahulu sebelum mendaftarkan aplikasi baru untuk menerima notifikasi push</string>\n    <string name=\"pref_gcm_ping_interval\">Interval ping: <xliff:g example=\"10 menit\">%1$s</xliff:g></string>\n    <string name=\"pref_about_title\">Tentang Layanan microG</string>\n    <string name=\"pref_about_summary\">Informasi versi dan perpustakaan yang digunakan</string>\n    <string name=\"gcm_app_error_unregistering\">Kesalahan saat membatalkan pendaftaran</string>\n    <string name=\"gcm_app_not_installed_anymore\">Tidak lagi terpasang</string>\n    <string name=\"gcm_unregister_app\">Batalkan pendaftaran</string>\n    <string name=\"gcm_not_registered\">Belum terdaftar</string>\n    <string name=\"gcm_no_message_yet\">Belum ada pesan yang diterima hingga saat ini</string>\n    <string name=\"gcm_last_message_at\">Pesan terakhir: <xliff:g example=\"Kemarin, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_registered\">Terdaftar</string>\n    <string name=\"gcm_registered_since\">Daftar sejak: <xliff:g example=\"Kemarin, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_unregister_confirm_title\">Batalkan pendaftaran <xliff:g example=\"F-Droid\">%1$s</xliff:g>\\?</string>\n    <string name=\"gcm_unregister_confirm_message\">Beberapa aplikasi tidak secara otomatis mendaftar ulang dan/atau tidak menyediakan opsi untuk melakukannya secara manual. Aplikasi-aplikasi ini mungkin tidak berfungsi dengan benar setelah proses unregistering.\\nLanjutkan?</string>\n    <string name=\"gcm_unregister_after_deny_message\">Anda telah menolak pendaftaran aplikasi untuk notifikasi push yang sebenarnya sudah terdaftar.\\nApakah Anda ingin membatalkan pendaftarannya sekarang agar tidak menerima notifikasi push di masa mendatang?</string>\n    <string name=\"gcm_messages_counter\">Pesan: <xliff:g example=\"123\">%1$d</xliff:g> (<xliff:g example=\"12345\">%2$d</xliff:g> byte)</string>\n    <string name=\"gcm_network_state_disconnected\">Terputus</string>\n    <string name=\"gcm_network_state_connected\">Terhubung sejak <xliff:g example=\"2 jam yang lalu\">%1$s</xliff:g></string>\n    <string name=\"gcm_enable_switch\">Terima pemberitahuan push</string>\n    <string name=\"gcm_allow_app_popup\">Izinkan <xliff:g example=\"F-Droid\">%1$s</xliff:g> untuk mendaftar notifikasi push?</string>\n    <string name=\"pref_push_app_allow_register_title\">Izinkan pendaftaran</string>\n    <string name=\"pref_push_app_allow_register_summary\">Izinkan aplikasi untuk mendaftar untuk pemberitahuan push.</string>\n    <string name=\"pref_push_app_wake_for_delivery_title\">Jalankan aplikasi saat menerima pesan push</string>\n    <string name=\"pref_push_app_wake_for_delivery_summary\">Jalankan aplikasi di latar belakang untuk menerima pesan push yang masuk.</string>\n    <string name=\"prefcat_push_apps_title\">Aplikasi yang menggunakan notifikasi push</string>\n    <string name=\"prefcat_push_apps_registered_title\">Aplikasi terdaftar</string>\n    <string name=\"prefcat_push_apps_unregistered_title\">Aplikasi yang tidak terdaftar</string>\n    <string name=\"prefcat_push_networks_title\">Jaringan yang digunakan untuk pemberitahuan push</string>\n    <string name=\"safetynet_intro\">Google SafetyNet adalah sistem sertifikasi perangkat yang memastikan perangkat tersebut aman dan kompatibel dengan Android CTS. Beberapa aplikasi menggunakan SafetyNet untuk alasan keamanan atau sebagai prasyarat untuk perlindungan terhadap manipulasi.\\n\\nmicroG GmsCore mengandung implementasi gratis dari SafetyNet, tetapi server resmi mengharuskan permintaan SafetyNet ditandatangani menggunakan sistem DroidGuard yang eksklusif.</string>\n    <string name=\"safetynet_enable_switch\">Izinkan verifikasi perangkat</string>\n    <string name=\"pref_safetynet_test_title\">Uji Sertifikasi SafetyNet</string>\n    <string name=\"pref_recaptcha_test_title\">Uji ReCAPTCHA</string>\n    <string name=\"pref_recaptcha_enterprise_test_title\">Uji Coba ReCAPTCHA Enterprise</string>\n    <string name=\"pref_test_summary_passed\">Lulus semua tes</string>\n    <string name=\"pref_test_summary_failed\">Gagal: %s</string>\n    <string name=\"pref_test_summary_warn\">Peringatan: %s</string>\n    <string name=\"pref_test_summary_running\">Berjalan…</string>\n    <string name=\"pref_droidguard_operation_mode\">Mode operasi</string>\n    <string name=\"pref_droidguard_unsupported_summary\">Eksekusi DroidGuard tidak didukung pada perangkat ini. Layanan SafetyNet mungkin tidak berfungsi dengan baik.</string>\n    <string name=\"prefcat_safetynet_apps_title\">Aplikasi yang menggunakan SafetyNet</string>\n    <string name=\"menu_clear_recent_requests\">Hapus permintaan terbaru</string>\n    <string name=\"safetynet_last_run_at\">Penggunaan terakhir: <xliff:g example=\"Kemarin, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"profile_name_native\">Asli</string>\n    <string name=\"profile_name_real\">Sebenarnya</string>\n    <string name=\"profile_name_user\">Kustom: %s</string>\n    <string name=\"profile_name_auto\">Otomatis: %s</string>\n    <string name=\"profile_name_system\">Sistem: %s</string>\n    <string name=\"pref_device_registration_import_custom_profile_title\">Impor profil kustom</string>\n    <string name=\"pref_device_registration_serial_title\">Serial</string>\n    <string name=\"pref_device_registration_import_custom_profile_summary\">Impor profil perangkat dari file</string>\n    <string name=\"pref_device_registration_select_profile_title\">Pilih profil</string>\n    <string name=\"pref_device_registration_device_profile_category\">Profil perangkat</string>\n    <string name=\"pref_safetynet_recent_uses\">Penggunaan terbaru</string>\n    <string name=\"pref_safetynet_recent_attestation_summary\">Pengesahan: %s</string>\n    <string name=\"pref_safetynet_recent_recaptcha_summary\">ReCaptcha: %s</string>\n    <string name=\"pref_safetynet_recent_recaptcha_enterprise_summary\">ReCaptcha Enterprise: %s</string>\n    <string name=\"pref_safetynet_recent_copy_json\">Salin data JSON JWS</string>\n    <string name=\"pref_safetynet_recent_advice\">Saran</string>\n    <string name=\"pref_safetynet_recent_eval_type\">Jenis evaluasi</string>\n    <string name=\"pref_safetynet_recent_response_status\">Status respons</string>\n    <string name=\"pref_safetynet_recent_cat_response\">Data respons</string>\n    <string name=\"pref_safetynet_recent_cat_request\">Minta data</string>\n    <string name=\"pref_safetynet_recent_nonce\">Nonce (Hex)</string>\n    <string name=\"pref_safetynet_recent_request_time\">Waktu permintaan</string>\n    <string name=\"pref_safetynet_recent_request_type\">Jenis permintaan</string>\n    <string name=\"pref_safetynet_recent_cat_basic\">Data dasar</string>\n    <string name=\"pref_safetynet_recent_token\">Token</string>\n    <string name=\"pref_safetynet_recent_copied\">Telah disalin ke clipboard!</string>\n    <string name=\"pref_safetynet_test_integrity_cts_passed\">Integritas dan CTS telah lulus</string>\n    <string name=\"pref_safetynet_test_cts_failed\">CTS gagal</string>\n    <string name=\"pref_safetynet_test_integrity_failed\">Integritas gagal</string>\n    <string name=\"pref_safetynet_test_not_completed\">Belum selesai</string>\n    <string name=\"pref_safetynet_test_no_result\">Tidak ada hasil</string>\n    <string name=\"pref_safetynet_test_invalid_json\">JSON tidak valid</string>\n    <string name=\"push_notifications_summary_off\">OFF</string>\n    <string name=\"push_notifications_summary_automatic\">ON / Otomatis: %s</string>\n    <string name=\"push_notifications_summary_manual\">ON / Manual: %s</string>\n    <string name=\"push_notifications_summary_values_seconds\">%s detik</string>\n    <string name=\"push_notifications_summary_values_minutes\">%s menit</string>\n    <string name=\"pref_vending_summary_licensing_off\">Lisensi dimatikan</string>\n    <string name=\"pref_vending_summary_licensing_on\">Lisensi diaktifkan</string>\n    <string name=\"pref_vending_licensing_category\">Lisensi Google Play</string>\n    <string name=\"pref_vending_licensing_enable_switch\">Menanggapi permintaan verifikasi lisensi</string>\n    <string name=\"pref_vending_license_enable_summary\">Beberapa aplikasi memerlukan verifikasi bahwa Anda telah membelinya di Google Play. Saat diminta oleh aplikasi, microG dapat mengunduh bukti pembelian dari Google. Jika dinonaktifkan, atau jika tidak ada akun Google yang ditambahkan, permintaan verifikasi lisensi akan diabaikan.</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_switch\">Tambahkan aplikasi gratis secara otomatis ke perpustakaan</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_summary\">Aplikasi gratis dapat memeriksa apakah mereka telah diunduh dari Google Play. Tambahkan secara otomatis aplikasi gratis ke perpustakaan akun Anda agar selalu lolos pemeriksaan untuk semua aplikasi gratis yang saat ini tersedia bagi Anda.</string>\n    <string name=\"pref_vending_feature_delivery\">Pengiriman Fitur Google Play</string>\n    <string name=\"pref_vending_split_install_switch\">Memasang komponen sesuai permintaan</string>\n    <string name=\"pref_vending_licensing_split_install_summary\">Izinkan aplikasi untuk mengunduh dan memasang komponen tambahan</string>\n    <string name=\"feedback_disabled\">Umpan balik saat ini tidak tersedia</string>\n    <string name=\"backup_disabled\">Pencadangan saat ini tidak mungkin dilakukan</string>\n    <string name=\"pref_vending_billing_category\">Penagihan Google Play</string>\n    <string name=\"pref_vending_billing_enable_switch\">Tangani permintaan penagihan</string>\n    <string name=\"pref_vending_billing_enable_summary\">Setelah diaktifkan, beberapa aplikasi dapat melakukan pembelian atau memulai langganan melalui layanan Google Play Billing.</string>\n    <string name=\"pref_vending_billing_note_experimental\">Fitur ini masih dalam tahap percobaan dan dapat menyebabkan kerugian finansial. Anda telah diperingatkan.</string>\n    <string name=\"pref_vending_billing_note_licensing\">Beberapa aplikasi mungkin memerlukan Anda untuk mengaktifkan verifikasi lisensi guna memverifikasi pembelian Anda.</string>\n    <string name=\"pref_vending_asset_delivery_category\">Pengiriman Aset Google Play</string>\n    <string name=\"pref_vending_asset_delivery_switch\">Aktifkan pengiriman aset sesuai permintaan</string>\n    <string name=\"pref_vending_asset_delivery_summary\">Unduh aset tambahan saat diminta oleh aplikasi yang menggunakan Play Asset Delivery</string>\n    <string name=\"pref_vending_asset_device_sync_summary\">Aplikasi yang menggunakan Play Asset Delivery akan mengunduh aset tambahan berdasarkan informasi perangkat yang sedang digunakan.</string>\n    <string name=\"pref_vending_asset_device_sync_switch\">Aktifkan sinkronisasi informasi perangkat</string>\n    <string name=\"pref_workprofile_create_account\">Izinkan pengaturan akun kerja</string>\n    <string name=\"pref_workprofile_intro\">Saat membuat profil kerja untuk tempat kerja atau institusi pendidikan Anda, proses pengaturan mungkin mencoba terhubung ke Google untuk mengaktifkan unduhan aplikasi ke profil tersebut.</string>\n    <string name=\"pref_workprofile_disclaimer\">Anda bertanggung jawab untuk memastikan bahwa penggunaan microG Anda sesuai dengan kebijakan perusahaan. microG disediakan berdasarkan upaya terbaik dan tidak dapat menjamin bahwa perilakunya akan persis seperti yang diharapkan.</string>\n    <string name=\"pref_auto_create_player\">Izinkan pendaftaran akun Play Games</string>\n    <string name=\"pref_auto_create_player_intro\">Saat bermain game, Anda perlu menggunakan akun Play Games untuk masuk dan mencatat fungsi terkait game, seperti pencapaian, papan peringkat, arsip, dan sebagainya. Setelah dinonaktifkan, akun Google yang tidak terikat dengan akun Play Games tidak akan terdaftar secara otomatis, dan game tidak akan dapat masuk dan dimainkan.</string>\n    <string name=\"pref_allow_upload_game_played\">Izinkan pengunggahan permainan yang dimainkan</string>\n    <string name=\"pref_allow_upload_game_played_summary\">Ketika dinonaktifkan, permainan tidak akan melaporkan status permainan yang dimainkan setelah masuk ke dalam permainan, dan beberapa permainan mungkin tidak dapat masuk.</string>\n    <string name=\"pref_change_default_game_player\">Ubah akun untuk permainan</string>\n    <string name=\"pref_change_default_game_player_summary\">Ubah akun default untuk game &amp; Ubah akun per game.</string>\n    <string name=\"pref_delete_game_account_data\">Hapus data Play Games</string>\n    <string name=\"pref_delete_game_account_data_summary\">Hapus akun Play Games dan semua data, serta hapus data game secara individual.</string>\n    <string name=\"credentials_assisted_cancel\">Batalkan</string>\n    <string name=\"credentials_assisted_continue\">Lanjutkan</string>\n    <string name=\"credentials_assisted_confirmation_header\">Masuk ke akun Anda</string>\n    <string name=\"credentials_assisted_continue_as_user_button_label\">Lanjutkan sebagai %1$s</string>\n    <string name=\"credentials_assisted_sign_back_title\">Masuk kembali ke %1$s dengan Google</string>\n    <string name=\"credentials_assisted_signin_consent_header\">Menandatangani sebagai %1$s</string>\n    <string name=\"credentials_assisted_signin_consent\">Dengan melanjutkan, Google akan membagikan nama, alamat email, dan foto profil Anda dengan %1$s. Lihat Kebijakan Privasi dan Syarat Layanan %1$s.</string>\n    <string name=\"credentials_assisted_signin_description\">Anda dapat mengelola “Masuk dengan Google” di Akun Google Anda.</string>\n    <string name=\"credentials_assisted_choose_account_label\">Pilih akun</string>\n    <string name=\"credentials_assisted_choose_account_subtitle\">untuk melanjutkan ke %1$s</string>\n    <string name=\"credentials_assisted_choose_account_error_tips\">Ketidaknormalan akun</string>\n    <string name=\"credentials_assisted_signin_button_text_long\">Masuk dengan Google</string>\n    <string name=\"credentials_assisted_signin_add_account\">Tambahkan Akun</string>\n    <string name=\"limited_services_dialog_information\">Anda sedang menggunakan Layanan microG Terbatas. Berbeda dengan Layanan microG biasa, varian ini hanya berfungsi dengan aplikasi yang menggunakan perpustakaan microG, bukan yang ada di Google Play. Artinya, sebagian besar aplikasi akan mengabaikan layanan ini.</string>\n    <string name=\"limited_services_dialog_information_ack\">Saya mengerti</string>\n    <string name=\"games_achievement_list_title\">Prestasi</string>\n    <string name=\"games_achievements_empty_text\">Tidak ada pencapaian untuk permainan ini</string>\n    <string name=\"games_api_access_denied\">Tidak ada akun di perangkat ini yang dapat mengakses API Game</string>\n    <string name=\"games_achievement_locked_content_description\">terkunci</string>\n    <string name=\"games_achievement_unlocked_content_description\">terbuka</string>\n    <string name=\"games_achievement_extra_text\">%1$s XP</string>\n    <string name=\"games_leaderboard_empty_text\">Tidak ada papan peringkat untuk permainan ini</string>\n    <string name=\"games_leaderboard_score_empty_text\">Tak percaya! Tidak ada skor tertinggi publik untuk permainan ini.</string>\n    <string name=\"games_leaderboard_list_title\">Peringkat</string>\n    <string name=\"games_leaderboards_score_label\">Skor: %1$s</string>\n    <string name=\"games_snapshot_empty_text\">Belum ada file save game yang disimpan</string>\n    <string name=\"games_snapshot_choose_btn_text\">pilih</string>\n    <string name=\"games_snapshot_delete_btn_text\">hapus</string>\n    <string name=\"games_delete_snapshot_dialog_title\">Hapus permainan yang disimpan</string>\n    <string name=\"games_delete_snapshot_dialog_message\">Apakah Anda yakin ingin menghapus permainan yang disimpan ini?</string>\n    <string name=\"games_delete_snapshot_dialog_cancel\">Batalkan</string>\n    <string name=\"games_delete_snapshot_dialog_ok\">Oke</string>\n    <string name=\"games_delete_snapshot_error\">Penghapusan gagal, silakan coba lagi nanti</string>\n    <string name=\"games_state_description_signed_out\">Sudah keluar</string>\n    <string name=\"games_state_description_delete\">Hapus</string>\n    <string name=\"games_change_button_text\">Perubahan</string>\n    <string name=\"games_change_default_account_section_title\">Ubah akun default untuk permainan</string>\n    <string name=\"games_change_default_account_description\">Akun default: %1$s</string>\n    <string name=\"games_change_default_account_explanation\">Akun ini digunakan untuk secara otomatis masuk ke permainan, menyimpan kemajuan permainan Anda, dan menyimpan pengaturan Anda. Mengubah akun default atau keluar dari akun mungkin akan mereset kemajuan dan pengaturan permainan yang telah Anda mainkan.</string>\n    <string name=\"games_change_per_game_title\">Ubah akun melalui game</string>\n    <string name=\"games_change_per_game_description\">Mengubah akun untuk game yang dipilih atau keluar dari game tersebut mungkin akan mereset kemajuan dan pengaturan game Anda.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_title\">Pilih opsi untuk akun default baru</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_description\">Akun default saat ini: %1$s</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_title\">Ubah akun default hanya untuk game baru</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_description\">Anda tidak akan kehilangan akses ke progres dan pengaturan untuk game yang telah Anda mainkan. Namun, progres Anda akan dibagi antara akun-akun.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_title\">Ubah akun default untuk semua game</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_description\">Anda mungkin kehilangan akses ke progres dan pengaturan untuk game yang telah Anda mainkan. Kami akan me-restart game untuk menerapkan perubahan Anda.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_title\">Keluar dari semua permainan</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_description\">Anda mungkin kehilangan akses ke progres dan pengaturan untuk game yang telah Anda mainkan. Kami akan me-restart game untuk menerapkan perubahan Anda.</string>\n    <string name=\"games_change_per_game_dialog_title\">Pilih opsi untuk permainan ini</string>\n    <string name=\"games_change_per_game_dialog_description\">Mengubah akun atau keluar dari akun mungkin akan mereset kemajuan dan pengaturan permainan Anda</string>\n    <string name=\"games_change_per_game_dialog_option_use_player\">Gunakan %1$s</string>\n    <string name=\"games_change_per_game_dialog_option_use_player_snackbar_success_message\">Anda akan masuk ke dalam permainan ini dengan %1$s</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out\">Keluar</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out_snackbar_success_message\">Anda sekarang telah keluar dari permainan ini</string>\n    <string name=\"games_change_sign_out_of_all_games_snackbar_success_message\">Anda sekarang telah keluar dari semua permainan</string>\n    <string name=\"games_change_default_account_for_all_games_snackbar_success_message\">Anda akan masuk ke semua game dengan %1$s</string>\n    <string name=\"games_change_default_account_for_new_games_snackbar_success_message\">Anda akan masuk ke permainan baru dengan %1$s</string>\n    <string name=\"games_account_display_content\">Rekening koran: %1$s</string>\n    <string name=\"games_delete_profile_header\">Hapus akun Play Games dan semua data</string>\n    <string name=\"games_delete_profile_explanation\">Hapus secara permanen akun Google Play Games Anda, XP, dan semua data profil. Tindakan ini juga dapat menghapus skor, kemajuan (game yang disimpan), dan pengaturan dalam game yang telah Anda mainkan.</string>\n    <string name=\"games_delete_profile_button\">Hapus secara permanen</string>\n    <string name=\"games_delete_game_data_header\">Hapus data game secara individual</string>\n    <string name=\"games_delete_game_data_explanation\">Anda dapat menghapus secara permanen data individu untuk game yang telah Anda mainkan menggunakan Google Play Games. Tindakan ini akan menghapus skor, kemajuan (game yang disimpan), dan pengaturan untuk game yang Anda pilih.</string>\n    <string name=\"games_delete_profile_dialog_title\">Apakah Anda yakin ingin menghapus akun ini?</string>\n    <string name=\"games_delete_profile_explanation_with_gamer_name\">Hapus secara permanen akun Google Play Games Anda untuk nama pemain <b>%1$s</b> (<b>%2$s</b>), XP, dan semua data profil. Tindakan ini juga dapat menghapus skor, kemajuan (game yang disimpan), dan pengaturan dalam game yang telah Anda mainkan.</string>\n    <string name=\"games_delete_profile_dialog_message\">Tindakan ini tidak dapat dibatalkan.</string>\n    <string name=\"games_delete_profile_fail\">Tidak dapat menghapus profil Anda. Coba lagi nanti.</string>\n    <string name=\"games_delete_game_data_confirm_dialog_title\">Hapus data untuk %1$s</string>\n    <string name=\"games_delete_game_data_confirm_dialog_message\">Menghapus data Anda secara permanen untuk %1$s akan menghapus skor, progres (game yang disimpan), dan pengaturan game Anda di Google Play Games.</string>\n    <string name=\"games_popup_signin_welcome\">Halo, %1$s</string>\n    <string name=\"barcode_scanner_brand\">Dipindai oleh microG atas nama %1$s</string>\n    <string name=\"camera_permission_dialog_button\">Oke</string>\n    <string name=\"camera_permission_dialog_message\">Layanan microG memerlukan akses ke kamera perangkat Anda untuk memindai kode untuk %1$s.\\n\\nUntuk mengaktifkannya, silakan berikan izin kamera kepada layanan microG di Pengaturan.</string>\n    <string name=\"camera_permission_dialog_title\">Izin kamera diperlukan</string>\n    <string name=\"service_name_google_location_sharing\">Berbagi Lokasi Google</string>\n    <string name=\"location_sharing_description\">Kelola berbagi lokasi real-time Anda di seluruh aplikasi dan layanan Google dari perangkat ini</string>\n    <string name=\"location_sharing_learn_more\">Pelajari lebih lanjut tentang Berbagi Lokasi</string>\n    <string name=\"location_sharing_switch_text\">Gunakan Berbagi Lokasi</string>\n    <string name=\"location_sharing_turn_off_notify_hint\">Jika Anda mematikan Bagikan Lokasi untuk perangkat ini, orang-orang yang Anda bagikan lokasinya tidak akan menerima pemberitahuan.</string>\n    <string name=\"location_sharing_off_previous_hint\">Hanya lokasi terakhir yang Anda bagikan yang akan tersedia hingga Anda mengaktifkannya kembali.</string>\n    <string name=\"location_sharing_disabled\">Tidak ada berbagi lokasi aktif untuk akun ini</string>\n    <string name=\"location_sharing_turn_on_hint\">Setelah Anda mulai membagikan lokasi Anda dari aplikasi atau layanan Google, Anda dapat mengelola Pembagian Lokasi dari sini.\\n\\nUntuk mulai membagikan lokasi Anda, buka Google Maps atau Family Link.</string>\n    <string name=\"location_sharing_turn_off_title\">Matikan Bagikan Lokasi</string>\n    <string name=\"location_sharing_turn_off_hint\">Anda mungkin masih membagikan lokasi Anda dari perangkat lain yang masuk ke Akun Google yang sama atau dari aplikasi non-Google. Pastikan untuk memeriksa pengaturan berbagi lokasi Anda di mana pun pengaturan tersebut berlaku.\\n\\nOrang yang Anda bagikan lokasi dengan mereka akan terus melihat lokasi terakhir yang Anda bagikan.</string>\n    <string name=\"location_sharing_turn_off_cancel\">Teruskan</string>\n    <string name=\"location_sharing_turn_off_confirm\">Matikan</string>\n    <string name=\"location_sharing_confirm_dialog_title\">Aktifkan Berbagi Lokasi</string>\n    <string name=\"location_sharing_confirm_dialog_text\">Orang yang Anda bagikan lokasi Anda dengannya selalu dapat melihat:\\n·Nama dan foto Anda\\n·Lokasi terbaru perangkat Anda, bahkan saat Anda tidak menggunakan layanan Google\\n·Daya baterai perangkat Anda, dan apakah sedang diisi daya\\n·Waktu kedatangan dan keberangkatan Anda, jika mereka menambahkan pemberitahuan Berbagi Lokasi</string>\n    <string name=\"family_management_title\">Keluarga</string>\n    <string name=\"family_management_retry\">Coba lagi</string>\n    <string name=\"family_management_load_error\">Pemuatan konten gagal</string>\n    <string name=\"family_management_toolbar_back\">Kembali</string>\n    <string name=\"family_management_toolbar_more\">Lebih banyak</string>\n    <string name=\"family_management_exit_family_group\">Keluar dari grup keluarga</string>\n    <string name=\"family_management_delete_family_group\">Hapus grup keluarga</string>\n    <string name=\"family_management_leave_family_password_title\">Konfirmasi kata sandi untuk keluar dari grup keluarga</string>\n    <string name=\"family_management_delete_family_password_title\">Konfirmasi kata sandi untuk menghapus grup keluarga</string>\n    <string name=\"family_management_remove_member_password_title\">Konfirmasi kata sandi untuk menghapus %s</string>\n    <string name=\"family_management_invite_family_member\">Undang anggota keluarga</string>\n    <string name=\"family_management_invite_slots_left\">%1$d undangan tersisa</string>\n    <string name=\"family_management_cancel_invite\">Batalkan undangan</string>\n    <string name=\"family_management_cancel_invite_success\">Undangan telah berhasil dibatalkan</string>\n    <string name=\"family_management_cancel_invite_error\">Kesulitan membatalkan undangan. Coba lagi.</string>\n    <string name=\"family_management_remove_member\">Hapus Anggota</string>\n    <string name=\"family_management_member_removed_success\">%s telah dihapus dari grup keluarga Anda</string>\n    <string name=\"family_management_member_remove_failed\">Kesulitan menghapus %s. Coba lagi.</string>\n    <string name=\"family_management_leave_family_error_message\">Kesulitan meninggalkan grup keluarga. Coba lagi.</string>\n    <string name=\"family_management_exist_group_success\">Anda telah meninggalkan grup keluarga Anda…</string>\n    <string name=\"family_management_delete_group_success\">Grup keluarga dihapus</string>\n    <string name=\"family_management_delete_group_failure\">Gagal menghapus grup rumah</string>\n    <string name=\"family_management_delete_group_cancel\">Batalkan</string>\n    <string name=\"family_management_delete_group_confirm\">Oke</string>\n    <string name=\"family_management_input_pwd\">Silakan masukkan kata sandi Anda</string>\n    <string name=\"family_management_invite_sent_date_format\">Undangan dikirim pada %s</string>\n    <string name=\"family_management_invite_send\">Undangan telah dikirim</string>\n    <string name=\"family_management_pwd_error\">Kata sandi salah, silakan masukkan kembali</string>\n    <string name=\"pref_app_install_settings_title\">Pengaturan Penginstal Aplikasi</string>\n    <string name=\"pref_app_install_switch_title\">Izinkan Instalasi Aplikasi</string>\n    <string name=\"pref_app_install_other_apps_note\">Izin memungkinkan penginstalan aplikasi yang disediakan dari sumber lain.</string>\n    <string name=\"pref_app_install_permission_instruction\">Untuk memastikan bahwa aplikasi yang Anda instal berfungsi dengan baik, silakan berikan izin kepada microG Companion untuk menginstal aplikasi yang diunduh dari sumber lain.</string>\n    <string name=\"prefcat_app_install_list_title\">Aplikasi yang menggunakan App Installer</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-is/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"permission_service_all_label\">Allar Google-þjónustur</string>\n    <string name=\"permission_service_all_description\">Heimilar forriti aðgang að öllum Google-þjónustum í gegnum tengdan Google-aðgang.</string>\n    <string name=\"permission_service_android_description\">Heimilar forriti aðgang að Android-þjónustum í gegnum tengdan Google-aðgang.</string>\n    <string name=\"permission_service_adsense_description\">Heimilar forriti aðgang að AdSense í gegnum tengdan Google-aðgang.</string>\n    <string name=\"permission_service_blogger_label\">Blogger-blogg</string>\n    <string name=\"permission_service_android_label\">Android-þjónustur</string>\n    <string name=\"permission_service_adwords_label\">AdWords</string>\n    <string name=\"permission_service_adwords_description\">Heimilar forriti aðgang að AdWords í gegnum tengdan Google-aðgang.</string>\n    <string name=\"permission_service_dodgeball_label\">Dodgeball</string>\n    <string name=\"permission_service_ig_label\">iGoogle</string>\n    <string name=\"permission_service_mail_label\">Google-póstur</string>\n    <string name=\"permission_service_orkut_label\">Orkut</string>\n    <string name=\"permission_service_print_label\">Google-bókaleit</string>\n    <string name=\"permission_service_print_description\">Heimilar forriti aðgang að Google Book Search í gegnum tengdan Google-aðgang.</string>\n    <string name=\"permission_service_speech_label\">Raddleit</string>\n    <string name=\"permission_service_speech_description\">Heimilar forriti aðgang að Voice Search í gegnum tengdan Google-aðgang.</string>\n    <string name=\"permission_service_speechpersonalization_label\">Persónuaðlöguð talgreining</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut\">Sýslaðu með Orkut-virknina þína</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue\">Sýslaðu með verkefnin þín</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks\">Sýslaðu með verkefnin þín</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks.readonly\">Skoðaðu verkefnin þín</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube\">Sýslaðu með YouTube-aðganginn þinn</string>\n    <string name=\"permission_service_mail_description\">Heimilar forriti aðgang að Google Mail í gegnum tengdan Google-aðgang.</string>\n    <string name=\"permission_service_news_label\">Google-fréttir</string>\n    <string name=\"permission_service_news_description\">Heimilar forriti aðgang að Google News í gegnum tengdan Google-aðgang.</string>\n    <string name=\"permission_service_speechpersonalization_description\">Heimilar forriti aðgang að Personalized Speech Recognition í gegnum tengdan Google-aðgang.</string>\n    <string name=\"permission_service_talk_label\">Google-tal</string>\n    <string name=\"permission_service_talk_description\">Heimilar forriti aðgang að Google Talk í gegnum tengdan Google-aðgang.</string>\n    <string name=\"permission_service_wifi_label\">Google Wi-Fi</string>\n    <string name=\"permission_service_wifi_description\">Heimilar forriti aðgang að Google Wi-Fi í gegnum tengdan Google-aðgang.</string>\n    <string name=\"permission_service_wise_label\">Google-töflureiknar</string>\n    <string name=\"permission_service_wise_description\">Heimilar forriti aðgang að Google Spreadsheets í gegnum tengdan Google-aðgang.</string>\n    <string name=\"permission_service_writely_label\">Google-skjöl</string>\n    <string name=\"permission_service_writely_description\">Heimilar forriti aðgang að Google Docs í gegnum tengdan Google-aðgang.</string>\n    <string name=\"permission_service_youtube_label\">YouTube</string>\n    <string name=\"permission_service_youtube_description\">Heimilar forriti aðgang að YouTube í gegnum tengdan Google-aðgang.</string>\n    <string name=\"permission_service_YouTubeUser_label\">YouTube-notendanöfn</string>\n    <string name=\"permission_service_YouTubeUser_description\">Heimilar forriti aðgang að YouTube-notandanöfnum í gegnum tengdan Google-aðgang.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense.readonly\">Skoðaðu AdSense-gögnin þín</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger\">Sýslaðu með Blogger-aðganginn þinn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_books\">Sýslaðu með bækurnar þínar</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar\">Sýslaðu með dagatölin þín</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar.readonly\">Skoðaðu dagatölin þín</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_cloudprint\">Sýslaðu með og skoðaðu prentgögnin þín í Google Cloud skýinu</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_write\">Sýslaðu með gögnin þín í Google Cloud geymsluskýinu</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase.readonly\">Skoðaðu Freebase-aðganginn þinn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables\">Sýslaðu með Fusion-töflurnar þínar</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan\">Sýslaðu með GAN-gögnin þín</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.upload\">Sýslaðu með YouTube-myndskeiðin þín</string>\n    <string name=\"permission_service_adsense_label\">Google AdSense-auglýsingar</string>\n    <string name=\"permission_service_cp_label\">Google tengiliðir</string>\n    <string name=\"permission_service_blogger_description\">Heimilar forriti aðgang að Blogger í gegnum tengdan Google-aðgang.</string>\n    <string name=\"permission_service_cp_description\">Heimilar forriti aðgang að Google Contacts í gegnum tengdan Google-aðgang.</string>\n    <string name=\"permission_service_cl_label\">Google dagatal</string>\n    <string name=\"permission_service_cl_description\">Heimilar forriti aðgang að Google Calendar í gegnum tengdan Google-aðgang.</string>\n    <string name=\"permission_service_health_label\">Google heilsuupplýsningar</string>\n    <string name=\"permission_service_health_description\">Heimilar forriti aðgang að Google Health í gegnum tengdan Google-aðgang.</string>\n    <string name=\"permission_service_grandcentral_label\">Google Voice</string>\n    <string name=\"permission_service_grandcentral_description\">Heimilar forriti aðgang að Google Voice í gegnum tengdan Google-aðgang.</string>\n    <string name=\"permission_service_dodgeball_description\">Heimilar forriti aðgang að Dodgeball í gegnum tengdan Google-aðgang.</string>\n    <string name=\"permission_service_finance_label\">Google-fjármál</string>\n    <string name=\"permission_service_finance_description\">Heimilar forriti aðgang að Google Finance í gegnum tengdan Google-aðgang.</string>\n    <string name=\"permission_service_gbase_label\">Google Base</string>\n    <string name=\"permission_service_gbase_description\">Heimilar forriti aðgang að Google Base í gegnum tengdan Google-aðgang.</string>\n    <string name=\"permission_service_groups2_label\">Google hópar</string>\n    <string name=\"permission_service_groups2_description\">Heimilar forriti aðgang að Google Groups í gegnum tengdan Google-aðgang.</string>\n    <string name=\"permission_service_ig_description\">Heimilar forriti aðgang að iGoogle í gegnum tengdan Google-aðgang.</string>\n    <string name=\"permission_service_jotspot_label\">JotSpot</string>\n    <string name=\"permission_service_lh2_label\">Picasa vefalbúm</string>\n    <string name=\"permission_service_lh2_description\">Heimilar forriti aðgang að Picasa Web Albums í gegnum tengdan Google-aðgang.</string>\n    <string name=\"permission_service_local_label\">Google-landakort</string>\n    <string name=\"permission_service_local_description\">Heimilar forriti aðgang að Google Maps í gegnum tengdan Google-aðgang.</string>\n    <string name=\"permission_service_notebook_label\">Google Notebook</string>\n    <string name=\"permission_service_notebook_description\">Heimilar forriti aðgang að Google Notebook í gegnum tengdan Google-aðgang.</string>\n    <string name=\"permission_service_orkut_description\">Heimilar forriti aðgang að Orkut í gegnum tengdan Google-aðgang.</string>\n    <string name=\"permission_service_sitemaps_label\">Google vefstjóraverkfæri</string>\n    <string name=\"permission_service_sitemaps_description\">Heimilar forriti aðgang að Google Webmaster Tools í gegnum tengdan Google-aðgang.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller.readonly\">Skoðaðu Ad Exchange gögnin þín</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics.readonly\">Skoðaðu Google Analytics gögnin þín</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery.readonly\">Skoðaðu gögnin þín í Google BigQuery</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery\">Sýslaðu með og skoðaðu gögnin þín í Google BigQuery</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger.readonly\">Skoðaðu Blogger-aðganginn þinn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate.readonly\">Skoðaðu Google Coordinate verkin þín</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.full_control\">Sýslaðu með gögnin þín og heimildir í Google Cloud geymsluskýinu</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.appdata\">Leyfa aðgang að Application Data forritamöppu</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.apps.readonly\">Skoðaðu Google Drive forritin þín</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_only\">Skoðaðu gögnin þín í Google Cloud geymsluskýinu</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase\">Skráðu þig inn í Freebase með notandaaðgangnum þínum</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables.readonly\">Sýslaðu með Fusion-töflurnar Skoðaðu</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan.readonly\">Skoðaðu GAN-gögnin þín</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gcm_for_chrome\">CloudMessaging fyrir chrome</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.email\">Skoðaðu tölvupóstfangið þitt</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.profile\">Skoðaðu grunnupplýsingar um aðganginn þinn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.readonly\">Skoðaðu YouTube-aðganginn þinn</string>\n    <string name=\"permission_service_jotspot_description\">Heimilar forriti aðgang að JotSpot í gegnum tengdan Google-aðgang.</string>\n    <string name=\"permission_service_knol_label\">Knol</string>\n    <string name=\"permission_service_knol_description\">Heimilar forriti aðgang að Knol í gegnum tengdan Google-aðgang.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_glass.timeline\">Umfang Glass-tímalínu</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut.readonly\">Skoðaðu Orkut-gögnin þín</string>\n</resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-is/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <plurals name=\"pref_unifiednlp_summary\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> bakendi stilltur</item>\n        <item quantity=\"other\">xliff:g example=\\\"3\\\"&gt;%1$d&lt;/xliff:g&gt; bakendar stilltir</item>\n    </plurals>\n    <plurals name=\"gcm_registered_apps_counter\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> skráð forrit</item>\n        <item quantity=\"other\"><xliff:g example=\"123\">%1$d</xliff:g> skráð forrit</item>\n    </plurals>\n    <plurals name=\"cond_perm_summary\">\n        <item quantity=\"one\">Heimild fyrir rétta virkni microG-þjónustna er ekki veitt.</item>\n        <item quantity=\"other\">Heimildir fyrir rétta virkni microG-þjónustna eru ekki veittar.</item>\n    </plurals>\n    <plurals name=\"cond_perm_action\">\n        <item quantity=\"one\">Biðja um heimild sem vantar</item>\n        <item quantity=\"other\">Biðja um heimildir sem vantar</item>\n    </plurals>\n</resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-is/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=\"limited_services_dialog_information_ack\">Ég skil</string>\n    <string name=\"games_achievement_list_title\">Frammistaða</string>\n    <string name=\"games_achievement_locked_content_description\">læst</string>\n    <string name=\"games_achievement_unlocked_content_description\">ólæst</string>\n    <string name=\"games_achievement_extra_text\">%1$s XP</string>\n    <string name=\"games_leaderboard_list_title\">Stigatafla</string>\n    <string name=\"games_leaderboards_score_label\">Stig: %1$s</string>\n    <string name=\"games_delete_snapshot_dialog_title\">Eyða vistuðum leik</string>\n    <string name=\"gms_app_name\">microG-þjónustur</string>\n    <string name=\"gms_settings_name\">microG-stillingar</string>\n    <string name=\"allow\">Leyfa</string>\n    <string name=\"self_check_pkg_gms\">microG-þjónustur</string>\n    <string name=\"cond_perm_title\">Heimild vantar</string>\n    <string name=\"cond_gcm_bat_action\">Hunsa rafhlöðusparnað</string>\n    <string name=\"pref_gcm_heartbeat_title\">Uppfærslutíðni Cloud Messaging</string>\n    <string name=\"pref_about_title\">Um microG-þjónusturnar</string>\n    <string name=\"gcm_messages_counter\">Skilaboð: <xliff:g example=\"123\">%1$d</xliff:g> (<xliff:g example=\"12345\">%2$d</xliff:g> bæti)</string>\n    <string name=\"profile_name_native\">Innbyggt</string>\n    <string name=\"pref_safetynet_recent_copied\">Afritað á klippispjaldið!</string>\n    <string name=\"pref_safetynet_test_integrity_cts_passed\">Áreiðanleikapróf og CTS mistókust</string>\n    <string name=\"push_notifications_summary_values_seconds\">%s sekúndur</string>\n    <string name=\"credentials_assisted_cancel\">Hætta við</string>\n    <string name=\"just_a_sec\">Bíddu aðeins…</string>\n    <string name=\"google_account_label\">Google</string>\n    <string name=\"sorry\">Því miður…</string>\n    <string name=\"ask_permission_tos\">Við það að halda áfram gefur þú þessu forriti, ásamt Google, leyfi til að nota upplýsingar um þig samkvæmt þjónustuskilmálum og persónuverndarstefnu beggja.</string>\n    <string name=\"account_manager_title\">Aðgangastýring Google</string>\n    <string name=\"auth_sign_in\">Skrá inn</string>\n    <string name=\"auth_connecting\">Tækið þitt er að koma á tengingu við netþjónustur Google til að geta skráð þig inn.\\n\\nÞetta gæti tekið örfáar sekúndur.</string>\n    <string name=\"deny\">Hafna</string>\n    <string name=\"no_network_error_desc\">Þú ert ekki með neina nettengingu.\\n\\nÞetta gæti verið tímabundið vandamál, eða að Android-tækið þitt sé ekki með neinar gagnaþjónustur. Prófaðu aftur þegar tengst hefur verið við farsímanet eða Wi-Fi netkerfi.</string>\n    <string name=\"auth_notification_title\">Auðkenningar krafist</string>\n    <string name=\"auth_notification_content\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> krefst heimilda frá þér til að fá aðgang að Google-reikningnum þinum.</string>\n    <string name=\"service_name_snet\">Google SafetyNet</string>\n    <string name=\"pick_place_title\">Veldu stað</string>\n    <string name=\"pick_place_desc\">Staðarveljari er ekki tiltækur ennþá.</string>\n    <string name=\"service_name_mcs\">Cloud Messaging</string>\n    <string name=\"place_picker_select_title\">Velja þessa staðsetningu</string>\n    <string name=\"self_check_name_system_spoofs\">Kerfið falsar undirritun:</string>\n    <string name=\"self_check_resolution_system_spoofs\">Skoðaðu leiðbeiningarnar um hvaða skref gætu verið nauðsynleg.</string>\n    <string name=\"self_check_pkg_vending\">microG-fylgiforrit / Play Store</string>\n    <string name=\"self_check_resolution_perm_granted\">Þetta er sterkleg ábending um að ROM-diskmyndin styðji við fölsun undirritana, en þarfnist frekari aðgerða til að virkja það. Skoðaðu leiðbeiningarnar um hvaða skref gætu verið nauðsynleg.</string>\n    <string name=\"pref_auth_trust_google_summary\">Þegar þetta er óvirkt, er notandinn spurður áður en auðkenningarbeiðni forrits er send til Google. Sum forrit munu ekki geta notað Google-reikninga ef þetta er óvirkt.</string>\n    <string name=\"pref_auth_visible_title\">Leyfa forritum að finna reikninga</string>\n    <string name=\"pref_auth_trust_google_title\">Treysta Google fyrir heimildum forrita</string>\n    <string name=\"pref_auth_visible_summary\">Þegar þetta er virkt, munu öll forrit á þessu tæki geta séð tölvupóstfang Google-reikninganna þinna án þess að áður sé gefið leyfi.</string>\n    <string name=\"pref_device_registration_android_id\">Android ID-auðkenni</string>\n    <string name=\"gcm_last_message_at\">Síðustu skilaboð: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_registered\">Skráð</string>\n    <string name=\"gcm_registered_since\">Skráð síðan: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_network_state_connected\">Tengt síðan <xliff:g example=\"2 hours ago\">%1$s</xliff:g></string>\n    <string name=\"pref_push_app_allow_register_summary\">Leyfa forritinu að skrá sig fyrir ýti-tilkynningum.</string>\n    <string name=\"pref_test_summary_failed\">Mistókst: %s</string>\n    <string name=\"pref_test_summary_warn\">Aðvörun: %s</string>\n    <string name=\"pref_test_summary_running\">Keyrandi…</string>\n    <string name=\"pref_test_summary_passed\">Stóðst allar prófanir</string>\n    <string name=\"pref_droidguard_operation_mode\">Aðgerðahamur</string>\n    <string name=\"pref_recaptcha_enterprise_test_title\">Prófa ReCaptcha fyrirtækis</string>\n    <string name=\"menu_clear_recent_requests\">Hreinsa nýlegar beiðnir</string>\n    <string name=\"safetynet_last_run_at\">Síðast notað: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"profile_name_real\">Raunverulegt</string>\n    <string name=\"profile_name_user\">Sérsniðið: %s</string>\n    <string name=\"profile_name_auto\">Sjálfvirkt: %s</string>\n    <string name=\"profile_name_system\">Kerfi: %s</string>\n    <string name=\"prefcat_safetynet_apps_title\">Forrit sem nota SafetyNet</string>\n    <string name=\"pref_device_registration_import_custom_profile_title\">Flytja inn sérsniðið snið</string>\n    <string name=\"pref_device_registration_serial_title\">Raðnúmer</string>\n    <string name=\"pref_device_registration_select_profile_title\">Veldu snið</string>\n    <string name=\"pref_device_registration_device_profile_category\">Snið tækis</string>\n    <string name=\"pref_safetynet_recent_uses\">Nýleg notkun</string>\n    <string name=\"pref_safetynet_recent_attestation_summary\">Vottun: %s</string>\n    <string name=\"pref_safetynet_recent_recaptcha_summary\">ReCaptcha: %s</string>\n    <string name=\"pref_safetynet_recent_recaptcha_enterprise_summary\">ReCaptcha fyrirtækis: %s</string>\n    <string name=\"pref_safetynet_recent_cat_request\">Beiðni um gögn</string>\n    <string name=\"pref_safetynet_recent_cat_response\">Gögn svars</string>\n    <string name=\"pref_safetynet_recent_nonce\">Nonce (Hex)</string>\n    <string name=\"pref_safetynet_recent_request_time\">Tími beiðnar</string>\n    <string name=\"pref_safetynet_recent_request_type\">Tegund beiðnar</string>\n    <string name=\"pref_safetynet_recent_cat_basic\">Grunngögn</string>\n    <string name=\"pref_vending_summary_licensing_on\">Kveikt á notkunarleyfi</string>\n    <string name=\"pref_vending_licensing_category\">Google Play notkunarleyfi</string>\n    <string name=\"pref_safetynet_test_invalid_json\">Ógilt JSON</string>\n    <string name=\"push_notifications_summary_off\">SLÖKKT</string>\n    <string name=\"push_notifications_summary_automatic\">KVEIKT / sjálfvirkt: %s</string>\n    <string name=\"push_notifications_summary_manual\">KVEIKT / handvirkt: %s</string>\n    <string name=\"pref_vending_summary_licensing_off\">Slökkt á notkunarleyfi</string>\n    <string name=\"credentials_assisted_continue\">Halda áfram</string>\n    <string name=\"credentials_assisted_signin_button_text_long\">Skrá inn með Google</string>\n    <string name=\"pref_safetynet_test_no_result\">Engin niðurstaða</string>\n    <string name=\"auth_action_step_completed_content_description\">Skrefi lokið</string>\n    <string name=\"auth_action_activity_finish\">Ljúka</string>\n    <string name=\"perm_c2dm_receive_label\">fylgjast með C2DM-skilaboðum</string>\n    <string name=\"place_picker_location_lat_lng\">(%1$.7f, %2$.7f)</string>\n    <string name=\"service_name_checkin\">Skráning tækis hjá Google</string>\n    <string name=\"place_picker_nearby_places\">Nálægir staðir</string>\n    <string name=\"network_type_mobile\">Farsímanet</string>\n    <string name=\"network_type_wifi\">Wi-Fi</string>\n    <string name=\"self_check_cat_gms_packages\">Uppsettir pakkar</string>\n    <string name=\"self_check_cat_system\">Kerfis</string>\n    <string name=\"lacking_permission_toast\">Þjónustur microG: Vantar heimild til að: Lacking permission to <xliff:g example=\"have full network acccess\">%1$s</xliff:g></string>\n    <string name=\"self_check_name_fake_sig_perm\">Kerfið er með stuðning við fölsun undirritana:</string>\n    <string name=\"self_check_resolution_fake_sig_perm\">ROM-diskmyndin er ekki með innbyggðan stuðning við fölsun undirritana. Þú getur samt notað Xposed eða önnur kerfi til að falsa undirritanir. Skoðaðu leiðbeiningarnar um hvaða ROM-diskmyndir styðji fölsun undirritana og hvernig eigi að nota microG á ROM-diskmyndum sem gera það ekki.</string>\n    <string name=\"self_check_name_perm_granted\">Kerfið gefur heimild til fölsunar undirritana:</string>\n    <string name=\"prefcat_components\">Einingar</string>\n    <string name=\"prefcat_configuration\">Grunnstillingar</string>\n    <string name=\"prefcat_google_services\">Google-þjónustur</string>\n    <string name=\"prefcat_location_service\">Staðsetningarþjónusta</string>\n    <string name=\"prefcat_services\">Þjónustur</string>\n    <string name=\"prefcat_test\">Prófun</string>\n    <string name=\"cond_gcm_bat_title\">Rafhlöðusparnaður virkur</string>\n    <string name=\"prefs_account\">Eiginleikar aðgangs</string>\n    <string name=\"prefs_account_privacy\">Persónulegar upplýsingar og gagnaleynd</string>\n    <string name=\"prefs_account_security\">Innskráning og öryggi</string>\n    <string name=\"pref_checkin_enable_summary\">Skráir tækið þitt á Google-þjónustur og útbýr einstakt auðkenni fyrir það. microG hreinsar auðkennandi upplýsingar aðrar en heiti Google-reikningsins úr skráningargögnunum.</string>\n    <string name=\"checkin_not_registered\">Óskráð</string>\n    <string name=\"pref_info_status\">Staða</string>\n    <string name=\"checkin_enable_switch\">Skrá tæki</string>\n    <string name=\"pref_more_settings\">Meira</string>\n    <string name=\"pref_accounts_title\">Google-aðgangar</string>\n    <string name=\"prefcat_accounts_settings_title\">Stillingar</string>\n    <string name=\"prefcat_accounts_current_accounts_title\">Notandaaðgangar</string>\n    <string name=\"pref_accounts_summary\">Bæta við og sýsla með Google-aðganga</string>\n    <string name=\"pref_add_account_title\">Notandaaðgangur</string>\n    <string name=\"pref_add_account_summary\">Bæta við Google-aðgangi</string>\n    <string name=\"pref_gcm_enable_mcs_summary\">Cloud Messaging er þjónustuveita fyrir ýti-tilkynningar sem notuð er af mörgum utanaðkomandi forritum. Til að nota þetta þarftu að virkja skráningu tækisins.</string>\n    <string name=\"pref_gcm_apps_title\">Forrit sem nota Cloud Messaging</string>\n    <string name=\"pref_gcm_ping_interval\">Uppfærslutíðni: <xliff:g example=\"10 minutes\">%1$s</xliff:g></string>\n    <string name=\"pref_about_summary\">Upplýsingar um útgáfu og notuð aðgerðasöfn</string>\n    <string name=\"gcm_app_error_unregistering\">Villa við afskráningu</string>\n    <string name=\"gcm_unregister_app\">Afskrá</string>\n    <string name=\"gcm_not_registered\">Óskráð</string>\n    <string name=\"gcm_unregister_confirm_title\">Afskrá <xliff:g example=\"F-Droid\">%1$s</xliff:g>\\?</string>\n    <string name=\"gcm_unregister_after_deny_message\">Þú neitaðir forriti sem þegar er skráð um að skrá sig fyrir ýti-tilkynningum.\\nViltu afskrá það núna svo það fái framvegis ekki ýti-tilkynningar?</string>\n    <string name=\"gcm_network_state_disconnected\">Aftengt</string>\n    <string name=\"gcm_enable_switch\">Taka á móti ýti-tilkynningum</string>\n    <string name=\"gcm_allow_app_popup\">Leyfa <xliff:g example=\"F-Droid\">%1$s</xliff:g> að skrá sig fyrir ýti-tilkynningum?</string>\n    <string name=\"pref_push_app_allow_register_title\">Leyfa skráningu</string>\n    <string name=\"prefcat_push_apps_registered_title\">Skráð forrit</string>\n    <string name=\"push_notifications_summary_values_minutes\">%s mínútur</string>\n    <string name=\"safetynet_enable_switch\">Leyfa vottun tækis</string>\n    <string name=\"pref_safetynet_test_title\">Prófa SafetyNet-vottun</string>\n    <string name=\"pref_recaptcha_test_title\">Prófa ReCAPTCHA</string>\n    <string name=\"pref_safetynet_recent_eval_type\">Gerð mats (evaluation)</string>\n    <string name=\"pref_safetynet_recent_response_status\">Staða svars</string>\n    <string name=\"credentials_assisted_confirmation_header\">Skrái þig inn</string>\n    <string name=\"credentials_assisted_continue_as_user_button_label\">Halda áfram sem %1$s</string>\n    <string name=\"credentials_assisted_signin_consent_header\">Skrái inn sem %1$s</string>\n    <string name=\"auth_general_error_desc\">Vandamál kom upp í samskiptunum við netþjóna Google.\\n\\nReyndu aftur síðar.</string>\n    <string name=\"auth_finalize\">Tækið þitt er að hafa samband við Google til að vista upplýsingar á reikninginn þinn.\\n\\nÞetta gæti tekið örfáar mínútur.</string>\n    <string name=\"auth_action_step_perform_content_description\">Smella til að framkvæma skref</string>\n    <string name=\"self_check_pkg_gsf\">Þjónustukerfi microG</string>\n    <string name=\"self_check_resolution_correct_sig\">Annað hvort er hið uppsetta <xliff:g example=\"F-Droid\">%1$s</xliff:g> ekki samhæft eða að fölsun undirritana sé ekki virk fyrir það. Skoðaðu leiðbeiningarnar um hvaða forrit og ROM séu samhæfð.</string>\n    <string name=\"self_check_resolution_battery_optimizations\">Ýttu hér til að gera rafhlöðusparnað óvirkan. Sé það ekki gert gætu forrit farið að haga sér skringilega.</string>\n    <string name=\"cond_gcm_bat_summary\">Þú virkjaðir Cloud Messaging en ert með rafhlöðusparnað virkan fyrir microG-þjónustur Til að ýti-tilkynningar nái í gegn ættirðu að hunsa rafhlöðusparnað.</string>\n    <string name=\"pref_auth_include_android_id_title\">Auðkenna með skráningu tækis</string>\n    <string name=\"pref_gcm_heartbeat_summary\">Millibilið í sekúndum milli þess að athugað sé með Google-netþjóna. Aukning á þessari tölu mun minnka eyðslu af rafhlöðu, en gæti valdið töfum á ýti-tilkynningum push messages.\\nÚrelt, verður skipt út í framtíðinni.</string>\n    <string name=\"checkin_last_registration\">Síðasta skráning: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"pref_gcm_apps_summary\">Listi yfir þau forrit sem skráð eru til að nota Cloud Messaging.</string>\n    <string name=\"pref_gcm_confirm_new_apps_title\">Staðfesta ný forrit</string>\n    <string name=\"pref_gcm_confirm_new_apps_summary\">Spyrja áður en ný forrit séu skráð til að taka við ýti-tilkynningum</string>\n    <string name=\"gcm_app_not_installed_anymore\">Engin lengur uppsett</string>\n    <string name=\"gcm_no_message_yet\">Engin skilaboð móttekin til þessa</string>\n    <string name=\"gcm_unregister_confirm_message\">Sum forrit endurskrá sig ekki sjálfkrafa og/eða bjóða ekki upp á möguleika til að gera það handvirkt. Þau forrit gætu virkað ekki rétt eftir afskráningu.\\nHalda áfram?</string>\n    <string name=\"pref_push_app_wake_for_delivery_title\">Ræsa forrit við ýti-tilkynningu</string>\n    <string name=\"pref_push_app_wake_for_delivery_summary\">Ræsa forritið í bakgrunnsvinnslu til að geta tekið við ýti-tilkynningum.</string>\n    <string name=\"prefcat_push_apps_title\">Forrit sem nota ýti-tilkynningar</string>\n    <string name=\"prefcat_push_apps_unregistered_title\">Óskráð forrit</string>\n    <string name=\"prefcat_push_networks_title\">Netkerfi sem á að nota fyrir ýti-tilkynningar</string>\n    <string name=\"safetynet_intro\">Google SafetyNet er vottunarkerfi tækja, sem tryggir að tæki séu örugg og samhæfð við Android CTS. Sum forrit nota SafetyNet af öryggisástæðum eða sem forsendu fyrir að ekki hafi verið átt við tækið.\\n\\nmicroG GmsCore kemur með frjálsa útfærslu af SafetyNet, en opinberi netþjónninn krefst þess að SafetyNet-beiðnir séu undirritaðar með séreignarhugbúnaðinum í DroidGuard-kerfinu.</string>\n    <string name=\"pref_device_registration_import_custom_profile_summary\">Flytja snið tækis inn úr skrá</string>\n    <string name=\"pref_safetynet_recent_copy_json\">Afrita JSON JWS gögn</string>\n    <string name=\"pref_safetynet_recent_advice\">Ráðlegging</string>\n    <string name=\"pref_safetynet_recent_token\">Teikn</string>\n    <string name=\"pref_safetynet_test_cts_failed\">CTS mistókst</string>\n    <string name=\"pref_safetynet_test_integrity_failed\">Áreiðanleikapróf mistókst</string>\n    <string name=\"pref_safetynet_test_not_completed\">Ekki lokið ennþá</string>\n    <string name=\"games_delete_snapshot_dialog_message\">Ertu viss um að þú viljir eyða þessum vistaða leik?</string>\n    <string name=\"games_delete_snapshot_dialog_cancel\">Hætta við</string>\n    <string name=\"games_delete_snapshot_dialog_ok\">Í lagi</string>\n    <string name=\"signin_picker_title\">Veldu aðgang</string>\n    <string name=\"signin_picker_add_account_label\">Bæta við öðrum aðgangi</string>\n    <string name=\"signin_confirm_button_text\">Leyfa og deila</string>\n    <string name=\"signin_picker_subtitle\">til að halda áfram í <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"perm_status_broadcast_label\">fylgjast með innri útsendingum ástands</string>\n    <string name=\"signin_subtext_policy\">Áður en þú notar þetta forrit, skaltu lesa yfir %1$s og %2$s.</string>\n    <string name=\"signin_subtext_policy_privacy\">stefnu vegna meðferðar persónuupplýsinga</string>\n    <string name=\"signin_subtext_policy_terms\">þjónustuskilmála</string>\n    <string name=\"perm_gtalk_svc_label\">skiptast á skilaboðum og taka á móti samstillingartilkynningum frá netþjónum Google</string>\n    <string name=\"perm_extended_access_label\">Útvíkka aðgang yfir á Google-þjónustur</string>\n    <string name=\"perm_provision_label\">veita microG-þjónustur</string>\n    <string name=\"perm_car_speed_label\">Hraði bíls</string>\n    <string name=\"perm_c2dm_send_label\">senda C2DM-skilaboð til annarra forrita</string>\n    <string name=\"perm_provision_description\">Gerir forritinu kleift að stilla microG-þjónustur án afskipta notandans</string>\n    <string name=\"games_title\">Google Play leikir</string>\n    <string name=\"service_name_vending\">Play Store þjónustur</string>\n    <string name=\"perm_car_info_label\">Upplýsingar um bifreið</string>\n    <string name=\"games_info_content\">Til að nota Play-leiki er nauðsynlegt að setja upp Google Play Games forritið. Forrit þetta getur haldið áfram án Play-leikja, en mögulaga gæti það hegðað sér á óvæntan veg.</string>\n    <string name=\"self_check_cat_fake_sig\">Stuðningur við fölsun undirritana (signature spoofing)</string>\n    <string name=\"network_type_roaming\">Reiki</string>\n    <string name=\"network_type_other\">Önnur netkerfi</string>\n    <string name=\"self_check_name_app_installed\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> er uppsett:</string>\n    <string name=\"self_check_resolution_app_installed\">Settu upp forritið <xliff:g example=\"F-Droid\">%1$s</xliff:g> eða annað samhæft. Skoðaðu leiðbeiningarnar um hvaða forrit séu samhæfð.</string>\n    <string name=\"self_check_name_correct_sig\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> er með rétta undirritun:</string>\n    <string name=\"self_check_name_battery_optimizations\">Rafhlöðusparnaður hunsaður:</string>\n    <string name=\"prefcat_about\">Um hugbúnaðinn</string>\n    <string name=\"games_achievements_empty_text\">Engin frammistaða í þessum leik</string>\n    <string name=\"limited_services_app_name\">Takmarkaðar microG-þjónustur</string>\n    <string name=\"ask_scope_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> myndi vilja:</string>\n    <string name=\"pref_vending_billing_category\">Google Play innheimta</string>\n    <string name=\"credentials_assisted_choose_account_label\">Veldu aðgang</string>\n    <string name=\"credentials_assisted_choose_account_subtitle\">til að halda áfram í %1$s</string>\n    <string name=\"auth_action_notification_content\">Google-aðgangurinn þinn krefst viðbótaruppsetningar.</string>\n    <string name=\"gms_settings_summary\">Settu upp microG-þjónustur.</string>\n    <string name=\"ask_service_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> myndi vilja nota:</string>\n    <string name=\"auth_action_notification_channel_name\">Aðvaranir Google-aðgangs</string>\n    <string name=\"auth_action_activity_header\">Ljúktu við að setja upp Google-aðganginn þinn</string>\n    <string name=\"auth_action_step_enable_checkin\">Virkja skráningu tækis</string>\n    <string name=\"credentials_assisted_sign_back_title\">Skráðu þig aftur inn á %1$s með Google</string>\n    <string name=\"games_snapshot_empty_text\">Engir leikir hafa enn verið vistaðir</string>\n    <string name=\"games_snapshot_choose_btn_text\">velja</string>\n    <string name=\"games_snapshot_delete_btn_text\">eyða</string>\n    <string name=\"games_delete_snapshot_error\">Eyðing mistókst, reyndu aftur síðar</string>\n    <string name=\"auth_package_override_request_title\">Leyfa <b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> óheftan aðgang að <xliff:g example=\"account@example.com\">%2$s</xliff:g>\\?</string>\n    <string name=\"perm_car_mileage_label\">Akstursvegalengd farartækis</string>\n    <string name=\"auth_action_step_allow_microg_gcm\">Leyfðu Cloud Messaging fyrir microG</string>\n    <string name=\"auth_action_step_enable_lockscreen\">Stilltu örugga skjálæsingu</string>\n    <string name=\"perm_car_info_description\">Fá aðgang að upplýsingum um farartækið</string>\n    <string name=\"perm_car_fuel_label\">Magn eldsneytis í farartæki</string>\n    <string name=\"perm_car_fuel_description\">Fá aðgang að upplýsingum um eldsneytismagn</string>\n    <string name=\"perm_car_mileage_description\">Fá aðgang að upplýsingum um ekna vegalengd farartækis</string>\n    <string name=\"perm_car_vendor_extension_label\">Rás framleiðanda farartækis</string>\n    <string name=\"auth_before_connect\">Forrit á tækinu þínu er að reyna að skrá sig inn á Google-reikning.\\n\\nEf þetta er ætlunin, skaltu nota <b>Skrá inn</b>-hnappinn til að tengjast innskráningarsíðu Google, en ef ekki skaltu ýta á <b>Hætta við</b> til að fara til baka í forritið sem olli því að þessi gluggi birtist.</string>\n    <string name=\"auth_action_notification_title\">Aðgerðar krafist á notandaaðgangi</string>\n    <string name=\"auth_action_step_enable_gcm\">Virkja Cloud Messaging</string>\n    <string name=\"perm_car_vendor_extension_description\">Fá aðgang að rás framleiðanda til að skiptast á sértækum upplýsingum um farartækið</string>\n    <string name=\"auth_package_override_request_message\"><b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> vill fá að nota notandaaðganginn þinn eins og það sé <b><xliff:g example=\"F-Droid\">%2$s</xliff:g> frá <xliff:g example=\"F-Droid Inc.\">%3$s</xliff:g></b>. Þetta gæti veitt því óheftan aðgang að notandaaðgangnum þínum.</string>\n    <string name=\"perm_gsf_read_gservices_label\">lesa uppsetningu Google-þjónustu</string>\n    <string name=\"perm_car_speed_description\">Fá aðgang að hraða farartækisins</string>\n    <string name=\"games_info_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> vill fá að nota Play Games</string>\n    <string name=\"pref_vending_asset_device_sync_switch\">Virkja samstillingu upplýsinga tækis</string>\n    <string name=\"pref_vending_billing_note_experimental\">Þessi eiginleiki er á tilraunastigi og gæti leitt til þess að fjármunir tapist. Þú hefur þar með fengið viðvörun.</string>\n    <string name=\"pref_droidguard_unsupported_summary\">Keyrsla DroidGuard er ekki studd á þessu tæki. SafetyNet-þjónustur gætu hegðað sér skringilega.</string>\n    <string name=\"pref_vending_licensing_enable_switch\">Svara beiðnum um sannvottun notkunarleyfis</string>\n    <string name=\"pref_vending_license_enable_summary\">Sum forrit krefjast sannvottunar á því að þú hafir keypt þau á Google Play. Þegar forrit biður um slíkt, getur microG sótt staðfestingu á kaupunum frá Google. Ef þetta er óvirkt, eða ef engum Google-reikningi hefur verið bætt við, verða beiðnir um sannvottun notkunarleyfis hunsaðar.</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_switch\">Bæta frjálsum forritum sjálfvirkt við safnið</string>\n    <string name=\"feedback_disabled\">Umsagnir ekki mögulegar í augnablikinu</string>\n    <string name=\"backup_disabled\">Öryggisafritun ekki möguleg í augnablikinu</string>\n    <string name=\"pref_vending_billing_enable_switch\">Meðhöndla innheimtubeiðnir</string>\n    <string name=\"credentials_assisted_signin_consent\">Með því að þú haldir áfram, mun Google deila nafninu þínu, tölvupóstfangi og auðkennismynd með %1$s. Skoðaðu persónuverndarstefnu %1$s og þjónustuskilmála.</string>\n    <string name=\"credentials_assisted_signin_description\">Þú getur haldið utan um innskráningar hjá Google á Google-aðgangnum þínum.</string>\n    <string name=\"auth_action_reauth_notification_title\">Aðgerðar krafist á notandaaðgangi</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-it/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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  --><resources>\n    <string name=\"permission_service_all_label\">Tutti i servizi Google</string>\n    <string name=\"permission_service_all_description\">Permette alle applicazioni di accedere a tutti i servizi Google mediante l\\'account Google.</string>\n    <string name=\"permission_service_android_label\">Servizi Android</string>\n    <string name=\"permission_service_android_description\">Permette alle applicazioni di accedere ai servizi Android mediante l\\'account Google.</string>\n    <string name=\"permission_service_adsense_label\">Google AdSense</string>\n    <string name=\"permission_service_adsense_description\">Permette alle applicazioni di accedere a Google AdSense mediante l\\'account Google.</string>\n    <string name=\"permission_service_adwords_label\">Google AdWords</string>\n    <string name=\"permission_service_adwords_description\">Permette alle applicazioni di accedere a Google AdWords mediante l\\'account Google.</string>\n    <string name=\"permission_service_ah_label\">Google App Engine</string>\n    <string name=\"permission_service_ah_description\">Permette alle applicazioni di accedere a Google App Engine mediante l\\'account Google.</string>\n    <string name=\"permission_service_blogger_label\">Google Blogger</string>\n    <string name=\"permission_service_blogger_description\">Permette alle applicazioni di accedere a Google Blogger mediante l\\'account Google.</string>\n    <string name=\"permission_service_cl_label\">Calendario Google</string>\n    <string name=\"permission_service_cl_description\">Permette alle applicazioni di accedere al calendario Google mediante l\\'account Google.</string>\n    <string name=\"permission_service_cp_label\">Contatti Google</string>\n    <string name=\"permission_service_cp_description\">Permette alle applicazioni di accedere ai Contatti Google mediante l\\'account Google.</string>\n    <string name=\"permission_service_dodgeball_label\">Dodgeball</string>\n    <string name=\"permission_service_dodgeball_description\">Permette alle applicazioni di accedere a Dodgeball mediante l\\'account Google.</string>\n    <string name=\"permission_service_finance_label\">Google Finance</string>\n    <string name=\"permission_service_finance_description\">Permette alle applicazioni di accedere a Google Finance mediante l\\'account Google.</string>\n    <string name=\"permission_service_gbase_label\">Google Base</string>\n    <string name=\"permission_service_gbase_description\">Permette alle applicazioni di accedere a Google Base mediante l\\'account Google.</string>\n    <string name=\"permission_service_grandcentral_label\">Google Voice</string>\n    <string name=\"permission_service_grandcentral_description\">Permette alle applicazioni di accedere a Google Voice mediante l\\'account Google.</string>\n    <string name=\"permission_service_groups2_label\">Google Gruppi</string>\n    <string name=\"permission_service_groups2_description\">Permette alle applicazioni di accedere Google Gruppi mediante l\\'account Google.</string>\n    <string name=\"permission_service_health_label\">Google Health</string>\n    <string name=\"permission_service_health_description\">Permette alle applicazioni di accedere a Google Health mediante l\\'account Google.</string>\n    <string name=\"permission_service_ig_label\">iGoogle</string>\n    <string name=\"permission_service_ig_description\">Permette alle applicazioni di accedere ad iGoogle mediante l\\'account Google.</string>\n    <string name=\"permission_service_jotspot_label\">JotSpot</string>\n    <string name=\"permission_service_jotspot_description\">Permette alle applicazioni di accedere a JotSpot mediante l\\'account Google.</string>\n    <string name=\"permission_service_knol_label\">Knol</string>\n    <string name=\"permission_service_knol_description\">Permette alle applicazioni di accedere a Knol mediante l\\'account Google.</string>\n    <string name=\"permission_service_lh2_label\">Album web Picasa</string>\n    <string name=\"permission_service_lh2_description\">Permette alle applicazioni di accedere agli album web Picasa mediante l\\'account Google.</string>\n    <string name=\"permission_service_local_label\">Mappe Google</string>\n    <string name=\"permission_service_local_description\">Permette alle applicazioni di accedere alle mappe Google mediante l\\'account Google.</string>\n    <string name=\"permission_service_mail_label\">Google Mail</string>\n    <string name=\"permission_service_mail_description\">Permette alle applicazioni di accedere a Google Mail mediante l\\'account Google.</string>\n    <string name=\"permission_service_news_label\">Google Notizie</string>\n    <string name=\"permission_service_news_description\">Permette alle applicazioni di accedere a Google Notizie mediante l\\'account Google.</string>\n    <string name=\"permission_service_notebook_label\">Google Notebook</string>\n    <string name=\"permission_service_notebook_description\">Permette alle applicazioni di accedere a Google Notebook mediante l\\'account Google.</string>\n    <string name=\"permission_service_orkut_label\">Orkut</string>\n    <string name=\"permission_service_orkut_description\">Permette alle applicazioni di accedere a Orkut mediante l\\'account Google.</string>\n    <string name=\"permission_service_print_label\">Ricerca libri Googleh</string>\n    <string name=\"permission_service_print_description\">Permette alle applicazioni di accedere alla ricerca libri Google mediante l\\'account Google.</string>\n    <string name=\"permission_service_sierra_label\">Account Google Chekout</string>\n    <string name=\"permission_service_sierra_description\">Permette alle applicazioni di accedere agli account Google Checkout mediante l\\'account Google.</string>\n    <string name=\"permission_service_sierraqa_label\">Account QA Google Checkout</string>\n    <string name=\"permission_service_sierraqa_description\">Permette alle applicazioni di accedere agli account QA Google Checkout mediante l\\'account Google.</string>\n    <string name=\"permission_service_sierrasandbox_label\">Account contenitore Google Checkout</string>\n    <string name=\"permission_service_sierrasandbox_description\">Permette alle applicazioni di accedere agli account contenitore Google Checkout mediante l\\'account Google.</string>\n    <string name=\"permission_service_sitemaps_label\">Strumenti webmaster Google</string>\n    <string name=\"permission_service_sitemaps_description\">Permette alle applicazioni di accedere agli strumenti webmaster Google mediante l\\'account Google.</string>\n    <string name=\"permission_service_speech_label\">Ricerca vocale</string>\n    <string name=\"permission_service_speech_description\">Permette alle applicazioni di accedere alla ricerca vocale mediante l\\'account Google.</string>\n    <string name=\"permission_service_speechpersonalization_label\">Riconoscimento vocale eprsonalizzato</string>\n    <string name=\"permission_service_speechpersonalization_description\">Permette alle applicazioni di accedere al riconoscimento vocale personalizzato mediante l\\'account Google.</string>\n    <string name=\"permission_service_talk_label\">Google Talk</string>\n    <string name=\"permission_service_talk_description\">Permette alle applicazioni di accedere a Google Talk mediante l\\'account Google.</string>\n    <string name=\"permission_service_wifi_label\">Google Wi-Fi</string>\n    <string name=\"permission_service_wifi_description\">Permette alle applicazioni di accedere a Google Wi-Fi mediante l\\'account Google.</string>\n    <string name=\"permission_service_wise_label\">Fogli Google</string>\n    <string name=\"permission_service_wise_description\">Permette alle applicazioni di accedere ai fogli Google mediante l\\'account Google.</string>\n    <string name=\"permission_service_writely_label\">Documenti Google Docs</string>\n    <string name=\"permission_service_writely_description\">Permette alle applicazioni di accedere ai documenti Google mediante l\\'account Google.</string>\n    <string name=\"permission_service_youtube_label\">YouTube</string>\n    <string name=\"permission_service_youtube_description\">Permette alle applicazioni di accedere a YouTube mediante l\\'account Google.</string>\n    <string name=\"permission_service_YouTubeUser_label\">Nomi utente YouTube</string>\n    <string name=\"permission_service_YouTubeUser_description\">Permette alle applicazioni di accedere ai nomi utente YouTube mediante l\\'account Google.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_activity\">Visualizza la cronologia delle attività delle tue applicazioni Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.buyer\">Gestisci la configurazione del tuo account Ad Echange per gli acquirenti</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller.readonly\">Visualizza i tuoi dati Ad Exchange</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller\">Visualizza e gestisci i tuoi dati di Ad Exchange</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsensehost\">Visualizza e gestisci i tuoi dati host di AdSense e gli account associati</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense.readonly\">Visualizza i tuoi dati AdSense</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense\">Visualizza e gestisci i tuoi dati di AdSense</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics.readonly\">Visualizza i tuoi dati di Google Analytics</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics\">Visualizza e gestisci i tuoi dati di Google Analytics</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_androidpublisher\">Accedi a Google Play Android Developer</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appengine.admin\">Ambito di amministrazione di App engine.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.migration\">Accesso in lettura e scrittura per l\\'API Groups Migration.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.settings\">Visualizza e gestisci le impostazioni di un gruppo di applicazioni Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.licensing\">Accesso in lettura e scrittura per l\\'API License Manager.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order\">Leggi e scrivi gli accessi per amministratori ed utenti che eseguono test nel contenitore delle API, oppure leggi e scrivi gli accessi quando viene evocata una operazione API direttamente.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order.readonly\">In aggiunta all\\'ambito complessivo di lettura e scrittura OAuth, utilizza l\\'ambito di sola lettura OAuth quando richiedi i dati dell\\'utente.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps_reporting_audit.readonly\">Accedi in sola lettura per la API Admin Audit</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appstate\">Ambito di utilizzo del servizio App State.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery.readonly\">Visualizza i tuoi dati di Google BigQuery</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery\">Visualizza e gestisci i tuoi dati di Google BigQuery</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger\">Gestisci il tuo account Blogger</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger.readonly\">Visualizza il tuo account Blogger</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_books\">Gestisci i tuoi libri</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar\">Gestisci i tuoi calendari</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar.readonly\">Visualizza i tuoi calendari</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_cloudprint\">Visualizza e gestisci i tuoi dati di Google Cloud Print</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute.readonly\">Visualizza le tue risorse del motore Google Compute</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute\">Visualizza e gestisci le tue risorse del motore Google Compute</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate.readonly\">Visualizza i tuoi lavori di Google Coordinate</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate\">Visualizza e gestisci i tuoi lavori di Google Coordinate</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.full_control\">Gestisci i tuoi dati e le autorizzazione di Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_only\">Visualizza i tuoi dati di Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_write\">Gestisci i tuoi dati di Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_dfareporting\">Visualizza e gestisci i resoconti di DoubleClick per inserzionisti</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.appdata\">Permette l\\'accesso alla cartella dati dell\\'applicazione</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.apps.readonly\">Visualizza le tue applicazioni di Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.file\">Visualizza e gestisci i file di Google Drive aperti o creati con questa applicazione</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.install\">Ambito speciale utilizzato per permettere agli utenti l\\'installazione di una applicazione</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.metadata.readonly\">Visualizza i metadati per i file ed i documenti di Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.readonly\">Visualizza i tuoi file ed i tuoi documenti di Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.scripts\">Modifica il comportamento dei tuoi script di Google Apps Script</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive\">Visualizza e gestisci i tuoi file ed i tuoi documenti di Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase.readonly\">Visualizza il tuo account Freebase</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase\">Accedi a Freebase con il tuo account</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables\">Gestisci le tue tabelle di Fusion Tables</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables.readonly\">Visualizza le tue tabelle di Fusion Tables</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_games\">Ambito per accedere ai dati di Google Play Giochi.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan\">Gestisci i tuoi dati GAN</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan.readonly\">Visualizza i tuoi dati GAN</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gcm_for_chrome\">Messaggistica cloud per Chrome</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_glass.timeline\">Ambito della sequenza temporale di Glass</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.compose\">Crea, leggi, aggiorna, cancella bozze ed invia messaggi.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.modify\">Tutte le operazioni di lettura e scrittura ad eccezione dell\\'immediata e permanente cancellazione dei threads e dei messaggi, bypassando il cestino.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.readonly\">Visualizza tutte le risorse e i rispettivi metadati—nessuna operazione in scrittura.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.best\">Gestisci la tua migliore posizione disponibile e la cronologia delle localizzazioni</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.city\">Gestisci la tua localizzazione a livello urbano e la cronologia delle localizzazioni</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.best\">Gestisci la tua migliore posizione disponibile</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.city\">Gestisci la localizzazione a livello urbano</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine\">Visualizza e gestisci i tuoi dati del motore delle mappe Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine.readonly\">Visualizza i tuoi dati del motore delle mappe Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mobilemaps.firstparty\">Visualizza e gestisci l\\'esperienza mobile dell mappe Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut\">Gestisci le tue attività di Orkut</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut.readonly\">Visualizza i tuoi dati di Orkut</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.login\">Conoscere il tuo nome, le tue informazioni di base e la lista di persone con cui sei connesso su Google+</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.me\">Conoscere chi sei su Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_prediction\">Gestisci i tuoi dati per la API di Google Prediction</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_shoppingapi\">Visualizza i dati dei tuoi prodotti</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification\">Gestisci la lista di siti e di domini che controlli</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification.verify_only\">Gestisci le verifiche del tuo nuovo sito con Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_structuredcontent\">Accesso in lettura e scrittura per l\\'API Shopping Content.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue.consumer\">Svolgi attività dalla tua coda</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue\">Gestisci le tue attività</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks\">Gestisci le tue attività</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks.readonly\">Visualizza le tue attività</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tracks\">API per le tracce delle mappe Google: questo ambito permette la lettura e scrittura nella cartella dati del tuo progetto.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_urlshortener\">Gestisci i tuoi collegamenti rapidi goo.gl</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.email\">Visualizza il tuo indirizzo di posta elettronica</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.profile\">Visualizza le informazioni di base sul tuo account</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube\">Gestisci il tuo account Youtube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtubepartner\">Visualizza e gestisci le tue risorse ed i contenuti associati di YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.readonly\">Visualizza il tuo account YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.upload\">Gestisci i tuoi video di YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics_monetary.readonly\">Visualizza i resoconti monetari di YouTube Analytics per i tuoi contenuti YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics.readonly\">Visualizza i resoconti di YouTube Analytics per i tuoi contenuti YouTube</string>\n    <string name=\"perm_activity_recognition_label\">Riconoscimento attività</string>\n    <string name=\"perm_activity_recognition_description\">Consente a un\\'app di ricevere da Google aggiornamenti periodici sul tuo livello di attività, ad esempio se stai camminando, guidando, andando in bicicletta o se sei fermo.</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-it/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2017 microG Project Team\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  --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <plurals name=\"pref_unifiednlp_summary\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> fornitore configurato</item>\n        <item quantity=\"many\"><xliff:g example=\"1000000\">%1$d</xliff:g> di fornitori configurati</item>\n        <item quantity=\"other\"><xliff:g example=\"3\">%1$d</xliff:g> fornitori configurati</item>\n    </plurals>\n    <plurals name=\"gcm_registered_apps_counter\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> applicazione registrata</item>\n        <item quantity=\"many\"><xliff:g example=\"1000000\">%1$d</xliff:g> di applicazioni registrate</item>\n        <item quantity=\"other\"><xliff:g example=\"123\">%1$d</xliff:g> applicazioni registrate</item>\n    </plurals>\n    <plurals name=\"cond_perm_summary\">\n        <item quantity=\"one\">Non è stato concesso un permesso necessario al corretto funzionamento dei servizi microG.</item>\n        <item quantity=\"many\">Non sono stati concessi vari permessi necessari al corretto funzionamento dei servizi microG.</item>\n        <item quantity=\"other\">Non sono stati concessi alcuni permessi necessari al corretto funzionamento dei servizi microG.</item>\n    </plurals>\n    <plurals name=\"cond_perm_action\">\n        <item quantity=\"one\">Richiedi il permesso mancante</item>\n        <item quantity=\"many\">Richiedi i permessi mancanti</item>\n        <item quantity=\"other\">Richiedi i permessi mancanti</item>\n    </plurals>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-it/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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  --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"gms_app_name\">microG Services</string>\n    <string name=\"gms_settings_name\">Impostazioni di microG</string>\n    <string name=\"gms_settings_summary\">Configura i servizi microG.</string>\n    <string name=\"just_a_sec\">Solo un secondo…</string>\n    <string name=\"google_account_label\">Google</string>\n    <string name=\"ask_permission_tos\">Continuando autorizzi questa applicazione e Google a usare le tue informazioni in accordo con i rispettivi termini di servizio e politiche di riservatezza.</string>\n    <string name=\"ask_scope_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> vorrebbe:</string>\n    <string name=\"ask_service_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> vorrebbe utilizzare:</string>\n    <string name=\"account_manager_title\">Gestione dell\\'account Google</string>\n    <string name=\"sorry\">Ci dispiace…</string>\n    <string name=\"auth_before_connect\">Un\\'applicazione sul tuo dispositivo sta tentando di effettuare l\\'accesso ad un account Google.\\n\\nSe ciò era intenzionale, utilizza il pulsante <b>Accedi</b> per collegarti alla pagina di autenticazione di Google, altrimenti premi <b>Annulla</b> per tornare all\\'applicazione che ha aperto questa schermata.</string>\n    <string name=\"auth_sign_in\">Accedi</string>\n    <string name=\"auth_connecting\">\"Il tuo dispositivo sta stabilendo la connessione con i server di Google per autenticarti.\n\nQuesta operazione può richiedere alcuni secondi.\"</string>\n    <string name=\"no_network_error_desc\">Non disponi di una connessione a Internet.\\n\\nPotrebbe trattarsi di un disservizio temporaneo, oppure il tuo dispositivo Android potrebbe non essere configurato per utilizzare una connessione dati. Riprova una volta connesso a una rete cellulare o a una rete Wi-Fi.</string>\n    <string name=\"auth_general_error_desc\">C\\'è stato un problema di comunicazione con i server di Google.\\n\\nRiprova più tardi.</string>\n    <string name=\"auth_finalize\">Il tuo dispositivo sta comunicando con i server di Google per salvare le informazioni sul tuo account.\\n\\nQuesta operazione può richiedere alcuni minuti.</string>\n    <string name=\"allow\">Permetti</string>\n    <string name=\"deny\">Nega</string>\n    <string name=\"auth_notification_title\">Autenticazione necessaria</string>\n    <string name=\"auth_notification_content\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> richiede la tua autorizzazione per accedere al tuo account Google.</string>\n    <string name=\"perm_status_broadcast_label\">ascolto di broadcast interni di stato</string>\n    <string name=\"perm_c2dm_receive_label\">ascolto di messaggi C2DM</string>\n    <string name=\"perm_c2dm_send_label\">invio di messaggi C2DM ad altre applicazioni</string>\n    <string name=\"perm_gtalk_svc_label\">scambio di messaggi e ricezione di notifiche di sincronizzazione dai server Google</string>\n    <string name=\"perm_extended_access_label\">Accesso esteso ai servizi Google</string>\n    <string name=\"perm_provision_label\">configurazione dei servizi microG</string>\n    <string name=\"perm_provision_description\">Permette all\\'applicazione di configurare i servizi microG senza l\\'interazione dell\\'utente</string>\n    <string name=\"service_name_checkin\">Registrazione del dispositivo</string>\n    <string name=\"service_name_mcs\">Messaggistica cloud</string>\n    <string name=\"service_name_snet\">SafetyNet</string>\n    <string name=\"games_title\">Google Play Giochi</string>\n    <string name=\"games_info_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> vorrebbe utilizzare Play Giochi</string>\n    <string name=\"games_info_content\">Per usare Play Giochi è necessario installare l\\'applicazione Google Play Giochi. L\\'applicazione può continuare ad essere utilizzata senza Play Giochi, ma è possibile che funzioni in modo anomalo.</string>\n    <string name=\"pick_place_title\">Seleziona un luogo</string>\n    <string name=\"pick_place_desc\">Non è ancora possibile selezionare un luogo.</string>\n    <string name=\"place_picker_select_title\">Seleziona questo luogo</string>\n    <string name=\"place_picker_nearby_places\">Luoghi vicini</string>\n    <string name=\"place_picker_location_lat_lng\">(%1$.7f, %2$.7f)</string>\n    <string name=\"lacking_permission_toast\">microG: Il permesso di <xliff:g example=\"have full network acccess\">%1$s</xliff:g> non è stato concesso</string>\n    <string name=\"network_type_mobile\">Reti mobili</string>\n    <string name=\"network_type_wifi\">Wi-Fi</string>\n    <string name=\"network_type_roaming\">Roaming</string>\n    <string name=\"network_type_other\">Altre reti</string>\n    <!-- Self check -->\n    <string name=\"self_check_cat_fake_sig\">Supporto alla falsificazione della firma</string>\n    <string name=\"self_check_cat_gms_packages\">Pacchetti installati</string>\n    <string name=\"self_check_cat_system\">Sistema</string>\n    <string name=\"self_check_name_fake_sig_perm\">Il sistema supporta la falsificazione della firma: </string>\n    <string name=\"self_check_resolution_fake_sig_perm\">La tua ROM non dispone del supporto nativo per la falsificazione della firma. Puoi comunque utilizzare Xposed o altri sistemi per garantire la falsificazione della firma. Consulta la documentazione per conoscere quali ROM supportano questa funzionalità e come utilizzare microG sulle ROM che non la supportano.</string>\n    <string name=\"self_check_name_perm_granted\">Il sistema concede l\\'autorizzazione a falsificare la firma: </string>\n    <string name=\"self_check_resolution_perm_granted\">Ciò indica che la ROM attuale supporta la falsificazione della firma, ma richiede azioni ulteriori per attivarla. Consulta la documentazione per conoscere quali operazioni siano necessarie.</string>\n    <string name=\"self_check_name_system_spoofs\">Il sistema falsifica la firma: </string>\n    <string name=\"self_check_resolution_system_spoofs\">Consulta la documentazione per conoscere quali operazioni siano necessarie.</string>\n    <string name=\"self_check_pkg_gms\">microG Services</string>\n    <string name=\"self_check_pkg_vending\">microG Companion / Play Store</string>\n    <string name=\"self_check_pkg_gsf\">microG Services Framework</string>\n    <string name=\"self_check_name_app_installed\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> installato: </string>\n    <string name=\"self_check_resolution_app_installed\">Installa l\\'applicazione <xliff:g example=\"F-Droid\">%1$s</xliff:g> oppure un\\'altra compatibile. Consulta la documentazione per conoscere quali applicazioni siano compatibili.</string>\n    <string name=\"self_check_name_correct_sig\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> ha la firma corretta: </string>\n    <string name=\"self_check_resolution_correct_sig\">L\\'applicazione <xliff:g example=\"F-Droid\">%1$s</xliff:g> non è compatibile oppure la falsificazione della sua firma non è abilitata. Consulta la documentazione per conoscere quali applicazioni e ROM siano compatibili.</string>\n    <string name=\"self_check_name_battery_optimizations\">Ottimizzazioni della batteria ignorate:</string>\n    <string name=\"self_check_resolution_battery_optimizations\">Tocca qui per disabilitare le ottimizzazioni della batteria. Non selezionare questa opzione potrebbe comportare il malfunzionamento delle applicazioni.</string>\n    <!-- Settings strings -->\n    <string name=\"prefcat_about\">Informazioni</string>\n    <string name=\"prefcat_components\">Componenti</string>\n    <string name=\"prefcat_configuration\">Configurazione</string>\n    <string name=\"prefcat_google_services\">Servizi Google</string>\n    <string name=\"prefcat_location_service\">Servizi di localizzazione</string>\n    <string name=\"prefcat_services\">Servizi</string>\n    <string name=\"prefcat_test\">Sperimentale</string>\n    <string name=\"cond_gcm_bat_title\">Ottimizzazioni della batteria abilitate</string>\n    <string name=\"cond_gcm_bat_summary\">Hai abilitato il servizio di messaggistica cloud, tuttavia le ottimizzazioni della batteria sono abilitate per microG. Al fine di garantire la ricezione delle notifiche push, dovresti selezionare l\\'opzione per ignorare le ottimizzazioni della batteria.</string>\n    <string name=\"cond_gcm_bat_action\">Ignora ottimizzazioni</string>\n    <string name=\"cond_perm_title\">Permesso mancante</string>\n    <string name=\"prefs_account\">Preferenze dell\\'account</string>\n    <string name=\"prefs_account_privacy\">Informazioni personali e riservatezza</string>\n    <string name=\"prefs_account_security\">Accesso e sicurezza</string>\n    <string name=\"pref_auth_trust_google_title\">Dai fiducia a Google per i permessi alle applicazioni</string>\n    <string name=\"pref_auth_trust_google_summary\">Quando l\\'opzione è disabilitata, l\\'utente viene interpellato prima che ogni richiesta di autorizzazione da parte di un\\'app venga inviata a Google. Alcune applicazioni non riusciranno a utilizzare l\\'account Google se questa opzione è disabilitata.</string>\n    <string name=\"pref_auth_visible_title\">Consenti alle applicazioni di visualizzare gli account</string>\n    <string name=\"pref_auth_visible_summary\">Quando l\\'opzione è abilitata, tutte le applicazioni su questo dispositivo saranno in grado di visualizzare gli indirizzi di posta elettronica degli account Google senza autorizzazione preventiva.</string>\n    <string name=\"pref_checkin_enable_summary\">Registra il tuo dispositivo ai servizi Google e crea un identificativo univoco. microG rimuove dai dati di registrazione alcune parti funzionali all\\'identificazione, oltre al nome dell\\'account Google.</string>\n    <string name=\"pref_device_registration_android_id\">Identificativo univoco Android</string>\n    <string name=\"checkin_not_registered\">Non registrato</string>\n    <string name=\"checkin_last_registration\">Ultima registrazione: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"checkin_enable_switch\">Registra il dispositivo</string>\n    <string name=\"pref_info_status\">Stato</string>\n    <string name=\"pref_more_settings\">Impostazioni avanzate</string>\n    <string name=\"pref_add_account_title\">Account</string>\n    <string name=\"pref_add_account_summary\">Aggiungi un account Google</string>\n    <string name=\"pref_gcm_enable_mcs_summary\">Il servizio di messaggistica cloud di Google è un fornitore di notifiche push utilizzato da molte applicazioni di terze parti. Per poterlo utilizzare devi abilitare la registrazione del dispositivo.</string>\n    <string name=\"pref_gcm_heartbeat_title\">Intervallo di aggiornamento del servizio di messaggistica cloud</string>\n    <string name=\"pref_gcm_heartbeat_summary\">L\\'intervallo temporale, espresso in secondi, utilizzato dal sistema per contattare i server di Google. Aumentare questo intervallo ridurrà il consumo di batteria, tuttavia potrebbe causare ritardi nella ricezione delle notifiche push.\\nDeprecato, verrà rimpiazzato in versioni future.</string>\n    <string name=\"pref_gcm_apps_title\">Applicazioni che utilizzano il servizio di messaggistica cloud</string>\n    <string name=\"pref_gcm_apps_summary\">Elenco delle app attualmente registrate al servizio di messaggistica cloud.</string>\n    <string name=\"pref_gcm_confirm_new_apps_title\">Conferma le nuove applicazioni</string>\n    <string name=\"pref_gcm_confirm_new_apps_summary\">Chiedi conferma all\\'utente prima di registrare una nuova applicazione per le notifiche push</string>\n    <string name=\"pref_gcm_ping_interval\">Intervallo di ping: <xliff:g example=\"10 minutes\">%1$s</xliff:g></string>\n    <string name=\"pref_about_title\">A proposito di microG</string>\n    <string name=\"pref_about_summary\">Informazioni sulla versione e sulle librerie utilizzate</string>\n    <string name=\"gcm_app_error_unregistering\">Errore durante l\\'annullamento della registrazione</string>\n    <string name=\"gcm_app_not_installed_anymore\">Non più installata</string>\n    <string name=\"gcm_unregister_app\">Annulla la registrazione</string>\n    <string name=\"gcm_not_registered\">Non registrata</string>\n    <string name=\"gcm_no_message_yet\">Nessun messaggio ricevuto fino ad ora</string>\n    <string name=\"gcm_last_message_at\">Ultimo messaggio: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_registered\">Registrata</string>\n    <string name=\"gcm_registered_since\">Registrata: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_unregister_confirm_title\">Annulla la registrazione di <xliff:g example=\"F-Droid\">%1$s</xliff:g>?</string>\n    <string name=\"gcm_unregister_confirm_message\">Alcune applicazioni non rinnovano automaticamente la registrazione o non forniscono un\\'opzione per farlo manualmente. Queste applicazioni potrebbero non funzionare correttamente a seguito dell\\'annullamento della registrazione.\\nVuoi continuare?</string>\n    <string name=\"gcm_unregister_after_deny_message\">Hai negato a un\\'applicazione, già registrata in precedenza, di registrarsi per la ricezione delle notifiche push.\\nDesideri annullare la registrazione così che non riceva più notifiche push in futuro?</string>\n    <string name=\"gcm_messages_counter\">Messaggi: <xliff:g example=\"123\">%1$d</xliff:g> (<xliff:g example=\"12345\">%2$d</xliff:g> bytes)</string>\n    <string name=\"gcm_network_state_disconnected\">Disconnesso</string>\n    <string name=\"gcm_network_state_connected\">Connesso <xliff:g example=\"2 hours ago\">%1$s</xliff:g></string>\n    <string name=\"gcm_enable_switch\">Ricevi le notifiche push</string>\n    <string name=\"gcm_allow_app_popup\">Vuoi consentire a <xliff:g example=\"F-Droid\">%1$s</xliff:g> di registrarsi per la ricezione delle notifiche push?</string>\n    <string name=\"pref_push_app_allow_register_title\">Permetti la registrazione</string>\n    <string name=\"pref_push_app_allow_register_summary\">Consenti all\\'applicazione di registrarsi per la ricezione delle notifiche push.</string>\n    <string name=\"pref_push_app_wake_for_delivery_title\">Avvia alla ricezione</string>\n    <string name=\"pref_push_app_wake_for_delivery_summary\">Avvia l\\'applicazione in background in seguito alla ricezione delle notifiche push.</string>\n    <string name=\"prefcat_push_apps_title\">Applicazioni che utilizzano le notifiche push</string>\n    <string name=\"prefcat_push_apps_registered_title\">Applicazioni registrate</string>\n    <string name=\"prefcat_push_apps_unregistered_title\">Applicazioni non registrate</string>\n    <string name=\"prefcat_push_networks_title\">Reti da utilizzare per le notifiche push</string>\n    <string name=\"safetynet_intro\">SafetyNet di Google è un sistema di certificazione del dispositivo che ne garantisce la sicurezza e la compatibilità con Android CTS. Alcune applicazioni utilizzano SafetyNet per ragioni di sicurezza o come prerequisito per la protezione da manomissione.\\n\\nUn\\'implementazione libera di SafetyNet è contenuta in microG, tuttavia i server ufficiali richiedono che le richieste SafetyNet siano firmate utilizzando il sistema proprietario DroidGuard.</string>\n    <string name=\"safetynet_enable_switch\">Permetti l\\'attestazione del dispositivo</string>\n    <string name=\"pref_safetynet_test_title\">Prova l\\'attestazione di SafetyNet</string>\n    <string name=\"pref_recaptcha_test_title\">Prova ReCAPTCHA</string>\n    <string name=\"pref_recaptcha_enterprise_test_title\">Prova ReCAPTCHA Enterprise</string>\n    <string name=\"pref_test_summary_passed\">Tutti i test superati</string>\n    <string name=\"pref_test_summary_failed\">Fallito: %s</string>\n    <string name=\"pref_test_summary_warn\">Attenzione: %s</string>\n    <string name=\"pref_test_summary_running\">In esecuzione…</string>\n    <string name=\"pref_droidguard_operation_mode\">Modalità operativa</string>\n    <string name=\"prefcat_safetynet_apps_title\">Applicazioni che utilizzano SafetyNet</string>\n    <string name=\"menu_clear_recent_requests\">Rimuovi richieste recenti</string>\n    <string name=\"safetynet_last_run_at\">Ultimo utilizzo: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"profile_name_native\">Nativo</string>\n    <string name=\"profile_name_real\">Reale</string>\n    <string name=\"profile_name_user\">Personalizzato: %s</string>\n    <string name=\"profile_name_auto\">Automatico: %s</string>\n    <string name=\"profile_name_system\">Sistema: %s</string>\n    <string name=\"pref_device_registration_import_custom_profile_title\">Importa profilo personalizzato</string>\n    <string name=\"pref_device_registration_serial_title\">Seriale</string>\n    <string name=\"pref_device_registration_import_custom_profile_summary\">Importa un profilo del dispositivo da un file</string>\n    <string name=\"pref_device_registration_select_profile_title\">Seleziona profilo</string>\n    <string name=\"pref_device_registration_device_profile_category\">Profilo del dispositivo</string>\n    <string name=\"pref_safetynet_recent_uses\">Utilizzi recenti</string>\n    <string name=\"pref_safetynet_recent_attestation_summary\">Attestazione: %s</string>\n    <string name=\"pref_safetynet_recent_recaptcha_summary\">ReCaptcha: %s</string>\n    <string name=\"pref_safetynet_recent_copy_json\">Copia dati JSON JWS</string>\n    <string name=\"pref_safetynet_recent_eval_type\">Tipo di valutazione</string>\n    <string name=\"pref_safetynet_recent_response_status\">Stato della risposta</string>\n    <string name=\"pref_safetynet_recent_cat_response\">Dati della risposta</string>\n    <string name=\"pref_safetynet_recent_cat_request\">Dati della richiesta</string>\n    <string name=\"pref_safetynet_recent_nonce\">Nonce (esadecimale)</string>\n    <string name=\"pref_safetynet_recent_request_time\">Data e ora della richiesta</string>\n    <string name=\"pref_safetynet_recent_cat_basic\">Dati di base</string>\n    <string name=\"pref_safetynet_recent_request_type\">Tipo di richiesta</string>\n    <string name=\"pref_safetynet_recent_token\">Token</string>\n    <string name=\"pref_safetynet_recent_copied\">Copiato negli appunti!</string>\n    <string name=\"pref_safetynet_test_not_completed\">Non ancora completato</string>\n    <string name=\"pref_safetynet_test_no_result\">Nessun risultato</string>\n    <string name=\"pref_safetynet_test_invalid_json\">JSON non valido</string>\n    <string name=\"pref_safetynet_recent_advice\">Suggerimento</string>\n    <string name=\"pref_safetynet_test_integrity_cts_passed\">Integrità e CTS superati</string>\n    <string name=\"pref_safetynet_test_cts_failed\">CTS non superato</string>\n    <string name=\"pref_safetynet_test_integrity_failed\">Integrità non superata</string>\n    <string name=\"push_notifications_summary_values_seconds\">%s secondi</string>\n    <string name=\"pref_safetynet_recent_recaptcha_enterprise_summary\">ReCaptcha Enterprise: %s</string>\n    <string name=\"push_notifications_summary_automatic\">Abilitato / Automatico: %s</string>\n    <string name=\"push_notifications_summary_manual\">Abilitato / Manuale: %s</string>\n    <string name=\"push_notifications_summary_values_minutes\">%s minuti</string>\n    <string name=\"push_notifications_summary_off\">Disabilitato</string>\n    <string name=\"signin_subtext_policy_privacy\">informativa sulla privacy</string>\n    <string name=\"perm_gsf_read_gservices_label\">lettura della configurazione dei servizi Google</string>\n    <string name=\"signin_picker_title\">Scegli un account</string>\n    <string name=\"pref_auth_include_android_id_summary\">Se l\\'opzione è disabilitata, le richieste di autenticazione non saranno collegate alla registrazione del dispositivo. Ciò può consentire a dispositivi non autorizzati di effettuare l\\'accesso, ma potrebbe avere delle conseguenze impreviste.</string>\n    <string name=\"signin_picker_subtitle\">per continuare su <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"pref_droidguard_unsupported_summary\">L\\'esecuzione di DroidGuard non è supportata su questo dispositivo. I servizi di SafetyNet potrebbero funzionare in maniera anomala.</string>\n    <string name=\"signin_confirm_title\">Consenti l\\'accesso a <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"signin_picker_add_account_label\">Aggiungi un altro account</string>\n    <string name=\"signin_confirm_button_text\">Consenti e condividi</string>\n    <string name=\"signin_subtext_policy\">Prima di usare quest\\'app, consulta la sua %1$s e i %2$s.</string>\n    <string name=\"signin_subtext_sharing\">Per continuare, microG condividerà il nome, l\\'indirizzo email e l\\'immagine del profilo del tuo account Google con <xliff:g example=\"F-Droid\">%1$s</xliff:g>.</string>\n    <string name=\"pref_auth_include_android_id_title\">Autenticazione con registrazione del dispositivo</string>\n    <string name=\"signin_subtext_policy_terms\">termini di servizio</string>\n    <string name=\"pref_vending_summary_licensing_on\">Verifica delle licenze abilitata</string>\n    <string name=\"service_name_vending\">Servizi Play Store</string>\n    <string name=\"pref_vending_licensing_enable_switch\">Rispondi alle richieste di verifica delle licenze</string>\n    <string name=\"feedback_disabled\">Non è possibile inviare feedback al momento</string>\n    <string name=\"pref_vending_summary_licensing_off\">Verifica delle licenze disabilitata</string>\n    <string name=\"pref_vending_license_enable_summary\">Alcune app richiedono la verifica dell\\'acquisto da Google Play. Quando un\\'app lo richiede, microG può scaricare una prova dell\\'acquisto da Google. Se l\\'opzione è disabilitata, o se non è stato aggiunto nessun account Google, le richieste di verifica delle licenze vengono ignorate.</string>\n    <string name=\"pref_accounts_title\">Account Google</string>\n    <string name=\"pref_accounts_summary\">Aggiungi e gestisci gli account Google</string>\n    <string name=\"prefcat_accounts_settings_title\">Impostazioni</string>\n    <string name=\"pref_vending_licensing_category\">Verifica delle licenze di Google Play</string>\n    <string name=\"backup_disabled\">Non è possibile effettuare backup al momento</string>\n    <string name=\"prefcat_accounts_current_accounts_title\">Account</string>\n    <string name=\"pref_vending_billing_category\">Pagamenti di Google Play</string>\n    <string name=\"pref_vending_billing_enable_switch\">Gestisci le richieste di pagamento</string>\n    <string name=\"pref_vending_billing_enable_summary\">Se l\\'opzione è abilitata, alcune app potranno completare acquisti o sottoscrivere abbonamenti tramite il servizio di pagamenti di Google Play.</string>\n    <string name=\"pref_auth_strip_device_name_summary\">Se l\\'opzione è abilitata, le richieste di autenticazione non includeranno il nome del dispositivo. Ciò può consentire a dispositivi non autorizzati di effettuare l\\'accesso, ma potrebbe avere delle conseguenze impreviste.</string>\n    <string name=\"pref_auth_strip_device_name_title\">Rimuovi il nome del dispositivo per l\\'autenticazione</string>\n    <string name=\"perm_car_speed_label\">Velocità dell\\'auto</string>\n    <string name=\"perm_car_speed_description\">Accesso alla velocità della tua auto</string>\n    <string name=\"perm_car_info_label\">Informazioni sull\\'auto</string>\n    <string name=\"perm_car_info_description\">Accesso alle informazioni della tua auto</string>\n    <string name=\"perm_car_fuel_label\">Livello di carburante dell\\'auto</string>\n    <string name=\"perm_car_fuel_description\">Accesso alle informazioni sul livello di carburante della tua auto</string>\n    <string name=\"perm_car_mileage_label\">Consumo di carburante dell\\'auto</string>\n    <string name=\"perm_car_vendor_extension_label\">Canale del produttore dell\\'auto</string>\n    <string name=\"perm_car_vendor_extension_description\">Accesso al canale del produttore per lo scambio di informazioni specifiche sull\\'auto</string>\n    <string name=\"perm_car_mileage_description\">Accesso alle informazioni sul consumo di carburante della tua auto</string>\n    <string name=\"credentials_assisted_cancel\">Annulla</string>\n    <string name=\"credentials_assisted_continue\">Continua</string>\n    <string name=\"credentials_assisted_sign_back_title\">Accedi di nuovo a %1$s con Google</string>\n    <string name=\"credentials_assisted_signin_consent_header\">Accedendo come %1$s</string>\n    <string name=\"credentials_assisted_confirmation_header\">Accesso in corso</string>\n    <string name=\"credentials_assisted_signin_button_text_long\">Accedi con Google</string>\n    <string name=\"credentials_assisted_signin_description\">Puoi gestire l\\'accesso con Google nei tuoi account Google.</string>\n    <string name=\"credentials_assisted_choose_account_subtitle\">per continuare su %1$s</string>\n    <string name=\"credentials_assisted_continue_as_user_button_label\">Continua come %1$s</string>\n    <string name=\"credentials_assisted_choose_account_label\">Scegli l\\'account</string>\n    <string name=\"credentials_assisted_signin_consent\">Continuando, Google condividerà il tuo nome, indirizzo email e immagine del profilo con %1$s. Consulta l\\'Informativa sulla privacy e i Termini di servizio di %1$s.</string>\n    <string name=\"pref_vending_billing_note_licensing\">Alcune applicazioni potrebbero richiedere anche di abilitare la verifica della licenza per verificare i tuoi acquisti.</string>\n    <string name=\"pref_vending_billing_note_experimental\">Questa funzionalità è ancora sperimentale e potrebbe comportare la perdita di denaro. Sei stato avvisato.</string>\n    <string name=\"auth_package_override_request_title\">Permetti a <b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> l\\'accesso privilegiato a <xliff:g example=\"account@example.com\">%2$s</xliff:g>\\?</string>\n    <string name=\"limited_services_app_name\">microG Limited Services</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_switch\">Aggiungi automaticamente le app gratuite alla libreria</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_summary\">Le app gratuite possono verificare se sono state scaricate da Google Play. Aggiungi automaticamente le app gratuite alla libreria del tuo account per superare sempre il controllo per tutte le app gratuite attualmente disponibili per te.</string>\n    <string name=\"limited_services_dialog_information_ack\">Ho capito</string>\n    <string name=\"auth_package_override_request_message\"><b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> vorrebbe accedere al tuo account come se fosse <b><xliff:g example=\"F-Droid\">%2$s</xliff:g> di <xliff:g example=\"F-Droid Inc.\">%3$s</xliff:g></b>. Ciò potrebbe garantirgli un accesso privilegiato al tuo account.</string>\n    <string name=\"limited_services_dialog_information\">Stai utilizzando microG Limited Services. A differenza dei soliti servizi microG, questa versione funziona solo con le app che utilizzano le librerie microG, non quelle su Google Play. Ciò significa che la maggior parte delle applicazioni ignorerà questi servizi.</string>\n    <string name=\"auth_action_notification_channel_name\">Avvisi dell\\'account Google</string>\n    <string name=\"auth_action_notification_title\">Azione richiesta sull\\'account</string>\n    <string name=\"auth_action_notification_content\">Il tuo account Google richiede una configurazione aggiuntiva.</string>\n    <string name=\"auth_action_activity_header\">Completa la configurazione del tuo account Google</string>\n    <string name=\"auth_action_activity_explanation\">Completa i seguenti passaggi per poter utilizzare il tuo account Google %s su questo dispositivo.</string>\n    <string name=\"auth_action_step_enable_checkin_description\">Il tuo dispositivo deve registrarsi ai servizi Google almeno una volta.\\n\\nPuoi disattivare la registrazione del dispositivo dopo aver completato la configurazione dell\\'account.</string>\n    <string name=\"auth_action_step_enable_checkin\">Abilita la registrazione del dispositivo</string>\n    <string name=\"auth_action_step_enable_gcm\">Abilita messaggistica cloud</string>\n    <string name=\"auth_action_step_enable_gcm_description\">Una volta completata la configurazione dell\\'account, puoi disattivare il servizio di messaggistica cloud.</string>\n    <string name=\"auth_action_step_allow_microg_gcm\">Consenti messaggistica cloud per microG</string>\n    <string name=\"auth_action_step_perform_content_description\">Tocca per confermare</string>\n    <string name=\"auth_action_step_completed_content_description\">Operazione completata</string>\n    <string name=\"auth_action_activity_finish\">Fine</string>\n    <string name=\"auth_action_notification_channel_description\">Ti avvisa quando uno dei tuoi account Google richiede una configurazione aggiuntiva prima di poter essere utilizzato o quando un account non è compatibile con microG.</string>\n    <string name=\"auth_action_step_allow_microg_gcm_description\">In base alle tue preferenze, microG ha bisogno della tua autorizzazione prima di potersi registrare al servizio di messaggistica cloud.</string>\n    <string name=\"auth_action_step_enable_lockscreen\">Configura il blocco schermo sicuro</string>\n    <string name=\"auth_action_step_enable_lockscreen_description\">Il tuo account Google è gestito dalla tua azienda o istituto scolastico. L\\'amministratore ha deciso che i dispositivi necessitano di un blocco schermo sicuro prima di poter accedere ai dati dell\\'account.\\n\\nImposta una password, un PIN o una sequenza per la schermata di blocco.</string>\n    <string name=\"pref_vending_asset_delivery_category\">Google Play Asset Delivery</string>\n    <string name=\"pref_vending_asset_delivery_switch\">Abilita il download delle risorse su richiesta</string>\n    <string name=\"pref_vending_asset_delivery_summary\">Consenti lo scaricamento di risorse aggiuntive su richiesta delle app che utilizzano Play Asset Delivery</string>\n    <string name=\"pref_vending_asset_device_sync_summary\">Le app che utilizzano Play Asset Delivery scaricheranno delle risorse aggiuntive in base alle informazioni del dispositivo in uso.</string>\n    <string name=\"pref_vending_asset_device_sync_switch\">Abilita sincronizzazione delle informazioni del dispositivo</string>\n    <string name=\"games_delete_snapshot_dialog_cancel\">Annulla</string>\n    <string name=\"games_delete_snapshot_dialog_ok\">OK</string>\n    <string name=\"games_delete_snapshot_error\">Eliminazione fallita, riprova più tardi</string>\n    <string name=\"games_achievement_extra_text\">%1$s XP</string>\n    <string name=\"games_achievement_unlocked_content_description\">sbloccato</string>\n    <string name=\"games_achievement_locked_content_description\">bloccato</string>\n    <string name=\"games_api_access_denied\">Nessun account su questo dispositivo può accedere alle API di Giochi</string>\n    <string name=\"games_achievement_list_title\">Obiettivi</string>\n    <string name=\"games_leaderboard_empty_text\">Non ci sono classifiche per questo gioco</string>\n    <string name=\"games_achievements_empty_text\">Non ci sono obiettivi per questo gioco</string>\n    <string name=\"games_leaderboards_score_label\">Punteggio: %1$s</string>\n    <string name=\"games_leaderboard_list_title\">Classifiche</string>\n    <string name=\"games_leaderboard_score_empty_text\">Incredibile! Non ci sono record pubblici per questo gioco.</string>\n    <string name=\"games_snapshot_choose_btn_text\">Seleziona</string>\n    <string name=\"games_snapshot_delete_btn_text\">Elimina</string>\n    <string name=\"games_delete_snapshot_dialog_title\">Elimina partita salvata</string>\n    <string name=\"games_delete_snapshot_dialog_message\">Sei sicuro di voler eliminare questa partita salvata?</string>\n    <string name=\"games_snapshot_empty_text\">Non ci sono ancora partite salvate</string>\n    <string name=\"service_name_work_profile\">Profilo di lavoro</string>\n    <string name=\"pref_vending_split_install_switch\">Installazione dei componenti su richiesta</string>\n    <string name=\"pref_vending_licensing_split_install_summary\">Consenti alle app di scaricare e installare componenti aggiuntivi</string>\n    <string name=\"pref_vending_feature_delivery\">Google Play Feature Delivery</string>\n    <string name=\"credentials_assisted_choose_account_error_tips\">Anomalia dell\\'account</string>\n    <string name=\"camera_permission_dialog_button\">OK</string>\n    <string name=\"credentials_assisted_signin_add_account\">Aggiungi account</string>\n    <string name=\"camera_permission_dialog_title\">Accesso alla fotocamera richiesto</string>\n    <string name=\"camera_permission_dialog_message\">microG Services richiede l\\'accesso alla fotocamera del dispositivo per poter scansionare un codice per %1$s.\\n\\nPer procedere, consenti l\\'accesso alla fotocamera a microG Services nelle Impostazioni.</string>\n    <string name=\"barcode_scanner_brand\">Scansionato da microG per conto di %1$s</string>\n    <string name=\"pref_workprofile_create_account\">Permetti la configurazione dell\\'account di lavoro</string>\n    <string name=\"pref_workprofile_disclaimer\">È tua responsabilità assicurarti che l\\'utilizzo di microG sia conforme alle politiche aziendali. microG è fornito nel miglior modo possibile e non può garantire di comportarsi esattamente come previsto.</string>\n    <string name=\"pref_workprofile_intro\">Quando si imposta un profilo di lavoro per la propria azienda o istituto scolastico, il processo di configurazione potrebbe tentare di connettersi a Google per consentire il download di app su quel profilo.</string>\n    <string name=\"auth_action_reauth_notification_title\">Richiesta azione dell\\'account</string>\n    <string name=\"pref_auth_two_step_verification_title\">Ricevi richieste di verifica in due passaggi</string>\n    <string name=\"pref_auth_two_step_verification_summary\">Quando l\\'opzione è abilitata, il dispositivo può ricevere richieste di verifica in due passaggi da Google (la messaggistica cloud dev\\'essere attiva).</string>\n    <string name=\"pref_game_accounts_title\">Account Google Giochi</string>\n    <string name=\"pref_auto_create_player\">Permetti la registrazione degli account Play Giochi</string>\n    <string name=\"pref_auto_create_player_intro\">Quando giochi, devi utilizzare un account Play Giochi per accedere e registrare le funzioni relative al gioco, come risultati, classifiche, archivi, ecc. Dopo la disabilitazione, gli account Google non associati a un account Play Giochi non verranno registrati automaticamente e il gioco non potrà accedere e giocare.</string>\n    <string name=\"pref_allow_upload_game_played\">Consenti caricamento giochi giocati</string>\n    <string name=\"pref_allow_upload_game_played_summary\">Quando l\\'opzione è disabilitata, il gioco non segnalerà lo stato \\\"giocato\\\" dopo l\\'accesso. Alcuni giochi potrebbero non riuscire ad accedere.</string>\n    <string name=\"pref_change_default_game_player\">Cambia account per i giochi</string>\n    <string name=\"pref_change_default_game_player_summary\">Cambia l\\'account predefinito per i giochi e cambia l\\'account per gioco.</string>\n    <string name=\"pref_delete_game_account_data\">Elimina dati Play Giochi</string>\n    <string name=\"pref_delete_game_account_data_summary\">Elimina account Play Giochi e tutti i dati ed elimina dati dei singoli giochi.</string>\n    <string name=\"games_state_description_signed_out\">Disconnesso</string>\n    <string name=\"games_state_description_delete\">Elimina</string>\n    <string name=\"games_change_button_text\">Cambia</string>\n    <string name=\"games_change_default_account_section_title\">Cambia l\\'account predefinito per i giochi</string>\n    <string name=\"games_change_default_account_description\">Account predefinito: %1$s</string>\n    <string name=\"games_change_default_account_explanation\">Questo account viene utilizzato per accedere automaticamente ai giochi, salvare i progressi di gioco e salvare le impostazioni. Cambiare l\\'account predefinito o disconnettersi potrebbe reimpostare i progressi e le impostazioni dei giochi a cui hai giocato.</string>\n    <string name=\"games_change_per_game_title\">Cambia account per gioco</string>\n    <string name=\"games_change_per_game_description\">Cambiare l\\'account per un gioco selezionato o disconnettersi da esso potrebbe reimpostare i progressi e le impostazioni del gioco.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_title\">Seleziona un\\'opzione per il nuovo account predefinito</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_description\">Account predefinito attuale: %1$s</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_title\">Cambia l\\'account predefinito solo per i nuovi giochi</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_description\">Non perderai l\\'accesso ai progressi e alle impostazioni dei giochi a cui hai giocato. Ma i tuoi progressi saranno divisi tra gli account.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_title\">Cambia l\\'account predefinito per tutti i giochi</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_description\">Potresti perdere l\\'accesso ai progressi e alle impostazioni dei giochi a cui hai giocato. Riavvieremo il gioco per applicare le modifiche.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_title\">Disconnetti da tutti i giochi</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_description\">Potresti perdere l\\'accesso ai progressi e alle impostazioni dei giochi a cui hai giocato. Riavvieremo il gioco per applicare le modifiche.</string>\n    <string name=\"games_change_per_game_dialog_title\">Seleziona un\\'opzione per questo gioco</string>\n    <string name=\"games_change_per_game_dialog_description\">Cambiare l\\'account o disconnettersi potrebbe reimpostare i tuoi progressi e le impostazioni del gioco</string>\n    <string name=\"games_change_per_game_dialog_option_use_player\">Usa %1$s</string>\n    <string name=\"games_change_per_game_dialog_option_use_player_snackbar_success_message\">Accederai a questo gioco con %1$s</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out\">Disconnetti</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out_snackbar_success_message\">Ora sei disconnesso da questo gioco</string>\n    <string name=\"games_change_sign_out_of_all_games_snackbar_success_message\">Ora sei disconnesso da tutti i giochi</string>\n    <string name=\"games_change_default_account_for_all_games_snackbar_success_message\">Accederai a tutti i giochi con %1$s</string>\n    <string name=\"games_change_default_account_for_new_games_snackbar_success_message\">Accederai ai nuovi giochi con %1$s</string>\n    <string name=\"games_account_display_content\">Account corrente: %1$s</string>\n    <string name=\"games_delete_profile_header\">Elimina account Play Giochi e tutti i dati</string>\n    <string name=\"games_delete_profile_explanation\">Elimina definitivamente il tuo account Google Play Giochi, XP e tutti i dati del profilo. Questa azione potrebbe anche eliminare i tuoi punteggi, progressi (partite salvate) e impostazioni nei giochi che hai giocato.</string>\n    <string name=\"games_delete_profile_button\">Elimina definitivamente</string>\n    <string name=\"games_delete_game_data_header\">Elimina dati dei singoli giochi</string>\n    <string name=\"games_delete_game_data_explanation\">Puoi eliminare definitivamente i dati per i singoli giochi che hai giocato usando Google Play Giochi. Questa azione elimina i tuoi punteggi, progressi (partite salvate) e impostazioni per il gioco che selezioni.</string>\n    <string name=\"games_delete_profile_dialog_title\">Sei sicuro di voler eliminare questo account?</string>\n    <string name=\"games_delete_profile_explanation_with_gamer_name\">Elimina definitivamente il tuo account Google Play Giochi per il nome giocatore <b>%1$s</b> (<b>%2$s</b>), XP e tutti i dati del profilo. Questa azione potrebbe anche eliminare i tuoi punteggi, progressi (partite salvate) e impostazioni nei giochi che hai giocato.</string>\n    <string name=\"games_delete_profile_dialog_message\">Questa azione non può essere annullata.</string>\n    <string name=\"games_delete_profile_fail\">Impossibile eliminare il tuo profilo. Riprova più tardi.</string>\n    <string name=\"games_delete_game_data_confirm_dialog_title\">Elimina dati per %1$s</string>\n    <string name=\"games_delete_game_data_confirm_dialog_message\">Eliminando definitivamente i tuoi dati per %1$s rimuoverai i tuoi punteggi, progressi (partite salvate) e impostazioni di gioco in Google Play Giochi.</string>\n    <string name=\"games_popup_signin_welcome\">Ciao, %1$s</string>\n    <string name=\"service_name_device_attestation\">Certificazione del dispositivo</string>\n    <string name=\"prefcat_device_attestation_apps_title\">App con certificazione del dispositivo</string>\n    <string name=\"pref_device_attestation_app_allow_requests_title\">Consenti richieste</string>\n    <string name=\"pref_device_attestation_app_allow_requests_summary\">Consenti all’app di richiedere la certificazione del dispositivo</string>\n    <string name=\"family_management_title\">Famiglia</string>\n    <string name=\"family_management_retry\">Riprova</string>\n    <string name=\"family_management_load_error\">Caricamento contenuto fallito</string>\n    <string name=\"family_management_toolbar_back\">Indietro</string>\n    <string name=\"family_management_toolbar_more\">Altro</string>\n    <string name=\"family_management_exit_family_group\">Abbandona il gruppo famiglia</string>\n    <string name=\"family_management_delete_family_group\">Elimina gruppo famiglia</string>\n    <string name=\"family_management_leave_family_password_title\">Conferma la password per abbandonare il gruppo famiglia</string>\n    <string name=\"family_management_delete_family_password_title\">Conferma la password per eliminare il gruppo famiglia</string>\n    <string name=\"family_management_remove_member_password_title\">Conferma la password per rimuovere %s</string>\n    <string name=\"family_management_invite_family_member\">Invita membri della famiglia</string>\n    <string name=\"family_management_invite_slots_left\">%1$d inviti rimanenti</string>\n    <string name=\"family_management_cancel_invite\">Annulla invito</string>\n    <string name=\"family_management_cancel_invite_success\">Invito annullato</string>\n    <string name=\"family_management_cancel_invite_error\">Problema durante l’annullamento. Riprova.</string>\n    <string name=\"family_management_remove_member\">Rimuovi membro</string>\n    <string name=\"family_management_member_removed_success\">%s è stato rimosso dal gruppo famiglia</string>\n    <string name=\"family_management_member_remove_failed\">Problema durante la rimozione di %s. Riprova.</string>\n    <string name=\"family_management_leave_family_error_message\">Problema durante l’uscita dal gruppo famiglia. Riprova.</string>\n    <string name=\"family_management_exist_group_success\">Hai lasciato il gruppo famiglia…</string>\n    <string name=\"family_management_delete_group_success\">Gruppo famiglia eliminato</string>\n    <string name=\"family_management_delete_group_failure\">Eliminazione gruppo famiglia fallita</string>\n    <string name=\"family_management_delete_group_cancel\">Annulla</string>\n    <string name=\"family_management_delete_group_confirm\">OK</string>\n    <string name=\"family_management_input_pwd\">Inserisci la tua password</string>\n    <string name=\"family_management_invite_sent_date_format\">Invito inviato il %s</string>\n    <string name=\"family_management_invite_send\">Invito inviato</string>\n    <string name=\"family_management_pwd_error\">Password errata, reinseriscila</string>\n    <string name=\"pref_app_install_settings_title\">Impostazioni Installatore App</string>\n    <string name=\"pref_app_install_switch_title\">Consenti installazione app</string>\n    <string name=\"pref_app_install_other_apps_note\">L’autorizzazione consente l’installazione di app provenienti da altre fonti.</string>\n    <string name=\"pref_app_install_permission_instruction\">Per garantire il corretto funzionamento delle app installate, autorizza microG Companion a installare app scaricate da altre fonti.</string>\n    <string name=\"prefcat_app_install_list_title\">Apps che usano Installatore app</string>\n    <string name=\"service_name_google_location_sharing\">Condivisione della posizione Google</string>\n    <string name=\"location_sharing_description\">Gestisci la condivisione della posizione in tempo reale tra le app e i servizi Google di questo dispositivo</string>\n    <string name=\"location_sharing_learn_more\">Scopri di più sulla Condivisione della posizione</string>\n    <string name=\"location_sharing_switch_text\">Usa Condivisione della posizione</string>\n    <string name=\"location_sharing_turn_off_notify_hint\">Se disattivi la Condivisione posizione su questo dispositivo, le persone con cui la condividi non riceveranno alcuna notifica.</string>\n    <string name=\"location_sharing_off_previous_hint\">Fino a quando non la riattivi, rimarrà visibile solo l’ultima posizione condivisa.</string>\n    <string name=\"location_sharing_disabled\">Nessuna condivisione attiva per questo account</string>\n    <string name=\"location_sharing_turn_on_hint\">Quando inizi a condividere la posizione da un’app o servizio Google, puoi gestire la Condivisione della posizione da qui.\\n\\nPer iniziare, vai su Google Maps o Family Link.</string>\n    <string name=\"location_sharing_turn_off_title\">Disattiva Condivisione della posizione</string>\n    <string name=\"location_sharing_turn_off_hint\">Potresti ancora condividere la posizione da altri dispositivi connessi allo stesso account Google o da app non Google: controlla le impostazioni di condivisione ovunque sia attiva.\\n\\nLe persone con cui la condividi continueranno a vedere l’ultima posizione inviata.</string>\n    <string name=\"location_sharing_turn_off_cancel\">Mantieni attiva</string>\n    <string name=\"location_sharing_turn_off_confirm\">Disattiva</string>\n    <string name=\"location_sharing_confirm_dialog_title\">Attiva Condivisione della posizione</string>\n    <string name=\"location_sharing_confirm_dialog_text\">Le persone con cui condividi la posizione possono sempre vedere:\\n·Nome e foto \\n·La posizione recente del dispositivo, anche se non stai usando un servizio Google\\n·La batteria del dispositivo e se è in carica\\n·orario di arrivo e partenza, se impostano una notifica di Condivisione posizione</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-iw/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"permission_service_all_label\">כל שירותי Google</string>\n    <string name=\"permission_service_android_label\">שירותי Android</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-iw/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n</resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-iw/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"limited_services_app_name\">שירותי microG מוגבלים</string>\n    <string name=\"gms_settings_name\">הגדרות microG</string>\n    <string name=\"gms_settings_summary\">להתקין את שירותי microG</string>\n    <string name=\"just_a_sec\">רק רגע.…</string>\n    <string name=\"google_account_label\">גוגל</string>\n    <string name=\"ask_permission_tos\">בהמשך השימוש, אתה מאשר לאפליקציה זו ול-Google לעשות שימוש במידע שלך בהתאם לתנאי השימוש ולמדיניות הפרטיות של כל אחת מהן.</string>\n    <string name=\"gms_app_name\">שירותי microG</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-ja/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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  --><resources>\n    <string name=\"permission_service_all_label\">すべての Google サービス</string>\n    <string name=\"permission_service_all_description\">リンクされた Google アカウントを介して、アプリにすべての Google サービスへのアクセスを許可します。</string>\n    <string name=\"permission_service_android_label\">Android サービス</string>\n    <string name=\"permission_service_android_description\">アプリにリンクされたGoogleアカウントを介したAndroidサービスの使用を許可します。</string>\n    <string name=\"permission_service_adsense_label\">AdSense</string>\n    <string name=\"permission_service_adsense_description\">アプリにリンクされたGoogleアカウントを介したAdSenseの使用を許可します。</string>\n    <string name=\"permission_service_adwords_label\">AdWords</string>\n    <string name=\"permission_service_adwords_description\">アプリにリンクされたGoogleアカウントを介したAdWordsの使用を許可します。</string>\n    <string name=\"permission_service_ah_label\">Google App Engine</string>\n    <string name=\"permission_service_ah_description\">アプリにリンクされたGoogleアカウントを介したGoogle App Engineの使用を許可します。</string>\n    <string name=\"permission_service_blogger_label\">Blogger</string>\n    <string name=\"permission_service_blogger_description\">アプリにリンクされたGoogleアカウントを介したBloggerの使用を許可します。</string>\n    <string name=\"permission_service_cl_label\">Googleカレンダー</string>\n    <string name=\"permission_service_cl_description\">アプリにリンクされたGoogleアカウントを介したGoogleカレンダーの使用を許可します。</string>\n    <string name=\"permission_service_cp_label\">連絡先</string>\n    <string name=\"permission_service_cp_description\">アプリにリンクされたGoogleアカウントを介した連絡先の使用を許可します。</string>\n    <string name=\"permission_service_dodgeball_label\">Dodgeball</string>\n    <string name=\"permission_service_dodgeball_description\">アプリにリンクされたGoogleアカウントを介したDodgeballの使用を許可します。</string>\n    <string name=\"permission_service_finance_label\">Google Finance</string>\n    <string name=\"permission_service_finance_description\">アプリにリンクされたGoogleアカウントを介したGoogle Financeの使用を許可します。</string>\n    <string name=\"permission_service_gbase_label\">Google Base</string>\n    <string name=\"permission_service_gbase_description\">アプリにリンクされたGoogleアカウントを介したGoogle Baseの使用を許可します。</string>\n    <string name=\"permission_service_grandcentral_label\">Google Voice</string>\n    <string name=\"permission_service_grandcentral_description\">アプリにリンクされたGoogleアカウントを介したGoogle Voiceの使用を許可します。</string>\n    <string name=\"permission_service_groups2_label\">Google Groups</string>\n    <string name=\"permission_service_groups2_description\">アプリにリンクされたGoogleアカウントを介したGoogle Groupsの使用を許可します。</string>\n    <string name=\"permission_service_health_label\">Google Health</string>\n    <string name=\"permission_service_health_description\">アプリにリンクされたGoogleアカウントを介したGoogle Healthの使用を許可します。</string>\n    <string name=\"permission_service_ig_label\">iGoogle</string>\n    <string name=\"permission_service_ig_description\">アプリにリンクされたGoogleアカウントを介したiGoogleの使用を許可します。</string>\n    <string name=\"permission_service_jotspot_label\">JotSpot</string>\n    <string name=\"permission_service_jotspot_description\">アプリにリンクされたGoogleアカウントを介したJotSpotの使用を許可します。</string>\n    <string name=\"permission_service_knol_label\">Knol</string>\n    <string name=\"permission_service_knol_description\">アプリにリンクされたGoogleアカウントを介したKnolの使用を許可します。</string>\n    <string name=\"permission_service_lh2_label\">Picasa Web Albums</string>\n    <string name=\"permission_service_lh2_description\">アプリにリンクされたGoogleアカウントを介したPicasa Web Albumsの使用を許可します。</string>\n    <string name=\"permission_service_local_label\">Googleマップ</string>\n    <string name=\"permission_service_local_description\">アプリにリンクされたGoogleアカウントを介したGoogleマップの使用を許可します。</string>\n    <string name=\"permission_service_mail_label\">Googleメール</string>\n    <string name=\"permission_service_mail_description\">アプリにリンクされたGoogleアカウントを介したGoogleメールの使用を許可します。</string>\n    <string name=\"permission_service_news_label\">Googleニュース</string>\n    <string name=\"permission_service_news_description\">アプリにリンクされたGoogleアカウントを介したGoogleニュースの使用を許可します。</string>\n    <string name=\"permission_service_notebook_label\">Google Notebook</string>\n    <string name=\"permission_service_notebook_description\">アプリにリンクされたGoogleアカウントを介したGoogle Notebookの使用を許可します。</string>\n    <string name=\"permission_service_orkut_label\">Orkut</string>\n    <string name=\"permission_service_orkut_description\">アプリにリンクされたGoogleアカウントを介したOrkutの使用を許可します。</string>\n    <string name=\"permission_service_print_label\">Google Book Search</string>\n    <string name=\"permission_service_print_description\">アプリにリンクされたGoogleアカウントを介したGoogle Book Searchの使用を許可します。</string>\n    <string name=\"permission_service_sierra_label\">Google Checkoutアカウント</string>\n    <string name=\"permission_service_sierra_description\">アプリにリンクされたGoogleアカウントを介したGoogle Checkoutアカウントの使用を許可します。</string>\n    <string name=\"permission_service_sierraqa_label\">Google Checkout QAアカウント</string>\n    <string name=\"permission_service_sierraqa_description\">アプリにリンクされたGoogleアカウントを介したGoogle Checkout QAアカウントの使用を許可します。</string>\n    <string name=\"permission_service_sierrasandbox_label\">Google Checkout Sandboxアカウント</string>\n    <string name=\"permission_service_sierrasandbox_description\">アプリにリンクされたGoogleアカウントを介したGoogle Checkout Sandboxアカウントの使用を許可します。</string>\n    <string name=\"permission_service_sitemaps_label\">Google Webmaster Tools</string>\n    <string name=\"permission_service_sitemaps_description\">アプリにリンクされたGoogleアカウントを介したGoogle Webmaster Toolsの使用を許可します。</string>\n    <string name=\"permission_service_speech_label\">音声検索</string>\n    <string name=\"permission_service_speech_description\">アプリにリンクされたGoogleアカウントを介した音声検索の使用を許可します。</string>\n    <string name=\"permission_service_speechpersonalization_label\">カスタマイズされた音声認識</string>\n    <string name=\"permission_service_speechpersonalization_description\">アプリにリンクされたGoogleアカウントを介したカスタマイズされた音声認識の使用を許可します。</string>\n    <string name=\"permission_service_talk_label\">Google Talk</string>\n    <string name=\"permission_service_talk_description\">アプリにリンクされたGoogleアカウントを介したGoogle Talkの使用を許可します。</string>\n    <string name=\"permission_service_wifi_label\">Google Wi-Fi</string>\n    <string name=\"permission_service_wifi_description\">アプリにリンクされたGoogleアカウントを介したGoogle Wi-Fiの使用を許可します。</string>\n    <string name=\"permission_service_wise_label\">Google Spreadsheets</string>\n    <string name=\"permission_service_wise_description\">アプリにリンクされたGoogleアカウントを介したGoogle Spreadsheetsの使用を許可します。</string>\n    <string name=\"permission_service_writely_label\">Google Docs</string>\n    <string name=\"permission_service_writely_description\">アプリにリンクされたGoogleアカウントを介したGoogle Docsの使用を許可します。</string>\n    <string name=\"permission_service_youtube_label\">YouTube</string>\n    <string name=\"permission_service_youtube_description\">アプリにリンクされたGoogleアカウントを介したYouTubeの使用を許可します。</string>\n    <string name=\"permission_service_YouTubeUser_label\">YouTubeユーザー</string>\n    <string name=\"permission_service_YouTubeUser_description\">アプリにリンクされたGoogleアカウントを介したYouTubeユーザーの使用を許可します。</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense\">AdSense データの表示と管理</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_activity\">Google アプリのアクティビティ履歴を表示する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics.readonly\">Google Analytics のデータを表示</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics\">Google Analytics データの表示と管理</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.licensing\">License Manager API への読み取り/書き込みアクセス。</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.buyer\">Ad Exchange 購入者アカウントの設定を管理する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller\">Ad Exchange データの表示と管理</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsensehost\">AdSense ホストデータと関連アカウントの表示と管理</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.settings\">Google アプリグループの設定を表示および管理する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller.readonly\">Ad Exchange のデータを表示</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appengine.admin\">アプリエンジンの管理スコープ。</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_androidpublisher\">Google Play Androd Developer へのアクセス</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.migration\">Groups Migration API への読み取り/書き込みアクセス。</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense.readonly\">AdSense のデータを表示</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps_reporting_audit.readonly\">管理監査APIへの読み取り専用のアクセス</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order\">再販業者管理者およびユーザーが、APIのサンドボックス環境でテストを行う際の読み取り/書き込みアクセス権、またはAPI操作を直接呼び出す際の読み取り/書き込みアクセス権。</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order.readonly\">全体的な読み取り/書き込み OAuth スコープに加えて、顧客のデータを取得するときに、読み取り専用の OAuth スコープを使用します。</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appstate\">アプリ状態サービスを使用する範囲。</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery.readonly\">Google BigQuery でデータを表示する</string>\n    <string name=\"perm_activity_recognition_description\">アプリが Google からあなたの活動レベル（例：歩行中、運転中、自転車乗車中、または静止中）の定期的な更新情報を受け取れるようにします。</string>\n    <string name=\"perm_activity_recognition_label\">活動認識</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery\">Google BigQuery でデータを表示および管理する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger\">Blogger アカウントを管理する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger.readonly\">Blogger アカウントを表示する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_books\">books を管理する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar\">カレンダー を管理する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar.readonly\">カレンダー を表示する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_cloudprint\">Google cloud print データの表示と管理</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute.readonly\">Google Compute Engine resources を表示する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute\">Google Compute Engine resources の表示と管理</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate.readonly\">Google Coordinate jobs の表示</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate\">Google Coordinate jobs の表示と管理</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.full_control\">Google Cloud Storage でデータを表示および管理する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_only\">Google Cloud Storage でデータを表示する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_write\">Google Cloud Storage でデータを管理する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_dfareporting\">DoubleClick for Advertisers reports の表示と管理</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.appdata\">アプリケーションデータフォルダへのアクセスを許可する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.apps.readonly\">Google ドライブ アプリで表示</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.file\">このアプリで開いた、または作成した Google ドライブ のファイルを表示および管理する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.install\">ユーザーがアプリのインストールを承認するために使用される特別なスコープ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.metadata.readonly\">Google ドライブ内のファイルとドキュメントのメタデータを表示する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.readonly\">Google ドライブ内のファイルとドキュメントを表示する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.scripts\">Google Apps Script スクリプトの動作を変更する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive\">Google ドライブ内のファイルやドキュメントを表示および管理する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase.readonly\">Freebase アカウントを表示する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase\">Freebase にあなたのアカウントでサインインしてください</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables\">Fusion Tables を管理する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables.readonly\">Fusion Tables を表示する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_games\">Google Play Games からのデータへのアクセス権限。</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan\">GAN データを管理する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan.readonly\">GAN データを表示する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gcm_for_chrome\">CloudMessaging for Chrome</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_glass.timeline\">Glass timeline scope</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.compose\">下書きの作成、閲覧、更新、削除。メッセージと下書きの送信。</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.modify\">スレッドとメッセージの即時かつ恒久的な削除を除くすべての読み取り/書き込み操作は、ごみ箱をバイパスします。</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.readonly\">すべてのリソースとそのメタデータを読み取る（書き込み操作なし）。</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.best\">最適な現在地と位置履歴を管理する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.city\">都市レベルの現在地と位置履歴を管理する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.best\">最適な場所を管理する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.city\">都市レベルの場所を管理する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine\">Google Maps Engine のデータを表示および管理する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine.readonly\">Google Maps Engine のデータを表示する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mobilemaps.firstparty\">モバイル向け Google マップの体験を表示および管理する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut\">Orkut のアクティビティを管理する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut.readonly\">Orkut のデータを表示する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.login\">Google+で自分の名前、基本情報、およびつながっている人のリストを確認する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.me\">Google 上で自分が誰であるかを把握する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_prediction\">Google Prediction API でデータを管理する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_shoppingapi\">製品データを表示する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification\">管理下にあるサイトおよびドメインの一覧を管理する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification.verify_only\">Google で新しいサイトの認証を管理する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_structuredcontent\">Shopping Content API への読み取り/書き込みアクセス権限。</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue.consumer\">タスクキューからタスクを消費する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue\">タスクを管理する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks\">タスクを管理する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks.readonly\">タスクを表示する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tracks\">Google Maps Tracks API、このスコープはプロジェクトのデータへの読み取りおよび書き込みアクセスを許可します。</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_urlshortener\">goo.gl 短縮URLを管理する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.email\">メールアドレスを表示する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.profile\">アカウントの基本情報を表示する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube\">YouTubeアカウントを管理する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtubepartner\">YouTube上の資産と関連コンテンツを表示・管理する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.readonly\">YouTubeアカウントを表示する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.upload\">YouTube動画を管理する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics_monetary.readonly\">YouTubeコンテンツのYouTubeアナリティクス金銭レポートを表示する</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics.readonly\">YouTubeコンテンツのYouTubeアナリティクスレポートを表示する</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-ja/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2017 microG Project Team\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<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <plurals name=\"pref_unifiednlp_summary\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> バックエンドが設定されました</item>\n        <item quantity=\"other\"><xliff:g example=\"3\">%1$d</xliff:g> バックエンドが設定されました</item>\n    </plurals>\n    <plurals name=\"gcm_registered_apps_counter\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> アプリが登録されました</item>\n        <item quantity=\"other\"><xliff:g example=\"123\">%1$d</xliff:g> アプリが登録されました</item>\n    </plurals>\n    <plurals name=\"cond_perm_summary\">\n        <item quantity=\"one\">microG Servicesの適切な機能に必要な権限が付与されていません。</item>\n        <item quantity=\"other\">microG Servicesの適切な機能に必要な権限が付与されていません。</item>\n    </plurals>\n    <plurals name=\"cond_perm_action\">\n        <item quantity=\"one\">不足している権限をリクエスト</item>\n        <item quantity=\"other\">不足している権限をリクエスト</item>\n    </plurals>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-ja/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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  --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"gms_app_name\">microG Services</string>\n    <string name=\"gms_settings_name\">microG 設定</string>\n    <string name=\"gms_settings_summary\">microG services をセットアップ。</string>\n    <string name=\"just_a_sec\">しばらくお待ちください…</string>\n    <string name=\"google_account_label\">Google</string>\n    <string name=\"ask_permission_tos\">続行すると、このアプリと Google がそれぞれの利用規約とプライバシーポリシーに従ってあなたの情報を使用することを許可したことになります。</string>\n    <string name=\"account_manager_title\">Google アカウント管理</string>\n    <string name=\"sorry\">申し訳ありません…</string>\n    <string name=\"auth_before_connect\">端末上のアプリが Google アカウントにログインしようとしています。\\n\\n<b>ログイン</b> ボタンを使用すると Google のログインページに接続します。ログインしたくない場合は、 <b>キャンセル</b> でダイアログ表示元のアプリに戻ります。</string>\n    <string name=\"auth_sign_in\">ログイン</string>\n    <string name=\"auth_connecting\">Google のサーバーに接続しています。\n\\n\n\\nしばらくお待ちください。</string>\n    <string name=\"no_network_error_desc\">ネットワークに接続されていません。\n\\n\n\\nこれは一時的な問題であるか、Android 端末がネットワークに接続されていない可能性があります。 モバイルネットワークや Wi-Fi ネットワークに接続し、もう一度やり直してください。</string>\n    <string name=\"auth_general_error_desc\">Google のサーバーとの通信に失敗しました。\n\\n\n\\n後ほど再度やり直してください。</string>\n    <string name=\"auth_finalize\">アカウントに情報を保存するため、Google と通信しています。\n\\n\n\\nこれには数分かかる場合があります。</string>\n    <string name=\"allow\">許可</string>\n    <string name=\"deny\">拒否</string>\n    <string name=\"auth_notification_title\">認証が必要です</string>\n    <string name=\"auth_notification_content\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> が Google アカウントにアクセスするには認証が必要です。</string>\n    <string name=\"perm_status_broadcast_label\">内部ステータスブロードキャストを受信</string>\n    <string name=\"perm_c2dm_receive_label\">C2DM メッセージを受信</string>\n    <string name=\"perm_c2dm_send_label\">C2DM メッセージを他のアプリに送信</string>\n    <string name=\"perm_gtalk_svc_label\">メッセージを交換し、Google のサーバーから同期通知を受信</string>\n    <string name=\"perm_extended_access_label\">Google サービスへの拡張アクセス</string>\n    <string name=\"service_name_checkin\">Google デバイス登録</string>\n    <string name=\"service_name_mcs\">Cloud Messaging</string>\n    <string name=\"games_title\">Google Play ゲーム</string>\n    <string name=\"games_info_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> が Play ゲームの使用を要求しています</string>\n    <string name=\"games_info_content\">Play ゲームを使用するには、Google Play ゲームアプリが必要です。 Google Play ゲームアプリなしでも続行できますが、予期せぬ動作をする可能性があります。</string>\n    <string name=\"pick_place_title\">場所を選択</string>\n    <string name=\"pick_place_desc\">場所の選択はまだ利用できません。</string>\n    <string name=\"place_picker_select_title\">この位置を選択</string>\n    <string name=\"place_picker_nearby_places\">近くの場所</string>\n    <string name=\"place_picker_location_lat_lng\">(%1$.7f, %2$.7f)</string>\n    <string name=\"lacking_permission_toast\">microG Services: <xliff:g example=\"have full network acccess\">%1$s</xliff:g>の許可がありません</string>\n    <string name=\"network_type_mobile\">モバイルネットワーク</string>\n    <string name=\"network_type_wifi\">Wi-Fi</string>\n    <string name=\"network_type_roaming\">ローミング</string>\n    <string name=\"network_type_other\">その他のネットワーク</string>\n    <!-- Self check -->\n    <string name=\"self_check_cat_fake_sig\">署名スプーフィングサポート</string>\n    <string name=\"self_check_cat_gms_packages\">インストールされたパッケージ</string>\n    <string name=\"self_check_cat_system\">システム</string>\n    <string name=\"self_check_name_fake_sig_perm\">システムは署名スプーフィングに対応しています: </string>\n    <string name=\"self_check_resolution_fake_sig_perm\">実行しているROMはネイティブの署名スプーフィングに対応していません。 あなたはXposedやその他のシステムを使用して、署名スプーフィングを使用することが出来ます。 どのROMが署名スプーフィングをサポートしているか、またサポートしていないROMでmicroGを使用する方法に関するドキュメントを確認してください。</string>\n    <string name=\"self_check_name_perm_granted\">システムは署名スプーフィング権限の許可しています: </string>\n    <string name=\"self_check_resolution_perm_granted\">これは、ROMが署名スプーフィングをサポートしていることを示す強力な指標ですが、有効化するには追加の操作が必要です。 必要になる可能性のある手順についてのドキュメントを確認してください。</string>\n    <string name=\"self_check_name_system_spoofs\">システムの署名スプーフィング: </string>\n    <string name=\"self_check_resolution_system_spoofs\">必要になる可能性のある手順についてのドキュメントを確認してください。</string>\n    <string name=\"self_check_pkg_gms\">microG Services(GmsCore)</string>\n    <string name=\"self_check_pkg_vending\">microG Companion(Phonesky)</string>\n    <string name=\"self_check_pkg_gsf\">microG サービスフレームワーク(GSF)</string>\n    <string name=\"self_check_name_app_installed\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> がインストールされています。</string>\n    <string name=\"self_check_resolution_app_installed\"><xliff:g example=\"F-Droid\">%1$s</xliff:g>、または互換性のあるものをインストールしてください。 互換性のあるアプリケーションについてのドキュメントを参照してください。</string>\n    <string name=\"self_check_name_correct_sig\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> が持つ正しい署名: </string>\n    <string name=\"self_check_resolution_correct_sig\">インストールされている <xliff:g example=\"F-Droid\">%1$s</xliff:g> に互換性がないか、署名スプーフィングが有効ではありません。 互換性のあるアプリケーションとROMに関するドキュメントを確認してください。</string>\n    <string name=\"self_check_name_battery_optimizations\">バッテリーの最適化を無効にしてください:</string>\n    <string name=\"self_check_resolution_battery_optimizations\">バッテリーの最適化を無効にするには、ここをタップしてください。 これを行わない場合、アプリが誤動作する可能性があります。</string>\n    <!-- Settings strings -->\n    <string name=\"prefcat_about\">情報</string>\n    <string name=\"prefcat_components\">コンポーネント</string>\n    <string name=\"prefcat_configuration\">設定</string>\n    <string name=\"prefcat_google_services\">Googleサービス</string>\n    <string name=\"prefcat_location_service\">位置情報サービス</string>\n    <string name=\"prefcat_services\">サービス</string>\n    <string name=\"prefcat_test\">テスト</string>\n    <string name=\"cond_gcm_bat_title\">バッテリーの最適化が有効です</string>\n    <string name=\"cond_gcm_bat_summary\">Cloud Messagingが有効になっていますが、microG Serviceのバッテリーの最適化が有効に設定されています。 プッシュ通知が正しく動作するためには、バッテリーの最適化を無効にする必要があります。</string>\n    <string name=\"cond_gcm_bat_action\">最適化無効</string>\n    <string name=\"cond_perm_title\">権限がありません</string>\n    <string name=\"prefs_account\">アカウント設定</string>\n    <string name=\"prefs_account_privacy\">個人情報 &amp; プライバシー</string>\n    <string name=\"prefs_account_security\">サインイン &amp; セキュリティ</string>\n    <string name=\"pref_auth_trust_google_title\">アプリの権限についてGoogleを信頼する</string>\n    <string name=\"pref_auth_trust_google_summary\">無効にすると、アプリの承認リクエストがGoogleに送信される前にユーザーに確認が求められます。 これが無効になっている場合、一部のアプリケーションはGoogleアカウントの使用に失敗します。</string>\n    <string name=\"pref_checkin_enable_summary\">お使いの携帯電話をGoogleサービスに登録し、一意のデバイス識別コードを作成します。 microGは、識別コードに加えて、登録済みのGoogleアカウント名も使用します。</string>\n    <string name=\"pref_device_registration_android_id\">Android ID</string>\n    <string name=\"checkin_not_registered\">未登録</string>\n    <string name=\"checkin_last_registration\">最終登録: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"checkin_enable_switch\">デバイスの登録</string>\n    <string name=\"pref_add_account_title\">アカウント</string>\n    <string name=\"pref_add_account_summary\">Googleアカウントを追加</string>\n    <string name=\"pref_gcm_enable_mcs_summary\">Cloud Messaging は、サードパーティアプリケーションで広く採用されているプッシュメッセージプロバイダーです。 使用する前に、デバイスの登録を有効にする必要があります。</string>\n    <string name=\"pref_gcm_heartbeat_title\">Cloud Messagingの同期周期</string>\n    <string name=\"pref_gcm_heartbeat_summary\">システムがGoogleサーバーと同期する秒単位の間隔。 この数値を増やすとバッテリーの消費量は減りますが、メッセージの遅延が発生する可能性があります。\\n非推奨: 将来のリリースで置き換えられる予定。</string>\n    <string name=\"pref_gcm_apps_title\">Cloud Messagingを使用するアプリ</string>\n    <string name=\"pref_gcm_apps_summary\">このリストは Cloud Messagingを使用するために登録されたアプリの一覧です。</string>\n    <string name=\"pref_gcm_confirm_new_apps_title\">新しいアプリの確認</string>\n    <string name=\"pref_gcm_confirm_new_apps_summary\">プッシュ通知を受信する新しいアプリが登録される前に確認する</string>\n    <string name=\"pref_gcm_ping_interval\">Ping間隔: <xliff:g example=\"10 minutes\">%1$s</xliff:g></string>\n    <string name=\"pref_about_title\">microG Servicesについて</string>\n    <string name=\"pref_about_summary\">バージョン情報と使用したライブラリ</string>\n    <string name=\"gcm_app_error_unregistering\">登録解除中にエラーが発生しました</string>\n    <string name=\"gcm_app_not_installed_anymore\">アプリが削除されています</string>\n    <string name=\"gcm_unregister_app\">登録解除</string>\n    <string name=\"gcm_not_registered\">未登録</string>\n    <string name=\"gcm_no_message_yet\">まだメッセージを受信していません</string>\n    <string name=\"gcm_last_message_at\">メッセージの最終受信:<xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_registered\">登録されています</string>\n    <string name=\"gcm_registered_since\">最終登録:<xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_unregister_confirm_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g>の登録を解除しますか?</string>\n    <string name=\"gcm_unregister_confirm_message\">一部のアプリは、自動的に再登録しないか、手動で再登録する機能を提供していません。 登録を解除すると、これらのアプリが正しく機能しない場合があります。\\n続行しますか?</string>\n    <string name=\"gcm_unregister_after_deny_message\">すでに登録されている、プッシュ通知に登録するアプリを拒否しました。\\n今後プッシュメッセージを受信しないように、登録を解除しますか?</string>\n    <string name=\"gcm_messages_counter\">メッセージ: <xliff:g example=\"123\">%1$d</xliff:g>個 (<xliff:g example=\"12345\">%2$d</xliff:g>バイト)</string>\n    <string name=\"gcm_enable_switch\">プッシュ通知を受信</string>\n    <string name=\"pref_push_app_allow_register_title\">登録を許可</string>\n    <string name=\"pref_push_app_allow_register_summary\">アプリのプッシュ通知への登録を許可</string>\n    <string name=\"pref_push_app_wake_for_delivery_title\">メッセージのプッシュ時にアプリを開始</string>\n    <string name=\"pref_push_app_wake_for_delivery_summary\">バックグラウンドでアプリを起動して、プッシュメッセージを受信します。</string>\n    <string name=\"prefcat_push_apps_title\">プッシュ通知を使用するアプリ</string>\n    <string name=\"prefcat_push_apps_registered_title\">登録されたアプリ</string>\n    <string name=\"prefcat_push_apps_unregistered_title\">未登録のアプリ</string>\n    <string name=\"prefcat_push_networks_title\">プッシュ通知に使用するためのネットワーク</string>\n    <string name=\"safetynet_intro\">Google SafetyNetはデバイス認証システムであり、デバイスが適切に保護され、Android CTSと互換性があることを保証します。 一部のアプリケーションは、セキュリティ上の理由または改ざん防止の前提条件としてSafetyNetを使用します。\\n\\nmicroG GmsCoreにはSafetyNetのオープンソースな実装が含まれていますが、公式サーバーでは、プロプライエタリなDroidGuardシステムを使用してSafetyNetリクエストに署名する必要があります。</string>\n    <string name=\"safetynet_enable_switch\">デバイスの認証を許可</string>\n    <string name=\"pref_safetynet_test_title\">SafetyNet テストの実行</string>\n    <string name=\"pref_droidguard_operation_mode\">動作モード</string>\n    <string name=\"signin_picker_title\">アカウントを選択</string>\n    <string name=\"signin_picker_subtitle\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> を続行するには</string>\n    <string name=\"signin_picker_add_account_label\">他のアカウントを追加</string>\n    <string name=\"ask_scope_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> は次の内容を要求しています:</string>\n    <string name=\"ask_service_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> は次の内容の使用を要求しています:</string>\n    <string name=\"prefcat_accounts_settings_title\">設定</string>\n    <string name=\"prefcat_accounts_current_accounts_title\">アカウント</string>\n    <string name=\"service_name_vending\">Play ストアサービス</string>\n    <string name=\"pref_auth_visible_title\">アプリがアカウントを検索できるようにする</string>\n    <string name=\"pref_auth_include_android_id_title\">デバイス登録による認証</string>\n    <string name=\"signin_confirm_button_text\">共有と許可</string>\n    <string name=\"signin_subtext_policy\">このアプリを使用する前に、%1$s と %2$s を確認してください。</string>\n    <string name=\"perm_provision_description\">ユーザーが操作しなくても、アプリがmicroGサービスを設定できるようにします</string>\n    <string name=\"pref_auth_visible_summary\">有効にすると、このデバイス上のすべてのアプリケーションは、事前の承認なしにGoogleアカウントのメールアドレスを見ることができます。</string>\n    <string name=\"signin_confirm_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> へのログインを許可</string>\n    <string name=\"signin_subtext_sharing\">続行するために、microG はあなたの Google アカウントの名前、メールアドレス、プロフィール画像を <xliff:g example=\"F-Droid\">%1$s</xliff:g> と共有します。</string>\n    <string name=\"signin_subtext_policy_privacy\">プライバシーポリシー</string>\n    <string name=\"signin_subtext_policy_terms\">利用規約</string>\n    <string name=\"perm_gsf_read_gservices_label\">Google サービスの設定を読み取る</string>\n    <string name=\"perm_provision_label\">microG サービスの提供</string>\n    <string name=\"perm_car_speed_label\">自動車の速度</string>\n    <string name=\"perm_car_speed_description\">あなたの車の速度にアクセスします</string>\n    <string name=\"perm_car_fuel_label\">車の燃料レベル</string>\n    <string name=\"perm_car_fuel_description\">あなたの車の燃料レベル情報にアクセスします</string>\n    <string name=\"perm_car_mileage_label\">車の走行距離</string>\n    <string name=\"perm_car_mileage_description\">車の走行距離情報にアクセスします</string>\n    <string name=\"perm_car_vendor_extension_label\">車のベンダーチャンネル</string>\n    <string name=\"perm_car_vendor_extension_description\">車種固有の情報を交換するために車のベンダー情報にアクセスします</string>\n    <string name=\"service_name_snet\">Google SafetyNet</string>\n    <string name=\"perm_car_info_label\">車の情報</string>\n    <string name=\"perm_car_info_description\">あなたの車の情報にアクセスします</string>\n    <string name=\"auth_package_override_request_title\"><b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> に <xliff:g example=\"account@example.com\">%2$s</xliff:g> への特権アクセスを許可しますか?</string>\n    <string name=\"auth_package_override_request_message\"><b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> は <b><xliff:g example=\"F-Droid Inc.\">%3$s</xliff:g> の <xliff:g example=\"F-Droid\">%2$s</xliff:g></b> であるかのようにあなたのアカウントにアクセスしようとしています。 これにより、アカウントへの特権アクセスが付与される可能性があります。</string>\n    <string name=\"auth_action_notification_channel_name\">Google アカウントへの通知</string>\n    <string name=\"auth_action_notification_channel_description\">Google アカウントのいずれかが使用前に追加設定が必要な場合、またはアカウントが microG と互換性がない場合に通知します。</string>\n    <string name=\"auth_action_notification_title\">アカウント操作が必要です</string>\n    <string name=\"auth_action_notification_content\">Google アカウントに追加の設定が必要です。</string>\n    <string name=\"auth_action_reauth_notification_title\">アカウント操作が必要です</string>\n    <string name=\"auth_action_activity_header\">Google アカウントの設定を完了してください</string>\n    <string name=\"auth_action_activity_explanation\">Google アカウント %s をこのデバイスで使用できるようにするには、次の手順を完了してください。</string>\n    <string name=\"auth_action_step_enable_checkin\">デバイス登録を有効にする</string>\n    <string name=\"auth_action_step_enable_checkin_description\">デバイスを少なくとも1回は Google に登録する必要があります。\\n\\nアカウント設定が完了した後に、 Google デバイス登録を無効にできます。</string>\n    <string name=\"auth_action_step_enable_gcm\">Cloud Messaging を有効にする</string>\n    <string name=\"auth_action_step_enable_gcm_description\">アカウント設定が完了した後に、 Cloud Messaging を無効にできます。</string>\n    <string name=\"auth_action_step_allow_microg_gcm\">microG の Cloud Messaging を許可する</string>\n    <string name=\"auth_action_step_allow_microg_gcm_description\">設定によっては、microG が Cloud Messaging に登録する前に許可が必要になります。</string>\n    <string name=\"auth_action_activity_finish\">完了</string>\n    <string name=\"auth_action_step_completed_content_description\">ステップ完了</string>\n    <string name=\"auth_action_step_perform_content_description\">クリックして手順を実行</string>\n    <string name=\"auth_action_step_enable_lockscreen\">安全な画面ロックを設定する</string>\n    <string name=\"auth_action_step_enable_lockscreen_description\">Google アカウントは職場または教育機関に管理されています。管理者により、デバイスがアカウントデータにアクセスするには安全な画面ロックが必要とされています。\\n\\nパスワード、PIN、またはパターンロック画面を設定してください。</string>\n    <string name=\"service_name_work_profile\">仕事用プロファイル</string>\n    <string name=\"pref_vending_license_enable_summary\">一部のアプリでは、 Google Play で購入したことを確認する必要があります。アプリから要求があった場合、 microG は Google から購入証明をダウンロードできます。無効化されている場合、または Google アカウントが追加されていない場合、ライセンス確認の要求は無視されます。</string>\n    <string name=\"pref_vending_licensing_enable_switch\">ライセンス確認リクエストに応答する</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_switch\">無料アプリを自動的にライブラリに追加する</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_summary\">無料アプリは、 Google Play からダウンロードされたかどうかを確認する場合があります。現在利用可能なすべての無料アプリについて常にチェックを通過できるよう、無料アプリを自動的にアカウントライブラリに追加します。</string>\n    <string name=\"pref_vending_split_install_switch\">オンデマンドでのコンポーネントインストール</string>\n    <string name=\"pref_vending_licensing_split_install_summary\">アプリが追加コンポーネントをダウンロードしてインストールすることを許可する</string>\n    <string name=\"pref_workprofile_create_account\">仕事用アカウントの設定を許可する</string>\n    <string name=\"pref_workprofile_intro\">職場や教育機関用の仕事用プロファイルを設定する際、設定が Google に接続を試み、そのプロファイルへのアプリダウンロードを有効化しようとする場合があります。</string>\n    <string name=\"pref_workprofile_disclaimer\">microG の使用が企業ポリシーに沿っていることを確認するのは、あなたの責任です。 microG はベストエフォートベースで提供されており、期待どおりに動作することを保証できません。</string>\n    <string name=\"pref_auto_create_player\">Play Games アカウントの登録を許可する</string>\n    <string name=\"pref_auto_create_player_intro\">ゲームをプレイする際には、Play Gamesアカウントを使用してログインし、実績、リーダーボード、アーカイブなどのゲーム関連機能を記録する必要があります。無効化後は、Play Gamesアカウントに紐付けられていないGoogleアカウントは自動登録されず、ゲームへのログインやプレイができなくなります。</string>\n    <string name=\"pref_allow_upload_game_played\">ゲームのプレイデータのアップロードを許可する</string>\n    <string name=\"pref_allow_upload_game_played_summary\">無効にすると、ゲームにログインした後のプレイ状況が報告されなくなり、一部のゲームではログインできなくなる場合があります。</string>\n    <string name=\"pref_change_default_game_player\">ゲーム用アカウントを変更する</string>\n    <string name=\"pref_change_default_game_player_summary\">ゲーム用のデフォルトアカウントを変更し、ゲームごとにアカウントを変更する。</string>\n    <string name=\"pref_delete_game_account_data\">Play Games データを削除する</string>\n    <string name=\"pref_delete_game_account_data_summary\">Play Games のアカウントとすべてのデータを削除し、個々のゲームデータを削除する。</string>\n    <string name=\"credentials_assisted_cancel\">キャンセル</string>\n    <string name=\"credentials_assisted_continue\">続行</string>\n    <string name=\"credentials_assisted_confirmation_header\">サインイン中</string>\n    <string name=\"credentials_assisted_continue_as_user_button_label\">%1$s として続行する</string>\n    <string name=\"credentials_assisted_sign_back_title\">Google で %1$s に再度ログインしてください</string>\n    <string name=\"credentials_assisted_signin_consent_header\">%1$s としてサインイン</string>\n    <string name=\"credentials_assisted_signin_consent\">続行すると、 Google はあなたの名前、メールアドレス、プロフィール写真を %1$s と共有します。 %1$s のプライバシーポリシーと利用規約をご覧ください。</string>\n    <string name=\"credentials_assisted_signin_description\">Google アカウントで「Google でサインイン」の設定を管理できます。</string>\n    <string name=\"credentials_assisted_choose_account_label\">アカウントを選択</string>\n    <string name=\"credentials_assisted_choose_account_subtitle\">%1$s を続行する</string>\n    <string name=\"credentials_assisted_choose_account_error_tips\">アカウント異常</string>\n    <string name=\"credentials_assisted_signin_button_text_long\">Google でサインイン</string>\n    <string name=\"credentials_assisted_signin_add_account\">アカウントを追加</string>\n    <string name=\"limited_services_dialog_information_ack\">わかりました</string>\n    <string name=\"games_achievement_list_title\">実績</string>\n    <string name=\"games_achievements_empty_text\">このゲームには実績がありません</string>\n    <string name=\"games_achievement_locked_content_description\">ロック中</string>\n    <string name=\"games_achievement_unlocked_content_description\">ロック解除</string>\n    <string name=\"games_achievement_extra_text\">%1$s 経験値</string>\n    <string name=\"games_leaderboard_empty_text\">このゲームにはリーダーボードがありません</string>\n    <string name=\"games_leaderboard_score_empty_text\">信じられない！このゲームには公開されたハイスコアが一つもありません。</string>\n    <string name=\"games_leaderboard_list_title\">ランキング</string>\n    <string name=\"games_leaderboards_score_label\">スコア: %1$s</string>\n    <string name=\"games_snapshot_empty_text\">ゲームのセーブデータはまだ保存されていません</string>\n    <string name=\"games_snapshot_choose_btn_text\">選択</string>\n    <string name=\"games_snapshot_delete_btn_text\">削除</string>\n    <string name=\"games_delete_snapshot_dialog_title\">セーブデータを削除</string>\n    <string name=\"games_delete_snapshot_dialog_message\">本当にこのセーブデータを削除しますか?</string>\n    <string name=\"games_delete_snapshot_dialog_cancel\">キャンセル</string>\n    <string name=\"games_delete_snapshot_dialog_ok\">OK</string>\n    <string name=\"games_delete_snapshot_error\">削除に失敗しました、後ほど再度お試しください</string>\n    <string name=\"games_state_description_signed_out\">サインアウトしました</string>\n    <string name=\"games_state_description_delete\">削除</string>\n    <string name=\"games_change_button_text\">変更</string>\n    <string name=\"games_change_default_account_section_title\">ゲーム用のデフォルトアカウントを変更する</string>\n    <string name=\"games_change_default_account_description\">デフォルトアカウント: %1$s</string>\n    <string name=\"games_change_default_account_explanation\">このアカウントは、ゲームへの自動サインイン、ゲームの進行状況の保存、設定の保存に使用されます。デフォルトアカウントの変更やサインアウトを行うと、プレイしたゲームの進行状況や設定がリセットされる可能性があります。</string>\n    <string name=\"games_change_per_game_title\">ゲームごとにアカウントを変更する</string>\n    <string name=\"games_change_per_game_description\">選択したゲームのアカウントを変更したり、サインアウトしたりすると、そのゲームの進行状況や設定がリセットされる可能性があります。</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_title\">新しいデフォルトアカウントのオプションを選択してください</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_description\">現在のデフォルトアカウント: %1$s</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_title\">新規ゲームのみデフォルトアカウントを変更する</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_description\">プレイしたゲームの進行状況や設定にアクセスできなくなることはありません。ただし、進行状況はアカウント間で分断されます。</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_title\">すべてのゲームのデフォルトアカウントを変更する</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_description\">プレイしたゲームの進行状況や設定にアクセスできなくなる可能性があります。変更を適用するため、ゲームを再起動します。</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_title\">すべてのゲームからサインアウトする</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_description\">プレイしたゲームの進行状況や設定にアクセスできなくなる可能性があります。変更を適用するため、ゲームを再起動します。</string>\n    <string name=\"games_change_per_game_dialog_description\">アカウントを変更したりサインアウトしたりすると、ゲームの進行状況や設定がリセットされる可能性があります</string>\n    <string name=\"games_change_per_game_dialog_option_use_player\">%1$s を使用する</string>\n    <string name=\"games_change_per_game_dialog_option_use_player_snackbar_success_message\">このゲームには %1$s でサインインされます</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out\">サインアウト</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out_snackbar_success_message\">このゲームからサインアウトされました</string>\n    <string name=\"games_change_sign_out_of_all_games_snackbar_success_message\">すべてのゲームからサインアウトされました</string>\n    <string name=\"limited_services_app_name\">限定された microG Services</string>\n    <string name=\"pref_auth_include_android_id_summary\">無効にすると、認証要求はデバイス登録と関連付けられなくなり、これにより不正なデバイスがサインインできる可能性がありますが、予期せぬ結果を招く恐れがあります。</string>\n    <string name=\"pref_auth_strip_device_name_title\">認証用のストリップデバイス名</string>\n    <string name=\"pref_auth_strip_device_name_summary\">有効にすると、認証リクエストにデバイスの名前が含まれなくなります。これにより、許可されていないデバイスがサインインできる可能性がありますが、予期せぬ結果を招く恐れがあります。</string>\n    <string name=\"pref_auth_two_step_verification_title\">二段階認証のプロンプトを受け取る</string>\n    <string name=\"pref_auth_two_step_verification_summary\">有効にすると、デバイスはGoogleからの二段階認証プロンプトを受信できます（Cloud Messaging が必要です）。</string>\n    <string name=\"pref_info_status\">ステータス</string>\n    <string name=\"pref_more_settings\">さらに</string>\n    <string name=\"pref_accounts_title\">Google アカウント</string>\n    <string name=\"pref_game_accounts_title\">Google Game アカウント</string>\n    <string name=\"pref_accounts_summary\">Google アカウントの追加と管理</string>\n    <string name=\"gcm_network_state_disconnected\">切断されました</string>\n    <string name=\"gcm_network_state_connected\"><xliff:g example=\"2 hours ago\">%1$s</xliff:g> から接続済み</string>\n    <string name=\"gcm_allow_app_popup\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> をプッシュ通知に登録することを許可しますか?</string>\n    <string name=\"pref_recaptcha_test_title\">ReCAPTCHA テストの実行</string>\n    <string name=\"pref_recaptcha_enterprise_test_title\">ReCAPTCHA Enterprise テストの実行</string>\n    <string name=\"pref_test_summary_passed\">すべてのテストに合格</string>\n    <string name=\"pref_test_summary_failed\">失敗: %s</string>\n    <string name=\"pref_test_summary_warn\">警告: %s</string>\n    <string name=\"pref_test_summary_running\">実行中…</string>\n    <string name=\"pref_droidguard_unsupported_summary\">この端末では DroidGuard の実行はサポートされていません。SafetyNet サービスが正常に動作しない可能性があります。</string>\n    <string name=\"prefcat_safetynet_apps_title\">SafetyNet を使用しているアプリ</string>\n    <string name=\"menu_clear_recent_requests\">直近のリクエストをクリアする</string>\n    <string name=\"safetynet_last_run_at\">最終使用日時: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"profile_name_native\">ネイティブ</string>\n    <string name=\"profile_name_real\">実機</string>\n    <string name=\"profile_name_user\">カスタム: %s</string>\n    <string name=\"profile_name_auto\">自動: %s</string>\n    <string name=\"profile_name_system\">システム: %s</string>\n    <string name=\"pref_device_registration_import_custom_profile_title\">カスタムプロファイルをインポート</string>\n    <string name=\"pref_device_registration_serial_title\">シリアル</string>\n    <string name=\"pref_device_registration_import_custom_profile_summary\">デバイスプロファイルをファイルからインポート</string>\n    <string name=\"pref_device_registration_select_profile_title\">プロファイルを選択</string>\n    <string name=\"pref_device_registration_device_profile_category\">デバイスプロファイル</string>\n    <string name=\"pref_safetynet_recent_uses\">最近の使用状況</string>\n    <string name=\"pref_safetynet_recent_attestation_summary\">認証: %s</string>\n    <string name=\"pref_safetynet_recent_recaptcha_summary\">ReCaptcha: %s</string>\n    <string name=\"pref_safetynet_recent_recaptcha_enterprise_summary\">ReCaptcha Enterprise: %s</string>\n    <string name=\"pref_safetynet_recent_copy_json\">JSON JWS データをコピー</string>\n    <string name=\"pref_safetynet_recent_advice\">アドバイス</string>\n    <string name=\"pref_safetynet_recent_eval_type\">評価タイプ</string>\n    <string name=\"pref_safetynet_recent_response_status\">応答ステータス</string>\n    <string name=\"pref_safetynet_recent_cat_response\">応答データ</string>\n    <string name=\"pref_safetynet_recent_cat_request\">リクエストデータ</string>\n    <string name=\"pref_safetynet_recent_nonce\">Nonce（16進数）</string>\n    <string name=\"pref_safetynet_recent_request_time\">リクエスト時刻</string>\n    <string name=\"pref_safetynet_recent_request_type\">リクエストタイプ</string>\n    <string name=\"pref_safetynet_recent_cat_basic\">ベーシックデータ</string>\n    <string name=\"pref_safetynet_recent_token\">トークン</string>\n    <string name=\"pref_safetynet_recent_copied\">クリップボードにコピーされました!</string>\n    <string name=\"pref_safetynet_test_integrity_cts_passed\">Integrity と CTS が合格した</string>\n    <string name=\"pref_safetynet_test_cts_failed\">CTS が不合格</string>\n    <string name=\"pref_safetynet_test_integrity_failed\">Integrity が不合格</string>\n    <string name=\"pref_safetynet_test_not_completed\">まだ完了していません</string>\n    <string name=\"pref_safetynet_test_no_result\">結果なし</string>\n    <string name=\"pref_safetynet_test_invalid_json\">無効なJSON</string>\n    <string name=\"push_notifications_summary_off\">オフ</string>\n    <string name=\"push_notifications_summary_automatic\">オン / 自動: %s</string>\n    <string name=\"push_notifications_summary_manual\">オン / 手動: %s</string>\n    <string name=\"push_notifications_summary_values_seconds\">%s 秒</string>\n    <string name=\"push_notifications_summary_values_minutes\">%s 分</string>\n    <string name=\"pref_vending_summary_licensing_off\">ライセンス オフ</string>\n    <string name=\"pref_vending_summary_licensing_on\">ライセンス オン</string>\n    <string name=\"pref_vending_licensing_category\">Google Play ライセンス</string>\n    <string name=\"pref_vending_feature_delivery\">Google Play 機能配信</string>\n    <string name=\"feedback_disabled\">現在、フィードバックはできません</string>\n    <string name=\"backup_disabled\">現在、バックアップはできません</string>\n    <string name=\"pref_vending_billing_category\">Google Play 課金</string>\n    <string name=\"pref_vending_billing_enable_switch\">請求リクエストを処理する</string>\n    <string name=\"pref_vending_billing_enable_summary\">有効化されると、一部のアプリは Google Play 課金サービスを通じて購入を完了したり、サブスクリプションを開始したりできます。</string>\n    <string name=\"pref_vending_billing_note_experimental\">この機能は実験的であり、金銭的損失を招く可能性があります。ご承知おきください。</string>\n    <string name=\"pref_vending_billing_note_licensing\">一部のアプリでは、購入を認証するためにライセンス認証も有効にする必要がある場合があります。</string>\n    <string name=\"pref_vending_asset_delivery_category\">Google Play アセット配信</string>\n    <string name=\"pref_vending_asset_delivery_switch\">オンデマンドでのアセット配信を有効にする</string>\n    <string name=\"pref_vending_asset_delivery_summary\">Play アセット配信 を使用するアプリから要求があった場合に追加アセットをダウンロードする</string>\n    <string name=\"pref_vending_asset_device_sync_summary\">Play アセット配信 を使用するアプリケーションは、現在使用中のデバイスの情報に基づいて追加のアセットをダウンロードします。</string>\n    <string name=\"pref_vending_asset_device_sync_switch\">デバイス情報の同期を有効にする</string>\n    <string name=\"limited_services_dialog_information\">限定された microG Services をご利用中です。通常の microG Services と異なり、このサービスは Google Play 上のアプリではなく、microG ライブラリを使用するアプリでのみ動作します。つまり、ほとんどのアプリケーションはこれらのサービスを無視します。</string>\n    <string name=\"games_api_access_denied\">このデバイス上のいずれのアカウントも Games API にアクセスできません</string>\n    <string name=\"games_change_default_account_for_all_games_snackbar_success_message\">%1$s で全てのゲームにサインインされます</string>\n    <string name=\"games_change_default_account_for_new_games_snackbar_success_message\">%1$s で新しいゲームにサインインされます</string>\n    <string name=\"games_account_display_content\">現在のアカウント: %1$s</string>\n    <string name=\"games_delete_profile_header\">Play Games アカウントとすべてのデータを削除する</string>\n    <string name=\"games_delete_profile_explanation\">Google Play Games アカウント、経験値、およびすべてのプロフィールデータを完全に削除します。この操作により、プレイしたゲーム内のスコア、進行状況（セーブデータ）、設定も削除される可能性があります。</string>\n    <string name=\"games_delete_profile_button\">完全に削除</string>\n    <string name=\"games_delete_game_data_header\">個々のゲームデータを削除</string>\n    <string name=\"games_delete_game_data_explanation\">Google Play Gamesでプレイしたゲームの個別データを完全に削除できます。この操作により、選択したゲームのスコア、進行状況（セーブデータ）、設定が削除されます。</string>\n    <string name=\"games_delete_profile_dialog_title\">このアカウントを削除してもよろしいですか?</string>\n    <string name=\"games_delete_profile_explanation_with_gamer_name\">Google Play Gamesアカウントを完全に削除します。対象はゲーマー名 <b>%1$s</b> (<b>%2$s</b>)、経験値、およびすべてのプロフィールデータです。この操作により、プレイしたゲーム内のスコア、進行状況（セーブデータ）、設定も削除される可能性があります。</string>\n    <string name=\"games_delete_profile_dialog_message\">この操作は取り消せません。</string>\n    <string name=\"games_delete_profile_fail\">プロフィールを削除できませんでした。後ほど再度お試しください。</string>\n    <string name=\"games_delete_game_data_confirm_dialog_title\">%1$s のデータを削除します</string>\n    <string name=\"games_delete_game_data_confirm_dialog_message\">%1$s のデータを完全に削除すると、Google Play Games内のスコア、進行状況（セーブデータ）、ゲーム設定が削除されます。</string>\n    <string name=\"games_popup_signin_welcome\">やあ、%1$s さん</string>\n    <string name=\"family_management_title\">ファミリー</string>\n    <string name=\"family_management_retry\">再試行</string>\n    <string name=\"family_management_load_error\">コンテンツの読み込みに失敗しました</string>\n    <string name=\"family_management_toolbar_back\">戻る</string>\n    <string name=\"family_management_toolbar_more\">さらに</string>\n    <string name=\"family_management_exit_family_group\">ファミリーグループを離脱する</string>\n    <string name=\"family_management_delete_family_group\">ファミリーグループを削除する</string>\n    <string name=\"family_management_leave_family_password_title\">ファミリーグループを離脱するにはパスワードを確認してください</string>\n    <string name=\"family_management_delete_family_password_title\">ファミリーグループを削除するにはパスワードを確認してください</string>\n    <string name=\"family_management_remove_member_password_title\">%s を削除するためのパスワードの確認</string>\n    <string name=\"family_management_invite_family_member\">家族を招待する</string>\n    <string name=\"family_management_invite_slots_left\">%1$d 通の招待状が残っています</string>\n    <string name=\"family_management_cancel_invite\">招待をキャンセルする</string>\n    <string name=\"family_management_cancel_invite_success\">招待のキャンセルに成功しました</string>\n    <string name=\"family_management_cancel_invite_error\">招待のキャンセルに問題が発生しました。もう一度お試しください。</string>\n    <string name=\"family_management_remove_member\">メンバーを削除する</string>\n    <string name=\"family_management_member_removed_success\">%s はあなたのファミリーグループから削除されました</string>\n    <string name=\"family_management_member_remove_failed\">%s の削除に失敗しました。もう一度お試しください。</string>\n    <string name=\"family_management_leave_family_error_message\">ファミリーグループからの離脱に失敗しました。もう一度お試しください。</string>\n    <string name=\"family_management_exist_group_success\">あなたはファミリーグループを離れました…</string>\n    <string name=\"family_management_delete_group_success\">ファミリーグループは削除されました</string>\n    <string name=\"family_management_delete_group_failure\">ホームグループの削除に失敗しました</string>\n    <string name=\"family_management_delete_group_cancel\">キャンセル</string>\n    <string name=\"family_management_delete_group_confirm\">OK</string>\n    <string name=\"family_management_input_pwd\">パスワードを入力してください</string>\n    <string name=\"family_management_invite_sent_date_format\">%s に招待状を送信しました</string>\n    <string name=\"family_management_invite_send\">招待状を送信しました</string>\n    <string name=\"family_management_pwd_error\">パスワードが間違っています。もう一度入力してください</string>\n    <string name=\"barcode_scanner_brand\">%1$s の代わりに microG によってスキャンされました</string>\n    <string name=\"camera_permission_dialog_button\">OK</string>\n    <string name=\"camera_permission_dialog_message\">microG サービスは、%1$s のコードをスキャンするためにデバイスのカメラにアクセスする必要があります。\\n\\n有効にするには、設定で microG サービスにカメラの権限を許可してください。</string>\n    <string name=\"camera_permission_dialog_title\">カメラの許可が必要です</string>\n    <string name=\"pref_app_install_settings_title\">アプリインストーラー設定</string>\n    <string name=\"pref_app_install_switch_title\">アプリのインストールを許可する</string>\n    <string name=\"pref_app_install_other_apps_note\">認証により、他のソースから提供されるアプリのインストールが可能になります。</string>\n    <string name=\"pref_app_install_permission_instruction\">インストールしたアプリが正常に動作するように、他のソースからダウンロードしたアプリのインストールを microG Companion に許可してください。</string>\n    <string name=\"prefcat_app_install_list_title\">アプリインストーラーを使用するアプリ</string>\n    <string name=\"service_name_google_location_sharing\">Google 位置情報の共有</string>\n    <string name=\"location_sharing_description\">このデバイスから Google アプリやサービス間でリアルタイムの位置情報を共有する管理</string>\n    <string name=\"location_sharing_learn_more\">位置情報の共有について詳しく知る</string>\n    <string name=\"location_sharing_switch_text\">位置情報の共有を使用する</string>\n    <string name=\"location_sharing_turn_off_notify_hint\">このデバイスの位置情報の共有をオフにしても、共有相手には通知されません。</string>\n    <string name=\"location_sharing_off_previous_hint\">再度有効にするまで、最後に共有した位置情報のみが利用可能です。</string>\n    <string name=\"location_sharing_disabled\">このアカウントにはアクティブな位置情報の共有がありません</string>\n    <string name=\"location_sharing_turn_on_hint\">Google アプリやサービスから位置情報の共有を開始すると、ここから位置情報の共有を管理できます。\\n\\n位置情報の共有を開始するには、Google マップ または ファミリー リンク にアクセスしてください。</string>\n    <string name=\"location_sharing_turn_off_title\">位置情報の共有をオフにする</string>\n    <string name=\"location_sharing_turn_off_hint\">同じ Google アカウントでサインインしている他のデバイスや、Google 以外のアプリから位置情報を共有している可能性があります。該当するすべての場所で位置情報共有の設定を確認してください。\\n\\n共有相手には、最後に共有した位置情報が引き続き表示されます。</string>\n    <string name=\"location_sharing_turn_off_cancel\">続ける</string>\n    <string name=\"location_sharing_turn_off_confirm\">オフにする</string>\n    <string name=\"location_sharing_confirm_dialog_title\">位置情報の共有を有効にする</string>\n    <string name=\"location_sharing_confirm_dialog_text\">位置情報を共有している相手には常に以下の情報が表示されます：\\n・あなたの名前と写真\\n・Googleサービスを利用していない場合でも、端末の直近の位置情報\\n・端末のバッテリー残量と充電中かどうか\\n・位置情報共有通知を追加した場合の到着時刻と出発時刻</string>\n    <string name=\"games_change_per_game_dialog_title\">このゲームのオプションを選択してください</string>\n    <string name=\"service_name_device_attestation\">デバイス認証</string>\n    <string name=\"prefcat_device_attestation_apps_title\">デバイス認証を使用するアプリ</string>\n    <string name=\"pref_device_attestation_app_allow_requests_title\">リクエストを許可</string>\n    <string name=\"pref_device_attestation_app_allow_requests_summary\">アプリにデバイス認証のリクエストを許可する</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-ko/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"permission_service_all_label\">모든 Google 서비스</string>\n    <string name=\"permission_service_all_description\">앱이 모든 관련된 Google 계정을 통해 모든 Google 서비스에 접근할 수 있도록 합니다.</string>\n    <string name=\"permission_service_android_label\">Android 서비스</string>\n    <string name=\"permission_service_android_description\">앱이 모든 관련된 Google 계정을 통해 모든 Android 서비스에 접근할 수 있도록 합니다.</string>\n    <string name=\"permission_service_adsense_label\">AdSense</string>\n    <string name=\"permission_service_adsense_description\">앱이 모든 관련된 Google 계정을 통해 AdSense에 접근할 수 있도록 합니다.</string>\n    <string name=\"permission_service_adwords_label\">AdWords</string>\n    <string name=\"permission_service_adwords_description\">앱이 관련된 모든 Google 계정을 통해 AdWords에 접근할 수 있도록 허용합니다.</string>\n    <string name=\"permission_service_ah_label\">Google 앱 엔진</string>\n    <string name=\"permission_service_blogger_label\">Blogger</string>\n    <string name=\"permission_service_cl_label\">Google 캘린더</string>\n    <string name=\"permission_service_jotspot_label\">JotSpot</string>\n    <string name=\"permission_service_ig_label\">iGoogle</string>\n    <string name=\"permission_service_wifi_label\">Google Wi-Fi</string>\n    <string name=\"permission_service_ah_description\">앱이 모든 관련된 Google 계정을 통해 Google 앱 엔진에 접근할 수 있도록 합니다.</string>\n    <string name=\"permission_service_blogger_description\">앱이 모든 관련된 Google 계정을 통해 Blogger에 접근할 수 있도록 합니다.</string>\n    <string name=\"permission_service_cl_description\">앱이 모든 관련된 Google 계정을 통해 Google 캘린더에 접근할 수 있도록 합니다.</string>\n    <string name=\"permission_service_cp_label\">연락처</string>\n    <string name=\"permission_service_cp_description\">앱이 모든 관련된 Google 계정을 통해 연락처에 접근할 수 있도록 합니다.</string>\n    <string name=\"permission_service_dodgeball_label\">Dodgeball</string>\n    <string name=\"permission_service_dodgeball_description\">앱이 모든 관련된 Google 계정을 통해 Dodgeball에 접근할 수 있도록 합니다.</string>\n    <string name=\"permission_service_finance_label\">Google Finance</string>\n    <string name=\"permission_service_finance_description\">앱이 모든 관련된 Google 계정을 통해 AdSense에 접근할 수 있도록 합니다.</string>\n    <string name=\"permission_service_gbase_label\">Google Base</string>\n    <string name=\"permission_service_gbase_description\">앱이 관련된 모든 Google 계정을 통해 Google Base에 접근할 수 있도록 허용합니다.</string>\n    <string name=\"permission_service_grandcentral_label\">Google Voice</string>\n    <string name=\"permission_service_grandcentral_description\">앱이 모든 관련된 Google 계정을 통해 Google Voice에 접근할 수 있도록 합니다.</string>\n    <string name=\"permission_service_groups2_label\">Google Groups</string>\n    <string name=\"permission_service_groups2_description\">앱이 모든 관련된 Google 계정을 통해 Google Groups에 접근할 수 있도록 합니다.</string>\n    <string name=\"permission_service_health_label\">Google Health</string>\n    <string name=\"permission_service_health_description\">앱이 모든 관련된 Google 계정을 통해 Google Health에 접근할 수 있도록 합니다.</string>\n    <string name=\"permission_service_ig_description\">앱이 모든 관련된 Google 계정을 통해 iGoogle에 접근할 수 있도록 합니다.</string>\n    <string name=\"permission_service_jotspot_description\">앱이 모든 관련된 Google 계정을 통해 JotSpot에 접근할 수 있도록 합니다.</string>\n    <string name=\"permission_service_knol_label\">Knol</string>\n    <string name=\"permission_service_knol_description\">앱이 모든 관련된 Google 계정을 통해 Knol에 접근할 수 있도록 합니다.</string>\n    <string name=\"permission_service_lh2_label\">Picasa 웹 앨범</string>\n    <string name=\"permission_service_lh2_description\">앱이 관련된 모든 Google 계정을 통해 Picasa 웹 앨범에 접근할 수 있도록 허용합니다.</string>\n    <string name=\"permission_service_local_label\">Google 지도</string>\n    <string name=\"permission_service_local_description\">앱이 모든 관련된 Google 계정을 통해 Google 지도에 접근할 수 있도록 합니다.</string>\n    <string name=\"permission_service_mail_label\">Gmail</string>\n    <string name=\"permission_service_mail_description\">앱이 관련된 모든 Google 계정을 통해 Gmail에 접근할 수 있도록 허용합니다.</string>\n    <string name=\"permission_service_news_label\">Google 뉴스</string>\n    <string name=\"permission_service_news_description\">앱이 모든 관련된 Google 계정을 통해 Google 뉴스에 접근할 수 있도록 합니다.</string>\n    <string name=\"permission_service_notebook_label\">Google 노트북</string>\n    <string name=\"permission_service_notebook_description\">앱이 모든 관련된 Google 계정을 통해 Google 노트북에 접근할 수 있도록 합니다.</string>\n    <string name=\"permission_service_orkut_label\">Orkut</string>\n    <string name=\"permission_service_orkut_description\">앱이 모든 관련된 Google 계정을 통해 Orkut에 접근할 수 있도록 합니다.</string>\n    <string name=\"permission_service_print_label\">Google 북 서치</string>\n    <string name=\"permission_service_print_description\">앱이 모든 관련된 Google 계정을 통해 Google 북 서치에 접근할 수 있도록 합니다.</string>\n    <string name=\"permission_service_sierra_label\">Google 체크아웃 계정</string>\n    <string name=\"permission_service_sierra_description\">앱이 모든 관련된 Google 계정을 통해 Google 체크아웃 계정에 접근할 수 있도록 합니다.</string>\n    <string name=\"permission_service_sierraqa_label\">Google 체크아웃 QA 계정</string>\n    <string name=\"permission_service_sierraqa_description\">앱이 모든 관련된 Google 계정을 통해 Google 체크아웃 QA 계정에 접근할 수 있도록 합니다.</string>\n    <string name=\"permission_service_sierrasandbox_label\">Google 체크아웃 샌드박스 계정</string>\n    <string name=\"permission_service_sierrasandbox_description\">앱이 모든 관련된 Google 계정을 통해 Google 체크아웃 샌드박스 계정에 접근할 수 있도록 합니다.</string>\n    <string name=\"permission_service_sitemaps_label\">Google 웹마스터 툴스</string>\n    <string name=\"permission_service_sitemaps_description\">앱이 모든 관련된 Google 계정을 통해 Google 웹마스터 툴스에 접근할 수 있도록 합니다.</string>\n    <string name=\"permission_service_speech_label\">음성 검색</string>\n    <string name=\"permission_service_speech_description\">앱이 모든 관련된 Google 계정을 통해 음성 검색에 접근할 수 있도록 합니다.</string>\n    <string name=\"permission_service_speechpersonalization_label\">개인 맞춤형 음성 인식</string>\n    <string name=\"permission_service_speechpersonalization_description\">앱이 모든 관련된 Google 계정을 통해 개인 맞춤형 음성 인식에 접근할 수 있도록 합니다.</string>\n    <string name=\"permission_service_talk_label\">Google 토크</string>\n    <string name=\"permission_service_talk_description\">앱이 모든 관련된 Google 계정을 통해 Google 토크에 접근할 수 있도록 합니다.</string>\n    <string name=\"permission_service_wifi_description\">앱이 모든 관련된 Google 계정을 통해 Google Wi-Fi에 접근할 수 있도록 합니다.</string>\n    <string name=\"permission_service_wise_label\">Google 스프레드시트</string>\n    <string name=\"permission_service_wise_description\">앱이 모든 관련된 Google 계정을 통해 Google 스프레드시트에 접근할 수 있도록 합니다.</string>\n    <string name=\"permission_service_writely_label\">Google 독스</string>\n    <string name=\"permission_service_writely_description\">앱이 모든 관련된 Google 계정을 통해 Google 독스에 접근할 수 있도록 합니다.</string>\n    <string name=\"permission_service_youtube_label\">YouTube</string>\n    <string name=\"permission_service_youtube_description\">앱이 모든 관련된 Google 계정을 통해 YouTube에 접근할 수 있도록 합니다.</string>\n    <string name=\"permission_service_YouTubeUser_label\">YouTube 사용자 이름</string>\n    <string name=\"permission_service_YouTubeUser_description\">앱이 모든 관련된 Google 계정이 사용하는 YouTube 사용자 이름에 접근할 수 있도록 합니다.</string>\n    <string name=\"perm_activity_recognition_label\">활동 인식</string>\n    <string name=\"perm_activity_recognition_description\">앱이 걷기, 운전, 자전거 타기, 정지해 있을 때와 같이 Google로부터 활동 수준에 대한 정기적인 업데이트를 받을 수 있도록 허용합니다.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_activity\">Google 앱의 활동 기록 보기</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.buyer\">Ad Exchange 구매자 계정 설정 관리</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller.readonly\">Ad Exchange 데이터 보기</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller\">Ad Exchange 데이터 보기 및 관리</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsensehost\">AdSense 호스트 데이터 및 관련 계정 보기 및 관리</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense.readonly\">AdSense 데이터 보기</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense\">AdSense 데이터 보기 및 관리</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics.readonly\">Google 애널리틱스 데이터 보기</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics\">Google 애널리틱스 데이터 보기 및 관리</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_androidpublisher\">Google Play Android 개발자 액세스</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appengine.admin\">앱 엔진 관리 범위.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.migration\">Groups Migration API에 대한 읽기 및 쓰기 액세스 권한.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.settings\">Google 앱 그룹 설정 보기 및 관리</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.licensing\">License Manager API에 대한 읽기/쓰기 액세스.</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-ko/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <plurals name=\"pref_unifiednlp_summary\">\n        <item quantity=\"other\">백엔드 <xliff:g example=\"1\">%1$d</xliff:g>개 설정됨</item>\n    </plurals>\n    <plurals name=\"gcm_registered_apps_counter\">\n        <item quantity=\"other\"><xliff:g example=\"123\">%1$d</xliff:g>개의 등록된 앱</item>\n    </plurals>\n    <plurals name=\"cond_perm_summary\">\n        <item quantity=\"other\">microG 서비스가 올바르게 작동하는데 필요한 권한이 부여되지 않았습니다.</item>\n    </plurals>\n    <plurals name=\"cond_perm_action\">\n        <item quantity=\"other\">누락된 권한 요청하기</item>\n    </plurals>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-ko/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=\"gms_app_name\">microG 서비스</string>\n    <string name=\"limited_services_app_name\">microG 제한 서비스</string>\n    <string name=\"gms_settings_name\">microG 설정</string>\n    <string name=\"gms_settings_summary\">microG 서비스를 설정합니다.</string>\n    <string name=\"just_a_sec\">잠시만 기다려주세요…</string>\n    <string name=\"google_account_label\">Google</string>\n    <string name=\"ask_permission_tos\">계속함으로써, 이 앱과 Google은 각각의 서비스 약관 및 개인정보 보호 정책에 따라 귀하의 정보를 사용할 수 있도록 허용합니다.</string>\n    <string name=\"ask_scope_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g>이/가 다음을 하려고 합니다:</string>\n    <string name=\"ask_service_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g>이/가 다음을 사용하려 합니다:</string>\n    <string name=\"account_manager_title\">Google 계정 관리자</string>\n    <string name=\"sorry\">죄송합니다…</string>\n    <string name=\"auth_before_connect\">이 기기의 앱이 Google 계정에 로그인하려고 합니다.\\n\\n의도한 경우라면, <b>로그인</b> 버튼으로 Google 로그인 페이지에 연결하고, 그렇지 않은 경우 <b>취소</b>를 눌러 이 팝업을 표시한 애플리케이션으로 돌아갑니다.</string>\n    <string name=\"auth_sign_in\">로그인</string>\n    <string name=\"auth_connecting\">기기가 로그인할 수 있도록 Google 서버에 연결하고 있습니다.\\n\\n몇 초 정도 걸릴 수 있어요.</string>\n    <string name=\"no_network_error_desc\">네트워크에 연결되어 있지 않습니다.\\n\\n이것은 일시적인 문제일 수도 있고 이 Android 기기가 데이터 서비스용으로 제공되지 않았을 수도 있습니다. 모바일 네트워크에 연결되면 다시 시도하거나 Wi-Fi 네트워크에 연결하세요.</string>\n    <string name=\"auth_general_error_desc\">Google 서버와 통신하는 데 문제가 발생했습니다.\\n\\n나중에 다시 시도해 주세요.</string>\n    <string name=\"auth_finalize\">기기가 Google에 연락하여 귀하의 계정에 정보를 저장하고 있습니다.\\n\\n몇 분 정도 걸릴 수 있어요.</string>\n    <string name=\"allow\">허용</string>\n    <string name=\"deny\">거부</string>\n    <string name=\"auth_notification_title\">인증 필요</string>\n    <string name=\"auth_notification_content\"><xliff:g example=\"F-Droid\">%1$s</xliff:g>이/가 귀하의 Google 계정에 접근하는데 인증이 필요합니다.</string>\n    <string name=\"auth_package_override_request_title\"><b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b>이 <xliff:g example=\"account@example.com\">%2$s</xliff:g>에 대한 고급 권한을 가지도록 허용할까요?</string>\n    <string name=\"auth_package_override_request_message\">&lt;b&gt;&lt;xliff:g example=\\\"F-Droid\\\"&gt;%1$s&lt;/xliff:g&gt;&lt;/b&gt;이/가 &lt;xliff:g example=\\\"F-Droid Inc.\\\"&gt;%3$s&lt;/xliff:g&gt;&lt;/b&gt;의 &lt;b&gt;&lt;xliff:g example=\\\"F-Droid\\\"&gt;%2$s&lt;/xliff:g&gt;처럼 귀하의 계정에 접근하려고 합니다. 이는 귀하의 계정에 대한 고급 권한을 부여할 수 있습니다.</string>\n    <string name=\"auth_action_notification_channel_name\">Google 계정 알림</string>\n    <string name=\"auth_action_notification_channel_description\">Google 계정 중 하나가 사용 전에 추가적인 설정이 필요하거나 계정이 microG와 호환되지 않는 경우 알립니다.</string>\n    <string name=\"auth_action_notification_title\">계정 조치 필요</string>\n    <string name=\"auth_action_notification_content\">귀하의 Google 계정이 추가적인 설정이 필요합니다.</string>\n    <string name=\"auth_action_reauth_notification_title\">계정 조치 필요</string>\n    <string name=\"auth_action_activity_header\">Google 계정 설정을 완료합시다</string>\n    <string name=\"auth_action_activity_explanation\">이 기기에서 Google 계정 %s을 사용하려면 다음 단계를 완료하세요.</string>\n    <string name=\"auth_action_step_enable_checkin\">기기 등록 활성화</string>\n    <string name=\"auth_action_step_enable_checkin_description\">기기를 Google에 한 번 이상 등록해야 합니다.\\n\\n계정 설정이 완료된 후 Google 기기 등록을 비활성화할 수 있습니다.</string>\n    <string name=\"auth_action_step_enable_gcm\">클라우드 메시징 활성화</string>\n    <string name=\"auth_action_step_enable_gcm_description\">계정 설정이 완료된 후 클라우드 메시징을 비활성화할 수 있습니다.</string>\n    <string name=\"auth_action_step_allow_microg_gcm\">microG 클라우드 메시징 허용</string>\n    <string name=\"auth_action_step_allow_microg_gcm_description\">귀하의 설정에 따라, microG는 클라우드 메시징에 등록하기 전에 귀하의 허가가 필요합니다.</string>\n    <string name=\"auth_action_step_enable_lockscreen\">보안 화면 잠금 설정</string>\n    <string name=\"auth_action_step_enable_lockscreen_description\">귀하의 Google 계정은 직장 또는 교육 기관에서 관리합니다. 귀하의 관리자는 기기가 계정 데이터에 접근하기 전에 안전한 화면 잠금이 필요하다고 결정했습니다.\\n\\n비밀번호, PIN, 또는 패턴 잠금 화면을 설정해 주세요.</string>\n    <string name=\"auth_action_step_perform_content_description\">단계를 수행하려면 클릭하세요</string>\n    <string name=\"auth_action_step_completed_content_description\">단계 완료</string>\n    <string name=\"auth_action_activity_finish\">완료</string>\n    <string name=\"signin_picker_title\">계정을 선택하세요</string>\n    <string name=\"signin_picker_subtitle\"><xliff:g example=\"F-Droid\">%1$s</xliff:g>에 사용할 계정 선택</string>\n    <string name=\"signin_picker_add_account_label\">다른 계정 추가</string>\n    <string name=\"signin_confirm_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g>에 로그인하도록 허용</string>\n    <string name=\"signin_confirm_button_text\">허용 및 공유</string>\n    <string name=\"signin_subtext_sharing\">계속하기 위해, microG는 귀하의 Google 계정의 이름, 이메일 주소, 프로필 사진을 <xliff:g example=\"F-Droid\">%1$s</xliff:g>에게 제공합니다.</string>\n    <string name=\"signin_subtext_policy\">이 앱을 사용하기 전에, %1$s과 %2$s를 확인하세요.</string>\n    <string name=\"signin_subtext_policy_privacy\">개인정보 정책</string>\n    <string name=\"signin_subtext_policy_terms\">서비스 약관</string>\n    <string name=\"perm_status_broadcast_label\">내부 상태 신호 듣기</string>\n    <string name=\"perm_gsf_read_gservices_label\">Google 서비스 설정 읽기</string>\n    <string name=\"perm_c2dm_receive_label\">C2DM 메시지 듣기</string>\n    <string name=\"perm_c2dm_send_label\">다른 앱에게 C2DM 메시지 보내기</string>\n    <string name=\"perm_gtalk_svc_label\">Google 서버와 메시지를 교환하고 동기화 알림 받기</string>\n    <string name=\"perm_extended_access_label\">Google 서비스에 대한 확장된 접근</string>\n    <string name=\"perm_provision_label\">microG 서비스 제공</string>\n    <string name=\"perm_provision_description\">사용자의 조작 없이 앱이 microG 서비스를 설정하도록 허용</string>\n    <string name=\"perm_car_speed_label\">차량 속도</string>\n    <string name=\"perm_car_speed_description\">차량의 속도 읽기</string>\n    <string name=\"perm_car_info_label\">차량 정보</string>\n    <string name=\"perm_car_info_description\">차량의 정보 읽기</string>\n    <string name=\"perm_car_fuel_label\">차량 연료</string>\n    <string name=\"perm_car_fuel_description\">차량 연료 정보 읽기</string>\n    <string name=\"perm_car_mileage_label\">차량 주행 거리</string>\n    <string name=\"perm_car_mileage_description\">차량의 주행 거리 정보 읽기</string>\n    <string name=\"perm_car_vendor_extension_label\">차량 공급업체 채널</string>\n    <string name=\"perm_car_vendor_extension_description\">차량 공급업체 채널에 접근하여 차량 정보 교환하기</string>\n    <string name=\"service_name_checkin\">Google 기기 등록</string>\n    <string name=\"service_name_mcs\">클라우드 메시징</string>\n    <string name=\"service_name_snet\">Google SafetyNet</string>\n    <string name=\"service_name_vending\">Play 스토어 서비스</string>\n    <string name=\"service_name_work_profile\">작업 프로필</string>\n    <string name=\"games_title\">Google Play 게임즈</string>\n    <string name=\"games_info_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g>이/가 Play 게임즈를 사용하려고 합니다</string>\n    <string name=\"games_info_content\">Play 게임즈를 사용하려면 Google Play 게임즈 앱을 설치해야 합니다. Play 게임즈 없이도 애플리케이션이 작동할 수도 있지만 예기치 않게 작동할 수 있습니다.</string>\n    <string name=\"pick_place_title\">장소 선택</string>\n    <string name=\"pick_place_desc\">장소 선택은 아직 사용할 수 없습니다.</string>\n    <string name=\"place_picker_select_title\">이 장소 선택</string>\n    <string name=\"place_picker_nearby_places\">주변 장소</string>\n    <string name=\"place_picker_location_lat_lng\">(%1$.7f, %2$.7f)</string>\n    <string name=\"lacking_permission_toast\">microG Services: <xliff:g example=\"have full network acccess\">%1$s</xliff:g> 권한 없음</string>\n    <string name=\"network_type_mobile\">모바일 네트워크</string>\n    <string name=\"network_type_wifi\">Wi-Fi</string>\n    <string name=\"network_type_roaming\">로밍</string>\n    <string name=\"network_type_other\">기타 네트워크</string>\n    <string name=\"self_check_cat_fake_sig\">서명 눈속임 지원</string>\n    <string name=\"self_check_cat_gms_packages\">설치된 패키지</string>\n    <string name=\"self_check_cat_system\">시스템</string>\n    <string name=\"self_check_name_fake_sig_perm\">시스템의 서명 눈속임 지원 여부:</string>\n    <string name=\"self_check_resolution_fake_sig_perm\">사용 중인 ROM에 서명 눈속임 지원이 내장되어 있지 않습니다. Xposed 또는 기타 시스템으로 서명 눈속임을 할 수 있습니다. 어떤 ROM에서 서명 눈속임을 지원하고, 지원하지 않는 ROM에서 microG를 사용하는 방법은 문서를 참고해주세요.</string>\n    <string name=\"prefcat_about\">정보</string>\n    <string name=\"prefcat_components\">구성요소</string>\n    <string name=\"prefcat_configuration\">설정</string>\n    <string name=\"prefcat_services\">서비스</string>\n    <string name=\"prefcat_test\">테스트</string>\n    <string name=\"pref_info_status\">상태</string>\n    <string name=\"pref_more_settings\">더보기</string>\n    <string name=\"prefcat_accounts_settings_title\">설정</string>\n    <string name=\"prefcat_accounts_current_accounts_title\">계정</string>\n    <string name=\"pref_add_account_title\">계정</string>\n    <string name=\"gcm_unregister_app\">등록 취소</string>\n    <string name=\"gcm_registered\">등록됨</string>\n    <string name=\"gcm_network_state_disconnected\">연결 끊김</string>\n    <string name=\"pref_test_summary_running\">실행 중…</string>\n    <string name=\"profile_name_real\">실제</string>\n    <string name=\"profile_name_native\">네이티브</string>\n    <string name=\"pref_device_registration_serial_title\">일련번호</string>\n    <string name=\"pref_safetynet_recent_token\">토큰</string>\n    <string name=\"credentials_assisted_cancel\">취소</string>\n    <string name=\"credentials_assisted_continue\">계속</string>\n    <string name=\"games_achievement_list_title\">도전과제</string>\n    <string name=\"games_leaderboard_list_title\">순위</string>\n    <string name=\"games_snapshot_choose_btn_text\">선택</string>\n    <string name=\"games_snapshot_delete_btn_text\">삭제</string>\n    <string name=\"games_delete_snapshot_dialog_cancel\">취소</string>\n    <string name=\"games_state_description_delete\">삭제</string>\n    <string name=\"games_change_button_text\">변경</string>\n    <string name=\"self_check_pkg_gms\">microG 서비스</string>\n    <string name=\"prefcat_google_services\">Google 서비스</string>\n    <string name=\"prefcat_location_service\">위치 서비스</string>\n    <string name=\"cond_gcm_bat_action\">최적화 무시</string>\n    <string name=\"pref_device_registration_android_id\">Android ID</string>\n    <string name=\"checkin_not_registered\">등록되지 않음</string>\n    <string name=\"checkin_enable_switch\">기기 등록</string>\n    <string name=\"pref_accounts_title\">Google 계정</string>\n    <string name=\"gcm_app_error_unregistering\">등록 취소 오류</string>\n    <string name=\"gcm_not_registered\">등록되지 않음</string>\n    <string name=\"pref_push_app_allow_register_title\">등록 허용</string>\n    <string name=\"prefcat_push_apps_registered_title\">등록된 앱</string>\n    <string name=\"prefcat_push_apps_unregistered_title\">등록 취소된 앱</string>\n    <string name=\"pref_recaptcha_test_title\">ReCAPTCHA 테스트</string>\n    <string name=\"pref_test_summary_failed\">실패: %s</string>\n    <string name=\"pref_test_summary_warn\">경고: %s</string>\n    <string name=\"pref_droidguard_operation_mode\">작동 모드</string>\n    <string name=\"profile_name_user\">사용자 지정: %s</string>\n    <string name=\"profile_name_auto\">자동: %s</string>\n    <string name=\"profile_name_system\">시스템: %s</string>\n    <string name=\"pref_device_registration_select_profile_title\">프로필 선택</string>\n    <string name=\"pref_device_registration_device_profile_category\">기기 프로필</string>\n    <string name=\"pref_safetynet_recent_uses\">최근 사용</string>\n    <string name=\"pref_safetynet_recent_recaptcha_summary\">ReCaptcha: %s</string>\n    <string name=\"pref_safetynet_test_cts_failed\">CTS 실패</string>\n    <string name=\"pref_safetynet_test_integrity_failed\">무결성 실패</string>\n    <string name=\"push_notifications_summary_values_seconds\">%s초</string>\n    <string name=\"push_notifications_summary_values_minutes\">%s분</string>\n    <string name=\"credentials_assisted_choose_account_label\">계정 선택</string>\n    <string name=\"credentials_assisted_signin_add_account\">계정 추가</string>\n    <string name=\"limited_services_dialog_information_ack\">이해했습니다</string>\n    <string name=\"games_achievement_extra_text\">%1$s XP</string>\n    <string name=\"games_leaderboards_score_label\">점수: %1$s</string>\n    <string name=\"games_state_description_signed_out\">로그아웃됨</string>\n    <string name=\"games_change_per_game_dialog_option_use_player\">%1$s 사용</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out\">로그아웃</string>\n    <string name=\"games_delete_profile_button\">영구적으로 삭제</string>\n    <string name=\"self_check_pkg_gsf\">microG 서비스 프레임워크</string>\n    <string name=\"pref_add_account_summary\">Google 계정 추가</string>\n    <string name=\"pref_about_title\">microG 서비스 정보</string>\n    <string name=\"gcm_enable_switch\">푸시 알림 받기</string>\n    <string name=\"pref_recaptcha_enterprise_test_title\">ReCAPTCHA Enterprise 테스트</string>\n    <string name=\"pref_safetynet_recent_recaptcha_enterprise_summary\">ReCaptcha Enterprise: %s</string>\n    <string name=\"credentials_assisted_confirmation_header\">로그인 중</string>\n    <string name=\"credentials_assisted_continue_as_user_button_label\">%1$s로 계속하기</string>\n    <string name=\"credentials_assisted_signin_consent_header\">%1$s으로 로그인 중</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-lv/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources></resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-lv/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources></resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-lv/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"gms_app_name\">microG pakalpojumi</string>\n    <string name=\"gms_settings_name\">microG iestatījumi</string>\n    <string name=\"gms_settings_summary\">Iestatīt microG pakalpojumus.</string>\n    <string name=\"google_account_label\">Google</string>\n    <string name=\"account_manager_title\">Google konta pārvaldnieks</string>\n    <string name=\"allow\">Atļaut</string>\n    <string name=\"deny\">Liegt</string>\n    <string name=\"auth_notification_title\">Nepieciešams autorizēties</string>\n    <string name=\"auth_action_notification_channel_name\">Google konta brīdinājumi</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-lzh/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources></resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-lzh/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources></resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-lzh/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources></resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-ml/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"permission_service_all_label\">എല്ലാ ഗൂഗിൾ സേവനങ്ങളും</string>\n    <string name=\"permission_service_all_description\">ബന്ധപ്പെട്ട ഏതൊരു ഗൂഗിൾ അക്കൗണ്ടിലൂടെയും എല്ലാ ഗൂഗിൾ സേവനങ്ങളും ആക്‌സസ് ചെയ്യാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു.</string>\n    <string name=\"permission_service_android_label\">ആൻഡ്രോയിഡ് സേവനങ്ങൾ</string>\n    <string name=\"permission_service_android_description\">ബന്ധപ്പെട്ട ഏതൊരു ഗൂഗിൾ അക്കൗണ്ടിലൂടെയും ആൻഡ്രോയിഡ് സേവനങ്ങൾ ആക്‌സസ് ചെയ്യാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു.</string>\n    <string name=\"permission_service_adsense_label\">ആഡ്സെൻസ്</string>\n    <string name=\"permission_service_adsense_description\">ബന്ധപ്പെട്ട ഏതൊരു ഗൂഗിൾ അക്കൗണ്ടിലൂടെയും ആഡ്‌സെൻസ് ആക്‌സസ് ചെയ്യാൻ ആപ്പിനെ അനുവദിക്കുന്നു.</string>\n    <string name=\"permission_service_adwords_label\">ആഡ്‌വേഡ്‌സ്</string>\n    <string name=\"permission_service_adwords_description\">\"ബന്ധപ്പെട്ട ഏതൊരു ഗൂഗിൾ അക്കൗണ്ടിലൂടെയും ആഡ്‌വേർഡ്‌സ്  ആക്‌സസ് ചെയ്യാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു.\"</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-ml/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <plurals name=\"pref_unifiednlp_summary\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> ബാക്കെൻഡ് കോൺഫിഗർ ചെയ്‌തു</item>\n        <item quantity=\"other\"><xliff:g example=\"3\">%1$d</xliff:g> ബാക്കെൻഡുകൾ കോൺഫിഗർ ചെയ്‌തു</item>\n    </plurals>\n    <plurals name=\"gcm_registered_apps_counter\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> രജിസ്റ്റർ ചെയ്ത ആപ്പ്</item>\n        <item quantity=\"other\"><xliff:g example=\"123\">%1$d</xliff:g> രജിസ്റ്റർ ചെയ്ത ആപ്പുകൾ</item>\n    </plurals>\n    <plurals name=\"cond_perm_summary\">\n        <item quantity=\"one\">മൈക്രോജി സേവനങ്ങളുടെ ശരിയായ പ്രവർത്തനത്തിന് ആവശ്യമായ അനുമതി നൽകുന്നില്ല.</item>\n        <item quantity=\"other\">മൈക്രോജി സേവനങ്ങളുടെ ശരിയായ പ്രവർത്തനത്തിന് ആവശ്യമായ അനുമതികൾ നൽകുന്നില്ല.</item>\n    </plurals>\n    <plurals name=\"cond_perm_action\">\n        <item quantity=\"one\">വിട്ടുപോയ അനുമതി അഭ്യർത്ഥിക്കുക</item>\n        <item quantity=\"other\">വിട്ടുപോയ അനുമതികൾ അഭ്യർത്ഥിക്കുക</item>\n    </plurals>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-ml/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=\"gms_app_name\">മൈക്രോ ജി സേവനങ്ങൾ</string>\n    <string name=\"limited_services_app_name\">മൈക്രോജി ലിമിറ്റഡ് സർവീസസ്</string>\n    <string name=\"gms_settings_name\">മൈക്രോജി ക്രമീകരണങ്ങൾ</string>\n    <string name=\"gms_settings_summary\">മൈക്രോജി സേവനങ്ങൾ സജ്ജീകരിക്കുക.</string>\n    <string name=\"just_a_sec\">ഒരു നിമിഷം…</string>\n    <string name=\"google_account_label\">ഗൂഗിൾ</string>\n    <string name=\"ask_permission_tos\">തുടരുന്നതിലൂടെ, ഈ ആപ്പിനെയും ഗൂഗിൾ -നെയും നിങ്ങളുടെ വിവരങ്ങൾ അവയുടെ ബന്ധപ്പെട്ട സേവന നിബന്ധനകൾക്കും സ്വകാര്യതാ നയങ്ങൾക്കും അനുസൃതമായി ഉപയോഗിക്കാൻ നിങ്ങൾ അനുവദിക്കുന്നു.</string>\n    <string name=\"ask_scope_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> ഇത് ചെയ്യാൻ ആഗ്രഹിക്കുന്നു:</string>\n    <string name=\"ask_service_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> ഉപയോഗിക്കാൻ ആഗ്രഹിക്കുന്നു:</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-nb-rNO/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"permission_service_all_label\">Alle Google-tjenester</string>\n    <string name=\"permission_service_android_label\">Android-tjenester</string>\n    <string name=\"permission_service_adsense_label\">AdSense</string>\n    <string name=\"permission_service_all_description\">Lar appen få tilgang til alle Google-tjenester gjennom enhver tilhørende Google-konto.</string>\n    <string name=\"permission_service_android_description\">Lar appen få tilgang til Android-tjenester gjennom enhver tilhørende Google-konto.</string>\n    <string name=\"permission_service_adsense_description\">Lar appen få tilgang til AdSense gjennom enhver tilhørende Google-konto.</string>\n    <string name=\"permission_service_adwords_label\">AdWords</string>\n    <string name=\"permission_service_adwords_description\">Lar appen få tilgang til AdWords gjennom enhver tilhørende Google-konto.</string>\n    <string name=\"permission_service_ah_label\">Google App Engine</string>\n    <string name=\"permission_service_ah_description\">Lar appen få tilgang til Google App Engine gjennom enhver tilhørende Google-konto.</string>\n    <string name=\"permission_service_blogger_label\">Blogger</string>\n    <string name=\"permission_service_blogger_description\">Lar appen få tilgang til Blogger gjennom enhver tilhørende Google-konto.</string>\n    <string name=\"permission_service_cl_label\">Google Kalender</string>\n    <string name=\"permission_service_cl_description\">Lar appen få tilgang til Google Kalender gjennom enhver tilhørende Google-konto.</string>\n    <string name=\"permission_service_cp_label\">Kontakter</string>\n    <string name=\"permission_service_cp_description\">Lar appen få tilgang til kontakter gjennom enhver tilhørende Google-konto.</string>\n    <string name=\"permission_service_dodgeball_label\">Dodgeball</string>\n    <string name=\"permission_service_dodgeball_description\">Lar appen få tilgang til Dodgeball gjennom enhver tilhørende Google-konto.</string>\n    <string name=\"permission_service_finance_label\">Google Finans</string>\n    <string name=\"permission_service_finance_description\">Lar appen få tilgang til Google Finans gjennom enhver tilhørende Google-konto.</string>\n    <string name=\"permission_service_gbase_label\">Google Base</string>\n    <string name=\"permission_service_gbase_description\">Lar appen få tilgang til Google Base gjennom enhver tilhørende Google-konto.</string>\n    <string name=\"permission_service_grandcentral_label\">Google Voice</string>\n    <string name=\"permission_service_grandcentral_description\">Lar appen få tilgang til Google Voice gjennom enhver tilhørende Google-konto.</string>\n    <string name=\"permission_service_groups2_label\">Google Groups</string>\n    <string name=\"permission_service_groups2_description\">Lar appen få tilgang til Google Groups gjennom enhver tilhørende Google-konto.</string>\n    <string name=\"permission_service_health_label\">Google Health</string>\n    <string name=\"permission_service_health_description\">Lar appen få tilgang til Google Health gjennom enhver tilhørende Google-konto.</string>\n    <string name=\"permission_service_ig_label\">iGoogle</string>\n    <string name=\"permission_service_ig_description\">Lar appen få tilgang til iGoogle gjennom enhver tilhørende Google-konto.</string>\n    <string name=\"permission_service_jotspot_label\">JotSpot</string>\n    <string name=\"permission_service_jotspot_description\">Lar appen få tilgang til JotSpot gjennom enhver tilhørende Google-konto.</string>\n    <string name=\"permission_service_knol_label\">Knol</string>\n    <string name=\"permission_service_knol_description\">Lar appen få tilgang til Knol gjennom enhver tilhørende Google-konto.</string>\n    <string name=\"permission_service_lh2_label\">Picasa Web Albums</string>\n    <string name=\"permission_service_lh2_description\">Lar appen få tilgang til Picasa Web Albums gjennom enhver tilhørende Google-konto.</string>\n    <string name=\"permission_service_local_label\">Google Maps</string>\n    <string name=\"permission_service_local_description\">Lar appen få tilgang til Google Maps gjennom enhver tilhørende Google-konto.</string>\n    <string name=\"permission_service_mail_label\">Google Mail</string>\n    <string name=\"permission_service_mail_description\">Lar appen få tilgang til Google Mail gjennom enhver tilhørende Google-konto.</string>\n    <string name=\"permission_service_news_label\">Google News</string>\n    <string name=\"permission_service_news_description\">Lar appen få tilgang til Google News gjennom enhver tilhørende Google-konto.</string>\n    <string name=\"permission_service_notebook_label\">Google Notebook</string>\n    <string name=\"permission_service_notebook_description\">Lar appen få tilgang til Google Notebook gjennom enhver tilhørende Google-konto.</string>\n    <string name=\"permission_service_orkut_label\">Orkut</string>\n    <string name=\"permission_service_orkut_description\">Lar appen få tilgang til Orkut gjennom enhver tilhørende Google-konto.</string>\n    <string name=\"permission_service_print_label\">Google Book Search</string>\n    <string name=\"permission_service_print_description\">Lar appen få tilgang til Google Book Search gjennom enhver tilhørende Google-konto.</string>\n    <string name=\"permission_service_sierra_label\">Google Checkout-kontoer</string>\n    <string name=\"permission_service_sierra_description\">Lar appen få tilgang til Google Checkout-kontoer gjennom enhver tilhørende Google-konto.</string>\n    <string name=\"permission_service_sierraqa_label\">Google Checkout QA-kontoer</string>\n    <string name=\"permission_service_sierraqa_description\">Lar appen få tilgang til Google Checkout QA-kontoer gjennom enhver tilhørende Google-konto.</string>\n    <string name=\"permission_service_sierrasandbox_label\">Google Checkout Sandbox-kontoer</string>\n    <string name=\"permission_service_sierrasandbox_description\">Lar appen få tilgang til Google Checkout Sandbox-kontoer gjennom enhver tilhørende Google-konto.</string>\n    <string name=\"permission_service_sitemaps_label\">Google Webmaster Tools</string>\n    <string name=\"permission_service_sitemaps_description\">Lar appen få tilgang til Google Webmaster Tools gjennom enhver tilhørende Google-konto.</string>\n    <string name=\"permission_service_speech_label\">Stemmesøk</string>\n    <string name=\"permission_service_speech_description\">Lar appen få tilgang til stemmesøk gjennom enhver tilhørende Google-konto.</string>\n    <string name=\"permission_service_speechpersonalization_label\">Personalisert stemmegjenkjenning</string>\n    <string name=\"permission_service_speechpersonalization_description\">Lar appen få tilgang til personalisert stemmegjenkjenning gjennom enhver tilhørende Google-konto.</string>\n    <string name=\"permission_service_talk_label\">Google Talk</string>\n    <string name=\"permission_service_talk_description\">Lar appen få tilgang til Google Talk gjennom enhver tilhørende Google-konto.</string>\n    <string name=\"permission_service_wifi_label\">Google Wi-Fi</string>\n    <string name=\"permission_service_wifi_description\">Lar appen få tilgang til Google Wi-Fi gjennom enhver tilhørende Google-konto.</string>\n    <string name=\"permission_service_wise_label\">Google Spreadsheets</string>\n    <string name=\"permission_service_wise_description\">Lar appen få tilgang til Google Spreadsheets gjennom enhver tilhørende Google-konto.</string>\n    <string name=\"permission_service_writely_label\">Google Docs</string>\n    <string name=\"permission_service_writely_description\">Lar appen få tilgang til Google Docs gjennom enhver tilhørende Google-konto.</string>\n    <string name=\"permission_service_youtube_label\">YouTube</string>\n    <string name=\"permission_service_youtube_description\">Lar appen få tilgang til YouTube gjennom enhver tilhørende Google-konto.</string>\n    <string name=\"permission_service_YouTubeUser_label\">Youtube-brukernavn</string>\n    <string name=\"permission_service_YouTubeUser_description\">Lar appen få tilgang til YouTube-brukernavn i bruk med enhver tilhørende Google-konto.</string>\n    <string name=\"perm_activity_recognition_label\">Aktivitetsgjenkjenning</string>\n    <string name=\"perm_activity_recognition_description\">Lar en app motta periodiske oppdateringer av aktivitetsnivået ditt fra Google, for eksempel, om du går, kjører, sykler eller står stille.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_activity\">Se aktivitetshistorikken til Google-appene dine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.buyer\">Håndtere konfigurasjonen til Ad Exchange-kjøperkontoen din</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller.readonly\">Se Ad Exchange-dataene dine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller\">Se og håndtere Ad Exchange-dataene dine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsensehost\">Se og håndtere Adsense-vertdataene dine og assosierte kontoer</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense.readonly\">Se AdSense-dataene dine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense\">Se og håndtere AdSense-dataene dine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics.readonly\">Se Google Analytics-dataene dine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics\">Se og håndtere Google Analytics-dataene dine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_androidpublisher\">Tilgang til Google Play Android Developer</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appengine.admin\">Administratoromfang for appmotoren.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.migration\">Lese- og skrivetilgang til Groups Migration-API-et.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery.readonly\">Se dataene dine i Google BigQuery</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery\">Se og håndtere dataene dine i Google BigQuery</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger\">Håndtere Blogger-kontoen din</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger.readonly\">Se Blogger-kontoen din</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_books\">Håndtere bøkene dine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar\">Håndtere kalenderne dine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar.readonly\">Se kalenderne dine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase\">Logge inn på Freebase med kontoen din</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.settings\">Se og håndtere innstillingene til en Google Apps-gruppe</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.licensing\">Lese- og skrivetilgang til License Manager-API-et.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps_reporting_audit.readonly\">Skrivetilgang til Admin Audit-API-et</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appstate\">Omfang for bruk av App State-tjenesten.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_cloudprint\">Se og håndtere Google Cloud-printdataene dine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute.readonly\">Se Google Compute Engine-ressursene dine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute\">Se og håndtere Google Compute Engine-ressursene dine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate.readonly\">Se Google koordinat-jobbene dine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate\">Se og håndtere Google Maps-koordinat-jobbene dine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.full_control\">Håndtere dataene dine og rettighetene dine i Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_only\">Se dataene dine i Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_write\">Håndtere dataene dine i Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.appdata\">Gi tilgang til applikasjonsdatamappen</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.apps.readonly\">Se Google Drive-appene dine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.file\">Se og håndtere Google Drive-filer som du har åpnet eller laget med denne appen</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.metadata.readonly\">Se metadata til filer og dokumenter i Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.readonly\">Se filene og dokumentene dine i Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.scripts\">Modifisere Google Apps Script-skripts adferd</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive\">Se og håndtere filene og dokumentene dine i Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase.readonly\">Se Freebase-kontoen din</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gcm_for_chrome\">CloudMessaging for chrome</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.compose\">Lage, lese, oppdatere og slette kladdemeldinger. Sende meldinger og kladdemeldinger.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.modify\">Alle lese- og skriveopperasjoner unntatt umiddelbar og permanent sletting av tråder og meldinger, som omgår papirkurven.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.readonly\">Lese alle ressurser og deres metadata, men ingen skrivetillatelser.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut\">Håndtere Orkut-aktiviteten din</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut.readonly\">Se Orkut-dataene dine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.login\">Vite navnet ditt, grunnleggende informasjon, og en liste over folk du er koblet til med på Google+</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.me\">Vite hvem du er på Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_shoppingapi\">Se produktdataene dine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification\">Se listen over sider og domener du kontrollerer</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.email\">Se e-postadressen din</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.profile\">Se grunnleggende informasjon om kontoen din</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube\">Håndtere YouTube-kontoen din</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.readonly\">Se YouTube-kontoen din</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.upload\">Håndtere YouTube-videoene dine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order.readonly\">I tillegg til lese- og skriverettigheter innenfor OAuth-omfanget, bare bruk leserettigheter når kundens data innhentes.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_dfareporting\">Se og håndtere DoubleClick for Advertisers-rapporter</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.install\">Særskilt omfang som brukes for å la brukere godkjenne installasjon av en app</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables\">Håndtere dine Fusion Tables</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables.readonly\">Se dine Fusion Tables</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan\">Håndtere GAN-dataene dine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan.readonly\">Se GAN-dataene dine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_games\">Omfang for å få tilgang til data fra Google Play Games.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.best\">Håndtere din beste tilgjengelige lokasjon og lokasjonshistorikk</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.city\">Håndtere din lokasjon og lokasjonshistorikk på bynivå</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.best\">Håndtere din beste tilgjengelige lokasjon</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.city\">Håndtere lokasjonen din på bynivå</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine.readonly\">Se Google Maps Engine-dataene dine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mobilemaps.firstparty\">Se og håndtere Google Maps på mobil</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_prediction\">Håndtere dataene dine i Google Prediction API-et</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue\">Håndtere oppgavene dine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks\">Håndtere oppgavene dine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks.readonly\">Se oppgavene dine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tracks\">Google Maps Tracks API-et, dette omfanget gir lese- og skrivetilgang til dataene i prosjektet ditt.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_urlshortener\">Håndtere dine goo.gl korte URL-er</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtubepartner\">Se og håndtere ditt innhold på YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics_monetary.readonly\">Se økonomiske rapporter fra YouTube Analytics i forbindelse med YouTube-innholdet ditt</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics.readonly\">Se YouTube Analytics-rapporter i forbindelse med YouTube-innholdet ditt</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order\">For gjensalgsadministratorer og brukeres lese- og skrivetilgang når det testes i API-et sandkasse, eller lese- og skrivetilgang når en API-operasjon kalles direkte.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_glass.timeline\">Omfang for Glass-tidslinjen</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine\">Se og håndtere dine Google Maps Engine-data</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification.verify_only\">Håndtere dine nye nettsstedsverifiseringer gjennom Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_structuredcontent\">Lese- og skrivetilgang til Shopping Content API-et.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue.consumer\">Utføre oppgaver fra oppgavekøene dine</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-nb-rNO/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <plurals name=\"cond_perm_action\">\n        <item quantity=\"one\">Forespør manglende rettighet</item>\n        <item quantity=\"other\">Forespør manglende rettigheter</item>\n    </plurals>\n    <plurals name=\"pref_unifiednlp_summary\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> bakend konfigurert</item>\n        <item quantity=\"other\"><xliff:g example=\"3\">%1$d</xliff:g> backender configured</item>\n    </plurals>\n    <plurals name=\"gcm_registered_apps_counter\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> registrert app</item>\n        <item quantity=\"other\"><xliff:g example=\"123\">%1$d</xliff:g> registrerte apper</item>\n    </plurals>\n    <plurals name=\"cond_perm_summary\">\n        <item quantity=\"one\">En rettighet som er nødvendig for at microG-tjenestene skal fungere riktig er ikke gitt.</item>\n        <item quantity=\"other\">Rettigheter som er nødvendige for at microG-tjenestene skal fungere riktig er ikke gitt.</item>\n    </plurals>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-nb-rNO/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=\"gms_app_name\">microG-tjenester</string>\n    <string name=\"gms_settings_name\">microG-innstillinger</string>\n    <string name=\"gms_settings_summary\">Konfigurer microG-tjenester.</string>\n    <string name=\"just_a_sec\">Et lite øyeblikk…</string>\n    <string name=\"google_account_label\">Google</string>\n    <string name=\"ask_scope_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> vil:</string>\n    <string name=\"ask_service_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> vil bruke:</string>\n    <string name=\"sorry\">Beklager…</string>\n    <string name=\"limited_services_app_name\">Begrensede microG-tjenester</string>\n    <string name=\"auth_sign_in\">Logg inn</string>\n    <string name=\"ask_permission_tos\">Ved å fortsette lar du denne appen og Google bruker informasjonen din i samsvar med brukervilkårene og personvernserklæringene deres.</string>\n    <string name=\"account_manager_title\">Google-kontoadministrasjon</string>\n    <string name=\"auth_before_connect\">En app på enheten din prøver å logge seg inn på en Google-konto.\\n\\nHvis dette var gjort med vilje, bruk <b>Logg inn</b>-knappen for å koble til Googles innloggingsside. Hvis ikke, trykk <b>Avbryt</b> for å gå tilbake til appen som åpnet denne meldingen.</string>\n    <string name=\"auth_connecting\">Enheten din prøver å koble seg til Googles servere for å logge deg inn.\\n\\nDette kan ta noen sekunder.</string>\n    <string name=\"no_network_error_desc\">Du har ingen nettverkstilkobling.\\n\\nDette kan være et midlertidig problem eller at Android-enheten din ikke har datatjenester. Prøv igjen etter å ha skrudd på mobildata eller å ha koblet til et Wi-Fi-nettverk.</string>\n    <string name=\"auth_general_error_desc\">Det oppsto et problem under tilkoblingen til Googles servere.\\n\\nPrøv igjen senere.</string>\n    <string name=\"auth_finalize\">Enheten din tar kontakt med Google for å lagre informasjon på kontoen din.\\n\\nDette kan ta noen minutter.</string>\n    <string name=\"allow\">Tillat</string>\n    <string name=\"deny\">Avvis</string>\n    <string name=\"auth_notification_title\">Autentisering kreves</string>\n    <string name=\"auth_notification_content\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> trenger din autentisering for å få tilgang til Google-kontoen din.</string>\n    <string name=\"auth_package_override_request_title\">La <b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> få privilegert tilgang til <xliff:g example=\"account@example.com\">%2$s</xliff:g>\\?</string>\n    <string name=\"auth_package_override_request_message\"><b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> vil få tilgang til kontoen din om den er <b><xliff:g example=\"F-Droid\">%2$s</xliff:g> av <xliff:g example=\"F-Droid Inc.\">%3$s</xliff:g></b>. Dette kan la den få privilegert tilgang til kontoen din.</string>\n    <string name=\"auth_action_notification_channel_name\">Google-konto-varslinger</string>\n    <string name=\"auth_action_notification_content\">Google-kontoen din trenger mer oppsett.</string>\n    <string name=\"auth_action_activity_header\">Bli ferdig med å sette opp Google-kontoen din</string>\n    <string name=\"auth_action_step_enable_checkin\">Skru på enhetsregistrering</string>\n    <string name=\"auth_action_step_perform_content_description\">Trykk for å utføre seg</string>\n    <string name=\"auth_action_step_completed_content_description\">Steg fullført</string>\n    <string name=\"auth_action_notification_title\">Kontohandling kreves</string>\n    <string name=\"auth_action_activity_finish\">Fullfør</string>\n    <string name=\"signin_picker_title\">Velg en konto</string>\n    <string name=\"signin_picker_subtitle\">for å fortsette til <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"signin_picker_add_account_label\">Legg til en annen konto</string>\n    <string name=\"signin_confirm_title\">Tillatt å logge inn på <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"signin_confirm_button_text\">Tillat og del</string>\n    <string name=\"signin_subtext_policy_privacy\">personvernserklæring</string>\n    <string name=\"signin_subtext_policy_terms\">vilkår for bruk</string>\n    <string name=\"perm_c2dm_receive_label\">lytte til C2DM-meldinger</string>\n    <string name=\"perm_c2dm_send_label\">send C2DM-meldinger til andre apper</string>\n    <string name=\"perm_car_speed_label\">Bilhastighet</string>\n    <string name=\"perm_car_speed_description\">Få tilgang til hastigheten til bilen din</string>\n    <string name=\"perm_car_info_label\">Bilinformasjon</string>\n    <string name=\"perm_car_info_description\">Tilgang til informasjon om bilen din</string>\n    <string name=\"perm_car_fuel_label\">Bilens drivstoffnivå</string>\n    <string name=\"perm_car_fuel_description\">Få tilgang til drivstoffnivået til bilen din</string>\n    <string name=\"games_title\">Google Play Games</string>\n    <string name=\"pick_place_title\">Velg et sted</string>\n    <string name=\"place_picker_select_title\">Velg dette stedet</string>\n    <string name=\"place_picker_nearby_places\">Steder i nærheten</string>\n    <string name=\"place_picker_location_lat_lng\">(%1$.7f, %2$.7f)</string>\n    <string name=\"network_type_mobile\">Mobilt nettverk</string>\n    <string name=\"network_type_wifi\">Wi-Fi</string>\n    <string name=\"network_type_roaming\">Roaming</string>\n    <string name=\"network_type_other\">Andre nettverk</string>\n    <string name=\"self_check_cat_gms_packages\">Installerte pakker</string>\n    <string name=\"self_check_cat_system\">System</string>\n    <string name=\"prefcat_about\">Om</string>\n    <string name=\"prefcat_components\">Komponenter</string>\n    <string name=\"prefcat_configuration\">Konfigurasjon</string>\n    <string name=\"prefcat_google_services\">Google-tjenester</string>\n    <string name=\"prefcat_location_service\">Lokasjonstjenester</string>\n    <string name=\"prefcat_services\">Tjenester</string>\n    <string name=\"prefcat_test\">Test</string>\n    <string name=\"cond_gcm_bat_title\">Batterioptimaliseringer skrudd på</string>\n    <string name=\"cond_gcm_bat_action\">Ignorer batterioptimaliseringer</string>\n    <string name=\"prefs_account\">Kontoinnstillinger</string>\n    <string name=\"prefs_account_security\">Innlogging og sikkerhet</string>\n    <string name=\"pref_auth_visible_title\">La apper finne kontoer</string>\n    <string name=\"pref_device_registration_android_id\">Android-ID</string>\n    <string name=\"checkin_not_registered\">Ikke registrert</string>\n    <string name=\"checkin_last_registration\">Siste registering: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"checkin_enable_switch\">Registrer enhet</string>\n    <string name=\"pref_info_status\">Status</string>\n    <string name=\"pref_more_settings\">Mer</string>\n    <string name=\"pref_accounts_title\">Google-kontoer</string>\n    <string name=\"pref_game_accounts_title\">Google Game-kontoer</string>\n    <string name=\"pref_accounts_summary\">Legg til og håndter Google-kontoer</string>\n    <string name=\"prefcat_accounts_settings_title\">Innstillinger</string>\n    <string name=\"prefcat_accounts_current_accounts_title\">Kontoer</string>\n    <string name=\"pref_add_account_title\">Konto</string>\n    <string name=\"pref_add_account_summary\">Legg til Google-konto</string>\n    <string name=\"pref_gcm_confirm_new_apps_title\">Bekreft nye apper</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-night-v31/themes.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <style name=\"Theme.App\" parent=\"Theme.Base.DayNight.NoActionBar\" />\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-night-v8/themes.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2024 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<resources>\n    <style name=\"Theme.Base.DayNight\" parent=\"Theme.Base.Dark\" />\n    <style name=\"Theme.Base.DayNight.NoActionBar\" parent=\"Theme.Base.Dark.NoActionBar\" />\n\n    <style name=\"Theme.App\" parent=\"Theme.Base.DayNight.NoActionBar\">\n        <item name=\"colorPrimary\">@color/gm3_ref_palette_primary80</item>\n        <item name=\"colorOnPrimary\">@color/gm3_ref_palette_primary20</item>\n        <item name=\"colorPrimaryContainer\">@color/gm3_ref_palette_primary30</item>\n        <item name=\"colorOnPrimaryContainer\">@color/gm3_ref_palette_primary90</item>\n        <item name=\"colorPrimaryInverse\">@color/gm3_ref_palette_primary40</item>\n        <item name=\"colorPrimaryFixed\">@color/gm3_ref_palette_primary90</item>\n        <item name=\"colorPrimaryFixedDim\">@color/gm3_ref_palette_primary80</item>\n        <item name=\"colorOnPrimaryFixed\">@color/gm3_ref_palette_primary10</item>\n        <item name=\"colorOnPrimaryFixedVariant\">@color/gm3_ref_palette_primary30</item>\n        <item name=\"colorSecondary\">@color/gm3_ref_palette_secondary80</item>\n        <item name=\"colorOnSecondary\">@color/gm3_ref_palette_secondary20</item>\n        <item name=\"colorSecondaryContainer\">@color/gm3_ref_palette_secondary30</item>\n        <item name=\"colorOnSecondaryContainer\">@color/gm3_ref_palette_secondary90</item>\n        <item name=\"colorSecondaryFixed\">@color/gm3_ref_palette_secondary90</item>\n        <item name=\"colorSecondaryFixedDim\">@color/gm3_ref_palette_secondary80</item>\n        <item name=\"colorOnSecondaryFixed\">@color/gm3_ref_palette_secondary10</item>\n        <item name=\"colorOnSecondaryFixedVariant\">@color/gm3_ref_palette_secondary30</item>\n        <item name=\"colorTertiary\">@color/gm3_ref_palette_tertiary80</item>\n        <item name=\"colorOnTertiary\">@color/gm3_ref_palette_tertiary20</item>\n        <item name=\"colorTertiaryContainer\">@color/gm3_ref_palette_tertiary30</item>\n        <item name=\"colorOnTertiaryContainer\">@color/gm3_ref_palette_tertiary90</item>\n        <item name=\"colorTertiaryFixed\">@color/gm3_ref_palette_tertiary90</item>\n        <item name=\"colorTertiaryFixedDim\">@color/gm3_ref_palette_tertiary80</item>\n        <item name=\"colorOnTertiaryFixed\">@color/gm3_ref_palette_tertiary10</item>\n        <item name=\"colorOnTertiaryFixedVariant\">@color/gm3_ref_palette_tertiary30</item>\n\n        <item name=\"colorError\">@color/gm3_ref_palette_error80</item>\n        <item name=\"colorOnError\">@color/gm3_ref_palette_error20</item>\n        <item name=\"colorErrorContainer\">@color/gm3_ref_palette_error30</item>\n        <item name=\"colorOnErrorContainer\">@color/gm3_ref_palette_error90</item>\n        <item name=\"colorOutline\">@color/gm3_ref_palette_neutral_variant60</item>\n        <item name=\"colorOutlineVariant\">@color/gm3_ref_palette_neutral_variant30</item>\n        <item name=\"android:colorBackground\">@color/gm3_ref_palette_neutral6</item>\n        <item name=\"colorOnBackground\">@color/gm3_ref_palette_neutral90</item>\n        <item name=\"colorSurface\">@color/gm3_ref_palette_neutral6</item>\n        <item name=\"colorOnSurface\">@color/gm3_ref_palette_neutral90</item>\n        <item name=\"colorSurfaceVariant\">@color/gm3_ref_palette_neutral_variant30</item>\n        <item name=\"colorOnSurfaceVariant\">@color/gm3_ref_palette_neutral_variant80</item>\n        <item name=\"colorSurfaceInverse\">@color/gm3_ref_palette_neutral90</item>\n        <item name=\"colorOnSurfaceInverse\">@color/gm3_ref_palette_neutral20</item>\n        <item name=\"colorSurfaceBright\">#ff37393b</item>\n        <item name=\"colorSurfaceDim\">@color/gm3_ref_palette_neutral6</item>\n        <item name=\"colorSurfaceContainer\">#ff1e1f20</item>\n        <item name=\"colorSurfaceContainerLow\">#ff1b1b1b</item>\n        <item name=\"colorSurfaceContainerLowest\">#ff0e0e0e</item>\n        <item name=\"colorSurfaceContainerHigh\">#ff282a2c</item>\n        <item name=\"colorSurfaceContainerHighest\">#ff333537</item>\n    </style>\n\n    <!-- TODO: Heavy duplication -->\n    <style name=\"Theme.App.Translucent\" parent=\"Theme.Base.Translucent\">\n        <item name=\"colorPrimary\">@color/gm3_ref_palette_primary80</item>\n        <item name=\"colorOnPrimary\">@color/gm3_ref_palette_primary20</item>\n        <item name=\"colorPrimaryContainer\">@color/gm3_ref_palette_primary30</item>\n        <item name=\"colorOnPrimaryContainer\">@color/gm3_ref_palette_primary90</item>\n        <item name=\"colorPrimaryInverse\">@color/gm3_ref_palette_primary40</item>\n        <item name=\"colorPrimaryFixed\">@color/gm3_ref_palette_primary90</item>\n        <item name=\"colorPrimaryFixedDim\">@color/gm3_ref_palette_primary80</item>\n        <item name=\"colorOnPrimaryFixed\">@color/gm3_ref_palette_primary10</item>\n        <item name=\"colorOnPrimaryFixedVariant\">@color/gm3_ref_palette_primary30</item>\n        <item name=\"colorSecondary\">@color/gm3_ref_palette_secondary80</item>\n        <item name=\"colorOnSecondary\">@color/gm3_ref_palette_secondary20</item>\n        <item name=\"colorSecondaryContainer\">@color/gm3_ref_palette_secondary30</item>\n        <item name=\"colorOnSecondaryContainer\">@color/gm3_ref_palette_secondary90</item>\n        <item name=\"colorSecondaryFixed\">@color/gm3_ref_palette_secondary90</item>\n        <item name=\"colorSecondaryFixedDim\">@color/gm3_ref_palette_secondary80</item>\n        <item name=\"colorOnSecondaryFixed\">@color/gm3_ref_palette_secondary10</item>\n        <item name=\"colorOnSecondaryFixedVariant\">@color/gm3_ref_palette_secondary30</item>\n        <item name=\"colorTertiary\">@color/gm3_ref_palette_tertiary80</item>\n        <item name=\"colorOnTertiary\">@color/gm3_ref_palette_tertiary20</item>\n        <item name=\"colorTertiaryContainer\">@color/gm3_ref_palette_tertiary30</item>\n        <item name=\"colorOnTertiaryContainer\">@color/gm3_ref_palette_tertiary90</item>\n        <item name=\"colorTertiaryFixed\">@color/gm3_ref_palette_tertiary90</item>\n        <item name=\"colorTertiaryFixedDim\">@color/gm3_ref_palette_tertiary80</item>\n        <item name=\"colorOnTertiaryFixed\">@color/gm3_ref_palette_tertiary10</item>\n        <item name=\"colorOnTertiaryFixedVariant\">@color/gm3_ref_palette_tertiary30</item>\n\n        <item name=\"colorError\">@color/gm3_ref_palette_error80</item>\n        <item name=\"colorOnError\">@color/gm3_ref_palette_error20</item>\n        <item name=\"colorErrorContainer\">@color/gm3_ref_palette_error30</item>\n        <item name=\"colorOnErrorContainer\">@color/gm3_ref_palette_error90</item>\n        <item name=\"colorOutline\">@color/gm3_ref_palette_neutral_variant60</item>\n        <item name=\"colorOutlineVariant\">@color/gm3_ref_palette_neutral_variant30</item>\n        <item name=\"android:colorBackground\">@color/gm3_ref_palette_neutral6</item>\n        <item name=\"colorOnBackground\">@color/gm3_ref_palette_neutral90</item>\n        <item name=\"colorSurface\">@color/gm3_ref_palette_neutral6</item>\n        <item name=\"colorOnSurface\">@color/gm3_ref_palette_neutral90</item>\n        <item name=\"colorSurfaceVariant\">@color/gm3_ref_palette_neutral_variant30</item>\n        <item name=\"colorOnSurfaceVariant\">@color/gm3_ref_palette_neutral_variant80</item>\n        <item name=\"colorSurfaceInverse\">@color/gm3_ref_palette_neutral90</item>\n        <item name=\"colorOnSurfaceInverse\">@color/gm3_ref_palette_neutral20</item>\n        <item name=\"colorSurfaceBright\">#ff37393b</item>\n        <item name=\"colorSurfaceDim\">@color/gm3_ref_palette_neutral6</item>\n        <item name=\"colorSurfaceContainer\">#ff1e1f20</item>\n        <item name=\"colorSurfaceContainerLow\">#ff1b1b1b</item>\n        <item name=\"colorSurfaceContainerLowest\">#ff0e0e0e</item>\n        <item name=\"colorSurfaceContainerHigh\">#ff282a2c</item>\n        <item name=\"colorSurfaceContainerHighest\">#ff333537</item>\n    </style>\n</resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-nl/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"permission_service_all_label\">Alle Google-diensten</string>\n    <string name=\"permission_service_all_description\">Hiermee krijgt de app toegang tot alle Google-services via elk gekoppeld Google-account.</string>\n    <string name=\"permission_service_android_label\">Android-diensten</string>\n    <string name=\"permission_service_android_description\">Hiermee krijgt de app toegang tot Android-services via een geassocieerd Google-account.</string>\n    <string name=\"permission_service_adsense_label\">AdSense</string>\n    <string name=\"permission_service_adsense_description\">Hiermee krijgt de app toegang tot AdSense via elk gekoppeld Google-account.</string>\n    <string name=\"permission_service_adwords_label\">AdWords</string>\n    <string name=\"permission_service_adwords_description\">Hiermee krijgt de app toegang tot AdWords via elk gekoppeld Google-account.</string>\n    <string name=\"permission_service_ah_label\">Google App Engine</string>\n    <string name=\"permission_service_ah_description\">Hiermee krijgt een app toegang tot Google App Engine via een geassocieerd Google-account.</string>\n    <string name=\"permission_service_blogger_label\">Blogger</string>\n    <string name=\"permission_service_blogger_description\">Hiermee krijgt de app toegang tot Blogger via een gekoppeld Google-account.</string>\n    <string name=\"permission_service_cl_label\">Google Agenda</string>\n    <string name=\"permission_service_cl_description\">Hiermee krijgt de app toegang tot Google Agenda via elk gekoppeld Google-account.</string>\n    <string name=\"permission_service_cp_label\">Contacten</string>\n    <string name=\"permission_service_dodgeball_label\">Dodgeball</string>\n    <string name=\"permission_service_dodgeball_description\">Geeft app toegang tot Dodgeball via een geassocieerd Google-account.</string>\n    <string name=\"permission_service_cp_description\">Hiermee krijgt de app toegang tot Contacten via een geassocieerd Google-account.</string>\n    <string name=\"permission_service_finance_label\">Google Financiën</string>\n    <string name=\"permission_service_finance_description\">Hiermee krijgt de app toegang tot Google Finance via een gekoppeld Google-account.</string>\n    <string name=\"permission_service_gbase_label\">Google Basis</string>\n    <string name=\"permission_service_gbase_description\">Stelt app in staat om toegang te krijgen tot Google Base via een geassocieerd Google-account.</string>\n    <string name=\"permission_service_grandcentral_label\">Google Voice</string>\n    <string name=\"permission_service_grandcentral_description\">Hiermee krijgt de app toegang tot Google Voice via een geassocieerd Google-account.</string>\n    <string name=\"permission_service_groups2_label\">Google Groups</string>\n    <string name=\"permission_service_health_label\">Google Health</string>\n    <string name=\"permission_service_health_description\">Hiermee krijgt de app toegang tot Google Health via een geassocieerd Google-account.</string>\n    <string name=\"permission_service_groups2_description\">Hiermee krijgt de app toegang tot Google Groups via elk gekoppeld Google-account.</string>\n    <string name=\"permission_service_ig_label\">iGoogle</string>\n    <string name=\"permission_service_ig_description\">Hiermee krijgt de app toegang tot iGoogle via een geassocieerd Google-account.</string>\n    <string name=\"permission_service_jotspot_label\">JotSpot</string>\n    <string name=\"permission_service_jotspot_description\">Stelt app in staat om toegang te krijgen tot JotSpot via een geassocieerd Google-account.</string>\n    <string name=\"permission_service_knol_label\">Knol</string>\n    <string name=\"permission_service_knol_description\">Stelt app in staat om toegang te krijgen tot Knol via een geassocieerd Google-account.</string>\n    <string name=\"permission_service_lh2_label\">Picasa Web Albums</string>\n    <string name=\"permission_service_lh2_description\">Hiermee krijgt de app toegang tot Picasa Web Albums via een geassocieerd Google-account.</string>\n    <string name=\"permission_service_local_label\">Google Maps</string>\n    <string name=\"permission_service_news_label\">Google News</string>\n    <string name=\"permission_service_news_description\">Hiermee krijgt de app toegang tot Google News via een geassocieerd Google-account.</string>\n    <string name=\"permission_service_notebook_label\">Google Notebook</string>\n    <string name=\"permission_service_notebook_description\">Hiermee krijgt de app toegang tot Google Notebook via elk gekoppeld Google-account.</string>\n    <string name=\"permission_service_orkut_label\">Orkut</string>\n    <string name=\"permission_service_orkut_description\">Hiermee krijgt de app toegang tot Orkut via een geassocieerd Google-account.</string>\n    <string name=\"permission_service_print_description\">Hiermee krijgt de app toegang tot Google Zoeken naar boeken via een geassocieerd Google-account.</string>\n    <string name=\"permission_service_sierra_description\">Hiermee krijgt de app toegang tot Google Checkout-accounts via een geassocieerd Google-account.</string>\n    <string name=\"permission_service_sierra_label\">Google Checkout accounts</string>\n    <string name=\"permission_service_sierrasandbox_label\">Google Checkout Sandbox accounts</string>\n    <string name=\"permission_service_sierraqa_label\">Google Checkout QA accounts</string>\n    <string name=\"permission_service_sierraqa_description\">Hiermee krijgt de app toegang tot Google Checkout QA-accounts via een geassocieerd Google-account.</string>\n    <string name=\"permission_service_sierrasandbox_description\">Geeft app toegang tot Google Checkout Sandbox-accounts via een geassocieerd Google-account.</string>\n    <string name=\"permission_service_sitemaps_label\">Google Webmasterhulpprogramma\\'s</string>\n    <string name=\"permission_service_sitemaps_description\">Hiermee krijgt de app toegang tot Google Webmasterhulpprogramma\\'s via elk gekoppeld Google-account.</string>\n    <string name=\"permission_service_speech_label\">Spraakgestuurd zoeken</string>\n    <string name=\"permission_service_speech_description\">Hiermee krijgt de app toegang tot Spraakgestuurd zoeken via een geassocieerd Google-account.</string>\n    <string name=\"permission_service_speechpersonalization_label\">Gepersonaliseerde spraakherkenning</string>\n    <string name=\"permission_service_speechpersonalization_description\">Geeft app toegang tot Persoonlijke Spraakherkenning via een geassocieerde Google-account.</string>\n    <string name=\"permission_service_talk_label\">Google gesprekken</string>\n    <string name=\"permission_service_talk_description\">Hiermee krijgt de app toegang tot Google gesprekken via een geassocieerd Google-account.</string>\n    <string name=\"permission_service_wifi_label\">Google Wi-Fi</string>\n    <string name=\"permission_service_wifi_description\">Hiermee krijgt de app toegang tot Google Wi-Fi via een geassocieerd Google-account.</string>\n    <string name=\"permission_service_wise_label\">Google Werkbladen</string>\n    <string name=\"permission_service_wise_description\">Hiermee krijgt de app toegang tot Google Werkbladen via elk gekoppeld Google-account.</string>\n    <string name=\"permission_service_writely_label\">Google Documenten</string>\n    <string name=\"permission_service_writely_description\">Hiermee krijgt de app toegang tot Google Documenten via elk gekoppeld Google-account.</string>\n    <string name=\"permission_service_youtube_label\">YouTube</string>\n    <string name=\"permission_service_youtube_description\">Hiermee krijgt de app toegang tot YouTube via een geassocieerd Google-account.</string>\n    <string name=\"permission_service_mail_description\">Hiermee krijgt de app toegang tot Google Mail via een geassocieerd Google-account.</string>\n    <string name=\"permission_service_local_description\">Hiermee krijgt de app toegang tot Google Maps via een geassocieerd Google-account.</string>\n    <string name=\"permission_service_mail_label\">Google Mail</string>\n    <string name=\"permission_service_print_label\">Google Zoeken naar boeken</string>\n    <string name=\"permission_service_YouTubeUser_label\">YouTube gebruikersnamen</string>\n    <string name=\"permission_service_YouTubeUser_description\">Hiermee krijgt de app toegang tot YouTube-gebruikersnaam (-namen) die worden gebruikt met een geassocieerd Google-account.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_activity\">De activiteitengeschiedenis van uw Google Apps bekijken</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.buyer\">De configuratie van uw Ad Exchange-kopersaccount beheren</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller.readonly\">Uw Ad Exchange-gegevens bekijken</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller\">Uw Ad Exchange-gegevens bekijken en beheren</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsensehost\">Bekijk en beheer je AdSense-hostgegevens en bijbehorende accounts</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense.readonly\">Je AdSense-gegevens bekijken</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense\">Bekijk en beheer je AdSense-gegevens</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics.readonly\">Uw Google Analytics-gegevens bekijken</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics\">Uw Google Analytics-gegevens bekijken en beheren</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_androidpublisher\">Toegang tot de Google Play Android-ontwikkelaar</string>\n    <string name=\"perm_activity_recognition_label\">Activiteit herkennen</string>\n    <string name=\"perm_activity_recognition_description\">Hiermee kan een app periodieke updates van je activiteitsniveau ontvangen van Google, bijvoorbeeld of je loopt, rijdt, fietst of stilstaat.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appengine.admin\">App engine beheerbereik.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.migration\">Lees- en schrijftoegang tot de Migratie-API van Groepen.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.settings\">De instellingen van een Google Apps-groep bekijken en beheren</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.licensing\">Lees/schrijftoegang tot License Manager API.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_cloudprint\">Bekijk en beheer uw Google Cloud Print-gegevens</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.full_control\">Beheer uw gegevens en machtigingen in Google Cloud Opslag</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_only\">Bekijk uw gegevens in Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_write\">Beheer uw gegevens in Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gcm_for_chrome\">CloudMessaging voor Chrome</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-nl/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <plurals name=\"cond_perm_summary\">\n        <item quantity=\"one\">Een toestemming die nodig is voor een goede werking van microG Services wordt niet verleend.</item>\n        <item quantity=\"other\">Toestemmingen die nodig zijn voor een goede werking van microG Services worden niet verleend.</item>\n    </plurals>\n    <plurals name=\"cond_perm_action\">\n        <item quantity=\"one\">Ontbrekende toestemming vragen</item>\n        <item quantity=\"other\">Ontbrekende toestemmingen aanvragen</item>\n    </plurals>\n    <plurals name=\"pref_unifiednlp_summary\">\n        <item quantity=\"one\">&lt;xliff:g example=“1”&gt;%1$d&lt;/xliff:g&gt; backend geconfigureerd</item>\n        <item quantity=\"other\">&lt;xliff:g example=“3”&gt;%1$d&lt;/xliff:g&gt; geconfigureerde backends</item>\n    </plurals>\n    <plurals name=\"gcm_registered_apps_counter\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> geregistreerde app</item>\n        <item quantity=\"other\"><xliff:g example=\"123\">%1$d</xliff:g> geregistreerde apps</item>\n    </plurals>\n</resources>\n"
  },
  {
    "path": "play-services-core/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\">\n    <string name=\"account_manager_title\">Google-accountbeheerder</string>\n    <string name=\"auth_sign_in\">Aanmelden</string>\n    <string name=\"self_check_name_fake_sig_perm\">Het systeem ondersteunt vervalste handtekening:</string>\n    <string name=\"self_check_name_perm_granted\">Verleen toestemming voor vervalste handtekening te gebruiken:</string>\n    <string name=\"pref_add_account_summary\">Google account toevoegen</string>\n    <string name=\"pref_push_app_wake_for_delivery_summary\">Start the app while in background to receive the incoming push messages.</string>\n    <string name=\"profile_name_user\">Custom: %s</string>\n    <string name=\"push_notifications_summary_off\">OFF</string>\n    <string name=\"gms_app_name\">microG-diensten</string>\n    <string name=\"gms_settings_name\">microG-instellingen</string>\n    <string name=\"gms_settings_summary\">MicroG-services instellen.</string>\n    <string name=\"just_a_sec\">Wacht even…</string>\n    <string name=\"ask_permission_tos\">Als u doorgaat, geeft u deze app en Google toestemming uw gegevens te gebruiken in overeenstemming met hun respectieve servicevoorwaarden en privacybeleid.</string>\n    <string name=\"google_account_label\">Google</string>\n    <string name=\"sorry\">Sorry…</string>\n    <string name=\"auth_before_connect\">Een app op uw apparaat probeert zich aan te melden bij een Google-account.\\n\\nAls dit de bedoeling was, gebruik dan de knop <b>Aanmelden</b> om verbinding te maken met de aanmeldingspagina van Google. Zo niet, druk dan op <b>Annuleren</b> om terug te gaan naar de toepassing die dit dialoogvenster heeft veroorzaakt.</string>\n    <string name=\"auth_connecting\">Je apparaat maakt verbinding met de servers van Google om je aan te melden.\\n\\nDit kan enkele seconden duren.</string>\n    <string name=\"no_network_error_desc\">Je hebt geen netwerkverbinding. \\n \\nDit kan een tijdelijk probleem zijn of je Android-toestel is mogelijk niet ingesteld op dataservices. Probeer het opnieuw als je verbinding hebt met een mobiel netwerk of maak verbinding met een Wi-Fi-netwerk.</string>\n    <string name=\"auth_general_error_desc\">Er is een probleem opgetreden bij de communicatie met de Google-servers. \\n \\nProbeer het later opnieuw.</string>\n    <string name=\"auth_finalize\">Uw apparaat neemt contact op met Google om informatie op te slaan in uw account. \\n \\nDit kan een paar minuten duren.</string>\n    <string name=\"allow\">Toestaan</string>\n    <string name=\"deny\">Niet toestaan</string>\n    <string name=\"auth_notification_title\">Verificatie vereist</string>\n    <string name=\"auth_notification_content\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> heeft uw autorisatie nodig om toegang te krijgen tot uw Google-account.</string>\n    <string name=\"signin_picker_title\">Kies een account</string>\n    <string name=\"signin_picker_subtitle\">om door te gaan met <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"signin_picker_add_account_label\">Een ander account toevoegen</string>\n    <string name=\"signin_confirm_title\">Toestaan om u aan te melden bij <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"signin_confirm_button_text\">Toestaan en delen</string>\n    <string name=\"signin_subtext_sharing\">Om door te gaan, deelt microG naam, e-mailadres en profielfoto van uw Google-account met <xliff:g example=\"F-Droid\">%1$s</xliff:g>.</string>\n    <string name=\"signin_subtext_policy\">Bekijk de %1$s en %2$s voordat u deze app gebruikt.</string>\n    <string name=\"signin_subtext_policy_privacy\">privacybeleid</string>\n    <string name=\"signin_subtext_policy_terms\">servicevoorwaarden</string>\n    <string name=\"perm_status_broadcast_label\">luisteren naar interne statusuitzendingen</string>\n    <string name=\"perm_gsf_read_gservices_label\">Google-serviceconfiguratie lezen</string>\n    <string name=\"perm_c2dm_receive_label\">C2DM berichten beluisteren</string>\n    <string name=\"perm_c2dm_send_label\">send C2DM messages to other apps</string>\n    <string name=\"perm_gtalk_svc_label\">exchange messages and receive sync notifications from Google servers</string>\n    <string name=\"perm_extended_access_label\">Extended access to Google services</string>\n    <string name=\"perm_provision_label\">provision microG services</string>\n    <string name=\"perm_provision_description\">Hiermee kan de app microG-diensten configureren zonder interactie van de gebruiker</string>\n    <string name=\"perm_car_speed_label\">Car speed</string>\n    <string name=\"perm_car_speed_description\">Access your car\\'s speed</string>\n    <string name=\"perm_car_info_label\">Car information</string>\n    <string name=\"perm_car_info_description\">Access your car\\'s information</string>\n    <string name=\"perm_car_fuel_label\">Car fuel level</string>\n    <string name=\"perm_car_fuel_description\">Access your car\\'s fuel level information</string>\n    <string name=\"perm_car_mileage_label\">Car mileage</string>\n    <string name=\"perm_car_vendor_extension_label\">Car vendor channel</string>\n    <string name=\"perm_car_mileage_description\">Access your car\\'s mileage information</string>\n    <string name=\"perm_car_vendor_extension_description\">Access your car\\'s vendor channel to exchange car-specific information</string>\n    <string name=\"service_name_checkin\">Google apparaat registratie</string>\n    <string name=\"service_name_mcs\">Cloud berichtenuitwisseling</string>\n    <string name=\"service_name_snet\">Google Beveiligingsnet</string>\n    <string name=\"service_name_vending\">Play Store diensten</string>\n    <string name=\"games_title\">Google Play Games</string>\n    <string name=\"games_info_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> zou graag Play Games gebruiken</string>\n    <string name=\"games_info_content\">To use Play Games it is required to install the Google Play Games app. The application might continue without Play Games, but it is possible that it will behave unexpectedly.</string>\n    <string name=\"pick_place_title\">Pick a place</string>\n    <string name=\"pick_place_desc\">Place picker is not yet available.</string>\n    <string name=\"place_picker_select_title\">Selecteer deze locatie</string>\n    <string name=\"place_picker_nearby_places\">Nearby places</string>\n    <string name=\"place_picker_location_lat_lng\">(%1$.7f, %2$.7f)</string>\n    <string name=\"lacking_permission_toast\">microG Services: Geen toestemming voor <xliff:g example=\"volledige netwerktoegang\">%1$s</xliff:g></string>\n    <string name=\"network_type_mobile\">Mobile network</string>\n    <string name=\"network_type_wifi\">Wi-Fi</string>\n    <string name=\"network_type_roaming\">Roaming</string>\n    <string name=\"network_type_other\">Other networks</string>\n    <string name=\"self_check_cat_fake_sig\">Vervalste handtekening ondersteuning</string>\n    <string name=\"self_check_cat_gms_packages\">Geïnstalleerde pakketten</string>\n    <string name=\"self_check_cat_system\">System</string>\n    <string name=\"self_check_resolution_fake_sig_perm\">Je ROM heeft geen native ondersteuning voor handtekening spoofing. Je kunt nog steeds Xposed of andere systemen gebruiken om de handtekening te spoofen. Bekijk de documentatie over welke ROM\\'s signature spoofing ondersteunen en hoe microG te gebruiken op ROM\\'s die dit niet ondersteunen.</string>\n    <string name=\"self_check_resolution_perm_granted\">Dit is een sterke indicator dat het ROM vervalste handtekening ondersteunt, maar verdere actie vereist om het te activeren. Controleer in de documentatie welke stappen nodig kunnen zijn.</string>\n    <string name=\"self_check_name_system_spoofs\">Het systeem vervalst de handtekening:</string>\n    <string name=\"self_check_resolution_system_spoofs\">Controleer in de documentatie welke stappen nodig kunnen zijn.</string>\n    <string name=\"self_check_pkg_gms\">microG Diensten</string>\n    <string name=\"self_check_pkg_vending\">microG Metgezel / Play Store</string>\n    <string name=\"self_check_pkg_gsf\">microG Diensten Kader</string>\n    <string name=\"self_check_name_app_installed\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> geïnstalleerd:</string>\n    <string name=\"self_check_resolution_app_installed\">Installeer de toepassing <xliff:g example=\"F-Droid\">%1$s</xliff:g> of een compatibele toepassing. Raadpleeg de documentatie over welke applicaties compatibel zijn.</string>\n    <string name=\"self_check_name_correct_sig\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> heeft correcte handtekening:</string>\n    <string name=\"self_check_resolution_correct_sig\">Of de geïnstalleerde <xliff:g example=\"F-Droid\">%1$s</xliff:g> is niet compatibel met de vervalste handtekening. Controleer in de documentatie welke applicaties en ROM\\'s compatibel zijn.</string>\n    <string name=\"self_check_name_battery_optimizations\">Batterijoptimalisaties genegeerd:</string>\n    <string name=\"self_check_resolution_battery_optimizations\">Raak hier aan om batterijoptimalisaties uit te schakelen. Als u dit niet doet, kan dit leiden tot applicaties die zich niet goed gedragen.</string>\n    <string name=\"prefcat_about\">Over</string>\n    <string name=\"prefcat_components\">Components</string>\n    <string name=\"prefcat_configuration\">Configuration</string>\n    <string name=\"prefcat_google_services\">Google Services</string>\n    <string name=\"prefcat_location_service\">Locatiedienst</string>\n    <string name=\"prefcat_services\">Services</string>\n    <string name=\"prefcat_test\">Test</string>\n    <string name=\"cond_gcm_bat_title\">Batterijoptimalisaties ingeschakeld</string>\n    <string name=\"cond_gcm_bat_summary\">Je hebt Cloud Messaging ingeschakeld maar batterijoptimalisatie is actief voor microG Services. Als je pushberichten wilt ontvangen, moet je de batterijoptimalisatie negeren.</string>\n    <string name=\"cond_gcm_bat_action\">Ignore optimizations</string>\n    <string name=\"cond_perm_title\">Toestemming ontbreekt</string>\n    <string name=\"prefs_account\">Account preferences</string>\n    <string name=\"prefs_account_privacy\">Personal info &amp; privacy</string>\n    <string name=\"prefs_account_security\">Sign-in &amp; security</string>\n    <string name=\"pref_auth_trust_google_title\">Vertrouw op Google voor app-machtigingen</string>\n    <string name=\"pref_auth_trust_google_summary\">When disabled, the user is asked before an app\\'s authorization request is sent to Google. Some applications will fail to use the Google account if this is disabled.</string>\n    <string name=\"pref_auth_visible_title\">Apps toestaan accounts te vinden</string>\n    <string name=\"pref_auth_visible_summary\">Als deze optie is ingeschakeld, kunnen alle applicaties op dit apparaat e-mailadressen van uw Google-accounts zien zonder voorafgaande toestemming.</string>\n    <string name=\"pref_auth_include_android_id_title\">Authenticeren met apparaatregistratie</string>\n    <string name=\"pref_auth_include_android_id_summary\">Als deze optie is uitgeschakeld, worden verificatieverzoeken niet gekoppeld aan de apparaatregistratie, waardoor onbevoegde apparaten zich kunnen aanmelden, maar wat onvoorziene gevolgen kan hebben.</string>\n    <string name=\"pref_auth_strip_device_name_title\">Apparaatnaam strippen voor verificatie</string>\n    <string name=\"pref_auth_strip_device_name_summary\">Als deze optie is ingeschakeld, bevatten verificatieverzoeken niet de naam van het apparaat, waardoor onbevoegde apparaten zich kunnen aanmelden, maar dit kan onvoorziene gevolgen hebben.</string>\n    <string name=\"pref_checkin_enable_summary\">Registreert uw apparaat bij Google-services en maakt een unieke apparaat-id aan. microG verwijdert andere identificerende bits dan uw Google-accountnaam uit de registratiegegevens.</string>\n    <string name=\"pref_device_registration_android_id\">Android ID</string>\n    <string name=\"checkin_not_registered\">Not registered</string>\n    <string name=\"checkin_last_registration\">Laatste registratie: <xliff:g example=\"Gisteren, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"checkin_enable_switch\">Registreer apparaat</string>\n    <string name=\"pref_info_status\">Status</string>\n    <string name=\"pref_more_settings\">More</string>\n    <string name=\"pref_accounts_title\">Google Accounts</string>\n    <string name=\"pref_accounts_summary\">Google-accounts toevoegen en beheren</string>\n    <string name=\"prefcat_accounts_settings_title\">Settings</string>\n    <string name=\"prefcat_accounts_current_accounts_title\">Accounts</string>\n    <string name=\"pref_add_account_title\">Account</string>\n    <string name=\"pref_gcm_enable_mcs_summary\">Cloud Messaging is een provider van pushberichten die door veel applicaties van derden wordt gebruikt. Om het te gebruiken moet je apparaatregistratie inschakelen.</string>\n    <string name=\"pref_gcm_heartbeat_title\">Cloud Messaging heartbeat interval</string>\n    <string name=\"pref_gcm_heartbeat_summary\">Het interval in seconden voor het systeem om de Google-servers te heartbeaten. Het verhogen van dit getal zal het batterijverbruik verminderen, maar kan vertragingen veroorzaken bij pushberichten.\\nWordt vervangen in toekomstige versies.</string>\n    <string name=\"pref_gcm_apps_title\">Apps die Cloud Messaging gebruiken</string>\n    <string name=\"pref_gcm_apps_summary\">Lijst van apps die momenteel zijn geregistreerd voor Cloud Messaging.</string>\n    <string name=\"pref_gcm_confirm_new_apps_title\">Confirm new apps</string>\n    <string name=\"pref_gcm_confirm_new_apps_summary\">Ask before registering a new app to receive push notifications</string>\n    <string name=\"pref_gcm_ping_interval\">Ping interval: <xliff:g example=\"10 minuten\">%1$s</xliff:g></string>\n    <string name=\"pref_about_title\">Over microG Diensten</string>\n    <string name=\"pref_about_summary\">Versie informatie en gebruikte bibliotheken</string>\n    <string name=\"gcm_app_error_unregistering\">Error unregistering</string>\n    <string name=\"gcm_app_not_installed_anymore\">No longer installed</string>\n    <string name=\"gcm_unregister_app\">Unregister</string>\n    <string name=\"gcm_not_registered\">Not registered</string>\n    <string name=\"gcm_no_message_yet\">No messages received so far</string>\n    <string name=\"gcm_last_message_at\">Laatste bericht: <xliff:g example=\"Gisteren, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_registered\">Registered</string>\n    <string name=\"gcm_registered_since\">Geregistreerd sinds: <xliff:g example=\"Gisteren, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_unregister_confirm_title\">Verwijderen <xliff:g example=\"F-Droid\">%1$s</xliff:g>\\?</string>\n    <string name=\"gcm_unregister_confirm_message\">Sommige apps registreren zich niet automatisch opnieuw en/of bieden geen optie om dit handmatig te doen. Deze apps werken mogelijk niet correct na het afmelden.\\nDoorgaan?</string>\n    <string name=\"gcm_unregister_after_deny_message\">You denied an app to register for push notifications that is already registered.\n\\nDo you want to unregister it now so it does not receive push messages in the future?</string>\n    <string name=\"gcm_messages_counter\">Berichten: <xliff:g example=\"123\">%1$d</xliff:g> (<xliff:g example=\"12345\">%2$d</xliff:g> bytes)</string>\n    <string name=\"gcm_network_state_disconnected\">Disconnected</string>\n    <string name=\"gcm_network_state_connected\">Verbonden sinds <xliff:g example=\"2 hours ago\">%1$s</xliff:g></string>\n    <string name=\"gcm_enable_switch\">Pushmeldingen ontvangen</string>\n    <string name=\"gcm_allow_app_popup\">Toestaan <xliff:g example=\"F-Droid\">%1$s</xliff:g> om te registreren voor pushmeldingen?</string>\n    <string name=\"pref_push_app_allow_register_title\">Allow registration</string>\n    <string name=\"pref_push_app_allow_register_summary\">Allow the app to register for push notifications.</string>\n    <string name=\"pref_push_app_wake_for_delivery_title\">Start app on push message</string>\n    <string name=\"prefcat_push_apps_title\">Apps die pushmeldingen gebruiken</string>\n    <string name=\"prefcat_push_apps_registered_title\">Registered apps</string>\n    <string name=\"prefcat_push_apps_unregistered_title\">Unregistered apps</string>\n    <string name=\"prefcat_push_networks_title\">Networks to use for push notifications</string>\n    <string name=\"safetynet_intro\">Google SafetyNet is een apparaatcertificeringssysteem dat ervoor zorgt dat het apparaat goed beveiligd is en compatibel is met Android CTS. Sommige toepassingen gebruiken SafetyNet om veiligheidsredenen of als voorwaarde voor sabotagebeveiliging.\\n \\nmicroG GmsCore bevat een vrije implementatie van SafetyNet, maar de officiële server vereist dat verzoeken voor SafetyNet worden ondertekend met het gepatenteerde DroidGuard-systeem.</string>\n    <string name=\"safetynet_enable_switch\">Apparaatattestatie toestaan</string>\n    <string name=\"pref_safetynet_test_title\">Test SafetyNet attestation</string>\n    <string name=\"pref_recaptcha_test_title\">Test ReCAPTCHA</string>\n    <string name=\"pref_recaptcha_enterprise_test_title\">Test ReCAPTCHA Enterprise</string>\n    <string name=\"pref_test_summary_passed\">Passed all tests</string>\n    <string name=\"pref_droidguard_operation_mode\">Operation mode</string>\n    <string name=\"pref_test_summary_failed\">Failed: %s</string>\n    <string name=\"pref_test_summary_warn\">Warning: %s</string>\n    <string name=\"pref_test_summary_running\">Running…</string>\n    <string name=\"pref_droidguard_unsupported_summary\">DroidGuard execution is unsupported on this device. SafetyNet services may misbehave.</string>\n    <string name=\"prefcat_safetynet_apps_title\">Apps using SafetyNet</string>\n    <string name=\"menu_clear_recent_requests\">Clear recent requests</string>\n    <string name=\"safetynet_last_run_at\">Laatste gebruik: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"profile_name_native\">Native</string>\n    <string name=\"profile_name_real\">Real</string>\n    <string name=\"profile_name_auto\">Automatic: %s</string>\n    <string name=\"profile_name_system\">System: %s</string>\n    <string name=\"pref_device_registration_import_custom_profile_title\">Aangepast profiel importeren</string>\n    <string name=\"pref_device_registration_serial_title\">Serial</string>\n    <string name=\"pref_device_registration_import_custom_profile_summary\">Apparaatprofiel importeren uit bestand</string>\n    <string name=\"pref_device_registration_select_profile_title\">Profiel selecteren</string>\n    <string name=\"pref_device_registration_device_profile_category\">Apparaatprofiel</string>\n    <string name=\"pref_safetynet_recent_uses\">Recent uses</string>\n    <string name=\"pref_safetynet_recent_attestation_summary\">Attestation: %s</string>\n    <string name=\"pref_safetynet_recent_recaptcha_summary\">ReCaptcha: %s</string>\n    <string name=\"pref_safetynet_recent_recaptcha_enterprise_summary\">ReCaptcha Enterprise: %s</string>\n    <string name=\"pref_safetynet_recent_copy_json\">Copy JSON JWS data</string>\n    <string name=\"pref_safetynet_recent_advice\">Advice</string>\n    <string name=\"pref_safetynet_recent_eval_type\">Evaluation type</string>\n    <string name=\"pref_safetynet_recent_response_status\">Response status</string>\n    <string name=\"pref_safetynet_recent_cat_response\">Response data</string>\n    <string name=\"pref_safetynet_recent_cat_request\">Request data</string>\n    <string name=\"pref_safetynet_recent_nonce\">Nonce (Hex)</string>\n    <string name=\"pref_safetynet_recent_request_time\">Time of request</string>\n    <string name=\"pref_safetynet_recent_request_type\">Request type</string>\n    <string name=\"pref_safetynet_recent_cat_basic\">Basic data</string>\n    <string name=\"pref_safetynet_recent_token\">Token</string>\n    <string name=\"pref_safetynet_recent_copied\">Copied to clipboard!</string>\n    <string name=\"pref_safetynet_test_integrity_cts_passed\">Integrity and CTS passed</string>\n    <string name=\"pref_safetynet_test_not_completed\">Not completed yet</string>\n    <string name=\"pref_safetynet_test_cts_failed\">CTS failed</string>\n    <string name=\"pref_safetynet_test_integrity_failed\">Integrity failed</string>\n    <string name=\"pref_safetynet_test_no_result\">No result</string>\n    <string name=\"pref_safetynet_test_invalid_json\">Invalid JSON</string>\n    <string name=\"push_notifications_summary_automatic\">ON / Automatic: %s</string>\n    <string name=\"push_notifications_summary_manual\">ON / Manual: %s</string>\n    <string name=\"push_notifications_summary_values_seconds\">%s seconds</string>\n    <string name=\"push_notifications_summary_values_minutes\">%s minutes</string>\n    <string name=\"pref_vending_summary_licensing_off\">Licensing off</string>\n    <string name=\"pref_vending_summary_licensing_on\">Licensing on</string>\n    <string name=\"pref_vending_licensing_category\">Google Play-licenties</string>\n    <string name=\"pref_vending_licensing_enable_switch\">Licentieverificatieverzoeken</string>\n    <string name=\"feedback_disabled\">Feedback currently not possible</string>\n    <string name=\"pref_vending_license_enable_summary\">Sommige apps vereisen verificatie dat u ze op Google Play hebt gekocht. Als een app daarom vraagt, kan microG een aankoopbewijs van Google downloaden. Als dit is uitgeschakeld of als er geen Google-account is toegevoegd, worden verzoeken om licentieverificatie genegeerd.</string>\n    <string name=\"backup_disabled\">Backup currently not possible</string>\n    <string name=\"pref_vending_billing_category\">Google Play Billing</string>\n    <string name=\"pref_vending_billing_enable_switch\">Factureringsverzoeken afhandelen</string>\n    <string name=\"pref_vending_billing_enable_summary\">Zodra dit is ingeschakeld, kunnen sommige apps aankopen voltooien of abonnementen starten via de Play Billing-service van Google.</string>\n    <string name=\"pref_vending_billing_note_experimental\">Deze functie is experimenteel en kan leiden tot geldverlies. Je bent gewaarschuwd.</string>\n    <string name=\"pref_vending_billing_note_licensing\">Bij sommige apps moet je mogelijk ook licentieverificatie inschakelen om je aankopen te verifiëren.</string>\n    <string name=\"ask_scope_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> wil het volgende:</string>\n    <string name=\"ask_service_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> wil het volgende gebruiken:</string>\n    <string name=\"limited_services_app_name\">microG Beperkte diensten</string>\n    <string name=\"auth_action_notification_channel_name\">Google accountmeldingen</string>\n    <string name=\"auth_action_notification_channel_description\">Geeft een melding wanneer een van uw Google-accounts extra moet worden ingesteld voordat deze kan worden gebruikt of wanneer een account niet compatibel is met microG.</string>\n    <string name=\"auth_action_notification_title\">Accountactie vereist</string>\n    <string name=\"auth_package_override_request_title\">&lt;b&gt;&lt;xliff:g example=“F-Droid”&gt;%1$s&lt;/xliff:g&gt;&lt;/b&gt; geprivilegieerde toegang toestaan tot &lt;xliff:g example=“account@example.com”&gt;%2$s&lt;/xliff:g&gt;?</string>\n    <string name=\"auth_package_override_request_message\"><b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> wants to access your account as if it was <b><xliff:g example=\"F-Droid\">%2$s</xliff:g> by <xliff:g example=\"F-Droid Inc.\">%3$s</xliff:g></b>. Dit kan het bevoorrechte toegang tot je account geven.</string>\n    <string name=\"auth_action_activity_explanation\">Voer de volgende stappen uit om uw Google-account %s op dit apparaat te kunnen gebruiken.</string>\n    <string name=\"auth_action_step_enable_checkin_description\">Je apparaat moet zich minstens één keer registreren bij Google.\\n\\nU kunt de registratie van Google-apparaten uitschakelen nadat de account is ingesteld.</string>\n    <string name=\"auth_action_step_enable_gcm\">Cloud Messaging inschakelen</string>\n    <string name=\"credentials_assisted_signin_description\">U kunt Aanmelden met Google beheren in uw Google-accounts.</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_switch\">Automatisch gratis apps toevoegen aan bibliotheek</string>\n    <string name=\"credentials_assisted_sign_back_title\">Aanmelden bij %1$s met Google</string>\n    <string name=\"credentials_assisted_signin_consent_header\">Aanmelden als %1$s</string>\n    <string name=\"credentials_assisted_choose_account_label\">Account kiezen</string>\n    <string name=\"auth_action_notification_content\">Je Google-account moet extra worden ingesteld.</string>\n    <string name=\"auth_action_activity_header\">Voltooi het instellen van je Google-account</string>\n    <string name=\"auth_action_step_enable_checkin\">Apparaatregistratie inschakelen</string>\n    <string name=\"auth_action_step_enable_gcm_description\">U kunt Cloud Messaging uitschakelen nadat de account is ingesteld.</string>\n    <string name=\"auth_action_step_allow_microg_gcm\">Cloudberichten voor microG toestaan</string>\n    <string name=\"auth_action_step_allow_microg_gcm_description\">Volgens uw voorkeuren heeft microG toestemming van u nodig voordat het zichzelf kan registreren voor Cloudberichten.</string>\n    <string name=\"auth_action_step_enable_lockscreen\">Beveiligde schermvergrendeling configureren</string>\n    <string name=\"auth_action_step_perform_content_description\">Klik om stap uit te voeren</string>\n    <string name=\"auth_action_step_completed_content_description\">Stap voltooid</string>\n    <string name=\"auth_action_activity_finish\">Afwerking</string>\n    <string name=\"credentials_assisted_cancel\">Annuleren</string>\n    <string name=\"credentials_assisted_continue\">Doorgaan</string>\n    <string name=\"limited_services_dialog_information\">U gebruikt de microG Limited Services. In tegenstelling tot de gebruikelijke microG-services, werkt deze alleen met apps die microG-bibliotheken gebruiken, niet die op Google Play. Dit betekent dat de meeste toepassingen deze services zullen negeren.</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_summary\">Gratis apps kunnen controleren of ze zijn gedownload van Google Play. Voeg automatisch gratis apps toe aan je accountbibliotheek zodat je altijd door de controle komt voor alle gratis apps die momenteel voor jou beschikbaar zijn.</string>\n    <string name=\"auth_action_step_enable_lockscreen_description\">Je Google-account wordt beheerd door je werkplek of onderwijsinstelling. Uw beheerder heeft besloten dat apparaten een veilige schermvergrendeling nodig hebben voordat ze toegang kunnen krijgen tot accountgegevens.\\n\\nStel een wachtwoord-, PIN- of patroonvergrendelingsscherm in.</string>\n    <string name=\"credentials_assisted_confirmation_header\">Aanmelden</string>\n    <string name=\"credentials_assisted_continue_as_user_button_label\">Verdergaan als %1$s</string>\n    <string name=\"credentials_assisted_choose_account_subtitle\">om verder te gaan naar %1$s</string>\n    <string name=\"credentials_assisted_signin_button_text_long\">Aanmelden met Google</string>\n    <string name=\"pref_vending_asset_delivery_category\">Levering van Google Play-items</string>\n    <string name=\"pref_vending_asset_delivery_switch\">Levering op aanvraag mogelijk maken</string>\n    <string name=\"pref_vending_asset_delivery_summary\">Extra middelen downloaden als daarom wordt gevraagd door apps die Play Asset Delivery gebruiken</string>\n    <string name=\"credentials_assisted_signin_consent\">Als u doorgaat, deelt Google uw naam, e-mailadres en profielfoto met %1$s. Zie het privacybeleid en de servicevoorwaarden van %1$s.</string>\n    <string name=\"limited_services_dialog_information_ack\">Ik begrijp het</string>\n    <string name=\"pref_vending_asset_device_sync_switch\">Synchronisatie van apparaatinformatie inschakelen</string>\n    <string name=\"pref_vending_asset_device_sync_summary\">Toepassingen die gebruik maken van Play Asset Delivery downloaden extra middelen op basis van de informatie van het apparaat dat op dat moment in gebruik is.</string>\n    <string name=\"service_name_work_profile\">Werkprofiel</string>\n    <string name=\"camera_permission_dialog_title\">Toestemming camera vereist</string>\n    <string name=\"camera_permission_dialog_message\">microG services heeft toegang tot de camera van uw apparaat nodig om een code voor %1$s te scannen.\\n\\nOm dit in te schakelen, geeft u microG services toestemming om de camera te gebruiken in Instellingen.</string>\n    <string name=\"pref_vending_licensing_split_install_summary\">Apps toestaan om extra componenten te downloaden en te installeren</string>\n    <string name=\"pref_workprofile_intro\">Wanneer u een werkprofiel instelt voor uw werkplek of onderwijsinstelling, kan de setup proberen verbinding te maken met Google om het downloaden van apps naar dat profiel mogelijk te maken.</string>\n    <string name=\"pref_workprofile_create_account\">Instellen werkaccount toestaan</string>\n    <string name=\"pref_vending_split_install_switch\">On-demand installatie van componenten</string>\n    <string name=\"pref_workprofile_disclaimer\">Het is uw verantwoordelijkheid om ervoor te zorgen dat uw gebruik van microG in overeenstemming is met het bedrijfsbeleid. microG wordt geleverd op een ‘best effort’ basis en kan niet garanderen dat het zich precies gedraagt zoals verwacht.</string>\n    <string name=\"pref_auth_two_step_verification_summary\">Indien ingeschakeld, kan het apparaat verzoeken voor tweestapsverificatie van Google ontvangen (Cloud Messaging is vereist).</string>\n    <string name=\"service_name_device_attestation\">Apparaatcertificering</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-pl/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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  --><resources>\n    <string name=\"permission_service_all_label\">Wszystkie usługi Google</string>\n    <string name=\"permission_service_all_description\">Zezwala aplikacji na dostęp do wszystkich usług Google przez dowolne powiązane konto Google.</string>\n    <string name=\"permission_service_android_label\">Usługi Androida</string>\n    <string name=\"permission_service_android_description\">Zezwala aplikacji na dostęp do usług Androida przez dowolne powiązane konto Google.</string>\n    <string name=\"permission_service_adsense_label\">AdSense</string>\n    <string name=\"permission_service_adsense_description\">Zezwala aplikacji na dostęp do AdSense przez dowolne powiązane konto Google.</string>\n    <string name=\"permission_service_adwords_label\">AdWords</string>\n    <string name=\"permission_service_adwords_description\">Zezwala aplikacji na dostęp do AdWords przez dowolne powiązane konto Google.</string>\n    <string name=\"permission_service_ah_label\">Google App Engine</string>\n    <string name=\"permission_service_ah_description\">Zezwala aplikacji na dostęp do Google App Engine przez dowolne powiązane konto Google.</string>\n    <string name=\"permission_service_blogger_label\">Blogger</string>\n    <string name=\"permission_service_blogger_description\">Zezwala aplikacji na dostęp do Bloggera przez dowolne powiązane konto Google.</string>\n    <string name=\"permission_service_cl_label\">Kalendarz Google</string>\n    <string name=\"permission_service_cl_description\">Zezwala aplikacji na dostęp do Kalendarza Google przez dowolne powiązane konto Google.</string>\n    <string name=\"permission_service_cp_label\">Kontakty</string>\n    <string name=\"permission_service_cp_description\">Zezwala aplikacji na dostęp do Kontaktów przez dowolne powiązane konto Google.</string>\n    <string name=\"permission_service_dodgeball_label\">Dodgeball</string>\n    <string name=\"permission_service_dodgeball_description\">Zezwala aplikacji na dostęp do Dodgeballa przez dowolne powiązane konto Google.</string>\n    <string name=\"permission_service_finance_label\">Finanse Google</string>\n    <string name=\"permission_service_finance_description\">Zezwala aplikacji na dostęp do Finansów Google przez dowolne powiązane konto Google.</string>\n    <string name=\"permission_service_gbase_label\">Google Base</string>\n    <string name=\"permission_service_gbase_description\">Zezwala aplikacji na dostęp do Google Base przez dowolne powiązane konto Google.</string>\n    <string name=\"permission_service_grandcentral_label\">Google Voice</string>\n    <string name=\"permission_service_grandcentral_description\">Zezwala aplikacji na dostęp do Google Voice przez dowolne powiązane konto Google.</string>\n    <string name=\"permission_service_groups2_label\">Grupy dyskusyjne Google</string>\n    <string name=\"permission_service_groups2_description\">Zezwala aplikacji na dostęp do Grup dyskusyjnych Google przez dowolne powiązane konto Google.</string>\n    <string name=\"permission_service_health_label\">Google Health</string>\n    <string name=\"permission_service_health_description\">Zezwala aplikacji na dostęp do Google Health przez dowolne powiązane konto Google.</string>\n    <string name=\"permission_service_ig_label\">iGoogle</string>\n    <string name=\"permission_service_ig_description\">Zezwala aplikacji na dostęp do iGoogle przez dowolne powiązane konto Google.</string>\n    <string name=\"permission_service_jotspot_label\">JotSpot</string>\n    <string name=\"permission_service_jotspot_description\">Zezwala aplikacji na dostęp do JotSpota przez dowolne powiązane konto Google.</string>\n    <string name=\"permission_service_knol_label\">Knol</string>\n    <string name=\"permission_service_knol_description\">Zezwala aplikacji na dostęp do Knola przez dowolne powiązane konto Google.</string>\n    <string name=\"permission_service_lh2_label\">Picasa Web Albums</string>\n    <string name=\"permission_service_lh2_description\">Zezwala aplikacji na dostęp do Picasa Web Albums przez dowolne powiązane konto Google.</string>\n    <string name=\"permission_service_local_label\">Mapy Google</string>\n    <string name=\"permission_service_local_description\">Zezwala aplikacji na dostęp do Map Google przez dowolne powiązane konto Google.</string>\n    <string name=\"permission_service_mail_label\">Poczta Google</string>\n    <string name=\"permission_service_mail_description\">Zezwala aplikacji na dostęp do Poczty Google przez dowolne powiązane konto Google.</string>\n    <string name=\"permission_service_news_label\">Wiadomości Google</string>\n    <string name=\"permission_service_news_description\">Zezwala aplikacji na dostęp do Wiadomości Google przez dowolne powiązane konto Google.</string>\n    <string name=\"permission_service_notebook_label\">Notatnik Google</string>\n    <string name=\"permission_service_notebook_description\">Zezwala aplikacji na dostęp do Notatnika Google przez dowolne powiązane konto Google.</string>\n    <string name=\"permission_service_orkut_label\">Orkut</string>\n    <string name=\"permission_service_orkut_description\">Zezwala aplikacji na dostęp do Orkuta przez dowolne powiązane konto Google.</string>\n    <string name=\"permission_service_print_label\">Książki Google</string>\n    <string name=\"permission_service_print_description\">Zezwala aplikacji na dostęp do Książek Google przez dowolne powiązane konto Google.</string>\n    <string name=\"permission_service_sierra_label\">Konta Google Checkout</string>\n    <string name=\"permission_service_sierra_description\">Zezwala aplikacji na dostęp do kont Google Checkout przez dowolne powiązane konto Google.</string>\n    <string name=\"permission_service_sierraqa_label\">Konta Google Checkout QA</string>\n    <string name=\"permission_service_sierraqa_description\">Zezwala aplikacji na dostęp do kont Google Checkout QA przez dowolne powiązane konto Google.</string>\n    <string name=\"permission_service_sierrasandbox_label\">Konta Google Checkout Sandbox</string>\n    <string name=\"permission_service_sierrasandbox_description\">Zezwala aplikacji na dostęp do kont Google Checkout Sandbox przez dowolne powiązane konto Google.</string>\n    <string name=\"permission_service_sitemaps_label\">Narzędzia webmasterskie Google</string>\n    <string name=\"permission_service_sitemaps_description\">Zezwala aplikacji na dostęp do Narzędzi webmasterskich Google przez dowolne powiązane konto Google.</string>\n    <string name=\"permission_service_speech_label\">Wyszukiwanie głosowe</string>\n    <string name=\"permission_service_speech_description\">Zezwala aplikacji na dostęp do Wyszukiwania głosowego przez dowolne powiązane konto Google.</string>\n    <string name=\"permission_service_speechpersonalization_label\">Spersonalizowane rozpoznawanie mowy</string>\n    <string name=\"permission_service_speechpersonalization_description\">Zezwala aplikacji na dostęp do Spersonalizowanego rozpoznawania mowy przez dowolne powiązane konto Google.</string>\n    <string name=\"permission_service_talk_label\">Google Talk</string>\n    <string name=\"permission_service_talk_description\">Zezwala aplikacji na dostęp do Google Talk przez dowolne powiązane konto Google.</string>\n    <string name=\"permission_service_wifi_label\">Google Wi-Fi</string>\n    <string name=\"permission_service_wifi_description\">Zezwala aplikacji na dostęp do Google Wi-Fi przez dowolne powiązane konto Google.</string>\n    <string name=\"permission_service_wise_label\">Arkusze Google</string>\n    <string name=\"permission_service_wise_description\">Zezwala aplikacji na dostęp do Arkuszy Google przez dowolne powiązane konto Google.</string>\n    <string name=\"permission_service_writely_label\">Dokumenty Google</string>\n    <string name=\"permission_service_writely_description\">Zezwala aplikacji na dostęp do Dokumentów Google przez dowolne powiązane konto Google.</string>\n    <string name=\"permission_service_youtube_label\">YouTube</string>\n    <string name=\"permission_service_youtube_description\">Zezwala aplikacji na dostęp do YouTube przez dowolne powiązane konto Google.</string>\n    <string name=\"permission_service_YouTubeUser_label\">Nazwy użytkowników YouTube</string>\n    <string name=\"permission_service_YouTubeUser_description\">Zezwala aplikacji na dostęp do nazw użytkowników YouTube przez dowolne powiązane konto Google.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_activity\">Podgląd historii aktywności twoich aplikacji Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.buyer\">Zarządzanie twoim kontem kupującego Ad Exchange</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller.readonly\">Podgląd twoich danych Ad Exchange</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller\">Podgląd i zarządzanie twoimi danymi Ad Exchange</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsensehost\">Podgląd i zarządzanie twoimi danymi głównymi AdSense i powiązanymi kontami</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense.readonly\">Podgląd twoich danych AdSense</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense\">Podgląd i zarządzanie twoimi danymi AdSense</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics.readonly\">Podgląd twoich danych Google Analytics</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics\">Podgląd i zarządzanie twoimi danymi Google Analytics</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_androidpublisher\">Dostęp do Google Play Android Developer</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appengine.admin\">Zakres widoczności administratora silnika aplikacji.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.migration\">Dostęp odczytu i zapisu do Groups Migration API.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.settings\">Podgląd i zarządzanie ustawieniami Google Apps Group</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.licensing\">Dostęp do odczytu/zapisu do License Manager API.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order\">Dla administratorów resellerów i użytkowników dostęp do odczytu/zapisu podczas testowania w środowiskach testowych API lub dostęp do odczytu/zapisu podczas bezpośredniego wywoływania operacji API.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order.readonly\">W dodatku do ogólnego zasięgu widoczności odczytu/zapisu OAuth, użyj OAuth tylko do odczytu do odczytu danych klienta.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps_reporting_audit.readonly\">Dostęp do Admin Audit API Tylko do odczytu</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appstate\">Zakres widoczności dla użycia usługi App State.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery.readonly\">Podgląd twoich danych na Google BigQuery</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery\">Podgląd i zarządzanie twoimi danymi na Google BigQuery</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger\">Zarządzanie twoim kontem Blogger</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger.readonly\">Podgląd twojego konta Blogger</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_books\">Zarządzanie twoimi książkami</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar\">Zarządzanie twoimi kalendarzami</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar.readonly\">Podgląd twoich kalendarzy</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_cloudprint\">Podgląd i zarządzanie twoimi danymi drukowania w chmurze Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute.readonly\">Podgląd twoich zasobów Google Compute Engine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute\">Podgląd i zarządzanie twoich zasobów Google Compute Engine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate.readonly\">Podgląd twoich zadań Google Coordinate</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate\">Podgląd i zarządzanie twoimi zadaniami Google Maps Coordinate</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.full_control\">Zarządzanie twoimi danymi i uprawnieniami w Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_only\">Podgląd twoich danych w Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_write\">Zarządzanie twoimi danymi w Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_dfareporting\">Podgląd i zarządzanie raportami Podwójnego kliknięcia dla reklamodawców</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.appdata\">Pozwala na dostęp do katalogu danych aplikacji</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.apps.readonly\">Podgląd twoich aplikacji na Dysku Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.file\">Podgląd i zarządzanie plikami na Dysku Google, które zostały otwarte lub utworzone przy pomocy tej aplikacji</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.install\">Specjalny zakres widoczności pozwalający użytkownikom zaakceptować instalację aplikacji</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.metadata.readonly\">Podgląd metadanych plików i dokumentów na twoim Dysku Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.readonly\">Podgląd plików i dokumentów na twoim Dysku Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.scripts\">Modyfikacja zachowań twoich skryptów Google Apps Script</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive\">Podgląd i zarządzanie plikami i dokumentami na twoim Dysku Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase.readonly\">Podgląd twojego konta Freebase</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase\">Zalogowanie się do Freebase przy użyciu twojego konta</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables\">Zarządzanie twoimi Fusion Tables</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables.readonly\">Podgląd twoich Fusion Tables</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_games\">Zakres widoczności dostępu danych z Gier Google Play.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan\">Zarządzanie twoimi danymi GAN</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan.readonly\">Podgląd twoich danych GAN</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gcm_for_chrome\">CloudMessaging dla Chrome</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_glass.timeline\">Zakres czasowy widoczności Glass</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.compose\">Tworzenie, odczytywanie, aktualizowanie i usuwanie wersji roboczych. Wysyłanie wiadomości i wersji roboczych.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.modify\">Wszystkie operacje odczytu/zapisu z wyjątkiem natychmiastowego usuwania tematów i wiadomości z pominięciem kosza.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.readonly\">Czytanie wszystkich zasobów i ich metadanych, bez operacji zapisu.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.best\">Zarządzanie woją szczegółową lokalizacją i historią lokalizacji</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.city\">Zarządzanie twoją przybliżoną (miasto) lokalizacją i historią lokalizacji</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.best\">Zarządzanie twoją szczegółową lokalizacją</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.city\">Zarządzanie twoją przybliżoną (miasto) lokalizacją</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine\">Podgląd i zarządzanie twoimi danymi Google Maps Engine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine.readonly\">Podgląd twoich danych Google Maps Engine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mobilemaps.firstparty\">Podgląd i zarządzanie twoimi Mapami Google na telefonie</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut\">Zarządzaj twoją aktywnością Orkut</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut.readonly\">Podgląd twoich danych Orkut</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.login\">Pozna twoje imię, podstawowe informacje i listę ludzi z którymi jesteś połączony na Google+</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.me\">Pozna kim jesteś na Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_prediction\">Zarządzanie twoimi danymi na Google Prediction API</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_shoppingapi\">Zarządzanie twoimi danymi produktu</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification\">Zarządzanie listą swoich stron i domen</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification.verify_only\">Zarządzanie twoimi nowymi weryfikacjami stron na Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_structuredcontent\">Dostęp odczytu/zapisu do Shopping Content API.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue.consumer\">Wypełnianie zadań na twoim Taskqueues</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue\">Zarządzanie twoimi zadaniami</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks\">Zarządzanie twoimi zadaniami</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks.readonly\">Podgląd twoich zadań</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tracks\">Google Maps Tracks API, ten zakres widoczności pozwala na odczyt i zapis do danych twoich projektów.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_urlshortener\">Zarządzanie twoimi skróconymi odnośnikami goo.gl</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.email\">Podgląd twojego adresu poczty e-mail</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.profile\">Podgląd podstawowych informacji odnośnie twojego konta</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube\">Zarządzanie twoim kontem YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtubepartner\">Podgląd i zarządzanie twoimi zasobami i powiązaną treścią na YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.readonly\">Podgląd twojego konta YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.upload\">Zarządzanie twoimi wideo na YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics_monetary.readonly\">Podgląd raportów finansowych na YouTube Analytics odnośnie twoich wideo</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics.readonly\">Podgląd raportów YouTube Analytics dla twoich wideo</string>\n    <string name=\"perm_activity_recognition_label\">Rozpoznawanie aktywności</string>\n    <string name=\"perm_activity_recognition_description\">Umożliwia aplikacji otrzymywanie od Google okresowych aktualizacji poziomu aktywności użytkownika, na przykład w przypadku chodzenia, jazdy samochodem, jazdy na rowerze lub bezruchu.</string>\n</resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-pl/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2017 microG Project Team\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<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <plurals name=\"pref_unifiednlp_summary\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> usługa skonfigurowana</item>\n        <item quantity=\"few\"><xliff:g example=\"3\">%1$d</xliff:g> usługi skonfigurowane</item>\n        <item quantity=\"many\"><xliff:g example=\"3\">%1$d</xliff:g> usług skonfigurowanych</item>\n        <item quantity=\"other\"><xliff:g example=\"3\">%1$d</xliff:g> usług skonfigurowanych</item>\n    </plurals>\n    <plurals name=\"gcm_registered_apps_counter\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> zarejestrowana aplikacja</item>\n        <item quantity=\"few\"><xliff:g example=\"123\">%1$d</xliff:g> zarejestrowane aplikacje</item>\n        <item quantity=\"many\"><xliff:g example=\"123\">%1$d</xliff:g> zarejestrowanych aplikacji</item>\n        <item quantity=\"other\"><xliff:g example=\"123\">%1$d</xliff:g> zarejestrowanych aplikacji</item>\n    </plurals>\n    <plurals name=\"cond_perm_summary\">\n        <item quantity=\"one\">Nie udzielono uprawnienia wymaganego do prawidłowego działania usługi microG.</item>\n        <item quantity=\"few\">Nie udzielono uprawnień wymaganych do prawidłowego działania usługi microG.</item>\n        <item quantity=\"many\">Nie udzielono uprawnień wymaganych do prawidłowego działania usługi microG.</item>\n        <item quantity=\"other\">Nie udzielono uprawnień wymaganych do prawidłowego działania usługi microG.</item>\n    </plurals>\n    <plurals name=\"cond_perm_action\">\n        <item quantity=\"one\">Brakuje wymaganego uprawnienia</item>\n        <item quantity=\"few\">Brakuje wymaganych uprawnień</item>\n        <item quantity=\"many\">Brakuje wymaganych uprawnień</item>\n        <item quantity=\"other\">Brakuje wymaganych uprawnień</item>\n    </plurals>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-pl/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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  --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"gms_app_name\">Usługi microG</string>\n    <string name=\"gms_settings_name\">Ustawienia microG</string>\n    <string name=\"just_a_sec\">Chwileczkę…</string>\n    <string name=\"google_account_label\">Google</string>\n    <string name=\"ask_permission_tos\">Kontynuując, zgadzasz się na wykorzystywanie swoich danych przez Google i usługi microG zgodnie z warunkami korzystania oraz polityką prywatności Google.</string>\n    <string name=\"ask_scope_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> chce:</string>\n    <string name=\"ask_service_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> chce wykorzystać:</string>\n    <string name=\"account_manager_title\">Zarządzanie kontem Google</string>\n    <string name=\"sorry\">Przepraszamy…</string>\n    <string name=\"no_network_error_desc\">Brak połączenia sieciowego.\n\\n\n\\nTo może być chwilowy problem lub Twoje urządzenie z systemem Android może nie być przystosowane do usług danych mobilnych. Połącz się z Wi-Fi lub danymi mobilnymi i spróbuj ponownie.</string>\n    <string name=\"auth_general_error_desc\">\"Wystąpił błąd podczas łączenia z serwerami Google.\n\nSpróbuj ponownie później.\"</string>\n    <string name=\"auth_finalize\">Twoje urządzenie łączy się z Google, aby zapisać informacje o koncie.\n\\n\n\\nMoże to zająć kilka minut.</string>\n    <string name=\"allow\">Zezwól</string>\n    <string name=\"deny\">Odrzuć</string>\n    <string name=\"auth_notification_title\">Wymagane uwierzytelnienie</string>\n    <string name=\"auth_notification_content\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> wymaga Twojej autoryzacji, aby skorzystać z konta Google.</string>\n    <string name=\"perm_status_broadcast_label\">sprawdzaj wewnętrzne powiadomienia stanu</string>\n    <string name=\"perm_c2dm_receive_label\">sprawdzaj wiadomości C2DM</string>\n    <string name=\"perm_c2dm_send_label\">wysyłaj wiadomości C2DM do innych aplikacji</string>\n    <string name=\"perm_gtalk_svc_label\">wymieniaj wiadomości i odbieraj powiadomienia synchronizacji z serwerów Google</string>\n    <string name=\"perm_extended_access_label\">Rozszerzony dostęp do usług Google</string>\n    <string name=\"service_name_checkin\">Rejestracja urządzenia Google</string>\n    <string name=\"service_name_mcs\">Cloud Messaging</string>\n    <string name=\"service_name_snet\">Google SafetyNet</string>\n    <string name=\"games_title\">Gry Google Play</string>\n    <string name=\"games_info_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> chce wykorzystać Gry Google Play</string>\n    <string name=\"games_info_content\">Aby korzystać z gier Google Play wymagana jest instalacja aplikacji Gry Google Play . Aplikacja może dalej działać bez Gry Google Play, ale możliwe, że nie będzie działać prawidłowo.</string>\n    <string name=\"pick_place_title\">Wybierz miejsce</string>\n    <string name=\"pick_place_desc\">Opcja wyboru miejsca nie jest jeszcze dostępna.</string>\n    <string name=\"place_picker_select_title\">Wybierz tę lokalizację</string>\n    <string name=\"place_picker_nearby_places\">Pobliskie miejsca</string>\n    <string name=\"place_picker_location_lat_lng\">(%1$.7f, %2$.7f)</string>\n    <string name=\"lacking_permission_toast\">usługi microG: Brakuje pozwolenia na <xliff:g example=\"have full network acccess\">%1$s</xliff:g></string>\n    <string name=\"network_type_mobile\">Sieć komórkowa</string>\n    <string name=\"network_type_wifi\">Wi-Fi</string>\n    <string name=\"network_type_roaming\">Roaming</string>\n    <string name=\"network_type_other\">Inne sieci</string>\n    <!-- Self check -->\n    <string name=\"self_check_cat_fake_sig\">Wsparcie dla imitacji sygnatur</string>\n    <string name=\"self_check_cat_gms_packages\">Zainstalowane paczki</string>\n    <string name=\"self_check_cat_system\">System</string>\n    <string name=\"self_check_name_fake_sig_perm\">System wspiera imitowanie sygnatur:</string>\n    <string name=\"self_check_resolution_fake_sig_perm\">Twój ROM nie posiada wbudowanego wsparcia dla imitacji sygnatur. Możesz jednak nadal spróbować użyć modułu Xposed (FakeGApps) lub innych systemów aby imitować sygnatury. Przejrzyj dokumentację dot. ROM-ów wspierających imitowanie sygnatur i sprawdź jak korzystać z usług microG na systemach tego nie wspierających.</string>\n    <string name=\"self_check_name_perm_granted\">System udziela pozwolenia na imitację sygnatur:</string>\n    <string name=\"self_check_resolution_perm_granted\">Możliwe, że Twój ROM wspiera imitowanie sygnatur, ale wymagane są dalsze działania, aby to włączyć. Przejrzyj dokumentacje, aby sprawdzić dalsze instrukcje.</string>\n    <string name=\"self_check_name_system_spoofs\">System imituje sygnatury:</string>\n    <string name=\"self_check_resolution_system_spoofs\">Przejrzyj dokumentację i sprawdź dalsze instrukcje.</string>\n    <string name=\"self_check_pkg_gms\">Usługi microG</string>\n    <string name=\"self_check_pkg_vending\">microG Companion / Sklep Play</string>\n    <string name=\"self_check_pkg_gsf\">microG Services Framework</string>\n    <string name=\"self_check_name_app_installed\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> zainstalowany: </string>\n    <string name=\"self_check_resolution_app_installed\">Zainstaluj aplikację <xliff:g example=\"F-Droid\">%1$s</xliff:g> lub kompatybilną. Przejrzyj dokumentację i sprawdź, które aplikacje są kompatybilne.</string>\n    <string name=\"self_check_name_correct_sig\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> posiada prawidłową sygnaturę: </string>\n    <string name=\"self_check_resolution_correct_sig\">Albo zainstalowany <xliff:g example=\"F-Droid\">%1$s</xliff:g> nie jest kompatybilny, albo imitacja sygnatur nie jest dla niego aktywna. Przejrzyj dokumentacje, aby sprawdzić, które aplikacje i ROM-y są kompatybilne.</string>\n    <string name=\"self_check_name_battery_optimizations\">Ignorowanie optymalizacji baterii:</string>\n    <string name=\"self_check_resolution_battery_optimizations\">Dotknji, aby wyłączyć optymalizację baterii. W przeciwnym razie aplikacje mogą nie działać prawidłowo.</string>\n    <!-- Settings strings -->\n    <string name=\"prefcat_about\">O programie</string>\n    <string name=\"prefcat_components\">Komponenty</string>\n    <string name=\"prefcat_configuration\">Konfiguracja</string>\n    <string name=\"prefcat_google_services\">Usługi Google</string>\n    <string name=\"prefcat_location_service\">Usługa lokalizacji</string>\n    <string name=\"prefcat_services\">Usługi w tle</string>\n    <string name=\"prefcat_test\">Test</string>\n    <string name=\"cond_gcm_bat_title\">Optymalizacja baterii włączona</string>\n    <string name=\"cond_gcm_bat_summary\">Aktywowano usługę Cloud Messaging, ale optymalizacja baterii dla usługi microG jest włączona. Aby powiadomienia ‘push’ działały, należy wyłączyć optymalizację baterii dla microG.</string>\n    <string name=\"cond_gcm_bat_action\">Ignoruj optymalizacje</string>\n    <string name=\"cond_perm_title\">Brakuje uprawnień</string>\n    <string name=\"prefs_account\">Ustawienia konta</string>\n    <string name=\"prefs_account_privacy\">Ustawienia osobiste i prywatność</string>\n    <string name=\"prefs_account_security\">Logowanie i bezpieczeństwo</string>\n    <string name=\"pref_auth_trust_google_title\">Zaufaj uprawnieniom aplikacji Google</string>\n    <string name=\"pref_auth_trust_google_summary\">Po wyłączeniu, do użytkownika kierowane jest pytanie przed wysyłaniem prośby o autoryzację do Google. Niektóre aplikacje nie będą mogły skorzystać z konta Google po wyłączeniu tej opcji.</string>\n    <string name=\"pref_checkin_enable_summary\">Rejestracja urządzenia to ukryty proces, służący do wygenerowania unikalnego identyfikatora dla usług Google. Usługi microG usuwają inne dane identyfikacyjne niż nazwa Twojego konta z tego identyfikatora.</string>\n    <string name=\"pref_more_settings\">Więcej</string>\n    <string name=\"pref_gcm_enable_mcs_summary\">Cloud Messaging jest systemem zapewniającym powiadomienia dla wielu aplikacji. Musisz włączyć rejestrowanie urządzenia, aby z niego korzystać.</string>\n    <string name=\"pref_gcm_heartbeat_title\">Częstotliwość sprawdzania Cloud Messaging</string>\n    <string name=\"pref_gcm_heartbeat_summary\">Częstotliwość (w sekundach) do sprawdzania serwerów Google. Zwiększenie tej wartości zmniejszy zużycie baterii, ale może spowodować opóźnienia w dostarczaniu powiadomień ‘push’.\\nPrzestarzałe, zostanie to usunięte w nowszej wersji.</string>\n    <string name=\"pref_gcm_apps_title\">Aplikacje korzystające z Cloud Messaging</string>\n    <string name=\"pref_gcm_apps_summary\">Lista aplikacji obecnie zarejestrowanych w usłudze Cloud Messaging.</string>\n    <string name=\"pref_gcm_confirm_new_apps_title\">Potwierdź nowe aplikacje</string>\n    <string name=\"pref_gcm_confirm_new_apps_summary\">Zapytaj przed zarejestrowaniem nowej aplikacji w usłudze powiadomień ‘push’</string>\n    <string name=\"pref_gcm_ping_interval\">Częstotliwość sprawdzania: <xliff:g example=\"10 minutes\">%1$s</xliff:g></string>\n    <string name=\"pref_about_title\">O usłudze microG</string>\n    <string name=\"pref_about_summary\">Informacje o wersji, użyte licencje i biblioteki</string>\n    <string name=\"gcm_app_error_unregistering\">Błąd wyrejestrowania</string>\n    <string name=\"gcm_app_not_installed_anymore\">Już odinstalowano</string>\n    <string name=\"gcm_unregister_app\">Wyrejestruj</string>\n    <string name=\"gcm_not_registered\">Nie zarejestrowano</string>\n    <string name=\"gcm_no_message_yet\">Jak dotąd nie otrzymano wiadomości</string>\n    <string name=\"gcm_last_message_at\">Ostatnia wiadomość: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_registered\">Zarejestrowano</string>\n    <string name=\"gcm_registered_since\">Zarejestrowano od: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_unregister_confirm_title\">Czy wyrejestrować <xliff:g example=\"F-Droid\">%1$s</xliff:g>?</string>\n    <string name=\"gcm_unregister_confirm_message\">Niektóre aplikacje nie rejestrują się automatycznie ponownie lub nie posiadają opcji do zrobienia tego ręcznie. Takie aplikacje po wyrejestrowaniu mogą nie działać prawidłowo.\\nCzy chcesz kontynuować?</string>\n    <string name=\"gcm_unregister_after_deny_message\">Odmówiono już zarejestrowanej aplikacji zarejestrować się w usłudze powiadomień ‘push’.\n\\nCzy chcesz ją wyrejestrować, aby nie otrzymywała powiadomień ‘push’ w przyszłości?</string>\n    <string name=\"gcm_messages_counter\">Wiadomości: <xliff:g example=\"123\">%1$d</xliff:g> (<xliff:g example=\"12345\">%2$d</xliff:g> bajtów)</string>\n    <string name=\"safetynet_intro\">Google SafetyNet jest systemem certyfikacji urządzenia, który upewnia się czy urządzenie jest poprawnie zabezpieczone i kompatybilne z Android CTS. Niektóre aplikacje używają SafetyNet ze względów bezpieczeństwa lub jako przeciwśrodek do modyfikacji.\\n\\nUsługa microG GmsCore zawiera wolną implementację SafetyNet, ale oficjalny serwer wymaga by SafetyNet był podpisany przez własnościowy system DroidGuard.</string>\n    <string name=\"pref_safetynet_test_title\">Wypróbuj działanie SafetyNet</string>\n    <string name=\"pref_droidguard_operation_mode\">Tryb działania</string>\n    <string name=\"pref_device_registration_import_custom_profile_title\">Importuj własny profil</string>\n    <string name=\"pref_safetynet_recent_request_type\">Typ żądania</string>\n    <string name=\"pref_recaptcha_enterprise_test_title\">Sprawdź usługę ReCAPTCHA Enterprise</string>\n    <string name=\"checkin_last_registration\">Ostatnia rejestracja: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"signin_subtext_policy_privacy\">politykę prywatności</string>\n    <string name=\"pref_safetynet_test_no_result\">Brak wyniku</string>\n    <string name=\"perm_gsf_read_gservices_label\">odczytuj ustawienia usług Google</string>\n    <string name=\"auth_sign_in\">Zaloguj</string>\n    <string name=\"pref_device_registration_import_custom_profile_summary\">Importuj profil urządzenia z pliku</string>\n    <string name=\"pref_safetynet_recent_copy_json\">Kopiuj dane JSON JWS</string>\n    <string name=\"pref_test_summary_failed\">Niepowodzenie: %s</string>\n    <string name=\"pref_auth_visible_summary\">Gdy włączone, wszystkie aplikacje na tym urządzeniu będą w stanie wyświetlić adres e-mail Twoich kont Google bez jakiejkolwiek autoryzacji.</string>\n    <string name=\"pref_safetynet_recent_advice\">Rada</string>\n    <string name=\"push_notifications_summary_values_seconds\">%s sekund</string>\n    <string name=\"pref_safetynet_test_invalid_json\">Nieprawidłowy format JSON</string>\n    <string name=\"menu_clear_recent_requests\">Wyczyść historię żądań</string>\n    <string name=\"signin_picker_title\">Wybierz konto,</string>\n    <string name=\"pref_safetynet_recent_recaptcha_enterprise_summary\">ReCaptcha Enterprise: %s</string>\n    <string name=\"pref_safetynet_recent_cat_request\">Dane żądania</string>\n    <string name=\"pref_push_app_wake_for_delivery_summary\">Uruchamia w tle aplikację, aby mogła ona odebrać przychodzące komunikaty ‘push‘.</string>\n    <string name=\"pref_safetynet_recent_attestation_summary\">Weryfikacja: %s</string>\n    <string name=\"prefcat_safetynet_apps_title\">Aplikacje korzystające z SafetyNet</string>\n    <string name=\"safetynet_enable_switch\">Zezwól na walidację urządzenia</string>\n    <string name=\"pref_safetynet_test_integrity_failed\">Problem z spójnością systemu</string>\n    <string name=\"push_notifications_summary_automatic\">Włączaj / Automatycznie: co %s</string>\n    <string name=\"pref_device_registration_serial_title\">Klucz seryjny</string>\n    <string name=\"checkin_enable_switch\">Zarejestruj urządzenie</string>\n    <string name=\"pref_safetynet_test_cts_failed\">Niepowodzenie profilu CTS</string>\n    <string name=\"push_notifications_summary_manual\">Włączaj / Ręcznie: co %s</string>\n    <string name=\"profile_name_auto\">Automatyczny: %s</string>\n    <string name=\"push_notifications_summary_values_minutes\">%s minut</string>\n    <string name=\"perm_provision_label\">dostarczanie usług microG</string>\n    <string name=\"gcm_network_state_connected\">Połączono od <xliff:g example=\"2 hours ago\">%1$s</xliff:g></string>\n    <string name=\"pref_auth_include_android_id_summary\">Gdy wyłączone, żądania uwierzytelnienia nie będą zależne od rejestracji urządzenia, co może zezwolić nieuwierzytelnionym urządzeniom na zalogowanie się, lecz może spowodować nieprzewidziane skutki.</string>\n    <string name=\"signin_picker_subtitle\">aby przejść dalej do aplikacji <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"pref_safetynet_test_integrity_cts_passed\">Spójność i CTS prawidłowe</string>\n    <string name=\"pref_safetynet_recent_uses\">Ostatnie żądania</string>\n    <string name=\"pref_droidguard_unsupported_summary\">Wykonywanie DroidGuard jest niewspierane na tym urządzeniu. Usługi SafetyNet mogą działać nieprawidłowo.</string>\n    <string name=\"signin_confirm_title\">Zezwól na zalogowanie się do <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"pref_safetynet_recent_nonce\">Nonce (Szestn.)</string>\n    <string name=\"safetynet_last_run_at\">Ostatnie użycie: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"pref_push_app_wake_for_delivery_title\">Uruchamiaj aplikację po otrzymaniu komunikatu ‘push‘</string>\n    <string name=\"perm_provision_description\">Zezwala aplikacji na konfigurację usług microG bez interakcji użytkownika</string>\n    <string name=\"pref_safetynet_recent_recaptcha_summary\">ReCaptcha: %s</string>\n    <string name=\"gcm_enable_switch\">Otrzymuj powiadomienia ‘push‘</string>\n    <string name=\"pref_test_summary_passed\">Wszystkie testy zakończone powodzeniem</string>\n    <string name=\"push_notifications_summary_off\">Wyłączono</string>\n    <string name=\"pref_info_status\">Stan</string>\n    <string name=\"gcm_allow_app_popup\">Zezwolić aplikacji <xliff:g example=\"F-Droid\">%1$s</xliff:g> na rejestrację w usłudze powiadomień ‘push‘?</string>\n    <string name=\"pref_safetynet_recent_response_status\">Status odpowiedzi</string>\n    <string name=\"pref_auth_visible_title\">Pozwól aplikacjom na znalezienie kont</string>\n    <string name=\"pref_device_registration_android_id\">ID Androida</string>\n    <string name=\"gcm_network_state_disconnected\">Odłączono</string>\n    <string name=\"signin_picker_add_account_label\">Dodaj inne konto</string>\n    <string name=\"pref_device_registration_select_profile_title\">Wybierz profil</string>\n    <string name=\"auth_connecting\">Twoje urządzenie nawiązuje teraz połączenie z serwerami Google, aby dokonać logowania.\n\\n\n\\nMoże to potrwać kilka sekund.</string>\n    <string name=\"signin_confirm_button_text\">Zezwól i udostępnij</string>\n    <string name=\"pref_test_summary_warn\">Ostrzeżenie: %s</string>\n    <string name=\"checkin_not_registered\">Nie zarejestrowano</string>\n    <string name=\"profile_name_real\">Rzeczywisty</string>\n    <string name=\"prefcat_push_apps_unregistered_title\">Aplikacje wyrejestrowane</string>\n    <string name=\"pref_add_account_title\">Konto</string>\n    <string name=\"signin_subtext_policy\">Przed korzystaniem z tej aplikacji, sprawdź jej %1$s i %2$s.</string>\n    <string name=\"pref_safetynet_recent_copied\">Skopiowano do schowka!</string>\n    <string name=\"prefcat_push_apps_title\">Aplikacje korzystające z powiadomień ‘push‘</string>\n    <string name=\"profile_name_user\">Własny: %s</string>\n    <string name=\"auth_before_connect\">Aplikacja na twoim urządzeniu próbuje zalogować się na konto Google.\\n\\nJeśli było to zamierzone, użyj przycisku <b>Zaloguj</b>, aby połączyć się ze stroną logowania Google, w przeciwnym wypadku, użyj przycisku <b>Anuluj</b>, aby wrócić z powrotem do aplikacji, która spowodowała wyświetlenie tego okna dialogowego.</string>\n    <string name=\"pref_recaptcha_test_title\">Sprawdź usługę ReCAPTCHA</string>\n    <string name=\"signin_subtext_sharing\">Aby kontynuować, microG udostępni aplikacji <xliff:g example=\"F-Droid\">%1$s</xliff:g> nazwę, adres e-mail i zdjęcie profilowe twojego konta Google.</string>\n    <string name=\"pref_auth_include_android_id_title\">Uwierzytelniaj za pomocą rejestracji urządzenia</string>\n    <string name=\"pref_push_app_allow_register_title\">Zezwalaj na rejestrację</string>\n    <string name=\"profile_name_native\">Natywny</string>\n    <string name=\"pref_test_summary_running\">Uruchamianie…</string>\n    <string name=\"pref_safetynet_recent_cat_basic\">Dane podstawowe</string>\n    <string name=\"gms_settings_summary\">Skonfiguruj usługi microG.</string>\n    <string name=\"pref_add_account_summary\">Dodaj konto Google</string>\n    <string name=\"profile_name_system\">Systemowy: %s</string>\n    <string name=\"pref_safetynet_recent_cat_response\">Dane odpowiedzi</string>\n    <string name=\"pref_push_app_allow_register_summary\">Zezwalaj aplikacji na rejestrację dla powiadomień ‘push‘.</string>\n    <string name=\"pref_safetynet_recent_token\">Token</string>\n    <string name=\"pref_safetynet_test_not_completed\">Jeszcze nie ukończono</string>\n    <string name=\"pref_safetynet_recent_request_time\">Czas żądania</string>\n    <string name=\"signin_subtext_policy_terms\">warunki korzystania z usługi</string>\n    <string name=\"prefcat_push_apps_registered_title\">Aplikacje zarejestrowane</string>\n    <string name=\"pref_device_registration_device_profile_category\">Profil urządzenia</string>\n    <string name=\"prefcat_push_networks_title\">Sieci z powiadomieniami ‘push‘</string>\n    <string name=\"pref_safetynet_recent_eval_type\">Typ sprawdzania</string>\n    <string name=\"perm_car_speed_label\">Prędkość samochodu</string>\n    <string name=\"perm_car_info_label\">Informacje o samochodzie</string>\n    <string name=\"perm_car_speed_description\">Uzyskaj dostęp do prędkości samochodu</string>\n    <string name=\"perm_car_info_description\">Uzyskaj dostęp do informacji o samochodzie</string>\n    <string name=\"perm_car_fuel_label\">Poziom paliwa samochodu</string>\n    <string name=\"perm_car_fuel_description\">Uzyskaj dostęp do poziomu paliwa samochodu</string>\n    <string name=\"perm_car_mileage_label\">Przebieg samochodu</string>\n    <string name=\"perm_car_mileage_description\">Uzyskaj dostęp do przebiegu samochodu</string>\n    <string name=\"perm_car_vendor_extension_label\">Kanał dostawcy samochodu</string>\n    <string name=\"perm_car_vendor_extension_description\">Uzyskaj dostęp do kanału dostawcy samochodu w celu wymiany informacji dotyczących samochodu</string>\n    <string name=\"pref_auth_strip_device_name_summary\">Po włączeniu tej opcji żądania uwierzytelnienia nie będą zawierać nazwy urządzenia, co może umożliwić logowanie się nieautoryzowanym urządzeniom, ale może mieć nieprzewidziane konsekwencje.</string>\n    <string name=\"pref_accounts_summary\">Dodawanie i zarządzanie kontami Google</string>\n    <string name=\"prefcat_accounts_settings_title\">Ustawienia</string>\n    <string name=\"feedback_disabled\">Informacje zwrotne nie są obecnie możliwe</string>\n    <string name=\"backup_disabled\">Tworzenie kopii zapasowych nie jest obecnie możliwe</string>\n    <string name=\"pref_auth_strip_device_name_title\">Usuwanie nazwy urządzenia przy uwierzytelnianiu</string>\n    <string name=\"pref_accounts_title\">Konta Google</string>\n    <string name=\"prefcat_accounts_current_accounts_title\">Konta</string>\n    <string name=\"service_name_vending\">Usługi Sklepu Play</string>\n    <string name=\"pref_vending_license_enable_summary\">Niektóre aplikacje wymagają weryfikacji, czy zostały zakupione w Sklepie Google Play. Na żądanie aplikacji, microG może pobrać dowód zakupu z Google. Jeśli funkcja ta jest wyłączona lub nie dodano konta Google, żądania weryfikacji licencji są ignorowane.</string>\n    <string name=\"pref_vending_summary_licensing_on\">Licencjonowanie włączone</string>\n    <string name=\"pref_vending_licensing_category\">Licencjonowanie Google Play</string>\n    <string name=\"pref_vending_licensing_enable_switch\">Odpowiadanie na prośby o weryfikację licencji</string>\n    <string name=\"pref_vending_summary_licensing_off\">Licencjonowanie wyłączone</string>\n    <string name=\"pref_vending_billing_enable_switch\">Obsługa zleceń rozliczeniowych</string>\n    <string name=\"pref_vending_billing_category\">Rozliczenia Google Play</string>\n    <string name=\"pref_vending_billing_enable_summary\">Po włączeniu niektóre aplikacje mogą dokonywać zakupów lub uruchamiać subskrypcje za pośrednictwem usługi Google Play Billing.</string>\n    <string name=\"pref_vending_billing_note_experimental\">Ta funkcja jest eksperymentalna i może prowadzić do utraty pieniędzy. Zostałeś ostrzeżony.</string>\n    <string name=\"pref_vending_billing_note_licensing\">Niektóre aplikacje mogą wymagać włączenia weryfikacji licencji w celu weryfikacji zakupów.</string>\n    <string name=\"credentials_assisted_cancel\">Anuluj</string>\n    <string name=\"credentials_assisted_continue\">Kontynuuj</string>\n    <string name=\"credentials_assisted_confirmation_header\">Logowanie</string>\n    <string name=\"credentials_assisted_continue_as_user_button_label\">Kontynuuj jako %1$s</string>\n    <string name=\"credentials_assisted_sign_back_title\">Zaloguj się ponownie do %1$s za pomocą Google</string>\n    <string name=\"credentials_assisted_signin_consent_header\">Podpisywanie jako %1$s</string>\n    <string name=\"credentials_assisted_signin_description\">Możesz zarządzać logowaniem za pomocą Google na swoich kontach Google.</string>\n    <string name=\"credentials_assisted_choose_account_label\">Wybierz konto</string>\n    <string name=\"credentials_assisted_choose_account_subtitle\">aby kontynuować do %1$s</string>\n    <string name=\"credentials_assisted_signin_button_text_long\">Zaloguj się przy użyciu Google</string>\n    <string name=\"credentials_assisted_signin_consent\">Kontynuując, Google udostępni twoje imię i nazwisko, adres e-mail i zdjęcie profilowe %1$s. Zobacz politykę prywatności i warunki korzystania z usługi %1$s.</string>\n    <string name=\"auth_package_override_request_title\">Zezwolić <b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> na uprzywilejowany dostęp do<xliff:g example=\"account@example.com\">%2$s</xliff:g>\\?</string>\n    <string name=\"auth_package_override_request_message\"><b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> chce uzyskać dostęp do konta tak, jakby było <b><xliff:g example=\"F-Droid\">%2$s</xliff:g> autorstwa <xliff:g example=\"F-Droid Inc.\">%3$s</xliff:g></b>. Może to zapewnić mu uprzywilejowany dostęp do konta użytkownika.</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_switch\">Automatycznie dodawaj bezpłatne aplikacje do biblioteki</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_summary\">Darmowe aplikacje mogą sprawdzać, czy zostały pobrane ze Sklepu Google Play. Automatycznie dodawaj darmowe aplikacje do biblioteki konta, aby zawsze sprawdzać wszystkie aktualnie dostępne darmowe aplikacje.</string>\n    <string name=\"limited_services_app_name\">Ograniczone usługi microG</string>\n    <string name=\"limited_services_dialog_information_ack\">Rozumiem</string>\n    <string name=\"limited_services_dialog_information\">Korzystasz z ograniczonych usług microG. W przeciwieństwie do zwykłych usług microG, ten wariant działa tylko z aplikacjami korzystającymi z bibliotek microG, a nie z tych w Google Play. Oznacza to, że większość aplikacji zignoruje te usługi.</string>\n    <string name=\"auth_action_step_enable_checkin\">Włącz rejestrację urządzenia</string>\n    <string name=\"auth_action_step_allow_microg_gcm\">Zezwalaj na Cloud Messaging dla microG</string>\n    <string name=\"auth_action_step_enable_lockscreen\">Skonfiguruj bezpieczną blokadę ekranu</string>\n    <string name=\"auth_action_notification_channel_name\">Alerty dotyczące konta Google</string>\n    <string name=\"auth_action_step_allow_microg_gcm_description\">Zgodnie z twoimi preferencjami, microG potrzebuje twojej zgody, zanim będzie mogło zarejestrować się w usłudze Cloud Messaging.</string>\n    <string name=\"auth_action_activity_header\">Zakończ konfigurację konta Google</string>\n    <string name=\"auth_action_notification_channel_description\">Powiadamia, gdy jedno z kont Google wymaga dodatkowej konfiguracji przed użyciem lub gdy konto jest niekompatybilne z microG.</string>\n    <string name=\"auth_action_notification_title\">Wymagane działanie na koncie</string>\n    <string name=\"auth_action_notification_content\">Konto Google wymaga dodatkowej konfiguracji.</string>\n    <string name=\"auth_action_activity_explanation\">Wykonaj następujące kroki, aby móc korzystać z konta Google %s na tym urządzeniu.</string>\n    <string name=\"auth_action_step_enable_gcm_description\">Cloud Messaging możesz wyłączyć po zakończeniu konfiguracji konta.</string>\n    <string name=\"auth_action_step_enable_checkin_description\">Urządzenie musi zarejestrować się w Google przynajmniej raz.\\n\\nRejestrację urządzenia Google można wyłączyć po zakończeniu konfiguracji konta.</string>\n    <string name=\"auth_action_step_enable_gcm\">Włącz Cloud Messaging</string>\n    <string name=\"auth_action_step_enable_lockscreen_description\">Twoje konto Google jest zarządzane przez twoje miejsce pracy lub instytucję edukacyjną. Administrator zdecydował, że urządzenia wymagają bezpiecznej blokady ekranu przed uzyskaniem dostępu do danych konta.\\n\\nUstaw hasło, kod PIN lub wzór blokady ekranu.</string>\n    <string name=\"auth_action_step_perform_content_description\">Dotknij, aby wykonać etap</string>\n    <string name=\"auth_action_step_completed_content_description\">Etap zakończony</string>\n    <string name=\"auth_action_activity_finish\">Zakończ</string>\n    <string name=\"pref_vending_asset_delivery_switch\">Włącz dostarczanie zasobów na żądanie</string>\n    <string name=\"pref_vending_asset_delivery_category\">Google Play Asset Delivery</string>\n    <string name=\"pref_vending_asset_delivery_summary\">Pobieranie dodatkowych zasobów na żądanie aplikacji korzystających z funkcji Play Asset Delivery</string>\n    <string name=\"pref_vending_asset_device_sync_summary\">Aplikacje korzystające z Play Asset Delivery będą pobierać dodatkowe zasoby na podstawie informacji o aktualnie używanym urządzeniu.</string>\n    <string name=\"pref_vending_asset_device_sync_switch\">Włącz synchronizację informacji o urządzeniu</string>\n    <string name=\"games_achievement_list_title\">Osiągnięcia</string>\n    <string name=\"games_achievements_empty_text\">Brak osiągnięć dla tej gry</string>\n    <string name=\"games_api_access_denied\">Żadne konto na tym urządzeniu nie ma dostępu do interfejsów API gier</string>\n    <string name=\"games_achievement_extra_text\">%1$s XP</string>\n    <string name=\"games_leaderboard_empty_text\">Brak rankingów dla tej gry</string>\n    <string name=\"games_leaderboard_score_empty_text\">Niewiarygodne! Nie ma publicznych wyników dla tej gry.</string>\n    <string name=\"games_delete_snapshot_dialog_message\">Czy na pewno chcesz usunąć zapisaną grę?</string>\n    <string name=\"games_delete_snapshot_dialog_cancel\">Anuluj</string>\n    <string name=\"games_delete_snapshot_dialog_ok\">OK</string>\n    <string name=\"games_delete_snapshot_error\">Usunięcie nie powiodło się, spróbuj ponownie później</string>\n    <string name=\"games_snapshot_empty_text\">Nie zapisano jeszcze żadnych zapisów gry</string>\n    <string name=\"games_snapshot_choose_btn_text\">wybierz</string>\n    <string name=\"games_leaderboard_list_title\">Rankingi</string>\n    <string name=\"games_delete_snapshot_dialog_title\">Usuń zapisaną grę</string>\n    <string name=\"games_achievement_unlocked_content_description\">odblokowano</string>\n    <string name=\"games_snapshot_delete_btn_text\">usuń</string>\n    <string name=\"games_achievement_locked_content_description\">zablokowano</string>\n    <string name=\"games_leaderboards_score_label\">Wynik: %1$s</string>\n    <string name=\"service_name_work_profile\">Profil służbowy</string>\n    <string name=\"pref_vending_licensing_split_install_summary\">Zezwalanie aplikacjom na pobieranie i instalowanie dodatkowych komponentów</string>\n    <string name=\"pref_workprofile_create_account\">Zezwalaj na konfigurację konta służbowego</string>\n    <string name=\"barcode_scanner_brand\">Zeskanowano przez microG w imieniu %1$s</string>\n    <string name=\"camera_permission_dialog_button\">OK</string>\n    <string name=\"pref_vending_split_install_switch\">Instalacja komponentów na żądanie</string>\n    <string name=\"camera_permission_dialog_message\">Usługi microG potrzebują dostępu do kamery urządzenia, aby zeskanować kod %1$s.\\n\\nAby to włączyć, należy przyznać uprawnienia do kamery usługom microG w Ustawieniach.</string>\n    <string name=\"pref_vending_feature_delivery\">Dostarczanie funkcji Google Play</string>\n    <string name=\"pref_workprofile_intro\">Podczas konfigurowania profilu służbowego dla miejsca pracy lub instytucji edukacyjnej konfigurator może próbować połączyć się z Google, aby umożliwić pobieranie aplikacji do tego profilu.</string>\n    <string name=\"pref_workprofile_disclaimer\">Użytkownik jest odpowiedzialny za zapewnienie, że korzystanie z microG jest zgodne z zasadami korporacyjnymi. microG jest dostarczane na zasadzie najlepszych starań i nie może zagwarantować, że będzie zachowywać się dokładnie tak, jak oczekiwano.</string>\n    <string name=\"camera_permission_dialog_title\">Wymagane zezwolenie na korzystanie z aparatu</string>\n    <string name=\"credentials_assisted_signin_add_account\">Dodaj konto</string>\n    <string name=\"credentials_assisted_choose_account_error_tips\">Nieprawidłowości na koncie</string>\n    <string name=\"auth_action_reauth_notification_title\">Wymagane działanie na koncie</string>\n    <string name=\"pref_game_accounts_title\">Konta Gry Google</string>\n    <string name=\"pref_auto_create_player\">Zezwól na rejestrację konta Gry Google Play</string>\n    <string name=\"pref_auto_create_player_intro\">Podczas grania w gry należy używać konta Gry Google Play do logowania się i rejestrowania funkcji związanych z grą, takich jak osiągnięcia, tabele wyników, archiwa itp. Po wyłączeniu konta Google, które nie są powiązane z kontem Gry Google Play, nie będą automatycznie rejestrowane, a gra nie będzie mogła się zalogować i uruchomić.</string>\n    <string name=\"pref_allow_upload_game_played\">Zezwalaj na przesyłanie rozegranych gier</string>\n    <string name=\"pref_allow_upload_game_played_summary\">Po wyłączeniu tej opcji gra nie będzie zgłaszać stanu rozegranej gry po zalogowaniu się do niej, a w niektórych grach może nie być możliwe zalogowanie się.</string>\n    <string name=\"pref_change_default_game_player\">Zmiana konto na gry</string>\n    <string name=\"pref_change_default_game_player_summary\">Zmień domyślne konto dla gier i zmień konto według gry.</string>\n    <string name=\"pref_delete_game_account_data\">Usuń dane konta Gry Google Play</string>\n    <string name=\"pref_delete_game_account_data_summary\">Usuń konto Gry Google Play i wszystkie dane oraz usuń dane poszczególnych gier.</string>\n    <string name=\"games_state_description_signed_out\">Wylogowano</string>\n    <string name=\"games_state_description_delete\">Usuń</string>\n    <string name=\"games_change_button_text\">Zmień</string>\n    <string name=\"games_change_default_account_section_title\">Zmień domyślne konto dla gier</string>\n    <string name=\"games_change_default_account_description\">Domyślne konto: %1$s</string>\n    <string name=\"games_change_default_account_explanation\">To konto jest używane do automatycznego logowania do gier, zapisywania postępów w grach i zapisywania ustawień. Zmiana domyślnego konta lub wylogowanie się może zresetować postępy i ustawienia gier, w które grano.</string>\n    <string name=\"games_change_per_game_title\">Zmiana konta według gry</string>\n    <string name=\"games_change_per_game_description\">Zmiana konta dla wybranej gry lub wylogowanie się z niej może spowodować zresetowanie postępów i ustawień gry.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_title\">Wybierz opcję dla nowego konta domyślnego</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_description\">Bieżące konto domyślne: %1$s</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_title\">Zmiana domyślnego konta tylko dla nowych gier</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_description\">Nie utracisz dostępu do postępów i ustawień gier, w które grano. Postępy zostaną jednak podzielone między konta.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_title\">Zmień domyślne konto dla wszystkich gier</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_description\">Możesz utracić dostęp do postępów i ustawień gier, w które grano. Ponownie uruchomimy grę, aby zastosować wprowadzone zmiany.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_title\">Wyloguj się ze wszystkich gier</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_description\">Możesz utracić dostęp do postępów i ustawień gier, w które grano. Ponownie uruchomimy grę, aby zastosować wprowadzone zmiany.</string>\n    <string name=\"games_change_per_game_dialog_title\">Wybierz opcję dla tej gry</string>\n    <string name=\"games_change_per_game_dialog_description\">Zmiana konta lub wylogowanie się może spowodować zresetowanie postępów i ustawień gry</string>\n    <string name=\"games_change_per_game_dialog_option_use_player\">Używaj %1$s</string>\n    <string name=\"games_change_per_game_dialog_option_use_player_snackbar_success_message\">Zalogowanie do tej gry nastąpi za pomocą %1$s</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out\">Wyloguj się</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out_snackbar_success_message\">Wylogowano cię z tej gry</string>\n    <string name=\"games_change_sign_out_of_all_games_snackbar_success_message\">Wylogowano cię ze wszystkich gier</string>\n    <string name=\"games_change_default_account_for_all_games_snackbar_success_message\">Nastąpi zalogowanie do wszystkich gier za pomocą %1$s</string>\n    <string name=\"games_change_default_account_for_new_games_snackbar_success_message\">Nastąpi zalogowanie do nowych gier za pomocą %1$s</string>\n    <string name=\"games_account_display_content\">Konto bieżące: %1$s</string>\n    <string name=\"games_delete_profile_header\">Usuń konto Gry Google Play i wszystkie dane</string>\n    <string name=\"games_delete_profile_explanation\">Trwałe usunięcie konta Gry Google Play, XP i wszystkich danych profilu. Ta czynność może również spowodować usunięcie wyników, postępów (zapisanych gier) i ustawień w grach, w które grano.</string>\n    <string name=\"games_delete_profile_button\">Trwale usuń</string>\n    <string name=\"games_delete_game_data_header\">Usuń dane poszczególnych gier</string>\n    <string name=\"games_delete_game_data_explanation\">Możesz trwale usunąć indywidualne dane gier, w które grano na koncie Gry Google Play. Ta czynność usuwa wyniki, postępy (zapisane gry) i ustawienia wybranej gry.</string>\n    <string name=\"games_delete_profile_dialog_title\">Czy na pewno chcesz usunąć to konto?</string>\n    <string name=\"games_delete_profile_explanation_with_gamer_name\">Trwałe usunięcie konta Gry Google Play z nazwą gracza <b>%1$s</b> (<b>%2$s</b>), XP i wszystkimi danymi profilu. Ta czynność może również spowodować usunięcie wyników, postępów (zapisanych gier) i ustawień w grach, w które grano.</string>\n    <string name=\"games_delete_profile_dialog_message\">Tego działania nie można cofnąć.</string>\n    <string name=\"games_delete_profile_fail\">Nie można usunąć profilu. Spróbuj ponownie później.</string>\n    <string name=\"games_delete_game_data_confirm_dialog_title\">Usuń dane dla %1$s</string>\n    <string name=\"games_delete_game_data_confirm_dialog_message\">Trwałe usunięcie danych dla %1$s spowoduje usunięcie wyników, postępów (zapisanych gier) i ustawień gry na koncie Gry Google Play.</string>\n    <string name=\"games_popup_signin_welcome\">Witaj, %1$s</string>\n    <string name=\"pref_auth_two_step_verification_title\">Otrzymuj monity weryfikacji dwuetapowej</string>\n    <string name=\"pref_auth_two_step_verification_summary\">Gdy włączone, urządzenie może odbierać monity weryfikacji dwuetapowej od Google (wymagana usługa Cloud Messaging).</string>\n    <string name=\"service_name_google_location_sharing\">Udostępnianie lokalizacji w Google</string>\n    <string name=\"location_sharing_description\">Zarządzaj udostępnianiem swojej lokalizacji w czasie rzeczywistym w aplikacjach i usługach Google z tego urządzenia</string>\n    <string name=\"location_sharing_learn_more\">Dowiedz się więcej o udostępnianiu lokalizacji</string>\n    <string name=\"location_sharing_switch_text\">Używaj funkcji udostępniania lokalizacji</string>\n    <string name=\"location_sharing_turn_off_notify_hint\">Jeśli wyłączysz udostępnianie lokalizacji dla tego urządzenia, osoby, którym udostępniasz lokalizację, nie będą powiadamiane.</string>\n    <string name=\"location_sharing_off_previous_hint\">Dopóki nie włączysz tej funkcji ponownie, dostępna będzie tylko ostatnia udostępniona lokalizacja.</string>\n    <string name=\"location_sharing_disabled\">Brak aktywnych udostępnień lokalizacji dla tego konta</string>\n    <string name=\"location_sharing_turn_on_hint\">Po rozpoczęciu udostępniania lokalizacji za pomocą aplikacji lub usługi Google możesz zarządzać udostępnianiem lokalizacji w tym miejscu.\\n\\nAby rozpocząć udostępnianie lokalizacji, przejdź do Map Google lub Family Link.</string>\n    <string name=\"location_sharing_turn_off_title\">Wyłącz udostępnianie lokalizacji</string>\n    <string name=\"location_sharing_turn_off_hint\">Możesz nadal udostępniać swoją lokalizację z innych urządzeń zalogowanych na to samo konto Google lub z aplikacji innych niż Google. Sprawdź ustawienia udostępniania lokalizacji wszędzie tam, gdzie może to mieć zastosowanie.\\n\\nOsoby, którym udostępniasz swoją lokalizację, będą nadal widzieć ostatnią udostępnioną lokalizację.</string>\n    <string name=\"location_sharing_turn_off_cancel\">Pozostaw</string>\n    <string name=\"location_sharing_turn_off_confirm\">Wyłącz</string>\n    <string name=\"location_sharing_confirm_dialog_title\">Włącz udostępnianie lokalizacji</string>\n    <string name=\"location_sharing_confirm_dialog_text\">Osoby, którym udostępniasz swoją lokalizację, zawsze mogą zobaczyć:\\n·Twoje imię i nazwisko oraz zdjęcie\\n·Ostatnią lokalizację twojego urządzenia, nawet jeśli nie korzystasz z usług Google\\n·Poziom naładowania baterii twojego urządzenia oraz informację, czy jest ono ładowane\\n·Godzinę przybycia i wyjazdu, jeśli dodadzą powiadomienie o udostępnianiu lokalizacji</string>\n    <string name=\"family_management_title\">Rodzina</string>\n    <string name=\"family_management_retry\">Ponów</string>\n    <string name=\"family_management_load_error\">Nie udało się załadować treści</string>\n    <string name=\"family_management_toolbar_back\">Wstecz</string>\n    <string name=\"family_management_toolbar_more\">Więcej</string>\n    <string name=\"family_management_exit_family_group\">Opuść grupę rodzinną</string>\n    <string name=\"family_management_delete_family_group\">Usuń grupę rodzinną</string>\n    <string name=\"family_management_leave_family_password_title\">Potwierdź hasło, aby opuścić grupę rodzinną</string>\n    <string name=\"family_management_delete_family_password_title\">Potwierdź hasło, aby usunąć grupę rodzinną</string>\n    <string name=\"family_management_remove_member_password_title\">Potwierdź hasło, aby usunąć %s</string>\n    <string name=\"family_management_invite_family_member\">Zaproś członków rodziny</string>\n    <string name=\"family_management_invite_slots_left\">Pozostało %1$d zaproszeń</string>\n    <string name=\"family_management_cancel_invite\">Anuluj zaproszenie</string>\n    <string name=\"family_management_cancel_invite_success\">Zaproszenie zostało pomyślnie anulowane</string>\n    <string name=\"family_management_cancel_invite_error\">Problem z anulowaniem zaproszenia. Spróbuj ponownie.</string>\n    <string name=\"family_management_remove_member\">Usuń członka</string>\n    <string name=\"family_management_member_removed_success\">%s został usunięty z twojej grupy rodzinnej</string>\n    <string name=\"family_management_member_remove_failed\">Problem z usunięciem %s. Spróbuj ponownie.</string>\n    <string name=\"family_management_leave_family_error_message\">Problem z opuszczeniem grupy rodzinnej. Spróbuj ponownie.</string>\n    <string name=\"family_management_exist_group_success\">Opuściłeś swoją grupę rodzinną…</string>\n    <string name=\"family_management_delete_group_success\">Grupa rodzinna usunięta</string>\n    <string name=\"family_management_delete_group_failure\">Nie udało się usunąć grupy domowej</string>\n    <string name=\"family_management_delete_group_cancel\">Anuluj</string>\n    <string name=\"family_management_delete_group_confirm\">OK</string>\n    <string name=\"family_management_input_pwd\">Wprowadź swoje hasło</string>\n    <string name=\"family_management_invite_sent_date_format\">Zaproszenie wysłane: %s</string>\n    <string name=\"family_management_invite_send\">Wysłano zaproszenie</string>\n    <string name=\"family_management_pwd_error\">Nieprawidłowe hasło, proszę wprowadzić ponownie</string>\n    <string name=\"pref_app_install_settings_title\">Ustawienia instalatora aplikacji</string>\n    <string name=\"pref_app_install_switch_title\">Zezwól na instalację aplikacji</string>\n    <string name=\"pref_app_install_other_apps_note\">Autoryzacja umożliwia instalację aplikacji pochodzących z innych źródeł.</string>\n    <string name=\"pref_app_install_permission_instruction\">Aby zapewnić prawidłowe działanie zainstalowanych aplikacji, należy zezwolić aplikacji microG Companion na instalowanie aplikacji pobranych z innych źródeł.</string>\n    <string name=\"prefcat_app_install_list_title\">Aplikacje korzystające z instalatora aplikacji</string>\n    <string name=\"service_name_device_attestation\">Poświadczenie urządzenia</string>\n    <string name=\"prefcat_device_attestation_apps_title\">Aplikacje korzystające z funkcji poświadczenie urządzenia</string>\n    <string name=\"pref_device_attestation_app_allow_requests_title\">Zezwól na żądania</string>\n    <string name=\"pref_device_attestation_app_allow_requests_summary\">Zezwól aplikacji na żądanie poświadczenia urządzenia</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-pt/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"permission_service_all_label\">Todos os serviços Google</string>\n    <string name=\"permission_service_all_description\">Permite que a app aceda todos os serviços Google através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_android_label\">Serviços Android</string>\n    <string name=\"permission_service_android_description\">Permite que a app aceda serviços Android através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_adsense_label\">AdSense</string>\n    <string name=\"permission_service_adsense_description\">Permite que a app aceda o AdSense através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_adwords_label\">AdWords</string>\n    <string name=\"permission_service_adwords_description\">Permite que a app aceda AdWords através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_ah_label\">Google App Engine</string>\n    <string name=\"permission_service_ah_description\">Permite que a app aceda o Google App Engine atráves de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_blogger_label\">Blogger</string>\n    <string name=\"permission_service_blogger_description\">Permite que a app aceda o Blogger através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_cl_label\">Google Agenda</string>\n    <string name=\"permission_service_cl_description\">Permite que a app aceda o Google Agenda através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_cp_label\">Contactos</string>\n    <string name=\"permission_service_cp_description\">Permite que a app aceda Contactos através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_dodgeball_label\">Dodgeball</string>\n    <string name=\"permission_service_dodgeball_description\">Permite que a app aceda Dodgeball através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_finance_label\">Google Finanças</string>\n    <string name=\"permission_service_finance_description\">Permite que a app aceda Google Finanças através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_gbase_label\">Google Base</string>\n    <string name=\"permission_service_gbase_description\">Permite que a app aceda Google Base através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_grandcentral_label\">Google Voice</string>\n    <string name=\"permission_service_grandcentral_description\">Permite que a app aceda Google Voice através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_groups2_label\">Grupos do Google</string>\n    <string name=\"permission_service_groups2_description\">Permite que a app aceda Grupos do Google através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_health_label\">Google Health</string>\n    <string name=\"permission_service_health_description\">Permite que a app aceda Google Health através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_ig_label\">iGoogle</string>\n    <string name=\"permission_service_ig_description\">Permite que a app aceda iGoogle através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_jotspot_label\">JotSpot</string>\n    <string name=\"permission_service_jotspot_description\">Permite que a app aceda JotSpot através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_knol_label\">Knol</string>\n    <string name=\"permission_service_knol_description\">Permite que a app aceda Knol através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_lh2_label\">Picasa Web Albums</string>\n    <string name=\"permission_service_lh2_description\">Permite que a app aceda Picasa Web Albums através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_local_label\">Google Maps</string>\n    <string name=\"permission_service_local_description\">Permite que a app aceda Google Maps através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_mail_label\">Google Mail</string>\n    <string name=\"permission_service_mail_description\">Permite que a app aceda Gmail através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_news_label\">Google News</string>\n    <string name=\"permission_service_news_description\">Permite que a app aceda Google News através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_notebook_label\">Google Notebook</string>\n    <string name=\"permission_service_notebook_description\">Permite que a app aceda Google Notebook através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_orkut_label\">Orkut</string>\n    <string name=\"permission_service_orkut_description\">Permite que a app aceda Orkut através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_print_label\">Google Book Search</string>\n    <string name=\"permission_service_print_description\">Permite que a app aceda Google Book Search através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_sierra_label\">Contas Google Checkout</string>\n    <string name=\"permission_service_sierra_description\">Permite que a app aceda contas do Google Checkout através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_sierraqa_label\">Contas Google Checkout QA</string>\n    <string name=\"permission_service_sierraqa_description\">Permite que a app aceda contas do Google Checkout QA através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_sierrasandbox_label\">Contas Google Checkout Sandbox</string>\n    <string name=\"permission_service_sierrasandbox_description\">Permite que a app aceda contas do Google Checkout Sandbox através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_sitemaps_label\">Google Ferramentas Webmaster</string>\n    <string name=\"permission_service_sitemaps_description\">Permite que a app aceda Google Ferramentas Webmaster através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_speech_label\">Pesquisa por voz</string>\n    <string name=\"permission_service_speech_description\">Permite que a app aceda Pesquisa por voz através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_speechpersonalization_label\">Reconhecimento de voz personalizado</string>\n    <string name=\"permission_service_speechpersonalization_description\">Permite que a app aceda o reconhecimento de voz personalizado através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_talk_label\">Google Talk</string>\n    <string name=\"permission_service_talk_description\">Permite que a app aceda Google Talk através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_wifi_label\">Google Wi-Fi</string>\n    <string name=\"permission_service_wifi_description\">Permite que a app aceda Google Wi-Fi através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_wise_label\">Google Planilhas</string>\n    <string name=\"permission_service_wise_description\">Permite que a app aceda Google Planilhas através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_writely_label\">Documentos Google</string>\n    <string name=\"permission_service_writely_description\">Permite que a app aceda Documentos Google através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_youtube_label\">YouTube</string>\n    <string name=\"permission_service_youtube_description\">Permite que a app aceda YouTube através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_YouTubeUser_label\">Usernames do YouTube</string>\n    <string name=\"permission_service_YouTubeUser_description\">Permite que a app aceda username(s) do YouTube através de qualquer conta do Google associada.</string>\n    <string name=\"perm_activity_recognition_label\">Reconhecimento de atividade</string>\n    <string name=\"perm_activity_recognition_description\">Permite que uma app receba atualizações periódicas do seu nível de atividade do Google, por exemplo, se está a andar, a conduzir, a andar de bicicleta, ou parado.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_activity\">Visualizar o histórico de atividade dos seus Google Apps</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.buyer\">Gerir configurações da sua conta de compras do Ad Exchange</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller.readonly\">Ver os seus dados do Ad Exchange</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller\">Ver e gerir os seus dados do Ad Exchange</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsensehost\">Ver e gerir os seus dados do AdSense host e contas associadas</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense.readonly\">Ver os seus dados do AdSense</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense\">Ver e gerir os seus dados do AdSense</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics.readonly\">Ver os seus dados do Google Analytics</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics\">Ver e gerir os seus dados do Google Analytics</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_androidpublisher\">Acesso ao Programador Android do Google Play</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appengine.admin\">Scope de admin do App Engine.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.migration\">Acesso para ler e escrever para a API de migração de grupos.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.settings\">Ver e gerir as configurações de um grupo do Google Apps</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.licensing\">Acesso de ler e escrever á API do License Manager.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order\">Para administradores e utilizadores de revenda acesso para ler/escrever quando testando o sandbox da API, ou acesso para ler/escrever quando chamando uma operação da API diretamente.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order.readonly\">Em adição à scope geral de ler/escrever do OAuth, use a scope de somente-leitura do OAuth quando carregando os dados de um consumidor.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps_reporting_audit.readonly\">Acesso à API de auditor de Admin somente-leitura</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appstate\">Scope para usar o serviço App State.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery.readonly\">Ver os seus dados no Google BigQuery</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery\">Ver e gerir os seus dados no Google BigQuery</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger\">Gerir a sua conta do Blogger</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger.readonly\">Ver a sua conta do Blogger</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_books\">Gerir os seus livros</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar\">Gerir os seus calendários</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar.readonly\">Ver os seus calendários</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_cloudprint\">Ver e gerir os seus dados do Google Cloud Print</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute.readonly\">Ver os seus recursos do Google Compute Engine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute\">Ver e gerir os seus recursos do Google Compute Engine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate.readonly\">Ver os seus trabalhos no Google Coordinate</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate\">Ver e gerir os seus trabalhos no Google Maps Coordinate</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.full_control\">Gerir os seus dados e permissões no Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_only\">Ver os seus dados no Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_write\">Gerir os seus dados no Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_dfareporting\">Ver e gerir relatórios do DoubleClick para Anunciantes</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.appdata\">Permite acesso à pasta de dados da aplicação</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.apps.readonly\">Ver os seus apps do Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.file\">Ver e gerir ficheiros do Google Drive que abriu ou criou com esta app</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.install\">Scope especial usada para permitir utilizadores aprovar a instalação de uma app</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.metadata.readonly\">Ver metadados de ficheiros e documentos no seu Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.readonly\">Ver ficheiros e documentos no seu Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.scripts\">Modificar o comportamento do seu script do Google Apps</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive\">Ver e gerir ficheiros e documentos no seu Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase.readonly\">ver a sua conta Freebase</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase\">Conectar-se ao Freebase com a sua conta</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables\">Gerir as suas Fusion Tables</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables.readonly\">Ver as suas Fusion Tables</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_games\">Scope para aceder dados do Googe Play Jogos.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan\">Gerir os seus dados GAN</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan.readonly\">Ver os seus dados GAN</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gcm_for_chrome\">Cloud Messaging para o Chrome</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_glass.timeline\">Scope de linha de tempo Glass</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.compose\">Criar, ler, atualizar e apagar rascunhos. Enviar mensagens e rascunhos.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.modify\">Todas as operações de ler/escrever, exceto o permanente e imediato apagamento de tópicos e mensagens, ignorando o lixo.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.readonly\">Ler todos os recursos e os seus metadados—nenhuma operação de escrita.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.best\">Gerir a sua melhor localização disponível e o histórico de localização</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.city\">Gerir a sua localização em nível de cidade e o histórico de localização</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.best\">Gerir a sua melhor localização disponível</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.city\">Gerir a sua localização em nível de cidade</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine\">Ver e gerir os seus dados do Google Maps Engine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine.readonly\">Ver os seus dados do Google Maps Engine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mobilemaps.firstparty\">Ver e gerir o seu Google Maps para experiência mobile</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut\">Gerir a sua atividade do Orkut</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut.readonly\">Ver os seus dados do Orkut</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.login\">Saber o seu nome, informações básicas e lista de pessoas com que está conectado no Google+</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.me\">Saber quem você é no Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_prediction\">Gerir os seus dados na API do Google Prediction</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_shoppingapi\">Ver dados de produtos</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification\">Gerir a lista de sites e domínios que controla</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification.verify_only\">Gerir as suas novas verificações de site com o Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_structuredcontent\">Acesso de ler/escrita à API Shopping Content.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue.consumer\">Consumir Tarefas das suas Taskqueues</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue\">Gerir as suas Tarefas</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks\">Gerir as suas tarefas</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks.readonly\">Ver as suas tarefas</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tracks\">API Google Maps Tracks, esta scope permite acesso de leitura e escrita aos dados do seu projeto.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_urlshortener\">Gerir as suas URLs curtas do goo.gl</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.email\">Ver o seu endereço de email</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.profile\">Ver informação básica sobre a sua conta</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube\">Gerir a sua conta do YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtubepartner\">Ver e gerir os seus recursos e conteúdo associado no YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.readonly\">Ver a sua conta do YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.upload\">Gerir os seus vídeos do YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics_monetary.readonly\">Ver relatórios monetários do YouTube Analytics do seu conteúdo no YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics.readonly\">Ver relatórios do YouTube Analytics do seu conteúdo do YouTube</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-pt/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <plurals name=\"pref_unifiednlp_summary\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> backend configurado</item>\n        <item quantity=\"many\"><xliff:g example=\"3\">%1$d</xliff:g> backends configurados</item>\n        <item quantity=\"other\"><xliff:g example=\"3\">%1$d</xliff:g> backends configurados</item>\n    </plurals>\n    <plurals name=\"gcm_registered_apps_counter\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> app registado</item>\n        <item quantity=\"many\"><xliff:g example=\"123\">%1$d</xliff:g> apps registados</item>\n        <item quantity=\"other\"><xliff:g example=\"123\">%1$d</xliff:g> apps registados</item>\n    </plurals>\n    <plurals name=\"cond_perm_summary\">\n        <item quantity=\"one\">Uma permissão necessária para o funcionamento adequado dos Serviços microG não foi concedida.</item>\n        <item quantity=\"many\">Permissões necessárias para o funcionamento adequado dos Serviços microG não foram concedidas.</item>\n        <item quantity=\"other\">Permissões necessárias para o funcionamento adequado dos Serviços microG não foram concedidas.</item>\n    </plurals>\n    <plurals name=\"cond_perm_action\">\n        <item quantity=\"one\">Solicitar permissão ausente</item>\n        <item quantity=\"many\">Solicitar permissões ausentes</item>\n        <item quantity=\"other\">Solicitar permissões ausentes</item>\n    </plurals>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-pt/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=\"gms_app_name\">Serviços microG</string>\n    <string name=\"limited_services_app_name\">Serviços microG limitados</string>\n    <string name=\"gms_settings_name\">Configurações do microG</string>\n    <string name=\"gms_settings_summary\">Configure os Serviços microG.</string>\n    <string name=\"just_a_sec\">Aguarde…</string>\n    <string name=\"google_account_label\">Google</string>\n    <string name=\"ask_permission_tos\">Ao continuar, permite que esta app e o Google usem as suas informações de acordo com os seus respetivos termos de serviço e políticas de privacidade.</string>\n    <string name=\"ask_scope_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> gostaria de:</string>\n    <string name=\"ask_service_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> gostaria de utilizar:</string>\n    <string name=\"account_manager_title\">Gestor de Contas do Google</string>\n    <string name=\"sorry\">Desculpe…</string>\n    <string name=\"auth_before_connect\">Uma app no seu dispositivo está a tentar conectar a uma conta do Google.\\n\\nSe isto for intencional, use o botão <b>Conectar-se</b> para conectar a sua conta, se não, toque em <b>Cancelar</b> para voltar para a aplicação que fez com que este diálogo aparecesse.</string>\n    <string name=\"auth_sign_in\">Conectar-se</string>\n    <string name=\"auth_connecting\">O seu dispositivo está a estabelecer uma conexão aos servidores do Google paraconectar-lo.\\n\\nIsto pode demorar alguns segundos.</string>\n    <string name=\"no_network_error_desc\">Não tem uma conexão de rede.\\n\\nEste pode ser um problema temporário ou o seu dispositivo Android pode não estar provisionado para serviços de dados. Tente novamente quando estiver conectado a uma rede móvel, ou conecte-se a uma rede Wi-Fi.</string>\n    <string name=\"auth_general_error_desc\">Ocorreu um problema ao comunicar com os servidores do Google.\\n\\nTente novamente mais tarde.</string>\n    <string name=\"auth_finalize\">O seu dispositivo está a contatar o Google para gravar informações na sua conta.\\n\\nIsto pode demorar alguns minutos.</string>\n    <string name=\"allow\">Permitir</string>\n    <string name=\"deny\">Negar</string>\n    <string name=\"auth_notification_title\">Autenticação necessária</string>\n    <string name=\"auth_notification_content\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> precisa da sua autorização para aceder a sua conta do Google.</string>\n    <string name=\"auth_package_override_request_title\">Permitir que <b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> tenha acesso privilegiado em <xliff:g example=\"account@example.com\">%2$s</xliff:g>\\?</string>\n    <string name=\"auth_package_override_request_message\"><b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> deseja aceder a sua conta como se fosse <b><xliff:g example=\"F-Droid\">%2$s</xliff:g> por <xliff:g example=\"F-Droid Inc.\">%3$s</xliff:g></b>. Isto pode concedê-lo acesso privilegiado à sua conta.</string>\n    <string name=\"auth_action_notification_channel_name\">Alertas de conta do Google</string>\n    <string name=\"auth_action_notification_channel_description\">Notifica quando uma das suas contas Google precisa de configuração adicional antes que seja utilizada ou quando uma conta é incompatível com o microG.</string>\n    <string name=\"auth_action_notification_title\">Ação de conta necessária</string>\n    <string name=\"auth_action_notification_content\">A sua conta Google precisa de configuração adicional.</string>\n    <string name=\"auth_action_reauth_notification_title\">Ação necessária na conta</string>\n    <string name=\"auth_action_activity_header\">Concluir a configuração da sua conta do Google</string>\n    <string name=\"auth_action_activity_explanation\">Complete os seguintes passos para poder usar a sua conta do Google %s neste dispositivo.</string>\n    <string name=\"auth_action_step_enable_checkin\">Ativar registo do dispositivo</string>\n    <string name=\"auth_action_step_enable_checkin_description\">O seu dispositivo precisa registar-se ao Google pelo menos uma vez.\\n\\nPode desativar o registo do dispositivo ao Google após a configuração da conta ser concluída.</string>\n    <string name=\"auth_action_step_enable_gcm\">Ativar o Cloud Messaging</string>\n    <string name=\"auth_action_step_enable_gcm_description\">Pode desativar o Cloud Messaging depois que configuração da conta ser concluída.</string>\n    <string name=\"auth_action_step_allow_microg_gcm\">Permitir Cloud Messaging para o microG</string>\n    <string name=\"auth_action_step_allow_microg_gcm_description\">De acordo com as suas preferências, o microG precisa da sua permissão antes que possa registar-se para o Cloud Messaging.</string>\n    <string name=\"auth_action_step_enable_lockscreen\">Configurar bloqueio de ecrã seguro</string>\n    <string name=\"auth_action_step_enable_lockscreen_description\">A sua conta Google é gerida pelo seu trabalho ou instituição escolar. O seu administrador decidiu que dispositivos devem ter um bloqueio de ecrã seguro antes que possam aceder dados da conta.\\n\\nPor favor configure uma palavra-passe, PIN, ou um padrão como o seu bloqueio de ecrã.</string>\n    <string name=\"auth_action_step_perform_content_description\">Clique para realizar esta etapa</string>\n    <string name=\"auth_action_step_completed_content_description\">Etapa concluída</string>\n    <string name=\"auth_action_activity_finish\">Concluir</string>\n    <string name=\"signin_picker_title\">Escolha uma conta</string>\n    <string name=\"signin_picker_subtitle\">para continuar em <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"signin_picker_add_account_label\">Adicionar outra conta</string>\n    <string name=\"signin_confirm_title\">Permitir conectar-se em <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"signin_confirm_button_text\">Permitir e partilhar</string>\n    <string name=\"signin_subtext_sharing\">Para continuar, o microG irá partilhar o nome, endereço de email e foto de perfil da sua conta do Google com <xliff:g example=\"F-Droid\">%1$s</xliff:g>.</string>\n    <string name=\"signin_subtext_policy\">Antes de usar esta app, revise a sua %1$s e os %2$s.</string>\n    <string name=\"signin_subtext_policy_privacy\">política de privacidade</string>\n    <string name=\"signin_subtext_policy_terms\">termos de serviço</string>\n    <string name=\"perm_status_broadcast_label\">ouvir transmissões de estado internos</string>\n    <string name=\"perm_gsf_read_gservices_label\">ler configuração de serviço Google</string>\n    <string name=\"perm_c2dm_receive_label\">ouvir mensagens C2DM</string>\n    <string name=\"perm_c2dm_send_label\">enviar mensagens C2DM para outras apps</string>\n    <string name=\"perm_gtalk_svc_label\">trocar mensagens e receber notificações de sincronização dos servidores do Google</string>\n    <string name=\"perm_extended_access_label\">Acesso estendido aos serviços Google</string>\n    <string name=\"perm_provision_label\">provisionar serviços microG</string>\n    <string name=\"perm_provision_description\">Permite que a app configure os serviços microG sem interação do utilizador</string>\n    <string name=\"perm_car_speed_label\">Velocidade do carro</string>\n    <string name=\"perm_car_speed_description\">Aceder a velocidade do seu carro</string>\n    <string name=\"perm_car_info_label\">Informação do carro</string>\n    <string name=\"perm_car_info_description\">Aceder a informação do seu carro</string>\n    <string name=\"perm_car_fuel_label\">Nível de combustível do carro</string>\n    <string name=\"perm_car_fuel_description\">Aceder o nível de combustível do seu carro</string>\n    <string name=\"perm_car_mileage_label\">Quilometragem do carro</string>\n    <string name=\"perm_car_mileage_description\">Aceder as informações de quilometragem do seu carro</string>\n    <string name=\"perm_car_vendor_extension_label\">Canal da fabricante do carro</string>\n    <string name=\"perm_car_vendor_extension_description\">Aceder o canal da fabricante do carro para trocar informações específicas do carro</string>\n    <string name=\"service_name_checkin\">Registo do dispositivo no Google</string>\n    <string name=\"service_name_mcs\">Cloud Messaging</string>\n    <string name=\"service_name_snet\">SafetyNet do Google</string>\n    <string name=\"service_name_vending\">Serviços da Play Store</string>\n    <string name=\"service_name_work_profile\">Perfil de trabalho</string>\n    <string name=\"games_title\">Google Play Jogos</string>\n    <string name=\"games_info_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> gostaria de utilizar o Play Jogos</string>\n    <string name=\"games_info_content\">Para usar o Play Jogos, é necessário instalar a app Google Play Jogos. A aplicação pode continuar sem o Play Jogos, mas é possível que ele se comporte inesperadamente.</string>\n    <string name=\"pick_place_title\">Escolha um lugar</string>\n    <string name=\"pick_place_desc\">O selecionador de lugares ainda não está disponível.</string>\n    <string name=\"place_picker_select_title\">Selecionar esta localização</string>\n    <string name=\"place_picker_nearby_places\">Lugares próximos</string>\n    <string name=\"place_picker_location_lat_lng\">(%1$.7f, %2$.7f)</string>\n    <string name=\"lacking_permission_toast\">Serviços microG: A permissão de <xliff:g example=\"have full network acccess\">%1$s</xliff:g> falta</string>\n    <string name=\"network_type_mobile\">Rede móvel</string>\n    <string name=\"network_type_wifi\">Wi-Fi</string>\n    <string name=\"network_type_roaming\">Roaming</string>\n    <string name=\"network_type_other\">Outras redes</string>\n    <string name=\"self_check_cat_fake_sig\">Apoio para a simulação de assinatura</string>\n    <string name=\"self_check_cat_gms_packages\">Pacotes instalados</string>\n    <string name=\"self_check_cat_system\">Sistema</string>\n    <string name=\"self_check_name_fake_sig_perm\">O sistema possui apoio à simulação de assinatura:</string>\n    <string name=\"self_check_resolution_fake_sig_perm\">A sua ROM não tem apoio nativo para a simulação de assinaturas. Ainda pode usar Xposed ou outros métodos para fazer a simulação da assinatura. Verifique a documentação sobre quais ROMs suportam a simulação de assinaturas e como usar o microG em ROMs que não o suportam.</string>\n    <string name=\"self_check_name_perm_granted\">O sistema concede a permissão de simulação de assinatura:</string>\n    <string name=\"self_check_resolution_perm_granted\">Este é um forte indicador de que a ROM suporta a simulação de assinatura, mas requer uma ação a mais para ativá-lo. Verifique a documentação sobre quais etapas podem ser necessárias.</string>\n    <string name=\"self_check_name_system_spoofs\">O sistema simula a assinatura:</string>\n    <string name=\"self_check_resolution_system_spoofs\">Consulte a documentação para quais etapas podem ser necessárias.</string>\n    <string name=\"self_check_pkg_gms\">Serviços microG</string>\n    <string name=\"self_check_pkg_vending\">Companheiro do microG</string>\n    <string name=\"self_check_pkg_gsf\">Framework dos Serviços microG</string>\n    <string name=\"self_check_name_app_installed\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> está instalado:</string>\n    <string name=\"self_check_resolution_app_installed\">Instale a aplicação <xliff:g example=\"F-Droid\">%1$s</xliff:g> ou um compatível. Consulte a documentação para saber quais aplicações são compatíveis.</string>\n    <string name=\"self_check_name_correct_sig\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> tem a assinatura correta:</string>\n    <string name=\"self_check_resolution_correct_sig\">A app <xliff:g example=\"F-Droid\">%1$s</xliff:g> instalada não é compatível ou a simulação de assinatura não está ativada para ele. Consulte a documentação para ver quais aplicações e ROMs são compatíveis.</string>\n    <string name=\"self_check_name_battery_optimizations\">Otimizações de pilha foram desativadas:</string>\n    <string name=\"self_check_resolution_battery_optimizations\">Toque aqui para desativar as otimizações de pilha. Não fazer isto pode resultar em aplicações com mal comportamento.</string>\n    <string name=\"prefcat_about\">Sobre</string>\n    <string name=\"prefcat_components\">Componentes</string>\n    <string name=\"prefcat_configuration\">Configuração</string>\n    <string name=\"prefcat_google_services\">Serviços do Google</string>\n    <string name=\"prefcat_location_service\">Serviço de localização</string>\n    <string name=\"prefcat_services\">Serviços</string>\n    <string name=\"prefcat_test\">Teste</string>\n    <string name=\"cond_gcm_bat_title\">Otimizações de pilha ativadas</string>\n    <string name=\"cond_gcm_bat_summary\">Ativou o Cloud Messaging, mas têm as otimizações de pilha ativas para os Serviços microG. Para que as notificações push sejam recebidas, deve desativar as otimizações da pilha.</string>\n    <string name=\"cond_gcm_bat_action\">Desativar otimizações</string>\n    <string name=\"cond_perm_title\">Permissão faltando</string>\n    <string name=\"prefs_account\">Preferências da conta</string>\n    <string name=\"prefs_account_privacy\">Informação pessoal &amp; privacidade</string>\n    <string name=\"prefs_account_security\">Credenciais e segurança</string>\n    <string name=\"pref_auth_trust_google_title\">Confiar o Google em permissões da app</string>\n    <string name=\"pref_auth_trust_google_summary\">Ao desativar, é perguntado ao utilizador antes que uma solicitação de autorização de uma app seja enviada ao Google. Algumas aplicações falharão em usar a conta do Google se isto estiver desativado.</string>\n    <string name=\"pref_auth_visible_title\">Permitir que apps encontrem contas</string>\n    <string name=\"pref_auth_visible_summary\">Ao ativar, todos os aplicações no dispositivo poderão ver o endereço de email das suas contas do Google sem autorização prévia.</string>\n    <string name=\"pref_auth_include_android_id_title\">Autenticar com o registo do dispositivo</string>\n    <string name=\"pref_auth_include_android_id_summary\">Ao desativar, solicitações de autenticação não serão vinculados com o registo do dispositivo, o que pode permitir que dispositivos não permitidos conectem-se, mas pode ter consequências inesperadas.</string>\n    <string name=\"pref_auth_strip_device_name_title\">Remover o nome do dispositivo para autenticação</string>\n    <string name=\"pref_auth_strip_device_name_summary\">Ao ativar, solicitações de autenticação não incluirão o nome do dispositivo, o que pode permitir que dispositivos não permitidos conectem-se, mas pode ter consequências inesperadas.</string>\n    <string name=\"pref_auth_two_step_verification_title\">Receber pedidos de verificação de duas etapas</string>\n    <string name=\"pref_auth_two_step_verification_summary\">Ao ativar, o dispositivo pode receber pedidos de verificação de duas etapas do Google (Cloud Messaging é necessário).</string>\n    <string name=\"pref_checkin_enable_summary\">Regista o seu dispositivo aos serviços do Google e cria um identificador de dispositivo único. O microG remove informações identificáveis dos dados do seu registo, exceto o nome da sua conta do Google.</string>\n    <string name=\"pref_device_registration_android_id\">ID do Android</string>\n    <string name=\"checkin_not_registered\">Não registado</string>\n    <string name=\"checkin_last_registration\">Último registo: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"checkin_enable_switch\">Registar dispositivo</string>\n    <string name=\"pref_info_status\">Estado</string>\n    <string name=\"pref_more_settings\">Mais</string>\n    <string name=\"pref_accounts_title\">Contas do Google</string>\n    <string name=\"pref_game_accounts_title\">Contas do Google de Jogos</string>\n    <string name=\"pref_accounts_summary\">Adicione e gira contas do Google</string>\n    <string name=\"prefcat_accounts_settings_title\">Configurações</string>\n    <string name=\"prefcat_accounts_current_accounts_title\">Contas</string>\n    <string name=\"pref_add_account_title\">Conta</string>\n    <string name=\"pref_add_account_summary\">Adicionar conta do Google</string>\n    <string name=\"pref_gcm_enable_mcs_summary\">O Cloud Messaging é um fornecedor de notificações push utilizado por muitos aplicações de terceiros. Para usá-lo, deve também ativar o registo do dispositivo.</string>\n    <string name=\"pref_gcm_heartbeat_title\">Intervalo da conexão do Cloud Messaging</string>\n    <string name=\"pref_gcm_heartbeat_summary\">O intervalo em segundos para verificar a conexão aos servidores do Google. Aumentar este número reduz o consumo da pilha, mas pode causar atrasos nas mensagens push.\\nDepreciado, será substituído numa versão futura.</string>\n    <string name=\"pref_gcm_apps_title\">Apps utilizando o Cloud Messaging</string>\n    <string name=\"pref_gcm_apps_summary\">Lista de apps atualmente registadas no Cloud Messaging.</string>\n    <string name=\"pref_gcm_confirm_new_apps_title\">Confirmar novas apps</string>\n    <string name=\"pref_gcm_confirm_new_apps_summary\">Perguntar antes que uma nova app se registe para notificações push</string>\n    <string name=\"pref_gcm_ping_interval\">Intervalo de verificação: <xliff:g example=\"10 minutes\">%1$s</xliff:g></string>\n    <string name=\"pref_about_title\">Sobre os Serviços microG</string>\n    <string name=\"pref_about_summary\">Informações de versão e bibliotecas usadas</string>\n    <string name=\"gcm_app_error_unregistering\">Erro ao remover o registo</string>\n    <string name=\"gcm_app_not_installed_anymore\">Não está mais instalado</string>\n    <string name=\"gcm_unregister_app\">Remover registo</string>\n    <string name=\"gcm_not_registered\">Não registado</string>\n    <string name=\"gcm_no_message_yet\">Nenhuma mensagem recebida até agora</string>\n    <string name=\"gcm_last_message_at\">Última mensagem: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_registered\">Registado</string>\n    <string name=\"gcm_registered_since\">Registado desde: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_unregister_confirm_title\">Remover registo de <xliff:g example=\"F-Droid\">%1$s</xliff:g>\\?</string>\n    <string name=\"gcm_unregister_confirm_message\">Algumas apps não se registam novamente automaticamente ou não fornecem uma opção para fazê-lo manualmente. Estas apps podem não funcionar corretamente após a remoção do registo.\\nDeseja mesmo continuar?</string>\n    <string name=\"gcm_unregister_after_deny_message\">Negou que uma app se registe para notificações push, mas que já está registado.\\nDeseja remover o registo agora para que não receba mensagens push no futuro?</string>\n    <string name=\"gcm_messages_counter\">Mensagens: <xliff:g example=\"123\">%1$d</xliff:g> (<xliff:g example=\"12345\">%2$d</xliff:g> bytes)</string>\n    <string name=\"gcm_network_state_disconnected\">Desconectado</string>\n    <string name=\"gcm_network_state_connected\">Conectado desde <xliff:g example=\"2 hours ago\">%1$s</xliff:g></string>\n    <string name=\"gcm_enable_switch\">Receber notificações push</string>\n    <string name=\"gcm_allow_app_popup\">Permitir que <xliff:g example=\"F-Droid\">%1$s</xliff:g> se registe para notificações push?</string>\n    <string name=\"pref_push_app_allow_register_title\">Permitir registo</string>\n    <string name=\"pref_push_app_allow_register_summary\">Permitir que a app se registe para notificações push.</string>\n    <string name=\"pref_push_app_wake_for_delivery_title\">Iniciar a app ao receber uma mensagem push</string>\n    <string name=\"pref_push_app_wake_for_delivery_summary\">Iniciar a app em segundo plano para receber as notificações push.</string>\n    <string name=\"prefcat_push_apps_title\">Apps utilizando notificações push</string>\n    <string name=\"prefcat_push_apps_registered_title\">Apps registados</string>\n    <string name=\"prefcat_push_apps_unregistered_title\">Apps não registados</string>\n    <string name=\"prefcat_push_networks_title\">Redes para usar para notificações push</string>\n    <string name=\"safetynet_intro\">O SafetyNet do Google é um sistema de certificação de dispositivo, que garante que um dispositivo é devidamente protegido e compatível com o Android CTS. Algumas aplicações utilizam o SafetyNet para motivos de segurança ou como um pré-requisito para proteção contra intervenção.\\n\\nmicroG GmsCore contém uma implementação livre do SafetyNet, mas o servidor oficial requer que as solicitações do SafetyNet sejam assinadas usando o sistema proprietário DroidGuard.</string>\n    <string name=\"safetynet_enable_switch\">Permitir atestação do dispositivo</string>\n    <string name=\"pref_safetynet_test_title\">Testar atestação do SafetyNet</string>\n    <string name=\"pref_recaptcha_test_title\">Testar reCAPTCHA</string>\n    <string name=\"pref_recaptcha_enterprise_test_title\">Testar reCAPTCHA Empresarial</string>\n    <string name=\"pref_test_summary_passed\">Passou todos os testes</string>\n    <string name=\"pref_test_summary_failed\">Falhou: %s</string>\n    <string name=\"pref_test_summary_warn\">Alerta: %s</string>\n    <string name=\"pref_test_summary_running\">Em execução…</string>\n    <string name=\"pref_droidguard_operation_mode\">Modo de operação</string>\n    <string name=\"pref_droidguard_unsupported_summary\">A execução do DroidGuard não é suportada neste dispositivo. Os serviços do SafetyNet podem comportar-se mal.</string>\n    <string name=\"prefcat_safetynet_apps_title\">Apps utilizando o SafetyNet</string>\n    <string name=\"menu_clear_recent_requests\">Apagar solicitações recentes</string>\n    <string name=\"safetynet_last_run_at\">Último uso: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"profile_name_native\">Nativo</string>\n    <string name=\"profile_name_real\">Real</string>\n    <string name=\"profile_name_user\">Customizado: %s</string>\n    <string name=\"profile_name_auto\">Automático: %s</string>\n    <string name=\"profile_name_system\">Sistema: %s</string>\n    <string name=\"pref_device_registration_import_custom_profile_title\">Importar perfil customizado</string>\n    <string name=\"pref_device_registration_serial_title\">Número de série</string>\n    <string name=\"pref_device_registration_import_custom_profile_summary\">Importar perfil de dispositivo por ficheiro</string>\n    <string name=\"pref_device_registration_select_profile_title\">Escolher perfil</string>\n    <string name=\"pref_device_registration_device_profile_category\">Perfil do dispositivo</string>\n    <string name=\"pref_safetynet_recent_uses\">Usos recentes</string>\n    <string name=\"pref_safetynet_recent_attestation_summary\">Atestação: %s</string>\n    <string name=\"pref_safetynet_recent_recaptcha_summary\">reCAPTCHA: %s</string>\n    <string name=\"pref_safetynet_recent_recaptcha_enterprise_summary\">reCAPTCHA Empresarial: %s</string>\n    <string name=\"pref_safetynet_recent_copy_json\">Copiar dados JSON JWS</string>\n    <string name=\"pref_safetynet_recent_advice\">Recomendação</string>\n    <string name=\"pref_safetynet_recent_eval_type\">Tipo de avaliação</string>\n    <string name=\"pref_safetynet_recent_response_status\">Estado da resposta</string>\n    <string name=\"pref_safetynet_recent_cat_response\">Dados da resposta</string>\n    <string name=\"pref_safetynet_recent_cat_request\">Solicitar dados</string>\n    <string name=\"pref_safetynet_recent_nonce\">Número usado uma só vez (Hex)</string>\n    <string name=\"pref_safetynet_recent_request_time\">Horário da solicitação</string>\n    <string name=\"pref_safetynet_recent_request_type\">Tipo da solicitação</string>\n    <string name=\"pref_safetynet_recent_cat_basic\">Dados básicos</string>\n    <string name=\"pref_safetynet_recent_token\">Código</string>\n    <string name=\"pref_safetynet_recent_copied\">Copiado para a área de transferência!</string>\n    <string name=\"pref_safetynet_test_integrity_cts_passed\">Integridade e CTS passaram</string>\n    <string name=\"pref_safetynet_test_cts_failed\">CTS falhou</string>\n    <string name=\"pref_safetynet_test_integrity_failed\">Integridade falhou</string>\n    <string name=\"pref_safetynet_test_not_completed\">Não concluído ainda</string>\n    <string name=\"pref_safetynet_test_no_result\">Nenhum resultado</string>\n    <string name=\"pref_safetynet_test_invalid_json\">JSON inválido</string>\n    <string name=\"push_notifications_summary_off\">DESLIGADO</string>\n    <string name=\"push_notifications_summary_automatic\">LIGADO / Automático: %s</string>\n    <string name=\"push_notifications_summary_manual\">LIGADO / Manual: %s</string>\n    <string name=\"push_notifications_summary_values_seconds\">%s segundos</string>\n    <string name=\"push_notifications_summary_values_minutes\">%s minutos</string>\n    <string name=\"pref_vending_summary_licensing_off\">Licenciamento desligado</string>\n    <string name=\"pref_vending_summary_licensing_on\">Licenciamento ativado</string>\n    <string name=\"pref_vending_licensing_category\">Licenciamento do Google Play</string>\n    <string name=\"pref_vending_licensing_enable_switch\">Lidar com verificações de licença</string>\n    <string name=\"pref_vending_license_enable_summary\">Algumas apps requerem uma verificação que comprou na Play Store. Ao ser solicitado por uma app, o microG pode descarregar uma prova de compra do Google. Se desativado, ou se nenhuma conta do Google foi adicionada, as verificações de licença são ignoradas.</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_switch\">Auto. adicionar apps grátis na biblioteca</string>\n    <string name=\"pref_vending_feature_delivery\">Feature Delivery do Google Play</string>\n    <string name=\"pref_vending_split_install_switch\">Instalação de componentes sob necessidade</string>\n    <string name=\"pref_vending_licensing_split_install_summary\">Permitir que apps descarreguem e instalem componentes adicionais</string>\n    <string name=\"feedback_disabled\">Feedback indisponível no momento</string>\n    <string name=\"backup_disabled\">Backup não possível nesse momento</string>\n    <string name=\"pref_vending_billing_category\">Cobrança do Google Play</string>\n    <string name=\"pref_vending_billing_enable_switch\">Lidar com solicitações de cobrança</string>\n    <string name=\"pref_vending_billing_enable_summary\">Ao ativar, algumas apps podem fazer compras ou iniciar assinaturas pelo serviço de cobrança do Google Play.</string>\n    <string name=\"pref_vending_billing_note_experimental\">Esta funcionalidade é experimental e pode causar perca de dinheiro. Foi avisado.</string>\n    <string name=\"pref_vending_billing_note_licensing\">Algumas apps requerem que ative a verificação de licença para verificar as suas compras.</string>\n    <string name=\"pref_vending_asset_delivery_category\">Asset Delivery do Google Play</string>\n    <string name=\"pref_vending_asset_delivery_switch\">Ativar entrega de recursos sob necessidade</string>\n    <string name=\"pref_vending_asset_delivery_summary\">Descarregar recursos adicionais ao ser solicitados por apps que utilizam o Play Asset Delivery</string>\n    <string name=\"pref_vending_asset_device_sync_summary\">Aplicações que utilizam o Play Asset Delivery descarregarão recursos adicionais baseados nas informações do dispositivo atualmente em uso.</string>\n    <string name=\"pref_vending_asset_device_sync_switch\">Ativar sincronização da info. do dispositivo</string>\n    <string name=\"pref_workprofile_create_account\">Permitir a configuração de um perfil de trabalho</string>\n    <string name=\"pref_workprofile_intro\">Ao configurar um perfil de trabalho para o seu local de trabalho ou instituição educacional, a configuração pode tentar conectar ao Google para descarregar apps naquele perfil.</string>\n    <string name=\"pref_workprofile_disclaimer\">É da sua responsabilidade garantir que o seu uso do microG está de acordo com as política da empresa. O microG é fornecido numa base de melhores esforços e não consegue garantir que se comportará exatamente como esperado.</string>\n    <string name=\"pref_auto_create_player\">Permitir integração da conta com o Play Games</string>\n    <string name=\"pref_auto_create_player_intro\">Ao jogar jogos, precisa usar uma conta do Play Games para conectar e gravar funções relacionadas a jogos, como conquistas, lista de ranques, arquivos, etc. Ao desativar, as contas do Google que não estão conectadas à uma conta do Play Games não serão registadas automaticamente e o jogo não poderá se conectar e jogar.</string>\n    <string name=\"pref_allow_upload_game_played\">Permitir envio do jogo</string>\n    <string name=\"pref_allow_upload_game_played_summary\">Ao desativar, o jogo não irá mais enviar o estado de jogado do jogo após conectar e alguns jogos podem não conseguir conectar.</string>\n    <string name=\"pref_change_default_game_player\">Alterar a conta para jogos</string>\n    <string name=\"pref_change_default_game_player_summary\">Alterar a conta padrão para jogos e alterar a conta por jogo.</string>\n    <string name=\"pref_delete_game_account_data\">Apagar dados do Play Games</string>\n    <string name=\"pref_delete_game_account_data_summary\">Apagar conta do Play Games e todos os dados, junto com os dados de jogos individuais.</string>\n    <string name=\"credentials_assisted_cancel\">Cancelar</string>\n    <string name=\"credentials_assisted_continue\">Continuar</string>\n    <string name=\"credentials_assisted_confirmation_header\">A conectar a sua conta</string>\n    <string name=\"credentials_assisted_continue_as_user_button_label\">Continuar como %1$s</string>\n    <string name=\"credentials_assisted_sign_back_title\">Fazer login novamente em %1$s com o Google</string>\n    <string name=\"credentials_assisted_signin_consent_header\">A conectar como %1$s</string>\n    <string name=\"credentials_assisted_signin_consent\">Se continuar, o Google partilhará o seu nome, endereço de e-mail e foto de perfil com %1$s. Verifique a política de privacidade e termos de serviço de %1$s.</string>\n    <string name=\"credentials_assisted_signin_description\">Pode gerir o Login com o Google nas suas contas do Google.</string>\n    <string name=\"credentials_assisted_choose_account_label\">Escolher conta</string>\n    <string name=\"credentials_assisted_choose_account_subtitle\">para continuar em %1$s</string>\n    <string name=\"credentials_assisted_choose_account_error_tips\">Anomalia na conta</string>\n    <string name=\"credentials_assisted_signin_button_text_long\">Fazer login com o Google</string>\n    <string name=\"credentials_assisted_signin_add_account\">Adicionar conta</string>\n    <string name=\"limited_services_dialog_information\">Usa os Serviços microG Limitados. Diferente dos Serviços microG comuns, esta variante só funciona com apps que usam as bibliotecas do microG, não aquelas do Google Play. Isto significa que a maioria das aplicações irão ignorar estes serviços.</string>\n    <string name=\"limited_services_dialog_information_ack\">Percebi</string>\n    <string name=\"games_achievement_list_title\">Conquistas</string>\n    <string name=\"games_achievements_empty_text\">Não há conquistas para este jogo</string>\n    <string name=\"games_api_access_denied\">Nenhuma conta neste dispositivo pode aceder as APIs do Jogos</string>\n    <string name=\"games_achievement_locked_content_description\">bloqueada</string>\n    <string name=\"games_achievement_unlocked_content_description\">desbloqueada</string>\n    <string name=\"games_achievement_extra_text\">%1$s XP</string>\n    <string name=\"games_leaderboard_empty_text\">Nenhuma lista de ranques neste jogo</string>\n    <string name=\"games_leaderboard_score_empty_text\">Inacreditável! Não há nenhuma maior pontuação pública neste jogo.</string>\n    <string name=\"games_leaderboard_list_title\">Ranques</string>\n    <string name=\"games_leaderboards_score_label\">Pontuação: %1$s</string>\n    <string name=\"games_snapshot_empty_text\">Ainda não há nenhum jogo gravado</string>\n    <string name=\"games_snapshot_choose_btn_text\">selecionar</string>\n    <string name=\"games_snapshot_delete_btn_text\">apagar</string>\n    <string name=\"games_delete_snapshot_dialog_title\">Apagar jogo gravado</string>\n    <string name=\"games_delete_snapshot_dialog_message\">Tem certeza que deseja apagar este jogo gravado?</string>\n    <string name=\"games_delete_snapshot_dialog_cancel\">Cancelar</string>\n    <string name=\"games_delete_snapshot_dialog_ok\">OK</string>\n    <string name=\"games_delete_snapshot_error\">Falha ao apagar, por favor tente novamente mais tarde</string>\n    <string name=\"games_state_description_signed_out\">Desconectado</string>\n    <string name=\"games_state_description_delete\">Apagar</string>\n    <string name=\"games_change_button_text\">Alterar</string>\n    <string name=\"games_change_default_account_section_title\">Alterar a conta padrão para jogos</string>\n    <string name=\"games_change_default_account_description\">Conta padrão: %1$s</string>\n    <string name=\"games_change_default_account_explanation\">Esta conta é usada para conectar automaticamente em jogos, gravar o seu progresso e as suas configurações. Alterar a conta padrão ou desconectar-se pode causar a perda do seu progresso e das configurações dos jogos que jogou.</string>\n    <string name=\"games_change_per_game_title\">Alterar a conta por jogo</string>\n    <string name=\"games_change_per_game_description\">Alterar a conta para um jogo específico ou desconectar-se pode causar a perda do seu progresso e das suas configurações para o jogo.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_title\">Selecione uma opção para a nova conta padrão</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_description\">Conta padrão atual: %1$s</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_title\">Alterar a conta padrão somente em jogos novos</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_description\">Não perderá o seu progresso ou as suas configurações nos jogos que jogou. Mas o seu progresso será dividido entre contas.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_title\">Alterar a conta padrão para todos os jogos</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_description\">Pode perder acesso ao seu progresso e às configurações dos jogos que jogou. Nós reiniciáramos o jogo para aplicar as alterações.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_title\">Desconectar-se de todos os jogos</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_description\">Pode perder o acesso ao seu progresso e as configurações dos jogos que jogou. Nós reiniciáramos o jogo para aplicar as alterações.</string>\n    <string name=\"games_change_per_game_dialog_title\">Selecione uma opção para este jogo</string>\n    <string name=\"games_change_per_game_dialog_description\">Alterar a conta ou desconectar-se pode causar a perda do seu progresso e das configurações para o jogo</string>\n    <string name=\"games_change_per_game_dialog_option_use_player\">Usar %1$s</string>\n    <string name=\"games_change_per_game_dialog_option_use_player_snackbar_success_message\">Será conectado com %1$s neste jogo</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out\">Desconectar-se</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out_snackbar_success_message\">Foi desconectado deste jogo</string>\n    <string name=\"games_change_sign_out_of_all_games_snackbar_success_message\">Foi desconectado de todos os jogos</string>\n    <string name=\"games_change_default_account_for_all_games_snackbar_success_message\">Está conectado com %1$s a todos os jogos</string>\n    <string name=\"games_change_default_account_for_new_games_snackbar_success_message\">Será conectado com %1$s em jogos novos</string>\n    <string name=\"games_account_display_content\">Conta atual: %1$s</string>\n    <string name=\"games_delete_profile_header\">Apagar conta do Play Games e todos os dados</string>\n    <string name=\"games_delete_profile_explanation\">Apagar permanentemente a sua conta do Google Play Games, XP e todos os dados do perfil. Esta ação também pode apagar as suas pontuações, progresso (jogos gravados), e configurações nos jogos que jogou.</string>\n    <string name=\"games_delete_profile_button\">Apagar permanentemente</string>\n    <string name=\"games_delete_game_data_header\">Apagar dados de jogos individuais</string>\n    <string name=\"games_delete_game_data_explanation\">Pode apagar dados de jogos individuais que jogou usando o Google Play Games. Esta ação apaga as suas pontuações, progresso (jogos gravados), e configurações para o jogo que selecionou.</string>\n    <string name=\"games_delete_profile_dialog_title\">Tem certeza que quer apagar esta conta?</string>\n    <string name=\"games_delete_profile_explanation_with_gamer_name\">Apagar permanentemente a sua conta do Google Play Games com nome de jogador <b>%1$s</b> (<b>%2$s</b>), com o seu XP e todos os dados do perfil. Esta ação também pode apagar as suas pontuações, progresso (jogos gravados), e outras configurações em jogos que jogou.</string>\n    <string name=\"games_delete_profile_dialog_message\">Esta ação não pode ser desfeita.</string>\n    <string name=\"games_delete_profile_fail\">Não foi possível apagar o seu perfil. Tente novamente mais tarde.</string>\n    <string name=\"games_delete_game_data_confirm_dialog_title\">Apagar dados de %1$s</string>\n    <string name=\"games_delete_game_data_confirm_dialog_message\">Apagar permanentemente os seus dados de %1$s apagará as suas pontuações, progresso (jogos gravados) e configurações do jogo no Google Play Games.</string>\n    <string name=\"games_popup_signin_welcome\">E aí, %1$s?</string>\n    <string name=\"barcode_scanner_brand\">Lido pelo microG no nome de %1$s</string>\n    <string name=\"camera_permission_dialog_button\">OK</string>\n    <string name=\"camera_permission_dialog_message\">Os Serviços microG precisa de acesso à câmara do dispositivo para ler o código para %1$s.\\n\\nPara ativar, conceda a permissão de câmara aos Serviços microG nas Configurações.</string>\n    <string name=\"camera_permission_dialog_title\">Permissão de câmara necessária</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_summary\">Apps grátis podem verificar que foram descarregadas do Google Play. Adicione apps grátis à sua biblioteca automaticamente para que essas verificações passem para si.</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-pt-rBR/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"permission_service_android_label\">Serviços Android</string>\n    <string name=\"permission_service_ah_description\">Permite que o app acesse o Google App Engine atráves de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_blogger_label\">Blogger</string>\n    <string name=\"permission_service_blogger_description\">Permite que o app acesse o Blogger através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_cl_label\">Google Agenda</string>\n    <string name=\"permission_service_android_description\">Permite que o app acesse serviços Android através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_adsense_description\">Permite que o app acesse o AdSense através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_ah_label\">Google App Engine</string>\n    <string name=\"permission_service_adwords_label\">AdWords</string>\n    <string name=\"permission_service_adwords_description\">Permite que o app acesse AdWords através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_cl_description\">Permite que o app acesse o Google Agenda através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_cp_label\">Contatos</string>\n    <string name=\"permission_service_health_description\">Permite que o app acesse Google Health através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_knol_label\">Knol</string>\n    <string name=\"permission_service_cp_description\">Permite que o app acesse Contatos através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_dodgeball_label\">Dodgeball</string>\n    <string name=\"permission_service_dodgeball_description\">Permite que o app acesse Dodgeball através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_gbase_label\">Google Base</string>\n    <string name=\"permission_service_gbase_description\">Permite que o app acesse Google Base através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_grandcentral_label\">Google Voice</string>\n    <string name=\"permission_service_grandcentral_description\">Permite que o app acesse Google Voice através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_finance_label\">Google Finanças</string>\n    <string name=\"permission_service_finance_description\">Permite que o app acesse Google Finanças através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_groups2_label\">Grupos do Google</string>\n    <string name=\"permission_service_groups2_description\">Permite que o app acesse Grupos do Google através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_jotspot_label\">JotSpot</string>\n    <string name=\"permission_service_health_label\">Google Health</string>\n    <string name=\"permission_service_ig_label\">iGoogle</string>\n    <string name=\"permission_service_knol_description\">Permite que o app acesse Knol através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_ig_description\">Permite que o app acesse iGoogle através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_jotspot_description\">Permite que o app acesse JotSpot através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_lh2_label\">Picasa Web Albums</string>\n    <string name=\"permission_service_lh2_description\">Permite que o app acesse Picasa Web Albums através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_local_label\">Google Maps</string>\n    <string name=\"permission_service_local_description\">Permite que o app acesse Google Maps através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_notebook_label\">Google Notebook</string>\n    <string name=\"permission_service_mail_label\">Google Mail</string>\n    <string name=\"permission_service_mail_description\">Permite que o app acesse Gmail através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_news_label\">Google News</string>\n    <string name=\"permission_service_news_description\">Permite que o app acesse Google News através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_notebook_description\">Permite que o app acesse Google Notebook através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_wise_description\">Permite que o app acesse Google Planilhas através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_youtube_description\">Permite que o app acesse YouTube através de qualquer conta do Google associada.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller.readonly\">Ver seus dados do Ad Exchange</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller\">Ver e gerenciar seus dados do Ad Exchange</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsensehost\">Ver e gerenciar seus dados do AdSense host e contas associadas</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense.readonly\">Ver seus dados do AdSense</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense\">Ver e gerenciar seus dados do AdSense</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics.readonly\">Ver seus dados do Google Analytics</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics\">Ver e gerenciar seus dados do Google Analytics</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_androidpublisher\">Acesso ao Desenvolvedor Android do Google Play</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.migration\">Acesso para ler e escrever para a API de migração de grupos.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.licensing\">Acesso de ler e escrever á API do License Manager.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.full_control\">Gerenciar seus dados e permissões no Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.apps.readonly\">Ver seus apps do Google Drive</string>\n    <string name=\"permission_service_writely_label\">Documentos Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.settings\">Ver e gerenciar as configurações de um grupo do Google Apps</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_only\">Ver seus dados no Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_cloudprint\">Ver e gerenciar seus dados do Google Cloud Print</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute.readonly\">Ver seus recursos do Google Compute Engine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_write\">Gerenciar seus dados no Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.appdata\">Permite acesso à pasta de dados da aplicação</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_dfareporting\">Ver e gerenciar relatórios do DoubleClick para Anunciantes</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute\">Ver e gerenciar seus recursos do Google Compute Engine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate.readonly\">Ver seus trabalhos no Google Coordinate</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate\">Ver e gerenciar seus trabalhos no Google Maps Coordinate</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive\">Ver e gerenciar arquivos e documentos no seu Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase.readonly\">ver sua conta Freebase</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.readonly\">Ler todos os recursos e seus metadados—nenhuma operação de escrita.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.file\">Ver e gerenciar arquivos do Google Drive que você abriu ou criou com esse app</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_structuredcontent\">Acesso de ler/escrita à API Shopping Content.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.readonly\">Ver sua conta do YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification.verify_only\">Gerenciar suas novas verificações de site com o Google</string>\n    <string name=\"permission_service_all_label\">Todos os serviços Google</string>\n    <string name=\"permission_service_all_description\">Permite que o app acesse todos os serviços Google através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_adsense_label\">AdSense</string>\n    <string name=\"permission_service_orkut_label\">Orkut</string>\n    <string name=\"permission_service_orkut_description\">Permite que o app acesse Orkut através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_print_label\">Google Book Search</string>\n    <string name=\"permission_service_print_description\">Permite que o app acesse Google Book Search através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_sierraqa_label\">Contas Google Checkout QA</string>\n    <string name=\"permission_service_sierra_description\">Permite que o app acesse contas do Google Checkout através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_sierra_label\">Contas Google Checkout</string>\n    <string name=\"permission_service_sierraqa_description\">Permite que o app acesse contas do Google Checkout QA através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_sierrasandbox_label\">Contas Google Checkout Sandbox</string>\n    <string name=\"permission_service_sierrasandbox_description\">Permite que o app acesse contas do Google Checkout Sandbox através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_sitemaps_label\">Google Ferramentas Webmaster</string>\n    <string name=\"permission_service_sitemaps_description\">Permite que o app acesse Google Ferramentas Webmaster através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_speech_label\">Pesquisa por voz</string>\n    <string name=\"permission_service_speech_description\">Permite que o app acesse Pesquisa por voz através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_speechpersonalization_label\">Reconhecimento de voz personalizado</string>\n    <string name=\"permission_service_speechpersonalization_description\">Permite que o app acesse o reconhecimento de voz personalizado através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_talk_label\">Google Talk</string>\n    <string name=\"permission_service_talk_description\">Permite que o app acesse Google Talk através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_wifi_label\">Google Wi-Fi</string>\n    <string name=\"permission_service_wifi_description\">Permite que o app acesse Google Wi-Fi através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_wise_label\">Google Planilhas</string>\n    <string name=\"permission_service_writely_description\">Permite que o app acesse Documentos Google através de qualquer conta do Google associada.</string>\n    <string name=\"permission_service_youtube_label\">YouTube</string>\n    <string name=\"permission_service_YouTubeUser_label\">Usernames do YouTube</string>\n    <string name=\"permission_service_YouTubeUser_description\">Permite que o app acesse username(s) do YouTube através de qualquer conta do Google associada.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_activity\">Visualizar o histórico de atividade dos seus Google Apps</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.buyer\">Gerenciar configurações da sua conta de compras do Ad Exchange</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order\">Para administradores e usuários de revenda acesso para ler/escrever quando testando o sandbox da API, ou acesso para ler/escrever quando chamando uma operação da API diretamente.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order.readonly\">Em adição à scope geral de ler/escrever do OAuth, use a scope de somente-leitura do OAuth quando carregando os dados de um consumidor.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps_reporting_audit.readonly\">Acesso à API de auditor de Admin somente-leitura</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery\">Ver e gerenciar seus dados no Google BigQuery</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appstate\">Scope para usar o serviço App State.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger\">Gerenciar sua conta do Blogger</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery.readonly\">Ver seus dados no Google BigQuery</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger.readonly\">Ver sua conta do Blogger</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_books\">Gerenciar seus livros</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar\">Gerenciar seus calendários</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar.readonly\">Ver seus calendários</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.install\">Scope especial usada para permitir usuários aprovar a instalação de um app</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.metadata.readonly\">Ver metadados de arquivos e documentos no seu Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.readonly\">Ver arquivos e documentos no seu Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.scripts\">Modificar o comportamento do seu script do Google Apps</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase\">Conectar-se ao Freebase com sua conta</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables\">Gerenciar suas Fusion Tables</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables.readonly\">Ver suas Fusion Tables</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_games\">Scope para acessar dados do Googe Play Jogos.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan\">Gerenciar seus dados GAN</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan.readonly\">Ver seus dados GAN</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gcm_for_chrome\">Cloud Messaging para o Chrome</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_glass.timeline\">Scope de linha de tempo Glass</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.compose\">Criar, ler, atualizar e apagar rascunhos. Enviar mensagens e rascunhos.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.modify\">Todas as operações de ler/escrever, exceto o permanente e imediato apagamento de tópicos e mensagens, ignorando a Lixeira.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine\">Ver e gerenciar seus dados do Google Maps Engine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine.readonly\">Ver seus dados do Google Maps Engine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mobilemaps.firstparty\">Ver e gerenciar seu Google Maps para experiência mobile</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut\">Gerenciar sua atividade do Orkut</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut.readonly\">Ver seus dados do Orkut</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.login\">Saber seu nome, informações básicas, e lista de pessoas que você está conectado no Google+</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.me\">Saber quem você é no Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_prediction\">Gerenciar seus dados na API do Google Prediction</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_shoppingapi\">Ver dados de produtos</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification\">Gerenciar a lista de sites e domínios que você controla</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue\">Gerenciar suas Tarefas</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks\">Gerenciar suas tarefas</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks.readonly\">Ver suas tarefas</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.email\">Ver seu endereço de email</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.profile\">Ver informação básica sobre sua conta</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube\">Gerenciar sua conta do YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtubepartner\">Ver e gerenciar seus recursos e conteúdo associado no YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.upload\">Gerenciar seus vídeos do YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics_monetary.readonly\">Ver relatórios monetários do YouTube Analytics do seu contéudo no YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics.readonly\">Ver relatórios do YouTube Analytics do seu contéudo do YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.best\">Gerenciar sua melhor localização disponível</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.city\">Gerenciar sua localização em nível de cidade</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue.consumer\">Consumir Tarefas de suas Taskqueues</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_urlshortener\">Gerenciar suas URLs curtas do goo.gl</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.best\">Gerenciar sua melhor localização disponível e o histórico de localização</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appengine.admin\">Scope de admin do App Engine.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tracks\">API Google Maps Tracks, esta scope permite acesso de leitura e escrita aos dados do seu projeto.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.city\">Gerenciar sua localização em nível de cidade e o histórico de localização</string>\n    <string name=\"perm_activity_recognition_label\">Reconhecimento de atividade</string>\n    <string name=\"perm_activity_recognition_description\">Permite que um app receba atualizações periódicas de seu nível de atividade do Google, por exemplo, se você está andando, dirigindo, andando de bicicleta, ou parado.</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-pt-rBR/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2017 microG Project Team\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  --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <plurals name=\"gcm_registered_apps_counter\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> app cadastrado</item>\n        <item quantity=\"many\"><xliff:g example=\"123\">%1$d</xliff:g> de apps cadastrados</item>\n        <item quantity=\"other\"><xliff:g example=\"123\">%1$d</xliff:g> apps cadastrados</item>\n    </plurals>\n    <plurals name=\"cond_perm_summary\">\n        <item quantity=\"one\">Uma permissão necessária para o funcionamento adequado dos Serviços microG não foi concedida.</item>\n        <item quantity=\"many\">Permissões necessárias para o funcionamento adequado dos Serviços microG não foram concedidas.</item>\n        <item quantity=\"other\">Permissões necessárias para o funcionamento adequado dos Serviços microG não foram concedidas.</item>\n    </plurals>\n    <plurals name=\"cond_perm_action\">\n        <item quantity=\"one\">Solicitar permissão faltante</item>\n        <item quantity=\"many\">Solicitar permissões faltantes</item>\n        <item quantity=\"other\">Solicitar permissões faltantes</item>\n    </plurals>\n    <plurals name=\"pref_unifiednlp_summary\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> backend configurado</item>\n        <item quantity=\"many\"><xliff:g example=\"3\">%1$d</xliff:g> de backends configurados</item>\n        <item quantity=\"other\"><xliff:g example=\"3\">%1$d</xliff:g> backends configurados</item>\n    </plurals>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-pt-rBR/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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  --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"gms_app_name\">Serviços microG</string>\n    <string name=\"gms_settings_name\">Configurações do microG</string>\n    <string name=\"just_a_sec\">Aguarde…</string>\n    <string name=\"google_account_label\">Google</string>\n    <string name=\"ask_permission_tos\">Ao continuar, você permite que este app e o Google usem suas informações de acordo com seus respectivos termos de serviço e políticas de privacidade.</string>\n    <string name=\"ask_scope_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> gostaria de:</string>\n    <string name=\"ask_service_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> gostaria de utilizar:</string>\n    <string name=\"account_manager_title\">Gerenciador de Contas do Google</string>\n    <string name=\"sorry\">Desculpe…</string>\n    <string name=\"no_network_error_desc\">Você não tem uma conexão de rede.\\n\\nEste pode ser um problema temporário ou seu dispositivo Android pode não estar provisionado para serviços de dados. Tente novamente quando estiver conectado a uma rede móvel, ou conecte-se a uma rede Wi-Fi.</string>\n    <string name=\"auth_general_error_desc\">Ocorreu um problema ao se comunicar com os servidores do Google.\\n\\nTente novamente mais tarde.</string>\n    <string name=\"auth_finalize\">\"Seu dispositivo está contatando o Google para salvar informações em sua conta.\n\nIsso pode demorar alguns minutos.\"</string>\n    <string name=\"allow\">Permitir</string>\n    <string name=\"deny\">Negar</string>\n    <string name=\"auth_notification_title\">Autenticação necessária</string>\n    <string name=\"auth_notification_content\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> precisa de sua autorização para acessar sua conta do Google.</string>\n    <string name=\"perm_status_broadcast_label\">ouvir transmissões de status internos</string>\n    <string name=\"perm_c2dm_receive_label\">ouvir mensagens C2DM</string>\n    <string name=\"perm_c2dm_send_label\">enviar mensagens C2DM para outros apps</string>\n    <string name=\"perm_gtalk_svc_label\">trocar mensagens e receber notificações de sincronização dos servidores do Google</string>\n    <string name=\"perm_extended_access_label\">Acesso extendido aos serviços Google</string>\n    <string name=\"service_name_checkin\">Cadastro do dispositivo no Google</string>\n    <string name=\"service_name_mcs\">Cloud Messaging</string>\n    <string name=\"games_title\">Google Play Jogos</string>\n    <string name=\"games_info_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> gostaria de utilizar o Play Jogos</string>\n    <string name=\"games_info_content\">Para usar o Play Jogos, é necessário instalar o app Google Play Jogos. O aplicativo pode continuar sem o Play Jogos, mas é possível que ele se comporte inesperadamente.</string>\n    <string name=\"pick_place_title\">Escolha um lugar</string>\n    <string name=\"pick_place_desc\">O selecionador de lugares ainda não está disponível.</string>\n    <string name=\"place_picker_select_title\">Selecionar esta localização</string>\n    <string name=\"place_picker_nearby_places\">Lugares próximos</string>\n    <string name=\"place_picker_location_lat_lng\">(%1$.7f, %2$.7f)</string>\n    <string name=\"lacking_permission_toast\">Serviços microG: A permissão de <xliff:g example=\"have full network acccess\">%1$s</xliff:g> está faltando</string>\n    <string name=\"network_type_mobile\">Rede móvel</string>\n    <string name=\"network_type_wifi\">Wi-Fi</string>\n    <string name=\"network_type_roaming\">Roaming</string>\n    <string name=\"network_type_other\">Outras redes</string>\n    <!-- Self check -->\n\n    <string name=\"self_check_cat_fake_sig\">Suporte à simulação de assinatura</string>\n    <string name=\"self_check_cat_gms_packages\">Pacotes instalados</string>\n    <string name=\"self_check_cat_system\">Sistema</string>\n    <string name=\"self_check_name_fake_sig_perm\">O sistema possui suporte à simulação de assinatura:</string>\n    <string name=\"self_check_resolution_fake_sig_perm\">Sua ROM não tem suporte nativo para a simulação de assinaturas. Você ainda pode usar Xposed ou outros métodos para fazer a simulação da assinatura. Verifique a documentação sobre quais ROMs suportam a simulação de assinaturas e como usar o microG em ROMs que não o suportam.</string>\n    <string name=\"self_check_name_perm_granted\">O sistema concede a permissão de simulação de assinatura:</string>\n    <string name=\"self_check_resolution_perm_granted\">Esse é um forte indicador de que a ROM suporta a simulação de assinatura, mas requer uma ação a mais para ativá-lo. Verifique a documentação sobre quais etapas podem ser necessárias.</string>\n    <string name=\"self_check_name_system_spoofs\">O sistema simula a assinatura:</string>\n    <string name=\"self_check_resolution_system_spoofs\">Consulte a documentação para quais etapas podem ser necessárias.</string>\n    <string name=\"self_check_pkg_gms\">Serviços microG</string>\n    <string name=\"self_check_pkg_vending\">Companheiro do microG</string>\n    <string name=\"self_check_pkg_gsf\">Framework dos Serviços microG</string>\n    <string name=\"self_check_name_app_installed\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> está instalado: </string>\n    <string name=\"self_check_resolution_app_installed\">Instale o aplicativo <xliff:g example=\"F-Droid\">%1$s</xliff:g> ou um compatível. Consulte a documentação para saber quais aplicativos são compatíveis.</string>\n    <string name=\"self_check_name_correct_sig\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> tem a assinatura correta: </string>\n    <string name=\"self_check_resolution_correct_sig\">O app <xliff:g example=\"F-Droid\">%1$s</xliff:g> instalado não é compatível ou a simulação de assinatura não está ativada para ele. Consulte a documentação para ver quais aplicativos e ROMs são compatíveis.</string>\n    <string name=\"self_check_name_battery_optimizations\">Otimizações de bateria foram desativadas:</string>\n    <string name=\"self_check_resolution_battery_optimizations\">Toque aqui para desativar as otimizações de bateria. Não fazer isso pode resultar em aplicativos com mal comportamento.</string>\n    <!-- Settings strings -->\n\n    <string name=\"prefcat_about\">Sobre</string>\n    <string name=\"prefcat_components\">Componentes</string>\n    <string name=\"prefcat_location_service\">Serviço de localização</string>\n    <string name=\"prefcat_services\">Serviços</string>\n    <string name=\"cond_gcm_bat_title\">Otimizações de bateria ativadas</string>\n    <string name=\"cond_gcm_bat_summary\">Você ativou o Cloud Messaging, mas têm as otimizações de bateria ativas para os Serviços microG. Para que as notificações push sejam recebidas, você deve desativar as otimizações da bateria.</string>\n    <string name=\"cond_gcm_bat_action\">Desativar otimizações</string>\n    <string name=\"cond_perm_title\">Permissão faltando</string>\n    <string name=\"prefs_account\">Preferências da conta</string>\n    <string name=\"prefs_account_privacy\">Informação pessoal &amp; privacidade</string>\n    <string name=\"prefs_account_security\">Credenciais e segurança</string>\n    <string name=\"pref_auth_trust_google_title\">Confiar o Google em permissões de app</string>\n    <string name=\"pref_auth_trust_google_summary\">Ao desativar, é perguntado ao usuário antes que uma solicitação de autorização de um app seja enviada ao Google. Alguns aplicativos falharão em usar a conta do Google se isto está desativado.</string>\n    <string name=\"pref_checkin_enable_summary\">Cadastra seu dispositivo aos serviços do Google e cria um identificador de dispositivo único. O microG remove informações identificavéis dos dados do seu cadastro, exceto o nome da sua conta do Google.</string>\n    <string name=\"pref_gcm_enable_mcs_summary\">O Cloud Messaging é um fornecedor de notificações push utilizado por muitos aplicativos de terceiros. Para usá-lo, você deve também ativar o cadastro do dispositivo.</string>\n    <string name=\"pref_gcm_heartbeat_title\">Intervalo da conexão do Cloud Messaging</string>\n    <string name=\"pref_gcm_heartbeat_summary\">O intervalo em segundos para verificar a conexão aos servidores do Google. Aumentar este número reduz o consumo da bateria, mas pode causar atrasos nas mensagens push.\\nDepreciado, será substituído em uma versão futura.</string>\n    <string name=\"pref_gcm_apps_title\">Apps utilizando o Cloud Messaging</string>\n    <string name=\"pref_gcm_apps_summary\">Lista de apps atualmente cadastrados no Cloud Messaging.</string>\n    <string name=\"pref_about_title\">Sobre os Serviços microG</string>\n    <string name=\"pref_about_summary\">Informações de versão e bibliotecas usadas</string>\n    <string name=\"gcm_app_error_unregistering\">Erro ao descadastrar</string>\n    <string name=\"gcm_app_not_installed_anymore\">Não está mais instalado</string>\n    <string name=\"gcm_unregister_app\">Descadastrar</string>\n    <string name=\"gcm_not_registered\">Não cadastrado</string>\n    <string name=\"gcm_no_message_yet\">Nenhuma mensagem recebida até agora</string>\n    <string name=\"gcm_last_message_at\">Última mensagem: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_registered\">Cadastrado</string>\n    <string name=\"gcm_registered_since\">Cadastrado desde: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_unregister_confirm_title\">Descadastrar <xliff:g example=\"F-Droid\">%1$s</xliff:g>\\?</string>\n    <string name=\"gcm_unregister_confirm_message\">Alguns apps não se cadastram novamente automaticamente ou não fornecem uma opção para fazer isso manualmente. Estes apps podem não funcionar corretamente após descadastrar.\\nContinuar?</string>\n    <string name=\"gcm_unregister_after_deny_message\">Você negou que um app se cadastre para notificações push, mas que já está cadastrado.\\nDeseja descadastrar agora para que não receba mensagens push no futuro?</string>\n    <string name=\"gcm_messages_counter\">Mensagens: <xliff:g example=\"123\">%1$d</xliff:g> (<xliff:g example=\"12345\">%2$d</xliff:g> bytes)</string>\n    <string name=\"gcm_network_state_disconnected\">Desconectado</string>\n    <string name=\"gcm_network_state_connected\">Conectado desde <xliff:g example=\"2 hours ago\">%1$s</xliff:g></string>\n    <string name=\"service_name_vending\">Serviços da Play Store</string>\n    <string name=\"prefcat_configuration\">Configuração</string>\n    <string name=\"pref_auth_include_android_id_title\">Autenticar com o cadastro do dispositivo</string>\n    <string name=\"pref_device_registration_android_id\">ID do Android</string>\n    <string name=\"checkin_enable_switch\">Cadastrar dispositivo</string>\n    <string name=\"pref_info_status\">Estado</string>\n    <string name=\"pref_more_settings\">Mais</string>\n    <string name=\"pref_add_account_title\">Conta</string>\n    <string name=\"pref_add_account_summary\">Adicionar conta do Google</string>\n    <string name=\"pref_gcm_confirm_new_apps_title\">Confirmar novos apps</string>\n    <string name=\"gcm_enable_switch\">Receber notificações push</string>\n    <string name=\"gcm_allow_app_popup\">Permitir que <xliff:g example=\"F-Droid\">%1$s</xliff:g> se cadraste para notificações push?</string>\n    <string name=\"pref_push_app_allow_register_title\">Permitir cadastro</string>\n    <string name=\"pref_push_app_allow_register_summary\">Permitir que o app se cadastre para notificações push.</string>\n    <string name=\"pref_push_app_wake_for_delivery_summary\">Iniciar o app em segundo plano para receber as notificações push.</string>\n    <string name=\"pref_push_app_wake_for_delivery_title\">Iniciar o app ao receber uma mensagem push</string>\n    <string name=\"prefcat_push_apps_title\">Apps utilizando notificações push</string>\n    <string name=\"prefcat_push_networks_title\">Redes para usar para notificações push</string>\n    <string name=\"safetynet_enable_switch\">Permitir atestação do dispositivo</string>\n    <string name=\"pref_safetynet_test_title\">Testar atestação do SafetyNet</string>\n    <string name=\"pref_test_summary_passed\">Passou todos os testes</string>\n    <string name=\"pref_test_summary_failed\">Falhou: %s</string>\n    <string name=\"pref_test_summary_warn\">Alerta: %s</string>\n    <string name=\"pref_droidguard_operation_mode\">Modo de operação</string>\n    <string name=\"prefcat_safetynet_apps_title\">Apps utilizando o SafetyNet</string>\n    <string name=\"menu_clear_recent_requests\">Apagar solicitações recentes</string>\n    <string name=\"safetynet_last_run_at\">Último uso: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"profile_name_native\">Nativo</string>\n    <string name=\"profile_name_real\">Real</string>\n    <string name=\"profile_name_user\">Customizado: %s</string>\n    <string name=\"profile_name_system\">Sistema: %s</string>\n    <string name=\"pref_device_registration_import_custom_profile_title\">Importar perfil customizado</string>\n    <string name=\"pref_device_registration_serial_title\">Número de série</string>\n    <string name=\"pref_device_registration_import_custom_profile_summary\">Importar perfil de dispositivo por arquivo</string>\n    <string name=\"pref_device_registration_select_profile_title\">Escolher perfil</string>\n    <string name=\"pref_safetynet_recent_recaptcha_enterprise_summary\">reCAPTCHA Empresarial: %s</string>\n    <string name=\"pref_safetynet_recent_response_status\">Estado da resposta</string>\n    <string name=\"pref_safetynet_recent_cat_response\">Dados da resposta</string>\n    <string name=\"pref_safetynet_recent_cat_request\">Solicitar dados</string>\n    <string name=\"pref_safetynet_recent_nonce\">Número usado uma só vez (Hex)</string>\n    <string name=\"pref_safetynet_recent_request_time\">Horário da solicitação</string>\n    <string name=\"push_notifications_summary_manual\">Ativado / Manual: %s</string>\n    <string name=\"push_notifications_summary_values_seconds\">%s segundos</string>\n    <string name=\"push_notifications_summary_values_minutes\">%s minutos</string>\n    <string name=\"pref_vending_summary_licensing_off\">Licenciamento desligado</string>\n    <string name=\"pref_vending_summary_licensing_on\">Licenciamento ativado</string>\n    <string name=\"pref_vending_licensing_enable_switch\">Lidar com verificações de licença</string>\n    <string name=\"signin_picker_subtitle\">para continuar em <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"signin_confirm_title\">Permitir conectar-se em <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"signin_subtext_sharing\">Para continuar, o microG irá compartilhar o nome, endereço de email, e foto de perfil de sua conta do Google com <xliff:g example=\"F-Droid\">%1$s</xliff:g>.</string>\n    <string name=\"feedback_disabled\">Feedback indisponível no momento</string>\n    <string name=\"auth_before_connect\">Um app no seu dispositivo está tentando se conectar à uma conta do Google.\\n\\nSe isso for intencional, use o botão <b>Conectar-se</b> para se conectar à sua conta, se não, toque em <b>Cancelar</b> para voltar para o aplicativo que fez com que este diálogo aparecesse.</string>\n    <string name=\"perm_provision_label\">provisionar serviços microG</string>\n    <string name=\"service_name_snet\">SafetyNet do Google</string>\n    <string name=\"prefcat_google_services\">Serviços do Google</string>\n    <string name=\"pref_gcm_confirm_new_apps_summary\">Perguntar antes que um novo app se cadastre para notificações push</string>\n    <string name=\"prefcat_test\">Teste</string>\n    <string name=\"pref_auth_include_android_id_summary\">Ao desativar, solicitações de autenticação não serão vinculados com o cadastro do dispositivo, o que pode permitir que dispositivos não permitidos conectem-se, mas pode ter consequências inesperadas.</string>\n    <string name=\"pref_gcm_ping_interval\">Intervalo de verificação: <xliff:g example=\"10 minutes\">%1$s</xliff:g></string>\n    <string name=\"pref_auth_visible_title\">Permitir que apps encontrem contas</string>\n    <string name=\"checkin_not_registered\">Não cadastrado</string>\n    <string name=\"pref_auth_visible_summary\">Ao ativar, todos os aplicativos no dispositivo poderão ver o endereço de email das suas contas do Google sem autorização prévia.</string>\n    <string name=\"checkin_last_registration\">Último cadastro: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"prefcat_push_apps_registered_title\">Apps cadastrados</string>\n    <string name=\"prefcat_push_apps_unregistered_title\">Apps não cadastrados</string>\n    <string name=\"pref_recaptcha_test_title\">Testar reCAPTCHA</string>\n    <string name=\"safetynet_intro\">O SafetyNet do Google é um sistema de certificação de dispositivo, que garante que um dispositivo é devidamente protegido e compatível com o Android CTS. Alguns aplicativos utilizam o SafetyNet para motivos de segurança ou como um pré-requisito para proteção contra intervenção.\\n\\nmicroG GmsCore contém uma implementação livre do SafetyNet, mas o servidor oficial requer que as solicitações do SafetyNet sejam assinadas usando o sistema proprietário DroidGuard.</string>\n    <string name=\"pref_recaptcha_enterprise_test_title\">Testar reCAPTCHA Empresarial</string>\n    <string name=\"pref_test_summary_running\">Em execução…</string>\n    <string name=\"pref_droidguard_unsupported_summary\">A execução do DroidGuard não é suportada neste dispositivo. Os serviços do SafetyNet podem se comportar mal.</string>\n    <string name=\"profile_name_auto\">Automático: %s</string>\n    <string name=\"pref_device_registration_device_profile_category\">Perfil do dispositivo</string>\n    <string name=\"pref_safetynet_recent_uses\">Usos recentes</string>\n    <string name=\"pref_safetynet_recent_attestation_summary\">Atestado: %s</string>\n    <string name=\"pref_safetynet_recent_request_type\">Tipo da solicitação</string>\n    <string name=\"pref_safetynet_recent_recaptcha_summary\">reCAPTCHA: %s</string>\n    <string name=\"pref_safetynet_recent_copy_json\">Copiar dados JSON JWS</string>\n    <string name=\"pref_safetynet_recent_advice\">Recomendação</string>\n    <string name=\"pref_safetynet_recent_eval_type\">Tipo de avaliação</string>\n    <string name=\"pref_vending_license_enable_summary\">Alguns apps requerem uma verificação que você comprou eles na Play Store. Ao ser solicitado por um app, o microG pode baixar uma prova de compra do Google. Se desativado, ou se nenhuma conta do Google foi adicionada, as verificações de licença são ignoradas.</string>\n    <string name=\"gms_settings_summary\">Configure os Serviços microG.</string>\n    <string name=\"auth_sign_in\">Conectar-se</string>\n    <string name=\"auth_connecting\">Seu dispositivo está estabelecendo uma conexão aos servidores do Google para te conectar.\\n\\nIsso pode demorar alguns segundos.</string>\n    <string name=\"signin_picker_title\">Escolha uma conta</string>\n    <string name=\"signin_picker_add_account_label\">Adicionar outra conta</string>\n    <string name=\"signin_confirm_button_text\">Permitir e compartilhar</string>\n    <string name=\"signin_subtext_policy\">Antes de usar este app, revise sua %1$s e os %2$s.</string>\n    <string name=\"signin_subtext_policy_privacy\">política de privacidade</string>\n    <string name=\"signin_subtext_policy_terms\">termos de serviço</string>\n    <string name=\"perm_gsf_read_gservices_label\">ler configuração de serviço Google</string>\n    <string name=\"perm_provision_description\">Permite que o app configure os serviços microG sem interação do usuário</string>\n    <string name=\"pref_safetynet_recent_cat_basic\">Dados básicos</string>\n    <string name=\"pref_safetynet_recent_token\">Código</string>\n    <string name=\"pref_safetynet_test_invalid_json\">JSON inválido</string>\n    <string name=\"push_notifications_summary_off\">Desativado</string>\n    <string name=\"push_notifications_summary_automatic\">Ativado / Automático: %s</string>\n    <string name=\"pref_safetynet_recent_copied\">Copiado para a área de transferência!</string>\n    <string name=\"pref_safetynet_test_integrity_cts_passed\">Integridade e CTS passaram</string>\n    <string name=\"pref_safetynet_test_cts_failed\">CTS falhou</string>\n    <string name=\"pref_safetynet_test_integrity_failed\">Integridade falhou</string>\n    <string name=\"pref_safetynet_test_not_completed\">Não concluído ainda</string>\n    <string name=\"pref_safetynet_test_no_result\">Nenhum resultado</string>\n    <string name=\"pref_auth_strip_device_name_title\">Remover o nome do dispositivo para autenticação</string>\n    <string name=\"pref_auth_strip_device_name_summary\">Ao ativar, solicitações de autenticação não incluirão o nome do dispositivo, o que pode permitir que dispositivos não permitidos conectem-se, mas pode ter consequências inesperadas.</string>\n    <string name=\"perm_car_speed_label\">Velocidade do carro</string>\n    <string name=\"perm_car_info_label\">Informação do carro</string>\n    <string name=\"perm_car_speed_description\">Acessar a velocidade do seu carro</string>\n    <string name=\"perm_car_info_description\">Acessar a informação do seu carro</string>\n    <string name=\"perm_car_fuel_label\">Nível de combustível do carro</string>\n    <string name=\"perm_car_fuel_description\">Acessar o nível de combustível do seu carro</string>\n    <string name=\"backup_disabled\">Backup não possível nesse momento</string>\n    <string name=\"perm_car_mileage_label\">Quilometragem do carro</string>\n    <string name=\"perm_car_mileage_description\">Acessar as informações de quilometragem do seu carro</string>\n    <string name=\"perm_car_vendor_extension_label\">Canal da fabricante do carro</string>\n    <string name=\"perm_car_vendor_extension_description\">Acessar o canal da fabricante do carro para trocar informações específicas do carro</string>\n    <string name=\"pref_accounts_title\">Contas do Google</string>\n    <string name=\"prefcat_accounts_settings_title\">Configurações</string>\n    <string name=\"prefcat_accounts_current_accounts_title\">Contas</string>\n    <string name=\"pref_accounts_summary\">Adicione e gerencie contas do Google</string>\n    <string name=\"pref_vending_billing_category\">Cobrança do Google Play</string>\n    <string name=\"pref_vending_licensing_category\">Licenciamento do Google Play</string>\n    <string name=\"pref_vending_billing_enable_switch\">Lidar com solicitações de cobrança</string>\n    <string name=\"pref_vending_billing_enable_summary\">Ao ativar, alguns apps podem fazer compras ou iniciar assinaturas pelo serviço de cobrança do Google Play.</string>\n    <string name=\"pref_vending_billing_note_experimental\">Essa funcionalidade é experimental e pode causar perca de dinheiro. Você foi avisado.</string>\n    <string name=\"pref_vending_billing_note_licensing\">Alguns apps requerem que você ative a verificação de licença para verificar suas compras.</string>\n    <string name=\"credentials_assisted_confirmation_header\">Conectando sua conta</string>\n    <string name=\"credentials_assisted_continue_as_user_button_label\">Continuar como %1$s</string>\n    <string name=\"credentials_assisted_sign_back_title\">Fazer login novamente em %1$s com o Google</string>\n    <string name=\"credentials_assisted_signin_consent_header\">Conectando-se como %1$s</string>\n    <string name=\"credentials_assisted_signin_description\">Você pode gerenciar o Login com o Google em suas contas do Google.</string>\n    <string name=\"credentials_assisted_choose_account_label\">Escolher conta</string>\n    <string name=\"credentials_assisted_choose_account_subtitle\">para continuar em %1$s</string>\n    <string name=\"credentials_assisted_signin_button_text_long\">Fazer login com o Google</string>\n    <string name=\"credentials_assisted_cancel\">Cancelar</string>\n    <string name=\"credentials_assisted_continue\">Continuar</string>\n    <string name=\"credentials_assisted_signin_consent\">Se continuar, o Google compartilhará seu nome, endereço de e-mail, e foto de perfil com %1$s. Verifique a política de privacidade e termos de serviço de %1$s.</string>\n    <string name=\"auth_package_override_request_title\">Permitir que <b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> tenha acesso privilegiado em <xliff:g example=\"account@example.com\">%2$s</xliff:g>\\?</string>\n    <string name=\"auth_package_override_request_message\"><b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> deseja acessar sua conta como se fosse <b><xliff:g example=\"F-Droid\">%2$s</xliff:g> por <xliff:g example=\"F-Droid Inc.\">%3$s</xliff:g></b>. Isto pode concedê-lo acesso privilegiado à sua conta.</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_switch\">Auto. adicionar apps grátis na biblioteca</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_summary\">Apps grátis podem verificar que foram baixados do Google Play. Adicione apps grátis à sua biblioteca automaticamente para que essas verificações passem pra você.</string>\n    <string name=\"limited_services_app_name\">Serviços microG Limitados</string>\n    <string name=\"limited_services_dialog_information\">Você está usando os Serviços microG Limitados. Diferente dos Serviços microG comuns, essa variante só funciona com apps que usam as bibliotecas do microG, não aquelas do Google Play. Isto significa que a maioria dos aplicativos irão ignorar estes serviços.</string>\n    <string name=\"limited_services_dialog_information_ack\">Entendi</string>\n    <string name=\"auth_action_activity_explanation\">Complete os seguintes passos para poder usar sua conta do Google %s neste dispositivo.</string>\n    <string name=\"auth_action_step_allow_microg_gcm\">Permitir Cloud Messaging para o microG</string>\n    <string name=\"auth_action_step_enable_lockscreen\">Configurar bloqueio de tela seguro</string>\n    <string name=\"auth_action_activity_header\">Concluir a configuração da sua conta do Google</string>\n    <string name=\"auth_action_notification_channel_name\">Alertas de conta do Google</string>\n    <string name=\"auth_action_notification_channel_description\">Notifica quando uma das suas contas Google precisa de configuração adicional antes que seja utilizada ou quando uma conta é incompatível com o microG.</string>\n    <string name=\"auth_action_notification_title\">Ação de conta necessária</string>\n    <string name=\"auth_action_notification_content\">Sua conta Google precisa de configuração adicional.</string>\n    <string name=\"auth_action_step_enable_checkin\">Ativar cadastro do dispositivo</string>\n    <string name=\"auth_action_step_enable_checkin_description\">Seu dispositivo precisa se cadastrar no Google pelo menos uma vez.\\n\\nVocê pode desativar o cadastro do dispositivo no Google após a configuração da conta ser concluída.</string>\n    <string name=\"auth_action_step_enable_gcm\">Ativar o Cloud Messaging</string>\n    <string name=\"auth_action_step_enable_gcm_description\">Você pode desativar o Cloud Messaging depois que configuração da conta ser concluída.</string>\n    <string name=\"auth_action_step_allow_microg_gcm_description\">De acordo com suas preferências, o microG precisa de permissão de você antes que possa se cadastrar para o Cloud Messaging.</string>\n    <string name=\"auth_action_step_enable_lockscreen_description\">Sua conta Google é gerenciada pelo seu trabalho ou instituição escolar. Seu administrador decidiu que dispositivos devem ter um bloqueio de tela seguro antes que possam acessar dados da conta.\\n\\nPor favor configure uma senha, PIN, ou um padrão como seu bloqueio de tela.</string>\n    <string name=\"auth_action_step_perform_content_description\">Clique para realizar esta etapa</string>\n    <string name=\"auth_action_activity_finish\">Concluir</string>\n    <string name=\"auth_action_step_completed_content_description\">Etapa concluída</string>\n    <string name=\"pref_vending_asset_delivery_category\">Asset Delivery do Google Play</string>\n    <string name=\"pref_vending_asset_delivery_switch\">Ativar entrega de recursos sob demanda</string>\n    <string name=\"pref_vending_asset_delivery_summary\">Baixar recursos adicionais ao ser solicitados por apps que utilizam o Play Asset Delivery</string>\n    <string name=\"pref_vending_asset_device_sync_summary\">Aplicativos utilizando o Play Asset Delivery baixarão recursos adicionais baseados nas informações do dispositivo atualmente em uso.</string>\n    <string name=\"pref_vending_asset_device_sync_switch\">Ativar sincronização da info. do dispositivo</string>\n    <string name=\"games_api_access_denied\">Nenhuma conta neste dispositivo pode acessar as APIs do Jogos</string>\n    <string name=\"games_snapshot_choose_btn_text\">selecionar</string>\n    <string name=\"games_delete_snapshot_dialog_cancel\">Cancelar</string>\n    <string name=\"games_achievement_list_title\">Conquistas</string>\n    <string name=\"games_leaderboard_score_empty_text\">Inacreditável! Não há nenhuma maior pontuação pública neste jogo.</string>\n    <string name=\"games_achievement_locked_content_description\">bloqueada</string>\n    <string name=\"games_snapshot_empty_text\">Não há nenhum jogo salvo ainda</string>\n    <string name=\"games_delete_snapshot_dialog_message\">Você tem certeza que deseja apagar este jogo salvo?</string>\n    <string name=\"games_snapshot_delete_btn_text\">apagar</string>\n    <string name=\"games_delete_snapshot_dialog_title\">Apagar jogo salvo</string>\n    <string name=\"games_achievements_empty_text\">Não há conquistas para este jogo</string>\n    <string name=\"games_achievement_unlocked_content_description\">desbloqueada</string>\n    <string name=\"games_leaderboard_list_title\">Ranques</string>\n    <string name=\"games_achievement_extra_text\">%1$s XP</string>\n    <string name=\"games_leaderboard_empty_text\">Nenhuma lista de ranques neste jogo</string>\n    <string name=\"games_leaderboards_score_label\">Pontuação: %1$s</string>\n    <string name=\"games_delete_snapshot_dialog_ok\">OK</string>\n    <string name=\"games_delete_snapshot_error\">Falha ao apagar, por favor tente novamente mais tarde</string>\n    <string name=\"camera_permission_dialog_title\">Permissão de câmera necessária</string>\n    <string name=\"service_name_work_profile\">Perfil de trabalho</string>\n    <string name=\"pref_workprofile_create_account\">Permitir a configuração de um perfil de trabalho</string>\n    <string name=\"pref_vending_split_install_switch\">Instalação de componentes sob demanda</string>\n    <string name=\"pref_vending_feature_delivery\">Feature Delivery do Google Play</string>\n    <string name=\"pref_workprofile_intro\">Ao configurar um perfil de trabalho para o seu local de trabalho ou instituição educacional, a configuração pode tentar se conectar ao Google para baixar apps naquele perfil.</string>\n    <string name=\"pref_workprofile_disclaimer\">É de sua responsabilidade garantir que o seu uso do microG está de acordo com as política da empresa. O microG é fornecido em uma base de melhores esforços e não consegue garantir que se comportará exatamente como esperado.</string>\n    <string name=\"barcode_scanner_brand\">Lido pelo microG no nome de %1$s</string>\n    <string name=\"pref_vending_licensing_split_install_summary\">Permitir que apps baixem e instalem componentes adicionais</string>\n    <string name=\"camera_permission_dialog_button\">OK</string>\n    <string name=\"camera_permission_dialog_message\">Os Serviços microG precisa de acesso à câmera do dispositivo para ler o código para %1$s.\\n\\nPara ativar, conceda a permissão de câmera aos Serviços microG nas Configurações.</string>\n    <string name=\"credentials_assisted_choose_account_error_tips\">Anomalia na conta</string>\n    <string name=\"credentials_assisted_signin_add_account\">Adicionar conta</string>\n    <string name=\"auth_action_reauth_notification_title\">Ação necessária na conta</string>\n    <string name=\"pref_game_accounts_title\">Contas do Google de Jogos</string>\n    <string name=\"pref_auto_create_player\">Permitir integração da conta com o Play Games</string>\n    <string name=\"pref_auto_create_player_intro\">Ao jogar jogos, você precisa usar uma conta do Play Games para se conectar e gravar funções relacionadas a jogos, como conquistas, lista de ranques, arquivos, etc. Ao desativar, as contas do Google que não estão conectadas à uma conta do Play Games não serão cadastradas automaticamente, e o jogo não poderá se conectar e jogar.</string>\n    <string name=\"pref_allow_upload_game_played\">Permitir envio do jogo</string>\n    <string name=\"pref_allow_upload_game_played_summary\">Ao desativar, o jogo não irá mais enviar o estado de jogado do jogo após se conectar, e alguns jogos podem não conseguir se conectar.</string>\n    <string name=\"pref_change_default_game_player\">Alterar a conta para jogos</string>\n    <string name=\"pref_change_default_game_player_summary\">Alterar a conta padrão para jogos e alterar a conta por jogo.</string>\n    <string name=\"pref_delete_game_account_data\">Apagar dados do Play Games</string>\n    <string name=\"pref_delete_game_account_data_summary\">Apagar conta do Play Games e todos os dados, junto com os dados de jogos individuais.</string>\n    <string name=\"games_state_description_signed_out\">Desconectado</string>\n    <string name=\"games_state_description_delete\">Apagar</string>\n    <string name=\"games_change_button_text\">Alterar</string>\n    <string name=\"games_change_default_account_section_title\">Alterar a conta padrão para jogos</string>\n    <string name=\"games_change_default_account_description\">Conta padrão: %1$s</string>\n    <string name=\"games_change_default_account_explanation\">Esta conta é usada para te conectar automaticamente em jogos, salvar seu progresso, e suas configurações. Alterar a conta padrão ou desconectar-se pode causar a perda do seu progresso e das configurações dos jogos que você jogou.</string>\n    <string name=\"games_change_per_game_title\">Alterar a conta por jogo</string>\n    <string name=\"games_change_per_game_description\">Alterar a conta para um jogo específico ou desconectar-se pode causar a perda do seu progresso e das suas configurações para o jogo.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_title\">Selecione uma opção para a nova conta padrão</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_description\">Conta padrão atual: %1$s</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_title\">Alterar a conta padrão somente em jogos novos</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_description\">Você não perderá seu progresso ou suas configurações nos jogos que jogou. Mas o seu progresso será dividido entre contas.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_title\">Alterar a conta padrão para todos os jogos</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_description\">Você pode perder acesso ao seu progresso e às configurações dos jogos que você jogou. Nós reiniciáramos o jogo para aplicar as alterações.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_title\">Desconectar-se de todos os jogos</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_description\">Você pode perder o acesso ao seu progresso e as configurações dos jogos que jogou. Nós reiniciáramos o jogo para aplicar as alterações.</string>\n    <string name=\"games_change_per_game_dialog_title\">Selecione uma opção para este jogo</string>\n    <string name=\"games_change_per_game_dialog_description\">Alterar a conta ou desconectar-se pode causar a perda do seu progresso e das configurações para o jogo</string>\n    <string name=\"games_change_per_game_dialog_option_use_player\">Usar %1$s</string>\n    <string name=\"games_change_per_game_dialog_option_use_player_snackbar_success_message\">Você será conectado com %1$s neste jogo</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out\">Desconectar-se</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out_snackbar_success_message\">Você foi desconectado deste jogo</string>\n    <string name=\"games_change_sign_out_of_all_games_snackbar_success_message\">Você foi desconectado de todos os jogos</string>\n    <string name=\"games_change_default_account_for_all_games_snackbar_success_message\">Você está conectado com %1$s a todos os jogos</string>\n    <string name=\"games_change_default_account_for_new_games_snackbar_success_message\">Você será conectado com %1$s em jogos novos</string>\n    <string name=\"games_account_display_content\">Conta atual: %1$s</string>\n    <string name=\"games_delete_profile_header\">Apagar conta do Play Games e todos os dados</string>\n    <string name=\"games_delete_profile_explanation\">Apagar permanentemente sua conta do Google Play Games, XP, e todos os dados do perfil. Esta ação também pode apagar suas pontuações, progresso (jogos salvos), e configurações nos jogos que jogou.</string>\n    <string name=\"games_delete_profile_button\">Apagar permanentemente</string>\n    <string name=\"games_delete_game_data_header\">Apagar dados de jogos individuais</string>\n    <string name=\"games_delete_game_data_explanation\">Você pode apagar dados de jogos individuais que jogou usando o Google Play Games. Esta ação apaga suas pontuações, progresso (jogos salvos), e configurações para o jogo que selecionou.</string>\n    <string name=\"games_delete_profile_dialog_title\">Você tem certeza que quer apagar esta conta?</string>\n    <string name=\"games_delete_profile_explanation_with_gamer_name\">Apagar permanentemente sua conta do Google Play Games com nome de jogador <b>%1$s</b> (<b>%2$s</b>), com seu XP, e todos os dados do perfil. Esta ação também pode apagar suas pontuações, progresso (jogos salvos), e outras configurações em jogos que jogou.</string>\n    <string name=\"games_delete_profile_dialog_message\">Esta ação não pode ser desfeita.</string>\n    <string name=\"games_delete_profile_fail\">Não foi possível apagar seu perfil. Tente novamente mais tarde.</string>\n    <string name=\"games_delete_game_data_confirm_dialog_title\">Apagar dados de %1$s</string>\n    <string name=\"games_delete_game_data_confirm_dialog_message\">Apagar permanentemente seus dados de %1$s apagará suas pontuações, progresso (jogos salvos), e configurações do jogo no Google Play Games.</string>\n    <string name=\"games_popup_signin_welcome\">E aí, %1$s?</string>\n    <string name=\"pref_auth_two_step_verification_title\">Receber pedidos de verificação de duas etapas</string>\n    <string name=\"pref_auth_two_step_verification_summary\">Ao ativar, o dispositivo pode receber pedidos de verificação de duas etapas do Google (Cloud Messaging é necessário).</string>\n    <string name=\"service_name_google_location_sharing\">Compartilhamento de localização do Google</string>\n    <string name=\"location_sharing_description\">Gerencie seu compartilhamento de localização em tempo real entre apps e serviços do Google a partir deste dispositivo</string>\n    <string name=\"location_sharing_learn_more\">Saiba mais sobre o compartilhamento de localização</string>\n    <string name=\"location_sharing_switch_text\">Usar compartilhamento de localização</string>\n    <string name=\"location_sharing_turn_off_notify_hint\">Se desativar o compartilhamento de localização deste dispositivo, as pessoas com quais você compartilha não serão notificadas.</string>\n    <string name=\"location_sharing_off_previous_hint\">Apenas a sua última localização compartilhada estará disponível até que você ative novamente.</string>\n    <string name=\"location_sharing_disabled\">Nenhum compartilhamento de localização ativo para esta conta</string>\n    <string name=\"location_sharing_turn_on_hint\">Quando você começar a compartilhar sua localização a partir de um app ou serviço do Google, você pode gerenciar o compartilhamento de localização por aqui.\\n\\nPara compartilhar sua localização, vá ao Google Maps ou Family Link.</string>\n    <string name=\"location_sharing_turn_off_title\">Desativar compartilhamento de localização</string>\n    <string name=\"location_sharing_turn_off_hint\">Você ainda pode estar compartilhando sua localização em outros dispositivos conectados à mesma conta do Google ou de apps que não são do Google. Certifique suas configurações de compartilhamento de localização em qualquer lugar que ele pode se aplicar.\\n\\nAs pessoas com quais você compartilha continuarão vendo sua última localização compartilhada.</string>\n    <string name=\"location_sharing_turn_off_cancel\">Manter ativado</string>\n    <string name=\"location_sharing_turn_off_confirm\">Desativar</string>\n    <string name=\"location_sharing_confirm_dialog_title\">Ativar compartilhamento de localização</string>\n    <string name=\"location_sharing_confirm_dialog_text\">As pessoas com quais você compartilha sua localização sempre conseguem ver:\\n· Seu nome e foto\\n· A localização recente do seu dispositivo, mesmo quando não está usando um serviço do Google\\n· O nível da bateria do seu dispositivo, até mesmo quando está carregando\\n· Seu horário de chegada e saída, se adicionarem uma notificação de compartilhamento de localização</string>\n    <string name=\"family_management_title\">Família</string>\n    <string name=\"family_management_retry\">Tentar novamente</string>\n    <string name=\"family_management_load_error\">Carregamento de conteúdo falhou</string>\n    <string name=\"family_management_toolbar_back\">Voltar</string>\n    <string name=\"family_management_toolbar_more\">Mais</string>\n    <string name=\"family_management_exit_family_group\">Sair do grupo familiar</string>\n    <string name=\"family_management_delete_family_group\">Apagar um grupo familiar</string>\n    <string name=\"family_management_leave_family_password_title\">Confirme a senha para sair do grupo familiar</string>\n    <string name=\"family_management_delete_family_password_title\">Confirme a senha para apagar o grupo familiar</string>\n    <string name=\"family_management_remove_member_password_title\">Confirme a senha para remover %s</string>\n    <string name=\"family_management_invite_family_member\">Convidar membros da família</string>\n    <string name=\"family_management_invite_slots_left\">%1$d convites restantes</string>\n    <string name=\"family_management_cancel_invite\">Cancelar convite</string>\n    <string name=\"family_management_cancel_invite_success\">Convite cancelado com sucesso</string>\n    <string name=\"family_management_cancel_invite_error\">Houve um problema ao cancelar o convite. Tente novamente.</string>\n    <string name=\"family_management_remove_member\">Remover membro</string>\n    <string name=\"family_management_member_removed_success\">%s foi removido do seu grupo familiar</string>\n    <string name=\"family_management_member_remove_failed\">Houve um problema ao remover %s. Tente novamente.</string>\n    <string name=\"family_management_leave_family_error_message\">Houve um problema ao sair do grupo familiar. Tente novamente.</string>\n    <string name=\"family_management_exist_group_success\">Você saiu do seu grupo familiar…</string>\n    <string name=\"family_management_delete_group_success\">Grupo familiar apagado</string>\n    <string name=\"family_management_delete_group_failure\">Falha ao apagar grupo familiar</string>\n    <string name=\"family_management_delete_group_cancel\">Cancelar</string>\n    <string name=\"family_management_delete_group_confirm\">OK</string>\n    <string name=\"family_management_input_pwd\">Digite sua senha</string>\n    <string name=\"family_management_invite_sent_date_format\">Convite enviado para %s</string>\n    <string name=\"family_management_invite_send\">Convite enviado</string>\n    <string name=\"family_management_pwd_error\">Senha errada, digite novamente</string>\n    <string name=\"pref_app_install_settings_title\">Configurações do instalador de apps</string>\n    <string name=\"pref_app_install_switch_title\">Permitir instalação de apps</string>\n    <string name=\"pref_app_install_other_apps_note\">A autorização permite a instalação de apps fornecidos por outras fontes.</string>\n    <string name=\"pref_app_install_permission_instruction\">Para certificar-se que seus apps instalados funcionem direito, autorize que o Acompanhante do microG instale apps baixados de outras fontes.</string>\n    <string name=\"prefcat_app_install_list_title\">Apps usando o instalador de apps</string>\n    <string name=\"service_name_device_attestation\">Atestação de dispositivo</string>\n    <string name=\"prefcat_device_attestation_apps_title\">Apps usando a atestação de dispositivo</string>\n    <string name=\"pref_device_attestation_app_allow_requests_title\">Permitir solicitações</string>\n    <string name=\"pref_device_attestation_app_allow_requests_summary\">Permita que o app solicite um atestado do dispositivo</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-ro/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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  --><resources>\n    <string name=\"permission_service_blogger_label\">Blogger</string>\n    <string name=\"permission_service_blogger_description\">Permite aplicației să acceseze Blogger prin orice cont Google asociat.</string>\n    <string name=\"permission_service_adwords_label\">AdWords</string>\n    <string name=\"permission_service_gbase_description\">Permite aplicației să acceseze Google Base prin orice cont Google asociat.</string>\n    <string name=\"permission_service_all_label\">Toate serviciile Google</string>\n    <string name=\"permission_service_finance_description\">Permite aplicației să acceseze Google Finance prin orice cont Google asociat.</string>\n    <string name=\"permission_service_android_label\">Servicii Android</string>\n    <string name=\"permission_service_cp_label\">Contacte</string>\n    <string name=\"permission_service_adsense_description\">Permite aplicației să acceseze AdSense prin orice cont Google asociat.</string>\n    <string name=\"permission_service_grandcentral_description\">Permite aplicației să acceseze Google Voice prin orice cont Google asociat.</string>\n    <string name=\"permission_service_cl_description\">Permite aplicației să acceseze Calendar Google prin orice cont Google asociat.</string>\n    <string name=\"permission_service_cl_label\">Calendar Google</string>\n    <string name=\"permission_service_android_description\">Permite aplicației să acceseze serviciile Android prin orice cont Google asociat.</string>\n    <string name=\"permission_service_adsense_label\">AdSense</string>\n    <string name=\"permission_service_all_description\">Permite aplicației să acceseze toate serviciile Google prin orice cont Google asociat.</string>\n    <string name=\"permission_service_dodgeball_label\">Dodgeball</string>\n    <string name=\"permission_service_adwords_description\">Permite aplicației să acceseze AdWords prin orice cont Google asociat.</string>\n    <string name=\"permission_service_gbase_label\">Google Base</string>\n    <string name=\"permission_service_groups2_label\">Google Groups</string>\n    <string name=\"permission_service_ah_description\">Permite aplicației să acceseze Google App Engine prin orice cont Google asociat.</string>\n    <string name=\"permission_service_ah_label\">Motor Google App</string>\n    <string name=\"permission_service_dodgeball_description\">Permite aplicației să acceseze Dodgeball prin orice cont Google asociat.</string>\n    <string name=\"permission_service_cp_description\">Permite aplicației să acceseze Contacte prin orice cont Google asociat.</string>\n    <string name=\"permission_service_grandcentral_label\">Google Voice</string>\n    <string name=\"permission_service_finance_label\">Google Finance</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense\">Vizualizează și gestionează datele AdSense</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue.consumer\">Execută sarcinile din TaskQueue</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tracks\">Google Maps Tracks API, acest domeniu permite accesul de citire și scriere la datele proiectului.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.full_control\">Gestionează datele și permisiunile în Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase.readonly\">vizualizează contul Freebase</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.readonly\">Vizualizează fișierele și documentele din Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.readonly\">Citește toate resursele și metadatele acestora - fără operațiuni de scriere.</string>\n    <string name=\"permission_service_sitemaps_label\">Instrumente Google Webmaster</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate.readonly\">Vizualizează joburile Google Coordinate</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.file\">Vizualizează și gestionează fișierele Google Drive pe care le-ai deschis sau creat cu această aplicație</string>\n    <string name=\"permission_service_speechpersonalization_label\">Recunoaștere personalizată a vorbirii</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.appdata\">Permite accesul la dosarul Application Data</string>\n    <string name=\"permission_service_youtube_label\">YouTube</string>\n    <string name=\"permission_service_news_label\">Google News</string>\n    <string name=\"permission_service_speechpersonalization_description\">Permite aplicației să acceseze Recunoașterea vocală personalizată prin orice cont Google asociat.</string>\n    <string name=\"permission_service_sitemaps_description\">Permite aplicației să acceseze Instrumentele Google Webmaster prin orice cont Google asociat.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue\">Gestionează sarcinile</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine\">Vizualizează și gestionează datele Google Maps Engine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine.readonly\">Vizualizează datele Google Maps Engine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_activity\">Vizualizează istoricul activității Google Apps</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive\">Vizualizează și gestionează fișierele și documentele din Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics.readonly\">Vizualizează datele Google Analytics</string>\n    <string name=\"permission_service_writely_description\">Permite aplicației să acceseze Google Docs prin orice cont Google asociat.</string>\n    <string name=\"permission_service_writely_label\">Documente Google</string>\n    <string name=\"permission_service_orkut_label\">Orkut</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_prediction\">Gestionează datele în API-ul Google Prediction</string>\n    <string name=\"permission_service_youtube_description\">Permite aplicației să acceseze YouTube prin orice cont Google asociat.</string>\n    <string name=\"permission_service_wise_label\">Foi de calcul Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_structuredcontent\">Acces de citire/scriere la Shopping Content API.</string>\n    <string name=\"permission_service_speech_description\">Permite aplicației să acceseze Căutarea vocală prin orice cont Google asociat.</string>\n    <string name=\"permission_service_knol_description\">Permite aplicației să acceseze Knol prin orice cont Google asociat.</string>\n    <string name=\"permission_service_wifi_label\">Google Wi-Fi</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.me\">Cunoaște cine ești pe Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.login\">Cunoaște numele, informațiile de bază și lista persoanelor cu care ești conectat pe Google+</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics.readonly\">Vizualizează rapoarte YouTube Analytics pentru conținutul YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics\">Vizualizează și gestionează datele Google Analytics</string>\n    <string name=\"permission_service_health_label\">Sănătate Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut\">Gestionează activitatea Orkut</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.apps.readonly\">Vizualizează aplicațiile Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.compose\">Creează, citește, actualizează și șterge schițe. Trimite mesaje și schițe.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger.readonly\">Vizualizează contul Blogger</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.licensing\">Acces de citire/scriere la API-ul License Manager.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery\">Vizualizează și gestionează datele în Google BigQuery</string>\n    <string name=\"permission_service_health_description\">Permite aplicației să acceseze Google Health prin orice cont Google asociat.</string>\n    <string name=\"permission_service_jotspot_description\">Permite aplicației să acceseze JotSpot prin orice cont Google asociat.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_dfareporting\">Vizualizează și gestionează rapoartele DoubleClick for Advertisers</string>\n    <string name=\"permission_service_notebook_label\">Google Notebook</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_urlshortener\">Gestionează adresele URL scurte goo.gl</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube\">Gestionează contul YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery.readonly\">Vizualizează datele în Google BigQuery</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order\">Pentru administratorii și utilizatorii revânzători acces de citire/scriere atunci când testează în sandbox-ul API sau acces de citire/scriere când apelează direct o operație API.</string>\n    <string name=\"permission_service_local_description\">Permite aplicației să acceseze Google Maps prin orice cont Google asociat.</string>\n    <string name=\"permission_service_speech_label\">Căutare vocală</string>\n    <string name=\"permission_service_groups2_description\">Permite aplicației să acceseze Grupuri Google prin orice cont Google asociat.</string>\n    <string name=\"permission_service_local_label\">Google Maps</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.buyer\">Gestionează configurația contului de cumpărător Ad Exchange</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gcm_for_chrome\">CloudMessaging pentru Chrome</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller\">Vizualizează și gestionează datele Ad Exchange</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_shoppingapi\">Vizualizează datele despre produse</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsensehost\">Vizualizează și gestionează datele de gazdă AdSense și conturile asociate</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.scripts\">Modifică comportamentul scripturilor Google Apps Script</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_write\">Gestionează datele în Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mobilemaps.firstparty\">Vizualizează și gestionează Google Maps pentru experiență mobilă</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appstate\">Domeniul de aplicare pentru utilizarea serviciului App State.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics_monetary.readonly\">Vizualizează rapoarte monetare YouTube Analytics pentru conținutul YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.city\">Gestionează locația la nivel de oraș și istoricul locațiilor</string>\n    <string name=\"permission_service_talk_label\">Google Talk</string>\n    <string name=\"permission_service_ig_label\">iGoogle</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks\">Gestionează sarcinile</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.settings\">Vizualizează și gestionează setările Google Apps Group</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute.readonly\">Vizualizează resursele Google Compute Engine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller.readonly\">Vizualizează datele Ad Exchange</string>\n    <string name=\"permission_service_ig_description\">Permite aplicației să acceseze iGoogle prin orice cont Google asociat.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables\">Gestionează Fusion Tables</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan.readonly\">Vizualizează datele GAN</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification.verify_only\">Gestionează noile verificări ale site-urilor cu Google</string>\n    <string name=\"permission_service_orkut_description\">Permite aplicației să acceseze orkut prin orice cont Google asociat.</string>\n    <string name=\"permission_service_sierrasandbox_label\">Conturi Google Checkout Sandbox</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.metadata.readonly\">Vizualizează metadatele fișierelor și documentelor din Google Drive</string>\n    <string name=\"permission_service_sierra_description\">Permite aplicației să acceseze conturile Google Checkout prin orice cont Google asociat.</string>\n    <string name=\"permission_service_lh2_description\">Permite aplicației să acceseze Picasa Web Albums prin orice cont Google asociat.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_games\">Domeniul de aplicare pentru accesarea datelor din Jocuri Google Play.</string>\n    <string name=\"permission_service_wifi_description\">Permite aplicației să acceseze Google Wi-Fi prin orice cont Google asociat.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_only\">Vizualizează datele în Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar.readonly\">Vizualizează calendarele</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appengine.admin\">Domeniul de aplicare al motorului de aplicații.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_androidpublisher\">Acces la Google Play Android Developer</string>\n    <string name=\"permission_service_notebook_description\">Permite aplicației să acceseze Google Notebook prin orice cont Google asociat.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification\">Gestionează lista de site-uri și domenii pe care le controlezi</string>\n    <string name=\"permission_service_YouTubeUser_label\">Nume de utilizator YouTube</string>\n    <string name=\"permission_service_mail_label\">Google Mail</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.install\">Domeniu special folosit pentru a permite utilizatorilor să aprobe instalarea unei aplicații</string>\n    <string name=\"permission_service_news_description\">Permite aplicației să acceseze Știri Google prin orice cont Google asociat.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables.readonly\">Vizualizează tabelele Fusion</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.modify\">Toate operațiunile de citire/scriere, cu excepția ștergerii imediate și permanente a firelor și mesajelor, ocolind Coșul de gunoi.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.city\">Gestionează locația la nivel de oraș</string>\n    <string name=\"permission_service_wise_description\">Permite aplicației să acceseze Foile de calcul Google prin orice cont Google asociat.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.migration\">Acces de citire și scriere la API-ul Groups Migration.</string>\n    <string name=\"permission_service_sierrasandbox_description\">Permite aplicației să acceseze conturile Google Checkout Sandbox prin orice cont Google asociat.</string>\n    <string name=\"permission_service_print_description\">Permite aplicației să acceseze Google Căutare de cărți prin orice cont Google asociat.</string>\n    <string name=\"permission_service_mail_description\">Permite aplicației să acceseze Google Mail prin orice cont Google asociat.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.email\">Vizualizează adresa de e-mail</string>\n    <string name=\"permission_service_jotspot_label\">JotSpot</string>\n    <string name=\"permission_service_lh2_label\">Albumuri Web Picasa</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase\">Conectare la Freebase cu contul tău</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_glass.timeline\">Sfera de aplicare Glass timeline</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate\">Vizualizează și gestionează joburile Google Maps Coordinate</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute\">Vizualizează și gestionează resursele Google Compute Engine</string>\n    <string name=\"permission_service_sierra_label\">Conturi Google Checkout</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.profile\">Vizualizează informații de bază despre contul tău</string>\n    <string name=\"permission_service_YouTubeUser_description\">Permite aplicației să acceseze numele de utilizatori YouTube utilizate cu orice cont Google asociat.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar\">Gestionează calendarele</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_books\">Gestionează cărțile</string>\n    <string name=\"permission_service_sierraqa_description\">Permite aplicației să acceseze conturile Google Checkout QA prin orice cont Google asociat.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan\">Gestionează datele GAN</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut.readonly\">Vizualizează datele Orkut</string>\n    <string name=\"permission_service_talk_description\">Permite aplicației să acceseze Google Talk prin orice cont Google asociat.</string>\n    <string name=\"permission_service_sierraqa_label\">Conturi Google Checkout QA</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks.readonly\">Vizualizează sarcinile</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.best\">Gestionează cea mai bună locație disponibilă și istoricul locațiilor</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense.readonly\">Vizualizează datele AdSense</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.readonly\">Vizualizează contul YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_cloudprint\">Vizualizează și gestionează datele Google Cloud Print</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order.readonly\">În plus față de domeniul OAuth de citire/scriere generală, utilizează domeniul OAuth numai pentru citire atunci când se preiau datele clientului.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger\">Gestionează contul Blogger</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps_reporting_audit.readonly\">Acces la Admin Audit API ReadOnly</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.best\">Gestionează cea mai bună locație disponibilă</string>\n    <string name=\"permission_service_print_label\">Google Book Search</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtubepartner\">Vizualizează și gestionează materialele și conținutul asociat pe YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.upload\">Gestionează videoclipurile de pe YouTube</string>\n    <string name=\"permission_service_knol_label\">Knol</string>\n    <string name=\"perm_activity_recognition_label\">Recunoașterea activității</string>\n    <string name=\"perm_activity_recognition_description\">Permite unei aplicații să primească actualizări periodice ale nivelului de activitate de la Google, de exemplu, dacă mergi pe jos, conduci, mergi cu bicicleta sau staționezi.</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-ro/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2017 microG Project Team\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  --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <plurals name=\"gcm_registered_apps_counter\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> aplicație înregistrată</item>\n        <item quantity=\"few\"><xliff:g example=\"123\">%1$d</xliff:g> aplicații înregistrate</item>\n        <item quantity=\"other\"><xliff:g example=\"123\">%1$d</xliff:g> aplicații înregistrate</item>\n    </plurals>\n    <plurals name=\"cond_perm_action\">\n        <item quantity=\"one\">Solicită permisiunea lipsă</item>\n        <item quantity=\"few\">Solicită permisiunile lipsă</item>\n        <item quantity=\"other\">Solicită permisiunile lipsă</item>\n    </plurals>\n    <plurals name=\"pref_unifiednlp_summary\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> modul de navigație configurat</item>\n        <item quantity=\"few\"><xliff:g example=\"3\">%1$d</xliff:g> module de navigație configurate</item>\n        <item quantity=\"other\"><xliff:g example=\"3\">%1$d</xliff:g> module de navigație configurate</item>\n    </plurals>\n    <plurals name=\"cond_perm_summary\">\n        <item quantity=\"one\">Nu este acordată permisiunea necesară pentru funcționarea corectă a Serviciilor microG.</item>\n        <item quantity=\"few\">Nu sunt acordate permisiunile necesare pentru funcționarea corectă a Serviciilor microG.</item>\n        <item quantity=\"other\">Nu sunt acordate permisiunile necesare pentru funcționarea corectă a Serviciilor microG.</item>\n    </plurals>\n</resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-ro/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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  --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"gms_app_name\">Servicii microG</string>\n    <string name=\"gms_settings_name\">Setări microG</string>\n    <string name=\"just_a_sec\">Doar o secundă…</string>\n    <string name=\"google_account_label\">Google</string>\n    <string name=\"ask_permission_tos\">Continuând, permiți acestei aplicații și Google să utilizeze informațiile tale în conformitate cu condițiile de utilizare și politicile de confidențialitate ale lor.</string>\n    <string name=\"ask_scope_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> ar dori să:</string>\n    <string name=\"ask_service_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> ar dori să utilizeze:</string>\n    <string name=\"account_manager_title\">Gestionare cont Google</string>\n    <string name=\"sorry\">Ne pare rău…</string>\n    <string name=\"no_network_error_desc\">Nu ai o conexiune la rețea.\n\\n\n\\nAceasta ar putea fi o problemă temporară, sau dispozitivul Android nu are o conexiune de date. Încearcă din nou atunci când ești conectat la o rețea de telefonie mobilă, sau o rețea Wi-Fi.</string>\n    <string name=\"auth_general_error_desc\">A fost o problemă de comunicare cu serverele Google.\n\\n\n\\nÎncearcă din nou mai târziu.</string>\n    <string name=\"auth_finalize\">Dispozitivul contactează Google pentru a salva informațiile în contul tău.\n\\n\n\\nAcest lucru poate dura câteva minute.</string>\n    <string name=\"allow\">Permite</string>\n    <string name=\"deny\">Refuză</string>\n    <string name=\"auth_notification_title\">Autentificarea este necesară</string>\n    <string name=\"auth_notification_content\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> necesită o autorizare pentru a accesa contul Google.</string>\n    <string name=\"perm_status_broadcast_label\">ascultă emisiunile de stare interne</string>\n    <string name=\"perm_c2dm_receive_label\">ascultă mesajele C2DM</string>\n    <string name=\"perm_c2dm_send_label\">trimite mesaje C2DM altor aplicaţii</string>\n    <string name=\"prefcat_components\">Componente</string>\n    <string name=\"prefcat_location_service\">Servicii de localizare</string>\n    <string name=\"prefcat_services\">Servicii de fundal</string>\n    <string name=\"pref_auth_trust_google_title\">Ai încredere în Google pentru permisiunile aplicației</string>\n    <string name=\"pref_auth_trust_google_summary\">Când este dezactivată, utilizatorul este întrebat înainte ca cererea de autorizare a unei aplicații să fie trimisă la Google. Unele aplicații nu vor reuși să utilizeze contul Google, dacă această opțiune este dezactivată.</string>\n    <string name=\"pref_checkin_enable_summary\">\\\"Înregistrarea dispozitivului\\\" este un proces ascuns care este utilizat pentru a crea un identificator unic pentru serviciile Google. Serviciile microG înlătură alte date de identificare cu excepția numelui contului Google.</string>\n    <string name=\"pref_gcm_enable_mcs_summary\">Mesageria Google Cloud este un furnizor de notificări de tip push utilizat de multe aplicații. Pentru a utiliza trebuie să activezi \\\"Înregistrarea dispozitivului\\\".</string>\n    <string name=\"auth_sign_in\">Conectare</string>\n    <string name=\"signin_picker_title\">Alege un cont</string>\n    <string name=\"signin_picker_subtitle\">pentru a continua la <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"signin_confirm_title\">Permite conectarea la <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"signin_picker_add_account_label\">Adaugă un alt cont</string>\n    <string name=\"auth_connecting\">Dispozitivul stabilește o conexiune la serverele Google pentru a te conecta.\\n\\nAcest lucru poate dura câteva secunde.</string>\n    <string name=\"signin_confirm_button_text\">Permite și distribuie</string>\n    <string name=\"auth_before_connect\">O aplicație de pe dispozitivul tău încearcă să se conecteze la un cont Google. \\n\\nDacă acest lucru a fost intenționat, utilizează butonul <b>Conectare</b> pentru a te conecta la pagina de conectare Google, dacă nu, apasă <b>Anulare</b> pentru a reveni la aplicația care a generat acest dialog.</string>\n    <string name=\"gms_settings_summary\">Configurează serviciile microG.</string>\n    <string name=\"pref_device_registration_import_custom_profile_title\">Importă un profil personalizat</string>\n    <string name=\"pref_safetynet_recent_request_type\">Tipul solicitării</string>\n    <string name=\"pref_recaptcha_enterprise_test_title\">Testează ReCAPTCHA Enterprise</string>\n    <string name=\"pref_gcm_confirm_new_apps_title\">Confirmarea aplicațiilor noi</string>\n    <string name=\"gcm_app_error_unregistering\">Eroare la anularea înregistrării</string>\n    <string name=\"pref_safetynet_test_title\">Testează atestarea SafetyNet</string>\n    <string name=\"pref_gcm_heartbeat_summary\">Interval în secunde pentru utilizarea serverelor Google. Mărirea acestui număr va reduce consumul bateriei, dar poate provoca întârzieri în mesajele push.\n\\nÎnvechit, va fi modificat în următoarea ediție.</string>\n    <string name=\"checkin_last_registration\">Ultima înregistrare: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_no_message_yet\">Nu s-a primit niciun mesaj până acum</string>\n    <string name=\"pref_about_title\">Despre serviciile microG</string>\n    <string name=\"signin_subtext_policy_privacy\">politica de confidențialitate</string>\n    <string name=\"pick_place_title\">Alege un loc</string>\n    <string name=\"games_info_content\">Pentru a utiliza Jocuri Play, este necesar să instalezi aplicația Jocuri Google Play. Aplicația poate continua fără Jocuri Play, dar este posibil să se comporte neașteptat.</string>\n    <string name=\"pref_safetynet_test_no_result\">Nici un rezultat</string>\n    <string name=\"safetynet_intro\">Google SafetyNet este un sistem de certificare a dispozitivului, care asigură că dispozitivul este securizat corespunzător și compatibil cu Android CTS. Unele aplicații folosesc SafetyNet din motive de securitate sau ca o condiție prealabilă pentru protecția împotriva manipulărilor.\n\\n\n\\nmicroG GmsCore conține o implementare gratuită a SafetyNet, dar serverul oficial necesită ca cererile SafetyNet să fie semnate folosind sistemul proprietar DroidGuard.</string>\n    <string name=\"gcm_unregister_after_deny_message\">Ai refuzat înregistrarea unei aplicații pentru notificări push care este deja înregistrată.\n\\nDorești să anulezi acum, astfel încât să nu mai primească mesaje push în viitor\\?</string>\n    <string name=\"self_check_resolution_correct_sig\">Fie aplicația <xliff:g example=\"F-Droid\">%1$s</xliff:g> nu este compatibilă, sau falsificarea semnăturii nu este activă pentru aceasta. Verifică documentația despre ce aplicații și ROM-uri sunt compatibile.</string>\n    <string name=\"self_check_cat_fake_sig\">Suport pentru falsificarea semnăturii</string>\n    <string name=\"perm_gsf_read_gservices_label\">citește configurația serviciului Google</string>\n    <string name=\"pref_device_registration_import_custom_profile_summary\">Importă profilul dispozitivului din fișier</string>\n    <string name=\"network_type_roaming\">Roaming</string>\n    <string name=\"pref_safetynet_recent_copy_json\">Copiază datele JSON JWS</string>\n    <string name=\"pref_test_summary_failed\">Eroare: %s</string>\n    <string name=\"pref_auth_visible_summary\">Când este activată, toate aplicațiile de pe acest dispozitiv vor putea vedea adresa de e-mail a conturilor Google fără autorizare prealabilă.</string>\n    <string name=\"network_type_wifi\">Wi-Fi</string>\n    <string name=\"gcm_unregister_app\">Anulează înregistrarea</string>\n    <string name=\"gcm_last_message_at\">Ultimul mesaj: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"pref_safetynet_recent_advice\">Sfat</string>\n    <string name=\"push_notifications_summary_values_seconds\">%s secunde</string>\n    <string name=\"prefcat_configuration\">Configurare</string>\n    <string name=\"place_picker_location_lat_lng\">(%1$.7f, %2$.7f)</string>\n    <string name=\"prefcat_google_services\">Servicii Google</string>\n    <string name=\"pref_safetynet_test_invalid_json\">JSON nevalid</string>\n    <string name=\"service_name_mcs\">Mesaje în cloud</string>\n    <string name=\"menu_clear_recent_requests\">Șterge solicitările recente</string>\n    <string name=\"gcm_unregister_confirm_title\">Anulezi înregistrarea <xliff:g example=\"F-Droid\">%1$s</xliff:g>\\?</string>\n    <string name=\"pref_safetynet_recent_recaptcha_enterprise_summary\">ReCaptcha Enterprise: %s</string>\n    <string name=\"pref_safetynet_recent_cat_request\">Datele solicitării</string>\n    <string name=\"pref_push_app_wake_for_delivery_summary\">Se pornește aplicația în fundal pentru a primi mesajele push.</string>\n    <string name=\"pref_safetynet_recent_attestation_summary\">Atestare: %s</string>\n    <string name=\"prefcat_safetynet_apps_title\">Aplicații ce utilizează SafetyNet</string>\n    <string name=\"safetynet_enable_switch\">Permite atestarea dispozitivului</string>\n    <string name=\"pref_safetynet_test_integrity_failed\">Integritatea a eșuat</string>\n    <string name=\"push_notifications_summary_automatic\">PORNIT / Automat: %s</string>\n    <string name=\"pref_device_registration_serial_title\">Număr de serie</string>\n    <string name=\"checkin_enable_switch\">Înregistrare dispozitiv</string>\n    <string name=\"place_picker_nearby_places\">Locuri din apropiere</string>\n    <string name=\"pref_safetynet_test_cts_failed\">CTS a eșuat</string>\n    <string name=\"push_notifications_summary_manual\">PORNIT / Manual: %s</string>\n    <string name=\"profile_name_auto\">Automat: %s</string>\n    <string name=\"push_notifications_summary_values_minutes\">%s minute</string>\n    <string name=\"perm_provision_label\">furnizarea de servicii microG</string>\n    <string name=\"service_name_snet\">Google SafetyNet</string>\n    <string name=\"self_check_cat_system\">Sistem</string>\n    <string name=\"pick_place_desc\">Selectorul de locuri nu este încă disponibil.</string>\n    <string name=\"prefcat_test\">Testare</string>\n    <string name=\"gcm_network_state_connected\">Conectat <xliff:g example=\"2 hours ago\">%1$s</xliff:g></string>\n    <string name=\"gcm_registered\">Înregistrat</string>\n    <string name=\"pref_more_settings\">Mai multe</string>\n    <string name=\"pref_auth_include_android_id_summary\">Când este dezactivată, solicitările de autentificare nu vor fi legate de înregistrarea dispozitivului, ceea ce poate permite dispozitivelor neautorizate să se conecteze, dar poate avea consecințe neprevăzute.</string>\n    <string name=\"pref_gcm_heartbeat_title\">Intervalul de conectare a mesajelor în cloud</string>\n    <string name=\"pref_safetynet_test_integrity_cts_passed\">Integritatea și CTS au trecut</string>\n    <string name=\"pref_safetynet_recent_uses\">Utilizări recente</string>\n    <string name=\"pref_droidguard_unsupported_summary\">Execuția DroidGuard nu este acceptată pe acest dispozitiv. Serviciile SafetyNet se pot comporta greșit.</string>\n    <string name=\"self_check_pkg_vending\">Companion microG / Magazin Play</string>\n    <string name=\"pref_safetynet_recent_nonce\">Cod unic (hexadecimal)</string>\n    <string name=\"self_check_resolution_battery_optimizations\">Atinge aici pentru a dezactiva optimizările bateriei. Nerespectarea acestui lucru poate duce la un comportament incorect al aplicațiilor.</string>\n    <string name=\"safetynet_last_run_at\">Ultima utilizare: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"pref_gcm_confirm_new_apps_summary\">Se întreabă înainte de a înregistra o nouă aplicație pentru a primi notificări push</string>\n    <string name=\"pref_push_app_wake_for_delivery_title\">Pornește aplicația la mesaj push</string>\n    <string name=\"cond_gcm_bat_action\">Ignoră optimizările</string>\n    <string name=\"pref_about_summary\">Informații despre versiune și biblioteci utilizate</string>\n    <string name=\"place_picker_select_title\">Selectează această locație</string>\n    <string name=\"perm_provision_description\">Permite aplicației să configureze servicii microG fără interacțiunea utilizatorului</string>\n    <string name=\"pref_safetynet_recent_recaptcha_summary\">ReCaptcha: %s</string>\n    <string name=\"gcm_enable_switch\">Primește notificări push</string>\n    <string name=\"perm_extended_access_label\">Acces extins la serviciile Google</string>\n    <string name=\"network_type_mobile\">Rețea de telefonie mobilă</string>\n    <string name=\"pref_test_summary_passed\">Toate testele au trecut</string>\n    <string name=\"push_notifications_summary_off\">OPRIT</string>\n    <string name=\"self_check_cat_gms_packages\">Pachete instalate</string>\n    <string name=\"cond_gcm_bat_summary\">Ai activat Mesageria Cloud, dar optimizarea bateriei este activată pentru serviciile microG. Pentru ca notificările push să ajungă, ar trebui să dezactivezi optimizarea bateriei.</string>\n    <string name=\"pref_info_status\">Stare</string>\n    <string name=\"gcm_allow_app_popup\">Permiți ca <xliff:g example=\"F-Droid\">%1$s</xliff:g> să se înregistreze pentru notificări push\\?</string>\n    <string name=\"games_title\">Jocuri Google Play</string>\n    <string name=\"pref_safetynet_recent_response_status\">Starea răspunsului</string>\n    <string name=\"self_check_name_fake_sig_perm\">Sistemul are suport pentru falsificarea semnăturii:</string>\n    <string name=\"pref_gcm_apps_summary\">Lista aplicațiilor înregistrate în prezent pentru Mesageria Cloud.</string>\n    <string name=\"pref_auth_visible_title\">Permite aplicațiilor să găsească conturile</string>\n    <string name=\"pref_device_registration_android_id\">ID Android</string>\n    <string name=\"self_check_resolution_app_installed\">Instalează aplicația <xliff:g example=\"F-Droid\">%1$s</xliff:g> sau una compatibilă. Verifică documentația despre ce aplicații sunt compatibile.</string>\n    <string name=\"network_type_other\">Alte rețele</string>\n    <string name=\"gcm_network_state_disconnected\">Deconectat</string>\n    <string name=\"service_name_checkin\">Înregistrarea dispozitivului Google</string>\n    <string name=\"pref_device_registration_select_profile_title\">Selectează profilul</string>\n    <string name=\"self_check_pkg_gsf\">Servicii Framework microG</string>\n    <string name=\"pref_gcm_apps_title\">Aplicații care folosesc Mesageria Cloud</string>\n    <string name=\"prefcat_about\">Despre</string>\n    <string name=\"gcm_unregister_confirm_message\">Unele aplicații nu se reînregistrează automat și/sau nu oferă o opțiune de a face acest lucru manual. Este posibil ca aceste aplicații să nu funcționeze corect după anularea înregistrării.\n\\nContinui\\?</string>\n    <string name=\"gcm_registered_since\">Înregistrat din: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"pref_test_summary_warn\">Avertizare: %s</string>\n    <string name=\"checkin_not_registered\">Neînregistrat</string>\n    <string name=\"pref_droidguard_operation_mode\">Mod de operare</string>\n    <string name=\"profile_name_real\">Real</string>\n    <string name=\"prefcat_push_apps_unregistered_title\">Aplicații neînregistrate</string>\n    <string name=\"self_check_resolution_perm_granted\">Acesta este un indicator puternic că ROM-ul acceptă falsificarea semnăturilor, dar necesită acțiuni suplimentare pentru a-l activa. Verifică documentația cu privire la pașii care ar putea fi necesari.</string>\n    <string name=\"cond_gcm_bat_title\">Optimizarea bateriei este activată</string>\n    <string name=\"pref_add_account_title\">Cont</string>\n    <string name=\"signin_subtext_policy\">Înainte de a utiliza această aplicație, examinează %1$s și %2$s.</string>\n    <string name=\"gcm_not_registered\">Neînregistrat</string>\n    <string name=\"pref_safetynet_recent_copied\">Copiat în clipboard!</string>\n    <string name=\"perm_gtalk_svc_label\">face schimb de mesaje și primește notificări de sincronizare de la serverele Google</string>\n    <string name=\"gcm_messages_counter\">Mesaje: <xliff:g example=\"123\">%1$d</xliff:g> (<xliff:g example=\"12345\">%2$d</xliff:g> bytes)</string>\n    <string name=\"self_check_name_system_spoofs\">Sistemul falsifică semnătura:</string>\n    <string name=\"prefcat_push_apps_title\">Aplicații ce folosesc notificări push</string>\n    <string name=\"prefs_account\">Preferințele contului</string>\n    <string name=\"self_check_pkg_gms\">Servicii microG</string>\n    <string name=\"lacking_permission_toast\">Serviciile microG: Lipsește permisiunea <xliff:g example=\"have full network acccess\">%1$s</xliff:g></string>\n    <string name=\"profile_name_user\">Personalizat: %s</string>\n    <string name=\"self_check_name_perm_granted\">Sistemul acceptă falsificarea semnăturii:</string>\n    <string name=\"self_check_name_battery_optimizations\">Optimizarea bateriei este dezactivată:</string>\n    <string name=\"pref_recaptcha_test_title\">Testează ReCAPTCHA</string>\n    <string name=\"signin_subtext_sharing\">Pentru a continua, microG va distribui numele, adresa de e-mail și fotografia de profil a Contului tău Google <xliff:g example=\"F-Droid\">%1$s</xliff:g>.</string>\n    <string name=\"pref_auth_include_android_id_title\">Autentificare cu înregistrarea dispozitivului</string>\n    <string name=\"pref_push_app_allow_register_title\">Permite înregistrarea</string>\n    <string name=\"profile_name_native\">Nativ</string>\n    <string name=\"prefs_account_security\">Conectare și securitate</string>\n    <string name=\"pref_gcm_ping_interval\">Interval de verificare: <xliff:g example=\"10 minutes\">%1$s</xliff:g></string>\n    <string name=\"pref_test_summary_running\">Rulează…</string>\n    <string name=\"pref_safetynet_recent_cat_basic\">Date de bază</string>\n    <string name=\"pref_add_account_summary\">Adaugă un cont Google</string>\n    <string name=\"self_check_resolution_fake_sig_perm\">ROM-ul nu are suport nativ pentru falsificarea semnăturilor. Poți utiliza în continuare Xposed sau alte sisteme pentru a falsifica semnătura. Verifică documentația despre care ROM-uri acceptă falsificarea semnăturilor și cum să utilizezi microG pe ROM-urile care nu o acceptă.</string>\n    <string name=\"profile_name_system\">Sistem: %s</string>\n    <string name=\"cond_perm_title\">Lipsește permisiunea</string>\n    <string name=\"pref_safetynet_recent_cat_response\">Datele de răspuns</string>\n    <string name=\"pref_push_app_allow_register_summary\">Permite aplicației să se înregistreze pentru notificări push.</string>\n    <string name=\"self_check_name_correct_sig\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> are semnătura corectă: </string>\n    <string name=\"pref_safetynet_recent_token\">Token</string>\n    <string name=\"pref_safetynet_test_not_completed\">Nu a fost finalizată încă</string>\n    <string name=\"pref_safetynet_recent_request_time\">Timpul solicitării</string>\n    <string name=\"signin_subtext_policy_terms\">termenii și condițiile</string>\n    <string name=\"prefcat_push_apps_registered_title\">Aplicații înregistrate</string>\n    <string name=\"pref_device_registration_device_profile_category\">Profilul dispozitivului</string>\n    <string name=\"gcm_app_not_installed_anymore\">Aplicația nu mai este instalată</string>\n    <string name=\"prefcat_push_networks_title\">Rețele de utilizat pentru notificări push</string>\n    <string name=\"self_check_name_app_installed\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> instalat: </string>\n    <string name=\"self_check_resolution_system_spoofs\">Verifică documentația cu privire la pașii care ar putea fi necesari.</string>\n    <string name=\"pref_safetynet_recent_eval_type\">Tipul de evaluare</string>\n    <string name=\"games_info_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> ar dori să folosească Jocuri Play</string>\n    <string name=\"prefs_account_privacy\">Informații personale și confidențialitate</string>\n    <string name=\"service_name_vending\">Servicii Play Store</string>\n    <string name=\"pref_vending_summary_licensing_off\">Licențiere oprită</string>\n    <string name=\"pref_vending_summary_licensing_on\">Licențiere pornită</string>\n    <string name=\"pref_vending_licensing_enable_switch\">Răspunde la solicitările de verificare a licenței</string>\n    <string name=\"pref_vending_license_enable_summary\">Unele aplicații necesită verificarea faptului că le-ai achiziționat de pe Google Play. Când este solicitat de o aplicație, microG poate descărca o dovadă de achiziție de la Google. Dacă este dezactivat sau dacă nu este adăugat niciun cont Google, solicitările de verificare a licenței sunt ignorate.</string>\n    <string name=\"feedback_disabled\">Momentan, feedback-ul nu este posibil</string>\n    <string name=\"perm_car_info_label\">Informații despre automobil</string>\n    <string name=\"perm_car_fuel_label\">Nivelul combustibilului în automobil</string>\n    <string name=\"perm_car_fuel_description\">Accesarea informațiilor despre nivelul de combustibil al automobilului</string>\n    <string name=\"perm_car_mileage_label\">Kilometrajul mașinii</string>\n    <string name=\"perm_car_vendor_extension_label\">Canalul furnizorului de automobile</string>\n    <string name=\"pref_auth_strip_device_name_title\">Elimină numele dispozitivului pentru autentificare</string>\n    <string name=\"perm_car_speed_label\">Viteza automobilului</string>\n    <string name=\"perm_car_speed_description\">Accesarea vitezei automobilului</string>\n    <string name=\"perm_car_info_description\">Accesarea informațiilor despre automobil</string>\n    <string name=\"perm_car_mileage_description\">Obținerea accesului la informații despre kilometrajul automobilului</string>\n    <string name=\"perm_car_vendor_extension_description\">Obținerea accesului la canalul furnizorului de automobile, pentru a face schimb de informații specifice automobilului</string>\n    <string name=\"pref_auth_strip_device_name_summary\">Când este activată, solicitările de autentificare nu vor include numele dispozitivului, ceea ce poate permite dispozitivelor neautorizate să se conecteze, dar poate avea consecințe neprevăzute.</string>\n    <string name=\"backup_disabled\">Momentan, copierea de rezervă nu este posibilă</string>\n    <string name=\"pref_accounts_title\">Conturi Google</string>\n    <string name=\"pref_vending_billing_category\">Facturare Google Play</string>\n    <string name=\"pref_accounts_summary\">Adaugă și gestionează conturile Google</string>\n    <string name=\"prefcat_accounts_settings_title\">Setări</string>\n    <string name=\"prefcat_accounts_current_accounts_title\">Conturi</string>\n    <string name=\"pref_vending_licensing_category\">Licențiere Google Play</string>\n    <string name=\"pref_vending_billing_enable_switch\">Gestionează cererile de facturare</string>\n    <string name=\"pref_vending_billing_enable_summary\">Odată activate, unele aplicații pot finaliza achizițiile sau pot începe abonamente prin serviciul Google Play Billing.</string>\n    <string name=\"pref_vending_billing_note_experimental\">Această funcție este experimentală și poate duce la pierderi de bani. Ai fost avertizat.</string>\n    <string name=\"pref_vending_billing_note_licensing\">Este posibil ca unele aplicații să solicite să activezi și verificarea licenței pentru a verifica achizițiile.</string>\n    <string name=\"credentials_assisted_cancel\">Anulează</string>\n    <string name=\"credentials_assisted_continue\">Continuă</string>\n    <string name=\"credentials_assisted_confirmation_header\">Autentificare</string>\n    <string name=\"credentials_assisted_continue_as_user_button_label\">Continuă ca %1$s</string>\n    <string name=\"credentials_assisted_signin_consent_header\">Autentificare ca %1$s</string>\n    <string name=\"credentials_assisted_signin_description\">Poți gestiona Conectarea cu Google în Conturile Google.</string>\n    <string name=\"credentials_assisted_choose_account_label\">Alege contul</string>\n    <string name=\"credentials_assisted_choose_account_subtitle\">pentru a continua să %1$s</string>\n    <string name=\"credentials_assisted_signin_button_text_long\">Conectează-te cu Google</string>\n    <string name=\"credentials_assisted_sign_back_title\">Conectează-te din nou la %1$s cu contul Google</string>\n    <string name=\"credentials_assisted_signin_consent\">Continuând, Google va partaja numele, adresa de e-mail și fotografia de profil cu %1$s. Consultă Politica de confidențialitate, Termenii și condițiile %1$s.</string>\n    <string name=\"auth_package_override_request_message\"><b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> dorește să acceseze contul ca și cum ar fi <b><xliff:g example=\"F-Droid\">%2$s</xliff:g> de la <xliff:g example=\"F-Droid Inc.\">%3$s</xliff:g></b>. Acest lucru i-ar putea oferi acces privilegiat la contul tău.</string>\n    <string name=\"auth_package_override_request_title\">Permiți pentru <b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> acces privilegiat la <xliff:g example=\"account@example.com\">%2$s</xliff:g>\\?</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_switch\">Adaugă automat aplicațiile gratuite în bibliotecă</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_summary\">Aplicațiile gratuite pot verifica dacă au fost descărcate de pe Google Play. Adaugă automat aplicațiile gratuite în biblioteca contului pentru a trece întotdeauna verificarea pentru toate aplicațiile gratuite disponibile în prezent.</string>\n    <string name=\"limited_services_app_name\">Servicii limitate microG</string>\n    <string name=\"limited_services_dialog_information\">Utilizezi serviciile limitate microG. Spre deosebire de serviciile microG obișnuite, această versiune funcționează numai cu aplicațiile care folosesc biblioteci microG, nu cu cele de pe Google Play. Aceasta înseamnă că majoritatea aplicațiilor vor ignora aceste servicii.</string>\n    <string name=\"limited_services_dialog_information_ack\">Am înțeles</string>\n    <string name=\"auth_action_notification_channel_name\">Alerte pentru contul Google</string>\n    <string name=\"auth_action_notification_content\">Contul Google necesită o configurare suplimentară.</string>\n    <string name=\"auth_action_activity_header\">Finalizează configurarea contului Google</string>\n    <string name=\"auth_action_step_enable_checkin\">Activează înregistrarea dispozitivului</string>\n    <string name=\"auth_action_step_enable_checkin_description\">Dispozitivul trebuie să se înregistreze la Google cel puțin o dată.\\n\\nPoți dezactiva înregistrarea dispozitivului Google după finalizarea configurării contului.</string>\n    <string name=\"auth_action_step_allow_microg_gcm\">Permite mesageria în cloud pentru microG</string>\n    <string name=\"auth_action_step_allow_microg_gcm_description\">În funcție de preferințele tale, microG are nevoie de permisiunea ta înainte de a se putea înregistra pentru mesageria în cloud.</string>\n    <string name=\"auth_action_step_perform_content_description\">Clic pentru a efectua pasul</string>\n    <string name=\"auth_action_step_completed_content_description\">Pas finalizat</string>\n    <string name=\"auth_action_activity_finish\">Finalizare</string>\n    <string name=\"auth_action_step_enable_lockscreen\">Configurează blocarea securizată a ecranului</string>\n    <string name=\"auth_action_notification_channel_description\">Notifică atunci când unul dintre conturile Google necesită o configurare suplimentară înainte de a putea fi utilizat sau când un cont este incompatibil cu microG.</string>\n    <string name=\"auth_action_notification_title\">Este necesară acțiunea în cont</string>\n    <string name=\"auth_action_activity_explanation\">Parcurge următorii pași pentru a putea folosi contul Google %s pe acest dispozitiv.</string>\n    <string name=\"auth_action_step_enable_gcm_description\">Poți dezactiva mesageria în cloud după finalizarea configurării contului.</string>\n    <string name=\"auth_action_step_enable_gcm\">Activează mesageria în cloud</string>\n    <string name=\"auth_action_step_enable_lockscreen_description\">Contul Google este gestionat de locul de muncă sau de instituția de învățământ. Administratorul a decis că dispozitivele au nevoie de o blocare securizată a ecranului înainte de a putea accesa datele contului.\\n\\nConfigurează o parolă, un cod PIN sau un model de deblocare al ecranului.</string>\n    <string name=\"pref_vending_asset_delivery_category\">Livrare de active Google Play</string>\n    <string name=\"pref_vending_asset_delivery_switch\">Activează livrarea de active la cerere</string>\n    <string name=\"pref_vending_asset_delivery_summary\">Descarcă materiale suplimentare atunci când sunt solicitate de aplicațiile care folosesc Play Asset Delivery</string>\n    <string name=\"pref_vending_asset_device_sync_summary\">Aplicațiile care folosesc Play Asset Delivery vor descărca materiale suplimentare pe baza informațiilor despre dispozitivul utilizat în prezent.</string>\n    <string name=\"pref_vending_asset_device_sync_switch\">Activează sincronizarea informațiilor despre dispozitiv</string>\n    <string name=\"games_achievement_list_title\">Realizări</string>\n    <string name=\"games_achievements_empty_text\">Nicio realizare pentru acest joc</string>\n    <string name=\"games_api_access_denied\">Niciun cont de pe acest dispozitiv nu poate accesa API-urile Jocuri</string>\n    <string name=\"games_achievement_locked_content_description\">blocat</string>\n    <string name=\"games_achievement_unlocked_content_description\">deblocat</string>\n    <string name=\"games_achievement_extra_text\">%1$s XP</string>\n    <string name=\"games_leaderboard_empty_text\">Nu există clasamente pentru acest joc</string>\n    <string name=\"games_leaderboard_score_empty_text\">De necrezut! Nu există scoruri mari publice pentru acest joc.</string>\n    <string name=\"games_leaderboard_list_title\">Clasamente</string>\n    <string name=\"games_leaderboards_score_label\">Scor: %1$s</string>\n    <string name=\"games_snapshot_empty_text\">Nu au fost salvate încă jocuri</string>\n    <string name=\"games_snapshot_choose_btn_text\">selectează</string>\n    <string name=\"games_snapshot_delete_btn_text\">șterge</string>\n    <string name=\"games_delete_snapshot_dialog_title\">Șterge jocul salvat</string>\n    <string name=\"games_delete_snapshot_dialog_message\">Sigur dorești să ștergi acest joc salvat?</string>\n    <string name=\"games_delete_snapshot_dialog_cancel\">Anulează</string>\n    <string name=\"games_delete_snapshot_dialog_ok\">OK</string>\n    <string name=\"games_delete_snapshot_error\">Ștergerea nu a reușit, încearcă din nou mai târziu</string>\n    <string name=\"service_name_work_profile\">Profil de serviciu</string>\n    <string name=\"pref_vending_feature_delivery\">Livrarea funcțiilor Google Play</string>\n    <string name=\"pref_vending_licensing_split_install_summary\">Permite aplicațiilor să descarce și să instaleze componente suplimentare</string>\n    <string name=\"pref_workprofile_create_account\">Permite configurarea profilului de serviciu</string>\n    <string name=\"pref_workprofile_disclaimer\">Este responsabilitatea ta să te asiguri că utilizarea microG este în conformitate cu politicile corporative. microG este furnizat pe bază de cel mai bun efort și nu poate garanta că se va comporta exact așa cum era de așteptat.</string>\n    <string name=\"barcode_scanner_brand\">Scanat de microG în numele %1$s</string>\n    <string name=\"camera_permission_dialog_button\">Ok</string>\n    <string name=\"camera_permission_dialog_message\">Serviciile microG trebuie să acceseze camera dispozitivului pentru a scana un cod necesar pentru %1$s.\\n\\nPentru a activa, acordă permisiunea Camera foto în Setări.</string>\n    <string name=\"camera_permission_dialog_title\">Permisiunea de accesare a camerei este necesară</string>\n    <string name=\"credentials_assisted_choose_account_error_tips\">Anomalia contului</string>\n    <string name=\"pref_vending_split_install_switch\">Instalarea componentelor la cerere</string>\n    <string name=\"pref_workprofile_intro\">La configurarea unui profil de serviciu pentru locul de muncă sau instituția de învățământ, configurarea poate încerca să se conecteze la Google pentru a activa descărcarea aplicațiilor în acel profil.</string>\n    <string name=\"credentials_assisted_signin_add_account\">Adaugă un cont</string>\n    <string name=\"auth_action_reauth_notification_title\">Acțiune cont necesară</string>\n    <string name=\"pref_game_accounts_title\">Conturi de joc Google</string>\n    <string name=\"pref_auto_create_player\">Permite înregistrarea contului de Jocuri Play</string>\n    <string name=\"pref_auto_create_player_intro\">În jocuri, trebuie să utilizezi un cont Jocuri Play pentru a conecta și a înregistra funcții legate de joc, cum ar fi realizări, clasamente, arhive, etc. După dezactivare, conturile Google care nu sunt legate de un cont de Jocuri Play nu vor fi înregistrate automat, iar jocul nu va fi capabil să se conecteze.</string>\n    <string name=\"pref_allow_upload_game_played\">Permite încărcarea jocului</string>\n    <string name=\"pref_allow_upload_game_played_summary\">Când este dezactivat, jocul nu va raporta starea jocului după conectare și este posibil ca unele jocuri să nu se poată conecta.</string>\n    <string name=\"pref_change_default_game_player\">Schimbă contul pentru jocuri</string>\n    <string name=\"pref_change_default_game_player_summary\">Modifică contul implicit pentru jocuri și schimbă contul în funcție joc.</string>\n    <string name=\"pref_delete_game_account_data\">Șterge datele Jocuri Play</string>\n    <string name=\"games_state_description_signed_out\">Te-ai deconectat</string>\n    <string name=\"games_state_description_delete\">Șterge</string>\n    <string name=\"games_change_button_text\">Schimbă</string>\n    <string name=\"pref_auth_two_step_verification_title\">Primește solicitări de verificare în doi pași</string>\n    <string name=\"pref_auth_two_step_verification_summary\">Când este activat, dispozitivul poate primi solicitări de verificare în doi pași de la Google (este necesară mesageria Cloud).</string>\n    <string name=\"games_change_default_account_section_title\">Schimbă contul implicit pentru jocuri</string>\n    <string name=\"games_change_default_account_description\">Șterge contul: %1$s</string>\n    <string name=\"games_popup_signin_welcome\">Salut %1$s</string>\n    <string name=\"pref_delete_game_account_data_summary\">Șterge contul Jocuri Play, toate datele și datele individuale ale jocului.</string>\n    <string name=\"games_change_default_account_explanation\">Acest cont este utilizat pentru a te conecta automat la jocuri, pentru a salva progresul jocului și pentru a salva setările. Modificarea contului implicit sau deconectarea ar putea reseta progresul și setările pentru jocurile pe care le-ai jucat.</string>\n    <string name=\"games_change_per_game_title\">Schimbă contul în funcție joc</string>\n    <string name=\"games_change_per_game_description\">Schimbarea contului pentru un joc selectat sau deconectarea de la acest joc ar putea reseta progresul și setările.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_title\">Selectează o opțiune pentru contul nou implicit</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_description\">Cont implicit curent: %1$s</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_title\">Modifică contul implicit numai pentru jocurile noi</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_description\">Nu vei pierde accesul la progres și la setări pentru jocurile pe care le-ai jucat, dar progresul va fi împărțit între conturi.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_title\">Modifică contul implicit pentru toate jocurile</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_description\">S-ar putea să pierzi accesul la progres și la setări pentru jocurile pe care le-ai jucat. Vom reporni jocul pentru a aplica modificările.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_title\">Deconectare în toate jocurile</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_description\">S-ar putea să pierzi accesul la progres și la setări pentru jocurile pe care le-ai jucat. Vom reporni jocul pentru a aplica modificările.</string>\n    <string name=\"games_change_per_game_dialog_title\">Selectează o opțiune pentru acest joc</string>\n    <string name=\"games_change_per_game_dialog_description\">Schimbarea contului sau deconectarea ar putea reseta progresul și setările jocului</string>\n    <string name=\"games_change_per_game_dialog_option_use_player\">Folosește %1$s</string>\n    <string name=\"games_change_per_game_dialog_option_use_player_snackbar_success_message\">Vei fi conectat la acest joc cu %1$s</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out\">Deconectare</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out_snackbar_success_message\">Acum ești deconectat din acest joc</string>\n    <string name=\"games_change_sign_out_of_all_games_snackbar_success_message\">Acum ești deconectat din toate jocurile</string>\n    <string name=\"games_change_default_account_for_all_games_snackbar_success_message\">Vei fi conectat la toate jocurile cu %1$s</string>\n    <string name=\"games_change_default_account_for_new_games_snackbar_success_message\">Vei fi conectat la jocurile noi cu %1$s</string>\n    <string name=\"games_account_display_content\">Contul curent: %1$s</string>\n    <string name=\"games_delete_profile_header\">Șterge contul Jocuri Play și toate datele</string>\n    <string name=\"games_delete_profile_explanation\">Șterge permanent contul Google Play Games, XP și toate datele de profil. Această acțiune ar putea, de asemenea, să șteargă scorurile, progresul (jocurile salvate) și setările în jocurile pe care le-ai jucat.</string>\n    <string name=\"games_delete_profile_button\">Șterge permanent</string>\n    <string name=\"games_delete_game_data_header\">Șterge datele individuale ale jocului</string>\n    <string name=\"games_delete_game_data_explanation\">Poți șterge definitiv datele individuale pentru jocurile pe care le-ai jucat folosind Jocurile Google Play. Această acțiune șterge scorurile, progresul (jocuri salvate) și setările pentru jocul selectat.</string>\n    <string name=\"games_delete_profile_dialog_title\">Ești sigur că vrei să ștergi acest cont?</string>\n    <string name=\"games_delete_profile_explanation_with_gamer_name\">Șterge permanent contul de jocuri Google Play pentru numele jucătorului <b>%1$s</b> (<b>%2$s</b>), XP și toate datele de profil. Această acțiune ar putea, de asemenea, să șteargă scorurile, progresul (jocurile salvate) și setările în jocurile pe care le-ai jucat.</string>\n    <string name=\"games_delete_profile_dialog_message\">Această acțiune nu poate fi anulată.</string>\n    <string name=\"games_delete_profile_fail\">Nu s-a putut șterge profilul. Încearcă din nou mai târziu.</string>\n    <string name=\"games_delete_game_data_confirm_dialog_title\">Șterge datele pentru %1$s</string>\n    <string name=\"games_delete_game_data_confirm_dialog_message\">Ștergerea permanentă a datelor pentru %1$s va elimina scorurile, progresul (jocurile salvate) și setările de joc în jocurile Google Play.</string>\n    <string name=\"service_name_google_location_sharing\">Partajarea locației Google</string>\n    <string name=\"location_sharing_description\">Gestionează-ți partajarea locației în timp real în aplicațiile și serviciile Google de pe acest dispozitiv</string>\n    <string name=\"location_sharing_learn_more\">Află mai multe despre partajarea locației</string>\n    <string name=\"location_sharing_switch_text\">Utilizează partajarea locației</string>\n    <string name=\"location_sharing_turn_off_notify_hint\">Dacă dezactivezi partajarea locației pentru acest dispozitiv, persoanele cărora le partajezi nu vor fi notificate.</string>\n    <string name=\"location_sharing_off_previous_hint\">Doar ultima locație partajată va fi disponibilă până când o pornești.</string>\n    <string name=\"location_sharing_disabled\">Fără partajări de locație activate pentru acest cont</string>\n    <string name=\"location_sharing_turn_on_hint\">După ce începi să partajezi locația dintr -o aplicație sau un serviciu Google, poți gestiona partajarea locației de aici.\\n\\nPentru a începe să partajezi locația, accesează Google Maps sau Family Link.</string>\n    <string name=\"location_sharing_turn_off_title\">Oprește partajarea locației</string>\n    <string name=\"location_sharing_turn_off_hint\">Ai putea partaja în continuare locația de la alte dispozitive conectate în același cont Google sau din aplicații non-Google. Asigură-te că verifici setările de partajare a locației oriunde se pot aplica.\\n\\nPersoanele cărora le partajezi vor continua să vă vadă ultima locație partajată.</string>\n    <string name=\"location_sharing_turn_off_cancel\">Păstrează pornit</string>\n    <string name=\"location_sharing_turn_off_confirm\">Oprește</string>\n    <string name=\"location_sharing_confirm_dialog_title\">Activează partajarea locației</string>\n    <string name=\"location_sharing_confirm_dialog_text\">Persoanele cărora le partajezi locația pot vedea întotdeauna:\\n· Numele și fotografia ta\\n· Locația recentă a dispozitivului, chiar și atunci când nu utilizezi un serviciu Google\\n· Nivelul bateriei dispozitivului și dacă se încarcă\\n· Ora de sosire și plecare, dacă adaugă o notificare de partajare a locației</string>\n    <string name=\"family_management_title\">Familie</string>\n    <string name=\"family_management_retry\">Reîncearcă</string>\n    <string name=\"family_management_load_error\">Încărcarea conținutului a eșuat</string>\n    <string name=\"family_management_toolbar_back\">Înapoi</string>\n    <string name=\"family_management_toolbar_more\">Mai multe</string>\n    <string name=\"family_management_exit_family_group\">Părăsește grupul familiei</string>\n    <string name=\"family_management_delete_family_group\">Șterge grupul familiei</string>\n    <string name=\"family_management_leave_family_password_title\">Confirmă parola pentru a părăsi grupul familiei</string>\n    <string name=\"family_management_delete_family_password_title\">Confirmă parola pentru a șterge grupul familiei</string>\n    <string name=\"family_management_remove_member_password_title\">Confirmă parola pentru a șterge %s</string>\n    <string name=\"family_management_invite_family_member\">Invită membrii familiei</string>\n    <string name=\"family_management_invite_slots_left\">%1$d invitații rămase</string>\n    <string name=\"family_management_cancel_invite\">Anulează invitația</string>\n    <string name=\"family_management_cancel_invite_success\">Anulare cu succes a invitației</string>\n    <string name=\"family_management_cancel_invite_error\">Eroare la anularea invitației. Încearcă din nou.</string>\n    <string name=\"family_management_remove_member\">Eliminare membru</string>\n    <string name=\"family_management_member_removed_success\">%s a fost eliminat din grupul familiei</string>\n    <string name=\"family_management_member_remove_failed\">Eroare la eliminarea %s. Încearcă din nou.</string>\n    <string name=\"family_management_leave_family_error_message\">Probleme la părăsirea grupului de familie. Încearcă din nou.</string>\n    <string name=\"family_management_exist_group_success\">Ai părăsit grupul familiei…</string>\n    <string name=\"family_management_delete_group_success\">Grupul familiei a fost șters</string>\n    <string name=\"family_management_delete_group_failure\">Grupul de acasă nu a putut fi șters</string>\n    <string name=\"family_management_delete_group_cancel\">Renunță</string>\n    <string name=\"family_management_delete_group_confirm\">OK</string>\n    <string name=\"family_management_input_pwd\">Introdu parola</string>\n    <string name=\"family_management_invite_sent_date_format\">Invitație trimisă la %s</string>\n    <string name=\"family_management_invite_send\">Invitație trimisă</string>\n    <string name=\"family_management_pwd_error\">Parolă greșită, introdu din nou</string>\n    <string name=\"pref_app_install_settings_title\">Setări instalator de aplicații</string>\n    <string name=\"pref_app_install_switch_title\">Permite instalarea aplicațiilor</string>\n    <string name=\"pref_app_install_other_apps_note\">Autorizarea permite instalarea aplicațiilor furnizate din alte surse.</string>\n    <string name=\"pref_app_install_permission_instruction\">Pentru a te asigura că aplicațiile instalate funcționează corect, permite Companionului microG să instaleze aplicații descărcate din alte surse.</string>\n    <string name=\"prefcat_app_install_list_title\">Aplicații ce folosesc instalatorul de aplicații</string>\n    <string name=\"service_name_device_attestation\">Atestarea dispozitivului</string>\n    <string name=\"prefcat_device_attestation_apps_title\">Aplicații ce utilizează Atestarea dispozitivului</string>\n    <string name=\"pref_device_attestation_app_allow_requests_title\">Permite solicitările</string>\n    <string name=\"pref_device_attestation_app_allow_requests_summary\">Permite aplicației să solicite atestarea dispozitivului</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-ru/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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  --><resources>\n    <string name=\"permission_service_all_label\">Все сервисы Google</string>\n    <string name=\"permission_service_all_description\">Дает приложению доступ к сервисам Google через любой связанный аккаунт Google.</string>\n    <string name=\"permission_service_android_label\">Сервисы Android</string>\n    <string name=\"permission_service_android_description\">Дает приложению доступ к сервисам Android через любую связанную учетную запись Google.</string>\n    <string name=\"permission_service_adsense_label\">AdSense</string>\n    <string name=\"permission_service_adsense_description\">Дает приложению доступ к Adsense через любой связанный аккаунт Google.</string>\n    <string name=\"permission_service_adwords_label\">AdWords</string>\n    <string name=\"permission_service_adwords_description\">Дает приложению доступ к AdWords через любой связанный аккаунт Google.</string>\n    <string name=\"permission_service_ah_label\">Google App Engine</string>\n    <string name=\"permission_service_ah_description\">Дает приложению доступ к Google App Engine через любой связанный аккаунт Google.</string>\n    <string name=\"permission_service_blogger_label\">Blogger</string>\n    <string name=\"permission_service_blogger_description\">Дает приложению доступ к Blogger через любую связанную учетную запись Google.</string>\n    <string name=\"permission_service_cl_label\">Google Календарь</string>\n    <string name=\"permission_service_cl_description\">Дает приложению доступ к Google Календарю через любую связанную учетную запись Google.</string>\n    <string name=\"permission_service_cp_label\">Контакты</string>\n    <string name=\"permission_service_cp_description\">Дает приложению доступ к Котактам через любую связанную учетную запись Google.</string>\n    <string name=\"permission_service_dodgeball_label\">Dodgeball</string>\n    <string name=\"permission_service_dodgeball_description\">Дает приложению доступ к Dodgeball через любую связанную учетную запись Google.</string>\n    <string name=\"permission_service_finance_label\">Google Finance</string>\n    <string name=\"permission_service_finance_description\">Дает приложению доступ к Google Finance через любую связанную учетную запись Google.</string>\n    <string name=\"permission_service_gbase_label\">Google Base</string>\n    <string name=\"permission_service_gbase_description\">Дает приложению доступ к Google Base через любую связанную учетную запись Google.</string>\n    <string name=\"permission_service_grandcentral_label\">Google Voice</string>\n    <string name=\"permission_service_grandcentral_description\">Дает приложению доступ к Google Voice через любую связанную учетную запись Google.</string>\n    <string name=\"permission_service_groups2_label\">Группы Google</string>\n    <string name=\"permission_service_groups2_description\">Дает приложению доступ к Google Groups через любую связанную учетную запись Google.</string>\n    <string name=\"permission_service_health_label\">Google Health</string>\n    <string name=\"permission_service_health_description\">Дает приложению доступ к Google Health через любую связанную учетную запись Google.</string>\n    <string name=\"permission_service_ig_label\">iGoogle</string>\n    <string name=\"permission_service_ig_description\">Дает приложению доступ к iGoogle через любую связанную учетную запись Google.</string>\n    <string name=\"permission_service_jotspot_label\">JotSpot</string>\n    <string name=\"permission_service_jotspot_description\">Дает приложению доступ к JotSpot через любую связанную учетную запись Google.</string>\n    <string name=\"permission_service_knol_label\">Knol</string>\n    <string name=\"permission_service_knol_description\">Дает приложению доступ к Knol через любую связанную учетную запись Google.</string>\n    <string name=\"permission_service_lh2_label\">Picasa Web Albums</string>\n    <string name=\"permission_service_lh2_description\">Дает приложению доступ к Picasa Web Albums через любую связанную учетную запись Google.</string>\n    <string name=\"permission_service_local_label\">Google Карты</string>\n    <string name=\"permission_service_local_description\">Дает приложению доступ к Google Maps через любую связанную учетную запись Google.</string>\n    <string name=\"permission_service_mail_label\">Google Mail</string>\n    <string name=\"permission_service_mail_description\">Дает приложению доступ к Google Mail через любую связанную учетную запись Google.</string>\n    <string name=\"permission_service_news_label\">Google Новости</string>\n    <string name=\"permission_service_news_description\">Дает приложению доступ к Google News через любую связанную учетную запись Google.</string>\n    <string name=\"permission_service_notebook_label\">Google Notebook</string>\n    <string name=\"permission_service_notebook_description\">Дает приложению доступ к Google Notebook через любую связанную учетную запись Google.</string>\n    <string name=\"permission_service_orkut_label\">Orkut</string>\n    <string name=\"permission_service_orkut_description\">Дает приложению доступ к Orkut через любую связанную учетную запись Google.</string>\n    <string name=\"permission_service_print_label\">Google Книги</string>\n    <string name=\"permission_service_print_description\">Дает приложению доступ к Google Book Search через любую связанную учетную запись Google.</string>\n    <string name=\"permission_service_sierra_label\">Аккаунты Google Checkout</string>\n    <string name=\"permission_service_sierra_description\">Дает приложению доступ к аккаунтам Google Checkout через любую связанную учетную запись Google.</string>\n    <string name=\"permission_service_sierraqa_label\">Аккаунты Google Checkout QA</string>\n    <string name=\"permission_service_sierraqa_description\">Дает приложению доступ к аккаунтам Google Checkout QA через любую связанную учетную запись Google.</string>\n    <string name=\"permission_service_sierrasandbox_label\">Аккаунты Google Checkout Sandbox</string>\n    <string name=\"permission_service_sierrasandbox_description\">Дает приложению доступ к аккаунтам Google Checkout Sandbox через любую связанную учетную запись Google.</string>\n    <string name=\"permission_service_sitemaps_label\">Google Webmaster Tools</string>\n    <string name=\"permission_service_sitemaps_description\">Дает приложению доступ к Google Webmaster Tools через любую связанную учетную запись Google.</string>\n    <string name=\"permission_service_speech_label\">Голосовой поиск</string>\n    <string name=\"permission_service_speech_description\">Дает приложению доступ к Voice Search через любую связанную учетную запись Google.</string>\n    <string name=\"permission_service_speechpersonalization_label\">Персонализированное распознавание речи</string>\n    <string name=\"permission_service_speechpersonalization_description\">Дает приложению доступ к Personalized Speech Recognition через любую связанную учетную запись Google.</string>\n    <string name=\"permission_service_talk_label\">Google Talk</string>\n    <string name=\"permission_service_talk_description\">Дает приложению доступ к Google Talk через любую связанную учетную запись Google.</string>\n    <string name=\"permission_service_wifi_label\">Google Wi-Fi</string>\n    <string name=\"permission_service_wifi_description\">Дает приложению доступ к Google Wi-Fi через любую связанную учетную запись Google.</string>\n    <string name=\"permission_service_wise_label\">Google Таблицы</string>\n    <string name=\"permission_service_wise_description\">Дает приложению доступ к Google Spreadsheets через любую связанную учетную запись Google.</string>\n    <string name=\"permission_service_writely_label\">Google Docs</string>\n    <string name=\"permission_service_writely_description\">Дает приложению доступ к Google Docs через любую связанную учетную запись Google.</string>\n    <string name=\"permission_service_youtube_label\">YouTube</string>\n    <string name=\"permission_service_youtube_description\">Дает приложению доступ к YouTube через любую связанную учетную запись Google.</string>\n    <string name=\"permission_service_YouTubeUser_label\">Имена пользователей YouTube</string>\n    <string name=\"permission_service_YouTubeUser_description\">Позволяет приложению получить доступ к имени пользователя(ей) YouTube, который связан с акаунтом Google.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_activity\">Просмотреть историю активности ваших приложений Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.buyer\">Управление своей учетной записью покупателя Ad Exchange</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller.readonly\">Просмотр ваших Ad Exchange данных</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller\">Просмотр и управление вашими Ad Exchange данными</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsensehost\">Просмотр и управление вашими AdSense данными хостингов и связанными аккаунтами</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense.readonly\">Просмотр ваших AdSense данных</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense\">Просмотр и управление вашими AdSense данными</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics.readonly\">Просмотр ваших Google Analytics данных</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics\">Просмотр и управление вашими Google Analytics данными</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_androidpublisher\">Доступ к магазину Google Play для Android разработчика</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appengine.admin\">Движок приложения сферы администрирования.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.migration\">Доступ на чтение и запись для Groups Migration API.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.settings\">Просмотр и управление настроек Google Apps Group</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.licensing\">Права на чтение/запись для License Manager API.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order\">\"Доступ для чтения/записи администраторам и пользователям при тестировании в песочнице API или доступ для чтения/записи при обращении к API-операциям напрямую.\"</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order.readonly\">\"Помимо общего чтения/записи по протоколу OAuth, следует использовать только для чтения протокол OAuth при извлечении данных клиента.\"</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps_reporting_audit.readonly\">Доступ к API аудиту администратора только для чтения</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appstate\">Область использования App State сервиса.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery.readonly\">Просмотр своих данных в Google BigQuery</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery\">Просмотр и управление своими данными в Google BigQuery</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger\">Управление своей учетной записи блоггера</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger.readonly\">Просмотр своей учетной записи блоггера</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_books\">Управление своими книгами</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar\">Управление своими календарями</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar.readonly\">Просмотр своих календарей</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_cloudprint\">Просмотр и управление своими данными Google Cloud Print</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute.readonly\">Просмотр своих ресурсов Google Compute Engine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute\">Просмотр и управление своими ресурсами Google Compute Engine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate.readonly\">Просмотр своих целей Google Coordinate</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate\">Просмотр и управление своими задаными координатами Google Maps</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.full_control\">Управление своими данными и разрешениями в Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_only\">Просмотр своих данных в Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_write\">Управление своими данными в Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_dfareporting\">Просмотр и управление DoubleClick отчетов рекламодателей</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.appdata\">Предоставить доступ к папке Application Data</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.apps.readonly\">Посмотреть свои приложения Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.file\">Просмотр и управление файлами Google Drive, которые вы открыли или создали в этом приложении</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.install\">Особые возможности, позволяющие пользователям одобрить установку приложения</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.metadata.readonly\">Просмотр метаданных для файлов и документов Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.readonly\">Просмотр файлов и документов Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.scripts\">\"Измениение поведения своих сценариев Google Apps Script\"</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive\">Просмотр и управление файлами и документами Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase.readonly\">просмотр своей учетной записи Freebase</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase\">Зарегистрироваться в Freebase с вашей учетной записью</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables\">Управление слиянием таблиц</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables.readonly\">Просмотр таблицы Fusion</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_games\"> Доступа к данным Google Play Игры.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan\">Управление данными GAN</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan.readonly\">Просмотр данных GAN</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gcm_for_chrome\">CloudMessaging для Chrome</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_glass.timeline\">Glass timeline scope</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.compose\">Создание, чтение, обновление и удаление черновиков. Отправка сообщений из черновиков.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.modify\">Все операции чтения/записи происходят немедленно, кроме удаления тем и сообщений, минуящих корзину.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.readonly\">Чтение всех ресурсов и их метаданных, не использующих операции записи.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.best\">Выбрать ваше наиболее точное местоположение и их историю</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.city\">Выбрать ваш город, и историю местоположений</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.best\">Выбрать ваше самое точно местоположение</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.city\">Выберите свой город</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine\">Просмотр и управление данными Google Maps Engine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine.readonly\">\"предоставляет доступ к пользовательмкому Maps Engine только для чтения для вас\"</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mobilemaps.firstparty\">Просмотр и управление вашими Google Картами для мобильных устройств</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut\">Управление своими действиями Orkut</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut.readonly\">Просмотр своих данных Orkut</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.login\">\"Узнать ваше имя, базовую информацию, и список людей, с которыми вы общаетесь в Google+\"</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.me\">Узнать кто вы в Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_prediction\">Управление своими данными в Google Prediction API</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_shoppingapi\">Просмотр данных продукта</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification\">Управление вашим списком сайтов и доменов</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification.verify_only\">Управление верификацией ваших сайтов в Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_structuredcontent\">Доступ на запись/чтение для Shopping Content API.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue.consumer\">Выполнение задач из вашего TaskQueue</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue\">Управление вашими задачами</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks\">Управление задачами</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks.readonly\">Просмотреть свои задачи</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tracks\">\"Google Maps Tracks API, эта сфера предоставляет доступ на чтение и запись ваших проектов.\"</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_urlshortener\">Управление вашими короткими URL-адресами goo.gl</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.email\">Посмотреть свой адрес электронной почты</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.profile\">Просмотр основной информации об аккаунте</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube\">Управление аккаунтом YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtubepartner\">Просматр и управлени своими активами и контентом на YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.readonly\">Просмотр своего аккаунта YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.upload\">Управление вашими видео на YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics_monetary.readonly\">Простор на YouTube аналитики валютного отчеты для вашего контента YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics.readonly\">Простотр на YouTube аналитических отчетов для вашего контента YouTube</string>\n    <string name=\"perm_activity_recognition_label\">Распознание активности</string>\n    <string name=\"perm_activity_recognition_description\">Разрешает приложению получать периодические обновления вашего уровня активности от Google, к примеру, если вы ходите, едете, едете на велосипеде, или находитесь в неподвижном состоянии.</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-ru/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2017-2020 microG Project Team\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  --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <plurals name=\"pref_unifiednlp_summary\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> навигационный модуль настроен</item>\n        <item quantity=\"few\"><xliff:g example=\"3\">%1$d</xliff:g> навигационных модуля настроено</item>\n        <item quantity=\"many\"><xliff:g example=\"5\">%1$d</xliff:g> навигационных модулей настроено</item>\n        <item quantity=\"other\"><xliff:g example=\"5\">%1$d</xliff:g> навигационных модулей настроено</item>\n    </plurals>\n    <plurals name=\"gcm_registered_apps_counter\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> привязанное приложение</item>\n        <item quantity=\"few\"><xliff:g example=\"3\">%1$d</xliff:g> привязанных приложения</item>\n        <item quantity=\"many\"><xliff:g example=\"5\">%1$d</xliff:g> привязанных приложений</item>\n        <item quantity=\"other\"><xliff:g example=\"5\">%1$d</xliff:g> привязанных приложений</item>\n    </plurals>\n    <plurals name=\"cond_perm_summary\">\n        <item quantity=\"one\">Не предоставлено разрешение, которое требуется для правильного функционирования microG Services.</item>\n        <item quantity=\"few\">Не предоставлены разрешения, которые требуются для правильного функционирования microG Services.</item>\n        <item quantity=\"other\">Не предоставлены разрешения, которые требуются для правильного функционирования microG Services.</item>\n    </plurals>\n    <plurals name=\"cond_perm_action\">\n        <item quantity=\"one\">Запросить отсутствующее разрешение</item>\n        <item quantity=\"few\">Запросить отсутствующие разрешения</item>\n        <item quantity=\"other\">Запросить отсутствующие разрешения</item>\n    </plurals>\n</resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-ru/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2017 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"gms_app_name\">Сервисы microG</string>\n    <string name=\"gms_settings_name\">Настройки microG</string>\n    <string name=\"gms_settings_summary\">Настройка сервисов microG.</string>\n    <string name=\"just_a_sec\">Секунду…</string>\n    <string name=\"google_account_label\">Google</string>\n    <string name=\"ask_permission_tos\">Продолжая, вы позволяете этому приложению и Google использовать свою информацию в соответствии с их соответствующими условиями предоставления услуг и политиками конфиденциальности.</string>\n    <string name=\"ask_scope_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> хотел бы:</string>\n    <string name=\"ask_service_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> хотел бы использовать:</string>\n    <string name=\"account_manager_title\">Менеджер аккаунта Google</string>\n    <string name=\"sorry\">Извините…</string>\n    <string name=\"auth_before_connect\">\"Приложение на вашем устройстве пытается войти в учетную запись Google.\n\nЕсли это было намеренно, нажмите кнопку <b>Войти</b>, чтобы подключиться к странице входа в Google, если нет, нажмите <b>Отмена</b>, чтобы вернуться к приложению, которое вызвало это диалоговое окно.\"</string>\n    <string name=\"auth_sign_in\">Войти</string>\n    <string name=\"auth_connecting\">\"Ваше устройство устанавливает соединение с серверами Google для входа в систему.\n\nЭто может занять несколько секунд.\"</string>\n    <string name=\"no_network_error_desc\">\"У вас нет подключения к сети.\n\nЭто может быть временной проблемой, или ваше Android устройство не может использовать передачу данных. Попробуйте еще раз, когда появится соединение с мобильной сетью или присоединитесь к сети Wi-Fi.\"</string>\n    <string name=\"auth_general_error_desc\">\"Не удается соединится с серверами Google.\n\nПопробуйте позже.\"</string>\n    <string name=\"auth_finalize\">\"Ваше устройство соединяется с Google, чтобы сохранить информацию в вашу учетную запись.\n\nЭто может занять несколько минут.\"</string>\n    <string name=\"allow\">Разрешить</string>\n    <string name=\"deny\">Отказать</string>\n    <string name=\"auth_notification_title\">Требуется аутентификация</string>\n    <string name=\"auth_notification_content\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> требуется ваша авторизация чтобы получить доступ к вашей учетной записи Google.</string>\n    <string name=\"perm_status_broadcast_label\">следить за внутренним состоянием статуса</string>\n    <string name=\"perm_c2dm_receive_label\">использовать C2DM сообщения</string>\n    <string name=\"perm_c2dm_send_label\">отправлять C2DM сообщения другим приложениям</string>\n    <string name=\"perm_gtalk_svc_label\">обмениваться сообщениями и получать уведомления о синхронизации от серверов Google</string>\n    <string name=\"perm_extended_access_label\">Расширенный доступ к сервисам Google</string>\n    <string name=\"perm_provision_label\">подготовка сервисов microG</string>\n    <string name=\"perm_provision_description\">Позволить приложению настраивать сервисы microG без вмешательства пользователя</string>\n    <string name=\"service_name_checkin\">Регистрация устройства</string>\n    <string name=\"service_name_mcs\">Облачные сообщения</string>\n    <string name=\"service_name_snet\">Google SafetyNet</string>\n    <string name=\"games_title\">Google Play Игры</string>\n    <string name=\"games_info_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> хочет использовать Play Игры</string>\n    <string name=\"games_info_content\">Чтобы использовать возможности Play Игры, нужно установить приложение Google Play Игры . Приложение может работать и без него, но возможны проблемы в его работе.</string>\n    <string name=\"pick_place_title\">Выберите место</string>\n    <string name=\"pick_place_desc\">Средство выбора места временно недоступно.</string>\n    <string name=\"place_picker_select_title\">Выберите это месторасположение</string>\n    <string name=\"place_picker_nearby_places\">Ближайшие места</string>\n    <string name=\"place_picker_location_lat_lng\">(%1$.7f, %2$.7f)</string>\n    <string name=\"lacking_permission_toast\">microG Services: Отсутствует разрешение для <xliff:g example=\"have full network acccess\">%1$s</xliff:g></string>\n    <string name=\"network_type_mobile\">Мобильная сеть</string>\n    <string name=\"network_type_wifi\">Wi-Fi</string>\n    <string name=\"network_type_roaming\">Роуминг</string>\n    <string name=\"network_type_other\">Прочие сети</string>\n    <!-- Self check -->\n\n    <string name=\"self_check_cat_fake_sig\">Поддержка подмены подписи</string>\n    <string name=\"self_check_cat_gms_packages\">Установленные пакеты</string>\n    <string name=\"self_check_cat_system\">Система</string>\n    <string name=\"self_check_name_fake_sig_perm\">Система поддерживает подмену подписи:</string>\n    <string name=\"self_check_resolution_fake_sig_perm\">Ваша прошивка не имеет нативной поддержки подмены подписи. Вы можете использовать Xposed или другие методы, чтобы активировать подмену подписи. Пожалуйста, ознакомьтесь с документацией, какая прошивка поддерживает подмену подписи и как использовать microG в прошивке, которая не поддерживает.</string>\n    <string name=\"self_check_name_perm_granted\">Система разрешает подмену подписи:</string>\n    <string name=\"self_check_resolution_perm_granted\">Ваша прошивка поддерживает подмену подписи, но требует дополнительных действий для ее активации. Пожалуйста, ознакомьтесь с документацией, где описано что нужно сделать.</string>\n    <string name=\"self_check_name_system_spoofs\">Система подменяет подписи:</string>\n    <string name=\"self_check_resolution_system_spoofs\">Пожалуйста, ознакомьтесь с документацией, где описано что нужно сделать.</string>\n    <string name=\"self_check_pkg_gms\">Сервисы microG</string>\n    <string name=\"self_check_pkg_vending\">Компаньон microG / Play Маркет</string>\n    <string name=\"self_check_pkg_gsf\">microG Services Framework</string>\n    <string name=\"self_check_name_app_installed\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> установлен: </string>\n    <string name=\"self_check_resolution_app_installed\">Установите приложение <xliff:g example=\"F-Droid\">%1$s</xliff:g> или совместимое. Пожалуйста, ознакомьтесь с документацией, где описано какие приложения совместимы.</string>\n    <string name=\"self_check_name_correct_sig\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> имеет правильную подпись: </string>\n    <string name=\"self_check_resolution_correct_sig\">Либо установленный <xliff:g example=\"F-Droid\">%1$s</xliff:g> не совместим, либо подмена подписи не активна для него. Пожалуйста, ознакомьтесь с документацией, где описано какие приложения или прошивки совместимы.</string>\n    <string name=\"self_check_name_battery_optimizations\">Оптимизация энергопотребления отключена:</string>\n    <string name=\"self_check_resolution_battery_optimizations\">Нажмите здесь, чтобы разрешить приложению работать в фоне. Без этого некоторые приложения могут работать со сбоями.</string>\n    <!-- Settings strings -->\n\n    <string name=\"prefcat_about\">О программе</string>\n    <string name=\"prefcat_components\">Компоненты</string>\n    <string name=\"prefcat_configuration\">Конфигурация</string>\n    <string name=\"prefcat_google_services\">Google сервисы</string>\n    <string name=\"prefcat_location_service\">Служба определения местоположения</string>\n    <string name=\"prefcat_services\">Сервисы</string>\n    <string name=\"prefcat_test\">Тест</string>\n    <string name=\"cond_gcm_bat_title\">Активна оптимизация энергопотребления</string>\n    <string name=\"cond_gcm_bat_summary\">Вы включили облачный обмен сообщениями, но у вас активна оптимизация энергопотребления для microG Services. Чтобы получать push-уведомления вам необходимо разрешить приложению работать в фоновом режиме.</string>\n    <string name=\"cond_gcm_bat_action\">Разрешить работу в фоне</string>\n    <string name=\"cond_perm_title\">Отсутствуют разрешения</string>\n    <string name=\"prefs_account\">Настройки аккаунта</string>\n    <string name=\"prefs_account_privacy\">Персональная информация и приватность</string>\n    <string name=\"prefs_account_security\">Авторизация и безопасность</string>\n    <string name=\"pref_auth_trust_google_title\">Автоматически входить с Google</string>\n    <string name=\"pref_auth_trust_google_summary\">Если параметр отключен, то у пользователя запрашивается разрешение для авторизации приложения в Google. Некоторые приложения не смогут использовать аккаунт Google, если эта возможность отключена.</string>\n    <string name=\"pref_auth_visible_title\">Доступ приложений к аккаунтам</string>\n    <string name=\"pref_auth_visible_summary\">Если включено, все приложения на этом устройстве смогут видеть адреса электронной почты ваших учетных записей Google без предварительного разрешения.</string>\n    <string name=\"pref_checkin_enable_summary\">Регистрирует ваше устройство в сервисах Google и создает уникальный идентификатор устройства. MicroG удаляет все идентификационные биты, кроме имени вашего аккаунта Google.</string>\n    <string name=\"pref_device_registration_android_id\">Android ID</string>\n    <string name=\"checkin_not_registered\">Не зарегистрировано</string>\n    <string name=\"checkin_last_registration\">Последняя регистрация: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"checkin_enable_switch\">Зарегистрировать устройство в Google</string>\n    <string name=\"pref_info_status\">Состояние</string>\n    <string name=\"pref_more_settings\">Ещё</string>\n    <string name=\"pref_add_account_title\">Аккаунт</string>\n    <string name=\"pref_add_account_summary\">Добавить аккаунт Google</string>\n    <string name=\"pref_gcm_enable_mcs_summary\">Облачный обмен сообщениями предоставляет push-уведомления, которые используются во многих в сторонних приложениях. Чтобы использовать их, вы должны включить регистрацию устройства.</string>\n    <string name=\"pref_gcm_heartbeat_title\">Интервал соединения облачных сообщений</string>\n    <string name=\"pref_gcm_heartbeat_summary\">\"Интервал в секундах, для использования серверов Google. Увеличение этого числа сократит потребление батареи, но может привести к задержкам push-сообщений.\\nУстарело, будет изменено в следующем релизе.\"</string>\n    <string name=\"pref_gcm_apps_title\">Приложения, использующие облачный обмен сообщениями</string>\n    <string name=\"pref_gcm_apps_summary\">Список приложений, которые привязаны к облачному обмену сообщениями.</string>\n    <string name=\"pref_gcm_confirm_new_apps_title\">Подтверждать новые приложения</string>\n    <string name=\"pref_gcm_confirm_new_apps_summary\">Спрашивать разрешение перед привязкой новых приложений для получения push-уведомлений</string>\n    <string name=\"pref_gcm_ping_interval\">Интервал проверки: <xliff:g example=\"10 минут\">%1$s</xliff:g></string>\n    <string name=\"pref_about_title\">О сервисах microG</string>\n    <string name=\"pref_about_summary\">Информация о версии и используемые библиотеки</string>\n    <string name=\"gcm_app_error_unregistering\">Не удалось отвязать</string>\n    <string name=\"gcm_app_not_installed_anymore\">Приложение больше не установлено</string>\n    <string name=\"gcm_unregister_app\">Отвязать</string>\n    <string name=\"gcm_not_registered\">Не привязано</string>\n    <string name=\"gcm_no_message_yet\">Сообщения еще не были получены</string>\n    <string name=\"gcm_last_message_at\">Последнее сообщение: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_registered\">Привязано</string>\n    <string name=\"gcm_registered_since\">Привязано: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_unregister_confirm_title\">Отвязать <xliff:g example=\"F-Droid\">%1$s</xliff:g>?</string>\n    <string name=\"gcm_unregister_confirm_message\">\"Некоторые приложение автоматически не перепривязываются и/или не предоставляют возможности сделать это вручную. Такие приложения могут работать некорректно после отвязки.\\nПродолжить?\"</string>\n    <string name=\"gcm_unregister_after_deny_message\">Вы запретили push-уведомления для приложения, которое уже привязано.\\nВы хотите отвязать его сейчас чтобы больше не получать от него push-уведомлений?</string>\n    <string name=\"gcm_messages_counter\">Уведомлений: <xliff:g example=\"123\">%1$d</xliff:g> (<xliff:g example=\"12345\">%2$d</xliff:g> байт)</string>\n    <string name=\"gcm_network_state_disconnected\">Отключено</string>\n    <string name=\"gcm_network_state_connected\">Подключено <xliff:g example=\"2 hours ago\">%1$s</xliff:g></string>\n    <string name=\"gcm_enable_switch\">Принимать push-уведомления</string>\n    <string name=\"gcm_allow_app_popup\">Разрешить <xliff:g example=\"F-Droid\">%1$s</xliff:g> регистрироваться для получения push-уведомлений?</string>\n    <string name=\"pref_push_app_allow_register_title\">Разрешить регистрацию</string>\n    <string name=\"pref_push_app_allow_register_summary\">Разрешить приложению регистрироваться для получения push-уведомлений.</string>\n    <string name=\"pref_push_app_wake_for_delivery_title\">Запускать приложение</string>\n    <string name=\"pref_push_app_wake_for_delivery_summary\">Запускать приложение в фоновом режиме при получении входящего push-уведомления.</string>\n    <string name=\"prefcat_push_apps_title\">Приложения использующие push-уведомления</string>\n    <string name=\"prefcat_push_apps_registered_title\">Зарегистрированные приложения</string>\n    <string name=\"prefcat_push_apps_unregistered_title\">Незарегистрированные приложения</string>\n    <string name=\"prefcat_push_networks_title\">Сети для приёма push-уведомлений</string>\n    <string name=\"safetynet_intro\">Google SafetyNet это система сертификации устройства, гарантирующая, что устройство корректно защищено и совместимо с Android CTS. Некоторые приложения используют SafetyNet из соображений безопасности или в качестве предварительной системы защиты от взлома.\\n\\nmicroG GmsCore содержит свободную реализацию SafetyNet, но официальный сервер требует, чтобы запросы были подписаны с помощью проприетарной системы DroidGuard.</string>\n    <string name=\"safetynet_enable_switch\">Разрешить проверку статуса устройства</string>\n    <string name=\"pref_safetynet_test_title\">Проверка аттестации SafetyNet</string>\n    <string name=\"pref_recaptcha_test_title\">Тест ReCAPTCHA</string>\n    <string name=\"pref_test_summary_passed\">Все проверки пройдены</string>\n    <string name=\"pref_test_summary_failed\">Ошибка: %s</string>\n    <string name=\"pref_test_summary_warn\">Предупреждение: %s</string>\n    <string name=\"pref_test_summary_running\">Выполнение…</string>\n    <string name=\"pref_droidguard_operation_mode\">Режим работы</string>\n    <string name=\"prefcat_safetynet_apps_title\">Приложения использующие SafetyNet</string>\n    <string name=\"menu_clear_recent_requests\">Очистить недавние запросы</string>\n    <string name=\"safetynet_last_run_at\">Последнее использование: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"profile_name_native\">Устройство</string>\n    <string name=\"profile_name_real\">Реальный</string>\n    <string name=\"profile_name_user\">Пользовательский: %s</string>\n    <string name=\"profile_name_auto\">Автоматический: %s</string>\n    <string name=\"profile_name_system\">Системный: %s</string>\n    <string name=\"pref_device_registration_import_custom_profile_title\">Импорт профиля</string>\n    <string name=\"pref_device_registration_serial_title\">Серийный номер</string>\n    <string name=\"pref_device_registration_import_custom_profile_summary\">Импортировать пользовательский профиль устройства из файла</string>\n    <string name=\"pref_device_registration_select_profile_title\">Выбрать профиль</string>\n    <string name=\"pref_device_registration_device_profile_category\">Профиль устройства</string>\n    <string name=\"pref_safetynet_recent_copy_json\">Скопировать данные JSON JWS</string>\n    <string name=\"pref_safetynet_recent_advice\">Совет</string>\n    <string name=\"pref_safetynet_recent_eval_type\">Метод проверки</string>\n    <string name=\"pref_safetynet_recent_response_status\">Статус ответа</string>\n    <string name=\"pref_safetynet_recent_cat_response\">Данные ответа</string>\n    <string name=\"pref_safetynet_recent_cat_request\">Данные запроса</string>\n    <string name=\"pref_safetynet_recent_nonce\">Одноразовый код (Hex)</string>\n    <string name=\"pref_safetynet_recent_request_time\">Время запроса</string>\n    <string name=\"pref_safetynet_recent_request_type\">Тип запроса</string>\n    <string name=\"pref_safetynet_recent_cat_basic\">Основные данные</string>\n    <string name=\"pref_safetynet_recent_token\">Токен</string>\n    <string name=\"service_name_vending\">Сервисы Google Play</string>\n    <string name=\"pref_auth_include_android_id_title\">Отправка информации об устройстве</string>\n    <string name=\"pref_recaptcha_enterprise_test_title\">Тест ReCAPTCHA Enterprise</string>\n    <string name=\"pref_safetynet_recent_uses\">Недавние использования</string>\n    <string name=\"pref_safetynet_recent_attestation_summary\">Аттестация: %s</string>\n    <string name=\"pref_safetynet_recent_recaptcha_summary\">ReCaptcha: %s</string>\n    <string name=\"pref_safetynet_recent_recaptcha_enterprise_summary\">ReCaptcha Enterprise: %s</string>\n    <string name=\"pref_safetynet_recent_copied\">Скопировано в буфер обмена!</string>\n    <string name=\"push_notifications_summary_manual\">ВКЛ / Вручную: %s</string>\n    <string name=\"push_notifications_summary_values_seconds\">%s секунд</string>\n    <string name=\"signin_picker_subtitle\">чтобы продолжить в <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"signin_confirm_title\">Разрешить <xliff:g example=\"F-Droid\">%1$s</xliff:g> войти в аккаунт</string>\n    <string name=\"pref_auth_include_android_id_summary\">Когда отключено, запросы аутентификации не будут привязаны к регистрации устройства, что позволяет неавторизованным устройствам входить в в учётную запись, но это может привести к непредвиденным последствиям.</string>\n    <string name=\"signin_subtext_sharing\">Чтобы продолжить, microG поделится вашим именем, адресом электронной почты, и изображением профиля вашего аккаунта Google с <xliff:g example=\"F-Droid\">%1$s</xliff:g>.</string>\n    <string name=\"pref_safetynet_test_cts_failed\">Тест CTS не пройден</string>\n    <string name=\"pref_safetynet_test_invalid_json\">Неверный JSON</string>\n    <string name=\"pref_vending_licensing_enable_switch\">Обрабатывать лицензии</string>\n    <string name=\"pref_vending_license_enable_summary\">Некоторые приложения требуют подтверждения того, что вы приобрели их в Google Play. По запросу приложения microG может загрузить подтверждение покупки от Google. Если отключено или учетная запись Google не добавлена, запросы на проверку лицензии игнорируются.</string>\n    <string name=\"feedback_disabled\">Отправка отзывов в настоящее время невозможна</string>\n    <string name=\"pref_droidguard_unsupported_summary\">Запуск DroidGuard не поддерживаются на этом устройстве. Сервисы SafetyNet могут не работать.</string>\n    <string name=\"pref_safetynet_test_integrity_cts_passed\">Тесты целостности и CTS пройдены</string>\n    <string name=\"pref_safetynet_test_not_completed\">Ещё не завершён</string>\n    <string name=\"push_notifications_summary_off\">ВЫКЛ</string>\n    <string name=\"pref_safetynet_test_no_result\">Нет результата</string>\n    <string name=\"push_notifications_summary_automatic\">ВКЛ / Автоматически: %s</string>\n    <string name=\"push_notifications_summary_values_minutes\">%s минут</string>\n    <string name=\"pref_vending_summary_licensing_off\">Обработка лицензий Выкл.</string>\n    <string name=\"pref_vending_summary_licensing_on\">Обработка лицензий Вкл.</string>\n    <string name=\"pref_safetynet_test_integrity_failed\">Проверка целостности провалена</string>\n    <string name=\"signin_picker_title\">Выберите аккаунт</string>\n    <string name=\"signin_picker_add_account_label\">Добавить другой аккаунт</string>\n    <string name=\"signin_confirm_button_text\">Разрешить и поделиться</string>\n    <string name=\"signin_subtext_policy_terms\">условия использования</string>\n    <string name=\"perm_gsf_read_gservices_label\">читать конфигурацию сервиса Google</string>\n    <string name=\"signin_subtext_policy\">Прежде чем использовать это приложение, проверьте его %1$s и %2$s.</string>\n    <string name=\"signin_subtext_policy_privacy\">политика конфиденциальности</string>\n    <string name=\"pref_auth_strip_device_name_title\">Удалять имя устройства</string>\n    <string name=\"pref_auth_strip_device_name_summary\">Если включено, запросы аутентификации не будут включать имя устройства, что может позволить неавторизованным устройствам входить в учётную запись, но это может привести к непредвиденным последствиям.</string>\n    <string name=\"perm_car_info_label\">Информация о машине</string>\n    <string name=\"perm_car_info_description\">Получение доступа к информации о вашем автомобиле</string>\n    <string name=\"perm_car_mileage_label\">Пробег автомобиля</string>\n    <string name=\"perm_car_mileage_description\">Получение доступа к информации о пробеге вашего автомобиля</string>\n    <string name=\"perm_car_vendor_extension_label\">Канал поставщика автомобиля</string>\n    <string name=\"perm_car_speed_label\">Скорость машины</string>\n    <string name=\"perm_car_speed_description\">Получение доступа к скорости вашего автомобиля</string>\n    <string name=\"perm_car_fuel_label\">Уровень топлива в машине</string>\n    <string name=\"perm_car_fuel_description\">Получение доступа к информации об уровне топлива вашего автомобиля</string>\n    <string name=\"perm_car_vendor_extension_description\">Получение доступа к каналу поставщика вашего автомобиля для обмена информацией, касающейся конкретного автомобиля</string>\n    <string name=\"backup_disabled\">Резервное копирование недоступно</string>\n    <string name=\"prefcat_accounts_settings_title\">Настройки</string>\n    <string name=\"prefcat_accounts_current_accounts_title\">Аккаунты</string>\n    <string name=\"pref_vending_licensing_category\">Лицензирование Google Play</string>\n    <string name=\"pref_vending_billing_category\">Платежи Google Play</string>\n    <string name=\"pref_vending_billing_enable_summary\">Если включено, некоторые приложения смогут совершать покупки или подписки через службу Google Play Billing.</string>\n    <string name=\"pref_vending_billing_note_experimental\">Эта функция экспериментальная и может привести к потере денег. Вы были предупреждены.</string>\n    <string name=\"pref_vending_billing_note_licensing\">Некоторым приложениям может потребоваться, чтобы вы включили проверку лицензии для проверки ваших платежей.</string>\n    <string name=\"pref_accounts_title\">Аккаунты Google</string>\n    <string name=\"pref_accounts_summary\">Добавление и управление учётными записями Google</string>\n    <string name=\"pref_vending_billing_enable_switch\">Обрабатывать платежи</string>\n    <string name=\"credentials_assisted_cancel\">Отмена</string>\n    <string name=\"credentials_assisted_continue\">Продолжить</string>\n    <string name=\"credentials_assisted_confirmation_header\">Вход в систему</string>\n    <string name=\"credentials_assisted_signin_consent_header\">Входим как %1$s</string>\n    <string name=\"credentials_assisted_sign_back_title\">Снова войти в %1$s с аккаунтом Google</string>\n    <string name=\"credentials_assisted_choose_account_label\">Выберите аккаунт</string>\n    <string name=\"credentials_assisted_choose_account_subtitle\">для продолжения использования %1$s</string>\n    <string name=\"credentials_assisted_signin_button_text_long\">Вход с аккаунтом Google</string>\n    <string name=\"credentials_assisted_continue_as_user_button_label\">Продолжить как %1$s</string>\n    <string name=\"credentials_assisted_signin_consent\">Если продолжите, Google предоставит %1$s ваше имя, адрес электронной почты и фотографию профиля. Ознакомьтесь с политикой конфиденциальности и условиями использования %1$s.</string>\n    <string name=\"credentials_assisted_signin_description\">Вы можете управлять авторизацией в своих учетных записях Google.</string>\n    <string name=\"auth_package_override_request_title\">Разрешить <b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> привилегированный доступ к <xliff:g example=\"account@example.com\">%2$s</xliff:g>\\?</string>\n    <string name=\"auth_package_override_request_message\"><b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> пытается получить доступ к учётной записи под видом <b><xliff:g example=\"F-Droid\">%2$s</xliff:g> от <xliff:g example=\"F-Droid Inc.\">%3$s</xliff:g></b>. Это даст привилегированный доступ к вашей учётной записи.</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_switch\">Автоматически добавлять бесплатные приложения в библиотеку</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_summary\">Бесплатные приложения могут проверять, загружались ли они из Google Play. Автоматическое добавление бесплатных приложений в библиотеку вашего аккаунта позволяет всегда проходить проверку для всех доступных вам бесплатных приложений.</string>\n    <string name=\"limited_services_dialog_information_ack\">Я понимаю</string>\n    <string name=\"games_leaderboard_empty_text\">Нет таблицы лидеров для этой игры</string>\n    <string name=\"games_achievements_empty_text\">Нет достижений для этой игры</string>\n    <string name=\"games_achievement_list_title\">Достижения</string>\n    <string name=\"games_delete_snapshot_dialog_message\">Вы уверены что хотите удалить эту сохраненную игру?</string>\n    <string name=\"games_delete_snapshot_dialog_title\">Удалить сохраненную игру</string>\n    <string name=\"games_snapshot_delete_btn_text\">удалить</string>\n    <string name=\"games_snapshot_choose_btn_text\">выбрать</string>\n    <string name=\"games_leaderboards_score_label\">Счет: %1$s</string>\n    <string name=\"games_leaderboard_list_title\">Рейтинги</string>\n    <string name=\"games_leaderboard_score_empty_text\">Невероятно! Для этой игры нету публичных высоких счетов.</string>\n    <string name=\"limited_services_app_name\">Ограниченные сервисы microG</string>\n    <string name=\"auth_action_notification_channel_name\">Оповещения Google аккаунта</string>\n    <string name=\"auth_action_notification_content\">Вашему Google аккаунту нужна дополнительная настройка.</string>\n    <string name=\"auth_action_activity_header\">Завершите настройку вашего Google аккаунта</string>\n    <string name=\"auth_action_activity_explanation\">Выполните следующие действия для того, чтобы использовать ваш Google аккаунт %s на этом устройстве.</string>\n    <string name=\"auth_action_step_enable_checkin\">Включить регистрацию устройства</string>\n    <string name=\"auth_action_step_enable_gcm\">Включить Облачный Обмен Сообщениями</string>\n    <string name=\"auth_action_step_allow_microg_gcm\">Разрешить Облачный Обмен Сообщениями для microG</string>\n    <string name=\"auth_action_step_perform_content_description\">Нажмите, чтобы выполнить шаг</string>\n    <string name=\"auth_action_activity_finish\">Завершить</string>\n    <string name=\"auth_action_step_completed_content_description\">Шаг выполнен</string>\n    <string name=\"pref_vending_asset_delivery_summary\">Загрузить дополнительные ресурсы по запросу приложений, которые используют Play Asset Delivery</string>\n    <string name=\"auth_action_step_allow_microg_gcm_description\">В соответствии с вашими предпочтениями, microG нужно разрешение от вас перед тем как оно может зарегистрировать себя для Облачного Обмена Сообщениями.</string>\n    <string name=\"auth_action_step_enable_gcm_description\">Вы можете отключить Облачный Обмен Сообщениями после того, как настройка аккаунта будет выполнена.</string>\n    <string name=\"games_delete_snapshot_dialog_ok\">Хорошо</string>\n    <string name=\"games_delete_snapshot_dialog_cancel\">Отменить</string>\n    <string name=\"pref_vending_asset_device_sync_switch\">Включить синхронизацию информации устройства</string>\n    <string name=\"auth_action_notification_channel_description\">Оповещает, когда один из ваших Google аккаунтов требует дополнительной настройки перед использованием или когда аккаунт несовместим с microG.</string>\n    <string name=\"games_achievement_locked_content_description\">заблокировано</string>\n    <string name=\"games_achievement_unlocked_content_description\">разблокировано</string>\n    <string name=\"games_achievement_extra_text\">%1$s ОПЫТ</string>\n    <string name=\"games_delete_snapshot_error\">Удаление не удалось, пожалуйста, попробуйте позже</string>\n    <string name=\"auth_action_step_enable_checkin_description\">Ваше устройство должно быть зарегистрировано в Google хотя бы один раз.\\n\\nВы можете отключить регистрацию устройств Google после того, как настройка аккаунта будет завершена.</string>\n    <string name=\"auth_action_notification_title\">Требуется действие с аккаунтом</string>\n    <string name=\"service_name_work_profile\">Рабочая учётная запись</string>\n    <string name=\"pref_vending_split_install_switch\">Установка компонентов по требованию</string>\n    <string name=\"pref_vending_licensing_split_install_summary\">Разрешить приложениям скачивать и устанавливать дополнительные компоненты</string>\n    <string name=\"pref_workprofile_create_account\">Разрешить настройку рабочей учетной записи</string>\n    <string name=\"camera_permission_dialog_button\">Хорошо</string>\n    <string name=\"camera_permission_dialog_title\">Требуется разрешение на камеру</string>\n    <string name=\"camera_permission_dialog_message\">Сервисам microG нужен доступ к камере вашего устройства, чтобы сканировать код для %1$s.\\n\\nЧтобы включить, пожалуйста предоставьте разрешение на камеру сервисам microG в Настройках.</string>\n    <string name=\"pref_vending_asset_delivery_switch\">Разрешить отправку пакетов по требованию</string>\n    <string name=\"credentials_assisted_signin_add_account\">Добавить Аккаунт</string>\n    <string name=\"pref_vending_feature_delivery\">Доставка Функций Google Play</string>\n    <string name=\"barcode_scanner_brand\">Отсканировано microG с разрешения %1$s</string>\n    <string name=\"pref_vending_asset_delivery_category\">Доставка Пакетов Google Play</string>\n    <string name=\"games_snapshot_empty_text\">Не было выполнено ни одного сохранения игры</string>\n    <string name=\"pref_vending_asset_device_sync_summary\">Приложения, использующие Play Asset Delivery, будут загружать дополнительные активы на основе информации об используемом в данный момент устройстве.</string>\n    <string name=\"pref_workprofile_disclaimer\">Вы несете ответственность за то, чтобы использование microG соответствовало корпоративной политике. microG предоставляется на основе наилучших усилий и не может гарантировать, что его поведение будет точно соответствовать ожиданиям.</string>\n    <string name=\"pref_workprofile_intro\">При настройке рабочего профиля на рабочем месте или в учебном заведении установка может попытаться подключиться к Google, чтобы загрузить приложения в этот профиль.</string>\n    <string name=\"games_api_access_denied\">Ни одна учетная запись на этом устройстве не может получить доступ к Games APIs</string>\n    <string name=\"auth_action_step_enable_lockscreen\">Настройте блокировку экрана</string>\n    <string name=\"auth_action_step_enable_lockscreen_description\">Ваш аккаунт Google управляется вашей организацией. Ваш администратор решил, что устройствам нужно настроить блокировку экрана, перед тем, как получить доступ к данным аккаунта.\\n\\nНастройте пароль, PIN или графический ключ.</string>\n    <string name=\"credentials_assisted_choose_account_error_tips\">Аномалия аккаунта</string>\n    <string name=\"limited_services_dialog_information\">Вы используете ограниченную версию сервисов microG. В отличие от обычной версии сервисов MicroG, эти сервисы работают только с теми приложениями, которые используют библиотеки microG. Это означает, что большинство приложений будут игнорировать эти сервисы.</string>\n    <string name=\"auth_action_reauth_notification_title\">Требуется действие с аккаунтом</string>\n    <string name=\"pref_auth_two_step_verification_title\">Получать запросы двухфакторной аутентификации</string>\n    <string name=\"pref_auth_two_step_verification_summary\">Когда включено, устройство может получать запросы двухфакторной аутентификации от Google (необходимо включить облачные сообщения).</string>\n    <string name=\"pref_game_accounts_title\">Игровые аккаунты Google</string>\n    <string name=\"pref_auto_create_player\">Разрешить регистрацию аккаунта Play игр</string>\n    <string name=\"pref_auto_create_player_intro\">Когда вы играете в игры, вам необходимо использовать учетную запись Play Игр для входа в систему и записывать функции игр, таких как достижения, таблицы лидеров, архивы и т.д. После отключения, учетные записи Google, которые не привязаны к учетной записи Play Игр, не будут автоматически зарегистрированы, и в игру нельзя будет войти и играть в нее.</string>\n    <string name=\"pref_allow_upload_game_played\">Разрешить загрузку сыгранных игр</string>\n    <string name=\"pref_allow_upload_game_played_summary\">Когда выключено, игра не будет сообщать статус сыгранности после входа в игру, и будет невозможно зайти в некоторые игры.</string>\n    <string name=\"pref_change_default_game_player\">Сменить аккаунт для Игр</string>\n    <string name=\"pref_change_default_game_player_summary\">Сменить аккаунт для Игр по-умолчанию &amp; сменить аккаунт для игры.</string>\n    <string name=\"pref_delete_game_account_data\">Удалить данные Play Игр</string>\n    <string name=\"pref_delete_game_account_data_summary\">Удалить аккаунт Play Игр и все данные &amp; удалить данные для игры.</string>\n    <string name=\"games_state_description_signed_out\">Вы вышли из аккаунта</string>\n    <string name=\"games_state_description_delete\">Удалить</string>\n    <string name=\"games_change_button_text\">Сменить</string>\n    <string name=\"games_change_default_account_section_title\">Изменить аккаунт для Игр по-умолчанию</string>\n    <string name=\"games_change_default_account_description\">Аккаунт по-умолчанию: %1$s</string>\n    <string name=\"games_change_default_account_explanation\">Этот аккаунт используется для автоматического входа в игры, сохранения игрового прогресса и сохранения настроек. Смена аккаунта по-умолчанию или выход может сбросить ваш прогресс и настройки для игры, в которую вы играли.</string>\n    <string name=\"games_change_per_game_title\">Сменить аккаунт для игры</string>\n    <string name=\"games_change_per_game_description\">Смена аккаунта для выбранной игры или выход из аккаунта может сбросить ваш прогресс и настройки для игры.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_title\">Выберите опцию для нового аккаунта по-умолчанию</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_description\">Текущий аккаунт по-умолчанию: %1$s</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_title\">Сменить аккаунт по-умолчанию только для новых игр</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_description\">Вы не потеряете доступ к прогрессу и настройки для игр, в которые вы играли. Но ваш прогресс будет разбит между аккаунтами.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_title\">Сменить аккаунт по-умолчанию для всех игр</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_description\">Вы можете потерять доступ к своему прогрессу и настройкам в играх, в которых вы играли. Мы перезапустим игру для применения изменений.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_title\">Выйти из всех игр</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_description\">Вы можете потерять доступ к своему прогрессу и настройкам в играх, в которых вы играли. Мы перезапустим игру для применения изменений.</string>\n    <string name=\"games_change_per_game_dialog_title\">Выберите опцию для этой игры</string>\n    <string name=\"games_change_per_game_dialog_description\">Смена аккаунта или выход из него может сбросить ваш прогресс и настройки для этой игры</string>\n    <string name=\"games_change_per_game_dialog_option_use_player_snackbar_success_message\">Вы войдете в эту игру с аккаунтом %1$s</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out\">Выйти</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out_snackbar_success_message\">Вы вышли из аккаунта в этой игре</string>\n    <string name=\"games_change_sign_out_of_all_games_snackbar_success_message\">Вы вышли из аккаунта во всех играх</string>\n    <string name=\"games_change_default_account_for_all_games_snackbar_success_message\">Вы войдёте во все игры с аккаунтом %1$s</string>\n    <string name=\"games_change_default_account_for_new_games_snackbar_success_message\">Вы войдете в новых играх с аккаунтом %1$s</string>\n    <string name=\"games_account_display_content\">Текущий аккаунт: %1$s</string>\n    <string name=\"games_delete_profile_header\">Удалить аккаунт Play Игр и все данные</string>\n    <string name=\"games_delete_profile_explanation\">Удалите навсегда ваш аккаунт Google Play Игр, опыт и все данные профиля. Это действие также удалит достижения, прогресс (сохраненные игры) и настройки в играх, в которые вы играли.</string>\n    <string name=\"games_delete_profile_button\">Удалить навсегда</string>\n    <string name=\"games_delete_game_data_header\">Удалить данные игры</string>\n    <string name=\"games_delete_game_data_explanation\">Вы можете удалить навсегда данные в определенных играх, в которые вы играли, используя Google Play Игр. Это удалит ваши достижения, прогресс (сохранённые игры) и настройки в играх, которые вы выбрали.</string>\n    <string name=\"games_delete_profile_dialog_title\">Вы уверены, что хотите удалить этот аккаунт?</string>\n    <string name=\"games_popup_signin_welcome\">Здравствуйте, %1$s</string>\n    <string name=\"games_delete_profile_dialog_message\">Это действие не может быть отменено.</string>\n    <string name=\"games_delete_profile_fail\">Невозможно удалить ваш профиль. Попробуйте позже.</string>\n    <string name=\"games_delete_profile_explanation_with_gamer_name\">Удалите навсегда свою учетную запись Google Play Games с именем игрока <b>%1$s</b> (<b>%2$s</b>), опытом и всеми данными профиля. Это действие также может привести к удалению ваших достижений, прогресса (сохраненных игр) и настроек в играх, в которые вы играли.</string>\n    <string name=\"games_delete_game_data_confirm_dialog_title\">Удаление данных для %1$s</string>\n    <string name=\"games_delete_game_data_confirm_dialog_message\">Удаление данных навсегда для %1$s приведет к потере достижений, прогресса (сохранённых игр) и игровых настроек в Google Play Играх.</string>\n    <string name=\"games_change_per_game_dialog_option_use_player\">Использовать %1$s</string>\n    <string name=\"location_sharing_description\">Управляйте обменом местоположения в реальном времени во всех приложениях Google и сервисах на этом устройстве</string>\n    <string name=\"location_sharing_learn_more\">Узнайте больше об обмене местоположением</string>\n    <string name=\"location_sharing_switch_text\">Использовать обмен местоположением</string>\n    <string name=\"location_sharing_turn_off_notify_hint\">Если вы отключите обмен местоположением на этом устройстве, то люди, с которыми вы обмениваетесь им, не будут оповещены.</string>\n    <string name=\"location_sharing_off_previous_hint\">Только ваше последнее местоположение будет доступно до тех пор, пока вы не включите его снова.</string>\n    <string name=\"location_sharing_disabled\">Нет активного обмена местоположением на этом аккаунте</string>\n    <string name=\"location_sharing_turn_on_hint\">Когда вы начнёте делиться местоположением из приложения Google или сервиса, вы можете управлять обменом местоположения здесь. \\n\\nЧтобы начать делиться местоположением, перейдите в Google Карты или Family Link.</string>\n    <string name=\"location_sharing_turn_off_title\">Выключить обмен местоположением</string>\n    <string name=\"location_sharing_turn_off_hint\">Вы можете продолжать делиться местоположением с других устройств, на которых вы вошли в тот-же аккаунт Google, или через сторонние приложения. Проверьте свои настройки обменом местоположения везде, где они могут применяться.\\n\\nЛюди, с которыми вы делились местоположением, продолжат видеть ваше последнее сохранённое местоположение.</string>\n    <string name=\"location_sharing_turn_off_cancel\">Оставить вкл.</string>\n    <string name=\"location_sharing_turn_off_confirm\">Выключить</string>\n    <string name=\"location_sharing_confirm_dialog_title\">Включить обмен местоположением</string>\n    <string name=\"location_sharing_confirm_dialog_text\">Люди, с которыми вы поделитесь местоположением, будут видеть:\\n• Ваше имя и фото\\n• Ваше последнее местоположение устройства, даже когда вы не будете использовать сервис Google\\n• Заряд батареи вашего устройства и когда оно заряжается\\n• Ваше время отправления и прибытия, если они добавят уведомление обмена местоположением</string>\n    <string name=\"service_name_google_location_sharing\">Обмен местоположением Google</string>\n    <string name=\"pref_app_install_other_apps_note\">Данное разрешение даёт добро на установку приложений, предоставляемых из других источников.</string>\n    <string name=\"pref_app_install_permission_instruction\">Чтобы убедиться, что Ваши установленные приложения работают без проблем, пожалуйста, разрешите Компаньону microG устанавливать приложения, загруженные из других источников.</string>\n    <string name=\"pref_app_install_settings_title\">Настройки установщика приложений</string>\n    <string name=\"pref_app_install_switch_title\">Разрешить установку приложений</string>\n    <string name=\"family_management_title\">Семья</string>\n    <string name=\"family_management_retry\">Повторить</string>\n    <string name=\"family_management_load_error\">Ошибка загрузки содержимого</string>\n    <string name=\"family_management_toolbar_back\">Назад</string>\n    <string name=\"family_management_toolbar_more\">Больше</string>\n    <string name=\"family_management_exit_family_group\">Выйти из семейной группы</string>\n    <string name=\"family_management_delete_family_group\">Удалить семейную группу</string>\n    <string name=\"family_management_leave_family_password_title\">Подтвердите пароль для выхода из семейной группы</string>\n    <string name=\"family_management_delete_family_password_title\">Подтвердите пароль для удаления семейной группы</string>\n    <string name=\"family_management_remove_member_password_title\">Подтвердите пароль для удаления %s</string>\n    <string name=\"family_management_invite_family_member\">Пригласить членов семьи</string>\n    <string name=\"family_management_invite_slots_left\">Осталось приглашений: %1$d</string>\n    <string name=\"family_management_cancel_invite\">Отменить приглашение</string>\n    <string name=\"family_management_cancel_invite_success\">Приглашение успешно отменено</string>\n    <string name=\"family_management_cancel_invite_error\">Проблема с отменой приглашения. Попробуйте еще раз.</string>\n    <string name=\"family_management_remove_member\">Удалить члена</string>\n    <string name=\"family_management_member_removed_success\">%s был удален из семейной группы</string>\n    <string name=\"family_management_member_remove_failed\">Проблема с удалением %s. Попробуйте еще раз.</string>\n    <string name=\"family_management_leave_family_error_message\">Проблема с выходом из семейной группы. Попробуйте еще раз.</string>\n    <string name=\"family_management_exist_group_success\">Вы вышли из вашей семейной группы…</string>\n    <string name=\"family_management_delete_group_success\">Семейная группа удалена</string>\n    <string name=\"family_management_delete_group_failure\">Не удалось удалить семейную группу</string>\n    <string name=\"family_management_delete_group_cancel\">Отмена</string>\n    <string name=\"family_management_delete_group_confirm\">Хорошо</string>\n    <string name=\"family_management_input_pwd\">Пожалуйста введите ваш пароль</string>\n    <string name=\"family_management_invite_sent_date_format\">Приглашение отправлено %s</string>\n    <string name=\"family_management_invite_send\">Приглашение отправлено</string>\n    <string name=\"family_management_pwd_error\">Неверный пароль, пожалуйста введите заново</string>\n    <string name=\"prefcat_app_install_list_title\">Приложения, использующие App Installer</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-sl/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n</resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-sl/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n</resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-sl/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n</resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-sr/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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  --><resources>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense\">Преглед и управљање вашим AdSense подацима</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue.consumer\">Извршавање задатака из ваших Taskqueues</string>\n    <string name=\"permission_service_blogger_label\">Blogger</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tracks\">Google Maps Tracks API, овај опсег омогућава приступ за читање и писање података вашег пројекта.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.full_control\">Управљање вашим подацима и дозволама у Google Cloud Storage-у</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase.readonly\">преглед вашег Freebase налога</string>\n    <string name=\"permission_service_blogger_description\">Дозвољава апликацији да приступи Blogger-у преко било ког повезаног Google налога.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.readonly\">Преглед фајлова и докумената на вашем Google диску</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.readonly\">Читање свих ресурса и њихових метаподатака—нема операција писања.</string>\n    <string name=\"permission_service_sitemaps_label\">Google Webmaster алатке</string>\n    <string name=\"permission_service_adwords_label\">AdWords</string>\n    <string name=\"permission_service_gbase_description\">Омогућава апликацији да приступи Google Base-у преко било ког повезаног Google налога.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate.readonly\">Преглед ваших Google Coordinate послова</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.file\">Преглед и управљање фајловима Google диска који су отворени или направљени помоћу ове апликације</string>\n    <string name=\"permission_service_speechpersonalization_label\">Персонализовано препознавање говора</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.appdata\">Омогућава приступ фолдеру Application Data</string>\n    <string name=\"permission_service_youtube_label\">YouTube</string>\n    <string name=\"permission_service_news_label\">Google вести</string>\n    <string name=\"permission_service_speechpersonalization_description\">Дозвољава апликацији да приступи Персонализованом препознавању говора преко било ког повезаног Google налога.</string>\n    <string name=\"permission_service_all_label\">Све Google услуге</string>\n    <string name=\"permission_service_sitemaps_description\">Дозвољава апликацији да приступи Google Webmaster алаткама преко било ког повезаног Google налога.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue\">Управљање задацима</string>\n    <string name=\"permission_service_finance_description\">Дозвољава апликацији да приступи Google Finance-у преко било ког повезаног Google налога.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine\">Преглед и управљање вашим Google Maps Engine подацима</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine.readonly\">Преглед ваших Google Maps Engine података</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_activity\">Преглед историје активности ваших Google апликација</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive\">Преглед и управљање фајловима и документима на вашем Google диску</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics.readonly\">Преглед ваших Google Analytics података</string>\n    <string name=\"permission_service_writely_description\">Дозвољава апликацији да приступа Google документима преко било ког повезаног Google налога.</string>\n    <string name=\"permission_service_writely_label\">Google документи</string>\n    <string name=\"permission_service_orkut_label\">Orkut</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_prediction\">Управљање вашим подацима у Google Prediction API</string>\n    <string name=\"permission_service_youtube_description\">Дозвољава апликацији да приступи YouTube-у преко било ког повезаног Google налога.</string>\n    <string name=\"permission_service_wise_label\">Google табеле</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_structuredcontent\">Приступ читања/писања за Shopping Content API.</string>\n    <string name=\"permission_service_speech_description\">Дозвољава апликацији да приступи Гласовној претрази преко било ког повезаног Google налога.</string>\n    <string name=\"permission_service_knol_description\">Дозвољава апликацији да приступи Knol-у преко било ког повезаног Google налога.</string>\n    <string name=\"permission_service_wifi_label\">Google Wi-Fi</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.me\">Зна ко сте ви на Google-у</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.login\">Зна ваше име, основне информације и листу људи са којима сте повезани на Google+</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics.readonly\">Преглед YouTube Analytics извештаја за ваш YouTube садржај</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics\">Преглед и управљање вашим Google Analytics подацима</string>\n    <string name=\"permission_service_health_label\">Google здравље</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut\">Управљање вашом Orkut активности</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.apps.readonly\">Преглед ваших Google диск апликација</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.compose\">Прављење, читање, ажурирање и брисање нацрта. Слање порука и нацрта.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger.readonly\">Преглед вашег Blogger налога</string>\n    <string name=\"permission_service_android_label\">Android услуге</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.licensing\">Приступ за читање/писање за License Manager API.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery\">Преглед и улрављање вашим подацима у Google BigQuery-ју</string>\n    <string name=\"permission_service_health_description\">Дозвољава апликацији да приступа Google здрављу преко било ког повезаног Google налога.</string>\n    <string name=\"permission_service_jotspot_description\">Дозвољава апликацији да приступи JotSpot-у преко било ког повезаног Google налога.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_dfareporting\">Преглед и управљање DoubleClick за оглашаваче извештајима</string>\n    <string name=\"permission_service_notebook_label\">Google свеска</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_urlshortener\">Управљање вашим goo.gl кратким URL адресама</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube\">Управљање вашим YouTube налогом</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery.readonly\">Преглед ваших података у Google BigQuery-ју</string>\n    <string name=\"permission_service_cp_label\">Контакти</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order\">За администраторе препродавача и кориснички приступ за читање/писање приликом тестирања у заштићеном окружењу API-ја или приступ за читање/писање када се директно позива API операција.</string>\n    <string name=\"permission_service_local_description\">Дозвољава апликацији да приступи Google мапама преко било ког повезаног Google налога.</string>\n    <string name=\"permission_service_speech_label\">Гласовна претрага</string>\n    <string name=\"permission_service_groups2_description\">Дозвољава апликацији да приступа Google групама преко било ког повезаног Google налога.</string>\n    <string name=\"permission_service_local_label\">Google мапе</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.buyer\">Управљање подешавањем Ad Exchange налога купца</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gcm_for_chrome\">Размена порука у облаку за Chrome</string>\n    <string name=\"permission_service_adsense_description\">Дозвољава апликацији да приступи AdSense-у преко било ког повезаног Google налога.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller\">Преглед и управљање вашим Ad Exchange подацима</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_shoppingapi\">Преглед ваших података производа</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsensehost\">Преглед и управљање подацима о AdSense хосту и повезаним налозима</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.scripts\">Измена понашања ваших Google Apps Script скрипата</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_write\">Управљање вашим подацима у Google Cloud Storage-у</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mobilemaps.firstparty\">Преглед и управљање вашим Google мапама за мобилно искуство</string>\n    <string name=\"permission_service_grandcentral_description\">Дозвољава апликацији да приступи Google Voice-у преко било ког повезаног Google налога.</string>\n    <string name=\"permission_service_cl_description\">Дозвољава апликацији да приступи Google календару преко било ког повезаног Google налога.</string>\n    <string name=\"permission_service_cl_label\">Google календар</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appstate\">Опсег коришћења App State услуге.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics_monetary.readonly\">Преглед YouTube Analytics монетарних извештаја за ваш YouTube садржај</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.city\">Управљање вашом локацијом на нивоу града и историјом локација</string>\n    <string name=\"permission_service_talk_label\">Google Talk</string>\n    <string name=\"permission_service_ig_label\">iGoogle</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks\">Управљање вашим задацима</string>\n    <string name=\"permission_service_android_description\">Дозвољава апликацији да приступа Android услугама преко било ког повезаног Google налога.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.settings\">Преглед и управљање подешавањима Google Apps Group-а</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute.readonly\">Преглед ваших Google Compute Engine изворима</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller.readonly\">Преглед ваших Ad Exchange података</string>\n    <string name=\"permission_service_ig_description\">Дозвољава апликацији да приступи iGoogle-у преко било ког повезаног Google налога.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables\">Управљање вашим Fusion табелама</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan.readonly\">Преглед ваших GAN података</string>\n    <string name=\"permission_service_adsense_label\">AdSense</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification.verify_only\">Управљање вашим потврдама нових сајтова са Google-ом</string>\n    <string name=\"permission_service_orkut_description\">Дозвољава апликацији да приступи Orkut-у преко било ког повезаног Google налога.</string>\n    <string name=\"permission_service_sierrasandbox_label\">Google Checkout Sandbox налози</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.metadata.readonly\">Преглед метаподатака за фајлове и документе на вашем Google диску</string>\n    <string name=\"permission_service_sierra_description\">Дозвољава апликацији да приступа Google Checkout налозима преко било ког повезаног Google налога.</string>\n    <string name=\"permission_service_lh2_description\">Дозвољава апликацији да приступи Picasa Web Albums-у преко било ког повезаног Google налога.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_games\">Опсег приступа подацима из Google Play игара.</string>\n    <string name=\"permission_service_wifi_description\">Дозвољава апликацији да приступи Google Wi-Fi-ју преко било ког повезаног Google налога.</string>\n    <string name=\"permission_service_all_description\">Дозвољава апликацији да приступи свим Google услугама преко било ког повезаног Google налога.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_only\">Преглед ваших података у Google Cloud Storage-у</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar.readonly\">Преглед ваших календара</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appengine.admin\">Опсег администратора апликације.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_androidpublisher\">Приступ Google Play Android програмеру</string>\n    <string name=\"permission_service_notebook_description\">Дозвољава апликацији да приступи Google свесци преко било ког повезаног Google налога.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification\">Управљање листом сајтова и домена које контролишете</string>\n    <string name=\"permission_service_YouTubeUser_label\">YouTube корисничка имена</string>\n    <string name=\"permission_service_mail_label\">Google мејл</string>\n    <string name=\"permission_service_dodgeball_label\">Dodgeball</string>\n    <string name=\"permission_service_adwords_description\">Дозвољава апликацији да приступи AdWords-у преко било ког повезаног Google налога.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.install\">Посебан опсег који се користи за омогућавање корисницима да одобре инсталацију апликације</string>\n    <string name=\"permission_service_news_description\">Дозвољава апликацији да приступа Google вестима преко било ког повезаног Google налога.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables.readonly\">Преглед ваших Fusion табела</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.modify\">Све операције читања/писања осим тренутног, трајног брисања нити и порука, заобилазећи смеће.</string>\n    <string name=\"permission_service_gbase_label\">Google Base</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.city\">Управљање вашом локацијом на нивоу града</string>\n    <string name=\"permission_service_wise_description\">Дозвољава апликацији да приступи Google табелама преко било ког повезаног Google налога.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.migration\">Приступ за читање и писање за Groups Migration API.</string>\n    <string name=\"permission_service_sierrasandbox_description\">Дозвољава апликацији да приступи Google Checkout Sandbox налозима преко било ког повезаног Google налога.</string>\n    <string name=\"permission_service_print_description\">Дозвољава апликацији да приступи Google претрази књига преко било ког повезаног Google налога.</string>\n    <string name=\"permission_service_mail_description\">Дозвољава апликацији да приступи Google мејлу преко било ког повезаног Google налога.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.email\">Преглед ваше имејл адресе</string>\n    <string name=\"permission_service_jotspot_label\">JotSpot</string>\n    <string name=\"permission_service_lh2_label\">Picasa Web Albums</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase\">Пријава на Freebase с вашим налогом</string>\n    <string name=\"permission_service_groups2_label\">Google групе</string>\n    <string name=\"permission_service_ah_description\">Дозвољава апликацији да приступи Google App Engine-у преко било ког повезаног Google налога.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_glass.timeline\">Опсег временске линије стакла</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate\">Преглед и управљање вашим Google Maps Coordinate пословима</string>\n    <string name=\"permission_service_ah_label\">Google App Engine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute\">Преглед и управљање вашим Google Compute Engine изворима</string>\n    <string name=\"permission_service_sierra_label\">Google Checkout налози</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.profile\">Преглед основних информација о вашем налогу</string>\n    <string name=\"permission_service_YouTubeUser_description\">Дозвољава апликацији да приступи YouTube корисничким именима која се користе са било којим повезаним Google налогом.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar\">Управљање вашим календарима</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_books\">Управљање вашим књигама</string>\n    <string name=\"permission_service_sierraqa_description\">Дозвољава апликацији да приступи Google Checkout QA налозима преко било ког повезаног Google налога.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan\">Управљање вашим GAN подацима</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut.readonly\">Преглед ваших Orkut података</string>\n    <string name=\"permission_service_talk_description\">Дозвољава апликацији да приступи Google Talk-у преко било ког повезаног Google налога.</string>\n    <string name=\"permission_service_sierraqa_label\">Google Checkout QA налози</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks.readonly\">Преглед ваших задатака</string>\n    <string name=\"permission_service_dodgeball_description\">Дозвољава апликацији да приступи Dodgeball-у преко било ког повезаног Google налога.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.best\">Управљање најбољом доступном локацијом и историјом локација</string>\n    <string name=\"permission_service_cp_description\">Дозвољава апликацији да приступи Контактима преко било ког повезаног Google налога.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense.readonly\">Преглед ваших AdSense података</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.readonly\">Преглед вашег YouTube налога</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_cloudprint\">Преглед и управљање вашим Google Cloud Print подацима</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order.readonly\">Поред укупног OAuth опсега за читање/писање, користи се OAuth опсег само за читање када се преузимају подаци клијента.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger\">Управљање вашим Blogger налогом</string>\n    <string name=\"permission_service_grandcentral_label\">Google Voice</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps_reporting_audit.readonly\">Приступ за Admin Audit API само за читање</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.best\">Управљање најбољом доступном локацијом</string>\n    <string name=\"permission_service_print_label\">Google претрага књига</string>\n    <string name=\"permission_service_finance_label\">Google Finance</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtubepartner\">Преглед и управљање вашим средствима и повезаним садржајем на YouTube-у</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.upload\">Преглед ваших YouTube видео снимака</string>\n    <string name=\"permission_service_knol_label\">Knol</string>\n    <string name=\"perm_activity_recognition_label\">Препознавање активности</string>\n    <string name=\"perm_activity_recognition_description\">Дозвољава апликацији да прима периодична ажурирања нивоа ваше активности од Google-а, на пример, ако ходате, возите аутомобил или бицикл или стојите.</string>\n</resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-sr/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2017 microG Project Team\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  --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <plurals name=\"gcm_registered_apps_counter\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> регистрована апликација</item>\n        <item quantity=\"few\"><xliff:g example=\"123\">%1$d</xliff:g> регистроване апликације</item>\n        <item quantity=\"other\"><xliff:g example=\"123\">%1$d</xliff:g> регистрованих апликација</item>\n    </plurals>\n    <plurals name=\"cond_perm_summary\">\n        <item quantity=\"one\">Дозвола потребна за исправну функционалност microG услуга није дата.</item>\n        <item quantity=\"few\">Дозволе потребне за исправну функционалност microG услуга нису дате.</item>\n        <item quantity=\"other\">Дозволе потребне за исправну функционалност microG услуга нису дате.</item>\n    </plurals>\n    <plurals name=\"cond_perm_action\">\n        <item quantity=\"one\">Захтевај недостајућу дозволу</item>\n        <item quantity=\"few\">Захтевај недостајуће дозволе</item>\n        <item quantity=\"other\">Захтевај недостајуће дозволе</item>\n    </plurals>\n    <plurals name=\"pref_unifiednlp_summary\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> бекенд подешен</item>\n        <item quantity=\"few\"><xliff:g example=\"3\">%1$d</xliff:g> бекенда подешена</item>\n        <item quantity=\"other\"><xliff:g example=\"3\">%1$d</xliff:g> бекендова подешено</item>\n    </plurals>\n</resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-sr/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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  --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"gms_app_name\">microG услуге</string>\n    <string name=\"gms_settings_name\">microG подешавања</string>\n    <string name=\"just_a_sec\">Само тренутак…</string>\n    <string name=\"google_account_label\">Google</string>\n    <string name=\"ask_permission_tos\">Ако наставите, дозволићете овој апликацији и Google-у да користе ваше податке у складу са њиховим условима коришћења и политикама приватности.</string>\n    <string name=\"ask_scope_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> жели да:</string>\n    <string name=\"ask_service_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> жели да користи:</string>\n    <string name=\"account_manager_title\">Менаџер Google налога</string>\n    <string name=\"sorry\">Извините…</string>\n    <string name=\"no_network_error_desc\">Нисте повезани на мрежу.\n\\n\n\\nОво може бити привремени проблем или ваш Android уређај можда није обезбеђен за услуге преноса података. Покушајте поново када се повежете на мобилну мрежу или на Wi-Fi мрежу.</string>\n    <string name=\"auth_general_error_desc\">Дошло је до грешке приликом комуникације са Google серверима.\n\\n\n\\nПокушајте поново касније.</string>\n    <string name=\"auth_finalize\">Ваш уређај контактира Google да би сачувао податке на ваш налог.\n\\n\n\\nОво може да потраје неколико минута.</string>\n    <string name=\"allow\">Дозволи</string>\n    <string name=\"deny\">Одбиј</string>\n    <string name=\"auth_notification_title\">Потребна је аутентификација</string>\n    <string name=\"auth_notification_content\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> захтева вашу аутентификацију за приступ вашем Google налогу.</string>\n    <string name=\"perm_status_broadcast_label\">слушање унутрашњих статусних емитовања</string>\n    <string name=\"perm_c2dm_receive_label\">слушање C2DM порука</string>\n    <string name=\"perm_c2dm_send_label\">слање C2DM порука другим апликацијама</string>\n    <string name=\"perm_gtalk_svc_label\">размена порука и примање обавештења о синхронизацији са Google серверима</string>\n    <string name=\"perm_extended_access_label\">Проширени приступ Google услугама</string>\n    <string name=\"service_name_checkin\">Регистрација уређаја на Google</string>\n    <string name=\"service_name_mcs\">Размена порука у облаку</string>\n    <string name=\"games_title\">Google Play игре</string>\n    <string name=\"games_info_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> жели да користи Play игре</string>\n    <string name=\"games_info_content\">Да бисте користили Play игре, потребно је да инсталирате Google Play игре. Апликација би могла да настави и без тога, али ће можда да се понаша неочекивано.</string>\n    <string name=\"pick_place_title\">Изаберите место</string>\n    <string name=\"pick_place_desc\">Бирач места још није доступан.</string>\n    <string name=\"place_picker_select_title\">Изаберите ову локацију</string>\n    <string name=\"place_picker_nearby_places\">Оближња места</string>\n    <string name=\"place_picker_location_lat_lng\">(%1$.7f, %2$.7f)</string>\n    <string name=\"lacking_permission_toast\">microG услуге: недостаје дозвола за <xliff:g example=\"have full network acccess\"> %1$s</xliff:g></string>\n    <string name=\"network_type_mobile\">Мобилна мрежа</string>\n    <string name=\"network_type_wifi\">Wi-Fi мрежа</string>\n    <string name=\"network_type_roaming\">Роминг</string>\n    <string name=\"network_type_other\">Остале мреже</string>\n    <!-- Self check -->\n    <string name=\"self_check_cat_fake_sig\">Подршка за лажирање потписа</string>\n    <string name=\"self_check_cat_gms_packages\">Инсталирани пакети</string>\n    <string name=\"self_check_cat_system\">Систем</string>\n    <string name=\"self_check_name_fake_sig_perm\">Систем има подршку лажирања потписа:</string>\n    <string name=\"self_check_resolution_fake_sig_perm\">Ваш ROM нема уграђену подршку за лажирање потписа. Свакако, можете да користите Xposed или друге системе лажирања потписа. Погледајте документацију да бисте видели који ROM-ови подржавају лажирање потписа и како да користите microG на ROM-овима који не подржавају.</string>\n    <string name=\"self_check_name_perm_granted\">Систем одобрава дозволу лажирања потписа:</string>\n    <string name=\"self_check_resolution_perm_granted\">Ово је озбиљан индикатор да ROM подржава лажирање потписа, али да захтева додатне радње за активацију. Погледајте документацију да бисте видели потребне кораке.</string>\n    <string name=\"self_check_name_system_spoofs\">Систем лажира потпис:</string>\n    <string name=\"self_check_resolution_system_spoofs\">Погледајте документацију да бисте видели потребне кораке.</string>\n    <string name=\"self_check_pkg_gms\">microG услуге</string>\n    <string name=\"self_check_pkg_vending\">microG пратилац / Play продавница</string>\n    <string name=\"self_check_pkg_gsf\">microG радни оквир услуге</string>\n    <string name=\"self_check_name_app_installed\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> инсталирано: </string>\n    <string name=\"self_check_resolution_app_installed\">Инсталирајте апликацију <xliff:g example=\"F-Droid\"> %1$s</xliff:g> или компатибилну апликацију. Погледајте документацију да бисте видели које апликације су компатибилне.</string>\n    <string name=\"self_check_name_correct_sig\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> има тачан потпис: </string>\n    <string name=\"self_check_resolution_correct_sig\">Или инсталирана <xliff:g example=\"F-Droid\"> %1$s</xliff:g> није компатибилна апликација или лажирање потписа није активно за њу. Погледајте документацију да бисте видели које апликације и ROM-ови су компатибилни.</string>\n    <string name=\"self_check_name_battery_optimizations\">Занемарене оптимизације батерије:</string>\n    <string name=\"self_check_resolution_battery_optimizations\">Додирните овде да бисте онемогућили оптимизацију батерије. Ако ово не урадите, може доћи до лошег понашања апликација.</string>\n    <!-- Settings strings -->\n    <string name=\"prefcat_about\">О програму</string>\n    <string name=\"prefcat_components\">Компоненте</string>\n    <string name=\"prefcat_location_service\">Услуга локације</string>\n    <string name=\"prefcat_services\">Услуге</string>\n    <string name=\"cond_gcm_bat_title\">Оптимизације батерије омогућене</string>\n    <string name=\"cond_gcm_bat_summary\">Омогућили сте размену порука у облаку, али имате активне оптимизације батерије за microG услуге. Да би стигла push-обавештења, занемарите оптимизације батерије.</string>\n    <string name=\"cond_gcm_bat_action\">Занемари оптимизације</string>\n    <string name=\"cond_perm_title\">Недостају дозволе</string>\n    <string name=\"prefs_account\">Подешавања налога</string>\n    <string name=\"prefs_account_privacy\">Лични подаци и приватност</string>\n    <string name=\"prefs_account_security\">Пријава и безбедност</string>\n    <string name=\"pref_auth_trust_google_title\">Веруј Google-у за дозволе за апликације</string>\n    <string name=\"pref_auth_trust_google_summary\">Када је онемогућено, корисник ће бити упитан пре него што се Google-у пошаље захтев за овлашћење апликације. Неке апликације неће моћи да користе Google налог ако је ово онемогућено.</string>\n    <string name=\"pref_checkin_enable_summary\">Региструје ваш уређај на Google услуге и прави јединствени идентификатор уређаја. microG траке идентификују битове, осим имена вашег Google налога из података о регистрацији.</string>\n    <string name=\"pref_gcm_enable_mcs_summary\">Размена порука у облаку је пружалац push-обавештења који користе многе апликације трећих страна. Да бисте га користили, морате омогућити регистрацију уређаја.</string>\n    <string name=\"pref_gcm_heartbeat_title\">Интервал откуцаја размене порука у облаку</string>\n    <string name=\"pref_gcm_heartbeat_summary\">Интервал у секундама за који систем треба да откуца Google сервере. Повећање овог броја ће смањити потрошњу батерије, али може довести до кашњења push-обавештења.\n\\nЗастарело, биће замењено у будућем издању.</string>\n    <string name=\"pref_gcm_apps_title\">Апликације које користе размену порука у облаку</string>\n    <string name=\"pref_gcm_apps_summary\">Листа апликација које су тренутно регистроване за размену порука у облаку.</string>\n    <string name=\"pref_about_title\">О microG услугама</string>\n    <string name=\"pref_about_summary\">Информације о издању и коришћеним библиотекама</string>\n    <string name=\"gcm_app_error_unregistering\">Грешка при опозивању регистрације</string>\n    <string name=\"gcm_app_not_installed_anymore\">Апликација више није инсталирана</string>\n    <string name=\"gcm_unregister_app\">Опозови регистрацију</string>\n    <string name=\"gcm_not_registered\">Није регистровано</string>\n    <string name=\"gcm_no_message_yet\">До сада није примљена ниједна порука</string>\n    <string name=\"gcm_last_message_at\">Последња порука: <xliff:g example=\"Yesterday, 02:20 PM\"> %1$s</xliff:g></string>\n    <string name=\"gcm_registered\">Регистровано</string>\n    <string name=\"gcm_registered_since\">Регистровано од: <xliff:g example=\"Yesterday, 02:20 PM\"> %1$s</xliff:g></string>\n    <string name=\"gcm_unregister_confirm_title\">Опозвати регистрацију <xliff:g example=\"F-Droid\"> %1$s</xliff:g>\\?</string>\n    <string name=\"gcm_unregister_confirm_message\">Неке апликације се не региструју аутоматски и/или не пружају опцију да се то уради ручно. Ове апликације можда неће радити исправно након опозивања регистрације.\n\\nНаставити\\?</string>\n    <string name=\"gcm_unregister_after_deny_message\">Одбили сте апликацији да се региструје за push-обавештења, која је већ регистрована.\n\\nЖелите ли да опозовете регистрацију сада, да не бисте примали push-обавештења у будућности\\?</string>\n    <string name=\"gcm_messages_counter\">Обавештења: <xliff:g example=\"123\"> %1$d</xliff:g> (<xliff:g example=\"12345\"> %2$d</xliff:g> бајтова)</string>\n    <string name=\"pref_device_registration_import_custom_profile_title\">Увези прилагођени профил</string>\n    <string name=\"pref_safetynet_recent_request_type\">Тип захтева</string>\n    <string name=\"pref_recaptcha_enterprise_test_title\">Тестирај ReCAPTCHA Enterprise</string>\n    <string name=\"pref_gcm_confirm_new_apps_title\">Потврди нове апликације</string>\n    <string name=\"pref_safetynet_test_title\">Тестирај SafetyNet проверу статуса</string>\n    <string name=\"checkin_last_registration\">Последња регистрација: <xliff:g example=\"Yesterday, 02:20 PM\"> %1$s</xliff:g></string>\n    <string name=\"signin_subtext_policy_privacy\">политика приватности</string>\n    <string name=\"pref_safetynet_test_no_result\">Нема резултата</string>\n    <string name=\"safetynet_intro\">Google SafetyNet је систем сертификације уређаја, који осигурава да је уређај правилно обезбеђен и компатибилан са Android CTS. Неке апликације користе SafetyNet из безбедносних разлога или као предуслов за заштиту од неовлашћеног приступа.\n\\n\n\\nmicroG GmsCore садржи бесплатну имплементацију SafetyNet-а, али званични сервер захтева да SafetyNet захтеви буду потписани коришћењем власничког система DroidGuard.</string>\n    <string name=\"perm_gsf_read_gservices_label\">читање подешавања Google услуге</string>\n    <string name=\"auth_sign_in\">Пријави се</string>\n    <string name=\"pref_device_registration_import_custom_profile_summary\">Увезите профил уређаја из фајла</string>\n    <string name=\"pref_safetynet_recent_copy_json\">Копирај JSON JWS податке</string>\n    <string name=\"pref_test_summary_failed\">Неуспешно: %s</string>\n    <string name=\"pref_auth_visible_summary\">Када је омогућено, све апликације на овом уређају ће моћи да виде имејл адресу ваших Google налога без претходног овлашћења.</string>\n    <string name=\"pref_safetynet_recent_advice\">Савет</string>\n    <string name=\"push_notifications_summary_values_seconds\">%s секунди</string>\n    <string name=\"prefcat_configuration\">Подешавање</string>\n    <string name=\"prefcat_google_services\">Google услуге</string>\n    <string name=\"pref_safetynet_test_invalid_json\">Неважећи JSON</string>\n    <string name=\"menu_clear_recent_requests\">Очисти недавне захтеве</string>\n    <string name=\"signin_picker_title\">Изаберите налог</string>\n    <string name=\"pref_safetynet_recent_recaptcha_enterprise_summary\">ReCaptcha Enterprise: %s</string>\n    <string name=\"pref_safetynet_recent_cat_request\">Захтевај податке</string>\n    <string name=\"pref_push_app_wake_for_delivery_summary\">Покретање апликације док је у позадини да бисте примали долазна push-обавештења.</string>\n    <string name=\"pref_safetynet_recent_attestation_summary\">Провера статуса: %s</string>\n    <string name=\"prefcat_safetynet_apps_title\">Апликације које користе SafetyNet</string>\n    <string name=\"safetynet_enable_switch\">Дозволи проверу статуса уређаја</string>\n    <string name=\"pref_safetynet_test_integrity_failed\">Интегритет није успео</string>\n    <string name=\"push_notifications_summary_automatic\">УКЉУЧЕНО / Аутоматски: %s</string>\n    <string name=\"pref_device_registration_serial_title\">Серијски</string>\n    <string name=\"checkin_enable_switch\">Региструј уређај</string>\n    <string name=\"pref_safetynet_test_cts_failed\">CTS није успео</string>\n    <string name=\"push_notifications_summary_manual\">УКЉУЧЕНО / Ручно: %s</string>\n    <string name=\"profile_name_auto\">Аутоматски: %s</string>\n    <string name=\"push_notifications_summary_values_minutes\">%s минута</string>\n    <string name=\"perm_provision_label\">пружање microG услуга</string>\n    <string name=\"service_name_snet\">Google SafetyNet</string>\n    <string name=\"prefcat_test\">Тест</string>\n    <string name=\"gcm_network_state_connected\">Повезано <xliff:g example=\"2 hours ago\"> %1$s</xliff:g></string>\n    <string name=\"pref_more_settings\">Више</string>\n    <string name=\"pref_auth_include_android_id_summary\">Када је онемогућено, захтеви за аутентификацију неће бити повезани са регистрацијом уређаја, што ће можда омогућити неовлашћеним уређајима да се пријаве, али може имати непредвиђене последице.</string>\n    <string name=\"signin_picker_subtitle\">настави на <xliff:g example=\"F-Droid\"> %1$s</xliff:g></string>\n    <string name=\"pref_safetynet_test_integrity_cts_passed\">Интегритет и CTS су прошли</string>\n    <string name=\"pref_safetynet_recent_uses\">Недавне употребе</string>\n    <string name=\"pref_droidguard_unsupported_summary\">Извршење DroidGuard није подржано на овом уређају. SafetyNet услуге се могу лоше понашати.</string>\n    <string name=\"signin_confirm_title\">Дозволите пријаву на <xliff:g example=\"F-Droid\"> %1$s</xliff:g></string>\n    <string name=\"pref_safetynet_recent_nonce\">Nonce (Hex)</string>\n    <string name=\"safetynet_last_run_at\">Последња употреба: <xliff:g example=\"Yesterday, 02:20 PM\"> %1$s</xliff:g></string>\n    <string name=\"pref_gcm_confirm_new_apps_summary\">Будите упитани пре регистровања нове апликације да бисте примали push-обавештења</string>\n    <string name=\"pref_push_app_wake_for_delivery_title\">Покрени апликацију при push-обавештењу</string>\n    <string name=\"perm_provision_description\">Дозвољава апликацији да подешава microG услуге без интеракције корисника</string>\n    <string name=\"pref_safetynet_recent_recaptcha_summary\">ReCaptcha: %s</string>\n    <string name=\"gcm_enable_switch\">Примај push-обавештења</string>\n    <string name=\"pref_test_summary_passed\">Прођени сви тестови</string>\n    <string name=\"push_notifications_summary_off\">ИСКЉУЧЕНО</string>\n    <string name=\"pref_info_status\">Статус</string>\n    <string name=\"gcm_allow_app_popup\">Дозволити <xliff:g example=\"F-Droid\"> %1$s</xliff:g> да се региструје за push-обавештења\\?</string>\n    <string name=\"pref_safetynet_recent_response_status\">Статус одговора</string>\n    <string name=\"pref_auth_visible_title\">Дозволи апликацијама да пронађу налоге</string>\n    <string name=\"pref_device_registration_android_id\">Android ID</string>\n    <string name=\"gcm_network_state_disconnected\">Прекинута веза</string>\n    <string name=\"signin_picker_add_account_label\">Додај други налог</string>\n    <string name=\"pref_device_registration_select_profile_title\">Избор профила</string>\n    <string name=\"auth_connecting\">Ваш уређај успоставља везу са Google серверима да бисте се пријавили.\n\\n\n\\nОво може да потраје неколико секунди.</string>\n    <string name=\"signin_confirm_button_text\">Дозволи и дели</string>\n    <string name=\"pref_test_summary_warn\">Упозорење: %s</string>\n    <string name=\"checkin_not_registered\">Није регистровано</string>\n    <string name=\"pref_droidguard_operation_mode\">Режим рада</string>\n    <string name=\"profile_name_real\">Реални</string>\n    <string name=\"prefcat_push_apps_unregistered_title\">Нерегистроване апликације</string>\n    <string name=\"pref_add_account_title\">Налог</string>\n    <string name=\"signin_subtext_policy\">Пре употребе ове апликације, прегледајте: %1$s и %2$s.</string>\n    <string name=\"pref_safetynet_recent_copied\">Копирано у привремену меморију!</string>\n    <string name=\"prefcat_push_apps_title\">Апликације које користе push-обавештења</string>\n    <string name=\"profile_name_user\">Прилагођено: %s</string>\n    <string name=\"auth_before_connect\">Апликација на вашем уређају покушава да се пријави на Google налог. \\n\\nАко је ово било намерно, користите дугме <b>Пријави се</b> да бисте се повезали са Google страницом за пријављивање, ако није, притисните <b>Откажи</b> да бисте се вратили на апликацију која је изазвала да се овај дијалог прикаже.</string>\n    <string name=\"pref_recaptcha_test_title\">Тестирај ReCAPTCHA</string>\n    <string name=\"signin_subtext_sharing\">Да бисте наставили, microG ће делити име, имејл адресу и слику профила вашег Google налога са <xliff:g example=\"F-Droid\"> %1$s</xliff:g> .</string>\n    <string name=\"pref_auth_include_android_id_title\">Аутентификуј регистрацијом уређаја</string>\n    <string name=\"pref_push_app_allow_register_title\">Дозволи регистрацију</string>\n    <string name=\"profile_name_native\">Изворни</string>\n    <string name=\"pref_gcm_ping_interval\">Пинг интервал: <xliff:g example=\"10 minutes\"> %1$s</xliff:g></string>\n    <string name=\"pref_test_summary_running\">Ради…</string>\n    <string name=\"pref_safetynet_recent_cat_basic\">Основни подаци</string>\n    <string name=\"gms_settings_summary\">Подесите microG услуге.</string>\n    <string name=\"pref_add_account_summary\">Додај Google налог</string>\n    <string name=\"profile_name_system\">Системски: %s</string>\n    <string name=\"pref_safetynet_recent_cat_response\">Подаци одговора</string>\n    <string name=\"pref_push_app_allow_register_summary\">Дозволите апликацији да се региструје за push-обавештења.</string>\n    <string name=\"pref_safetynet_recent_token\">Токен</string>\n    <string name=\"pref_safetynet_test_not_completed\">Још није завршено</string>\n    <string name=\"pref_safetynet_recent_request_time\">Време захтева</string>\n    <string name=\"signin_subtext_policy_terms\">услови коришћења</string>\n    <string name=\"prefcat_push_apps_registered_title\">Регистроване апликације</string>\n    <string name=\"pref_device_registration_device_profile_category\">Профил уређаја</string>\n    <string name=\"prefcat_push_networks_title\">Мреже за коришћење за push-обавештења</string>\n    <string name=\"pref_safetynet_recent_eval_type\">Тип провере</string>\n    <string name=\"pref_vending_summary_licensing_on\">Лиценцирање укључено</string>\n    <string name=\"pref_vending_licensing_enable_switch\">Одговори на захтеве за верификацију лиценце</string>\n    <string name=\"pref_vending_license_enable_summary\">Неке апликације захтевају верификацију да сте их купили на Google Play-у. Када апликација то затражи, microG може да преузме доказ о куповини с Google-а. Ако је онемогућено или ако Google налог није додат, захтеви за верификацију лиценце се занемарују.</string>\n    <string name=\"pref_vending_summary_licensing_off\">Лиценцирање искључено</string>\n    <string name=\"service_name_vending\">Play Store услуге</string>\n    <string name=\"perm_car_info_description\">Приступите информацијама о вашем аутомобилу</string>\n    <string name=\"perm_car_fuel_label\">Ниво горива у аутомобилу</string>\n    <string name=\"perm_car_fuel_description\">Приступите информацијама о нивоу горива у вашем аутомобилу</string>\n    <string name=\"perm_car_mileage_label\">Километража аутомобила</string>\n    <string name=\"perm_car_vendor_extension_label\">Канал добављача аутомобила</string>\n    <string name=\"perm_car_speed_label\">Брзина аутомобила</string>\n    <string name=\"perm_car_info_label\">Информације о аутомобилу</string>\n    <string name=\"perm_car_mileage_description\">Приступите информацијама о километражи вашег аутомобила</string>\n    <string name=\"perm_car_vendor_extension_description\">Приступите каналу добављача вашег аутомобила да бисте разменили информације специфичне за аутомобил</string>\n    <string name=\"pref_auth_strip_device_name_summary\">Када је омогућено, захтеви за аутентификацију неће укључивати име уређаја, што може омогућити неовлашћеним уређајима да се пријаве, али може имати непредвиђене последице.</string>\n    <string name=\"perm_car_speed_description\">Приступите брзини вашег аутомобила</string>\n    <string name=\"pref_auth_strip_device_name_title\">Уклони име уређаја за аутентификацију</string>\n    <string name=\"feedback_disabled\">Повратна информација тренутно није могућа</string>\n    <string name=\"backup_disabled\">Прављење резервне копије тренутно није могуће</string>\n    <string name=\"pref_accounts_title\">Google налози</string>\n    <string name=\"pref_accounts_summary\">Додајте или управљајте Google налозима</string>\n    <string name=\"prefcat_accounts_settings_title\">Подешавања</string>\n    <string name=\"prefcat_accounts_current_accounts_title\">Налози</string>\n    <string name=\"pref_vending_licensing_category\">Google Play лиценцирање</string>\n    <string name=\"pref_vending_billing_note_experimental\">Ова функција је експериментална и може довести до губитка новца. Упозорени сте.</string>\n    <string name=\"pref_vending_billing_category\">Google Play наплата</string>\n    <string name=\"pref_vending_billing_note_licensing\">Неке апликације могу захтевати да омогућите и верификацију лиценце да бисте верификовали своје куповине.</string>\n    <string name=\"pref_vending_billing_enable_summary\">Једном када је омогућено, неке апликације могу да доврше куповине или да започну претплате преко Google Play услуге наплате.</string>\n    <string name=\"pref_vending_billing_enable_switch\">Обрађуј захтеве за наплату</string>\n    <string name=\"credentials_assisted_cancel\">Откажи</string>\n    <string name=\"credentials_assisted_continue\">Настави</string>\n    <string name=\"credentials_assisted_confirmation_header\">Пријављивање</string>\n    <string name=\"credentials_assisted_sign_back_title\">Поновна пријава на %1$s помоћу Google налога</string>\n    <string name=\"credentials_assisted_signin_consent_header\">Пријављивање као %1$s</string>\n    <string name=\"credentials_assisted_signin_description\">Можете управљати пријављивањем помоћу Google налога у вашим Google налозима.</string>\n    <string name=\"credentials_assisted_choose_account_subtitle\">за наставак на %1$s</string>\n    <string name=\"credentials_assisted_signin_button_text_long\">Пријава помоћу Google налога</string>\n    <string name=\"credentials_assisted_continue_as_user_button_label\">Настави као %1$s</string>\n    <string name=\"credentials_assisted_choose_account_label\">Изабери налог</string>\n    <string name=\"credentials_assisted_signin_consent\">Ако наставите, Google ће делити ваше име, имејл адресу и слику профила са %1$s. Погледајте политику приватности и услове коришћења услуге %1$s.</string>\n    <string name=\"auth_package_override_request_title\">Омогући <b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> привилеговани приступ за <xliff:g example=\"account@example.com\">%2$s</xliff:g>\\?</string>\n    <string name=\"auth_package_override_request_message\"><b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> жели да приступе вашем налогу као да је <b><xliff:g example=\"F-Droid\">%2$s</xliff:g> од <xliff:g example=\"F-Droid Inc.\">%3$s</xliff:g></b>. Ово би му могло дати привилеговани приступ вашем налогу.</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_summary\">Бесплатне апликације могу да провере да ли су преузете са Google Play-а. Аутоматски додајте бесплатне апликације у библиотеку налога да бисте увек прошли проверу за све бесплатне апликације које су вам тренутно доступне.</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_switch\">Аутоматски додај бесплатне апликације у библиотеку</string>\n    <string name=\"limited_services_app_name\">microG ограничене услуге</string>\n    <string name=\"limited_services_dialog_information_ack\">Разумем</string>\n    <string name=\"limited_services_dialog_information\">Користите microG ограничене услуге. За разлику од уобичајених microG услуга, ова верзија функционише само са апликацијама које користе microG библиотеке, а не са онима на Google Play-у. То значи да ће већина апликација занемарити ове услуге.</string>\n    <string name=\"auth_action_notification_title\">Неопходна радња на налогу</string>\n    <string name=\"auth_action_notification_content\">Вашем Google налогу је потребно додатно подешавање.</string>\n    <string name=\"auth_action_step_enable_checkin\">Омогући регистрацију уређаја</string>\n    <string name=\"auth_action_step_enable_gcm\">Омогући размену поруку у облаку</string>\n    <string name=\"auth_action_step_allow_microg_gcm\">Омогући размену порука у облаку за microG</string>\n    <string name=\"auth_action_step_perform_content_description\">Додирните да бисте извршили корак</string>\n    <string name=\"auth_action_step_completed_content_description\">Корак завршен</string>\n    <string name=\"auth_action_activity_finish\">Заврши</string>\n    <string name=\"auth_action_activity_explanation\">Завршите следеће кораке да бисте могли да користите свој Google налог %s на овом уређају.</string>\n    <string name=\"auth_action_notification_channel_name\">Обавештења Google налога</string>\n    <string name=\"auth_action_notification_channel_description\">Обавештава када неки од ваших Google налога захтева додатно подешавање пре него што се може користити или када налог није компатибилан са microG-ом.</string>\n    <string name=\"auth_action_step_enable_checkin_description\">Ваш уређај мора да се региструје на Google бар једном.\\n\\nМожете да онемогућите Google регистрацију уређаја након што је подешавање налога завршено.</string>\n    <string name=\"auth_action_activity_header\">Завршите подешавање свог Google налога</string>\n    <string name=\"auth_action_step_allow_microg_gcm_description\">Према вашим преференцама, microG-у је потребна ваша дозвола да би могао да се региструје за размену порука у облаку.</string>\n    <string name=\"auth_action_step_enable_gcm_description\">Можете онемогућити размену порука у облаку након што је подешавање налога завршено.</string>\n    <string name=\"auth_action_step_enable_lockscreen\">Подесите безбедно закључавање екрана</string>\n    <string name=\"auth_action_step_enable_lockscreen_description\">Вашим Google налогом управља ваше радно место или образовна институција. Ваш администратор је одлучио да је уређајима потребно безбедно закључавање екрана да би могли да приступе подацима налога.\\n\\nПодесите лозинку, PIN или шаблон за закључавање екрана.</string>\n    <string name=\"pref_vending_asset_delivery_switch\">Омогући испоруку средстава на захтев</string>\n    <string name=\"pref_vending_asset_delivery_summary\">Преузмите додатна средства када то затраже апликације које користе Play Asset Delivery</string>\n    <string name=\"pref_vending_asset_delivery_category\">Google Play Asset Delivery</string>\n    <string name=\"pref_vending_asset_device_sync_switch\">Омогући синхронизацију информација о уређају</string>\n    <string name=\"pref_vending_asset_device_sync_summary\">Апликације које користе Play Asset Delivery ће преузети додатна средства на основу информација о уређају који се тренутно користи.</string>\n    <string name=\"games_achievement_list_title\">Достигнућа</string>\n    <string name=\"games_achievements_empty_text\">Нема достигнућа за ову игру</string>\n    <string name=\"games_achievement_locked_content_description\">закључано</string>\n    <string name=\"games_achievement_unlocked_content_description\">откључано</string>\n    <string name=\"games_achievement_extra_text\">%1$s XP</string>\n    <string name=\"games_leaderboard_empty_text\">Нема табеле са резултатима за ову игру</string>\n    <string name=\"games_api_access_denied\">Ниједан налог на овом уређају не може да приступи API-јима за Play игре</string>\n    <string name=\"games_leaderboard_list_title\">Рангирања</string>\n    <string name=\"games_leaderboards_score_label\">Резултат: %1$s</string>\n    <string name=\"games_snapshot_empty_text\">Још увек није сачувана ниједна игра</string>\n    <string name=\"games_snapshot_choose_btn_text\">изабери</string>\n    <string name=\"games_snapshot_delete_btn_text\">избриши</string>\n    <string name=\"games_delete_snapshot_dialog_message\">Желите ли заиста да избришете ову сачувану игру?</string>\n    <string name=\"games_delete_snapshot_dialog_cancel\">Откажи</string>\n    <string name=\"games_delete_snapshot_dialog_ok\">У реду</string>\n    <string name=\"games_delete_snapshot_error\">Брисање није успело, покушајте поново касније</string>\n    <string name=\"games_delete_snapshot_dialog_title\">Избриши сачувану игру</string>\n    <string name=\"games_leaderboard_score_empty_text\">Невероватно! Нема јавних високих резултата за ову игру.</string>\n    <string name=\"service_name_work_profile\">Радни профил</string>\n    <string name=\"pref_vending_feature_delivery\">Испорука Google Play функција</string>\n    <string name=\"pref_vending_split_install_switch\">Инсталација компоненти на захтев</string>\n    <string name=\"pref_vending_licensing_split_install_summary\">Дозволите апликацијама да преузимају и инсталирају додатне компоненте</string>\n    <string name=\"pref_workprofile_create_account\">Дозволи подешавање радног налога</string>\n    <string name=\"pref_workprofile_disclaimer\">Ваша је одговорност да обезбедите да ваше коришћење microG буде у складу са корпоративним политикама. microG се обезбеђује на основу најбољег труда и не може гарантовати да ће се понашати тачно онако како се очекује.</string>\n    <string name=\"barcode_scanner_brand\">Скенирао microG у име %1$s</string>\n    <string name=\"camera_permission_dialog_button\">У реду</string>\n    <string name=\"camera_permission_dialog_message\">microG услуге морају да приступе камери вашег уређаја да би скенирале код за %1$s.\\n\\nДа бисте омогућили, дајте дозволу за камеру microG услугама у подешавањима.</string>\n    <string name=\"camera_permission_dialog_title\">Потребна је дозвола за камеру</string>\n    <string name=\"pref_workprofile_intro\">Приликом подешавања радног профила за ваше радно место или образовну институцију, подешавање може да покуша да се повеже са Google-ом да би омогућило преузимање апликација на тај профил.</string>\n    <string name=\"credentials_assisted_signin_add_account\">Додај налог</string>\n    <string name=\"credentials_assisted_choose_account_error_tips\">Абнормалност налога</string>\n    <string name=\"auth_action_reauth_notification_title\">Неопходна радња на налогу</string>\n    <string name=\"pref_auth_two_step_verification_title\">Примај упите за двостепену верификацију</string>\n    <string name=\"pref_auth_two_step_verification_summary\">Када је омогућено, уређај може да прима упите за двостепену верификацију од компаније Google (потребна је „Размена порука у облаку “).</string>\n    <string name=\"pref_game_accounts_title\">Google налози за игре</string>\n    <string name=\"pref_auto_create_player\">Дозволи регистрацију налога за Play игре</string>\n    <string name=\"pref_auto_create_player_intro\">Када играте игре, потребно је да користите налог за Play игте да бисте се пријавили и забележили функције везане за игру, као што су достигнућа, табеле са резултатима, архиве итд. Након онемогућавања, Google налози који нису повезани са налогом за Play игре неће бити аутоматски регистровани и игра неће моћи да се пријави и игра.</string>\n    <string name=\"pref_allow_upload_game_played\">Дозволи отпремање одигране игре</string>\n    <string name=\"pref_allow_upload_game_played_summary\">Када је онемогућено, игра неће пријављивати статус одигране игре након пријављивања у игру, а неке игре можда неће моћи да се пријаве.</string>\n    <string name=\"pref_change_default_game_player\">Промени налог за игре</string>\n    <string name=\"pref_change_default_game_player_summary\">Промените подразумевани налог за игре и промените налог по игри.</string>\n    <string name=\"pref_delete_game_account_data\">Избриши податке Play игара</string>\n    <string name=\"pref_delete_game_account_data_summary\">Избришите налог Play игара и све податке и избришите појединачне податке игре.</string>\n    <string name=\"games_state_description_signed_out\">Одјављено</string>\n    <string name=\"games_state_description_delete\">Избриши</string>\n    <string name=\"games_change_button_text\">Промени</string>\n    <string name=\"games_change_default_account_section_title\">Промените подразумевани налог за игре</string>\n    <string name=\"games_change_default_account_description\">Подразумевани налог: %1$s</string>\n    <string name=\"games_change_default_account_explanation\">Овај налог се користи за аутоматско пријављивање у игре, чување вашег напретка у игри и чување ваших подешавања. Промена подразумеваног налога или одјављивање могу ресетовати ваш напредак и подешавања за игру.</string>\n    <string name=\"games_change_per_game_title\">Промените налог по игри</string>\n    <string name=\"games_change_per_game_description\">Промена налога за изабрану игру или одјављивање са њега може ресетовати ваш напредак и подешавања за игру.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_title\">Изаберите опцију за нови подразумевани налог</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_description\">Тренутни подразумевани налог: %1$s</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_title\">Промените подразумевани налог само за нове игре</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_description\">Нећете изгубити приступ напретку и подешавањима за игре које сте играли. Али ваш напредак ће бити подељен између налога.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_title\">Промените подразумевани налог за све игре</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_description\">Можда ћете изгубити приступ напретку и подешавањима за игре које сте играли. Поново ћемо покренути игру да бисмо применили ваше промене.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_title\">Одјава из свих игара</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_description\">Можда ћете изгубити приступ напретку и подешавањима за игре које сте играли. Поново ћемо покренути игру да бисмо применили ваше промене.</string>\n    <string name=\"games_change_per_game_dialog_title\">Изаберите опцију за ову игру</string>\n    <string name=\"games_change_per_game_dialog_description\">Промена налога или одјављивање могу ресетовати ваш напредак и подешавања за игру</string>\n    <string name=\"games_change_per_game_dialog_option_use_player\">Користи %1$s</string>\n    <string name=\"games_change_per_game_dialog_option_use_player_snackbar_success_message\">Бићете пријављени у ову игру са %1$s</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out\">Одјава</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out_snackbar_success_message\">Сада сте одјављени из ове игре</string>\n    <string name=\"games_change_sign_out_of_all_games_snackbar_success_message\">Сада сте одјављени из свих игара</string>\n    <string name=\"games_change_default_account_for_all_games_snackbar_success_message\">Бићете пријављени у све игре са %1$s</string>\n    <string name=\"games_change_default_account_for_new_games_snackbar_success_message\">Бићете пријављени у нове игре са %1$s</string>\n    <string name=\"games_account_display_content\">Тренутни налог: %1$s</string>\n    <string name=\"games_delete_profile_header\">Избришите налог Play игара и све податке</string>\n    <string name=\"games_delete_profile_explanation\">Трајно избришите свој налог за Google Play игре, XP поене и све податке профила. Ова радња може такође избрисати ваше резултате, напредак (сачуване игре) и подешавања у играма које сте играли.</string>\n    <string name=\"games_delete_profile_button\">Трајно избриши</string>\n    <string name=\"games_delete_game_data_header\">Избришите појединачне податке игре</string>\n    <string name=\"games_delete_game_data_explanation\">Можете трајно избрисати појединачне податке за игре које сте играли помоћу Google Play игара. Ова радња брише ваше резултате, напредак (сачуване игре) и подешавања за игру коју изаберете.</string>\n    <string name=\"games_delete_profile_dialog_title\">Желите ли заиста да избришете овај налог?</string>\n    <string name=\"games_delete_profile_explanation_with_gamer_name\">Трајно избришите налог за Google Play игре за име играча <b>%1$s</b> (<b>%2$s</b>), XP поене и све податке профила. Ова радња може такође избрисати ваше резултате, напредак (сачуване игре) и подешавања игара које сте играли.</string>\n    <string name=\"games_delete_profile_dialog_message\">Ова радња се не може поништити.</string>\n    <string name=\"games_delete_profile_fail\">Није могуће избрисати ваш профил. Покушајте поново касније.</string>\n    <string name=\"games_delete_game_data_confirm_dialog_title\">Избришите податке за %1$s</string>\n    <string name=\"games_delete_game_data_confirm_dialog_message\">Трајним брисањем података за %1$s уклонићете резултате, напредак (сачуване игре) и подешавања игре у Google Play играма.</string>\n    <string name=\"games_popup_signin_welcome\">Здраво, %1$s</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-sv/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense\">Visa och hantera din AdSense-data</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue.consumer\">Använd uppgifter från dina uppgiftsköer</string>\n    <string name=\"permission_service_blogger_label\">Blogger</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tracks\">Google Maps Tracks API, Detta omfång ger läs- och skrivåtkomst till ditt projekts data.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.full_control\">Hantera din data och dina behörigheter i Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase.readonly\">Visa ditt Freebase-konto</string>\n    <string name=\"permission_service_blogger_description\">Tillåter en app att komma åt Blogger via något tillhörande Google-konto.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.readonly\">Visa filer och dokument på Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.readonly\">Läs alla resurser och deras metadata – inga skrivåtgärder.</string>\n    <string name=\"permission_service_sitemaps_label\">Google Webmaster Tools</string>\n    <string name=\"permission_service_adwords_label\">AdWords</string>\n    <string name=\"permission_service_gbase_description\">Tillåter en app att komma åt Google Bas via något tillhörande Google-konto.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate.readonly\">Visa dina Google Coordinate-jobb</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.file\">Visa och hantera Google Drive-filer som du har öppnat eller skapat med den här appen</string>\n    <string name=\"permission_service_speechpersonalization_label\">Personlig taligenkänning</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.appdata\">Ger åtkomst till mappen Programdata</string>\n    <string name=\"permission_service_youtube_label\">YouTube</string>\n    <string name=\"permission_service_news_label\">Google News</string>\n    <string name=\"permission_service_speechpersonalization_description\">Tillåter en app att komma åt personlig taligenkänning via något associerat Google-konto.</string>\n    <string name=\"permission_service_all_label\">Alla Google-tjänster</string>\n    <string name=\"permission_service_sitemaps_description\">Tillåter en app att komma åt Google Webmaster Tools via något associerat Google-konto.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue\">Hantera dina uppgifter</string>\n    <string name=\"permission_service_finance_description\">Tillåter en app att komma åt Google Finans genom alla tillhörande Google-konton.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine\">Visa och hantera din data från Google Maps Engine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine.readonly\">Visa din data från Google Maps Engine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_activity\">Visa aktivitetshistoriken för dina Google-appar</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive\">Visa och hantera filer och dokument på Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics.readonly\">Visa din Google Analytics-data</string>\n    <string name=\"permission_service_writely_description\">Tillåter en app att komma åt Google Docs via något associerat Google-konto.</string>\n    <string name=\"permission_service_writely_label\">Google Docs</string>\n    <string name=\"permission_service_orkut_label\">Orkut</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_prediction\">Hantera din data i Google Prediction API</string>\n    <string name=\"permission_service_youtube_description\">Tillåter en app att komma åt YouTube via något associerat Google-konto.</string>\n    <string name=\"permission_service_wise_label\">Google Spreadsheets</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_structuredcontent\">Läs-/skrivåtkomst till Shopping Content API.</string>\n    <string name=\"permission_service_speech_description\">Tillåter en app att komma åt Voice Search via något associerat Google-konto.</string>\n    <string name=\"permission_service_knol_description\">Tillåter en app att komma åt Knol via något associerat Google-konto.</string>\n    <string name=\"permission_service_wifi_label\">Google Wi-Fi</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.me\">Ta reda på vem du är på Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.login\">Ta reda på ditt namn, grundläggande information och en lista över personer som du är ansluten till på Google+</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics.readonly\">Visa YouTube Analytics-rapporter för ditt YouTube-innehåll</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics\">Visa och hantera din Google Analytics-data</string>\n    <string name=\"permission_service_health_label\">Google Health</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut\">Hantera din Orkut-aktivitet</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.apps.readonly\">Visa dina Google Drive-appar</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.compose\">Skapa, läs, uppdatera och ta bort utkast. Skicka meddelanden och utkast.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger.readonly\">Visa ditt Blogger-konto</string>\n    <string name=\"permission_service_android_label\">Android-tjänster</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.licensing\">Läs-/skrivåtkomst till License Manager API.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery\">Visa och hantera din data i Google BigQuery</string>\n    <string name=\"permission_service_health_description\">Tillåter en app att komma åt Google Health via något tillhörande Google-konto.</string>\n    <string name=\"permission_service_jotspot_description\">Tillåter en app att komma åt JotSpot via något tillhörande Google-konto.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_dfareporting\">Visa och hantera DoubleClick for Advertisers-rapporter</string>\n    <string name=\"permission_service_notebook_label\">Google Notebook</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_urlshortener\">Hantera dina goo.gl-korta webbadresser</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube\">Hantera ditt YouTube-konto</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery.readonly\">Visa din data i Google BigQuery</string>\n    <string name=\"permission_service_cp_label\">Kontakter</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order\">För återförsäljaradministratörer och användare läs-/skrivåtkomst vid testning i API:ets sandlådemiljö eller läs-/skrivåtkomst när en API-åtgärd anropas direkt.</string>\n    <string name=\"permission_service_local_description\">Tillåter en app att komma åt Google Maps via något tillhörande Google-konto.</string>\n    <string name=\"permission_service_speech_label\">Voice Search</string>\n    <string name=\"permission_service_groups2_description\">Tillåter en app att komma åt Google Groups via något associerat Google-konto.</string>\n    <string name=\"permission_service_local_label\">Google Maps</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.buyer\">Hantera konfigurationen av ditt Ad Exchange-köparkonto</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gcm_for_chrome\">CloudMessaging för chrome</string>\n    <string name=\"permission_service_adsense_description\">Tillåter en app att komma åt AdSense via något tillhörande Google-konto.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller\">Visa och hantera din Ad Exchange-data</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_shoppingapi\">Visa din produktdata</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsensehost\">Visa och hantera din AdSense-värddata och kopplade konton</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.scripts\">Ändra beteendet för Google Apps Script-skript</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_write\">Hantera din data i Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mobilemaps.firstparty\">Visa och hantera din Google Maps för mobilupplevelse</string>\n    <string name=\"permission_service_grandcentral_description\">Tillåter en app att komma åt Google Voice via något associerat Google-konto.</string>\n    <string name=\"permission_service_cl_description\">Tillåter en app att komma åt Google Kalender via något associerat Google-konto.</string>\n    <string name=\"permission_service_cl_label\">Google Kalender</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appstate\">Omfång för att använda App State-tjänsten.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics_monetary.readonly\">Visa ekonomiska rapporter för ditt YouTube-innehåll i YouTube Analytics</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.city\">Hantera din plats och platshistorik på stadsnivå</string>\n    <string name=\"permission_service_talk_label\">Google Talk</string>\n    <string name=\"permission_service_ig_label\">iGoogle</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks\">Hantera dina uppgifter</string>\n    <string name=\"permission_service_android_description\">Tillåter en app att komma åt Android-tjänster via något tillhörande Google-konto.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.settings\">Visa och hantera inställningarna för en Google Apps-grupp</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute.readonly\">Visa dina Google Compute Engine-resurser</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller.readonly\">Visa din Ad Exchange-data</string>\n    <string name=\"permission_service_ig_description\">Tillåter en app att komma åt iGoogle via något tillhörande Google-konto.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables\">Hantera dina Fusion Tables</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan.readonly\">Visa din GAN-data</string>\n    <string name=\"permission_service_adsense_label\">AdSense</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification.verify_only\">Hantera dina nya webbplatsverifieringar med Google</string>\n    <string name=\"permission_service_orkut_description\">Tillåter en app att komma åt Orkut via något associerat Google-konto.</string>\n    <string name=\"permission_service_sierrasandbox_label\">Google Checkout Sandbox accounts</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.metadata.readonly\">Visa metadata för filer och dokument på Google Drive</string>\n    <string name=\"permission_service_sierra_description\">Tillåter en app att komma åt Google Checkout-konton via något tillhörande Google-konto.</string>\n    <string name=\"permission_service_lh2_description\">Tillåter en app att komma åt Picasa webbalbum via något associerat Google-konto.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_games\">Omfång för att komma åt data från Google Play Games.</string>\n    <string name=\"permission_service_wifi_description\">Tillåter en app att komma åt Google Wi-Fi via något associerat Google-konto.</string>\n    <string name=\"permission_service_all_description\">Tillåter en app att komma åt alla Google-tjänster via något tillhörande Google-konto.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_only\">Visa din data i Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar.readonly\">Visa dina kalendrar</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appengine.admin\">Administratörsomfång för appmotorn.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_androidpublisher\">Åtkomst till Google Play Android Developer</string>\n    <string name=\"permission_service_notebook_description\">Tillåter en app att komma åt Google Notebook via något tillhörande Google-konto.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification\">Hantera listan över webbplatser och domäner som du kontrollerar</string>\n    <string name=\"permission_service_YouTubeUser_label\">YouTube användarnamn</string>\n    <string name=\"permission_service_mail_label\">Google Mail</string>\n    <string name=\"permission_service_dodgeball_label\">Dodgeball</string>\n    <string name=\"permission_service_adwords_description\">Tillåter en app att komma åt AdWords via något tillhörande Google-konto.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.install\">Särskilt omfång som används för att låta användare godkänna installationen av en app</string>\n    <string name=\"permission_service_news_description\">Tillåter en app att komma åt Google News via något tillhörande Google-konto.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables.readonly\">Visa dina Fusion Tables</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.modify\">Alla läs-/skrivåtgärder utom omedelbar, permanent borttagning av trådar och meddelanden, kringgår papperskorgen.</string>\n    <string name=\"permission_service_gbase_label\">Google Bas</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.city\">Hantera din plats på stadsnivå</string>\n    <string name=\"permission_service_wise_description\">Tillåter en app att komma åt Google Spreadsheets via något associerat Google-konto.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.migration\">Läs- och skrivåtkomst till migrerings-API för grupper.</string>\n    <string name=\"permission_service_sierrasandbox_description\">Tillåter en app att komma åt Google Checkout Sandbox-konton via något tillhörande Google-konto.</string>\n    <string name=\"permission_service_print_description\">Tillåter en app att komma åt Google Book Search via något associerat Google-konto.</string>\n    <string name=\"permission_service_mail_description\">Tillåter en app att komma åt Google Mail via något tillhörande Google-konto.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.email\">Visa din e-postadress</string>\n    <string name=\"permission_service_jotspot_label\">JotSpot</string>\n    <string name=\"permission_service_lh2_label\">Picasa webbalbum</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase\">Logga in på ditt Freebase-konto</string>\n    <string name=\"permission_service_groups2_label\">Google Groups</string>\n    <string name=\"permission_service_ah_description\">Tillåter en app att komma åt Google App Engine via något associerat Google-konto.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_glass.timeline\">Glasomfång för tidslinjen</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate\">Visa och hantera dina Google Maps Coordinate-jobb</string>\n    <string name=\"permission_service_ah_label\">Google App Engine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute\">Visa och hantera dina Google Compute Engine-resurser</string>\n    <string name=\"permission_service_sierra_label\">Google Checkout konton</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.profile\">Visa grundläggande information om ditt konto</string>\n    <string name=\"permission_service_YouTubeUser_description\">Tillåter en app att komma åt YouTube-användarnamn via något associerat Google-konto.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar\">Hantera dina kalendrar</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_books\">Hantera dina böcker</string>\n    <string name=\"permission_service_sierraqa_description\">Tillåter en app att komma åt Google Checkout QA-konton via något tillhörande Google-konto.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan\">Hantera din GAN-data</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut.readonly\">Visa din Orkut-data</string>\n    <string name=\"permission_service_talk_description\">Tillåter en app att komma åt Google Talk via något associerat Google-konto.</string>\n    <string name=\"permission_service_sierraqa_label\">Google Checkout QA accounts</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks.readonly\">Visa dina uppgifter</string>\n    <string name=\"permission_service_dodgeball_description\">Tillåter en app att komma åt Dodgeball via något tillhörande Google-konto.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.best\">Hantera bästa tillgängliga plats och platshistorik</string>\n    <string name=\"permission_service_cp_description\">Tillåter en app att komma åt dina kontakter via något tillhörande Google-konto.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense.readonly\">Visa din AdSense-data</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.readonly\">Visa ditt YouTube-konto</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_cloudprint\">Visa och hantera din data från Google Cloud Print</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order.readonly\">Förutom det övergripande OAuth-omfånget för läsning/skrivning använder du det skrivskyddade OAuth-omfånget när du hämtar kundens data.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger\">Hantera ditt Blogger-konto</string>\n    <string name=\"permission_service_grandcentral_label\">Google Voice</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps_reporting_audit.readonly\">Åtkomst till Admin Audit API ReadOnly</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.best\">Hantera bästa tillgängliga plats</string>\n    <string name=\"permission_service_print_label\">Google Book Search</string>\n    <string name=\"permission_service_finance_label\">Google Finans</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtubepartner\">Visa och hantera dina tillgångar och tillhörande innehåll på YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.upload\">Hantera dina YouTube-videos</string>\n    <string name=\"permission_service_knol_label\">Knol</string>\n    <string name=\"perm_activity_recognition_label\">Aktivitetsigenkänning</string>\n    <string name=\"perm_activity_recognition_description\">Tillåter en app att få periodiska uppdateringar av din aktivitetsnivå från Google, till exempel om du går, kör, cyklar eller stationär.</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-sv/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <plurals name=\"gcm_registered_apps_counter\">\n        <item quantity=\"one\"><xliff:g example=\"123\">%1$d</xliff:g> registrerad app</item>\n        <item quantity=\"other\"><xliff:g example=\"123\">%1$d</xliff:g> registrerade appar</item>\n    </plurals>\n    <plurals name=\"cond_perm_action\">\n        <item quantity=\"one\">Begär saknad behörighet</item>\n        <item quantity=\"other\">Begär saknade behörigheter</item>\n    </plurals>\n    <plurals name=\"pref_unifiednlp_summary\">\n        <item quantity=\"one\"><xliff:g example=\"3\"> %1$d </xliff:g> backend konfigurerad</item>\n        <item quantity=\"other\"><xliff:g example=\"3\"> %1$d </xliff:g> backends konfigurerad</item>\n    </plurals>\n    <plurals name=\"cond_perm_summary\">\n        <item quantity=\"one\">Behörighet som krävs för korrekt funktion av mikroG-tjänst beviljas inte.</item>\n        <item quantity=\"other\">Behörigheter som krävs för korrekt funktion av mikroG-tjänster beviljas inte.</item>\n    </plurals>\n</resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-sv/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=\"pref_gcm_confirm_new_apps_title\">Bekräfta nya appar</string>\n    <string name=\"gcm_app_error_unregistering\">Fel vid avregistrering</string>\n    <string name=\"pref_gcm_heartbeat_summary\">Intervallet i sekunder, för att systemet ska pinga Googles servrar. Längre intervall kommer att minska batteriförbrukningen, men kan orsaka förseningar på push-meddelanden.\n\\nInaktuell, kommer att ersättas i framtida versioner.</string>\n    <string name=\"checkin_last_registration\">Senaste registrering: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"pref_auth_trust_google_title\">Lita på Google för appbehörigheter</string>\n    <string name=\"gcm_no_message_yet\">Inga meddelanden hittills</string>\n    <string name=\"pref_about_title\">Om MicroG-tjänster</string>\n    <string name=\"signin_subtext_policy_privacy\">Sekretesspolicy</string>\n    <string name=\"pick_place_title\">Välj en plats</string>\n    <string name=\"games_info_content\">För att använda Play Games krävs det att du installerar appen Google Play Games. Appen kan fortsätta utan Play Games, men det är möjligt att den kommer att bete sig oväntat.</string>\n    <string name=\"gcm_unregister_after_deny_message\">Du nekade en app, att registrera dig för push-meddelanden, som redan är registrerad.\n\\nVill du avregistrera den nu så den inte får push-meddelanden i framtiden?</string>\n    <string name=\"self_check_resolution_correct_sig\">Antingen är den installerade <xliff:g example=\"F-Droid\">%1$s</xliff:g> inte kompatibel eller så är signaturspoofing inte aktiv för den. Kontrollera dokumentationen om vilka applikationer och ROM-filer som är kompatibla.</string>\n    <string name=\"self_check_cat_fake_sig\">Stöd för signaturspoofing</string>\n    <string name=\"perm_gsf_read_gservices_label\">läs konfiguration av Google-tjänster</string>\n    <string name=\"auth_sign_in\">Logga in</string>\n    <string name=\"no_network_error_desc\">Du har ingen nätverksanslutning.\n\\n\n\\nDetta kan vara ett tillfälligt problem eller så kanske din Android-enhet inte tillhandahåller datatjänster. Försök igen när du är ansluten till ett mobilt nätverk eller anslut till ett Wi-Fi-nätverk.</string>\n    <string name=\"network_type_roaming\">Roaming</string>\n    <string name=\"pref_auth_visible_summary\">När detta är aktiverat kommer alla appar på den här enheten att kunna se e-postadressen till dina Google-konton utan förhandsgodkännande.</string>\n    <string name=\"network_type_wifi\">Wi-Fi</string>\n    <string name=\"gcm_unregister_app\">Avregistrera</string>\n    <string name=\"gcm_last_message_at\">Senaste meddelandet: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"prefcat_configuration\">Konfiguration</string>\n    <string name=\"perm_c2dm_receive_label\">lyssna på C2DM-meddelanden</string>\n    <string name=\"place_picker_location_lat_lng\">(%1$.7f, %2$.7f)</string>\n    <string name=\"prefcat_google_services\">Google Services</string>\n    <string name=\"prefcat_components\">Komponenter</string>\n    <string name=\"just_a_sec\">En sekund…</string>\n    <string name=\"service_name_mcs\">Cloud Messaging</string>\n    <string name=\"gcm_unregister_confirm_title\">Avregistrera <xliff:g example=\"F-Droid\">%1$s</xliff:g>\\?</string>\n    <string name=\"signin_picker_title\">Välj ett konto</string>\n    <string name=\"pref_push_app_wake_for_delivery_summary\">Starta appen när i bakgrunden för att ta emot inkommande push-meddelanden.</string>\n    <string name=\"auth_general_error_desc\">Det gick inte att kommunicera med Googles servrar.\n\\n\n\\nFörsök igen senare.</string>\n    <string name=\"google_account_label\">Google</string>\n    <string name=\"checkin_enable_switch\">Registrera enhet</string>\n    <string name=\"place_picker_nearby_places\">Närliggande platser</string>\n    <string name=\"perm_provision_label\">tillhandahållande av mikro G-tjänster</string>\n    <string name=\"service_name_snet\">Google SafetyNet</string>\n    <string name=\"self_check_cat_system\">System</string>\n    <string name=\"pick_place_desc\">Platsväljaren är ännu inte tillgänglig.</string>\n    <string name=\"prefcat_test\">Testa</string>\n    <string name=\"gcm_network_state_connected\">Ansluten sedan <xliff:g example=\"2 hours ago\">%1$s</xliff:g></string>\n    <string name=\"gcm_registered\">Registrerad</string>\n    <string name=\"pref_more_settings\">Mer</string>\n    <string name=\"pref_auth_include_android_id_summary\">Vid inaktivering kommer autentiseringsförfrågningar inte att kopplas till enhetsregistreringen, vilket kan göra att obehöriga enheter kan logga in, men kan ha oförutsedda konsekvenser.</string>\n    <string name=\"pref_gcm_heartbeat_title\">Cloud Messaging hjärtslagsintervall</string>\n    <string name=\"signin_picker_subtitle\">för att fortsätta till <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"signin_confirm_title\">Tillåt att logga in på <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"self_check_pkg_vending\">microG Companion / Play Store</string>\n    <string name=\"self_check_resolution_battery_optimizations\">Tryck här för att inaktivera batterioptimering. Att inte göra detta kan leda till att appar inte fungerar.</string>\n    <string name=\"sorry\">Tyvärr…</string>\n    <string name=\"pref_gcm_confirm_new_apps_summary\">Fråga innan en ny app registreras för att få push-meddelanden</string>\n    <string name=\"pref_push_app_wake_for_delivery_title\">Starta app på push-meddelande</string>\n    <string name=\"cond_gcm_bat_action\">Inaktivera optimering</string>\n    <string name=\"pref_about_summary\">Versionsinformation och använda bibliotek</string>\n    <string name=\"place_picker_select_title\">Välj denna plats</string>\n    <string name=\"perm_provision_description\">Tillåter appen att konfigurera mikro G-tjänster utan användarinteraktion</string>\n    <string name=\"gcm_enable_switch\">Ta emot push-meddelanden</string>\n    <string name=\"perm_extended_access_label\">Utökad åtkomst till Google-tjänster</string>\n    <string name=\"network_type_mobile\">Mobilt nätverk</string>\n    <string name=\"pref_auth_trust_google_summary\">När inaktivering frågas användaren innan en apps auktorisationsförfrågan skickas till Google. Vissa appar kommer inte att kunna använda Google-kontot om detta är inaktiverat.</string>\n    <string name=\"self_check_cat_gms_packages\">Installerade paket</string>\n    <string name=\"ask_permission_tos\">Genom att fortsätta tillåter du att appen och Google använder din information i enlighet med deras respektive användarvillkor och sekretesspolicyer.</string>\n    <string name=\"cond_gcm_bat_summary\">Du aktiverade Cloud Messaging men har batterioptimering aktivt för mikroG-tjänster. För att push-meddelanden skall kunna tas emot bör du avaktivera batterioptimering.</string>\n    <string name=\"pref_info_status\">Status</string>\n    <string name=\"gcm_allow_app_popup\">Vill du tillåta <xliff:g example=\"F-Droid\">%1$s</xliff:g> att registrera sig för push-meddelanden?</string>\n    <string name=\"games_title\">Google Play Games</string>\n    <string name=\"self_check_name_fake_sig_perm\">Systemet stödjer signaturspoofing:</string>\n    <string name=\"pref_gcm_apps_summary\">Lista över appar som för närvarande är registrerade för Cloud Messaging.</string>\n    <string name=\"pref_auth_visible_title\">Tillåt appar att hitta konton</string>\n    <string name=\"pref_device_registration_android_id\">Android-ID</string>\n    <string name=\"self_check_resolution_app_installed\">Installera programmet <xliff:g example=\"F-Droid\"> %1$s </xliff:g> eller ett kompatibel. Kontrollera dokumentationen om vilka applikationer som är kompatibla.</string>\n    <string name=\"network_type_other\">Andra nätverk</string>\n    <string name=\"gcm_network_state_disconnected\">Bortkopplad</string>\n    <string name=\"service_name_checkin\">Google enhetsregistrering</string>\n    <string name=\"signin_picker_add_account_label\">Lägg till ett annat konto</string>\n    <string name=\"self_check_pkg_gsf\">microG Services Framework</string>\n    <string name=\"auth_connecting\">Din enhet upprättar en anslutning till Googles servrar för att logga in dig.\n\\n\n\\nDet kan ta några sekunder.</string>\n    <string name=\"pref_gcm_apps_title\">Appar som använder Cloud Messaging</string>\n    <string name=\"deny\">Neka</string>\n    <string name=\"perm_c2dm_send_label\">skicka C2DM-meddelanden till andra appar</string>\n    <string name=\"signin_confirm_button_text\">Tillåt och dela</string>\n    <string name=\"prefcat_about\">Om</string>\n    <string name=\"gcm_unregister_confirm_message\">Vissa appar registreras inte om automatiskt och/eller ger inte möjlighet att göra det manuellt. Dessa appar kanske inte fungerar korrekt efter avregistrering.\n\\nVill du fortsätta?</string>\n    <string name=\"gcm_registered_since\">Registrerad sedan: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"checkin_not_registered\">Inte registrerat</string>\n    <string name=\"ask_scope_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> vill:</string>\n    <string name=\"prefcat_push_apps_unregistered_title\">Oregistrerade appar</string>\n    <string name=\"self_check_resolution_perm_granted\">Detta är en stark indikator på att din ROM stödjer signaturspoofing, men kräver ytterligare åtgärder för att aktivera den. Kontrollera dokumentationen om vilka åtgärder som kan krävas.</string>\n    <string name=\"gms_settings_name\">microG-inställningar</string>\n    <string name=\"cond_gcm_bat_title\">Batterioptimering aktiverad</string>\n    <string name=\"pref_add_account_title\">Konto</string>\n    <string name=\"signin_subtext_policy\">Innan du använder den här appen, granska dess %1$s och %2$s.</string>\n    <string name=\"gcm_not_registered\">Inte registrerad</string>\n    <string name=\"account_manager_title\">Google Account Manager</string>\n    <string name=\"perm_status_broadcast_label\">lyssna på interna statusmeddelanden</string>\n    <string name=\"perm_gtalk_svc_label\">utbyta meddelanden och ta emot synkroniseringsaviseringar från Googles servrar</string>\n    <string name=\"gcm_messages_counter\">Meddelanden: <xliff:g example=\"123\">%1$d</xliff:g> (<xliff:g example=\"12345\">%2$d</xliff:g> bytes)</string>\n    <string name=\"self_check_name_system_spoofs\">Systemets spoofsignatur:</string>\n    <string name=\"prefcat_push_apps_title\">Appar som använder push-meddelanden</string>\n    <string name=\"prefs_account\">Kontoinställningar</string>\n    <string name=\"self_check_pkg_gms\">microG Services</string>\n    <string name=\"lacking_permission_toast\">microG-tjänster: Saknar behörighet att <xliff:g example=\"have full network acccess\">%1$s</xliff:g></string>\n    <string name=\"auth_notification_content\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> kräver din autentisering för att komma åt ditt Google-konto.</string>\n    <string name=\"gms_app_name\">microG-tjänster</string>\n    <string name=\"self_check_name_perm_granted\">Systemet ger signaturspoofingtillstånd:</string>\n    <string name=\"auth_before_connect\">En app på din enhet försöker logga in på ett Google-konto.\\n\\nOm detta var avsiktligt, använd knappen <b>Logga in</b> för att ansluta till Googles inloggningssida, om inte, tryck på <b>Avbryt</b> för att gå tillbaka till programmet som gjorde att den här dialogrutan dök upp.</string>\n    <string name=\"self_check_name_battery_optimizations\">Batterioptimering ignorerad:</string>\n    <string name=\"signin_subtext_sharing\">För att fortsätta kommer microG att dela namn, e-postadress och profilbild för ditt Google-konto med <xliff:g example=\"F-Droid\">%1$s</xliff:g>.</string>\n    <string name=\"auth_notification_title\">Autentisering krävs</string>\n    <string name=\"pref_auth_include_android_id_title\">Autentisera med enhetsregistrering</string>\n    <string name=\"pref_push_app_allow_register_title\">Tillåt registrering</string>\n    <string name=\"allow\">Tillåt</string>\n    <string name=\"prefs_account_security\">Inloggning och säkerhet</string>\n    <string name=\"pref_gcm_ping_interval\">Pingintervall: <xliff:g example=\"10 minutes\">%1$s</xliff:g></string>\n    <string name=\"gms_settings_summary\">Konfigurera microG-tjänster.</string>\n    <string name=\"pref_add_account_summary\">Lägg till Google-konto</string>\n    <string name=\"self_check_resolution_fake_sig_perm\">Din ROM har inget inhemskt stöd för signaturspoofing. Du kan fortfarande använda Xposed eller andra system för att spoofa signaturen. Kontrollera dokumentationen vilka ROM som stödjer signaturspoofing och hur man använder mikroG på ROM som inte gör det.</string>\n    <string name=\"auth_finalize\">Din enhet kontaktar Google för att spara information på ditt konto.\n\\n\n\\nDet kan ta några minuter.</string>\n    <string name=\"pref_checkin_enable_summary\">Registrerar din enhet på Google services och skapar en unik enhetsidentifierare. MikroG tar bort andra identifieringsbitar utom ditt Google-kontonamn från registreringsdata.</string>\n    <string name=\"cond_perm_title\">Behörighet saknas</string>\n    <string name=\"pref_push_app_allow_register_summary\">Tillåt appen att registrera sig för push-meddelanden.</string>\n    <string name=\"self_check_name_correct_sig\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> har rätt signatur: </string>\n    <string name=\"pref_gcm_enable_mcs_summary\">Cloud Messaging är en push-meddelandeleverantör som används av många tredjepartsprogram. För att använda den måste du aktivera enhetsregistrering.</string>\n    <string name=\"signin_subtext_policy_terms\">villkor för tjänsten</string>\n    <string name=\"prefcat_push_apps_registered_title\">Registrerade appar</string>\n    <string name=\"prefcat_location_service\">Platstjänster</string>\n    <string name=\"gcm_app_not_installed_anymore\">Inte längre installerad</string>\n    <string name=\"prefcat_push_networks_title\">Nätverk att använda för push-meddelanden</string>\n    <string name=\"ask_service_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> vill använda:</string>\n    <string name=\"self_check_name_app_installed\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> installerad: </string>\n    <string name=\"prefcat_services\">Tjänster</string>\n    <string name=\"self_check_resolution_system_spoofs\">Kontrollera dokumentationen om vilka åtgärder som kan krävas.</string>\n    <string name=\"games_info_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> vill använda Play Games</string>\n    <string name=\"prefs_account_privacy\">Personlig information och sekretess</string>\n    <string name=\"pref_device_registration_import_custom_profile_title\">Importera anpassad profil</string>\n    <string name=\"pref_safetynet_recent_request_type\">Förfrågningstyp</string>\n    <string name=\"pref_recaptcha_enterprise_test_title\">Testa ReCAPTCHA Enterprise</string>\n    <string name=\"pref_safetynet_test_title\">Testa SafetyNet-attestering</string>\n    <string name=\"pref_safetynet_test_no_result\">Inget resultat</string>\n    <string name=\"safetynet_intro\">Google SafetyNet är ett enhetscertifieringssystem, vilket säkerställer att enheten är korrekt säkrad och kompatibel med Android CTS. Vissa program använder SafetyNet av säkerhetsskäl eller som en förutsättning för manipuleringsskydd.\n\\n\n\\nMicroG GmsCore innehåller en fri implementering av SafetyNet, men den officiella servern kräver att SafetyNet-förfrågningar undertecknas med hjälp av det proprietära DroidGuard-systemet.</string>\n    <string name=\"pref_device_registration_import_custom_profile_summary\">Importera enhetsprofil från fil</string>\n    <string name=\"pref_safetynet_recent_copy_json\">Kopiera JSON JWS-data</string>\n    <string name=\"pref_test_summary_failed\">Misslyckat: %s</string>\n    <string name=\"pref_safetynet_recent_advice\">Råd</string>\n    <string name=\"push_notifications_summary_values_seconds\">%s sekunder</string>\n    <string name=\"pref_safetynet_test_invalid_json\">Ogiltig JSON</string>\n    <string name=\"menu_clear_recent_requests\">Rensa tidigare förfrågningar</string>\n    <string name=\"pref_safetynet_recent_recaptcha_enterprise_summary\">ReCaptcha Enterprise: %s</string>\n    <string name=\"pref_safetynet_recent_cat_request\">Förfrågningsdata</string>\n    <string name=\"pref_safetynet_recent_attestation_summary\">Attest: %s</string>\n    <string name=\"prefcat_safetynet_apps_title\">Appar som använder SafetyNet</string>\n    <string name=\"safetynet_enable_switch\">Tillåt enhetsattestering</string>\n    <string name=\"pref_safetynet_test_integrity_failed\">Sekretess misslyckades</string>\n    <string name=\"push_notifications_summary_automatic\">PÅ / Automatisk: %s</string>\n    <string name=\"pref_device_registration_serial_title\">Serienummer</string>\n    <string name=\"pref_safetynet_test_cts_failed\">CTS misslyckades</string>\n    <string name=\"push_notifications_summary_manual\">PÅ / Manuell: %s</string>\n    <string name=\"profile_name_auto\">Automatisk: %s</string>\n    <string name=\"push_notifications_summary_values_minutes\">%s minuter</string>\n    <string name=\"pref_safetynet_test_integrity_cts_passed\">Sekretess och CTS klart</string>\n    <string name=\"pref_safetynet_recent_uses\">Tidigare använt</string>\n    <string name=\"pref_droidguard_unsupported_summary\">DroidGuard stöds inte på denna enhet. SafetyNet-jänster kanske inte fungerar korrekt.</string>\n    <string name=\"pref_safetynet_recent_nonce\">Icke (Hex)</string>\n    <string name=\"safetynet_last_run_at\">Senast använd: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"pref_safetynet_recent_recaptcha_summary\">ReCaptcha: %s</string>\n    <string name=\"pref_test_summary_passed\">Klarade alla tester</string>\n    <string name=\"push_notifications_summary_off\">AV</string>\n    <string name=\"pref_safetynet_recent_response_status\">Svarsstatus</string>\n    <string name=\"pref_device_registration_select_profile_title\">Välj profil</string>\n    <string name=\"pref_test_summary_warn\">Varning: %s</string>\n    <string name=\"pref_droidguard_operation_mode\">Åtgärdsläge</string>\n    <string name=\"profile_name_real\">Verklig</string>\n    <string name=\"pref_safetynet_recent_copied\">Kopierat till urklipp!</string>\n    <string name=\"profile_name_user\">Anpassad: %s</string>\n    <string name=\"pref_recaptcha_test_title\">Testa ReCAPTCHA</string>\n    <string name=\"profile_name_native\">Inhemsk</string>\n    <string name=\"pref_test_summary_running\">Kör…</string>\n    <string name=\"pref_safetynet_recent_cat_basic\">Grundläggande data</string>\n    <string name=\"profile_name_system\">System: %s</string>\n    <string name=\"pref_safetynet_recent_cat_response\">Svarsdata</string>\n    <string name=\"pref_safetynet_recent_token\">Token</string>\n    <string name=\"pref_safetynet_test_not_completed\">Inte färdigt ännu</string>\n    <string name=\"pref_safetynet_recent_request_time\">Tid för förfrågan</string>\n    <string name=\"pref_device_registration_device_profile_category\">Enhetsprofil</string>\n    <string name=\"pref_safetynet_recent_eval_type\">Evalueringstyp</string>\n    <string name=\"pref_vending_summary_licensing_on\">Licensiering på</string>\n    <string name=\"pref_vending_licensing_enable_switch\">Svara på förfrågningar om licensverifiering</string>\n    <string name=\"pref_vending_license_enable_summary\">Vissa appar kräver verifiering att du har köpt dem på Google Play. På begäran av en app kan microG ladda ner ett köpbevis från Google. Om det är inaktiverat, eller om inget Google-konto lagts till, ignoreras förfrågan om licensverifiering.</string>\n    <string name=\"pref_vending_summary_licensing_off\">Licensiering av</string>\n    <string name=\"service_name_vending\">Play Store-tjänster</string>\n    <string name=\"feedback_disabled\">Återkoppling är inte möjligt för närvarande</string>\n    <string name=\"pref_auth_strip_device_name_summary\">När det är aktiverat kommer autentiseringsförfrågningar inte att inkludera enhetens namn, vilket kan tillåta obehöriga enheter att logga in, men kan ha oförutsedda konsekvenser.</string>\n    <string name=\"pref_auth_strip_device_name_title\">Ta bort enhetsnamn för autentisering</string>\n    <string name=\"perm_car_info_description\">Tillgång till din bils information</string>\n    <string name=\"perm_car_speed_label\">Bilhastighet</string>\n    <string name=\"perm_car_info_label\">Bilinformation</string>\n    <string name=\"perm_car_fuel_label\">Bilens bränslenivå</string>\n    <string name=\"perm_car_fuel_description\">Få tillgång till din bils bränslenivåinformation</string>\n    <string name=\"perm_car_mileage_label\">Bilens körsträcka</string>\n    <string name=\"perm_car_speed_description\">Få tillgång till din bils hastighet</string>\n    <string name=\"perm_car_vendor_extension_label\">Bilförsäljarkanal</string>\n    <string name=\"perm_car_vendor_extension_description\">Få tillgång till din bils leverantörskanal för att utbyta bilspecifik information</string>\n    <string name=\"pref_accounts_summary\">Lägg till och hantera Google-konton</string>\n    <string name=\"prefcat_accounts_settings_title\">Inställningar</string>\n    <string name=\"pref_accounts_title\">Google-konton</string>\n    <string name=\"prefcat_accounts_current_accounts_title\">Konton</string>\n    <string name=\"pref_vending_licensing_category\">Google Play-licensiering</string>\n    <string name=\"pref_vending_billing_category\">Google Play-fakturering</string>\n    <string name=\"pref_vending_billing_enable_switch\">Hantera fakturafrågor</string>\n    <string name=\"pref_vending_billing_enable_summary\">När det är aktiverat kan vissa appar slutföra inköp eller starta prenumerationer via Googles Plays betalningstjänst.</string>\n    <string name=\"pref_vending_billing_note_experimental\">Denna funktion är experimentell och kan leda till förlust av pengar. Du har varnats.</string>\n    <string name=\"pref_vending_billing_note_licensing\">Vissa appar kan kräva att du också aktiverar licensverifiering för att verifiera dina inköp.</string>\n    <string name=\"backup_disabled\">Säkerhetskopiering är för närvarande inte möjlig</string>\n    <string name=\"perm_car_mileage_description\">Få tillgång till din bils körsträcka</string>\n    <string name=\"credentials_assisted_continue\">Fortsätt</string>\n    <string name=\"credentials_assisted_cancel\">Avbryt</string>\n    <string name=\"credentials_assisted_confirmation_header\">Loggar in dig</string>\n    <string name=\"credentials_assisted_continue_as_user_button_label\">Fortsätt som %1$s</string>\n    <string name=\"credentials_assisted_sign_back_title\">Logga in igen, på %1$s, med Google</string>\n    <string name=\"credentials_assisted_signin_consent_header\">Loggar in som %1$s</string>\n    <string name=\"credentials_assisted_signin_description\">Du kan hantera inloggning med Google i dina Google-konton.</string>\n    <string name=\"credentials_assisted_choose_account_label\">Välj konto</string>\n    <string name=\"credentials_assisted_signin_consent\">Genom att fortsätta kommer Google att dela ditt namn, din e-postadress och din profilbild med %1$s. Se %1$s:s sekretesspolicy och användarvillkor.</string>\n    <string name=\"credentials_assisted_choose_account_subtitle\">för att fortsätta till %1$s</string>\n    <string name=\"credentials_assisted_signin_button_text_long\">Logga in med Google</string>\n    <string name=\"auth_package_override_request_title\">Tillåt <b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> privilegierad åtkomst till <xliff:g example=\"account@example.com\">%2$s</xliff:g>\\?</string>\n    <string name=\"auth_package_override_request_message\"><b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> vill komma åt ditt konto som om det var <b><xliff:g example=\"F-Droid\">%2$s</xliff:g> by <xliff:g example=\"F-Droid Inc.\">%3$s</xliff:g></b>. Detta kan ge F-Droid privilegierad tillgång till ditt konto.</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_switch\">Lägg automatiskt till gratisappar i biblioteket</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_summary\">Gratisappar kan kontrollera om de har laddats ner från Google Play. Lägg automatiskt till gratisappar i ditt kontobibliotek för att alltid klara kontrollen för alla gratisappar som för närvarande är tillgängliga för dig.</string>\n    <string name=\"limited_services_dialog_information_ack\">Jag förstår</string>\n    <string name=\"limited_services_app_name\">microG Limited Services</string>\n    <string name=\"limited_services_dialog_information\">Du använder microG Limited Services. Till skillnad från de vanliga mikroG-tjänsterna fungerar denna version endast med appar som använder mikroG-bibliotek, inte de på Google Play. Det innebär att de flesta appar ignorerar dessa tjänster.</string>\n    <string name=\"auth_action_notification_content\">Ditt Google-konto behöver ytterligare inställning.</string>\n    <string name=\"auth_action_step_allow_microg_gcm\">Tillåt Cloud Messaging för microG</string>\n    <string name=\"auth_action_step_enable_lockscreen\">Konfigurera säkert skärmlås</string>\n    <string name=\"auth_action_step_perform_content_description\">Tryck för att utföra steg</string>\n    <string name=\"auth_action_notification_title\">Kontoåtgärder krävs</string>\n    <string name=\"auth_action_notification_channel_name\">Google kontomeddelanden</string>\n    <string name=\"auth_action_activity_explanation\">Slutför följande steg för att kunna använda ditt Google-konto %s på den här enheten.</string>\n    <string name=\"auth_action_notification_channel_description\">Meddelar när en av dina Google-konton kräver ytterligare inställning innan det kan användas eller när ett konto är oförenligt med microG.</string>\n    <string name=\"auth_action_activity_header\">Slutför installation av ditt Google-konto</string>\n    <string name=\"auth_action_step_enable_checkin\">Aktivera enhetsregistrering</string>\n    <string name=\"auth_action_step_enable_checkin_description\">Din enhet måste registreras hos Google minst en gång.\\n\\nDu kan inaktivera Googles enhetsregistrering efter att kontoinställningen är klar.</string>\n    <string name=\"auth_action_step_enable_gcm\">Aktivera Cloud Messaging</string>\n    <string name=\"auth_action_step_enable_gcm_description\">Du kan inaktivera Cloud Messaging efter att kontoinställningen är klar.</string>\n    <string name=\"auth_action_step_allow_microg_gcm_description\">Enligt dina inställningar, behöver microG tillstånd från dig innan det kan registreras för Cloud Messaging.</string>\n    <string name=\"auth_action_activity_finish\">Slutför</string>\n    <string name=\"auth_action_step_enable_lockscreen_description\">Ditt Google-konto hanteras av din arbetsplats eller utbildningsinstitution. Din administratör bestämde att enheter behöver ett säkert skärmlås innan de kan komma åt kontodata.\\n\\nAnge ett lösenord, PIN eller mönsterlåsskärm.</string>\n    <string name=\"auth_action_step_completed_content_description\">Steg färdigställt</string>\n    <string name=\"pref_vending_asset_delivery_category\">Google Play Asset Delivery</string>\n    <string name=\"pref_vending_asset_delivery_switch\">Aktivera tillgångsleverans på begäran</string>\n    <string name=\"pref_vending_asset_delivery_summary\">Ladda ner fler tillgångar, på begäran av appar som använder Google Play Asset Delivery</string>\n    <string name=\"pref_vending_asset_device_sync_summary\">Applikationer som använder Play Asset Delivery kommer att ladda ner ytterligare tillgångar baserat på informationen från den enhet som för närvarande används.</string>\n    <string name=\"pref_vending_asset_device_sync_switch\">Aktivera synkronisering av enhetsinformation</string>\n    <string name=\"games_achievement_list_title\">Framgångar</string>\n    <string name=\"games_achievements_empty_text\">Inga framgångar för detta spel</string>\n    <string name=\"games_api_access_denied\">Inget konton på den här enheten kan komma åt spelets API</string>\n    <string name=\"games_achievement_locked_content_description\">låst</string>\n    <string name=\"games_achievement_unlocked_content_description\">upplåst</string>\n    <string name=\"games_achievement_extra_text\">%1$s XP</string>\n    <string name=\"games_leaderboard_score_empty_text\">Otroligt! Det finns inga offentliga högsta poäng för detta spel.</string>\n    <string name=\"games_leaderboard_list_title\">Ranking</string>\n    <string name=\"games_leaderboards_score_label\">Poäng: %1$s</string>\n    <string name=\"games_snapshot_empty_text\">Inga spel har sparats ännu</string>\n    <string name=\"games_snapshot_choose_btn_text\">välj</string>\n    <string name=\"games_snapshot_delete_btn_text\">ta bort</string>\n    <string name=\"games_delete_snapshot_dialog_title\">Ta bort sparat spel</string>\n    <string name=\"games_delete_snapshot_error\">Borttagning misslyckades, försök igen senare</string>\n    <string name=\"games_delete_snapshot_dialog_cancel\">Avbryt</string>\n    <string name=\"games_leaderboard_empty_text\">Inga leaderboards för detta spel</string>\n    <string name=\"games_delete_snapshot_dialog_message\">Är du säker på att du vill ta bort detta sparade spel?</string>\n    <string name=\"games_delete_snapshot_dialog_ok\">OK</string>\n    <string name=\"pref_vending_split_install_switch\">On-demand komponentinstallation</string>\n    <string name=\"camera_permission_dialog_button\">OK</string>\n    <string name=\"camera_permission_dialog_title\">Kameratillstånd krävs</string>\n    <string name=\"pref_workprofile_create_account\">Tillåt arbetskontoinställning</string>\n    <string name=\"barcode_scanner_brand\">Skannad av microG på uppdrag av %1$s</string>\n    <string name=\"pref_workprofile_intro\">När du ställer in en arbetsprofil för din arbetsplats eller utbildningsinstitution kan installationen försöka ansluta till Google för att aktivera nedladdning av appar till den profilen.</string>\n    <string name=\"pref_vending_licensing_split_install_summary\">Tillåt appar att ladda ner och installera ytterligare komponenter</string>\n    <string name=\"camera_permission_dialog_message\">mikro mikroG-tjänster måste komma åt din enhets kamera för att skanna en kod för %1$s.\\n\\nFör att möjliggöra detta, behöver du ge kamerabehörighet till mikroG-tjänster i Inställningar.</string>\n    <string name=\"service_name_work_profile\">Arbetsprofil</string>\n    <string name=\"pref_vending_feature_delivery\">Google Play funktionsleverans</string>\n    <string name=\"pref_workprofile_disclaimer\">Det är ditt ansvar att se till att din användning av mikro G är i linje med företagets policy. mikroG tillhandahålls på bästa sätt och kan inte garanteras att bete sig exakt som förväntat.</string>\n    <string name=\"credentials_assisted_choose_account_error_tips\">Konto onormalt</string>\n    <string name=\"credentials_assisted_signin_add_account\">Lägg till konto</string>\n    <string name=\"auth_action_reauth_notification_title\">Kontoåtgärd krävs</string>\n    <string name=\"pref_game_accounts_title\">Google Game-konton</string>\n    <string name=\"pref_auto_create_player\">Tillåt Play Games kontoregistrering</string>\n    <string name=\"pref_auto_create_player_intro\">När du spelar spel måste du använda ett Play Games-konto för att logga in och spela in spelrelaterade funktioner, såsom prestationer, leaderboards, arkiv etc. Efter inaktivering kommer Google-konton som inte är bundna till ett Play Games-konto inte att registreras automatiskt, och spelet kommer inte att kunna loggas in och spelas.</string>\n    <string name=\"pref_allow_upload_game_played\">Tillåt uppladdning av spel</string>\n    <string name=\"pref_allow_upload_game_played_summary\">Vid inaktivering kommer spelet inte att rapportera spelstatus efter inloggning, och vissa spel kanske inte kan logga in.</string>\n    <string name=\"pref_change_default_game_player\">Byt konto för spel</string>\n    <string name=\"pref_change_default_game_player_summary\">Byt standardkonto för spel och byt konto efter spel.</string>\n    <string name=\"pref_delete_game_account_data\">Ta bort Play Games-data</string>\n    <string name=\"pref_delete_game_account_data_summary\">Ta bort Play Games-konto &amp; all data, och radera individuella speldata.</string>\n    <string name=\"games_state_description_signed_out\">Utloggad</string>\n    <string name=\"games_state_description_delete\">Ta bort</string>\n    <string name=\"games_change_button_text\">Ändra</string>\n    <string name=\"games_change_default_account_section_title\">Ändra standardkontot för spel</string>\n    <string name=\"games_change_default_account_description\">Standardkonto: %1$s</string>\n    <string name=\"games_change_default_account_explanation\">Detta konto används för att automatiskt logga in dig på spel, spara din spelstatus och spara dina inställningar. Ändra standardkontot eller logga ut kan återställa din status och inställningar för spel du har spelat.</string>\n    <string name=\"games_change_per_game_title\">Ändra konto efter spel</string>\n    <string name=\"games_change_per_game_description\">Ändra kontot för ett valt spel eller logga ut från det kan återställa din status och inställningar för spelet.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_title\">Välj ett alternativ för det nya standardkontot</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_description\">Aktuellt standardkonto: %1$s</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_title\">Ändra standardkontot endast för nya spel</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_description\">Du kommer inte att förlora tillgången till status och inställningar för spel du har spelat. Men din status kommer att delas mellan konton.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_title\">Ändra standardkonto för alla spel</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_description\">Du kan förlora åtkomst till status och inställningar för spel du har spelat. Vi startar om spelet för att tillämpa dina ändringar.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_title\">Logga ut från alla spel</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_description\">Du kan förlora åtkomst till status och inställningar för spel du har spelat. Vi startar om spelet för att tillämpa dina ändringar.</string>\n    <string name=\"games_change_per_game_dialog_title\">Välj ett alternativ för detta spel</string>\n    <string name=\"games_change_per_game_dialog_description\">Ändra kontot eller logga ut kan återställa din status och inställningar för spelet</string>\n    <string name=\"games_change_per_game_dialog_option_use_player\">Använd %1$s</string>\n    <string name=\"games_change_per_game_dialog_option_use_player_snackbar_success_message\">Du kommer att bli inloggad på detta spel med %1$s</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out\">Logga ut</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out_snackbar_success_message\">Du är nu utloggad från detta spel</string>\n    <string name=\"games_change_sign_out_of_all_games_snackbar_success_message\">Du är nu utloggad från alla spel</string>\n    <string name=\"games_change_default_account_for_all_games_snackbar_success_message\">Du kommer att loggas in på alla spel med %1$s</string>\n    <string name=\"games_change_default_account_for_new_games_snackbar_success_message\">Du kommer att loggas in på nya spel med %1$s</string>\n    <string name=\"games_account_display_content\">Aktuellt konto: %1$s</string>\n    <string name=\"games_delete_profile_header\">Ta bort Play Games-konto och all data</string>\n    <string name=\"games_delete_profile_explanation\">Ta permanent bort ditt Google Play Games-konto, XP och alla profildata. Denna åtgärd kan också ta bort dina poäng, status (sparade spel) och inställningar i spel du har spelat.</string>\n    <string name=\"games_delete_profile_button\">Ta bort permanent</string>\n    <string name=\"games_delete_game_data_header\">Ta bort individuella speldata</string>\n    <string name=\"games_delete_game_data_explanation\">Du kan permanent radera enskilda data för spel som du har spelat med hjälp av Google Play Games. Denna åtgärd raderar dina poäng, status (sparade spel) och inställningar för det spel du väljer.</string>\n    <string name=\"games_delete_profile_dialog_title\">Vill du verkligen ta bort detta konto?</string>\n    <string name=\"games_delete_profile_explanation_with_gamer_name\">Radera permanent ditt Google Play Games-konto för gamer-namn <b>%1$s</b> (<b>%2$s</b>), XP och alla profildata. Denna åtgärd kan också ta bort dina poäng, status (sparade spel) och inställningar i spel du har spelat.</string>\n    <string name=\"games_delete_profile_dialog_message\">Denna åtgärd kan inte ångras.</string>\n    <string name=\"games_delete_profile_fail\">Kunde inte ta bort din profil. Försök igen senare.</string>\n    <string name=\"games_delete_game_data_confirm_dialog_title\">Ta bort data för %1$s</string>\n    <string name=\"games_delete_game_data_confirm_dialog_message\">Att permanent ta bort dina data för %1$s kommer att ta bort dina poäng, status (sparade spel) och spelinställningar i Google Play Games.</string>\n    <string name=\"games_popup_signin_welcome\">Hej där, %1$s</string>\n    <string name=\"pref_auth_two_step_verification_title\">Ta emot 2-stegsverifiering</string>\n    <string name=\"pref_auth_two_step_verification_summary\">När det är aktiverat kan enheten få tvåstegsverifiering från Google (Cloud Messaging krävs).</string>\n    <string name=\"service_name_google_location_sharing\">Google platsdelning</string>\n    <string name=\"location_sharing_description\">Hantera din realtids platsdelning mellan Google-appar och tjänster från den här enheten</string>\n    <string name=\"location_sharing_learn_more\">Läs mer om platsdelning</string>\n    <string name=\"location_sharing_switch_text\">Använd platsdelning</string>\n    <string name=\"location_sharing_turn_off_notify_hint\">Om du stänger av platsdelning för den här enheten kommer personer du delar med inte att meddelas.</string>\n    <string name=\"location_sharing_off_previous_hint\">Endast din sista delade plats kommer att finnas tillgänglig tills du slår på den igen.</string>\n    <string name=\"location_sharing_disabled\">Inga aktiva platsdelningar för detta konto</string>\n    <string name=\"location_sharing_turn_on_hint\">När du börjar dela din plats från en Google-app eller tjänst kan du hantera platsdelningen härifrån.\\n\\nFör att börja dela din plats, gå till Google Maps eller Family Link.</string>\n    <string name=\"location_sharing_turn_off_title\">Stäng av platsdelning</string>\n    <string name=\"location_sharing_turn_off_hint\">Du kan fortfarande dela din plats från andra enheter som är inloggade på samma Google-konto eller från icke-Google-appar. Se till att kontrollera dina platsdelningsinställningar var det än kan gälla.\\n\\nPersoner du delar med kommer att fortsätta att se din sista delade plats.</string>\n    <string name=\"location_sharing_turn_off_cancel\">Fortsätt</string>\n    <string name=\"location_sharing_turn_off_confirm\">Stäng av</string>\n    <string name=\"location_sharing_confirm_dialog_title\">Aktivera platsdelning</string>\n    <string name=\"location_sharing_confirm_dialog_text\">Personer du delar din plats med kan alltid se:\\n·Ditt namn och foto\\n·Din enhets senaste plats, även när du inte använder en Google-tjänst\\n·Din enhets batterikraft, och om den laddas\\n·Din ankomst- och avgångstid, om de lägger till en platsdelningsmeddelande</string>\n    <string name=\"family_management_title\">Familj</string>\n    <string name=\"family_management_retry\">Försök igen</string>\n    <string name=\"family_management_load_error\">Kunde inte läsa in innehåll</string>\n    <string name=\"family_management_toolbar_back\">Tillbaka</string>\n    <string name=\"family_management_toolbar_more\">Mer</string>\n    <string name=\"family_management_exit_family_group\">Lämna familjegruppen</string>\n    <string name=\"family_management_delete_family_group\">Ta bort en familjegrupp</string>\n    <string name=\"family_management_leave_family_password_title\">Bekräfta lösenord för att lämna familjegruppen</string>\n    <string name=\"family_management_delete_family_password_title\">Bekräfta lösenord för att ta bort en familjegrupp</string>\n    <string name=\"family_management_remove_member_password_title\">Bekräfta lösenord för att ta bort %s</string>\n    <string name=\"family_management_invite_family_member\">Bjud in familjemedlemmar</string>\n    <string name=\"family_management_invite_slots_left\">%1$d inbjudningar kvar</string>\n    <string name=\"family_management_cancel_invite\">Avboka inbjudan</string>\n    <string name=\"family_management_cancel_invite_success\">Inbjudan avbruten</string>\n    <string name=\"family_management_cancel_invite_error\">Kunde inte avbryta inbjudan, Försök igen.</string>\n    <string name=\"family_management_remove_member\">Ta bort medlem</string>\n    <string name=\"family_management_member_removed_success\">%s togs bort från din familjegrupp</string>\n    <string name=\"family_management_member_remove_failed\">Kunde inte ta bort %s. Försök igen.</string>\n    <string name=\"family_management_leave_family_error_message\">Kunde inte lämna familjegruppen. Försök igen.</string>\n    <string name=\"family_management_exist_group_success\">Du har lämnat din familjegrupp…</string>\n    <string name=\"family_management_delete_group_success\">Familjegruppen borttagen</string>\n    <string name=\"family_management_delete_group_failure\">Underlåten att ta bort hemgrupp</string>\n    <string name=\"family_management_delete_group_cancel\">Avbryt</string>\n    <string name=\"family_management_delete_group_confirm\">OK</string>\n    <string name=\"family_management_input_pwd\">Vänligen ange ditt lösenord</string>\n    <string name=\"family_management_invite_sent_date_format\">Inbjudan skickad %s</string>\n    <string name=\"family_management_invite_send\">Inbjudan skickad</string>\n    <string name=\"family_management_pwd_error\">Fel lösenord, försök igen</string>\n    <string name=\"pref_app_install_settings_title\">Inställningar för appinstallatör</string>\n    <string name=\"pref_app_install_switch_title\">Tillåt appinstallation</string>\n    <string name=\"pref_app_install_other_apps_note\">Auktorisering tillåter installation av appar som tillhandahålls från andra källor.</string>\n    <string name=\"pref_app_install_permission_instruction\">För att säkerställa att dina installerade appar fungerar ordentligt, godkänn att mikroG Companion installerar appar hämtade från andra källor.</string>\n    <string name=\"prefcat_app_install_list_title\">Appar som använder App Installer</string>\n    <string name=\"pref_device_attestation_app_allow_requests_summary\">Tillåt appen att begära enhetsattestering</string>\n    <string name=\"prefcat_device_attestation_apps_title\">Appar som använder Enhetsattestering</string>\n    <string name=\"pref_device_attestation_app_allow_requests_title\">Tillåt förfrågningar</string>\n    <string name=\"service_name_device_attestation\">Enhetsattestering</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-ta/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"permission_service_cl_description\">எந்தவொரு தொடர்புடைய Google கணக்கின் மூலமும் Google காலெண்டரை அணுக பயன்பாட்டை அனுமதிக்கிறது.</string>\n    <string name=\"permission_service_cp_description\">தொடர்புடைய எந்தவொரு Google கணக்கின் மூலமும் தொடர்புகளை அணுக பயன்பாட்டை அனுமதிக்கிறது.</string>\n    <string name=\"permission_service_dodgeball_label\">டாட்ச்பால்</string>\n    <string name=\"permission_service_dodgeball_description\">தொடர்புடைய எந்தவொரு கூகிள் கணக்கின் மூலமும் டாட்ச்பைலை அணுக பயன்பாட்டை அனுமதிக்கிறது.</string>\n    <string name=\"permission_service_finance_label\">கூகிள் பொருள்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.scripts\">உங்கள் Google Apps ச்கிரிப்ட் ச்கிரிப்ட்களின் நடத்தையை மாற்றவும்</string>\n    <string name=\"permission_service_finance_description\">தொடர்புடைய எந்தவொரு Google கணக்கின் மூலமும் Google பொருள் அணுக பயன்பாட்டை அனுமதிக்கிறது.</string>\n    <string name=\"permission_service_gbase_label\">கூகிள் அடிப்படை</string>\n    <string name=\"permission_service_gbase_description\">தொடர்புடைய எந்தவொரு Google கணக்கின் மூலமும் Google தளத்தை அணுக பயன்பாட்டை அனுமதிக்கிறது.</string>\n    <string name=\"permission_service_grandcentral_label\">கூகிள் குரல்</string>\n    <string name=\"permission_service_grandcentral_description\">தொடர்புடைய எந்தவொரு Google கணக்கின் மூலமும் Google குரலை அணுக பயன்பாட்டை அனுமதிக்கிறது.</string>\n    <string name=\"permission_service_groups2_label\">கூகிள் குழுக்கள்</string>\n    <string name=\"permission_service_groups2_description\">தொடர்புடைய கூகிள் கணக்கின் மூலம் Google குழுக்களை அணுக பயன்பாட்டை அனுமதிக்கிறது.</string>\n    <string name=\"permission_service_health_label\">கூகிள் உடல்நலம்</string>\n    <string name=\"permission_service_health_description\">தொடர்புடைய எந்தவொரு Google கணக்கின் மூலமும் Google ஆரோக்கியத்தை அணுக பயன்பாட்டை அனுமதிக்கிறது.</string>\n    <string name=\"permission_service_ig_label\">கூகிள்</string>\n    <string name=\"permission_service_ig_description\">தொடர்புடைய எந்தவொரு Google கணக்கின் மூலமும் Igoogle ஐ அணுக பயன்பாட்டை அனுமதிக்கிறது.</string>\n    <string name=\"permission_service_jotspot_label\">சோட்ச்பாட்</string>\n    <string name=\"permission_service_jotspot_description\">தொடர்புடைய எந்தவொரு Google கணக்கின் மூலமும் JOTSPOT ஐ அணுக பயன்பாட்டை அனுமதிக்கிறது.</string>\n    <string name=\"permission_service_knol_label\">கிழங்கு</string>\n    <string name=\"permission_service_knol_description\">தொடர்புடைய எந்தவொரு Google கணக்கின் மூலமும் பயன்பாட்டை அனுமதிக்கிறது.</string>\n    <string name=\"permission_service_lh2_label\">பிகாசா வலை ஆல்பங்கள்</string>\n    <string name=\"permission_service_lh2_description\">தொடர்புடைய கூகிள் கணக்கின் மூலம் பிகாசா வலை ஆல்பங்களை அணுக பயன்பாட்டை அனுமதிக்கிறது.</string>\n    <string name=\"permission_service_local_label\">கூகிள் வரைபடங்கள்</string>\n    <string name=\"permission_service_local_description\">தொடர்புடைய எந்தவொரு Google கணக்கின் மூலமும் Google வரைபடங்களை அணுக பயன்பாட்டை அனுமதிக்கிறது.</string>\n    <string name=\"permission_service_mail_label\">கூகிள் மெயில்</string>\n    <string name=\"permission_service_mail_description\">தொடர்புடைய எந்த Google கணக்கின் மூலமும் Google அஞ்சலை அணுக பயன்பாட்டை அனுமதிக்கிறது.</string>\n    <string name=\"permission_service_news_label\">கூகிள் செய்தி</string>\n    <string name=\"permission_service_news_description\">தொடர்புடைய எந்தவொரு Google கணக்கின் மூலமும் Google செய்திகளை அணுக பயன்பாட்டை அனுமதிக்கிறது.</string>\n    <string name=\"permission_service_notebook_label\">கூகிள் நோட்புக்</string>\n    <string name=\"permission_service_notebook_description\">தொடர்புடைய கூகிள் கணக்கின் மூலம் Google நோட்புக்கை அணுக பயன்பாட்டை அனுமதிக்கிறது.</string>\n    <string name=\"permission_service_orkut_label\">Orkut</string>\n    <string name=\"permission_service_orkut_description\">தொடர்புடைய எந்தவொரு Google கணக்கின் மூலமும் ORKUT ஐ அணுக பயன்பாட்டை அனுமதிக்கிறது.</string>\n    <string name=\"permission_service_print_label\">கூகிள் புத்தக தேடல்</string>\n    <string name=\"permission_service_print_description\">தொடர்புடைய எந்தவொரு Google கணக்கின் மூலமும் Google புத்தகத் தேடலை அணுக பயன்பாட்டை அனுமதிக்கிறது.</string>\n    <string name=\"permission_service_sierra_label\">கூகிள் புதுப்பித்து கணக்குகள்</string>\n    <string name=\"permission_service_sierra_description\">எந்தவொரு தொடர்புடைய Google கணக்கின் மூலமும் Google புதுப்பித்தல் கணக்குகளை அணுக பயன்பாட்டை அனுமதிக்கிறது.</string>\n    <string name=\"permission_service_sierraqa_label\">கூகிள் புதுப்பித்தல் QA கணக்குகள்</string>\n    <string name=\"permission_service_sierraqa_description\">தொடர்புடைய எந்தவொரு Google கணக்கின் மூலமும் Google Checkout QA கணக்குகளை அணுக பயன்பாட்டை அனுமதிக்கிறது.</string>\n    <string name=\"permission_service_sierrasandbox_label\">கூகிள் செக்அவுட் சாண்ட்பாக்ச் கணக்குகள்</string>\n    <string name=\"permission_service_sierrasandbox_description\">எந்தவொரு தொடர்புடைய Google கணக்கின் மூலமும் Google புதுப்பித்த சாண்ட்பாக்ச் கணக்குகளை அணுக பயன்பாட்டை அனுமதிக்கிறது.</string>\n    <string name=\"permission_service_sitemaps_label\">கூகிள் வெப்மாச்டர் கருவிகள்</string>\n    <string name=\"permission_service_sitemaps_description\">எந்தவொரு தொடர்புடைய Google கணக்கின் மூலமும் Google வெப்மாச்டர் கருவிகளை அணுக பயன்பாட்டை அனுமதிக்கிறது.</string>\n    <string name=\"permission_service_speech_label\">குரல் தேடல்</string>\n    <string name=\"permission_service_speechpersonalization_description\">தொடர்புடைய எந்தவொரு கூகிள் கணக்கின் மூலமும் தனிப்பயனாக்கப்பட்ட பேச்சு அங்கீகாரத்தை அணுக பயன்பாட்டை அனுமதிக்கிறது.</string>\n    <string name=\"permission_service_talk_label\">கூகிள் பேச்சு</string>\n    <string name=\"permission_service_talk_description\">தொடர்புடைய எந்த Google கணக்கின் மூலமும் Google பேச்சை அணுக பயன்பாட்டை அனுமதிக்கிறது.</string>\n    <string name=\"permission_service_wifi_label\">கூகிள் வைஃபை</string>\n    <string name=\"permission_service_wifi_description\">தொடர்புடைய எந்தவொரு Google கணக்கின் மூலமும் Google Wi-Fi ஐ அணுக பயன்பாட்டை அனுமதிக்கிறது.</string>\n    <string name=\"permission_service_wise_label\">கூகிள் விரிதாள்கள்</string>\n    <string name=\"permission_service_wise_description\">தொடர்புடைய எந்தவொரு Google கணக்கின் மூலமும் Google விரிதாள்களை அணுக பயன்பாட்டை அனுமதிக்கிறது.</string>\n    <string name=\"permission_service_writely_label\">கூகிள் டாக்ச்</string>\n    <string name=\"permission_service_writely_description\">தொடர்புடைய எந்தவொரு Google கணக்கின் மூலமும் Google கோப்புகள் ஐ அணுக பயன்பாட்டை அனுமதிக்கிறது.</string>\n    <string name=\"permission_service_youtube_label\">YouTube</string>\n    <string name=\"permission_service_youtube_description\">தொடர்புடைய எந்தவொரு Google கணக்கின் மூலமும் YouTube ஐ அணுக பயன்பாட்டை அனுமதிக்கிறது.</string>\n    <string name=\"permission_service_YouTubeUser_label\">YouTube பயனர்பெயர்கள்</string>\n    <string name=\"permission_service_all_label\">அனைத்து Google சேவைகளும்</string>\n    <string name=\"permission_service_all_description\">எந்தவொரு தொடர்புடைய Google கணக்கின் மூலமும் அனைத்து Google சேவைகளையும் அணுக பயன்பாட்டை அனுமதிக்கிறது.</string>\n    <string name=\"permission_service_android_label\">ஆண்ட்ராய்டு சேவைகள்</string>\n    <string name=\"permission_service_android_description\">எந்தவொரு தொடர்புடைய Google கணக்கின் மூலமும் ஆண்ட்ராய்டு சேவைகளை அணுக பயன்பாட்டை அனுமதிக்கிறது.</string>\n    <string name=\"permission_service_adsense_label\">Adsense</string>\n    <string name=\"permission_service_adwords_label\">ஆட்வேர்ட்ச்</string>\n    <string name=\"permission_service_cp_label\">தொடர்புகள்</string>\n    <string name=\"permission_service_speech_description\">தொடர்புடைய எந்தவொரு Google கணக்கின் மூலமும் குரல் தேடலை அணுக பயன்பாட்டை அனுமதிக்கிறது.</string>\n    <string name=\"permission_service_speechpersonalization_label\">தனிப்பயனாக்கப்பட்ட பேச்சு ஏற்பு</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue\">உங்கள் பணிகளை நிர்வகிக்கவும்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive\">உங்கள் Google இயக்ககத்தில் கோப்புகள் மற்றும் ஆவணங்களைக் காணலாம் மற்றும் நிர்வகிக்கவும்</string>\n    <string name=\"permission_service_YouTubeUser_description\">தொடர்புடைய எந்தவொரு Google கணக்கிலும் பயன்படுத்தப்படும் YouTube பயனர்பெயரை (களை) அணுக பயன்பாட்டை அனுமதிக்கிறது.</string>\n    <string name=\"perm_activity_recognition_label\">செயல்பாட்டு ஏற்பு</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase.readonly\">உங்கள் ஃப்ரீ பேச் கணக்கைக் காண்க</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase\">உங்கள் கணக்குடன் ஃப்ரீபேசில் உள்நுழைக</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables\">உங்கள் இணைவு அட்டவணைகளை நிர்வகிக்கவும்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables.readonly\">உங்கள் இணைவு அட்டவணைகளைக் காண்க</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_games\">கூகிள் பிளே கேம்களிலிருந்து தரவை அணுகுவதற்கான நோக்கம்.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan\">உங்கள் GAN தரவை நிர்வகிக்கவும்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan.readonly\">உங்கள் GAN தரவைக் காண்க</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gcm_for_chrome\">Chrome க்கு கிளவுட்மசேசிங்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_glass.timeline\">கண்ணாடி காலவரிசை நோக்கம்</string>\n    <string name=\"perm_activity_recognition_description\">கூகிளிலிருந்து உங்கள் செயல்பாட்டு மட்டத்தின் அவ்வப்போது புதுப்பிப்புகளைப் பெற ஒரு பயன்பாட்டை அனுமதிக்கிறது, எடுத்துக்காட்டாக, நீங்கள் நடைபயிற்சி, வண்டி ஓட்டுதல், சைக்கிள் ஓட்டுதல் அல்லது நிலையானது என்றால்.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_activity\">உங்கள் Google பயன்பாடுகளின் செயல்பாட்டு வரலாற்றைக் காண்க</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.buyer\">உங்கள் விளம்பர பரிமாற்ற வாங்குபவர் கணக்கு உள்ளமைவை நிர்வகிக்கவும்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller.readonly\">உங்கள் விளம்பர பரிமாற்ற தரவைக் காண்க</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller\">உங்கள் விளம்பர பரிமாற்ற தரவைக் காணலாம் மற்றும் நிர்வகிக்கவும்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsensehost\">உங்கள் ஆட்சன்ச் புரவலன் தரவு மற்றும் அதனுடன் தொடர்புடைய கணக்குகளைக் காணலாம் மற்றும் நிர்வகிக்கவும்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense.readonly\">உங்கள் adsense தரவைக் காண்க</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense\">உங்கள் ஆட்சன்ச் தரவைக் காணலாம் மற்றும் நிர்வகிக்கவும்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics.readonly\">உங்கள் Google பகுப்பாய்வு தரவைக் காண்க</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics\">உங்கள் Google Analytics தரவைக் காணலாம் மற்றும் நிர்வகிக்கவும்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_androidpublisher\">Google Play ஆண்ட்ராய்டு டெவலப்பருக்கான அணுகல்</string>\n    <string name=\"permission_service_adsense_description\">தொடர்புடைய எந்தவொரு Google கணக்கின் மூலமும் AdSense ஐ அணுக பயன்பாட்டை அனுமதிக்கிறது.</string>\n    <string name=\"permission_service_adwords_description\">தொடர்புடைய எந்தவொரு Google கணக்கின் மூலமும் ADWORDS ஐ அணுக பயன்பாட்டை அனுமதிக்கிறது.</string>\n    <string name=\"permission_service_ah_label\">கூகிள் ஆப் எஞ்சின்</string>\n    <string name=\"permission_service_ah_description\">எந்தவொரு தொடர்புடைய Google கணக்கின் மூலமும் Google Appinge ஐ அணுக பயன்பாட்டை அனுமதிக்கிறது.</string>\n    <string name=\"permission_service_blogger_label\">பதிவர்</string>\n    <string name=\"permission_service_blogger_description\">தொடர்புடைய எந்தவொரு கூகிள் கணக்கின் மூலமும் பதிவரை அணுக பயன்பாட்டை அனுமதிக்கிறது.</string>\n    <string name=\"permission_service_cl_label\">கூகிள் காலண்டர்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appengine.admin\">பயன்பாட்டு இயந்திர நிர்வாக நோக்கம்.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.migration\">குழுக்கள் இடம்பெயர்வு பநிஇ க்கான அணுகலைப் படித்து எழுதுங்கள்.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.settings\">Google Apps குழுவின் அமைப்புகளைக் காணலாம் மற்றும் நிர்வகிக்கவும்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.licensing\">உரிம மேலாளர் பநிஇ க்கான அணுகலைப் படிக்கவும்/எழுதவும்.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order\">மறுவிற்பனையாளர் நிர்வாகிகள் மற்றும் பயனர்கள் பநிஇ இன் சாண்ட்பாக்சில் சோதனை செய்யும் போது அணுகலைப் படிக்கிறார்கள்/எழுதுங்கள், அல்லது பநிஇ செயல்பாட்டை நேரடியாக அழைக்கும்போது அணுகலைப் படிக்கவும்/எழுதவும்.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order.readonly\">ஒட்டுமொத்த வாசிப்பு/எழுத OAuth நோக்கத்திற்கு கூடுதலாக, வாடிக்கையாளரின் தரவை மீட்டெடுக்கும் போது படிக்க மட்டும் OAuth நோக்கத்தைப் பயன்படுத்தவும்.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps_reporting_audit.readonly\">KIND தணிக்கை பநிஇ வாசிப்புக்கான அணுகல்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appstate\">பயன்பாட்டு மாநில சேவையைப் பயன்படுத்துவதற்கான நோக்கம்.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery.readonly\">Google Bigquery இல் உங்கள் தரவைக் காண்க</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery\">Google Bigquery இல் உங்கள் தரவைக் காணலாம் மற்றும் நிர்வகிக்கவும்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger\">உங்கள் பதிவர் கணக்கை நிர்வகிக்கவும்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger.readonly\">உங்கள் பதிவர் கணக்கைக் காண்க</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_books\">உங்கள் புத்தகங்களை நிர்வகிக்கவும்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar\">உங்கள் காலெண்டர்களை நிர்வகிக்கவும்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar.readonly\">உங்கள் காலெண்டர்களைக் காண்க</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_cloudprint\">உங்கள் Google முகில் அச்சு தரவைக் காணலாம் மற்றும் நிர்வகிக்கவும்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute.readonly\">உங்கள் Google கம்ப்யூட் என்சின் வளங்களைக் காண்க</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute\">உங்கள் Google கம்ப்யூட் என்சின் வளங்களைக் காணலாம் மற்றும் நிர்வகிக்கவும்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate.readonly\">உங்கள் Google ஒருங்கிணைப்பு வேலைகளைக் காண்க</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate\">உங்கள் Google வரைபடங்களை ஒருங்கிணைக்கும் வேலைகளைக் காணலாம் மற்றும் நிர்வகிக்கவும்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.full_control\">கூகிள் முகில் சேமிப்பகத்தில் உங்கள் தரவு மற்றும் அனுமதிகளை நிர்வகிக்கவும்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_only\">கூகிள் முகில் சேமிப்பகத்தில் உங்கள் தரவைக் காண்க</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_write\">Google முகில் சேமிப்பகத்தில் உங்கள் தரவை நிர்வகிக்கவும்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_dfareporting\">விளம்பரதாரர்களின் அறிக்கைகளுக்கு டபுள் கிளிக்கைக் காணவும் நிர்வகிக்கவும்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.appdata\">பயன்பாட்டு தரவு கோப்புறையை அணுக அனுமதிக்கிறது</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.apps.readonly\">உங்கள் Google இயக்கி பயன்பாடுகளைக் காண்க</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.file\">இந்த பயன்பாட்டின் மூலம் நீங்கள் திறந்த அல்லது உருவாக்கிய Google இயக்கி கோப்புகளைக் காணலாம் மற்றும் நிர்வகிக்கவும்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.install\">பயன்பாட்டை நிறுவுவதை பயனர்கள் அனுமதிக்க பயன்படுத்தப்படும் சிறப்பு நோக்கம்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.metadata.readonly\">உங்கள் Google இயக்ககத்தில் கோப்புகள் மற்றும் ஆவணங்களுக்கான மெட்டாடேட்டாவைக் காண்க</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.readonly\">உங்கள் Google இயக்ககத்தில் கோப்புகள் மற்றும் ஆவணங்களைக் காண்க</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_structuredcontent\">சாப்பிங் உள்ளடக்க பநிஇ க்கான அணுகலைப் படிக்கவும்/எழுதவும்.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue.consumer\">உங்கள் பணிப்பகுதிகளில் இருந்து பணிகளை உட்கொள்ளுங்கள்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks\">உங்கள் பணிகளை நிர்வகிக்கவும்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks.readonly\">உங்கள் பணிகளைக் காண்க</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tracks\">கூகிள் மேப்ச் பநிஇ கண்காணிக்கிறது, இந்த நோக்கம் உங்கள் திட்டத்தின் தரவைப் படிக்கவும் எழுதவும் அனுமதிக்கிறது.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_urlshortener\">உங்கள் goo.gl குறுகிய முகவரி களை நிர்வகிக்கவும்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.email\">உங்கள் மின்னஞ்சல் முகவரியைக் காண்க</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.profile\">உங்கள் கணக்கைப் பற்றிய அடிப்படை தகவல்களைக் காண்க</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube\">உங்கள் YouTube கணக்கை நிர்வகிக்கவும்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtubepartner\">YouTube இல் உங்கள் சொத்துக்கள் மற்றும் அதனுடன் தொடர்புடைய உள்ளடக்கத்தைக் காணலாம் மற்றும் நிர்வகிக்கவும்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.readonly\">உங்கள் YouTube கணக்கைக் காண்க</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.upload\">உங்கள் YouTube வீடியோக்களை நிர்வகிக்கவும்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics_monetary.readonly\">உங்கள் YouTube உள்ளடக்கத்திற்கான யூடியூப் அனலிட்டிக்ச் நாணய அறிக்கைகளைக் காண்க</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics.readonly\">உங்கள் YouTube உள்ளடக்கத்திற்கான YouTube Analytics அறிக்கைகளைக் காண்க</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.compose\">வரைவுகளை உருவாக்கவும், படிக்கவும், புதுப்பிக்கவும், நீக்கவும். செய்திகள் மற்றும் வரைவுகளை அனுப்பவும்.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.modify\">உடனடி, நூல்கள் மற்றும் செய்திகளை நிரந்தரமாக நீக்குதல், குப்பைகளைத் தவிர்த்து, அனைத்து படிக்க/எழுதும் செயல்பாடுகளும்.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.readonly\">எல்லா வளங்களையும் அவற்றின் மெட்டாடேட்டாவையும் படியுங்கள் - எந்த எழுதும் நடவடிக்கைகளும் இல்லை.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.best\">உங்கள் சிறந்த கிடைக்கக்கூடிய இருப்பிடம் மற்றும் இருப்பிட வரலாற்றை நிர்வகிக்கவும்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.city\">உங்கள் நகர அளவிலான இருப்பிடம் மற்றும் இருப்பிட வரலாற்றை நிர்வகிக்கவும்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.best\">உங்கள் சிறந்த கிடைக்கக்கூடிய இடத்தை நிர்வகிக்கவும்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.city\">உங்கள் நகர அளவிலான இருப்பிடத்தை நிர்வகிக்கவும்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine\">உங்கள் Google MAPS இயந்திர தரவைக் காணலாம் மற்றும் நிர்வகிக்கவும்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine.readonly\">உங்கள் Google MAPS இயந்திர தரவைக் காண்க</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mobilemaps.firstparty\">மொபைல் அனுபவத்திற்காக உங்கள் Google வரைபடங்களைக் காணலாம் மற்றும் நிர்வகிக்கவும்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut\">உங்கள் ஓர்குட் செயல்பாட்டை நிர்வகிக்கவும்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut.readonly\">உங்கள் ஓர்குட் தரவைக் காண்க</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.login\">Google+ இல் நீங்கள் இணைக்கப்பட்ட நபர்களின் பெயர், அடிப்படை செய்தி மற்றும் பட்டியலை அறிந்து கொள்ளுங்கள்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.me\">கூகிளில் நீங்கள் யார் என்பதை அறிந்து கொள்ளுங்கள்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_prediction\">Google முன்கணிப்பு பநிஇ இல் உங்கள் தரவை நிர்வகிக்கவும்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_shoppingapi\">உங்கள் தயாரிப்பு தரவைக் காண்க</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification\">நீங்கள் கட்டுப்படுத்தும் தளங்கள் மற்றும் களங்களின் பட்டியலை நிர்வகிக்கவும்</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification.verify_only\">உங்கள் புதிய தள சரிபார்ப்பை Google உடன் நிர்வகிக்கவும்</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-ta/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <plurals name=\"pref_unifiednlp_summary\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> பின்தளத்தில் கட்டமைக்கப்பட்டுள்ளது</item>\n        <item quantity=\"other\"><xliff:g example=\"3\">%1$d</xliff:g> பின்தளங்கலில் கட்டமைக்கப்பட்டுள்ளது</item>\n    </plurals>\n    <plurals name=\"gcm_registered_apps_counter\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> பதிவு செய்யப்பட்ட பயன்பாடு</item>\n        <item quantity=\"other\"><xliff:g example=\"123\">%1$d</xliff:g> பதிவு செய்யப்பட்ட பயன்பாடுகள்</item>\n    </plurals>\n    <plurals name=\"cond_perm_summary\">\n        <item quantity=\"one\">நுண்சீ சேவைகளின் சரியான செயல்பாட்டிற்கு தேவையான இசைவு வழங்கப்படவில்லை.</item>\n        <item quantity=\"other\">நுண்சீ சேவைகளின் சரியான செயல்பாட்டிற்கு தேவையான இசைவுகள் வழங்கப்படவில்லை.</item>\n    </plurals>\n    <plurals name=\"cond_perm_action\">\n        <item quantity=\"one\">காணாமல் போன இசைவு கோருங்கள்</item>\n        <item quantity=\"other\">காணாமல் போன இசைவுகளைக் கோருங்கள்</item>\n    </plurals>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-ta/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=\"gms_app_name\">மைக்ரோ சேவைகள்</string>\n    <string name=\"limited_services_app_name\">மைக்ரோக் வரையறுக்கப்பட்ட சேவைகள்</string>\n    <string name=\"gms_settings_name\">மைக்ரோ அமைப்புகள்</string>\n    <string name=\"gms_settings_summary\">மைக்ரோக் சேவைகளை அமைக்கவும்.</string>\n    <string name=\"just_a_sec\">ஒரு நொடி…</string>\n    <string name=\"google_account_label\">கூகிள்</string>\n    <string name=\"auth_action_step_completed_content_description\">படி முடிந்தது</string>\n    <string name=\"auth_action_activity_finish\">முடிக்க</string>\n    <string name=\"signin_picker_title\">ஒரு கணக்கைத் தேர்வுசெய்க</string>\n    <string name=\"signin_picker_add_account_label\">மற்றொரு கணக்கைச் சேர்க்கவும்</string>\n    <string name=\"signin_confirm_button_text\">அனுமதிக்கவும் பகிரவும்</string>\n    <string name=\"games_info_content\">பிளே கேம்களைப் பயன்படுத்த கூகிள் பிளே கேம்ச் பயன்பாட்டை நிறுவ வேண்டும். விளையாட்டு விளையாட்டுகள் இல்லாமல் பயன்பாடு தொடரக்கூடும், ஆனால் அது எதிர்பாராத விதமாக நடந்து கொள்ளும்.</string>\n    <string name=\"pick_place_title\">ஒரு இடத்தைத் தேர்ந்தெடுங்கள்</string>\n    <string name=\"pick_place_desc\">இடம் எடுப்பவர் இன்னும் கிடைக்கவில்லை.</string>\n    <string name=\"place_picker_select_title\">இந்த இருப்பிடத்தைத் தேர்ந்தெடுக்கவும்</string>\n    <string name=\"place_picker_nearby_places\">அருகிலுள்ள இடங்கள்</string>\n    <string name=\"prefcat_about\">பற்றி</string>\n    <string name=\"pref_device_registration_android_id\">ஆண்ட்ராய்டு ஐடி</string>\n    <string name=\"checkin_enable_switch\">சாதனம் பதிவு செய்யுங்கள்</string>\n    <string name=\"pref_info_status\">நிலை</string>\n    <string name=\"pref_more_settings\">மேலும்</string>\n    <string name=\"pref_accounts_title\">கூகிள் கணக்குகள்</string>\n    <string name=\"pref_accounts_summary\">கூகிள் கணக்குகளைச் சேர்த்து நிர்வகிக்கவும்</string>\n    <string name=\"prefcat_accounts_settings_title\">அமைப்புகள்</string>\n    <string name=\"prefcat_accounts_current_accounts_title\">கணக்குகள்</string>\n    <string name=\"gcm_no_message_yet\">இதுவரை எந்த செய்திகளும் கிடைக்கவில்லை</string>\n    <string name=\"gcm_registered\">பதிவுசெய்யப்பட்டது</string>\n    <string name=\"profile_name_auto\">தானியங்கி: %s</string>\n    <string name=\"profile_name_system\">அமைப்பு: %s</string>\n    <string name=\"pref_device_registration_import_custom_profile_title\">தனிப்பயன் சுயவிவரத்தை இறக்குமதி செய்க</string>\n    <string name=\"pref_device_registration_serial_title\">தொடர்</string>\n    <string name=\"pref_device_registration_import_custom_profile_summary\">கோப்பிலிருந்து சாதன சுயவிவரத்தை இறக்குமதி செய்யுங்கள்</string>\n    <string name=\"pref_device_registration_select_profile_title\">சுயவிவரத்தைத் தேர்ந்தெடுக்கவும்</string>\n    <string name=\"pref_safetynet_recent_eval_type\">மதிப்பீட்டு வகை</string>\n    <string name=\"pref_safetynet_recent_response_status\">மறுமொழி நிலை</string>\n    <string name=\"pref_safetynet_recent_cat_response\">மறுமொழி தரவு</string>\n    <string name=\"pref_safetynet_recent_cat_request\">தரவைக் கோருங்கள்</string>\n    <string name=\"pref_safetynet_recent_nonce\">அல்லாத (எக்ச்)</string>\n    <string name=\"pref_safetynet_recent_request_time\">கோரிக்கையின் நேரம்</string>\n    <string name=\"pref_safetynet_recent_request_type\">கோரிக்கை வகை</string>\n    <string name=\"pref_safetynet_recent_cat_basic\">அடிப்படை தரவு</string>\n    <string name=\"pref_safetynet_recent_token\">கிள்ளாக்கு</string>\n    <string name=\"pref_safetynet_recent_copied\">இடைநிலைப்பலகைக்கு நகலெடுக்கப்பட்டது!</string>\n    <string name=\"pref_vending_summary_licensing_on\">உரிமம்</string>\n    <string name=\"pref_vending_licensing_category\">கூகிள் பிளே உரிமம்</string>\n    <string name=\"pref_vending_licensing_enable_switch\">உரிம சரிபார்ப்பு கோரிக்கைகளுக்கு பதில்</string>\n    <string name=\"pref_vending_license_enable_summary\">சில பயன்பாடுகளுக்கு நீங்கள் அவற்றை Google Play இல் வாங்கிய சரிபார்ப்பு தேவைப்படுகிறது. பயன்பாட்டால் கோரப்பட்டால், மைக்ரோக் கூகிளிலிருந்து வாங்குவதற்கான ஆதாரத்தை பதிவிறக்கம் செய்யலாம். முடக்கப்பட்டால், அல்லது கூகிள் கணக்கு எதுவும் சேர்க்கப்படாவிட்டால், உரிம சரிபார்ப்புக்கான கோரிக்கைகள் புறக்கணிக்கப்படும்.</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_switch\">இலவச பயன்பாடுகளை நூலகத்தில் தானாக சேர்க்கவும்</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_summary\">கூகிள் பிளேயில் இருந்து பதிவிறக்கம் செய்யப்பட்டுள்ளதா என்பதை இலவச பயன்பாடுகள் சரிபார்க்கலாம். தற்போது உங்களுக்கு கிடைக்கக்கூடிய அனைத்து இலவச பயன்பாடுகளையும் காசோலையை எப்போதும் அனுப்ப உங்கள் கணக்கு நூலகத்தில் இலவச பயன்பாடுகளை தானாக சேர்க்கவும்.</string>\n    <string name=\"feedback_disabled\">கருத்து தற்போது சாத்தியமில்லை</string>\n    <string name=\"backup_disabled\">காப்புப்பிரதி தற்போது சாத்தியமில்லை</string>\n    <string name=\"pref_vending_billing_category\">கூகிள் ப்ளே பட்டியலிடல்</string>\n    <string name=\"pref_vending_billing_enable_switch\">பட்டியலிடல் கோரிக்கைகளைக் கையாளவும்</string>\n    <string name=\"pref_vending_billing_enable_summary\">இயக்கப்பட்டதும், சில பயன்பாடுகள் கூகிள் பிளே பட்டியலிடல் பணி மூலம் வாங்குவதை முடிக்கலாம் அல்லது தொடங்கலாம்.</string>\n    <string name=\"credentials_assisted_continue_as_user_button_label\">%1$s ஆக தொடரவும்</string>\n    <string name=\"credentials_assisted_sign_back_title\">கூகிள் மூலம் %1$s க்கு மீண்டும் உள்நுழைக</string>\n    <string name=\"credentials_assisted_signin_description\">உங்கள் Google கணக்குகளில் Google உடன் உள்நுழையலாம்.</string>\n    <string name=\"credentials_assisted_choose_account_label\">கணக்கைத் தேர்வுசெய்க</string>\n    <string name=\"credentials_assisted_choose_account_subtitle\">%1$s தொடர</string>\n    <string name=\"credentials_assisted_signin_button_text_long\">Google உடன் உள்நுழைக</string>\n    <string name=\"games_snapshot_delete_btn_text\">நீக்கு</string>\n    <string name=\"games_delete_snapshot_dialog_title\">சேமித்த விளையாட்டை நீக்கு</string>\n    <string name=\"games_delete_snapshot_dialog_message\">இந்த சேமித்த விளையாட்டை நீக்க விரும்புகிறீர்களா?</string>\n    <string name=\"games_delete_snapshot_dialog_cancel\">ரத்துசெய்</string>\n    <string name=\"games_delete_snapshot_dialog_ok\">சரி</string>\n    <string name=\"games_delete_snapshot_error\">நீக்குதல் தோல்வியடைந்தது, தயவுசெய்து பின்னர் மீண்டும் முயற்சிக்கவும்</string>\n    <string name=\"self_check_name_system_spoofs\">கணினி ஏமாற்று கையொப்பம்:</string>\n    <string name=\"ask_permission_tos\">தொடர்வதன் மூலம், இந்த பயன்பாடு மற்றும் கூகிள் அந்தந்த பணி விதிமுறைகள் மற்றும் தனியுரிமைக் கொள்கைகளுக்கு ஏற்ப உங்கள் தகவல்களைப் பயன்படுத்த அனுமதிக்கிறீர்கள்.</string>\n    <string name=\"account_manager_title\">கூகிள் கணக்கு மேலாளர்</string>\n    <string name=\"sorry\">மன்னிக்கவும்…</string>\n    <string name=\"auth_before_connect\">உங்கள் சாதனத்தில் ஒரு பயன்பாடு Google கணக்கில் உள்நுழைய முயற்சிக்கிறது.\\n\\n இது வேண்டுமென்றே இருந்தால், கூகிளின் உள்நுழைவு பக்கத்துடன் இணைக்க <b> உள்நுழைவு </b> பொத்தானைப் பயன்படுத்தவும், இல்லையென்றால், இந்த உரையாடலைக் காண்பிக்கும் பயன்பாட்டிற்குச் செல்ல <b> ரத்து </b> ஐ அழுத்தவும்.</string>\n    <string name=\"auth_sign_in\">விடுபதிகை</string>\n    <string name=\"auth_connecting\">உங்களை கையொப்பமிட Google இன் சேவையகங்களுக்கான இணைப்பை உங்கள் சாதனம் நிறுவுகிறது.\\n\\n இதற்கு சில வினாடிகள் ஆகலாம்.</string>\n    <string name=\"no_network_error_desc\">உங்களிடம் பிணைய இணைப்பு இல்லை.\\n\\n இது ஒரு தற்காலிக சிக்கலாக இருக்கலாம் அல்லது தரவு சேவைகளுக்கு உங்கள் ஆண்ட்ராய்டு சாதனம் வழங்கப்படாமல் போகலாம். மொபைல் நெட்வொர்க்குடன் இணைக்கப்படும்போது மீண்டும் முயற்சிக்கவும் அல்லது வைஃபை நெட்வொர்க்குடன் இணைக்கவும்.</string>\n    <string name=\"auth_general_error_desc\">கூகிள் சேவையகங்களுடன் தொடர்புகொள்வதில் சிக்கல் இருந்தது.\\n\\n பின்னர் மீண்டும் முயற்சிக்கவும்.</string>\n    <string name=\"auth_finalize\">உங்கள் கணக்கில் தகவல்களைச் சேமிக்க உங்கள் சாதனம் Google ஐ தொடர்பு கொள்கிறது.\\n\\n இதற்கு இரண்டு நிமிடங்கள் ஆகலாம்.</string>\n    <string name=\"allow\">இசைவு</string>\n    <string name=\"deny\">மறுக்கவும்</string>\n    <string name=\"auth_notification_title\">ஏற்பு தேவை</string>\n    <string name=\"auth_action_notification_channel_name\">கூகிள் கணக்கு விழிப்பூட்டல்கள்</string>\n    <string name=\"auth_action_notification_channel_description\">உங்கள் Google கணக்குகளில் ஒன்றைப் பயன்படுத்துவதற்கு முன்பு கூடுதல் அமைப்பு தேவைப்படும்போது அல்லது மைக்ரோசுடன் ஒரு கணக்கு பொருந்தாதபோது அறிவிக்கிறது.</string>\n    <string name=\"auth_action_notification_title\">கணக்கு நடவடிக்கை தேவை</string>\n    <string name=\"auth_action_notification_content\">உங்கள் Google கணக்கில் கூடுதல் அமைப்பு தேவை.</string>\n    <string name=\"auth_action_activity_header\">உங்கள் Google கணக்கை அமைப்பதை முடிக்கவும்</string>\n    <string name=\"auth_action_activity_explanation\">இந்த சாதனத்தில் உங்கள் Google கணக்கு %s ஐப் பயன்படுத்த பின்வரும் படிகளை முடிக்கவும்.</string>\n    <string name=\"auth_action_step_enable_checkin\">சாதன பதிவை இயக்கவும்</string>\n    <string name=\"auth_action_step_enable_checkin_description\">உங்கள் சாதனம் ஒரு முறையாவது Google இல் பதிவு செய்ய வேண்டும்.\\n\\n கணக்கு அமைவு முடிந்ததும் Google சாதன பதிவை முடக்கலாம்.</string>\n    <string name=\"auth_action_step_enable_gcm\">முகில் செய்தியை இயக்கவும்</string>\n    <string name=\"auth_action_step_enable_gcm_description\">கணக்கு அமைவு முடிந்ததும் நீங்கள் முகில் செய்தியை முடக்கலாம்.</string>\n    <string name=\"auth_action_step_allow_microg_gcm\">மைக்ரோக்கிற்கு முகில் செய்தியை அனுமதிக்கவும்</string>\n    <string name=\"auth_action_step_allow_microg_gcm_description\">உங்கள் விருப்பங்களின்படி, மேகக்கணி செய்திக்கு தன்னை பதிவு செய்வதற்கு முன்பு மைக்ரோக்கிற்கு இசைவு தேவை.</string>\n    <string name=\"auth_action_step_enable_lockscreen\">பாதுகாப்பான திரை பூட்டை உள்ளமைக்கவும்</string>\n    <string name=\"auth_action_step_enable_lockscreen_description\">உங்கள் Google கணக்கு உங்கள் பணியிடம் அல்லது கல்வி நிறுவனத்தால் நிர்வகிக்கப்படுகிறது. கணக்குத் தரவை அணுகுவதற்கு முன்பு சாதனங்களுக்கு பாதுகாப்பான திரை பூட்டு தேவை என்று உங்கள் நிர்வாகி முடிவு செய்தார்.\\n\\n கடவுச்சொல், முள் அல்லது முறை பூட்டுத் திரையை அமைக்கவும்.</string>\n    <string name=\"auth_action_step_perform_content_description\">படி செய்ய சொடுக்கு செய்க</string>\n    <string name=\"signin_subtext_policy\">இந்த பயன்பாட்டைப் பயன்படுத்துவதற்கு முன், அதன் %1$s மற்றும் %2$s ஐ மதிப்பாய்வு செய்யவும்.</string>\n    <string name=\"signin_subtext_policy_privacy\">தனியுரிமைக் கொள்கை</string>\n    <string name=\"signin_subtext_policy_terms\">பணி விதிமுறைகள்</string>\n    <string name=\"perm_status_broadcast_label\">உள் நிலை ஒளிபரப்புகளைக் கேளுங்கள்</string>\n    <string name=\"perm_gsf_read_gservices_label\">Google பணி உள்ளமைவைப் படியுங்கள்</string>\n    <string name=\"perm_c2dm_receive_label\">C2DM செய்திகளைக் கேளுங்கள்</string>\n    <string name=\"perm_c2dm_send_label\">பிற பயன்பாடுகளுக்கு C2DM செய்திகளை அனுப்பவும்</string>\n    <string name=\"perm_gtalk_svc_label\">கூகிள் சேவையகங்களிலிருந்து செய்திகளை பரிமாறிக்கொண்டு ஒத்திசைவு அறிவிப்புகளைப் பெறுங்கள்</string>\n    <string name=\"pref_device_registration_device_profile_category\">சாதன சுயவிவரம்</string>\n    <string name=\"pref_safetynet_recent_uses\">அண்மைக் கால பயன்பாடுகள்</string>\n    <string name=\"pref_safetynet_recent_attestation_summary\">சான்றளிப்பு: %s</string>\n    <string name=\"pref_safetynet_recent_recaptcha_summary\">Recaptcha: %s</string>\n    <string name=\"pref_safetynet_recent_recaptcha_enterprise_summary\">ரெக்காப்ட்சா எண்டர்பிரைச்: %s</string>\n    <string name=\"pref_safetynet_recent_copy_json\">சாதொபொகு JWS தரவை நகலெடுக்கவும்</string>\n    <string name=\"pref_safetynet_recent_advice\">அறிவுரை</string>\n    <string name=\"pref_safetynet_test_integrity_cts_passed\">ஒருமைப்பாடு மற்றும் சி.டி.எச் கடந்துவிட்டன</string>\n    <string name=\"pref_safetynet_test_cts_failed\">சி.டி.எச் தோல்வியுற்றது</string>\n    <string name=\"pref_safetynet_test_integrity_failed\">நேர்மை தோல்வியடைந்தது</string>\n    <string name=\"pref_safetynet_test_not_completed\">இன்னும் முடிக்கப்படவில்லை</string>\n    <string name=\"pref_safetynet_test_no_result\">முடிவு இல்லை</string>\n    <string name=\"perm_extended_access_label\">Google சேவைகளுக்கான நீட்டிக்கப்பட்ட அணுகல்</string>\n    <string name=\"perm_provision_label\">வழங்கல் மைக்ரோக் சேவைகள்</string>\n    <string name=\"perm_provision_description\">பயனர் தொடர்பு இல்லாமல் மைக்ரோசி சேவைகளை உள்ளமைக்க பயன்பாட்டை அனுமதிக்கிறது</string>\n    <string name=\"perm_car_speed_label\">கார் விரைவு</string>\n    <string name=\"perm_car_speed_description\">உங்கள் காரின் வேகத்தை அணுகவும்</string>\n    <string name=\"perm_car_info_label\">கார் செய்தி</string>\n    <string name=\"perm_car_info_description\">உங்கள் காரின் தகவலை அணுகவும்</string>\n    <string name=\"perm_car_fuel_label\">கார் எரிபொருள் நிலை</string>\n    <string name=\"perm_car_fuel_description\">உங்கள் காரின் எரிபொருள் நிலை தகவல்களை அணுகவும்</string>\n    <string name=\"perm_car_mileage_label\">கார் மைலேச்</string>\n    <string name=\"perm_car_mileage_description\">உங்கள் காரின் மைலேச் தகவலை அணுகவும்</string>\n    <string name=\"perm_car_vendor_extension_label\">கார் விற்பனையாளர் சேனல்</string>\n    <string name=\"perm_car_vendor_extension_description\">கார் சார்ந்த தகவல்களை பரிமாறிக்கொள்ள உங்கள் காரின் விற்பனையாளர் சேனலை அணுகவும்</string>\n    <string name=\"service_name_checkin\">கூகிள் சாதன பதிவு</string>\n    <string name=\"service_name_mcs\">முகில் செய்தி</string>\n    <string name=\"service_name_snet\">Google SafeTynet</string>\n    <string name=\"service_name_vending\">கடை சேவைகளை விளையாடுங்கள்</string>\n    <string name=\"games_title\">கூகிள் பிளே கேம்கள்</string>\n    <string name=\"network_type_mobile\">மொபைல் பிணையம்</string>\n    <string name=\"network_type_wifi\">இல்</string>\n    <string name=\"network_type_roaming\">ரோமிங்</string>\n    <string name=\"network_type_other\">பிற நெட்வொர்க்குகள்</string>\n    <string name=\"self_check_cat_fake_sig\">கையொப்பம் ச்பூஃபிங் உதவி</string>\n    <string name=\"self_check_cat_gms_packages\">நிறுவப்பட்ட தொகுப்புகள்</string>\n    <string name=\"self_check_cat_system\">மண்டலம்</string>\n    <string name=\"self_check_name_fake_sig_perm\">கணினியில் கையொப்பம் ச்பூஃபிங் உதவி உள்ளது:</string>\n    <string name=\"self_check_resolution_fake_sig_perm\">கையொப்பம் ச்பூஃபிங்கிற்கு உங்கள் ரோமுக்கு சொந்த உதவி இல்லை. கையொப்பத்தை ஏமாற்றுவதற்கு நீங்கள் இன்னும் எக்ச்போச் அல்லது பிற அமைப்புகளைப் பயன்படுத்தலாம். எந்த ROM கள் கையொப்பம் ச்பூஃபிங்கை ஆதரிக்கின்றன என்பதையும், செய்யாத ROM களில் மைக்ரோக்கை எவ்வாறு பயன்படுத்துவது என்பதையும் சரிபார்க்கவும்.</string>\n    <string name=\"self_check_name_perm_granted\">கணினி கையொப்பம் ச்பூஃபிங் அனுமதி:</string>\n    <string name=\"self_check_resolution_perm_granted\">ரோம் கையொப்பம் ச்பூஃபிங்கை ஆதரிக்கிறது என்பதற்கான வலுவான குறிகாட்டியாகும், ஆனால் அதைச் செயல்படுத்த கூடுதல் நடவடிக்கை தேவைப்படுகிறது. எந்த படிகள் தேவைப்படலாம் என்று ஆவணங்களை சரிபார்க்கவும்.</string>\n    <string name=\"self_check_name_battery_optimizations\">பேட்டரி மேம்படுத்தல்கள் புறக்கணிக்கப்பட்டன:</string>\n    <string name=\"self_check_resolution_battery_optimizations\">பேட்டரி தேர்வுமுறை முடக்க இங்கே தொடவும். இதைச் செய்யாதது தவறான பயன்பாட்டை ஏற்படுத்தக்கூடும்.</string>\n    <string name=\"prefcat_components\">கூறுகள்</string>\n    <string name=\"prefcat_configuration\">உள்ளமைவு</string>\n    <string name=\"prefcat_google_services\">கூகிள் சேவைகள்</string>\n    <string name=\"prefcat_location_service\">இருப்பிட பணி</string>\n    <string name=\"self_check_resolution_system_spoofs\">எந்த படிகள் தேவைப்படலாம் என்று ஆவணங்களை சரிபார்க்கவும்.</string>\n    <string name=\"self_check_pkg_gms\">மைக்ரோஜி சேவைகள்</string>\n    <string name=\"self_check_pkg_vending\">மைக்ரோஜி கம்பானியன் / ப்ளே ஸ்டோர்</string>\n    <string name=\"self_check_pkg_gsf\">மைக்ரோஜி சேவைகள் கட்டமைப்பு</string>\n    <string name=\"prefcat_services\">சேவைகள்</string>\n    <string name=\"prefcat_test\">தேர்வு</string>\n    <string name=\"cond_gcm_bat_title\">பேட்டரி மேம்படுத்தல்கள் இயக்கப்பட்டன</string>\n    <string name=\"cond_gcm_bat_summary\">நீங்கள் முகில் செய்தியிடலை இயக்கியுள்ளீர்கள், ஆனால் மைக்ரோக் சேவைகளுக்கு பேட்டரி மேம்படுத்தல்கள் செயலில் உள்ளன. புச் அறிவிப்புகள் வருவதற்கு நீங்கள் பேட்டரி மேம்படுத்தல்களை புறக்கணிக்க வேண்டும்.</string>\n    <string name=\"cond_gcm_bat_action\">மேம்படுத்தல்களை புறக்கணிக்கவும்</string>\n    <string name=\"cond_perm_title\">இசைவு இல்லை</string>\n    <string name=\"prefs_account\">கணக்கு விருப்பத்தேர்வுகள்</string>\n    <string name=\"prefs_account_privacy\">தனிப்பட்ட செய்தி மற்றும் தனியுரிமை</string>\n    <string name=\"prefs_account_security\">உள்நுழைவு &amp; பாதுகாப்பு</string>\n    <string name=\"pref_auth_trust_google_title\">பயன்பாட்டு அனுமதிகளுக்கு கூகிளை நம்புங்கள்</string>\n    <string name=\"pref_auth_trust_google_summary\">முடக்கப்பட்டபோது, பயன்பாட்டின் அங்கீகார கோரிக்கை Google க்கு அனுப்பப்படுவதற்கு முன்பு பயனர் கேட்கப்படுகிறார். இது முடக்கப்பட்டால் சில பயன்பாடுகள் Google கணக்கைப் பயன்படுத்தத் தவறும்.</string>\n    <string name=\"pref_auth_visible_title\">கணக்குகளைக் கண்டுபிடிக்க பயன்பாடுகளை அனுமதிக்கவும்</string>\n    <string name=\"pref_auth_visible_summary\">இயக்கப்பட்டால், இந்த சாதனத்தில் உள்ள அனைத்து பயன்பாடுகளும் முன் அங்கீகாரமின்றி உங்கள் Google கணக்குகளின் மின்னஞ்சல் முகவரியைக் காண முடியும்.</string>\n    <string name=\"pref_auth_include_android_id_title\">சாதன பதிவுடன் அங்கீகரிக்கவும்</string>\n    <string name=\"pref_auth_include_android_id_summary\">முடக்கப்பட்டால், அங்கீகார கோரிக்கைகள் சாதன பதிவுடன் இணைக்கப்படாது, இது அங்கீகரிக்கப்படாத சாதனங்களை உள்நுழைய அனுமதிக்கும், ஆனால் எதிர்பாராத விளைவுகளை ஏற்படுத்தக்கூடும்.</string>\n    <string name=\"pref_auth_strip_device_name_title\">அங்கீகாரத்திற்கான சாதனத்தின் பெயர்</string>\n    <string name=\"pref_auth_strip_device_name_summary\">இயக்கப்பட்டால், அங்கீகார கோரிக்கைகளில் சாதனத்தின் பெயரை சேர்க்காது, இது அங்கீகரிக்கப்படாத சாதனங்களை உள்நுழைய அனுமதிக்கும், ஆனால் எதிர்பாராத விளைவுகளை ஏற்படுத்தக்கூடும்.</string>\n    <string name=\"pref_checkin_enable_summary\">உங்கள் சாதனத்தை Google சேவைகளில் பதிவுசெய்து தனித்துவமான சாதன அடையாளங்காட்டியை உருவாக்குகிறது. பதிவு தரவுகளிலிருந்து உங்கள் Google கணக்கு பெயரைத் தவிர வேறு பிட்களை அடையாளம் காணும் மைக்ரோ ச்ட்ரிப்ச்.</string>\n    <string name=\"checkin_not_registered\">பதிவு செய்யப்படவில்லை</string>\n    <string name=\"pref_add_account_title\">கணக்கு</string>\n    <string name=\"pref_add_account_summary\">Google கணக்கைச் சேர்க்கவும்</string>\n    <string name=\"pref_gcm_enable_mcs_summary\">முகில் மெசேசிங் என்பது பல மூன்றாம் தரப்பு பயன்பாடுகளால் பயன்படுத்தப்படும் புச் அறிவிப்பு வழங்குநராகும். இதைப் பயன்படுத்த நீங்கள் சாதன பதிவை இயக்க வேண்டும்.</string>\n    <string name=\"pref_gcm_heartbeat_title\">முகில் செய்தியிடல் இதய துடிப்பு இடைவெளி</string>\n    <string name=\"pref_gcm_heartbeat_summary\">கூகிள் சேவையகங்களை இதய துடிப்புக்கான அமைப்புக்கான நொடிகளில் இடைவெளி. இந்த எண்ணிக்கையை அதிகரிப்பது பேட்டரி நுகர்வு குறைக்கும், ஆனால் புச் செய்திகளில் தாமதத்தை ஏற்படுத்தக்கூடும்.\\n எதிர்கால வெளியீட்டில் மாற்றப்படும்.</string>\n    <string name=\"pref_gcm_apps_title\">முகில் செய்தியைப் பயன்படுத்தும் பயன்பாடுகள்</string>\n    <string name=\"pref_gcm_apps_summary\">முகில் செய்திக்கு தற்போது பதிவு செய்யப்பட்டுள்ள பயன்பாடுகளின் பட்டியல்.</string>\n    <string name=\"pref_gcm_confirm_new_apps_title\">புதிய பயன்பாடுகளை உறுதிப்படுத்தவும்</string>\n    <string name=\"gcm_unregister_app\">பதிவு செய்யப்படாதது</string>\n    <string name=\"pref_gcm_confirm_new_apps_summary\">புச் அறிவிப்புகளைப் பெற புதிய பயன்பாட்டை பதிவு செய்வதற்கு முன் கேளுங்கள்</string>\n    <string name=\"pref_about_title\">மைக்ரோக் சேவைகள் பற்றி</string>\n    <string name=\"pref_about_summary\">பதிப்பு செய்தி மற்றும் பயன்படுத்தப்பட்ட நூலகங்கள்</string>\n    <string name=\"gcm_app_error_unregistering\">பதிவு செய்யாத பிழை</string>\n    <string name=\"gcm_app_not_installed_anymore\">இனி நிறுவப்படவில்லை</string>\n    <string name=\"gcm_not_registered\">பதிவு செய்யப்படவில்லை</string>\n    <string name=\"gcm_unregister_confirm_message\">சில பயன்பாடுகள் தானாக மீண்டும் பதிவு செய்யாது மற்றும்/அல்லது கைமுறையாக அவ்வாறு செய்ய ஒரு விருப்பத்தை வழங்காது. பதிவு செய்யப்படாத பிறகு இந்த பயன்பாடுகள் சரியாக வேலை செய்யாது.\\n தொடரவா?</string>\n    <string name=\"gcm_unregister_after_deny_message\">ஏற்கனவே பதிவுசெய்யப்பட்ட புச் அறிவிப்புகளுக்கு பதிவு செய்ய ஒரு பயன்பாட்டை மறுத்தீர்கள்.\\n எதிர்காலத்தில் புச் செய்திகளைப் பெறாததால் இப்போது அதை பதிவு செய்ய விரும்புகிறீர்களா?</string>\n    <string name=\"gcm_network_state_disconnected\">துண்டிக்கப்பட்டது</string>\n    <string name=\"gcm_enable_switch\">புச் அறிவிப்புகளைப் பெறுங்கள்</string>\n    <string name=\"pref_push_app_allow_register_title\">பதிவு செய்ய அனுமதிக்கவும்</string>\n    <string name=\"pref_push_app_allow_register_summary\">புச் அறிவிப்புகளுக்கு பயன்பாட்டை பதிவு செய்ய அனுமதிக்கவும்.</string>\n    <string name=\"pref_push_app_wake_for_delivery_title\">புச் செய்தியில் பயன்பாட்டைத் தொடங்கவும்</string>\n    <string name=\"pref_push_app_wake_for_delivery_summary\">உள்வரும் புச் செய்திகளைப் பெற பின்னணியில் இருக்கும்போது பயன்பாட்டைத் தொடங்கவும்.</string>\n    <string name=\"prefcat_push_apps_title\">புச் அறிவிப்புகளைப் பயன்படுத்தும் பயன்பாடுகள்</string>\n    <string name=\"prefcat_push_apps_registered_title\">பதிவுசெய்யப்பட்ட பயன்பாடுகள்</string>\n    <string name=\"prefcat_push_apps_unregistered_title\">பதிவு செய்யப்படாத பயன்பாடுகள்</string>\n    <string name=\"prefcat_push_networks_title\">புச் அறிவிப்புகளுக்கு பயன்படுத்த நெட்வொர்க்குகள்</string>\n    <string name=\"safetynet_intro\">Google SafeTynet ஒரு சாதன சான்றிதழ் அமைப்பாகும், இது சாதனம் சரியாகப் பாதுகாக்கப்பட்டு ஆண்ட்ராய்டு CTS உடன் இணக்கமானது என்பதை உறுதி செய்கிறது. சில பயன்பாடுகள் பாதுகாப்பு காரணங்களுக்காகவோ அல்லது சேதத்தை பாதுகாப்பதற்கான முன்நிபந்தனையாகவோ SafeTynet ஐப் பயன்படுத்துகின்றன.\\n\\n மைக்ரோக் சி.எம்.கே.ஓ.ஓ.</string>\n    <string name=\"safetynet_enable_switch\">சாதன சான்றிதழ் அனுமதிக்கவும்</string>\n    <string name=\"pref_safetynet_test_title\">சோதனை பாதுகாப்பான சான்றிதழ்</string>\n    <string name=\"pref_recaptcha_test_title\">சோதனை ரெக்காப்ட்சா</string>\n    <string name=\"pref_recaptcha_enterprise_test_title\">டெச்ட் ரெக்காப்ட்சா எண்டர்பிரைச்</string>\n    <string name=\"pref_test_summary_passed\">அனைத்து சோதனைகளையும் நிறைவேற்றியது</string>\n    <string name=\"profile_name_native\">பழமை</string>\n    <string name=\"profile_name_real\">உண்மையான</string>\n    <string name=\"pref_test_summary_failed\">தோல்வியுற்றது: %s</string>\n    <string name=\"pref_test_summary_warn\">எச்சரிக்கை: %s</string>\n    <string name=\"pref_test_summary_running\">ஓடுகிறது…</string>\n    <string name=\"pref_droidguard_operation_mode\">செயல்பாட்டு பயன்முறை</string>\n    <string name=\"profile_name_user\">தனிப்பயன்: %s</string>\n    <string name=\"credentials_assisted_signin_consent_header\">%1$s ஆக கையொப்பமிடுதல்</string>\n    <string name=\"credentials_assisted_signin_consent\">தொடர்வதன் மூலம், கூகிள் உங்கள் பெயர், மின்னஞ்சல் முகவரி மற்றும் சுயவிவரப் படத்தை %1$s உடன் பகிர்ந்து கொள்ளும். %1$s இன் தனியுரிமைக் கொள்கை மற்றும் பணி விதிமுறைகளைப் பார்க்கவும்.</string>\n    <string name=\"pref_droidguard_unsupported_summary\">இந்த சாதனத்தில் டிராய்ட்கார்ட் செயல்படுத்தல் ஆதரிக்கப்படவில்லை. SAFETYNET சேவைகள் தவறாக நடந்து கொள்ளலாம்.</string>\n    <string name=\"prefcat_safetynet_apps_title\">SafeTynet ஐப் பயன்படுத்தும் பயன்பாடுகள்</string>\n    <string name=\"menu_clear_recent_requests\">அண்மைக் கால கோரிக்கைகளை அழிக்கவும்</string>\n    <string name=\"pref_safetynet_test_invalid_json\">தவறான சாதொபொகு</string>\n    <string name=\"push_notifications_summary_off\">அணை</string>\n    <string name=\"push_notifications_summary_automatic\">ஆன் / தானியங்கி: %s</string>\n    <string name=\"push_notifications_summary_manual\">ஆன் / கையேடு: %s</string>\n    <string name=\"push_notifications_summary_values_seconds\">%s வினாடிகள்</string>\n    <string name=\"push_notifications_summary_values_minutes\">%s நிமிடங்கள்</string>\n    <string name=\"pref_vending_summary_licensing_off\">உரிமம் வழங்குதல்</string>\n    <string name=\"pref_vending_billing_note_experimental\">இந்த நற்பொருத்தம் சோதனை மற்றும் பணத்தை இழக்க வழிவகுக்கும். உங்களுக்கு எச்சரிக்கை விடுக்கப்பட்டுள்ளது.</string>\n    <string name=\"pref_vending_billing_note_licensing\">உங்கள் வாங்குதல்களைச் சரிபார்க்க உரிம சரிபார்ப்பை இயக்க சில பயன்பாடுகள் தேவைப்படலாம்.</string>\n    <string name=\"pref_vending_asset_delivery_category\">கூகிள் பிளே சொத்து டெலிவரி</string>\n    <string name=\"pref_vending_asset_delivery_switch\">தேவைக்கேற்ப சொத்து விநியோகத்தை இயக்கவும்</string>\n    <string name=\"pref_vending_asset_delivery_summary\">பிளே சொத்து விநியோகத்தைப் பயன்படுத்தும் பயன்பாடுகளால் கோரப்படும்போது கூடுதல் சொத்துக்களைப் பதிவிறக்கவும்</string>\n    <string name=\"pref_vending_asset_device_sync_summary\">பிளே சொத்து விநியோகத்தைப் பயன்படுத்தும் பயன்பாடுகள் தற்போது பயன்பாட்டில் உள்ள சாதனத்தின் தகவலின் அடிப்படையில் கூடுதல் சொத்துக்களை பதிவிறக்கும்.</string>\n    <string name=\"pref_vending_asset_device_sync_switch\">சாதன செய்தி ஒத்திசைவை இயக்கவும்</string>\n    <string name=\"credentials_assisted_cancel\">ரத்துசெய்</string>\n    <string name=\"credentials_assisted_continue\">தொடரவும்</string>\n    <string name=\"credentials_assisted_confirmation_header\">உங்களை கையொப்பமிடுவது</string>\n    <string name=\"limited_services_dialog_information\">நீங்கள் மைக்ரோக் வரையறுக்கப்பட்ட சேவைகளைப் பயன்படுத்துகிறீர்கள். வழக்கமான மைக்ரோக் சேவைகளைப் போலன்றி, இந்த சுவை மைக்ரோக் நூலகங்களைப் பயன்படுத்தும் பயன்பாடுகளுடன் மட்டுமே செயல்படுகிறது, கூகிள் பிளேயில் இல்லை. இதன் பொருள் பெரும்பாலான பயன்பாடுகள் இந்த சேவைகளை புறக்கணிக்கும்.</string>\n    <string name=\"limited_services_dialog_information_ack\">எனக்கு புரிகிறது</string>\n    <string name=\"games_achievement_list_title\">சாதனைகள்</string>\n    <string name=\"games_achievements_empty_text\">இந்த விளையாட்டுக்கான சாதனைகள் இல்லை</string>\n    <string name=\"games_achievement_extra_text\">%1$s xp</string>\n    <string name=\"games_api_access_denied\">இந்த சாதனத்தில் எந்த கணக்கும் கேம்ச் ஏபிஐகளை அணுக முடியாது</string>\n    <string name=\"games_achievement_locked_content_description\">பூட்டப்பட்டுள்ளது</string>\n    <string name=\"games_achievement_unlocked_content_description\">திறக்கப்பட்டது</string>\n    <string name=\"games_leaderboard_empty_text\">இந்த விளையாட்டுக்கு லீடர்போர்டுகள் இல்லை</string>\n    <string name=\"games_leaderboard_score_empty_text\">நம்பமுடியாதது! இந்த விளையாட்டுக்கு பொது அதிக மதிப்பெண்கள் இல்லை.</string>\n    <string name=\"games_leaderboard_list_title\">தரவரிசை</string>\n    <string name=\"games_leaderboards_score_label\">ச்கோர்: %1$s</string>\n    <string name=\"games_snapshot_empty_text\">எந்த விளையாட்டு சேமிப்புகளும் இன்னும் சேமிக்கப்படவில்லை</string>\n    <string name=\"games_snapshot_choose_btn_text\">தேர்ந்தெடு</string>\n    <string name=\"barcode_scanner_brand\">%1$s சார்பாக மைக்ரோக் மூலம் ச்கேன் செய்யப்பட்டது</string>\n    <string name=\"camera_permission_dialog_button\">சரி</string>\n    <string name=\"self_check_resolution_app_installed\">பயன்பாட்டை நிறுவவும் &lt;xliff: g எடுத்துக்காட்டு = \\\"f-droid\\\"&gt;%1$s &lt;/xliff: g&gt; அல்லது இணக்கமான ஒன்று. எந்த பயன்பாடுகள் இணக்கமானவை என்ற ஆவணங்களை சரிபார்க்கவும்.</string>\n    <string name=\"service_name_work_profile\">பணி சுயவிவரம்</string>\n    <string name=\"self_check_resolution_correct_sig\">நிறுவப்பட்ட &lt;xliff: g எடுத்துக்காட்டு = \\\"f-droid\\\"&gt;%1$s &lt;/xliff: g&gt; பொருந்தாது அல்லது கையொப்பம் ச்பூஃபிங் செயலில் இல்லை. பயன்பாடுகள் மற்றும் ROM கள் இணக்கமான ஆவணங்களை சரிபார்க்கவும்.</string>\n    <string name=\"self_check_name_correct_sig\">&lt;xliff: g எடுத்துக்காட்டு = \\\"f-droid\\\"&gt;%1$s &lt;/xliff: g&gt; சரியான கையொப்பத்தைக் கொண்டுள்ளது:</string>\n    <string name=\"gcm_unregister_confirm_title\">பதிவுசெய்தல் &lt;xliff: g எடுத்துக்காட்டு = \\\"f-droid\\\"&gt;%1$s &lt;/xliff: g&gt;?</string>\n    <string name=\"gcm_last_message_at\">கடைசி செய்தி: &lt;xliff: g எடுத்துக்காட்டு = \\\"நேற்று, 02:20 PM\\\"&gt;%1$s &lt;/xliff: g&gt;</string>\n    <string name=\"gcm_registered_since\">பின்னர் பதிவுசெய்தது: &lt;xliff: g எடுத்துக்காட்டு = \\\"நேற்று, 02:20 PM\\\"&gt;%1$s &lt;/xliff: g&gt;</string>\n    <string name=\"gcm_messages_counter\">செய்திகள்: &lt;xliff: g எடுத்துக்காட்டு = \\\"123\\\"&gt;%1$d &lt;/xliff: g&gt; (&lt;xliff: g எடுத்துக்காட்டு = \\\"12345\\\"&gt;%2$d &lt;/xliff: g&gt; பைட்டுகள்)</string>\n    <string name=\"gcm_network_state_connected\">&lt;Xliff: g எடுத்துக்காட்டு = \\\"2 மணி நேரத்திற்கு முன்பு\\\"&gt;%1$s &lt;/xliff: g&gt;</string>\n    <string name=\"gcm_allow_app_popup\">&lt;Xliff: g எடுத்துக்காட்டு = \\\"f-droid\\\"&gt;%1$s &lt;/xliff: g&gt; ஐ அழுத்தவும், புச் அறிவிப்புகளுக்கு பதிவு செய்ய?</string>\n    <string name=\"safetynet_last_run_at\">கடைசி பயன்பாடு: &lt;xliff: g எடுத்துக்காட்டு = \\\"நேற்று, 02:20 PM\\\"&gt;%1$s &lt;/xliff: g&gt;</string>\n    <string name=\"pref_vending_feature_delivery\">Google Play நற்பொருத்தம் வழங்கல்</string>\n    <string name=\"pref_vending_split_install_switch\">ஆன்-டிமாண்ட் கூறு நிறுவல்</string>\n    <string name=\"pref_vending_licensing_split_install_summary\">கூடுதல் கூறுகளை பதிவிறக்கம் செய்து நிறுவ பயன்பாடுகளை அனுமதிக்கவும்</string>\n    <string name=\"pref_workprofile_create_account\">பணி கணக்கு அமைப்பை அனுமதிக்கவும்</string>\n    <string name=\"pref_workprofile_intro\">உங்கள் பணியிடத்திற்காக அல்லது கல்வி நிறுவனத்திற்கான பணி சுயவிவரத்தை அமைக்கும் போது, அந்த சுயவிவரத்தில் பயன்பாடுகளைப் பதிவிறக்குவதற்கு Google உடன் இணைக்க அமைவு முயற்சி செய்யலாம்.</string>\n    <string name=\"pref_workprofile_disclaimer\">உங்கள் மைக்ரோகின் பயன்பாடு கார்ப்பரேட் கொள்கைகளுக்கு ஏற்ப இருப்பதை உறுதி செய்வது உங்கள் பொறுப்பு. மைக்ரோக் ஒரு சிறந்த உதவி அடிப்படையில் வழங்கப்படுகிறது, மேலும் எதிர்பார்த்தபடி சரியாக நடந்து கொள்ள பொறுப்பு அளிக்க முடியாது.</string>\n    <string name=\"camera_permission_dialog_title\">கேமரா இசைவு தேவை</string>\n    <string name=\"camera_permission_dialog_message\">%1$s க்கு ஒரு குறியீட்டை ச்கேன் செய்ய மைக்ரோக் சேவைகள் உங்கள் சாதனத்தின் கேமராவை அணுக வேண்டும்.\\n\\n இயக்க, அமைப்புகளில் மைக்ரோக் சேவைகளுக்கு கேமரா இசைவு வழங்கவும்.</string>\n    <string name=\"auth_package_override_request_message\"><b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> உங்கள் கணக்கை அணுக விரும்புகிறது<b><xliff:g example=\"F-Droid\">%2$s</xliff:g> இவரால் <xliff:g example=\"F-Droid Inc.\">%3$s</xliff:g></b>. இது உங்கள் கணக்கிற்கு சலுகை பெற்ற அணுகலை வழங்கக்கூடும்.</string>\n    <string name=\"auth_package_override_request_title\"><b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> இவருக்குச் சலுகை பெற்ற அணுகலை அனுமதி<xliff:g example=\"account@example.com\">%2$s</xliff:g>\\?</string>\n    <string name=\"signin_subtext_sharing\">தொடர, மைக்ரோக் உங்கள் Google கணக்கின் பெயர், மின்னஞ்சல் முகவரி மற்றும் சுயவிவரப் படத்தை &lt;xliff: g எடுத்துக்காட்டு = \\\"f-droid\\\"&gt;%1$s &lt;/xliff: g&gt; உடன் பகிர்ந்து கொள்ளும்.</string>\n    <string name=\"lacking_permission_toast\">மைக்ரோக் சேவைகள்: &lt;xliff: g எடுத்துக்காட்டு = \\\"முழு பிணையம் அக்சசைக் கொண்டிருங்கள்\\\"&gt;%1$s &lt;/xliff: g&gt;</string>\n    <string name=\"pref_gcm_ping_interval\">பிங் இடைவெளி: &lt;xliff: g எடுத்துக்காட்டு = \\\"10 நிமிடங்கள்\\\"&gt;%1$s &lt;/xliff: g&gt;</string>\n    <string name=\"signin_picker_subtitle\">&lt;xliff: g எடுத்துக்காட்டு = \\\"f-droid\\\"&gt;%1$s &lt;/xliff: g&gt;</string>\n    <string name=\"signin_confirm_title\">உங்களை &lt;xliff: g எடுத்துக்காட்டு = \\\"f-droid\\\"&gt;%1$s &lt;/xliff: g&gt; இல் கையொப்பமிட அனுமதிக்கவும்</string>\n    <string name=\"checkin_last_registration\">கடைசி பதிவு: &lt;xliff: g எடுத்துக்காட்டு = \\\"நேற்று, 02:20 PM\\\"&gt;%1$s &lt;/xliff: g&gt;</string>\n    <string name=\"ask_scope_permission_title\">&lt;xliff: g எடுத்துக்காட்டு = \\\"f-droid\\\"&gt;%1$s &lt;/xliff: g&gt; விரும்புகிறது:</string>\n    <string name=\"ask_service_permission_title\">&lt;xliff: g எடுத்துக்காட்டு = \\\"f-droid\\\"&gt;%1$s &lt;/xliff: g&gt; பயன்படுத்த விரும்புகிறது:</string>\n    <string name=\"auth_notification_content\">&lt;xliff: g எடுத்துக்காட்டு = \\\"f-droid\\\"&gt;%1$s &lt;/xliff: g&gt; உங்கள் Google கணக்கை அணுக உங்கள் ஏற்பு தேவை.</string>\n    <string name=\"games_info_title\">&lt;xliff: g எடுத்துக்காட்டு = \\\"f-droid\\\"&gt;%1$s &lt;/xliff: g&gt; பிளே கேம்களைப் பயன்படுத்த விரும்புகிறது</string>\n    <string name=\"place_picker_location_lat_lng\">(%1$.7f, %2$.7f)</string>\n    <string name=\"self_check_name_app_installed\">&lt;xliff: g எடுத்துக்காட்டு = \\\"f-droid\\\"&gt;%1$s &lt;/xliff: g&gt; நிறுவப்பட்டுள்ளது:</string>\n    <string name=\"credentials_assisted_choose_account_error_tips\">கணக்கு அசாதாரணமானது</string>\n    <string name=\"credentials_assisted_signin_add_account\">கணக்கைச் சேர்க்கவும்</string>\n    <string name=\"auth_action_reauth_notification_title\">கணக்கு நடவடிக்கை தேவை</string>\n    <string name=\"pref_auth_two_step_verification_title\">இரண்டு-படி சரிபார்ப்பு அறிவிப்புகளைப் பெறுங்கள்</string>\n    <string name=\"pref_auth_two_step_verification_summary\">இயக்கப்பட்டால், சாதனம் Google இலிருந்து இரண்டு-படி சரிபார்ப்பு அறிவிப்புகளைப் பெற முடியும் (கிளவுட் செய்தி அனுப்புதல் தேவை).</string>\n    <string name=\"pref_game_accounts_title\">கூகிள் விளையாட்டு கணக்குகள்</string>\n    <string name=\"pref_auto_create_player\">ப்ளே கேம்ஸ் கணக்கைப் பதிவுசெய்ய அனுமதி</string>\n    <string name=\"pref_auto_create_player_intro\">கேம்களை விளையாடும்போது, சாதனைகள், லீடர்போர்டுகள், காப்பகங்கள் போன்ற கேம் தொடர்பான செயல்பாடுகளை உள்நுழைந்து பதிவு செய்ய Play கேம்ஸ் கணக்கைப் பயன்படுத்த வேண்டும். முடக்கிய பிறகு, Play கேம்ஸ் கணக்குடன் பிணைக்கப்படாத Google கணக்குகள் தானாகவே பதிவு செய்யப்படாது, மேலும் கேம் உள்நுழைந்து விளையாட முடியாது.</string>\n    <string name=\"pref_allow_upload_game_played\">விளையாடிய விளையாட்டைப் பதிவேற்ற அனுமதிக்கவும்</string>\n    <string name=\"pref_allow_upload_game_played_summary\">முடக்கப்பட்டிருக்கும் போது, விளையாட்டில் உள்நுழைந்த பிறகு விளையாட்டு விளையாடிய நிலையை விளையாட்டு தெரிவிக்காது, மேலும் சில விளையாட்டுகளால் உள்நுழைய முடியாமல் போகலாம்.</string>\n    <string name=\"pref_change_default_game_player\">கேம்களுக்கான கணக்கை மாற்று</string>\n    <string name=\"pref_change_default_game_player_summary\">விளையாட்டுகளுக்கான இயல்புநிலை கணக்கை மாற்றவும் &amp; ஒவ்வொரு விளையாட்டிற்கும் கணக்கை மாற்றவும்.</string>\n    <string name=\"pref_delete_game_account_data\">Play கேம்ஸ் தரவை நீக்கு</string>\n    <string name=\"pref_delete_game_account_data_summary\">Play கேம்ஸ் கணக்கு &amp; அனைத்து தரவையும் நீக்கவும் மற்றும் தனிப்பட்ட கேம் தரவை நீக்கவும்.</string>\n    <string name=\"games_state_description_signed_out\">வெளியேறிவிட்டார்</string>\n    <string name=\"games_state_description_delete\">நீக்கு</string>\n    <string name=\"games_change_button_text\">மாற்று</string>\n    <string name=\"games_change_default_account_section_title\">கேம்களுக்கான இயல்புநிலை கணக்கை மாற்றவும்</string>\n    <string name=\"games_change_default_account_description\">இயல்புநிலை கணக்கு: %1$s</string>\n    <string name=\"games_change_default_account_explanation\">இந்தக் கணக்கு உங்களை கேம்களில் தானாக உள்நுழையவும், உங்கள் கேம் முன்னேற்றத்தைச் சேமிக்கவும், உங்கள் அமைப்புகளைச் சேமிக்கவும் பயன்படுகிறது. இயல்புநிலை கணக்கை மாற்றுவது அல்லது வெளியேறுவது உங்கள் முன்னேற்றத்தையும் நீங்கள் விளையாடிய கேம்களுக்கான அமைப்புகளையும் மீட்டமைக்கக்கூடும்.</string>\n    <string name=\"games_change_per_game_title\">விளையாட்டின் அடிப்படையில் கணக்கை மாற்றவும்</string>\n    <string name=\"games_change_per_game_description\">தேர்ந்தெடுக்கப்பட்ட விளையாட்டுக்கான கணக்கை மாற்றுவது அல்லது அதிலிருந்து வெளியேறுவது உங்கள் முன்னேற்றத்தையும் விளையாட்டு அமைப்புகளையும் மீட்டமைக்கக்கூடும்.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_title\">புதிய இயல்புநிலை கணக்கிற்கான விருப்பத்தைத் தேர்ந்தெடுக்கவும்</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_description\">தற்போதைய இயல்புநிலை கணக்கு: %1$s</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_title\">புதிய கேம்களுக்கு மட்டும் இயல்புநிலை கணக்கை மாற்றவும்</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_description\">நீங்கள் விளையாடிய கேம்களின் முன்னேற்றம் மற்றும் அமைப்புகளுக்கான அணுகலை இழக்க மாட்டீர்கள். ஆனால் உங்கள் முன்னேற்றம் கணக்குகளுக்கு இடையில் பிரிக்கப்படும்.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_title\">எல்லா விளையாட்டுகளுக்கும் இயல்புநிலை கணக்கை மாற்றவும்</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_description\">நீங்கள் விளையாடிய கேம்களின் முன்னேற்றம் மற்றும் அமைப்புகளுக்கான அணுகலை நீங்கள் இழக்க நேரிடும். உங்கள் மாற்றங்களைப் பயன்படுத்த நாங்கள் கேமை மீண்டும் தொடங்குவோம்.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_title\">எல்லா விளையாட்டுகளிலிருந்தும் வெளியேறு</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_description\">நீங்கள் விளையாடிய கேம்களின் முன்னேற்றம் மற்றும் அமைப்புகளுக்கான அணுகலை நீங்கள் இழக்க நேரிடும். உங்கள் மாற்றங்களைப் பயன்படுத்த நாங்கள் கேமை மீண்டும் தொடங்குவோம்.</string>\n    <string name=\"games_change_per_game_dialog_title\">இந்த விளையாட்டுக்கு ஒரு விருப்பத்தைத் தேர்ந்தெடுக்கவும்</string>\n    <string name=\"games_change_per_game_dialog_description\">கணக்கை மாற்றுவது அல்லது வெளியேறுவது உங்கள் விளையாட்டு முன்னேற்றத்தையும் அமைப்புகளையும் மீட்டமைக்கக்கூடும்</string>\n    <string name=\"games_change_per_game_dialog_option_use_player\">%1$s ஐப் பயன்படுத்தவும்</string>\n    <string name=\"games_change_per_game_dialog_option_use_player_snackbar_success_message\">நீங்கள் %1$s மூலம் இந்த கேமில் உள்நுழைவீர்கள்</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out\">வெளியேறு</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out_snackbar_success_message\">நீங்கள் இப்போது இந்த விளையாட்டிலிருந்து வெளியேறிவிட்டீர்கள்</string>\n    <string name=\"games_change_sign_out_of_all_games_snackbar_success_message\">நீங்கள் இப்போது எல்லா கேம்களிலிருந்தும் வெளியேறிவிட்டீர்கள்</string>\n    <string name=\"games_change_default_account_for_all_games_snackbar_success_message\">%1$s மூலம் எல்லா கேம்களிலும் உள்நுழைவீர்கள்</string>\n    <string name=\"games_change_default_account_for_new_games_snackbar_success_message\">%1$s உடன் புதிய கேம்களில் உள்நுழைவீர்கள்</string>\n    <string name=\"games_account_display_content\">நடப்புக் கணக்கு: %1$s</string>\n    <string name=\"games_delete_profile_header\">Play கேம்ஸ் கணக்கையும் எல்லா தரவையும் நீக்கு</string>\n    <string name=\"games_delete_profile_explanation\">உங்கள் Google Play கேம்ஸ் கணக்கு, XP மற்றும் அனைத்து சுயவிவரத் தரவையும் நிரந்தரமாக நீக்கவும். இந்தச் செயல் உங்கள் ஸ்கோர்கள், முன்னேற்றம் (சேமிக்கப்பட்ட கேம்கள்) மற்றும் நீங்கள் விளையாடிய கேம்களின் அமைப்புகளையும் நீக்கக்கூடும்.</string>\n    <string name=\"games_delete_profile_button\">நிரந்தரமாக நீக்கு</string>\n    <string name=\"games_delete_game_data_header\">தனிப்பட்ட விளையாட்டு தரவை நீக்கு</string>\n    <string name=\"games_delete_game_data_explanation\">Google Play கேம்ஸைப் பயன்படுத்தி நீங்கள் விளையாடிய கேம்களுக்கான தனிப்பட்ட தரவை நிரந்தரமாக நீக்கலாம். இந்தச் செயல் உங்கள் ஸ்கோர்கள், முன்னேற்றம் (சேமிக்கப்பட்ட கேம்கள்) மற்றும் நீங்கள் தேர்ந்தெடுக்கும் கேமிற்கான அமைப்புகளை நீக்கும்.</string>\n    <string name=\"games_delete_profile_dialog_title\">இந்தக் கணக்கை நீக்க விரும்புகிறீர்களா?</string>\n    <string name=\"games_delete_profile_explanation_with_gamer_name\"><b>%1$s</b> (<b>%2$s</b>) என்ற கேமர் பெயருக்கான உங்கள் Google Play கேம்ஸ் கணக்கு, XP மற்றும் அனைத்து சுயவிவரத் தரவையும் நிரந்தரமாக நீக்கவும். இந்தச் செயல், நீங்கள் விளையாடிய கேம்களில் உள்ள உங்கள் ஸ்கோர்கள், முன்னேற்றம் (சேமித்த கேம்கள்) மற்றும் அமைப்புகளையும் நீக்கக்கூடும்.</string>\n    <string name=\"games_delete_profile_dialog_message\">இந்தச் செயலைச் செயல்தவிர்க்க முடியாது.</string>\n    <string name=\"games_delete_profile_fail\">உங்கள் சுயவிவரத்தை நீக்க முடியவில்லை. பிறகு முயற்சிக்கவும்.</string>\n    <string name=\"games_delete_game_data_confirm_dialog_title\">%1$s க்கான தரவை நீக்கு</string>\n    <string name=\"games_delete_game_data_confirm_dialog_message\">%1$sக்கான உங்கள் தரவை நிரந்தரமாக நீக்குவது, Google Play கேம்ஸில் உள்ள உங்கள் ஸ்கோர்கள், முன்னேற்றம் (சேமிக்கப்பட்ட கேம்கள்) மற்றும் கேம் அமைப்புகளை நீக்கிவிடும்.</string>\n    <string name=\"games_popup_signin_welcome\">வணக்கம், %1$s</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-th/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"permission_service_all_label\">บริการทั้งหมดของ Google</string>\n    <string name=\"permission_service_all_description\">อนุญาตให้แอปเข้าถึงบริการ Google ทั้งหมดที่เชื่อมโยงกันผ่านทางบัญชีของ Google</string>\n    <string name=\"permission_service_android_label\">บริการแอนดรอยด์</string>\n    <string name=\"permission_service_adsense_description\">อนุญาตให้แอปเข้าถึง AdSense ผ่านบัญชี Google ที่เชื่อมโยงกัน</string>\n    <string name=\"permission_service_adwords_label\">Google Ads</string>\n    <string name=\"permission_service_ah_label\">Google App Engine</string>\n    <string name=\"permission_service_ah_description\">อนุญาตให้แอปเข้าถึง Google App Engine ผ่านทางบัญชี Google ที่เชื่อมโยงกัน</string>\n    <string name=\"permission_service_adsense_label\">AdSense</string>\n    <string name=\"permission_service_blogger_label\">Blogger</string>\n    <string name=\"permission_service_cl_label\">ปฏิทิน Google</string>\n    <string name=\"permission_service_cl_description\">อนุญาตให้แอปเข้าถึง Google Calendar ผ่านทางบัญชี Google ที่เชื่อมโยงกัน</string>\n    <string name=\"permission_service_cp_label\">รายชื่อ</string>\n    <string name=\"permission_service_dodgeball_label\">ดอดจ์บอล</string>\n    <string name=\"permission_service_dodgeball_description\">อนุญาตให้แอปเข้าถึง Dodgeball ผ่านทางบัญชี Google ที่เชื่อมโยง</string>\n    <string name=\"permission_service_android_description\">อนุญาตให้แอปเข้าถึงบริการ Android ผ่านทางบัญชี Google ที่เชื่อมโยงกัน</string>\n    <string name=\"permission_service_adwords_description\">อนุญาตให้แอปเข้าถึง Google Ads ผ่านทางบัญชี Google ที่เชื่อมโยงกัน</string>\n    <string name=\"permission_service_blogger_description\">อนุญาตให้แอปเข้าถึง Blogger ผ่านทางบัญชี Google ที่เชื่อมโยงกัน</string>\n    <string name=\"permission_service_cp_description\">อนุญาตให้แอปเข้าถึงรายชื่อผ่านบัญชี Google ที่เชื่อมโยงกัน</string>\n    <string name=\"permission_service_finance_description\">อนุญาตให้แอปเข้าถึง Google Finance ผ่านบัญชี Google ที่เชื่อมโยง</string>\n    <string name=\"permission_service_gbase_description\">อนุญาตให้แอปเข้าถึง Google Base ผ่านทางบัญชี Google ที่เชื่อมโยง</string>\n    <string name=\"permission_service_grandcentral_label\">Google Voice</string>\n    <string name=\"permission_service_grandcentral_description\">อนุญาตให้แอปเข้าถึง Google Voice ผ่านทางบัญชี Google ที่เชื่อมโยง</string>\n    <string name=\"permission_service_finance_label\">Google Finance</string>\n    <string name=\"permission_service_gbase_label\">Google Base</string>\n    <string name=\"permission_service_health_label\">Google Health</string>\n    <string name=\"permission_service_health_description\">อนุญาตให้แอปเข้าถึง Google Health ผ่านทางบัญชี Google ที่เชื่อมโยง</string>\n    <string name=\"permission_service_ig_label\">iGoogle</string>\n    <string name=\"permission_service_news_label\">Google News</string>\n    <string name=\"permission_service_news_description\">อนุญาตให้แอปเข้าถึง Google News ผ่านทางบัญชี Google ที่เชื่อมโยง</string>\n    <string name=\"permission_service_orkut_label\">Orkut</string>\n    <string name=\"permission_service_orkut_description\">อนุญาตให้แอปเข้าถึง Orkut ผ่านทางบัญชี Google ที่เชื่อมโยง</string>\n    <string name=\"permission_service_print_label\">Google Book Search</string>\n    <string name=\"permission_service_sierra_label\">บัญชี Google Checkout</string>\n    <string name=\"permission_service_sierra_description\">อนุญาตให้แอปเข้าถึงบัญชี Google Checkout ผ่านทางบัญชี Google ที่เชื่อมโยง</string>\n    <string name=\"permission_service_sierraqa_description\">อนุญาตให้แอปเข้าถึงบัญชี Google Checkout QA ผ่านทางบัญชี Google ที่เชื่อมโยง</string>\n    <string name=\"permission_service_sierrasandbox_label\">บัญชี Google Checkout Sandbox</string>\n    <string name=\"permission_service_sitemaps_label\">เครื่องมือสำหรับผู้ดูแลเว็บของ Google</string>\n    <string name=\"permission_service_sitemaps_description\">อนุญาตให้แอปเข้าถึง Google Webmaster Tools ผ่านทางบัญชี Google ที่เชื่อมโยง</string>\n    <string name=\"permission_service_speech_label\">การค้นหาด้วยเสียง</string>\n    <string name=\"permission_service_speechpersonalization_label\">การจดจำเสียงพูดส่วนบุคคล</string>\n    <string name=\"permission_service_talk_label\">Google Talk</string>\n    <string name=\"permission_service_talk_description\">อนุญาตให้แอปเข้าถึง Google Talk ผ่านทางบัญชี Google ที่เชื่อมโยง</string>\n    <string name=\"permission_service_wifi_label\">Google Wi-Fi</string>\n    <string name=\"permission_service_wifi_description\">อนุญาตให้แอปเข้าถึง Google Wi-Fi ผ่านบัญชี Google ที่เชื่อมโยง</string>\n    <string name=\"permission_service_wise_description\">อนุญาตให้แอปเข้าถึง Google Spreadsheets ผ่านทางบัญชี Google ที่เชื่อมโยง</string>\n    <string name=\"permission_service_writely_label\">Google Docs</string>\n    <string name=\"permission_service_youtube_label\">YouTube</string>\n    <string name=\"permission_service_youtube_description\">อนุญาตให้แอปเข้าถึง YouTube ผ่านทางบัญชี Google ที่เชื่อมโยง</string>\n    <string name=\"permission_service_YouTubeUser_label\">ชื่อผู้ใช้ YouTube</string>\n    <string name=\"permission_service_groups2_label\">Google Groups</string>\n    <string name=\"permission_service_groups2_description\">อนุญาตให้แอปเข้าถึง Google Groups ผ่านทางบัญชี Google ที่เชื่อมโยงกัน</string>\n    <string name=\"permission_service_mail_description\">อนุญาตให้แอปเข้าถึง Google Mail ผ่านทางบัญชี Google ที่เชื่อมโยง</string>\n    <string name=\"permission_service_notebook_label\">Google Notebook</string>\n    <string name=\"permission_service_notebook_description\">อนุญาตให้แอปเข้าถึง Google Notebook ผ่านทางบัญชี Google ที่เชื่อมโยง</string>\n    <string name=\"permission_service_print_description\">อนุญาตให้แอปเข้าถึง Google Book Search ผ่านทางบัญชี Google ที่เชื่อมโยง</string>\n    <string name=\"permission_service_sierraqa_label\">บัญชี QA ของ Google Checkout</string>\n    <string name=\"permission_service_sierrasandbox_description\">อนุญาตให้แอปเข้าถึงบัญชี Google Checkout Sandbox ผ่านทางบัญชี Google ที่เชื่อมโยง</string>\n    <string name=\"permission_service_speech_description\">อนุญาตให้แอปเข้าถึงการค้นหาด้วยเสียงผ่านบัญชี Google ที่เชื่อมโยง</string>\n    <string name=\"permission_service_speechpersonalization_description\">อนุญาตให้แอปเข้าถึงการจดจำคำพูดส่วนบุคคลผ่านทางบัญชี Google ที่เชื่อมโยง</string>\n    <string name=\"permission_service_wise_label\">Google สเปรดชีต</string>\n    <string name=\"permission_service_writely_description\">อนุญาตให้แอปเข้าถึง Google Docs ผ่านทางบัญชี Google ที่เชื่อมโยง</string>\n    <string name=\"permission_service_YouTubeUser_description\">อนุญาตให้แอปเข้าถึงชื่อผู้ใช้ YouTube ที่ใช้กับบัญชี Google ที่เชื่อมโยง</string>\n    <string name=\"permission_service_ig_description\">อนุญาตให้แอปเข้าถึง iGoogle ผ่านทางบัญชี Google ที่เชื่อมโยง</string>\n    <string name=\"permission_service_jotspot_label\">ฮอตสปอต</string>\n    <string name=\"permission_service_jotspot_description\">อนุญาตให้แอปเข้าถึง HotSpot ผ่านทางบัญชี Google ที่เชื่อมโยง</string>\n    <string name=\"permission_service_knol_label\">Knol</string>\n    <string name=\"permission_service_knol_description\">อนุญาตให้แอปเข้าถึง สารานุกรมออนไลน์ ผ่านบัญชี Google ที่เชื่อมโยง</string>\n    <string name=\"permission_service_lh2_label\">อัลบั้มเว็บ Picasa</string>\n    <string name=\"permission_service_lh2_description\">อนุญาตให้แอปเข้าถึง Picasa Web Albums ผ่านทางบัญชี Google ที่เชื่อมโยง</string>\n    <string name=\"permission_service_local_label\">แผนที่ Google</string>\n    <string name=\"permission_service_local_description\">อนุญาตให้แอปเข้าถึง Google Maps ผ่านบัญชี Google ที่เชื่อมโยง</string>\n    <string name=\"permission_service_mail_label\">Google Mail</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_activity\">ดูประวัติกิจกรรมของ Google Apps ของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.buyer\">จัดการการกำหนดค่าบัญชีผู้ซื้อ Ad Exchange ของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller.readonly\">ดูข้อมูล Ad Exchange ของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller\">ดูข้อมูล Ad Exchange ของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order.readonly\">นอกเหนือจากขอบเขตการอ่าน/เขียน OAuth โดยรวมแล้ว ให้ใช้ขอบเขต OAuth แบบอ่านอย่างเดียวเมื่อดึงข้อมูลของลูกค้า</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger.readonly\">จัดการบัญชีบล็อกเกอร์ของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.metadata.readonly\">ดูข้อมูลเมตาสำหรับไฟล์และเอกสารใน Google Drive ของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate\">ดูและจัดการงาน Google Maps Coordinate ของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_cloudprint\">ดูและจัดการข้อมูลการพิมพ์บนคลาวด์ของ Google ของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.file\">ดูและจัดการไฟล์ Google Drive ที่คุณเปิดหรือสร้างด้วยแอปนี้</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_only\">ดูข้อมูลของคุณใน Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive\">ดูและจัดการไฟล์และเอกสารใน Google Drive ของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.email\">ดูที่อยู่อีเมลของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tracks\">Google Maps Tracks API, ขอบเขตนี้อนุญาตให้เข้าถึงแบบอ่านและเขียนข้อมูลของโครงการของคุณได้</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.profile\">ดูข้อมูลพื้นฐานเกี่ยวกับบัญชีของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.upload\">การจัดการของคุณ วิดีโอ YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsensehost\">ดูและจัดการข้อมูลโฮสต์ AdSense และบัญชีที่เกี่ยวข้องของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense.readonly\">ดูข้อมูล AdSense ของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense\">ดูและจัดการข้อมูล AdSense ของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appengine.admin\">ขอบเขตการดูแลระบบแอปเอนจิ้น</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.migration\">การเข้าถึงแบบอ่านและเขียนไปยัง Groups Migration API</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.settings\">ดูและจัดการการตั้งค่าของกลุ่ม Google Apps</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.licensing\">การเข้าถึงแบบอ่าน/เขียนสำหรับ License Manager API</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order\">สำหรับผู้ดูแลระบบตัวแทนจำหน่ายและผู้ใช้มีสิทธิ์การอ่าน/เขียนเมื่อทำการทดสอบในแซนด์บ็อกซ์ของ API หรือมีสิทธิ์การอ่าน/เขียนเมื่อเรียกการดำเนินการ API โดยตรง</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps_reporting_audit.readonly\">การเข้าถึง API การตรวจสอบผู้ดูแลระบบแบบอ่านอย่างเดียว</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appstate\">ขอบเขตการใช้งานบริการ App State</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery.readonly\">ดูข้อมูลของคุณใน Google BigQuery</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery\">ดูและจัดการข้อมูลของคุณใน Google BigQuery</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger\">จัดการบัญชีบล็อกเกอร์ของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_books\">จัดการหนังสือของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar\">จัดการปฏิทินของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar.readonly\">ดูปฏิทินของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute.readonly\">ดูทรัพยากร Google Compute Engine ของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute\">ดูและจัดการทรัพยากร Google Compute Engine ของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate.readonly\">ดูงาน Google Coordinate ของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.full_control\">จัดการข้อมูลและสิทธิ์ของคุณใน Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_write\">จัดการข้อมูลของคุณใน Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_dfareporting\">ดูและจัดการรายงาน DoubleClick สำหรับผู้โฆษณา</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.appdata\">อนุญาตให้เข้าถึงโฟลเดอร์ข้อมูลแอปพลิเคชัน</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.apps.readonly\">ดูแอป Google Drive ของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.install\">ขอบเขตพิเศษที่ใช้เพื่อให้ผู้ใช้สามารถอนุมัติการติดตั้งแอปได้</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.readonly\">ดูไฟล์และเอกสารใน Google Drive ของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.scripts\">ปรับเปลี่ยนพฤติกรรมสคริปต์ Google Apps ของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase.readonly\">ดูบัญชี Freebase ของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_urlshortener\">จัดการ URL สั้นของ goo.gl ของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks.readonly\">ดูงานของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks\">จัดการงานของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue.consumer\">ใช้ภารกิจจากคิวภารกิจของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue\">จัดการงานของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube\">การจัดการของคุณ บัญชี YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtubepartner\">ดูและจัดการสินทรัพย์ของคุณและเนื้อหาที่เกี่ยวข้องกับ YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.readonly\">ดูบัญชี YouTube ของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.readonly\">อ่านทรัพยากรทั้งหมดและข้อมูลเมตาของทรัพยากรเหล่านั้น—ไม่มีการดำเนินการเขียน</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_androidpublisher\">การเข้าถึงนักพัฒนา Android ของ Google Play</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics.readonly\">ดูข้อมูล Google Analytics ของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics\">ดูและจัดการข้อมูล Google Analytics ของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase\">ลงชื่อเข้าใช้ Firebase ด้วยบัญชีของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables\">จัดการตารางฟิวชันของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables.readonly\">ดูตารางฟิวชันของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_games\">ขอบเขตการเข้าถึงข้อมูลจาก Google Play Games</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan\">จัดการข้อมูล GAN ของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan.readonly\">ดูข้อมูล GAN ของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gcm_for_chrome\">CloudMessaging สำหรับ Chrome</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_glass.timeline\">ขอบเขตของ Glass timeline</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.compose\">สร้าง อ่าน อัปเดต และลบฉบับร่าง ส่งข้อความและฉบับร่าง</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.modify\">การดำเนินการอ่าน/เขียนทั้งหมด ยกเว้นการลบเธรดและข้อความทันทีและถาวร โดยข้ามถังขยะ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.best\">จัดการตำแหน่งที่ดีที่สุดที่มีอยู่และประวัติตำแหน่งของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.city\">จัดการตำแหน่งระดับเมืองและประวัติตำแหน่งของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.best\">จัดการตำแหน่งที่ดีที่สุดที่มีอยู่ของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.city\">จัดการตำแหน่งระดับเมืองของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine\">ดูและจัดการข้อมูล Google Maps Engine ของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine.readonly\">ดูข้อมูล Google Maps Engine ของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mobilemaps.firstparty\">ดูและจัดการ Google Maps ของคุณสำหรับประสบการณ์มือถือ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut\">จัดการกิจกรรม Orkut ของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut.readonly\">ดูข้อมูล Orkut ของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.login\">ทราบชื่อของคุณ ข้อมูลพื้นฐาน และรายชื่อบุคคลที่คุณเชื่อมต่อด้วยบน Google+</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.me\">รู้ว่าคุณเป็นใครบน Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_prediction\">จัดการข้อมูลของคุณใน Google Prediction API</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_shoppingapi\">ดูข้อมูลผลิตภัณฑ์ของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification\">จัดการรายการไซต์และโดเมนที่คุณควบคุม</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification.verify_only\">จัดการการตรวจสอบไซต์ใหม่ของคุณด้วย Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_structuredcontent\">การเข้าถึงแบบอ่าน/เขียนสำหรับ Shopping Content API</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics_monetary.readonly\">ดูรายงานทางการเงินของ YouTube Analytics สำหรับเนื้อหา YouTube ของคุณ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics.readonly\">ดูรายงาน YouTube Analytics สำหรับเนื้อหา YouTube ของคุณ</string>\n    <string name=\"perm_activity_recognition_description\">อนุญาตให้แอปรับการอัปเดตระดับกิจกรรมของคุณจาก Google เป็นระยะๆ เช่น หากคุณกำลังเดิน ขับรถ ปั่นจักรยาน หรืออยู่กับที่</string>\n    <string name=\"perm_activity_recognition_label\">การจดจำกิจกรรม</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-th/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <plurals name=\"pref_unifiednlp_summary\">\n        <item quantity=\"other\"><xliff:g example=\"1\">%1$d</xliff:g> กำหนดค่า แบ็คเอนด์แล้ว</item>\n    </plurals>\n    <plurals name=\"gcm_registered_apps_counter\">\n        <item quantity=\"other\"><xliff:g example=\"123\">%1$d</xliff:g> ลงทะเบียนแอปแล้ว</item>\n    </plurals>\n    <plurals name=\"cond_perm_summary\">\n        <item quantity=\"other\">ไม่ได้รับอนุญาตสิทธิ์ที่จำเป็นสำหรับการทำงานที่ถูกต้องของ microG Services</item>\n    </plurals>\n    <plurals name=\"cond_perm_action\">\n        <item quantity=\"other\">การร้องขอการอนุญาตผิดพลาด</item>\n    </plurals>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-th/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=\"gms_settings_name\">การตั้งค่า microG</string>\n    <string name=\"just_a_sec\">รอสักครู่…</string>\n    <string name=\"google_account_label\">Google</string>\n    <string name=\"ask_service_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> ต้องการใช้:</string>\n    <string name=\"account_manager_title\">ผู้จัดการบัญชี Google</string>\n    <string name=\"sorry\">ขอโทษด้วย…</string>\n    <string name=\"auth_sign_in\">ลงชื่อเข้าใช้</string>\n    <string name=\"auth_general_error_desc\">มีปัญหาในการสื่อสารกับเซิร์ฟเวอร์ของ Google\\n\\nลองอีกครั้งในภายหลัง</string>\n    <string name=\"auth_finalize\">อุปกรณ์ของคุณกำลังติดต่อ Google เพื่อบันทึกข้อมูลลงในบัญชีของคุณ\\n\\nกระบวนการนี้อาจใช้ระยะเวลาสักครู่</string>\n    <string name=\"allow\">อนุญาต</string>\n    <string name=\"gms_app_name\">microG Services</string>\n    <string name=\"gms_settings_summary\">ตั้งค่าบริการ microG</string>\n    <string name=\"ask_permission_tos\">ในการดำเนินการต่อไป จะถือว่าคุณยินยอมให้แอปนี้และ Google ใช้ข้อมูลของคุณตามข้อกำหนดในการให้บริการและนโยบายความเป็นส่วนตัวของแต่ละแอป</string>\n    <string name=\"ask_scope_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> ต้องการ:</string>\n    <string name=\"auth_before_connect\">แอปบนอุปกรณ์ของคุณกำลังพยายามลงชื่อเข้าใช้บัญชี Google\\n\\nหากเกิดจากความตั้งใจของคุณเอง ให้ใช้ปุ่ม <b>ลงชื่อเข้าใช้</b> เพื่อเชื่อมต่อกับหน้าลงชื่อเข้าใช้ของ Google หากไม่ได้ตั้งใจ ให้กด <b>ยกเลิก</b> เพื่อกลับไปยังแอปพลิเคชันที่ทำให้กล่องโต้ตอบนี้ปรากฏขึ้น</string>\n    <string name=\"auth_connecting\">อุปกรณ์ของคุณกำลังสร้างการเชื่อมต่อกับเซิร์ฟเวอร์ของ Google เพื่อลงชื่อเข้าใช้ให้คุณ\\n\\nอาจใช้เวลาสักครู่</string>\n    <string name=\"no_network_error_desc\">คุณไม่ได้เชื่อมต่อกับเครือข่าย\\n\\nนี่อาจเป็นปัญหาชั่วคราวหรืออุปกรณ์ Android ของคุณอาจไม่มีการให้บริการข้อมูล ลองอีกครั้งเมื่อเชื่อมต่อกับเครือข่ายมือถือหรือเชื่อมต่อกับเครือข่าย Wi-Fi</string>\n    <string name=\"limited_services_app_name\">microG Limited Services</string>\n    <string name=\"deny\">ปฏิเสธ</string>\n    <string name=\"auth_notification_title\">จำเป็นต้องมีการพิสูจน์ตัวตน</string>\n    <string name=\"auth_notification_content\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> ต้องได้รับอนุญาตจากคุณก่อนถึงจะสามารถเข้าถึงบัญชี Google ของคุณได้</string>\n    <string name=\"auth_package_override_request_message\"><b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> ต้องการเข้าถึงบัญชีของคุณราวกับว่าเป็น <b><xliff:g example=\"F-Droid\">%2$s</xliff:g> โดย <xliff:g example=\"F-Droid Inc.\">%3$s</xliff:g></b> การกระทำดังกล่าวอาจทำให้บัญชีดังกล่าวได้รับสิทธิ์พิเศษในการเข้าถึงบัญชีของคุณ</string>\n    <string name=\"signin_picker_title\">เลือกบัญชี</string>\n    <string name=\"signin_picker_subtitle\">เพื่อดำเนินการต่อ <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"signin_picker_add_account_label\">เพิ่มบัญชีอื่น</string>\n    <string name=\"signin_confirm_title\">อนุญาตให้คุณลงชื่อเข้าใช้ <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"signin_confirm_button_text\">อนุญาตและแบ่งปัน</string>\n    <string name=\"perm_provision_label\">เตรียมบริการของ microG ให้พร้อมใช้งาน</string>\n    <string name=\"perm_provision_description\">อนุญาตให้แอปกำหนดค่าบริการ microG โดยไม่ต้องมีการโต้ตอบจากผู้ใช้</string>\n    <string name=\"perm_car_speed_label\">ความเร็วรถ</string>\n    <string name=\"perm_car_speed_description\">เข้าถึงความเร็วรถของคุณ</string>\n    <string name=\"perm_car_info_label\">ข้อมูลรถยนต์</string>\n    <string name=\"perm_car_info_description\">เข้าถึงข้อมูลรถของคุณ</string>\n    <string name=\"perm_car_fuel_label\">ระดับน้ำมันเชื้อเพลิงรถยนต์</string>\n    <string name=\"perm_car_mileage_label\">ระยะทางการใช้รถ</string>\n    <string name=\"perm_car_mileage_description\">เข้าถึงข้อมูลไมล์รถของคุณ</string>\n    <string name=\"perm_car_vendor_extension_label\">ช่องทางจำหน่ายรถยนต์</string>\n    <string name=\"service_name_checkin\">การลงทะเบียนอุปกรณ์ Google</string>\n    <string name=\"service_name_mcs\">การส่งข้อความบนคลาวด์</string>\n    <string name=\"service_name_vending\">บริการ Play Store</string>\n    <string name=\"games_title\">Google Play Games</string>\n    <string name=\"games_info_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> ต้องการใช้ Play Games</string>\n    <string name=\"games_info_content\">หากต้องการใช้ Play Games จำเป็นต้องติดตั้งแอป Google Play Games แอปพลิเคชันอาจทำงานต่อไปโดยไม่มี Play Games แต่ก็เป็นไปได้ที่แอปพลิเคชันจะทำงานผิดปกติ</string>\n    <string name=\"pick_place_title\">เลือกสถานที่</string>\n    <string name=\"pick_place_desc\">ตัวเลือกสถานที่ยังไม่พร้อมใช้งาน</string>\n    <string name=\"place_picker_nearby_places\">สถานที่ใกล้เคียง</string>\n    <string name=\"place_picker_location_lat_lng\">(%1$.7f, %2$.7f)</string>\n    <string name=\"network_type_mobile\">เครือข่ายมือถือ</string>\n    <string name=\"network_type_roaming\">โรมมิ่ง</string>\n    <string name=\"network_type_other\">เครือข่ายอื่นๆ</string>\n    <string name=\"self_check_cat_fake_sig\">รองรับการปลอมแปลงลายเซ็นดิจิตอล</string>\n    <string name=\"self_check_cat_gms_packages\">แพ็คเกจที่ติดตั้ง</string>\n    <string name=\"self_check_cat_system\">ระบบ</string>\n    <string name=\"self_check_name_fake_sig_perm\">ระบบรองรับการปลอมแปลงลายเซ็นดิจิตอล:</string>\n    <string name=\"auth_package_override_request_title\">อนุญาตให้ <b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> มีสิทธิพิเศษในการเข้าถึง <xliff:g example=\"account@example.com\">%2$s</xliff:g>\\?</string>\n    <string name=\"signin_subtext_sharing\">ในการดำเนินการต่อ microG จะแบ่งปันชื่อ ที่อยู่อีเมล และรูปโปรไฟล์ของบัญชี Google ของคุณกับ <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"perm_car_fuel_description\">เข้าถึงข้อมูลระดับน้ำมันเชื้อเพลิงของรถของคุณ</string>\n    <string name=\"perm_car_vendor_extension_description\">เข้าถึงช่องทางผู้จำหน่ายรถของคุณเพื่อแลกเปลี่ยนข้อมูลเฉพาะรถ</string>\n    <string name=\"service_name_snet\">Google SafetyNet</string>\n    <string name=\"place_picker_select_title\">เลือกตำแหน่งนี้</string>\n    <string name=\"lacking_permission_toast\">บริการ microG: ขาดการอนุญาตให้ <xliff:g example=\"have full network acccess\">%1$s</xliff:g></string>\n    <string name=\"network_type_wifi\">Wi-Fi</string>\n    <string name=\"self_check_resolution_correct_sig\">ที่ติดตั้งไว้ <xliff:g example=\"F-Droid\">%1$s</xliff:g> เข้ากันไม่ได้ หรือการปลอมแปลงลายเซ็นดิจิตอลไม่ได้เปิดใช้งาน โปรดตรวจสอบเอกสารเกี่ยวกับแอปพลิเคชันและ ROM ที่เข้ากันได้</string>\n    <string name=\"self_check_resolution_battery_optimizations\">แตะที่นี่เพื่อปิดใช้งานการเพิ่มประสิทธิภาพแบตเตอรี่ หากไม่ทำเช่นนี้ อาจทำให้แอปพลิเคชันทำงานผิดปกติ</string>\n    <string name=\"self_check_resolution_app_installed\">ติดตั้งแอปพลิเคชัน <xliff:g example=\"F-Droid\">%1$s</xliff:g> หรือแอปพลิเคชันที่เข้ากันได้ โปรดตรวจสอบเอกสารประกอบว่าแอปพลิเคชันใดที่เข้ากันได้</string>\n    <string name=\"signin_subtext_policy\">ก่อนใช้แอปนี้ โปรดอ่าน %1$s และ %2$s</string>\n    <string name=\"signin_subtext_policy_privacy\">นโยบายความเป็นส่วนตัว</string>\n    <string name=\"signin_subtext_policy_terms\">ข้อกําหนดในการให้บริการ</string>\n    <string name=\"perm_status_broadcast_label\">ฟังสถานะภายในของการออกอากาศ</string>\n    <string name=\"perm_gsf_read_gservices_label\">อ่านการกําหนดค่า Google</string>\n    <string name=\"perm_c2dm_receive_label\">ดักข้อความ C2DM</string>\n    <string name=\"perm_c2dm_send_label\">ส่งข้อความ C2DM ไปยังแอปอื่น ๆ</string>\n    <string name=\"perm_gtalk_svc_label\">การแลกเปลี่ยนข้อความและรับการแจ้งเตือนจากเซิร์ฟเวอร์ Google</string>\n    <string name=\"perm_extended_access_label\">เข้าถึงบริการ Google</string>\n    <string name=\"self_check_resolution_fake_sig_perm\">ROM ที่มาพร้อมกับระบบของคุณไม่มีการสนับสนุนการปลอมแปลงลายเซ็นดิจิตอล คุณยังสามารถใช้ Xposed หรือระบบอื่นเพื่อปลอมแปลงลายเซ็นได้ โปรดตรวจสอบเอกสารประกอบเกี่ยวกับ ROM ที่รองรับการปลอมแปลงลายเซ็นดิจิตอลและวิธีใช้ microG บน ROM ที่ไม่รองรับ</string>\n    <string name=\"self_check_name_perm_granted\">ระบบให้สิทธิ์ในการปลอมแปลงลายเซ็นดิจิตอล:</string>\n    <string name=\"self_check_resolution_perm_granted\">นี่เป็นตัวบ่งชี้ที่ชัดเจนว่า ROM รองรับการปลอมแปลงลายเซ็นดิจิตอล แต่ต้องมีการดำเนินการเพิ่มเติมเพื่อเปิดใช้งาน โปรดตรวจสอบเอกสารเกี่ยวกับขั้นตอนที่อาจจำเป็น</string>\n    <string name=\"self_check_name_system_spoofs\">ระบบปลอมแปลงลายเซ็นดิจิตอล:</string>\n    <string name=\"self_check_resolution_system_spoofs\">โปรดตรวจสอบเอกสารเกี่ยวกับขั้นตอนที่อาจจำเป็น</string>\n    <string name=\"self_check_pkg_gms\">microG Services</string>\n    <string name=\"self_check_pkg_vending\">microG Companion / Google Play</string>\n    <string name=\"self_check_pkg_gsf\">microG Services Framework</string>\n    <string name=\"self_check_name_app_installed\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> ติดตั้งแล้ว: </string>\n    <string name=\"self_check_name_correct_sig\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> มีลายเซ็นที่ถูกต้อง: </string>\n    <string name=\"self_check_name_battery_optimizations\">ละเว้นการเพิ่มประสิทธิภาพแบตเตอรี่:</string>\n    <string name=\"prefcat_about\">เกี่ยวกับ</string>\n    <string name=\"prefcat_components\">ส่วนประกอบ</string>\n    <string name=\"prefcat_configuration\">การกําหนดค่า</string>\n    <string name=\"prefcat_google_services\">Google Services</string>\n    <string name=\"prefcat_location_service\">การบริการระบุตำแหน่ง</string>\n    <string name=\"prefcat_services\">บริการ</string>\n    <string name=\"prefcat_test\">ทดสอบ</string>\n    <string name=\"cond_gcm_bat_title\">เปิดใช้งานการเพิ่มประสิทธิภาพแบตเตอรี่แล้ว</string>\n    <string name=\"auth_action_notification_channel_name\">การแจ้งเตือนบัญชี Google</string>\n    <string name=\"auth_action_notification_title\">จำเป็นต้องดำเนินการกับบัญชี</string>\n    <string name=\"auth_action_notification_channel_description\">แจ้งเตือนเมื่อบัญชี Google ของคุณต้องมีการตั้งค่าเพิ่มเติมก่อนถึงจะสามารถใช้งานได้ หรือเมื่อบัญชีเข้ากันไม่ได้กับ microG</string>\n    <string name=\"auth_action_notification_content\">บัญชี Google ของคุณต้องมีการตั้งค่าเพิ่มเติม</string>\n    <string name=\"auth_action_activity_header\">เสร็จสิ้นการตั้งค่าบัญชี Google ของคุณ</string>\n    <string name=\"auth_action_step_enable_checkin\">เปิดใช้งานการลงทะเบียนอุปกรณ์</string>\n    <string name=\"auth_action_step_enable_gcm\">เปิดใช้งานการส่งข้อความบนคลาวด์</string>\n    <string name=\"auth_action_step_enable_gcm_description\">คุณสามารถปิดการใช้งาน Cloud Messaging ได้หลังจากตั้งค่าบัญชีเสร็จสิ้น</string>\n    <string name=\"auth_action_step_allow_microg_gcm\">อนุญาตให้มีการส่งข้อความบนคลาวด์สำหรับ microG</string>\n    <string name=\"auth_action_step_enable_lockscreen\">กำหนดค่าการล็อคหน้าจอที่ปลอดภัย</string>\n    <string name=\"auth_action_step_perform_content_description\">คลิกเพื่อดำเนินการขั้นตอน</string>\n    <string name=\"auth_action_step_completed_content_description\">ขั้นตอนเสร็จสมบูรณ์</string>\n    <string name=\"auth_action_activity_finish\">เสร็จ</string>\n    <string name=\"prefs_account\">การตั้งค่าบัญชี</string>\n    <string name=\"prefs_account_privacy\">ข้อมูลส่วนตัวและความเป็นส่วนตัว</string>\n    <string name=\"prefs_account_security\">การลงชื่อเข้าใช้และความปลอดภัย</string>\n    <string name=\"pref_auth_trust_google_title\">เชื่อถือ Google สำหรับการอนุญาตสิทธิ์แอป</string>\n    <string name=\"pref_auth_trust_google_summary\">หากปิดการใช้งาน ผู้ใช้จะถูกถามก่อนที่จะส่งคำขออนุญาตของแอปไปยัง Google แอปพลิเคชันบางตัวจะไม่สามารถใช้บัญชี Google ได้หากปิดใช้งานตัวเลือกนี้</string>\n    <string name=\"pref_auth_visible_title\">อนุญาตให้แอปค้นหาบัญชี</string>\n    <string name=\"pref_auth_include_android_id_title\">ยืนยันตัวตนด้วยการลงทะเบียนอุปกรณ์</string>\n    <string name=\"pref_auth_strip_device_name_title\">ถอดชื่ออุปกรณ์ออกเพื่อยืนยันตัวตน</string>\n    <string name=\"pref_checkin_enable_summary\">ลงทะเบียนอุปกรณ์ของคุณกับบริการของ Google และสร้างตัวระบุอุปกรณ์เฉพาะ microG จะลบบิตที่ระบุอื่นๆ นอกเหนือจากชื่อบัญชี Google ของคุณออกจากข้อมูลการลงทะเบียน</string>\n    <string name=\"pref_device_registration_android_id\">Android ID</string>\n    <string name=\"checkin_not_registered\">ไม่ได้ลงทะเบียน</string>\n    <string name=\"checkin_last_registration\">ลงทะเบียนล่าสุด: <xliff:g example=\"เมื่อวาน, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"checkin_enable_switch\">ลงทะเบียนอุปกรณ์</string>\n    <string name=\"pref_info_status\">สถานะ</string>\n    <string name=\"pref_more_settings\">มากกว่า</string>\n    <string name=\"pref_accounts_title\">บัญชี Google</string>\n    <string name=\"pref_accounts_summary\">เพิ่มและจัดการบัญชี Google</string>\n    <string name=\"prefcat_accounts_settings_title\">ตั้งค่า</string>\n    <string name=\"prefcat_accounts_current_accounts_title\">บัญชี</string>\n    <string name=\"pref_add_account_title\">บัญชี</string>\n    <string name=\"pref_add_account_summary\">เพิ่มบัญชี Google</string>\n    <string name=\"pref_gcm_apps_title\">แอปที่ใช้ระบบ Cloud Messaging</string>\n    <string name=\"pref_gcm_apps_summary\">รายการแอปที่ลงทะเบียนสำหรับ Cloud Messaging ในปัจจุบัน</string>\n    <string name=\"pref_gcm_confirm_new_apps_title\">ยืนยันแอปใหม่</string>\n    <string name=\"pref_gcm_confirm_new_apps_summary\">ถามก่อนลงทะเบียนแอพใหม่เพื่อรับการแจ้งเตือนแบบพุช</string>\n    <string name=\"auth_action_activity_explanation\">ดำเนินการตามขั้นตอนต่อไปนี้เพื่อจะใช้งานบัญชี Google %s ของคุณบนอุปกรณ์นี้ได้</string>\n    <string name=\"auth_action_step_enable_checkin_description\">อุปกรณ์ของคุณจำเป็นต้องลงทะเบียนกับ Google อย่างน้อยหนึ่งครั้ง\\n\\nคุณสามารถปิดใช้งานการลงทะเบียนอุปกรณ์ Google ได้หลังจากตั้งค่าบัญชีเสร็จสิ้น</string>\n    <string name=\"auth_action_step_allow_microg_gcm_description\">ตามการตั้งค่าของคุณ microG จะต้องได้รับอนุญาตจากคุณก่อนจึงจะสามารถลงทะเบียนสำหรับ Cloud Messaging ได้</string>\n    <string name=\"pref_auth_visible_summary\">เมื่อเปิดการใช้งานแล้ว แอปพลิเคชันทั้งหมดในอุปกรณ์นี้จะสามารถเห็นที่อยู่อีเมลของบัญชี Google ของคุณได้ โดยไม่ต้องได้รับอนุญาตก่อน</string>\n    <string name=\"auth_action_step_enable_lockscreen_description\">บัญชี Google ของคุณได้รับการจัดการโดยที่ทำงานหรือสถาบันการศึกษาของคุณ ผู้ดูแลระบบของคุณตัดสินใจว่าอุปกรณ์จำเป็นต้องมีการล็อกหน้าจอที่ปลอดภัยก่อนจึงจะสามารถเข้าถึงข้อมูลบัญชีได้\\n\\nโปรดตั้งรหัสผ่าน PIN หรือรูปแบบการล็อกหน้าจอ</string>\n    <string name=\"pref_auth_strip_device_name_summary\">เมื่อเปิดการใช้งาน การร้องขอการตรวจสอบสิทธิ์จะไม่รวมเอาชื่ออุปกรณ์เข้าไปด้วย ซึ่งอาจทำให้อุปกรณ์ที่ไม่ได้รับอนุญาตสามารถลงชื่อเข้าใช้ได้ แต่ก็อาจส่งผลที่ไม่คาดคิดได้</string>\n    <string name=\"pref_auth_include_android_id_summary\">เมื่อปิดการใช้งาน คำขอการตรวจสอบสิทธิ์จะไม่เชื่อมโยงกับการลงทะเบียนอุปกรณ์ ซึ่งอาจทำให้อุปกรณ์ที่ไม่ได้รับอนุญาตสามารถลงชื่อเข้าใช้ได้ แต่ก็อาจส่งผลลัพธ์ที่ไม่คาดคิดได้</string>\n    <string name=\"pref_gcm_heartbeat_summary\">ระยะเวลาเป็นวินาทีที่ระบบจะส่งสัญญาณไปยังเซิร์ฟเวอร์ของ Google การเพิ่มจำนวนนี้จะช่วยลดการใช้แบตเตอรี่ แต่ข้อความพุชอาจเกิดความล่าช้าได้\\nไม่สนับสนุนอีกต่อไป แต่จะถูกแทนที่ในรุ่นถัดไป</string>\n    <string name=\"pref_gcm_ping_interval\">ช่วงเวลาปิง: <xliff:g example=\"10 minutes\">%1$s</xliff:g></string>\n    <string name=\"cond_gcm_bat_summary\">คุณได้เปิดใช้งาน Cloud Messaging แต่ว่ามีการสั่งงานการเพิ่มประสิทธิภาพแบตเตอรี่สำหรับบริการ microG ร่วมด้วย หากต้องการให้การแจ้งเตือนแบบพุชมาถึงคุณ ควรละเว้นการเพิ่มประสิทธิภาพแบตเตอรี่</string>\n    <string name=\"cond_gcm_bat_action\">ละเว้นการเพิ่มประสิทธิภาพ</string>\n    <string name=\"cond_perm_title\">ขาดการอนุญาต</string>\n    <string name=\"pref_gcm_enable_mcs_summary\">Cloud Messaging คือผู้ให้บริการการแจ้งเตือนแบบพุชที่แอปพลิเคชันของบุคคลที่สามจำนวนมากใช้ หากต้องการใช้งาน คุณต้องเปิดใช้งานการลงทะเบียนอุปกรณ์</string>\n    <string name=\"pref_gcm_heartbeat_title\">รอบในการส่งข้อความบนคลาวด์</string>\n    <string name=\"pref_about_title\">เกี่ยวกับบริการของ microG</string>\n    <string name=\"gcm_app_error_unregistering\">เกิดข้อผิดพลาดในการยกเลิกการลงทะเบียน</string>\n    <string name=\"gcm_app_not_installed_anymore\">ไม่ติดตั้งอีกต่อไป</string>\n    <string name=\"gcm_not_registered\">ไม่ได้ลงทะเบียน</string>\n    <string name=\"gcm_no_message_yet\">ไม่ได้รับข้อความใดๆจนถึงขณะนี้</string>\n    <string name=\"gcm_registered\">ลงทะเบียนแล้ว</string>\n    <string name=\"gcm_registered_since\">ลงทะเบียนตั้งแต่: <xliff:g example=\"เมื่อวาน, 14:20 น.\">%1$s</xliff:g></string>\n    <string name=\"gcm_unregister_confirm_title\">ยกเลิกการลงทะเบียน <xliff:g example=\"F-Droid\">%1$s</xliff:g>\\?</string>\n    <string name=\"gcm_unregister_after_deny_message\">คุณปฏิเสธไม่ให้แอปลงทะเบียนรับข้อความแจ้งเตือนแบบพุชที่ลงทะเบียนไปแล้ว\\nคุณต้องการยกเลิกการลงทะเบียนทันทีเพื่อไม่ให้รับข้อความแจ้งเตือนแบบพุชในอนาคตหรือไม่?</string>\n    <string name=\"pref_push_app_allow_register_summary\">อนุญาตให้แอปลงทะเบียนเพื่อรับการแจ้งเตือนแบบพุช</string>\n    <string name=\"pref_push_app_wake_for_delivery_title\">เริ่มการทำงานของแอปด้วยข้อความแบบพุช</string>\n    <string name=\"pref_push_app_wake_for_delivery_summary\">เริ่มการทำงานของแอปในขณะที่อยู่ในพื้นหลังเพื่อรับข้อความพุชที่เข้ามา</string>\n    <string name=\"prefcat_push_apps_title\">แอปกำลังใช้การแจ้งเตือนแบบพุช</string>\n    <string name=\"prefcat_push_apps_registered_title\">แอปที่ลงทะเบียนแล้ว</string>\n    <string name=\"prefcat_push_apps_unregistered_title\">แอปที่ไม่ได้ลงทะเบียน</string>\n    <string name=\"prefcat_push_networks_title\">เครือข่ายที่จะใช้สำหรับการแจ้งเตือนแบบพุช</string>\n    <string name=\"pref_test_summary_failed\">ล้มเหลว: %s</string>\n    <string name=\"pref_test_summary_warn\">คำเตือน: %s</string>\n    <string name=\"pref_test_summary_running\">กำลังทำงาน…</string>\n    <string name=\"pref_droidguard_operation_mode\">โหมดการทำงาน</string>\n    <string name=\"menu_clear_recent_requests\">ล้างคำร้องขอล่าสุด</string>\n    <string name=\"safetynet_last_run_at\">ใช้งานล่าสุด: <xliff:g example=\"เมื่อวาน, 14:20 น.\">%1$s</xliff:g></string>\n    <string name=\"profile_name_real\">จริง</string>\n    <string name=\"profile_name_user\">กำหนดเอง: %s</string>\n    <string name=\"profile_name_auto\">อัตโนมัติ: %s</string>\n    <string name=\"profile_name_system\">ระบบ: %s</string>\n    <string name=\"pref_device_registration_import_custom_profile_title\">นำเข้าโปรไฟล์ที่กำหนดเอง</string>\n    <string name=\"pref_device_registration_select_profile_title\">เลือกโปรไฟล์</string>\n    <string name=\"pref_device_registration_device_profile_category\">โปรไฟล์อุปกรณ์</string>\n    <string name=\"pref_safetynet_recent_uses\">การใช้งานล่าสุด</string>\n    <string name=\"pref_safetynet_recent_attestation_summary\">การรับรอง: %s</string>\n    <string name=\"pref_safetynet_recent_recaptcha_summary\">ReCaptcha: %s</string>\n    <string name=\"pref_safetynet_recent_recaptcha_enterprise_summary\">ReCaptcha Enterprise: %s</string>\n    <string name=\"pref_safetynet_recent_copy_json\">คัดลอกข้อมูล JSON JWS</string>\n    <string name=\"pref_safetynet_recent_advice\">คำแนะนำ</string>\n    <string name=\"pref_safetynet_recent_eval_type\">ประเภทการประเมิน</string>\n    <string name=\"pref_safetynet_recent_response_status\">สถานะการตอบกลับ</string>\n    <string name=\"pref_safetynet_recent_cat_response\">สถานะการตอบกลับ</string>\n    <string name=\"pref_safetynet_recent_cat_request\">ร้องขอข้อมูล</string>\n    <string name=\"pref_safetynet_recent_nonce\">Nonce (เลขฐานสิบหก)</string>\n    <string name=\"pref_safetynet_test_cts_failed\">CTS ล้มเหลว</string>\n    <string name=\"pref_safetynet_test_integrity_failed\">การยืนยันล้มเหลว</string>\n    <string name=\"pref_safetynet_test_not_completed\">ยังไม่เสร็จสมบูรณ์</string>\n    <string name=\"pref_safetynet_test_no_result\">ไม่มีผลลัพธ์</string>\n    <string name=\"pref_safetynet_test_invalid_json\">JSON ไม่ถูกต้อง</string>\n    <string name=\"push_notifications_summary_automatic\">เปิด / อัตโนมัติ: %s</string>\n    <string name=\"push_notifications_summary_manual\">เปิด / แมนนวล: %s</string>\n    <string name=\"push_notifications_summary_values_seconds\">%s วินาที</string>\n    <string name=\"push_notifications_summary_values_minutes\">%s นาที</string>\n    <string name=\"pref_vending_summary_licensing_on\">เปิดใบอนุญาต</string>\n    <string name=\"pref_vending_summary_licensing_off\">ปิดใบอนุญาต</string>\n    <string name=\"pref_vending_licensing_category\">การอนุญาตสิทธิ์ใช้งาน Google Play</string>\n    <string name=\"pref_vending_licensing_enable_switch\">ตอบคำขอตรวจสอบใบอนุญาต</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_switch\">เพิ่มแอปฟรีลงในไลบรารีโดยอัตโนมัติ</string>\n    <string name=\"feedback_disabled\">ขณะนี้ไม่สามารถให้ข้อเสนอแนะได้</string>\n    <string name=\"backup_disabled\">ไม่สามารถสำรองข้อมูลได้ในขณะนี้</string>\n    <string name=\"pref_vending_billing_category\">การเรียกเก็บเงินของ Google Play</string>\n    <string name=\"pref_vending_billing_enable_switch\">จัดการคำขอเรียกเก็บเงิน</string>\n    <string name=\"pref_vending_billing_enable_summary\">เมื่อเปิดใช้งานแล้ว แอปบางตัวสามารถทำการซื้อหรือเริ่มการสมัครสมาชิกผ่านบริการ Play Billing ของ Google ได้</string>\n    <string name=\"pref_vending_billing_note_licensing\">แอปบางตัวอาจต้องการให้คุณเปิดใช้การตรวจสอบใบอนุญาตเพื่อยืนยันการซื้อของคุณด้วย</string>\n    <string name=\"credentials_assisted_cancel\">ยกเลิก</string>\n    <string name=\"credentials_assisted_continue\">ดำเนินการต่อ</string>\n    <string name=\"credentials_assisted_confirmation_header\">การลงชื่อเข้าใช้ของคุณ</string>\n    <string name=\"credentials_assisted_continue_as_user_button_label\">ดำเนินการต่อเป็น %1$s</string>\n    <string name=\"credentials_assisted_sign_back_title\">ลงชื่อเข้าใช้ %1$s อีกครั้งด้วย Google</string>\n    <string name=\"credentials_assisted_signin_consent_header\">ลงนามในฐานะ %1$s</string>\n    <string name=\"credentials_assisted_signin_description\">คุณสามารถจัดการการลงชื่อเข้าใช้ด้วย Google ในบัญชี Google ของคุณได้</string>\n    <string name=\"credentials_assisted_choose_account_label\">เลือกบัญชี</string>\n    <string name=\"credentials_assisted_choose_account_subtitle\">เพื่อดำเนินการต่อ %1$s</string>\n    <string name=\"pref_about_summary\">ข้อมูลเวอร์ชันและไลบรารีที่ใช้</string>\n    <string name=\"gcm_unregister_app\">ยกเลิกการลงทะเบียน</string>\n    <string name=\"gcm_last_message_at\">ข้อความล่าสุด: <xliff:g example=\"เมื่อวาน, 14:20 น.\">%1$s</xliff:g></string>\n    <string name=\"gcm_unregister_confirm_message\">แอปบางตัวจะไม่ลงทะเบียนใหม่โดยอัตโนมัติและ/หรือไม่มีตัวเลือกให้ดำเนินการดังกล่าวด้วยตนเอง แอปเหล่านี้อาจไม่ทำงานอย่างถูกต้องหลังจากยกเลิกการลงทะเบียน\\nดำเนินการต่อหรือไม่?</string>\n    <string name=\"safetynet_intro\">Google SafetyNet เป็นระบบการรับรองอุปกรณ์ ซึ่งรับรองว่าอุปกรณ์ได้รับการรักษาความปลอดภัยอย่างเหมาะสมและเข้ากันได้กับ Android CTS แอปพลิเคชันบางตัวใช้ SafetyNet เพื่อเหตุผลด้านความปลอดภัยหรือเป็นข้อกำหนดเบื้องต้นสำหรับการป้องกันการงัดแงะ\\n\\nmicroG GmsCore มีการนำ SafetyNet มาใช้ได้ฟรี แต่เซิร์ฟเวอร์อย่างเป็นทางการต้องการให้มีการลงนามคำขอ SafetyNet โดยใช้ระบบ ที่เป็นกรรมสิทธิ์ ของDroidGuard</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_summary\">แอปฟรีสามารถตรวจสอบว่าดาวน์โหลดมาจาก Google Play หรือไม่ เพิ่มแอปฟรีลงในไลบรารีบัญชีของคุณโดยอัตโนมัติเพื่อให้ผ่านการตรวจสอบสำหรับแอปฟรีทั้งหมดที่มีให้คุณใช้งานในปัจจุบัน</string>\n    <string name=\"pref_vending_license_enable_summary\">แอปบางตัวต้องได้รับการยืนยันว่าคุณซื้อแอปเหล่านั้นจาก Google Play เมื่อแอปร้องขอ microG จะสามารถดาวน์โหลดหลักฐานการซื้อจาก Google ได้ หากปิดใช้งานหรือไม่ได้เพิ่มบัญชี Google คำขอตรวจสอบใบอนุญาตจะถูกละเว้น</string>\n    <string name=\"limited_services_dialog_information\">คุณกำลังใช้บริการ microG Limited ซึ่งต่างจากบริการ microG ทั่วไป ฟังก์ชันนี้จะทำงานได้เฉพาะกับแอปที่ใช้ไลบรารี microG เท่านั้น ไม่ใช่กับแอปบน Google Play ซึ่งหมายความว่าแอปพลิเคชันส่วนใหญ่จะละเว้นบริการเหล่านี้</string>\n    <string name=\"pref_vending_billing_note_experimental\">ฟีเจอร์นี้อยู่ในขั้นทดลองและอาจนำไปสู่การสูญเสียเงิน คุณได้รับคำเตือนแล้ว</string>\n    <string name=\"credentials_assisted_signin_consent\">หากดำเนินการต่อ Google จะแชร์ชื่อ ที่อยู่อีเมล และรูปโปรไฟล์ของคุณกับ %1$s ดูนโยบายความเป็นส่วนตัวและข้อกำหนดในการให้บริการของ %1$s</string>\n    <string name=\"credentials_assisted_signin_button_text_long\">ลงชื่อเข้าใช้ด้วย Google</string>\n    <string name=\"gcm_enable_switch\">รับการแจ้งเตือนแบบพุช</string>\n    <string name=\"pref_push_app_allow_register_title\">อนุญาตให้ลงทะเบียน</string>\n    <string name=\"gcm_allow_app_popup\">อนุญาตให้ <xliff:g example=\"F-Droid\">%1$s</xliff:g> ลงทะเบียนเพื่อรับการแจ้งเตือนแบบพุชหรือไม่?</string>\n    <string name=\"gcm_messages_counter\">ข้อความ: <xliff:g example=\"123\">%1$d</xliff:g> (<xliff:g example=\"12345\">%2$d</xliff:g> ไบต์)</string>\n    <string name=\"gcm_network_state_disconnected\">ถูกตัดการเชื่อมต่อ</string>\n    <string name=\"gcm_network_state_connected\">เชื่อมต่อตั้งแต่ <xliff:g example=\"2 ชั่วโมงที่แล้ว\">%1$s</xliff:g></string>\n    <string name=\"safetynet_enable_switch\">อนุญาติให้รับรองอุปกรณ์</string>\n    <string name=\"pref_recaptcha_test_title\">ทดสอบ ReCAPTCHA</string>\n    <string name=\"pref_recaptcha_enterprise_test_title\">ทดสอบ ReCAPTCHA Enterprise</string>\n    <string name=\"pref_test_summary_passed\">ผ่านการทดสอบทั้งหมด</string>\n    <string name=\"pref_safetynet_test_title\">ทดสอบการรับรอง SafetyNet</string>\n    <string name=\"pref_droidguard_unsupported_summary\">อุปกรณ์นี้ไม่รองรับการทำงานของ DroidGuard บริการ SafetyNet อาจทำงานไม่ถูกต้อง</string>\n    <string name=\"prefcat_safetynet_apps_title\">แอปกำลังใช้งาน SafetyNet</string>\n    <string name=\"profile_name_native\">เนทีฟ</string>\n    <string name=\"pref_device_registration_serial_title\">ซีเรียล</string>\n    <string name=\"pref_device_registration_import_custom_profile_summary\">นำเข้าโปรไฟล์อุปกรณ์จากไฟล์</string>\n    <string name=\"pref_safetynet_recent_request_type\">ประเภทคำร้องขอ</string>\n    <string name=\"pref_safetynet_recent_cat_basic\">ข้อมูลพื้นฐาน</string>\n    <string name=\"pref_safetynet_recent_token\">โทเค็น</string>\n    <string name=\"pref_safetynet_test_integrity_cts_passed\">ยืนยันเข้ากันได้และผ่าน CTS</string>\n    <string name=\"pref_safetynet_recent_copied\">คัดลอกไปยังคลิปบอร์ดแล้ว!</string>\n    <string name=\"pref_safetynet_recent_request_time\">เวลาการร้องขอ</string>\n    <string name=\"push_notifications_summary_off\">ปิด</string>\n    <string name=\"limited_services_dialog_information_ack\">ฉันเข้าใจ</string>\n    <string name=\"pref_vending_asset_delivery_switch\">เปิดใช้งานการส่งเนื้อหาเพิ่มเติม ตามความต้องการ</string>\n    <string name=\"pref_vending_asset_delivery_category\">การจัดส่งเนื้อหาเพิ่มเติมของ Google Play</string>\n    <string name=\"pref_vending_asset_delivery_summary\">ดาวน์โหลดเนื้อหาเพิ่มเติมเมื่อได้รับการร้องขอจากแอปที่ใช้ Play Asset Delivery</string>\n    <string name=\"pref_vending_asset_device_sync_summary\">แอปพลิเคชันที่ใช้ Play Asset Delivery จะดาวน์โหลดทรัพยากรเพิ่มเติมตามข้อมูลของอุปกรณ์ที่ใช้งานในขณะนั้น</string>\n    <string name=\"pref_vending_asset_device_sync_switch\">เปิดใช้งานการซิงค์ข้อมูลอุปกรณ์</string>\n    <string name=\"games_leaderboards_score_label\">คะแนน：: %1$s</string>\n    <string name=\"games_achievements_empty_text\">ไม่มีความสำเร็จสำหรับเกมนี้</string>\n    <string name=\"games_leaderboard_list_title\">อันดับ</string>\n    <string name=\"games_delete_snapshot_dialog_message\">คุณแน่ใจว่าต้องการลบเกมที่บันทึกไว้นี้หรือไม่?</string>\n    <string name=\"games_achievement_extra_text\">%1$s ค่าประสบการณ์</string>\n    <string name=\"games_achievement_list_title\">ความสำเร็จ</string>\n    <string name=\"games_api_access_denied\">ไม่มีบัญชีใดบนอุปกรณ์นี้สามารถเข้าถึง Games API ได้</string>\n    <string name=\"games_achievement_locked_content_description\">ล็อค</string>\n    <string name=\"games_achievement_unlocked_content_description\">ปลดล็อค</string>\n    <string name=\"games_leaderboard_empty_text\">ไม่มีกระดานผู้นำสำหรับเกมนี้</string>\n    <string name=\"games_snapshot_empty_text\">ยังไม่มีการบันทึกเกมใดๆ</string>\n    <string name=\"games_snapshot_choose_btn_text\">เลือก</string>\n    <string name=\"games_delete_snapshot_dialog_title\">ลบเกมที่บันทึกไว้</string>\n    <string name=\"games_delete_snapshot_dialog_cancel\">ยกเลิก</string>\n    <string name=\"games_delete_snapshot_dialog_ok\">ตกลง</string>\n    <string name=\"games_delete_snapshot_error\">การลบข้อมูลล้มเหลว กรุณาลองใหม่อีกครั้งในภายหลัง</string>\n    <string name=\"games_snapshot_delete_btn_text\">ลบ</string>\n    <string name=\"games_leaderboard_score_empty_text\">เหลือเชื่อ! ไม่มีคะแนนสูงสุดสาธารณะสำหรับเกมนี้</string>\n    <string name=\"service_name_work_profile\">โปรไฟล์การทำงาน</string>\n    <string name=\"pref_vending_split_install_switch\">การติดตั้งส่วนประกอบตามความต้องการ</string>\n    <string name=\"camera_permission_dialog_button\">ตกลง</string>\n    <string name=\"camera_permission_dialog_title\">ต้องได้รับอนุญาตการใช้งานกล้อง</string>\n    <string name=\"pref_vending_licensing_split_install_summary\">อนุญาตให้แอปดาวน์โหลดและติดตั้งส่วนประกอบเพิ่มเติม</string>\n    <string name=\"pref_workprofile_create_account\">อนุญาติให้ตั้งค่าบัญชีงาน</string>\n    <string name=\"pref_workprofile_intro\">เมื่อตั้งค่าโปรไฟล์การทำงานสำหรับสถานที่ทำงานหรือสถาบันการศึกษา การตั้งค่าอาจพยายามเชื่อมต่อกับ Google เพื่อเปิดใช้งานการดาวน์โหลดแอปไปยังโปรไฟล์นั้น</string>\n    <string name=\"pref_vending_feature_delivery\">การส่งมอบฟีเจอร์ของ Google Play</string>\n    <string name=\"pref_workprofile_disclaimer\">คุณมีหน้าที่รับผิดชอบในการตรวจสอบให้แน่ใจว่าการใช้งาน microG ของคุณเป็นไปตามนโยบายขององค์กร microG จัดทำขึ้นโดยใช้ความพยายามอย่างดีที่สุด และไม่สามารถรับประกันว่าจะทำงานตามที่คาดหวังได้</string>\n    <string name=\"barcode_scanner_brand\">สแกนโดย microG ในนามของ %1$s</string>\n    <string name=\"camera_permission_dialog_message\">บริการ microG ต้องเข้าถึงกล้องของอุปกรณ์ของคุณเพื่อสแกนรหัสสำหรับ %1$s\\n\\nหากต้องการเปิดใช้งาน โปรดให้สิทธิ์กล้องแก่บริการ microG ในการตั้งค่า</string>\n    <string name=\"credentials_assisted_signin_add_account\">เพิ่มบัญชี</string>\n    <string name=\"credentials_assisted_choose_account_error_tips\">บัญชีผู้ใช้งานผิดปกติ</string>\n    <string name=\"auth_action_reauth_notification_title\">จำเป็นต้องดำเนินการกับบัญชี</string>\n    <string name=\"pref_auth_two_step_verification_title\">รับการแจ้งเตือนการยืนยันตัวตนสองขั้นตอน</string>\n    <string name=\"pref_auth_two_step_verification_summary\">เมื่อเปิดใช้งาน อุปกรณ์จะสามารถรับการแจ้งเตือนการยืนยันแบบ 2 ขั้นตอนจาก Google ได้ (จำเป็นต้องเปิดใช้งาน Cloud Messaging ด้วย)</string>\n    <string name=\"pref_game_accounts_title\">บัญชีเกม Google</string>\n    <string name=\"pref_auto_create_player\">อนุญาตให้ลงทะเบียนบัญชี Play Games</string>\n    <string name=\"pref_auto_create_player_intro\">เมื่อเล่นเกม คุณจำเป็นต้องใช้บัญชี Play Games ในการเข้าสู่ระบบและบันทึกฟังก์ชันต่าง ๆ ที่เกี่ยวข้องกับเกม เช่น ความสำเร็จ (achievements), กระดานผู้นำ (leaderboards), และข้อมูลบันทึก (archives) เป็นต้น หลังจากปิดการใช้งานแล้ว บัญชี Google ที่ไม่ได้เชื่อมโยงกับบัญชี Play Games จะไม่ถูกลงทะเบียนโดยอัตโนมัติ และเกมจะไม่สามารถเข้าสู่ระบบหรือเล่นได้</string>\n    <string name=\"pref_allow_upload_game_played\">อนุญาตให้อัพโหลดเกมที่เล่น</string>\n    <string name=\"pref_allow_upload_game_played_summary\">เมื่อปิดใช้งาน เกมจะไม่รายงานสถานะการเล่นเกมหลังจากเข้าสู่ระบบเกม และเกมบางเกมอาจไม่สามารถเข้าสู่ระบบได้</string>\n    <string name=\"pref_change_default_game_player\">เปลี่ยนบัญชีสำหรับเกม</string>\n    <string name=\"pref_change_default_game_player_summary\">เปลี่ยนบัญชีเริ่มต้นสำหรับเกม &amp; เปลี่ยนบัญชีตามเกม</string>\n    <string name=\"pref_delete_game_account_data\">ลบข้อมูล Play Games</string>\n    <string name=\"pref_delete_game_account_data_summary\">ลบบัญชี Play Games และข้อมูลทั้งหมด และลบข้อมูลเกมแต่ละรายการ</string>\n    <string name=\"games_state_description_signed_out\">ออกจากระบบ</string>\n    <string name=\"games_change_button_text\">ลบ</string>\n    <string name=\"games_change_default_account_section_title\">เปลี่ยนบัญชีเริ่มต้นสำหรับเกม</string>\n    <string name=\"games_change_default_account_description\">บัญชีเริ่มต้น: %1$s</string>\n    <string name=\"games_change_default_account_explanation\">บัญชีนี้ใช้เพื่อลงชื่อเข้าใช้เกม บันทึกความคืบหน้าของเกม และบันทึกการตั้งค่าของคุณโดยอัตโนมัติ การเปลี่ยนบัญชีเริ่มต้นหรือการออกจากระบบอาจรีเซ็ตความคืบหน้าและการตั้งค่าของเกมที่คุณเล่นไปแล้ว</string>\n    <string name=\"games_change_per_game_title\">เปลี่ยนบัญชีตามเกม</string>\n    <string name=\"games_change_per_game_description\">การเปลี่ยนบัญชีสำหรับเกมที่เลือกหรือการออกจากระบบอาจทำให้ความคืบหน้าและการตั้งค่าเกมของคุณได้รับการรีเซ็ต</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_title\">เลือกตัวเลือกสำหรับบัญชีเริ่มต้นใหม่</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_description\">บัญชีปัจจุบันที่ตั้งเป็นค่าเริ่มต้น: %1$s</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_title\">เปลี่ยนบัญชีเริ่มต้นเฉพาะเกมใหม่เท่านั้น</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_description\">คุณจะไม่สูญเสียการเข้าถึงความคืบหน้าและการตั้งค่าของเกมที่คุณเล่น แต่ความคืบหน้าของคุณจะถูกแบ่งระหว่างบัญชี</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_title\">เปลี่ยนบัญชีเริ่มต้นสำหรับเกมทั้งหมด</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_description\">คุณอาจสูญเสียการเข้าถึงความคืบหน้าและการตั้งค่าของเกมที่คุณเล่นไปแล้ว เราจะรีสตาร์ทเกมเพื่อนำการเปลี่ยนแปลงของคุณไปใช้</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_title\">ออกจากระบบเกมทั้งหมด</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_description\">คุณอาจสูญเสียการเข้าถึงความคืบหน้าและการตั้งค่าของเกมที่คุณเล่นไปแล้ว เราจะรีสตาร์ทเกมเพื่อนำการเปลี่ยนแปลงของคุณไปใช้</string>\n    <string name=\"games_change_per_game_dialog_title\">เลือกตัวเลือกสำหรับเกมนี้</string>\n    <string name=\"games_change_per_game_dialog_description\">การเปลี่ยนบัญชีหรือการออกจากระบบอาจทำให้ความคืบหน้าและการตั้งค่าเกมของคุณถูกรีเซ็ต</string>\n    <string name=\"games_change_per_game_dialog_option_use_player\">ใช้งาน %1$s</string>\n    <string name=\"games_change_per_game_dialog_option_use_player_snackbar_success_message\">คุณจะลงชื่อเข้าใช้เกมนี้ด้วย %1$s</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out\">ออกจากระบบ</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out_snackbar_success_message\">ตอนนี้คุณได้ออกจากเกมนี้แล้ว</string>\n    <string name=\"games_change_sign_out_of_all_games_snackbar_success_message\">ตอนนี้คุณได้ออกจากระบบเกมทั้งหมดแล้ว</string>\n    <string name=\"games_change_default_account_for_all_games_snackbar_success_message\">คุณจะลงชื่อเข้าใช้เกมทั้งหมดด้วย %1$s</string>\n    <string name=\"games_change_default_account_for_new_games_snackbar_success_message\">คุณจะลงชื่อเข้าใช้เกมใหม่ด้วย %1$s</string>\n    <string name=\"games_account_display_content\">บัญชีปัจจุบัน: %1$s</string>\n    <string name=\"games_delete_profile_header\">ลบบัญชี Play Games และข้อมูลทั้งหมด</string>\n    <string name=\"games_delete_profile_explanation\">ลบบัญชี Google Play Games, XP และข้อมูลโปรไฟล์ทั้งหมดของคุณอย่างถาวร การดำเนินการนี้อาจลบคะแนน ความคืบหน้า (เกมที่บันทึกไว้) และการตั้งค่าในเกมที่คุณเล่นด้วย</string>\n    <string name=\"games_delete_profile_button\">ลบถาวร</string>\n    <string name=\"games_delete_game_data_header\">ลบข้อมูลเกมแต่ละรายการ</string>\n    <string name=\"games_delete_game_data_explanation\">คุณสามารถลบข้อมูลแต่ละรายการของเกมที่คุณเล่นผ่าน Google Play Games ได้อย่างถาวร การดำเนินการนี้จะลบคะแนน ความคืบหน้า (เกมที่บันทึกไว้) และการตั้งค่าของเกมที่คุณเลือก</string>\n    <string name=\"games_delete_profile_dialog_title\">คุณแน่ใจว่าต้องการลบบัญชีนี้หรือไม่?</string>\n    <string name=\"games_delete_profile_explanation_with_gamer_name\">ลบบัญชี Google Play Games ของคุณอย่างถาวรสำหรับชื่อเกมเมอร์ <b>%1$s</b> (<b>%2$s</b>), XP และข้อมูลโปรไฟล์ทั้งหมด การดำเนินการนี้อาจลบคะแนน ความคืบหน้า (เกมที่บันทึกไว้) และการตั้งค่าในเกมที่คุณเล่นด้วย</string>\n    <string name=\"games_state_description_delete\">ลบ</string>\n    <string name=\"games_delete_profile_dialog_message\">การดำเนินการนี้ไม่สามารถย้อนกลับได้</string>\n    <string name=\"games_delete_profile_fail\">ไม่สามารถลบโปรไฟล์ของคุณได้ โปรดลองอีกครั้งในภายหลัง</string>\n    <string name=\"games_delete_game_data_confirm_dialog_title\">ลบข้อมูลสำหรับ %1$s</string>\n    <string name=\"games_delete_game_data_confirm_dialog_message\">การลบข้อมูลของคุณอย่างถาวรสำหรับ %1$s จะทำให้คะแนน ความคืบหน้า (เกมที่บันทึกไว้) และการตั้งค่าเกมใน Google Play Games ถูกลบออก</string>\n    <string name=\"games_popup_signin_welcome\">เฮ้ %1$s</string>\n    <string name=\"service_name_google_location_sharing\">การแชร์ตำแหน่งของ Google</string>\n    <string name=\"location_sharing_description\">จัดการการแชร์ตำแหน่งแบบเรียลไทม์ของคุณผ่านแอปและบริการของ Google จากอุปกรณ์นี้</string>\n    <string name=\"location_sharing_learn_more\">เรียนรู้เพิ่มเติมเกี่ยวกับการแชร์ตำแหน่ง</string>\n    <string name=\"location_sharing_switch_text\">ใช้การแชร์ตำแหน่ง</string>\n    <string name=\"location_sharing_turn_off_notify_hint\">หากคุณปิดการแชร์ตำแหน่งสำหรับอุปกรณ์นี้ ผู้คนที่คุณแชร์ตำแหน่งด้วยจะไม่ได้รับการแจ้งเตือน</string>\n    <string name=\"location_sharing_off_previous_hint\">เฉพาะตำแหน่งที่คุณแชร์ครั้งสุดท้ายเท่านั้นที่จะพร้อมใช้งานจนกว่าคุณจะเปิดใช้งานอีกครั้ง</string>\n    <string name=\"location_sharing_disabled\">ไม่มีการแชร์ตำแหน่งที่ใช้งานอยู่สำหรับบัญชีนี้</string>\n    <string name=\"location_sharing_turn_on_hint\">เมื่อคุณเริ่มแชร์ตำแหน่งที่ตั้งจากแอปหรือบริการของ Google แล้ว คุณสามารถจัดการการแชร์ตำแหน่งที่ตั้งได้จากที่นี่\\n\\nหากต้องการเริ่มแชร์ตำแหน่งที่ตั้งของคุณ ให้ไปที่ Google Maps หรือ Family Link</string>\n    <string name=\"location_sharing_turn_off_title\">ปิดการแชร์ตำแหน่ง</string>\n    <string name=\"location_sharing_turn_off_hint\">คุณอาจยังคงแชร์ตำแหน่งของคุณจากอุปกรณ์อื่นๆ ที่ลงชื่อเข้าใช้บัญชี Google เดียวกัน หรือจากแอปที่ไม่ใช่ของ Google โปรดตรวจสอบการตั้งค่าการแชร์ตำแหน่งของคุณในส่วนที่เกี่ยวข้อง\\n\\nคนที่คุณแชร์ตำแหน่งด้วยจะยังคงเห็นตำแหน่งที่คุณแชร์ล่าสุดอยู่</string>\n    <string name=\"location_sharing_turn_off_cancel\">ต่อไป</string>\n    <string name=\"location_sharing_turn_off_confirm\">ปิด</string>\n    <string name=\"location_sharing_confirm_dialog_title\">เปิดใช้งานการแชร์ตำแหน่ง</string>\n    <string name=\"location_sharing_confirm_dialog_text\">คนที่คุณแชร์ตำแหน่งด้วยจะสามารถดูข้อมูลต่อไปนี้ได้เสมอ:\\n·ชื่อและรูปถ่ายของคุณ\\n·ตำแหน่งล่าสุดของอุปกรณ์ แม้ในขณะที่คุณไม่ได้ใช้บริการ Google\\n·ระดับพลังงานแบตเตอรี่ของอุปกรณ์ และหากกำลังชาร์จ\\n·เวลาถึงและออกเดินทางของคุณ หากพวกเขาเพิ่มการแจ้งเตือนการแชร์ตำแหน่ง</string>\n    <string name=\"family_management_title\">ครอบครัว</string>\n    <string name=\"family_management_retry\">ลองใหม่อีกครั้ง</string>\n    <string name=\"family_management_load_error\">การโหลดเนื้อหาล้มเหลว</string>\n    <string name=\"family_management_toolbar_back\">ย้อนกลับ</string>\n    <string name=\"family_management_toolbar_more\">มากกว่า</string>\n    <string name=\"family_management_exit_family_group\">ออกจากกลุ่มครอบครัว</string>\n    <string name=\"family_management_delete_family_group\">ลบกลุ่มครอบครัว</string>\n    <string name=\"family_management_leave_family_password_title\">ยืนยันรหัสผ่านเพื่อออกจากกลุ่มครอบครัว</string>\n    <string name=\"family_management_delete_family_password_title\">ยืนยันรหัสผ่านเพื่อลบกลุ่มครอบครัว</string>\n    <string name=\"family_management_remove_member_password_title\">ยืนยันรหัสผ่านเพื่อลบ %s</string>\n    <string name=\"family_management_invite_family_member\">เชิญสมาชิกในครอบครัว</string>\n    <string name=\"family_management_invite_slots_left\">เหลือคำเชิญอีก %1$d รายการ</string>\n    <string name=\"family_management_cancel_invite\">ยกเลิกคำเชิญ</string>\n    <string name=\"family_management_cancel_invite_success\">ยกเลิกคำเชิญสำเร็จ</string>\n    <string name=\"family_management_cancel_invite_error\">มีปัญหาในการยกเลิกคำเชิญ โปรดลองอีกครั้ง</string>\n    <string name=\"family_management_remove_member\">ลบสมาชิก</string>\n    <string name=\"family_management_member_removed_success\">%s ถูกลบออกจากกลุ่มครอบครัวของคุณแล้ว</string>\n    <string name=\"family_management_member_remove_failed\">มีปัญหาในการลบ %s โปรดลองอีกครั้ง</string>\n    <string name=\"family_management_leave_family_error_message\">มีปัญหาในการออกจากกลุ่มครอบครัว โปรดลองอีกครั้ง</string>\n    <string name=\"family_management_exist_group_success\">คุณได้ออกจากกลุ่มครอบครัวของคุณแล้ว…</string>\n    <string name=\"family_management_delete_group_success\">กลุ่มครอบครัวถูกลบแล้ว</string>\n    <string name=\"family_management_delete_group_failure\">ไม่สามารถลบกลุ่มโฮมได้</string>\n    <string name=\"family_management_delete_group_cancel\">ยกเลิก</string>\n    <string name=\"family_management_delete_group_confirm\">ตกลง</string>\n    <string name=\"family_management_input_pwd\">กรุณากรอกรหัสผ่านของคุณ</string>\n    <string name=\"family_management_invite_sent_date_format\">ส่งคำเชิญเมื่อ %s</string>\n    <string name=\"family_management_invite_send\">ส่งคำเชิญแล้ว</string>\n    <string name=\"family_management_pwd_error\">รหัสผ่านผิด กรุณากรอกใหม่อีกครั้ง</string>\n    <string name=\"pref_app_install_settings_title\">การตั้งค่าตัวติดตั้งแอป</string>\n    <string name=\"pref_app_install_switch_title\">อนุญาตให้ติดตั้งแอป</string>\n    <string name=\"pref_app_install_other_apps_note\">การอนุญาตให้ติดตั้งแอพพลิเคชั่นจากแหล่งอื่น</string>\n    <string name=\"pref_app_install_permission_instruction\">เพื่อให้แน่ใจว่าแอปที่คุณติดตั้งทำงานอย่างถูกต้อง โปรดอนุญาตให้ microG Companion ติดตั้งแอปที่ดาวน์โหลดจากแหล่งอื่น</string>\n    <string name=\"prefcat_app_install_list_title\">แอปที่ใช้ App Installer</string>\n    <string name=\"service_name_device_attestation\">การรับรองความน่าเชื่อถือของอุปกรณ์</string>\n    <string name=\"prefcat_device_attestation_apps_title\">แอปที่ใช้การรับรองความน่าเชื่อถือของอุปกรณ์</string>\n    <string name=\"pref_device_attestation_app_allow_requests_title\">อนุญาตคำขอ</string>\n    <string name=\"pref_device_attestation_app_allow_requests_summary\">อนุญาตให้แอปร้องขอการรับรองความน่าเชื่อถือของอุปกรณ์</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-tr/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"permission_service_all_label\">Tüm Google servisleri</string>\n    <string name=\"permission_service_all_description\">Uygulamanın, ilgili herhangi bir Google hesabı aracılığıyla tüm Google servislerine erişmesine izin verir.</string>\n    <string name=\"permission_service_adsense_label\">AdSense</string>\n    <string name=\"permission_service_ah_label\">Google App Engine</string>\n    <string name=\"permission_service_blogger_label\">Blogger</string>\n    <string name=\"permission_service_blogger_description\">Uygulamanın, ilgili herhangi bir Google hesabı aracılığıyla Blogger\\'a erişmesine izin verir.</string>\n    <string name=\"permission_service_cl_label\">Google Takvim</string>\n    <string name=\"permission_service_cl_description\">Uygulamanın, ilgili herhangi bir Google hesabı aracılığıyla Google Takvim\\'e erişmesine izin verir.</string>\n    <string name=\"permission_service_cp_label\">Kişiler</string>\n    <string name=\"permission_service_cp_description\">Uygulamanın, ilgili herhangi bir Google hesabı aracılığıyla Kişiler\\'e erişmesine izin verir.</string>\n    <string name=\"permission_service_dodgeball_label\">Dodgeball</string>\n    <string name=\"permission_service_finance_label\">Google Finans</string>\n    <string name=\"permission_service_gbase_label\">Google Base</string>\n    <string name=\"permission_service_grandcentral_label\">Google Voice</string>\n    <string name=\"permission_service_groups2_label\">Google Gruplar</string>\n    <string name=\"permission_service_grandcentral_description\">Uygulamanın, ilgili herhangi bir Google hesabı aracılığıyla Google Voice\\'a erişmesine izin verir.</string>\n    <string name=\"permission_service_health_label\">Google Health</string>\n    <string name=\"permission_service_health_description\">Uygulamanın, ilgili herhangi bir Google hesabı aracılığıyla Google Health\\'a erişmesine izin verir.</string>\n    <string name=\"permission_service_ig_label\">iGoogle</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.readonly\">YouTube hesabını görüntüle</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.upload\">YouTube videolarını yönet</string>\n    <string name=\"permission_service_dodgeball_description\">Uygulamanın, ilgili herhangi bir Google hesabı aracılığıyla Dodgeball\\'a erişmesine izin verir.</string>\n    <string name=\"permission_service_finance_description\">Uygulamanın, ilgili herhangi bir Google hesabı aracılığıyla Google Finans\\'a erişmesine izin verir.</string>\n    <string name=\"permission_service_gbase_description\">Uygulamanın, ilgili herhangi bir Google hesabı aracılığıyla Google Base\\'e erişmesine izin verir.</string>\n    <string name=\"permission_service_groups2_description\">Uygulamanın, ilgili herhangi bir Google hesabı aracılığıyla Google Gruplar\\'a erişmesine izin verir.</string>\n    <string name=\"permission_service_android_label\">Android servisleri</string>\n    <string name=\"permission_service_android_description\">Uygulamanın, ilgili herhangi bir Google hesabı aracılığıyla Android servislerine erişmesine izin verir.</string>\n    <string name=\"permission_service_adsense_description\">Uygulamanın, ilgili herhangi bir Google hesabı aracılığıyla AdSense\\'e erişmesine izin verir.</string>\n    <string name=\"permission_service_adwords_label\">AdWords</string>\n    <string name=\"permission_service_adwords_description\">Uygulamanın, ilgili herhangi bir Google hesabı aracılığıyla AdWords\\'e erişmesine izin verir.</string>\n    <string name=\"permission_service_ah_description\">Uygulamanın, ilgili herhangi bir Google hesabı aracılığıyla Google App Engine\\'e erişmesine izin verir.</string>\n    <string name=\"permission_service_ig_description\">Uygulamanın, ilgili herhangi bir Google hesabı aracılığıyla iGoogle\\'a erişmesine izin verir.</string>\n    <string name=\"permission_service_jotspot_label\">JotSpot</string>\n    <string name=\"permission_service_jotspot_description\">Uygulamanın, ilgili herhangi bir Google hesabı aracılığıyla JotSpot\\'a erişmesine izin verir.</string>\n    <string name=\"permission_service_knol_label\">Knol</string>\n    <string name=\"permission_service_knol_description\">Uygulamanın, ilgili herhangi bir Google hesabı aracılığıyla Knol\\'a erişmesine izin verir.</string>\n    <string name=\"permission_service_lh2_label\">Picasa Web Albümleri</string>\n    <string name=\"permission_service_lh2_description\">Uygulamanın, ilgili herhangi bir Google hesabı aracılığıyla Picasa Web Albümleri\\'ne erişmesine izin verir.</string>\n    <string name=\"permission_service_local_label\">Google Haritalar</string>\n    <string name=\"permission_service_local_description\">Uygulamanın, ilgili herhangi bir Google hesabı aracılığıyla Google Haritalar\\'a erişmesine izin verir.</string>\n    <string name=\"permission_service_news_label\">Google Haberler</string>\n    <string name=\"permission_service_mail_label\">Google E-Posta</string>\n    <string name=\"permission_service_news_description\">Uygulamanın, ilgili herhangi bir Google hesabı aracılığıyla Google Haberler\\'e erişmesine izin verir.</string>\n    <string name=\"permission_service_notebook_label\">Google Not Defteri</string>\n    <string name=\"permission_service_notebook_description\">Uygulamanın, ilgili herhangi bir Google hesabı aracılığıyla Google Not Defteri\\'ne erişmesine izin verir.</string>\n    <string name=\"permission_service_orkut_label\">Orkut</string>\n    <string name=\"permission_service_print_label\">Google Kitap Arama</string>\n    <string name=\"permission_service_print_description\">Uygulamanın, ilgili herhangi bir Google hesabı aracılığıyla Google Kitap Arama\\'ya erişmesine izin verir.</string>\n    <string name=\"permission_service_sierra_label\">Google Checkout hesapları</string>\n    <string name=\"permission_service_orkut_description\">Uygulamanın, ilgili herhangi bir Google hesabı aracılığıyla Orkut\\'a erişmesine izin verir.</string>\n    <string name=\"permission_service_sierra_description\">Uygulamanın, ilgili herhangi bir Google hesabı aracılığıyla Google Checkout hesaplarına erişmesine izin verir.</string>\n    <string name=\"permission_service_sierraqa_label\">Google Checkout QA hesapları</string>\n    <string name=\"permission_service_sierraqa_description\">Uygulamanın, ilgili herhangi bir Google hesabı aracılığıyla Google Checkout QA hesaplarına erişmesine izin verir.</string>\n    <string name=\"permission_service_sierrasandbox_label\">Google Checkout Sandbox hesapları</string>\n    <string name=\"permission_service_sierrasandbox_description\">Uygulamanın, ilgili herhangi bir Google hesabı aracılığıyla Google Checkout Sandbox hesaplarına erişmesine izin verir.</string>\n    <string name=\"permission_service_sitemaps_label\">Google Web Yöneticisi Araçları</string>\n    <string name=\"permission_service_sitemaps_description\">Uygulamanın, ilgili herhangi bir Google hesabı aracılığıyla Google Web Yöneticisi Araçları\\'na erişmesine izin verir.</string>\n    <string name=\"permission_service_speech_label\">Sesli Arama</string>\n    <string name=\"permission_service_speech_description\">Uygulamanın, ilgili herhangi bir Google hesabı aracılığıyla Sesli Arama\\'ya erişmesine izin verir.</string>\n    <string name=\"permission_service_speechpersonalization_label\">Kişiselleştirilmiş Konuşma Tanıma</string>\n    <string name=\"permission_service_talk_label\">Google Talk</string>\n    <string name=\"permission_service_talk_description\">Uygulamanın, ilgili herhangi bir Google hesabı aracılığıyla Google Talk\\'a erişmesine izin verir.</string>\n    <string name=\"permission_service_wifi_label\">Google Wi-Fi</string>\n    <string name=\"permission_service_wifi_description\">Uygulamanın, ilgili herhangi bir Google hesabı aracılığıyla Google Wi-Fi\\'ye erişmesine izin verir.</string>\n    <string name=\"permission_service_wise_label\">Google E-Tablolar</string>\n    <string name=\"permission_service_wise_description\">Uygulamanın, ilgili herhangi bir Google hesabı aracılığıyla Google E-Tablolar\\'a erişmesine izin verir.</string>\n    <string name=\"permission_service_writely_label\">Google Dokümanlar</string>\n    <string name=\"permission_service_writely_description\">Uygulamanın, ilgili herhangi bir Google hesabı aracılığıyla Google Dokümanlar\\'a erişmesine izin verir.</string>\n    <string name=\"permission_service_youtube_label\">YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_activity\">Google Uygulamalarınızın etkinlik geçmişini görüntüle</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.buyer\">Reklam Değişimi alıcı hesabı yapılandırmasını yönet</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller.readonly\">Reklam Değişimi verilerini görüntüle</string>\n    <string name=\"permission_service_YouTubeUser_description\">Uygulamanın, ilgili herhangi bir Google hesabıyla kullanılan YouTube kullanıcı adlarına erişmesine izin verir.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller\">Reklam Değişimi verilerini görüntüle ve yönet</string>\n    <string name=\"permission_service_mail_description\">Uygulamanın, ilgili herhangi bir Google hesabı aracılığıyla Google E-Posta\\'ya erişmesine izin verir.</string>\n    <string name=\"permission_service_speechpersonalization_description\">Uygulamanın, ilgili herhangi bir Google hesabı aracılığıyla Kişiselleştirilmiş Konuşma Tanıma\\'ya erişmesine izin verir.</string>\n    <string name=\"permission_service_youtube_description\">Uygulamanın, ilgili herhangi bir Google hesabı aracılığıyla YouTube\\'a erişmesine izin verir.</string>\n    <string name=\"permission_service_YouTubeUser_label\">YouTube kullanıcı adları</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsensehost\">AdSense barındırıcı verilerinizi ve ilişkili hesaplarınızı görüntüleyin ve yönetin</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense.readonly\">AdSense verilerinizi görüntüleyin</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense\">AdSense verilerinizi görüntüleyin ve yönetin</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics.readonly\">Google Analytics verilerinizi görüntüleyin</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics\">Google Analytics verilerinizi görüntüleyin ve yönetin</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_androidpublisher\">Google Play Android Geliştiricisine Erişim</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.migration\">Groups Migration API\\'ına okuma ve yazma erişimi.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.settings\">Bir Google Apps Grubunun ayarlarını görüntüleyin ve yönetin</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.licensing\">Lisans Yöneticisi API\\'sine okuma/yazma erişimi.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order\">Satıcı yöneticileri ve kullanıcılar için, API\\'nin korumalı alanında test yaparken okuma/yazma erişimi veya bir API işlemini doğrudan çağırırken okuma/yazma erişimi.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger\">Blogger hesabınızı yönetin</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger.readonly\">Blogger hesabınızı görüntüleyin</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_books\">Kitaplarınızı yönetin</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar\">Takvimlerinizi yönetin</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar.readonly\">Takvimlerinizi görüntüleyin</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_cloudprint\">Google bulut yazdırma verilerinizi görüntüleyin ve yönetin</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute.readonly\">Google Compute Engine kaynaklarınızı görüntüleyin</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute\">Google Compute Engine kaynaklarınızı görüntüleyin ve yönetin</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate.readonly\">Google Koordinatör işlerinizi görüntüleyin</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate\">Google Haritalar Koordinatör işlerinizi görüntüleyin ve yönetin</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.full_control\">Google Bulut Depolama\\'daki verilerinizi ve izinlerinizi yönetin</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_write\">Google Bulut Depolama\\'daki verilerinizi yönetme</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_dfareporting\">DoubleClick for Advertisers raporlarını görüntüleme ve yönetme</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.appdata\">Application Data klasörüne erişme izni</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.apps.readonly\">Google Drive uygulamalarınızı görüntüleyin</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.file\">Bu uygulamayla açtığınız veya oluşturduğunuz Google Drive dosyalarını görüntüleyin ve yönetin</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.metadata.readonly\">Google Drive\\'ınızdaki dosya ve dokümanlara ilişkin meta verileri görüntüleyin</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.readonly\">Google Drive\\'ınızdaki dosya ve belgeleri görüntüleyin</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive\">Google Drive\\'ınızdaki dosya ve belgeleri görüntüleyin ve yönetin</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_only\">Verilerinizi Google Bulut Depolama\\'da görüntüleyin</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.install\">Kullanıcıların bir uygulamanın kurulumunu onaylamasına izin vermek için kullanılan özel kapsam</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appengine.admin\">App Engine yönetici erişimi.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order.readonly\">Genel okuma/yazma OAuth yetkisinin yanı sıra, müşterinin verisini getirirken yalnızca okuma OAuth yetkisini kullan.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery.readonly\">Google BigQuery\\'deki verinizi görme</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps_reporting_audit.readonly\">Admin Audit API sadece okuma izni</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appstate\">App State servisini kullanma yetkisi.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase.readonly\">Freebase hesabınızı görüntüleme</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase\">Freebase\\'e kendi hesabınız ile giriş yapma</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables.readonly\">Fusion Tables öğelerinizi görüntüleme</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan.readonly\">GAN verinizi görme</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gcm_for_chrome\">Chrome için Cloud Messaging</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_glass.timeline\">Glass zaman çizelgesi yetkisi</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.compose\">Taslak oluştur, oku, düzenle ve sil. Taslak ve mesaj gönder.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.modify\">Tüm yazma/okuma işlemleri fakat derhal, çöp kutusuna atmadan kalıcı silme işlemleri hariç.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.best\">Kullanılabilir en iyi konumunuzu ve konum geçmişinizi yönetme</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.city\">Şehir seviyesindeki konumunuzu ve konum geçmişinizi yönetme</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine\">Google Maps Engine verinizi görüntüleme ve yönetme</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine.readonly\">Google Maps Engine verinizi görüntüleme</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mobilemaps.firstparty\">Mobil deneyim için Google Haritalar\\'ınızı görüntüleme ve yönetme</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut\">Orkut aktivitenizi yönetme</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut.readonly\">Orkut verinizi görme</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.login\">Adınızı, temel bilginizi ve Google+\\'daki bağlantılarınızı öğrenme</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.me\">Google\\'da kim olduğunuzu öğrenme</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_prediction\">Google Prediction API verinizi yönetme</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_shoppingapi\">Ürün verinizi yönetme</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification\">Yetkilisi olduğunuz siteleri ve alan adlarını yönetme</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue.consumer\">Görev kuyruklarınızdaki görevlerinizi kullanma</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue\">Görevlerinizi yönetme</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks\">Görevlerinizi yönetme</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_urlshortener\">goo.gl kısa bağlantılarınızı yönetme</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.email\">E-posta adresinizi görüntüleme</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.profile\">Hesabınız hakkında temel bilgileri görüntüleme</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube\">YouTube hesabınızı yönetme</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtubepartner\">YouTube\\'daki varlıklarınızı ve ilişkili içeriklerinizi görüntüleme ve yönetme</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics_monetary.readonly\">YouTube içeriğinizdeki YouTube Analytics parasal raporları görüntüleme</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics.readonly\">YouTube içeriğinizdeki YouTube Analytics raporları görüntüleme</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.best\">Kullanılabilir en iyi konumunuzu yönetme</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.city\">Şehir seviyesindeki konumunuzu yönetme</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables\">Fusion Tables öğelerinizi yönetme</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan\">GAN verinizi yönetme</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.readonly\">Tüm kaynakları ve metaverilerini oku — yazma erişimi olmadan.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery\">Google BigQuery\\'deki verinizi görme veya yönetme</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.scripts\">Google Apps Script komutlarının davranışını değiştirme</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_games\">Google Play Oyunlar verinize erişme yetkisi.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks.readonly\">Görevlerinizi görüntüleme</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_structuredcontent\">Shopping Content API\\'a okuma/yazma erişimi.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tracks\">Google Maps Tracks API, Bu yetki, projenizin verisine okuma ve yazma erişimi sağlar.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification.verify_only\">Google ile yeni site doğrulamalarınızı yönetme</string>\n    <string name=\"perm_activity_recognition_label\">Aktivite tanıma</string>\n    <string name=\"perm_activity_recognition_description\">Uygulamanın, Google\\'dan aktivite durumunuz ile ilgili periyodik güncellemeler almasını sağlar; örneğin, yürüyor, araba kullanıyor, bisiklete biniyor veya sabit duruyorsanız.</string>\n</resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-tr/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <plurals name=\"pref_unifiednlp_summary\">\n        <item quantity=\"one\">&lt;xliff:g example=“1”&gt;%1$d&lt;/xliff:g&gt; arka uç yapılandırıldı</item>\n        <item quantity=\"other\"><xliff:g example=\"3\">%1$d</xliff:g> arka uç yapılandırıldı</item>\n    </plurals>\n    <plurals name=\"gcm_registered_apps_counter\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> kayıtlı uygulama</item>\n        <item quantity=\"other\"><xliff:g example=\"123\">%1$d</xliff:g> kayıtlı uygulama</item>\n    </plurals>\n    <plurals name=\"cond_perm_action\">\n        <item quantity=\"one\">Eksik izni iste</item>\n        <item quantity=\"other\">Eksik izinleri iste</item>\n    </plurals>\n    <plurals name=\"cond_perm_summary\">\n        <item quantity=\"one\">microG Servisleri\\'nin düzgün çalışması için gereken bir izin sağlanmadı.</item>\n        <item quantity=\"other\">microG Servisleri\\'nin düzgün çalışması için gereken izinler sağlanmadı.</item>\n    </plurals>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-tr/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=\"allow\">İzin ver</string>\n    <string name=\"perm_car_vendor_extension_label\">Araç üreticisi kanalı</string>\n    <string name=\"service_name_checkin\">Google cihaz kaydı</string>\n    <string name=\"self_check_name_perm_granted\">Sistem imza sahteciliği desteği izni sağlandı mı:</string>\n    <string name=\"pref_auth_include_android_id_title\">Cihaz kaydı ile kimlik doğrulama</string>\n    <string name=\"pref_push_app_wake_for_delivery_summary\">Gönderilen anlık bildirimleri almak için uygulamayı arka planda başlat.</string>\n    <string name=\"prefcat_push_apps_title\">Anlık bildirim sistemini kullanan uygulamalar</string>\n    <string name=\"menu_clear_recent_requests\">Önceki istekleri temizle</string>\n    <string name=\"safetynet_last_run_at\">Son kullanım: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"pref_safetynet_recent_advice\">Tavsiye</string>\n    <string name=\"pref_safetynet_recent_response_status\">Yanıt kodu</string>\n    <string name=\"pref_safetynet_test_cts_failed\">CTS başarısız</string>\n    <string name=\"pref_safetynet_test_integrity_failed\">Bütünlük sağlanamadı</string>\n    <string name=\"push_notifications_summary_values_minutes\">%s dakika</string>\n    <string name=\"credentials_assisted_choose_account_subtitle\">%1$s uygulamasına devam etmek için</string>\n    <string name=\"credentials_assisted_signin_button_text_long\">Google ile oturum aç</string>\n    <string name=\"gms_app_name\">microG Servisleri</string>\n    <string name=\"gms_settings_name\">microG Ayarları</string>\n    <string name=\"gms_settings_summary\">microG servislerini ayarla.</string>\n    <string name=\"just_a_sec\">Bir saniye…</string>\n    <string name=\"google_account_label\">Google</string>\n    <string name=\"ask_permission_tos\">Devam ederek, bu uygulamanın ve Google\\'ın bilgilerinizi kendi hizmet şartları ve gizlilik politikalarına uygun olarak kullanmasına izin vermiş olursunuz.</string>\n    <string name=\"ask_scope_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> şunu istiyor:</string>\n    <string name=\"ask_service_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> şunu kullanmak istiyor:</string>\n    <string name=\"account_manager_title\">Google Hesap Yöneticisi</string>\n    <string name=\"auth_before_connect\">Cihazınızdaki bir uygulama, Google hesabına giriş yapmaya çalışıyor.\\n\\nEğer bunu istediyseniz, <b>Oturum aç</b> tuşunu kullanarak Google\\'un oturum açma sayfasına giriş yapın, eğer istemediyseniz, <b>İptal</b> tuşuna basarak oturum açmayı deneyen uygulamaya geri dönün.</string>\n    <string name=\"auth_sign_in\">Oturum aç</string>\n    <string name=\"sorry\">Hay aksi…</string>\n    <string name=\"auth_connecting\">Cihazınız, oturum açmanız için Google sunucuları ile iletişim kuruyor.\n\\n\n\\nBu birkaç saniye sürebilir.</string>\n    <string name=\"no_network_error_desc\">İnternet bağlantınız yok.\n\\n\n\\nBu geçici bir sorun olabilir veya Android cihazınızın veri hizmetleri sağlanmamış olabilir. Bir mobil ağa veya Wi-Fi ağına bağlandığınızda tekrar deneyin.</string>\n    <string name=\"auth_general_error_desc\">Google sunucuları ile iletişime geçerken bir sorun oluştu.\n\\n\n\\nDaha sonra tekrar deneyin.</string>\n    <string name=\"auth_finalize\">Cihazınız, bilgileri hesabınıza kaydetmek için Google ile iletişime geçiyor.\n\\n\n\\nBu birkaç dakika sürebilir.</string>\n    <string name=\"deny\">Reddet</string>\n    <string name=\"auth_notification_title\">Yetkilendirme gerekiyor</string>\n    <string name=\"auth_notification_content\"><xliff:g example=\"F-Droid\">%1$s</xliff:g>, Google hesabınıza erişmek için yetkinize ihtiyaç duyuyor.</string>\n    <string name=\"auth_package_override_request_title\"><b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> uygulamasının <xliff:g example=\"account@example.com\">%2$s</xliff:g> hesabına ayrıcalıklı erişimine izin vermek istiyor musunuz?</string>\n    <string name=\"auth_package_override_request_message\"><b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> uygulaması <b><xliff:g example=\"F-Droid\">%2$s</xliff:g> uygulaması gibi (yayıncısı <xliff:g example=\"F-Droid Inc.\">%3$s</xliff:g>)</b>, hesabınıza erişmek istiyor. Bu izin, hesabınıza ayrıcalıklı erişim verebilir.</string>\n    <string name=\"signin_picker_title\">Bir hesap seç</string>\n    <string name=\"signin_picker_subtitle\">ve <xliff:g example=\"F-Droid\">%1$s</xliff:g> uygulamasına devam et</string>\n    <string name=\"signin_picker_add_account_label\">Başka bir hesap ekle</string>\n    <string name=\"signin_confirm_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> uygulamasına giriş yapmak istediğinizi onaylayın</string>\n    <string name=\"signin_confirm_button_text\">Kabul et ve paylaş</string>\n    <string name=\"signin_subtext_sharing\">Devam etmek için, microG, Google hesabınızın ismini, e-posta adresini ve profil resmini <xliff:g example=\"F-Droid\">%1$s</xliff:g> ile paylaşacak.</string>\n    <string name=\"signin_subtext_policy\">Bu uygulamayı kullanmadan önce, uygulamanın %1$s ve %2$s inceleyin.</string>\n    <string name=\"signin_subtext_policy_privacy\">gizlilik politikasını</string>\n    <string name=\"signin_subtext_policy_terms\">kullanım şartlarını</string>\n    <string name=\"perm_status_broadcast_label\">özel durum yayınlarını alma</string>\n    <string name=\"perm_gsf_read_gservices_label\">Google servis bilgisini okuma</string>\n    <string name=\"perm_c2dm_receive_label\">C2DM mesajlarını okuma</string>\n    <string name=\"perm_c2dm_send_label\">diğer uygulamalara C2DM mesajları gönderme</string>\n    <string name=\"perm_gtalk_svc_label\">Google sunucularına mesaj gönderme ve senkronize etme bildirimlerini alma</string>\n    <string name=\"perm_extended_access_label\">Google servislerine ek erişim</string>\n    <string name=\"perm_provision_label\">microG servislerine erişim</string>\n    <string name=\"perm_provision_description\">Uygulamanın, kullanıcıya sorulmadan microG servislerinin ayarlarını değiştirmesine izin verir</string>\n    <string name=\"perm_car_speed_label\">Araç hızı</string>\n    <string name=\"perm_car_speed_description\">Aracınızın hızına erişme</string>\n    <string name=\"perm_car_info_label\">Araç bilgisi</string>\n    <string name=\"perm_car_info_description\">Aracınızın bilgisine erişme</string>\n    <string name=\"perm_car_fuel_label\">Araç yakıt bilgisi</string>\n    <string name=\"perm_car_fuel_description\">Aracınızın yakıt seviyesinin bilgisine erişme</string>\n    <string name=\"perm_car_mileage_label\">Araç mesafesi</string>\n    <string name=\"perm_car_mileage_description\">Aracınızın mesafe bilgisine erişme</string>\n    <string name=\"perm_car_vendor_extension_description\">Araca özel bilgi alışverişi yapmak için aracınızın üretici kanalına erişme</string>\n    <string name=\"service_name_mcs\">Cloud Messaging</string>\n    <string name=\"service_name_snet\">Google SafetyNet</string>\n    <string name=\"service_name_vending\">Play Store servisleri</string>\n    <string name=\"games_info_content\">Play Games\\'i kullanmak için Google Play Games uygulamasını yüklemeniz gerekir. Uygulama Play Games olmadan çalışmaya devam edebilir, ancak beklenmedik şekilde davranabilir.</string>\n    <string name=\"games_title\">Google Play Oyunlar</string>\n    <string name=\"pick_place_title\">Bir yer seç</string>\n    <string name=\"games_info_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> uygulaması Play Games\\'e erişmek istiyor</string>\n    <string name=\"pick_place_desc\">Yer seçici henüz mevcut değil.</string>\n    <string name=\"place_picker_select_title\">Bu konumu seç</string>\n    <string name=\"place_picker_nearby_places\">Yakındaki yerler</string>\n    <string name=\"place_picker_location_lat_lng\">(%1$.7f, %2$.7f)</string>\n    <string name=\"lacking_permission_toast\">microG Servisleri: Gerekli olan <xliff:g example=\"have full network acccess\">%1$s</xliff:g> izni sağlanmadı</string>\n    <string name=\"network_type_mobile\">Mobil ağ</string>\n    <string name=\"network_type_wifi\">Wi-Fi</string>\n    <string name=\"network_type_roaming\">Dolaşım</string>\n    <string name=\"network_type_other\">Diğer ağlar</string>\n    <string name=\"self_check_cat_fake_sig\">İmza sahteciliği desteği</string>\n    <string name=\"self_check_cat_gms_packages\">Yüklü paketler</string>\n    <string name=\"self_check_cat_system\">Sistem</string>\n    <string name=\"self_check_name_fake_sig_perm\">Sistemde imza sahteciliği desteği var mı:</string>\n    <string name=\"self_check_resolution_fake_sig_perm\">ROM\\'unuzun imza sahteciliği için yerel desteği yoktur. Yine de imza sahteciliği için Xposed veya diğer sistemleri kullanabilirsiniz. Lütfen hangi ROM\\'ların imza sahteciliğini desteklediğine ve desteklemeyen ROM\\'larda microG\\'nin nasıl kullanılacağına ilişkin rehbere göz atın.</string>\n    <string name=\"self_check_resolution_perm_granted\">Bu, ROM\\'un imza sahteciliğini desteklediğinin güçlü bir göstergesidir, ancak etkinleştirmek için daha fazla işlem yapılması gerekir. Lütfen hangi adımların gerekli olabileceğine dair rehbere göz atın.</string>\n    <string name=\"self_check_name_system_spoofs\">Sistem imza sahteciliği yapıyor mu:</string>\n    <string name=\"self_check_resolution_app_installed\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> uygulamasını veya uyumlu olanını yükleyin. Lütfen hangi uygulamaların uyumlu olduğuna dair rehbere göz atın.</string>\n    <string name=\"self_check_resolution_system_spoofs\">Lütfen hangi adımların gerekli olabileceğine dair rehberi kontrol edin.</string>\n    <string name=\"self_check_pkg_gms\">microG Servisleri</string>\n    <string name=\"self_check_pkg_vending\">microG Eşlikçisi / Play Store</string>\n    <string name=\"self_check_pkg_gsf\">microG Hizmet Çerçevesi (GSF)</string>\n    <string name=\"self_check_name_app_installed\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> yüklü mü: </string>\n    <string name=\"self_check_name_correct_sig\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> doğru imzaya sahip mi: </string>\n    <string name=\"self_check_resolution_correct_sig\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> uygulaması uyumlu değil veya doğru imzaya sahip değil. Lütfen hangi uygulamaların ve ROM\\'ların uyumlu olduğuna dair rehbere göz atın.</string>\n    <string name=\"self_check_name_battery_optimizations\">Pil optimizasyonları devre dışı bırakıldı mı:</string>\n    <string name=\"self_check_resolution_battery_optimizations\">Pil optimizasyonlarını devre dışı bırakmak için buraya dokunun. Bunu yapmamak uygulamaların hatalı çalışmasına neden olabilir.</string>\n    <string name=\"prefcat_about\">Hakkında</string>\n    <string name=\"prefcat_components\">Bileşenler</string>\n    <string name=\"prefcat_configuration\">Seçenekler</string>\n    <string name=\"prefcat_google_services\">Google Servisleri</string>\n    <string name=\"prefcat_location_service\">Konum servisi</string>\n    <string name=\"prefcat_services\">Hizmetler</string>\n    <string name=\"prefcat_test\">Test</string>\n    <string name=\"cond_gcm_bat_title\">Pil optimizasyonları açık</string>\n    <string name=\"cond_gcm_bat_action\">Optimizasyonları kapat</string>\n    <string name=\"cond_gcm_bat_summary\">Cloud Messaging\\'i etkinleştirdiniz ancak microG Servisleri için pil optimizasyonları etkin. Anlık bildirimlerin gelmesi için pil optimizasyonlarını devre dışı bırakmalısınız.</string>\n    <string name=\"cond_perm_title\">İzin eksik</string>\n    <string name=\"prefs_account\">Hesap tercihleri</string>\n    <string name=\"prefs_account_privacy\">Kişisel bilgiler &amp; gizlilik</string>\n    <string name=\"prefs_account_security\">Oturum açma &amp; güvenlik</string>\n    <string name=\"pref_auth_trust_google_title\">Uygulama izinleri için Google\\'a güven</string>\n    <string name=\"pref_auth_trust_google_summary\">Devre dışı bırakıldığında, bir uygulamanın yetkilendirme isteği Google\\'a gönderilmeden önce kullanıcıya sorulur. Bu devre dışı bırakılırsa bazı uygulamalar Google hesabını kullanamaz.</string>\n    <string name=\"pref_auth_visible_title\">Uygulamaların hesapları bulmasına izin ver</string>\n    <string name=\"pref_auth_visible_summary\">Etkinleştirildiğinde, bu cihazdaki bütün uygulamalar size sormadan Google hesaplarınızın e-posta adresini görebilecektir.</string>\n    <string name=\"pref_auth_include_android_id_summary\">Devre dışı bırakıldığında, kimlik doğrulama istekleri cihaz kaydıyla ilişkilendirilmez, bu da yetkisiz cihazların oturum açmasına izin verebilir, ancak öngörülemeyen sonuçları olabilir.</string>\n    <string name=\"pref_auth_strip_device_name_title\">Kimlik doğrulama yaparken cihaz adını dahil etme</string>\n    <string name=\"pref_auth_strip_device_name_summary\">Etkinleştirildiğinde, kimlik doğrulama istekleri cihazın adını içermez, bu da yetkisiz cihazların oturum açmasına izin verebilir, ancak öngörülemeyen sonuçları olabilir.</string>\n    <string name=\"pref_device_registration_android_id\">Android kimliği</string>\n    <string name=\"pref_checkin_enable_summary\">Cihazınızı Google servislerine kaydettirir ve benzersiz bir cihaz kimliği oluşturur. microG, kayıt verilerinden Google hesap adınız dışındaki diğer tanımlayıcı bilgileri çıkarır.</string>\n    <string name=\"checkin_not_registered\">Kayıtlı değil</string>\n    <string name=\"checkin_last_registration\">Son kayıt: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"checkin_enable_switch\">Cihazı kaydettir</string>\n    <string name=\"pref_info_status\">Durum</string>\n    <string name=\"pref_more_settings\">Daha fazla</string>\n    <string name=\"pref_gcm_enable_mcs_summary\">Cloud Messaging, birçok üçüncü parti uygulama tarafından kullanılan bir anlık bildirim sağlayıcısıdır. Bunu kullanabilmek için cihaz kaydını da etkinleştirmeniz gerekir.</string>\n    <string name=\"pref_gcm_heartbeat_title\">Cloud Messaging kontrol periyodu</string>\n    <string name=\"pref_accounts_title\">Google hesapları</string>\n    <string name=\"pref_accounts_summary\">Google hesaplarını bağla veya yönet</string>\n    <string name=\"prefcat_accounts_settings_title\">Ayarlar</string>\n    <string name=\"prefcat_accounts_current_accounts_title\">Hesaplar</string>\n    <string name=\"pref_add_account_title\">Hesap</string>\n    <string name=\"pref_add_account_summary\">Google hesabı ekle</string>\n    <string name=\"pref_gcm_apps_title\">Cloud Messaging kullanan uygulamalar</string>\n    <string name=\"pref_gcm_apps_summary\">Cloud Messaging servisine kayıtlı uygulamaların listesi.</string>\n    <string name=\"pref_gcm_confirm_new_apps_title\">Yeni uygulamalar için sor</string>\n    <string name=\"pref_gcm_heartbeat_summary\">Sistemin Google sunucularını kontrol etmesi için saniye cinsinden aralık. Bu sayının artırılması pil tüketimini azaltır, ancak anlık bildirimlerde gecikmelere neden olabilir.\\nBu özellik gelecek sürümlerde değiştirileceğinden kullanımdan kaldırıldı.</string>\n    <string name=\"pref_gcm_confirm_new_apps_summary\">Anlık bildirimleri almak üzere yeni bir uygulamayı kaydetmeden önce sorun</string>\n    <string name=\"pref_gcm_ping_interval\">Ping aralığı: <xliff:g example=\"10 minutes\">%1$s</xliff:g></string>\n    <string name=\"pref_about_title\">microG Servisleri hakkında</string>\n    <string name=\"pref_about_summary\">Sürüm bilgisi ve kullanılan kütüphaneler</string>\n    <string name=\"gcm_app_error_unregistering\">Kaydı silerken hata</string>\n    <string name=\"gcm_app_not_installed_anymore\">Artık yüklü değil</string>\n    <string name=\"gcm_unregister_app\">Kaydı sil</string>\n    <string name=\"gcm_not_registered\">Kayıtlı değil</string>\n    <string name=\"gcm_no_message_yet\">Henüz mesaj gelmedi</string>\n    <string name=\"gcm_last_message_at\">Son mesaj: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_registered\">Kayıtlı</string>\n    <string name=\"gcm_registered_since\"><xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g> beri kayıtlı</string>\n    <string name=\"gcm_unregister_confirm_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> uygulamasının kaydını sil?</string>\n    <string name=\"gcm_unregister_confirm_message\">Bazı uygulamalar otomatik olarak yeniden kaydolmaya çalışmaz ve/veya bunu manuel olarak yapmak için bir seçenek sunmaz. Bu uygulamalar kaydı kaldırıldıktan sonra düzgün çalışmayabilir.\\nEmin misiniz?</string>\n    <string name=\"gcm_unregister_after_deny_message\">Zaten kaydettirilmiş bir uygulamanın anlık bildirim gönderme kaydını reddettiniz.\\nBu uygulamanın bir daha anlık bildirim almaması için şu anki kaydını da silmek istiyor musunuz?</string>\n    <string name=\"gcm_messages_counter\">Mesaj sayısı: <xliff:g example=\"123\">%1$d</xliff:g> (<xliff:g example=\"12345\">%2$d</xliff:g> bayt)</string>\n    <string name=\"gcm_network_state_disconnected\">Bağlı değil</string>\n    <string name=\"gcm_network_state_connected\"><xliff:g example=\"2 hours ago\">%1$s</xliff:g> beri bağlı</string>\n    <string name=\"gcm_enable_switch\">Anlık bildirimleri al</string>\n    <string name=\"gcm_allow_app_popup\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> uygulamasının anlık bildirim gönderebilmesi için kaydettirilmesine izin vermek istiyor musunuz?</string>\n    <string name=\"pref_push_app_allow_register_title\">Kaydettirmeye izin ver</string>\n    <string name=\"pref_push_app_allow_register_summary\">Uygulamanın anlık bildirim gönderebilmesi için kaydettir.</string>\n    <string name=\"pref_push_app_wake_for_delivery_title\">Anlık bildirim geldiğinde uygulamayı başlat</string>\n    <string name=\"prefcat_push_apps_registered_title\">Kayıtlı uygulamalar</string>\n    <string name=\"prefcat_push_apps_unregistered_title\">Kayıtlı olmayan uygulamalar</string>\n    <string name=\"safetynet_enable_switch\">Cihaz doğrulamasına izin ver</string>\n    <string name=\"prefcat_push_networks_title\">Anlık bildirimler için kullanılacak ağlar</string>\n    <string name=\"safetynet_intro\">Google SafetyNet, cihazın yeterince güvenli ve Android CTS ile uyumlu olduğunu doğrulayan bir cihaz sertifikasyon sistemidir. Çeşitli uygulamalar, güvenlik nedeniyle veya uygulamanın kurcalanmasına karşı koruma sağlamak için SafetyNet\\'i kullanır.\\n\\nmicroG Servisleri, SafetyNet\\'in özgür geliştirilmiş bir varyasyonunu içerir, ancak resmi sunucu, SafetyNet isteklerinin sahipli DroidGuard sistemiyle imzalanmasını gerektirir.</string>\n    <string name=\"pref_safetynet_test_title\">SafetyNet kontrolü yap</string>\n    <string name=\"pref_recaptcha_test_title\">ReCAPTCHA\\'yı test et</string>\n    <string name=\"profile_name_real\">Gerçek</string>\n    <string name=\"pref_recaptcha_enterprise_test_title\">ReCAPTCHA Enterprise\\'ı test et</string>\n    <string name=\"pref_test_summary_passed\">Tüm testler geçildi</string>\n    <string name=\"pref_test_summary_failed\">Başarısız: %s</string>\n    <string name=\"pref_test_summary_warn\">Uyarı: %s</string>\n    <string name=\"pref_test_summary_running\">Çalışıyor…</string>\n    <string name=\"pref_droidguard_operation_mode\">Çalışma modu</string>\n    <string name=\"pref_droidguard_unsupported_summary\">DroidGuard\\'ın çalıştırılması bu cihazda desteklenmiyor. SafetyNet hizmetleri beklenildiği gibi davranamayabilir.</string>\n    <string name=\"prefcat_safetynet_apps_title\">SafetyNet kullanan uygulamalar</string>\n    <string name=\"profile_name_native\">Dahili</string>\n    <string name=\"profile_name_user\">Özel: %s</string>\n    <string name=\"profile_name_auto\">Otomatik: %s</string>\n    <string name=\"profile_name_system\">Sistem: %s</string>\n    <string name=\"pref_device_registration_import_custom_profile_title\">Özel profili içe aktar</string>\n    <string name=\"pref_device_registration_serial_title\">Seri numarası</string>\n    <string name=\"pref_device_registration_import_custom_profile_summary\">Dosyadan cihaz profili içe aktar</string>\n    <string name=\"pref_device_registration_select_profile_title\">Profil seç</string>\n    <string name=\"pref_device_registration_device_profile_category\">Cihaz profili</string>\n    <string name=\"pref_safetynet_recent_uses\">Son kullanımlar</string>\n    <string name=\"pref_safetynet_recent_attestation_summary\">Kontrol: %s</string>\n    <string name=\"pref_safetynet_recent_recaptcha_summary\">ReCaptcha: %s</string>\n    <string name=\"pref_safetynet_recent_eval_type\">Çalıştırma türü</string>\n    <string name=\"pref_safetynet_recent_cat_response\">Yanıt verisi</string>\n    <string name=\"pref_safetynet_recent_recaptcha_enterprise_summary\">ReCaptcha Enterprise: %s</string>\n    <string name=\"pref_safetynet_recent_copy_json\">JSON JWS verisini kopyala</string>\n    <string name=\"pref_safetynet_recent_cat_request\">İstek verisi</string>\n    <string name=\"pref_safetynet_recent_nonce\">Sağlama (Hex)</string>\n    <string name=\"pref_safetynet_recent_request_time\">İstek zamanı</string>\n    <string name=\"pref_safetynet_recent_request_type\">İstek türü</string>\n    <string name=\"pref_safetynet_recent_cat_basic\">Basit veri</string>\n    <string name=\"pref_safetynet_recent_token\">Anahtar</string>\n    <string name=\"pref_safetynet_recent_copied\">Panoya kopyalandı!</string>\n    <string name=\"pref_safetynet_test_integrity_cts_passed\">Bütünlük and CTS geçti</string>\n    <string name=\"pref_safetynet_test_not_completed\">Henüz tamamlanmadı</string>\n    <string name=\"pref_safetynet_test_no_result\">Sonuç yok</string>\n    <string name=\"push_notifications_summary_values_seconds\">%s saniye</string>\n    <string name=\"pref_safetynet_test_invalid_json\">Geçersiz JSON</string>\n    <string name=\"push_notifications_summary_off\">KAPALI</string>\n    <string name=\"pref_vending_summary_licensing_off\">Lisanslama kapalı</string>\n    <string name=\"push_notifications_summary_automatic\">AÇIK / Otomatik: %s</string>\n    <string name=\"push_notifications_summary_manual\">AÇIK / Manuel: %s</string>\n    <string name=\"pref_vending_summary_licensing_on\">Lisanslama açık</string>\n    <string name=\"pref_vending_licensing_category\">Google Play Lisanslama</string>\n    <string name=\"pref_vending_licensing_enable_switch\">Lisans doğrulama isteklerine cevap ver</string>\n    <string name=\"pref_vending_license_enable_summary\">Bazı uygulamalar, kendilerinin gerçekten de Google Play\\'den satın alındığının doğrulanmasını talep eder. Bir uygulama tarafından talep edilirse, microG, Google\\'dan uygulamanın satın alındığına dair bir kanıt indirebilir. Devre dışı bırakılırsa veya hiçbir Google hesabı eklenmezse, lisans doğrulama istekleri görmezden gelinir.</string>\n    <string name=\"feedback_disabled\">Geri bildirim henüz mevcut değil</string>\n    <string name=\"backup_disabled\">Yedekleme henüz mevcut değil</string>\n    <string name=\"pref_vending_billing_category\">Google Play Satın Alımları</string>\n    <string name=\"pref_vending_billing_enable_switch\">Satın alım isteklerini gerçekleştir</string>\n    <string name=\"pref_vending_billing_enable_summary\">Etkinleştirildikten sonra, bazı uygulamalar Google\\'ın Play Satın Alım hizmeti aracılığıyla satın alma işlemlerini tamamlayabilir veya abonelik başlatabilir.</string>\n    <string name=\"pref_vending_billing_note_experimental\">Uyarı, bu özellik deneyseldir ve para kaybına yol açabilir.</string>\n    <string name=\"pref_vending_billing_note_licensing\">Bazı uygulamalar, satın alma işlemlerinizi doğrulamak için lisans doğrulamayı da etkinleştirmenizi gerektirebilir.</string>\n    <string name=\"credentials_assisted_cancel\">İptal</string>\n    <string name=\"credentials_assisted_continue\">Devam et</string>\n    <string name=\"credentials_assisted_confirmation_header\">Oturumunuz açılıyor</string>\n    <string name=\"credentials_assisted_continue_as_user_button_label\">%1$s olarak devam et</string>\n    <string name=\"credentials_assisted_sign_back_title\">Google ile %1$s uygulamasında tekrar oturum aç</string>\n    <string name=\"credentials_assisted_signin_consent_header\">%1$s olarak oturum açılıyor</string>\n    <string name=\"credentials_assisted_signin_consent\">Devam ettiğinizde Google, adınızı, e-posta adresinizi ve profil resminizi %1$s ile paylaşacaktır. %1$s uygulamasının gizlilik politikasına ve hizmet şartlarına göz atın.</string>\n    <string name=\"credentials_assisted_signin_description\">Google ile oturum aç özelliğini Google hesaplarınızdan yönetebilirsiniz.</string>\n    <string name=\"credentials_assisted_choose_account_label\">Hesap seç</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_switch\">Ücretsiz uygulamaları kendiliğinden kütüphaneye ekle</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_summary\">Ücretsiz uygulamalar kendilerinin Google Play\\'den indirilip indirilmediklerini kontrol etmek isteyebilir. Size mevcut olan bütün ücretsiz uygulamaların bu denetimini her zaman atlamak için ücretsiz uygulamaları otomatik olarak hesap kütüphanenize ekleyin.</string>\n    <string name=\"limited_services_app_name\">microG Kısıtlı Servisleri</string>\n    <string name=\"auth_action_notification_channel_name\">Google hesap uyarıları</string>\n    <string name=\"auth_action_notification_title\">Hesaba eylem gerekiyor</string>\n    <string name=\"auth_action_notification_content\">Google hesabınızın ek kuruluma ihtiyacı var.</string>\n    <string name=\"auth_action_activity_header\">Google hesabınızı ayarlamayı bitirin</string>\n    <string name=\"auth_action_notification_channel_description\">Google hesaplarınızdan biri kullanılmadan önce ek kurulum gerektirdiğinde veya bir hesap, microG ile uyumsuz olduğunda bildirimde bulunur.</string>\n    <string name=\"auth_action_activity_explanation\">Bu cihazda %s Google hesabınızı kullanmak için verilen adımları tamamlayın.</string>\n    <string name=\"auth_action_step_enable_checkin_description\">Cihazınızın, en azından bir seferliğine Google\\'a kaydettirilmesi gerekiyor.\\n\\nHesap kurulumu tamamlandıktan sonra Google cihaz kaydını devre dışı bırakabilirsiniz.</string>\n    <string name=\"auth_action_step_enable_gcm\">Cloud Messaging\\'i etkinleştir</string>\n    <string name=\"auth_action_step_enable_lockscreen\">Güvenli ekran kilidi ayarla</string>\n    <string name=\"auth_action_step_enable_gcm_description\">Hesap kurulumu tamamlandıktan sonra Cloud Messaging\\'i geri kapatabilirsiniz.</string>\n    <string name=\"auth_action_step_allow_microg_gcm\">microG için Cloud Messaging\\'e izin ver</string>\n    <string name=\"auth_action_step_allow_microg_gcm_description\">Tercihlerinize göre, microG\\'nin kendisini Cloud Messaging\\'e kaydetmesi için sizin yetki vermeniz gerekiyor.</string>\n    <string name=\"auth_action_step_completed_content_description\">Adım tamamlandı</string>\n    <string name=\"auth_action_step_perform_content_description\">Adımı gerçekleştirmek için dokunun</string>\n    <string name=\"auth_action_activity_finish\">Bitir</string>\n    <string name=\"limited_services_dialog_information_ack\">Anlaşıldı</string>\n    <string name=\"auth_action_step_enable_checkin\">Cihaz kaydını etkinleştir</string>\n    <string name=\"auth_action_step_enable_lockscreen_description\">Google hesabınız, eğitim kurumunuz veya çalışma ortamınız tarafından yönetiliyor. Yöneticiniz, hesap verilerine erişilmeden önce cihazların bir ekran kilidine sahip olmasını zorunlu kıldı.\\n\\nBundan dolayı, lütfen cihazınızı bir şifre, PIN veya desen kilidi ile koruyun.</string>\n    <string name=\"limited_services_dialog_information\">microG Kısıtlı Servisleri\\'ni kullanıyorsunuz. Normal microG Servisleri\\'ne kıyasla, microG\\'nin bu varyasyonu, Google Play\\'deki uygulamalarla değil, özellikle microG kütüphanelerini kullanan uygulamalarla çalışacaktır. Diğer bir deyişle, çoğu uygulama, bu servisleri görmezden gelecektir.</string>\n    <string name=\"pref_vending_asset_delivery_summary\">Play Asset Delivery kullanan uygulamalar tarafından istendiğinde ek varlıkları indirir</string>\n    <string name=\"pref_vending_asset_delivery_category\">Google Play Varlık Dağıtımı</string>\n    <string name=\"pref_vending_asset_delivery_switch\">İstendiğinde varlık dağıtımını etkinleştir</string>\n    <string name=\"pref_vending_asset_device_sync_summary\">Play Asset Delivery kullanan uygulamalar, şu anki cihazın bilgilerine göre ek varlıklar indirecektir.</string>\n    <string name=\"pref_vending_asset_device_sync_switch\">Cihaz bilgi senkronizasyonunu etkinleştir</string>\n    <string name=\"games_achievement_list_title\">Başarımlar</string>\n    <string name=\"games_achievements_empty_text\">Bu oyun için başarım yok</string>\n    <string name=\"games_api_access_denied\">Bu cihazdaki hiçbir hesap Oyunlar API\\'sine erişemiyor</string>\n    <string name=\"games_achievement_locked_content_description\">kilitli</string>\n    <string name=\"games_achievement_unlocked_content_description\">kilidi açık</string>\n    <string name=\"games_achievement_extra_text\">%1$s XP</string>\n    <string name=\"games_leaderboard_empty_text\">Bu oyun için sıralama tablosu yok</string>\n    <string name=\"games_leaderboard_score_empty_text\">İnanılmaz! Bu oyun için halka açık kaydedilmiş bir yüksek skor yok.</string>\n    <string name=\"games_leaderboard_list_title\">Sıralamalar</string>\n    <string name=\"games_leaderboards_score_label\">Skor: %1$s</string>\n    <string name=\"games_snapshot_empty_text\">Henüz kaydedilen bir kayıtlı oyun yok</string>\n    <string name=\"games_snapshot_choose_btn_text\">seç</string>\n    <string name=\"games_delete_snapshot_dialog_message\">Bu oyun kaydını silmek istediğinizden emin misiniz?</string>\n    <string name=\"games_delete_snapshot_dialog_cancel\">İptal</string>\n    <string name=\"games_delete_snapshot_dialog_ok\">Tamam</string>\n    <string name=\"games_delete_snapshot_error\">Silme başarısız oldu, lütfen daha sonra tekrar deneyin</string>\n    <string name=\"games_delete_snapshot_dialog_title\">Kayıtlı oyunu sil</string>\n    <string name=\"games_snapshot_delete_btn_text\">sil</string>\n    <string name=\"auth_action_reauth_notification_title\">Hesapta eylem gerekiyor</string>\n    <string name=\"camera_permission_dialog_title\">Kamera izni gerekiyor</string>\n    <string name=\"camera_permission_dialog_button\">Tamam</string>\n    <string name=\"games_popup_signin_welcome\">Merhaba, %1$s</string>\n    <string name=\"games_delete_game_data_confirm_dialog_title\">%1$s için verileri sil</string>\n    <string name=\"games_delete_profile_fail\">Profiliniz silinemedi. Daha sonra tekrar deneyin.</string>\n    <string name=\"games_delete_profile_dialog_message\">Bu eylem geri alınamaz.</string>\n    <string name=\"games_delete_profile_dialog_title\">Bu hesabı silmek istediğinize emin misiniz?</string>\n    <string name=\"games_delete_profile_button\">Kalıcı olarak sil</string>\n    <string name=\"games_delete_profile_header\">Play Oyunlar hesabını &amp; tüm verileri sil</string>\n    <string name=\"games_account_display_content\">Şu anki hesap: %1$s</string>\n    <string name=\"games_change_default_account_for_new_games_snackbar_success_message\">Yeni oyunlarda %1$s olarak giriş yapacaksınız</string>\n    <string name=\"games_change_default_account_for_all_games_snackbar_success_message\">Bütün oyunlarda %1$s olarak giriş yapacaksınız</string>\n    <string name=\"games_change_sign_out_of_all_games_snackbar_success_message\">Bütün oyunlardan çıkış yaptınız</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out_snackbar_success_message\">Bu oyundan çıkış yaptınız</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out\">Çıkış yap</string>\n    <string name=\"games_change_per_game_dialog_option_use_player_snackbar_success_message\">Bu oyuna %1$s olarak giriş yapacaksınız</string>\n    <string name=\"games_change_per_game_dialog_option_use_player\">%1$s olarak</string>\n    <string name=\"games_change_per_game_dialog_title\">Bu oyun için bir seçenek seç</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_title\">Bütün oyunlardan çıkış yap</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_title\">Bütün oyunlar için varsayılan hesabı değiştir</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_description\">Şu anki varsayılan hesap: %1$s</string>\n    <string name=\"games_change_default_account_description\">Varsayılan hesap: %1$s</string>\n    <string name=\"games_change_button_text\">Değiştir</string>\n    <string name=\"games_state_description_delete\">Sil</string>\n    <string name=\"games_state_description_signed_out\">Çıkış yapıldı</string>\n    <string name=\"credentials_assisted_signin_add_account\">Hesap Ekle</string>\n    <string name=\"credentials_assisted_choose_account_error_tips\">Hesap tutarsızlığı</string>\n    <string name=\"pref_delete_game_account_data\">Play Oyunlar verisini sil</string>\n    <string name=\"pref_auto_create_player\">Play Oyunlar hesap kaydına izin ver</string>\n    <string name=\"pref_workprofile_create_account\">İş hesabı kurulumuna izin ver</string>\n    <string name=\"pref_vending_feature_delivery\">Google Play Özellik Dağıtımı</string>\n    <string name=\"pref_vending_split_install_switch\">İstenildiğinde bileşen kurulumu</string>\n    <string name=\"pref_vending_licensing_split_install_summary\">Uygulamaların ek bileşenler indirmesine ve bunları yüklemesine izin verir</string>\n    <string name=\"pref_game_accounts_title\">Google Oyun Hesapları</string>\n    <string name=\"pref_auth_two_step_verification_summary\">Etkinleştirildiğinde, bu cihaz Google\\'dan gelen iki adımlı doğrulama isteklerini alabilecek (Cloud Messaging\\'in etkinleştirilmesi gerekiyor).</string>\n    <string name=\"pref_auth_two_step_verification_title\">İki adımlı doğrulama isteklerini al</string>\n    <string name=\"service_name_work_profile\">İş profili</string>\n    <string name=\"pref_workprofile_intro\">İşyeriniz veya eğitim kurumunuz için bir iş profili oluştururken, kurulum sihirbazı, o profile uygulama indirmeyi etkinleştirmek için Google\\'a bağlanmaya çalışabilir.</string>\n    <string name=\"pref_workprofile_disclaimer\">microG kullanımınızın şirket politikalarına uygun olmasını sağlamak sizin sorumluluğunuzdadır. microG, en iyi çaba gösterilerek sağlanmaktadır ve beklendiği gibi çalışacağı garanti edilemez.</string>\n    <string name=\"pref_auto_create_player_intro\">Oyun oynarken, oturum açmak ve başarılar, liderlik tabloları gibi oyunla ilgili işlevleri kaydettirmek için bir Play Oyunlar hesabı kullanmanız gerekir. Devre dışı bırakılırsa, Play Oyunlar hesabına bağlı olmayan Google hesapları otomatik olarak kaydettirilmeyecek ve oyun içinde oturum açılamayacaktır.</string>\n    <string name=\"pref_allow_upload_game_played\">Oynanan oyunların bildirilmesine izin ver</string>\n    <string name=\"pref_allow_upload_game_played_summary\">Devre dışı bırakıldığında, oyunların, hesap ile giriş yapıldıktan sonra oynandığı durumunu bildirmesi engellenir, aynı zamanda bazı oyunlar hesaba giriş yapamayabilir.</string>\n    <string name=\"pref_change_default_game_player\">Oyunlar için kullanılacak hesabı değiştir</string>\n    <string name=\"games_change_default_account_section_title\">Oyunlar için varsayılan hesabı değiştir</string>\n    <string name=\"games_change_per_game_title\">Oyun için kullanılacak hesabı değiştir</string>\n    <string name=\"barcode_scanner_brand\">%1$s adına microG tarafından taratıldı</string>\n    <string name=\"camera_permission_dialog_message\">microG Servisleri\\'nin %1$s için barkodları okuyabilmesi için cihazınızın kamera iznine ihtiyacı var.\\n\\nEtkinleştirmek için Ayarlar üzerinden microG Servisleri\\'ne kamera iznini verin.</string>\n    <string name=\"family_management_title\">Aile</string>\n    <string name=\"family_management_retry\">Yeniden dene</string>\n    <string name=\"family_management_load_error\">İçerik yüklenirken hata</string>\n    <string name=\"family_management_toolbar_back\">Geri</string>\n    <string name=\"family_management_toolbar_more\">Daha fazla</string>\n    <string name=\"family_management_exit_family_group\">Aile grubundan ayrıl</string>\n    <string name=\"family_management_delete_family_group\">Aile grubunu sil</string>\n    <string name=\"family_management_leave_family_password_title\">Aile grubundan ayrılmak için şifreyi doğrulayın</string>\n    <string name=\"family_management_delete_family_password_title\">Aile grubunu silmek için şifreyi doğrulayın</string>\n    <string name=\"family_management_remove_member_password_title\">%s üyesini kaldırmak için şifreyi doğrulayın</string>\n    <string name=\"family_management_invite_family_member\">Aile üyesi davet et</string>\n    <string name=\"family_management_invite_slots_left\">%1$d davet kaldı</string>\n    <string name=\"family_management_cancel_invite\">Daveti iptal et</string>\n    <string name=\"family_management_cancel_invite_success\">Davet başarıyla iptal edildi</string>\n    <string name=\"family_management_cancel_invite_error\">Davet iptal edilirken hata. Tekrar deneyin.</string>\n    <string name=\"family_management_remove_member\">Üyeyi kaldır</string>\n    <string name=\"family_management_member_removed_success\">%s aile grubunuzdan kaldırıldı</string>\n    <string name=\"family_management_member_remove_failed\">%s üyesini kaldırırken hata. Tekrar deneyin.</string>\n    <string name=\"family_management_leave_family_error_message\">Aile grubundan ayrılırken hata. Tekrar deneyin.</string>\n    <string name=\"family_management_exist_group_success\">Aile grubunuzdan ayrıldınız…</string>\n    <string name=\"family_management_delete_group_success\">Aile grubu silindi</string>\n    <string name=\"family_management_delete_group_cancel\">İptal</string>\n    <string name=\"family_management_delete_group_confirm\">Tamam</string>\n    <string name=\"family_management_input_pwd\">Lütfen şifrenizi girin</string>\n    <string name=\"family_management_invite_sent_date_format\">Davet gönderilme zamanı: %s</string>\n    <string name=\"family_management_invite_send\">Davet gönderildi</string>\n    <string name=\"family_management_pwd_error\">Şifre yanlış, lütfen tekrar deneyin</string>\n    <string name=\"pref_app_install_settings_title\">Uygulama Kurucu Ayarları</string>\n    <string name=\"pref_app_install_switch_title\">Uygulama Kurulumuna İzin Ver</string>\n    <string name=\"pref_app_install_other_apps_note\">Diğer kaynaklardan sağlanan uygulamaların yüklenilmesine izin verir.</string>\n    <string name=\"pref_app_install_permission_instruction\">Yüklenen uygulamaların düzgün çalıştığından emin olmak için, microG Eşlikçisi\\'ne, diğer kaynaklardan indirilen uygulamaların kurulmasına izin verin.</string>\n    <string name=\"prefcat_app_install_list_title\">Uygulama Kurucuyu kullanan uygulamalar</string>\n    <string name=\"service_name_google_location_sharing\">Google Konum Paylaşımı</string>\n    <string name=\"location_sharing_description\">Bu cihazdan Google uygulamaları ve hizmetleri arasında gerçek zamanlı konum paylaşımınızı yönetin</string>\n    <string name=\"location_sharing_learn_more\">Konum Paylaşımı hakkında daha fazla bilgi alın</string>\n    <string name=\"location_sharing_switch_text\">Konum Paylaşımını Kullan</string>\n    <string name=\"location_sharing_turn_off_notify_hint\">Bu cihaz için Konum Paylaşımını devre dışı bırakırsanız, konum paylaştığınız kişiler bilgilendirilmeyecektir.</string>\n    <string name=\"location_sharing_off_previous_hint\">Tekrar açana kadar yalnızca son paylaştığınız konum görülebilir olacaktır.</string>\n    <string name=\"location_sharing_disabled\">Bu hesap için aktif konum paylaşımı yok</string>\n    <string name=\"location_sharing_turn_off_cancel\">Açık tut</string>\n    <string name=\"location_sharing_turn_off_confirm\">Kapalı hale getir</string>\n    <string name=\"location_sharing_confirm_dialog_title\">Konum Paylaşımını Etkinleştir</string>\n    <string name=\"location_sharing_confirm_dialog_text\">Konumunu paylaştığınız kişiler, size ait olan bu bilgileri her zaman görebilir:\\n·Adınızı ve fotoğrafınızı\\n·Google hizmeti kullanmıyor olsanız bile cihazınızdan alınan son konumu\\n·Cihazınızın şarj seviyesini ve şarja takılı olup olmadığını\\n·Eğer Konum Paylaşma bildirimine eklenmiş ise kalkış ve iniş sürelerinizi</string>\n    <string name=\"pref_change_default_game_player_summary\">Oyunlar için varsayılan hesabı değiştirin ve oyun başına hesabı değiştirin.</string>\n    <string name=\"pref_delete_game_account_data_summary\">Play Games hesabını ve tüm verileri silin ve tek tek oyun verilerini silin.</string>\n    <string name=\"games_change_default_account_explanation\">Bu hesap, oyunlara otomatik olarak giriş yapmanızı, oyun ilerlemenizi kaydetmenizi ve ayarlarınızı kaydetmenizi sağlamak için kullanılır. Varsayılan hesabı değiştirmek veya çıkış yapmak, oynadığınız oyunlardaki ilerlemenizi ve ayarlarınızı sıfırlayabilir.</string>\n    <string name=\"games_change_per_game_description\">Seçilen bir oyunun hesabını değiştirmek veya oyundan çıkış yapmak, oyundaki ilerlemenizi ve ayarlarınızı sıfırlayabilir.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_title\">Yeni varsayılan hesap için bir seçenek seçin</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_title\">Yalnızca yeni oyunlar için varsayılan hesabı değiştir</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_description\">Oynadığınız oyunların ilerlemelerine ve ayarlarına erişiminizi kaybetmeyeceksiniz. Ancak ilerlemeniz hesaplar arasında bölünecektir.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_description\">Oynadığınız oyunların ilerleme ve ayarlarına erişiminizi kaybedebilirsiniz. Değişikliklerinizi uygulamak için oyunu yeniden başlatacağız.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_description\">Oynadığınız oyunların ilerlemelerine ve ayarlarına erişiminizi kaybedebilirsiniz. Değişikliklerinizi uygulamak için oyunu yeniden başlatacağız.</string>\n    <string name=\"games_change_per_game_dialog_description\">Hesabı değiştirmek veya oturumu kapatmak, oyundaki ilerlemenizi ve ayarlarınızı sıfırlayabilir</string>\n    <string name=\"games_delete_profile_explanation\">Google Play Games hesabınızı, XP puanınızı ve tüm profil verilerinizi kalıcı olarak silin. Bu işlem, oynadığınız oyunlardaki puanlarınızı, ilerlemenizi (kaydedilmiş oyunlar) ve ayarlarınızı da silebilir.</string>\n    <string name=\"games_delete_game_data_header\">Bireysel oyun verilerini sil</string>\n    <string name=\"games_delete_game_data_explanation\">Google Play Games\\'i kullanarak oynadığınız oyunlara ait verileri kalıcı olarak silebilirsiniz. Bu işlem, seçtiğiniz oyuna ait puanlarınızı, ilerlemenizi (kaydedilmiş oyunlar) ve ayarlarınızı siler.</string>\n    <string name=\"games_delete_profile_explanation_with_gamer_name\">Oyuncu adı <b>%1$s</b> (<b>%2$s</b>) olan Google Play Games hesabınızı, XP puanınızı ve tüm profil verilerinizi kalıcı olarak silin. Bu işlem, oynadığınız oyunlardaki puanlarınızı, ilerlemenizi (kaydedilmiş oyunlar) ve ayarlarınızı da silebilir.</string>\n    <string name=\"games_delete_game_data_confirm_dialog_message\">%1$s için verilerinizi kalıcı olarak silmek, Google Play Oyunlar\\'daki puanlarınızı, ilerlemenizi (kaydedilmiş oyunlar) ve oyun ayarlarınızı silecektir.</string>\n    <string name=\"family_management_delete_group_failure\">Ev grubu silinmedi</string>\n    <string name=\"location_sharing_turn_on_hint\">Google uygulaması veya hizmetinden konumunuzu paylaşmaya başladığınızda, konum paylaşımını buradan yönetebilirsiniz.\\n\\nKonumunuzu paylaşmaya başlamak için Google Haritalar veya Family Link\\'e gidin.</string>\n    <string name=\"location_sharing_turn_off_title\">Konum Paylaşımını Kapat</string>\n    <string name=\"location_sharing_turn_off_hint\">Aynı Google Hesabı\\'na giriş yapmış diğer cihazlardan veya Google dışı uygulamalardan konumunuzu paylaşıyor olabilirsiniz. Konum paylaşım ayarlarınızı, geçerli olabilecek her yerde kontrol ettiğinizden emin olun.\\n\\nKonumunuzu paylaştığınız kişiler, en son paylaştığınız konumu görmeye devam edecek.</string>\n    <string name=\"service_name_device_attestation\">Cihaz Sertifikasyonu</string>\n    <string name=\"prefcat_device_attestation_apps_title\">Cihaz sertifikasyonu kullanan uygulamalar</string>\n    <string name=\"pref_device_attestation_app_allow_requests_title\">İsteklere izin ver</string>\n    <string name=\"pref_device_attestation_app_allow_requests_summary\">Bu uygulamanın cihaz sertifikasyonu isteği göndermesine izin verin</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-ug/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"permission_service_all_label\">بارلىق Google مۇلازىمىتى</string>\n    <string name=\"permission_service_android_label\">Android مۇلازىمىتى</string>\n    <string name=\"permission_service_android_description\">ئەپنىڭ باغلانغان خالىغان Google ھېساباتى ئارقىلىق بارلىق Android مۇلازىمىتىنى زىيارەت قىلىشىغا يول قويىدۇ.</string>\n    <string name=\"permission_service_adsense_label\">AdSense</string>\n    <string name=\"permission_service_adsense_description\">ئەپنىڭ باغلانغان خالىغان Google ھېساباتى ئارقىلىق AdSense نى زىيارەت قىلىشىغا يول قويىدۇ.</string>\n    <string name=\"permission_service_adwords_label\">AdWords</string>\n    <string name=\"permission_service_adwords_description\">ئەپنىڭ باغلانغان خالىغان Google ھېساباتى ئارقىلىق AdWords نى زىيارەت قىلىشىغا يول قويىدۇ.</string>\n    <string name=\"permission_service_ah_label\">Google ئەپ موتورى</string>\n    <string name=\"permission_service_ah_description\">ئەپنىڭ باغلانغان خالىغان Google ھېساباتى ئارقىلىق Google ئەپ موتورىنى زىيارەت قىلىشىغا يول قويىدۇ.</string>\n    <string name=\"permission_service_blogger_label\">بىلوگگېر</string>\n    <string name=\"permission_service_blogger_description\">ئەپنىڭ باغلانغان خالىغان Google ھېساباتى ئارقىلىق بىلوگگېرنى زىيارەت قىلىشىغا يول قويىدۇ.</string>\n    <string name=\"permission_service_cl_label\">Google يىلنامىسى</string>\n    <string name=\"permission_service_cl_description\">ئەپنىڭ باغلانغان خالىغان Google ھېساباتى ئارقىلىق Google يىلنامىسىنى زىيارەت قىلىشىغا يول قويىدۇ.</string>\n    <string name=\"permission_service_cp_label\">ئالاقەداش</string>\n    <string name=\"permission_service_cp_description\">ئەپنىڭ باغلانغان خالىغان Google ھېساباتى ئارقىلىق ئالاقەداشنى زىيارەت قىلىشىغا يول قويىدۇ.</string>\n    <string name=\"permission_service_dodgeball_label\">Dodgeball</string>\n    <string name=\"permission_service_dodgeball_description\">ئەپنىڭ باغلانغان خالىغان Google ھېساباتى ئارقىلىق Dodgeball نى زىيارەت قىلىشىغا يول قويىدۇ.</string>\n    <string name=\"permission_service_finance_label\">Google مالىيەسى</string>\n    <string name=\"permission_service_finance_description\">ئەپنىڭ باغلانغان خالىغان Google ھېساباتى ئارقىلىق Google مالىيەسىنى زىيارەت قىلىشىغا يول قويىدۇ.</string>\n    <string name=\"permission_service_gbase_label\">Google Base</string>\n    <string name=\"permission_service_gbase_description\">ئەپنىڭ باغلانغان خالىغان Google ھېساباتى ئارقىلىق Google Base نى زىيارەت قىلىشىغا يول قويىدۇ.</string>\n    <string name=\"permission_service_grandcentral_description\">ئەپنىڭ باغلانغان خالىغان Google ھېساباتى ئارقىلىق Google ئۈننى زىيارەت قىلىشىغا يول قويىدۇ.</string>\n    <string name=\"permission_service_groups2_label\">Google گۇرۇپپا</string>\n    <string name=\"permission_service_groups2_description\">ئەپنىڭ باغلانغان خالىغان Google ھېساباتى ئارقىلىق Google گۇرۇپپىسىنى زىيارەت قىلىشىغا يول قويىدۇ.</string>\n    <string name=\"permission_service_health_label\">Google ساغلاملىق</string>\n    <string name=\"permission_service_health_description\">ئەپنىڭ باغلانغان خالىغان Google ھېساباتى ئارقىلىق Google ساغلاملىقنى زىيارەت قىلىشىغا يول قويىدۇ.</string>\n    <string name=\"permission_service_ig_label\">iGoogle</string>\n    <string name=\"permission_service_ig_description\">ئەپنىڭ باغلانغان خالىغان Google ھېساباتى ئارقىلىق iGoogle نى زىيارەت قىلىشىغا يول قويىدۇ.</string>\n    <string name=\"permission_service_jotspot_label\">JotSpot</string>\n    <string name=\"permission_service_jotspot_description\">ئەپنىڭ باغلانغان خالىغان Google ھېساباتى ئارقىلىق JotSpot نى زىيارەت قىلىشىغا يول قويىدۇ.</string>\n    <string name=\"permission_service_knol_label\">Knol</string>\n    <string name=\"permission_service_knol_description\">ئەپنىڭ باغلانغان خالىغان Google ھېساباتى ئارقىلىق Knol نى زىيارەت قىلىشىغا يول قويىدۇ.</string>\n    <string name=\"permission_service_lh2_label\">Picasa تور ئالبومى</string>\n    <string name=\"permission_service_lh2_description\">ئەپنىڭ باغلانغان خالىغان Google ھېساباتى ئارقىلىق Picasa تور ئالبومىنى زىيارەت قىلىشىغا يول قويىدۇ.</string>\n    <string name=\"permission_service_local_label\">Google خەرىتە</string>\n    <string name=\"permission_service_local_description\">ئەپنىڭ باغلانغان خالىغان Google ھېساباتى ئارقىلىق Google خەرىتەنى زىيارەت قىلىشىغا يول قويىدۇ.</string>\n    <string name=\"permission_service_mail_label\">Google خەت</string>\n    <string name=\"permission_service_mail_description\">ئەپنىڭ باغلانغان خالىغان Google ھېساباتى ئارقىلىق Google خەتنى زىيارەت قىلىشىغا يول قويىدۇ.</string>\n    <string name=\"permission_service_news_label\">Google خەۋەرلىرى</string>\n    <string name=\"permission_service_news_description\">ئەپنىڭ باغلانغان خالىغان Google ھېساباتى ئارقىلىق Google خەۋەرلىرىنى زىيارەت قىلىشىغا يول قويىدۇ.</string>\n    <string name=\"permission_service_notebook_label\">Google خاتىرە دەپتىرى</string>\n    <string name=\"permission_service_notebook_description\">ئەپنىڭ باغلانغان خالىغان Google ھېساباتى ئارقىلىق Google خاتىرە دەپتىرىنى زىيارەت قىلىشىغا يول قويىدۇ.</string>\n    <string name=\"permission_service_orkut_label\">Orkut</string>\n    <string name=\"permission_service_orkut_description\">ئەپنىڭ باغلانغان خالىغان Google ھېساباتى ئارقىلىق Orkut نى زىيارەت قىلىشىغا يول قويىدۇ.</string>\n    <string name=\"permission_service_print_label\">Google كىتاب ئىزدەش</string>\n    <string name=\"permission_service_print_description\">ئەپنىڭ باغلانغان خالىغان Google ھېساباتى ئارقىلىق Google كىتاب ئىزدەشنى زىيارەت قىلىشىغا يول قويىدۇ.</string>\n    <string name=\"permission_service_sierra_label\">Google Checkout ھېساباتى</string>\n    <string name=\"permission_service_sierra_description\">ئەپنىڭ باغلانغان خالىغان Google ھېساباتى ئارقىلىق Google Checkout ھېساباتىنى زىيارەت قىلىشىغا يول قويىدۇ.</string>\n    <string name=\"permission_service_sierraqa_label\">Google Checkout سوئال جاۋاب ھېساباتى</string>\n    <string name=\"permission_service_sierraqa_description\">ئەپنىڭ باغلانغان خالىغان Google ھېساباتى ئارقىلىق Google Checkout سوئال جاۋاب ھېساباتىنى زىيارەت قىلىشىغا يول قويىدۇ.</string>\n    <string name=\"permission_service_sierrasandbox_label\">Google Checkout قۇم قۇتا ھېساباتى</string>\n    <string name=\"permission_service_sierrasandbox_description\">ئەپنىڭ باغلانغان خالىغان Google ھېساباتى ئارقىلىق Google Checkout قۇم قۇتا ھېساباتىنى زىيارەت قىلىشىغا يول قويىدۇ.</string>\n    <string name=\"permission_service_sitemaps_label\">Google Webmaster قورالى</string>\n    <string name=\"permission_service_sitemaps_description\">4ئەپنىڭ باغلانغان خالىغان Google ھېساباتى ئارقىلىق Google Webmaster قورالىنى زىيارەت قىلىشىغا يول قويىدۇ.</string>\n    <string name=\"permission_service_speech_label\">تاۋۇش ئىزدەش</string>\n    <string name=\"permission_service_speech_description\">ئەپنىڭ باغلانغان خالىغان Google ھېساباتى ئارقىلىق تاۋۇش ئىزدەشنى زىيارەت قىلىشىغا يول قويىدۇ.</string>\n    <string name=\"permission_service_speechpersonalization_label\">خاسلاشتۇرۇلغان ئاۋاز تونۇش</string>\n    <string name=\"permission_service_speechpersonalization_description\">ئەپنىڭ باغلانغان خالىغان Google ھېساباتى ئارقىلىق خاسلاشتۇرۇلغان ئاۋاز تونۇشنى زىيارەت قىلىشىغا يول قويىدۇ.</string>\n    <string name=\"permission_service_talk_label\">Google Talk</string>\n    <string name=\"permission_service_talk_description\">ئەپنىڭ باغلانغان خالىغان Google ھېساباتى ئارقىلىق Google Talk نى زىيارەت قىلىشىغا يول قويىدۇ.</string>\n    <string name=\"permission_service_wifi_label\">Google Wi-Fi</string>\n    <string name=\"permission_service_wifi_description\">ئەپنىڭ باغلانغان خالىغان Google ھېساباتى ئارقىلىق Google Wi-Fi نى زىيارەت قىلىشىغا يول قويىدۇ.</string>\n    <string name=\"permission_service_wise_label\">Google جەدۋەل</string>\n    <string name=\"permission_service_wise_description\">ئەپنىڭ باغلانغان خالىغان Google ھېساباتى ئارقىلىق Google جەدۋەلنى زىيارەت قىلىشىغا يول قويىدۇ.</string>\n    <string name=\"permission_service_writely_label\">Google پۈتۈك</string>\n    <string name=\"permission_service_writely_description\">ئەپنىڭ باغلانغان خالىغان Google ھېساباتى ئارقىلىق Google پۈتۈكنى زىيارەت قىلىشىغا يول قويىدۇ.</string>\n    <string name=\"permission_service_youtube_label\">YouTube</string>\n    <string name=\"permission_service_youtube_description\">ئەپنىڭ باغلانغان خالىغان Google ھېساباتى ئارقىلىق YouTube نى زىيارەت قىلىشىغا يول قويىدۇ.</string>\n    <string name=\"permission_service_YouTubeUser_label\">YouTube ئىشلەتكۈچى ئاتى</string>\n    <string name=\"permission_service_YouTubeUser_description\">ئەپنىڭ باغلانغان خالىغان Google ھېساباتى ئارقىلىق YouTube ئىشلەتكۈچى ئاتىنى زىيارەت قىلىشىغا يول قويىدۇ.</string>\n    <string name=\"perm_activity_recognition_label\">پائالىيەت تونۇش</string>\n    <string name=\"perm_activity_recognition_description\">ئەپنىڭ Google دىن قەرەللىك ھالدا پائالىيەت دەرىجىسىنىڭ يېڭىلىنىشىنى قوبۇللىشىغا يول قويىدۇ، مەسىلەن، مېڭىۋاتىدۇ، ماشىنا ھەيدەۋاتىدۇ، ۋېلىسىپىت مىنىۋاتىدۇ ياكى جىم تۇرۇۋاتامدۇ يوق.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_activity\">Google ئەپتىكى پائالىيەت تارىخىڭىزنى كۆرسىتىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.buyer\">Ad Exchange buyer ھېساباتىڭىزنىڭ سەپلىمىسىنى باشقۇرىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller.readonly\">Ad Exchange سانلىق مەلۇماتىڭىزنى كۆرسىتىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller\">Ad Exchange سانلىق مەلۇماتىڭىزنى كۆرسىتىپ ۋە باشقۇرىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsensehost\">سىزنىڭ AdSense مۇلازىمېتىر سانلىق مەلۇماتى ۋە مۇناسىۋەتلىك ھېساباتىڭىزنى كۆرسىتىپ ۋە باشقۇرىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense.readonly\">AdSense سانلىق مەلۇماتىڭىزنى كۆرسىتىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense\">AdSense سانلىق مەلۇماتىڭىزنى كۆرسىتىپ ۋە باشقۇرىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics\">Google Analytics سانلىق مەلۇماتىڭىزنى كۆرسىتىپ ۋە باشقۇرىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_androidpublisher\">Google Play Android ئىجادكار ئىجازىتىنى زىيارەت قىلىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appengine.admin\">ئەپ موتورى باشقۇرۇش دائىرىسى.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.migration\">Groups Migration API نىڭ ئوقۇش ۋە يېزىش ئىجازىتىنىڭ زىيارىتى.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.settings\">Google ئەپ گۇرۇپپىنىڭ تەڭشىكىنى كۆرسىتىپ ۋە باشقۇرىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.licensing\">ئىجازەتنامە باشقۇرغۇچ API نىڭ ئوقۇش ۋە يېزىش ئىجازىتىنىڭ زىيارىتى.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order\">ۋاكالەتچى سودىگەر باشقۇرغۇچى ۋە ئىشلەتكۈچىگە ماس كېلىدىغان API قۇم قۇتىسىدا سىنىغاندىكى ئوقۇش/يېزىش زىيارىتى ياكى بىۋاسىتە API نى چاقىرىش مەشغۇلاتى ئېلىپ بارغاندىكى ئوقۇش/يېزىش زىيارىتى.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order.readonly\">پۈتكۈل ئوقۇش/يېزىش OAuth دائىرىسىنىڭ سىرتىدا، ئىشلەتكۈچىنىڭ سانلىق مەلۇماتىغا ئېرىشكەندە يەنىلا ئوقۇشقىلا بولىدىغان OAuth دائىرىسىنى ئىشلىتىدۇ.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps_reporting_audit.readonly\">Admin Audit API ئوقۇشقىلا بولىدىغان ئىجازىتىنى زىيارەت قىلىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appstate\">ئەپ ھالەت مۇلازىمىتىنى ئىشلىتىش دائىرىسى.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery.readonly\">Google BigQuery دىكى سانلىق مەلۇماتىڭىزنى كۆرسىتىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery\">Google BigQuery دىكى سانلىق مەلۇماتىڭىزنى كۆرسىتىپ ۋە باشقۇرىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger\">Blogger ھېساباتىڭىزنى باشقۇرىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_books\">كىتابلىرىڭىزنى باشقۇرىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger.readonly\">Blogger ھېساباتىڭىزنى كۆرسىتىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar\">يىلنامەڭىزنى باشقۇرىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar.readonly\">يىلنامەڭىزنى كۆرسىتىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_cloudprint\">Google بۇلۇت پىرىنتېر سانلىق مەلۇماتىڭىزنى كۆرسىتىپ ۋە باشقۇرىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute.readonly\">Google كومپيۇتېر موتور مەنبەسىنى كۆرسىتىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute\">Google كومپيۇتېر موتور مەنبەسىنى كۆرسىتىپ ۋە باشقۇرىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate.readonly\">Google Coordinate jobs نى كۆرسىتىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate\">Google Maps Coordinate jobs نى كۆرسىتىپ ۋە باشقۇرىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.full_control\">Google بۇلۇت ساقلىغۇچىسىدىكى سانلىق مەلۇمات ۋە ئىجازەتلىرىڭىزنى باشقۇرىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_only\">Google بۇلۇت ساقلىغۇچىسىدىكى سانلىق مەلۇماتىڭىزنى كۆرسىتىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_write\">Google بۇلۇت ساقلىغۇچىسىدىكى سانلىق مەلۇماتىڭىزنى باشقۇرىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_dfareporting\">ئېلان بەرگۈچىلەرنىڭ دوكلاتى ئۈچۈن چېكىلىشنى كۆرسىتىپ ۋە باشقۇرىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.appdata\">ئەپ سانلىق مەلۇمات قىسقۇچىنى زىيارەت قىلىشقا يول قويىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.apps.readonly\">Google دىسكا ئەپىڭىزنى كۆرسىتىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.file\">بۇ ئەپ Google دىسكىدا سىز ئاچقان ياكى قۇرغان ھۆججەتلەرنى كۆرسىتىپ ۋە باشقۇرىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.install\">ئىشلەتكۈچىنىڭ ئەپ ئورنىتىشىغا ئىشلىتىلىدىغان ئالاھىدە ئىجازىتى</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.metadata.readonly\">Google دىسكىڭىزدىكى ھۆججەت ۋە پۈتۈكلەرنىڭ تەپسىلىي ئۇچۇرىنى كۆرسىتىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.readonly\">Google دىسكىڭىزدىكى ھۆججەت ۋە پۈتۈكلەرنى كۆرسىتىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.scripts\">Google ئەپ قوليازمىسىنىڭ قوليازما مەشغۇلاتىنى ئۆزگەرتىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive\">Google دىسكىڭىزدىكى ھۆججەت ۋە پۈتۈكلەرنى كۆرسىتىپ ۋە باشقۇرىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase.readonly\">Freebase ھېساباتىڭىزنى كۆرسىتىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase\">ھېساباتىڭىزدا Freebase كە تىزىمغا كىرىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables\">Fusion Tables نى باشقۇرىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables.readonly\">Fusion Tables نى كۆرسىتىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_games\">Google Play ئويۇنىنىڭ سانلىق مەلۇماتىنى زىيارەت قىلىش دائىرىسى.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan\">GAN سانلىق مەلۇماتىڭىزنى باشقۇرىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan.readonly\">GAN سانلىق مەلۇماتىڭىزنى كۆرسىتىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gcm_for_chrome\">Chrome نىڭ بۇلۇت ئۇچۇرى</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_glass.timeline\">Glass ۋاقىت ئوقى دائىرىسى</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.compose\">دەسلەپكى نۇسخىنى قۇرۇپ، ئوقۇپ، يېڭىلاپ ۋە ئۆچۈرىدۇ. ئۇچۇر يوللايدۇ ۋە دەسلەپكى نۇسخا.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.modify\">ئۇچۇرنى دەرھال ياكى مەڭگۈلۈك ئۆچۈرۈشتىن سىرت باشقا ئوقۇش/يېزىش مەشغۇلاتى، ئەخلەتخانا بۇنىڭ سىرتىدا.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.readonly\">بارلىق مەنبە ۋە ئۇلارنىڭ تەپسىلىي سانلىق مەلۇماتىنى ئوقۇيدۇ - يېزىش مەشغۇلاتى يوق.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.best\">ئەڭ ياخشى ئىشلىتىلىشچان ئورنىڭىز ۋە ئورۇن تارىخىڭىزنى باشقۇرىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.city\">شەھەر دەرىجىلىك ئورنىڭىز ۋە ئورۇن تارىخىڭىزنى باشقۇرىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.best\">ئەڭ ياخشى ئىشلىتىلىشچان ئورنىڭىزنى باشقۇرىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.city\">شەھەر دەرىجىلىك ئورنىڭىزنى باشقۇرىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine\">Google خەرىتە موتورى سانلىق مەلۇماتىڭىزنى كۆرسىتىپ ۋە باشقۇرىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine.readonly\">Google خەرىتە موتورى سانلىق مەلۇماتىڭىزنى كۆرسىتىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mobilemaps.firstparty\">Google خەرىتە كۆچمە تەسىراتىڭىزنى كۆرسىتىپ ۋە باشقۇرىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut\">Orkut پائالىيىتىڭىزنى باشقۇرىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut.readonly\">Orkut سانلىق مەلۇماتىڭىزنى كۆرسىتىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.login\">ئىسمىڭىز، ئاساسىي ئۇچۇر ۋە سىز Google+ دا ئالاقىلەشكەن كىشىلەرنىڭ تىزىمىنى بىلدۈرىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.me\">Google دىكى كىم ئىكەنلىكىڭىزنى بىلدۈرىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_prediction\">Google Prediction API دا سانلىق مەلۇماتلىرىڭىزنى باشقۇرىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_shoppingapi\">مەھسۇلات سانلىق مەلۇماتلىرىڭىزنى كۆرسىتىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification\">سىز تىزگىنلەيدىغان تور بېكەت ۋە دائىرە نامىنىڭ تىزىمىنى باشقۇرىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_structuredcontent\">Shopping Content API نىڭ ئوقۇش/يېزىش زىيارىتى.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue.consumer\">ۋەزىپە ئۆچرىتىڭىزدىكى ۋەزىپىنى ئىشلىتىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue\">ۋەزىپىڭىزنى باشقۇرىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks\">ۋەزىپىڭىزنى باشقۇرىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification.verify_only\">يېڭى تور بېكىتىڭىزنىڭ Google ئارقىلىق دەلىللىنىشىنى باشقۇرىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks.readonly\">ۋەزىپىڭىزنى كۆرسىتىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.email\">ئېلخەت ئادرېسىڭىزنى كۆرسىتىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.profile\">ھېساباتىڭىز ھەققىدىكى ئاساسىي ئۇچۇرلارنى كۆرسىتىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tracks\">Google Maps Tracks API، بۇ ئىجازەت قۇرۇلۇش سانلىق مەلۇماتىڭىزنى ئوقۇپ ۋە يېزىشىغا يول قويىدۇ.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_urlshortener\">سىزنىڭ goo.gl قىسقا تور ئادرېسىڭىزنى باشقۇرىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube\">YouTube ھېساباتىڭىزنى باشقۇرىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtubepartner\">YouTube تىكى بايلىق ۋە مۇناسىۋەتلىك مەزمۇنلىرىڭىزنى كۆرسىتىپ ۋە باشقۇرىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.readonly\">YouTube ھېساباتىڭىزنى كۆرسىتىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.upload\">YouTube سىنلىرىڭىزنى باشقۇرىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics_monetary.readonly\">YouTube مەزمۇنىڭىزنىڭ كىرىم تەھلىل دوكلاتىنى كۆرسىتىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics.readonly\">YouTube مەزمۇنىڭىزنىڭ تەھلىل دوكلاتىنى كۆرسىتىدۇ</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics.readonly\">Google Analytics سانلىق مەلۇماتىڭىزنى كۆرسىتىدۇ</string>\n    <string name=\"permission_service_all_description\">ئەپنىڭ باغلانغان خالىغان Google ھېساباتى ئارقىلىق بارلىق Google مۇلازىمىتىنى زىيارەت قىلىشىغا يول قويىدۇ.</string>\n    <string name=\"permission_service_grandcentral_label\">Google ئۈن</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-ug/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <plurals name=\"pref_unifiednlp_summary\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> ئارقا ئۇچ سەپلەندى</item>\n        <item quantity=\"other\"><xliff:g example=\"3\">%1$d</xliff:g> ئارقا ئۇچ سەپلەندى</item>\n    </plurals>\n    <plurals name=\"gcm_registered_apps_counter\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> ئەپ تىزىملىتىلغان</item>\n        <item quantity=\"other\"><xliff:g example=\"123\">%1$d</xliff:g> ئەپ تىزىملىتىلغان</item>\n    </plurals>\n    <plurals name=\"cond_perm_summary\">\n        <item quantity=\"one\">microG مۇلازىمىتى ئادەتتىكىدەك ئىشلەشكە زۆرۈر ئىجازەتكە ئېھتىياجلىق.</item>\n        <item quantity=\"other\">microG مۇلازىمىتى ئادەتتىكىدەك ئىشلەشكە زۆرۈر ئىجازەتكە ئېھتىياجلىق.</item>\n    </plurals>\n    <plurals name=\"cond_perm_action\">\n        <item quantity=\"one\">كەم ئىجازەت ئىلتىماسى</item>\n        <item quantity=\"other\">كەم ئىجازەتلەر ئىلتىماسى</item>\n    </plurals>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-ug/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=\"auth_general_error_desc\">Google مۇلازىمېتىر بىلەن ئالاقە قىلغاندا مەسىلە كۆرۈلدى.\\n\\nسەل تۇرۇپ قايتا سىناڭ.</string>\n    <string name=\"auth_finalize\">تېلېفونىڭىز Google بىلەن ئالاقە قىلىپ ئۇچۇرلارنى ھېساباتىڭىزغا ساقلايدۇ.\\n\\nبۇنىڭغا بىر قانچە مىنۇت كېتىشى مۇمكىن.</string>\n    <string name=\"allow\">يول قوي</string>\n    <string name=\"deny\">رەت قىل</string>\n    <string name=\"auth_notification_title\">سالاھىيەت دەلىللەش زۆرۈر</string>\n    <string name=\"auth_action_notification_channel_name\">Google ھېسابات ئاگاھلاندۇرۇشى</string>\n    <string name=\"auth_action_notification_channel_description\">سىزنىڭ كۆپ Google ھېساباتىڭىزدىن بىرىنى ئىشلىتىشتىن ئىلگىرى قوشۇمچە تەڭشەش زۆرۈر بولسا ياكى بىر ھېساباتىڭىز microG بىلەن ماسلاشمىسا ئۇقتۇرىدۇ.</string>\n    <string name=\"auth_action_notification_title\">ھېسابات مەشغۇلاتى زۆرۈر</string>\n    <string name=\"auth_action_notification_content\">Google ھېساباتىڭىز قوشۇمچە تەڭشەشكە موھتاج.</string>\n    <string name=\"auth_action_activity_header\">Google ھېساباتىڭىزنى تەڭشەشنى تاماملايدۇ</string>\n    <string name=\"auth_action_activity_explanation\">بۇ ئۈسكۈنىدىكى Google ھېساباتىڭىز %s نى ئىشلىتىش ئۈچۈن تۆۋەندىكى قەدەم باسقۇچنى تاماملاڭ.</string>\n    <string name=\"auth_action_step_enable_checkin\">ئۈسكۈنە تىزىملىتىشنى قوزغىتىدۇ</string>\n    <string name=\"auth_action_step_enable_checkin_description\">ئۈسكۈنىڭىزنى كەم دېگەندە بىر قېتىم Google غا تىزىملىتىشىڭىز كېرەك.\\n\\nھېسابات تەڭشەش تاماملانغاندىن كېيىن Google دا ئۈسكۈنە تىزىملىتىشنى چەكلىيەلەيسىز.</string>\n    <string name=\"auth_action_step_enable_gcm\">بۇلۇت ئۇچۇرلىشىشنى قوزغىتىدۇ</string>\n    <string name=\"auth_action_step_enable_lockscreen\">بىخەتەر ئېكران قۇلۇپى سەپلىمىسى</string>\n    <string name=\"auth_action_step_enable_lockscreen_description\">سىزنىڭ Google ھېساباتىڭىزنى خىزمەت ئورنىڭىز ياكى مائارىپ ئورۇنلىرى باشقۇرىدۇ. باشقۇرغۇچىڭىز ئۈسكۈنىڭىز ھېسابات سانلىق مەلۇماتىنى زىيارەت قىلىشتىن ئىلگىرى بىخەتەر ئېكران قۇلۇپى تەڭشەشنى تەۋسىيە قىلىدۇ.\\n\\nئىم، PIN ياكى ئەندىزە ئېكران قۇلۇپى تەڭشەڭ.</string>\n    <string name=\"auth_action_step_perform_content_description\">چېكىلسە قەدەم باسقۇچنى ئىجرا قىلىدۇ</string>\n    <string name=\"auth_action_step_completed_content_description\">قەدەم باسقۇچ تاماملاندى</string>\n    <string name=\"auth_action_step_enable_gcm_description\">ھېسابات تەڭشەش تاماملانغاندىن كېيىن بۇلۇت ئۇچۇرلىشىشنى چەكلىيەلەيسىز.</string>\n    <string name=\"auth_action_step_allow_microg_gcm\">microG نىڭ بۇلۇت ئۇچۇرلىشىشىغا يول قويىدۇ</string>\n    <string name=\"auth_action_step_allow_microg_gcm_description\">مايىللىقىڭىزغا ئاساسەن، microG ئۆزىنى بۇلۇت ئۇچۇرلىشىش سۈپىتىدە تىزىملىتىشى ئۈچۈن سىزنىڭ ئىجازىتىڭىزگە موھتاج.</string>\n    <string name=\"signin_picker_title\">ھېسابات تاللىنىدۇ</string>\n    <string name=\"signin_picker_add_account_label\">باشقا ھېسابات قوش</string>\n    <string name=\"signin_confirm_button_text\">يول قوي ۋە ھەمبەھىرلە</string>\n    <string name=\"signin_subtext_policy\">بۇ ئەپنى ئىشلىتىشتىن ئىلگىرى، %1$s ۋە %2$s نى قاراپ چىقىڭ.</string>\n    <string name=\"signin_subtext_policy_privacy\">شەخسىيەت تۈزۈمى</string>\n    <string name=\"signin_subtext_policy_terms\">مۇلازىمەت ماددىلىرى</string>\n    <string name=\"perm_status_broadcast_label\">ئىچكى ھالەت تارقىتىشنى تىڭشايدۇ</string>\n    <string name=\"perm_gsf_read_gservices_label\">Google مۇلازىمەت سەپلىمىسىنى ئوقۇيدۇ</string>\n    <string name=\"perm_c2dm_receive_label\">C2DM ئۇچۇرىنى تىڭشايدۇ</string>\n    <string name=\"auth_action_activity_finish\">تامام</string>\n    <string name=\"perm_c2dm_send_label\">باشقا ئەپكە C2DM ئۇچۇرى يوللايدۇ</string>\n    <string name=\"perm_gtalk_svc_label\">Google مۇلازىمېتىرىدىن ئۇچۇر ئالماشتۇرىدۇ ۋە قەدەمداش ئۇقتۇرۇشى تاپشۇرۇۋالىدۇ</string>\n    <string name=\"perm_extended_access_label\">كېڭەيتىلگەن Google مۇلازىمىتىنى زىيارەت قىلىدۇ</string>\n    <string name=\"perm_provision_label\">ئالدىن سەپلەنگەن microG مۇلازىمىتى</string>\n    <string name=\"perm_provision_description\">ئەپنىڭ ئىشلەتكۈچى ئارىلاشمىغان ئەھۋالدا microG مۇلازىمىتىنى سەپلىشىگە يول قويىدۇ</string>\n    <string name=\"perm_car_speed_label\">ماشىنا سۈرئىتى</string>\n    <string name=\"perm_car_speed_description\">ماشىنىڭىزنىڭ سۈرئىتىنى زىيارەت قىلىدۇ</string>\n    <string name=\"perm_car_info_label\">ماشىنا ئۇچۇرى</string>\n    <string name=\"perm_car_info_description\">ماشىنىڭىزنىڭ ئۇچۇرىنى زىيارەت قىلىدۇ</string>\n    <string name=\"perm_car_fuel_label\">ماشىنا يېقىلغۇ سەۋىيەسى</string>\n    <string name=\"service_name_checkin\">Google ئۈسكۈنە تىزىملىتىش</string>\n    <string name=\"service_name_mcs\">بۇلۇت ئۇچۇرلىشىش</string>\n    <string name=\"service_name_snet\">Google SafetyNet</string>\n    <string name=\"service_name_vending\">Play دۇكان مۇلازىمىتى</string>\n    <string name=\"games_title\">Google Play ئويۇنى</string>\n    <string name=\"perm_car_fuel_description\">ماشىنىڭىزنىڭ يېقىلغۇ سەۋىيەسىنىڭ ئۇچۇرىنى زىيارەت قىلىدۇ</string>\n    <string name=\"games_info_content\">Play ئويۇنىنى ئىشلىتىشتە Google Play ئەپنى ئورنىتىش زۆرۈر. ئەپ Play ئويۇنى ئورنىتىلمىسىمۇ داۋاملىق ئىجرا قىلىنىشى مۇمكىن، ئەمما كۈتۈلمىگەن مەسىلە كۆرۈلۈشى مۇمكىن.</string>\n    <string name=\"perm_car_mileage_label\">ماشىنا مۇساپىسى</string>\n    <string name=\"perm_car_mileage_description\">ماشىنىڭىزنىڭ مۇساپە ئۇچۇرىنى زىيارەت قىلىدۇ</string>\n    <string name=\"perm_car_vendor_extension_label\">ماشىنا سودىگىرىنىڭ قانىلى</string>\n    <string name=\"perm_car_vendor_extension_description\">ماشىنىنىڭ مۇئەييەن ئۇچۇرىنى ئالماشتۇرۇشتا ماشىنىڭىزنىڭ ساتقۇچى سودىگىرىنىڭ قانىلىنى زىيارەت قىلىدۇ</string>\n    <string name=\"pick_place_title\">ئورۇن تاللىنىدۇ</string>\n    <string name=\"pick_place_desc\">ئورۇن تاللىغۇچنى ئىشلەتكىلى بولمايدۇ.</string>\n    <string name=\"self_check_cat_fake_sig\">ئىمزا نىقابلاشنى قوللاش</string>\n    <string name=\"self_check_cat_gms_packages\">ئورنىتىلغان بوغچا</string>\n    <string name=\"self_check_cat_system\">سىستېما</string>\n    <string name=\"place_picker_select_title\">بۇ ئورۇننى تاللاڭ</string>\n    <string name=\"place_picker_nearby_places\">ئەتراپتىكى جاي</string>\n    <string name=\"place_picker_location_lat_lng\">(%1$.7f, %2$.7f)</string>\n    <string name=\"network_type_mobile\">كۆچمە تور</string>\n    <string name=\"network_type_wifi\">Wi-Fi</string>\n    <string name=\"network_type_roaming\">كەزمە</string>\n    <string name=\"network_type_other\">باشقا تور</string>\n    <string name=\"self_check_name_fake_sig_perm\">سىستېما ئىمزا نىقابلاشنى قوللايدۇ:</string>\n    <string name=\"self_check_resolution_fake_sig_perm\">سىزنىڭ ROM ڭىز ئىمزا نىقابلاشنى قوللىمايدۇ. سىز Xposed ياكى ئىمزا نىقابلاشنى قوللايدىغان سىستېمىنى ئىشلەتسىڭىز بولىدۇ. قوللانمىنى تەكشۈرۈپ قايسى ROM نىڭ ئىمزا نىقابلاشنى قوللايدىغانلىقىنى تەكشۈرۈپ ھەمدە قوللىمايدىغان ROM دا microG ئىشلىتىشنى ئۆگىنىڭ.</string>\n    <string name=\"self_check_name_perm_granted\">سىستېما ئىمزا نىقابلاش ئىجازىتىنى بەردى:</string>\n    <string name=\"self_check_name_system_spoofs\">سىستېما ئىمزانى نىقابلايدۇ:</string>\n    <string name=\"self_check_resolution_system_spoofs\">قايسى قەدەم باسقۇچنىڭ زۆرۈرلۈكىنى قوللانمىدىن تەكشۈرۈڭ.</string>\n    <string name=\"self_check_pkg_gms\">microG مۇلازىمىتى</string>\n    <string name=\"self_check_resolution_perm_granted\">بۇ سىستېمىڭىزنىڭ ئىمزا نىقابلاشنى قوللاش مۇمكىنچىلىكىنىڭ كۈچلۈكلۈكىنى بىلدۈرىدۇ ئەمما يەنىمۇ ئىلگىرىلىگەن ھالدا مەشغۇلات قىلىپ ئاكتىپلاش كېرەك. قايسى قەدەم باسقۇچلارنىڭ زۆرۈرلۈكىنى قوللانمىدىن تەكشۈرۈڭ.</string>\n    <string name=\"self_check_pkg_vending\">microG بۆلىكى/ Play دۇكىنى</string>\n    <string name=\"self_check_pkg_gsf\">microG مۇلازىمەت قۇرۇلمىسى</string>\n    <string name=\"self_check_name_battery_optimizations\">توكدان ئەلالاشتۇرۇشقا پەرۋا قىلمىدى:</string>\n    <string name=\"self_check_resolution_battery_optimizations\">بۇ جاي چېكىلسە توكدان ئەلالاشتۇرۇشنى چەكلەيدۇ. بۇنداق قىلمىغاندا ئەپ قىلمىشىدا مەسىلە كۆرۈلۈشى مۇمكىن.</string>\n    <string name=\"pref_auth_strip_device_name_summary\">قوزغىتىلغاندا، سالاھىيەت دەلىللەش ئىلتىماسى ئۈسكۈنە ئىسمىنى ئۆز ئىچىگە ئالمايدۇ، سالاھىيىتى دەلىللەنمىگەن ئۈسكۈنىدە تىزىمغا كىرىشكە يول قويۇشى مۇمكىن، ئەمما ئويلىشىلمىغان ئاقىۋەت كېلىپ چىقىشى مۇمكىن.</string>\n    <string name=\"prefcat_about\">ھەققىدە</string>\n    <string name=\"prefcat_components\">بۆلەك</string>\n    <string name=\"prefcat_configuration\">سەپلىمە</string>\n    <string name=\"prefcat_google_services\">Google مۇلازىمىتى</string>\n    <string name=\"prefcat_location_service\">ئورۇن مۇلازىمىتى</string>\n    <string name=\"prefcat_services\">مۇلازىمەت</string>\n    <string name=\"prefcat_test\">سىناق</string>\n    <string name=\"cond_gcm_bat_title\">توكدان ئەلالاشتۇرۇش قوزغىتىلدى</string>\n    <string name=\"cond_gcm_bat_summary\">microG مۇلازىمىتىنىڭ توكدان ئەلالاشتۇرۇشىنى ئاكتىپلانغاندىن كېيىن بۇلۇت ئۇچۇرلىشىشنى قوزغاتتىڭىز. يەتكۈزۈش ئۇقتۇرۇشىنىڭ ئادەتتىكىدەك يېتىپ بېرىشى ئۈچۈن توكدان ئەلالاشتۇرۇشقا پەرۋا قىلماسلىقىڭىز كېرەك.</string>\n    <string name=\"cond_gcm_bat_action\">ئەلالاشتۇرۇشقا پەرۋا قىلما</string>\n    <string name=\"cond_perm_title\">ئىجازەت كەم</string>\n    <string name=\"prefs_account\">ھېسابات مايىللىقى</string>\n    <string name=\"pref_auth_trust_google_title\">ئەپ ئىجازىتىنى Google تەمىنلەيدۇ</string>\n    <string name=\"pref_auth_trust_google_summary\">چەكلەنسە، ئەپ Google غا دەلىللەش ئىلتىماسى يوللاشتىن ئىلگىرى سىزنىڭ ماقۇللۇقىڭىزنى سورايدۇ. ئەگەر بۇ چەكلەنسە، بەزى ئەپلەر Google ھېساباتىنى ئىشلىتەلمەسلىكى مۇمكىن.</string>\n    <string name=\"pref_auth_visible_title\">ئەپنىڭ ھېساباتنى ئىزدىشىگە يول قويىدۇ</string>\n    <string name=\"pref_auth_visible_summary\">قوزغىتىلغاندا، بۇ ئۈسكۈنىدىكى بارلىق ئەپ ئىجازىتىڭىز بولمىغان تەقدىردىمۇ Google ھېساباتىڭىزغا باغلانغان ئېلخەت ئادرېسىنى كۆرەلەيدۇ.</string>\n    <string name=\"pref_auth_include_android_id_title\">ئۈسكۈنە تىزىملىتىش ئۇچۇرى بىلەن دەلىللەيدۇ</string>\n    <string name=\"pref_auth_include_android_id_summary\">چەكلەنگەندە، سالاھىيەت دەلىللەش ئىلتىماسى ئۈسكۈنە تىزىملىتىش ئۇچۇرىغا باغلانمايدۇ، سالاھىيىتى دەلىللەنمىگەن ئۈسكۈنىدە تىزىمغا كىرىشكە يول قويۇشى مۇمكىن، ئەمما ئويلىشىلمىغان ئاقىۋەت كېلىپ چىقىشى مۇمكىن.</string>\n    <string name=\"pref_auth_strip_device_name_title\">سالاھىيەت دەلىللەش ئۈچۈن ئۈسكۈنە ئىسمىنى ئاجرىتىدۇ</string>\n    <string name=\"pref_checkin_enable_summary\">ئۈسكۈنىڭىزنى Google مۇلازىمىتىگە تىزىملىتىپ، بىردىنبىر ئۈسكۈنە پەرقلەندۈرگۈچ ھاسىللايدۇ. microG تىزىملىتىش سانلىق مەلۇماتىدىكى Google ھېساباتىڭىزنىڭ ئىسمىدىن باشقا پەرقلەندۈرۈشكە ئىشلىتىدىغان ئۇچۇرلارنى چىقىرىۋېتىدۇ.</string>\n    <string name=\"pref_device_registration_android_id\">Android كىملىكى</string>\n    <string name=\"checkin_not_registered\">تىزىملىتىلمىغان</string>\n    <string name=\"checkin_enable_switch\">ئۈسكۈنە تىزىملىتىش</string>\n    <string name=\"pref_info_status\">ھالەت</string>\n    <string name=\"pref_more_settings\">تېخىمۇ كۆپ</string>\n    <string name=\"pref_accounts_title\">Google ھېساباتى</string>\n    <string name=\"pref_accounts_summary\">Google ھېساباتى قوشۇپ ۋە باشقۇرىدۇ</string>\n    <string name=\"prefcat_accounts_settings_title\">تەڭشەك</string>\n    <string name=\"prefcat_accounts_current_accounts_title\">ھېسابات</string>\n    <string name=\"pref_add_account_title\">ھېسابات</string>\n    <string name=\"pref_gcm_heartbeat_title\">بۇلۇت ئۇچۇرلىشىش يۈرەك سوقۇش ئارىلىقى</string>\n    <string name=\"pref_add_account_summary\">Google ھېساباتى قوش</string>\n    <string name=\"pref_gcm_heartbeat_summary\">سىستېما Google مۇلازىمېتىرىغا يۈرەك سوقۇش ئارىلىقىنىڭ سېكۇنت سانىنى يوللايدۇ. بۇ ئارىلىق ئۇزارتىلسا توك سەرپىياتىنى ئازايتىدۇ ئەمما ئۇچۇر يەتكۈزۈشنى كېچىكتۈرۈشى مۇمكىن.\\nقوللىمايدۇ، كەلگۈسىدىكى نەشرى ئورنىنى ئالىدۇ.</string>\n    <string name=\"pref_gcm_apps_title\">بۇلۇت ئۇچۇرلىشىشنى ئىشلىتىۋاتقان ئەپ</string>\n    <string name=\"pref_gcm_enable_mcs_summary\">Google بۇلۇت ئۇچۇرلىشىش نۇرغۇن ئۈچىنچى تەرەپ ئەپ تاللىغان ئۇچۇر يەتكۈزۈشنى تەمىنلىگۈچى. ئۇنى ئىشلىتىشتىن ئىلگىرى چوقۇم ئۈسكۈنە تىزىملىتىشنى قوزغىتىش كېرەك.</string>\n    <string name=\"pref_about_summary\">نەشر ئۇچۇرى ۋە ئىشلەتكەن ئامبارلار</string>\n    <string name=\"gcm_app_error_unregistering\">تىزىملىتىشنى بىكار قىلغاندا خاتالىق كۆرۈلدى</string>\n    <string name=\"pref_gcm_apps_summary\">نۆۋەتتە بۇلۇت ئۇچۇرلىشىشقا تىزىملاتقان ئەپ تىزىمى.</string>\n    <string name=\"pref_gcm_confirm_new_apps_title\">يېڭى ئەپنى جەزملەش</string>\n    <string name=\"pref_gcm_confirm_new_apps_summary\">يېڭى ئەپ يەتكۈزۈش ئۇقتۇرۇشىنى تىزىملىتىشتىن ئىلگىرى سورايدۇ</string>\n    <string name=\"pref_about_title\">microG مۇلازىمىتى ھەققىدە</string>\n    <string name=\"gcm_app_not_installed_anymore\">ئۆچۈرۈلگەن</string>\n    <string name=\"gcm_unregister_app\">تىزىملىتىشنى بىكار قىل</string>\n    <string name=\"gcm_not_registered\">تىزىملىتىلمىغان</string>\n    <string name=\"gcm_no_message_yet\">ھازىرغىچە ھېچقانداق ئۇچۇر تاپشۇرۇۋالمىدى</string>\n    <string name=\"gcm_registered\">تىزىملاتقان ۋاقىت</string>\n    <string name=\"gcm_unregister_confirm_message\">بەزى ئەپلەر ئۆزلۈكىدىن قايتا تىزىملاتمايدۇ ۋە ياكى قايتا تىزىملىتىش تاللانمىسى تەمىنلىمەيدۇ. تىزىملىتىشنى بىكار قىلغاندىن كېيىن بۇ ئەپلەر توغرا ئىشلىمەسلىكى مۇمكىن.\\nداۋاملاشتۇرامدۇ؟</string>\n    <string name=\"prefcat_push_networks_title\">يەتكۈزۈش ئۇقتۇرۇشى ئىشلىتىدىغان تور</string>\n    <string name=\"gcm_unregister_after_deny_message\">سىز يەتكۈزۈش ئۇقتۇرۇشىنى تىزىملاتقان ئەپنى تىزىملىتىشنى رەت قىلدىڭىز.\\nكەلگۈسىدە ئۇ ئۇچۇر يەتكۈزۈش ئۇقتۇرۇشى تاپشۇرۇۋالمايدۇ، ئۇنى تىزىملىتىشنى ھازىر بىكار قىلامسىز؟</string>\n    <string name=\"gcm_network_state_disconnected\">ئۈزۈلدى</string>\n    <string name=\"gcm_enable_switch\">يەتكۈزۈش ئۇقتۇرۇشى تاپشۇرۇۋالدى</string>\n    <string name=\"pref_push_app_allow_register_title\">تىزىملىتىشقا يول قويىدۇ</string>\n    <string name=\"pref_push_app_allow_register_summary\">ئەپنىڭ يەتكۈزۈش ئۇقتۇرۇشىنى تىزىملىتىشىغا يول قويىدۇ.</string>\n    <string name=\"pref_push_app_wake_for_delivery_title\">ئۇچۇر يەتكۈزگەندە ئەپنى قوزغىتىدۇ</string>\n    <string name=\"pref_push_app_wake_for_delivery_summary\">يەتكۈزۈش ئۇقتۇرۇشىنى تاپشۇرۇۋېلىش ئۈچۈن ئەپنى ئارقا سۇپىدا قوزغىتىدۇ.</string>\n    <string name=\"prefcat_push_apps_title\">يەتكۈزۈش ئۇقتۇرۇشى ئىشلىتىدىغان ئەپ</string>\n    <string name=\"prefcat_push_apps_registered_title\">تىزىملاتقان ئەپ</string>\n    <string name=\"prefcat_push_apps_unregistered_title\">تىزىملاتمىغان ئەپ</string>\n    <string name=\"safetynet_intro\">Google SafetyNet ئۈسكۈنە گۇۋاھنامە سىستېمىسى، ئۈسكۈنىنىڭ مۇۋاپىق بىخەتەرلىككە ئىگە ئىكەنلىكى ۋە Android CTS بىلەن ماسلىشىشىغا كاپالەتلىك قىلىدۇ. بەزى ئەپلەر بىخەتەرلىك سەۋەبىدىن ياكى ئۆزگەرتىشنىڭ ئالدىنى ئېلىش ئالدىنقى شەرتى بىلەن SafetyNet نى ئىشلىتىدۇ.\\n\\nmicroG GmsCore دا SafetyNet نىڭ ئەركىن ئەمەلىيلىشىشى جايلاشتۇرۇلغان، ئەمما رەسمىي مۇلازىمېتىر SafetyNet ئۆزىنىڭ مەخسۇس DroidGuard سىستېما ئىمزاسىنى ئىشلىتىشنى تەلەپ قىلىدۇ.</string>\n    <string name=\"safetynet_enable_switch\">ئۈسكۈنە دەلىللەشكە يول قويىدۇ</string>\n    <string name=\"pref_safetynet_test_title\">SafetyNet دەلىللەشنى سىنايدۇ</string>\n    <string name=\"pref_recaptcha_test_title\">ReCAPTCHA نى سىنايدۇ</string>\n    <string name=\"pref_recaptcha_enterprise_test_title\">ReCAPTCHA Enterprise نى سىنايدۇ</string>\n    <string name=\"pref_test_summary_passed\">بارلىق سىناقتىن ئۆتتى</string>\n    <string name=\"pref_test_summary_failed\">مەغلۇپ بولدى: %s</string>\n    <string name=\"pref_test_summary_warn\">ئاگاھلاندۇرۇش: %s</string>\n    <string name=\"pref_test_summary_running\">ئىجرا قىلىنىۋاتىدۇ…</string>\n    <string name=\"pref_droidguard_operation_mode\">مەشغۇلات ھالىتى</string>\n    <string name=\"prefcat_safetynet_apps_title\">SafetyNet ئىشلىتىدىغان ئەپ</string>\n    <string name=\"pref_droidguard_unsupported_summary\">بۇ ئۈسكۈنە DroidGuard ئىجرا قىلىشنى قوللىمايدۇ. SafetyNet مۇلازىمىتى نورمالسىز بولۇشى مۇمكىن.</string>\n    <string name=\"menu_clear_recent_requests\">يېقىنقى ئىلتىماسنى تازىلايدۇ</string>\n    <string name=\"profile_name_native\">يەرلىك</string>\n    <string name=\"profile_name_real\">ھەقىقىي</string>\n    <string name=\"profile_name_user\">ئىختىيارى: %s</string>\n    <string name=\"profile_name_auto\">ئاپتوماتىك: %s</string>\n    <string name=\"pref_device_registration_serial_title\">تەرتىپ نومۇرى</string>\n    <string name=\"pref_device_registration_import_custom_profile_summary\">ئۈسكۈنە سەپلىمە ھۆججىتىنى ھۆججەتتىن ئەكىرىدۇ</string>\n    <string name=\"pref_device_registration_select_profile_title\">سەپلىمە ھۆججەت تاللىنىدۇ</string>\n    <string name=\"profile_name_system\">سىستېما: %s</string>\n    <string name=\"pref_device_registration_import_custom_profile_title\">ئىختىيارى سەپلىمە ھۆججەت ئەكىرىدۇ</string>\n    <string name=\"pref_device_registration_device_profile_category\">ئۈسكۈنە سەپلىمىسى</string>\n    <string name=\"pref_safetynet_recent_uses\">يېقىندا ئىشلەتكىنى</string>\n    <string name=\"pref_safetynet_recent_attestation_summary\">ئىسپات: %s</string>\n    <string name=\"pref_safetynet_recent_recaptcha_summary\">ReCaptcha: %s</string>\n    <string name=\"pref_safetynet_recent_copy_json\">JSON JWS سانلىق مەلۇماتىنى كۆچۈرىدۇ</string>\n    <string name=\"pref_safetynet_recent_advice\">تەۋسىيە</string>\n    <string name=\"pref_safetynet_recent_eval_type\">باھالاش تۈرى</string>\n    <string name=\"pref_safetynet_recent_response_status\">ئىنكاس ھالىتى</string>\n    <string name=\"pref_safetynet_recent_recaptcha_enterprise_summary\">ReCaptcha Enterprise: %s</string>\n    <string name=\"pref_safetynet_recent_cat_response\">ئىنكاس سانلىق مەلۇماتى</string>\n    <string name=\"pref_safetynet_recent_cat_request\">سانلىق مەلۇمات ئىلتىماسى</string>\n    <string name=\"pref_safetynet_recent_nonce\">بىر قېتىم (ئون ئالتىلىك سىستېما)</string>\n    <string name=\"pref_safetynet_test_integrity_cts_passed\">مۇكەممەللىك ۋە CTS تەكشۈرۈشىدىن ئۆتتى</string>\n    <string name=\"pref_safetynet_test_cts_failed\">CTS تەكشۈرۈشىدىن ئۆتەلمىدى</string>\n    <string name=\"pref_safetynet_test_integrity_failed\">مۇكەممەللىك تەكشۈرۈشى مەغلۇپ بولدى</string>\n    <string name=\"pref_safetynet_recent_request_time\">ئىلتىماس ۋاقتى</string>\n    <string name=\"pref_safetynet_test_not_completed\">تېخى تاماملانمىدى</string>\n    <string name=\"pref_safetynet_recent_request_type\">ئىلتىماس تۈرى</string>\n    <string name=\"pref_safetynet_recent_cat_basic\">ئاساسىي سانلىق مەلۇمات</string>\n    <string name=\"pref_safetynet_recent_token\">پەرمان تاختا</string>\n    <string name=\"pref_safetynet_recent_copied\">چاپلاش تاختىسىغا كۆچۈرۈلدى!</string>\n    <string name=\"pref_safetynet_test_no_result\">نەتىجە يوق</string>\n    <string name=\"pref_safetynet_test_invalid_json\">ئىناۋەتسىز JSON</string>\n    <string name=\"push_notifications_summary_off\">تاقاق</string>\n    <string name=\"push_notifications_summary_automatic\">ئوچۇق/ئاپتوماتىك: %s</string>\n    <string name=\"push_notifications_summary_manual\">ئوچۇق/قولدا: %s</string>\n    <string name=\"push_notifications_summary_values_seconds\">%s سېكۇنت</string>\n    <string name=\"push_notifications_summary_values_minutes\">%s مىنۇت</string>\n    <string name=\"pref_vending_summary_licensing_off\">ئىجازەت دەلىللەش تاقاق</string>\n    <string name=\"pref_vending_summary_licensing_on\">ئىجازەت دەلىللەش ئوچۇق</string>\n    <string name=\"pref_vending_licensing_category\">Google Play ئىجازىتى</string>\n    <string name=\"pref_vending_license_enable_summary\">بەزى ئەپلەر سىزنىڭ Google Play دە سېتىۋالغانلىقىڭىزنى دەلىللەشنى تەلەپ قىلىدۇ. ئەپ تەلەپ قىلغاندا microG سېتىۋالغانلىق ئىسپاتىنى Google دىن چۈشۈرەلەيدۇ. ئەگەر بۇ تەڭشەك چەكلەنسە ياكى ئەگەر Google ھېساباتى قوشۇلمىغان بولسا، ئىجازەتنامە دەلىللەشنىڭ تەلىپىگە سەل قارىلىدۇ.</string>\n    <string name=\"pref_vending_licensing_enable_switch\">ئىجازەتنامە تەكشۈرۈش ئىلتىماس جاۋابى</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_switch\">ھەقسىز ئەپنى ئامبارغا ئۆزلۈكىدىن قوشىدۇ</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_summary\">ھەقسىز ئەپ ئۇلارنىڭ ئىلگىرى Google Play دىن چۈشۈرۈلگەن ياكى چۈشۈرۈلمىگەنلىكىنى تەكشۈرۈشى مۇمكىن. ھەقسىز ئەپنى ھېسابات ئامبىرىڭىزغا ئۆزلۈكىدىن قوشسا سىزنىڭ نۆۋەتتىكى ئىشلىتەلەيدىغان ھەممە ھەقسىز ئەپلىرىڭىزنى ھەمىشە تەكشۈرۈشتىن ئۆتكۈزۈۋېتىدۇ.</string>\n    <string name=\"feedback_disabled\">نۆۋەتتە قايتۇرما ئىنكاسنى ئىشلەتكىلى بولمايدۇ</string>\n    <string name=\"backup_disabled\">نۆۋەتتە زاپاسلاش ئىقتىدارىنى ئىشلەتكىلى بولمايدۇ</string>\n    <string name=\"pref_vending_billing_category\">Google Play ھېسابات سىستېمىسى</string>\n    <string name=\"pref_vending_billing_enable_switch\">ھېسابات سىستېما ئىلتىماسىنى بىر تەرەپ قىلىدۇ</string>\n    <string name=\"pref_vending_billing_enable_summary\">قوزغىتىلسا، بەزى ئەپلەر Google Play نىڭ ھېسابات سىستېما مۇلازىمىتى ئارقىلىق ئەپ ئىچىدە مال سېتىۋېلىشنى تاماملاپ ياكى مۇشتەرى بولۇشنى باشلىيالايدۇ.</string>\n    <string name=\"pref_vending_billing_note_experimental\">بۇ ئىقتىدار تەجرىبە خاراكتېرلىك، پۇلنىڭ يوقىلىپ كېتىشىنى كەلتۈرۈپ چىقىرىشى مۇمكىن. ئاگاھلاندۇرۇلدىڭىز.</string>\n    <string name=\"pref_vending_billing_note_licensing\">بەزى ئەپلەر مال سېتىۋېلىشنى دەلىللەش ئۈچۈن سىزدىن گۇۋاھنامە دەلىللەشنى قوزغىتىشنى تەلەپ قىلىشى مۇمكىن.</string>\n    <string name=\"pref_vending_asset_delivery_category\">Google Play مۈلۈك يەتكۈزۈش</string>\n    <string name=\"pref_vending_asset_delivery_switch\">ئېھتىياجغا ئاساسەن مۈلۈك يەتكۈزۈشنى قوزغىتىدۇ</string>\n    <string name=\"pref_vending_asset_delivery_summary\">Play مۈلۈك يەتكۈزۈش ئارقىلىق ئەپ ئىلتىماس يوللىغاندا نورمىدىن ئارتۇق مۈلۈكنى چۈشۈرىدۇ</string>\n    <string name=\"pref_vending_asset_device_sync_summary\">Play مۈلۈك يەتكۈزۈش ئارقىلىق ئەپ ئىلتىماس يوللىغاندا نۆۋەتتە ئىشلىتىلىۋاتقان ئۈسكۈنىنىڭ ئۇچۇرى ئاساسىدا نورمىدىن ئارتۇق مۈلۈكنى چۈشۈرىدۇ.</string>\n    <string name=\"pref_vending_asset_device_sync_switch\">ئۈسكۈنە ئۇچۇرىنى قەدەمداشلاشنى قوزغىتىدۇ</string>\n    <string name=\"credentials_assisted_cancel\">ۋاز كەچ</string>\n    <string name=\"credentials_assisted_continue\">داۋاملاشتۇر</string>\n    <string name=\"credentials_assisted_confirmation_header\">تىزىمغا كىرىۋاتىدۇ</string>\n    <string name=\"credentials_assisted_continue_as_user_button_label\">%1$s سۈپىتىدە داۋاملاشتۇرىدۇ</string>\n    <string name=\"credentials_assisted_sign_back_title\">Google ئارقىلىق %1$s‎ غا قايتا تىزىمغا كىرىدۇ</string>\n    <string name=\"games_achievement_list_title\">ئۇتۇق</string>\n    <string name=\"games_achievements_empty_text\">بۇ ئويۇننىڭ ئۇتۇقى يوق</string>\n    <string name=\"games_api_access_denied\">بۇ ئۈسكۈنىدە ئويۇن API نى زىيارەت قىلالايدىغان ھېسابات يوق</string>\n    <string name=\"games_achievement_locked_content_description\">قۇلۇپلانغان</string>\n    <string name=\"games_achievement_unlocked_content_description\">قۇلۇپ ئېچىلدى</string>\n    <string name=\"games_achievement_extra_text\">%1$s XP</string>\n    <string name=\"games_leaderboard_empty_text\">بۇ ئويۇندا شەرەپ تاختىسى يوق</string>\n    <string name=\"games_leaderboard_score_empty_text\">ئادەمنىڭ ئىشەنگۈسى كەلمەيدۇ! بۇ ئويۇننىڭ ئاشكارا يۇقىرى نومۇرى يوق.</string>\n    <string name=\"games_leaderboard_list_title\">دەرىجىسى</string>\n    <string name=\"games_leaderboards_score_label\">نومۇرى: %1$s</string>\n    <string name=\"games_snapshot_empty_text\">تېخى ھېچقانداق ئويۇن ساقلانمىغان</string>\n    <string name=\"games_snapshot_choose_btn_text\">تاللا</string>\n    <string name=\"games_snapshot_delete_btn_text\">ئۆچۈر</string>\n    <string name=\"games_delete_snapshot_dialog_title\">ساقلانغان ئويۇننى ئۆچۈرىدۇ</string>\n    <string name=\"games_delete_snapshot_dialog_message\">ساقلانغان بۇ ئويۇننى راستتىنلا ئۆچۈرەمسىز؟</string>\n    <string name=\"games_delete_snapshot_dialog_cancel\">ۋاز كەچ</string>\n    <string name=\"games_delete_snapshot_error\">ئۆچۈرەلمىدى، سەل تۇرۇپ قايتا سىناڭ</string>\n    <string name=\"games_delete_snapshot_dialog_ok\">جەزملە</string>\n    <string name=\"gms_app_name\">microG مۇلازىمىتى</string>\n    <string name=\"limited_services_app_name\">Microg چەكلىك مۇلازىمىتى</string>\n    <string name=\"gms_settings_name\">Microg تەڭشىكى</string>\n    <string name=\"gms_settings_summary\">microG مۇلازىمىتى تەڭشىكى.</string>\n    <string name=\"just_a_sec\">سەل كۈتۈڭ…</string>\n    <string name=\"google_account_label\">Google</string>\n    <string name=\"ask_permission_tos\">داۋاملاشتۇرۇلسا، بۇ ئەپ ۋە Google نىڭ ھەر قايسىسىنىڭ مۇلازىمەت شەرتلىرى ۋە شەخسىيەت تۈزۈمى بويىچە ئۇچۇرلىرىڭىزنى ئىشلىتىشىگە يول قويغان بولىسىز.</string>\n    <string name=\"account_manager_title\">Google ھېسابات باشقۇرغۇچ</string>\n    <string name=\"sorry\">كەچۈرۈڭ…</string>\n    <string name=\"auth_before_connect\">ئۈسكۈنىڭىزدىكى ئەپ Google ھېساباتقا كىرىشنى سىناۋاتىدۇ.\\n\\nئەگەر بۇ مەقسەتلىك بولسا، <b>تىزىمغا كىر</b>ىڭ توپچىنى ئىشلىتىپ Google نىڭ تىزىمغا كىرىش بېتىگە باغلىنىدۇ، ئەگەر ئۇنداق بولمىسا <b>ۋاز كەچ</b> نى چېكىپ بۇ كۆزنەكنى كۆرسەتكەن ئەپكە قايتىڭ.</string>\n    <string name=\"auth_sign_in\">تىزىمغا كىر</string>\n    <string name=\"auth_connecting\">ئۈسكۈنىڭىز سىزنى تىزىمغا كىرگۈزۈش ئۈچۈن Google مۇلازىمېتىرى بىلەن باغلىنىش قۇرۇۋاتىدۇ.\\n\\nبۇنىڭغا بىر نەچچە سېكۇنت كېتىدۇ.</string>\n    <string name=\"no_network_error_desc\">ئىنتېرنېت باغلىنىشىڭىز يوق.\\n\\nبۇ بىر ۋاقىتلىق مەسىلە ياكى Android ئۈسكۈنىڭىز سانلىق مەلۇمات مۇلازىمىتىنى ئىشلىتەلمەيدۇ. كۆچمە تور ياكى Wi-Fi تورىغا باغلانغاندا قايتا سىناڭ.</string>\n    <string name=\"ask_scope_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> قىلىدىغىنى:</string>\n    <string name=\"ask_service_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> ئىشلىتىدىغىنى:</string>\n    <string name=\"auth_notification_content\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> ھېساباتىڭىزنى زىيارەت قىلىشى ئۈچۈن ئىجازىتىڭىز بولۇشى كېرەك.</string>\n    <string name=\"auth_package_override_request_title\"><b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> نىڭ <xliff:g example=\"account@example.com\">%2$s</xliff:g> نى زىيارەت قىلىشىغا يول قويامدۇ؟</string>\n    <string name=\"auth_package_override_request_message\"><b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> ھېساباتىڭىزنى زىيارەت قىلماقچى، ئۇ <b><xliff:g example=\"F-Droid\">%2$s</xliff:g> <xliff:g example=\"F-Droid Inc.\">%3$s</xliff:g></b> دەك قىلىدۇ. بۇ ھېساباتىڭىزنى زىيارەت قىلىشقا ئىجازەت بېرىشى مۇمكىن.</string>\n    <string name=\"signin_picker_subtitle\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> نى داۋاملاشتۇرۇشتا</string>\n    <string name=\"signin_confirm_title\">سىزنىڭ <xliff:g example=\"F-Droid\">%1$s</xliff:g> قا تىزىمغا كىرىشىڭىزگە يول قويىدۇ</string>\n    <string name=\"signin_subtext_sharing\">داۋاملاشتۇرۇلسا، microG سىزنىڭ Google ھېساباتىڭىزنىڭ ئىسمى، ئېلخەت ئادرېسى ۋە تەرجىمىھال رەسىمىنى <xliff:g example=\"F-Droid\">%1$s</xliff:g> غا ھەمبەھىرلەيدۇ.</string>\n    <string name=\"games_info_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> Play ئويۇنىنى ئىشلەتمەكچى</string>\n    <string name=\"lacking_permission_toast\">microG مۇلازىمىتى: <xliff:g example=\"have full network acccess\">%1$s</xliff:g> ئىجازىتى كەم</string>\n    <string name=\"prefs_account_privacy\">شەخسىي ئۇچۇر ۋە شەخسىيەت</string>\n    <string name=\"prefs_account_security\">تىزىمغا كىرىش ۋە بىخەتەرلىك</string>\n    <string name=\"self_check_name_app_installed\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> ئورنىتىلدى:</string>\n    <string name=\"self_check_resolution_app_installed\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> ئەپ ياكى ماسلىشىدىغاندىن بىرنى ئورنىتىڭ. قايسى ئەپنىڭ ماس كېلىدىغانلىقىنى قوللانمىدىن تەكشۈرۈڭ.</string>\n    <string name=\"self_check_name_correct_sig\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> دا توغرا ئىمزا بار:</string>\n    <string name=\"self_check_resolution_correct_sig\">ئورنىتىلغان <xliff:g example=\"F-Droid\">%1$s</xliff:g> ماسلاشمايدۇ ياكى ئىمزا نىقابلاشنى قوزغاتمىدىڭىز. قايسى ئەپ ۋە ROM نىڭ ماسلىشىدىغانلىقىنى قوللانمىدىن تەكشۈرۈڭ.</string>\n    <string name=\"checkin_last_registration\">ئاخىرقى تىزىملاتقان ۋاقىت: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"pref_gcm_ping_interval\">Ping ئارىلىقى: <xliff:g example=\"10 minutes\">%1$s</xliff:g></string>\n    <string name=\"gcm_last_message_at\">ئاخىرقى ئۇچۇر: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_registered_since\">تىزىملاتقان ۋاقتى: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_unregister_confirm_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> تىزىملىتىشنى بىكار قىلامدۇ؟</string>\n    <string name=\"gcm_messages_counter\">ئۇچۇر: <xliff:g example=\"123\">%1$d</xliff:g> (<xliff:g example=\"12345\">%2$d</xliff:g> بايت)</string>\n    <string name=\"gcm_network_state_connected\">باغلانغان ۋاقتى: <xliff:g example=\"2 hours ago\">%1$s</xliff:g></string>\n    <string name=\"gcm_allow_app_popup\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> نىڭ يەتكۈزۈش ئۇقتۇرۇشى تىزىملىتىشىغا يول قويامدۇ؟</string>\n    <string name=\"safetynet_last_run_at\">ئاخىرقى ئىشلەتكەن ۋاقتى: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"credentials_assisted_signin_consent_header\">%1$s سۈپىتىدە تىزىمغا كىرىۋاتىدۇ</string>\n    <string name=\"credentials_assisted_signin_consent\">داۋاملاشتۇرۇلسا، Google ئىسىم، ئېلخەت ئادرېسى ۋە تەرجىمىھال رەسىمىنى %1$s غا ھەمبەھىرلەيدۇ. %1$s نىڭ شەخسىيەت تۈزۈمى ۋە مۇلازىمەت ماددىلىرىنى كۆرۈڭ.</string>\n    <string name=\"credentials_assisted_signin_description\">سىز Google ھېساباتىڭىزدا Google ئارقىلىق تىزىمغا كىرىش ئىقتىدارىنى باشقۇرالايدۇ.</string>\n    <string name=\"credentials_assisted_choose_account_label\">ھېسابات تاللىنىدۇ</string>\n    <string name=\"credentials_assisted_choose_account_subtitle\">%1$s نى ئىشلىتىشنى داۋاملاشتۇرىدۇ</string>\n    <string name=\"credentials_assisted_signin_button_text_long\">Google ئارقىلىق تىزىمغا كىرىڭ</string>\n    <string name=\"limited_services_dialog_information\">سىز microG چەكلىك مۇلازىمەت نەشرىنى ئىشلىتىۋاتىسىز. ئادەتتىكى microG مۇلازىمىتى بىلەن ئوخشىمايدىغىنى، مەزكۇر نەشرى پەقەت microG ئامبىرىنى ئىشلىتىدىغان ئەپكىلا ماس كېلىدۇ، Google Play دىكى ئەپكە ئەمەس. كۆپىنچە ئەپلەر بۇ مۇلازىمەتلەرگە پەرۋا قىلمايدىغانلىقىنى بىلدۈرىدۇ.</string>\n    <string name=\"limited_services_dialog_information_ack\">چۈشەندىم</string>\n    <string name=\"pref_vending_split_install_switch\">ئېھتىياجغا قاراپ بۆلەك ئورنىتىش</string>\n    <string name=\"camera_permission_dialog_button\">جەزملە</string>\n    <string name=\"pref_workprofile_create_account\">خىزمەت ھېساباتىنى تەڭشەشكە يول قويىدۇ</string>\n    <string name=\"pref_vending_licensing_split_install_summary\">ئەپنىڭ قوشۇمچە بۆلەكنى چۈشۈرۈپ ۋە ئورنىتىشىغا يول قويىدۇ</string>\n    <string name=\"barcode_scanner_brand\">«%1$s» غا ۋاكالىتەن microG تارىغان</string>\n    <string name=\"pref_workprofile_disclaimer\">microG نى ئىشلىتىش شىركىتىڭىزنىڭ تۈزۈمىگە ئۇيغۇن بولۇشىنى جەزملەش سىزنىڭ مەسئۇلىيىتىڭىز. microG ئەڭ زور تىرىشچانلىق كۆرسىتىپ تەمىنلەنگەن، پۈتۈنلەي كۆڭۈلدىكىدەك ئىجرا قىلىنىشىغا كاپالەتلىك قىلمايدۇ.</string>\n    <string name=\"service_name_work_profile\">خىزمەت تەرجىمىھالى</string>\n    <string name=\"pref_workprofile_intro\">خىزمە ئورنىڭىز ياكى مائارىپ ئورۇنلىرىغا خىزمەت تەرجىمىھالى تەڭشىگەندە، تەڭشەش پىروگراممىسى Google غا باغلىنىپ تەرجىمىھالغا كېرەكلىك ئەپلەرنى چۈشۈرۈشنى سىنىشى مۇمكىن.</string>\n    <string name=\"pref_vending_feature_delivery\">Google Play ئىقتىدار يەتكۈزۈش</string>\n    <string name=\"credentials_assisted_choose_account_error_tips\">ھېسابات نورمالسىزلىقى</string>\n    <string name=\"credentials_assisted_signin_add_account\">ھېسابات قوش</string>\n    <string name=\"camera_permission_dialog_title\">كامېرا ئىجازىتى زۆرۈر</string>\n    <string name=\"camera_permission_dialog_message\">microG مۇلازىمىتى %1$s نىڭ كودىنى تاراش ئۈچۈن ئۈسكۈنىڭىزنىڭ كامېراسىنى زىيارەت قىلىشقا ئېھتىياجلىق.\\n\\nقوزغىتىشتا، تەڭشەكتىن microG غا كامېرا زىيارەت ئىجازىتى بېرىڭ.</string>\n    <string name=\"auth_action_reauth_notification_title\">ھېسابات مەشغۇلاتى زۆرۈر</string>\n    <string name=\"pref_auth_two_step_verification_title\">ئىككى قەدەملىك دەلىللەش ئۇچۇرىنى قويۇل قىلىدۇ</string>\n    <string name=\"pref_auth_two_step_verification_summary\">قوزغىتىلغاندا، ئۈسكۈنە Google (بۇلۇت ئۇچۇرلىشىش زۆرۈر) دىن ئىككى قەدەملىك دەلىللەش ئۇقتۇرۇشىنى تاپشۇرۇۋالالايدۇ.</string>\n    <string name=\"pref_game_accounts_title\">Google ئويۇن ھېساباتى</string>\n    <string name=\"pref_auto_create_player\">Play ئويۇن ھېساباتىنى تىزىملىتىشقا يول قويىدۇ</string>\n    <string name=\"pref_allow_upload_game_played\">ئوينىغان ئويۇن ھالىتىنى يۈكلەشكە يول قويىدۇ</string>\n    <string name=\"pref_auto_create_player_intro\">ئويۇن ئوينىغاندا، سىز Play ئويۇن ھېساباتىدا تىزىمغا كىرىپ ۋە ئويۇنغا ئائىت ئىقتىدارنى خاتىرىلىشىڭىز كېرەك، مەسىلەن، نەتىجە، رەت تەرتىپ، ئارخىپ قاتارلىق. چەكلەنگەندىن كېيىن، Play ئويۇن ھېساباتقا باغلانمىغان Google ھېسابات ئۆزلۈكىدىن تىزىملاتمايدۇ شۇڭا ئويۇن ئۆزلۈكىدىن تىزىمغا كىرمەيدۇ.</string>\n    <string name=\"pref_allow_upload_game_played_summary\">چەكلەنگەندە، ئويۇنغا تىزىمغا كىرگەندىن كېيىن ئويۇن ئويناۋاتقان ھالەتنى دوكلات قىلمايدۇ ۋە بەزى ئويۇنغا شۇ سەۋەبتىن تىزىمغا كىرەلمەسلىكى مۇمكىن.</string>\n    <string name=\"pref_change_default_game_player\">ئويۇن ھېساباتىنى ئۆزگەرت</string>\n    <string name=\"pref_change_default_game_player_summary\">كۆڭۈلدىكى ئويۇن ھېساباتىنى ئۆزگەرتىپ ۋە ئويۇنغا ئاساسەن ھېساباتنى ئۆزگەرتىدۇ.</string>\n    <string name=\"pref_delete_game_account_data\">Play ئويۇن سانلىق مەلۇماتىنى ئۆچۈر</string>\n    <string name=\"pref_delete_game_account_data_summary\">Play ئويۇن ھېساباتى ۋە بارلىق سانلىق مەلۇمات شۇنداقلا ئايرىم ئويۇن سانلىق مەلۇماتىنى ئۆچۈرىدۇ.</string>\n    <string name=\"games_state_description_signed_out\">تىزىمدىن چىقتى</string>\n    <string name=\"games_state_description_delete\">ئۆچۈر</string>\n    <string name=\"games_change_button_text\">ئۆزگەرت</string>\n    <string name=\"games_change_default_account_section_title\">ئويۇننىڭ كۆڭۈلدىكى ھېساباتىنى ئۆزگەرتىدۇ</string>\n    <string name=\"games_change_default_account_description\">كۆڭۈلدىكى ھېساب: %1$s</string>\n    <string name=\"games_change_default_account_explanation\">بۇ ھېسابات ئويۇنغا ئۆزلۈكىدىن تىزىمغا كىرىش ۋە ئويۇن ئىلگىرىلىشى ۋە تەڭشىكىنى ساقلاشقا ئىشلىتىلىدۇ. كۆڭۈلدىكى ھېسابات ئۆزگەرتىلسە ياكى تىزىمدىن چىقسا سىز ئوينىغان ئويۇننىڭ ئىلگىرىلىشى ۋە تەڭشىكى ئەسلىگە قايتۇرۇلۇشى مۇمكىن.</string>\n    <string name=\"games_change_per_game_title\">ھېسابنى ئويۇن بويىچە ئۆزگەرت</string>\n    <string name=\"games_change_per_game_description\">تاللانغان ئويۇننىڭ ھېسابى ئۆزگەرتىلسە ياكى تىزىمدىن چىقسا ئويۇن ئىلگىرىلىشى ۋە تەڭشىكى ئەسلىگە قايتۇرۇلۇشى مۇمكىن.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_title\">يېڭى كۆڭۈلدىكى ھېسابقا بىر تاللانما تاللىنىدۇ</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_description\">نۆۋەتتىكى كۆڭۈلدىكى ھېساب: %1$s</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_title\">پەقەت يېڭى ئويۇننىڭ كۆڭۈلدىكى ھېسابىنىلا ئۆزگەرتىدۇ</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_description\">سىز ئوينىغان ئويۇننىڭ ئىلگىرىلىشى ۋە تەڭشىكىنى يەنىلا كۆرەلەيسىز. ئەمما ئىلگىرىلىشىڭىز ئەسلى ھېسابات بىلەن يېڭى ھېسابات ئارىسىدا ئايرىم-ئايرىم ساقلىنىدۇ.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_title\">ھەممە ئويۇننىڭ كۆڭۈلدىكى ھېسابىنى ئۆزگەرتىدۇ</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_description\">سىز ئوينىغان ئويۇننىڭ ئىلگىرىلىشى ۋە تەڭشىكىنى زىيارەت قىلىشتىن مەھرۇم قېلىشىڭىز مۇمكىن. ئۆزگەرتىشىڭىزنى قوللىنىش ئۈچۈن سىستېما ئويۇننى قايتا قوزغىتىدۇ.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_title\">ھەممە ئويۇندىن تىزىمدىن چىقىدۇ</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_description\">سىز ئوينىغان ئويۇننىڭ ئىلگىرىلىشى ۋە تەڭشىكىنى زىيارەت قىلىشتىن مەھرۇم قېلىشىڭىز مۇمكىن. ئۆزگەرتىشىڭىزنى قوللىنىش ئۈچۈن سىستېما ئويۇننى قايتا قوزغىتىدۇ.</string>\n    <string name=\"games_change_per_game_dialog_title\">بۇ ئويۇنغا بىر تاللانما تاللىنىدۇ</string>\n    <string name=\"games_change_per_game_dialog_description\">ئويۇننىڭ ھېسابى ئۆزگەرتىلسە ياكى تىزىمدىن چىقسا ئويۇن ئىلگىرىلىشى ۋە تەڭشىكى ئەسلىگە قايتۇرۇلۇشى مۇمكىن</string>\n    <string name=\"games_change_per_game_dialog_option_use_player\">%1$s ئىشلەت</string>\n    <string name=\"games_change_per_game_dialog_option_use_player_snackbar_success_message\">بۇ ئويۇنغا %1$s دەپ كىرىسىز</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out\">تىزىمدىن چىق</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out_snackbar_success_message\">ھازىر بۇ ئويۇندىن چىقتىڭىز</string>\n    <string name=\"games_change_sign_out_of_all_games_snackbar_success_message\">ھازىر ھەممە ئويۇندىن چىقتىڭىز</string>\n    <string name=\"games_change_default_account_for_all_games_snackbar_success_message\">سىز ھەممە ئويۇنغا %1$s دەپ تىزىمغا كىرىسىز</string>\n    <string name=\"games_change_default_account_for_new_games_snackbar_success_message\">سىز يېڭى ئويۇنغا %1$s دەپ تىزىمغا كىرىسىز</string>\n    <string name=\"games_account_display_content\">نۆۋەتتىكى ھېساب: %1$s</string>\n    <string name=\"games_delete_profile_header\">Play ئويۇن ھېسابى ۋە ھەممە سانلىق مەلۇماتنى ئۆچۈر</string>\n    <string name=\"games_delete_profile_explanation\">سىزنىڭ Google Play ئويۇن ھېسابىڭىز، تەجرىبە قىممىتى ۋە بارلىق تەرجىمىھال سانلىق مەلۇماتىڭىزنى مەڭگۈلۈك ئۆچۈرىدۇ. بۇ مەشغۇلات يەنە سىز ئوينىغان ئويۇندىكى نومۇر، ئىلگىرىلەش (ساقلانغان ئويۇن) ۋە تەڭشەكنىمۇ ئۆچۈرۈشى مۇمكىن.</string>\n    <string name=\"games_delete_profile_button\">مەڭگۈلۈك ئۆچۈر</string>\n    <string name=\"games_delete_game_data_header\">ئايرىم ئويۇن سانلىق مەلۇماتىنى ئۆچۈر</string>\n    <string name=\"games_delete_game_data_explanation\">سىز Google Play ئويۇنىدا ئوينىغان ئايرىم ئويۇن سانلىق مەلۇماتىنى مەڭگۈلۈك ئۆچۈرەلەيسىز. بۇ مەشغۇلات سىز تاللىغان ئويۇننىڭ ئويۇن نومۇرى، ئىلگىرىلىشى (ساقلانغان ئويۇن) ۋە تەڭشەكنى قوشۇپ بىللە ئۆچۈرىدۇ.</string>\n    <string name=\"games_delete_profile_dialog_title\">بۇ ھېسابنى راستتىنلا ئۆچۈرەمسىز؟</string>\n    <string name=\"games_delete_profile_explanation_with_gamer_name\">سىزنىڭ Google Play ئويۇن ھېسابىڭىزدىكى<b>%1$s</b> (<b>%2$s</b>) ئاتلىق ھېسابتىكى تەجرىبە قىممىتى ۋە بارلىق تەرجىمىھال سانلىق مەلۇماتىڭىزنى مەڭگۈلۈك ئۆچۈرىدۇ. بۇ مەشغۇلات يەنە سىز ئوينىغان ئويۇندىكى نومۇر، ئىلگىرىلەش (ساقلانغان ئويۇن) ۋە تەڭشەكنىمۇ ئۆچۈرۈشى مۇمكىن.</string>\n    <string name=\"games_delete_profile_dialog_message\">بۇ مەشغۇلاتتىن يېنىۋالغىلى بولمايدۇ.</string>\n    <string name=\"games_delete_profile_fail\">تەرجىمىھالىڭىزنى ئۆچۈرەلمەيدۇ. سەل تۇرۇپ قايتا سىناڭ.</string>\n    <string name=\"games_delete_game_data_confirm_dialog_title\">%1$s نىڭ سانلىق مەلۇماتىنى ئۆچۈر</string>\n    <string name=\"games_delete_game_data_confirm_dialog_message\">سىزنىڭ %1$s سانلىق مەلۇماتىنى مەڭگۈلۈك ئۆچۈرگەندىن كېيىن، Google Play ئويۇندىكى ئويۇن نومۇرى، ئىلگىرىلىشى (ساقلانغان ئويۇن) ۋە ئويۇن تەڭشىكىنى چىقىرىۋېتىدۇ.</string>\n    <string name=\"games_popup_signin_welcome\">خۇش كەلدىڭىز، %1$s</string>\n    <string name=\"family_management_title\">ئائىلە</string>\n    <string name=\"family_management_retry\">قايتا سىنا</string>\n    <string name=\"family_management_load_error\">مەزمۇننى يۈكلىيەلمىدى</string>\n    <string name=\"family_management_toolbar_back\">قايت</string>\n    <string name=\"family_management_toolbar_more\">تېخىمۇ كۆپ</string>\n    <string name=\"family_management_exit_family_group\">ئائىلە گۇرۇپپىسىدىن ئايرىل</string>\n    <string name=\"family_management_delete_family_group\">ئائىلە گۇرۇپپىسىنى ئۆچۈر</string>\n    <string name=\"family_management_leave_family_password_title\">ئائىلە گۇرۇپپىسىدىن ئايرىلىش ئۈچۈن ئىم جەزملىنىدۇ</string>\n    <string name=\"family_management_delete_family_password_title\">ئائىلە گۇرۇپپىسىنى ئۆچۈرۈش ئۈچۈن ئىم جەزملىنىدۇ</string>\n    <string name=\"family_management_remove_member_password_title\">%s نى چىقىرىۋېتىش ئۈچۈن ئىم جەزملىنىدۇ</string>\n    <string name=\"family_management_invite_family_member\">ئائىلە ئەزا تەكلىپى</string>\n    <string name=\"family_management_invite_slots_left\">%1$d تەكلىپ قالدى</string>\n    <string name=\"family_management_cancel_invite\">تەكلىپتىن ۋاز كەچ</string>\n    <string name=\"family_management_cancel_invite_success\">تەكلىپنى بىكار قىلىش مۇۋەپپەقىيەتلىك</string>\n    <string name=\"family_management_cancel_invite_error\">تەكلىپنى بىكار قىلىۋاتقاندا مەسىلە كۆرۈلدى، قايتا سىناڭ.</string>\n    <string name=\"family_management_remove_member\">ئەزانى چىقىرىۋەت</string>\n    <string name=\"family_management_member_removed_success\">ئائىلە گۇرۇپپىڭىزدىن %s چىقىرىۋېتىلگەن</string>\n    <string name=\"family_management_member_remove_failed\">%s چىقىرىۋاتقاندا مەسىلە كۆرۈلدى. قايتا سىناڭ.</string>\n    <string name=\"family_management_leave_family_error_message\">ئائىلە گۇرۇپپىسىدىن ئايرىلىۋاتقاندا مەسىلە كۆرۈلدى. قايتا سىناڭ.</string>\n    <string name=\"family_management_exist_group_success\">ئائىلە گۇرۇپپىڭىزدىن مۇۋەپپەقىيەتلىك ئايرىلدىڭىز…</string>\n    <string name=\"family_management_delete_group_success\">ئائىلە گۇرۇپپىسى ئۆچۈرۈلدى</string>\n    <string name=\"family_management_delete_group_failure\">ئائىلە گۇرۇپپىسىنى ئۆچۈرەلمىدى</string>\n    <string name=\"family_management_delete_group_cancel\">ۋاز كەچ</string>\n    <string name=\"family_management_delete_group_confirm\">جەزملە</string>\n    <string name=\"family_management_input_pwd\">ئىم كىرگۈزۈلىدۇ</string>\n    <string name=\"family_management_invite_sent_date_format\">تەكلىپنامە %s يوللاندى</string>\n    <string name=\"family_management_invite_send\">تەكلىپنامە يوللاندى</string>\n    <string name=\"family_management_pwd_error\">ئىم خاتا، قايتا كىرگۈزۈڭ</string>\n    <string name=\"pref_app_install_settings_title\">ئەپ ئورناتقۇچ تەڭشىكى</string>\n    <string name=\"pref_app_install_switch_title\">ئەپ ئورنىتىشقا يول قويىدۇ</string>\n    <string name=\"pref_app_install_other_apps_note\">سالاھىيەت دەلىللەش باشقا مەنبەدىن تەمىنلەنگەن ئەپنى ئورنىتىشقا يول قويىدۇ.</string>\n    <string name=\"pref_app_install_permission_instruction\">ئورناتقان ئەپنىڭ ئادەتتىكىدەك ئىشلىشى ئۈچۈن، microG ھەمكارلاشقۇچىنىڭ باشقا مەنبەدىن چۈشۈرگەن ئەپنى ئورنىتىشىغا يول قويۇڭ.</string>\n    <string name=\"prefcat_app_install_list_title\">ئەپ ئورناتقۇچ ئىشلىتىدىغان ئەپ</string>\n    <string name=\"service_name_google_location_sharing\">Google ئورۇن ھەمبەھىر</string>\n    <string name=\"location_sharing_description\">بۇ ئۈسكۈنىدىكى Google ئەپ ۋە مۇلازىمەتنىڭ شۇئان ئورۇن ئۇچۇرىنى ھەمبەھىرلەشنى باشقۇرىدۇ</string>\n    <string name=\"location_sharing_learn_more\">ئورۇن ھەمبەھىر ھەققىدىكى مول بىلىم</string>\n    <string name=\"location_sharing_switch_text\">ئورۇن ھەمبەھىرنى ئىشلىتىدۇ</string>\n    <string name=\"location_sharing_turn_off_notify_hint\">ئەگەر بۇ ئۈسكۈنىنىڭ ئورۇن ھەمبەھىرلەش ئىقتىدارى تاقالسا، سىز ئورۇن ئۇچۇرىنى ھەمبەھىرلىگەن كىشىگە ئۇقتۇرۇلمايدۇ.</string>\n    <string name=\"location_sharing_off_previous_hint\">سىز ئۇنى قايتا ئاچمىغۇچە ئاخىرقى قېتىم ھەمبەھىرلىگەن ئورۇن ئۇچۇرىنىلا ئىشلەتكىلى بولىدۇ.</string>\n    <string name=\"location_sharing_disabled\">بۇ ھېسابنىڭ ئورۇن ئۇچۇرىنى ھەمبەھىرلەش پائالىيىتى يوق</string>\n    <string name=\"location_sharing_turn_on_hint\">سىز Google ئەپ ياكى مۇلازىمەتتىن ئورۇن ئۇچۇرىنى ھەمبەھىرلىگەندىن باشلاپ، بۇ جايدىن ئورۇن ھەمبەھىرلەشنى باشقۇرغىلى بولىدۇ.\\n\\nئورۇن ئۇچۇرىنى ھەمبەھىرلەشتە، Google خەرىتە ياكى ئائىلە ئۇلانمىسىغا يۆتكىلىڭ.</string>\n    <string name=\"location_sharing_turn_off_title\">ئورۇن ھەمبەھىرنى تاقايدۇ</string>\n    <string name=\"location_sharing_turn_off_hint\">سىز باشقا بىر ئۈسكۈنىڭىزدىن ئوخشاش بىر Google ھېسابىڭىز ياكى غەيرى Google ئەپتىن ئورنىڭىزنى ھەمبەھىرلەۋاتقان بولۇشىڭىز مۇمكىن. ئورۇن ھەمبەھىرلەشنى ئىشلىتىش ئېھتىمالى بار ھەر قانداق جايدىن ئورۇن ھەمبەھىرلەش تەڭشىكىنى تەكشۈرۈڭ.\\n\\nسىز ئورۇن ئۇچۇرىڭىزنى ھەمبەھىرلىگەن كىشى ئاخىرقى ھەمبەھىرلىگەن ئورۇن ئۇچۇرىڭىزنى كۆرەلەيدۇ.</string>\n    <string name=\"location_sharing_turn_off_cancel\">ئوچۇق قالدۇر</string>\n    <string name=\"location_sharing_turn_off_confirm\">تاقا</string>\n    <string name=\"location_sharing_confirm_dialog_title\">ئورۇن ھەمبەھىرلەشنى قوزغىتىدۇ</string>\n    <string name=\"location_sharing_confirm_dialog_text\">سىز ئورۇن ئۇچۇرىڭىزنى ھەمبەھىرلىگەن كىشىنىڭ كۆرەلەيدىغىنى:\\n· ئات ۋە سۈرىتىڭىز\\n· ھەتتا سىز Google مۇلازىمىتىنى ئىشلەتمىگەن تەقدىردىمۇ ئۈسكۈنىڭىزنىڭ يېقىنقى ئورنى\\n· ئەگەر توكلىنىۋاتقان بولسا ئۈسكۈنىڭىز توكدانىنىڭ توكى \\n· ئەگەر ئۇلار ئورۇن ھەمبەھىرلەش ئۇقتۇرۇشىنى قوشقان بولسا سىز يېتىپ كەلگەن ۋە ئايرىلغان ۋاقىت</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-uk/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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  --><resources>\n    <string name=\"permission_service_all_label\">Всі сервіси Google</string>\n    <string name=\"permission_service_all_description\">Надає доступ застосунку до всіх сервісів Google через будь-який прив\\'язаний обліковий запис Google.</string>\n    <string name=\"permission_service_android_label\">Сервіси Android</string>\n    <string name=\"permission_service_android_description\">Надає доступ застосунку до сервісів Android через будь-який прив\\'язаний обліковий запис Google.</string>\n    <string name=\"permission_service_adsense_label\">AdSense</string>\n    <string name=\"permission_service_adsense_description\">Надає доступ застосунку до AdSense через будь-який прив\\'язаний обліковий запис Google.</string>\n    <string name=\"permission_service_adwords_label\">AdWords</string>\n    <string name=\"permission_service_adwords_description\">Надає доступ застосунку до AdWords через будь-який прив\\'язаний обліковий запис Google.</string>\n    <string name=\"permission_service_ah_label\">Google App Engine</string>\n    <string name=\"permission_service_ah_description\">Надає доступ застосунку до Google App Engine через будь-який прив\\'язаний обліковий запис Google.</string>\n    <string name=\"permission_service_blogger_label\">Blogger</string>\n    <string name=\"permission_service_blogger_description\">Надає доступ застосунку до Blogger через будь-який прив\\'язаний обліковий запис Google.</string>\n    <string name=\"permission_service_cl_label\">Google Календар</string>\n    <string name=\"permission_service_cl_description\">Надає доступ застосунку до Google Календар через будь-який прив\\'язаний обліковий запис Google.</string>\n    <string name=\"permission_service_cp_label\">Контакти</string>\n    <string name=\"permission_service_cp_description\">Надає доступ застосунку до Контактів через будь-який прив\\'язаний обліковий запис Google.</string>\n    <string name=\"permission_service_dodgeball_label\">Dodgeball</string>\n    <string name=\"permission_service_dodgeball_description\">Надає доступ застосунку до Dodgeball через будь-який прив\\'язаний обліковий запис Google.</string>\n    <string name=\"permission_service_finance_label\">Google Finance</string>\n    <string name=\"permission_service_finance_description\">Надає доступ застосунку до Google Фінанси через будь-який прив\\'язаний обліковий запис Google.</string>\n    <string name=\"permission_service_gbase_label\">Google Base</string>\n    <string name=\"permission_service_gbase_description\">Надає доступ застосунку до Google Base через будь-який прив\\'язаний обліковий запис Google.</string>\n    <string name=\"permission_service_grandcentral_label\">Google Voice</string>\n    <string name=\"permission_service_grandcentral_description\">Надає доступ застосунку до Google Voice через будь-який прив\\'язаний обліковий запис Google.</string>\n    <string name=\"permission_service_groups2_label\">Google Групи</string>\n    <string name=\"permission_service_groups2_description\">Надає доступ застосунку до Google Groups через будь-який прив\\'язаний обліковий запис Google.</string>\n    <string name=\"permission_service_health_label\">Google Здоров\\'я</string>\n    <string name=\"permission_service_health_description\">Надає доступ застосунку до Google Health через будь-який прив\\'язаний обліковий запис Google.</string>\n    <string name=\"permission_service_ig_label\">iGoogle</string>\n    <string name=\"permission_service_ig_description\">Надає доступ застосунку до iGoogle через будь-який прив\\'язаний обліковий запис Google.</string>\n    <string name=\"permission_service_jotspot_label\">JotSpot</string>\n    <string name=\"permission_service_jotspot_description\">Надає доступ застосунку до JotSpot через будь-який прив\\'язаний обліковий запис Google.</string>\n    <string name=\"permission_service_knol_label\">Knol</string>\n    <string name=\"permission_service_knol_description\">Надає доступ застосунку до Knol через будь-який прив\\'язаний обліковий запис Google.</string>\n    <string name=\"permission_service_lh2_label\">Picasa Web Albums</string>\n    <string name=\"permission_service_lh2_description\">Надає доступ застосунку до Picasa Web Albums через будь-який прив\\'язаний обліковий запис Google.</string>\n    <string name=\"permission_service_local_label\">Google Карти</string>\n    <string name=\"permission_service_local_description\">Надає доступ застосунку до Google Карти через будь-який прив\\'язаний обліковий запис Google.</string>\n    <string name=\"permission_service_mail_label\">Google Пошта</string>\n    <string name=\"permission_service_mail_description\">Надає доступ застосунку до Gmail через будь-який прив\\'язаний обліковий запис Google.</string>\n    <string name=\"permission_service_news_label\">Google Новини</string>\n    <string name=\"permission_service_news_description\">Надає доступ застосунку до Google Новини через будь-який прив\\'язаний обліковий запис Google.</string>\n    <string name=\"permission_service_notebook_label\">Google Нотатник</string>\n    <string name=\"permission_service_notebook_description\">Надає доступ застосунку до Google Нотатки через будь-який прив\\'язаний обліковий запис Google.</string>\n    <string name=\"permission_service_orkut_label\">Orkut</string>\n    <string name=\"permission_service_orkut_description\">Надає доступ застосунку до Orkut через будь-який прив\\'язаний обліковий запис Google.</string>\n    <string name=\"permission_service_print_label\">Google Книги</string>\n    <string name=\"permission_service_print_description\">Надає доступ застосунку до Google Книги через будь-який прив\\'язаний обліковий запис Google.</string>\n    <string name=\"permission_service_sierra_label\">Облікові записи Google Checkout</string>\n    <string name=\"permission_service_sierra_description\">Надає доступ застосунку до Google Checkout через будь-який прив\\'язаний обліковий запис Google.</string>\n    <string name=\"permission_service_sierraqa_label\">Облікові записи Google Checkout QA</string>\n    <string name=\"permission_service_sierraqa_description\">Надає доступ застосунку до Google Checkout QA через будь-який прив\\'язаний обліковий запис Google.</string>\n    <string name=\"permission_service_sierrasandbox_label\">Облікові записи Google Checkout Sandbox</string>\n    <string name=\"permission_service_sierrasandbox_description\">Надає доступ застосунку до Google Checkout Sandbox через будь-який прив\\'язаний обліковий запис Google.</string>\n    <string name=\"permission_service_sitemaps_label\">Інструменти Google Webmaster</string>\n    <string name=\"permission_service_sitemaps_description\">Надає доступ застосункк до Google Webmaster Tools через будь-який прив\\'язаний обліковий запис Google.</string>\n    <string name=\"permission_service_speech_label\">Голосовий пошук</string>\n    <string name=\"permission_service_speech_description\">Надає доступ застосунку до Voice Search через будь-який прив\\'язаний обліковий запис Google.</string>\n    <string name=\"permission_service_speechpersonalization_label\">Персоналізоване розпізнавання мови</string>\n    <string name=\"permission_service_speechpersonalization_description\">Надає доступ застосунку до Personalized Speech Recognition через будь-який прив\\'язаний обліковий запис Google.</string>\n    <string name=\"permission_service_talk_label\">Google Talk</string>\n    <string name=\"permission_service_talk_description\">Надає доступ застосунку до Google Talk через будь-який прив\\'язаний обліковий запис Google.</string>\n    <string name=\"permission_service_wifi_label\">Google Wi-Fi</string>\n    <string name=\"permission_service_wifi_description\">Надає доступ застосунку до Google Wi-Fi через будь-який прив\\'язаний обліковий запис Google.</string>\n    <string name=\"permission_service_wise_label\">Google Таблиці</string>\n    <string name=\"permission_service_wise_description\">Надає доступ застосунку до Google Таблиці через будь-який прив\\'язаний обліковий запис Google.</string>\n    <string name=\"permission_service_writely_label\">Google Документи</string>\n    <string name=\"permission_service_writely_description\">Надає доступ застосунку до Google Документи через будь-який прив\\'язаний обліковий запис Google.</string>\n    <string name=\"permission_service_youtube_label\">YouTube</string>\n    <string name=\"permission_service_youtube_description\">Надає доступ застосунку до YouTube через будь-який прив\\'язаний обліковий запис Google.</string>\n    <string name=\"permission_service_YouTubeUser_label\">Імена користувачів YouTube</string>\n    <string name=\"permission_service_YouTubeUser_description\">Надає доступ застосунку до імен користувача(ів) YouTube через будь-який прив\\'язаний обліковий запис Google.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_activity\">Переглянути історію активності Ваших застосунків Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.buyer\">Керування Вашим обліковим записом покупця Ad Exchange</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller.readonly\">Перегляд Ваших Ad Exchange даних</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller\">Перегляд та керування Вашими Ad Exchange даними</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsensehost\">Перегляд та керування Вашими даними хостингів AdSense та пов\\'язаними обліковими записами</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense.readonly\">Перегляд Ваших AdSense даних</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense\">Перегляд та керування Вашими AdSense  даними</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics.readonly\">Перегляд Ваших Google Analytics даних</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics\">Перегляд та керування Вашими Google Analytics даними</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_androidpublisher\">Доступ Android розробникам до Google Play</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appengine.admin\">Рушій застосунку сфери адміністрування.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.migration\">Доступ на запис та читання до Groups Migration API.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.settings\">Перегляд та керування налаштуваннями до Google Apps Group</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.licensing\">Доступ на запис та читання до License Manager API.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order\">Доступ для читання та запису адміністраторам та користувачам під час тестування в пісочниці API або ж доступ для читання та запису під час звернень до API-операцій напряму.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order.readonly\">Окрім загального читання/запису по протоколу OAuth, слід використовувати лише для читання протокол OAuth під час видобування даних клієнта.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps_reporting_audit.readonly\">Доступ лише на читання до Admin Audit API</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appstate\">Сфера використання сервісу App State.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery.readonly\">Перегляд Ваших даних в Google BigQuery</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery\">Перегляд та керування Вашими даними в Google BigQuery</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger\">Керування Вашим обліковим записом Blogger</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger.readonly\">Перегляд Вашого облікового запису Blogger</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_books\">Керування Вашими книгами</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar\">Керування Вашими календарями</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar.readonly\">Перегляд Ваших календарів</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_cloudprint\">Перегляд та керування Вашими даними google cloud print</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute.readonly\">Перегляд своїх ресурсів Google Compute Engine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute\">Перегляд та керування своїми ресурсами Google Compute Engine</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate.readonly\">Перегляд своїх Google Coordinate завдань</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate\">Перегляд та керування своїми Google Maps Coordinate завданнями</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.full_control\">Керування своїми даними та дозволами в Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_only\">Перегляд своїх даних в Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_write\">Керування своїми даними в Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_dfareporting\">Перегляд та керування DoubleClick звітами рекламодавців</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.appdata\">Надати доступ до теки Application Data</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.apps.readonly\">Переглянути своїх застосунків Google Диск</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.file\">Перегляд та керування файлами Google Диску, які ви відкрили чи створили в даному застосунку</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.install\">Спеціальні можливості, які дозволяють користувачу ухвалювати встановлення застосунків</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.metadata.readonly\">Перегляд метаданих для файлів та документів в Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.readonly\">Перегляд файлів та документів в Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.scripts\">Зміна поведінки своїх Google Apps Script</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive\">Перегляд та керування файлами та документами в Google Drive</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase.readonly\">Перегляд свого облікового запису Freebase</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase\">Зареєструватися в Freebase через свій обліковий запис</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables\">Керування своїми об\\'єднаними таблицями</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables.readonly\">Перегляд своїх об\\'єднаних таблиць</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_games\">Доступу до даних з Google Play ігри.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan\">Керування своїми GAN даними</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan.readonly\">Перегляд своїх GAN даних</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gcm_for_chrome\">CloudMessaging для chrome</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_glass.timeline\">Скляна шкала часу</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.compose\">Створювати, читати, оновлювати та видаляти чернетки. Відправляти повідомлення та чернетки.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.modify\">Всі операції читання/запису виконуються одразу ж, окрім видалення тем та повідомлень повз кошик.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.readonly\">Читання всіх ресурсів та метаданих, які не потребують операцій запису.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.best\">Керування своїм точним місцем перебуванням та його історією</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.city\">Керування своїм місцем перебуванням в межах міста та його історією</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.best\">Керування своїм точним місцем перебуванням</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.city\">Керування своїм місцем перебуванням в межах міста</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine\">Перегляд та керування Вашими Google Maps Engine даними</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine.readonly\">Перегляд Ваших Google Maps Engine даних</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mobilemaps.firstparty\">Перегляд та керування своїми Google картами для мобільного пристрою</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut\">Керування Вашою Orkut активністю</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut.readonly\">Перегляд Ваших Orkut даних</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.login\">Дізнатися Ваше ім\\'я, основну інформацію, та перелік людей, з якими ви пов\\'язані через Google+</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.me\">Дізнатися хто Ви є в Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_prediction\">Керування своїми даними в Google Prediction API</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_shoppingapi\">Перегляд даних продукту</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification\">Керування своїм переліком сайтів та доменів</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification.verify_only\">Керування верифікацією ваших нових сайтів в Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_structuredcontent\">Доступ на запис та читання до Shopping Content API.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue.consumer\">Виконання завдань із вашого планувальника завдань</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue\">Керування своїми задачами</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks\">Керування своїми задачами</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks.readonly\">Перегляд своїх задач</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tracks\">Google Maps Tracks API, Дана можливість дозволить читати та писати до даних Вашого проекту.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_urlshortener\">Керування своїми короткими посиланнями goo.gl</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.email\">Перегляд Вашої електронної адреси</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.profile\">Перегляд базової інформації про свій обліковий запис</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube\">Керування Вашим обліковим записом YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtubepartner\">Перегляд та керування Вашими активами та пов\\'язаним контентом на YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.readonly\">Перегляд Вашого облікового запису YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.upload\">Керування Вашими відеороликами YouTube</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics_monetary.readonly\">Перегляд валютних звітів аналітики YouTube для свого YouTube контенту</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics.readonly\">Перегляд звітів аналітики YouTube для свого YouTube контенту</string>\n    <string name=\"perm_activity_recognition_label\">Розпізнавання активності</string>\n    <string name=\"perm_activity_recognition_description\">Дозволяє застосунку отримувати періодичні оновлення рівня вашої активності від Google, наприклад, якщо ви ходите пішки, їдете за кермом, їдете на велосипеді або перебуваєте в нерухомому стані.</string>\n</resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-uk/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2017 microG Project Team\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  --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <plurals name=\"pref_unifiednlp_summary\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> сервер сконфігуровано</item>\n        <item quantity=\"few\"><xliff:g example=\"3\">%1$d</xliff:g> сервера сконфігуровано</item>\n        <item quantity=\"many\"><xliff:g example=\"3\">%1$d</xliff:g> серверів сконфігуровано</item>\n        <item quantity=\"other\"><xliff:g example=\"3\">%1$d</xliff:g> серверів сконфігуровано</item>\n    </plurals>\n    <plurals name=\"gcm_registered_apps_counter\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> застосунок зареєстровано</item>\n        <item quantity=\"few\"><xliff:g example=\"123\">%1$d</xliff:g> заcтосунки зареєстровано</item>\n        <item quantity=\"many\"><xliff:g example=\"123\">%1$d</xliff:g> застосунків зареєстровано</item>\n        <item quantity=\"other\"><xliff:g example=\"123\">%1$d</xliff:g> застосунків зареєстровано</item>\n    </plurals>\n    <plurals name=\"cond_perm_summary\">\n        <item quantity=\"one\">Не надано дозвіл, якій необхідний для нормальної роботи microG Services.</item>\n        <item quantity=\"few\">Не надано дозволи, які необхідні для нормальної роботи microG Services.</item>\n        <item quantity=\"many\">Не надано дозволів, які необхідні для нормальної роботи microG Services.</item>\n        <item quantity=\"other\">Не надано дозволів, які необхідні для нормальної роботи microG Services.</item>\n    </plurals>\n    <plurals name=\"cond_perm_action\">\n        <item quantity=\"one\">Запитати відсутній дозвіл</item>\n        <item quantity=\"few\">Запитати відсутні дозволи</item>\n        <item quantity=\"many\">Запитати відсутніх дозволів</item>\n        <item quantity=\"other\">Запитати відсутніх дозволів</item>\n    </plurals>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-uk/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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  --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"gms_app_name\">Служби microG</string>\n    <string name=\"gms_settings_name\">Налаштування microG</string>\n    <string name=\"just_a_sec\">Зачекайте трохи…</string>\n    <string name=\"google_account_label\">Google</string>\n    <string name=\"ask_permission_tos\">Продовжуючи, ви дозволяєте даному додатку та Google використовувати ваші дані згідно з їх відповідними умовами надання послуг та політикою конфіденційності.</string>\n    <string name=\"ask_scope_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> бажав би:</string>\n    <string name=\"ask_service_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> бажав би використовувати:</string>\n    <string name=\"account_manager_title\">Google Account Manager</string>\n    <string name=\"sorry\">Вибачте…</string>\n    <string name=\"auth_before_connect\">Застосунок на вашому пристрої намагається увійти до облікового запису Google.\\n\\nЯкщо ви очікували на це, натисніть кнопку <b>Увійти</b> для під\\'єднання до сторінки авторизації Google, інакше натисніть <b>Скасувати</b>, аби перейти назад до застосунку, що викликав це вікно.</string>\n    <string name=\"auth_sign_in\">Увійти</string>\n    <string name=\"auth_connecting\">Ваш пристрій встановлює зв\\'язок із серверами Google для авторизації.\n\\n\n\\nЦе може зайняти кілька секунд.</string>\n    <string name=\"no_network_error_desc\">Відсутнє з\\'єднання із мережею.\n\\n\n\\nЦе може бути як тимчасова проблема, так і проблемою із послугою передачі даних на Вашому пристрої Anddroid. Спробуйте ще раз, коли з\\'єднаєтесь із мобільної мережею, або до мережі Wi-Fi.</string>\n    <string name=\"auth_general_error_desc\">Не вдалося з\\'єднатися із сервісами Google.\n\\n\n\\nСпробуйте пізніше.</string>\n    <string name=\"auth_finalize\">Ваш пристрій з\\'єднається із Google, аби зберегти інформацію до вашого облікового запису.\n\\n\n\\nЦе може тривати кілька хвилин.</string>\n    <string name=\"allow\">Дозволено</string>\n    <string name=\"deny\">Відмовлено</string>\n    <string name=\"auth_notification_title\">Потрібна аутентифікація</string>\n    <string name=\"auth_notification_content\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> потребує авторизації для отримання доступу до Вашого облікового запису Google.</string>\n    <string name=\"perm_status_broadcast_label\">слухати внутрішній статус трансляцій</string>\n    <string name=\"perm_c2dm_receive_label\">слухати C2DM повідомлення</string>\n    <string name=\"perm_c2dm_send_label\">надсилати C2DM повідомлення до інших додатків</string>\n    <string name=\"perm_gtalk_svc_label\">обмінюватись повідомленнями та отримувати запити на синхронізацію від сервісів Google</string>\n    <string name=\"perm_extended_access_label\">Розширений доступ до сервісів Google</string>\n    <string name=\"service_name_checkin\">Реєстрація пристрою в Google</string>\n    <string name=\"service_name_mcs\">Хмарні повідомлення</string>\n    <string name=\"service_name_snet\">Google SafetyNet</string>\n    <string name=\"games_title\">Ігри Google Play</string>\n    <string name=\"games_info_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> бажає використовувати Play ігри</string>\n    <string name=\"games_info_content\">Для використання можливостей Play Games, необхідно встановити додаток Google Play Games. Додаток може працювати і без нього, але можливі проблеми під час роботи.</string>\n    <string name=\"pick_place_title\">Оберіть місце</string>\n    <string name=\"pick_place_desc\">Засіб вибору місця ще не доступний.</string>\n    <string name=\"place_picker_select_title\">Оберіть місце-розташування</string>\n    <string name=\"place_picker_nearby_places\">Найближчі місця</string>\n    <string name=\"place_picker_location_lat_lng\">(%1$.7f, %2$.7f)</string>\n    <string name=\"lacking_permission_toast\">microG Services: Відсутній дозвіл на <xliff:g example=\"have full network acccess\">%1$s</xliff:g></string>\n    <string name=\"network_type_mobile\">Мобільні мережі</string>\n    <string name=\"network_type_wifi\">Wi-Fi</string>\n    <string name=\"network_type_roaming\">Роумінг</string>\n    <string name=\"network_type_other\">Інші мережі</string>\n    <!-- Self check -->\n    <string name=\"self_check_cat_fake_sig\">Підтримка підміни підпису</string>\n    <string name=\"self_check_cat_gms_packages\">Встановлені додатки</string>\n    <string name=\"self_check_cat_system\">Система</string>\n    <string name=\"self_check_name_fake_sig_perm\">Підтримка системою підміни підпису:</string>\n    <string name=\"self_check_resolution_fake_sig_perm\">Поточне програмне забезпечення пристрою не підтримує підміну підпису. Ви можете використовувати Xposed або інші методи підтримки підміни підпису. Будь ласка, перевірте документацію, де вказано яка система підтримує підміну підпису і як використовувати microG, якщо немає такої підтримки.</string>\n    <string name=\"self_check_name_perm_granted\">Надання системою дозволу на підміну підпису:</string>\n    <string name=\"self_check_resolution_perm_granted\">Ваше програмне забезпечення пристрою підтримує підміну підпису, але потребує додаткової дії для її активації. Будь ласка, перевірте документацію, де вказано як це зробити.</string>\n    <string name=\"self_check_name_system_spoofs\">Підміна підпису системою:</string>\n    <string name=\"self_check_resolution_system_spoofs\">Будь ласка, перевірте документацію, де вказано як це зробити.</string>\n    <string name=\"self_check_pkg_gms\">Послуги microG</string>\n    <string name=\"self_check_pkg_vending\">microG Companion / Play Маркет</string>\n    <string name=\"self_check_pkg_gsf\">microG Services Framework</string>\n    <string name=\"self_check_name_app_installed\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> встановлено: </string>\n    <string name=\"self_check_resolution_app_installed\">Встановіть додаток <xliff:g example=\"F-Droid\">%1$s</xliff:g> або сумісний. Будь ласка, перевірте документацію, де вказано сумісні додатки.</string>\n    <string name=\"self_check_name_correct_sig\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> має вірний підпис: </string>\n    <string name=\"self_check_resolution_correct_sig\">Або встановлений додаток <xliff:g example=\"F-Droid\">%1$s</xliff:g> не сумісний чи має невірний підпис, або підміна підпису не активована для нього. Будь ласка, перевірте документацію, де вказано сумісні додатки чи програмне забезпечення пристрою.</string>\n    <string name=\"self_check_name_battery_optimizations\">Ігнорування оптимізації енергоспоживання:</string>\n    <string name=\"self_check_resolution_battery_optimizations\">Торкніться тут, аби вимкнути оптимізацію енергоспоживання. Якщо цього не зробити, додаток працюватиме не коректно в фоновому режимі.</string>\n    <!-- Settings strings -->\n    <string name=\"prefcat_about\">Про</string>\n    <string name=\"prefcat_components\">Компоненти</string>\n    <string name=\"prefcat_configuration\">Конфігурація</string>\n    <string name=\"prefcat_google_services\">Сервіси Google</string>\n    <string name=\"prefcat_location_service\">Сервіси позиціювання</string>\n    <string name=\"prefcat_services\">Сервіси</string>\n    <string name=\"prefcat_test\">Тест</string>\n    <string name=\"cond_gcm_bat_title\">Увімкнута оптимізація енергоспоживання</string>\n    <string name=\"cond_gcm_bat_summary\">Ви увімкнули Cloud Messaging але лиши оптимізацію енергоспоживання активним для microG Services. Аби отримувати push-сповіщення необхідно вимкнути оптимізацію енергоспоживання.</string>\n    <string name=\"cond_gcm_bat_action\">Ігнорувати оптимізацію</string>\n    <string name=\"cond_perm_title\">Відсутній дозвіл</string>\n    <string name=\"prefs_account\">Налаштування облікового запису</string>\n    <string name=\"prefs_account_privacy\">Персональна інформація та приватність</string>\n    <string name=\"prefs_account_security\">Авторизація та безпека</string>\n    <string name=\"pref_auth_trust_google_title\">Довіряти дозволам Google в додатках</string>\n    <string name=\"pref_auth_trust_google_summary\">Коли вимкнено, у користувача запитується дозвіл на авторизацію Google. Деякі застосунки не можуть використовувати обліковий запис Google, без даної можливості.</string>\n    <string name=\"pref_checkin_enable_summary\">Реєструє Ваш пристрій в сервісах Google та створює унікальний ідентифікатор. MicroG видаляє всі біти ідентифікації, окрім імені Вашого облікового запису Google.</string>\n    <string name=\"pref_more_settings\">Додатково</string>\n    <string name=\"pref_gcm_enable_mcs_summary\">Cloud Messaging надає push-сповіщення, які використовуються в багатьох сторонніх додатках. Аби використовувати їх, ви повинні увімкнути реєстрацію пристрою.</string>\n    <string name=\"pref_gcm_heartbeat_title\">Інтервал з\\'єднання Cloud Messaging</string>\n    <string name=\"pref_gcm_heartbeat_summary\">Інтервал в секундах для опитування серверів Google. Збільшення даного значення скоротить споживання батареї, але може призвести до затримок push-повідомлень.\\nЗастаріло, буде змінено в наступних випусках.</string>\n    <string name=\"pref_gcm_apps_title\">Додатки, які використовують Cloud Messaging</string>\n    <string name=\"pref_gcm_apps_summary\">Перелік додатків, які прив\\'язані до Cloud Messaging.</string>\n    <string name=\"pref_gcm_confirm_new_apps_title\">Підтверджувати нові додатки</string>\n    <string name=\"pref_gcm_confirm_new_apps_summary\">Запитувати перед реєстрацією нового додатку для отримання push-повідомлень</string>\n    <string name=\"pref_gcm_ping_interval\">Інтервал опитування: <xliff:g example=\"10 minutes\">%1$s</xliff:g></string>\n    <string name=\"pref_about_title\">Про microG Services</string>\n    <string name=\"pref_about_summary\">Версія та використані бібліотеки</string>\n    <string name=\"gcm_app_error_unregistering\">Помилка відв\\'язування</string>\n    <string name=\"gcm_app_not_installed_anymore\">Додаток вже не встановлено</string>\n    <string name=\"gcm_unregister_app\">Відв\\'язати</string>\n    <string name=\"gcm_not_registered\">Не прив\\'язано</string>\n    <string name=\"gcm_no_message_yet\">Повідомлення ще не отримано</string>\n    <string name=\"gcm_last_message_at\">Крайне повідомлення: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_registered\">Прив\\'язано</string>\n    <string name=\"gcm_registered_since\">Прив\\'язано від: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_unregister_confirm_title\">Відв\\'язати <xliff:g example=\"F-Droid\">%1$s</xliff:g>?</string>\n    <string name=\"gcm_unregister_confirm_message\">Деякі додатки автоматично не прив\\'язуються або/та не дозволяють зробити це вручну. Такі додатки можуть робити некоректно після відв\\'язування.\\nПродовжити?</string>\n    <string name=\"gcm_unregister_after_deny_message\">Ви заборонили додатку push-повідомлення, який вже був прив\\'язаний.\\nВи бажаєте відв\\'язати його зараз, аби більше не отримувати від нього push-повідомлень?</string>\n    <string name=\"gcm_messages_counter\">Повідомлень: <xliff:g example=\"123\">%1$d</xliff:g> (<xliff:g example=\"12345\">%2$d</xliff:g> байт)</string>\n    <string name=\"safetynet_intro\">Google SafetyNet — це система сертифікації пристрою, яка гарантує, що пристрій коректно захищено та сумісне із Android CTS. Деякі застосунки використовують SafetyNet для безпеки або в якості попередньої системи захисту від злому.\n\\n\n\\nmicroG GmsCore містить вільну реалізацію SafetyNet, але офіційний сервер вимагає, аби запити були підписані за допомогою закритої програмної системи DroidGuard.</string>\n    <string name=\"pref_safetynet_test_title\">Протестувати SafetyNet перевірку</string>\n    <string name=\"pref_droidguard_operation_mode\">Режим роботи</string>\n    <string name=\"pref_device_registration_import_custom_profile_title\">Імпортувати користувацький профіль</string>\n    <string name=\"pref_safetynet_recent_request_type\">Тип запиту</string>\n    <string name=\"pref_recaptcha_enterprise_test_title\">Тест ReCAPTCHA Enterprise</string>\n    <string name=\"checkin_last_registration\">Остання реєстрація: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"signin_subtext_policy_privacy\">політика приватності</string>\n    <string name=\"pref_safetynet_test_no_result\">Немає результату</string>\n    <string name=\"perm_gsf_read_gservices_label\">читати конфігурацію служби Google</string>\n    <string name=\"pref_device_registration_import_custom_profile_summary\">Імпортувати профіль пристрою з файла</string>\n    <string name=\"pref_safetynet_recent_copy_json\">Копіювати дані JSON JWS</string>\n    <string name=\"pref_test_summary_failed\">Не вдалося: %s</string>\n    <string name=\"pref_auth_visible_summary\">При включенні всі застосунки на цьому пристрої зможуть бачити адресу пошти ваших облікових записів Google без попередньої авторизації.</string>\n    <string name=\"pref_safetynet_recent_advice\">Порада</string>\n    <string name=\"push_notifications_summary_values_seconds\">%s с</string>\n    <string name=\"pref_safetynet_test_invalid_json\">Недійсний JSON</string>\n    <string name=\"menu_clear_recent_requests\">Очистити нещодавні запити</string>\n    <string name=\"signin_picker_title\">Оберіть обліковий запис</string>\n    <string name=\"pref_safetynet_recent_recaptcha_enterprise_summary\">ReCaptcha Enterprise: %s</string>\n    <string name=\"pref_safetynet_recent_cat_request\">Надіслати запит на дані</string>\n    <string name=\"pref_push_app_wake_for_delivery_summary\">Запускати застосунок у фоновому режимі, щоб отримувати вхідні push-повідомлення.</string>\n    <string name=\"pref_safetynet_recent_attestation_summary\">Підтвердження: %s</string>\n    <string name=\"prefcat_safetynet_apps_title\">Застосунки, що використовують SafetyNet</string>\n    <string name=\"safetynet_enable_switch\">Дозволити підтвердження пристрою</string>\n    <string name=\"pref_safetynet_test_integrity_failed\">Помилка цілісності</string>\n    <string name=\"push_notifications_summary_automatic\">ВВІМК / Автоматично: %s</string>\n    <string name=\"pref_device_registration_serial_title\">Серійний</string>\n    <string name=\"checkin_enable_switch\">Зареєструвати пристрій</string>\n    <string name=\"pref_safetynet_test_cts_failed\">Помилка CTS</string>\n    <string name=\"push_notifications_summary_manual\">ВВІМК / Вручну: %s</string>\n    <string name=\"profile_name_auto\">Автоматичний: %s</string>\n    <string name=\"push_notifications_summary_values_minutes\">%s хв</string>\n    <string name=\"perm_provision_label\">надання послуг microG</string>\n    <string name=\"gcm_network_state_connected\">З\\'єднано з <xliff:g example=\"2 hours ago\">%1$s</xliff:g></string>\n    <string name=\"pref_auth_include_android_id_summary\">Якщо вимкнено, запити на автентифікацію не будуть пов\\'язані з реєстрацією пристрою, що дозволяє несанкціонованим пристроям входити в обліковий запис, але може мати непередбачені наслідки.</string>\n    <string name=\"signin_picker_subtitle\">, щоб продовжити в <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"pref_safetynet_test_integrity_cts_passed\">Цілісність та CTS пройдено</string>\n    <string name=\"pref_safetynet_recent_uses\">Нещодавнє використання</string>\n    <string name=\"pref_droidguard_unsupported_summary\">Виконання DroidGuard на цьому пристрої не підтримується. Служби SafetyNet можуть поводитися неправильно.</string>\n    <string name=\"signin_confirm_title\">Дозволити вам увійти в <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"pref_safetynet_recent_nonce\">Одноразовий код (Hex)</string>\n    <string name=\"safetynet_last_run_at\">Останнє використання: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"pref_push_app_wake_for_delivery_title\">Запустити застосунок при push-повідомленнях</string>\n    <string name=\"perm_provision_description\">Дозволяє застосунку налаштовувати служби microG без взаємодії з користувачем</string>\n    <string name=\"pref_safetynet_recent_recaptcha_summary\">ReCaptcha: %s</string>\n    <string name=\"gcm_enable_switch\">Отримувати push-сповіщення</string>\n    <string name=\"pref_test_summary_passed\">Пройдено всі тести</string>\n    <string name=\"push_notifications_summary_off\">ВИМК</string>\n    <string name=\"pref_info_status\">Стан</string>\n    <string name=\"gcm_allow_app_popup\">Дозволити <xliff:g example=\"F-Droid\">%1$s</xliff:g> зареєструватися для push-сповіщень\\?</string>\n    <string name=\"pref_safetynet_recent_response_status\">Статус відповіді</string>\n    <string name=\"pref_auth_visible_title\">Дозволити застосункам знаходити облікові записи</string>\n    <string name=\"pref_device_registration_android_id\">Android ID</string>\n    <string name=\"gcm_network_state_disconnected\">Від\\'єднано</string>\n    <string name=\"signin_picker_add_account_label\">Додати інший обліковий запис</string>\n    <string name=\"pref_device_registration_select_profile_title\">Виберіть профіль</string>\n    <string name=\"signin_confirm_button_text\">Дозволити та поділитися</string>\n    <string name=\"pref_test_summary_warn\">Попередження: %s</string>\n    <string name=\"checkin_not_registered\">Не зареєстровано</string>\n    <string name=\"profile_name_real\">Реальний</string>\n    <string name=\"prefcat_push_apps_unregistered_title\">Незареєстровані застосунки</string>\n    <string name=\"pref_add_account_title\">Обліковий запис</string>\n    <string name=\"signin_subtext_policy\">Перш ніж використовувати цей застосунок, перегляньте його %1$s і %2$s.</string>\n    <string name=\"pref_safetynet_recent_copied\">Скопійовано до буфера обміну!</string>\n    <string name=\"prefcat_push_apps_title\">Застосунки, що використовують push-сповіщення</string>\n    <string name=\"profile_name_user\">Власний: %s</string>\n    <string name=\"pref_recaptcha_test_title\">Тест ReCAPTCHA</string>\n    <string name=\"signin_subtext_sharing\">Щоб продовжити, microG буде ділитися ім\\'ям, адресою пошти та зображенням профілю вашого облікового запису Google з <xliff:g example=\"F-Droid\">%1$s</xliff:g>.</string>\n    <string name=\"pref_auth_include_android_id_title\">Автентифікація за допомогою реєстрації пристрою</string>\n    <string name=\"pref_push_app_allow_register_title\">Дозволити реєстрацію</string>\n    <string name=\"profile_name_native\">Нативний</string>\n    <string name=\"pref_test_summary_running\">Запуск…</string>\n    <string name=\"pref_safetynet_recent_cat_basic\">Основні дані</string>\n    <string name=\"gms_settings_summary\">Налаштування служб microG.</string>\n    <string name=\"pref_add_account_summary\">Додати обліковий запис Google</string>\n    <string name=\"profile_name_system\">Системний: %s</string>\n    <string name=\"pref_safetynet_recent_cat_response\">Дані відповіді</string>\n    <string name=\"pref_push_app_allow_register_summary\">Дозволити застосунку реєструватися для push-сповіщень.</string>\n    <string name=\"pref_safetynet_recent_token\">Токен</string>\n    <string name=\"pref_safetynet_test_not_completed\">Ще не завершено</string>\n    <string name=\"pref_safetynet_recent_request_time\">Час запиту</string>\n    <string name=\"signin_subtext_policy_terms\">умови надання послуг</string>\n    <string name=\"prefcat_push_apps_registered_title\">Зареєстровані застосунки</string>\n    <string name=\"pref_device_registration_device_profile_category\">Профіль пристрою</string>\n    <string name=\"prefcat_push_networks_title\">Мережі, які слід використовувати для push-сповіщень</string>\n    <string name=\"pref_safetynet_recent_eval_type\">Тип оцінки</string>\n    <string name=\"pref_vending_summary_licensing_on\">Ліцензування ввімкнено</string>\n    <string name=\"pref_vending_licensing_enable_switch\">Відповідати на запити перевірки ліцензії</string>\n    <string name=\"pref_vending_license_enable_summary\">Деякі застосунки вимагають підтвердження того, що ви придбали їх у Google Play. На запит застосунку microG може завантажити підтвердження покупки з Google. Якщо цю функцію вимкнено або якщо обліковий запис Google не додано, запити на перевірку ліцензії ігноруються.</string>\n    <string name=\"pref_vending_summary_licensing_off\">Ліцензування вимкнено</string>\n    <string name=\"service_name_vending\">Служби Play Store</string>\n    <string name=\"perm_car_speed_label\">Швидкість машини</string>\n    <string name=\"perm_car_speed_description\">Отримання доступу до швидкості вашої машини</string>\n    <string name=\"perm_car_info_label\">Інформація про машину</string>\n    <string name=\"perm_car_info_description\">Отримання доступу до інформації про вашу машину</string>\n    <string name=\"pref_accounts_title\">Облікові записи Google</string>\n    <string name=\"prefcat_accounts_current_accounts_title\">Облікові записи</string>\n    <string name=\"pref_vending_licensing_category\">Ліцензування Google Play</string>\n    <string name=\"pref_vending_billing_enable_switch\">Обробляти платіжні запити</string>\n    <string name=\"perm_car_fuel_label\">Рівень палива в машині</string>\n    <string name=\"perm_car_fuel_description\">Доступ до інформації про рівень пального у вашій машині</string>\n    <string name=\"perm_car_mileage_label\">Пробіг машини</string>\n    <string name=\"perm_car_mileage_description\">Доступ до інформації про пробіг машини</string>\n    <string name=\"perm_car_vendor_extension_label\">Канал постачальника машин</string>\n    <string name=\"perm_car_vendor_extension_description\">Отримання доступу до каналу продавця вашої машини, щоб обмінятися інформацією про специфічну машину</string>\n    <string name=\"pref_accounts_summary\">Додати та керувати обліковими записами Google</string>\n    <string name=\"prefcat_accounts_settings_title\">Налаштування</string>\n    <string name=\"feedback_disabled\">Надіслати відгук наразі неможливо</string>\n    <string name=\"pref_vending_billing_category\">Платежі Google Play</string>\n    <string name=\"pref_vending_billing_enable_summary\">Після ввімкнення деякі застосунки можуть оформлювати покупки або підписки через платіжну систему Google Play.</string>\n    <string name=\"pref_vending_billing_note_experimental\">Ця функція експериментальна і може призвести до втрати грошей. Вас попередили.</string>\n    <string name=\"pref_vending_billing_note_licensing\">Для підтвердження покупок у деяких застосунках може знадобитися також увімкнути перевірку ліцензії.</string>\n    <string name=\"backup_disabled\">Резервне копіювання наразі неможливе</string>\n    <string name=\"pref_auth_strip_device_name_title\">Видалити назву пристрою для автентифікації</string>\n    <string name=\"pref_auth_strip_device_name_summary\">Якщо ввімкнено, запити на автентифікацію не міститимуть ім\\'я пристрою, що може дозволити несанкціонованим пристроям входити в обліковий запис, але може мати непередбачені наслідки.</string>\n    <string name=\"credentials_assisted_cancel\">Скасувати</string>\n    <string name=\"credentials_assisted_continue\">Продовжити</string>\n    <string name=\"credentials_assisted_confirmation_header\">Зареєструватися</string>\n    <string name=\"credentials_assisted_continue_as_user_button_label\">Продовжити як %1$s</string>\n    <string name=\"credentials_assisted_signin_consent_header\">Увійти як %1$s</string>\n    <string name=\"credentials_assisted_signin_consent\">Якщо ви продовжите, Google передасть ваше ім\\'я %1$s, адресу пошти та фото профілю. Ознайомтеся з політикою приватності та умовами використання %1$s.</string>\n    <string name=\"credentials_assisted_signin_description\">Ви можете керувати входом за допомогою Google у своїх облікових записах Google.</string>\n    <string name=\"credentials_assisted_choose_account_label\">Оберіть обліковий запис</string>\n    <string name=\"credentials_assisted_choose_account_subtitle\">щоб продовжити з %1$s</string>\n    <string name=\"credentials_assisted_sign_back_title\">Увійти до %1$s за допомогою Google</string>\n    <string name=\"credentials_assisted_signin_button_text_long\">Увійти за допомогою Google</string>\n    <string name=\"auth_package_override_request_title\">Дозволити <b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> привілейований доступ до <xliff:g example=\"account@example.com\">%2$s</xliff:g>\\?</string>\n    <string name=\"auth_package_override_request_message\"><b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> хоче отримати доступ до вашого облікового запису під видом <b><xliff:g example=\"F-Droid\">%2$s</xliff:g> by <xliff:g example=\"F-Droid Inc.\">%3$s</xliff:g></b>. Це може надати йому привілейований доступ до вашого облікового запису.</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_switch\">Автоматично додавати безплатні застосунки до бібліотеки</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_summary\">Безплатні застосунки можуть перевіряти, чи були вони завантажені з Google Play. Автоматично додавайте безплатні програми до бібліотеки свого облікового запису, щоб завжди проходити перевірку всіх доступних вам безоплатних застосунків.</string>\n    <string name=\"limited_services_app_name\">Обмежені сервіси microG</string>\n    <string name=\"limited_services_dialog_information_ack\">Я розумію</string>\n    <string name=\"limited_services_dialog_information\">Ви користуєтеся «Обмежені сервіси microG». На відміну від звичайних сервісів microG, цей варіант працює лише із застосунками, що використовують бібліотеки microG, а не з тими, що є у Google Play. Це означає, що більшість застосунків ігноруватимуть ці служби.</string>\n    <string name=\"auth_action_step_enable_checkin\">Увімкнути реєстрацію пристрою</string>\n    <string name=\"auth_action_step_enable_gcm\">Увімкнути хмарні повідомлення</string>\n    <string name=\"auth_action_step_allow_microg_gcm_description\">Відповідно до ваших налаштувань, microG потребує вашого дозволу, перш ніж зареєструватися у хмарних повідомленнях.</string>\n    <string name=\"auth_action_step_perform_content_description\">Натисніть, щоби виконати крок</string>\n    <string name=\"auth_action_step_completed_content_description\">Крок виконано</string>\n    <string name=\"auth_action_activity_finish\">Завершити</string>\n    <string name=\"auth_action_step_enable_lockscreen\">Налаштувати надійне блокування екрана</string>\n    <string name=\"auth_action_step_enable_lockscreen_description\">Ваш обліковий запис Google управляється на вашому робочому місці або у навчальному закладі. Ваш адміністратор вирішив, що пристрої потребують надійного блокування екрана, перш ніж отримати доступ до даних облікового запису.\\n\\nНалаштуйте пароль, PIN-код або графічний ключ для блокування екрана.</string>\n    <string name=\"auth_action_notification_channel_name\">Сповіщення про обліковий запис Google</string>\n    <string name=\"auth_action_notification_channel_description\">Сповіщає, коли один з ваших облікових записів Google потребує додаткового налаштування перед використанням або коли обліковий запис несумісний з microG.</string>\n    <string name=\"auth_action_notification_title\">Потрібні дії з обліковим записом</string>\n    <string name=\"auth_action_notification_content\">Ваш обліковий запис Google потребує додаткового налаштування.</string>\n    <string name=\"auth_action_activity_explanation\">Виконайте наведені нижче дії, щоби мати змогу використовувати свій обліковий запис Google %s на цьому пристрої.</string>\n    <string name=\"auth_action_activity_header\">Завершення налаштування облікового запису Google</string>\n    <string name=\"auth_action_step_enable_checkin_description\">Ваш пристрій повинен зареєструватися в Google принаймні один раз.\\n\\nВи можете вимкнути реєстрацію пристрою в Google після завершення налаштування облікового запису.</string>\n    <string name=\"auth_action_step_allow_microg_gcm\">Дозволити хмарні повідомлення для microG</string>\n    <string name=\"auth_action_step_enable_gcm_description\">Ви можете вимкнути хмарні повідомлення після завершення налаштування облікового запису.</string>\n    <string name=\"pref_vending_asset_delivery_summary\">Завантажити додаткові ресурси за запитом застосунків, які використовують Play Asset Delivery</string>\n    <string name=\"pref_vending_asset_delivery_category\">Google Play Asset Delivery</string>\n    <string name=\"pref_vending_asset_delivery_switch\">Увімкнути доставку ресурсів на вимогу</string>\n    <string name=\"pref_vending_asset_device_sync_summary\">Застосунки, що використовують Play Asset Delivery, завантажуватимуть додаткові ресурси на основі інформації про пристрій, який наразі використовується.</string>\n    <string name=\"pref_vending_asset_device_sync_switch\">Увімкнути синхронізацію інформації про пристрої</string>\n    <string name=\"games_achievement_list_title\">Досягнення</string>\n    <string name=\"games_achievements_empty_text\">Немає досягнень для цієї гри</string>\n    <string name=\"games_api_access_denied\">Жоден обліковий запис на цьому пристрої не має доступу до ігрових API</string>\n    <string name=\"games_achievement_locked_content_description\">заблоковано</string>\n    <string name=\"games_achievement_unlocked_content_description\">розблоковано</string>\n    <string name=\"games_achievement_extra_text\">%1$s ОД</string>\n    <string name=\"games_leaderboard_empty_text\">Немає таблиці лідерів для цієї гри</string>\n    <string name=\"games_leaderboard_score_empty_text\">Неймовірно! У цій грі немає публічних високих оцінок.</string>\n    <string name=\"games_leaderboard_list_title\">Рейтинги</string>\n    <string name=\"games_leaderboards_score_label\">Рахунок: %1$s</string>\n    <string name=\"games_snapshot_empty_text\">Наразі немає ігрових збережень</string>\n    <string name=\"games_snapshot_choose_btn_text\">вибрати</string>\n    <string name=\"games_snapshot_delete_btn_text\">видалити</string>\n    <string name=\"games_delete_snapshot_dialog_title\">Видалити збережену гру</string>\n    <string name=\"games_delete_snapshot_dialog_message\">Ви впевнені, що хочете видалити цю збережену гру?</string>\n    <string name=\"games_delete_snapshot_dialog_cancel\">Скасувати</string>\n    <string name=\"games_delete_snapshot_dialog_ok\">Гаразд</string>\n    <string name=\"games_delete_snapshot_error\">Не вдалося видалити, повторіть спробу пізніше</string>\n    <string name=\"service_name_work_profile\">Робочий профіль</string>\n    <string name=\"pref_vending_feature_delivery\">Доставка функцій Google Play</string>\n    <string name=\"pref_vending_split_install_switch\">Встановлення компонентів на вимогу</string>\n    <string name=\"barcode_scanner_brand\">Проскановано microG від імені %1$s</string>\n    <string name=\"camera_permission_dialog_title\">Потрібен дозвіл на використання камери</string>\n    <string name=\"pref_workprofile_disclaimer\">Ви несете відповідальність за те, щоби ваше використання microG відповідало корпоративній політиці. microG надається на основі принципу «робимо все можливе і не може гарантувати, що його поведінка буде такою, як очікується».</string>\n    <string name=\"pref_vending_licensing_split_install_summary\">Дозволити застосункам завантажувати та встановлювати додаткові компоненти</string>\n    <string name=\"pref_workprofile_create_account\">Дозволити налаштування робочого облікового запису</string>\n    <string name=\"pref_workprofile_intro\">Під час налаштування робочого профілю для вашого робочого місця або навчального закладу програма може спробувати з\\'єднатися з Google, щоб уможливити завантаження застосунків до цього профілю.</string>\n    <string name=\"camera_permission_dialog_button\">Гаразд</string>\n    <string name=\"camera_permission_dialog_message\">Службам microG потрібен доступ до камери вашого пристрою для сканування коду для %1$s.\\n\\nЩоб увімкнути цю функцію, надайте дозвіл на доступ камери до сервісів microG у налаштуваннях.</string>\n    <string name=\"credentials_assisted_choose_account_error_tips\">Аномалія облікового запису</string>\n    <string name=\"credentials_assisted_signin_add_account\">Додати обліковий запис</string>\n    <string name=\"auth_action_reauth_notification_title\">Необхідні дії щодо облікового запису</string>\n    <string name=\"pref_game_accounts_title\">Ігрові облікові записи Google</string>\n    <string name=\"pref_auto_create_player\">Дозволити реєстрацію облікового запису Play Ігри</string>\n    <string name=\"pref_auto_create_player_intro\">Під час гри вам потрібно використовувати обліковий запис Play Ігри для входу та запису функцій, пов\\'язаних з грою, таких як досягнення, таблиці лідерів, архіви тощо. Після вимкнення облікові записи Google, які не прив\\'язані до облікового запису Play Ігри, не будуть автоматично реєструватися, і гра не зможе входити та не можна буде грати.</string>\n    <string name=\"pref_allow_upload_game_played\">Дозволити вивантаження пройденої гри</string>\n    <string name=\"pref_allow_upload_game_played_summary\">Якщо ця функція вимкнена, гра не буде повідомляти про ігровий статус після входу в гру, а деякі ігри можуть не дозволити вхід.</string>\n    <string name=\"pref_change_default_game_player\">Змінити обліковий запис для ігор</string>\n    <string name=\"pref_change_default_game_player_summary\">Змінити типовий обліковий запис для ігор та змінити обліковий запис для кожної гри.</string>\n    <string name=\"pref_delete_game_account_data\">Видалити дані Play Ігри</string>\n    <string name=\"pref_delete_game_account_data_summary\">Видалити обліковий запис Play Ігри та всі дані, а також видалити дані окремих ігор.</string>\n    <string name=\"games_state_description_signed_out\">Вийти із системи</string>\n    <string name=\"games_state_description_delete\">Видалити</string>\n    <string name=\"games_change_button_text\">Змінити</string>\n    <string name=\"games_change_default_account_section_title\">Змінити типовий обліковий запис для ігор</string>\n    <string name=\"games_change_default_account_description\">Типовий обліковий запис: %1$s</string>\n    <string name=\"games_change_default_account_explanation\">Цей обліковий запис використовується для автоматичного входу в ігри, збереження прогресу та налаштувань. Зміна типового облікового запису або вихід із системи може призвести до скидання прогресу та налаштувань у іграх, в які ви грали.</string>\n    <string name=\"games_change_per_game_title\">Змінити обліковий запис гри</string>\n    <string name=\"games_change_per_game_description\">Зміна облікового запису для вибраної гри або вихід з нього може призвести до скидання вашого прогресу та налаштувань у грі.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_title\">Вибрати варіант для нового типового облікового запису</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_description\">Поточний типовий обліковий запис: %1$s</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_title\">Змінити типовий обліковий запис тільки для нових ігор</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_description\">Ви не втратите доступ до прогресу та налаштувань ігор, в які ви грали. Але ваш прогрес буде розділений між обліковими записами.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_title\">Змінити типовий обліковий запис для всіх ігор</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_description\">Ви можете втратити доступ до прогресу та налаштувань ігор, в які ви грали. Ми перезапустимо гру, щоб застосувати ваші зміни.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_title\">Вийти з усіх ігор</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_description\">Ви можете втратити доступ до прогресу та налаштувань ігор, в які ви грали. Ми перезапустимо гру, щоб застосувати ваші зміни.</string>\n    <string name=\"games_change_per_game_dialog_title\">Вибрати варіант для цієї гри</string>\n    <string name=\"games_change_per_game_dialog_description\">Зміна облікового запису або вихід із системи може призвести до скидання вашого прогресу та налаштувань у грі</string>\n    <string name=\"games_change_per_game_dialog_option_use_player\">Використовується %1$s</string>\n    <string name=\"games_change_per_game_dialog_option_use_player_snackbar_success_message\">Ви будете використовувати %1$s для входу в цю гру</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out\">Вийти із системи</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out_snackbar_success_message\">Ви вийшли з цієї гри</string>\n    <string name=\"games_change_sign_out_of_all_games_snackbar_success_message\">Ви вийшли з усіх ігор</string>\n    <string name=\"games_change_default_account_for_all_games_snackbar_success_message\">Ви будете використовувати %1$s для входу в усі ігри</string>\n    <string name=\"games_change_default_account_for_new_games_snackbar_success_message\">Ви будете використовувати %1$s для входу в нову гру</string>\n    <string name=\"games_account_display_content\">Поточний обліковий запис: %1$s</string>\n    <string name=\"games_delete_profile_header\">Видалити обліковий запис Play Ігри та всі дані</string>\n    <string name=\"games_delete_profile_explanation\">Назавжди видалити свій обліковий запис Google Play Ігри, ОД та всі дані профілю. Ця дія також може призвести до видалення ваших результатів, прогресу (збережених ігор) та налаштувань в іграх, в які ви грали.</string>\n    <string name=\"games_delete_profile_button\">Остаточно видалити</string>\n    <string name=\"games_delete_game_data_header\">Видалити дані конкретної гри</string>\n    <string name=\"games_delete_game_data_explanation\">Ви можете назавжди видалити окремі дані про ігри, в які ви грали за допомогою Google Play Ігри. Ця дія видаляє ваші результати, прогрес (збережені ігри) та налаштування для вибраної гри.</string>\n    <string name=\"games_delete_profile_dialog_title\">Упевнені, що хочете видалити цей обліковий запис?</string>\n    <string name=\"games_delete_profile_explanation_with_gamer_name\">Назавжди видалити свій обліковий запис Google Play Ігри гравця <b>%1$s</b> (<b>%2$s</b>), ОД, та всі дані профілю. Ця дія також може призвести до видалення ваших результатів, прогресу (збережених ігор) та налаштувань в іграх, в які ви грали.</string>\n    <string name=\"games_delete_profile_dialog_message\">Цю дію неможливо скасувати.</string>\n    <string name=\"games_delete_profile_fail\">Не вдалося видалити ваш профіль. Спробуйте пізніше.</string>\n    <string name=\"games_delete_game_data_confirm_dialog_title\">Видалити дані для %1$s</string>\n    <string name=\"games_delete_game_data_confirm_dialog_message\">Остаточне видалення ваших даних для %1$s призведе до видалення ваших результатів, прогресу (збережених ігор) та налаштувань ігор у Google Play Ігри.</string>\n    <string name=\"games_popup_signin_welcome\">Вітаємо, %1$s</string>\n    <string name=\"pref_auth_two_step_verification_title\">Отримувати запити на двоетапну перевірку</string>\n    <string name=\"pref_auth_two_step_verification_summary\">Якщо ця функція ввімкнена, пристрій може отримувати запити на двоетапну перевірку від Google (потрібна служба Cloud Messaging).</string>\n    <string name=\"service_name_google_location_sharing\">Надсилання геоданих Google</string>\n    <string name=\"location_sharing_description\">Керуйте надсиланням геоданих у реальному часі в застосунках і сервісах Google із цього пристрою</string>\n    <string name=\"location_sharing_learn_more\">Дізнатися більше про надсилання геоданих</string>\n    <string name=\"location_sharing_switch_text\">Використовувати надсилання геоданих</string>\n    <string name=\"location_sharing_turn_off_notify_hint\">Якщо ви вимкнете функцію «Надсилання геоданих» для цього пристрою, люди, з якими ви ділитеся даними, не отримають сповіщення.</string>\n    <string name=\"location_sharing_off_previous_hint\">Лише ваше останнє розташування буде доступне, доки ви не ввімкнете його знову.</string>\n    <string name=\"location_sharing_disabled\">Немає активних надсилань геоданих для цього облікового запису</string>\n    <string name=\"location_sharing_turn_on_hint\">Коли ви почнете ділитися геоданими із застосунку чи сервісу Google, керувати функцією «Надсилання геоданих» можна буде тут.\\n\\nЩоби почати ділитися геоданими, перейдіть у Google Карти або Family Link.</string>\n    <string name=\"location_sharing_turn_off_title\">Вимкнути надсилання геоданих</string>\n    <string name=\"location_sharing_turn_off_hint\">Ви все ще можете ділитися своїм розташуванням з інших пристроїв, на яких виконано вхід в той самий обліковий запис Google, або із застосунків не від Google. Переконайтеся, що ви перевірили налаштування надсилання геоданих скрізь, де це може застосовуватися.\\n\\nЛюди, з якими ви ділитеся, продовжуватимуть бачити ваше останнє надіслане розташування.</string>\n    <string name=\"location_sharing_turn_off_cancel\">Залишити ввімкненим</string>\n    <string name=\"location_sharing_turn_off_confirm\">Вимкнути</string>\n    <string name=\"location_sharing_confirm_dialog_title\">Увімкнути надсилання геоданих</string>\n    <string name=\"location_sharing_confirm_dialog_text\">Люди, яким ви надаєте доступ до свого розташування, завжди бачитимуть:\\n· Ваше ім’я та фото\\n· Останнє розташування вашого пристрою, навіть якщо ви не користуєтеся сервісом Google\\n· Заряд акумулятора вашого пристрою та чи заряджається він\\n· Час вашого прибуття та відправлення, якщо вони додадуть сповіщення про надсилання геоданих</string>\n    <string name=\"family_management_title\">Родина</string>\n    <string name=\"family_management_retry\">Повторити</string>\n    <string name=\"family_management_load_error\">Не вдалося завантажити вміст</string>\n    <string name=\"family_management_toolbar_back\">Назад</string>\n    <string name=\"family_management_toolbar_more\">Більше</string>\n    <string name=\"family_management_exit_family_group\">Покинути родинну групу</string>\n    <string name=\"family_management_delete_family_group\">Видалити родинну групу</string>\n    <string name=\"family_management_leave_family_password_title\">Підтвердьте пароль, аби покинути родинну групу</string>\n    <string name=\"family_management_delete_family_password_title\">Підтвердьте пароль, аби видалити родинну групу</string>\n    <string name=\"family_management_remove_member_password_title\">Підтвердьие пароль, аби вигнати %s</string>\n    <string name=\"family_management_invite_family_member\">Запросити членів родини</string>\n    <string name=\"family_management_invite_slots_left\">Залишилося %1$d запрошень</string>\n    <string name=\"family_management_cancel_invite\">Скасувати запрошення</string>\n    <string name=\"family_management_cancel_invite_success\">Запрошення успішно скасовано</string>\n    <string name=\"family_management_cancel_invite_error\">Не вдалося скасувати запрошення. Спробуйте знову.</string>\n    <string name=\"family_management_remove_member\">Вигнати члена</string>\n    <string name=\"family_management_member_removed_success\">%s було вигнано з родинної групи</string>\n    <string name=\"family_management_member_remove_failed\">Не вдалося вигнати %s. Спробуйте знову.</string>\n    <string name=\"family_management_leave_family_error_message\">Не вдалося покинути родинну групу. Спробуйте знову.</string>\n    <string name=\"family_management_exist_group_success\">Ви покинули родинну групу…</string>\n    <string name=\"family_management_delete_group_success\">Родинну групу видалено</string>\n    <string name=\"family_management_delete_group_failure\">Не вдалося видалити родинну групу</string>\n    <string name=\"family_management_delete_group_cancel\">Скасувати</string>\n    <string name=\"family_management_delete_group_confirm\">Гаразд</string>\n    <string name=\"family_management_input_pwd\">Введіть свій пароль</string>\n    <string name=\"family_management_invite_sent_date_format\">Запрошення надіслано %s</string>\n    <string name=\"family_management_invite_send\">Запрошення надіслано</string>\n    <string name=\"family_management_pwd_error\">Невірний пароль, введіть ще раз</string>\n    <string name=\"pref_app_install_settings_title\">Налаштування встановлювача застосунків</string>\n    <string name=\"pref_app_install_switch_title\">Дозволити встановлення застосунків</string>\n    <string name=\"pref_app_install_other_apps_note\">Авторизація дозволяє встановлювати застосунки з інших джерел.</string>\n    <string name=\"pref_app_install_permission_instruction\">Щоби гарантувати коректну роботу встановлених застосунків, дозвольте microG Companion встановлювати їх, завантажуючи з інших джерел.</string>\n    <string name=\"prefcat_app_install_list_title\">Застосунки, що використовують встановлювач застосунків</string>\n    <string name=\"service_name_device_attestation\">Підтвердження пристрою</string>\n    <string name=\"prefcat_device_attestation_apps_title\">Застосунки, які використовують підтвердження пристрою</string>\n    <string name=\"pref_device_attestation_app_allow_requests_title\">Дозволити запити</string>\n    <string name=\"pref_device_attestation_app_allow_requests_summary\">Дозволити застосунку запитувати підтвердження пристрою</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-v23/themes.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <style name=\"Theme.Base.Light\">\n        <item name=\"android:statusBarColor\">@android:color/transparent</item>\n        <item name=\"android:windowLightStatusBar\">true</item>\n    </style>\n    <style name=\"Theme.Base.Dark\">\n        <item name=\"android:statusBarColor\">@android:color/transparent</item>\n        <item name=\"android:windowLightStatusBar\">false</item>\n    </style>\n\n    <!-- Preference theme -->\n    <style name=\"Theme.Base.PreferenceThemeOverlay\" parent=\"@style/PreferenceThemeOverlay\">\n        <item name=\"switchPreferenceCompatStyle\">@style/Theme.Base.Preference.SwitchPreferenceCompat</item>\n        <item name=\"switchBarPreferenceStyle\">@style/Theme.Base.Preference.SwitchBarPreference</item>\n    </style>\n\n    <style name=\"Theme.Base.Preference.SwitchBarPreference\" parent=\"@style/Preference.SwitchBar\">\n        <item name=\"layout\">@layout/preference_material_switch_bar</item>\n        <item name=\"switchBarFrameId\">@id/frame</item>\n        <item name=\"switchBarFrameBackgroundOn\">@drawable/material_switch_bar_background</item>\n        <item name=\"switchBarFrameBackgroundOff\">@drawable/material_switch_bar_background</item>\n        <item name=\"switchBarFrameBackgroundDisabled\">@drawable/material_switch_bar_background_disabled</item>\n    </style>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-v26/ic_app_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"ic_app_background\">#00897B</color>\n</resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-v27/themes.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <style name=\"Theme.Base.Light\">\n        <item name=\"android:statusBarColor\">@android:color/transparent</item>\n        <item name=\"android:windowLightStatusBar\">true</item>\n        <item name=\"android:navigationBarColor\">@android:color/transparent</item>\n        <item name=\"android:windowLightNavigationBar\">true</item>\n    </style>\n    <style name=\"Theme.Base.Dark\">\n        <item name=\"android:statusBarColor\">@android:color/transparent</item>\n        <item name=\"android:windowLightStatusBar\">false</item>\n        <item name=\"android:navigationBarColor\">@android:color/transparent</item>\n        <item name=\"android:windowLightNavigationBar\">false</item>\n    </style>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-v31/themes.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <style name=\"Theme.App\" parent=\"Theme.Base.DayNight.NoActionBar\" />\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-vi/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"permission_service_cp_label\">Danh bạ</string>\n    <string name=\"permission_service_cp_description\">Cho phép ứng dụng truy cập Danh bạ thông qua bất kỳ tài khoản Google nào được liên kết.</string>\n    <string name=\"permission_service_android_label\">Dịch vụ Android</string>\n    <string name=\"permission_service_android_description\">Cho phép ứng dụng truy cập các dịch vụ của Android thông qua bất kỳ tài khoản Google nào được liên kết.</string>\n    <string name=\"permission_service_adwords_label\">Google Ads</string>\n    <string name=\"permission_service_adwords_description\">Cho phép ứng dụng truy cập Google Ads thông qua bất kỳ tài khoản Google nào được liên kết.</string>\n    <string name=\"permission_service_ah_label\">Google App Engine</string>\n    <string name=\"permission_service_blogger_label\">Blogger</string>\n    <string name=\"permission_service_blogger_description\">Cho phép ứng dụng truy cập Blogger thông qua bất kỳ tài khoản Google nào được liên kết.</string>\n    <string name=\"permission_service_cl_label\">Lịch Google</string>\n    <string name=\"permission_service_cl_description\">Cho phép ứng dụng truy cập Lịch Google thông qua bất kỳ tài khoản Google nào được liên kết.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.readonly\">Xem tài khoản YouTube của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics.readonly\">Xem báo cáo phân tích YouTube cho nội dung YouTube của bạn</string>\n    <string name=\"permission_service_all_label\">Tất cả dịch vụ Google</string>\n    <string name=\"permission_service_all_description\">Cho phép ứng dụng truy cập tất cả dịch vụ của Google thông qua bất kỳ tài khoản Google nào được liên kết.</string>\n    <string name=\"permission_service_adsense_label\">AdSense</string>\n    <string name=\"permission_service_adsense_description\">Cho phép ứng dụng truy cập AdSense thông qua bất kỳ tài khoản Google nào được liên kết.</string>\n    <string name=\"permission_service_ah_description\">Cho phép ứng dụng truy cập Google App Engine thông qua bất kỳ tài khoản Google nào được liên kết.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics_monetary.readonly\">Xem báo cáo doanh thu của YouTube Analytics cho nội dung YouTube của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.upload\">Quản lý video YouTube của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtubepartner\">Quản lý tài sản cùng nội dung liên quan của bạn trên YouTube</string>\n    <string name=\"permission_service_dodgeball_label\">Dodgeball</string>\n    <string name=\"permission_service_finance_label\">Google Tài chính</string>\n    <string name=\"permission_service_dodgeball_description\">Cho phép ứng dụng truy cập Dodgeball thông qua bất kỳ tài khoản Google nào được liên kết.</string>\n    <string name=\"permission_service_finance_description\">Cho phép ứng dụng truy cập Google tài chính thông qua bất kỳ tài khoản Google nào được liên kết.</string>\n    <string name=\"permission_service_gbase_label\">Google Base</string>\n    <string name=\"permission_service_gbase_description\">Cho phép ứng dụng truy cập Google Base thông qua bất kỳ tài khoản Google nào được liên kết.</string>\n    <string name=\"permission_service_grandcentral_description\">Cho phép ứng dụng truy cập Google Voice thông qua bất kỳ tài khoản Google nào được liên kết.</string>\n    <string name=\"permission_service_groups2_label\">Google Groups</string>\n    <string name=\"permission_service_grandcentral_label\">Google Voice</string>\n    <string name=\"permission_service_groups2_description\">Cho phép ứng dụng truy cập Google Groups thông qua bất kỳ tài khoản Google nào được liên kết.</string>\n    <string name=\"permission_service_health_label\">Google Health</string>\n    <string name=\"permission_service_health_description\">Cho phép ứng dụng truy cập Google Health thông qua bất kỳ tài khoản Google nào được liên kết.</string>\n    <string name=\"permission_service_ig_label\">iGoogle</string>\n    <string name=\"permission_service_ig_description\">Cho phép ứng dụng truy cập iGoogle thông qua bất kỳ tài khoản Google nào được liên kết.</string>\n    <string name=\"permission_service_jotspot_label\">JotSpot</string>\n    <string name=\"permission_service_jotspot_description\">Cho phép ứng dụng truy cập JotSpot thông qua bất kỳ tài khoản Google nào được liên kết.</string>\n    <string name=\"permission_service_knol_description\">Cho phép ứng dụng truy cập Knol thông qua bất kỳ tài khoản Google nào được liên kết.</string>\n    <string name=\"permission_service_lh2_label\">Google Photos</string>\n    <string name=\"permission_service_knol_label\">Knol</string>\n    <string name=\"permission_service_lh2_description\">Cho phép ứng dụng truy cập Google Photos thông qua bất kỳ tài khoản Google nào được liên kết.</string>\n    <string name=\"permission_service_local_label\">Google Maps</string>\n    <string name=\"permission_service_local_description\">Cho phép ứng dụng truy cập Google Maps thông qua bất kỳ tài khoản Google nào được liên kết.</string>\n    <string name=\"permission_service_mail_label\">Gmail</string>\n    <string name=\"permission_service_mail_description\">Cho phép ứng dụng truy cập Gmail thông qua bất kỳ tài khoản Google nào được liên kết.</string>\n    <string name=\"permission_service_news_description\">Cho phép ứng dụng truy cập Google Tin tức thông qua bất kỳ tài khoản Google nào được liên kết.</string>\n    <string name=\"permission_service_notebook_description\">Cho phép ứng dụng truy cập Google Keep thông qua bất kỳ tài khoản Google nào được liên kết.</string>\n    <string name=\"permission_service_orkut_description\">Cho phép ứng dụng truy cập Orkut thông qua bất kỳ tài khoản Google nào được liên kết.</string>\n    <string name=\"permission_service_notebook_label\">Google Keep</string>\n    <string name=\"permission_service_orkut_label\">Orkut</string>\n    <string name=\"permission_service_news_label\">Google Tin tức</string>\n    <string name=\"permission_service_print_label\">Google Sách</string>\n    <string name=\"permission_service_sierraqa_description\">Cho phép ứng dụng truy cập tài khoản QA Google Pay thông qua bất kỳ tài khoản Google nào được liên kết.</string>\n    <string name=\"permission_service_sitemaps_label\">Google Search Console</string>\n    <string name=\"permission_service_print_description\">Cho phép ứng dụng truy cập Google Sách thông qua bất kỳ tài khoản Google nào được liên kết.</string>\n    <string name=\"permission_service_sierra_label\">Tài khoản Google Pay</string>\n    <string name=\"permission_service_sierraqa_label\">Tài khoản QA Google Pay</string>\n    <string name=\"permission_service_sierrasandbox_label\">Tài khoản Sandbox Google Pay</string>\n    <string name=\"permission_service_sierrasandbox_description\">Cho phép ứng dụng truy cập tài khoản Sandbox Google Pay thông qua bất kỳ tài khoản Google nào được liên kết.</string>\n    <string name=\"permission_service_sitemaps_description\">Cho phép ứng dụng truy cập Google Search Console thông qua bất kỳ tài khoản Google nào được liên kết.</string>\n    <string name=\"permission_service_speech_label\">Tìm kiếm bằng giọng nói</string>\n    <string name=\"permission_service_speech_description\">Cho phép ứng dụng truy cập Tìm kiếm bằng giọng nói thông qua bất kỳ tài khoản Google nào được liên kết.</string>\n    <string name=\"permission_service_speechpersonalization_label\">Speech Recognition &amp; Synthesis</string>\n    <string name=\"permission_service_speechpersonalization_description\">Cho phép ứng dụng truy cập Speech Recognition &amp; Synthesis thông qua bất kỳ tài khoản Google nào được liên kết.</string>\n    <string name=\"permission_service_talk_label\">Google Chat</string>\n    <string name=\"permission_service_talk_description\">Cho phép ứng dụng truy cập Google Chat thông qua bất kỳ tài khoản Google nào được liên kết.</string>\n    <string name=\"permission_service_wifi_description\">Cho phép ứng dụng truy cập Google Wi-Fi thông qua bất kỳ tài khoản Google nào được liên kết.</string>\n    <string name=\"permission_service_wise_description\">Cho phép ứng dụng truy cập Google Trang tính thông qua bất kỳ tài khoản Google nào được liên kết.</string>\n    <string name=\"permission_service_writely_description\">Cho phép ứng dụng truy cập Google Tài liệu thông qua bất kỳ tài khoản Google nào được liên kết.</string>\n    <string name=\"permission_service_youtube_label\">YouTube</string>\n    <string name=\"permission_service_youtube_description\">Cho phép ứng dụng truy cập YouTube thông qua bất kỳ tài khoản Google nào được liên kết.</string>\n    <string name=\"permission_service_wifi_label\">Google Wi-Fi</string>\n    <string name=\"permission_service_YouTubeUser_label\">Tên người dùng YouTube</string>\n    <string name=\"permission_service_YouTubeUser_description\">Cho phép ứng dụng truy cập tên người dùng YouTube thông qua bất kỳ tài khoản Google nào được liên kết.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_activity\">Xem lại những hoạt động bạn đã thực hiện trên các ứng dụng Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.buyer\">Quản lý cấu hình tài khoản người mua Ad Exchange của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller.readonly\">Xem dữ liệu Ad Exchange của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsensehost\">Quản lý dữ liệu máy chủ AdSense của bạn và các tài khoản liên kết</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller\">Quản lý dữ liệu Ad Exchange của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense.readonly\">Xem dữ liệu AdSense của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense\">Quản lý dữ liệu AdSense của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics.readonly\">Xem dữ liệu Google Analytics của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics\">Quản lý dữ liệu Google Analytics của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_androidpublisher\">Truy cập vào Google Play Android Developer</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appengine.admin\">Quyền truy cập dành cho quản trị viên App Engine.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.settings\">Quản lý cài đặt Google Apps Group</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order\">Dành cho quản trị viên và người dùng đại lý: quyền đọc/ghi khi kiểm thử trong môi trường sandbox của API, hoặc quyền đọc/ghi khi gọi trực tiếp một thao tác API.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.licensing\">Quyền đọc/ghi đối với License Manager API.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.migration\">Quyền đọc và ghi đối với Groups Migration API.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order.readonly\">Bên cạnh OAuth đọc và ghi đầy đủ, hãy dùng OAuth chỉ đọc khi bạn chỉ cần lấy dữ liệu của khách hàng.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps_reporting_audit.readonly\">Truy cập vào API Admin Audit API ReadOnly</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appstate\">Phạm vi sử dụng dịch vụ App State.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery.readonly\">Xem dữ liệu của bạn trong Google BigQuery</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery\">Quản lý dữ liệu của bạn trong Google BigQuery</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger\">Quản lý tài khoản Blogger của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger.readonly\">Xem tài khoản Blogger của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_books\">Quản lý sách của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar\">Quản lý lịch của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar.readonly\">Xem lịch của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_cloudprint\">Quản lý dữ liệu Google Cloud Print của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute.readonly\">Xem tài nguyên Google Compute Engine của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute\">Quản lý tài nguyên Google Compute Engine của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate.readonly\">Xem nhiệm vụ Google Coordinate của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate\">Quản lý nhiệm vụ Google Coordinate của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.full_control\">Quản lý dữ liệu và quyền của bạn trong Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_only\">Xem dữ liệu của bạn trong Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_write\">Quản lý dữ liệu của bạn trong Google Cloud Storage</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_dfareporting\">Quản lý báo cáo DoubleClick for Advertisers</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.appdata\">Cho phép truy cập vào thư mục Dữ liệu ứng dụng</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.apps.readonly\">Xem ứng dụng Google Drive của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.file\">Quản lý các tệp Google Drive mà bạn đã mở hoặc tạo bằng ứng dụng này</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.install\">Quyền đặc biệt cho phép người dùng xác nhận và đồng ý cài đặt ứng dụng</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.metadata.readonly\">Xem metadata cho các tệp và tài liệu trong Google Drive của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.readonly\">Xem tệp và tài liệu trong Google Drive của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.scripts\">Chỉnh sửa cách thức hoạt động Google Apps Script của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive\">Quản lý tệp và tài liệu trong Google Drive của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase.readonly\">xem tài khoản Freebase của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables\">Quản lý Fusion Tables của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase\">Sử dụng tài khoản của bạn để truy cập Freebase</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables.readonly\">Xem Fusion Tables của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_games\">Quyền cho phép ứng dụng truy cập dữ liệu của bạn trên Google Play Games.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan\">Quản lý dữ liệu GAN của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan.readonly\">Xem dữ liệu GAN của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_glass.timeline\">Quyền truy cập dòng thời gian trên Google Glass</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gcm_for_chrome\">CloudMessaging cho Chrome</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.compose\">Tạo, đọc, cập nhật và xóa bản nháp. Gửi tin nhắn và bản nháp.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.modify\">Cho phép thực hiện mọi thao tác đọc và ghi, trừ việc xóa vĩnh viễn ngay lập tức các cuộc hội thoại và tin nhắn mà không qua Thùng rác.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.readonly\">Đọc tất cả tài nguyên và metadata của chúng—không thực hiện thao tác ghi.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.best\">Quản lý vị trí có sẵn chính xác nhất và lịch sử vị trí của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.city\">Quản lý vị trí thành phố và lịch sử vị trí của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.best\">Quản lý vị trí chính xác nhất của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.city\">Quản lý vị trí thành phố của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine\">Quản lý dữ liệu Google Maps Engine của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine.readonly\">Xem dữ liệu Google Maps Engine của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mobilemaps.firstparty\">Quản lý trải nghiệm Google Maps dành cho thiết bị di động của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut\">Quản lý hoạt động Orkut của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut.readonly\">Xem dữ liệu Orkut của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.login\">Biết tên của bạn, thông tin cơ bản và danh sách những người bạn kết nối trên Google+</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.me\">Biết bạn là ai trên Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_prediction\">Quản lý dữ liệu của bạn trong Google Prediction API</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_shoppingapi\">Xem dữ liệu sản phẩm của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification\">Quản lý danh sách trang web và tên miền bạn đang sở hữu</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification.verify_only\">Quản lý xác minh trang web mới của bạn với Google</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_structuredcontent\">Cấp quyền đọc/ghi vào Shopping Content API.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue.consumer\">Xử lý các Tác vụ từ Hàng chờ của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue\">Quản lý các Tác vụ của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks\">Quản lý các tác vụ của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks.readonly\">Xem các tác vụ của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tracks\">Google Maps Tracks API – Cho phép ứng dụng đọc và chỉnh sửa dữ liệu trong dự án của bạn.</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_urlshortener\">Quản lý các URL rút gọn goo.gl của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.email\">Xem địa chỉ email của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.profile\">Xem thông tin cơ bản về tài khoản của bạn</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube\">Quản lý tài khoản Youtube của bạn</string>\n    <string name=\"permission_service_wise_label\">Google Trang tính</string>\n    <string name=\"permission_service_writely_label\">Google Tài liệu</string>\n    <string name=\"permission_service_sierra_description\">Cho phép ứng dụng truy cập tài khoản Google Pay thông qua bất kỳ tài khoản Google nào được liên kết.</string>\n    <string name=\"perm_activity_recognition_label\">Nhận dạng hoạt động</string>\n    <string name=\"perm_activity_recognition_description\">Cho phép ứng dụng nhận các cập nhật định kỳ về mức độ hoạt động của bạn từ Google, ví dụ như khi bạn đang đi bộ, lái xe, đạp xe hoặc đứng yên.</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-vi/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <plurals name=\"pref_unifiednlp_summary\">\n        <item quantity=\"other\">Đã cấu hình <xliff:g example=\"3\">%1$d</xliff:g> backend</item>\n    </plurals>\n    <plurals name=\"gcm_registered_apps_counter\">\n        <item quantity=\"other\"><xliff:g example=\"123\">%1$d</xliff:g> ứng dụng đăng ký</item>\n    </plurals>\n    <plurals name=\"cond_perm_summary\">\n        <item quantity=\"other\">Dịch vụ microG chưa được cấp đủ quyền cần thiết để hoạt động đúng cách.</item>\n    </plurals>\n    <plurals name=\"cond_perm_action\">\n        <item quantity=\"other\">Yêu cầu cấp các quyền còn thiếu</item>\n    </plurals>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-vi/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=\"gms_app_name\">Dịch vụ microG</string>\n    <string name=\"gms_settings_name\">Cài đặt microG</string>\n    <string name=\"gms_settings_summary\">Thiết lập dịch vụ microG.</string>\n    <string name=\"auth_general_error_desc\">Không thể kết nối với máy chủ Google.\\n\\nVui lòng thử lại sau.</string>\n    <string name=\"auth_finalize\">Đang liên kết với Google để lưu thông tin tài khoản của bạn.\\n\\nQuá trình này có thể hoàn tất sau vài phút.</string>\n    <string name=\"allow\">Cho phép</string>\n    <string name=\"deny\">Từ chối</string>\n    <string name=\"auth_notification_title\">Yêu cầu xác thực</string>\n    <string name=\"auth_notification_content\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> cần bạn ủy quyền để truy cập vào tài khoản Google của bạn.</string>\n    <string name=\"signin_picker_title\">Chọn tài khoản</string>\n    <string name=\"signin_picker_add_account_label\">Thêm tài khoản khác</string>\n    <string name=\"signin_confirm_button_text\">Cho phép và chia sẻ</string>\n    <string name=\"signin_subtext_policy\">Trước khi sử dụng ứng dụng này, hãy xem lại %1$s và %2$s của ứng dụng.</string>\n    <string name=\"signin_subtext_policy_privacy\">chính sách bảo mật</string>\n    <string name=\"signin_subtext_policy_terms\">điều khoản dịch vụ</string>\n    <string name=\"just_a_sec\">Đợi một chút…</string>\n    <string name=\"ask_permission_tos\">Bằng cách tiếp tục, bạn đồng ý cho ứng dụng này và Google dùng thông tin của bạn theo điều khoản dịch vụ và chính sách bảo mật tương ứng.</string>\n    <string name=\"auth_sign_in\">Đăng nhập</string>\n    <string name=\"auth_connecting\">Đang kết nối tới máy chủ Google để đăng nhập.\\n\\nQuá trình này sẽ hoàn tất sau giây lát.</string>\n    <string name=\"no_network_error_desc\">Không có kết nối mạng.\\n\\nCó thể do mạng yếu hoặc sự cố tạm thời. Vui lòng kiểm tra kết nối mạng và thử lại.</string>\n    <string name=\"signin_picker_subtitle\">để tiếp tục <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"signin_confirm_title\">Cho phép bạn đăng nhập vào <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"signin_subtext_sharing\">Để tiếp tục, microG sẽ chia sẻ tên, địa chỉ email và ảnh hồ sơ từ tải khoản Google của bạn với <xliff:g example=\"F-Droid\">%1$s</xliff:g>.</string>\n    <string name=\"google_account_label\">Google</string>\n    <string name=\"account_manager_title\">Quản Lí Tài Khoản Google</string>\n    <string name=\"sorry\">Rất tiếc…</string>\n    <string name=\"auth_before_connect\">Một ứng dụng trên thiết bị của bạn đang yêu cầu đăng nhập tài khoản Google.\\n\\nNếu đúng là bạn, hãy chọn <b>Đăng nhập</b> để chuyển hướng tới trang đăng nhập của Google, nếu không, chọn <b>Hủy</b> để quay trở lại.</string>\n    <string name=\"limited_services_app_name\">Dịch vụ microG Limited</string>\n    <string name=\"auth_package_override_request_title\">Cho phép <b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> quyền truy cập đặc quyền vào <xliff:g example=\"account@example.com\">%2$s</xliff:g>\\?</string>\n    <string name=\"auth_package_override_request_message\"><b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> muốn truy cập vào tài khoản của bạn như thể nó là <b><xliff:g example=\"F-Droid\">%2$s</xliff:g> của <xliff:g example=\"F-Droid Inc.\">%3$s</xliff:g></b>. Điều này có thể cấp cho nó quyền truy cập đặc quyền vào tài khoản của bạn.</string>\n    <string name=\"ask_scope_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> muốn:</string>\n    <string name=\"ask_service_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> muốn sử dụng:</string>\n    <string name=\"credentials_assisted_cancel\">Huỷ</string>\n    <string name=\"credentials_assisted_signin_button_text_long\">Đăng nhập bằng Google</string>\n    <string name=\"credentials_assisted_choose_account_subtitle\">để tiếp tục đến %1$s</string>\n    <string name=\"perm_gtalk_svc_label\">trao đổi và nhận thông báo đồng bộ từ máy chủ của Google</string>\n    <string name=\"perm_extended_access_label\">Mở rộng quyền truy cập vào các dịch vụ của Google</string>\n    <string name=\"perm_provision_label\">cung cấp dịch vụ microG</string>\n    <string name=\"perm_provision_description\">Cho phép ứng dụng cấu hình các dịch vụ microG mà không cần tương tác của người dùng</string>\n    <string name=\"perm_car_speed_label\">Tốc độ xe</string>\n    <string name=\"perm_car_vendor_extension_description\">Truy cập kênh nhà cung cấp xe của bạn để trao đổi thông tin cụ thể về xe</string>\n    <string name=\"service_name_checkin\">Đăng ký thiết bị Google</string>\n    <string name=\"service_name_snet\">Google SafetyNet</string>\n    <string name=\"games_info_content\">Để sử dụng Play Games, bạn cần cài đặt ứng dụng Google Play Games. Ứng dụng có thể tiếp tục mà không cần Play Games, nhưng có khả năng ứng dụng sẽ hoạt động không như mong đợi.</string>\n    <string name=\"network_type_mobile\">Dữ liệu di dộng</string>\n    <string name=\"service_name_mcs\">Cloud Messaging</string>\n    <string name=\"self_check_cat_fake_sig\">Hỗ trợ giả mạo chữ ký</string>\n    <string name=\"self_check_cat_system\">Hệ thống</string>\n    <string name=\"self_check_name_system_spoofs\">Hệ thống giả mạo chữ ký:</string>\n    <string name=\"cond_perm_title\">Thiếu quyền</string>\n    <string name=\"prefs_account\">Tùy chọn tài khoản</string>\n    <string name=\"prefs_account_privacy\">Thông tin cá nhân &amp; quyền riêng tư</string>\n    <string name=\"pref_auth_visible_summary\">Khi bật, tất cả ứng dụng trên thiết bị này sẽ có thể xem địa chỉ email của Tài khoản Google của bạn mà không cần sự uỷ quyền trước.</string>\n    <string name=\"pref_auth_strip_device_name_title\">Loại bỏ tên thiết bị để xác thực</string>\n    <string name=\"pref_auth_strip_device_name_summary\">Khi bật, các yêu cầu xác thực sẽ không bao gồm tên thiết bị, điều này có thể cho phép các thiết bị không được ủy quyền mà vẫn đăng nhập, nhưng có thể gây ra hậu quả không lường trước được.</string>\n    <string name=\"pref_checkin_enable_summary\">Đăng ký thiết bị của bạn với các dịch vụ của Google và tạo một mã định danh thiết bị duy nhất. microG loại bỏ các bit nhận dạng khác ngoài tên tài khoản Google của bạn từ dữ liệu đăng ký.</string>\n    <string name=\"pref_device_registration_android_id\">ID Android</string>\n    <string name=\"checkin_not_registered\">Chưa được đăng ký</string>\n    <string name=\"checkin_last_registration\">Đăng ký lần cuối: <xliff:g example=\"Hôm qua, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"checkin_enable_switch\">Đăng ký thiết bị</string>\n    <string name=\"pref_info_status\">Trạng thái</string>\n    <string name=\"pref_more_settings\">Thêm</string>\n    <string name=\"pref_accounts_title\">Tài khoản Google</string>\n    <string name=\"pref_accounts_summary\">Thêm và quản lý tài khoản Google</string>\n    <string name=\"prefcat_accounts_settings_title\">Cài đặt</string>\n    <string name=\"prefcat_accounts_current_accounts_title\">Tài khoản</string>\n    <string name=\"pref_add_account_title\">Tài khoản</string>\n    <string name=\"pref_add_account_summary\">Thêm tài khoản Google</string>\n    <string name=\"pref_gcm_apps_summary\">Danh sách các ứng dụng hiện đang được đăng ký sử dụng Cloud Messaging.</string>\n    <string name=\"pref_gcm_confirm_new_apps_summary\">Hỏi trước khi đăng ký một ứng dụng mới để nhận thông báo đẩy</string>\n    <string name=\"pref_about_title\">Giới thiệu về Dịch vụ microG</string>\n    <string name=\"pref_about_summary\">Thông tin phiên bản và thư viện đã sử dụng</string>\n    <string name=\"gcm_app_error_unregistering\">Lỗi khi hủy đăng ký</string>\n    <string name=\"gcm_registered_since\">Đã đăng ký từ: <xliff:g example=\"Hôm qua, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_unregister_confirm_title\">Hủy đăng ký <xliff:g example=\"F-Droid\">%1$s</xliff:g>\\?</string>\n    <string name=\"gcm_unregister_confirm_message\">Một số ứng dụng không tự động đăng ký lại và/hoặc không cung cấp tùy chọn để thực hiện thủ công. Những ứng dụng này có thể không hoạt động chính xác sau khi hủy đăng ký.\\nBạn có muốn tiếp tục không?</string>\n    <string name=\"gcm_messages_counter\">Thông báo: <xliff:g example=\"123\">%1$d</xliff:g> (<xliff:g example=\"12345\">%2$d</xliff:g> byte)</string>\n    <string name=\"gcm_enable_switch\">Nhận thông báo đẩy</string>\n    <string name=\"gcm_allow_app_popup\">Cho phép <xliff:g example=\"F-Droid\">%1$s</xliff:g> đăng ký nhận thông báo đẩy?</string>\n    <string name=\"pref_push_app_allow_register_title\">Cho phép đăng ký</string>\n    <string name=\"prefcat_push_apps_title\">Ứng dụng sử dụng thông báo đẩy</string>\n    <string name=\"pref_test_summary_running\">Đang chạy…</string>\n    <string name=\"pref_safetynet_recent_attestation_summary\">Chứng thực: %s</string>\n    <string name=\"pref_safetynet_recent_recaptcha_summary\">ReCaptcha: %s</string>\n    <string name=\"pref_safetynet_recent_recaptcha_enterprise_summary\">ReCaptcha Enterprise: %s</string>\n    <string name=\"pref_safetynet_recent_copy_json\">Sao chép dữ liệu JSON JWS</string>\n    <string name=\"pref_safetynet_recent_advice\">Lời khuyên</string>\n    <string name=\"pref_safetynet_recent_nonce\">Nonce (Hex)</string>\n    <string name=\"pref_safetynet_recent_request_time\">Thời gian yêu cầu</string>\n    <string name=\"pref_safetynet_recent_request_type\">Loại yêu cầu</string>\n    <string name=\"pref_safetynet_recent_token\">Token</string>\n    <string name=\"pref_safetynet_recent_copied\">Đã sao chép vào bảng nhớ tạm!</string>\n    <string name=\"pref_safetynet_test_integrity_cts_passed\">Đã vượt qua Integrity và kiểm tra CTS</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_switch\">Tự động thêm ứng dụng miễn phí vào thư viện</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_summary\">Ứng dụng miễn phí có thể kiểm tra xem chúng đã được tải xuống từ Google Play hay chưa. Tự động thêm ứng dụng miễn phí vào thư viện tài khoản của bạn để luôn vượt qua kiểm tra đối với tất cả các ứng dụng miễn phí hiện có sẵn cho bạn.</string>\n    <string name=\"credentials_assisted_continue\">Tiếp tục</string>\n    <string name=\"credentials_assisted_confirmation_header\">Đang đăng nhập cho bạn</string>\n    <string name=\"credentials_assisted_sign_back_title\">Đăng nhập lại vào %1$s bằng Google</string>\n    <string name=\"credentials_assisted_signin_consent_header\">Đang đăng nhập với tư cách %1$s</string>\n    <string name=\"credentials_assisted_signin_consent\">Bằng cách tiếp tục, Google sẽ chia sẻ tên, địa chỉ email và ảnh hồ sơ của bạn với %1$s. Xem Chính sách quyền riêng tư và Điều khoản dịch vụ của %1$s.</string>\n    <string name=\"limited_services_dialog_information\">Bạn đang sử dụng Dịch vụ microG Limited. Không giống như các Dịch vụ microG thông thường, phiên bản này chỉ hoạt động với các ứng dụng sử dụng thư viện microG, không phải các ứng dụng trên Google Play. Điều này có nghĩa là hầu hết các ứng dụng sẽ bỏ qua các dịch vụ này.</string>\n    <string name=\"perm_status_broadcast_label\">Nghe các thông báo trạng thái nội bộ</string>\n    <string name=\"perm_gsf_read_gservices_label\">đọc cấu hình dịch vụ Google</string>\n    <string name=\"perm_c2dm_receive_label\">nghe các thông báo C2DM</string>\n    <string name=\"perm_c2dm_send_label\">gửi các thông báo C2DM đến các ứng dụng khác</string>\n    <string name=\"perm_car_fuel_label\">Mức nhiên liệu của xe</string>\n    <string name=\"perm_car_mileage_label\">Số km xe đã đi</string>\n    <string name=\"perm_car_speed_description\">Truy cập tốc độ xe của bạn</string>\n    <string name=\"perm_car_info_label\">Thông tin xe</string>\n    <string name=\"perm_car_mileage_description\">Truy cập thông tin về số km đã đi của xe bạn</string>\n    <string name=\"perm_car_info_description\">Truy cập thông tin xe của bạn</string>\n    <string name=\"perm_car_fuel_description\">Truy cập thông tin mức nhiên liệu của xe bạn</string>\n    <string name=\"perm_car_vendor_extension_label\">Kênh nhà cung cấp xe</string>\n    <string name=\"games_info_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> muốn sử dụng Play Games</string>\n    <string name=\"service_name_vending\">Dịch vụ Cửa hàng Play</string>\n    <string name=\"games_title\">Google Play Games</string>\n    <string name=\"pick_place_title\">Chọn địa điểm</string>\n    <string name=\"pick_place_desc\">Trình chọn địa điểm hiện chưa có sẵn.</string>\n    <string name=\"place_picker_select_title\">Chọn địa điểm này</string>\n    <string name=\"place_picker_nearby_places\">Địa điểm gần đây</string>\n    <string name=\"lacking_permission_toast\">Dịch vụ microG: Không có quyền <xliff:g example=\"có quyền truy cập mạng đầy đủ\">%1$s</xliff:g></string>\n    <string name=\"place_picker_location_lat_lng\">(%1$.7f, %2$.7f)</string>\n    <string name=\"network_type_roaming\">Chuyển vùng quốc tế</string>\n    <string name=\"network_type_other\">Các mạng khác</string>\n    <string name=\"network_type_wifi\">Wi-Fi</string>\n    <string name=\"self_check_name_perm_granted\">Hệ thống cấp quyền giả mạo chữ ký:</string>\n    <string name=\"self_check_name_fake_sig_perm\">Hệ thống có hỗ trợ giả mạo chữ ký:</string>\n    <string name=\"self_check_resolution_perm_granted\">Đây là một chỉ báo mạnh cho thấy ROM hỗ trợ giả mạo chữ ký, nhưng cần thêm thao tác để kích hoạt nó. Vui lòng kiểm tra tài liệu để biết về các bước cần thiết.</string>\n    <string name=\"self_check_name_app_installed\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> đã cài đặt: </string>\n    <string name=\"self_check_pkg_vending\">Trợ lý microG / Cửa hàng Play</string>\n    <string name=\"self_check_pkg_gsf\">Khung dịch vụ microG</string>\n    <string name=\"self_check_name_battery_optimizations\">Tắt tối ưu hóa pin:</string>\n    <string name=\"prefcat_about\">Giới thiệu</string>\n    <string name=\"self_check_resolution_battery_optimizations\">Chạm vào đây để tắt tối ưu hóa pin. Không làm như vậy có thể khiến các ứng dụng hoạt động không bình thường.</string>\n    <string name=\"prefcat_components\">Thành phần</string>\n    <string name=\"cond_gcm_bat_title\">Đã bật tính năng tối ưu hóa pin</string>\n    <string name=\"cond_gcm_bat_summary\">Bạn đã bật Cloud Messaging nhưng cũng bật tối ưu hóa pin cho Dịch vụ microG. Để thông báo đẩy, bạn nên tắt tối ưu hóa pin.</string>\n    <string name=\"prefs_account_security\">Đăng nhập &amp; bảo mật</string>\n    <string name=\"pref_auth_visible_title\">Cho phép ứng dụng tìm tài khoản</string>\n    <string name=\"pref_auth_trust_google_title\">Tin tưởng Google về quyền truy cập ứng dụng</string>\n    <string name=\"pref_auth_trust_google_summary\">Khi tắt, người dùng sẽ được hỏi trước khi yêu cầu uỷ quyền của ứng dụng được gửi đến Google. Một số ứng dụng sẽ không sử dụng được tài khoản Google nếu tắt tính năng này.</string>\n    <string name=\"pref_auth_include_android_id_title\">Xác thực bằng cách đăng ký thiết bị</string>\n    <string name=\"pref_auth_include_android_id_summary\">Khi tắt, các yêu cầu xác thực sẽ không được liên kết với việc đăng ký thiết bị, điều này có thể cho phép các thiết bị không được uỷ quyền mà vẫn đăng nhập, nhưng có thể gây ra hậu quả không lường trước được.</string>\n    <string name=\"pref_gcm_heartbeat_title\">Khoảng thời gian kiểm tra kết nối của Cloud Messaging</string>\n    <string name=\"pref_gcm_enable_mcs_summary\">Cloud Messaging là nhà cung cấp dịch vụ thông báo đẩy được nhiều ứng dụng của bên thứ ba sử dụng. Để sử dụng, bạn phải bật đăng ký thiết bị.</string>\n    <string name=\"pref_gcm_apps_title\">Các ứng dụng sử dụng Cloud Messaging</string>\n    <string name=\"pref_gcm_confirm_new_apps_title\">Xác nhận ứng dụng mới</string>\n    <string name=\"gcm_app_not_installed_anymore\">Không còn được cài đặt</string>\n    <string name=\"gcm_registered\">Đã đăng ký</string>\n    <string name=\"gcm_no_message_yet\">Chưa nhận được thông báo nào cho đến nay</string>\n    <string name=\"gcm_unregister_app\">Hủy đăng ký</string>\n    <string name=\"gcm_not_registered\">Chưa đăng ký</string>\n    <string name=\"gcm_last_message_at\">Thông báo cuối cùng: <xliff:g example=\"Hôm qua, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_network_state_disconnected\">Đã ngắt kết nối</string>\n    <string name=\"gcm_network_state_connected\">Đã kết nối từ <xliff:g example=\"2 giờ trước\">%1$s</xliff:g></string>\n    <string name=\"pref_push_app_wake_for_delivery_summary\">Khởi chạy ứng dụng khi ở chế độ nền để nhận các tin nhắn đẩy.</string>\n    <string name=\"safetynet_enable_switch\">Cho phép xác thực thiết bị</string>\n    <string name=\"pref_safetynet_test_title\">Kiểm tra chứng nhận SafetyNet</string>\n    <string name=\"pref_recaptcha_test_title\">Kiểm tra ReCAPTCHA</string>\n    <string name=\"pref_test_summary_passed\">Đã vượt qua tất cả các bài kiểm tra</string>\n    <string name=\"pref_test_summary_failed\">Thất bại: %s</string>\n    <string name=\"pref_test_summary_warn\">Cảnh báo: %s</string>\n    <string name=\"pref_droidguard_unsupported_summary\">Thực thi DroidGuard không được hỗ trợ trên thiết bị này. Các dịch vụ SafetyNet có thể hoạt động không bình thường.</string>\n    <string name=\"prefcat_safetynet_apps_title\">Ứng dụng sử dụng SafetyNet</string>\n    <string name=\"menu_clear_recent_requests\">Xóa các yêu cầu gần đây</string>\n    <string name=\"pref_device_registration_serial_title\">Số sê-ri</string>\n    <string name=\"pref_device_registration_import_custom_profile_summary\">Nhập hồ sơ thiết bị từ tệp</string>\n    <string name=\"pref_device_registration_select_profile_title\">Chọn hồ sơ</string>\n    <string name=\"pref_device_registration_device_profile_category\">Hồ sơ thiết bị</string>\n    <string name=\"pref_safetynet_recent_uses\">Sử dụng gần đây</string>\n    <string name=\"pref_safetynet_recent_response_status\">Trạng thái phản hồi</string>\n    <string name=\"pref_safetynet_recent_cat_response\">Dữ liệu phản hồi</string>\n    <string name=\"pref_safetynet_recent_cat_request\">Yêu cầu dữ liệu</string>\n    <string name=\"pref_vending_license_enable_summary\">Một số ứng dụng yêu cầu xác thực rằng bạn đã mua chúng trên Google Play. Khi được ứng dụng yêu cầu, microG có thể tải xuống bằng chứng mua hàng từ Google. Nếu bị vô hiệu hóa hoặc không có tài khoản Google được thêm vào, các yêu cầu xác minh giấy phép sẽ bị bỏ qua.</string>\n    <string name=\"feedback_disabled\">Hiện tại không thể phản hồi</string>\n    <string name=\"backup_disabled\">Hiện tại không thể sao lưu</string>\n    <string name=\"pref_vending_billing_category\">Thanh toán Google Play</string>\n    <string name=\"pref_vending_billing_note_experimental\">Cảnh báo: Tính năng này đang trong giai đoạn thử nghiệm và có thể dẫn đến mất tiền.</string>\n    <string name=\"self_check_name_correct_sig\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> có chữ ký chính xác: </string>\n    <string name=\"self_check_resolution_fake_sig_perm\">ROM của bạn không có hỗ trợ gốc cho việc giả mạo chữ ký. Bạn vẫn có thể sử dụng Xposed hoặc các hệ thống khác để giả mạo chữ ký. Vui lòng kiểm tra tài liệu về ROM nào hỗ trợ giả mạo chữ ký và cách sử dụng microG trên ROM không được hỗ trợ.</string>\n    <string name=\"self_check_resolution_correct_sig\">Hoặc là <xliff:g example=\"F-Droid\">%1$s</xliff:g> đã cài đặt không tương thích hoặc tính năng giả mạo chữ ký không hoạt động đối với nó. Vui lòng kiểm tra tài liệu về các ứng dụng và ROM nào tương thích.</string>\n    <string name=\"prefcat_configuration\">Cấu hình</string>\n    <string name=\"prefcat_google_services\">Dịch vụ của Google</string>\n    <string name=\"prefcat_location_service\">Dịch vụ định vị</string>\n    <string name=\"prefcat_services\">Dịch vụ</string>\n    <string name=\"prefcat_push_networks_title\">Mạng sử dụng cho thông báo đẩy</string>\n    <string name=\"pref_droidguard_operation_mode\">Chế độ hoạt động</string>\n    <string name=\"safetynet_last_run_at\">Lần sử dụng cuối cùng: <xliff:g example=\"Hôm qua, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"prefcat_push_apps_registered_title\">Ứng dụng đã đăng ký</string>\n    <string name=\"profile_name_native\">Gốc</string>\n    <string name=\"profile_name_user\">Tùy chỉnh: %s</string>\n    <string name=\"profile_name_auto\">Tự động: %s</string>\n    <string name=\"profile_name_real\">Thực</string>\n    <string name=\"pref_safetynet_recent_eval_type\">Loại đánh giá</string>\n    <string name=\"profile_name_system\">Hệ thống: %s</string>\n    <string name=\"pref_device_registration_import_custom_profile_title\">Nhập hồ sơ tùy chỉnh</string>\n    <string name=\"pref_safetynet_test_not_completed\">Chưa hoàn thành</string>\n    <string name=\"pref_safetynet_test_no_result\">Không có kết quả</string>\n    <string name=\"push_notifications_summary_manual\">BẬT/Thủ công: %s</string>\n    <string name=\"push_notifications_summary_values_seconds\">%s giây</string>\n    <string name=\"push_notifications_summary_values_minutes\">%s phút</string>\n    <string name=\"pref_vending_summary_licensing_off\">Tắt cấp phép</string>\n    <string name=\"pref_vending_summary_licensing_on\">Bật cấp phép</string>\n    <string name=\"pref_vending_licensing_category\">Cấp phép Google Play</string>\n    <string name=\"pref_vending_licensing_enable_switch\">Phản hồi các yêu cầu xác thực giấy phép</string>\n    <string name=\"pref_vending_billing_enable_switch\">Xử lý yêu cầu thanh toán</string>\n    <string name=\"pref_vending_billing_enable_summary\">Sau khi được bật, một số ứng dụng có thể hoàn tất giao dịch mua hoặc bắt đầu đăng ký thông qua dịch vụ thanh toàn Google Play.</string>\n    <string name=\"pref_vending_billing_note_licensing\">Một số ứng dụng có thể yêu cầu bạn cũng phải bật xác thực giấy phép để xác minh các giao dịch mua của bạn.</string>\n    <string name=\"credentials_assisted_signin_description\">Bạn có thể quản lý Đăng nhập bằng Google trong tài khoản Google của bạn.</string>\n    <string name=\"pref_safetynet_test_cts_failed\">Kiểm tra CTS không thành công</string>\n    <string name=\"self_check_cat_gms_packages\">Các gói đã cài đặt</string>\n    <string name=\"self_check_resolution_system_spoofs\">Vui lòng kiểm tra tài liệu để biết những bước nào có thể được yêu cầu.</string>\n    <string name=\"self_check_resolution_app_installed\">Cài đặt ứng dụng <xliff:g example=\"F-Droid\">%1$s</xliff:g> hoặc ứng dụng tương thích. Vui lòng kiểm tra tài liệu về ứng dụng nào tương thích.</string>\n    <string name=\"self_check_pkg_gms\">Dịch vụ microG</string>\n    <string name=\"prefcat_test\">Kiểm tra</string>\n    <string name=\"cond_gcm_bat_action\">Tắt tối ưu hóa pin</string>\n    <string name=\"pref_gcm_heartbeat_summary\">Khoảng thời gian tính bằng giây để hệ thống gửi tín hiệu đến máy chủ Google. Tăng giá trị này sẽ giảm tiêu thụ pin, nhưng có thể gây ra sự chậm trễ trong việc nhận thông báo đẩy.\\nTính năng này đã bị loại bỏ và sẽ được thay thế trong các phiên bản sau.</string>\n    <string name=\"pref_gcm_ping_interval\">Khoảng thời gian ping: <xliff:g example=\"10 phút\">%1$s</xliff:g></string>\n    <string name=\"gcm_unregister_after_deny_message\">Bạn đã từ chối một ứng dụng đăng ký nhận thông báo đẩy đã được đăng ký.\\nBạn có muốn hủy đăng ký ngay bây giờ để ứng dụng không nhận được tin nhắn đẩy trong tương lai không?</string>\n    <string name=\"pref_push_app_allow_register_summary\">Cho phép ứng dụng đăng ký nhận thông báo đẩy.</string>\n    <string name=\"pref_push_app_wake_for_delivery_title\">Khởi chạy ứng dụng khi có thông báo đẩy</string>\n    <string name=\"prefcat_push_apps_unregistered_title\">Ứng dụng chưa đăng ký</string>\n    <string name=\"safetynet_intro\">Google SafetyNet là hệ thống chứng nhận thiết bị, đảm bảo rằng thiết bị được bảo mật đúng cách và tương thích với Android CTS. Một số ứng dụng sử dụng SafetyNet vì lý do bảo mật hoặc như một điều kiện tiên quyết để ngăn chặn việc can thiệp trái phép.\\n\\nMicroG GmsCore có tích hợp phiên bản SafetyNet mã nguồn mở, nhưng để gửi yêu cầu đến máy chủ chính thức, hệ thống cần sử dụng DroidGuard – một công nghệ độc quyền của Google để xác minh.</string>\n    <string name=\"pref_recaptcha_enterprise_test_title\">Kiểm tra ReCAPTCHA Enterprise</string>\n    <string name=\"pref_safetynet_recent_cat_basic\">Dữ liệu cơ bản</string>\n    <string name=\"pref_safetynet_test_integrity_failed\">Integrity không thành công</string>\n    <string name=\"pref_safetynet_test_invalid_json\">JSON không hợp lệ</string>\n    <string name=\"push_notifications_summary_off\">TẮT</string>\n    <string name=\"push_notifications_summary_automatic\">BẬT/Tự động: %s</string>\n    <string name=\"credentials_assisted_continue_as_user_button_label\">Tiếp tục như %1$s</string>\n    <string name=\"credentials_assisted_choose_account_label\">Chọn tài khoản</string>\n    <string name=\"limited_services_dialog_information_ack\">Tôi hiểu</string>\n    <string name=\"auth_action_activity_explanation\">Hoàn thành các bước sau để có thể sử dụng tài khoản Google %s trên thiết bị này.</string>\n    <string name=\"auth_action_step_enable_lockscreen_description\">Tài khoản Google của bạn được quản lý bởi nơi làm việc hoặc cơ sở giáo dục của bạn. Quản trị viên của bạn đã quyết định rằng các thiết bị cần có màn hình khóa bảo mật trước khi chúng có thể truy cập dữ liệu tài khoản.\\n\\nVui lòng thiết lập màn hình khóa bằng mật khẩu, mã PIN hoặc hình vẽ.</string>\n    <string name=\"auth_action_notification_channel_name\">Cảnh báo tài khoản Google</string>\n    <string name=\"auth_action_activity_header\">Hoàn tất thiết lập tài khoản Google của bạn</string>\n    <string name=\"auth_action_notification_channel_description\">Thông báo khi một trong các tài khoản Google của bạn cần thiết lập thêm trước khi có thể sử dụng hoặc khi một tài khoản không tương thích với microG.</string>\n    <string name=\"auth_action_notification_content\">Tài khoản Google của bạn cần được thiết lập thêm.</string>\n    <string name=\"auth_action_notification_title\">Hành động tài khoản bắt buộc</string>\n    <string name=\"auth_action_step_allow_microg_gcm\">Cho phép Cloud Messaging cho microG</string>\n    <string name=\"auth_action_step_allow_microg_gcm_description\">Theo tuỳ chọn của bạn, microG cần có sự cho phép của bạn trước khi có thể tự đăng ký dịch vụ Cloud Messaging.</string>\n    <string name=\"auth_action_step_enable_gcm\">Kích hoạt Cloud Messaging</string>\n    <string name=\"auth_action_step_enable_gcm_description\">Bạn có thể tắt Cloud Messaging sau khi hoàn tất quá trình thiết lập tài khoản.</string>\n    <string name=\"auth_action_step_enable_checkin\">Kích hoạt đăng kí thiết bị</string>\n    <string name=\"auth_action_step_enable_checkin_description\">Thiết bị của bạn cần phải đăng ký với Google ít nhất một lần.\\n\\nBạn có thể tắt đăng ký thiết bị Google sau khi thiết lập tài khoản hoàn tất.</string>\n    <string name=\"auth_action_step_enable_lockscreen\">Cấu hình khóa màn hình bảo mật</string>\n    <string name=\"auth_action_activity_finish\">Hoàn tất</string>\n    <string name=\"auth_action_step_perform_content_description\">Nhấn để thực hiện</string>\n    <string name=\"auth_action_step_completed_content_description\">Bước đã hoàn thành</string>\n    <string name=\"pref_vending_asset_delivery_category\">Google Play Asset Delivery</string>\n    <string name=\"pref_vending_asset_delivery_switch\">Cho phép phân phối tài sản theo yêu cầu</string>\n    <string name=\"pref_vending_asset_delivery_summary\">Tải xuống các tài sản bổ sung khi được các ứng dụng sử dụng Play Asset Delivery yêu cầu</string>\n    <string name=\"pref_vending_asset_device_sync_summary\">Các ứng dụng sử dụng Play Asset Delivery sẽ tải xuống các nội dung bổ sung dựa trên thông tin của thiết bị hiện đang sử dụng.</string>\n    <string name=\"pref_vending_asset_device_sync_switch\">Bật đồng bộ thông tin thiết bị</string>\n    <string name=\"games_achievement_list_title\">Thành tựu</string>\n    <string name=\"games_achievements_empty_text\">Không có thành tựu nào cho trò chơi này</string>\n    <string name=\"games_api_access_denied\">Không có tài khoản nào trên thiết bị này có thể truy cập API trò chơi</string>\n    <string name=\"games_achievement_locked_content_description\">bị khóa</string>\n    <string name=\"games_achievement_unlocked_content_description\">đã mở khóa</string>\n    <string name=\"games_snapshot_choose_btn_text\">chọn</string>\n    <string name=\"games_leaderboards_score_label\">Điểm: %1$s</string>\n    <string name=\"games_achievement_extra_text\">%1$s kinh nghiệm</string>\n    <string name=\"games_leaderboard_score_empty_text\">Không thể tin được! Không có điểm cao công khai cho trò chơi này.</string>\n    <string name=\"games_leaderboard_list_title\">Xếp hạng</string>\n    <string name=\"games_snapshot_empty_text\">Chưa có bản ghi trò chơi nào được lưu</string>\n    <string name=\"games_delete_snapshot_dialog_message\">Bạn có chắc chắn muốn xóa điểm lưu của trò chơi không?</string>\n    <string name=\"games_delete_snapshot_dialog_cancel\">Hủy</string>\n    <string name=\"games_delete_snapshot_dialog_ok\">OK</string>\n    <string name=\"games_delete_snapshot_error\">Xóa không thành công, vui lòng thử lại sau</string>\n    <string name=\"games_snapshot_delete_btn_text\">xóa</string>\n    <string name=\"games_delete_snapshot_dialog_title\">Xóa điểm lưu của trò chơi</string>\n    <string name=\"games_leaderboard_empty_text\">Không có bảng xếp hạng cho trò chơi này</string>\n    <string name=\"service_name_work_profile\">Hồ sơ công việc</string>\n    <string name=\"pref_vending_feature_delivery\">Google Play Feature Delivery</string>\n    <string name=\"pref_vending_split_install_switch\">Cài đặt thành phần theo yêu cầu</string>\n    <string name=\"pref_workprofile_create_account\">Cho phép thiết lập tài khoản công việc</string>\n    <string name=\"pref_workprofile_intro\">Khi thiết lập hồ sơ công việc cho nơi làm việc hoặc tổ chức giáo dục của bạn, thiết lập có thể kết nối với Google để cho phép tải xuống các ứng dụng vào hồ sơ đó.</string>\n    <string name=\"camera_permission_dialog_title\">Yêu cầu quyền truy cập máy ảnh</string>\n    <string name=\"pref_workprofile_disclaimer\">Bạn cần tự đảm bảo rằng việc sử dụng microG phù hợp với chính sách của doanh nghiệp. MicroG được cung cấp theo khả năng tốt nhất và có thể không đảm bảo hoạt động hoàn toàn như mong đợi.</string>\n    <string name=\"camera_permission_dialog_button\">ĐỒNG Ý</string>\n    <string name=\"pref_vending_licensing_split_install_summary\">Cho phép các ứng dụng tải xuống và cài đặt các thành phần bổ sung</string>\n    <string name=\"barcode_scanner_brand\">Được quét bởi microG thay cho %1$s</string>\n    <string name=\"camera_permission_dialog_message\">Dịch vụ microG cần quyền truy cập vào máy ảnh của thiết bị để quét mã cho %1$s.\\n\\nĐể bật, vui lòng cấp quyền sử dụng máy ảnh cho dịch vụ microG trong cài đặt.</string>\n    <string name=\"credentials_assisted_choose_account_error_tips\">Tài khoản có dấu hiệu bất thường</string>\n    <string name=\"credentials_assisted_signin_add_account\">Thêm tài khoản</string>\n    <string name=\"auth_action_reauth_notification_title\">Cần thao tác với tài khoản</string>\n    <string name=\"pref_auth_two_step_verification_title\">Nhận lời nhắc xác minh hai lớp</string>\n    <string name=\"pref_auth_two_step_verification_summary\">Khi bật, thiết bị có thể nhận được lời nhắc xác minh hai lớp từ Google (cần phải bật Cloud Messaging).</string>\n    <string name=\"pref_game_accounts_title\">Tài khoản trò chơi Google</string>\n    <string name=\"pref_auto_create_player\">Cho phép đăng ký tài khoản Play Games</string>\n    <string name=\"pref_auto_create_player_intro\">Khi chơi trò chơi, bạn cần sử dụng tài khoản Play Games để đăng nhập và ghi lại các chức năng liên quan đến trò chơi, chẳng hạn như thành tích, bảng xếp hạng, kho lưu trữ, v.v.. Sau khi tắt, các tài khoản Google không liên kết với tài khoản Play Games sẽ không được tự động đăng ký và trò chơi sẽ không thể đăng nhập cũng như chơi.</string>\n    <string name=\"pref_allow_upload_game_played\">Cho phép tải lên trò chơi đã chơi</string>\n    <string name=\"pref_allow_upload_game_played_summary\">Khi tắt, trò chơi sẽ không báo cáo trạng thái trò chơi đã chơi sau khi đăng nhập vào trò chơi và một số trò chơi có thể không đăng nhập được.</string>\n    <string name=\"pref_change_default_game_player\">Thay đổi tài khoản cho trò chơi</string>\n    <string name=\"pref_change_default_game_player_summary\">Thay đổi tài khoản mặc định cho trò chơi và Thay đổi tài khoản theo trò chơi.</string>\n    <string name=\"pref_delete_game_account_data\">Xóa dữ liệu Play Games</string>\n    <string name=\"pref_delete_game_account_data_summary\">Xóa tài khoản Play Games, toàn bộ dữ liệu và xóa dữ liệu trò chơi riêng lẻ.</string>\n    <string name=\"games_state_description_signed_out\">Đã đăng xuất</string>\n    <string name=\"games_state_description_delete\">Xoá</string>\n    <string name=\"games_change_button_text\">Thay đổi</string>\n    <string name=\"games_change_default_account_section_title\">Thay đổi tài khoản mặc định cho trò chơi</string>\n    <string name=\"games_change_default_account_description\">Tài khoản mặc định: %1$s</string>\n    <string name=\"games_change_default_account_explanation\">Tài khoản này được sử dụng để tự động đăng nhập vào trò chơi, lưu tiến trình chơi và cài đặt. Việc thay đổi tài khoản mặc định hoặc đăng xuất có thể đặt lại tiến trình và cài đặt cho các trò chơi bạn đã chơi.</string>\n    <string name=\"games_change_per_game_title\">Thay đổi tài khoản theo trò chơi</string>\n    <string name=\"games_change_per_game_description\">Việc thay đổi tài khoản cho trò chơi đã chọn hoặc đăng xuất có thể đặt lại tiến trình và cài đặt của bạn cho trò chơi.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_title\">Chọn một tùy chọn cho tài khoản mặc định mới</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_description\">Tài khoản mặc định hiện tại: %1$s</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_title\">Chỉ thay đổi tài khoản mặc định cho trò chơi mới</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_description\">Bạn sẽ không mất quyền truy cập vào tiến trình và cài đặt của các trò chơi đã chơi. Tuy nhiên, tiến trình của bạn sẽ được chia đều cho các tài khoản.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_title\">Thay đổi tài khoản mặc định cho tất cả trò chơi</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_description\">Bạn có thể mất quyền truy cập vào tiến trình và cài đặt của các trò chơi đã chơi. Chúng tôi sẽ khởi động lại trò chơi để áp dụng các thay đổi của bạn.</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_title\">Đăng xuất khỏi tất cả các trò chơi</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_description\">Bạn có thể mất cài đặt và tiến trình trò chơi của mình. Chúng tôi sẽ khởi chạy lại trò chơi để áp dụng thay đổi của bạn.</string>\n    <string name=\"games_change_per_game_dialog_title\">Chọn tuỳ chọn cho trò chơi này</string>\n    <string name=\"games_change_per_game_dialog_description\">Đăng xuất hoặc chuyển đổi tài khoản có thể làm mất cài đặt và tiến trình trong trò chơi</string>\n    <string name=\"games_change_per_game_dialog_option_use_player\">Dùng %1$s</string>\n    <string name=\"games_change_per_game_dialog_option_use_player_snackbar_success_message\">Bạn sẽ đăng nhập vào trò chơi này bằng %1$s</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out\">Đăng xuất</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out_snackbar_success_message\">Bạn đã đăng xuất khỏi trò chơi này</string>\n    <string name=\"games_change_sign_out_of_all_games_snackbar_success_message\">Bạn đã đăng xuất khỏi tất cả trò chơi</string>\n    <string name=\"games_change_default_account_for_all_games_snackbar_success_message\">Bạn sẽ đăng nhập vào tất cả trò chơi bằng %1$s</string>\n    <string name=\"games_change_default_account_for_new_games_snackbar_success_message\">Bạn sẽ đăng nhập vào trò chơi mới bằng %1$s</string>\n    <string name=\"games_account_display_content\">Tài khoản hiện tại: %1$s</string>\n    <string name=\"games_delete_profile_header\">Xoá tài khoản Play Game &amp; tất cả dữ liệu</string>\n    <string name=\"games_delete_profile_explanation\">Xoá vĩnh viễn tài khoản Google Play Game, XP và toàn bộ dữ liệu hồ hơ của bạn. Thao tác này cũng xoá điểm, tiến trình (lưu trò chơi), và cài đặt trong trò chơi bạn từng chơi.</string>\n    <string name=\"games_delete_profile_button\">Xoá vĩnh viễn</string>\n    <string name=\"games_delete_game_data_header\">Xoá dữ liệu trò chơi cá nhân</string>\n    <string name=\"games_delete_game_data_explanation\">Bạn có thể xoá vĩnh viễn dữ liệu cá nhân cho trò chơi bạn chơi khi dùng Google Play Game. Thao tác này sẽ xoá điểm, tiến trình (lưu trò chơi), và cài đặt cho trò chơi bạn đã chọn.</string>\n    <string name=\"games_delete_profile_dialog_title\">Bạn có chắc chắn muốn xoá tài khoản này?</string>\n    <string name=\"games_delete_profile_explanation_with_gamer_name\">Xoá vĩnh viễn tài khoản Google Play Game cho người chơi <b>%1$s</b> (<b>%2$s</b>), XP và toàn bộ dữ liệu hồ hơ của bạn. Thao tác này cũng xoá điểm, tiến trình (lưu trò chơi), và cài đặt trong trò chơi bạn từng chơi.</string>\n    <string name=\"games_delete_profile_dialog_message\">Thao tác này không thể hoàn tác.</string>\n    <string name=\"games_delete_profile_fail\">Không thể xoá hồ sơ của bạn. Thử lại sau.</string>\n    <string name=\"games_delete_game_data_confirm_dialog_title\">Xoá dữ liệu của %1$s</string>\n    <string name=\"games_delete_game_data_confirm_dialog_message\">Xoá vĩnh viễn dữ liệu của %1$s sẽ xoá điểm, tiến trình (lưu trò chơi), và cài đặt trong Google Play Game.</string>\n    <string name=\"games_popup_signin_welcome\">Chào bạn, %1$s</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-zh-rCN/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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  --><resources>\n    <string name=\"permission_service_all_label\">所有 Google 服务</string>\n    <string name=\"permission_service_all_description\">允许应用通过任何已关联的 Google 账号访问所有 Google 服务。</string>\n    <string name=\"permission_service_android_label\">Android 服务</string>\n    <string name=\"permission_service_android_description\">允许应用通过任何已关联的 Google 账号访问所有 Android 服务。</string>\n    <string name=\"permission_service_adsense_description\">允许应用通过任何已关联的 Google 账号访问 AdSense。</string>\n    <string name=\"permission_service_adwords_description\">允许应用通过任何已关联的 Google 账号访问 AdWords。</string>\n    <string name=\"permission_service_ah_description\">允许应用通过任何已关联的 Google 账号访问 Google App Engine。</string>\n    <string name=\"permission_service_blogger_description\">允许应用通过任何已关联的 Google 账号访问 Blogger。</string>\n    <string name=\"permission_service_cl_description\">允许应用通过任何已关联的 Google 账号访问 Google 日历。</string>\n    <string name=\"permission_service_cp_description\">允许应用通过任何已关联的 Google 账号访问联系人。</string>\n    <string name=\"permission_service_dodgeball_description\">允许应用通过任何已关联的 Google 账号访问 Dodgeball。</string>\n    <string name=\"permission_service_finance_description\">允许应用通过任何已关联的 Google 账号访问 Google 财经。</string>\n    <string name=\"permission_service_gbase_description\">允许应用通过任何已关联的 Google 账号访问 Google Base。</string>\n    <string name=\"permission_service_finance_label\">Google 财经</string>\n    <string name=\"permission_service_cp_label\">联系人</string>\n    <string name=\"permission_service_cl_label\">Google 日历</string>\n    <string name=\"permission_service_grandcentral_description\">允许应用通过任何已关联的 Google 账号访问 Google Voice。</string>\n    <string name=\"permission_service_speech_label\">语音搜索</string>\n    <string name=\"permission_service_speech_description\">允许应用通过任何已关联的 Google 账号访问语音搜索。</string>\n    <string name=\"permission_service_speechpersonalization_label\">个性化语音识别</string>\n    <string name=\"permission_service_speechpersonalization_description\">允许应用通过任何已关联的 Google 账号访问个性化语音识别。</string>\n    <string name=\"permission_service_talk_description\">允许应用通过任何已关联的 Google 账号访问 Google Talk。</string>\n    <string name=\"permission_service_wifi_description\">允许应用通过任何已关联的 Google 账号访问 Google Wi-Fi。</string>\n    <string name=\"permission_service_wise_description\">允许应用通过任何已关联的 Google 账号访问 Google Spreadsheets。</string>\n    <string name=\"permission_service_writely_label\">Google 文档</string>\n    <string name=\"permission_service_writely_description\">允许应用通过任何已关联的 Google 账号访问 Google 文档。</string>\n    <string name=\"permission_service_youtube_description\">允许应用通过任何已关联的 Google 账号访问 YouTube。</string>\n    <string name=\"permission_service_YouTubeUser_label\">YouTube 用户名</string>\n    <string name=\"permission_service_YouTubeUser_description\">允许应用通过任何已关联的 Google 账号获知其 YouTube 用户名。</string>\n    <string name=\"permission_service_lh2_label\">Picasa 网络相册</string>\n    <string name=\"permission_service_lh2_description\">允许应用通过任何已关联的 Google 账号访问 Picasa 网络相册。</string>\n    <string name=\"permission_service_local_label\">Google 地图</string>\n    <string name=\"permission_service_local_description\">允许应用通过任何已关联的 Google 账号访问 Google 地图。</string>\n    <string name=\"permission_service_mail_label\">Google 电子邮件</string>\n    <string name=\"permission_service_mail_description\">允许应用通过任何已关联的 Google 账号访问 Google 电子邮件。</string>\n    <string name=\"permission_service_news_label\">Google 新闻</string>\n    <string name=\"permission_service_news_description\">允许应用通过任何已关联的 Google 账号访问 Google 新闻。</string>\n    <string name=\"permission_service_orkut_description\">允许应用通过任何已关联的 Google 账号访问 Orkut。</string>\n    <string name=\"permission_service_notebook_description\">允许应用通过任何已关联的 Google 账号访问 Google 笔记本。</string>\n    <string name=\"permission_service_notebook_label\">Google 笔记本</string>\n    <string name=\"permission_service_groups2_label\">Google 网上论坛</string>\n    <string name=\"permission_service_groups2_description\">允许应用通过任何已关联的 Google 账号访问 Google 网上论坛。</string>\n    <string name=\"permission_service_youtube_label\">YouTube</string>\n    <string name=\"permission_service_wise_label\">Google 表格</string>\n    <string name=\"permission_service_wifi_label\">Google Wi-Fi</string>\n    <string name=\"permission_service_talk_label\">Google Talk</string>\n    <string name=\"permission_service_print_label\">Google 图书搜索</string>\n    <string name=\"permission_service_print_description\">允许应用通过任何已关联的 Google 账号访问 Google 图书搜索。</string>\n    <string name=\"permission_service_orkut_label\">Orkut</string>\n    <string name=\"permission_service_dodgeball_label\">Dodgeball</string>\n    <string name=\"permission_service_gbase_label\">Google Base</string>\n    <string name=\"permission_service_grandcentral_label\">Google 语音</string>\n    <string name=\"permission_service_adsense_label\">AdSense</string>\n    <string name=\"permission_service_adwords_label\">Adwords</string>\n    <string name=\"permission_service_ah_label\">Google App Engine</string>\n    <string name=\"permission_service_blogger_label\">Blogger</string>\n    <string name=\"permission_service_health_label\">Google 健康</string>\n    <string name=\"permission_service_health_description\">允许应用通过任何已关联的 Google 账号访问 Google Health。</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube\">管理您的 YouTube 账号</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtubepartner\">查看并管理您在 YouTube 上的资产和相关内容</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.readonly\">查看您的 YouTube 账号</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.upload\">管理您的 YouTube 视频</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics.readonly\">查看您 YouTube 内容的分析报告</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics_monetary.readonly\">查看您 YouTube 内容的收入报告</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.profile\">查看您账号的基本内容</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.email\">查看您的邮件地址</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_urlshortener\">管理您的 goo.gl 短网址</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue\">管理您的任务</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks\">管理您的任务</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks.readonly\">查看您的任务</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gcm_for_chrome\">Chrome 的消息推送</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan\">管理您的 GAN 数据</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan.readonly\">查看您的 GAN 数据</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_games\">从 Google Play 游戏获取资料的权限。</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase.readonly\">查看您的 Freebase 账号</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase\">用您的账号登录到 Freebase</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_books\">管理您的图书</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar\">管理您的日历</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar.readonly\">查看您的日历</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_cloudprint\">查看并管理您的 Google 云端打印数据</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute.readonly\">查看您的 Google Compute Engine 资源</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute\">查看并管理您的 Google Compute Engine 资源</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_activity\">查看您在 Google 应用中的活动历史</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense.readonly\">查看您的 AdSense 数据</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense\">查看并管理您的 AdSense 数据</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics.readonly\">查看您的 Google Analytics 数据</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics\">查看并管理您的 Google Analytics 数据</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_androidpublisher\">访问 Google Play Android 开发者的权限</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller.readonly\">查看您的 Ad Exchange 数据</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller\">查看并管理您的 Ad Exchange 数据</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger.readonly\">查看您的 Blogger 账号</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger\">管理您的 Blogger 账号</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery.readonly\">查看您在 Google BigQuery 上的数据</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery\">查看并管理您在 Google BigQuery 上的数据</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_write\">管理您 Google 云存储中的数据</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_only\">查看您 Google 云存储中的数据</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.full_control\">管理您 Google 云存储中的数据与权限</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.apps.readonly\">查看您的 Google 云端硬盘应用</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.file\">查看并管理此应用在您 Google 云端硬盘中打开 / 创建的文件</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.metadata.readonly\">查看您 Google 云端硬盘中文件和档案的元数据</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.readonly\">查看您 Google 云端硬盘中的文件和档案</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive\">查看并管理您 Google 云端硬盘中的文件和档案</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables\">管理您的 Fusion Tables</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables.readonly\">\"查看您的 Fusion Tables\"</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsensehost\">查看并管理您的 AdSense 服务资料和关联账号</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.licensing\">License Manager API 的读写权限。</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.me\">知道您在 Google 是谁</string>\n    <string name=\"permission_service_jotspot_description\">允许应用通过任何已关联的 Google 账号访问 JotSpot。</string>\n    <string name=\"permission_service_knol_description\">允许应用通过任何已关联的 Google 账号访问 Knol。</string>\n    <string name=\"permission_service_ig_label\">iGoogle</string>\n    <string name=\"permission_service_ig_description\">允许应用通过任何已关联的 Google 账号访问 iGoogle。</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.appdata\">允许访问应用数据文件夹</string>\n    <string name=\"permission_service_sierra_label\">Google Checkout账号</string>\n    <string name=\"permission_service_sierraqa_label\">Google Checkout QA账号</string>\n    <string name=\"permission_service_sierrasandbox_label\">Google Checkout沙盒账号</string>\n    <string name=\"permission_service_sierrasandbox_description\">允许应用通过任何已关联的 Google 账号访问 Google Checkout 沙盒账号。</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.buyer\">管理你的 Ad Exchange 买方账号设置</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.migration\">Groups Migration API的读写权限。</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.settings\">查看和管理 Google 应用组的设置</string>\n    <string name=\"permission_service_sitemaps_label\">Google Webmaster工具</string>\n    <string name=\"permission_service_sierra_description\">允许应用通过任何已关联的 Google 帐号访问 Google Checkout 账号。</string>\n    <string name=\"permission_service_sierraqa_description\">允许应用通过任何已关联的 Google 账号访问 Google Checkout QA账号。</string>\n    <string name=\"permission_service_sitemaps_description\">允许应用通过任何已关联的 Google 账号访问 Google Webmaster 工具。</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appengine.admin\">应用引擎管理范围。</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine\">查看和管理您的 Google Maps Engine 数据</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.scripts\">修改你的谷歌应用脚本的行为</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.readonly\">读取所有资源及其元数据—无需写操作。</string>\n    <string name=\"permission_service_jotspot_label\">JotSpot</string>\n    <string name=\"permission_service_knol_label\">Knol</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order\">适用于经销商管理员和用户在API沙箱中测试时的读/写访问，或直接调用API操作时的读写访问。</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps_reporting_audit.readonly\">访问Admin Audit API只读权限</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_dfareporting\">查看和管理广告主点击报告</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.compose\">创建、读取、更新和删除草稿。发送邮件和草稿。</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.best\">管理您的最佳可用位置和位置历史记录</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.city\">管理您的城市级位置和位置历史记录</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.best\">管理您的最佳可用位置</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.city\">管理您的城市级位置</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine.readonly\">查看您的 Google Maps Engine 数据</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mobilemaps.firstparty\">查看和管理您的 Google Maps 以获得移动体验</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut\">管理您的Orkut活动</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut.readonly\">查看您的Orkut活动</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tracks\">Google Maps Tracks API，此权限允许读写您的计划数据。</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue.consumer\">使用任务队列中的任务</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification\">管理您控制的网站和域名列表</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification.verify_only\">使用 Google 管理您的新网站验证</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_shoppingapi\">查看您的产品数据</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_prediction\">在Google Prediction API中管理您的数据</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.login\">知道你的名字、基本信息和你在 Google+ 上的联系人列表</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.modify\">除立即和永久性删除信息以外的读/写权限（不含回收站）。</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_structuredcontent\">Shopping Content API 的读/写权限。</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_glass.timeline\">Glass 时间轴权限</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order.readonly\">在整体读取 / 写入 Oauth 范围之外，在获取用户资料时还使用只读 Oauth 范围。</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appstate\">应用状态服务的运行权限。</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate.readonly\">查看您的 Google Coordinate jobs</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate\">查看并管理您的 Google Maps Coordinate jobs</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.install\">让用户允许安装应用的特殊权限</string>\n    <string name=\"perm_activity_recognition_label\">活动识别</string>\n    <string name=\"perm_activity_recognition_description\">允许一款应用从 Google 接收你活动等级的定期更新，例如你是否在走路、驾车、骑车或停止不动。</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-zh-rCN/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <plurals name=\"pref_unifiednlp_summary\">\n        <item quantity=\"one\">已配置 <xliff:g example=\"1\">%1$d</xliff:g> 个后端</item>\n        <item quantity=\"other\">已配置 <xliff:g example=\"3\">%1$d</xliff:g> 个后端</item>\n    </plurals>\n    <plurals name=\"gcm_registered_apps_counter\">\n        <item quantity=\"one\"><xliff:g example=\"1\">%1$d</xliff:g> 个应用已注册</item>\n        <item quantity=\"other\"><xliff:g example=\"123\">%1$d</xliff:g> 个应用已注册</item>\n    </plurals>\n    <plurals name=\"cond_perm_summary\">\n        <item quantity=\"other\">microG 服务缺少正常工作所需的权限。</item>\n    </plurals>\n    <plurals name=\"cond_perm_action\">\n        <item quantity=\"other\">请求缺少的权限</item>\n    </plurals>\n</resources>"
  },
  {
    "path": "play-services-core/src/main/res/values-zh-rCN/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=\"auth_sign_in\">登录</string>\n    <string name=\"auth_connecting\">\"正在建立到 Google 服务器的连接以供您登录。\n\n这需要几秒钟时间。\"</string>\n    <string name=\"no_network_error_desc\">\"您未连接到互联网。\n\n这可能是暂时性的问题，或者是您的 Android 设备不能使用数据服务。请在连接到移动网络或 Wi-Fi 网络后重试。\"</string>\n    <string name=\"sorry\">抱歉…</string>\n    <string name=\"allow\">允许</string>\n    <string name=\"deny\">拒绝</string>\n    <string name=\"auth_notification_title\">需要认证</string>\n    <string name=\"perm_c2dm_send_label\">向其他应用发送 C2DM 消息</string>\n    <string name=\"service_name_mcs\">Google 云端消息推送</string>\n    <string name=\"games_title\">Google Play 游戏</string>\n    <string name=\"games_info_content\">要使用 Play 游戏，您需要安装“Google Play 游戏”应用。您的应用在 Play 游戏未安装时也许能继续运行，但也可能发生异常。</string>\n    <string name=\"pick_place_title\">选择一个地点</string>\n    <string name=\"pick_place_desc\">现在无法选择地点。</string>\n    <string name=\"place_picker_select_title\">选择此地点</string>\n    <string name=\"place_picker_nearby_places\">附近的地点</string>\n    <string name=\"lacking_permission_toast\">microG 服务：缺少<xliff:g example=\"have full network acccess\">%1$s</xliff:g>权限</string>\n    <string name=\"network_type_mobile\">移动网络</string>\n    <string name=\"network_type_roaming\">漫游</string>\n    <string name=\"network_type_other\">其他网络</string>\n    <string name=\"self_check_cat_fake_sig\">签名伪装支持</string>\n    <string name=\"self_check_cat_gms_packages\">已安装的应用</string>\n    <string name=\"self_check_cat_system\">系统</string>\n    <string name=\"self_check_name_fake_sig_perm\">系统支持签名伪装：</string>\n    <string name=\"self_check_resolution_fake_sig_perm\">您的 ROM 并不自带签名伪装支持。您仍可以利用 Xposed 或刷入支持的 ROM 来伪装签名。请查阅文档以了解哪些 ROM 自带伪装支持，以及如何在不支持的 ROM 上继续使用 microG。</string>\n    <string name=\"self_check_name_perm_granted\">系统已授予签名伪装权限：</string>\n    <string name=\"self_check_resolution_perm_granted\">这表明您的系统极有可能支持签名伪装，但仍需要一些步骤来激活它。请查阅文档以了解后续步骤。</string>\n    <string name=\"self_check_pkg_gms\">microG 服务</string>\n    <string name=\"self_check_pkg_vending\">microG 伴侣/Play商店</string>\n    <string name=\"self_check_pkg_gsf\">microG 服务框架</string>\n    <string name=\"self_check_name_battery_optimizations\">停用电池优化：</string>\n    <string name=\"self_check_resolution_battery_optimizations\">点击停用电池优化。否则可能导致程序工作异常。</string>\n    <string name=\"prefcat_about\">关于</string>\n    <string name=\"prefcat_components\">组件</string>\n    <string name=\"prefcat_configuration\">配置</string>\n    <string name=\"prefcat_location_service\">位置服务</string>\n    <string name=\"prefcat_services\">服务</string>\n    <string name=\"prefcat_test\">测试</string>\n    <string name=\"cond_gcm_bat_title\">电池优化已启用</string>\n    <string name=\"cond_gcm_bat_summary\">您在电池优化生效的情况下启用了消息推送。为保证消息正常推送，您需要停用本应用的电池优化。</string>\n    <string name=\"cond_gcm_bat_action\">忽略优化</string>\n    <string name=\"cond_perm_title\">缺少权限</string>\n    <string name=\"prefs_account\">账号设置</string>\n    <string name=\"prefs_account_privacy\">个人资料与隐私</string>\n    <string name=\"prefs_account_security\">登录与安全</string>\n    <string name=\"pref_auth_trust_google_summary\">禁用后，应用在向 Google 请求验证前需要得到您的同意。部分程序可能会因此无法使用 Google 账号。</string>\n    <string name=\"checkin_not_registered\">未注册</string>\n    <string name=\"checkin_last_registration\">上次注册：<xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gms_settings_name\">microG 设置</string>\n    <string name=\"gms_settings_summary\">设置 microG 服务。</string>\n    <string name=\"just_a_sec\">请稍等…</string>\n    <string name=\"ask_permission_tos\">继续则代表您同意此应用和 Google 遵循各自的服务条款和隐私政策使用您的个人信息。</string>\n    <string name=\"ask_scope_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> 想要：</string>\n    <string name=\"ask_service_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> 想要使用：</string>\n    <string name=\"account_manager_title\">Google 账号管理员</string>\n    <string name=\"auth_before_connect\">\"您设备上的某个应用正尝试登录一个 Google 账号。\n\n若这是您有意而为，点击<b>登录</b>以连接到 Google 的登录页面；否则点击<b>取消</b>以返回到弹出此页面的应用。\"</string>\n    <string name=\"auth_finalize\">\"您的设备正在与 Google 联系以将您的信息存入账号。\n\n这可能需要几分钟。\"</string>\n    <string name=\"auth_general_error_desc\">\"与 Google 服务器通信时发生问题。\n\n请稍后重试。\"</string>\n    <string name=\"auth_notification_content\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> 需要您的授权以使用 Google 账号。</string>\n    <string name=\"perm_c2dm_receive_label\">接收 C2DM 消息</string>\n    <string name=\"perm_status_broadcast_label\">接收内部状态广播</string>\n    <string name=\"perm_gtalk_svc_label\">从 Google 服务器交换信息并接收同步通知</string>\n    <string name=\"service_name_checkin\">向 Google 注册设备</string>\n    <string name=\"perm_provision_description\">允许应用在无用户交互的情况下设置 microG 服务</string>\n    <string name=\"games_info_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> 想要使用 Play 游戏</string>\n    <string name=\"self_check_name_system_spoofs\">系统签名伪装：</string>\n    <string name=\"self_check_resolution_system_spoofs\">请查阅文档以了解所需步骤。</string>\n    <string name=\"self_check_name_app_installed\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> 已安装： </string>\n    <string name=\"self_check_resolution_app_installed\">安装 <xliff:g example=\"F-Droid\">%1$s</xliff:g> 或与之兼容的应用。请查阅文档以了解有哪些兼容应用。</string>\n    <string name=\"self_check_name_correct_sig\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> 包含正确签名： </string>\n    <string name=\"self_check_resolution_correct_sig\">已安装的 <xliff:g example=\"F-Droid\">%1$s</xliff:g> 不兼容，或者您未对其启用签名伪装。请查阅文档以了解兼容的应用或 ROM。</string>\n    <string name=\"pref_auth_visible_title\">允许应用寻找 Google 账号</string>\n    <string name=\"pref_auth_visible_summary\">启用后，您设备上的所有应用将可以看到与您 Google 账号关联的电子邮件地址，而无需您的许可。</string>\n    <string name=\"pref_auth_two_step_verification_title\">允许接收 Google 二次验证信息</string>\n    <string name=\"pref_auth_two_step_verification_summary\">启用后，设备可以接收来自 Google 的两步验证通知（需启用云端消息推送并保持连接）。</string>\n    <string name=\"pref_checkin_enable_summary\">将您的设备注册到 Google 服务，并创建唯一的设备识别码。microG 将去除注册信息中您 Google 账户名以外的用于识别的信息。</string>\n    <string name=\"checkin_enable_switch\">注册设备</string>\n    <string name=\"pref_info_status\">状态</string>\n    <string name=\"pref_more_settings\">更多</string>\n    <string name=\"pref_add_account_title\">账号</string>\n    <string name=\"pref_add_account_summary\">添加 Google 账号</string>\n    <string name=\"pref_gcm_enable_mcs_summary\">Google 云端消息推送（GCM）是由众多第三方应用选用的消息推送提供者。使用之前您需要先向 Google 注册该设备。</string>\n    <string name=\"pref_gcm_heartbeat_title\">云端消息心跳间隔</string>\n    <string name=\"pref_gcm_heartbeat_summary\">系统向 Google 服务器发送心跳包的间隔秒数。延长该间隔将减少电量消耗，但可能导致推送延迟。\\n已废弃，将在未来版本被取代。</string>\n    <string name=\"pref_gcm_apps_title\">正使用云端消息推送的应用</string>\n    <string name=\"pref_gcm_apps_summary\">已经注册使用云端消息推送的应用列表。</string>\n    <string name=\"pref_gcm_confirm_new_apps_title\">确认新应用</string>\n    <string name=\"pref_gcm_confirm_new_apps_summary\">在应用注册使用消息推送之前询问您</string>\n    <string name=\"pref_gcm_ping_interval\">Ping 间隔：<xliff:g example=\"10 minutes\">%1$s</xliff:g></string>\n    <string name=\"pref_about_title\">关于 microG 服务</string>\n    <string name=\"pref_about_summary\">版本信息与使用的库</string>\n    <string name=\"gcm_app_error_unregistering\">取消注册时出错</string>\n    <string name=\"gcm_app_not_installed_anymore\">已被卸载</string>\n    <string name=\"gcm_unregister_app\">取消注册</string>\n    <string name=\"gcm_not_registered\">未注册</string>\n    <string name=\"gcm_no_message_yet\">尚未收到任何消息</string>\n    <string name=\"gcm_last_message_at\">最后收到消息：<xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_registered\">已注册</string>\n    <string name=\"gcm_registered_since\">自<xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g>起注册</string>\n    <string name=\"gcm_unregister_confirm_title\">取消注册 <xliff:g example=\"F-Droid\">%1$s</xliff:g>？</string>\n    <string name=\"gcm_unregister_confirm_message\">有些应用并不会自动重新注册，也可能不向您提供重新注册的选项。取消注册后这些应用可能出现异常。\\n是否继续？</string>\n    <string name=\"gcm_unregister_after_deny_message\">您拒绝了一个已经注册过的应用去注册接受推送通知。\\n您是否想现在取消它的注册，使其今后不再接收消息推送？</string>\n    <string name=\"gcm_messages_counter\">已接收 <xliff:g example=\"123\">%1$d</xliff:g> 条消息 (<xliff:g example=\"12345\">%2$d</xliff:g> 字节)</string>\n    <string name=\"gcm_network_state_disconnected\">已断开连接</string>\n    <string name=\"gcm_network_state_connected\">上次连接：<xliff:g example=\"2 hours ago\">%1$s</xliff:g></string>\n    <string name=\"gcm_enable_switch\">接收通知推送</string>\n    <string name=\"gcm_allow_app_popup\">允许 <xliff:g example=\"F-Droid\">%1$s</xliff:g> 注册通知推送？</string>\n    <string name=\"pref_push_app_allow_register_title\">允许注册</string>\n    <string name=\"pref_push_app_allow_register_summary\">允许该应用注册通知推送。</string>\n    <string name=\"pref_push_app_wake_for_delivery_title\">推送时启动应用</string>\n    <string name=\"pref_push_app_wake_for_delivery_summary\">适时在后台唤起应用以接收推送消息。</string>\n    <string name=\"prefcat_push_apps_title\">使用通知推送的应用</string>\n    <string name=\"prefcat_push_apps_registered_title\">已注册的应用</string>\n    <string name=\"prefcat_push_apps_unregistered_title\">已取消注册的应用</string>\n    <string name=\"prefcat_push_networks_title\">接收推送时使用的网络</string>\n    <string name=\"safetynet_enable_switch\">允许设备认证</string>\n    <string name=\"pref_recaptcha_test_title\">测试 ReCAPTCHA</string>\n    <string name=\"pref_test_summary_passed\">所有测试已通过</string>\n    <string name=\"pref_test_summary_failed\">失败：%s</string>\n    <string name=\"pref_test_summary_warn\">警告：%s</string>\n    <string name=\"pref_test_summary_running\">正在运行…</string>\n    <string name=\"pref_droidguard_operation_mode\">运作模式</string>\n    <string name=\"profile_name_native\">本地</string>\n    <string name=\"profile_name_real\">真实</string>\n    <string name=\"profile_name_user\">自定义：%s</string>\n    <string name=\"profile_name_auto\">自动：%s</string>\n    <string name=\"profile_name_system\">系统：%s</string>\n    <string name=\"pref_device_attestation_app_allow_requests_title\">允许请求</string>\n    <string name=\"pref_device_attestation_app_allow_requests_summary\">允许应用程序请求设备身份验证</string>\n    <string name=\"pref_safetynet_test_title\">\"测试 SafetyNet 认证\"</string>\n    <string name=\"safetynet_intro\">\"Google SafetyNet 是一套设备认证系统，旨在确认设备具有适当安全性，并与 Android CTS 兼容。某些应用会出于安全考虑或是防篡改目的而使用 SafetyNet。\n\nmicroG GmsCore 内置一套自由的 SafetyNet 实现，但是官方服务器要求 SafetyNet 请求使用其专有的 DroidGuard 系统签名。\"</string>\n    <string name=\"prefcat_google_services\">Google 服务</string>\n    <string name=\"perm_extended_access_label\">额外使用 Google 服务</string>\n    <string name=\"google_account_label\">Google</string>\n    <string name=\"network_type_wifi\">Wi-Fi</string>\n    <string name=\"place_picker_location_lat_lng\">(%1$.7f, %2$.7f)</string>\n    <string name=\"perm_provision_label\">预配置 microG 服务</string>\n    <string name=\"gms_app_name\">microG 服务</string>\n    <string name=\"pref_auth_trust_google_title\">允许 Google 向应用提供验证</string>\n    <string name=\"pref_device_registration_import_custom_profile_title\">导入自定义配置信息</string>\n    <string name=\"pref_device_registration_serial_title\">序列号</string>\n    <string name=\"pref_device_registration_import_custom_profile_summary\">从文件导入自定义的设备配置信息</string>\n    <string name=\"pref_device_registration_select_profile_title\">选择配置信息</string>\n    <string name=\"pref_device_registration_device_profile_category\">设备配置信息</string>\n    <string name=\"prefcat_safetynet_apps_title\">使用 SafetyNet 的应用</string>\n    <string name=\"prefcat_device_attestation_apps_title\">使用设备认证的应用</string>\n    <string name=\"menu_clear_recent_requests\">清除近期的 SafetyNet 请求</string>\n    <string name=\"safetynet_last_run_at\">最近使用于<xliff:g example=\"昨天 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"pref_safetynet_recent_eval_type\">评估类型</string>\n    <string name=\"pref_safetynet_recent_response_status\">响应状态</string>\n    <string name=\"pref_safetynet_recent_cat_response\">响应数据</string>\n    <string name=\"pref_safetynet_recent_cat_request\">请求数据</string>\n    <string name=\"pref_safetynet_recent_nonce\">十六进制 Nonce</string>\n    <string name=\"pref_safetynet_recent_request_time\">请求时间</string>\n    <string name=\"pref_safetynet_recent_request_type\">请求类型</string>\n    <string name=\"pref_safetynet_recent_cat_basic\">基础数据</string>\n    <string name=\"pref_safetynet_recent_token\">令牌</string>\n    <string name=\"pref_safetynet_recent_copy_json\">复制 JSON JWS 数据</string>\n    <string name=\"pref_safetynet_recent_advice\">建议</string>\n    <string name=\"pref_safetynet_test_not_completed\">尚未完成</string>\n    <string name=\"pref_safetynet_test_no_result\">无结果</string>\n    <string name=\"pref_safetynet_test_invalid_json\">无效 JSON</string>\n    <string name=\"pref_safetynet_test_cts_failed\">未通过 CTS 测试</string>\n    <string name=\"pref_recaptcha_enterprise_test_title\">进行 reCAPTCHA Enterprise 测试</string>\n    <string name=\"pref_safetynet_recent_copied\">已复制到剪贴板！</string>\n    <string name=\"pref_safetynet_test_integrity_cts_passed\">已通过完整性和 CTS 测试</string>\n    <string name=\"pref_safetynet_test_integrity_failed\">未通过完整性测试</string>\n    <string name=\"pref_safetynet_recent_uses\">最近使用</string>\n    <string name=\"signin_picker_title\">选择一个账号</string>\n    <string name=\"signin_picker_add_account_label\">添加另一个账号</string>\n    <string name=\"pref_auth_include_android_id_summary\">禁用此项后，验证请求将不包含设备注册信息，以允许您在未获认证的设备上登录，但可能有未知后果。</string>\n    <string name=\"signin_picker_subtitle\">以继续使用“<xliff:g example=\"F-Droid\">%1$s</xliff:g>”</string>\n    <string name=\"signin_confirm_title\">允许将您登录到“<xliff:g example=\"F-Droid\">%1$s</xliff:g>”</string>\n    <string name=\"pref_vending_license_enable_summary\">一些应用需要验证您是否已在 Google Play 商店购买。收到相应请求时，microG 可以从 Google 处下载您的购买凭证。若禁用此设置，或未添加 Google 账号，授权验证请求将被忽略。</string>\n    <string name=\"pref_auth_include_android_id_title\">验证时发送设备信息</string>\n    <string name=\"push_notifications_summary_automatic\">已开启 / 自动：%s</string>\n    <string name=\"push_notifications_summary_off\">已关闭</string>\n    <string name=\"push_notifications_summary_manual\">已开启 / 手动：%s</string>\n    <string name=\"push_notifications_summary_values_seconds\">%s 秒</string>\n    <string name=\"push_notifications_summary_values_minutes\">%s 分钟</string>\n    <string name=\"pref_vending_licensing_enable_switch\">响应授权验证请求</string>\n    <string name=\"pref_vending_summary_licensing_on\">授权验证开启</string>\n    <string name=\"pref_vending_summary_licensing_off\">授权验证关闭</string>\n    <string name=\"signin_subtext_policy_privacy\">隐私政策</string>\n    <string name=\"signin_subtext_policy_terms\">服务条款</string>\n    <string name=\"signin_subtext_sharing\">若继续，microG 将向“<xliff:g example=\"F-Droid\">%1$s</xliff:g>”共享您 Google 账号的姓名、电子邮件地址和个人资料照片。</string>\n    <string name=\"signin_subtext_policy\">使用此应用前，请先阅读%1$s和%2$s。</string>\n    <string name=\"signin_confirm_button_text\">允许并共享</string>\n    <string name=\"feedback_disabled\">反馈功能不可用</string>\n    <string name=\"backup_disabled\">备份功能不可用</string>\n    <string name=\"pref_vending_billing_enable_switch\">使用 Google 应用内购买服务</string>\n    <string name=\"pref_vending_billing_enable_summary\">启用后，一些应用可以通过 Google 应用内购买服务完成应用内服务购买或订阅。</string>\n    <string name=\"perm_car_speed_label\">车辆速度</string>\n    <string name=\"perm_car_speed_description\">访问您的车速</string>\n    <string name=\"perm_car_info_label\">车辆信息</string>\n    <string name=\"perm_car_info_description\">访问您的车辆信息</string>\n    <string name=\"perm_car_fuel_label\">车辆燃油油位</string>\n    <string name=\"perm_car_fuel_description\">访问您的汽车的燃油油位信息</string>\n    <string name=\"perm_car_mileage_label\">车辆行驶里程</string>\n    <string name=\"perm_car_mileage_description\">访问您的车辆里程信息</string>\n    <string name=\"perm_car_vendor_extension_label\">车辆经销商频道</string>\n    <string name=\"perm_car_vendor_extension_description\">允许与车辆经销商交换车辆特定信息</string>\n    <string name=\"pref_auth_strip_device_name_title\">剥离设备名称以进行身份验证</string>\n    <string name=\"pref_auth_strip_device_name_summary\">启用后，身份验证请求将不包括设备名称，这可能允许未经授权的设备登录，但可能会产生不可预见的后果。</string>\n    <string name=\"pref_accounts_title\">Google 账号</string>\n    <string name=\"prefcat_accounts_settings_title\">设置</string>\n    <string name=\"pref_vending_licensing_category\">Google Play 许可</string>\n    <string name=\"prefcat_accounts_current_accounts_title\">账号</string>\n    <string name=\"pref_vending_billing_category\">Google Play 结算系统</string>\n    <string name=\"pref_vending_billing_note_experimental\">此功能是实验性的，可能会导致资金损失。您已收到警告。</string>\n    <string name=\"pref_vending_billing_note_licensing\">某些应用程序可能还要求您启用许可证验证以验证您的购买。</string>\n    <string name=\"service_name_vending\">Play 商店服务</string>\n    <string name=\"pref_device_registration_android_id\">Android ID</string>\n    <string name=\"pref_droidguard_unsupported_summary\">此设备不支持 DroidGuard。SafetyNet 服务不可靠。</string>\n    <string name=\"pref_safetynet_recent_attestation_summary\">证明：%s</string>\n    <string name=\"pref_accounts_summary\">添加和管理 Google 账号</string>\n    <string name=\"perm_gsf_read_gservices_label\">读取Google服务配置</string>\n    <string name=\"service_name_snet\">Google SafetyNet</string>\n    <string name=\"service_name_device_attestation\">设备认证</string>\n    <string name=\"pref_safetynet_recent_recaptcha_summary\">ReCaptcha: %s</string>\n    <string name=\"pref_safetynet_recent_recaptcha_enterprise_summary\">ReCaptcha Enterprise: %s</string>\n    <string name=\"pref_game_accounts_title\">Google 游戏账号</string>\n    <string name=\"pref_auto_create_player\">允许注册Play 游戏账号</string>\n    <string name=\"pref_auto_create_player_intro\">在游戏游玩时，需要使用Play 游戏账号来进行登录并记录游戏相关功能，如成就、排行榜、存档等。禁用后，未绑定Play 游戏账号的Google 账号将不会自动注册，游戏因此无法登录游玩。</string>\n    <string name=\"pref_allow_upload_game_played\">允许上传游戏状态</string>\n    <string name=\"pref_allow_upload_game_played_summary\">禁用后，登录游戏后将不会报告游戏已游玩状态，部分游戏可能因此无法登录。</string>\n    <string name=\"pref_change_default_game_player\">更改游戏账号</string>\n    <string name=\"pref_change_default_game_player_summary\">更改游戏的默认登录帐户以及按游戏更改登录帐户。</string>\n    <string name=\"pref_delete_game_account_data\">删除Play 游戏数据</string>\n    <string name=\"pref_delete_game_account_data_summary\">删除Play 游戏帐号和所有数据以及删除单个游戏数据。</string>\n    <string name=\"games_state_description_signed_out\">已退出账号</string>\n    <string name=\"games_state_description_delete\">删除</string>\n    <string name=\"games_change_button_text\">更改</string>\n    <string name=\"games_change_default_account_section_title\">更改游戏的默认账号</string>\n    <string name=\"games_change_default_account_description\">默认账号：%1$s</string>\n    <string name=\"games_change_default_account_explanation\">系统使用此账号自动登录游戏，以及保存您的游戏进度和设置。更改默认账号或退出账号可能会重置您玩过的游戏的进度和设置。</string>\n    <string name=\"games_change_per_game_title\">更改具体游戏的账号</string>\n    <string name=\"games_change_per_game_description\">更改所选游戏的账号或退出账号可能会重置游戏进度和设置。</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_title\">请为新的默认账号选择一个选项</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_description\">当前的默认账号：%1$s</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_title\">仅更改新游戏的默认账号</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_only_for_new_games_description\">您将仍然可以查看在玩过的游戏中的进度和设置。但是，更改账号前后的进度会在原账号和新账号之间分开存储。</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_title\">更改所有游戏的默认账号</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_for_all_games_description\">您可能无法再访问玩过的游戏的进度和设置。系统会重启游戏以应用您所做的更改。</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_title\">从所有游戏中退出该账号</string>\n    <string name=\"games_change_default_account_for_all_games_dialog_option_sign_out_of_all_games_description\">您可能无法再访问玩过的游戏的进度和设置。系统会重启游戏以应用您所做的更改。</string>\n    <string name=\"games_change_per_game_dialog_title\">请为此游戏选择一个选项</string>\n    <string name=\"games_change_per_game_dialog_description\">更改账号或退出账号可能会重置游戏进度和设置</string>\n    <string name=\"games_change_per_game_dialog_option_use_player\">使用 %1$s</string>\n    <string name=\"games_change_per_game_dialog_option_use_player_snackbar_success_message\">您将使用 %1$s 登录此游戏</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out\">退出账号</string>\n    <string name=\"games_change_per_game_dialog_option_sign_out_snackbar_success_message\">您现在已从此游戏中退出账号</string>\n    <string name=\"games_change_sign_out_of_all_games_snackbar_success_message\">您现在已从所有游戏中退出账号</string>\n    <string name=\"games_change_default_account_for_all_games_snackbar_success_message\">您将使用 %1$s 登录所有游戏</string>\n    <string name=\"games_change_default_account_for_new_games_snackbar_success_message\">您将使用 %1$s 登录新游戏</string>\n    <string name=\"games_popup_signin_welcome\">您好，%1$s</string>\n    <string name=\"games_account_display_content\">当前账号: %1$s</string>\n    <string name=\"games_delete_profile_header\">删除 Play 游戏账号和所有数据</string>\n    <string name=\"games_delete_profile_explanation\">永久删除您的 Google Play 游戏账号、经验值和所有玩家资料数据。您在所玩游戏中的得分、进度（游戏存档）和设置也可能会随之一并删除。</string>\n    <string name=\"games_delete_profile_button\">永久删除</string>\n    <string name=\"games_delete_game_data_header\">删除个别游戏数据</string>\n    <string name=\"games_delete_game_data_explanation\">您可以永久删除您在 Google Play 游戏中玩过的某个游戏的数据。您在所选游戏中的得分、进度（游戏存档）和设置也会随之一并删除。</string>\n    <string name=\"games_delete_profile_dialog_title\">确定要删除此账号吗？</string>\n    <string name=\"games_delete_profile_explanation_with_gamer_name\">永久删除玩家名称&lt;b&gt;%1$s&lt;/b&gt; (&lt;b&gt;%2$s&lt;/b&gt;) 所对应的 Google Play 游戏账号、经验值和所有玩家资料数据。您在所玩游戏中的得分、进度（游戏存档）和设置也可能会随之一并删除。</string>\n    <string name=\"games_delete_profile_dialog_message\">此操作无法撤消。</string>\n    <string name=\"games_delete_profile_fail\">无法删除您的玩家资料，请稍后重试。</string>\n    <string name=\"games_delete_game_data_confirm_dialog_title\">删除“%1$s”的数据</string>\n    <string name=\"games_delete_game_data_confirm_dialog_message\">永久删除您的“%1$s”数据后，您在 Google Play 游戏中的得分、进度（游戏存档）和游戏设置都会遭到移除。</string>\n    <string name=\"games_achievement_list_title\">成就</string>\n    <string name=\"games_achievements_empty_text\">此游戏没有成就</string>\n    <string name=\"games_api_access_denied\">此设备上没有可访问 Games API 的账号</string>\n    <string name=\"games_achievement_locked_content_description\">未解锁</string>\n    <string name=\"games_achievement_unlocked_content_description\">已解锁</string>\n    <string name=\"games_achievement_extra_text\">%1$s XP</string>\n    <string name=\"games_leaderboard_empty_text\">此游戏没有排行榜</string>\n    <string name=\"games_leaderboard_score_empty_text\">不可思议！居然还没有人公开创下这个游戏的高分记录。</string>\n    <string name=\"games_leaderboard_list_title\">排行榜</string>\n    <string name=\"games_leaderboards_score_label\">得分：%1$s</string>\n    <string name=\"games_snapshot_empty_text\">目前尚未保存任何游戏存档</string>\n    <string name=\"games_snapshot_choose_btn_text\">选择</string>\n    <string name=\"games_snapshot_delete_btn_text\">删除</string>\n    <string name=\"games_delete_snapshot_dialog_title\">删除游戏存档</string>\n    <string name=\"games_delete_snapshot_dialog_message\">确定要删除这个游戏存档吗?</string>\n    <string name=\"games_delete_snapshot_dialog_cancel\">取消</string>\n    <string name=\"games_delete_snapshot_dialog_ok\">确定</string>\n    <string name=\"games_delete_snapshot_error\">删除失败，请稍后重试</string>\n    <string name=\"family_management_title\">家庭</string>\n    <string name=\"family_management_retry\">重试</string>\n    <string name=\"family_management_load_error\">内容加载失败</string>\n    <string name=\"family_management_toolbar_back\">返回</string>\n    <string name=\"family_management_toolbar_more\">更多</string>\n    <string name=\"family_management_exit_family_group\">退出家庭群组</string>\n    <string name=\"family_management_delete_family_group\">删除家庭群组</string>\n    <string name=\"family_management_delete_family_password_title\">确认密码以删除家庭群组</string>\n    <string name=\"family_management_leave_family_password_title\">确认密码以退出家庭群组</string>\n    <string name=\"family_management_remove_member_password_title\">确认密码以移除“%s”</string>\n    <string name=\"family_management_invite_family_member\">邀请家庭成员</string>\n    <string name=\"family_management_invite_slots_left\">剩余%1$d个邀请名额</string>\n    <string name=\"family_management_cancel_invite\">取消邀请</string>\n    <string name=\"family_management_cancel_invite_success\">取消邀请成功</string>\n    <string name=\"family_management_cancel_invite_error\">取消邀请失败，请重试。</string>\n    <string name=\"family_management_remove_member\">移除成员</string>\n    <string name=\"family_management_member_removed_success\">%s已从您的家庭群组中移除</string>\n    <string name=\"family_management_member_remove_failed\">移除%s失败，请重试。</string>\n    <string name=\"family_management_leave_family_error_message\">无法退出家庭群组。请重试。</string>\n    <string name=\"family_management_exist_group_success\">您已成功退出家庭群组…</string>\n    <string name=\"family_management_delete_group_success\">家庭群组已删除</string>\n    <string name=\"family_management_delete_group_failure\">删除家庭群组失败</string>\n    <string name=\"family_management_delete_group_cancel\">取消</string>\n    <string name=\"family_management_delete_group_confirm\">确认</string>\n    <string name=\"family_management_input_pwd\">请输入密码</string>\n    <string name=\"family_management_invite_sent_date_format\">邀请已于%s发送</string>\n    <string name=\"family_management_invite_send\">邀请已发送</string>\n    <string name=\"family_management_pwd_error\">密码错误，请重新输入</string>\n    <string name=\"credentials_assisted_cancel\">取消</string>\n    <string name=\"credentials_assisted_continue\">继续</string>\n    <string name=\"credentials_assisted_confirmation_header\">正在登录</string>\n    <string name=\"credentials_assisted_continue_as_user_button_label\">继续以 %1$s 的身份登录</string>\n    <string name=\"credentials_assisted_sign_back_title\">通过 Google 重新登录 %1$s</string>\n    <string name=\"credentials_assisted_signin_consent_header\">登录%1$s</string>\n    <string name=\"credentials_assisted_signin_consent\">如果您继续操作，Google 会将您的姓名、电子邮件地址和个人资料照片提供给 %1$s。请参阅 %1$s 的隐私权政策和服务条款。</string>\n    <string name=\"credentials_assisted_signin_description\">您可以在您的 Google 账号中管理“使用 Google 账号登录”功能。</string>\n    <string name=\"credentials_assisted_choose_account_label\">选择账号</string>\n    <string name=\"credentials_assisted_choose_account_subtitle\">以继续使用 %1$s</string>\n    <string name=\"credentials_assisted_choose_account_error_tips\">账号异常</string>\n    <string name=\"credentials_assisted_signin_button_text_long\">使用 Google 账号登录</string>\n    <string name=\"credentials_assisted_signin_add_account\">添加账号</string>\n    <string name=\"auth_package_override_request_title\">允许<b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> 访问 <xliff:g example=\"account@example.com\">%2$s</xliff:g>\\?</string>\n    <string name=\"auth_package_override_request_message\"><b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b>想以 <b><xliff:g example=\"F-Droid\">%2$s</xliff:g> by <xliff:g example=\"F-Droid Inc.\">%3$s</xliff:g></b>的身份访问您的账户，这可能会授予它访问您帐户的权限。</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_switch\">自动添加免费应用到库中</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_summary\">免费应用可能会检查它们是否曾经从 Google Play 被下载过。自动添加免费应用到你的账户库中可以让你一直通过当前对你可用的所有免费应用的检查。</string>\n    <string name=\"limited_services_app_name\">microG 有限服务</string>\n    <string name=\"limited_services_dialog_information_ack\">我理解</string>\n    <string name=\"limited_services_dialog_information\">你在使用 microG 有限服务版本。和通常的 microG 服务不同，此版本仅适用使用 microG 库的应用，而非在 Google Play 上的应用。 这意味着多数应用会忽略这些服务。</string>\n    <string name=\"auth_action_notification_channel_name\">Google 账户警告</string>\n    <string name=\"auth_action_notification_title\">需要账户操作</string>\n    <string name=\"auth_action_step_enable_checkin\">启用设备注册</string>\n    <string name=\"auth_action_step_enable_checkin_description\">你的设备需要至少向 Google 注册一次。\\n\\n在账户设置完成后，你可以停用 Google 设备注册。</string>\n    <string name=\"auth_action_step_enable_gcm\">启用云消息传递</string>\n    <string name=\"auth_action_step_enable_gcm_description\">账户设置完成后，你可以停用云消息传递。</string>\n    <string name=\"auth_action_step_allow_microg_gcm\">允许 microG 的云消息传递</string>\n    <string name=\"auth_action_step_allow_microg_gcm_description\">根据您的设置，microG 需要您的许可才能注册云消息传递。</string>\n    <string name=\"auth_action_step_enable_lockscreen\">配置安全屏幕锁</string>\n    <string name=\"auth_action_step_perform_content_description\">点击执行设置</string>\n    <string name=\"auth_action_step_completed_content_description\">步骤已完成</string>\n    <string name=\"auth_action_activity_finish\">完成</string>\n    <string name=\"auth_action_notification_channel_description\">在您某个 Google 账户需要额外设置才能使用或者不兼容 microG 时通知您。</string>\n    <string name=\"auth_action_activity_header\">完成 Google 账户设置</string>\n    <string name=\"auth_action_notification_content\">你的 Google 账户需要额外设置。</string>\n    <string name=\"auth_action_activity_explanation\">要在这台设备上使用你的 Google 账户 %s，请完成下列步骤。</string>\n    <string name=\"auth_action_step_enable_lockscreen_description\">您的 Google 账户受工作场所或教育机构管理。您的管理员决定设备在可以访问账户数据前需要设置安全屏幕锁。\\n\\n请设置一个密码、PIN或手势屏幕锁。</string>\n    <string name=\"auth_action_reauth_notification_title\">需要执行账号相关操作</string>\n    <string name=\"barcode_scanner_brand\">由 microG 代表“%1$s”扫描</string>\n    <string name=\"camera_permission_dialog_button\">确定</string>\n    <string name=\"camera_permission_dialog_message\">microG 服务需要访问设备的摄像头，才能为%1$s扫描二维码。\\n\\n若要启用该权限，请在“设置”中向 microG 服务授予相机权限。</string>\n    <string name=\"camera_permission_dialog_title\">需要相机使用权限</string>\n    <string name=\"pref_vending_asset_delivery_summary\">当使用 Play 资产分发的应用请求时下载额外的资产</string>\n    <string name=\"pref_vending_asset_delivery_category\">Google Play 资产分发</string>\n    <string name=\"pref_vending_asset_delivery_switch\">启用按需资产分发</string>\n    <string name=\"pref_vending_asset_device_sync_summary\">使用 Play 资产分发的应用会根据当前使用设备的信息下载额外的资产。</string>\n    <string name=\"pref_vending_asset_device_sync_switch\">启用设备信息同步</string>\n    <string name=\"pref_vending_split_install_switch\">启用按需下载应用的某些功能</string>\n    <string name=\"pref_vending_licensing_split_install_summary\">使用分包安装，应用会根据当前使用情况下载特定功能模块</string>\n    <string name=\"pref_vending_feature_delivery\">Google Play 功能传递</string>\n    <string name=\"pref_workprofile_create_account\">允许设置工作账户</string>\n    <string name=\"pref_workprofile_intro\">当为您的工作场所或教育机构设置工作资料时，设置程序可能会尝试连接到 Google 以允许下载应用到工作资料。</string>\n    <string name=\"service_name_work_profile\">工作资料</string>\n    <string name=\"pref_workprofile_disclaimer\">您应自行确保使用 microG 符合企业的规章政策。microG 是在尽最大努力基础上提供的，不能保证完全按预期运行。</string>\n    <string name=\"service_name_google_location_sharing\">Google 位置分享</string>\n    <string name=\"location_sharing_description\">管理来自此设备的 Google 应用和服务实时位置分享</string>\n    <string name=\"location_sharing_learn_more\">了解更多位置分享的信息</string>\n    <string name=\"location_sharing_switch_text\">使用位置分享</string>\n    <string name=\"location_sharing_turn_off_notify_hint\">如果关闭本设备的位置分享，接收位置分享的人不会被通知。</string>\n    <string name=\"location_sharing_off_previous_hint\">重新打开位置分享前，仅最后分享的位置可用。</string>\n    <string name=\"location_sharing_disabled\">此账户没有活跃的位置分享</string>\n    <string name=\"location_sharing_turn_on_hint\">开始从 Google 应用或服务分享位置后，可以从此处管理位置分享。\\n\\n要开始分享位置，请转到 Google 地图或 Family Link。</string>\n    <string name=\"location_sharing_turn_off_title\">关闭位置分享</string>\n    <string name=\"location_sharing_turn_off_hint\">你可能仍在从登录同一 Google 账户的其他设备或非 Google 应用分享你的位置。请在任何可能用到位置分享的地方检查位置分享设置。\\n\\n接收你位置分享的人会继续看到你最后分享的位置。</string>\n    <string name=\"location_sharing_turn_off_cancel\">保持开启</string>\n    <string name=\"location_sharing_turn_off_confirm\">关闭</string>\n    <string name=\"location_sharing_confirm_dialog_title\">启用位置分享</string>\n    <string name=\"location_sharing_confirm_dialog_text\">接收你位置分享的人始终可以看到：\\n· 你的名字和照片\\n·你设备近期的位置，即使你没在用 Google 服务\\n·你设备的电量以及是否在充电\\n·你的抵达和离开时间，如果位置分享接收人添加位置分享通知</string>\n    <string name=\"pref_app_install_settings_title\">商店安装设置</string>\n    <string name=\"pref_app_install_switch_title\">允许安装渠道应用</string>\n    <string name=\"pref_app_install_other_apps_note\">授权允许安装从其他渠道下载的应用程序。</string>\n    <string name=\"pref_app_install_permission_instruction\">为确保您的应用程序正常运行，请授权安装从其他来源下载的应用程序。该应用程序的某些服务需要必要的权限才能运行，拒绝权限可能会限制或禁用该应用程序的功能。</string>\n    <string name=\"prefcat_app_install_list_title\">授权渠道</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-zh-rTW/permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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  --><resources>\n    <string name=\"permission_service_all_label\">所有 Google 服務</string>\n    <string name=\"permission_service_all_description\">允許程式透過任何已關聯的 Google 帳戶來使用所有 Google 服務。</string>\n    <string name=\"permission_service_android_label\">Android 服務</string>\n    <string name=\"permission_service_android_description\">允許程式透過任何已關聯的 Google 帳戶來使用 Android 服務。</string>\n    <string name=\"permission_service_adsense_label\">AdSense</string>\n    <string name=\"permission_service_adsense_description\">允許程式透過任何已關聯的 Google 帳戶來使用 AdSense。</string>\n    <string name=\"permission_service_adwords_label\">AdWords</string>\n    <string name=\"permission_service_adwords_description\">允許程式透過任何已關聯的 Google 帳戶來使用 AdWords。</string>\n    <string name=\"permission_service_ah_label\">Google App Engine</string>\n    <string name=\"permission_service_ah_description\">允許程式透過任何已關聯的 Google 帳戶來使用 Google App Engine。</string>\n    <string name=\"permission_service_blogger_label\">Blogger</string>\n    <string name=\"permission_service_blogger_description\">允許程式透過任何已關聯的 Google 帳戶來使用 Blogger。</string>\n    <string name=\"permission_service_cl_label\">Google 日曆</string>\n    <string name=\"permission_service_cl_description\">允許程式透過任何已關聯的 Google 帳戶來使用 Google 日曆。</string>\n    <string name=\"permission_service_cp_label\">聯絡人</string>\n    <string name=\"permission_service_cp_description\">允許程式透過任何已關聯的 Google 帳戶來使用聯絡人。</string>\n    <string name=\"permission_service_dodgeball_label\">Dodgeball</string>\n    <string name=\"permission_service_dodgeball_description\">允許程式透過任何已關聯的 Google 帳戶來使用 Dodgeball。</string>\n    <string name=\"permission_service_finance_label\">Google 經濟</string>\n    <string name=\"permission_service_finance_description\">允許程式透過任何已關聯的 Google 帳戶來使用 Google 經濟。</string>\n    <string name=\"permission_service_gbase_label\">Google Base</string>\n    <string name=\"permission_service_gbase_description\">允許程式透過任何已關聯的 Google 帳戶來使用 Google Base。</string>\n    <string name=\"permission_service_grandcentral_label\">Google 語音</string>\n    <string name=\"permission_service_grandcentral_description\">允許程式透過任何已關聯的 Google 帳戶來使用 Google 語音。</string>\n    <string name=\"permission_service_groups2_label\">Google 網上論壇</string>\n    <string name=\"permission_service_groups2_description\">允許程式透過任何已關聯的 Google 帳戶來使用 Google 網上論壇。</string>\n    <string name=\"permission_service_health_label\">Google 健康</string>\n    <string name=\"permission_service_health_description\">允許程式透過任何已關聯的 Google 帳戶來使用 Google 健康。</string>\n    <string name=\"permission_service_ig_label\">iGoogle</string>\n    <string name=\"permission_service_ig_description\">允許程式透過任何已關聯的 Google 帳戶來使用 iGoogle。</string>\n    <string name=\"permission_service_jotspot_label\">JotSpot</string>\n    <string name=\"permission_service_jotspot_description\">允許程式透過任何已關聯的 Google 帳戶來使用 JotSpot。</string>\n    <string name=\"permission_service_knol_label\">Knol</string>\n    <string name=\"permission_service_knol_description\">允許程式透過任何已關聯的 Google 帳戶來使用 Knol。</string>\n    <string name=\"permission_service_lh2_label\">Picasa 網路相簿</string>\n    <string name=\"permission_service_lh2_description\">允許程式透過任何已關聯的 Google 帳戶來使用 Picasa 網路相簿。</string>\n    <string name=\"permission_service_local_label\">Google 地圖</string>\n    <string name=\"permission_service_local_description\">允許程式透過任何已關聯的 Google 帳戶來使用 Google 地圖。</string>\n    <string name=\"permission_service_mail_label\">Google 郵件</string>\n    <string name=\"permission_service_mail_description\">允許程式透過任何已關聯的 Google 帳戶來使用 Google 郵件。</string>\n    <string name=\"permission_service_news_label\">Google 新聞</string>\n    <string name=\"permission_service_news_description\">允許程式透過任何已關聯的 Google 帳戶來使用 Google 新聞。</string>\n    <string name=\"permission_service_notebook_label\">Google 筆記本</string>\n    <string name=\"permission_service_notebook_description\">允許程式透過任何已關聯的 Google 帳戶來使用 Google 筆記本。</string>\n    <string name=\"permission_service_orkut_label\">Orkut</string>\n    <string name=\"permission_service_orkut_description\">允許程式透過任何已關聯的 Google 帳戶來使用 Orkut。</string>\n    <string name=\"permission_service_print_label\">Google 圖書搜尋</string>\n    <string name=\"permission_service_print_description\">允許程式透過任何已關聯的 Google 帳戶來使用 Google 圖書搜尋。</string>\n    <string name=\"permission_service_sierra_label\">Google Checkout 帳戶</string>\n    <string name=\"permission_service_sierra_description\">允許程式透過任何已關聯的 Google 帳戶來使用 Google Checkout 帳戶。</string>\n    <string name=\"permission_service_sierraqa_label\">Google Checkout QA 帳戶</string>\n    <string name=\"permission_service_sierraqa_description\">允許程式透過任何已關聯的 Google 帳戶來使用 Google Checkout QA 帳戶。</string>\n    <string name=\"permission_service_sierrasandbox_label\">Google Checkout Sandbox 帳戶</string>\n    <string name=\"permission_service_sierrasandbox_description\">允許程式透過任何已關聯的 Google 帳戶來使用 Google Checkout Sandbox 帳戶。</string>\n    <string name=\"permission_service_sitemaps_label\">Google Webmaster Tools</string>\n    <string name=\"permission_service_sitemaps_description\">允許程式透過任何已關聯的 Google 帳戶來使用 Google Webmaster Tools。</string>\n    <string name=\"permission_service_speech_label\">語音搜尋</string>\n    <string name=\"permission_service_speech_description\">允許程式透過任何已關聯的 Google 帳戶來使用語音搜尋。</string>\n    <string name=\"permission_service_speechpersonalization_label\">個人化語音辨識</string>\n    <string name=\"permission_service_speechpersonalization_description\">允許程式透過任何已關聯的 Google 帳戶來使用個人化語音辨識。</string>\n    <string name=\"permission_service_talk_label\">Google Talk</string>\n    <string name=\"permission_service_talk_description\">允許程式透過任何已關聯的 Google 帳戶來使用 Google Talk。</string>\n    <string name=\"permission_service_wifi_label\">Google Wi-Fi</string>\n    <string name=\"permission_service_wifi_description\">允許程式透過任何已關聯的 Google 帳戶來使用 Google Wi-Fi。</string>\n    <string name=\"permission_service_wise_label\">Google 試算表</string>\n    <string name=\"permission_service_wise_description\">允許程式透過任何已關聯的 Google 帳戶來使用 Google 試算表。</string>\n    <string name=\"permission_service_writely_label\">Google 文件</string>\n    <string name=\"permission_service_writely_description\">允許程式透過任何已關聯的 Google 帳戶來使用 Google 文件。</string>\n    <string name=\"permission_service_youtube_label\">YouTube</string>\n    <string name=\"permission_service_youtube_description\">允許程式透過任何已關聯的 Google 帳戶來使用 YouTube。</string>\n    <string name=\"permission_service_YouTubeUser_label\">YouTube 使用者名稱</string>\n    <string name=\"permission_service_YouTubeUser_description\">允許程式透過任何已關聯的 Google 帳戶來使用一個或多個的 YouTube 使用者名稱。</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_activity\">查看您在 Google 應用程式的活動紀錄</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.buyer\">管理您的 Ad Exchange buyer 帳戶設定</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller.readonly\">查看您的 Ad Exchange 資料</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adexchange.seller\">查看並管理您的 Ad Exchange 資料</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsensehost\">查看並管理您的 AdSense 伺服資料和關聯帳戶</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense.readonly\">查看您的 AdSense 資料</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_adsense\">查看並管理您的 AdSense 資料</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics.readonly\">查看您的 Google Analytics 資料</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_analytics\">查看並管理您的 Google Analytics 資料</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_androidpublisher\">使用 Google Play Android 開發者的權限</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appengine.admin\">App engine 最高權限。</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.migration\">Groups Migration API 的讀寫權限。</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.groups.settings\">查看及管理 Google 程式群組的設定</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.licensing\">License Manager API 的讀寫權限。</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order\">供經銷商管理員和使用者在 API 沙盒中測試時取得讀取 / 寫入存取權限，或在直接呼叫 API 操作時取得讀取/寫入存取權限。</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps.order.readonly\">除了整體讀取 / 寫入 OAuth 範圍外，在檢索客戶資料時還使用唯讀 OAuth 範圍。</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_apps_reporting_audit.readonly\">使用 Admin Audit API 的唯讀權限</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_appstate\">供程式狀態服務運行的權限。</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery.readonly\">查看您在 Google BigQuery 的資料</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_bigquery\">查看並管理您在 Google BigQuery 的資料</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger\">管理您的 Blogger 帳戶</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_blogger.readonly\">查看您的 Blogger 帳戶</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_books\">管理您的圖書</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar\">管理您的日曆</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_calendar.readonly\">查看您的日曆</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_cloudprint\">查看並管理您的 Google 雲端列印資料</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute.readonly\">查看您的 Google 電算引擎資源</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_compute\">查看並管理您的 Google 電算引擎資源</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate.readonly\">查看您的 Google Coordinate jobs</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_coordinate\">查看並管理您的 Google Maps Coordinate jobs</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.full_control\">管理您 Google Cloud Storage 中的資料及權限</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_only\">查看您 Google Cloud Storage 中的資料</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_devstorage.read_write\">管理您 Google Cloud Storage 中的資料</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_dfareporting\">查看並管理 DoubleClick 的廣告商報告</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.appdata\">允許使用「應用程式資料」資料夾</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.apps.readonly\">查看您的 Google Drive Apps</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.file\">查看並管理您用此程式在 Google Drive 中開啟或新增的檔案</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.install\">用於讓使用者核准應用程式安裝的特殊權限</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.metadata.readonly\">查看您有關 Google Drive 中檔案和文件的相關資料</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.readonly\">查看您 Google Drive 中的檔案和文件</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive.scripts\">修改您 Google Apps Script 程式腳本的行為</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_drive\">查看並管理您 Google Drive 中的檔案和文件</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase.readonly\">查看您的 Freebase 帳戶</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_freebase\">用您的帳戶登入 Freebase</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables\">管理您的 Fusion Tables</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_fusiontables.readonly\">查看您的 Fusion Tables</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_games\">從 Google Play 遊戲獲取資料的權限。</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan\">管理您的 GAN 資料</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gan.readonly\">查看您的 GAN 資料</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gcm_for_chrome\">Chrome 的 GCM 服務</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_glass.timeline\">Glass 時間軸權限</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.compose\">新增、讀取、更新和刪除草稿。傳送訊息和草稿。</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.modify\">除了立即性和永久性刪除訊息串或訊息以外的讀寫權限（垃圾桶不在此限）。</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_gmail.readonly\">讀取所有資源和相關資料—無需寫入。</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.best\">管理您的最佳可用地點和地點歷史</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.all.city\">管理您的城市等級地點和地點歷史</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.best\">管理您的最佳可用地點</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_latitude.current.city\">管理您的城市等級地點</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine\">從您的程式提供使用者 Google Maps Engine 資料的讀寫權限</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mapsengine.readonly\">從您的程式提供使用者 Google Maps Engine 資料的唯讀權限</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_mobilemaps.firstparty\">為了行動裝置上的體驗閱覽和管理您的 Google 地圖</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut\">管理您的 Orkut 活動</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_orkut.readonly\">檢視您的 Orkut 資料</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.login\">知道您在 Google+ 的名字，基本資訊，以及和誰聯絡</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_plus.me\">知道您在 Google 是誰</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_prediction\">管理您在 Google Prediction API 中的資料</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_shoppingapi\">查看您的商品資料</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification\">管理您控制網站和域名的表單</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_siteverification.verify_only\">用 Google 管理您新的網站認證</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_structuredcontent\">Shopping Content API 的讀寫權限。</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue.consumer\">從您的任務列隊中執行任務</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_taskqueue\">管理您的任務</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks\">管理您的任務</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tasks.readonly\">查看您的任務</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_tracks\">Google 地圖追蹤 API，這個權限允許讀寫您的計畫資料。</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_urlshortener\">管理您的 goo.gl 短網址</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.email\">查看您的郵件地址</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_userinfo.profile\">查看您帳戶的基本資訊</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube\">管理您的 YouTube 帳戶</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtubepartner\">查看和管理您和 YouTube 帳戶相關聯的內容和物品</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.readonly\">查看您的 YouTube 帳戶</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_youtube.upload\">管理您的 YouTube 影片</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics_monetary.readonly\">查看您 YouTube 內容的收入報告</string>\n    <string name=\"permission_scope_www.googleapis.com_auth_yt_analytics.readonly\">查看您 YouTube 內容的分析報告</string>\n    <string name=\"perm_activity_recognition_description\">允許應用程式定期接收來自 Google 的活動狀態更新，例如您是否正在步行、開車、騎腳踏車或靜止不動。</string>\n    <string name=\"perm_activity_recognition_label\">體能活動辨識</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-zh-rTW/plurals.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2017 microG Project Team\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  --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <plurals name=\"pref_unifiednlp_summary\">\n        <item quantity=\"other\">已設定 <xliff:g example=\"3\">%1$d</xliff:g> 個背景伺服器</item>\n    </plurals>\n    <plurals name=\"gcm_registered_apps_counter\">\n        <item quantity=\"other\">已註冊 <xliff:g example=\"123\">%1$d</xliff:g> 個程式</item>\n    </plurals>\n    <plurals name=\"cond_perm_summary\">\n        <item quantity=\"other\">microG Service 缺少了多個權限以至於不能正常運作。</item>\n    </plurals>\n    <plurals name=\"cond_perm_action\">\n        <item quantity=\"other\">請求缺少的權限</item>\n    </plurals>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/values-zh-rTW/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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  --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"gms_app_name\">microG 服務</string>\n    <string name=\"gms_settings_name\">microG 設定</string>\n    <string name=\"just_a_sec\">請稍候…</string>\n    <string name=\"google_account_label\">Google</string>\n    <string name=\"ask_permission_tos\">當您繼續下一步時，代表您同意 Google 與本程式在遵守《服務條款》與《隱私權政策》下使用您的個人資訊。</string>\n    <string name=\"ask_scope_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> 想要執行以下操作：</string>\n    <string name=\"ask_service_permission_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> 想要使用以下服務：</string>\n    <string name=\"account_manager_title\">Google 帳戶管理工具</string>\n    <string name=\"sorry\">抱歉…</string>\n    <string name=\"no_network_error_desc\">您目前沒有網路連線。\\n\\n這可能是暫時性的問題，或是您的 Android 裝置尚未啟用行動數據服務。請在連上行動網路或 Wi-Fi 後再試一次。</string>\n    <string name=\"auth_general_error_desc\">與 Google 伺服器通訊時發生問題。\n\\n\n\\n請稍後重試。</string>\n    <string name=\"auth_finalize\">您的裝置正在與 Google 伺服器連線以將資訊儲存至您的帳戶。\\n\\n這可能需要幾分鐘。</string>\n    <string name=\"allow\">允許</string>\n    <string name=\"deny\">拒絕</string>\n    <string name=\"auth_notification_title\">需要驗證</string>\n    <string name=\"auth_notification_content\"><xliff:g example=\"F-Droid\">%1$s</xliff:g>需要您的授權來使用 Google 帳戶。</string>\n    <string name=\"perm_status_broadcast_label\">接收內部狀態廣播</string>\n    <string name=\"perm_c2dm_receive_label\">接收 C2DM 訊息</string>\n    <string name=\"perm_c2dm_send_label\">傳送 C2DM 訊息給其它程式</string>\n    <string name=\"perm_gtalk_svc_label\">從 Google 伺服器交換訊息並接收同步通知</string>\n    <string name=\"perm_extended_access_label\">進階存取 Google 服務的權限</string>\n    <string name=\"service_name_checkin\">註冊為 Google 裝置</string>\n    <string name=\"service_name_mcs\">雲端推播（Cloud Messaging）</string>\n    <string name=\"games_title\">Google Play 遊戲</string>\n    <string name=\"games_info_title\"><xliff:g example=\"F-Droid\">%1$s</xliff:g>想要使用 Play 遊戲</string>\n    <string name=\"games_info_content\">若要使用 Play 遊戲，必須安裝 Google Play 遊戲應用程式。應用程式在未安裝 Play 遊戲的情況下或許能繼續執行，但可能會出現異常行為。</string>\n    <string name=\"pick_place_title\">選擇地點</string>\n    <string name=\"pick_place_desc\">現在無法選擇地點。</string>\n    <string name=\"place_picker_select_title\">選擇這個地點</string>\n    <string name=\"place_picker_nearby_places\">附近的地點</string>\n    <string name=\"place_picker_location_lat_lng\">（%1$.7f，%2$.7f）</string>\n    <string name=\"lacking_permission_toast\">microG 服務：缺少 <xliff:g example=\"have full network acccess\">%1$s</xliff:g> 的權限</string>\n    <string name=\"network_type_mobile\">行動數據</string>\n    <string name=\"network_type_wifi\">Wi-Fi</string>\n    <string name=\"network_type_roaming\">漫遊</string>\n    <string name=\"network_type_other\">其它網路</string>\n    <!-- Self check -->\n\n    <string name=\"self_check_cat_fake_sig\">支援簽名破解</string>\n    <string name=\"self_check_cat_gms_packages\">已安裝的程式</string>\n    <string name=\"self_check_cat_system\">系統</string>\n    <string name=\"self_check_name_fake_sig_perm\">系統支援簽名破解： </string>\n    <string name=\"self_check_resolution_fake_sig_perm\">您的 ROM 不具備原生支援簽名破解的功能。不過，您仍然可以透過 Xposed 或其他系統進行簽名破解。請參閱相關文件，了解哪些 ROM 支援簽名破解，以及如何在不支援的 ROM 上使用 microG。</string>\n    <string name=\"self_check_name_perm_granted\">系統允許簽名破解的權限： </string>\n    <string name=\"self_check_resolution_perm_granted\">這是韌體支援簽名破解的強力指標，但可能需要額外步驟才能啟用。請參閱相關文件，瞭解可能需要進行哪些設定。</string>\n    <string name=\"self_check_name_system_spoofs\">系統破解簽名： </string>\n    <string name=\"self_check_resolution_system_spoofs\">請參閱相關文件，瞭解可能需要執行的步驟。</string>\n    <string name=\"self_check_pkg_gms\">Play 服務（GmsCore）</string>\n    <string name=\"self_check_pkg_vending\">Play 商店（Phonesky）</string>\n    <string name=\"self_check_pkg_gsf\">服務框架（GSF）</string>\n    <string name=\"self_check_name_app_installed\"><xliff:g example=\"F-Droid\">%1$s</xliff:g>已安裝：</string>\n    <string name=\"self_check_resolution_app_installed\">安裝 <xliff:g example=\"F-Droid\">%1$s</xliff:g> 或是相容的程式。請參閱哪些程式相容的說明文件。</string>\n    <string name=\"self_check_name_correct_sig\"><xliff:g example=\"F-Droid\">%1$s</xliff:g> 有正確簽名： </string>\n    <string name=\"self_check_resolution_correct_sig\">不是已安裝的 <xliff:g example=\"F-Droid\">%1$s</xliff:g> 不相容就是簽名破解沒啟動。請參閱相關文件，瞭解哪些應用程式與 ROM 相容。</string>\n    <string name=\"self_check_name_battery_optimizations\">停用最佳化電池：</string>\n    <string name=\"self_check_resolution_battery_optimizations\">點擊這裡來停用最佳化電池。不這麼做可能導致程式運作不正常。</string>\n    <!-- Settings strings -->\n\n    <string name=\"prefcat_about\">關於</string>\n    <string name=\"prefcat_components\">元件</string>\n    <string name=\"prefcat_configuration\">設定</string>\n    <string name=\"prefcat_location_service\">定位服務</string>\n    <string name=\"prefcat_services\">服務</string>\n    <string name=\"prefcat_test\">測試</string>\n    <string name=\"cond_gcm_bat_title\">已開啟最佳化電池</string>\n    <string name=\"cond_gcm_bat_summary\">您已啟用雲端推播，但目前 microG 服務仍啟用了電池最佳化功能。為了確保能正常接收推播通知，建議將電池最佳化設為忽略。</string>\n    <string name=\"cond_gcm_bat_action\">忽略最佳化</string>\n    <string name=\"cond_perm_title\">缺少權限</string>\n    <string name=\"prefs_account\">帳戶設定</string>\n    <string name=\"prefs_account_privacy\">個人資訊 &amp; 隱私</string>\n    <string name=\"prefs_account_security\">登入 &amp; 安全</string>\n    <string name=\"pref_auth_trust_google_title\">信任 Google 處理應用程式權限請求</string>\n    <string name=\"pref_auth_trust_google_summary\">關閉此功能後，系統會在將應用程式的授權請求傳送給 Google 前先徵求您的同意。若停用此功能，部分應用程式可能無法使用 Google 帳戶。</string>\n    <string name=\"pref_checkin_enable_summary\">將您的裝置註冊至 Google 服務，並建立唯一的裝置識別碼。microG 會從註冊資料中移除除 Google 帳戶名稱以外的所有識別資訊。</string>\n    <string name=\"pref_gcm_enable_mcs_summary\">Cloud Messaging 是許多第三方應用程式所使用的推播通知服務。若要使用此功能，您必須先完成裝置註冊。</string>\n    <string name=\"pref_gcm_heartbeat_title\">雲端推播心跳間隔</string>\n    <string name=\"pref_gcm_heartbeat_summary\">系統向 Google 伺服器發送心跳訊號的時間間隔（以秒為單位）。增加此數值可降低電池消耗，但可能會導致推播訊息延遲。\\n此功能已被標示為淘汰，未來版本將會移除。</string>\n    <string name=\"pref_gcm_apps_title\">使用雲端推播的程式</string>\n    <string name=\"pref_gcm_apps_summary\">目前已註冊使用雲端推播通知的應用程式列表。</string>\n    <string name=\"pref_about_title\">關於 microG 服務</string>\n    <string name=\"pref_about_summary\">版本資訊與使用的程式庫</string>\n    <string name=\"gcm_app_error_unregistering\">取消註冊時發生錯誤</string>\n    <string name=\"gcm_app_not_installed_anymore\">已被移除</string>\n    <string name=\"gcm_unregister_app\">取消註冊</string>\n    <string name=\"gcm_not_registered\">未註冊</string>\n    <string name=\"gcm_no_message_yet\">尚未收至任何訊息</string>\n    <string name=\"gcm_last_message_at\">最後收至訊息：<xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"gcm_registered\">已註冊</string>\n    <string name=\"gcm_registered_since\">自 <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g> 註冊至今</string>\n    <string name=\"gcm_unregister_confirm_title\">取消註冊<xliff:g example=\"F-Droid\">%1$s</xliff:g>？</string>\n    <string name=\"gcm_unregister_confirm_message\">有些應用程式不會自動重新註冊，或不提供手動註冊的選項。這些應用程式在取消註冊後可能無法正常運作。\\n是否要繼續？</string>\n    <string name=\"gcm_unregister_after_deny_message\">您已拒絕某個已註冊的應用程式使用推播通知功能。\\n是否要立即將其取消註冊，以防止它日後接收推播訊息？</string>\n    <string name=\"gcm_messages_counter\">已接收：<xliff:g example=\"123\">%1$d</xliff:g> 個訊息（<xliff:g example=\"12345\">%2$d</xliff:g> 位元組）</string>\n    <string name=\"safetynet_intro\">Google SafetyNet 是一套裝置認證系統，旨在確保裝置具備適當的安全性，並與 Android 相容性測試套件（CTS, Compatibility Test Suite）相容。部分應用程式會因安全性需求，或作為防篡改機制的前置條件而使用 SafetyNet。\\n\\nmicroG GmsCore 提供了 SafetyNet 的自由實作版本，但 Google 官方伺服器要求所有 SafetyNet 請求必須透過專有的 DroidGuard 系統進行簽章。</string>\n    <string name=\"pref_safetynet_test_title\">測試 SafetyNet 裝置認證</string>\n    <string name=\"pref_vending_billing_enable_switch\">處理帳款請求</string>\n    <string name=\"perm_car_speed_label\">車速</string>\n    <string name=\"perm_car_info_label\">車輛資訊</string>\n    <string name=\"perm_car_mileage_label\">車輛行駛里程</string>\n    <string name=\"pref_auth_strip_device_name_title\">使用匿名裝置名稱以進行身份驗證</string>\n    <string name=\"prefcat_push_apps_registered_title\">已註冊的應用程式</string>\n    <string name=\"pref_safetynet_recent_nonce\">隨機數（Hex）</string>\n    <string name=\"prefcat_push_apps_unregistered_title\">未註冊的應用程式</string>\n    <string name=\"pref_safetynet_recent_request_time\">請求時間</string>\n    <string name=\"pref_safetynet_recent_request_type\">請求類型</string>\n    <string name=\"feedback_disabled\">目前無法提供意見回饋</string>\n    <string name=\"prefcat_accounts_current_accounts_title\">帳戶</string>\n    <string name=\"gcm_allow_app_popup\">允許 <xliff:g example=\"F-Droid\">%1$s</xliff:g> 註冊推播通知？</string>\n    <string name=\"prefcat_push_apps_title\">使用推播通知的應用程式</string>\n    <string name=\"prefcat_push_networks_title\">用於推播通知的網路</string>\n    <string name=\"pref_droidguard_unsupported_summary\">此裝置不支援執行 DroidGuard，SafetyNet 服務可能無法正常運作。</string>\n    <string name=\"safetynet_last_run_at\">最後使用於：<xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"profile_name_system\">系統：%s</string>\n    <string name=\"pref_device_registration_import_custom_profile_summary\">從檔案匯入裝置設定檔</string>\n    <string name=\"pref_safetynet_recent_copy_json\">複製 JSON JWS 資料</string>\n    <string name=\"pref_safetynet_recent_advice\">建議</string>\n    <string name=\"pref_safetynet_recent_token\">權杖</string>\n    <string name=\"pref_safetynet_recent_copied\">已複製到剪貼簿！</string>\n    <string name=\"pref_vending_billing_enable_summary\">啟用後，部分應用程式即可透過 Google Play 帳款服務完成購買或啟用訂閱。</string>\n    <string name=\"pref_vending_billing_note_experimental\">此功能仍在實驗階段，所造成的經濟損失我們概不負責。</string>\n    <string name=\"pref_vending_billing_note_licensing\">某些應用程式可能還要求您啟用授權驗證以驗證您的購買。</string>\n    <string name=\"service_name_vending\">Play 商店服務</string>\n    <string name=\"prefcat_google_services\">Google 服務</string>\n    <string name=\"pref_auth_visible_title\">允許應用程式尋找帳戶</string>\n    <string name=\"pref_auth_visible_summary\">啟用此功能後，裝置上的所有應用程式都可以在未經您授權的情況下，讀取您的 Google 帳戶電子郵件地址。</string>\n    <string name=\"pref_auth_include_android_id_title\">透過裝置註冊進行身份驗證</string>\n    <string name=\"pref_auth_include_android_id_summary\">關閉此功能後，驗證請求將不會與裝置註冊資訊綁定，這可能允許未授權的裝置登入，但也可能導致不可預期的後果。</string>\n    <string name=\"pref_device_registration_android_id\">Android ID</string>\n    <string name=\"checkin_not_registered\">未註冊</string>\n    <string name=\"checkin_last_registration\">最後註冊於：<xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"checkin_enable_switch\">註冊裝置</string>\n    <string name=\"pref_gcm_confirm_new_apps_summary\">在註冊新應用程式以接收推播通知之前詢問</string>\n    <string name=\"pref_gcm_ping_interval\">Ping 間隔：<xliff:g example=\"10 minutes\">%1$s</xliff:g></string>\n    <string name=\"gcm_network_state_disconnected\">已中斷連線</string>\n    <string name=\"gcm_network_state_connected\">自 <xliff:g example=\"2 hours ago\">%1$s</xliff:g> 已連線</string>\n    <string name=\"safetynet_enable_switch\">允許裝置認證</string>\n    <string name=\"pref_recaptcha_test_title\">測試 ReCAPTCHA</string>\n    <string name=\"pref_recaptcha_enterprise_test_title\">測試 ReCAPTCHA Enterprise</string>\n    <string name=\"pref_test_summary_passed\">通過所有測試</string>\n    <string name=\"pref_test_summary_failed\">失敗：%s</string>\n    <string name=\"pref_test_summary_warn\">警告：%s</string>\n    <string name=\"pref_test_summary_running\">執行中…</string>\n    <string name=\"pref_droidguard_operation_mode\">運作模式</string>\n    <string name=\"prefcat_safetynet_apps_title\">使用 SafetyNet 的應用程式</string>\n    <string name=\"prefcat_device_attestation_apps_title\">使用設備認證的應用程式</string>\n    <string name=\"menu_clear_recent_requests\">清除最近的請求</string>\n    <string name=\"profile_name_native\">原生</string>\n    <string name=\"profile_name_real\">實機</string>\n    <string name=\"profile_name_user\">自定義：%s</string>\n    <string name=\"profile_name_auto\">自動：%s</string>\n    <string name=\"pref_safetynet_test_cts_failed\">CTS 失敗</string>\n    <string name=\"pref_safetynet_test_integrity_cts_passed\">完整性與 CTS 通過</string>\n    <string name=\"pref_safetynet_test_integrity_failed\">完整性失敗</string>\n    <string name=\"pref_safetynet_test_not_completed\">尚未完成</string>\n    <string name=\"pref_safetynet_test_no_result\">沒有結果</string>\n    <string name=\"pref_safetynet_test_invalid_json\">無效 JSON</string>\n    <string name=\"push_notifications_summary_manual\">開啟 / 手動：%s</string>\n    <string name=\"push_notifications_summary_values_seconds\">%s 秒</string>\n    <string name=\"push_notifications_summary_values_minutes\">%s 分鐘</string>\n    <string name=\"gms_settings_summary\">設定 microG 服務。</string>\n    <string name=\"auth_before_connect\">有應用程式正在嘗試登入一個 Google 帳戶。\\n\\n若這是有意而為，請透過<b>登入</b>按鈕以連線至 Google 登入頁面；反之，請點擊<b>取消</b>並跳轉至觸發此對話框的應用程式。」</string>\n    <string name=\"auth_sign_in\">登入</string>\n    <string name=\"auth_connecting\">您的裝置正在連線至 Google 伺服器以完成登入。\\n\\n這可能需要幾秒鐘的時間。</string>\n    <string name=\"signin_picker_title\">選擇帳戶</string>\n    <string name=\"signin_picker_subtitle\">以繼續 <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"signin_picker_add_account_label\">新增其它帳戶</string>\n    <string name=\"signin_confirm_title\">允許您登入至 <xliff:g example=\"F-Droid\">%1$s</xliff:g></string>\n    <string name=\"signin_subtext_sharing\">要繼續，microG 將與 <xliff:g example=\"F-Droid\">%1$s</xliff:g> 分享您的 Google 帳戶的姓名、電子郵件地址與個人資料照片。</string>\n    <string name=\"signin_subtext_policy_privacy\">《隱私權政策》</string>\n    <string name=\"signin_subtext_policy_terms\">《服務條款》</string>\n    <string name=\"perm_gsf_read_gservices_label\">閱讀 Google 服務配置</string>\n    <string name=\"perm_provision_label\">提供 microG 服務</string>\n    <string name=\"perm_provision_description\">允許應用程式在無需使用者互動的情況下配置 microG 服務</string>\n    <string name=\"perm_car_speed_description\">存取您的車速</string>\n    <string name=\"perm_car_info_description\">存取您的車輛資訊</string>\n    <string name=\"perm_car_fuel_label\">車輛燃油剩餘量</string>\n    <string name=\"perm_car_fuel_description\">存取您的車輛燃油剩餘量</string>\n    <string name=\"perm_car_mileage_description\">存取您的車輛行駛里程</string>\n    <string name=\"perm_car_vendor_extension_label\">車用廠商通訊通道</string>\n    <string name=\"perm_car_vendor_extension_description\">存取您車輛的車廠專屬通道，以交換與車輛相關的專屬資訊</string>\n    <string name=\"service_name_snet\">Google SafetyNet</string>\n    <string name=\"service_name_device_attestation\">設備認證</string>\n    <string name=\"pref_device_attestation_app_allow_requests_title\">允許請求</string>\n    <string name=\"pref_device_attestation_app_allow_requests_summary\">允許應用程式請求裝置身份驗證</string>\n    <string name=\"pref_auth_strip_device_name_summary\">啟用此功能後，驗證請求中將不包含裝置名稱，這可能允許未授權的裝置登入，但也可能導致不可預期的後果。</string>\n    <string name=\"pref_info_status\">狀態</string>\n    <string name=\"pref_more_settings\">更多</string>\n    <string name=\"pref_accounts_title\">Google 帳戶</string>\n    <string name=\"pref_accounts_summary\">新增與管理 Google 帳戶</string>\n    <string name=\"prefcat_accounts_settings_title\">設定</string>\n    <string name=\"pref_add_account_title\">帳戶</string>\n    <string name=\"pref_add_account_summary\">新增 Google 帳戶</string>\n    <string name=\"pref_gcm_confirm_new_apps_title\">確認新的應用程式</string>\n    <string name=\"gcm_enable_switch\">接收推播通知</string>\n    <string name=\"pref_push_app_allow_register_title\">允許註冊</string>\n    <string name=\"pref_push_app_allow_register_summary\">允許應用程式註冊推播通知。</string>\n    <string name=\"pref_push_app_wake_for_delivery_title\">收到推播訊息時啟動應用程式</string>\n    <string name=\"pref_push_app_wake_for_delivery_summary\">在背景執行時自動啟動應用程式，以接收傳入的推播訊息。</string>\n    <string name=\"pref_device_registration_import_custom_profile_title\">匯入自訂義設定檔</string>\n    <string name=\"pref_device_registration_serial_title\">序號</string>\n    <string name=\"pref_device_registration_select_profile_title\">選擇設定檔</string>\n    <string name=\"pref_device_registration_device_profile_category\">選擇裝置設定檔</string>\n    <string name=\"pref_safetynet_recent_uses\">最近使用</string>\n    <string name=\"pref_safetynet_recent_attestation_summary\">認證：%s</string>\n    <string name=\"pref_safetynet_recent_recaptcha_summary\">ReCaptcha：%s</string>\n    <string name=\"pref_safetynet_recent_recaptcha_enterprise_summary\">ReCaptcha Enterprise：%s</string>\n    <string name=\"pref_safetynet_recent_response_status\">回應狀態</string>\n    <string name=\"pref_safetynet_recent_cat_response\">回應資料</string>\n    <string name=\"pref_safetynet_recent_cat_request\">請求資料</string>\n    <string name=\"pref_safetynet_recent_cat_basic\">基本資料</string>\n    <string name=\"push_notifications_summary_off\">關閉</string>\n    <string name=\"push_notifications_summary_automatic\">開啟 / 自動：%s</string>\n    <string name=\"pref_vending_summary_licensing_off\">關閉授權</string>\n    <string name=\"pref_vending_summary_licensing_on\">開啟授權</string>\n    <string name=\"pref_vending_licensing_category\">Google Play 授權</string>\n    <string name=\"pref_vending_licensing_enable_switch\">回應授權驗證請求</string>\n    <string name=\"pref_vending_license_enable_summary\">有些應用程式需要驗證是否已於 Google Play 購買。當應用程式提出要求時，microG 可以從 Google 下載購買憑證。若此功能未啟用，或尚未新增 Google 帳戶，授權驗證請求將會被忽略。</string>\n    <string name=\"pref_vending_billing_category\">Google Play 帳款</string>\n    <string name=\"backup_disabled\">目前無法備份</string>\n    <string name=\"signin_confirm_button_text\">允許與分享</string>\n    <string name=\"signin_subtext_policy\">在使用此應用程式之前，請檢查其 %1$s 和 %2$s。</string>\n    <string name=\"pref_safetynet_recent_eval_type\">評估類型</string>\n    <string name=\"credentials_assisted_cancel\">取消</string>\n    <string name=\"credentials_assisted_continue\">下一步</string>\n    <string name=\"credentials_assisted_confirmation_header\">正在將您登入</string>\n    <string name=\"credentials_assisted_continue_as_user_button_label\">以「%1$s」的身分繼續</string>\n    <string name=\"credentials_assisted_signin_consent_header\">以「%1$s」的身分登入</string>\n    <string name=\"credentials_assisted_signin_consent\">如果您繼續操作，Google 會將您的姓名、電郵地址和個人照片提供給 %1$s。請參閱 %1$s 的隱私權政策和服務條款。</string>\n    <string name=\"auth_package_override_request_message\"><b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> 想以 <b><xliff:g example=\"F-Droid\">%2$s</xliff:g>（由 <xliff:g example=\"F-Droid Inc.\">%3$s</xliff:g> 開發）</b> 的身分存取您的帳戶。這可能會讓其獲得對您帳戶的特殊存取權限。\\\"</string>\n    <string name=\"limited_services_app_name\">microG Limited Services</string>\n    <string name=\"auth_action_notification_channel_name\">Google 帳戶警告</string>\n    <string name=\"auth_package_override_request_title\">允許 <b><xliff:g example=\"F-Droid\">%1$s</xliff:g></b> 對 <xliff:g example=\"account@example.com\">%2$s</xliff:g> 擁有特殊存取權限嗎？\\\"</string>\n    <string name=\"games_achievements_empty_text\">此遊戲沒有成就</string>\n    <string name=\"games_achievement_locked_content_description\">未解鎖</string>\n    <string name=\"games_achievement_unlocked_content_description\">已解鎖</string>\n    <string name=\"games_leaderboard_empty_text\">此遊戲沒有排行榜</string>\n    <string name=\"games_leaderboard_list_title\">排行榜</string>\n    <string name=\"games_snapshot_empty_text\">尚未儲存任何遊戲進度</string>\n    <string name=\"games_snapshot_choose_btn_text\">選擇</string>\n    <string name=\"games_snapshot_delete_btn_text\">刪除</string>\n    <string name=\"games_delete_snapshot_dialog_cancel\">取消</string>\n    <string name=\"games_delete_snapshot_error\">刪除失敗，請稍後再試</string>\n    <string name=\"family_management_title\">家庭</string>\n    <string name=\"family_management_retry\">重試</string>\n    <string name=\"family_management_load_error\">內容載入失敗</string>\n    <string name=\"family_management_toolbar_back\">返回</string>\n    <string name=\"family_management_toolbar_more\">更多</string>\n    <string name=\"family_management_exit_family_group\">退出家庭群組</string>\n    <string name=\"family_management_delete_family_group\">刪除家庭群組</string>\n    <string name=\"family_management_leave_family_password_title\">確認密碼以退出家庭群組</string>\n    <string name=\"family_management_delete_family_password_title\">確認密碼以刪除家庭群組</string>\n    <string name=\"family_management_remove_member_password_title\">確認密碼以移除“%s”</string>\n    <string name=\"family_management_invite_family_member\">邀請家庭成員</string>\n    <string name=\"family_management_invite_slots_left\">剩餘%1$d個邀請名額</string>\n    <string name=\"family_management_cancel_invite\">取消邀請</string>\n    <string name=\"family_management_cancel_invite_success\">已成功取消邀請</string>\n    <string name=\"family_management_cancel_invite_error\">取消邀請失敗，請重試</string>\n    <string name=\"family_management_remove_member\">移除成員</string>\n    <string name=\"family_management_member_removed_success\">已將%s從您的家庭群組中移除</string>\n    <string name=\"family_management_member_remove_failed\">移除%s失敗，請再試一次</string>\n    <string name=\"family_management_leave_family_error_message\">退出家庭群組時發生問題，請再試一次。</string>\n    <string name=\"family_management_exist_group_success\">您已成功退出家庭群組⋯</string>\n    <string name=\"family_management_delete_group_success\">家庭群組已刪除</string>\n    <string name=\"family_management_delete_group_failure\">刪除家庭群組失敗</string>\n    <string name=\"family_management_delete_group_cancel\">取消</string>\n    <string name=\"family_management_delete_group_confirm\">確定</string>\n    <string name=\"family_management_input_pwd\">請輸入密碼</string>\n    <string name=\"family_management_invite_sent_date_format\">已於%s發送邀請</string>\n    <string name=\"family_management_invite_send\">已發送邀請</string>\n    <string name=\"family_management_pwd_error\">密碼錯誤，請重新輸入</string>\n    <string name=\"barcode_scanner_brand\">已由 microG 代表 %1$s 掃描</string>\n    <string name=\"camera_permission_dialog_title\">需要相機使用權限</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_switch\">自動添加免費應用程式到媒體庫</string>\n    <string name=\"pref_vending_feature_delivery\">Google Play 功能傳遞 (Feature Delivery)</string>\n    <string name=\"pref_vending_split_install_switch\">隨選提供功能安裝</string>\n    <string name=\"pref_workprofile_create_account\">允許設定工作帳戶</string>\n    <string name=\"pref_vending_asset_device_sync_switch\">啟用設備資訊同步</string>\n    <string name=\"games_achievement_list_title\">成就</string>\n    <string name=\"games_achievement_extra_text\">%1$s XP</string>\n    <string name=\"games_delete_snapshot_dialog_message\">您確定要刪除這個遊戲存檔嗎？</string>\n    <string name=\"games_delete_snapshot_dialog_title\">刪除已儲存的遊戲存檔</string>\n    <string name=\"games_api_access_denied\">此裝置上沒有任何帳戶可以存取 Games API</string>\n    <string name=\"pref_workprofile_intro\">在為公司或學校建立工作設定檔時，系統可能會嘗試連線至 Google，以便啟用該設定檔下載應用程式。</string>\n    <string name=\"pref_workprofile_disclaimer\">您有責任確保您對 microG 的使用符合公司政策。microG 採盡力提供 (best-effort) 方式運作，無法保證其行為完全符合預期。</string>\n    <string name=\"auth_action_step_enable_lockscreen_description\">您的 Google 帳戶由您的工作單位或教育機構管理。管理員規定裝置必須先設定安全的螢幕鎖定方式，才能存取帳戶資料。\\n\\n請設定密碼、PIN 碼或圖案鎖。</string>\n    <string name=\"limited_services_dialog_information\">您正在使用 microG Limited Services。與一般的 microG Services 不同，這個版本僅支援使用 microG 函式庫的應用程式，而不支援來自 Google Play 的應用程式。這代表大多數應用程式會忽略這些服務。</string>\n    <string name=\"games_delete_snapshot_dialog_ok\">確定</string>\n    <string name=\"service_name_work_profile\">工作設定檔</string>\n    <string name=\"pref_vending_licensing_split_install_summary\">允許應用程式下載並安裝額外的元件</string>\n    <string name=\"pref_vending_asset_delivery_summary\">當使用 Play 資源傳遞 (Asset Delivery) 的應用程式提出請求時，下載額外資源</string>\n    <string name=\"credentials_assisted_sign_back_title\">透過 Google 重新登入 %1$s</string>\n    <string name=\"credentials_assisted_signin_description\">您可以在 Google 帳戶中管理「使用 Google 登入」的設定。</string>\n    <string name=\"credentials_assisted_signin_button_text_long\">使用 Google 帳戶登入</string>\n    <string name=\"games_leaderboard_score_empty_text\">太不可思議了！這款遊戲竟然沒有公開的高分紀錄。</string>\n    <string name=\"limited_services_dialog_information_ack\">我了解</string>\n    <string name=\"camera_permission_dialog_button\">確定</string>\n    <string name=\"camera_permission_dialog_message\">microG 服務需要存取您設備的相機，以便為 %1$s 掃描二維碼。\\n\\n請前往設定中，授權 microG 服務使用相機權限以啟用此功能。</string>\n    <string name=\"auth_action_step_allow_microg_gcm_description\">依照您的偏好設定，microG 需要取得您的授權後才能註冊使用雲端推播服務。</string>\n    <string name=\"pref_vending_asset_device_sync_summary\">使用 Play 資源傳遞 (Asset Delivery) 的應用程式，會根據使用者裝置的規格，自動下載需要的額外素材或資源。</string>\n    <string name=\"auth_action_notification_title\">需要帳戶操作</string>\n    <string name=\"auth_action_notification_channel_description\">當您的某個 Google 帳戶需要額外設定才能使用，或該帳戶與 microG 不相容時會顯示通知。</string>\n    <string name=\"auth_action_notification_content\">您的 Google 帳戶需要額外設定。</string>\n    <string name=\"auth_action_activity_header\">完成 Google 帳戶設定</string>\n    <string name=\"auth_action_activity_explanation\">請完成以下步驟，以便在此裝置上使用您的 Google 帳戶 %s。</string>\n    <string name=\"auth_action_step_enable_checkin\">啟用裝置註冊</string>\n    <string name=\"auth_action_step_enable_checkin_description\">您的裝置至少需要向 Google 註冊一次。\\n\\n在帳戶設定完成後，您可以停用 Google 裝置註冊功能。</string>\n    <string name=\"auth_action_step_enable_lockscreen\">設定安全的螢幕鎖定方式</string>\n    <string name=\"auth_action_step_enable_gcm\">啟用雲端推播</string>\n    <string name=\"auth_action_step_enable_gcm_description\">在帳戶設定完成後，您可以停用雲端推播。</string>\n    <string name=\"auth_action_step_allow_microg_gcm\">允許 microG 的雲端推播</string>\n    <string name=\"auth_action_step_perform_content_description\">點擊進行設定</string>\n    <string name=\"auth_action_step_completed_content_description\">步驟已完成</string>\n    <string name=\"auth_action_activity_finish\">完成</string>\n    <string name=\"pref_vending_licensing_purchase_free_apps_summary\">免費應用程式可能會檢查它們是否是從 Google Play 下載的。自動將免費應用程式加入您的帳戶媒體庫，可讓目前可用的所有免費應用程式通過這項檢查。</string>\n    <string name=\"credentials_assisted_choose_account_label\">選擇帳戶</string>\n    <string name=\"credentials_assisted_choose_account_subtitle\">以繼續使用 %1$s</string>\n    <string name=\"games_leaderboards_score_label\">得分：%1$s</string>\n    <string name=\"pref_vending_asset_delivery_switch\">啟用按需資源傳遞</string>\n    <string name=\"pref_vending_asset_delivery_category\">Google Play 資源傳遞 (Asset Delivery)</string>\n    <string name=\"credentials_assisted_choose_account_error_tips\">帳號異常</string>\n    <string name=\"credentials_assisted_signin_add_account\">新增帳號</string>\n</resources>\n"
  },
  {
    "path": "play-services-core/src/main/res/xml/authenticator.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<account-authenticator xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:accountPreferences=\"@xml/preferences_auth\"\n    android:accountType=\"com.google\"\n    android:customTokens=\"true\"\n    android:icon=\"@drawable/proprietary_auth_gls_ic_google_selected\"\n    android:smallIcon=\"@drawable/proprietary_auth_gls_ic_google_minitab_selected\"\n    android:label=\"@string/google_account_label\" />\n"
  },
  {
    "path": "play-services-core/src/main/res/xml/contact_syncadapter.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2017 microG Project Team\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<sync-adapter xmlns:android=\"http://schemas.android.com/apk/res/android\"\n              android:accountType=\"com.google\"\n              android:contentAuthority=\"com.android.contacts\"\n              android:userVisible=\"false\"/>"
  },
  {
    "path": "play-services-core/src/main/res/xml/file_provider_paths.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<paths xmlns:tools=\"http://schemas.android.com/tools\"\n    tools:ignore=\"MissingDefaultResource\">\n    <cache-path name=\"octarine_camera_tmp\" path=\"octa_camera_temp/\"/>\n</paths>"
  },
  {
    "path": "play-services-core/src/main/res/xml/network_security_config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<network-security-config>\n    <!-- We need to allow cleartext access to certain domains for local wifi location -->\n    <domain-config cleartextTrafficPermitted=\"true\">\n        <domain includeSubdomains=\"true\">portal.mav.hu</domain>\n        <domain includeSubdomains=\"true\">cdwifi.cz</domain>\n        <domain includeSubdomains=\"true\">hsp.hotsplots.net</domain>\n    </domain-config>\n</network-security-config>"
  },
  {
    "path": "play-services-core/src/main/res/xml/preferences_accounts.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n    <PreferenceCategory\n        android:key=\"prefcat_current_accounts\"\n        android:title=\"@string/prefcat_accounts_current_accounts_title\"\n        app:iconSpaceReserved=\"false\">\n        <Preference\n            android:enabled=\"false\"\n            android:order=\"9\"\n            android:key=\"pref_current_accounts_none\"\n            android:title=\"@string/list_no_item_none\" />\n        <Preference\n            android:icon=\"@drawable/ic_add\"\n            android:order=\"10\"\n            android:title=\"@string/pref_add_account_summary\">\n            <intent\n                android:targetClass=\"org.microg.gms.auth.login.LoginActivity\"\n                android:targetPackage=\"com.google.android.gms\" />\n        </Preference>\n    </PreferenceCategory>\n    <PreferenceCategory\n        android:key=\"prefcat_account_settings\"\n        android:title=\"@string/prefcat_accounts_settings_title\"\n        app:iconSpaceReserved=\"false\">\n        <SwitchPreferenceCompat\n            android:persistent=\"false\"\n            android:key=\"auth_manager_trust_google\"\n            android:summary=\"@string/pref_auth_trust_google_summary\"\n            android:title=\"@string/pref_auth_trust_google_title\"\n            app:iconSpaceReserved=\"false\" />\n        <SwitchPreferenceCompat\n            android:persistent=\"false\"\n            android:key=\"auth_manager_visible\"\n            android:summary=\"@string/pref_auth_visible_summary\"\n            android:title=\"@string/pref_auth_visible_title\"\n            app:iconSpaceReserved=\"false\" />\n        <SwitchPreferenceCompat\n            android:persistent=\"false\"\n            android:key=\"auth_include_android_id\"\n            android:summary=\"@string/pref_auth_include_android_id_summary\"\n            android:title=\"@string/pref_auth_include_android_id_title\"\n            app:iconSpaceReserved=\"false\" />\n        <SwitchPreferenceCompat\n            android:persistent=\"false\"\n            android:key=\"auth_strip_device_name\"\n            android:summary=\"@string/pref_auth_strip_device_name_summary\"\n            android:title=\"@string/pref_auth_strip_device_name_title\"\n            app:iconSpaceReserved=\"false\" />\n        <SwitchPreferenceCompat\n            android:persistent=\"false\"\n            android:key=\"auth_two_step_verification\"\n            android:summary=\"@string/pref_auth_two_step_verification_summary\"\n            android:title=\"@string/pref_auth_two_step_verification_title\"\n            app:iconSpaceReserved=\"false\" />\n    </PreferenceCategory>\n</PreferenceScreen>\n"
  },
  {
    "path": "play-services-core/src/main/res/xml/preferences_auth.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <PreferenceScreen\n        android:key=\"k2\"\n        android:title=\"@string/prefs_account_security\">\n        <intent\n            android:action=\"com.google.android.gms.accountsettings.SECURITY_SETTINGS\"\n            android:targetPackage=\"@string/package_id\" />\n    </PreferenceScreen>\n    <PreferenceScreen\n        android:key=\"k3\"\n        android:title=\"@string/prefs_account_privacy\">\n        <intent\n            android:action=\"com.google.android.gms.accountsettings.PRIVACY_SETTINGS\"\n            android:targetPackage=\"@string/package_id\" />\n    </PreferenceScreen>\n    <PreferenceScreen\n        android:key=\"k4\"\n        android:title=\"@string/prefs_account\">\n        <intent\n            android:action=\"com.google.android.gms.accountsettings.ACCOUNT_PREFERENCES_SETTINGS\"\n            android:targetPackage=\"@string/package_id\" />\n    </PreferenceScreen>\n</PreferenceScreen>\n"
  },
  {
    "path": "play-services-core/src/main/res/xml/preferences_device_registration.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2017, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<PreferenceScreen 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\n    <org.microg.gms.ui.SwitchBarPreference\n        android:title=\"@string/checkin_enable_switch\"\n        android:key=\"pref_checkin_enabled\"\n        android:persistent=\"false\" />\n\n    <PreferenceCategory\n        android:key=\"prefcat_device_profile\"\n        android:title=\"@string/pref_device_registration_device_profile_category\"\n        app:iconSpaceReserved=\"false\">\n        <ListPreference\n            android:key=\"pref_device_profile\"\n            android:persistent=\"false\"\n            android:title=\"@string/pref_device_registration_select_profile_title\"\n            tools:summary=\"Automatic (Google Pixel 3, Android 11)\"\n            app:iconSpaceReserved=\"false\" />\n        <Preference\n            android:key=\"pref_device_profile_import\"\n            android:summary=\"@string/pref_device_registration_import_custom_profile_summary\"\n            android:title=\"@string/pref_device_registration_import_custom_profile_title\"\n            app:iconSpaceReserved=\"false\" />\n        <Preference\n            android:enabled=\"false\"\n            android:key=\"pref_device_serial\"\n            android:title=\"@string/pref_device_registration_serial_title\"\n            tools:summary=\"123456\"\n            app:iconSpaceReserved=\"false\" />\n    </PreferenceCategory>\n    <PreferenceCategory\n        android:key=\"prefcat_device_registration_status\"\n        android:layout=\"@layout/preference_category_no_label\"\n        app:iconSpaceReserved=\"false\">\n        <Preference\n            android:enabled=\"false\"\n            android:key=\"pref_device_registration_status\"\n            android:title=\"@string/pref_info_status\"\n            tools:summary=\"Last registration: 13 hours ago\"\n            app:iconSpaceReserved=\"false\" />\n        <Preference\n            android:enabled=\"false\"\n            android:key=\"pref_device_registration_android_id\"\n            android:title=\"@string/pref_device_registration_android_id\"\n            tools:summary=\"1953a59d1c1b7e4b\"\n            app:iconSpaceReserved=\"false\" />\n    </PreferenceCategory>\n    <PreferenceCategory android:layout=\"@layout/preference_category_no_label\">\n        <org.microg.gms.ui.FooterPreference\n            android:selectable=\"false\"\n            android:title=\"@string/pref_checkin_enable_summary\" />\n    </PreferenceCategory>\n</PreferenceScreen>\n"
  },
  {
    "path": "play-services-core/src/main/res/xml/preferences_game_profile.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2025 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n    <org.microg.gms.ui.SwitchBarPreference\n        android:title=\"@string/pref_auto_create_player\"\n        android:key=\"game_allow_create_player\"\n        android:persistent=\"false\" />\n\n    <org.microg.gms.ui.TextPreference\n        android:key=\"pref_game_allow_create_player_summary\"\n        android:selectable=\"false\"\n        app:iconSpaceReserved=\"false\"\n        android:summary=\"@string/pref_auto_create_player_intro\" />\n\n    <PreferenceCategory\n        android:title=\"@string/prefcat_accounts_settings_title\"\n        app:iconSpaceReserved=\"false\">\n        <SwitchPreferenceCompat\n            android:persistent=\"false\"\n            android:key=\"allow_upload_game_played\"\n            android:summary=\"@string/pref_allow_upload_game_played_summary\"\n            android:title=\"@string/pref_allow_upload_game_played\"\n            app:iconSpaceReserved=\"false\" />\n        <Preference\n            android:key=\"pref_change_default_account\"\n            android:summary=\"@string/pref_change_default_game_player_summary\"\n            android:title=\"@string/pref_change_default_game_player\"\n            app:isPreferenceVisible=\"false\"\n            app:iconSpaceReserved=\"false\" />\n        <Preference\n            android:key=\"pref_delete_game_account\"\n            android:summary=\"@string/pref_delete_game_account_data_summary\"\n            android:title=\"@string/pref_delete_game_account_data\"\n            app:isPreferenceVisible=\"false\"\n            app:iconSpaceReserved=\"false\" />\n    </PreferenceCategory>\n\n</PreferenceScreen>\n"
  },
  {
    "path": "play-services-core/src/main/res/xml/preferences_gcm_advanced.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2013 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\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    <SwitchPreferenceCompat\n        android:defaultValue=\"false\"\n        android:persistent=\"false\"\n        android:key=\"gcm_confirm_new_apps\"\n        android:summary=\"@string/pref_gcm_confirm_new_apps_summary\"\n        android:title=\"@string/pref_gcm_confirm_new_apps_title\"\n        app:iconSpaceReserved=\"false\" />\n\n    <PreferenceCategory\n        android:key=\"prefcat_networks\"\n        android:title=\"@string/prefcat_push_networks_title\"\n        app:iconSpaceReserved=\"false\">\n\n        <ListPreference\n            android:defaultValue=\"0\"\n            android:persistent=\"false\"\n            android:entries=\"@array/gcm_network_config_names\"\n            android:entryValues=\"@array/gcm_network_config_values\"\n            android:key=\"gcm_network_mobile\"\n            android:title=\"@string/network_type_mobile\"\n            tools:summary=\"ON / Automatic: 13 min\"\n            app:iconSpaceReserved=\"false\" />\n\n        <ListPreference\n            android:defaultValue=\"0\"\n            android:persistent=\"false\"\n            android:entries=\"@array/gcm_network_config_names\"\n            android:entryValues=\"@array/gcm_network_config_values\"\n            android:key=\"gcm_network_wifi\"\n            android:title=\"@string/network_type_wifi\"\n            tools:summary=\"ON / Manual: 30 min\"\n            app:iconSpaceReserved=\"false\" />\n\n        <ListPreference\n            android:defaultValue=\"0\"\n            android:persistent=\"false\"\n            android:entries=\"@array/gcm_network_config_names\"\n            android:entryValues=\"@array/gcm_network_config_values\"\n            android:key=\"gcm_network_roaming\"\n            android:title=\"@string/network_type_roaming\"\n            tools:summary=\"OFF\"\n            app:iconSpaceReserved=\"false\" />\n\n        <ListPreference\n            android:defaultValue=\"0\"\n            android:persistent=\"false\"\n            android:entries=\"@array/gcm_network_config_names\"\n            android:entryValues=\"@array/gcm_network_config_values\"\n            android:key=\"gcm_network_other\"\n            android:title=\"@string/network_type_other\"\n            tools:summary=\"ON / Automatic: 30 min\"\n            app:iconSpaceReserved=\"false\" />\n\n    </PreferenceCategory>\n</PreferenceScreen>\n"
  },
  {
    "path": "play-services-core/src/main/res/xml/preferences_google_more.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2017 microG Project Team\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<PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <SwitchPreferenceCompat\n        android:defaultValue=\"true\"\n        android:enabled=\"false\"\n        android:key=\"network_google_enabled\"\n        android:summary=\"If disabled, all connections to Google servers usually done by microG will be denied. This overrides service specific settings.\"\n        android:title=\"Allow connecting to Google servers\"/>\n    <SwitchPreferenceCompat\n        android:defaultValue=\"false\"\n        android:dependency=\"network_google_enabled\"\n        android:enabled=\"false\"\n        android:key=\"network_google_use_tor\"\n        android:summary=\"Requires Orbot to be installed\\nNot yet supported\"\n        android:title=\"Connect to Google via Tor network\"/>\n</PreferenceScreen>"
  },
  {
    "path": "play-services-core/src/main/res/xml/preferences_push_notifications.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2020 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\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    android:title=\"Push notifications\">\n\n    <org.microg.gms.ui.SwitchBarPreference\n        android:title=\"@string/gcm_enable_switch\"\n        android:key=\"pref_push_enabled\"\n        android:persistent=\"false\" />\n\n    <PreferenceCategory\n        android:key=\"prefcat_push_apps\"\n        android:title=\"@string/prefcat_push_apps_title\"\n        app:iconSpaceReserved=\"false\">\n        <Preference\n            android:enabled=\"false\"\n            android:key=\"pref_push_apps_none\"\n            android:title=\"@string/list_no_item_none\" />\n        <Preference\n            android:icon=\"@drawable/ic_expand_apps\"\n            android:key=\"pref_push_apps_all\"\n            android:order=\"5\"\n            android:title=\"@string/list_item_see_all\" />\n    </PreferenceCategory>\n    <PreferenceCategory\n        android:key=\"prefcat_push_status\"\n        android:layout=\"@layout/preference_category_no_label\"\n        app:iconSpaceReserved=\"false\">\n        <Preference\n            android:key=\"pref_push_status\"\n            android:enabled=\"false\"\n            android:title=\"@string/pref_info_status\"\n            tools:summary=\"Connected since 15 minutes ago\"\n            app:iconSpaceReserved=\"false\" />\n    </PreferenceCategory>\n    <PreferenceCategory android:layout=\"@layout/preference_category_no_label\">\n        <org.microg.gms.ui.FooterPreference\n            android:selectable=\"false\"\n            android:title=\"@string/pref_gcm_enable_mcs_summary\" />\n    </PreferenceCategory>\n</PreferenceScreen>\n"
  },
  {
    "path": "play-services-core/src/main/res/xml/preferences_push_notifications_all_apps.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2020 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\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    android:title=\"@string/prefcat_push_apps_title\">\n    <Preference\n        android:key=\"pref_push_apps_all_progress\"\n        android:layout=\"@layout/preference_progress_bar\"\n        app:allowDividerBelow=\"false\"\n        app:iconSpaceReserved=\"false\" />\n    <PreferenceCategory\n        android:key=\"prefcat_push_apps_registered\"\n        android:title=\"@string/prefcat_push_apps_registered_title\"\n        app:isPreferenceVisible=\"false\"\n        app:iconSpaceReserved=\"false\"\n        tools:isPreferenceVisible=\"true\">\n        <Preference\n            android:enabled=\"false\"\n            android:key=\"pref_push_apps_registered_none\"\n            android:title=\"@string/list_no_item_none\"\n            app:isPreferenceVisible=\"false\"\n            tools:isPreferenceVisible=\"true\" />\n    </PreferenceCategory>\n    <PreferenceCategory\n        android:key=\"prefcat_push_apps_unregistered\"\n        android:title=\"@string/prefcat_push_apps_unregistered_title\"\n        app:isPreferenceVisible=\"false\"\n        app:iconSpaceReserved=\"false\"\n        tools:isPreferenceVisible=\"true\">\n        <Preference\n            android:enabled=\"false\"\n            android:key=\"pref_push_apps_unregistered_none\"\n            android:title=\"@string/list_no_item_none\"\n            app:isPreferenceVisible=\"false\"\n            tools:isPreferenceVisible=\"true\" />\n    </PreferenceCategory>\n</PreferenceScreen>\n"
  },
  {
    "path": "play-services-core/src/main/res/xml/preferences_push_notifications_app.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2020 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<PreferenceScreen 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\n    <org.microg.gms.ui.AppHeadingPreference\n        android:key=\"pref_push_app_heading\"\n        tools:icon=\"@android:mipmap/sym_def_app_icon\"\n        tools:title=\"@tools:sample/lorem\"\n        app:allowDividerBelow=\"false\" />\n\n    <PreferenceCategory\n        android:key=\"prefcat_push_app_settings\"\n        android:layout=\"@layout/preference_category_no_label\"\n        app:iconSpaceReserved=\"false\">\n\n        <SwitchPreferenceCompat\n            android:defaultValue=\"true\"\n            android:key=\"pref_push_app_allow_register\"\n            android:persistent=\"false\"\n            android:summary=\"@string/pref_push_app_allow_register_summary\"\n            android:title=\"@string/pref_push_app_allow_register_title\"\n            app:iconSpaceReserved=\"false\" />\n\n        <SwitchPreferenceCompat\n            android:defaultValue=\"true\"\n            android:key=\"pref_push_app_wake_for_delivery\"\n            android:persistent=\"false\"\n            android:summary=\"@string/pref_push_app_wake_for_delivery_summary\"\n            android:title=\"@string/pref_push_app_wake_for_delivery_title\"\n            app:iconSpaceReserved=\"false\" />\n\n    </PreferenceCategory>\n\n    <PreferenceCategory\n        android:key=\"prefcat_push_app_unregister\"\n        android:layout=\"@layout/preference_category_no_label\"\n        app:iconSpaceReserved=\"false\">\n        <Preference\n            android:key=\"pref_push_app_unregister\"\n            android:title=\"@string/gcm_unregister_app\"\n            app:iconSpaceReserved=\"false\" />\n    </PreferenceCategory>\n\n    <PreferenceCategory\n        android:layout=\"@layout/preference_category_no_label\"\n        app:iconSpaceReserved=\"false\">\n        <Preference\n            android:key=\"pref_push_app_status\"\n            android:selectable=\"false\"\n            tools:summary=\"Messages: 1000 (37 MB)\\nLast message: 22 min ago\\nRegistered since: 3 month ago\"\n            app:iconSpaceReserved=\"false\" />\n    </PreferenceCategory>\n</PreferenceScreen>\n"
  },
  {
    "path": "play-services-core/src/main/res/xml/preferences_safetynet.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2017 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\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    <org.microg.gms.ui.SwitchBarPreference\n        android:title=\"@string/safetynet_enable_switch\"\n        android:key=\"pref_safetynet_enabled\"\n        android:persistent=\"false\" />\n\n    <PreferenceCategory\n        android:key=\"prefcat_safetynet_apps\"\n        android:title=\"@string/prefcat_safetynet_apps_title\"\n        app:iconSpaceReserved=\"false\">\n        <Preference\n            android:enabled=\"false\"\n            android:key=\"pref_safetynet_apps_none\"\n            android:title=\"@string/list_no_item_none\" />\n        <Preference\n            android:icon=\"@drawable/ic_expand_apps\"\n            android:key=\"pref_safetynet_apps_all\"\n            android:order=\"5\"\n            android:title=\"@string/list_item_see_all\" />\n    </PreferenceCategory>\n    <PreferenceCategory\n        android:layout=\"@layout/preference_category_no_label\"\n        android:dependency=\"pref_safetynet_enabled\">\n        <Preference\n            android:key=\"pref_safetynet_run_attest\"\n            android:title=\"@string/pref_safetynet_test_title\"\n            tools:icon=\"@drawable/ic_circle_check\"\n            tools:summary=\"@string/pref_test_summary_passed\" />\n        <Preference\n            android:key=\"pref_recaptcha_run_test\"\n            android:title=\"@string/pref_recaptcha_test_title\"\n            tools:icon=\"@drawable/ic_circle_check\"\n            tools:summary=\"@string/pref_test_summary_passed\" />\n        <Preference\n            android:key=\"pref_recaptcha_enterprise_run_test\"\n            android:title=\"@string/pref_recaptcha_enterprise_test_title\"\n            tools:icon=\"@drawable/ic_circle_check\"\n            tools:summary=\"@string/pref_test_summary_passed\" />\n    </PreferenceCategory>\n    <PreferenceCategory android:layout=\"@layout/preference_category_no_label\">\n        <Preference\n            app:isPreferenceVisible=\"false\"\n            tools:isPreferenceVisible=\"true\"\n            android:icon=\"@drawable/ic_circle_warn\"\n            android:key=\"pref_droidguard_unsupported\"\n            android:selectable=\"false\"\n            android:summary=\"@string/pref_droidguard_unsupported_summary\" />\n        <org.microg.gms.ui.FooterPreference\n            android:key=\"pref_safetynet_summary\"\n            android:selectable=\"false\"\n            android:title=\"@string/safetynet_intro\" />\n    </PreferenceCategory>\n</PreferenceScreen>\n"
  },
  {
    "path": "play-services-core/src/main/res/xml/preferences_safetynet_advanced.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2017 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<PreferenceScreen 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    <PreferenceCategory\n        android:title=\"DroidGuard\"\n        app:iconSpaceReserved=\"false\">\n        <Preference\n            android:key=\"pref_droidguard_mode\"\n            android:title=\"@string/pref_droidguard_operation_mode\"\n            tools:summary=\"Local (embedded)\"\n            app:iconSpaceReserved=\"false\" />\n    </PreferenceCategory>\n</PreferenceScreen>\n"
  },
  {
    "path": "play-services-core/src/main/res/xml/preferences_safetynet_all_apps.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\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    android:title=\"@string/prefcat_safetynet_apps_title\">\n    <Preference\n        android:key=\"pref_safetynet_apps_all_progress\"\n        android:layout=\"@layout/preference_progress_bar\"\n        app:allowDividerBelow=\"false\" />\n    <PreferenceCategory\n        android:key=\"prefcat_safetynet_apps_all\"\n        android:layout=\"@layout/preference_category_no_label\"\n        app:isPreferenceVisible=\"false\"\n        tools:isPreferenceVisible=\"true\">\n        <Preference\n            android:enabled=\"false\"\n            android:key=\"pref_safetynet_apps_all_none\"\n            android:title=\"@string/list_no_item_none\"\n            app:isPreferenceVisible=\"false\"\n            tools:isPreferenceVisible=\"true\" />\n    </PreferenceCategory>\n</PreferenceScreen>\n"
  },
  {
    "path": "play-services-core/src/main/res/xml/preferences_safetynet_app.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<PreferenceScreen 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\n    <org.microg.gms.ui.AppHeadingPreference\n        android:key=\"pref_safetynet_app_heading\"\n        tools:icon=\"@android:mipmap/sym_def_app_icon\"\n        tools:title=\"@tools:sample/lorem\"\n        app:allowDividerBelow=\"false\" />\n\n    <SwitchPreferenceCompat\n        android:defaultValue=\"true\"\n        android:key=\"pref_device_attestation_app_allow_requests\"\n        android:persistent=\"false\"\n        android:summary=\"@string/pref_device_attestation_app_allow_requests_summary\"\n        android:title=\"@string/pref_device_attestation_app_allow_requests_title\"\n        app:iconSpaceReserved=\"false\"/>\n\n    <PreferenceCategory\n        android:key=\"prefcat_safetynet_recent_list\"\n        android:title=\"@string/pref_safetynet_recent_uses\"\n        app:iconSpaceReserved=\"false\">\n        <Preference\n            android:enabled=\"false\"\n            android:key=\"pref_safetynet_recent_none\"\n            android:title=\"@string/list_no_item_none\" />\n    </PreferenceCategory>\n</PreferenceScreen>\n"
  },
  {
    "path": "play-services-core/src/main/res/xml/preferences_snet_recent_attestation.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\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    <PreferenceCategory\n        android:title=\"@string/pref_safetynet_recent_cat_basic\"\n        app:iconSpaceReserved=\"false\">\n        <Preference\n            android:key=\"pref_request_type\"\n            android:selectable=\"false\"\n            android:title=\"@string/pref_safetynet_recent_request_type\"\n            app:iconSpaceReserved=\"false\"\n            tools:summary=\"ATTESTATION\" />\n\n        <Preference\n            android:key=\"pref_time\"\n            android:selectable=\"false\"\n            android:title=\"@string/pref_safetynet_recent_request_time\"\n            app:iconSpaceReserved=\"false\"\n            tools:summary=\"1970/01/01 1:00 AM\" />\n    </PreferenceCategory>\n\n    <PreferenceCategory\n        android:title=\"@string/pref_safetynet_recent_cat_request\"\n        app:iconSpaceReserved=\"false\">\n\n        <Preference\n            android:key=\"pref_nonce\"\n            android:selectable=\"false\"\n            android:title=\"@string/pref_safetynet_recent_nonce\"\n            app:iconSpaceReserved=\"false\"\n            tools:summary=\"68b329da9893e34099c7d8ad5c\" />\n    </PreferenceCategory>\n\n    <PreferenceCategory\n        android:title=\"@string/pref_safetynet_recent_cat_response\"\n        app:iconSpaceReserved=\"false\">\n        <Preference\n            android:key=\"pref_status\"\n            android:selectable=\"false\"\n            android:title=\"@string/pref_safetynet_recent_response_status\"\n            app:iconSpaceReserved=\"false\"\n            tools:summary=\"CTS failed\" />\n\n        <Preference\n            android:key=\"pref_eval_type\"\n            android:selectable=\"false\"\n            android:title=\"@string/pref_safetynet_recent_eval_type\"\n            app:iconSpaceReserved=\"false\"\n            tools:summary=\"HARDWARE_BACKED\" />\n\n        <Preference\n            android:key=\"pref_advice\"\n            android:selectable=\"false\"\n            android:title=\"@string/pref_safetynet_recent_advice\"\n            app:iconSpaceReserved=\"false\"\n            tools:summary=\"RESTORE_TO_FACTORY_ROM\" />\n\n        <Preference\n            android:key=\"pref_copy_result\"\n            android:title=\"@string/pref_safetynet_recent_copy_json\"\n            app:icon=\"?attr/actionModeCopyDrawable\" />\n    </PreferenceCategory>\n\n</PreferenceScreen>\n"
  },
  {
    "path": "play-services-core/src/main/res/xml/preferences_snet_recent_recaptcha.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<PreferenceScreen 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\n    <PreferenceCategory\n        android:title=\"@string/pref_safetynet_recent_cat_basic\"\n        app:iconSpaceReserved=\"false\">\n        <Preference\n            android:key=\"pref_request_type\"\n            android:title=\"@string/pref_safetynet_recent_request_type\"\n            app:iconSpaceReserved=\"false\"\n            tools:summary=\"RECAPTCHA\" />\n\n        <Preference\n            android:key=\"pref_time\"\n            android:title=\"@string/pref_safetynet_recent_request_time\"\n            app:iconSpaceReserved=\"false\"\n            tools:summary=\"1970/01/01 1:00 AM\" />\n    </PreferenceCategory>\n\n    <PreferenceCategory\n        android:title=\"@string/pref_safetynet_recent_cat_response\"\n        app:iconSpaceReserved=\"false\">\n        <Preference\n            android:key=\"pref_status\"\n            android:title=\"@string/pref_safetynet_recent_response_status\"\n            app:iconSpaceReserved=\"false\"\n            tools:summary=\"Success\" />\n\n        <Preference\n            android:key=\"pref_token\"\n            android:title=\"@string/pref_safetynet_recent_token\"\n            app:iconSpaceReserved=\"false\"\n            tools:summary=\"Success\" />\n\n    </PreferenceCategory>\n\n</PreferenceScreen>\n"
  },
  {
    "path": "play-services-core/src/main/res/xml/preferences_start.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n    <PreferenceCategory android:layout=\"@layout/preference_category_no_label\" android:key=\"prefcat_header\">\n        <Preference\n            android:icon=\"@drawable/ic_check_list\"\n            android:summary=\"@string/self_check_desc\"\n            android:title=\"@string/self_check_title\">\n            <intent\n                android:targetClass=\"org.microg.gms.ui.SelfCheckFragment$AsActivity\"\n                android:targetPackage=\"@string/package_id\" />\n        </Preference>\n    </PreferenceCategory>\n    <PreferenceCategory android:title=\"@string/prefcat_google_services\" android:key=\"prefcat_google_services\">\n        <Preference\n            android:icon=\"@drawable/ic_manage_accounts\"\n            android:key=\"pref_accounts\"\n            android:summary=\"@string/pref_accounts_summary\"\n            android:title=\"@string/pref_accounts_title\" />\n        <Preference\n            android:icon=\"@drawable/ic_device_login\"\n            android:key=\"pref_checkin\"\n            android:title=\"@string/service_name_checkin\" />\n        <Preference\n            android:icon=\"@drawable/ic_cloud_bell\"\n            android:key=\"pref_gcm\"\n            android:title=\"@string/service_name_mcs\" />\n        <Preference\n            android:icon=\"@drawable/ic_certificate\"\n            android:key=\"pref_snet\"\n            android:title=\"@string/service_name_device_attestation\" />\n        <Preference\n            android:icon=\"@drawable/ic_shop\"\n            android:key=\"pref_vending\"\n            android:title=\"@string/service_name_vending\" />\n        <Preference\n            android:icon=\"@drawable/ic_work\"\n            android:key=\"pref_work_profile\"\n            android:title=\"@string/service_name_work_profile\" />\n        <Preference\n            android:icon=\"@drawable/dots_horizontal\"\n            android:key=\"pref_google_more\"\n            android:title=\"@string/pref_more_settings\"\n            app:isPreferenceVisible=\"false\">\n            <intent\n                android:targetClass=\"org.microg.gms.ui.GoogleMoreFragment$AsActivity\"\n                android:targetPackage=\"@string/package_id\" />\n        </Preference>\n    </PreferenceCategory>\n    <PreferenceCategory android:layout=\"@layout/preference_category_no_label\" android:key=\"prefcat_other_services\">\n        <Preference\n            android:icon=\"@drawable/ic_map_marker\"\n            android:key=\"pref_location\"\n            android:title=\"@string/service_name_location\"/>\n    </PreferenceCategory>\n    <PreferenceCategory android:layout=\"@layout/preference_category_no_label\" android:key=\"prefcat_footer\">\n        <Preference\n            android:icon=\"@drawable/ic_info_outline\"\n            android:key=\"pref_about\"\n            android:title=\"@string/pref_about_title\" />\n    </PreferenceCategory>\n</PreferenceScreen>\n"
  },
  {
    "path": "play-services-core/src/main/res/xml/preferences_vending.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2023, e Foundation\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n    <PreferenceCategory\n        android:title=\"@string/pref_vending_licensing_category\"\n        app:iconSpaceReserved=\"false\">\n        <org.microg.gms.ui.TextPreference\n            android:selectable=\"false\"\n            android:summary=\"@string/pref_vending_license_enable_summary\"\n            app:iconSpaceReserved=\"false\" />\n        <SwitchPreferenceCompat\n            android:title=\"@string/pref_vending_licensing_enable_switch\"\n            android:key=\"vending_licensing\"\n            android:persistent=\"false\"\n            app:iconSpaceReserved=\"false\" />\n        <org.microg.gms.ui.TextPreference\n            android:selectable=\"false\"\n            android:summary=\"@string/pref_vending_licensing_purchase_free_apps_summary\"\n            app:iconSpaceReserved=\"false\" />\n        <SwitchPreferenceCompat\n            android:title=\"@string/pref_vending_licensing_purchase_free_apps_switch\"\n            android:key=\"vending_licensing_purchase_free_apps\"\n            android:persistent=\"false\"\n            android:dependency=\"vending_licensing\"\n            app:iconSpaceReserved=\"false\" />\n    </PreferenceCategory>\n\n    <PreferenceCategory\n        android:title=\"@string/pref_vending_billing_category\"\n        app:iconSpaceReserved=\"false\">\n        <org.microg.gms.ui.TextPreference\n            android:selectable=\"false\"\n            android:summary=\"@string/pref_vending_billing_enable_summary\"\n            app:iconSpaceReserved=\"false\" />\n        <org.microg.gms.ui.TextPreference\n            android:icon=\"@drawable/ic_circle_warn\"\n            android:selectable=\"false\"\n            android:summary=\"@string/pref_vending_billing_note_experimental\" />\n        <SwitchPreferenceCompat\n            android:title=\"@string/pref_vending_billing_enable_switch\"\n            android:key=\"vending_iap\"\n            android:persistent=\"false\"\n            app:iconSpaceReserved=\"false\" />\n        <org.microg.gms.ui.TextPreference\n            android:selectable=\"false\"\n            android:summary=\"@string/pref_vending_billing_note_licensing\"\n            app:iconSpaceReserved=\"false\" />\n    </PreferenceCategory>\n\n    <PreferenceCategory\n        android:title=\"@string/pref_vending_feature_delivery\"\n        app:iconSpaceReserved=\"false\">\n        <SwitchPreferenceCompat\n            android:title=\"@string/pref_vending_split_install_switch\"\n            android:key=\"vending_split_install\"\n            android:summary=\"@string/pref_vending_licensing_split_install_summary\"\n            android:persistent=\"false\"\n            android:dependency=\"vending_licensing\"\n            app:iconSpaceReserved=\"false\" />\n    </PreferenceCategory>\n\n    <PreferenceCategory\n        android:title=\"@string/pref_vending_asset_delivery_category\"\n        app:iconSpaceReserved=\"false\">\n        <SwitchPreferenceCompat\n            android:title=\"@string/pref_vending_asset_delivery_switch\"\n            android:summary=\"@string/pref_vending_asset_delivery_summary\"\n            android:key=\"vending_asset_delivery\"\n            android:persistent=\"false\"\n            app:iconSpaceReserved=\"false\" />\n        <SwitchPreferenceCompat\n            android:title=\"@string/pref_vending_asset_device_sync_switch\"\n            android:summary=\"@string/pref_vending_asset_device_sync_summary\"\n            android:key=\"vending_device_sync\"\n            android:persistent=\"false\"\n            app:iconSpaceReserved=\"false\" />\n    </PreferenceCategory>\n</PreferenceScreen>\n"
  },
  {
    "path": "play-services-core/src/main/res/xml/preferences_vending_installer_settings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n    <org.microg.gms.ui.SwitchBarPreference\n        android:title=\"@string/pref_app_install_switch_title\"\n        android:key=\"pref_vending_allow_install_apps\"\n        android:persistent=\"false\" />\n\n    <PreferenceCategory android:layout=\"@layout/preference_category_no_label\">\n        <org.microg.gms.ui.TextPreference\n            android:key=\"pref_permissions_titles\"\n            android:selectable=\"false\"\n            app:iconSpaceReserved=\"false\"\n            android:summary=\"@string/pref_app_install_other_apps_note\" />\n\n        <org.microg.gms.ui.TextPreference\n            android:icon=\"@drawable/ic_circle_warn\"\n            android:selectable=\"false\"\n            android:summary=\"@string/pref_app_install_permission_instruction\" />\n    </PreferenceCategory>\n\n    <PreferenceCategory\n        android:key=\"pref_permission_installer_settings\"\n        android:title=\"@string/prefcat_app_install_list_title\"\n        app:allowDividerAbove=\"false\"\n        app:allowDividerBelow=\"false\"\n        app:iconSpaceReserved=\"false\">\n        <Preference\n            android:enabled=\"false\"\n            android:key=\"pref_permission_installer_none\"\n            app:iconSpaceReserved=\"true\"\n            android:title=\"@string/list_no_item_none\" />\n    </PreferenceCategory>\n\n</PreferenceScreen>"
  },
  {
    "path": "play-services-core/src/main/res/xml/preferences_work_profile.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2023, e Foundation\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n    <org.microg.gms.ui.SwitchBarPreference\n        android:title=\"@string/pref_workprofile_create_account\"\n        android:key=\"workprofile_allow_create_work_account\"\n        android:persistent=\"false\" />\n\n    <org.microg.gms.ui.TextPreference\n        android:key=\"pref_safetynet_summary\"\n        android:selectable=\"false\"\n        app:iconSpaceReserved=\"false\"\n        android:summary=\"@string/pref_workprofile_intro\" />\n\n    <org.microg.gms.ui.TextPreference\n        android:icon=\"@drawable/ic_circle_warn\"\n        android:selectable=\"false\"\n        android:summary=\"@string/pref_workprofile_disclaimer\" />\n\n</PreferenceScreen>\n"
  },
  {
    "path": "play-services-core/src/main/res/xml/profile_bullhead_27.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2021 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<profile name=\"Google Nexus 5X (Android 8.1.0)\" product=\"bullhead\" sdk=\"27\" id=\"bullhead_27\" auto=\"true\">\n    <!-- Data from OPM3.171019.016, Mar 2018 -->\n    <data key=\"Build.BOARD\" value=\"bullhead\" />\n    <data key=\"Build.BOOTLOADER\" value=\"BHZ31b\" />\n    <data key=\"Build.BRAND\" value=\"google\" />\n    <data key=\"Build.CPU_ABI\" value=\"arm64-v8a\" />\n    <data key=\"Build.CPU_ABI2\" value=\"\" />\n    <data key=\"Build.DEVICE\" value=\"bullhead\" />\n    <data key=\"Build.DISPLAY\" value=\"bullhead-user 8.1.0 OPM3.171019.016 4565142 release-keys\" />\n    <data key=\"Build.FINGERPRINT\" value=\"google/bullhead/bullhead:8.1.0/OPM3.171019.016/4565142:user/release-keys\" />\n    <data key=\"Build.HARDWARE\" value=\"bullhead\" />\n    <data key=\"Build.HOST\" value=\"wpdt4.hot.corp.google.com\" />\n    <data key=\"Build.ID\" value=\"OPM3.171019.016\" />\n    <data key=\"Build.MANUFACTURER\" value=\"LGE\" />\n    <data key=\"Build.MODEL\" value=\"Nexus 5X\" />\n    <data key=\"Build.PRODUCT\" value=\"bullhead\" />\n    <data key=\"Build.RADIO\" value=\"unknown\" />\n    <data key=\"Build.TAGS\" value=\"release-keys\" />\n    <data key=\"Build.TIME\" value=\"1516849845000\" />\n    <data key=\"Build.TYPE\" value=\"user\" />\n    <data key=\"Build.USER\" value=\"android-build\" />\n    <data key=\"Build.VERSION.CODENAME\" value=\"REL\" />\n    <data key=\"Build.VERSION.INCREMENTAL\" value=\"6d95f5a143\" />\n    <data key=\"Build.VERSION.RELEASE\" value=\"8.1.0\" />\n    <data key=\"Build.VERSION.SECURITY_PATCH\" value=\"2021-10-05\" />\n    <data key=\"Build.VERSION.SDK\" value=\"27\" />\n    <data key=\"Build.VERSION.SDK_INT\" value=\"27\" />\n    <data key=\"Build.SUPPORTED_ABIS\" value=\"arm64-v8a,armeabi-v7a,armeabi\" />\n\n    <serial template=\"005b56ffff999999\" />\n</profile>\n"
  },
  {
    "path": "play-services-core/src/main/res/xml/profile_lineage_falcon_25.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<profile name=\"Motorola Moto G (LineageOS 14.1)\" product=\"lineage_falcon\" sdk=\"25\" id=\"lineage_falcon_25\" auto=\"true\">\n    <!-- Data from LineageOS 14.1-20190207-NIGHTLY-falcon, Feb 2019 -->\n    <data key=\"Build.BOARD\" value=\"MSM8226\" />\n    <data key=\"Build.BOOTLOADER\" value=\"0x4118\" />\n    <data key=\"Build.BRAND\" value=\"motorola\" />\n    <data key=\"Build.CPU_ABI\" value=\"armeabi-v7a\" />\n    <data key=\"Build.CPU_ABI2\" value=\"armeabi\" />\n    <data key=\"Build.DEVICE\" value=\"falcon_umts\" />\n    <data key=\"Build.DISPLAY\" value=\"lineage_falcon-userdebug 7.1.2 NJH47F f4535aec29\" />\n    <data key=\"Build.FINGERPRINT\" value=\"motorola/falcon_retuglb/falcon_umts:5.1/LPB23.13-58/58:user/release-keys\" />\n    <data key=\"Build.HARDWARE\" value=\"qcom\" />\n    <data key=\"Build.HOST\" value=\"lineage-runner\" />\n    <data key=\"Build.ID\" value=\"NJH47F\" />\n    <data key=\"Build.MANUFACTURER\" value=\"motorola\" />\n    <data key=\"Build.MODEL\" value=\"Moto G\" />\n    <data key=\"Build.PRODUCT\" value=\"lineage_falcon\" />\n    <data key=\"Build.RADIO\" value=\"unknown\" />\n    <data key=\"Build.TAGS\" value=\"release-keys\" />\n    <data key=\"Build.TIME\" value=\"1549548437000\" />\n    <data key=\"Build.TYPE\" value=\"user\" />\n    <data key=\"Build.USER\" value=\"gitlab-runner\" />\n    <data key=\"Build.VERSION.CODENAME\" value=\"REL\" />\n    <data key=\"Build.VERSION.INCREMENTAL\" value=\"f4535aec29\" />\n    <data key=\"Build.VERSION.RELEASE\" value=\"7.1.2\" />\n    <data key=\"Build.VERSION.SECURITY_PATCH\" value=\"2019-01-05\" />\n    <data key=\"Build.VERSION.SDK\" value=\"25\" />\n    <data key=\"Build.VERSION.SDK_INT\" value=\"25\" />\n    <data key=\"Build.SUPPORTED_ABIS\" value=\"armeabi-v7a,armeabi\" />\n\n    <serial template=\"TA9290XXXX\" />\n</profile>\n"
  },
  {
    "path": "play-services-core/src/main/res/xml/profile_sdk_gphone64_arm64_33.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    SPDX-FileCopyrightText: none\n    SPDX-License-Identifier: CC0-1.0\n    SPDX-FileType: SOURCE\n-->\n<profile name=\"Emulator arm64-v8a (Android 13)\" product=\"sdk_gphone64_arm64\" sdk=\"33\" id=\"sdk_gphone64_arm64_33\">\n    <data key=\"Build.BOARD\" value=\"goldfish_arm64\" />\n    <data key=\"Build.BOOTLOADER\" value=\"unknown\" />\n    <data key=\"Build.BRAND\" value=\"google\" />\n    <data key=\"Build.CPU_ABI\" value=\"arm64-v8a\" />\n    <data key=\"Build.CPU_ABI2\" value=\"\" />\n    <data key=\"Build.DEVICE\" value=\"emu64a\" />\n    <data key=\"Build.DISPLAY\" value=\"TE1A.220922.012\" />\n    <data key=\"Build.FINGERPRINT\" value=\"google/sdk_gphone64_arm64/emu64a:13/TE1A.220922.012/9302419:user/release-keys\" />\n    <data key=\"Build.HARDWARE\" value=\"ranchu\" />\n    <data key=\"Build.HOST\" value=\"abfarm-release-2004-0208\" />\n    <data key=\"Build.ID\" value=\"TE1A.220922.012\" />\n    <data key=\"Build.MANUFACTURER\" value=\"Google\" />\n    <data key=\"Build.MODEL\" value=\"sdk_gphone64_arm64\" />\n    <data key=\"Build.PRODUCT\" value=\"sdk_gphone64_arm64\" />\n    <data key=\"Build.RADIO\" value=\"1.0.0.0\" />\n    <data key=\"Build.TAGS\" value=\"release-keys\" />\n    <data key=\"Build.TIME\" value=\"1668654818000\" />\n    <data key=\"Build.TYPE\" value=\"user\" />\n    <data key=\"Build.USER\" value=\"android-build\" />\n    <data key=\"Build.VERSION.CODENAME\" value=\"REL\" />\n    <data key=\"Build.VERSION.INCREMENTAL\" value=\"9302419\" />\n    <data key=\"Build.VERSION.RELEASE\" value=\"13\" />\n    <data key=\"Build.VERSION.SECURITY_PATCH\" value=\"2022-11-05\" />\n    <data key=\"Build.VERSION.SDK\" value=\"33\" />\n    <data key=\"Build.VERSION.SDK_INT\" value=\"33\" />\n    <data key=\"Build.VERSION.DEVICE_INITIAL_SDK_INT\" value=\"33\" />\n    <data key=\"Build.SUPPORTED_ABIS\" value=\"arm64-v8a\" />\n\n    <serial template=\"\" />\n</profile>\n"
  },
  {
    "path": "play-services-core/src/main/res/xml/profile_sdk_gphone64_x86_64_33.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    SPDX-FileCopyrightText: none\n    SPDX-License-Identifier: CC0-1.0\n    SPDX-FileType: SOURCE\n-->\n<profile name=\"Emulator x86_64 (Android 13)\" product=\"sdk_gphone64_x86_64\" sdk=\"33\" id=\"sdk_gphone64_x86_64_33\">\n    <data key=\"Build.BOARD\" value=\"goldfish_x86_64\" />\n    <data key=\"Build.BOOTLOADER\" value=\"unknown\" />\n    <data key=\"Build.BRAND\" value=\"google\" />\n    <data key=\"Build.CPU_ABI\" value=\"x86_64\" />\n    <data key=\"Build.CPU_ABI2\" value=\"\" />\n    <data key=\"Build.DEVICE\" value=\"emu64x\" />\n    <data key=\"Build.DISPLAY\" value=\"TE1A.220922.010\" />\n    <data key=\"Build.FINGERPRINT\" value=\"google/sdk_gphone64_x86_64/emu64x:13/TE1A.220922.010/9219351:user/release-keys\" />\n    <data key=\"Build.HARDWARE\" value=\"ranchu\" />\n    <data key=\"Build.HOST\" value=\"abfarm-release-2004-0186\" />\n    <data key=\"Build.ID\" value=\"TE1A.220922.010\" />\n    <data key=\"Build.MANUFACTURER\" value=\"Google\" />\n    <data key=\"Build.MODEL\" value=\"sdk_gphone64_x86_64\" />\n    <data key=\"Build.PRODUCT\" value=\"sdk_gphone64_x86_64\" />\n    <data key=\"Build.RADIO\" value=\"1.0.0.0\" />\n    <data key=\"Build.TAGS\" value=\"release-keys\" />\n    <data key=\"Build.TIME\" value=\"1666763706000\" />\n    <data key=\"Build.TYPE\" value=\"user\" />\n    <data key=\"Build.USER\" value=\"android-build\" />\n    <data key=\"Build.VERSION.CODENAME\" value=\"REL\" />\n    <data key=\"Build.VERSION.INCREMENTAL\" value=\"9219351\" />\n    <data key=\"Build.VERSION.RELEASE\" value=\"13\" />\n    <data key=\"Build.VERSION.SECURITY_PATCH\" value=\"2022-11-05\" />\n    <data key=\"Build.VERSION.SDK\" value=\"33\" />\n    <data key=\"Build.VERSION.SDK_INT\" value=\"33\" />\n    <data key=\"Build.VERSION.DEVICE_INITIAL_SDK_INT\" value=\"33\" />\n    <data key=\"Build.SUPPORTED_ABIS\" value=\"x86_64\" />\n\n    <serial template=\"\" />\n</profile>\n"
  },
  {
    "path": "play-services-core-proto/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.squareup.wire'\napply plugin: 'kotlin'\n\ndependencies {\n    implementation \"com.squareup.wire:wire-runtime:$wireVersion\"\n    api \"com.squareup.wire:wire-grpc-client:$wireVersion\"\n}\n\nwire {\n    kotlin {\n        javaInterop = true\n    }\n}\n\nsourceSets {\n    main.java.srcDirs += \"$buildDir/generated/source/wire\"\n}\n\ncompileJava {\n    sourceCompatibility = 1.8\n    targetCompatibility = 1.8\n}\n\ncompileKotlin {\n    kotlinOptions.jvmTarget = 1.8\n}\n\ncompileTestKotlin {\n    kotlinOptions.jvmTarget = 1.8\n}\n"
  },
  {
    "path": "play-services-core-proto/src/main/proto/apitoken.proto",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage google.internal.maps.mapsmobilesdks.v1;\n\noption java_outer_classname = \"ApiTokenProto\";\noption java_package = \"com.google.android.gms.maps.auth\";\noption java_multiple_files = true;\n\nservice MapsMobileSDKsService {\n  rpc CreateAndroidApiToken (ApiTokenRequestWrapper) returns (CreateAndroidApiTokenResponse);\n}\n\nmessage ApiTokenRequest {\n  optional string apiKey = 1;\n  optional string fingerprint = 2;\n  optional string packageName = 3;\n  optional int64 expiryTimeMillis = 4;\n}\n\nmessage ApiTokenRequestWrapper {\n  optional ApiTokenRequest request = 1;\n}\n\nmessage CreateAndroidApiTokenResponse {\n  optional string apiToken = 1;\n  optional int64 expiryTime = 2;\n  optional int64 durationTime = 3;\n}"
  },
  {
    "path": "play-services-core-proto/src/main/proto/appcert.proto",
    "content": "option java_package = \"org.microg.gms.auth.appcert\";\noption java_outer_classname = \"AppCertProto\";\n\nmessage DeviceKeyRequest {\n    optional string droidGuardResult = 1;\n    optional uint64 androidId = 2;\n    optional uint64 sessionId = 3;\n    message VersionInfo {\n        optional fixed32 sdkVersion = 1;\n        optional fixed32 gmsVersion = 2;\n    }\n    optional VersionInfo versionInfo = 4;\n    optional string token = 6;\n}\n\nmessage DeviceKey {\n    optional uint64 keyId = 1;\n    optional uint64 deviceId = 3;\n    optional bytes macSecret = 4;\n    optional bytes keyCert = 5;\n}\n\nmessage SpatulaHeaderProto {\n    message PackageInfo {\n        optional string packageName = 1;\n        optional string packageCertificateHash = 3;\n    }\n    optional PackageInfo packageInfo = 1;\n    optional bytes hmac = 2;\n    optional uint64 deviceId = 3;\n    optional uint64 keyId = 4;\n    optional bytes keyCert = 5;\n}\n"
  },
  {
    "path": "play-services-core-proto/src/main/proto/auth.proto",
    "content": "option java_package = \"org.microg.gms.auth\";\n\noption java_outer_classname = \"AuthProto\";\n\nmessage ConsentData {\n    message AppDetails {\n        optional string title = 1;\n        optional string email = 3;\n    }\n    optional AppDetails app = 1;\n    message ScopeDetails {\n        optional string title = 1;\n        optional string description = 2;\n        optional string id = 6;\n    }\n    repeated ScopeDetails scopes = 2;\n}\n\nmessage RequestOptions {\n//    optional bool field_1 = 1;\n//    optional string field_2 = 2;\n//    optional string field_3 = 3;\n//    optional int32 field_4 = 4;\n//    optional int32 field_5 = 5;\n    optional int32 remote = 7;\n    optional NonceWrapper nonceWrapper = 8;\n    optional int32 version = 10;\n    optional string sessionId = 11;\n//    optional bool field_12 = 12;\n}\n\nmessage NonceWrapper {\n    optional string nonce = 1;\n}\n\nmessage ConsentUrlResponse {\n    optional int32 resultCode = 2;\n    optional string consentUrl = 3;\n    optional Cookie cookie = 4;\n}\n\nmessage ConsentCookiesResponse {\n    optional ConsentCookies consentCookies = 1;\n}\n\nmessage ConsentCookies {\n    optional int32 resultCode = 1;\n    repeated Cookie cookies = 2;\n}\n\nmessage Cookie {\n    optional string cookieName = 1;\n    optional string cookieValue = 2;\n    optional string domain = 3;\n    optional string path = 4;\n    optional int64 sameSite = 5;\n    optional int64 secure = 6;\n    optional int64 httpOnly = 7;\n    optional int64 maxAge = 8;\n    optional int64 version = 9;\n    optional string discard = 10;\n    optional string comment = 12;\n}\n\nmessage ItAuthData {\n    optional bytes auth = 1;\n    repeated bytes tokens = 2;\n    optional bytes signature = 3;\n}\n\nmessage ItMetadataData {\n    message ScopeEntry {\n        repeated string name = 1;\n        optional int32 id = 2;\n    }\n    repeated ScopeEntry entries = 1;\n    optional TokenField field = 3;\n    optional int32 liveTime = 4;\n}\n\nmessage TokenField {\n    enum FieldType {\n        UNKNOWN = 0;\n        SCOPE = 1;\n        EXPIRATION = 2;\n    }\n    repeated FieldType types = 1 [packed = true];\n}\n\nmessage OAuthAuthorization {\n    repeated int32 scopeIds = 1 [packed = true];\n    optional int32 effectiveDurationSeconds = 2;\n}\n\nmessage OAuthTokenData {\n    optional int32 fieldType = 1;\n    optional bytes authorization = 2;\n    optional int32 durationMillis = 3;\n}"
  },
  {
    "path": "play-services-core-proto/src/main/proto/checkin.proto",
    "content": "option java_package = \"org.microg.gms.checkin\";\n\noption java_outer_classname = \"CheckinProto\";\n\nimport \"deviceconfig.proto\";\n\n// Sample data, if provided, is fished from a Nexus 7 (2013) / flo running Android 5.0\nmessage CheckinRequest {\n    // unused\n    optional string imei = 1;\n\n    // Gservices[\"android_id\"] or 0 on first-checkin\n    optional int64 androidId = 2;\n\n    // Gservices[\"digest\"] or \"\"\n    optional string digest = 3;\n\n    required Checkin checkin = 4;\n    message Checkin {\n        // empty Build on pre-checkin\n        required Build build = 1;\n        message Build {\n            // Build.FINGERPRINT\n            // eg. google/razor/flo:5.0.1/LRX22C/1602158:user/release-keys\n            optional string fingerprint = 1;\n\n            // Build.HARDWARE\n            // eg. flo\n            optional string hardware = 2;\n\n            // Build.BRAND\n            // eg. google\n            optional string brand = 3;\n\n            // Build.getRadioVersion()\n            optional string radio = 4;\n\n            // Build.BOOTLOADER\n            // eg. FLO-04.04\n            optional string bootloader = 5;\n\n            // GoogleSettingsContract.Partner[\"client_id\"]\n            // eg. android-google\n            optional string clientId = 6;\n\n            // Build.TIME / 1000L\n            // eg. 1416533192\n            optional int64 time = 7;\n\n            // PackageInfo.versionCode\n            // eg. 6188736\n            optional int32 packageVersionCode = 8;\n\n            // Build.DEVICE\n            // eg. flo\n            optional string device = 9;\n\n            // Build.VERSION.SDK_INT\n            // eg. 21\n            optional int32 sdkVersion = 10;\n\n            // Build.MODEL\n            // eg. Nexus 7\n            optional string model = 11;\n\n            // Build.MANUFACTURER\n            // eg. asus\n            optional string manufacturer = 12;\n\n            // Build.PRODUCT\n            // eg. razor\n            optional string product = 13;\n\n            // fileExists(\"/system/recovery-from-boot.p\")\n            // eg. false\n            optional bool otaInstalled = 14;\n        }\n\n        // last checkin ms or 0 if first checkin\n        // eg. 0\n        optional int64 lastCheckinMs = 2;\n\n        // eg. (\"event_log_start\",~,1424612602652) on first checkin\n        repeated Event event = 3;\n        message Event {\n            optional string tag = 1;\n            optional string value = 2;\n            optional int64 timeMs = 3;\n        }\n\n        // unknown, n/a on first checkin\n        repeated Statistic stat = 4;\n        message Statistic {\n            required string tag = 1;\n            optional int32 count = 2;\n            optional float sum = 3;\n        }\n\n        // unused\n        repeated string requestedGroup = 5;\n\n        // TelephonyManager.getNetworkOperator != null|empty\n        optional string cellOperator = 6;\n\n        // TelephonyManager.getSimOperator != null|empty\n        optional string simOperator = 7;\n\n        // \"WIFI::\" | (\"mobile\" | \"notmobile\" | \"unknown\") + \"-\" + (\"roaming\" | \"notroaming\" | \"unknown\")\n        optional string roaming = 8;\n\n        // UserHandle.myUserId\n        // eg. 0\n        optional int32 userNumber = 9;\n    }\n\n    // unused\n    optional string desiredBuild = 5;\n\n    // Locale.toString\n    optional string locale = 6;\n\n    // GoogleSettingsContract.Partner[\"logging_id2\"] (choosen randomly on first checkin)\n    // eg. 12561488293572742346\n    optional int64 loggingId = 7;\n\n    // unused\n    optional string marketCheckin = 8;\n\n    // NetworkInfo.getExtraInfo, WifiInfo.getMacAddress (12 hex-digits)\n    // eg. d850e6abcdef\n    repeated string macAddress = 9;\n\n    // TelephonyManager.getDeviceId (14 hex-digits), not set on tablets\n    optional string meid = 10;\n\n    // \"[<email>]\" followed by \"<authToken>\", empty string on first checkin\n    repeated string accountCookie = 11;\n\n    // TimeZone.getId\n    // eg. GMT\n    optional string timeZone = 12;\n\n    // security token as given on first checkin, not set on first checkin\n    optional fixed64 securityToken = 13;\n\n    // use 3\n    optional int32 version = 14;\n\n    // SHA-1 of each in /system/etc/security/otacerts.zip or \"--IOException--\" or \"--no-output--\"\n    // eg. dKXTm1QH9QShGQwBM/4rg6/lCNQ=\n    repeated string otaCert = 15;\n\n    // Build.SERIAL != \"unknown\"\n    // eg. 07d90b18\n    optional string serial = 16;\n\n    // TelephonyManager.getDeviceId (8 hex-digits), not set on tablets\n    optional string esn = 17;\n\n    optional DeviceConfig deviceConfiguration = 18;\n\n    // \"ethernet\" or \"wifi\"\n    repeated string macAddressType = 19;\n\n    // unknown, use 0 on pre- and first-checkin, and 1 for later checkins\n    // also present on pre-checkin\n    required int32 fragment = 20;\n\n    // unknown\n    optional string userName = 21;\n\n    // UserManager.getUserSerialNumber\n    // eg. 0\n    optional int32 userSerialNumber = 22;\n}\n\nmessage CheckinResponse {\n    optional bool statsOk = 1;\n    repeated Intent intent = 2;\n    message Intent {\n        optional string action = 1;\n        optional string dataUri = 2;\n        optional string mimeType = 3;\n        optional string javaClass = 4;\n        repeated Extra extra = 5;\n        message Extra {\n            optional string name = 6;\n            optional string value = 7;\n        }\n    }\n    optional int64 timeMs = 3;\n    optional string digest = 4;\n    repeated GservicesSetting setting = 5;\n    message GservicesSetting {\n        optional bytes name = 1;\n        optional bytes value = 2;\n    }\n    optional bool marketOk = 6;\n    optional fixed64 androidId = 7;\n    optional fixed64 securityToken = 8;\n    optional bool settingsDiff = 9;\n    repeated string deleteSetting = 10;\n    optional string versionInfo = 11;\n    optional string deviceDataVersionInfo = 12;\n}\n"
  },
  {
    "path": "play-services-core-proto/src/main/proto/controlsettings.proto",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\noption java_outer_classname = \"ControlsSettings\";\n\noption java_package = \"org.microg.gms.udc\";\noption java_multiple_files = true;\n\nmessage ActivityControlsSettings {\n    repeated ActivityControlItem items = 1;\n    optional GlobalSettings global = 2;\n}\n\nmessage ActivityControlItem {\n    optional int32 id = 1;\n    optional int32 enabled = 2;\n    optional int32 allowed = 3;\n    optional int32 forced = 4;\n}\n\nmessage GlobalSettings {\n    optional int32 enabled = 1;\n    optional int32 allowed = 2;\n}"
  },
  {
    "path": "play-services-core-proto/src/main/proto/cryptauth/LICENSE",
    "content": "// Copyright 2015 The Chromium Authors\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//    * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//    * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//    * Neither the name of Google LLC nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "play-services-core-proto/src/main/proto/cryptauth/cryptauth_better_together_device_metadata.proto",
    "content": "/* SPDX-FileCopyrightText: 2014 The Chromium Authors\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\nsyntax = \"proto3\";\n\npackage cryptauthv2;\n\noption optimize_for = LITE_RUNTIME;\n\n//--------------------- ATTENTION ------------------------\n// If you chamge this file please change \n// j/c/g/android/gms/auth_proximity/proto/cryptauth_better_together_feature_metadata.proto\n// as well.\n\n\n// A seed used to feed an EID BLE advertisement for some time period.\n// Next ID: 4\nmessage BeaconSeed {\n  // The beacon seed bytes.\n  bytes data = 1;\n\n  // The time at which this key becomes active.\n  int64 start_time_millis = 2;\n\n  // The time at which this key becomes inactive.\n  int64 end_time_millis = 3;\n}\n\n// Data required to verify the remote device.\n// Next ID: 3\nmessage AttestationData {\n  enum Type {\n    UNKNOWN = 0;\n\n    // A Chrome OS \"soft-bind\" certificate chain.\n    // The |certificates| field holds a PEM encoded X.509 certificate chain\n    // ordered from leaf to root.\n    CROS_SOFT_BIND_CERT_CHAIN = 1;\n  }\n\n  Type type = 1;\n\n  // The certificate data as specified by |type|.\n  repeated bytes certificates = 2;\n}\n\n// Device metadata relevant to the suite of multi-device (Better Together)\n// features. This data is sent to and received from CryptAuth--using end-to-end\n// encryption--as part of DeviceSync v2.\n// Next ID: 5\nmessage BetterTogetherDeviceMetadata {\n  // A cryptographic public key associated with the device.\n  // The format of this key is a serialized SecureMessage.GenericPublicKey.\n  bytes public_key = 1;\n\n  // A device model name that's guaranteed not to contain any PII.\n  string no_pii_device_name = 2;\n\n  // A list of seeds for EID BLE advertisements targeting this device.\n  repeated BeaconSeed beacon_seeds = 3;\n\n  // Bluetooth public address, formatted as a hex string with colons and capital\n  // letters. Example: \"01:23:45:67:89:AB\"\n  string bluetooth_public_address = 4;\n\n  // Attestation data associated with this device.\n  AttestationData attestation_data = 5;\n}"
  },
  {
    "path": "play-services-core-proto/src/main/proto/cryptauth/cryptauth_better_together_feature_metadata.proto",
    "content": "/* SPDX-FileCopyrightText: 2014 The Chromium Authors\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\n// This message fills the |metadata| bytes field of the FeatureMetadata message\n// (found in the file cryptauth_client_app_metadata.proto) when |feature_type|\n// is FeatureMetadata::Feature::BETTER_TOGETHER.\nsyntax = \"proto3\";\n\npackage cryptauthv2;\n\noption optimize_for = LITE_RUNTIME;\n\nmessage BetterTogetherFeatureMetadata {\n  enum FeatureName {\n    UNKNOWN_FEATURE = 0;\n    BETTER_TOGETHER_HOST = 1;\n    BETTER_TOGETHER_CLIENT = 2;\n    EASY_UNLOCK_HOST = 3;\n    EASY_UNLOCK_CLIENT = 4;\n    MAGIC_TETHER_HOST = 5;\n    MAGIC_TETHER_CLIENT = 6;\n    SMS_CONNECT_HOST = 7;\n    SMS_CONNECT_CLIENT = 8;\n    PHONE_HUB_HOST = 9;\n    PHONE_HUB_CLIENT = 10;\n    WIFI_SYNC_HOST = 11;\n    WIFI_SYNC_CLIENT = 12;\n    ECHE_HOST = 13;\n    ECHE_CLIENT = 14;\n    PHONE_HUB_CAMERA_ROLL_HOST = 15;\n    PHONE_HUB_CAMERA_ROLL_CLIENT = 16;\n  }\n\n  repeated FeatureName supported_features = 1;\n  repeated FeatureName enabled_features = 2;\n}\n"
  },
  {
    "path": "play-services-core-proto/src/main/proto/cryptauth/cryptauth_client_app_metadata.proto",
    "content": "/* SPDX-FileCopyrightText: 2014 The Chromium Authors\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\n// Client-specific metadata used in the CryptAuth v2 Enrollment protocol, which\n// is serialized and held in |client_app_metadata| of SyncKeysRequest (in file\n// cryptauth_enrollment.proto).\nsyntax = \"proto3\";\n\npackage cryptauthv2;\n\noption optimize_for = LITE_RUNTIME;\n\n// Client specific metadata contained in SyncKeysRequest.client_app_metadata.\n// Next id: 31\nmessage ClientAppMetadata {\n  // App specific metadata from the device. On Android, these should be common\n  // for all the features as they come from GmsCore, however, on IOS and other\n  // devices, there could be multiple apps with the feature.\n  repeated ApplicationSpecificMetadata application_specific_metadata = 1;\n\n  // Subgrouping of device identifiers.\n  // Instance ID: See more info at go/gcm-in-gmscore and\n  // https://g3doc.corp.google.com/java/com/google/wireless/android/iid/g3doc/index.md?cl=head\n  string instance_id = 2;\n  // Token to authenticate the instance ID.\n  string instance_id_token = 3;\n  // Checkin android id of the device.\n  fixed64 android_device_id = 4;\n  // Chrome and iOS use a UUID in the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\n  // Where x is a lowercase hex digit.\n  // For iOS, this UUID is the IDFV.\n  // For backward compatibility with some Chrome long_device_ids, this can also\n  // be something else.\n  // For the same reason, this field is case sensitive, even with valid UUIDs.\n  string long_device_id = 5;\n\n  // Subgrouping of device features field. These help in targeting specific\n  // class of devices, for ex: Tablets vs phones etc.\n  // Locale of the device.\n  string locale = 6;\n  // The Operating System version.\n  string device_os_version = 7;\n  // The Operating System version number on the device.\n  int64 device_os_version_code = 8;\n  // The Operating system release on the device.\n  string device_os_release = 9;\n  // The Operating system codename on the device.\n  string device_os_codename = 10;\n  // Size of the display in thousandths of an inch (e.g. 7000 mils = 7 in)\n  int32 device_display_diagonal_mils = 11;\n  // Device's model name (e.g., an android.os.Build.MODEL)\n  string device_model = 12;\n  // The device manufacturer name.\n  string device_manufacturer = 13;\n  // The type of device this is.\n  enum DeviceType {\n    UNKNOWN = 0;\n    ANDROID = 1;\n    CHROME = 2;\n    IOS = 3;\n    BROWSER = 4;\n    OSX = 5;\n  }\n  DeviceType device_type = 14;\n\n  // Subgrouping of lock screen related fields. Used by many identity features.\n  // Is this device using a secure screenlock (e.g., a pattern or pin unlock).\n  bool using_secure_screenlock = 15;\n  // Is auto-unlocking the screenlock supported ?\n  bool auto_unlock_screenlock_supported = 16;\n  // Is auto-unlocking the screenlock (e.g., when at \"home\") enabled ?\n  bool auto_unlock_screenlock_enabled = 17;\n\n  // Subgrouping of bluetooth state related fields on the device. Used by many\n  // features.\n  // Does the device have a Bluetooth (classic) radio?\n  bool bluetooth_radio_supported = 18;\n  // Is the Bluetooth (classic) radio on?\n  bool bluetooth_radio_enabled = 19;\n  // Does the device have a ble radio?\n  bool ble_radio_supported = 20;\n\n  // Does the device hardware support a mobile data connection?\n  bool mobile_data_supported = 21;\n  // Does the device support tethering ?\n  bool tethering_supported = 22;\n  // If a feature wants to upload some metadata common to all its keys.\n  repeated FeatureMetadata feature_metadata = 23;\n\n  // Bluetooth address for EasyUnlock.\n  string bluetooth_address = 24;\n\n  // Is the device a \"Pixel Experience\" Android device?\n  bool pixel_experience = 25;\n  // Is the device running in the ARC++ container on a chromebook?\n  bool arc_plus_plus = 26;\n  // Does the device support user presence that is backed by hardware\n  // (unspoofable by malware)?\n  bool hardware_user_presence_supported = 27;\n  // Does the device support user verification (E.g., passcode, biometrics)?\n  bool user_verification_supported = 28;\n  // Does the device support creating a key in trusted execution environment?\n  bool trusted_execution_environment_supported = 29;\n  // Does the device support creating a key in a dedicated secure element\n  // hardware?\n  bool dedicated_secure_element_supported = 30;\n\n  // The response blob generated by the DroidGuard client on the device.\n  string droid_guard_response = 31;\n}\n\n// Metadata that's app specific.\n// Next id: 6\nmessage ApplicationSpecificMetadata {\n  // Used for device_address of DeviceInfo field 2, but for GCM capable devices.\n  bytes gcm_registration_id = 1;\n  // Does the user have notifications enabled for the given device address.\n  bool notification_enabled = 2;\n  // The software version running on the device.\n  string device_software_version = 3;\n  // The software version number running on the device.\n  int64 device_software_version_code = 4;\n  // Software package information if applicable.\n  string device_software_package = 5;\n  // Whether the user has Bluetooth enabled for the given device address.\n  bool bluetooth_enabled = 6;\n}\n\n// Metadata which is same for different keys belonging to a particular feature.\nmessage FeatureMetadata {\n  enum Feature {\n    UNKNOWN = 0;\n    AUTHZEN = 1;\n    BETTER_TOGETHER = 2;\n  }\n  Feature feature_type = 1;\n  bytes metadata = 2;\n}\n"
  },
  {
    "path": "play-services-core-proto/src/main/proto/cryptauth/cryptauth_common.proto",
    "content": "/* SPDX-FileCopyrightText: 2014 The Chromium Authors\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\n// Contains messages and data types used by request, response, and directive\n// messages in the CryptAuth v2 Enrollment protocol.\nsyntax = \"proto3\";\n\npackage cryptauthv2;\n\noption optimize_for = LITE_RUNTIME;\n\n// The types of cryptographic keys that are supported.\nenum KeyType {\n  // Default value. Don't use!\n  KEY_TYPE_UNSPECIFIED = 0;\n\n  // 16-byte random byte string\n  RAW128 = 1;\n  // 32-byte random byte string\n  RAW256 = 2;\n  // Curve25519\n  CURVE25519 = 3;\n  // P256\n  P256 = 4;\n\n  // The key will be provided by the application.\n  CUSTOM = 127;\n}\n\n// The generic format for public-key certificates.\nmessage Certificate {\n  // The identifier bound to the cert, e.g., an email address or phone number.\n  string common_name = 1;\n  // The raw bytes of the public key.\n  bytes public_key = 2;\n  // The UNIX timestamp when the cert will expire.\n  int64 expire_time_millis = 3;\n\n  // A restriction imposed on the applications using this key.\n  // Claims are validated along with the signature, when this key is used.\n  message Claim {\n    // Claim name.\n    string name = 1;\n    // Whether this claim is critical in the certificate. If it is critical,\n    // the client must fail the validation of the certificate if the client does\n    // not recognize the name of the claim.\n    bool critical = 2;\n    // Claim value.\n    bytes value = 3;\n  }\n  // All claims associated with the use of this key.\n  repeated Claim claims = 4;\n\n  // The signature over all of the above.\n  bytes signature = 5;\n}\n\n// Uniquely identifies a server-side policy instance, which is associated with a\n// key or a client. Subset of this policy is communicated to the client and\n// referenced using this message.\n// A set of related policies are identified by a name. Every time the policy\n// changes, it gets a new unique version number to distinguish it from the\n// policy instance it is based on. Together, following fields uniquely identify\n// a policy instance.\nmessage PolicyReference {\n  // The name of the policy.\n  string name = 1;\n\n  // The version of the policy.\n  int64 version = 2;\n}\n\n// The client-specific metadata contained in SyncKeysRequest.\n//\n// Note: This message is encoded as query parameters for some requests. If any\n// field or subfield of this proto changes, update the files\n// cryptauth_proto_to_query_parameters_util.{h,cc}.\nmessage ClientMetadata {\n  // The counter for how many times the request has been retried.\n  int64 retry_count = 1;\n\n  // The reason why the request has been invoked.\n  enum InvocationReason {\n    // Unspecified invocation reason.\n    INVOCATION_REASON_UNSPECIFIED = 0;\n\n    // First run of the software package invoking this call.\n    INITIALIZATION = 1;\n    // Ordinary periodic actions (e.g., monthly key rotation).\n    PERIODIC = 2;\n    // Slow-cycle periodic action (e.g., yearly keypair rotation).\n    SLOW_PERIODIC = 3;\n    // Fast-cycle periodic action (e.g., daily sync for Smart Lock users).\n    FAST_PERIODIC = 4;\n\n    // Expired state (e.g., expired credentials, or cached entries) was\n    // detected.\n    EXPIRATION = 5;\n    // An unexpected protocol failure occurred (so attempting to repair state).\n    FAILURE_RECOVERY = 6;\n\n    // A new account has been added to the device.\n    NEW_ACCOUNT = 7;\n    // An existing account on the device has been changed.\n    CHANGED_ACCOUNT = 8;\n\n    // The user toggled the state of a feature (e.g., Smart Lock enabled via\n    // bluetooth).\n    FEATURE_TOGGLED = 9;\n    // A \"push\" from the server caused this action (e.g., a sync tickle).\n    SERVER_INITIATED = 10;\n\n    // A local address change triggered this (e.g., GCM registration id\n    // changed).\n    ADDRESS_CHANGE = 11;\n    // A software update has triggered this.\n    SOFTWARE_UPDATE = 12;\n\n    // A manual action by the user triggered this (e.g., commands sent via adb).\n    MANUAL = 13;\n\n    // A custom key has been invalidated on the device (e.g. screen lock is\n    // disabled).\n    CUSTOM_KEY_INVALIDATION = 14;\n\n    // Periodic action triggered by auth_proximity\n    PROXIMITY_PERIODIC = 15;\n  }\n  // Reason for invocation.\n  InvocationReason invocation_reason = 2;\n\n  // Whether the platform has hardware supports for certain algorithms.\n  message CryptoHardware {\n    // AES-128\n    bool aes128 = 1;\n    // ASE-256\n    bool aes256 = 2;\n    // Carryless multiplication\n    bool clmul = 3;\n    // Curve25519\n    bool curve25519 = 4;\n    // P256\n    bool p256 = 5;\n  }\n  // Crypto hardware available on the client.\n  CryptoHardware crypto_hardware = 3;\n\n  // If the request is issued as a direct result, or a follow-up for a\n  // notification/tickle, the session_id from that notification.\n  string session_id = 4;\n}\n\n// Identifies Cryptauth services.\nenum TargetService {\n  // Unspecified Cryptauth service.\n  TARGET_SERVICE_UNSPECIFIED = 0;\n\n  // Cryptauth Enrollment.\n  ENROLLMENT = 1;\n\n  // Cryptauth DeviceSync.\n  DEVICE_SYNC = 2;\n}\n"
  },
  {
    "path": "play-services-core-proto/src/main/proto/cryptauth/cryptauth_devicesync.proto",
    "content": "/* SPDX-FileCopyrightText: 2014 The Chromium Authors\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\n// Contains the request and response messages used in the CryptAuth v2\n// DeviceSync protocol. Specifically,\n//\n// -- SyncMetadata --\n// * Request: The device sends its metadata to CryptAuth, some of it encrypted\n//     with the the device's version of the group public key. This version of\n//     the group public key is also sent in the request.\n// * Response: If CryptAuth can confirm that the device is in possession of the\n//     correct group public key, then CryptAuth returns metadata for the user's\n//     devices in the DeviceSync group. The group public key and/or the\n//     encrypted group private key might also be returned.\n//\n// -- ShareGroupPrivateKey --\n// * Request: The device shares the group private key by encrypting it with the\n//     public key of the user's other devices. These encrypted group private\n//     keys are persisted by CryptAuth for the other devices to retrieve as\n//     necessary.\n// * Response: Trivial\n//\n// -- BatchNotifyGroupDevices --\n// * Request: The client sends a list of the devices that it wants to tickle via\n//     a GCM message.\n// * Response: Trivial\n//\n// -- BatchGetFeatureStatuses --\n// * Request: The client queries CryptAuth for the state of features on the\n//     user's devices, for example, whether or not Magic Tether is enabled on\n//     any of the user's phones.\n// * Response: The query results.\n//\n// -- BatchSetFeatureStatuses --\n// * Request: The client requests CryptAuth to set the state of various features\n//     for the user's devices. Optionally, features can be enabled exclusively,\n//     meaning enabled on one device and disabled on all others.\n// * Response: Trivial\n//\n// -- GetDevicesActivityStatus --\n// * Request: Trivial\n// * Response: The state of activity for the user's devices. This includes if\n//     the device is currently online and the time the device was last active.\nsyntax = \"proto3\";\n\npackage cryptauthv2;\n\noption optimize_for = LITE_RUNTIME;\n\nimport \"cryptauth/cryptauth_common.proto\";\nimport \"cryptauth/cryptauth_directive.proto\";\n\n// A common context for requests.\n//\n// Note: This message is encoded as query parameters for some requests. If any\n// field or subfield of this proto changes, update the files\n// cryptauth_proto_to_query_parameters_util.{h,cc}.\nmessage RequestContext {\n  // The group name.\n  // A device can join multiple groups. Each group will be identified by a\n  // unique name.\n  // The device should have previously enrolled a public key with this name with\n  // the server, using the Enrollment API.\n  // The key material associated with the key of this name is used by other\n  // devices in the group to communicate securely with this device.\n  string group = 1;\n\n  // Common metadata about this request.\n  ClientMetadata client_metadata = 2;\n\n  // Device identifier.\n  string device_id = 3;\n\n  // Used to authenticate device_id.\n  string device_id_token = 4;\n}\n\n// Requests from a client to sync its metadata and receive encrypted copy of\n// other metadata updated since its last sync.\nmessage SyncMetadataRequest {\n  // The context of this request.\n  RequestContext context = 1;\n\n  // Public key material intended for group use. Will either be created by the\n  // device upon first joining, or will be existing group public key in its\n  // possession.\n  // May be discarded if device is joining an existing group that already has a\n  // group key pair.\n  bytes group_public_key = 3;\n\n  // Device's metadata encrypted with the given group public key.\n  bytes encrypted_metadata = 4;\n\n  // Set to true if the device needs the group's private key.\n  bool need_group_private_key = 5;\n\n  // Used to obtain only updated metadata, since the last request.\n  // If not set, all metadata will be sent.\n  bytes freshness_token = 6;\n}\n\n// One device's metadata, containing an identifier for the particular device,\n// along with its encrypted metadata.\nmessage DeviceMetadataPacket {\n  // Device identifier.\n  string device_id = 1;\n\n  // This device's metadata, encrypted with the group's private key.\n  bytes encrypted_metadata = 2;\n\n  // Indicates that the associated device needs the group's private key.\n  bool need_group_private_key = 3;\n\n  // The associated device's public key, to be used with\n  // EncryptedGroupPrivateKey below.\n  bytes device_public_key = 4;\n\n  // A name known to the server or which was assigned by the user to the device.\n  string device_name = 5;\n}\n\n// Response from server with any new devices' encrypted metadata and public key.\nmessage SyncMetadataResponse {\n  // Collection of encrypted metadata from devices that have been updated since\n  // last provided refresh_token. All metadata if none was provided.\n  repeated DeviceMetadataPacket encrypted_metadata = 1;\n\n  // Public key associated with the group, used to encrypt all metadata.\n  // May be different than key received in the request.\n  // If not set, the server is indicating a new group key pair must be created\n  // by this device.\n  bytes group_public_key = 2;\n\n  // An encrypted group private key that contains device public key used for\n  // encryption. Encrypted with the public key of the device.\n  EncryptedGroupPrivateKey encrypted_group_private_key = 3;\n\n  // Updated freshness token from the server.\n  // Use this value in subsequent requests, to obtain only data updated since\n  // the last request.\n  bytes freshness_token = 4;\n\n  // The updated client-specific directives.\n  ClientDirective client_directive = 5;\n}\n\n// Encrypted group private key, including identifiers for both sender and\n// recipient devices.\nmessage EncryptedGroupPrivateKey {\n  // Identifier for device receiving group private key.\n  string recipient_device_id = 1;\n\n  // Identifier for device sending group private key.\n  string sender_device_id = 2;\n\n  // Group private key, encrypted with the public key of the recipient device.\n  bytes encrypted_private_key = 3;\n\n  // Hash of the group public key used to encrypt this device’s metadata.\n  int64 group_public_key_hash = 7;\n}\n\n// Share the group's private key with another device.\nmessage ShareGroupPrivateKeyRequest {\n  // The context of this request.\n  RequestContext context = 1;\n\n  // A collection of encrypted group private keys, each identified with the\n  // device public key of both the sender and the recipient.\n  repeated EncryptedGroupPrivateKey encrypted_group_private_keys = 2;\n}\n\n// The server's response to sharing the group's private key.\nmessage ShareGroupPrivateKeyResponse {}\n\n// Allows a device, which is part of the group, notify another group device.\n// This allows setup to work, e.g. by letting the other device know it needs to\n// turn on the bluetooth radio.\n//\n// Note: This request is encoded as query parameters in a GET request. If any\n// field or subfield of this proto changes, update the files\n// cryptauth_proto_to_query_parameters_util.{h,cc}.\nmessage BatchNotifyGroupDevicesRequest {\n  // The context of this request.\n  RequestContext context = 1;\n\n  // Group devices to notify.\n  repeated string notify_device_ids = 2;\n\n  // Target service & feature type to specify in the notification.\n  TargetService target_service = 3;\n  // Feature type.\n  string feature_type = 4;\n}\n\n// Response to BatchNotifyGroupDevices.\nmessage BatchNotifyGroupDevicesResponse {}\n\n// Requests feature enabled/disabled statuses per device in the group.\n//\n// Note: This request is encoded as query parameters in a GET request. If any\n// field or subfield of this proto changes, update the files\n// cryptauth_proto_to_query_parameters_util.{h,cc}.\nmessage BatchGetFeatureStatusesRequest {\n  // The context of this request.\n  RequestContext context = 1;\n\n  // Which devices to query.\n  // Leave unset if all group devices should be queried.\n  repeated string device_ids = 2;\n\n  // Which feature types to query.\n  repeated string feature_types = 3;\n}\n\n// Enabled/disabled status of a single device.\nmessage DeviceFeatureStatus {\n  // Enabled/disabled status of a named feature.\n  message FeatureStatus {\n    // Feature type name.\n    string feature_type = 1;\n\n    // If the feature is enabled.\n    bool enabled = 2;\n\n    // The last time the feature was set. Only set for BatchGetFeatureStatuses.\n    int64 last_modified_time_millis = 3;\n\n    // Set to true to disable all group devices other than the specified device.\n    // This can only be used when enabling features. Only set for\n    // BatchSetFeatureStatuses.\n    bool enable_exclusively = 4;\n  }\n\n  // Device identifier.\n  string device_id = 1;\n\n  // The status of features associated with this device.\n  repeated FeatureStatus feature_statuses = 2;\n}\n\n// Response to BatchGetFeatureStatuses.\nmessage BatchGetFeatureStatusesResponse {\n  // The status of all queried group devices.\n  // Only the requested devices and requested features will be populated.\n  repeated DeviceFeatureStatus device_feature_statuses = 1;\n}\n\n// Sets feature types enable/disable statuses per device in the group.\nmessage BatchSetFeatureStatusesRequest {\n  // The context of this request.\n  RequestContext context = 1;\n\n  // The feature statuses to set for specific devices.\n  repeated DeviceFeatureStatus device_feature_statuses = 2;\n\n  // Set to true to disable all group devices other than the specified device.\n  // This can only be used with a single device and only when enabling features.\n  bool enable_exclusively = 3 [deprecated = true];\n}\n\n// Response to BatchSetFeatureStatuses.\nmessage BatchSetFeatureStatusesResponse {}\n\n// Request for GetDevicesActivityStatus.\nmessage GetDevicesActivityStatusRequest {\n  // The context of this request.\n  RequestContext context = 1;\n}\n\n// Describes the device's network reachability.\nenum ConnectivityStatus {\n  // Default value.\n  UNKNOWN_CONNECTIVITY = 0;\n  // The device appears to be unreachable.\n  OFFLINE = 1;\n  // The device appears to be online and reachable.\n  ONLINE = 2;\n}\n\n// Copied from\n// https://cs.chromium.org/chromium/src/third_party/protobuf/src/google/protobuf/timestamp.proto?rcl=b51864c7aae4372308052b9fd5c1913ceeee3884\nmessage Timestamp {\n  // Represents seconds of UTC time since Unix epoch\n  // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to\n  // 9999-12-31T23:59:59Z inclusive.\n  int64 seconds = 1;\n\n  // Non-negative fractions of a second at nanosecond resolution. Negative\n  // second values with fractions must still have non-negative nanos values\n  // that count forward in time. Must be from 0 to 999,999,999\n  // inclusive.\n  int32 nanos = 2;\n}\n\n// Activity status of a single device.\nmessage DeviceActivityStatus {\n  // Device identifier.\n  string device_id = 1;\n\n  // The last time this device was active as retrieved from Bond. Freshness\n  // is on the order of minutes.\n  int64 last_activity_time_sec = 2;\n\n  // Online status of the device as inferred by reachability via FCM.\n  ConnectivityStatus connectivity_status = 3;\n\n  // When the device last enrolled its DeviceSync key or when its metadata was\n  // last updated, the most recent of these two timestamps.\n  Timestamp last_update_time = 4;\n}\n\n// Response for GetDevicesActivityStatus.\nmessage GetDevicesActivityStatusResponse {\n  // The status of all group devices.\n  repeated DeviceActivityStatus device_activity_statuses = 1;\n}\n"
  },
  {
    "path": "play-services-core-proto/src/main/proto/cryptauth/cryptauth_directive.proto",
    "content": "/* SPDX-FileCopyrightText: 2014 The Chromium Authors\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\n// Contains messages sent from CryptAuth to clients who registered keys using\n// the v2 Enrollment protocol. The messages provide instructions to clients such\n// as how frequently to check in with CryptAuth via a SyncKeysRequest, how long\n// to wait between failed enrollment attempts, and what other keys are required\n// to cross-sign for a particular key.\nsyntax = \"proto3\";\n\npackage cryptauthv2;\n\noption optimize_for = LITE_RUNTIME;\n\nimport \"cryptauth/cryptauth_common.proto\";\n\n// The policy to be handed down to the party which registered the public key\n// with the server. It is produced on the fly from current ServerSidePolicy\n// and PolicyConfig (PC).\nmessage KeyDirective {\n  // The specific policy which was used to generate this message.\n  PolicyReference policy_reference = 1;\n\n  // When rotating the current key, 'crossproof_key_name' keys should be used\n  // to cross sign. This is retrieved from PolicyConfig.crossproof_key_name .\n  repeated string crossproof_key_names = 2;\n\n  // The time when the key was enrolled/rotated (as observed by the server).\n  // This should be the same as ServerSidePolicy.enroll_time_millis .\n  int64 enroll_time_millis = 3;\n}\n\n// This contains the directives handed down to the party which registered the\n// public key with the server. These directives are aggregated from across all\n// the policies of the keys that have been registered by this first party.\nmessage ClientDirective {\n  // The specific policy which was used to generate this message.\n  PolicyReference policy_reference = 1;\n\n  // The first party should check in with the server after this period.\n  // The server may require the client (first party) to rotate the key\n  // (based on PolicyConfig.rotate_delay_millis from across all the policies\n  // of the registered keys).\n  // For each policy of a registered key a value is randomly drawn from\n  // [PC.checkin_delay_millis - PC.checkin_delay_millis_interval,\n  // PC.checkin_delay_millis + PC.checkin_delay_millis_interval].\n  // The minimum value from across all these values is used.\n  //\n  // Whenever such a time period is coming due, the client should check in\n  // all its keys with the server. The server tells the client which of those\n  // keys need to be rotated and the rotation process proceeds for all these\n  // keys (bundled together).\n  int64 checkin_delay_millis = 2;\n\n  // In case any call to CryptAuth v2 failed, the first party should retry\n  // at most these many times right away, without the need to wait at all.\n  // Passed in from PC.retry_attempts.\n  // For example, a value of 1 means one original request, and if failed, a\n  // single retry should follow.\n  int32 retry_attempts = 3;\n\n  // In case any call to CryptAuth v2 failed retry_attempts + 1 times, the first\n  // party should retry the call again after this time period. If this latter\n  // retry fails, the first party should wait this time period again then retry\n  // and repeat until the request succeeds.\n  // For each policy of a registered key a value is randomly drawn from\n  // [PC.retry_period_millis - PC.retry_period_millis_interval,\n  // PC.retry_period_millis + PC.retry_period_millis_interval].\n  // The maximum value from across all these values is used.\n  int64 retry_period_millis = 4;\n\n  // The timestamp when this policy was minted.\n  // This can help the client sync with the server's time.\n  // checkin_delay_millis and retry_period_millis are relative to this time.\n  // Without this timestamp, the client should act right away with regard to\n  // the *_millis fields (ie, schedule something at NOW + *_millis).\n  // With this timestamp (considering the times of both server and client are\n  // in sync), the client would have all the required information for\n  // a later action.\n  int64 create_time_millis = 5;\n\n  // Which other services should be invoked after this interaction is complete.\n  repeated InvokeNext invoke_next = 6;\n}\n\n// Instructing the client to invoke a specific service.\nmessage InvokeNext {\n  // Target service to be involved next.\n  TargetService service = 1;\n\n  // Key name to be processed for target service.\n  string key_name = 2;\n}\n\n// The policy to be handed down to a third party along with the corresponding\n// public key of the device it asked for. It is produced on the fly from current\n// PolicyConfig and ServerSidePolicy (defined in\n// java/com/google/security/cryptauth/v2/backend/common/policy/policy.proto).\nmessage ThirdPartyKeyDirective {\n  // The specific policy which was used to generate this message.\n  PolicyReference policy_reference = 1;\n\n  // The third party should not use this key after this timestamp.\n  // It should sync with CryptAuth for getting a fresh one after this timestamp.\n  // This should be consistent with what the latest first party directive states\n  // (in its create_time_millis field), combined with\n  // PolicyConfig.rotate_delay_millis .\n  int64 expire_time_millis = 2;\n\n  // The timestamp when this policy was distributed to the third party.\n  int64 distribute_time_millis = 3;\n}\n"
  },
  {
    "path": "play-services-core-proto/src/main/proto/cryptauth/cryptauth_enrollment.proto",
    "content": "/* SPDX-FileCopyrightText: 2014 The Chromium Authors\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\n// Contains the request and response messages used in the CryptAuth v2\n// Enrollment protocol. Specifically,\n//   (1) SyncKeysRequest: The client submits information about their current set\n//       of keys to the CryptAuth server. The client can update their\n//       client-specific or key-specific metadata at this time as well.\n//   (2) SyncKeysResponse: The CryptAuth server responds with instructions such\n//       as what existing keys to (de)active, what new keys to create, and the\n//       time of the next check-in.\n//   (3) EnrollKeysRequest: If new keys were requested in the SyncKeysResponse,\n//       the client sends the new key information to CryptAuth in this request.\n//   (4) EnrollKeysResponse: If a certificate was generated, it will be provided\n//       here; otherwise, this can simply be a signal of a successful\n//       enrollment.\nsyntax = \"proto3\";\n\npackage cryptauthv2;\n\noption optimize_for = LITE_RUNTIME;\n\nimport \"cryptauth/cryptauth_common.proto\";\nimport \"cryptauth/cryptauth_directive.proto\";\n\n// The first request in the enrollment protocol. The request contains the\n// information including the keys currently held by the client, the latest\n// policies received from the server, and the metadata associated with the\n// client and keys.\nmessage SyncKeysRequest {\n  // The unique name of the application.\n  string application_name = 1;\n  // The version of the CryptAuth client library.\n  string client_version = 2;\n\n  // The request to enroll a key or update the info related to a key.\n  message SyncSingleKeyRequest {\n    // The purpose/application of the key.\n    string key_name = 1;\n    // Identifiers of keys currently held by the client.\n    repeated bytes key_handles = 2;\n\n    // The policy_reference received in the last KeyDirective.\n    PolicyReference policy_reference = 3;\n    // Key-specific metadata.\n    KeyMetadata key_metadata = 4;\n    // A key-specific opaque blob provided by the application.\n    bytes key_app_metadata = 5;\n  }\n  // Per key sync data.\n  repeated SyncSingleKeyRequest sync_single_key_requests = 3;\n\n  // The policy_reference received in the last ClientDirective.\n  PolicyReference policy_reference = 4;\n  // Client-specific metadata.\n  ClientMetadata client_metadata = 5;\n  // A client-specific opaque blob provided by the application.\n  // In the GmsCore case, this is a protobuf of type `ClientAppMetadata`.\n  bytes client_app_metadata = 6;\n}\n\n// The response to SyncKeysRequest. The response instructs how the client should\n// manage existing keys and whether to create a new key.\nmessage SyncKeysResponse {\n  // The session indentifer generated by the server, which must be\n  // cryptographically random.\n  bytes random_session_id = 1;\n  // The ephemeral DH public key generated by the server.\n  bytes server_ephemeral_dh = 2;\n\n  // The response corresponding to the SyncSingleKeyRequest message.\n  message SyncSingleKeyResponse {\n    // The actions corresponding to the key handles in SyncKeysRequest.\n    enum KeyAction {\n      // Default value. A client receiving this should treat it as a noop.\n      // (-- But, be wary of b/119886258. --)\n      KEY_ACTION_UNSPECIFIED = 0;\n\n      // Keep the key and make it the \"active\" key.\n      ACTIVATE = 1;\n      // Keep the key. When enrollment is complete, ensure the key is not\n      // \"active\".\n      // (-- But, be wary of b/119886258 and a noop on iOS. --)\n      DEACTIVATE = 2;\n      // Delete the key.\n      DELETE = 3;\n    }\n    // Key actions with one entry per key handle and in the same order as in the\n    // request.\n    repeated KeyAction key_actions = 1;\n\n    // The instruction for the client to create a new key.\n    enum KeyCreation {\n      // Do not create a new key.\n      NONE = 0;\n      // Create a new key, and then use it as the \"active\" key.\n      ACTIVE = 1;\n      // Create a new key, but do not use it as the \"active\" key.\n      // (-- Beware of b/119889101. This doesn't work on Android or iOS. --)\n      INACTIVE = 2;\n    }\n    // Instruction for key creation.\n    KeyCreation key_creation = 2;\n\n    // The type of the cryptographic key.\n    KeyType key_type = 3;\n    // The updated key-specific directives.\n    KeyDirective key_directive = 4;\n    // A key-specific opaque blob given to the application.\n    bytes key_app_directive = 5;\n\n    // The storage level where the key is created and stored.\n    enum KeyStorageLevel {\n      // Default value. The client is free to decide where to create the key.\n      KEY_STORAGE_LEVEL_UNSPECIFIED = 0;\n\n      // The key should be created and stored in software store. E.g. the\n      // client may create a key using a crypto library and store it in a\n      // file.\n      SOFTWARE = 1;\n\n      // The key should be created in a Trusted Execution Environment (TEE).\n      // E.g., TrustZone from ARM chips.\n      TRUSTED_EXECUTION_ENVIRONMENT = 2;\n\n      // The key should be created in a dedicated hardware that is separate from\n      // the main processor. E.g., StrongBox chips in Android devices and Secure\n      // Enclave in iOS devices.\n      DEDICATED_SECURE_ELEMENT = 3;\n    };\n    // The storage level to create the key.\n    KeyStorageLevel key_storage_level = 6;\n    // The newly created key should require hardware backed user presence when\n    // using the key.\n    bool hardware_user_presence_required = 7;\n    // The newly created key should require user verification when using the\n    // key.\n    bool user_verification_required = 8;\n  }\n  // Per key sync response.\n  repeated SyncSingleKeyResponse sync_single_key_responses = 3;\n\n  // The updated client-specific directives.\n  ClientDirective client_directive = 4;\n  // A client-specific opaque blob given to the application.\n  bytes client_app_directive = 5;\n\n  // The state of the server.\n  enum ServerStatus {\n    // The server is fine; the rest of SyncKeysResponse should be processed.\n    SERVER_OK = 0;\n    // The server is overloaded; client_directive should be followed.\n    SERVER_OVERLOADED = 1;\n  }\n  // The status of the server.\n  ServerStatus server_status = 6;\n}\n\n// The second request in the enrollment protocol. The second request is\n// necessary if the client wants to enroll a new key. The request contains the\n// information such as the material of the new key, and necessary proofs for\n// verifying the key.\nmessage EnrollKeysRequest {\n  // The session identifier copied from the SyncKeysResponse message.\n  bytes random_session_id = 1;\n  // The ephemeral DH public key generated by the client.\n  bytes client_ephemeral_dh = 2;\n\n  // The request to enroll a key, e.g., create a new key or rotate an old one.\n  message EnrollSingleKeyRequest {\n    // The key_name copied from SyncKeysRequest.\n    string key_name = 1;\n    // The identifier of the new key.\n    bytes new_key_handle = 2;\n    // The raw bytes of the new public key or custom data.\n    bytes key_material = 3;\n    // The public-key signature or MAC tag that shows the client indeed\n    // possesses the private or secret key.\n    bytes key_proof = 4;\n\n    // Cross-signatures or MAC tags by other keys.\n    message KeyCrossproof {\n      // The key_name of the cross-signing key.\n      string other_key_name = 1;\n      // The computed cross-signatures or MAC tags.\n      bytes other_key_proof = 2;\n    }\n    // Cross proofs.\n    repeated KeyCrossproof key_crossproofs = 5;\n\n    // Subject to certify.\n    repeated CertificateRequest certificate_requests = 6;\n\n    // Attestation of the key.\n    message KeyAttestation {\n      // The type of the key attestation.\n      enum KeyAttestationType {\n        // Default value.\n        KEY_ATTESTATION_TYPE_UNSPECIFIED = 0;\n\n        // Attestation generated by Android KeyStore API.\n        // See\n        // https://developer.android.com/training/articles/security-key-attestation\n        // The payload should be the concatenation of the X.509\n        // certificates returned by KeyStore attestation API encoded in ASN.1\n        // DER.\n        ANDROID_KEYSTORE_ATTESTATION = 1;\n      }\n      // The attestation type.\n      KeyAttestationType type = 1;\n\n      // The payload of the key attestation. The content of the payload is\n      // dependent on the attestation type.\n      bytes payload = 2;\n    }\n    // The attestation of the key if the key supports one.\n    KeyAttestation key_attestation = 7;\n  }\n  // Per key enroll data.\n  repeated EnrollSingleKeyRequest enroll_single_key_requests = 3;\n}\n\n// The response to EnrollKeysRequest. The response can contain a public-key\n// certificate for the client to perform offline authentications.\nmessage EnrollKeysResponse {\n  // The response corresponding to the EnrollSingleKeyRequest message.\n  message EnrollSingleKeyResponse {\n    // The server may produce a certificate and send it to the client.\n    repeated Certificate certificate = 1;\n  }\n  // Per key enroll response.\n  repeated EnrollSingleKeyResponse enroll_single_key_responses = 1;\n}\n\n// Subject to certify.\nmessage CertificateRequest {\n  // The type of subject to certify.\n  enum CommonNameType {\n    // Reserved.\n    UNKNOWN_COMMON_NAME_TYPE = 0;\n    // Indicates a phone number needs to be signed.\n    PHONE_NUMBER = 1;\n  }\n  // Type of content to be signed.\n  CommonNameType type = 1;\n  // Raw data of the content.\n  bytes data = 2;\n  // Bytes used to verify the validation of data.\n  bytes token = 3;\n  // Additional data used to help verify data. (e.g. audience)\n  bytes additional_data = 4;\n}\n\n// The key-specific metadata contained in SyncKeysRequest.\nmessage KeyMetadata {}\n\n// This generic rpc is used by MagicShare, BetterTogether and possibly other\n// features in the future to obtain enrollment information from the server.\n// This method’s behavior shall be based on the key_name which is supplied.\n// The client and server shall set and expect specific data in\n// request_key_metadata and response_key_metadata, based on the application_name\n// and key_name.\nmessage GetMetadataRequest {\n  // The unique name of the application\n  string application_name = 1;\n  // The version of the CryptAuth client library\n  string client_version = 2;\n\n  // The request to get key metadata related to a key name.\n  message GetSingleKeyMetadataRequest {\n    // The purpose/application of the key.\n    string key_name = 1;\n    // key specific metadata\n    bytes request_key_metadata = 2;\n  }\n  // Per key request\n  repeated GetSingleKeyMetadataRequest get_single_key_metadata_request = 3;\n\n  // InvocationReason, retry count, etc. (same as SyncKeys).\n  ClientMetadata client_metadata = 4;\n\n  // A client-specific opaque blob provided by the application.\n  bytes app_metadata = 5;\n}\n\n// The response to GetMetadataRequest. The response contains key metadata based\n// on the application name_and key_name in GetMetadataRequest.\nmessage GetMetadataResponse {\n  // The response of GetKeyMetadataRequest.\n  message GetSingleKeyMetadataResponse {\n    // Key specific response metadtata.\n    bytes response_key_metadata = 1;\n  }\n\n  // A response for every key_metadata_request above.\n  repeated GetSingleKeyMetadataResponse get_single_skey_metadata_response = 1;\n}\n"
  },
  {
    "path": "play-services-core-proto/src/main/proto/deviceconfig.proto",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\noption java_package = \"org.microg.gms.checkin\";\noption java_outer_classname = \"DeviceConfig\";\n\n\nmessage DeviceConfig {\n  // ConfigurationInfo.reqTouchScreen\n  // eg. 3\n  optional int32 touchScreen = 1;\n\n  // ConfigurationInfo.reqKeyboardType\n  // eg. 1\n  optional int32 keyboardType = 2;\n\n  // ConfigurationInfo.reqNavigation\n  // eg. 1\n  optional int32 navigation = 3;\n  // ConfigurationInfo.screenLayout\n  // eg. 3\n  optional int32 screenLayout = 4;\n\n  // ConfigurationInfo.reqInputFeatures & ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD\n  // eg. 0\n  optional bool hasHardKeyboard = 5;\n\n  // ConfigurationInfo.reqInputFeatures & ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV\n  // eg. 0\n  optional bool hasFiveWayNavigation = 6;\n\n  // DisplayMetrics.densityDpi\n  // eg. 320\n  optional int32 densityDpi = 7;\n\n  // ConfigurationInfo.reqGlEsVersion\n  // eg. 196608\n  optional int32 glEsVersion = 8;\n\n  // PackageManager.getSystemSharedLibraryNames\n  // eg. \"android.test.runner\", \"com.android.future.usb.accessory\", \"com.android.location.provider\",\n  //     \"com.android.media.remotedisplay\", \"com.android.mediadrm.signer\", \"com.google.android.maps\",\n  //     \"com.google.android.media.effects\", \"com.google.widevine.software.drm\", \"javax.obex\"\n  repeated string sharedLibrary = 9;\n\n  // PackageManager.getSystemAvailableFeatures\n  // eg. android.hardware.[...]\n  repeated string availableFeature = 10;\n\n  // Build.CPU_ABI and Build.CPU_ABI2 != \"unknown\"\n  // eg. \"armeabi-v7a\", \"armeabi\"\n  repeated string nativePlatform = 11;\n\n  // DisplayMetrics.widthPixels\n  // eg. 1200\n  optional int32 widthPixels = 12;\n\n  // DisplayMetrics.heightPixels\n  // eg. 1824\n  optional int32 heightPixels = 13;\n\n  // Context.getAssets.getLocales\n  // eg. [...], \"en-US\", [...]\n  repeated string locale = 14;\n\n  // GLES10.glGetString(GLES10.GL_EXTENSIONS)\n  // eg. \"GL_AMD_compressed_ATC_texture\", [...]\n  repeated string glExtension = 15;\n\n  // unused\n  optional int32 deviceClass = 16;\n  // unused\n  optional int32 maxApkDownloadSizeMb = 17;\n}\n"
  },
  {
    "path": "play-services-core-proto/src/main/proto/familymanagement.proto",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage google.familymanagement.v1;\n\noption java_outer_classname = \"FamilyManagementProto\";\n\noption java_package = \"org.microg.gms.family\";\noption java_multiple_files = true;\n\nservice FamilyManagementService {\n  // Get the home group management configuration interface\n  rpc GetFamilyManagementConfig(GetFamilyManagementConfigRequest) returns (GetFamilyManagementConfigResponse);\n\n  // Get the family group member list interface\n  rpc GetFamily(GetFamilyRequest) returns (GetFamilyResponse);\n\n  // When exiting the family group, the page content displays\n  rpc GetFamilyManagementPageContent(GetFamilyRequest) returns (GetFamilyManagementPageContentResponse);\n\n  // Delete invitation interface\n  rpc DeleteInvitation(DeleteOperationRequest) returns (DeleteOperationResponse);\n\n  // Delete member interface\n  rpc DeleteMember(DeleteOperationRequest) returns (DeleteOperationResponse);\n\n  // Delete family interface\n  rpc DeleteFamily(DeleteOperationRequest) returns (DeleteOperationResponse);\n}\n\n// Responses to operations such as canceling invitations and removing members\nmessage DeleteOperationResponse {\n  optional DeleteOperationResult result = 1;\n}\n\nmessage DeleteOperationResult {\n  optional string consistencyToken = 1;\n  optional int32 expireTime = 2;\n}\n\n// When jumping to WebView when removing family members, etc., the page configuration loaded\nmessage OctarineWebViewPageConfiguration {\n  optional string requestUrl = 1;\n  optional string accountName = 2;\n  optional int32 initialTitleType = 3;\n  optional int32 initialAccountDisplay = 4;\n  optional int32 theme = 5;\n  optional string callingPackageName = 6;\n  optional string consistencyToken = 7;\n  optional bool disableClearCut = 8;\n}\n\n// Get home group management configuration\nmessage GetFamilyManagementConfigRequest {\n  optional RequestContext context = 1;\n  optional bool unknownBool2 = 2 [default = true];\n  optional bool unknownBool3 = 3 [default = true];\n  optional bool directAdd = 4;\n}\n\nmessage GetFamilyManagementConfigResponse {\n  optional FamilyConfigExtra configExtra = 1;\n  optional FamilyConfigMain configMain = 2;\n}\n\nmessage FamilyConfigExtra {\n\n}\n\nmessage FamilyConfigMain {\n  optional FamilyTypeList familyTypeList = 2;\n  repeated FamilyOption familyOption = 5;\n  optional FamilyInviteConfig familyInviteConfig = 6;\n}\n\nmessage FamilyTypeList {\n  repeated int32 type = 1;\n  repeated FamilyMemberIdList memberIdList = 2;\n}\n\nmessage FamilyOption {\n  optional int32 optionId = 1;\n  repeated FamilyOptionContent optionContents = 2;\n}\n\nmessage FamilyInviteConfig {\n  optional FamilyInviteText content = 5;\n}\n\nmessage FamilyInviteText {\n  optional string cpTitle = 1;\n  optional string addRecipientEmail = 2;\n  optional string addOthersEmail = 3;\n  optional string contacts = 4;\n  optional string send = 5;\n  optional string smsFeeNotice = 6;\n  optional string invalidEmailNotice = 7;\n  optional string validEmailReminderInfo = 8;\n  optional string selectedInviteesInfo = 9;\n}\n\nmessage FamilyMemberIdList {\n  optional string memberId = 1;\n  repeated int32 unKnownInt2 = 2;\n}\n\nmessage FamilyOptionContent {\n  optional int32 optId = 1;\n  optional string content = 2;\n}\n\n// Return value when exiting a family group\nmessage GetFamilyManagementPageContentResponse {\n  optional FamilyPageHeader header = 1;\n  optional FamilyPageBody body = 2;\n}\n\nmessage FamilyPageHeader {\n  optional FamilyHeaderInfo info = 1;\n}\n\nmessage FamilyHeaderInfo {\n  optional string title = 1;\n  optional int32 type = 2;\n}\n\nmessage FamilyPageBody {\n  optional int32 status = 1;\n  repeated FamilySection sections = 2;\n  repeated FamilyHelpLink helpLinks = 3;\n  repeated FamilyBulletPoint bulletPoints = 4;\n}\n\nmessage FamilySection {\n  optional int32 sectionId = 1;\n  optional string content = 2;\n}\n\nmessage FamilyHelpLink {\n  optional string tag = 1;\n  optional string appContext = 2;\n  optional string url = 4;\n}\n\nmessage FamilyBulletPoint {\n  repeated FamilySection items = 1;\n}\n\nmessage GetFamilyRequest {\n  optional RequestContext context = 1;\n  optional uint32 flag = 2;\n  optional PlaceHolder placeHolder = 3;\n//  optional PlaceHolder placeHolder2 = 4;\n  optional MemberInfo memberInfo = 5;\n}\n\nmessage DeleteOperationRequest {\n  optional RequestContext context = 1;\n  optional string memberId = 2;\n  optional PlaceHolder placeHolder = 3;\n//  optional PlaceHolder2 placeHolder2 = 4;\n  optional MemberInfo memberInfo = 5;\n}\n\nmessage MemberInfo {\n  optional string memberId = 1;\n}\n\nmessage PlaceHolder {\n}\n\nmessage RequestContext {\n  required string familyExperimentOverrides = 1;\n  optional DeviceInfo deviceInfo = 3;\n  optional string moduleSet = 4;\n}\n\nmessage DeviceInfo {\n  optional string moduleVersion = 1;\n  optional int32 clientType = 2;\n  optional CallerInfo moduleInfo = 4;\n//  required ScreenDensity screenDensity = 5;\n}\n\nmessage CallerInfo {\n  optional string appId = 1;\n}\n\nmessage ScreenDensity {\n  required int32 densityLevel = 1;\n}\n\nmessage GetFamilyResponse {\n  optional string userId = 2;\n  optional bool isActive = 3;\n  optional FamilyRole familyRole = 4;\n  optional JoinMethod joinType = 5;\n  optional int32 maxAvailableSlots = 7;\n  repeated FamilyMember memberDataList = 8;\n  repeated FamilyInvite invitationList = 9;\n}\n\nmessage FamilyInvite {\n  optional string invitationId = 1;\n  optional InviteInfo inviteInfo = 2;\n  optional MemberProfile profile = 3;\n  optional FamilyRole role = 4;\n  optional int64 inviteState = 5;\n  optional string appId = 7;\n  optional string invitationMessage = 8;\n  optional string contactId = 11;\n}\n\nmessage InviteInfo {\n  optional string emailAddress = 1;\n  optional string phoneNumber = 2;\n}\n\n// Family group member roles\nenum FamilyRole {\n  UNKNOWN_FAMILY_ROLE = 0;\n  HEAD_OF_HOUSEHOLD = 1;\n  PARENT = 2;\n  MEMBER = 3;\n  CHILD = 4;\n  UNCONFIRMED_MEMBER = 5;\n}\n\n// The method of joining the group, that is, by invitation or other means\nenum JoinMethod {\n  UNKNOWN_JOIN_METHOD = 0;\n  INVITED_BY_ADMIN = 1;\n  JOINED_BY_LINK = 2;\n  JOINED_BY_EMAIL = 3;\n  MIGRATED = 4;\n}\n\nmessage FamilyMember {\n  optional string memberId = 1;\n  optional FamilyRole role = 3;\n  optional MemberProfile profile = 4;\n  optional string hohGivenName = 6;\n  repeated int32 tags = 7;\n}\n\nmessage MemberProfile {\n  optional string displayName = 1;\n  optional string profilePhotoUrl = 3;\n  optional string email = 4;\n  optional string familyName = 6;\n  optional string defaultPhotoUrl = 9;\n}\n\n// reAuthProofTokensRequest\nmessage ReAuthProofTokensRequest {\n  optional int32 type = 2;\n  optional string password = 4;\n}\n\n// reAuth settings response\nmessage ReAuthSettingsResponse {\n  optional ReAuthSettings settings = 1;\n}\n\nmessage ReAuthSettings {\n  optional ReAuthSettingsOption option1 = 1;\n  optional ReAuthSettingsOption option2 = 2;\n}\n\nmessage ReAuthSettingsOption {\n  optional int32 type = 1;\n  optional string resetPinUrlPart1 = 2;\n  optional string resetPinUrlPart2 = 3;\n  optional string resetPinUrlPart3 = 5;\n  optional string recoveryUrl = 6;\n}\n"
  },
  {
    "path": "play-services-core-proto/src/main/proto/games.proto",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage google.play.games.whitelisted.v1whitelisted;\n\noption java_outer_classname = \"GamesPlayersProto\";\n\noption java_package = \"org.microg.gms.games\";\noption java_multiple_files = true;\n\nservice PlayersFirstParty {\n  rpc DeleteApplicationDataFirstParty (DeleteApplicationDataRequest) returns (DeleteApplicationDataResponse);\n  rpc DeletePlayerFirstParty (DeletePlayerRequest) returns (DeletePlayerResponse);\n}\n\nservice ApplicationsFirstParty {\n  rpc ListApplicationsWithUserDataFirstParty (ListApplicationsWithUserDataRequest) returns (ListApplicationsWithUserDataResponse);\n}\n\nmessage ListApplicationsWithUserDataRequest {\n  optional string locale = 1;\n  optional string androidSdk = 2;\n}\n\nmessage ListApplicationsWithUserDataResponse {\n  optional string tag = 1;\n  optional int32 code = 2;\n  repeated FirstPartyApplication firstPartyApplication = 3;\n}\n\nmessage FirstPartyApplication {\n  optional string tag = 1;\n  optional Application application = 2;\n  optional int32 unlockAchievementsNum = 6;\n  optional int32 played = 9;\n}\n\nmessage Application {\n  optional string tag = 1;\n  optional string gameId = 2;\n  optional string gameName = 3;\n  optional ApplicationIcon gameIcon = 7;\n  optional int32 achievementsNum = 10;\n}\n\nmessage ApplicationIcon {\n  optional string type = 1;\n  optional int32 width = 2;\n  optional int32 height = 3;\n  optional string url = 4;\n  optional string tag = 5;\n}\n\nmessage DeletePlayerRequest {}\n\nmessage DeletePlayerResponse {}\n\nmessage DeleteApplicationDataRequest {\n  optional string gameId = 1;\n  optional int32 status = 2;\n}\n\nmessage DeleteApplicationDataResponse {}"
  },
  {
    "path": "play-services-core-proto/src/main/proto/gnots.proto",
    "content": "package social.boq.notifications.gmscoreapi;\n\noption java_outer_classname = \"GunsGmscoreApiService\";\noption java_package = \"org.microg.gms.gcm\";\n\nservice GunsGmscoreApiService {\n  rpc GmsGnotsFetchByIdentifier(FetchByIdentifierRequest) returns (FetchByIdentifierResponse);\n  rpc GmsGnotsSetReadStates(GmsGnotsSetReadStatesRequest) returns (GmsGnotsSetReadStatesResponse);\n}\n\nmessage FetchByIdentifierRequest {\n  optional GmsConfig config = 1;\n  optional NotificationIdentifierList identifiers = 2;\n}\n\nmessage GmsConfig {\n  message GmsVersionInfo {\n    optional int32 version = 10;\n  }\n  optional GmsVersionInfo versionInfo = 3;\n}\n\nmessage NotificationIdentifierList {\n  repeated NotificationIdentifier notifications = 1;\n  optional DeviceInfo deviceInfo = 2;\n}\n\nmessage FetchByIdentifierResponse {\n  optional NotificationList notifications = 2;\n}\n\nmessage NotificationList {\n  repeated NotificationData notificationDataList = 1;\n  optional uint64 serverTime = 3;\n}\n\nmessage NotificationData {\n  optional UserInfo userInfo = 1;\n  optional NotificationIdentifier identifier = 2;\n  optional bool isActive = 3;\n  optional NotificationContent content = 4;\n  optional NotificationAction action = 5;\n  optional DeviceInfo deviceInfo = 6;\n  optional uint64 createTime = 7;\n  optional IntentActions intentActions = 8;\n  optional uint64 expiryTime = 9;\n  optional BinaryPayload binaryPayload = 10;\n}\n\nmessage IntentActions {\n  optional IntentPayload primaryPayload = 1;\n  optional IntentPayload secondaryPayload = 2;\n}\n\nmessage UserInfo {\n  optional string userId = 1;\n}\n\nmessage NotificationIdentifier {\n  optional string type = 1;\n  optional string uniqueId = 2;\n  optional uint64 timestamp = 3;\n  optional string source = 4;\n  optional string registrationId = 5;\n  optional int64 receivedTime = 6;\n  optional bytes payload = 7;\n}\n\nmessage NotificationContent {\n  optional int32 priority = 1;\n  optional IconInfo icon = 2;\n  optional string title = 3;\n  optional string accountName = 4;\n  optional string email = 5;\n  optional string description = 6;\n  optional string contentDescription = 7;\n  optional string notificationContentKey = 8;\n  optional string toastMessage = 9;\n  optional bool notifDefFlag = 10;\n  optional bool notifDefVibrateEnabled = 11;\n  optional bool notifDefSound = 12;\n  optional bool notifDefVisibilityLevel = 13;\n  optional ActionButtons buttons = 14;\n  optional bool isLocalOnly = 15;\n  optional string taskDescriptionLabel = 16;\n  repeated NotificationButton actionButtons = 17;\n  optional NotificationChannelInfo channelInfo = 18;\n  optional string groupKey = 19;\n  optional string substName = 20;\n}\n\nmessage NotificationChannelInfo {\n  optional string id = 1;\n  optional string description = 2;\n  optional string groupId = 3;\n  optional string groupName = 4;\n  optional int32 importance = 5;\n  optional string name = 6;\n}\n\nmessage IconInfo {\n  optional string iconUrl = 1;\n}\n\nmessage ActionButtons {\n  optional string primaryText = 1;\n  optional string secondaryText = 2;\n}\n\nmessage NotificationButton {\n  optional string text = 1;\n  optional NotificationAction action = 2;\n  optional string icon = 3;\n  optional bool isEnabled = 4;\n  optional int32 buttonType = 6;\n}\n\nmessage NotificationAction {\n  optional ActionMetadata metadata = 1;\n  optional ActionIntent intent = 2;\n}\n\nmessage ActionMetadata {\n  optional string actionUrl = 1;\n  optional bool value = 2;\n}\n\nmessage ActionIntent {\n  optional IntentPayload intentPayload = 4;\n}\n\nmessage IntentPayload {\n  optional string className = 1;\n  optional string action = 2;\n  optional int32 launchType = 3;\n  repeated IntentExtra extras = 4;\n  optional int32 flags = 5;\n}\n\nmessage IntentExtra {\n  optional string key = 1;\n  optional string value = 2;\n}\n\nmessage GmsGnotsSetReadStatesRequest {\n  optional GmsConfig config = 1;\n  optional ReadStateList readStates = 2;\n}\n\nmessage ReadStateList {\n  repeated ReadStateItem items = 1;\n}\n\nmessage ReadStateItem {\n  optional NotificationIdentifier notification = 1;\n  optional string state = 3;\n  optional int32 status = 4;\n}\n\nmessage GmsGnotsSetReadStatesResponse {\n}\n\nmessage DeviceInfo {\n  optional DensityQualifier densityQualifier = 1;\n  enum DensityQualifier {\n    LDPI = 0;\n    MDPI = 1;\n    HDPI = 2;\n    XHDPI = 3;\n    TVDPI = 4;\n    XXHDPI = 5;\n  }\n  optional string localeTag = 2;\n  optional int32 sdkVersion = 3;\n  optional float density = 4;\n  optional string timeZoneId = 5;\n  repeated NotificationChannelInfo notificationChannels = 6;\n}\n\nmessage BinaryPayload {\n  required string type = 1;\n  required bytes data = 2;\n}"
  },
  {
    "path": "play-services-core-proto/src/main/proto/help.proto",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\noption java_package = \"org.microg.gms.googlehelp\";\n\noption java_multiple_files = true;\n\nmessage RequestContent {\n  optional CallerAppInfo appInfo = 1;\n  optional DeviceInfo deviceInfo = 2;\n  optional RequestBody body = 3;\n  optional string host = 4;\n}\n\nmessage ResponseContentWarp {\n    optional ResponseContent content = 1;\n}\n\nmessage ResponseContent {\n  optional AnswerInfo info = 1;\n  optional uint32 theme = 2;\n}\n\nmessage AnswerInfo {\n  optional string answerId = 1;\n  optional string answerTitle = 2;\n  optional string answerUrl = 3;\n  optional uint32 type = 5;\n}\n\nmessage CallerAppInfo {\n  optional string packageName = 1;\n  optional string version = 2;\n}\n\nmessage DeviceInfo {\n  optional string language = 1;\n  optional string name = 2;\n  optional string version = 3;\n  optional string code = 7;\n  optional string timeZone = 9;\n}\n\nmessage RequestBody {\n  optional string appContext = 3;\n  optional string session = 4;\n  optional uint32 gmsVersionCode = 12;\n  optional string gmsVersionName = 13;\n  optional uint32 type = 26;\n  optional string ap = 28;\n}"
  },
  {
    "path": "play-services-core-proto/src/main/proto/locationsharingreporter/reporting.proto",
    "content": "package com.google.android.gms.locationsharingreporter.service;\n\n\nmessage ReportingRequestStore {\n    optional int32 batterySaverState = 2;\n    optional int32 locationSettingState = 3;\n    optional int64 lastReceivedLocationTs = 4;\n    optional int64 recordedSessionStartTime = 7;\n    optional NetworkConnectivityState networkConnectivityState = 11;\n    map<string, LocationSharingInfo> accountLocationSharingMap = 12;\n    optional int64 createTimestamp = 14;\n    optional int64 startReportingTimestamp = 15;\n}\n\n\nenum ReportingType {\n    ONGOING_REPORTING_ENABLED = 1;\n    SINGLE_SHARE_REPORTING_ENABLED = 2;\n}\n\nmessage LocationSharingInfo {\n    optional int64 createdTimestamp = 5;\n}\n\n\nenum NetworkConnectivityState {\n    CONNECTIVITY_UNKNOWN = 0;\n    CONNECTIVITY_DISCONNECTED = 1;\n    CONNECTIVITY_CONNECTED = 2;\n}\n\n"
  },
  {
    "path": "play-services-core-proto/src/main/proto/locationsharingreporter/user_location_frontend_service.proto",
    "content": "syntax = \"proto2\";\n\npackage social.userlocation.frontend;\n\nservice UserLocationFrontendService {\n  rpc UpdateSharingState(UpdateSharesStateRequest) returns (UpdateSharesStateResponse);\n  rpc ReadShares(ReadSharesRequest) returns (ReadSharesResponse);\n  rpc RemoveShares(RemoveSharesRequest) returns (RemoveSharesResponse);\n  rpc UploadLocation(UploadLocationRequest) returns (UploadLocationResponse);\n  rpc UploadLocationIfShareExists(UploadLocationIfShareExistsRequest) returns (UploadLocationIfShareExistsResponse);\n}\n\nmessage UpdateSharesStateRequest {\n  optional UserSharingState userSharingState = 1;\n}\n\nmessage UserSharingState {\n  optional int32 isSharingEnabled = 1;\n  optional int32 hasSignedTos = 2;\n  optional string countryCode = 3;\n  optional bool isUpdate = 6;\n}\n\nmessage UpdateSharesStateResponse {\n  optional int32 status = 1;\n}\n\n\nmessage RemoveSharesRequest {\n}\n\nmessage RemoveSharesResponse {\n\n}\n\nmessage UploadLocationIfShareExistsRequest {\n\n}\n\nmessage UploadLocationIfShareExistsResponse {\n\n}\n\nmessage UploadLocationRequest {\n  optional int64 requestCreationTime = 2;\n  optional bool isUserReportingDisabled = 3;\n  optional LocationReportingRecord locationReportingRecord = 4;\n  optional ClientEnvironment clientEnvironment = 5;\n  repeated DeviceLocationMessage deviceLocationMessageList = 6;\n  optional GeofenceReportingConfig geofenceReportingConfig = 7;\n  optional bool shouldEnableGeofencingOptimization = 9;\n  optional UploadConfig uploadConfig = 10;\n}\n\nmessage UploadLocationResponse {\n  optional UploadLocationResult result = 1;\n  optional LocationReportingParameters locationReportingParameters = 3;\n}\n\n/**\n * Upload begin\n */\n\nmessage LocationReportingRecord {\n  optional string ovenfreshId = 1;\n  optional LocationReportingStatus locationReportingStatus = 2;\n  optional int32 attemptCount = 3;\n  optional int64 uploadTime = 4;\n  optional int64 ovenfreshCreationTime = 5;\n}\n\nenum LocationReportingStatus {\n  LOCATION_REPORTING_STATUS_UNKNOWN = 0;\n  LOCATION_REPORTING_STATUS_OVENFRESH_RECEIVED = 1;\n  LOCATION_REPORTING_STATUS_COLLECTION_STARTED = 2;\n  LOCATION_REPORTING_STATUS_COLLECTION_IN_PROGRESS = 3;\n  LOCATION_REPORTING_STATUS_SUCCEEDED = 4;\n  LOCATION_REPORTING_STATUS_FAILED_LOCATION_UNAVAILABLE = 5;\n  LOCATION_REPORTING_STATUS_FAILED_PERMISSIONS_DENIED = 6;\n  LOCATION_REPORTING_STATUS_FAILED_LOCATION_DISABLED = 7;\n  LOCATION_REPORTING_STATUS_FAILED_DEVICE_INCAPABLE = 8;\n  LOCATION_REPORTING_STATUS_FAILED_REPORTING_RATE_EXCEEDED = 9;\n  LOCATION_REPORTING_STATUS_FAILED_NO_CONNECTIVITY = 10;\n  LOCATION_REPORTING_STATUS_FAILED_NO_ACTIVE_CLIENTS = 11;\n  LOCATION_REPORTING_STATUS_FAILED_NO_CLIENTS_WITH_LOCATION_ACCESS = 12;\n  LOCATION_REPORTING_STATUS_FAILED_INELIGIBLE_TO_REPORT = 13;\n}\n\nmessage ClientEnvironment {\n  optional string androidVersion = 2;\n  optional string gmscoreVersion = 3;\n}\n\nmessage DeviceLocationMessage {\n  optional DeviceLocationRecord deviceLocationRecord = 1;\n}\n\nmessage DeviceLocationRecord {\n  optional int64 eventTimestampMillis = 1;\n  optional GeoPoint geoPoint = 2;\n  optional double accuracy = 3;\n  optional BatteryInfo batteryInfo = 4;\n  repeated hflh unKnownMessage5 = 5;\n  optional WearableStatusCode wearableStatusCode = 7; // unused\n  optional PlaceCandidateIdentifier placeCandidateIdentifier = 8; // unused\n}\n\nmessage GeoPoint {\n  optional double altitude = 1;\n  optional double longitude = 2;\n  optional double latitude = 3;\n}\n\nmessage BatteryInfo {\n  optional bool isCharging = 1;\n  optional int32 batteryLevelPercent = 2;\n}\n\nmessage hflh {\n  optional int32 unknowInt1 = 1; //unknow enum\n}\n\nmessage WearableStatusCode {\n  optional int32 wearableStateCode = 1;\n}\n\nmessage PlaceCandidateIdentifier {\n  optional fixed64 highId = 1;\n  optional fixed64 lowId = 2;\n}\n\nmessage UploadConfig {\n  optional int32 unknowInt1 = 1; //unknow enum\n  optional UploadPolicy uploadPolicy = 2;\n}\n\nmessage UploadPolicy {\n  optional bool allowNonOvenfreshUploads = 1;\n}\n\n\nenum UploadLocationResult {\n  UNKNOWN_RESULT = 0;\n  SUCCESS = 1;\n  UPLOAD_REJECTED = 2;\n}\n\n/**\n * Upload end\n */\n\nmessage ReadSharesRequest {\n  optional WearOsAccountAndLocationConfig config = 2;\n  optional GeofenceReportingConfig geofenceReportingConfig = 4;\n}\n\nmessage WearOsAccountAndLocationConfig {\n    optional bool hasWearOsUsmAccount = 4;\n    optional bool isLocationReportingEnabled = 5;\n}\n\nmessage GeofenceReportingConfig {\n  optional bytes geofenceToken = 1;\n  enum ReportingProtocol {\n    REPORTING_PROTOCOL_UNKNOWN = 0;\n    REPORTING_PROTOCOL_SINGLE_DEVICE = 1;\n    REPORTING_PROTOCOL_MULTI_DEVICE_WITH_PRIMARY_DETECTION = 2;\n  }\n  optional ReportingProtocol protocol = 2;\n}\n\nmessage ReadSharesResponse {\n  repeated PinpointLocationShare pinpointLocationSharesList = 2;\n  optional LocationReportingParameters locationReportingParameters = 12;\n  optional bool isNoticeUpdated = 14;\n}\n\nmessage PinpointLocationShare {\n  repeated LocationShareCondition shareConditions = 2;\n  optional LocationShareOptions locationShareOptions = 4;\n  optional string shareLabel = 5;\n  optional string locationShareUrl = 7;\n}\n\nmessage LocationShareCondition {\n  optional int32 conditionType = 1;\n}\n\nmessage LocationShareOptions {\n  optional LocationShareId locationShareId = 1;\n  optional int32 shareType = 2;\n  optional int32 conditionType = 3;\n}\n\nmessage LocationShareId {\n  optional string oid = 4;\n  optional LocationShareAuth locationShareAuth = 10;\n}\n\nmessage LocationShareAuth {\n  optional string tokenId = 1;\n  optional string zookie = 2;\n  optional int32 unknowFileInt3 = 3; //unknow enum\n}\n\nmessage LocationReportingParameters {\n    optional int64 serverTimestamp = 1;\n    optional bool isReportingEnabled = 2;\n    optional int32 shareRemainingTimeSec = 5;\n    optional bool hasAdditionalRestrictions = 10;\n}\n\n"
  },
  {
    "path": "play-services-core-proto/src/main/proto/mcs.proto",
    "content": "// Derived from mcs.proto in chromium source code. Original license text below.\n\n// Copyright 2013 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n//\n// MCS protocol for communication between Chrome client and Mobile Connection\n// Server .\n\noption java_package = \"org.microg.gms.gcm.mcs\";\n\n/*\n   Common fields/comments:\n\n    stream_id: no longer sent by server, each side keeps a counter\n    last_stream_id_received: sent only if a packet was received since last time\n    a last_stream was sent\n    status: new bitmask including the 'idle' as bit 0.\n\n */\n\n/**\n  TAG: 0\n  */\nmessage HeartbeatPing {\n  optional int32 stream_id = 1;\n  optional int32 last_stream_id_received = 2;\n  optional int64 status = 3;\n}\n\n/**\n  TAG: 1\n  */\nmessage HeartbeatAck {\n  optional int32 stream_id = 1;\n  optional int32 last_stream_id_received = 2;\n  optional int64 status = 3;\n}\n\nmessage ErrorInfo {\n  required int32 code = 1;\n  optional string message = 2;\n  optional string type = 3;\n  optional  Extension extension = 4;\n}\n\n// MobileSettings class.\n// \"u:f\", \"u:b\", \"u:s\" - multi user devices reporting foreground, background\n// and stopped users.\n// hbping: heatbeat ping interval\n// rmq2v: include explicit stream IDs\n\nmessage Setting {\n  required string name = 1;\n  required string value = 2;\n}\n\nmessage HeartbeatStat {\n  required string ip = 1;\n  required bool timeout = 2;\n  required int32 interval_ms = 3;\n}\n\nmessage HeartbeatConfig {\n  optional bool upload_stat = 1;\n  optional string ip = 2;\n  optional int32 interval_ms = 3;\n}\n\n/**\n  TAG: 2\n  */\nmessage LoginRequest {\n  enum AuthService {\n    ANDROID_ID = 2;\n  }\n  required string id = 1; // Must be present ( proto required ), may be empty\n                          // string.\n  // mcs.android.com.\n  required string domain = 2;\n  // Decimal android ID\n  required string user = 3;\n\n  required string resource = 4;\n\n  // Secret\n  required string auth_token = 5;\n\n  // Format is: android-HEX_DEVICE_ID\n  // The user is the decimal value.\n  optional string device_id = 6;\n\n  // RMQ1 - no longer used\n  optional int64 last_rmq_id = 7;\n\n  repeated Setting setting = 8;\n  optional int32 compress = 9;\n  repeated string received_persistent_id = 10;\n\n  // Replaced by \"rmq2v\" setting\n  optional bool include_stream_ids = 11;\n\n  optional bool adaptive_heartbeat = 12;\n  optional HeartbeatStat heartbeat_stat = 13;\n  // Must be true.\n  optional bool use_rmq2 = 14;\n  optional int64 account_id = 15;\n\n  // ANDROID_ID = 2\n  optional AuthService auth_service = 16;\n\n  optional int32 network_type = 17;\n  optional int64 status = 18;\n}\n\n/**\n  * TAG: 3\n  */\nmessage LoginResponse {\n  required string id = 1;\n  // Not used.\n  optional string jid = 2;\n  // Null if login was ok.\n  optional ErrorInfo error = 3;\n  repeated Setting setting = 4;\n  optional int32 stream_id = 5;\n  // Should be \"1\"\n  optional int32 last_stream_id_received = 6;\n  optional HeartbeatConfig heartbeat_config = 7;\n  // used by the client to synchronize with the server timestamp.\n  optional int64 server_timestamp = 8;\n}\n\nmessage StreamErrorStanza {\n  required string type = 1;\n  optional string text = 2;\n}\n\n/**\n  * TAG: 4\n  */\nmessage Close {\n}\n\nmessage Extension {\n  // 12: SelectiveAck\n  // 13: StreamAck\n  required int32 id = 1;\n  required bytes data = 2;\n}\n\n/**\n  * TAG: 7\n  * IqRequest must contain a single extension.  IqResponse may contain 0 or 1\n  * extensions.\n  */\nmessage IqStanza {\n  enum IqType {\n    GET = 0;\n    SET = 1;\n    RESULT = 2;\n    IQ_ERROR = 3;\n  }\n\n  optional int64 rmq_id = 1;\n  required IqType type = 2;\n  required string id = 3;\n  optional string from = 4;\n  optional string to = 5;\n  optional ErrorInfo error = 6;\n\n  // Only field used in the 38+ protocol (besides common last_stream_id_received, status, rmq_id)\n  optional Extension extension = 7;\n\n  optional string persistent_id = 8;\n  optional int32 stream_id = 9;\n  optional int32 last_stream_id_received = 10;\n  optional int64 account_id = 11;\n  optional int64 status = 12;\n}\n\nmessage AppData {\n  required string key = 1;\n  required string value = 2;\n}\n\n/**\n * TAG: 8\n */\nmessage DataMessageStanza {\n  // Not used.\n  optional int64 rmq_id = 1;\n\n  // This is the message ID, set by client, DMP.9 (message_id)\n  optional string id = 2;\n\n  // Project ID of the sender, DMP.1\n  required string from = 3;\n\n  // Part of DMRequest - also the key in DataMessageProto.\n  optional string to = 4;\n\n  // Package name. DMP.2\n  required string category = 5;\n\n  // The collapsed key, DMP.3\n  optional string token = 6;\n\n  // User data + GOOGLE. prefixed special entries, DMP.4\n  repeated AppData app_data = 7;\n\n  // Not used.\n  optional bool from_trusted_server = 8;\n\n  // Part of the ACK protocol, returned in DataMessageResponse on server side.\n  // It's part of the key of DMP.\n  optional string persistent_id = 9;\n\n  // In-stream ack. Increments on each message sent - a bit redundant\n  // Not used in DMP/DMR.\n  optional int32 stream_id = 10;\n  optional int32 last_stream_id_received = 11;\n\n  // Not used.\n  optional string permission = 12;\n\n  // Sent by the device shortly after registration.\n  optional string reg_id = 13;\n\n  // Not used.\n  optional string pkg_signature = 14;\n  // Not used.\n  optional string client_id = 15;\n\n  // serial number of the target user, DMP.8\n  // It is the 'serial number' according to user manager.\n  optional int64 device_user_id = 16;\n\n  // Time to live, in seconds.\n  optional int32 ttl = 17;\n  // Timestamp ( according to client ) when message was sent by app, in seconds\n  optional int64 sent = 18;\n\n  // How long has the message been queued before the flush, in seconds.\n  // This is needed to account for the time difference between server and\n  // client: server should adjust 'sent' based on his 'receive' time.\n  optional int32 queued = 19;\n\n  optional int64 status = 20;\n\n  optional bytes raw_data = 21;\n\n  optional int32 delay = 22;\n}\n\n/**\n  Included in IQ with ID 13, sent from client or server after 10 unconfirmed\n  messages.\n */\nmessage StreamAck {\n  // No last_streamid_received required.  This is included within an IqStanza,\n  // which includes the last_stream_id_received.\n}\n\n/**\n  Included in IQ sent after LoginResponse from server with ID 12.\n*/\nmessage SelectiveAck {\n  repeated string id = 1;\n}\n"
  },
  {
    "path": "play-services-core-proto/src/main/proto/potoken.proto",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\noption java_package = \"com.google.android.gms.potokens\";\n\noption java_multiple_files = true;\n\nmessage CipherKey {\n  optional int32 key = 1;\n  optional bytes value = 3;\n}\n\nmessage KeyData {\n  optional string typeUrl = 1;\n  optional CipherKey value = 2;\n  optional int32 keyMaterialType = 3;\n}\n\nmessage Key {\n  optional KeyData data = 1;\n  optional int32 status = 2;\n  optional int32 keyId = 3;\n  optional int32 outputPrefixType = 4;\n}\n\nmessage KeySet {\n  optional int32 keyId = 1;\n  repeated Key keyList = 2;\n}\n\nmessage PoTokenInfo {\n  optional int32 key = 6;\n  optional int32 time = 1;\n  optional bytes inputData = 2;\n  optional string pkgName = 3;\n  optional bytes pkgSignSha256 = 4;\n  optional bytes tokenData = 5;\n}\n\nmessage GetPoIntegrityTokenRequest {\n  optional int32 mode = 1;\n  optional bytes dgResult = 2;\n  optional bytes dgRandKey = 3;\n}\n\nmessage GetPoIntegrityTokenResponse {\n  optional bytes desc = 1;\n  optional int32 code = 2;\n  optional bytes backup = 3;\n//  optional bytes d = 4;\n//  optional bytes e = 5;\n}\n\nmessage PoTokenResult {\n  optional bytes encryptData = 1;\n  optional bytes tokenData = 2;\n}\n\nmessage PoTokenResultWrap {\n  optional PoTokenResult data = 1;\n}\n"
  },
  {
    "path": "play-services-core-proto/src/main/proto/registration.proto",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage google.internal.notifications.v1;\n\nservice NotificationsApiService {\n  rpc MultiLoginUpdate(RegistrationRequest) returns (RegistrationResponse);\n  rpc FetchLatestThreads(FetchLatestThreadsRequest) returns (FetchLatestThreadsResponse);\n}\n\nmessage RegistrationRequest {\n  optional string chimeGmsClientId = 1;\n  optional RegistrationPayload registrationPayload = 2;\n  repeated DeviceRequest devices = 3;\n  optional RegistrationReason reason = 5;\n  optional string internalTargetId = 7;\n}\n\nmessage RegistrationPayload {\n  optional Channel channel = 1;\n  optional AppRegistrationContainer appRegistrationContainer = 2;\n  optional string representativeTargetId = 3;\n}\n\nenum Channel {\n  CHANNEL_UNKNOWN = 0;\n  EMAIL = 1;\n  APPLE_PUSH = 2;\n  GCM_DEVICE_PUSH = 3;\n  SMS = 5;\n  CUSTOM_ENDPOINT = 6;\n  WEB_PUSH = 7;\n  MATCHSTICK = 8 [deprecated = true];\n  VIRTUAL_INBOX = 10;\n  IN_APP_TRAY = 11 [deprecated = true];\n  IN_WEB = 12;\n}\n\nmessage AppRegistrationContainer {\n    oneof appRegistrationChoice {\n      AppRegistration appRegistration = 1;\n  }\n}\n\nmessage AppRegistration {\n  optional string regId = 1;\n  optional string packageName = 2;\n  optional int64 androidId = 3;\n  optional int64 userSerialNumber = 4;\n}\n\nmessage DeviceRequest {\n  optional string unused = 1;\n  optional GmsDeviceContext gmsDeviceContext = 3;\n  optional int32 ttl = 4;\n  optional string representativeTargetId = 5;\n  optional AuthWrapper auth = 6;\n  optional string id = 7;\n}\n\nmessage GmsDeviceContext {\n  optional string languageTag = 1;\n  optional GmsDeviceProfile gmsDeviceProfile = 3;\n  optional string timeZoneId = 4;\n}\n\nmessage GmsDeviceProfile {\n  optional float density = 2;\n  optional string versionName = 3;\n  optional string release = 4;\n  optional string id = 5;\n  optional string model = 6;\n  optional int32 sdkVersion = 7;\n  optional string manufacturer = 8;\n  optional SdkType sdkType = 9;\n  optional string channelNumber = 10;\n  optional string deviceModel = 11;\n  repeated NotificationChannel channels = 12;\n  repeated NotificationChannelGroup channel_groups = 13;\n  optional AppBlockState appBlockState = 14;\n  optional string deviceCountry = 15;\n  optional FeatureBitmapList featureBitmapList = 16;\n  optional DeviceType deviceType = 18;\n  optional string unused = 24;\n}\n\nenum SdkType {\n  SDK_TYPE_UNSPECIFIED = 0;\n  CUSTOM = 1;\n  GUNS = 2;\n  CHIME = 3;\n  GUNS_GMSCORE = 4;\n  RAW_FCM_GMSCORE = 5;\n}\n\nmessage NotificationChannel {\n  optional string channelId = 1;\n  optional string groupId = 2;\n  optional NotificationImportance importance = 3;\n  enum UnknownMessage {\n    UNSPECIFIED = 0;\n    TRUE = 1;\n    FALSE = 2;\n  }\n  optional UnknownMessage unknownMessage = 4;\n}\n\nenum NotificationImportance {\n  IMPORTANCE_UNSPECIFIED = 0;\n  IMPORTANCE_NONE = 1;\n  IMPORTANCE_DEFAULT = 2;\n  IMPORTANCE_HIGH = 3;\n  IMPORTANCE_LOW = 4;\n  IMPORTANCE_MAX = 5;\n  IMPORTANCE_MIN = 6;\n}\n\nmessage NotificationChannelGroup {\n  optional string groupId = 1;\n  optional ChannelGroupStatus channelGroupStatus = 2;\n}\n\nenum ChannelGroupStatus {\n  CHANNEL_GROUP_UNKNOWN = 0;\n  CHANNEL_GROUP_ALLOWED = 1;\n  CHANNEL_GROUP_BANNED = 2;\n}\n\nenum AppBlockState {\n  APP_BLOCK_STATE_UNKNOWN = 0;\n  ALLOWED = 1;\n  BANNED = 2;\n}\n\nmessage FeatureBitmapList {\n  repeated uint64 featureBitmaps = 1;\n}\n\nenum DeviceType {\n  DEVICE_TYPE_DEFAULT = 0;\n  DEVICE_TYPE_TV = 1;\n  DEVICE_TYPE_WEARABLE = 2;\n  DEVICE_TYPE_AUTOMOTIVE = 3;\n  DEVICE_TYPE_BATTLESTAR = 4;\n  DEVICE_TYPE_CHROME_OS = 5;\n}\n\nmessage AuthWrapper {\n  message AuthToken {\n    optional string authToken = 1;\n  }\n\n  oneof auth {\n    AuthToken authTokenWrapper = 1;\n  }\n}\n\nenum RegistrationReason {\n  REGISTRATION_REASON_UNSPECIFIED = 0;\n  DEVICE_START = 1;\n  APP_UPDATED = 2;\n  ACCOUNT_CHANGED = 3;\n  SERVER_SYNC_INSTRUCTION = 4;\n  LOCALE_CHANGED = 5;\n  TIMEZONE_CHANGED = 6;\n  COLLABORATOR_API_CALL = 7;\n  GUNS_MIGRATION = 8;\n  REGISTRATION_ID_CHANGED = 9;\n  CHANNEL_BLOCK_STATE_CHANGED = 10;\n  GROWTHKIT_PERIODIC_REGISTRATION = 11;\n  PERIODIC_REGISTRATION = 12;\n  GMSCORE_DEBUG = 13;\n  APP_BLOCK_STATE_CHANGED = 14;\n}\n\nmessage RegistrationResponse {\n  repeated AccountRegistrationResult registrationResults = 1;\n  optional string internalTargetId = 2;\n}\n\nmessage AccountRegistrationResult {\n  optional RegistrationError error = 1;\n  optional RegistrationPayload payload = 2;\n  optional string obfuscatedGaiaId = 4;\n  optional string id = 6;\n  optional bool success = 7;\n}\n\nmessage RegistrationError {\n  optional int32 errorCode = 1;\n  optional string errorMessage = 2;\n}\n\nenum RegistrationStatus {\n  STATUS_UNKNOWN = 0;\n  STATUS_REGISTERED = 1;\n  STATUS_PENDING_REGISTRATION = 2;\n  STATUS_FAILED_REGISTRATION = 3;\n  STATUS_UNREGISTERED = 4;\n  STATUS_PENDING_UNREGISTRATION = 5;\n  STATUS_FAILED_UNREGISTRATION = 6;\n}\n\nmessage FetchLatestThreadsRequest {\n}\n\nmessage FetchLatestThreadsResponse {\n}\n"
  },
  {
    "path": "play-services-core-proto/src/main/proto/snapshot.proto",
    "content": "package google.play.games.games.v1;\n\noption java_outer_classname = \"SnapshotProto\";\n\noption java_package = \"org.microg.gms.games\";\noption java_multiple_files = true;\n\nservice SnapshotsExtended {\n  rpc SyncSnapshots (GetSnapshotRequest) returns (GetSnapshotResponse);\n  rpc DeleteSnapshot (DeleteSnapshotInfo) returns (EmptyResult);\n  rpc ResolveSnapshotHead(ResolveSnapshotHeadRequest) returns (ResolveSnapshotHeadResponse);\n  rpc PrepareSnapshotRevision(PrepareSnapshotRevisionRequest) returns (PrepareSnapshotRevisionResponse);\n  rpc CommitSnapshotRevision(CommitSnapshotRevisionRequest) returns (EmptyResult);\n}\n\nmessage ResolveSnapshotHeadResponse {\n  optional SnapshotMetadata snapshotMetadata = 1;\n}\n\nmessage PrepareSnapshotRevisionRequest {\n  optional string title = 1;\n  repeated ukq c = 2;\n  optional string randomUUID = 3;\n}\n\nmessage PrepareSnapshotRevisionResponse {\n  optional string title = 1;\n  repeated UploadLinkInfo uploadLinkInfos = 2;\n}\n\nmessage CommitSnapshotRevisionRequest {\n  optional string snapshotName = 1;\n  optional Snapshot snapshot = 3;\n  optional string unknownFileString2 = 2;\n  repeated string unknownFileString4 = 4;\n  optional string randomUUID = 5;\n  optional string oneofField6 = 6;\n  optional int32 unknownFileInt7 = 7;\n}\n\nmessage UploadLinkInfo {\n  optional int32 id = 2;\n  optional string url = 3;\n  optional int32 unknownFileInt4 = 4;\n}\n\nmessage ukq {\n  optional int32 unknownFileInt1 = 1;\n  optional int32 unknownFileInt2 = 2;\n}\n\nmessage ResolveSnapshotHeadRequest {\n  optional string snapshotName = 1;\n  optional int32 unknownFileInt2 = 2;\n  optional int32 unknownFileInt3 = 3;\n}\n\nmessage GetSnapshotRequest {\n  repeated int32 unknownFileIntList3 = 3;\n  optional int32 unknownFileInt4 = 4;\n  optional int32 unknownFileInt6 = 6;\n}\n\nmessage DeleteSnapshotInfo {\n  optional string snapshotName = 1;\n  optional string snapshotId = 2;\n}\n\nmessage EmptyResult {\n\n}\n\nmessage GetSnapshotResponse {\n  repeated GameSnapshot gameSnapshot = 1;\n  optional string dataSnapshot = 2;\n  optional string unknownFileString3 = 3;\n  optional int32 unknownFileInt4 = 4;\n}\n\nmessage GameSnapshot {\n  optional SnapshotMetadata metadata = 1;\n  optional int32 type = 2;\n}\n\nmessage SnapshotMetadata {\n  optional string snapshotName = 1;\n  optional Snapshot snapshot = 2;\n  optional int32 type = 3;\n  repeated Snapshot snapshots = 4;\n}\n\nmessage Snapshot {\n  optional string snapshotId = 1;\n  optional SnapshotContent content = 2;\n  optional SnapshotContentInfo snapshotContentInfo = 3;\n  optional SnapshotImage coverImage = 4;\n}\n\nmessage SnapshotContent {\n  optional string description = 2;\n  optional SnapshotTimeInfo snapshotTimeInfo = 3;\n  optional int64 progressValue = 5;\n  optional string deviceName = 6;\n  optional int64 duration = 7;\n}\n\nmessage SnapshotTimeInfo {\n  required int64 timestamp = 1;\n  required int32 playedTime = 2;\n}\n\nmessage SnapshotContentInfo {\n  optional string token = 1;\n  optional string url = 2;\n  optional string contentHash = 3;\n  optional int64 size = 4;\n}\n\nmessage SnapshotImage {\n  optional string token = 1;\n  optional string imageUrl = 2;\n  optional int32 width = 3;\n  optional int32 height = 4;\n  optional string contentHash = 5;\n  optional string mimeType = 6;\n}"
  },
  {
    "path": "play-services-core-proto/src/main/proto/uploaddeviceconfig.proto",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\n// This should be part of the vending package, but it is hard to import proto\n// files from other modules.\n\noption java_package = \"org.microg.vending\";\noption java_outer_classname = \"UploadDeviceConfigRequest\";\n\nimport \"deviceconfig.proto\";\n\nmessage UploadDeviceConfigRequest {\n  optional DeviceConfig deviceConfiguration = 1;\n  optional string manufacturer = 2;\n  optional string gcmRegistrationId = 3;\n}"
  },
  {
    "path": "play-services-cronet/core/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\ndependencies {\n    // TODO: Embedding the API causes random crashes as the Android AOT compiler will link the native implementation to\n    // out API classes even if embedded by a third-party app that comes with their own API classes.\n    // Need to find a better way to disable AOT for Cronet. Could be by packaging cronet as it's own apk that is\n    // embedded in the main APK but only loaded at runtime so that the AOT compiler has no way to become active.\n    // implementation(\"org.microg:cronet-api:$cronetVersion\")\n    implementation(\"org.microg:cronet-common:$cronetVersion\")\n    implementation(\"org.microg:cronet-native:$cronetVersion\")\n}\n\nandroid {\n    namespace \"org.microg.gms.net.core\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    lintOptions {\n        disable 'MissingTranslation'\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n}\n\napply from: '../../gradle/publish-android.gradle'\n\ndescription = 'microG service implementation for play-services-cronet'\n"
  },
  {
    "path": "play-services-cronet/core/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2021, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <application>\n    </application>\n</manifest>\n"
  },
  {
    "path": "play-services-cronet/core/src/main/java/com/google/android/gms/dynamite/descriptors/com/google/android/gms/cronet_dynamite/ModuleDescriptor.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.dynamite.descriptors.com.google.android.gms.cronet_dynamite;\n\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class ModuleDescriptor {\n    public static final String MODULE_ID = \"com.google.android.gms.cronet_dynamite\";\n    public static final int MODULE_VERSION = 2;\n    public static final List<String> MERGED_CLASSES = Arrays.asList(\n            \"org.chromium.net.ApiVersion\",\n            \"org.chromium.net.BidirectionalStream\",\n            \"org.chromium.net.CallbackException\",\n            \"org.chromium.net.CronetEngine\",\n            \"org.chromium.net.CronetException\",\n            \"org.chromium.net.CronetProvider\",\n            \"org.chromium.net.ExperimentalBidirectionalStream\",\n            \"org.chromium.net.ExperimentalCronetEngine\",\n            \"org.chromium.net.ExperimentalUrlRequest\",\n            \"org.chromium.net.ICronetEngineBuilder\",\n            \"org.chromium.net.InlineExecutionProhibitedException\",\n            \"org.chromium.net.NetworkException\",\n            \"org.chromium.net.NetworkQualityRttListener\",\n            \"org.chromium.net.NetworkQualityThroughputListener\",\n            \"org.chromium.net.QuicException\",\n            \"org.chromium.net.RequestFinishedInfo\",\n            \"org.chromium.net.UploadDataProvider\",\n            \"org.chromium.net.UploadDataProviders\",\n            \"org.chromium.net.UploadDataSink\",\n            \"org.chromium.net.UrlRequest\",\n            \"org.chromium.net.UrlResponseInfo\"\n    );\n}\n"
  },
  {
    "path": "play-services-drive/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\nandroid {\n    namespace \"com.google.android.gms.drive\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n}\n\napply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG implementation of play-services-drive'\n\ndependencies {\n    // Dependencies from play-services-drive:17.0.0\n    api \"androidx.collection:collection:1.0.0\"\n    api project(':play-services-base')\n    api project(':play-services-basement')\n    api project(':play-services-tasks')\n    annotationProcessor project(':safe-parcel-processor')\n}\n"
  },
  {
    "path": "play-services-drive/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest />"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/Contents.aidl",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.drive;\n\nparcelable Contents;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/DriveId.aidl",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.drive;\n\nparcelable DriveId;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/AddEventListenerRequest.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable AddEventListenerRequest;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/AddPermissionRequest.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable AddPermissionRequest;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/AuthorizeAccessRequest.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable AuthorizeAccessRequest;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/CancelPendingActionsRequest.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable CancelPendingActionsRequest;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/ChangeResourceParentsRequest.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable ChangeResourceParentsRequest;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/ChangeSequenceNumber.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable ChangeSequenceNumber;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/ChangesResponse.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable ChangesResponse;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/CheckResourceIdsExistRequest.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable CheckResourceIdsExistRequest;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/CloseContentsAndUpdateMetadataRequest.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable CloseContentsAndUpdateMetadataRequest;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/CloseContentsRequest.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable CloseContentsRequest;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/ContentsResponse.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable ContentsResponse;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/ControlProgressRequest.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable ControlProgressRequest;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/CreateContentsRequest.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable CreateContentsRequest;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/CreateFileIntentSenderRequest.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable CreateFileIntentSenderRequest;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/CreateFileRequest.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable CreateFileRequest;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/CreateFolderRequest.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable CreateFolderRequest;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/DeleteResourceRequest.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable DeleteResourceRequest;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/DeviceUsagePreferenceResponse.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable DeviceUsagePreferenceResponse;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/DisconnectRequest.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable DisconnectRequest;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/DownloadProgressResponse.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable DownloadProgressResponse;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/DriveIdResponse.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable DriveIdResponse;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/DrivePreferencesResponse.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable DrivePreferencesResponse;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/DriveServiceResponse.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable DriveServiceResponse;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/EventResponse.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable EventResponse;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/FetchThumbnailRequest.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable FetchThumbnailRequest;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/FetchThumbnailResponse.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable FetchThumbnailResponse;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/GetChangesRequest.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable GetChangesRequest;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/GetDriveIdFromUniqueIdRequest.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable GetDriveIdFromUniqueIdRequest;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/GetMetadataRequest.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable GetMetadataRequest;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/GetPermissionsRequest.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable GetPermissionsRequest;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/GetPermissionsResponse.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable GetPermissionsResponse;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/IDriveService.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nimport com.google.android.gms.drive.internal.DriveServiceResponse;\nimport com.google.android.gms.drive.internal.IDriveServiceCallbacks;\nimport com.google.android.gms.drive.internal.IEventCallback;\n\nimport com.google.android.gms.drive.internal.AddEventListenerRequest;\nimport com.google.android.gms.drive.internal.AddPermissionRequest;\nimport com.google.android.gms.drive.internal.AuthorizeAccessRequest;\nimport com.google.android.gms.drive.internal.CancelPendingActionsRequest;\nimport com.google.android.gms.drive.internal.ChangeResourceParentsRequest;\nimport com.google.android.gms.drive.internal.CheckResourceIdsExistRequest;\nimport com.google.android.gms.drive.internal.CloseContentsAndUpdateMetadataRequest;\nimport com.google.android.gms.drive.internal.CloseContentsRequest;\nimport com.google.android.gms.drive.internal.ControlProgressRequest;\nimport com.google.android.gms.drive.internal.CreateContentsRequest;\nimport com.google.android.gms.drive.internal.CreateFileRequest;\nimport com.google.android.gms.drive.internal.CreateFileIntentSenderRequest;\nimport com.google.android.gms.drive.internal.CreateFolderRequest;\nimport com.google.android.gms.drive.internal.DeleteResourceRequest;\nimport com.google.android.gms.drive.internal.DisconnectRequest;\nimport com.google.android.gms.drive.internal.FetchThumbnailRequest;\nimport com.google.android.gms.drive.internal.GetChangesRequest;\nimport com.google.android.gms.drive.internal.GetDriveIdFromUniqueIdRequest;\nimport com.google.android.gms.drive.internal.GetMetadataRequest;\nimport com.google.android.gms.drive.internal.GetPermissionsRequest;\nimport com.google.android.gms.drive.internal.ListParentsRequest;\nimport com.google.android.gms.drive.internal.LoadRealtimeRequest;\nimport com.google.android.gms.drive.internal.OpenContentsRequest;\nimport com.google.android.gms.drive.internal.OpenFileIntentSenderRequest;\nimport com.google.android.gms.drive.internal.RealtimeDocumentSyncRequest;\nimport com.google.android.gms.drive.internal.RemoveEventListenerRequest;\nimport com.google.android.gms.drive.internal.RemovePermissionRequest;\nimport com.google.android.gms.drive.internal.SetDrivePreferencesRequest;\nimport com.google.android.gms.drive.internal.SetFileUploadPreferencesRequest;\nimport com.google.android.gms.drive.internal.SetResourceParentsRequest;\nimport com.google.android.gms.drive.internal.StreamContentsRequest;\nimport com.google.android.gms.drive.internal.TrashResourceRequest;\nimport com.google.android.gms.drive.internal.UnsubscribeResourceRequest;\nimport com.google.android.gms.drive.internal.UntrashResourceRequest;\nimport com.google.android.gms.drive.internal.UpdateMetadataRequest;\nimport com.google.android.gms.drive.internal.UpdatePermissionRequest;\n\ninterface IDriveService {\n    void getMetadata(in GetMetadataRequest request, IDriveServiceCallbacks callbacks) = 0;\n\n    void updateMetadata(in UpdateMetadataRequest request, IDriveServiceCallbacks callbacks) = 2;\n    void createContents(in CreateContentsRequest request, IDriveServiceCallbacks callbacks) = 3;\n    void createFile(in CreateFileRequest request, IDriveServiceCallbacks callbacks) = 4;\n    void createFolder(in CreateFolderRequest request, IDriveServiceCallbacks callbacks) = 5;\n    DriveServiceResponse openContents(in OpenContentsRequest request, IDriveServiceCallbacks callbacks) = 6;\n    void closeContents(in CloseContentsRequest request, IDriveServiceCallbacks callbacks) = 7;\n    void requestSync(IDriveServiceCallbacks callbacks) = 8;\n    IntentSender openFileIntentSender(in OpenFileIntentSenderRequest request) = 9;\n    IntentSender createFileIntentSender(in CreateFileIntentSenderRequest request) = 10;\n    void authorizeAccess(in AuthorizeAccessRequest request, IDriveServiceCallbacks callbacks) = 11;\n    void listParents(in ListParentsRequest request, IDriveServiceCallbacks callbacks) = 12;\n    void addEventListener(in AddEventListenerRequest request, IEventCallback callback, String unused, IDriveServiceCallbacks callbacks) = 13;\n    void removeEventListener(in RemoveEventListenerRequest request, IEventCallback callback, String unused, IDriveServiceCallbacks callbacks) = 14;\n    void disconnect(in DisconnectRequest request) = 15;\n    void trashResource(in TrashResourceRequest request, IDriveServiceCallbacks callbacks) = 16;\n    void closeContentsAndUpdateMetadata(in CloseContentsAndUpdateMetadataRequest request, IDriveServiceCallbacks callbacks) = 17;\n\n    void deleteResource(in DeleteResourceRequest request, IDriveServiceCallbacks callbacks) = 23;\n\n    void loadRealtime(in LoadRealtimeRequest request, IDriveServiceCallbacks callbacks) = 26;\n    void setResourceParents(in SetResourceParentsRequest request, IDriveServiceCallbacks callbacks) = 27;\n    void getDriveIdFromUniqueId(in GetDriveIdFromUniqueIdRequest request, IDriveServiceCallbacks callbacks) = 28;\n    void checkResourceIdsExist(in CheckResourceIdsExistRequest request, IDriveServiceCallbacks callbacks) = 29;\n    void completePendingAction(IDriveServiceCallbacks callbacks) = 30;\n    void getDrivePreferences(IDriveServiceCallbacks callbacks) = 31;\n    void setDrivePreferences(in SetDrivePreferencesRequest request, IDriveServiceCallbacks callbacks) = 32;\n    void realtimeDocumentSync(in RealtimeDocumentSyncRequest request, IDriveServiceCallbacks callbacks) = 33;\n    void getDeviceUsagePreferences(IDriveServiceCallbacks callbacks) = 34;\n    void setFileUploadPreferences(in SetFileUploadPreferencesRequest request, IDriveServiceCallbacks callbacks) = 35;\n    void cancelPendingActions(in CancelPendingActionsRequest request, IDriveServiceCallbacks callbacks) = 36;\n    void untrashResource(in UntrashResourceRequest request, IDriveServiceCallbacks callbacks) = 37;\n\n    void isAutoBackupEnabled(IDriveServiceCallbacks callbacks) = 40;\n    void fetchThumbnail(in FetchThumbnailRequest request, IDriveServiceCallbacks callbacks) = 41;\n\n    void getChanges(in GetChangesRequest request, IDriveServiceCallbacks callbacks) = 43;\n\n    void unsubscribeResource(in UnsubscribeResourceRequest request, IDriveServiceCallbacks callbacks) = 45;\n    void getPermissions(in GetPermissionsRequest request, IDriveServiceCallbacks callbacks) = 46;\n    void addPermission(in AddPermissionRequest request, IDriveServiceCallbacks callbacks) = 47;\n    void updatePermission(in UpdatePermissionRequest request, IDriveServiceCallbacks callbacks) = 48;\n    void removePermission(in RemovePermissionRequest request, IDriveServiceCallbacks callbacks) = 49;\n\n    void removeQueryResultListener(IEventCallback callback, IDriveServiceCallbacks callbacks) = 51;\n    void controlProgress(in ControlProgressRequest request, IDriveServiceCallbacks callbacks) = 52;\n\n    void changeResourceParents(in ChangeResourceParentsRequest request, IDriveServiceCallbacks callbacks) = 54;\n    DriveServiceResponse streamContents(in StreamContentsRequest request, IDriveServiceCallbacks callbacks) = 55;\n}\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/IDriveServiceCallbacks.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nimport com.google.android.gms.drive.internal.IRealtimeService;\n\nimport com.google.android.gms.drive.internal.DownloadProgressResponse;\nimport com.google.android.gms.drive.internal.ListEntriesResponse;\nimport com.google.android.gms.drive.internal.DriveIdResponse;\nimport com.google.android.gms.drive.internal.MetadataResponse;\nimport com.google.android.gms.drive.internal.ContentsResponse;\nimport com.google.android.gms.drive.internal.ListParentsResponse;\nimport com.google.android.gms.drive.internal.SyncMoreResponse;\nimport com.google.android.gms.drive.internal.LoadRealtimeResponse;\nimport com.google.android.gms.drive.internal.ResourceIdSetResponse;\nimport com.google.android.gms.drive.internal.DrivePreferencesResponse;\nimport com.google.android.gms.drive.internal.DeviceUsagePreferenceResponse;\nimport com.google.android.gms.drive.internal.FetchThumbnailResponse;\nimport com.google.android.gms.drive.internal.ChangeSequenceNumber;\nimport com.google.android.gms.drive.internal.ChangesResponse;\nimport com.google.android.gms.drive.internal.GetPermissionsResponse;\nimport com.google.android.gms.drive.internal.StringListResponse;\nimport com.google.android.gms.drive.internal.StartStreamSession;\n\nimport com.google.android.gms.common.api.Status;\n\ninterface IDriveServiceCallbacks {\n    void onDownloadProgress(in DownloadProgressResponse response) = 0;\n    void onListEntries(in ListEntriesResponse response) = 1;\n    void onDriveId(in DriveIdResponse response) = 2;\n    void onMetadata(in MetadataResponse response) = 3;\n    void onContents(in ContentsResponse response) = 4;\n    void onStatus(in Status status) = 5;\n    void onSuccess() = 6;\n    void onListParents(in ListParentsResponse response) = 7;\n    void onSyncMore(in SyncMoreResponse response) = 8;\n\n    void onLoadRealtime(in LoadRealtimeResponse response, IRealtimeService realtimeService) = 10;\n    void onResourceIdSet(in ResourceIdSetResponse response) = 11;\n    void onDrivePreferences(in DrivePreferencesResponse response) = 12;\n    void onDeviceUsagePreference(in DeviceUsagePreferenceResponse response) = 13;\n    void onBooleanAnswer(boolean bool) = 14;\n    void onFetchThumbnail(in FetchThumbnailResponse response) = 15;\n    void onChangeSequenceNumber(in ChangeSequenceNumber csn) = 16;\n    void onChanges(in ChangesResponse response) = 17;\n\n    void onGetPermissions(in GetPermissionsResponse response) = 19;\n    void onStringList(in StringListResponse response) = 20;\n    void onStartStreamSession(in StartStreamSession response) = 21;\n}\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/IEventCallback.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nimport com.google.android.gms.drive.internal.EventResponse;\n\ninterface IEventCallback {\n    void onEventResponse(in EventResponse response) = 0;\n}\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/IRealtimeService.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\ninterface IRealtimeService {\n    // TODO\n}\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/ListEntriesResponse.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable ListEntriesResponse;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/ListParentsRequest.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable ListParentsRequest;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/ListParentsResponse.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable ListParentsResponse;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/LoadRealtimeRequest.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable LoadRealtimeRequest;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/LoadRealtimeResponse.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable LoadRealtimeResponse;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/MetadataResponse.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable MetadataResponse;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/OpenContentsRequest.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable OpenContentsRequest;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/OpenFileIntentSenderRequest.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable OpenFileIntentSenderRequest;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/RealtimeDocumentSyncRequest.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable RealtimeDocumentSyncRequest;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/RemoveEventListenerRequest.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable RemoveEventListenerRequest;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/RemovePermissionRequest.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable RemovePermissionRequest;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/ResourceIdSetResponse.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable ResourceIdSetResponse;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/SetDrivePreferencesRequest.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable SetDrivePreferencesRequest;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/SetFileUploadPreferencesRequest.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable SetFileUploadPreferencesRequest;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/SetResourceParentsRequest.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable SetResourceParentsRequest;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/StartStreamSession.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable StartStreamSession;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/StreamContentsRequest.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable StreamContentsRequest;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/StringListResponse.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable StringListResponse;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/SyncMoreResponse.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable SyncMoreResponse;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/TrashResourceRequest.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable TrashResourceRequest;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/UnsubscribeResourceRequest.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable UnsubscribeResourceRequest;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/UntrashResourceRequest.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable UntrashResourceRequest;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/UpdateMetadataRequest.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable UpdateMetadataRequest;\n"
  },
  {
    "path": "play-services-drive/src/main/aidl/com/google/android/gms/drive/internal/UpdatePermissionRequest.aidl",
    "content": "package com.google.android.gms.drive.internal;\n\nparcelable UpdatePermissionRequest;\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/Contents.java",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.drive;\n\nimport android.os.Parcel;\nimport android.os.ParcelFileDescriptor;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\n\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.OutputStream;\n\n@Hide\n@SafeParcelable.Class\npublic class Contents extends AbstractSafeParcelable {\n\n    @Field(value = 2, getterName = \"getParcelFileDescriptor\")\n    private final ParcelFileDescriptor fileDescriptor;\n    @Field(value = 3, getterName = \"getRequestId\")\n    private final int requestId;\n    @Field(value = 4, getterName = \"getMode\")\n    private final int mode;\n    @Field(value = 5, getterName = \"getDriveId\")\n    private final DriveId driveId;\n    @Field(value = 7)\n    final boolean unknown7;\n    @Field(value = 8)\n    @Nullable\n    final String unknown8;\n\n    @Constructor\n    public Contents(@Param(value = 2) ParcelFileDescriptor fileDescriptor, @Param(value = 3) int requestId, @Param(value = 4) int mode, @Param(value = 5) DriveId driveId, @Param(value = 7) boolean unknown7, @Param(value = 8) @Nullable String unknown8) {\n        this.fileDescriptor = fileDescriptor;\n        this.requestId = requestId;\n        this.mode = mode;\n        this.driveId = driveId;\n        this.unknown7 = unknown7;\n        this.unknown8 = unknown8;\n    }\n\n    public ParcelFileDescriptor getParcelFileDescriptor() {\n        return this.fileDescriptor;\n    }\n\n    public final DriveId getDriveId() {\n        return this.driveId;\n    }\n\n    public final FileInputStream getInputStream() {\n        return new FileInputStream(this.fileDescriptor.getFileDescriptor());\n    }\n\n    public final OutputStream getOutputStream() {\n        return new FileOutputStream(this.fileDescriptor.getFileDescriptor());\n    }\n\n    public final int getMode() {\n        return this.mode;\n    }\n\n    public final int getRequestId() {\n        return this.requestId;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<Contents> CREATOR = findCreator(Contents.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/DriveId.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.drive;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\n\n/**\n * A canonical identifier for a Drive resource. The identifier can be converted to a String representation for storage using {@link #encodeToString()}\n * and then later converted back to the ID representation using {@link #decodeFromString(String)}. {@link #equals(Object)} can be used to see if two\n * different identifiers refer to the same resource.\n */\n@SafeParcelable.Class\npublic class DriveId extends AbstractSafeParcelable {\n    /**\n     * An unknown resource type, meaning the {@link DriveId} corresponds to either a file or a folder.\n     */\n    public static final int RESOURCE_TYPE_UNKNOWN = -1;\n    /**\n     * A file resource type, meaning the {@link DriveId} corresponds to a file.\n     */\n    public static final int RESOURCE_TYPE_FILE = 0;\n    /**\n     * A folder resource type, meaning the {@link DriveId} corresponds to a folder.\n     */\n    public static final int RESOURCE_TYPE_FOLDER = 1;\n\n    @Field(value = 2, getterName = \"getResourceId\")\n    @Nullable\n    private final String resourceId;\n    @Field(value = 3)\n    private final long unknown3;\n    @Field(value = 4)\n    private final long unknown4;\n    @Field(value = 5, getterName = \"getResourceType\", defaultValue = \"com.google.android.gms.drive.DriveId.RESOURCE_TYPE_UNKNOWN\")\n    private final int resourceType;\n\n    @Constructor\n    @Hide\n    public DriveId(@Param(value = 2) @Nullable String resourceId, @Param(value = 3) long unknown3, @Param(value = 4) long unknown4, @Param(value = 5) int resourceType) {\n        this.resourceId = resourceId;\n        this.unknown3 = unknown3;\n        this.unknown4 = unknown4;\n        this.resourceType = resourceType;\n    }\n\n    /**\n     * Returns a String representation of this {@link DriveId} that can be safely persisted, and from which an equivalent {@link DriveId} can later be\n     * reconstructed using {@link #decodeFromString(String)}.\n     * <p>\n     * The String representation is not guaranteed to be stable over time for a given resource so should never be compared for equality. Always\n     * use {@link #decodeFromString(String)} and then {@link #equals(Object)} to compare two identifiers to see if they refer to the same resource.\n     * Otherwise, {@link #toInvariantString()} is stable and can be safely used for {@link DriveId} comparison.\n     */\n    public final String encodeToString() {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Returns the remote Drive resource id associated with the resource. May be {@code null} for local resources that have not yet been synchronized to\n     * the Drive service.\n     */\n    @Nullable\n    public String getResourceId() {\n        return this.resourceId;\n    }\n\n    /**\n     * Returns the resource type corresponding to this {@link DriveId}. Possible values are {@link #RESOURCE_TYPE_FILE}, {@link #RESOURCE_TYPE_FOLDER} or\n     * {@link #RESOURCE_TYPE_UNKNOWN}.\n     * <p>\n     * The {@link #RESOURCE_TYPE_UNKNOWN} will only be returned if the {@link DriveId} instance has been created using {@link #decodeFromString(String)}, with an\n     * old string that was generated and persisted by the client with an old version of Google Play Services. If the client is not encoding, persisting\n     * and decoding {@link DriveId}s, this method will always return either {@link #RESOURCE_TYPE_FILE} or {@link #RESOURCE_TYPE_FOLDER}.\n     */\n    public int getResourceType() {\n        return this.resourceType;\n    }\n\n    /**\n     * Returns an invariant string for this {@link DriveId}. This is stable over time, so for a given {@link DriveId}, this value will always remain the same, and is\n     * guaranteed to be unique for each {@link DriveId}. The client can use it directly to compare equality of {@link DriveId}s, since two {@link DriveId}s are equal\n     * if and only if its invariant string is equal.\n     * <p>\n     * Note: This value cannot be used to {@link #decodeFromString(String)}, since it's not meant to encode a {@link DriveId}, but can be useful for client-side\n     * string-based {@link DriveId} comparison, or for logging purposes.\n     */\n    public final String toInvariantString() {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Decodes the result of {@link #encodeToString()} back into a {@link DriveId}.\n     * @throws IllegalArgumentException if the argument is not a valid result of {@link #encodeToString()}.\n     */\n    public static DriveId decodeFromString (String s) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<DriveId> CREATOR = findCreator(DriveId.class);\n}\n\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/AddEventListenerRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class AddEventListenerRequest extends AutoSafeParcelable {\n    public static Creator<AddEventListenerRequest> CREATOR = new AutoCreator<AddEventListenerRequest>(AddEventListenerRequest.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/AddPermissionRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class AddPermissionRequest extends AutoSafeParcelable {\n    public static Creator<AddPermissionRequest> CREATOR = new AutoCreator<AddPermissionRequest>(AddPermissionRequest.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/AuthorizeAccessRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class AuthorizeAccessRequest extends AutoSafeParcelable {\n    public static Creator<AuthorizeAccessRequest> CREATOR = new AutoCreator<AuthorizeAccessRequest>(AuthorizeAccessRequest.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/CancelPendingActionsRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class CancelPendingActionsRequest extends AutoSafeParcelable {\n    public static Creator<CancelPendingActionsRequest> CREATOR = new AutoCreator<CancelPendingActionsRequest>(CancelPendingActionsRequest.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/ChangeResourceParentsRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class ChangeResourceParentsRequest extends AutoSafeParcelable {\n    public static Creator<ChangeResourceParentsRequest> CREATOR = new AutoCreator<ChangeResourceParentsRequest>(ChangeResourceParentsRequest.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/ChangeSequenceNumber.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class ChangeSequenceNumber extends AutoSafeParcelable {\n    public static Creator<ChangeSequenceNumber> CREATOR = new AutoCreator<ChangeSequenceNumber>(ChangeSequenceNumber.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/ChangesResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class ChangesResponse extends AutoSafeParcelable {\n    public static Creator<ChangesResponse> CREATOR = new AutoCreator<ChangesResponse>(ChangesResponse.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/CheckResourceIdsExistRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class CheckResourceIdsExistRequest extends AutoSafeParcelable {\n    public static Creator<CheckResourceIdsExistRequest> CREATOR = new AutoCreator<CheckResourceIdsExistRequest>(CheckResourceIdsExistRequest.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/CloseContentsAndUpdateMetadataRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class CloseContentsAndUpdateMetadataRequest extends AutoSafeParcelable {\n    public static Creator<CloseContentsAndUpdateMetadataRequest> CREATOR = new AutoCreator<CloseContentsAndUpdateMetadataRequest>(CloseContentsAndUpdateMetadataRequest.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/CloseContentsRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class CloseContentsRequest extends AutoSafeParcelable {\n    public static Creator<CloseContentsRequest> CREATOR = new AutoCreator<CloseContentsRequest>(CloseContentsRequest.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/ContentsResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class ContentsResponse extends AutoSafeParcelable {\n    public static Creator<ContentsResponse> CREATOR = new AutoCreator<ContentsResponse>(ContentsResponse.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/ControlProgressRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class ControlProgressRequest extends AutoSafeParcelable {\n    public static Creator<ControlProgressRequest> CREATOR = new AutoCreator<ControlProgressRequest>(ControlProgressRequest.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/CreateContentsRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class CreateContentsRequest extends AutoSafeParcelable {\n    public static Creator<CreateContentsRequest> CREATOR = new AutoCreator<CreateContentsRequest>(CreateContentsRequest.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/CreateFileIntentSenderRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class CreateFileIntentSenderRequest extends AutoSafeParcelable {\n    public static Creator<CreateFileIntentSenderRequest> CREATOR = new AutoCreator<CreateFileIntentSenderRequest>(CreateFileIntentSenderRequest.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/CreateFileRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class CreateFileRequest extends AutoSafeParcelable {\n    public static Creator<CreateFileRequest> CREATOR = new AutoCreator<CreateFileRequest>(CreateFileRequest.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/CreateFolderRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class CreateFolderRequest extends AutoSafeParcelable {\n    public static Creator<CreateFolderRequest> CREATOR = new AutoCreator<CreateFolderRequest>(CreateFolderRequest.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/DeleteResourceRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class DeleteResourceRequest extends AutoSafeParcelable {\n    public static Creator<DeleteResourceRequest> CREATOR = new AutoCreator<DeleteResourceRequest>(DeleteResourceRequest.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/DeviceUsagePreferenceResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class DeviceUsagePreferenceResponse extends AutoSafeParcelable {\n    public static Creator<DeviceUsagePreferenceResponse> CREATOR = new AutoCreator<DeviceUsagePreferenceResponse>(DeviceUsagePreferenceResponse.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/DisconnectRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class DisconnectRequest extends AutoSafeParcelable {\n    public static Creator<DisconnectRequest> CREATOR = new AutoCreator<DisconnectRequest>(DisconnectRequest.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/DownloadProgressResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class DownloadProgressResponse extends AutoSafeParcelable {\n    public static Creator<DownloadProgressResponse> CREATOR = new AutoCreator<DownloadProgressResponse>(DownloadProgressResponse.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/DriveIdResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class DriveIdResponse extends AutoSafeParcelable {\n    public static Creator<DriveIdResponse> CREATOR = new AutoCreator<DriveIdResponse>(DriveIdResponse.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/DrivePreferencesResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class DrivePreferencesResponse extends AutoSafeParcelable {\n    public static Creator<DrivePreferencesResponse> CREATOR = new AutoCreator<DrivePreferencesResponse>(DrivePreferencesResponse.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/DriveServiceResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class DriveServiceResponse extends AutoSafeParcelable {\n    public static Creator<DriveServiceResponse> CREATOR = new AutoCreator<DriveServiceResponse>(DriveServiceResponse.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/EventResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class EventResponse extends AutoSafeParcelable {\n    public static Creator<EventResponse> CREATOR = new AutoCreator<EventResponse>(EventResponse.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/FetchThumbnailRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class FetchThumbnailRequest extends AutoSafeParcelable {\n    public static Creator<FetchThumbnailRequest> CREATOR = new AutoCreator<FetchThumbnailRequest>(FetchThumbnailRequest.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/FetchThumbnailResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class FetchThumbnailResponse extends AutoSafeParcelable {\n    public static Creator<FetchThumbnailResponse> CREATOR = new AutoCreator<FetchThumbnailResponse>(FetchThumbnailResponse.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/GetChangesRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class GetChangesRequest extends AutoSafeParcelable {\n    public static Creator<GetChangesRequest> CREATOR = new AutoCreator<GetChangesRequest>(GetChangesRequest.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/GetDriveIdFromUniqueIdRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class GetDriveIdFromUniqueIdRequest extends AutoSafeParcelable {\n    public static Creator<GetDriveIdFromUniqueIdRequest> CREATOR = new AutoCreator<GetDriveIdFromUniqueIdRequest>(GetDriveIdFromUniqueIdRequest.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/GetMetadataRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class GetMetadataRequest extends AutoSafeParcelable {\n    public static Creator<GetMetadataRequest> CREATOR = new AutoCreator<GetMetadataRequest>(GetMetadataRequest.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/GetPermissionsRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class GetPermissionsRequest extends AutoSafeParcelable {\n    public static Creator<GetPermissionsRequest> CREATOR = new AutoCreator<GetPermissionsRequest>(GetPermissionsRequest.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/GetPermissionsResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class GetPermissionsResponse extends AutoSafeParcelable {\n    public static Creator<GetPermissionsResponse> CREATOR = new AutoCreator<GetPermissionsResponse>(GetPermissionsResponse.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/ListEntriesResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class ListEntriesResponse extends AutoSafeParcelable {\n    public static Creator<ListEntriesResponse> CREATOR = new AutoCreator<ListEntriesResponse>(ListEntriesResponse.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/ListParentsRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class ListParentsRequest extends AutoSafeParcelable {\n    public static Creator<ListParentsRequest> CREATOR = new AutoCreator<ListParentsRequest>(ListParentsRequest.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/ListParentsResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class ListParentsResponse extends AutoSafeParcelable {\n    public static Creator<ListParentsResponse> CREATOR = new AutoCreator<ListParentsResponse>(ListParentsResponse.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/LoadRealtimeRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class LoadRealtimeRequest extends AutoSafeParcelable {\n    public static Creator<LoadRealtimeRequest> CREATOR = new AutoCreator<LoadRealtimeRequest>(LoadRealtimeRequest.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/LoadRealtimeResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class LoadRealtimeResponse extends AutoSafeParcelable {\n    public static Creator<LoadRealtimeResponse> CREATOR = new AutoCreator<LoadRealtimeResponse>(LoadRealtimeResponse.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/MetadataResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class MetadataResponse extends AutoSafeParcelable {\n    public static Creator<MetadataResponse> CREATOR = new AutoCreator<MetadataResponse>(MetadataResponse.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/OpenContentsRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class OpenContentsRequest extends AutoSafeParcelable {\n    public static Creator<OpenContentsRequest> CREATOR = new AutoCreator<OpenContentsRequest>(OpenContentsRequest.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/OpenFileIntentSenderRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class OpenFileIntentSenderRequest extends AutoSafeParcelable {\n    public static Creator<OpenFileIntentSenderRequest> CREATOR = new AutoCreator<OpenFileIntentSenderRequest>(OpenFileIntentSenderRequest.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/RealtimeDocumentSyncRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class RealtimeDocumentSyncRequest extends AutoSafeParcelable {\n    public static Creator<RealtimeDocumentSyncRequest> CREATOR = new AutoCreator<RealtimeDocumentSyncRequest>(RealtimeDocumentSyncRequest.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/RemoveEventListenerRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class RemoveEventListenerRequest extends AutoSafeParcelable {\n    public static Creator<RemoveEventListenerRequest> CREATOR = new AutoCreator<RemoveEventListenerRequest>(RemoveEventListenerRequest.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/RemovePermissionRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class RemovePermissionRequest extends AutoSafeParcelable {\n    public static Creator<RemovePermissionRequest> CREATOR = new AutoCreator<RemovePermissionRequest>(RemovePermissionRequest.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/ResourceIdSetResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class ResourceIdSetResponse extends AutoSafeParcelable {\n    public static Creator<ResourceIdSetResponse> CREATOR = new AutoCreator<ResourceIdSetResponse>(ResourceIdSetResponse.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/SetDrivePreferencesRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class SetDrivePreferencesRequest extends AutoSafeParcelable {\n    public static Creator<SetDrivePreferencesRequest> CREATOR = new AutoCreator<SetDrivePreferencesRequest>(SetDrivePreferencesRequest.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/SetFileUploadPreferencesRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class SetFileUploadPreferencesRequest extends AutoSafeParcelable {\n    public static Creator<SetFileUploadPreferencesRequest> CREATOR = new AutoCreator<SetFileUploadPreferencesRequest>(SetFileUploadPreferencesRequest.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/SetResourceParentsRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class SetResourceParentsRequest extends AutoSafeParcelable {\n    public static Creator<SetResourceParentsRequest> CREATOR = new AutoCreator<SetResourceParentsRequest>(SetResourceParentsRequest.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/StartStreamSession.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class StartStreamSession extends AutoSafeParcelable {\n    public static Creator<StartStreamSession> CREATOR = new AutoCreator<StartStreamSession>(StartStreamSession.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/StreamContentsRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class StreamContentsRequest extends AutoSafeParcelable {\n    public static Creator<StreamContentsRequest> CREATOR = new AutoCreator<StreamContentsRequest>(StreamContentsRequest.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/StringListResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class StringListResponse extends AutoSafeParcelable {\n    public static Creator<StringListResponse> CREATOR = new AutoCreator<StringListResponse>(StringListResponse.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/SyncMoreResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class SyncMoreResponse extends AutoSafeParcelable {\n    public static Creator<SyncMoreResponse> CREATOR = new AutoCreator<SyncMoreResponse>(SyncMoreResponse.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/TrashResourceRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class TrashResourceRequest extends AutoSafeParcelable {\n    public static Creator<TrashResourceRequest> CREATOR = new AutoCreator<TrashResourceRequest>(TrashResourceRequest.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/UnsubscribeResourceRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class UnsubscribeResourceRequest extends AutoSafeParcelable {\n    public static Creator<UnsubscribeResourceRequest> CREATOR = new AutoCreator<UnsubscribeResourceRequest>(UnsubscribeResourceRequest.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/UntrashResourceRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class UntrashResourceRequest extends AutoSafeParcelable {\n    public static Creator<UntrashResourceRequest> CREATOR = new AutoCreator<UntrashResourceRequest>(UntrashResourceRequest.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/UpdateMetadataRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class UpdateMetadataRequest extends AutoSafeParcelable {\n    public static Creator<UpdateMetadataRequest> CREATOR = new AutoCreator<UpdateMetadataRequest>(UpdateMetadataRequest.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/internal/UpdatePermissionRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class UpdatePermissionRequest extends AutoSafeParcelable {\n    public static Creator<UpdatePermissionRequest> CREATOR = new AutoCreator<UpdatePermissionRequest>(UpdatePermissionRequest.class);\n}\n"
  },
  {
    "path": "play-services-drive/src/main/java/com/google/android/gms/drive/metadata/internal/MetadataBundle.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.drive.metadata.internal;\n\npublic class MetadataBundle {\n}\n"
  },
  {
    "path": "play-services-droidguard/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply plugin: 'kotlin-android'\napply plugin: 'signing'\n\nandroid {\n    namespace \"org.microg.gms.droidguard\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    sourceSets {\n        main.java.srcDirs += 'src/main/kotlin'\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n\n    kotlinOptions {\n        jvmTarget = 1.8\n    }\n}\n\napply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG implementation of play-services-droidguard'\n\ndependencies {\n    api project(':play-services-base')\n\n    implementation \"androidx.annotation:annotation:$annotationVersion\"\n}\n"
  },
  {
    "path": "play-services-droidguard/core/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'com.squareup.wire'\napply plugin: 'kotlin-android'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\ndependencies {\n    api project(':play-services-droidguard')\n\n    implementation project(':play-services-base-core')\n    implementation project(':play-services-chimera-core')\n    implementation project(':play-services-tasks-ktx')\n\n    implementation \"androidx.appcompat:appcompat:$appcompatVersion\"\n    implementation \"androidx.core:core-ktx:$coreVersion\"\n    implementation \"androidx.preference:preference-ktx:$preferenceVersion\"\n\n    implementation \"com.android.volley:volley:$volleyVersion\"\n    implementation \"com.squareup.wire:wire-runtime:$wireVersion\"\n\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion\"\n}\n\nwire {\n    kotlin {}\n}\n\nandroid {\n    namespace \"org.microg.gms.droidguard.core\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        buildConfig = true\n    }\n\n    defaultConfig {\n        versionName \"20.47.14\"\n        versionCode 204714000\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n        buildConfigField(\"String\", \"VERSION_NAME\", \"\\\"${defaultConfig.versionName}\\\"\")\n        buildConfigField(\"int\", \"VERSION_CODE\", \"${defaultConfig.versionCode}\")\n    }\n\n    sourceSets {\n        main.java.srcDirs += 'src/main/kotlin'\n    }\n\n    lintOptions {\n        disable 'MissingTranslation', 'GetLocales'\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n\n    kotlinOptions {\n        jvmTarget = 1.8\n    }\n}\n\napply from: '../../gradle/publish-android.gradle'\n\ndescription = 'microG service implementation for play-services-droidguard'\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2021, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n\n    <application>\n        <service\n            android:name=\".DroidGuardService\"\n            android:enabled=\"true\"\n            android:exported=\"true\"\n            android:process=\"com.google.android.gms.unstable\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.droidguard.service.INIT\" />\n                <action android:name=\"com.google.android.gms.droidguard.service.PING\" />\n                <action android:name=\"com.google.android.gms.droidguard.service.START\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </service>\n    </application>\n\n</manifest>\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/java/com/google/android/gms/droidguard/DroidGuardChimeraService.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.droidguard;\n\nimport android.content.Intent;\nimport android.os.Handler;\nimport android.os.IBinder;\nimport android.util.Base64;\nimport android.util.Log;\n\nimport androidx.annotation.Nullable;\n\nimport com.google.android.gms.framework.tracing.wrapper.TracingIntentService;\n\nimport org.microg.gms.droidguard.core.DroidGuardPreferences;\nimport org.microg.gms.droidguard.core.DroidGuardServiceBroker;\nimport org.microg.gms.droidguard.GuardCallback;\nimport org.microg.gms.droidguard.core.NetworkHandleProxyFactory;\nimport org.microg.gms.droidguard.PingData;\nimport org.microg.gms.droidguard.Request;\nimport org.microg.gms.droidguard.core.HardwareAttestationBlockingProvider;\nimport org.microg.gms.droidguard.core.SerialUnflaky;\n\nimport java.util.Collections;\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\n\npublic class DroidGuardChimeraService extends TracingIntentService {\n    public static final Object a = new Object();\n    // factory\n    public NetworkHandleProxyFactory b;\n    // widevine\n    public Object c;\n    // executor\n    public Executor d;\n    // log\n    public Object e;\n\n    private static final Object f = new Object();\n\n    // ping\n    private Object g;\n    // handler\n    private Handler h;\n\n\n    public DroidGuardChimeraService() {\n        super(\"DG\");\n        setIntentRedelivery(true);\n    }\n\n    public DroidGuardChimeraService(NetworkHandleProxyFactory factory, Object ping, Object database) {\n        super(\"DG\");\n        setIntentRedelivery(true);\n        this.b = factory;\n        this.g = ping;\n        this.h = new Handler();\n    }\n\n    // fsc\n    private final void c(byte[] data) {\n        PingData ping = null;\n        if (data != null) {\n            Log.d(\"GmsGuardChimera\", \"c(\" + Base64.encodeToString(data, Base64.NO_WRAP) + \")\", new RuntimeException().fillInStackTrace());\n            try {\n                ping = PingData.ADAPTER.decode(data);\n            } catch (Exception e) {\n                Log.w(\"GmsGuardChimera\", e);\n            }\n        } else {\n            Log.d(\"GmsGuardChimera\", \"c(null)\", new RuntimeException().fillInStackTrace());\n        }\n        try {\n            byte[] bytes = b.createPingHandle(getPackageName(), \"full\", b(\"\"), ping).run(Collections.emptyMap());\n            Log.d(\"GmsGuardChimera\", \"c.bytes = \" + Base64.encodeToString(bytes, Base64.NO_WRAP));\n            Request fastRequest = b.createRequest(\"fast\", getPackageName(), null, bytes);\n            b.fetchFromServer(\"fast\", fastRequest);\n        } catch (Exception e) {\n            Log.w(\"GmsGuardChimera\", e);\n        }\n    }\n\n    // handle intent\n    public final void a(@Nullable Intent intent) {\n        Log.d(\"GmsGuardChimera\", \"a(\" + intent + \")\");\n        if (intent != null && intent.getAction() != null && intent.getAction().equals(\"com.google.android.gms.droidguard.service.PING\")) {\n            byte[] byteData = intent.getByteArrayExtra(\"data\");\n            if (byteData == null) {\n                int[] intData = intent.getIntArrayExtra(\"data\");\n                if (intData == null) {\n                    c(null);\n                    return;\n                }\n                byteData = new byte[intData.length];\n                for (int i = 0; i < intData.length; i++) {\n                    byteData[i] = (byte) intData[i];\n                }\n            }\n            c(byteData);\n        }\n    }\n\n    // getCallback\n    public final GuardCallback b(String packageName) {\n        Log.d(\"GmsGuardChimera\", \"b[getCallback](\" + packageName + \")\");\n        return new GuardCallback(this, packageName);\n    }\n\n    @Nullable\n    @Override\n    public final IBinder onBind(Intent intent) {\n        if (intent != null && intent.getAction() != null && intent.getAction().equals(\"com.google.android.gms.droidguard.service.START\")) {\n            HardwareAttestationBlockingProvider.ensureEnabled(DroidGuardPreferences.isHardwareAttestationBlocked(this));\n            SerialUnflaky.INSTANCE.fetch();\n            return new DroidGuardServiceBroker(this);\n        }\n        return null;\n    }\n\n    @Override\n    public void onCreate() {\n        this.e = new Object();\n        this.b = new NetworkHandleProxyFactory(this);\n        this.g = new Object();\n        this.h = new Handler();\n        this.c = new Object();\n        this.d = new ThreadPoolExecutor(1, 1, 0, TimeUnit.NANOSECONDS, new LinkedBlockingQueue<>(1), new ThreadPoolExecutor.DiscardPolicy());\n        HardwareAttestationBlockingProvider.ensureEnabled(DroidGuardPreferences.isHardwareAttestationBlocked(this));\n        SerialUnflaky.INSTANCE.fetch();\n        super.onCreate();\n    }\n\n    @Override\n    public void onDestroy() {\n        super.onDestroy();\n        this.e = null;\n        this.b = null;\n        this.g = null;\n        this.h = null;\n        this.c = null;\n        this.d = null;\n    }\n}\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/java/com/google/android/gms/framework/tracing/wrapper/TracingIntentService.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.framework.tracing.wrapper;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.google.android.chimera.IntentService;\n\nimport org.microg.gms.utils.PackageManagerWrapper;\nimport org.microg.gms.droidguard.core.VersionUtil;\n\npublic abstract class TracingIntentService extends IntentService {\n    private static final String TAG = \"TracingIntentService\";\n\n    public TracingIntentService(String name) {\n        super(name);\n    }\n\n    @Override\n    public void attachBaseContext(Context newBase) {\n        super.attachBaseContext(newBase);\n    }\n\n    protected abstract void a(@Nullable Intent intent);\n\n    @Override\n    public PackageManager getPackageManager() {\n        return new PackageManagerWrapper(super.getPackageManager()) {\n            @NonNull\n            @Override\n            public PackageInfo getPackageInfo(@NonNull String packageName, int flags) {\n                PackageInfo packageInfo = super.getPackageInfo(packageName, flags);\n                if (\"com.google.android.gms\".equals(packageName)) {\n                    VersionUtil versionUtil = new VersionUtil(TracingIntentService.this);\n                    packageInfo.versionCode = versionUtil.getVersionCode();\n                    packageInfo.versionName = versionUtil.getVersionString();\n                    packageInfo.sharedUserId = \"com.google.uid.shared\";\n                }\n                return packageInfo;\n            }\n        };\n    }\n\n    @Override\n    public void onHandleIntent(@Nullable Intent intent) {\n        this.a(intent);\n    }\n}\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/java/org/microg/gms/droidguard/GuardCallback.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.droidguard;\n\nimport android.content.Context;\nimport android.media.MediaDrm;\nimport android.util.Log;\n\nimport org.microg.gms.droidguard.core.FallbackCreator;\nimport org.microg.gms.settings.SettingsContract;\n\nimport java.util.HashMap;\n\nimport static android.os.Build.VERSION.SDK_INT;\n\n/**\n * Callbacks invoked from the DroidGuard VM\n * <p>\n * We keep this file in Java to ensure ABI compatibility.\n * Methods are invoked by name from within the VM and thus must keep current name.\n */\npublic class GuardCallback {\n    private static final String TAG = \"GmsGuardCallback\";\n    private final Context context;\n    private final String packageName;\n\n    public GuardCallback(Context context, String packageName) {\n        this.context = context;\n        this.packageName = packageName;\n    }\n\n    public final String a(final byte[] array) {\n        Log.d(TAG, \"a[?](\" + array + \")\");\n        return new String(FallbackCreator.create(new HashMap<>(), array, \"\", context, null));\n    }\n\n    // getAndroidId\n    public final String b() {\n        try {\n            long androidId = SettingsContract.INSTANCE.getSettings(context, SettingsContract.CheckIn.INSTANCE.getContentUri(context), new String[]{SettingsContract.CheckIn.ANDROID_ID}, cursor -> cursor.getLong(0));\n            Log.d(TAG, \"b[getAndroidId]() = \" + androidId);\n            return String.valueOf(androidId);\n        } catch (Throwable e) {\n            Log.w(TAG, \"Failed to get Android ID, fallback to random\", e);\n        }\n        long androidId = (long) (Math.random() * Long.MAX_VALUE);\n        Log.d(TAG, \"b[getAndroidId]() = \" + androidId + \" (random)\");\n        return String.valueOf(androidId);\n    }\n\n    // getPackageName\n    public final String c() {\n        Log.d(TAG, \"c[getPackageName]() = \" + packageName);\n        return packageName;\n    }\n\n    // closeMediaDrmSession\n    public final void d(final Object mediaDrm, final byte[] sessionId) {\n        Log.d(TAG, \"d[closeMediaDrmSession](\" + mediaDrm + \", \" + sessionId + \")\");\n        synchronized (MediaDrmLock.LOCK) {\n            if (SDK_INT >= 18) {\n                ((MediaDrm) mediaDrm).closeSession(sessionId);\n            }\n        }\n    }\n\n    public final void e(final int task) {\n        Log.d(TAG, \"e[?](\" + task + \")\");\n        // TODO: Open database\n        if (task == 1) {\n            // TODO\n        } else if (task == 0) {\n            // TODO\n        }\n        // TODO: Set value in database\n    }\n}\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/java/org/microg/gms/droidguard/MediaDrmLock.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.droidguard;\n\npublic class MediaDrmLock {\n    public static final Object LOCK = new Object();\n}\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/kotlin/org/microg/gms/droidguard/core/DgDatabaseHelper.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.droidguard.core\n\nimport android.content.ContentValues\nimport android.content.Context\nimport android.database.sqlite.SQLiteDatabase\nimport android.database.sqlite.SQLiteOpenHelper\n\n/**\n * - a: id\n * - b: timestamp\n * - c: seconds until expiry\n * - d: vm key\n * - e: ?\n * - f: byte code\n * - g: extra\n */\nclass DgDatabaseHelper(context: Context) : SQLiteOpenHelper(context, \"dg.db\", null, 2) {\n    override fun onCreate(db: SQLiteDatabase) {\n        // Note: \"NON NULL\" is actually not a valid sqlite constraint, but this is what we see in the original database 🤷\n        db.execSQL(\"CREATE TABLE main (a TEXT NOT NULL, b LONG NOT NULL, c LONG NOT NULL, d TEXT NON NULL, e TEXT NON NULL,f BLOB NOT NULL,g BLOB NOT NULL);\");\n    }\n\n    override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {\n        db.execSQL(\"DROP TABLE IF EXISTS main;\");\n        this.onCreate(db);\n    }\n\n    /**\n     * @return vm key, byte code, extra\n     */\n    fun get(id: String): Triple<String, ByteArray, ByteArray>? = readableDatabase.use { db ->\n        val time = System.currentTimeMillis() / 1000\n        val it = db.query(\"main\", arrayOf(\"f\", \"d\", \"e\", \"c\", \"g\"), \"a = ? AND b <= $time AND $time < (b + c)\", arrayOf(id), null, null, \"b DESC\", \"1\")\n        try {\n            if (it.moveToNext()) {\n                Triple(it.getString(1), it.getBlob(0), it.getBlob(4))\n            } else {\n                null\n            }\n        } finally {\n            it.close()\n        }\n    }\n\n    fun put(id: String, expiry: Long, vmKey: String, byteCode: ByteArray, extra: ByteArray) {\n        val dbData = ContentValues().apply {\n            put(\"a\", id)\n            put(\"b\", System.currentTimeMillis() / 1000)\n            put(\"c\", expiry)\n            put(\"d\", vmKey)\n            put(\"e\", \"\")\n            put(\"f\", byteCode)\n            put(\"g\", extra)\n        }\n        writableDatabase.use {\n            it.beginTransaction()\n            if (expiry <= 0) {\n                it.delete(\"main\", \"a = ?\", arrayOf(id))\n            } else if (it.update(\"main\", dbData, \"a = ?\", arrayOf(id)) <= 0) {\n                it.insert(\"main\", null, dbData)\n            }\n            it.setTransactionSuccessful()\n            it.endTransaction()\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/kotlin/org/microg/gms/droidguard/core/DgpDatabaseHelper.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.droidguard.core\n\nimport android.content.Context\nimport android.database.sqlite.SQLiteDatabase\nimport android.database.sqlite.SQLiteOpenHelper\n\nclass DgpDatabaseHelper(context: Context) : SQLiteOpenHelper(context, \"dgp.db\", null, 1) {\n    override fun onCreate(db: SQLiteDatabase) {\n        db.execSQL(\"CREATE TABLE t (a BLOB NOT NULL);\");\n    }\n\n    override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {\n    }\n}\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/kotlin/org/microg/gms/droidguard/core/DroidGuardHandleImpl.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2021 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.droidguard.core\n\nimport android.annotation.SuppressLint\nimport android.content.Context\nimport android.os.ConditionVariable\nimport android.os.ParcelFileDescriptor\nimport android.os.Parcelable\nimport android.util.Log\nimport com.google.android.gms.droidguard.internal.DroidGuardInitReply\nimport com.google.android.gms.droidguard.internal.DroidGuardResultsRequest\nimport com.google.android.gms.droidguard.internal.IDroidGuardHandle\nimport org.microg.gms.droidguard.BytesException\nimport org.microg.gms.droidguard.GuardCallback\nimport org.microg.gms.droidguard.HandleProxy\nimport java.io.FileNotFoundException\n\nclass DroidGuardHandleImpl(private val context: Context, private val packageName: String, private val factory: NetworkHandleProxyFactory, private val callback: GuardCallback) : IDroidGuardHandle.Stub() {\n    private val condition = ConditionVariable()\n\n    private var flow: String? = null\n    private var handleProxy: HandleProxy? = null\n    private var handleInitError: Throwable? = null\n\n    override fun init(flow: String?) {\n        Log.d(TAG, \"init($flow)\")\n        initWithRequest(flow, null)\n    }\n\n    @SuppressLint(\"SetWorldReadable\")\n    override fun initWithRequest(flow: String?, request: DroidGuardResultsRequest?): DroidGuardInitReply {\n        Log.d(TAG, \"initWithRequest($flow, $request)\")\n        this.flow = flow\n        var handleProxy: HandleProxy? = null\n        try {\n            if (!LOW_LATENCY_ENABLED || flow in NOT_LOW_LATENCY_FLOWS) {\n                handleProxy = null\n            } else {\n                try {\n                    handleProxy = factory.createLowLatencyHandle(flow, callback, request)\n                    Log.d(TAG, \"Using low-latency handle\")\n                } catch (e: Exception) {\n                    Log.w(TAG, e)\n                    handleProxy = null\n                }\n            }\n            if (handleProxy == null) {\n                handleProxy = factory.createHandle(packageName, flow, callback, request)\n            }\n            if (handleProxy.init()) {\n                this.handleProxy = handleProxy\n            } else {\n                throw Exception(\"init failed\")\n            }\n        } catch (e: Exception) {\n            Log.w(TAG, \"Error during handle init\", e)\n            this.handleInitError = e\n        }\n        this.condition.open()\n        if (handleInitError == null) {\n            try {\n                val `object` = handleProxy!!.handle.javaClass.getDeclaredMethod(\"rb\").invoke(handleProxy.handle) as? Parcelable?\n                if (`object` != null) {\n                    val vmKey = handleProxy.vmKey\n                    val theApk = factory.getTheApkFile(vmKey)\n                    try {\n                        theApk.setReadable(true, false)\n                        return DroidGuardInitReply(ParcelFileDescriptor.open(theApk, ParcelFileDescriptor.MODE_READ_ONLY), `object`)\n                    } catch (e: FileNotFoundException) {\n                        throw Exception(\"Files for VM $vmKey not found on disk\")\n                    }\n                }\n            } catch (e: Exception) {\n                this.handleProxy = null\n                handleInitError = e\n            }\n        }\n        return DroidGuardInitReply(null, null)\n    }\n\n    override fun snapshot(map: MutableMap<Any?, Any?>): ByteArray {\n        Log.d(TAG, \"snapshot($map)\")\n        condition.block()\n        handleInitError?.let { return FallbackCreator.create(flow, context, map, it) }\n        val handleProxy = this.handleProxy ?: return FallbackCreator.create(flow, context, map, IllegalStateException())\n        return try {\n            handleProxy.handle::class.java.getDeclaredMethod(\"ss\", Map::class.java).invoke(handleProxy.handle, map) as ByteArray\n        } catch (e: Exception) {\n            try {\n                throw BytesException(handleProxy.extra, e)\n            } catch (e2: Exception) {\n                FallbackCreator.create(flow, context, map, e2)\n            }\n        }\n    }\n\n    override fun close() {\n        Log.d(TAG, \"close()\")\n        condition.block()\n        try {\n            handleProxy?.close()\n        } catch (e: Exception) {\n            Log.w(TAG, \"Error during handle close\", e)\n        }\n        handleProxy = null\n        handleInitError = null\n    }\n\n    companion object {\n        private const val TAG = \"GmsGuardHandleImpl\"\n        private val LOW_LATENCY_ENABLED = false\n        private val NOT_LOW_LATENCY_FLOWS = setOf(\"ad_attest\", \"attest\", \"checkin\", \"federatedMachineLearningReduced\", \"msa-f\", \"ad-event-attest-token\")\n    }\n}\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/kotlin/org/microg/gms/droidguard/core/DroidGuardPreferences.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2021 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.droidguard.core\n\nimport android.content.ContentValues\nimport android.content.Context\nimport android.database.Cursor\nimport androidx.core.database.getStringOrNull\nimport org.microg.gms.settings.SettingsContract\nimport org.microg.gms.settings.SettingsContract.DroidGuard.ENABLED\nimport org.microg.gms.settings.SettingsContract.DroidGuard.FORCE_LOCAL_DISABLED\nimport org.microg.gms.settings.SettingsContract.DroidGuard.HARDWARE_ATTESTATION_BLOCKED\nimport org.microg.gms.settings.SettingsContract.DroidGuard.MODE\nimport org.microg.gms.settings.SettingsContract.DroidGuard.NETWORK_SERVER_URL\n\nobject DroidGuardPreferences {\n\n    private fun <T> getSettings(context: Context, projection: String, def: T, f: (Cursor) -> T): T {\n        return try {\n            SettingsContract.getSettings(context, SettingsContract.DroidGuard.getContentUri(context), arrayOf(projection), f)\n        } catch (e: Exception) {\n            def\n        }\n    }\n\n    private fun setSettings(context: Context, f: ContentValues.() -> Unit) =\n            SettingsContract.setSettings(context, SettingsContract.DroidGuard.getContentUri(context), f)\n\n    @JvmStatic\n    fun isForcedLocalDisabled(context: Context): Boolean = getSettings(context, FORCE_LOCAL_DISABLED, false) { it.getInt(0) != 0 }\n\n    @JvmStatic\n    fun isEnabled(context: Context): Boolean = getSettings(context, ENABLED, false) { it.getInt(0) != 0 }\n\n    @JvmStatic\n    fun isAvailable(context: Context): Boolean = isEnabled(context) && (!isForcedLocalDisabled(context) || getMode(context) != Mode.Embedded)\n\n    @JvmStatic\n    fun isLocalAvailable(context: Context): Boolean = isEnabled(context) && !isForcedLocalDisabled(context) && getMode(context) == Mode.Embedded\n\n    @JvmStatic\n    fun setEnabled(context: Context, enabled: Boolean) = setSettings(context) { put(ENABLED, enabled) }\n\n    @JvmStatic\n    fun getMode(context: Context): Mode = getSettings(context, MODE, Mode.Embedded) { c -> Mode.valueOf(c.getString(0)) }\n\n    @JvmStatic\n    fun setMode(context: Context, mode: Mode) = setSettings(context) { put(MODE, mode.toString()) }\n\n    @JvmStatic\n    fun getNetworkServerUrl(context: Context): String? = getSettings(context, NETWORK_SERVER_URL, null) { c -> c.getStringOrNull(0) }\n\n    @JvmStatic\n    fun setNetworkServerUrl(context: Context, url: String?) = setSettings(context) { put(NETWORK_SERVER_URL, url) }\n\n    @JvmStatic\n    fun isHardwareAttestationBlocked(context: Context) = getSettings(context, HARDWARE_ATTESTATION_BLOCKED, false) { it.getInt(0) != 0 }\n\n    @JvmStatic\n    fun setHardwareAttestationBlocked(context: Context, value: Boolean) = setSettings(context) { put(HARDWARE_ATTESTATION_BLOCKED, value) }\n\n    enum class Mode {\n        Embedded,\n        Network\n    }\n}\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/kotlin/org/microg/gms/droidguard/core/DroidGuardService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage org.microg.gms.droidguard.core\n\nimport com.google.android.gms.droidguard.DroidGuardChimeraService\nimport org.microg.gms.chimera.ServiceLoader\nimport org.microg.gms.chimera.ServiceProxy\n\nclass DroidGuardService : ServiceProxy(ServiceLoader.static<DroidGuardChimeraService>())\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/kotlin/org/microg/gms/droidguard/core/DroidGuardServiceBroker.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2021 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.droidguard.core\n\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport com.google.android.gms.droidguard.DroidGuardChimeraService\nimport org.microg.gms.AbstractGmsServiceBroker\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.common.PackageUtils\nimport java.util.*\n\nclass DroidGuardServiceBroker(val service: DroidGuardChimeraService) : AbstractGmsServiceBroker(EnumSet.of(GmsService.DROID_GUARD)) {\n\n    override fun getService(callback: IGmsCallbacks?, request: GetServiceRequest?) {\n        handleServiceRequest(callback, request, null)\n    }\n\n    override fun handleServiceRequest(callback: IGmsCallbacks?, request: GetServiceRequest?, service: GmsService?) {\n        val packageName = PackageUtils.getAndCheckCallingPackageOrImpersonation(this.service, request!!.packageName)\n        callback!!.onPostInitComplete(0, DroidGuardServiceImpl(this.service, packageName!!), null)\n    }\n}\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/kotlin/org/microg/gms/droidguard/core/DroidGuardServiceImpl.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2021 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.droidguard.core\n\nimport android.util.Log\nimport com.google.android.gms.droidguard.DroidGuardChimeraService\nimport com.google.android.gms.droidguard.internal.DroidGuardResultsRequest\nimport com.google.android.gms.droidguard.internal.IDroidGuardCallbacks\nimport com.google.android.gms.droidguard.internal.IDroidGuardHandle\nimport com.google.android.gms.droidguard.internal.IDroidGuardService\n\nclass DroidGuardServiceImpl(private val service: DroidGuardChimeraService, private val packageName: String) : IDroidGuardService.Stub() {\n    override fun guard(callbacks: IDroidGuardCallbacks?, flow: String?, map: MutableMap<Any?, Any?>?) {\n        Log.d(TAG, \"guard()\")\n        guardWithRequest(callbacks, flow, map, null)\n    }\n\n    override fun guardWithRequest(callbacks: IDroidGuardCallbacks?, flow: String?, map: MutableMap<Any?, Any?>?, request: DroidGuardResultsRequest?) {\n        Log.d(TAG, \"guardWithRequest()\")\n        TODO(\"Not yet implemented\")\n    }\n\n    override fun getHandle(): IDroidGuardHandle {\n        Log.d(TAG, \"getHandle()\")\n        return when (DroidGuardPreferences.getMode(service)) {\n            DroidGuardPreferences.Mode.Embedded -> DroidGuardHandleImpl(service, packageName, service.b, service.b(packageName))\n            DroidGuardPreferences.Mode.Network -> RemoteHandleImpl(service, packageName)\n        }\n    }\n\n    override fun getClientTimeoutMillis(): Int {\n        Log.d(TAG, \"getClientTimeoutMillis()\")\n        return 60000\n    }\n\n    companion object {\n        const val TAG = \"GmsGuardServiceImpl\"\n    }\n}\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/kotlin/org/microg/gms/droidguard/core/FallbackCreator.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2021 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.droidguard.core\n\nimport android.content.Context\nimport android.util.Log\n\nobject FallbackCreator {\n    private val FAST_FAIL = setOf(\"ad_attest\", \"recaptcha-frame\", \"federatedMachineLearningReduced\", \"msa-f\", \"ad-event-attest-token\")\n\n    @JvmStatic\n    fun create(flow: String?, context: Context, map: Map<Any?, Any?>, e: Throwable): ByteArray {\n        Log.w(\"DGFallback\", \"create($flow)\")\n        return if (flow in FAST_FAIL) {\n            \"ERROR : no fallback for $flow\".encodeToByteArray()\n        } else {\n            try {\n                create(map, null, flow, context, e)\n            } catch (e: Throwable) {\n                Log.w(\"DGFallback\", e)\n                \"ERROR : $e\".encodeToByteArray()\n            }\n        }\n    }\n\n    @JvmStatic\n    fun create(map: Map<Any?, Any?>, bytes: ByteArray?, flow: String?, context: Context, e: Throwable): ByteArray {\n        TODO(\"Not yet implemented\")\n    }\n}\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/kotlin/org/microg/gms/droidguard/core/HardwareAttestationBlockingProvider.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: This is heavily inspired by \"Universal SafetyNet Fix\", used under the terms of MIT License,\n *         Copyright (c) 2021 Danny Lin <danny@kdrag0n.dev>\n */\n\npackage org.microg.gms.droidguard.core\n\nimport android.util.Log\nimport androidx.annotation.Keep\nimport java.io.InputStream\nimport java.io.OutputStream\nimport java.security.*\nimport java.security.cert.Certificate\nimport java.util.*\n\nprivate const val TAG = \"DroidGuard\"\n\nclass HardwareAttestationBlockingProvider(\n    realProvider: Provider,\n    realSpi: KeyStoreSpi\n) : Provider(realProvider.name, realProvider.version, realProvider.info) {\n    init {\n        HardwareAttestationBlockingKeyStore.realSpi = realSpi\n        this[\"KeyStore.$PROVIDER_NAME\"] = HardwareAttestationBlockingKeyStore::class.java.name\n    }\n\n    companion object {\n        private var currentlyEnabled = false\n        private lateinit var originalProvider: Provider\n        private const val PROVIDER_NAME = \"AndroidKeyStore\"\n        private const val FIELD_KEY_STORE_SPI = \"keyStoreSpi\"\n\n        @JvmStatic\n        fun ensureEnabled(enabled: Boolean = true) {\n            if (currentlyEnabled == enabled) return\n            try {\n                if (enabled) {\n                    Log.d(TAG, \"Hardware attestation blocking enabled\")\n                    originalProvider = Security.getProvider(PROVIDER_NAME)\n                    val realKeystore = KeyStore.getInstance(PROVIDER_NAME)\n                    val realSpi = realKeystore.get<KeyStoreSpi>(FIELD_KEY_STORE_SPI)\n\n                    val newProvider = HardwareAttestationBlockingProvider(originalProvider, realSpi)\n                    Security.removeProvider(PROVIDER_NAME)\n                    Security.insertProviderAt(newProvider, 1)\n                    currentlyEnabled = true\n                } else {\n                    Log.d(TAG, \"Hardware attestation blocking disabled\")\n                    Security.removeProvider(PROVIDER_NAME)\n                    Security.insertProviderAt(originalProvider, 1)\n                    currentlyEnabled = false\n                }\n            } catch (e: Exception) {\n                Log.w(TAG, \"Failed replacing the security provider\", e)\n            }\n        }\n    }\n}\n\nclass HardwareAttestationBlockingKeyStore(private val realSpi: KeyStoreSpi) : KeyStoreSpi() {\n    @Keep\n    constructor() : this(Companion.realSpi ?: throw IllegalStateException())\n\n    override fun engineGetCertificateChain(alias: String?): Array<Certificate>? {\n        for (stackTraceElement in Thread.currentThread().getStackTrace()) {\n            if (stackTraceElement.className.lowercase().contains(\"droidguard\")) {\n                Log.d(TAG, \"Block DroidGuard from accessing engineGetCertificateChain\")\n                throw UnsupportedOperationException()\n            }\n        }\n        return realSpi.engineGetCertificateChain(alias)\n    }\n\n    override fun engineGetKey(alias: String?, password: CharArray?): Key? = realSpi.engineGetKey(alias, password)\n    override fun engineGetCertificate(alias: String?): Certificate? = realSpi.engineGetCertificate(alias)\n    override fun engineGetCreationDate(alias: String?): Date? = realSpi.engineGetCreationDate(alias)\n    override fun engineSetKeyEntry(alias: String?, key: Key?, password: CharArray?, chain: Array<out Certificate>?) = realSpi.engineSetKeyEntry(alias, key, password, chain)\n    override fun engineSetKeyEntry(alias: String?, key: ByteArray?, chain: Array<out Certificate>?) = realSpi.engineSetKeyEntry(alias, key, chain)\n    override fun engineSetCertificateEntry(alias: String?, cert: Certificate?) = realSpi.engineSetCertificateEntry(alias, cert)\n    override fun engineDeleteEntry(alias: String?) = realSpi.engineDeleteEntry(alias)\n    override fun engineAliases(): Enumeration<String>? = realSpi.engineAliases()\n    override fun engineContainsAlias(alias: String?) = realSpi.engineContainsAlias(alias)\n    override fun engineSize() = realSpi.engineSize()\n    override fun engineIsKeyEntry(alias: String?) = realSpi.engineIsKeyEntry(alias)\n    override fun engineIsCertificateEntry(alias: String?) = realSpi.engineIsCertificateEntry(alias)\n    override fun engineGetCertificateAlias(cert: Certificate?): String? = realSpi.engineGetCertificateAlias(cert)\n    override fun engineStore(stream: OutputStream?, password: CharArray?) = realSpi.engineStore(stream, password)\n    override fun engineLoad(stream: InputStream?, password: CharArray?) = realSpi.engineLoad(stream, password)\n\n    companion object {\n        var realSpi: KeyStoreSpi? = null\n    }\n}\n\nprivate fun <T> Any.get(name: String) = this::class.java.getDeclaredField(name).let { field ->\n    field.isAccessible = true\n    @Suppress(\"unchecked_cast\")\n    field.get(this) as T\n}\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/kotlin/org/microg/gms/droidguard/core/NetworkHandleProxyFactory.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2021 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.droidguard.core\n\nimport android.content.Context\nimport com.android.volley.NetworkResponse\nimport com.android.volley.VolleyError\nimport com.android.volley.toolbox.RequestFuture\nimport com.android.volley.toolbox.Volley\nimport com.google.android.gms.droidguard.internal.DroidGuardResultsRequest\nimport okio.ByteString.Companion.decodeHex\nimport okio.ByteString.Companion.of\nimport org.microg.gms.droidguard.*\nimport org.microg.gms.profile.Build\nimport org.microg.gms.profile.ProfileManager\nimport org.microg.gms.utils.singleInstanceOf\nimport java.io.File\nimport java.util.*\nimport com.android.volley.Request as VolleyRequest\nimport com.android.volley.Response as VolleyResponse\n\nclass NetworkHandleProxyFactory(private val context: Context) : HandleProxyFactory(context) {\n    private val dgDb: DgDatabaseHelper = DgDatabaseHelper(context)\n    private val version = VersionUtil(context)\n    private val queue = singleInstanceOf { Volley.newRequestQueue(context.applicationContext) }\n\n    fun createHandle(packageName: String, flow: String?, callback: GuardCallback, request: DroidGuardResultsRequest?): HandleProxy {\n        if (!DroidGuardPreferences.isLocalAvailable(context)) throw IllegalAccessException(\"DroidGuard should not be available locally\")\n        val (vmKey, byteCode, bytes) = readFromDatabase(flow) ?: fetchFromServer(flow, packageName)\n        return createHandleProxy(flow, vmKey, byteCode, bytes, callback, request)\n    }\n\n    fun createPingHandle(packageName: String, flow: String, callback: GuardCallback, pingData: PingData?): HandleProxy {\n        if (!DroidGuardPreferences.isLocalAvailable(context)) throw IllegalAccessException(\"DroidGuard should not be available locally\")\n        val (vmKey, byteCode, bytes) = fetchFromServer(flow, createRequest(flow, packageName, pingData))\n        return createHandleProxy(flow, vmKey, byteCode, bytes, callback, DroidGuardResultsRequest().also { it.clientVersion = 0 })\n    }\n\n    fun createLowLatencyHandle(flow: String?, callback: GuardCallback, request: DroidGuardResultsRequest?): HandleProxy {\n        if (!DroidGuardPreferences.isLocalAvailable(context)) throw IllegalAccessException(\"DroidGuard should not be available locally\")\n        val (vmKey, byteCode, bytes) = readFromDatabase(\"fast\") ?: throw Exception(\"low latency (fast) flow not available\")\n        return createHandleProxy(flow, vmKey, byteCode, bytes, callback, request)\n    }\n\n    fun SignedResponse.unpack(): Response {\n        if (SignatureVerifier.verifySignature(data_!!.toByteArray(), signature!!.toByteArray())) {\n            return Response.ADAPTER.decode(data_!!)\n        } else {\n            throw SecurityException(\"Signature invalid\")\n        }\n    }\n\n    private fun readFromDatabase(flow: String?): Triple<String, ByteArray, ByteArray>? {\n        ProfileManager.ensureInitialized(context)\n        val id = \"$flow/${version.versionString}/${Build.FINGERPRINT}\"\n        return dgDb.get(id)\n    }\n\n    fun createRequest(flow: String?, packageName: String, pingData: PingData? = null, extra: ByteArray? = null): Request {\n        ProfileManager.ensureInitialized(context)\n        return Request(\n                usage = Usage(flow, packageName),\n                info = listOf(\n                        KeyValuePair(\"BOARD\", Build.BOARD),\n                        KeyValuePair(\"BOOTLOADER\", Build.BOOTLOADER),\n                        KeyValuePair(\"BRAND\", Build.BRAND),\n                        KeyValuePair(\"CPU_ABI\", Build.CPU_ABI),\n                        KeyValuePair(\"CPU_ABI2\", Build.CPU_ABI2),\n                        KeyValuePair(\"SUPPORTED_ABIS\", Build.SUPPORTED_ABIS.joinToString(\",\")),\n                        KeyValuePair(\"DEVICE\", Build.DEVICE),\n                        KeyValuePair(\"DISPLAY\", Build.DISPLAY),\n                        KeyValuePair(\"FINGERPRINT\", Build.FINGERPRINT),\n                        KeyValuePair(\"HARDWARE\", Build.HARDWARE),\n                        KeyValuePair(\"HOST\", Build.HOST),\n                        KeyValuePair(\"ID\", Build.ID),\n                        KeyValuePair(\"MANUFACTURER\", Build.MANUFACTURER),\n                        KeyValuePair(\"MODEL\", Build.MODEL),\n                        KeyValuePair(\"PRODUCT\", Build.PRODUCT),\n                        KeyValuePair(\"RADIO\", Build.RADIO),\n                        KeyValuePair(\"SERIAL\", Build.SERIAL),\n                        KeyValuePair(\"TAGS\", Build.TAGS),\n                        KeyValuePair(\"TIME\", Build.TIME.toString()),\n                        KeyValuePair(\"TYPE\", Build.TYPE),\n                        KeyValuePair(\"USER\", Build.USER),\n                        KeyValuePair(\"VERSION.CODENAME\", Build.VERSION.CODENAME),\n                        KeyValuePair(\"VERSION.INCREMENTAL\", Build.VERSION.INCREMENTAL),\n                        KeyValuePair(\"VERSION.RELEASE\", Build.VERSION.RELEASE),\n                        KeyValuePair(\"VERSION.SDK\", Build.VERSION.SDK),\n                        KeyValuePair(\"VERSION.SDK_INT\", Build.VERSION.SDK_INT.toString()),\n                ),\n                versionName = version.versionString,\n                versionCode = BuildConfig.VERSION_CODE,\n                hasAccount = false,\n                isGoogleCn = false,\n                enableInlineVm = true,\n                cached = getCacheDir().list()?.map { it.decodeHex() }.orEmpty(),\n                arch = System.getProperty(\"os.arch\"),\n                ping = pingData,\n                field10 = extra?.let { of(*it) },\n        )\n    }\n\n    fun fetchFromServer(flow: String?, packageName: String): Triple<String, ByteArray, ByteArray> {\n        return fetchFromServer(flow, createRequest(flow, packageName))\n    }\n\n    fun fetchFromServer(flow: String?, request: Request): Triple<String, ByteArray, ByteArray> {\n        ProfileManager.ensureInitialized(context)\n        val future = RequestFuture.newFuture<SignedResponse>()\n        queue.add(object : VolleyRequest<SignedResponse>(Method.POST, SERVER_URL, future) {\n            override fun parseNetworkResponse(response: NetworkResponse): VolleyResponse<SignedResponse> {\n                return try {\n                    VolleyResponse.success(SignedResponse.ADAPTER.decode(response.data), null)\n                } catch (e: Exception) {\n                    VolleyResponse.error(VolleyError(e))\n                }\n            }\n\n            override fun deliverResponse(response: SignedResponse) {\n                future.onResponse(response)\n            }\n\n            override fun getBody(): ByteArray = request.encode()\n\n            override fun getBodyContentType(): String = \"application/x-protobuf\"\n\n            override fun getHeaders(): Map<String, String> {\n                return mapOf(\n                    \"User-Agent\" to \"DroidGuard/${version.versionCode}\"\n                )\n            }\n        })\n        val signed: SignedResponse = future.get()\n        val response = signed.unpack()\n        val vmKey = response.vmChecksum!!.hex()\n        if (!isValidCache(vmKey)) {\n            val temp = File(getCacheDir(), \"${UUID.randomUUID()}.apk\")\n            temp.parentFile!!.mkdirs()\n            temp.writeBytes(response.content!!.toByteArray())\n            getOptDir(vmKey).mkdirs()\n            temp.renameTo(getTheApkFile(vmKey))\n            updateCacheTimestamp(vmKey)\n            if (!isValidCache(vmKey)) {\n                getCacheDir(vmKey).deleteRecursively()\n                throw IllegalStateException()\n            }\n        }\n        val id = \"$flow/${version.versionString}/${Build.FINGERPRINT}\"\n        val expiry = (response.expiryTimeSecs ?: 0).toLong()\n        val byteCode = response.byteCode?.toByteArray() ?: ByteArray(0)\n        val extra = response.extra?.toByteArray() ?: ByteArray(0)\n        if (response.save != false) {\n            dgDb.put(id, expiry, vmKey, byteCode, extra)\n        }\n        return Triple(vmKey, byteCode, extra)\n    }\n\n    private fun createHandleProxy(\n        flow: String?,\n        vmKey: String,\n        byteCode: ByteArray,\n        extra: ByteArray,\n        callback: GuardCallback,\n        request: DroidGuardResultsRequest?\n    ): HandleProxy {\n        ProfileManager.ensureInitialized(context)\n        val clazz = loadClass(vmKey, extra)\n        return HandleProxy(clazz, context, flow, byteCode, callback, vmKey, extra, request?.bundle)\n    }\n\n    companion object {\n        const val SERVER_URL = \"https://www.googleapis.com/androidantiabuse/v1/x/create?alt=PROTO&key=AIzaSyBofcZsgLSS7BOnBjZPEkk4rYwzOIz-lTI\"\n    }\n}\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/kotlin/org/microg/gms/droidguard/core/RemoteHandleImpl.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.droidguard.core\n\nimport android.content.Context\nimport android.net.Uri\nimport android.util.Base64\nimport com.google.android.gms.droidguard.internal.DroidGuardInitReply\nimport com.google.android.gms.droidguard.internal.DroidGuardResultsRequest\nimport com.google.android.gms.droidguard.internal.IDroidGuardHandle\nimport android.util.Log\nimport java.net.HttpURLConnection\nimport java.net.URL\n\nprivate const val TAG = \"RemoteGuardImpl\"\n\nclass RemoteHandleImpl(private val context: Context, private val packageName: String) : IDroidGuardHandle.Stub() {\n    private var flow: String? = null\n    private var request: DroidGuardResultsRequest? = null\n    private val url: String\n        get() = DroidGuardPreferences.getNetworkServerUrl(context) ?: throw IllegalStateException(\"Network URL required\")\n\n    override fun init(flow: String?) {\n        Log.d(TAG, \"init($flow)\")\n        this.flow = flow\n    }\n\n    override fun snapshot(map: Map<Any?, Any?>?): ByteArray {\n        Log.d(TAG, \"snapshot($map)\")\n        val paramsMap = mutableMapOf(\"flow\" to flow, \"source\" to packageName)\n        for (key in request?.bundle?.keySet().orEmpty()) {\n            request?.bundle?.getString(key)?.let { paramsMap[\"x-request-$key\"] = it }\n        }\n        val params = paramsMap.map { Uri.encode(it.key) + \"=\" + Uri.encode(it.value) }.joinToString(\"&\")\n        val connection = URL(\"$url?$params\").openConnection() as HttpURLConnection\n        val payload = map.orEmpty().map { Uri.encode(it.key as String) + \"=\" + Uri.encode(it.value as String) }.joinToString(\"&\")\n        Log.d(TAG, \"POST ${connection.url}: $payload\")\n        connection.setRequestProperty(\"Content-Type\", \"application/x-www-form-urlencoded; charset=UTF-8\")\n        connection.requestMethod = \"POST\"\n        connection.doInput = true\n        connection.doOutput = true\n        connection.outputStream.use { it.write(payload.encodeToByteArray()) }\n        val bytes = connection.inputStream.use { it.readBytes() }.decodeToString()\n        return Base64.decode(bytes, Base64.URL_SAFE + Base64.NO_WRAP + Base64.NO_PADDING)\n    }\n\n    override fun close() {\n        Log.d(TAG, \"close()\")\n        this.request = null\n        this.flow = null\n    }\n\n    override fun initWithRequest(flow: String?, request: DroidGuardResultsRequest?): DroidGuardInitReply? {\n        Log.d(TAG, \"initWithRequest($flow, $request)\")\n        this.flow = flow\n        this.request = request\n        return null\n    }\n}"
  },
  {
    "path": "play-services-droidguard/core/src/main/kotlin/org/microg/gms/droidguard/core/SerialUnflaky.kt",
    "content": "package org.microg.gms.droidguard.core\n\nimport android.annotation.SuppressLint\nimport android.os.Build.VERSION.SDK_INT\nimport android.util.Log\n\n/**\n * DroidGuard may invoke Build.getSerial(), which will throw an exception, as, in contrast to original GMS, it doesn't\n * have the permission to do so.\n *\n * We found that on some systems, the behavior of Build.getSerial() is flaky, as it would only throw an exception on\n * the first attempt invoking it, but would return \"unknown\" afterward (which is intended for apps with\n * target SDK <= 28). DroidGuard doesn't like those flaky results, so to make them consistent, we just invoke\n * Build.getSerial() here once.\n */\nobject SerialUnflaky {\n    @SuppressLint(\"MissingPermission\")\n    fun fetch() {\n        if (SDK_INT >= 26) {\n            val res1 = runCatching { android.os.Build.getSerial() }.fold({ it }, { it.javaClass.name })\n            val res2 = runCatching { android.os.Build.getSerial() }.fold({ it }, { it.javaClass.name })\n            if (res1 != res2) {\n                Log.w(\"SerialUnflaky\", \"Build.getSerial() was flaky. res1=$res1, res2=$res2\")\n            }\n        }\n    }\n}"
  },
  {
    "path": "play-services-droidguard/core/src/main/kotlin/org/microg/gms/droidguard/core/SignatureVerifier.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2021 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.droidguard.core\n\nimport android.util.Base64\nimport android.util.Log\nimport java.security.KeyFactory\nimport java.security.Signature\nimport java.security.spec.X509EncodedKeySpec\n\nobject SignatureVerifier {\n    const val TAG = \"GmsGuardSigVerify\"\n    const val PUBLIC_KEY = \"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxW77dCKJ8mhEIfXXdeidi7/7LMNM/fzwI+wj1Ed8xIKgTYWCnekRko3JxQb4Cv/gEL5hEA8e9lFs3V67VUL6hCo1FxysXj7Q8n3Kp7hARDkbiZ0mdk8bSanqrPAXTPx6pEL2ZOzfFCHEtJdhz5Ozp2C4XTKF1SBv/YbpsqSUJwdhG7ZPGjyCMRloMww6ITpGdVQ8lChklkCek0WPbz2UrY5RC1qIJKmmcB6KNxxE776Dn6QoYbhN5jPeVBp7lDD3UxjfVzTxKKDAome6fUVBop3dpcLM6rq3+nNT2YArgqTD1qtsVM9vHlcLaAYaPg82vtIN80iDUseMlVHgK+nf6wIDAQAB\"\n\n    fun verifySignature(data: ByteArray, signature: ByteArray): Boolean {\n        try {\n            val keyFactory = KeyFactory.getInstance(\"RSA\") ?: return false\n            val sig = Signature.getInstance(\"SHA256withRSA\") ?: return false\n            val keySpec = X509EncodedKeySpec(Base64.decode(PUBLIC_KEY, 0))\n            sig.initVerify(keyFactory.generatePublic(keySpec))\n            sig.update(data)\n            return sig.verify(signature)\n        } catch (e: Exception) {\n            Log.w(TAG, e)\n            return false\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/kotlin/org/microg/gms/droidguard/core/VersionUtil.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2021 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.droidguard.core\n\nimport android.content.Context\nimport org.microg.gms.profile.Build\nimport org.microg.gms.profile.ProfileManager\n\nclass VersionUtil(private val context: Context) {\n    val buildType: String\n        get() {\n            ProfileManager.ensureInitialized(context)\n            // Note: Android TV and Watch use different version codes\n            val versionCode = when (Build.VERSION.SDK_INT) {\n                31 -> \"19\"\n                30 -> \"15\"\n                29 -> \"12\"\n                28 -> \"10\"\n                23, 24, 25, 26, 27 -> \"04\"\n                21, 22 -> \"02\"\n                else -> \"00\"\n            }\n            val architectureCode = when (Build.CPU_ABI) {\n                \"x86_64\" -> \"08\"\n                \"x86\" -> \"07\"\n                \"arm64-v8a\" -> \"04\"\n                \"arm\", \"armeabi\", \"armeabi-v7a\" -> \"03\"\n                else -> \"00\"\n            }\n            val dpiCode = when (context.resources.displayMetrics.densityDpi) { // TODO: Also something to get from profile\n                160 -> \"02\"\n                240 -> \"04\"\n                320 -> \"06\"\n                480 -> \"08\"\n                else -> \"00\"\n            }\n            val type = \"$versionCode$architectureCode$dpiCode\"\n            if (isKnown(type)) return type\n            val nodpi = \"$versionCode${architectureCode}00\"\n            if (isKnown(nodpi)) return nodpi // Fallback to nodpi for increased compat\n            return type // Use unknown build type\n        }\n    val versionString: String\n        get() = \"${BuildConfig.VERSION_NAME} ($buildType-{{cl}})\"\n    val versionCode: Int\n        get() = BuildConfig.VERSION_CODE + (getVersionOffset(buildType) ?: 0)\n\n    fun isKnown(type: String): Boolean = getVersionOffset(type) != null\n\n    fun getVersionOffset(type: String): Int? {\n        val v1 = type.substring(0, 2)\n        val v2 = type.substring(2, 4)\n        val v3 = type.substring(4, 6)\n        val i1 = BUILD_MAP.indexOfFirst { it.first == v1 }.takeIf { it >= 0 } ?: return null\n        val i2 = BUILD_MAP[i1].second.indexOfFirst { it.first == v2 }.takeIf { it >= 0 } ?: return null\n        val i3 = BUILD_MAP[i1].second[i2].second.indexOf(v3).takeIf { it > 0 } ?: return null\n        val o1 = BUILD_MAP.subList(0, i1).map { it.second.map { it.second.size }.sum() }.sum()\n        val o2 = BUILD_MAP[i1].second.subList(0, i2).map { it.second.size }.sum()\n        return o1 + o2 + i3\n    }\n\n    companion object {\n        val BUILD_MAP = listOf(\n                \"00\" to listOf(\"03\" to listOf(\"00\", \"02\", \"04\", \"06\", \"08\"), \"07\" to listOf(\"00\")),\n                \"02\" to listOf(\"03\" to listOf(\"00\", \"04\", \"06\", \"08\"), \"04\" to listOf(\"00\", \"06\", \"08\"), \"07\" to listOf(\"00\"), \"08\" to listOf(\"00\")),\n                \"04\" to listOf(\"03\" to listOf(\"00\", \"04\", \"06\", \"08\"), \"04\" to listOf(\"00\", \"06\", \"08\"), \"07\" to listOf(\"00\"), \"08\" to listOf(\"00\")),\n                \"10\" to listOf(\"03\" to listOf(\"00\", \"04\", \"06\", \"08\"), \"04\" to listOf(\"00\", \"06\", \"08\"), \"07\" to listOf(\"00\"), \"08\" to listOf(\"00\")),\n                \"12\" to listOf(\"03\" to listOf(\"00\", \"04\", \"06\", \"08\"), \"04\" to listOf(\"00\", \"06\", \"08\"), \"07\" to listOf(\"00\"), \"08\" to listOf(\"00\")),\n                \"15\" to listOf(\"03\" to listOf(\"00\", \"04\", \"06\", \"08\"), \"04\" to listOf(\"00\", \"06\", \"08\"), \"07\" to listOf(\"00\"), \"08\" to listOf(\"00\")),\n                \"19\" to listOf(\"03\" to listOf(\"00\", \"08\"), \"04\" to listOf(\"00\", \"08\"), \"07\" to listOf(\"00\"), \"08\" to listOf(\"00\")),\n        )\n    }\n}\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/kotlin/org/microg/gms/droidguard/core/ui/ContainedEditTextPreference.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2021 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.droidguard.core.ui\n\nimport android.content.Context\nimport android.text.TextWatcher\nimport android.util.AttributeSet\nimport android.view.inputmethod.InputMethodManager\nimport android.widget.EditText\nimport androidx.core.widget.addTextChangedListener\nimport androidx.preference.Preference\nimport androidx.preference.PreferenceViewHolder\nimport org.microg.gms.droidguard.core.R\n\nclass ContainedEditTextPreference : Preference {\n    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)\n    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)\n    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)\n    constructor(context: Context) : super(context)\n\n    override fun onBindViewHolder(holder: PreferenceViewHolder) {\n        super.onBindViewHolder(holder)\n        val editText = holder.itemView.findViewById<EditText>(android.R.id.edit)\n        (editText as? TextWatcher)?.let { editText.removeTextChangedListener(it) }\n        editText.addTextChangedListener { textChangedListener(it?.toString() ?: \"\") }\n        editText.tag = this\n        editText.hint = hint\n        editText.text.replace(0, editText.text.length, text)\n        editText.isEnabled = editable\n        if (requestFocus) {\n            editText.requestFocus()\n            (editText.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager).showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT)\n            requestFocus = false\n        }\n    }\n\n    private var requestFocus: Boolean = false\n    fun editRequestFocus() {\n        requestFocus = true\n        notifyChanged()\n    }\n\n    var textChangedListener: (String) -> Unit = {}\n\n    var editable: Boolean = true\n        set(value) {\n            field = value\n            notifyChanged()\n        }\n\n    var text: String = \"\"\n        set(value) {\n            field = value\n            notifyChanged()\n        }\n\n    var hint: String = \"\"\n        set(value) {\n            field = value\n            notifyChanged()\n        }\n\n    init {\n        layoutResource = R.layout.preference_material_with_widget_below\n        widgetLayoutResource = R.layout.preference_edit_widget\n    }\n}\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/kotlin/org/microg/gms/droidguard/core/ui/DroidGuardPreferencesFragment.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.droidguard.core.ui\n\nimport android.annotation.SuppressLint\nimport android.os.Bundle\nimport androidx.preference.Preference\nimport androidx.preference.PreferenceFragmentCompat\nimport androidx.preference.TwoStatePreference\nimport org.microg.gms.droidguard.core.DroidGuardPreferences\nimport org.microg.gms.droidguard.core.DroidGuardPreferences.Mode.Embedded\nimport org.microg.gms.droidguard.core.DroidGuardPreferences.Mode.Network\nimport org.microg.gms.droidguard.core.R\nimport org.microg.gms.base.core.R.drawable.ic_radio_checked\nimport org.microg.gms.base.core.R.drawable.ic_radio_unchecked\n\nclass DroidGuardPreferencesFragment : PreferenceFragmentCompat() {\n    private lateinit var modeEmbedded: Preference\n    private lateinit var modeNetwork: ContainedEditTextPreference\n    private lateinit var blockHardwareAttestation: TwoStatePreference\n\n    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {\n        addPreferencesFromResource(R.xml.preferences_droidguard)\n    }\n\n    @SuppressLint(\"RestrictedApi\")\n    override fun onBindPreferences() {\n        modeEmbedded = preferenceScreen.findPreference(\"pref_droidguard_mode_embedded\") ?: modeEmbedded\n        modeNetwork = preferenceScreen.findPreference(\"pref_droidguard_mode_network\") ?: modeNetwork\n        blockHardwareAttestation = preferenceScreen.findPreference(\"pref_droidguard_block_hw_attestation\") ?: blockHardwareAttestation\n        modeEmbedded.setOnPreferenceClickListener {\n            DroidGuardPreferences.setMode(it.context, Embedded)\n            updateConfiguration()\n            true\n        }\n        modeNetwork.setOnPreferenceClickListener {\n            DroidGuardPreferences.setMode(it.context, Network)\n            modeNetwork.editRequestFocus()\n            updateConfiguration()\n            true\n        }\n        modeNetwork.textChangedListener = {\n            DroidGuardPreferences.setNetworkServerUrl(requireContext(), it)\n        }\n        blockHardwareAttestation.setOnPreferenceChangeListener { _, newValue ->\n            DroidGuardPreferences.setHardwareAttestationBlocked(requireContext(), newValue as Boolean)\n            true\n        }\n        modeEmbedded.isEnabled = !DroidGuardPreferences.isForcedLocalDisabled(requireContext())\n        blockHardwareAttestation.isChecked = DroidGuardPreferences.isHardwareAttestationBlocked(requireContext())\n        updateConfiguration()\n    }\n\n    fun updateConfiguration() {\n        val mode = DroidGuardPreferences.getMode(requireContext())\n        modeEmbedded.setIcon(if (mode == Embedded) ic_radio_checked else ic_radio_unchecked)\n        modeNetwork.setIcon(if (mode == Network) ic_radio_checked else ic_radio_unchecked)\n        modeNetwork.text = DroidGuardPreferences.getNetworkServerUrl(requireContext()) ?: \"\"\n        modeNetwork.editable = mode == Network\n        modeNetwork.hint = \"https://example.com/droidguard/\"\n        blockHardwareAttestation.isEnabled = mode == Embedded\n    }\n}\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/proto/droidguard.proto",
    "content": "/*\n * SPDX-FileCopyrightText: 2016, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\noption java_package = \"org.microg.gms.droidguard\";\n\nmessage Usage {\n    optional string flow = 1;\n    optional string packageName = 2;\n}\n\nmessage KeyValuePair {\n    optional string key = 1;\n    optional string val = 2;\n}\n\nmessage StackTraceElement {\n    optional string className = 1;\n    optional string methodName = 2;\n    optional string fileName = 3;\n    optional int32 lineNumber = 4;\n    optional bool isNativeMethod = 5;\n}\n\nmessage ExceptionInfo {\n    optional string name = 1;\n    optional string message = 2;\n    repeated StackTraceElement stackTrace = 3;\n}\n\nmessage ExceptionList {\n    repeated ExceptionInfo exceptions = 1;\n}\n\nmessage PingData {\n    optional string field1 = 1;\n    optional int64 field2 = 2;\n}\n\nmessage Request {\n    optional Usage usage = 1;\n    repeated KeyValuePair info = 2;\n    optional string versionName = 3;\n    optional bool hasAccount = 6;\n    optional bool isGoogleCn = 7;\n    optional bool enableInlineVm = 8;\n    repeated bytes cached = 9;\n    optional bytes field10 = 10;\n    optional int32 field11 = 11;\n    optional ExceptionList exceptions = 12;\n    optional int32 versionCode = 13;\n    optional string arch = 14;\n    optional int32 field15 = 15;\n    optional PingData ping = 16;\n}\n\nmessage SignedResponse {\n    optional bytes data = 1;\n    optional bytes signature = 2;\n}\n\nmessage Response {\n    optional bytes byteCode = 1;\n    optional string vmUrl = 2;\n    optional bytes vmChecksum = 3;\n    optional int32 expiryTimeSecs = 4;\n    optional bytes content = 5;\n    optional bool save = 6;\n    optional int32 minWait = 7;\n    optional int32 maxWait = 8;\n    optional bytes extra = 9;\n}\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/layout/preference_edit_widget.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2021 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<LinearLayout 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\n    <EditText\n        android:id=\"@android:id/edit\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:focusedByDefault=\"false\"\n        android:inputType=\"textUri\"\n        android:lines=\"1\"\n        android:maxLines=\"1\" />\n</LinearLayout>\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/layout/preference_material_with_widget_below.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2015 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<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:minHeight=\"?android:attr/listPreferredItemHeightSmall\"\n    android:gravity=\"center_vertical\"\n    android:paddingLeft=\"?android:attr/listPreferredItemPaddingLeft\"\n    android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n    android:paddingRight=\"?android:attr/listPreferredItemPaddingRight\"\n    android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"\n    android:background=\"?android:attr/selectableItemBackground\"\n    android:clipToPadding=\"false\"\n    android:baselineAligned=\"false\">\n\n    <include layout=\"@layout/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        <TextView\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\n        <TextView\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:textColor=\"?android:attr/textColorSecondary\"\n            android:maxLines=\"10\"\n            style=\"@style/PreferenceSummaryTextStyle\"/>\n\n\n        <!-- Preference should place its actual preference widget here. -->\n        <LinearLayout\n            android:id=\"@android:id/widget_frame\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_below=\"@android:id/summary\"\n            android:layout_alignLeft=\"@android:id/title\"\n            android:layout_alignStart=\"@android:id/title\"\n            android:gravity=\"end|center_vertical\"\n            android:orientation=\"vertical\"/>\n    </RelativeLayout>\n\n</LinearLayout>\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2021 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<resources>\n    <string name=\"prefcat_droidguard_mode\">DroidGuard operation mode</string>\n    <string name=\"pref_droidguard_mode_embedded_title\">Embedded</string>\n    <string name=\"pref_droidguard_mode_embedded_summary\">Use local DroidGuard runtime</string>\n    <string name=\"pref_droidguard_mode_network_title\">Remote</string>\n    <string name=\"pref_droidguard_mode_network_summary\">Connect to DroidGuard runtime via network</string>\n    <string name=\"pref_droidguard_block_hw_attestation_title\">Block hardware attestation</string>\n    <string name=\"pref_droidguard_block_hw_attestation_summary\">When using embedded DroidGuard, disable access to hardware attestation. Might help passing integrity checks on some devices.</string>\n</resources>\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-ar/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"prefcat_droidguard_mode\">وضع تشغيل درويدغارد</string>\n    <string name=\"pref_droidguard_mode_embedded_title\">مدمج</string>\n    <string name=\"pref_droidguard_mode_embedded_summary\">استخدم نظام تنفيد درويدغارد المحلي</string>\n    <string name=\"pref_droidguard_mode_network_title\">عن بعد</string>\n    <string name=\"pref_droidguard_mode_network_summary\">اتصل بنظام تنفيذ درويدغارد عبر الشبكة</string>\n    <string name=\"pref_droidguard_block_hw_attestation_title\">منع اختبار مصادقة العتاد</string>\n    <string name=\"pref_droidguard_block_hw_attestation_summary\">عند استخدام درويدغارد المدمج، إمنع اختبارات مصادفة العتاد (اختبار الجهاز). قد يساعد ذلك في اجتياز اختبارات التكامل على بعض الأجهزة.</string>\n</resources>\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-ast/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources></resources>"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-az/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"pref_droidguard_mode_network_summary\">Şəbəkə vasitəsilə DroidGuard iş vaxtına qoşul</string>\n    <string name=\"prefcat_droidguard_mode\">DroidGuard iş rejimi</string>\n    <string name=\"pref_droidguard_mode_embedded_title\">Daxili</string>\n    <string name=\"pref_droidguard_mode_embedded_summary\">Yerli DroidGuard iş vaxtın istifadə et</string>\n    <string name=\"pref_droidguard_mode_network_title\">Uzaqdan</string>\n</resources>"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-be/strings.xml",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2021 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<resources>\n    <string name=\"prefcat_droidguard_mode\">Рэжым работы DroidGuard</string>\n    <string name=\"pref_droidguard_mode_embedded_title\">Лакальны</string>\n    <string name=\"pref_droidguard_mode_embedded_summary\">Выкарыстоўваць лакальнае асяроддзе выканання DroidGuard</string>\n    <string name=\"pref_droidguard_mode_network_title\">Выдалены</string>\n    <string name=\"pref_droidguard_mode_network_summary\">Падключыцца да асяроддзя выканання DroidGuard па сетцы</string>\n</resources>\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-bn/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n</resources>"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-ca/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"prefcat_droidguard_mode\">Mode d\\'operació DroidGuard</string>\n    <string name=\"pref_droidguard_mode_embedded_title\">Integrat</string>\n    <string name=\"pref_droidguard_mode_embedded_summary\">Utilitza l\\'entorn d\\'execució DroidGuard local</string>\n    <string name=\"pref_droidguard_mode_network_title\">Remot</string>\n    <string name=\"pref_droidguard_mode_network_summary\">Connecta a l\\'entorn d\\'execució de DroidGuard a través de la xarxa</string>\n    <string name=\"pref_droidguard_block_hw_attestation_title\">Bloca la certificació del maquinari</string>\n    <string name=\"pref_droidguard_block_hw_attestation_summary\">Quan utilitzeu DroidGuard integrat, desactiveu l\\'accés a la certificació del maquinari. Pot ajudar a superar les comprovacions d\\'integritat en alguns dispositius.</string>\n</resources>\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-cs/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"pref_droidguard_mode_embedded_summary\">Použít místní běhové prostředí DroidGuard</string>\n    <string name=\"pref_droidguard_mode_network_summary\">Připojit se k běhovému prostředí DroidGuard pomocí sítě</string>\n    <string name=\"prefcat_droidguard_mode\">Režim operace DroidGuard</string>\n    <string name=\"pref_droidguard_mode_embedded_title\">Vložený</string>\n    <string name=\"pref_droidguard_mode_network_title\">Vzdálený</string>\n    <string name=\"pref_droidguard_block_hw_attestation_title\">Blokovat hardwarovou atestaci</string>\n    <string name=\"pref_droidguard_block_hw_attestation_summary\">Při používání vložené služby DroidGuard zakázat přístup k hardwarové atestaci. Může pomoci projít kontrolami integrity na některých zařízeních.</string>\n</resources>\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-de/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"prefcat_droidguard_mode\">DroidGuard-Betriebsmodus</string>\n    <string name=\"pref_droidguard_mode_embedded_title\">Eingebettet</string>\n    <string name=\"pref_droidguard_mode_embedded_summary\">Lokale DroidGuard-Laufzeit verwenden</string>\n    <string name=\"pref_droidguard_mode_network_summary\">Über das Netzwerk mit der DroidGuard-Laufzeit verbinden</string>\n    <string name=\"pref_droidguard_mode_network_title\">Externe</string>\n    <string name=\"pref_droidguard_block_hw_attestation_title\">Hardware-Attestierung blockieren</string>\n    <string name=\"pref_droidguard_block_hw_attestation_summary\">Bei Verwendung des integrierten DroidGuard den Zugriff auf die Hardware-Attestierung deaktivieren. Dies kann dazu beitragen, dass Integritätsprüfungen auf einigen Geräten erfolgreich durchgeführt werden können.</string>\n</resources>\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-eo/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources></resources>"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-es/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"prefcat_droidguard_mode\">Modo de funcionamiento de DroidGuard</string>\n    <string name=\"pref_droidguard_mode_network_summary\">Conectar al entorno de ejecución DroidGuard a través de la red</string>\n    <string name=\"pref_droidguard_mode_embedded_title\">Integrado</string>\n    <string name=\"pref_droidguard_mode_embedded_summary\">Utilice el entorno de ejecución local de DroidGuard</string>\n    <string name=\"pref_droidguard_mode_network_title\">A distancia</string>\n    <string name=\"pref_droidguard_block_hw_attestation_title\">Bloquear la atestación de hardware</string>\n    <string name=\"pref_droidguard_block_hw_attestation_summary\">Al usar DroidGuard integrado, desactive el acceso a la atestación de hardware. Esto puede ayudar a superar las comprobaciones de integridad en algunos dispositivos.</string>\n</resources>\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-fa/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"prefcat_droidguard_mode\">حالت عملکرد DroidGuard</string>\n    <string name=\"pref_droidguard_mode_embedded_title\">جاسازی شده</string>\n    <string name=\"pref_droidguard_mode_embedded_summary\">استفاده از زمان اجرا محلی DroidGuard</string>\n    <string name=\"pref_droidguard_mode_network_title\">راه دور</string>\n    <string name=\"pref_droidguard_mode_network_summary\">اتصال به زمان اجرا DroidGuard با شبکه</string>\n    <string name=\"pref_droidguard_block_hw_attestation_title\">تأییدیه بلوک سخت افزار</string>\n    <string name=\"pref_droidguard_block_hw_attestation_summary\">زمانی که از DroidGuard جاسازی شده استفاده میکنید، دسترسی به تأییدیه سخت افزار را غیرفعال کنید. این کار ممکن است به قبولی در بررسی‌های یکپارچگی، در برخی دستگاه ها کمک کند.</string>\n</resources>\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-fi/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"prefcat_droidguard_mode\">DroidGuardin käyttötila</string>\n    <string name=\"pref_droidguard_mode_embedded_title\">Sisäänrakennettu</string>\n    <string name=\"pref_droidguard_mode_embedded_summary\">Käytä paikallista DroidGuard runtimea</string>\n    <string name=\"pref_droidguard_mode_network_summary\">Yhdistä DroidGuard runtimeen verkon kautta</string>\n</resources>\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-fil/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"pref_droidguard_mode_embedded_summary\">Gamitin ang lokal na DroidGuard runtime</string>\n    <string name=\"pref_droidguard_mode_network_summary\">Kumonekta sa DroidGuard runtime sa pamamagitan ng network</string>\n    <string name=\"pref_droidguard_mode_network_title\">Remote</string>\n    <string name=\"prefcat_droidguard_mode\">Mode ng operasyon ng DroidGuard</string>\n    <string name=\"pref_droidguard_mode_embedded_title\">Naka-embed</string>\n    <string name=\"pref_droidguard_block_hw_attestation_title\">Harangan ang pagpapatunay gamit ng hardware</string>\n    <string name=\"pref_droidguard_block_hw_attestation_summary\">Kapag gumagamit ng embedded na DroidGuard, i-disable ang access sa hardware na pagpapatunay. Maaaring makatulong sa pagpasa ng mga pagsusuri sa integridad sa ilang device.</string>\n</resources>\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-fr/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"prefcat_droidguard_mode\">Mode d\\'opération DroidGuard</string>\n    <string name=\"pref_droidguard_mode_embedded_title\">Embarqué</string>\n    <string name=\"pref_droidguard_mode_network_title\">A distance</string>\n    <string name=\"pref_droidguard_mode_embedded_summary\">Exécuter localement DroidGuard</string>\n    <string name=\"pref_droidguard_mode_network_summary\">Exécuter DroidGuard via une connexion réseau</string>\n    <string name=\"pref_droidguard_block_hw_attestation_title\">Bloquer l\\'attestation matérielle</string>\n    <string name=\"pref_droidguard_block_hw_attestation_summary\">Désactive l’accès à l’attestation matérielle quand DroidGuard embarqué est utilisé. Peut aider à passer les vérifications d\\'intégrité sur certains appareils.</string>\n</resources>\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-ga/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"pref_droidguard_mode_network_summary\">Ceangail le ham rite DroidGuard tríd an líonra</string>\n    <string name=\"pref_droidguard_mode_network_title\">Cianda</string>\n    <string name=\"prefcat_droidguard_mode\">Modh oibríochta DroidGuard</string>\n    <string name=\"pref_droidguard_mode_embedded_title\">Leabaithe</string>\n    <string name=\"pref_droidguard_mode_embedded_summary\">Úsáid am rite áitiúil DroidGuard</string>\n    <string name=\"pref_droidguard_block_hw_attestation_title\">Deimhniú crua-earraí bloc</string>\n    <string name=\"pref_droidguard_block_hw_attestation_summary\">Agus DroidGuard leabaithe in úsáid agat, díchumasaigh rochtain ar dheimhniú crua-earraí. D’fhéadfadh sé seo cabhrú le seiceálacha sláine a rith ar roinnt gléasanna.</string>\n</resources>\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-hu/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"prefcat_droidguard_mode\">DroidGuard működési mód</string>\n    <string name=\"pref_droidguard_mode_embedded_title\">Beépített</string>\n    <string name=\"pref_droidguard_mode_embedded_summary\">Helyi DroidGuard futásidejű szoftver használata</string>\n    <string name=\"pref_droidguard_mode_network_title\">Távoli</string>\n    <string name=\"pref_droidguard_mode_network_summary\">Távoli DroidGuard futásidejű szoftver használata</string>\n</resources>\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-in/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"prefcat_droidguard_mode\">Mode operasi DroidGuard</string>\n    <string name=\"pref_droidguard_mode_embedded_summary\">Gunakan runtime DroidGuard lokal</string>\n    <string name=\"pref_droidguard_mode_embedded_title\">Tertanam</string>\n    <string name=\"pref_droidguard_mode_network_title\">Jarak jauh</string>\n    <string name=\"pref_droidguard_mode_network_summary\">Hubungkan ke runtime DroidGuard melalui jaringan</string>\n    <string name=\"pref_droidguard_block_hw_attestation_title\">Blokir pengesahan perangkat keras</string>\n    <string name=\"pref_droidguard_block_hw_attestation_summary\">Saat menggunakan DroidGuard yang terintegrasi, nonaktifkan akses ke pengesahan perangkat keras. Hal ini mungkin membantu melewati pemeriksaan integritas pada beberapa perangkat.</string>\n</resources>\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-is/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"prefcat_droidguard_mode\">Virknihamur DroidGuard</string>\n    <string name=\"pref_droidguard_mode_embedded_title\">Ívafið</string>\n    <string name=\"pref_droidguard_mode_network_title\">Fjartengt</string>\n    <string name=\"pref_droidguard_mode_embedded_summary\">Nota staðbundna DroidGuard-keyrsluskrá</string>\n    <string name=\"pref_droidguard_mode_network_summary\">Tengjast DroidGuard-keyrsluskrá í gegnum netkerfi</string>\n    <string name=\"pref_droidguard_block_hw_attestation_title\">Loka á sannvottun vélbúnaðar</string>\n    <string name=\"pref_droidguard_block_hw_attestation_summary\">Þegar verið er að nota ívafið DroidGuard (embedded), skal gera sannvottun vélbúnaðar (hardware attestation) óvirka. Þetta gæti hjálpað til við að standast áreiðanleikaprófanir á sumum tækjum.</string>\n</resources>\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-it/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"prefcat_droidguard_mode\">Modalità operativa di DroidGuard</string>\n    <string name=\"pref_droidguard_mode_embedded_title\">Integrata</string>\n    <string name=\"pref_droidguard_mode_embedded_summary\">Utilizza il runtime locale di DroidGuard</string>\n    <string name=\"pref_droidguard_mode_network_title\">Remota</string>\n    <string name=\"pref_droidguard_mode_network_summary\">Effettua la connessione al runtime di DroidGuard attraverso la rete</string>\n    <string name=\"pref_droidguard_block_hw_attestation_title\">Blocca attestazione hardware</string>\n    <string name=\"pref_droidguard_block_hw_attestation_summary\">Quando si utilizza DroidGuard integrato, disabilita l\\'accesso all\\'attestazione hardware. Potrebbe aiutare a superare i controlli di integrità su alcuni dispositivi.</string>\n</resources>\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-iw/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n</resources>"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-ja/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"prefcat_droidguard_mode\">DroidGuard操作モード</string>\n    <string name=\"pref_droidguard_mode_embedded_title\">組み込み型</string>\n    <string name=\"pref_droidguard_mode_embedded_summary\">ローカルの DroidGuard ランタイムを使用する</string>\n    <string name=\"pref_droidguard_mode_network_title\">リモート</string>\n    <string name=\"pref_droidguard_mode_network_summary\">ネットワーク経由でDroidGuardランタイムに接続する</string>\n    <string name=\"pref_droidguard_block_hw_attestation_title\">ハードウェア認証をブロックする</string>\n    <string name=\"pref_droidguard_block_hw_attestation_summary\">組み込み DroidGuard を使用する際は、ハードウェア認証へのアクセスを無効にしてください。一部のデバイスで完全性チェックを通過するのに役立つ可能性があります。</string>\n</resources>\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-ko/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"prefcat_droidguard_mode\">DroidGuard 작동 모드</string>\n    <string name=\"pref_droidguard_mode_embedded_title\">임베디드</string>\n    <string name=\"pref_droidguard_mode_embedded_summary\">내장된 DroidGuard 런타임 사용</string>\n    <string name=\"pref_droidguard_mode_network_title\">원격</string>\n    <string name=\"pref_droidguard_mode_network_summary\">네트워크로 DroidGuard 런타임에 연결</string>\n    <string name=\"pref_droidguard_block_hw_attestation_title\">하드웨어 증명 차단</string>\n    <string name=\"pref_droidguard_block_hw_attestation_summary\">임베디드 DroidGuard를 사용할 때, 하드웨어 인증에 대한 접근을 비활성화합니다. 일부 장치에서 무결성 검사를 통과하는 데 도움이 될 수 있습니다.</string>\n</resources>\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-lv/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources></resources>"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-lzh/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources></resources>"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-ml/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"prefcat_droidguard_mode\">ഡ്രോയിഡ് ഗാർഡ് പ്രവർത്തന രീതി</string>\n    <string name=\"pref_droidguard_mode_embedded_title\">എംബഡഡ്</string>\n    <string name=\"pref_droidguard_mode_network_title\">റിമോട്ട്</string>\n    <string name=\"pref_droidguard_mode_embedded_summary\">ലോക്കൽ ഡ്രോയിഡ് ഗാർഡ് റൺടൈം ഉപയോഗിക്കുക</string>\n    <string name=\"pref_droidguard_mode_network_summary\">നെറ്റ്‌വർക്ക് വഴി ഡ്രോയിഡ് ഗാർഡ് റൺടൈമിലേക്ക് കണക്റ്റുചെയ്യുക</string>\n    <string name=\"pref_droidguard_block_hw_attestation_title\">ഹാർഡ്‌വെയർ അറ്റസ്റ്റേഷൻ തടയുക</string>\n    <string name=\"pref_droidguard_block_hw_attestation_summary\">എംബഡഡ് ഡ്രോയിഡ് ഗാർഡ് ഉപയോഗിക്കുമ്പോൾ, ഹാർഡ്‌വെയർ അറ്റസ്റ്റേഷനിലേക്കുള്ള ആക്‌സസ് പ്രവർത്തനരഹിതമാക്കുക. ചില ഉപകരണങ്ങളിൽ സമഗ്രത പരിശോധനകൾ പാസാക്കാൻ സഹായിച്ചേക്കാം.</string>\n</resources>\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-nb-rNO/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"prefcat_droidguard_mode\">DroidGuard-driftsmodus</string>\n    <string name=\"pref_droidguard_mode_embedded_title\">Innebygd</string>\n    <string name=\"pref_droidguard_mode_embedded_summary\">Bruk lokal DroidGuard-runtime</string>\n    <string name=\"pref_droidguard_mode_network_title\">Ekstern</string>\n    <string name=\"pref_droidguard_mode_network_summary\">Koble til DroidGuard-runtime over nettverket</string>\n    <string name=\"pref_droidguard_block_hw_attestation_title\">Klokker maskinvareattestering</string>\n    <string name=\"pref_droidguard_block_hw_attestation_summary\">Blokker tilgang til maskinvareattestering når innebygd Droidguard er i bruk. Kan hjelpe med å få godkjent integritetssjekker på enkelte enheter.</string>\n</resources>\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-nl/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"pref_droidguard_block_hw_attestation_summary\">Bij gebruik van de ingebouwde DroidGuard-hardware is het raadzaam de toegang tot hardware-attestatie uit te schakelen. Dit kan helpen bij het slagen voor integriteitscontroles op sommige apparaten.</string>\n</resources>\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-pl/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"pref_droidguard_mode_network_summary\">Połącz z usługą DroidGuard przez sieć</string>\n    <string name=\"prefcat_droidguard_mode\">Tryb działania DroidGuard</string>\n    <string name=\"pref_droidguard_mode_embedded_summary\">Korzystaj z lokalnej usługi DroidGuard</string>\n    <string name=\"pref_droidguard_mode_embedded_title\">Wbudowany</string>\n    <string name=\"pref_droidguard_mode_network_title\">Zdalny</string>\n    <string name=\"pref_droidguard_block_hw_attestation_title\">Blokowanie zaświadczeń sprzętowych</string>\n    <string name=\"pref_droidguard_block_hw_attestation_summary\">Podczas korzystania z wbudowanego DroidGuard należy wyłączyć dostęp do poświadczeń sprzętowych. Może to pomóc w przejściu kontroli integralności na niektórych urządzeniach.</string>\n</resources>\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-pt/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"prefcat_droidguard_mode\">Modo de operação do DroidGuard</string>\n    <string name=\"pref_droidguard_mode_embedded_title\">Embutido</string>\n    <string name=\"pref_droidguard_mode_embedded_summary\">Usar runtime local do DroidGuard</string>\n    <string name=\"pref_droidguard_mode_network_title\">Remoto</string>\n    <string name=\"pref_droidguard_mode_network_summary\">Conectar ao runtime do DroidGuard pela rede</string>\n    <string name=\"pref_droidguard_block_hw_attestation_title\">Bloquear atestação por hardware</string>\n    <string name=\"pref_droidguard_block_hw_attestation_summary\">Ao usar o DroidGuard embutido, desative o acesso à atestação por hardware. Pode ajudar a passar os testes de integridade em alguns dispositivos.</string>\n</resources>\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-pt-rBR/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"prefcat_droidguard_mode\">Modo de operação do DroidGuard</string>\n    <string name=\"pref_droidguard_mode_embedded_title\">Embutido</string>\n    <string name=\"pref_droidguard_mode_embedded_summary\">Usar runtime local do DroidGuard</string>\n    <string name=\"pref_droidguard_mode_network_title\">Remoto</string>\n    <string name=\"pref_droidguard_mode_network_summary\">Conectar ao runtime do DroidGuard pela rede</string>\n    <string name=\"pref_droidguard_block_hw_attestation_title\">Bloquear atestação por hardware</string>\n    <string name=\"pref_droidguard_block_hw_attestation_summary\">Ao usar o DroidGuard embutido, desativar o acesso à atestação por hardware. Pode ajudar a passar os testes de integridade em alguns dispositivos.</string>\n</resources>\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-ro/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"pref_droidguard_mode_network_summary\">Conectează-te la runtime DroidGuard prin rețea</string>\n    <string name=\"prefcat_droidguard_mode\">Modul de operare DroidGuard</string>\n    <string name=\"pref_droidguard_mode_embedded_summary\">Utilizează timpul de rulare local DroidGuard</string>\n    <string name=\"pref_droidguard_mode_embedded_title\">Încorporat</string>\n    <string name=\"pref_droidguard_mode_network_title\">La distanță</string>\n    <string name=\"pref_droidguard_block_hw_attestation_title\">Blochează atestarea hardware</string>\n    <string name=\"pref_droidguard_block_hw_attestation_summary\">Când utilizezi DroidGuard încorporat, dezactivează accesul la atestarea hardware. Ar putea ajuta la trecerea verificărilor de integritate pe unele dispozitive.</string>\n</resources>\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-ru/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2021 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  --><resources>\n    <string name=\"prefcat_droidguard_mode\">Режим работы DroidGuard</string>\n    <string name=\"pref_droidguard_mode_embedded_title\">Локальный</string>\n    <string name=\"pref_droidguard_mode_embedded_summary\">Использовать локальную среду выполнения DroidGuard</string>\n    <string name=\"pref_droidguard_mode_network_title\">Удалённый</string>\n    <string name=\"pref_droidguard_mode_network_summary\">Подключиться к среде выполнения DroidGuard по сети</string>\n    <string name=\"pref_droidguard_block_hw_attestation_summary\">При использовании встроенного DroidGuard отключите доступ к аппаратной аттестации. Это может помочь пройти проверку целостности на некоторых устройствах.</string>\n    <string name=\"pref_droidguard_block_hw_attestation_title\">Блокировать аппаратную аттестацию</string>\n</resources>\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-sl/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n</resources>"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-sr/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"pref_droidguard_mode_network_summary\">Повежите се са DroidGuard временом извршавања преко мреже</string>\n    <string name=\"prefcat_droidguard_mode\">DroidGuard режим рада</string>\n    <string name=\"pref_droidguard_mode_embedded_summary\">Користите локално DroidGuard време извршавања</string>\n    <string name=\"pref_droidguard_mode_embedded_title\">Уграђени</string>\n    <string name=\"pref_droidguard_mode_network_title\">Удаљени</string>\n    <string name=\"pref_droidguard_block_hw_attestation_title\">Блокирај атестацију хардвера</string>\n    <string name=\"pref_droidguard_block_hw_attestation_summary\">Када користите уграђени DroidGuard, онемогућите приступ атестацији хардвера. Може помоћи у проласку провера интегритета на неким уређајима.</string>\n</resources>\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-sv/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"pref_droidguard_mode_network_summary\">Anslut till DroidGuard runtime via nätverk</string>\n    <string name=\"prefcat_droidguard_mode\">DroidGuard driftläge</string>\n    <string name=\"pref_droidguard_mode_embedded_summary\">Använd lokal DroidGuard-körning</string>\n    <string name=\"pref_droidguard_mode_embedded_title\">Inbäddad</string>\n    <string name=\"pref_droidguard_mode_network_title\">Fjärr</string>\n    <string name=\"pref_droidguard_block_hw_attestation_title\">Blockera hårdvaruattestering</string>\n    <string name=\"pref_droidguard_block_hw_attestation_summary\">Inaktivera åtkomst till hårdvaruattestering, om du använder inbäddad DroidGuard. Kan hjälpa för att passera integritetskontroller på vissa enheter.</string>\n</resources>\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-ta/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"prefcat_droidguard_mode\">டிராய்ட்காப்பு செயல்பாட்டு முறை</string>\n    <string name=\"pref_droidguard_mode_embedded_title\">உட்பொதிக்கப்பட்டது</string>\n    <string name=\"pref_droidguard_mode_embedded_summary\">உள்ளக டிராய்ட்காப்பு இயக்க நேரத்தைப் பயன்படுத்து</string>\n    <string name=\"pref_droidguard_mode_network_title\">தொலைநிலை</string>\n    <string name=\"pref_droidguard_mode_network_summary\">பிணையம் வழியாக டிராய்ட்காப்பு இயக்க நேரத்துடன் இணை</string>\n    <string name=\"pref_droidguard_block_hw_attestation_title\">வன்பொருள் சான்றளிப்பைத் தடு</string>\n    <string name=\"pref_droidguard_block_hw_attestation_summary\">உட்பொதிக்கப்பட்ட DroidGuard ஐப் பயன்படுத்தும்போது, வன்பொருள் சான்றளிப்புக்கான அணுகலை முடக்கவும். சில சாதனங்களில் ஒருமைப்பாடு சோதனைகளை அனுப்ப உதவக்கூடும்.</string>\n</resources>\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-th/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"pref_droidguard_mode_embedded_title\">ฝังตัว</string>\n    <string name=\"pref_droidguard_mode_network_title\">ระยะไกล</string>\n    <string name=\"pref_droidguard_mode_network_summary\">เชื่อมต่อกับรันไทม์ DroidGuard ผ่านเครือข่าย</string>\n    <string name=\"prefcat_droidguard_mode\">โหมดการทำงานของ DroidGuard</string>\n    <string name=\"pref_droidguard_mode_embedded_summary\">ใช้รันไทม์ DroidGuard ในเครื่อง</string>\n    <string name=\"pref_droidguard_block_hw_attestation_title\">ปิดกั้นการตรวจสอบฮาร์ดแวร์</string>\n    <string name=\"pref_droidguard_block_hw_attestation_summary\">เมื่อใช้ DroidGuard แบบฝัง (embedded) ให้ ปิดการเข้าถึงการยืนยันฮาร์ดแวร์ (hardware attestation) ซึ่งอาจช่วยให้ ผ่านการตรวจสอบความสมบูรณ์ (integrity checks) บนอุปกรณ์บางเครื่องได้</string>\n</resources>\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-tr/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"prefcat_droidguard_mode\">DroidGuard çalışma modu</string>\n    <string name=\"pref_droidguard_mode_embedded_title\">Gömülü</string>\n    <string name=\"pref_droidguard_mode_embedded_summary\">Yerel DroidGuard çalıştırıcısını kullan</string>\n    <string name=\"pref_droidguard_mode_network_title\">Uzak</string>\n    <string name=\"pref_droidguard_mode_network_summary\">Ağ üzerinden DroidGuard çalıştırıcısına bağlan</string>\n    <string name=\"pref_droidguard_block_hw_attestation_title\">Donanım dayalı sağlamayı engelle</string>\n    <string name=\"pref_droidguard_block_hw_attestation_summary\">Gömülü DroidGuard\\'ı kullanırken donanıma dayalı doğrulamaya erişimi devre dışı bırakır. Bazı cihazlarda bütünlük doğrulama testinden başarıyla geçilmesini sağlayabilir.</string>\n</resources>\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-ug/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"pref_droidguard_mode_network_summary\">تور ئارقىلىق DroidGuard ئىجرا ۋاقتىغا باغلانغاندا</string>\n    <string name=\"prefcat_droidguard_mode\">DroidGuard مەشغۇلات ھالىتى</string>\n    <string name=\"pref_droidguard_mode_embedded_title\">سىڭدۈرۈلگەن</string>\n    <string name=\"pref_droidguard_mode_embedded_summary\">يەرلىك DroidGuard ئىجرا ۋاقتىنى ئىشلىتىدۇ</string>\n    <string name=\"pref_droidguard_mode_network_title\">يىراق</string>\n    <string name=\"pref_droidguard_block_hw_attestation_title\">قاتتىق دېتال دەلىللەشنى توسىدۇ</string>\n    <string name=\"pref_droidguard_block_hw_attestation_summary\">سىڭدۈرمە DroidGuard ئىشلەتكەندە، قاتتىق دېتال دەلىللەشنى زىيارەت قىلىشنى چەكلەيدۇ. بۇ بەزى ئۈسكۈنىلەردە مۇكەممەللىكنى تەكشۈرۈشتىن ئۆتۈشكە ياردىمى بولۇشى مۇمكىن.</string>\n</resources>\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-uk/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"pref_droidguard_mode_network_summary\">Під\\'єднатися до середовища виконання DroidGuard через мережу</string>\n    <string name=\"prefcat_droidguard_mode\">Режим роботи DroidGuard</string>\n    <string name=\"pref_droidguard_mode_embedded_summary\">Використовувати локальне середовище виконання DroidGuard</string>\n    <string name=\"pref_droidguard_mode_embedded_title\">Вбудований</string>\n    <string name=\"pref_droidguard_mode_network_title\">Віддалений</string>\n    <string name=\"pref_droidguard_block_hw_attestation_title\">Блокувати підтвердження обладнання</string>\n    <string name=\"pref_droidguard_block_hw_attestation_summary\">При використанні вбудованого DroidGuard вимкніть доступ до підтвердження апаратного забезпечення. Це може допомогти пройти перевірку цілісності на деяких пристроях.</string>\n</resources>\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-vi/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"prefcat_droidguard_mode\">Chế độ hoạt động của DroidGuard</string>\n    <string name=\"pref_droidguard_mode_embedded_title\">Nhúng</string>\n    <string name=\"pref_droidguard_mode_embedded_summary\">Sử dụng runtime DroidGuard cục bộ</string>\n    <string name=\"pref_droidguard_mode_network_title\">Từ xa</string>\n    <string name=\"pref_droidguard_mode_network_summary\">Kết nối đến runtime DroidGuard qua mạng</string>\n    <string name=\"pref_droidguard_block_hw_attestation_title\">Chặn xác thực phần cứng</string>\n    <string name=\"pref_droidguard_block_hw_attestation_summary\">Khi dùng DroidGuard nhúng, vô hiệu hóa truy cập xác thực phần cứng. Có thể giúp vượt qua kiểm tra tính toàn vẹn trên một số thiết bị.</string>\n</resources>\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-zh-rCN/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"prefcat_droidguard_mode\">DroidGuard 运作模式</string>\n    <string name=\"pref_droidguard_mode_network_summary\">通过网络连接到 DroidGuard 运行时</string>\n    <string name=\"pref_droidguard_mode_embedded_title\">内置</string>\n    <string name=\"pref_droidguard_mode_network_title\">远程</string>\n    <string name=\"pref_droidguard_mode_embedded_summary\">使用本地 DroidGuard 运行时</string>\n    <string name=\"pref_droidguard_block_hw_attestation_title\">阻止硬件认证</string>\n    <string name=\"pref_droidguard_block_hw_attestation_summary\">在使用嵌入式 DroidGuard 时，禁用对硬件认证的访问。这可能有助于在某些设备上通过完整性检查。</string>\n</resources>\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/values-zh-rTW/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"pref_droidguard_mode_network_title\">遠端</string>\n    <string name=\"prefcat_droidguard_mode\">DroidGuard 運作模式</string>\n    <string name=\"pref_droidguard_mode_embedded_title\">內建</string>\n    <string name=\"pref_droidguard_mode_embedded_summary\">使用本地 DroidGuard runtime</string>\n    <string name=\"pref_droidguard_mode_network_summary\">透過網路連接到 DroidGuard runtime</string>\n</resources>\n"
  },
  {
    "path": "play-services-droidguard/core/src/main/res/xml/preferences_droidguard.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n    <PreferenceCategory\n        android:title=\"@string/prefcat_droidguard_mode\"\n        app:iconSpaceReserved=\"false\">\n        <Preference\n            android:icon=\"@drawable/ic_radio_unchecked\"\n            android:key=\"pref_droidguard_mode_embedded\"\n            android:persistent=\"false\"\n            android:summary=\"@string/pref_droidguard_mode_embedded_summary\"\n            android:title=\"@string/pref_droidguard_mode_embedded_title\" />\n        <org.microg.gms.droidguard.core.ui.ContainedEditTextPreference\n            android:icon=\"@drawable/ic_radio_unchecked\"\n            android:key=\"pref_droidguard_mode_network\"\n            android:persistent=\"false\"\n            android:summary=\"@string/pref_droidguard_mode_network_summary\"\n            android:title=\"@string/pref_droidguard_mode_network_title\" />\n    </PreferenceCategory>\n    <SwitchPreferenceCompat\n        android:defaultValue=\"true\"\n        android:persistent=\"false\"\n        android:key=\"pref_droidguard_block_hw_attestation\"\n        android:summary=\"@string/pref_droidguard_block_hw_attestation_summary\"\n        android:title=\"@string/pref_droidguard_block_hw_attestation_title\"\n        app:iconSpaceReserved=\"false\" />\n</PreferenceScreen>\n"
  },
  {
    "path": "play-services-droidguard/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<manifest />\n"
  },
  {
    "path": "play-services-droidguard/src/main/aidl/com/google/android/gms/droidguard/internal/DroidGuardInitReply.aidl",
    "content": "package com.google.android.gms.droidguard.internal;\n\nparcelable DroidGuardInitReply;\n"
  },
  {
    "path": "play-services-droidguard/src/main/aidl/com/google/android/gms/droidguard/internal/DroidGuardResultsRequest.aidl",
    "content": "package com.google.android.gms.droidguard.internal;\n\nparcelable DroidGuardResultsRequest;\n"
  },
  {
    "path": "play-services-droidguard/src/main/aidl/com/google/android/gms/droidguard/internal/IDroidGuardCallbacks.aidl",
    "content": "package com.google.android.gms.droidguard.internal;\n\ninterface IDroidGuardCallbacks {\n    void onResult(in byte[] res);\n}\n"
  },
  {
    "path": "play-services-droidguard/src/main/aidl/com/google/android/gms/droidguard/internal/IDroidGuardHandle.aidl",
    "content": "package com.google.android.gms.droidguard.internal;\n\nimport com.google.android.gms.droidguard.internal.DroidGuardInitReply;\nimport com.google.android.gms.droidguard.internal.DroidGuardResultsRequest;\n\ninterface IDroidGuardHandle {\n    oneway void init(String flow) = 0;\n    byte[] snapshot(in Map map) = 1;\n    oneway void close() = 2;\n    DroidGuardInitReply initWithRequest(String flow, in DroidGuardResultsRequest request) = 4;\n}\n"
  },
  {
    "path": "play-services-droidguard/src/main/aidl/com/google/android/gms/droidguard/internal/IDroidGuardService.aidl",
    "content": "package com.google.android.gms.droidguard.internal;\n\nimport com.google.android.gms.droidguard.internal.IDroidGuardCallbacks;\nimport com.google.android.gms.droidguard.internal.IDroidGuardHandle;\nimport com.google.android.gms.droidguard.internal.DroidGuardResultsRequest;\n\ninterface IDroidGuardService {\n    void guard(IDroidGuardCallbacks callbacks, String flow, in Map map) = 0;\n    void guardWithRequest(IDroidGuardCallbacks callbacks, String flow, in Map map, in DroidGuardResultsRequest request) = 3;\n\n    IDroidGuardHandle getHandle() = 1;\n\n    int getClientTimeoutMillis() = 2;\n}\n"
  },
  {
    "path": "play-services-droidguard/src/main/java/com/google/android/gms/droidguard/DroidGuard.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.droidguard;\n\nimport android.content.Context;\n\nimport org.microg.gms.droidguard.DroidGuardClientImpl;\n\npublic class DroidGuard {\n    public static DroidGuardClient getClient(Context context) {\n        return new DroidGuardClientImpl(context);\n    }\n    public static DroidGuardClient getClient(Context context, String packageName) {\n        return new DroidGuardClientImpl(context, packageName);\n    }\n}\n"
  },
  {
    "path": "play-services-droidguard/src/main/java/com/google/android/gms/droidguard/DroidGuardClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.droidguard;\n\nimport android.content.Context;\n\nimport android.os.Bundle;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.droidguard.internal.DroidGuardResultsRequest;\nimport com.google.android.gms.tasks.Task;\n\nimport java.util.Map;\n\npublic interface DroidGuardClient {\n    @NonNull Task<DroidGuardHandle> init(@NonNull String flow, @Nullable DroidGuardResultsRequest request);\n\n    @NonNull Task<String> getResults(@NonNull String flow, @Nullable Map<String, String> data, @Nullable DroidGuardResultsRequest request);\n\n    @NonNull\n    static Task<DroidGuardHandle> init(@NonNull Context context, @NonNull String flow) {\n        return DroidGuard.getClient(context).init(flow, null);\n    }\n\n    @NonNull\n    static Task<String> getResults(@NonNull Context context, @NonNull String flow, @Nullable Map<String, String> data) {\n        return getResults(context, flow, data, (DroidGuardResultsRequest) null);\n    }\n\n    @NonNull\n    static Task<String> getResults(@NonNull Context context, @NonNull String flow, @Nullable Map<String, String> data, @Nullable Bundle extras) {\n        DroidGuardResultsRequest request = null;\n        if (extras != null) {\n            request = new DroidGuardResultsRequest();\n            request.bundle.putAll(extras);\n        }\n        return getResults(context, flow, data, request);\n    }\n\n    @NonNull\n    static Task<String> getResults(@NonNull Context context, @NonNull String flow, @Nullable Map<String, String> data, @Nullable DroidGuardResultsRequest request) {\n        return DroidGuard.getClient(context).getResults(flow, data, request);\n    }\n}\n"
  },
  {
    "path": "play-services-droidguard/src/main/java/com/google/android/gms/droidguard/DroidGuardHandle.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.droidguard;\n\nimport java.util.Map;\n\npublic interface DroidGuardHandle {\n    String snapshot(Map<String, String> data);\n\n    boolean isOpened();\n\n    void close();\n}\n"
  },
  {
    "path": "play-services-droidguard/src/main/java/com/google/android/gms/droidguard/internal/DroidGuardInitReply.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.droidguard.internal;\n\nimport android.os.Parcel;\nimport android.os.ParcelFileDescriptor;\nimport android.os.Parcelable;\n\nimport androidx.annotation.Nullable;\n\npublic class DroidGuardInitReply implements Parcelable {\n    public @Nullable ParcelFileDescriptor pfd;\n    public @Nullable Parcelable object;\n\n    public DroidGuardInitReply(@Nullable ParcelFileDescriptor pfd, @Nullable Parcelable object) {\n        this.pfd = pfd;\n        this.object = object;\n    }\n\n    @Override\n    public int describeContents() {\n        return (pfd != null ? Parcelable.CONTENTS_FILE_DESCRIPTOR : 0) | (object != null ? object.describeContents() : 0);\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        dest.writeParcelable(pfd, flags);\n        dest.writeParcelable(object, flags);\n    }\n\n    public final static Creator<DroidGuardInitReply> CREATOR = new Creator<DroidGuardInitReply>() {\n        @Override\n        public DroidGuardInitReply createFromParcel(Parcel source) {\n            ParcelFileDescriptor pfd = source.readParcelable(ParcelFileDescriptor.class.getClassLoader());\n            Parcelable object = source.readParcelable(getClass().getClassLoader());\n            if (pfd != null && object != null) {\n                return new DroidGuardInitReply(pfd, object);\n            }\n            return null;\n        }\n\n        @Override\n        public DroidGuardInitReply[] newArray(int size) {\n            return new DroidGuardInitReply[size];\n        }\n    };\n}\n"
  },
  {
    "path": "play-services-droidguard/src/main/java/com/google/android/gms/droidguard/internal/DroidGuardResultsRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.droidguard.internal;\n\nimport android.net.Network;\nimport android.os.Bundle;\nimport android.os.ParcelFileDescriptor;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.RequiresApi;\n\nimport org.microg.gms.common.Constants;\nimport org.microg.gms.utils.ToStringHelper;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class DroidGuardResultsRequest extends AutoSafeParcelable {\n    private static final String KEY_APP_ARCHITECTURE = \"appArchitecture\";\n    private static final String KEY_CLIENT_VERSION = \"clientVersion\";\n    private static final String KEY_FD = \"fd\";\n    private static final String KEY_NETWORK_TO_USE = \"networkToUse\";\n    private static final String KEY_TIMEOUT_MS = \"timeoutMs\";\n    public static final String KEY_OPEN_HANDLES = \"openHandles\";\n\n    @Field(2)\n    public Bundle bundle;\n\n    public DroidGuardResultsRequest() {\n        bundle = new Bundle();\n        String arch;\n        try {\n            arch = System.getProperty(\"os.arch\");\n        } catch (Exception ignored) {\n            arch = \"?\";\n        }\n        bundle.putString(KEY_APP_ARCHITECTURE, arch);\n        setClientVersion(Constants.GMS_VERSION_CODE);\n    }\n\n    public String getAppArchitecture() {\n        return bundle.getString(KEY_APP_ARCHITECTURE);\n    }\n\n    public int getTimeoutMillis() {\n        return bundle.getInt(KEY_TIMEOUT_MS, 60000);\n    }\n\n    public DroidGuardResultsRequest setTimeoutMillis(int millis) {\n        bundle.putInt(KEY_TIMEOUT_MS, millis);\n        return this;\n    }\n\n    public int getClientVersion() {\n        return bundle.getInt(KEY_CLIENT_VERSION);\n    }\n\n    public DroidGuardResultsRequest setClientVersion(int clientVersion) {\n        bundle.putInt(KEY_CLIENT_VERSION, clientVersion);\n        return this;\n    }\n\n    public ParcelFileDescriptor getFd() {\n        return bundle.getParcelable(KEY_FD);\n    }\n\n    public DroidGuardResultsRequest setFd(ParcelFileDescriptor fd) {\n        bundle.putParcelable(KEY_FD, fd);\n        return this;\n    }\n\n    public int getOpenHandles() {\n        return bundle.getInt(KEY_OPEN_HANDLES);\n    }\n\n    public DroidGuardResultsRequest setOpenHandles(int openHandles) {\n        bundle.putInt(KEY_OPEN_HANDLES, openHandles);\n        return this;\n    }\n\n    @RequiresApi(api = 21)\n    public Network getNetworkToUse() {\n        return bundle.getParcelable(KEY_NETWORK_TO_USE);\n    }\n\n    @RequiresApi(api = 21)\n    public DroidGuardResultsRequest setNetworkToUse(Network networkToUse) {\n        bundle.putParcelable(KEY_NETWORK_TO_USE, networkToUse);\n        return this;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        ToStringHelper helper = ToStringHelper.name(\"DroidGuardResultsRequest\");\n        for (String key : bundle.keySet()) {\n            helper.field(key, bundle.get(key));\n        }\n        return helper.end();\n    }\n\n    public static final Creator<DroidGuardResultsRequest> CREATOR = new AutoCreator<>(DroidGuardResultsRequest.class);\n}\n"
  },
  {
    "path": "play-services-droidguard/src/main/java/org/microg/gms/droidguard/DroidGuardApiClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.droidguard;\n\nimport android.content.Context;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.os.HandlerThread;\nimport android.os.IBinder;\nimport android.os.Looper;\nimport android.os.ParcelFileDescriptor;\nimport android.util.Log;\n\nimport com.google.android.gms.droidguard.DroidGuardHandle;\nimport com.google.android.gms.droidguard.internal.DroidGuardInitReply;\nimport com.google.android.gms.droidguard.internal.DroidGuardResultsRequest;\nimport com.google.android.gms.droidguard.internal.IDroidGuardHandle;\nimport com.google.android.gms.droidguard.internal.IDroidGuardService;\n\nimport org.microg.gms.common.GmsClient;\nimport org.microg.gms.common.GmsService;\nimport com.google.android.gms.common.api.internal.ConnectionCallbacks;\nimport com.google.android.gms.common.api.internal.OnConnectionFailedListener;\n\npublic class DroidGuardApiClient extends GmsClient<IDroidGuardService> {\n    private static final String TAG = \"DroidGuardApiClient\";\n    private final Context context;\n    private int openHandles = 0;\n    private Handler handler;\n    private HandleProxyFactory factory;\n\n    public DroidGuardApiClient(Context context, ConnectionCallbacks callbacks, OnConnectionFailedListener connectionFailedListener) {\n        super(context, callbacks, connectionFailedListener, GmsService.DROID_GUARD.ACTION);\n        this.context = context;\n        serviceId = GmsService.DROID_GUARD.SERVICE_ID;\n\n        HandlerThread thread = new HandlerThread(\"DG\");\n        thread.start();\n        handler = new Handler(thread.getLooper());\n\n        factory = new HandleProxyFactory(context);\n    }\n\n    public void setPackageName(String packageName) {\n        this.packageName = packageName;\n    }\n\n    public DroidGuardHandle openHandle(String flow, DroidGuardResultsRequest request) {\n        try {\n            IDroidGuardHandle handle = getServiceInterface().getHandle();\n            request.setOpenHandles(openHandles);\n            DroidGuardInitReply reply = handle.initWithRequest(flow, request);\n            if (reply == null) {\n                handle.init(flow);\n            }\n            if (reply != null) {\n                if (reply.pfd != null && reply.object != null) {\n                    Log.w(TAG, \"DroidGuardInitReply suggests additional actions in main thread\");\n                    Bundle bundle = (Bundle) reply.object;\n                    if (bundle != null) {\n                        for (String key : bundle.keySet()) {\n                            Log.d(TAG, \"reply.object[\" + key + \"] = \" + bundle.get(key));\n                        }\n                        handleDroidGuardData(reply.pfd, (Bundle) reply.object);\n                    }\n                }\n            }\n            openHandles++;\n            return new DroidGuardHandleImpl(this, request, handle);\n        } catch (Exception e) {\n            return new DroidGuardHandleImpl(this, request, \"Initialization failed: \" + e);\n        }\n    }\n\n    private void handleDroidGuardData(ParcelFileDescriptor pfd, Bundle bundle) {\n        String vmKey = bundle.getString(\"h\");\n        if (vmKey == null) {\n            throw new RuntimeException(\"Missing vmKey\");\n        }\n        HandleProxy proxy = factory.createHandle(vmKey, pfd, bundle);\n        proxy.init();\n        proxy.close();\n    }\n\n    public void markHandleClosed() {\n        if (openHandles == 0) {\n            Log.w(TAG, \"Can't mark handle closed if none is open\");\n            return;\n        }\n        openHandles--;\n        if (openHandles == 0) disconnect();\n    }\n\n    public void runOnHandler(Runnable runnable) {\n        if (Looper.myLooper() == handler.getLooper()) {\n            runnable.run();\n        } else {\n            handler.post(runnable);\n        }\n    }\n\n    @Override\n    protected IDroidGuardService interfaceFromBinder(IBinder binder) {\n        return IDroidGuardService.Stub.asInterface(binder);\n    }\n}\n"
  },
  {
    "path": "play-services-droidguard/src/main/java/org/microg/gms/droidguard/DroidGuardClientImpl.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.droidguard;\n\nimport android.content.Context;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.GoogleApi;\nimport com.google.android.gms.droidguard.DroidGuardClient;\nimport com.google.android.gms.droidguard.DroidGuardHandle;\nimport com.google.android.gms.droidguard.internal.DroidGuardResultsRequest;\nimport com.google.android.gms.tasks.Task;\n\nimport org.microg.gms.common.api.ReturningGoogleApiCall;\n\nimport java.util.Map;\n\npublic class DroidGuardClientImpl extends GoogleApi<DroidGuardClientImpl.Options> implements DroidGuardClient {\n    private static final Api<Options> API = new Api<>((options, context, looper, clientSettings, callbacks, connectionFailedListener) -> {\n        DroidGuardApiClient client = new DroidGuardApiClient(context, callbacks, connectionFailedListener);\n        if (options != null && options.packageName != null) client.setPackageName(options.packageName);\n        return client;\n    });\n\n    public DroidGuardClientImpl(Context context) {\n        super(context, API, new Options(context.getPackageName()));\n    }\n    public DroidGuardClientImpl(Context context, String packageName) {\n        super(context, API, new Options(packageName));\n    }\n\n    @Override\n    @NonNull\n    public Task<DroidGuardHandle> init(@NonNull String flow, @Nullable DroidGuardResultsRequest request) {\n        DroidGuardResultsRequest finalRequest = request != null ? request : new DroidGuardResultsRequest();\n        return scheduleTask((ReturningGoogleApiCall<DroidGuardHandle, DroidGuardApiClient>) client -> client.openHandle(flow, finalRequest));\n    }\n\n    @Override\n    @NonNull\n    public Task<String> getResults(@NonNull String flow, @Nullable Map<String, String> data, @Nullable DroidGuardResultsRequest request) {\n        DroidGuardResultsRequest finalRequest = request != null ? request : new DroidGuardResultsRequest();\n        return scheduleTask((ReturningGoogleApiCall<String, DroidGuardApiClient>) client -> {\n            DroidGuardHandle handle = client.openHandle(flow, finalRequest);\n            String results = handle.snapshot(data);\n            handle.close();\n            return results;\n        });\n    }\n\n    public static class Options implements Api.ApiOptions.Optional {\n        public final String packageName;\n\n        public Options(String packageName) {\n            this.packageName = packageName;\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-droidguard/src/main/java/org/microg/gms/droidguard/DroidGuardHandleImpl.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.droidguard;\n\nimport android.util.Log;\n\nimport com.google.android.gms.droidguard.DroidGuardHandle;\nimport com.google.android.gms.droidguard.internal.DroidGuardResultsRequest;\nimport com.google.android.gms.droidguard.internal.IDroidGuardHandle;\n\nimport java.util.Map;\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.TimeUnit;\n\npublic class DroidGuardHandleImpl implements DroidGuardHandle {\n    private static final String TAG = \"DroidGuardHandle\";\n    private final DroidGuardApiClient apiClient;\n    private final DroidGuardResultsRequest request;\n    private IDroidGuardHandle handle;\n    private byte[] error;\n\n    public DroidGuardHandleImpl(DroidGuardApiClient apiClient, DroidGuardResultsRequest request, IDroidGuardHandle handle) {\n        this.apiClient = apiClient;\n        this.request = request;\n        this.handle = handle;\n    }\n\n    public DroidGuardHandleImpl(DroidGuardApiClient apiClient, DroidGuardResultsRequest request, String error) {\n        this.apiClient = apiClient;\n        this.request = request;\n        this.error = Utils.getErrorBytes(error);\n    }\n\n    @Override\n    public String snapshot(Map<String, String> data) {\n        byte[] result;\n        if (error != null) {\n            result = error;\n        } else {\n            ArrayBlockingQueue<byte[]> resultQueue = new ArrayBlockingQueue<>(1);\n            apiClient.runOnHandler(() -> {\n                byte[] innerResult;\n                try {\n                    innerResult = handle.snapshot(data);\n                    if (innerResult == null) {\n                        error = Utils.getErrorBytes(\"Received null\");\n                        innerResult = error;\n                    }\n                } catch (Exception e) {\n                    error = Utils.getErrorBytes(\"Snapshot failed: \" + e);\n                    innerResult = error;\n                }\n                resultQueue.offer(innerResult);\n            });\n            try {\n                result = resultQueue.poll(request.getTimeoutMillis(), TimeUnit.MILLISECONDS);\n                if (result == null) {\n                    result = Utils.getErrorBytes(\"Snapshot timeout: \" + request.getTimeoutMillis() + \" ms\");\n                }\n            } catch (InterruptedException e) {\n                result = Utils.getErrorBytes(\"Results transfer failed: \" + e);\n            }\n        }\n        return Utils.toBase64(result);\n    }\n\n    @Override\n    public boolean isOpened() {\n        return handle != null && error == null && handle.asBinder().pingBinder();\n    }\n\n    @Override\n    public void close() {\n        apiClient.runOnHandler(() -> {\n            if (handle != null) {\n                try {\n                    handle.close();\n                } catch (Exception e) {\n                    Log.w(TAG, \"Error while closing handle.\");\n                }\n                apiClient.markHandleClosed();\n                handle = null;\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "play-services-droidguard/src/main/java/org/microg/gms/droidguard/Utils.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.droidguard;\n\nimport android.util.Base64;\n\npublic class Utils {\n    public static byte[] getErrorBytes(String s) {\n        return (\"ERROR : \" + s).getBytes();\n    }\n\n    public static String toBase64(byte[] result) {\n        return Base64.encodeToString(result, Base64.URL_SAFE + Base64.NO_WRAP + Base64.NO_PADDING);\n    }\n}\n"
  },
  {
    "path": "play-services-droidguard/src/main/kotlin/org/microg/gms/droidguard/BytesException.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.droidguard\n\nclass BytesException : Exception {\n    val bytes: ByteArray\n\n    constructor(bytes: ByteArray, message: String) : super(message) {\n        this.bytes = bytes\n    }\n\n    constructor(bytes: ByteArray, cause: Throwable) : super(cause) {\n        this.bytes = bytes\n    }\n\n    constructor(bytes: ByteArray, message: String, cause: Throwable) : super(message, cause) {\n        this.bytes = bytes\n    }\n}\n"
  },
  {
    "path": "play-services-droidguard/src/main/kotlin/org/microg/gms/droidguard/HandleProxy.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.droidguard\n\nimport android.content.Context\nimport android.os.Bundle\nimport android.os.Parcelable\n\nclass HandleProxy(val handle: Any, val vmKey: String, val extra: ByteArray = ByteArray(0)) {\n    constructor(clazz: Class<*>, context: Context, vmKey: String, data: Parcelable) : this(\n        kotlin.runCatching {\n            clazz.getDeclaredConstructor(Context::class.java, Parcelable::class.java).newInstance(context, data)\n        }.getOrElse {\n            throw BytesException(ByteArray(0), it)\n        },\n        vmKey\n    )\n\n    constructor(clazz: Class<*>, context: Context, flow: String?, byteCode: ByteArray, callback: Any, vmKey: String, extra: ByteArray, bundle: Bundle?) : this(\n        kotlin.runCatching {\n            clazz.getDeclaredConstructor(Context::class.java, String::class.java, ByteArray::class.java, Object::class.java, Bundle::class.java).newInstance(context, flow, byteCode, callback, bundle)\n        }.getOrElse {\n            throw BytesException(extra, it)\n        }, vmKey, extra)\n\n    fun run(data: Map<Any, Any>): ByteArray {\n        try {\n            return handle.javaClass.getDeclaredMethod(\"run\", Map::class.java).invoke(handle, data) as ByteArray\n        } catch (e: Exception) {\n            throw BytesException(extra, e)\n        }\n    }\n\n    fun init(): Boolean {\n        try {\n            return handle.javaClass.getDeclaredMethod(\"init\").invoke(handle) as Boolean\n        } catch (e: Exception) {\n            throw BytesException(extra, e)\n        }\n    }\n\n    fun close() {\n        try {\n            handle.javaClass.getDeclaredMethod(\"close\").invoke(handle)\n        } catch (e: Exception) {\n            throw BytesException(extra, e)\n        }\n    }\n\n}\n"
  },
  {
    "path": "play-services-droidguard/src/main/kotlin/org/microg/gms/droidguard/HandleProxyFactory.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2021 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.droidguard\n\nimport android.content.Context\nimport android.os.Bundle\nimport android.os.ParcelFileDescriptor\nimport android.os.Parcelable\nimport androidx.annotation.GuardedBy\nimport dalvik.system.DexClassLoader\nimport java.io.File\nimport java.io.IOException\nimport java.security.MessageDigest\nimport java.security.cert.Certificate\nimport java.util.*\n\nopen class HandleProxyFactory(private val context: Context) {\n    @GuardedBy(\"CLASS_LOCK\")\n    protected val classMap = hashMapOf<String, Class<*>>()\n\n    fun createHandle(vmKey: String, pfd: ParcelFileDescriptor, extras: Bundle): HandleProxy {\n        fetchFromFileDescriptor(pfd, vmKey)\n        return createHandleProxy(vmKey, extras)\n    }\n\n    private fun fetchFromFileDescriptor(pfd: ParcelFileDescriptor, vmKey: String) {\n        if (!isValidCache(vmKey)) {\n            val auIs = ParcelFileDescriptor.AutoCloseInputStream(pfd)\n            val temp = File(getCacheDir(), \"${UUID.randomUUID()}.apk\")\n            temp.parentFile!!.mkdirs()\n            temp.writeBytes(auIs.readBytes())\n            auIs.close()\n            getOptDir(vmKey).mkdirs()\n            temp.renameTo(getTheApkFile(vmKey))\n            updateCacheTimestamp(vmKey)\n            if (!isValidCache(vmKey)) {\n                getCacheDir(vmKey).deleteRecursively()\n                throw IllegalStateException(\"Error \")\n            }\n        }\n    }\n\n    private fun createHandleProxy(\n        vmKey: String,\n        extras: Parcelable\n    ): HandleProxy {\n        val clazz = loadClass(vmKey)\n        return HandleProxy(clazz, context, vmKey, extras)\n    }\n\n    fun getTheApkFile(vmKey: String) = File(getCacheDir(vmKey), \"the.apk\")\n    protected fun getCacheDir() = context.getDir(CACHE_FOLDER_NAME, Context.MODE_PRIVATE)\n    protected fun getCacheDir(vmKey: String) = File(getCacheDir(), vmKey)\n    protected fun getOptDir(vmKey: String) = File(getCacheDir(vmKey), \"opt\")\n    protected fun isValidCache(vmKey: String) = getTheApkFile(vmKey).isFile && getOptDir(vmKey).isDirectory\n\n    protected fun updateCacheTimestamp(vmKey: String) {\n        try {\n            val timestampFile = File(getCacheDir(vmKey), \"t\")\n            if (!timestampFile.exists() && !timestampFile.createNewFile()) {\n                throw Exception(\"Failed to touch last-used file for $vmKey.\")\n            }\n            if (!timestampFile.setLastModified(System.currentTimeMillis())) {\n                throw Exception(\"Failed to update last-used timestamp for $vmKey.\")\n            }\n        } catch (e: IOException) {\n            throw Exception(\"Failed to touch last-used file for $vmKey.\")\n        }\n    }\n\n    private fun verifyApkSignature(apk: File): Boolean {\n        return true\n        val certificates: Array<Certificate> = TODO()\n        if (certificates.size != 1) return false\n        return Arrays.equals(MessageDigest.getInstance(\"SHA-256\").digest(certificates[0].encoded), PROD_CERT_HASH)\n    }\n\n    protected fun loadClass(vmKey: String, bytes: ByteArray = ByteArray(0)): Class<*> {\n        synchronized(CLASS_LOCK) {\n            val cachedClass = classMap[vmKey]\n            if (cachedClass != null) {\n                updateCacheTimestamp(vmKey)\n                return cachedClass\n            }\n            val weakClass = weakClassMap[vmKey]\n            if (weakClass != null) {\n                classMap[vmKey] = weakClass\n                updateCacheTimestamp(vmKey)\n                return weakClass\n            }\n            if (!isValidCache(vmKey)) {\n                throw BytesException(bytes, \"VM key $vmKey not found in cache\")\n            }\n            if (!verifyApkSignature(getTheApkFile(vmKey))) {\n                getCacheDir(vmKey).deleteRecursively()\n                throw ClassNotFoundException(\"APK signature verification failed\")\n            }\n            val loader = DexClassLoader(getTheApkFile(vmKey).absolutePath, getOptDir(vmKey).absolutePath, null, context.classLoader)\n            val clazz = loader.loadClass(CLASS_NAME)\n            classMap[vmKey] = clazz\n            weakClassMap[vmKey] = clazz\n            return clazz\n        }\n    }\n\n    companion object {\n        const val CLASS_NAME = \"com.google.ccc.abuse.droidguard.DroidGuard\"\n        const val CACHE_FOLDER_NAME = \"cache_dg\"\n        val CLASS_LOCK = Object()\n        @GuardedBy(\"CLASS_LOCK\")\n        val weakClassMap = WeakHashMap<String, Class<*>>()\n        val PROD_CERT_HASH = byteArrayOf(61, 122, 18, 35, 1, -102, -93, -99, -98, -96, -29, 67, 106, -73, -64, -119, 107, -5, 79, -74, 121, -12, -34, 95, -25, -62, 63, 50, 108, -113, -103, 74)\n    }\n}\n"
  },
  {
    "path": "play-services-fido/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\nandroid {\n    namespace \"com.google.android.gms.fido\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n}\n\napply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG implementation of play-services-fido'\n\ndependencies {\n    // Dependencies from play-services-fido:18.1.0\n    api project(':play-services-base')\n    api project(':play-services-basement')\n    api project(':play-services-tasks')\n\n    annotationProcessor project(':safe-parcel-processor')\n}\n"
  },
  {
    "path": "play-services-fido/core/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'kotlin-android'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\ndependencies {\n    api project(':play-services-fido')\n\n    implementation project(':play-services-base-core')\n    implementation project(':play-services-safetynet')\n    implementation project(':play-services-tasks-ktx')\n\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion\"\n    implementation \"org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutineVersion\"\n    implementation \"org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutineVersion\"\n\n    implementation \"androidx.appcompat:appcompat:$appcompatVersion\"\n    implementation \"androidx.biometric:biometric:$biometricVersion\"\n    implementation \"androidx.core:core-ktx:$coreVersion\"\n    implementation \"androidx.lifecycle:lifecycle-runtime-ktx:$lifecycleVersion\"\n    implementation \"androidx.lifecycle:lifecycle-service:$lifecycleVersion\"\n\n    // Navigation\n    implementation \"androidx.navigation:navigation-fragment-ktx:$navigationVersion\"\n    implementation \"androidx.navigation:navigation-ui-ktx:$navigationVersion\"\n\n    implementation \"com.android.volley:volley:$volleyVersion\"\n    implementation 'com.upokecenter:cbor:4.5.2'\n    implementation 'com.google.guava:guava:31.1-android'\n}\n\nandroid {\n    namespace \"org.microg.gms.fido.core\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    buildFeatures {\n        dataBinding = true\n    }\n\n    sourceSets {\n        main.java.srcDirs += 'src/main/kotlin'\n    }\n\n    lintOptions {\n        disable 'MissingTranslation', 'GetLocales'\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n\n    kotlinOptions {\n        jvmTarget = 1.8\n    }\n}\n\napply from: '../../gradle/publish-android.gradle'\n\ndescription = 'microG service implementation for play-services-fido'\n"
  },
  {
    "path": "play-services-fido/core/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <uses-permission android:name=\"android.permission.USE_BIOMETRIC\" />\n    <uses-permission android:name=\"android.permission.USE_FINGERPRINT\" />\n    <uses-permission android:name=\"android.permission.NFC\" />\n    <uses-permission\n        android:name=\"android.permission.MANAGE_USB\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission android:name=\"android.permission.START_ACTIVITIES_FROM_BACKGROUND\"\n        tools:ignore=\"ProtectedPermissions\" />\n\n    <application>\n        <service\n            android:name=\".privileged.Fido2PrivilegedService\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.fido.fido2.privileged.START\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </service>\n        <service\n            android:name=\".regular.Fido2AppService\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.fido.fido2.regular.START\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </service>\n        <activity\n            android:name=\".ui.AuthenticatorActivity\"\n            android:configChanges=\"orientation|keyboard|keyboardHidden|screenSize\"\n            android:exported=\"false\"\n            android:process=\":ui\"\n            android:theme=\"@style/Theme.Translucent\">\n            <intent-filter>\n                <action android:name=\"org.microg.gms.fido.AUTHENTICATE\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </activity>\n    </application>\n</manifest>\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/Database.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core\n\nimport android.content.ContentValues\nimport android.content.Context\nimport android.database.sqlite.SQLiteDatabase\nimport android.database.sqlite.SQLiteDatabase.CONFLICT_REPLACE\nimport android.database.sqlite.SQLiteOpenHelper\nimport android.util.Log\nimport androidx.core.database.getLongOrNull\nimport androidx.core.database.getStringOrNull\nimport org.microg.gms.fido.core.transport.Transport\nimport org.microg.gms.fido.core.ui.TAG\n\nclass Database(context: Context) : SQLiteOpenHelper(context, \"fido.db\", null, VERSION) {\n\n    fun isPrivileged(packageName: String, signatureDigest: String): Boolean = readableDatabase.use {\n        it.count(TABLE_PRIVILEGED_APPS, \"$COLUMN_PACKAGE_NAME = ? AND $COLUMN_SIGNATURE_DIGEST = ?\", packageName, signatureDigest) > 0\n    }\n\n    fun wasUsed(): Boolean = readableDatabase.use { it.count(TABLE_KNOWN_REGISTRATIONS) > 0 }\n\n    fun getKnownRegistrationTransport(rpId: String, credentialId: String) = readableDatabase.use {\n        val c = it.query(TABLE_KNOWN_REGISTRATIONS, arrayOf(COLUMN_TRANSPORT), \"$COLUMN_RP_ID = ? AND $COLUMN_CREDENTIAL_ID = ?\", arrayOf(rpId, credentialId), null, null, null)\n        try {\n            if (c.moveToFirst()) Transport.valueOf(c.getString(0)) else null\n        } finally {\n            c.close()\n        }\n    }\n\n    fun getKnownRegistrationInfo(rpId: String) = readableDatabase.use {\n        val cursor = it.query(\n            TABLE_KNOWN_REGISTRATIONS, arrayOf(COLUMN_CREDENTIAL_ID, COLUMN_REGISTER_USER, COLUMN_TRANSPORT), \"$COLUMN_RP_ID=?\", arrayOf(rpId), null, null, null\n        )\n        val result = mutableListOf<CredentialUserInfo>()\n        cursor.use { c ->\n            while (c.moveToNext()) {\n                val credentialId = c.getString(0)\n                val userJson = c.getStringOrNull(1) ?: continue\n                val transport = c.getStringOrNull(2) ?: continue\n                Log.d(TAG, \"getKnownRegistrationInfo: credential: $credentialId user: $userJson transport: $transport\")\n                result.add(CredentialUserInfo(credentialId, userJson, Transport.valueOf(transport)))\n            }\n        }\n        result\n    }\n\n    fun insertPrivileged(packageName: String, signatureDigest: String) = writableDatabase.use {\n        it.insertWithOnConflict(TABLE_PRIVILEGED_APPS, null, ContentValues().apply {\n            put(COLUMN_PACKAGE_NAME, packageName)\n            put(COLUMN_SIGNATURE_DIGEST, signatureDigest)\n            put(COLUMN_TIMESTAMP, System.currentTimeMillis())\n        }, CONFLICT_REPLACE)\n    }\n\n    fun insertKnownRegistration(rpId: String, credentialId: String, transport: Transport, userJson: String? = null) = writableDatabase.use {\n        Log.d(TAG, \"insertKnownRegistration: $rpId $credentialId $transport $userJson\")\n        val values = ContentValues().apply {\n            put(COLUMN_CREDENTIAL_ID, credentialId)\n            put(COLUMN_TRANSPORT, transport.name)\n            put(COLUMN_TIMESTAMP, System.currentTimeMillis())\n            if (userJson != null) {\n                put(COLUMN_REGISTER_USER, userJson)\n            }\n        }\n\n        val updated = if (userJson == null) {\n            it.update(TABLE_KNOWN_REGISTRATIONS, values, \"$COLUMN_RP_ID = ? AND $COLUMN_CREDENTIAL_ID = ?\", arrayOf(rpId, credentialId))\n        } else {\n            it.update(TABLE_KNOWN_REGISTRATIONS, values, \"$COLUMN_RP_ID = ? AND $COLUMN_REGISTER_USER = ?\", arrayOf(rpId, userJson))\n        }\n\n        if (updated == 0) {\n            val insertValues = ContentValues().apply {\n                put(COLUMN_RP_ID, rpId)\n                put(COLUMN_CREDENTIAL_ID, credentialId)\n                put(COLUMN_TRANSPORT, transport.name)\n                put(COLUMN_TIMESTAMP, System.currentTimeMillis())\n                userJson?.let { json -> put(COLUMN_REGISTER_USER, json) }\n            }\n            it.insert(TABLE_KNOWN_REGISTRATIONS, null, insertValues)\n        }\n    }\n\n    override fun onCreate(db: SQLiteDatabase) {\n        onUpgrade(db, 0, VERSION)\n    }\n\n    override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {\n        if (oldVersion < 1) {\n            db.execSQL(\"CREATE TABLE $TABLE_PRIVILEGED_APPS($COLUMN_PACKAGE_NAME TEXT, $COLUMN_SIGNATURE_DIGEST TEXT, $COLUMN_TIMESTAMP INT, UNIQUE($COLUMN_PACKAGE_NAME, $COLUMN_SIGNATURE_DIGEST) ON CONFLICT REPLACE);\")\n        }\n        if (oldVersion < 2) {\n            db.execSQL(\"CREATE TABLE $TABLE_KNOWN_REGISTRATIONS($COLUMN_RP_ID TEXT, $COLUMN_CREDENTIAL_ID TEXT, $COLUMN_TRANSPORT TEXT, $COLUMN_TIMESTAMP INT, UNIQUE($COLUMN_RP_ID, $COLUMN_CREDENTIAL_ID) ON CONFLICT REPLACE)\")\n        }\n        if (oldVersion < 3) {\n            db.execSQL(\"ALTER TABLE $TABLE_KNOWN_REGISTRATIONS ADD COLUMN $COLUMN_REGISTER_USER TEXT\")\n        }\n    }\n\n    companion object {\n        const val VERSION = 3\n        private const val TABLE_PRIVILEGED_APPS = \"privileged_apps\"\n        private const val TABLE_KNOWN_REGISTRATIONS = \"known_registrations\"\n        private const val COLUMN_PACKAGE_NAME = \"package_name\"\n        private const val COLUMN_SIGNATURE_DIGEST = \"signature_digest\"\n        private const val COLUMN_TIMESTAMP = \"timestamp\"\n        private const val COLUMN_RP_ID = \"rp_id\"\n        private const val COLUMN_CREDENTIAL_ID = \"credential_id\"\n        private const val COLUMN_TRANSPORT = \"transport\"\n        private const val COLUMN_REGISTER_USER = \"register_user\"\n    }\n}\n\nfun SQLiteDatabase.count(table: String, selection: String? = null, vararg selectionArgs: String): Long {\n    val it = if (selection == null) {\n        rawQuery(\"SELECT COUNT(*) FROM $table\", null)\n    } else {\n        rawQuery(\"SELECT COUNT(*) FROM $table WHERE $selection\", selectionArgs)\n    }\n    return try {\n        if (it.moveToFirst()) {\n            it.getLongOrNull(0) ?: 0\n        } else {\n            0\n        }\n    } finally {\n        it.close()\n    }\n}"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/RequestHandling.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core\n\nimport android.content.Context\nimport android.net.Uri\nimport android.util.Base64\nimport android.util.Log\nimport com.android.volley.toolbox.JsonArrayRequest\nimport com.android.volley.toolbox.JsonObjectRequest\nimport com.android.volley.toolbox.Volley\nimport com.google.android.gms.fido.fido2.api.common.*\nimport com.google.android.gms.fido.fido2.api.common.ErrorCode.*\nimport com.google.common.net.InternetDomainName\nimport kotlinx.coroutines.CompletableDeferred\nimport org.json.JSONArray\nimport org.json.JSONObject\nimport org.microg.gms.fido.core.RequestOptionsType.REGISTER\nimport org.microg.gms.fido.core.RequestOptionsType.SIGN\nimport org.microg.gms.fido.core.transport.Transport\nimport org.microg.gms.utils.*\nimport java.net.HttpURLConnection\nimport java.security.MessageDigest\n\nprivate const val TAG = \"Fido\"\n\nclass RequestHandlingException(val errorCode: ErrorCode, message: String? = null) : Exception(message)\nclass MissingPinException(message: String? = null): Exception(message)\nclass WrongPinException(message: String? = null): Exception(message)\n\ndata class CredentialUserInfo(val credential: String, val userJson: String, val transport: Transport)\nenum class RequestOptionsType { REGISTER, SIGN }\n\nval RequestOptions.registerOptions: PublicKeyCredentialCreationOptions\n    get() = when (this) {\n        is BrowserPublicKeyCredentialCreationOptions -> publicKeyCredentialCreationOptions\n        is PublicKeyCredentialCreationOptions -> this\n        else -> throw RequestHandlingException(DATA_ERR, \"The request options are not valid\")\n    }\n\nval RequestOptions.signOptions: PublicKeyCredentialRequestOptions\n    get() = when (this) {\n        is BrowserPublicKeyCredentialRequestOptions -> publicKeyCredentialRequestOptions\n        is PublicKeyCredentialRequestOptions -> this\n        else -> throw RequestHandlingException(DATA_ERR, \"The request options are not valid\")\n    }\n\nval RequestOptions.type: RequestOptionsType\n    get() = when (this) {\n        is PublicKeyCredentialCreationOptions, is BrowserPublicKeyCredentialCreationOptions -> REGISTER\n        is PublicKeyCredentialRequestOptions, is BrowserPublicKeyCredentialRequestOptions -> SIGN\n        else -> throw RequestHandlingException(INVALID_STATE_ERR)\n    }\n\nval RequestOptions.webAuthnType: String\n    get() = when (type) {\n        REGISTER -> \"webauthn.create\"\n        SIGN -> \"webauthn.get\"\n    }\n\nval RequestOptions.challenge: ByteArray\n    get() = when (type) {\n        REGISTER -> registerOptions.challenge\n        SIGN -> signOptions.challenge\n    }\n\nval RequestOptions.rpId: String\n    get() = when (type) {\n        REGISTER -> registerOptions.rp.id\n        SIGN -> signOptions.rpId\n    }\n\nval RequestOptions.user: String?\n    get() = when (type) {\n        REGISTER -> registerOptions.user.toJson()\n        SIGN -> null\n    }\n\nval PublicKeyCredentialCreationOptions.skipAttestation: Boolean\n    get() = attestationConveyancePreference in setOf(AttestationConveyancePreference.NONE, null)\n\nfun topDomainOf(string: String?) =\n    string?.let { InternetDomainName.from(string).topDomainUnderRegistrySuffix().toString() }\n\nfun <T> JSONArray.map(fn: JSONArray.(Int) -> T): List<T> = (0 until length()).map { fn(this, it) }\n\nprivate suspend fun isFacetIdTrusted(context: Context, facetIds: Set<String>, appId: String): Boolean {\n    val trustedFacets = try {\n        val deferred = CompletableDeferred<JSONObject>()\n        HttpURLConnection.setFollowRedirects(false)\n        singleInstanceOf { Volley.newRequestQueue(context.applicationContext) }\n            .add(JsonObjectRequest(appId, { deferred.complete(it) }, { deferred.completeExceptionally(it) }))\n        val obj = deferred.await()\n        val arr = obj.getJSONArray(\"trustedFacets\")\n        if (arr.length() > 1) {\n            // Unsupported\n            emptyList()\n        } else {\n            arr.getJSONObject(0).getJSONArray(\"ids\").map(JSONArray::getString)\n        }\n    } catch (e: Exception) {\n        // Ignore and fail\n        emptyList()\n    }\n    return facetIds.any { trustedFacets.contains(it) }\n}\n\nprivate const val ASSET_LINK_REL = \"delegate_permission/common.get_login_creds\"\nprivate suspend fun isAssetLinked(context: Context, rpId: String, fp: String, packageName: String?): Boolean {\n    try {\n        val deferred = CompletableDeferred<JSONArray>()\n        HttpURLConnection.setFollowRedirects(true)\n        val url = \"https://$rpId/.well-known/assetlinks.json\"\n        singleInstanceOf { Volley.newRequestQueue(context.applicationContext) }\n            .add(JsonArrayRequest(url, { deferred.complete(it) }, { deferred.completeExceptionally(it) }))\n        val arr = deferred.await()\n        for (obj in arr.map(JSONArray::getJSONObject)) {\n            if (!obj.getJSONArray(\"relation\").map(JSONArray::getString).contains(ASSET_LINK_REL)) continue\n            val target = obj.getJSONObject(\"target\")\n            if (target.getString(\"namespace\") != \"android_app\") continue\n            if (packageName != null && target.getString(\"package_name\") != packageName) continue\n            for (fingerprint in target.getJSONArray(\"sha256_cert_fingerprints\").map(JSONArray::getString)) {\n                if (fingerprint.equals(fp, ignoreCase = true)) return true\n            }\n        }\n        Log.w(TAG, \"No matching asset link\")\n        return false\n    } catch (e: Exception) {\n        Log.w(TAG, \"Failed fetching asset link\", e)\n        return false\n    }\n}\n\n// Note: This assumes the RP ID is allowed\nprivate suspend fun isAppIdAllowed(context: Context, appId: String, facetIds: Set<String>, rpId: String): Boolean {\n    return try {\n        when {\n            topDomainOf(Uri.parse(appId).host) == topDomainOf(rpId) -> {\n                // Valid: AppId TLD+1 matches RP ID\n                true\n            }\n            topDomainOf(Uri.parse(appId).host) == \"gstatic.com\" && rpId == \"google.com\" -> {\n                // Valid: Hardcoded support for Google putting their app id under gstatic.com.\n                // This is gonna save us a ton of requests\n                true\n            }\n            isFacetIdTrusted(context, facetIds, appId) -> {\n                // Valid: Allowed by TrustedFacets list\n                true\n            }\n            else -> {\n                false\n            }\n        }\n    } catch (e: Exception) {\n        false\n    }\n}\n\nsuspend fun RequestOptions.checkIsValid(context: Context, origin: String, packageName: String?) {\n    val allApplicableFacetIds = hashSetOf<String>()\n    if (origin.startsWith(\"https://\")) {\n        allApplicableFacetIds.add(origin)\n        if (topDomainOf(Uri.parse(origin).host) != topDomainOf(rpId)) {\n            throw RequestHandlingException(NOT_ALLOWED_ERR, \"RP ID $rpId not allowed from origin $origin\")\n        }\n        // FIXME: Standard suggests doing additional checks, but this is already sensible enough\n    } else if ((origin.startsWith(\"android:apk-key-hash:\") || origin.startsWith(\"android:apk-key-hash-sha256:\")) && packageName != null) {\n        allApplicableFacetIds.addAll(getAllFacetIdCandidates(context, packageName, origin))\n        val sha256facetId = allApplicableFacetIds.firstOrNull { it.startsWith(\"android:apk-key-hash-sha256:\") }\n            ?: throw RequestHandlingException(NOT_ALLOWED_ERR, \"RP ID $rpId not allowed from origin $origin\")\n        val fp = Base64.decode(sha256facetId.substring(28), HASH_BASE64_FLAGS).toHexString(\":\")\n        if (!isAssetLinked(context, rpId, fp, packageName)) {\n            throw RequestHandlingException(NOT_ALLOWED_ERR, \"RP ID $rpId not allowed from origin $origin (expected fingerprint $fp)\")\n        }\n    } else {\n        throw RequestHandlingException(NOT_SUPPORTED_ERR, \"Origin $origin not supported\")\n    }\n    val appId = authenticationExtensions?.fidoAppIdExtension?.appId\n    if (appId != null) {\n        if (!appId.startsWith(\"https://\")) {\n            throw RequestHandlingException(NOT_ALLOWED_ERR, \"AppId $appId must start with https://\")\n        }\n        if (Uri.parse(appId).host.isNullOrEmpty()) {\n            throw RequestHandlingException(NOT_ALLOWED_ERR, \"AppId $appId must have a valid hostname\")\n        }\n        if (!isAppIdAllowed(context, appId, allApplicableFacetIds, rpId)) {\n            throw RequestHandlingException(NOT_ALLOWED_ERR, \"AppId $appId not allowed from facets [${allApplicableFacetIds.joinToString()}]\")\n        }\n    }\n}\n\nprivate const val HASH_BASE64_FLAGS = Base64.NO_PADDING + Base64.NO_WRAP + Base64.URL_SAFE\n\nfun RequestOptions.getWebAuthnClientData(callingPackage: String, origin: String): ByteArray {\n    val obj = JSONObject()\n        .put(\"type\", webAuthnType)\n        .put(\"challenge\", challenge.toBase64(HASH_BASE64_FLAGS))\n        .put(\"androidPackageName\", callingPackage)\n        .put(\"tokenBinding\", tokenBinding?.toJsonObject())\n        .put(\"origin\", origin)\n    return obj.toString().encodeToByteArray()\n}\n\nfun getApplicationName(context: Context, options: RequestOptions, callingPackage: String): String = when (options) {\n    is BrowserPublicKeyCredentialCreationOptions, is BrowserPublicKeyCredentialRequestOptions -> options.rpId\n    else -> context.packageManager.getApplicationLabel(callingPackage).toString()\n}\n\nfun getApkKeyHashOrigin(context: Context, packageName: String): String {\n    val digest = context.packageManager.getFirstSignatureDigest(packageName, \"SHA-256\")\n        ?: throw RequestHandlingException(NOT_ALLOWED_ERR, \"Unknown package $packageName\")\n    return \"android:apk-key-hash:${digest.toBase64(HASH_BASE64_FLAGS)}\"\n}\n\nfun getAllFacetIdCandidates(context: Context, packageName: String, origin: String): List<String> {\n    val firstSignature = context.packageManager.getSignatures(packageName).firstOrNull()\n        ?: throw RequestHandlingException(NOT_ALLOWED_ERR, \"Unknown package $packageName\")\n    val sha1 = firstSignature.digest(\"SHA1\").toBase64(HASH_BASE64_FLAGS)\n    val sha256 = firstSignature.digest(\"SHA-256\").toBase64(HASH_BASE64_FLAGS)\n    val candidates = arrayListOf(\n        \"android:apk-key-hash:$sha1\",\n        \"android:apk-key-hash:$sha256\",\n        \"android:apk-key-hash-sha256:$sha256\",\n    )\n    if (!candidates.contains(origin))\n        throw RequestHandlingException(NOT_ALLOWED_ERR, \"Unknown package $packageName ($origin)\")\n    return candidates\n}\n\nfun getOrigin(context: Context, options: RequestOptions, callingPackage: String): String = when {\n    options is BrowserRequestOptions -> {\n        if (options.origin.scheme == null || options.origin.authority == null) {\n            throw RequestHandlingException(NOT_ALLOWED_ERR, \"Bad url ${options.origin}\")\n        }\n        \"${options.origin.scheme}://${options.origin.authority}\"\n    }\n    else -> getApkKeyHashOrigin(context, callingPackage)\n}\n\nfun ByteArray.digest(md: String): ByteArray = MessageDigest.getInstance(md).digest(this)\n\nfun getClientDataAndHash(\n    context: Context,\n    options: RequestOptions,\n    callingPackage: String\n): Pair<ByteArray, ByteArray> {\n    val clientData: ByteArray?\n    var clientDataHash = (options as? BrowserRequestOptions)?.clientDataHash\n    if (clientDataHash == null) {\n        clientData = options.getWebAuthnClientData(callingPackage, getOrigin(context, options, callingPackage))\n        clientDataHash = clientData.digest(\"SHA-256\")\n    } else {\n        clientData = \"<invalid>\".toByteArray()\n    }\n    return clientData to clientDataHash\n}\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/features.kt",
    "content": "package org.microg.gms.fido.core\n\nimport com.google.android.gms.common.Feature\n\nval FEATURES = arrayOf(\n    Feature(\"cancel_target_direct_transfer\", 1),\n    Feature(\"delete_credential\", 1),\n    Feature(\"delete_device_public_key\", 1),\n    Feature(\"get_or_generate_device_public_key\", 1),\n    Feature(\"get_passkeys\", 1),\n    Feature(\"update_passkey\", 1),\n    Feature(\"is_user_verifying_platform_authenticator_available_for_credential\", 1),\n    Feature(\"is_user_verifying_platform_authenticator_available\", 1),\n    Feature(\"privileged_api_list_credentials\", 2),\n    Feature(\"start_target_direct_transfer\", 1),\n    Feature(\"first_party_api_get_link_info\", 1),\n    Feature(\"get_browser_hybrid_client_sign_pending_intent\", 1),\n    Feature(\"get_browser_hybrid_client_registration_pending_intent\", 1),\n    Feature(\"privileged_authenticate_passkey\", 1),\n    Feature(\"privileged_register_passkey_with_sync_account\", 1)\n)"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/privileged/Fido2PrivilegedService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.privileged\n\nimport android.app.KeyguardManager\nimport android.app.PendingIntent.FLAG_UPDATE_CURRENT\nimport android.content.Context\nimport android.content.Context.KEYGUARD_SERVICE\nimport android.content.Intent\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.Parcel\nimport android.util.Log\nimport androidx.core.app.PendingIntentCompat\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.LifecycleOwner\nimport androidx.lifecycle.lifecycleScope\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.internal.ConnectionInfo\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport com.google.android.gms.fido.fido2.api.IBooleanCallback\nimport com.google.android.gms.fido.fido2.api.ICredentialListCallback\nimport com.google.android.gms.fido.fido2.api.common.BrowserPublicKeyCredentialCreationOptions\nimport com.google.android.gms.fido.fido2.api.common.BrowserPublicKeyCredentialRequestOptions\nimport com.google.android.gms.fido.fido2.internal.privileged.IFido2PrivilegedCallbacks\nimport com.google.android.gms.fido.fido2.internal.privileged.IFido2PrivilegedService\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.common.GmsService.FIDO2_PRIVILEGED_API\nimport org.microg.gms.fido.core.FEATURES\nimport org.microg.gms.fido.core.ui.AuthenticatorActivity\nimport org.microg.gms.fido.core.ui.AuthenticatorActivity.Companion.SOURCE_BROWSER\nimport org.microg.gms.fido.core.ui.AuthenticatorActivity.Companion.KEY_SOURCE\nimport org.microg.gms.fido.core.ui.AuthenticatorActivity.Companion.KEY_OPTIONS\nimport org.microg.gms.fido.core.ui.AuthenticatorActivity.Companion.KEY_SERVICE\nimport org.microg.gms.fido.core.ui.AuthenticatorActivity.Companion.KEY_TYPE\nimport org.microg.gms.fido.core.ui.AuthenticatorActivity.Companion.TYPE_REGISTER\nimport org.microg.gms.fido.core.ui.AuthenticatorActivity.Companion.TYPE_SIGN\nimport org.microg.gms.utils.warnOnTransactionIssues\n\nconst val TAG = \"Fido2Privileged\"\n\nclass Fido2PrivilegedService : BaseService(TAG, FIDO2_PRIVILEGED_API) {\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        callback.onPostInitCompleteWithConnectionInfo(\n            CommonStatusCodes.SUCCESS,\n            Fido2PrivilegedServiceImpl(this, lifecycle).asBinder(),\n            ConnectionInfo().apply { features = FEATURES }\n        );\n    }\n}\n\nclass Fido2PrivilegedServiceImpl(private val context: Context, override val lifecycle: Lifecycle) :\n    IFido2PrivilegedService.Stub(), LifecycleOwner {\n    override fun getRegisterPendingIntent(callbacks: IFido2PrivilegedCallbacks, options: BrowserPublicKeyCredentialCreationOptions) {\n        lifecycleScope.launchWhenStarted {\n            val intent = Intent(context, AuthenticatorActivity::class.java)\n                .putExtra(KEY_SERVICE, FIDO2_PRIVILEGED_API.SERVICE_ID)\n                .putExtra(KEY_SOURCE, SOURCE_BROWSER)\n                .putExtra(KEY_TYPE, TYPE_REGISTER)\n                .putExtra(KEY_OPTIONS, options.serializeToBytes())\n\n            val pendingIntent =\n                PendingIntentCompat.getActivity(context, options.hashCode(), intent, FLAG_UPDATE_CURRENT, false)\n            callbacks.onPendingIntent(Status.SUCCESS, pendingIntent)\n        }\n    }\n\n    override fun getSignPendingIntent(callbacks: IFido2PrivilegedCallbacks, options: BrowserPublicKeyCredentialRequestOptions) {\n        lifecycleScope.launchWhenStarted {\n            val intent = Intent(context, AuthenticatorActivity::class.java)\n                .putExtra(KEY_SERVICE, FIDO2_PRIVILEGED_API.SERVICE_ID)\n                .putExtra(KEY_SOURCE, SOURCE_BROWSER)\n                .putExtra(KEY_TYPE, TYPE_SIGN)\n                .putExtra(KEY_OPTIONS, options.serializeToBytes())\n\n            val pendingIntent =\n                PendingIntentCompat.getActivity(context, options.hashCode(), intent, FLAG_UPDATE_CURRENT, false)\n            callbacks.onPendingIntent(Status.SUCCESS, pendingIntent)\n        }\n    }\n\n    override fun isUserVerifyingPlatformAuthenticatorAvailable(callbacks: IBooleanCallback) {\n        lifecycleScope.launchWhenStarted {\n            if (SDK_INT < 24) {\n                callbacks.onBoolean(false)\n            } else {\n                val keyguardManager = context.getSystemService(KEYGUARD_SERVICE) as? KeyguardManager?\n                callbacks.onBoolean(keyguardManager?.isDeviceSecure == true)\n            }\n        }\n    }\n\n    override fun getCredentialList(callbacks: ICredentialListCallback, rpId: String) {\n        Log.w(TAG, \"Not yet implemented: getCredentialList\")\n        lifecycleScope.launchWhenStarted {\n            runCatching { callbacks.onCredentialList(emptyList()) }\n        }\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =\n        warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n}\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/protocol/AndroidKeyAttestationObject.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.protocol\n\nimport com.google.android.gms.fido.fido2.api.common.Algorithm\nimport com.upokecenter.cbor.CBORObject\n\nclass AndroidKeyAttestationObject(\n    authData: AuthenticatorData,\n    val alg: Algorithm,\n    val sig: ByteArray,\n    val x5c: List<ByteArray>\n) :\n    AttestationObject(authData.encode()) {\n    override val fmt: String\n        get() = \"android-key\"\n    override val attStmt: CBORObject\n        get() = CBORObject.NewMap().apply {\n            set(\"alg\", alg.algoValue.encodeAsCbor())\n            set(\"sig\", sig.encodeAsCbor())\n            set(\"x5c\", CBORObject.NewArray().apply {\n                for (certificate in x5c) {\n                    Add(certificate.encodeAsCbor())\n                }\n            })\n        }\n}\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/protocol/AndroidSafetyNetAttestationObject.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.protocol\n\nimport com.upokecenter.cbor.CBORObject\n\nclass AndroidSafetyNetAttestationObject(authData: AuthenticatorData, val ver: String, val response: ByteArray) :\n    AttestationObject(authData.encode()) {\n    override val fmt: String\n        get() = \"android-safetynet\"\n    override val attStmt: CBORObject\n        get() = CBORObject.NewMap().apply {\n            set(\"ver\", ver.encodeAsCbor())\n            set(\"response\", response.encodeAsCbor())\n        }\n}\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/protocol/AttestationObject.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.protocol\n\nimport com.upokecenter.cbor.CBOREncodeOptions\nimport com.upokecenter.cbor.CBORObject\n\nabstract class AttestationObject(val authData: ByteArray) {\n    abstract val fmt: String\n    abstract val attStmt: CBORObject\n\n    fun encode(): ByteArray = CBORObject.NewMap().apply {\n        set(\"fmt\", fmt.encodeAsCbor())\n        set(\"attStmt\", attStmt)\n        set(\"authData\", authData.encodeAsCbor())\n    }.EncodeToBytes(CBOREncodeOptions.DefaultCtap2Canonical)\n}\n\nclass AnyAttestationObject(authData: ByteArray, override val fmt: String, override val attStmt: CBORObject) : AttestationObject(authData)\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/protocol/AttestedCredentialData.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.protocol\n\nimport com.upokecenter.cbor.CBORObject\nimport java.io.ByteArrayInputStream\nimport java.nio.ByteBuffer\nimport java.nio.ByteOrder\n\nclass AttestedCredentialData(val aaguid: ByteArray, val id: ByteArray, val publicKey: ByteArray) {\n    fun encode() = ByteBuffer.allocate(aaguid.size + 2 + id.size + publicKey.size)\n        .put(aaguid)\n        .order(ByteOrder.BIG_ENDIAN).putShort(id.size.toShort())\n        .put(id)\n        .put(publicKey)\n        .array()\n\n    companion object {\n        fun decode(buffer: ByteBuffer) = buffer.run {\n            val aaguid = ByteArray(16)\n            get(aaguid)\n            val idSize = order(ByteOrder.BIG_ENDIAN).short.toInt() and 0xffff\n            val id = ByteArray(idSize)\n            get(id)\n            mark()\n            val remaining = ByteArray(remaining())\n            get(remaining)\n            val bis = ByteArrayInputStream(remaining)\n            CBORObject.Read(bis) // Read object and ignore, we only want to know the size\n            reset()\n            val publicKey = ByteArray(remaining() - bis.available())\n            get(publicKey)\n            return@run AttestedCredentialData(aaguid, id, publicKey)\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/protocol/AuthenticatorData.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.protocol\n\nimport java.nio.ByteBuffer\nimport java.nio.ByteOrder\nimport kotlin.experimental.and\nimport kotlin.experimental.or\n\nclass AuthenticatorData(\n    val rpIdHash: ByteArray,\n    val userPresent: Boolean,\n    val userVerified: Boolean,\n    val signCount: Int,\n    val attestedCredentialData: AttestedCredentialData? = null,\n    val extensions: ByteArray? = null\n) {\n    fun encode(): ByteArray {\n        val attestedCredentialData = attestedCredentialData?.encode() ?: ByteArray(0)\n        val extensions = extensions ?: ByteArray(0)\n        return ByteBuffer.allocate(rpIdHash.size + 5 + attestedCredentialData.size + extensions.size)\n            .put(rpIdHash)\n            .put(buildFlags(userPresent, userVerified, attestedCredentialData.isNotEmpty(), extensions.isNotEmpty()))\n            .order(ByteOrder.BIG_ENDIAN).putInt(signCount)\n            .put(attestedCredentialData)\n            .put(extensions)\n            .array()\n    }\n\n    companion object {\n        /** User Present **/\n        private const val FLAG_UP: Byte = 0x01\n\n        /** User Verified **/\n        private const val FLAG_UV: Byte = 0x04\n\n        /** Attested credential data included **/\n        private const val FLAG_AT: Byte = 0x40\n\n        /** Extension data included **/\n        private const val FLAG_ED: Byte = -0x80\n\n        private fun buildFlags(up: Boolean, uv: Boolean, at: Boolean, ed: Boolean): Byte =\n            (if (up) FLAG_UP else 0) or (if (uv) FLAG_UV else 0) or (if (at) FLAG_AT else 0) or (if (ed) FLAG_ED else 0)\n\n        fun decode(byteArray: ByteArray): AuthenticatorData = ByteBuffer.wrap(byteArray).run {\n            val rpIdHash = ByteArray(32)\n            get(rpIdHash)\n            val flags = get()\n            val signCount = order(ByteOrder.BIG_ENDIAN).int\n            val attestedCredentialData = if ((flags and FLAG_AT) == FLAG_AT) AttestedCredentialData.decode(this) else null\n            val extensions = if ((flags and FLAG_ED) == FLAG_ED) {\n                val ed = ByteArray(remaining())\n                get(ed)\n                ed\n            } else {\n                null\n            }\n            return@run AuthenticatorData(rpIdHash, flags and FLAG_UP == FLAG_UP, flags and FLAG_UV == FLAG_UV, signCount, attestedCredentialData, extensions)\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/protocol/Cbor.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage org.microg.gms.fido.core.protocol\n\nimport android.util.Log\nimport com.google.android.gms.fido.common.Transport\nimport com.google.android.gms.fido.fido2.api.common.Algorithm\nimport com.google.android.gms.fido.fido2.api.common.EC2Algorithm\nimport com.google.android.gms.fido.fido2.api.common.PublicKeyCredentialDescriptor\nimport com.google.android.gms.fido.fido2.api.common.PublicKeyCredentialParameters\nimport com.google.android.gms.fido.fido2.api.common.PublicKeyCredentialRpEntity\nimport com.google.android.gms.fido.fido2.api.common.PublicKeyCredentialUserEntity\nimport com.google.android.gms.fido.fido2.api.common.RSAAlgorithm\nimport com.upokecenter.cbor.CBORObject\n\nprivate const val TAG = \"FidoCbor\"\n\nfun CBORObject.AsStringSequence(): Iterable<String> = Iterable {\n    object : Iterator<String> {\n        var index = 0\n        override fun hasNext(): Boolean = size() + 1 < index\n        override fun next(): String = get(index++).AsString()\n    }\n}\n\nfun CBORObject.AsInt32Sequence(): Iterable<Int> = Iterable {\n    object : Iterator<Int> {\n        var index = 0\n        override fun hasNext(): Boolean = size() + 1 < index\n        override fun next(): Int = get(index++).AsInt32()\n    }\n}\n\nfun String.encodeAsCbor() = CBORObject.FromObject(this)\nfun ByteArray.encodeAsCbor() = CBORObject.FromObject(this)\nfun Int.encodeAsCbor() = CBORObject.FromObject(this)\nfun Boolean.encodeAsCbor() = CBORObject.FromObject(this)\n\nfun PublicKeyCredentialRpEntity.encodeAsCbor() = CBORObject.NewMap().apply {\n    set(\"id\", id.encodeAsCbor())\n    if (!name.isNullOrBlank()) set(\"name\", name.encodeAsCbor())\n    if (!icon.isNullOrBlank()) set(\"icon\", icon!!.encodeAsCbor())\n}\n\nfun PublicKeyCredentialUserEntity.encodeAsCbor() = CBORObject.NewMap().apply {\n    set(\"id\", id.encodeAsCbor())\n    if (!name.isNullOrBlank()) set(\"name\", name.encodeAsCbor())\n    if (!icon.isNullOrBlank()) set(\"icon\", icon!!.encodeAsCbor())\n    if (!displayName.isNullOrBlank()) set(\"displayName\", displayName.encodeAsCbor())\n}\n\nfun CBORObject.decodeAsPublicKeyCredentialUserEntity() = PublicKeyCredentialUserEntity(\n    get(\"id\")?.GetByteString() ?: ByteArray(0).also { Log.w(TAG, \"id was not present\") },\n    get(\"name\")?.AsString() ?: \"\".also { Log.w(TAG, \"name was not present\") },\n    get(\"icon\")?.AsString(),\n    get(\"displayName\")?.AsString() ?: \"\".also { Log.w(TAG, \"displayName was not present\") }\n)\n\nfun CBORObject.decodeAsCoseKey() = CoseKey(\n    getAlgorithm(get(CoseKey.ALG).AsInt32Value()),\n    get(CoseKey.X).GetByteString(),\n    get(CoseKey.Y).GetByteString(),\n    get(CoseKey.CRV).AsInt32Value()\n)\n\nfun getAlgorithm(algorithmInt: Int): Algorithm {\n    return when (algorithmInt) {\n        -65535 -> RSAAlgorithm.RS1\n        -262 -> RSAAlgorithm.LEGACY_RS1\n        -261 -> EC2Algorithm.ED512\n        -260 -> EC2Algorithm.ED256\n        -259 -> RSAAlgorithm.RS512\n        -258 -> RSAAlgorithm.RS384\n        -257 -> RSAAlgorithm.RS256\n        -39 -> RSAAlgorithm.PS512\n        -38 -> RSAAlgorithm.PS384\n        -37 -> RSAAlgorithm.PS256\n        -36 -> EC2Algorithm.ES512\n        -35 -> EC2Algorithm.ES384\n        -7 -> EC2Algorithm.ES256\n\n        else -> Algorithm { algorithmInt }\n    }\n}\n\nfun PublicKeyCredentialParameters.encodeAsCbor() = CBORObject.NewMap().apply {\n    set(\"alg\", algorithmIdAsInteger.encodeAsCbor())\n    set(\"type\", typeAsString.encodeAsCbor())\n}\n\nfun CBORObject.decodeAsPublicKeyCredentialParameters() = PublicKeyCredentialParameters(\n    get(\"type\").AsString(),\n    get(\"alg\").AsInt32Value()\n)\n\nfun PublicKeyCredentialDescriptor.encodeAsCbor() = CBORObject.NewMap().apply {\n    set(\"type\", typeAsString.encodeAsCbor())\n    set(\"id\", id.encodeAsCbor())\n    set(\"transports\", transports.orEmpty().encodeAsCbor { it.toString().encodeAsCbor() })\n}\n\nfun CBORObject.decodeAsPublicKeyCredentialDescriptor() = PublicKeyCredentialDescriptor(\n    get(\"type\")?.AsString() ?: \"\".also { Log.w(TAG, \"type was not present\") },\n    get(\"id\")?.GetByteString() ?: ByteArray(0).also { Log.w(TAG, \"id was not present\") },\n    get(\"transports\")?.AsStringSequence()?.map { Transport.fromString(it) }\n)\n\nfun<T> List<T>.encodeAsCbor(f: (T) -> CBORObject) = CBORObject.NewArray().apply { this@encodeAsCbor.forEach { Add(f(it)) } }\nfun<T> Map<String,T>.encodeAsCbor(f: (T) -> CBORObject) = CBORObject.NewMap().apply {\n    for (entry in this@encodeAsCbor) {\n        set(entry.key, f(entry.value))\n    }\n}\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/protocol/CoseKey.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.protocol\n\nimport com.google.android.gms.fido.fido2.api.common.Algorithm\nimport com.upokecenter.cbor.CBOREncodeOptions\nimport com.upokecenter.cbor.CBORObject\nimport java.math.BigInteger\n\nclass CoseKey(\n    val algorithm: Algorithm,\n    val x: ByteArray,\n    val y: ByteArray,\n    val curveId: Int\n) {\n    constructor(algorithm: Algorithm, x: BigInteger, y: BigInteger, curveId: Int, curvePointSize: Int) :\n            this(algorithm, x.toByteArray(curvePointSize), y.toByteArray(curvePointSize), curveId)\n\n    fun encode(): ByteArray = encodeAsCbor().EncodeToBytes(CBOREncodeOptions.DefaultCtap2Canonical)\n\n    fun encodeAsCbor(): CBORObject = CBORObject.NewMap().apply {\n        set(KTY, 2.encodeAsCbor())\n        set(ALG, algorithm.algoValue.encodeAsCbor())\n        set(CRV, curveId.encodeAsCbor())\n        set(X, x.encodeAsCbor())\n        set(Y, y.encodeAsCbor())\n    }\n\n    companion object {\n        const val KTY = 1\n        const val ALG = 3\n        const val CRV = -1\n        const val X = -2\n        const val Y = -3\n\n        fun BigInteger.toByteArray(size: Int): ByteArray {\n            val res = ByteArray(size)\n            val orig = toByteArray()\n            if (orig.size > size) {\n                System.arraycopy(orig, orig.size - size, res, 0, size)\n            } else {\n                System.arraycopy(orig, 0, res, size - orig.size, orig.size)\n            }\n            return res\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/protocol/CredentialId.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.protocol\n\nimport android.util.Base64\nimport org.microg.gms.fido.core.digest\nimport org.microg.gms.utils.toBase64\nimport java.nio.ByteBuffer\nimport java.security.PublicKey\n\nclass CredentialId(val type: Byte, val data: ByteArray, val rpId: String, val publicKey: PublicKey) {\n    fun encode(): ByteArray = ByteBuffer.allocate(1 + data.size + 32).apply {\n        put(type)\n        put(data)\n        put((rpId.toByteArray() + publicKey.encoded).digest(\"SHA-256\"))\n    }.array()\n\n    fun toBase64(): String = encode().toBase64(Base64.URL_SAFE or Base64.NO_WRAP or Base64.NO_PADDING)\n\n    companion object {\n\n        fun decodeTypeAndDataByBase64(base64: String): Pair<Byte, ByteArray> {\n            val bytes = Base64.decode(base64, Base64.URL_SAFE or Base64.NO_WRAP or Base64.NO_PADDING)\n            return decodeTypeAndData(bytes)\n        }\n\n        fun decodeTypeAndData(bytes: ByteArray): Pair<Byte, ByteArray> {\n            val buffer = ByteBuffer.wrap(bytes)\n            val type = buffer.get()\n            val data = ByteArray(32)\n            buffer.get(data)\n            return type to data\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/protocol/FidoU2fAttestationObject.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.protocol\n\nimport com.upokecenter.cbor.CBORObject\n\nclass FidoU2fAttestationObject(authData: AuthenticatorData, val signature: ByteArray, val attestationCertificate: ByteArray) :\n    AttestationObject(authData.encode()) {\n    override val fmt: String\n        get() = \"fido-u2f\"\n    override val attStmt: CBORObject\n        get() = CBORObject.NewMap().apply {\n            set(\"sig\", signature.encodeAsCbor())\n            set(\"x5c\", CBORObject.NewArray().apply { Add(attestationCertificate.encodeAsCbor()) })\n        }\n}\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/protocol/NoneAttestationObject.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.protocol\n\nimport com.upokecenter.cbor.CBORObject\n\nclass NoneAttestationObject(authData: AuthenticatorData) : AttestationObject(authData.encode()) {\n    override val fmt: String\n        get() = \"none\"\n    override val attStmt: CBORObject\n        get() = CBORObject.NewMap()\n}\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/protocol/msgs/Apdu.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.protocol.msgs\n\nfun encodeCommandApdu(\n    cla: Byte,\n    ins: Byte,\n    p1: Byte,\n    p2: Byte,\n    data: ByteArray = ByteArray(0),\n    le: Int = -1,\n    extended: Boolean = data.size > 255 || le > 255\n): ByteArray {\n    val fixed = byteArrayOf(cla, ins, p1, p2)\n    val ext = if (extended) byteArrayOf(0) else ByteArray(0)\n    val req = when {\n        data.isEmpty() -> ByteArray(0)\n        extended -> byteArrayOf((data.size shr 8).toByte(), data.size.toByte()) + data\n        else -> byteArrayOf(data.size.toByte()) + data\n    }\n    val res = when {\n        le == -1 -> ByteArray(0)\n        extended -> byteArrayOf((le shr 8).toByte(), le.toByte())\n        else -> byteArrayOf(le.toByte())\n    }\n    return fixed + ext + req + res\n}\n\nfun decodeResponseApdu(bytes: ByteArray): Pair<Short, ByteArray> {\n    require(bytes.size >= 2)\n    return ((bytes[bytes.size - 2].toInt() and 0xff shl 8) + (bytes.last()\n        .toInt() and 0xff)).toShort() to bytes.sliceArray(0 until bytes.size - 2)\n}\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/protocol/msgs/AuthenticatorClientPIN.kt",
    "content": "package org.microg.gms.fido.core.protocol.msgs\n\nimport com.upokecenter.cbor.CBORObject\nimport org.microg.gms.fido.core.protocol.CoseKey\nimport org.microg.gms.fido.core.protocol.decodeAsCoseKey\nimport org.microg.gms.fido.core.protocol.encodeAsCbor\n\nclass AuthenticatorClientPINCommand(request: AuthenticatorClientPINRequest) :\n    Ctap2Command<AuthenticatorClientPINRequest, AuthenticatorClientPINResponse>(request) {\n\n    override fun decodeResponse(obj: CBORObject) = AuthenticatorClientPINResponse.decodeFromCbor(obj)\n\n    override val timeout: Long\n        get() = 60000\n\n}\n\nclass AuthenticatorClientPINRequest(\n    val pinProtocol: Int,\n    val subCommand: Int,\n    val keyAgreement: CoseKey? = null,\n    val pinAuth: ByteArray? = null,\n    val newPinEnc: ByteArray? = null,\n    val pinHashEnc: ByteArray? = null\n) : Ctap2Request(0x06, CBORObject.NewMap().apply {\n    set(0x01, pinProtocol.encodeAsCbor())\n    set(0x02, subCommand.encodeAsCbor())\n    if (keyAgreement != null) set(0x03, keyAgreement.encodeAsCbor())\n    if (pinAuth != null) set(0x04, pinAuth.encodeAsCbor())\n    if (newPinEnc != null) set(0x05, newPinEnc.encodeAsCbor())\n    if (pinHashEnc != null) set(0x06, pinHashEnc.encodeAsCbor())\n}) {\n    override fun toString(): String {\n        return \"AuthenticatorClientPINRequest(pinProtocol=$pinProtocol, \" +\n                \"subCommand=$subCommand, keyAgreement=$keyAgreement, \" +\n                \"pinAuth=${pinAuth?.contentToString()}, \" +\n                \"newPinEnc=${newPinEnc?.contentToString()}, \" +\n                \"pinHashEnc=${pinHashEnc?.contentToString()})\"\n    }\n\n    companion object {\n        // PIN protocol versions\n        const val PIN_PROTOCOL_VERSION_ONE = 0x01\n\n        // PIN subcommands\n        const val GET_RETRIES = 0x01\n        const val GET_KEY_AGREEMENT = 0x02\n        const val SET_PIN = 0x03\n        const val CHANGE_PIN = 0x04\n        const val GET_PIN_TOKEN = 0x05\n    }\n}\n\nclass AuthenticatorClientPINResponse(\n    val keyAgreement: CoseKey?,\n    val pinToken: ByteArray?,\n    val retries: Int?\n) : Ctap2Response {\n    companion object {\n        fun decodeFromCbor(obj: CBORObject) = AuthenticatorClientPINResponse(\n            obj.get(0x01)?.decodeAsCoseKey(),\n            obj.get(0x02)?.GetByteString(),\n            obj.get(0x03)?.AsInt32Value()\n        )\n    }\n}"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/protocol/msgs/AuthenticatorGetAssertion.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.protocol.msgs\n\nimport android.util.Base64\nimport com.google.android.gms.fido.fido2.api.common.PublicKeyCredentialDescriptor\nimport com.google.android.gms.fido.fido2.api.common.PublicKeyCredentialUserEntity\nimport com.upokecenter.cbor.CBORObject\nimport org.microg.gms.fido.core.protocol.decodeAsPublicKeyCredentialDescriptor\nimport org.microg.gms.fido.core.protocol.decodeAsPublicKeyCredentialUserEntity\nimport org.microg.gms.fido.core.protocol.encodeAsCbor\nimport org.microg.gms.utils.toBase64\n\nclass AuthenticatorGetAssertionCommand(request: AuthenticatorGetAssertionRequest) :\n    Ctap2Command<AuthenticatorGetAssertionRequest, AuthenticatorGetAssertionResponse>(request) {\n    override fun decodeResponse(obj: CBORObject) = AuthenticatorGetAssertionResponse.decodeFromCbor(obj)\n    override val timeout: Long\n        get() = 60000\n}\n\nclass AuthenticatorGetAssertionRequest(\n    val rpId: String,\n    val clientDataHash: ByteArray,\n    val allowList: List<PublicKeyCredentialDescriptor> = emptyList(),\n    val extensions: Map<String, CBORObject> = emptyMap(),\n    val options: Options? = null,\n    val pinAuth: ByteArray? = null,\n    val pinProtocol: Int? = null\n) : Ctap2Request(0x02, CBORObject.NewMap().apply {\n    set(0x01, rpId.encodeAsCbor())\n    set(0x02, clientDataHash.encodeAsCbor())\n    if (allowList.isNotEmpty()) set(0x03, allowList.encodeAsCbor { it.encodeAsCbor() })\n    if (extensions.isNotEmpty()) set(0x04, extensions.encodeAsCbor { it })\n    if (options != null) set(0x05, options.encodeAsCbor())\n    if (pinAuth != null) set(0x06, pinAuth.encodeAsCbor())\n    if (pinProtocol != null) set(0x07, pinProtocol.encodeAsCbor())\n}) {\n    override fun toString() = \"AuthenticatorGetAssertionRequest(rpId=${rpId},\" +\n            \"clientDataHash=0x${clientDataHash.toBase64(Base64.NO_WRAP)}, \" +\n            \"allowList=[${allowList.joinToString()}],extensions=[${extensions.entries.joinToString()}],\" +\n            \"options=$options,pinAuth=${pinAuth?.toBase64(Base64.NO_WRAP)},pinProtocol=$pinProtocol)\"\n\n    companion object {\n        class Options(\n            val userPresence: Boolean = true,\n            val userVerification: Boolean = false\n        ) {\n            fun encodeAsCbor(): CBORObject = CBORObject.NewMap().apply {\n                // Only encode non-default values\n                if (!userPresence) set(\"up\", userPresence.encodeAsCbor())\n                if (userVerification) set(\"uv\", userVerification.encodeAsCbor())\n            }\n\n            override fun toString(): String {\n                return \"(userPresence=$userPresence, userVerification=$userVerification)\"\n            }\n        }\n    }\n}\n\nclass AuthenticatorGetAssertionResponse(\n    val credential: PublicKeyCredentialDescriptor?,\n    val authData: ByteArray,\n    val signature: ByteArray,\n    val user: PublicKeyCredentialUserEntity?,\n    val numberOfCredentials: Int?\n) : Ctap2Response {\n\n    companion object {\n        fun decodeFromCbor(obj: CBORObject) = AuthenticatorGetAssertionResponse(\n            credential = obj.get(0x01)?.decodeAsPublicKeyCredentialDescriptor(),\n            authData = obj.get(0x02).GetByteString(),\n            signature = obj.get(0x03).GetByteString(),\n            user = obj.get(0x04)?.decodeAsPublicKeyCredentialUserEntity(),\n            numberOfCredentials = obj.get(0x05)?.AsInt32Value()\n        )\n    }\n}\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/protocol/msgs/AuthenticatorGetInfo.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.protocol.msgs\n\nimport com.google.android.gms.fido.fido2.api.common.PublicKeyCredentialParameters\nimport com.upokecenter.cbor.CBORObject\nimport org.microg.gms.fido.core.protocol.AsInt32Sequence\nimport org.microg.gms.fido.core.protocol.AsStringSequence\nimport org.microg.gms.fido.core.protocol.decodeAsPublicKeyCredentialParameters\nimport org.microg.gms.utils.ToStringHelper\n\nclass AuthenticatorGetInfoCommand : Ctap2Command<AuthenticatorGetInfoRequest, AuthenticatorGetInfoResponse>(AuthenticatorGetInfoRequest()) {\n    override fun decodeResponse(obj: CBORObject) = AuthenticatorGetInfoResponse.decodeFromCbor(obj)\n}\n\nclass AuthenticatorGetInfoRequest : Ctap2Request(0x04)\n\nclass AuthenticatorGetInfoResponse(\n    val versions: List<String>,\n    val extensions: List<String>,\n    val aaguid: ByteArray,\n    val options: Options,\n    val maxMsgSize: Int?,\n    val pinUvAuthProtocols: List<Int>,\n    val maxCredentialCountInList: Int?,\n    val maxCredentialIdLength: Int?,\n    val transports: List<String>?,\n    val algorithms: List<PublicKeyCredentialParameters>?,\n    val maxSerializedLargeBlobArray: Int?,\n    val forcePINChange: Boolean,\n    val minPINLength: Int?,\n    val firmwareVersion: Int?,\n    val maxCredBlobLength: Int?,\n    val maxRPIDsForSetMinPINLength: Int?,\n    val preferredPlatformUvAttempts: Int?,\n    val uvModality: Int?,\n    val certifications: Map<String, Int>?,\n    val remainingDiscoverableCredentials: Int?,\n    val vendorPrototypeConfigCommands: List<Int>?,\n) : Ctap2Response {\n\n    companion object {\n        class Options(\n            val platformDevice: Boolean,\n            val residentKey: Boolean,\n            val clientPin: Boolean?,\n            val userPresence: Boolean,\n            val userVerification: Boolean?,\n            val pinUvAuthToken: Boolean?,\n            val noMcGaPermissionsWithClientPin: Boolean,\n            val largeBlobs: Boolean?,\n            val enterpriseAttestation: Boolean?,\n            val bioEnroll: Boolean?,\n            val userVerificationMgmtPreview: Boolean?,\n            val uvBioEnroll: Boolean?,\n            val authenticatorConfigSupported: Boolean?,\n            val uvAcfg: Boolean?,\n            val credentialManagementSupported: Boolean?,\n            val credentialMgmtPreview: Boolean?,\n            val setMinPINLengthSupported: Boolean?,\n            val makeCredUvNotRqd: Boolean,\n            val alwaysUv: Boolean?,\n        ) {\n            companion object {\n                fun decodeFromCbor(map: CBORObject?) = Options(\n                    platformDevice = map?.get(\"plat\")?.AsBoolean() == true,\n                    residentKey = map?.get(\"rk\")?.AsBoolean() == true,\n                    clientPin = map?.get(\"clientPin\")?.AsBoolean(),\n                    userPresence = map?.get(\"up\")?.AsBoolean() != false,\n                    userVerification = map?.get(\"uv\")?.AsBoolean(),\n                    pinUvAuthToken = map?.get(\"pinUvAuthToken\")?.AsBoolean(),\n                    noMcGaPermissionsWithClientPin = map?.get(\"noMcGaPermissionsWithClientPin\")?.AsBoolean() == true,\n                    largeBlobs = map?.get(\"largeBlobs\")?.AsBoolean(),\n                    enterpriseAttestation = map?.get(\"ep\")?.AsBoolean(),\n                    bioEnroll = map?.get(\"bioEnroll\")?.AsBoolean(),\n                    userVerificationMgmtPreview = map?.get(\"userVerificationMgmtPreview\")?.AsBoolean(),\n                    uvBioEnroll = map?.get(\"uvBioEnroll\")?.AsBoolean(),\n                    authenticatorConfigSupported = map?.get(\"authnrCfg\")?.AsBoolean(),\n                    uvAcfg = map?.get(\"uvAcfg\")?.AsBoolean(),\n                    credentialManagementSupported = map?.get(\"credMgmt\")?.AsBoolean(),\n                    credentialMgmtPreview = map?.get(\"credentialMgmtPreview\")?.AsBoolean(),\n                    setMinPINLengthSupported = map?.get(\"setMinPINLength\")?.AsBoolean(),\n                    makeCredUvNotRqd = map?.get(\"makeCredUvNotRqd\")?.AsBoolean() == true,\n                    alwaysUv = map?.get(\"alwaysUv\")?.AsBoolean(),\n                )\n            }\n\n            override fun toString(): String {\n                return ToStringHelper.name(\"Options\")\n                    .field(\"platformDevice\", platformDevice)\n                    .field(\"residentKey\", residentKey)\n                    .field(\"clientPin\", clientPin)\n                    .field(\"userPresence\", userPresence)\n                    .field(\"userVerification\", userVerification)\n                    .field(\"pinUvAuthToken\", pinUvAuthToken)\n                    .field(\"noMcGaPermissionsWithClientPin\", noMcGaPermissionsWithClientPin)\n                    .field(\"largeBlobs\", largeBlobs)\n                    .field(\"enterpriseAttestation\", enterpriseAttestation)\n                    .field(\"bioEnroll\", bioEnroll)\n                    .field(\"userVerificationMgmtPreview\", userVerificationMgmtPreview)\n                    .field(\"uvBioEnroll\", uvBioEnroll)\n                    .field(\"authenticatorConfigSupported\", authenticatorConfigSupported)\n                    .field(\"uvAcfg\", uvAcfg)\n                    .field(\"credentialManagementSupported\", credentialManagementSupported)\n                    .field(\"credentialMgmtPreview\", credentialMgmtPreview)\n                    .field(\"setMinPINLengthSupported\", setMinPINLengthSupported)\n                    .field(\"makeCredUvNotRqd\", makeCredUvNotRqd)\n                    .field(\"alwaysUv\", alwaysUv)\n                    .end()\n            }\n        }\n\n        fun decodeFromCbor(obj: CBORObject) = AuthenticatorGetInfoResponse(\n            versions = obj.get(1)?.AsStringSequence()?.toList().orEmpty(),\n            extensions = obj.get(2)?.AsStringSequence()?.toList().orEmpty(),\n            aaguid = obj.get(3)?.GetByteString()\n                ?: throw IllegalArgumentException(\"Not a valid response for authenticatorGetInfo\"),\n            options = Options.decodeFromCbor(obj.get(4)),\n            maxMsgSize = obj.get(5)?.AsInt32Value(),\n            pinUvAuthProtocols = obj.get(6)?.AsInt32Sequence()?.toList().orEmpty(),\n            maxCredentialCountInList = obj.get(7)?.AsInt32Value(),\n            maxCredentialIdLength = obj.get(8)?.AsInt32Value(),\n            transports = obj.get(9)?.AsStringSequence()?.toList(),\n            algorithms = runCatching { obj.get(10)?.values?.map { it.decodeAsPublicKeyCredentialParameters() } }.getOrNull(),\n            maxSerializedLargeBlobArray = obj.get(11)?.AsInt32Value(),\n            forcePINChange = obj.get(12)?.AsBoolean() == true,\n            minPINLength = obj.get(13)?.AsInt32Value(),\n            firmwareVersion = obj.get(14)?.AsInt32Value(),\n            maxCredBlobLength = obj.get(15)?.AsInt32Value(),\n            maxRPIDsForSetMinPINLength = obj.get(16)?.AsInt32Value(),\n            preferredPlatformUvAttempts = obj.get(17)?.AsInt32Value(),\n            uvModality = obj.get(18)?.AsInt32Value(),\n            certifications = obj.get(19)?.entries?.mapNotNull { runCatching { it.key.AsString() to it.value.AsInt32Value() }.getOrNull() }?.toMap(),\n            remainingDiscoverableCredentials = obj.get(20)?.AsInt32Value(),\n            vendorPrototypeConfigCommands = obj.get(21)?.AsInt32Sequence()?.toList(),\n        )\n    }\n\n    override fun toString(): String {\n        return ToStringHelper.name(\"AuthenticatorGetInfoResponse\")\n            .field(\"versions\", versions)\n            .field(\"extensions\", extensions)\n            .field(\"aaguid\", aaguid)\n            .field(\"options\", options)\n            .field(\"maxMsgSize\", maxMsgSize)\n            .field(\"pinUvAuthProtocols\", pinUvAuthProtocols)\n            .field(\"maxCredentialCountInList\", maxCredentialCountInList)\n            .field(\"maxCredentialIdLength\", maxCredentialIdLength)\n            .field(\"transports\", transports)\n            .field(\"algorithms\", algorithms)\n            .field(\"maxSerializedLargeBlobArray\", maxSerializedLargeBlobArray)\n            .field(\"forcePINChange\", forcePINChange)\n            .field(\"minPINLength\", minPINLength)\n            .field(\"firmwareVersion\", firmwareVersion)\n            .field(\"maxCredBlobLength\", maxCredBlobLength)\n            .field(\"maxRPIDsForSetMinPINLength\", maxRPIDsForSetMinPINLength)\n            .field(\"preferredPlatformUvAttempts\", preferredPlatformUvAttempts)\n            .field(\"uvModality\", uvModality)\n            .field(\"certifications\", certifications)\n            .field(\"remainingDiscoverableCredentials\", remainingDiscoverableCredentials)\n            .field(\"vendorPrototypeConfigCommands\", vendorPrototypeConfigCommands)\n            .end()\n    }\n}\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/protocol/msgs/AuthenticatorMakeCredential.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.protocol.msgs\n\nimport android.util.Base64\nimport com.google.android.gms.fido.fido2.api.common.PublicKeyCredentialDescriptor\nimport com.google.android.gms.fido.fido2.api.common.PublicKeyCredentialParameters\nimport com.google.android.gms.fido.fido2.api.common.PublicKeyCredentialRpEntity\nimport com.google.android.gms.fido.fido2.api.common.PublicKeyCredentialUserEntity\nimport com.upokecenter.cbor.CBORObject\nimport org.microg.gms.fido.core.protocol.encodeAsCbor\nimport org.microg.gms.utils.toBase64\n\nclass AuthenticatorMakeCredentialCommand(request: AuthenticatorMakeCredentialRequest) :\n    Ctap2Command<AuthenticatorMakeCredentialRequest, AuthenticatorMakeCredentialResponse>(request) {\n    override fun decodeResponse(obj: CBORObject) = AuthenticatorMakeCredentialResponse.decodeFromCbor(obj)\n    override val timeout: Long\n        get() = 60000\n}\n\nclass AuthenticatorMakeCredentialRequest(\n    val clientDataHash: ByteArray,\n    val rp: PublicKeyCredentialRpEntity,\n    val user: PublicKeyCredentialUserEntity,\n    val pubKeyCredParams: List<PublicKeyCredentialParameters>,\n    val excludeList: List<PublicKeyCredentialDescriptor> = emptyList(),\n    val extensions: Map<String, CBORObject> = emptyMap(),\n    val options: Options? = null,\n    val pinAuth: ByteArray? = null,\n    val pinProtocol: Int? = null\n) : Ctap2Request(0x01, CBORObject.NewMap().apply {\n    set(0x01, clientDataHash.encodeAsCbor())\n    set(0x02, rp.encodeAsCbor())\n    set(0x03, user.encodeAsCbor())\n    set(0x04, pubKeyCredParams.encodeAsCbor { it.encodeAsCbor() })\n    if (excludeList.isNotEmpty()) set(0x05, excludeList.encodeAsCbor { it.encodeAsCbor() })\n    if (extensions.isNotEmpty()) set(0x06, extensions.encodeAsCbor { it })\n    if (options != null) set(0x07, options.encodeAsCbor())\n    if (pinAuth != null) set(0x08, pinAuth.encodeAsCbor())\n    if (pinProtocol != null) set(0x09, pinProtocol.encodeAsCbor())\n}) {\n    override fun toString() = \"AuthenticatorMakeCredentialRequest(clientDataHash=0x${clientDataHash.toBase64(Base64.NO_WRAP)}, \" +\n            \"rp=$rp,user=$user,pubKeyCredParams=[${pubKeyCredParams.joinToString()}],\" +\n            \"excludeList=[${excludeList.joinToString()}],extensions=[${extensions.entries.joinToString()}],\" +\n            \"options=$options,pinAuth=${pinAuth?.toBase64(Base64.NO_WRAP)},pinProtocol=$pinProtocol)\"\n\n    companion object {\n        class Options(\n            val residentKey: Boolean = false,\n            val userVerification: Boolean = false\n        ) {\n            fun encodeAsCbor() = CBORObject.NewMap().apply {\n                // Only encode non-default values\n                if (residentKey) set(\"rk\", residentKey.encodeAsCbor())\n                if (userVerification) set(\"uv\", userVerification.encodeAsCbor())\n            }\n        }\n    }\n}\n\nclass AuthenticatorMakeCredentialResponse(\n    val authData: ByteArray,\n    val fmt: String,\n    val attStmt: CBORObject\n) : Ctap2Response {\n    companion object {\n        fun decodeFromCbor(obj: CBORObject) = AuthenticatorMakeCredentialResponse(\n            fmt = obj.get(0x01).AsString(),\n            authData = obj.get(0x02).GetByteString(),\n            attStmt = obj.get(0x03)\n        )\n    }\n}\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/protocol/msgs/Ctap1Command.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.protocol.msgs\n\nimport android.util.Base64\nimport org.microg.gms.utils.toBase64\nimport java.io.ByteArrayInputStream\nimport java.io.InputStream\n\nabstract class Ctap1Command<Q : Ctap1Request, S : Ctap1Response>(val request: Q) {\n    val commandByte: Byte\n        get() = request.commandByte\n    fun decodeResponse(statusCode: Short, bytes: ByteArray, offset: Int = 0): S =\n        decodeResponse(statusCode, ByteArrayInputStream(bytes, offset, bytes.size - offset))\n    abstract fun decodeResponse(statusCode: Short, i: InputStream): S\n}\n\nabstract class Ctap1Request(\n    val commandByte: Byte,\n    val p1: Byte = 0,\n    val p2: Byte = 0,\n    val data: ByteArray\n) {\n    val apdu = encodeCommandApdu(0, commandByte, p1, p2, data, extended = true)\n\n    override fun toString(): String = \"Ctap1Request(command=0x${commandByte.toString(16)}, \" +\n            \"p1=0x${p1.toString(16)}, \" +\n            \"p2=0x${p2.toString(16)}, \" +\n            \"data=${data.toBase64(Base64.NO_WRAP)})\"\n}\n\nabstract class Ctap1Response(val statusCode: Short) {\n    open fun encode(): ByteArray = throw UnsupportedOperationException()\n}\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/protocol/msgs/Ctap2Command.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.protocol.msgs\n\nimport android.util.Base64\nimport com.upokecenter.cbor.CBOREncodeOptions\nimport com.upokecenter.cbor.CBORObject\nimport org.microg.gms.utils.toBase64\nimport java.io.ByteArrayInputStream\nimport java.io.InputStream\n\nabstract class Ctap2Command<Q: Ctap2Request, R: Ctap2Response>(val request: Q) {\n    val hasParameters: Boolean\n        get() = request.parameters != null\n    open val timeout: Long\n        get() = 1000\n    fun decodeResponse(bytes: ByteArray, offset: Int = 0): R =\n        decodeResponse(ByteArrayInputStream(bytes, offset, bytes.size - offset))\n    open fun decodeResponse(i: InputStream) = decodeResponse(CBORObject.Read(i))\n    abstract fun decodeResponse(obj: CBORObject): R\n}\n\ninterface Ctap2Response\n\nabstract class Ctap2Request(val commandByte: Byte, val parameters: CBORObject? = null) {\n    val payload: ByteArray = parameters?.EncodeToBytes(CBOREncodeOptions.DefaultCtap2Canonical) ?: ByteArray(0)\n\n    override fun toString(): String = \"Ctap2Request(command=0x${commandByte.toString(16)}, \" +\n            \"payload=${payload.toBase64(Base64.NO_WRAP)})\"\n}\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/protocol/msgs/U2fAuthentication.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.protocol.msgs\n\nimport android.util.Base64\nimport org.microg.gms.utils.toBase64\nimport java.io.DataInputStream\nimport java.io.InputStream\n\nclass U2fAuthenticationCommand(request: U2fAuthenticationRequest) :\n    Ctap1Command<U2fAuthenticationRequest, U2fAuthenticationResponse>(request) {\n    constructor(controlByte: Byte, challenge: ByteArray, application: ByteArray, keyHandle: ByteArray) :\n            this(U2fAuthenticationRequest(controlByte, challenge, application, keyHandle))\n\n    override fun decodeResponse(statusCode: Short, i: InputStream): U2fAuthenticationResponse = U2fAuthenticationResponse.decode(statusCode, i)\n}\n\nclass U2fAuthenticationRequest(val controlByte: Byte, val challenge: ByteArray, val application: ByteArray, val keyHandle: ByteArray) :\n    Ctap1Request(0x02, data = challenge + application + keyHandle.size.toByte() + keyHandle, p1 = controlByte) {\n    init {\n        require(challenge.size == 32)\n        require(application.size == 32)\n    }\n    override fun toString(): String = \"U2fAuthenticationRequest(controlByte=0x${controlByte.toString(16)}, \" +\n            \"challenge=${challenge.toBase64(Base64.NO_WRAP)}, \" +\n            \"application=${application.toBase64(Base64.NO_WRAP)}, \" +\n            \"keyHandle=${keyHandle.toBase64(Base64.NO_WRAP)})\"\n}\n\nclass U2fAuthenticationResponse(\n    statusCode: Short,\n    val userPresence: Boolean,\n    val counter: Int,\n    val signature: ByteArray\n) : Ctap1Response(statusCode) {\n    companion object {\n        fun decode(statusCode: Short, i: InputStream): U2fAuthenticationResponse {\n            val userPresence = i.read() and 0x1 > 0\n            val counter = DataInputStream(i).readInt()\n            val signature = i.readBytes()\n            return U2fAuthenticationResponse(statusCode, userPresence, counter, signature)\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/protocol/msgs/U2fRegistration.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.protocol.msgs\n\nimport android.util.Base64\nimport org.microg.gms.utils.toBase64\nimport java.io.InputStream\nimport javax.security.cert.X509Certificate\n\nclass U2fRegistrationCommand(request: U2fRegistrationRequest) :\n    Ctap1Command<U2fRegistrationRequest, U2fRegistrationResponse>(request) {\n    constructor(challenge: ByteArray, application: ByteArray) : this(U2fRegistrationRequest(challenge, application))\n\n    override fun decodeResponse(statusCode: Short, i: InputStream): U2fRegistrationResponse = U2fRegistrationResponse.decode(statusCode, i)\n}\n\nclass U2fRegistrationRequest(val challenge: ByteArray, val application: ByteArray) :\n    Ctap1Request(0x01, data = challenge + application) {\n    init {\n        require(challenge.size == 32)\n        require(application.size == 32)\n    }\n    override fun toString(): String = \"U2fRegistrationRequest(challenge=${challenge.toBase64(Base64.NO_WRAP)}, \" +\n            \"application=${application.toBase64(Base64.NO_WRAP)})\"\n}\n\nclass U2fRegistrationResponse(\n    statusCode: Short,\n    val userPublicKey: ByteArray,\n    val keyHandle: ByteArray,\n    val attestationCertificate: ByteArray,\n    val signature: ByteArray\n) : Ctap1Response(statusCode) {\n    companion object {\n        fun decode(statusCode: Short, i: InputStream): U2fRegistrationResponse {\n            require(i.read() == 0x05) // reserved byte\n            val userPublicKey = ByteArray(65)\n            i.read(userPublicKey)\n            val keyHandle = ByteArray(i.read())\n            i.read(keyHandle)\n            val attestationCertificate = X509Certificate.getInstance(i).encoded\n            val signature = i.readBytes()\n            return U2fRegistrationResponse(statusCode, userPublicKey, keyHandle, attestationCertificate, signature)\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/regular/Fido2AppService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.regular\n\nimport android.app.KeyguardManager\nimport android.app.PendingIntent.FLAG_UPDATE_CURRENT\nimport android.content.Context\nimport android.content.Context.KEYGUARD_SERVICE\nimport android.content.Intent\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.Parcel\nimport androidx.core.app.PendingIntentCompat\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.LifecycleOwner\nimport androidx.lifecycle.lifecycleScope\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.internal.ConnectionInfo\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport com.google.android.gms.fido.fido2.api.IBooleanCallback\nimport com.google.android.gms.fido.fido2.api.common.PublicKeyCredentialCreationOptions\nimport com.google.android.gms.fido.fido2.api.common.PublicKeyCredentialRequestOptions\nimport com.google.android.gms.fido.fido2.internal.regular.IFido2AppCallbacks\nimport com.google.android.gms.fido.fido2.internal.regular.IFido2AppService\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.common.GmsService.FIDO2_API\nimport org.microg.gms.fido.core.FEATURES\nimport org.microg.gms.fido.core.ui.AuthenticatorActivity\nimport org.microg.gms.fido.core.ui.AuthenticatorActivity.Companion.SOURCE_APP\nimport org.microg.gms.fido.core.ui.AuthenticatorActivity.Companion.KEY_SOURCE\nimport org.microg.gms.fido.core.ui.AuthenticatorActivity.Companion.KEY_OPTIONS\nimport org.microg.gms.fido.core.ui.AuthenticatorActivity.Companion.KEY_SERVICE\nimport org.microg.gms.fido.core.ui.AuthenticatorActivity.Companion.KEY_TYPE\nimport org.microg.gms.fido.core.ui.AuthenticatorActivity.Companion.TYPE_REGISTER\nimport org.microg.gms.fido.core.ui.AuthenticatorActivity.Companion.TYPE_SIGN\nimport org.microg.gms.utils.warnOnTransactionIssues\n\nconst val TAG = \"Fido2Regular\"\n\nclass Fido2AppService : BaseService(TAG, FIDO2_API) {\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        callback.onPostInitCompleteWithConnectionInfo(\n            CommonStatusCodes.SUCCESS,\n            Fido2AppServiceImpl(this, lifecycle).asBinder(),\n            ConnectionInfo().apply { features = FEATURES }\n        );\n    }\n}\n\nclass Fido2AppServiceImpl(private val context: Context, override val lifecycle: Lifecycle) :\n    IFido2AppService.Stub(), LifecycleOwner {\n    override fun getRegisterPendingIntent(callbacks: IFido2AppCallbacks, options: PublicKeyCredentialCreationOptions) {\n        lifecycleScope.launchWhenStarted {\n            val intent = Intent(context, AuthenticatorActivity::class.java)\n                .putExtra(KEY_SERVICE, FIDO2_API.SERVICE_ID)\n                .putExtra(KEY_SOURCE, SOURCE_APP)\n                .putExtra(KEY_TYPE, TYPE_REGISTER)\n                .putExtra(KEY_OPTIONS, options.serializeToBytes())\n\n            val pendingIntent =\n                PendingIntentCompat.getActivity(context, options.hashCode(), intent, FLAG_UPDATE_CURRENT, false)\n            callbacks.onPendingIntent(Status.SUCCESS, pendingIntent)\n        }\n    }\n\n    override fun getSignPendingIntent(callbacks: IFido2AppCallbacks, options: PublicKeyCredentialRequestOptions) {\n        lifecycleScope.launchWhenStarted {\n            val intent = Intent(context, AuthenticatorActivity::class.java)\n                .putExtra(KEY_SERVICE, FIDO2_API.SERVICE_ID)\n                .putExtra(KEY_SOURCE, SOURCE_APP)\n                .putExtra(KEY_TYPE, TYPE_SIGN)\n                .putExtra(KEY_OPTIONS, options.serializeToBytes())\n\n            val pendingIntent =\n                PendingIntentCompat.getActivity(context, options.hashCode(), intent, FLAG_UPDATE_CURRENT, false)\n            callbacks.onPendingIntent(Status.SUCCESS, pendingIntent)\n        }\n    }\n\n    override fun isUserVerifyingPlatformAuthenticatorAvailable(callbacks: IBooleanCallback) {\n        lifecycleScope.launchWhenStarted {\n            if (SDK_INT < 24) {\n                callbacks.onBoolean(false)\n            } else {\n                val keyguardManager = context.getSystemService(KEYGUARD_SERVICE) as? KeyguardManager?\n                callbacks.onBoolean(keyguardManager?.isDeviceSecure == true)\n            }\n        }\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =\n        warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n}\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/transport/CtapConnection.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.transport\n\nimport com.google.android.gms.fido.fido2.api.common.ErrorCode\nimport org.microg.gms.fido.core.RequestHandlingException\nimport org.microg.gms.fido.core.protocol.msgs.*\n\nconst val CAPABILITY_CTAP_1 = 1 shl 0\nconst val CAPABILITY_CTAP_2 = 1 shl 1\nconst val CAPABILITY_CTAP_2_1 = 1 shl 2\nconst val CAPABILITY_CLIENT_PIN = 1 shl 3\nconst val CAPABILITY_WINK = 1 shl 4\nconst val CAPABILITY_MAKE_CRED_WITHOUT_UV = 1 shl 5\nconst val CAPABILITY_USER_VERIFICATION = 1 shl 6\nconst val CAPABILITY_RESIDENT_KEY = 1 shl 7\n\ninterface CtapConnection {\n    val capabilities: Int\n    val transports: List<String>\n\n    val hasCtap1Support: Boolean\n        get() = capabilities and CAPABILITY_CTAP_1 > 0\n    val hasCtap2Support: Boolean\n        get() = capabilities and CAPABILITY_CTAP_2 > 0\n    val hasCtap21Support: Boolean\n        get() = capabilities and CAPABILITY_CTAP_2_1 > 0\n    val hasClientPin: Boolean\n        get() = capabilities and CAPABILITY_CLIENT_PIN > 0\n    val hasWinkSupport: Boolean\n        get() = capabilities and CAPABILITY_WINK > 0\n    val canMakeCredentialWithoutUserVerification: Boolean\n        get() = capabilities and CAPABILITY_MAKE_CRED_WITHOUT_UV > 0\n    val hasUserVerificationSupport: Boolean\n        get() = capabilities and CAPABILITY_USER_VERIFICATION > 0\n    val hasResidentKey: Boolean\n        get() = capabilities and CAPABILITY_RESIDENT_KEY > 0\n\n    suspend fun <Q : Ctap1Request, S : Ctap1Response> runCommand(command: Ctap1Command<Q, S>): S\n    suspend fun <Q : Ctap2Request, S : Ctap2Response> runCommand(command: Ctap2Command<Q, S>): S\n}\n\nclass Ctap2StatusException(val status: Byte) : Exception(\"Received status ${(status.toInt() and 0xff).toString(16)}\")\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/transport/Transport.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.transport\n\nenum class Transport {\n    BLUETOOTH,\n    NFC,\n    USB,\n    SCREEN_LOCK\n}\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/transport/TransportHandler.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.transport\n\nimport android.content.Context\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.Bundle\nimport android.security.keystore.KeyGenParameterSpec\nimport android.security.keystore.KeyProperties\nimport android.util.Log\nimport androidx.annotation.RequiresApi\nimport com.google.android.gms.fido.fido2.api.common.*\nimport com.google.android.gms.fido.fido2.api.common.ResidentKeyRequirement.*\nimport com.google.android.gms.fido.fido2.api.common.UserVerificationRequirement.*\nimport com.upokecenter.cbor.CBORObject\nimport kotlinx.coroutines.delay\nimport org.microg.gms.fido.core.*\nimport org.microg.gms.fido.core.protocol.*\nimport org.microg.gms.fido.core.protocol.CoseKey.Companion.toByteArray\nimport org.microg.gms.fido.core.protocol.msgs.*\nimport org.microg.gms.fido.core.transport.nfc.CtapNfcMessageStatusException\nimport org.microg.gms.fido.core.transport.usb.ctaphid.CtapHidMessageStatusException\nimport java.math.BigInteger\nimport java.nio.charset.StandardCharsets\nimport java.security.AlgorithmParameters\nimport java.security.KeyFactory\nimport java.security.KeyPairGenerator\nimport java.security.MessageDigest\nimport java.security.interfaces.ECPublicKey\nimport java.security.spec.ECGenParameterSpec\nimport java.security.spec.ECParameterSpec\nimport java.security.spec.ECPoint\nimport java.security.spec.ECPublicKeySpec\nimport javax.crypto.Cipher\nimport javax.crypto.KeyAgreement\nimport javax.crypto.Mac\nimport javax.crypto.spec.IvParameterSpec\nimport javax.crypto.spec.SecretKeySpec\n\nabstract class TransportHandler(val transport: Transport, val callback: TransportHandlerCallback?) {\n    open val isSupported: Boolean\n        get() = false\n\n    open suspend fun start(options: RequestOptions, callerPackage: String, pinRequested: Boolean = false, pin: String? = null, userInfo: String? = null): AuthenticatorResponse =\n        throw RequestHandlingException(ErrorCode.NOT_SUPPORTED_ERR)\n\n    open fun shouldBeUsedInstantly(options: RequestOptions): Boolean = false\n    fun invokeStatusChanged(status: String, extras: Bundle? = null) =\n        callback?.onStatusChanged(transport, status, extras)\n\n    private suspend fun ctap1DeviceHasCredential(\n        connection: CtapConnection,\n        challenge: ByteArray,\n        application: ByteArray,\n        descriptor: PublicKeyCredentialDescriptor\n    ): Boolean {\n        try {\n            connection.runCommand(U2fAuthenticationCommand(0x07, challenge, application, descriptor.id))\n            return true\n        } catch (e: CtapHidMessageStatusException) {\n            return e.status == 0x6985;\n        } catch (e: CtapNfcMessageStatusException) {\n            return e.status == 0x6985;\n        }\n    }\n\n    private suspend fun ctap2register(\n        connection: CtapConnection,\n        options: RequestOptions,\n        clientDataHash: ByteArray,\n        requireResidentKey: Boolean,\n        requireUserVerification: Boolean,\n        pinToken: ByteArray? = null\n    ): Pair<AuthenticatorMakeCredentialResponse, ByteArray?> {\n\n        // The CTAP2 spec states that the requireUserVerification option from WebAuthn should map\n        // to the \"uv\" option OR the pinAuth/pinProtocl options in the CTAP standard.\n        // https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html#authenticatorGetInfo\n        // Later drafts of the standard are much more explicit about this, and state that platforms\n        // MUST NOT include the \"uv\" option key if the authenticator does not support built-in\n        // verification, and that they MUST NOT include both the \"uv\" option key and the pinUvAuth\n        // parameter in the same request\n        // https://fidoalliance.org/specs/fido-v2.2-rd-20230321/fido-client-to-authenticator-protocol-v2.2-rd-20230321.html#authenticatorMakeCredential\n        val ctap2RequireVerification = requireUserVerification && (pinToken == null)\n\n        val reqOptions = AuthenticatorMakeCredentialRequest.Companion.Options(\n            requireResidentKey,\n            ctap2RequireVerification\n        )\n\n        val extensions = mutableMapOf<String, CBORObject>()\n        if (options.authenticationExtensions?.fidoAppIdExtension?.appId != null) {\n            extensions[\"appidExclude\"] =\n                options.authenticationExtensions!!.fidoAppIdExtension!!.appId.encodeAsCbor()\n        }\n        if (options.authenticationExtensions?.userVerificationMethodExtension?.uvm != null) {\n            extensions[\"uvm\"] =\n                options.authenticationExtensions!!.userVerificationMethodExtension!!.uvm.encodeAsCbor()\n        }\n\n        var pinProtocol: Int? = null\n        var pinHashEnc: ByteArray? = null\n        if (pinToken != null) {\n            val secretKeySpec = SecretKeySpec(pinToken, \"HmacSHA256\")\n            val mac = Mac.getInstance(\"HmacSHA256\")\n            mac.init(secretKeySpec)\n            pinHashEnc = mac.doFinal(clientDataHash).sliceArray(IntRange(0, 15))\n            pinProtocol = 1\n        }\n\n        val request = AuthenticatorMakeCredentialRequest(\n            clientDataHash,\n            options.registerOptions.rp,\n            options.registerOptions.user,\n            options.registerOptions.parameters,\n            options.registerOptions.excludeList.orEmpty(),\n            extensions,\n            reqOptions,\n            pinHashEnc,\n            pinProtocol\n        )\n        val response = connection.runCommand(AuthenticatorMakeCredentialCommand(request))\n        val credentialId = AuthenticatorData.decode(response.authData).attestedCredentialData?.id\n        return response to credentialId\n    }\n\n    private suspend fun ctap1register(\n        connection: CtapConnection,\n        options: RequestOptions,\n        clientDataHash: ByteArray\n    ): Pair<AuthenticatorMakeCredentialResponse, ByteArray> {\n        val rpIdHash = options.rpId.toByteArray().digest(\"SHA-256\")\n        val appIdHash =\n            options.authenticationExtensions?.fidoAppIdExtension?.appId?.toByteArray()?.digest(\"SHA-256\")\n        if (!options.registerOptions.parameters.isNullOrEmpty() && options.registerOptions.parameters.all { it.algorithmIdAsInteger != -7 })\n            throw IllegalArgumentException(\"Can't use CTAP1 protocol for non ES256 requests\")\n        if (options.registerOptions.authenticatorSelection?.requireResidentKey == true)\n            throw IllegalArgumentException(\"Can't use CTAP1 protocol when resident key required\")\n        val hasCredential = options.registerOptions.excludeList.orEmpty().any { cred ->\n            ctap1DeviceHasCredential(connection, clientDataHash, rpIdHash, cred) ||\n                    if (appIdHash != null) {\n                        ctap1DeviceHasCredential(connection, clientDataHash, appIdHash, cred)\n                    } else {\n                        false\n                    }\n        }\n        while (true) {\n            try {\n                val response = connection.runCommand(U2fRegistrationCommand(clientDataHash, rpIdHash))\n                if (hasCredential) throw RequestHandlingException(\n                    ErrorCode.NOT_ALLOWED_ERR,\n                    \"An excluded credential has already been registered with the device\"\n                )\n                require(response.userPublicKey[0] == 0x04.toByte())\n                val coseKey = CoseKey(\n                    EC2Algorithm.ES256,\n                    response.userPublicKey.sliceArray(1 until 33),\n                    response.userPublicKey.sliceArray(33 until 65),\n                    1\n                )\n                val credentialData =\n                    AttestedCredentialData(ByteArray(16), response.keyHandle, coseKey.encode())\n                val authData = AuthenticatorData(\n                    options.rpId.toByteArray().digest(\"SHA-256\"),\n                    true,\n                    false,\n                    0,\n                    credentialData\n                )\n                val attestationObject = if (options.registerOptions.skipAttestation) {\n                    NoneAttestationObject(authData)\n                } else {\n                    FidoU2fAttestationObject(authData, response.signature, response.attestationCertificate)\n                }\n                val ctap2Response = AuthenticatorMakeCredentialResponse(\n                    authData.encode(),\n                    attestationObject.fmt,\n                    attestationObject.attStmt\n                )\n                return ctap2Response to response.keyHandle\n            } catch (e: CtapHidMessageStatusException) {\n                if (e.status != 0x6985) {\n                    throw e\n                }\n            }\n            delay(100)\n        }\n    }\n\n    internal suspend fun register(\n        connection: CtapConnection,\n        context: Context,\n        options: RequestOptions,\n        callerPackage: String,\n        pinRequested: Boolean,\n        pin: String?\n    ): AuthenticatorAttestationResponse {\n        val (clientData, clientDataHash) = getClientDataAndHash(context, options, callerPackage)\n\n        val requireResidentKey = when (options.registerOptions.authenticatorSelection?.residentKeyRequirement) {\n            RESIDENT_KEY_REQUIRED -> true\n            RESIDENT_KEY_PREFERRED -> connection.hasResidentKey\n            RESIDENT_KEY_DISCOURAGED -> false\n            // If residentKeyRequirement is not set, use the value for requireResidentKey\n            // Default value for requireResidentKey is false\n            else -> options.registerOptions.authenticatorSelection?.requireResidentKey == true\n        }\n\n        val requireUserVerification = when(options.registerOptions.authenticatorSelection?.requireUserVerification) {\n            REQUIRED -> true\n            DISCOURAGED -> false\n            // PREFERRED is the default, according to the standard\n            // https://www.w3.org/TR/webauthn-3/#dom-authenticatorselectioncriteria-userverification\n            // If preferred, only return true if connection is capable of user verification\n            else -> connection.hasClientPin || connection.hasUserVerificationSupport\n        }\n        // If the authenticator has a built-in verification method, let that take precedence over\n        // client PIN\n        val requiresPin = requireUserVerification && !connection.hasUserVerificationSupport && connection.hasClientPin\n\n        val (response, keyHandle) = when {\n            connection.hasCtap2Support && (requireResidentKey || requiresPin) -> {\n                try {\n                    var pinToken: ByteArray? = null\n\n                    // If we previously requested a pin and the user cancelled it (ie. pinRequested\n                    // is true and pin is still null), don't throw the exception, and pass the request\n                    // to the authenticator without a pin.\n                    if (requiresPin && !pinRequested && pin == null) {\n                        throw MissingPinException()\n                    }\n\n                    if (requiresPin && pin != null && SDK_INT >= 23) {\n                        pinToken = ctap2getPinToken(connection, pin)\n                    }\n\n                    // Authenticators seem to give a response even without a PIN token, so we'll allow\n                    // the client to call this even without having a PIN token set\n                    ctap2register(connection, options, clientDataHash, requireResidentKey, requireUserVerification, pinToken)\n                } catch (e: Ctap2StatusException) {\n                    if (e.status == 0x36.toByte()) {\n                        throw MissingPinException()\n                    } else if (e.status == 0x31.toByte()) {\n                        throw WrongPinException()\n                    } else {\n                        throw e\n                    }\n                }\n            }\n            connection.hasCtap1Support -> ctap1register(connection, options, clientDataHash)\n            else -> throw IllegalStateException()\n        }\n        return AuthenticatorAttestationResponse(\n            keyHandle ?: ByteArray(0).also { Log.w(TAG, \"keyHandle was null\") },\n            clientData,\n            AnyAttestationObject(response.authData, response.fmt, response.attStmt).encode(),\n            connection.transports.toTypedArray()\n        )\n    }\n\n\n    private suspend fun ctap2sign(\n        connection: CtapConnection,\n        options: RequestOptions,\n        clientDataHash: ByteArray,\n        requireUserVerification: Boolean,\n        pinToken: ByteArray? = null\n    ): Pair<AuthenticatorGetAssertionResponse, ByteArray?> {\n        val reqOptions = AuthenticatorGetAssertionRequest.Companion.Options(\n            // The specification states that the WebAuthn requireUserVerification option should map to\n            // the CTAP2 \"uv\" flag OR pinAuth/pinProtocol. Therefore, set this flag to false if\n            // a pinToken is present\n            userVerification = requireUserVerification && (pinToken == null)\n        )\n        val extensions = mutableMapOf<String, CBORObject>()\n        if (options.authenticationExtensions?.fidoAppIdExtension?.appId != null) {\n            extensions[\"appid\"] = options.authenticationExtensions!!.fidoAppIdExtension!!.appId.encodeAsCbor()\n        }\n        if (options.authenticationExtensions?.userVerificationMethodExtension?.uvm != null) {\n            extensions[\"uvm\"] =\n                options.authenticationExtensions!!.userVerificationMethodExtension!!.uvm.encodeAsCbor()\n        }\n\n        var pinProtocol: Int? = null\n        var pinHashEnc: ByteArray? = null\n        if (pinToken != null) {\n            val secretKeySpec = SecretKeySpec(pinToken, \"HmacSHA256\")\n            val mac = Mac.getInstance(\"HmacSHA256\")\n            mac.init(secretKeySpec)\n            pinHashEnc = mac.doFinal(clientDataHash).sliceArray(IntRange(0, 15))\n            pinProtocol = 1\n        }\n\n        val request = AuthenticatorGetAssertionRequest(\n            options.rpId,\n            clientDataHash,\n            options.signOptions.allowList.orEmpty(),\n            extensions,\n            reqOptions,\n            pinHashEnc,\n            pinProtocol\n        )\n        val ctap2Response = connection.runCommand(AuthenticatorGetAssertionCommand(request))\n        return ctap2Response to ctap2Response.credential?.id\n    }\n\n    @RequiresApi(23)\n    private suspend fun ctap2getPinToken(\n        connection: CtapConnection,\n        pin: String\n    ): ByteArray? {\n        // Ask for shared secret from authenticator\n        val sharedSecretRequest = AuthenticatorClientPINRequest(\n            AuthenticatorClientPINRequest.PIN_PROTOCOL_VERSION_ONE,\n            AuthenticatorClientPINRequest.GET_KEY_AGREEMENT\n        )\n        val sharedSecretResponse = connection.runCommand(AuthenticatorClientPINCommand(sharedSecretRequest))\n\n        if (sharedSecretResponse.keyAgreement == null) {\n            return null;\n        }\n\n        val x = sharedSecretResponse.keyAgreement.x\n        val y = sharedSecretResponse.keyAgreement.y\n\n        val curveName = when (sharedSecretResponse.keyAgreement.curveId) {\n            1 -> \"secp256r1\"\n            2 -> \"secp384r1\"\n            3 -> \"secp521r1\"\n            4 -> \"x25519\"\n            5 -> \"x448\"\n            6 -> \"Ed25519\"\n            7 -> \"Ed448\"\n            else -> return null\n        }\n\n        // Perform Diffie Hellman key generation\n        val generator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_EC)\n        generator.initialize(ECGenParameterSpec(curveName))\n\n        val myKeyPair = generator.generateKeyPair()\n        val parameters = AlgorithmParameters.getInstance(\"EC\")\n        parameters.init(ECGenParameterSpec(curveName))\n        val parameterSpec = parameters.getParameterSpec(ECParameterSpec::class.java)\n        val serverKey = KeyFactory.getInstance(\"EC\")\n            .generatePublic(ECPublicKeySpec(ECPoint(BigInteger(1, x), BigInteger(1, y)), parameterSpec))\n        val keyAgreement = KeyAgreement.getInstance(\"ECDH\")\n        keyAgreement.init(myKeyPair.private)\n        keyAgreement.doPhase(serverKey, true)\n\n        // We get the key for the encryption used between the client and the platform by doing an\n        // SHA 256 hash of the shared secret\n        val sharedSecret = keyAgreement.generateSecret()\n        val hash = MessageDigest.getInstance(\"SHA-256\")\n        hash.update(sharedSecret)\n        val sharedKey = SecretKeySpec(hash.digest(), \"AES\")\n\n        // Hash the PIN, and then encrypt the first 16 bytes of the hash using the shared key\n        val pinHash = MessageDigest.getInstance(\"SHA-256\").digest(pin.toByteArray(StandardCharsets.UTF_8))\n        val cipher = Cipher.getInstance(\"AES/CBC/NoPadding\")\n        cipher.init(Cipher.ENCRYPT_MODE, sharedKey, IvParameterSpec(ByteArray(16)))\n        val pinHashEnc = cipher.doFinal(pinHash.sliceArray(IntRange(0,15)))\n\n        // Now, send back the encrypted pin hash, as well as the public portion of our key so\n        // the authenticator also may perform Diffie Hellman\n        val publicKey = myKeyPair.public\n        if (publicKey !is ECPublicKey) {\n            return null\n        }\n        val coseKey = CoseKey(\n            sharedSecretResponse.keyAgreement.algorithm,\n            publicKey.w.affineX.toByteArray(32),\n            publicKey.w.affineY.toByteArray(32),\n            sharedSecretResponse.keyAgreement.curveId\n        )\n\n        val pinTokenRequest = AuthenticatorClientPINRequest(\n            AuthenticatorClientPINRequest.PIN_PROTOCOL_VERSION_ONE,\n            AuthenticatorClientPINRequest.GET_PIN_TOKEN,\n            coseKey,\n            pinHashEnc = pinHashEnc\n        )\n\n        // The pin token is returned to us in encrypted form. Decrypt it, so we may use it when HMAC\n        // signing later\n        val pinTokenResponse = connection.runCommand(AuthenticatorClientPINCommand(pinTokenRequest))\n        cipher.init(Cipher.DECRYPT_MODE, sharedKey, IvParameterSpec(ByteArray(16)))\n        return cipher.doFinal(pinTokenResponse.pinToken)\n    }\n\n    private suspend fun ctap1sign(\n        connection: CtapConnection,\n        options: RequestOptions,\n        clientDataHash: ByteArray,\n        rpIdHash: ByteArray\n    ): Pair<AuthenticatorGetAssertionResponse, ByteArray> {\n        val cred = options.signOptions.allowList.orEmpty().firstOrNull { cred ->\n            ctap1DeviceHasCredential(connection, clientDataHash, rpIdHash, cred)\n        } ?: options.signOptions.allowList!!.first()\n\n        while (true) {\n            try {\n                val response = connection.runCommand(U2fAuthenticationCommand(0x03, clientDataHash, rpIdHash, cred.id))\n                val authData = AuthenticatorData(rpIdHash, response.userPresence, false, response.counter)\n                val ctap2Response = AuthenticatorGetAssertionResponse(\n                    cred,\n                    authData.encode(),\n                    response.signature,\n                    null,\n                    null\n                )\n                return ctap2Response to cred.id\n            } catch (e: CtapHidMessageStatusException) {\n                if (e.status != 0x6985) {\n                    throw e\n                }\n                delay(100)\n            }\n        }\n    }\n\n    private suspend fun ctap1sign(\n        connection: CtapConnection,\n        options: RequestOptions,\n        clientDataHash: ByteArray\n    ): Pair<AuthenticatorGetAssertionResponse, ByteArray> {\n        try {\n            val rpIdHash = options.rpId.toByteArray().digest(\"SHA-256\")\n            return ctap1sign(connection, options, clientDataHash, rpIdHash)\n        } catch (e: Exception) {\n            try {\n                if (options.authenticationExtensions?.fidoAppIdExtension?.appId != null) {\n                    val appIdHash = options.authenticationExtensions!!.fidoAppIdExtension!!.appId.toByteArray()\n                        .digest(\"SHA-256\")\n                    return ctap1sign(connection, options, clientDataHash, appIdHash)\n                }\n            } catch (e2: Exception) {\n            }\n            // Throw original\n            throw e\n        }\n    }\n\n    internal suspend fun sign(\n        connection: CtapConnection,\n        context: Context,\n        options: RequestOptions,\n        callerPackage: String,\n        pinRequested: Boolean,\n        pin: String?\n    ): AuthenticatorAssertionResponse {\n        val (clientData, clientDataHash) = getClientDataAndHash(context, options, callerPackage)\n\n        val (response, credentialId) = when {\n            connection.hasCtap2Support -> {\n                try {\n                    var pinToken: ByteArray? = null\n\n                    val requireUserVerification = when(options.signOptions.requireUserVerification) {\n                        REQUIRED -> true\n                        DISCOURAGED -> false\n                        // PREFERRED is the default, according to the standard\n                        // https://www.w3.org/TR/webauthn-3/#dom-authenticatorselectioncriteria-userverification\n                        else -> {\n                            // If preferred, only return true if connection is capable of user verification\n                            connection.hasClientPin || connection.hasUserVerificationSupport\n                        }\n                    }\n                    // If the authenticator has built in user verification, let that take precedence\n                    // over PIN verification\n                    val requiresPin = requireUserVerification && !connection.hasUserVerificationSupport && connection.hasClientPin\n\n                    // If we require a PIN, throw an exception up to the AuthenticatorActivity\n                    // However, if we've already asked the user for a PIN and the user cancelled\n                    // (ie. pinRequested is true), continue without asking\n                    if (requiresPin && !pinRequested && pin == null) {\n                        throw MissingPinException()\n                    }\n\n                    if (requiresPin && pin != null && SDK_INT >= 23) {\n                        pinToken = ctap2getPinToken(connection, pin)\n                    }\n\n                    // Authenticators seem to give a response even without a PIN token, so we'll allow\n                    // the client to call this even without having a PIN token set\n                    ctap2sign(connection, options, clientDataHash, requireUserVerification, pinToken)\n                } catch (e: Ctap2StatusException) {\n                    if (e.status == 0x31.toByte()) {\n                        throw WrongPinException()\n                    } else if (e.status == 0x36.toByte()) {\n                        throw MissingPinException()\n                    } else if (e.status == 0x2e.toByte() &&\n                        connection.hasCtap1Support && connection.hasClientPin &&\n                        options.signOptions.allowList.orEmpty().isNotEmpty() &&\n                        options.signOptions.requireUserVerification != REQUIRED\n                    ) {\n                        Log.d(TAG, \"Falling back to CTAP1/U2F\")\n                        try {\n                            ctap1sign(connection, options, clientDataHash)\n                        } catch (e2: Exception) {\n                            // Throw original exception\n                            throw e\n                        }\n                    } else {\n                        throw e\n                    }\n                }\n            }\n            connection.hasCtap1Support -> ctap1sign(connection, options, clientDataHash)\n            else -> throw IllegalStateException()\n        }\n        return AuthenticatorAssertionResponse(\n            credentialId ?: ByteArray(0).also { Log.w(TAG, \"keyHandle was null\") },\n            clientData,\n            response.authData,\n            response.signature,\n            null\n        )\n    }\n\n    companion object {\n        const val TAG = \"FidoTransportHandler\"\n    }\n}\n\ninterface TransportHandlerCallback {\n    fun onStatusChanged(transport: Transport, status: String, extras: Bundle? = null)\n\n    companion object {\n        @JvmStatic\n        val STATUS_WAITING_FOR_DEVICE = \"waiting-for-device\"\n\n        @JvmStatic\n        val STATUS_WAITING_FOR_USER = \"waiting-for-user\"\n\n        @JvmStatic\n        val STATUS_UNKNOWN = \"unknown\"\n    }\n}\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/transport/bluetooth/BluetoothTransportHandler.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.transport.bluetooth\n\nimport android.bluetooth.BluetoothManager\nimport android.content.Context\nimport android.os.Build.VERSION.SDK_INT\nimport androidx.core.content.getSystemService\nimport org.microg.gms.fido.core.transport.Transport\nimport org.microg.gms.fido.core.transport.TransportHandler\nimport org.microg.gms.fido.core.transport.TransportHandlerCallback\n\nclass BluetoothTransportHandler(private val context: Context, callback: TransportHandlerCallback? = null) :\n    TransportHandler(Transport.BLUETOOTH, callback) {\n    override val isSupported: Boolean\n        get() = SDK_INT >= 18 && context.getSystemService<BluetoothManager>()?.adapter != null\n}\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/transport/nfc/CtapNfcConnection.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.transport.nfc\n\nimport android.content.Context\nimport android.nfc.Tag\nimport android.nfc.tech.IsoDep\nimport android.util.Base64\nimport android.util.Log\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\nimport org.microg.gms.fido.core.protocol.msgs.*\nimport org.microg.gms.fido.core.transport.*\nimport org.microg.gms.utils.toBase64\n\nclass CtapNfcConnection(\n    val context: Context,\n    val tag: Tag\n) : CtapConnection {\n    private val isoDep = IsoDep.get(tag)\n    override var capabilities: Int = 0\n    override var transports: List<String> = listOf(\"nfc\")\n\n    override suspend fun <Q : Ctap1Request, S : Ctap1Response> runCommand(command: Ctap1Command<Q, S>): S {\n        require(hasCtap1Support)\n        Log.d(TAG, \"Send CTAP1 command: ${command.request.apdu.toBase64(Base64.NO_WRAP)}\")\n        val (statusCode, payload) = decodeResponseApdu(isoDep.transceive(command.request.apdu))\n        Log.d(TAG, \"Received CTAP1 response(${(statusCode.toInt() and 0xffff).toString(16)}): ${payload.toBase64(Base64.NO_WRAP)}\")\n        if (statusCode != 0x9000.toShort()) {\n            throw CtapNfcMessageStatusException(statusCode.toInt() and 0xffff)\n        }\n        return command.decodeResponse(statusCode, payload)\n    }\n\n    override suspend fun <Q : Ctap2Request, S : Ctap2Response> runCommand(command: Ctap2Command<Q, S>): S {\n        require(hasCtap2Support)\n        val request = encodeCommandApdu(0x80.toByte(), 0x10, 0x00, 0x00, byteArrayOf(command.request.commandByte) + command.request.payload, extended = true)\n        Log.d(TAG, \"Send CTAP2 command: ${request.toBase64(Base64.NO_WRAP)} (${command.request.commandByte} - ${command.request.parameters})\")\n        var (statusCode, payload) = decodeResponseApdu(isoDep.transceive(request))\n        Log.d(TAG, \"Received CTAP2 response(${(statusCode.toInt() and 0xffff).toString(16)}): ${payload.toBase64(Base64.NO_WRAP)}\")\n        while (statusCode == 0x9100.toShort() || (statusCode > 0x6100.toShort() && statusCode < 0x6200.toShort())) {\n            Log.d(TAG, \"Sending GETRESPONSE\")\n            val res = decodeResponseApdu(isoDep.transceive(encodeCommandApdu(0x00, 0xC0.toByte(), 0x00,0x00)))\n            Log.d(TAG, \"Received CTAP2 response(${(statusCode.toInt() and 0xffff).toString(16)}): ${payload.toBase64(Base64.NO_WRAP)}\")\n            if (statusCode < 0x6200.toShort()) {\n                payload = payload.plus(res.second)\n            } else {\n                payload = res.second\n            }\n            statusCode = res.first\n        }\n        if (statusCode != 0x9000.toShort()) {\n            throw CtapNfcMessageStatusException(statusCode.toInt() and 0xffff)\n        }\n        require(payload.isNotEmpty())\n        val ctapStatusCode = payload[0]\n        if (ctapStatusCode != 0x00.toByte()) {\n            throw Ctap2StatusException(ctapStatusCode)\n        }\n        return command.decodeResponse(payload, 1)\n    }\n\n    private fun select(aid: ByteArray): Pair<Short, ByteArray> {\n        Log.d(TAG, \"Selecting AID: ${aid.toBase64(Base64.NO_WRAP)}\")\n        return decodeResponseApdu(isoDep.transceive(encodeCommandApdu(0x00, 0xa4.toByte(), 0x04, 0x00, aid)))\n    }\n\n    private fun deselect() = isoDep.transceive(encodeCommandApdu(0x80.toByte(), 0x12, 0x01, 0x02))\n\n    private suspend fun fetchCapabilities() {\n        val response = runCommand(AuthenticatorGetInfoCommand())\n        Log.d(TAG, \"Got info: $response\")\n        capabilities = capabilities or CAPABILITY_CTAP_2 or\n                (if (response.versions.contains(\"FIDO_2_1\")) CAPABILITY_CTAP_2_1 else 0) or\n                (if (response.options.clientPin == true) CAPABILITY_CLIENT_PIN else 0) or\n                (if (response.options.userVerification == true) CAPABILITY_USER_VERIFICATION else 0) or\n                (if (response.options.residentKey == true) CAPABILITY_RESIDENT_KEY else 0)\n        if (response.transports != null) transports = response.transports\n    }\n\n    suspend fun open(): Boolean = withContext(Dispatchers.IO) {\n        isoDep.timeout = 5000\n        isoDep.connect()\n        val (statusCode, version) = select(FIDO2_AID)\n        if (statusCode == 0x9000.toShort()) {\n            Log.d(TAG, \"Device sent version: ${version.decodeToString()}\")\n            when (version.decodeToString()) {\n                \"FIDO_2_0\" -> {\n                    capabilities = CAPABILITY_CTAP_2\n                    try {\n                        fetchCapabilities()\n                    } catch (e: Exception) {\n                        Log.w(TAG, e)\n                    }\n                    true\n                }\n                \"U2F_V2\" -> {\n                    capabilities = CAPABILITY_CTAP_1 or CAPABILITY_CTAP_2\n                    try {\n                        fetchCapabilities()\n                    } catch (e: Exception) {\n                        Log.w(TAG, e)\n                        capabilities = CAPABILITY_CTAP_1\n                    }\n                    true\n                }\n                else -> {\n                    false\n                }\n            }\n        } else {\n            false\n        }\n    }\n\n    suspend fun close() = withContext(Dispatchers.IO) {\n        deselect()\n        isoDep.close()\n        capabilities = 0\n    }\n\n\n    suspend fun <R> open(block: suspend (CtapNfcConnection) -> R): R {\n        if (!open()) throw RuntimeException(\"Could not open device\")\n        var exception: Throwable? = null\n        try {\n            return block(this)\n        } catch (e: Throwable) {\n            exception = e\n            throw e\n        } finally {\n            when (exception) {\n                null -> close()\n                else -> try {\n                    close()\n                } catch (closeException: Throwable) {\n                    // cause.addSuppressed(closeException) // ignored here\n                }\n            }\n        }\n    }\n\n    companion object {\n        const val TAG = \"FidoCtapNfcConnection\"\n        private val FIDO2_AID = byteArrayOf(0xA0.toByte(), 0x00, 0x00, 0x06, 0x47, 0x2F, 0x00, 0x01)\n    }\n}\n\nclass CtapNfcMessageStatusException(val status: Int) : Exception(\"Received status ${status.toString(16)}\")\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/transport/nfc/NfcTransportHandler.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.transport.nfc\n\nimport android.app.Activity\nimport android.app.ActivityOptions\nimport android.app.PendingIntent\nimport android.content.Intent\nimport android.content.IntentFilter\nimport android.nfc.NfcAdapter\nimport android.nfc.Tag\nimport android.nfc.tech.IsoDep\nimport android.os.Build.VERSION.SDK_INT\nimport android.util.Log\nimport androidx.core.app.OnNewIntentProvider\nimport androidx.core.app.PendingIntentCompat\nimport androidx.core.util.Consumer\nimport com.google.android.gms.fido.fido2.api.common.AuthenticatorAssertionResponse\nimport com.google.android.gms.fido.fido2.api.common.AuthenticatorAttestationResponse\nimport com.google.android.gms.fido.fido2.api.common.AuthenticatorResponse\nimport com.google.android.gms.fido.fido2.api.common.RequestOptions\nimport kotlinx.coroutines.CancellationException\nimport kotlinx.coroutines.CompletableDeferred\nimport org.microg.gms.fido.core.MissingPinException\nimport org.microg.gms.fido.core.RequestOptionsType\nimport org.microg.gms.fido.core.WrongPinException\nimport org.microg.gms.fido.core.transport.Transport\nimport org.microg.gms.fido.core.transport.TransportHandler\nimport org.microg.gms.fido.core.transport.TransportHandlerCallback\nimport org.microg.gms.fido.core.type\n\nclass NfcTransportHandler(private val activity: Activity, callback: TransportHandlerCallback? = null) :\n    TransportHandler(Transport.NFC, callback) {\n    override val isSupported: Boolean\n        get() = NfcAdapter.getDefaultAdapter(activity)?.isEnabled == true && activity is OnNewIntentProvider\n\n    private var deferred = CompletableDeferred<Tag>()\n\n    private suspend fun waitForNewNfcTag(adapter: NfcAdapter): Tag {\n        val intent = Intent(activity, activity.javaClass).apply { addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP) }\n        val piOptions = if (SDK_INT >= 34) {\n            ActivityOptions.makeBasic().apply {\n                pendingIntentCreatorBackgroundActivityStartMode =\n                    ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED\n            }.toBundle()\n        } else null\n        val pendingIntent: PendingIntent = PendingIntentCompat.getActivity(\n            activity, 0, intent,\n            0,\n            piOptions,\n            true)!!\n        adapter.enableForegroundDispatch(\n            activity,\n            pendingIntent,\n            arrayOf(IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED)),\n            arrayOf(arrayOf(IsoDep::class.java.name))\n        )\n        invokeStatusChanged(TransportHandlerCallback.STATUS_WAITING_FOR_DEVICE)\n        val tag = deferred.await()\n        deferred = CompletableDeferred()\n        return tag\n    }\n\n    suspend fun register(\n        options: RequestOptions,\n        callerPackage: String,\n        tag: Tag,\n        pinRequested: Boolean,\n        pin: String?\n    ): AuthenticatorAttestationResponse {\n        return CtapNfcConnection(activity, tag).open {\n            register(it, activity, options, callerPackage, pinRequested, pin)\n        }\n    }\n\n    suspend fun sign(\n        options: RequestOptions,\n        callerPackage: String,\n        tag: Tag,\n        pinRequested: Boolean,\n        pin: String?\n    ): AuthenticatorAssertionResponse {\n        return CtapNfcConnection(activity, tag).open {\n            sign(it, activity, options, callerPackage, pinRequested, pin)\n        }\n    }\n\n\n    suspend fun handle(\n        options: RequestOptions,\n        callerPackage: String,\n        tag: Tag,\n        pinRequested: Boolean,\n        pin: String?\n    ): AuthenticatorResponse {\n        return when (options.type) {\n            RequestOptionsType.REGISTER -> register(options, callerPackage, tag, pinRequested, pin)\n            RequestOptionsType.SIGN -> sign(options, callerPackage, tag, pinRequested, pin)\n        }\n    }\n\n\n    override suspend fun start(options: RequestOptions, callerPackage: String, pinRequested: Boolean, pin: String?, userInfo: String?): AuthenticatorResponse {\n        val adapter = NfcAdapter.getDefaultAdapter(activity)\n        val newIntentListener = Consumer<Intent> {\n            if (it?.action != NfcAdapter.ACTION_TECH_DISCOVERED) return@Consumer\n            val tag = it.getParcelableExtra<Tag>(NfcAdapter.EXTRA_TAG) ?: return@Consumer\n            deferred.complete(tag)\n        }\n        try {\n            (activity as OnNewIntentProvider).addOnNewIntentListener(newIntentListener)\n            var ex: Exception? = null\n            for (i in 1..2) {\n                val tag = waitForNewNfcTag(adapter)\n                try {\n                    return handle(options, callerPackage, tag, pinRequested, pin)\n                } catch (e: CancellationException) {\n                    throw e\n                } catch (e: MissingPinException) {\n                    throw e\n                } catch (e: WrongPinException) {\n                    throw e\n                } catch (e: Exception) {\n                    Log.w(TAG, e)\n                    ex = e\n                }\n            }\n            throw ex ?: Exception(\"Unknown exception\")\n        } finally {\n            (activity as OnNewIntentProvider).removeOnNewIntentListener(newIntentListener)\n        }\n    }\n\n    companion object {\n        const val TAG = \"FidoNfcHandler\"\n    }\n}\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/transport/screenlock/ScreenLockCredentialStore.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.transport.screenlock\n\nimport android.content.Context\nimport android.content.pm.PackageManager\nimport android.database.sqlite.SQLiteDatabase\nimport android.database.sqlite.SQLiteOpenHelper\nimport android.os.Build.VERSION.SDK_INT\nimport android.security.keystore.KeyGenParameterSpec\nimport android.security.keystore.KeyPermanentlyInvalidatedException\nimport android.security.keystore.KeyProperties\nimport android.security.keystore.StrongBoxUnavailableException\nimport android.util.Base64\nimport android.util.Log\nimport androidx.annotation.RequiresApi\nimport org.microg.gms.utils.toBase64\nimport java.security.*\nimport java.security.cert.Certificate\nimport java.security.spec.ECGenParameterSpec\nimport kotlin.random.Random\n\n@RequiresApi(23)\nclass ScreenLockCredentialStore(val context: Context) {\n    private val keyStore by lazy { KeyStore.getInstance(\"AndroidKeyStore\").apply { load(null) } }\n\n    private fun getAlias(rpId: String, keyId: ByteArray): String =\n        \"1.\" + keyId.toBase64(Base64.NO_PADDING, Base64.NO_WRAP) + \".\" + rpId\n\n    private fun getPrivateKey(rpId: String, keyId: ByteArray) = keyStore.getKey(getAlias(rpId, keyId), null) as? PrivateKey\n\n    @RequiresApi(23)\n    fun createKey(rpId: String, challenge: ByteArray): ByteArray {\n        var useStrongbox = false\n        if (SDK_INT >= 28) useStrongbox = context.packageManager.hasSystemFeature(PackageManager.FEATURE_STRONGBOX_KEYSTORE)\n        val keyId = Random.nextBytes(32)\n        val identifier = getAlias(rpId, keyId)\n        Log.d(TAG, \"Creating key for $identifier\")\n        val generator = KeyPairGenerator.getInstance(\"EC\", \"AndroidKeyStore\")\n        val builder = KeyGenParameterSpec.Builder(identifier, KeyProperties.PURPOSE_SIGN)\n            .setDigests(KeyProperties.DIGEST_SHA256)\n            .setAlgorithmParameterSpec(ECGenParameterSpec(\"secp256r1\"))\n            .setUserAuthenticationRequired(true)\n        if (SDK_INT >= 28) builder.setIsStrongBoxBacked(useStrongbox)\n        if (SDK_INT >= 24) builder.setAttestationChallenge(challenge)\n\n        var generatedKeypair = false\n        val exceptionClassesCaught = HashSet<Class<Exception>>()\n        while (!generatedKeypair) {\n            try {\n                generator.initialize(builder.build())\n                generator.generateKeyPair()\n                generatedKeypair = true\n            } catch (e: Exception) {\n                // Catch each exception class at most once.\n                // If we've caught the exception before, tried to correct it, and still catch the\n                // same exception, then we can't fix it and the exception should be thrown further\n                if (exceptionClassesCaught.contains(e.javaClass)) {\n                    throw e\n                }\n                exceptionClassesCaught.add(e.javaClass)\n\n                if (SDK_INT >= 28 && e is StrongBoxUnavailableException) {\n                    Log.w(TAG, \"Failed with StrongBox, retrying without it...\")\n                    // Not all algorithms are backed by the Strongbox. If the Strongbox doesn't\n                    // support this keypair, fall back to TEE\n                    builder.setIsStrongBoxBacked(false)\n                } else if (SDK_INT >= 24 && e is ProviderException) {\n                    Log.w(TAG, \"Failed with attestation challenge, retrying without it...\")\n                    // This ProviderException is often thrown if the TEE or Strongbox doesn't have\n                    // a built-in key to attest the new key pair with. If this happens, remove the\n                    // attestation challenge and create an unattested key\n                    builder.setAttestationChallenge(null)\n                } else {\n                    // We don't know how to handle other errors, so they should be thrown up the\n                    // system\n                    throw e\n                }\n            }\n        }\n\n        return keyId\n    }\n\n    fun getPublicKey(rpId: String, keyId: ByteArray): PublicKey? =\n        keyStore.getCertificate(getAlias(rpId, keyId))?.publicKey\n\n    fun getCertificateChain(rpId: String, keyId: ByteArray): Array<Certificate> =\n        keyStore.getCertificateChain(getAlias(rpId, keyId))\n\n    fun getSignature(rpId: String, keyId: ByteArray): Signature? {\n        try {\n            val privateKey = getPrivateKey(rpId, keyId) ?: return null\n            val signature = Signature.getInstance(\"SHA256withECDSA\")\n            signature.initSign(privateKey)\n            return signature\n        } catch (e: KeyPermanentlyInvalidatedException) {\n            keyStore.deleteEntry(getAlias(rpId, keyId))\n            throw e\n        }\n    }\n\n    fun containsKey(rpId: String, keyId: ByteArray): Boolean = keyStore.containsAlias(getAlias(rpId, keyId))\n\n    companion object {\n        const val TAG = \"FidoLockStore\"\n    }\n}\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/transport/screenlock/ScreenLockTransportHandler.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.transport.screenlock\n\nimport android.app.KeyguardManager\nimport android.os.Build.VERSION.SDK_INT\nimport android.util.Base64\nimport android.util.Log\nimport androidx.annotation.RequiresApi\nimport androidx.biometric.BiometricPrompt\nimport androidx.core.content.getSystemService\nimport androidx.fragment.app.FragmentActivity\nimport com.google.android.gms.fido.fido2.api.common.*\nimport com.google.android.gms.safetynet.SafetyNet\nimport com.google.android.gms.tasks.await\nimport kotlinx.coroutines.suspendCancellableCoroutine\nimport org.microg.gms.common.Constants\nimport org.microg.gms.fido.core.*\nimport org.microg.gms.fido.core.protocol.*\nimport org.microg.gms.fido.core.transport.Transport\nimport org.microg.gms.fido.core.transport.TransportHandler\nimport org.microg.gms.fido.core.transport.TransportHandlerCallback\nimport org.microg.gms.utils.toBase64\nimport java.security.Signature\nimport java.security.interfaces.ECPublicKey\nimport kotlin.coroutines.resume\nimport kotlin.coroutines.resumeWithException\n\n@RequiresApi(23)\nclass ScreenLockTransportHandler(private val activity: FragmentActivity, callback: TransportHandlerCallback? = null) :\n    TransportHandler(Transport.SCREEN_LOCK, callback) {\n    private val store by lazy { ScreenLockCredentialStore(activity) }\n    private val database by lazy { Database(activity) }\n\n    override val isSupported: Boolean\n        get() = activity.getSystemService<KeyguardManager>()?.isDeviceSecure == true\n\n    suspend fun showBiometricPrompt(applicationName: String, signature: Signature?) {\n        suspendCancellableCoroutine<BiometricPrompt.AuthenticationResult> { continuation ->\n            val prompt = BiometricPrompt(activity, object : BiometricPrompt.AuthenticationCallback() {\n                override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {\n                    continuation.resume(result)\n                }\n\n                override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {\n                    val errorMessage = when (errorCode) {\n                        BiometricPrompt.ERROR_CANCELED, BiometricPrompt.ERROR_USER_CANCELED, BiometricPrompt.ERROR_NEGATIVE_BUTTON -> \"User canceled verification\"\n                        else -> errString.toString()\n                    }\n                    continuation.resumeWithException(RequestHandlingException(ErrorCode.NOT_ALLOWED_ERR, errorMessage))\n                }\n            })\n            val promptInfo = BiometricPrompt.PromptInfo.Builder()\n                .setTitle(activity.getString(R.string.fido_biometric_prompt_title))\n                .setDescription(\n                    activity.getString(\n                        R.string.fido_biometric_prompt_body,\n                        applicationName\n                    )\n                )\n                .setNegativeButtonText(activity.getString(android.R.string.cancel))\n                .build()\n            invokeStatusChanged(TransportHandlerCallback.STATUS_WAITING_FOR_USER)\n            if (signature != null) {\n                prompt.authenticate(promptInfo, BiometricPrompt.CryptoObject(signature))\n            } else {\n                prompt.authenticate(promptInfo)\n            }\n            continuation.invokeOnCancellation { prompt.cancelAuthentication() }\n        }\n    }\n\n    suspend fun getActiveSignature(\n        options: RequestOptions,\n        callingPackage: String,\n        keyId: ByteArray\n    ): Signature {\n        val signature =\n            store.getSignature(options.rpId, keyId) ?: throw RequestHandlingException(ErrorCode.INVALID_STATE_ERR)\n        showBiometricPrompt(getApplicationName(activity, options, callingPackage), signature)\n        return signature\n    }\n\n    fun getCredentialData(aaguid: ByteArray, credentialId: CredentialId, coseKey: CoseKey) = AttestedCredentialData(\n        aaguid,\n        credentialId.encode(),\n        coseKey.encode()\n    )\n\n    fun getAuthenticatorData(\n        rpId: String,\n        credentialData: AttestedCredentialData?,\n        userPresent: Boolean = true,\n        userVerified: Boolean = true,\n        signCount: Int = 0\n    ) = AuthenticatorData(\n        rpId.toByteArray().digest(\"SHA-256\"),\n        userPresent = userPresent,\n        userVerified = userVerified,\n        signCount = signCount,\n        attestedCredentialData = credentialData\n    )\n\n    suspend fun register(\n        options: RequestOptions,\n        callerPackage: String\n    ): AuthenticatorAttestationResponse {\n        if (options.type != RequestOptionsType.REGISTER) throw RequestHandlingException(ErrorCode.INVALID_STATE_ERR)\n        val knownRegistrationInfo = database.getKnownRegistrationInfo(options.rpId)\n        for (descriptor in options.registerOptions.excludeList.orEmpty()) {\n            val credentialBase64 = descriptor.id.toBase64(Base64.NO_WRAP or Base64.NO_PADDING or Base64.URL_SAFE)\n            val excluded = knownRegistrationInfo.any { it.credential == credentialBase64 }\n            if (store.containsKey(options.rpId, descriptor.id) || excluded) {\n                throw RequestHandlingException(\n                    ErrorCode.NOT_ALLOWED_ERR,\n                    \"An excluded credential has already been registered with the device\"\n                )\n            }\n        }\n        val (clientData, clientDataHash) = getClientDataAndHash(activity, options, callerPackage)\n        val aaguid = if (options.registerOptions.skipAttestation) ByteArray(16) else AAGUID\n        val keyId = store.createKey(options.rpId, clientDataHash)\n        val publicKey =\n            store.getPublicKey(options.rpId, keyId) ?: throw RequestHandlingException(ErrorCode.INVALID_STATE_ERR)\n\n        // We're ignoring the signature object as we don't need it for registration\n        val signature = getActiveSignature(options, callerPackage, keyId)\n\n        val (x, y) = (publicKey as ECPublicKey).w.let { it.affineX to it.affineY }\n        val coseKey = CoseKey(EC2Algorithm.ES256, x, y, 1, 32)\n        val credentialId = CredentialId(1, keyId, options.rpId, publicKey)\n\n        val credentialData = getCredentialData(aaguid, credentialId, coseKey)\n        val authenticatorData = getAuthenticatorData(options.rpId, credentialData)\n\n        val attestationObject = if (options.registerOptions.skipAttestation) {\n            NoneAttestationObject(authenticatorData)\n        } else {\n            try {\n                if (SDK_INT >= 24) {\n                    createAndroidKeyAttestation(signature, authenticatorData, clientDataHash, options.rpId, keyId)\n                } else {\n                    createSafetyNetAttestation(authenticatorData, clientDataHash)\n                }\n            } catch (e: Exception) {\n                Log.w(\"FidoScreenLockTransport\", e)\n                NoneAttestationObject(authenticatorData)\n            }\n        }\n\n        return AuthenticatorAttestationResponse(\n            credentialId.encode(),\n            clientData,\n            attestationObject.encode(),\n            arrayOf(\"internal\")\n        )\n    }\n\n    @RequiresApi(24)\n    private fun createAndroidKeyAttestation(\n        signature: Signature,\n        authenticatorData: AuthenticatorData,\n        clientDataHash: ByteArray,\n        rpId: String,\n        keyId: ByteArray\n    ): AndroidKeyAttestationObject {\n        signature.update(authenticatorData.encode() + clientDataHash)\n        val sig = signature.sign()\n        return AndroidKeyAttestationObject(\n            authenticatorData,\n            EC2Algorithm.ES256,\n            sig,\n            store.getCertificateChain(rpId, keyId).map { it.encoded })\n    }\n\n    private suspend fun createSafetyNetAttestation(\n        authenticatorData: AuthenticatorData,\n        clientDataHash: ByteArray\n    ): AndroidSafetyNetAttestationObject {\n        val response = SafetyNet.getClient(activity).attest(\n            (authenticatorData.encode() + clientDataHash).digest(\"SHA-256\"),\n            \"AIzaSyDqVnJBjE5ymo--oBJt3On7HQx9xNm1RHA\"\n        ).await()\n        return AndroidSafetyNetAttestationObject(\n            authenticatorData,\n            Constants.GMS_VERSION_CODE.toString(),\n            response.jwsResult.toByteArray()\n        )\n    }\n\n    suspend fun sign(\n        options: RequestOptions,\n        callerPackage: String,\n        userInfo: String?\n    ): AuthenticatorAssertionResponse {\n        if (options.type != RequestOptionsType.SIGN) throw RequestHandlingException(ErrorCode.INVALID_STATE_ERR)\n        val candidates = mutableListOf<CredentialId>()\n        for (descriptor in options.signOptions.allowList.orEmpty()) {\n            try {\n                val (type, data) = CredentialId.decodeTypeAndData(descriptor.id)\n                if (type == 1.toByte() && store.containsKey(options.rpId, data)) {\n                    candidates.add(CredentialId(type, data, options.rpId, store.getPublicKey(options.rpId, data)!!))\n                }\n            } catch (e: Exception) {\n                // Not in store or unknown id\n            }\n        }\n        val knownRegistrationInfo = database.getKnownRegistrationInfo(options.rpId)\n        candidates.ifEmpty {\n            knownRegistrationInfo.mapNotNull {\n                val (type, data) = CredentialId.decodeTypeAndDataByBase64(it.credential)\n                if (type == 1.toByte() && store.containsKey(options.rpId, data)) {\n                    CredentialId(type, data, options.rpId, store.getPublicKey(options.rpId, data)!!)\n                } else null\n            }.forEach {\n                candidates.add(it)\n            }\n        }\n        if (candidates.isEmpty()) {\n            // Show a biometric prompt even if no matching key to effectively rate-limit\n            showBiometricPrompt(getApplicationName(activity, options, callerPackage), null)\n            throw RequestHandlingException(\n                ErrorCode.NOT_ALLOWED_ERR,\n                \"Cannot find credential in local KeyStore or database\"\n            )\n        }\n\n        val (clientData, clientDataHash) = getClientDataAndHash(activity, options, callerPackage)\n        val credentialUserInfo = if (userInfo != null) {\n            knownRegistrationInfo.firstOrNull { it.userJson == userInfo }\n        } else knownRegistrationInfo.firstOrNull()\n        val userHandle = credentialUserInfo?.let { PublicKeyCredentialUserEntity.parseJson(it.userJson).id }\n        val credentialId = candidates.firstOrNull { credentialUserInfo?.credential != null && credentialUserInfo.credential == it.toBase64() } ?: candidates.first()\n        val keyId = credentialId.data\n        val authenticatorData = getAuthenticatorData(options.rpId, null)\n\n        val signature = getActiveSignature(options, callerPackage, keyId)\n        signature.update(authenticatorData.encode() + clientDataHash)\n        val sig = signature.sign()\n\n        return AuthenticatorAssertionResponse(\n            credentialId.encode(),\n            clientData,\n            authenticatorData.encode(),\n            sig,\n            userHandle\n        )\n    }\n\n    @RequiresApi(24)\n    override suspend fun start(options: RequestOptions, callerPackage: String, pinRequested: Boolean, pin: String?, userInfo: String?): AuthenticatorResponse =\n        when (options.type) {\n            RequestOptionsType.REGISTER -> register(options, callerPackage)\n            RequestOptionsType.SIGN -> sign(options, callerPackage, userInfo)\n        }\n\n    override fun shouldBeUsedInstantly(options: RequestOptions): Boolean {\n        if (options.type != RequestOptionsType.SIGN) return false\n        for (descriptor in options.signOptions.allowList.orEmpty()) {\n            try {\n                val (type, data) = CredentialId.decodeTypeAndData(descriptor.id)\n                if (type == 1.toByte() && store.containsKey(options.rpId, data)) {\n                    return true\n                }\n            } catch (e: Exception) {\n                // Ignore\n            }\n        }\n        return false\n    }\n\n    companion object {\n        private val AAGUID = byteArrayOf(\n            0xb9.toByte(), 0x3f, 0xd9.toByte(), 0x61, 0xf2.toByte(), 0xe6.toByte(), 0x46, 0x2f,\n            0xb1.toByte(), 0x22, 0x82.toByte(), 0x00, 0x22, 0x47, 0xde.toByte(), 0x78\n        )\n    }\n}\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/transport/usb/UsbDevicePermissionManager.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.transport.usb\n\nimport android.content.BroadcastReceiver\nimport android.content.Context\nimport android.content.Intent\nimport android.content.IntentFilter\nimport android.hardware.usb.UsbDevice\nimport android.hardware.usb.UsbManager\nimport androidx.core.app.PendingIntentCompat\nimport androidx.core.content.ContextCompat\nimport androidx.core.content.ContextCompat.RECEIVER_NOT_EXPORTED\nimport kotlinx.coroutines.CompletableDeferred\n\nprivate val Context.usbPermissionCallbackAction\n    get() = \"$packageName.USB_PERMISSION_CALLBACK\"\n\nprivate object UsbDevicePermissionReceiver : BroadcastReceiver() {\n    private var registered = false\n    private val pendingRequests = hashMapOf<UsbDevice, MutableList<CompletableDeferred<Boolean>>>()\n\n    fun register(context: Context) = synchronized(this) {\n        if (!registered) {\n            ContextCompat.registerReceiver(context, this, IntentFilter(context.usbPermissionCallbackAction), RECEIVER_NOT_EXPORTED)\n            registered = true\n        }\n    }\n\n    fun addDeferred(device: UsbDevice, deferred: CompletableDeferred<Boolean>) = synchronized(this) {\n        if (pendingRequests.containsKey(device)) {\n            pendingRequests[device]!!.add(deferred)\n            false\n        } else {\n            pendingRequests[device] = arrayListOf(deferred)\n            true\n        }\n    }\n\n    fun unregister(context: Context) = synchronized(this) {\n        if (registered) {\n            context.unregisterReceiver(this)\n            registered = false\n        }\n    }\n\n    override fun onReceive(context: Context?, intent: Intent?) {\n        if (intent == null || context == null) return\n        if (intent.action == context.usbPermissionCallbackAction) {\n            val device = intent.getParcelableExtra<UsbDevice>(UsbManager.EXTRA_DEVICE)\n            if (device != null) {\n                synchronized(this) {\n                    if (pendingRequests.containsKey(device)) {\n                        val hasPermission = context.usbManager?.hasPermission(device) == true\n                        for (deferred in pendingRequests[device].orEmpty()) {\n                            deferred.complete(hasPermission)\n                        }\n                        pendingRequests.remove(device)\n                        if (pendingRequests.isEmpty()) {\n                            unregister(context)\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n\nclass UsbDevicePermissionManager(private val context: Context) {\n\n    suspend fun awaitPermission(device: UsbDevice): Boolean {\n        if (context.usbManager?.hasPermission(device) == true) return true\n        val res = CompletableDeferred<Boolean>()\n        if (UsbDevicePermissionReceiver.addDeferred(device, res)) {\n            UsbDevicePermissionReceiver.register(context)\n            val intent = PendingIntentCompat.getBroadcast(context, 0, Intent(context.usbPermissionCallbackAction).apply { `package` = context.packageName }, 0, true)\n            context.usbManager?.requestPermission(device, intent)\n        }\n        return res.await()\n    }\n}\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/transport/usb/UsbTransportHandler.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.transport.usb\n\nimport android.content.BroadcastReceiver\nimport android.content.Context\nimport android.content.Intent\nimport android.content.IntentFilter\nimport android.hardware.usb.UsbConstants.*\nimport android.hardware.usb.UsbDevice\nimport android.hardware.usb.UsbInterface\nimport android.hardware.usb.UsbManager\nimport android.os.Bundle\nimport android.util.Base64\nimport android.util.Log\nimport androidx.annotation.RequiresApi\nimport androidx.core.content.ContextCompat\nimport androidx.core.content.ContextCompat.RECEIVER_NOT_EXPORTED\nimport com.google.android.gms.fido.fido2.api.common.*\nimport kotlinx.coroutines.CancellationException\nimport kotlinx.coroutines.CompletableDeferred\nimport org.microg.gms.fido.core.*\nimport org.microg.gms.fido.core.transport.Transport\nimport org.microg.gms.fido.core.transport.TransportHandler\nimport org.microg.gms.fido.core.transport.TransportHandlerCallback\nimport org.microg.gms.fido.core.transport.usb.ctaphid.CtapHidConnection\nimport org.microg.gms.utils.toBase64\n\n@RequiresApi(21)\nclass UsbTransportHandler(private val context: Context, callback: TransportHandlerCallback? = null) :\n    TransportHandler(Transport.USB, callback) {\n    override val isSupported: Boolean\n        get() = context.packageManager.hasSystemFeature(\"android.hardware.usb.host\") && context.usbManager != null\n\n    private val devicePermissionManager by lazy { UsbDevicePermissionManager(context) }\n\n    private var device: UsbDevice? = null\n\n    private infix fun <T> List<T>.eq(other: List<T>): Boolean =\n        other.size == size && zip(other).all { (x, y) -> x == y }\n\n    suspend fun getCtapHidInterface(device: UsbDevice): UsbInterface? {\n        for (iface in device.interfaces) {\n            if (iface.interfaceClass != USB_CLASS_HID) continue\n            if (iface.endpointCount != 2) continue\n            if (!iface.endpoints.all { it.type == USB_ENDPOINT_XFER_INT }) continue\n            if (!iface.endpoints.any { it.direction == USB_DIR_IN }) continue\n            if (!iface.endpoints.any { it.direction == USB_DIR_OUT }) continue\n\n            Log.d(TAG, \"${device.productName} has suitable hid interface ${iface.id}\")\n            if (!devicePermissionManager.awaitPermission(device)) continue\n            Log.d(TAG, \"${device.productName} has permission\")\n            val match = context.usbManager?.openDevice(device)?.use { connection ->\n                if (connection.claimInterface(iface, true)) {\n                    val buf = ByteArray(256)\n                    val read = connection.controlTransfer(0x81, 0x06, 0x2200, iface.id, buf, buf.size, 5000)\n                    Log.d(TAG, \"Signature: ${buf.slice(0 until read).toByteArray().toBase64(Base64.NO_WRAP)}\")\n                    read >= 5 && buf.slice(0 until 5) eq CTAPHID_SIGNATURE\n                } else {\n                    Log.d(TAG, \"Failed claiming interface\")\n                    false\n                }\n            } == true\n            if (match) {\n                return iface\n            } else {\n                Log.d(TAG, \"${device.productName} signature does not match\")\n            }\n        }\n        return null\n    }\n\n    suspend fun register(\n        options: RequestOptions,\n        callerPackage: String,\n        device: UsbDevice,\n        iface: UsbInterface,\n        pinRequested: Boolean,\n        pin: String?\n    ): AuthenticatorAttestationResponse {\n        return CtapHidConnection(context, device, iface).open {\n            register(it, context, options, callerPackage, pinRequested, pin)\n        }\n    }\n\n    suspend fun sign(\n        options: RequestOptions,\n        callerPackage: String,\n        device: UsbDevice,\n        iface: UsbInterface,\n        pinRequested: Boolean,\n        pin: String?\n    ): AuthenticatorAssertionResponse {\n        return CtapHidConnection(context, device, iface).open {\n            sign(it, context, options, callerPackage, pinRequested, pin)\n        }\n    }\n\n    private suspend fun waitForNewUsbDevice(): UsbDevice {\n        val deferred = CompletableDeferred<UsbDevice>()\n        val receiver = object : BroadcastReceiver() {\n            override fun onReceive(context: Context?, intent: Intent?) {\n                if (intent?.action != UsbManager.ACTION_USB_DEVICE_ATTACHED) return\n                val device = intent.getParcelableExtra<UsbDevice>(UsbManager.EXTRA_DEVICE) ?: return\n                deferred.complete(device)\n            }\n        }\n        ContextCompat.registerReceiver(context, receiver, IntentFilter(UsbManager.ACTION_USB_DEVICE_ATTACHED), RECEIVER_NOT_EXPORTED)\n        invokeStatusChanged(TransportHandlerCallback.STATUS_WAITING_FOR_DEVICE)\n        val device = deferred.await()\n        context.unregisterReceiver(receiver)\n        return device\n    }\n\n    suspend fun handle(\n        options: RequestOptions,\n        callerPackage: String,\n        device: UsbDevice,\n        iface: UsbInterface,\n        pinRequested: Boolean,\n        pin: String?\n    ): AuthenticatorResponse {\n        Log.d(TAG, \"Trying to use ${device.productName} for ${options.type}\")\n        invokeStatusChanged(\n            TransportHandlerCallback.STATUS_WAITING_FOR_USER,\n            Bundle().apply { putParcelable(UsbManager.EXTRA_DEVICE, device) })\n        try {\n            return when (options.type) {\n                RequestOptionsType.REGISTER -> register(options, callerPackage, device, iface, pinRequested, pin)\n                RequestOptionsType.SIGN -> sign(options, callerPackage, device, iface, pinRequested, pin)\n            }\n        } finally {\n            this.device = null\n        }\n    }\n\n    override suspend fun start(options: RequestOptions, callerPackage: String, pinRequested: Boolean, pin: String?, userInfo: String?): AuthenticatorResponse {\n        for (device in context.usbManager?.deviceList?.values.orEmpty()) {\n            val iface = getCtapHidInterface(device) ?: continue\n            try {\n                return handle(options, callerPackage, device, iface, pinRequested, pin)\n            } catch (e: CancellationException) {\n                throw e\n            } catch (e: MissingPinException) {\n                throw e\n            } catch (e: WrongPinException) {\n                throw e\n            }  catch (e: Exception) {\n                Log.w(TAG, e)\n            }\n        }\n        // None of the already connected devices was suitable, waiting for new device\n        while (true) {\n            val device = waitForNewUsbDevice()\n            val iface = getCtapHidInterface(device) ?: continue\n            try {\n                return handle(options, callerPackage, device, iface, pinRequested, pin)\n            } catch (e: CancellationException) {\n                throw e\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n            }\n        }\n    }\n\n    companion object {\n        const val TAG = \"FidoUsbHandler\"\n        val CTAPHID_SIGNATURE = listOf<Byte>(0x06, 0xd0.toByte(), 0xf1.toByte(), 0x09, 0x01)\n    }\n}\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/transport/usb/ctaphid/CtapHidConnection.kt",
    "content": "package org.microg.gms.fido.core.transport.usb.ctaphid\n\nimport android.content.Context\nimport android.hardware.usb.UsbConstants.USB_DIR_IN\nimport android.hardware.usb.UsbConstants.USB_DIR_OUT\nimport android.hardware.usb.UsbDevice\nimport android.hardware.usb.UsbDeviceConnection\nimport android.hardware.usb.UsbInterface\nimport android.hardware.usb.UsbRequest\nimport android.util.Base64\nimport android.util.Log\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\nimport kotlinx.coroutines.withTimeout\nimport org.microg.gms.fido.core.protocol.msgs.*\nimport org.microg.gms.fido.core.transport.*\nimport org.microg.gms.fido.core.transport.usb.endpoints\nimport org.microg.gms.fido.core.transport.usb.initialize\nimport org.microg.gms.fido.core.transport.usb.usbManager\nimport org.microg.gms.utils.toBase64\nimport java.nio.ByteBuffer\nimport kotlin.experimental.and\n\nclass CtapHidConnection(\n    val context: Context,\n    val device: UsbDevice,\n    val iface: UsbInterface,\n) : CtapConnection {\n    private var connection: UsbDeviceConnection? = null\n    private val inEndpoint = iface.endpoints.first { it.direction == USB_DIR_IN }\n    private val outEndpoint = iface.endpoints.first { it.direction == USB_DIR_OUT }\n    private var channelIdentifier = 0xffffffff.toInt()\n    override var capabilities: Int = 0\n    override var transports: List<String> = listOf(\"usb\")\n\n    suspend fun open(): Boolean {\n        Log.d(TAG, \"Opening connection\")\n        connection = context.usbManager?.openDevice(device)\n        if (connection?.claimInterface(iface, true) != true) {\n            Log.d(TAG, \"Failed claiming interface\")\n            close()\n            return false\n        }\n        val initRequest = CtapHidInitRequest()\n        sendRequest(initRequest)\n        val initResponse = readResponse()\n        if (initResponse !is CtapHidInitResponse || !initResponse.nonce.contentEquals(initRequest.nonce)) {\n            Log.d(TAG, \"Failed init procedure\")\n            close()\n            return false\n        }\n        channelIdentifier = initResponse.channelId\n        val caps = initResponse.capabilities\n        capabilities = 0 or\n                (if (caps and CtapHidInitResponse.CAPABILITY_NMSG == 0.toByte()) CAPABILITY_CTAP_1 else 0) or\n                (if (caps and CtapHidInitResponse.CAPABILITY_CBOR > 0) CAPABILITY_CTAP_2 else 0) or\n                (if (caps and CtapHidInitResponse.CAPABILITY_WINK > 0) CAPABILITY_WINK else 0)\n        if (hasCtap2Support) {\n            try {\n                fetchCapabilities()\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n            }\n        }\n        return true\n    }\n\n    suspend fun close() {\n        connection?.close()\n        connection = null\n        channelIdentifier = 0xffffffff.toInt()\n        capabilities = 0\n    }\n\n    private suspend fun fetchCapabilities() {\n        val response = runCommand(AuthenticatorGetInfoCommand())\n        Log.d(TAG, \"Got info: $response\")\n        capabilities = capabilities or CAPABILITY_CTAP_2 or\n                (if (response.versions.contains(\"FIDO_2_1\")) CAPABILITY_CTAP_2_1 else 0) or\n                (if (response.options.clientPin == true) CAPABILITY_CLIENT_PIN else 0) or\n                (if (response.options.userVerification == true) CAPABILITY_USER_VERIFICATION else 0) or\n                (if (response.options.residentKey == true) CAPABILITY_RESIDENT_KEY else 0)\n        if (response.transports != null) transports = response.transports\n    }\n\n    suspend fun sendRequest(request: CtapHidRequest) {\n        val connection = connection ?: throw IllegalStateException(\"Not opened\")\n        val packets = request.encodePackets(channelIdentifier, outEndpoint.maxPacketSize)\n        Log.d(TAG, \"Sending $request in ${packets.size} packets\")\n        UsbRequest().initialize(connection, outEndpoint) { outRequest ->\n            for (packet in packets) {\n                if (outRequest.queue(ByteBuffer.wrap(packet.bytes), packet.bytes.size)) {\n                    withContext(Dispatchers.IO) { connection.requestWait() }\n                    Log.d(TAG, \"Sent packet ${packet.bytes.toBase64(Base64.NO_WRAP)}\")\n                } else {\n                    throw RuntimeException(\"Failed queuing packet\")\n                }\n            }\n        }\n    }\n\n    suspend fun readResponse(timeout: Long = 1000): CtapHidResponse = withTimeout(timeout) {\n        val connection = connection ?: throw IllegalStateException(\"Not opened\")\n        UsbRequest().initialize(connection, inEndpoint) { inRequest ->\n            val packets = mutableListOf<CtapHidPacket>()\n            val buffer = ByteBuffer.allocate(inEndpoint.maxPacketSize)\n            var initializationPacket: CtapHidInitializationPacket? = null\n            while (true) {\n                buffer.clear()\n                if (inRequest.queue(buffer, inEndpoint.maxPacketSize)) {\n                    Log.d(TAG, \"Reading ${inEndpoint.maxPacketSize} bytes from usb\")\n                    withContext(Dispatchers.IO) { connection.requestWait() }\n                    Log.d(TAG, \"Received packet ${buffer.array().toBase64(Base64.NO_WRAP)}\")\n                    if (initializationPacket == null) {\n                        initializationPacket = CtapHidInitializationPacket.decode(buffer.array())\n                        packets.add(initializationPacket)\n                    } else {\n                        val continuationPacket = CtapHidContinuationPacket.decode(buffer.array())\n                        if (continuationPacket.channelIdentifier == initializationPacket.channelIdentifier) {\n                            packets.add(continuationPacket)\n                        } else {\n                            Log.w(TAG, \"Dropping unexpected packet: $continuationPacket\")\n                        }\n                    }\n                    if (packets.sumOf { it.data.size } >= initializationPacket.payloadLength) {\n                        if (initializationPacket.channelIdentifier != channelIdentifier) {\n                            packets.clear()\n                            initializationPacket = null\n                        } else {\n                            val message = CtapHidMessage.decode(packets)\n                            if (message.commandId == CtapHidKeepAliveMessage.COMMAND_ID) {\n                                Log.w(TAG, \"Keep alive: $message\")\n                                packets.clear()\n                                initializationPacket = null\n                            } else {\n                                val response = CtapHidResponse.parse(message)\n                                Log.d(TAG, \"Received $response in ${packets.size} packets\")\n                                return@withTimeout response\n                            }\n                        }\n                    }\n                } else {\n                    throw RuntimeException(\"Failed queuing packet\")\n                }\n            }\n            throw RuntimeException(\"Interrupted\")\n        }\n    }\n\n    override suspend fun <Q : Ctap1Request, S : Ctap1Response> runCommand(command: Ctap1Command<Q, S>): S {\n        require(hasCtap1Support)\n        sendRequest(CtapHidMessageRequest(command.request))\n        val response = readResponse()\n        if (response is CtapHidMessageResponse) {\n            if (response.statusCode == 0x9000.toShort()) {\n                return command.decodeResponse(response.statusCode, response.payload)\n            }\n            throw CtapHidMessageStatusException(response.statusCode.toInt() and 0xffff)\n        }\n        throw RuntimeException(\"Unexpected response: $response\")\n    }\n\n    override suspend fun <Q: Ctap2Request, S: Ctap2Response> runCommand(command: Ctap2Command<Q, S>): S {\n        require(hasCtap2Support)\n        sendRequest(CtapHidCborRequest(command.request))\n        val response = readResponse(command.timeout)\n        if (response is CtapHidCborResponse) {\n            if (response.statusCode == 0x00.toByte()) {\n                return command.decodeResponse(response.payload)\n            }\n            throw Ctap2StatusException(response.statusCode)\n        }\n        throw RuntimeException(\"Unexpected response: $response\")\n    }\n\n    suspend fun <R> open(block: suspend (CtapHidConnection) -> R): R {\n        if (!open()) throw RuntimeException(\"Could not open device\")\n        var exception: Throwable? = null\n        try {\n            return block(this)\n        } catch (e: Throwable) {\n            exception = e\n            throw e\n        } finally {\n            when (exception) {\n                null -> close()\n                else -> try {\n                    close()\n                } catch (closeException: Throwable) {\n                    // cause.addSuppressed(closeException) // ignored here\n                }\n            }\n        }\n    }\n\n    companion object {\n        const val TAG = \"FidoCtapHidConnection\"\n    }\n}\n\nclass CtapHidMessageStatusException(val status: Int) : Exception(\"Received status ${status.toString(16)}\")\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/transport/usb/ctaphid/CtapHidMessage.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.transport.usb.ctaphid\n\nimport android.util.Base64\nimport org.microg.gms.utils.toBase64\nimport kotlin.experimental.and\nimport kotlin.experimental.or\nimport kotlin.math.min\n\nopen class CtapHidMessage(val commandId: Byte, val data: ByteArray = ByteArray(0)) {\n    init {\n        if (data.size > Short.MAX_VALUE) throw IllegalArgumentException(\"Request too large\")\n    }\n\n    fun encodePackets(channelIdentifier: Int, packetSize: Int): List<CtapHidPacket> {\n        val packets = arrayListOf<CtapHidPacket>()\n        val initializationDataSize = packetSize - 7\n        val continuationDataSize = packetSize - 5\n        var position = 0\n        var nextPosition = min(data.size, initializationDataSize)\n        packets.add(\n            CtapHidInitializationPacket(\n                channelIdentifier,\n                commandId or 0x80.toByte(),\n                data.size.toShort(),\n                data.sliceArray(position until nextPosition),\n                packetSize\n            )\n        )\n        var sequenceNumber: Byte = 0\n        while (nextPosition < data.size) {\n            position = nextPosition\n            nextPosition = min(data.size, position + continuationDataSize)\n            packets.add(\n                CtapHidContinuationPacket(\n                    channelIdentifier,\n                    sequenceNumber++,\n                    data.sliceArray(position until nextPosition),\n                    packetSize\n                )\n            )\n        }\n        return packets\n    }\n\n    override fun toString(): String =\n        \"CtapHidMessage(commandId=0x${commandId.toString(16)}, data=${data.toBase64(Base64.NO_WRAP)})\"\n\n    companion object {\n        fun decode(packets: List<CtapHidPacket>): CtapHidMessage {\n            val initializationPacket = packets.first() as? CtapHidInitializationPacket\n                ?: throw IllegalArgumentException(\"First packet must ba an initialization packet\")\n            val data = packets.map { it.data }.fold(ByteArray(0)) { a, b -> a + b }\n                .sliceArray(0 until initializationPacket.payloadLength)\n            return CtapHidMessage(initializationPacket.commandId and 0x7f, data)\n        }\n    }\n}\n\nclass CtapHidKeepAliveMessage(val status: Byte) : CtapHidMessage(COMMAND_ID, byteArrayOf(status)) {\n    companion object {\n        const val STATUS_PROCESSING: Byte = 1\n        const val STATUS_UPNEEDED: Byte = 2\n        const val COMMAND_ID: Byte = 0x3b\n    }\n}\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/transport/usb/ctaphid/CtapHidPacket.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.transport.usb.ctaphid\n\nimport java.nio.ByteBuffer\nimport java.nio.ByteOrder\n\ninterface CtapHidPacket {\n    val bytes: ByteArray\n    val data: ByteArray\n}\n\nclass CtapHidInitializationPacket(\n    val channelIdentifier: Int,\n    val commandId: Byte,\n    val payloadLength: Short,\n    override val data: ByteArray,\n    val packetSize: Int\n) : CtapHidPacket {\n\n    override val bytes: ByteArray = ByteBuffer.allocate(packetSize).apply {\n        order(ByteOrder.BIG_ENDIAN)\n        position(0)\n        putInt(channelIdentifier)\n        put(commandId)\n        putShort(payloadLength)\n        put(data)\n    }.array()\n\n    init {\n        if (data.size > packetSize - 7) throw IllegalArgumentException(\"Too much data for packet size\")\n        if (commandId >= 0) throw IllegalArgumentException(\"7-bit must be set on initialization packet\")\n    }\n\n    companion object {\n        fun decode(bytes: ByteArray) = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN).run {\n            CtapHidInitializationPacket(\n                int,\n                get(),\n                short,\n                ByteArray(bytes.size - 7).also { get(it) },\n                bytes.size\n            )\n        }\n    }\n}\n\nclass CtapHidContinuationPacket(\n    val channelIdentifier: Int,\n    val sequenceNumber: Byte,\n    override val data: ByteArray,\n    val packetSize: Int\n) : CtapHidPacket {\n    override val bytes: ByteArray = ByteBuffer.allocate(packetSize).apply {\n        order(ByteOrder.BIG_ENDIAN)\n        position(0)\n        putInt(channelIdentifier)\n        put(sequenceNumber)\n        put(data)\n    }.array()\n\n    init {\n        if (data.size > packetSize - 5) throw IllegalArgumentException(\"Too much data for packet size\")\n        if (sequenceNumber < 0) throw IllegalArgumentException(\"7-bit must not be set on continuation packet\")\n    }\n\n    companion object {\n        fun decode(bytes: ByteArray) = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN).run {\n            CtapHidContinuationPacket(\n                int,\n                get(),\n                ByteArray(bytes.size - 5).also { get(it) },\n                bytes.size\n            )\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/transport/usb/ctaphid/CtapHidRequest.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.transport.usb.ctaphid\n\nimport android.util.Base64\nimport org.microg.gms.fido.core.protocol.msgs.Ctap1Request\nimport org.microg.gms.fido.core.protocol.msgs.Ctap2Request\nimport org.microg.gms.utils.toBase64\nimport kotlin.random.Random\n\nabstract class CtapHidRequest(commandId: Byte, data: ByteArray = ByteArray(0)) : CtapHidMessage(commandId, data) {\n    override fun toString(): String =\n        \"CtapHidRequest(commandId=0x${commandId.toString(16)}, data=${data.toBase64(Base64.NO_WRAP)})\"\n}\n\nclass CtapHidPingRequest(data: ByteArray) : CtapHidRequest(0x01, data) {\n    override fun toString(): String = \"CtapHidPingRequest(data=${data.toBase64(Base64.NO_WRAP)})\"\n}\n\nclass CtapHidMessageRequest(val request: Ctap1Request) :\n    CtapHidRequest(0x03, request.apdu) {\n    override fun toString(): String = \"CtapHidMessageRequest(${request})\"\n}\n\nclass CtapHidLockRequest(val seconds: Byte) : CtapHidRequest(0x04, byteArrayOf(seconds)) {\n    override fun toString(): String = \"CtapHidLockRequest(seconds=$seconds)\"\n}\n\nclass CtapHidInitRequest(val nonce: ByteArray = Random.nextBytes(8)) :\n    CtapHidRequest(0x06, nonce) {\n    init {\n        if (nonce.size != 8) throw IllegalArgumentException(\"nonce must be 8 bytes\")\n    }\n\n    override fun toString(): String = \"CtapHidInitRequest(nonce=${nonce.toBase64(Base64.NO_WRAP)})\"\n}\n\nclass CtapHidWinkRequest : CtapHidRequest(0x08) {\n    override fun toString(): String = \"CtapHidWinkRequest()\"\n}\n\nclass CtapHidCborRequest(val request: Ctap2Request) :\n    CtapHidRequest(0x10, byteArrayOf(request.commandByte) + request.payload) {\n\n    override fun toString(): String = \"CtapHidCborRequest(${request})\"\n}\n\nclass CtapHidCancelRequest : CtapHidRequest(0x11) {\n    override fun toString(): String = \"CtapHidCancelRequest()\"\n}\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/transport/usb/ctaphid/CtapHidResponse.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.transport.usb.ctaphid\n\nimport android.util.Base64\nimport org.microg.gms.fido.core.protocol.msgs.decodeResponseApdu\nimport org.microg.gms.utils.toBase64\nimport java.nio.ByteBuffer\nimport java.nio.ByteOrder\n\nopen class CtapHidResponse(commandId: Byte, data: ByteArray) : CtapHidMessage(commandId, data) {\n    override fun toString(): String =\n        \"CtapHidResponse(commandId=0x${commandId.toString(16)}, data=${data.toBase64(Base64.NO_WRAP)})\"\n\n    companion object {\n        val responseTypes = mapOf(\n            CtapHidPingResponse.COMMAND_ID to CtapHidPingResponse::parse,\n            CtapHidMessageResponse.COMMAND_ID to CtapHidMessageResponse::parse,\n            CtapHidInitResponse.COMMAND_ID to CtapHidInitResponse::parse,\n            CtapHidWinkResponse.COMMAND_ID to CtapHidWinkResponse::parse,\n            CtapHidCborResponse.COMMAND_ID to CtapHidCborResponse::parse,\n            CtapHidErrorResponse.COMMAND_ID to CtapHidErrorResponse::parse,\n        )\n\n        fun parse(message: CtapHidMessage): CtapHidResponse =\n            responseTypes[message.commandId]?.invoke(message) ?: CtapHidResponse(message.commandId, message.data)\n    }\n}\n\nclass CtapHidPingResponse(data: ByteArray) : CtapHidResponse(COMMAND_ID, data) {\n    override fun toString(): String = \"CtapHidPingResponse(data=${data.toBase64(Base64.NO_WRAP)})\"\n\n    companion object {\n        const val COMMAND_ID: Byte = 0x01\n\n        fun parse(message: CtapHidMessage): CtapHidPingResponse {\n            require(message.commandId == COMMAND_ID)\n            return CtapHidPingResponse(message.data)\n        }\n    }\n}\n\nclass CtapHidMessageResponse(val statusCode: Short, val payload: ByteArray) :\n    CtapHidResponse(COMMAND_ID, byteArrayOf((statusCode.toInt() shr 8).toByte(), statusCode.toByte()) + payload) {\n    override fun toString(): String =\n        \"CtapHidMessageResponse(statusCode=0x${statusCode.toString(16)}, payload=${payload.toBase64(Base64.NO_WRAP)})\"\n\n    companion object {\n        const val COMMAND_ID: Byte = 0x03\n\n        fun parse(message: CtapHidMessage): CtapHidMessageResponse {\n            require(message.commandId == COMMAND_ID)\n            val (statusCode, payload) = decodeResponseApdu(message.data)\n            return CtapHidMessageResponse(statusCode, payload)\n        }\n    }\n}\n\nclass CtapHidInitResponse(\n    val nonce: ByteArray,\n    val channelId: Int,\n    val protocolVersion: Byte,\n    val majorDeviceVersion: Byte,\n    val minorDeviceVersion: Byte,\n    val buildDeviceVersion: Byte,\n    val capabilities: Byte\n) : CtapHidResponse(COMMAND_ID, ByteBuffer.allocate(17).apply {\n    order(ByteOrder.BIG_ENDIAN)\n    position(0)\n    put(nonce)\n    putInt(channelId)\n    put(protocolVersion)\n    put(majorDeviceVersion)\n    put(minorDeviceVersion)\n    put(buildDeviceVersion)\n    put(capabilities)\n}.array()) {\n    val deviceVersion: String = \"$majorDeviceVersion.$minorDeviceVersion.$buildDeviceVersion\"\n\n    override fun toString(): String = \"CtapHidInitResponse(nonce=0x${nonce.toBase64(Base64.NO_WRAP)}, \" +\n            \"channelId=0x${channelId.toString(16)}, \" +\n            \"protocolVersion=0x${protocolVersion.toString(16)}, \" +\n            \"version=$deviceVersion, \" +\n            \"capabilities=0x${capabilities.toString(16)})\"\n\n    companion object {\n        const val COMMAND_ID: Byte = 0x06\n\n        const val CAPABILITY_WINK: Byte = 0x01\n        const val CAPABILITY_CBOR: Byte = 0x04\n        const val CAPABILITY_NMSG: Byte = 0x08\n\n        fun parse(message: CtapHidMessage): CtapHidInitResponse {\n            require(message.commandId == COMMAND_ID)\n            require(message.data.size == 17)\n            return ByteBuffer.wrap(message.data).order(ByteOrder.BIG_ENDIAN).run {\n                CtapHidInitResponse(\n                    ByteArray(8).also { get(it) },\n                    int,\n                    get(),\n                    get(),\n                    get(),\n                    get(),\n                    get()\n                )\n            }\n        }\n    }\n}\n\nclass CtapHidWinkResponse : CtapHidResponse(COMMAND_ID, ByteArray(0)) {\n    override fun toString(): String = \"CtapHidWinkResponse()\"\n\n    companion object {\n        const val COMMAND_ID: Byte = 0x08\n\n        fun parse(message: CtapHidMessage): CtapHidWinkResponse {\n            require(message.commandId == COMMAND_ID)\n            require(message.data.isEmpty())\n            return CtapHidWinkResponse()\n        }\n    }\n}\n\nclass CtapHidCborResponse(val statusCode: Byte, val payload: ByteArray) :\n    CtapHidResponse(COMMAND_ID, byteArrayOf(statusCode) + payload) {\n    override fun toString(): String =\n        \"CtapHidCborResponse(statusCode=0x${statusCode.toString(16)}, payload=${payload.toBase64(Base64.NO_WRAP)})\"\n\n    companion object {\n        const val COMMAND_ID: Byte = 0x10\n\n        fun parse(message: CtapHidMessage): CtapHidCborResponse {\n            require(message.commandId == COMMAND_ID)\n            return CtapHidCborResponse(message.data[0], message.data.sliceArray(1 until message.data.size))\n        }\n    }\n}\n\nclass CtapHidErrorResponse(val errorCode: Byte) : CtapHidResponse(COMMAND_ID, byteArrayOf(errorCode)) {\n    override fun toString(): String = \"CtapHidErrorResponse(errorCode=0x${errorCode.toString(16)})\"\n\n    companion object {\n        const val COMMAND_ID: Byte = 0x3f\n        const val ERR_INVALID_CMD: Byte = 0x01\n        const val ERR_INVALID_PAR: Byte = 0x02\n        const val ERR_INVALID_LEN: Byte = 0x03\n        const val ERR_INVALID_SEQ: Byte = 0x04\n        const val ERR_MSG_TIMEOUT: Byte = 0x05\n        const val ERR_CHANNEL_BUSY: Byte = 0x06\n        const val ERR_LOCK_REQUIRED: Byte = 0x0A\n        const val ERR_INVALID_CHANNEL: Byte = 0x0B\n        const val ERR_OTHER: Byte = 0x7F\n\n        fun parse(message: CtapHidMessage): CtapHidErrorResponse {\n            require(message.commandId == COMMAND_ID)\n            require(message.data.size == 1)\n            return CtapHidErrorResponse(message.data[0])\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/transport/usb/extensions.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.transport.usb\n\nimport android.content.Context\nimport android.hardware.usb.*\n\nval Context.usbManager: UsbManager?\n    get() = getSystemService(Context.USB_SERVICE) as? UsbManager?\n\nval UsbDevice.interfaces: Iterable<UsbInterface>\n    get() = Iterable {\n        object : Iterator<UsbInterface> {\n            private var index = 0\n            override fun hasNext(): Boolean = index < interfaceCount\n            override fun next(): UsbInterface = getInterface(index++)\n        }\n    }\n\nval UsbInterface.endpoints: Iterable<UsbEndpoint>\n    get() = Iterable {\n        object : Iterator<UsbEndpoint> {\n            private var index = 0\n            override fun hasNext(): Boolean = index < endpointCount\n            override fun next(): UsbEndpoint = getEndpoint(index++)\n        }\n    }\n\ninline fun <R> UsbDeviceConnection.use(block: (UsbDeviceConnection) -> R): R {\n    var exception: Throwable? = null\n    try {\n        return block(this)\n    } catch (e: Throwable) {\n        exception = e\n        throw e\n    } finally {\n        when (exception) {\n            null -> close()\n            else -> try {\n                close()\n            } catch (closeException: Throwable) {\n                // cause.addSuppressed(closeException) // ignored here\n            }\n        }\n    }\n}\n\ninline fun <R> UsbRequest.initialize(connection: UsbDeviceConnection, endpoint: UsbEndpoint, block: (UsbRequest) -> R): R {\n    var exception: Throwable? = null\n    try {\n        initialize(connection, endpoint)\n        return block(this)\n    } catch (e: Throwable) {\n        exception = e\n        throw e\n    } finally {\n        when (exception) {\n            null -> close()\n            else -> try {\n                close()\n            } catch (closeException: Throwable) {\n                // cause.addSuppressed(closeException) // ignored here\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/ui/AuthenticatorActivity.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.ui\n\nimport android.content.Intent\nimport android.graphics.Color\nimport android.graphics.drawable.ColorDrawable\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.Bundle\nimport android.util.Base64\nimport android.util.Log\nimport android.widget.Toast\nimport androidx.annotation.RequiresApi\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.fragment.app.commit\nimport androidx.lifecycle.lifecycleScope\nimport androidx.navigation.fragment.NavHostFragment\nimport com.google.android.gms.fido.Fido.*\nimport com.google.android.gms.fido.fido2.api.common.*\nimport com.google.android.gms.fido.fido2.api.common.AuthenticationExtensionsPrfOutputs\nimport com.google.android.gms.fido.fido2.api.common.ErrorCode.*\nimport kotlinx.coroutines.CancellationException\nimport kotlinx.coroutines.Job\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.fido.core.*\nimport org.microg.gms.fido.core.transport.Transport\nimport org.microg.gms.fido.core.transport.Transport.*\nimport org.microg.gms.fido.core.transport.TransportHandler\nimport org.microg.gms.fido.core.transport.TransportHandlerCallback\nimport org.microg.gms.fido.core.transport.bluetooth.BluetoothTransportHandler\nimport org.microg.gms.fido.core.transport.nfc.NfcTransportHandler\nimport org.microg.gms.fido.core.transport.screenlock.ScreenLockTransportHandler\nimport org.microg.gms.fido.core.transport.usb.UsbTransportHandler\nimport org.microg.gms.utils.getApplicationLabel\nimport org.microg.gms.utils.getFirstSignatureDigest\nimport org.microg.gms.utils.toBase64\n\nconst val TAG = \"FidoUi\"\n\nclass AuthenticatorActivity : AppCompatActivity(), TransportHandlerCallback {\n    val options: RequestOptions?\n        get() = when (intent.getStringExtra(KEY_SOURCE) to intent.getStringExtra(KEY_TYPE)) {\n            SOURCE_BROWSER to TYPE_REGISTER ->\n                BrowserPublicKeyCredentialCreationOptions.deserializeFromBytes(intent.getByteArrayExtra(KEY_OPTIONS))\n            SOURCE_BROWSER to TYPE_SIGN ->\n                BrowserPublicKeyCredentialRequestOptions.deserializeFromBytes(intent.getByteArrayExtra(KEY_OPTIONS))\n            SOURCE_APP to TYPE_REGISTER ->\n                PublicKeyCredentialCreationOptions.deserializeFromBytes(intent.getByteArrayExtra(KEY_OPTIONS))\n            SOURCE_APP to TYPE_SIGN ->\n                PublicKeyCredentialRequestOptions.deserializeFromBytes(intent.getByteArrayExtra(KEY_OPTIONS))\n            else -> null\n        }\n\n    private val service: GmsService\n        get() = GmsService.byServiceId(intent.getIntExtra(KEY_SERVICE, GmsService.UNKNOWN.SERVICE_ID))\n    private val database by lazy { Database(this) }\n    private val transportHandlers by lazy {\n        setOfNotNull(\n            BluetoothTransportHandler(this, this),\n            NfcTransportHandler(this, this),\n            if (SDK_INT >= 21) UsbTransportHandler(this, this) else null,\n            if (SDK_INT >= 23) ScreenLockTransportHandler(this, this) else null\n        )\n    }\n\n    lateinit var callerPackage: String\n    lateinit var callerSignature: String\n    private lateinit var navHostFragment: NavHostFragment\n\n    private inline fun <reified T : TransportHandler> getTransportHandler(): T? =\n        transportHandlers.filterIsInstance<T>().firstOrNull { it.isSupported }\n\n    fun getTransportHandler(transport: Transport): TransportHandler? =\n        transportHandlers.firstOrNull { it.transport == transport && it.isSupported }\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n\n        try {\n\n            val callerPackage = (if (callingActivity?.packageName == packageName && intent.hasExtra(KEY_CALLER)) intent.getStringExtra(KEY_CALLER) else callingActivity?.packageName) ?: return finish()\n            if (!intent.extras?.keySet().orEmpty().containsAll(REQUIRED_EXTRAS)) {\n                return finishWithError(UNKNOWN_ERR, \"Extra missing from request\")\n            }\n            if (SDK_INT < 24) {\n                return finishWithError(NOT_SUPPORTED_ERR, \"FIDO2 API is not supported on devices below N\")\n            }\n            val options = options ?: return finishWithError(DATA_ERR, \"The request options are not valid\")\n            this.callerPackage = callerPackage\n            this.callerSignature = packageManager.getFirstSignatureDigest(callerPackage, \"SHA-256\")?.toBase64()\n                ?: return finishWithError(UNKNOWN_ERR, \"Could not determine signature of app\")\n\n            Log.d(TAG, \"onCreate caller=$callerPackage options=$options\")\n\n            val requiresPrivilege =\n                options is BrowserRequestOptions && !database.isPrivileged(callerPackage, callerSignature)\n\n            // Check if we can directly open screen lock handling\n            if (!requiresPrivilege) {\n                val instantTransport = transportHandlers.firstOrNull { it.isSupported && it.shouldBeUsedInstantly(options) }\n                if (instantTransport != null && instantTransport.transport in INSTANT_SUPPORTED_TRANSPORTS) {\n                    window.setBackgroundDrawable(ColorDrawable(0))\n                    window.statusBarColor = Color.TRANSPARENT\n                    setTheme(org.microg.gms.base.core.R.style.Theme_Translucent)\n                }\n            }\n\n            setTheme(androidx.appcompat.R.style.Theme_AppCompat_DayNight_NoActionBar)\n            setContentView(R.layout.fido_authenticator_activity)\n\n            lifecycleScope.launchWhenCreated {\n                handleRequest(options)\n            }\n        } catch (e: RequestHandlingException) {\n            finishWithError(e.errorCode, e.message ?: e.errorCode.name)\n        } catch (e: Exception) {\n            Log.w(TAG, e)\n            finishWithError(UNKNOWN_ERR, e.message ?: e.javaClass.simpleName)\n        }\n    }\n\n    @RequiresApi(24)\n    suspend fun handleRequest(options: RequestOptions, allowInstant: Boolean = true) {\n        try {\n            val origin = getOrigin(this, options, callerPackage)\n            options.checkIsValid(this, origin, callerPackage)\n            val appName = getApplicationName(this, options, callerPackage)\n            val callerName = packageManager.getApplicationLabel(callerPackage).toString()\n\n            val requiresPrivilege =\n                options is BrowserRequestOptions && !database.isPrivileged(callerPackage, callerSignature)\n\n            Log.d(TAG, \"origin=$origin, appName=$appName\")\n\n            // Check if we can directly open screen lock handling\n            if (!requiresPrivilege && allowInstant) {\n                val instantTransport = transportHandlers.firstOrNull { it.isSupported && it.shouldBeUsedInstantly(options) }\n                if (instantTransport != null && instantTransport.transport in INSTANT_SUPPORTED_TRANSPORTS) {\n                    startTransportHandling(instantTransport.transport, true)\n                    return\n                }\n            }\n\n            val arguments = AuthenticatorActivityFragmentData().apply {\n                this.appName = appName\n                this.isFirst = true\n                this.privilegedCallerName = callerName.takeIf { options is BrowserRequestOptions }\n                this.requiresPrivilege = requiresPrivilege\n                this.supportedTransports = transportHandlers.filter { it.isSupported }.map { it.transport }.toSet()\n            }.arguments\n            val next = if (!requiresPrivilege) {\n                val knownRegistrationTransports = mutableSetOf<Transport>()\n                val allowedTransports = mutableSetOf<Transport>()\n                val localSavedUserKey = mutableSetOf<String>()\n                if (options.type == RequestOptionsType.SIGN) {\n                    for (descriptor in options.signOptions.allowList.orEmpty()) {\n                        val knownTransport = database.getKnownRegistrationTransport(options.rpId, descriptor.id.toBase64(Base64.URL_SAFE, Base64.NO_WRAP, Base64.NO_PADDING))\n                        if (knownTransport != null && knownTransport in IMPLEMENTED_TRANSPORTS)\n                            knownRegistrationTransports.add(knownTransport)\n                        if (descriptor.transports.isNullOrEmpty()) {\n                            allowedTransports.addAll(Transport.values())\n                        } else {\n                            for (transport in descriptor.transports.orEmpty()) {\n                                val allowedTransport = when (transport) {\n                                    com.google.android.gms.fido.common.Transport.BLUETOOTH_CLASSIC -> BLUETOOTH\n                                    com.google.android.gms.fido.common.Transport.BLUETOOTH_LOW_ENERGY -> BLUETOOTH\n                                    com.google.android.gms.fido.common.Transport.NFC -> NFC\n                                    com.google.android.gms.fido.common.Transport.USB -> USB\n                                    com.google.android.gms.fido.common.Transport.INTERNAL -> SCREEN_LOCK\n                                    else -> null\n                                }\n                                if (allowedTransport != null && allowedTransport in IMPLEMENTED_TRANSPORTS)\n                                    allowedTransports.add(allowedTransport)\n                            }\n                        }\n                    }\n                    database.getKnownRegistrationInfo(options.rpId).forEach { localSavedUserKey.add(it.userJson) }\n                }\n                val preselectedTransport = knownRegistrationTransports.singleOrNull() ?: allowedTransports.singleOrNull()\n                if (database.wasUsed()) {\n                    if (localSavedUserKey.isNotEmpty()) {\n                        R.id.signInSelectionFragment\n                    } else when (preselectedTransport) {\n                        USB -> R.id.usbFragment\n                        NFC -> R.id.nfcFragment\n                        else -> R.id.transportSelectionFragment\n                    }\n                } else {\n                    null\n                }\n            } else {\n                null\n            }\n            navHostFragment = NavHostFragment()\n            supportFragmentManager.commit {\n                replace(R.id.fragment_container, navHostFragment)\n                runOnCommit {\n                    val navGraph = navHostFragment.navController.navInflater.inflate(R.navigation.nav_fido_authenticator)\n                    if (next != null) {\n                        navGraph.setStartDestination(next)\n                    }\n                    navHostFragment.navController.setGraph(navGraph, arguments)\n                }\n            }\n        } catch (e: RequestHandlingException) {\n            finishWithError(e.errorCode, e.message ?: e.errorCode.name)\n        } catch (e: Exception) {\n            Log.w(TAG, e)\n            finishWithError(UNKNOWN_ERR, e.message ?: e.javaClass.simpleName)\n        }\n    }\n\n    fun finishWithError(errorCode: ErrorCode, errorMessage: String) {\n        Log.d(TAG, \"Finish with error: $errorMessage ($errorCode)\")\n        finishWithCredential(\n            PublicKeyCredential.Builder().setResponse(AuthenticatorErrorResponse(errorCode, errorMessage)).build()\n        )\n    }\n\n    fun finishWithSuccessResponse(response: AuthenticatorResponse, transport: Transport) {\n        Log.d(TAG, \"Finish with success response: $response\")\n        if (options is BrowserRequestOptions) database.insertPrivileged(callerPackage, callerSignature)\n        val rpId = options?.rpId\n        val rawId = when(response) {\n            is AuthenticatorAttestationResponse -> response.keyHandle\n            is AuthenticatorAssertionResponse -> response.keyHandle\n            else -> null\n        }\n        val id = rawId?.toBase64(Base64.URL_SAFE, Base64.NO_WRAP, Base64.NO_PADDING)\n\n        if (rpId != null && id != null) {\n            database.insertKnownRegistration(rpId, id, transport, options?.user)\n        }\n\n        val prfFirst = rawId?.let { java.security.MessageDigest.getInstance(\"SHA-256\").digest(it) }?.copyOf(32)\n        val prfOutputs = prfFirst?.let { AuthenticationExtensionsPrfOutputs(true, it, null) }\n\n        val clientExtResults = AuthenticationExtensionsClientOutputs(\n            null,\n            null,\n            AuthenticationExtensionsCredPropsOutputs(true),\n            prfOutputs,\n            null\n        )\n\n        val pkc = PublicKeyCredential.Builder()\n            .setResponse(response)\n            .setRawId(rawId ?: ByteArray(0).also { Log.w(TAG, \"rawId was null\") })\n            .setId(id ?: \"\".also { Log.w(TAG, \"id was null\") })\n            .setAuthenticatorAttachment(if (transport == SCREEN_LOCK) \"platform\" else \"cross-platform\")\n            .setAuthenticationExtensionsClientOutputs(clientExtResults)\n            .build()\n\n        finishWithCredential(pkc)\n    }\n\n    private fun finishWithCredential(publicKeyCredential: PublicKeyCredential) {\n        val intent = Intent()\n        intent.putExtra(FIDO2_KEY_CREDENTIAL_EXTRA, publicKeyCredential.serializeToBytes())\n        val response: AuthenticatorResponse = publicKeyCredential.response\n        if (response is AuthenticatorErrorResponse) {\n            intent.putExtra(FIDO2_KEY_ERROR_EXTRA, response.serializeToBytes())\n        } else {\n            intent.putExtra(FIDO2_KEY_RESPONSE_EXTRA, response.serializeToBytes())\n        }\n        setResult(RESULT_OK, intent)\n        finish()\n    }\n\n    fun shouldStartTransportInstantly(transport: Transport): Boolean {\n        return getTransportHandler(transport)?.shouldBeUsedInstantly(options ?: return false) == true\n    }\n\n    fun isScreenLockSigner(): Boolean {\n        return shouldStartTransportInstantly(SCREEN_LOCK)\n    }\n\n    @RequiresApi(24)\n    fun startTransportHandling(transport: Transport, instant: Boolean = false, pinRequested: Boolean = false, authenticatorPin: String? = null, userInfo: String? = null): Job = lifecycleScope.launchWhenResumed {\n        val options = options ?: return@launchWhenResumed\n        try {\n            finishWithSuccessResponse(getTransportHandler(transport)!!.start(options, callerPackage, pinRequested, authenticatorPin, userInfo), transport)\n        } catch (e: SecurityException) {\n            Log.w(TAG, e)\n            if (instant) {\n                handleRequest(options, false)\n            } else {\n                finishWithError(SECURITY_ERR, e.message ?: e.javaClass.simpleName)\n            }\n        } catch (e: CancellationException) {\n            Log.w(TAG, e)\n            // Ignoring cancellation here\n        } catch (e: RequestHandlingException) {\n            Log.w(TAG, e)\n            finishWithError(e.errorCode, e.message ?: e.errorCode.name)\n        } catch (e: MissingPinException) {\n            // Redirect the user to ask for a PIN code\n            navHostFragment.navController.navigate(R.id.openPinFragment)\n        } catch (e: WrongPinException) {\n            // Redirect the user, and inform them that the pin was wrong\n            Toast.makeText(baseContext, R.string.fido_wrong_pin, Toast.LENGTH_LONG).show()\n            navHostFragment.navController.navigate(R.id.openPinFragment)\n        } catch (e: Exception) {\n            Log.w(TAG, e)\n            finishWithError(UNKNOWN_ERR, e.message ?: e.javaClass.simpleName)\n        }\n    }\n\n    override fun onStatusChanged(transport: Transport, status: String, extras: Bundle?) {\n        Log.d(TAG, \"$transport status set to $status ($extras)\")\n        try {\n            for (callback in navHostFragment.childFragmentManager.fragments.filterIsInstance<TransportHandlerCallback>()) {\n                try {\n                    callback.onStatusChanged(transport, status, extras)\n                } catch (e: Exception) {\n                    // Ignoring\n                }\n            }\n        } catch (e: Exception) {\n            // Ignoring\n        }\n    }\n\n    override fun onBackPressed() {\n        try {\n            if (navHostFragment.navController.popBackStack()) return\n        } catch (e: Exception) {\n            // Ignore\n        }\n        super.onBackPressed()\n    }\n\n    override fun onSupportNavigateUp(): Boolean {\n        try {\n            if (navHostFragment.navController.navigateUp()) return true\n        } catch (e: Exception) {\n            // Ignore\n        }\n        return super.onSupportNavigateUp()\n    }\n\n    companion object {\n        const val KEY_SERVICE = \"service\"\n        const val KEY_SOURCE = \"source\"\n        const val KEY_TYPE = \"type\"\n        const val KEY_OPTIONS = \"options\"\n        val REQUIRED_EXTRAS = setOf(KEY_SERVICE, KEY_SOURCE, KEY_TYPE, KEY_OPTIONS)\n\n        const val SOURCE_BROWSER = \"browser\"\n        const val SOURCE_APP = \"app\"\n\n        const val TYPE_REGISTER = \"register\"\n        const val TYPE_SIGN = \"sign\"\n\n        const val KEY_CALLER = \"caller\"\n\n        val IMPLEMENTED_TRANSPORTS = setOf(USB, SCREEN_LOCK, NFC)\n        val INSTANT_SUPPORTED_TRANSPORTS = setOf(SCREEN_LOCK)\n    }\n}\n\n\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/ui/AuthenticatorActivityFragment.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.ui\n\nimport android.annotation.TargetApi\nimport android.content.Intent\nimport android.os.Bundle\nimport android.util.Log\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport androidx.fragment.app.Fragment\nimport androidx.fragment.app.activityViewModels\nimport androidx.lifecycle.lifecycleScope\nimport com.google.android.gms.fido.fido2.api.common.ErrorCode\nimport com.google.android.gms.fido.fido2.api.common.RequestOptions\nimport org.microg.gms.fido.core.*\nimport org.microg.gms.fido.core.transport.Transport\n\n@TargetApi(24)\nabstract class AuthenticatorActivityFragment : Fragment() {\n    private val pinViewModel: AuthenticatorPinViewModel by activityViewModels()\n    val data: AuthenticatorActivityFragmentData\n        get() = AuthenticatorActivityFragmentData(arguments ?: Bundle.EMPTY)\n    val authenticatorActivity: AuthenticatorActivity?\n        get() = activity as? AuthenticatorActivity\n    val options: RequestOptions?\n        get() = authenticatorActivity?.options\n\n    fun startTransportHandling(transport: Transport, userInfo: String? = null) =\n        authenticatorActivity?.startTransportHandling(transport, pinRequested = pinViewModel.pinRequest, authenticatorPin = pinViewModel.pin, userInfo = userInfo)\n    fun shouldStartTransportInstantly(transport: Transport) = authenticatorActivity?.shouldStartTransportInstantly(transport) == true\n\n    abstract override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View?\n}\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/ui/AuthenticatorActivityFragmentData.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.ui\n\nimport android.os.Bundle\nimport org.microg.gms.fido.core.transport.Transport\nimport org.microg.gms.fido.core.ui.AuthenticatorActivityFragmentData.Companion.KEY_IS_FIRST\n\nclass AuthenticatorActivityFragmentData(val arguments: Bundle = Bundle()) {\n    var appName: String?\n        get() = arguments.getString(KEY_APP_NAME)\n        set(value) = arguments.putString(KEY_APP_NAME, value)\n\n    var isFirst: Boolean\n        get() = arguments.getBoolean(KEY_IS_FIRST, true)\n        set(value) = arguments.putBoolean(KEY_IS_FIRST, value)\n\n    var supportedTransports: Set<Transport>\n        get() = arguments.getStringArrayList(KEY_SUPPORTED_TRANSPORTS)?.map { Transport.valueOf(it) }?.toSet().orEmpty()\n        set(value) = arguments.putStringArrayList(KEY_SUPPORTED_TRANSPORTS, ArrayList(value.map { it.name }))\n\n    val implementedTransports: Set<Transport>\n        get() = AuthenticatorActivity.IMPLEMENTED_TRANSPORTS\n\n    var privilegedCallerName: String?\n        get() = arguments.getString(KEY_PRIVILEGED_CALLER_NAME)\n        set(value) = arguments.putString(KEY_PRIVILEGED_CALLER_NAME, value)\n\n    var requiresPrivilege: Boolean\n        get() = arguments.getBoolean(KEY_REQUIRES_PRIVILEGE)\n        set(value) = arguments.putBoolean(KEY_REQUIRES_PRIVILEGE, value)\n\n    companion object {\n        const val KEY_APP_NAME = \"appName\"\n        const val KEY_IS_FIRST = \"isFirst\"\n        const val KEY_SUPPORTED_TRANSPORTS = \"supportedTransports\"\n        const val KEY_REQUIRES_PRIVILEGE = \"requiresPrivilege\"\n        const val KEY_PRIVILEGED_CALLER_NAME = \"privilegedCallerName\"\n    }\n}\n\nfun Bundle?.withIsFirst(isFirst: Boolean) = Bundle(this ?: Bundle.EMPTY).apply { putBoolean(KEY_IS_FIRST, isFirst) }\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/ui/NfcTransportFragment.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.ui\n\nimport android.graphics.drawable.Animatable2\nimport android.graphics.drawable.AnimatedVectorDrawable\nimport android.graphics.drawable.Drawable\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.Bundle\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport androidx.lifecycle.lifecycleScope\nimport androidx.navigation.fragment.findNavController\nimport androidx.navigation.navOptions\nimport kotlinx.coroutines.Job\nimport kotlinx.coroutines.delay\nimport org.microg.gms.fido.core.R\nimport org.microg.gms.fido.core.databinding.FidoNfcTransportFragmentBinding\nimport org.microg.gms.fido.core.transport.Transport\nimport org.microg.gms.fido.core.transport.TransportHandlerCallback\n\nclass NfcTransportFragment : AuthenticatorActivityFragment(), TransportHandlerCallback {\n    private lateinit var binding: FidoNfcTransportFragmentBinding\n    private var job: Job? = null\n\n    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {\n        binding = FidoNfcTransportFragmentBinding.inflate(inflater, container, false)\n        binding.data = data\n        binding.onBackClick = View.OnClickListener {\n            if (!findNavController().navigateUp()) {\n                findNavController().navigate(\n                    R.id.transportSelectionFragment,\n                    arguments,\n                    navOptions { popUpTo(R.id.usbFragment) { inclusive = true } })\n            }\n        }\n        if (SDK_INT >= 23) {\n            (binding.fidoNfcWaitConnectAnimation.drawable as? AnimatedVectorDrawable)?.registerAnimationCallback(object :\n                Animatable2.AnimationCallback() {\n                override fun onAnimationEnd(drawable: Drawable?) {\n                    lifecycleScope.launchWhenStarted {\n                        delay(250)\n                        (drawable as? AnimatedVectorDrawable)?.reset()\n                        delay(500)\n                        (drawable as? AnimatedVectorDrawable)?.start()\n                    }\n                }\n            })\n            (binding.fidoNfcWaitConnectAnimation.drawable as? AnimatedVectorDrawable)?.start()\n        }\n        return binding.root\n    }\n\n    override fun onStatusChanged(transport: Transport, status: String, extras: Bundle?) {\n        if (transport != Transport.NFC) return\n        binding.status = status\n    }\n\n    override fun onStart() {\n        super.onStart()\n        job = startTransportHandling(Transport.NFC)\n    }\n\n    override fun onStop() {\n        job?.cancel()\n        super.onStop()\n    }\n}\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/ui/PinFragment.kt",
    "content": "package org.microg.gms.fido.core.ui\n\nimport android.os.Bundle\nimport android.view.KeyEvent\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.view.inputmethod.EditorInfo\nimport android.view.inputmethod.InputMethodManager\nimport android.widget.Button\nimport android.widget.EditText\nimport androidx.core.content.getSystemService\nimport androidx.databinding.adapters.TextViewBindingAdapter\nimport androidx.fragment.app.activityViewModels\nimport androidx.lifecycle.ViewModel\nimport androidx.navigation.fragment.findNavController\nimport androidx.navigation.navOptions\nimport org.microg.gms.fido.core.R\nimport org.microg.gms.fido.core.databinding.FidoPinFragmentBinding\n\nclass AuthenticatorPinViewModel : ViewModel() {\n    var pinRequest: Boolean = false\n    var pin: String? = null\n}\n\nclass PinFragment: AuthenticatorActivityFragment() {\n    private lateinit var binding: FidoPinFragmentBinding\n    private val pinViewModel: AuthenticatorPinViewModel by activityViewModels()\n\n    override fun onCreateView(\n        inflater: LayoutInflater,\n        container: ViewGroup?,\n        savedInstanceState: Bundle?\n    ): View {\n        binding = FidoPinFragmentBinding.inflate(inflater, container, false)\n        binding.onCancel = View.OnClickListener {\n            leaveFragment()\n        }\n        binding.onEnterPin = View.OnClickListener {\n            enterPin()\n        }\n        binding.onInputChange = TextViewBindingAdapter.AfterTextChanged {\n            view?.findViewById<Button>(R.id.pin_fragment_ok)?.isEnabled = it.toString().encodeToByteArray().size in 4..63\n        }\n        binding.root.findViewById<EditText>(R.id.pin_editor)?.setOnEditorActionListener { v, actionId, event ->\n            if (actionId == EditorInfo.IME_ACTION_DONE &&\n                (event == null || event.action == KeyEvent.ACTION_DOWN) &&\n                v.text.toString().encodeToByteArray().size in 4 ..63) {\n                enterPin()\n                true\n            } else {\n                false\n            }\n        }\n\n        return binding.root\n    }\n\n    override fun onResume() {\n        super.onResume()\n        view?.findViewById<EditText>(R.id.pin_editor)?.let { editText ->\n            requireContext().getSystemService<InputMethodManager>()?.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT)\n        }\n    }\n\n    fun enterPin () {\n        val textEditor = view?.findViewById<EditText>(R.id.pin_editor)\n        if (textEditor != null) {\n            pinViewModel.pin = textEditor.text.toString()\n        }\n        leaveFragment()\n    }\n\n    fun leaveFragment() {\n        pinViewModel.pinRequest = true\n        if (!findNavController().navigateUp()) {\n            findNavController().navigate(\n                R.id.transportSelectionFragment,\n                arguments,\n                navOptions { popUpTo(R.id.usbFragment) { inclusive = true } })\n        }\n    }\n}"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/ui/SignInSelectionFragment.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.ui\n\nimport android.os.Bundle\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.ImageView\nimport android.widget.TextView\nimport androidx.navigation.fragment.findNavController\nimport androidx.recyclerview.widget.LinearLayoutManager\nimport androidx.recyclerview.widget.RecyclerView\nimport com.google.android.gms.common.images.ImageManager\nimport com.google.android.gms.fido.fido2.api.common.ErrorCode\nimport com.google.android.gms.fido.fido2.api.common.PublicKeyCredentialUserEntity\nimport org.microg.gms.fido.core.CredentialUserInfo\nimport org.microg.gms.fido.core.Database\nimport org.microg.gms.fido.core.R\nimport org.microg.gms.fido.core.databinding.FidoSignInSelectionFragmentBinding\nimport org.microg.gms.fido.core.rpId\nimport org.microg.gms.fido.core.transport.Transport\nimport androidx.core.view.isGone\n\nclass SignInSelectionFragment : AuthenticatorActivityFragment() {\n    private lateinit var binding: FidoSignInSelectionFragmentBinding\n\n    private val database by lazy { Database(requireContext()) }\n\n    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {\n        binding = FidoSignInSelectionFragmentBinding.inflate(inflater, container, false)\n        binding.data = data\n        binding.signInKeyRecycler.layoutManager = LinearLayoutManager(requireContext())\n        binding.signInKeyBack.setOnClickListener { requireActivity().finish() }\n        return binding.root.apply { isGone }\n    }\n\n    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {\n        super.onViewCreated(view, savedInstanceState)\n        val rpId = options?.rpId\n        if (rpId.isNullOrEmpty()) {\n            authenticatorActivity?.finishWithError(ErrorCode.UNKNOWN_ERR, \"Missing rpId\")\n            return\n        }\n        val knownRegistrationInfo = database.getKnownRegistrationInfo(rpId)\n        if (knownRegistrationInfo.isEmpty()) {\n            findNavController().navigate(R.id.openWelcomeFragment)\n        } else if (knownRegistrationInfo.size == 1) {\n            val info = knownRegistrationInfo.first()\n            startTransportHandling(info.transport, info.userJson)\n        } else {\n            binding.root.apply { isVisible }\n            binding.signInKeyRecycler.adapter = SignInKeyAdapter(knownRegistrationInfo) { user, transport ->\n                startTransportHandling(transport, user)\n            }\n        }\n    }\n}\n\ninternal class SignInKeyAdapter(val data: List<CredentialUserInfo>, val onKeyClick: (String, Transport) -> Unit) :\n    RecyclerView.Adapter<SignInKeyAdapter.SignInHolder>() {\n\n    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SignInHolder {\n        val view = LayoutInflater.from(parent.context).inflate(R.layout.fido_sign_in_item_layout, parent, false)\n        return SignInHolder(view)\n    }\n\n    override fun onBindViewHolder(holder: SignInHolder, position: Int) {\n        val item = data[position]\n        val user = PublicKeyCredentialUserEntity.parseJson(item.userJson)\n        holder.signInKeyName.text = user.displayName\n        holder.signInKeyEmail.text = user.name\n        user.icon?.let { ImageManager.create(holder.itemView.context).loadImage(it, holder.signInKeyLogo) }\n        holder.itemView.setOnClickListener { onKeyClick(item.userJson, item.transport) }\n    }\n\n    override fun getItemCount(): Int {\n        return data.size\n    }\n\n    inner class SignInHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {\n        val signInKeyLogo: ImageView = itemView.findViewById(R.id.sign_in_key_logo)\n        val signInKeyName: TextView = itemView.findViewById(R.id.sign_in_key_name)\n        val signInKeyEmail: TextView = itemView.findViewById(R.id.sign_in_key_email)\n    }\n}\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/ui/TransportSelectionFragment.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.ui\n\nimport android.os.Bundle\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport androidx.navigation.fragment.findNavController\nimport org.microg.gms.fido.core.R\nimport org.microg.gms.fido.core.databinding.FidoTransportSelectionFragmentBinding\nimport org.microg.gms.fido.core.transport.Transport\nimport org.microg.gms.fido.core.transport.Transport.SCREEN_LOCK\n\nclass TransportSelectionFragment : AuthenticatorActivityFragment() {\n    private lateinit var binding: FidoTransportSelectionFragmentBinding\n\n    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {\n        binding = FidoTransportSelectionFragmentBinding.inflate(inflater, container, false)\n        binding.data = data\n        binding.setOnBluetoothClick {\n            findNavController().navigate(R.id.openBluetoothFragment, arguments.withIsFirst(false))\n        }\n        binding.setOnNfcClick {\n            findNavController().navigate(R.id.openNfcFragment, arguments.withIsFirst(false))\n        }\n        binding.setOnUsbClick {\n            findNavController().navigate(R.id.openUsbFragment, arguments.withIsFirst(false))\n        }\n        binding.setOnScreenLockClick {\n            startTransportHandling(SCREEN_LOCK)\n        }\n        return binding.root\n    }\n}\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/ui/UsbTransportFragment.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.ui\n\nimport android.graphics.drawable.Animatable2\nimport android.graphics.drawable.AnimatedVectorDrawable\nimport android.graphics.drawable.Drawable\nimport android.hardware.usb.UsbDevice\nimport android.hardware.usb.UsbManager\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.Bundle\nimport android.util.Log\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport androidx.lifecycle.lifecycleScope\nimport androidx.navigation.NavOptions\nimport androidx.navigation.fragment.findNavController\nimport androidx.navigation.navOptions\nimport kotlinx.coroutines.Job\nimport kotlinx.coroutines.delay\nimport org.microg.gms.fido.core.R\nimport org.microg.gms.fido.core.databinding.FidoUsbTransportFragmentBinding\nimport org.microg.gms.fido.core.transport.Transport\nimport org.microg.gms.fido.core.transport.TransportHandlerCallback\n\nclass UsbTransportFragment : AuthenticatorActivityFragment(), TransportHandlerCallback {\n    private lateinit var binding: FidoUsbTransportFragmentBinding\n    private var job: Job? = null\n\n    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {\n        binding = FidoUsbTransportFragmentBinding.inflate(inflater, container, false)\n        binding.data = data\n        binding.onBackClick = View.OnClickListener {\n            if (!findNavController().navigateUp()) {\n                findNavController().navigate(\n                    R.id.transportSelectionFragment,\n                    arguments,\n                    navOptions { popUpTo(R.id.usbFragment) { inclusive = true } })\n            }\n        }\n        if (SDK_INT >= 23) {\n            for (imageView in listOfNotNull(binding.fidoUsbWaitConnectAnimation, binding.fidoUsbWaitConfirmAnimation)) {\n                (imageView.drawable as? AnimatedVectorDrawable)?.registerAnimationCallback(object : Animatable2.AnimationCallback() {\n                    override fun onAnimationEnd(drawable: Drawable?) {\n                        lifecycleScope.launchWhenStarted {\n                            delay(250)\n                            (drawable as? AnimatedVectorDrawable)?.reset()\n                            delay(500)\n                            (drawable as? AnimatedVectorDrawable)?.start()\n                        }\n                    }\n                })\n                (imageView.drawable as? AnimatedVectorDrawable)?.start()\n            }\n        }\n        return binding.root\n    }\n\n    override fun onStatusChanged(transport: Transport, status: String, extras: Bundle?) {\n        if (transport != Transport.USB) return\n        binding.status = status\n        if (SDK_INT >= 21) {\n            binding.deviceName =\n                extras?.getParcelable<UsbDevice>(UsbManager.EXTRA_DEVICE)?.productName ?: \"your security key\"\n        } else {\n            binding.deviceName = \"your security key\"\n        }\n    }\n\n    override fun onStart() {\n        super.onStart()\n        job = startTransportHandling(Transport.USB)\n    }\n\n    override fun onStop() {\n        job?.cancel()\n        super.onStop()\n    }\n}\n"
  },
  {
    "path": "play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/ui/WelcomeFragment.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.core.ui\n\nimport android.os.Bundle\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport androidx.navigation.fragment.findNavController\nimport org.microg.gms.fido.core.R\nimport org.microg.gms.fido.core.transport.Transport\nimport org.microg.gms.fido.core.databinding.FidoWelcomeFragmentBinding\n\nclass WelcomeFragment : AuthenticatorActivityFragment() {\n    private lateinit var binding: FidoWelcomeFragmentBinding\n\n    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {\n        binding = FidoWelcomeFragmentBinding.inflate(inflater, container, false)\n        binding.data = data\n        binding.onGetStartedClick = View.OnClickListener {\n            for (transport in data.supportedTransports) {\n                if (shouldStartTransportInstantly(transport)) {\n                    startTransportHandling(transport)\n                    return@OnClickListener\n                }\n            }\n            val next = data.supportedTransports.singleOrNull()?.let {\n                when (it) {\n                    Transport.BLUETOOTH -> R.id.openBluetoothFragmentDirect\n                    Transport.NFC -> R.id.openNfcFragmentDirect\n                    Transport.USB -> R.id.openUsbFragmentDirect\n                    Transport.SCREEN_LOCK -> {\n                        startTransportHandling(Transport.SCREEN_LOCK)\n                        return@OnClickListener\n                    }\n                }\n            } ?: R.id.openTransportSelectionFragment\n            findNavController().navigate(next, arguments.withIsFirst(false))\n        }\n        return binding.root\n    }\n}\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/drawable/fido_nfc_wait_connect.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<vector\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:name=\"vector\"\n    android:width=\"90dp\"\n    android:height=\"160dp\"\n    android:viewportWidth=\"90\"\n    android:viewportHeight=\"160\">\n    <path\n        android:name=\"path\"\n        android:fillColor=\"#757575\"\n        android:pathData=\"M 10 0 L 80 0 C 82.651 0 85.196 1.054 87.071 2.929 C 88.946 4.804 90 7.349 90 10 L 90 150 C 90 152.651 88.946 155.196 87.071 157.071 C 85.196 158.946 82.651 160 80 160 L 10 160 C 7.349 160 4.804 158.946 2.929 157.071 C 1.054 155.196 0 152.651 0 150 L 0 10 C 0 7.349 1.054 4.804 2.929 2.929 C 4.804 1.054 7.349 0 10 0\"\n        android:strokeWidth=\"1\" />\n    <path\n        android:name=\"path_1\"\n        android:fillColor=\"#545454\"\n        android:pathData=\"M 15 10 C 13.674 10 12.402 10.527 11.464 11.464 C 10.527 12.402 10 13.674 10 15 C 10 16.326 10.527 17.598 11.464 18.536 C 12.402 19.473 13.674 20 15 20 C 16.326 20 17.598 19.473 18.536 18.536 C 19.473 17.598 20 16.326 20 15 C 20 13.674 19.473 12.402 18.536 11.464 C 17.598 10.527 16.326 10 15 10 Z\"\n        android:strokeWidth=\"2\"\n        android:strokeColor=\"#cccccc\" />\n    <group android:name=\"group\">\n        <path\n            android:name=\"path_2\"\n            android:fillColor=\"#d8d8d8\"\n            android:pathData=\"M 57.072 32.8 L 65.97 40.851 L 57.919 49.749 L 49.021 41.698 Z\"\n            android:strokeWidth=\"2\"\n            android:strokeColor=\"#545454\" />\n        <path\n            android:name=\"path_3\"\n            android:fillColor=\"#545454\"\n            android:pathData=\"M 48.879 38.876 L 60.744 49.61 C 61.004 49.846 61.198 50.145 61.306 50.48 C 61.413 50.814 61.431 51.17 61.357 51.514 C 61.284 51.857 61.121 52.175 60.885 52.435 L 38.745 76.906 C 37.856 77.889 36.611 78.479 35.287 78.545 C 33.963 78.611 32.666 78.148 31.683 77.259 L 24.268 70.55 C 23.285 69.661 22.695 68.416 22.628 67.092 C 22.562 65.768 23.025 64.471 23.914 63.488 L 46.054 39.017 C 46.29 38.757 46.59 38.563 46.924 38.455 C 47.258 38.347 47.615 38.33 47.958 38.403 C 48.301 38.477 48.619 38.64 48.879 38.876 Z\"\n            android:strokeWidth=\"1\" />\n        <path\n            android:name=\"path_4\"\n            android:fillColor=\"#ddcc44\"\n            android:pathData=\"M 41.391 59.074 C 40.608 58.366 39.621 57.923 38.571 57.81 C 37.521 57.697 36.462 57.919 35.546 58.445 C 34.63 58.971 33.904 59.773 33.472 60.737 C 33.041 61.7 32.925 62.777 33.142 63.81 C 33.36 64.843 33.899 65.782 34.682 66.49 C 35.465 67.199 36.452 67.641 37.502 67.755 C 38.552 67.868 39.611 67.645 40.527 67.12 C 41.443 66.594 42.169 65.791 42.601 64.828 C 43.033 63.864 43.148 62.788 42.931 61.754 C 42.714 60.721 42.174 59.783 41.391 59.074 Z\"\n            android:strokeWidth=\"1\" />\n    </group>\n</vector>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/drawable/fido_usb_wait_confirm.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-License-Identifier: CC-BY-4.0\n  -->\n\n<vector\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:name=\"vector\"\n    android:width=\"90dp\"\n    android:height=\"220dp\"\n    android:viewportWidth=\"90\"\n    android:viewportHeight=\"220\">\n    <group\n        android:name=\"group\"\n        android:translateY=\"-22\">\n        <path\n            android:name=\"path\"\n            android:fillColor=\"#d8d8d8\"\n            android:pathData=\"M 39 170 L 51 170 L 51 182 L 39 182 Z\"\n            android:strokeWidth=\"2\"\n            android:strokeColor=\"#545454\" />\n        <path\n            android:name=\"path_1\"\n            android:fillColor=\"#545454\"\n            android:pathData=\"M 37 180 L 53 180 C 53.53 180 54.039 180.211 54.414 180.586 C 54.789 180.961 55 181.47 55 182 L 55 215 C 55 216.326 54.473 217.598 53.536 218.536 C 52.598 219.473 51.326 220 50 220 L 40 220 C 38.674 220 37.402 219.473 36.464 218.536 C 35.527 217.598 35 216.326 35 215 L 35 182 C 35 181.47 35.211 180.961 35.586 180.586 C 35.961 180.211 36.47 180 37 180 Z\"\n            android:strokeWidth=\"1\" />\n        <path\n            android:name=\"path_2\"\n            android:fillColor=\"#ddcc44\"\n            android:pathData=\"M 45 200 C 43.674 200 42.402 200.527 41.464 201.464 C 40.527 202.402 40 203.674 40 205 C 40 206.326 40.527 207.598 41.464 208.536 C 42.402 209.473 43.674 210 45 210 C 46.326 210 47.598 209.473 48.536 208.536 C 49.473 207.598 50 206.326 50 205 C 50 203.674 49.473 202.402 48.536 201.464 C 47.598 200.527 46.326 200 45 200 Z\"\n            android:strokeWidth=\"1\" />\n        <group\n            android:name=\"group_1\"\n            android:scaleX=\"0.75\"\n            android:scaleY=\"0.75\"\n            android:translateX=\"11.25\"\n            android:translateY=\"51.25\">\n            <path\n                android:name=\"path_3\"\n                android:pathData=\"M 45 195 C 42.349 195 39.804 196.054 37.929 197.929 C 36.054 199.804 35 202.349 35 205 C 35 207.651 36.054 210.196 37.929 212.071 C 39.804 213.946 42.349 215 45 215 C 47.651 215 50.196 213.946 52.071 212.071 C 53.946 210.196 55 207.651 55 205 C 55 202.349 53.946 199.804 52.071 197.929 C 50.196 196.054 47.651 195 45 195 Z\"\n                android:strokeWidth=\"1\"\n                android:strokeColor=\"#ddcc44\" />\n        </group>\n    </group>\n    <path\n        android:name=\"path_4\"\n        android:fillColor=\"#757575\"\n        android:pathData=\"M 10 0 L 80 0 C 82.651 0 85.196 1.054 87.071 2.929 C 88.946 4.804 90 7.349 90 10 L 90 150 C 90 152.651 88.946 155.196 87.071 157.071 C 85.196 158.946 82.651 160 80 160 L 10 160 C 7.349 160 4.804 158.946 2.929 157.071 C 1.054 155.196 0 152.651 0 150 L 0 10 C 0 7.349 1.054 4.804 2.929 2.929 C 4.804 1.054 7.349 0 10 0\"\n        android:strokeWidth=\"1\" />\n    <path\n        android:name=\"path_5\"\n        android:fillColor=\"#545454\"\n        android:pathData=\"M 15 10 C 13.674 10 12.402 10.527 11.464 11.464 C 10.527 12.402 10 13.674 10 15 C 10 16.326 10.527 17.598 11.464 18.536 C 12.402 19.473 13.674 20 15 20 C 16.326 20 17.598 19.473 18.536 18.536 C 19.473 17.598 20 16.326 20 15 C 20 13.674 19.473 12.402 18.536 11.464 C 17.598 10.527 16.326 10 15 10 Z\"\n        android:strokeWidth=\"2\"\n        android:strokeColor=\"#cccccc\" />\n</vector>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/drawable/fido_usb_wait_connect.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-License-Identifier: CC-BY-4.0\n  -->\n\n<vector\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:name=\"vector\"\n    android:width=\"90dp\"\n    android:height=\"220dp\"\n    android:viewportWidth=\"90\"\n    android:viewportHeight=\"220\">\n    <group\n        android:name=\"group\"\n        android:translateY=\"-16\">\n        <path\n            android:name=\"path\"\n            android:fillColor=\"#d8d8d8\"\n            android:pathData=\"M 39 170 L 51 170 L 51 182 L 39 182 Z\"\n            android:strokeWidth=\"2\"\n            android:strokeColor=\"#545454\" />\n        <path\n            android:name=\"path_1\"\n            android:fillColor=\"#545454\"\n            android:pathData=\"M 37 180 L 53 180 C 53.53 180 54.039 180.211 54.414 180.586 C 54.789 180.961 55 181.47 55 182 L 55 215 C 55 216.326 54.473 217.598 53.536 218.536 C 52.598 219.473 51.326 220 50 220 L 40 220 C 38.674 220 37.402 219.473 36.464 218.536 C 35.527 217.598 35 216.326 35 215 L 35 182 C 35 181.47 35.211 180.961 35.586 180.586 C 35.961 180.211 36.47 180 37 180 Z\"\n            android:strokeWidth=\"1\" />\n        <path\n            android:name=\"path_2\"\n            android:fillColor=\"#ddcc44\"\n            android:pathData=\"M 45 200 C 43.674 200 42.402 200.527 41.464 201.464 C 40.527 202.402 40 203.674 40 205 C 40 206.326 40.527 207.598 41.464 208.536 C 42.402 209.473 43.674 210 45 210 C 46.326 210 47.598 209.473 48.536 208.536 C 49.473 207.598 50 206.326 50 205 C 50 203.674 49.473 202.402 48.536 201.464 C 47.598 200.527 46.326 200 45 200 Z\"\n            android:strokeWidth=\"1\" />\n    </group>\n    <path\n        android:name=\"path_4\"\n        android:fillColor=\"#757575\"\n        android:pathData=\"M 10 0 L 80 0 C 82.651 0 85.196 1.054 87.071 2.929 C 88.946 4.804 90 7.349 90 10 L 90 150 C 90 152.651 88.946 155.196 87.071 157.071 C 85.196 158.946 82.651 160 80 160 L 10 160 C 7.349 160 4.804 158.946 2.929 157.071 C 1.054 155.196 0 152.651 0 150 L 0 10 C 0 7.349 1.054 4.804 2.929 2.929 C 4.804 1.054 7.349 0 10 0\"\n        android:strokeWidth=\"1\" />\n    <path\n        android:name=\"path_5\"\n        android:fillColor=\"#545454\"\n        android:pathData=\"M 15 10 C 13.674 10 12.402 10.527 11.464 11.464 C 10.527 12.402 10 13.674 10 15 C 10 16.326 10.527 17.598 11.464 18.536 C 12.402 19.473 13.674 20 15 20 C 16.326 20 17.598 19.473 18.536 18.536 C 19.473 17.598 20 16.326 20 15 C 20 13.674 19.473 12.402 18.536 11.464 C 17.598 10.527 16.326 10 15 10 Z\"\n        android:strokeWidth=\"2\"\n        android:strokeColor=\"#cccccc\" />\n</vector>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/drawable/ic_fido_bluetooth.xml",
    "content": "<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-FileCopyrightText: 2019 The Android Open Source Project\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\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=\"#000\"\n        android:pathData=\"M17.71,7.71L12,2h-1v7.59L6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 11,14.41L11,22h1l5.71,-5.71 -4.3,-4.29 4.3,-4.29zM13,5.83l1.88,1.88L13,9.59L13,5.83zM14.88,16.29L13,18.17v-3.76l1.88,1.88z\" />\n</vector>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/drawable/ic_fido_close_btn.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2025 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:tint=\"?attr/colorOnPrimary\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n    <path\n        android:fillColor=\"#000\"\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,12 19,6.41z\" />\n</vector>"
  },
  {
    "path": "play-services-fido/core/src/main/res/drawable/ic_fido_fingerprint.xml",
    "content": "<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-FileCopyrightText: 2019 The Android Open Source Project\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\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=\"#000\"\n        android:pathData=\"M17.81,4.47c-0.08,0 -0.16,-0.02 -0.23,-0.06C15.66,3.42 14,3 12.01,3c-1.98,0 -3.86,0.47 -5.57,1.41 -0.24,0.13 -0.54,0.04 -0.68,-0.2 -0.13,-0.24 -0.04,-0.55 0.2,-0.68C7.82,2.52 9.86,2 12.01,2c2.13,0 3.99,0.47 6.03,1.52 0.25,0.13 0.34,0.43 0.21,0.67 -0.09,0.18 -0.26,0.28 -0.44,0.28zM3.5,9.72c-0.1,0 -0.2,-0.03 -0.29,-0.09 -0.23,-0.16 -0.28,-0.47 -0.12,-0.7 0.99,-1.4 2.25,-2.5 3.75,-3.27C9.98,4.04 14,4.03 17.15,5.65c1.5,0.77 2.76,1.86 3.75,3.25 0.16,0.22 0.11,0.54 -0.12,0.7 -0.23,0.16 -0.54,0.11 -0.7,-0.12 -0.9,-1.26 -2.04,-2.25 -3.39,-2.94 -2.87,-1.47 -6.54,-1.47 -9.4,0.01 -1.36,0.7 -2.5,1.7 -3.4,2.96 -0.08,0.14 -0.23,0.21 -0.39,0.21zM9.75,21.79c-0.13,0 -0.26,-0.05 -0.35,-0.15 -0.87,-0.87 -1.34,-1.43 -2.01,-2.64 -0.69,-1.23 -1.05,-2.73 -1.05,-4.34 0,-2.97 2.54,-5.39 5.66,-5.39s5.66,2.42 5.66,5.39c0,0.28 -0.22,0.5 -0.5,0.5s-0.5,-0.22 -0.5,-0.5c0,-2.42 -2.09,-4.39 -4.66,-4.39 -2.57,0 -4.66,1.97 -4.66,4.39 0,1.44 0.32,2.77 0.93,3.85 0.64,1.15 1.08,1.64 1.85,2.42 0.19,0.2 0.19,0.51 0,0.71 -0.11,0.1 -0.24,0.15 -0.37,0.15zM16.92,19.94c-1.19,0 -2.24,-0.3 -3.1,-0.89 -1.49,-1.01 -2.38,-2.65 -2.38,-4.39 0,-0.28 0.22,-0.5 0.5,-0.5s0.5,0.22 0.5,0.5c0,1.41 0.72,2.74 1.94,3.56 0.71,0.48 1.54,0.71 2.54,0.71 0.24,0 0.64,-0.03 1.04,-0.1 0.27,-0.05 0.53,0.13 0.58,0.41 0.05,0.27 -0.13,0.53 -0.41,0.58 -0.57,0.11 -1.07,0.12 -1.21,0.12zM14.91,22c-0.04,0 -0.09,-0.01 -0.13,-0.02 -1.59,-0.44 -2.63,-1.03 -3.72,-2.1 -1.4,-1.39 -2.17,-3.24 -2.17,-5.22 0,-1.62 1.38,-2.94 3.08,-2.94 1.7,0 3.08,1.32 3.08,2.94 0,1.07 0.93,1.94 2.08,1.94s2.08,-0.87 2.08,-1.94c0,-3.77 -3.25,-6.83 -7.25,-6.83 -2.84,0 -5.44,1.58 -6.61,4.03 -0.39,0.81 -0.59,1.76 -0.59,2.8 0,0.78 0.07,2.01 0.67,3.61 0.1,0.26 -0.03,0.55 -0.29,0.64 -0.26,0.1 -0.55,-0.04 -0.64,-0.29 -0.49,-1.31 -0.73,-2.61 -0.73,-3.96 0,-1.2 0.23,-2.29 0.68,-3.24 1.33,-2.79 4.28,-4.6 7.51,-4.6 4.55,0 8.25,3.51 8.25,7.83 0,1.62 -1.38,2.94 -3.08,2.94s-3.08,-1.32 -3.08,-2.94c0,-1.07 -0.93,-1.94 -2.08,-1.94s-2.08,0.87 -2.08,1.94c0,1.71 0.66,3.31 1.87,4.51 0.95,0.94 1.86,1.46 3.27,1.85 0.27,0.07 0.42,0.35 0.35,0.61 -0.05,0.23 -0.26,0.38 -0.47,0.38z\" />\n</vector>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/drawable/ic_fido_key.xml",
    "content": "<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-FileCopyrightText: 2019 The Android Open Source Project\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:tint=\"?attr/colorAccent\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n    <path\n        android:fillColor=\"#000\"\n        android:pathData=\"M12.65,10C11.83,7.67 9.61,6 7,6c-3.31,0 -6,2.69 -6,6s2.69,6 6,6c2.61,0 4.83,-1.67 5.65,-4H17v4h4v-4h2v-4H12.65zM7,14c-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": "play-services-fido/core/src/main/res/drawable/ic_fido_nfc.xml",
    "content": "<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-FileCopyrightText: 2019 The Android Open Source Project\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\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=\"#000\"\n        android:pathData=\"M20,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,4h16v16zM18,6h-5c-1.1,0 -2,0.9 -2,2v2.28c-0.6,0.35 -1,0.98 -1,1.72 0,1.1 0.9,2 2,2s2,-0.9 2,-2c0,-0.74 -0.4,-1.38 -1,-1.72L13,8h3v8L8,16L8,8h2L10,6L6,6v12h12L18,6z\" />\n</vector>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/drawable/ic_fido_usb.xml",
    "content": "<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-FileCopyrightText: 2019 The Android Open Source Project\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\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=\"#000\"\n        android:pathData=\"M15,7v4h1v2h-3V5h2l-3,-4 -3,4h2v8H8v-2.07c0.7,-0.37 1.2,-1.08 1.2,-1.93 0,-1.21 -0.99,-2.2 -2.2,-2.2 -1.21,0 -2.2,0.99 -2.2,2.2 0,0.85 0.5,1.56 1.2,1.93V13c0,1.11 0.89,2 2,2h3v3.05c-0.71,0.37 -1.2,1.1 -1.2,1.95 0,1.22 0.99,2.2 2.2,2.2 1.21,0 2.2,-0.98 2.2,-2.2 0,-0.85 -0.49,-1.58 -1.2,-1.95V15h3c1.11,0 2,-0.89 2,-2v-2h1V7h-4z\" />\n</vector>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/drawable-anydpi-v23/fido_nfc_wait_connect.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<animated-vector\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\">\n    <aapt:attr name=\"android:drawable\">\n        <vector\n            android:name=\"vector\"\n            android:width=\"90dp\"\n            android:height=\"160dp\"\n            android:viewportWidth=\"90\"\n            android:viewportHeight=\"160\">\n            <path\n                android:name=\"path\"\n                android:fillColor=\"#757575\"\n                android:pathData=\"M 10 0 L 80 0 C 82.651 0 85.196 1.054 87.071 2.929 C 88.946 4.804 90 7.349 90 10 L 90 150 C 90 152.651 88.946 155.196 87.071 157.071 C 85.196 158.946 82.651 160 80 160 L 10 160 C 7.349 160 4.804 158.946 2.929 157.071 C 1.054 155.196 0 152.651 0 150 L 0 10 C 0 7.349 1.054 4.804 2.929 2.929 C 4.804 1.054 7.349 0 10 0\"\n                android:strokeWidth=\"1\" />\n            <path\n                android:name=\"path_1\"\n                android:fillColor=\"#545454\"\n                android:pathData=\"M 15 10 C 13.674 10 12.402 10.527 11.464 11.464 C 10.527 12.402 10 13.674 10 15 C 10 16.326 10.527 17.598 11.464 18.536 C 12.402 19.473 13.674 20 15 20 C 16.326 20 17.598 19.473 18.536 18.536 C 19.473 17.598 20 16.326 20 15 C 20 13.674 19.473 12.402 18.536 11.464 C 17.598 10.527 16.326 10 15 10 Z\"\n                android:strokeWidth=\"2\"\n                android:strokeColor=\"#cccccc\" />\n            <group android:name=\"group\">\n                <path\n                    android:name=\"path_2\"\n                    android:fillColor=\"#d8d8d8\"\n                    android:pathData=\"M 57.072 32.8 L 65.97 40.851 L 57.919 49.749 L 49.021 41.698 Z\"\n                    android:strokeWidth=\"2\"\n                    android:strokeColor=\"#545454\" />\n                <path\n                    android:name=\"path_3\"\n                    android:fillColor=\"#545454\"\n                    android:pathData=\"M 48.879 38.876 L 60.744 49.61 C 61.004 49.846 61.198 50.145 61.306 50.48 C 61.413 50.814 61.431 51.17 61.357 51.514 C 61.284 51.857 61.121 52.175 60.885 52.435 L 38.745 76.906 C 37.856 77.889 36.611 78.479 35.287 78.545 C 33.963 78.611 32.666 78.148 31.683 77.259 L 24.268 70.55 C 23.285 69.661 22.695 68.416 22.628 67.092 C 22.562 65.768 23.025 64.471 23.914 63.488 L 46.054 39.017 C 46.29 38.757 46.59 38.563 46.924 38.455 C 47.258 38.347 47.615 38.33 47.958 38.403 C 48.301 38.477 48.619 38.64 48.879 38.876 Z\"\n                    android:strokeWidth=\"1\" />\n                <path\n                    android:name=\"path_4\"\n                    android:fillColor=\"#ddcc44\"\n                    android:pathData=\"M 41.391 59.074 C 40.608 58.366 39.621 57.923 38.571 57.81 C 37.521 57.697 36.462 57.919 35.546 58.445 C 34.63 58.971 33.904 59.773 33.472 60.737 C 33.041 61.7 32.925 62.777 33.142 63.81 C 33.36 64.843 33.899 65.782 34.682 66.49 C 35.465 67.199 36.452 67.641 37.502 67.755 C 38.552 67.868 39.611 67.645 40.527 67.12 C 41.443 66.594 42.169 65.791 42.601 64.828 C 43.033 63.864 43.148 62.788 42.931 61.754 C 42.714 60.721 42.174 59.783 41.391 59.074 Z\"\n                    android:strokeWidth=\"1\" />\n            </group>\n        </vector>\n    </aapt:attr>\n    <target android:name=\"group\">\n        <aapt:attr name=\"android:animation\">\n            <objectAnimator\n                android:duration=\"1000\"\n                android:interpolator=\"@android:anim/overshoot_interpolator\"\n                android:propertyName=\"translateY\"\n                android:valueFrom=\"50\"\n                android:valueTo=\"0\"\n                android:valueType=\"floatType\" />\n        </aapt:attr>\n    </target>\n    <target android:name=\"path_2\">\n        <aapt:attr name=\"android:animation\">\n            <set>\n                <objectAnimator\n                    android:duration=\"200\"\n                    android:interpolator=\"@android:interpolator/fast_out_slow_in\"\n                    android:propertyName=\"fillAlpha\"\n                    android:valueFrom=\"0\"\n                    android:valueTo=\"1\"\n                    android:valueType=\"floatType\" />\n                <objectAnimator\n                    android:duration=\"200\"\n                    android:interpolator=\"@android:interpolator/fast_out_slow_in\"\n                    android:propertyName=\"strokeAlpha\"\n                    android:valueFrom=\"0\"\n                    android:valueTo=\"1\"\n                    android:valueType=\"floatType\" />\n            </set>\n        </aapt:attr>\n    </target>\n    <target android:name=\"path_3\">\n        <aapt:attr name=\"android:animation\">\n            <objectAnimator\n                android:duration=\"200\"\n                android:interpolator=\"@android:interpolator/fast_out_slow_in\"\n                android:propertyName=\"fillAlpha\"\n                android:valueFrom=\"0\"\n                android:valueTo=\"1\"\n                android:valueType=\"floatType\" />\n        </aapt:attr>\n    </target>\n    <target android:name=\"path_4\">\n        <aapt:attr name=\"android:animation\">\n            <objectAnimator\n                android:duration=\"200\"\n                android:interpolator=\"@android:interpolator/fast_out_slow_in\"\n                android:propertyName=\"fillAlpha\"\n                android:valueFrom=\"0\"\n                android:valueTo=\"1\"\n                android:valueType=\"floatType\" />\n        </aapt:attr>\n    </target>\n</animated-vector>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/drawable-anydpi-v23/fido_usb_wait_confirm.xml",
    "content": "<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-License-Identifier: CC-BY-4.0\n  -->\n\n<animated-vector\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\">\n    <aapt:attr name=\"android:drawable\">\n        <vector\n            android:name=\"vector\"\n            android:width=\"90dp\"\n            android:height=\"220dp\"\n            android:viewportWidth=\"90\"\n            android:viewportHeight=\"220\">\n            <group\n                android:name=\"group\"\n                android:translateY=\"-22\">\n                <path\n                    android:name=\"path\"\n                    android:fillColor=\"#d8d8d8\"\n                    android:pathData=\"M 39 170 L 51 170 L 51 182 L 39 182 Z\"\n                    android:strokeWidth=\"2\"\n                    android:strokeColor=\"#545454\" />\n                <path\n                    android:name=\"path_1\"\n                    android:fillColor=\"#545454\"\n                    android:pathData=\"M 37 180 L 53 180 C 53.53 180 54.039 180.211 54.414 180.586 C 54.789 180.961 55 181.47 55 182 L 55 215 C 55 216.326 54.473 217.598 53.536 218.536 C 52.598 219.473 51.326 220 50 220 L 40 220 C 38.674 220 37.402 219.473 36.464 218.536 C 35.527 217.598 35 216.326 35 215 L 35 182 C 35 181.47 35.211 180.961 35.586 180.586 C 35.961 180.211 36.47 180 37 180 Z\"\n                    android:strokeWidth=\"1\" />\n                <path\n                    android:name=\"path_2\"\n                    android:fillColor=\"#ddcc44\"\n                    android:pathData=\"M 45 200 C 43.674 200 42.402 200.527 41.464 201.464 C 40.527 202.402 40 203.674 40 205 C 40 206.326 40.527 207.598 41.464 208.536 C 42.402 209.473 43.674 210 45 210 C 46.326 210 47.598 209.473 48.536 208.536 C 49.473 207.598 50 206.326 50 205 C 50 203.674 49.473 202.402 48.536 201.464 C 47.598 200.527 46.326 200 45 200 Z\"\n                    android:strokeWidth=\"1\" />\n                <group android:name=\"group_1\">\n                    <path\n                        android:name=\"path_3\"\n                        android:pathData=\"M 45 195 C 42.349 195 39.804 196.054 37.929 197.929 C 36.054 199.804 35 202.349 35 205 C 35 207.651 36.054 210.196 37.929 212.071 C 39.804 213.946 42.349 215 45 215 C 47.651 215 50.196 213.946 52.071 212.071 C 53.946 210.196 55 207.651 55 205 C 55 202.349 53.946 199.804 52.071 197.929 C 50.196 196.054 47.651 195 45 195 Z\"\n                        android:strokeWidth=\"1\"\n                        android:strokeColor=\"#ddcc44\" />\n                </group>\n            </group>\n            <path\n                android:name=\"path_4\"\n                android:fillColor=\"#757575\"\n                android:pathData=\"M 10 0 L 80 0 C 82.651 0 85.196 1.054 87.071 2.929 C 88.946 4.804 90 7.349 90 10 L 90 150 C 90 152.651 88.946 155.196 87.071 157.071 C 85.196 158.946 82.651 160 80 160 L 10 160 C 7.349 160 4.804 158.946 2.929 157.071 C 1.054 155.196 0 152.651 0 150 L 0 10 C 0 7.349 1.054 4.804 2.929 2.929 C 4.804 1.054 7.349 0 10 0\"\n                android:strokeWidth=\"1\" />\n            <path\n                android:name=\"path_5\"\n                android:fillColor=\"#545454\"\n                android:pathData=\"M 15 10 C 13.674 10 12.402 10.527 11.464 11.464 C 10.527 12.402 10 13.674 10 15 C 10 16.326 10.527 17.598 11.464 18.536 C 12.402 19.473 13.674 20 15 20 C 16.326 20 17.598 19.473 18.536 18.536 C 19.473 17.598 20 16.326 20 15 C 20 13.674 19.473 12.402 18.536 11.464 C 17.598 10.527 16.326 10 15 10 Z\"\n                android:strokeWidth=\"2\"\n                android:strokeColor=\"#cccccc\" />\n        </vector>\n    </aapt:attr>\n    <target android:name=\"group_1\">\n        <aapt:attr name=\"android:animation\">\n            <set>\n                <objectAnimator\n                    android:duration=\"1000\"\n                    android:interpolator=\"@android:interpolator/fast_out_slow_in\"\n                    android:propertyName=\"translateX\"\n                    android:valueFrom=\"22.5\"\n                    android:valueTo=\"0\"\n                    android:valueType=\"floatType\" />\n                <objectAnimator\n                    android:duration=\"1000\"\n                    android:interpolator=\"@android:interpolator/fast_out_slow_in\"\n                    android:propertyName=\"scaleX\"\n                    android:valueFrom=\"0.5\"\n                    android:valueTo=\"1\"\n                    android:valueType=\"floatType\" />\n                <objectAnimator\n                    android:duration=\"1000\"\n                    android:interpolator=\"@android:interpolator/fast_out_slow_in\"\n                    android:propertyName=\"translateY\"\n                    android:valueFrom=\"102.5\"\n                    android:valueTo=\"0\"\n                    android:valueType=\"floatType\" />\n                <objectAnimator\n                    android:duration=\"1000\"\n                    android:interpolator=\"@android:interpolator/fast_out_slow_in\"\n                    android:propertyName=\"scaleY\"\n                    android:valueFrom=\"0.5\"\n                    android:valueTo=\"1\"\n                    android:valueType=\"floatType\" />\n            </set>\n        </aapt:attr>\n    </target>\n    <target android:name=\"path_3\">\n        <aapt:attr name=\"android:animation\">\n            <set>\n                <objectAnimator\n                    android:duration=\"500\"\n                    android:interpolator=\"@android:interpolator/fast_out_slow_in\"\n                    android:propertyName=\"strokeAlpha\"\n                    android:valueFrom=\"0\"\n                    android:valueTo=\"1\"\n                    android:valueType=\"floatType\" />\n                <objectAnimator\n                    android:duration=\"500\"\n                    android:interpolator=\"@android:interpolator/fast_out_slow_in\"\n                    android:propertyName=\"strokeAlpha\"\n                    android:startOffset=\"500\"\n                    android:valueFrom=\"1\"\n                    android:valueTo=\"0\"\n                    android:valueType=\"floatType\" />\n            </set>\n        </aapt:attr>\n    </target>\n</animated-vector>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/drawable-anydpi-v23/fido_usb_wait_connect.xml",
    "content": "<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-License-Identifier: CC-BY-4.0\n  -->\n\n<animated-vector\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\">\n    <aapt:attr name=\"android:drawable\">\n        <vector\n            android:name=\"vector\"\n            android:width=\"90dp\"\n            android:height=\"220dp\"\n            android:viewportWidth=\"90\"\n            android:viewportHeight=\"220\">\n            <group android:name=\"group\">\n                <path\n                    android:name=\"path\"\n                    android:pathData=\"M 39 170 L 51 170 L 51 182 L 39 182 Z\"\n                    android:fillColor=\"#d8d8d8\"\n                    android:strokeColor=\"#545454\"\n                    android:strokeWidth=\"2\"/>\n                <path\n                    android:name=\"path_1\"\n                    android:pathData=\"M 37 180 L 53 180 C 53.53 180 54.039 180.211 54.414 180.586 C 54.789 180.961 55 181.47 55 182 L 55 215 C 55 216.326 54.473 217.598 53.536 218.536 C 52.598 219.473 51.326 220 50 220 L 40 220 C 38.674 220 37.402 219.473 36.464 218.536 C 35.527 217.598 35 216.326 35 215 L 35 182 C 35 181.47 35.211 180.961 35.586 180.586 C 35.961 180.211 36.47 180 37 180 Z\"\n                    android:fillColor=\"#545454\"\n                    android:strokeWidth=\"1\"/>\n                <path\n                    android:name=\"path_2\"\n                    android:pathData=\"M 45 200 C 43.674 200 42.402 200.527 41.464 201.464 C 40.527 202.402 40 203.674 40 205 C 40 206.326 40.527 207.598 41.464 208.536 C 42.402 209.473 43.674 210 45 210 C 46.326 210 47.598 209.473 48.536 208.536 C 49.473 207.598 50 206.326 50 205 C 50 203.674 49.473 202.402 48.536 201.464 C 47.598 200.527 46.326 200 45 200 Z\"\n                    android:fillColor=\"#ddcc44\"\n                    android:strokeWidth=\"1\"/>\n            </group>\n            <path\n                android:name=\"path_4\"\n                android:pathData=\"M 10 0 L 80 0 C 82.651 0 85.196 1.054 87.071 2.929 C 88.946 4.804 90 7.349 90 10 L 90 150 C 90 152.651 88.946 155.196 87.071 157.071 C 85.196 158.946 82.651 160 80 160 L 10 160 C 7.349 160 4.804 158.946 2.929 157.071 C 1.054 155.196 0 152.651 0 150 L 0 10 C 0 7.349 1.054 4.804 2.929 2.929 C 4.804 1.054 7.349 0 10 0\"\n                android:fillColor=\"#757575\"\n                android:strokeWidth=\"1\"/>\n            <path\n                android:name=\"path_5\"\n                android:pathData=\"M 15 10 C 13.674 10 12.402 10.527 11.464 11.464 C 10.527 12.402 10 13.674 10 15 C 10 16.326 10.527 17.598 11.464 18.536 C 12.402 19.473 13.674 20 15 20 C 16.326 20 17.598 19.473 18.536 18.536 C 19.473 17.598 20 16.326 20 15 C 20 13.674 19.473 12.402 18.536 11.464 C 17.598 10.527 16.326 10 15 10 Z\"\n                android:fillColor=\"#545454\"\n                android:strokeColor=\"#cccccc\"\n                android:strokeWidth=\"2\"/>\n        </vector>\n    </aapt:attr>\n    <target android:name=\"group\">\n        <aapt:attr name=\"android:animation\">\n            <set>\n                <objectAnimator\n                    android:propertyName=\"translateY\"\n                    android:duration=\"600\"\n                    android:valueFrom=\"0\"\n                    android:valueTo=\"-16\"\n                    android:valueType=\"floatType\"\n                    android:interpolator=\"@android:interpolator/fast_out_slow_in\"/>\n                <objectAnimator\n                    android:propertyName=\"translateY\"\n                    android:startOffset=\"600\"\n                    android:duration=\"200\"\n                    android:valueFrom=\"-16\"\n                    android:valueTo=\"-22\"\n                    android:valueType=\"floatType\"\n                    android:interpolator=\"@android:interpolator/fast_out_slow_in\"/>\n            </set>\n        </aapt:attr>\n    </target>\n</animated-vector>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/layout/fido_authenticator_activity.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:id=\"@+id/fragment_container\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\" />\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/layout/fido_nfc_transport_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <data>\n\n        <import type=\"android.view.View\" />\n\n        <import type=\"org.microg.gms.fido.core.transport.Transport\" />\n\n        <import type=\"org.microg.gms.fido.core.transport.TransportHandlerCallback\" />\n\n        <variable\n            name=\"data\"\n            type=\"org.microg.gms.fido.core.ui.AuthenticatorActivityFragmentData\" />\n\n        <variable\n            name=\"status\"\n            type=\"String\" />\n\n\n        <variable\n            name=\"onBackClick\"\n            type=\"android.view.View.OnClickListener\" />\n\n    </data>\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\"\n        android:padding=\"24dp\">\n\n        <ImageView\n            android:layout_width=\"32dp\"\n            android:layout_height=\"32dp\"\n            android:scaleType=\"fitXY\"\n            android:src=\"@drawable/ic_fido_key\" />\n\n        <TextView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"24dp\"\n            android:paddingBottom=\"8dp\"\n            android:text=\"@{data.isFirst ? @string/fido_welcome_title(data.appName) : @string/fido_nfc_title}\"\n            android:textAppearance=\"@style/TextAppearance.AppCompat.Title\"\n            tools:text=\"@string/fido_nfc_title\" />\n\n        <TextView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"8dp\"\n            android:text=\"@string/fido_nfc_prompt_body\"\n            android:textAppearance=\"@style/TextAppearance.AppCompat.Body2\" />\n\n        <TextView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"16dp\"\n            android:text=\"@{@string/fido_welcome_body(data.appName)}\"\n            android:textAppearance=\"@style/TextAppearance.AppCompat.Body2\"\n            android:visibility=\"@{data.isFirst ? View.VISIBLE : View.GONE}\"\n            tools:text=\"@string/fido_welcome_body\" />\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"0dp\"\n            android:layout_weight=\"1\"\n            android:gravity=\"center\"\n            android:orientation=\"vertical\"\n            android:visibility=\"@{status == TransportHandlerCallback.STATUS_WAITING_FOR_DEVICE ? View.VISIBLE : View.GONE}\">\n\n            <ImageView\n                android:id=\"@+id/fido_nfc_wait_connect_animation\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:adjustViewBounds=\"true\"\n                android:maxHeight=\"240dp\"\n                android:scaleType=\"fitCenter\"\n                android:src=\"@drawable/fido_nfc_wait_connect\" />\n        </LinearLayout>\n\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:gravity=\"bottom|start\"\n            android:orientation=\"horizontal\"\n            android:visibility=\"@{data.supportedTransports.size() > 1 ? View.VISIBLE : View.GONE}\">\n\n            <Button\n                android:id=\"@android:id/button1\"\n                style=\"@style/Widget.AppCompat.Button.Borderless.Colored\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:minHeight=\"0dp\"\n                android:onClick=\"@{onBackClick}\"\n                android:text=\"@string/fido_transport_modify\"\n                android:textSize=\"12sp\" />\n        </LinearLayout>\n\n    </LinearLayout>\n</layout>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/layout/fido_pin_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout 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    <data>\n\n        <variable\n            name=\"onEnterPin\"\n            type=\"android.view.View.OnClickListener\" />\n\n        <variable\n            name=\"onCancel\"\n            type=\"android.view.View.OnClickListener\" />\n\n        <variable\n            name=\"onInputChange\"\n            type=\"androidx.databinding.adapters.TextViewBindingAdapter.AfterTextChanged\" />\n    </data>\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\"\n        android:padding=\"24dp\">\n\n        <ImageView\n            android:layout_width=\"32dp\"\n            android:layout_height=\"32dp\"\n            android:scaleType=\"fitXY\"\n            android:src=\"@drawable/ic_fido_key\" />\n\n        <TextView\n            android:id=\"@+id/pin_fragment_title\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"24dp\"\n            android:paddingBottom=\"8dp\"\n            android:text=\"@string/fido_pin_title\"\n            android:textAppearance=\"@style/TextAppearance.AppCompat.Title\" />\n\n        <com.google.android.material.textfield.TextInputLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:hint=\"@string/fido_pin_hint\">\n\n            <requestFocus />\n\n            <com.google.android.material.textfield.TextInputEditText\n                android:id=\"@+id/pin_editor\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"16dp\"\n                android:ems=\"10\"\n                android:inputType=\"textPassword\"\n                android:afterTextChanged=\"@{onInputChange}\"\n                android:imeOptions=\"actionDone\"\n                android:autofillHints=\"password\" />\n        </com.google.android.material.textfield.TextInputLayout>\n\n        <LinearLayout\n            android:layout_marginTop=\"24dp\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:gravity=\"bottom|end\"\n            android:orientation=\"horizontal\">\n\n            <Button\n                android:id=\"@+id/pin_fragment_cancel\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"@string/fido_pin_cancel\"\n                android:onClick=\"@{onCancel}\"\n                style=\"@style/Widget.AppCompat.Button.Borderless.Colored\" />\n\n            <Button\n                android:id=\"@+id/pin_fragment_ok\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"@string/fido_pin_ok\"\n                android:onClick=\"@{onEnterPin}\"\n                style=\"@style/Widget.AppCompat.Button.Borderless.Colored\" />\n\n        </LinearLayout>\n    </LinearLayout>\n</layout>"
  },
  {
    "path": "play-services-fido/core/src/main/res/layout/fido_sign_in_item_layout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2025 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:layout_margin=\"12dp\"\n    android:gravity=\"center_vertical\"\n    android:orientation=\"horizontal\">\n\n    <ImageView\n        android:id=\"@+id/sign_in_key_logo\"\n        android:layout_width=\"24dp\"\n        android:layout_height=\"24dp\"\n        android:layout_gravity=\"center_vertical\"\n        android:src=\"@drawable/ic_fido_key\" />\n\n    <LinearLayout\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center_vertical\"\n        android:layout_marginStart=\"16dp\"\n        android:orientation=\"vertical\">\n\n        <TextView\n            android:id=\"@+id/sign_in_key_name\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:textSize=\"14sp\" />\n\n        <TextView\n            android:id=\"@+id/sign_in_key_email\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:paddingVertical=\"2dp\"\n            android:textSize=\"12sp\" />\n\n        <TextView\n            android:id=\"@+id/sign_in_key_description\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/fido_sign_in_selection_description\"\n            android:textSize=\"12sp\" />\n    </LinearLayout>\n</LinearLayout>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/layout/fido_sign_in_selection_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2025 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <data>\n\n        <import type=\"android.view.View\" />\n\n        <variable\n            name=\"data\"\n            type=\"org.microg.gms.fido.core.ui.AuthenticatorActivityFragmentData\" />\n\n    </data>\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\"\n        android:padding=\"24dp\">\n\n        <ImageView\n            android:id=\"@+id/sign_in_key_back\"\n            android:layout_width=\"24dp\"\n            android:layout_height=\"24dp\"\n            android:scaleType=\"fitXY\"\n            android:layout_gravity=\"end\"\n            android:src=\"@drawable/ic_fido_close_btn\" />\n\n        <TextView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"24dp\"\n            android:paddingBottom=\"8dp\"\n            android:gravity=\"center\"\n            android:textSize=\"24dp\"\n            android:text=\"@string/fido_sign_in_selection_title\"\n            android:textAppearance=\"@style/TextAppearance.AppCompat.Title\"\n            tools:text=\"@string/fido_sign_in_selection_title\" />\n\n        <TextView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:gravity=\"center\"\n            android:textSize=\"18dp\"\n            android:text=\"@{@string/fido_sign_in_selection_continue(data.appName)}\"\n            android:textAppearance=\"@style/TextAppearance.AppCompat.Medium\"\n            tools:text=\"@string/fido_sign_in_selection_continue\" />\n\n        <androidx.recyclerview.widget.RecyclerView\n            android:id=\"@+id/sign_in_key_recycler\"\n            android:layout_marginVertical=\"16dp\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"/>\n\n    </LinearLayout>\n</layout>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/layout/fido_transport_selection_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <data>\n\n        <import type=\"android.view.View\" />\n\n        <import type=\"org.microg.gms.fido.core.transport.Transport\" />\n\n        <variable\n            name=\"data\"\n            type=\"org.microg.gms.fido.core.ui.AuthenticatorActivityFragmentData\" />\n\n        <variable\n            name=\"onBluetoothClick\"\n            type=\"android.view.View.OnClickListener\" />\n\n        <variable\n            name=\"onNfcClick\"\n            type=\"android.view.View.OnClickListener\" />\n\n        <variable\n            name=\"onUsbClick\"\n            type=\"android.view.View.OnClickListener\" />\n\n        <variable\n            name=\"onScreenLockClick\"\n            type=\"android.view.View.OnClickListener\" />\n    </data>\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\"\n        android:padding=\"24dp\">\n\n        <ImageView\n            android:layout_width=\"32dp\"\n            android:layout_height=\"32dp\"\n            android:scaleType=\"fitXY\"\n            android:src=\"@drawable/ic_fido_key\" />\n\n        <TextView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"24dp\"\n            android:paddingBottom=\"8dp\"\n            android:text=\"@{data.isFirst ? @string/fido_welcome_title(data.appName): @string/fido_transport_selection_title}\"\n            android:textAppearance=\"@style/TextAppearance.AppCompat.Title\"\n            tools:text=\"@string/fido_transport_selection_title\" />\n\n        <TextView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"8dp\"\n            android:text=\"@string/fido_transport_selection_body\"\n            android:textAppearance=\"@style/TextAppearance.AppCompat.Body2\" />\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:background=\"?selectableItemBackground\"\n            android:clickable=\"@{data.implementedTransports.contains(Transport.BLUETOOTH)}\"\n            android:focusable=\"@{data.implementedTransports.contains(Transport.BLUETOOTH)}\"\n            android:alpha=\"@{data.implementedTransports.contains(Transport.BLUETOOTH) ? 1.0f : 0.5f}\"\n            android:onClick=\"@{onBluetoothClick}\"\n            android:orientation=\"horizontal\"\n            android:visibility=\"@{data.supportedTransports.contains(Transport.BLUETOOTH) ? View.VISIBLE : View.GONE}\">\n\n            <ImageView\n                android:layout_width=\"24dp\"\n                android:layout_height=\"24dp\"\n                android:layout_gravity=\"center\"\n                android:scaleType=\"fitXY\"\n                android:src=\"@drawable/ic_fido_bluetooth\" />\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginStart=\"24dp\"\n                android:layout_marginLeft=\"24dp\"\n                android:orientation=\"vertical\">\n\n                <TextView\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:paddingTop=\"12dp\"\n                    android:paddingBottom=\"12dp\"\n                    android:text=\"@string/fido_transport_selection_bluetooth\"\n                    android:textAppearance=\"@style/TextAppearance.AppCompat.Body1\" />\n\n                <View\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"1dp\"\n                    android:background=\"?attr/colorPrimary\" />\n            </LinearLayout>\n        </LinearLayout>\n\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:background=\"?selectableItemBackground\"\n            android:clickable=\"@{data.implementedTransports.contains(Transport.NFC)}\"\n            android:focusable=\"@{data.implementedTransports.contains(Transport.NFC)}\"\n            android:alpha=\"@{data.implementedTransports.contains(Transport.NFC) ? 1.0f : 0.5f}\"\n            android:onClick=\"@{onNfcClick}\"\n            android:orientation=\"horizontal\"\n            android:visibility=\"@{data.supportedTransports.contains(Transport.NFC) ? View.VISIBLE : View.GONE}\">\n\n            <ImageView\n                android:layout_width=\"24dp\"\n                android:layout_height=\"24dp\"\n                android:layout_gravity=\"center\"\n                android:scaleType=\"fitXY\"\n                android:src=\"@drawable/ic_fido_nfc\" />\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginStart=\"24dp\"\n                android:layout_marginLeft=\"24dp\"\n                android:orientation=\"vertical\">\n\n                <TextView\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:paddingTop=\"12dp\"\n                    android:paddingBottom=\"12dp\"\n                    android:text=\"@string/fido_transport_selection_nfc\"\n                    android:textAppearance=\"@style/TextAppearance.AppCompat.Body1\" />\n\n                <View\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"1dp\"\n                    android:background=\"?attr/colorPrimary\" />\n            </LinearLayout>\n        </LinearLayout>\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:background=\"?selectableItemBackground\"\n            android:clickable=\"@{data.implementedTransports.contains(Transport.USB)}\"\n            android:focusable=\"@{data.implementedTransports.contains(Transport.USB)}\"\n            android:alpha=\"@{data.implementedTransports.contains(Transport.USB) ? 1.0f : 0.5f}\"\n            android:onClick=\"@{onUsbClick}\"\n            android:orientation=\"horizontal\"\n            android:visibility=\"@{data.supportedTransports.contains(Transport.USB) ? View.VISIBLE : View.GONE}\">\n\n            <ImageView\n                android:layout_width=\"24dp\"\n                android:layout_height=\"24dp\"\n                android:layout_gravity=\"center\"\n                android:scaleType=\"fitXY\"\n                android:src=\"@drawable/ic_fido_usb\" />\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginStart=\"24dp\"\n                android:layout_marginLeft=\"24dp\"\n                android:orientation=\"vertical\">\n\n                <TextView\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:paddingTop=\"12dp\"\n                    android:paddingBottom=\"12dp\"\n                    android:text=\"@string/fido_transport_selection_usb\"\n                    android:textAppearance=\"@style/TextAppearance.AppCompat.Body1\" />\n\n                <View\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"1dp\"\n                    android:background=\"?attr/colorPrimary\" />\n            </LinearLayout>\n        </LinearLayout>\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:background=\"?selectableItemBackground\"\n            android:clickable=\"@{data.implementedTransports.contains(Transport.SCREEN_LOCK)}\"\n            android:focusable=\"@{data.implementedTransports.contains(Transport.SCREEN_LOCK)}\"\n            android:alpha=\"@{data.implementedTransports.contains(Transport.SCREEN_LOCK) ? 1.0f : 0.5f}\"\n            android:onClick=\"@{onScreenLockClick}\"\n            android:orientation=\"horizontal\"\n            android:visibility=\"@{data.supportedTransports.contains(Transport.SCREEN_LOCK) ? View.VISIBLE : View.GONE}\">\n\n            <ImageView\n                android:layout_width=\"24dp\"\n                android:layout_height=\"24dp\"\n                android:layout_gravity=\"center\"\n                android:scaleType=\"fitXY\"\n                android:src=\"@drawable/ic_fido_fingerprint\" />\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginStart=\"24dp\"\n                android:layout_marginLeft=\"24dp\"\n                android:orientation=\"vertical\">\n\n                <TextView\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:paddingTop=\"12dp\"\n                    android:paddingBottom=\"12dp\"\n                    android:text=\"@string/fido_transport_selection_biometric\"\n                    android:textAppearance=\"@style/TextAppearance.AppCompat.Body1\" />\n\n                <View\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"1dp\"\n                    android:background=\"?attr/colorPrimary\" />\n            </LinearLayout>\n        </LinearLayout>\n    </LinearLayout>\n</layout>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/layout/fido_usb_transport_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <data>\n\n        <import type=\"android.view.View\" />\n\n        <import type=\"org.microg.gms.fido.core.transport.Transport\" />\n\n        <import type=\"org.microg.gms.fido.core.transport.TransportHandlerCallback\" />\n\n        <variable\n            name=\"data\"\n            type=\"org.microg.gms.fido.core.ui.AuthenticatorActivityFragmentData\" />\n\n        <variable\n            name=\"status\"\n            type=\"String\" />\n\n        <variable\n            name=\"deviceName\"\n            type=\"String\" />\n\n\n        <variable\n            name=\"onBackClick\"\n            type=\"android.view.View.OnClickListener\" />\n\n    </data>\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\"\n        android:padding=\"24dp\">\n\n        <ImageView\n            android:layout_width=\"32dp\"\n            android:layout_height=\"32dp\"\n            android:scaleType=\"fitXY\"\n            android:src=\"@drawable/ic_fido_key\" />\n\n        <TextView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"24dp\"\n            android:paddingBottom=\"8dp\"\n            android:text=\"@{data.isFirst ? @string/fido_welcome_title(data.appName) : @string/fido_usb_title}\"\n            android:textAppearance=\"@style/TextAppearance.AppCompat.Title\"\n            tools:text=\"@string/fido_usb_title\" />\n\n        <TextView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"8dp\"\n            android:text=\"@string/fido_usb_prompt_body\"\n            android:textAppearance=\"@style/TextAppearance.AppCompat.Body2\" />\n\n        <TextView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"16dp\"\n            android:text=\"@{@string/fido_welcome_body(data.appName)}\"\n            android:textAppearance=\"@style/TextAppearance.AppCompat.Body2\"\n            android:visibility=\"@{data.isFirst ? View.VISIBLE : View.GONE}\"\n            tools:text=\"@string/fido_welcome_body\" />\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"0dp\"\n            android:layout_weight=\"1\"\n            android:gravity=\"center\"\n            android:orientation=\"vertical\"\n            android:visibility=\"@{status == TransportHandlerCallback.STATUS_WAITING_FOR_DEVICE ? View.VISIBLE : View.GONE}\">\n\n            <ImageView\n                android:id=\"@+id/fido_usb_wait_connect_animation\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:adjustViewBounds=\"true\"\n                android:maxHeight=\"240dp\"\n                android:scaleType=\"fitCenter\"\n                android:src=\"@drawable/fido_usb_wait_connect\" />\n\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center_horizontal\"\n                android:layout_marginTop=\"16dp\"\n                android:layout_marginBottom=\"16dp\"\n                android:text=\"@string/fido_transport_usb_wait_connect_body\" />\n        </LinearLayout>\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"0dp\"\n            android:layout_weight=\"1\"\n            android:gravity=\"center\"\n            android:orientation=\"vertical\"\n            android:visibility=\"@{status == TransportHandlerCallback.STATUS_WAITING_FOR_USER ? View.VISIBLE : View.GONE}\"\n            tools:visibility=\"gone\">\n\n            <ImageView\n                android:id=\"@+id/fido_usb_wait_confirm_animation\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:adjustViewBounds=\"true\"\n                android:maxHeight=\"240dp\"\n                android:scaleType=\"fitCenter\"\n                android:src=\"@drawable/fido_usb_wait_confirm\" />\n\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center_horizontal\"\n                android:layout_marginTop=\"16dp\"\n                android:layout_marginBottom=\"16dp\"\n                android:text='@{@string/fido_transport_usb_wait_confirm_body(deviceName)}'\n                tools:text=\"@string/fido_transport_usb_wait_confirm_body\" />\n        </LinearLayout>\n\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:gravity=\"bottom|start\"\n            android:orientation=\"horizontal\"\n            android:visibility=\"@{data.supportedTransports.size() > 1 ? View.VISIBLE : View.GONE}\">\n\n            <Button\n                android:id=\"@android:id/button1\"\n                style=\"@style/Widget.AppCompat.Button.Borderless.Colored\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:minHeight=\"0dp\"\n                android:onClick=\"@{onBackClick}\"\n                android:text=\"@string/fido_transport_modify\"\n                android:textSize=\"12sp\" />\n        </LinearLayout>\n\n    </LinearLayout>\n</layout>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/layout/fido_welcome_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<layout 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    <data>\n\n        <variable\n            name=\"data\"\n            type=\"org.microg.gms.fido.core.ui.AuthenticatorActivityFragmentData\" />\n\n        <variable\n            name=\"onGetStartedClick\"\n            type=\"android.view.View.OnClickListener\" />\n\n        <import type=\"android.view.View\" />\n    </data>\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\"\n        android:padding=\"24dp\">\n\n        <ImageView\n            android:layout_width=\"32dp\"\n            android:layout_height=\"32dp\"\n            android:scaleType=\"fitXY\"\n            android:src=\"@drawable/ic_fido_key\" />\n\n        <TextView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"24dp\"\n            android:paddingBottom=\"8dp\"\n            android:text=\"@{@string/fido_welcome_title(data.appName)}\"\n            android:textAppearance=\"@style/TextAppearance.AppCompat.Title\"\n            tools:text=\"@string/fido_welcome_title\" />\n\n        <TextView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@{@string/fido_welcome_body(data.appName)}\"\n            android:textAppearance=\"@style/TextAppearance.AppCompat.Body2\"\n            tools:text=\"@string/fido_welcome_body\" />\n\n        <TextView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"8dp\"\n            android:textAppearance=\"@style/TextAppearance.AppCompat.Body2\"\n            android:visibility=\"@{data.privilegedCallerName != null ? View.VISIBLE : View.GONE}\"\n            android:text=\"@{@string/fido_welcome_privileged_info(data.privilegedCallerName, data.appName)}\"\n            tools:text=\"@string/fido_welcome_privileged_info\" />\n\n        <androidx.appcompat.widget.SwitchCompat\n            android:id=\"@+id/privilegedCheck\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"4dp\"\n            android:visibility=\"@{data.requiresPrivilege ? View.VISIBLE : View.GONE}\"\n            android:text=\"@{@string/fido_welcome_privileged_check(data.privilegedCallerName)}\"\n            tools:text=\"@string/fido_welcome_privileged_check\" />\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:layout_marginTop=\"48dp\"\n            android:gravity=\"bottom|end\"\n            android:orientation=\"horizontal\">\n\n            <Button\n                android:id=\"@android:id/button1\"\n                style=\"@style/Widget.AppCompat.Button.Colored\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:enabled=\"@{privilegedCheck.checked || !data.requiresPrivilege}\"\n                android:onClick=\"@{onGetStartedClick}\"\n                android:text=\"@string/fido_welcome_button_get_started\" />\n        </LinearLayout>\n\n    </LinearLayout>\n</layout>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/navigation/nav_fido_authenticator.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<navigation 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/nav_fido_authenticator\"\n    app:startDestination=\"@id/welcomeFragment\">\n\n    <fragment\n        android:id=\"@+id/welcomeFragment\"\n        android:name=\"org.microg.gms.fido.core.ui.WelcomeFragment\"\n        tools:layout=\"@layout/fido_welcome_fragment\">\n        <argument\n            android:name=\"appName\"\n            app:argType=\"string\" />\n\n        <action\n            android:id=\"@+id/openTransportSelectionFragment\"\n            app:destination=\"@id/transportSelectionFragment\" />\n        <action\n            android:id=\"@+id/openBluetoothFragmentDirect\"\n            app:destination=\"@id/bluetoothFragment\" />\n        <action\n            android:id=\"@+id/openNfcFragmentDirect\"\n            app:destination=\"@id/nfcFragment\" />\n        <action\n            android:id=\"@+id/openUsbFragmentDirect\"\n            app:destination=\"@id/usbFragment\" />\n    </fragment>\n\n    <fragment\n        android:id=\"@+id/transportSelectionFragment\"\n        android:name=\"org.microg.gms.fido.core.ui.TransportSelectionFragment\"\n        tools:layout=\"@layout/fido_transport_selection_fragment\">\n        <argument\n            android:name=\"appName\"\n            app:argType=\"string\" />\n        <argument\n            android:name=\"isFirst\"\n            app:argType=\"boolean\" />\n\n        <action\n            android:id=\"@+id/openBluetoothFragment\"\n            app:destination=\"@id/bluetoothFragment\" />\n        <action\n            android:id=\"@+id/openNfcFragment\"\n            app:destination=\"@id/nfcFragment\" />\n        <action\n            android:id=\"@+id/openUsbFragment\"\n            app:destination=\"@id/usbFragment\" />\n    </fragment>\n\n    <fragment android:id=\"@+id/bluetoothFragment\" />\n    <fragment\n        android:id=\"@+id/nfcFragment\"\n        android:name=\"org.microg.gms.fido.core.ui.NfcTransportFragment\"\n        tools:layout=\"@layout/fido_nfc_transport_fragment\">\n        <action\n            android:id=\"@+id/openPinFragment\"\n            app:destination=\"@id/pinFragment\" />\n    </fragment>\n    <fragment\n        android:id=\"@+id/usbFragment\"\n        android:name=\"org.microg.gms.fido.core.ui.UsbTransportFragment\"\n        tools:layout=\"@layout/fido_usb_transport_fragment\">\n        <action\n            android:id=\"@+id/openPinFragment\"\n            app:destination=\"@id/pinFragment\" />\n    </fragment>\n\n    <fragment\n        android:id=\"@+id/pinFragment\"\n        android:name=\"org.microg.gms.fido.core.ui.PinFragment\"\n        tools:layout=\"@layout/fido_pin_fragment\" />\n\n    <fragment\n        android:id=\"@+id/signInSelectionFragment\"\n        android:name=\"org.microg.gms.fido.core.ui.SignInSelectionFragment\"\n        tools:layout=\"@layout/fido_sign_in_selection_fragment\">\n        <action\n            android:id=\"@+id/openWelcomeFragment\"\n            app:destination=\"@id/welcomeFragment\" />\n    </fragment>\n\n</navigation>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<resources>\n    <string name=\"fido_welcome_title\">Use your security key with %1$s</string>\n    <string name=\"fido_welcome_body\">Using your security key with %1$s helps protect your private data.</string>\n    <string name=\"fido_welcome_button_get_started\">Get started</string>\n    <string name=\"fido_welcome_privileged_info\">%1$s acts as a trusted browser to use your security key with %2$s.</string>\n    <string name=\"fido_welcome_privileged_check\">Yes, %1$s is my trusted browser and should be allowed to use security keys with third-party websites.</string>\n    <string name=\"fido_transport_selection_title\">Choose how to use your security key</string>\n    <string name=\"fido_transport_selection_body\">Security keys work with Bluetooth, NFC, and USB. Choose how you want to use your key.</string>\n    <string name=\"fido_biometric_prompt_title\">Verify your identity</string>\n    <string name=\"fido_biometric_prompt_body\">\"%1$s needs to verify it's you.\"</string>\n    <string name=\"fido_usb_title\">Connect your USB security key</string>\n    <string name=\"fido_usb_prompt_body\">Connect your security key to the USB port or connect it with an USB cable. If your key has a button or a gold disc, tap it now.</string>\n    <string name=\"fido_nfc_title\">Connect your NFC security key</string>\n    <string name=\"fido_nfc_prompt_body\">Hold your key flat against the back of your device until it stops vibrating</string>\n    <string name=\"fido_transport_selection_bluetooth\">Use security key with Bluetooth</string>\n    <string name=\"fido_transport_selection_nfc\">Use security key with NFC</string>\n    <string name=\"fido_transport_selection_usb\">Use security key with USB</string>\n    <string name=\"fido_transport_selection_biometric\">Use this device with screen lock</string>\n    <string name=\"fido_transport_usb_wait_connect_body\">Please connect your USB security key.</string>\n    <string name=\"fido_transport_usb_wait_confirm_body\">Please tap the golden ring or disc on %1$s.</string>\n    <string name=\"fido_pin_title\">Please enter the PIN for your authenticator</string>\n    <string name=\"fido_pin_hint\">4 to 63 characters</string>\n    <string name=\"fido_pin_ok\">OK</string>\n    <string name=\"fido_pin_cancel\">Cancel</string>\n    <string name=\"fido_wrong_pin\">Wrong PIN entered!</string>\n    <string name=\"fido_transport_modify\">Change how to use your security key</string>\n    <string name=\"fido_sign_in_selection_title\">Select an account</string>\n    <string name=\"fido_sign_in_selection_continue\">to continue using %1$s </string>\n    <string name=\"fido_sign_in_selection_description\">Passkey</string>\n</resources>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-ar/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"fido_welcome_title\">استخدم مفتاح أمانك مع %1$s</string>\n    <string name=\"fido_welcome_body\">استخدام مفتاح أمانك مع %1$s يساهم في حماية بياناتك الشخصية.</string>\n    <string name=\"fido_welcome_button_get_started\">ابدأ</string>\n    <string name=\"fido_welcome_privileged_info\">%1$s يعمل كمتصفح موثوق لاستخدام مفتاح أمانك مع %2$s.</string>\n    <string name=\"fido_welcome_privileged_check\">نعم، %1$s متصفحي الموثوق ويجب السماح له باستخدام مفاتيح الأمان مع مواقع خارجية.</string>\n    <string name=\"fido_transport_selection_title\">اختر كيف تستخدم مفتاح أمانك</string>\n    <string name=\"fido_transport_selection_body\">مفاتيح الأمان تعمل مع البلوتوث وNFC وUSB. اختر كيف تريد استخدام مفتاحك.</string>\n    <string name=\"fido_usb_prompt_body\">قم بتوصيل مفتاح أمانك إلى منفذ الـ USB أو وصله بسلك USB. إذا كان لمفتاحك زر أو قرص ذهبي، اضغط عليه الآن.</string>\n    <string name=\"fido_nfc_title\">قم بتوصيل مفتاح أمان الـ NFC الخاص بك</string>\n    <string name=\"fido_transport_selection_bluetooth\">استخدم مفتاح الأمان مع البلوتوث</string>\n    <string name=\"fido_transport_selection_nfc\">استخدم مفتاح الأمان مع الـ NFC</string>\n    <string name=\"fido_transport_selection_biometric\">استخدم هذا الجهاز بقفل الشاشة</string>\n    <string name=\"fido_transport_usb_wait_connect_body\">يرجى توصيل مفتاح أمان الـ USB الخاص بك.</string>\n    <string name=\"fido_biometric_prompt_title\">تحقق من هويتك</string>\n    <string name=\"fido_biometric_prompt_body\">يحتاج %1$s إلى أن يتحقق من هويتك.</string>\n    <string name=\"fido_usb_title\">قم بتوصيل مفتاح أمان الـ USB الخاص بك</string>\n    <string name=\"fido_transport_selection_usb\">استخدم مفتاح الأمان مع الـ USB</string>\n    <string name=\"fido_nfc_prompt_body\">امسك مفتاحك مستويًا على ظهر جهازك حتى يتوقف الاهتزاز</string>\n    <string name=\"fido_transport_usb_wait_confirm_body\">يرجى الضغط على الحلقة الذهبية أو القرص على %1$s.</string>\n    <string name=\"fido_pin_hint\">من 4 إلى 63 حرفًا</string>\n    <string name=\"fido_pin_ok\">موافق</string>\n    <string name=\"fido_pin_cancel\">إلغاء</string>\n    <string name=\"fido_wrong_pin\">رقم سري خاطئ!</string>\n    <string name=\"fido_pin_title\">يرجى إدخال الرقم السري لجهاز المصادقتك</string>\n    <string name=\"fido_transport_modify\">غير طريقة استخدامك لمفتاح اﻷمان</string>\n    <string name=\"fido_sign_in_selection_title\">اختر حسابًا</string>\n    <string name=\"fido_sign_in_selection_continue\">لمواصلة استخدام %1$s</string>\n    <string name=\"fido_sign_in_selection_description\">مفتاح مرور</string>\n</resources>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-ast/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"fido_welcome_button_get_started\">Comenzar</string>\n    <string name=\"fido_usb_prompt_body\">Conecta la llave de seguranza al puertu USB o conéctala con un cable USB. Si la llave tien un botón o una aniella dorada, tócalos yá.</string>\n    <string name=\"fido_transport_usb_wait_connect_body\">Conecta la to llave USB de seguranza.</string>\n    <string name=\"fido_nfc_prompt_body\">Ten arimada la llave a la parte trasera del preséu hasta qu\\'esti dexe de vibrar</string>\n    <string name=\"fido_welcome_body\">Usar la to llave de seguranza con «%1$s» ayuda a protexer los tos datos privaos.</string>\n    <string name=\"fido_welcome_title\">Usu de llaves de seguranza con «%1$s»</string>\n    <string name=\"fido_transport_selection_biometric\">Usar esti preséu col bloquéu de pantalla</string>\n    <string name=\"fido_welcome_privileged_check\">Sí, «%1$s» ye\\'l mio restolador d\\'enfotu ya habría tener permisu pa usar llaves de seguranza con sitios web de terceros.</string>\n    <string name=\"fido_biometric_prompt_body\">«%1$s» tien de verificar que yes tu.</string>\n    <string name=\"fido_transport_selection_usb\">Usar la llave col USB</string>\n    <string name=\"fido_transport_selection_title\">Cómo usar la llave de seguranza</string>\n    <string name=\"fido_biometric_prompt_title\">Verificación de la identidá</string>\n    <string name=\"fido_usb_title\">Conexón per USB</string>\n    <string name=\"fido_transport_usb_wait_confirm_body\">Toca l\\'aniella dorada o\\'l discu de: %1$s.</string>\n    <string name=\"fido_welcome_privileged_info\">«%1$s» actúa como un restolador d\\'enfotu pa usar la to llave de seguranza con «%2$s».</string>\n    <string name=\"fido_nfc_title\">Conexón per NFC</string>\n    <string name=\"fido_transport_selection_bluetooth\">Usar la llave col bluetooth</string>\n    <string name=\"fido_transport_selection_body\">Les llaves de seguranza funcionen con bluetooth, NFC y USB. Escueyi cómo quies usar la to llave.</string>\n    <string name=\"fido_transport_selection_nfc\">Usar la llave col NFC</string>\n</resources>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-az/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"fido_pin_title\">Xahiş edirik, təsdiqləyiciniz üçün PIN daxil edin</string>\n    <string name=\"fido_pin_hint\">4 - 63 simvol</string>\n    <string name=\"fido_pin_ok\">Oldu</string>\n    <string name=\"fido_pin_cancel\">Ləğv et</string>\n    <string name=\"fido_nfc_prompt_body\">Açarınızı titrəməyi dayandırana kimi cihazınızın arxasına düz tutun</string>\n    <string name=\"fido_transport_selection_bluetooth\">Bluetooth ilə təhlükəsizlik açarın istifadə edin</string>\n    <string name=\"fido_transport_selection_nfc\">NFC ilə təhlükəsizlik açarın istifadə edin</string>\n    <string name=\"fido_transport_selection_usb\">Təhlükəsizlik açarın USB ilə istifadə et</string>\n    <string name=\"fido_transport_selection_biometric\">Bu cihazı ekran kilidi ilə istifadə et</string>\n    <string name=\"fido_transport_usb_wait_connect_body\">USB təhlükəsizlik açarınızı qoşun.</string>\n    <string name=\"fido_transport_usb_wait_confirm_body\">%1$s üzərində qızıl üzük və ya diskə toxunun.</string>\n    <string name=\"fido_welcome_title\">Təhlükəsizlik açarınızı %1$s ilə istifadə edin</string>\n    <string name=\"fido_welcome_body\">Təhlükəsizlik açarınızın %1$s ilə istifadəsi şəxsi məlumatınızı qorumağa kömək edir.</string>\n    <string name=\"fido_welcome_button_get_started\">Başla</string>\n    <string name=\"fido_welcome_privileged_info\">%1$s təhlükəsizlik açarınızı %2$s ilə istifadə etmək üçün etibarlı brauzer kimi işləyir.</string>\n    <string name=\"fido_welcome_privileged_check\">Bəli, %1$s mənim etibarlı brauzerimdir və üçüncü tərəf veb saytları ilə təhlükəsizlik açarların işlətməyə icazə verməlidir.</string>\n    <string name=\"fido_transport_selection_title\">Təhlükəsizlik açarınızı necə istifadə edəcəyinizi seçin</string>\n    <string name=\"fido_transport_selection_body\">Təhlükəsizlik açarları Bluetooth, NFC və USB ilə işləyir. Açarınızı necə istifadə edəcəyinizi seçin.</string>\n    <string name=\"fido_biometric_prompt_title\">Kim olduğunuzu təsdiqləyin</string>\n    <string name=\"fido_biometric_prompt_body\">%1$s kimliyinizi təsdiqləməlidir.</string>\n    <string name=\"fido_usb_title\">USB təhlükəsizlik açarınızı qoşun</string>\n    <string name=\"fido_usb_prompt_body\">Təhlükəsizlik açarınızı USB portuna qoşun və ya USB kabel ilə əlaqələndirin. Açarınızın düyməsi və ya qızılı diski varsa, indi ona toxunun.</string>\n    <string name=\"fido_nfc_title\">NFC təhlükəsizlik açarınızı qoşun</string>\n    <string name=\"fido_wrong_pin\">Səhv PIN daxil edilib!</string>\n</resources>"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-be/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  --><resources>\n    <string name=\"fido_welcome_title\">Выкарыстоўваць ваш ключ бяспекі для %1$s</string>\n    <string name=\"fido_welcome_body\">Выкарыстанне ключа бяспекі для %1$s дапамагае абараніць вашыя асабістыя дадзеныя.</string>\n    <string name=\"fido_welcome_button_get_started\">Пачынаем працу</string>\n    <string name=\"fido_welcome_privileged_info\">%1$s выступае ў якасці даверанага браўзэра для выкарыстання вашага ключа бяспекі з %2$s.</string>\n    <string name=\"fido_welcome_privileged_check\">Так, %1$s мой давераны браўзэр, і яму павінна быць дазволена выкарыстоўваць ключы бяспекі на іншых вэб-сайтах.</string>\n    <string name=\"fido_transport_selection_title\">Выберыце, як выкарыстоўваць ключ бяспекі</string>\n    <string name=\"fido_transport_selection_body\">Ключы бяспекі працуюць з Bluetooth, NFC і USB. Выберыце, як вы хочаце выкарыстоўваць свой ключ.</string>\n    <string name=\"fido_biometric_prompt_title\">Пацвердзіце сваю асобу</string>\n    <string name=\"fido_biometric_prompt_body\">\"%1$s павінен пацвердзіць, што гэта вы.\"</string>\n    <string name=\"fido_usb_title\">Падключыце USB ключ бяспекі</string>\n    <string name=\"fido_usb_prompt_body\">Падключыце ключ бяспекі да USB-парта або з дапамогай USB-кабеля. Калі на вашым ключы ёсць кнопка, дакраніцеся яе.</string>\n    <string name=\"fido_nfc_title\">Падключыце свой NFC ключ бяспекі</string>\n    <string name=\"fido_nfc_prompt_body\">Прыцісніце ключ да задняй панэлі прылады, пакуль яно не перастане вібраваць</string>\n    <string name=\"fido_transport_selection_bluetooth\">Выкарыстоўваць ключ бяспекі з Bluetooth</string>\n    <string name=\"fido_transport_selection_nfc\">Выкарыстоўваць ключ бяспекі з NFC</string>\n    <string name=\"fido_transport_selection_usb\">Выкарыстоўваць ключ бяспекі з USB</string>\n    <string name=\"fido_transport_selection_biometric\">Выкарыстоўваць гэтую прыладу з заблакаваным экранам</string>\n    <string name=\"fido_transport_usb_wait_connect_body\">Калі ласка, падключыце ваш USB-ключ бяспекі.</string>\n    <string name=\"fido_transport_usb_wait_confirm_body\">Калі ласка, краніце залатога кальца або дыска на %1$s.</string>\n    <string name=\"fido_pin_ok\">OK</string>\n    <string name=\"fido_wrong_pin\">Няправільны PIN-код!</string>\n    <string name=\"fido_pin_title\">Увядзіце PIN-код вашага аўтэнтыфікатара</string>\n    <string name=\"fido_pin_cancel\">Адмена</string>\n    <string name=\"fido_pin_hint\">Ад 4 да 63 сімвалаў</string>\n</resources>"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-bn/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n</resources>"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-ca/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"fido_welcome_title\">Utilitzeu la vostra clau de seguretat amb %1$s</string>\n    <string name=\"fido_welcome_body\">Utilitzar la vostra clau de seguretat amb %1$s vos ajuda a protegir les vostres dades.</string>\n    <string name=\"fido_welcome_button_get_started\">Comença</string>\n    <string name=\"fido_welcome_privileged_info\">%1$s actua com un navegador de confiança per utilitzar la vostra clau de seguretat amb %2$s.</string>\n    <string name=\"fido_welcome_privileged_check\">Sí, %1$s és el meu navegador de confiança i s\\'hauria de permetre que utilitzi claus de seguretat amb llocs web de tercers.</string>\n    <string name=\"fido_transport_selection_title\">Trieu com fer servir la vostra clau de seguretat</string>\n    <string name=\"fido_transport_selection_body\">Les claus de seguretat funcionen amb Bluetooth, NFC i USB. Trieu com voleu utilitzar la vostra clau.</string>\n    <string name=\"fido_biometric_prompt_title\">Verifica la teva identitat</string>\n    <string name=\"fido_biometric_prompt_body\">%1$s necessita verificar que ets tu.</string>\n    <string name=\"fido_usb_title\">Connecteu la vostra clau de seguretat USB</string>\n    <string name=\"fido_usb_prompt_body\">Connecteu la vostra clau de seguretat al port USB o connecteu-la amb un cable USB. Si la vostra clau té un botó o un disc daurat, toqueu-lo ara.</string>\n    <string name=\"fido_nfc_title\">Connecteu la vostra clau de seguretat NFC</string>\n    <string name=\"fido_nfc_prompt_body\">Premeu la tecla contra la part posterior del dispositiu fins que deixi de vibrar</string>\n    <string name=\"fido_transport_selection_bluetooth\">Utilitzeu la clau de seguretat amb Bluetooth</string>\n    <string name=\"fido_transport_usb_wait_connect_body\">Desa localment les ubicacions de la xarxa mòbil quan s\\'utilitza el GPS.</string>\n    <string name=\"fido_transport_usb_wait_confirm_body\">Si us plau, toqueu l\\'anell o el disc daurat en %1$s.</string>\n    <string name=\"fido_pin_title\">Introduïu el PIN del vostre autenticador</string>\n    <string name=\"fido_pin_hint\">De 4 a 63 caràcters</string>\n    <string name=\"fido_pin_ok\">D\\'acord</string>\n    <string name=\"fido_pin_cancel\">Cancel·lar</string>\n    <string name=\"fido_wrong_pin\">El PIN introduït és incorrecte!</string>\n    <string name=\"fido_transport_modify\">Canvieu com utilitzar la vostra clau de seguretat</string>\n    <string name=\"fido_sign_in_selection_title\">Seleccioneu un compte</string>\n    <string name=\"fido_sign_in_selection_continue\">per continuar utilitzant %1$s</string>\n    <string name=\"fido_sign_in_selection_description\">Contrasenya d\\'accés</string>\n    <string name=\"fido_transport_selection_nfc\">Utilitzeu la clau de seguretat amb NFC</string>\n    <string name=\"fido_transport_selection_usb\">Utilitzeu la clau de seguretat amb USB</string>\n    <string name=\"fido_transport_selection_biometric\">Utilitza aquest dispositiu amb bloqueig de pantalla</string>\n</resources>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-cs/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"fido_welcome_title\">Použijte svůj bezpečnostní klíč s %1$s</string>\n    <string name=\"fido_welcome_body\">Použitím svého bezpečnostního klíče s %1$s lépe ochráníte svá soukromá data.</string>\n    <string name=\"fido_welcome_privileged_info\">%1$s funguje jako důvěryhodný prohlížeč, který používá váš bezpečnostní klíč s %2$s.</string>\n    <string name=\"fido_transport_selection_title\">Zvolte, jak chcete používat váš bezpečnostní klíč</string>\n    <string name=\"fido_transport_selection_body\">Bezpečnostní klíče fungují přes Bluetooth, NFC a USB. Zvolte, jak chcete používat váš klíč.</string>\n    <string name=\"fido_biometric_prompt_body\">%1$s potřebuje ověřit, že jste to vy.</string>\n    <string name=\"fido_usb_prompt_body\">Připojte svůj bezpečnostní klíč do USB portu nebo jej připojte pomocí USB kabelu. Pokud je váš klíč vybaven tlačítkem nebo zlatým kruhem, klepněte na něj.</string>\n    <string name=\"fido_nfc_title\">Připojte svůj NFC bezpečnostní klíč</string>\n    <string name=\"fido_transport_selection_bluetooth\">Použít bezpečnostní klíč s Bluetooth</string>\n    <string name=\"fido_transport_selection_nfc\">Použít bezpečnostní klíč s NFC</string>\n    <string name=\"fido_transport_selection_usb\">Použít bezpečnostní klíč s USB</string>\n    <string name=\"fido_transport_selection_biometric\">Použít toto zařízení se zámkem obrazovky</string>\n    <string name=\"fido_transport_usb_wait_connect_body\">Připojte prosím svůj USB bezpečnostní klíč.</string>\n    <string name=\"fido_transport_usb_wait_confirm_body\">Klepněte prosím na zlatý kruh na %1$s.</string>\n    <string name=\"fido_welcome_button_get_started\">Začínáme</string>\n    <string name=\"fido_welcome_privileged_check\">Ano, %1$s je můj důvěryhodný prohlížeč a měl by mít přístup k používání bezpečnostních klíčů s webovými stránkami třetích stran.</string>\n    <string name=\"fido_biometric_prompt_title\">Ověřte svou totožnost</string>\n    <string name=\"fido_usb_title\">Připojte svůj bezpečnostní USB klíč</string>\n    <string name=\"fido_nfc_prompt_body\">Podržte klávesu naplocho na zadní straně zařízení, dokud zařízení nepřestane vibrovat</string>\n    <string name=\"fido_pin_title\">Zadejte prosím PIN vašeho autentifikátoru</string>\n    <string name=\"fido_pin_hint\">4 až 63 znaků</string>\n    <string name=\"fido_pin_ok\">OK</string>\n    <string name=\"fido_wrong_pin\">Zadán nesprávný PIN!</string>\n    <string name=\"fido_pin_cancel\">Zrušit</string>\n    <string name=\"fido_transport_modify\">Změnit používání bezpečnostního klíče</string>\n    <string name=\"fido_sign_in_selection_title\">Vyberte účet</string>\n    <string name=\"fido_sign_in_selection_continue\">který chcete používat v aplikaci %1$s</string>\n    <string name=\"fido_sign_in_selection_description\">Přístupový klíč</string>\n</resources>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-de/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"fido_usb_title\">Schließe deinen USB-Sicherheitsschlüssel an</string>\n    <string name=\"fido_welcome_title\">Verwende deinen Sicherheitsschlüssel mit %1$s</string>\n    <string name=\"fido_welcome_privileged_info\">%1$s fungiert als vertrauenswürdiger Browser zur Verwendung deines Sicherheitsschlüssels mit %2$s.</string>\n    <string name=\"fido_transport_selection_body\">Sicherheitsschlüssel funktionieren mit Bluetooth, NFC und USB. Wähle aus, wie du deinen Schlüssel verwenden möchtest.</string>\n    <string name=\"fido_usb_prompt_body\">Stecke deinen Sicherheitsschlüssel in den USB-Anschluss oder verbinde ihn mit einem USB-Kabel. Wenn dein Schlüssel eine Taste oder eine goldene Scheibe hat, tippe jetzt darauf.</string>\n    <string name=\"fido_transport_usb_wait_confirm_body\">Bitte tippe auf den goldenen Ring oder die goldene Scheibe auf %1$s.</string>\n    <string name=\"fido_welcome_body\">Die Verwendung deines Sicherheitsschlüssels mit %1$s hilft, deine privaten Daten zu schützen.</string>\n    <string name=\"fido_welcome_button_get_started\">Los geht’s</string>\n    <string name=\"fido_welcome_privileged_check\">Ja, %1$s ist mein vertrauenswürdiger Browser und sollte Sicherheitsschlüssel für Webseiten von Drittanbietern verwenden dürfen.</string>\n    <string name=\"fido_transport_selection_title\">Wähle aus, wie du deinen Sicherheitsschlüssel verwendest</string>\n    <string name=\"fido_biometric_prompt_title\">Verifiziere deine Identität</string>\n    <string name=\"fido_biometric_prompt_body\">%1$s muss verifizieren, dass du es bist.</string>\n    <string name=\"fido_nfc_title\">Verbinde deinen NFC-Sicherheitsschlüssel</string>\n    <string name=\"fido_nfc_prompt_body\">Halte deinen Schlüssel flach auf die Rückseite deines Geräts, bis es aufhört zu vibrieren</string>\n    <string name=\"fido_transport_selection_bluetooth\">Sicherheitsschlüssel mit Bluetooth verwenden</string>\n    <string name=\"fido_transport_selection_nfc\">Sicherheitsschlüssel mit NFC verwenden</string>\n    <string name=\"fido_transport_selection_usb\">Sicherheitsschlüssel mit USB verwenden</string>\n    <string name=\"fido_transport_selection_biometric\">Dieses Gerät mit Bildschirmsperre verwenden</string>\n    <string name=\"fido_transport_usb_wait_connect_body\">Bitte schließe deinen USB-Sicherheitsschlüssel an.</string>\n    <string name=\"fido_pin_title\">Bitte gib die PIN für deinen Authentifikator ein</string>\n    <string name=\"fido_pin_hint\">4 bis 63 Zeichen</string>\n    <string name=\"fido_pin_ok\">OK</string>\n    <string name=\"fido_pin_cancel\">Abbrechen</string>\n    <string name=\"fido_wrong_pin\">Falsche PIN eingegeben!</string>\n    <string name=\"fido_transport_modify\">Ändere, wie du deinen Sicherheitsschlüssel verwendest</string>\n    <string name=\"fido_sign_in_selection_title\">Wähle ein Konto aus</string>\n    <string name=\"fido_sign_in_selection_description\">Passkey</string>\n    <string name=\"fido_sign_in_selection_continue\">um weiterhin %1$s zu verwenden</string>\n</resources>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-eo/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources></resources>"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-es/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"fido_welcome_title\">Utilice su clave de seguridad con %1$s</string>\n    <string name=\"fido_transport_selection_body\">Las llaves de seguridad funcionan con Bluetooth, NFC y USB. Elija cómo quiere usar su llave.</string>\n    <string name=\"fido_welcome_body\">Utilizar su llave de seguridad con %1$s le ayuda a proteger sus datos privados.</string>\n    <string name=\"fido_welcome_button_get_started\">Empezar</string>\n    <string name=\"fido_welcome_privileged_info\">%1$s actúa como navegador de confianza para utilizar su clave de seguridad con %2$s.</string>\n    <string name=\"fido_welcome_privileged_check\">Sí, %1$s es mi navegador de confianza y debería poder utilizar claves de seguridad con sitios web de terceros.</string>\n    <string name=\"fido_transport_selection_title\">Elija cómo utilizar su clave de seguridad</string>\n    <string name=\"fido_biometric_prompt_title\">Compruebe su identidad</string>\n    <string name=\"fido_biometric_prompt_body\">%1$s necesita verificar que se trata de usted.</string>\n    <string name=\"fido_usb_title\">Conecte su llave de seguridad USB</string>\n    <string name=\"fido_usb_prompt_body\">Conecte su llave de seguridad al puerto USB o conéctela con un cable USB. Si su llave tiene un botón o un disco dorado, tóquelo ahora.</string>\n    <string name=\"fido_nfc_title\">Conecte su llave de seguridad NFC</string>\n    <string name=\"fido_nfc_prompt_body\">Mantén la llave apoyada en la parte posterior del dispositivo hasta que deje de vibrar</string>\n    <string name=\"fido_transport_selection_bluetooth\">Utilizar la clave de seguridad con Bluetooth</string>\n    <string name=\"fido_transport_selection_nfc\">Utilizar la clave de seguridad con NFC</string>\n    <string name=\"fido_transport_selection_usb\">Utilizar la llave de seguridad con USB</string>\n    <string name=\"fido_transport_selection_biometric\">Utilizar este dispositivo con bloqueo de pantalla</string>\n    <string name=\"fido_transport_usb_wait_connect_body\">Conecte su llave de seguridad USB.</string>\n    <string name=\"fido_transport_usb_wait_confirm_body\">Toque el anillo o disco dorado en %1$s.</string>\n    <string name=\"fido_pin_hint\">De 4 a 63 caracteres</string>\n    <string name=\"fido_pin_title\">Introduzca el PIN de su autenticador</string>\n    <string name=\"fido_pin_ok\">Aceptar</string>\n    <string name=\"fido_pin_cancel\">Cancelar</string>\n    <string name=\"fido_wrong_pin\">Se introdujo el PIN incorrecto.</string>\n    <string name=\"fido_transport_modify\">Cambie cómo se usa la llave de seguridad</string>\n    <string name=\"fido_sign_in_selection_title\">Seleccione una cuenta</string>\n    <string name=\"fido_sign_in_selection_continue\">para continuar utilizando %1$s</string>\n    <string name=\"fido_sign_in_selection_description\">Passkey</string>\n</resources>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-fa/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"fido_welcome_button_get_started\">آغاز کنید</string>\n    <string name=\"fido_welcome_privileged_info\">%1$s به عنوان یک مرورگر مورد اعتماد برای استفاده از کلید امنیتی شما با %2$s عمل می‌کند.</string>\n    <string name=\"fido_welcome_privileged_check\">بله، %1$s مرورگر مورد اعتماد من است و باید اجازه استفاده از کلیدهای امنیتی با وبگاه‌های شخص ثالث را داشته باشد.</string>\n    <string name=\"fido_biometric_prompt_title\">هویت خود را ثابت کنید</string>\n    <string name=\"fido_transport_selection_title\">انتخاب کنید چگونه از کلید امنیتی خود استفاده کنید</string>\n    <string name=\"fido_transport_selection_body\">کلیدهای امنیتی با بلوتوث، ان‌اف‌سی و یو‌اس‌بی کار می‌کنند. انتخاب کنید چگونه می‌خواهید از کلید خود استفاده کنید.</string>\n    <string name=\"fido_biometric_prompt_body\">%1$s نیاز دارد ثابت کند که این شما هستید.</string>\n    <string name=\"fido_usb_title\">کلید امنیتی یو‌اس‌بی خود را متصل کنید</string>\n    <string name=\"fido_nfc_title\">کلید امنیتی ان‌اف‌سی خود را متصل کنید</string>\n    <string name=\"fido_nfc_prompt_body\">کلید خود را به صورت صاف روی پشت دستگاه خود نگه دارید تا زمانی که لرزش آن متوقف شود</string>\n    <string name=\"fido_transport_selection_bluetooth\">استفاده از کلید امنیتی با بلوتوث</string>\n    <string name=\"fido_transport_selection_usb\">استفاده از کلید امنیتی با یو‌اس‌بی</string>\n    <string name=\"fido_transport_selection_nfc\">استفاده از کلید امنیتی با ان‌اف‌سی</string>\n    <string name=\"fido_transport_selection_biometric\">استفاده از این دستگاه با قفل صفحه</string>\n    <string name=\"fido_transport_usb_wait_connect_body\">لطفاً کلید امنیتی یو‌اس‌بی خود را متصل کنید.</string>\n    <string name=\"fido_pin_title\">لطفاً رمز کوتاه احرازکننده هویت خود را وارد کنید</string>\n    <string name=\"fido_pin_cancel\">رد کردن</string>\n    <string name=\"fido_wrong_pin\">رمز کوتاه اشتباه وارد شد!</string>\n    <string name=\"fido_transport_usb_wait_confirm_body\">لطفاً روی حلقه یا دیسک طلایی روی %1$s ضربه بزنید.</string>\n    <string name=\"fido_transport_modify\">تغییر روش استفاده از کلید امنیتی</string>\n    <string name=\"fido_welcome_title\">از کلید امنیتی خود با %1$s استفاده کنید</string>\n    <string name=\"fido_welcome_body\">استفاده از کلید امنیتی با %1$s به محافظت از داده‌های خصوصی شما کمک می‌کند.</string>\n    <string name=\"fido_usb_prompt_body\">کلید امنیتی خود را به درگاه یو‌اس‌بی متصل کنید یا آن را با کابل یو‌اس‌بی وصل کنید. اگر کلید شما دکمه یا دیسک طلایی دارد، اکنون روی آن ضربه بزنید.</string>\n    <string name=\"fido_pin_hint\">۴ تا ۶۳ نویسه</string>\n    <string name=\"fido_pin_ok\">پذیرش</string>\n    <string name=\"fido_sign_in_selection_title\">یک حساب را انتخاب کنید</string>\n    <string name=\"fido_sign_in_selection_continue\">برای ادامه با %1$s</string>\n    <string name=\"fido_sign_in_selection_description\">کلید عبور</string>\n</resources>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-fi/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"fido_welcome_title\">Käytä turva-avaintasi %1$s</string>\n    <string name=\"fido_welcome_body\">Turva-avaimen käyttäminen %1$s avulla auttaa suojelemaan yksityisiä tietojasi.</string>\n    <string name=\"fido_welcome_button_get_started\">Aloita</string>\n    <string name=\"fido_welcome_privileged_info\">%1$s toimii luotettuna selaimena käyttääkseen turva-avaintasi %2$s avulla.</string>\n    <string name=\"fido_welcome_privileged_check\">Kyllä, %1$s on minun luotettu selaimeni jolle tulisi myöntää lupa käyttää turva-avaimia kolmannen osapuolen sivustoilla.</string>\n    <string name=\"fido_transport_selection_title\">Valitse miten haluat käyttää turva-avaintasi</string>\n    <string name=\"fido_transport_selection_body\">Turva-avaimet toimivat Bluetoothin, NFC:n ja USB:n kanssa. Valitse, miten haluat käyttää avaintasi.</string>\n</resources>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-fil/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"fido_welcome_title\">Gamitin ang iyong security key sa %1$s</string>\n    <string name=\"fido_welcome_body\">Ang paggamit ng security key sa %1$s ay tinutulungang protektahan ang iyong pribadong data.</string>\n    <string name=\"fido_welcome_button_get_started\">Magsimula</string>\n    <string name=\"fido_welcome_privileged_check\">Oo, ang %1$s ay ang aking pinagkakatiwalaang browser at papayagan na gamitin ang mga security key sa mga third-party na website.</string>\n    <string name=\"fido_transport_selection_title\">Pumili kung paano gamitin ang iyong security key</string>\n    <string name=\"fido_biometric_prompt_title\">I-verify ang iyong pagkakakilanlan</string>\n    <string name=\"fido_biometric_prompt_body\">Kailangang i-verify ka ng %1$s.</string>\n    <string name=\"fido_usb_title\">Konektahin ang iyong USB security key</string>\n    <string name=\"fido_usb_prompt_body\">Konektahin ang iyong security key sa USB port o konektahin gamit ng USB cable. Kapag may button o gintong disc ang iyong key, i-tap ngayon.</string>\n    <string name=\"fido_nfc_prompt_body\">Hawakan ng patag ang iyong key sa likod ng iyong device hanggang sa tumigil ito sa pag-vibrate</string>\n    <string name=\"fido_transport_selection_bluetooth\">Gamitin ang iyong security key gamit ng Bluetooth</string>\n    <string name=\"fido_transport_selection_nfc\">Gamitin ang iyong security gamit ng NFC</string>\n    <string name=\"fido_transport_selection_usb\">Gamitin ang security key gamit ng USB</string>\n    <string name=\"fido_transport_usb_wait_connect_body\">Paki-konekta ng iyong USB security key.</string>\n    <string name=\"fido_transport_usb_wait_confirm_body\">Paki-tap ang gintong ring o disc sa %1$s.</string>\n    <string name=\"fido_welcome_privileged_info\">Ang %1$s ay gumaganap bilang pinagkakatiwalaang browser para gamitin ang iyong security key sa %2$s.</string>\n    <string name=\"fido_transport_selection_body\">Gumagana ang mga security key sa Bluetooth, NFC, at USB. Piliin kung paano mo gustong gamitin ang iyong key.</string>\n    <string name=\"fido_nfc_title\">Konektahin ang iyong NFC security key</string>\n    <string name=\"fido_transport_selection_biometric\">Gamitin ang device na ito gamit ng screen lock</string>\n    <string name=\"fido_pin_title\">Pakilagay ang PIN para sa iyong authenticator</string>\n    <string name=\"fido_pin_hint\">4 hanggang 63 karakter</string>\n    <string name=\"fido_pin_ok\">OK</string>\n    <string name=\"fido_pin_cancel\">Kanselahin</string>\n    <string name=\"fido_wrong_pin\">Maling PIN ang inilagay!</string>\n    <string name=\"fido_transport_modify\">Baguhin kung paano mo gagamitin ang iyong security key</string>\n</resources>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-fr/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"fido_welcome_title\">Utilisez votre clé de sécurité avec %1$s</string>\n    <string name=\"fido_pin_title\">Merci de saisir le code PIN de votre authentifiant</string>\n    <string name=\"fido_pin_hint\">4 à 63 caractères</string>\n    <string name=\"fido_pin_ok\">OK</string>\n    <string name=\"fido_pin_cancel\">Annuler</string>\n    <string name=\"fido_wrong_pin\">Mauvais code PIN saisi !</string>\n    <string name=\"fido_welcome_body\">Utiliser votre clé de sécurité avec %1$s contribue à protéger vos données privées.</string>\n    <string name=\"fido_welcome_button_get_started\">Commencer</string>\n    <string name=\"fido_welcome_privileged_info\">%1$s agit en tant que navigateur de confiance pour utiliser votre clé de sécurité avec %2$s.</string>\n    <string name=\"fido_welcome_privileged_check\">Oui, %1$s est mon navigateur de confiance et peut être autorisé à utiliser des clés de sécurité avec des sites web tiers.</string>\n    <string name=\"fido_transport_selection_title\">Choisir comment utiliser votre clé de sécurité</string>\n    <string name=\"fido_transport_selection_body\">Les clés de sécurité fonctionnent via Bluetooth, NFC ou USB. Choisissez comment utiliser votre clé.</string>\n    <string name=\"fido_biometric_prompt_title\">Confirmez votre identité</string>\n    <string name=\"fido_biometric_prompt_body\">%1$s nécessite de vérifier que c\\'est bien vous.</string>\n    <string name=\"fido_usb_title\">Connecter votre clé de sécurité USB</string>\n    <string name=\"fido_usb_prompt_body\">Connectez votre clé de sécurité à un port USB ou connectez-là avec un câble USB. Si votre clé a un bouton ou un disque doré, appuyez dessus.</string>\n    <string name=\"fido_nfc_title\">Connecter votre clé de sécurité NFC</string>\n    <string name=\"fido_nfc_prompt_body\">Tenez votre clé contre l\\'arrière de votre appareil jusqu\\'à la fin des vibrations</string>\n    <string name=\"fido_transport_selection_bluetooth\">Utiliser votre clé de sécurité via Bluetooth</string>\n    <string name=\"fido_transport_selection_nfc\">Utiliser votre clé de sécurité via NFC</string>\n    <string name=\"fido_transport_selection_usb\">Utiliser votre clé de sécurité via USB</string>\n    <string name=\"fido_transport_selection_biometric\">Utiliser le verrouillage écran de cet appareil</string>\n    <string name=\"fido_transport_usb_wait_connect_body\">Merci de connecter votre clé de sécurité USB.</string>\n    <string name=\"fido_transport_usb_wait_confirm_body\">Merci d\\'appuyer sur l\\'anneau ou disque doré sur %1$s.</string>\n    <string name=\"fido_transport_modify\">Changer le fonctionnement de votre clé de sécurité</string>\n    <string name=\"fido_sign_in_selection_title\">Sélectionnez un compte</string>\n    <string name=\"fido_sign_in_selection_continue\">pour continuer à utiliser %1$s</string>\n    <string name=\"fido_sign_in_selection_description\">Clé d\\'accès</string>\n</resources>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-ga/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"fido_welcome_title\">Úsáid d\\'eochair shlándála le %1$s</string>\n    <string name=\"fido_welcome_button_get_started\">Cuir tús leis</string>\n    <string name=\"fido_transport_selection_nfc\">Úsáid eochair shlándála le NFC</string>\n    <string name=\"fido_transport_selection_biometric\">Úsáid an gléas seo le glas scáileáin</string>\n    <string name=\"fido_transport_usb_wait_confirm_body\">Tapáil an fáinne órga nó an diosca ar %1$s.</string>\n    <string name=\"fido_welcome_body\">Má úsáideann tú d\\'eochair shlándála le %1$s cuidítear do shonraí príobháideacha a chosaint.</string>\n    <string name=\"fido_welcome_privileged_info\">Feidhmíonn %1$s mar bhrabhsálaí iontaofa chun d\\'eochair shlándála a úsáid le %2$s.</string>\n    <string name=\"fido_biometric_prompt_title\">Fíoraigh d\\'aitheantas</string>\n    <string name=\"fido_welcome_privileged_check\">Sea, is é %1$s mo bhrabhsálaí iontaofa agus ba cheart go mbeadh cead aige eochracha slándála a úsáid le suíomhanna gréasáin tríú páirtí.</string>\n    <string name=\"fido_transport_selection_body\">Oibríonn eochracha slándála le Bluetooth, NFC, agus USB. Roghnaigh conas ba mhaith leat d\\'eochair a úsáid.</string>\n    <string name=\"fido_biometric_prompt_body\">Caithfidh %1$s a fhíorú gur tusa atá ann.</string>\n    <string name=\"fido_transport_selection_title\">Roghnaigh conas d\\'eochair shlándála a úsáid</string>\n    <string name=\"fido_usb_title\">Ceangail d\\'eochair shlándála USB</string>\n    <string name=\"fido_nfc_title\">Ceangail d\\'eochair shlándála NFC</string>\n    <string name=\"fido_usb_prompt_body\">Ceangail d\\'eochair shlándála leis an gcalafort USB nó ceangail le cábla USB í. Má tá cnaipe nó diosca óir ar d’eochair, tapáil anois é.</string>\n    <string name=\"fido_nfc_prompt_body\">Coinnigh d\\'eochair cothrom ar chúl do ghléis go dtí go stopann sé ag creathadh</string>\n    <string name=\"fido_transport_selection_bluetooth\">Bain úsáid as eochair shlándála le Bluetooth</string>\n    <string name=\"fido_transport_usb_wait_connect_body\">Ceangail d\\'eochair shlándála USB le do thoil.</string>\n    <string name=\"fido_transport_selection_usb\">Úsáid eochair shlándála le USB</string>\n    <string name=\"fido_pin_title\">Cuir isteach UAP do fhíordheimhneora</string>\n    <string name=\"fido_pin_hint\">4 go 63 carachtar</string>\n    <string name=\"fido_pin_ok\">Ceart go leor</string>\n    <string name=\"fido_pin_cancel\">Cealaigh</string>\n    <string name=\"fido_wrong_pin\">UAP mícheart curtha isteach!</string>\n    <string name=\"fido_transport_modify\">Athraigh conas d\\'eochair shlándála a úsáid</string>\n    <string name=\"fido_sign_in_selection_title\">Roghnaigh cuntas</string>\n    <string name=\"fido_sign_in_selection_continue\">leanúint ar aghaidh ag úsáid %1$s</string>\n    <string name=\"fido_sign_in_selection_description\">Pas eochair</string>\n</resources>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-hu/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"fido_welcome_title\">Használd a biztonsági kulcsodat ezzel: %1$s</string>\n</resources>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-in/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"fido_welcome_title\">Gunakan kunci keamanan Anda dengan %1$s</string>\n    <string name=\"fido_welcome_body\">Menggunakan kunci keamanan Anda dengan %1$s membantu melindungi data pribadi Anda.</string>\n    <string name=\"fido_welcome_button_get_started\">Memulai</string>\n    <string name=\"fido_welcome_privileged_info\">%1$s berfungsi sebagai browser tepercaya untuk menggunakan kunci keamanan Anda dengan %2$s.</string>\n    <string name=\"fido_welcome_privileged_check\">Ya, %1$s adalah browser tepercaya saya dan seharusnya diizinkan untuk menggunakan kunci keamanan dengan situs web pihak ketiga.</string>\n    <string name=\"fido_transport_selection_title\">Pilih cara menggunakan kunci keamanan Anda</string>\n    <string name=\"fido_transport_selection_body\">Kunci keamanan berfungsi dengan Bluetooth, NFC, dan USB. Pilih cara Anda ingin menggunakan kunci Anda.</string>\n    <string name=\"fido_biometric_prompt_title\">Verifikasi identitas Anda</string>\n    <string name=\"fido_biometric_prompt_body\">%1$s perlu memverifikasi bahwa itu Anda.</string>\n    <string name=\"fido_usb_title\">Hubungkan kunci keamanan USB Anda</string>\n    <string name=\"fido_usb_prompt_body\">Hubungkan kunci keamanan Anda ke port USB atau hubungkan dengan kabel USB. Jika kunci Anda memiliki tombol atau cakram emas, tekan tombol atau cakram tersebut sekarang.</string>\n    <string name=\"fido_nfc_title\">Hubungkan kunci keamanan NFC Anda</string>\n    <string name=\"fido_nfc_prompt_body\">Tempelkan kunci Anda secara datar pada bagian belakang perangkat Anda hingga berhenti bergetar</string>\n    <string name=\"fido_transport_selection_bluetooth\">Gunakan kunci keamanan dengan Bluetooth</string>\n    <string name=\"fido_transport_selection_nfc\">Gunakan kunci keamanan dengan NFC</string>\n    <string name=\"fido_transport_selection_usb\">Gunakan kunci keamanan dengan USB</string>\n    <string name=\"fido_transport_selection_biometric\">Gunakan perangkat ini dengan kunci layar</string>\n    <string name=\"fido_transport_usb_wait_connect_body\">Silakan hubungkan kunci keamanan USB Anda.</string>\n    <string name=\"fido_transport_usb_wait_confirm_body\">Silakan ketuk cincin atau piringan emas pada %1$s.</string>\n    <string name=\"fido_pin_title\">Silakan masukkan PIN untuk autentikator Anda</string>\n    <string name=\"fido_pin_hint\">4 hingga 63 karakter</string>\n    <string name=\"fido_pin_ok\">Oke</string>\n    <string name=\"fido_pin_cancel\">Batal</string>\n    <string name=\"fido_wrong_pin\">PIN yang dimasukkan salah!</string>\n    <string name=\"fido_transport_modify\">Ubah cara penggunaan kunci keamanan Anda</string>\n    <string name=\"fido_sign_in_selection_title\">Pilih akun</string>\n    <string name=\"fido_sign_in_selection_continue\">untuk terus menggunakan %1$s</string>\n    <string name=\"fido_sign_in_selection_description\">Passkey</string>\n</resources>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-is/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"fido_welcome_title\">Notaðu öryggislykilinn þinn með %1$s</string>\n    <string name=\"fido_welcome_privileged_info\">%1$s virkar sem treystur vafri til að nota öryggislykilinn þinn með %2$s.</string>\n    <string name=\"fido_welcome_privileged_check\">Já, %1$s er vafrinn sem ég treysti og ætti að vera leyft að nota öryggislykla með utanaðkomandi vefsvæðum.</string>\n    <string name=\"fido_nfc_prompt_body\">Haltu lyklinum þínum upp við bak tækisins þar til það hættir að titra</string>\n    <string name=\"fido_pin_hint\">4 til 63 stafir</string>\n    <string name=\"fido_welcome_body\">Að nota öryggislykilinn þinn með %1$s hjálpar til við að vernda einkagögnin þín.</string>\n    <string name=\"fido_welcome_button_get_started\">Hefjumst handa</string>\n    <string name=\"fido_transport_selection_title\">Veldu hvernig á að nota öryggislykilinn þinn</string>\n    <string name=\"fido_transport_selection_body\">Öryggislyklar virka með Bluetooth, NFC og USB. Veldu hvernig á að nota öryggislykilinn þinn.</string>\n    <string name=\"fido_biometric_prompt_title\">Sannreyndu auðkennin þín</string>\n    <string name=\"fido_biometric_prompt_body\">%1$s þarf að sannreyna að þetta sért þú.</string>\n    <string name=\"fido_usb_title\">Tengdu USB-öryggislykilinn þinn</string>\n    <string name=\"fido_usb_prompt_body\">Tengdu öryggislykilinn þinn við USB-gátt eða með USB-kapli. Ef minnislykillinn er með hnapp eða gullinn disk, skaltu ýta á hann núna.</string>\n    <string name=\"fido_nfc_title\">Tengdu NFC-öryggislykilinn þinn</string>\n    <string name=\"fido_transport_selection_bluetooth\">Nota öryggislykil með Bluetooth</string>\n    <string name=\"fido_transport_selection_nfc\">Nota öryggislykil með NFC</string>\n    <string name=\"fido_transport_selection_usb\">Nota öryggislykil með USB</string>\n    <string name=\"fido_transport_selection_biometric\">Nota þetta tæki með skjálæsingu</string>\n    <string name=\"fido_transport_usb_wait_connect_body\">Tengdu USB-öryggislykilinn þinn.</string>\n    <string name=\"fido_transport_usb_wait_confirm_body\">Ýttu á gyllta diskinn eða hringinn á %1$s.</string>\n    <string name=\"fido_pin_title\">Settu inn PIN-númerið fyrir auðkenningarforritið</string>\n    <string name=\"fido_pin_ok\">Í lagi</string>\n    <string name=\"fido_pin_cancel\">Hætta við</string>\n    <string name=\"fido_wrong_pin\">Rangt PIN-númer sett inn!</string>\n    <string name=\"fido_transport_modify\">Breyttu því hvernig þú notar öryggislykilinn þinn</string>\n</resources>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-it/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"fido_welcome_button_get_started\">Inizia</string>\n    <string name=\"fido_usb_prompt_body\">Collega la tua chiave di sicurezza alla porta USB, o collegala con un cavo USB. Se la tua chiave ha un pulsante o un disco dorato, premilo ora.</string>\n    <string name=\"fido_transport_usb_wait_connect_body\">Per favore, collega la tua chiave di sicurezza via USB.</string>\n    <string name=\"fido_nfc_prompt_body\">Tieni appoggiata la tua chiave sul retro del tuo dispositivo fino a quando non smette di vibrare</string>\n    <string name=\"fido_welcome_body\">Usare la tua chiave di sicurezza con %1$s aiuta a proteggere i tuoi dati personali.</string>\n    <string name=\"fido_welcome_title\">Usa la tua chiave di sicurezza con %1$s</string>\n    <string name=\"fido_transport_selection_biometric\">Usa questo dispositivo con un blocco schermo</string>\n    <string name=\"fido_welcome_privileged_check\">Sì, %1$s è il mio broswer di fiducia e deve avere il permesso di usare le chiavi di sicurezza con siti web di terze parti.</string>\n    <string name=\"fido_biometric_prompt_body\">%1$s deve verificare che sia tu.</string>\n    <string name=\"fido_transport_selection_usb\">Usa chiave di sicurezza via USB</string>\n    <string name=\"fido_transport_selection_title\">Scegli come usare la tua chiave di sicurezza</string>\n    <string name=\"fido_biometric_prompt_title\">Verifica la tua identità</string>\n    <string name=\"fido_usb_title\">Collega la tua chiave di sicurezza via USB</string>\n    <string name=\"fido_transport_usb_wait_confirm_body\">Per favore, premi l\\'anello o il disco dorato su %1$s.</string>\n    <string name=\"fido_welcome_privileged_info\">%1$s agisce come browser fidato per usare la tua chiave di sicurezza con %2$s.</string>\n    <string name=\"fido_nfc_title\">Collega la tua chiave di sicurezza via NFC</string>\n    <string name=\"fido_transport_selection_bluetooth\">Usa chiave di sicurezza via Bluetooth</string>\n    <string name=\"fido_transport_selection_body\">Le chiavi di sicurezza funzionano via Bluetooth, NFC e USB. Scegli come vuoi usare la tua chiave.</string>\n    <string name=\"fido_transport_selection_nfc\">Usa chiave di sicurezza via NFC</string>\n    <string name=\"fido_pin_title\">Inserisci il PIN per l\\'autenticazione</string>\n    <string name=\"fido_pin_hint\">Da 4 a 63 caratteri</string>\n    <string name=\"fido_pin_ok\">OK</string>\n    <string name=\"fido_pin_cancel\">Annulla</string>\n    <string name=\"fido_wrong_pin\">PIN inserito errato!</string>\n    <string name=\"fido_transport_modify\">Cambia la modalità in cui utilizzi la tua chiave di sicurezza</string>\n    <string name=\"fido_sign_in_selection_title\">Seleziona un account</string>\n    <string name=\"fido_sign_in_selection_continue\">per continuare ad utilizzare %1$s</string>\n    <string name=\"fido_sign_in_selection_description\">Passkey</string>\n</resources>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-iw/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"fido_welcome_privileged_check\">כן, %1$s הוא הדפדפן שנתתי בו אמון וברצוני לאפשר לו להשתמש במפתחות אבטחה עם אתרי צד שלישי.</string>\n</resources>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-ja/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"fido_transport_selection_body\">セキュリティキーは、Bluetooth、NFC、USBで動作します。キーの使用方法を選択してください。</string>\n    <string name=\"fido_nfc_prompt_body\">振動が止まるまで、キーをデバイスの背面に平らにかざします</string>\n    <string name=\"fido_transport_selection_nfc\">NFCでセキュリティキーを使用する</string>\n    <string name=\"fido_transport_selection_usb\">USBでセキュリティキーを使用する</string>\n    <string name=\"fido_pin_hint\">4から63文字</string>\n    <string name=\"fido_welcome_title\">%1$sでセキュリティキーを使用する</string>\n    <string name=\"fido_welcome_body\">%1$sでセキュリティキーを使用すると、プライベートデータを保護できます。</string>\n    <string name=\"fido_welcome_button_get_started\">始める</string>\n    <string name=\"fido_welcome_privileged_info\">%1$sは、%2$sでセキュリティキーを使用する信頼できるブラウザとして機能します。</string>\n    <string name=\"fido_welcome_privileged_check\">はい、%1$sは私の信頼できるブラウザであり、サードパーティのWebサイトでセキュリティキーを使用することが許可されるべきです。</string>\n    <string name=\"fido_transport_selection_title\">セキュリティキーの使用方法を選択してください</string>\n    <string name=\"fido_biometric_prompt_body\">%1$sはあなたであることを確認する必要があります。</string>\n    <string name=\"fido_usb_title\">USBセキュリティキーを接続する</string>\n    <string name=\"fido_usb_prompt_body\">セキュリティキーをUSBポートに接続するか、USBケーブルで接続します。キーにボタンやゴールドディスクがある場合は、今すぐタップしてください。</string>\n    <string name=\"fido_nfc_title\">NFCセキュリティキーを接続する</string>\n    <string name=\"fido_transport_selection_bluetooth\">Bluetoothでセキュリティキーを使用する</string>\n    <string name=\"fido_transport_selection_biometric\">このデバイスでスクリーンロックを使用してください</string>\n    <string name=\"fido_transport_usb_wait_connect_body\">USBセキュリティキーを接続してください。</string>\n    <string name=\"fido_transport_usb_wait_confirm_body\">%1$s の上の金色のリングまたは円盤を押してください。</string>\n    <string name=\"fido_pin_title\">認証アプリのPINを入力してください</string>\n    <string name=\"fido_pin_ok\">OK</string>\n    <string name=\"fido_pin_cancel\">キャンセル</string>\n    <string name=\"fido_wrong_pin\">PINが正しくありません!</string>\n    <string name=\"fido_transport_modify\">セキュリティキーの使用方法を変更する</string>\n    <string name=\"fido_sign_in_selection_title\">アカウントを選択する</string>\n    <string name=\"fido_sign_in_selection_continue\">%1$s を使用して続行する</string>\n    <string name=\"fido_sign_in_selection_description\">パスキー</string>\n    <string name=\"fido_biometric_prompt_title\">本人確認を行う</string>\n</resources>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-ko/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"fido_welcome_title\">%1$s와 보안 키를 사용해보세요</string>\n    <string name=\"fido_welcome_body\">%1$s와 보안 키를 사용하면 개인 데이터를 보호할 수 있습니다.</string>\n    <string name=\"fido_welcome_button_get_started\">시작</string>\n    <string name=\"fido_welcome_privileged_info\">%1$s는 %2$s와 함께 보안 키를 사용하는 신뢰된 브라우저 역할을 합니다.</string>\n    <string name=\"fido_welcome_privileged_check\">네, %1$s는 신뢰할 수 있는 브라우저이며 타사 웹사이트에서 보안 키를 사용할 수 있게 허용합니다.</string>\n    <string name=\"fido_transport_selection_title\">보안 키 사용 방법 선택</string>\n    <string name=\"fido_transport_selection_body\">보안 키는 블루투스, NFC, USB로 작동합니다. 키를 어떻게 사용할지 선택하세요.</string>\n    <string name=\"fido_biometric_prompt_title\">본인 확인</string>\n    <string name=\"fido_biometric_prompt_body\">%1$s은 본인 확인이 필요합니다.</string>\n    <string name=\"fido_transport_selection_bluetooth\">블루투스로 보안 키 사용</string>\n    <string name=\"fido_pin_cancel\">취소</string>\n    <string name=\"fido_usb_title\">USB 보안 키 연결</string>\n    <string name=\"fido_usb_prompt_body\">보안 키를 USB 포트에 연결하거나 USB 케이블로 연결하세요. 키에 버튼이나 금색 디스크가 있는 경우, 지금 눌러주세요.</string>\n    <string name=\"fido_nfc_title\">NFC 보안 키 연결</string>\n    <string name=\"fido_nfc_prompt_body\">진동이 멈출 때까지 키를 기기 뒷면에 대주세요</string>\n    <string name=\"fido_transport_selection_nfc\">NFC로 보안 키 사용</string>\n    <string name=\"fido_transport_selection_usb\">USB로 보안 키 사용</string>\n    <string name=\"fido_transport_selection_biometric\">화면 잠금으로 이 기기 사용</string>\n    <string name=\"fido_transport_usb_wait_connect_body\">USB 보안 키를 연결해 주세요.</string>\n    <string name=\"fido_transport_usb_wait_confirm_body\">%1$s에 있는 금색 링 또는 디스크를 눌러주세요.</string>\n    <string name=\"fido_pin_title\">인증기의 PIN을 입력해주세요</string>\n    <string name=\"fido_pin_hint\">4~63자</string>\n    <string name=\"fido_pin_ok\">확인</string>\n    <string name=\"fido_wrong_pin\">PIN이 잘못되었습니다!</string>\n    <string name=\"fido_transport_modify\">보안 키 사용 방법 변경</string>\n    <string name=\"fido_sign_in_selection_title\">계정 선택</string>\n    <string name=\"fido_sign_in_selection_continue\">%1$s을 계속 이용하려면 계정이 필요합니다</string>\n    <string name=\"fido_sign_in_selection_description\">패스키</string>\n</resources>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-lv/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources></resources>"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-lzh/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources></resources>"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-ml/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"fido_welcome_title\">%1$s-നൊപ്പം നിങ്ങളുടെ സുരക്ഷാ കീ ഉപയോഗിക്കുക</string>\n    <string name=\"fido_welcome_body\">%1$s ഉപയോഗിച്ച് നിങ്ങളുടെ സുരക്ഷാ കീ ഉപയോഗിക്കുന്നത് നിങ്ങളുടെ സ്വകാര്യ ഡാറ്റ പരിരക്ഷിക്കാൻ സഹായിക്കുന്നു.</string>\n    <string name=\"fido_welcome_button_get_started\">ആരംഭിക്കുക</string>\n    <string name=\"fido_welcome_privileged_info\">%2$s-നൊപ്പം നിങ്ങളുടെ സുരക്ഷാ കീ ഉപയോഗിക്കുന്നതിന് %1$s ഒരു വിശ്വസനീയ ബ്രൗസറായി പ്രവർത്തിക്കുന്നു.</string>\n    <string name=\"fido_welcome_privileged_check\">അതെ, %1$s എന്റെ വിശ്വസനീയ ബ്രൗസറാണ്, മൂന്നാം കക്ഷി വെബ്‌സൈറ്റുകളിൽ സുരക്ഷാ കീകൾ ഉപയോഗിക്കാൻ അതിനെ അനുവദിക്കണം.</string>\n    <string name=\"fido_transport_selection_title\">നിങ്ങളുടെ സുരക്ഷാ കീ എങ്ങനെ ഉപയോഗിക്കണമെന്ന് തിരഞ്ഞെടുക്കുക</string>\n    <string name=\"fido_transport_selection_body\">സുരക്ഷാ കീകൾ ബ്ലൂടൂത്ത് , എൻ എഫ് സി , യു എസ് ബി എന്നിവയിൽ പ്രവർത്തിക്കുന്നു. നിങ്ങളുടെ കീ എങ്ങനെ ഉപയോഗിക്കണമെന്ന് തിരഞ്ഞെടുക്കുക.</string>\n    <string name=\"fido_biometric_prompt_title\">നിങ്ങളുടെ ഐഡന്റിറ്റി പരിശോധിക്കുക</string>\n    <string name=\"fido_biometric_prompt_body\">%1$s-ന് ഇത് നിങ്ങളാണെന്ന് സ്ഥിരീകരിക്കേണ്ടതുണ്ട്.</string>\n    <string name=\"fido_usb_title\">നിങ്ങളുടെ USB സുരക്ഷാ കീ ബന്ധിപ്പിക്കുക</string>\n    <string name=\"fido_usb_prompt_body\">നിങ്ങളുടെ സുരക്ഷാ കീ USB പോർട്ടുമായി ബന്ധിപ്പിക്കുക അല്ലെങ്കിൽ ഒരു USB കേബിൾ ഉപയോഗിച്ച് ബന്ധിപ്പിക്കുക. നിങ്ങളുടെ കീയിൽ ഒരു ബട്ടണോ സ്വർണ്ണ ഡിസ്കോ ഉണ്ടെങ്കിൽ, ഇപ്പോൾ അതിൽ ടാപ്പ് ചെയ്യുക.</string>\n    <string name=\"fido_nfc_title\">നിങ്ങളുടെ NFC സുരക്ഷാ കീ ബന്ധിപ്പിക്കുക</string>\n    <string name=\"fido_nfc_prompt_body\">വൈബ്രേറ്റ് ചെയ്യുന്നത് നിർത്തുന്നത് വരെ നിങ്ങളുടെ ഉപകരണത്തിന്റെ പിൻഭാഗത്ത് കീ നേരെ അമർത്തിപ്പിടിക്കുക</string>\n    <string name=\"fido_transport_selection_bluetooth\">ബ്ലൂടൂത്തിനൊപ്പം സുരക്ഷാ കീ ഉപയോഗിക്കുക</string>\n    <string name=\"fido_transport_selection_nfc\">NFC-യിൽ സുരക്ഷാ കീ ഉപയോഗിക്കുക</string>\n    <string name=\"fido_transport_selection_usb\">USB-യിൽ സുരക്ഷാ കീ ഉപയോഗിക്കുക</string>\n    <string name=\"fido_transport_selection_biometric\">സ്ക്രീൻ ലോക്ക് ഉപയോഗിച്ച് ഈ ഉപകരണം ഉപയോഗിക്കുക</string>\n    <string name=\"fido_transport_usb_wait_connect_body\">നിങ്ങളുടെ USB സുരക്ഷാ കീ ബന്ധിപ്പിക്കുക.</string>\n    <string name=\"fido_transport_usb_wait_confirm_body\">%1$s-ലെ സ്വർണ്ണ മോതിരം അല്ലെങ്കിൽ ഡിസ്ക് ടാപ്പ് ചെയ്യുക.</string>\n    <string name=\"fido_pin_title\">നിങ്ങളുടെ ഓതന്റിക്കേറ്ററിന്റെ പിൻ നൽകുക</string>\n    <string name=\"fido_pin_hint\">4 മുതൽ 63 വരെ പ്രതീകങ്ങൾ</string>\n    <string name=\"fido_pin_ok\">ശരി</string>\n    <string name=\"fido_pin_cancel\">റദ്ദാക്കുക</string>\n    <string name=\"fido_wrong_pin\">തെറ്റായ പിൻ നൽകി!</string>\n    <string name=\"fido_transport_modify\">നിങ്ങളുടെ സുരക്ഷാ കീ ഉപയോഗിക്കുന്ന രീതി മാറ്റുക</string>\n</resources>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-nb-rNO/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"fido_welcome_button_get_started\">Begynn</string>\n    <string name=\"fido_welcome_title\">Bruk sikkerhetsnøkkelen din med %1$s</string>\n    <string name=\"fido_welcome_body\">Å bruke sikkerhetsnøkkelen din med %1$s hjelper med å beskytte de private dataene dine.</string>\n    <string name=\"fido_welcome_privileged_info\">%1$s fungerer som en troverdig nettleser for å bruke sikkerhetsnøkkelen din med %2$s.</string>\n    <string name=\"fido_welcome_privileged_check\">Ja, %1$s er en nettleser jeg stoler på og burde få tillatelse til å bruke sikkerhetsnøkler med tredjepartsnettsider.</string>\n    <string name=\"fido_transport_selection_title\">Velg hvordan du vil bruke sikkerhetsnøkkelen din</string>\n    <string name=\"fido_transport_selection_body\">Sikkerhetsnøkler fungerer over Bluetooth, NFC og USB. Velg hvordan du vil bruke nøkkelen din.</string>\n    <string name=\"fido_biometric_prompt_title\">Bekreft identiteten din</string>\n    <string name=\"fido_biometric_prompt_body\">%1$s må bekrefte at det er deg.</string>\n    <string name=\"fido_usb_title\">Koble til sikkerhetsnøkkelen din over USB</string>\n    <string name=\"fido_usb_prompt_body\">Kobl sikkerhetsnøkkelen din til en USB port eller gjennom en USB-kabel. Hvis nøkkelen din er en knapp eller en gullfarget disk, trykk på den nå.</string>\n    <string name=\"fido_nfc_title\">Koble til sikkerhetsnøkkelen din over NFC</string>\n    <string name=\"fido_nfc_prompt_body\">Hold nøkkelen din flatt over baksiden av enheten din til den stopper å vibrere</string>\n    <string name=\"fido_transport_selection_bluetooth\">Koble til sikkerhetsnøkkelen din med Bluetooth</string>\n    <string name=\"fido_transport_selection_nfc\">Bruk sikkerhetsnøkkel med NFC</string>\n    <string name=\"fido_transport_selection_usb\">Bruk sikkerhetsnøkkel med USB</string>\n    <string name=\"fido_transport_selection_biometric\">Bruk denne enheten med skjermlås</string>\n    <string name=\"fido_transport_usb_wait_connect_body\">Koble til USB-sikkerhetsnøkkelen din.</string>\n    <string name=\"fido_transport_usb_wait_confirm_body\">Trykk på den gyldne ringen eller disken på %1$s.</string>\n    <string name=\"fido_pin_title\">Tast inn PIN-koden din for å autentiseres</string>\n    <string name=\"fido_pin_hint\">4 til 63 tegn</string>\n    <string name=\"fido_pin_ok\">OK</string>\n    <string name=\"fido_pin_cancel\">Avbryt</string>\n    <string name=\"fido_wrong_pin\">Feil PIN-kode!</string>\n    <string name=\"fido_transport_modify\">Endre hvordan du vil bruke sikkerhetsnøkkelen din</string>\n    <string name=\"fido_sign_in_selection_title\">Velg en konto</string>\n    <string name=\"fido_sign_in_selection_continue\">for å fortsette med %1$s</string>\n    <string name=\"fido_sign_in_selection_description\">Passnøkkel</string>\n</resources>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-nl/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"fido_nfc_prompt_body\">Houd uw sleutel plat tegen de achterkant van uw apparaat totdat het stopt met trillen.</string>\n    <string name=\"fido_transport_selection_biometric\">Gebruik dit apparaat met schermvergrendeling</string>\n</resources>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-pl/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"fido_welcome_button_get_started\">Rozpocznij</string>\n    <string name=\"fido_usb_prompt_body\">Wsuń klucz bezpieczeństwa do portu USB lub połącz się z nim przez kabel USB. Jeżeli twój klucz ma przycisk lub złoty dysk, teraz go dotknij.</string>\n    <string name=\"fido_transport_usb_wait_connect_body\">Podłącz swój klucz U2F przez USB.</string>\n    <string name=\"fido_nfc_prompt_body\">Przyłóż swój klucz bezpieczeństwa ściśle do tyłu urządzenia i trzymaj, aż twoje urządzenie przestanie wibrować</string>\n    <string name=\"fido_welcome_body\">Używanie swojego klucza bezpieczeństwa z %1$s pomaga chronić twoje prywatne dane.</string>\n    <string name=\"fido_welcome_title\">Używaj swojego klucza U2F z %1$s</string>\n    <string name=\"fido_transport_selection_biometric\">Korzystaj z tego urządzenia przez blokadę ekranu</string>\n    <string name=\"fido_welcome_privileged_check\">Tak, %1$s jest moją zaufaną przeglądarką i powinna mieć dostęp do korzystania z kluczy bezpieczeństwa przez witryny firm trzecich.</string>\n    <string name=\"fido_biometric_prompt_body\">%1$s chce potwierdzić, że to Ty.</string>\n    <string name=\"fido_transport_selection_usb\">Korzystaj z klucza przez USB</string>\n    <string name=\"fido_transport_selection_title\">Wybierz, jak korzystać ze swojego klucza bezpieczeństwa</string>\n    <string name=\"fido_biometric_prompt_title\">Potwierdź swoją tożsamość</string>\n    <string name=\"fido_usb_title\">Połącz ze swoim kluczem przez USB</string>\n    <string name=\"fido_transport_usb_wait_confirm_body\">Dotknij złotego pierścienia lub dysku na %1$s.</string>\n    <string name=\"fido_welcome_privileged_info\">%1$s powinna funkcjonować jako bezpieczna przeglądarka do używania własnego klucza bezpieczeństwa z %2$s.</string>\n    <string name=\"fido_nfc_title\">Połącz ze swoim kluczem przez NFC</string>\n    <string name=\"fido_transport_selection_bluetooth\">Korzystaj z klucza przez Bluetooth</string>\n    <string name=\"fido_transport_selection_body\">Klucze bezpieczeństwa mogą działać przez Bluetooth, NFC i USB. Wybierz jak chcesz korzystać ze swojego klucza.</string>\n    <string name=\"fido_transport_selection_nfc\">Korzystaj z klucza przez NFC</string>\n    <string name=\"fido_wrong_pin\">Wprowadzono błędny kod PIN!</string>\n    <string name=\"fido_pin_title\">Wprowadź kod PIN urządzenia uwierzytelniającego</string>\n    <string name=\"fido_pin_hint\">Od 4 do 63 znaków</string>\n    <string name=\"fido_pin_ok\">OK</string>\n    <string name=\"fido_pin_cancel\">Anuluj</string>\n    <string name=\"fido_transport_modify\">Zmiana sposobu korzystania z klucza zabezpieczeń</string>\n    <string name=\"fido_sign_in_selection_title\">Wybierz konto</string>\n    <string name=\"fido_sign_in_selection_continue\">aby kontynuować korzystanie z %1$s</string>\n    <string name=\"fido_sign_in_selection_description\">Klucz dostępu</string>\n</resources>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-pt/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"fido_welcome_title\">Use a sua chave de segurança com %1$s</string>\n    <string name=\"fido_welcome_body\">Usar a sua chave de segurança com %1$s ajuda a proteger os seus dados.</string>\n    <string name=\"fido_welcome_button_get_started\">Iniciar</string>\n    <string name=\"fido_welcome_privileged_info\">%1$s age como um navegador confiado para utilizar a sua chave de segurança com %2$s.</string>\n    <string name=\"fido_welcome_privileged_check\">Sim, %1$s é o meu navegador confiado e deve ser permitido que use chaves de segurança com sites da web de terceiros.</string>\n    <string name=\"fido_transport_selection_title\">Escolha como usar a sua chave de segurança</string>\n    <string name=\"fido_transport_selection_body\">Chaves de segurança funcionam com Bluetooth, NFC e USB. Escolha como quer usar a sua chave.</string>\n    <string name=\"fido_biometric_prompt_title\">Verifique a sua identidade</string>\n    <string name=\"fido_biometric_prompt_body\">%1$s precisa verificar que é você.</string>\n    <string name=\"fido_usb_title\">Conecte a sua chave de segurança USB</string>\n    <string name=\"fido_usb_prompt_body\">Conecte a sua chave de segurança na porta USB ou com um cabo USB. Se a sua chave tem um botão ou disco de ouro, clique nele agora.</string>\n    <string name=\"fido_nfc_title\">Conecte a sua chave de segurança NFC</string>\n    <string name=\"fido_nfc_prompt_body\">Segure a sua chave de segurança atrás do seu dispositivo até que ele pare de vibrar</string>\n    <string name=\"fido_transport_selection_bluetooth\">Usar chave de segurança com Bluetooth</string>\n    <string name=\"fido_transport_selection_nfc\">Usar chave de segurança com NFC</string>\n    <string name=\"fido_transport_selection_usb\">Usar chave de segurança com USB</string>\n    <string name=\"fido_transport_selection_biometric\">Usar este dispositivo com o bloqueio de ecrã</string>\n    <string name=\"fido_transport_usb_wait_connect_body\">Por favor, conecte a sua chave de segurança USB.</string>\n    <string name=\"fido_transport_usb_wait_confirm_body\">Por favor, clique no disco ou anel de ouro em %1$s.</string>\n    <string name=\"fido_pin_title\">Por favor, digite o PIN do seu autenticador</string>\n    <string name=\"fido_pin_hint\">de 4 à 63 caracteres</string>\n    <string name=\"fido_pin_ok\">OK</string>\n    <string name=\"fido_pin_cancel\">Cancelar</string>\n    <string name=\"fido_wrong_pin\">O PIN digitado está incorreto!</string>\n    <string name=\"fido_transport_modify\">Mudar o modo de uso da chave de segurança</string>\n</resources>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-pt-rBR/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"fido_welcome_body\">Usar sua chave de segurança com %1$s ajuda a proteger seus dados.</string>\n    <string name=\"fido_welcome_button_get_started\">Iniciar</string>\n    <string name=\"fido_welcome_privileged_info\">%1$s age como um navegador confiado para utilizar sua chave de segurança com %2$s.</string>\n    <string name=\"fido_transport_selection_title\">Escolha como usar sua chave de segurança</string>\n    <string name=\"fido_transport_selection_bluetooth\">Usar chave de segurança com Bluetooth</string>\n    <string name=\"fido_welcome_privileged_check\">Sim, %1$s é meu navegador confiado e deve ser permitido que use chaves de segurança com sites da web de terceiros.</string>\n    <string name=\"fido_usb_title\">Conecte sua chave de segurança USB</string>\n    <string name=\"fido_transport_selection_body\">Chaves de segurança funcionam com Bluetooth, NFC e USB. Escolha como quer usar sua chave.</string>\n    <string name=\"fido_nfc_prompt_body\">Segure sua chave de segurança atrás do seu dispositivo até que ele pare de vibrar</string>\n    <string name=\"fido_biometric_prompt_title\">Verifique sua identidade</string>\n    <string name=\"fido_biometric_prompt_body\">%1$s precisa verificar que é você.</string>\n    <string name=\"fido_usb_prompt_body\">Conecte sua chave de segurança na porta USB ou com um cabo USB. Se sua chave tem um botão ou disco de ouro, clique nele agora.</string>\n    <string name=\"fido_nfc_title\">Conecte sua chave de segurança NFC</string>\n    <string name=\"fido_welcome_title\">Use sua chave de segurança com %1$s</string>\n    <string name=\"fido_transport_selection_nfc\">Usar chave de segurança com NFC</string>\n    <string name=\"fido_transport_selection_usb\">Usar chave de segurança com USB</string>\n    <string name=\"fido_transport_selection_biometric\">Usar este dispositivo com o bloqueio de tela</string>\n    <string name=\"fido_transport_usb_wait_connect_body\">Por favor, conecte sua chave de segurança USB.</string>\n    <string name=\"fido_transport_usb_wait_confirm_body\">Por favor, clique no disco ou anel de ouro em %1$s.</string>\n    <string name=\"fido_pin_title\">Por favor, digite o PIN do seu autenticador</string>\n    <string name=\"fido_pin_hint\">de 4 à 63 caracteres</string>\n    <string name=\"fido_pin_ok\">OK</string>\n    <string name=\"fido_pin_cancel\">Cancelar</string>\n    <string name=\"fido_wrong_pin\">O PIN digitado está incorreto!</string>\n    <string name=\"fido_transport_modify\">Mudar o modo de uso da chave de segurança</string>\n    <string name=\"fido_sign_in_selection_title\">Selecione uma conta</string>\n    <string name=\"fido_sign_in_selection_continue\">para continuar usando %1$s</string>\n    <string name=\"fido_sign_in_selection_description\">Chave de acesso</string>\n</resources>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-ro/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"fido_welcome_button_get_started\">Să începem</string>\n    <string name=\"fido_usb_prompt_body\">Conectează cheia de securitate la portul USB sau printr-un cablu USB. Dacă cheia are un buton sau un disc auriu, atinge-l acum.</string>\n    <string name=\"fido_transport_usb_wait_connect_body\">Conectează cheia de securitate USB.</string>\n    <string name=\"fido_nfc_prompt_body\">Ține cheia pe partea din spate a dispozitivului până când nu mai vibrează</string>\n    <string name=\"fido_welcome_body\">Folosirea cheii de securitate cu %1$s te ajută să protejezi datele private.</string>\n    <string name=\"fido_welcome_title\">Utilizează cheia de securitate pentru %1$s</string>\n    <string name=\"fido_transport_selection_biometric\">Utilizează acest dispozitiv cu blocarea ecranului</string>\n    <string name=\"fido_welcome_privileged_check\">Da, %1$s este browser-ul meu de încredere și ar trebui să aibă permisiunea de a utiliza chei de securitate cu site-uri web terțe.</string>\n    <string name=\"fido_biometric_prompt_body\">%1$s trebuie să verifice dacă ești tu.</string>\n    <string name=\"fido_transport_selection_usb\">Utilizează cheia de securitate cu USB</string>\n    <string name=\"fido_transport_selection_title\">Alege cum să utilizezi cheia de securitate</string>\n    <string name=\"fido_biometric_prompt_title\">Verifică-ți identitatea</string>\n    <string name=\"fido_usb_title\">Conectează cheia de securitate USB</string>\n    <string name=\"fido_transport_usb_wait_confirm_body\">Atinge inelul sau discul de aur de pe %1$s.</string>\n    <string name=\"fido_welcome_privileged_info\">%1$s acționează ca un browser de încredere pentru a-ți folosi cheia de securitate %2$s.</string>\n    <string name=\"fido_nfc_title\">Conectează cheia de securitate NFC</string>\n    <string name=\"fido_transport_selection_bluetooth\">Utilizează cheia de securitate cu Bluetooth</string>\n    <string name=\"fido_transport_selection_body\">Cheile de securitate funcționează cu Bluetooth, NFC și USB. Alege cum dorești să utilizezi cheia.</string>\n    <string name=\"fido_transport_selection_nfc\">Utilizează cheia de securitate cu NFC</string>\n    <string name=\"fido_pin_title\">Introdu codul PIN pentru autentificatorul tău</string>\n    <string name=\"fido_pin_hint\">De la 4 la 63 de caractere</string>\n    <string name=\"fido_pin_cancel\">Anulează</string>\n    <string name=\"fido_pin_ok\">OK</string>\n    <string name=\"fido_wrong_pin\">PIN greșit!</string>\n    <string name=\"fido_transport_modify\">Schimbă cum să utilizezi cheia de securitate</string>\n    <string name=\"fido_sign_in_selection_title\">Selectează un cont</string>\n    <string name=\"fido_sign_in_selection_continue\">pentru a continua să utilizezi %1$s</string>\n    <string name=\"fido_sign_in_selection_description\">Cheie de acces</string>\n</resources>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-ru/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  --><resources>\n    <string name=\"fido_welcome_title\">Используйте ваш ключ безопасности для %1$s</string>\n    <string name=\"fido_welcome_body\">Использование ключа безопасности для %1$s помогает защитить ваши личные данные.</string>\n    <string name=\"fido_welcome_button_get_started\">Приступаем к работе</string>\n    <string name=\"fido_welcome_privileged_info\">%1$s выступает в качестве доверенного браузера для использования вашего ключа безопасности с %2$s.</string>\n    <string name=\"fido_welcome_privileged_check\">Да, %1$s мой доверенный браузер, и ему должно быть разрешено использовать ключи безопасности на сторонних веб-сайтах.</string>\n    <string name=\"fido_transport_selection_title\">Выберите, как использовать ключ безопасности</string>\n    <string name=\"fido_transport_selection_body\">Ключи безопасности работают с Bluetooth, NFC и USB. Выберите, как вы хотите использовать свой ключ.</string>\n    <string name=\"fido_biometric_prompt_title\">Подтвердите свою личность</string>\n    <string name=\"fido_biometric_prompt_body\">\"%1$s должен подтвердить, что это вы.\"</string>\n    <string name=\"fido_usb_title\">Подключите USB-ключ безопасности</string>\n    <string name=\"fido_usb_prompt_body\">Подключите ключ безопасности к USB-порту или с помощью USB-кабеля. Если на вашем ключе есть кнопка, коснитесь её.</string>\n    <string name=\"fido_nfc_title\">Подключите свой NFC ключ безопасности</string>\n    <string name=\"fido_nfc_prompt_body\">Прижмите ключ к задней панели устройства, пока оно не перестанет вибрировать</string>\n    <string name=\"fido_transport_selection_bluetooth\">Использовать ключ безопасности с Bluetooth</string>\n    <string name=\"fido_transport_selection_nfc\">Использовать ключ безопасности с NFC</string>\n    <string name=\"fido_transport_selection_usb\">Использовать ключ безопасности с USB</string>\n    <string name=\"fido_transport_selection_biometric\">Использовать это устройство с заблокированным экраном</string>\n    <string name=\"fido_transport_usb_wait_connect_body\">Пожалуйста, подключите ваш USB-ключ безопасности.</string>\n    <string name=\"fido_transport_usb_wait_confirm_body\">Пожалуйста, коснитесь золотого кольца или диска на %1$s.</string>\n    <string name=\"fido_pin_title\">Введите PIN-код вашего аутентификатора</string>\n    <string name=\"fido_pin_ok\">OK</string>\n    <string name=\"fido_pin_cancel\">Отмена</string>\n    <string name=\"fido_pin_hint\">От 4 до 63 символов</string>\n    <string name=\"fido_wrong_pin\">Неверный PIN-код!</string>\n    <string name=\"fido_transport_modify\">Изменить способ использования ключа безопасности</string>\n    <string name=\"fido_sign_in_selection_title\">Выберите учётку</string>\n    <string name=\"fido_sign_in_selection_continue\">продолжить используя %1$s</string>\n    <string name=\"fido_sign_in_selection_description\">Код доступа</string>\n</resources>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-sl/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n</resources>"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-sr/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"fido_welcome_button_get_started\">Започни</string>\n    <string name=\"fido_usb_prompt_body\">Повежите свој безбедносни кључ са USB портом или га повежите помоћу USB кабла. Ако ваш кључ има дугме или златни диск, додирните га сада.</string>\n    <string name=\"fido_transport_usb_wait_connect_body\">Повежите свој USB безбедносни кључ.</string>\n    <string name=\"fido_nfc_prompt_body\">Држите кључ равно уз полеђину уређаја док не престане да вибрира</string>\n    <string name=\"fido_welcome_body\">Коришћење безбедносног кључа са %1$s помаже у заштити ваших приватних података.</string>\n    <string name=\"fido_welcome_title\">Користите свој безбедносни кључ са %1$s</string>\n    <string name=\"fido_transport_selection_biometric\">Користите овај уређај са закључавањем екрана</string>\n    <string name=\"fido_welcome_privileged_check\">Да, %1$s је мој поуздани прегледач и требало би да ми буде дозвољено да користим безбедносне кључеве са веб-сајтовима трећих страна.</string>\n    <string name=\"fido_biometric_prompt_body\">%1$s треба да потврди да сте то ви.</string>\n    <string name=\"fido_transport_selection_usb\">Користите безбедносни кључ са USB-ом</string>\n    <string name=\"fido_transport_selection_title\">Изаберите како ћете да користите свој безбедносни кључ</string>\n    <string name=\"fido_biometric_prompt_title\">Потврдите свој идентитет</string>\n    <string name=\"fido_usb_title\">Повежите свој USB безбедносни кључ</string>\n    <string name=\"fido_transport_usb_wait_confirm_body\">Додирните златни прстен или диск на %1$s.</string>\n    <string name=\"fido_welcome_privileged_info\">%1$s делује као поуздан прегледач који користи ваш безбедносни кључ са %2$s.</string>\n    <string name=\"fido_nfc_title\">Повежите свој NFC безбедносни кључ</string>\n    <string name=\"fido_transport_selection_bluetooth\">Користите безбедносни кључ са Bluetooth-ом</string>\n    <string name=\"fido_transport_selection_body\">Безбедносни кључеви раде са Bluetooth-ом, NFC-ом и USB-ом. Изаберите како желите да користите свој кључ.</string>\n    <string name=\"fido_transport_selection_nfc\">Користите безбедносни кључ са NFC-ом</string>\n    <string name=\"fido_pin_title\">Унесите PIN за ваш аутентификатор</string>\n    <string name=\"fido_pin_hint\">од 4 до 63 знакова</string>\n    <string name=\"fido_pin_ok\">ОК</string>\n    <string name=\"fido_pin_cancel\">Откажи</string>\n    <string name=\"fido_wrong_pin\">Унет је погрешан PIN!</string>\n    <string name=\"fido_transport_modify\">Промените начин коришћења безбедносног кључа</string>\n</resources>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-sv/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"fido_welcome_button_get_started\">Sätt igång</string>\n    <string name=\"fido_usb_prompt_body\">Anslut din säkerhetsnyckel till USB-porten eller anslut den med en USB-kabel. Om nyckeln har en knapp eller en guldskiva trycker du på den nu.</string>\n    <string name=\"fido_transport_usb_wait_connect_body\">Anslut din USB-säkerhetsnyckel.</string>\n    <string name=\"fido_nfc_prompt_body\">Håll nyckeln platt mot baksidan av enheten tills den slutar vibrera</string>\n    <string name=\"fido_welcome_body\">Genom att använda din säkerhetsnyckel med %1$s kan du skydda dina privata data.</string>\n    <string name=\"fido_welcome_title\">Använd din säkerhetsnyckel med %1$s</string>\n    <string name=\"fido_transport_selection_biometric\">Använd den här enheten med skärmlås</string>\n    <string name=\"fido_welcome_privileged_check\">Ja, %1$s är min betrodda webbläsare och bör tillåtas att använda säkerhetsnycklar med webbplatser från tredje part.</string>\n    <string name=\"fido_biometric_prompt_body\">%1$s behöver verifiera att det är du.</string>\n    <string name=\"fido_transport_selection_usb\">Använd säkerhetsnyckel med USB</string>\n    <string name=\"fido_transport_selection_title\">Välj hur du vill använda din säkerhetsnyckel</string>\n    <string name=\"fido_biometric_prompt_title\">Verifiera din identitet</string>\n    <string name=\"fido_usb_title\">Anslut din USB-säkerhetsnyckel</string>\n    <string name=\"fido_transport_usb_wait_confirm_body\">Tryck på den gyllene ringen eller skivan på %1$s.</string>\n    <string name=\"fido_welcome_privileged_info\">%1$s fungerar som en betrodd webbläsare för att använda din säkerhetsnyckel med %2$s.</string>\n    <string name=\"fido_nfc_title\">Anslut din NFC-säkerhetsnyckel</string>\n    <string name=\"fido_transport_selection_bluetooth\">Använd säkerhetsnyckel med Bluetooth</string>\n    <string name=\"fido_transport_selection_body\">Säkerhetsnycklar fungerar med Bluetooth, NFC och USB. Välj hur du vill använda nyckeln.</string>\n    <string name=\"fido_transport_selection_nfc\">Använd säkerhetsnyckel med NFC</string>\n    <string name=\"fido_pin_hint\">4 till 63 tecken</string>\n    <string name=\"fido_pin_title\">Vänligen ange PIN-kod för din autentisering</string>\n    <string name=\"fido_pin_ok\">OK</string>\n    <string name=\"fido_pin_cancel\">Avbryt</string>\n    <string name=\"fido_wrong_pin\">Fel PIN-kod!</string>\n    <string name=\"fido_transport_modify\">Ändra hur du vill använda din säkerhetsnyckel</string>\n    <string name=\"fido_sign_in_selection_title\">Välj ett konto</string>\n    <string name=\"fido_sign_in_selection_continue\">för att fortsätta använda %1$s</string>\n    <string name=\"fido_sign_in_selection_description\">Passnyckel</string>\n</resources>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-ta/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"fido_welcome_button_get_started\">தொடங்கவும்</string>\n    <string name=\"fido_welcome_privileged_info\">%1$s உங்கள் பாதுகாப்பு விசையை %2$s உடன் பயன்படுத்த நம்பகமான உலாவியாக செயல்படுகின்றன.</string>\n    <string name=\"fido_welcome_privileged_check\">ஆம், %1$s எனது நம்பகமான உலாவி மற்றும் மூன்றாம் தரப்பு வலைத்தளங்களுடன் பாதுகாப்பு விசைகளைப் பயன்படுத்த அனுமதிக்க வேண்டும்.</string>\n    <string name=\"fido_transport_selection_title\">உங்கள் பாதுகாப்பு விசையை எவ்வாறு பயன்படுத்துவது என்பதைத் தேர்வுசெய்க</string>\n    <string name=\"fido_transport_selection_body\">பாதுகாப்பு விசைகள் ஊடலை, என்எப்சி மற்றும் யூ.எச்.பி உடன் வேலை செய்கின்றன. உங்கள் விசையை எவ்வாறு பயன்படுத்த விரும்புகிறீர்கள் என்பதைத் தேர்வுசெய்க.</string>\n    <string name=\"fido_biometric_prompt_title\">உங்கள் அடையாளத்தை சரிபார்க்கவும்</string>\n    <string name=\"fido_biometric_prompt_body\">%1$s இது நீங்கள் என்பதை சரிபார்க்க வேண்டும்.</string>\n    <string name=\"fido_usb_title\">உங்கள் யூ.எச்.பி பாதுகாப்பு விசையை இணைக்கவும்</string>\n    <string name=\"fido_welcome_title\">உங்கள் பாதுகாப்பு விசையை %1$s உடன் பயன்படுத்தவும்</string>\n    <string name=\"fido_welcome_body\">உங்கள் பாதுகாப்பு விசையை %1$s உடன் பயன்படுத்துவது உங்கள் தனிப்பட்ட தரவைப் பாதுகாக்க உதவுகிறது.</string>\n    <string name=\"fido_nfc_prompt_body\">உங்கள் சாதனத்தின் பின்புறத்திற்கு எதிராக உங்கள் விசை பிளாட்டை அதிர்வுறும் வரை வைத்திருங்கள்</string>\n    <string name=\"fido_transport_selection_bluetooth\">ஊடலை மூலம் பாதுகாப்பு விசையைப் பயன்படுத்தவும்</string>\n    <string name=\"fido_transport_selection_nfc\">NFC உடன் பாதுகாப்பு விசையைப் பயன்படுத்தவும்</string>\n    <string name=\"fido_transport_selection_usb\">யூ.எச்.பி உடன் பாதுகாப்பு விசையைப் பயன்படுத்தவும்</string>\n    <string name=\"fido_transport_selection_biometric\">திரை பூட்டுடன் இந்த சாதனத்தைப் பயன்படுத்தவும்</string>\n    <string name=\"fido_transport_usb_wait_connect_body\">உங்கள் யூ.எச்.பி பாதுகாப்பு விசையை இணைக்கவும்.</string>\n    <string name=\"fido_transport_usb_wait_confirm_body\">தயவுசெய்து கோல்டன் ரிங் அல்லது வட்டு %1$s இல் தட்டவும்.</string>\n    <string name=\"fido_pin_title\">உங்கள் அங்கீகாரத்திற்கு முள் உள்ளிடவும்</string>\n    <string name=\"fido_pin_hint\">4 முதல் 63 எழுத்துக்கள்</string>\n    <string name=\"fido_pin_ok\">சரி</string>\n    <string name=\"fido_pin_cancel\">ரத்துசெய்</string>\n    <string name=\"fido_wrong_pin\">தவறான முள் நுழைந்தது!</string>\n    <string name=\"fido_usb_prompt_body\">உங்கள் பாதுகாப்பு விசையை யூ.எச்.பி போர்ட்டுடன் இணைக்கவும் அல்லது யூ.எச்.பி கேபிள் மூலம் இணைக்கவும். உங்கள் விசையில் ஒரு பொத்தான் அல்லது தங்க வட்டு இருந்தால், இப்போது அதைத் தட்டவும்.</string>\n    <string name=\"fido_nfc_title\">உங்கள் NFC பாதுகாப்பு விசையை இணைக்கவும்</string>\n    <string name=\"fido_transport_modify\">உங்கள் பாதுகாப்பு விசையை எவ்வாறு பயன்படுத்துவது என்பதை மாற்று</string>\n</resources>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-th/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"fido_welcome_body\">การใช้คีย์ความปลอดภัยของคุณกับ %1$s จะช่วยปกป้องข้อมูลส่วนตัวของคุณ</string>\n    <string name=\"fido_welcome_button_get_started\">เริ่มต้นใช้งาน</string>\n    <string name=\"fido_transport_selection_title\">เลือกวิธีใช้คีย์ความปลอดภัยของคุณ</string>\n    <string name=\"fido_transport_selection_body\">คีย์ความปลอดภัยทำงานร่วมกับ Bluetooth, NFC และ USB เลือกวิธีที่คุณต้องการใช้คีย์ของคุณ</string>\n    <string name=\"fido_biometric_prompt_title\">ยืนยันตัวตนของคุณ</string>\n    <string name=\"fido_biometric_prompt_body\">%1$s จำเป็นต้องยืนยันว่าเป็นคุณ</string>\n    <string name=\"fido_nfc_title\">เชื่อมต่อคีย์ความปลอดภัย NFC ของคุณ</string>\n    <string name=\"fido_transport_selection_bluetooth\">ใช้คีย์ความปลอดภัยร่วมกับ Bluetooth</string>\n    <string name=\"fido_transport_selection_nfc\">ใช้คีย์ความปลอดภัยกับ NFC</string>\n    <string name=\"fido_transport_selection_usb\">ใช้คีย์ความปลอดภัยกับ USB</string>\n    <string name=\"fido_transport_usb_wait_connect_body\">โปรดเชื่อมต่อคีย์ความปลอดภัย USB ของคุณ</string>\n    <string name=\"fido_transport_usb_wait_confirm_body\">กรุณาแตะที่วงกลมสีทองหรือที่วงกลม %1$s.</string>\n    <string name=\"fido_pin_title\">กรุณากรอกรหัส PIN สำหรับผู้ตรวจสอบสิทธิ์ของคุณ</string>\n    <string name=\"fido_pin_ok\">ตกลง</string>\n    <string name=\"fido_wrong_pin\">ป้อน PIN ผิด!</string>\n    <string name=\"fido_welcome_title\">ใช้คีย์ความปลอดภัยของคุณกับ %1$s</string>\n    <string name=\"fido_welcome_privileged_info\">%1$s ทำหน้าที่เป็นเบราว์เซอร์ที่เชื่อถือได้เพื่อใช้รหัสความปลอดภัยของคุณกับ %2$s</string>\n    <string name=\"fido_welcome_privileged_check\">ใช่ %1$s เป็นเบราว์เซอร์ที่เชื่อถือได้ของฉัน และควรได้รับอนุญาตให้ใช้คีย์ความปลอดภัยกับเว็บไซต์บุคคลที่สาม</string>\n    <string name=\"fido_usb_title\">เชื่อมต่อคีย์ความปลอดภัย USB ของคุณ</string>\n    <string name=\"fido_usb_prompt_body\">เชื่อมต่อกุญแจความปลอดภัยของคุณกับพอร์ต USB หรือเชื่อมต่อด้วยสาย USB หากกุญแจของคุณมีปุ่มหรือวงกลมสีทอง ให้แตะทันที</string>\n    <string name=\"fido_nfc_prompt_body\">ถือกุญแจของคุณให้แนบกับด้านหลังของอุปกรณ์จนกว่าจะหยุดสั่น</string>\n    <string name=\"fido_transport_selection_biometric\">ใช้เครื่องนี้ด้วยการล็อคหน้าจอ</string>\n    <string name=\"fido_pin_hint\">4 ถึง 63 ตัวอักษร</string>\n    <string name=\"fido_pin_cancel\">ยกเลิก</string>\n    <string name=\"fido_transport_modify\">เปลี่ยนวิธีใช้คีย์ความปลอดภัยของคุณ</string>\n    <string name=\"fido_sign_in_selection_title\">เลือกบัญชี</string>\n    <string name=\"fido_sign_in_selection_continue\">เพื่อใช้งาน %1$s ต่อไป</string>\n    <string name=\"fido_sign_in_selection_description\">พาสคีย์</string>\n</resources>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-tr/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"fido_welcome_title\">Güvenlik anahtarınızı %1$s ile kullanın</string>\n    <string name=\"fido_welcome_body\">Güvenlik anahtarınızı %1$s ile kullanmak özel verilerinizin korunmasına yardımcı olur.</string>\n    <string name=\"fido_welcome_button_get_started\">Başlayın</string>\n    <string name=\"fido_welcome_privileged_check\">Evet, %1$s benim güvenilir tarayıcım ve üçüncü taraf web siteleri ile güvenlik anahtarlarını kullanmasına izin verilmelidir.</string>\n    <string name=\"fido_welcome_privileged_info\">%1$s, güvenlik anahtarınızı %2$s ile kullanmak için güvenilir bir tarayıcı olarak hareket eder.</string>\n    <string name=\"fido_transport_selection_title\">Güvenlik anahtarınızı nasıl kullanacağınızı seçin</string>\n    <string name=\"fido_biometric_prompt_title\">Kimliğinizi doğrulayın</string>\n    <string name=\"fido_biometric_prompt_body\">%1$s sizin siz olduğunuzu doğrulamayı gerektiriyor.</string>\n    <string name=\"fido_usb_title\">USB güvenlik anahtarınızı bağlayın</string>\n    <string name=\"fido_usb_prompt_body\">Güvenlik anahtarınızı USB bağlantı noktasına bağlayın veya bir USB kablosu ile bağlayın. Anahtarınızda bir düğme veya altın renkli bir disk varsa, şimdi ona dokunun.</string>\n    <string name=\"fido_nfc_prompt_body\">Anahtarınızı cihazınızın arkasına düz bir şekilde koyun ve titreşimi durana kadar bekleyin</string>\n    <string name=\"fido_transport_selection_nfc\">NFC ile güvenlik anahtarınızı kullanın</string>\n    <string name=\"fido_transport_selection_usb\">USB ile güvenlik anahtarınızı kullanın</string>\n    <string name=\"fido_transport_selection_biometric\">Bu cihazı ekran kilidi ile kullanın</string>\n    <string name=\"fido_transport_usb_wait_confirm_body\">Lütfen %1$s üzerindeki altın çember ya da diske dokunun.</string>\n    <string name=\"fido_transport_selection_body\">Güvenlik anahtarları Bluetooth, NFC ve USB ile çalışır. Anahtarınızı nasıl kullanmak istediğinizi seçin.</string>\n    <string name=\"fido_nfc_title\">NFC güvenlik anahtarınızı bağlayın</string>\n    <string name=\"fido_transport_selection_bluetooth\">Bluetooth ile güvenlik anahtarınızı kullanın</string>\n    <string name=\"fido_transport_usb_wait_connect_body\">Lütfen USB güvenlik anahtarınızı bağlayın.</string>\n    <string name=\"fido_pin_title\">Lütfen kimlik doğrulayıcınızın PIN kodunu girin</string>\n    <string name=\"fido_pin_hint\">4 ile 63 karakter arasında</string>\n    <string name=\"fido_wrong_pin\">Yanlış PIN girildi!</string>\n    <string name=\"fido_pin_ok\">Tamam</string>\n    <string name=\"fido_pin_cancel\">İptal</string>\n    <string name=\"fido_transport_modify\">Güvenlik anahtarınızı nasıl kullanmak istediğinizi değiştirin</string>\n    <string name=\"fido_sign_in_selection_title\">Hesap seçin</string>\n    <string name=\"fido_sign_in_selection_continue\">%1$s kullanmaya devam etmek için</string>\n    <string name=\"fido_sign_in_selection_description\">Geçiş anahtarı</string>\n</resources>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-ug/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"fido_welcome_title\">%1$s غا بىخەتەرلىك ئاچقۇچى ئىشلىتىدۇ</string>\n    <string name=\"fido_welcome_privileged_check\">ھەئە، مەن %1$s توركۆرگۈگە ئىشىنىمەن، ئۇنىڭ ئۈچىنچى تەرەپ تور بېكەت ئۈچۈن شىفىرلىق ئاچقۇچ ئىشلىتىشىگە يول قويۇلۇشى كېرەك.</string>\n    <string name=\"fido_welcome_body\">شەخسىي سانلىق مەلۇماتلىرىڭىزنى قوغداشقا ياردەملىشىش ئۈچۈن %1$s غا بىخەتەرلىك ئاچقۇچى ئىشلىتىدۇ.</string>\n    <string name=\"fido_welcome_button_get_started\">باشلاش</string>\n    <string name=\"fido_welcome_privileged_info\">%2$s غا بىخەتەرلىك ئاچقۇچىڭىزنى ئىشلىتىشتە %1$s نىڭ ئىشەنچلىك توركۆرگۈ ئىكەنلىكىگە كاپالەتلىك قىلىدۇ.</string>\n    <string name=\"fido_transport_selection_title\">شىفىرلىق ئاچقۇچىڭىزنى قانداق ئىشلىتىشنى تاللاڭ</string>\n    <string name=\"fido_biometric_prompt_title\">كىملىكىڭىزنى دەلىللەيدۇ</string>\n    <string name=\"fido_transport_selection_body\">شىفىرلىق ئاچقۇچ كۆكچىش، NFC ۋە USB بىلەن ئىشلەيدۇ. شىفىرلىق ئاچقۇچىڭىزنى ئىشلىتىش ئۇسۇلىنى تاللاڭ.</string>\n    <string name=\"fido_biometric_prompt_body\">%1$s سىز ئىكەنلىكىڭىزنى دەلىللىشى كېرەك.</string>\n    <string name=\"fido_usb_title\">USB بىخەتەرلىك ئاچقۇچىنى ئۇلاڭ</string>\n    <string name=\"fido_usb_prompt_body\">بىخەتەرلىك ئاچقۇچىڭىزنى USB ئېغىزىغا چېتىڭ ياكى USB سىمى بىلەن باغلاڭ. ئەگەر ئاچقۇچتا توپچە ياكى ئالتۇن رەڭلىك دىسكا بولسا ئۇنى چېكىڭ.</string>\n    <string name=\"fido_nfc_title\">NFC بىخەتەرلىك ئاچقۇچىنى ئۇلاڭ</string>\n    <string name=\"fido_nfc_prompt_body\">ئاچقۇچنى ئۈسكۈنىڭىزنىڭ ئارقىسىغا چاپلاپ ئۈسكۈنىڭىز تىترەشتىن توختىغۇچە تۇتۇپ تۇرۇڭ</string>\n    <string name=\"fido_transport_selection_bluetooth\">كۆكچىش ئارقىلىق بىخەتەرلىك ئاچقۇچى ئىشلىتىدۇ</string>\n    <string name=\"fido_transport_selection_nfc\">NFC ئارقىلىق بىخەتەرلىك ئاچقۇچى ئىشلىتىدۇ</string>\n    <string name=\"fido_pin_title\">دەلىللەش ئۈچۈن PIN نى كىرگۈزۈڭ</string>\n    <string name=\"fido_transport_selection_usb\">USB ئارقىلىق بىخەتەرلىك ئاچقۇچى ئىشلىتىدۇ</string>\n    <string name=\"fido_transport_selection_biometric\">نۆۋەتتىكى ئۈسكۈنىنىڭ ئېكران قۇلۇپىنى ئىشلىتىدۇ</string>\n    <string name=\"fido_transport_usb_wait_connect_body\">USB بىخەتەرلىك ئاچقۇچىنى ئۇلاڭ.</string>\n    <string name=\"fido_transport_usb_wait_confirm_body\">%1$s دىكى ئالتۇن رەڭلىك ھالقا ياكى دىسكىنى چېكىڭ.</string>\n    <string name=\"fido_pin_hint\">4 تىن 63 كىچە ھەرپ</string>\n    <string name=\"fido_pin_ok\">جەزملە</string>\n    <string name=\"fido_pin_cancel\">ۋاز كەچ</string>\n    <string name=\"fido_wrong_pin\">PIN خاتا كىرگۈزۈلدى!</string>\n    <string name=\"fido_transport_modify\">بىخەتەرلىك ئاچقۇچىنى قانداق ئىشلىتىشنى ئۆزگەرتىدۇ</string>\n    <string name=\"fido_sign_in_selection_title\">بىر ھېسابات تاللىنىدۇ</string>\n    <string name=\"fido_sign_in_selection_continue\">%1$s ئىشلىتىشنى داۋاملاشتۇرىدۇ</string>\n    <string name=\"fido_sign_in_selection_description\">ئىم ئىبارە</string>\n</resources>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-uk/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"fido_welcome_button_get_started\">Почнімо</string>\n    <string name=\"fido_usb_prompt_body\">Під\\'єднайте ключ безпеки до USB-порту або за допомогою USB-кабелю. Якщо на вашому ключі є кнопка, торкніться його.</string>\n    <string name=\"fido_transport_usb_wait_connect_body\">Будь ласка, під\\'єднайте свій USB-ключ безпеки.</string>\n    <string name=\"fido_nfc_prompt_body\">Притисніть ключ до задньої панелі пристрою, доки він не перестане вібрувати</string>\n    <string name=\"fido_welcome_body\">Використання ключа безпеки для %1$s допомагає захистити ваші приватні дані.</string>\n    <string name=\"fido_welcome_title\">Використати ключ безпеки для %1$s</string>\n    <string name=\"fido_transport_selection_biometric\">Використовувати цей пристрій з заблокованим екраном</string>\n    <string name=\"fido_welcome_privileged_check\">Так, %1$s – мій довірений браузер, і надати йому дозвіл використовувати ключі безпеки на сторонніх вебсайтах.</string>\n    <string name=\"fido_biometric_prompt_body\">%1$s потрібно підтвердити, що це ви.</string>\n    <string name=\"fido_transport_selection_usb\">Використовувати ключ безпеки з USB</string>\n    <string name=\"fido_transport_selection_title\">Оберіть як використовувати ключ безпеки</string>\n    <string name=\"fido_biometric_prompt_title\">Підтвердьте свою особу</string>\n    <string name=\"fido_usb_title\">Під\\'єднайте USB-ключ безпеки</string>\n    <string name=\"fido_transport_usb_wait_confirm_body\">Торкніться золотого кільця або диска на %1$s.</string>\n    <string name=\"fido_welcome_privileged_info\">%1$s діє як довірений браузер для використання вашого ключа безпеки з %2$s.</string>\n    <string name=\"fido_nfc_title\">Під\\'єднайте NFC-ключ безпеки</string>\n    <string name=\"fido_transport_selection_bluetooth\">Використовувати ключ безпеки з Bluetooth</string>\n    <string name=\"fido_transport_selection_body\">Ключі безпеки працюють із Bluetooth, NFC і USB. Виберіть, як ви хочете використовувати свій ключ.</string>\n    <string name=\"fido_transport_selection_nfc\">Використовувати ключ безпеки з NFC</string>\n    <string name=\"fido_pin_title\">Введіть PIN-код для вашого автентифікатора</string>\n    <string name=\"fido_pin_hint\">Від 4 до 63 символів</string>\n    <string name=\"fido_pin_cancel\">Скасувати</string>\n    <string name=\"fido_pin_ok\">ГАРАЗД</string>\n    <string name=\"fido_wrong_pin\">Введено невірний PIN-код!</string>\n    <string name=\"fido_transport_modify\">Змінити спосіб використання ключа безпеки</string>\n    <string name=\"fido_sign_in_selection_title\">Виберіть обліковий запис</string>\n    <string name=\"fido_sign_in_selection_continue\">аби продовжити використання %1$s</string>\n    <string name=\"fido_sign_in_selection_description\">Ключ доступу</string>\n</resources>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-vi/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"fido_welcome_title\">Sử dụng khóa bảo mật của bạn với %1$s</string>\n    <string name=\"fido_welcome_body\">Sử dụng khóa bảo mật với %1$s giúp bảo vệ dữ liệu riêng tư của bạn.</string>\n    <string name=\"fido_welcome_button_get_started\">Bắt đầu</string>\n    <string name=\"fido_welcome_privileged_info\">%1$s hoạt động như một trình duyệt đáng tin cậy để sử dụng khóa bảo mật của bạn với %2$s.</string>\n    <string name=\"fido_welcome_privileged_check\">Vâng, %1$s là trình duyệt đáng tin cậy của tôi và được phép sử dụng khóa bảo mật với các trang web của bên thứ ba.</string>\n    <string name=\"fido_transport_selection_title\">Chọn cách sử dụng khóa bảo mật của bạn</string>\n    <string name=\"fido_transport_selection_body\">Khóa bảo mật hoạt động với Bluetooth, NFC và USB. Chọn cách bạn muốn sử dụng khóa của mình.</string>\n    <string name=\"fido_biometric_prompt_title\">Xác minh danh tính của bạn</string>\n    <string name=\"fido_biometric_prompt_body\">%1$s cần xác minh đó là bạn.</string>\n    <string name=\"fido_usb_title\">Kết nối khóa bảo mật USB của bạn</string>\n    <string name=\"fido_nfc_title\">Kết nối khóa bảo mật NFC của bạn</string>\n    <string name=\"fido_nfc_prompt_body\">Giữ khóa của bạn nằm phẳng trên mặt sau của thiết bị cho đến khi nó ngừng rung</string>\n    <string name=\"fido_transport_selection_bluetooth\">Sử dụng khóa bảo mật với Bluetooth</string>\n    <string name=\"fido_transport_selection_nfc\">Sử dụng khóa bảo mật với NFC</string>\n    <string name=\"fido_transport_selection_usb\">Sử dụng khóa bảo mật với USB</string>\n    <string name=\"fido_transport_selection_biometric\">Sử dụng thiết bị này với khóa màn hình</string>\n    <string name=\"fido_transport_usb_wait_connect_body\">Vui lòng kết nối khóa bảo mật USB của bạn.</string>\n    <string name=\"fido_transport_usb_wait_confirm_body\">Vui lòng nhấn vào vòng tròn hoặc đĩa vàng trên %1$s.</string>\n    <string name=\"fido_pin_title\">Vui lòng nhập mã PIN cho thiết bị xác thực của bạn</string>\n    <string name=\"fido_pin_hint\">4 đến 63 ký tự</string>\n    <string name=\"fido_pin_ok\">ĐƯỢC RỒI</string>\n    <string name=\"fido_wrong_pin\">Nhập sai mã PIN!</string>\n    <string name=\"fido_pin_cancel\">Huỷ</string>\n    <string name=\"fido_usb_prompt_body\">Kết nối khóa bảo mật của bạn với cổng USB hoặc kết nối bằng cáp USB. Nếu khóa của bạn có nút hoặc đĩa vàng, hãy nhấn vào đó ngay.</string>\n    <string name=\"fido_transport_modify\">Thay đổi cách sử dụng khóa bảo mật của bạn</string>\n</resources>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-zh-rCN/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  --><resources>\n    <string name=\"fido_welcome_title\">为 %1$s 启用安全密钥</string>\n    <string name=\"fido_welcome_body\">为 %1$s 启用安全密钥有助于保护您的个人数据。</string>\n    <string name=\"fido_welcome_button_get_started\">开始</string>\n    <string name=\"fido_welcome_privileged_info\">确保 %1$s 是您信任的浏览器，以便为 %2$s 启用安全密钥。</string>\n    <string name=\"fido_welcome_privileged_check\">是的，我信任 %1$s，请允许它为第三方网站使用安全密钥。</string>\n    <string name=\"fido_transport_selection_title\">选择您使用安全密钥的方式</string>\n    <string name=\"fido_transport_selection_body\">安全密钥可通过蓝牙、NFC 或 USB 方式使用。请选择您的使用方式。</string>\n    <string name=\"fido_biometric_prompt_title\">验证您的身份</string>\n    <string name=\"fido_biometric_prompt_body\">%1$s 需要确认是您本人在操作。</string>\n    <string name=\"fido_usb_title\">连接您的 USB 安全密钥</string>\n    <string name=\"fido_usb_prompt_body\">请将安全密钥插入到 USB 端口，或通过 USB 线缆连接。若密钥上有按钮或金色圆片，请点按它。</string>\n    <string name=\"fido_transport_selection_bluetooth\">通过蓝牙使用安全密钥</string>\n    <string name=\"fido_transport_selection_nfc\">通过 NFC 使用安全密钥</string>\n    <string name=\"fido_transport_selection_usb\">通过 USB 使用安全密钥</string>\n    <string name=\"fido_transport_selection_biometric\">使用当前设备的屏幕锁定选项</string>\n    <string name=\"fido_transport_usb_wait_connect_body\">请连接您的 USB 安全密钥。</string>\n    <string name=\"fido_transport_usb_wait_confirm_body\">请点按 %1$s 上的金色圆环或圆片。</string>\n    <string name=\"fido_nfc_title\">连接您的 NFC 安全密钥</string>\n    <string name=\"fido_nfc_prompt_body\">请将安全密钥平贴在设备背部，直到振动停止</string>\n    <string name=\"fido_pin_ok\">好</string>\n    <string name=\"fido_wrong_pin\">输入了错误的 PIN 码！</string>\n    <string name=\"fido_pin_title\">请输入 PIN 码以验证</string>\n    <string name=\"fido_pin_cancel\">取消</string>\n    <string name=\"fido_pin_hint\">4 到 63 个字符</string>\n    <string name=\"fido_transport_modify\">更改如何使用你的安全密钥</string>\n    <string name=\"fido_sign_in_selection_title\">选择账号</string>\n    <string name=\"fido_sign_in_selection_continue\">以继续使用 %1$s </string>\n    <string name=\"fido_sign_in_selection_description\">通行密钥</string>\n</resources>\n"
  },
  {
    "path": "play-services-fido/core/src/main/res/values-zh-rTW/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"fido_pin_title\">請輸入驗證器的 PIN 碼</string>\n    <string name=\"fido_pin_hint\">4 到 63 個字元</string>\n    <string name=\"fido_pin_ok\">確定</string>\n    <string name=\"fido_welcome_body\">為 %1$s 使用安全金鑰有助於保護您的個人資料。</string>\n    <string name=\"fido_wrong_pin\">輸入的 PIN 碼不正確！</string>\n    <string name=\"fido_usb_prompt_body\">請將安全金鑰插入到 USB 埠，或透過 USB 線纜連接。若金鑰上有按鈕或金色觸控點，請點按。</string>\n    <string name=\"fido_transport_usb_wait_connect_body\">請連接您的 USB 安全金鑰。</string>\n    <string name=\"fido_transport_usb_wait_confirm_body\">請點按 %1$s 上的金色圓環或接觸點。</string>\n    <string name=\"fido_pin_cancel\">取消</string>\n    <string name=\"fido_welcome_button_get_started\">開始</string>\n    <string name=\"fido_welcome_title\">為 %1$s 使用安全金鑰</string>\n    <string name=\"fido_welcome_privileged_info\">確保 %1$s 是您信任的瀏覽器，以便為 %2$s 使用安全金鑰。</string>\n    <string name=\"fido_welcome_privileged_check\">是，我信任 %1$s，請允許它為第三方網站使用安全金鑰。</string>\n    <string name=\"fido_transport_selection_title\">選擇您要如何使用安全金鑰</string>\n    <string name=\"fido_transport_selection_body\">安全金鑰可透過藍牙、NFC 或 USB 使用。請選擇您要如何使用它。</string>\n    <string name=\"fido_biometric_prompt_title\">驗證您的身分</string>\n    <string name=\"fido_biometric_prompt_body\">%1$s 需確認這是您。</string>\n    <string name=\"fido_nfc_title\">連接您的 NFC 安全金鑰</string>\n    <string name=\"fido_usb_title\">連接您的 USB 安全金鑰</string>\n    <string name=\"fido_nfc_prompt_body\">請將安全金鑰平貼在裝置背面，直到不再震動</string>\n    <string name=\"fido_transport_selection_bluetooth\">透過藍牙使用安全金鑰</string>\n    <string name=\"fido_transport_selection_nfc\">透過 NFC 使用安全金鑰</string>\n    <string name=\"fido_transport_selection_usb\">透過 USB 使用安全金鑰</string>\n    <string name=\"fido_transport_selection_biometric\">使用此裝置的螢幕鎖定功能</string>\n    <string name=\"fido_transport_modify\">更改使用安全金鑰的方式</string>\n    <string name=\"fido_sign_in_selection_title\">選擇帳號</string>\n    <string name=\"fido_sign_in_selection_continue\">以繼續使用 %1$s </string>\n    <string name=\"fido_sign_in_selection_description\">通行金鑰</string>\n</resources>\n"
  },
  {
    "path": "play-services-fido/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest />\n"
  },
  {
    "path": "play-services-fido/src/main/aidl/com/google/android/gms/fido/fido2/api/IBooleanCallback.aidl",
    "content": "package com.google.android.gms.fido.fido2.api;\n\nimport com.google.android.gms.common.api.Status;\n\ninterface IBooleanCallback {\n    void onBoolean(boolean value) = 0;\n    void onError(in Status status) = 1;\n}\n"
  },
  {
    "path": "play-services-fido/src/main/aidl/com/google/android/gms/fido/fido2/api/ICredentialListCallback.aidl",
    "content": "package com.google.android.gms.fido.fido2.api;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.fido.fido2.api.common.FidoCredentialDetails;\n\ninterface ICredentialListCallback {\n    void onCredentialList(in List<FidoCredentialDetails> value) = 0;\n    void onError(in Status status) = 1;\n}\n"
  },
  {
    "path": "play-services-fido/src/main/aidl/com/google/android/gms/fido/fido2/api/common/BrowserPublicKeyCredentialCreationOptions.aidl",
    "content": "package com.google.android.gms.fido.fido2.api.common;\n\nparcelable BrowserPublicKeyCredentialCreationOptions;\n"
  },
  {
    "path": "play-services-fido/src/main/aidl/com/google/android/gms/fido/fido2/api/common/BrowserPublicKeyCredentialRequestOptions.aidl",
    "content": "package com.google.android.gms.fido.fido2.api.common;\n\nparcelable BrowserPublicKeyCredentialRequestOptions;\n"
  },
  {
    "path": "play-services-fido/src/main/aidl/com/google/android/gms/fido/fido2/api/common/FidoCredentialDetails.aidl",
    "content": "package com.google.android.gms.fido.fido2.api.common;\n\nparcelable FidoCredentialDetails;\n"
  },
  {
    "path": "play-services-fido/src/main/aidl/com/google/android/gms/fido/fido2/api/common/PublicKeyCredentialCreationOptions.aidl",
    "content": "package com.google.android.gms.fido.fido2.api.common;\n\nparcelable PublicKeyCredentialCreationOptions;\n"
  },
  {
    "path": "play-services-fido/src/main/aidl/com/google/android/gms/fido/fido2/api/common/PublicKeyCredentialRequestOptions.aidl",
    "content": "package com.google.android.gms.fido.fido2.api.common;\n\nparcelable PublicKeyCredentialRequestOptions;\n"
  },
  {
    "path": "play-services-fido/src/main/aidl/com/google/android/gms/fido/fido2/internal/privileged/IFido2PrivilegedCallbacks.aidl",
    "content": "package com.google.android.gms.fido.fido2.internal.privileged;\n\nimport android.app.PendingIntent;\nimport com.google.android.gms.common.api.Status;\n\ninterface IFido2PrivilegedCallbacks {\n    void onPendingIntent(in Status status, in PendingIntent pendingIntent);\n}\n"
  },
  {
    "path": "play-services-fido/src/main/aidl/com/google/android/gms/fido/fido2/internal/privileged/IFido2PrivilegedService.aidl",
    "content": "package com.google.android.gms.fido.fido2.internal.privileged;\n\nimport com.google.android.gms.fido.fido2.internal.privileged.IFido2PrivilegedCallbacks;\nimport com.google.android.gms.fido.fido2.api.IBooleanCallback;\nimport com.google.android.gms.fido.fido2.api.ICredentialListCallback;\nimport com.google.android.gms.fido.fido2.api.common.BrowserPublicKeyCredentialCreationOptions;\nimport com.google.android.gms.fido.fido2.api.common.BrowserPublicKeyCredentialRequestOptions;\n\ninterface IFido2PrivilegedService {\n    void getRegisterPendingIntent(IFido2PrivilegedCallbacks callbacks, in BrowserPublicKeyCredentialCreationOptions options) = 0;\n    void getSignPendingIntent(IFido2PrivilegedCallbacks callbacks, in BrowserPublicKeyCredentialRequestOptions options) = 1;\n    void isUserVerifyingPlatformAuthenticatorAvailable(IBooleanCallback callbacks) = 2;\n    void getCredentialList(ICredentialListCallback callbacks, String rpId) = 3;\n}\n"
  },
  {
    "path": "play-services-fido/src/main/aidl/com/google/android/gms/fido/fido2/internal/regular/IFido2AppCallbacks.aidl",
    "content": "package com.google.android.gms.fido.fido2.internal.regular;\n\nimport android.app.PendingIntent;\nimport com.google.android.gms.common.api.Status;\n\ninterface IFido2AppCallbacks {\n    void onPendingIntent(in Status status, in PendingIntent pendingIntent);\n}\n"
  },
  {
    "path": "play-services-fido/src/main/aidl/com/google/android/gms/fido/fido2/internal/regular/IFido2AppService.aidl",
    "content": "package com.google.android.gms.fido.fido2.internal.regular;\n\nimport com.google.android.gms.fido.fido2.internal.regular.IFido2AppCallbacks;\nimport com.google.android.gms.fido.fido2.api.IBooleanCallback;\nimport com.google.android.gms.fido.fido2.api.ICredentialListCallback;\nimport com.google.android.gms.fido.fido2.api.common.PublicKeyCredentialCreationOptions;\nimport com.google.android.gms.fido.fido2.api.common.PublicKeyCredentialRequestOptions;\n\ninterface IFido2AppService {\n    void getRegisterPendingIntent(IFido2AppCallbacks callbacks, in PublicKeyCredentialCreationOptions options) = 0;\n    void getSignPendingIntent(IFido2AppCallbacks callbacks, in PublicKeyCredentialRequestOptions options) = 1;\n    void isUserVerifyingPlatformAuthenticatorAvailable(IBooleanCallback callbacks) = 2;\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/Fido.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.content.Intent;\n\nimport com.google.android.gms.fido.fido2.api.common.AuthenticatorAssertionResponse;\nimport com.google.android.gms.fido.fido2.api.common.AuthenticatorAttestationResponse;\nimport com.google.android.gms.fido.fido2.api.common.AuthenticatorErrorResponse;\nimport com.google.android.gms.fido.fido2.api.common.PublicKeyCredential;\nimport com.google.android.gms.fido.fido2.Fido2ApiClient;\nimport com.google.android.gms.fido.fido2.Fido2PendingIntent;\nimport com.google.android.gms.fido.fido2.Fido2PrivilegedApiClient;\nimport com.google.android.gms.fido.sourcedevice.SourceDirectTransferClient;\nimport com.google.android.gms.fido.u2f.U2fApiClient;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Entry point for Fido APIs.\n * <p>\n * FIDO (Fast IDentity Online), which is the industry alliance where Security Keys are being standardized.\n */\n@PublicApi\npublic class Fido {\n    /**\n     * The key used by the calling {@link Activity} to retrieve {@link PublicKeyCredential} from the Intent received by\n     * {@link Activity#onActivityResult(int, int, Intent)} after launching {@link Fido2PendingIntent}.\n     */\n    public static final String FIDO2_KEY_CREDENTIAL_EXTRA = \"FIDO2_CREDENTIAL_EXTRA\";\n\n    /**\n     * The key used by the calling {@link Activity} to retrieve {@link AuthenticatorErrorResponse} from the Intent received by\n     * {@link Activity#onActivityResult(int, int, Intent)} after launching {@link Fido2PendingIntent}.\n     *\n     * @deprecated use {@link #FIDO2_KEY_CREDENTIAL_EXTRA} to fetch {@link PublicKeyCredential} instead.\n     * {@link PublicKeyCredential} contains an {@link AuthenticatorErrorResponse}.\n     */\n    @Deprecated\n    public static final String FIDO2_KEY_ERROR_EXTRA = \"FIDO2_ERROR_EXTRA\";\n\n    /**\n     * The key used by the calling {@link Activity} to retrieve {@link AuthenticatorAttestationResponse} or\n     * {@link AuthenticatorAssertionResponse} from the Intent received by\n     * {@link Activity#onActivityResult(int, int, Intent)} after launching {@link Fido2PendingIntent}.\n     *\n     * @deprecated use {@link #FIDO2_KEY_CREDENTIAL_EXTRA} to fetch {@link PublicKeyCredential} instead.\n     * {@link PublicKeyCredential} contains an {@link AuthenticatorAttestationResponse} or an {@link AuthenticatorAssertionResponse}.\n     */\n    @Deprecated\n    public static final String FIDO2_KEY_RESPONSE_EXTRA = \"FIDO2_RESPONSE_EXTRA\";\n\n    /**\n     * The key used by the calling {@link Activity} to retrieve {@link ResponseData} from the Intent received by\n     * {@link Activity#onActivityResult(int, int, Intent)} after launching {@link Fido2PendingIntent}.\n     */\n    public static final String KEY_RESPONSE_EXTRA = \"RESPONSE_EXTRA\";\n\n    /**\n     * Creates a new instance of {@link Fido2ApiClient} for use in a non-activity {@link Context}.\n     */\n    public static Fido2ApiClient getFido2ApiClient(Context context) {\n        return new Fido2ApiClient(context);\n    }\n\n    /**\n     * Creates a new instance of {@link Fido2ApiClient} for use in an {@link Activity}.\n     */\n    public static Fido2ApiClient getFido2ApiClient(Activity activity) {\n        return new Fido2ApiClient(activity);\n    }\n\n    /**\n     * Creates a new instance of {@link Fido2PrivilegedApiClient} for use in a non-activity {@link Context}.\n     */\n    public static Fido2PrivilegedApiClient getFido2PrivilegedApiClient(Context context) {\n        return new Fido2PrivilegedApiClient(context);\n    }\n\n    /**\n     * Creates a new instance of {@link Fido2PrivilegedApiClient} for use in an {@link Activity}.\n     */\n    public static Fido2PrivilegedApiClient getFido2PrivilegedApiClient(Activity activity) {\n        return new Fido2PrivilegedApiClient(activity);\n    }\n\n    /**\n     * Creates a new instance of {@link SourceDirectTransferClient} for use in a non-activity {@link Context}.\n     */\n    public static final SourceDirectTransferClient getSourceDirectTransferClient(Context context) {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Creates a new instance of {@link SourceDirectTransferClient} for use in an {@link Activity}.\n     */\n    public static final SourceDirectTransferClient getSourceDirectTransferClient(Activity activity) {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Creates a new instance of {@link U2fApiClient} for use in a non-activity {@link Context}.\n     */\n    public static U2fApiClient getU2fApiClient(Context context) {\n        return new U2fApiClient(context);\n    }\n\n    /**\n     * Creates a new instance of {@link U2fApiClient} for use in an {@link Activity}.\n     */\n    public static U2fApiClient getU2fApiClient(Activity activity) {\n        return new U2fApiClient(activity);\n    }\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/common/Transport.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.common;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.util.Log;\n\nimport org.json.JSONArray;\nimport org.json.JSONException;\nimport org.microg.gms.common.PublicApi;\n\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * The transport between the authenticator and the client.\n */\n@PublicApi\npublic enum Transport implements Parcelable {\n    BLUETOOTH_CLASSIC(\"bt\"),\n    BLUETOOTH_LOW_ENERGY(\"ble\"),\n    NFC(\"nfc\"),\n    USB(\"usb\"),\n    INTERNAL(\"internal\"),\n    HYBRID(\"cable\");\n\n    private final String value;\n\n    Transport(String value) {\n        this.value = value;\n    }\n\n    @Override\n    public String toString() {\n        return value;\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(toString());\n    }\n\n    @PublicApi(exclude = true)\n    public static Transport fromString(String transport) throws UnsupportedTransportException {\n        for (Transport value : values()) {\n            if (value.value.equals(transport)) return value;\n        }\n        if (transport.equals(\"hybrid\")) {\n            return HYBRID;\n        }\n        throw new UnsupportedTransportException(\"Transport \" + transport + \" not supported\");\n    }\n\n    @PublicApi(exclude = true)\n    public static List<Transport> parseTransports(JSONArray jsonArray) throws JSONException {\n        if (jsonArray == null) return null;\n        Set<Transport> set = new HashSet<>();\n        for (int i = 0; i < jsonArray.length(); i++) {\n            String transport = jsonArray.getString(i);\n            if (transport != null && !transport.isEmpty()) {\n                try {\n                    set.add(fromString(transport));\n                } catch (UnsupportedTransportException e) {\n                    Log.w(\"Transport\", \"Ignoring unrecognized transport \" + transport);\n                }\n            }\n        }\n        return new ArrayList<>(set);\n    }\n\n    public static Creator<Transport> CREATOR = new Creator<Transport>() {\n        @Override\n        public Transport createFromParcel(Parcel source) {\n            try {\n                return Transport.fromString(source.readString());\n            } catch (UnsupportedTransportException e) {\n                throw new RuntimeException(e);\n            }\n        }\n\n        @Override\n        public Transport[] newArray(int size) {\n            return new Transport[size];\n        }\n    };\n\n    /**\n     * Exception thrown when an unsupported or unrecognized transport is encountered.\n     */\n    public static class UnsupportedTransportException extends Exception {\n        public UnsupportedTransportException(String errorMessage) {\n            super(errorMessage);\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/Fido2ApiClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.fido2;\n\nimport android.app.PendingIntent;\nimport android.content.Context;\nimport android.os.RemoteException;\n\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.ApiException;\nimport com.google.android.gms.common.api.GoogleApi;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.fido.fido2.api.IBooleanCallback;\nimport com.google.android.gms.fido.fido2.api.common.PublicKeyCredentialCreationOptions;\nimport com.google.android.gms.fido.fido2.api.common.PublicKeyCredentialRequestOptions;\nimport com.google.android.gms.fido.fido2.internal.regular.IFido2AppCallbacks;\nimport com.google.android.gms.tasks.Task;\nimport com.google.android.gms.tasks.Tasks;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.common.api.PendingGoogleApiCall;\nimport org.microg.gms.fido.fido2.Fido2GmsClient;\nimport org.microg.gms.fido.fido2.Fido2PendingIntentImpl;\n\n/**\n * The entry point for interacting with FIDO2 APIs.\n */\n@PublicApi\npublic class Fido2ApiClient extends GoogleApi<Api.ApiOptions.NoOptions> {\n    private static final Api<Api.ApiOptions.NoOptions> API = new Api<>((options, context, looper, clientSettings, callbacks, connectionFailedListener) -> new Fido2GmsClient(context, callbacks, connectionFailedListener));\n\n    @PublicApi(exclude = true)\n    public Fido2ApiClient(Context context) {\n        super(context, API, Api.ApiOptions.NO_OPTIONS);\n    }\n\n    /**\n     * @deprecated use {@link #getRegisterPendingIntent(PublicKeyCredentialCreationOptions)} instead\n     */\n    @Deprecated\n    public Task<Fido2PendingIntent> getRegisterIntent(PublicKeyCredentialCreationOptions requestOptions) {\n        return getRegisterPendingIntent(requestOptions).onSuccessTask(pendingIntent -> Tasks.forResult(new Fido2PendingIntentImpl(pendingIntent)));\n    }\n\n    /**\n     * Creates a Task with {@link PendingIntent}, when started, will issue a FIDO2 registration request, which is done\n     * once per FIDO2 device per account for associating the new FIDO2 device with that account.\n     *\n     * @param requestOptions for the registration request\n     * @return Task with PendingIntent to launch FIDO2 registration request\n     */\n    public Task<PendingIntent> getRegisterPendingIntent(PublicKeyCredentialCreationOptions requestOptions) {\n        return scheduleTask((PendingGoogleApiCall<PendingIntent, Fido2GmsClient>) (client, completionSource) -> {\n            try {\n                client.getRegisterPendingIntent(new IFido2AppCallbacks.Stub() {\n                    @Override\n                    public void onPendingIntent(Status status, PendingIntent pendingIntent) throws RemoteException {\n                        if (status.isSuccess()) {\n                            completionSource.setResult(pendingIntent);\n                        } else {\n                            completionSource.setException(new ApiException(status));\n                        }\n                    }\n                }, requestOptions);\n            } catch (Exception e) {\n                completionSource.setException(e);\n            }\n        });\n    }\n\n    /**\n     * @deprecated use {@link #getSignPendingIntent(PublicKeyCredentialRequestOptions)} instead\n     */\n    @Deprecated\n    public Task<Fido2PendingIntent> getSignIntent(PublicKeyCredentialRequestOptions requestOptions) {\n        return getSignPendingIntent(requestOptions).onSuccessTask(pendingIntent -> Tasks.forResult(new Fido2PendingIntentImpl(pendingIntent)));\n    }\n\n    /**\n     * Creates a Task with {@link PendingIntent}, when started, will issue a FIDO2 signature request for a relying\n     * party to authenticate a user.\n     *\n     * @param requestOptions for the sign request\n     * @return Task with PendingIntent to launch FIDO2 signature request\n     */\n    public Task<PendingIntent> getSignPendingIntent(PublicKeyCredentialRequestOptions requestOptions) {\n        return scheduleTask((PendingGoogleApiCall<PendingIntent, Fido2GmsClient>) (client, completionSource) -> {\n            try {\n                client.getSignPendingIntent(new IFido2AppCallbacks.Stub() {\n                    @Override\n                    public void onPendingIntent(Status status, PendingIntent pendingIntent) throws RemoteException {\n                        if (status.isSuccess()) {\n                            completionSource.setResult(pendingIntent);\n                        } else {\n                            completionSource.setException(new ApiException(status));\n                        }\n                    }\n                }, requestOptions);\n            } catch (Exception e) {\n                completionSource.setException(e);\n            }\n        });\n    }\n\n    /**\n     * Creates a Task with {@link Boolean}, which check if a user verifying platform authenticator is available on the\n     * device.\n     */\n    public Task<Boolean> isUserVerifyingPlatformAuthenticatorAvailable() {\n        return scheduleTask((PendingGoogleApiCall<Boolean, Fido2GmsClient>) (client, completionSource) -> {\n            try {\n                client.isUserVerifyingPlatformAuthenticatorAvailable(new IBooleanCallback.Stub() {\n                    @Override\n                    public void onBoolean(boolean value) throws RemoteException {\n                        completionSource.setResult(value);\n                    }\n\n                    @Override\n                    public void onError(Status status) throws RemoteException {\n                        completionSource.setException(new ApiException(status));\n                    }\n                });\n            } catch (Exception e) {\n                completionSource.setException(e);\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/Fido2PendingIntent.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.fido2;\n\nimport android.app.Activity;\nimport android.app.PendingIntent;\nimport android.content.IntentSender;\n\n/**\n * Use {@link Fido2ApiClient#getRegisterPendingIntent(PublicKeyCredentialCreationOptions)} or\n * {@link Fido2ApiClient#getSignPendingIntent(PublicKeyCredentialRequestOptions)} to avoid a dependence on this.\n */\n@Deprecated\npublic interface Fido2PendingIntent {\n    /**\n     * Returns true if an {@link Activity} has a {@link PendingIntent}.\n     */\n    boolean hasPendingIntent();\n\n    /**\n     * Launches the PendingIntent.\n     *\n     * @param activity    An Activity context to use to launch the intent. The activity's onActivityResult method will\n     *                    be invoked after the user is done.\n     * @param requestCode The request code to pass to onActivityResult.\n     * @throws IllegalStateException            if hasPendingIntent is false\n     * @throws IntentSender.SendIntentException If the resolution intent has been canceled or is no longer able to\n     *                                          execute the request.\n     */\n    void launchPendingIntent(Activity activity, int requestCode) throws IntentSender.SendIntentException;\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/Fido2PrivilegedApiClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.fido2;\n\nimport android.app.PendingIntent;\nimport android.content.Context;\nimport android.os.RemoteException;\n\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.ApiException;\nimport com.google.android.gms.common.api.GoogleApi;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.fido.fido2.api.IBooleanCallback;\nimport com.google.android.gms.fido.fido2.api.ICredentialListCallback;\nimport com.google.android.gms.fido.fido2.api.common.BrowserPublicKeyCredentialCreationOptions;\nimport com.google.android.gms.fido.fido2.api.common.BrowserPublicKeyCredentialRequestOptions;\nimport com.google.android.gms.fido.fido2.api.common.FidoCredentialDetails;\nimport com.google.android.gms.fido.fido2.internal.privileged.IFido2PrivilegedCallbacks;\nimport com.google.android.gms.tasks.Task;\nimport com.google.android.gms.tasks.Tasks;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.common.api.PendingGoogleApiCall;\nimport org.microg.gms.fido.fido2.Fido2PendingIntentImpl;\nimport org.microg.gms.fido.fido2.Fido2PrivilegedGmsClient;\n\nimport java.util.List;\n\n/**\n * The entry point for interacting with the privileged FIDO2 APIs.\n */\n@PublicApi\npublic class Fido2PrivilegedApiClient extends GoogleApi<Api.ApiOptions.NoOptions> {\n    private static final Api<Api.ApiOptions.NoOptions> API = new Api<>((options, context, looper, clientSettings, callbacks, connectionFailedListener) -> new Fido2PrivilegedGmsClient(context, callbacks, connectionFailedListener));\n\n    @PublicApi(exclude = true)\n    public Fido2PrivilegedApiClient(Context context) {\n        super(context, API, Api.ApiOptions.NO_OPTIONS);\n    }\n\n    /**\n     * Creates a Task with a list of {@link FidoCredentialDetails} which, when started, will retrieve a list of credentials associated\n     * with the given relying party ID.\n     *\n     * @param rpId indicating the relying party for which we want to list credentials\n     * @return PendingResult with PendingIntent to retrieve the credential list\n     */\n    public Task<List<FidoCredentialDetails>> getCredentialList(String rpId) {\n        return scheduleTask((PendingGoogleApiCall<List<FidoCredentialDetails>, Fido2PrivilegedGmsClient>) (client, completionSource) -> {\n            try {\n                client.getCredentialList(new ICredentialListCallback.Stub() {\n                    @Override\n                    public void onCredentialList(List<FidoCredentialDetails> value) throws RemoteException {\n                        completionSource.setResult(value);\n                    }\n\n                    @Override\n                    public void onError(Status status) throws RemoteException {\n                        completionSource.setException(new ApiException(status));\n                    }\n                }, rpId);\n            } catch (Exception e) {\n                completionSource.setException(e);\n            }\n        });\n    }\n\n    /**\n     * Creates a Task with PendingIntent, when started, will issue a FIDO2 registration request for privileged apps.\n     *\n     * @param requestOptions for the registration request from a Web browser\n     * @return PendingResult with PendingIntent to launch FIDO2 registration request\n     * @deprecated use {@link #getRegisterPendingIntent(BrowserPublicKeyCredentialCreationOptions)} instead\n     */\n    @Deprecated\n    public Task<Fido2PendingIntent> getRegisterIntent(BrowserPublicKeyCredentialCreationOptions requestOptions) {\n        return getRegisterPendingIntent(requestOptions).onSuccessTask(pendingIntent -> Tasks.forResult(new Fido2PendingIntentImpl(pendingIntent)));\n    }\n\n    /**\n     * Creates a Task with PendingIntent, when started, will issue a FIDO2 registration request for privileged apps.\n     *\n     * @param requestOptions for the registration request from a Web browser\n     * @return PendingResult with PendingIntent to launch FIDO2 registration request\n     */\n    public Task<PendingIntent> getRegisterPendingIntent(BrowserPublicKeyCredentialCreationOptions requestOptions) {\n        return scheduleTask((PendingGoogleApiCall<PendingIntent, Fido2PrivilegedGmsClient>) (client, completionSource) -> {\n            try {\n                client.getRegisterPendingIntent(new IFido2PrivilegedCallbacks.Stub() {\n                    @Override\n                    public void onPendingIntent(Status status, PendingIntent pendingIntent) throws RemoteException {\n                        if (status.isSuccess()) {\n                            completionSource.setResult(pendingIntent);\n                        } else {\n                            completionSource.setException(new ApiException(status));\n                        }\n                    }\n                }, requestOptions);\n            } catch (Exception e) {\n                completionSource.setException(e);\n            }\n        });\n    }\n\n    /**\n     * Creates a Task with PendingIntent, when started, will issue a FIDO2 signature request for privileged apps.\n     *\n     * @param requestOptions for the sign request from a Web browser\n     * @return PendingResult with PendingIntent to launch FIDO2 signature request\n     * @deprecated use {@link #getSignPendingIntent(BrowserPublicKeyCredentialRequestOptions)} instead\n     */\n    @Deprecated\n    public Task<Fido2PendingIntent> getSignIntent(BrowserPublicKeyCredentialRequestOptions requestOptions) {\n        return getSignPendingIntent(requestOptions).onSuccessTask(pendingIntent -> Tasks.forResult(new Fido2PendingIntentImpl(pendingIntent)));\n    }\n\n    /**\n     * Creates a Task with PendingIntent, when started, will issue a FIDO2 signature request for privileged apps.\n     *\n     * @param requestOptions for the sign request from a Web browser\n     * @return PendingResult with PendingIntent to launch FIDO2 signature request\n     */\n    public Task<PendingIntent> getSignPendingIntent(BrowserPublicKeyCredentialRequestOptions requestOptions) {\n        return scheduleTask((PendingGoogleApiCall<PendingIntent, Fido2PrivilegedGmsClient>) (client, completionSource) -> {\n            try {\n                client.getSignPendingIntent(new IFido2PrivilegedCallbacks.Stub() {\n                    @Override\n                    public void onPendingIntent(Status status, PendingIntent pendingIntent) throws RemoteException {\n                        if (status.isSuccess()) {\n                            completionSource.setResult(pendingIntent);\n                        } else {\n                            completionSource.setException(new ApiException(status));\n                        }\n                    }\n                }, requestOptions);\n            } catch (Exception e) {\n                completionSource.setException(e);\n            }\n        });\n    }\n\n    /**\n     * Creates a Task with {@link Boolean}, which check if a user verifying platform authenticator is available on the\n     * device.\n     */\n    public Task<Boolean> isUserVerifyingPlatformAuthenticatorAvailable() {\n        return scheduleTask((PendingGoogleApiCall<Boolean, Fido2PrivilegedGmsClient>) (client, completionSource) -> {\n            try {\n                client.isUserVerifyingPlatformAuthenticatorAvailable(new IBooleanCallback.Stub() {\n                    @Override\n                    public void onBoolean(boolean value) throws RemoteException {\n                        completionSource.setResult(value);\n                    }\n\n                    @Override\n                    public void onError(Status status) throws RemoteException {\n                        completionSource.setException(new ApiException(status));\n                    }\n                });\n            } catch (Exception e) {\n                completionSource.setException(e);\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/Algorithm.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\n/**\n * An interface for an algorithm used in public key encryption. All implementations must conform to the guidelines\n * regarding algorithm registrations in RFC8152.\n */\npublic interface Algorithm {\n    /**\n     * Gets the COSE value for the algorithm used in the encryption of the credential.\n     */\n    int getAlgoValue();\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/Attachment.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport org.microg.gms.common.Hide;\n\n/**\n * Clients may communicate with authenticators using a variety of mechanisms. We define authenticators that are\n * part of the client's platform as having a platform attachment, and refer to them as platform authenticators.\n * While those that are reachable via cross-platform transport protocols are defined as having cross-platform\n * attachment, and refer to them as roaming authenticators.\n */\npublic enum Attachment implements Parcelable {\n    PLATFORM(\"platform\"),\n    CROSS_PLATFORM(\"cross-platform\");\n\n    private final String value;\n\n    Attachment(String value) {\n        this.value = value;\n    }\n\n    @Override\n    public String toString() {\n        return value;\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(toString());\n    }\n\n    @Hide\n    public static Attachment fromString(String attachment) throws UnsupportedAttachmentException {\n        for (Attachment value : values()) {\n            if (value.value.equals(attachment)) return value;\n        }\n        throw new UnsupportedAttachmentException(\"Attachment \" + attachment + \" not supported\");\n    }\n\n    public static Creator<Attachment> CREATOR = new Creator<Attachment>() {\n        @Override\n        public Attachment createFromParcel(Parcel source) {\n            try {\n                return Attachment.fromString(source.readString());\n            } catch (Attachment.UnsupportedAttachmentException e) {\n                throw new RuntimeException(e);\n            }\n        }\n\n        @Override\n        public Attachment[] newArray(int size) {\n            return new Attachment[size];\n        }\n    };\n\n    /**\n     * Exception thrown when an unsupported or unrecognized attachment is encountered.\n     */\n    public static class UnsupportedAttachmentException extends Exception {\n        public UnsupportedAttachmentException(String message) {\n            super(message);\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/AttestationConveyancePreference.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport androidx.annotation.NonNull;\nimport org.microg.gms.common.Hide;\n\n/**\n * An enum describing the relying party's preference for attestation conveyance.\n */\npublic enum AttestationConveyancePreference implements Parcelable {\n    NONE(\"none\"),\n    INDIRECT(\"indirect\"),\n    DIRECT(\"direct\");\n\n    private final String value;\n\n    AttestationConveyancePreference(String value) {\n        this.value = value;\n    }\n\n    @Override\n    @NonNull\n    public String toString() {\n        return value;\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(toString());\n    }\n\n    @Hide\n    @NonNull\n    public static AttestationConveyancePreference fromString(String attachment) throws UnsupportedAttestationConveyancePreferenceException {\n        for (AttestationConveyancePreference value : values()) {\n            if (value.value.equals(attachment)) return value;\n        }\n        throw new UnsupportedAttestationConveyancePreferenceException(\"Attestation conveyance preference \" + attachment + \" not supported\");\n    }\n\n    public static Creator<AttestationConveyancePreference> CREATOR = new Creator<AttestationConveyancePreference>() {\n        @Override\n        public AttestationConveyancePreference createFromParcel(Parcel source) {\n            try {\n                return AttestationConveyancePreference.fromString(source.readString());\n            } catch (UnsupportedAttestationConveyancePreferenceException e) {\n                throw new RuntimeException(e);\n            }\n        }\n\n        @Override\n        public AttestationConveyancePreference[] newArray(int size) {\n            return new AttestationConveyancePreference[size];\n        }\n    };\n\n    /**\n     * Exception thrown when an unsupported or unrecognized attestation conveyance preference is encountered.\n     */\n    public static class UnsupportedAttestationConveyancePreferenceException extends Exception {\n        public UnsupportedAttestationConveyancePreferenceException(String message) {\n            super(message);\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/AuthenticationExtensions.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.Arrays;\nimport java.util.Objects;\n\n/**\n * Represents extensions that can be passed into FIDO2 APIs. This container class corresponds to the additional\n * parameters requesting additional processing by authenticators.\n * <p>\n * Note that rather than accepting arbitrary objects as specified in WebAuthn, this class requires a structured entry\n * for each supported extension.\n */\n@PublicApi\n@SafeParcelable.Class\npublic class AuthenticationExtensions extends AbstractSafeParcelable {\n    @Field(value = 2, getterName = \"getFidoAppIdExtension\")\n    @Nullable\n    private FidoAppIdExtension fidoAppIdExtension;\n    @Field(value = 3, getterName = \"getCableAuthenticationExtension\")\n    @Nullable\n    private CableAuthenticationExtension cableAuthenticationExtension;\n    @Field(value = 4, getterName = \"getUserVerificationMethodExtension\")\n    @Nullable\n    private UserVerificationMethodExtension userVerificationMethodExtension;\n    @Field(value = 5, getterName = \"getGoogleMultiAssertionExtension\")\n    @Nullable\n    private GoogleMultiAssertionExtension googleMultiAssertionExtension;\n    @Field(value = 6, getterName = \"getGoogleSessionIdExtension\")\n    @Nullable\n    private GoogleSessionIdExtension googleSessionIdExtension;\n    @Field(value = 7, getterName = \"getGoogleSilentVerificationExtension\")\n    @Nullable\n    private GoogleSilentVerificationExtension googleSilentVerificationExtension;\n    @Field(value = 8, getterName = \"getDevicePublicKeyExtension\")\n    @Nullable\n    private DevicePublicKeyExtension devicePublicKeyExtension;\n    @Field(value = 9, getterName = \"getGoogleTunnelServerIdExtension\")\n    @Nullable\n    private GoogleTunnelServerIdExtension googleTunnelServerIdExtension;\n    @Field(value = 10, getterName = \"getGoogleThirdPartyPaymentExtension\")\n    @Nullable\n    private GoogleThirdPartyPaymentExtension googleThirdPartyPaymentExtension;\n    @Field(value = 11, getterName = \"getPrfExtension\")\n    @Nullable\n    private PrfExtension prfExtension;\n    @Field(value = 12, getterName = \"getSimpleTransactionAuthorizationExtension\")\n    @Nullable\n    private SimpleTransactionAuthorizationExtension simpleTransactionAuthorizationExtension;\n    @Field(value = 13, getterName = \"getHmacSecretExtension\")\n    @Nullable\n    private HmacSecretExtension hmacSecretExtension;\n    @Field(value = 14, getterName = \"getPaymentExtension\")\n    @Nullable\n    private PaymentExtension paymentExtension;\n\n    @Constructor\n    public AuthenticationExtensions(@Param(2) @Nullable FidoAppIdExtension fidoAppIdExtension, @Param(3) @Nullable CableAuthenticationExtension cableAuthenticationExtension, @Param(4) @Nullable UserVerificationMethodExtension userVerificationMethodExtension, @Param(5) @Nullable GoogleMultiAssertionExtension googleMultiAssertionExtension, @Param(6) @Nullable GoogleSessionIdExtension googleSessionIdExtension, @Param(7) @Nullable GoogleSilentVerificationExtension googleSilentVerificationExtension, @Param(8) @Nullable DevicePublicKeyExtension devicePublicKeyExtension, @Param(9) @Nullable GoogleTunnelServerIdExtension googleTunnelServerIdExtension, @Param(10) @Nullable GoogleThirdPartyPaymentExtension googleThirdPartyPaymentExtension, @Param(11) @Nullable PrfExtension prfExtension, @Param(12) @Nullable SimpleTransactionAuthorizationExtension simpleTransactionAuthorizationExtension, @Param(13) @Nullable HmacSecretExtension hmacSecretExtension, @Param(14) @Nullable PaymentExtension paymentExtension) {\n        this.fidoAppIdExtension = fidoAppIdExtension;\n        this.cableAuthenticationExtension = cableAuthenticationExtension;\n        this.userVerificationMethodExtension = userVerificationMethodExtension;\n        this.googleMultiAssertionExtension = googleMultiAssertionExtension;\n        this.googleSessionIdExtension = googleSessionIdExtension;\n        this.googleSilentVerificationExtension = googleSilentVerificationExtension;\n        this.devicePublicKeyExtension = devicePublicKeyExtension;\n        this.googleTunnelServerIdExtension = googleTunnelServerIdExtension;\n        this.googleThirdPartyPaymentExtension = googleThirdPartyPaymentExtension;\n        this.prfExtension = prfExtension;\n        this.simpleTransactionAuthorizationExtension = simpleTransactionAuthorizationExtension;\n        this.hmacSecretExtension = hmacSecretExtension;\n        this.paymentExtension = paymentExtension;\n    }\n\n    @Nullable\n    public FidoAppIdExtension getFidoAppIdExtension() {\n        return fidoAppIdExtension;\n    }\n\n    @Hide\n    @Nullable\n    public CableAuthenticationExtension getCableAuthenticationExtension() {\n        return cableAuthenticationExtension;\n    }\n\n    @Nullable\n    public UserVerificationMethodExtension getUserVerificationMethodExtension() {\n        return userVerificationMethodExtension;\n    }\n\n    @Nullable\n    public GoogleMultiAssertionExtension getGoogleMultiAssertionExtension() {\n        return googleMultiAssertionExtension;\n    }\n\n    @Nullable\n    public GoogleSessionIdExtension getGoogleSessionIdExtension() {\n        return googleSessionIdExtension;\n    }\n\n    @Nullable\n    public GoogleSilentVerificationExtension getGoogleSilentVerificationExtension() {\n        return googleSilentVerificationExtension;\n    }\n\n    @Nullable\n    public DevicePublicKeyExtension getDevicePublicKeyExtension() {\n        return devicePublicKeyExtension;\n    }\n\n    @Nullable\n    public GoogleTunnelServerIdExtension getGoogleTunnelServerIdExtension() {\n        return googleTunnelServerIdExtension;\n    }\n\n    @Nullable\n    public GoogleThirdPartyPaymentExtension getGoogleThirdPartyPaymentExtension() {\n        return googleThirdPartyPaymentExtension;\n    }\n\n    @Nullable\n    public PrfExtension getPrfExtension() {\n        return prfExtension;\n    }\n\n    @Nullable\n    public SimpleTransactionAuthorizationExtension getSimpleTransactionAuthorizationExtension() {\n        return simpleTransactionAuthorizationExtension;\n    }\n\n    @Nullable\n    public HmacSecretExtension getHmacSecretExtension() {\n        return hmacSecretExtension;\n    }\n\n    @Nullable\n    public PaymentExtension getPaymentExtension() {\n        return paymentExtension;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof AuthenticationExtensions)) return false;\n\n        AuthenticationExtensions that = (AuthenticationExtensions) o;\n\n        if (!Objects.equals(fidoAppIdExtension, that.fidoAppIdExtension)) return false;\n        if (!Objects.equals(cableAuthenticationExtension, that.cableAuthenticationExtension)) return false;\n        if (!Objects.equals(userVerificationMethodExtension, that.userVerificationMethodExtension)) return false;\n        if (!Objects.equals(googleMultiAssertionExtension, that.googleMultiAssertionExtension)) return false;\n        if (!Objects.equals(googleSessionIdExtension, that.googleSessionIdExtension)) return false;\n        if (!Objects.equals(googleSilentVerificationExtension, that.googleSilentVerificationExtension)) return false;\n        if (!Objects.equals(devicePublicKeyExtension, that.devicePublicKeyExtension)) return false;\n        if (!Objects.equals(googleTunnelServerIdExtension, that.googleTunnelServerIdExtension)) return false;\n        if (!Objects.equals(googleThirdPartyPaymentExtension, that.googleThirdPartyPaymentExtension)) return false;\n        if (!Objects.equals(prfExtension, that.prfExtension)) return false;\n        if (!Objects.equals(simpleTransactionAuthorizationExtension, that.simpleTransactionAuthorizationExtension)) return false;\n        if (!Objects.equals(hmacSecretExtension, that.hmacSecretExtension)) return false;\n        return Objects.equals(paymentExtension, that.paymentExtension);\n    }\n\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(new Object[]{fidoAppIdExtension, cableAuthenticationExtension, userVerificationMethodExtension, googleMultiAssertionExtension, googleSessionIdExtension, googleSilentVerificationExtension, devicePublicKeyExtension, googleTunnelServerIdExtension, googleThirdPartyPaymentExtension, prfExtension, simpleTransactionAuthorizationExtension, hmacSecretExtension, paymentExtension});\n    }\n\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"AuthenticationExtensions\").field(\"fidoAppIdExtension\", fidoAppIdExtension != null ? fidoAppIdExtension.getAppId() : null).field(\"cableAuthenticationExtension\", cableAuthenticationExtension).field(\"userVerificationMethodExtension\", userVerificationMethodExtension != null ? userVerificationMethodExtension.getUvm() : null).field(\"googleMultiAssertionExtension\", googleMultiAssertionExtension).field(\"googleSessionIdExtension\", googleSessionIdExtension).field(\"googleSilentVerificationExtension\", googleSilentVerificationExtension).field(\"devicePublicKeyExtension\", devicePublicKeyExtension).field(\"googleTunnelServerIdExtension\", googleTunnelServerIdExtension).field(\"googleThirdPartyPaymentExtension\", googleThirdPartyPaymentExtension).field(\"prfExtension\", prfExtension).field(\"simpleTransactionAuthorizationExtension\", simpleTransactionAuthorizationExtension).field(\"hmacSecretExtension\", hmacSecretExtension).field(\"paymentExtension\", paymentExtension).end();\n    }\n\n    /**\n     * Builder for {@link AuthenticationExtensions}.\n     */\n    public static class Builder {\n        @Nullable\n        private FidoAppIdExtension fidoAppIdExtension;\n        @Nullable\n        private UserVerificationMethodExtension userVerificationMethodExtension;\n\n        /**\n         * The constructor of {@link AuthenticationExtensions.Builder}.\n         */\n        public Builder() {\n        }\n\n        /**\n         * Sets the App ID extension, which allows for authentication of U2F authenticators previously registered\n         * under the supplied App ID.\n         */\n        public Builder setFido2Extension(@Nullable FidoAppIdExtension appIdExtension) {\n            this.fidoAppIdExtension = appIdExtension;\n            return this;\n        }\n\n        /**\n         * Sets the User Verification Method extension, which allows the relying party to ascertain up to three\n         * authentication methods that were used.\n         */\n        public Builder setUserVerificationMethodExtension(@Nullable UserVerificationMethodExtension userVerificationMethodExtension) {\n            this.userVerificationMethodExtension = userVerificationMethodExtension;\n            return this;\n        }\n\n        /**\n         * Builds the {@link AuthenticationExtensions} object.\n         */\n        @NonNull\n        public AuthenticationExtensions build() {\n            return new AuthenticationExtensions(fidoAppIdExtension, null, userVerificationMethodExtension, null, null, null, null, null, null, null, null, null, null);\n        }\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<AuthenticationExtensions> CREATOR = findCreator(AuthenticationExtensions.class);\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/AuthenticationExtensionsClientOutputs.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableSerializer;\n\nimport org.microg.gms.common.PublicApi;\n\nimport java.util.Arrays;\nimport java.util.Objects;\n\n/**\n * This container class represents client output for extensions that can be passed into FIDO2 APIs.\n */\n@PublicApi\n@SafeParcelable.Class\npublic class AuthenticationExtensionsClientOutputs extends AbstractSafeParcelable {\n    @Field(value = 1, getterName = \"getUvmEntries\")\n    @Nullable\n    private UvmEntries uvmEntries;\n\n    @Field(value = 2, getterName = \"getDevicePublicKeyOutputs\")\n    @Nullable\n    private AuthenticationExtensionsDevicePublicKeyOutputs devicePublicKeyOutputs;\n\n    @Field(value = 3, getterName = \"getCredProps\")\n    @Nullable\n    private AuthenticationExtensionsCredPropsOutputs credProps;\n\n    @Field(value = 4, getterName = \"getPrfOutputs\")\n    @Nullable\n    private AuthenticationExtensionsPrfOutputs prfOutputs;\n\n    @Field(value = 5, getterName = \"getTxAuthSimple\")\n    @Nullable\n    private String txAuthSimple;\n\n    @Constructor\n    public AuthenticationExtensionsClientOutputs(@Param(1) @Nullable UvmEntries uvmEntries, @Param(2) @Nullable AuthenticationExtensionsDevicePublicKeyOutputs devicePublicKeyOutputs, @Param(3) @Nullable AuthenticationExtensionsCredPropsOutputs credProps, @Param(4) @Nullable AuthenticationExtensionsPrfOutputs prfOutputs, @Param(5) @Nullable String txAuthSimple) {\n        this.uvmEntries = uvmEntries;\n        this.devicePublicKeyOutputs = devicePublicKeyOutputs;\n        this.credProps = credProps;\n        this.prfOutputs = prfOutputs;\n        this.txAuthSimple = txAuthSimple;\n    }\n\n    @Nullable\n    public UvmEntries getUvmEntries() {\n        return uvmEntries;\n    }\n\n    @Nullable\n    public AuthenticationExtensionsDevicePublicKeyOutputs getDevicePublicKeyOutputs() {\n        return devicePublicKeyOutputs;\n    }\n\n    @Nullable\n    public AuthenticationExtensionsCredPropsOutputs getCredProps() {\n        return credProps;\n    }\n\n    @Nullable\n    public AuthenticationExtensionsPrfOutputs getPrfOutputs() {\n        return prfOutputs;\n    }\n\n    @Nullable\n    public String getTxAuthSimple() {\n        return txAuthSimple;\n    }\n\n    /**\n     * Serializes the {@link AuthenticationExtensionsClientOutputs} to bytes.\n     * Use {@link #deserializeFromBytes(byte[])} to deserialize.\n     */\n    @NonNull\n    public byte[] serializeToBytes() {\n        return SafeParcelableSerializer.serializeToBytes(this);\n    }\n\n    /**\n     * De-serializes the {@link AuthenticationExtensionsClientOutputs} from bytes, reversing {@link #serializeToBytes()}.\n     *\n     * @return The deserialized {@link AuthenticationExtensionsClientOutputs}\n     */\n    @NonNull\n    public static AuthenticationExtensionsClientOutputs deserializeFromBytes(byte[] serializedBytes) {\n        return SafeParcelableSerializer.deserializeFromBytes(serializedBytes, CREATOR);\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof AuthenticationExtensionsClientOutputs)) return false;\n\n        AuthenticationExtensionsClientOutputs that = (AuthenticationExtensionsClientOutputs) o;\n        return (Objects.equals(uvmEntries, that.uvmEntries)) && (Objects.equals(devicePublicKeyOutputs, that.devicePublicKeyOutputs)) && (Objects.equals(credProps, that.credProps)) && (Objects.equals(prfOutputs, that.prfOutputs)) && (Objects.equals(txAuthSimple, that.txAuthSimple));\n    }\n\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(new Object[]{uvmEntries, devicePublicKeyOutputs, credProps, prfOutputs, txAuthSimple});\n    }\n\n    /**\n     * Builder for {@link AuthenticationExtensionsClientOutputs}.\n     */\n    public static class Builder {\n        @Nullable\n        private UvmEntries uvmEntries;\n        @Nullable\n        private AuthenticationExtensionsDevicePublicKeyOutputs devicePublicKeyOutputs;\n        @Nullable\n        private AuthenticationExtensionsCredPropsOutputs credProps;\n        @Nullable\n        private AuthenticationExtensionsPrfOutputs prfOutputs;\n        @Nullable\n        private String txAuthSimple;\n\n        /**\n         * The constructor of {@link AuthenticationExtensionsClientOutputs.Builder}.\n         */\n        public Builder() {\n        }\n\n        /**\n         * Sets the User Verification Method extension, which allows the relying party to ascertain up to three\n         * authentication methods that were used.\n         */\n        public Builder setUserVerificationMethodEntries(@Nullable UvmEntries uvmEntries) {\n            this.uvmEntries = uvmEntries;\n            return this;\n        }\n\n        /**\n         * Set Device Public Key client outputs\n         */\n        public Builder setDevicePublicKeyOutputs(@Nullable AuthenticationExtensionsDevicePublicKeyOutputs dpkOutputs) {\n            this.devicePublicKeyOutputs = dpkOutputs;\n            return this;\n        }\n\n        /**\n         * Set Credential Properties client outputs (e.g., rk=true)\n         */\n        public Builder setCredProps(@Nullable AuthenticationExtensionsCredPropsOutputs credProps) {\n            this.credProps = credProps;\n            return this;\n        }\n\n        /**\n         * Set PRF client outputs\n         */\n        public Builder setPrfOutputs(@Nullable AuthenticationExtensionsPrfOutputs prfOutputs) {\n            this.prfOutputs = prfOutputs;\n            return this;\n        }\n\n        /**\n         * Set txAuthSimple string\n         */\n        public Builder setTxAuthSimple(@Nullable String txAuthSimple) {\n            this.txAuthSimple = txAuthSimple;\n            return this;\n        }\n\n        /**\n         * Builds the {@link AuthenticationExtensionsClientOutputs} object.\n         */\n        public AuthenticationExtensionsClientOutputs build() {\n            return new AuthenticationExtensionsClientOutputs(uvmEntries, devicePublicKeyOutputs, credProps, prfOutputs, txAuthSimple);\n        }\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<AuthenticationExtensionsClientOutputs> CREATOR = findCreator(AuthenticationExtensionsClientOutputs.class);\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/AuthenticationExtensionsCredPropsOutputs.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport java.util.Objects;\n\n/**\n * Class that holds the result of the credProps extension.\n * <p>\n * Since this extension only reports information, it is always included in registration responses and does not need to be requested.\n */\n@SafeParcelable.Class\npublic class AuthenticationExtensionsCredPropsOutputs extends AbstractSafeParcelable {\n    @Field(value = 1, getterName = \"getIsDiscoverableCredential\")\n    private boolean rk;\n\n    @Constructor\n    public AuthenticationExtensionsCredPropsOutputs(@Param(1) boolean rk) {\n        this.rk = rk;\n    }\n\n    public boolean equals(Object other) {\n        return (other instanceof AuthenticationExtensionsCredPropsOutputs) && this.rk == ((AuthenticationExtensionsCredPropsOutputs) other).rk;\n    }\n\n    /**\n     * This value reflects the \"rk\" flag of the WebAuthn extension.\n     */\n    public boolean getIsDiscoverableCredential() {\n        return rk;\n    }\n\n    public int hashCode() {\n        return Objects.hashCode(new Object[]{this.rk});\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<AuthenticationExtensionsCredPropsOutputs> CREATOR = findCreator(AuthenticationExtensionsCredPropsOutputs.class);\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/AuthenticationExtensionsDevicePublicKeyOutputs.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableSerializer;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.Arrays;\n\n@PublicApi\n@SafeParcelable.Class\npublic class AuthenticationExtensionsDevicePublicKeyOutputs extends AbstractSafeParcelable {\n\n    @Field(value = 1, getterName = \"getDevicePublicKey\")\n    @Nullable\n    private final byte[] devicePublicKey;\n\n    @Field(value = 2, getterName = \"getSignature\")\n    @Nullable\n    private final byte[] signature;\n\n    @Constructor\n    public AuthenticationExtensionsDevicePublicKeyOutputs(@Param(1) byte[] devicePublicKey, @Param(2) byte[] signature) {\n        this.devicePublicKey = devicePublicKey;\n        this.signature = signature;\n    }\n\n    @Nullable\n    public byte[] getDevicePublicKey() {\n        return devicePublicKey;\n    }\n\n    @Nullable\n    public byte[] getSignature() {\n        return signature;\n    }\n\n    @PublicApi\n    public static class Builder {\n        @Nullable\n        private byte[] devicePublicKey;\n        @Nullable\n        private byte[] signature;\n\n        public Builder() {\n        }\n\n        public Builder setDevicePublicKey(@Nullable byte[] devicePublicKey) {\n            this.devicePublicKey = devicePublicKey;\n            return this;\n        }\n\n        public Builder setSignature(@Nullable byte[] signature) {\n            this.signature = signature;\n            return this;\n        }\n\n        public AuthenticationExtensionsDevicePublicKeyOutputs build() {\n            return new AuthenticationExtensionsDevicePublicKeyOutputs(devicePublicKey, signature);\n        }\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    @PublicApi\n    @NonNull\n    public byte[] serializeToBytes() {\n        return SafeParcelableSerializer.serializeToBytes(this);\n    }\n\n    @PublicApi\n    @NonNull\n    public static AuthenticationExtensionsDevicePublicKeyOutputs deserializeFromBytes(@NonNull byte[] serializedBytes) {\n        return SafeParcelableSerializer.deserializeFromBytes(serializedBytes, CREATOR);\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (!(o instanceof AuthenticationExtensionsDevicePublicKeyOutputs)) return false;\n        AuthenticationExtensionsDevicePublicKeyOutputs that = (AuthenticationExtensionsDevicePublicKeyOutputs) o;\n        return Arrays.equals(devicePublicKey, that.devicePublicKey) && Arrays.equals(signature, that.signature);\n    }\n\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(new Object[]{Arrays.hashCode(devicePublicKey), Arrays.hashCode(signature)});\n    }\n\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"AuthenticationExtensionsDevicePublicKeyOutputs\").field(\"devicePublicKey\", devicePublicKey != null ? devicePublicKey.length : null).field(\"signature\", signature != null ? signature.length : null).end();\n    }\n\n    public static final SafeParcelableCreatorAndWriter<AuthenticationExtensionsDevicePublicKeyOutputs> CREATOR = findCreator(AuthenticationExtensionsDevicePublicKeyOutputs.class);\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/AuthenticationExtensionsPrfOutputs.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\nimport android.util.Base64;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class AuthenticationExtensionsPrfOutputs extends AbstractSafeParcelable {\n\n    @Field(value = 1, getterName = \"isEnabled\")\n    private final boolean enabled;\n\n    @Field(value = 2, getterName = \"getFirst\")\n    @Nullable\n    private final byte[] first;\n\n    @Field(value = 3, getterName = \"getSecond\")\n    @Nullable\n    private final byte[] second;\n\n    @Constructor\n    public AuthenticationExtensionsPrfOutputs(@Param(1) boolean enabled, @Param(2) @Nullable byte[] first, @Param(3) @Nullable byte[] second) {\n        this.enabled = enabled;\n        this.first = first;\n        this.second = second;\n    }\n\n    public boolean isEnabled() {\n        return enabled;\n    }\n\n    @Nullable\n    public byte[] getFirst() {\n        return first;\n    }\n\n    @Nullable\n    public byte[] getSecond() {\n        return second;\n    }\n\n    private String b64url(byte[] v) {\n        return Base64.encodeToString(v, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING);\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<AuthenticationExtensionsPrfOutputs> CREATOR = findCreator(AuthenticationExtensionsPrfOutputs.class);\n\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"AuthenticationExtensionsPrfOutputs\").field(\"enabled\", enabled).field(\"first\", first).field(\"second\", second).end();\n    }\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/AuthenticatorAssertionResponse.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableSerializer;\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.Arrays;\n\n/**\n * This structure contains cryptographic signatures produced by scoped credentials that provides proof of possession\n * of a private key as well as evidence of user consent to a specific transaction.\n */\n@PublicApi\n@SafeParcelable.Class\npublic class AuthenticatorAssertionResponse extends AuthenticatorResponse {\n    @Field(value = 2, getterName = \"getKeyHandle\")\n    @NonNull\n    private byte[] keyHandle;\n    @Field(value = 3, getterName = \"getClientDataJSON\")\n    @NonNull\n    private byte[] clientDataJSON;\n    @Field(value = 4, getterName = \"getAuthenticatorData\")\n    @NonNull\n    private byte[] authenticatorData;\n    @Field(value = 5, getterName = \"getSignature\")\n    @NonNull\n    private byte[] signature;\n    @Field(value = 6, getterName = \"getUserHandle\")\n    @Nullable\n    private byte[] userHandle;\n\n    private AuthenticatorAssertionResponse() {\n    }\n\n    @Constructor\n    public AuthenticatorAssertionResponse(@Param(2) @NonNull byte[] keyHandle, @Param(3) @NonNull byte[] clientDataJSON, @Param(4) @NonNull byte[] authenticatorData, @Param(5) @NonNull byte[] signature, @Param(6) @Nullable byte[] userHandle) {\n        this.keyHandle = keyHandle;\n        this.clientDataJSON = clientDataJSON;\n        this.authenticatorData = authenticatorData;\n        this.signature = signature;\n        this.userHandle = userHandle;\n    }\n\n    @NonNull\n    public byte[] getAuthenticatorData() {\n        return authenticatorData;\n    }\n\n    @Override\n    @NonNull\n    public byte[] getClientDataJSON() {\n        return clientDataJSON;\n    }\n\n    /**\n     * @deprecated use {@link PublicKeyCredential#getRawId()} instead\n     */\n    @Deprecated\n    @NonNull\n    public byte[] getKeyHandle() {\n        return keyHandle;\n    }\n\n    @NonNull\n    public byte[] getSignature() {\n        return signature;\n    }\n\n    @Nullable\n    public byte[] getUserHandle() {\n        return userHandle;\n    }\n\n    @Override\n    @NonNull\n    public byte[] serializeToBytes() {\n        return SafeParcelableSerializer.serializeToBytes(this);\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof AuthenticatorAssertionResponse)) return false;\n\n        AuthenticatorAssertionResponse that = (AuthenticatorAssertionResponse) o;\n\n        if (!Arrays.equals(keyHandle, that.keyHandle)) return false;\n        if (!Arrays.equals(clientDataJSON, that.clientDataJSON)) return false;\n        if (!Arrays.equals(authenticatorData, that.authenticatorData)) return false;\n        if (!Arrays.equals(signature, that.signature)) return false;\n        return Arrays.equals(userHandle, that.userHandle);\n    }\n\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(new Object[]{Arrays.hashCode(keyHandle), Arrays.hashCode(clientDataJSON), Arrays.hashCode(authenticatorData), Arrays.hashCode(signature), Arrays.hashCode(userHandle)});\n    }\n\n    @Override\n    @NonNull\n    public String toString() {\n        return ToStringHelper.name(\"AuthenticatorAssertionResponse\")\n                .field(\"keyHandle\", keyHandle)\n                .field(\"clientDataJSON\", clientDataJSON)\n                .field(\"authenticatorData\", authenticatorData)\n                .field(\"signature\", signature)\n                .field(\"userHandle\", userHandle)\n                .end();\n    }\n\n    @NonNull\n    public static AuthenticatorAssertionResponse deserializeFromBytes(byte[] serializedBytes) {\n        return SafeParcelableSerializer.deserializeFromBytes(serializedBytes, CREATOR);\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<AuthenticatorAssertionResponse> CREATOR = findCreator(AuthenticatorAssertionResponse.class);\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/AuthenticatorAttestationResponse.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableSerializer;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.Arrays;\n\n/**\n * Represents a newly-created scoped credential, aka the response from a registration request.\n */\n@PublicApi\n@SafeParcelable.Class\npublic class AuthenticatorAttestationResponse extends AuthenticatorResponse {\n    @Field(value = 2, getterName = \"getKeyHandle\")\n    @NonNull\n    private byte[] keyHandle;\n    @Field(value = 3, getterName = \"getClientDataJSON\")\n    @NonNull\n    private byte[] clientDataJSON;\n    @Field(value = 4, getterName = \"getAttestationObject\")\n    @NonNull\n    private byte[] attestationObject;\n    @Field(value = 5, getterName = \"getTransports\")\n    @NonNull\n    private String[] transports;\n\n    private AuthenticatorAttestationResponse() {\n    }\n\n    @Hide\n    @Constructor\n    public AuthenticatorAttestationResponse(@Param(2) @NonNull byte[] keyHandle, @Param(3) @NonNull byte[] clientDataJSON, @Param(4) @NonNull byte[] attestationObject, @Param(5) @NonNull String[] transports) {\n        this.keyHandle = keyHandle;\n        this.clientDataJSON = clientDataJSON;\n        this.attestationObject = attestationObject;\n        this.transports = transports;\n    }\n\n    @NonNull\n    public byte[] getAttestationObject() {\n        return attestationObject;\n    }\n\n    @Override\n    @NonNull\n    public byte[] getClientDataJSON() {\n        return clientDataJSON;\n    }\n\n    /**\n     * @deprecated use {@link PublicKeyCredential#getRawId()} instead\n     */\n    @Deprecated\n    @NonNull\n    public byte[] getKeyHandle() {\n        return keyHandle;\n    }\n\n    @NonNull\n    public String[] getTransports() {\n        return transports;\n    }\n\n    @Override\n    @NonNull\n    public byte[] serializeToBytes() {\n        return SafeParcelableSerializer.serializeToBytes(this);\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof AuthenticatorAttestationResponse)) return false;\n\n        AuthenticatorAttestationResponse that = (AuthenticatorAttestationResponse) o;\n\n        if (!Arrays.equals(keyHandle, that.keyHandle)) return false;\n        if (!Arrays.equals(clientDataJSON, that.clientDataJSON)) return false;\n        if (!Arrays.equals(attestationObject, that.attestationObject)) return false;\n        if (!Arrays.equals(transports, that.transports)) return false;\n        return true;\n    }\n\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(new Object[]{Arrays.hashCode(keyHandle), Arrays.hashCode(clientDataJSON), Arrays.hashCode(attestationObject), Arrays.hashCode(transports)});\n    }\n\n    @Override\n    @NonNull\n    public String toString() {\n        return ToStringHelper.name(\"AuthenticatorAttestationResponse\")\n                .field(\"keyHandle\", keyHandle)\n                .field(\"clientDataJSON\", clientDataJSON)\n                .field(\"attestationObject\", attestationObject)\n                .field(\"transports\", transports)\n                .end();\n    }\n\n    @NonNull\n    public static AuthenticatorAttestationResponse deserializeFromBytes(byte[] serializedBytes) {\n        return SafeParcelableSerializer.deserializeFromBytes(serializedBytes, CREATOR);\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<AuthenticatorAttestationResponse> CREATOR = findCreator(AuthenticatorAttestationResponse.class);\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/AuthenticatorErrorResponse.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableSerializer;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.Arrays;\n\n/**\n * The response after an error occurred.\n */\n@PublicApi\n@SafeParcelable.Class\npublic class AuthenticatorErrorResponse extends AuthenticatorResponse {\n    @Field(value = 2, getterName = \"getErrorCode\")\n    @NonNull\n    private ErrorCode errorCode;\n    @Field(value = 3, getterName = \"getErrorMessage\")\n    @Nullable\n    private String errorMessage;\n    @Field(value = 4, getterName = \"getInternalErrorCode\")\n    private int internalErrorCode;\n\n    private AuthenticatorErrorResponse() {\n    }\n\n    @Hide\n    public AuthenticatorErrorResponse(@NonNull ErrorCode errorCode, @Nullable String errorMessage) {\n        this.errorCode = errorCode;\n        this.errorMessage = errorMessage;\n    }\n\n    @Constructor\n    AuthenticatorErrorResponse(@Param(2) @NonNull ErrorCode errorCode, @Param(3) @Nullable String errorMessage, @Param(4) int internalErrorCode) {\n        this.errorCode = errorCode;\n        this.errorMessage = errorMessage;\n        this.internalErrorCode = internalErrorCode;\n    }\n\n    @Override\n    @NonNull\n    public byte[] getClientDataJSON() {\n        throw new UnsupportedOperationException();\n    }\n\n    @NonNull\n    public ErrorCode getErrorCode() {\n        return errorCode;\n    }\n\n    public int getErrorCodeAsInt() {\n        return errorCode.getCode();\n    }\n\n    @Nullable\n    public String getErrorMessage() {\n        return errorMessage;\n    }\n\n    @Hide\n    public int getInternalErrorCode() {\n        return internalErrorCode;\n    }\n\n    @Override\n    @NonNull\n    public byte[] serializeToBytes() {\n        return SafeParcelableSerializer.serializeToBytes(this);\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof AuthenticatorErrorResponse)) return false;\n\n        AuthenticatorErrorResponse that = (AuthenticatorErrorResponse) o;\n\n        if (errorCode != null ? !errorCode.equals(that.errorCode) : that.errorCode != null) return false;\n        if (errorMessage != null ? !errorMessage.equals(that.errorMessage) : that.errorMessage != null) return false;\n        if (internalErrorCode != that.internalErrorCode) return false;\n        return true;\n    }\n\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(new Object[]{errorCode, errorMessage, internalErrorCode});\n    }\n\n    @Override\n    @NonNull\n    public String toString() {\n        return ToStringHelper.name(\"AuthenticatorErrorResponse\")\n                .value(errorCode.name())\n                .value(errorMessage)\n                .end();\n    }\n\n    @NonNull\n    public static AuthenticatorErrorResponse deserializeFromBytes(byte[] serializedBytes) {\n        return SafeParcelableSerializer.deserializeFromBytes(serializedBytes, CREATOR);\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<AuthenticatorErrorResponse> CREATOR = findCreator(AuthenticatorErrorResponse.class);\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/AuthenticatorResponse.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\n\n/**\n * Authenticators respond to relying party requests by returning an object derived from this interface.\n */\npublic abstract class AuthenticatorResponse extends AbstractSafeParcelable {\n    @NonNull\n    public abstract byte[] getClientDataJSON();\n\n    @NonNull\n    public abstract byte[] serializeToBytes();\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/AuthenticatorSelectionCriteria.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.Arrays;\n\n/**\n * Relying Parties may use {@link AuthenticatorSelectionCriteria} to specify their requirements regarding authenticator\n * attributes.\n */\n@SafeParcelable.Class\npublic class AuthenticatorSelectionCriteria extends AbstractSafeParcelable {\n    @Field(value = 2, getterName = \"getAttachment\")\n    @Nullable\n    private Attachment attachment;\n    @Field(value = 3, getterName = \"getRequireResidentKey\")\n    @Nullable\n    private Boolean requireResidentKey;\n    @Field(value = 4, getterName = \"getRequireUserVerification\")\n    @Nullable\n    private UserVerificationRequirement requireUserVerification;\n    @Field(value = 5, getterName = \"getResidentKeyRequirement\")\n    @Nullable\n    private ResidentKeyRequirement residentKeyRequirement;\n\n    @Constructor\n    AuthenticatorSelectionCriteria(@Param(2) @Nullable Attachment attachment, @Param(3) @Nullable Boolean requireResidentKey, @Param(4) @Nullable UserVerificationRequirement requireUserVerification, @Param(5) @Nullable ResidentKeyRequirement residentKeyRequirement) {\n        this.attachment = attachment;\n        this.requireResidentKey = requireResidentKey;\n        this.requireUserVerification = requireUserVerification;\n        this.residentKeyRequirement = residentKeyRequirement;\n    }\n\n    @Nullable\n    public Attachment getAttachment() {\n        return attachment;\n    }\n\n    @Nullable\n    public String getAttachmentAsString() {\n        if (attachment == null) return null;\n        return attachment.toString();\n    }\n\n    @Nullable\n    public Boolean getRequireResidentKey() {\n        return requireResidentKey;\n    }\n\n    @Nullable\n    public ResidentKeyRequirement getResidentKeyRequirement() {\n        return residentKeyRequirement;\n    }\n\n    @Nullable\n    public String getResidentKeyRequirementAsString() {\n        if (residentKeyRequirement == null) return null;\n        return residentKeyRequirement.toString();\n    }\n\n    @Hide\n    @Nullable\n    public UserVerificationRequirement getRequireUserVerification() {\n        return requireUserVerification;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof AuthenticatorSelectionCriteria)) return false;\n\n        AuthenticatorSelectionCriteria that = (AuthenticatorSelectionCriteria) o;\n\n        if (attachment != that.attachment) return false;\n        if (requireResidentKey != null ? !requireResidentKey.equals(that.requireResidentKey) : that.requireResidentKey != null) return false;\n        if (requireUserVerification != that.requireUserVerification) return false;\n        if (residentKeyRequirement != that.residentKeyRequirement) return false;\n        return true;\n    }\n\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(new Object[]{attachment, requireResidentKey, requireUserVerification});\n    }\n\n    @Override\n    @NonNull\n    public String toString() {\n        return ToStringHelper.name(\"AuthenticatorSelectionCriteria\")\n                .field(\"attachment\", attachment)\n                .field(\"requireResidentKey\", requireResidentKey)\n                .field(\"requireUserVerification\", requireUserVerification)\n                .field(\"residentKeyRequirement\", residentKeyRequirement)\n                .end();\n    }\n\n    /**\n     * Builder for {@link AuthenticatorSelectionCriteria}.\n     */\n    public static class Builder {\n        @Nullable\n        private Attachment attachment;\n        @Nullable\n        private Boolean requireResidentKey;\n        @Nullable\n        private ResidentKeyRequirement residentKeyRequirement;\n\n        /**\n         * Sets the attachment to use for this session.\n         */\n        public Builder setAttachment(@Nullable Attachment attachment) {\n            this.attachment = attachment;\n            return this;\n        }\n\n        /**\n         * Sets whether the key created will be a resident key.\n         */\n        public Builder setRequireResidentKey(@Nullable Boolean requireResidentKey) {\n            this.requireResidentKey = requireResidentKey;\n            return this;\n        }\n\n        /**\n         * Sets residentKeyRequirement\n         */\n        public Builder setResidentKeyRequirement(@Nullable ResidentKeyRequirement residentKeyRequirement) {\n            this.residentKeyRequirement = residentKeyRequirement;\n            return this;\n        }\n\n        @NonNull\n        public AuthenticatorSelectionCriteria build() {\n            return new AuthenticatorSelectionCriteria(attachment, requireResidentKey, null, residentKeyRequirement);\n        }\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<AuthenticatorSelectionCriteria> CREATOR = findCreator(AuthenticatorSelectionCriteria.class);\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/BrowserPublicKeyCredentialCreationOptions.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.net.Uri;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableSerializer;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.Arrays;\n\n/**\n * Parameters to a make credential request from a Web browser.\n */\n@PublicApi\n@SafeParcelable.Class\npublic class BrowserPublicKeyCredentialCreationOptions extends BrowserRequestOptions {\n    @Field(value = 2, getterName = \"getPublicKeyCredentialCreationOptions\")\n    @NonNull\n    private PublicKeyCredentialCreationOptions delegate;\n    @Field(value = 3, getterName = \"getOrigin\")\n    @NonNull\n    private Uri origin;\n    @Field(value = 4, getterName = \"getClientDataHash\")\n    @Nullable\n    private byte[] clientDataHash;\n\n    @Constructor\n    BrowserPublicKeyCredentialCreationOptions(@Param(2) @NonNull PublicKeyCredentialCreationOptions delegate, @Param(3) @NonNull Uri origin, @Param(4) @Nullable byte[] clientDataHash) {\n        this.delegate = delegate;\n        this.origin = origin;\n        this.clientDataHash = clientDataHash;\n    }\n\n    @Override\n    @Nullable\n    public AuthenticationExtensions getAuthenticationExtensions() {\n        return delegate.getAuthenticationExtensions();\n    }\n\n    @Override\n    @NonNull\n    public byte[] getChallenge() {\n        return delegate.getChallenge();\n    }\n\n    @Override\n    @Nullable\n    public byte[] getClientDataHash() {\n        return clientDataHash;\n    }\n\n    @Override\n    @NonNull\n    public Uri getOrigin() {\n        return origin;\n    }\n\n    @NonNull\n    public PublicKeyCredentialCreationOptions getPublicKeyCredentialCreationOptions() {\n        return delegate;\n    }\n\n    @Override\n    @Nullable\n    public Integer getRequestId() {\n        return delegate.getRequestId();\n    }\n\n    @Override\n    @Nullable\n    public Double getTimeoutSeconds() {\n        return delegate.getTimeoutSeconds();\n    }\n\n    @Override\n    @Nullable\n    public TokenBinding getTokenBinding() {\n        return delegate.getTokenBinding();\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof BrowserPublicKeyCredentialCreationOptions)) return false;\n\n        BrowserPublicKeyCredentialCreationOptions that = (BrowserPublicKeyCredentialCreationOptions) o;\n\n        if (delegate != null ? !delegate.equals(that.delegate) : that.delegate != null) return false;\n        if (origin != null ? !origin.equals(that.origin) : that.origin != null) return false;\n        return Arrays.equals(clientDataHash, that.clientDataHash);\n    }\n\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(new Object[]{delegate, origin, Arrays.hashCode(clientDataHash)});\n    }\n\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"BrowserPublicKeyCredentialCreationOptions\")\n                .value(delegate)\n                .field(\"origin\", origin)\n                .field(\"clientDataHash\", clientDataHash)\n                .end();\n    }\n\n    /**\n     * Builder for {@link BrowserPublicKeyCredentialCreationOptions}.\n     */\n    public static class Builder {\n        @NonNull\n        private PublicKeyCredentialCreationOptions delegate;\n        @NonNull\n        private Uri origin;\n        @Nullable\n        private byte[] clientDataHash;\n\n        /**\n         * The constructor of {@link BrowserPublicKeyCredentialCreationOptions.Builder}.\n         */\n        public Builder() {\n        }\n\n        /**\n         * Sets a clientDataHash value to sign over in place of assembling and hashing clientDataJSON during the\n         * signature request.\n         * <p>\n         * Note: This is optional and only provided for contexts where the unhashed information necessary to assemble\n         * WebAuthn clientDataJSON is not available. If set, the resulting {@link AuthenticatorAssertionResponse} will\n         * return an invalid value for {@code getClientDataJSON()}. Generally, browser clients should use\n         * {@link PublicKeyCredentialCreationOptions.Builder#setChallenge(byte[])} instead.\n         *\n         * @return\n         */\n        public BrowserPublicKeyCredentialCreationOptions.Builder setClientDataHash(@NonNull byte[] clientDataHash) {\n            this.clientDataHash = clientDataHash;\n            return this;\n        }\n\n        /**\n         * Sets the origin on whose behalf the calling browser is requesting a registration operation.\n         */\n        public BrowserPublicKeyCredentialCreationOptions.Builder setOrigin(@NonNull Uri origin) {\n            this.origin = origin;\n            return this;\n        }\n\n        /**\n         * Sets the parameters to dictate the client behavior during this registration session.\n         */\n        public BrowserPublicKeyCredentialCreationOptions.Builder setPublicKeyCredentialCreationOptions(@NonNull PublicKeyCredentialCreationOptions publicKeyCredentialCreationOptions) {\n            this.delegate = publicKeyCredentialCreationOptions;\n            return this;\n        }\n\n        /**\n         * Builds the {@link BrowserPublicKeyCredentialCreationOptions} object.\n         */\n        @NonNull\n        public BrowserPublicKeyCredentialCreationOptions build() {\n            return new BrowserPublicKeyCredentialCreationOptions(delegate, origin, clientDataHash);\n        }\n    }\n\n    public static BrowserPublicKeyCredentialCreationOptions deserializeFromBytes(byte[] serializedBytes) {\n        return SafeParcelableSerializer.deserializeFromBytes(serializedBytes, CREATOR);\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<BrowserPublicKeyCredentialCreationOptions> CREATOR = findCreator(BrowserPublicKeyCredentialCreationOptions.class);\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/BrowserPublicKeyCredentialRequestOptions.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.net.Uri;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableSerializer;\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.Arrays;\n\n/**\n * Parameters for a signature request from a Web Browser.\n */\n@PublicApi\n@SafeParcelable.Class\npublic class BrowserPublicKeyCredentialRequestOptions extends BrowserRequestOptions {\n    @Field(value = 2, getterName = \"getPublicKeyCredentialRequestOptions\")\n    @NonNull\n    private PublicKeyCredentialRequestOptions delegate;\n    @Field(value = 3, getterName = \"getOrigin\")\n    @NonNull\n    private Uri origin;\n    @Field(value = 4, getterName = \"getClientDataHash\")\n    @Nullable\n    private byte[] clientDataHash;\n\n    @Constructor\n    BrowserPublicKeyCredentialRequestOptions(@Param(2) @NonNull PublicKeyCredentialRequestOptions delegate, @Param(3) @NonNull Uri origin, @Param(4) @Nullable byte[] clientDataHash) {\n        this.delegate = delegate;\n        this.origin = origin;\n        this.clientDataHash = clientDataHash;\n    }\n\n    @Override\n    @Nullable\n    public AuthenticationExtensions getAuthenticationExtensions() {\n        return delegate.getAuthenticationExtensions();\n    }\n\n    @Override\n    @NonNull\n    public byte[] getChallenge() {\n        return delegate.getChallenge();\n    }\n\n    @Override\n    @Nullable\n    public byte[] getClientDataHash() {\n        return clientDataHash;\n    }\n\n    @Override\n    @NonNull\n    public Uri getOrigin() {\n        return origin;\n    }\n\n    @NonNull\n    public PublicKeyCredentialRequestOptions getPublicKeyCredentialRequestOptions() {\n        return delegate;\n    }\n\n    @Override\n    @Nullable\n    public Integer getRequestId() {\n        return delegate.getRequestId();\n    }\n\n    @Override\n    @Nullable\n    public Double getTimeoutSeconds() {\n        return delegate.getTimeoutSeconds();\n    }\n\n    @Override\n    @Nullable\n    public TokenBinding getTokenBinding() {\n        return delegate.getTokenBinding();\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof BrowserPublicKeyCredentialRequestOptions)) return false;\n\n        BrowserPublicKeyCredentialRequestOptions that = (BrowserPublicKeyCredentialRequestOptions) o;\n\n        if (delegate != null ? !delegate.equals(that.delegate) : that.delegate != null) return false;\n        if (origin != null ? !origin.equals(that.origin) : that.origin != null) return false;\n        return Arrays.equals(clientDataHash, that.clientDataHash);\n    }\n\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(new Object[]{delegate, origin, Arrays.hashCode(clientDataHash)});\n    }\n\n    @Override\n    @NonNull\n    public String toString() {\n        return ToStringHelper.name(\"BrowserPublicKeyCredentialRequestOptions\")\n                .value(delegate)\n                .field(\"origin\", origin)\n                .field(\"clientDataHash\", clientDataHash)\n                .end();\n    }\n\n    /**\n     * Builder for {@link BrowserPublicKeyCredentialRequestOptions}.\n     */\n    public static class Builder {\n        @NonNull\n        private PublicKeyCredentialRequestOptions delegate;\n        @NonNull\n        private Uri origin;\n        @Nullable\n        private byte[] clientDataHash;\n\n        /**\n         * The constructor of {@link BrowserPublicKeyCredentialRequestOptions.Builder}.\n         */\n        public Builder() {\n        }\n\n        /**\n         * Sets a clientDataHash value to sign over in place of assembling and hashing clientDataJSON during the\n         * signature request.\n         * <p>\n         * Note: This is optional and only provided for contexts where the unhashed information necessary to assemble\n         * WebAuthn clientDataJSON is not available. If set, the resulting {@link AuthenticatorAssertionResponse} will\n         * return an invalid value for {@code getClientDataJSON()}. Generally, browser clients should use\n         * {@link PublicKeyCredentialRequestOptions.Builder#setChallenge(byte[])} instead.\n         *\n         * @return\n         */\n        public Builder setClientDataHash(@NonNull byte[] clientDataHash) {\n            this.clientDataHash = clientDataHash;\n            return this;\n        }\n\n        /**\n         * Sets the origin on whose behalf the calling browser is requesting an authentication operation.\n         */\n        public Builder setOrigin(@NonNull Uri origin) {\n            this.origin = origin;\n            return this;\n        }\n\n        /**\n         * Sets the parameters to dictate client behavior during this authentication session.\n         */\n        public Builder setPublicKeyCredentialRequestOptions(@NonNull PublicKeyCredentialRequestOptions publicKeyCredentialRequestOptions) {\n            this.delegate = publicKeyCredentialRequestOptions;\n            return this;\n        }\n\n        /**\n         * Builds the {@link BrowserPublicKeyCredentialRequestOptions} object.\n         */\n        @NonNull\n        public BrowserPublicKeyCredentialRequestOptions build() {\n            return new BrowserPublicKeyCredentialRequestOptions(delegate, origin, clientDataHash);\n        }\n    }\n\n    public static BrowserPublicKeyCredentialRequestOptions deserializeFromBytes(byte[] serializedBytes) {\n        return SafeParcelableSerializer.deserializeFromBytes(serializedBytes, CREATOR);\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<BrowserPublicKeyCredentialRequestOptions> CREATOR = findCreator(BrowserPublicKeyCredentialRequestOptions.class);\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/BrowserRequestOptions.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.net.Uri;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\n/**\n * An abstract class representing browser-based request parameters.\n */\npublic abstract class BrowserRequestOptions extends RequestOptions {\n    /**\n     * Gets value of the client data hash.\n     */\n    @Nullable\n    public abstract byte[] getClientDataHash();\n\n    @NonNull\n    public abstract Uri getOrigin();\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/COSEAlgorithmIdentifier.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport androidx.annotation.NonNull;\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.utils.ToStringHelper;\n\n@PublicApi\npublic class COSEAlgorithmIdentifier implements Parcelable {\n    private Algorithm algorithm;\n\n    private COSEAlgorithmIdentifier() {\n    }\n\n    private COSEAlgorithmIdentifier(Algorithm algorithm) {\n        this.algorithm = algorithm;\n    }\n\n    @NonNull\n    public static COSEAlgorithmIdentifier fromCoseValue(int value) throws UnsupportedAlgorithmIdentifierException {\n        if (value == RSAAlgorithm.LEGACY_RS1.getAlgoValue()) return new COSEAlgorithmIdentifier(RSAAlgorithm.RS1);\n        for (RSAAlgorithm algorithm : RSAAlgorithm.values()) {\n            if (algorithm.getAlgoValue() == value) return new COSEAlgorithmIdentifier(algorithm);\n        }\n        for (EC2Algorithm algorithm : EC2Algorithm.values()) {\n            if (algorithm.getAlgoValue() == value) return new COSEAlgorithmIdentifier(algorithm);\n        }\n        throw new UnsupportedAlgorithmIdentifierException(value);\n    }\n\n    public int toCoseValue() {\n        return algorithm.getAlgoValue();\n    }\n\n    @Override\n    @NonNull\n    public String toString() {\n        return ToStringHelper.name(\"COSEAlgorithmIdentifier\")\n                .value(algorithm)\n                .end();\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.writeInt(algorithm.getAlgoValue());\n    }\n\n    public static final Creator<COSEAlgorithmIdentifier> CREATOR = new Creator<COSEAlgorithmIdentifier>() {\n        @Override\n        public COSEAlgorithmIdentifier createFromParcel(Parcel in) {\n            try {\n                return fromCoseValue(in.readInt());\n            } catch (UnsupportedAlgorithmIdentifierException e) {\n                throw new RuntimeException(e);\n            }\n        }\n\n        @Override\n        public COSEAlgorithmIdentifier[] newArray(int size) {\n            return new COSEAlgorithmIdentifier[size];\n        }\n    };\n\n    public static class UnsupportedAlgorithmIdentifierException extends Exception {\n        public UnsupportedAlgorithmIdentifierException(int algId) {\n            super(\"Algorithm with COSE value \" + algId + \" not supported\");\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/CableAuthenticationData.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class CableAuthenticationData extends AbstractSafeParcelable {\n    @Field(1)\n    long version;\n    @Field(2)\n    @NonNull\n    byte[] clientEid;\n    @Field(3)\n    @NonNull\n    byte[] authenticatorEid;\n    @Field(4)\n    @NonNull\n    byte[] sessionPreKey;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<CableAuthenticationData> CREATOR = findCreator(CableAuthenticationData.class);\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/CableAuthenticationExtension.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport java.util.List;\n\n@SafeParcelable.Class\npublic class CableAuthenticationExtension extends AbstractSafeParcelable {\n    @Field(1)\n    @NonNull\n    List<CableAuthenticationData> cableAuthentication;\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<CableAuthenticationExtension> CREATOR = findCreator(CableAuthenticationExtension.class);\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/CredentialPropertiesOutput.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport org.microg.gms.common.PublicApi;\n\nimport java.util.Arrays;\n\n@PublicApi\n@SafeParcelable.Class\npublic class CredentialPropertiesOutput extends AbstractSafeParcelable {\n    @Field(value = 1, getterName = \"isResidentKey\")\n    private final boolean residentKey;\n\n    @Constructor\n    public CredentialPropertiesOutput(@Param(1) boolean residentKey) {\n        this.residentKey = residentKey;\n    }\n\n    public boolean isResidentKey() {\n        return residentKey;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof CredentialPropertiesOutput)) return false;\n        CredentialPropertiesOutput that = (CredentialPropertiesOutput) o;\n        return residentKey == that.residentKey;\n    }\n\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(new Object[]{residentKey});\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<CredentialPropertiesOutput> CREATOR = findCreator(CredentialPropertiesOutput.class);\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/DevicePublicKeyExtension.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.utils.ToStringHelper;\n\n@PublicApi\n@SafeParcelable.Class\npublic class DevicePublicKeyExtension extends AbstractSafeParcelable {\n    @Field(value = 1, getterName = \"isDevicePublicKey\")\n    private final boolean devicePublicKey;\n\n    @Constructor\n    public DevicePublicKeyExtension(@Param(1) boolean devicePublicKey) {\n        this.devicePublicKey = devicePublicKey;\n    }\n\n    public boolean isDevicePublicKey() {\n        return devicePublicKey;\n    }\n\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"DevicePublicKeyExtension\").field(\"isDevicePublicKey\", devicePublicKey).end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<DevicePublicKeyExtension> CREATOR = AbstractSafeParcelable.findCreator(DevicePublicKeyExtension.class);\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/DevicePublicKeyStringDef.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport androidx.annotation.NonNull;\n\n/**\n * Enum values to be passed into DevicePublicKeyExtension. This tells the authenticator what to return for the DPK extension object.\n * <p>\n * These values are placeholders until the final spec is determined. For now,\n * <ul>\n * <li>NONE is to not request a DPK.</li>\n * <li>DIRECT is to request a DPK.</li>\n * <li>INDIRECT has no function at this time.</li>\n * </ul>\n */\npublic @interface DevicePublicKeyStringDef {\n    @NonNull\n    String NONE = \"none\";\n    @NonNull\n    String INDIRECT = \"indirect\";\n    @NonNull\n    String DIRECT = \"direct\";\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/EC2Algorithm.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Algorithm names and COSE identifiers for EC2 (public) keys.\n */\n@PublicApi\npublic enum EC2Algorithm implements Algorithm {\n    /**\n     * ECDH-ES with HKDF-SHA-256\n     */\n    ECDH_HKDF_256(-25),\n    /**\n     * EdDSA with Ed25519\n     */\n    ED25519(-8),\n    /**\n     * TPM_ECC_BN_P256 curve w/ SHA-256\n     */\n    ED256(-260),\n    /**\n     * ECC_BN_ISOP512 curve w/ SHA-512\n     */\n    ED512(-261),\n    /**\n     * ECDSA w/ SHA-256\n     */\n    ES256(-7),\n    /**\n     * ECDSA w/ SHA-384\n     */\n    ES384(-35),\n    /**\n     * ECDSA w/ SHA-512\n     */\n    ES512(-36);\n\n    private final int algoValue;\n\n    EC2Algorithm(int algoValue) {\n        this.algoValue = algoValue;\n    }\n\n    @Override\n    public int getAlgoValue() {\n        return algoValue;\n    }\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/ErrorCode.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Error codes that are referenced by WebAuthn spec.\n */\n@PublicApi\npublic enum ErrorCode implements Parcelable {\n    /**\n     * The operation is not supported.\n     */\n    NOT_SUPPORTED_ERR(9),\n    /**\n     * The object is in an invalid state.\n     */\n    INVALID_STATE_ERR(11),\n    /**\n     * The operation is insecure.\n     */\n    SECURITY_ERR(18),\n    /**\n     * A network error occurred.\n     */\n    NETWORK_ERR(19),\n    /**\n     * The operation was aborted.\n     */\n    ABORT_ERR(20),\n    /**\n     * The operation timed out.\n     */\n    TIMEOUT_ERR(23),\n    /**\n     * The encoding operation (either encoded or decoding) failed.\n     */\n    ENCODING_ERR(27),\n    /**\n     * The operation failed for an unknown transient reason.\n     */\n    UNKNOWN_ERR(28),\n    /**\n     * A mutation operation in a transaction failed because a constraint was not satisfied.\n     */\n    CONSTRAINT_ERR(29),\n    /**\n     * Provided data is inadequate.\n     */\n    DATA_ERR(30),\n    /**\n     * The request is not allowed by the user agent or the platform in the current context, possibly because the user\n     * denied permission.\n     */\n    NOT_ALLOWED_ERR(35),\n    /**\n     * The authenticator violates the privacy requirements of the {@code AttestationStatementType} it is using.\n     */\n    ATTESTATION_NOT_PRIVATE_ERR(36);\n\n    private int code;\n\n    ErrorCode(int code) {\n        this.code = code;\n    }\n\n    @Hide\n    public int getCode() {\n        return code;\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.writeInt(code);\n    }\n\n    @Hide\n    public static ErrorCode toErrorCode(int errorCode) throws UnsupportedErrorCodeException {\n        for (ErrorCode value : values()) {\n            if (value.code == errorCode) return value;\n        }\n        throw new UnsupportedErrorCodeException(errorCode);\n    }\n\n    /**\n     * Exception thrown when an unsupported or unrecognized error code is encountered.\n     */\n    public static class UnsupportedErrorCodeException extends Exception {\n        /**\n         * Constructor for the {@link ErrorCode.UnsupportedErrorCodeException}.\n         */\n        public UnsupportedErrorCodeException(int errorCode) {\n            super(\"Error code \" + errorCode + \" is not supported\");\n        }\n    }\n\n    @Hide\n    public static final Creator<ErrorCode> CREATOR = new Creator<ErrorCode>() {\n        @Override\n        public ErrorCode createFromParcel(Parcel source) {\n            try {\n                return ErrorCode.toErrorCode(source.readInt());\n            } catch (UnsupportedErrorCodeException e) {\n                throw new IllegalArgumentException(e);\n            }\n        }\n\n        @Override\n        public ErrorCode[] newArray(int size) {\n            return new ErrorCode[size];\n        }\n    };\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/FidoAppIdExtension.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.PublicApi;\n\nimport java.util.Arrays;\n\n/**\n * Extension for FIDO appId, to support U2F backward compatibility in FIDO2 assertion requests.\n * <p>\n * This authentication extension allows Relying Parties that have previously registered a credential using the legacy\n * FIDO U2F APIs to request an assertion. Specifically, this extension allows Relying Parties to specify an appId to\n * overwrite the computed rpId for U2F authenticators.\n * <p>\n * Note that this extension is only valid if used during the get() call; other usage should result in client error.\n */\n@PublicApi\n@SafeParcelable.Class\npublic class FidoAppIdExtension extends AbstractSafeParcelable {\n    @Field(value = 2, getterName = \"getAppId\")\n    @NonNull\n    private String appId;\n\n    private FidoAppIdExtension() {\n    }\n\n    @Constructor\n    public FidoAppIdExtension(@Param(2) @NonNull String appId) {\n        this.appId = appId;\n    }\n\n    @NonNull\n    public String getAppId() {\n        return appId;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof FidoAppIdExtension)) return false;\n\n        FidoAppIdExtension that = (FidoAppIdExtension) o;\n\n        return appId.equals(that.appId);\n    }\n\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(new Object[]{appId});\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<FidoAppIdExtension> CREATOR = findCreator(FidoAppIdExtension.class);\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/FidoCredentialDetails.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableSerializer;\n\nimport java.util.Objects;\n\n/**\n * Contains the attributes of a single FIDO credential that are returned to the caller in response to a\n * {@link Fido2PrivilegedApiClient#getCredentialList(String)} call.\n */\n@SafeParcelable.Class\npublic class FidoCredentialDetails extends AbstractSafeParcelable {\n    @Field(value = 1, getterName = \"getUserName\")\n    @Nullable\n    private String userName;\n    @Field(value = 2, getterName = \"getUserDisplayName\")\n    @Nullable\n    private String userDisplayName;\n    @Field(value = 3, getterName = \"getUserId\")\n    @Nullable\n    private byte[] userId;\n    @Field(value = 4, getterName = \"getCredentialId\")\n    @NonNull\n    private byte[] credentialId;\n    @Field(value = 5, getterName = \"getIsDiscoverable\")\n    private boolean discoverable;\n    @Field(value = 6, getterName = \"getIsPaymentCredential\")\n    private boolean paymentCredential;\n\n    private FidoCredentialDetails() {\n    }\n\n    @Constructor\n    FidoCredentialDetails(@Nullable @Param(1) String userName, @Nullable @Param(2) String userDisplayName, @Nullable @Param(3) byte[] userId, @NonNull @Param(4) byte[] credentialId, @Param(5) boolean discoverable, @Param(6) boolean paymentCredential) {\n        this.userName = userName;\n        this.userDisplayName = userDisplayName;\n        this.userId = userId;\n        this.credentialId = credentialId;\n        this.discoverable = discoverable;\n        this.paymentCredential = paymentCredential;\n    }\n\n    /**\n     * De-serializes the {@link FidoCredentialDetails} from bytes, reversing {@link #serializeToBytes()}.\n     *\n     * @return The deserialized {@link FidoCredentialDetails}.\n     */\n    @NonNull\n    public static FidoCredentialDetails deserializeFromBytes(@NonNull byte[] serializedBytes) {\n        return SafeParcelableSerializer.deserializeFromBytes(serializedBytes, CREATOR);\n    }\n\n    /**\n     * Returns the credential's credential ID.\n     */\n    @NonNull\n    public byte[] getCredentialId() {\n        return credentialId;\n    }\n\n    /**\n     * Returns true if the credential is discoverable.\n     */\n    public boolean getIsDiscoverable() {\n        return discoverable;\n    }\n\n    /**\n     * Returns true if the credential is for payments.\n     */\n    public boolean getIsPaymentCredential() {\n        return paymentCredential;\n    }\n\n    /**\n     * Returns the last used time in Unix Epoch Millis.\n     */\n    public long getLastUsedTime() {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Returns the credential's user display name.\n     */\n    @Nullable\n    public String getUserDisplayName() {\n        return userDisplayName;\n    }\n\n    /**\n     * Returns the credential's user ID.\n     */\n    @Nullable\n    public byte[] getUserId() {\n        return userId;\n    }\n\n    /**\n     * Returns the credential's user name.\n     */\n    @Nullable\n    public String getUserName() {\n        return this.userName;\n    }\n\n    public int hashCode() {\n        return Objects.hashCode(new Object[]{this.userName, this.userDisplayName, this.userId, this.credentialId, this.discoverable, this.paymentCredential});\n    }\n\n    /**\n     * Serializes the {@link FidoCredentialDetails} to bytes. Use {@link #deserializeFromBytes(byte[])} to deserialize.\n     *\n     * @return the serialized byte array.\n     */\n    @NonNull\n    public byte[] serializeToBytes() {\n        return SafeParcelableSerializer.serializeToBytes(this);\n    }\n\n    @Override\n    public void writeToParcel(Parcel out, int flags) {\n        CREATOR.writeToParcel(this, out, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<FidoCredentialDetails> CREATOR = findCreator(FidoCredentialDetails.class);\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/GoogleMultiAssertionExtension.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport org.microg.gms.common.PublicApi;\n\n@PublicApi\n@SafeParcelable.Class\npublic class GoogleMultiAssertionExtension extends AbstractSafeParcelable {\n    @Field(value = 1, getterName = \"isRequestForMultiAssertion\")\n    private final boolean requestForMultiAssertion;\n\n    @Constructor\n    public GoogleMultiAssertionExtension(@Param(1) boolean requestForMultiAssertion) {\n        this.requestForMultiAssertion = requestForMultiAssertion;\n    }\n\n    public boolean isRequestForMultiAssertion() {\n        return requestForMultiAssertion;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<GoogleMultiAssertionExtension> CREATOR = AbstractSafeParcelable.findCreator(GoogleMultiAssertionExtension.class);\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/GoogleSessionIdExtension.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.utils.ToStringHelper;\n\n@PublicApi\n@SafeParcelable.Class\npublic class GoogleSessionIdExtension extends AbstractSafeParcelable {\n    @Field(value = 1, getterName = \"getSessionId\")\n    private final long sessionId;\n\n    @Constructor\n    public GoogleSessionIdExtension(@Param(1) long sessionId) {\n        this.sessionId = sessionId;\n    }\n\n    public long getSessionId() {\n        return sessionId;\n    }\n\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"GoogleSessionIdExtension\").field(\"sessionId\", sessionId).end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<GoogleSessionIdExtension> CREATOR = AbstractSafeParcelable.findCreator(GoogleSessionIdExtension.class);\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/GoogleSilentVerificationExtension.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.utils.ToStringHelper;\n\n@PublicApi\n@SafeParcelable.Class\npublic class GoogleSilentVerificationExtension extends AbstractSafeParcelable {\n    @Field(value = 1, getterName = \"isSilentVerification\")\n    private final boolean silentVerification;\n\n    @Constructor\n    public GoogleSilentVerificationExtension(@Param(1) boolean silentVerification) {\n        this.silentVerification = silentVerification;\n    }\n\n    public boolean isSilentVerification() {\n        return silentVerification;\n    }\n\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"GoogleSilentVerificationExtension\").field(\"silentVerification\", silentVerification).end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<GoogleSilentVerificationExtension> CREATOR = AbstractSafeParcelable.findCreator(GoogleSilentVerificationExtension.class);\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/GoogleThirdPartyPaymentExtension.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.utils.ToStringHelper;\n\n@PublicApi\n@SafeParcelable.Class\npublic class GoogleThirdPartyPaymentExtension extends AbstractSafeParcelable {\n    @Field(value = 1, getterName = \"isThirdPartyPayment\")\n    private final boolean thirdPartyPayment;\n\n    @Constructor\n    public GoogleThirdPartyPaymentExtension(@Param(1) boolean thirdPartyPayment) {\n        this.thirdPartyPayment = thirdPartyPayment;\n    }\n\n    public boolean isThirdPartyPayment() {\n        return thirdPartyPayment;\n    }\n\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"GoogleThirdPartyPaymentExtension\").field(\"thirdPartyPayment\", thirdPartyPayment).end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<GoogleThirdPartyPaymentExtension> CREATOR = AbstractSafeParcelable.findCreator(GoogleThirdPartyPaymentExtension.class);\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/GoogleTunnelServerIdExtension.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.utils.ToStringHelper;\n\n@PublicApi\n@SafeParcelable.Class\npublic class GoogleTunnelServerIdExtension extends AbstractSafeParcelable {\n    @Field(value = 1, getterName = \"getTunnelServerId\")\n    @NonNull\n    private final String tunnelServerId;\n\n    @Constructor\n    public GoogleTunnelServerIdExtension(@Param(1) @NonNull String tunnelServerId) {\n        this.tunnelServerId = tunnelServerId;\n    }\n\n    @NonNull\n    public String getTunnelServerId() {\n        return tunnelServerId;\n    }\n\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"GoogleTunnelServerIdExtension\").field(\"tunnelServerId\", tunnelServerId).end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<GoogleTunnelServerIdExtension> CREATOR = AbstractSafeParcelable.findCreator(GoogleTunnelServerIdExtension.class);\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/HmacSecretExtension.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.utils.ToStringHelper;\n\n@PublicApi\n@SafeParcelable.Class\npublic class HmacSecretExtension extends AbstractSafeParcelable {\n\n    @Field(value = 1, getterName = \"getCoseKeyAgreement\")\n    private final byte[] coseKeyAgreement;\n\n    @Field(value = 2, getterName = \"getSaltEnc\")\n    private final byte[] saltEnc;\n\n    @Field(value = 3, getterName = \"getSaltAuth\")\n    private final byte[] saltAuth;\n\n    @Field(value = 4, getterName = \"getPinUvAuthProtocol\")\n    private final int pinUvAuthProtocol;\n\n    @Constructor\n    public HmacSecretExtension(@Param(1) byte[] coseKeyAgreement, @Param(2) byte[] saltEnc, @Param(3) byte[] saltAuth, @Param(4) int pinUvAuthProtocol) {\n        this.coseKeyAgreement = coseKeyAgreement;\n        this.saltEnc = saltEnc;\n        this.saltAuth = saltAuth;\n        this.pinUvAuthProtocol = pinUvAuthProtocol;\n    }\n\n    public byte[] getCoseKeyAgreement() {\n        return coseKeyAgreement;\n    }\n\n    public byte[] getSaltEnc() {\n        return saltEnc;\n    }\n\n    public byte[] getSaltAuth() {\n        return saltAuth;\n    }\n\n    public int getPinUvAuthProtocol() {\n        return pinUvAuthProtocol;\n    }\n\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"HmacSecretExtension\").field(\"coseKeyAgreement\", coseKeyAgreement == null ? \"\" : coseKeyAgreement.length).field(\"saltEnc\", saltEnc == null ? \"\" : saltEnc.length).field(\"saltAuth\", saltAuth == null ? \"\" : saltAuth.length).field(\"pinUvAuthProtocol\", pinUvAuthProtocol).end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<HmacSecretExtension> CREATOR = AbstractSafeParcelable.findCreator(HmacSecretExtension.class);\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/KeyProtectionTypes.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\n/**\n * The method used by the authenticator to protect the FIDO registration private key material. Available values are\n * defined in Section 3.2 Key Protection Types.\n */\npublic final class KeyProtectionTypes {\n    /**\n     * This flag must be set if the authenticator uses software-based key management. Exclusive in authenticator\n     * metadata with KEY_PROTECTION_HARDWARE, KEY_PROTECTION_TEE, KEY_PROTECTION_SECURE_ELEMENT.\n     */\n    public static final short KEY_PROTECTION_SOFTWARE = 1;\n    /**\n     * This flag should be set if the authenticator uses hardware-based key management. Exclusive in authenticator\n     * metadata with KEY_PROTECTION_SOFTWARE.\n     */\n    public static final short KEY_PROTECTION_HARDWARE = 2;\n    /**\n     * This flag should be set if the authenticator uses the Trusted Execution Environment for key management. In\n     * authenticator metadata, this flag should be set in conjunction with KEY_PROTECTION_HARDWARE. Mutually exclusive\n     * in authenticator metadata with KEY_PROTECTION_SOFTWARE, KEY_PROTECTION_SECURE_ELEMENT.\n     */\n    public static final short KEY_PROTECTION_TEE = 4;\n    /**\n     * This flag should be set if the authenticator uses a Secure Element for key management. In authenticator metadata,\n     * this flag should be set in conjunction with KEY_PROTECTION_HARDWARE. Mutually exclusive in authenticator metadata\n     * with KEY_PROTECTION_TEE, KEY_PROTECTION_SOFTWARE.\n     */\n    public static final short KEY_PROTECTION_SECURE_ELEMENT = 8;\n    /**\n     * This flag must be set if the authenticator does not store (wrapped) UAuth keys at the client, but relies on a\n     * server-provided key handle. This flag must be set in conjunction with one of the other KEY_PROTECTION flags to\n     * indicate how the local key handle wrapping key and operations are protected. Servers may unset this flag in\n     * authenticator policy if they are not prepared to store and return key handles, for example, if they have a\n     * requirement to respond indistinguishably to authentication attempts against userIDs that do and do not exist.\n     * Refer to for more details.\n     */\n    public static final short KEY_PROTECTION_REMOTE_HANDLE = 16;\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/MatcherProtectionTypes.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\n/**\n * The method used by the authenticator to protect the matcher that performs user verification. Available values are\n * defined in Section 3.3 Matcher Protection Types.\n */\npublic final class MatcherProtectionTypes {\n    /**\n     * This flag must be set if the authenticator's matcher is running in software. Exclusive in authenticator metadata\n     * with MATCHER_PROTECTION_TEE, MATCHER_PROTECTION_ON_CHIP.\n     */\n    public static final short MATCHER_PROTECTION_SOFTWARE = 1;\n    /**\n     * This flag should be set if the authenticator's matcher is running inside the Trusted Execution Environment.\n     * Mutually exclusive in authenticator metadata with MATCHER_PROTECTION_SOFTWARE, MATCHER_PROTECTION_ON_CHIP.\n     */\n    public static final short MATCHER_PROTECTION_TEE = 2;\n    /**\n     * This flag should be set if the authenticator's matcher is running on the chip. Mutually exclusive in\n     * authenticator metadata with MATCHER_PROTECTION_TEE, MATCHER_PROTECTION_SOFTWARE.\n     */\n    public static final short MATCHER_PROTECTION_ON_CHIP = 4;\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/PaymentExtension.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.utils.ToStringHelper;\n\n@PublicApi\n@SafeParcelable.Class\npublic class PaymentExtension extends AbstractSafeParcelable {\n    @Field(value = 1, getterName = \"isPayment\")\n    private final boolean payment;\n\n    @Constructor\n    public PaymentExtension(@Param(1) boolean payment) {\n        this.payment = payment;\n    }\n\n    public boolean isPayment() {\n        return payment;\n    }\n\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"PaymentExtension\").field(\"payment\", payment).end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<PaymentExtension> CREATOR = AbstractSafeParcelable.findCreator(PaymentExtension.class);\n}"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/PrfExtension.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport org.microg.gms.common.PublicApi;\n\n@PublicApi\n@SafeParcelable.Class\npublic class PrfExtension extends AbstractSafeParcelable {\n    @Field(value = 1, getterName = \"getEntries\")\n    private final byte[][] entries;\n\n    @Constructor\n    public PrfExtension(@Param(1) byte[][] entries) {\n        this.entries = entries;\n    }\n\n    @NonNull\n    public byte[][] getEntries() {\n        return entries;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<PrfExtension> CREATOR =\n            AbstractSafeParcelable.findCreator(PrfExtension.class);\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/PublicKeyCredential.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\nimport android.util.Base64;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableSerializer;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.Arrays;\nimport java.util.Objects;\n\n/**\n * This class is contains the attributes that are returned to the caller when a new credential is created, or a new\n * assertion is requested.\n */\n@PublicApi\n@SafeParcelable.Class\npublic class PublicKeyCredential extends AbstractSafeParcelable {\n    @Field(value = 1, getterName = \"getId\")\n    @NonNull\n    private String id;\n    @Field(value = 2, getterName = \"getType\")\n    @NonNull\n    private String type;\n    @Field(value = 3, getterName = \"getRawId\")\n    @NonNull\n    private byte[] rawId;\n    @Field(value = 4, getter = \"$object.getResponse() instanceof $type ? ($type) $object.getResponse() : null\")\n    @Nullable\n    private AuthenticatorAttestationResponse registerResponse;\n    @Field(value = 5, getter = \"$object.getResponse() instanceof $type ? ($type) $object.getResponse() : null\")\n    @Nullable\n    private AuthenticatorAssertionResponse signResponse;\n    @Field(value = 6, getter = \"$object.getResponse() instanceof $type ? ($type) $object.getResponse() : null\")\n    @Nullable\n    private AuthenticatorErrorResponse errorResponse;\n    @Field(value = 7, getterName = \"getClientExtensionResults\")\n    @Nullable\n    private AuthenticationExtensionsClientOutputs clientExtensionResults;\n    @Field(value = 8, getterName = \"getAuthenticatorAttachment\")\n    @Nullable\n    private String authenticatorAttachment;\n\n    PublicKeyCredential(@NonNull String id, @NonNull String type, @NonNull byte[] rawId, @NonNull AuthenticatorResponse response, @Nullable AuthenticationExtensionsClientOutputs clientExtensionResults, @Nullable String authenticatorAttachment) {\n        this(id, type, rawId, response instanceof AuthenticatorAttestationResponse ? (AuthenticatorAttestationResponse) response : null, response instanceof AuthenticatorAssertionResponse ? (AuthenticatorAssertionResponse) response : null, response instanceof AuthenticatorErrorResponse ? (AuthenticatorErrorResponse) response : null, clientExtensionResults, authenticatorAttachment);\n    }\n\n    @Constructor\n    PublicKeyCredential(@Param(1) @NonNull String id, @Param(2) @NonNull String type, @Param(3) @NonNull byte[] rawId, @Param(4) @Nullable AuthenticatorAttestationResponse registerResponse, @Param(5) @Nullable AuthenticatorAssertionResponse signResponse, @Param(6) @Nullable AuthenticatorErrorResponse errorResponse, @Param(7) @Nullable AuthenticationExtensionsClientOutputs clientExtensionResults, @Param(8) @Nullable String authenticatorAttachment) {\n        this.id = id;\n        this.type = type;\n        this.rawId = rawId;\n        this.registerResponse = registerResponse;\n        this.signResponse = signResponse;\n        this.errorResponse = errorResponse;\n        this.clientExtensionResults = clientExtensionResults;\n        this.authenticatorAttachment = authenticatorAttachment;\n    }\n\n    /**\n     * Returns the authenticator attachment of this credential.\n     */\n    @Nullable\n    public String getAuthenticatorAttachment() {\n        return authenticatorAttachment;\n    }\n\n    @Nullable\n    public AuthenticationExtensionsClientOutputs getClientExtensionResults() {\n        return clientExtensionResults;\n    }\n\n    @NonNull\n    public String getId() {\n        return id;\n    }\n\n    @NonNull\n    public byte[] getRawId() {\n        return rawId;\n    }\n\n    public AuthenticatorResponse getResponse() {\n        if (registerResponse != null) return registerResponse;\n        if (signResponse != null) return signResponse;\n        if (errorResponse != null) return errorResponse;\n        throw new IllegalStateException(\"No response set.\");\n    }\n\n    @NonNull\n    public String getType() {\n        return type;\n    }\n\n    /**\n     * Builder for {@link PublicKeyCredential}.\n     */\n    public static class Builder {\n        @NonNull\n        private String id;\n        @NonNull\n        private byte[] rawId;\n        private AuthenticatorResponse response;\n        @Nullable\n        private AuthenticationExtensionsClientOutputs extensionsClientOutputs;\n        @Nullable\n        private String authenticatorAttachment;\n\n        /**\n         * The constructor of {@link PublicKeyCredential.Builder}.\n         */\n        public Builder() {\n        }\n\n        /**\n         * Sets the output produced by the client's processing of the extensions requested by the relying party.\n         */\n        public Builder setAuthenticationExtensionsClientOutputs(@Nullable AuthenticationExtensionsClientOutputs extensionsClientOutputs) {\n            this.extensionsClientOutputs = extensionsClientOutputs;\n            return this;\n        }\n\n        /**\n         * Sets the authenticator attachment of the credential.\n         */\n        public Builder setAuthenticatorAttachment(@NonNull String authenticatorAttachment) {\n            this.authenticatorAttachment = authenticatorAttachment;\n            return this;\n        }\n\n        /**\n         * Sets the base64url encoding of the credential identifier.\n         */\n        public Builder setId(@NonNull String id) {\n            this.id = id;\n            return this;\n        }\n\n        /**\n         * Sets the raw value of the credential identifier.\n         */\n        public Builder setRawId(@NonNull byte[] rawId) {\n            this.rawId = rawId;\n            return this;\n        }\n\n        /**\n         * Sets the authenticator's response to the clients register or sign request.\n         * <p>\n         * This attribute contains the authenticator's response to the client’s request to either create a public key\n         * credential, or generate an authentication assertion. If the {@link PublicKeyCredential} is created in\n         * response a register request, this attribute’s value will be an {@link AuthenticatorAttestationResponse},\n         * otherwise, the {@link PublicKeyCredential} was created in response to a sign request, and this attribute’s\n         * value will be an {@link AuthenticatorAssertionResponse}.\n         */\n        public Builder setResponse(@NonNull AuthenticatorResponse response) {\n            this.response = response;\n            return this;\n        }\n\n        /**\n         * Builds the {@link PublicKeyCredential} object.\n         */\n        public PublicKeyCredential build() {\n            return new PublicKeyCredential(id, PublicKeyCredentialType.PUBLIC_KEY.toString(), rawId, response, extensionsClientOutputs, authenticatorAttachment);\n        }\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        String rawIdB64 = Base64.encodeToString(rawId, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING);\n        return ToStringHelper.name(\"PublicKeyCredential\")\n                .field(\"id\", id)\n                .field(\"type\", type)\n                .field(\"rawId\", rawIdB64)\n                .field(\"registerResponse\", registerResponse)\n                .field(\"signResponse\", signResponse)\n                .field(\"errorResponse\", errorResponse)\n                .field(\"clientExtensionResults\", clientExtensionResults)\n                .field(\"authenticatorAttachment\", authenticatorAttachment)\n                .end();\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof PublicKeyCredential)) return false;\n\n        PublicKeyCredential that = (PublicKeyCredential) o;\n\n        if (!Objects.equals(id, that.id)) return false;\n        if (!Objects.equals(type, that.type)) return false;\n        if (!Arrays.equals(rawId, that.rawId)) return false;\n        if (!Objects.equals(registerResponse, that.registerResponse)) return false;\n        if (!Objects.equals(signResponse, that.signResponse)) return false;\n        if (!Objects.equals(errorResponse, that.errorResponse)) return false;\n        if (!Objects.equals(clientExtensionResults, that.clientExtensionResults)) return false;\n        return Objects.equals(authenticatorAttachment, that.authenticatorAttachment);\n    }\n\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(new Object[]{id, type, rawId, signResponse, registerResponse, errorResponse, clientExtensionResults, authenticatorAttachment});\n    }\n\n    /**\n     * Serializes the {@link PublicKeyCredential} to bytes. Use {@link #deserializeFromBytes(byte[])} to deserialize.\n     *\n     * @return the serialized byte array.\n     */\n    @NonNull\n    public byte[] serializeToBytes() {\n        return SafeParcelableSerializer.serializeToBytes(this);\n    }\n\n    /**\n     * Deserializes the {@link PublicKeyCredential} from bytes, reversing {@link #serializeToBytes()}.\n     *\n     * @param serializedBytes The serialized bytes.\n     * @return The deserialized {@link PublicKeyCredential}.\n     */\n    @NonNull\n    public static PublicKeyCredential deserializeFromBytes(byte[] serializedBytes) {\n        return SafeParcelableSerializer.deserializeFromBytes(serializedBytes, CREATOR);\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    @Hide\n    public static final SafeParcelableCreatorAndWriter<PublicKeyCredential> CREATOR = findCreator(PublicKeyCredential.class);\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/PublicKeyCredentialCreationOptions.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableSerializer;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.Arrays;\nimport java.util.List;\n\n/**\n * This class is used to supply options when creating a new credential.\n */\n@PublicApi\n@SafeParcelable.Class\npublic class PublicKeyCredentialCreationOptions extends RequestOptions {\n    @Field(value = 2, getterName = \"getRp\")\n    @NonNull\n    private PublicKeyCredentialRpEntity rp;\n    @Field(value = 3, getterName = \"getUser\")\n    @NonNull\n    private PublicKeyCredentialUserEntity user;\n    @Field(value = 4, getterName = \"getChallenge\")\n    @NonNull\n    private byte[] challenge;\n    @Field(value = 5, getterName = \"getParameters\")\n    @NonNull\n    private List<PublicKeyCredentialParameters> parameters;\n    @Field(value = 6, getterName = \"getTimeoutSeconds\")\n    @Nullable\n    private Double timeoutSeconds;\n    @Field(value = 7, getterName = \"getExcludeList\")\n    @Nullable\n    private List<PublicKeyCredentialDescriptor> excludeList;\n    @Field(value = 8, getterName = \"getAuthenticatorSelection\")\n    @Nullable\n    private AuthenticatorSelectionCriteria authenticatorSelection;\n    @Field(value = 9, getterName = \"getRequestId\")\n    @Nullable\n    private Integer requestId;\n    @Field(value = 10, getterName = \"getTokenBinding\")\n    @Nullable\n    private TokenBinding tokenBinding;\n    @Field(value = 11, getterName = \"getAttestationConveyancePreference\")\n    @Nullable\n    private AttestationConveyancePreference attestationConveyancePreference;\n    @Field(value = 12, getterName = \"getAuthenticationExtensions\")\n    @Nullable\n    private AuthenticationExtensions authenticationExtensions;\n\n    @Constructor\n    PublicKeyCredentialCreationOptions(@Param(2) @NonNull PublicKeyCredentialRpEntity rp, @Param(3) @NonNull PublicKeyCredentialUserEntity user, @Param(4) @NonNull byte[] challenge, @Param(5) @NonNull List<PublicKeyCredentialParameters> parameters, @Param(6) @Nullable Double timeoutSeconds, @Param(7) @Nullable List<PublicKeyCredentialDescriptor> excludeList, @Param(8) @Nullable AuthenticatorSelectionCriteria authenticatorSelection, @Param(9) @Nullable Integer requestId, @Param(10) @Nullable TokenBinding tokenBinding, @Param(11) @Nullable AttestationConveyancePreference attestationConveyancePreference, @Param(12) @Nullable AuthenticationExtensions authenticationExtensions) {\n        this.rp = rp;\n        this.user = user;\n        this.challenge = challenge;\n        this.parameters = parameters;\n        this.timeoutSeconds = timeoutSeconds;\n        this.excludeList = excludeList;\n        this.authenticatorSelection = authenticatorSelection;\n        this.requestId = requestId;\n        this.tokenBinding = tokenBinding;\n        this.attestationConveyancePreference = attestationConveyancePreference;\n        this.authenticationExtensions = authenticationExtensions;\n    }\n\n    @Nullable\n    public AttestationConveyancePreference getAttestationConveyancePreference() {\n        return attestationConveyancePreference;\n    }\n\n    @Nullable\n    public String getAttestationConveyancePreferenceAsString() {\n        if (attestationConveyancePreference == null) return null;\n        return attestationConveyancePreference.toString();\n    }\n\n    @Nullable\n    @Override\n    public AuthenticationExtensions getAuthenticationExtensions() {\n        return authenticationExtensions;\n    }\n\n    @Nullable\n    public AuthenticatorSelectionCriteria getAuthenticatorSelection() {\n        return authenticatorSelection;\n    }\n\n    @NonNull\n    @Override\n    public byte[] getChallenge() {\n        return challenge;\n    }\n\n    @Nullable\n    public List<PublicKeyCredentialDescriptor> getExcludeList() {\n        return excludeList;\n    }\n\n    @NonNull\n    public List<PublicKeyCredentialParameters> getParameters() {\n        return parameters;\n    }\n\n    @Nullable\n    @Override\n    public Integer getRequestId() {\n        return requestId;\n    }\n\n    @NonNull\n    public PublicKeyCredentialRpEntity getRp() {\n        return rp;\n    }\n\n    @Nullable\n    @Override\n    public Double getTimeoutSeconds() {\n        return timeoutSeconds;\n    }\n\n    @Nullable\n    @Override\n    public TokenBinding getTokenBinding() {\n        return tokenBinding;\n    }\n\n    @NonNull\n    public PublicKeyCredentialUserEntity getUser() {\n        return user;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof PublicKeyCredentialCreationOptions)) return false;\n\n        PublicKeyCredentialCreationOptions that = (PublicKeyCredentialCreationOptions) o;\n\n        if (rp != null ? !rp.equals(that.rp) : that.rp != null) return false;\n        if (user != null ? !user.equals(that.user) : that.user != null) return false;\n        if (!Arrays.equals(challenge, that.challenge)) return false;\n        if (parameters != null ? !parameters.equals(that.parameters) : that.parameters != null) return false;\n        if (timeoutSeconds != null ? !timeoutSeconds.equals(that.timeoutSeconds) : that.timeoutSeconds != null)\n            return false;\n        if (excludeList != null ? !excludeList.equals(that.excludeList) : that.excludeList != null) return false;\n        if (authenticatorSelection != null ? !authenticatorSelection.equals(that.authenticatorSelection) : that.authenticatorSelection != null)\n            return false;\n        if (requestId != null ? !requestId.equals(that.requestId) : that.requestId != null) return false;\n        if (tokenBinding != null ? !tokenBinding.equals(that.tokenBinding) : that.tokenBinding != null) return false;\n        if (attestationConveyancePreference != that.attestationConveyancePreference) return false;\n        return authenticationExtensions != null ? authenticationExtensions.equals(that.authenticationExtensions) : that.authenticationExtensions == null;\n    }\n\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(new Object[]{rp, user, Arrays.hashCode(challenge), parameters, timeoutSeconds, excludeList, authenticatorSelection, requestId, tokenBinding, attestationConveyancePreference, authenticationExtensions});\n    }\n\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"PublicKeyCredentialCreationOptions\")\n                .field(\"rp\", rp)\n                .field(\"user\", user)\n                .field(\"challenge\", challenge)\n                .field(\"parameters\", parameters)\n                .field(\"timeoutSeconds\", timeoutSeconds)\n                .field(\"excludeList\", excludeList)\n                .field(\"authenticatorSelection\", authenticatorSelection)\n                .field(\"requestId\", requestId)\n                .field(\"tokenBinding\", tokenBinding)\n                .field(\"attestationConveyancePreference\", attestationConveyancePreference)\n                .field(\"authenticationExtensions\", authenticationExtensions)\n                .end();\n    }\n\n    /**\n     * Builder for {@link PublicKeyCredentialCreationOptions}.\n     */\n    public static class Builder {\n        @NonNull\n        private PublicKeyCredentialRpEntity rp;\n        @NonNull\n        private PublicKeyCredentialUserEntity user;\n        @NonNull\n        private byte[] challenge;\n        @NonNull\n        private List<PublicKeyCredentialParameters> parameters;\n        @Nullable\n        private Double timeoutSeconds;\n        @Nullable\n        private List<PublicKeyCredentialDescriptor> excludeList;\n        @Nullable\n        private AuthenticatorSelectionCriteria authenticatorSelection;\n        @Nullable\n        private Integer requestId;\n        @Nullable\n        private TokenBinding tokenBinding;\n        @Nullable\n        private AttestationConveyancePreference attestationConveyancePreference;\n        @Nullable\n        private AuthenticationExtensions authenticationExtensions;\n\n        /**\n         * The constructor of {@link PublicKeyCredentialCreationOptions.Builder}.\n         */\n        public Builder() {\n        }\n\n        /**\n         * Sets the preference for obfuscation level of the returned attestation data.\n         */\n        public Builder setAttestationConveyancePreference(@Nullable AttestationConveyancePreference attestationConveyancePreference) {\n            this.attestationConveyancePreference = attestationConveyancePreference;\n            return this;\n        }\n\n        /**\n         * Sets additional extensions that may dictate some client behavior during an exchange with a connected\n         * authenticator.\n         */\n        public Builder setAuthenticationExtensions(@Nullable AuthenticationExtensions authenticationExtensions) {\n            this.authenticationExtensions = authenticationExtensions;\n            return this;\n        }\n\n        /**\n         * Sets constraints on the type of authenticator that is acceptable for this session.\n         */\n        public Builder setAuthenticatorSelection(@Nullable AuthenticatorSelectionCriteria authenticatorSelection) {\n            this.authenticatorSelection = authenticatorSelection;\n            return this;\n        }\n\n        /**\n         * Sets the challenge to sign when generating the attestation for this request.\n         */\n        public Builder setChallenge(@NonNull byte[] challenge) {\n            this.challenge = challenge;\n            return this;\n        }\n\n        /**\n         * Sets a list of credentials that, if found on a connected authenticator, will preclude registration of that\n         * authenticator with the relying party. This is often set to prevent re-registration of authenticators that\n         * the relying party has already registered on behalf of the user.\n         */\n        public Builder setExcludeList(@Nullable List<PublicKeyCredentialDescriptor> excludeList) {\n            this.excludeList = excludeList;\n            return this;\n        }\n\n        /**\n         * Sets the {@link PublicKeyCredentialParameters} that constrain the type of credential to generate.\n         */\n        public Builder setParameters(@NonNull List<PublicKeyCredentialParameters> parameters) {\n            this.parameters = parameters;\n            return this;\n        }\n\n        /**\n         * Sets the request id in order to link together events into a single session (the span of events between the\n         * time that the server initiates a single FIDO2 request to the client and receives reply) on a single device.\n         */\n        public Builder setRequestId(@Nullable Integer requestId) {\n            this.requestId = requestId;\n            return this;\n        }\n\n        /**\n         * Sets information for a relying party, on whose behalf a given registration operation is being performed.\n         * <p>\n         * Note: the RpId should be an effective domain (aka, without scheme or port); and it should also be in secure\n         * context (aka https connection). Apps-facing API needs to check the package signature against Digital Asset\n         * Links, whose resource is the RP ID with prepended \"//\". Privileged (browser) API doesn't need the check.\n         */\n        public Builder setRp(@NonNull PublicKeyCredentialRpEntity rp) {\n            this.rp = rp;\n            return this;\n        }\n\n        /**\n         * Sets a timeout that limits the duration of the registration session provided to the user.\n         */\n        public Builder setTimeoutSeconds(@Nullable Double timeoutSeconds) {\n            this.timeoutSeconds = timeoutSeconds;\n            return this;\n        }\n\n        /**\n         * Sets the {@link TokenBinding} associated with the calling origin.\n         */\n        public Builder setTokenBinding(@Nullable TokenBinding tokenBinding) {\n            this.tokenBinding = tokenBinding;\n            return this;\n        }\n\n        /**\n         * Sets information about the user on whose behalf the relying party is registering a credential.\n         */\n        public Builder setUser(@NonNull PublicKeyCredentialUserEntity user) {\n            this.user = user;\n            return this;\n        }\n\n        /**\n         * Builds the {@link PublicKeyCredentialCreationOptions} object.\n         */\n        public PublicKeyCredentialCreationOptions build() {\n            return new PublicKeyCredentialCreationOptions(rp, user, challenge, parameters, timeoutSeconds, excludeList, authenticatorSelection, requestId, tokenBinding, attestationConveyancePreference, authenticationExtensions);\n        }\n    }\n\n    /**\n     * Deserializes the {@link PublicKeyCredentialCreationOptions} from bytes, reversing {@link #serializeToBytes()}.\n     *\n     * @param serializedBytes The serialized bytes.\n     * @return The deserialized {@link PublicKeyCredentialCreationOptions}.\n     */\n    @NonNull\n    public static PublicKeyCredentialCreationOptions deserializeFromBytes(byte[] serializedBytes) {\n        return SafeParcelableSerializer.deserializeFromBytes(serializedBytes, CREATOR);\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    @Hide\n    public static final SafeParcelableCreatorAndWriter<PublicKeyCredentialCreationOptions> CREATOR = findCreator(PublicKeyCredentialCreationOptions.class);\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/PublicKeyCredentialDescriptor.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.fido.common.Transport;\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.Arrays;\nimport java.util.List;\n\n/**\n * This class contains the attributes that are specified by a caller when referring to a credential as an input\n * parameter to the registration or authentication method.\n */\n@PublicApi\n@SafeParcelable.Class\npublic class PublicKeyCredentialDescriptor extends AbstractSafeParcelable {\n    @Field(value = 2, getterName = \"getType\")\n    @NonNull\n    private PublicKeyCredentialType type;\n    @Field(value = 3, getterName = \"getId\")\n    @NonNull\n    private byte[] id;\n    @Field(value = 4, getterName = \"getTransports\")\n    @Nullable\n    private List<Transport> transports;\n\n    private PublicKeyCredentialDescriptor() {\n    }\n\n    public PublicKeyCredentialDescriptor(@NonNull String type, @NonNull byte[] id, @Nullable List<Transport> transports) {\n        try {\n            this.type = PublicKeyCredentialType.fromString(type);\n        } catch (PublicKeyCredentialType.UnsupportedPublicKeyCredTypeException e) {\n            throw new IllegalArgumentException(e);\n        }\n        this.id = id;\n        this.transports = transports;\n    }\n\n    @Constructor\n    PublicKeyCredentialDescriptor(@Param(2) @NonNull PublicKeyCredentialType type, @Param(3) @NonNull byte[] id, @Param(4) @Nullable List<Transport> transports) {\n        this.type = type;\n        this.id = id;\n        this.transports = transports;\n    }\n\n    @NonNull\n    public byte[] getId() {\n        return id;\n    }\n\n    @Nullable\n    public List<Transport> getTransports() {\n        return transports;\n    }\n\n    @NonNull\n    public PublicKeyCredentialType getType() {\n        return type;\n    }\n\n    @NonNull\n    public String getTypeAsString() {\n        return type.toString();\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof PublicKeyCredentialDescriptor)) return false;\n\n        PublicKeyCredentialDescriptor that = (PublicKeyCredentialDescriptor) o;\n\n        if (type != that.type) return false;\n        if (!Arrays.equals(id, that.id)) return false;\n        return transports != null ? transports.equals(that.transports) : that.transports == null;\n    }\n\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(new Object[]{type, Arrays.hashCode(id), transports});\n    }\n\n    @Override\n    @NonNull\n    public String toString() {\n        return ToStringHelper.name(\"PublicKeyCredentialDescriptor\")\n                .value(id)\n                .field(\"type\", type)\n                .field(\"transports\", transports)\n                .end();\n    }\n\n    /**\n     * Exception thrown when an unsupported or unrecognized public key credential descriptor is encountered.\n     */\n    public static class UnsupportedPubKeyCredDescriptorException extends Exception {\n        public UnsupportedPubKeyCredDescriptorException(String message) {\n            super(message);\n        }\n\n        public UnsupportedPubKeyCredDescriptorException(String message, Throwable cause) {\n            super(message, cause);\n        }\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<PublicKeyCredentialDescriptor> CREATOR = findCreator(PublicKeyCredentialDescriptor.class);\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/PublicKeyCredentialParameters.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.Arrays;\n\n/**\n * This class supplies additional parameters when creating a new credential.\n */\n@PublicApi\n@SafeParcelable.Class\npublic class PublicKeyCredentialParameters extends AbstractSafeParcelable {\n    @Field(value = 2, getterName = \"getType\")\n    @NonNull\n    private PublicKeyCredentialType type;\n    @Field(value = 3, getterName = \"getAlgorithm\")\n    @NonNull\n    private COSEAlgorithmIdentifier algorithm;\n\n    private PublicKeyCredentialParameters() {\n    }\n\n    public PublicKeyCredentialParameters(@NonNull String type, int algorithm) {\n        try {\n            this.type = PublicKeyCredentialType.fromString(type);\n        } catch (PublicKeyCredentialType.UnsupportedPublicKeyCredTypeException e) {\n            throw new IllegalArgumentException(e);\n        }\n        try {\n            this.algorithm = COSEAlgorithmIdentifier.fromCoseValue(algorithm);\n        } catch (COSEAlgorithmIdentifier.UnsupportedAlgorithmIdentifierException e) {\n            throw new IllegalArgumentException(e);\n        }\n    }\n\n    @Constructor\n    PublicKeyCredentialParameters(@Param(2) @NonNull PublicKeyCredentialType type, @Param(3) @NonNull COSEAlgorithmIdentifier algorithm) {\n        this.type = type;\n        this.algorithm = algorithm;\n    }\n\n    @NonNull\n    public COSEAlgorithmIdentifier getAlgorithm() {\n        return algorithm;\n    }\n\n    public int getAlgorithmIdAsInteger() {\n        return algorithm.toCoseValue();\n    }\n\n    @NonNull\n    public PublicKeyCredentialType getType() {\n        return type;\n    }\n\n    @NonNull\n    public String getTypeAsString() {\n        return type.toString();\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof PublicKeyCredentialParameters)) return false;\n\n        PublicKeyCredentialParameters that = (PublicKeyCredentialParameters) o;\n\n        if (type != that.type) return false;\n        return algorithm != null ? algorithm.equals(that.algorithm) : that.algorithm == null;\n    }\n\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(new Object[]{type, algorithm});\n    }\n\n    @Override\n    @NonNull\n    public String toString() {\n        return ToStringHelper.name(\"PublicKeyCredentialParameters\")\n                .field(\"type\", type)\n                .field(\"algorithm\", algorithm)\n                .end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    @Hide\n    public static final SafeParcelableCreatorAndWriter<PublicKeyCredentialParameters> CREATOR = findCreator(PublicKeyCredentialParameters.class);\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/PublicKeyCredentialRequestOptions.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableSerializer;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.Arrays;\nimport java.util.List;\n\n/**\n * This class is used to supply an authentication request with the data it needs to generate an assertion.\n */\n@PublicApi\n@SafeParcelable.Class\npublic class PublicKeyCredentialRequestOptions extends RequestOptions {\n    @Field(value = 2, getterName = \"getChallenge\")\n    @NonNull\n    private byte[] challenge;\n    @Field(value = 3, getterName = \"getTimeoutSeconds\")\n    @Nullable\n    private Double timeoutSeconds;\n    @Field(value = 4, getterName = \"getRpId\")\n    @NonNull\n    private String rpId;\n    @Field(value = 5, getterName = \"getAllowList\")\n    @Nullable\n    private List<PublicKeyCredentialDescriptor> allowList;\n    @Field(value = 6, getterName = \"getRequestId\")\n    @Nullable\n    private Integer requestId;\n    @Field(value = 7, getterName = \"getTokenBinding\")\n    @Nullable\n    private TokenBinding tokenBinding;\n    @Field(value = 8, getterName = \"getRequireUserVerification\")\n    @Nullable\n    private UserVerificationRequirement requireUserVerification;\n    @Field(value = 9, getterName = \"getAuthenticationExtensions\")\n    @Nullable\n    private AuthenticationExtensions authenticationExtensions;\n    @Field(10)\n    @Nullable\n    Long longRequestId;\n\n    @Constructor\n    public PublicKeyCredentialRequestOptions(@Param(2)@NonNull byte[] challenge,@Param(3) @Nullable Double timeoutSeconds, @Param(4)@NonNull String rpId, @Param(5)@Nullable List<PublicKeyCredentialDescriptor> allowList,@Param(6) @Nullable Integer requestId,@Param(7) @Nullable TokenBinding tokenBinding,@Param(8) @Nullable UserVerificationRequirement requireUserVerification, @Param(9)@Nullable AuthenticationExtensions authenticationExtensions) {\n        this.challenge = challenge;\n        this.timeoutSeconds = timeoutSeconds;\n        this.rpId = rpId;\n        this.allowList = allowList;\n        this.requestId = requestId;\n        this.tokenBinding = tokenBinding;\n        this.requireUserVerification = requireUserVerification;\n        this.authenticationExtensions = authenticationExtensions;\n    }\n\n    @Nullable\n    public List<PublicKeyCredentialDescriptor> getAllowList() {\n        return allowList;\n    }\n\n    @Override\n    @Nullable\n    public AuthenticationExtensions getAuthenticationExtensions() {\n        return authenticationExtensions;\n    }\n\n    @Hide\n    @Nullable\n    public UserVerificationRequirement getRequireUserVerification() {\n        return requireUserVerification;\n    }\n\n    @Override\n    @NonNull\n    public byte[] getChallenge() {\n        return challenge;\n    }\n\n    @Override\n    @Nullable\n    public Integer getRequestId() {\n        return requestId;\n    }\n\n    @NonNull\n    public String getRpId() {\n        return rpId;\n    }\n\n    @Override\n    @Nullable\n    public Double getTimeoutSeconds() {\n        return timeoutSeconds;\n    }\n\n    @Override\n    @Nullable\n    public TokenBinding getTokenBinding() {\n        return tokenBinding;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof PublicKeyCredentialRequestOptions)) return false;\n\n        PublicKeyCredentialRequestOptions that = (PublicKeyCredentialRequestOptions) o;\n\n        if (!Arrays.equals(challenge, that.challenge)) return false;\n        if (timeoutSeconds != null ? !timeoutSeconds.equals(that.timeoutSeconds) : that.timeoutSeconds != null)\n            return false;\n        if (rpId != null ? !rpId.equals(that.rpId) : that.rpId != null) return false;\n        if (allowList != null ? !allowList.equals(that.allowList) : that.allowList != null) return false;\n        if (requestId != null ? !requestId.equals(that.requestId) : that.requestId != null) return false;\n        if (tokenBinding != null ? !tokenBinding.equals(that.tokenBinding) : that.tokenBinding != null) return false;\n        if (requireUserVerification != that.requireUserVerification) return false;\n        return authenticationExtensions != null ? authenticationExtensions.equals(that.authenticationExtensions) : that.authenticationExtensions == null;\n    }\n\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(new Object[]{Arrays.hashCode(challenge), timeoutSeconds, rpId, allowList, requestId, tokenBinding, requireUserVerification, authenticationExtensions});\n    }\n\n    @Override\n    @NonNull\n    public String toString() {\n        return ToStringHelper.name(\"PublicKeyCredentialRequestOptions\")\n                .field(\"challenge\", challenge)\n                .field(\"timeoutSeconds\", timeoutSeconds)\n                .field(\"rpId\", rpId)\n                .field(\"allowList\", allowList)\n                .field(\"requestId\", requestId)\n                .field(\"tokenBinding\", tokenBinding)\n                .field(\"userVerificationRequirement\", requireUserVerification)\n                .field(\"authenticationExtensions\", authenticationExtensions)\n                .end();\n    }\n\n    /**\n     * Builder for {@link PublicKeyCredentialRequestOptions}.\n     */\n    public static class Builder {\n        @NonNull\n        private byte[] challenge;\n        @Nullable\n        private Double timeoutSeconds;\n        @NonNull\n        private String rpId;\n        @Nullable\n        private List<PublicKeyCredentialDescriptor> allowList;\n        @Nullable\n        private Integer requestId;\n        @Nullable\n        private TokenBinding tokenBinding;\n        @Nullable\n        private AuthenticationExtensions authenticationExtensions;\n        @Nullable\n        private UserVerificationRequirement requireUserVerification;\n\n        /**\n         * The constructor of {@link PublicKeyCredentialRequestOptions.Builder}.\n         */\n        public Builder() {\n        }\n\n        /**\n         * Sets a list of public key credentials which constrain authentication to authenticators that contain a\n         * private key for at least one of the supplied public keys.\n         */\n        @NonNull\n        public Builder setAllowList(@Nullable List<PublicKeyCredentialDescriptor> allowList) {\n            this.allowList = allowList;\n            return this;\n        }\n\n        /**\n         * Sets additional extensions that may dictate some client behavior during an exchange with a connected\n         * authenticator.\n         */\n        @NonNull\n        public Builder setAuthenticationExtensions(@Nullable AuthenticationExtensions authenticationExtensions) {\n            this.authenticationExtensions = authenticationExtensions;\n            return this;\n        }\n\n        /**\n         * Sets the nonce value that the authenticator should sign using a private key corresponding to a public key\n         * credential that is acceptable for this authentication session.\n         */\n        @NonNull\n        public Builder setChallenge(@NonNull byte[] challenge) {\n            this.challenge = challenge;\n            return this;\n        }\n\n        /**\n         * Sets the request id in order to link together events into a single session (the span of events between the\n         * time that the server initiates a single FIDO2 request to the client and receives reply) on a single device.\n         * This field is optional.\n         */\n        @NonNull\n        public Builder setRequestId(@Nullable Integer requestId) {\n            this.requestId = requestId;\n            return this;\n        }\n\n        @Hide\n        @NonNull\n        public Builder setRequireUserVerification(@Nullable UserVerificationRequirement requireUserVerification) {\n            this.requireUserVerification = requireUserVerification;\n            return this;\n        }\n\n        /**\n         * Sets identifier for a relying party, on whose behalf a given authentication operation is being performed.\n         * A public key credential can only be used for authentication with the same replying party it was registered\n         * with.\n         * <p>\n         * Note: the RpId should be an effective domain (aka, without scheme or port); and it should also be in secure\n         * context (aka https connection). Apps-facing API needs to check the package signature against Digital Asset\n         * Links, whose resource is the RP ID with prepended \"//\". Privileged (browser) API doesn't need the check.\n         */\n        @NonNull\n        public Builder setRpId(@NonNull String rpId) {\n            this.rpId = rpId;\n            return this;\n        }\n\n        @NonNull\n        public Builder setTimeoutSeconds(@Nullable Double timeoutSeconds) {\n            this.timeoutSeconds = timeoutSeconds;\n            return this;\n        }\n\n        /**\n         * Sets the {@link TokenBinding} associated with the calling origin.\n         */\n        @NonNull\n        public Builder setTokenBinding(@Nullable TokenBinding tokenBinding) {\n            this.tokenBinding = tokenBinding;\n            return this;\n        }\n\n        /**\n         * Builds the {@link PublicKeyCredentialRequestOptions} object.\n         */\n        @NonNull\n        public PublicKeyCredentialRequestOptions build() {\n            return new PublicKeyCredentialRequestOptions(challenge, timeoutSeconds, rpId, allowList, requestId, tokenBinding, requireUserVerification, authenticationExtensions);\n        }\n    }\n\n    /**\n     * Deserializes the {@link PublicKeyCredentialRequestOptions} from bytes, reversing {@link #serializeToBytes()}.\n     *\n     * @param serializedBytes The serialized bytes.\n     * @return The deserialized {@link PublicKeyCredentialRequestOptions}.\n     */\n    @NonNull\n    public static PublicKeyCredentialRequestOptions deserializeFromBytes(byte[] serializedBytes) {\n        return SafeParcelableSerializer.deserializeFromBytes(serializedBytes, CREATOR);\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    @Hide\n    public static final SafeParcelableCreatorAndWriter<PublicKeyCredentialRequestOptions> CREATOR = findCreator(PublicKeyCredentialRequestOptions.class);\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/PublicKeyCredentialRpEntity.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.Arrays;\n\n/**\n * Represents the information about a relying party with which a credential is associated.\n */\n@PublicApi\n@SafeParcelable.Class\npublic class PublicKeyCredentialRpEntity extends AbstractSafeParcelable {\n    @Field(value = 2, getterName = \"getId\")\n    @NonNull\n    private String id;\n    @Field(value = 3, getterName = \"getName\")\n    @NonNull\n    private String name;\n    @Field(value = 4, getterName = \"getIcon\")\n    @Nullable\n    private String icon;\n\n    private PublicKeyCredentialRpEntity() {\n    }\n\n    @Constructor\n    public PublicKeyCredentialRpEntity(@Param(2)@NonNull String id, @Param(3)@NonNull String name, @Param(4)@Nullable String icon) {\n        this.id = id;\n        this.name = name;\n        this.icon = icon;\n    }\n\n    @Nullable\n    public String getIcon() {\n        return icon;\n    }\n\n    @NonNull\n    public String getId() {\n        return id;\n    }\n\n    @NonNull\n    public String getName() {\n        return name;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof PublicKeyCredentialRpEntity)) return false;\n\n        PublicKeyCredentialRpEntity that = (PublicKeyCredentialRpEntity) o;\n\n        if (id != null ? !id.equals(that.id) : that.id != null) return false;\n        if (name != null ? !name.equals(that.name) : that.name != null) return false;\n        return icon != null ? icon.equals(that.icon) : that.icon == null;\n    }\n\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(new Object[]{id, name, icon});\n    }\n\n    @Override\n    @NonNull\n    public String toString() {\n        return ToStringHelper.name(\"PublicKeyCredentialRpEntity\")\n                .value(id)\n                .field(\"name\", name)\n                .field(\"icon\", icon)\n                .end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    @Hide\n    public static final SafeParcelableCreatorAndWriter<PublicKeyCredentialRpEntity> CREATOR = findCreator(PublicKeyCredentialRpEntity.class);\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/PublicKeyCredentialType.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport androidx.annotation.NonNull;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.common.PublicApi;\n\n/**\n * This enumeration defines the valid credential types.\n */\npublic enum PublicKeyCredentialType implements Parcelable {\n    PUBLIC_KEY(\"public-key\");\n\n    private final String value;\n\n    PublicKeyCredentialType(String value) {\n        this.value = value;\n    }\n\n    @Override\n    @NonNull\n    public String toString() {\n        return value;\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(toString());\n    }\n\n    @Hide\n    public static PublicKeyCredentialType fromString(String type) throws UnsupportedPublicKeyCredTypeException {\n        for (PublicKeyCredentialType value : values()) {\n            if (value.value.equals(type)) return value;\n        }\n        throw new UnsupportedPublicKeyCredTypeException(\"PublicKeyCredentialType \" + type + \" not supported\");\n    }\n\n    public static Creator<PublicKeyCredentialType> CREATOR = new Creator<PublicKeyCredentialType>() {\n        @Override\n        public PublicKeyCredentialType createFromParcel(Parcel source) {\n            try {\n                return PublicKeyCredentialType.fromString(source.readString());\n            } catch (UnsupportedPublicKeyCredTypeException e) {\n                throw new RuntimeException(e);\n            }\n        }\n\n        @Override\n        public PublicKeyCredentialType[] newArray(int size) {\n            return new PublicKeyCredentialType[size];\n        }\n    };\n\n    /**\n     * Exception thrown when an unsupported or unrecognized transport is encountered.\n     */\n    public static class UnsupportedPublicKeyCredTypeException extends Exception {\n        public UnsupportedPublicKeyCredTypeException(String message) {\n            super(message);\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/PublicKeyCredentialUserEntity.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\nimport android.util.Base64;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.Arrays;\n\n/**\n * This class is used to supply additional parameters about the user account when creating a new Credential.\n */\n@PublicApi\n@SafeParcelable.Class\npublic class PublicKeyCredentialUserEntity extends AbstractSafeParcelable {\n    @Field(value = 2, getterName = \"getId\")\n    @NonNull\n    private byte[] id;\n    @Field(value = 3, getterName = \"getName\")\n    @NonNull\n    private String name;\n    @Field(value = 4, getterName = \"getIcon\")\n    @Nullable\n    private String icon;\n    @Field(value = 5, getterName = \"getDisplayName\")\n    @NonNull\n    private String displayName;\n\n    private PublicKeyCredentialUserEntity() {\n    }\n\n    public String toJson() throws JSONException {\n        JSONObject jsonObject = new JSONObject();\n        jsonObject.put(\"id\", Base64.encodeToString(id, Base64.NO_WRAP | Base64.URL_SAFE | Base64.NO_PADDING));\n        jsonObject.put(\"name\", name);\n        jsonObject.put(\"icon\", icon);\n        jsonObject.put(\"displayName\", displayName);\n        return jsonObject.toString();\n    }\n\n    public static PublicKeyCredentialUserEntity parseJson(String json) throws JSONException {\n        JSONObject jsonObject = new JSONObject(json);\n        byte[] id = Base64.decode(jsonObject.getString(\"id\"), Base64.NO_WRAP | Base64.URL_SAFE | Base64.NO_PADDING);\n        String name = jsonObject.optString(\"name\");\n        String icon = jsonObject.optString(\"icon\");\n        String displayName = jsonObject.optString(\"displayName\");\n        return new PublicKeyCredentialUserEntity(id, name, icon, displayName);\n    }\n\n    @Constructor\n    public PublicKeyCredentialUserEntity(@Param(2) @NonNull byte[] id, @Param(3) @NonNull String name, @Param(4) @Nullable String icon, @Param(5) @NonNull String displayName) {\n        this.id = id;\n        this.name = name;\n        this.icon = icon;\n        this.displayName = displayName;\n    }\n\n    @NonNull\n    public String getDisplayName() {\n        return displayName;\n    }\n\n    @Nullable\n    public String getIcon() {\n        return icon;\n    }\n\n    @NonNull\n    public byte[] getId() {\n        return id;\n    }\n\n    @NonNull\n    public String getName() {\n        return name;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof PublicKeyCredentialUserEntity)) return false;\n\n        PublicKeyCredentialUserEntity that = (PublicKeyCredentialUserEntity) o;\n\n        if (!Arrays.equals(id, that.id)) return false;\n        if (name != null ? !name.equals(that.name) : that.name != null) return false;\n        if (icon != null ? !icon.equals(that.icon) : that.icon != null) return false;\n        return displayName != null ? displayName.equals(that.displayName) : that.displayName == null;\n    }\n\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(new Object[]{id, name, icon, displayName});\n    }\n\n    @Override\n    @NonNull\n    public String toString() {\n        return ToStringHelper.name(\"PublicKeyCredentialUserEntity\")\n                .value(id)\n                .field(\"name\", name)\n                .field(\"icon\", icon)\n                .field(\"displayName\", displayName)\n                .end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    @Hide\n    public static final SafeParcelableCreatorAndWriter<PublicKeyCredentialUserEntity> CREATOR = findCreator(PublicKeyCredentialUserEntity.class);\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/RSAAlgorithm.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Algorithm names and COSE identifiers for RSA (public) keys.\n */\n@PublicApi\npublic enum RSAAlgorithm implements Algorithm {\n    /**\n     * RSASSA-PKCS1-v1_5 w/ SHA-256\n     */\n    RS256(-257),\n    /**\n     * RSASSA-PKCS1-v1_5 w/ SHA-384\n     */\n    RS384(-258),\n    /**\n     * RSASSA-PKCS1-v1_5 w/ SHA-512\n     */\n    RS512(-259),\n    /**\n     * The legacy value for \"RSASSA-PKCS1-v1_5 w/ SHA-1\"\n     *\n     * @deprecated please use {@link #RS1} instead.\n     */\n    @Deprecated\n    LEGACY_RS1(-262),\n    /**\n     * RSASSA-PSS w/ SHA-256\n     */\n    PS256(-37),\n    /**\n     * RSASSA-PSS w/ SHA-384\n     */\n    PS384(-38),\n    /**\n     * RSASSA-PSS w/ SHA-512\n     */\n    PS512(-39),\n    /**\n     * RSASSA-PKCS1-v1_5 w/ SHA-1\n     */\n    RS1(-65535);\n\n    private final int algoValue;\n\n    RSAAlgorithm(int algoValue) {\n        this.algoValue = algoValue;\n    }\n\n    @Override\n    public int getAlgoValue() {\n        return algoValue;\n    }\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/RequestOptions.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableSerializer;\nimport org.microg.gms.common.PublicApi;\n\n/**\n * An abstract class representing FIDO2 request options.\n */\n@PublicApi\npublic abstract class RequestOptions extends AbstractSafeParcelable {\n    @NonNull\n    public abstract byte[] getChallenge();\n    @Nullable\n    public abstract Double getTimeoutSeconds();\n    @Nullable\n    public abstract Integer getRequestId();\n    @Nullable\n    public abstract TokenBinding getTokenBinding();\n    @Nullable\n    public abstract AuthenticationExtensions getAuthenticationExtensions();\n\n    /**\n     * Serializes the {@link RequestOptions} to bytes. Use deserializeFromBytes(byte[]) to deserialize.\n     */\n    @NonNull\n    public byte[] serializeToBytes() {\n        return SafeParcelableSerializer.serializeToBytes(this);\n    }\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/ResidentKeyRequirement.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport androidx.annotation.NonNull;\n\n/**\n * An enum that describes the Resident Key (Discoverable Credential) requirements.\n * <p>\n * According to WebAuthn, this structure describes the Relying Party's requirements for client-side discoverable credentials\n * (formerly known as resident credentials or resident keys):\n * <p>\n * If the resident key requirement is set to \"required\", then the Relying Party requires a client-side discoverable credential\n * and is prepared to receive an error if it can't be created. If the resident key requirement is set to \"preferred\", the Relying\n * party strongly prefers a client-side discoverable credential but will accept a server-side credential. If the resident key\n * requirement is set to \"discouraged\" then a server-side credential is preferable, but will accept a client-side discoverable\n * credential.\n */\npublic enum ResidentKeyRequirement implements Parcelable {\n    RESIDENT_KEY_DISCOURAGED(\"discouraged\"),\n    RESIDENT_KEY_PREFERRED(\"preferred\"),\n    RESIDENT_KEY_REQUIRED(\"required\");\n\n    private final String requirement;\n\n    ResidentKeyRequirement(String requirement) {\n        this.requirement = requirement;\n    }\n\n    @NonNull\n    public static ResidentKeyRequirement fromString(@NonNull String requirement) throws UnsupportedResidentKeyRequirementException {\n        for (ResidentKeyRequirement value : values()) {\n            if (requirement.equals(value.requirement)) return value;\n        }\n        throw new UnsupportedResidentKeyRequirementException(requirement);\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return requirement;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        dest.writeString(requirement);\n    }\n\n    public static Creator<ResidentKeyRequirement> CREATOR = new Creator<ResidentKeyRequirement>() {\n        @Override\n        public ResidentKeyRequirement createFromParcel(Parcel source) {\n            try {\n                return ResidentKeyRequirement.fromString(source.readString());\n            } catch (UnsupportedResidentKeyRequirementException e) {\n                throw new RuntimeException(e);\n            }\n        }\n\n        @Override\n        public ResidentKeyRequirement[] newArray(int size) {\n            return new ResidentKeyRequirement[size];\n        }\n    };\n\n    /**\n     * Exception thrown when an unsupported or unrecognized resident key requirement is encountered.\n     */\n    public static class UnsupportedResidentKeyRequirementException extends Exception {\n        public UnsupportedResidentKeyRequirementException(@NonNull String requirement) {\n            super(\"Resident key requirement \" + requirement + \" not supported\");\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/SimpleTransactionAuthorizationExtension.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.utils.ToStringHelper;\n\n@PublicApi\n@SafeParcelable.Class\npublic class SimpleTransactionAuthorizationExtension extends AbstractSafeParcelable {\n    @Field(value = 1, getterName = \"getText\")\n    private final String text;\n\n    @Constructor\n    public SimpleTransactionAuthorizationExtension(@Param(1) String text) {\n        this.text = text;\n    }\n\n    public String getText() {\n        return text;\n    }\n\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"SimpleTransactionAuthorizationExtension\").field(\"text\", text).end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<SimpleTransactionAuthorizationExtension> CREATOR = AbstractSafeParcelable.findCreator(SimpleTransactionAuthorizationExtension.class);\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/TokenBinding.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.json.JSONException;\nimport org.json.JSONObject;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.Arrays;\n\n/**\n * Represents the Token binding information provided by the relying party.\n */\n@PublicApi\n@SafeParcelable.Class\npublic class TokenBinding extends AbstractSafeParcelable {\n    /**\n     * A singleton instance representing that token binding is not supported by the client.\n     */\n    @NonNull\n    public static final TokenBinding NOT_SUPPORTED = new TokenBinding(TokenBindingStatus.NOT_SUPPORTED, null);\n    /**\n     * A singleton instance representing that token binding is supported by the client, but unused by the relying party.\n     */\n    @NonNull\n    public static final TokenBinding SUPPORTED = new TokenBinding(TokenBindingStatus.SUPPORTED, null);\n\n    @Field(value = 2, getterName = \"getTokenBindingStatus\")\n    @NonNull\n    private TokenBindingStatus status;\n    @Field(value = 3, getterName = \"getTokenBindingId\")\n    @Nullable\n    private String tokenBindingId;\n\n    private TokenBinding() {\n    }\n\n    /**\n     * Constructs an instance of a {@link TokenBinding} for a provided token binding id.\n     */\n    public TokenBinding(@Nullable String tokenBindingId) {\n        status = TokenBindingStatus.PRESENT;\n        this.tokenBindingId = tokenBindingId;\n    }\n\n    @Constructor\n    TokenBinding(@Param(2) @NonNull TokenBindingStatus status, @Param(3) @Nullable String tokenBindingId) {\n        this.status = status;\n        this.tokenBindingId = tokenBindingId;\n    }\n\n    /**\n     * Returns the token binding ID if the token binding status is {@code PRESENT}, otherwise returns null.\n     */\n    @Nullable\n    public String getTokenBindingId() {\n        return tokenBindingId;\n    }\n\n    @Hide\n    @NonNull\n    public TokenBindingStatus getTokenBindingStatus() {\n        return status;\n    }\n\n    /**\n     * Returns the stringified {@link TokenBinding.TokenBindingStatus} associated with this instance.\n     */\n    @NonNull\n    public String getTokenBindingStatusAsString() {\n        return status.toString();\n    }\n\n    /**\n     * Returns this {@link TokenBinding} object as a {@link JSONObject}.\n     */\n    public JSONObject toJsonObject() {\n        try {\n            return new JSONObject().put(\"status\", this.status).put(\"id\", this.tokenBindingId);\n        } catch (JSONException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof TokenBinding)) return false;\n\n        TokenBinding that = (TokenBinding) o;\n\n        if (status != that.status) return false;\n        return tokenBindingId != null ? tokenBindingId.equals(that.tokenBindingId) : that.tokenBindingId == null;\n    }\n\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(new Object[]{status, tokenBindingId});\n    }\n\n    @Override\n    @NonNull\n    public String toString() {\n        return ToStringHelper.name(\"TokenBinding\")\n                .value(tokenBindingId)\n                .field(\"status\", status)\n                .end();\n    }\n\n    /**\n     * The token binding status specified by the client.\n     */\n    public enum TokenBindingStatus implements Parcelable {\n        /**\n         * The client supports token binding and the relying party is using it.\n         */\n        PRESENT(\"present\"),\n        /**\n         * The client supports token binding but the relying party is not using it.\n         */\n        SUPPORTED(\"supported\"),\n        /**\n         * The client does not support token binding.\n         */\n        NOT_SUPPORTED(\"not-supported\");\n\n        @NonNull\n        private final String value;\n\n        TokenBindingStatus(@NonNull String value) {\n            this.value = value;\n        }\n\n        @Hide\n        public static TokenBindingStatus fromString(String str) throws UnsupportedTokenBindingStatusException {\n            for (TokenBindingStatus value : values()) {\n                if (value.value.equals(str)) return value;\n            }\n            throw new UnsupportedTokenBindingStatusException(\"TokenBindingStatus \" + str + \" not supported\");\n        }\n\n        @Override\n        public void writeToParcel(Parcel dest, int flags) {\n            dest.writeString(value);\n        }\n\n        @Override\n        public int describeContents() {\n            return 0;\n        }\n\n        public static final Creator<TokenBindingStatus> CREATOR = new Creator<TokenBindingStatus>() {\n            @Override\n            public TokenBindingStatus createFromParcel(Parcel in) {\n                try {\n                    return fromString(in.readString());\n                } catch (UnsupportedTokenBindingStatusException e) {\n                    throw new RuntimeException(e);\n                }\n            }\n\n            @Override\n            public TokenBindingStatus[] newArray(int size) {\n                return new TokenBindingStatus[size];\n            }\n        };\n\n        @Override\n        @NonNull\n        public String toString() {\n            return value;\n        }\n    }\n\n    /**\n     * Exception thrown when an unsupported or unrecognized {@link TokenBinding.TokenBindingStatus} is encountered.\n     */\n    public static class UnsupportedTokenBindingStatusException extends Exception {\n        public UnsupportedTokenBindingStatusException(String message) {\n            super(message);\n        }\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    @Hide\n    public static final SafeParcelableCreatorAndWriter<TokenBinding> CREATOR = findCreator(TokenBinding.class);\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/UserVerificationMethodExtension.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.PublicApi;\n\nimport java.util.Arrays;\n\n/**\n * Extension for FIDO User Verification Method.\n * <p>\n * This authentication extension allows Relying Parties to ascertain the method(s) used by the user to authorize the\n * operation.\n * <p>\n * Note that this extension can be used in only sign calls.\n */\n@PublicApi\n@SafeParcelable.Class\npublic class UserVerificationMethodExtension extends AbstractSafeParcelable {\n    @Field(value = 1, getterName = \"getUvm\")\n    @NonNull\n    private boolean uvm;\n\n    @Constructor\n    UserVerificationMethodExtension(@Param(1) boolean uvm) {\n        this.uvm = uvm;\n    }\n\n    @NonNull\n    public boolean getUvm() {\n        return uvm;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof UserVerificationMethodExtension)) return false;\n\n        UserVerificationMethodExtension that = (UserVerificationMethodExtension) o;\n\n        return uvm == that.uvm;\n    }\n\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(new Object[]{uvm});\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<UserVerificationMethodExtension> CREATOR = findCreator(UserVerificationMethodExtension.class);\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/UserVerificationMethods.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * The authentication method/factor used by the authenticator to verify the user.\n */\n@PublicApi\npublic final class UserVerificationMethods {\n    /**\n     * This flag must be set if the authenticator is able to confirm user presence in any fashion. If this flag and no\n     * other is set for user verification, the guarantee is only that the authenticator cannot be operated without some\n     * human intervention, not necessarily that the sensing of \"presence\" provides any level of user verification (e.g.\n     * a device that requires a button press to activate).\n     */\n    public static final int USER_VERIFY_PRESENCE = 1;\n    /**\n     * This flag must be set if the authenticator uses any type of measurement of a fingerprint for user verification.\n     */\n    public static final int USER_VERIFY_FINGERPRINT = 2;\n    /**\n     * This flag must be set if the authenticator uses a local-only passcode (i.e. a passcode not known by the server)\n     * for user verification.\n     */\n    public static final int USER_VERIFY_PASSCODE = 4;\n    /**\n     * This flag must be set if the authenticator uses a voiceprint (also known as speaker recognition) for user\n     * verification.\n     */\n    public static final int USER_VERIFY_VOICEPRINT = 8;\n    /**\n     * This flag must be set if the authenticator uses any manner of face recognition to verify the user.\n     */\n    public static final int USER_VERIFY_FACEPRINT = 16;\n    /**\n     * This flag must be set if the authenticator uses any form of location sensor or measurement for user verification.\n     */\n    public static final int USER_VERIFY_LOCATION = 32;\n    /**\n     * This flag must be set if the authenticator uses any form of eye biometrics for user verification.\n     */\n    public static final int USER_VERIFY_EYEPRINT = 64;\n    /**\n     * This flag must be set if the authenticator uses a drawn pattern for user verification.\n     */\n    public static final int USER_VERIFY_PATTERN = 128;\n    /**\n     * This flag must be set if the authenticator uses any measurement of a full hand (including palm-print, hand\n     * geometry or vein geometry) for user verification.\n     */\n    public static final int USER_VERIFY_HANDPRINT = 256;\n    /**\n     * This flag must be set if the authenticator will respond without any user interaction (e.g. Silent Authenticator).\n     */\n    public static final int USER_VERIFY_NONE = 512;\n    /**\n     * If an authenticator sets multiple flags for user verification types, it may also set this flag to indicate that\n     * all verification methods will be enforced (e.g. faceprint AND voiceprint). If flags for multiple user\n     * verification methods are set and this flag is not set, verification with only one is necessary (e.g. fingerprint\n     * OR passcode).\n     */\n    public static final int USER_VERIFY_ALL = 1024;\n\n    private UserVerificationMethods() {\n    }\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/UserVerificationRequirement.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.common.PublicApi;\n\npublic enum UserVerificationRequirement implements Parcelable {\n    REQUIRED(\"required\"),\n    PREFERRED(\"preferred\"),\n    DISCOURAGED(\"discouraged\");\n\n    private final String value;\n\n    UserVerificationRequirement(String value) {\n        this.value = value;\n    }\n\n    @Override\n    public String toString() {\n        return value;\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(toString());\n    }\n\n    @Hide\n    public static UserVerificationRequirement fromString(String attachment) throws UnsupportedUserVerificationRequirementException {\n        for (UserVerificationRequirement value : values()) {\n            if (value.value.equals(attachment)) return value;\n        }\n        throw new UnsupportedUserVerificationRequirementException(\"User verification requirement \" + attachment + \" not supported\");\n    }\n\n    public static Creator<UserVerificationRequirement> CREATOR = new Creator<UserVerificationRequirement>() {\n        @Override\n        public UserVerificationRequirement createFromParcel(Parcel source) {\n            try {\n                return UserVerificationRequirement.fromString(source.readString());\n            } catch (UnsupportedUserVerificationRequirementException e) {\n                throw new RuntimeException(e);\n            }\n        }\n\n        @Override\n        public UserVerificationRequirement[] newArray(int size) {\n            return new UserVerificationRequirement[size];\n        }\n    };\n\n    public static class UnsupportedUserVerificationRequirementException extends Exception {\n        public UnsupportedUserVerificationRequirementException(String message) {\n            super(message);\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/UvmEntries.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.common.PublicApi;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.List;\n\n/**\n * Represents up to three user verification methods used by the authenticator.\n */\n@PublicApi\n@SafeParcelable.Class\npublic class UvmEntries extends AbstractSafeParcelable {\n    @Field(value = 1, getterName = \"getUvmEntryList\")\n    @Nullable\n    private List<UvmEntry> uvmEntryList;\n\n    @Nullable\n    public List<UvmEntry> getUvmEntryList() {\n        return uvmEntryList;\n    }\n\n    @Constructor\n    UvmEntries(@Param(1) @Nullable List<UvmEntry> uvmEntryList) {\n        this.uvmEntryList = uvmEntryList;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof UvmEntries)) return false;\n\n        UvmEntries that = (UvmEntries) o;\n\n        if (uvmEntryList == null && that.uvmEntryList == null) return true;\n        if (uvmEntryList == null || that.uvmEntryList == null) return false;\n        return uvmEntryList.containsAll(that.uvmEntryList) && that.uvmEntryList.containsAll(uvmEntryList);\n    }\n\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(new Object[]{new HashSet<>(uvmEntryList)});\n    }\n\n    /**\n     * Builder for {@link UvmEntries}\n     */\n    public static class Builder {\n        private List<UvmEntry> uvmEntryList = new ArrayList<>();\n\n        /**\n         * The constructor of {@link UvmEntries.Builder}.\n         */\n        public Builder() {\n        }\n\n        public Builder addAll(@NonNull List<UvmEntry> uvmEntryList) {\n            if (this.uvmEntryList.size() + uvmEntryList.size() > 3) throw new IllegalStateException();\n            this.uvmEntryList.addAll(uvmEntryList);\n            return this;\n        }\n\n        public Builder addUvmEntry(@Nullable UvmEntry uvmEntry) {\n            if (uvmEntryList.size() >= 3) throw new IllegalStateException();\n            uvmEntryList.add(uvmEntry);\n            return this;\n        }\n\n        @NonNull\n        public UvmEntries build() {\n            return new UvmEntries(new ArrayList<>(uvmEntryList));\n        }\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    @Hide\n    public static SafeParcelableCreatorAndWriter<UvmEntries> CREATOR = findCreator(UvmEntries.class);\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/fido2/api/common/UvmEntry.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.fido2.api.common;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.common.PublicApi;\n\nimport java.util.Arrays;\n\n/**\n * Represents a single User Verification Method Entry\n */\n@PublicApi\n@SafeParcelable.Class\npublic class UvmEntry extends AbstractSafeParcelable {\n    @Field(value = 1, getterName = \"getUserVerificationMethod\")\n    private int userVerificationMethod;\n    @Field(value = 2, getterName = \"getKeyProtectionType\")\n    private short keyProtectionType;\n    @Field(value = 3, getterName = \"getMatcherProtectionType\")\n    private short matcherProtectionType;\n\n    @Constructor\n    UvmEntry(@Param(1) int userVerificationMethod, @Param(2) short keyProtectionType, @Param(3) short matcherProtectionType) {\n        this.userVerificationMethod = userVerificationMethod;\n        this.keyProtectionType = keyProtectionType;\n        this.matcherProtectionType = matcherProtectionType;\n    }\n\n    public int getUserVerificationMethod() {\n        return userVerificationMethod;\n    }\n\n    public short getKeyProtectionType() {\n        return keyProtectionType;\n    }\n\n    public short getMatcherProtectionType() {\n        return matcherProtectionType;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof UvmEntry)) return false;\n\n        UvmEntry uvmEntry = (UvmEntry) o;\n\n        if (userVerificationMethod != uvmEntry.userVerificationMethod) return false;\n        if (keyProtectionType != uvmEntry.keyProtectionType) return false;\n        return matcherProtectionType == uvmEntry.matcherProtectionType;\n    }\n\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(new Object[]{userVerificationMethod, keyProtectionType, matcherProtectionType});\n    }\n\n    /**\n     * Builder for {@link UvmEntry}.\n     */\n    public static class Builder {\n        private int userVerificationMethod;\n        private short keyProtectionType;\n        private short matcherProtectionType;\n\n        public Builder setUserVerificationMethod(int userVerificationMethod) {\n            this.userVerificationMethod = userVerificationMethod;\n            return this;\n        }\n\n        public Builder setKeyProtectionType(short keyProtectionType) {\n            this.keyProtectionType = keyProtectionType;\n            return this;\n        }\n\n        public Builder setMatcherProtectionType(short matcherProtectionType) {\n            this.matcherProtectionType = matcherProtectionType;\n            return this;\n        }\n\n        public UvmEntry build() {\n            return new UvmEntry(userVerificationMethod, keyProtectionType, matcherProtectionType);\n        }\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    @Hide\n    public static final SafeParcelableCreatorAndWriter<UvmEntry> CREATOR = findCreator(UvmEntry.class);\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/sourcedevice/SourceDirectTransferClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.sourcedevice;\n\nimport android.app.Activity;\nimport android.app.PendingIntent;\nimport android.content.Intent;\nimport android.os.ParcelFileDescriptor;\n\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.ApiException;\nimport com.google.android.gms.common.api.HasApiKey;\nimport com.google.android.gms.tasks.Task;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * The entry point for interacting with the FIDO SourceDirectTransfer APIs.\n */\n@PublicApi\npublic interface SourceDirectTransferClient extends HasApiKey<Api.ApiOptions.NoOptions> {\n    /**\n     * The key used to retrieve {@link SourceDirectTransferResult} from the intent received by\n     * {@link Activity#onActivityResult(int, int, Intent)} after launching {@link PendingIntent} returned by\n     * {@link #startDirectTransfer(SourceStartDirectTransferOptions, ParcelFileDescriptor, ParcelFileDescriptor)}.\n     */\n    String KEY_SOURCE_DIRECT_TRANSFER_RESULT = \"source_direct_transfer_result\";\n\n    /**\n     * Retrieves {@link SourceDirectTransferResult} from the intent received by\n     * {@link Activity#onActivityResult(int, int, Intent)} after launching {@link PendingIntent} returned by\n     * {@link #startDirectTransfer(SourceStartDirectTransferOptions, ParcelFileDescriptor, ParcelFileDescriptor)}.\n     */\n    SourceDirectTransferResult getSourceDirectTransferResultFromIntent(Intent intent) throws ApiException;\n\n    /**\n     * Creates a Task with {@link PendingIntent}, which when started, will start direct transfer.\n     *\n     * @param input  read side of pipe from the other device.\n     * @param output write side of pipe to the other device.\n     */\n    Task<PendingIntent> startDirectTransfer(SourceStartDirectTransferOptions options, ParcelFileDescriptor input, ParcelFileDescriptor output);\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/sourcedevice/SourceDirectTransferResult.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.sourcedevice;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Result returned from the UI activity in {@link Activity#onActivityResult(int, int, Intent)} after the direct transfer finishes.\n */\n@PublicApi\n@SafeParcelable.Class\npublic class SourceDirectTransferResult extends AbstractSafeParcelable {\n    @Field(value = 1, getterName = \"getStatus\")\n    private Status status;\n\n    private SourceDirectTransferResult() {\n    }\n\n    @Constructor\n    public SourceDirectTransferResult(@Param(1) Status status) {\n        this.status = status;\n    }\n\n    /**\n     * Gets the {@link Status} from the returned {@link SourceDirectTransferResult}.\n     */\n    public Status getStatus() {\n        return status;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<SourceDirectTransferResult> CREATOR = findCreator(SourceDirectTransferResult.class);\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/sourcedevice/SourceStartDirectTransferOptions.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.sourcedevice;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n/**\n * Customized options to start direct transfer.\n */\npublic class SourceStartDirectTransferOptions extends AbstractSafeParcelable {\n    /**\n     * Value of the callerType if the caller is unknown.\n     */\n    public static final int CALLER_TYPE_UNKNOWN = 0;\n    /**\n     * Value of the callerType if the caller is browser.\n     */\n    public static final int CALLER_TYPE_BROWSER = 2;\n\n    @Field(value = 1, getterName = \"getCallerType\")\n    private int callerType;\n\n    private SourceStartDirectTransferOptions() {\n    }\n\n    /**\n     * Constructor for the {@link SourceStartDirectTransferOptions}.\n     */\n    public SourceStartDirectTransferOptions(@Param(1) int callerType) {\n        this.callerType = callerType;\n    }\n\n    public int getCallerType() {\n        return callerType;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<SourceStartDirectTransferOptions> CREATOR = findCreator(SourceStartDirectTransferOptions.class);\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/u2f/U2fApiClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.u2f;\n\nimport android.app.Activity;\nimport android.content.Context;\n\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.GoogleApi;\nimport com.google.android.gms.fido.Fido;\nimport com.google.android.gms.tasks.Task;\n\n/**\n * The entry point for interacting with the regular app U2F APIs.\n * <p>\n * U2F (Universal Second Factor) is the name of the Security Key protocol in FIDO (Fast IDentity Online), which is the\n * industry alliance where Security Keys are being standardized.\n *\n * @deprecated Please use {@link Fido} APIs instead.\n */\n@Deprecated\npublic class U2fApiClient extends GoogleApi<Api.ApiOptions.NoOptions> {\n    private static final Api<Api.ApiOptions.NoOptions> API = null;\n\n    /**\n     * @param activity Calling {@link Activity}\n     */\n    public U2fApiClient(Activity activity) {\n        super(activity, API, Api.ApiOptions.NO_OPTIONS);\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * @param context The {@link Context} of the calling application\n     */\n    public U2fApiClient(Context context) {\n        super(context, API, Api.ApiOptions.NO_OPTIONS);\n        throw new UnsupportedOperationException();\n    }\n\n//    /**\n//     * Creates a Task with {@link U2fPendingIntent}. When this Task object starts, it issues a U2F registration request,\n//     * which is done once per U2F device per account for associating the new U2F device with that account.\n//     *\n//     * @param requestParams for the registration request\n//     * @return Task with PendingIntent to launch U2F registration request\n//     */\n//    public Task<U2fPendingIntent> getRegisterIntent(RegisterRequestParams requestParams) {\n//        throw new UnsupportedOperationException();\n//    }\n\n//    /**\n//     * Creates a Task with U2fPendingIntent. When this Task object starts, it issues a U2F signing request for a relying party to authenticate a user.\n//     *\n//     * @param requestParams for the sign request\n//     * @return Task with PendingIntent to launch U2F signature request\n//     */\n//    public Task<U2fPendingIntent> getSignIntent(SignRequestParams requestParams) {\n//        throw new UnsupportedOperationException();\n//    }\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/com/google/android/gms/fido/u2f/U2fPendingIntent.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fido.u2f;\n\nimport android.app.Activity;\nimport android.app.PendingIntent;\nimport android.content.IntentSender;\n\nimport com.google.android.gms.fido.Fido;\n\n/**\n * Interface for apps to launch a {@link PendingIntent}.\n *\n * @deprecated Please use {@link Fido} APIs instead.\n */\npublic interface U2fPendingIntent {\n    /**\n     * Returns true if an {@link Activity} has a {@link PendingIntent}.\n     */\n    boolean hasPendingIntent();\n\n    /**\n     * Launches the PendingIntent.\n     *\n     * @param activity    An Activity context to use to launch the intent. The activity's onActivityResult method will\n     *                    be invoked after the user is done.\n     * @param requestCode The request code to pass to onActivityResult.\n     * @throws IllegalStateException            if hasPendingIntent is false\n     * @throws IntentSender.SendIntentException If the resolution intent has been canceled or is no longer able to\n     *                                          execute the request.\n     */\n    void launchPendingIntent(Activity activity, int requestCode);\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/org/microg/gms/fido/fido2/Fido2GmsClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.fido2;\n\nimport android.content.Context;\nimport android.os.IBinder;\nimport android.os.RemoteException;\n\nimport com.google.android.gms.fido.fido2.api.IBooleanCallback;\nimport com.google.android.gms.fido.fido2.api.common.PublicKeyCredentialCreationOptions;\nimport com.google.android.gms.fido.fido2.api.common.PublicKeyCredentialRequestOptions;\nimport com.google.android.gms.fido.fido2.internal.regular.IFido2AppCallbacks;\nimport com.google.android.gms.fido.fido2.internal.regular.IFido2AppService;\n\nimport org.microg.gms.common.GmsClient;\nimport org.microg.gms.common.GmsService;\nimport com.google.android.gms.common.api.internal.ConnectionCallbacks;\nimport com.google.android.gms.common.api.internal.OnConnectionFailedListener;\n\npublic class Fido2GmsClient extends GmsClient<IFido2AppService> {\n    public Fido2GmsClient(Context context, ConnectionCallbacks callbacks, OnConnectionFailedListener connectionFailedListener) {\n        super(context, callbacks, connectionFailedListener, GmsService.FIDO2_API.ACTION);\n        serviceId = GmsService.FIDO2_API.SERVICE_ID;\n    }\n\n    public void getRegisterPendingIntent(IFido2AppCallbacks callbacks, PublicKeyCredentialCreationOptions options) throws RemoteException {\n        getServiceInterface().getRegisterPendingIntent(callbacks, options);\n    }\n\n    public void getSignPendingIntent(IFido2AppCallbacks callbacks, PublicKeyCredentialRequestOptions options) throws RemoteException {\n        getServiceInterface().getSignPendingIntent(callbacks, options);\n    }\n\n    public void isUserVerifyingPlatformAuthenticatorAvailable(IBooleanCallback callback) throws RemoteException {\n        getServiceInterface().isUserVerifyingPlatformAuthenticatorAvailable(callback);\n    }\n\n    @Override\n    protected IFido2AppService interfaceFromBinder(IBinder binder) {\n        return IFido2AppService.Stub.asInterface(binder);\n    }\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/org/microg/gms/fido/fido2/Fido2PendingIntentImpl.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.fido2;\n\nimport android.app.Activity;\nimport android.app.PendingIntent;\nimport android.content.IntentSender;\n\nimport com.google.android.gms.fido.fido2.Fido2PendingIntent;\n\npublic class Fido2PendingIntentImpl implements Fido2PendingIntent {\n    private PendingIntent pendingIntent;\n\n    public Fido2PendingIntentImpl(PendingIntent pendingIntent) {\n        this.pendingIntent = pendingIntent;\n    }\n\n    @Override\n    public boolean hasPendingIntent() {\n        return pendingIntent != null;\n    }\n\n    @Override\n    public void launchPendingIntent(Activity activity, int requestCode) throws IntentSender.SendIntentException {\n        if (!hasPendingIntent()) throw new IllegalStateException(\"No PendingIntent available\");\n        activity.startIntentSenderForResult(pendingIntent.getIntentSender(), requestCode, null, 0, 0, 0);\n    }\n}\n"
  },
  {
    "path": "play-services-fido/src/main/java/org/microg/gms/fido/fido2/Fido2PrivilegedGmsClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.fido.fido2;\n\nimport android.content.Context;\nimport android.os.IBinder;\nimport android.os.RemoteException;\n\nimport com.google.android.gms.fido.fido2.api.IBooleanCallback;\nimport com.google.android.gms.fido.fido2.api.ICredentialListCallback;\nimport com.google.android.gms.fido.fido2.api.common.BrowserPublicKeyCredentialCreationOptions;\nimport com.google.android.gms.fido.fido2.api.common.BrowserPublicKeyCredentialRequestOptions;\nimport com.google.android.gms.fido.fido2.internal.privileged.IFido2PrivilegedCallbacks;\nimport com.google.android.gms.fido.fido2.internal.privileged.IFido2PrivilegedService;\n\nimport org.microg.gms.common.GmsClient;\nimport org.microg.gms.common.GmsService;\nimport com.google.android.gms.common.api.internal.ConnectionCallbacks;\nimport com.google.android.gms.common.api.internal.OnConnectionFailedListener;\n\npublic class Fido2PrivilegedGmsClient extends GmsClient<IFido2PrivilegedService> {\n    public Fido2PrivilegedGmsClient(Context context, ConnectionCallbacks callbacks, OnConnectionFailedListener connectionFailedListener) {\n        super(context, callbacks, connectionFailedListener, GmsService.FIDO2_PRIVILEGED_API.ACTION);\n        serviceId = GmsService.FIDO2_PRIVILEGED_API.SERVICE_ID;\n    }\n\n    public void getRegisterPendingIntent(IFido2PrivilegedCallbacks callbacks, BrowserPublicKeyCredentialCreationOptions options) throws RemoteException {\n        getServiceInterface().getRegisterPendingIntent(callbacks, options);\n    }\n\n    public void getSignPendingIntent(IFido2PrivilegedCallbacks callbacks, BrowserPublicKeyCredentialRequestOptions options) throws RemoteException {\n        getServiceInterface().getSignPendingIntent(callbacks, options);\n    }\n\n    public void isUserVerifyingPlatformAuthenticatorAvailable(IBooleanCallback callback) throws RemoteException {\n        getServiceInterface().isUserVerifyingPlatformAuthenticatorAvailable(callback);\n    }\n\n    public void getCredentialList(ICredentialListCallback callbacks, String rpId) throws RemoteException {\n        getServiceInterface().getCredentialList(callbacks, rpId);\n    }\n\n    @Override\n    protected IFido2PrivilegedService interfaceFromBinder(IBinder binder) {\n        return IFido2PrivilegedService.Stub.asInterface(binder);\n    }\n}\n"
  },
  {
    "path": "play-services-fitness/.gitignore",
    "content": "/build"
  },
  {
    "path": "play-services-fitness/build.gradle",
    "content": "plugins {\n    id 'com.android.library'\n    id 'kotlin-android'\n}\n\nandroid {\n    namespace \"com.google.android.gms.fitness\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n}\n\ndependencies {\n    // Dependencies from play-services-fitness:21.2.0\n    api 'androidx.collection:collection:1.0.0'\n    api project(':play-services-base')\n    api project(':play-services-basement')\n    api project(':play-services-tasks')\n\n    annotationProcessor project(':safe-parcel-processor')\n}"
  },
  {
    "path": "play-services-fitness/core/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'kotlin-android'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\ndependencies {\n    api project(':play-services-fitness')\n\n    implementation project(':play-services-base-core')\n}\n\nandroid {\n    namespace \"org.microg.gms.fitness.core\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    sourceSets {\n        main.java.srcDirs += 'src/main/kotlin'\n    }\n\n    lintOptions {\n        disable 'MissingTranslation', 'GetLocales'\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n\n    kotlinOptions {\n        jvmTarget = 1.8\n    }\n}\n\n// Not publishable yet\n// apply from: '../../gradle/publish-android.gradle'\n\ndescription = 'microG service implementation for play-services-fitness'"
  },
  {
    "path": "play-services-fitness/core/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2024 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <application>\n        <service\n            android:name=\"com.google.android.gms.fitness.service.config.FitConfigBroker\"\n            android:exported=\"true\"\n            android:enabled=\"true\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.fitness.ConfigApi\" />\n            </intent-filter>\n        </service>\n\n        <service\n            android:name=\"com.google.android.gms.fitness.service.history.FitHistoryBroker\"\n            android:enabled=\"true\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.fitness.HistoryApi\" />\n            </intent-filter>\n        </service>\n\n        <service\n            android:name=\"com.google.android.gms.fitness.service.sessions.FitSessionsBroker\"\n            android:enabled=\"true\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.fitness.SessionsApi\" />\n            </intent-filter>\n        </service>\n\n        <service\n            android:name=\"com.google.android.gms.fitness.service.recording.FitRecordingBroker\"\n            android:enabled=\"true\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.fitness.RecordingApi\"/>\n            </intent-filter>\n        </service>\n\n    </application>\n</manifest>"
  },
  {
    "path": "play-services-fitness/core/src/main/kotlin/com/google/android/gms/fitness/service/config/FitConfigBroker.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.service.config\n\nimport com.google.android.gms.fitness.service.FITNESS_FEATURES\nimport android.os.Parcel\nimport android.util.Log\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.internal.ConnectionInfo\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport com.google.android.gms.fitness.internal.IGoogleFitConfigApi\nimport com.google.android.gms.fitness.request.DataTypeCreateRequest\nimport com.google.android.gms.fitness.request.DisableFitRequest\nimport com.google.android.gms.fitness.request.ReadDataTypeRequest\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.utils.warnOnTransactionIssues\n\nprivate const val TAG = \"FitConfigBroker\"\n\nclass FitConfigBroker : BaseService(TAG, GmsService.FIT_CONFIG) {\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        callback.onPostInitCompleteWithConnectionInfo(CommonStatusCodes.SUCCESS, FitConfigBrokerImpl(),\n            ConnectionInfo().apply {\n                features = FITNESS_FEATURES\n            })\n    }\n}\n\nclass FitConfigBrokerImpl : IGoogleFitConfigApi.Stub() {\n\n    override fun createCustomDataType(request: DataTypeCreateRequest?) {\n        Log.d(TAG, \"Not implemented createCustomDataType: $request\")\n    }\n\n    override fun readDataType(request: ReadDataTypeRequest?) {\n        Log.d(TAG, \"Not implemented readDataType: $request\")\n    }\n\n    override fun disableFit(request: DisableFitRequest?) {\n        Log.d(TAG, \"Method <disableFit> Called: $request\")\n        try {\n            request?.callback?.onResult(Status.SUCCESS)\n        } catch (e: Exception) {\n            Log.w(TAG, \"disableFit Error $e\")\n        }\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =\n        warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n}"
  },
  {
    "path": "play-services-fitness/core/src/main/kotlin/com/google/android/gms/fitness/service/extensions.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.service\n\nimport com.google.android.gms.common.Feature\n\nval FITNESS_FEATURES = arrayOf(\n    Feature(\"temp_data_point_changelogs\", 1L),\n    Feature(\"temp_session_changelogs\", 1L),\n    Feature(\"temp_data_source_changelogs\", 1L),\n    Feature(\"local_no_account_mode\", 1L),\n)"
  },
  {
    "path": "play-services-fitness/core/src/main/kotlin/com/google/android/gms/fitness/service/history/FitHistoryBroker.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.service.history\n\nimport com.google.android.gms.fitness.service.FITNESS_FEATURES\nimport android.os.Parcel\nimport android.util.Log\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.internal.ConnectionInfo\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport com.google.android.gms.fitness.internal.IGoogleFitHistoryApi\nimport com.google.android.gms.fitness.request.DailyTotalRequest\nimport com.google.android.gms.fitness.request.DataDeleteRequest\nimport com.google.android.gms.fitness.request.DataInsertRequest\nimport com.google.android.gms.fitness.request.DataPointChangesRequest\nimport com.google.android.gms.fitness.request.DataReadRequest\nimport com.google.android.gms.fitness.request.DataUpdateListenerRegistrationRequest\nimport com.google.android.gms.fitness.request.DataUpdateListenerUnregistrationRequest\nimport com.google.android.gms.fitness.request.DataUpdateRequest\nimport com.google.android.gms.fitness.request.DebugInfoRequest\nimport com.google.android.gms.fitness.request.GetFileUriRequest\nimport com.google.android.gms.fitness.request.GetSyncInfoRequest\nimport com.google.android.gms.fitness.request.ReadRawRequest\nimport com.google.android.gms.fitness.request.ReadStatsRequest\nimport com.google.android.gms.fitness.request.SessionChangesRequest\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.utils.warnOnTransactionIssues\n\nprivate const val TAG = \"FitHistoryBroker\"\n\nclass FitHistoryBroker : BaseService(TAG, GmsService.FIT_HISTORY) {\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        callback.onPostInitCompleteWithConnectionInfo(CommonStatusCodes.SUCCESS, FitHistoryBrokerImpl().asBinder(),\n            ConnectionInfo().apply {\n                features = FITNESS_FEATURES\n            })\n    }\n}\n\nclass FitHistoryBrokerImpl : IGoogleFitHistoryApi.Stub() {\n\n    override fun readData(request: DataReadRequest?) {\n        Log.d(TAG, \"Not implemented readData: $request\")\n    }\n\n    override fun insertData(request: DataInsertRequest?) {\n        Log.d(TAG, \"Not implemented insertData: $request\")\n    }\n\n    override fun deleteData(request: DataDeleteRequest?) {\n        Log.d(TAG, \"Not implemented deleteData: $request\")\n    }\n\n    override fun getSyncInfo(request: GetSyncInfoRequest) {\n        Log.d(TAG, \"Not implemented getSyncInfo: $request\")\n    }\n\n    override fun readStats(request: ReadStatsRequest?) {\n        Log.d(TAG, \"Not implemented readStats: $request\")\n    }\n\n    override fun readRaw(request: ReadRawRequest?) {\n        Log.d(TAG, \"Not implemented readRaw: $request\")\n    }\n\n    override fun getDailyTotal(request: DailyTotalRequest?) {\n        Log.d(TAG, \"Not implemented getDailyTotal: $request\")\n    }\n\n    override fun insertDataPrivileged(request: DataInsertRequest?) {\n        Log.d(TAG, \"Not implemented insertDataPrivileged: $request\")\n    }\n\n    override fun updateData(request: DataUpdateRequest?) {\n        Log.d(TAG, \"Not implemented updateData: $request\")\n    }\n\n    override fun registerDataUpdateListener(request: DataUpdateListenerRegistrationRequest?) {\n        Log.d(TAG, \"Not implemented registerDataUpdateListener: $request\")\n    }\n\n    override fun unregisterDataUpdateListener(request: DataUpdateListenerUnregistrationRequest?) {\n        Log.d(TAG, \"Not implemented unregisterDataUpdateListener: $request\")\n    }\n\n    override fun getFileUri(request: GetFileUriRequest?) {\n        Log.d(TAG, \"Not implemented getFileUri: $request\")\n    }\n\n    override fun getDebugInfo(request: DebugInfoRequest?) {\n        Log.d(TAG, \"Not implemented getDebugInfo: $request\")\n    }\n\n    override fun getDataPointChanges(request: DataPointChangesRequest?) {\n        Log.d(TAG, \"Not implemented getDataPointChanges: $request\")\n    }\n\n    override fun getSessionChanges(request: SessionChangesRequest?) {\n        Log.d(TAG, \"Not implemented getSessionChanges: $request\")\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =\n        warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n}\n"
  },
  {
    "path": "play-services-fitness/core/src/main/kotlin/com/google/android/gms/fitness/service/recording/FitRecordingBroker.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.service.recording\n\nimport com.google.android.gms.fitness.service.FITNESS_FEATURES\nimport android.util.Log\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.internal.ConnectionInfo\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport com.google.android.gms.fitness.data.Subscription\nimport com.google.android.gms.fitness.internal.IGoogleFitRecordingApi\nimport com.google.android.gms.fitness.request.ListSubscriptionsRequest\nimport com.google.android.gms.fitness.request.SubscribeRequest\nimport com.google.android.gms.fitness.request.UnsubscribeRequest\nimport com.google.android.gms.fitness.result.ListSubscriptionsResult\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\n\nprivate const val TAG = \"FitRecordingBroker\"\n\nclass FitRecordingBroker : BaseService(TAG, GmsService.FIT_RECORDING) {\n\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        Log.d(TAG, \"handleServiceRequest: account: ${request.account.name} packageName: ${request.packageName}\")\n        callback.onPostInitCompleteWithConnectionInfo(CommonStatusCodes.SUCCESS, FitRecordingBrokerImpl(),\n            ConnectionInfo().apply {\n                features = FITNESS_FEATURES\n            })\n    }\n\n}\n\nclass FitRecordingBrokerImpl() : IGoogleFitRecordingApi.Stub() {\n\n    override fun subscribe(request: SubscribeRequest) {\n        Log.d(TAG, \"Not yet implemented subscribe request: $request\")\n        return request.callback.onResult(Status.SUCCESS)\n    }\n\n    override fun unsubscribe(request: UnsubscribeRequest) {\n        Log.d(TAG, \"Not yet implemented unsubscribe request: $request\")\n        request.callback.onResult(Status.SUCCESS)\n    }\n\n    override fun listSubscriptions(request: ListSubscriptionsRequest) {\n        Log.d(TAG, \"Not yet implemented listSubscriptions request: $request\")\n        return request.callback.onListSubscriptions(ListSubscriptionsResult(emptyList<Subscription>(), Status(5008)))\n    }\n\n}"
  },
  {
    "path": "play-services-fitness/core/src/main/kotlin/com/google/android/gms/fitness/service/sessions/FitSessionsBroker.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.service.sessions;\n\nimport com.google.android.gms.fitness.service.FITNESS_FEATURES\nimport android.os.Parcel\nimport android.util.Log\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.internal.ConnectionInfo\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport com.google.android.gms.fitness.internal.IGoogleFitSessionsApi\nimport com.google.android.gms.fitness.request.SessionInsertRequest\nimport com.google.android.gms.fitness.request.SessionReadRequest\nimport com.google.android.gms.fitness.request.SessionRegistrationRequest\nimport com.google.android.gms.fitness.request.SessionStartRequest\nimport com.google.android.gms.fitness.request.SessionStopRequest\nimport com.google.android.gms.fitness.request.SessionUnregistrationRequest\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.utils.warnOnTransactionIssues\n\nprivate const val TAG = \"FitSessionsBroker\"\n\nclass FitSessionsBroker : BaseService(TAG, GmsService.FIT_SESSIONS) {\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        callback.onPostInitCompleteWithConnectionInfo(CommonStatusCodes.SUCCESS, FitSessionsBrokerImpl(),\n            ConnectionInfo().apply {\n                features = FITNESS_FEATURES\n            })\n    }\n}\n\nclass FitSessionsBrokerImpl : IGoogleFitSessionsApi.Stub() {\n    override fun startRequest(startRequest: SessionStartRequest?) {\n        Log.d(TAG, \"Not implemented startRequest: $startRequest\")\n    }\n\n    override fun stopRequest(stopRequest: SessionStopRequest?) {\n        Log.d(TAG, \"Not implemented stopRequest: $stopRequest\")\n    }\n\n    override fun insertRequest(insetRequest: SessionInsertRequest?) {\n        Log.d(TAG, \"Not implemented insertRequest: $insetRequest\")\n    }\n\n    override fun readRequest(readRequest: SessionReadRequest?) {\n        Log.d(TAG, \"Not implemented readRequest: $readRequest\")\n    }\n\n    override fun registrationRequest(registrationRequest: SessionRegistrationRequest?) {\n        Log.d(TAG, \"Not implemented registrationRequest: $registrationRequest\")\n    }\n\n    override fun unRegistrationRequest(unRegistrationRequest: SessionUnregistrationRequest?) {\n        Log.d(TAG, \"Not implemented unRegistrationRequest: $unRegistrationRequest\")\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =\n        warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n}"
  },
  {
    "path": "play-services-fitness/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n</manifest>"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/internal/IDailyTotalCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.internal;\n\ninterface IDailyTotalCallback {\n\n}"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/internal/IDataPointChangesCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.internal;\n\ninterface IDataPointChangesCallback {\n\n}"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/internal/IDataReadCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.internal;\n\nimport com.google.android.gms.fitness.request.DataReadResult;\n\ninterface IDataReadCallback {\n    void onPostResult(in DataReadResult dataReadResult) = 0;\n}"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/internal/IDataTypeCallback.aidl",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.internal;\n\nimport com.google.android.gms.fitness.result.DataTypeResult;\n\ninterface IDataTypeCallback {\n    void onDataType(in DataTypeResult dataTypeResult) = 0;\n}"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/internal/IDebugInfoCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.internal;\n\ninterface IDebugInfoCallback {\n\n}"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/internal/IFileUriCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.internal;\n\ninterface IFileUriCallback {\n\n}"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/internal/IGoogleFitConfigApi.aidl",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.internal;\n\nimport com.google.android.gms.fitness.request.DataTypeCreateRequest;\nimport com.google.android.gms.fitness.request.DisableFitRequest;\nimport com.google.android.gms.fitness.request.ReadDataTypeRequest;\n\ninterface IGoogleFitConfigApi {\n    void createCustomDataType(in DataTypeCreateRequest request) = 0;\n    void readDataType(in ReadDataTypeRequest request) = 1;\n    void disableFit(in DisableFitRequest request) = 21;\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/internal/IGoogleFitHistoryApi.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.internal;\n\nimport com.google.android.gms.fitness.request.DataDeleteRequest;\nimport com.google.android.gms.fitness.request.GetSyncInfoRequest;\nimport com.google.android.gms.fitness.request.DataInsertRequest;\nimport com.google.android.gms.fitness.request.DataReadRequest;\nimport com.google.android.gms.fitness.request.ReadStatsRequest;\nimport com.google.android.gms.fitness.request.ReadRawRequest;\nimport com.google.android.gms.fitness.request.DailyTotalRequest;\nimport com.google.android.gms.fitness.request.DataUpdateRequest;\nimport com.google.android.gms.fitness.request.DataUpdateListenerRegistrationRequest;\nimport com.google.android.gms.fitness.request.DataUpdateListenerUnregistrationRequest;\nimport com.google.android.gms.fitness.request.GetFileUriRequest;\nimport com.google.android.gms.fitness.request.DebugInfoRequest;\nimport com.google.android.gms.fitness.request.DataPointChangesRequest;\nimport com.google.android.gms.fitness.request.SessionChangesRequest;\n\ninterface IGoogleFitHistoryApi {\n    void readData(in DataReadRequest request) = 0;\n    void insertData(in DataInsertRequest request) = 1;\n    void deleteData(in DataDeleteRequest request) = 2;\n    void getSyncInfo(in GetSyncInfoRequest request) = 3;\n    void readStats(in ReadStatsRequest request) = 4;\n    void readRaw(in ReadRawRequest request) = 5;\n    void getDailyTotal(in DailyTotalRequest request) = 6;\n    void insertDataPrivileged(in DataInsertRequest request) = 7;\n    void updateData(in DataUpdateRequest request) = 8;\n    void registerDataUpdateListener(in DataUpdateListenerRegistrationRequest request) = 9;\n    void unregisterDataUpdateListener(in DataUpdateListenerUnregistrationRequest request) = 10;\n    void getFileUri(in GetFileUriRequest request) = 11;\n    void getDebugInfo(in DebugInfoRequest request) = 12;\n    void getDataPointChanges(in DataPointChangesRequest request) = 15;\n    void getSessionChanges(in SessionChangesRequest request) = 16;\n}"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/internal/IGoogleFitRecordingApi.aidl",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.internal;\n\nimport com.google.android.gms.fitness.request.ListSubscriptionsRequest;\nimport com.google.android.gms.fitness.request.SubscribeRequest;\nimport com.google.android.gms.fitness.request.UnsubscribeRequest;\n\ninterface IGoogleFitRecordingApi {\n    void subscribe(in SubscribeRequest request) = 0;\n    void unsubscribe(in UnsubscribeRequest request) = 1;\n    void listSubscriptions(in ListSubscriptionsRequest request) = 2;\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/internal/IGoogleFitSessionsApi.aidl",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.fitness.internal;\n\nimport com.google.android.gms.fitness.request.SessionStartRequest;\nimport com.google.android.gms.fitness.request.SessionStopRequest;\nimport com.google.android.gms.fitness.request.SessionInsertRequest;\nimport com.google.android.gms.fitness.request.SessionReadRequest;\nimport com.google.android.gms.fitness.request.SessionRegistrationRequest;\nimport com.google.android.gms.fitness.request.SessionUnregistrationRequest;\n\ninterface IGoogleFitSessionsApi {\n    void startRequest(in SessionStartRequest startRequest) = 0;\n    void stopRequest(in SessionStopRequest stopRequest) = 1;\n    void insertRequest(in SessionInsertRequest insetRequest) = 2;\n    void readRequest(in SessionReadRequest readRequest) = 3;\n    void registrationRequest(in SessionRegistrationRequest registrationRequest) = 4;\n    void unRegistrationRequest(in SessionUnregistrationRequest unRegistrationRequest) = 5;\n}"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/internal/IListSubscriptionsCallback.aidl",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.internal;\n\nimport com.google.android.gms.fitness.result.ListSubscriptionsResult;\n\ninterface IListSubscriptionsCallback {\n    void onListSubscriptions(in ListSubscriptionsResult listSubscriptionsResult) = 0;\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/internal/IReadRawCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.internal;\n\ninterface IReadRawCallback {\n\n}"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/internal/IReadStatsCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.internal;\n\nimport com.google.android.gms.fitness.result.DataStatsResult;\n\ninterface IReadStatsCallback {\n    void onResult(in DataStatsResult result) = 1;\n}"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/internal/ISessionChangesCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.internal;\n\ninterface ISessionChangesCallback {\n\n}"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/internal/ISessionReadCallback.aidl",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.fitness.internal;\n\nimport com.google.android.gms.fitness.result.SessionReadResult;\n\ninterface ISessionReadCallback {\n    void onResult(in SessionReadResult sessionReadResult) = 0;\n}"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/internal/ISessionStopCallback.aidl",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.fitness.internal;\n\nimport com.google.android.gms.fitness.result.SessionStopResult;\n\ninterface ISessionStopCallback {\n    void onResult(in SessionStopResult sessionStopReult) = 0;\n}"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/internal/IStatusCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.internal;\n\nimport com.google.android.gms.common.api.Status;\n\ninterface IStatusCallback {\n   void onResult(in Status status) = 0;\n}"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/internal/ISyncInfoCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.internal;\n\ninterface ISyncInfoCallback {\n\n}"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/request/DailyTotalRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nparcelable DailyTotalRequest;"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/request/DataDeleteRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nparcelable DataDeleteRequest;"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/request/DataInsertRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nparcelable DataInsertRequest;"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/request/DataPointChangesRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nparcelable DataPointChangesRequest;"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/request/DataReadRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nparcelable DataReadRequest;"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/request/DataReadResult.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nparcelable DataReadResult;"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/request/DataSourceQueryParams.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nparcelable DataSourceQueryParams;"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/request/DataTypeCreateRequest.aidl",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nparcelable DataTypeCreateRequest;"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/request/DataUpdateListenerRegistrationRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nparcelable DataUpdateListenerRegistrationRequest;"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/request/DataUpdateListenerUnregistrationRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nparcelable DataUpdateListenerUnregistrationRequest;"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/request/DataUpdateRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nparcelable DataUpdateRequest;"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/request/DebugInfoRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nparcelable DebugInfoRequest;"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/request/DisableFitRequest.aidl",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nparcelable DisableFitRequest;"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/request/GetFileUriRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nparcelable GetFileUriRequest;"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/request/GetSyncInfoRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nparcelable GetSyncInfoRequest;"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/request/ListSubscriptionsRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nparcelable ListSubscriptionsRequest;"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/request/ReadDataTypeRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nparcelable ReadDataTypeRequest;"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/request/ReadRawRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nparcelable ReadRawRequest;"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/request/ReadStatsRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nparcelable ReadStatsRequest;"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/request/SessionChangesRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nparcelable SessionChangesRequest;"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/request/SessionInsertRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nparcelable SessionInsertRequest;"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/request/SessionReadRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nparcelable SessionReadRequest;"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/request/SessionRegistrationRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nparcelable SessionRegistrationRequest;"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/request/SessionStartRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nparcelable SessionStartRequest;"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/request/SessionStopRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nparcelable SessionStopRequest;"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/request/SessionUnregistrationRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nparcelable SessionUnregistrationRequest;"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/request/SubscribeRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nparcelable SubscribeRequest;"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/request/UnsubscribeRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nparcelable UnsubscribeRequest;"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/result/DataSourceStatsResult.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.result;\n\nparcelable DataSourceStatsResult;"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/result/DataStatsResult.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.result;\n\nparcelable DataStatsResult;"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/result/DataTypeResult.aidl",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.result;\n\nparcelable DataTypeResult;"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/result/ListSubscriptionsResult.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.result;\n\nparcelable ListSubscriptionsResult;"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/result/SessionReadResult.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.result;\n\nparcelable SessionReadResult;"
  },
  {
    "path": "play-services-fitness/src/main/aidl/com/google/android/gms/fitness/result/SessionStopResult.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.result;\n\nparcelable SessionStopResult;"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/data/Application.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.data;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport org.microg.gms.common.Constants;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\n@Hide\npublic class Application extends AbstractSafeParcelable {\n\n    public static final Application GMS_APP = new Application(Constants.GMS_PACKAGE_NAME);\n\n    @Field(value = 1, getterName = \"getPackageName\")\n    @NonNull\n    private final String packageName;\n\n    @Constructor\n    public Application(@Param(1) @NonNull String packageName) {\n        this.packageName = packageName;\n    }\n\n    @NonNull\n    public String getPackageName() {\n        return packageName;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"Application\").value(packageName).end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<Application> CREATOR = findCreator(Application.class);\n\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/data/Bucket.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fitness.data;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\n\n@SafeParcelable.Class\npublic class Bucket extends AbstractSafeParcelable {\n\n    /**\n     * Type constant denoting that bucketing by time is requested.\n     */\n    public static final int TYPE_TIME = 1;\n    /**\n     * Type constant denoting that bucketing by session is requested.\n     */\n    public static final int TYPE_SESSION = 2;\n    /**\n     * Type constant denoting that bucketing by activity type is requested.\n     */\n    public static final int TYPE_ACTIVITY_TYPE = 3;\n    /**\n     * Type constant denoting that bucketing by individual activity segment is requested.\n     */\n    public static final int TYPE_ACTIVITY_SEGMENT = 4;\n\n    @Field(value = 1, getterName = \"getStartTimeMillis\")\n    private final long startTimeMillis;\n    @Field(value = 2, getterName = \"getEndTimeMillis\")\n    private final long endTimeMillis;\n    @Field(value = 3, getterName = \"getSession\")\n    @Nullable\n    private final Session session;\n    @Field(value = 4, getterName = \"getActivityType\")\n    private final int activityType;\n    @Field(value = 5, getterName = \"getDataSets\")\n    private final List<DataSet> dataSets;\n    @Field(value = 6, getterName = \"getBucketType\")\n    private final int bucketType;\n\n    @Constructor\n    public Bucket(@Param(1) long startTimeMillis, @Param(2) long endTimeMillis, @Nullable @Param(3) Session session, @Param(4) int activityType, @Param(5) List<DataSet> dataSets, @Param(6) int bucketType) {\n        this.startTimeMillis = startTimeMillis;\n        this.endTimeMillis = endTimeMillis;\n        this.session = session;\n        this.activityType = activityType;\n        this.dataSets = dataSets;\n        this.bucketType = bucketType;\n    }\n\n    /**\n     * Returns the activity of the bucket if bucketing by activity was requested, or {@link FitnessActivities#UNKNOWN} otherwise.\n     */\n    @NonNull\n    public String getActivity() {\n        // TODO\n        return null;\n    }\n\n    /**\n     * Returns the type of the bucket.\n     */\n    public int getBucketType() {\n        return bucketType;\n    }\n\n    /**\n     * Returns the data set of requested data type over the time interval of the bucket. Returns null, if data set for the requested type is not found.\n     */\n    public DataSet getDataSet(@NonNull DataType dataType) {\n        for (DataSet dataSet : this.dataSets) {\n            if (dataSet.getDataType().equals(dataType)) {\n                return dataSet;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Returns the requested data sets over the time interval of the bucket.\n     */\n    public List<DataSet> getDataSets() {\n        return dataSets;\n    }\n\n    /**\n     * Returns the end time of the bucket, in the given time unit since epoch.\n     */\n    public long getEndTime(TimeUnit timeUnit) {\n        return timeUnit.convert(this.endTimeMillis, TimeUnit.MILLISECONDS);\n    }\n\n    /**\n     * Returns the session of the bucket if bucketing by session was requested, {@code null} otherwise.\n     */\n    @Nullable\n    public Session getSession() {\n        return session;\n    }\n\n    /**\n     * Returns the start time of the bucket, in the given time unit since epoch.\n     */\n    public long getStartTime(@NonNull TimeUnit timeUnit) {\n        return timeUnit.convert(this.startTimeMillis, TimeUnit.MILLISECONDS);\n    }\n\n    int getActivityType() {\n        return activityType;\n    }\n\n    long getEndTimeMillis() {\n        return endTimeMillis;\n    }\n\n    long getStartTimeMillis() {\n        return startTimeMillis;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<Bucket> CREATOR = findCreator(Bucket.class);\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"Bucket\")\n                .field(\"startTimeMillis\", startTimeMillis)\n                .field(\"endTimeMillis\", endTimeMillis)\n                .field(\"session\", session)\n                .field(\"activityType\", activityType)\n                .field(\"dataSets\", dataSets)\n                .field(\"bucketType\", bucketType)\n                .end();\n    }\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/data/DataPoint.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fitness.data;\n\nimport android.content.Intent;\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableSerializer;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.TimeUnit;\n\n@SafeParcelable.Class\npublic class DataPoint extends AbstractSafeParcelable {\n    @Field(value = 1, getterName = \"getDataSource\")\n    @NonNull\n    private final DataSource dataSource;\n    @Field(value = 3, getterName = \"getTimestampNanos\")\n    private long timestampNanos;\n    @Field(value = 4, getterName = \"getStartTimeNanos\")\n    private long startTimeNanos;\n    @Field(value = 5, getterName = \"getValues\")\n    private final Value[] values;\n    @Field(value = 6, getterName = \"getOriginalDataSourceIfSet\")\n    @Nullable\n    private DataSource originalDataSource;\n    @Field(value = 7, getterName = \"getRawTimestamp\")\n    private final long rawTimestamp;\n\n    DataPoint(DataSource dataSource) {\n        this.dataSource = dataSource;\n        List<com.google.android.gms.fitness.data.Field> fields = dataSource.getDataType().getFields();\n        this.values = new Value[fields.size()];\n        for (int i = 0; i < fields.size(); i++) {\n            values[i] = new Value(fields.get(i).getFormat());\n        }\n        this.rawTimestamp = 0;\n    }\n\n    @Constructor\n    DataPoint(@Param(1) @NonNull DataSource dataSource, @Param(3) long timestampNanos, @Param(4) long startTimeNanos, @Param(5) Value[] values, @Param(6) @Nullable DataSource originalDataSource, @Param(7) long rawTimestamp) {\n        this.dataSource = dataSource;\n        this.timestampNanos = timestampNanos;\n        this.startTimeNanos = startTimeNanos;\n        this.values = values;\n        this.originalDataSource = originalDataSource;\n        this.rawTimestamp = rawTimestamp;\n    }\n\n    /**\n     * Returns the data source for the data point. If the data point is part of a {@link DataSet}, this will correspond to the data set's data source.\n     */\n    @NonNull\n    public DataSource getDataSource() {\n        return dataSource;\n    }\n\n    /**\n     * Returns the data type defining the format of the values in this data point.\n     */\n    @NonNull\n    public DataType getDataType() {\n        return dataSource.getDataType();\n    }\n\n    /**\n     * Returns the end time of the interval represented by this data point, in the given unit since epoch. This method is equivalent to\n     * {@link #getTimestamp(TimeUnit)}\n     */\n    public long getEndTime(@NonNull TimeUnit timeUnit) {\n        return timeUnit.convert(this.timestampNanos, TimeUnit.NANOSECONDS);\n    }\n\n    /**\n     * Returns the original data source for this data point. The original data source helps identify the source of the data point as it gets merged and\n     * transformed into different streams.\n     * <p>\n     * Note that, if this data point is part of a {@link DataSet}, the data source returned here may be different from the data set's data source. In case of\n     * transformed or merged data sets, each data point's original data source will retain the original attribution as much as possible, while the\n     * data set's data source will represent the merged or transformed stream.\n     * <p>\n     * WARNING: do not rely on this field for anything other than debugging. The value of this field, if it is set at all, is an implementation detail and\n     * is not guaranteed to remain consistent.\n     */\n    @NonNull\n    public DataSource getOriginalDataSource() {\n        if (originalDataSource != null) return originalDataSource;\n        return dataSource;\n    }\n\n    /**\n     * Returns the start time of the interval represented by this data point, in the given unit since epoch.\n     */\n    public long getStartTime(@NonNull TimeUnit timeUnit) {\n        return timeUnit.convert(this.startTimeNanos, TimeUnit.NANOSECONDS);\n    }\n\n    /**\n     * Returns the timestamp of the data point, in the given unit since epoch. For data points that represent intervals, this method will return the\n     * end time.\n     */\n    public long getTimestamp(@NonNull TimeUnit timeUnit) {\n        return timeUnit.convert(this.timestampNanos, TimeUnit.NANOSECONDS);\n    }\n\n    /**\n     * Returns the value holder for the field with the given name. This method can be used both to query the value and to set it.\n     *\n     * @param field One of the fields of this data type.\n     * @return The Value associated with the given field.\n     * @throws IllegalArgumentException If the given field doesn't match any of the fields for this DataPoint's data type.\n     */\n    @NonNull\n    public Value getValue(com.google.android.gms.fitness.data.Field field) {\n        return this.values[getDataType().indexOf(field)];\n    }\n\n    long getTimestampNanos() {\n        return timestampNanos;\n    }\n\n    long getStartTimeNanos() {\n        return startTimeNanos;\n    }\n\n    Value[] getValues() {\n        return values;\n    }\n\n    DataSource getOriginalDataSourceIfSet() {\n        return originalDataSource;\n    }\n\n    long getRawTimestamp() {\n        return rawTimestamp;\n    }\n\n    /**\n     * Sets the values of this data point, where the format for all of its values is float.\n     *\n     * @param values The value for each field of the data point, in order.\n     * @deprecated Use {@link DataPoint.Builder} to create {@link DataPoint} instances.\n     */\n    @Deprecated\n    public DataPoint setFloatValues(float... values) {\n        if (values.length != this.getDataType().getFields().size())\n            throw new IllegalArgumentException(\"The number of values does not match the number of fields\");\n        for (int i = 0; i < values.length; i++) {\n            this.values[i].setFloat(values[i]);\n        }\n        return this;\n    }\n\n    /**\n     * Sets the values of this data point, where the format for all of its values is int.\n     *\n     * @param values The value for each field of the data point, in order.\n     * @deprecated Use {@link DataPoint.Builder} to create {@link DataPoint} instances.\n     */\n    @Deprecated\n    public DataPoint setIntValues(int... values) {\n        if (values.length != this.getDataType().getFields().size())\n            throw new IllegalArgumentException(\"The number of values does not match the number of fields\");\n        for (int i = 0; i < values.length; i++) {\n            this.values[i].setInt(values[i]);\n        }\n        return this;\n    }\n\n    /**\n     * Sets the time interval of a data point that represents an interval of time. For data points that represent instantaneous readings,\n     * {@link #setTimestamp(long, TimeUnit)} should be used.\n     *\n     * @param startTime The start time in the given unit, representing elapsed time since epoch.\n     * @param endTime   The end time in the given unit, representing elapsed time since epoch.\n     * @param timeUnit  The time unit of both start and end timestamps.\n     * @deprecated Use {@link DataPoint.Builder} to create {@link DataPoint} instances.\n     */\n    @Deprecated\n    public DataPoint setTimeInterval(long startTime, long endTime, TimeUnit timeUnit) {\n        this.startTimeNanos = timeUnit.toNanos(startTime);\n        this.timestampNanos = timeUnit.toNanos(endTime);\n        return this;\n    }\n\n    /**\n     * Sets the timestamp of a data point that represent an instantaneous reading, measurement, or input. For data points that represent intervals,\n     * {@link #setTimeInterval(long, long, TimeUnit)} should be used.\n     *\n     * @param timestamp The timestamp in the given unit, representing elapsed time since epoch.\n     * @param timeUnit  The unit of the given timestamp.\n     * @deprecated Use {@link DataPoint.Builder} to create {@link DataPoint} instances.\n     */\n    @Deprecated\n    public DataPoint setTimestamp(long timestamp, TimeUnit timeUnit) {\n        this.timestampNanos = timeUnit.toNanos(timestamp);\n        return this;\n    }\n\n    /**\n     * Creates a new builder for a {@link DataPoint} with the given {@code dataSource}.\n     *\n     * @throws NullPointerException If specified data source is null.\n     */\n    @NonNull\n    public static Builder builder(@NonNull DataSource dataSource) {\n        return new Builder(dataSource);\n    }\n\n    /**\n     * Creates a new data point for the given dataSource. An unset {@link Value} is created for each field of the data source's data type.\n     *\n     * @return An empty data point instance.\n     * @deprecated Use {@link DataPoint.Builder} to create {@link DataPoint} instances.\n     */\n    @NonNull\n    @Deprecated\n    public static DataPoint create(@NonNull DataSource dataSource) {\n        return new DataPoint(dataSource);\n    }\n\n    /**\n     * Extracts a data point from a callback intent received after registering to a data source with a PendingIntent.\n     *\n     * @return The extracted DataPoint, or {@code null} if the given intent does not contain a DataPoint\n     */\n    @Nullable\n    public static DataPoint extract(@NonNull Intent intent) {\n        return SafeParcelableSerializer.deserializeFromBytes(intent.getByteArrayExtra(\"com.google.android.gms.fitness.EXTRA_DATA_POINT\"), CREATOR);\n    }\n\n    /**\n     * Builder for {@link DataPoint} instances.\n     */\n    public static class Builder {\n        private final DataPoint dataPoint;\n        private boolean built = false;\n\n        Builder(DataSource dataSource) {\n            this.dataPoint = DataPoint.create(dataSource);\n        }\n\n        /**\n         * Builds and returns the {@link DataPoint}.\n         */\n        @NonNull\n        public DataPoint build() {\n            if (built) throw new IllegalStateException(\"DataPoint already built\");\n            this.built = true;\n            return this.dataPoint;\n        }\n\n        /**\n         * Sets the value of an activity field to {@code activity}.\n         *\n         * @throws IllegalArgumentException If the given index is out of the range for this data type.\n         * @throws IllegalStateException    If the field isn't of format {@link com.google.android.gms.fitness.data.Field#FORMAT_INT32}.\n         */\n        @NonNull\n        public Builder setActivityField(@NonNull com.google.android.gms.fitness.data.Field field, @NonNull String activity) {\n            if (built) throw new IllegalStateException(\"DataPoint already built\");\n            this.dataPoint.getValue(field).setActivity(activity);\n            return this;\n        }\n\n        /**\n         * Sets the floating point value of the given {@code field} to {@code value}.\n         *\n         * @throws IllegalArgumentException If the given index is out of the range for this data type.\n         * @throws IllegalStateException    If the field isn't of format {@link com.google.android.gms.fitness.data.Field#FORMAT_FLOAT}.\n         */\n        @NonNull\n        public Builder setField(@NonNull com.google.android.gms.fitness.data.Field field, float value) {\n            if (built) throw new IllegalStateException(\"DataPoint already built\");\n            this.dataPoint.getValue(field).setFloat(value);\n            return this;\n        }\n\n\n        /**\n         * Sets the map value of the given {@code field} to {@code value}.\n         *\n         * @throws IllegalArgumentException If the given index is out of the range for this data type.\n         * @throws IllegalStateException    If the field isn't of format {@link com.google.android.gms.fitness.data.Field#FORMAT_MAP}.\n         */\n        @NonNull\n        public Builder setField(@NonNull com.google.android.gms.fitness.data.Field field, @NonNull Map<String, Float> map) {\n            if (built) throw new IllegalStateException(\"DataPoint already built\");\n            this.dataPoint.getValue(field).setMap(map);\n            return this;\n        }\n\n\n        /**\n         * Sets the integer value of the given {@code field} to {@code value}.\n         *\n         * @throws IllegalArgumentException If the given index is out of the range for this data type.\n         * @throws IllegalStateException    If the field isn't of format {@link com.google.android.gms.fitness.data.Field#FORMAT_INT32}.\n         */\n        @NonNull\n        public Builder setField(@NonNull com.google.android.gms.fitness.data.Field field, int value) {\n            if (built) throw new IllegalStateException(\"DataPoint already built\");\n            this.dataPoint.getValue(field).setInt(value);\n            return this;\n        }\n\n        /**\n         * Sets the string value of the given {@code field} to {@code value}.\n         *\n         * @throws IllegalArgumentException If the given index is out of the range for this data type.\n         * @throws IllegalStateException    If the field isn't of format {@link com.google.android.gms.fitness.data.Field#FORMAT_STRING}.\n         */\n        @NonNull\n        public Builder setField(@NonNull com.google.android.gms.fitness.data.Field field, @NonNull String value) {\n            if (built) throw new IllegalStateException(\"DataPoint already built\");\n            this.dataPoint.getValue(field).setString(value);\n            return this;\n        }\n\n        /**\n         * Sets the values of the data point, where the format for all of its values is float.\n         *\n         * @param values The value for each field of the data point, in order.\n         */\n        @NonNull\n        public Builder setFloatValues(@NonNull float... values) {\n            if (built) throw new IllegalStateException(\"DataPoint already built\");\n            this.dataPoint.setFloatValues(values);\n            return this;\n        }\n\n        /**\n         * Sets the values of the data point, where the format for all of its values is int.\n         *\n         * @param values The value for each field of the data point, in order.\n         */\n        @NonNull\n        public Builder setIntValues(@NonNull int... values) {\n            if (built) throw new IllegalStateException(\"DataPoint already built\");\n            this.dataPoint.setIntValues(values);\n            return this;\n        }\n\n        /**\n         * Sets the time interval of a data point that represents an interval of time. For data points that represent instantaneous readings,\n         * {@link #setTimestamp(long, TimeUnit)} should be used.\n         *\n         * @param startTime The start time in the given unit, representing elapsed time since epoch.\n         * @param endTime   The end time in the given unit, representing elapsed time since epoch.\n         * @param timeUnit  The time unit of both start and end timestamps.\n         */\n        @NonNull\n        public Builder setTimeInterval(long startTime, long endTime, @NonNull TimeUnit timeUnit) {\n            if (built) throw new IllegalStateException(\"DataPoint already built\");\n            this.dataPoint.setTimeInterval(startTime, endTime, timeUnit);\n            return this;\n        }\n\n        /**\n         * Sets the timestamp of a data point that represent an instantaneous reading, measurement, or input. For data points that represent intervals,\n         * {@link #setTimeInterval(long, long, TimeUnit)} should be used.\n         *\n         * @param timestamp The timestamp in the given unit, representing elapsed time since epoch.\n         * @param timeUnit  The unit of the given timestamp.\n         */\n        @NonNull\n        public Builder setTimestamp(long timestamp, @NonNull TimeUnit timeUnit) {\n            if (built) throw new IllegalStateException(\"DataPoint already built\");\n            this.dataPoint.setTimestamp(timestamp, timeUnit);\n            return this;\n        }\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<DataPoint> CREATOR = findCreator(DataPoint.class);\n\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/data/DataSet.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fitness.data;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\n/**\n * Represents a fixed set of data points in a data type's stream from a particular data source. A data set usually represents data at\n * fixed time boundaries, and can be used both for batch data insertion and as a result of read requests.\n */\n@SafeParcelable.Class\npublic class DataSet extends AbstractSafeParcelable {\n\n    @Field(1000)\n    final int versionCode;\n    @Field(value = 1, getterName = \"getDataSource\")\n    @NonNull\n    private final DataSource dataSource;\n    @Field(value = 3, getterName = \"getRawDataPoints\")\n    @NonNull\n    private final List<DataPoint> rawDataPoints;\n    @Field(value = 4, getterName = \"getUniqueDataSources\")\n    @NonNull\n    private final List<DataSource> uniqueDataSources;\n\n    @Constructor\n    DataSet(@Param(1000) int versionCode, @Param(1) @NonNull DataSource dataSource, @Param(3) @NonNull List<DataPoint> rawDataPoints, @Param(4) List<DataSource> uniqueDataSources) {\n        this.versionCode = versionCode;\n        this.dataSource = dataSource;\n        this.rawDataPoints = rawDataPoints;\n        this.uniqueDataSources = versionCode < 2 ? Collections.singletonList(dataSource) : uniqueDataSources;\n    }\n\n    DataSet(@NonNull DataSource dataSource) {\n        this.versionCode = 3;\n        this.dataSource = dataSource;\n        this.rawDataPoints = new ArrayList<>();\n        this.uniqueDataSources = new ArrayList<>();\n        uniqueDataSources.add(dataSource);\n    }\n\n    /**\n     * Adds a data point to this data set. The data points should be for the correct data type and data source, and should have its timestamp\n     * already set.\n     *\n     * @throws IllegalArgumentException If dataPoint has invalid data.\n     * @deprecated Build {@link DataSet} instances using the builder.\n     */\n    @Deprecated\n    public void add(@NonNull DataPoint dataPoint) {\n        if (!dataPoint.getDataSource().getStreamIdentifier().equals(dataSource.getStreamIdentifier()))\n            throw new IllegalArgumentException(\"Conflicting data sources found\");\n        // TODO\n        rawDataPoints.add(dataPoint);\n    }\n\n    /**\n     * Adds a list of data points to this data set in bulk. All data points should be for the correct data type and data source, and should have their\n     * timestamp already set.\n     *\n     * @deprecated Build {@link DataSet} instances using the builder.\n     */\n    @Deprecated\n    public void addAll(@NonNull Iterable<DataPoint> iterable) {\n        for (DataPoint dataPoint : iterable) {\n            add(dataPoint);\n        }\n    }\n\n    /**\n     * Creates an empty data point for this data set's data source. The new data point is not added to the data set by this method. After the data\n     * point is initialized, {@link #add(DataPoint)} should be called.\n     */\n    @NonNull\n    public DataPoint createDataPoint() {\n        return DataPoint.create(this.dataSource);\n    }\n\n    /**\n     * Returns the list of data points represented by this data set. The data points will preserve the same order in which they were inserted.\n     * <p>\n     * Certain APIs that return a DataSet might insert data points in chronological order, but this isn't enforced.\n     */\n    @NonNull\n    public List<DataPoint> getDataPoints() {\n        return Collections.unmodifiableList(rawDataPoints);\n    }\n\n    /**\n     * Returns the data source which this data set represents. All of the data points in the data set are from this data source.\n     */\n    @NonNull\n    public DataSource getDataSource() {\n        return dataSource;\n    }\n\n    /**\n     * Returns the data type this data set represents. All of the data points in the data set are of this data type.\n     */\n    @NonNull\n    public DataType getDataType() {\n        return dataSource.getDataType();\n    }\n\n    @NonNull\n    List<DataPoint> getRawDataPoints() {\n        return rawDataPoints;\n    }\n\n    @NonNull\n    List<DataSource> getUniqueDataSources() {\n        return uniqueDataSources;\n    }\n\n    /**\n     * Creates a new builder for a {@link DataSet} with the given {@code dataSource}.\n     *\n     * @throws NullPointerException If specified data source is null.\n     */\n    @NonNull\n    public static Builder builder(@NonNull DataSource dataSource) {\n        return new Builder(dataSource);\n    }\n\n    /**\n     * Creates a new data set to hold data points for the given {@code dataSource}.\n     * <p>\n     * Data points with the matching data source can be created using {@link #createDataPoint()}, and after having the values set added to the data set\n     * via {@link #add(DataPoint)}.\n     *\n     * @throws NullPointerException If specified data source is null.\n     */\n    @NonNull\n    public static DataSet create(@NonNull DataSource dataSource) {\n        return new DataSet(dataSource);\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    /**\n     * Builder used to create new data sets.\n     */\n    public static class Builder {\n        private final DataSet dataSet;\n        private boolean built = false;\n\n        Builder(DataSource dataSource) {\n            this.dataSet = DataSet.create(dataSource);\n        }\n\n        /**\n         * Adds a data point to this data set. The data points should be for the correct data type and data source, and should have its timestamp\n         * already set.\n         *\n         * @throws IllegalArgumentException If dataPoint has the wrong {@link DataSource}, or contain invalid data.\n         */\n        @NonNull\n        public Builder add(@NonNull DataPoint dataPoint) {\n            if (built) throw new IllegalStateException(\"DataSet has already been built.\");\n            this.dataSet.add(dataPoint);\n            return this;\n        }\n\n        /**\n         * Adds a list of data points to this data set in bulk. All data points should be for the correct data type and data source, and should have their\n         * timestamp already set.\n         *\n         * @throws IllegalArgumentException If the {@code dataPoints} have the wrong source, or contain invalid data.\n         */\n        @NonNull\n        public Builder addAll(@NonNull Iterable<DataPoint> iterable) {\n            if (built) throw new IllegalStateException(\"DataSet has already been built.\");\n            this.dataSet.addAll(iterable);\n            return this;\n        }\n\n        /**\n         * Finishes building and returns the {@link DataSet}.\n         *\n         * @throws IllegalStateException If called more than once.\n         */\n        @NonNull\n        public DataSet build() {\n            if (built) throw new IllegalStateException(\"DataSet has already been built.\");\n            this.built = true;\n            return this.dataSet;\n        }\n    }\n\n    public static final SafeParcelableCreatorAndWriter<DataSet> CREATOR = findCreator(DataSet.class);\n\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/data/DataSource.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fitness.data;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableSerializer;\nimport org.microg.gms.common.Constants;\nimport org.microg.gms.utils.ToStringHelper;\n\n/**\n * Definition of a unique source of sensor data. Data sources can expose raw data coming from hardware sensors on local or companion\n * devices. They can also expose derived data, created by transforming or merging other data sources. Multiple data sources can exist for the\n * same data type. Every data point inserted into or read from Google Fit has an associated data source.\n * <p>\n * The data source contains enough information to uniquely identify its data, including the hardware device and the application that\n * collected and/or transformed the data. It also holds useful metadata, such as a stream name and the device type.\n * <p>\n * The data source's data stream can be accessed in a live fashion by registering a data source listener, or via queries over fixed time intervals.\n * <p>\n * An end-user-visible name for the data stream can be set by calling {@link DataSource.Builder.setStreamName(String)} or otherwise computed\n * from the device model and application name.\n */\n@SafeParcelable.Class\npublic class DataSource extends AbstractSafeParcelable {\n\n    /**\n     * Name for the parcelable intent extra containing a data source. It can be extracted using {@link #extract(Intent)}.\n     */\n    public static final String EXTRA_DATA_SOURCE = \"vnd.google.fitness.data_source\";\n\n    /**\n     * Type constant for a data source which exposes original, raw data from an external source such as a hardware sensor, a wearable device, or\n     * user input.\n     */\n    public static final int TYPE_RAW = 0;\n\n    /**\n     * Type constant for a data source which exposes data which is derived from one or more existing data sources by performing\n     * transformations on the original data.\n     */\n    public static final int TYPE_DERIVED = 1;\n\n    @Field(value = 1, getterName = \"getDataType\")\n    @NonNull\n    private final DataType dataType;\n    @Field(value = 3, getterName = \"getType\")\n    private final int type;\n    @Field(value = 4, getterName = \"getDevice\")\n    @Nullable\n    private final Device device;\n    @Field(value = 5, getterName = \"getApplication\")\n    @Nullable\n    final Application application;\n    @Field(value = 6, getterName = \"getStreamName\")\n    private final String streamName;\n\n    @Constructor\n    DataSource(@Param(1) @NonNull DataType dataType, @Param(3) int type, @Param(4) @Nullable Device device, @Param(5) @Nullable Application application, @Param(6) String streamName) {\n        this.dataType = dataType;\n        this.type = type;\n        this.device = device;\n        this.application = application;\n        this.streamName = streamName;\n    }\n\n    @Nullable\n    public Application getApplication() {\n        return application;\n    }\n\n    /**\n     * Returns the package name for the application responsible for setting the data, or {@code null} if unset/unknown. {@link PackageManager} can be used to\n     * query relevant information about the application, such as the name, icon, and logo.\n     * <p>\n     * Data coming from local sensors or BLE devices will not have a corresponding application.\n     */\n    @Nullable\n    public String getAppPackageName() {\n        if (application == null) return null;\n        return application.getPackageName();\n    }\n\n    /**\n     * Returns the data type for data coming from this data source. Knowing the type of a data source can be useful to perform transformations on\n     * top of raw data without using sources that are themselves computed by transforming raw data.\n     */\n    @NonNull\n    public DataType getDataType() {\n        return dataType;\n    }\n\n    /**\n     * Returns the device where data is being collected, or {@code null} if unset.\n     */\n    @Nullable\n    public Device getDevice() {\n        return device;\n    }\n\n    /**\n     * Returns a unique identifier for the data stream produced by this data source. The identifier includes, in order:\n     * <ol>\n     * <li>the data source's type (raw or derived)</li>\n     * <li>the data source's data type</li>\n     * <li>the application's package name (unique for a given application)</li>\n     * <li>the physical device's manufacturer, model, and serial number (UID)</li>\n     * <li>the data source's stream name.</li>\n     * </ol>\n     */\n    @NonNull\n    public String getStreamIdentifier() {\n        StringBuilder sb = new StringBuilder();\n        sb.append(type == TYPE_RAW ? \"raw\" : \"derived\");\n        sb.append(\":\").append(dataType.getName());\n        if (application != null) sb.append(\":\").append(application.getPackageName());\n        if (device != null) sb.append(\":\").append(device.getDeviceId());\n        if (streamName != null) sb.append(\":\").append(streamName);\n        return sb.toString();\n    }\n\n    /**\n     * Returns the specific stream name for the stream coming from this data source, or an empty string if unset.\n     */\n    @NonNull\n    public String getStreamName() {\n        return streamName;\n    }\n\n    /**\n     * Returns the constant describing the type of this data source.\n     *\n     * @return One of the constant values ({@link #TYPE_DERIVED} or {@link #TYPE_RAW}), zero if unset. Values outside of this range should be treated as\n     * unset/unknown.\n     */\n    public int getType() {\n        return type;\n    }\n\n    @Override\n    public int hashCode() {\n        return getStreamIdentifier().hashCode();\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"DataSource\").value(getStreamIdentifier()).end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    /**\n     * Extracts the data source extra from the given intent, such as an intent to view user's data.\n     *\n     * @return The data source, or {@code null} if not found.\n     */\n    @Nullable\n    public static DataSource extract(@NonNull Intent intent) {\n        return SafeParcelableSerializer.deserializeFromBytes(intent.getByteArrayExtra(EXTRA_DATA_SOURCE), CREATOR);\n    }\n\n    /**\n     * A builder that can be used to construct new data source objects. In general, a built data source should be saved in memory to avoid the cost\n     * of re-constructing it for every request.\n     */\n    public static class Builder {\n        private DataType dataType;\n        private Device device;\n        private Application application;\n        private int type = -1;\n        private String streamName = \"\";\n\n        /**\n         * Finishes building the data source and returns a DataSource object.\n         *\n         * @throws IllegalStateException If the builder didn't have enough data to build a valid data source.\n         */\n        @NonNull\n        public DataSource build() {\n            if (dataType == null) throw new IllegalStateException(\"dataType must be set\");\n            if (type < 0) throw new IllegalStateException(\"type must be set\");\n            return new DataSource(dataType, type, device, application, streamName);\n        }\n\n        /**\n         * Sets the package name for the application that is recording or computing the data. Used for data sources that aren't built into the platform\n         * (local sensors and BLE sensors are built-in). It can be used to identify the data source, to disambiguate between data from different\n         * applications, and also to link back to the original application for a detailed view.\n         */\n        @NonNull\n        public Builder setAppPackageName(@NonNull String packageName) {\n            Application application = Application.GMS_APP;\n            this.application = Constants.GMS_PACKAGE_NAME.equals(packageName) ? Application.GMS_APP : new Application(packageName);\n            return this;\n        }\n\n        /**\n         * Sets the package name for the application that is recording or computing the data based on the app's context. This method should be\n         * preferred when an application is creating a data source that represents its own data. When creating a data source to query data from other\n         * apps, {@link #setAppPackageName(String)} should be used.\n         */\n        @NonNull\n        public Builder setAppPackageName(@NonNull Context appContext) {\n            setAppPackageName(appContext.getPackageName());\n            return this;\n        }\n\n        /**\n         * Sets the data type for the data source. Every data source is required to have a data type.\n         *\n         * @param dataType One of the data types defined in {@link DataType}, or a custom data type.\n         */\n        @NonNull\n        public Builder setDataType(@NonNull DataType dataType) {\n            this.dataType = dataType;\n            return this;\n        }\n\n        /**\n         * Sets the integrated device where data is being recorded (for instance, a phone that has sensors, or a wearable). Can be useful to identify the\n         * data source, and to disambiguate between data from different devices. If the data is coming from the local device, use\n         * {@link Device#getLocalDevice(Context)}.\n         * <p>\n         * Note that it may be useful to set the device even if the data is not coming from a hardware sensor on the device. For instance, if the user\n         * installs an application which generates sensor data in two separate devices, the only way to differentiate the two data sources is using the\n         * device. This can be specially important if both devices are used at the same time.\n         */\n        @NonNull\n        public Builder setDevice(@NonNull Device device) {\n            this.device = device;\n            return this;\n        }\n\n        /**\n         * The stream name uniquely identifies this particular data source among other data sources of the same type from the same underlying\n         * producer. Setting the stream name is optional, but should be done whenever an application exposes two streams for the same data type, or\n         * when a device has two equivalent sensors.\n         * <p>\n         * The stream name is used by {@link DataSource#getStreamIdentifier()} to make sure the different streams are properly separated when\n         * querying or persisting data.\n         *\n         * @throws IllegalArgumentException If the specified stream name is null.\n         */\n        @NonNull\n        public Builder setStreamName(@NonNull String streamName) {\n            //noinspection ConstantValue\n            if (streamName == null) throw new IllegalArgumentException(\"streamName must be set\");\n            this.streamName = streamName;\n            return this;\n        }\n\n        /**\n         * Sets the type of the data source. {@link DataSource#TYPE_DERIVED} should be used if any other data source is used in generating the data.\n         * {@link DataSource#TYPE_RAW} should be used if the data comes completely from outside of Google Fit.\n         */\n        @NonNull\n        public Builder setType(int type) {\n            this.type = type;\n            return this;\n        }\n    }\n\n    public static final SafeParcelableCreatorAndWriter<DataSource> CREATOR = findCreator(DataSource.class);\n\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/data/DataType.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fitness.data;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\nimport static com.google.android.gms.fitness.data.Field.*;\n\n/**\n * The data type defines the schema for a stream of data being collected by, inserted into, or queried from Google Fit. The data type defines\n * only the representation and format of the data, and not how it's being collected, the sensor being used, or the parameters of the collection.\n * <p>\n * A data type contains one or more fields. In case of multi-dimensional data (such as location with latitude, longitude, and accuracy) each\n * field represents one dimension. Each data type field has a unique name which identifies it. The field also defines the format of the data\n * (such as int or float).\n * <p>\n * The data types in the {@code com.google} namespace are shared with any app with the user consent. These are fixed and can only be updated in\n * new releases of the platform. This class contains constants representing each of the {@code com.google} data types, each prefixed with {@code TYPE_}.\n * Custom data types can be accessed via the {@link ConfigClient}.\n * <p>\n * Certain data types can represent aggregates, and can be computed as part of read requests by calling\n * {@link DataReadRequest.Builder#aggregate(DataType)}. This class contains constants for all the valid aggregates, each prefixed with\n * {@code AGGREGATE_}. The aggregates for each input type can be queried via {@link #getAggregatesForInput(DataType)}.\n */\n@SafeParcelable.Class\npublic class DataType extends AbstractSafeParcelable {\n    /**\n     * The common prefix for data type MIME types, for use in intents. The MIME type for a particular data type will be this prefix followed by\n     * the data type name.\n     * <p>\n     * The data type's name is returned by {@link #getName()}. The full MIME type can be computed by {@link #getMimeType(DataType)}.\n     */\n    public static final String MIME_TYPE_PREFIX = \"vnd.google.fitness.data_type/\";\n\n    public static final DataType TYPE_ACTIVITY_SEGMENT = new DataType(\"com.google.activity.segment\", \"https://www.googleapis.com/auth/fitness.activity.read\", \"https://www.googleapis.com/auth/fitness.activity.write\", FIELD_ACTIVITY);\n    public static final DataType TYPE_BASAL_METABOLIC_RATE = new DataType(\"com.google.calories.bmr\", \"https://www.googleapis.com/auth/fitness.activity.read\", \"https://www.googleapis.com/auth/fitness.activity.write\", FIELD_CALORIES);\n    public static final DataType TYPE_BODY_FAT_PERCENTAGE = new DataType(\"com.google.body.fat.percentage\", \"https://www.googleapis.com/auth/fitness.body.read\", \"https://www.googleapis.com/auth/fitness.body.write\", FIELD_PERCENTAGE);\n    public static final DataType TYPE_CALORIES_EXPENDED = new DataType(\"com.google.calories.expended\", \"https://www.googleapis.com/auth/fitness.activity.read\", \"https://www.googleapis.com/auth/fitness.activity.write\", FIELD_CALORIES);\n    public static final DataType TYPE_CYCLING_PEDALING_CADENCE = new DataType(\"com.google.cycling.pedaling.cadence\", \"https://www.googleapis.com/auth/fitness.activity.read\", \"https://www.googleapis.com/auth/fitness.activity.write\", FIELD_RPM);\n    public static final DataType TYPE_CYCLING_PEDALING_CUMULATIVE = new DataType(\"com.google.cycling.pedaling.cumulative\", \"https://www.googleapis.com/auth/fitness.activity.read\", \"https://www.googleapis.com/auth/fitness.activity.write\", FIELD_REVOLUTIONS);\n    public static final DataType TYPE_CYCLING_WHEEL_REVOLUTION = new DataType(\"com.google.cycling.wheel_revolution.cumulative\", \"https://www.googleapis.com/auth/fitness.location.read\", \"https://www.googleapis.com/auth/fitness.location.write\", FIELD_REVOLUTIONS);\n    public static final DataType TYPE_CYCLING_WHEEL_RPM = new DataType(\"com.google.cycling.wheel_revolution.rpm\", \"https://www.googleapis.com/auth/fitness.location.read\", \"https://www.googleapis.com/auth/fitness.location.write\", FIELD_RPM);\n    public static final DataType TYPE_DISTANCE_DELTA = new DataType(\"com.google.distance.delta\", \"https://www.googleapis.com/auth/fitness.location.read\", \"https://www.googleapis.com/auth/fitness.location.write\", FIELD_DISTANCE);\n    public static final DataType TYPE_HEART_POINTS = new DataType(\"com.google.heart_minutes\", \"https://www.googleapis.com/auth/fitness.activity.read\", \"https://www.googleapis.com/auth/fitness.activity.write\", FIELD_INTENSITY);\n    public static final DataType TYPE_HEART_RATE_BPM = new DataType(\"com.google.heart_rate.bpm\", \"https://www.googleapis.com/auth/fitness.heart_rate.read\", \"https://www.googleapis.com/auth/fitness.heart_rate.write\", FIELD_BPM);\n    public static final DataType TYPE_HEIGHT = new DataType(\"com.google.height\", \"https://www.googleapis.com/auth/fitness.body.read\", \"https://www.googleapis.com/auth/fitness.body.write\", FIELD_HEIGHT);\n    public static final DataType TYPE_HYDRATION = new DataType(\"com.google.hydration\", \"https://www.googleapis.com/auth/fitness.nutrition.read\", \"https://www.googleapis.com/auth/fitness.nutrition.write\", FIELD_VOLUME);\n    public static final DataType TYPE_LOCATION_SAMPLE = new DataType(\"com.google.location.sample\", \"https://www.googleapis.com/auth/fitness.location.read\", \"https://www.googleapis.com/auth/fitness.location.write\", FIELD_LATITUDE, FIELD_LONGITUDE, FIELD_ACCURACY, FIELD_ALTITUDE);\n    @Deprecated\n    public static final DataType TYPE_LOCATION_TRACK = new DataType(\"com.google.location.track\", \"https://www.googleapis.com/auth/fitness.location.read\", \"https://www.googleapis.com/auth/fitness.location.write\", FIELD_LATITUDE, FIELD_LONGITUDE, FIELD_ACCURACY, FIELD_ALTITUDE);\n    public static final DataType TYPE_MOVE_MINUTES = new DataType(\"com.google.active_minutes\", \"https://www.googleapis.com/auth/fitness.activity.read\", \"https://www.googleapis.com/auth/fitness.activity.write\", FIELD_DURATION);\n    public static final DataType TYPE_NUTRITION = new DataType(\"com.google.nutrition\", \"https://www.googleapis.com/auth/fitness.nutrition.read\", \"https://www.googleapis.com/auth/fitness.nutrition.write\", FIELD_NUTRIENTS, FIELD_MEAL_TYPE, FIELD_FOOD_ITEM);\n    public static final DataType TYPE_POWER_SAMPLE = new DataType(\"com.google.power.sample\", \"https://www.googleapis.com/auth/fitness.activity.read\", \"https://www.googleapis.com/auth/fitness.activity.write\", FIELD_WATTS);\n    public static final DataType TYPE_SLEEP_SEGMENT = new DataType(\"com.google.sleep.segment\", \"https://www.googleapis.com/auth/fitness.sleep.read\", \"https://www.googleapis.com/auth/fitness.sleep.write\", FIELD_SLEEP_SEGMENT_TYPE);\n    public static final DataType TYPE_SPEED = new DataType(\"com.google.speed\", \"https://www.googleapis.com/auth/fitness.location.read\", \"https://www.googleapis.com/auth/fitness.location.write\", FIELD_SPEED);\n    public static final DataType TYPE_STEP_COUNT_CADENCE = new DataType(\"com.google.step_count.cadence\", \"https://www.googleapis.com/auth/fitness.activity.read\", \"https://www.googleapis.com/auth/fitness.activity.write\", FIELD_RPM);\n    public static final DataType TYPE_STEP_COUNT_DELTA = new DataType(\"com.google.step_count.delta\", \"https://www.googleapis.com/auth/fitness.activity.read\", \"https://www.googleapis.com/auth/fitness.activity.write\", FIELD_STEPS);\n    public static final DataType TYPE_WEIGHT = new DataType(\"com.google.weight\", \"https://www.googleapis.com/auth/fitness.body.read\", \"https://www.googleapis.com/auth/fitness.body.write\", FIELD_WEIGHT);\n    public static final DataType TYPE_WORKOUT_EXERCISE = new DataType(\"com.google.activity.exercise\", \"https://www.googleapis.com/auth/fitness.activity.read\", \"https://www.googleapis.com/auth/fitness.activity.write\", FIELD_EXERCISE, FIELD_REPETITIONS, FIELD_DURATION_OPTIONAL, FIELD_RESISTANCE_TYPE, FIELD_RESISTANCE);\n\n    public static final DataType TYPE_DEVICE_ON_BODY = new DataType(\"com.google.device_on_body\", \"https://www.googleapis.com/auth/fitness.activity.read\", \"https://www.googleapis.com/auth/fitness.activity.write\", FIELD_PROBABILITY);\n    public static final DataType TYPE_INTERNAL_GOAL = new DataType(\"com.google.internal.goal\", \"https://www.googleapis.com/auth/fitness.activity.read\", \"https://www.googleapis.com/auth/fitness.activity.write\", FIELD_FITNESS_GOAL_V2);\n    public static final DataType TYPE_MET = new DataType(\"com.google.internal.met\", \"https://www.googleapis.com/auth/fitness.location.read\", \"https://www.googleapis.com/auth/fitness.location.write\", FIELD_MET);\n    public static final DataType TYPE_PACED_WALKING_ATTRIBUTES = new DataType(\"com.google.internal.paced_walking_attributes\", \"https://www.googleapis.com/auth/fitness.activity.read\", \"https://www.googleapis.com/auth/fitness.activity.write\", FIELD_FITNESS_PACED_WALKING_ATTRIBUTES);\n    public static final DataType TYPE_RESPIRATORY_RATE = new DataType(\"com.google.respiratory_rate\", \"https://www.googleapis.com/auth/fitness.respiratory_rate.read\", \"https://www.googleapis.com/auth/fitness.respiratory_rate.write\", FIELD_RESPIRATORY_RATE);\n    public static final DataType TYPE_SENSOR_EVENTS = new DataType(\"com.google.sensor.events\", \"https://www.googleapis.com/auth/fitness.activity.read\", \"https://www.googleapis.com/auth/fitness.activity.write\", FIELD_SENSOR_TYPE, FIELD_TIMESTAMPS, FIELD_SENSOR_VALUES);\n    public static final DataType TYPE_SLEEP_ATTRIBUTES = new DataType(\"com.google.internal.sleep_attributes\", \"https://www.googleapis.com/auth/fitness.sleep.read\", \"https://www.googleapis.com/auth/fitness.sleep.write\", FIELD_FITNESS_SLEEP_ATTRIBUTES);\n    public static final DataType TYPE_SLEEP_SCHEDULE = new DataType(\"com.google.internal.sleep_schedule\", \"https://www.googleapis.com/auth/fitness.sleep.read\", \"https://www.googleapis.com/auth/fitness.sleep.write\", FIELD_FITNESS_SLEEP_SCHEDULE);\n    public static final DataType TYPE_STEP_COUNT_CUMULATIVE = new DataType(\"com.google.step_count.cumulative\", \"https://www.googleapis.com/auth/fitness.activity.read\", \"https://www.googleapis.com/auth/fitness.activity.write\", FIELD_STEPS);\n    public static final DataType TYPE_TIME_ZONE_CHANGE = new DataType(\"com.google.time_zone_change\", \"https://www.googleapis.com/auth/fitness.location.read\", \"https://www.googleapis.com/auth/fitness.location.write\", FIELD_ZONE_ID);\n    public static final DataType TYPE_WORKOUT_SAMPLES = new DataType(\"com.google.activity.samples\", \"https://www.googleapis.com/auth/fitness.activity.read\", \"https://www.googleapis.com/auth/fitness.activity.write\", FIELD_ACTIVITY_CONFIDENCE);\n\n\n    public static final DataType AGGREGATE_ACTIVITY_SUMMARY = new DataType(\"com.google.activity.summary\", \"https://www.googleapis.com/auth/fitness.activity.read\", \"https://www.googleapis.com/auth/fitness.activity.write\", FIELD_ACTIVITY, FIELD_DURATION, FIELD_NUM_SEGMENTS);\n    public static final DataType AGGREGATE_BASAL_METABOLIC_RATE_SUMMARY = new DataType(\"com.google.calories.bmr.summary\", \"https://www.googleapis.com/auth/fitness.activity.read\", \"https://www.googleapis.com/auth/fitness.activity.write\", FIELD_AVERAGE, FIELD_MAX, FIELD_MIN);\n    public static final DataType AGGREGATE_BODY_FAT_PERCENTAGE_SUMMARY = new DataType(\"com.google.body.fat.percentage.summary\", \"https://www.googleapis.com/auth/fitness.body.read\", \"https://www.googleapis.com/auth/fitness.body.write\", FIELD_AVERAGE, FIELD_MAX, FIELD_MIN);\n    public static final DataType AGGREGATE_CALORIES_EXPENDED = TYPE_CALORIES_EXPENDED;\n    public static final DataType AGGREGATE_DISTANCE_DELTA = TYPE_DISTANCE_DELTA;\n    public static final DataType AGGREGATE_HEART_POINTS = new DataType(\"com.google.heart_minutes.summary\", \"https://www.googleapis.com/auth/fitness.activity.read\", \"https://www.googleapis.com/auth/fitness.activity.write\", FIELD_INTENSITY, FIELD_DURATION);\n    public static final DataType AGGREGATE_HEART_RATE_SUMMARY = new DataType(\"com.google.heart_rate.summary\", \"https://www.googleapis.com/auth/fitness.heart_rate.read\", \"https://www.googleapis.com/auth/fitness.heart_rate.write\", FIELD_AVERAGE, FIELD_MAX, FIELD_MIN);\n    public static final DataType AGGREGATE_HEIGHT_SUMMARY = new DataType(\"com.google.height.summary\", \"https://www.googleapis.com/auth/fitness.body.read\", \"https://www.googleapis.com/auth/fitness.body.write\", FIELD_AVERAGE, FIELD_MAX, FIELD_MIN);\n    public static final DataType AGGREGATE_HYDRATION = TYPE_HYDRATION;\n    public static final DataType AGGREGATE_LOCATION_BOUNDING_BOX = new DataType(\"com.google.location.bounding_box\", \"https://www.googleapis.com/auth/fitness.location.read\", \"https://www.googleapis.com/auth/fitness.location.write\", FIELD_LOW_LATITUDE, FIELD_LOW_LONGITUDE, FIELD_HIGH_LATITUDE, FIELD_HIGH_LONGITUDE);\n    public static final DataType AGGREGATE_MOVE_MINUTES = TYPE_MOVE_MINUTES;\n    public static final DataType AGGREGATE_NUTRITION_SUMMARY = new DataType(\"com.google.nutrition.summary\", \"https://www.googleapis.com/auth/fitness.nutrition.read\", \"https://www.googleapis.com/auth/fitness.nutrition.write\", FIELD_NUTRIENTS, FIELD_MEAL_TYPE);\n    public static final DataType AGGREGATE_POWER_SUMMARY = new DataType(\"com.google.power.summary\", \"https://www.googleapis.com/auth/fitness.activity.read\", \"https://www.googleapis.com/auth/fitness.activity.write\", FIELD_AVERAGE, FIELD_MAX, FIELD_MIN);\n    public static final DataType AGGREGATE_SPEED_SUMMARY = new DataType(\"com.google.speed.summary\", \"https://www.googleapis.com/auth/fitness.location.read\", \"https://www.googleapis.com/auth/fitness.location.write\", FIELD_AVERAGE, FIELD_MAX, FIELD_MIN);\n    public static final DataType AGGREGATE_STEP_COUNT_DELTA = TYPE_STEP_COUNT_DELTA;\n    public static final DataType AGGREGATE_WEIGHT_SUMMARY = new DataType(\"com.google.weight.summary\", \"https://www.googleapis.com/auth/fitness.body.read\", \"https://www.googleapis.com/auth/fitness.body.write\", FIELD_AVERAGE, FIELD_MAX, FIELD_MIN);\n\n    @Field(value = 1, getterName = \"getName\")\n    @NonNull\n    private final String name;\n    @Field(value = 2, getterName = \"getFields\")\n    @NonNull\n    private final List<com.google.android.gms.fitness.data.Field> fields;\n    @Field(3)\n    @Nullable\n    final String readScope;\n    @Field(4)\n    @Nullable\n    final String writeScope;\n\n    DataType(@NonNull String name, @Nullable String readScope, @Nullable String writeScope, com.google.android.gms.fitness.data.Field... fields) {\n        this.name = name;\n        this.readScope = readScope;\n        this.writeScope = writeScope;\n        this.fields = Collections.unmodifiableList(Arrays.asList(fields));\n    }\n\n    @Constructor\n    DataType(@Param(1) @NonNull String name, @Param(2) @NonNull List<com.google.android.gms.fitness.data.Field> fields, @Param(3) @Nullable String readScope, @Param(4) @Nullable String writeScope) {\n        this.name = name;\n        this.fields = fields;\n        this.readScope = readScope;\n        this.writeScope = writeScope;\n    }\n\n    /**\n     * Returns the aggregate output type for this type, or {@code null} if the type does not support aggregation.\n     * <p>\n     * To check if a data type is supported for aggregation, check that the returned type is non-null.\n     */\n    @Nullable\n    public DataType getAggregateType() {\n        // TODO\n        return null;\n    }\n\n    /**\n     * Returns the ordered list of fields for the data type.\n     */\n    @NonNull\n    public List<com.google.android.gms.fitness.data.Field> getFields() {\n        return fields;\n    }\n\n    /**\n     * Returns the namespaced name which uniquely identifies this data type.\n     */\n    @NonNull\n    public String getName() {\n        return name;\n    }\n\n    /**\n     * Returns the index of a field.\n     *\n     * @throws IllegalArgumentException If field isn't defined for this data type.\n     */\n    public int indexOf(@NonNull com.google.android.gms.fitness.data.Field field) {\n        int indexOf = this.fields.indexOf(field);\n        if (indexOf < 0) throw new IllegalArgumentException(\"Field not found\");\n        return indexOf;\n    }\n\n    /**\n     * Returns a list of output aggregate data types for the specified {@code inputDataType}.\n     * <p>\n     * To check if a data type is supported for aggregation, check that the returned list is not empty\n     * {@code DataType.getAggregatesForInput(dataType).isEmpty()}.\n     *\n     * @deprecated Use {@link #getAggregateType()} instead.\n     */\n    @NonNull\n    @Deprecated\n    public static List<DataType> getAggregatesForInput(@NonNull DataType inputDataType) {\n        DataType aggregateType = inputDataType.getAggregateType();\n        if (aggregateType == null) return Collections.emptyList();\n        return Collections.singletonList(aggregateType);\n    }\n\n    /**\n     * Returns the MIME type for a particular {@link DataType}. The MIME type is used in intents such as the data view intent.\n     */\n    @NonNull\n    public static String getMimeType(@NonNull DataType dataType) {\n        return MIME_TYPE_PREFIX + dataType.getName();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<DataType> CREATOR = findCreator(DataType.class);\n\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/data/Device.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fitness.data;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.content.pm.PackageManager;\nimport android.content.res.Configuration;\nimport android.os.Parcel;\n\nimport android.provider.Settings;\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport static android.os.Build.VERSION.SDK_INT;\n\n/**\n * Representation of an integrated device (such as a phone or a wearable) that can hold sensors. Each sensor is exposed as a {@link DataSource}.\n */\n@SafeParcelable.Class\npublic class Device extends AbstractSafeParcelable {\n\n    /**\n     * Constant indicating the device type is not known.\n     */\n    public static final int TYPE_UNKNOWN = 0;\n    /**\n     * Constant indicating the device is an Android phone.\n     */\n    public static final int TYPE_PHONE = 1;\n    /**\n     * Constant indicating the device is an Android tablet.\n     */\n    public static final int TYPE_TABLET = 2;\n    /**\n     * Constant indicating the device is a watch or other wrist-mounted band.\n     */\n    public static final int TYPE_WATCH = 3;\n    /**\n     * Constant indicating the device is a chest strap.\n     */\n    public static final int TYPE_CHEST_STRAP = 4;\n    /**\n     * Constant indicating the device is a scale or similar device the user steps on.\n     */\n    public static final int TYPE_SCALE = 5;\n    /**\n     * Constant indicating the device is a headset, pair of glasses, or other head-mounted device\n     */\n    public static final int TYPE_HEAD_MOUNTED = 6;\n\n    @Field(value = 1, getterName = \"getManufacturer\")\n    @NonNull\n    private final String manufacturer;\n    @Field(value = 2, getterName = \"getModel\")\n    @NonNull\n    private final String model;\n    @Field(value = 4, getterName = \"getUid\")\n    @NonNull\n    private final String uid;\n    @Field(value = 5, getterName = \"getType\")\n    private final int type;\n    @Field(value = 6, getterName = \"getPlatformType\")\n    private final int platformType;\n\n    @Constructor\n    Device(@NonNull @Param(1) String manufacturer, @NonNull @Param(2) String model, @NonNull @Param(4) String uid, @Param(5) int type, @Param(6) int platformType) {\n        this.manufacturer = manufacturer;\n        this.model = model;\n        this.uid = uid;\n        this.type = type;\n        this.platformType = platformType;\n    }\n\n    /**\n     * Creates a new device.\n     *\n     * @param manufacturer The manufacturer of the product/hardware.\n     * @param model        The end-user-visible name for the end product.\n     * @param uid          A serial number or other unique identifier for the particular device hardware.\n     * @param type         The type of device. One of the type constants.\n     */\n    public Device(@NonNull String manufacturer, @NonNull String model, @NonNull String uid, int type) {\n        this(manufacturer, model, uid, type, 0);\n    }\n\n    /**\n     * Returns the manufacturer of the product/hardware.\n     */\n    @NonNull\n    public String getManufacturer() {\n        return manufacturer;\n    }\n\n    /**\n     * Returns the end-user-visible model name for the device.\n     */\n    @NonNull\n    public String getModel() {\n        return model;\n    }\n\n    /**\n     * Returns the constant representing the type of the device. This will usually be one of the values from the type constants in this class, but it's\n     * not required to be. Any other value should be treated as {@link #TYPE_UNKNOWN}.\n     */\n    public int getType() {\n        return type;\n    }\n\n    /**\n     * Returns the serial number or other unique ID for the hardware.\n     * <p>\n     * Device UIDs are obfuscated based on the calling application's package name. Different applications will see different UIDs for the same\n     * {@link Device}. If two {@link Device} instances have the same underlying UID, they'll also have the same obfuscated UID within each app (but not across\n     * apps).\n     */\n    @NonNull\n    public String getUid() {\n        return uid;\n    }\n\n    String getDeviceId() {\n        return manufacturer + \":\" + model + \":\" + uid;\n    }\n\n    int getPlatformType() {\n        return platformType;\n    }\n\n    /**\n     * Returns the Device representation of the local device, which can be used when defining local data sources.\n     *\n     * @noinspection deprecation\n     */\n    public static Device getLocalDevice(Context context) {\n        @SuppressLint(\"HardwareIds\") String uid = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);\n        int type = TYPE_PHONE;\n        Configuration configuration = context.getResources().getConfiguration();\n        PackageManager packageManager = context.getPackageManager();\n        if (SDK_INT >= 20 && packageManager.hasSystemFeature(PackageManager.FEATURE_WATCH))\n            type = TYPE_WATCH;\n        else if (packageManager.hasSystemFeature(PackageManager.FEATURE_TELEVISION) || packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK))\n            type = TYPE_UNKNOWN; // TV\n        else if (packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE))\n            type = TYPE_UNKNOWN; // Car\n        else if ((configuration.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) > Configuration.SCREENLAYOUT_SIZE_LARGE && configuration.smallestScreenWidthDp >= 600)\n            type = TYPE_TABLET;\n        else if (android.os.Build.PRODUCT.startsWith(\"glass_\"))\n            type = TYPE_HEAD_MOUNTED;\n        return new Device(android.os.Build.MANUFACTURER, android.os.Build.MODEL, uid, type, 2);\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"Device\").value(getDeviceId() + \":\" + type + \":\" + platformType).end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<Device> CREATOR = findCreator(Device.class);\n\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/data/Field.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fitness.data;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\n\n/**\n * A field represents one dimension of a data type. It defines the name and format of data. Unlike data type names, field names are not\n * namespaced, and only need to be unique within the data type.\n * <p>\n * This class contains constants representing the field names of common data types, each prefixed with {@code FIELD_}. These can be used to\n * access and set the fields via {@link DataPoint#getValue(com.google.android.gms.fitness.data.Field)}.\n * <p>\n * Fields for custom data types can be created using {@link DataTypeCreateRequest.Builder#addField(String, int)}.\n */\n@SafeParcelable.Class\npublic class Field extends AbstractSafeParcelable {\n\n    /**\n     * Format constant indicating the field holds integer values.\n     */\n    public static final int FORMAT_INT32 = 1;\n    /**\n     * Format constant indicating the field holds float values.\n     */\n    public static final int FORMAT_FLOAT = 2;\n    /**\n     * Format constant indicating the field holds string values. Strings should be kept small whenever possible. Data streams with large string\n     * values and high data frequency may be down sampled.\n     */\n    public static final int FORMAT_STRING = 3;\n    /**\n     * Format constant indicating the field holds a map of string keys to values. The valid key space and units for the corresponding value should\n     * be documented as part of the data type definition.\n     * <p>\n     * Map values can be set using {@link DataPoint.Builder#setField(com.google.android.gms.fitness.data.Field, java.util.Map)}.\n     * <p>\n     * Keys should be kept small whenever possible. Data streams with large keys and high data frequency may be down sampled.\n     */\n    public static final int FORMAT_MAP = 4;\n\n    public static final int FORMAT_LONG = 5;\n    public static final int FORMAT_DOUBLE = 6;\n    public static final int FORMAT_OBJECT = 7;\n\n    /**\n     * Meal type constant representing that the meal type is unknown.\n     */\n    public static final int MEAL_TYPE_UNKNOWN = 0;\n    /**\n     * Meal type constant representing a breakfast meal.\n     */\n    public static final int MEAL_TYPE_BREAKFAST = 1;\n    /**\n     * Meal type constant representing a lunch meal.\n     */\n    public static final int MEAL_TYPE_LUNCH = 2;\n    /**\n     * Meal type constant representing a dinner meal.\n     */\n    public static final int MEAL_TYPE_DINNER = 3;\n    /**\n     * Meal type constant representing a snack meal.\n     */\n    public static final int MEAL_TYPE_SNACK = 4;\n    /**\n     * Calcium amount in milligrams.\n     */\n    @NonNull\n    public static final String NUTRIENT_CALCIUM = \"calcium\";\n    /**\n     * Calories in kcal.\n     */\n    @NonNull\n    public static final String NUTRIENT_CALORIES = \"calories\";\n    /**\n     * Cholesterol in milligrams.\n     */\n    @NonNull\n    public static final String NUTRIENT_CHOLESTEROL = \"cholesterol\";\n    /**\n     * Dietary fiber in grams.\n     */\n    @NonNull\n    public static final String NUTRIENT_DIETARY_FIBER = \"dietary_fiber\";\n    /**\n     * Iron amount in milligrams.\n     */\n    @NonNull\n    public static final String NUTRIENT_IRON = \"iron\";\n    /**\n     * Monounsaturated fat in grams.\n     */\n    @NonNull\n    public static final String NUTRIENT_MONOUNSATURATED_FAT = \"fat.monounsaturated\";\n    /**\n     * Polyunsaturated fat in grams.\n     */\n    @NonNull\n    public static final String NUTRIENT_POLYUNSATURATED_FAT = \"fat.polyunsaturated\";\n    /**\n     * Potassium in milligrams.\n     */\n    @NonNull\n    public static final String NUTRIENT_POTASSIUM = \"potassium\";\n    /**\n     * Protein amount in grams.\n     */\n    @NonNull\n    public static final String NUTRIENT_PROTEIN = \"protein\";\n    /**\n     * Saturated fat in grams.\n     */\n    @NonNull\n    public static final String NUTRIENT_SATURATED_FAT = \"fat.saturated\";\n    /**\n     * Sodium in milligrams.\n     */\n    @NonNull\n    public static final String NUTRIENT_SODIUM = \"sodium\";\n    /**\n     * Sugar amount in grams.\n     */\n    @NonNull\n    public static final String NUTRIENT_SUGAR = \"sugar\";\n    /**\n     * Total carbohydrates in grams.\n     */\n    @NonNull\n    public static final String NUTRIENT_TOTAL_CARBS = \"carbs.total\";\n    /**\n     * Total fat in grams.\n     */\n    @NonNull\n    public static final String NUTRIENT_TOTAL_FAT = \"fat.total\";\n    /**\n     * Trans fat in grams.\n     */\n    @NonNull\n    public static final String NUTRIENT_TRANS_FAT = \"fat.trans\";\n    /**\n     * Unsaturated fat in grams.\n     */\n    @NonNull\n    public static final String NUTRIENT_UNSATURATED_FAT = \"fat.unsaturated\";\n    /**\n     * Vitamin A amount in International Units (IU). For converting from daily percentages, the FDA recommended 5000 IUs Daily Value can be\n     * used.\n     */\n    @NonNull\n    public static final String NUTRIENT_VITAMIN_A = \"vitamin_a\";\n    /**\n     * Vitamin C amount in milligrams.\n     */\n    @NonNull\n    public static final String NUTRIENT_VITAMIN_C = \"vitamin_c\";\n    /**\n     * The resistance type is unknown, unspecified, or not represented by any canonical values.\n     */\n    public static final int RESISTANCE_TYPE_UNKNOWN = 0;\n    /**\n     * The user is using a barbell for resistance. The specified resistance should include the weight of the bar, as well as weights added to both\n     * sides.\n     */\n    public static final int RESISTANCE_TYPE_BARBELL = 1;\n    /**\n     * The user is using a cable for resistance. When two cables are being used (one for each arm), the specified resistance should include the\n     * weight being pulled by one cable.\n     */\n    public static final int RESISTANCE_TYPE_CABLE = 2;\n    /**\n     * The user is using dumbells for resistance. The specified resistance should include the weight of a single dumbell.\n     */\n    public static final int RESISTANCE_TYPE_DUMBBELL = 3;\n    /**\n     * The user is using a kettlebell for resistance.\n     */\n    public static final int RESISTANCE_TYPE_KETTLEBELL = 4;\n    /**\n     * The user is performing the exercise in a machine. The specified resistance should match the weight specified by the machine.\n     */\n    public static final int RESISTANCE_TYPE_MACHINE = 5;\n    /**\n     * The user is using their own body weight for resistance.\n     */\n    public static final int RESISTANCE_TYPE_BODY = 6;\n    /**\n     * The accuracy of an accompanied value (such as location).\n     */\n    public static final com.google.android.gms.fitness.data.Field FIELD_ACCURACY = createFloatField(\"accuracy\");\n    /**\n     * An activity type of {@link FitnessActivities}, encoded as an integer for efficiency. The activity value should be stored using\n     * {@link DataPoint.Builder#setActivityField(Field, String)}.\n     */\n    public static final com.google.android.gms.fitness.data.Field FIELD_ACTIVITY = createIntField(\"activity\");\n    /**\n     * An altitude of a location represented as a float, in meters above sea level. Some location samples don't have an altitude value so this field\n     * might not be set.\n     */\n    public static final com.google.android.gms.fitness.data.Field FIELD_ALTITUDE = createOptionalFloatField(\"altitude\");\n    /**\n     * An average value.\n     */\n    public static final com.google.android.gms.fitness.data.Field FIELD_AVERAGE = createFloatField(\"average\");\n    /**\n     * A heart rate in beats per minute.\n     */\n    public static final com.google.android.gms.fitness.data.Field FIELD_BPM = createFloatField(\"bpm\");\n    /**\n     * Calories in kcal.\n     */\n    public static final com.google.android.gms.fitness.data.Field FIELD_CALORIES = createFloatField(\"calories\");\n    /**\n     * Circumference of a body part, in centimeters.\n     *\n     * @deprecated There is no applicable replacement field.\n     */\n    @Deprecated\n    public static final com.google.android.gms.fitness.data.Field FIELD_CIRCUMFERENCE = createFloatField(\"circumference\");\n    /**\n     * The confidence of an accompanied value, specified as a value between 0.0 and 100.0.\n     */\n    public static final com.google.android.gms.fitness.data.Field FIELD_CONFIDENCE = createFloatField(\"confidence\");\n    /**\n     * A distance in meters.\n     */\n    public static final com.google.android.gms.fitness.data.Field FIELD_DISTANCE = createFloatField(\"distance\");\n    /**\n     * A field containing duration. The units of the field are defined by the outer data type.\n     */\n    public static final com.google.android.gms.fitness.data.Field FIELD_DURATION = createIntField(\"duration\");\n    /**\n     * A workout exercise, as represented by one of the constants in {@link WorkoutExercises}.\n     */\n    public static final com.google.android.gms.fitness.data.Field FIELD_EXERCISE = createStringField(\"exercise\");\n    /**\n     * The corresponding food item for a nutrition entry.\n     */\n    public static final com.google.android.gms.fitness.data.Field FIELD_FOOD_ITEM = createOptionalStringField(\"food_item\");\n    /**\n     * A height in meters.\n     */\n    public static final com.google.android.gms.fitness.data.Field FIELD_HEIGHT = createFloatField(\"height\");\n    /**\n     * A high latitude of a location bounding box represented as a float, in degrees.\n     */\n    public static final com.google.android.gms.fitness.data.Field FIELD_HIGH_LATITUDE = createFloatField(\"high_latitude\");\n    /**\n     * A high longitude of a location bounding box represented as a float, in degrees.\n     */\n    public static final com.google.android.gms.fitness.data.Field FIELD_HIGH_LONGITUDE = createFloatField(\"high_longitude\");\n    /**\n     * Intensity of user activity, represented as a float.\n     */\n    public static final com.google.android.gms.fitness.data.Field FIELD_INTENSITY = createFloatField(\"intensity\");\n    /**\n     * A latitude of a location represented as a float, in degrees.\n     */\n    public static final com.google.android.gms.fitness.data.Field FIELD_LATITUDE = createFloatField(\"latitude\");\n    /**\n     * A longitude of a location represented as a float, in degrees.\n     */\n    public static final com.google.android.gms.fitness.data.Field FIELD_LONGITUDE = createFloatField(\"longitude\");\n    /**\n     * A low latitude of a location bounding box represented as a float, in degrees.\n     */\n    public static final com.google.android.gms.fitness.data.Field FIELD_LOW_LATITUDE = createFloatField(\"low_latitude\");\n    /**\n     * A low longitude of a location bounding box represented as a float, in degrees.\n     */\n    public static final com.google.android.gms.fitness.data.Field FIELD_LOW_LONGITUDE = createFloatField(\"low_longitude\");\n    /**\n     * A maximum value.\n     */\n    public static final com.google.android.gms.fitness.data.Field FIELD_MAX = createFloatField(\"max\");\n    /**\n     * A maximum int value.\n     */\n    public static final com.google.android.gms.fitness.data.Field FIELD_MAX_INT = createIntField(\"max\");\n    /**\n     * Type of meal, represented as the appropriate int constant.\n     */\n    public static final com.google.android.gms.fitness.data.Field FIELD_MEAL_TYPE = createOptionalIntField(\"meal_type\");\n    /**\n     * A minimum value.\n     */\n    public static final com.google.android.gms.fitness.data.Field FIELD_MIN = createFloatField(\"min\");\n    /**\n     * A minimum int value.\n     */\n    public static final com.google.android.gms.fitness.data.Field FIELD_MIN_INT = createIntField(\"min\");\n    /**\n     * A number of segments.\n     */\n    public static final com.google.android.gms.fitness.data.Field FIELD_NUM_SEGMENTS = createIntField(\"num_segments\");\n    /**\n     * Nutrients ingested by the user, represented as a float map of nutrient key to quantity. The valid keys of the map are listed in this class using\n     * the {@code NUTRIENT_} prefix. The documentation for each key describes the unit of its value.\n     */\n    public static final com.google.android.gms.fitness.data.Field FIELD_NUTRIENTS = createMapField(\"nutrients\");\n    /**\n     * How many occurrences of an event there were in a time range. For sample data types this should not be set to more than one.\n     */\n    public static final com.google.android.gms.fitness.data.Field FIELD_OCCURRENCES = createIntField(\"occurrences\");\n    /**\n     * A percentage value, between 0 and 100.\n     */\n    public static final com.google.android.gms.fitness.data.Field FIELD_PERCENTAGE = createFloatField(\"percentage\");\n    /**\n     * A count of repetitions for a single set of a workout exercise.\n     */\n    public static final com.google.android.gms.fitness.data.Field FIELD_REPETITIONS = createOptionalIntField(\"repetitions\");\n    /**\n     * The resistance of the exercise (or weight), in kg.\n     */\n    public static final com.google.android.gms.fitness.data.Field FIELD_RESISTANCE = createOptionalFloatField(\"resistance\");\n    /**\n     * The type of resistance used in this exercise, represented as the appropriate int constant.\n     */\n    public static final com.google.android.gms.fitness.data.Field FIELD_RESISTANCE_TYPE = createOptionalIntField(\"resistance_type\");\n    /**\n     * A count of revolutions.\n     */\n    public static final com.google.android.gms.fitness.data.Field FIELD_REVOLUTIONS = createIntField(\"revolutions\");\n    /**\n     * Revolutions per minute or rate per minute.\n     */\n    public static final com.google.android.gms.fitness.data.Field FIELD_RPM = createFloatField(\"rpm\");\n    /**\n     * Sleep Segment type defined in {@link SleepStages}.\n     */\n    public static final com.google.android.gms.fitness.data.Field FIELD_SLEEP_SEGMENT_TYPE = createIntField(\"sleep_segment_type\");\n    /**\n     * A speed in meter/sec.\n     */\n    public static final com.google.android.gms.fitness.data.Field FIELD_SPEED = createFloatField(\"speed\");\n    /**\n     * A count of steps.\n     */\n    public static final com.google.android.gms.fitness.data.Field FIELD_STEPS = createIntField(\"steps\");\n    /**\n     * Distance between steps in meters.\n     *\n     * @deprecated There is no applicable replacement field.\n     */\n    @Deprecated\n    public static final com.google.android.gms.fitness.data.Field FIELD_STEP_LENGTH = createFloatField(\"step_length\");\n    /**\n     * Volume in liters.\n     */\n    public static final com.google.android.gms.fitness.data.Field FIELD_VOLUME = createFloatField(\"volume\");\n    /**\n     * Power in watts.\n     */\n    public static final com.google.android.gms.fitness.data.Field FIELD_WATTS = createFloatField(\"watts\");\n    /**\n     * A weight in kilograms.\n     */\n    public static final com.google.android.gms.fitness.data.Field FIELD_WEIGHT = createFloatField(\"weight\");\n\n    public static final com.google.android.gms.fitness.data.Field FIELD_ACTIVITY_CONFIDENCE = createMapField(\"activity_confidence\");\n    public static final com.google.android.gms.fitness.data.Field FIELD_ACTIVITY_DURATION_ASCENDING = createMapField(\"activity_duration.ascending\");\n    public static final com.google.android.gms.fitness.data.Field FIELD_ACTIVITY_DURATION_DESCENDING = createMapField(\"activity_duration.descending\");\n    public static final com.google.android.gms.fitness.data.Field FIELD_DURATION_OPTIONAL = createOptionalIntField(\"duration\");\n    public static final com.google.android.gms.fitness.data.Field FIELD_FITNESS_DEVICE = createObjectField(\"google.android.fitness.Device\");\n    public static final com.google.android.gms.fitness.data.Field FIELD_FITNESS_GOAL_V2 = createObjectField(\"google.android.fitness.GoalV2\");\n    public static final com.google.android.gms.fitness.data.Field FIELD_FITNESS_SLEEP_ATTRIBUTES = createObjectField(\"google.android.fitness.SleepAttributes\");\n    public static final com.google.android.gms.fitness.data.Field FIELD_FITNESS_SLEEP_SCHEDULE = createObjectField(\"google.android.fitness.SleepSchedule\");\n    public static final com.google.android.gms.fitness.data.Field FIELD_FITNESS_PACED_WALKING_ATTRIBUTES = createObjectField(\"google.android.fitness.PacedWalkingAttributes\");\n    public static final com.google.android.gms.fitness.data.Field FIELD_MET = createFloatField(\"met\");\n    public static final com.google.android.gms.fitness.data.Field FIELD_PROBABILITY = createFloatField(\"probability\");\n    public static final com.google.android.gms.fitness.data.Field FIELD_RESPIRATORY_RATE = createFloatField(\"respiratory_rate\");\n    public static final com.google.android.gms.fitness.data.Field FIELD_SENSOR_TYPE = createIntField(\"sensor_type\");\n    public static final com.google.android.gms.fitness.data.Field FIELD_SENSOR_VALUES = createDoubleField(\"sensor_values\");\n    public static final com.google.android.gms.fitness.data.Field FIELD_TIMESTAMPS = createLongField(\"timestamps\");\n    public static final com.google.android.gms.fitness.data.Field FIELD_ZONE_ID = createStringField(\"zone_id\");\n\n    @Field(value = 1, getterName = \"getName\")\n    @NonNull\n    private final String name;\n    @Field(value = 2, getterName = \"getFormat\")\n    private final int format;\n    @Field(value = 3, getterName = \"isOptional\")\n    @Nullable\n    private final Boolean optional;\n\n    @Constructor\n    public Field(@Param(1) @NonNull String name, @Param(2) int format, @Param(3) @Nullable Boolean optional) {\n        this.name = name;\n        this.format = format;\n        this.optional = optional;\n    }\n\n    public Field(@NonNull String name, int format) {\n        this(name, format, null);\n    }\n\n    /**\n     * Returns the format of the field, as one of the format constant values.\n     */\n    public int getFormat() {\n        return format;\n    }\n\n    /**\n     * Returns the name of the field.\n     */\n    public String getName() {\n        return name;\n    }\n\n    public Boolean isOptional() {\n        return optional;\n    }\n\n    @Override\n    public int hashCode() {\n        return name.hashCode();\n    }\n\n    @Override\n    public final boolean equals(Object o) {\n        if (!(o instanceof com.google.android.gms.fitness.data.Field)) return false;\n\n        com.google.android.gms.fitness.data.Field field = (com.google.android.gms.fitness.data.Field) o;\n        return format == field.format && name.equals(field.name);\n    }\n\n    public static com.google.android.gms.fitness.data.Field createIntField(String name) {\n        return new com.google.android.gms.fitness.data.Field(name, FORMAT_INT32);\n    }\n\n    public static com.google.android.gms.fitness.data.Field createFloatField(String name) {\n        return new com.google.android.gms.fitness.data.Field(name, FORMAT_FLOAT);\n    }\n\n    public static com.google.android.gms.fitness.data.Field createStringField(String name) {\n        return new com.google.android.gms.fitness.data.Field(name, FORMAT_STRING);\n    }\n\n    public static com.google.android.gms.fitness.data.Field createMapField(String name) {\n        return new com.google.android.gms.fitness.data.Field(name, FORMAT_MAP);\n    }\n\n    public static com.google.android.gms.fitness.data.Field createLongField(String name) {\n        return new com.google.android.gms.fitness.data.Field(name, FORMAT_LONG);\n    }\n\n    public static com.google.android.gms.fitness.data.Field createDoubleField(String name) {\n        return new com.google.android.gms.fitness.data.Field(name, FORMAT_DOUBLE);\n    }\n\n    public static com.google.android.gms.fitness.data.Field createObjectField(String name) {\n        return new com.google.android.gms.fitness.data.Field(name, FORMAT_OBJECT);\n    }\n\n    public static com.google.android.gms.fitness.data.Field createOptionalIntField(String name) {\n        return new com.google.android.gms.fitness.data.Field(name, FORMAT_INT32, true);\n    }\n\n    public static com.google.android.gms.fitness.data.Field createOptionalFloatField(String name) {\n        return new com.google.android.gms.fitness.data.Field(name, FORMAT_FLOAT, true);\n    }\n\n    public static com.google.android.gms.fitness.data.Field createOptionalStringField(String name) {\n        return new com.google.android.gms.fitness.data.Field(name, FORMAT_STRING, true);\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<com.google.android.gms.fitness.data.Field> CREATOR = findCreator(com.google.android.gms.fitness.data.Field.class);\n\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/data/MapValue.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.data;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\n\nimport static com.google.android.gms.fitness.data.Field.FORMAT_FLOAT;\n\n@Hide\n@SafeParcelable.Class\npublic class MapValue extends AbstractSafeParcelable {\n    @Field(value = 1, getterName = \"getFormat\")\n    private final int format;\n    @Field(value = 2, getterName = \"getValue\")\n    private final float value;\n\n    @Constructor\n    public MapValue(@Param(1) int format, @Param(2) float value) {\n        this.format = format;\n        this.value = value;\n    }\n\n    @NonNull\n    public static MapValue ofFloat(float value) {\n        return new MapValue(FORMAT_FLOAT, value);\n    }\n\n    public int getFormat() {\n        return format;\n    }\n\n    float getValue() {\n        return value;\n    }\n\n    public float asFloat() {\n        if (format != FORMAT_FLOAT) throw new IllegalStateException(\"MapValue is not a float\");\n        return value;\n    }\n\n    @Override\n    public int hashCode() {\n        return (int) value;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<MapValue> CREATOR = findCreator(MapValue.class);\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/data/Session.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fitness.data;\n\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableSerializer;\n\nimport java.util.concurrent.TimeUnit;\n\n/**\n * A Session represents a time interval with associated metadata. Sessions provide a mechanism to store user-visible groups of related\n * stream data in a useful and shareable manner, and allows for easy querying of the data in a detailed or aggregated fashion. The start and\n * end times for sessions will be controlled by applications, and can be used to represent user-friendly groupings of activities, such as \"bike\n * ride\", \"marathon training run\". Any data in Google Fit which falls within this time range is implicitly associated with the session.\n */\n@SafeParcelable.Class\npublic class Session extends AbstractSafeParcelable {\n\n    /**\n     * Name for the parcelable intent extra containing a session. It can be extracted using {@link #extract(Intent)}.\n     */\n    @NonNull\n    public static final String EXTRA_SESSION = \"vnd.google.fitness.session\";\n\n    /**\n     * The common prefix for session MIME types. The MIME type for a particular session will be this prefix followed by the session's activity\n     * name.\n     * <p>\n     * The session's activity type is returned by {@link #getActivity()}. The MIME type can be computed from the activity using {@link #getMimeType(String)}\n     */\n    @NonNull\n    public static final String MIME_TYPE_PREFIX = \"vnd.google.fitness.session/\";\n\n    @Field(value = 1, getterName = \"getStartTimeMillis\")\n    private final long startTimeMillis;\n    @Field(value = 2, getterName = \"getEndTimeMillis\")\n    private final long endTimeMillis;\n    @Field(value = 3, getterName = \"getName\")\n    @Nullable\n    private final String name;\n    @Field(value = 4, getterName = \"getIdentifier\")\n    @NonNull\n    private final String identifier;\n    @Field(value = 5, getterName = \"getDescription\")\n    @NonNull\n    private final String description;\n    @Field(value = 7, getterName = \"getActivityType\")\n    private final int activityType;\n    @Field(value = 8, getterName = \"getApplication\")\n    private final Application application;\n    @Field(value = 9, getterName = \"getActiveTimeMillis\")\n    @Nullable\n    private final Long activeTimeMillis;\n\n    @Constructor\n    Session(@Param(1) long startTimeMillis, @Param(2) long endTimeMillis, @Param(3) @Nullable String name, @Param(4) @NonNull String identifier, @Param(5) @NonNull String description, @Param(7) int activityType, @Param(8) Application application, @Param(9) @Nullable Long activeTimeMillis) {\n        this.startTimeMillis = startTimeMillis;\n        this.endTimeMillis = endTimeMillis;\n        this.name = name;\n        this.identifier = identifier;\n        this.description = description;\n        this.activityType = activityType;\n        this.application = application;\n        this.activeTimeMillis = activeTimeMillis;\n    }\n\n    /**\n     * Returns the active time period of the session.\n     * <p>\n     * Make sure to use {@link #hasActiveTime()} before using this method.\n     *\n     * @throws IllegalStateException {@link #hasActiveTime()} returns false.\n     */\n    public long getActiveTime(@NonNull TimeUnit timeUnit) {\n        if (activeTimeMillis == null) throw new IllegalStateException(\"Active time is not set\");\n        return timeUnit.convert(activeTimeMillis, TimeUnit.MILLISECONDS);\n    }\n\n    /**\n     * Returns the activity associated with this session, if set. Else returns {@link FitnessActivities#UNKNOWN}.\n     */\n    @NonNull\n    public String getActivity() {\n        return null; // TODO\n    }\n\n    /**\n     * Returns the package name for the application responsible for adding the session. or {@code null} if unset/unknown. The {@link PackageManager} can be\n     * used to query relevant data on the application, such as the name, icon, or logo.\n     */\n    @Nullable\n    public String getAppPackageName() {\n        if (application == null) return null;\n        return application.getPackageName();\n    }\n\n    /**\n     * Returns the description for this session.\n     */\n    @NonNull\n    public String getDescription() {\n        return description;\n    }\n\n    /**\n     * Returns the end time for the session, in the given unit since epoch. If the session is ongoing (it hasn't ended yet), this will return 0.\n     */\n    public long getEndTime(@NonNull TimeUnit timeUnit) {\n        return timeUnit.convert(endTimeMillis, TimeUnit.MILLISECONDS);\n    }\n\n    /**\n     * Returns the identifier for this session.\n     */\n    @NonNull\n    public String getIdentifier() {\n        return identifier;\n    }\n\n    /**\n     * Returns the name for this session, if set.\n     */\n    @Nullable\n    public String getName() {\n        return name;\n    }\n\n    /**\n     * Returns the start time for the session, in the given time unit since epoch. A valid start time is always set.\n     */\n    public long getStartTime(@NonNull TimeUnit timeUnit) {\n        return timeUnit.convert(startTimeMillis, TimeUnit.MILLISECONDS);\n    }\n\n    /**\n     * Returns whether the session active time is set.\n     */\n    public boolean hasActiveTime() {\n        return activeTimeMillis != null;\n    }\n\n    /**\n     * Returns whether the session is ongoing. If the session has ended, this will return false.\n     */\n    public boolean isOngoing() {\n        return endTimeMillis == 0;\n    }\n\n    Application getApplication() {\n        return application;\n    }\n\n    int getActivityType() {\n        return activityType;\n    }\n\n    long getStartTimeMillis() {\n        return startTimeMillis;\n    }\n\n    long getEndTimeMillis() {\n        return endTimeMillis;\n    }\n\n    @Nullable\n    Long getActiveTimeMillis() {\n        return activeTimeMillis;\n    }\n\n    /**\n     * Extracts the session extra from the given intent, such as a callback intent received after registering to session start/end notifications, or an intent to view a session.\n     *\n     * @param intent The extracted Session, or {@code null} if the given intent does not contain a Session.\n     */\n    @Nullable\n    public static Session extract(@NonNull Intent intent) {\n        return SafeParcelableSerializer.deserializeFromBytes(intent.getByteArrayExtra(EXTRA_SESSION), CREATOR);\n    }\n\n    /**\n     * Returns the MIME type which describes a Session for a particular activity. The MIME type is used in intents such as the session view\n     * intent.\n     *\n     * @param activity One of the activities in {@link FitnessActivities}.\n     */\n    @NonNull\n    public static String getMimeType(@NonNull String activity) {\n        return MIME_TYPE_PREFIX + activity;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<Session> CREATOR = findCreator(Session.class);\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/data/SessionDataSet.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.data;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\n\n@SafeParcelable.Class\n@Hide\npublic class SessionDataSet extends AbstractSafeParcelable {\n    public static final SafeParcelableCreatorAndWriter<SessionDataSet> CREATOR = findCreator(SessionDataSet.class);\n\n    @Field(1)\n    public final Session session;\n    @Field(2)\n    public final DataSet dataSet;\n\n    @Constructor\n    public SessionDataSet(@Param(1) Session session, @Param(2) DataSet dataSet) {\n        this.session = session;\n        this.dataSet = dataSet;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/data/Subscription.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.data;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class Subscription extends AbstractSafeParcelable {\n    @Field(1)\n    public DataSource dataSource;\n    @Field(2)\n    public DataType dataType;\n    @Field(3)\n    public long samplingIntervalMicros;\n    @Field(4)\n    public int accuracyMode;\n    @Field(5)\n    public int subscriptionType;\n\n    @Constructor\n    public Subscription(@Param(1) DataSource dataSource, @Param(2) DataType dataType, @Param(3) long samplingIntervalMicros, @Param(4) int accuracyMode, @Param(5) int subscriptionType) {\n        this.dataSource = dataSource;\n        this.dataType = dataType;\n        this.samplingIntervalMicros = samplingIntervalMicros;\n        this.accuracyMode = accuracyMode;\n        this.subscriptionType = subscriptionType;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<Subscription> CREATOR = findCreator(Subscription.class);\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/data/Value.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fitness.data;\n\nimport android.os.Bundle;\nimport android.os.Build.VERSION;\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport java.util.Map;\n\nimport static com.google.android.gms.fitness.data.Field.*;\n\n/**\n * Holder object for the value of a single field in a data point. Values are not constructed directly; a value for each field of the data type\n * is created for each data point.\n * <p>\n * A field value has a particular format, and should be set and read using the format-specific methods. For instance, a float value should be set\n * via {@link #setFloat(float)} and read via {@link #asFloat()}. Formats are defined as constants in {@link com.google.android.gms.fitness.data.Field}.\n */\n@SafeParcelable.Class\npublic final class Value extends AbstractSafeParcelable {\n    @Field(value = 1, getterName = \"getFormat\")\n    public int format;\n    @Field(value = 2, getterName = \"isSet\")\n    public boolean set;\n    @Field(value = 3, getterName = \"getValue\")\n    public float value;\n    @Field(value = 4, getterName = \"getStringValue\")\n    public String stringValue;\n    @Field(value = 5, getterName = \"getMapValue\")\n    @Nullable\n    public Bundle mapValue;\n    @Field(value = 6, getterName = \"getIntArrayValue\")\n    public int[] intArrayValue;\n    @Field(value = 7, getterName = \"getFloatArrayValue\")\n    public float[] floatArrayValue;\n    @Field(value = 8, getterName = \"getBlob\")\n    public byte[] blob;\n\n    @Constructor\n    public Value(@Param(1) int format, @Param(2) boolean set, @Param(3) float value, @Param(4) String stringValue, @Param(5) @Nullable Bundle mapValue, @Param(6) int[] intArrayValue, @Param(7) float[] floatArrayValue, @Param(8) byte[] blob) {\n        this.format = format;\n        this.set = set;\n        this.value = value;\n        this.stringValue = stringValue;\n        this.mapValue = mapValue;\n        this.intArrayValue = intArrayValue;\n        this.floatArrayValue = floatArrayValue;\n        this.blob = blob;\n    }\n\n    Value(int format) {\n        this(format, false, 0f, null, null, null, null, null);\n    }\n\n    /**\n     * Returns the value of this object as an activity. The integer representation of the activity is converted to a String prior to returning.\n     *\n     * @return One of the constants from {@link FitnessActivities}; {@link FitnessActivities#UNKNOWN} if the object does not hold a valid activity\n     * representation\n     * @throws IllegalStateException If this {@link Value} does not correspond to a {@link com.google.android.gms.fitness.data.Field#FORMAT_INT32}\n     */\n    public String asActivity() {\n        return null; // TODO\n    }\n\n    /**\n     * Returns the value of this object as a float.\n     *\n     * @throws IllegalStateException If this {@link Value} does not correspond to a {@link com.google.android.gms.fitness.data.Field#FORMAT_FLOAT}\n     */\n    public float asFloat() {\n        if (format != FORMAT_FLOAT) throw new IllegalStateException(\"Value is not a float.\");\n        return value;\n    }\n\n    /**\n     * Returns the value of this object as a int.\n     *\n     * @throws IllegalStateException If this {@link Value} does not correspond to a {@link com.google.android.gms.fitness.data.Field#FORMAT_INT32}\n     */\n    public int asInt() {\n        if (format != FORMAT_INT32) throw new IllegalStateException(\"Value is not a int.\");\n        return Float.floatToRawIntBits(this.value);\n    }\n\n    /**\n     * Returns the value of this object as a string.\n     *\n     * @throws IllegalStateException If this {@link Value} does not correspond to a {@link com.google.android.gms.fitness.data.Field#FORMAT_STRING}\n     */\n    @NonNull\n    public String asString() {\n        if (format != FORMAT_STRING) throw new IllegalStateException(\"Value is not a string.\");\n        if (stringValue == null) return \"\";\n        return stringValue;\n    }\n\n    /**\n     * Clears any value currently associated with the given {@code key} in the map. This method can be used only on map values.\n     *\n     * @param key The key you're modifying.\n     * @deprecated Use {@link DataPoint.Builder} to construct new {@link DataPoint} instances.\n     */\n    @Deprecated\n    public void clearKey(String key) {\n        if (format != FORMAT_MAP) throw new IllegalStateException(\"Value is not a map.\");\n        if (mapValue != null) {\n            mapValue.remove(key);\n        }\n    }\n\n    /**\n     * Returns the format of this value, which matches the appropriate field in the data type definition.\n     *\n     * @return One of the format constants from {@link com.google.android.gms.fitness.data.Field}.\n     */\n    public int getFormat() {\n        return format;\n    }\n\n    /**\n     * Returns the value of the given key in the map as a {@link Float}.\n     *\n     * @return {@code null} if the key doesn't have a set value in the map.\n     * @throws IllegalStateException If this {@link Value} does not correspond to a {@link com.google.android.gms.fitness.data.Field#FORMAT_MAP}\n     */\n    @Nullable\n    public Float getKeyValue(@NonNull String key) {\n        if (format != FORMAT_MAP) throw new IllegalStateException(\"Value is not a map.\");\n        if (mapValue == null || !mapValue.containsKey(key)) {\n            return null;\n        }\n        mapValue.setClassLoader(MapValue.class.getClassLoader());\n        if (VERSION.SDK_INT >= 33) {\n            return mapValue.getParcelable(key, MapValue.class).asFloat();\n        } else {\n            //noinspection deprecation\n            return ((MapValue) mapValue.getParcelable(key)).asFloat();\n        }\n    }\n\n    /**\n     * Returns {@code true} if this object's value has been set by calling one of the setters.\n     */\n    public boolean isSet() {\n        return set;\n    }\n\n    float getValue() {\n        return value;\n    }\n\n    String getStringValue() {\n        return stringValue;\n    }\n\n    @Nullable\n    Bundle getMapValue() {\n        return mapValue;\n    }\n\n    int[] getIntArrayValue() {\n        return intArrayValue;\n    }\n\n    float[] getFloatArrayValue() {\n        return floatArrayValue;\n    }\n\n    byte[] getBlob() {\n        return blob;\n    }\n\n    /**\n     * Updates this value object to represent an activity value. Activities are internally represented as integers for storage.\n     *\n     * @param activity One of the activities from {@link FitnessActivities}\n     * @deprecated Use {@link DataPoint.Builder} to construct new {@link DataPoint} instances.\n     */\n    public void setActivity(String activity) {\n        setInt(0); // TODO\n    }\n\n    /**\n     * Updates this value object to represent a float value. Any previous values associated with this object are erased.\n     *\n     * @param value The new value that this objects holds.\n     * @deprecated Use {@link DataPoint.Builder} to construct new {@link DataPoint} instances.\n     */\n    public void setFloat(float value) {\n        if (format != FORMAT_FLOAT) throw new IllegalStateException(\"Value is not a float.\");\n        this.set = true;\n        this.value = value;\n    }\n\n    /**\n     * Updates this value object to represent an int value. Any previous values are erased.\n     *\n     * @param value The new value that this object holds.\n     * @deprecated Use {@link DataPoint.Builder} to construct new {@link DataPoint} instances.\n     */\n    public void setInt(int value) {\n        if (format != FORMAT_INT32) throw new IllegalStateException(\"Value is not a int.\");\n        this.set = true;\n        this.value = Float.intBitsToFloat(value);\n    }\n\n    /**\n     * Updates the value for a given key in the map to the given float value. Any previous values associated with the key are erased. This method\n     * can be used only on map values.\n     * <p>\n     * Key values should be kept small whenever possible. This is specially important for high frequency streams, since large keys may result in\n     * down sampling.\n     *\n     * @param key   The key you're modifying.\n     * @param value The new value for the given key.\n     * @deprecated Use {@link DataPoint.Builder} to construct new {@link DataPoint} instances.\n     */\n    public void setKeyValue(String key, float value) {\n        if (format != FORMAT_MAP) throw new IllegalStateException(\"Value is not a map.\");\n        this.set = true;\n        if (mapValue == null) mapValue = new Bundle();\n        mapValue.putParcelable(key, MapValue.ofFloat(value));\n    }\n\n    void setMap(@NonNull Map<String, Float> value) {\n        if (format != FORMAT_MAP) throw new IllegalStateException(\"Value is not a map.\");\n        this.set = true;\n        if (mapValue == null) mapValue = new Bundle();\n        for (String key : value.keySet()) {\n            mapValue.putParcelable(key, MapValue.ofFloat(value.get(key)));\n        }\n    }\n\n    /**\n     * Updates this value object to represent a string value. Any previous values associated with this object are erased.\n     * <p>\n     * String values should be kept small whenever possible. This is specially important for high frequency streams, since large values may result\n     * in down sampling.\n     *\n     * @param value The new value that this objects holds.\n     * @deprecated Use {@link DataPoint.Builder} to construct new {@link DataPoint} instances.\n     */\n    public void setString(String value) {\n        if (format != FORMAT_STRING) throw new IllegalStateException(\"Value is not a string.\");\n        this.set = true;\n        this.stringValue = value;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<Value> CREATOR = findCreator(Value.class);\n}"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/data/package-info.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n/**\n * Contains the Google Fit data model.\n */\npackage com.google.android.gms.fitness.data;\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/package-info.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n/**\n * Contains the Google Fit APIs.\n */\npackage com.google.android.gms.fitness;\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/request/DailyTotalRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.fitness.data.DataType;\nimport com.google.android.gms.fitness.internal.IDailyTotalCallback;\n\n@SafeParcelable.Class\npublic class DailyTotalRequest extends AbstractSafeParcelable {\n\n    @Field(1)\n    public IDailyTotalCallback callback;\n    @Field(2)\n    public DataType dataType;\n    @Field(4)\n    public Boolean unknownBool4;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<DailyTotalRequest> CREATOR = findCreator(DailyTotalRequest.class);\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/request/DataDeleteRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.fitness.data.DataSource;\nimport com.google.android.gms.fitness.data.DataType;\nimport com.google.android.gms.fitness.data.Session;\nimport com.google.android.gms.fitness.internal.IStatusCallback;\n\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.List;\n\n@SafeParcelable.Class\npublic class DataDeleteRequest extends AbstractSafeParcelable {\n    @Field(1)\n    public long startTimeMillis;\n    @Field(2)\n    public long endTimeMillis;\n    @Field(3)\n    public List<DataSource> dataSources;\n    @Field(4)\n    public List<DataType> dataTypes;\n    @Field(5)\n    public List<Session> sessions;\n    @Field(6)\n    public boolean deleteAllData;\n    @Field(7)\n    public boolean deleteAllSessions;\n    @Field(8)\n    public IStatusCallback callback;\n    @Field(10)\n    public boolean deleteByTimeRange;\n    @Field(11)\n    public boolean enableLocationCleanup;\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"DataDeleteRequest\")\n                .field(\"startTimeMillis\", startTimeMillis)\n                .field(\"endTimeMillis\", endTimeMillis)\n                .field(\"dataSources\", dataSources)\n                .field(\"dataTypes\", dataTypes)\n                .field(\"sessions\", sessions)\n                .field(\"deleteAllData\", deleteAllData)\n                .field(\"deleteAllSessions\", deleteAllSessions)\n                .field(\"callback\", callback)\n                .field(\"deleteByTimeRange\", deleteByTimeRange)\n                .field(\"enableLocationCleanup\", enableLocationCleanup)\n                .end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<DataDeleteRequest> CREATOR = findCreator(DataDeleteRequest.class);\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/request/DataInsertRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.fitness.data.DataSet;\nimport com.google.android.gms.fitness.internal.IStatusCallback;\n\n@SafeParcelable.Class\npublic class DataInsertRequest extends AbstractSafeParcelable {\n    @Field(1)\n    public DataSet dataSet;\n    @Field(2)\n    public IStatusCallback callback;\n    @Field(4)\n    public boolean isPrimary;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<DataInsertRequest> CREATOR = findCreator(DataInsertRequest.class);\n\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/request/DataPointChangesRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.fitness.internal.IDataPointChangesCallback;\n\n@SafeParcelable.Class\npublic class DataPointChangesRequest extends AbstractSafeParcelable {\n\n    @Field(1)\n    public IDataPointChangesCallback callback;\n    @Field(2)\n    public Long unknownLong2;\n    @Field(3)\n    public int unknownInt3;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<DataPointChangesRequest> CREATOR = findCreator(DataPointChangesRequest.class);\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/request/DataReadRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.fitness.data.DataSource;\n\nimport com.google.android.gms.fitness.data.DataType;\nimport com.google.android.gms.fitness.internal.IDataReadCallback;\n\nimport java.util.List;\n\n@SafeParcelable.Class\npublic class DataReadRequest extends AbstractSafeParcelable {\n\n    @Field(1)\n    public List<DataType> dataTypes;\n    @Field(2)\n    public List<DataSource> dataSources;\n    @Field(3)\n    public long startTimeMillis;\n    @Field(4)\n    public long endTimeMillis;\n    @Field(5)\n    public List<DataType> aggregatedDataTypes;\n    @Field(6)\n    public List<DataSource> aggregatedDataSources;\n    @Field(7)\n    public int bucketType;\n    @Field(8)\n    public long bucketDurationMillis;\n    @Field(9)\n    public DataSource activityDataSource;\n    @Field(10)\n    public int limit;\n    @Field(12)\n    public boolean flushBufferBeforeRead;\n    @Field(13)\n    public boolean areServerQueriesEnabled;\n    @Field(14)\n    public IDataReadCallback callback;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<DataReadRequest> CREATOR = findCreator(DataReadRequest.class);\n\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/request/DataReadResult.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.fitness.data.Bucket;\nimport com.google.android.gms.fitness.data.DataSet;\n\nimport java.util.List;\n\n@SafeParcelable.Class\npublic class DataReadResult extends AbstractSafeParcelable {\n\n    @Field(1)\n    public List<DataSet> rawDataSets;\n    @Field(2)\n    public Status status;\n    @Field(3)\n    public List<Bucket> rawBuckets;\n    @Field(5)\n    public int batchCount;\n    @Field(6)\n    public List<DataSet> uniqueDataSources;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<DataReadResult> CREATOR = findCreator(DataReadResult.class);\n\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/request/DataSourceQueryParams.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.fitness.data.DataSource;\n\n@SafeParcelable.Class\npublic class DataSourceQueryParams extends AbstractSafeParcelable {\n\n    @Field(1)\n    public DataSource dataSource;\n    @Field(3)\n    public long unknownLong3;\n    @Field(4)\n    public long unknownLong4;\n    @Field(5)\n    public int unknownInt5;\n    @Field(6)\n    public int unknownInt6;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<DataSourceQueryParams> CREATOR = findCreator(DataSourceQueryParams.class);\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/request/DataTypeCreateRequest.java",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.fitness.internal.IDataTypeCallback;\n\nimport java.util.List;\n\n@SafeParcelable.Class\npublic class DataTypeCreateRequest extends AbstractSafeParcelable {\n    public static final SafeParcelableCreatorAndWriter<DataTypeCreateRequest> CREATOR = findCreator(DataTypeCreateRequest.class);\n\n    @Field(1)\n    public String name;\n    @Field(2)\n    public List<com.google.android.gms.fitness.data.Field> fields;\n    @Field(3)\n    public IDataTypeCallback callback;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/request/DataUpdateListenerRegistrationRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nimport android.app.PendingIntent;\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.fitness.data.DataSource;\nimport com.google.android.gms.fitness.data.DataType;\nimport com.google.android.gms.fitness.internal.IStatusCallback;\n\n@SafeParcelable.Class\npublic class DataUpdateListenerRegistrationRequest extends AbstractSafeParcelable {\n\n    @Field(1)\n    public DataSource dataSource;\n    @Field(2)\n    public DataType dataType;\n    @Field(3)\n    public PendingIntent pendingIntent;\n    @Field(4)\n    public IStatusCallback callback;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<DataUpdateListenerRegistrationRequest> CREATOR = findCreator(DataUpdateListenerRegistrationRequest.class);\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/request/DataUpdateListenerUnregistrationRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nimport android.app.PendingIntent;\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.fitness.internal.IStatusCallback;\n\n@SafeParcelable.Class\npublic class DataUpdateListenerUnregistrationRequest extends AbstractSafeParcelable {\n\n    @Field(1)\n    public PendingIntent pendingIntent;\n    @Field(2)\n    public IStatusCallback callback;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<DataUpdateListenerUnregistrationRequest> CREATOR = findCreator(DataUpdateListenerUnregistrationRequest.class);\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/request/DataUpdateRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.fitness.data.DataSet;\nimport com.google.android.gms.fitness.internal.IStatusCallback;\n\n@SafeParcelable.Class\npublic class DataUpdateRequest extends AbstractSafeParcelable {\n\n    @Field(1)\n    public Long startTimeMillis;\n    @Field(2)\n    public Long endTimeMillis;\n    @Field(3)\n    public DataSet dataSet;\n    @Field(4)\n    public IStatusCallback callback;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<DataUpdateRequest> CREATOR = findCreator(DataUpdateRequest.class);\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/request/DebugInfoRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.fitness.internal.IDebugInfoCallback;\n\n@SafeParcelable.Class\npublic class DebugInfoRequest extends AbstractSafeParcelable {\n\n    @Field(1)\n    public IDebugInfoCallback callback;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<DebugInfoRequest> CREATOR = findCreator(DebugInfoRequest.class);\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/request/DisableFitRequest.java",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.fitness.internal.IStatusCallback;\n\n@SafeParcelable.Class\npublic class DisableFitRequest extends AbstractSafeParcelable {\n    public static final SafeParcelableCreatorAndWriter<DisableFitRequest> CREATOR = findCreator(DisableFitRequest.class);\n\n    @Field(1)\n    public IStatusCallback callback;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/request/GetFileUriRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.fitness.internal.IFileUriCallback;\n\n@SafeParcelable.Class\npublic class GetFileUriRequest extends AbstractSafeParcelable {\n\n    @Field(1)\n    public IFileUriCallback callback;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<GetFileUriRequest> CREATOR = findCreator(GetFileUriRequest.class);\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/request/GetSyncInfoRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.fitness.internal.ISyncInfoCallback;\n\n@SafeParcelable.Class\npublic class GetSyncInfoRequest extends AbstractSafeParcelable {\n\n    @Field(1)\n    public ISyncInfoCallback callback;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<GetSyncInfoRequest> CREATOR = findCreator(GetSyncInfoRequest.class);\n}\n\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/request/ListSubscriptionsRequest.java",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.fitness.data.DataType;\nimport com.google.android.gms.fitness.internal.IListSubscriptionsCallback;\n\n@SafeParcelable.Class\npublic class ListSubscriptionsRequest extends AbstractSafeParcelable {\n    @Field(1)\n    public DataType dataType;\n    @Field(2)\n    public IListSubscriptionsCallback callback;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<ListSubscriptionsRequest> CREATOR = findCreator(ListSubscriptionsRequest.class);\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/request/ReadDataTypeRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.fitness.internal.IDataTypeCallback;\n\n@SafeParcelable.Class\npublic class ReadDataTypeRequest extends AbstractSafeParcelable {\n    public static final SafeParcelableCreatorAndWriter<ReadDataTypeRequest> CREATOR = findCreator(ReadDataTypeRequest.class);\n\n    @Field(1)\n    public String name;\n    @Field(3)\n    public IDataTypeCallback callback;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/request/ReadRawRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.fitness.internal.IReadRawCallback;\n\nimport java.util.List;\n\n@SafeParcelable.Class\npublic class ReadRawRequest extends AbstractSafeParcelable {\n\n    @Field(1)\n    public IReadRawCallback callback;\n    @Field(3)\n    public List<DataSourceQueryParams> dataSourceQueryParams;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<ReadRawRequest> CREATOR = findCreator(ReadRawRequest.class);\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/request/ReadStatsRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.fitness.data.DataSource;\nimport com.google.android.gms.fitness.internal.IReadStatsCallback;\n\nimport java.util.List;\n\n@SafeParcelable.Class\npublic class ReadStatsRequest extends AbstractSafeParcelable {\n\n    @Field(1000)\n    public int versionCode;\n    @Field(1)\n    public IReadStatsCallback callback;\n    @Field(3)\n    public List<DataSource> dataSources;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<ReadStatsRequest> CREATOR = findCreator(ReadStatsRequest.class);\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/request/SessionChangesRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.fitness.internal.ISessionChangesCallback;\n\n@SafeParcelable.Class\npublic class SessionChangesRequest extends AbstractSafeParcelable {\n\n    @Field(1)\n    public ISessionChangesCallback callback;\n    @Field(2)\n    public Long unknownLong2;\n    @Field(3)\n    public int unknownInt3;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<SessionChangesRequest> CREATOR = findCreator(SessionChangesRequest.class);\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/request/SessionInsertRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.fitness.data.DataPoint;\nimport com.google.android.gms.fitness.data.DataSet;\nimport com.google.android.gms.fitness.data.Session;\nimport com.google.android.gms.fitness.internal.IStatusCallback;\n\nimport java.util.List;\n\n@SafeParcelable.Class\npublic class SessionInsertRequest extends AbstractSafeParcelable {\n\n    @Field(1)\n    public Session seesion;\n    @Field(2)\n    public List<DataSet> dataSets;\n\n    @Field(3)\n    public List<DataPoint> aggregateDataPoints;\n\n    @Field(4)\n    public IStatusCallback callback;\n\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<SessionInsertRequest> CREATOR = findCreator(SessionInsertRequest.class);\n\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/request/SessionReadRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.fitness.data.DataSource;\nimport com.google.android.gms.fitness.data.DataType;\nimport com.google.android.gms.fitness.internal.ISessionReadCallback;\n\nimport java.util.List;\n\n@SafeParcelable.Class\npublic class SessionReadRequest extends AbstractSafeParcelable {\n    @Field(1)\n    public String sessionName;\n    @Field(2)\n    public String sessionId;\n    @Field(3)\n    public long StartTimeMillis;\n    @Field(4)\n    public long EndTimeMillis;\n    @Field(5)\n    public List<DataType> dataTypes;\n    @Field(6)\n    public List<DataSource> dataSources;\n    @Field(7)\n    public boolean includeSessionsFromAllApps;\n    @Field(8)\n    public boolean areServerQueriesEnabled;\n    @Field(9)\n    public List<String> excludedPackages;\n    @Field(10)\n    public ISessionReadCallback callback;\n    @Field(value = 12, defaultValue = \"true\")\n    public boolean areActivitySessionsIncluded;\n    @Field(value = 13, defaultValue = \"false\")\n    public boolean areSleepSessionsIncluded;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<SessionReadRequest> CREATOR = findCreator(SessionReadRequest.class);\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/request/SessionRegistrationRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nimport android.app.PendingIntent;\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.api.internal.IStatusCallback;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class SessionRegistrationRequest extends AbstractSafeParcelable {\n\n    @Field(1)\n    public PendingIntent intent;\n    @Field(2)\n    public IStatusCallback callback;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<SessionRegistrationRequest> CREATOR = findCreator(SessionRegistrationRequest.class);\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/request/SessionStartRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.fitness.data.Session;\nimport com.google.android.gms.fitness.internal.IStatusCallback;\n\n@SafeParcelable.Class\npublic class SessionStartRequest extends AbstractSafeParcelable {\n    @Field(1)\n    public Session session;\n    @Field(2)\n    public IStatusCallback callback;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<SessionStartRequest> CREATOR = findCreator(SessionStartRequest.class);\n\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/request/SessionStopRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.fitness.internal.ISessionStopCallback;\n\n@SafeParcelable.Class\npublic class SessionStopRequest extends AbstractSafeParcelable {\n    @Field(1)\n    public String name;\n    @Field(2)\n    public String identifier;\n    @Field(3)\n    public ISessionStopCallback callback;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<SessionStopRequest> CREATOR = findCreator(SessionStopRequest.class);\n\n}"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/request/SessionUnregistrationRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nimport android.app.PendingIntent;\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.api.internal.IStatusCallback;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class SessionUnregistrationRequest extends AbstractSafeParcelable {\n    @Field(1)\n    public PendingIntent intent;\n    @Field(2)\n    public IStatusCallback callback;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<SessionUnregistrationRequest> CREATOR = findCreator(SessionUnregistrationRequest.class);\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/request/SubscribeRequest.java",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.fitness.data.Subscription;\nimport com.google.android.gms.fitness.internal.IStatusCallback;\n\n@SafeParcelable.Class\npublic class SubscribeRequest extends AbstractSafeParcelable {\n    @Field(1)\n    public Subscription subscription;\n    @Field(2)\n    public boolean isServerType; // SERVER:true  LOCAL_AND_SERVER:false\n    @Field(3)\n    public IStatusCallback callback;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<SubscribeRequest> CREATOR = findCreator(SubscribeRequest.class);\n}"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/request/UnsubscribeRequest.java",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.request;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.fitness.data.DataSource;\nimport com.google.android.gms.fitness.data.DataType;\nimport com.google.android.gms.fitness.internal.IStatusCallback;\n\n@SafeParcelable.Class\npublic class UnsubscribeRequest extends AbstractSafeParcelable {\n    @Field(1)\n    public DataType dataType;\n    @Field(2)\n    public DataSource dataSource;\n    @Field(3)\n    public IStatusCallback callback;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<UnsubscribeRequest> CREATOR = findCreator(UnsubscribeRequest.class);\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/request/package-info.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n/**\n * Contains request objects used in Google Fit API methods.\n */\npackage com.google.android.gms.fitness.request;\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/result/DataSourceStatsResult.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.result;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.fitness.data.DataSource;\nimport org.microg.gms.common.Hide;\n\n@Hide\n@SafeParcelable.Class\npublic class DataSourceStatsResult extends AbstractSafeParcelable {\n    @Field(1)\n    public DataSource dataSource;\n    @Field(2)\n    public long id;\n    @Field(3)\n    public boolean isRemote;\n    @Field(4)\n    public long minEndTimeNanos;\n    @Field(5)\n    public long maxEndTimeNanos;\n    @Field(6)\n    public long minContiguousTimeNanos;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<DataSourceStatsResult> CREATOR = findCreator(DataSourceStatsResult.class);\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/result/DataStatsResult.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.result;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.common.data.DataHolder;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\n\nimport java.io.Closeable;\nimport java.util.List;\n\n@Hide\n@SafeParcelable.Class\npublic class DataStatsResult extends AbstractSafeParcelable implements Closeable {\n    @Field(1)\n    public Status status;\n    @Field(2)\n    public List<DataSourceStatsResult> dataSourceStatsResultList;\n    @Field(3)\n    public long unknownLong3;\n    @Field(4)\n    public String unknownString4;\n    @Field(5)\n    public long unknownLong5;\n    @Field(6)\n    public DataHolder dataHolder;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<DataStatsResult> CREATOR = findCreator(DataStatsResult.class);\n\n    @Override\n    public void close() {\n        if (dataHolder != null) {\n            dataHolder.close();\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/result/DataTypeResult.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fitness.result;\n\nimport android.app.Activity;\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.fitness.data.DataType;\nimport org.microg.gms.common.Hide;\n\n/**\n * Result of {@link ConfigApi#readDataType(GoogleApiClient, String)}.\n * <p>\n * The method {@link #getStatus()} can be used to confirm if the request was successful. On success, the returned data type can be accessed\n * via {@link #getDataType()}.\n * <p>\n * In case the calling app is missing the required permissions, the returned status has status code set to\n * {@link FitnessStatusCodes#NEEDS_OAUTH_PERMISSIONS}. In this case the caller should use {@link Status#startResolutionForResult(Activity, int)}\n * to start an intent to get the necessary consent from the user before retrying the request.\n * <p>\n * In case the app attempts to read a custom data type created by other app, the returned status has status code set to\n * {@link FitnessStatusCodes#INCONSISTENT_DATA_TYPE}.\n *\n * @deprecated No replacement.\n */\n@Deprecated\n@SafeParcelable.Class\npublic class DataTypeResult extends AbstractSafeParcelable {\n\n    @Field(value = 1, getterName = \"getStatus\")\n    private final Status status;\n    @Field(value = 3, getterName = \"getDataType\")\n    @Nullable\n    private final DataType dataType;\n\n    @Constructor\n    @Hide\n    public DataTypeResult(@Param(1) Status status, @Param(3) @Nullable DataType dataType) {\n        this.status = status;\n        this.dataType = dataType;\n    }\n\n    /**\n     * Returns the new custom data type inserted, or {@code null} if the request failed.\n     */\n    @Nullable\n    public DataType getDataType() {\n        return dataType;\n    }\n\n    public Status getStatus() {\n        return status;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<DataTypeResult> CREATOR = findCreator(DataTypeResult.class);\n\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/result/ListSubscriptionsResult.java",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.fitness.result;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.fitness.data.Subscription;\n\nimport java.util.List;\n\n@SafeParcelable.Class\npublic class ListSubscriptionsResult extends AbstractSafeParcelable {\n\n    @Field(1)\n    public List<Subscription> subscriptions;\n    @Field(2)\n    public Status status;\n\n    @Constructor\n    public ListSubscriptionsResult(@Param(1) List<Subscription> list, @Param(2) Status status) {\n        this.subscriptions = list;\n        this.status = status;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<ListSubscriptionsResult> CREATOR = findCreator(ListSubscriptionsResult.class);\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/result/SessionReadResult.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fitness.result;\n\nimport android.app.Activity;\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.fitness.data.DataSet;\nimport com.google.android.gms.fitness.data.DataType;\nimport com.google.android.gms.fitness.data.Session;\nimport com.google.android.gms.fitness.data.SessionDataSet;\nimport com.google.android.gms.fitness.request.SessionReadRequest;\nimport org.microg.gms.common.Hide;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\n/**\n * Result of {@link SessionsApi#readSession(GoogleApiClient, SessionReadRequest)}.\n * Contains all Sessions and their corresponding data sets that matched the filters specified in the {@link SessionReadRequest}.\n * <p>\n * The method {@link #getStatus()} can be used to confirm if the request was successful.\n * <p>\n * In case the calling app is missing the required permissions, the returned status has status code set to\n * {@link FitnessStatusCodes#NEEDS_OAUTH_PERMISSIONS}. In this case the caller should use {@link Status#startResolutionForResult(Activity, int)}\n * to start an intent to get the necessary consent from the user before retrying the request.\n * <p>\n * The method {@link #getSessions()} returns all sessions that are returned for the request. The method {@link #getDataSet(Session, DataType)} returns\n * {@link DataSet} for a particular Session and {@link DataType} from the result.\n * <p>\n * In case the app tried to read data for a custom data type created by another app, the returned status has status code set to\n * {@link FitnessStatusCodes#INCONSISTENT_DATA_TYPE}.\n */\n@SafeParcelable.Class\npublic class SessionReadResult extends AbstractSafeParcelable {\n    @Field(value = 1, getterName = \"getSessions\")\n    @NonNull\n    private final List<Session> sessions;\n    @Field(value = 2, getterName = \"getSessionDataSets\")\n    @NonNull\n    private final List<SessionDataSet> sessionDataSets;\n    @Field(value = 3, getterName = \"getStatus\")\n    @NonNull\n    private final Status status;\n\n    @Constructor\n    @Hide\n    public SessionReadResult(@Param(1) @NonNull List<Session> sessions, @Param(2) @NonNull List<SessionDataSet> sessionDataSets, @Param(3) @NonNull Status status) {\n        this.sessions = sessions;\n        this.sessionDataSets = sessionDataSets;\n        this.status = status;\n    }\n\n    /**\n     * Returns the data sets for a given {@code session} and {@code dataType}. If a specific data source was requested for this data type in the read request, the\n     * returned data set is from that source. Else, the default data source for this data type is used. Returns empty if no data for the requested data\n     * type is found.\n     *\n     * @return Data sets for the given session and data type, empty if no data was found. Multiple data sets may be returned for a given type, based\n     * on the read request\n     * @throws IllegalArgumentException If the given session was not part of getSessions() output.\n     */\n    @NonNull\n    public List<DataSet> getDataSet(@NonNull Session session, @NonNull DataType dataType) {\n        if (!sessions.contains(session)) throw new IllegalArgumentException(\"Attempting to read data for session which was not returned\");\n        List<DataSet> dataSets = new ArrayList<>();\n        for (SessionDataSet sessionDataSet : this.sessionDataSets) {\n            if (session.equals(sessionDataSet.session) && dataType.equals(sessionDataSet.dataSet.getDataType())) {\n                dataSets.add(sessionDataSet.dataSet);\n            }\n        }\n        return dataSets;\n    }\n\n    /**\n     * Returns the data sets for all data sources for a given {@code session}. If a specific data source was requested for a data type in the read request,\n     * the returned data set is from that source. Else, the default data source for the requested data type is used.\n     *\n     * @return Data sets for the given session for all data sources, empty if no data was found. Multiple data sets may be returned for a given type,\n     * based on the read request\n     * @throws IllegalArgumentException If the given session was not part of getSessions() output\n     */\n    @NonNull\n    public List<DataSet> getDataSet(@NonNull Session session) {\n        if (!sessions.contains(session)) throw new IllegalArgumentException(\"Attempting to read data for session which was not returned\");\n        List<DataSet> dataSets = new ArrayList<>();\n        for (SessionDataSet sessionDataSet : sessionDataSets) {\n            if (session.equals(sessionDataSet.session)) {\n                dataSets.add(sessionDataSet.dataSet);\n            }\n        }\n        return dataSets;\n    }\n\n    /**\n     * Returns all sessions that matched the requested filters.\n     */\n    @NonNull\n    public List<Session> getSessions() {\n        return this.sessions;\n    }\n\n    @NonNull\n    public Status getStatus() {\n        return this.status;\n    }\n\n    @NonNull\n    List<SessionDataSet> getSessionDataSets() {\n        return sessionDataSets;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<SessionReadResult> CREATOR = findCreator(SessionReadResult.class);\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/result/SessionStopResult.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.fitness.result;\n\nimport android.app.Activity;\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.fitness.data.Session;\nimport org.microg.gms.common.Hide;\n\nimport java.util.List;\n\n/**\n * Result of {@link SessionsApi#stopSession(GoogleApiClient, String)}.\n * <p>\n * The method {@link #getStatus()} can be used to confirm if the request was successful.\n * <p>\n * In case the calling app is missing the required permissions, the returned status has status code set to\n * {@link FitnessStatusCodes#NEEDS_OAUTH_PERMISSIONS}. In this case the caller should use {@link Status#startResolutionForResult(Activity, int)}\n * to start an intent to get the necessary consent from the user before retrying the request.\n */\n@SafeParcelable.Class\npublic class SessionStopResult extends AbstractSafeParcelable {\n    @Field(value = 2, getterName = \"getStatus\")\n    @NonNull\n    private final Status status;\n    @Field(value = 3, getterName = \"getSessions\")\n    @NonNull\n    private final List<Session> sessions;\n\n    @Constructor\n    @Hide\n    public SessionStopResult(@Param(2) @NonNull Status status, @Param(3) @NonNull List<Session> sessions) {\n        this.status = status;\n        this.sessions = sessions;\n    }\n\n    /**\n     * Returns the list of sessions that were stopped by the request. Returns an empty list if no active session was stopped.\n     */\n    @NonNull\n    public List<Session> getSessions() {\n        return sessions;\n    }\n\n    /**\n     * Returns the status of the call to Google Fit. {@link Status#isSuccess()} can be used to determine whether the call succeeded. In the case of\n     * failure, you can inspect the status to determine the reason.\n     */\n    @NonNull\n    public Status getStatus() {\n        return status;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<SessionStopResult> CREATOR = findCreator(SessionStopResult.class);\n}\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/result/package-info.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n/**\n * Contains response objects used in Google Fit API methods.\n */\npackage com.google.android.gms.fitness.result;\n"
  },
  {
    "path": "play-services-fitness/src/main/java/com/google/android/gms/fitness/service/package-info.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n/**\n * Contains APIs for exposing third-party sensors to Google Fit using a service.\n */\npackage com.google.android.gms.fitness.service;\n"
  },
  {
    "path": "play-services-games/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\nandroid {\n    namespace \"com.google.android.gms.games\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n}\n\napply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG implementation of play-services-games'\n\ndependencies {\n    // Dependencies from play-services-games:23.1.0\n    api project(':play-services-base')\n    api project(':play-services-basement')\n    api project(':play-services-drive')\n    api project(':play-services-tasks')\n\n    annotationProcessor project(':safe-parcel-processor')\n}\n"
  },
  {
    "path": "play-services-games/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest />\n"
  },
  {
    "path": "play-services-games/src/main/aidl/com/google/android/gms/games/PlayerEntity.aidl",
    "content": "package com.google.android.gms.games;\n\nparcelable PlayerEntity;\n"
  },
  {
    "path": "play-services-games/src/main/aidl/com/google/android/gms/games/client/IPlayGamesCallbacks.aidl",
    "content": "package com.google.android.gms.games.client;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.common.data.DataHolder;\n\ninterface IPlayGamesCallbacks {\n    void onData(in DataHolder dataHolder) = 1000;\n    void onStatus5028(in Status status) = 5027;\n}"
  },
  {
    "path": "play-services-games/src/main/aidl/com/google/android/gms/games/client/IPlayGamesService.aidl",
    "content": "package com.google.android.gms.games.client;\n\nimport com.google.android.gms.games.client.IPlayGamesCallbacks;\nimport com.google.android.gms.games.client.PlayGamesConsistencyTokens;\n\ninterface IPlayGamesService {\n    void getGameCollection(IPlayGamesCallbacks callbacks, int maxResults, int gameCollectionType, boolean z, boolean forceReload) = 1000;\n    void loadGames(IPlayGamesCallbacks callbacks, String playerId, int maxResults, boolean z, boolean forceReload) = 1002;\n\n    PlayGamesConsistencyTokens getConsistencyTokens() = 5027;\n    void updateConsistencyTokens(in PlayGamesConsistencyTokens tokens) = 5028;\n\n    void fun5041(IPlayGamesCallbacks callbacks) = 5040;\n}"
  },
  {
    "path": "play-services-games/src/main/aidl/com/google/android/gms/games/client/PlayGamesConsistencyTokens.aidl",
    "content": "package com.google.android.gms.games.client;\n\nparcelable PlayGamesConsistencyTokens;"
  },
  {
    "path": "play-services-games/src/main/aidl/com/google/android/gms/games/internal/IGamesCallbacks.aidl",
    "content": "package com.google.android.gms.games.internal;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.common.data.DataHolder;\nimport com.google.android.gms.drive.Contents;\nimport com.google.android.gms.games.multiplayer.realtime.RealTimeMessage;\n\ninterface IGamesCallbacks {\n  /* @deprecated */ void onAuthTokenLoaded(int statusCode, String authToken) = 5000;\n  void onAchievementsLoaded(in DataHolder data) = 5001;\n  void onAchievementUpdated(int statusCode, String achievementId) = 5002;\n  void onLeaderboardsLoaded(in DataHolder data) = 5003;\n  void onLeaderboardScoresLoaded(in DataHolder leaderboard, in DataHolder scores) = 5004;\n  void onScoreSubmitted(in DataHolder data) = 5005;\n  void onPlayersLoaded(in DataHolder data) = 5006;\n  void onExtendedPlayersLoaded(in DataHolder data) = 5007;\n  /* @deprecated */ void onGamesLoaded(in DataHolder data) = 5008;\n  /* @deprecated */ void onExtendedGamesLoaded(in DataHolder data) = 5009;\n  /* @deprecated */ void onGameInstancesLoaded(in DataHolder data) = 5010;\n  /* @deprecated */ void onGameplayAclLoaded(in DataHolder data) = 5011;\n  /* @deprecated */ void onGameplayAclUpdated(int statusCode) = 5012;\n  /* @deprecated */ void onFAclLoaded(in DataHolder data) = 5013;\n  /* @deprecated */ void onFAclUpdated(int statusCode) = 5014;\n  void onSignOutComplete() = 5015;\n  /* @deprecated */ void onInvitationsLoaded(in DataHolder data) = 5016;\n  /* @deprecated */ void onRoomCreated(in DataHolder data) = 5017;\n  /* @deprecated */ void onJoinedRoom(in DataHolder data) = 5018;\n  /* @deprecated */ void onLeftRoom(int statusCode, String roomId) = 5019;\n  /* @deprecated */ void onRoomConnecting(in DataHolder data) = 5020;\n  /* @deprecated */ void onRoomAutoMatching(in DataHolder data) = 5021;\n  /* @deprecated */ void onRoomConnected(in DataHolder data) = 5022;\n  /* @deprecated */ void onConnectedToRoom(in DataHolder data) = 5023;\n  /* @deprecated */ void onDisconnectedFromRoom(in DataHolder data) = 5024;\n  /* @deprecated */ void onPeerInvitedToRoom(in DataHolder data, in String[] participantIds) = 5025;\n  /* @deprecated */ void onPeerJoinedRoom(in DataHolder data, in String[] participantIds) = 5026;\n  /* @deprecated */ void onPeerLeftRoom(in DataHolder data, in String[] participantIds) = 5027;\n  /* @deprecated */ void onPeerDeclined(in DataHolder data, in String[] participantIds) = 5028;\n  /* @deprecated */ void onPeerConnected(in DataHolder data, in String[] participantIds) = 5029;\n  /* @deprecated */ void onPeerDisconnected(in DataHolder data, in String[] participantIds) = 5030;\n  /* @deprecated */ void onRealTimeMessageReceived(in RealTimeMessage message) = 5031;\n  /* @deprecated */ void onMessageSent(int statusCode, int messageId, String recipientParticipantId) = 5032;\n  /* @deprecated */ void onGameMuteStatusChanged(int statusCode, String externalGameId, boolean isMuted) = 5033;\n  /* @deprecated */ void onNotifyAclLoaded(in DataHolder data) = 5034;\n  /* @deprecated */ void onNotifyAclUpdated(int statusCode) = 5035;\n  /* @deprecated */ void onInvitationReceived(in DataHolder data) = 5036;\n  /* @deprecated */ void onGameMuteStatusLoaded(in DataHolder data) = 5037;\n  /* @deprecated */ void onContactSettingsLoaded(in DataHolder data) = 5038;\n  /* @deprecated */ void onContactSettingsUpdated(int statusCode) = 5039;\n  void onResolveSnapshotHead(in DataHolder data, in Contents contents) = 12003;\n  void commitSnapshotResult(in DataHolder data) = 12004;\n  void onServerAuthCode(in Status status, String serverAuthCode) = 25002;\n}\n"
  },
  {
    "path": "play-services-games/src/main/aidl/com/google/android/gms/games/internal/IGamesClient.aidl",
    "content": "package com.google.android.gms.games.internal;\n\ninterface IGamesClient {\n}\n"
  },
  {
    "path": "play-services-games/src/main/aidl/com/google/android/gms/games/internal/IGamesService.aidl",
    "content": "package com.google.android.gms.games.internal;\n\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.os.IBinder;\n\nimport com.google.android.gms.common.data.DataHolder;\nimport com.google.android.gms.drive.Contents;\nimport com.google.android.gms.games.PlayerEntity;\nimport com.google.android.gms.games.internal.IGamesCallbacks;\nimport com.google.android.gms.games.internal.IGamesClient;\nimport com.google.android.gms.games.snapshot.SnapshotMetadataChangeEntity;\n\ninterface IGamesService {\n    void clientDisconnecting(long clientId) = 5000;\n    void signOut(IGamesCallbacks callbacks) = 5001;\n    String getAppId() = 5002;\n    Bundle getConnectionHint() = 5003;\n    void showWelcomePopup(IBinder windowToken, in Bundle extras) = 5004;\n    void cancelPopups() = 5005;\n    String getCurrentAccountName() = 5006;\n    void loadGameplayAclInternal(IGamesCallbacks callbacks, String gameId) = 5007;\n    void updateGameplayAclInternal(IGamesCallbacks callbacks, String gameId, String aclData) = 5008;\n    void loadFAclInternal(IGamesCallbacks callbacks, String gameId) = 5009;\n    void updateFAclInternal(IGamesCallbacks callbacks, String gameId, boolean allCirclesVisible, in long[] circleIds) = 5010;\n    String getCurrentPlayerId() = 5011;\n    DataHolder getCurrentPlayer() = 5012;\n    void loadPlayer(IGamesCallbacks callbacks, String playerId) = 5013;\n    void loadInvitablePlayers(IGamesCallbacks callbacks, int pageSize, boolean expandCachedData, boolean forceReload) = 5014;\n    void submitScore(IGamesCallbacks callbacks, String leaderboardId, long score) = 5015;\n    void loadLeaderboards(IGamesCallbacks callbacks) = 5016;\n    void loadLeaderboard(IGamesCallbacks callbacks, String leaderboardId) = 5017;\n    void loadTopScores(IGamesCallbacks callbacks, String leaderboardId, int span, int leaderboardCollection, int maxResults, boolean forceReload) = 5018;\n    void loadPlayerCenteredScores(IGamesCallbacks callbacks, String leaderboardId, int span, int leaderboardCollection, int maxResults, boolean forceReload) = 5019;\n    void loadMoreScores(IGamesCallbacks callbacks, in Bundle previousheader, int maxResults, int pageDirection) = 5020;\n    void loadAchievements(IGamesCallbacks callbacks) = 5021;\n    void revealAchievement(IGamesCallbacks callbacks, String achievementId, IBinder windowToken, in Bundle extras) = 5022;\n    void unlockAchievement(IGamesCallbacks callbacks, String achievementId, IBinder windowToken, in Bundle extras) = 5023;\n    void incrementAchievement(IGamesCallbacks callbacks, String achievementId, int numSteps, IBinder windowToken, in Bundle extras) = 5024;\n    void loadGame(IGamesCallbacks callbacks) = 5025;\n    void loadInvitations(IGamesCallbacks callbacks) = 5026;\n    void declineInvitation(String invitationId, int invitationType) = 5027;\n    void dismissInvitation(String invitationId, int invitationType) = 5028;\n    void createRoom(IGamesCallbacks callbacks, IBinder processBinder, int variant, in String[] invitedPlayerIds, in Bundle autoMatchCriteria, boolean enableSockets, long clientId) = 5029;\n    void joinRoom(IGamesCallbacks callbacks, IBinder processBinder, String matchId, boolean enableSockets, long clientId) = 5030;\n    void leaveRoom(IGamesCallbacks callbacks, String matchId) = 5031;\n    int sendReliableMessage(IGamesCallbacks callbacks, in byte[] messageData, String matchId, String recipientParticipantId) = 5032;\n    int sendUnreliableMessage(in byte[] messageData, String matchId, in String[] recipientParticipantIds) = 5033;\n    String createSocketConnection(String participantId) = 5034;\n    void clearNotifications(int notificationTypes) = 5035;\n    void loadLeaderboardsFirstParty(IGamesCallbacks callbacks, String gameId) = 5036;\n    void loadLeaderboardFirstParty(IGamesCallbacks callbacks, String gameId, String leaderboardId) = 5037;\n    void loadTopScoresFirstParty(IGamesCallbacks callbacks, String gameId, String leaderboardId, int span, int leaderboardCollection, int maxResults, boolean forceReload) = 5038;\n    void loadPlayerCenteredScoresFirstParty(IGamesCallbacks callbacks, String gameId, String leaderboardId, int span, int leaderboardCollection, int maxResults, boolean forceReload) = 5039;\n    void loadAchievementsFirstParty(IGamesCallbacks callbacks, String playerId, String gameId) = 5040;\n    void loadGameFirstParty(IGamesCallbacks callbacks, String gameId) = 5041;\n    void loadGameInstancesFirstParty(IGamesCallbacks callbacks, String gameId) = 5042;\n    void loadGameCollectionFirstParty(IGamesCallbacks callbacks, int pageSize, int collectionType, boolean expandCachedData, boolean forceReload) = 5043;\n    void loadRecentlyPlayedGamesFirstParty(IGamesCallbacks callbacks, String externalPlayerId, int pageSize, boolean expandCachedData, boolean forceReload) = 5044;\n    void loadInvitablePlayersFirstParty(IGamesCallbacks callbacks, int pageSize, boolean expandCachedData, boolean forceReload) = 5045;\n    void loadRecentPlayersFirstParty(IGamesCallbacks callbacks) = 5046;\n    void loadCircledPlayersFirstParty(IGamesCallbacks callbacks, int pageSize, boolean expandCachedData, boolean forceReload) = 5047;\n    void loadSuggestedPlayersFirstParty(IGamesCallbacks callbacks) = 5048;\n    void dismissPlayerSuggestionFirstParty(String playerIdToDismiss) = 5049;\n    void declineInvitationFirstParty(String gameId, String invitationId, int invitationType) = 5050;\n    void loadInvitationsFirstParty(IGamesCallbacks callbacks, String gameId) = 5051;\n    int registerWaitingRoomListenerRestricted(IGamesCallbacks callbacks, String roomId) = 5052;\n    void setGameMuteStatusInternal(IGamesCallbacks callbacks, String gameId, boolean muted) = 5053;\n    void clearNotificationsFirstParty(String gameId, int notificationTypes) = 5054;\n    void loadNotifyAclInternal(IGamesCallbacks callbacks) = 5055;\n    void updateNotifyAclInternal(IGamesCallbacks callbacks, String aclData) = 5056;\n    void registerInvitationListener(IGamesCallbacks callbacks, long clientId) = 5057;\n    void unregisterInvitationListener(long clientId) = 5058;\n    int unregisterWaitingRoomListenerRestricted(String roomId) = 5059;\n    void isGameMutedInternal(IGamesCallbacks callbacks, String gameId) = 5060;\n    void loadContactSettingsInternal(IGamesCallbacks callbacks) = 5061;\n    void updateContactSettingsInternal(IGamesCallbacks callbacks, boolean enableMobileNotifications) = 5062;\n    String getSelectedAccountForGameFirstParty(String gamePackageName) = 5063;\n    void updateSelectedAccountForGameFirstParty(String gamePackageName, String accountName) = 5064;\n    Uri getGamesContentUriRestricted(String gameId) = 5065;\n    boolean shouldUseNewPlayerNotificationsFirstParty() = 5066;\n    void setUseNewPlayerNotificationsFirstParty(boolean newPlayerStyle) = 5067;\n\n    void searchForPlayersFirstParty(IGamesCallbacks callbacks, String query, int pageSize, boolean expandCachedData, boolean forceReload) = 5500;\n    DataHolder getCurrentGame() = 5501;\n\n    void loadAchievementsV2(IGamesCallbacks callbacks, boolean forceReload) = 6000;\n\n    void submitLeaderboardScore(IGamesCallbacks callbacks, String leaderboardId, long score, @nullable String scoreTag) = 7001;\n    void setAchievementSteps(IGamesCallbacks callbacks, String id, int numSteps, IBinder windowToken, in Bundle extras) = 7002;\n\n    Intent getAllLeaderboardsIntent() = 9002;\n    Intent getAchievementsIntent() = 9004;\n    Intent getPlayerSearchIntent() = 9009;\n    Intent getSelectSnapshotIntent(String title, boolean allowAddButton, boolean allowDelete, int maxSnapshots) = 12000;\n    void loadSnapshots(IGamesCallbacks callbacks, boolean forceReload) = 12001;\n    void commitSnapshot(IGamesCallbacks callbacks, String str, in SnapshotMetadataChangeEntity change, in Contents contents) = 12006;\n    void loadEvents(IGamesCallbacks callbacks, boolean forceReload) = 12015;\n    void incrementEvent(String eventId, int incrementAmount) = 12016;\n    void discardAndCloseSnapshot(in Contents contents) = 12018;\n    void loadEventsById(IGamesCallbacks callbacks, boolean forceReload, in String[] eventsIds) = 12030;\n//    void resolveSnapshotConflict(IGamesCallbacks callbacks, String conflictId, String snapshotId, in SnapshotMetadataChangeEntity metadata, in Contents contents) = 12032;\n    int getMaxDataSize() = 12034;\n    int getMaxCoverImageSize() = 12035;\n    void resolveSnapshotHead(IGamesCallbacks callbacks, String saveName, int i) = 15000;\n    void registerEventClient(IGamesClient callback, long l) = 15500;\n    Intent getCompareProfileIntentForPlayer(in PlayerEntity player) = 15502;\n\n    void loadPlayerStats(IGamesCallbacks callbacks, boolean forceReload) = 17000;\n    Intent getLeaderboardsScoresIntent(String leaderboardId, int timeSpan, int collection) = 18000;\n\n    Account getCurrentAccount() = 21000;\n\n    boolean isTelevision() = 22029;\n\n    Intent getCompareProfileIntentWithAlternativeNameHints(String otherPlayerId, String otherPlayerInGameName, String currentPlayerInGameName) = 25015;\n\n    void requestServerSideAccess(IGamesCallbacks callbacks, String serverClientId, boolean forceRefreshToken) = 27002;\n\n}\n"
  },
  {
    "path": "play-services-games/src/main/aidl/com/google/android/gms/games/internal/connect/GamesSignInRequest.aidl",
    "content": "package com.google.android.gms.games.internal.connect;\n\nparcelable GamesSignInRequest;"
  },
  {
    "path": "play-services-games/src/main/aidl/com/google/android/gms/games/internal/connect/GamesSignInResponse.aidl",
    "content": "package com.google.android.gms.games.internal.connect;\n\nparcelable GamesSignInResponse;"
  },
  {
    "path": "play-services-games/src/main/aidl/com/google/android/gms/games/internal/connect/IGamesConnectCallbacks.aidl",
    "content": "package com.google.android.gms.games.internal.connect;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.games.internal.connect.GamesSignInResponse;\n\ninterface IGamesConnectCallbacks {\n    void onSignIn(in Status status, in GamesSignInResponse response) = 1;\n}"
  },
  {
    "path": "play-services-games/src/main/aidl/com/google/android/gms/games/internal/connect/IGamesConnectService.aidl",
    "content": "package com.google.android.gms.games.internal.connect;\n\nimport com.google.android.gms.games.internal.connect.GamesSignInRequest;\nimport com.google.android.gms.games.internal.connect.IGamesConnectCallbacks;\n\ninterface IGamesConnectService {\n    void signIn(IGamesConnectCallbacks callback, in GamesSignInRequest request) = 1;\n}"
  },
  {
    "path": "play-services-games/src/main/aidl/com/google/android/gms/games/multiplayer/realtime/RealTimeMessage.aidl",
    "content": "package com.google.android.gms.games.multiplayer.realtime;\n\nparcelable RealTimeMessage;\n"
  },
  {
    "path": "play-services-games/src/main/aidl/com/google/android/gms/games/snapshot/SnapshotMetadataChangeEntity.aidl",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.games.snapshot;\n\nparcelable SnapshotMetadataChangeEntity;\n"
  },
  {
    "path": "play-services-games/src/main/aidl/com/google/android/gms/games/snapshot/SnapshotMetadataEntity.aidl",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.games.snapshot;\n\nparcelable SnapshotMetadataEntity;\n"
  },
  {
    "path": "play-services-games/src/main/java/com/google/android/gms/games/AnnotatedData.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.games;\n\nimport org.microg.gms.common.Hide;\n\n/**\n * Class to return annotated data. Currently, the only annotation is whether the data is stale or not.\n */\npublic class AnnotatedData<T> {\n    private final T value;\n    private final boolean stale;\n\n    @Hide\n    public AnnotatedData(T value, boolean stale) {\n        this.value = value;\n        this.stale = stale;\n    }\n\n    /**\n     * Returns the data that is annotated by this class.\n     */\n    public T get() {\n        return value;\n    }\n\n    /**\n     * Returns {@code true} if the data returned by {@link #get()} is stale. This usually indicates that there was a network error and data was\n     * returned from the local cache.\n     */\n    public boolean isStale() {\n        return stale;\n    }\n}\n"
  },
  {
    "path": "play-services-games/src/main/java/com/google/android/gms/games/CurrentPlayerInfo.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.games;\n\nimport android.os.Parcelable;\nimport com.google.android.gms.common.data.Freezable;\n\n/**\n * Data object representing the information related only to the signed in user.\n */\npublic interface CurrentPlayerInfo extends Freezable<CurrentPlayerInfo>, Parcelable {\n    /**\n     * Retrieves if the user has shared the friends list with the game. The possible output can be found in {@link Player.FriendsListVisibilityStatus}.\n     */\n    @Player.FriendsListVisibilityStatus\n    int getFriendsListVisibilityStatus();\n}\n"
  },
  {
    "path": "play-services-games/src/main/java/com/google/android/gms/games/CurrentPlayerInfoEntity.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.games;\n\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n@Hide\npublic class CurrentPlayerInfoEntity extends AutoSafeParcelable implements CurrentPlayerInfo {\n    @Field(1)\n    @Player.FriendsListVisibilityStatus\n    private int friendsListVisibilityStatus;\n\n    public CurrentPlayerInfoEntity() {\n    }\n\n    public CurrentPlayerInfoEntity(CurrentPlayerInfo copy) {\n        friendsListVisibilityStatus = copy.getFriendsListVisibilityStatus();\n    }\n\n    public CurrentPlayerInfoEntity(int friendsListVisibilityStatus) {\n        this.friendsListVisibilityStatus = friendsListVisibilityStatus;\n    }\n\n    @Override\n    @Player.FriendsListVisibilityStatus\n    public int getFriendsListVisibilityStatus() {\n        return friendsListVisibilityStatus;\n    }\n\n    @Override\n    public CurrentPlayerInfo freeze() {\n        return this;\n    }\n\n    @Override\n    public boolean isDataValid() {\n        return true;\n    }\n\n    public static final SafeParcelableCreatorAndWriter<CurrentPlayerInfoEntity> CREATOR = findCreator(CurrentPlayerInfoEntity.class);\n}\n"
  },
  {
    "path": "play-services-games/src/main/java/com/google/android/gms/games/Game.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.games;\n\nimport android.database.CharArrayBuffer;\nimport android.net.Uri;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.data.Freezable;\nimport com.google.android.gms.common.images.ImageManager;\nimport org.microg.gms.common.Hide;\n\n/**\n * Data interface for retrieving game information.\n */\npublic interface Game extends Freezable<Game> {\n    /**\n     * Indicates whether or not this game supports snapshots.\n     *\n     * @return Whether or not this game supports snapshots.\n     */\n    boolean areSnapshotsEnabled();\n\n    /**\n     * Retrieves the number of achievements registered for this game.\n     *\n     * @return The number of achievements registered for this game.\n     */\n    int getAchievementTotalCount();\n\n    /**\n     * Retrieves the application ID for this game.\n     *\n     * @return The application ID for this game.\n     */\n    @NonNull\n    String getApplicationId();\n\n    /**\n     * Retrieves the description of this game.\n     *\n     * @return The description of this game.\n     */\n    @NonNull\n    String getDescription();\n\n    /**\n     * Loads the description string into the given {@link CharArrayBuffer}.\n     *\n     * @param dataOut The buffer to load the data into.\n     */\n    void getDescription(@NonNull CharArrayBuffer dataOut);\n\n    /**\n     * Retrieves the name of the developer of this game.\n     *\n     * @return The name of the developer of this game.\n     */\n    @NonNull\n    String getDeveloperName();\n\n    /**\n     * Loads the developer name into the given {@link CharArrayBuffer}.\n     *\n     * @param dataOut The buffer to load the data into.\n     */\n    void getDeveloperName(@NonNull CharArrayBuffer dataOut);\n\n    /**\n     * Retrieves the display name for this game.\n     *\n     * @return The display name for this game.\n     */\n    @NonNull\n    String getDisplayName();\n\n    /**\n     * Loads the display name string into the given {@link CharArrayBuffer}.\n     *\n     * @param dataOut The buffer to load the data into.\n     */\n    void getDisplayName(@NonNull CharArrayBuffer dataOut);\n\n    /**\n     * Retrieves an image URI that can be used to load the game's featured (banner) image from Google Play. Returns null if game has no featured image.\n     * <p>\n     * To retrieve the Image from the {@link Uri}, use {@link ImageManager}.\n     *\n     * @return A URI that can be used to load the game's featured image, or null if the game has no featured image.\n     */\n    @Nullable\n    Uri getFeaturedImageUri();\n\n    @Hide\n    @Deprecated\n    String getFeaturedImageUrl();\n\n    /**\n     * Retrieves an image URI that can be used to load the game's hi-res image. Returns null if game has no hi-res image.\n     * <p>\n     * To retrieve the Image from the {@link Uri}, use {@link ImageManager}.\n     *\n     * @return A URI that can be used to load the game's hi-res image, or null if the game has no hi-res image.\n     */\n    @Nullable\n    Uri getHiResImageUri();\n\n    @Hide\n    @Deprecated\n    String getHiResImageUrl();\n\n    /**\n     * Retrieves an image URI that can be used to load the game's icon. Returns null if game has no icon.\n     * <p>\n     * To retrieve the Image from the {@link Uri}, use {@link ImageManager}.\n     *\n     * @return A URI that can be used to load the game's icon, or null if the game has no icon.\n     */\n    @Nullable\n    Uri getIconImageUri();\n\n    @Hide\n    @Deprecated\n    String getIconImageUrl();\n\n    /**\n     * Gets the number of leaderboards registered for this game.\n     *\n     * @return The number of leaderboards registered for this game.\n     */\n    int getLeaderboardCount();\n\n    /**\n     * Retrieves the primary category of the game - this may be null.\n     *\n     * @return The primary category of the game.\n     */\n    @Nullable\n    String getPrimaryCategory();\n\n    /**\n     * Retrieves the secondary category of the game - this may be null.\n     *\n     * @return The secondary category of the game, or null if not provided.\n     */\n    @Nullable\n    String getSecondaryCategory();\n\n    /**\n     * Retrieves the theme color for this game. The theme color is used to configure the appearance of Play Games UIs.\n     *\n     * @return The color to use as an RGB hex triplet, e.g. \"E0E0E0\"\n     */\n    @NonNull\n    String getThemeColor();\n\n    /**\n     * Indicates whether or not this game is marked as supporting gamepads.\n     *\n     * @return Whether or not this game declares gamepad support.\n     */\n    boolean hasGamepadSupport();\n}\n"
  },
  {
    "path": "play-services-games/src/main/java/com/google/android/gms/games/GameColumns.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.games;\n\nimport org.microg.gms.common.Hide;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\n@Hide\npublic class GameColumns {\n    public static final String EXTERNAL_GAME_ID = \"external_game_id\";\n    public static final String DISPLAY_NAME = \"display_name\";\n    public static final String PRIMARY_CATEGORY = \"primary_category\";\n    public static final String SECONDARY_CATEGORY = \"secondary_category\";\n    public static final String GAME_DESCRIPTION = \"game_description\";\n    public static final String DEVELOPER_NAME = \"developer_name\";\n    public static final String GAME_ICON_IMAGE_URI = \"game_icon_image_uri\";\n    public static final String GAME_ICON_IMAGE_URL = \"game_icon_image_url\";\n    public static final String GAME_HI_RES_IMAGE_URI = \"game_hi_res_image_uri\";\n    public static final String GAME_HI_RES_IMAGE_URL = \"game_hi_res_image_url\";\n    public static final String FEATURED_IMAGE_URI = \"featured_image_uri\";\n    public static final String FEATURED_IMAGE_URL = \"featured_image_url\";\n    public static final String PLAY_ENABLED_GAME = \"play_enabled_game\";\n    public static final String MUTED = \"muted\";\n    public static final String IDENTITY_SHARING_CONFIRMED = \"identity_sharing_confirmed\";\n    public static final String INSTALLED = \"installed\";\n    public static final String PACKAGE_NAME = \"package_name\";\n    public static final String ACHIEVEMENT_TOTAL_COUNT = \"achievement_total_count\";\n    public static final String LEADERBOARD_COUNT = \"leaderboard_count\";\n    public static final String REAL_TIME_SUPPORT = \"real_time_support\";\n    public static final String TURN_BASED_SUPPORT = \"turn_based_support\";\n    public static final String SNAPSHOTS_ENABLED = \"snapshots_enabled\";\n    public static final String THEME_COLOR = \"theme_color\";\n    public static final String GAMEPAD_SUPPORT = \"gamepad_support\";\n\n    public static final List<String> CURRENT_GAME_COLUMNS = Collections.unmodifiableList(Arrays.asList(\n            EXTERNAL_GAME_ID, DISPLAY_NAME, PRIMARY_CATEGORY, SECONDARY_CATEGORY, GAME_DESCRIPTION, DEVELOPER_NAME, GAME_ICON_IMAGE_URI, GAME_ICON_IMAGE_URL,\n            GAME_HI_RES_IMAGE_URI, GAME_HI_RES_IMAGE_URL, FEATURED_IMAGE_URI, FEATURED_IMAGE_URL, PLAY_ENABLED_GAME, MUTED, IDENTITY_SHARING_CONFIRMED, INSTALLED,\n            PACKAGE_NAME, ACHIEVEMENT_TOTAL_COUNT, LEADERBOARD_COUNT, REAL_TIME_SUPPORT, TURN_BASED_SUPPORT, SNAPSHOTS_ENABLED, THEME_COLOR, GAMEPAD_SUPPORT\n    ));\n}\n"
  },
  {
    "path": "play-services-games/src/main/java/com/google/android/gms/games/GameEntity.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.games;\n\nimport android.database.CharArrayBuffer;\nimport android.net.Uri;\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.images.ImageManager;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\n\n/**\n * Data object representing a set of Game data. This is immutable, and therefore safe to cache or store. Note, however, that the data it\n * represents may grow stale.\n * <p>\n * This class exists solely to support parceling these objects and should not be used directly.\n */\n@SafeParcelable.Class\npublic class GameEntity extends AbstractSafeParcelable implements Game {\n    @Field(value = 1, getterName = \"getApplicationId\")\n    private final String applicationId;\n    @Field(value = 2, getterName = \"getDisplayName\")\n    private final String displayName;\n    @Field(value = 3, getterName = \"getPrimaryCategory\")\n    private final String primaryCategory;\n    @Field(value = 4, getterName = \"getSecondaryCategory\")\n    private final String secondaryCategory;\n    @Field(value = 5, getterName = \"getDescription\")\n    private final String description;\n    @Field(value = 6, getterName = \"getDeveloperName\")\n    private final String developerName;\n    @Field(value = 7, getterName = \"getIconImageUri\")\n    private final Uri iconImageUri;\n    @Field(value = 8, getterName = \"getHiResImageUri\")\n    private final Uri hiResImageUri;\n    @Field(value = 9, getterName = \"getFeaturedImageUri\")\n    private final Uri featuredImageUri;\n    @Field(value = 10, getterName = \"isPlayEnabledGame\")\n    private final boolean isPlayEnabledGame;\n    @Field(value = 11, getterName = \"isInstanceInstalled\")\n    private final boolean isInstanceInstalled;\n    @Field(value = 12, getterName = \"getInstancePackageName\")\n    private final String instancePackageName;\n    @Field(value = 13, getterName = \"getGameplayAclStatus\")\n    private final int gameplayAclStatus;\n    @Field(value = 14, getterName = \"getAchievementTotalCount\")\n    private final int achievementTotalCount;\n    @Field(value = 15, getterName = \"getLeaderboardCount\")\n    private final int leaderboardCount;\n    @Field(value = 16, getterName = \"isRealTimeMultiplayerEnabled\")\n    private final boolean isRealTimeMultiplayerEnabled;\n    @Field(value = 17, getterName = \"isTurnBasedMultiplayerEnabled\")\n    private final boolean isTurnBasedMultiplayerEnabled;\n    @Field(value = 18, getterName = \"getIconImageUrl\")\n    private final String iconImageUrl;\n    @Field(value = 19, getterName = \"getHiResImageUrl\")\n    private final String hiResImageUrl;\n    @Field(value = 20, getterName = \"getFeaturedImageUrl\")\n    private final String featuredImageUrl;\n    @Field(value = 21, getterName = \"isMuted\")\n    private final boolean isMuted;\n    @Field(value = 22, getterName = \"isIdentitySharingConfirmed\")\n    private final boolean isIdentitySharingConfirmed;\n    @Field(value = 23, getterName = \"areSnapshotsEnabled\")\n    private final boolean areSnapshotsEnabled;\n    @Field(value = 24, getterName = \"getThemeColor\")\n    private final String getThemeColor;\n    @Field(value = 25, getterName = \"hasGamepadSupport\")\n    private final boolean hasGamepadSupport;\n\n    @Hide\n    @Constructor\n    public GameEntity(@Param(value = 1) String applicationId, @Param(value = 2) String displayName, @Param(value = 3) String primaryCategory, @Param(value = 4) String secondaryCategory, @Param(value = 5) String description, @Param(value = 6) String developerName, @Param(value = 7) Uri iconImageUri, @Param(value = 8) Uri hiResImageUri, @Param(value = 9) Uri featuredImageUri, @Param(value = 10) boolean isPlayEnabledGame, @Param(value = 11) boolean isInstanceInstalled, @Param(value = 12) String instancePackageName, @Param(value = 13) int gameplayAclStatus, @Param(value = 14) int achievementTotalCount, @Param(value = 15) int leaderboardCount, @Param(value = 16) boolean isRealTimeMultiplayerEnabled, @Param(value = 17) boolean isTurnBasedMultiplayerEnabled, @Param(value = 18) String iconImageUrl, @Param(value = 19) String hiResImageUrl, @Param(value = 20) String featuredImageUrl, @Param(value = 21) boolean isMuted, @Param(value = 22) boolean isIdentitySharingConfirmed, @Param(value = 23) boolean areSnapshotsEnabled, @Param(value = 24) String getThemeColor, @Param(value = 25) boolean hasGamepadSupport) {\n        this.applicationId = applicationId;\n        this.displayName = displayName;\n        this.primaryCategory = primaryCategory;\n        this.secondaryCategory = secondaryCategory;\n        this.description = description;\n        this.developerName = developerName;\n        this.iconImageUri = iconImageUri;\n        this.iconImageUrl = iconImageUrl;\n        this.hiResImageUri = hiResImageUri;\n        this.hiResImageUrl = hiResImageUrl;\n        this.featuredImageUri = featuredImageUri;\n        this.featuredImageUrl = featuredImageUrl;\n        this.isPlayEnabledGame = isPlayEnabledGame;\n        this.isInstanceInstalled = isInstanceInstalled;\n        this.instancePackageName = instancePackageName;\n        this.gameplayAclStatus = gameplayAclStatus;\n        this.achievementTotalCount = achievementTotalCount;\n        this.leaderboardCount = leaderboardCount;\n        this.isRealTimeMultiplayerEnabled = isRealTimeMultiplayerEnabled;\n        this.isTurnBasedMultiplayerEnabled = isTurnBasedMultiplayerEnabled;\n        this.isMuted = isMuted;\n        this.isIdentitySharingConfirmed = isIdentitySharingConfirmed;\n        this.areSnapshotsEnabled = areSnapshotsEnabled;\n        this.getThemeColor = getThemeColor;\n        this.hasGamepadSupport = hasGamepadSupport;\n    }\n\n    /**\n     * Indicates whether or not this game supports snapshots.\n     *\n     * @return Whether or not this game supports snapshots.\n     */\n    @Override\n    public boolean areSnapshotsEnabled() {\n        return this.areSnapshotsEnabled;\n    }\n\n    @Override\n    public Game freeze() {\n        return this;\n    }\n\n    /**\n     * Retrieves the number of achievements registered for this game.\n     *\n     * @return The number of achievements registered for this game.\n     */\n    @Override\n    public int getAchievementTotalCount() {\n        return this.achievementTotalCount;\n    }\n\n    /**\n     * Retrieves the application ID for this game.\n     *\n     * @return The application ID for this game.\n     */\n    @Override\n    @NonNull\n    public String getApplicationId() {\n        return this.applicationId;\n    }\n\n    /**\n     * Retrieves the description of this game.\n     *\n     * @return The description of this game.\n     */\n    @Override\n    @NonNull\n    public String getDescription() {\n        return this.description;\n    }\n\n    /**\n     * Loads the description string into the given {@link CharArrayBuffer}.\n     *\n     * @param dataOut The buffer to load the data into.\n     */\n    @Override\n    public void getDescription(@NonNull CharArrayBuffer dataOut) {\n        copyStringToBuffer(this.description, dataOut);\n    }\n\n    /**\n     * Retrieves the name of the developer of this game.\n     *\n     * @return The name of the developer of this game.\n     */\n    @Override\n    @NonNull\n    public String getDeveloperName() {\n        return this.developerName;\n    }\n\n    /**\n     * Loads the developer name into the given {@link CharArrayBuffer}.\n     *\n     * @param dataOut The buffer to load the data into.\n     */\n    @Override\n    public void getDeveloperName(@NonNull CharArrayBuffer dataOut) {\n        copyStringToBuffer(this.developerName, dataOut);\n    }\n\n    /**\n     * Retrieves the display name for this game.\n     *\n     * @return The display name for this game.\n     */\n    @Override\n    @NonNull\n    public String getDisplayName() {\n        return this.displayName;\n    }\n\n    /**\n     * Loads the display name string into the given {@link CharArrayBuffer}.\n     *\n     * @param dataOut The buffer to load the data into.\n     */\n    @Override\n    public void getDisplayName(@NonNull CharArrayBuffer dataOut) {\n        copyStringToBuffer(this.displayName, dataOut);\n    }\n\n    /**\n     * Retrieves an image URI that can be used to load the game's featured (banner) image from Google Play. Returns null if game has no featured image.\n     * <p>\n     * To retrieve the Image from the {@link Uri}, use {@link ImageManager}.\n     *\n     * @return A URI that can be used to load the game's featured image, or null if the game has no featured image.\n     */\n    @Override\n    @Nullable\n    public Uri getFeaturedImageUri() {\n        return this.featuredImageUri;\n    }\n\n    @Override\n    @Hide\n    @Deprecated\n    public String getFeaturedImageUrl() {\n        return this.featuredImageUrl;\n    }\n\n    /**\n     * Retrieves an image URI that can be used to load the game's hi-res image. Returns null if game has no hi-res image.\n     * <p>\n     * To retrieve the Image from the {@link Uri}, use {@link ImageManager}.\n     *\n     * @return A URI that can be used to load the game's hi-res image, or null if the game has no hi-res image.\n     */\n    @Override\n    @Nullable\n    public Uri getHiResImageUri() {\n        return this.hiResImageUri;\n    }\n\n    @Override\n    @Hide\n    @Deprecated\n    public String getHiResImageUrl() {\n        return this.hiResImageUrl;\n    }\n\n    /**\n     * Retrieves an image URI that can be used to load the game's icon. Returns null if game has no icon.\n     * <p>\n     * To retrieve the Image from the {@link Uri}, use {@link ImageManager}.\n     *\n     * @return A URI that can be used to load the game's icon, or null if the game has no icon.\n     */\n    @Override\n    public Uri getIconImageUri() {\n        return this.iconImageUri;\n    }\n\n    @Override\n    @Hide\n    @Deprecated\n    public String getIconImageUrl() {\n        return this.iconImageUrl;\n    }\n\n    /**\n     * Gets the number of leaderboards registered for this game.\n     *\n     * @return The number of leaderboards registered for this game.\n     */\n    @Override\n    public int getLeaderboardCount() {\n        return this.leaderboardCount;\n    }\n\n    /**\n     * Retrieves the primary category of the game - this is may be null.\n     *\n     * @return The primary category of the game.\n     */\n    @Override\n    @Nullable\n    public String getPrimaryCategory() {\n        return this.primaryCategory;\n    }\n\n    /**\n     * Retrieves the secondary category of the game - this may be null.\n     *\n     * @return The secondary category of the game, or null if not provided.\n     */\n    @Override\n    @Nullable\n    public String getSecondaryCategory() {\n        return this.secondaryCategory;\n    }\n\n    /**\n     * Retrieves the theme color for this game. The theme color is used to configure the appearance of Play Games UIs.\n     *\n     * @return The color to use as an RGB hex triplet, e.g. \"E0E0E0\"\n     */\n    @Override\n    @NonNull\n    public String getThemeColor() {\n        return this.getThemeColor;\n    }\n\n    /**\n     * Indicates whether or not this game is marked as supporting gamepads.\n     *\n     * @return Whether or not this game declares gamepad support.\n     */\n    @Override\n    public boolean hasGamepadSupport() {\n        return this.hasGamepadSupport;\n    }\n\n    @Override\n    public boolean isDataValid() {\n        return true;\n    }\n\n    int getGameplayAclStatus() {\n        return gameplayAclStatus;\n    }\n\n    String getInstancePackageName() {\n        return this.instancePackageName;\n    }\n\n    boolean isMuted() {\n        return this.isMuted;\n    }\n\n    boolean isIdentitySharingConfirmed() {\n        return this.isIdentitySharingConfirmed;\n    }\n\n    boolean isPlayEnabledGame() {\n        return this.isPlayEnabledGame;\n    }\n\n    boolean isInstanceInstalled() {\n        return this.isInstanceInstalled;\n    }\n\n    @Hide\n    boolean isRealTimeMultiplayerEnabled() {\n        return this.isRealTimeMultiplayerEnabled;\n    }\n\n    @Hide\n    boolean isTurnBasedMultiplayerEnabled() {\n        return this.isTurnBasedMultiplayerEnabled;\n    }\n\n    private static void copyStringToBuffer(@Nullable String toCopy, @NonNull CharArrayBuffer dataOut) {\n        if (toCopy == null || toCopy.isEmpty()) {\n            dataOut.sizeCopied = 0;\n            return;\n        }\n        if (dataOut.data == null || dataOut.data.length < toCopy.length()) {\n            dataOut.data = toCopy.toCharArray();\n        } else {\n            toCopy.getChars(0, toCopy.length(), dataOut.data, 0);\n        }\n        dataOut.sizeCopied = toCopy.length();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<GameEntity> CREATOR = findCreator(GameEntity.class);\n}\n"
  },
  {
    "path": "play-services-games/src/main/java/com/google/android/gms/games/GamesStatusCodes.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.games;\n\nimport com.google.android.gms.common.api.Status;\n\npublic enum GamesStatusCodes {\n    ACHIEVEMENT_NOT_INCREMENTAL(3002, \"Achievement not incremental\"),\n    ACHIEVEMENT_UNKNOWN(3001, \"Achievement unknown\"),\n    ACHIEVEMENT_UNLOCKED(3003, \"Achievement unlocked\"),\n    ACHIEVEMENT_UNLOCK_FAILURE(3000, \"Achievement unlock failure\"),\n    APP_MISCONFIGURED(8, \"App misconfigured\"),\n    CLIENT_RECONNECT_REQUIRED(2, \"Client reconnect required\"),\n    GAME_NOT_FOUND(9, \"Game not found\"),\n    INTERNAL_ERROR(1, \"Internal error\"),\n    INTERRUPTED(14, \"Interrupted\"),\n    INVALID_REAL_TIME_ROOM_ID(7002, \"Invalid real time room ID\"),\n    LICENSE_CHECK_FAILED(7, \"License check failed\"),\n    MATCH_ERROR_ALREADY_REMATCHED(6505, \"Match error already rematched\"),\n    MATCH_ERROR_INACTIVE_MATCH(6501, \"Match error inactive match\"),\n    MATCH_ERROR_INVALID_MATCH_RESULTS(6504, \"Match error invalid match results\"),\n    MATCH_ERROR_INVALID_MATCH_STATE(6502, \"Match error invalid match state\"),\n    MATCH_ERROR_INVALID_PARTICIPANT_STATE(6500, \"Match error invalid participant state\"),\n    MATCH_ERROR_LOCALLY_MODIFIED(6507, \"Match error locally modified\"),\n    MATCH_ERROR_OUT_OF_DATE_VERSION(6503, \"Match error out of date version\"),\n    MATCH_NOT_FOUND(6506, \"Match not found\"),\n    MILESTONE_CLAIMED_PREVIOUSLY(8000, \"Milestone claimed previously\"),\n    MILESTONE_CLAIM_FAILED(8001, \"Milestone claim failed\"),\n    MULTIPLAYER_DISABLED(6003, \"Multiplayer disabled\"),\n    MULTIPLAYER_ERROR_CREATION_NOT_ALLOWED(6000, \"Multiplayer error creation not allowed\"),\n    MULTIPLAYER_ERROR_INVALID_MULTIPLAYER_TYPE(6002, \"Multiplayer error invalid multiplayer type\"),\n    MULTIPLAYER_ERROR_INVALID_OPERATION(6004, \"Multiplayer error invalid operation\"),\n    MULTIPLAYER_ERROR_NOT_TRUSTED_TESTER(6001, \"Multiplayer error not trusted tester\"),\n    NETWORK_ERROR_NO_DATA(4, \"Network error no data\"),\n    NETWORK_ERROR_OPERATION_DEFERRED(5, \"Network error operation deferred\"),\n    NETWORK_ERROR_OPERATION_FAILED(6, \"Network error operation failed\"),\n    NETWORK_ERROR_STALE_DATA(3, \"Network error stale data\"),\n    OK(0, \"OK\"),\n    OPERATION_IN_FLIGHT(7007, \"Operation in flight\"),\n    PARTICIPANT_NOT_CONNECTED(7003, \"Participant not connected\"),\n    QUEST_NOT_STARTED(8003, \"Quest not started\"),\n    QUEST_NO_LONGER_AVAILABLE(8002, \"Quest no longer available\"),\n    REAL_TIME_CONNECTION_FAILED(7000, \"Real time connection failed\"),\n    REAL_TIME_INACTIVE_ROOM(7005, \"Real time inactive room\"),\n    REAL_TIME_MESSAGE_SEND_FAILED(7001, \"Real time message send failed\"),\n    REAL_TIME_ROOM_NOT_JOINED(7004, \"Real time room not joined\"),\n    REQUEST_TOO_MANY_RECIPIENTS(2002, \"Request too many recipients\"),\n    REQUEST_UPDATE_PARTIAL_SUCCESS(2000, \"Request update partial success\"),\n    REQUEST_UPDATE_TOTAL_FAILURE(2001, \"Request update total failure\"),\n    SNAPSHOT_COMMIT_FAILED(4003, \"Snapshot commit failed\"),\n    SNAPSHOT_CONFLICT(4004, \"Snapshot conflict\"),\n    SNAPSHOT_CONFLICT_MISSING(4006, \"Snapshot conflict missing\"),\n    SNAPSHOT_CONTENTS_UNAVAILABLE(4002, \"Snapshot contents unavailable\"),\n    SNAPSHOT_CREATION_FAILED(4001, \"Snapshot creation failed\"),\n    SNAPSHOT_FOLDER_UNAVAILABLE(4005, \"Snapshot folder unavailable\"),\n    SNAPSHOT_NOT_FOUND(4000, \"Snapshot not found\"),\n    TIMEOUT(15, \"Timeout\"),\n    VIDEO_ALREADY_CAPTURING(9006, \"Video already capturing\"),\n    VIDEO_NOT_ACTIVE(9000, \"Video not active\"),\n    VIDEO_OUT_OF_DISK_SPACE(9009, \"Video out of disk space\"),\n    VIDEO_PERMISSION_ERROR(9002, \"Video permission error\"),\n    VIDEO_STORAGE_ERROR(9003, \"Video storage error\"),\n    VIDEO_UNEXPECTED_CAPTURE_ERROR(9004, \"Video unexpected capture error\"),\n    VIDEO_UNSUPPORTED(9001, \"Video unsupported\");\n\n    private final int code;\n    private final String description;\n\n    GamesStatusCodes(int code, String description) {\n        this.code = code;\n        this.description = description;\n    }\n\n    public int getCode() {\n        return code;\n    }\n\n    public String getDescription() {\n        return description;\n    }\n\n    public static Status createStatus(GamesStatusCodes gamesStatusCodes) {\n        return new Status(gamesStatusCodes.code, gamesStatusCodes.description);\n    }\n\n}\n"
  },
  {
    "path": "play-services-games/src/main/java/com/google/android/gms/games/Player.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.games;\n\nimport android.database.CharArrayBuffer;\nimport android.net.Uri;\nimport android.os.Parcelable;\nimport androidx.annotation.IntDef;\nimport com.google.android.gms.common.data.Freezable;\nimport com.google.android.gms.common.images.ImageManager;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\n/**\n * Data interface for retrieving player information.\n */\npublic interface Player extends Freezable<Player>, Parcelable {\n    /**\n     * Friends list visibility statuses.\n     */\n    @IntDef({FriendsListVisibilityStatus.UNKNOWN, FriendsListVisibilityStatus.VISIBLE, FriendsListVisibilityStatus.REQUEST_REQUIRED, FriendsListVisibilityStatus.FEATURE_UNAVAILABLE})\n    @Retention(RetentionPolicy.SOURCE)\n    @interface FriendsListVisibilityStatus {\n        /**\n         * Constant indicating that currently it's unknown if the friends list is visible to the game, or whether the game can ask for\n         * access from the user. Use {@link PlayersClient#getCurrentPlayer(boolean)} to force reload the latest status.\n         */\n        int UNKNOWN = 0;\n        /**\n         * Constant indicating that the friends list is currently visible to the game.\n         */\n        int VISIBLE = 1;\n        /**\n         * Constant indicating that the friends list is not visible to the game, but the game can ask for access.\n         */\n        int REQUEST_REQUIRED = 2;\n        /**\n         * Constant indicating that the friends list is currently unavailable for the game. You cannot request access at this time,\n         * either because the user has permanently declined or the friends feature is not available to them. In this state, any\n         * attempts to request access to the friends list will be unsuccessful.\n         */\n        int FEATURE_UNAVAILABLE = 3;\n    }\n\n    /**\n     * Player friend statuses.\n     */\n    @IntDef({PlayerFriendStatus.UNKNOWN, PlayerFriendStatus.NO_RELATIONSHIP, PlayerFriendStatus.FRIEND})\n    @Retention(RetentionPolicy.SOURCE)\n    @interface PlayerFriendStatus {\n        /**\n         * Constant indicating that the currently signed-in player's friend status with this player is unknown. This may happen if the\n         * user has not shared the friends list with the game.\n         */\n        int UNKNOWN = -1;\n        /**\n         * Constant indicating that the currently signed-in player is not a friend of this player, and there are no pending invitations\n         * between them.\n         */\n        int NO_RELATIONSHIP = 0;\n        /**\n         * Constant indicating that the currently signed-in player and this player are friends.\n         */\n        int FRIEND = 4;\n    }\n\n    /**\n     * Constant indicating that the current XP total for a player is not known.\n     */\n    long CURRENT_XP_UNKNOWN = -1;\n    /**\n     * Constant indicating that a timestamp for a player is not known.\n     */\n    long TIMESTAMP_UNKNOWN = -1;\n\n    /**\n     * Retrieves the URI for loading this player's landscape banner image. Returns null if the player has no landscape banner image.\n     * <p>\n     * To retrieve the Image from the {@link Uri}, use {@link ImageManager}.\n     *\n     * @return The image URI for the player's landscape banner image, or null if the player has none.\n     */\n    Uri getBannerImageLandscapeUri();\n\n    /**\n     * Retrieves the URI for loading this player's portrait banner image. Returns null if the player has no portrait banner image.\n     * <p>\n     * To retrieve the Image from the {@link Uri}, use {@link ImageManager}.\n     *\n     * @return The image URI for the player's portrait banner image, or null if the player has none.\n     */\n    Uri getBannerImagePortraitUri();\n\n    /**\n     * Returns information only available for the signed-in user. The method will return {@code null} for other players.\n     */\n    CurrentPlayerInfo getCurrentPlayerInfo();\n\n    /**\n     * Loads the player's display name into the given {@link CharArrayBuffer}.\n     *\n     * @param dataOut The buffer to load the data into.\n     */\n    void getDisplayName(CharArrayBuffer dataOut);\n\n    /**\n     * Retrieves the display name for this player.\n     *\n     * @return The player's display name.\n     */\n    String getDisplayName();\n\n    /**\n     * Retrieves the URI for loading this player's hi-res profile image. Returns null if the player has no profile image.\n     * <p>\n     * To retrieve the Image from the {@link Uri}, use {@link ImageManager}.\n     *\n     * @return The image URI for the player's hi-res profile image, or null if the player has none.\n     */\n    Uri getHiResImageUri();\n\n    /**\n     * Retrieves the URI for loading this player's icon-size profile image. Returns null if the player has no profile image.\n     * <p>\n     * To retrieve the Image from the {@link Uri}, use {@link ImageManager}.\n     *\n     * @return The image URI for the player's icon-size profile image, or null if the player has none.\n     */\n    Uri getIconImageUri();\n\n    /**\n     * Retrieves the timestamp at which this player last played a multiplayer game with the currently signed in user. If the\n     * timestamp is not found, this method returns {@link #TIMESTAMP_UNKNOWN}.\n     *\n     * @return The timestamp (in ms since epoch) at which the player last played a multiplayer game with the currently signed in user.\n     * @deprecated Real-time multiplayer and Turn-based multiplayer support is being shut down on March 31, 2020.\n     */\n    @Deprecated\n    long getLastPlayedWithTimestamp();\n\n    /**\n     * Retrieves the player level associated information if any exists. If no level information exists for this player, this method will return {@code null}.\n     *\n     * @return The {@link PlayerLevelInfo} associated with this player, if any.\n     */\n    PlayerLevelInfo getLevelInfo();\n\n    /**\n     * Retrieves the ID of this player.\n     *\n     * @return The player ID.\n     */\n    String getPlayerId();\n\n    /**\n     * Returns relationship information of this player. If no relationship information exists for this player, this method will return {@code null}.\n     */\n    PlayerRelationshipInfo getRelationshipInfo();\n\n    /**\n     * Retrieves the timestamp at which this player record was last updated locally.\n     *\n     * @return The timestamp (in ms since epoch) at which the player data was last updated locally.\n     */\n    long getRetrievedTimestamp();\n\n    /**\n     * Retrieves the title of the player. This is based on the player's gameplay activity in apps using Google Play Games\n     * services. Note that not all players have titles, and that a player's title may change over time.\n     *\n     * @return The player's title, or {@code null} if this player has no title.\n     */\n    String getTitle();\n\n    /**\n     * Loads the player's title into the given {@link CharArrayBuffer}.\n     *\n     * @param dataOut The buffer to load the data into.\n     */\n    void getTitle(CharArrayBuffer dataOut);\n\n    /**\n     * Indicates whether this player has a hi-res profile image to display.\n     *\n     * @return Whether the player has a hi-res profile image to display.\n     */\n    boolean hasHiResImage();\n\n    /**\n     * Indicates whether this player has an icon-size profile image to display.\n     *\n     * @return Whether the player has an icon-size profile image to display.\n     */\n    boolean hasIconImage();\n}\n"
  },
  {
    "path": "play-services-games/src/main/java/com/google/android/gms/games/PlayerBuffer.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.games;\n\nimport com.google.android.gms.common.data.AbstractDataBuffer;\nimport com.google.android.gms.common.data.DataHolder;\nimport org.microg.gms.common.Hide;\n\n/**\n * Data structure providing access to a list of players.\n */\npublic class PlayerBuffer extends AbstractDataBuffer<Player> {\n    @Hide\n    public PlayerBuffer(DataHolder dataHolder) {\n        super(dataHolder);\n    }\n\n    public Player get(int position) {\n        throw new UnsupportedOperationException();\n        //return new PlayerRef(dataHolder, position);\n    }\n}\n"
  },
  {
    "path": "play-services-games/src/main/java/com/google/android/gms/games/PlayerColumns.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.games;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class PlayerColumns {\n    public static final String externalPlayerId = \"external_player_id\";\n    public static final String profileName = \"profile_name\";\n    public static final String profileIconImageId = \"profile_icon_image_id\";\n    public static final String profileIconImageUri = \"profile_icon_image_uri\";\n    public static final String profileIconImageUrl = \"profile_icon_image_url\";\n    public static final String profileHiResImageId = \"profile_hi_res_image_id\";\n    public static final String profileHiResImageUri = \"profile_hi_res_image_uri\";\n    public static final String profileHiResImageUrl = \"profile_hi_res_image_url\";\n    public static final String lastUpdated = \"last_updated\";\n    public static final String isInCircles = \"is_in_circles\";\n    public static final String playedWithTimestamp = \"played_with_timestamp\";\n    public static final String currentXpTotal = \"current_xp_total\";\n    public static final String currentLevel = \"current_level\";\n    public static final String currentLevelMinXp = \"current_level_min_xp\";\n    public static final String currentLevelMaxXp = \"current_level_max_xp\";\n    public static final String nextLevel = \"next_level\";\n    public static final String nextLevelMaxXp = \"next_level_max_xp\";\n    public static final String lastLevelUpTimestamp = \"last_level_up_timestamp\";\n    public static final String playerTitle = \"player_title\";\n    public static final String hasAllPublicAcls = \"has_all_public_acls\";\n    public static final String isProfileVisible = \"is_profile_visible\";\n    public static final String mostRecentExternalGameId = \"most_recent_external_game_id\";\n    public static final String mostRecentGameName = \"most_recent_game_name\";\n    public static final String mostRecentActivityTimestamp = \"most_recent_activity_timestamp\";\n    public static final String mostRecentGameIconId = \"most_recent_game_icon_id\";\n    public static final String mostRecentGameIconUri = \"most_recent_game_icon_uri\";\n    public static final String mostRecentGameHiResId = \"most_recent_game_hi_res_id\";\n    public static final String mostRecentGameHiResUri = \"most_recent_game_hi_res_uri\";\n    public static final String mostRecentGameFeaturedId = \"most_recent_game_featured_id\";\n    public static final String mostRecentGameFeaturedUri = \"most_recent_game_featured_uri\";\n    public static final String hasDebugAccess = \"has_debug_access\";\n    public static final String gamerTag = \"gamer_tag\";\n    public static final String realName = \"real_name\";\n    public static final String bannerImageLandscapeId = \"banner_image_landscape_id\";\n    public static final String bannerImageLandscapeUri = \"banner_image_landscape_uri\";\n    public static final String bannerImageLandscapeUrl = \"banner_image_landscape_url\";\n    public static final String bannerImagePortraitId = \"banner_image_portrait_id\";\n    public static final String bannerImagePortraitUri = \"banner_image_portrait_uri\";\n    public static final String bannerImagePortraitUrl = \"banner_image_portrait_url\";\n    public static final String gamerFriendStatus = \"gamer_friend_status\";\n    public static final String gamerFriendUpdateTimestamp = \"gamer_friend_update_timestamp\";\n    public static final String isMuted = \"is_muted\";\n    public static final String totalUnlockedAchievements = \"total_unlocked_achievements\";\n    public static final String playTogetherFriendStatus = \"play_together_friend_status\";\n    public static final String playTogetherNickname = \"play_together_nickname\";\n    public static final String playTogetherInvitationNickname = \"play_together_invitation_nickname\";\n    public static final String nicknameAbuseReportToken = \"nickname_abuse_report_token\";\n    public static final String friendsListVisibility = \"friends_list_visibility\";\n    public static final String alwaysAutoSignIn = \"always_auto_sign_in\";\n    public static final String profileCreationTimestamp = \"profile_creation_timestamp\";\n    public static final String gamePlayerId = \"game_player_id\";\n\n    public static final List<String> CURRENT_PLAYER_COLUMNS = Collections.unmodifiableList(Arrays.asList(\n            externalPlayerId,\n            profileIconImageId, profileHiResImageId, profileIconImageUri, profileIconImageUrl, profileHiResImageUri, profileHiResImageUrl,\n            profileName, lastUpdated, isInCircles, hasAllPublicAcls, hasDebugAccess, isProfileVisible,\n            currentXpTotal, currentLevel, currentLevelMinXp, currentLevelMaxXp, nextLevel, nextLevelMaxXp, lastLevelUpTimestamp,\n            playerTitle,\n            mostRecentExternalGameId, mostRecentGameName, mostRecentActivityTimestamp, mostRecentGameIconId, mostRecentGameIconUri, mostRecentGameHiResId, mostRecentGameHiResUri, mostRecentGameFeaturedId, mostRecentGameFeaturedUri,\n            gamerTag, realName,\n            bannerImageLandscapeId, bannerImageLandscapeUri, bannerImageLandscapeUrl, bannerImagePortraitId, bannerImagePortraitUri, bannerImagePortraitUrl,\n            totalUnlockedAchievements,\n            playTogetherFriendStatus, playTogetherNickname, playTogetherInvitationNickname,\n            profileCreationTimestamp, nicknameAbuseReportToken, friendsListVisibility, alwaysAutoSignIn,\n            gamerFriendStatus, gamerFriendUpdateTimestamp,\n            isMuted, gamePlayerId\n    ));\n}\n"
  },
  {
    "path": "play-services-games/src/main/java/com/google/android/gms/games/PlayerEntity.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.games;\n\nimport android.database.CharArrayBuffer;\nimport android.net.Uri;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.games.internal.player.MostRecentGameInfoEntity;\nimport org.microg.gms.common.Hide;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n/**\n * Data object representing a set of Player data. This is immutable, and therefore safe to cache or store. Note, however, that\n * the data it represents may grow stale.\n * <p>\n * This class exists solely to support parceling these objects and should not be used directly.\n */\npublic class PlayerEntity extends AutoSafeParcelable implements Player {\n    @Field(1)\n    private String playerId;\n    @Field(2)\n    private String displayName;\n    @Field(3)\n    private Uri iconImageUri;\n    @Field(4)\n    private Uri hiResImageUri;\n    @Field(5)\n    private long retrievedTimestamp;\n    @Field(6)\n    private int isInCircles;\n    @Field(7)\n    private long lastPlayedWithTimestamp;\n    @Field(8)\n    private String iconImageUrl;\n    @Field(9)\n    private String hiResImageUrl;\n    @Field(14)\n    private String title;\n    @Field(15)\n    private MostRecentGameInfoEntity mostRecentGameInfo;\n    @Field(16)\n    private PlayerLevelInfo levelInfo;\n    @Field(18)\n    private boolean profileVisible;\n    @Field(19)\n    private boolean hasDebugAccess;\n    @Field(20)\n    private String gamerTag;\n    @Field(21)\n    private String name;\n    @Field(22)\n    private Uri bannerImageLandscapeUri;\n    @Field(23)\n    private String bannerImageLandscapeUrl;\n    @Field(24)\n    private Uri bannerImagePortraitUri;\n    @Field(25)\n    private String bannerImagePortraitUrl;\n    @Field(29)\n    private long totalUnlockedAchievement = -1;\n    @Field(33)\n    private PlayerRelationshipInfoEntity relationshipInfo;\n    @Field(35)\n    private CurrentPlayerInfoEntity currentPlayerInfo;\n    @Field(36)\n    private boolean alwaysAutoSignIn;\n    @Field(37)\n    private String gamePlayerId;\n\n    @Hide\n    public PlayerEntity() {\n    }\n\n    @Hide\n    public PlayerEntity(Player copy) {\n        bannerImageLandscapeUri = copy.getBannerImageLandscapeUri();\n        bannerImagePortraitUri = copy.getBannerImagePortraitUri();\n        currentPlayerInfo = new CurrentPlayerInfoEntity(copy.getCurrentPlayerInfo());\n        displayName = copy.getDisplayName();\n        hiResImageUri = copy.getHiResImageUri();\n        iconImageUri = copy.getIconImageUri();\n        lastPlayedWithTimestamp = copy.getLastPlayedWithTimestamp();\n        levelInfo = copy.getLevelInfo();\n        playerId = copy.getPlayerId();\n        relationshipInfo = new PlayerRelationshipInfoEntity(copy.getRelationshipInfo());\n        retrievedTimestamp = copy.getRetrievedTimestamp();\n        title = copy.getTitle();\n    }\n\n    @Hide\n    public PlayerEntity(String playerId, String displayName, Uri iconImageUri, Uri hiResImageUri, long retrievedTimestamp, int isInCircles, long lastPlayedWithTimestamp, String iconImageUrl, String hiResImageUrl, String title, MostRecentGameInfoEntity mostRecentGameInfo, PlayerLevelInfo levelInfo, boolean profileVisible, boolean hasDebugAccess, String gamerTag, String name, Uri bannerImageLandscapeUri, String bannerImageLandscapeUrl, Uri bannerImagePortraitUri, String bannerImagePortraitUrl, long totalUnlockedAchievement, PlayerRelationshipInfoEntity relationshipInfo, CurrentPlayerInfoEntity currentPlayerInfo, boolean alwaysAutoSignIn, String gamePlayerId) {\n        this.playerId = playerId;\n        this.displayName = displayName;\n        this.iconImageUri = iconImageUri;\n        this.hiResImageUri = hiResImageUri;\n        this.retrievedTimestamp = retrievedTimestamp;\n        this.isInCircles = isInCircles;\n        this.lastPlayedWithTimestamp = lastPlayedWithTimestamp;\n        this.iconImageUrl = iconImageUrl;\n        this.hiResImageUrl = hiResImageUrl;\n        this.title = title;\n        this.mostRecentGameInfo = mostRecentGameInfo;\n        this.levelInfo = levelInfo;\n        this.profileVisible = profileVisible;\n        this.hasDebugAccess = hasDebugAccess;\n        this.gamerTag = gamerTag;\n        this.name = name;\n        this.bannerImageLandscapeUri = bannerImageLandscapeUri;\n        this.bannerImageLandscapeUrl = bannerImageLandscapeUrl;\n        this.bannerImagePortraitUri = bannerImagePortraitUri;\n        this.bannerImagePortraitUrl = bannerImagePortraitUrl;\n        this.totalUnlockedAchievement = totalUnlockedAchievement;\n        this.relationshipInfo = relationshipInfo;\n        this.currentPlayerInfo = currentPlayerInfo;\n        this.alwaysAutoSignIn = alwaysAutoSignIn;\n        this.gamePlayerId = gamePlayerId;\n    }\n\n    @Override\n    public Uri getBannerImageLandscapeUri() {\n        return bannerImageLandscapeUri;\n    }\n\n    @Override\n    public Uri getBannerImagePortraitUri() {\n        return bannerImagePortraitUri;\n    }\n\n    @Override\n    public CurrentPlayerInfo getCurrentPlayerInfo() {\n        return currentPlayerInfo;\n    }\n\n    @Override\n    public void getDisplayName(CharArrayBuffer dataOut) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public String getDisplayName() {\n        return displayName;\n    }\n\n    @Override\n    public Uri getHiResImageUri() {\n        return hiResImageUri;\n    }\n\n    @Override\n    public Uri getIconImageUri() {\n        return iconImageUri;\n    }\n\n    @Override\n    public long getLastPlayedWithTimestamp() {\n        return lastPlayedWithTimestamp;\n    }\n\n    @Override\n    public PlayerLevelInfo getLevelInfo() {\n        return levelInfo;\n    }\n\n    @Override\n    public String getPlayerId() {\n        return playerId;\n    }\n\n    @Override\n    public PlayerRelationshipInfo getRelationshipInfo() {\n        return relationshipInfo;\n    }\n\n    @Override\n    public long getRetrievedTimestamp() {\n        return retrievedTimestamp;\n    }\n\n    @Override\n    public String getTitle() {\n        return title;\n    }\n\n    @Override\n    public void getTitle(CharArrayBuffer dataOut) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public boolean hasHiResImage() {\n        return hiResImageUri != null;\n    }\n\n    @Override\n    public boolean hasIconImage() {\n        return iconImageUri != null;\n    }\n\n    @Override\n    public boolean isDataValid() {\n        return true;\n    }\n\n    @Override\n    public Player freeze() {\n        return this;\n    }\n\n    @Hide\n    public String getGamerTag() {\n        return gamerTag;\n    }\n\n    @Hide\n    public String getName() {\n        return name;\n    }\n\n    @Hide\n    public String getIconImageUrl() {\n        return iconImageUrl;\n    }\n\n    @Hide\n    public String getHiResImageUrl() {\n        return hiResImageUrl;\n    }\n\n    @Hide\n    public String getBannerImageLandscapeUrl() {\n        return bannerImageLandscapeUrl;\n    }\n\n    @Hide\n    public String getBannerImagePortraitUrl() {\n        return bannerImagePortraitUrl;\n    }\n\n    @Hide\n    public int getIsInCircles() {\n        return isInCircles;\n    }\n\n    @Hide\n    public boolean isProfileVisible() {\n        return profileVisible;\n    }\n\n    @Hide\n    public boolean getHasDebugAccess() {\n        return hasDebugAccess;\n    }\n\n    @Hide\n    public long getTotalUnlockedAchievement() {\n        return totalUnlockedAchievement;\n    }\n\n    @Hide\n    public boolean isAlwaysAutoSignIn() {\n        return alwaysAutoSignIn;\n    }\n\n    @Hide\n    public MostRecentGameInfoEntity getMostRecentGameInfo() {\n        return mostRecentGameInfo;\n    }\n\n    public static final SafeParcelableCreatorAndWriter<PlayerEntity> CREATOR = findCreator(PlayerEntity.class);\n}\n"
  },
  {
    "path": "play-services-games/src/main/java/com/google/android/gms/games/PlayerLevel.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.games;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\n\n/**\n * Data object representing a level a player can obtain in the metagame.\n * <p>\n * A {@code PlayerLevel} has three components: a numeric value, and a range of XP totals it represents. A player is considered a\n * given level if they have <b>at least</b> {@link #getMinXp()} and <b>less than</b> {@link #getMaxXp()}.\n */\n@SafeParcelable.Class\npublic class PlayerLevel extends AbstractSafeParcelable {\n    @Field(value = 1, getterName = \"getLevelNumber\")\n    private final int levelNumber;\n    @Field(value = 2, getterName = \"getMinXp\")\n    private final long minXp;\n    @Field(value = 3, getterName = \"getMaxXp\")\n    private final long maxXp;\n\n    @Constructor\n    @Hide\n    public PlayerLevel(@Param(1) int levelNumber, @Param(2) long minXp, @Param(3) long maxXp) {\n        this.levelNumber = levelNumber;\n        this.minXp = minXp;\n        this.maxXp = maxXp;\n    }\n\n    /**\n     * Returns the number for this level, e.g. \"level 10\".\n     * <p>\n     * This is the level that this object represents. For a player to be considered as being of this level, the value given by\n     * {@link PlayerLevelInfo#getCurrentXpTotal()} must fall in the range [{@link #getMinXp()}, {@link #getMaxXp()}).\n     *\n     * @return The level number for this level.\n     */\n    public int getLevelNumber() {\n        return levelNumber;\n    }\n\n    /**\n     * @return The maximum XP value represented by this level, exclusive.\n     */\n    public long getMaxXp() {\n        return maxXp;\n    }\n\n    /**\n     * @return The minimum XP value needed to attain this level, inclusive.\n     */\n    public long getMinXp() {\n        return minXp;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<PlayerLevel> CREATOR = findCreator(PlayerLevel.class);\n}\n"
  },
  {
    "path": "play-services-games/src/main/java/com/google/android/gms/games/PlayerLevelInfo.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.games;\n\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n/**\n * Data object representing the current level information of a player in the metagame.\n * <p>\n * A {@code PlayerLevelInfo} has four components: the player's current XP, the timestamp of the player's last level-up, the\n * player's current level, and the player's next level.\n */\npublic class PlayerLevelInfo extends AutoSafeParcelable {\n    @Field(1)\n    private long currentXpTotal;\n    @Field(2)\n    private long lastLevelUpTimestamp;\n    @Field(3)\n    private PlayerLevel currentLevel;\n    @Field(4)\n    private PlayerLevel nextLevel;\n\n    @Hide\n    public PlayerLevelInfo() {\n    }\n\n    @Hide\n    public PlayerLevelInfo(long currentXpTotal, long lastLevelUpTimestamp, PlayerLevel currentLevel, PlayerLevel nextLevel) {\n        this.currentXpTotal = currentXpTotal;\n        this.lastLevelUpTimestamp = lastLevelUpTimestamp;\n        this.currentLevel = currentLevel;\n        this.nextLevel = nextLevel;\n    }\n\n    /**\n     * Getter for the player's current level object. This object will be the same as the one returned from {@link #getNextLevel()} if the\n     * player reached the maximum level.\n     *\n     * @return The player's current level object.\n     * @see #isMaxLevel()\n     */\n    public PlayerLevel getCurrentLevel() {\n        return currentLevel;\n    }\n\n    /**\n     * @return The player's current XP value.\n     */\n    public long getCurrentXpTotal() {\n        return currentXpTotal;\n    }\n\n    /**\n     * @return The timestamp of the player's last level-up.\n     */\n    public long getLastLevelUpTimestamp() {\n        return lastLevelUpTimestamp;\n    }\n\n    /**\n     * Getter for the player's next level object. This object will be the same as the one returned from {@link #getCurrentLevel()} if the\n     * player reached the maximum level.\n     *\n     * @return The player's next level object.\n     * @see #isMaxLevel()\n     */\n    public PlayerLevel getNextLevel() {\n        return nextLevel;\n    }\n\n    /**\n     * @return {@code true} if the player reached the maximum level ({@link #getCurrentLevel()} is the same as {@link #getNextLevel()}.\n     */\n    public boolean isMaxLevel() {\n        return currentLevel.equals(nextLevel);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<PlayerLevelInfo> CREATOR = findCreator(PlayerLevelInfo.class);\n}\n"
  },
  {
    "path": "play-services-games/src/main/java/com/google/android/gms/games/PlayerRef.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.games;\n\nimport android.database.CharArrayBuffer;\nimport android.net.Uri;\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.data.DataBufferRef;\nimport com.google.android.gms.common.data.DataHolder;\nimport org.microg.gms.common.Hide;\n\n@Hide\npublic class PlayerRef extends DataBufferRef implements Player {\n    public PlayerRef(DataHolder dataHolder, int position) {\n        super(dataHolder, position);\n    }\n\n    private Uri toUri(String str) {\n        if (str == null) return null;\n        return Uri.parse(str);\n    }\n\n    @Override\n    public Uri getBannerImageLandscapeUri() {\n        return toUri(getString(PlayerColumns.bannerImageLandscapeUri));\n    }\n\n    @Override\n    public Uri getBannerImagePortraitUri() {\n        return toUri(getString(PlayerColumns.bannerImagePortraitUri));\n    }\n\n    @Override\n    public CurrentPlayerInfo getCurrentPlayerInfo() {\n        return null;\n    }\n\n    @Override\n    public void getDisplayName(CharArrayBuffer dataOut) {\n        copyToBuffer(PlayerColumns.profileName, dataOut);\n    }\n\n    @Override\n    public String getDisplayName() {\n        return getString(PlayerColumns.profileName);\n    }\n\n    @Override\n    public Uri getHiResImageUri() {\n        return toUri(getString(PlayerColumns.profileHiResImageUri));\n    }\n\n    @Override\n    public Uri getIconImageUri() {\n        return toUri(getString(PlayerColumns.profileIconImageUri));\n    }\n\n    @Override\n    public long getLastPlayedWithTimestamp() {\n        return getLong(PlayerColumns.playedWithTimestamp);\n    }\n\n    @Override\n    public PlayerLevelInfo getLevelInfo() {\n        return null;\n    }\n\n    @Override\n    public String getPlayerId() {\n        return getString(PlayerColumns.externalPlayerId);\n    }\n\n    @Override\n    public PlayerRelationshipInfo getRelationshipInfo() {\n        return null;\n    }\n\n    @Override\n    public long getRetrievedTimestamp() {\n        return getLong(PlayerColumns.lastUpdated);\n    }\n\n    @Override\n    public String getTitle() {\n        return getString(PlayerColumns.playerTitle);\n    }\n\n    @Override\n    public void getTitle(CharArrayBuffer dataOut) {\n        copyToBuffer(PlayerColumns.playerTitle, dataOut);\n    }\n\n    @Override\n    public boolean hasHiResImage() {\n        return hasColumn(PlayerColumns.profileHiResImageUri);\n    }\n\n    @Override\n    public boolean hasIconImage() {\n        return hasColumn(PlayerColumns.profileIconImageUri);\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        new PlayerEntity(this).writeToParcel(dest, flags);\n    }\n\n    @Override\n    public Player freeze() {\n        return null;\n    }\n\n    public static final Creator<Player> CREATOR = new Creator<Player>() {\n        @Override\n        public Player createFromParcel(Parcel source) {\n            return PlayerEntity.CREATOR.createFromParcel(source);\n        }\n\n        @Override\n        public Player[] newArray(int size) {\n            return new Player[size];\n        }\n    };\n}\n"
  },
  {
    "path": "play-services-games/src/main/java/com/google/android/gms/games/PlayerRelationshipInfo.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.games;\n\nimport android.os.Parcelable;\nimport com.google.android.gms.common.data.Freezable;\n\n/**\n * Data object representing the relationship information of a player.\n */\npublic interface PlayerRelationshipInfo extends Freezable<PlayerRelationshipInfo>, Parcelable {\n    /**\n     * Retrieves this player's friend status relative to the currently signed-in player. The possible output can be found in\n     * {@link Player.PlayerFriendStatus}.\n     */\n    @Player.PlayerFriendStatus\n    int getFriendStatus();\n}\n"
  },
  {
    "path": "play-services-games/src/main/java/com/google/android/gms/games/PlayerRelationshipInfoEntity.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.games;\n\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n@Hide\npublic class PlayerRelationshipInfoEntity extends AutoSafeParcelable implements PlayerRelationshipInfo {\n    @Field(1)\n    @Player.PlayerFriendStatus\n    private int friendStatus;\n    @Field(2)\n    private String nickname;\n    @Field(3)\n    private String invitationNickname;\n    @Field(4)\n    private String nicknameAbuseReportToken;\n\n    public PlayerRelationshipInfoEntity() {\n    }\n\n    public PlayerRelationshipInfoEntity(PlayerRelationshipInfo copy) {\n        friendStatus = copy.getFriendStatus();\n    }\n\n    public PlayerRelationshipInfoEntity(int friendStatus, String nickname, String invitationNickname, String nicknameAbuseReportToken) {\n        this.friendStatus = friendStatus;\n        this.nickname = nickname;\n        this.invitationNickname = invitationNickname;\n        this.nicknameAbuseReportToken = nicknameAbuseReportToken;\n    }\n\n    @Override\n    @Player.PlayerFriendStatus\n    public int getFriendStatus() {\n        return friendStatus;\n    }\n\n    @Override\n    public PlayerRelationshipInfo freeze() {\n        return this;\n    }\n\n    @Override\n    public boolean isDataValid() {\n        return true;\n    }\n\n    public String getNickname() {\n        return nickname;\n    }\n\n    public String getInvitationNickname() {\n        return invitationNickname;\n    }\n\n    public String getNicknameAbuseReportToken() {\n        return nicknameAbuseReportToken;\n    }\n\n    public static final SafeParcelableCreatorAndWriter<PlayerRelationshipInfoEntity> CREATOR = findCreator(PlayerRelationshipInfoEntity.class);\n}\n"
  },
  {
    "path": "play-services-games/src/main/java/com/google/android/gms/games/Players.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.games;\n\n/**\n * Entry point for player functionality.\n *\n * @deprecated Use {@link PlayersClient} instead\n */\n@Deprecated\npublic interface Players {\n}\n"
  },
  {
    "path": "play-services-games/src/main/java/com/google/android/gms/games/PlayersClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.games;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.os.RemoteException;\nimport com.google.android.gms.tasks.Task;\n\n/**\n * A client to interact with Players.\n */\npublic interface PlayersClient {\n    /**\n     * Used by the Player Search UI to return a list of parceled Player objects. Retrieve with {@link Intent#getParcelableArrayListExtra(String)}.\n     *\n     * @see #getPlayerSearchIntent()\n     */\n    String EXTRA_PLAYER_SEARCH_RESULTS = \"player_search_results\";\n\n    /**\n     * Returns a {@link Task} which asynchronously loads the current signed-in {@link Player}, if available.\n     * <p>\n     * The returned {@code Task} can fail with a {@link RemoteException}.\n     *\n     * @param forceReload If {@code true}, this call will clear any locally-cached data and attempt to fetch the latest data from the server. This would\n     *                    commonly be used for something like a user-initiated refresh. Normally, this should be set to {@code false} to gain advantages\n     *                    of data caching.\n     */\n    Task<AnnotatedData<Player>> getCurrentPlayer(boolean forceReload);\n\n    /**\n     * Returns a {@link Task} which asynchronously loads the current signed-in {@link Player}, if available.\n     * <p>\n     * The returned {@code Task} can fail with a {@link RemoteException}.\n     */\n    Task<Player> getCurrentPlayer();\n\n    /**\n     * Returns a {@link Task} which asynchronously loads the current signed-in player ID, if available.\n     * <p>\n     * The returned {@code Task} can fail with a {@link RemoteException}.\n     */\n    Task<String> getCurrentPlayerId();\n\n    /**\n     * Returns a {@link Task} which asynchronously loads an {@link Intent} that will display a screen where the user can search for players.\n     * <p>\n     * Note that this must be invoked with {@link Activity#startActivityForResult(Intent, int)}, so that the identity of the\n     * calling package can be established.\n     * <p>\n     * If the user canceled, the result will be {@link Activity#RESULT_CANCELED}. If the user selected any players from the search\n     * results list, the result will be {@link Activity#RESULT_OK}, and the data intent will contain a list of parceled Player objects in\n     * {@link #EXTRA_PLAYER_SEARCH_RESULTS}.\n     * <p>\n     * Note that the current Player Search UI only allows a single selection, so the returned list of parceled Player objects will\n     * currently contain at most one Player.\n     * <p>\n     * The returned {@code Task} can fail with a {@link RemoteException}.\n     */\n    Task<Intent> getPlayerSearchIntent();\n}\n"
  },
  {
    "path": "play-services-games/src/main/java/com/google/android/gms/games/achievement/package-info.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n/**\n * Contains classes for loading and updating achievements.\n */\npackage com.google.android.gms.games.achievement;\n"
  },
  {
    "path": "play-services-games/src/main/java/com/google/android/gms/games/client/PlayGamesConsistencyTokens.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.games.client;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport androidx.annotation.NonNull;\nimport org.microg.gms.utils.ToStringHelper;\n\npublic class PlayGamesConsistencyTokens implements Parcelable {\n    public final String oneupConsistencyToken;\n    public final String superGlueConsistencyToken;\n\n    public PlayGamesConsistencyTokens(String oneupConsistencyToken, String superGlueConsistencyToken) {\n        this.oneupConsistencyToken = oneupConsistencyToken;\n        this.superGlueConsistencyToken = superGlueConsistencyToken;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"PlayGamesConsistencyTokens\")\n                .field(\"oneupConsistencyToken\", oneupConsistencyToken)\n                .field(\"superGlueConsistencyToken\", superGlueConsistencyToken)\n                .end();\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(oneupConsistencyToken);\n        dest.writeString(superGlueConsistencyToken);\n    }\n\n    public static final Creator<PlayGamesConsistencyTokens> CREATOR = new Creator<PlayGamesConsistencyTokens>() {\n        @Override\n        public PlayGamesConsistencyTokens createFromParcel(Parcel source) {\n            return new PlayGamesConsistencyTokens(source.readString(), source.readString());\n        }\n\n        @Override\n        public PlayGamesConsistencyTokens[] newArray(int size) {\n            return new PlayGamesConsistencyTokens[size];\n        }\n    };\n}\n"
  },
  {
    "path": "play-services-games/src/main/java/com/google/android/gms/games/internal/connect/GamesSignInRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.games.internal.connect;\n\nimport androidx.annotation.NonNull;\nimport org.microg.gms.utils.ToStringHelper;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class GamesSignInRequest extends AutoSafeParcelable {\n    @Field(1)\n    public int signInType;\n    @Field(2)\n    public SignInResolutionResult previousStepResolutionResult;\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"GamesSignInRequest\")\n                .field(\"signInType\", signInType)\n                .field(\"previousStepResolutionResult\", previousStepResolutionResult)\n                .end();\n    }\n\n    public static final Creator<GamesSignInRequest> CREATOR = findCreator(GamesSignInRequest.class);\n}\n"
  },
  {
    "path": "play-services-games/src/main/java/com/google/android/gms/games/internal/connect/GamesSignInResponse.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.games.internal.connect;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class GamesSignInResponse extends AutoSafeParcelable {\n    @Field(1)\n    public String gameRunToken;\n    public static final Creator<GamesSignInResponse> CREATOR = findCreator(GamesSignInResponse.class);\n}\n"
  },
  {
    "path": "play-services-games/src/main/java/com/google/android/gms/games/internal/connect/SignInResolutionResult.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.games.internal.connect;\n\nimport android.content.Intent;\nimport androidx.annotation.NonNull;\nimport org.microg.gms.utils.ToStringHelper;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class SignInResolutionResult extends AutoSafeParcelable {\n    @Field(1)\n    public Intent resultData;\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"SignInResolutionResult\").field(\"resultData\", resultData).end();\n    }\n\n    public static final Creator<SignInResolutionResult> CREATOR = findCreator(SignInResolutionResult.class);\n}\n"
  },
  {
    "path": "play-services-games/src/main/java/com/google/android/gms/games/internal/player/MostRecentGameInfo.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.games.internal.player;\n\nimport android.net.Uri;\nimport android.os.Parcelable;\nimport com.google.android.gms.common.data.Freezable;\n\npublic interface MostRecentGameInfo extends Freezable<MostRecentGameInfo>, Parcelable {\n    long getActivityTimestampMillis();\n\n    Uri getGameFeaturedImageUri();\n\n    Uri getGameHiResImageUri();\n\n    Uri getGameIconImageUri();\n\n    String getGameId();\n\n    String getGameName();\n}\n"
  },
  {
    "path": "play-services-games/src/main/java/com/google/android/gms/games/internal/player/MostRecentGameInfoEntity.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.games.internal.player;\n\nimport android.net.Uri;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class MostRecentGameInfoEntity extends AutoSafeParcelable implements MostRecentGameInfo {\n    @Field(1)\n    private String gameId;\n    @Field(2)\n    private String gameName;\n    @Field(3)\n    private long activityTimestampMillis;\n    @Field(4)\n    private Uri gameIconImageUri;\n    @Field(5)\n    private Uri gameHiResImageUri;\n    @Field(6)\n    private Uri gameFeaturedImageUri;\n\n    @Hide\n    public MostRecentGameInfoEntity() {\n    }\n\n    @Hide\n    public MostRecentGameInfoEntity(String gameId, String gameName, long activityTimestampMillis, Uri gameIconImageUri, Uri gameHiResImageUri, Uri gameFeaturedImageUri) {\n        this.gameId = gameId;\n        this.gameName = gameName;\n        this.activityTimestampMillis = activityTimestampMillis;\n        this.gameIconImageUri = gameIconImageUri;\n        this.gameHiResImageUri = gameHiResImageUri;\n        this.gameFeaturedImageUri = gameFeaturedImageUri;\n    }\n\n    @Override\n    public long getActivityTimestampMillis() {\n        return activityTimestampMillis;\n    }\n\n    @Override\n    public Uri getGameFeaturedImageUri() {\n        return gameFeaturedImageUri;\n    }\n\n    @Override\n    public Uri getGameHiResImageUri() {\n        return gameHiResImageUri;\n    }\n\n    @Override\n    public Uri getGameIconImageUri() {\n        return gameIconImageUri;\n    }\n\n    @Override\n    public String getGameId() {\n        return gameId;\n    }\n\n    @Override\n    public String getGameName() {\n        return gameName;\n    }\n\n    @Override\n    public boolean isDataValid() {\n        return true;\n    }\n\n    @Override\n    public MostRecentGameInfo freeze() {\n        return this;\n    }\n\n    public static final SafeParcelableCreatorAndWriter<MostRecentGameInfoEntity> CREATOR = findCreator(MostRecentGameInfoEntity.class);\n}\n"
  },
  {
    "path": "play-services-games/src/main/java/com/google/android/gms/games/leaderboard/package-info.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n/**\n * Contains data classes for leaderboards.\n */\npackage com.google.android.gms.games.leaderboard;\n"
  },
  {
    "path": "play-services-games/src/main/java/com/google/android/gms/games/multiplayer/realtime/RealTimeMessage.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2019 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.games.multiplayer.realtime;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport org.microg.gms.common.Hide;\n\n@Hide\npublic final class RealTimeMessage implements Parcelable {\n    public static final int RELIABLE = 1;\n    public static final int UNRELIABLE = 0;\n\n    private final String senderParticipantId;\n    private final byte[] messageData;\n    private final int reliable;\n\n    public RealTimeMessage(String senderParticipantId, byte[] messageData, int reliable) {\n        this.senderParticipantId = senderParticipantId;\n        this.messageData = messageData.clone();\n        this.reliable = reliable;\n    }\n\n    private RealTimeMessage(Parcel parcel) {\n        this(parcel.readString(), parcel.createByteArray(), parcel.readInt());\n    }\n\n    public static final Creator<RealTimeMessage> CREATOR = new Creator<RealTimeMessage>() {\n        @Override\n        public RealTimeMessage createFromParcel(Parcel in) {\n            return new RealTimeMessage(in);\n        }\n        @Override\n        public RealTimeMessage[] newArray(int size) {\n            return new RealTimeMessage[size];\n        }\n    };\n\n    public byte[] getMessageData() {\n        return this.messageData;\n    }\n\n    public String getSenderParticipantId() {\n        return this.senderParticipantId;\n    }\n\n    public boolean isReliable() {\n        return this.reliable == RELIABLE;\n    }\n\n    @Override\n    public void writeToParcel(Parcel parcel, int flag) {\n        parcel.writeString(this.senderParticipantId);\n        parcel.writeByteArray(this.messageData);\n        parcel.writeInt(this.reliable);\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n}\n"
  },
  {
    "path": "play-services-games/src/main/java/com/google/android/gms/games/package-info.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n/**\n * Contains the games client class.\n */\npackage com.google.android.gms.games;\n"
  },
  {
    "path": "play-services-games/src/main/java/com/google/android/gms/games/snapshot/SnapshotColumns.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.games.snapshot;\n\nimport org.microg.gms.common.Hide;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\n@Hide\npublic class SnapshotColumns {\n    public static final String EXTERNAL_SNAPSHOT_ID = \"external_snapshot_id\";\n    public static final String COVER_ICON_IMAGE_URI = \"cover_icon_image_uri\";\n    public static final String COVER_ICON_IMAGE_URL = \"cover_icon_image_url\";\n    public static final String COVER_ICON_IMAGE_HEIGHT = \"cover_icon_image_height\";\n    public static final String COVER_ICON_IMAGE_WIDTH = \"cover_icon_image_width\";\n    public static final String UNIQUE_NAME = \"unique_name\";\n    public static final String TITLE = \"title\";\n    public static final String DESCRIPTION = \"description\";\n    public static final String LAST_MODIFIED_TIMESTAMP = \"last_modified_timestamp\";\n    public static final String DURATION = \"duration\";\n    public static final String PENDING_CHANGE_COUNT = \"pending_change_count\";\n    public static final String PROGRESS_VALUE = \"progress_value\";\n    public static final String DEVICE_NAME = \"device_name\";\n\n    public static final List<String> CURRENT_GAME_COLUMNS = Collections.unmodifiableList(Arrays.asList(\n            EXTERNAL_SNAPSHOT_ID, COVER_ICON_IMAGE_URI, COVER_ICON_IMAGE_URL, COVER_ICON_IMAGE_HEIGHT,\n            COVER_ICON_IMAGE_WIDTH, UNIQUE_NAME, TITLE, DESCRIPTION, LAST_MODIFIED_TIMESTAMP, DURATION,\n            PENDING_CHANGE_COUNT, PROGRESS_VALUE, DEVICE_NAME\n    ));\n}\n"
  },
  {
    "path": "play-services-games/src/main/java/com/google/android/gms/games/snapshot/SnapshotMetadata.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.games.snapshot;\n\nimport android.database.CharArrayBuffer;\nimport android.net.Uri;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.data.Freezable;\nimport com.google.android.gms.common.images.ImageManager;\nimport com.google.android.gms.games.Game;\nimport com.google.android.gms.games.Player;\nimport org.microg.gms.common.Hide;\n\n/**\n * Data interface for the metadata of a saved game.\n */\npublic interface SnapshotMetadata extends Freezable<SnapshotMetadata> {\n    /**\n     * Constant indicating that the played time of a snapshot is unknown.\n     */\n    long PLAYED_TIME_UNKNOWN = -1;\n    /**\n     * Constant indicating that the progress value of a snapshot is unknown.\n     */\n    long PROGRESS_VALUE_UNKNOWN = -1;\n\n    /**\n     * Retrieves the aspect ratio of the cover image for this snapshot, if any. This is the ratio of width to height, so a value > 1.0f indicates a\n     * landscape image while a value < 1.0f indicates a portrait image. If the snapshot has no cover image, this will return 0.0f.\n     *\n     * @return The aspect ratio of the cover image, or 0.0f if no image is present.\n     */\n    float getCoverImageAspectRatio();\n\n    /**\n     * Retrieves an image URI that can be used to load the snapshot's cover image. Returns null if the snapshot has no cover image.\n     * <p>\n     * To retrieve the Image from the {@link Uri}, use {@link ImageManager}.\n     *\n     * @return A URI that can be used to load this snapshot's cover image, if one is present.\n     */\n    @Nullable\n    Uri getCoverImageUri();\n\n    @Hide\n    @Deprecated\n    String getCoverImageUrl();\n\n    /**\n     * Retrieves the description of this snapshot.\n     *\n     * @return The description of this snapshot.\n     */\n    @NonNull\n    String getDescription();\n\n    /**\n     * Loads the snapshot description into the given {@link CharArrayBuffer}.\n     *\n     * @param dataOut The buffer to load the data into.\n     */\n    void getDescription(@NonNull CharArrayBuffer dataOut);\n\n    /**\n     * Retrieves the name of the device that wrote this snapshot, if known.\n     *\n     * @return The name of the device that wrote this snapshot, or null if not known.\n     */\n    @Nullable\n    String getDeviceName();\n\n    /**\n     * Retrieves the game associated with this snapshot.\n     *\n     * @return The associated game.\n     */\n    @NonNull\n    Game getGame();\n\n    /**\n     * Retrieves the last time this snapshot was modified, in millis since epoch.\n     *\n     * @return The last modification time of this snapshot.\n     */\n    long getLastModifiedTimestamp();\n\n    /**\n     * Retrieves the player that owns this snapshot.\n     *\n     * @return The owning player.\n     */\n    @NonNull\n    Player getOwner();\n\n    /**\n     * Retrieves the played time of this snapshot in milliseconds. This value is specified during the update operation. If not known, returns\n     * {@link #PLAYED_TIME_UNKNOWN}.\n     *\n     * @return The played time of this snapshot in milliseconds, or {@link #PLAYED_TIME_UNKNOWN} if not known.\n     */\n    long getPlayedTime();\n\n    /**\n     * Retrieves the progress value for this snapshot. Can be used to provide automatic conflict resolution (see\n     * {@link SnapshotsClient#RESOLUTION_POLICY_HIGHEST_PROGRESS}). If not known, returns {@link #PROGRESS_VALUE_UNKNOWN}.\n     *\n     * @return Progress value for this snapshot, or {@link #PROGRESS_VALUE_UNKNOWN} if not known.\n     */\n    long getProgressValue();\n\n    /**\n     * Retrieves the ID of this snapshot.\n     *\n     * @return The ID of this snapshot.\n     */\n    @NonNull\n    String getSnapshotId();\n\n    /**\n     * Retrieves the unique identifier of this snapshot. This value can be passed to {@link SnapshotsClient#open(SnapshotMetadata)} to open the\n     * snapshot for modification.\n     * <p>\n     * This name should be unique within the scope of the application.\n     *\n     * @return Unique identifier of this snapshot.\n     */\n    @NonNull\n    String getUniqueName();\n\n    /**\n     * Indicates whether or not this snapshot has any changes pending that have not been uploaded to the server. Once all changes have been\n     * flushed to the server, this will return false.\n     *\n     * @return Whether or not this snapshot has any outstanding changes.\n     */\n    boolean hasChangePending();\n}\n"
  },
  {
    "path": "play-services-games/src/main/java/com/google/android/gms/games/snapshot/SnapshotMetadataChange.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.games.snapshot;\n\nimport android.graphics.Bitmap;\nimport androidx.annotation.Nullable;\n\n/**\n * A collection of changes to apply to the metadata of a snapshot. Fields that are not set will retain their current values.\n */\npublic interface SnapshotMetadataChange {\n    /**\n     * Returns the new cover image to set for the snapshot.\n     */\n    @Nullable\n    Bitmap getCoverImage();\n\n    /**\n     * Returns the new description to set for the snapshot.\n     */\n    @Nullable\n    String getDescription();\n\n    /**\n     * Returns the new played time to set for the snapshot.\n     */\n    @Nullable\n    Long getPlayedTimeMillis();\n\n    /**\n     * Returns the new progress value to set for the snapshot.\n     */\n    @Nullable\n    Long getProgressValue();\n}\n"
  },
  {
    "path": "play-services-games/src/main/java/com/google/android/gms/games/snapshot/SnapshotMetadataChangeEntity.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.games.snapshot;\n\nimport android.graphics.Bitmap;\nimport android.net.Uri;\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.google.android.gms.common.data.BitmapTeleporter;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\n\n@Hide\n@SafeParcelable.Class\npublic class SnapshotMetadataChangeEntity extends AbstractSafeParcelable implements SnapshotMetadataChange {\n\n    @Field(value = 1, getterName = \"getDescription\")\n    @Nullable\n    private final String description;\n    @Field(value = 2, getterName = \"getPlayedTimeMillis\")\n    @Nullable\n    private final Long playedTimeMillis;\n    @Field(value = 4, getterName = \"getCoverImageUri\")\n    @Nullable\n    private final Uri coverImageUri;\n    @Field(value = 5, getterName = \"getCoverImageTeleporter\")\n    @Nullable\n    private final BitmapTeleporter coverImageTeleporter;\n    @Field(value = 6, getterName = \"getProgressValue\")\n    @Nullable\n    private final Long progressValue;\n\n    @Constructor\n    SnapshotMetadataChangeEntity(@Nullable @Param(value = 1) String description, @Nullable @Param(value = 2) Long playedTimeMillis, @Nullable @Param(value = 5) BitmapTeleporter coverImageTeleporter, @Nullable @Param(value = 4) Uri coverImageUri, @Nullable @Param(value = 6) Long progressValue) {\n        this.description = description;\n        this.playedTimeMillis = playedTimeMillis;\n        this.coverImageTeleporter = coverImageTeleporter;\n        this.coverImageUri = coverImageUri;\n        this.progressValue = progressValue;\n    }\n\n    /**\n     * Returns the new cover image to set for the snapshot.\n     */\n    @Override\n    @Nullable\n    public Bitmap getCoverImage() {\n        return this.coverImageTeleporter == null ? null : this.coverImageTeleporter.createTargetBitmap();\n    }\n\n    @Nullable\n    public BitmapTeleporter getCoverImageTeleporter() {\n        return this.coverImageTeleporter;\n    }\n\n    @Nullable\n    Uri getCoverImageUri() {\n        return coverImageUri;\n    }\n\n    /**\n     * Returns the new description to set for the snapshot.\n     */\n    @Override\n    @Nullable\n    public String getDescription() {\n        return this.description;\n    }\n\n    /**\n     * Returns the new played time to set for the snapshot.\n     */\n    @Override\n    @Nullable\n    public Long getPlayedTimeMillis() {\n        return this.playedTimeMillis;\n    }\n\n    /**\n     * Returns the new progress value to set for the snapshot.\n     */\n    @Override\n    @Nullable\n    public Long getProgressValue() {\n        return this.progressValue;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<SnapshotMetadataChangeEntity> CREATOR = findCreator(SnapshotMetadataChangeEntity.class);\n\n    @Override\n    public String toString() {\n        return \"SnapshotMetadataChangeEntity{\" +\n                \"description='\" + description + '\\'' +\n                \", playedTimeMillis=\" + playedTimeMillis +\n                \", coverImageUri=\" + coverImageUri +\n                \", coverImageTeleporter=\" + coverImageTeleporter +\n                \", progressValue=\" + progressValue +\n                '}';\n    }\n}\n"
  },
  {
    "path": "play-services-games/src/main/java/com/google/android/gms/games/snapshot/SnapshotMetadataEntity.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.games.snapshot;\n\nimport android.database.CharArrayBuffer;\nimport android.net.Uri;\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.google.android.gms.common.images.ImageManager;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.games.GameEntity;\nimport com.google.android.gms.games.PlayerEntity;\nimport org.microg.gms.common.Hide;\n\n@SafeParcelable.Class\npublic class SnapshotMetadataEntity extends AbstractSafeParcelable implements SnapshotMetadata {\n\n    @Field(value = 1, getterName = \"getGame\")\n    private final GameEntity game;\n    @Field(value = 2, getterName = \"getOwner\")\n    private final PlayerEntity player;\n    @Field(value = 3, getterName = \"getSnapshotId\")\n    private final String snapshotId;\n    @Field(value = 5, getterName = \"getCoverImageUri\")\n    @Nullable\n    private final Uri coverImageUri;\n    @Field(value = 6, getterName = \"getCoverImageUrl\")\n    @Nullable\n    private final String coverImageUrl;\n    @Field(value = 7, getterName = \"getTitle\")\n    private final String title;\n    @Field(value = 8, getterName = \"getDescription\")\n    private final String description;\n    @Field(value = 9, getterName = \"getLastModifiedTimestamp\")\n    private final long lastModifiedTimestamp;\n    @Field(value = 10, getterName = \"getPlayedTime\")\n    private final long playedTime;\n    @Field(value = 11, getterName = \"getCoverImageAspectRatio\")\n    private final float coverImageAspectRatio;\n    @Field(value = 12, getterName = \"getUniqueName\")\n    private final String uniqueName;\n    @Field(value = 13, getterName = \"hasChangePending\")\n    private final boolean hasChangePending;\n    @Field(value = 14, getterName = \"getProgressValue\")\n    private final long progressValue;\n    @Field(value = 15, getterName = \"getDeviceName\")\n    @Nullable\n    private final String deviceName;\n\n    @Hide\n    @Constructor\n    public SnapshotMetadataEntity(@Param(value = 1) GameEntity gameEntity, @Param(value = 2) PlayerEntity playerEntity, @Param(value = 3) String snapshotId, @Param(value = 5) @Nullable Uri coverImageUri,@Param(value = 6) @Nullable String coverImageUrl, @Param(value = 7) String title, @Param(value = 8) String description, @Param(value = 9) long lastModifiedTimestamp, @Param(value = 10) long playedTime, @Param(value = 11) float coverImageAspectRatio, @Param(value = 12) String uniqueName, @Param(value = 13) boolean hasChangePending, @Param(value = 14) long progressValue, @Param(value = 15) @Nullable String deviceName) {\n        this.game = gameEntity;\n        this.player = playerEntity;\n        this.snapshotId = snapshotId;\n        this.coverImageUri = coverImageUri;\n        this.coverImageUrl = coverImageUrl;\n        this.coverImageAspectRatio = coverImageAspectRatio;\n        this.title = title;\n        this.description = description;\n        this.lastModifiedTimestamp = lastModifiedTimestamp;\n        this.playedTime = playedTime;\n        this.uniqueName = uniqueName;\n        this.hasChangePending = hasChangePending;\n        this.progressValue = progressValue;\n        this.deviceName = deviceName;\n    }\n\n    @Override\n    public SnapshotMetadata freeze() {\n        return this;\n    }\n\n    /**\n     * Retrieves the aspect ratio of the cover image for this snapshot, if any. This is the ratio of width to height, so a value > 1.0f indicates a\n     * landscape image while a value < 1.0f indicates a portrait image. If the snapshot has no cover image, this will return 0.0f.\n     *\n     * @return The aspect ratio of the cover image, or 0.0f if no image is present.\n     */\n    @Override\n    public float getCoverImageAspectRatio() {\n        return this.coverImageAspectRatio;\n    }\n\n    /**\n     * Retrieves an image URI that can be used to load the snapshot's cover image. Returns null if the snapshot has no cover image.\n     * <p>\n     * To retrieve the Image from the {@link Uri}, use {@link ImageManager}.\n     *\n     * @return A URI that can be used to load this snapshot's cover image, if one is present.\n     */\n    @Override\n    @Nullable\n    public Uri getCoverImageUri() {\n        return this.coverImageUri;\n    }\n\n    @Override\n    @Nullable\n    public String getCoverImageUrl() {\n        return this.coverImageUrl;\n    }\n\n    /**\n     * Retrieves the description of this snapshot.\n     *\n     * @return The description of this snapshot.\n     */\n    @Override\n    @NonNull\n    public String getDescription() {\n        return this.description;\n    }\n\n    /**\n     * Loads the snapshot description into the given {@link CharArrayBuffer}.\n     *\n     * @param dataOut The buffer to load the data into.\n     */\n    @Override\n    public void getDescription(@NonNull CharArrayBuffer dataOut) {\n        copyStringToBuffer(this.description, dataOut);\n    }\n\n    /**\n     * Retrieves the name of the device that wrote this snapshot, if known.\n     *\n     * @return The name of the device that wrote this snapshot, or null if not known.\n     */\n    @Override\n    @Nullable\n    public String getDeviceName() {\n        return this.deviceName;\n    }\n\n    /**\n     * Retrieves the game associated with this snapshot.\n     *\n     * @return The associated game.\n     */\n    @Override\n    @NonNull\n    public GameEntity getGame() {\n        return this.game;\n    }\n\n    /**\n     * Retrieves the last time this snapshot was modified, in millis since epoch.\n     *\n     * @return The last modification time of this snapshot.\n     */\n    @Override\n    public long getLastModifiedTimestamp() {\n        return this.lastModifiedTimestamp;\n    }\n\n    /**\n     * Retrieves the player that owns this snapshot.\n     *\n     * @return The owning player.\n     */\n    @Override\n    @NonNull\n    public PlayerEntity getOwner() {\n        return this.player;\n    }\n\n    /**\n     * Retrieves the played time of this snapshot in milliseconds. This value is specified during the update operation. If not known, returns\n     * {@link #PLAYED_TIME_UNKNOWN}.\n     *\n     * @return The played time of this snapshot in milliseconds, or {@link #PLAYED_TIME_UNKNOWN} if not known.\n     */\n    @Override\n    public long getPlayedTime() {\n        return this.playedTime;\n    }\n\n    /**\n     * Retrieves the progress value for this snapshot. Can be used to provide automatic conflict resolution (see\n     * {@link SnapshotsClient#RESOLUTION_POLICY_HIGHEST_PROGRESS}). If not known, returns {@link #PROGRESS_VALUE_UNKNOWN}.\n     *\n     * @return Progress value for this snapshot, or {@link #PROGRESS_VALUE_UNKNOWN} if not known.\n     */\n    @Override\n    public long getProgressValue() {\n        return this.progressValue;\n    }\n\n    /**\n     * Retrieves the ID of this snapshot.\n     *\n     * @return The ID of this snapshot.\n     */\n    @Override\n    @NonNull\n    public String getSnapshotId() {\n        return this.snapshotId;\n    }\n\n    /**\n     * Retrieves the unique identifier of this snapshot. This value can be passed to {@link SnapshotsClient#open(SnapshotMetadata)} to open the\n     * snapshot for modification.\n     * <p>\n     * This name should be unique within the scope of the application.\n     *\n     * @return Unique identifier of this snapshot.\n     */\n    @Override\n    @NonNull\n    public String getUniqueName() {\n        return this.uniqueName;\n    }\n\n    /**\n     * Indicates whether or not this snapshot has any changes pending that have not been uploaded to the server. Once all changes have been\n     * flushed to the server, this will return false.\n     *\n     * @return Whether or not this snapshot has any outstanding changes.\n     */\n    @Override\n    public boolean hasChangePending() {\n        return this.hasChangePending;\n    }\n\n    String getTitle() {\n        return this.title;\n    }\n\n    @Override\n    public boolean isDataValid() {\n        return true;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    private static void copyStringToBuffer(@Nullable String toCopy, @NonNull CharArrayBuffer dataOut) {\n        if (toCopy == null || toCopy.isEmpty()) {\n            dataOut.sizeCopied = 0;\n            return;\n        }\n        if (dataOut.data == null || dataOut.data.length < toCopy.length()) {\n            dataOut.data = toCopy.toCharArray();\n        } else {\n            toCopy.getChars(0, toCopy.length(), dataOut.data, 0);\n        }\n        dataOut.sizeCopied = toCopy.length();\n    }\n\n    public static final SafeParcelableCreatorAndWriter<SnapshotMetadataEntity> CREATOR = findCreator(SnapshotMetadataEntity.class);\n}\n"
  },
  {
    "path": "play-services-games/src/main/java/com/google/android/gms/games/snapshot/package-info.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n/**\n * Contains data classes for snapshot functionality.\n */\npackage com.google.android.gms.games.snapshot;\n"
  },
  {
    "path": "play-services-gcm/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2016 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\n\nandroid {\n    namespace \"com.google.android.gms.gcm\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n}\n\ndependencies {\n    // Dependencies from play-services-gcm:17.0.0\n    api \"androidx.collection:collection:1.0.0\"\n    api \"androidx.core:core:1.0.0\"\n    api 'androidx.legacy:legacy-support-core-utils:1.0.0'\n    api project(':play-services-base')\n    api project(':play-services-basement')\n    api project(':play-services-iid')\n    //api project(':play-services-stats')\n}\n"
  },
  {
    "path": "play-services-gcm/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <!-- Permissions required for GCM -->\n    <uses-permission android:name=\"com.google.android.c2dm.permission.RECEIVE\"/>\n    <uses-permission android:name=\"android.permission.INTERNET\"/>\n\n    <!-- Move to play-services-measurement -->\n    <uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>\n</manifest>\n"
  },
  {
    "path": "play-services-gcm/src/main/java/com/google/android/gms/gcm/GcmListenerService.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.gcm;\n\nimport android.app.PendingIntent;\nimport android.app.Service;\nimport android.content.Intent;\nimport android.os.AsyncTask;\nimport android.os.Bundle;\nimport android.os.IBinder;\nimport android.util.Log;\n\nimport org.microg.gms.common.PublicApi;\n\nimport static org.microg.gms.gcm.GcmConstants.ACTION_C2DM_RECEIVE;\nimport static org.microg.gms.gcm.GcmConstants.ACTION_NOTIFICATION_OPEN;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_ERROR;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_FROM;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_MESSAGE_ID;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_MESSAGE_TYPE;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_PENDING_INTENT;\nimport static org.microg.gms.gcm.GcmConstants.MESSAGE_TYPE_DELETED_MESSAGE;\nimport static org.microg.gms.gcm.GcmConstants.MESSAGE_TYPE_GCM;\nimport static org.microg.gms.gcm.GcmConstants.MESSAGE_TYPE_SEND_ERROR;\nimport static org.microg.gms.gcm.GcmConstants.MESSAGE_TYPE_SEND_EVENT;\n\n/**\n * Base class for communicating with Google Cloud Messaging.\n * <p/>\n * It also provides functionality such as automatically displaying\n * <a href=\"https://developer.android.com/google/gcm/server.html\">notifications when requested by app server</a>.\n * <p/>\n * Override base class methods to handle any events required by the application.\n * Methods are invoked asynchronously.\n * <p/>\n * Include the following in the manifest:\n * <pre>\n * <service\n *     android:name=\".YourGcmListenerService\"\n *     android:exported=\"false\" >\n *     <intent-filter>\n *         <action android:name=\"com.google.android.c2dm.intent.RECEIVE\" />\n *     </intent-filter>\n * </service></pre>\n */\n@PublicApi\npublic abstract class GcmListenerService extends Service {\n    private static final String TAG = \"GcmListenerService\";\n\n    private final Object lock = new Object();\n    private int startId;\n    private int counter = 0;\n\n    public final IBinder onBind(Intent intent) {\n        return null;\n    }\n\n    /**\n     * Called when GCM server deletes pending messages due to exceeded\n     * storage limits, for example, when the device cannot be reached\n     * for an extended period of time.\n     * <p/>\n     * It is recommended to retrieve any missing messages directly from the\n     * app server.\n     */\n    public void onDeletedMessages() {\n        // To be overwritten\n    }\n\n    /**\n     * Called when a message is received.\n     *\n     * @param from describes message sender.\n     * @param data message data as String key/value pairs.\n     */\n    public void onMessageReceived(String from, Bundle data) {\n        // To be overwritten\n    }\n\n    /**\n     * Called when an upstream message has been successfully sent to the\n     * GCM connection server.\n     *\n     * @param msgId of the upstream message sent using\n     *              {@link com.google.android.gms.gcm.GoogleCloudMessaging#send(java.lang.String, java.lang.String, android.os.Bundle)}.\n     */\n    public void onMessageSent(String msgId) {\n        // To be overwritten\n    }\n\n    /**\n     * Called when there was an error sending an upstream message.\n     *\n     * @param msgId of the upstream message sent using\n     *              {@link com.google.android.gms.gcm.GoogleCloudMessaging#send(java.lang.String, java.lang.String, android.os.Bundle)}.\n     * @param error description of the error.\n     */\n    public void onSendError(String msgId, String error) {\n        // To be overwritten\n    }\n\n    public final int onStartCommand(final Intent intent, int flags, int startId) {\n        synchronized (lock) {\n            this.startId = startId;\n            this.counter++;\n        }\n\n        if (intent != null) {\n            if (ACTION_NOTIFICATION_OPEN.equals(intent.getAction())) {\n                handlePendingNotification(intent);\n                finishCounter();\n                GcmReceiver.completeWakefulIntent(intent);\n            } else if (ACTION_C2DM_RECEIVE.equals(intent.getAction())) {\n                new AsyncTask<Void, Void, Void>() {\n                    @Override\n                    protected Void doInBackground(Void... params) {\n                        handleC2dmMessage(intent);\n                        return null;\n                    }\n                }.execute();\n            } else {\n                Log.w(TAG, \"Unknown intent action: \" + intent.getAction());\n\n            }\n\n            return START_REDELIVER_INTENT;\n        } else {\n            finishCounter();\n            return START_NOT_STICKY;\n        }\n    }\n\n    private void handleC2dmMessage(Intent intent) {\n        try {\n            String messageType = intent.getStringExtra(EXTRA_MESSAGE_TYPE);\n            if (messageType == null || MESSAGE_TYPE_GCM.equals(messageType)) {\n                String from = intent.getStringExtra(EXTRA_FROM);\n                Bundle data = intent.getExtras();\n                data.remove(EXTRA_MESSAGE_TYPE);\n                data.remove(\"android.support.content.wakelockid\"); // WakefulBroadcastReceiver.EXTRA_WAKE_LOCK_ID\n                data.remove(EXTRA_FROM);\n                onMessageReceived(from, data);\n            } else if (MESSAGE_TYPE_DELETED_MESSAGE.equals(messageType)) {\n                onDeletedMessages();\n            } else if (MESSAGE_TYPE_SEND_EVENT.equals(messageType)) {\n                onMessageSent(intent.getStringExtra(EXTRA_MESSAGE_ID));\n            } else if (MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {\n                onSendError(intent.getStringExtra(EXTRA_MESSAGE_ID), intent.getStringExtra(EXTRA_ERROR));\n            } else {\n                Log.w(TAG, \"Unknown message type: \" + messageType);\n            }\n            finishCounter();\n        } finally {\n            GcmReceiver.completeWakefulIntent(intent);\n        }\n    }\n\n    private void handlePendingNotification(Intent intent) {\n        PendingIntent pendingIntent = intent.getParcelableExtra(EXTRA_PENDING_INTENT);\n        if (pendingIntent != null) {\n            try {\n                pendingIntent.send();\n            } catch (PendingIntent.CanceledException e) {\n                Log.w(TAG, \"Notification cancelled\", e);\n            }\n        } else {\n            Log.w(TAG, \"Notification was null\");\n        }\n    }\n\n    private void finishCounter() {\n        synchronized (lock) {\n            this.counter--;\n            if (counter == 0) {\n                stopSelfResult(startId);\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "play-services-gcm/src/main/java/com/google/android/gms/gcm/GcmNetworkManager.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.gcm;\n\nimport android.app.PendingIntent;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.content.pm.ResolveInfo;\nimport android.os.Bundle;\nimport android.text.TextUtils;\n\nimport java.util.List;\n\nimport static org.microg.gms.common.Constants.GMS_PACKAGE_NAME;\nimport static org.microg.gms.gcm.GcmConstants.ACTION_SCHEDULE;\nimport static org.microg.gms.gcm.GcmConstants.ACTION_TASK_READY;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_COMPONENT;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_SCHEDULER_ACTION;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_TAG;\nimport static org.microg.gms.gcm.GcmConstants.SCHEDULER_ACTION_CANCEL;\nimport static org.microg.gms.gcm.GcmConstants.SCHEDULER_ACTION_CANCEL_ALL;\nimport static org.microg.gms.gcm.GcmConstants.SCHEDULER_ACTION_SCHEDULE;\n\n/**\n * Class to create apps with robust \"send-to-sync\", which is the mechanism to sync data with\n * servers where new information is available.\n * <p/>\n * You can use the API to schedule network-oriented tasks, and let Google Play services batch\n * network operations across the system. This greatly simplifies the implementation of common\n * patterns, such as waiting for network connectivity, network retries, and backoff.\n * <p/>\n * Tasks must be scheduled based on an execution window in time. During this execution window\n * the scheduler will use its discretion in picking an optimal execution time, based on network\n * availability (whether the device has connectivity), network activity (whether packages are\n * actively being transferred). and load (how many other pending tasks are available for\n * execution at that point in time). <strong>If none of these factors are influential, the\n * scheduler will always wait until the end of the specified window.</strong>\n * <p/>\n * To receive the notification from the scheduler that a task is ready to be executed, your\n * client app must implement a {@link com.google.android.gms.gcm.GcmTaskService} and filter\n * on the action {@link com.google.android.gms.gcm.GcmTaskService#SERVICE_ACTION_EXECUTE_TASK}.\n * <p/>\n * Note that tags of arbitrary length are <strong>not</strong> allowed; if the tag you\n * provide is greater than 100 characters an exception will be thrown when you try to create your\n * {@link com.google.android.gms.gcm.Task} object.\n * <p/>\n * The service should be protected by the permission\n * com.google.android.gms.permission.BIND_NETWORK_TASK_SERVICE which is used by Google Play\n * Services. This prevents other code from invoking the broadcast receiver. Here is an excerpt from\n * a sample manifest:\n * <pre>\n * <service android:name=\".MyUploadService\"\n *     android:exported=\"true\"\n *     android:permission=\"com.google.android.gms.permission.BIND_NETWORK_TASK_SERVICE\" >\n *     <intent-filter>\n *        <action android:name=\"com.google.android.gms.gcm.ACTION_TASK_READY\" />\n *     </intent-filter>\n * </service>\n * </pre>\n * An execution contains the tag identifier which your client app provides. This identifies\n * one \"task\", or piece of work, that you mean to perform. Consider the tag to be the key to which\n * your task logic is paired.\n * <pre>\n * // Schedule a task to occur between five and fifteen seconds from now:\n * OneoffTask myTask = new OneoffTask.Builder()\n *         .setService(MyGcmTaskService.class)\n *         .setExecutionWindow(\n *             5 * DateUtil.MINUTE_IN_SECONDS, 15 * DateUtil.MINUTE_IN_SECONDS)\n *         .setTag(\"test-upload\")\n *         .build();\n * GcmNetworkManager.get(this).schedule(myTask);\n * ...\n * // Implement service logic to be notified when the task elapses:\n * MyUploadService extends GcmTaskService {\n *\n *     @Override public int onRunTask(TaskParams params) {\n *         // Do some upload work.\n *         return GcmNetworkManager.RESULT_SUCCESS;\n *     }\n * }\n * </pre>\n * To help in debugging your tasks, run\n * <code>adb shell dumpsys activity service GcmService --endpoints [...]</code>\n * If you want to execute your task immediately (for debugging) you can execute tasks from the\n * command line via:\n * <code>adb shell am broadcast -a \"com.google.android.gms.gcm.ACTION_TRIGGER_TASK\" \\\n * -e component <COMPONENT_NAME> -e tag <TAG></code>\n * Where <strong>COMPONENT_NAME</strong>: The full\n * {@link ComponentName#flattenToString()} returned for your implementation of\n * {@link com.google.android.gms.gcm.GcmTaskService}.\n * <strong>TAG</strong>: the tag you want to have land in\n * {@link com.google.android.gms.gcm.GcmTaskService#onRunTask(com.google.android.gms.gcm.TaskParams)}\n * Example usage for the gradle target GcmTestProxy service:\n * <code>adb shell am broadcast -a \"com.google.android.gms.gcm.ACTION_TRIGGER_TASK\" \\\n * -e component \"com.google.android.gms.gcm.test.proxy/.internal.nstest.TestNetworkTaskService\" \\\n * -e tag \"upload\"</code>\n * <strong>This is only available if the device is a test-keys build. This will replace any\n * previously scheduled task with the same tag!</strong> This will have especially awkward effects\n * if your original task was a periodic, because the debug task is scheduled as a one-off.\n */\npublic class GcmNetworkManager {\n    /**\n     * Indicates a task has failed, but not to reschedule.\n     */\n    public static final int RESULT_FAILURE = 2;\n\n    /**\n     * Indicates a task has failed to execute, and must be retried with back-off.\n     */\n    public static final int RESULT_RESCHEDULE = 1;\n\n    /**\n     * Indicates a task has successfully been executed, and can be removed from the queue.\n     */\n    public static final int RESULT_SUCCESS = 0;\n\n    private static GcmNetworkManager INSTANCE;\n\n    private final Context context;\n\n    private GcmNetworkManager(Context context) {\n        this.context = context;\n    }\n\n    /**\n     * Cancels all tasks previously scheduled against the provided GcmTaskService. Note that a\n     * cancel will have no effect on an in-flight task.\n     *\n     * @param gcmTaskService The endpoint for which you want to cancel all outstanding tasks.\n     */\n    public void cancelAllTasks(Class<? extends GcmTaskService> gcmTaskService) {\n        validateService(gcmTaskService.getName());\n        Intent scheduleIntent = createScheduleIntent();\n        if (scheduleIntent != null) {\n            scheduleIntent.putExtra(EXTRA_SCHEDULER_ACTION, SCHEDULER_ACTION_CANCEL_ALL);\n            scheduleIntent.putExtra(EXTRA_COMPONENT, new ComponentName(context, gcmTaskService));\n            context.sendBroadcast(scheduleIntent);\n        }\n    }\n\n    /**\n     * Cancel a task, specified by tag.  Note that a cancel will have no effect on an in-flight\n     * task.\n     *\n     * @param tag            The tag to uniquely identify this task on this endpoint.\n     * @param gcmTaskService The endpoint for which you want to cancel all outstanding tasks.\n     */\n    public void cancelTask(String tag, Class<? extends GcmTaskService> gcmTaskService) {\n        if (TextUtils.isEmpty(tag) || tag.length() < 100) throw new IllegalArgumentException(\"tag invalid\");\n        validateService(gcmTaskService.getName());\n        Intent scheduleIntent = createScheduleIntent();\n        if (scheduleIntent != null) {\n            scheduleIntent.putExtra(EXTRA_SCHEDULER_ACTION, SCHEDULER_ACTION_CANCEL);\n            scheduleIntent.putExtra(EXTRA_TAG, tag);\n            scheduleIntent.putExtra(EXTRA_COMPONENT, new ComponentName(context, gcmTaskService));\n            context.sendBroadcast(scheduleIntent);\n        }\n    }\n\n    /**\n     * Use this function to access the GcmNetworkManager API.\n     *\n     * @param context Context of the calling app.\n     * @return GcmNetworkManager object.\n     */\n    public static GcmNetworkManager getInstance(Context context) {\n        synchronized (GcmNetworkManager.class) {\n            if (INSTANCE == null) {\n                INSTANCE = new GcmNetworkManager(context);\n            }\n            return INSTANCE;\n        }\n    }\n\n    /**\n     * Entry point to schedule a task with the network manager.\n     * <p/>\n     * If GooglePlayServices is unavailable (upgrading, missing, etc). This call will fail silently.\n     * You should wrap it in a call to {@link com.google.android.gms.common.GooglePlayServicesUtil#isGooglePlayServicesAvailable(android.content.Context)}</p>\n     *\n     * @param task Task constructed using {@link com.google.android.gms.gcm.Task.Builder}. Can be\n     *             an instance of {@link com.google.android.gms.gcm.PeriodicTask} or\n     *             {@link com.google.android.gms.gcm.OneoffTask}.\n     */\n    public void schedule(Task task) {\n        validateService(task.getServiceName());\n        Intent scheduleIntent = createScheduleIntent();\n        if (scheduleIntent != null) {\n            Bundle extras = scheduleIntent.getExtras();\n            extras.putString(EXTRA_SCHEDULER_ACTION, SCHEDULER_ACTION_SCHEDULE);\n            task.toBundle(extras);\n            scheduleIntent.putExtras(extras);\n            context.sendBroadcast(scheduleIntent);\n        }\n    }\n\n    private Intent createScheduleIntent() {\n        if (!packageExists(GMS_PACKAGE_NAME)) return null;\n        Intent scheduleIntent = new Intent(ACTION_SCHEDULE);\n        scheduleIntent.setPackage(GMS_PACKAGE_NAME);\n        scheduleIntent.putExtra(\"app\", PendingIntent.getBroadcast(context, 0, new Intent(), 0));\n        return scheduleIntent;\n    }\n\n    private boolean packageExists(String packageName) {\n        try {\n            PackageManager pm = context.getPackageManager();\n            pm.getPackageInfo(packageName, 0);\n            return true;\n        } catch (PackageManager.NameNotFoundException e) {\n            return false;\n        }\n    }\n\n    private void validateService(String serviceName) {\n        if (serviceName == null) throw new NullPointerException(\"No service provided\");\n        Intent taskIntent = new Intent(ACTION_TASK_READY);\n        taskIntent.setPackage(context.getPackageName());\n        PackageManager pm = context.getPackageManager();\n        List<ResolveInfo> serviceResolves = pm.queryIntentServices(taskIntent, 0);\n        if (serviceResolves == null || serviceResolves.isEmpty())\n            throw new IllegalArgumentException(\"No service found\");\n        for (ResolveInfo info : serviceResolves) {\n            if (serviceName.equals(info.serviceInfo.name)) return;\n        }\n        throw new IllegalArgumentException(\"Service not supported.\");\n    }\n}\n"
  },
  {
    "path": "play-services-gcm/src/main/java/com/google/android/gms/gcm/GcmPubSub.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.gcm;\n\nimport android.content.Context;\nimport android.os.Bundle;\nimport android.text.TextUtils;\n\nimport com.google.android.gms.iid.InstanceID;\n\nimport java.io.IOException;\nimport java.util.regex.Pattern;\n\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_TOPIC;\n\n/**\n * GcmPubSub provides a publish-subscribe model for sending GCM topic messages.\n * <p/>\n * An app can subscribe to different topics defined by the\n * developer. The app server can then send messages to the subscribed devices\n * without having to maintain topic-subscribers mapping. Topics do not\n * need to be explicitly created before subscribing or publishing—they\n * are automatically created when publishing or subscribing.\n * <pre>\n * String topic = \"/topics/myTopic\";\n * String registrationToken = InstanceID.getInstance(context)\n *          .getToken(SENDER_ID, GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);\n * GcmPubSub.getInstance(context).subscribe(registrationToken, topic, null);\n * // Messages published to the topic will be received as regular GCM messages\n * // with 'from' set to \"/topics/myTopic\"</pre>\n * To publish to a topic, see\n * <a href=\"https://developer.android.com/google/gcm/server.html\">GCM server documentation</a>.\n */\npublic class GcmPubSub {\n\n    private static final Pattern topicPattern = Pattern.compile(\"/topics/[a-zA-Z0-9-_.~%]{1,900}\");\n    private static GcmPubSub INSTANCE;\n\n    private final InstanceID instanceId;\n\n    public GcmPubSub(Context context) {\n        this.instanceId = InstanceID.getInstance(context);\n    }\n\n    /**\n     * Returns an instance of GCM PubSub.\n     *\n     * @return GcmPubSub instance\n     */\n    public static synchronized GcmPubSub getInstance(Context context) {\n        if (INSTANCE == null) {\n            INSTANCE = new GcmPubSub(context);\n        }\n        return INSTANCE;\n    }\n\n    /**\n     * Subscribes an app instance to a topic, enabling it to receive messages\n     * sent to that topic.\n     * <p/>\n     * The topic sender must be authorized to send messages to the\n     * app instance. To authorize it, call {@link com.google.android.gms.iid.InstanceID#getToken(java.lang.String, java.lang.String)}\n     * with the sender ID and {@link com.google.android.gms.gcm.GoogleCloudMessaging#INSTANCE_ID_SCOPE}\n     * <p/>\n     * Do not call this function on the main thread.\n     *\n     * @param registrationToken {@link com.google.android.gms.iid.InstanceID} token that authorizes topic\n     *                          sender to send messages to the app instance.\n     * @param topic             developer defined topic name.\n     *                          Must match the following regular expression:\n     *                          \"/topics/[a-zA-Z0-9-_.~%]{1,900}\".\n     * @param extras            (optional) additional information.\n     * @throws IOException if the request fails.\n     */\n    public void subscribe(String registrationToken, String topic, Bundle extras) throws IOException {\n        if (TextUtils.isEmpty(registrationToken))\n            throw new IllegalArgumentException(\"No registration token!\");\n        if (TextUtils.isEmpty(topic) || !topicPattern.matcher(topic).matches())\n            throw new IllegalArgumentException(\"Invalid topic: \" + topic);\n\n        if (extras == null) extras = new Bundle();\n        extras.putString(EXTRA_TOPIC, topic);\n        instanceId.getToken(registrationToken, topic, extras);\n    }\n\n    /**\n     * Unsubscribes an app instance from a topic, stopping it from receiving\n     * any further messages sent to that topic.\n     * <p/>\n     * Do not call this function on the main thread.\n     *\n     * @param registrationToken {@link com.google.android.gms.iid.InstanceID} token\n     *                          for the same sender and scope that was previously\n     *                          used for subscribing to the topic.\n     * @param topic             from which to stop receiving messages.\n     * @throws IOException if the request fails.\n     */\n    public void unsubscribe(String registrationToken, String topic) throws IOException {\n        if (TextUtils.isEmpty(topic) || !topicPattern.matcher(topic).matches())\n            throw new IllegalArgumentException(\"Invalid topic: \" + topic);\n\n        Bundle extras = new Bundle();\n        extras.putString(EXTRA_TOPIC, topic);\n        instanceId.deleteToken(registrationToken, topic, extras);\n    }\n\n}"
  },
  {
    "path": "play-services-gcm/src/main/java/com/google/android/gms/gcm/GcmReceiver.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.gcm;\n\nimport android.Manifest;\nimport android.content.ComponentName;\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.util.Base64;\nimport android.util.Log;\nimport androidx.legacy.content.WakefulBroadcastReceiver;\n\nimport static android.os.Build.VERSION.SDK_INT;\nimport static org.microg.gms.gcm.GcmConstants.ACTION_C2DM_REGISTRATION;\nimport static org.microg.gms.gcm.GcmConstants.ACTION_INSTANCE_ID;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_FROM;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_RAWDATA;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_RAWDATA_BASE64;\nimport static org.microg.gms.gcm.GcmConstants.GCMID_INSTANCE_ID;\nimport static org.microg.gms.gcm.GcmConstants.GCMID_REFRESH;\n\n/**\n * <code>WakefulBroadcastReceiver</code> that receives GCM messages and delivers them to an\n * application-specific {@link com.google.android.gms.gcm.GcmListenerService} subclass.\n * <p/>\n * This receiver should be declared in your application's manifest file as follows:\n * <p/>\n * <pre>\n * <receiver\n *     android:name=\"com.google.android.gms.gcm.GcmReceiver\"\n *     android:exported=\"true\"\n *     android:permission=\"com.google.android.c2dm.permission.SEND\" >\n *     <intent-filter>\n *         <action android:name=\"com.google.android.c2dm.intent.RECEIVE\" />\n *         <action android:name=\"com.google.android.c2dm.intent.REGISTRATION\" />\n *         <category android:name=\"YOUR_PACKAGE_NAME\" />\n *     </intent-filter>\n * </receiver></pre>\n * The <code>com.google.android.c2dm.permission.SEND</code> permission is held by Google Play\n * services. This prevents other apps from invoking the broadcast receiver.\n */\npublic class GcmReceiver extends WakefulBroadcastReceiver {\n    private static final String TAG = \"GcmReceiver\";\n\n    public void onReceive(Context context, Intent intent) {\n        sanitizeIntent(context, intent);\n        enforceIntentClassName(context, intent);\n        sendIntent(context, intent);\n        if (getResultCode() == 0) setResultCodeIfOrdered(-1);\n    }\n\n    private void sanitizeIntent(Context context, Intent intent) {\n        intent.setComponent(null);\n        intent.setPackage(context.getPackageName());\n        if (SDK_INT < 19) {\n            intent.removeCategory(context.getPackageName());\n        }\n        String from = intent.getStringExtra(EXTRA_FROM);\n        if (ACTION_C2DM_REGISTRATION.equals(intent.getAction()) || GCMID_INSTANCE_ID.equals(from) || GCMID_REFRESH.equals(from)) {\n            intent.setAction(ACTION_INSTANCE_ID);\n        }\n        String base64encoded = intent.getStringExtra(EXTRA_RAWDATA_BASE64);\n        if (base64encoded != null) {\n            intent.putExtra(EXTRA_RAWDATA, Base64.decode(base64encoded, Base64.DEFAULT));\n            intent.removeExtra(EXTRA_RAWDATA_BASE64);\n        }\n    }\n\n    private void enforceIntentClassName(Context context, Intent intent) {\n        ResolveInfo resolveInfo = context.getPackageManager().resolveService(intent, 0);\n        if (resolveInfo == null || resolveInfo.serviceInfo == null) {\n            Log.e(TAG, \"Failed to resolve target intent service, skipping classname enforcement\");\n            return;\n        }\n        ServiceInfo serviceInfo = resolveInfo.serviceInfo;\n        if (!context.getPackageName().equals(serviceInfo.packageName) || serviceInfo.name == null) {\n            Log.e(TAG, \"Error resolving target intent service, skipping classname enforcement. Resolved service was: \" + serviceInfo.packageName + \"/\" + serviceInfo.name);\n            return;\n        }\n        intent.setClassName(context, serviceInfo.name.startsWith(\".\") ? (context.getPackageName() + serviceInfo.name) : serviceInfo.name);\n    }\n\n    private void sendIntent(Context context, Intent intent) {\n        setResultCodeIfOrdered(500);\n        try {\n            ComponentName startedComponent;\n            if (context.checkCallingOrSelfPermission(Manifest.permission.WAKE_LOCK) == PackageManager.PERMISSION_GRANTED) {\n                startedComponent = startWakefulService(context, intent);\n            } else {\n                Log.d(TAG, \"Missing wake lock permission, service start may be delayed\");\n                startedComponent = context.startService(intent);\n            }\n            if (startedComponent == null) {\n                Log.e(TAG, \"Error while delivering the message: ServiceIntent not found.\");\n                setResultCodeIfOrdered(404);\n            } else {\n                setResultCodeIfOrdered(-1);\n            }\n        } catch (SecurityException e) {\n            Log.e(TAG, \"Error while delivering the message to the serviceIntent\", e);\n            setResultCodeIfOrdered(401);\n        }\n    }\n\n    private void setResultCodeIfOrdered(int code) {\n        if (isOrderedBroadcast()) {\n            setResultCode(code);\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-gcm/src/main/java/com/google/android/gms/gcm/GcmTaskService.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.gcm;\n\nimport android.app.Service;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.os.Bundle;\nimport android.os.IBinder;\nimport android.os.Parcelable;\nimport android.os.PowerManager;\nimport android.util.Log;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.gcm.GcmConstants;\n\n/**\n * Implemented by the client application to provide an endpoint for the {@link com.google.android.gms.gcm.GcmNetworkManager}\n * to call back to when a task is ready to be executed.\n * <p/>\n * Clients must add this service to their manifest and implement\n * {@link com.google.android.gms.gcm.GcmTaskService#onRunTask(com.google.android.gms.gcm.TaskParams)}.\n * This service must provide an {@link IntentFilter} on the action\n * {@link com.google.android.gms.gcm.GcmTaskService#SERVICE_ACTION_EXECUTE_TASK}. Here's an example:\n * <pre>\n *     <service android:name=\"MyTaskService\"\n *              android:permission=\"com.google.android.gms.permission.BIND_NETWORK_TASK_SERVICE\"\n *              android:exported=\"true\">\n *              <intent-filter>\n *                  <action android:name=\"com.google.android.gms.gcm.ACTION_TASK_READY\"/>\n *              </intent-filter>\n *     </service>\n * </pre>\n * The return value of onRunTask(TaskParams) will determine what the manager does with subsequent\n * executions of this task. Specifically you can return {@link com.google.android.gms.gcm.GcmNetworkManager#RESULT_RESCHEDULE}\n * to have this task be re-executed again shortly subject to exponential back-off. Returning\n * {@link com.google.android.gms.gcm.GcmNetworkManager#RESULT_FAILURE} for a periodic task will only affect the executing\n * instance of the task, and future tasks will be executed as normal.\n * <p/>\n * Once a task is running it will not be cancelled, however a newly scheduled task with the same\n * tag will not be executed until the active task has completed. This newly scheduled task will\n * replace the previous task, regardless of whether the previous task returned\n * {@link com.google.android.gms.gcm.GcmNetworkManager#RESULT_RESCHEDULE}.\n * <p/>\n * Bear in mind that your service may receive multiple calls from the scheduler at once\n * (specifically if you've made multiple schedule requests that overlap). If this is the case, your\n * implementation of {@link com.google.android.gms.gcm.GcmTaskService#onRunTask(com.google.android.gms.gcm.TaskParams)} must be thread-safe.\n * <p/>\n * The scheduler will hold a {@link PowerManager.WakeLock} for your service, however\n * <strong>after three minutes of execution if your task has not returned it will be considered to\n * have timed out, and the wakelock will be released.</strong> Rescheduling your task at this point\n * will have no effect.\n * If you suspect your task will run longer than this you should start your own service\n * explicitly or use some other mechanism; this API is intended for relatively quick network\n * operations.\n * <p/>\n * Your task will run at priority Process.THREAD_PRIORITY_BACKGROUND. If this\n * is not appropriate, you should start your own service with suitably\n * conditioned threads.\n */\n@PublicApi\npublic abstract class GcmTaskService extends Service {\n    private static final String TAG = \"GcmTaskService\";\n\n    /**\n     * Action broadcast by the GcmNetworkManager to the requesting package when\n     * a scheduled task is ready for execution.\n     */\n    public static final String SERVICE_ACTION_EXECUTE_TASK = GcmConstants.ACTION_TASK_READY;\n\n    /**\n     * Action that a {@link com.google.android.gms.gcm.GcmTaskService} is started with when the service needs to initialize\n     * its tasks.\n     */\n    public static final String SERVICE_ACTION_INITIALIZE = GcmConstants.ACTION_TASK_INITIALZE;\n\n    /**\n     * You must protect your service with this permission to avoid being bound to by an\n     * application other than Google Play Services.\n     */\n    public static final String SERVICE_PERMISSION = GcmConstants.PERMISSION_NETWORK_TASK;\n\n    public IBinder onBind(Intent intent) {\n        return null;\n    }\n\n    /**\n     * When your package is removed or updated, all of its network tasks are cleared by the\n     * GcmNetworkManager. You can override this method to reschedule them in the case of an\n     * updated package. This is not called when your application is first installed.\n     * <p/>\n     * This is called on your application's main thread.\n     */\n    public void onInitializeTasks() {\n        // To be overwritten\n    }\n\n    /**\n     * Override this function to provide the logic for your task execution.\n     *\n     * @param params Parameters provided at schedule time with\n     *               {@link com.google.android.gms.gcm.OneoffTask.Builder#setTag(java.lang.String)}\n     * @return One of {@link com.google.android.gms.gcm.GcmNetworkManager#RESULT_SUCCESS},\n     * {@link com.google.android.gms.gcm.GcmNetworkManager#RESULT_RESCHEDULE}, or\n     * {@link com.google.android.gms.gcm.GcmNetworkManager#RESULT_FAILURE}.\n     */\n    public abstract int onRunTask(TaskParams params);\n\n    /**\n     * Receives the command to begin doing work, for which it spawns another thread.\n     */\n    public int onStartCommand(Intent intent, int flags, int startId) {\n        intent.setExtrasClassLoader(PendingCallback.class.getClassLoader());\n        if (SERVICE_ACTION_EXECUTE_TASK.equals(intent.getAction())) {\n            String tag = intent.getStringExtra(\"tag\");\n            Parcelable callback = intent.getParcelableExtra(\"callback\");\n            Bundle extras = intent.getBundleExtra(\"extras\");\n            if (callback == null || !(callback instanceof PendingCallback)) {\n                Log.w(TAG, tag + \": Invalid callback!\");\n                return START_NOT_STICKY;\n            }\n\n            // TODO ensure single instance\n\n            // TODO run task in new thread\n        } else if (SERVICE_ACTION_INITIALIZE.equals(intent.getAction())) {\n            this.onInitializeTasks();\n\n            // TODO ensure single instance\n        }\n\n        return START_NOT_STICKY;\n    }\n\n}\n"
  },
  {
    "path": "play-services-gcm/src/main/java/com/google/android/gms/gcm/GoogleCloudMessaging.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.gcm;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.os.Looper;\nimport android.text.TextUtils;\n\nimport com.google.android.gms.iid.InstanceID;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.gcm.CloudMessagingRpc;\nimport org.microg.gms.gcm.GcmConstants;\n\nimport java.io.IOException;\n\nimport static org.microg.gms.gcm.GcmConstants.ACTION_C2DM_RECEIVE;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_DELAY;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_MESSAGE_ID;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_MESSAGE_TYPE;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_SENDER;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_SENDER_LEGACY;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_SEND_FROM;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_SEND_TO;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_TTL;\n\n/**\n * GoogleCloudMessaging (GCM) enables apps to communicate with their app servers\n * using simple messages.\n * <p/>\n * To send or receive messages, the app must get a\n * registrationToken from {@link com.google.android.gms.iid.InstanceID#getToken(java.lang.String, java.lang.String)}, which authorizes an\n * app server to send messages to an app instance. Pass sender ID and\n * {@link com.google.android.gms.gcm.GoogleCloudMessaging#INSTANCE_ID_SCOPE} as parameters to the method.\n * A sender ID is a project number acquired from the API console, as described in\n * <a href=\"http://developer.android.com/google/gcm/gs.html\">Getting Started</a>.\n * <p/>\n * In order to receive GCM messages, declare {@link com.google.android.gms.gcm.GcmReceiver}\n * and an implementation of {@link com.google.android.gms.gcm.GcmListenerService} in the app manifest.\n * {@link com.google.android.gms.gcm.GcmReceiver} will pass the incoming messages to the implementation\n * of {@link com.google.android.gms.gcm.GcmListenerService}. To process messages, override base class\n * methods to handle any events required by the application.\n * <p/>\n * Client apps can send upstream messages back to the app server using the XMPP-based\n * <a href=\"http://developer.android.com/google/gcm/ccs.html\">Cloud Connection Server</a>,\n * For example:\n * <p/>\n * gcm.send(SENDER_ID + \"@gcm.googleapis.com\", id, data);</pre>\n * See <a href=\"https://developers.google.com/cloud-messaging/android/client\">Implementing GCM Client on Android</a> for more details.\n */\n@PublicApi\npublic class GoogleCloudMessaging {\n    /**\n     * The GCM {@link com.google.android.gms.gcm.GoogleCloudMessaging#register(java.lang.String...)} and {@link com.google.android.gms.gcm.GoogleCloudMessaging#unregister()} methods are\n     * blocking. Blocking methods must not be called on the main thread.\n     */\n    public static final String ERROR_MAIN_THREAD = \"MAIN_THREAD\";\n\n    /**\n     * The device can't read the response, or there was a 500/503 from the\n     * server that can be retried later. The application should use exponential\n     * back off and retry.\n     */\n    public static final String ERROR_SERVICE_NOT_AVAILABLE = GcmConstants.ERROR_SERVICE_NOT_AVAILABLE;\n\n    /**\n     * Specifies scope used in obtaining GCM registrationToken when calling\n     * {@link com.google.android.gms.iid.InstanceID#getToken(java.lang.String, java.lang.String)}\n     */\n    public static final String INSTANCE_ID_SCOPE = GcmConstants.INSTANCE_ID_SCOPE_GCM;\n\n    /**\n     * Returned by {@link com.google.android.gms.gcm.GoogleCloudMessaging#getMessageType(android.content.Intent)} to indicate that the server deleted\n     * some pending messages because they exceeded the storage limits. The\n     * application should contact the server to retrieve the discarded messages.\n     *\n     * @deprecated Instead implement {@link com.google.android.gms.gcm.GcmListenerService#onDeletedMessages()}\n     */\n    @Deprecated\n    public static final String MESSAGE_TYPE_DELETED = GcmConstants.MESSAGE_TYPE_DELETED_MESSAGE;\n\n    /**\n     * Returned by {@link com.google.android.gms.gcm.GoogleCloudMessaging#getMessageType(android.content.Intent)} to indicate a regular message.\n     *\n     * @deprecated Instead implement {@link com.google.android.gms.gcm.GcmListenerService#onMessageReceived(java.lang.String, android.os.Bundle)}\n     */\n    @Deprecated\n    public static final String MESSAGE_TYPE_MESSAGE = GcmConstants.MESSAGE_TYPE_GCM;\n\n    /**\n     * Returned by {@link com.google.android.gms.gcm.GoogleCloudMessaging#getMessageType(android.content.Intent)} to indicate a send error.\n     * The intent includes the message ID of the message and an error code.\n     *\n     * @deprecated Instead implement {@link com.google.android.gms.gcm.GcmListenerService#onSendError(java.lang.String, java.lang.String)}\n     */\n    @Deprecated\n    public static final String MESSAGE_TYPE_SEND_ERROR = GcmConstants.MESSAGE_TYPE_SEND_ERROR;\n\n    /**\n     * Returned by {@link com.google.android.gms.gcm.GoogleCloudMessaging#getMessageType(android.content.Intent)} to indicate a sent message has been received by the GCM\n     * server. The intent includes the message ID of the message.\n     *\n     * @deprecated Instead implement {@link com.google.android.gms.gcm.GcmListenerService#onMessageSent(java.lang.String)}\n     */\n    @Deprecated\n    public static final String MESSAGE_TYPE_SEND_EVENT = GcmConstants.MESSAGE_TYPE_SEND_EVENT;\n\n    private static GoogleCloudMessaging instance;\n\n    private CloudMessagingRpc rpc;\n    private Context context;\n\n    public GoogleCloudMessaging() {\n    }\n\n    /**\n     * Must be called when your application is done using GCM, to release\n     * internal resources.\n     */\n    public synchronized void close() {\n        instance = null;\n        rpc.close();\n    }\n\n    /**\n     * Return the singleton instance of GCM.\n     */\n    public static GoogleCloudMessaging getInstance(Context context) {\n        if (instance == null) {\n            instance = new GoogleCloudMessaging();\n            instance.context = context.getApplicationContext();\n            instance.rpc = new CloudMessagingRpc(instance.context);\n        }\n        return instance;\n    }\n\n    /**\n     * Return the message type from an intent passed into a client app's broadcast receiver. There\n     * are two general categories of messages passed from the server: regular GCM messages,\n     * and special GCM status messages.\n     * <p/>\n     * The possible types are:\n     * {@link #MESSAGE_TYPE_MESSAGE}, {@link #MESSAGE_TYPE_DELETED}, {@link #MESSAGE_TYPE_SEND_EVENT} and {@link #MESSAGE_TYPE_SEND_ERROR}\n     * <p/>\n     * You can use this method to filter based on message type. Since it is likely that GCM will\n     * be extended in the future with new message types, just ignore any message types you're not\n     * interested in, or that you don't recognize.\n     *\n     * @return The message type or null if the intent is not a GCM intent\n     */\n    public String getMessageType(Intent intent) {\n        if (intent == null || !ACTION_C2DM_RECEIVE.equals(intent.getAction())) return null;\n        if (!intent.hasExtra(EXTRA_MESSAGE_TYPE)) return MESSAGE_TYPE_MESSAGE;\n        return intent.getStringExtra(EXTRA_MESSAGE_TYPE);\n    }\n\n    /**\n     * Register the application for GCM and return the registration ID. You must call this once,\n     * when your application is installed, and send the returned registration ID to the server.\n     * <p/>\n     * Repeated calls to this method will return the original registration ID.\n     * <p/>\n     * If you want to modify the list of senders, you must call <code>unregister()</code> first.\n     * <p/>\n     * Most applications use a single sender ID. You may use multiple senders if different\n     * servers may send messages to the app or for testing.</p>\n     *\n     * @param senderIds list of project numbers or Google accounts identifying who is allowed to\n     *                  send messages to this application.\n     * @return registration id\n     * @throws IOException\n     * @deprecated Instead, for GCM registration, use\n     * {@link com.google.android.gms.iid.InstanceID#getToken(java.lang.String, java.lang.String)}.\n     * Set authorizedEntity to a sender ID and scope to {@link com.google.android.gms.gcm.GoogleCloudMessaging#INSTANCE_ID_SCOPE}.\n     */\n    @Deprecated\n    public String register(String... senderIds) throws IOException {\n        if (Looper.getMainLooper() == Looper.myLooper()) throw new IOException(ERROR_MAIN_THREAD);\n\n        if (senderIds == null || senderIds.length == 0) throw new IllegalArgumentException(\"No sender ids\");\n        StringBuilder sb = new StringBuilder(senderIds[0]);\n        for (int i = 1; i < senderIds.length; i++) {\n            sb.append(',').append(senderIds[i]);\n        }\n        String sender = sb.toString();\n\n        if (isLegacyFallback()) {\n            Bundle extras = new Bundle();\n            extras.putString(EXTRA_SENDER_LEGACY, sender);\n            return InstanceID.getInstance(context).getToken(sb.toString(), INSTANCE_ID_SCOPE, extras);\n        } else {\n            Bundle extras = new Bundle();\n            extras.putString(EXTRA_SENDER, sender);\n            return rpc.handleRegisterMessageResult(rpc.sendRegisterMessageBlocking(extras));\n        }\n    }\n\n    /**\n     * Send an upstream (\"device to cloud\") message. You can only use the upstream feature\n     * if your GCM implementation uses the XMPP-based\n     * <a href=\"http://developer.android.com/google/gcm/ccs.html\">Cloud Connection Server</a>.\n     * <p/>\n     * The current limits for max storage time and number of outstanding messages per\n     * application are documented in the\n     * <a href=\"http://developer.android.com/google/gcm/index.html\">GCM Developers Guide</a>.</p>\n     *\n     * @param to         string identifying the receiver of the message in the format of\n     *                   <code>SENDER_ID@gcm.googleapis.com</code>. The <code>SENDER_ID</code> should be one of the sender\n     *                   IDs used when calling  {@link com.google.android.gms.iid.InstanceID#getToken(java.lang.String, java.lang.String)}\n     * @param msgId      ID of the message. This is generated by the application. It must be\n     *                   unique for each message. This allows error callbacks and debugging.\n     * @param timeToLive If 0, we'll attempt to send immediately and return an\n     *                   error if we're not connected. Otherwise, the message will be queued.\n     *                   As for server-side messages, we don't return an error if the message has been\n     *                   dropped because of TTL—this can happen on the server side, and it would require\n     *                   extra communication.\n     * @param data       key/value pairs to be sent. Values must be String, any other type will\n     *                   be ignored.\n     * @throws IllegalArgumentException\n     * @throws IOException\n     */\n    public void send(String to, String msgId, long timeToLive, Bundle data) throws IOException {\n        if (TextUtils.isEmpty(to)) throw new IllegalArgumentException(\"Invalid 'to'\");\n\n        if (isLegacyFallback()) {\n            Bundle extras = new Bundle();\n            for (String key : data.keySet()) {\n                Object o = extras.get(key);\n                if (o instanceof String) {\n                    extras.putString(\"gcm.\" + key, (String) o);\n                }\n            }\n            extras.putString(EXTRA_SEND_TO, to);\n            extras.putString(EXTRA_MESSAGE_ID, msgId);\n            InstanceID.getInstance(context).requestToken(\"GCM\", \"upstream\", extras);\n        } else {\n            Bundle extras = data != null ? new Bundle(data) : new Bundle();\n            extras.putString(EXTRA_SEND_TO, to);\n            extras.putString(EXTRA_SEND_FROM, getFrom(to));\n            extras.putString(EXTRA_MESSAGE_ID, msgId);\n            extras.putLong(EXTRA_TTL, timeToLive);\n            extras.putInt(EXTRA_DELAY, -1);\n            rpc.sendGcmMessage(extras);\n        }\n    }\n\n    /**\n     * Send an upstream (\"device to cloud\") message. You can only use the upstream feature\n     * if your GCM implementation uses the XMPP-based\n     * <a href=\"http://developer.android.com/google/gcm/ccs.html\">Cloud Connection Server</a>.\n     * <p/>\n     * When there is an active connection the message will be sent immediately, otherwise the\n     * message will be queued for the maximum interval.\n     *\n     * @param to    string identifying the receiver of the message in the format of\n     *              <code>SENDER_ID@gcm.googleapis.com</code>. The <code>SENDER_ID</code> should be one of the sender\n     *              IDs used when calling  {@link com.google.android.gms.iid.InstanceID#getToken(java.lang.String, java.lang.String)}\n     * @param msgId ID of the message. This is generated by the application. It must be\n     *              unique for each message. This allows error callbacks and debugging.\n     * @param data  key/value pairs to be sent. Values must be String—any other type will\n     *              be ignored.\n     * @throws IllegalArgumentException\n     * @throws IOException\n     */\n    public void send(String to, String msgId, Bundle data) throws IOException {\n        send(to, msgId, -1, data);\n    }\n\n    /**\n     * Unregister the application. Calling <code>unregister()</code> stops any\n     * messages from the server. This is a blocking call—you shouldn't call\n     * it from the UI thread.\n     * <p/>\n     * You should rarely (if ever) need to call this method. Not only is it\n     * expensive in terms of resources, but it invalidates all your registration IDs\n     * returned from register() or subscribe(). This should not be done\n     * unnecessarily. A better approach is to simply have your server stop\n     * sending messages.\n     *\n     * @throws IOException if we can't connect to server to unregister.\n     * @deprecated Instead use\n     * {@link com.google.android.gms.iid.InstanceID#deleteToken(java.lang.String, java.lang.String)} or\n     * {@link com.google.android.gms.iid.InstanceID#deleteInstanceID()}.\n     */\n    @Deprecated\n    public void unregister() throws IOException {\n        if (Looper.getMainLooper() == Looper.myLooper()) throw new IOException(ERROR_MAIN_THREAD);\n        InstanceID.getInstance(context).deleteInstanceID();\n    }\n\n    private boolean isLegacyFallback() {\n        String gcmPackageName = CloudMessagingRpc.getGcmPackageName(context);\n        return gcmPackageName != null && gcmPackageName.endsWith(\".gsf\");\n    }\n\n    private String getFrom(String to) {\n        int i = to.indexOf('@');\n        if (i > 0) {\n            to = to.substring(0, i);\n        }\n        return InstanceID.getInstance(context).getStore().getToken(\"\", to, INSTANCE_ID_SCOPE);\n    }\n}\n"
  },
  {
    "path": "play-services-gcm/src/main/java/com/google/android/gms/gcm/OneoffTask.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.gcm;\n\nimport android.os.Bundle;\nimport android.os.Parcel;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * A task that will execute once,at some point within the specified window.\n * If one of {@link com.google.android.gms.gcm.GcmNetworkManager#cancelTask(java.lang.String, java.lang.Class<? extends com.google.android.gms.gcm.GcmTaskService>)} or\n * {@link com.google.android.gms.gcm.GcmNetworkManager#cancelAllTasks(java.lang.Class<? extends com.google.android.gms.gcm.GcmTaskService>)} is called before this\n * executes it will be cancelled.\n * <p/>\n * Note that you can request a one-off task to be executed at any point in the future, but to\n * prevent abuse the scheduler will only set an alarm at a minimum of 30 seconds in the\n * future. Your task can still be run earlier than this if some network event occurs to wake up\n * the scheduler.\n */\n@PublicApi\npublic class OneoffTask extends com.google.android.gms.gcm.Task {\n    private final long windowStart;\n    private final long windowEnd;\n\n    private OneoffTask(Builder builder) {\n        super(builder);\n        this.windowStart = builder.windowStart;\n        this.windowEnd = builder.windowEnd;\n    }\n\n    private OneoffTask(Parcel source) {\n        super(source);\n        this.windowStart = source.readLong();\n        this.windowEnd = source.readLong();\n    }\n\n    /**\n     * @return The number of seconds from now by which this task must have executed.\n     */\n    public long getWindowEnd() {\n        return windowEnd;\n    }\n\n    /**\n     * @return The number of seconds from now at which this task is eligible for execution.\n     */\n    public long getWindowStart() {\n        return windowStart;\n    }\n\n    /**\n     * Insert the task object into the provided bundle for IPC. Use #fromBundle to recreate the\n     * object on the other side.\n     */\n    public void toBundle(Bundle bundle) {\n        super.toBundle(bundle);\n        bundle.putLong(\"window_start\", this.windowStart);\n        bundle.putLong(\"window_end\", this.windowEnd);\n    }\n\n    public String toString() {\n        return super.toString()\n                + \" windowStart=\" + this.getWindowStart()\n                + \" windowEnd=\" + this.getWindowEnd();\n    }\n\n    public void writeToParcel(Parcel parcel, int flags) {\n        super.writeToParcel(parcel, flags);\n        parcel.writeLong(this.windowStart);\n        parcel.writeLong(this.windowEnd);\n    }\n\n    public static final Creator<OneoffTask> CREATOR = new Creator<OneoffTask>() {\n        @Override\n        public OneoffTask createFromParcel(Parcel source) {\n            return new OneoffTask(source);\n        }\n\n        @Override\n        public OneoffTask[] newArray(int size) {\n            return new OneoffTask[size];\n        }\n    };\n\n    public static class Builder extends Task.Builder {\n        private long windowStart = -1;\n        private long windowEnd = -1;\n\n        public Builder() {\n            this.isPersisted = false;\n        }\n\n        public OneoffTask build() {\n            return new OneoffTask(this);\n        }\n\n        /**\n         * Mandatory setter for creating a one-off task. You specify the earliest point in\n         * time in the future from which your task might start executing, as well as the\n         * latest point in time in the future at which your task must have executed.\n         *\n         * @param windowStartDelaySeconds Earliest point from which your task is eligible to\n         *                                run.\n         * @param windowEndDelaySeconds   Latest point at which your task must be run.\n         */\n        public OneoffTask.Builder setExecutionWindow(long windowStartDelaySeconds, long windowEndDelaySeconds) {\n            this.windowEnd = windowEndDelaySeconds;\n            this.windowStart = windowStartDelaySeconds;\n            return this;\n        }\n\n        /**\n         * Optional setter for specifying any extra parameters necessary for the task.\n         */\n        public OneoffTask.Builder setExtras(Bundle extras) {\n            this.extras = extras;\n            return this;\n        }\n\n        /**\n         * Optional setter to specify whether this task should be persisted across reboots..\n         * Callers <strong>must</strong> hold the permission\n         * android.Manifest.permission.RECEIVE_BOOT_COMPLETED, otherwise this setter is\n         * ignored.\n         *\n         * @param isPersisted True if this task should be persisted across device reboots.\n         */\n        public OneoffTask.Builder setPersisted(boolean isPersisted) {\n            this.isPersisted = isPersisted;\n            return this;\n        }\n\n        /**\n         * Set the network state your task requires to run. <strong>If the specified network is\n         * unavailable your task will not be executed until it becomes available.</strong>\n         * <p/>\n         * The default for either a periodic or one-off task is\n         * {@link com.google.android.gms.gcm.Task#NETWORK_STATE_CONNECTED}. Note that changing this to\n         * {@link com.google.android.gms.gcm.Task#NETWORK_STATE_ANY} means there is no guarantee that data will be available\n         * when your task executes.\n         * <p/>\n         * In addition, the only guarantee for connectivity is at the moment of execution - it is\n         * possible for the device to lose data shortly after your task begins executing.\n         */\n        public OneoffTask.Builder setRequiredNetwork(int requiredNetworkState) {\n            this.requiredNetworkState = requiredNetworkState;\n            return this;\n        }\n\n        /**\n         * Set whether your task requires that the device be connected to power in order to\n         * execute.\n         * <p/>\n         * Use this to defer nonessential operations whenever possible. Note that if you set this\n         * field and the device is not connected to power <strong>your task will not run</strong>\n         * until the device is plugged in.\n         * <p/>\n         * One way to deal with your task not executing until the constraint is met is to schedule\n         * another task without the constraints that is subject to some deadline that you can abide.\n         * This task would be responsible for executing your fallback logic.\n         */\n        public OneoffTask.Builder setRequiresCharging(boolean requiresCharging) {\n            this.requiresCharging = requiresCharging;\n            return this;\n        }\n\n        /**\n         * Set whichever {@link com.google.android.gms.gcm.GcmTaskService} you implement to execute the logic for this task.\n         *\n         * @param gcmTaskService Endpoint against which you're scheduling this task.\n         */\n        public OneoffTask.Builder setService(Class<? extends GcmTaskService> gcmTaskService) {\n            this.gcmTaskService = gcmTaskService.getName();\n            return this;\n        }\n\n        /**\n         * Mandatory setter for specifying the tag identifer for this task. This tag will be\n         * returned at execution time to your endpoint. See\n         * {@link com.google.android.gms.gcm.GcmTaskService#onRunTask(com.google.android.gms.gcm.TaskParams)}\n         * Maximum tag length is 100.<\n         *\n         * @param tag String identifier for this task. Consecutive schedule calls for the same\n         *            tag will update any preexisting task with the same tag.\n         */\n        public OneoffTask.Builder setTag(String tag) {\n            this.tag = tag;\n            return this;\n        }\n\n        /**\n         * Optional setter to specify whether this task should override any preexisting tasks\n         * with the same tag. This defaults to false, which means that a new task will not\n         * override an existing one.\n         *\n         * @param updateCurrent True to update the current task with the parameters of the new.\n         *                      Default false.\n         */\n        public OneoffTask.Builder setUpdateCurrent(boolean updateCurrent) {\n            this.updateCurrent = updateCurrent;\n            return this;\n        }\n\n    }\n\n}"
  },
  {
    "path": "play-services-gcm/src/main/java/com/google/android/gms/gcm/PendingCallback.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.gcm;\n\nimport android.os.IBinder;\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\npublic class PendingCallback implements Parcelable {\n    private final IBinder binder;\n\n    public PendingCallback(IBinder binder) {\n        this.binder = binder;\n    }\n\n    private PendingCallback(Parcel in) {\n        this.binder = in.readStrongBinder();\n    }\n\n    public IBinder getBinder() {\n        return binder;\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(binder);\n    }\n\n    public static final Creator<PendingCallback> CREATOR = new Creator<PendingCallback>() {\n        @Override\n        public PendingCallback createFromParcel(Parcel source) {\n            return new PendingCallback(source);\n        }\n\n        @Override\n        public PendingCallback[] newArray(int size) {\n            return new PendingCallback[size];\n        }\n    };\n}\n"
  },
  {
    "path": "play-services-gcm/src/main/java/com/google/android/gms/gcm/PeriodicTask.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.gcm;\n\nimport android.os.Bundle;\nimport android.os.Parcel;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * A periodic task is one that will recur at the specified interval, without needing to be\n * rescheduled.\n * Schedule a task that will recur until the user calls one of\n * {@link com.google.android.gms.gcm.GcmNetworkManager#cancelAllTasks(java.lang.Class<? extends com.google.android.gms.gcm.GcmTaskService>)}, or\n * {@link com.google.android.gms.gcm.GcmNetworkManager#cancelTask(java.lang.String, java.lang.Class<? extends com.google.android.gms.gcm.GcmTaskService>)} with\n * an identifying tag.\n * <p/>\n * Periodic tasks will not be scheduled if their period is below a certain minimum\n * (currently 30 seconds).\n */\n@PublicApi\npublic class PeriodicTask extends com.google.android.gms.gcm.Task {\n\n    protected long mFlexInSeconds;\n\n    protected long mIntervalInSeconds;\n\n    private PeriodicTask(Builder builder) {\n        super(builder);\n        this.mIntervalInSeconds = builder.periodInSeconds;\n        this.mFlexInSeconds = Math.min(builder.flexInSeconds, mIntervalInSeconds);\n    }\n\n    private PeriodicTask(Parcel source) {\n        super(source);\n        mIntervalInSeconds = source.readLong();\n        mFlexInSeconds = Math.min(source.readLong(), mIntervalInSeconds);\n    }\n\n\n    /**\n     * @return The number of seconds before the end of the period returned via\n     * {@link com.google.android.gms.gcm.PeriodicTask#getPeriod()} that this periodic task can be executed early.\n     */\n    public long getFlex() {\n        return mFlexInSeconds;\n    }\n\n    /**\n     * @return The period for this task. The number of seconds between subsequent executions.\n     */\n    public long getPeriod() {\n        return mIntervalInSeconds;\n    }\n\n    /**\n     * Insert the task object into the provided bundle for IPC. Use #fromBundle to recreate the\n     * object on the other side.\n     */\n    public void toBundle(Bundle bundle) {\n        super.toBundle(bundle);\n        bundle.putLong(\"period\", this.mIntervalInSeconds);\n        bundle.putLong(\"period_flex\", this.mFlexInSeconds);\n    }\n\n    public String toString() {\n        return super.toString() + \" period=\" + this.getPeriod() + \" flex=\" + this.getFlex();\n    }\n\n    public void writeToParcel(Parcel parcel, int flags) {\n        super.writeToParcel(parcel, flags);\n        parcel.writeLong(this.mIntervalInSeconds);\n        parcel.writeLong(this.mFlexInSeconds);\n    }\n\n    public static final Creator<PeriodicTask> CREATOR = new Creator<PeriodicTask>() {\n        @Override\n        public PeriodicTask createFromParcel(Parcel source) {\n            return new PeriodicTask(source);\n        }\n\n        @Override\n        public PeriodicTask[] newArray(int size) {\n            return new PeriodicTask[size];\n        }\n    };\n\n    public static class Builder extends com.google.android.gms.gcm.Task.Builder {\n        private long flexInSeconds = -1;\n        private long periodInSeconds = -1;\n\n        public Builder() {\n            isPersisted = true;\n        }\n\n        public PeriodicTask build() {\n            return new PeriodicTask(this);\n        }\n\n        /**\n         * Optional setter for specifying any extra parameters necessary for the task.\n         */\n        public PeriodicTask.Builder setExtras(Bundle extras) {\n            this.extras = extras;\n            return this;\n        }\n\n        /**\n         * Optional setter for specifying how close to the end of the period set in\n         * {@link com.google.android.gms.gcm.PeriodicTask.Builder#setPeriod(long)} you are willing to execute.\n         * <p/>\n         * For example, specifying a period of 30 seconds, with a flex value of 10 seconds\n         * will allow the scheduler to determine the best moment between the 20th and 30th\n         * second at which to execute your task.\n         */\n        public PeriodicTask.Builder setFlex(long flexInSeconds) {\n            this.flexInSeconds = flexInSeconds;\n            return this;\n        }\n\n        /**\n         * Mandatory setter for creating a periodic task. This specifies that you would like\n         * this task to recur at most once every <code>mIntervalInSeconds.</code>\n         * <p/>\n         * By default you have no control over where within this period the task will execute.\n         * If you want to restrict the task to run within a certain timeframe from the end of\n         * the period, use {@link com.google.android.gms.gcm.PeriodicTask.Builder#setFlex(long)}\n         */\n        public PeriodicTask.Builder setPeriod(long periodInSeconds) {\n            this.periodInSeconds = periodInSeconds;\n            return this;\n        }\n\n        /**\n         * Optional setter to specify whether this task should be persisted across reboots. This\n         * defaults to true for periodic tasks,\n         * <p/>\n         * Callers <strong>must</strong> hold the permission\n         * android.Manifest.permission.RECEIVE_BOOT_COMPLETED, otherwise this setter is\n         * ignored.\n         *\n         * @param isPersisted True if this task should be persisted across device reboots.\n         */\n        public PeriodicTask.Builder setPersisted(boolean isPersisted) {\n            this.isPersisted = isPersisted;\n            return this;\n        }\n\n        /**\n         * Set the network state your task requires to run. <strong>If the specified network is\n         * unavailable your task will not be executed until it becomes available.</strong>\n         * <p/>\n         * The default for either a periodic or one-off task is\n         * {@link com.google.android.gms.gcm.Task#NETWORK_STATE_CONNECTED}. Note that changing this to\n         * {@link com.google.android.gms.gcm.Task#NETWORK_STATE_ANY} means there is no guarantee that data will be available\n         * when your task executes.\n         * <p/>\n         * In addition, the only guarantee for connectivity is at the moment of execution - it is\n         * possible for the device to lose data shortly after your task begins executing.\n         */\n        public PeriodicTask.Builder setRequiredNetwork(int requiredNetworkState) {\n            this.requiredNetworkState = requiredNetworkState;\n            return this;\n        }\n\n        /**\n         * Set whether your task requires that the device be connected to power in order to\n         * execute.\n         * <p/>\n         * Use this to defer nonessential operations whenever possible. Note that if you set this\n         * field and the device is not connected to power <strong>your task will not run</strong>\n         * until the device is plugged in.\n         * <p/>\n         * One way to deal with your task not executing until the constraint is met is to schedule\n         * another task without the constraints that is subject to some deadline that you can abide.\n         * This task would be responsible for executing your fallback logic.\n         */\n        public PeriodicTask.Builder setRequiresCharging(boolean requiresCharging) {\n            this.requiresCharging = requiresCharging;\n            return this;\n        }\n\n        /**\n         * <p>Set whichever {@link com.google.android.gms.gcm.GcmTaskService} you implement to execute the logic for this task.</p>\n         *\n         * @param gcmTaskService Endpoint against which you're scheduling this task.\n         */\n        public PeriodicTask.Builder setService(Class<? extends GcmTaskService> gcmTaskService) {\n            this.gcmTaskService = gcmTaskService.getName();\n            return this;\n        }\n\n        /**\n         * Mandatory setter for specifying the tag identifer for this task. This tag will be\n         * returned at execution time to your endpoint. See\n         * {@link com.google.android.gms.gcm.GcmTaskService#onRunTask(com.google.android.gms.gcm.TaskParams)}\n         * <p/>\n         * Maximum tag length is 100.\n         *\n         * @param tag String identifier for this task. Consecutive schedule calls for the same\n         *            tag will update any preexisting task with the same tag.\n         */\n        public PeriodicTask.Builder setTag(String tag) {\n            this.tag = tag;\n            return this;\n        }\n\n        /**\n         * Optional setter to specify whether this task should override any preexisting tasks\n         * with the same tag. This defaults to false, which means that a new task will not\n         * override an existing one.\n         *\n         * @param updateCurrent True to update the current task with the parameters of the new.\n         *                      Default false.\n         */\n        public PeriodicTask.Builder setUpdateCurrent(boolean updateCurrent) {\n            this.updateCurrent = updateCurrent;\n            return this;\n        }\n    }\n}"
  },
  {
    "path": "play-services-gcm/src/main/java/com/google/android/gms/gcm/Task.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.gcm;\n\nimport android.os.Bundle;\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Encapsulates the parameters of a task that you will schedule on the\n * {@link com.google.android.gms.gcm.GcmNetworkManager}.\n * <p/>\n * Construct instances of either {@link com.google.android.gms.gcm.PeriodicTask} or\n * {@link com.google.android.gms.gcm.OneoffTask} with the desired parameters/behaviour and\n * schedule them using {@link com.google.android.gms.gcm.GcmNetworkManager#schedule(com.google.android.gms.gcm.Task)}.\n */\n@PublicApi\npublic abstract class Task implements Parcelable {\n\n    /**\n     * <p>The maximum size allowed for extras bundle in bytes.\n     * </p>\n     */\n    public static final int EXTRAS_LIMIT_BYTES = 10240;\n\n    /**\n     * <p>Specify using {@link com.google.android.gms.gcm.Task.Builder#setRequiredNetwork(int)}\n     * that your task will execute [...] of whether network is available.\n     * </p>\n     */\n    public static final int NETWORK_STATE_ANY = 2;\n\n    /**\n     * <p>Specify using {@link com.google.android.gms.gcm.Task.Builder#setRequiredNetwork(int)}\n     * that your task will only execute if [...] sort of data connection is available -\n     * either metered or unmetered. <strong>This is the default.</strong></p>\n     */\n    public static final int NETWORK_STATE_CONNECTED = 0;\n\n    /**\n     * <p>Specify using {@link com.google.android.gms.gcm.Task.Builder#setRequiredNetwork(int)}\n     * that your task will only execute if there is an unmetered network connection available.\n     * </p>\n     */\n    public static final int NETWORK_STATE_UNMETERED = 1;\n\n    protected static final long UNINITIALIZED = -1;\n\n    private final String serviceName;\n    private final String tag;\n    private final boolean updateCurrent;\n    private final boolean persisted;\n    private final int requiredNetwork;\n    private final boolean requiresCharging;\n    private final Bundle extras;\n\n    Task(Builder builder) {\n        this.serviceName = builder.gcmTaskService;\n        this.tag = builder.tag;\n        this.updateCurrent = builder.updateCurrent;\n        this.persisted = builder.isPersisted;\n        this.requiredNetwork = builder.requiredNetworkState;\n        this.requiresCharging = builder.requiresCharging;\n        this.extras = builder.extras;\n    }\n\n    Task(Parcel in) {\n        this.serviceName = in.readString();\n        this.tag = in.readString();\n        this.updateCurrent = in.readInt() == 1;\n        this.persisted = in.readInt() == 1;\n        this.requiredNetwork = NETWORK_STATE_ANY;\n        this.requiresCharging = false;\n        this.extras = null;\n    }\n\n    public int describeContents() {\n        return 0;\n    }\n\n    /**\n     * @return The extra parameters for the task set by the client.\n     */\n    public Bundle getExtras() {\n        return extras;\n    }\n\n    /**\n     * If the specified network is unavailable, your task <strong>will not be run</strong> until\n     * it is.\n     *\n     * @return The network type that this task requires in order to run. See the NETWORK_TYPE_*\n     * flavours for an explanation of what this value can be.\n     */\n    public int getRequiredNetwork() {\n        return requiredNetwork;\n    }\n\n    /**\n     * If the device is not charging and this is set to true, your task <strong>will not be run\n     * </strong> until it is.\n     *\n     * @return Whether or not this task depends on the device being connected to power in order to\n     * execute.\n     */\n    public boolean getRequiresCharging() {\n        return requiresCharging;\n    }\n\n    /**\n     * @return The {@link com.google.android.gms.gcm.GcmTaskService} component that this task\n     * will execute on.\n     */\n    public String getServiceName() {\n        return serviceName;\n    }\n\n    /**\n     * @return The String identifier for this task, that is returned to\n     * {@link com.google.android.gms.gcm.GcmTaskService#onRunTask(com.google.android.gms.gcm.TaskParams)}\n     * when this task executes.\n     */\n    public String getTag() {\n        return tag;\n    }\n\n    /**\n     * @return Whether this task will be persisted across devices restarts or Google Play Services\n     * crashes.\n     */\n    public boolean isPersisted() {\n        return persisted;\n    }\n\n    /**\n     * @return Whether or not this task will update a pre-existing task in the scheduler queue.\n     */\n    public boolean isUpdateCurrent() {\n        return updateCurrent;\n    }\n\n    public void toBundle(Bundle bundle) {\n        bundle.putString(\"tag\", this.tag);\n        bundle.putBoolean(\"update_current\", this.updateCurrent);\n        bundle.putBoolean(\"persisted\", this.persisted);\n        bundle.putString(\"service\", this.serviceName);\n        bundle.putInt(\"requiredNetwork\", this.requiredNetwork);\n        bundle.putBoolean(\"requiresCharging\", this.requiresCharging);\n        bundle.putBundle(\"retryStrategy\", null); // TODO\n        bundle.putBundle(\"extras\", this.extras);\n    }\n\n    public void writeToParcel(Parcel parcel, int i) {\n        parcel.writeString(serviceName);\n        parcel.writeString(tag);\n        parcel.writeInt(updateCurrent ? 1 : 0);\n        parcel.writeInt(persisted ? 1 : 0);\n    }\n\n\n    /**\n     * <p>Builder object to construct these tasks before sending them to the network manager. Use\n     * either {@link com.google.android.gms.gcm.PeriodicTask.Builder} or\n     * {@link com.google.android.gms.gcm.Task.Builder}</p>\n     */\n    public abstract static class Builder {\n        protected Bundle extras;\n        protected String gcmTaskService;\n        protected boolean isPersisted;\n        protected int requiredNetworkState;\n        protected boolean requiresCharging;\n        protected String tag;\n        protected boolean updateCurrent;\n\n        public Builder() {\n            throw new UnsupportedOperationException();\n        }\n\n        public abstract Task build();\n\n        /**\n         * Optional setter for specifying any extra parameters necessary for the task.\n         */\n        public abstract Task.Builder setExtras(Bundle extras);\n\n        /**\n         * Optional setter to specify whether this task should be persisted across reboots. This\n         * defaults to true for periodic tasks, and is not supported for one-off tasks.\n         * <p/>\n         * Callers <strong>must</strong> hold the permission\n         * android.Manifest.permission.RECEIVE_BOOT_COMPLETED, otherwise this setter is\n         * ignored.\n         *\n         * @param isPersisted True if this task should be persisted across device reboots.\n         */\n        public abstract Task.Builder setPersisted(boolean isPersisted);\n\n        /**\n         * Set the network state your task requires to run. <strong>If the specified network is\n         * unavailable your task will not be executed until it becomes available.</strong>\n         * <p/>\n         * The default for either a periodic or one-off task is\n         * {@link com.google.android.gms.gcm.Task#NETWORK_STATE_CONNECTED}. Note that changing this to\n         * {@link com.google.android.gms.gcm.Task#NETWORK_STATE_ANY} means there is no guarantee that data will be available\n         * when your task executes.\n         * <p/>\n         * In addition, the only guarantee for connectivity is at the moment of execution - it is\n         * possible for the device to lose data shortly after your task begins executing.\n         */\n        public abstract Task.Builder setRequiredNetwork(int requiredNetworkState);\n\n        /**\n         * Set whether your task requires that the device be connected to power in order to\n         * execute.\n         * <p/>\n         * Use this to defer nonessential operations whenever possible. Note that if you set this\n         * field and the device is not connected to power <strong>your task will not run</strong>\n         * until the device is plugged in.\n         * <p/>\n         * One way to deal with your task not executing until the constraint is met is to schedule\n         * another task without the constraints that is subject to some deadline that you can abide.\n         * This task would be responsible for executing your fallback logic.\n         */\n        public abstract Task.Builder setRequiresCharging(boolean requiresCharging);\n\n        /**\n         * Set whichever {@link com.google.android.gms.gcm.GcmTaskService} you implement to execute the logic for this task.\n         *\n         * @param gcmTaskService Endpoint against which you're scheduling this task.\n         */\n        public abstract Task.Builder setService(Class<? extends GcmTaskService> gcmTaskService);\n\n        /**\n         * Mandatory setter for specifying the tag identifer for this task. This tag will be\n         * returned at execution time to your endpoint. See\n         * {@link com.google.android.gms.gcm.GcmTaskService#onRunTask(com.google.android.gms.gcm.TaskParams)}\n         * <p/>\n         * Maximum tag length is 100.\n         *\n         * @param tag String identifier for this task. Consecutive schedule calls for the same tag\n         *            will update any preexisting task with the same tag.\n         */\n        public abstract Task.Builder setTag(String tag);\n\n        /**\n         * Optional setter to specify whether this task should override any preexisting tasks with\n         * the same tag. This defaults to false, which means that a new task will not override an\n         * existing one.\n         *\n         * @param updateCurrent True to update the current task with the parameters of the new.\n         *                      Default false.\n         */\n        public abstract Task.Builder setUpdateCurrent(boolean updateCurrent);\n    }\n}"
  },
  {
    "path": "play-services-gcm/src/main/java/com/google/android/gms/gcm/TaskParams.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.gcm;\n\nimport android.os.Bundle;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Container of parameters handed off to the client app in\n * {@link com.google.android.gms.gcm.GcmTaskService#onRunTask(com.google.android.gms.gcm.TaskParams)}.\n */\n@PublicApi\npublic class TaskParams {\n    private final String tag;\n    private final Bundle extras;\n\n    public TaskParams(String tag) {\n        this(tag, null);\n    }\n\n    public TaskParams(String tag, Bundle extras) {\n        this.tag = tag;\n        this.extras = extras;\n    }\n\n    public Bundle getExtras() {\n        return extras;\n    }\n\n    public String getTag() {\n        return tag;\n    }\n\n}\n"
  },
  {
    "path": "play-services-gcm/src/main/java/org/microg/gms/gcm/CloudMessagingRpc.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.gcm;\n\nimport android.app.PendingIntent;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageManager;\nimport android.content.pm.ResolveInfo;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.os.Looper;\nimport android.os.Message;\nimport android.os.Messenger;\nimport android.util.Log;\n\nimport com.google.android.gms.iid.InstanceID;\n\nimport java.io.IOException;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport static android.content.pm.PackageManager.PERMISSION_GRANTED;\nimport static com.google.android.gms.gcm.GoogleCloudMessaging.ERROR_SERVICE_NOT_AVAILABLE;\nimport static org.microg.gms.common.Constants.GMS_PACKAGE_NAME;\nimport static org.microg.gms.common.Constants.GSF_PACKAGE_NAME;\nimport static org.microg.gms.gcm.GcmConstants.ACTION_C2DM_REGISTER;\nimport static org.microg.gms.gcm.GcmConstants.ACTION_C2DM_REGISTRATION;\nimport static org.microg.gms.gcm.GcmConstants.ACTION_GCM_SEND;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_APP;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_ERROR;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_MESSAGE_ID;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_MESSENGER;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_REGISTRATION_ID;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_UNREGISTERED;\nimport static org.microg.gms.gcm.GcmConstants.PERMISSION_GTALK;\nimport static org.microg.gms.gcm.GcmConstants.PERMISSION_RECEIVE;\n\npublic class CloudMessagingRpc {\n    private static final AtomicInteger messageIdCounter = new AtomicInteger(1);\n    private static String gcmPackageName;\n\n    private final BlockingQueue<Intent> messengerResponseQueue = new LinkedBlockingQueue<Intent>();\n    private final Messenger messenger = new Messenger(new Handler(Looper.getMainLooper()) {\n        @Override\n        public void handleMessage(Message msg) {\n            if (msg == null || !(msg.obj instanceof Intent)) {\n                // Invalid message -> drop\n                return;\n            }\n            Intent intent = (Intent) msg.obj;\n            if (ACTION_C2DM_REGISTRATION.equals(intent.getAction())) {\n                messengerResponseQueue.add(intent);\n            }\n        }\n    });\n\n    /**\n     * Due to it's nature of being a monitored reference, Intents can be used to authenticate a package source.\n     */\n    private PendingIntent selfAuthIntent;\n    private Context context;\n\n    public CloudMessagingRpc(Context context) {\n        this.context = context;\n    }\n\n    public static String getGcmPackageName(Context context) {\n        if (gcmPackageName != null) {\n            return gcmPackageName;\n        }\n        PackageManager packageManager = context.getPackageManager();\n        for (ResolveInfo resolveInfo : packageManager.queryIntentServices(new Intent(ACTION_C2DM_REGISTER), 0)) {\n            if (packageManager.checkPermission(PERMISSION_RECEIVE, resolveInfo.serviceInfo.packageName) == PERMISSION_GRANTED) {\n                return gcmPackageName = resolveInfo.serviceInfo.packageName;\n            }\n        }\n        try {\n            ApplicationInfo appInfo = packageManager.getApplicationInfo(GMS_PACKAGE_NAME, 0);\n            return gcmPackageName = appInfo.packageName;\n        } catch (PackageManager.NameNotFoundException ignored) {\n        }\n        try {\n            ApplicationInfo appInfo = packageManager.getApplicationInfo(GSF_PACKAGE_NAME, 0);\n            return gcmPackageName = appInfo.packageName;\n        } catch (PackageManager.NameNotFoundException ex3) {\n            return null;\n        }\n    }\n\n    public void close() {\n        // Cancel the authentication\n        if (selfAuthIntent != null) {\n            selfAuthIntent.cancel();\n            selfAuthIntent = null;\n        }\n    }\n\n    private PendingIntent getSelfAuthIntent() {\n        if (selfAuthIntent == null) {\n            Intent intent = new Intent();\n            intent.setPackage(\"com.google.example.invalidpackage\");\n            selfAuthIntent = PendingIntent.getBroadcast(context, 0, intent, 0);\n        }\n        return selfAuthIntent;\n    }\n\n    public Intent sendRegisterMessageBlocking(Bundle extras) throws IOException {\n        sendRegisterMessage(extras);\n        Intent resultIntent;\n        try {\n            resultIntent = messengerResponseQueue.poll(30, TimeUnit.SECONDS);\n        } catch (InterruptedException e) {\n            throw new IOException(e.getMessage());\n        }\n        if (resultIntent == null) {\n            throw new IOException(ERROR_SERVICE_NOT_AVAILABLE);\n        }\n        return resultIntent;\n    }\n\n    private void sendRegisterMessage(Bundle extras) {\n        Intent intent = new Intent(ACTION_C2DM_REGISTER);\n        intent.setPackage(getGcmPackageName(context));\n        extras.putString(EXTRA_MESSAGE_ID, \"google.rpc\" + messageIdCounter.getAndIncrement());\n        intent.putExtras(extras);\n        intent.putExtra(EXTRA_MESSENGER, messenger);\n        intent.putExtra(EXTRA_APP, getSelfAuthIntent());\n        context.startService(intent);\n    }\n\n    public void sendGcmMessage(Bundle extras) {\n        Intent intent = new Intent(ACTION_GCM_SEND);\n        intent.setPackage(GMS_PACKAGE_NAME);\n        intent.putExtras(extras);\n        intent.putExtra(EXTRA_APP, getSelfAuthIntent());\n        context.sendOrderedBroadcast(intent, PERMISSION_GTALK);\n    }\n\n    public String handleRegisterMessageResult(Intent resultIntent) throws IOException {\n        if (resultIntent == null) throw new IOException(InstanceID.ERROR_SERVICE_NOT_AVAILABLE);\n        String result = resultIntent.getStringExtra(EXTRA_REGISTRATION_ID);\n        if (result == null) result = resultIntent.getStringExtra(EXTRA_UNREGISTERED);\n        if (result != null) return result;\n        result = resultIntent.getStringExtra(EXTRA_ERROR);\n        throw new IOException(result != null ? result : InstanceID.ERROR_SERVICE_NOT_AVAILABLE);\n    }\n}\n"
  },
  {
    "path": "play-services-gmscompliance/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\nandroid {\n    namespace \"org.microg.gms.gmscompliance.api\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n}\n\napply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG API for play-services-gmscompliance'\n\ndependencies {\n    api project(':play-services-base')\n\n    implementation \"androidx.annotation:annotation:$annotationVersion\"\n}\n"
  },
  {
    "path": "play-services-gmscompliance/core/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'kotlin-android'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\ndependencies {\n    api project(':play-services-gmscompliance')\n\n    implementation project(':play-services-base-core')\n\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion\"\n    implementation \"org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutineVersion\"\n    implementation \"org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutineVersion\"\n\n    implementation \"androidx.core:core-ktx:$coreVersion\"\n    implementation \"androidx.lifecycle:lifecycle-runtime-ktx:$lifecycleVersion\"\n    implementation \"androidx.lifecycle:lifecycle-service:$lifecycleVersion\"\n\n    implementation \"com.android.volley:volley:$volleyVersion\"\n    implementation \"com.squareup.wire:wire-runtime:$wireVersion\"\n}\n\nandroid {\n    namespace \"org.microg.gms.gmscompliance.core\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    sourceSets {\n        main.java.srcDirs += 'src/main/kotlin'\n    }\n\n    lintOptions {\n        disable 'MissingTranslation'\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n\n    kotlinOptions {\n        jvmTarget = 1.8\n    }\n}\n\napply from: '../../gradle/publish-android.gradle'\n\ndescription = 'microG service implementation for play-services-gmscompliance'\n"
  },
  {
    "path": "play-services-gmscompliance/core/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <application>\n        <service android:name=\"org.microg.gms.gmscompliance.GmsDeviceComplianceService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.gmscompliance.service.START\" />\n            </intent-filter>\n        </service>\n    </application>\n</manifest>\n"
  },
  {
    "path": "play-services-gmscompliance/core/src/main/kotlin/org/microg/gms/gmscompliance/GmsDeviceComplianceService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.gmscompliance\n\nimport android.util.Log\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.LifecycleOwner\nimport androidx.lifecycle.lifecycleScope\nimport com.google.android.gms.common.Feature\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.internal.ConnectionInfo\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport com.google.android.gms.gmscompliance.GmsDeviceComplianceResponse\nimport com.google.android.gms.gmscompliance.IGmsDeviceComplianceService\nimport com.google.android.gms.gmscompliance.IGmsDeviceComplianceServiceCallback\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\n\nconst val TAG = \"DeviceCompliance\"\n\nclass GmsDeviceComplianceService : BaseService(TAG, GmsService.GMS_COMPLIANCE) {\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        callback.onPostInitCompleteWithConnectionInfo(CommonStatusCodes.SUCCESS, GmsDeviceComplianceServiceImpl(lifecycle).asBinder(), ConnectionInfo().apply {\n            features = arrayOf(\n                Feature(\"gmscompliance_api\", 1)\n            )\n        });\n    }\n}\n\nclass GmsDeviceComplianceServiceImpl(override val lifecycle: Lifecycle) : IGmsDeviceComplianceService.Stub(), LifecycleOwner {\n    override fun getDeviceCompliance(callback: IGmsDeviceComplianceServiceCallback?) {\n        Log.d(TAG, \"getDeviceCompliance()\")\n        lifecycleScope.launchWhenStarted {\n            try {\n                callback?.onResponse(Status.SUCCESS, GmsDeviceComplianceResponse().apply { compliant = true })\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-gmscompliance/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<manifest />\n"
  },
  {
    "path": "play-services-gmscompliance/src/main/aidl/com/google/android/gms/gmscompliance/GmsDeviceComplianceResponse.aidl",
    "content": "package com.google.android.gms.gmscompliance;\n\nparcelable GmsDeviceComplianceResponse;\n"
  },
  {
    "path": "play-services-gmscompliance/src/main/aidl/com/google/android/gms/gmscompliance/IGmsDeviceComplianceService.aidl",
    "content": "package com.google.android.gms.gmscompliance;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.gmscompliance.IGmsDeviceComplianceServiceCallback;\n\ninterface IGmsDeviceComplianceService {\n    void getDeviceCompliance(IGmsDeviceComplianceServiceCallback callback);\n}\n"
  },
  {
    "path": "play-services-gmscompliance/src/main/aidl/com/google/android/gms/gmscompliance/IGmsDeviceComplianceServiceCallback.aidl",
    "content": "package com.google.android.gms.gmscompliance;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.gmscompliance.GmsDeviceComplianceResponse;\n\ninterface IGmsDeviceComplianceServiceCallback {\n    oneway void onResponse(in Status status, in GmsDeviceComplianceResponse response);\n}\n"
  },
  {
    "path": "play-services-gmscompliance/src/main/java/com/google/android/gms/gmscompliance/GmsDeviceComplianceResponse.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.gmscompliance;\n\nimport android.app.PendingIntent;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class GmsDeviceComplianceResponse extends AutoSafeParcelable {\n    @Field(1)\n    private int versionCode = 1;\n    @Field(2)\n    public boolean compliant;\n    @Field(3)\n    public PendingIntent errorIntent;\n\n    public static final Creator<GmsDeviceComplianceResponse> CREATOR = new AutoCreator<>(GmsDeviceComplianceResponse.class);\n}\n"
  },
  {
    "path": "play-services-iid/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2016 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\n\nandroid {\n    namespace \"com.google.android.gms.iid\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n}\n\ndependencies {\n    // Dependencies from play-services-iid:17.0.0\n    api \"androidx.collection:collection:1.0.0\"\n    api \"androidx.core:core:1.0.0\"\n    api project(':play-services-base')\n    api project(':play-services-basement')\n    //api project(':play-services-stats')\n    api project(':play-services-tasks')\n}\n"
  },
  {
    "path": "play-services-iid/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2016 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <!-- Permissions required for IID -->\n    <uses-permission android:name=\"com.google.android.c2dm.permission.RECEIVE\"/>\n    <uses-permission android:name=\"android.permission.INTERNET\"/>\n</manifest>\n"
  },
  {
    "path": "play-services-iid/src/main/aidl/com/google/android/gms/iid/IMessengerCompat.aidl",
    "content": "package com.google.android.gms.iid;\n\nimport android.os.Message;\n\ninterface IMessengerCompat {\n    void send(in Message message);\n}\n"
  },
  {
    "path": "play-services-iid/src/main/java/com/google/android/gms/iid/InstanceID.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.iid;\n\nimport android.content.Context;\nimport android.os.Bundle;\nimport android.os.Looper;\nimport android.text.TextUtils;\nimport android.util.Base64;\nimport android.util.Log;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.gcm.GcmConstants;\nimport org.microg.gms.iid.InstanceIdRpc;\nimport org.microg.gms.iid.InstanceIdStore;\n\nimport java.io.IOException;\nimport java.security.KeyPair;\nimport java.security.KeyPairGenerator;\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_DELETE;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_SCOPE;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_SENDER;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_SUBSCIPTION;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_SUBTYPE;\n\n/**\n * Instance ID provides a unique identifier for each app instance and a mechanism\n * to authenticate and authorize actions (for example, sending a GCM message).\n * <p/>\n * Instance ID is stable but may become invalid, if:\n * <ul>\n * <li>App deletes Instance ID</li>\n * <li>Device is factory reset</li>\n * <li>User uninstalls the app</li>\n * <li>User clears app data</li>\n * </ul>\n * If Instance ID has become invalid, the app can call {@link com.google.android.gms.iid.InstanceID#getId()}\n * to request a new Instance ID.\n * To prove ownership of Instance ID and to allow servers to access data or\n * services associated with the app, call {@link com.google.android.gms.iid.InstanceID#getToken(java.lang.String, java.lang.String)}.\n */\n@PublicApi\npublic class InstanceID {\n    /**\n     * Error returned when failed requests are retried too often.  Use\n     * exponential backoff when retrying requests\n     */\n    public static final String ERROR_BACKOFF = \"RETRY_LATER\";\n\n    /**\n     * Blocking methods must not be called on the main thread.\n     */\n    public static final String ERROR_MAIN_THREAD = \"MAIN_THREAD\";\n\n    /**\n     * Tokens can't be generated. Only devices with Google Play are supported.\n     */\n    public static final String ERROR_MISSING_INSTANCEID_SERVICE = \"MISSING_INSTANCEID_SERVICE\";\n\n    /**\n     * The device cannot read the response, or there was a server error.\n     * Application should retry the request later using exponential backoff\n     * and retry (on each subsequent failure increase delay before retrying).\n     */\n    public static final String ERROR_SERVICE_NOT_AVAILABLE = GcmConstants.ERROR_SERVICE_NOT_AVAILABLE;\n\n    /**\n     * Timeout waiting for a response.\n     */\n    public static final String ERROR_TIMEOUT = \"TIMEOUT\";\n\n    private static final int RSA_KEY_SIZE = 2048;\n    private static final String TAG = \"InstanceID\";\n\n    private static InstanceIdStore storeInstance;\n    private static InstanceIdRpc rpc;\n    private static Map<String, InstanceID> instances = new HashMap<String, InstanceID>();\n\n    private final String subtype;\n    private KeyPair keyPair;\n    private long creationTime;\n\n    private InstanceID(String subtype) {\n        this.subtype = subtype == null ? \"\" : subtype;\n    }\n\n    /**\n     * Resets Instance ID and revokes all tokens.\n     *\n     * @throws IOException\n     */\n    public void deleteInstanceID() throws IOException {\n        deleteToken(\"*\", \"*\");\n        creationTime = 0;\n        storeInstance.delete(subtype + \"|\");\n        keyPair = null;\n    }\n\n    /**\n     * Revokes access to a scope (action) for an entity previously\n     * authorized by {@link com.google.android.gms.iid.InstanceID#getToken(java.lang.String, java.lang.String)}.\n     * <p/>\n     * Do not call this function on the main thread.\n     *\n     * @param authorizedEntity Entity that must no longer have access.\n     * @param scope            Action that entity is no longer authorized to perform.\n     * @throws IOException if the request fails.\n     */\n    public void deleteToken(String authorizedEntity, String scope) throws IOException {\n        deleteToken(authorizedEntity, scope, null);\n    }\n\n    @PublicApi(exclude = true)\n    public void deleteToken(String authorizedEntity, String scope, Bundle extras) throws IOException {\n        if (Looper.getMainLooper() == Looper.myLooper()) throw new IOException(ERROR_MAIN_THREAD);\n\n        storeInstance.delete(subtype, authorizedEntity, scope);\n\n        if (extras == null) extras = new Bundle();\n        extras.putString(EXTRA_SENDER, authorizedEntity);\n        extras.putString(EXTRA_SUBSCIPTION, authorizedEntity);\n        extras.putString(EXTRA_DELETE, \"1\");\n        extras.putString(\"X-\" + EXTRA_DELETE, \"1\");\n        extras.putString(EXTRA_SUBTYPE, TextUtils.isEmpty(subtype) ? authorizedEntity : subtype);\n        extras.putString(\"X-\" + EXTRA_SUBTYPE, TextUtils.isEmpty(subtype) ? authorizedEntity : subtype);\n        if (scope != null) extras.putString(EXTRA_SCOPE, scope);\n\n        rpc.handleRegisterMessageResult(rpc.sendRegisterMessageBlocking(extras, getKeyPair()));\n    }\n\n    /**\n     * Returns time when instance ID was created.\n     *\n     * @return Time when instance ID was created (milliseconds since Epoch).\n     */\n    public long getCreationTime() {\n        if (creationTime == 0) {\n            String s = storeInstance.getSecret(subtype, \"cre\");\n            if (s != null) {\n                creationTime = Long.parseLong(s);\n            }\n        }\n        return creationTime;\n    }\n\n    /**\n     * Returns a stable identifier that uniquely identifies the app instance.\n     *\n     * @return The identifier for the application instance.\n     */\n    public String getId() {\n        return sha1KeyPair(getKeyPair());\n    }\n\n    /**\n     * Returns an instance of this class.\n     *\n     * @return InstanceID instance.\n     */\n    public static InstanceID getInstance(Context context) {\n        String subtype = \"\";\n        if (storeInstance == null) {\n            storeInstance = new InstanceIdStore(context.getApplicationContext());\n            rpc = new InstanceIdRpc(context.getApplicationContext());\n        }\n        InstanceID instance = instances.get(subtype);\n        if (instance == null) {\n            instance = new InstanceID(subtype);\n            instances.put(subtype, instance);\n        }\n        return instance;\n    }\n\n    /**\n     * Returns a token that authorizes an Entity (example: cloud service) to perform\n     * an action on behalf of the application identified by Instance ID.\n     * <p/>\n     * This is similar to an OAuth2 token except, it applies to the\n     * application instance instead of a user.\n     * <p/>\n     * Do not call this function on the main thread.\n     *\n     * @param authorizedEntity Entity authorized by the token.\n     * @param scope            Action authorized for authorizedEntity.\n     * @param extras           additional parameters specific to each token scope.\n     *                         Bundle keys starting with 'GCM.' and 'GOOGLE.' are\n     *                         reserved.\n     * @return a token that can identify and authorize the instance of the\n     * application on the device.\n     * @throws IOException if the request fails.\n     */\n    public String getToken(String authorizedEntity, String scope, Bundle extras) throws IOException {\n        if (Looper.getMainLooper() == Looper.myLooper()) throw new IOException(ERROR_MAIN_THREAD);\n\n        long tokenTimestamp = storeInstance.getTokenTimestamp(subtype, authorizedEntity, scope);\n        if (tokenTimestamp > System.currentTimeMillis() - 7 * 24 * 60 * 60 * 1000L) {\n            String token = storeInstance.getToken(subtype, authorizedEntity, scope);\n            if (token != null) return token;\n        }\n        String token = requestToken(authorizedEntity, scope, extras);\n        storeInstance.putToken(subtype, authorizedEntity, scope, token);\n        return token;\n    }\n\n    /**\n     * Returns a token that authorizes an Entity (example: cloud service) to perform\n     * an action on behalf of the application identified by Instance ID.\n     * <p/>\n     * This is similar to an OAuth2 token except, it applies to the\n     * application instance instead of a user.\n     * <p/>\n     * Do not call this function on the main thread.\n     *\n     * @param authorizedEntity Entity authorized by the token.\n     * @param scope            Action authorized for authorizedEntity.\n     * @return a token that can identify and authorize the instance of the\n     * application on the device.\n     * @throws IOException if the request fails.\n     */\n    public String getToken(String authorizedEntity, String scope) throws IOException {\n        return getToken(authorizedEntity, scope, null);\n    }\n\n    @PublicApi(exclude = true)\n    public InstanceIdStore getStore() {\n        return storeInstance;\n    }\n\n    @PublicApi(exclude = true)\n    public String requestToken(String authorizedEntity, String scope, Bundle extras) {\n        throw new UnsupportedOperationException();\n    }\n\n    private synchronized KeyPair getKeyPair() {\n        if (keyPair == null) {\n            keyPair = storeInstance.getKeyPair(subtype);\n            if (keyPair == null) {\n                try {\n                    KeyPairGenerator rsaGenerator = KeyPairGenerator.getInstance(\"RSA\");\n                    rsaGenerator.initialize(RSA_KEY_SIZE);\n                    keyPair = rsaGenerator.generateKeyPair();\n                    creationTime = System.currentTimeMillis();\n                    storeInstance.putKeyPair(subtype, keyPair, creationTime);\n                } catch (NoSuchAlgorithmException e) {\n                    Log.w(TAG, e);\n                }\n            }\n        }\n        return keyPair;\n    }\n\n    @PublicApi(exclude = true)\n    public static String sha1KeyPair(KeyPair keyPair) {\n        try {\n            byte[] digest = MessageDigest.getInstance(\"SHA1\").digest(keyPair.getPublic().getEncoded());\n            digest[0] = (byte) (112 + (0xF & digest[0]) & 0xFF);\n            return Base64.encodeToString(digest, 0, 8, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING);\n        } catch (NoSuchAlgorithmException e) {\n            Log.w(TAG, e);\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-iid/src/main/java/com/google/android/gms/iid/InstanceIDListenerService.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.iid;\n\nimport android.app.Service;\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.os.Handler;\nimport android.os.IBinder;\nimport android.os.Looper;\nimport android.os.Message;\nimport androidx.legacy.content.WakefulBroadcastReceiver;\nimport com.google.android.gms.stats.GCoreWakefulBroadcastReceiver;\n\nimport static org.microg.gms.gcm.GcmConstants.ACTION_C2DM_REGISTRATION;\nimport static org.microg.gms.gcm.GcmConstants.ACTION_INSTANCE_ID;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_FROM;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_GSF_INTENT;\n\n/**\n * Base class to handle Instance ID service notifications on token\n * refresh.\n * <p/>\n * Any app using Instance ID or GCM must include a class extending\n * InstanceIDListenerService and implement {@link com.google.android.gms.iid.InstanceIDListenerService#onTokenRefresh()}.\n * <p/>\n * Include the following in the manifest:\n * <pre>\n * <service android:name=\".YourInstanceIDListenerService\" android:exported=\"false\">\n *     <intent-filter>\n *         <action android:name=\"com.google.android.gms.iid.InstanceID\"/>\n *     </intent-filter>\n * </service></pre>\n * Do not export this service. Instead, keep it private to prevent other apps\n * accessing your service.\n */\npublic class InstanceIDListenerService extends Service {\n\n    private BroadcastReceiver registrationReceiver = new BroadcastReceiver() {\n        @Override\n        public void onReceive(Context context, Intent intent) {\n            handleIntent(intent);\n            stop();\n        }\n    };\n    private MessengerCompat messengerCompat = new MessengerCompat(new Handler(Looper.getMainLooper()) {\n        @Override\n        public void handleMessage(Message msg) {\n            handleIntent((Intent) msg.obj);\n        }\n    });\n\n    private int counter = 0;\n    private int startId = -1;\n\n    private void handleIntent(Intent intent) {\n        // TODO\n    }\n\n    public IBinder onBind(Intent intent) {\n        if (intent != null && ACTION_INSTANCE_ID.equals(intent.getAction())) {\n            return messengerCompat.getBinder();\n        }\n        return null;\n    }\n\n    public void onCreate() {\n        IntentFilter filter = new IntentFilter(ACTION_C2DM_REGISTRATION);\n        filter.addCategory(getPackageName());\n        registerReceiver(registrationReceiver, filter);\n    }\n\n    public void onDestroy() {\n        unregisterReceiver(registrationReceiver);\n    }\n\n    public int onStartCommand(Intent intent, int flags, int startId) {\n        synchronized (this) {\n            this.counter++;\n            if (startId > this.startId) this.startId = startId;\n        }\n        try {\n            if (intent != null) {\n                if (ACTION_INSTANCE_ID.equals(intent.getAction()) && intent.hasExtra(EXTRA_GSF_INTENT)) {\n                    startService((Intent) intent.getParcelableExtra(EXTRA_GSF_INTENT));\n                    return START_STICKY;\n                }\n\n                handleIntent(intent);\n\n                if (intent.hasExtra(EXTRA_FROM))\n                    GCoreWakefulBroadcastReceiver.completeWakefulIntent(intent);\n            }\n        } finally {\n            stop();\n        }\n        return START_NOT_STICKY;\n    }\n\n    /**\n     * Called when the system determines that the tokens need to be refreshed. The application\n     * should call getToken() and send the tokens to all application servers.\n     * <p/>\n     * This will not be called very frequently, it is needed for key rotation and to handle special\n     * cases.\n     * <p/>\n     * The system will throttle the refresh event across all devices to avoid overloading\n     * application servers with token updates.\n     */\n    public void onTokenRefresh() {\n        // To be overwritten\n    }\n\n    private void stop() {\n        synchronized (this) {\n            counter--;\n            if (counter <= 0) {\n                stopSelf(startId);\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "play-services-iid/src/main/java/com/google/android/gms/iid/MessengerCompat.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.iid;\n\nimport android.os.Binder;\nimport android.os.Handler;\nimport android.os.IBinder;\nimport android.os.Message;\nimport android.os.Messenger;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.os.RemoteException;\n\nimport static android.os.Build.VERSION.SDK_INT;\n\npublic class MessengerCompat implements Parcelable {\n    private Messenger messenger;\n    private IMessengerCompat messengerCompat;\n\n    public MessengerCompat(IBinder binder) {\n        if (SDK_INT >= 21) {\n            messenger = new Messenger(binder);\n        } else {\n            messengerCompat = IMessengerCompat.Stub.asInterface(binder);\n        }\n    }\n\n    public MessengerCompat(Handler handler) {\n        if (SDK_INT >= 21) {\n            messenger = new Messenger(handler);\n        } else {\n            messengerCompat = new IMessengerCompatImpl(handler);\n        }\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        return o instanceof MessengerCompat && ((MessengerCompat) o).getBinder().equals(getBinder());\n    }\n\n    public IBinder getBinder() {\n        return messenger != null ? messenger.getBinder() : messengerCompat.asBinder();\n    }\n\n    @Override\n    public int hashCode() {\n        return getBinder().hashCode();\n    }\n\n    public void send(Message message) throws RemoteException {\n        if (messenger != null) messenger.send(message);\n        else messengerCompat.send(message);\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        dest.writeStrongBinder(getBinder());\n    }\n\n    public static final Creator<MessengerCompat> CREATOR = new Creator<MessengerCompat>() {\n        @Override\n        public MessengerCompat createFromParcel(Parcel source) {\n            IBinder binder = source.readStrongBinder();\n            return binder != null ? new MessengerCompat(binder) : null;\n        }\n\n        @Override\n        public MessengerCompat[] newArray(int size) {\n            return new MessengerCompat[size];\n        }\n    };\n\n    private static class IMessengerCompatImpl extends IMessengerCompat.Stub {\n        private final Handler handler;\n\n        public IMessengerCompatImpl(Handler handler) {\n            this.handler = handler;\n        }\n\n        @Override\n        public void send(Message message) throws RemoteException {\n            message.arg2 = Binder.getCallingUid();\n            handler.dispatchMessage(message);\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-iid/src/main/java/org/microg/gms/iid/InstanceIdRpc.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.iid;\n\nimport android.app.PendingIntent;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageManager;\nimport android.content.pm.ResolveInfo;\nimport android.os.Bundle;\nimport android.os.ConditionVariable;\nimport android.os.Handler;\nimport android.os.Looper;\nimport android.os.Message;\nimport android.os.Messenger;\nimport android.os.Parcelable;\nimport android.os.RemoteException;\nimport android.os.SystemClock;\nimport android.text.TextUtils;\nimport android.util.Base64;\nimport android.util.Log;\n\nimport com.google.android.gms.iid.InstanceID;\nimport com.google.android.gms.iid.MessengerCompat;\n\nimport java.io.IOException;\nimport java.io.UnsupportedEncodingException;\nimport java.security.GeneralSecurityException;\nimport java.security.KeyPair;\nimport java.security.PrivateKey;\nimport java.security.Signature;\nimport java.security.interfaces.RSAPrivateKey;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Random;\n\nimport static android.content.pm.PackageManager.PERMISSION_GRANTED;\nimport static android.os.Build.VERSION.SDK_INT;\nimport static com.google.android.gms.iid.InstanceID.ERROR_BACKOFF;\nimport static com.google.android.gms.iid.InstanceID.ERROR_MISSING_INSTANCEID_SERVICE;\nimport static com.google.android.gms.iid.InstanceID.ERROR_SERVICE_NOT_AVAILABLE;\nimport static com.google.android.gms.iid.InstanceID.ERROR_TIMEOUT;\nimport static org.microg.gms.common.Constants.GMS_PACKAGE_NAME;\nimport static org.microg.gms.common.Constants.GSF_PACKAGE_NAME;\nimport static org.microg.gms.common.Constants.GMS_VERSION_CODE;\nimport static org.microg.gms.gcm.GcmConstants.ACTION_C2DM_REGISTER;\nimport static org.microg.gms.gcm.GcmConstants.ACTION_C2DM_REGISTRATION;\nimport static org.microg.gms.gcm.GcmConstants.ACTION_INSTANCE_ID;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_APP;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_APP_ID;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_APP_VERSION_CODE;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_APP_VERSION_NAME;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_CLIENT_VERSION;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_ERROR;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_GMS_VERSION;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_GSF_INTENT;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_IS_MESSENGER2;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_KID;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_MESSENGER;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_OS_VERSION;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_PUBLIC_KEY;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_REGISTRATION_ID;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_SIGNATURE;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_UNREGISTERED;\nimport static org.microg.gms.gcm.GcmConstants.EXTRA_USE_GSF;\nimport static org.microg.gms.gcm.GcmConstants.PERMISSION_RECEIVE;\n\npublic class InstanceIdRpc {\n    private static final String TAG = \"InstanceID/Rpc\";\n\n    private static final int BLOCKING_WAIT_TIME = 30000;\n\n    private static String iidPackageName;\n    private static int lastRequestId;\n    private static int retryCount;\n    private static Map<String, Object> blockingResponses = new HashMap<String, Object>();\n\n    private long nextAttempt;\n    private int interval;\n    private Context context;\n    private PendingIntent selfAuthToken;\n    private Messenger messenger;\n    private Messenger myMessenger;\n    private MessengerCompat messengerCompat;\n\n    public InstanceIdRpc(Context context) {\n        this.context = context;\n    }\n\n    public static String getIidPackageName(Context context) {\n        if (iidPackageName != null) {\n            return iidPackageName;\n        }\n        PackageManager packageManager = context.getPackageManager();\n        for (ResolveInfo resolveInfo : packageManager.queryIntentServices(new Intent(ACTION_C2DM_REGISTER), 0)) {\n            if (packageManager.checkPermission(PERMISSION_RECEIVE, resolveInfo.serviceInfo.packageName) == PERMISSION_GRANTED) {\n                return iidPackageName = resolveInfo.serviceInfo.packageName;\n            }\n        }\n        try {\n            ApplicationInfo appInfo = packageManager.getApplicationInfo(GMS_PACKAGE_NAME, 0);\n            return iidPackageName = appInfo.packageName;\n        } catch (PackageManager.NameNotFoundException ignored) {\n        }\n        try {\n            ApplicationInfo appInfo = packageManager.getApplicationInfo(GSF_PACKAGE_NAME, 0);\n            return iidPackageName = appInfo.packageName;\n        } catch (PackageManager.NameNotFoundException ex3) {\n            Log.w(TAG, \"Both Google Play Services and legacy GSF package are missing\");\n            return null;\n        }\n    }\n\n    private static int getGmsVersionCode(final Context context) {\n        final PackageManager packageManager = context.getPackageManager();\n        try {\n            return packageManager.getPackageInfo(getIidPackageName(context), 0).versionCode;\n        } catch (PackageManager.NameNotFoundException ex) {\n            return -1;\n        }\n    }\n\n    private static int getSelfVersionCode(final Context context) {\n        try {\n            return context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionCode;\n        } catch (PackageManager.NameNotFoundException neverHappens) {\n            return 0;\n        }\n    }\n\n    private static String getSelfVersionName(final Context context) {\n        try {\n            return context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName;\n        } catch (PackageManager.NameNotFoundException neverHappens) {\n            return null;\n        }\n    }\n\n    void initialize() {\n        if (myMessenger != null) return;\n        getIidPackageName(context);\n        myMessenger = new Messenger(new Handler(Looper.getMainLooper()) {\n            @Override\n            public void handleMessage(Message msg) {\n                if (msg == null) {\n                    return;\n                }\n                if (msg.obj instanceof Intent) {\n                    Intent intent = (Intent) msg.obj;\n                    intent.setExtrasClassLoader(MessengerCompat.class.getClassLoader());\n                    if (intent.hasExtra(EXTRA_MESSENGER)) {\n                        Parcelable messengerCandidate = intent.getParcelableExtra(EXTRA_MESSENGER);\n                        if (messengerCandidate instanceof MessengerCompat) {\n                            messengerCompat = (MessengerCompat) messengerCandidate;\n                        } else if (messengerCandidate instanceof Messenger) {\n                            messenger = (Messenger) messengerCandidate;\n                        }\n                    }\n                    handleResponseInternal(intent);\n                } else {\n                    Log.w(TAG, \"Dropping invalid message\");\n                }\n            }\n        });\n    }\n\n    public void handleResponseInternal(Intent resultIntent) {\n        if (resultIntent == null) return;\n        if (!ACTION_C2DM_REGISTRATION.equals(resultIntent.getAction()) && !ACTION_INSTANCE_ID.equals(resultIntent.getAction()))\n            return;\n        String result = resultIntent.getStringExtra(EXTRA_REGISTRATION_ID);\n        if (result == null) result = resultIntent.getStringExtra(EXTRA_UNREGISTERED);\n        if (result == null) {\n            handleError(resultIntent);\n            return;\n        }\n        retryCount = 0;\n        nextAttempt = 0;\n        interval = 0;\n\n        String requestId = null;\n        if (result.startsWith(\"|\")) {\n            // parse structured response\n            String[] split = result.split(\"\\\\|\");\n            if (!\"ID\".equals(split[1])) {\n                Log.w(TAG, \"Unexpected structured response \" + result);\n            }\n            requestId = split[2];\n            if (split.length > 4) {\n                if (\"SYNC\".equals(split[3])) {\n                    // TODO: sync\n                } else if(\"RST\".equals(split[3])) {\n                    // TODO: rst\n                    resultIntent.removeExtra(EXTRA_REGISTRATION_ID);\n                    return;\n                }\n            }\n            result = split[split.length-1];\n            if (result.startsWith(\":\"))\n                result = result.substring(1);\n            resultIntent.putExtra(EXTRA_REGISTRATION_ID, result);\n        }\n        setResponse(requestId, resultIntent);\n    }\n\n    private void handleError(Intent resultIntent) {\n        String error = resultIntent.getStringExtra(\"error\");\n        if (error == null) return;\n        String requestId = null;\n        if (error.startsWith(\"|\")) {\n            // parse structured error message\n            String[] split = error.split(\"\\\\|\");\n            if (!\"ID\".equals(split[1])) {\n                Log.w(TAG, \"Unexpected structured response \" + error);\n            }\n            if (split.length > 2) {\n                requestId = split[2];\n                error = split[3];\n                if (error.startsWith(\":\"))\n                    error = error.substring(1);\n            } else {\n                error = \"UNKNOWN\";\n            }\n            resultIntent.putExtra(\"error\", error);\n        }\n        setResponse(requestId, resultIntent);\n        long retryAfter = resultIntent.getLongExtra(\"Retry-After\", 0);\n        if (retryAfter > 0) {\n            interval = (int) (retryAfter * 1000);\n            nextAttempt = SystemClock.elapsedRealtime() + interval;\n            Log.d(TAG, \"Server requested retry delay: \" + interval);\n        } else if (ERROR_SERVICE_NOT_AVAILABLE.equals(error) || \"AUTHENTICATION_FAILED\".equals(error)\n                && GSF_PACKAGE_NAME.equals(getIidPackageName(context))) {\n            retryCount++;\n            if (retryCount < 3) return;\n            if (retryCount == 3) interval = 1000 + new Random().nextInt(1000);\n            interval = interval * 2;\n            nextAttempt = SystemClock.elapsedRealtime() + interval;\n            Log.d(TAG, \"Setting retry delay to \" + interval);\n        }\n    }\n\n    private synchronized PendingIntent getSelfAuthToken() {\n        if (selfAuthToken == null) {\n            Intent intent = new Intent();\n            intent.setPackage(\"com.google.example.invalidpackage\");\n            selfAuthToken = PendingIntent.getBroadcast(context, 0, intent, 0);\n        }\n        return selfAuthToken;\n    }\n\n    private static synchronized String getRequestId() {\n        return Integer.toString(lastRequestId++);\n    }\n\n    private void sendRegisterMessage(Bundle data, KeyPair keyPair, String requestId) throws IOException {\n        long elapsedRealtime = SystemClock.elapsedRealtime();\n        if (nextAttempt != 0 && elapsedRealtime <= nextAttempt) {\n            Log.w(TAG, \"Had to wait for \" + interval + \", that's still \" + (nextAttempt - elapsedRealtime));\n            throw new IOException(ERROR_BACKOFF);\n        }\n        initialize();\n        if (iidPackageName == null) {\n            throw new IOException(ERROR_MISSING_INSTANCEID_SERVICE);\n        }\n        Intent intent = new Intent(ACTION_C2DM_REGISTER);\n        intent.setPackage(iidPackageName);\n        data.putString(EXTRA_GMS_VERSION, Integer.toString(getGmsVersionCode(context)));\n        data.putString(EXTRA_OS_VERSION, Integer.toString(SDK_INT));\n        data.putString(EXTRA_APP_VERSION_CODE, Integer.toString(getSelfVersionCode(context)));\n        data.putString(EXTRA_APP_VERSION_NAME, getSelfVersionName(context));\n        data.putString(EXTRA_CLIENT_VERSION, \"iid-\" + GMS_VERSION_CODE);\n        data.putString(EXTRA_APP_ID, InstanceID.sha1KeyPair(keyPair));\n        String pub = base64encode(keyPair.getPublic().getEncoded());\n        data.putString(EXTRA_PUBLIC_KEY, pub);\n        data.putString(EXTRA_SIGNATURE, sign(keyPair, context.getPackageName(), pub));\n        intent.putExtras(data);\n        intent.putExtra(EXTRA_APP, getSelfAuthToken());\n        sendRequest(intent, requestId);\n    }\n\n    private static String sign(KeyPair keyPair, String... payload) {\n        byte[] bytes;\n        try {\n            bytes = TextUtils.join(\"\\n\", payload).getBytes(\"UTF-8\");\n        } catch (UnsupportedEncodingException e) {\n            Log.e(TAG, \"Unable to encode\", e);\n            return null;\n        }\n        PrivateKey privateKey = keyPair.getPrivate();\n        try {\n            Signature signature = Signature.getInstance(privateKey instanceof RSAPrivateKey ? \"SHA256withRSA\" : \"SHA256withECDSA\");\n            signature.initSign(privateKey);\n            signature.update(bytes);\n            return base64encode(signature.sign());\n        } catch (GeneralSecurityException e) {\n            Log.e(TAG, \"Unable to sign\", e);\n            return null;\n        }\n    }\n\n    private static String base64encode(byte[] bytes) {\n        return Base64.encodeToString(bytes, Base64.URL_SAFE + Base64.NO_PADDING + Base64.NO_WRAP);\n    }\n\n    private void sendRequest(Intent intent, String requestId) {\n        intent.putExtra(EXTRA_KID, \"|ID|\" + requestId + \"|\");\n        intent.putExtra(\"X-\" + EXTRA_KID, \"|ID|\" + requestId + \"|\");\n        Log.d(TAG, \"Sending \" + intent.getExtras());\n        if (messenger != null) {\n            intent.putExtra(EXTRA_MESSENGER, myMessenger);\n            Message msg = Message.obtain();\n            msg.obj = intent;\n            try {\n                messenger.send(msg);\n                return;\n            } catch (RemoteException e) {\n                Log.d(TAG, \"Messenger failed, falling back to service\");\n            }\n        }\n\n        boolean useGsf = iidPackageName.endsWith(\".gsf\");\n        if (intent.hasExtra(EXTRA_USE_GSF))\n            useGsf = \"1\".equals(intent.getStringExtra(EXTRA_USE_GSF));\n\n        if (useGsf) {\n            Intent holder = new Intent(ACTION_INSTANCE_ID);\n            holder.setPackage(context.getPackageName());\n            holder.putExtra(EXTRA_GSF_INTENT, intent);\n            context.startService(holder);\n        } else {\n            intent.putExtra(EXTRA_MESSENGER, myMessenger);\n            intent.putExtra(EXTRA_IS_MESSENGER2, \"1\");\n            if (messengerCompat != null) {\n                Message msg = Message.obtain();\n                msg.obj = intent;\n                try {\n                    messengerCompat.send(msg);\n                    return;\n                } catch (RemoteException e) {\n                    Log.d(TAG, \"Messenger failed, falling back to service\");\n                }\n            }\n            context.startService(intent);\n        }\n    }\n\n    public Intent sendRegisterMessageBlocking(Bundle data, KeyPair keyPair) throws IOException {\n        Intent intent = sendRegisterMessageBlockingInternal(data, keyPair);\n        if (intent != null && intent.hasExtra(EXTRA_MESSENGER)) {\n            // Now with a messenger\n            intent = sendRegisterMessageBlockingInternal(data, keyPair);\n        }\n        return intent;\n    }\n\n    private Intent sendRegisterMessageBlockingInternal(Bundle data, KeyPair keyPair) throws IOException {\n        ConditionVariable cv = new ConditionVariable();\n        String requestId = getRequestId();\n        synchronized (InstanceIdRpc.class) {\n            blockingResponses.put(requestId, cv);\n        }\n\n        sendRegisterMessage(data, keyPair, requestId);\n\n        cv.block(BLOCKING_WAIT_TIME);\n        synchronized (InstanceIdRpc.class) {\n            Object res = blockingResponses.remove(requestId);\n            if (res instanceof Intent) {\n                return (Intent) res;\n            } else if (res instanceof String) {\n                throw new IOException((String) res);\n            }\n            Log.w(TAG, \"No response \" + res);\n            throw new IOException(ERROR_TIMEOUT);\n        }\n    }\n\n    public String handleRegisterMessageResult(Intent resultIntent) throws IOException {\n        if (resultIntent == null) throw new IOException(ERROR_SERVICE_NOT_AVAILABLE);\n        String result = resultIntent.getStringExtra(EXTRA_REGISTRATION_ID);\n        if (result == null) result = resultIntent.getStringExtra(EXTRA_UNREGISTERED);\n        if (result != null) return result;\n        result = resultIntent.getStringExtra(EXTRA_ERROR);\n        throw new IOException(result != null ? result : ERROR_SERVICE_NOT_AVAILABLE);\n    }\n\n    private void setResponse(String requestId, Object response) {\n        if (requestId == null) {\n            for (String r : blockingResponses.keySet()) {\n                setResponse(r, response);\n            }\n        }\n        Object old = blockingResponses.get(requestId);\n        blockingResponses.put(requestId, response);\n        if (old instanceof ConditionVariable) {\n            ((ConditionVariable) old).open();\n        } else if (old instanceof Messenger) {\n            Message msg = Message.obtain();\n            msg.obj = response;\n            try {\n                ((Messenger) old).send(msg);\n            } catch (RemoteException e) {\n                Log.w(TAG, \"Failed to send response\", e);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-iid/src/main/java/org/microg/gms/iid/InstanceIdStore.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.iid;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\nimport android.util.Base64;\nimport android.util.Log;\n\nimport java.security.KeyFactory;\nimport java.security.KeyPair;\nimport java.security.spec.PKCS8EncodedKeySpec;\nimport java.security.spec.X509EncodedKeySpec;\n\npublic class InstanceIdStore {\n    private static final String TAG = \"InstanceID/Store\";\n    private static final String PREF_NAME = \"com.google.android.gms.appid\";\n\n    private Context context;\n    private SharedPreferences sharedPreferences;\n\n    public InstanceIdStore(Context context) {\n        this.context = context;\n        this.sharedPreferences = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);\n    }\n\n    public synchronized String getString(String key) {\n        return sharedPreferences.getString(key, null);\n    }\n\n    public synchronized long getLong(String key) {\n        return sharedPreferences.getLong(key, -1);\n    }\n\n    public String getSecret(String subtype, String key) {\n        return getString(subtype + \"|S|\" + key);\n    }\n\n    public String getToken(String subtype, String authorizedEntity, String scope) {\n        return getString(subtype + \"|T|\" + authorizedEntity + \"|\" + scope);\n    }\n\n    public long getTokenTimestamp(String subtype, String authorizedEntity, String scope) {\n        return getLong(subtype + \"|T-timestamp|\" + authorizedEntity + \"|\" + scope);\n    }\n\n    public KeyPair getKeyPair(String subtype) {\n        String pub = getSecret(subtype, \"|P|\");\n        String priv = getSecret(subtype, \"|K|\");\n        if (pub == null || priv == null) {\n            return null;\n        }\n        try {\n            byte[] pubKey = Base64.decode(pub, Base64.URL_SAFE);\n            byte[] privKey = Base64.decode(priv, Base64.URL_SAFE);\n            KeyFactory rsaFactory = KeyFactory.getInstance(\"RSA\");\n            return new KeyPair(rsaFactory.generatePublic(new X509EncodedKeySpec(pubKey)), rsaFactory.generatePrivate(new PKCS8EncodedKeySpec(privKey)));\n        } catch (Exception e) {\n            Log.w(TAG, \"Invalid key stored \" + e);\n            return null;\n        }\n    }\n\n    public synchronized void putString(String key, String value) {\n        SharedPreferences.Editor editor = sharedPreferences.edit();\n        editor.putString(key, value);\n        editor.apply();\n    }\n\n    public synchronized void putLong(String key, long value) {\n        SharedPreferences.Editor editor = sharedPreferences.edit();\n        editor.putLong(key, value);\n        editor.apply();\n    }\n\n    public void putSecret(String subtype, String key, String value) {\n        putString(subtype + \"|S|\" + key, value);\n    }\n\n    public void putToken(String subtype, String authorizedEntity, String scope, String token) {\n        putString(subtype + \"|T|\" + authorizedEntity + \"|\" + scope, token);\n        putLong(subtype + \"|T-timestamp|\" + authorizedEntity + \"|\" + scope, System.currentTimeMillis());\n    }\n\n    public synchronized void putKeyPair(String subtype, KeyPair keyPair, long timestamp) {\n        putSecret(subtype, \"|P|\", Base64.encodeToString(keyPair.getPublic().getEncoded(), Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING));\n        putSecret(subtype, \"|K|\", Base64.encodeToString(keyPair.getPrivate().getEncoded(), Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING));\n        putSecret(subtype, \"cre\", Long.toString(timestamp));\n    }\n\n    public synchronized void delete() {\n        SharedPreferences.Editor editor = sharedPreferences.edit();\n        editor.clear();\n        editor.apply();\n    }\n\n    public synchronized void delete(String prefix) {\n        SharedPreferences.Editor editor = sharedPreferences.edit();\n        for (String key : sharedPreferences.getAll().keySet()) {\n            if (key.startsWith(prefix)) {\n                editor.remove(key);\n            }\n        }\n        editor.apply();\n    }\n\n    public synchronized void delete(String subtype, String authorizedEntity, String scope) {\n        SharedPreferences.Editor editor = sharedPreferences.edit();\n        editor.remove(subtype + \"|T|\" + authorizedEntity + \"|\" + scope);\n        editor.remove(subtype + \"|T-timestamp|\" + authorizedEntity + \"|\" + scope);\n        editor.apply();\n    }\n}\n"
  },
  {
    "path": "play-services-location/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2015 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\nandroid {\n    namespace \"com.google.android.gms.location\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n}\n\napply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG implementation of play-services-location'\n\ndependencies {\n    // Dependencies from play-services-location:21.0.1\n    api project(':play-services-base')\n    api project(':play-services-basement')\n    api project(':play-services-tasks')\n\n    annotationProcessor project(':safe-parcel-processor')\n}\n"
  },
  {
    "path": "play-services-location/core/base/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'kotlin-android'\n\ndependencies {\n    api project(':play-services-location')\n    implementation project(':play-services-base-core')\n}\n\nandroid {\n    namespace \"org.microg.gms.location.base\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        buildConfig = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n        def onlineSourcesString = \"\"\n        if (localProperties.get(\"location.online-sources\", \"\") != \"\") {\n            onlineSourcesString = localProperties.get(\"location.online-sources\", \"[]\")\n        } else if (localProperties.get(\"ichnaea.endpoint\", \"\") != \"\") {\n            onlineSourcesString = \"[{\\\"id\\\": \\\"default\\\", \\\"url\\\": \\\"${localProperties.get(\"ichnaea.endpoint\", \"\")}\\\"},{\\\"id\\\": \\\"custom\\\", \\\"import\\\": true}]\"\n        } else {\n            onlineSourcesString = \"[{\\\"id\\\": \\\"beacondb\\\", \\\"name\\\": \\\"BeaconDB\\\", \\\"url\\\": \\\"https://api.beacondb.net/\\\", \\\"host\\\": \\\"beacondb.net\\\", \\\"terms\\\": \\\"https://beacondb.net/privacy/\\\", \\\"import\\\": true, \\\"allowContribute\\\": true},{\\\"id\\\": \\\"custom\\\", \\\"import\\\": true}]\"\n        }\n        buildConfigField \"java.util.List<org.microg.gms.location.network.OnlineSource>\", \"ONLINE_SOURCES\", \"org.microg.gms.location.network.OnlineSourceKt.parseOnlineSources(\\\"${onlineSourcesString.replaceAll(\"\\\"\", \"\\\\\\\\\\\"\")}\\\")\"\n    }\n\n    sourceSets {\n        main.java.srcDirs += 'src/main/kotlin'\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n\n    kotlinOptions {\n        jvmTarget = 1.8\n    }\n}\n"
  },
  {
    "path": "play-services-location/core/base/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest />\n"
  },
  {
    "path": "play-services-location/core/base/src/main/kotlin/org/microg/gms/location/LocationSettings.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location\n\nimport android.content.ContentValues\nimport android.content.Context\nimport android.database.Cursor\nimport org.microg.gms.location.base.BuildConfig\nimport org.microg.gms.settings.SettingsContract\n\nprivate const val PATH_GEOLOCATE = \"/v1/geolocate\"\nprivate const val PATH_GEOLOCATE_QUERY = \"/v1/geolocate?\"\nprivate const val PATH_GEOSUBMIT = \"/v2/geosubmit\"\nprivate const val PATH_GEOSUBMIT_QUERY = \"/v2/geosubmit?\"\nprivate const val PATH_QUERY_ONLY = \"/?\"\n\nclass LocationSettings(private val context: Context) {\n    private fun <T> getSettings(vararg projection: String, f: (Cursor) -> T): T =\n        SettingsContract.getSettings(context, SettingsContract.Location.getContentUri(context), projection, f)\n\n    private fun setSettings(v: ContentValues.() -> Unit) = SettingsContract.setSettings(context, SettingsContract.Location.getContentUri(context), v)\n\n    var wifiIchnaea: Boolean\n        get() = getSettings(SettingsContract.Location.WIFI_ICHNAEA) { c -> c.getInt(0) != 0 }\n        set(value) = setSettings { put(SettingsContract.Location.WIFI_ICHNAEA, value) }\n\n    var wifiMoving: Boolean\n        get() = getSettings(SettingsContract.Location.WIFI_MOVING) { c -> c.getInt(0) != 0 }\n        set(value) = setSettings { put(SettingsContract.Location.WIFI_MOVING, value) }\n\n    var wifiLearning: Boolean\n        get() = getSettings(SettingsContract.Location.WIFI_LEARNING) { c -> c.getInt(0) != 0 }\n        set(value) = setSettings { put(SettingsContract.Location.WIFI_LEARNING, value) }\n\n    var wifiCaching: Boolean\n        get() = getSettings(SettingsContract.Location.WIFI_CACHING) { c -> c.getInt(0) != 0 }\n        set(value) = setSettings { put(SettingsContract.Location.WIFI_CACHING, value) }\n\n    var cellIchnaea: Boolean\n        get() = getSettings(SettingsContract.Location.CELL_ICHNAEA) { c -> c.getInt(0) != 0 }\n        set(value) = setSettings { put(SettingsContract.Location.CELL_ICHNAEA, value) }\n\n    var cellLearning: Boolean\n        get() = getSettings(SettingsContract.Location.CELL_LEARNING) { c -> c.getInt(0) != 0 }\n        set(value) = setSettings { put(SettingsContract.Location.CELL_LEARNING, value) }\n\n    var cellCaching: Boolean\n        get() = getSettings(SettingsContract.Location.CELL_CACHING) { c -> c.getInt(0) != 0 }\n        set(value) = setSettings { put(SettingsContract.Location.CELL_CACHING, value) }\n\n    var geocoderNominatim: Boolean\n        get() = getSettings(SettingsContract.Location.GEOCODER_NOMINATIM) { c -> c.getInt(0) != 0 }\n        set(value) = setSettings { put(SettingsContract.Location.GEOCODER_NOMINATIM, value) }\n\n    var customEndpoint: String?\n        get() {\n            try {\n                var endpoint = getSettings(SettingsContract.Location.ICHNAEA_ENDPOINT) { c -> c.getString(0) }\n                // This is only temporary as users might have already broken configuration.\n                // Usually this would be corrected before storing it in settings, see below.\n                if (endpoint.endsWith(PATH_GEOLOCATE)) {\n                    endpoint = endpoint.substring(0, endpoint.length - PATH_GEOLOCATE.length + 1)\n                } else if (endpoint.contains(PATH_GEOLOCATE_QUERY)) {\n                    endpoint = endpoint.replace(PATH_GEOLOCATE_QUERY, PATH_QUERY_ONLY)\n                } else if (endpoint.endsWith(PATH_GEOSUBMIT)) {\n                    endpoint = endpoint.substring(0, endpoint.length - PATH_GEOSUBMIT.length + 1)\n                } else if (endpoint.contains(PATH_GEOSUBMIT_QUERY)) {\n                    endpoint = endpoint.replace(PATH_GEOSUBMIT_QUERY, PATH_QUERY_ONLY)\n                }\n                return endpoint\n            } catch (e: Exception) {\n                return null\n            }\n        }\n        set(value) {\n            val endpoint = if (value == null) {\n                null\n            } else if (value.endsWith(PATH_GEOLOCATE)) {\n                value.substring(0, value.length - PATH_GEOLOCATE.length + 1)\n            } else if (value.contains(PATH_GEOLOCATE_QUERY)) {\n                value.replace(PATH_GEOLOCATE_QUERY, PATH_QUERY_ONLY)\n            } else if (value.endsWith(PATH_GEOSUBMIT)) {\n                value.substring(0, value.length - PATH_GEOSUBMIT.length + 1)\n            } else if (value.contains(PATH_GEOSUBMIT_QUERY)) {\n                value.replace(PATH_GEOSUBMIT_QUERY, PATH_QUERY_ONLY)\n            } else {\n                value\n            }\n            setSettings { put(SettingsContract.Location.ICHNAEA_ENDPOINT, endpoint) }\n        }\n\n    var onlineSourceId: String?\n        get() = getSettings(SettingsContract.Location.ONLINE_SOURCE) { c -> c.getString(0) }\n        set(value) = setSettings { put(SettingsContract.Location.ONLINE_SOURCE, value) }\n\n    var ichnaeaContribute: Boolean\n        get() = getSettings(SettingsContract.Location.ICHNAEA_CONTRIBUTE) { c -> c.getInt(0) != 0 }\n        set(value) = setSettings { put(SettingsContract.Location.ICHNAEA_CONTRIBUTE, value) }\n}"
  },
  {
    "path": "play-services-location/core/base/src/main/kotlin/org/microg/gms/location/extensions.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location\n\nimport android.content.Context\nimport android.content.Intent\nimport android.content.pm.PackageManager\nimport android.location.Location\nimport android.os.SystemClock\nimport android.text.format.DateUtils\nimport androidx.core.location.LocationCompat\n\nconst val ACTION_NETWORK_LOCATION_SERVICE = \"org.microg.gms.location.network.ACTION_NETWORK_LOCATION_SERVICE\"\nconst val EXTRA_LOCATION = \"location\"\nconst val EXTRA_ELAPSED_REALTIME = \"elapsed_realtime\"\nconst val EXTRA_PENDING_INTENT = \"pending_intent\"\nconst val EXTRA_ENABLE = \"enable\"\nconst val EXTRA_INTERVAL_MILLIS = \"interval\"\nconst val EXTRA_FORCE_NOW = \"force_now\"\nconst val EXTRA_LOW_POWER = \"low_power\"\nconst val EXTRA_WORK_SOURCE = \"work_source\"\nconst val EXTRA_BYPASS = \"bypass\"\n\nconst val ACTION_CONFIGURATION_REQUIRED = \"org.microg.gms.location.network.ACTION_CONFIGURATION_REQUIRED\"\nconst val EXTRA_CONFIGURATION = \"config\"\nconst val CONFIGURATION_FIELD_ONLINE_SOURCE = \"online_source\"\n\nconst val ACTION_NETWORK_IMPORT_EXPORT = \"org.microg.gms.location.network.ACTION_NETWORK_IMPORT_EXPORT\"\nconst val EXTRA_DIRECTION = \"direction\"\nconst val DIRECTION_IMPORT = \"import\"\nconst val DIRECTION_EXPORT = \"export\"\nconst val EXTRA_NAME = \"name\"\nconst val NAME_WIFI = \"wifi\"\nconst val NAME_CELL = \"cell\"\nconst val EXTRA_URI = \"uri\"\nconst val EXTRA_MESSENGER = \"messenger\"\nconst val EXTRA_REPLY_WHAT = \"what\"\n\nval Location.elapsedMillis: Long\n    get() = LocationCompat.getElapsedRealtimeMillis(this)\n\nfun Long.formatRealtime(): CharSequence = if (this <= 0) \"n/a\" else DateUtils.getRelativeTimeSpanString((this - SystemClock.elapsedRealtime()) + System.currentTimeMillis(), System.currentTimeMillis(), 0)\nfun Long.formatDuration(): CharSequence {\n    if (this == 0L) return \"0ms\"\n    if (this > 315360000000L /* ten years */) return \"\\u221e\"\n    val interval = listOf(1000, 60, 60, 24, Long.MAX_VALUE)\n    val intervalName = listOf(\"ms\", \"s\", \"m\", \"h\", \"d\")\n    var ret = \"\"\n    var rem = this\n    for (i in 0 until interval.size) {\n        val mod = rem % interval[i]\n        if (mod != 0L) {\n            ret = \"$mod${intervalName[i]}$ret\"\n        }\n        rem /= interval[i]\n        if (mod == 0L && rem == 1L) {\n            ret = \"${interval[i]}${intervalName[i]}$ret\"\n            break\n        } else if (rem == 0L) {\n            break\n        }\n    }\n    return ret\n}\n\nprivate var hasNetworkLocationServiceBuiltInFlag: Boolean? = null\nfun Context.hasNetworkLocationServiceBuiltIn(): Boolean {\n    var flag = hasNetworkLocationServiceBuiltInFlag\n    if (flag == null) {\n        try {\n            val serviceIntent = Intent().apply {\n                action = ACTION_NETWORK_LOCATION_SERVICE\n                setPackage(packageName)\n            }\n            val services = packageManager?.queryIntentServices(serviceIntent, PackageManager.MATCH_DEFAULT_ONLY)\n            flag = services?.isNotEmpty() ?: false\n            hasNetworkLocationServiceBuiltInFlag = flag\n            return flag\n        } catch (e: Exception) {\n            hasNetworkLocationServiceBuiltInFlag = false\n            return false\n        }\n    } else {\n        return flag\n    }\n}"
  },
  {
    "path": "play-services-location/core/base/src/main/kotlin/org/microg/gms/location/network/OnlineSource.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.network\n\nimport android.net.Uri\nimport android.util.Log\nimport org.json.JSONArray\nimport org.json.JSONObject\nimport org.microg.gms.location.LocationSettings\nimport org.microg.gms.location.base.BuildConfig\n\nfun parseOnlineSources(string: String): List<OnlineSource> = JSONArray(string).let { array ->\n    (0 until array.length()).map { parseOnlineSource(array.getJSONObject(it)) }.also { Log.d(\"Location\", \"parseOnlineSources: ${it.joinToString()}\") }\n}\n\nfun parseOnlineSource(json: JSONObject): OnlineSource {\n    val id = json.getString(\"id\")\n    val url = json.optString(\"url\").takeIf { it.isNotBlank() }\n    val host = json.optString(\"host\").takeIf { it.isNotBlank() } ?: runCatching { Uri.parse(url).host }.getOrNull()\n    val name = json.optString(\"name\").takeIf { it.isNotBlank() } ?: host\n    return OnlineSource(\n        id = id,\n        name = name,\n        url = url,\n        host = host,\n        terms = json.optString(\"terms\").takeIf { it.isNotBlank() }?.let { runCatching { Uri.parse(it) }.getOrNull() },\n        suggested = json.optBoolean(\"suggested\", false),\n        import = json.optBoolean(\"import\", false),\n        allowContribute = json.optBoolean(\"allowContribute\", false),\n    )\n}\n\ndata class OnlineSource(\n    val id: String,\n    val name: String? = null,\n    val url: String? = null,\n    val host: String? = null,\n    val terms: Uri? = null,\n    /**\n     * Show suggested flag\n     */\n    val suggested: Boolean = false,\n    /**\n     * If set, automatically import from custom URL if host matches (is the same domain suffix)\n     */\n    val import: Boolean = false,\n    val allowContribute: Boolean = false,\n) {\n    companion object {\n        /**\n         * Entry to allow configuring a custom URL\n         */\n        val ID_CUSTOM = \"custom\"\n\n        /**\n         * Legacy compatibility\n         */\n        val ID_DEFAULT = \"default\"\n\n        val ALL: List<OnlineSource> = BuildConfig.ONLINE_SOURCES\n    }\n}\n\nval LocationSettings.onlineSource: OnlineSource?\n    get() {\n        val id = onlineSourceId\n        if (id != null) {\n            val source = OnlineSource.ALL.firstOrNull { it.id == id }\n            if (source != null) return source\n        }\n        val endpoint = customEndpoint\n        if (endpoint != null) {\n            val endpointHostSuffix = runCatching { \".\" + Uri.parse(endpoint).host }.getOrNull()\n            if (endpointHostSuffix != null) {\n                for (source in OnlineSource.ALL) {\n                    if (source.import && endpointHostSuffix.endsWith(\".\" + source.host)) {\n                        return source\n                    }\n                }\n            }\n            val customSource = OnlineSource.ALL.firstOrNull { it.id == OnlineSource.ID_CUSTOM }\n            if (customSource != null && customSource.import) {\n                return customSource\n            }\n        }\n        if (OnlineSource.ALL.size == 1) return OnlineSource.ALL.single()\n        return OnlineSource.ALL.firstOrNull { it.id == OnlineSource.ID_DEFAULT }\n    }\n\nval LocationSettings.effectiveEndpoint: String?\n    get() {\n        val source = onlineSource ?: return null\n        if (source.id == OnlineSource.ID_CUSTOM) return customEndpoint\n        return source.url\n    }"
  },
  {
    "path": "play-services-location/core/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'kotlin-android'\n\ndependencies {\n    api project(':play-services-location')\n    implementation project(':play-services-base-core')\n    implementation project(':play-services-location-core-base')\n\n    implementation \"androidx.core:core-ktx:$coreVersion\"\n    implementation \"androidx.lifecycle:lifecycle-service:$lifecycleVersion\"\n    implementation \"androidx.lifecycle:lifecycle-runtime-ktx:$lifecycleVersion\"\n    implementation \"androidx.navigation:navigation-fragment-ktx:$navigationVersion\"\n    implementation \"androidx.navigation:navigation-ui-ktx:$navigationVersion\"\n    implementation \"androidx.preference:preference-ktx:$preferenceVersion\"\n\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion\"\n    implementation \"org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutineVersion\"\n    implementation \"org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutineVersion\"\n\n    implementation \"com.android.volley:volley:$volleyVersion\"\n\n    compileOnly project(':play-services-maps')\n}\n\nandroid {\n    namespace \"org.microg.gms.location.core\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        buildConfig = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n        buildConfigField \"String\", \"FORCE_SHOW_BACKGROUND_PERMISSION\", \"\\\"\\\"\"\n        buildConfigField \"boolean\", \"SHOW_NOTIFICATION_WHEN_NOT_PERMITTED\", \"false\"\n    }\n\n    lintOptions {\n        disable 'MissingTranslation', 'GetLocales'\n    }\n\n    flavorDimensions = ['target']\n    productFlavors {\n        \"default\" {\n            dimension 'target'\n        }\n        \"huawei\" {\n            dimension 'target'\n            buildConfigField \"String\", \"FORCE_SHOW_BACKGROUND_PERMISSION\", \"\\\"com.huawei.permission.sec.MDM.v2\\\"\"\n            buildConfigField \"boolean\", \"SHOW_NOTIFICATION_WHEN_NOT_PERMITTED\", \"true\"\n        }\n        \"huaweilh\" {\n            dimension 'target'\n            buildConfigField \"String\", \"FORCE_SHOW_BACKGROUND_PERMISSION\", \"\\\"com.huawei.permission.sec.MDM.v2\\\"\"\n            buildConfigField \"boolean\", \"SHOW_NOTIFICATION_WHEN_NOT_PERMITTED\", \"true\"\n        }\n    }\n\n    sourceSets {\n        main.java.srcDirs += 'src/main/kotlin'\n        huawei.java.srcDirs += 'src/huawei/kotlin'\n        huaweilh.java.srcDirs += huawei.java.srcDirs\n        huaweilh.res.srcDirs += huawei.res.srcDirs\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n\n    kotlinOptions {\n        jvmTarget = 1.8\n    }\n}\n"
  },
  {
    "path": "play-services-location/core/provider/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'kotlin-android'\n\ndependencies {\n    api project(':play-services-location')\n    compileOnly project(':play-services-location-core-system-api')\n    implementation project(':play-services-base-core')\n    implementation project(':play-services-location-core-base')\n\n    implementation \"androidx.appcompat:appcompat:$appcompatVersion\"\n    implementation \"androidx.core:core-ktx:$coreVersion\"\n    implementation \"androidx.lifecycle:lifecycle-service:$lifecycleVersion\"\n    implementation \"androidx.lifecycle:lifecycle-runtime-ktx:$lifecycleVersion\"\n\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion\"\n    implementation \"org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutineVersion\"\n    implementation \"org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutineVersion\"\n\n    implementation \"com.android.volley:volley:$volleyVersion\"\n\n    implementation 'org.microg:address-formatter:0.3.1'\n}\n\nandroid {\n    namespace \"org.microg.gms.location.provider\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        buildConfig = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n        buildConfigField \"String\", \"ICHNAEA_USER_AGENT\", \"\\\"microG/${version}\\\"\"\n    }\n\n    sourceSets {\n        main.java.srcDirs += 'src/main/kotlin'\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n\n    kotlinOptions {\n        jvmTarget = 1.8\n    }\n}\n"
  },
  {
    "path": "play-services-location/core/provider/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest xmlns:tools=\"http://schemas.android.com/tools\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\" />\n    <uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\" />\n    <uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />\n    <uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\" />\n    <uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\" />\n    <uses-permission android:name=\"android.permission.BODY_SENSORS\" />\n\n    <uses-permission\n        android:name=\"android.permission.LOCATION_HARDWARE\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.INSTALL_LOCATION_PROVIDER\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.NETWORK_SCAN\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.MODIFY_PHONE_STATE\"\n        tools:ignore=\"ProtectedPermissions\" />\n\n    <application>\n        <uses-library android:name=\"com.android.location.provider\" />\n\n        <service\n            android:name=\"org.microg.gms.location.network.NetworkLocationService\"\n            android:exported=\"false\">\n            <intent-filter>\n                <action android:name=\"org.microg.gms.location.network.ACTION_NETWORK_LOCATION_SERVICE\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"org.microg.gms.location.network.ACTION_NETWORK_IMPORT_EXPORT\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </service>\n        <provider\n            android:name=\"org.microg.gms.location.network.DatabaseExportFileProvider\"\n            android:authorities=\"${applicationId}.microg.location.export\"\n            android:exported=\"false\"\n            android:grantUriPermissions=\"true\">\n            <meta-data\n                android:name=\"android.support.FILE_PROVIDER_PATHS\"\n                android:resource=\"@xml/location_exported_files\" />\n        </provider>\n        <service\n            android:name=\"org.microg.gms.location.provider.NetworkLocationProviderService\"\n            android:exported=\"true\"\n            android:permission=\"android.permission.WRITE_SECURE_SETTINGS\">\n            <intent-filter>\n                <action android:name=\"com.android.location.service.v2.NetworkLocationProvider\" />\n                <action android:name=\"com.android.location.service.v3.NetworkLocationProvider\" />\n            </intent-filter>\n            <meta-data\n                android:name=\"serviceVersion\"\n                android:value=\"2\" />\n        </service>\n        <service\n            android:name=\"org.microg.gms.location.provider.FusedLocationProviderService\"\n            android:exported=\"true\"\n            android:permission=\"android.permission.WRITE_SECURE_SETTINGS\">\n            <intent-filter>\n                <action android:name=\"com.android.location.service.FusedLocationProvider\" />\n            </intent-filter>\n            <meta-data\n                android:name=\"serviceVersion\"\n                android:value=\"2\" />\n        </service>\n        <service\n            android:name=\"org.microg.gms.location.provider.GeocodeProviderService\"\n            android:exported=\"true\"\n            android:permission=\"android.permission.WRITE_SECURE_SETTINGS\">\n            <intent-filter>\n                <action android:name=\"com.android.location.service.GeocodeProvider\" />\n                <action android:name=\"com.google.android.location.GeocodeProvider\" />\n            </intent-filter>\n            <meta-data\n                android:name=\"serviceVersion\"\n                android:value=\"2\" />\n        </service>\n    </application>\n</manifest>\n"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/network/DatabaseExportFileProvider.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.network\n\nimport android.net.Uri\nimport androidx.core.content.FileProvider\n\nclass DatabaseExportFileProvider : FileProvider() {\n    override fun getType(uri: Uri): String? {\n        try {\n            if (uri.lastPathSegment?.startsWith(\"cell-\") == true) {\n                return \"application/vnd.microg.location.cell+csv+gzip\"\n            }\n            if (uri.lastPathSegment?.startsWith(\"wifi-\") == true) {\n                return \"application/vnd.microg.location.wifi+csv+gzip\"\n            }\n        } catch (ignored: Exception) {}\n        return super.getType(uri)\n    }\n}"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/network/LocationDatabase.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.network\n\nimport android.content.ContentValues\nimport android.content.Context\nimport android.database.Cursor\nimport android.database.DatabaseUtils\nimport android.database.sqlite.SQLiteDatabase\nimport android.database.sqlite.SQLiteException\nimport android.database.sqlite.SQLiteOpenHelper\nimport android.location.Location\nimport android.net.Uri\nimport android.os.ParcelFileDescriptor\nimport android.util.Log\nimport androidx.core.content.FileProvider\nimport androidx.core.content.contentValuesOf\nimport androidx.core.database.getDoubleOrNull\nimport androidx.core.database.getStringOrNull\nimport androidx.core.os.BundleCompat\nimport org.microg.gms.location.NAME_CELL\nimport org.microg.gms.location.NAME_WIFI\nimport org.microg.gms.location.network.cell.CellDetails\nimport org.microg.gms.location.network.cell.isValid\nimport org.microg.gms.location.network.wifi.WifiDetails\nimport org.microg.gms.location.network.wifi.isRequestable\nimport org.microg.gms.location.network.wifi.macBytes\nimport org.microg.gms.utils.toHexString\nimport java.io.File\nimport java.io.FileNotFoundException\nimport java.io.PrintWriter\nimport java.util.*\nimport java.util.zip.GZIPInputStream\nimport java.util.zip.GZIPOutputStream\nimport kotlin.math.abs\nimport kotlin.math.max\nimport kotlin.math.min\n\nprivate const val CURRENT_VERSION = 8\n\ninternal class LocationDatabase(private val context: Context) : SQLiteOpenHelper(context, \"geocache.db\", null, CURRENT_VERSION) {\n    private data class Migration(val apply: String?, val revert: String?, val allowApplyFailure: Boolean, val allowRevertFailure: Boolean)\n    private val migrations: Map<Int, List<Migration>>\n\n    init {\n        val migrations = mutableMapOf<Int, MutableList<Migration>>()\n        fun declare(version: Int, apply: String, revert: String? = null, allowFailure: Boolean = false, allowApplyFailure: Boolean = allowFailure, allowRevertFailure: Boolean = allowFailure) {\n            if (!migrations.containsKey(version))\n                migrations[version] = arrayListOf()\n            migrations[version]!!.add(Migration(apply, revert, allowApplyFailure, allowRevertFailure))\n        }\n\n        declare(3, \"CREATE TABLE $TABLE_CELLS($FIELD_MCC INTEGER NOT NULL, $FIELD_MNC INTEGER NOT NULL, $FIELD_TYPE INTEGER NOT NULL, $FIELD_LAC_TAC INTEGER NOT NULL, $FIELD_CID INTEGER NOT NULL, $FIELD_PSC INTEGER NOT NULL, $FIELD_LATITUDE REAL NOT NULL, $FIELD_LONGITUDE REAL NOT NULL, $FIELD_ACCURACY REAL NOT NULL, $FIELD_TIME INTEGER NOT NULL, $FIELD_PRECISION REAL NOT NULL);\")\n        declare(3, \"CREATE TABLE $TABLE_CELLS_PRE($FIELD_MCC INTEGER NOT NULL, $FIELD_MNC INTEGER NOT NULL, $FIELD_TIME INTEGER NOT NULL);\")\n        declare(3, \"CREATE TABLE $TABLE_WIFIS($FIELD_MAC BLOB, $FIELD_LATITUDE REAL NOT NULL, $FIELD_LONGITUDE REAL NOT NULL, $FIELD_ACCURACY REAL NOT NULL, $FIELD_TIME INTEGER NOT NULL, $FIELD_PRECISION REAL NOT NULL);\")\n        declare(3, \"CREATE TABLE $TABLE_CELLS_LEARN($FIELD_MCC INTEGER NOT NULL, $FIELD_MNC INTEGER NOT NULL, $FIELD_TYPE INTEGER NOT NULL, $FIELD_LAC_TAC INTEGER NOT NULL, $FIELD_CID INTEGER NOT NULL, $FIELD_PSC INTEGER NOT NULL, $FIELD_LATITUDE_HIGH REAL NOT NULL, $FIELD_LATITUDE_LOW REAL NOT NULL, $FIELD_LONGITUDE_HIGH REAL NOT NULL, $FIELD_LONGITUDE_LOW REAL NOT NULL, $FIELD_TIME INTEGER NOT NULL, $FIELD_BAD_TIME INTEGER);\")\n        declare(3, \"CREATE TABLE $TABLE_WIFI_LEARN($FIELD_MAC BLOB, $FIELD_LATITUDE_HIGH REAL NOT NULL, $FIELD_LATITUDE_LOW REAL NOT NULL, $FIELD_LONGITUDE_HIGH REAL NOT NULL, $FIELD_LONGITUDE_LOW REAL NOT NULL, $FIELD_TIME INTEGER NOT NULL, $FIELD_BAD_TIME INTEGER);\")\n        declare(3, \"CREATE UNIQUE INDEX ${TABLE_CELLS}_index ON $TABLE_CELLS($FIELD_MCC, $FIELD_MNC, $FIELD_TYPE, $FIELD_LAC_TAC, $FIELD_CID, $FIELD_PSC);\")\n        declare(3, \"CREATE UNIQUE INDEX ${TABLE_CELLS_PRE}_index ON $TABLE_CELLS_PRE($FIELD_MCC, $FIELD_MNC);\")\n        declare(3, \"CREATE UNIQUE INDEX ${TABLE_WIFIS}_index ON $TABLE_WIFIS($FIELD_MAC);\")\n        declare(3, \"CREATE UNIQUE INDEX ${TABLE_CELLS_LEARN}_index ON $TABLE_CELLS_LEARN($FIELD_MCC, $FIELD_MNC, $FIELD_TYPE, $FIELD_LAC_TAC, $FIELD_CID, $FIELD_PSC);\")\n        declare(3, \"CREATE UNIQUE INDEX ${TABLE_WIFI_LEARN}_index ON $TABLE_WIFI_LEARN($FIELD_MAC);\")\n        declare(3, \"CREATE INDEX ${TABLE_CELLS}_time_index ON $TABLE_CELLS($FIELD_TIME);\")\n        declare(3, \"CREATE INDEX ${TABLE_CELLS_PRE}_time_index ON $TABLE_CELLS_PRE($FIELD_TIME);\")\n        declare(3, \"CREATE INDEX ${TABLE_WIFIS}_time_index ON $TABLE_WIFIS($FIELD_TIME);\")\n        declare(3, \"CREATE INDEX ${TABLE_CELLS_LEARN}_time_index ON $TABLE_CELLS_LEARN($FIELD_TIME);\")\n        declare(3, \"CREATE INDEX ${TABLE_WIFI_LEARN}_time_index ON $TABLE_WIFI_LEARN($FIELD_TIME);\")\n        declare(3, \"DROP TABLE IF EXISTS $TABLE_WIFI_SCANS;\", allowFailure = true)\n\n        declare(4, \"ALTER TABLE $TABLE_CELLS_LEARN ADD COLUMN $FIELD_LEARN_RECORD_COUNT INTEGER;\")\n        declare(4, \"ALTER TABLE $TABLE_WIFI_LEARN ADD COLUMN $FIELD_LEARN_RECORD_COUNT INTEGER;\")\n\n        declare(5, \"ALTER TABLE $TABLE_CELLS ADD COLUMN $FIELD_ALTITUDE REAL;\")\n        declare(5, \"ALTER TABLE $TABLE_CELLS ADD COLUMN $FIELD_ALTITUDE_ACCURACY REAL;\")\n        declare(5, \"ALTER TABLE $TABLE_WIFIS ADD COLUMN $FIELD_ALTITUDE REAL;\")\n        declare(5, \"ALTER TABLE $TABLE_WIFIS ADD COLUMN $FIELD_ALTITUDE_ACCURACY REAL;\")\n\n        declare(6, \"ALTER TABLE $TABLE_CELLS_LEARN ADD COLUMN $FIELD_ALTITUDE_HIGH REAL;\")\n        declare(6, \"ALTER TABLE $TABLE_CELLS_LEARN ADD COLUMN $FIELD_ALTITUDE_LOW REAL;\")\n        declare(6, \"ALTER TABLE $TABLE_WIFI_LEARN ADD COLUMN $FIELD_ALTITUDE_HIGH REAL;\")\n        declare(6, \"ALTER TABLE $TABLE_WIFI_LEARN ADD COLUMN $FIELD_ALTITUDE_LOW REAL;\")\n\n        declare(8, \"DELETE FROM $TABLE_WIFIS WHERE $FIELD_ACCURACY = 0.0 AND ($FIELD_LATITUDE != 0.0 OR $FIELD_LONGITUDE != 0.0);\", allowRevertFailure = true)\n        declare(8, \"DELETE FROM $TABLE_CELLS WHERE $FIELD_ACCURACY = 0.0 AND ($FIELD_LATITUDE != 0.0 OR $FIELD_LONGITUDE != 0.0);\", allowRevertFailure = true)\n        declare(8, \"UPDATE $TABLE_CELLS_LEARN SET $FIELD_ALTITUDE_LOW = NULL WHERE $FIELD_ALTITUDE_LOW = 0.0;\", allowRevertFailure = true)\n        declare(8, \"UPDATE $TABLE_CELLS_LEARN SET $FIELD_ALTITUDE_HIGH = NULL WHERE $FIELD_ALTITUDE_HIGH = 0.0;\", allowRevertFailure = true)\n        declare(8, \"UPDATE $TABLE_WIFI_LEARN SET $FIELD_ALTITUDE_LOW = NULL WHERE $FIELD_ALTITUDE_LOW = 0.0;\", allowRevertFailure = true)\n        declare(8, \"UPDATE $TABLE_WIFI_LEARN SET $FIELD_ALTITUDE_HIGH = NULL WHERE $FIELD_ALTITUDE_HIGH = 0.0;\", allowRevertFailure = true)\n\n        this.migrations = migrations\n    }\n\n    private fun migrate(db: SQLiteDatabase, oldVersion: Int, newVersion: Int, allowFailure: Boolean = false) {\n        var currentVersion = oldVersion\n        while (currentVersion < newVersion) {\n            val nextVersion = currentVersion + 1\n            val migrations = this.migrations[nextVersion].orEmpty()\n            for (migration in migrations) {\n                if (migration.apply == null && !migration.allowApplyFailure && !allowFailure)\n                    throw SQLiteException(\"Incomplete migration from $currentVersion to $nextVersion\")\n                try {\n                    db.execSQL(migration.apply)\n                    Log.d(TAG, \"Applied migration from version $currentVersion to $nextVersion: ${migration.apply}\")\n                } catch (e: Exception) {\n                    Log.w(TAG, \"Error while applying migration from version $currentVersion to $nextVersion: ${migration.apply}\", e)\n                    if (!migration.allowApplyFailure && !allowFailure)\n                        throw e\n                }\n            }\n\n            currentVersion = nextVersion\n        }\n        while (currentVersion > newVersion) {\n            val nextVersion = currentVersion - 1\n            val migrations = this.migrations[currentVersion].orEmpty()\n            for (migration in migrations.asReversed()) {\n                if (migration.revert == null && !migration.allowRevertFailure && !allowFailure)\n                    throw SQLiteException(\"Incomplete migration from $currentVersion to $nextVersion\")\n                try {\n                    db.execSQL(migration.revert)\n                    Log.d(TAG, \"Reverted migration from version $currentVersion to $nextVersion: ${migration.revert}\")\n                } catch (e: Exception) {\n                    Log.w(TAG, \"Error while reverting migration from version $currentVersion to $nextVersion: ${migration.revert}\", e)\n                    if (!migration.allowRevertFailure && !allowFailure)\n                        throw e\n                }\n            }\n\n            currentVersion = nextVersion\n        }\n        Log.i(TAG, \"Migrated from $oldVersion to $newVersion\")\n    }\n\n    private fun SQLiteDatabase.query(table: String, columns: Array<String>, selection: String? = null, selectionArgs: Array<String>? = null) =\n        query(table, columns, selection, selectionArgs, null, null, null)\n\n    fun getCellLocation(cell: CellDetails, allowLearned: Boolean = true): Location? {\n        var cursor = readableDatabase.query(TABLE_CELLS, FIELDS_CACHE_LOCATION, CELLS_SELECTION, getCellSelectionArgs(cell))\n        val cellLocation = cursor.getSingleLocation(MAX_CACHE_AGE)\n        if (allowLearned) {\n            cursor = readableDatabase.query(TABLE_CELLS_LEARN, FIELDS_MID_LOCATION_GET_LEARN, CELLS_SELECTION, getCellSelectionArgs(cell))\n            try {\n                if (cursor.moveToNext()) {\n                    val badTime = cursor.getLong(8)\n                    val time = cursor.getLong(7)\n                    if (badTime < time - LEARN_BAD_CUTOFF) {\n                        cursor.getCellMidLocation()?.let {\n                            if (cellLocation == null || cellLocation == NEGATIVE_CACHE_ENTRY || cellLocation.precision < it.precision) return it\n                        }\n                    }\n                }\n            } finally {\n                cursor.close()\n            }\n        }\n        if (cellLocation != null) return cellLocation\n        cursor = readableDatabase.query(TABLE_CELLS_PRE, arrayOf(FIELD_TIME), CELLS_PRE_SELECTION, getCellPreSelectionArgs(cell))\n        try {\n            if (cursor.moveToNext()) {\n                if (cursor.getLong(1) > System.currentTimeMillis() - MAX_CACHE_AGE) {\n                    return NEGATIVE_CACHE_ENTRY\n                }\n            }\n        } finally {\n            cursor.close()\n        }\n        return null\n    }\n\n    fun getWifiLocation(wifi: WifiDetails, allowLearned: Boolean = true): Location? {\n        var cursor = readableDatabase.query(TABLE_WIFIS, FIELDS_CACHE_LOCATION, getWifiSelection(wifi))\n        val wifiLocation = cursor.getSingleLocation(MAX_CACHE_AGE)\n        if (allowLearned) {\n            cursor = readableDatabase.query(TABLE_WIFI_LEARN, FIELDS_MID_LOCATION_GET_LEARN, getWifiSelection(wifi))\n            try {\n                if (cursor.moveToNext()) {\n                    val badTime = cursor.getLong(8)\n                    val time = cursor.getLong(7)\n                    if (badTime < time - LEARN_BAD_CUTOFF) {\n                        cursor.getWifiMidLocation()?.let {\n                            if (wifiLocation == null || wifiLocation == NEGATIVE_CACHE_ENTRY || wifiLocation.precision < it.precision) return it\n                        }\n                    }\n                }\n            } finally {\n                cursor.close()\n            }\n        }\n        return wifiLocation\n    }\n\n    fun putCellLocation(cell: CellDetails, location: Location) {\n        if (!cell.isValid) return\n        val cv = contentValuesOf(\n            FIELD_MCC to cell.mcc,\n            FIELD_MNC to cell.mnc,\n            FIELD_LAC_TAC to (cell.lac ?: cell.tac ?: 0),\n            FIELD_TYPE to cell.type.ordinal,\n            FIELD_CID to cell.cid,\n            FIELD_PSC to (cell.pscOrPci ?: 0)\n        ).apply { putLocation(location) }\n        writableDatabase.insertWithOnConflict(TABLE_CELLS, null, cv, SQLiteDatabase.CONFLICT_REPLACE)\n    }\n\n    fun putWifiLocation(wifi: WifiDetails, location: Location) {\n        if (!wifi.isRequestable) return\n        val cv = contentValuesOf(\n            FIELD_MAC to wifi.macBytes\n        ).apply { putLocation(location) }\n        writableDatabase.insertWithOnConflict(TABLE_WIFIS, null, cv, SQLiteDatabase.CONFLICT_REPLACE)\n    }\n\n    fun learnCellLocation(cell: CellDetails, location: Location, import: Boolean = false): Boolean {\n        if (!cell.isValid) return false\n        val cursor = readableDatabase.query(TABLE_CELLS_LEARN, FIELDS_MID_LOCATION, CELLS_SELECTION, getCellSelectionArgs(cell))\n        var exists = false\n        var isBad = false\n        var midLocation: Location? = null\n        try {\n            if (cursor.moveToNext()) {\n                midLocation = cursor.getMidLocation()\n                exists = midLocation != null\n                isBad = midLocation?.let { it.distanceTo(location) > LEARN_BAD_SIZE_CELL } == true\n            }\n        } finally {\n            cursor.close()\n        }\n        if (exists && isBad) {\n            val values = ContentValues().apply { putLearnLocation(location, badTime = location.time, import = import) }\n            writableDatabase.update(TABLE_CELLS_LEARN, values, CELLS_SELECTION, getCellSelectionArgs(cell))\n        } else if (!exists) {\n            val values = contentValuesOf(\n                FIELD_MCC to cell.mcc,\n                FIELD_MNC to cell.mnc,\n                FIELD_LAC_TAC to (cell.lac ?: cell.tac ?: 0),\n                FIELD_TYPE to cell.type.ordinal,\n                FIELD_CID to cell.cid,\n                FIELD_PSC to (cell.pscOrPci ?: 0),\n            ).apply { putLearnLocation(location, badTime = 0) }\n            writableDatabase.insertWithOnConflict(TABLE_CELLS_LEARN, null, values, SQLiteDatabase.CONFLICT_REPLACE)\n        } else {\n            val values = ContentValues().apply { putLearnLocation(location, midLocation) }\n            writableDatabase.update(TABLE_CELLS_LEARN, values, CELLS_SELECTION, getCellSelectionArgs(cell))\n        }\n        return true\n    }\n\n    fun learnWifiLocation(wifi: WifiDetails, location: Location, import: Boolean = false): Boolean {\n        if (!wifi.isRequestable) return false\n        val cursor = readableDatabase.query(TABLE_WIFI_LEARN, FIELDS_MID_LOCATION, getWifiSelection(wifi))\n        var exists = false\n        var isBad = false\n        var midLocation: Location? = null\n        try {\n            if (cursor.moveToNext()) {\n                midLocation = cursor.getMidLocation()\n                exists = midLocation != null\n                isBad = midLocation?.let { it.distanceTo(location) > LEARN_BAD_SIZE_WIFI } == true\n            }\n        } finally {\n            cursor.close()\n        }\n        if (exists && isBad) {\n            val values = ContentValues().apply { putLearnLocation(location, badTime = location.time, import = import) }\n            writableDatabase.update(TABLE_WIFI_LEARN, values, getWifiSelection(wifi), null)\n        } else if (!exists) {\n            val values = contentValuesOf(\n                FIELD_MAC to wifi.macBytes\n            ).apply { putLearnLocation(location, badTime = 0) }\n            writableDatabase.insertWithOnConflict(TABLE_WIFI_LEARN, null, values, SQLiteDatabase.CONFLICT_REPLACE)\n        } else {\n            val values = ContentValues().apply { putLearnLocation(location, midLocation) }\n            writableDatabase.update(TABLE_WIFI_LEARN, values, getWifiSelection(wifi), null)\n        }\n        return true\n    }\n\n    fun exportLearned(name: String): Uri? {\n        try {\n            val wifi = when (name) {\n                NAME_WIFI -> true\n                NAME_CELL -> false\n                else -> throw IllegalArgumentException()\n            }\n            val fieldNames = if (wifi) FIELDS_WIFI else FIELDS_CELL\n            val tableName = if (wifi) TABLE_WIFI_LEARN else TABLE_CELLS_LEARN\n            val midLocationGetter: (Cursor) -> Location? = if (wifi) Cursor::getWifiMidLocation else Cursor::getCellMidLocation\n\n            val exportDir = File(context.cacheDir, \"location\")\n            exportDir.mkdir()\n            val exportFile = File(exportDir, \"$name-${UUID.randomUUID()}.csv.gz\")\n            val output = GZIPOutputStream(exportFile.outputStream()).bufferedWriter()\n            output.write(\"${fieldNames.joinToString(\",\")},${FIELDS_EXPORT_DATA.joinToString(\",\")}\\n\")\n            val cursor = readableDatabase.query(tableName, FIELDS_MID_LOCATION + fieldNames)\n            val indices = fieldNames.map { cursor.getColumnIndexOrThrow(it) }\n            while (cursor.moveToNext()) {\n                val midLocation = midLocationGetter(cursor)\n                if (midLocation != null) {\n                    output.write(indices.joinToString(\",\") { index ->\n                        if (cursor.getType(index) == Cursor.FIELD_TYPE_BLOB) {\n                            cursor.getBlob(index).toHexString()\n                        } else {\n                            cursor.getStringOrNull(index) ?: \"\"\n                        }\n                    })\n                    output.write(\",${midLocation.latitude},${midLocation.longitude},${if (midLocation.hasAltitude()) midLocation.altitude else \"\"}\\n\")\n                }\n            }\n            output.close()\n            return FileProvider.getUriForFile(context,\"${context.packageName}.microg.location.export\", exportFile)\n        } catch (e: Exception) {\n            Log.w(TAG, e)\n        }\n        return null\n    }\n\n    fun importLearned(fileUri: Uri): Int {\n        var counter = 0\n        try {\n            val type = context.contentResolver.getType(fileUri)\n            val gzip = if (type == null || type !in SUPPORTED_TYPES) {\n                if (fileUri.path == null) throw IllegalArgumentException(\"Unsupported file extension\")\n                if (fileUri.path!!.endsWith(\".gz\")) {\n                    true\n                } else if (fileUri.path!!.endsWith(\".csv\")) {\n                    false\n                } else {\n                    throw IllegalArgumentException(\"Unsupported file extension\")\n                }\n            } else {\n                type.endsWith(\"gzip\")\n            }\n            val desc = context.contentResolver.openFileDescriptor(fileUri, \"r\") ?: throw FileNotFoundException()\n            ParcelFileDescriptor.AutoCloseInputStream(desc).use { source ->\n                val input = (if (gzip) GZIPInputStream(source) else source).bufferedReader()\n                val headers = input.readLine().split(\",\")\n                val name = when {\n                    headers.containsAll(FIELDS_WIFI.toList()) && headers.containsAll(FIELDS_EXPORT_DATA.toList()) -> NAME_WIFI\n                    headers.containsAll(FIELDS_CELL.toList()) && headers.containsAll(FIELDS_EXPORT_DATA.toList()) -> NAME_CELL\n                    else -> null\n                }\n                if (name != null) {\n                    while (true) {\n                        val line = input.readLine().split(\",\")\n                        if (line.size != headers.size) break // End of file reached\n                        val location = Location(PROVIDER_CACHE)\n                        location.latitude = line[headers.indexOf(FIELD_LATITUDE)].toDoubleOrNull() ?: continue\n                        location.longitude = line[headers.indexOf(FIELD_LONGITUDE)].toDoubleOrNull() ?: continue\n                        line[headers.indexOf(FIELD_ALTITUDE)].toDoubleOrNull()?.let { location.altitude = it }\n                        location.time = headers.indexOf(FIELD_TIME).takeIf { it != -1 }?.let { line[it] }?.toLongOrNull()?.takeIf { it > 0 } ?: System.currentTimeMillis()\n                        if (name == NAME_WIFI) {\n                            val wifi = WifiDetails(\n                                macAddress = line[headers.indexOf(FIELD_MAC)]\n                            )\n                            if (learnWifiLocation(wifi, location)) counter++\n                        } else  {\n                            val cell = CellDetails(\n                                type = line[headers.indexOf(FIELD_TYPE)].let {\n                                    it.toIntOrNull()?.let { CellDetails.Companion.Type.entries[it] } ?:\n                                    runCatching { CellDetails.Companion.Type.valueOf(it) }.getOrNull()\n                                } ?: continue,\n                                mcc = line[headers.indexOf(FIELD_MCC)].toIntOrNull() ?: continue,\n                                mnc = line[headers.indexOf(FIELD_MNC)].toIntOrNull() ?: continue,\n                                lac = line[headers.indexOf(FIELD_LAC_TAC)].toIntOrNull(),\n                                tac = line[headers.indexOf(FIELD_LAC_TAC)].toIntOrNull(),\n                                cid = line[headers.indexOf(FIELD_CID)].toLongOrNull() ?: continue,\n                                pscOrPci = line[headers.indexOf(FIELD_PSC)].toIntOrNull(),\n                            )\n                            if (learnCellLocation(cell, location)) counter++\n                        }\n                    }\n                }\n            }\n        } catch (e: Exception) {\n            Log.w(TAG, e)\n        }\n        return counter\n    }\n\n    override fun onCreate(db: SQLiteDatabase) {\n        migrate(db, 0, CURRENT_VERSION)\n    }\n\n    fun cleanup(db: SQLiteDatabase) {\n        db.delete(TABLE_CELLS, \"$FIELD_TIME < ?\", arrayOf((System.currentTimeMillis() - MAX_CACHE_AGE).toString()))\n        db.delete(TABLE_CELLS_PRE, \"$FIELD_TIME < ?\", arrayOf((System.currentTimeMillis() - MAX_CACHE_AGE).toString()))\n        db.delete(TABLE_WIFIS, \"$FIELD_TIME < ?\", arrayOf((System.currentTimeMillis() - MAX_CACHE_AGE).toString()))\n        db.delete(TABLE_CELLS_LEARN, \"$FIELD_TIME < ?\", arrayOf((System.currentTimeMillis() - MAX_LEARN_AGE).toString()))\n        db.delete(TABLE_WIFI_LEARN, \"$FIELD_TIME < ?\", arrayOf((System.currentTimeMillis() - MAX_LEARN_AGE).toString()))\n    }\n\n    override fun onOpen(db: SQLiteDatabase) {\n        super.onOpen(db)\n        if (!db.isReadOnly) {\n            cleanup(db)\n        }\n    }\n\n    override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {\n        migrate(db, oldVersion, newVersion)\n    }\n\n    override fun onDowngrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {\n        migrate(db, oldVersion, newVersion)\n    }\n\n    fun dump(writer: PrintWriter) {\n        writer.println(\"Database: cells(cached)=${DatabaseUtils.queryNumEntries(readableDatabase, TABLE_CELLS)}, cells(learnt)=${DatabaseUtils.queryNumEntries(readableDatabase, TABLE_CELLS_LEARN)}, wifis(cached)=${DatabaseUtils.queryNumEntries(readableDatabase, TABLE_WIFIS)}, wifis(learnt)=${DatabaseUtils.queryNumEntries(readableDatabase, TABLE_WIFI_LEARN)}\")\n    }\n}\n\nconst val EXTRA_HIGH_LOCATION = \"high\"\nconst val EXTRA_LOW_LOCATION = \"low\"\nconst val EXTRA_RECORD_COUNT = \"recs\"\nprivate const val MAX_CACHE_AGE = 1000L * 60 * 60 * 24 * 14 // 14 days\nprivate const val MAX_LEARN_AGE = 1000L * 60 * 60 * 24 * 365 // 1 year\nprivate const val TABLE_CELLS = \"cells\"\nprivate const val TABLE_CELLS_PRE = \"cells_pre\"\nprivate const val TABLE_WIFIS = \"wifis\"\nprivate const val TABLE_WIFI_SCANS = \"wifi_scans\"\nprivate const val TABLE_CELLS_LEARN = \"cells_learn\"\nprivate const val TABLE_WIFI_LEARN = \"wifis_learn\"\nprivate const val FIELD_MCC = \"mcc\"\nprivate const val FIELD_MNC = \"mnc\"\nprivate const val FIELD_TYPE = \"type\"\nprivate const val FIELD_LAC_TAC = \"lac\"\nprivate const val FIELD_CID = \"cid\"\nprivate const val FIELD_PSC = \"psc\"\nprivate const val FIELD_LATITUDE = \"lat\"\nprivate const val FIELD_LONGITUDE = \"lon\"\nprivate const val FIELD_ACCURACY = \"acc\"\nprivate const val FIELD_ALTITUDE = \"alt\"\nprivate const val FIELD_ALTITUDE_ACCURACY = \"alt_acc\"\nprivate const val FIELD_TIME = \"time\"\nprivate const val FIELD_PRECISION = \"prec\"\nprivate const val FIELD_MAC = \"mac\"\nprivate const val FIELD_SCAN_HASH = \"hash\"\nprivate const val FIELD_LATITUDE_HIGH = \"lath\"\nprivate const val FIELD_LATITUDE_LOW = \"latl\"\nprivate const val FIELD_LONGITUDE_HIGH = \"lonh\"\nprivate const val FIELD_LONGITUDE_LOW = \"lonl\"\nprivate const val FIELD_ALTITUDE_HIGH = \"alth\"\nprivate const val FIELD_ALTITUDE_LOW = \"altl\"\nprivate const val FIELD_BAD_TIME = \"btime\"\nprivate const val FIELD_LEARN_RECORD_COUNT = \"recs\"\n\nprivate const val LEARN_BASE_ACCURACY_CELL = 10_000.0\nprivate const val LEARN_BASE_VERTICAL_ACCURACY_CELL = 5_000.0\nprivate const val LEARN_BASE_PRECISION_CELL = 0.5\nprivate const val LEARN_ACCURACY_FACTOR_CELL = 0.002\nprivate const val LEARN_VERTICAL_ACCURACY_FACTOR_CELL = 0.002\nprivate const val LEARN_PRECISION_FACTOR_CELL = 0.01\nprivate const val LEARN_BAD_SIZE_CELL = 10_000\n\nprivate const val LEARN_BASE_ACCURACY_WIFI = 200.0\nprivate const val LEARN_BASE_VERTICAL_ACCURACY_WIFI = 100.0\nprivate const val LEARN_BASE_PRECISION_WIFI = 0.2\nprivate const val LEARN_ACCURACY_FACTOR_WIFI = 0.02\nprivate const val LEARN_VERTICAL_ACCURACY_FACTOR_WIFI = 0.02\nprivate const val LEARN_PRECISION_FACTOR_WIFI = 0.1\nprivate const val LEARN_BAD_SIZE_WIFI = 200\n\nprivate const val LEARN_BAD_CUTOFF = 1000L * 60 * 60 * 24 * 14\n\nprivate const val CELLS_SELECTION = \"$FIELD_MCC = ? AND $FIELD_MNC = ? AND $FIELD_TYPE = ? AND $FIELD_LAC_TAC = ? AND $FIELD_CID = ? AND $FIELD_PSC = ?\"\nprivate const val CELLS_PRE_SELECTION = \"$FIELD_MCC = ? AND $FIELD_MNC = ?\"\n\nprivate val FIELDS_CACHE_LOCATION = arrayOf(FIELD_LATITUDE, FIELD_LONGITUDE, FIELD_ACCURACY, FIELD_ALTITUDE, FIELD_ALTITUDE_ACCURACY, FIELD_TIME, FIELD_PRECISION)\nprivate val FIELDS_MID_LOCATION = arrayOf(FIELD_LATITUDE_HIGH, FIELD_LATITUDE_LOW, FIELD_LONGITUDE_HIGH, FIELD_LONGITUDE_LOW, FIELD_ALTITUDE_HIGH, FIELD_ALTITUDE_LOW, FIELD_LEARN_RECORD_COUNT, FIELD_TIME)\nprivate val FIELDS_MID_LOCATION_GET_LEARN = FIELDS_MID_LOCATION + FIELD_BAD_TIME\nprivate val FIELDS_CELL = arrayOf(FIELD_MCC, FIELD_MNC, FIELD_TYPE, FIELD_LAC_TAC, FIELD_CID, FIELD_PSC)\nprivate val FIELDS_WIFI = arrayOf(FIELD_MAC)\nprivate val FIELDS_EXPORT_DATA = arrayOf(FIELD_LATITUDE, FIELD_LONGITUDE, FIELD_ALTITUDE)\nprivate val SUPPORTED_TYPES = listOf(\n    \"application/vnd.microg.location.cell+csv+gzip\",\n    \"application/vnd.microg.location.cell+csv\",\n    \"application/vnd.microg.location.wifi+csv+gzip\",\n    \"application/vnd.microg.location.wifi+csv\",\n    \"application/gzip\",\n    \"application/x-gzip\",\n    \"text/csv\",\n)\n\nprivate fun getCellSelectionArgs(cell: CellDetails): Array<String> {\n    return arrayOf(\n        cell.mcc.toString(),\n        cell.mnc.toString(),\n        cell.type.ordinal.toString(),\n        (cell.lac ?: cell.tac ?: 0).toString(),\n        cell.cid.toString(),\n        (cell.pscOrPci ?: 0).toString(),\n    )\n}\n\nprivate fun getWifiSelection(wifi: WifiDetails): String {\n    return \"$FIELD_MAC = x'${wifi.macBytes.toHexString()}'\"\n}\n\nprivate fun getCellPreSelectionArgs(cell: CellDetails): Array<String> {\n    return arrayOf(\n        cell.mcc.toString(),\n        cell.mnc.toString()\n    )\n}\n\nprivate fun Cursor.getSingleLocation(maxAge: Long): Location? {\n    return try {\n        if (moveToNext()) {\n            getLocation(maxAge)\n        } else {\n            null\n        }\n    } finally {\n        close()\n    }\n}\n\nprivate fun Cursor.getLocation(maxAge: Long): Location? {\n    if (getLong(5) > System.currentTimeMillis() - maxAge) {\n        if (getDouble(2) == 0.0) return NEGATIVE_CACHE_ENTRY\n        return Location(PROVIDER_CACHE).apply {\n            latitude = getDouble(0)\n            longitude = getDouble(1)\n            accuracy = getDouble(2).toFloat()\n            getDoubleOrNull(3)?.let { altitude = it }\n            verticalAccuracy = getDoubleOrNull(4)?.toFloat()\n            time = getLong(5)\n            precision = getDouble(6)\n        }\n    }\n    return null\n}\n\nprivate fun Cursor.getMidLocation(\n    maxAge: Long = Long.MAX_VALUE,\n    baseAccuracy: Double = 0.0,\n    accuracyFactor: Double = 0.0,\n    baseVerticalAccuracy: Double = baseAccuracy,\n    verticalAccuracyFactor: Double = accuracyFactor,\n    basePrecision: Double = 0.0,\n    precisionFactor: Double = 0.0\n): Location? {\n    if (maxAge == Long.MAX_VALUE || getLong(7) > System.currentTimeMillis() - maxAge) {\n        val high = Location(PROVIDER_CACHE).apply { latitude = getDouble(0); longitude = getDouble(2) }\n        if (!isNull(4)) high.altitude = getDouble(4)\n        val low = Location(PROVIDER_CACHE).apply { latitude = getDouble(1); longitude = getDouble(3) }\n        if (!isNull(5)) low.altitude = getDouble(5)\n        val count = getInt(6)\n        val computedAccuracy = baseAccuracy / (1 + (accuracyFactor * (count - 1).toDouble()))\n        val computedVerticalAccuracy = baseVerticalAccuracy / (1 + (verticalAccuracyFactor * (count - 1).toDouble()))\n        return Location(PROVIDER_CACHE).apply {\n            latitude = (high.latitude + low.latitude) / 2.0\n            longitude = (high.longitude + low.longitude) / 2.0\n            accuracy = max(high.distanceTo(low) / 2.0, computedAccuracy).toFloat()\n            if (high.hasAltitude() && low.hasAltitude()) {\n                altitude = (high.altitude + low.altitude) / 2.0\n                verticalAccuracy = max((abs(high.altitude - low.altitude) / 2.0), computedVerticalAccuracy).toFloat()\n            } else if (high.hasAltitude()) {\n                altitude = high.altitude\n                verticalAccuracy = computedVerticalAccuracy.toFloat()\n            } else if (low.hasAltitude()) {\n                altitude = low.altitude\n                verticalAccuracy = computedVerticalAccuracy.toFloat()\n            }\n            precision = basePrecision * (1 + (precisionFactor * (count - 1)))\n            highLocation = high\n            lowLocation = low\n            extras += EXTRA_RECORD_COUNT to count\n        }\n    }\n    return null\n}\n\nprivate fun Cursor.getWifiMidLocation() = getMidLocation(\n    MAX_LEARN_AGE,\n    baseAccuracy = LEARN_BASE_ACCURACY_WIFI,\n    accuracyFactor = LEARN_ACCURACY_FACTOR_WIFI,\n    baseVerticalAccuracy = LEARN_BASE_VERTICAL_ACCURACY_WIFI,\n    verticalAccuracyFactor = LEARN_VERTICAL_ACCURACY_FACTOR_WIFI,\n    basePrecision = LEARN_BASE_PRECISION_WIFI,\n    precisionFactor = LEARN_PRECISION_FACTOR_WIFI\n)\n\nprivate fun Cursor.getCellMidLocation() = getMidLocation(\n    MAX_LEARN_AGE,\n    baseAccuracy = LEARN_BASE_ACCURACY_CELL,\n    accuracyFactor = LEARN_ACCURACY_FACTOR_CELL,\n    baseVerticalAccuracy = LEARN_BASE_VERTICAL_ACCURACY_CELL,\n    verticalAccuracyFactor = LEARN_VERTICAL_ACCURACY_FACTOR_CELL,\n    basePrecision = LEARN_BASE_PRECISION_CELL,\n    precisionFactor = LEARN_PRECISION_FACTOR_CELL\n)\n\nprivate var Location.highLocation: Location?\n    get() = extras?.let { BundleCompat.getParcelable(it, EXTRA_HIGH_LOCATION, Location::class.java) }\n    set(value) { extras += EXTRA_HIGH_LOCATION to value }\n\nprivate val Location.highLatitude: Double\n    get() = highLocation?.latitude ?: latitude\nprivate val Location.highLongitude: Double\n    get() = highLocation?.longitude ?: longitude\nprivate val Location.highAltitude: Double?\n    get() = highLocation?.takeIf { it.hasAltitude() }?.altitude ?: altitude.takeIf { hasAltitude() }\n\nprivate var Location.lowLocation: Location?\n    get() = extras?.let { BundleCompat.getParcelable(it, EXTRA_LOW_LOCATION, Location::class.java) }\n    set(value) { extras += EXTRA_LOW_LOCATION to value }\n\nprivate val Location.lowLatitude: Double\n    get() = lowLocation?.latitude ?: latitude\nprivate val Location.lowLongitude: Double\n    get() = lowLocation?.longitude ?: longitude\nprivate val Location.lowAltitude: Double?\n    get() = lowLocation?.takeIf { it.hasAltitude() }?.altitude ?: altitude.takeIf { hasAltitude() }\n\nprivate var Location?.recordCount: Int\n    get() = this?.extras?.getInt(EXTRA_RECORD_COUNT, 0) ?: 0\n    set(value) { this?.extras += EXTRA_RECORD_COUNT to value }\n\nprivate fun max(first: Double, second: Double?): Double {\n    if (second == null) return first\n    return max(first, second)\n}\n\nprivate fun max(first: Long, second: Long?): Long {\n    if (second == null) return first\n    return max(first, second)\n}\n\nprivate fun min(first: Double, second: Double?): Double {\n    if (second == null) return first\n    return min(first, second)\n}\n\nprivate fun ContentValues.putLocation(location: Location) {\n    if (location != NEGATIVE_CACHE_ENTRY) {\n        put(FIELD_LATITUDE, location.latitude)\n        put(FIELD_LONGITUDE, location.longitude)\n        put(FIELD_ACCURACY, location.accuracy)\n        put(FIELD_TIME, location.time)\n        put(FIELD_PRECISION, location.precision)\n        if (location.hasAltitude()) {\n            put(FIELD_ALTITUDE, location.altitude)\n            put(FIELD_ALTITUDE_ACCURACY, location.verticalAccuracy)\n        }\n    } else {\n        put(FIELD_LATITUDE, 0.0)\n        put(FIELD_LONGITUDE, 0.0)\n        put(FIELD_ACCURACY, 0.0)\n        put(FIELD_TIME, System.currentTimeMillis())\n        put(FIELD_PRECISION, 0.0)\n    }\n}\n\nprivate fun ContentValues.putLearnLocation(location: Location, previous: Location? = null, badTime: Long? = null, import: Boolean = false) {\n    if (location != NEGATIVE_CACHE_ENTRY) {\n        put(FIELD_LATITUDE_HIGH, max(location.latitude, previous?.highLatitude))\n        put(FIELD_LATITUDE_LOW, min(location.latitude, previous?.lowLatitude))\n        put(FIELD_LONGITUDE_HIGH, max(location.longitude, previous?.highLongitude))\n        put(FIELD_LONGITUDE_LOW, min(location.longitude, previous?.lowLongitude))\n        put(FIELD_TIME, max(location.time, previous?.time ?: 0))\n        if (location.hasAltitude()) {\n            put(FIELD_ALTITUDE_HIGH, max(location.altitude, previous?.highAltitude))\n            put(FIELD_ALTITUDE_LOW, min(location.altitude, previous?.lowAltitude))\n        }\n        put(FIELD_LEARN_RECORD_COUNT, previous.recordCount + 1)\n        if (badTime != null && !import) {\n            put(FIELD_BAD_TIME, max(badTime, previous?.time))\n        }\n    }\n}"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/network/NetworkDetails.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.network\n\ninterface NetworkDetails {\n    val timestamp: Long?\n    val signalStrength: Int?\n}"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/network/NetworkLocationRequest.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.network\n\nimport android.app.PendingIntent\nimport android.content.Context\nimport android.content.Intent\nimport android.location.Location\nimport android.os.SystemClock\nimport android.os.WorkSource\nimport org.microg.gms.location.EXTRA_LOCATION\nimport org.microg.gms.location.EXTRA_ELAPSED_REALTIME\n\nclass NetworkLocationRequest(\n    var pendingIntent: PendingIntent,\n    var intervalMillis: Long,\n    var lowPower: Boolean,\n    var bypass: Boolean,\n    var workSource: WorkSource\n) {\n    var lastRealtime = 0L\n        private set\n\n    fun send(context: Context, location: Location) {\n        lastRealtime = SystemClock.elapsedRealtime()\n        pendingIntent.send(context, 0, Intent().apply {\n            putExtra(EXTRA_LOCATION, location)\n            putExtra(EXTRA_ELAPSED_REALTIME, lastRealtime)\n        })\n    }\n}"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/network/NetworkLocationService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.network\n\nimport android.annotation.SuppressLint\nimport android.app.PendingIntent\nimport android.content.Intent\nimport android.location.Location\nimport android.location.LocationManager\nimport android.net.Uri\nimport android.net.wifi.WifiManager\nimport android.os.*\nimport android.os.Build.VERSION.SDK_INT\nimport android.util.Log\nimport androidx.annotation.GuardedBy\nimport androidx.core.content.IntentCompat\nimport androidx.core.content.getSystemService\nimport androidx.core.location.LocationListenerCompat\nimport androidx.core.location.LocationManagerCompat\nimport androidx.core.location.LocationRequestCompat\nimport androidx.core.os.bundleOf\nimport androidx.lifecycle.LifecycleService\nimport androidx.lifecycle.lifecycleScope\nimport kotlinx.coroutines.launch\nimport kotlinx.coroutines.withTimeout\nimport org.microg.gms.location.*\nimport org.microg.gms.location.network.cell.CellDetails\nimport org.microg.gms.location.network.cell.CellDetailsCallback\nimport org.microg.gms.location.network.cell.CellDetailsSource\nimport org.microg.gms.location.network.ichnaea.IchnaeaServiceClient\nimport org.microg.gms.location.network.wifi.*\nimport java.io.FileDescriptor\nimport java.io.PrintWriter\nimport java.util.*\nimport kotlin.math.*\n\nclass NetworkLocationService : LifecycleService(), WifiDetailsCallback, CellDetailsCallback {\n    private lateinit var handlerThread: HandlerThread\n    private lateinit var handler: Handler\n\n    @GuardedBy(\"activeRequests\")\n    private val activeRequests = HashSet<NetworkLocationRequest>()\n    private val highPowerScanRunnable = Runnable { this.scan(false) }\n    private val lowPowerScanRunnable = Runnable { this.scan(true) }\n    private var wifiDetailsSource: WifiDetailsSource? = null\n    private var cellDetailsSource: CellDetailsSource? = null\n    private val ichnaea by lazy { IchnaeaServiceClient(this) }\n    private val database by lazy { LocationDatabase(this) }\n    private val movingWifiHelper by lazy { MovingWifiHelper(this) }\n    private val settings by lazy { LocationSettings(this) }\n\n    private var lastHighPowerScanRealtime = 0L\n    private var lastLowPowerScanRealtime = 0L\n    private var highPowerIntervalMillis = Long.MAX_VALUE\n    private var lowPowerIntervalMillis = Long.MAX_VALUE\n\n    private var lastWifiDetailsRealtimeMillis = 0L\n    private var lastCellDetailsRealtimeMillis = 0L\n\n    private val locationLock = Any()\n    private var lastWifiLocation: Location? = null\n    private var lastCellLocation: Location? = null\n    private var lastLocation: Location? = null\n\n    private val passiveLocationListener by lazy { LocationListenerCompat { onNewPassiveLocation(it) } }\n\n    @GuardedBy(\"gpsLocationBuffer\")\n    private val gpsLocationBuffer = LinkedList<Location>()\n    private var passiveListenerActive = false\n\n    private var currentLocalMovingWifi: WifiDetails? = null\n    private var lastLocalMovingWifiLocationCandidate: Location? = null\n\n    private val interval: Long\n        get() = min(highPowerIntervalMillis, lowPowerIntervalMillis)\n\n    override fun onCreate() {\n        super.onCreate()\n        handlerThread = HandlerThread(NetworkLocationService::class.java.simpleName)\n        handlerThread.start()\n        handler = Handler(handlerThread.looper)\n        wifiDetailsSource = WifiDetailsSource.create(this, this).apply { enable() }\n        cellDetailsSource = CellDetailsSource.create(this, this).apply { enable() }\n        if (settings.effectiveEndpoint == null && (settings.wifiIchnaea || settings.cellIchnaea)) {\n            sendBroadcast(Intent(ACTION_CONFIGURATION_REQUIRED).apply {\n                `package` = packageName\n                putExtra(EXTRA_CONFIGURATION, CONFIGURATION_FIELD_ONLINE_SOURCE)\n            })\n        }\n    }\n\n    private fun updatePassiveGpsListenerRegistration() {\n        try {\n            getSystemService<LocationManager>()?.let { locationManager ->\n                if ((settings.cellLearning || settings.wifiLearning) && (highPowerIntervalMillis != Long.MAX_VALUE)) {\n                    if (!passiveListenerActive) {\n                        LocationManagerCompat.requestLocationUpdates(\n                            locationManager,\n                            LocationManager.PASSIVE_PROVIDER,\n                            LocationRequestCompat.Builder(LocationRequestCompat.PASSIVE_INTERVAL)\n                                .setQuality(LocationRequestCompat.QUALITY_LOW_POWER)\n                                .setMinUpdateIntervalMillis(GPS_PASSIVE_INTERVAL)\n                                .build(),\n                            passiveLocationListener,\n                            handlerThread.looper\n                        )\n                        passiveListenerActive = true\n                    }\n                } else {\n                    if (passiveListenerActive) {\n                        LocationManagerCompat.removeUpdates(locationManager, passiveLocationListener)\n                        passiveListenerActive = false\n                    }\n                }\n            }\n        } catch (e: SecurityException) {\n            Log.d(TAG, \"GPS location retriever not initialized due to lack of permission\")\n        } catch (e: Exception) {\n            Log.d(TAG, \"GPS location retriever not initialized\", e)\n        }\n    }\n\n    @Suppress(\"DEPRECATION\")\n    @SuppressLint(\"WrongConstant\")\n    private fun scan(lowPower: Boolean) {\n        if (!lowPower) lastHighPowerScanRealtime = SystemClock.elapsedRealtime()\n        lastLowPowerScanRealtime = SystemClock.elapsedRealtime()\n        val currentLocalMovingWifi = currentLocalMovingWifi\n        val lastWifiScanIsSufficientlyNewForMoving = lastWifiDetailsRealtimeMillis > SystemClock.elapsedRealtime() - MAX_LOCAL_WIFI_SCAN_AGE_MS\n        val movingWifiWasProducingRecentResults = (lastLocalMovingWifiLocationCandidate?.elapsedMillis ?: 0L) > SystemClock.elapsedRealtime() - max(MAX_LOCAL_WIFI_AGE_MS, interval * 2)\n        val movingWifiLocationWasAccurate = (lastLocalMovingWifiLocationCandidate?.accuracy ?: Float.MAX_VALUE) <= MOVING_WIFI_HIGH_POWER_ACCURACY\n        if (currentLocalMovingWifi != null &&\n            movingWifiWasProducingRecentResults &&\n            lastWifiScanIsSufficientlyNewForMoving &&\n            (movingWifiLocationWasAccurate || lowPower) &&\n            getSystemService<WifiManager>()?.connectionInfo?.bssid == currentLocalMovingWifi.macAddress\n        ) {\n            Log.d(TAG, \"Skip network scan and use current local wifi instead. low=$lowPower accurate=$movingWifiLocationWasAccurate\")\n            onWifiDetailsAvailable(listOf(currentLocalMovingWifi.copy(timestamp = System.currentTimeMillis())))\n        } else {\n            val workSource = synchronized(activeRequests) { activeRequests.minByOrNull { it.intervalMillis }?.workSource }\n            Log.d(TAG, \"Start network scan for $workSource\")\n            if (settings.wifiLearning || settings.wifiCaching || settings.wifiIchnaea) {\n                wifiDetailsSource?.startScan(workSource)\n            } else if (settings.wifiMoving) {\n                // No need to scan if only moving wifi enabled, instead simulate scan based on current connection info\n                val connectionInfo = getSystemService<WifiManager>()?.connectionInfo\n                if (SDK_INT >= 31 && connectionInfo != null && connectionInfo.toWifiDetails() != null) {\n                    onWifiDetailsAvailable(listOfNotNull(connectionInfo.toWifiDetails()))\n                } else if (currentLocalMovingWifi != null && connectionInfo?.bssid == currentLocalMovingWifi.macAddress) {\n                    onWifiDetailsAvailable(listOf(currentLocalMovingWifi.copy(timestamp = System.currentTimeMillis())))\n                } else {\n                    // Can't simulate scan, so just scan\n                    wifiDetailsSource?.startScan(workSource)\n                }\n            }\n            if (settings.cellLearning || settings.cellCaching || settings.cellIchnaea) {\n                cellDetailsSource?.startScan(workSource)\n            }\n        }\n        updateRequests()\n    }\n\n    private fun updateRequests(forceNow: Boolean = false, lowPower: Boolean = true) {\n        synchronized(activeRequests) {\n            lowPowerIntervalMillis = Long.MAX_VALUE\n            highPowerIntervalMillis = Long.MAX_VALUE\n            for (request in activeRequests) {\n                if (request.lowPower) lowPowerIntervalMillis = min(lowPowerIntervalMillis, request.intervalMillis)\n                else highPowerIntervalMillis = min(highPowerIntervalMillis, request.intervalMillis)\n            }\n        }\n\n        // Low power must be strictly less than high power\n        if (highPowerIntervalMillis <= lowPowerIntervalMillis) lowPowerIntervalMillis = Long.MAX_VALUE\n\n        val nextHighPowerRequestIn =\n            if (highPowerIntervalMillis == Long.MAX_VALUE) Long.MAX_VALUE else highPowerIntervalMillis - (SystemClock.elapsedRealtime() - lastHighPowerScanRealtime)\n        val nextLowPowerRequestIn =\n            if (lowPowerIntervalMillis == Long.MAX_VALUE) Long.MAX_VALUE else lowPowerIntervalMillis - (SystemClock.elapsedRealtime() - lastLowPowerScanRealtime)\n\n        handler.removeCallbacks(highPowerScanRunnable)\n        handler.removeCallbacks(lowPowerScanRunnable)\n        if ((forceNow && !lowPower) || nextHighPowerRequestIn <= 0) {\n            Log.d(TAG, \"Schedule high-power scan now\")\n            handler.post(highPowerScanRunnable)\n        } else if (forceNow || nextLowPowerRequestIn <= 0) {\n            Log.d(TAG, \"Schedule low-power scan now\")\n            handler.post(lowPowerScanRunnable)\n        } else {\n            // Reschedule next request\n            if (nextLowPowerRequestIn < nextHighPowerRequestIn) {\n                Log.d(TAG, \"Schedule low-power scan in ${nextLowPowerRequestIn}ms\")\n                handler.postDelayed(lowPowerScanRunnable, nextLowPowerRequestIn)\n            } else if (nextHighPowerRequestIn != Long.MAX_VALUE) {\n                Log.d(TAG, \"Schedule high-power scan in ${nextHighPowerRequestIn}ms\")\n                handler.postDelayed(highPowerScanRunnable, nextHighPowerRequestIn)\n            }\n        }\n\n        updatePassiveGpsListenerRegistration()\n    }\n\n    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {\n        if (intent?.action == ACTION_NETWORK_LOCATION_SERVICE) {\n            handler.post {\n                val pendingIntent = IntentCompat.getParcelableExtra(intent, EXTRA_PENDING_INTENT, PendingIntent::class.java) ?: return@post\n                val enable = intent.getBooleanExtra(EXTRA_ENABLE, false)\n                if (enable) {\n                    val intervalMillis = intent.getLongExtra(EXTRA_INTERVAL_MILLIS, -1L)\n                    if (intervalMillis < 0) return@post\n                    var forceNow = intent.getBooleanExtra(EXTRA_FORCE_NOW, false)\n                    val lowPower = intent.getBooleanExtra(EXTRA_LOW_POWER, true)\n                    val bypass = intent.getBooleanExtra(EXTRA_BYPASS, false)\n                    val workSource = IntentCompat.getParcelableExtra(intent, EXTRA_WORK_SOURCE, WorkSource::class.java) ?: WorkSource()\n                    synchronized(activeRequests) {\n                        if (activeRequests.any { it.pendingIntent == pendingIntent }) {\n                            forceNow = false\n                            activeRequests.removeAll { it.pendingIntent == pendingIntent }\n                        }\n                        activeRequests.add(NetworkLocationRequest(pendingIntent, intervalMillis, lowPower, bypass, workSource))\n                    }\n                    handler.post { updateRequests(forceNow, lowPower) }\n                } else {\n                    synchronized(activeRequests) {\n                        activeRequests.removeAll { it.pendingIntent == pendingIntent }\n                    }\n                    handler.post { updateRequests() }\n                }\n            }\n        } else if (intent?.action == ACTION_NETWORK_IMPORT_EXPORT) {\n            handler.post {\n                val callback = IntentCompat.getParcelableExtra(intent, EXTRA_MESSENGER, Messenger::class.java)\n                val replyWhat = intent.getIntExtra(EXTRA_REPLY_WHAT, 0)\n                when (intent.getStringExtra(EXTRA_DIRECTION)) {\n                    DIRECTION_EXPORT -> {\n                        val name = intent.getStringExtra(EXTRA_NAME)\n                        val uri = name?.let { database.exportLearned(it) }\n                        callback?.send(Message.obtain().apply {\n                            what = replyWhat\n                            data = bundleOf(\n                                EXTRA_DIRECTION to DIRECTION_EXPORT,\n                                EXTRA_NAME to name,\n                                EXTRA_URI to uri,\n                            )\n                        })\n                    }\n                    DIRECTION_IMPORT -> {\n                        val uri = IntentCompat.getParcelableExtra(intent, EXTRA_URI, Uri::class.java)\n                        val counter = uri?.let { database.importLearned(it) } ?: 0\n                        callback?.send(Message.obtain().apply {\n                            what = replyWhat\n                            arg1 = counter\n                            data = bundleOf(\n                                EXTRA_DIRECTION to DIRECTION_IMPORT,\n                                EXTRA_URI to uri,\n                            )\n                        })\n                    }\n                }\n            }\n        }\n        super.onStartCommand(intent, flags, startId)\n        return START_STICKY\n    }\n\n    override fun onDestroy() {\n        handlerThread.quitSafely()\n        wifiDetailsSource?.disable()\n        wifiDetailsSource = null\n        cellDetailsSource?.disable()\n        cellDetailsSource = null\n        super.onDestroy()\n    }\n\n    fun Location.mayTakeAltitude(location: Location?) {\n        if (location != null && !hasAltitude() && location.hasAltitude()) {\n            altitude = location.altitude\n            verticalAccuracy = location.verticalAccuracy\n        }\n    }\n\n    suspend fun queryWifiLocation(wifis: List<WifiDetails>): Location? {\n        var candidate: Location? = queryCurrentLocalMovingWifiLocation()\n        if ((candidate?.accuracy ?: Float.MAX_VALUE) <= 50f) return candidate\n        val databaseCandidate = queryWifiLocationFromDatabase(wifis)\n        if (databaseCandidate != null && (candidate == null || databaseCandidate.precision > candidate.precision)) {\n            databaseCandidate.mayTakeAltitude(candidate)\n            candidate = databaseCandidate\n        }\n        if ((candidate?.accuracy ?: Float.MAX_VALUE) <= 50f && (candidate?.precision ?: 0.0) > 1.0) return candidate\n        val ichnaeaCandidate = queryIchnaeaWifiLocation(wifis, minimumPrecision = (candidate?.precision ?: 0.0))\n        if (ichnaeaCandidate != null && ichnaeaCandidate.accuracy >= (candidate?.accuracy ?: 0f)) {\n            ichnaeaCandidate.mayTakeAltitude(candidate)\n            candidate = ichnaeaCandidate\n        }\n        return candidate\n    }\n\n    private suspend fun queryCurrentLocalMovingWifiLocation(): Location? {\n        var candidate: Location? = null\n        val currentLocalMovingWifi = currentLocalMovingWifi\n        if (currentLocalMovingWifi != null && settings.wifiMoving) {\n            try {\n                withTimeout(5000L) {\n                    lastLocalMovingWifiLocationCandidate = movingWifiHelper.retrieveMovingLocation(currentLocalMovingWifi)\n                }\n                candidate = lastLocalMovingWifiLocationCandidate\n            } catch (e: Exception) {\n                lastLocalMovingWifiLocationCandidate = null\n                Log.w(TAG, \"Failed retrieving location for current moving wifi ${currentLocalMovingWifi.ssid}\", e)\n            }\n        }\n        return candidate\n    }\n\n    private suspend fun queryWifiLocationFromDatabase(wifis: List<WifiDetails>): Location? =\n        queryLocationFromRetriever(wifis, 1000.0) { database.getWifiLocation(it, settings.wifiLearning) }\n\n    private suspend fun queryCellLocationFromDatabase(cells: List<CellDetails>): Location? =\n        queryLocationFromRetriever(cells, 50000.0) { it.location ?: database.getCellLocation(it, settings.cellLearning) }\n\n    private val NetworkDetails.signalStrengthBounded: Int\n        get() = (signalStrength ?: -100).coerceIn(-100, -10)\n\n    private val NetworkDetails.ageBounded: Long\n        get() = (System.currentTimeMillis() - (timestamp ?: 0)).coerceIn(0, 60000)\n\n    private val NetworkDetails.weight: Double\n        get() = min(1.0, sqrt(2000.0 / ageBounded)) / signalStrengthBounded.toDouble().pow(2)\n\n    private fun <T: NetworkDetails> queryLocationFromRetriever(data: List<T>, maxClusterDistance: Double = 0.0, retriever: (T) -> Location?): Location? {\n        val locations = data.mapNotNull { detail -> retriever(detail)?.takeIf { it != NEGATIVE_CACHE_ENTRY }?.let { detail to it } }\n        if (locations.isNotEmpty()) {\n            val clusters = locations.map { mutableListOf(it) }\n            for (cellLocation in locations) {\n                for (cluster in clusters) {\n                    if (cluster.first() == cellLocation) continue;\n                    if (cluster.first().second.distanceTo(cellLocation.second) < max(cluster.first().second.accuracy * 2.0, maxClusterDistance)) {\n                        cluster.add(cellLocation)\n                    }\n                }\n            }\n            val cluster = clusters.maxBy { it.sumOf { it.second.precision } }\n\n            return Location(PROVIDER_CACHE).apply {\n                latitude = cluster.weightedAverage { it.second.latitude to it.first.weight }\n                longitude = cluster.weightedAverage { it.second.longitude to it.first.weight }\n                accuracy = min(\n                    cluster.map { it.second.distanceTo(this) + it.second.accuracy }.average().toFloat() / cluster.size,\n                    cluster.minOf { it.second.accuracy }\n                )\n                val altitudeCluster = cluster.filter { it.second.hasAltitude() }.takeIf { it.isNotEmpty() }\n                if (altitudeCluster != null) {\n                    altitude = altitudeCluster.weightedAverage { it.second.altitude to it.first.weight }\n                    verticalAccuracy = min(\n                        altitudeCluster.map { abs(altitude - it.second.altitude) + (it.second.verticalAccuracy ?: it.second.accuracy) }.average().toFloat() / cluster.size,\n                        altitudeCluster.minOf { it.second.verticalAccuracy ?: it.second.accuracy }\n                    )\n                }\n                precision = cluster.sumOf { it.second.precision }\n                time = System.currentTimeMillis()\n            }\n        }\n        return null\n    }\n\n    private suspend fun queryIchnaeaWifiLocation(wifis: List<WifiDetails>, minimumPrecision: Double = 0.0): Location? {\n        if (settings.wifiIchnaea && wifis.size >= 3 && wifis.size / IchnaeaServiceClient.WIFI_BASE_PRECISION_COUNT >= minimumPrecision) {\n            try {\n                val ichnaeaCandidate = ichnaea.retrieveMultiWifiLocation(wifis) { wifi, location ->\n                    if (settings.wifiCaching) database.putWifiLocation(wifi, location)\n                }!!\n                ichnaeaCandidate.time = System.currentTimeMillis()\n                return ichnaeaCandidate\n            } catch (e: Exception) {\n                Log.w(TAG, \"Failed retrieving location for ${wifis.size} wifi networks\", e)\n            }\n        }\n        return null\n    }\n\n    private fun <T> List<T>.weightedAverage(f: (T) -> Pair<Double, Double>): Double {\n        val valuesAndWeights = map { f(it) }\n        return valuesAndWeights.sumOf { it.first * it.second } / valuesAndWeights.sumOf { it.second }\n    }\n\n    override fun onWifiDetailsAvailable(wifis: List<WifiDetails>) {\n        if (wifis.isEmpty()) return\n        val scanResultTimestamp = min(wifis.maxOf { it.timestamp ?: Long.MAX_VALUE }, System.currentTimeMillis())\n        val scanResultRealtimeMillis = SystemClock.elapsedRealtime() - (System.currentTimeMillis() - scanResultTimestamp)\n        @Suppress(\"DEPRECATION\")\n        currentLocalMovingWifi = getSystemService<WifiManager>()?.connectionInfo\n            ?.let { wifiInfo -> wifis.filter { it.macAddress == wifiInfo.bssid && it.isMoving } }\n            ?.filter { movingWifiHelper.isLocallyRetrievable(it) }\n            ?.singleOrNull()\n        val requestableWifis = wifis.filter(WifiDetails::isRequestable)\n        if (requestableWifis.isEmpty() && currentLocalMovingWifi == null) return\n        updateWifiLocation(requestableWifis, scanResultRealtimeMillis, scanResultTimestamp)\n    }\n\n    private fun updateWifiLocation(requestableWifis: List<WifiDetails>, scanResultRealtimeMillis: Long = 0, scanResultTimestamp: Long = 0) {\n        if (settings.wifiLearning) {\n            for (wifi in requestableWifis.filter { it.timestamp != null }) {\n                val wifiElapsedMillis = SystemClock.elapsedRealtime() - (System.currentTimeMillis() - wifi.timestamp!!)\n                getGpsLocation(wifiElapsedMillis)?.let {\n                    database.learnWifiLocation(wifi, it)\n                }\n            }\n        }\n        if (scanResultRealtimeMillis < lastWifiDetailsRealtimeMillis + interval / 2 && lastWifiDetailsRealtimeMillis != 0L && scanResultRealtimeMillis != 0L) {\n            Log.d(TAG, \"Ignoring wifi details, similar age as last ($scanResultRealtimeMillis < $lastWifiDetailsRealtimeMillis + $interval / 2)\")\n            return\n        }\n        val previousLastRealtimeMillis = lastWifiDetailsRealtimeMillis\n        if (scanResultRealtimeMillis != 0L) lastWifiDetailsRealtimeMillis = scanResultRealtimeMillis\n        lifecycleScope.launch {\n            val location = queryWifiLocation(requestableWifis)\n            if (location == null) {\n                lastWifiDetailsRealtimeMillis = previousLastRealtimeMillis\n                return@launch\n            }\n            if (scanResultTimestamp != 0L) location.time = max(scanResultTimestamp, location.time)\n            if (scanResultRealtimeMillis != 0L) location.elapsedRealtimeNanos = max(location.elapsedRealtimeNanos, scanResultRealtimeMillis * 1_000_000L)\n            synchronized(locationLock) {\n                lastWifiLocation = location\n            }\n            sendLocationUpdate()\n        }\n    }\n\n    override fun onWifiSourceFailed() {\n        // Wifi source failed, create a new one\n        wifiDetailsSource?.disable()\n        wifiDetailsSource = WifiDetailsSource.create(this, this).apply { enable() }\n    }\n\n    private suspend fun queryCellLocation(cells: List<CellDetails>): Location? {\n        val candidate = queryCellLocationFromDatabase(cells)\n        if ((candidate?.precision ?: 0.0) > 1.0) return candidate\n        val cellsToUpdate = cells.filter { it.location == null && database.getCellLocation(it, settings.cellLearning) == null }\n        for (cell in cellsToUpdate) {\n            queryIchnaeaCellLocation(cell)\n        }\n        // Try again after fetching records from internet\n        return queryCellLocationFromDatabase(cells)\n    }\n\n    private suspend fun queryIchnaeaCellLocation(cell: CellDetails): Location? {\n        if (settings.cellIchnaea) {\n            try {\n                val ichnaeaCandidate = ichnaea.retrieveSingleCellLocation(cell) { cell, location ->\n                    if (settings.cellCaching) database.putCellLocation(cell, location)\n                } ?: NEGATIVE_CACHE_ENTRY\n                if (settings.cellCaching) {\n                    if (ichnaeaCandidate == NEGATIVE_CACHE_ENTRY) {\n                        database.putCellLocation(cell, NEGATIVE_CACHE_ENTRY)\n                        return null\n                    } else {\n                        ichnaeaCandidate.time = System.currentTimeMillis()\n                        database.putCellLocation(cell, ichnaeaCandidate)\n                        return ichnaeaCandidate\n                    }\n                }\n            } catch (e: Exception) {\n                Log.w(TAG, \"Failed retrieving location for cell network\", e)\n            }\n        }\n        return null\n    }\n\n    override fun onCellDetailsAvailable(cells: List<CellDetails>) {\n        if (settings.cellLearning) {\n            for (cell in cells.filter { it.timestamp != null && it.location == null }) {\n                val cellElapsedMillis = SystemClock.elapsedRealtime() - (System.currentTimeMillis() - cell.timestamp!!)\n                getGpsLocation(cellElapsedMillis)?.let {\n                    database.learnCellLocation(cell, it)\n                }\n            }\n        }\n        val scanResultTimestamp = min(cells.maxOf { it.timestamp ?: Long.MAX_VALUE }, System.currentTimeMillis())\n        val scanResultRealtimeMillis = SystemClock.elapsedRealtime() - (System.currentTimeMillis() - scanResultTimestamp)\n        if (scanResultRealtimeMillis < lastCellDetailsRealtimeMillis + interval / 2 && lastCellDetailsRealtimeMillis != 0L) {\n            Log.d(TAG, \"Ignoring cell details, similar age as last ($scanResultRealtimeMillis < $lastCellDetailsRealtimeMillis + $interval / 2)\")\n            return\n        }\n        val previousLastRealtimeMillis = lastWifiDetailsRealtimeMillis\n        lastCellDetailsRealtimeMillis = scanResultRealtimeMillis\n        lifecycleScope.launch {\n            val location = queryCellLocation(cells)\n            if (location == null) {\n                lastCellDetailsRealtimeMillis = previousLastRealtimeMillis\n                return@launch\n            }\n            if (scanResultTimestamp != 0L) location.time = max(scanResultTimestamp, location.time)\n            if (scanResultRealtimeMillis != 0L) location.elapsedRealtimeNanos = max(location.elapsedRealtimeNanos, scanResultRealtimeMillis * 1_000_000L)\n            synchronized(locationLock) {\n                lastCellLocation = location\n            }\n            sendLocationUpdate()\n        }\n    }\n\n    private fun sendLocationUpdate(now: Boolean = false) {\n        fun cliffLocations(old: Location?, new: Location?): Location? {\n            // We move from wifi towards cell with accuracy\n            if (old == null) return new\n            if (new == null) return old\n            val diff = new.elapsedMillis - old.elapsedMillis\n            if (diff < LOCATION_TIME_CLIFF_START_MS) return old\n            if (diff > LOCATION_TIME_CLIFF_END_MS) return new\n            val pct = (diff - LOCATION_TIME_CLIFF_START_MS).toDouble() / (LOCATION_TIME_CLIFF_END_MS - LOCATION_TIME_CLIFF_START_MS).toDouble()\n            return Location(old).apply {\n                provider = \"cliff\"\n                latitude = old.latitude * (1.0-pct) + new.latitude * pct\n                longitude = old.longitude * (1.0-pct) + new.longitude * pct\n                accuracy = (old.accuracy * (1.0-pct) + new.accuracy * pct).toFloat()\n                altitude = old.altitude * (1.0-pct) + new.altitude * pct\n                time = (old.time.toDouble() * (1.0-pct) + new.time.toDouble() * pct).toLong()\n                elapsedRealtimeNanos = (old.elapsedRealtimeNanos.toDouble() * (1.0-pct) + new.elapsedRealtimeNanos.toDouble() * pct).toLong()\n            }\n        }\n        val location = synchronized(locationLock) {\n            if (lastCellLocation == null && lastWifiLocation == null) return\n            when {\n                // Only non-null\n                lastCellLocation == null -> lastWifiLocation\n                lastWifiLocation == null -> lastCellLocation\n                // Consider cliff end\n                lastCellLocation!!.elapsedMillis > lastWifiLocation!!.elapsedMillis + LOCATION_TIME_CLIFF_END_MS -> lastCellLocation\n                lastWifiLocation!!.elapsedMillis > lastCellLocation!!.elapsedMillis + LOCATION_TIME_CLIFF_START_MS -> lastWifiLocation\n                // Wifi out of cell range with higher precision\n                lastCellLocation!!.precision > lastWifiLocation!!.precision && lastWifiLocation!!.distanceTo(lastCellLocation!!) > 2 * lastCellLocation!!.accuracy -> lastCellLocation\n                // Consider cliff start\n                lastCellLocation!!.elapsedMillis > lastWifiLocation!!.elapsedMillis + LOCATION_TIME_CLIFF_START_MS -> cliffLocations(lastWifiLocation, lastCellLocation)\n                else -> lastWifiLocation\n            }\n        } ?: return\n        if (location == lastLocation) return\n        if (lastLocation == lastWifiLocation && lastLocation.let { it != null && location.accuracy > it.accuracy } && !now) {\n            Log.d(TAG, \"Debounce inaccurate location update\")\n            handler.postDelayed({\n                sendLocationUpdate(true)\n            }, DEBOUNCE_DELAY_MS)\n            return\n        }\n        lastLocation = location\n        synchronized(activeRequests) {\n            for (request in activeRequests.toList()) {\n                try {\n                    request.send(this@NetworkLocationService, location)\n                } catch (e: Exception) {\n                    Log.w(TAG, \"Pending intent error $request\")\n                    activeRequests.remove(request)\n                }\n            }\n        }\n    }\n\n    private fun onNewPassiveLocation(location: Location) {\n        if (location.provider != LocationManager.GPS_PROVIDER || location.accuracy > GPS_PASSIVE_MIN_ACCURACY) return\n        synchronized(gpsLocationBuffer) {\n            if (gpsLocationBuffer.isNotEmpty() && gpsLocationBuffer.last.elapsedMillis < SystemClock.elapsedRealtime() - GPS_BUFFER_SIZE * GPS_PASSIVE_INTERVAL) {\n                gpsLocationBuffer.clear()\n            } else if (gpsLocationBuffer.size >= GPS_BUFFER_SIZE) {\n                gpsLocationBuffer.remove()\n            }\n            gpsLocationBuffer.offer(location)\n        }\n    }\n\n    private fun getGpsLocation(elapsedMillis: Long): Location? {\n        if (elapsedMillis + GPS_BUFFER_SIZE * GPS_PASSIVE_INTERVAL < SystemClock.elapsedRealtime()) return null\n        synchronized(gpsLocationBuffer) {\n            if (gpsLocationBuffer.isEmpty()) return null\n            for (location in gpsLocationBuffer.descendingIterator()) {\n                if (location.elapsedMillis in (elapsedMillis - GPS_PASSIVE_INTERVAL)..(elapsedMillis + GPS_PASSIVE_INTERVAL)) return location\n                if (location.elapsedMillis < elapsedMillis) return null\n            }\n        }\n        return null\n    }\n\n    override fun dump(fd: FileDescriptor?, writer: PrintWriter, args: Array<out String>?) {\n        writer.println(\"Last scan elapsed realtime: high-power: ${lastHighPowerScanRealtime.formatRealtime()}, low-power: ${lastLowPowerScanRealtime.formatRealtime()}\")\n        writer.println(\"Last scan result time: wifi: ${lastWifiDetailsRealtimeMillis.formatRealtime()}, cells: ${lastCellDetailsRealtimeMillis.formatRealtime()}\")\n        writer.println(\"Interval: high-power: ${highPowerIntervalMillis.formatDuration()}, low-power: ${lowPowerIntervalMillis.formatDuration()}\")\n        writer.println(\"Last wifi location: $lastWifiLocation${if (lastWifiLocation == lastLocation) \" (active)\" else \"\"}\")\n        writer.println(\"Last cell location: $lastCellLocation${if (lastCellLocation == lastLocation) \" (active)\" else \"\"}\")\n        writer.println(\"Wifi settings: ichnaea=${settings.wifiIchnaea} moving=${settings.wifiMoving} learn=${settings.wifiLearning}\")\n        writer.println(\"Cell settings: ichnaea=${settings.cellIchnaea} learn=${settings.cellLearning}\")\n        writer.println(\"Ichnaea settings: source=${settings.onlineSource?.id} endpoint=${settings.effectiveEndpoint} contribute=${settings.ichnaeaContribute}\")\n        ichnaea.dump(writer)\n        writer.println(\"GPS location buffer size=${gpsLocationBuffer.size} first=${gpsLocationBuffer.firstOrNull()?.elapsedMillis?.formatRealtime()} last=${gpsLocationBuffer.lastOrNull()?.elapsedMillis?.formatRealtime()}\")\n        database.dump(writer)\n        synchronized(activeRequests) {\n            if (activeRequests.isNotEmpty()) {\n                writer.println(\"Active requests:\")\n                for (request in activeRequests) {\n                    writer.println(\"- ${request.workSource} ${request.intervalMillis.formatDuration()} (low power: ${request.lowPower}, bypass: ${request.bypass}) reported ${request.lastRealtime.formatRealtime()}\")\n                }\n            }\n        }\n    }\n\n    companion object {\n        const val GPS_BUFFER_SIZE = 60\n        const val GPS_PASSIVE_INTERVAL = 1000L\n        const val GPS_PASSIVE_MIN_ACCURACY = 25f\n        const val LOCATION_TIME_CLIFF_START_MS = 30000L\n        const val LOCATION_TIME_CLIFF_END_MS = 60000L\n        const val DEBOUNCE_DELAY_MS = 5000L\n        const val MAX_WIFI_SCAN_CACHE_AGE = 1000L * 60 * 60 * 24 // 1 day\n        const val MAX_LOCAL_WIFI_AGE_MS = 60_000_000L // 1 minute\n        const val MAX_LOCAL_WIFI_SCAN_AGE_MS = 600_000_000L // 10 minutes\n        const val MOVING_WIFI_HIGH_POWER_ACCURACY = 100f\n    }\n}"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/network/cell/CellDetails.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.network.cell\n\nimport android.location.Location\nimport org.microg.gms.location.network.NetworkDetails\n\ndata class CellDetails(\n    val type: Type,\n    val mcc: Int? = null,\n    val mnc: Int? = null,\n    val lac: Int? = null,\n    val tac: Int? = null,\n    val cid: Long? = null,\n    val sid: Int? = null,\n    val nid: Int? = null,\n    val bsid: Int? = null,\n    val pscOrPci: Int? = null,\n    override val timestamp: Long? = null,\n    override val signalStrength: Int? = null,\n    val location: Location? = null\n) : NetworkDetails {\n    companion object {\n        enum class Type {\n            CDMA, GSM, WCDMA, LTE, TDSCDMA, NR\n        }\n    }\n}"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/network/cell/CellDetailsCallback.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.network.cell\n\ninterface CellDetailsCallback {\n    fun onCellDetailsAvailable(cells: List<CellDetails>)\n}"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/network/cell/CellDetailsSource.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.network.cell\n\nimport android.annotation.SuppressLint\nimport android.content.Context\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.WorkSource\nimport android.telephony.CellInfo\nimport android.telephony.TelephonyManager\nimport android.util.Log\nimport androidx.core.content.getSystemService\n\nprivate const val TAG = \"CellDetailsSource\"\n\nclass CellDetailsSource(private val context: Context, private val callback: CellDetailsCallback) {\n    fun enable() = Unit\n    fun disable() = Unit\n\n    @SuppressLint(\"MissingPermission\")\n    fun startScan(workSource: WorkSource?) {\n        val telephonyManager = context.getSystemService<TelephonyManager>() ?: return\n        if (SDK_INT >= 29) {\n            try {\n                telephonyManager.requestCellInfoUpdate(context.mainExecutor, object : TelephonyManager.CellInfoCallback() {\n                    override fun onCellInfo(cells: MutableList<CellInfo>) {\n                        val details = cells.map(CellInfo::toCellDetails).map { it.repair(context) }.filter(CellDetails::isValid)\n                        if (details.isNotEmpty()) callback.onCellDetailsAvailable(details)\n                    }\n                })\n            } catch (e: SecurityException) {\n                // It may trigger a SecurityException if the ACCESS_FINE_LOCATION permission isn't granted\n                Log.w(TAG, \"requestCellInfoUpdate in startScan failed\", e)\n            }\n\n            return\n        } else if (SDK_INT >= 17) {\n            val allCellInfo: List<CellInfo>? = try {\n                telephonyManager.allCellInfo\n            } catch (e: SecurityException) {\n                // It may trigger a SecurityException if the ACCESS_FINE_LOCATION permission isn't granted\n                Log.w(TAG, \"allCellInfo in startScan failed\", e)\n                null\n            }\n            if (allCellInfo != null) {\n                val details = allCellInfo.map(CellInfo::toCellDetails).map { it.repair(context) }.filter(CellDetails::isValid)\n                if (details.isNotEmpty()) {\n                    callback.onCellDetailsAvailable(details)\n                    return\n                }\n            }\n        }\n        val networkOperator = telephonyManager.networkOperator\n        if (networkOperator != null && networkOperator.length > 4) {\n            val mcc = networkOperator.substring(0, 3).toIntOrNull()\n            val mnc = networkOperator.substring(3).toIntOrNull()\n            val detail: CellDetails? = try {\n                telephonyManager.cellLocation?.toCellDetails(mcc, mnc)\n            } catch (e: SecurityException) {\n                // It may trigger a SecurityException if the ACCESS_FINE_LOCATION permission isn't granted\n                Log.w(TAG, \"cellLocation in startScan failed\", e)\n                null\n            }\n            if (detail?.isValid == true) callback.onCellDetailsAvailable(listOf(detail))\n        }\n    }\n\n    companion object {\n        fun create(context: Context, callback: CellDetailsCallback): CellDetailsSource = CellDetailsSource(context, callback)\n    }\n}\n"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/network/cell/extensions.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.network.cell\n\nimport android.content.Context\nimport android.location.Location\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.SystemClock\nimport android.telephony.CellIdentity\nimport android.telephony.CellIdentityCdma\nimport android.telephony.CellIdentityGsm\nimport android.telephony.CellIdentityLte\nimport android.telephony.CellIdentityNr\nimport android.telephony.CellIdentityTdscdma\nimport android.telephony.CellIdentityWcdma\nimport android.telephony.CellInfo\nimport android.telephony.CellInfoCdma\nimport android.telephony.CellInfoGsm\nimport android.telephony.CellInfoLte\nimport android.telephony.CellInfoTdscdma\nimport android.telephony.CellInfoWcdma\nimport android.telephony.CellLocation\nimport android.telephony.TelephonyManager\nimport android.telephony.cdma.CdmaCellLocation\nimport android.telephony.gsm.GsmCellLocation\nimport androidx.annotation.RequiresApi\nimport androidx.core.content.getSystemService\n\nprivate fun locationFromCdma(latitude: Int, longitude: Int) = if (latitude == Int.MAX_VALUE || longitude == Int.MAX_VALUE) null else Location(\"cdma\").also {\n    it.latitude = latitude.toDouble() / 14400.0\n    it.longitude = longitude.toDouble() / 14400.0\n    it.accuracy = 30000f\n}\n\nprivate fun CdmaCellLocation.toCellDetails(timestamp: Long? = null) = CellDetails(\n    type = CellDetails.Companion.Type.CDMA,\n    sid = systemId,\n    nid = networkId,\n    bsid = baseStationId,\n    location = locationFromCdma(baseStationLatitude, baseStationLongitude),\n    timestamp = timestamp\n)\n\nprivate fun GsmCellLocation.toCellDetails(mcc: Int? = null, mnc: Int? = null, timestamp: Long? = null) = CellDetails(\n    type = CellDetails.Companion.Type.GSM,\n    mcc = mcc,\n    mnc = mnc,\n    lac = lac.takeIf { it != Int.MAX_VALUE && it != -1 },\n    cid = cid.takeIf { it != Int.MAX_VALUE && it != -1 }?.toLong(),\n    pscOrPci = psc.takeIf { it != Int.MAX_VALUE && it != -1 },\n    timestamp = timestamp\n)\n\ninternal fun CellLocation.toCellDetails(mcc: Int? = null, mnc: Int? = null, timestamp: Long? = null) = when (this) {\n    is CdmaCellLocation -> toCellDetails(timestamp)\n    is GsmCellLocation -> toCellDetails(mcc, mnc, timestamp)\n    else -> throw IllegalArgumentException(\"Unknown CellLocation type\")\n}\n\nprivate fun CellIdentityCdma.toCellDetails() = CellDetails(\n    type = CellDetails.Companion.Type.CDMA,\n    sid = systemId,\n    nid = networkId,\n    bsid = basestationId,\n    location = locationFromCdma(latitude, longitude)\n)\n\nprivate fun CellIdentityGsm.toCellDetails() = CellDetails(\n    type = CellDetails.Companion.Type.GSM,\n    mcc = if (SDK_INT >= 28) mccString?.toIntOrNull() else mcc.takeIf { it != Int.MAX_VALUE && it != -1 },\n    mnc = if (SDK_INT >= 28) mncString?.toIntOrNull() else mnc.takeIf { it != Int.MAX_VALUE && it != -1 },\n    lac = lac.takeIf { it != Int.MAX_VALUE && it != -1 },\n    cid = cid.takeIf { it != Int.MAX_VALUE && it != -1 }?.toLong()\n)\n\nprivate fun CellIdentityWcdma.toCellDetails() = CellDetails(\n    type = CellDetails.Companion.Type.WCDMA,\n    mcc = if (SDK_INT >= 28) mccString?.toIntOrNull() else mcc.takeIf { it != Int.MAX_VALUE && it != -1 },\n    mnc = if (SDK_INT >= 28) mncString?.toIntOrNull() else mnc.takeIf { it != Int.MAX_VALUE && it != -1 },\n    lac = lac.takeIf { it != Int.MAX_VALUE && it != -1 },\n    cid = cid.takeIf { it != Int.MAX_VALUE && it != -1 }?.toLong(),\n    pscOrPci = psc.takeIf { it != Int.MAX_VALUE && it != -1 }\n)\n\nprivate fun CellIdentityLte.toCellDetails() = CellDetails(\n    type = CellDetails.Companion.Type.LTE,\n    mcc = if (SDK_INT >= 28) mccString?.toIntOrNull() else mcc.takeIf { it != Int.MAX_VALUE && it != -1 },\n    mnc = if (SDK_INT >= 28) mncString?.toIntOrNull() else mnc.takeIf { it != Int.MAX_VALUE && it != -1 },\n    tac = tac.takeIf { it != Int.MAX_VALUE && it != -1 },\n    cid = ci.takeIf { it != Int.MAX_VALUE && it != -1 }?.toLong(),\n    pscOrPci = pci.takeIf { it != Int.MAX_VALUE && it != -1 }\n)\n\n@RequiresApi(28)\nprivate fun CellIdentityTdscdma.toCellDetails() = CellDetails(\n    type = CellDetails.Companion.Type.TDSCDMA,\n    mcc = mccString?.toIntOrNull(),\n    mnc = mncString?.toIntOrNull(),\n    lac = lac.takeIf { it != Int.MAX_VALUE && it != -1 },\n    cid = cid.takeIf { it != Int.MAX_VALUE && it != -1 }?.toLong()\n)\n\n@RequiresApi(29)\nprivate fun CellIdentityNr.toCellDetails() = CellDetails(\n    type = CellDetails.Companion.Type.NR,\n    mcc = mccString?.toIntOrNull(),\n    mnc = mncString?.toIntOrNull(),\n    tac = tac.takeIf { it != Int.MAX_VALUE && it != -1 },\n    cid = nci.takeIf { it != Long.MAX_VALUE && it != -1L }\n)\n\n@RequiresApi(28)\ninternal fun CellIdentity.toCellDetails() = when {\n    this is CellIdentityCdma -> toCellDetails()\n    this is CellIdentityGsm -> toCellDetails()\n    this is CellIdentityWcdma -> toCellDetails()\n    this is CellIdentityLte -> toCellDetails()\n    this is CellIdentityTdscdma -> toCellDetails()\n    SDK_INT >= 29 && this is CellIdentityNr -> toCellDetails()\n    else -> throw IllegalArgumentException(\"Unknown CellIdentity type\")\n}\n\nprivate val CellInfo.epochTimestamp: Long\n    @RequiresApi(17)\n    get() = if (SDK_INT >= 30) System.currentTimeMillis() - (SystemClock.elapsedRealtime() - timestampMillis)\n    else System.currentTimeMillis() - (SystemClock.elapsedRealtimeNanos() - timeStamp)\n\n@RequiresApi(17)\ninternal fun CellInfo.toCellDetails() = when {\n    this is CellInfoCdma -> cellIdentity.toCellDetails().copy(timestamp = epochTimestamp, signalStrength = cellSignalStrength.dbm)\n    this is CellInfoGsm -> cellIdentity.toCellDetails().copy(timestamp = epochTimestamp, signalStrength = cellSignalStrength.dbm)\n    SDK_INT >= 18 && this is CellInfoWcdma -> cellIdentity.toCellDetails().copy(timestamp = epochTimestamp, signalStrength = cellSignalStrength.dbm)\n    this is CellInfoLte -> cellIdentity.toCellDetails().copy(timestamp = epochTimestamp, signalStrength = cellSignalStrength.dbm)\n    SDK_INT >= 29 && this is CellInfoTdscdma -> cellIdentity.toCellDetails().copy(timestamp = epochTimestamp, signalStrength = cellSignalStrength.dbm)\n    SDK_INT >= 30 -> cellIdentity.toCellDetails().copy(timestamp = epochTimestamp, signalStrength = cellSignalStrength.dbm)\n    else -> throw IllegalArgumentException(\"Unknown CellInfo type\")\n}\n\n/**\n * Fix a few known issues in Android's parsing of MNCs\n */\ninternal fun CellDetails.repair(context: Context): CellDetails {\n    if (type == CellDetails.Companion.Type.CDMA) return this\n    val networkOperator = context.getSystemService<TelephonyManager>()?.networkOperator ?: return this\n    if (networkOperator.length < 5) return this\n    val networkOperatorMnc = networkOperator.substring(3).toInt()\n    if (networkOperator[3] == '0' && mnc == null || networkOperator.length == 5 && mnc == networkOperatorMnc * 10 + 15)\n        return copy(mnc = networkOperatorMnc)\n    return this\n}\n\nval CellDetails.isValid: Boolean\n    get() = when (type) {\n        CellDetails.Companion.Type.CDMA -> sid != null && nid != null && bsid != null\n        else -> mcc != null && mnc != null && cid != null && (lac != null || tac != null)\n    }"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/network/extensions.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.network\n\nimport android.location.Location\nimport android.os.Bundle\nimport androidx.core.location.LocationCompat\nimport androidx.core.os.bundleOf\nimport java.security.MessageDigest\n\nconst val TAG = \"NetworkLocation\"\nconst val LOCATION_EXTRA_PRECISION = \"precision\"\n\nconst val PROVIDER_CACHE = \"cache\"\nconst val PROVIDER_CACHE_NEGATIVE = \"cache-\"\nval NEGATIVE_CACHE_ENTRY = Location(PROVIDER_CACHE_NEGATIVE)\n\ninternal operator fun <T> Bundle?.plus(pair: Pair<String, T>): Bundle = this + bundleOf(pair)\n\ninternal operator fun Bundle?.plus(other: Bundle): Bundle = when {\n    this == null -> other\n    else -> Bundle(this).apply { putAll(other) }\n}\n\ninternal var Location.precision: Double\n    get() = extras?.getDouble(LOCATION_EXTRA_PRECISION, 1.0) ?: 1.0\n    set(value) {\n        extras += LOCATION_EXTRA_PRECISION to value\n    }\n\ninternal var Location.verticalAccuracy: Float?\n    get() = if (LocationCompat.hasVerticalAccuracy(this)) LocationCompat.getVerticalAccuracyMeters(this) else null\n    set(value) = if (value == null) LocationCompat.removeVerticalAccuracy(this) else LocationCompat.setVerticalAccuracyMeters(this, value)\n\nfun ByteArray.toHexString(separator: String = \"\") : String = joinToString(separator) { \"%02x\".format(it) }\nfun ByteArray.digest(md: String): ByteArray = MessageDigest.getInstance(md).digest(this)"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/network/ichnaea/BluetoothBeacon.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.network.ichnaea\n\ndata class BluetoothBeacon(\n    /**\n     * The address of the Bluetooth Low Energy (BLE) beacon.\n     */\n    val macAddress: String? = null,\n    /**\n     * The name of the BLE beacon.\n     */\n    val name: String? = null,\n    /**\n     * The number of milliseconds since this BLE beacon was last seen.\n     */\n    val age: Long? = null,\n    /**\n     * The measured signal strength of the BLE beacon in dBm.\n     */\n    val signalStrength: Int? = null,\n)"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/network/ichnaea/CellTower.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.network.ichnaea\n\ndata class CellTower(\n    /**\n     * The type of radio network.\n     */\n    val radioType: RadioType? = null,\n    /**\n     * The mobile country code.\n     */\n    val mobileCountryCode: Int? = null,\n    /**\n     * The mobile network code.\n     */\n    val mobileNetworkCode: Int? = null,\n    /**\n     * The location area code for GSM and WCDMA networks. The tracking area code for LTE networks.\n     */\n    val locationAreaCode: Int? = null,\n    /**\n     * The cell id or cell identity.\n     */\n    val cellId: Int? = null,\n    /**\n     * The number of milliseconds since this networks was last detected.\n     */\n    val age: Long? = null,\n    /**\n     * The primary scrambling code for WCDMA and physical cell id for LTE.\n     */\n    val psc: Int? = null,\n    /**\n     * The signal strength for this cell network, either the RSSI or RSCP.\n     */\n    val signalStrength: Int? = null,\n    /**\n     * The timing advance value for this cell network.\n     */\n    val timingAdvance: Int? = null,\n)"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/network/ichnaea/Fallback.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.network.ichnaea\n\n/**\n * By default, both a GeoIP based position fallback and a fallback based on cell location areas (lac’s) are enabled. Omit the fallbacks section if you want to use the defaults. Change the values to false if you want to disable either of the fallbacks.\n */\ndata class Fallback(\n    /**\n     * If no exact cell match can be found, fall back from exact cell position estimates to more coarse grained cell location area estimates rather than going directly to an even worse GeoIP based estimate.\n     */\n    val lacf: Boolean? = null,\n    /**\n     * If no position can be estimated based on any of the provided data points, fall back to an estimate based on a GeoIP database based on the senders IP address at the time of the query.\n     */\n    val ipf: Boolean? = null\n)"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/network/ichnaea/GeolocateRequest.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.network.ichnaea\n\ndata class GeolocateRequest(\n    /**\n     * The clear text name of the cell carrier / operator.\n     */\n    val carrier: String? = null,\n    /**\n     * Should the clients IP address be used to locate it; defaults to true.\n     */\n    val considerIp: Boolean? = null,\n    /**\n     * The mobile country code stored on the SIM card.\n     */\n    val homeMobileCountryCode: Int? = null,\n    /**\n     * The mobile network code stored on the SIM card.\n     */\n    val homeMobileNetworkCode: Int? = null,\n    /**\n     * Same as the `radioType` entry in each cell record. If all the cell entries have the same `radioType`, it can be provided at the top level instead.\n     */\n    val radioType: RadioType? = null,\n    val bluetoothBeacons: List<BluetoothBeacon>? = null,\n    val cellTowers: List<CellTower>? = null,\n    val wifiAccessPoints: List<WifiAccessPoint>? = null,\n    /**\n     * By default, both a GeoIP based position fallback and a fallback based on cell location areas (lac’s) are enabled. Omit the fallbacks section if you want to use the defaults. Change the values to false if you want to disable either of the fallbacks.\n     */\n    val fallbacks: Fallback? = null,\n)"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/network/ichnaea/GeolocateResponse.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.network.ichnaea\n\ndata class GeolocateResponse(\n    val location: ResponseLocation? = null,\n    val horizontalAccuracy: Double? = null,\n    val fallback: String? = null,\n    val error: ResponseError? = null,\n\n    // Custom\n    val verticalAccuracy: Double? = null,\n    val raw: List<RawGeolocateEntry> = emptyList(),\n)"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/network/ichnaea/GeosubmitItem.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.network.ichnaea\n\ndata class GeosubmitItem(\n    /**\n     * The time of observation of the data, measured in milliseconds since the UNIX epoch. Can be omitted if the observation time is very recent. The age values in each section are relative to this timestamp.\n     */\n    val timestamp: Long? = null,\n    /**\n     * The position block contains information about where and when the data was observed.\n     */\n    val position: GeosubmitPosition? = null,\n    val bluetoothBeacons: List<BluetoothBeacon>? = null,\n    val cellTowers: List<CellTower>? = null,\n    val wifiAccessPoints: List<WifiAccessPoint>? = null,\n)"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/network/ichnaea/GeosubmitPosition.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.network.ichnaea\n\ndata class GeosubmitPosition(\n    /**\n     * The latitude of the observation (WSG 84).\n     */\n    val latitude: Double? = null,\n    /**\n     * The longitude of the observation (WSG 84).\n     */\n    val longitude: Double? = null,\n    /**\n     * The accuracy of the observed position in meters.\n     */\n    val accuracy: Double? = null,\n    /**\n     * The altitude at which the data was observed in meters above sea-level.\n     */\n    val altitude: Double? = null,\n    /**\n     * The accuracy of the altitude estimate in meters.\n     */\n    val altitudeAccuracy: Double? = null,\n    /**\n     * The age of the position data (in milliseconds).\n     */\n    val age: Long? = null,\n    /**\n     * The heading field denotes the direction of travel of the device and is specified in degrees, where 0° ≤ heading < 360°, counting clockwise relative to the true north.\n     */\n    val heading: Double? = null,\n    /**\n     * The air pressure in hPa (millibar).\n     */\n    val pressure: Double? = null,\n    /**\n     * The speed field denotes the magnitude of the horizontal component of the device’s current velocity and is specified in meters per second.\n     */\n    val speed: Double? = null,\n    /**\n     * The source of the position information. If the field is omitted, “gps” is assumed. The term gps is used to cover all types of satellite based positioning systems including Galileo and Glonass. Other possible values are manual for a position entered manually into the system and fused for a position obtained from a combination of other sensors or outside service queries.\n     */\n    val source: GeosubmitSource? = null,\n)"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/network/ichnaea/GeosubmitRequest.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.network.ichnaea\n\ndata class GeosubmitRequest(\n    val items: List<GeosubmitItem>? = null\n)"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/network/ichnaea/GeosubmitSource.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.network.ichnaea\n\nenum class GeosubmitSource {\n    GPS, MANUAL, FUSED;\n\n    override fun toString(): String {\n        return super.toString().lowercase()\n    }\n}"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/network/ichnaea/IchnaeaServiceClient.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.network.ichnaea\n\nimport android.content.Context\nimport android.content.pm.PackageManager\nimport android.location.Location\nimport android.net.Uri\nimport android.os.Bundle\nimport android.os.SystemClock\nimport android.util.Log\nimport androidx.collection.LruCache\nimport com.android.volley.VolleyError\nimport com.android.volley.toolbox.JsonObjectRequest\nimport com.android.volley.toolbox.Volley\nimport org.json.JSONObject\nimport org.microg.gms.location.LocationSettings\nimport org.microg.gms.location.formatRealtime\nimport org.microg.gms.location.network.*\nimport org.microg.gms.location.network.cell.CellDetails\nimport org.microg.gms.location.network.precision\nimport org.microg.gms.location.network.verticalAccuracy\nimport org.microg.gms.location.network.wifi.*\nimport org.microg.gms.location.provider.BuildConfig\nimport org.microg.gms.utils.singleInstanceOf\nimport java.io.PrintWriter\nimport java.nio.ByteBuffer\nimport java.util.LinkedList\nimport kotlin.coroutines.Continuation\nimport kotlin.coroutines.resume\nimport kotlin.coroutines.resumeWithException\nimport kotlin.coroutines.suspendCoroutine\nimport kotlin.math.min\n\nclass IchnaeaServiceClient(private val context: Context) {\n    private val queue = singleInstanceOf { Volley.newRequestQueue(context.applicationContext) }\n    private val settings = LocationSettings(context)\n    private val omitables = LinkedList<String>()\n    private val cache = LruCache<String, Location>(REQUEST_CACHE_SIZE)\n    private val start = SystemClock.elapsedRealtime()\n\n    private val hasTelephony by lazy {\n        context.packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)\n    }\n\n    private fun GeolocateRequest.hash(): ByteArray? {\n        if (cellTowers.isNullOrEmpty() && (wifiAccessPoints?.size ?: 0) < 3 || bluetoothBeacons?.isNotEmpty() == true) return null\n        val minAge = min(\n            cellTowers?.takeIf { it.isNotEmpty() }?.minOf { it.age?.takeIf { it > 0L } ?: 0L } ?: Long.MAX_VALUE,\n            wifiAccessPoints?.takeIf { it.isNotEmpty() }?.minOf { it.age?.takeIf { it > 0L } ?: 0L } ?: Long.MAX_VALUE\n        )\n        val buffer = ByteBuffer.allocate(8 + (cellTowers?.size ?: 0) * 23 + (wifiAccessPoints?.size ?: 0) * 8)\n        buffer.putInt(cellTowers?.size?: 0)\n        buffer.putInt(wifiAccessPoints?.size?: 0)\n        for (cell in cellTowers.orEmpty()) {\n            buffer.put(cell.radioType?.ordinal?.toByte() ?: -1)\n            buffer.putInt(cell.mobileCountryCode ?: -1)\n            buffer.putInt(cell.mobileNetworkCode ?: -1)\n            buffer.putInt(cell.locationAreaCode ?: -1)\n            buffer.putInt(cell.cellId ?: -1)\n            buffer.putInt(cell.psc ?: -1)\n            buffer.put(((cell.age?.let { it - minAge }?: 0L) / (60 * 1000)).toByte())\n            buffer.put(((cell.signalStrength ?: 0) / 20).toByte())\n        }\n        for (wifi in wifiAccessPoints.orEmpty()) {\n            buffer.put(wifi.macBytes)\n            buffer.put(((wifi.age?.let { it - minAge }?: 0L) / (60 * 1000)).toByte())\n            buffer.put(((wifi.signalStrength ?: 0) / 20).toByte())\n        }\n        return buffer.array().digest(\"SHA-256\")\n    }\n\n    fun isRequestable(wifi: WifiDetails): Boolean {\n        return wifi.isRequestable && !omitables.contains(wifi.macClean)\n    }\n\n    suspend fun retrieveMultiWifiLocation(wifis: List<WifiDetails>, rawHandler: ((WifiDetails, Location) -> Unit)? = null): Location? = geoLocate(\n        GeolocateRequest(\n            considerIp = !hasTelephony,\n            wifiAccessPoints = wifis.filter { isRequestable(it) }.map(WifiDetails::toWifiAccessPoint),\n            fallbacks = Fallback(lacf = false, ipf = false)\n        ),\n        rawWifiHandler = rawHandler\n    )?.apply {\n        precision = wifis.size.toDouble() / WIFI_BASE_PRECISION_COUNT\n    }\n\n    suspend fun retrieveSingleCellLocation(cell: CellDetails, rawHandler: ((CellDetails, Location) -> Unit)? = null): Location? = geoLocate(\n        GeolocateRequest(\n            considerIp = false,\n            radioType = cell.toCellTower().radioType,\n            homeMobileCountryCode = cell.toCellTower().mobileCountryCode,\n            homeMobileNetworkCode = cell.toCellTower().mobileNetworkCode,\n            cellTowers = listOf(cell.toCellTower()),\n            fallbacks = Fallback(\n                lacf = true,\n                ipf = false\n            )\n        ),\n        rawCellHandler = rawHandler\n    )?.apply {\n        precision = if (extras?.getString(LOCATION_EXTRA_FALLBACK) != null) CELL_FALLBACK_PRECISION else CELL_DEFAULT_PRECISION\n    }\n\n    private suspend fun geoLocate(\n        request: GeolocateRequest,\n        rawWifiHandler: ((WifiDetails, Location) -> Unit)? = null,\n        rawCellHandler: ((CellDetails, Location) -> Unit)? = null\n    ): Location? {\n        val requestHash = request.hash()\n        if (requestHash != null) {\n            val locationFromCache = cache[requestHash.toHexString()]\n            if (locationFromCache == NEGATIVE_CACHE_ENTRY) return null\n            if (locationFromCache != null) return Location(locationFromCache)\n        }\n        val response = rawGeoLocate(request)\n        Log.d(TAG, \"$request -> $response\")\n        for (entry in response.raw) {\n            if (entry.omit && entry.wifiAccessPoint?.macAddress != null) {\n                omitables.offer(entry.wifiAccessPoint.macAddress.lowercase().replace(\":\", \"\"))\n                if (omitables.size > OMITABLES_LIMIT) omitables.remove()\n                runCatching { rawWifiHandler?.invoke(entry.wifiAccessPoint.toWifiDetails(), NEGATIVE_CACHE_ENTRY) }\n            }\n            if (entry.omit && entry.cellTower?.radioType != null) {\n                runCatching { rawCellHandler?.invoke(entry.cellTower.toCellDetails(), NEGATIVE_CACHE_ENTRY) }\n            }\n            if (!entry.omit && entry.wifiAccessPoint?.macAddress != null && entry.location != null) {\n                val location = buildLocation(entry.location, entry.horizontalAccuracy, entry.verticalAccuracy).apply {\n                    precision = 1.0\n                }\n                runCatching { rawWifiHandler?.invoke(entry.wifiAccessPoint.toWifiDetails(), location) }\n            }\n            if (!entry.omit && entry.cellTower?.radioType != null && entry.location != null) {\n                val location = buildLocation(entry.location, entry.horizontalAccuracy, entry.verticalAccuracy).apply {\n                    precision = 1.0\n                }\n                runCatching { rawCellHandler?.invoke(entry.cellTower.toCellDetails(), location) }\n            }\n        }\n        val location = if (response.location != null) {\n            buildLocation(response.location, response.horizontalAccuracy, response.verticalAccuracy).apply {\n                if (response.fallback != null) extras = (extras ?: Bundle()).apply { putString(LOCATION_EXTRA_FALLBACK, response.fallback) }\n            }\n        } else if (response.error != null && response.error.code == 404) {\n            NEGATIVE_CACHE_ENTRY\n        } else if (response.error != null) {\n            throw ServiceException(response.error)\n        } else {\n            throw RuntimeException(\"Invalid response JSON\")\n        }\n        if (requestHash != null) {\n            cache[requestHash.toHexString()] = if (location == NEGATIVE_CACHE_ENTRY) NEGATIVE_CACHE_ENTRY else Location(location)\n        }\n        if (location == NEGATIVE_CACHE_ENTRY) return null\n        return location\n    }\n\n    private fun buildLocation(location: ResponseLocation, defaultHorizontalAccuracy: Double? = null, defaultVerticalAccuracy: Double? = null): Location {\n        return Location(PROVIDER).apply {\n            latitude = location.latitude\n            longitude = location.longitude\n            if (location.altitude != null) altitude = location.altitude\n            if (defaultHorizontalAccuracy != null && defaultHorizontalAccuracy > 0.0) accuracy = defaultHorizontalAccuracy.toFloat()\n            if (hasAltitude() && defaultVerticalAccuracy != null && defaultVerticalAccuracy > 0.0) verticalAccuracy = defaultVerticalAccuracy.toFloat()\n            if (location.horizontalAccuracy != null && location.horizontalAccuracy > 0.0) accuracy = location.horizontalAccuracy.toFloat()\n            if (hasAltitude() && location.verticalAccuracy != null && location.verticalAccuracy > 0.0) verticalAccuracy = location.verticalAccuracy.toFloat()\n            time = System.currentTimeMillis()\n        }\n    }\n\n    private fun getRequestHeaders(): Map<String, String> = buildMap {\n        set(\"User-Agent\", \"${BuildConfig.ICHNAEA_USER_AGENT} (Linux; Android ${android.os.Build.VERSION.RELEASE}; ${context.packageName})\")\n        if (settings.ichnaeaContribute) {\n            set(\"X-Ichnaea-Contribute-Opt-In\", \"1\")\n        }\n    }\n\n    private fun continueError(continuation: Continuation<GeolocateResponse>, error: VolleyError) {\n        try {\n            val response = JSONObject(error.networkResponse.data.decodeToString()).toGeolocateResponse()\n            if (response.error != null) {\n                continuation.resume(response)\n                return\n            } else if (response.location?.latitude != null){\n                Log.w(TAG, \"Received location in response with error code\")\n            } else {\n                Log.w(TAG, \"Received valid json without error in response with error code\")\n            }\n        } catch (_: Exception) {\n        }\n        if (error.networkResponse != null) {\n            continuation.resume(GeolocateResponse(error = ResponseError(error.networkResponse.statusCode, error.message)))\n            return\n        }\n        continuation.resumeWithException(error)\n    }\n\n    private suspend fun rawGeoLocate(request: GeolocateRequest): GeolocateResponse = suspendCoroutine { continuation ->\n        val url = Uri.parse(settings.effectiveEndpoint).buildUpon().appendPath(\"v1\").appendPath(\"geolocate\").build().toString()\n        queue.add(object : JsonObjectRequest(Method.POST, url, request.toJson(), {\n            try {\n                continuation.resume(it.toGeolocateResponse())\n            } catch (e: Exception) {\n                continuation.resumeWithException(e)\n            }\n        }, {\n            continueError(continuation, it)\n        }) {\n            override fun getHeaders(): Map<String, String> = getRequestHeaders()\n        })\n    }\n\n    private suspend fun rawGeoSubmit(request: GeosubmitRequest): Unit = suspendCoroutine { continuation ->\n        val url = Uri.parse(settings.effectiveEndpoint).buildUpon().appendPath(\"v2\").appendPath(\"geosubmit\").build().toString()\n        queue.add(object : JsonObjectRequest(Method.POST, url, request.toJson(), {\n            continuation.resume(Unit)\n        }, {\n            continuation.resumeWithException(it)\n        }) {\n            override fun getHeaders(): Map<String, String> = getRequestHeaders()\n        })\n    }\n\n    fun dump(writer: PrintWriter) {\n        writer.println(\"Ichnaea start=${start.formatRealtime()} omitables=${omitables.size}\")\n        writer.println(\"Ichnaea request cache size=${cache.size()} hits=${cache.hitCount()} miss=${cache.missCount()} puts=${cache.putCount()} evicts=${cache.evictionCount()}\")\n    }\n\n    private operator fun <K : Any, V : Any> LruCache<K, V>.set(key: K, value: V) {\n        put(key, value)\n    }\n\n    companion object {\n        private const val TAG = \"IchnaeaLocation\"\n        private const val PROVIDER = \"ichnaea\"\n        const val WIFI_BASE_PRECISION_COUNT = 4.0\n        const val CELL_DEFAULT_PRECISION = 1.0\n        const val CELL_FALLBACK_PRECISION = 0.5\n        private const val OMITABLES_LIMIT = 100\n        private const val REQUEST_CACHE_SIZE = 200\n        const val LOCATION_EXTRA_FALLBACK = \"fallback\"\n    }\n}"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/network/ichnaea/RadioType.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.network.ichnaea\n\nenum class RadioType {\n    GSM, WCDMA, LTE;\n\n    override fun toString(): String {\n        return super.toString().lowercase()\n    }\n}"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/network/ichnaea/RawGeolocateEntry.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.network.ichnaea\n\ndata class RawGeolocateEntry(\n    val timestamp: Long? = null,\n\n    val bluetoothBeacon: BluetoothBeacon? = null,\n    val cellTower: CellTower? = null,\n    val wifiAccessPoint: WifiAccessPoint? = null,\n\n    val location: ResponseLocation? = null,\n    val horizontalAccuracy: Double? = null,\n    val verticalAccuracy: Double? = null,\n\n    val omit: Boolean = false,\n)\n"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/network/ichnaea/ResponseError.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.network.ichnaea\n\ndata class ResponseError(\n    val code: Int? = null,\n    val message: String? = null\n)"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/network/ichnaea/ResponseLocation.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.network.ichnaea\n\ndata class ResponseLocation(\n    val latitude: Double,\n    val longitude: Double,\n\n    // Custom\n    val horizontalAccuracy: Double? = null,\n    val altitude: Double? = null,\n    val verticalAccuracy: Double? = null\n)"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/network/ichnaea/ServiceException.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.network.ichnaea\n\nclass ServiceException(val error: ResponseError) : Exception(error.message)"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/network/ichnaea/WifiAccessPoint.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.network.ichnaea\n\ndata class WifiAccessPoint(\n    /**\n     * The BSSID of the WiFi network.\n     */\n    val macAddress: String,\n    /**\n     * The number of milliseconds since this network was last detected.\n     */\n    val age: Long? = null,\n    /**\n     * The WiFi channel for networks in the 2.4GHz range. This often ranges from 1 to 13.\n     */\n    val channel: Int? = null,\n    /**\n     * The frequency in MHz of the channel over which the client is communicating with the access point.\n     */\n    val frequency: Int? = null,\n    /**\n     * The received signal strength (RSSI) in dBm.\n     */\n    val signalStrength: Int? = null,\n    /**\n     * The current signal to noise ratio measured in dB.\n     */\n    val signalToNoiseRatio: Int? = null,\n    /**\n     * The SSID of the Wifi network.\n     */\n    val ssid: String? = null\n) {\n    init {\n        if (ssid != null && ssid.endsWith(\"_nomap\")) throw IllegalArgumentException(\"Wifi networks with a SSID ending in _nomap must not be collected.\")\n    }\n}"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/network/ichnaea/extensions.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.network.ichnaea\n\nimport org.json.JSONArray\nimport org.json.JSONException\nimport org.json.JSONObject\nimport org.microg.gms.location.network.cell.CellDetails\nimport org.microg.gms.location.network.wifi.WifiDetails\n\nprivate fun JSONObject.getDouble(vararg names: String): Double {\n    for (name in names) {\n        if (has(name)) return getDouble(name)\n    }\n    throw JSONException(\"Values are all null: ${names.joinToString(\", \")}\")\n}\n\nprivate fun JSONObject.getInt(vararg names: String): Int {\n    for (name in names) {\n        if (has(name)) return getInt(name)\n    }\n    throw JSONException(\"Values are all null: ${names.joinToString(\", \")}\")\n}\n\nprivate fun JSONObject.getString(vararg names: String): String {\n    for (name in names) {\n        if (has(name)) return getString(name)\n    }\n    throw JSONException(\"Values are all null: ${names.joinToString(\", \")}\")\n}\n\nprivate fun JSONObject.optDouble(vararg names: String): Double? {\n    for (name in names) {\n        if (has(name)) optDouble(name).takeIf { it.isFinite() }?.let { return it }\n    }\n    return null\n}\n\nprivate fun JSONObject.optInt(vararg names: String): Int? {\n    for (name in names) {\n        runCatching { if (has(name)) return getInt(name) }\n    }\n    return null\n}\n\nprivate fun JSONObject.optLong(vararg names: String): Long? {\n    for (name in names) {\n        runCatching { if (has(name)) return getLong(name) }\n    }\n    return null\n}\n\nprivate fun JSONObject.optString(vararg names: String): String? {\n    for (name in names) {\n        if (has(name)) return optString(name)\n    }\n    return null\n}\n\ninternal fun CellDetails.toCellTower() = CellTower(\n    radioType = when (type) {\n        CellDetails.Companion.Type.GSM -> RadioType.GSM\n        CellDetails.Companion.Type.WCDMA -> RadioType.WCDMA\n        CellDetails.Companion.Type.LTE -> RadioType.LTE\n        else -> throw IllegalArgumentException(\"Unsupported radio type\")\n    },\n    mobileCountryCode = mcc,\n    mobileNetworkCode = mnc,\n    locationAreaCode = lac ?: tac,\n    cellId = cid?.toInt(),\n    age = timestamp?.let { System.currentTimeMillis() - it },\n    psc = pscOrPci,\n    signalStrength = signalStrength\n)\n\ninternal fun CellTower.toCellDetails() = CellDetails(\n    type = when(radioType) {\n        RadioType.GSM -> CellDetails.Companion.Type.GSM\n        RadioType.WCDMA -> CellDetails.Companion.Type.WCDMA\n        RadioType.LTE -> CellDetails.Companion.Type.LTE\n        else -> throw IllegalArgumentException(\"Unsupported radio type\")\n    },\n    mcc = mobileNetworkCode,\n    mnc = mobileNetworkCode,\n    lac = locationAreaCode,\n    tac = locationAreaCode,\n    cid = cellId?.toLong(),\n    pscOrPci = psc,\n    signalStrength = signalStrength\n)\n\ninternal fun WifiDetails.toWifiAccessPoint() = WifiAccessPoint(\n    macAddress = macAddress,\n    age = timestamp?.let { System.currentTimeMillis() - it },\n    channel = channel,\n    frequency = frequency,\n    signalStrength = signalStrength,\n    ssid = ssid\n)\n\ninternal fun WifiAccessPoint.toWifiDetails() = WifiDetails(\n    macAddress = macAddress,\n    channel = channel,\n    frequency = frequency,\n    signalStrength = signalStrength,\n    ssid = ssid,\n)\n\ninternal fun JSONObject.toGeolocateResponse() = GeolocateResponse(\n    location = optJSONObject(\"location\")?.toResponseLocation(),\n    horizontalAccuracy = optDouble(\"accuracy\", \"acc\", \"horizontalAccuracy\"),\n    verticalAccuracy = optDouble(\"altAccuracy\", \"altitudeAccuracy\", \"verticalAccuracy\"),\n    fallback = optString(\"fallback\").takeIf { it.isNotEmpty() },\n    raw = optJSONArray(\"raw\")?.toRawGeolocateEntries().orEmpty(),\n    error = optJSONObject(\"error\")?.toResponseError()\n)\n\ninternal fun GeolocateRequest.toJson() = JSONObject().apply {\n    if (carrier != null) put(\"carrier\", carrier)\n    if (considerIp != null) put(\"considerIp\", considerIp)\n    if (homeMobileCountryCode != null) put(\"homeMobileCountryCode\", homeMobileCountryCode)\n    if (homeMobileNetworkCode != null) put(\"homeMobileNetworkCode\", homeMobileNetworkCode)\n    if (radioType != null) put(\"radioType\", radioType.toString())\n    if (!bluetoothBeacons.isNullOrEmpty()) put(\"bluetoothBeacons\", JSONArray(bluetoothBeacons.map(BluetoothBeacon::toJson)))\n    if (!cellTowers.isNullOrEmpty()) put(\"cellTowers\", JSONArray(cellTowers.map(CellTower::toJson)))\n    if (!wifiAccessPoints.isNullOrEmpty()) put(\"wifiAccessPoints\", JSONArray(wifiAccessPoints.map(WifiAccessPoint::toJson)))\n    if (fallbacks != null) put(\"fallbacks\", fallbacks.toJson())\n}\n\ninternal fun GeosubmitRequest.toJson() = JSONObject().apply {\n    if (items != null) put(\"items\", JSONArray(items.map(GeosubmitItem::toJson)))\n}\n\nprivate fun GeosubmitItem.toJson() = JSONObject().apply {\n    if (timestamp != null) put(\"timestamp\", timestamp)\n    if (position != null) put(\"position\", position.toJson())\n    if (!bluetoothBeacons.isNullOrEmpty()) put(\"bluetoothBeacons\", JSONArray(bluetoothBeacons.map(BluetoothBeacon::toJson)))\n    if (!cellTowers.isNullOrEmpty()) put(\"cellTowers\", JSONArray(cellTowers.map(CellTower::toJson)))\n    if (!wifiAccessPoints.isNullOrEmpty()) put(\"wifiAccessPoints\", JSONArray(wifiAccessPoints.map(WifiAccessPoint::toJson)))\n}\n\nprivate fun GeosubmitPosition.toJson() = JSONObject().apply {\n    if (latitude != null) put(\"latitude\", latitude)\n    if (longitude != null) put(\"longitude\", longitude)\n    if (accuracy != null) put(\"accuracy\", accuracy)\n    if (altitude != null) put(\"altitude\", altitude)\n    if (altitudeAccuracy != null) put(\"altitudeAccuracy\", altitudeAccuracy)\n    if (age != null) put(\"age\", age)\n    if (heading != null) put(\"heading\", heading)\n    if (pressure != null) put(\"pressure\", pressure)\n    if (speed != null) put(\"speed\", speed)\n    if (source != null) put(\"source\", source.toString())\n}\n\nprivate fun JSONObject.toResponseLocation() = ResponseLocation(\n    latitude = getDouble(\"lat\", \"latitude\"),\n    longitude = getDouble(\"lng\", \"longitude\"),\n    altitude = optDouble(\"alt\", \"altitude\"),\n    horizontalAccuracy = optDouble(\"acc\", \"accuracy\", \"horizontalAccuracy\"),\n    verticalAccuracy = optDouble(\"altAccuracy\", \"altitudeAccuracy\", \"verticalAccuracy\"),\n)\n\nprivate fun JSONObject.toResponseError() = ResponseError(\n    code = optInt(\"code\", \"errorCode\", \"statusCode\"),\n    message = optString(\"message\", \"msg\", \"statusText\")\n)\n\nprivate fun JSONArray.toRawGeolocateEntries(): List<RawGeolocateEntry> =\n    (0 until length()).mapNotNull { optJSONObject(it)?.toRawGeolocateEntry() }\n\nprivate fun JSONObject.toRawGeolocateEntry() = RawGeolocateEntry(\n    timestamp = optLong(\"time\", \"timestamp\"),\n    bluetoothBeacon = optJSONObject(\"bluetoothBeacon\")?.toBluetoothBeacon(),\n    cellTower = optJSONObject(\"cellTower\")?.toCellTower(),\n    wifiAccessPoint = optJSONObject(\"wifiAccessPoint\")?.toWifiAccessPoint(),\n    location = optJSONObject(\"location\")?.toResponseLocation(),\n    horizontalAccuracy = optDouble(\"acc\", \"accuracy\", \"horizontalAccuracy\"),\n    verticalAccuracy = optDouble(\"altAccuracy\", \"altitudeAccuracy\", \"verticalAccuracy\"),\n    omit = optBoolean(\"omit\")\n)\n\nprivate fun JSONObject.toBluetoothBeacon() = BluetoothBeacon(\n    macAddress = getString(\"macAddress\", \"mac\", \"address\"),\n    name = optString(\"name\"),\n)\n\nprivate fun JSONObject.toCellTower() = CellTower(\n    radioType = optString(\"radioType\", \"radio\", \"type\")?.let { runCatching { RadioType.valueOf(it.uppercase()) }.getOrNull() },\n    mobileCountryCode = optInt(\"mobileCountryCode\", \"mcc\"),\n    mobileNetworkCode = optInt(\"mobileNetworkCode\", \"mnc\"),\n    locationAreaCode = optInt(\"locationAreaCode\", \"lac\", \"trackingAreaCode\", \"tac\"),\n    cellId = optInt(\"cellId\", \"cellIdentity\", \"cid\"),\n    psc = optInt(\"psc\", \"primaryScramblingCode\", \"physicalCellId\", \"pci\"),\n)\n\nprivate fun JSONObject.toWifiAccessPoint() = WifiAccessPoint(\n    macAddress = getString(\"macAddress\", \"mac\", \"bssid\", \"address\"),\n    channel = optInt(\"channel\", \"chan\"),\n    frequency = optInt(\"frequency\", \"freq\"),\n    ssid = optString(\"ssid\"),\n)\n\nprivate fun BluetoothBeacon.toJson() = JSONObject().apply {\n    if (macAddress != null) put(\"macAddress\", macAddress)\n    if (name != null) put(\"name\", name)\n    if (age != null) put(\"age\", age)\n    if (signalStrength != null) put(\"signalStrength\", signalStrength)\n}\n\nprivate fun CellTower.toJson() = JSONObject().apply {\n    if (radioType != null) put(\"radioType\", radioType.toString())\n    if (mobileCountryCode != null) put(\"mobileCountryCode\", mobileCountryCode)\n    if (mobileNetworkCode != null) put(\"mobileNetworkCode\", mobileNetworkCode)\n    if (locationAreaCode != null) put(\"locationAreaCode\", locationAreaCode)\n    if (cellId != null) put(\"cellId\", cellId)\n    if (age != null) put(\"age\", age)\n    if (psc != null) put(\"psc\", psc)\n    if (signalStrength != null) put(\"signalStrength\", signalStrength)\n    if (timingAdvance != null) put(\"timingAdvance\", timingAdvance)\n}\n\nprivate fun WifiAccessPoint.toJson() = JSONObject().apply {\n    put(\"macAddress\", macAddress)\n    if (age != null) put(\"age\", age)\n    if (channel != null) put(\"channel\", channel)\n    if (frequency != null) put(\"frequency\", frequency)\n    if (signalStrength != null) put(\"signalStrength\", signalStrength)\n    if (signalToNoiseRatio != null) put(\"signalToNoiseRatio\", signalToNoiseRatio)\n    if (ssid != null) put(\"ssid\", ssid)\n}\n\nval WifiAccessPoint.macClean: String\n    get() = macAddress.lowercase().replace(\":\", \"\")\n\nval WifiAccessPoint.macBytes: ByteArray\n    get() {\n        val mac = macClean\n        return byteArrayOf(\n            mac.substring(0, 2).toInt(16).toByte(),\n            mac.substring(2, 4).toInt(16).toByte(),\n            mac.substring(4, 6).toInt(16).toByte(),\n            mac.substring(6, 8).toInt(16).toByte(),\n            mac.substring(8, 10).toInt(16).toByte(),\n            mac.substring(10, 12).toInt(16).toByte()\n        )\n    }\n\nval GeolocateRequest.isWifiOnly: Boolean\n    get() = bluetoothBeacons.isNullOrEmpty() && cellTowers.isNullOrEmpty() && wifiAccessPoints?.isNotEmpty() == true\n\nval GeolocateRequest.isCellOnly: Boolean\n    get() = bluetoothBeacons.isNullOrEmpty() && wifiAccessPoints.isNullOrEmpty() && cellTowers?.isNotEmpty() == true\n\nprivate fun Fallback.toJson() = JSONObject().apply {\n    if (lacf != null) put(\"lacf\", lacf)\n    if (ipf != null) put(\"ipf\", ipf)\n}"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/network/wifi/MovingWifiHelper.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.network.wifi\n\nimport android.content.Context\nimport android.location.Location\nimport android.net.ConnectivityManager\nimport android.net.ConnectivityManager.TYPE_WIFI\nimport android.os.Build.VERSION.SDK_INT\nimport android.util.Log\nimport androidx.core.content.getSystemService\nimport androidx.core.location.LocationCompat\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\nimport org.json.JSONArray\nimport org.json.JSONObject\nimport org.microg.gms.location.network.TAG\nimport java.net.HttpURLConnection\nimport java.net.Proxy\nimport java.net.URL\nimport java.security.KeyStore\nimport java.security.cert.*\nimport java.text.SimpleDateFormat\nimport java.util.*\nimport javax.net.ssl.HttpsURLConnection\nimport javax.net.ssl.SSLContext\nimport javax.net.ssl.TrustManager\nimport javax.net.ssl.TrustManagerFactory\nimport javax.net.ssl.X509TrustManager\n\n\nprivate val MOVING_WIFI_HOTSPOTS = setOf(\n    // Austria\n    \"OEBB\",\n    \"Austrian FlyNet\",\n    \"svciob\", // OEBB Service WIFI\n    // Belgium\n    \"THALYSNET\",\n    // Canada\n    \"Air Canada\",\n    \"ACWiFi\",\n    \"ACWiFi.com\",\n    // Colombia\n    \"avianca\",\n    \"avaincaonair.com\",\n    // Czech Republic\n    \"CDWiFi\",\n    // France\n    \"_SNCF_WIFI_INOUI\",\n    \"_SNCF_WIFI_INTERCITES\",\n    \"_WIFI_LYRIA\",\n    \"OUIFI\",\n    \"NormandieTrainConnecte\",\n    // Germany\n    \"WIFIonICE\",\n    \"WIFI@DB\",\n    \"WiFi@DB\",\n    \"RRX Hotspot\",\n    \"FlixBux\",\n    \"FlixBus Wi-Fi\",\n    \"FlixTrain Wi-Fi\",\n    \"FlyNet\",\n    \"Telekom_FlyNet\",\n    \"Vestische WLAN\",\n    \"agilis-Wifi\",\n    \"freeWIFIahead!\",\n    // Greece\n    \"AegeanWiFi\",\n    // Hong Kong\n    \"Cathay Pacific\",\n    // Hungary\n    \"MAVSTART-WIFI\",\n    // Netherlands\n    \"KEOLIS Nederland\",\n    // New Zealand\n    \"AirNZ_InflightWiFi\",\n    \"Bluebridge WiFi\",\n    // Portugal\n    \"TAP Air Portugal\",\n    // Singapore\n    \"KrisWorld\",\n    // Sweden\n    \"SJ\",\n    \"saswifi\",\n    // Switzerland\n    \"SBB-Free\",\n    \"SBB-FREE\",\n    \"SWISS Connect\",\n    \"Edelweiss Entertainment\",\n    // Thailand\n    \"THAI Wireless IFE\",\n    // United Kingdom\n    \"Avanti_Free_WiFi\",\n    \"CrossCountryWiFi\",\n    \"GWR WiFi\",\n    \"LNR On Board Wi-Fi\",\n    \"LOOP on train WiFi\",\n    \"WMR On Board Wi-Fi\",\n    \"EurostarTrainsWiFi\",\n    // United States\n    \"Amtrak_WiFi\",\n)\n\nprivate val PHONE_HOTSPOT_KEYWORDS = setOf(\n    \"iPhone\",\n    \"Galaxy\",\n    \"AndroidAP\"\n)\n\n/**\n * A Wi-Fi hotspot that changes its location dynamically and thus is unsuitable for use with location services that assume stable locations.\n *\n * Some moving Wi-Fi hotspots allow to determine their location when connected or through a public network API.\n */\nval WifiDetails.isMoving: Boolean\n    get() {\n        if (MOVING_WIFI_HOTSPOTS.contains(ssid)) {\n            return true\n        }\n        if (PHONE_HOTSPOT_KEYWORDS.any { ssid?.contains(it) == true }) {\n            return true\n        }\n        return false\n    }\n\nconst val FEET_TO_METERS = 0.3048\nconst val KNOTS_TO_METERS_PER_SECOND = 0.5144\nconst val MILES_PER_HOUR_TO_METERS_PER_SECOND = 0.447\n\nclass MovingWifiHelper(private val context: Context) {\n    suspend fun retrieveMovingLocation(current: WifiDetails): Location {\n        if (!isLocallyRetrievable(current)) throw IllegalArgumentException()\n        val connectivityManager = context.getSystemService<ConnectivityManager>() ?: throw IllegalStateException()\n        val sources = MOVING_WIFI_HOTSPOTS_LOCALLY_RETRIEVABLE[current.ssid]!!\n        val exceptions = mutableListOf<Exception>()\n        for (source in sources) {\n            try {\n                val url = URL(source.url)\n                return withContext(Dispatchers.IO) {\n                    val network = if (isLocallyRetrievable(current) && SDK_INT >= 23) {\n                        @Suppress(\"DEPRECATION\")\n                        (connectivityManager.allNetworks.singleOrNull {\n                            val networkInfo = connectivityManager.getNetworkInfo(it)\n                            networkInfo?.type == TYPE_WIFI && networkInfo.isConnected\n                        })\n                    } else {\n                        null\n                    }\n                    val connection = (if (SDK_INT >= 23) {\n                        network?.openConnection(url, Proxy.NO_PROXY)\n                    } else {\n                        null\n                    } ?: url.openConnection()) as HttpURLConnection\n                    try {\n                        connection.doInput = true\n                        if (connection is HttpsURLConnection && SDK_INT >= 24) {\n                            try {\n                                val ctx = SSLContext.getInstance(\"TLS\")\n                                val tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())\n                                fun wrap(originalTrustManager: TrustManager): TrustManager {\n                                    if (originalTrustManager is X509TrustManager) {\n                                        return object : X509TrustManager {\n                                            override fun checkClientTrusted(chain: Array<out X509Certificate>?, authType: String?) {\n                                                Log.d(TAG, \"checkClientTrusted: $chain, $authType\")\n                                                originalTrustManager.checkClientTrusted(chain, authType)\n                                            }\n\n                                            override fun checkServerTrusted(chain: Array<out X509Certificate>?, authType: String?) {\n                                                Log.d(TAG, \"checkServerTrusted: $chain, $authType\")\n                                                originalTrustManager.checkServerTrusted(chain, authType)\n                                            }\n\n                                            override fun getAcceptedIssuers(): Array<X509Certificate> {\n                                                return originalTrustManager.acceptedIssuers\n                                            }\n                                        }\n                                    } else {\n                                        return originalTrustManager\n                                    }\n                                }\n                                val ks = KeyStore.getInstance(\"AndroidCAStore\")\n                                ks.load(null, null)\n                                tmf.init(ks)\n                                ctx.init(null, tmf.trustManagers.map(::wrap).toTypedArray(), null)\n                                connection.sslSocketFactory = ctx.socketFactory\n                            } catch (e: Exception) {\n                                Log.w(TAG, \"Failed to disable revocation\", e)\n                            }\n                        }\n                        if (connection.responseCode != 200) throw RuntimeException(\"Got error\")\n                        val location = Location(current.ssid ?: \"wifi\")\n                        source.parse(location, connection.inputStream.readBytes())\n                    } finally {\n                        connection.inputStream.close()\n                        connection.disconnect()\n                    }\n                }\n            } catch (e: Exception) {\n                exceptions.add(e)\n            }\n        }\n        if (exceptions.size == 1) throw exceptions.single()\n        throw RuntimeException(exceptions.joinToString(\"\\n\"))\n    }\n\n    fun isLocallyRetrievable(wifi: WifiDetails): Boolean =\n        MOVING_WIFI_HOTSPOTS_LOCALLY_RETRIEVABLE.containsKey(wifi.ssid)\n\n    companion object {\n        abstract class MovingWifiLocationSource(val url: String) {\n            abstract fun parse(location: Location, data: ByteArray): Location\n        }\n\n        private val SOURCE_WIFI_ON_ICE = object : MovingWifiLocationSource(\"https://iceportal.de/api1/rs/status\") {\n            override fun parse(location: Location, data: ByteArray): Location {\n                val json = JSONObject(data.decodeToString())\n                if (json.getString(\"gpsStatus\") != \"VALID\") throw RuntimeException(\"GPS not valid\")\n                location.accuracy = 100f\n                location.time = json.getLong(\"serverTime\") - 15000L\n                location.latitude = json.getDouble(\"latitude\")\n                location.longitude = json.getDouble(\"longitude\")\n                json.optDouble(\"speed\").takeIf { !it.isNaN() }?.let {\n                    location.speed = (it / 3.6).toFloat()\n                    LocationCompat.setSpeedAccuracyMetersPerSecond(location, location.speed * 0.1f)\n                }\n                return location\n            }\n        }\n\n        private val SOURCE_OEBB_1 = object : MovingWifiLocationSource(\"https://railnet.oebb.at/assets/modules/fis/combined.json\") {\n            override fun parse(location: Location, data: ByteArray): Location {\n                val json = JSONObject(data.decodeToString()).getJSONObject(\"latestStatus\")\n                location.accuracy = 100f\n                runCatching { SimpleDateFormat(\"yyyy-MM-dd'T'HH:mm:ssZ\", Locale.US).parse(json.getString(\"dateTime\"))?.time }.getOrNull()?.let { location.time = it }\n                location.latitude = json.getJSONObject(\"gpsPosition\").getDouble(\"latitude\")\n                location.longitude = json.getJSONObject(\"gpsPosition\").getDouble(\"longitude\")\n                json.getJSONObject(\"gpsPosition\").optDouble(\"orientation\").takeIf { !it.isNaN() }?.let {\n                    location.bearing = it.toFloat()\n                    LocationCompat.setBearingAccuracyDegrees(location, 90f)\n                }\n                json.optDouble(\"speed\").takeIf { !it.isNaN() }?.let {\n                    location.speed = (it / 3.6).toFloat()\n                    LocationCompat.setSpeedAccuracyMetersPerSecond(location, location.speed * 0.1f)\n                }\n                return location\n            }\n        }\n\n        private val SOURCE_OEBB_2 = object : MovingWifiLocationSource(\"https://railnet.oebb.at/api/gps\") {\n            override fun parse(location: Location, data: ByteArray): Location {\n                val root = JSONObject(data.decodeToString())\n                if (root.has(\"JSON\")) {\n                    val json = root.getJSONObject(\"JSON\")\n                    if (!json.isNull(\"error\")) throw RuntimeException(\"Error: ${json.get(\"error\")}\");\n                    location.accuracy = 100f\n                    location.latitude = json.getDouble(\"lat\")\n                    location.longitude = json.getDouble(\"lon\")\n                    json.optDouble(\"speed\").takeIf { !it.isNaN() }?.let {\n                        location.speed = (it / 3.6).toFloat()\n                        LocationCompat.setSpeedAccuracyMetersPerSecond(location, location.speed * 0.1f)\n                    }\n                } else if (root.optDouble(\"Latitude\").let { !it.isNaN() && it.isFinite() && it > 0.1 }) {\n                    location.accuracy = 100f\n                    location.latitude = root.getDouble(\"Latitude\")\n                    location.longitude = root.getDouble(\"Longitude\")\n                } else {\n                    throw RuntimeException(\"Unsupported: $root\")\n                }\n                return location\n            }\n        }\n\n        private val SOURCE_FLIXBUS = object : MovingWifiLocationSource(\"https://media.flixbus.com/services/pis/v1/position\") {\n            override fun parse(location: Location, data: ByteArray): Location {\n                val json = JSONObject(data.decodeToString())\n                location.accuracy = 100f\n                location.latitude = json.getDouble(\"latitude\")\n                location.longitude = json.getDouble(\"longitude\")\n                json.optDouble(\"speed\").takeIf { !it.isNaN() }?.let {\n                    location.speed = it.toFloat()\n                    LocationCompat.setSpeedAccuracyMetersPerSecond(location, location.speed * 0.1f)\n                }\n                return location\n            }\n        }\n\n        class PassengeraLocationSource(base: String) : MovingWifiLocationSource(\"$base/portal/api/vehicle/realtime\") {\n            override fun parse(location: Location, data: ByteArray): Location {\n                val json = JSONObject(data.decodeToString())\n                location.accuracy = 100f\n                location.latitude = json.getDouble(\"gpsLat\")\n                location.longitude = json.getDouble(\"gpsLng\")\n                json.optDouble(\"speed\").takeIf { !it.isNaN() }?.let {\n                    location.speed = (it / 3.6).toFloat()\n                    LocationCompat.setSpeedAccuracyMetersPerSecond(location, location.speed * 0.1f)\n                }\n                json.optDouble(\"altitude\").takeIf { !it.isNaN() }?.let { location.altitude = it }\n                return location\n            }\n        }\n        private val SOURCE_PASSENGERA_MAV = PassengeraLocationSource(\"http://portal.mav.hu\")\n        private val SOURCE_PASSENGERA_CD = PassengeraLocationSource(\"http://cdwifi.cz\")\n\n        private val SOURCE_DISPLAY_UGO = object : MovingWifiLocationSource(\"https://api.ife.ugo.aero/navigation/positions\") {\n            override fun parse(location: Location, data: ByteArray): Location {\n                val json = JSONArray(data.decodeToString()).getJSONObject(0)\n                location.accuracy = 100f\n                location.latitude = json.getDouble(\"latitude\")\n                location.longitude = json.getDouble(\"longitude\")\n                runCatching { SimpleDateFormat(\"yyyy-MM-dd'T'HH:mm:ssZ\", Locale.US).parse(json.getString(\"created_at\"))?.time }.getOrNull()?.let { location.time = it }\n                json.optDouble(\"speed_kilometers_per_hour\").takeIf { !it.isNaN() }?.let {\n                    location.speed = (it / 3.6).toFloat()\n                    LocationCompat.setSpeedAccuracyMetersPerSecond(location, location.speed * 0.1f)\n                }\n                json.optDouble(\"altitude_meters\").takeIf { !it.isNaN() }?.let { location.altitude = it }\n                json.optDouble(\"bearing_in_degree\").takeIf { !it.isNaN() }?.let {\n                    location.bearing = it.toFloat()\n                    LocationCompat.setBearingAccuracyDegrees(location, 90f)\n                }\n                return location\n            }\n        }\n\n        private val SOURCE_INFLIGHT_PANASONIC = object : MovingWifiLocationSource(\"https://services.inflightpanasonic.aero/inflight/services/flightdata/v2/flightdata\") {\n            override fun parse(location: Location, data: ByteArray): Location {\n                val json = JSONObject(data.decodeToString())\n                location.accuracy = 100f\n                location.latitude = json.getJSONObject(\"current_coordinates\").getDouble(\"latitude\")\n                location.longitude = json.getJSONObject(\"current_coordinates\").getDouble(\"longitude\")\n                json.optDouble(\"ground_speed_knots\").takeIf { !it.isNaN() }?.let {\n                    location.speed = (it * KNOTS_TO_METERS_PER_SECOND).toFloat()\n                    LocationCompat.setSpeedAccuracyMetersPerSecond(location, location.speed * 0.1f)\n                }\n                json.optDouble(\"altitude_feet\").takeIf { !it.isNaN() }?.let { location.altitude = it * FEET_TO_METERS }\n                json.optDouble(\"true_heading_degree\").takeIf { !it.isNaN() }?.let {\n                    location.bearing = it.toFloat()\n                    LocationCompat.setBearingAccuracyDegrees(location, 90f)\n                }\n                return location\n            }\n        }\n\n        class BoardConnectLocationSource(base: String) : MovingWifiLocationSource(\"$base/map/api/flightData\") {\n            override fun parse(location: Location, data: ByteArray): Location {\n                val json = JSONObject(data.decodeToString())\n                location.accuracy = 100f\n                location.latitude = json.getDouble(\"lat\")\n                location.longitude = json.getDouble(\"lon\")\n                runCatching { SimpleDateFormat(\"yyyy-MM-dd'T'HH:mm:ssZ\", Locale.US).parse(json.getString(\"utc\"))?.time }.getOrNull()?.let { location.time = it }\n                json.optDouble(\"groundSpeed\").takeIf { !it.isNaN() }?.let {\n                    location.speed = (it * KNOTS_TO_METERS_PER_SECOND).toFloat()\n                    LocationCompat.setSpeedAccuracyMetersPerSecond(location, location.speed * 0.1f)\n                }\n                json.optDouble(\"altitude\").takeIf { !it.isNaN() }?.let { location.altitude = it * FEET_TO_METERS }\n                json.optDouble(\"heading\").takeIf { !it.isNaN() }?.let {\n                    location.bearing = it.toFloat()\n                    LocationCompat.setBearingAccuracyDegrees(location, 90f)\n                }\n                return location\n            }\n        }\n        private val SOURCE_LUFTHANSA_FLYNET_EUROPE = BoardConnectLocationSource(\"https://www.lufthansa-flynet.com\")\n        private val SOURCE_LUFTHANSA_FLYNET_EUROPE_2 = BoardConnectLocationSource(\"https://ww2.lufthansa-flynet.com\")\n        private val SOURCE_AUSTRIAN_FLYNET_EUROPE = BoardConnectLocationSource(\"https://www.austrian-flynet.com\")\n\n        class SncfLocationSource(base: String) : MovingWifiLocationSource(\"$base/router/api/train/gps\") {\n            override fun parse(location: Location, data: ByteArray): Location {\n                val json = JSONObject(data.decodeToString())\n                if(json.has(\"fix\") && json.getInt(\"fix\") == -1) throw RuntimeException(\"GPS not valid\")\n                location.accuracy = 100f\n                location.latitude = json.getDouble(\"latitude\")\n                location.longitude = json.getDouble(\"longitude\")\n                json.optDouble(\"speed\").takeIf { !it.isNaN() }?.let {\n                    location.speed = it.toFloat()\n                    LocationCompat.setSpeedAccuracyMetersPerSecond(location, location.speed * 0.1f)\n                }\n                location.time = json.getLong(\"timestamp\")\n                json.optDouble(\"heading\").takeIf { !it.isNaN() }?.let {\n                    location.bearing = it.toFloat()\n                    LocationCompat.setBearingAccuracyDegrees(location, 90f)\n                }\n                return location\n            }\n        }\n        private val SOURCE_SNCF = SncfLocationSource(\"https://wifi.sncf\")\n        private val SOURCE_SNCF_INTERCITES = SncfLocationSource(\"https://wifi.intercites.sncf\")\n        private val SOURCE_NORMANDIE = SncfLocationSource(\"https://wifi.normandie.fr\")\n\n        private val SOURCE_LYRIA = object : MovingWifiLocationSource(\"https://wifi.tgv-lyria.com/api/train/gps/position/\") {\n            /* If there is no location available (e.g. in a tunnel), the API\n               endpoint returns HTTP 500, though it may reuse a previous\n               location for a few seconds. The returned JSON has a\n               \"satellites\" integer field, but this always seems to be 0, even\n               when there is a valid location available.\n            */\n            override fun parse(location: Location, data: ByteArray): Location {\n                val json = JSONObject(data.decodeToString())\n                location.accuracy = 100f\n                location.latitude = json.getDouble(\"latitude\")\n                location.longitude = json.getDouble(\"longitude\")\n                json.optDouble(\"speed\").takeIf { !it.isNaN() }?.let {\n                    // Speed is returned in m/s.\n                    location.speed = it.toFloat()\n                    LocationCompat.setSpeedAccuracyMetersPerSecond(location, location.speed * 0.1f)\n                }\n                json.optDouble(\"altitude\").takeIf { !it.isNaN() }?.let { location.altitude = it }\n                return location\n            }\n        }\n\n        private val SOURCE_OUIFI = object : MovingWifiLocationSource(\"https://ouifi.ouigo.com:8084/api/gps\") {\n            override fun parse(location: Location, data: ByteArray): Location {\n                val json = JSONObject(data.decodeToString())\n                if(json.has(\"fix\") && json.getInt(\"fix\") == -1) throw RuntimeException(\"GPS not valid\")\n                location.accuracy = 100f\n                location.latitude = json.getDouble(\"latitude\")\n                location.longitude = json.getDouble(\"longitude\")\n                json.optDouble(\"speed\").takeIf { !it.isNaN() }?.let {\n                    location.speed = it.toFloat()\n                    LocationCompat.setSpeedAccuracyMetersPerSecond(location, location.speed * 0.1f)\n                }\n                location.time = json.getLong(\"timestamp\")\n                json.optDouble(\"heading\").takeIf { !it.isNaN() }?.let {\n                    location.bearing = it.toFloat()\n                    LocationCompat.setBearingAccuracyDegrees(location, 90f)\n                }\n                return location\n            }\n        }\n\n        private val SOURCE_OMBORD = object : MovingWifiLocationSource(\"https://www.ombord.info/api/jsonp/position/\") {\n            override fun parse(location: Location, data: ByteArray): Location {\n                // The API endpoint returns a JSONP object (even when no ?callback= is supplied), so strip the surrounding function call.\n                val json = JSONObject(data.decodeToString().trim().trim('(', ')', ';'))\n                // TODO: what happens in the Channel Tunnel? Does \"satellites\" go to zero? Does \"mode\" change?\n                if (json.has(\"satellites\") && json.getInt(\"satellites\") < 1) throw RuntimeException(\"Ombord has no GPS fix\")\n                location.accuracy = 100f\n                location.latitude = json.getDouble(\"latitude\")\n                location.longitude = json.getDouble(\"longitude\")\n                json.optDouble(\"speed\").takeIf { !it.isNaN() }?.let {\n                    location.speed = it.toFloat()\n                    LocationCompat.setSpeedAccuracyMetersPerSecond(location, location.speed * 0.1f)\n                }\n                location.time = json.getLong(\"time\")\n                // \"cmg\" means \"course made good\", i.e. the compass heading of the track over the ground.\n                // Sometimes gets stuck for a few minutes, so use a generous accuracy value.\n                json.optDouble(\"cmg\").takeIf { !it.isNaN() }?.let {\n                    location.bearing = it.toFloat()\n                    LocationCompat.setBearingAccuracyDegrees(location, 90f)\n                }\n                json.optDouble(\"altitude\").takeIf { !it.isNaN() }?.let {\n                    location.altitude = it\n                }\n                return location\n            }\n        }\n\n        private val SOURCE_AIR_CANADA = object : MovingWifiLocationSource(\"https://airbornemedia.inflightinternet.com/asp/api/flight/info\") {\n            override fun parse(location: Location, data: ByteArray): Location {\n                val json = JSONObject(data.decodeToString()).getJSONObject(\"gpsData\")\n                location.accuracy = 100f\n                location.latitude = json.getDouble(\"latitude\")\n                location.longitude = json.getDouble(\"longitude\")\n                json.optLong(\"utcTime\").takeIf { it != 0L }?.let { location.time = it }\n                json.optDouble(\"altitude\").takeIf { !it.isNaN() }?.let { location.altitude = it * FEET_TO_METERS }\n                json.optDouble(\"horizontalVelocity\").takeIf { !it.isNaN() }?.let {\n                    location.speed = (it * MILES_PER_HOUR_TO_METERS_PER_SECOND).toFloat()\n                    LocationCompat.setSpeedAccuracyMetersPerSecond(location, location.speed * 0.1f)\n                }\n                return location\n            }\n        }\n\n        private val SOURCE_HOTSPLOTS = object : MovingWifiLocationSource(\"http://hsp.hotsplots.net/status.json\") {\n            override fun parse(location: Location, data: ByteArray): Location {\n                val json = JSONObject(data.decodeToString())\n                location.accuracy = 100f\n                location.latitude = json.getDouble(\"lat\")\n                location.longitude = json.getDouble(\"lng\")\n                json.optLong(\"ts\").takeIf { it != 0L }?.let { location.time = it * 1000 }\n                json.optDouble(\"speed\").takeIf { !it.isNaN() }?.let {\n                    location.speed = it.toFloat()\n                    LocationCompat.setSpeedAccuracyMetersPerSecond(location, location.speed * 0.1f)\n                }\n                return location\n            }\n        }\n\n        private val SOURCE_FP3D_THAI_IFE = object : MovingWifiLocationSource(\"https://tha.mediasuite.zii.aero:8483/fp3d_logs/last\") {\n            override fun parse(location: Location, data: ByteArray): Location {\n                val json = JSONObject(data.decodeToString())\n                if (!json.optBoolean(\"positionValid\")) throw RuntimeException(\"GPS not valid\")\n                location.accuracy = 100f\n                location.latitude = json.getDouble(\"presentLat\")\n                location.longitude = json.getDouble(\"presentLon\")\n                json.optLong(\"time\").takeIf { it != 0L }?.let { location.time = it * 1000 }\n                json.optDouble(\"groundSpeedKnots\").takeIf { !it.isNaN() }?.let {\n                    location.speed = (it * KNOTS_TO_METERS_PER_SECOND).toFloat()\n                    LocationCompat.setSpeedAccuracyMetersPerSecond(location, location.speed * 0.1f)\n                }\n                json.optDouble(\"trueHeading\").takeIf { !it.isNaN() }?.let {\n                    location.bearing = it.toFloat()\n                    LocationCompat.setBearingAccuracyDegrees(location, 90f)\n                }\n                return location\n            }\n        }\n\n        private val MOVING_WIFI_HOTSPOTS_LOCALLY_RETRIEVABLE: Map<String, List<MovingWifiLocationSource>> = mapOf(\n            \"WIFIonICE\" to listOf(SOURCE_WIFI_ON_ICE),\n            \"OEBB\" to listOf(SOURCE_OEBB_2, SOURCE_OEBB_1),\n            \"FlixBus\" to listOf(SOURCE_FLIXBUS),\n            \"FlixBus Wi-Fi\" to listOf(SOURCE_FLIXBUS),\n            \"FlixTrain Wi-Fi\" to listOf(SOURCE_FLIXBUS),\n            \"MAVSTART-WIFI\" to listOf(SOURCE_PASSENGERA_MAV),\n            \"AegeanWiFi\" to listOf(SOURCE_DISPLAY_UGO),\n            \"Telekom_FlyNet\" to listOf(SOURCE_INFLIGHT_PANASONIC),\n            \"Cathay Pacific\" to listOf(SOURCE_INFLIGHT_PANASONIC),\n            \"KrisWorld\" to listOf(SOURCE_INFLIGHT_PANASONIC),\n            \"SWISS Connect\" to listOf(SOURCE_INFLIGHT_PANASONIC),\n            \"Edelweiss Entertainment\" to listOf(SOURCE_INFLIGHT_PANASONIC),\n            \"TAP Air Portugal\" to listOf(SOURCE_INFLIGHT_PANASONIC),\n            \"FlyNet\" to listOf(SOURCE_LUFTHANSA_FLYNET_EUROPE, SOURCE_LUFTHANSA_FLYNET_EUROPE_2),\n            \"CDWiFi\" to listOf(SOURCE_PASSENGERA_CD),\n            \"Air Canada\" to listOf(SOURCE_AIR_CANADA),\n            \"ACWiFi\" to listOf(SOURCE_AIR_CANADA),\n            \"ACWiFi.com\" to listOf(SOURCE_AIR_CANADA),\n            \"OUIFI\" to listOf(SOURCE_OUIFI),\n            \"_SNCF_WIFI_INOUI\" to listOf(SOURCE_SNCF),\n            \"_SNCF_WIFI_INTERCITES\" to listOf(SOURCE_SNCF_INTERCITES),\n            \"_WIFI_LYRIA\" to listOf(SOURCE_LYRIA),\n            \"NormandieTrainConnecte\" to listOf(SOURCE_NORMANDIE),\n            \"agilis-Wifi\" to listOf(SOURCE_HOTSPLOTS),\n            \"Austrian FlyNet\" to listOf(SOURCE_AUSTRIAN_FLYNET_EUROPE),\n            \"EurostarTrainsWiFi\" to listOf(SOURCE_OMBORD),\n            \"THAI Wireless IFE\" to listOf(SOURCE_FP3D_THAI_IFE)\n        )\n    }\n}\n"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/network/wifi/WifiDetails.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.network.wifi\n\nimport org.microg.gms.location.network.NetworkDetails\n\ndata class WifiDetails(\n    val macAddress: String,\n    val ssid: String? = null,\n    val frequency: Int? = null,\n    val channel: Int? = null,\n    override val timestamp: Long? = null,\n    override val signalStrength: Int? = null,\n    val open: Boolean = false\n): NetworkDetails\n"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/network/wifi/WifiDetailsCallback.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.network.wifi\n\ninterface WifiDetailsCallback {\n    fun onWifiDetailsAvailable(wifis: List<WifiDetails>)\n    fun onWifiSourceFailed()\n}"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/network/wifi/WifiDetailsSource.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.network.wifi\n\nimport android.content.Context\nimport android.os.WorkSource\n\ninterface WifiDetailsSource {\n    fun enable() = Unit\n    fun disable() = Unit\n    fun startScan(workSource: WorkSource?) = Unit\n\n    companion object {\n        fun create(context: Context, callback: WifiDetailsCallback) = when {\n            WifiScannerSource.isSupported(context) -> WifiScannerSource(context, callback)\n            else -> WifiManagerSource(context, callback)\n        }\n    }\n}"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/network/wifi/WifiManagerSource.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.network.wifi\n\nimport android.annotation.SuppressLint\nimport android.content.BroadcastReceiver\nimport android.content.Context\nimport android.content.Intent\nimport android.content.IntentFilter\nimport android.net.wifi.ScanResult\nimport android.net.wifi.WifiManager\nimport android.os.WorkSource\nimport android.util.Log\nimport androidx.core.content.getSystemService\n\nclass WifiManagerSource(private val context: Context, private val callback: WifiDetailsCallback) : BroadcastReceiver(), WifiDetailsSource {\n\n    @SuppressLint(\"MissingPermission\")\n    override fun onReceive(context: Context, intent: Intent) {\n        try {\n            callback.onWifiDetailsAvailable(this.context.getSystemService<WifiManager>()?.scanResults.orEmpty().map(ScanResult::toWifiDetails))\n        } catch (e: Exception) {\n            Log.w(org.microg.gms.location.network.TAG, e)\n        }\n    }\n\n    override fun enable() {\n        context.registerReceiver(this, IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION))\n    }\n\n    override fun disable() {\n        context.unregisterReceiver(this)\n    }\n\n    override fun startScan(workSource: WorkSource?) {\n        context.getSystemService<WifiManager>()?.startScan()\n    }\n}"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/network/wifi/WifiScannerSource.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.network.wifi\n\nimport android.Manifest\nimport android.annotation.SuppressLint\nimport android.content.Context\nimport android.content.pm.PackageManager.PERMISSION_GRANTED\nimport android.net.wifi.ScanResult\nimport android.net.wifi.WifiManager\nimport android.net.wifi.WifiScanner\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.WorkSource\nimport android.util.Log\nimport androidx.core.content.ContextCompat\nimport androidx.core.content.getSystemService\nimport org.microg.gms.location.network.TAG\n\n@SuppressLint(\"WrongConstant\")\nclass WifiScannerSource(private val context: Context, private val callback: WifiDetailsCallback) : WifiDetailsSource {\n    override fun startScan(workSource: WorkSource?) {\n        val scanner = context.getSystemService(\"wifiscanner\") as WifiScanner\n        scanner.startScan(WifiScanner.ScanSettings().apply {\n            band = WifiScanner.WIFI_BAND_BOTH\n        }, object : WifiScanner.ScanListener {\n            override fun onSuccess() {\n                Log.d(TAG, \"Not yet implemented: onSuccess\")\n                failed = false\n            }\n\n            override fun onFailure(reason: Int, description: String?) {\n                Log.d(TAG, \"Not yet implemented: onFailure $reason $description\")\n                failed = true\n                callback.onWifiSourceFailed()\n            }\n\n            @Deprecated(\"Not supported on all devices\")\n            override fun onPeriodChanged(periodInMs: Int) {\n                Log.d(TAG, \"Not yet implemented: onPeriodChanged $periodInMs\")\n            }\n\n            override fun onResults(results: Array<out WifiScanner.ScanData>) {\n                val wifis = results.flatMap { it.results.toList() }.map(ScanResult::toWifiDetails).toMutableList()\n\n                // Some devices may have incomplete scan data to preserve battery. Ironically, this may even result\n                // in the actively connected wifi being missing from the results. Add them manually to ensure local\n                // moving wifi location works properly\n                if (SDK_INT >= 31) {\n                    @Suppress(\"DEPRECATION\")\n                    val connectedWifi = context.getSystemService<WifiManager>()?.connectionInfo?.toWifiDetails()\n                    if (connectedWifi != null && wifis.none { it.macClean == connectedWifi.macClean }) {\n                        wifis += connectedWifi\n                    }\n                }\n\n                callback.onWifiDetailsAvailable(wifis)\n            }\n\n            override fun onFullResult(fullScanResult: ScanResult) {\n                Log.d(TAG, \"Not yet implemented: onFullResult $fullScanResult\")\n            }\n        }, workSource)\n    }\n\n    companion object {\n        private var failed = false\n        fun isSupported(context: Context): Boolean {\n            return SDK_INT >= 26 && !failed && (context.getSystemService(\"wifiscanner\") as? WifiScanner) != null && ContextCompat.checkSelfPermission(context, Manifest.permission.LOCATION_HARDWARE) == PERMISSION_GRANTED\n        }\n    }\n}"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/network/wifi/extensions.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.network.wifi\n\nimport android.net.wifi.ScanResult\nimport android.net.wifi.WifiInfo\nimport android.net.wifi.WifiManager\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.SystemClock\nimport androidx.annotation.RequiresApi\n\ninternal fun ScanResult.toWifiDetails(): WifiDetails = WifiDetails(\n    macAddress = BSSID,\n    ssid = SSID,\n    timestamp = if (SDK_INT >= 19) System.currentTimeMillis() - (SystemClock.elapsedRealtime() - (timestamp / 1000)) else null,\n    frequency = frequency,\n    channel = frequencyToChannel(frequency),\n    signalStrength = level,\n    open = setOf(\"WEP\", \"WPA\", \"PSK\", \"EAP\", \"IEEE8021X\", \"PEAP\", \"TLS\", \"TTLS\").none { capabilities.contains(it) }\n)\n\n@RequiresApi(31)\ninternal fun WifiInfo.toWifiDetails(): WifiDetails? {\n    return WifiDetails(\n        macAddress = bssid ?: return null,\n        ssid = ssid?.removeSurrounding(\"\\\"\")\n            ?.takeIf { it != WifiManager.UNKNOWN_SSID },\n        timestamp = System.currentTimeMillis(),\n        frequency = frequency,\n        signalStrength = rssi,\n        open = currentSecurityType == WifiInfo.SECURITY_TYPE_OPEN\n    )\n}\n\nprivate const val BAND_24_GHZ_FIRST_CH_NUM = 1\nprivate const val BAND_24_GHZ_LAST_CH_NUM = 14\nprivate const val BAND_5_GHZ_FIRST_CH_NUM = 32\nprivate const val BAND_5_GHZ_LAST_CH_NUM = 177\nprivate const val BAND_6_GHZ_FIRST_CH_NUM = 1\nprivate const val BAND_6_GHZ_LAST_CH_NUM = 233\nprivate const val BAND_60_GHZ_FIRST_CH_NUM = 1\nprivate const val BAND_60_GHZ_LAST_CH_NUM = 6\nprivate const val BAND_24_GHZ_START_FREQ_MHZ = 2412\nprivate const val BAND_24_GHZ_END_FREQ_MHZ = 2484\nprivate const val BAND_5_GHZ_START_FREQ_MHZ = 5160\nprivate const val BAND_5_GHZ_END_FREQ_MHZ = 5885\nprivate const val BAND_6_GHZ_OP_CLASS_136_CH_2_FREQ_MHZ = 5935\nprivate const val BAND_6_GHZ_START_FREQ_MHZ = 5955\nprivate const val BAND_6_GHZ_END_FREQ_MHZ = 7115\nprivate const val BAND_60_GHZ_START_FREQ_MHZ = 58320\nprivate const val BAND_60_GHZ_END_FREQ_MHZ = 70200\n\ninternal fun frequencyToChannel(freq: Int): Int? {\n    return when (freq) {\n        // Special cases\n        BAND_24_GHZ_END_FREQ_MHZ -> BAND_24_GHZ_LAST_CH_NUM\n        BAND_6_GHZ_OP_CLASS_136_CH_2_FREQ_MHZ -> 2\n\n        in BAND_24_GHZ_START_FREQ_MHZ..BAND_24_GHZ_END_FREQ_MHZ ->\n            (freq - BAND_24_GHZ_START_FREQ_MHZ) / 5 + BAND_24_GHZ_FIRST_CH_NUM\n\n        in BAND_5_GHZ_START_FREQ_MHZ..BAND_5_GHZ_END_FREQ_MHZ ->\n            (freq - BAND_5_GHZ_START_FREQ_MHZ) / 5 + BAND_5_GHZ_FIRST_CH_NUM\n\n        in BAND_6_GHZ_START_FREQ_MHZ..BAND_6_GHZ_END_FREQ_MHZ ->\n            (freq - BAND_6_GHZ_START_FREQ_MHZ) / 5 + BAND_6_GHZ_FIRST_CH_NUM\n\n        in BAND_60_GHZ_START_FREQ_MHZ..BAND_60_GHZ_END_FREQ_MHZ ->\n            (freq - BAND_60_GHZ_START_FREQ_MHZ) / 2160 + BAND_60_GHZ_FIRST_CH_NUM\n\n        else -> null\n    }\n}\n\nval WifiDetails.isNomap: Boolean\n    get() = ssid?.endsWith(\"_nomap\") == true\n\nval WifiDetails.isHidden: Boolean\n    get() = ssid == \"\"\n\nval WifiDetails.isRequestable: Boolean\n    get() = !isNomap && !isHidden && !isMoving\n\nval WifiDetails.macBytes: ByteArray\n    get() {\n        val mac = macClean\n        return byteArrayOf(\n            mac.substring(0, 2).toInt(16).toByte(),\n            mac.substring(2, 4).toInt(16).toByte(),\n            mac.substring(4, 6).toInt(16).toByte(),\n            mac.substring(6, 8).toInt(16).toByte(),\n            mac.substring(8, 10).toInt(16).toByte(),\n            mac.substring(10, 12).toInt(16).toByte()\n        )\n    }\nval WifiDetails.macClean: String\n    get() = macAddress.lowercase().replace(\":\", \"\")"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/provider/AbstractLocationProviderPreTiramisu.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.provider\n\nimport android.content.Context\nimport android.location.LocationProvider\nimport android.os.Bundle\nimport android.os.SystemClock\nimport android.util.Log\nimport androidx.annotation.RequiresApi\nimport com.android.location.provider.LocationProviderBase\nimport com.android.location.provider.ProviderPropertiesUnbundled\nimport java.io.FileDescriptor\nimport java.io.PrintWriter\n\nabstract class AbstractLocationProviderPreTiramisu : LocationProviderBase, GenericLocationProvider {\n    @Deprecated(\"Use only with SDK < 31\")\n    constructor(properties: ProviderPropertiesUnbundled) : super(TAG, properties)\n\n    @RequiresApi(31)\n    constructor(context: Context, properties: ProviderPropertiesUnbundled) : super(context, TAG, properties)\n\n    private var statusUpdateTime = SystemClock.elapsedRealtime()\n\n    override fun onDump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {\n        dump(pw)\n    }\n\n    override fun dump(writer: PrintWriter) {\n        // Nothing by default\n    }\n\n    override fun onFlush(callback: OnFlushCompleteCallback?) {\n        Log.d(TAG, \"onFlush\")\n        callback!!.onFlushComplete()\n    }\n\n    override fun onSendExtraCommand(command: String?, extras: Bundle?): Boolean {\n        Log.d(TAG, \"onSendExtraCommand $command $extras\")\n        return false\n    }\n\n    @Deprecated(\"Overriding this is required pre-Q, but not used since Q\")\n    override fun onEnable() {\n        Log.d(TAG, \"onEnable\")\n        statusUpdateTime = SystemClock.elapsedRealtime()\n    }\n\n    @Deprecated(\"Overriding this is required pre-Q, but not used since Q\")\n    override fun onDisable() {\n        Log.d(TAG, \"onDisable\")\n        statusUpdateTime = SystemClock.elapsedRealtime()\n    }\n\n    @Deprecated(\"Overriding this is required pre-Q, but not used since Q\")\n    override fun onGetStatus(extras: Bundle?): Int {\n        Log.d(TAG, \"onGetStatus $extras\")\n        return LocationProvider.AVAILABLE\n    }\n\n\n    @Deprecated(\"Overriding this is required pre-Q, but not used since Q\")\n    override fun onGetStatusUpdateTime(): Long {\n        Log.d(TAG, \"onGetStatusUpdateTime\")\n        return statusUpdateTime\n    }\n}"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/provider/FusedLocationProviderService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.provider\n\nimport android.annotation.SuppressLint\nimport android.app.PendingIntent\nimport android.content.Intent\nimport android.location.Criteria\nimport android.location.Location\nimport android.os.Binder\nimport android.os.Build.VERSION.SDK_INT\nimport android.util.Log\nimport androidx.core.location.LocationRequestCompat\nimport com.android.location.provider.ProviderPropertiesUnbundled\nimport com.android.location.provider.ProviderRequestUnbundled\nimport com.google.android.gms.location.LocationRequest\nimport com.google.android.gms.location.LocationResult\nimport com.google.android.gms.location.LocationServices\nimport com.google.android.gms.location.Priority\nimport kotlin.math.max\n\nclass FusedLocationProviderService : IntentLocationProviderService() {\n    override fun extractLocation(intent: Intent): Location? = LocationResult.extractResult(intent)?.lastLocation\n\n    @SuppressLint(\"MissingPermission\")\n    override fun requestIntentUpdated(currentRequest: ProviderRequestUnbundled?, pendingIntent: PendingIntent) {\n        val intervalMillis = max(currentRequest?.interval ?: Long.MAX_VALUE, minIntervalMillis)\n        val request = LocationRequest.Builder(intervalMillis)\n        if (SDK_INT >= 31 && currentRequest != null) {\n            request.setPriority(when {\n                currentRequest.interval == LocationRequestCompat.PASSIVE_INTERVAL -> Priority.PRIORITY_PASSIVE\n                currentRequest.isLowPower -> Priority.PRIORITY_LOW_POWER\n                currentRequest.quality == LocationRequestCompat.QUALITY_LOW_POWER -> Priority.PRIORITY_LOW_POWER\n                currentRequest.quality == LocationRequestCompat.QUALITY_HIGH_ACCURACY -> Priority.PRIORITY_HIGH_ACCURACY\n                else -> Priority.PRIORITY_BALANCED_POWER_ACCURACY\n            })\n            request.setMaxUpdateDelayMillis(currentRequest.maxUpdateDelayMillis)\n            request.setWorkSource(currentRequest.workSource)\n        } else {\n            request.setPriority(when {\n                currentRequest?.interval == LocationRequestCompat.PASSIVE_INTERVAL -> Priority.PRIORITY_PASSIVE\n                else -> Priority.PRIORITY_BALANCED_POWER_ACCURACY\n            })\n        }\n        if (SDK_INT >= 29 && currentRequest != null) {\n            request.setBypass(currentRequest.isLocationSettingsIgnored)\n        }\n        val identity = Binder.clearCallingIdentity()\n        try {\n            LocationServices.getFusedLocationProviderClient(this).requestLocationUpdates(request.build(), pendingIntent)\n        } catch (e: SecurityException) {\n            Log.d(TAG, \"Failed requesting location updated\", e)\n        }\n        Binder.restoreCallingIdentity(identity)\n    }\n\n    override fun stopIntentUpdated(pendingIntent: PendingIntent) {\n        LocationServices.getFusedLocationProviderClient(this).removeLocationUpdates(pendingIntent)\n    }\n\n    override val minIntervalMillis: Long\n        get() = MIN_INTERVAL_MILLIS\n    override val minReportMillis: Long\n        get() = MIN_REPORT_MILLIS\n    override val properties: ProviderPropertiesUnbundled\n        get() = PROPERTIES\n    override val providerName: String\n        get() = \"fused\"\n\n    companion object {\n        private const val MIN_INTERVAL_MILLIS = 1000L\n        private const val MIN_REPORT_MILLIS = 1000L\n        private val PROPERTIES = ProviderPropertiesUnbundled.create(false, false, false, false, true, true, true, Criteria.POWER_LOW, Criteria.ACCURACY_COARSE)\n    }\n}"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/provider/GenericLocationProvider.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.provider\n\nimport android.location.Location\nimport android.os.IBinder\nimport java.io.PrintWriter\n\ninterface GenericLocationProvider {\n    fun getBinder(): IBinder\n    fun enable()\n    fun disable()\n    fun dump(writer: PrintWriter)\n    fun reportLocationToSystem(location: Location)\n}"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/provider/GeocodeProviderService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.provider\n\nimport android.app.Service\nimport android.content.Intent\nimport android.os.IBinder\nimport java.io.FileDescriptor\nimport java.io.PrintWriter\n\nclass GeocodeProviderService : Service() {\n    private var bound: Boolean = false\n    private var provider: OpenStreetMapNominatimGeocodeProvider? = null\n\n    override fun onBind(intent: Intent?): IBinder? {\n        if (provider == null) {\n            provider = OpenStreetMapNominatimGeocodeProvider(this)\n        }\n        bound = true\n        return provider?.binder\n    }\n\n    override fun dump(fd: FileDescriptor?, writer: PrintWriter?, args: Array<out String>?) {\n        provider?.dump(writer)\n    }\n}"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/provider/IntentLocationProviderPreTiramisu.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.provider\n\nimport android.app.PendingIntent\nimport android.app.PendingIntent.FLAG_UPDATE_CURRENT\nimport android.content.Intent\nimport android.location.Location\nimport android.location.LocationManager\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.Handler\nimport android.os.Looper\nimport android.os.SystemClock\nimport android.os.WorkSource\nimport androidx.annotation.RequiresApi\nimport androidx.core.app.PendingIntentCompat\nimport androidx.core.content.getSystemService\nimport com.android.location.provider.ProviderPropertiesUnbundled\nimport com.android.location.provider.ProviderRequestUnbundled\nimport org.microg.gms.location.elapsedMillis\nimport org.microg.gms.location.formatRealtime\nimport java.io.PrintWriter\nimport kotlin.math.max\n\nclass IntentLocationProviderPreTiramisu : AbstractLocationProviderPreTiramisu {\n    @Deprecated(\"Use only with SDK < 31\")\n    constructor(service: IntentLocationProviderService, properties: ProviderPropertiesUnbundled, legacy: Unit) : super(properties) {\n        this.service = service\n    }\n\n    @RequiresApi(31)\n    constructor(service: IntentLocationProviderService, properties: ProviderPropertiesUnbundled) : super(service, properties) {\n        this.service = service\n    }\n\n    private val service: IntentLocationProviderService\n    private var enabled = false\n    private var currentRequest: ProviderRequestUnbundled? = null\n    private var pendingIntent: PendingIntent? = null\n    private var lastReportedLocation: Location? = null\n    private var lastReportTime: Long = 0\n    private val handler = Handler(Looper.getMainLooper())\n    private val reportAgainRunnable = Runnable { reportAgain() }\n\n    private fun updateRequest() {\n        if (enabled && pendingIntent != null) {\n            service.requestIntentUpdated(currentRequest, pendingIntent!!)\n            reportAgain()\n        }\n    }\n\n    override fun dump(writer: PrintWriter) {\n        writer.println(\"Enabled: $enabled\")\n        writer.println(\"Current request: $currentRequest\")\n        if (SDK_INT >= 31) writer.println(\"Current work source: ${currentRequest?.workSource}\")\n        writer.println(\"Last reported: $lastReportedLocation\")\n        writer.println(\"Last report time: ${lastReportTime.formatRealtime()}\")\n    }\n\n    override fun onSetRequest(request: ProviderRequestUnbundled, source: WorkSource) {\n        synchronized(this) {\n            currentRequest = request\n            updateRequest()\n        }\n    }\n\n    override fun enable() {\n        synchronized(this) {\n            if (enabled) throw IllegalStateException()\n            val intent = Intent(service, service.javaClass)\n            intent.action = ACTION_REPORT_LOCATION\n            pendingIntent = PendingIntentCompat.getService(service, 0, intent, FLAG_UPDATE_CURRENT, true)\n            currentRequest = null\n            enabled = true\n            when {\n                SDK_INT >= 30 -> isAllowed = true\n                SDK_INT >= 29 -> isEnabled = true\n            }\n            try {\n                if (lastReportedLocation == null) {\n                    lastReportedLocation = service.getSystemService<LocationManager>()?.getLastKnownLocation(service.providerName)\n                }\n            } catch (_: SecurityException) {\n            } catch (_: Exception) {\n            }\n        }\n    }\n\n    override fun disable() {\n        synchronized(this) {\n            if (!enabled || pendingIntent == null) throw IllegalStateException()\n            service.stopIntentUpdated(pendingIntent!!)\n            pendingIntent?.cancel()\n            pendingIntent = null\n            currentRequest = null\n            enabled = false\n            handler.removeCallbacks(reportAgainRunnable)\n        }\n    }\n\n    private fun reportAgain() {\n        // Report location again if it's recent enough\n        lastReportedLocation?.let {\n            if (it.elapsedMillis + max(currentRequest?.interval ?: 0, service.minIntervalMillis) > SystemClock.elapsedRealtime()) {\n                reportLocationToSystem(it)\n            }\n        }\n    }\n\n    override fun reportLocationToSystem(location: Location) {\n        handler.removeCallbacks(reportAgainRunnable)\n        location.provider = service.providerName\n        lastReportedLocation = location\n        lastReportTime = SystemClock.elapsedRealtime()\n        super.reportLocation(location)\n        val repeatInterval = max(service.minReportMillis, currentRequest?.interval ?: Long.MAX_VALUE)\n        if (repeatInterval < service.minIntervalMillis) {\n            handler.postDelayed(reportAgainRunnable, repeatInterval)\n        }\n    }\n}"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/provider/IntentLocationProviderService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.provider\n\nimport android.app.PendingIntent\nimport android.app.Service\nimport android.content.Intent\nimport android.location.Location\nimport android.os.Binder\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.Handler\nimport android.os.HandlerThread\nimport android.os.IBinder\nimport android.os.Process\nimport android.util.Log\nimport com.android.location.provider.ProviderPropertiesUnbundled\nimport com.android.location.provider.ProviderRequestUnbundled\nimport java.io.FileDescriptor\nimport java.io.PrintWriter\n\nabstract class IntentLocationProviderService : Service() {\n    private lateinit var handlerThread: HandlerThread\n    private lateinit var handler: Handler\n    private var bound: Boolean = false\n    private var provider: GenericLocationProvider? = null\n\n    override fun onCreate() {\n        super.onCreate()\n        handlerThread = HandlerThread(this.javaClass.simpleName)\n        handlerThread.start()\n        handler = Handler(handlerThread.looper)\n    }\n\n    abstract fun requestIntentUpdated(currentRequest: ProviderRequestUnbundled?, pendingIntent: PendingIntent)\n\n    abstract fun stopIntentUpdated(pendingIntent: PendingIntent)\n\n    abstract fun extractLocation(intent: Intent): Location?\n\n    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {\n        if (Binder.getCallingUid() == Process.myUid() && intent?.action == ACTION_REPORT_LOCATION) {\n            handler.post {\n                val location = extractLocation(intent)\n                if (location != null) {\n                    provider?.reportLocationToSystem(location)\n                }\n            }\n        }\n        return START_NOT_STICKY\n    }\n\n    override fun onBind(intent: Intent?): IBinder? {\n        bound = true\n        if (provider == null) {\n            provider = when {\n                // TODO: Migrate to Tiramisu provider. Not yet required thanks to backwards compat\n                // SDK_INT >= 33 ->\n                SDK_INT >= 31 ->\n                    IntentLocationProviderPreTiramisu(this, properties)\n\n                else ->\n                    @Suppress(\"DEPRECATION\")\n                    (IntentLocationProviderPreTiramisu(this, properties, Unit))\n            }\n            provider?.enable()\n        }\n        return provider?.getBinder()\n    }\n\n    override fun dump(fd: FileDescriptor, writer: PrintWriter, args: Array<out String>) {\n        writer.println(\"Bound: $bound\")\n        provider?.dump(writer)\n    }\n\n    override fun onDestroy() {\n        if (SDK_INT >= 18) handlerThread.looper.quitSafely()\n        else handlerThread.looper.quit()\n        provider?.disable()\n        provider = null\n        bound = false\n        super.onDestroy()\n    }\n\n    abstract val minIntervalMillis: Long\n    abstract val minReportMillis: Long\n    abstract val properties: ProviderPropertiesUnbundled\n    abstract val providerName: String\n}"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/provider/NetworkLocationProviderService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.provider\n\nimport android.app.PendingIntent\nimport android.content.Intent\nimport android.location.Criteria\nimport android.location.Location\nimport android.location.LocationManager\nimport android.os.Build.VERSION.SDK_INT\nimport com.android.location.provider.ProviderPropertiesUnbundled\nimport com.android.location.provider.ProviderRequestUnbundled\nimport org.microg.gms.location.*\nimport org.microg.gms.location.network.LOCATION_EXTRA_PRECISION\nimport kotlin.math.max\n\nclass NetworkLocationProviderService : IntentLocationProviderService() {\n    override fun extractLocation(intent: Intent): Location? = intent.getParcelableExtra<Location?>(EXTRA_LOCATION)?.apply {\n        extras?.remove(LOCATION_EXTRA_PRECISION)\n    }\n\n    override fun requestIntentUpdated(currentRequest: ProviderRequestUnbundled?, pendingIntent: PendingIntent) {\n        val forceNow: Boolean\n        val intervalMillis: Long\n        if (currentRequest?.reportLocation == true) {\n            forceNow = true\n            intervalMillis = max(currentRequest.interval ?: Long.MAX_VALUE, minIntervalMillis)\n        } else {\n            forceNow = false\n            intervalMillis = Long.MAX_VALUE\n        }\n        val intent = Intent(ACTION_NETWORK_LOCATION_SERVICE)\n        intent.`package` = packageName\n        intent.putExtra(EXTRA_PENDING_INTENT, pendingIntent)\n        intent.putExtra(EXTRA_ENABLE, true)\n        intent.putExtra(EXTRA_INTERVAL_MILLIS, intervalMillis)\n        intent.putExtra(EXTRA_FORCE_NOW, forceNow)\n        if (SDK_INT >= 31) {\n            intent.putExtra(EXTRA_LOW_POWER, currentRequest?.isLowPower ?: false)\n            intent.putExtra(EXTRA_WORK_SOURCE, currentRequest?.workSource)\n        }\n        if (SDK_INT >= 29) {\n            intent.putExtra(EXTRA_BYPASS, currentRequest?.isLocationSettingsIgnored ?: false)\n        }\n        startService(intent)\n    }\n\n    override fun stopIntentUpdated(pendingIntent: PendingIntent) {\n        val intent = Intent(ACTION_NETWORK_LOCATION_SERVICE)\n        intent.`package` = packageName\n        intent.putExtra(EXTRA_PENDING_INTENT, pendingIntent)\n        intent.putExtra(EXTRA_ENABLE, false)\n        startService(intent)\n    }\n\n    override val minIntervalMillis: Long\n        get() = MIN_INTERVAL_MILLIS\n    override val minReportMillis: Long\n        get() = MIN_REPORT_MILLIS\n    override val properties: ProviderPropertiesUnbundled\n        get() = PROPERTIES\n    override val providerName: String\n        get() = LocationManager.NETWORK_PROVIDER\n\n\n    companion object {\n        private const val MIN_INTERVAL_MILLIS = 20000L\n        private const val MIN_REPORT_MILLIS = 1000L\n        private val PROPERTIES = ProviderPropertiesUnbundled.create(false, false, false, false, true, true, true, Criteria.POWER_LOW, Criteria.ACCURACY_COARSE)\n    }\n}"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/provider/OpenStreetMapNominatimGeocodeProvider.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.provider\n\nimport android.content.Context\nimport android.location.Address\nimport android.location.GeocoderParams\nimport android.net.Uri\nimport android.util.Log\nimport android.util.LruCache\nimport com.android.location.provider.GeocodeProvider\nimport com.android.volley.toolbox.JsonArrayRequest\nimport com.android.volley.toolbox.JsonObjectRequest\nimport com.android.volley.toolbox.Volley\nimport com.google.android.gms.location.internal.ClientIdentity\nimport org.json.JSONObject\nimport org.microg.address.Formatter\nimport org.microg.gms.location.LocationSettings\nimport org.microg.gms.utils.singleInstanceOf\nimport java.io.PrintWriter\nimport java.util.*\nimport java.util.concurrent.CountDownLatch\nimport java.util.concurrent.TimeUnit\nimport java.util.concurrent.atomic.AtomicReference\n\n\nclass OpenStreetMapNominatimGeocodeProvider(private val context: Context) : GeocodeProvider() {\n    private val queue = singleInstanceOf { Volley.newRequestQueue(context.applicationContext) }\n    private val formatter = runCatching { Formatter() }.getOrNull()\n    private val addressCache = LruCache<CacheKey, Address>(CACHE_SIZE)\n    private val settings by lazy { LocationSettings(context) }\n\n    override fun onGetFromLocation(latitude: Double, longitude: Double, maxResults: Int, params: GeocoderParams, addresses: MutableList<Address>): String? {\n        val clientIdentity = params.clientIdentity ?: return \"null client package\"\n        val locale = params.locale ?: return \"null locale\"\n        if (!settings.geocoderNominatim) return \"disabled\"\n        val cacheKey = CacheKey(clientIdentity, locale, latitude, longitude)\n        addressCache[cacheKey]?.let {address ->\n            addresses.add(address)\n            return null\n        }\n        val uri = Uri.Builder()\n            .scheme(\"https\").authority(NOMINATIM_SERVER).path(\"/reverse\")\n            .appendQueryParameter(\"format\", \"json\")\n            .appendQueryParameter(\"accept-language\", locale.language)\n            .appendQueryParameter(\"addressdetails\", \"1\")\n            .appendQueryParameter(\"lat\", latitude.toString())\n            .appendQueryParameter(\"lon\", longitude.toString())\n        val result = AtomicReference<String?>(\"timeout reached\")\n        val returnedAddress = AtomicReference<Address?>(null)\n        val latch = CountDownLatch(1)\n        queue.add(object : JsonObjectRequest(uri.build().toString(), {\n            parseResponse(locale, it)?.let(returnedAddress::set)\n            result.set(null)\n            latch.countDown()\n        }, {\n            result.set(it.message)\n            latch.countDown()\n        }) {\n            override fun getHeaders(): Map<String, String> = mapOf(\"User-Agent\" to \"microG/${context.versionName}\")\n        })\n        latch.await(5, TimeUnit.SECONDS)\n        val address = returnedAddress.get()\n        if (address != null) {\n            Log.d(TAG, \"Returned $address for $latitude,$longitude\")\n            addresses.add(address)\n            addressCache.put(cacheKey, address)\n        }\n        return result.get()\n    }\n\n    override fun onGetFromLocationName(\n        locationName: String,\n        lowerLeftLatitude: Double,\n        lowerLeftLongitude: Double,\n        upperRightLatitude: Double,\n        upperRightLongitude: Double,\n        maxResults: Int,\n        params: GeocoderParams,\n        addresses: MutableList<Address>\n    ): String? {\n        val clientIdentity = params.clientIdentity ?: return \"null client package\"\n        val locale = params.locale ?: return \"null locale\"\n        if (!settings.geocoderNominatim) return \"disabled\"\n        val uri = Uri.Builder()\n            .scheme(\"https\").authority(NOMINATIM_SERVER).path(\"/search\")\n            .appendQueryParameter(\"format\", \"json\")\n            .appendQueryParameter(\"accept-language\", locale.language)\n            .appendQueryParameter(\"addressdetails\", \"1\")\n            .appendQueryParameter(\"bounded\", \"1\")\n            .appendQueryParameter(\"q\", locationName)\n            .appendQueryParameter(\"limit\", maxResults.toString())\n        if (lowerLeftLatitude != upperRightLatitude && lowerLeftLongitude != upperRightLongitude) {\n            uri.appendQueryParameter(\"viewbox\", \"$lowerLeftLongitude,$upperRightLatitude,$upperRightLongitude,$lowerLeftLatitude\")\n        }\n        val result = AtomicReference<String?>(\"timeout reached\")\n        val latch = CountDownLatch(1)\n        queue.add(object : JsonArrayRequest(uri.build().toString(), {\n            for (i in 0 until it.length()) {\n                parseResponse(locale, it.getJSONObject(i))?.let(addresses::add)\n            }\n            result.set(null)\n            latch.countDown()\n        }, {\n            result.set(it.message)\n            latch.countDown()\n        }) {\n            override fun getHeaders(): Map<String, String> = mapOf(\"User-Agent\" to \"microG/${context.versionName}\")\n        })\n        latch.await(5, TimeUnit.SECONDS)\n        return result.get()\n    }\n\n    private fun parseResponse(locale: Locale, result: JSONObject): Address? {\n        if (!result.has(WIRE_LATITUDE) || !result.has(WIRE_LONGITUDE) ||\n            !result.has(WIRE_ADDRESS)\n        ) {\n            return null\n        }\n        Log.d(TAG, \"Result: $result\")\n        val address = Address(locale)\n        address.latitude = result.getDouble(WIRE_LATITUDE)\n        address.longitude = result.getDouble(WIRE_LONGITUDE)\n        val a = result.getJSONObject(WIRE_ADDRESS)\n        address.thoroughfare = a.optString(WIRE_THOROUGHFARE)\n        address.subLocality = a.optString(WIRE_SUBLOCALITY)\n        address.postalCode = a.optString(WIRE_POSTALCODE)\n        address.subAdminArea = a.optString(WIRE_SUBADMINAREA)\n        address.adminArea = a.optString(WIRE_ADMINAREA)\n        address.countryName = a.optString(WIRE_COUNTRYNAME)\n        address.countryCode = a.optString(WIRE_COUNTRYCODE)\n        if (a.has(WIRE_LOCALITY_CITY)) {\n            address.locality = a.getString(WIRE_LOCALITY_CITY)\n        } else if (a.has(WIRE_LOCALITY_TOWN)) {\n            address.locality = a.getString(WIRE_LOCALITY_TOWN)\n        } else if (a.has(WIRE_LOCALITY_VILLAGE)) {\n            address.locality = a.getString(WIRE_LOCALITY_VILLAGE)\n        }\n        if (formatter != null) {\n            val components = mutableMapOf<String, String>()\n            for (s in a.keys()) {\n                if (s !in WIRE_IGNORED) {\n                    components[s] = a[s].toString()\n                }\n            }\n            val split = formatter.formatAddress(components).split(\"\\n\")\n            for (i in split.indices) {\n                address.setAddressLine(i, split[i])\n            }\n            address.featureName = formatter.guessName(components)\n        }\n        return address\n    }\n\n    fun dump(writer: PrintWriter?) {\n        writer?.println(\"Enabled: ${settings.geocoderNominatim}\")\n        writer?.println(\"Address cache: size=${addressCache.size()} hits=${addressCache.hitCount()} miss=${addressCache.missCount()} puts=${addressCache.putCount()} evicts=${addressCache.evictionCount()}\")\n    }\n\n    companion object {\n        private const val CACHE_SIZE = 200\n\n        private const val NOMINATIM_SERVER = \"nominatim.openstreetmap.org\"\n\n        private const val WIRE_LATITUDE = \"lat\"\n        private const val WIRE_LONGITUDE = \"lon\"\n        private const val WIRE_ADDRESS = \"address\"\n        private const val WIRE_THOROUGHFARE = \"road\"\n        private const val WIRE_SUBLOCALITY = \"suburb\"\n        private const val WIRE_POSTALCODE = \"postcode\"\n        private const val WIRE_LOCALITY_CITY = \"city\"\n        private const val WIRE_LOCALITY_TOWN = \"town\"\n        private const val WIRE_LOCALITY_VILLAGE = \"village\"\n        private const val WIRE_SUBADMINAREA = \"county\"\n        private const val WIRE_ADMINAREA = \"state\"\n        private const val WIRE_COUNTRYNAME = \"country\"\n        private const val WIRE_COUNTRYCODE = \"country_code\"\n\n        private val WIRE_IGNORED = setOf<String>(\"ISO3166-2-lvl4\")\n\n        private data class CacheKey(val uid: Int, val packageName: String?, val locale: Locale, val latitude: Int, val longitude: Int) {\n            constructor(clientIdentity: ClientIdentity, locale: Locale, latitude: Double, longitude: Double) : this(clientIdentity.uid, clientIdentity.packageName.takeIf { clientIdentity.uid != 0 }, locale, (latitude * 100000.0).toInt(), (longitude * 100000.0).toInt())\n        }\n    }\n}"
  },
  {
    "path": "play-services-location/core/provider/src/main/kotlin/org/microg/gms/location/provider/extensions.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.provider\n\nimport android.content.Context\nimport android.location.GeocoderParams\nimport android.os.Build.VERSION.SDK_INT\nimport com.google.android.gms.location.internal.ClientIdentity\n\nconst val TAG = \"LocationProvider\"\n\nconst val ACTION_REPORT_LOCATION = \"org.microg.gms.location.provider.ACTION_REPORT_LOCATION\"\n\nval GeocoderParams.clientIdentity: ClientIdentity?\n    get() = clientPackage?.let {\n        ClientIdentity(it).apply {\n            if (SDK_INT >= 33) {\n                uid = clientUid\n                attributionTag = clientAttributionTag\n            }\n        }\n    }\n\nval Context.versionName: String?\n    get() = packageManager.getPackageInfo(packageName, 0).versionName"
  },
  {
    "path": "play-services-location/core/provider/src/main/res/xml/location_exported_files.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2024 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<paths>\n    <cache-path name=\"location\" path=\"location\" />\n</paths>"
  },
  {
    "path": "play-services-location/core/src/huawei/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2020 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest xmlns:tools=\"http://schemas.android.com/tools\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <application>\n        <activity\n            android:name=\"org.microg.gms.location.manager.AskPermissionNotificationActivity\"\n            android:excludeFromRecents=\"true\"\n            android:process=\":ui\"\n            android:theme=\"@style/Theme.AppCompat.DayNight.NoActionBar\"\n            android:exported=\"false\" />\n\n        <service\n            android:name=\"org.microg.gms.location.manager.LocationManagerService\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.google.android.location.internal.GoogleLocationManagerService.START\" />\n            </intent-filter>\n        </service>\n        <service\n            android:name=\"org.microg.gms.location.reporting.ReportingAndroidService\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.google.android.location.reporting.service.START\" />\n                <action android:name=\"com.google.android.gms.location.reporting.service.START\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </service>\n    </application>\n</manifest>\n"
  },
  {
    "path": "play-services-location/core/src/huawei/kotlin/org/microg/gms/location/manager/AskPermissionNotificationActivity.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.manager\n\nimport android.Manifest.permission.*\nimport android.annotation.TargetApi\nimport android.app.Notification\nimport android.app.NotificationChannel\nimport android.app.NotificationManager\nimport android.content.Context\nimport android.content.Intent\nimport android.content.pm.PackageManager\nimport android.graphics.Color\nimport android.graphics.Typeface\nimport android.net.Uri\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.Bundle\nimport android.provider.Settings\nimport android.text.Spannable\nimport android.text.SpannableStringBuilder\nimport android.text.style.ForegroundColorSpan\nimport android.text.style.StyleSpan\nimport android.util.Log\nimport android.view.View\nimport android.widget.TextView\nimport androidx.annotation.RequiresApi\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.core.app.ActivityCompat\nimport androidx.core.app.NotificationCompat\nimport androidx.core.app.PendingIntentCompat\nimport androidx.core.content.getSystemService\nimport org.microg.gms.location.core.BuildConfig\nimport org.microg.gms.location.core.R\nimport org.microg.gms.utils.getApplicationLabel\n\nprivate const val ACTION_ASK = \"org.microg.gms.location.manager.ASK_PERMISSION\"\nprivate const val ACTION_CANCEL = \"org.microg.gms.location.manager.ASK_PERMISSION_CANCEL\"\n\n@RequiresApi(23)\nclass AskPermissionNotificationActivity : AppCompatActivity() {\n\n    private val foregroundRequestCode = 5\n    private val backgroundRequestCode = 55\n    private val sharedPreferences by lazy {\n        getSharedPreferences(SHARED_PREFERENCE_NAME, MODE_PRIVATE)\n    }\n    private lateinit var hintView: View\n\n    private lateinit var rationaleTextView: TextView\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n\n        if (intent?.action == ACTION_CANCEL) {\n            hideLocationPermissionNotification(this)\n            finish()\n            return\n        }\n\n        setContentView(R.layout.extended_permission_request)\n        rationaleTextView = findViewById(R.id.rationale_textview)\n\n        if (checkAllPermissions()) {\n            hideLocationPermissionNotification(this)\n            finish()\n            return\n        } else if (isGranted(ACCESS_COARSE_LOCATION) && isGranted(ACCESS_FINE_LOCATION) && !isGranted(ACCESS_BACKGROUND_LOCATION) && SDK_INT >= 29) {\n            requestBackground()\n        } else {\n            requestForeground()\n        }\n\n\n        findViewById<View>(R.id.open_setting_tv).setOnClickListener {\n            val intent = Intent()\n            intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS\n            val uri = Uri.fromParts(\"package\", packageName, null)\n            intent.data = uri\n            startActivityForResult(intent, 123)\n        }\n\n        findViewById<View>(R.id.decline_remind_tv).setOnClickListener {\n            val editor = sharedPreferences.edit()\n            editor.putBoolean(PERMISSION_REJECT_SHOW, true)\n            editor.apply()\n            finish()\n        }\n\n        hintView = findViewById(R.id.hint_sl)\n\n        val hintTitle = getString(R.string.permission_hint_title)\n        val builder = SpannableStringBuilder(hintTitle + getString(R.string.permission_hint))\n        val span = ForegroundColorSpan(Color.BLACK)\n        builder.setSpan(span, 0, hintTitle.length, Spannable.SPAN_INCLUSIVE_EXCLUSIVE)\n        builder.setSpan(StyleSpan(Typeface.BOLD), 0, hintTitle.length, Spannable.SPAN_INCLUSIVE_EXCLUSIVE)\n\n        val hintContentTv = findViewById<TextView>(R.id.hint_content_tv)\n        hintContentTv.text = builder\n        hintView.visibility = View.VISIBLE\n    }\n\n    private fun checkAllPermissions(): Boolean {\n        if (SDK_INT < 23) return true\n        return if (SDK_INT >= 29) {\n            isGranted(ACCESS_COARSE_LOCATION)\n                    && isGranted(ACCESS_FINE_LOCATION)\n                    && isGranted(ACCESS_BACKGROUND_LOCATION)\n        } else {\n            isGranted(ACCESS_COARSE_LOCATION)\n                    && isGranted(ACCESS_FINE_LOCATION)\n        }\n    }\n\n    private fun isGranted(permission: String): Boolean {\n        return checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED\n    }\n\n    private fun checkAndAddPermission(list: ArrayList<String>, permission: String) {\n        val result = checkSelfPermission(permission)\n        Log.i(TAG, \"$permission: $result\")\n        if (result != PackageManager.PERMISSION_GRANTED) {\n            list.add(permission)\n        }\n    }\n\n    private fun requestForeground() {\n        val appName = packageManager.getApplicationLabel(packageName)\n        rationaleTextView.text = getString(R.string.rationale_foreground_permission, appName)\n        val permissions = arrayListOf<String>()\n\n        if (BuildConfig.FORCE_SHOW_BACKGROUND_PERMISSION.isNotEmpty()) {\n            permissions.add(BuildConfig.FORCE_SHOW_BACKGROUND_PERMISSION)\n        }\n        checkAndAddPermission(permissions, ACCESS_COARSE_LOCATION)\n        checkAndAddPermission(permissions, ACCESS_FINE_LOCATION)\n        if (SDK_INT == 29) {\n            rationaleTextView.text = getString(R.string.rationale_permission, appName)\n            checkAndAddPermission(permissions, ACCESS_BACKGROUND_LOCATION)\n        }\n        requestPermissions(permissions, foregroundRequestCode)\n    }\n\n    private fun requestBackground() {\n        rationaleTextView.setText(R.string.rationale_background_permission)\n        val permissions = arrayListOf<String>()\n        if (BuildConfig.FORCE_SHOW_BACKGROUND_PERMISSION.isNotEmpty()) {\n            permissions.add(BuildConfig.FORCE_SHOW_BACKGROUND_PERMISSION)\n        }\n        if (SDK_INT >= 29) {\n            checkAndAddPermission(permissions, ACCESS_BACKGROUND_LOCATION)\n        }\n        requestPermissions(permissions, backgroundRequestCode)\n    }\n\n    private fun requestPermissions(permissions: ArrayList<String>, requestCode: Int) {\n        if (permissions.isNotEmpty()) {\n            Log.w(TAG, \"Request permissions: $permissions\")\n            ActivityCompat.requestPermissions(this, permissions.toTypedArray(), requestCode)\n        } else {\n            Log.i(TAG, \"All permission granted\")\n            setResult(RESULT_OK)\n            finish()\n        }\n    }\n\n    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {\n        super.onActivityResult(requestCode, resultCode, data)\n        Log.d(TAG, \"onActivityResult: \")\n        checkPermissions()\n    }\n\n    private fun checkPermissions() {\n        val permissions = mutableListOf(ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION)\n        if (SDK_INT >= 29) permissions.add(ACCESS_BACKGROUND_LOCATION)\n\n        if (permissions.all { checkSelfPermission(it) == PackageManager.PERMISSION_GRANTED }) {\n            Log.d(TAG, \"location permission is all granted\")\n            hideLocationPermissionNotification(this)\n            finish()\n        }\n    }\n\n    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {\n        when (requestCode) {\n            foregroundRequestCode -> {\n                for (i in permissions.indices) {\n                    val p = permissions[i]\n                    val grant = grantResults[i]\n                    val msg = if (grant == PackageManager.PERMISSION_GRANTED) \"GRANTED\" else \"DENIED\"\n                    Log.w(TAG, \"$p: $grant - $msg\")\n                }\n                requestBackground()\n            }\n\n            backgroundRequestCode -> {\n                if (isGranted(ACCESS_BACKGROUND_LOCATION)) {\n                    hideLocationPermissionNotification(this)\n                    setResult(RESULT_OK)\n                    finish()\n                } else {\n                    reject()\n                }\n            }\n\n            else -> {\n                super.onRequestPermissionsResult(requestCode, permissions, grantResults)\n                reject()\n            }\n        }\n    }\n\n    private fun reject() {\n        hintView.visibility = View.VISIBLE\n    }\n\n\n    companion object {\n        private const val SHARED_PREFERENCE_NAME = \"location_perm_notify\"\n        const val PERMISSION_REJECT_SHOW = \"permission_reject_show\"\n        private const val NOTIFICATION_ID = 1026359765\n        private const val ASK_REQUEST_CODE = 1026359766\n        private const val CANCEL_REQUEST_CODE = 1026359767\n\n        @JvmStatic\n        fun showLocationPermissionNotification(context: Context) {\n            val appName = context.packageManager.getApplicationLabel(context.packageName).toString()\n            val title = context.getString(R.string.location_permission_notification_title, appName)\n            val backgroundPermissionOption =\n                if (SDK_INT >= 30) context.packageManager.backgroundPermissionOptionLabel else context.getString(R.string.location_permission_background_option_name)\n            val text = context.getString(R.string.location_permission_notification_content, backgroundPermissionOption, appName)\n            val notification = NotificationCompat.Builder(context, createNotificationChannel(context))\n                .setContentTitle(title).setContentText(text)\n                .setSmallIcon(R.drawable.ic_permission_notification)\n                .setContentIntent(PendingIntentCompat.getActivity(context, ASK_REQUEST_CODE, Intent(context, AskPermissionNotificationActivity::class.java).apply { action = ACTION_ASK }, 0, false))\n                .setStyle(NotificationCompat.BigTextStyle().bigText(text))\n                .setPriority(NotificationCompat.PRIORITY_HIGH)\n                .setOngoing(true)\n                .setDeleteIntent(PendingIntentCompat.getActivity(context, CANCEL_REQUEST_CODE, Intent(context, AskPermissionNotificationActivity::class.java).apply { action = ACTION_CANCEL}, 0, false))\n                .build()\n            context.getSystemService<NotificationManager>()?.notify(NOTIFICATION_ID, notification)\n        }\n\n        @JvmStatic\n        fun hideLocationPermissionNotification(context: Context) {\n            context.getSystemService<NotificationManager>()?.cancel(NOTIFICATION_ID)\n        }\n\n        @TargetApi(26)\n        private fun createNotificationChannel(context: Context): String {\n            val channelId = \"missing-location-permission\"\n            if (SDK_INT >= 26) {\n                val channel = NotificationChannel(channelId, \"Missing location permission\", NotificationManager.IMPORTANCE_HIGH)\n                channel.setSound(null, null)\n                channel.lockscreenVisibility = Notification.VISIBILITY_PUBLIC\n                channel.setShowBadge(true)\n                if (SDK_INT >= 29) {\n                    channel.setAllowBubbles(false)\n                }\n                channel.vibrationPattern = longArrayOf(0)\n                context.getSystemService<NotificationManager>()?.createNotificationChannel(channel)\n                return channel.id\n            }\n            return channelId\n        }\n\n    }\n}"
  },
  {
    "path": "play-services-location/core/src/huawei/res/drawable/ic_permission_notification.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"#FFFFFF\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M1,21h22L12,2 1,21zM13,18h-2v-2h2v2zM13,14h-2v-4h2v4z\"/>\n</vector>\n"
  },
  {
    "path": "play-services-location/core/src/huawei/res/layout/extended_permission_request.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout 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\n    <TextView\n        android:id=\"@+id/rationale_textview\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignParentTop=\"true\"\n        android:layout_margin=\"16dp\"\n        android:textAppearance=\"@android:style/TextAppearance.Large\"\n        tools:text=\"Need this permission for ...\" />\n\n    <LinearLayout\n        android:id=\"@+id/hint_sl\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:background=\"@android:color/white\"\n        android:orientation=\"vertical\"\n        android:paddingStart=\"30dp\"\n        android:paddingTop=\"10dp\"\n        android:paddingEnd=\"30dp\"\n        android:visibility=\"gone\"\n        tools:visibility=\"visible\">\n\n        <ScrollView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"0dp\"\n            android:layout_weight=\"1\">\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:orientation=\"vertical\"\n                android:scrollbars=\"none\">\n\n                <TextView\n                    android:id=\"@+id/hint_content_tv\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:textColor=\"@android:color/darker_gray\"\n                    android:text=\"@string/permission_hint\"\n                    android:textSize=\"16sp\" />\n\n                <TextView\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginTop=\"8dp\"\n                    android:text=\"@string/permission_setting_hint_title\"\n                    android:textColor=\"@android:color/black\"\n                    android:textSize=\"16sp\"\n                    android:textStyle=\"bold\" />\n\n                <ImageView\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"217dp\"\n                    android:layout_marginTop=\"5dp\"\n                    android:layout_marginStart=\"25dp\"\n                    android:layout_marginEnd=\"25dp\"\n                    android:scaleType=\"fitCenter\"\n                    android:src=\"@drawable/permission_step_1\" />\n\n                <ImageView\n                    android:layout_width=\"25dp\"\n                    android:layout_height=\"33dp\"\n                    android:layout_gravity=\"center_horizontal\"\n                    android:src=\"@drawable/arrow\" />\n\n                <ImageView\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"300dp\"\n                    android:layout_marginTop=\"5dp\"\n                    android:layout_marginStart=\"25dp\"\n                    android:layout_marginEnd=\"25dp\"\n                    android:scaleType=\"fitCenter\"\n                    android:src=\"@drawable/permission_step_2\" />\n\n            </LinearLayout>\n\n        </ScrollView>\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_marginBottom=\"12dp\"\n            android:layout_height=\"wrap_content\">\n\n            <Button\n                android:id=\"@+id/open_setting_tv\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"match_parent\"\n                android:layout_weight=\"1\"\n                android:gravity=\"center\"\n                android:text=\"@string/open_settings\"\n                android:textSize=\"14sp\" />\n\n            <Button\n                android:id=\"@+id/decline_remind_tv\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"match_parent\"\n                android:layout_marginStart=\"16dp\"\n                android:layout_weight=\"1\"\n                android:gravity=\"center\"\n                android:text=\"@string/dont_remind_again\"\n                android:textSize=\"14sp\"\n                android:layout_marginLeft=\"16dp\" />\n\n        </LinearLayout>\n\n    </LinearLayout>\n\n</RelativeLayout>"
  },
  {
    "path": "play-services-location/core/src/huawei/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"location_permission_notification_title\">%s requires location permissions</string>\n    <string name=\"location_permission_notification_content\">Please click and select \\\"%s\\\" to allow %s to access this device\\'s location</string>\n    <string name=\"location_permission_background_option_name\">Allow all the time</string>\n\n    <string name=\"permission_hint\">It is recommended to grant the \"Allow all the time\" permission to the MicroG service. The lack of this permission may cause some APPs to be unable to obtain the current location when running in the background. For example, Microsoft Team location sharing function may be affected.</string>\n    <string name=\"permission_hint_title\">Tip:</string>\n    <string name=\"permission_setting_hint_title\">Two steps Only:</string>\n    <string name=\"open_settings\">Open settings</string>\n    <string name=\"dont_remind_again\">Don\\'t remind again</string>\n\n    <string name=\"rationale_foreground_permission\">\n        Please allow <xliff:g example=\"microG\">%1$s</xliff:g> to access this device\\'s location.\n        \\nThe permissions are needed to enable location in map features of supporting apps.\n    </string>\n    <string name=\"rationale_permission\">\n        Please select \\\"ALLOW ALL THE TIME\\\" to allow <xliff:g example=\"microG\">%1$s</xliff:g> to access this device\\'s location.\n    </string>\n    <string name=\"rationale_background_permission\">\n        Please click on the \\\"Permission\\u00A0Manager\\\" and select \\\"ALLOW ALL THE TIME\\\".\n    </string>\n</resources>"
  },
  {
    "path": "play-services-location/core/src/huawei/res/values-zh-rCN/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=\"location_permission_notification_title\">%s 需要位置权限</string>\n    <string name=\"location_permission_notification_content\">请点击并选择 \\\"%s\\\" 去允许 %s 访问此设备的位置。</string>\n    <string name=\"location_permission_background_option_name\">始终允许</string>\n\n    <string name=\"permission_hint\">建议给microG服务授予\"始终允许\"权限，缺少此权限可能将导致部分应用在后台运行时无法获取当前位置的问题，如Microsoft Teams的位置分享功能可能会受影响。</string>\n    <string name=\"permission_hint_title\">提示信息:</string>\n    <string name=\"permission_setting_hint_title\">只需两步：</string>\n    <string name=\"open_settings\">打开设置</string>\n    <string name=\"dont_remind_again\">不再提醒</string>\n\n    <string name=\"rationale_foreground_permission\">\n        请允许 <xliff:g example=\"microG\">%1$s</xliff:g> 访问此设备的位置。\n        \\n需要这些权限才能在支持应用程序的地图功能中启用位置。\n    </string>\n    <string name=\"rationale_permission\">\n       请选择“始终允许”以允许 <xliff:g example=\"microG\">%1$s</xliff:g> 访问此设备的位置。\n    </string>\n    <string name=\"rationale_background_permission\">\n        请点击“权限管理器”并选择“始终允许”。\n    </string>\n</resources>"
  },
  {
    "path": "play-services-location/core/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2020 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest xmlns:tools=\"http://schemas.android.com/tools\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\" />\n    <uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\" />\n    <uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />\n    <uses-permission android:name=\"android.permission.BODY_SENSORS\" />\n    <uses-permission android:name=\"android.permission.POST_NOTIFICATIONS\" />\n\n    <uses-permission\n        android:name=\"android.permission.UPDATE_DEVICE_STATS\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.UPDATE_APP_OPS_STATS\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.WATCH_APPOPS\"\n        tools:ignore=\"ProtectedPermissions\" />\n\n    <application>\n\n        <activity\n            android:name=\"org.microg.gms.location.settings.LocationSettingsCheckerActivity\"\n            android:excludeFromRecents=\"true\"\n            android:exported=\"false\"\n            android:process=\":ui\"\n            android:launchMode=\"singleTask\"\n            android:theme=\"@style/Theme.App.Translucent\">\n            <intent-filter android:priority=\"-1\">\n                <action android:name=\"com.google.android.gms.location.settings.CHECK_SETTINGS\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </activity>\n\n        <activity\n            android:name=\"org.microg.gms.location.settings.GoogleLocationSettingsActivity\"\n            android:excludeFromRecents=\"true\"\n            android:exported=\"true\"\n            android:launchMode=\"singleTask\"\n            android:process=\":ui\"\n            android:theme=\"@style/Theme.App.Translucent\">\n            <intent-filter>\n                <action android:name=\"com.google.android.location.settings.GOOGLE_LOCATION_SETTINGS\" />\n                <action android:name=\"com.google.android.gms.location.settings.GOOGLE_LOCATION_SETTINGS\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </activity>\n\n        <activity\n            android:name=\"org.microg.gms.location.manager.AskPermissionActivity\"\n            android:excludeFromRecents=\"true\"\n            android:process=\":ui\"\n            android:theme=\"@style/Theme.App.Translucent\"\n            android:exported=\"false\" />\n\n        <service\n            android:name=\"org.microg.gms.location.manager.LocationManagerService\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.google.android.location.internal.GoogleLocationManagerService.START\" />\n            </intent-filter>\n        </service>\n\n        <service\n            android:name=\"org.microg.gms.location.reporting.ReportingAndroidService\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.google.android.location.reporting.service.START\" />\n                <action android:name=\"com.google.android.gms.location.reporting.service.START\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </service>\n\n        <receiver\n            android:name=\"org.microg.gms.location.ui.ConfigurationRequiredReceiver\"\n            android:exported=\"false\">\n            <intent-filter>\n                <action android:name=\"org.microg.gms.location.network.ACTION_CONFIGURATION_REQUIRED\" />\n            </intent-filter>\n        </receiver>\n    </application>\n</manifest>\n"
  },
  {
    "path": "play-services-location/core/src/main/kotlin/com/google/android/location/settings/LocationHistorySettingsActivity.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.location.settings\n\nimport android.accounts.Account\nimport android.content.Intent\nimport android.os.Bundle\nimport androidx.appcompat.app.AppCompatActivity\n\nclass LocationHistorySettingsActivity : AppCompatActivity() {\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        if (intent != null) {\n            val account = intent.extras?.getParcelable<Account>(\"account\")\n            val settingIntent = Intent(\"com.google.android.gms.accountsettings.ACCOUNT_PREFERENCES_SETTINGS\")\n            settingIntent.putExtra(\"extra.accountName\", account?.name)\n            settingIntent.putExtra(\"extra.screenId\", 227)\n            startActivity(settingIntent)\n        }\n        finish()\n    }\n}"
  },
  {
    "path": "play-services-location/core/src/main/kotlin/org/microg/gms/location/manager/AbstractLocationManagerInstance.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.manager\n\nimport android.app.PendingIntent\nimport android.location.Location\nimport android.os.IBinder\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.api.internal.IStatusCallback\nimport com.google.android.gms.common.internal.ICancelToken\nimport com.google.android.gms.location.*\nimport com.google.android.gms.location.internal.*\nimport java.util.concurrent.CountDownLatch\nimport java.util.concurrent.TimeUnit\nimport java.util.concurrent.atomic.AtomicReference\n\nabstract class AbstractLocationManagerInstance : IGoogleLocationManagerService.Stub() {\n\n    override fun requestActivityUpdates(detectionIntervalMillis: Long, triggerUpdates: Boolean, callbackIntent: PendingIntent) {\n        requestActivityUpdatesWithCallback(ActivityRecognitionRequest().apply {\n            intervalMillis = detectionIntervalMillis\n            triggerUpdate = triggerUpdates\n        }, callbackIntent, EmptyStatusCallback())\n    }\n\n    override fun getLocationAvailabilityWithPackage(packageName: String?): LocationAvailability {\n        val reference = AtomicReference(LocationAvailability.UNAVAILABLE)\n        val latch = CountDownLatch(1)\n        getLocationAvailabilityWithReceiver(LocationAvailabilityRequest(), LocationReceiver(object : ILocationAvailabilityStatusCallback.Stub() {\n            override fun onLocationAvailabilityStatus(status: Status, location: LocationAvailability) {\n                if (status.isSuccess) {\n                    reference.set(location)\n                }\n                latch.countDown()\n            }\n        }))\n        return reference.get()\n    }\n\n    override fun getCurrentLocation(request: CurrentLocationRequest, callback: ILocationStatusCallback): ICancelToken {\n        return getCurrentLocationWithReceiver(request, LocationReceiver(callback))\n    }\n\n    // region Geofences\n\n    override fun addGeofencesList(geofences: List<ParcelableGeofence>, pendingIntent: PendingIntent, callbacks: IGeofencerCallbacks, packageName: String) {\n        val request = GeofencingRequest.Builder()\n            .addGeofences(geofences)\n            .setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER or GeofencingRequest.INITIAL_TRIGGER_DWELL)\n            .build()\n        addGeofences(request, pendingIntent, callbacks)\n    }\n\n    override fun addGeofencesWithCallback(request: GeofencingRequest?, pendingIntent: PendingIntent?, callback: IStatusCallback?) {\n        addGeofences(request, pendingIntent, object : IGeofencerCallbacks.Default() {\n            override fun onAddGeofenceResult(statusCode: Int, requestIds: Array<out String?>?) {\n                callback?.onResult(Status(statusCode, null))\n            }\n        })\n    }\n\n    override fun removeGeofencesWithCallback(request: RemoveGeofencingRequest?, callback: IStatusCallback?) {\n        removeGeofences(request, object : IGeofencerCallbacks.Default() {\n            override fun onRemoveGeofencesByRequestIdsResult(statusCode: Int, requestIds: Array<out String?>?) {\n                callback?.onResult(Status(statusCode, null))\n            }\n\n            override fun onRemoveGeofencesByPendingIntentResult(statusCode: Int, pendingIntent: PendingIntent?) {\n                callback?.onResult(Status(statusCode, null))\n            }\n        })\n    }\n\n    override fun removeGeofencesById(geofenceRequestIds: Array<out String>, callbacks: IGeofencerCallbacks?, packageName: String?) {\n        removeGeofences(RemoveGeofencingRequest.byGeofenceIds(geofenceRequestIds.toList()), callbacks)\n    }\n\n    override fun removeGeofencesByIntent(pendingIntent: PendingIntent, callbacks: IGeofencerCallbacks?, packageName: String?) {\n        removeGeofences(RemoveGeofencingRequest.byPendingIntent(pendingIntent), callbacks)\n    }\n\n    // endregion\n\n    // region Last location\n\n    override fun getLastLocation(): Location? {\n        val reference = AtomicReference<Location>()\n        val latch = CountDownLatch(1)\n        val request = LastLocationRequest.Builder().setMaxUpdateAgeMillis(Long.MAX_VALUE).setGranularity(Granularity.GRANULARITY_PERMISSION_LEVEL).build()\n        getLastLocationWithReceiver(request, LocationReceiver(object : ILocationStatusCallback.Stub() {\n            override fun onLocationStatus(status: Status, location: Location?) {\n                if (status.isSuccess) {\n                    reference.set(location)\n                }\n                latch.countDown()\n            }\n        }))\n        if (latch.await(30, TimeUnit.SECONDS)) {\n            return reference.get()\n        }\n        return null\n    }\n\n    override fun getLastLocationWithRequest(request: LastLocationRequest, callback: ILocationStatusCallback) {\n        getLastLocationWithReceiver(request, LocationReceiver(callback))\n    }\n\n    override fun getLastLocationWithPackage(packageName: String?): Location? {\n        return lastLocation\n    }\n\n    override fun getLastLocationWith(s: String?): Location? {\n        return lastLocation\n    }\n\n    // endregion\n\n    // region Mock locations\n\n    override fun setMockMode(mockMode: Boolean) {\n        val latch = CountDownLatch(1)\n        setMockModeWithCallback(mockMode, object : IStatusCallback.Stub() {\n            override fun onResult(status: Status?) {\n                latch.countDown()\n            }\n        })\n        latch.await(30, TimeUnit.SECONDS)\n    }\n\n    override fun setMockLocation(mockLocation: Location) {\n        val latch = CountDownLatch(1)\n        setMockLocationWithCallback(mockLocation, object : IStatusCallback.Stub() {\n            override fun onResult(status: Status?) {\n                latch.countDown()\n            }\n        })\n        latch.await(30, TimeUnit.SECONDS)\n    }\n\n    // endregion\n\n    // region Location updates\n\n    abstract fun registerLocationUpdates(\n        oldBinder: IBinder?,\n        binder: IBinder,\n        callback: ILocationCallback,\n        request: LocationRequest,\n        statusCallback: IStatusCallback\n    )\n\n    abstract fun registerLocationUpdates(pendingIntent: PendingIntent, request: LocationRequest, statusCallback: IStatusCallback)\n    abstract fun unregisterLocationUpdates(binder: IBinder, statusCallback: IStatusCallback)\n    abstract fun unregisterLocationUpdates(pendingIntent: PendingIntent, statusCallback: IStatusCallback)\n\n    override fun requestLocationUpdatesWithCallback(receiver: LocationReceiver, request: LocationRequest, callback: IStatusCallback) {\n        when (receiver.type) {\n            LocationReceiver.TYPE_LISTENER -> registerLocationUpdates(\n                receiver.oldBinderReceiver,\n                receiver.binderReceiver!!,\n                receiver.listener.asCallback(),\n                request,\n                callback\n            )\n\n            LocationReceiver.TYPE_CALLBACK -> registerLocationUpdates(\n                receiver.oldBinderReceiver,\n                receiver.binderReceiver!!,\n                receiver.callback,\n                request,\n                callback\n            )\n\n            LocationReceiver.TYPE_PENDING_INTENT -> registerLocationUpdates(receiver.pendingIntentReceiver!!, request, callback)\n            else -> throw IllegalArgumentException(\"unknown location receiver type\");\n        }\n    }\n\n    override fun removeLocationUpdatesWithCallback(receiver: LocationReceiver, callback: IStatusCallback) {\n        when (receiver.type) {\n            LocationReceiver.TYPE_LISTENER -> unregisterLocationUpdates(receiver.binderReceiver!!, callback)\n            LocationReceiver.TYPE_CALLBACK -> unregisterLocationUpdates(receiver.binderReceiver!!, callback)\n            LocationReceiver.TYPE_PENDING_INTENT -> unregisterLocationUpdates(receiver.pendingIntentReceiver!!, callback)\n            else -> throw IllegalArgumentException(\"unknown location receiver type\");\n        }\n    }\n\n    override fun updateLocationRequest(data: LocationRequestUpdateData) {\n        val statusCallback = object : IStatusCallback.Stub() {\n            override fun onResult(status: Status) {\n                data.fusedLocationProviderCallback?.onFusedLocationProviderResult(FusedLocationProviderResult.create(status))\n            }\n        }\n        when (data.opCode) {\n            LocationRequestUpdateData.REQUEST_UPDATES -> {\n                when {\n                    data.listener != null -> registerLocationUpdates(\n                        null,\n                        data.listener.asBinder(),\n                        data.listener.asCallback().redirectCancel(data.fusedLocationProviderCallback),\n                        data.request.request,\n                        statusCallback\n                    )\n\n                    data.callback != null -> registerLocationUpdates(\n                        null,\n                        data.callback.asBinder(),\n                        data.callback.redirectCancel(data.fusedLocationProviderCallback),\n                        data.request.request,\n                        statusCallback\n                    )\n\n                    data.pendingIntent != null -> registerLocationUpdates(data.pendingIntent, data.request.request, statusCallback)\n                }\n            }\n\n            LocationRequestUpdateData.REMOVE_UPDATES -> {\n                when {\n                    data.listener != null -> unregisterLocationUpdates(data.listener.asBinder(), statusCallback)\n                    data.callback != null -> unregisterLocationUpdates(data.callback.asBinder(), statusCallback)\n                    data.pendingIntent != null -> unregisterLocationUpdates(data.pendingIntent, statusCallback)\n                }\n            }\n\n            else -> {\n                statusCallback.onResult(Status(CommonStatusCodes.ERROR, \"invalid location request update operation: \" + data.opCode))\n            }\n        }\n    }\n\n    override fun requestLocationUpdatesWithListener(request: LocationRequest, listener: ILocationListener) {\n        requestLocationUpdatesWithCallback(LocationReceiver(listener), request, EmptyStatusCallback())\n    }\n\n    override fun requestLocationUpdatesWithPackage(request: LocationRequest, listener: ILocationListener, packageName: String?) {\n        requestLocationUpdatesWithCallback(LocationReceiver(listener), request, EmptyStatusCallback())\n    }\n\n    override fun requestLocationUpdatesWithIntent(request: LocationRequest, callbackIntent: PendingIntent) {\n        requestLocationUpdatesWithCallback(LocationReceiver(callbackIntent), request, EmptyStatusCallback())\n    }\n\n    override fun requestLocationUpdatesInternalWithListener(request: LocationRequestInternal, listener: ILocationListener) {\n        requestLocationUpdatesWithCallback(LocationReceiver(listener), request.request, EmptyStatusCallback())\n    }\n\n    override fun requestLocationUpdatesInternalWithIntent(request: LocationRequestInternal, callbackIntent: PendingIntent) {\n        requestLocationUpdatesWithCallback(LocationReceiver(callbackIntent), request.request, EmptyStatusCallback())\n    }\n\n    override fun removeLocationUpdatesWithListener(listener: ILocationListener) {\n        removeLocationUpdatesWithCallback(LocationReceiver(listener), EmptyStatusCallback())\n    }\n\n    override fun removeLocationUpdatesWithIntent(callbackIntent: PendingIntent) {\n        removeLocationUpdatesWithCallback(LocationReceiver(callbackIntent), EmptyStatusCallback())\n    }\n\n    // endregion\n\n    class EmptyStatusCallback : IStatusCallback.Stub() {\n        override fun onResult(status: Status?) = Unit\n    }\n}"
  },
  {
    "path": "play-services-location/core/src/main/kotlin/org/microg/gms/location/manager/AskPermissionActivity.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.manager\n\nimport android.Manifest.permission.ACCESS_BACKGROUND_LOCATION\nimport android.content.Context\nimport android.content.Intent\nimport android.content.pm.PackageManager\nimport android.net.Uri\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.Bundle\nimport android.os.Message\nimport android.os.Messenger\nimport android.provider.Settings\nimport android.util.Log\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.core.app.ActivityCompat\nimport androidx.core.content.ContextCompat\nimport androidx.core.os.bundleOf\nimport org.microg.gms.location.core.BuildConfig\nimport org.microg.gms.location.core.BuildConfig.FORCE_SHOW_BACKGROUND_PERMISSION\n\nconst val EXTRA_MESSENGER = \"messenger\"\nconst val EXTRA_PERMISSIONS = \"permissions\"\nconst val EXTRA_GRANT_RESULTS = \"results\"\n\nprivate const val REQUEST_CODE_PERMISSION = 120\nprivate const val REQUEST_CODE_SETTINGS = 121\n\nclass AskPermissionActivity : AppCompatActivity() {\n    private var permissionGrants = IntArray(0)\n    private val permissionsFromIntent: Array<String>\n        get() = intent?.getStringArrayExtra(EXTRA_PERMISSIONS) ?: emptyArray()\n    private val permissionsToRequest: Array<String>\n        get() = permissionsFromIntent.let {\n            if (FORCE_SHOW_BACKGROUND_PERMISSION.isNotEmpty() && it.contains(ACCESS_BACKGROUND_LOCATION) && !it.contains(FORCE_SHOW_BACKGROUND_PERMISSION)) {\n                it + FORCE_SHOW_BACKGROUND_PERMISSION\n            } else {\n                it\n            }\n        }\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        Log.d(TAG, \"AskPermissionActivity: onCreate\")\n        requestPermissions()\n    }\n\n    private fun updatePermissionGrants() {\n        permissionGrants = permissionsFromIntent.map {\n            if (FORCE_SHOW_BACKGROUND_PERMISSION.isNotEmpty() && FORCE_SHOW_BACKGROUND_PERMISSION == it) {\n                PackageManager.PERMISSION_GRANTED\n            } else {\n                ContextCompat.checkSelfPermission(this, it)\n            }\n        }.toIntArray()\n    }\n\n    private fun requestPermissions() {\n        updatePermissionGrants()\n        if (permissionGrants.all { it == PackageManager.PERMISSION_GRANTED }) {\n            finishWithReply()\n        } else {\n            if (firstRequestLocationSettingsDialog) {\n                ActivityCompat.requestPermissions(this, permissionsToRequest, REQUEST_CODE_PERMISSION)\n            } else {\n                startActivityForResult(Intent().apply {\n                    action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS\n                    data = Uri.fromParts(\"package\", packageName, null)\n                }, REQUEST_CODE_SETTINGS)\n            }\n        }\n    }\n\n    private fun finishWithReply(code: Int = RESULT_OK) {\n        updatePermissionGrants()\n        val extras = bundleOf(EXTRA_GRANT_RESULTS to permissionGrants)\n        intent?.getParcelableExtra<Messenger>(EXTRA_MESSENGER)?.let {\n            runCatching {\n                it.send(Message.obtain().apply {\n                    what = code\n                    data = extras\n                })\n            }\n        }\n        setResult(code, Intent().apply { putExtras(extras) })\n        if (BuildConfig.SHOW_NOTIFICATION_WHEN_NOT_PERMITTED) {\n            updatePermissionGrants()\n            val clazz = runCatching { Class.forName(\"org.microg.gms.location.manager.AskPermissionNotificationActivity\") }.getOrNull()\n            if (permissionGrants.any { it == PackageManager.PERMISSION_DENIED }) {\n                runCatching {\n                    clazz?.getDeclaredMethod(\"showLocationPermissionNotification\", Context::class.java)\n                        ?.invoke(null, this@AskPermissionActivity.applicationContext)\n                }\n            } else {\n                runCatching {\n                    clazz?.getDeclaredMethod(\"hideLocationPermissionNotification\", Context::class.java)\n                        ?.invoke(null, this@AskPermissionActivity.applicationContext)\n                }\n            }\n        }\n        finish()\n    }\n\n    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {\n        if (requestCode == REQUEST_CODE_PERMISSION) {\n            Log.d(TAG, \"onRequestPermissionsResult: permissions:${permissions.joinToString(\",\")} grantResults:${grantResults.joinToString(\",\")}\")\n            if (SDK_INT >= 30) {\n                val backgroundRequested = permissions.contains(ACCESS_BACKGROUND_LOCATION)\n                if (FORCE_SHOW_BACKGROUND_PERMISSION.isNotEmpty() && permissions.contains(FORCE_SHOW_BACKGROUND_PERMISSION)) {\n                    grantResults[permissions.indexOf(FORCE_SHOW_BACKGROUND_PERMISSION)] = PackageManager.PERMISSION_GRANTED\n                }\n                grantResults.forEach { Log.d(TAG, \"onRequestPermissionsResult: $it\") }\n                permissionGrants.forEach { Log.d(TAG, \"onRequestPermissionsResult permissionGrants: $it\") }\n                val backgroundDenied = backgroundRequested && grantResults[permissions.indexOf(ACCESS_BACKGROUND_LOCATION)] == PackageManager.PERMISSION_DENIED\n                val onlyBackgroundDenied = backgroundDenied && grantResults.count { it == PackageManager.PERMISSION_DENIED } == 1\n                val someAccepted = !permissionGrants.contentEquals(grantResults)\n                Log.d(TAG, \"onRequestPermissionsResult onlyBackgroundDenied: $onlyBackgroundDenied someAccepted:$someAccepted\")\n                if (onlyBackgroundDenied && someAccepted) {\n                    // Only background denied, ask again as some systems require that\n                    requestPermissions()\n                    return\n                }\n            }\n            firstRequestLocationSettingsDialog = false\n            finishWithReply()\n        } else {\n            super.onRequestPermissionsResult(requestCode, permissions, grantResults)\n        }\n    }\n\n    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {\n        if (requestCode == REQUEST_CODE_SETTINGS) {\n            updatePermissionGrants()\n            finishWithReply()\n        } else {\n            super.onActivityResult(requestCode, resultCode, data)\n        }\n    }\n\n    companion object {\n        private var firstRequestLocationSettingsDialog: Boolean = true\n    }\n}"
  },
  {
    "path": "play-services-location/core/src/main/kotlin/org/microg/gms/location/manager/DeviceOrientationManager.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.manager\n\nimport android.app.AppOpsManager\nimport android.content.Context\nimport android.hardware.GeomagneticField\nimport android.hardware.Sensor\nimport android.hardware.Sensor.*\nimport android.hardware.SensorEvent\nimport android.hardware.SensorEventListener\nimport android.hardware.SensorManager\nimport android.hardware.SensorManager.*\nimport android.location.Location\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.Handler\nimport android.os.HandlerThread\nimport android.os.IBinder\nimport android.os.SystemClock\nimport android.os.WorkSource\nimport android.util.Log\nimport android.view.Surface\nimport android.view.WindowManager\nimport androidx.annotation.GuardedBy\nimport androidx.core.content.getSystemService\nimport androidx.core.location.LocationCompat\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.LifecycleOwner\nimport androidx.lifecycle.lifecycleScope\nimport com.google.android.gms.location.DeviceOrientation\nimport com.google.android.gms.location.DeviceOrientationRequest\nimport com.google.android.gms.location.IDeviceOrientationListener\nimport com.google.android.gms.location.Priority.PRIORITY_PASSIVE\nimport com.google.android.gms.location.internal.ClientIdentity\nimport com.google.android.gms.location.internal.DeviceOrientationRequestInternal\nimport kotlinx.coroutines.sync.Mutex\nimport kotlinx.coroutines.sync.withLock\nimport org.microg.gms.location.formatDuration\nimport org.microg.gms.utils.WorkSourceUtil\nimport java.io.PrintWriter\nimport kotlin.math.*\n\nclass DeviceOrientationManager(private val context: Context, override val lifecycle: Lifecycle, private val requestDetailsUpdatedCallback: () -> Unit) : LifecycleOwner, SensorEventListener, IBinder.DeathRecipient {\n    private var lock = Mutex(false)\n    private var started: Boolean = false\n    private var sensors: Set<Sensor>? = null\n    private var handlerThread: HandlerThread? = null\n    private val requests = mutableMapOf<IBinder, DeviceOrientationRequestHolder>()\n\n    private val appOpsLock = Any()\n    @GuardedBy(\"appOpsLock\")\n    private var currentAppOps = emptySet<ClientIdentity>()\n\n    val isActive: Boolean\n        get() = requests.isNotEmpty()\n\n    suspend fun add(clientIdentity: ClientIdentity, request: DeviceOrientationRequestInternal, listener: IDeviceOrientationListener) {\n        listener.asBinder().linkToDeath(this, 0)\n        lock.withLock {\n            requests[listener.asBinder()] = DeviceOrientationRequestHolder(clientIdentity, request.request, listener)\n            updateStatus()\n        }\n    }\n\n    suspend fun remove(clientIdentity: ClientIdentity, listener: IDeviceOrientationListener) {\n        listener.asBinder().unlinkToDeath(this, 0)\n        lock.withLock {\n            requests.remove(listener.asBinder())\n            updateStatus()\n        }\n    }\n\n    private fun SensorManager.registerListener(sensor: Sensor, handler: Handler) {\n        if (SDK_INT >= 19) {\n            registerListener(this@DeviceOrientationManager, sensor, SAMPLING_PERIOD_US, MAX_REPORT_LATENCY_US, handler)\n        } else {\n            registerListener(this@DeviceOrientationManager, sensor, SAMPLING_PERIOD_US, handler)\n        }\n    }\n\n    private fun updateStatus() {\n        if (requests.isNotEmpty() && !started) {\n            try {\n                val sensorManager = context.getSystemService<SensorManager>() ?: return\n                val sensors = mutableSetOf<Sensor>()\n                if (SDK_INT >= 33) {\n                    sensorManager.getDefaultSensor(TYPE_HEADING)?.let { sensors.add(it) }\n                }\n                if (sensors.isEmpty()) {\n                    sensorManager.getDefaultSensor(TYPE_ROTATION_VECTOR)?.let { sensors.add(it) }\n                }\n                if (sensors.isEmpty()) {\n                    sensors.add(sensorManager.getDefaultSensor(TYPE_MAGNETIC_FIELD) ?: return)\n                    sensors.add(sensorManager.getDefaultSensor(TYPE_ACCELEROMETER) ?: return)\n                }\n                handlerThread = HandlerThread(\"DeviceOrientation\")\n                handlerThread!!.start()\n                val handler = Handler(handlerThread!!.looper)\n                for (sensor in sensors) {\n                    sensorManager.registerListener(sensor, handler)\n                }\n                this.sensors = sensors\n                started = true\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n            }\n        } else if (requests.isEmpty() && started) {\n            stop()\n        }\n        requestDetailsUpdatedCallback()\n        updateAppOps()\n    }\n\n    private fun updateAppOps() {\n        synchronized(appOpsLock) {\n            val newAppOps = mutableSetOf<ClientIdentity>()\n            for (request in requests.values) {\n                if (request.clientIdentity.isSelfUser()) continue\n                newAppOps.add(request.clientIdentity)\n            }\n            Log.d(TAG, \"Updating app ops for device orientation, change attribution to: ${newAppOps.map { it.packageName }.joinToString().takeIf { it.isNotEmpty() } ?: \"none\"}\")\n\n            for (oldAppOp in currentAppOps) {\n                context.finishAppOp(AppOpsManager.OPSTR_MONITOR_LOCATION, oldAppOp)\n            }\n            for (newAppOp in newAppOps) {\n                context.startAppOp(AppOpsManager.OPSTR_MONITOR_LOCATION, newAppOp)\n            }\n            currentAppOps = newAppOps\n        }\n    }\n\n    override fun binderDied() {\n        lifecycleScope.launchWhenStarted {\n            val toRemove = requests.keys.filter { !it.isBinderAlive }.toList()\n            for (binder in toRemove) {\n                requests.remove(binder)\n            }\n            updateStatus()\n        }\n    }\n\n    private var location: Location? = null\n    fun onLocationChanged(location: Location) {\n        this.location = location\n        updateHeading()\n    }\n\n    private var accelerometerValues = FloatArray(3)\n    private var accelerometerRealtimeNanos = 0L\n    private fun handleAccelerometerEvent(event: SensorEvent) {\n        event.values.copyInto(accelerometerValues)\n        accelerometerRealtimeNanos = event.timestamp\n        updateAzimuth()\n    }\n\n    private var magneticFieldValues = FloatArray(3)\n    private var magneticRealtimeNanos = 0L\n    private fun handleMagneticEvent(event: SensorEvent) {\n        event.values.copyInto(magneticFieldValues)\n        magneticRealtimeNanos = event.timestamp\n        updateAzimuth()\n    }\n\n    private var azimuths = FloatArray(5)\n    private var azimuthIndex = 0\n    private var hadAzimuths = false\n    private var azimuth = Float.NaN\n    private var azimuthRealtimeNanos = 0L\n    private var azimuthAccuracy = Float.NaN\n    private fun updateAzimuth() {\n        if (accelerometerRealtimeNanos == 0L || magneticRealtimeNanos == 0L) return\n        var r = FloatArray(9)\n        val i = FloatArray(9)\n        if (getRotationMatrix(r, i, accelerometerValues, magneticFieldValues)) {\n            r = remapForOrientation(r)\n            val values = FloatArray(3)\n            getOrientation(r, values)\n            azimuths[azimuthIndex] = values[0]\n            if (azimuthIndex == azimuths.size - 1) {\n                azimuthIndex = 0\n                hadAzimuths = true\n            } else {\n                azimuthIndex++\n            }\n            var sumSin = 0.0\n            var sumCos = 0.0\n            for (j in 0 until (if (hadAzimuths) azimuths.size else azimuthIndex)) {\n                sumSin = sin(azimuths[j].toDouble())\n                sumCos = cos(azimuths[j].toDouble())\n            }\n            azimuth = Math.toDegrees(atan2(sumSin, sumCos)).toFloat()\n            azimuthRealtimeNanos = max(accelerometerRealtimeNanos, magneticRealtimeNanos)\n            updateHeading()\n        }\n    }\n\n    private fun remapForOrientation(r: FloatArray): FloatArray {\n        val display = context.getSystemService<WindowManager>()?.defaultDisplay\n        fun remap(x: Int, y: Int) = FloatArray(9).also { remapCoordinateSystem(r, x, y, it) }\n        return when (display?.rotation) {\n            Surface.ROTATION_90 -> remap(AXIS_Y, AXIS_MINUS_X)\n            Surface.ROTATION_180 -> remap(AXIS_MINUS_X, AXIS_MINUS_Y)\n            Surface.ROTATION_270 -> remap(AXIS_MINUS_Y, AXIS_X)\n            else -> r\n        }\n    }\n\n    private fun handleRotationVectorEvent(event: SensorEvent) {\n        val v = FloatArray(3)\n        event.values.copyInto(v, endIndex = 3)\n        var r = FloatArray(9)\n        getRotationMatrixFromVector(r, v)\n        r = remapForOrientation(r)\n        val values = FloatArray(3)\n        getOrientation(r, values)\n        azimuth = Math.toDegrees(values[0].toDouble()).toFloat()\n        azimuthRealtimeNanos = event.timestamp\n        if (SDK_INT >= 18 && values.size >= 5 && values[4] != -1f) {\n            azimuthAccuracy = Math.toDegrees(values[4].toDouble()).toFloat()\n        }\n        updateHeading()\n    }\n\n    private var heading = Float.NaN\n    private var headingAccuracy = Float.NaN\n    private var headingRealtimeNanos = 0L\n    private fun updateHeading() {\n        if (!azimuth.isNaN()) {\n            if (location == null) {\n                heading = azimuth\n                headingAccuracy = azimuthAccuracy.takeIf { !it.isNaN() } ?: 90.0f\n                headingRealtimeNanos = azimuthRealtimeNanos\n            } else {\n                heading = azimuth + location!!.run { GeomagneticField(latitude.toFloat(), longitude.toFloat(), altitude.toFloat(), time).declination }\n                headingAccuracy = azimuthAccuracy.takeIf { !it.isNaN() } ?: 45.0f\n                headingRealtimeNanos = max(LocationCompat.getElapsedRealtimeNanos(location!!), azimuthRealtimeNanos)\n            }\n            updateDeviceOrientation()\n        }\n    }\n\n    private fun handleHeadingEvent(event: SensorEvent) {\n        heading = event.values[0]\n        headingAccuracy = event.values[1]\n        headingRealtimeNanos = event.timestamp\n        updateDeviceOrientation()\n    }\n\n    private fun updateDeviceOrientation() {\n        val deviceOrientation = DeviceOrientation()\n        deviceOrientation.headingDegrees = heading\n        deviceOrientation.headingErrorDegrees = headingAccuracy\n        deviceOrientation.elapsedRealtimeNanos = headingRealtimeNanos\n        lifecycleScope.launchWhenStarted {\n            processNewDeviceOrientation(deviceOrientation)\n        }\n    }\n\n    override fun onSensorChanged(event: SensorEvent) {\n        when (event.sensor.type) {\n            TYPE_ACCELEROMETER -> handleAccelerometerEvent(event)\n            TYPE_MAGNETIC_FIELD -> handleMagneticEvent(event)\n            TYPE_ROTATION_VECTOR -> handleRotationVectorEvent(event)\n            TYPE_HEADING -> handleHeadingEvent(event)\n            else -> return\n        }\n    }\n\n    override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {\n        if (sensor.type == TYPE_ROTATION_VECTOR) {\n            azimuthAccuracy = when (accuracy) {\n                SENSOR_STATUS_ACCURACY_LOW -> 45.0f\n                SENSOR_STATUS_ACCURACY_MEDIUM -> 30.0f\n                SENSOR_STATUS_ACCURACY_HIGH -> 15.0f\n                else -> Float.NaN\n            }\n        }\n    }\n\n    fun stop() {\n        if (SDK_INT >= 18) handlerThread?.looper?.quitSafely()\n        else handlerThread?.looper?.quit()\n        context.getSystemService<SensorManager>()?.unregisterListener(this)\n        started = false\n    }\n\n    fun dump(writer: PrintWriter) {\n        writer.println(\"Current device orientation request (started=$started, sensors=${sensors?.map { it.name }})\")\n        for (request in requests.values.toList()) {\n            writer.println(\"- ${request.workSource} (pending: ${request.updatesPending.let { if (it == Int.MAX_VALUE) \"\\u221e\" else \"$it\" }} ${request.timePendingMillis.formatDuration()}, app-op: ${currentAppOps.contains(request.clientIdentity)})\")\n        }\n    }\n\n    suspend fun processNewDeviceOrientation(deviceOrientation: DeviceOrientation) {\n        lock.withLock {\n            val toRemove = mutableSetOf<IBinder>()\n            for ((binder, holder) in requests) {\n                try {\n                    holder.processNewDeviceOrientation(deviceOrientation)\n                } catch (e: Exception) {\n                    toRemove.add(binder)\n                }\n            }\n            for (binder in toRemove) {\n                requests.remove(binder)\n            }\n            if (toRemove.isNotEmpty()) {\n                updateStatus()\n            }\n        }\n    }\n\n    companion object {\n        const val SAMPLING_PERIOD_US = 20_000\n        const val MAX_REPORT_LATENCY_US = 200_000\n\n        private class DeviceOrientationRequestHolder(\n            val clientIdentity: ClientIdentity,\n            private val request: DeviceOrientationRequest,\n            private val listener: IDeviceOrientationListener,\n        ) {\n            private var updates = 0\n            private var lastOrientation: DeviceOrientation? = null\n\n            val updatesPending: Int\n                get() = request.numUpdates - updates\n            val timePendingMillis: Long\n                get() = request.expirationTime - SystemClock.elapsedRealtime()\n            val workSource = WorkSource().also { WorkSourceUtil.add(it, clientIdentity.uid, clientIdentity.packageName) }\n\n            fun processNewDeviceOrientation(deviceOrientation: DeviceOrientation) {\n                if (timePendingMillis < 0) throw RuntimeException(\"duration limit reached (expired at ${request.expirationTime}, now is ${SystemClock.elapsedRealtime()})\")\n                if (lastOrientation != null && abs(lastOrientation!!.headingDegrees - deviceOrientation.headingDegrees) < Math.toDegrees(request.smallestAngleChangeRadians.toDouble())) return\n                if (lastOrientation == deviceOrientation) return\n                listener.onDeviceOrientationChanged(deviceOrientation)\n                if (request.numUpdates != Int.MAX_VALUE) updates++\n                if (updatesPending <= 0) throw RuntimeException(\"max updates reached\")\n            }\n        }\n    }\n}"
  },
  {
    "path": "play-services-location/core/src/main/kotlin/org/microg/gms/location/manager/LastLocationCapsule.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.manager\n\nimport android.content.Context\nimport android.location.Location\nimport android.location.LocationManager\nimport android.os.SystemClock\nimport android.util.Log\nimport androidx.core.content.getSystemService\nimport androidx.core.location.LocationCompat\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable.Field\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableSerializer\nimport com.google.android.gms.location.Granularity\nimport com.google.android.gms.location.Granularity.GRANULARITY_COARSE\nimport com.google.android.gms.location.Granularity.GRANULARITY_FINE\nimport com.google.android.gms.location.LocationAvailability\nimport org.microg.gms.location.elapsedMillis\nimport org.microg.safeparcel.AutoSafeParcelable\nimport java.io.File\nimport java.lang.Long.max\nimport java.util.concurrent.TimeUnit\nimport kotlin.math.min\n\nclass LastLocationCapsule(private val context: Context) {\n    private var lastFineLocation: Location? = null\n    private var lastCoarseLocation: Location? = null\n\n    private var lastFineLocationTimeCoarsed: Location? = null\n    private var lastCoarseLocationTimeCoarsed: Location? = null\n\n    var locationAvailability: LocationAvailability = LocationAvailability.AVAILABLE\n\n    private val file: File\n        get() = context.getFileStreamPath(FILE_NAME)\n\n    fun getLocation(effectiveGranularity: @Granularity Int, maxUpdateAgeMillis: Long = Long.MAX_VALUE): Location? {\n        val location = when (effectiveGranularity) {\n            GRANULARITY_COARSE -> lastCoarseLocationTimeCoarsed\n            GRANULARITY_FINE -> lastCoarseLocation\n            else -> return null\n        } ?: return null\n        val cliff = if (effectiveGranularity == GRANULARITY_COARSE) max(maxUpdateAgeMillis, TIME_COARSE_CLIFF) else maxUpdateAgeMillis\n        val elapsedRealtimeDiff = SystemClock.elapsedRealtime() - location.elapsedMillis\n        if (elapsedRealtimeDiff > cliff) return null\n        if (elapsedRealtimeDiff <= maxUpdateAgeMillis) return location\n        // Location is too old according to maxUpdateAgeMillis, but still in scope due to time coarsing. Adjust time\n        val locationUpdated = Location(location)\n        val timeAdjustment = elapsedRealtimeDiff - maxUpdateAgeMillis\n        locationUpdated.elapsedRealtimeNanos = location.elapsedRealtimeNanos + TimeUnit.MILLISECONDS.toNanos(timeAdjustment)\n        locationUpdated.time = location.time + timeAdjustment\n        return locationUpdated\n    }\n\n    fun reset() {\n        lastFineLocation = null\n        lastFineLocationTimeCoarsed = null\n        lastCoarseLocation = null\n        lastCoarseLocationTimeCoarsed = null\n        locationAvailability = LocationAvailability.AVAILABLE\n    }\n\n    fun updateCoarseLocation(location: Location) {\n        location.elapsedRealtimeNanos = min(location.elapsedRealtimeNanos, SystemClock.elapsedRealtimeNanos())\n        location.time = min(location.time, System.currentTimeMillis())\n        if (lastCoarseLocation != null && lastCoarseLocation!!.elapsedMillis + EXTENSION_CLIFF > location.elapsedMillis) {\n            if (!location.hasSpeed()) {\n                location.speed = lastCoarseLocation!!.distanceTo(location) / ((location.elapsedMillis - lastCoarseLocation!!.elapsedMillis) / 1000)\n                LocationCompat.setSpeedAccuracyMetersPerSecond(location, location.speed)\n            }\n            if (!location.hasBearing() && location.speed > 0.5f) {\n                location.bearing = lastCoarseLocation!!.bearingTo(location)\n                LocationCompat.setBearingAccuracyDegrees(location, 180.0f)\n            }\n        }\n        lastCoarseLocation = newest(lastCoarseLocation, location)\n        lastCoarseLocationTimeCoarsed = newest(lastCoarseLocationTimeCoarsed, location, TIME_COARSE_CLIFF)\n    }\n\n    fun updateFineLocation(location: Location) {\n        location.elapsedRealtimeNanos = min(location.elapsedRealtimeNanos, SystemClock.elapsedRealtimeNanos())\n        location.time = min(location.time, System.currentTimeMillis())\n        lastFineLocation = newest(lastFineLocation, location)\n        lastFineLocationTimeCoarsed = newest(lastFineLocationTimeCoarsed, location, TIME_COARSE_CLIFF)\n        updateCoarseLocation(location)\n    }\n\n    private fun newest(oldLocation: Location?, newLocation: Location, cliff: Long = 0): Location {\n        if (oldLocation == null) return newLocation\n        if (LocationCompat.isMock(oldLocation) && !LocationCompat.isMock(newLocation)) return newLocation\n        oldLocation.elapsedRealtimeNanos = min(oldLocation.elapsedRealtimeNanos, SystemClock.elapsedRealtimeNanos())\n        oldLocation.time = min(oldLocation.time, System.currentTimeMillis())\n        if (newLocation.elapsedRealtimeNanos >= oldLocation.elapsedRealtimeNanos + TimeUnit.MILLISECONDS.toNanos(cliff)) return newLocation\n        return oldLocation\n    }\n\n    fun start() {\n        fun Location.adjustRealtime() = apply {\n            time = min(time, System.currentTimeMillis())\n            elapsedRealtimeNanos = min(\n                SystemClock.elapsedRealtimeNanos() - TimeUnit.MILLISECONDS.toNanos((System.currentTimeMillis() - time)),\n                SystemClock.elapsedRealtimeNanos()\n            )\n        }\n        try {\n            if (file.exists()) {\n                val capsule = SafeParcelableSerializer.deserializeFromBytes(file.readBytes(), LastLocationCapsuleParcelable.CREATOR)\n                lastFineLocation = capsule.lastFineLocation?.adjustRealtime()\n                lastCoarseLocation = capsule.lastCoarseLocation?.adjustRealtime()\n                lastFineLocationTimeCoarsed = capsule.lastFineLocationTimeCoarsed?.adjustRealtime()\n                lastCoarseLocationTimeCoarsed = capsule.lastCoarseLocationTimeCoarsed?.adjustRealtime()\n            }\n        } catch (e: Exception) {\n            Log.w(TAG, e)\n            // Ignore\n        }\n        fetchFromSystem()\n    }\n\n    fun fetchFromSystem() {\n        val locationManager = context.getSystemService<LocationManager>() ?: return\n        try {\n            locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER)?.let { updateCoarseLocation(it) }\n            locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)?.let { updateFineLocation(it) }\n        } catch (e: SecurityException) {\n            // Ignore\n        }\n    }\n\n    fun stop() {\n        try {\n            if (file.exists()) file.delete()\n            file.writeBytes(SafeParcelableSerializer.serializeToBytes(LastLocationCapsuleParcelable(lastFineLocation, lastCoarseLocation, lastFineLocationTimeCoarsed, lastCoarseLocationTimeCoarsed)))\n        } catch (e: Exception) {\n            Log.w(TAG, e)\n            // Ignore\n        }\n    }\n\n    companion object {\n        private const val FILE_NAME = \"last_location_capsule\"\n        private const val TIME_COARSE_CLIFF = 60_000L\n        private const val EXTENSION_CLIFF = 30_000L\n\n        private class LastLocationCapsuleParcelable(\n            @Field(1) @JvmField val lastFineLocation: Location?,\n            @Field(2) @JvmField val lastCoarseLocation: Location?,\n            @Field(3) @JvmField val lastFineLocationTimeCoarsed: Location?,\n            @Field(4) @JvmField val lastCoarseLocationTimeCoarsed: Location?\n        ) : AutoSafeParcelable() {\n            constructor() : this(null, null, null, null)\n\n            companion object {\n                @JvmField\n                val CREATOR = AutoCreator(LastLocationCapsuleParcelable::class.java)\n            }\n        }\n    }\n}"
  },
  {
    "path": "play-services-location/core/src/main/kotlin/org/microg/gms/location/manager/LocationAppsDatabase.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.manager\n\nimport android.content.ContentValues\nimport android.content.Context\nimport android.database.sqlite.SQLiteDatabase\nimport android.database.sqlite.SQLiteOpenHelper\nimport android.location.Location\nimport android.util.Log\nimport androidx.core.content.contentValuesOf\nimport androidx.core.database.getIntOrNull\n\nclass LocationAppsDatabase(context: Context) : SQLiteOpenHelper(context, \"geoapps.db\", null, 2) {\n    override fun onCreate(db: SQLiteDatabase) {\n        db.execSQL(\"CREATE TABLE IF NOT EXISTS $TABLE_APPS($FIELD_PACKAGE TEXT NOT NULL, $FIELD_TIME INTEGER NOT NULL, $FIELD_FORCE_COARSE INTEGER);\")\n        db.execSQL(\"CREATE TABLE IF NOT EXISTS $TABLE_APPS_LAST_LOCATION($FIELD_PACKAGE TEXT NOT NULL, $FIELD_TIME INTEGER NOT NULL, $FIELD_LATITUDE REAL NOT NULL, $FIELD_LONGITUDE REAL NOT NULL, $FIELD_ACCURACY REAL NOT NULL, $FIELD_PROVIDER TEXT NOT NULL);\")\n        db.execSQL(\"CREATE UNIQUE INDEX IF NOT EXISTS ${TABLE_APPS}_index ON ${TABLE_APPS}(${FIELD_PACKAGE});\")\n        db.execSQL(\"CREATE UNIQUE INDEX IF NOT EXISTS ${TABLE_APPS_LAST_LOCATION}_index ON ${TABLE_APPS_LAST_LOCATION}(${FIELD_PACKAGE});\")\n    }\n\n    private fun insertOrUpdateApp(packageName: String, vararg pairs: Pair<String, Any?>) {\n        val values = contentValuesOf(FIELD_PACKAGE to packageName, *pairs)\n        if (writableDatabase.insertWithOnConflict(TABLE_APPS, null, values, SQLiteDatabase.CONFLICT_IGNORE) < 0) {\n            writableDatabase.update(TABLE_APPS, values, \"$FIELD_PACKAGE = ?\", arrayOf(packageName))\n        }\n        close()\n    }\n\n    fun noteAppUsage(packageName: String) {\n        insertOrUpdateApp(packageName, FIELD_TIME to System.currentTimeMillis())\n    }\n\n    fun getForceCoarse(packageName: String): Boolean {\n        return readableDatabase.query(TABLE_APPS, arrayOf(FIELD_FORCE_COARSE), \"$FIELD_PACKAGE = ?\", arrayOf(packageName), null, null, null, \"1\").run {\n            try {\n                if (moveToNext()) {\n                    getIntOrNull(0) == 1\n                } else {\n                    false\n                }\n            } finally {\n                close()\n            }\n        }\n    }\n\n    fun setForceCoarse(packageName: String, forceCoarse: Boolean) {\n        insertOrUpdateApp(packageName, FIELD_FORCE_COARSE to (if (forceCoarse) 1 else 0))\n    }\n\n    fun noteAppLocation(packageName: String, location: Location?) {\n        noteAppUsage(packageName)\n        if (location == null) return\n        val values = contentValuesOf(\n            FIELD_PACKAGE to packageName,\n            FIELD_TIME to location.time,\n            FIELD_LATITUDE to location.latitude,\n            FIELD_LONGITUDE to location.longitude,\n            FIELD_ACCURACY to location.accuracy,\n            FIELD_PROVIDER to location.provider\n        )\n        writableDatabase.insertWithOnConflict(TABLE_APPS_LAST_LOCATION, null, values, SQLiteDatabase.CONFLICT_REPLACE)\n        close()\n    }\n\n    fun listAppsByAccessTime(limit: Int = Int.MAX_VALUE): List<Pair<String, Long>> {\n        val res = arrayListOf<Pair<String, Long>>()\n        readableDatabase.query(TABLE_APPS, arrayOf(FIELD_PACKAGE, FIELD_TIME), null, null, null, null, \"$FIELD_TIME DESC\", \"$limit\").apply {\n            while (moveToNext()) {\n                res.add(getString(0) to getLong(1))\n            }\n            close()\n        }\n        return res\n    }\n\n    fun getAppLocation(packageName: String): Location? {\n        return readableDatabase.query(\n            TABLE_APPS_LAST_LOCATION,\n            arrayOf(FIELD_LATITUDE, FIELD_LONGITUDE, FIELD_ACCURACY, FIELD_TIME, FIELD_PROVIDER),\n            \"$FIELD_PACKAGE = ?\",\n            arrayOf(packageName),\n            null,\n            null,\n            null,\n            \"1\"\n        ).run {\n            try {\n                if (moveToNext()) {\n                    Location(getString(4)).also {\n                        it.latitude = getDouble(0)\n                        it.longitude = getDouble(1)\n                        it.accuracy = getFloat(2)\n                        it.time = getLong(3)\n                    }\n                } else {\n                    null\n                }\n            } finally {\n                close()\n            }\n        }\n    }\n\n    override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {\n        onCreate(db)\n        if (oldVersion < 2) {\n            try {\n                db.execSQL(\"ALTER TABLE $TABLE_APPS ADD COLUMN IF NOT EXISTS $FIELD_FORCE_COARSE INTEGER;\")\n            } catch (ignored: Exception) {\n                // Ignoring\n            }\n        }\n    }\n\n    companion object {\n        private const val TABLE_APPS = \"apps\"\n        private const val TABLE_APPS_LAST_LOCATION = \"app_location\"\n        private const val FIELD_PACKAGE = \"package\"\n        private const val FIELD_FORCE_COARSE = \"force_coarse\"\n        private const val FIELD_LATITUDE = \"lat\"\n        private const val FIELD_LONGITUDE = \"lon\"\n        private const val FIELD_ACCURACY = \"acc\"\n        private const val FIELD_TIME = \"time\"\n        private const val FIELD_PROVIDER = \"provider\"\n    }\n}"
  },
  {
    "path": "play-services-location/core/src/main/kotlin/org/microg/gms/location/manager/LocationManager.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.manager\n\nimport android.Manifest\nimport android.app.Activity\nimport android.app.PendingIntent\nimport android.app.PendingIntent.FLAG_UPDATE_CURRENT\nimport android.content.Context\nimport android.content.Intent\nimport android.content.pm.PackageManager\nimport android.location.Location\nimport android.location.LocationManager.*\nimport android.os.*\nimport android.os.Build.VERSION.SDK_INT\nimport android.util.Log\nimport androidx.core.app.PendingIntentCompat\nimport androidx.core.content.ContextCompat\nimport androidx.core.content.getSystemService\nimport androidx.core.location.LocationListenerCompat\nimport androidx.core.location.LocationManagerCompat\nimport androidx.core.location.LocationRequestCompat.*\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.LifecycleOwner\nimport androidx.lifecycle.lifecycleScope\nimport com.google.android.gms.location.*\nimport com.google.android.gms.location.Granularity.GRANULARITY_COARSE\nimport com.google.android.gms.location.Granularity.GRANULARITY_FINE\nimport com.google.android.gms.location.Priority.PRIORITY_HIGH_ACCURACY\nimport com.google.android.gms.location.Priority.PRIORITY_PASSIVE\nimport com.google.android.gms.location.internal.ClientIdentity\nimport kotlinx.coroutines.CompletableDeferred\nimport kotlinx.coroutines.Deferred\nimport kotlinx.coroutines.sync.Mutex\nimport kotlinx.coroutines.sync.withLock\nimport org.microg.gms.location.*\nimport org.microg.gms.location.core.BuildConfig\nimport org.microg.gms.utils.IntentCacheManager\nimport java.io.PrintWriter\nimport kotlin.math.max\nimport kotlin.math.min\nimport android.location.LocationManager as SystemLocationManager\n\nclass LocationManager(private val context: Context, override val lifecycle: Lifecycle) : LifecycleOwner {\n    private var coarsePendingIntent: PendingIntent? = null\n    private val postProcessor by lazy { LocationPostProcessor() }\n    private val lastLocationCapsule by lazy { LastLocationCapsule(context) }\n    val database by lazy { LocationAppsDatabase(context) }\n    private val requestManager by lazy { LocationRequestManager(context, lifecycle, postProcessor, database) { updateLocationRequests() } }\n    private val gpsLocationListener by lazy { LocationListenerCompat { updateGpsLocation(it) } }\n    private val networkLocationListener by lazy { LocationListenerCompat { updateNetworkLocation(it) } }\n    private val settings by lazy { LocationSettings(context) }\n    private var boundToSystemNetworkLocation: Boolean = false\n    private val activePermissionRequestLock = Mutex()\n    private var activePermissionRequest: Deferred<Boolean>? = null\n    private var lastGpsLocation: Location? = null\n    private var lastNetworkLocation: Location? = null\n\n    private var currentGpsInterval: Long = -1\n    private var currentNetworkInterval: Long = -1\n\n    val deviceOrientationManager = DeviceOrientationManager(context, lifecycle) { updateLocationRequests() }\n\n    var started: Boolean = false\n        private set\n\n    suspend fun getLastLocation(clientIdentity: ClientIdentity, request: LastLocationRequest): Location? {\n        if (request.maxUpdateAgeMillis < 0) throw IllegalArgumentException()\n        GranularityUtil.checkValidGranularity(request.granularity)\n        if (request.isBypass) {\n            val permission = if (SDK_INT >= 33) \"android.permission.LOCATION_BYPASS\" else Manifest.permission.WRITE_SECURE_SETTINGS\n            if (context.checkPermission(permission, clientIdentity.pid, clientIdentity.uid) != PackageManager.PERMISSION_GRANTED) {\n                throw SecurityException(\"Caller must hold $permission for location bypass\")\n            }\n        }\n        if (request.impersonation != null) {\n            Log.w(TAG, \"${clientIdentity.packageName} wants to impersonate ${request.impersonation!!.packageName}. Ignoring.\")\n        }\n        val permissionGranularity = context.granularityFromPermission(clientIdentity)\n        var effectiveGranularity = getEffectiveGranularity(request.granularity, permissionGranularity)\n        if (effectiveGranularity == GRANULARITY_FINE && database.getForceCoarse(clientIdentity.packageName) && !clientIdentity.isSelfUser()) effectiveGranularity = GRANULARITY_COARSE\n        val returnedLocation = if (effectiveGranularity > permissionGranularity) {\n            // No last location available at requested granularity due to lack of permission\n            null\n        } else {\n            ensurePermissions()\n            val preLocation = lastLocationCapsule.getLocation(effectiveGranularity, request.maxUpdateAgeMillis)\n            val processedLocation = postProcessor.process(preLocation, effectiveGranularity, clientIdentity.isGoogle(context))\n            if (!context.noteAppOpForEffectiveGranularity(clientIdentity, effectiveGranularity)) {\n                // App Op denied\n                null\n            } else if (processedLocation != null && clientIdentity.isSelfProcess()) {\n                // When the request is coming from us, we want to make sure to return a new object to not accidentally modify the internal state\n                Location(processedLocation)\n            } else {\n                processedLocation\n            }\n        }\n        if (!clientIdentity.isSelfUser()) database.noteAppLocation(clientIdentity.packageName, returnedLocation)\n        return returnedLocation?.let { Location(it).apply { provider = \"fused\" } }\n    }\n\n    fun getLocationAvailability(clientIdentity: ClientIdentity, request: LocationAvailabilityRequest): LocationAvailability {\n        if (request.bypass) {\n            val permission = if (SDK_INT >= 33) \"android.permission.LOCATION_BYPASS\" else Manifest.permission.WRITE_SECURE_SETTINGS\n            if (context.checkPermission(permission, clientIdentity.pid, clientIdentity.uid) != PackageManager.PERMISSION_GRANTED) {\n                throw SecurityException(\"Caller must hold $permission for location bypass\")\n            }\n        }\n        if (request.impersonation != null) {\n            Log.w(TAG, \"${clientIdentity.packageName} wants to impersonate ${request.impersonation!!.packageName}. Ignoring.\")\n        }\n        return lastLocationCapsule.locationAvailability\n    }\n\n    suspend fun addBinderRequest(clientIdentity: ClientIdentity, binder: IBinder, callback: ILocationCallback, request: LocationRequest) {\n        updateBinderRequest(clientIdentity, null, binder, callback, request)\n    }\n\n    suspend fun updateBinderRequest(\n        clientIdentity: ClientIdentity,\n        oldBinder: IBinder?,\n        binder: IBinder,\n        callback: ILocationCallback,\n        request: LocationRequest\n    ) {\n        Log.d(TAG, \"updateBinderRequest $clientIdentity $request\")\n        request.verify(context, clientIdentity)\n        val new = requestManager.update(oldBinder, binder, clientIdentity, callback, request, lastLocationCapsule)\n        if (new) {\n            val permissionsChanged = ensurePermissions()\n            if (permissionsChanged) {\n                updateLocationRequests()\n            }\n        }\n    }\n\n    suspend fun removeBinderRequest(binder: IBinder) {\n        requestManager.remove(binder)\n    }\n\n    suspend fun addIntentRequest(clientIdentity: ClientIdentity, pendingIntent: PendingIntent, request: LocationRequest) {\n        request.verify(context, clientIdentity)\n        ensurePermissions()\n        requestManager.add(pendingIntent, clientIdentity, request, lastLocationCapsule)\n    }\n\n    suspend fun removeIntentRequest(pendingIntent: PendingIntent) {\n        requestManager.remove(pendingIntent)\n    }\n\n    fun start() {\n        synchronized(this) {\n            if (started) return\n            started = true\n        }\n        val intent = Intent(context, LocationManagerService::class.java)\n        intent.action = LocationManagerService.ACTION_REPORT_LOCATION\n        coarsePendingIntent = PendingIntentCompat.getService(context, 0, intent, FLAG_UPDATE_CURRENT, true)\n        lastLocationCapsule.start()\n        requestManager.start()\n    }\n\n    fun stop() {\n        synchronized(this) {\n            if (!started) return\n            started = false\n        }\n        requestManager.stop()\n        lastLocationCapsule.stop()\n        deviceOrientationManager.stop()\n\n        if (context.hasNetworkLocationServiceBuiltIn()) {\n            val intent = Intent(ACTION_NETWORK_LOCATION_SERVICE)\n            intent.`package` = context.packageName\n            intent.putExtra(EXTRA_PENDING_INTENT, coarsePendingIntent)\n            intent.putExtra(EXTRA_ENABLE, false)\n            context.startService(intent)\n        }\n\n        val locationManager = context.getSystemService<SystemLocationManager>() ?: return\n        try {\n            if (boundToSystemNetworkLocation) {\n                LocationManagerCompat.removeUpdates(locationManager, networkLocationListener)\n                boundToSystemNetworkLocation = false\n            }\n            LocationManagerCompat.removeUpdates(locationManager, gpsLocationListener)\n        } catch (e: SecurityException) {\n            // Ignore\n        }\n    }\n\n    private fun updateLocationRequests() {\n        val gpsInterval = when {\n            deviceOrientationManager.isActive -> min(requestManager.intervalMillis, DEVICE_ORIENTATION_INTERVAL)\n            requestManager.priority == PRIORITY_HIGH_ACCURACY && requestManager.granularity == GRANULARITY_FINE -> requestManager.intervalMillis\n            else -> Long.MAX_VALUE\n        }\n        val networkInterval = when {\n            gpsInterval != Long.MAX_VALUE &&\n                    (lastGpsLocation?.accuracy ?: Float.POSITIVE_INFINITY) <= NETWORK_OFF_GPS_ACCURACY &&\n                    (lastGpsLocation?.elapsedMillis ?: 0) > SystemClock.elapsedRealtime() - NETWORK_OFF_GPS_AGE -> Long.MAX_VALUE\n            requestManager.priority < PRIORITY_PASSIVE && requestManager.granularity == GRANULARITY_COARSE -> max(requestManager.intervalMillis, MAX_COARSE_UPDATE_INTERVAL)\n            requestManager.priority < PRIORITY_PASSIVE && requestManager.granularity == GRANULARITY_FINE -> max(requestManager.intervalMillis, MAX_FINE_UPDATE_INTERVAL)\n            deviceOrientationManager.isActive -> DEVICE_ORIENTATION_INTERVAL\n            else -> Long.MAX_VALUE\n        }\n        val lowPower = requestManager.granularity <= GRANULARITY_COARSE || requestManager.priority >= Priority.PRIORITY_LOW_POWER || (requestManager.priority >= Priority.PRIORITY_BALANCED_POWER_ACCURACY && requestManager.intervalMillis >= BALANCE_LOW_POWER_INTERVAL)\n\n        if (context.hasNetworkLocationServiceBuiltIn() && currentNetworkInterval != networkInterval) {\n            val intent = Intent(ACTION_NETWORK_LOCATION_SERVICE)\n            intent.`package` = context.packageName\n            intent.putExtra(EXTRA_PENDING_INTENT, coarsePendingIntent)\n            intent.putExtra(EXTRA_ENABLE, networkInterval != Long.MAX_VALUE)\n            intent.putExtra(EXTRA_INTERVAL_MILLIS, networkInterval)\n            intent.putExtra(EXTRA_LOW_POWER, lowPower)\n            intent.putExtra(EXTRA_WORK_SOURCE, requestManager.workSource)\n            context.startService(intent)\n            currentNetworkInterval = networkInterval\n        }\n\n        val locationManager = context.getSystemService<SystemLocationManager>() ?: return\n        if (gpsInterval != currentGpsInterval) {\n            if (gpsInterval == Long.MAX_VALUE) {\n                // Fetch last location from GPS, just to make sure we already considered it\n                try {\n                    val newGpsLocation = locationManager.getLastKnownLocation(GPS_PROVIDER)\n                    if (newGpsLocation != null && newGpsLocation.elapsedMillis > (lastGpsLocation?.elapsedMillis ?: 0)) {\n                        updateGpsLocation(newGpsLocation)\n                    }\n                } catch (e: SecurityException) {\n                    // Ignore\n                }\n            }\n            try {\n                locationManager.requestSystemProviderUpdates(GPS_PROVIDER, gpsInterval, QUALITY_HIGH_ACCURACY, gpsLocationListener)\n                currentGpsInterval = gpsInterval\n            } catch (e: Exception) {\n                // Ignore\n            }\n        }\n        if (!context.hasNetworkLocationServiceBuiltIn() && LocationManagerCompat.hasProvider(locationManager, NETWORK_PROVIDER) && currentNetworkInterval != networkInterval) {\n            boundToSystemNetworkLocation = true\n            if (networkInterval == Long.MAX_VALUE) {\n                // Fetch last location from GPS, just to make sure we already considered it\n                try {\n                    locationManager.getLastKnownLocation(NETWORK_PROVIDER)?.let { updateNetworkLocation(it) }\n                } catch (e: SecurityException) {\n                    // Ignore\n                }\n            }\n            try {\n                val quality = if (lowPower) QUALITY_LOW_POWER else QUALITY_BALANCED_POWER_ACCURACY\n                locationManager.requestSystemProviderUpdates(NETWORK_PROVIDER, networkInterval, quality, networkLocationListener)\n                currentNetworkInterval = networkInterval\n            } catch (e: Exception) {\n                // Ignore\n            }\n        }\n    }\n\n    private fun SystemLocationManager.requestSystemProviderUpdates(provider: String, interval: Long, @Quality quality: Int, listener: LocationListenerCompat) {\n        try {\n            if (interval != Long.MAX_VALUE) {\n                Log.d(TAG, \"Request updates for $provider at interval ${interval}ms\")\n                LocationManagerCompat.requestLocationUpdates(this, provider, Builder(interval).setQuality(quality).build(), listener, context.mainLooper)\n            } else {\n                Log.d(TAG, \"Remove updates for $provider\")\n                LocationManagerCompat.removeUpdates(this, listener)\n            }\n        } catch (e: SecurityException) {\n            throw RuntimeException(e)\n        } catch (e: Exception) {\n            throw RuntimeException(e)\n        }\n    }\n\n    fun updateNetworkLocation(location: Location) {\n        val lastLocation = lastLocationCapsule.getLocation(GRANULARITY_FINE)\n\n        // Ignore outdated location\n        if (lastLocation != null && location.elapsedMillis + UPDATE_CLIFF_MS < lastLocation.elapsedMillis) return\n\n        if (lastLocation == null ||\n            lastLocation.accuracy > location.accuracy ||\n            lastLocation.elapsedMillis + min(requestManager.intervalMillis * 2, UPDATE_CLIFF_MS) < location.elapsedMillis ||\n            lastLocation.accuracy + ((location.elapsedMillis - lastLocation.elapsedMillis) / 1000.0) > location.accuracy\n        ) {\n            lastLocationCapsule.updateCoarseLocation(location)\n            sendNewLocation()\n        }\n    }\n\n    private fun updateGpsLocation(location: Location) {\n        if (location.provider != GPS_PROVIDER) return\n        lastGpsLocation = location\n        lastLocationCapsule.updateFineLocation(location)\n        sendNewLocation()\n        updateLocationRequests()\n    }\n\n    private fun sendNewLocation() {\n        lifecycleScope.launchWhenStarted {\n            requestManager.processNewLocation(lastLocationCapsule)\n        }\n        lastLocationCapsule.getLocation(GRANULARITY_FINE)?.let { deviceOrientationManager.onLocationChanged(it) }\n    }\n\n    /**\n     * @return `true` if permissions changed\n     */\n    private suspend fun ensurePermissions(): Boolean {\n        if (SDK_INT < 23)\n            return false\n\n        val permissions = mutableListOf(Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION)\n        if (SDK_INT >= 29) permissions.add(Manifest.permission.ACCESS_BACKGROUND_LOCATION)\n\n        if (permissions.all { ContextCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED })\n            return false\n\n        if (BuildConfig.FORCE_SHOW_BACKGROUND_PERMISSION.isNotEmpty()) permissions.add(BuildConfig.FORCE_SHOW_BACKGROUND_PERMISSION)\n\n        return requestPermission(permissions)\n    }\n\n    private suspend fun requestPermission(permissions: List<String>): Boolean {\n        val (completable, deferred) = activePermissionRequestLock.withLock {\n            if (activePermissionRequest == null) {\n                val completable = CompletableDeferred<Boolean>()\n                activePermissionRequest = completable\n                completable to activePermissionRequest!!\n            } else {\n                null to activePermissionRequest!!\n            }\n        }\n        if (completable != null) {\n            val intent = Intent(context, AskPermissionActivity::class.java)\n            intent.putExtra(EXTRA_MESSENGER, Messenger(object : Handler(Looper.getMainLooper()) {\n                override fun handleMessage(msg: Message) {\n                    if (msg.what == Activity.RESULT_OK) {\n                        lastLocationCapsule.fetchFromSystem()\n                        updateLocationRequests()\n                        val grantResults = msg.data?.getIntArray(EXTRA_GRANT_RESULTS) ?: IntArray(0)\n                        completable.complete(grantResults.size == permissions.size && grantResults.all { it == PackageManager.PERMISSION_GRANTED })\n                    } else {\n                        completable.complete(false)\n                    }\n                }\n            }))\n            intent.putExtra(EXTRA_PERMISSIONS, permissions.toTypedArray())\n            intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK\n            context.startActivity(intent)\n            Log.d(TAG, \"Started AskPermissionActivity\")\n        }\n        return deferred.await()\n    }\n\n    fun dump(writer: PrintWriter) {\n        writer.println(\"Location availability: ${lastLocationCapsule.locationAvailability}\")\n        writer.println(\"Last coarse location: ${postProcessor.process(lastLocationCapsule.getLocation(GRANULARITY_COARSE), GRANULARITY_COARSE, true)}\")\n        writer.println(\"Last fine location: ${postProcessor.process(lastLocationCapsule.getLocation(GRANULARITY_FINE), GRANULARITY_FINE, true)}\")\n        writer.println(\"Interval: gps=${if (currentGpsInterval==Long.MAX_VALUE) \"off\" else currentGpsInterval.formatDuration()} network=${if (currentNetworkInterval==Long.MAX_VALUE) \"off\" else currentNetworkInterval.formatDuration()}\")\n        writer.println(\"Network location: built-in=${context.hasNetworkLocationServiceBuiltIn()} system=$boundToSystemNetworkLocation\")\n        requestManager.dump(writer)\n        deviceOrientationManager.dump(writer)\n    }\n\n    fun handleCacheIntent(intent: Intent) {\n        when (IntentCacheManager.getType(intent)) {\n            LocationRequestManager.CACHE_TYPE -> {\n                requestManager.handleCacheIntent(intent)\n            }\n\n            else -> {\n                Log.w(TAG, \"Unknown cache intent: $intent\")\n            }\n        }\n    }\n\n    companion object {\n        const val MAX_COARSE_UPDATE_INTERVAL = 20_000L\n        const val MAX_FINE_UPDATE_INTERVAL = 10_000L\n        const val EXTENSION_CLIFF_MS = 10_000L\n        const val UPDATE_CLIFF_MS = 30_000L\n        const val DEVICE_ORIENTATION_INTERVAL = 10_000L\n        const val NETWORK_OFF_GPS_AGE = 5000L\n        const val NETWORK_OFF_GPS_ACCURACY = 10f\n        const val BALANCE_LOW_POWER_INTERVAL = 30_000L\n    }\n}"
  },
  {
    "path": "play-services-location/core/src/main/kotlin/org/microg/gms/location/manager/LocationManagerInstance.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.manager\n\nimport android.Manifest.permission.*\nimport android.app.PendingIntent\nimport android.bluetooth.BluetoothManager\nimport android.content.Context\nimport android.content.Intent\nimport android.content.pm.PackageManager\nimport android.content.pm.PackageManager.PERMISSION_GRANTED\nimport android.location.Location\nimport android.location.LocationManager.GPS_PROVIDER\nimport android.location.LocationManager.NETWORK_PROVIDER\nimport android.os.Binder\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.IBinder\nimport android.os.Parcel\nimport android.os.SystemClock\nimport android.provider.Settings\nimport android.util.Log\nimport androidx.core.app.PendingIntentCompat\nimport androidx.core.content.getSystemService\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.LifecycleOwner\nimport androidx.lifecycle.lifecycleScope\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.api.internal.IStatusCallback\nimport com.google.android.gms.common.internal.ICancelToken\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableSerializer\nimport com.google.android.gms.location.*\nimport com.google.android.gms.location.internal.*\nimport com.google.android.gms.location.internal.DeviceOrientationRequestUpdateData.REMOVE_UPDATES\nimport com.google.android.gms.location.internal.DeviceOrientationRequestUpdateData.REQUEST_UPDATES\nimport kotlinx.coroutines.*\nimport org.microg.gms.location.hasNetworkLocationServiceBuiltIn\nimport org.microg.gms.location.settings.*\nimport org.microg.gms.utils.warnOnTransactionIssues\n\nclass LocationManagerInstance(\n    private val context: Context,\n    private val locationManager: LocationManager,\n    private val packageName: String,\n    override val lifecycle: Lifecycle\n) :\n    AbstractLocationManagerInstance(), LifecycleOwner {\n\n    // region Geofences\n\n    override fun addGeofences(geofencingRequest: GeofencingRequest?, pendingIntent: PendingIntent?, callbacks: IGeofencerCallbacks?) {\n        Log.d(TAG, \"Not yet implemented: addGeofences by ${getClientIdentity().packageName}\")\n    }\n\n    override fun removeGeofences(request: RemoveGeofencingRequest?, callback: IGeofencerCallbacks?) {\n        Log.d(TAG, \"Not yet implemented: removeGeofences by ${getClientIdentity().packageName}\")\n    }\n\n    override fun removeAllGeofences(callbacks: IGeofencerCallbacks?, packageName: String?) {\n        Log.d(TAG, \"Not yet implemented: removeAllGeofences by ${getClientIdentity().packageName}\")\n    }\n\n    // endregion\n\n    // region Activity\n\n    override fun getLastActivity(packageName: String?): ActivityRecognitionResult {\n        Log.d(TAG, \"Not yet implemented: getLastActivity by ${getClientIdentity().packageName}\")\n        return ActivityRecognitionResult(listOf(DetectedActivity(DetectedActivity.UNKNOWN, 0)), System.currentTimeMillis(), SystemClock.elapsedRealtime())\n    }\n\n    override fun requestActivityTransitionUpdates(request: ActivityTransitionRequest?, pendingIntent: PendingIntent?, callback: IStatusCallback?) {\n        Log.d(TAG, \"Not yet implemented: requestActivityTransitionUpdates by ${getClientIdentity().packageName}\")\n        callback?.onResult(Status.SUCCESS)\n    }\n\n    override fun removeActivityTransitionUpdates(pendingIntent: PendingIntent?, callback: IStatusCallback?) {\n        Log.d(TAG, \"Not yet implemented: removeActivityTransitionUpdates by ${getClientIdentity().packageName}\")\n        callback?.onResult(Status.SUCCESS)\n    }\n\n    override fun requestActivityUpdatesWithCallback(request: ActivityRecognitionRequest?, pendingIntent: PendingIntent?, callback: IStatusCallback?) {\n        Log.d(TAG, \"Not yet implemented: requestActivityUpdatesWithCallback by ${getClientIdentity().packageName}\")\n        callback?.onResult(Status.SUCCESS)\n    }\n\n    override fun removeActivityUpdates(callbackIntent: PendingIntent?) {\n        Log.d(TAG, \"Not yet implemented: removeActivityUpdates by ${getClientIdentity().packageName}\")\n    }\n\n    // endregion\n\n    // region Sleep\n\n    override fun removeSleepSegmentUpdates(pendingIntent: PendingIntent?, callback: IStatusCallback?) {\n        Log.d(TAG, \"Not yet implemented: removeSleepSegmentUpdates by ${getClientIdentity().packageName}\")\n        callback?.onResult(Status.SUCCESS)\n    }\n\n    override fun requestSleepSegmentUpdates(pendingIntent: PendingIntent?, request: SleepSegmentRequest?, callback: IStatusCallback?) {\n        Log.d(TAG, \"Not yet implemented: requestSleepSegmentUpdates by ${getClientIdentity().packageName}\")\n        callback?.onResult(Status.SUCCESS)\n    }\n\n    // endregion\n\n    // region Location\n\n    override fun flushLocations(callback: IFusedLocationProviderCallback?) {\n        Log.d(TAG, \"flushLocations by ${getClientIdentity().packageName}\")\n        checkHasAnyLocationPermission()\n        Log.d(TAG, \"Not yet implemented: flushLocations\")\n    }\n\n    override fun getLocationAvailabilityWithReceiver(request: LocationAvailabilityRequest, receiver: LocationReceiver) {\n        Log.d(TAG, \"getLocationAvailabilityWithReceiver by ${getClientIdentity().packageName}\")\n        checkHasAnyLocationPermission()\n        val callback = receiver.availabilityStatusCallback\n        val clientIdentity = getClientIdentity()\n        lifecycleScope.launchWhenStarted {\n            try {\n                callback.onLocationAvailabilityStatus(Status.SUCCESS, locationManager.getLocationAvailability(clientIdentity, request))\n            } catch (e: Exception) {\n                try {\n                    callback.onLocationAvailabilityStatus(Status(CommonStatusCodes.ERROR, e.message), LocationAvailability.UNAVAILABLE)\n                } catch (e2: Exception) {\n                    Log.w(TAG, \"Failed\", e)\n                }\n            }\n        }\n    }\n\n    override fun getCurrentLocationWithReceiver(request: CurrentLocationRequest, receiver: LocationReceiver): ICancelToken {\n        Log.d(TAG, \"getCurrentLocationWithReceiver by ${getClientIdentity().packageName}\")\n        checkHasAnyLocationPermission()\n        var returned = false\n        val callback = receiver.statusCallback\n        val clientIdentity = getClientIdentity()\n        val binderIdentity = Binder()\n        val job = lifecycleScope.launchWhenStarted {\n            try {\n                val scope = this\n                val callbackForRequest = object : ILocationCallback.Stub() {\n                    override fun onLocationResult(result: LocationResult?) {\n                        if (!returned) runCatching { callback.onLocationStatus(Status.SUCCESS, result?.lastLocation) }\n                        returned = true\n                        scope.cancel()\n                    }\n\n                    override fun onLocationAvailability(availability: LocationAvailability?) {\n                        // Ignore\n                    }\n\n                    override fun cancel() {\n                        if (!returned) runCatching { callback.onLocationStatus(Status.SUCCESS, null) }\n                        returned = true\n                        scope.cancel()\n                    }\n                }\n                val currentLocationRequest = LocationRequest.Builder(request.priority, 1000)\n                    .setGranularity(request.granularity)\n                    .setMaxUpdateAgeMillis(request.maxUpdateAgeMillis)\n                    .setDurationMillis(request.durationMillis)\n                    .setPriority(request.priority)\n                    .setWorkSource(request.workSource)\n                    .setThrottleBehavior(request.throttleBehavior)\n                    .build()\n                locationManager.addBinderRequest(clientIdentity, binderIdentity, callbackForRequest, currentLocationRequest)\n                awaitCancellation()\n            } catch (e: CancellationException) {\n                // Don't send result. Either this was cancelled from the CancelToken or because a location was retrieved.\n                // Both cases send the result themselves.\n            } catch (e: Exception) {\n                try {\n                    if (!returned) callback.onLocationStatus(Status(CommonStatusCodes.ERROR, e.message), null)\n                    returned = true\n                } catch (e2: Exception) {\n                    Log.w(TAG, \"Failed\", e)\n                }\n            } finally {\n                runCatching { locationManager.removeBinderRequest(binderIdentity) }\n            }\n        }\n        return object : ICancelToken.Stub() {\n            override fun cancel() {\n                if (!returned) runCatching { callback.onLocationStatus(Status.CANCELED, null) }\n                returned = true\n                job.cancel()\n            }\n        }\n    }\n\n    override fun getLastLocationWithReceiver(request: LastLocationRequest, receiver: LocationReceiver) {\n        Log.d(TAG, \"getLastLocationWithReceiver by ${getClientIdentity().packageName}\")\n        checkHasAnyLocationPermission()\n        val callback = receiver.statusCallback\n        val clientIdentity = getClientIdentity()\n        lifecycleScope.launchWhenStarted {\n            try {\n                callback.onLocationStatus(Status.SUCCESS, locationManager.getLastLocation(clientIdentity, request))\n            } catch (e: Exception) {\n                try {\n                    callback.onLocationStatus(Status(CommonStatusCodes.ERROR, e.message), null)\n                } catch (e2: Exception) {\n                    Log.w(TAG, \"Failed\", e)\n                }\n            }\n        }\n    }\n\n    override fun requestLocationSettingsDialog(settingsRequest: LocationSettingsRequest?, callback: ISettingsCallbacks?, packageName: String?) {\n        Log.d(TAG, \"requestLocationSettingsDialog by ${getClientIdentity().packageName} $settingsRequest\")\n        val clientIdentity = getClientIdentity()\n        lifecycleScope.launchWhenStarted {\n            val states = context.getDetailedLocationSettingsStates()\n            val requests = settingsRequest?.requests?.map {\n                it.priority to (if (it.granularity == Granularity.GRANULARITY_PERMISSION_LEVEL) context.granularityFromPermission(clientIdentity) else it.granularity)\n            }.orEmpty()\n            val gpsRequested = requests.any { it.first == Priority.PRIORITY_HIGH_ACCURACY && it.second == Granularity.GRANULARITY_FINE }\n            val networkLocationRequested = requests.any { it.first <= Priority.PRIORITY_LOW_POWER && it.second >= Granularity.GRANULARITY_COARSE }\n            val bleRequested = settingsRequest?.needBle == true\n            // Starting Android 10, fine location permission is required to scan for wifi networks\n            val networkLocationRequiresFine = context.hasNetworkLocationServiceBuiltIn() && SDK_INT >= 29\n            val statusCode = when {\n                // Permission checks\n                gpsRequested && states.gpsPresent && !states.fineLocationPermission -> CommonStatusCodes.RESOLUTION_REQUIRED\n                networkLocationRequested && states.networkLocationPresent && !states.coarseLocationPermission -> CommonStatusCodes.RESOLUTION_REQUIRED\n                networkLocationRequested && states.networkLocationPresent && networkLocationRequiresFine && !states.fineLocationPermission -> CommonStatusCodes.RESOLUTION_REQUIRED\n                // Enabled checks\n                gpsRequested && states.gpsPresent && !states.gpsUsable -> CommonStatusCodes.RESOLUTION_REQUIRED\n                networkLocationRequested && states.networkLocationPresent && !states.networkLocationUsable -> CommonStatusCodes.RESOLUTION_REQUIRED\n                bleRequested && states.blePresent && !states.bleUsable -> CommonStatusCodes.RESOLUTION_REQUIRED\n                // Feature not present checks\n                gpsRequested && !states.gpsPresent -> LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE\n                networkLocationRequested && !states.networkLocationPresent -> LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE\n                bleRequested && !states.blePresent -> LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE\n                else -> CommonStatusCodes.SUCCESS\n            }\n\n            val resolution = if (statusCode == CommonStatusCodes.RESOLUTION_REQUIRED) {\n                val intent = Intent(ACTION_LOCATION_SETTINGS_CHECKER)\n                intent.setPackage(context.packageName)\n                intent.putExtra(EXTRA_ORIGINAL_PACKAGE_NAME, clientIdentity.packageName)\n                intent.putExtra(EXTRA_SETTINGS_REQUEST, SafeParcelableSerializer.serializeToBytes(settingsRequest))\n                PendingIntentCompat.getActivity(context, clientIdentity.packageName.hashCode(), intent, PendingIntent.FLAG_UPDATE_CURRENT, true)\n            } else null\n            val status = Status(statusCode, LocationSettingsStatusCodes.getStatusCodeString(statusCode), resolution)\n            Log.d(TAG, \"requestLocationSettingsDialog by ${getClientIdentity().packageName} returns $status\")\n            runCatching { callback?.onLocationSettingsResult(LocationSettingsResult(status, states.toApi())) }\n        }\n    }\n\n    override fun isGoogleLocationAccuracyEnabled(callback: IBooleanStatusCallback?) {\n        Log.d(TAG, \"isGoogleLocationAccuracyEnabled by ${getClientIdentity().packageName}\")\n        callback?.onBooleanStatus(Status.SUCCESS, true)\n    }\n\n    override fun setGoogleLocationAccuracy(request: SetGoogleLocationAccuracyRequest?, callback: IStatusCallback?) {\n        Log.d(TAG, \"setGoogleLocationAccuracy by ${getClientIdentity().packageName}\")\n        callback?.onResult(Status.SUCCESS)\n    }\n\n    // region Mock locations\n\n    override fun setMockModeWithCallback(mockMode: Boolean, callback: IStatusCallback) {\n        Log.d(TAG, \"setMockModeWithCallback by ${getClientIdentity().packageName}\")\n        checkHasAnyLocationPermission()\n        val clientIdentity = getClientIdentity()\n        lifecycleScope.launchWhenStarted {\n            try {\n                Log.d(TAG, \"Not yet implemented: setMockModeWithCallback\")\n                callback.onResult(Status.SUCCESS)\n            } catch (e: Exception) {\n                Log.w(TAG, \"Failed\", e)\n            }\n        }\n    }\n\n    override fun setMockLocationWithCallback(mockLocation: Location, callback: IStatusCallback) {\n        Log.d(TAG, \"setMockLocationWithCallback by ${getClientIdentity().packageName}\")\n        checkHasAnyLocationPermission()\n        val clientIdentity = getClientIdentity()\n        lifecycleScope.launchWhenStarted {\n            try {\n                Log.d(TAG, \"Not yet implemented: setMockLocationWithCallback\")\n                callback.onResult(Status.SUCCESS)\n            } catch (e: Exception) {\n                Log.w(TAG, \"Failed\", e)\n            }\n        }\n    }\n\n    // endregion\n\n    // region Location updates\n\n    override fun registerLocationUpdates(\n        oldBinder: IBinder?,\n        binder: IBinder,\n        callback: ILocationCallback,\n        request: LocationRequest,\n        statusCallback: IStatusCallback\n    ) {\n        Log.d(TAG, \"registerLocationUpdates (callback) by ${getClientIdentity().packageName}\")\n        checkHasAnyLocationPermission()\n        val clientIdentity = getClientIdentity()\n        lifecycleScope.launchWhenStarted {\n            try {\n                locationManager.updateBinderRequest(clientIdentity, oldBinder, binder, callback, request)\n                statusCallback.onResult(Status.SUCCESS)\n            } catch (e: Exception) {\n                try {\n                    statusCallback.onResult(Status(CommonStatusCodes.ERROR, e.message))\n                } catch (e2: Exception) {\n                    Log.w(TAG, \"Failed\", e)\n                }\n            }\n        }\n    }\n\n    override fun registerLocationUpdates(pendingIntent: PendingIntent, request: LocationRequest, statusCallback: IStatusCallback) {\n        Log.d(TAG, \"registerLocationUpdates (intent) by ${getClientIdentity().packageName}\")\n        checkHasAnyLocationPermission()\n        val clientIdentity = getClientIdentity()\n        lifecycleScope.launchWhenStarted {\n            try {\n                locationManager.addIntentRequest(clientIdentity, pendingIntent, request)\n                statusCallback.onResult(Status.SUCCESS)\n            } catch (e: Exception) {\n                try {\n                    statusCallback.onResult(Status(CommonStatusCodes.ERROR, e.message))\n                } catch (e2: Exception) {\n                    Log.w(TAG, \"Failed\", e)\n                }\n            }\n        }\n    }\n\n    override fun unregisterLocationUpdates(binder: IBinder, statusCallback: IStatusCallback) {\n        Log.d(TAG, \"unregisterLocationUpdates (callback) by ${getClientIdentity().packageName}\")\n        lifecycleScope.launchWhenStarted {\n            try {\n                locationManager.removeBinderRequest(binder)\n                statusCallback.onResult(Status.SUCCESS)\n            } catch (e: Exception) {\n                try {\n                    statusCallback.onResult(Status(CommonStatusCodes.ERROR, e.message))\n                } catch (e2: Exception) {\n                    Log.w(TAG, \"Failed\", e)\n                }\n            }\n        }\n    }\n\n    override fun unregisterLocationUpdates(pendingIntent: PendingIntent, statusCallback: IStatusCallback) {\n        Log.d(TAG, \"unregisterLocationUpdates (intent) by ${getClientIdentity().packageName}\")\n        lifecycleScope.launchWhenStarted {\n            try {\n                locationManager.removeIntentRequest(pendingIntent)\n                statusCallback.onResult(Status.SUCCESS)\n            } catch (e: Exception) {\n                try {\n                    statusCallback.onResult(Status(CommonStatusCodes.ERROR, e.message))\n                } catch (e2: Exception) {\n                    Log.w(TAG, \"Failed\", e)\n                }\n            }\n        }\n    }\n\n    // endregion\n\n    // endregion\n\n    // region Device Orientation\n\n    override fun updateDeviceOrientationRequest(request: DeviceOrientationRequestUpdateData) {\n        Log.d(TAG, \"updateDeviceOrientationRequest by ${getClientIdentity().packageName}\")\n        checkHasAnyLocationPermission()\n        val clientIdentity = getClientIdentity()\n        val callback = request.fusedLocationProviderCallback\n        lifecycleScope.launchWhenStarted {\n            try {\n                when (request.opCode) {\n                    REQUEST_UPDATES -> locationManager.deviceOrientationManager.add(clientIdentity, request.request, request.listener)\n                    REMOVE_UPDATES -> locationManager.deviceOrientationManager.remove(clientIdentity, request.listener)\n                    else -> throw UnsupportedOperationException(\"Op code ${request.opCode} not supported\")\n                }\n                callback?.onFusedLocationProviderResult(FusedLocationProviderResult.SUCCESS)\n            } catch (e: Exception) {\n                try {\n                    callback?.onFusedLocationProviderResult(FusedLocationProviderResult.create(Status(CommonStatusCodes.ERROR, e.message)))\n                } catch (e2: Exception) {\n                    Log.w(TAG, \"Failed\", e)\n                }\n            }\n        }\n    }\n\n    // endregion\n\n    private fun getClientIdentity() = ClientIdentity(packageName).apply { uid = getCallingUid(); pid = getCallingPid() }\n\n    private fun checkHasAnyLocationPermission() = checkHasAnyPermission(ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION)\n\n    private fun checkHasAnyPermission(vararg permissions: String) {\n        for (permission in permissions) {\n            if (context.packageManager.checkPermission(permission, packageName) == PERMISSION_GRANTED) {\n                return\n            }\n        }\n        throw SecurityException(\"$packageName does not have any of $permissions\")\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =\n        warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n}"
  },
  {
    "path": "play-services-location/core/src/main/kotlin/org/microg/gms/location/manager/LocationManagerService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.manager\n\nimport android.content.Intent\nimport android.location.Location\nimport android.os.Binder\nimport android.os.Process\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.internal.ConnectionInfo\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.common.PackageUtils\nimport org.microg.gms.location.EXTRA_LOCATION\nimport org.microg.gms.utils.IntentCacheManager\nimport java.io.FileDescriptor\nimport java.io.PrintWriter\n\n\nclass LocationManagerService : BaseService(TAG, GmsService.GOOGLE_LOCATION_MANAGER) {\n    private val locationManager = LocationManager(this, lifecycle)\n\n    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {\n        locationManager.start()\n        if (Binder.getCallingUid() == Process.myUid() && intent?.action == ACTION_REPORT_LOCATION) {\n            val location = intent.getParcelableExtra<Location>(EXTRA_LOCATION)\n            if (location != null) {\n                locationManager.updateNetworkLocation(location)\n            }\n        }\n        if (intent != null && IntentCacheManager.isCache(intent)) {\n            locationManager.handleCacheIntent(intent)\n        }\n        return super.onStartCommand(intent, flags, startId)\n    }\n\n    override fun onDestroy() {\n        locationManager.stop()\n        super.onDestroy()\n    }\n\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService?) {\n        val packageName = PackageUtils.getAndCheckCallingPackage(this, request.packageName)\n            ?: throw IllegalArgumentException(\"Missing package name\")\n        locationManager.start()\n        callback.onPostInitCompleteWithConnectionInfo(\n            CommonStatusCodes.SUCCESS,\n            LocationManagerInstance(this, locationManager, packageName, lifecycle).asBinder(),\n            ConnectionInfo().apply { features = FEATURES }\n        )\n    }\n\n    override fun dump(fd: FileDescriptor?, writer: PrintWriter, args: Array<out String>?) {\n        super.dump(fd, writer, args)\n        locationManager.dump(writer)\n    }\n\n    companion object {\n        const val ACTION_REPORT_LOCATION = \"org.microg.gms.location.manager.ACTION_REPORT_LOCATION\"\n    }\n}"
  },
  {
    "path": "play-services-location/core/src/main/kotlin/org/microg/gms/location/manager/LocationPostProcessor.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.manager\n\nimport android.location.Location\nimport android.os.SystemClock\nimport androidx.core.location.LocationCompat\nimport com.google.android.gms.location.Granularity\nimport com.google.android.gms.location.Granularity.GRANULARITY_COARSE\nimport java.security.SecureRandom\nimport kotlin.math.cos\nimport kotlin.math.max\nimport kotlin.math.round\n\nclass LocationPostProcessor {\n    private var nextUpdateElapsedRealtime = 0L\n    private val random = SecureRandom()\n    private var latitudeOffsetMeters = nextOffsetMeters()\n    private var longitudeOffsetMeters = nextOffsetMeters()\n\n    // We cache the latest coarsed location\n    private var coarseLocationBefore: Location? = null\n    private var coarseLocationAfter: Location? = null\n\n    private fun nextOffsetMeters(): Double = random.nextGaussian() * (COARSE_ACCURACY_METERS / 4.0)\n\n    // We change the offset regularly to ensure there is no possibility to determine the offset and thus know exact locations when at a cliff.\n    private fun updateOffsetMetersIfNeeded() {\n        if (nextUpdateElapsedRealtime >= SystemClock.elapsedRealtime()) {\n            latitudeOffsetMeters = latitudeOffsetMeters * 0.97 + nextOffsetMeters() * 0.03\n            longitudeOffsetMeters = longitudeOffsetMeters * 0.97 + nextOffsetMeters() * 0.03\n            nextUpdateElapsedRealtime = SystemClock.elapsedRealtime() + COARSE_UPDATE_TIME\n        }\n    }\n\n    fun process(location: Location?, granularity: @Granularity Int, forGoogle: Boolean): Location? {\n        if (location == null) return null\n        val extrasAllowList = if (forGoogle) GOOGLE_EXTRAS_LIST else PUBLIC_EXTRAS_LIST\n        return when {\n            granularity == GRANULARITY_COARSE -> {\n                if (location == coarseLocationBefore || location == coarseLocationAfter) {\n                    coarseLocationAfter\n                } else {\n                    val newLocation = Location(location)\n                    newLocation.removeBearing()\n                    newLocation.removeSpeed()\n                    newLocation.removeAltitude()\n                    if (LocationCompat.hasBearingAccuracy(newLocation)) LocationCompat.setBearingAccuracyDegrees(newLocation, 0f)\n                    if (LocationCompat.hasSpeedAccuracy(newLocation)) LocationCompat.setSpeedAccuracyMetersPerSecond(newLocation, 0f)\n                    if (LocationCompat.hasVerticalAccuracy(newLocation)) LocationCompat.setVerticalAccuracyMeters(newLocation, 0f)\n                    newLocation.extras = null\n                    newLocation.accuracy = max(newLocation.accuracy, COARSE_ACCURACY_METERS)\n                    updateOffsetMetersIfNeeded()\n                    val latitudeAccuracy = metersToLongitudeAtEquator(COARSE_ACCURACY_METERS.toDouble())\n                    val longitudeAccuracy = metersToLongitudeAtLatitude(COARSE_ACCURACY_METERS.toDouble(), location.latitude)\n                    val offsetLatitude = coerceLatitude(location.latitude) + metersToLongitudeAtEquator(latitudeOffsetMeters)\n                    newLocation.latitude = coerceLatitude(round(offsetLatitude / latitudeAccuracy) * latitudeAccuracy)\n                    val offsetLongitude = coerceLongitude(location.longitude) + metersToLongitudeAtLatitude(longitudeOffsetMeters, newLocation.latitude)\n                    newLocation.longitude = coerceLongitude(round(offsetLongitude / longitudeAccuracy) * longitudeAccuracy)\n                    coarseLocationBefore = location\n                    coarseLocationAfter = newLocation\n                    newLocation\n                }\n            }\n\n            location.hasAnyNonAllowedExtra(extrasAllowList) -> Location(location).stripExtras(extrasAllowList)\n            else -> location\n        }\n    }\n\n    companion object {\n        private const val COARSE_ACCURACY_METERS = 2000f\n        private const val COARSE_UPDATE_TIME = 3600_000\n        private const val EQUATOR_METERS_PER_LONGITUDE = 111000.0\n\n        val PUBLIC_EXTRAS_LIST = listOf(\n            \"noGPSLocation\",\n            LocationCompat.EXTRA_VERTICAL_ACCURACY,\n            LocationCompat.EXTRA_BEARING_ACCURACY,\n            LocationCompat.EXTRA_SPEED_ACCURACY,\n            LocationCompat.EXTRA_MSL_ALTITUDE,\n            LocationCompat.EXTRA_MSL_ALTITUDE_ACCURACY,\n            LocationCompat.EXTRA_IS_MOCK,\n        )\n\n        val GOOGLE_EXTRAS_LIST = listOf(\n            \"noGPSLocation\",\n            LocationCompat.EXTRA_VERTICAL_ACCURACY,\n            LocationCompat.EXTRA_BEARING_ACCURACY,\n            LocationCompat.EXTRA_SPEED_ACCURACY,\n            LocationCompat.EXTRA_MSL_ALTITUDE,\n            LocationCompat.EXTRA_MSL_ALTITUDE_ACCURACY,\n            LocationCompat.EXTRA_IS_MOCK,\n            \"locationType\",\n            \"levelId\",\n            \"levelNumberE3\",\n            \"floorLabel\",\n            \"indoorProbability\",\n            \"wifiScan\"\n        )\n\n        private fun Location.hasAnyNonAllowedExtra(allowList: List<String>): Boolean {\n            for (key in extras?.keySet().orEmpty()) {\n                if (key !in allowList) {\n                    return true\n                }\n            }\n            return false\n        }\n\n        private fun Location.stripExtras(allowList: List<String>): Location {\n            val extras = extras\n            for (key in extras?.keySet().orEmpty()) {\n                if (key !in allowList) {\n                    extras?.remove(key)\n                }\n            }\n            this.extras = if (extras?.isEmpty == true) null else extras\n            return this\n        }\n\n        private fun metersToLongitudeAtEquator(meters: Double): Double = meters / EQUATOR_METERS_PER_LONGITUDE\n\n        private fun metersToLongitudeAtLatitude(meters: Double, latitude: Double): Double = metersToLongitudeAtEquator(meters) / cos(Math.toRadians(latitude))\n\n        /**\n         * Coerce latitude value to be between -89.99999° and 89.99999°.\n         *\n         * Sorry to those, who actually are at the geographical north/south pole, but at exactly 90°, our math wouldn't work out anymore.\n         */\n        private fun coerceLatitude(latitude: Double): Double = latitude.coerceIn(-89.99999, 89.99999)\n\n        /**\n         * Coerce longitude value to be between -180.00° and 180.00°.\n         */\n        private fun coerceLongitude(longitude: Double): Double = (longitude % 360.0).let {\n            when {\n                it >= 180.0 -> it - 360.0\n                it < -180.0 -> it + 360.0\n                else -> it\n            }\n        }\n    }\n}"
  },
  {
    "path": "play-services-location/core/src/main/kotlin/org/microg/gms/location/manager/LocationRequestManager.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.manager\n\nimport android.Manifest\nimport android.app.AppOpsManager\nimport android.app.PendingIntent\nimport android.content.Context\nimport android.content.Intent\nimport android.content.pm.PackageManager\nimport android.location.Location\nimport android.os.*\nimport android.os.Build.VERSION.SDK_INT\nimport android.util.Log\nimport androidx.annotation.GuardedBy\nimport androidx.core.content.ContextCompat\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.LifecycleOwner\nimport androidx.lifecycle.lifecycleScope\nimport com.google.android.gms.location.*\nimport com.google.android.gms.location.Granularity.*\nimport com.google.android.gms.location.Priority.*\nimport com.google.android.gms.location.internal.ClientIdentity\nimport kotlinx.coroutines.delay\nimport kotlinx.coroutines.sync.Mutex\nimport kotlinx.coroutines.sync.withLock\nimport org.microg.gms.location.GranularityUtil\nimport org.microg.gms.location.PriorityUtil\nimport org.microg.gms.location.elapsedMillis\nimport org.microg.gms.location.formatDuration\nimport org.microg.gms.utils.IntentCacheManager\nimport org.microg.gms.utils.WorkSourceUtil\nimport java.io.PrintWriter\nimport kotlin.math.max\n\nclass LocationRequestManager(private val context: Context, override val lifecycle: Lifecycle, private val postProcessor: LocationPostProcessor, private val database: LocationAppsDatabase = LocationAppsDatabase(context), private val requestDetailsUpdatedCallback: () -> Unit) :\n    IBinder.DeathRecipient, LifecycleOwner {\n    private val lock = Mutex()\n    private val binderRequests = mutableMapOf<IBinder, LocationRequestHolder>()\n    private val pendingIntentRequests = mutableMapOf<PendingIntent, LocationRequestHolder>()\n    private val cacheManager by lazy { IntentCacheManager.create<LocationManagerService, LocationRequestHolderParcelable>(context, CACHE_TYPE) }\n    var priority: @Priority Int = PRIORITY_PASSIVE\n    var granularity: @Granularity Int = GRANULARITY_PERMISSION_LEVEL\n        private set\n    var intervalMillis: Long = Long.MAX_VALUE\n        private set\n    var workSource = WorkSource()\n        private set\n    private var grantedPermissions: List<Int> = locationPermissions.map { ContextCompat.checkSelfPermission(context, it) }\n    private var permissionChanged: Boolean = false\n    private var requestDetailsUpdated = false\n    private var checkingWhileHighAccuracy = false\n\n    private val appOpsLock = Any()\n    @GuardedBy(\"appOpsLock\")\n    private var currentAppOps = emptyMap<ClientIdentity, Boolean>()\n\n    override fun binderDied() {\n        lifecycleScope.launchWhenStarted {\n            lock.withLock {\n                val toRemove = binderRequests.keys.filter { !it.isBinderAlive }.toList()\n                for (binder in toRemove) {\n                    binderRequests.remove(binder)\n                }\n                recalculateRequests()\n            }\n            notifyRequestDetailsUpdated()\n        }\n    }\n\n    suspend fun add(binder: IBinder, clientIdentity: ClientIdentity, callback: ILocationCallback, request: LocationRequest, lastLocationCapsule: LastLocationCapsule) {\n        update(null, binder, clientIdentity, callback, request, lastLocationCapsule)\n    }\n\n    suspend fun update(oldBinder: IBinder?, binder: IBinder, clientIdentity: ClientIdentity, callback: ILocationCallback, request: LocationRequest, lastLocationCapsule: LastLocationCapsule): Boolean {\n        var new = false\n        lock.withLock {\n            try {\n                oldBinder?.unlinkToDeath(this, 0)\n            } catch (e: Exception) {\n                Log.w(TAG, \"update: \", e)\n            }\n            val holder = binderRequests.remove(oldBinder)\n            new = holder == null\n            try {\n                val startedHolder = holder?.update(callback, request) ?: LocationRequestHolder(context, clientIdentity, request, callback, null).start().also {\n                    var effectiveGranularity = it.effectiveGranularity\n                    if (effectiveGranularity == GRANULARITY_FINE && database.getForceCoarse(it.clientIdentity.packageName) && !clientIdentity.isSelfUser()) effectiveGranularity = GRANULARITY_COARSE\n                    val lastLocation = lastLocationCapsule.getLocation(effectiveGranularity, request.maxUpdateAgeMillis)\n                    if (lastLocation != null) it.processNewLocation(lastLocation)\n                }\n                binderRequests[binder] = startedHolder\n                binder.linkToDeath(this, 0)\n            } catch (e: Exception) {\n                holder?.cancel()\n            }\n            recalculateRequests()\n        }\n        notifyRequestDetailsUpdated()\n        return new\n    }\n\n    suspend fun remove(oldBinder: IBinder) {\n        lock.withLock {\n            oldBinder.unlinkToDeath(this, 0)\n            val holder = binderRequests.remove(oldBinder)\n            if (holder != null) {\n                holder.cancel()\n                recalculateRequests()\n            }\n        }\n        notifyRequestDetailsUpdated()\n    }\n\n    suspend fun add(pendingIntent: PendingIntent, clientIdentity: ClientIdentity, request: LocationRequest, lastLocationCapsule: LastLocationCapsule) {\n        lock.withLock {\n            try {\n                pendingIntentRequests[pendingIntent] = LocationRequestHolder(context, clientIdentity, request, null, pendingIntent).start().also {\n                    cacheManager.add(it.asParcelable()) { it.pendingIntent == pendingIntent }\n                    var effectiveGranularity = it.effectiveGranularity\n                    if (effectiveGranularity == GRANULARITY_FINE && database.getForceCoarse(it.clientIdentity.packageName) && !clientIdentity.isSelfUser()) effectiveGranularity = GRANULARITY_COARSE\n                    val lastLocation = lastLocationCapsule.getLocation(effectiveGranularity, request.maxUpdateAgeMillis)\n                    if (lastLocation != null) it.processNewLocation(lastLocation)\n                }\n            } catch (e: Exception) {\n                // Ignore\n            }\n            recalculateRequests()\n        }\n        notifyRequestDetailsUpdated()\n    }\n\n    suspend fun remove(pendingIntent: PendingIntent) {\n        lock.withLock {\n            cacheManager.removeIf { it.pendingIntent == pendingIntent }\n            if (pendingIntentRequests.remove(pendingIntent) != null) recalculateRequests()\n        }\n        notifyRequestDetailsUpdated()\n    }\n\n    private fun <T> processNewLocation(lastLocationCapsule: LastLocationCapsule, map: Map<T, LocationRequestHolder>): Pair<Set<T>, Set<T>> {\n        val toRemove = mutableSetOf<T>()\n        val updated = mutableSetOf<T>()\n        for ((key, holder) in map) {\n            try {\n                var effectiveGranularity = holder.effectiveGranularity\n                if (effectiveGranularity == GRANULARITY_FINE && database.getForceCoarse(holder.clientIdentity.packageName) && !holder.clientIdentity.isSelfUser()) effectiveGranularity = GRANULARITY_COARSE\n                val location = lastLocationCapsule.getLocation(effectiveGranularity)\n                postProcessor.process(location, effectiveGranularity, holder.clientIdentity.isGoogle(context))?.let {\n                    if (holder.processNewLocation(it)) {\n                        if (!holder.clientIdentity.isSelfUser()) database.noteAppLocation(holder.clientIdentity.packageName, it)\n                        updated.add(key)\n                    }\n                }\n            } catch (e: Exception) {\n                Log.w(TAG, \"Exception while processing for ${holder.workSource}: ${e.message}\")\n                toRemove.add(key)\n            }\n        }\n        return toRemove to updated\n    }\n\n    suspend fun processNewLocation(lastLocationCapsule: LastLocationCapsule) {\n        lock.withLock {\n            val (pendingIntentsToRemove, pendingIntentsUpdated) = processNewLocation(lastLocationCapsule, pendingIntentRequests)\n            for (pendingIntent in pendingIntentsToRemove) {\n                cacheManager.removeIf { it.pendingIntent == pendingIntent }\n                pendingIntentRequests.remove(pendingIntent)\n            }\n            for (pendingIntent in pendingIntentsUpdated) {\n                cacheManager.add(pendingIntentRequests[pendingIntent]!!.asParcelable()) { it.pendingIntent == pendingIntent }\n            }\n            val (bindersToRemove, _) = processNewLocation(lastLocationCapsule, binderRequests)\n            for (binder in bindersToRemove) {\n                try {\n                    binderRequests[binder]?.cancel()\n                } catch (e: Exception) {\n                    // Ignore\n                }\n                binderRequests.remove(binder)\n            }\n            if (pendingIntentsToRemove.isNotEmpty() || bindersToRemove.isNotEmpty()) {\n                recalculateRequests()\n            }\n        }\n        notifyRequestDetailsUpdated()\n    }\n\n    private fun recalculateRequests() {\n        val merged = binderRequests.values + pendingIntentRequests.values\n        val newGranularity = merged.maxOfOrNull { it.effectiveGranularity } ?: GRANULARITY_PERMISSION_LEVEL\n        val newPriority = merged.minOfOrNull { it.effectivePriority } ?: PRIORITY_PASSIVE\n        val newIntervalMillis = merged.minOfOrNull { it.intervalMillis } ?: Long.MAX_VALUE\n        val newWorkSource = WorkSource()\n        for (holder in merged) {\n            newWorkSource.add(holder.workSource)\n        }\n        if (newPriority == PRIORITY_HIGH_ACCURACY && priority != PRIORITY_HIGH_ACCURACY) lifecycleScope.launchWhenStarted { checkWhileHighAccuracy() }\n        if (newPriority != priority || newGranularity != granularity || newIntervalMillis != intervalMillis || newWorkSource != workSource || permissionChanged) {\n            priority = newPriority\n            granularity = newGranularity\n            intervalMillis = newIntervalMillis\n            workSource = newWorkSource\n            requestDetailsUpdated = true\n            permissionChanged = false\n        }\n    }\n\n    private fun updateAppOps() {\n        synchronized(appOpsLock) {\n            val newAppOps = mutableMapOf<ClientIdentity, Boolean>()\n            val merged = binderRequests.values + pendingIntentRequests.values\n            for (request in merged) {\n                if (request.effectivePriority >= PRIORITY_PASSIVE || request.clientIdentity.isSelfUser()) continue\n                if (!newAppOps.containsKey(request.clientIdentity)) {\n                    newAppOps[request.clientIdentity] = request.effectiveHighPower\n                } else if (request.effectiveHighPower) {\n                    newAppOps[request.clientIdentity] = true\n                }\n            }\n            Log.d(TAG, \"Updating app ops for location requests, change attribution to: ${newAppOps.keys.map { it.packageName }.joinToString().takeIf { it.isNotEmpty() } ?: \"none\"}\")\n\n            for (oldAppOp in currentAppOps) {\n                context.finishAppOp(AppOpsManager.OPSTR_MONITOR_LOCATION, oldAppOp.key)\n                if (oldAppOp.value) {\n                    context.finishAppOp(AppOpsManager.OPSTR_MONITOR_HIGH_POWER_LOCATION, oldAppOp.key)\n                }\n            }\n            for (newAppOp in newAppOps) {\n                context.startAppOp(AppOpsManager.OPSTR_MONITOR_LOCATION, newAppOp.key)\n                if (newAppOp.value) {\n                    context.startAppOp(AppOpsManager.OPSTR_MONITOR_HIGH_POWER_LOCATION, newAppOp.key)\n                }\n            }\n            currentAppOps = newAppOps\n        }\n    }\n\n    private suspend fun check() {\n        lock.withLock {\n            val pendingIntentsToRemove = mutableSetOf<PendingIntent>()\n            for ((key, holder) in pendingIntentRequests) {\n                try {\n                    holder.check()\n                } catch (e: Exception) {\n                    Log.w(TAG, \"Exception while checking for ${holder.workSource}\", e)\n                    pendingIntentsToRemove.add(key)\n                }\n            }\n            for (pendingIntent in pendingIntentsToRemove) {\n                cacheManager.removeIf { it.pendingIntent == pendingIntent }\n                pendingIntentRequests.remove(pendingIntent)\n            }\n            val bindersToRemove = mutableSetOf<IBinder>()\n            for ((key, holder) in binderRequests) {\n                try {\n                    holder.check()\n                } catch (e: Exception) {\n                    Log.w(TAG, \"Exception while checking for ${holder.workSource}\", e)\n                    bindersToRemove.add(key)\n                }\n            }\n            for (binder in bindersToRemove) {\n                try {\n                    binderRequests[binder]?.cancel()\n                } catch (e: Exception) {\n                    // Ignore\n                }\n                binderRequests.remove(binder)\n            }\n            if (grantedPermissions.any { it != PackageManager.PERMISSION_GRANTED }) {\n                val grantedPermissions = locationPermissions.map { ContextCompat.checkSelfPermission(context, it) }\n                if (grantedPermissions == this.grantedPermissions) {\n                    this.grantedPermissions = grantedPermissions\n                    permissionChanged = true\n                }\n            }\n            if (pendingIntentsToRemove.isNotEmpty() || bindersToRemove.isNotEmpty() || permissionChanged) {\n                recalculateRequests()\n            }\n        }\n        notifyRequestDetailsUpdated()\n    }\n\n    private suspend fun checkWhileHighAccuracy() {\n        if (checkingWhileHighAccuracy) return\n        checkingWhileHighAccuracy = true\n        while (priority == PRIORITY_HIGH_ACCURACY) {\n            check()\n            delay(1000)\n        }\n        checkingWhileHighAccuracy = false\n    }\n\n    private fun notifyRequestDetailsUpdated() {\n        if (!requestDetailsUpdated) return\n        requestDetailsUpdatedCallback()\n        updateAppOps()\n        requestDetailsUpdated = false\n    }\n\n    fun stop() {\n        binderRequests.clear()\n        pendingIntentRequests.clear()\n        recalculateRequests()\n    }\n\n    fun start() {\n        recalculateRequests()\n        notifyRequestDetailsUpdated()\n    }\n\n    fun dump(writer: PrintWriter) {\n        writer.println(\"Request cache: id=${cacheManager.getId()} size=${cacheManager.getEntries().size}\")\n        writer.println(\"Current location request (${GranularityUtil.granularityToString(granularity)}, ${PriorityUtil.priorityToString(priority)}, ${intervalMillis.formatDuration()} from ${workSource})\")\n        for (request in binderRequests.values.toList()) {\n            writer.println(\"- bound ${request.workSource} ${request.intervalMillis.formatDuration()} ${GranularityUtil.granularityToString(request.effectiveGranularity)}, ${PriorityUtil.priorityToString(request.effectivePriority)} (pending: ${request.updatesPending.let { if (it == Int.MAX_VALUE) \"\\u221e\" else \"$it\" }} ${request.timePendingMillis.formatDuration()}) app-op: ${when(currentAppOps[request.clientIdentity]) { null -> \"false\"; false -> \"low\"; true -> \"high\"}}\")\n        }\n        for (request in pendingIntentRequests.values.toList()) {\n            writer.println(\"- pending intent ${request.workSource} ${request.intervalMillis.formatDuration()} ${GranularityUtil.granularityToString(request.effectiveGranularity)}, ${PriorityUtil.priorityToString(request.effectivePriority)} (pending: ${request.updatesPending.let { if (it == Int.MAX_VALUE) \"\\u221e\" else \"$it\" }} ${request.timePendingMillis.formatDuration()}) app-op: ${when(currentAppOps[request.clientIdentity]) { null -> \"false\"; false -> \"low\"; true -> \"high\"}}\")\n        }\n    }\n\n    fun handleCacheIntent(intent: Intent) {\n        cacheManager.processIntent(intent)\n        for (parcelable in cacheManager.getEntries()) {\n            pendingIntentRequests[parcelable.pendingIntent] = LocationRequestHolder(context, parcelable)\n        }\n        recalculateRequests()\n        notifyRequestDetailsUpdated()\n    }\n\n    companion object {\n        private val locationPermissions = listOfNotNull(\n            Manifest.permission.ACCESS_COARSE_LOCATION,\n            Manifest.permission.ACCESS_FINE_LOCATION,\n            if (SDK_INT >= 29) Manifest.permission.ACCESS_BACKGROUND_LOCATION else null\n        )\n        const val CACHE_TYPE = 1\n\n        private class LocationRequestHolderParcelable(\n            val clientIdentity: ClientIdentity,\n            val request: LocationRequest,\n            val pendingIntent: PendingIntent,\n            val start: Long,\n            val updates: Int,\n            val lastLocation: Location?\n        ) : Parcelable {\n            constructor(parcel: Parcel) : this(\n                parcel.readParcelable(ClientIdentity::class.java.classLoader)!!,\n                parcel.readParcelable(LocationRequest::class.java.classLoader)!!,\n                parcel.readParcelable(PendingIntent::class.java.classLoader)!!,\n                parcel.readLong(),\n                parcel.readInt(),\n                parcel.readParcelable(Location::class.java.classLoader)\n            )\n\n            override fun writeToParcel(parcel: Parcel, flags: Int) {\n                parcel.writeParcelable(clientIdentity, flags)\n                parcel.writeParcelable(request, flags)\n                parcel.writeParcelable(pendingIntent, flags)\n                parcel.writeLong(start)\n                parcel.writeInt(updates)\n                parcel.writeParcelable(lastLocation, flags)\n            }\n\n            override fun describeContents(): Int {\n                return 0\n            }\n\n            companion object CREATOR : Parcelable.Creator<LocationRequestHolderParcelable> {\n                override fun createFromParcel(parcel: Parcel): LocationRequestHolderParcelable {\n                    return LocationRequestHolderParcelable(parcel)\n                }\n\n                override fun newArray(size: Int): Array<LocationRequestHolderParcelable?> {\n                    return arrayOfNulls(size)\n                }\n            }\n        }\n\n        private class LocationRequestHolder(\n            private val context: Context,\n            val clientIdentity: ClientIdentity,\n            private var request: LocationRequest,\n            private var callback: ILocationCallback?,\n            private val pendingIntent: PendingIntent?\n        ) {\n            private var start = SystemClock.elapsedRealtime()\n            private var updates = 0\n            private var lastLocation: Location? = null\n\n            constructor(context: Context, parcelable: LocationRequestHolderParcelable) : this(context, parcelable.clientIdentity, parcelable.request, null, parcelable.pendingIntent) {\n                start = parcelable.start\n                updates = parcelable.updates\n                lastLocation = parcelable.lastLocation\n            }\n\n            fun asParcelable() = LocationRequestHolderParcelable(clientIdentity, request, pendingIntent!!, start, updates, lastLocation)\n\n            val permissionGranularity: @Granularity Int\n                get() = context.granularityFromPermission(clientIdentity)\n            val effectiveGranularity: @Granularity Int\n                get() = getEffectiveGranularity(request.granularity, permissionGranularity)\n            val effectivePriority: @Priority Int\n                get() {\n                    if (request.priority == PRIORITY_HIGH_ACCURACY && permissionGranularity < GRANULARITY_FINE) {\n                        return PRIORITY_BALANCED_POWER_ACCURACY\n                    }\n                    return request.priority\n                }\n            val maxUpdateDelayMillis: Long\n                get() = max(max(request.maxUpdateDelayMillis, intervalMillis), 0L)\n            val intervalMillis: Long\n                get() = request.intervalMillis\n            val updatesPending: Int\n                get() = request.maxUpdates - updates\n            val timePendingMillis: Long\n                get() = request.durationMillis - (SystemClock.elapsedRealtime() - start)\n            var workSource: WorkSource = WorkSource(request.workSource).also { if (!clientIdentity.isSelfUser()) WorkSourceUtil.add(it, clientIdentity.uid, clientIdentity.packageName) }\n                private set\n            val effectiveHighPower: Boolean\n                get() = request.intervalMillis < 60000 || effectivePriority == PRIORITY_HIGH_ACCURACY\n\n            fun update(callback: ILocationCallback, request: LocationRequest): LocationRequestHolder {\n                val changedGranularity = request.granularity != this.request.granularity || request.granularity == GRANULARITY_PERMISSION_LEVEL\n                this.callback = callback\n                this.request = request\n                this.start = SystemClock.elapsedRealtime()\n                this.updates = 0\n                this.workSource = WorkSource(request.workSource).also { if (!clientIdentity.isSelfUser()) WorkSourceUtil.add(it, clientIdentity.uid, clientIdentity.packageName) }\n                if (changedGranularity) {\n                    if (!context.checkAppOpForEffectiveGranularity(clientIdentity, effectiveGranularity)) throw RuntimeException(\"Lack of permission\")\n                }\n                return this\n            }\n\n            fun start(): LocationRequestHolder {\n                if (!context.checkAppOpForEffectiveGranularity(clientIdentity, effectiveGranularity)) throw RuntimeException(\"Lack of permission\")\n                return this\n            }\n\n            fun cancel() {\n                try {\n                    callback?.cancel()\n                } catch (e: Exception) {\n                    Log.w(TAG, e)\n                }\n            }\n\n            fun check() {\n                if (!context.checkAppOpForEffectiveGranularity(clientIdentity, effectiveGranularity)) throw RuntimeException(\"Lack of permission\")\n                if (effectiveGranularity > permissionGranularity) throw RuntimeException(\"Lack of permission\")\n                if (timePendingMillis < 0) throw RuntimeException(\"duration limit reached (active for ${(SystemClock.elapsedRealtime() - start).formatDuration()}, duration ${request.durationMillis.formatDuration()})\")\n                if (updatesPending <= 0) throw RuntimeException(\"max updates reached\")\n                if (callback?.asBinder()?.isBinderAlive == false) throw RuntimeException(\"Binder died\")\n            }\n\n            fun processNewLocation(location: Location): Boolean {\n                check()\n                if (lastLocation != null && location.elapsedMillis - lastLocation!!.elapsedMillis < request.minUpdateIntervalMillis) return false\n                if (lastLocation != null && location.distanceTo(lastLocation!!) < request.minUpdateDistanceMeters) return false\n                if (lastLocation == location) return false\n                val returnedLocation = if (effectiveGranularity > permissionGranularity) {\n                    throw RuntimeException(\"Lack of permission\")\n                } else {\n                    if (!context.noteAppOpForEffectiveGranularity(clientIdentity, effectiveGranularity)) {\n                        throw RuntimeException(\"app op denied\")\n                    } else if (clientIdentity.isSelfProcess()) {\n                        Location(location)\n                    } else {\n                        Location(location).apply { provider = \"fused\" }\n                    }\n                }\n                val result = LocationResult.create(listOf(returnedLocation))\n                callback?.onLocationResult(result)\n                pendingIntent?.send(context, 0, Intent().apply { putExtra(LocationResult.EXTRA_LOCATION_RESULT, result) })\n                if (request.maxUpdates != Int.MAX_VALUE) updates++\n                check()\n                return true\n            }\n\n            init {\n                require(callback != null || pendingIntent != null)\n            }\n        }\n    }\n}"
  },
  {
    "path": "play-services-location/core/src/main/kotlin/org/microg/gms/location/manager/extensions.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.manager\n\nimport android.Manifest\nimport android.app.AppOpsManager\nimport android.content.Context\nimport android.content.pm.PackageManager\nimport android.os.Binder\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.Process\nimport android.util.Log\nimport androidx.core.app.AppOpsManagerCompat\nimport androidx.core.content.getSystemService\nimport com.google.android.gms.common.Feature\nimport com.google.android.gms.location.*\nimport com.google.android.gms.location.internal.ClientIdentity\nimport com.google.android.gms.location.internal.IFusedLocationProviderCallback\nimport org.microg.gms.common.PackageUtils\nimport org.microg.gms.location.GranularityUtil\n\nconst val TAG = \"LocationManager\"\n\ninternal val FEATURES = arrayOf(\n    Feature(\"name_ulr_private\", 1),\n    Feature(\"driving_mode\", 6),\n    Feature(\"name_sleep_segment_request\", 1),\n    Feature(\"support_context_feature_id\", 1),\n    Feature(\"get_current_location\", 2),\n    Feature(\"get_last_activity_feature_id\", 1),\n    Feature(\"get_last_location_with_request\", 1),\n    Feature(\"set_mock_mode_with_callback\", 1),\n    Feature(\"set_mock_location_with_callback\", 1),\n    Feature(\"inject_location_with_callback\", 1),\n    Feature(\"location_updates_with_callback\", 1),\n    Feature(\"user_service_developer_features\", 1),\n    Feature(\"user_service_location_accuracy\", 1),\n    Feature(\"user_service_safety_and_emergency\", 1),\n    Feature(\"google_location_accuracy_enabled\", 1),\n    Feature(\"geofences_with_callback\", 1),\n    Feature(\"use_safe_parcelable_in_intents\", 1)\n)\n\nfun ILocationListener.asCallback(): ILocationCallback {\n    return object : ILocationCallback.Stub() {\n        override fun onLocationResult(result: LocationResult) {\n            for (location in result.locations) {\n                onLocationChanged(location)\n            }\n        }\n\n        override fun onLocationAvailability(availability: LocationAvailability) = Unit\n        override fun cancel() = this@asCallback.cancel()\n    }\n}\n\nfun ILocationCallback.redirectCancel(fusedCallback: IFusedLocationProviderCallback?): ILocationCallback {\n    if (fusedCallback == null) return this\n    return object : ILocationCallback.Stub() {\n        override fun onLocationResult(result: LocationResult) = this@redirectCancel.onLocationResult(result)\n        override fun onLocationAvailability(availability: LocationAvailability) = this@redirectCancel.onLocationAvailability(availability)\n        override fun cancel() = fusedCallback.cancel()\n    }\n}\n\nfun ClientIdentity.isGoogle(context: Context) = PackageUtils.isGooglePackage(context, packageName)\n\nfun ClientIdentity.isSelfProcess() = pid == Process.myPid()\nfun ClientIdentity.isSelfUser() = uid == Process.myUid()\n\nfun Context.granularityFromPermission(clientIdentity: ClientIdentity): @Granularity Int = when (PackageManager.PERMISSION_GRANTED) {\n    packageManager.checkPermission(Manifest.permission.ACCESS_FINE_LOCATION, clientIdentity.packageName) -> Granularity.GRANULARITY_FINE\n    packageManager.checkPermission(Manifest.permission.ACCESS_COARSE_LOCATION, clientIdentity.packageName) -> Granularity.GRANULARITY_COARSE\n    else -> Granularity.GRANULARITY_PERMISSION_LEVEL\n}\n\nfun LocationRequest.verify(context: Context, clientIdentity: ClientIdentity) {\n    GranularityUtil.checkValidGranularity(granularity)\n    if (isBypass && !clientIdentity.isSelfUser()) {\n        val permission = if (SDK_INT >= 33) \"android.permission.LOCATION_BYPASS\" else Manifest.permission.WRITE_SECURE_SETTINGS\n        if (context.checkPermission(permission, clientIdentity.pid, clientIdentity.uid) != PackageManager.PERMISSION_GRANTED) {\n            throw SecurityException(\"Caller must hold $permission for location bypass\")\n        }\n    }\n    if (impersonation != null && !clientIdentity.isSelfUser()) {\n        Log.w(TAG, \"${clientIdentity.packageName} wants to impersonate ${impersonation!!.packageName}. Ignoring.\")\n    }\n\n}\n\nfun checkAppOpFromEffectiveGranularity(effectiveGranularity: @Granularity Int) = when (effectiveGranularity) {\n    Granularity.GRANULARITY_FINE -> AppOpsManager.OPSTR_FINE_LOCATION\n    Granularity.GRANULARITY_COARSE -> AppOpsManager.OPSTR_COARSE_LOCATION\n    else -> throw IllegalArgumentException()\n}\n\nfun persistAppOpsFromEffectiveGranularity(effectiveGranularity: @Granularity Int) = when (effectiveGranularity) {\n    Granularity.GRANULARITY_FINE -> listOf(AppOpsManager.OPSTR_MONITOR_LOCATION, AppOpsManager.OPSTR_MONITOR_HIGH_POWER_LOCATION)\n    Granularity.GRANULARITY_COARSE -> listOf(AppOpsManager.OPSTR_MONITOR_LOCATION)\n    else -> throw IllegalArgumentException()\n}\n\nfun getEffectiveGranularity(requestGranularity: @Granularity Int, permissionGranularity: @Granularity Int) = when {\n    requestGranularity == Granularity.GRANULARITY_PERMISSION_LEVEL && permissionGranularity == Granularity.GRANULARITY_PERMISSION_LEVEL -> Granularity.GRANULARITY_FINE\n    requestGranularity == Granularity.GRANULARITY_PERMISSION_LEVEL -> permissionGranularity\n    else -> requestGranularity\n}\n\nfun Context.noteAppOpForEffectiveGranularity(\n    clientIdentity: ClientIdentity,\n    effectiveGranularity: @Granularity Int,\n    message: String? = null\n): Boolean {\n    return try {\n        val op = checkAppOpFromEffectiveGranularity(effectiveGranularity)\n        noteAppOp(op, clientIdentity, message)\n    } catch (e: Exception) {\n        Log.w(TAG, \"Could not notify appops\", e)\n        true\n    }\n}\n\nfun Context.checkAppOpForEffectiveGranularity(clientIdentity: ClientIdentity, effectiveGranularity: @Granularity Int): Boolean {\n    return try {\n        val op = checkAppOpFromEffectiveGranularity(effectiveGranularity)\n        checkAppOp(op, clientIdentity)\n    } catch (e: Exception) {\n        Log.w(TAG, \"Could not check appops\", e)\n        true\n    }\n}\n\nfun Context.startAppOpForEffectiveGranularity(clientIdentity: ClientIdentity, effectiveGranularity: @Granularity Int): Boolean {\n    return try {\n        val ops = persistAppOpsFromEffectiveGranularity(effectiveGranularity)\n        startAppOps(ops, clientIdentity)\n    } catch (e: Exception) {\n        Log.w(TAG, \"Could not start appops\", e)\n        true\n    }\n}\n\nfun Context.finishAppOpForEffectiveGranularity(clientIdentity: ClientIdentity, effectiveGranularity: @Granularity Int) {\n    try {\n        val ops = persistAppOpsFromEffectiveGranularity(effectiveGranularity)\n        finishAppOps(ops, clientIdentity)\n    } catch (e: Exception) {\n        Log.w(TAG, \"Could not finish appops\", e)\n    }\n}\n\nprivate fun Context.checkAppOp(\n    op: String,\n    clientIdentity: ClientIdentity\n) = try {\n    if (SDK_INT >= 29) {\n        getSystemService<AppOpsManager>()?.unsafeCheckOpNoThrow(op, clientIdentity.uid, clientIdentity.packageName) == AppOpsManager.MODE_ALLOWED\n    } else {\n        getSystemService<AppOpsManager>()?.checkOpNoThrow(op, clientIdentity.uid, clientIdentity.packageName) == AppOpsManager.MODE_ALLOWED\n    }\n} catch (e: SecurityException) {\n    true\n}\n\nfun Context.startAppOps(\n    ops: List<String>,\n    clientIdentity: ClientIdentity,\n    message: String? = null\n) = ops.all { startAppOp(it, clientIdentity, message) }\n\nfun Context.startAppOp(\n    op: String,\n    clientIdentity: ClientIdentity,\n    message: String? = null\n) = try {\n    if (SDK_INT >= 30 && clientIdentity.attributionTag != null) {\n        getSystemService<AppOpsManager>()?.startOpNoThrow(op, clientIdentity.uid, clientIdentity.packageName, clientIdentity.attributionTag!!, message)\n    } else {\n        getSystemService<AppOpsManager>()?.startOpNoThrow(op, clientIdentity.uid, clientIdentity.packageName)\n    }\n} catch (e: SecurityException) {\n    if (SDK_INT >= 31) {\n        getSystemService<AppOpsManager>()?.startProxyOpNoThrow(op, clientIdentity.uid, clientIdentity.packageName, clientIdentity.attributionTag, message)\n    } else {\n        AppOpsManager.MODE_ALLOWED\n    }\n} == AppOpsManager.MODE_ALLOWED\n\nfun Context.finishAppOps(\n    ops: List<String>,\n    clientIdentity: ClientIdentity\n) = ops.forEach { finishAppOp(it, clientIdentity) }\n\nfun Context.finishAppOp(\n    op: String,\n    clientIdentity: ClientIdentity\n) {\n    try {\n        if (SDK_INT >= 30 && clientIdentity.attributionTag != null) {\n            getSystemService<AppOpsManager>()?.finishOp(op, clientIdentity.uid, clientIdentity.packageName, clientIdentity.attributionTag!!)\n        } else {\n            getSystemService<AppOpsManager>()?.finishOp(op, clientIdentity.uid, clientIdentity.packageName)\n        }\n    } catch (e: SecurityException) {\n        if (SDK_INT >= 31) {\n            getSystemService<AppOpsManager>()?.finishProxyOp(op, clientIdentity.uid, clientIdentity.packageName, clientIdentity.attributionTag)\n        }\n    }\n}\n\nprivate fun Context.noteAppOp(\n    op: String,\n    clientIdentity: ClientIdentity,\n    message: String? = null\n) = try {\n    if (SDK_INT >= 30) {\n        getSystemService<AppOpsManager>()\n            ?.noteOpNoThrow(op, clientIdentity.uid, clientIdentity.packageName, clientIdentity.attributionTag, message) == AppOpsManager.MODE_ALLOWED\n    } else {\n        AppOpsManagerCompat.noteOpNoThrow(this, op, clientIdentity.uid, clientIdentity.packageName) == AppOpsManager.MODE_ALLOWED\n    }\n} catch (e: SecurityException) {\n    if (Binder.getCallingUid() == clientIdentity.uid) {\n        AppOpsManagerCompat.noteProxyOpNoThrow(this, op, clientIdentity.packageName) == AppOpsManager.MODE_ALLOWED\n    } else if (SDK_INT >= 29) {\n        getSystemService<AppOpsManager>()\n            ?.noteProxyOpNoThrow(op, clientIdentity.packageName, clientIdentity.uid) == AppOpsManager.MODE_ALLOWED\n    } else {\n        true\n    }\n}"
  },
  {
    "path": "play-services-location/core/src/main/kotlin/org/microg/gms/location/reporting/ReportingAndroidService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage org.microg.gms.location.reporting\n\nimport android.os.RemoteException\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.internal.ConnectionInfo\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.common.PackageUtils\nimport org.microg.gms.location.manager.FEATURES\n\nclass ReportingAndroidService : BaseService(\"GmsLocReportingSvc\", GmsService.REPORTING) {\n    @Throws(RemoteException::class)\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        val packageName = PackageUtils.getAndCheckCallingPackage(this, request.packageName)\n            ?: throw IllegalArgumentException(\"Missing package name\")\n        callback.onPostInitCompleteWithConnectionInfo(\n            CommonStatusCodes.SUCCESS,\n            ReportingServiceInstance(this, packageName),\n            ConnectionInfo().apply { features = FEATURES }\n        )\n    }\n}\n"
  },
  {
    "path": "play-services-location/core/src/main/kotlin/org/microg/gms/location/reporting/ReportingServiceInstance.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage org.microg.gms.location.reporting\n\nimport android.accounts.Account\nimport android.content.Context\nimport android.os.Parcel\nimport android.util.Log\nimport com.google.android.gms.location.reporting.*\nimport com.google.android.gms.location.reporting.internal.IReportingService\nimport org.microg.gms.common.GooglePackagePermission\nimport org.microg.gms.common.PackageUtils\nimport org.microg.gms.utils.warnOnTransactionIssues\n\n/**\n * https://userlocation.googleapis.com/userlocation.UserLocationReportingService/GetApiSettings\n * Follow-up: Fill ReportingState based on AccountConfig returned by the interface and persistence processing\n */\n\n//import com.google.android.gms.location.places.PlaceReport;\nclass ReportingServiceInstance(private val context: Context, private val packageName: String) : IReportingService.Stub() {\n\n    override fun getReportingState(account: Account): ReportingState {\n        Log.d(TAG, \"getReportingState\")\n        val (deviceTag, allowed) =  if (PackageUtils.callerHasGooglePackagePermission(context, GooglePackagePermission.REPORTING)) {\n            Pair(0, true)\n        } else {\n            Pair(null, false)\n        }\n        return ReportingState(-1, -1, allowed, false, 1, 1, deviceTag, false, true)\n    }\n\n    override fun tryOptInAccount(account: Account): Int {\n        val request = OptInRequest()\n        request.account = account\n        return tryOptIn(request)\n    }\n\n    override fun requestUpload(request: UploadRequest): UploadRequestResult {\n        Log.d(TAG, \"requestUpload\")\n        return UploadRequestResult()\n    }\n\n    override fun cancelUploadRequest(l: Long): Int {\n        Log.d(TAG, \"cancelUploadRequest\")\n        return 0\n    }\n\n    //    @Override\n    //    public int reportDeviceAtPlace(Account account, PlaceReport report) throws RemoteException {\n    //        Log.d(TAG, \"reportDeviceAtPlace\");\n    //        return 0;\n    //    }\n\n    override fun tryOptIn(request: OptInRequest): Int {\n        return 0\n    }\n\n    override fun sendData(request: SendDataRequest): Int {\n        return 0\n    }\n\n    override fun requestPrivateMode(request: UlrPrivateModeRequest): Int {\n        return 0\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =\n        warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n}\n"
  },
  {
    "path": "play-services-location/core/src/main/kotlin/org/microg/gms/location/reporting/extensions.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.reporting\n\nconst val TAG = \"LocationReporting\""
  },
  {
    "path": "play-services-location/core/src/main/kotlin/org/microg/gms/location/settings/DetailedLocationSettingsStates.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.settings\n\nimport android.Manifest.permission.*\nimport android.bluetooth.BluetoothManager\nimport android.content.Context\nimport android.content.pm.PackageManager.*\nimport android.location.LocationManager\nimport android.location.LocationManager.GPS_PROVIDER\nimport android.location.LocationManager.NETWORK_PROVIDER\nimport android.os.Build.VERSION.SDK_INT\nimport android.provider.Settings\nimport androidx.core.content.getSystemService\nimport com.google.android.gms.location.LocationSettingsStates\nimport org.microg.gms.location.hasNetworkLocationServiceBuiltIn\n\ndata class DetailedLocationSettingsStates(\n    val gpsSystemFeature: Boolean,\n    val networkLocationSystemFeature: Boolean,\n    val bluetoothLeSystemFeature: Boolean,\n    val gpsProviderEnabled: Boolean,\n    val networkLocationProviderEnabled: Boolean,\n    val networkLocationProviderBuiltIn: Boolean,\n    val fineLocationPermission: Boolean,\n    val coarseLocationPermission: Boolean,\n    val backgroundLocationPermission: Boolean,\n    val blePresent: Boolean,\n    val bleEnabled: Boolean,\n    val bleScanAlways: Boolean,\n    val airplaneMode: Boolean,\n) {\n    val gpsPresent: Boolean\n        get() = gpsSystemFeature\n    val networkLocationPresent: Boolean\n        get() = networkLocationSystemFeature || networkLocationProviderBuiltIn\n    val gpsUsable: Boolean\n        get() = gpsProviderEnabled\n    val networkLocationUsable: Boolean\n        get() = (networkLocationProviderEnabled || networkLocationProviderBuiltIn)\n    val bleUsable: Boolean\n        get() = blePresent && (bleEnabled || (bleScanAlways && !airplaneMode))\n\n    fun toApi() = LocationSettingsStates(gpsUsable, networkLocationUsable, bleUsable, gpsPresent, networkLocationPresent, blePresent)\n}\n\nfun Context.getDetailedLocationSettingsStates(): DetailedLocationSettingsStates {\n    val bluetoothLeSystemFeature = packageManager.hasSystemFeature(FEATURE_BLUETOOTH_LE)\n    val locationManager = getSystemService<LocationManager>()\n    val bluetoothManager = if (bluetoothLeSystemFeature) getSystemService<BluetoothManager>() else null\n    val bleAdapter = bluetoothManager?.adapter\n\n    return DetailedLocationSettingsStates(\n        gpsSystemFeature = packageManager.hasSystemFeature(FEATURE_LOCATION_GPS),\n        networkLocationSystemFeature = packageManager.hasSystemFeature(FEATURE_LOCATION_NETWORK),\n        bluetoothLeSystemFeature = bluetoothLeSystemFeature,\n        gpsProviderEnabled = locationManager?.isProviderEnabled(GPS_PROVIDER) == true,\n        networkLocationProviderEnabled = locationManager?.isProviderEnabled(NETWORK_PROVIDER) == true,\n        networkLocationProviderBuiltIn = hasNetworkLocationServiceBuiltIn(),\n        fineLocationPermission = packageManager.checkPermission(ACCESS_FINE_LOCATION, packageName) == PERMISSION_GRANTED,\n        coarseLocationPermission = packageManager.checkPermission(ACCESS_COARSE_LOCATION, packageName) == PERMISSION_GRANTED,\n        backgroundLocationPermission = if (SDK_INT < 29) true else\n            packageManager.checkPermission(ACCESS_BACKGROUND_LOCATION, packageName) == PERMISSION_GRANTED,\n        blePresent = bleAdapter != null,\n        bleEnabled = bleAdapter?.isEnabled == true,\n        bleScanAlways = Settings.Global.getInt(contentResolver, \"ble_scan_always_enabled\", 0) == 1,\n        airplaneMode = Settings.Global.getInt(contentResolver, Settings.Global.AIRPLANE_MODE_ON, 0) != 0\n    )\n}"
  },
  {
    "path": "play-services-location/core/src/main/kotlin/org/microg/gms/location/settings/GoogleLocationSettingsActivity.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.settings\n\nimport android.content.Intent\nimport android.os.Bundle\nimport androidx.appcompat.app.AppCompatActivity\n\nclass GoogleLocationSettingsActivity : AppCompatActivity() {\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        runCatching { startActivity(Intent(\"android.settings.LOCATION_SOURCE_SETTINGS\")) }\n        finish()\n    }\n}"
  },
  {
    "path": "play-services-location/core/src/main/kotlin/org/microg/gms/location/settings/LocationSettingsCheckerActivity.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.settings\n\nimport android.Manifest\nimport android.app.Activity\nimport android.content.DialogInterface\nimport android.content.Intent\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.Bundle\nimport android.provider.Settings\nimport android.util.Log\nimport android.widget.ImageView\nimport android.widget.LinearLayout\nimport android.widget.TextView\nimport androidx.appcompat.app.AlertDialog\nimport androidx.core.content.ContextCompat\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableSerializer\nimport com.google.android.gms.location.Granularity\nimport com.google.android.gms.location.LocationRequest\nimport com.google.android.gms.location.LocationSettingsRequest\nimport com.google.android.gms.location.Priority\nimport org.microg.gms.location.core.R\nimport org.microg.gms.location.manager.AskPermissionActivity\nimport org.microg.gms.location.manager.EXTRA_PERMISSIONS\nimport org.microg.gms.ui.buildAlertDialog\n\nconst val ACTION_LOCATION_SETTINGS_CHECKER = \"com.google.android.gms.location.settings.CHECK_SETTINGS\"\nconst val EXTRA_ORIGINAL_PACKAGE_NAME = \"originalPackageName\"\nconst val EXTRA_SETTINGS_REQUEST = \"locationSettingsRequests\"\nconst val EXTRA_REQUESTS = \"locationRequests\"\nconst val EXTRA_SETTINGS_STATES = \"com.google.android.gms.location.LOCATION_SETTINGS_STATES\"\n\nprivate const val REQUEST_CODE_LOCATION = 120\nprivate const val REQUEST_CODE_PERMISSION = 121\nprivate const val TAG = \"LocationSettings\"\n\nclass LocationSettingsCheckerActivity : Activity(), DialogInterface.OnCancelListener, DialogInterface.OnClickListener {\n    private var alwaysShow = false\n    private var needBle = false\n    private var improvements = emptyList<Improvement>()\n    private var requests: List<LocationRequest>? = null\n    private var dialog: AlertDialog? = null\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        Log.d(TAG, \"LocationSettingsCheckerActivity onCreate\")\n        if (intent.hasExtra(EXTRA_SETTINGS_REQUEST)) {\n            try {\n                val request = SafeParcelableSerializer.deserializeFromBytes(intent.getByteArrayExtra(EXTRA_SETTINGS_REQUEST), LocationSettingsRequest.CREATOR)\n                alwaysShow = request.alwaysShow\n                needBle = request.needBle\n                requests = request.requests\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n            }\n        }\n        if (requests == null && intent.hasExtra(EXTRA_REQUESTS)) {\n            try {\n                val arrayList = intent.getSerializableExtra(EXTRA_REQUESTS) as? ArrayList<*>\n                requests = arrayList?.map {\n                    SafeParcelableSerializer.deserializeFromBytes(it as ByteArray, LocationRequest.CREATOR)\n                }\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n            }\n        }\n        if (requests == null) {\n            finishResult(RESULT_CANCELED)\n        } else {\n            updateImprovements()\n            if (improvements.isEmpty()) {\n                finishResult(RESULT_OK)\n            } else {\n                showDialog()\n            }\n        }\n    }\n\n    override fun onResume() {\n        super.onResume()\n        checkImprovements()\n    }\n\n    override fun onPause() {\n        dialog?.dismiss()\n        super.onPause()\n    }\n\n    enum class Improvement {\n        GPS, NLP, GPS_AND_NLP, WIFI, WIFI_SCANNING, BLUETOOTH, BLE_SCANNING, PERMISSIONS, DATA_SOURCE\n    }\n\n    private fun updateImprovements() {\n        val states = getDetailedLocationSettingsStates()\n        val requests = requests?.map {\n            // TODO: We assume fine for permission level granularity here\n            it.priority to (if (it.granularity == Granularity.GRANULARITY_PERMISSION_LEVEL) Granularity.GRANULARITY_FINE else it.granularity)\n        }.orEmpty()\n        val gpsRequested = requests.any { it.first == Priority.PRIORITY_HIGH_ACCURACY && it.second == Granularity.GRANULARITY_FINE }\n        val networkLocationRequested = requests.any { it.first <= Priority.PRIORITY_LOW_POWER && it.second >= Granularity.GRANULARITY_COARSE }\n        improvements = listOfNotNull(\n            Improvement.GPS_AND_NLP.takeIf { gpsRequested && !states.gpsUsable || networkLocationRequested && !states.networkLocationUsable },\n            Improvement.PERMISSIONS.takeIf { !states.coarseLocationPermission || !states.fineLocationPermission },\n        )\n    }\n\n    private fun showDialog() {\n        val dialog = this.dialog?.takeIf { it.isShowing } ?: buildAlertDialog()\n            .setOnCancelListener(this)\n            .setPositiveButton(R.string.location_settings_dialog_btn_sure, this)\n            .setNegativeButton(R.string.location_settings_dialog_btn_cancel, this)\n            .create()\n            .apply { setCanceledOnTouchOutside(false) }\n            .also { this@LocationSettingsCheckerActivity.dialog = it }\n\n        val view = layoutInflater.inflate(R.layout.location_settings_dialog, null)\n        view.findViewById<TextView>(R.id.message_title)\n            .setText(if (alwaysShow) R.string.location_settings_dialog_message_title_to_continue else R.string.location_settings_dialog_message_title_for_better_experience)\n\n        val messages = view.findViewById<LinearLayout>(R.id.messages)\n        for ((messageIndex, improvement) in improvements.withIndex()) {\n            val item = layoutInflater.inflate(R.layout.location_settings_dialog_item, messages, false)\n            item.findViewById<TextView>(android.R.id.text1).text = when (improvement) {\n                Improvement.GPS_AND_NLP -> getString(R.string.location_settings_dialog_message_location_services_gps_and_nlp)\n                Improvement.PERMISSIONS -> getString(R.string.location_settings_dialog_message_grant_permissions)\n                else -> {\n                    Log.w(TAG, \"Unsupported improvement: $improvement\")\n                    \"\"\n                }\n            }\n            item.findViewById<ImageView>(android.R.id.icon).setImageDrawable(\n                when (improvement) {\n                    Improvement.GPS_AND_NLP -> ContextCompat.getDrawable(this, R.drawable.ic_gps)\n                    Improvement.PERMISSIONS -> ContextCompat.getDrawable(this, R.drawable.ic_location)\n                    else -> {\n                        Log.w(TAG, \"Unsupported improvement: $improvement\")\n                        null\n                    }\n                }\n            )\n            messages.addView(item, messageIndex + 1)\n        }\n\n        dialog.setView(view)\n        if (!dialog.isShowing) dialog.show()\n    }\n\n    private fun handleContinue() {\n        val improvement = improvements.firstOrNull() ?: return finishResult(RESULT_OK)\n        when (improvement) {\n            Improvement.PERMISSIONS -> {\n                val intent = Intent(this, AskPermissionActivity::class.java).apply {\n                    putExtra(EXTRA_PERMISSIONS, locationPermissions.toTypedArray())\n                }\n                startActivityForResult(intent, REQUEST_CODE_PERMISSION)\n                return\n            }\n\n            Improvement.GPS, Improvement.NLP, Improvement.GPS_AND_NLP -> {\n                // TODO: If we have permission to, just activate directly\n                val intent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)\n                startActivityForResult(intent, REQUEST_CODE_LOCATION)\n                return // We will continue from onActivityResult\n            }\n\n            else -> {\n                Log.w(TAG, \"Unsupported improvement: $improvement\")\n            }\n        }\n        updateImprovements()\n        handleContinue()\n    }\n\n    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {\n        if (requestCode == REQUEST_CODE_LOCATION || requestCode == REQUEST_CODE_PERMISSION) {\n            checkImprovements()\n        } else {\n            super.onActivityResult(requestCode, resultCode, data)\n        }\n    }\n\n    private fun checkImprovements() {\n        // Check if we improved, if so continue, otherwise show dialog again\n        val oldImprovements = improvements\n        updateImprovements()\n        if (oldImprovements == improvements) {\n            showDialog()\n        } else {\n            handleContinue()\n        }\n    }\n\n    private fun finishResult(resultCode: Int) {\n        if (dialog?.isShowing == true) dialog?.dismiss()\n        val states = getDetailedLocationSettingsStates().toApi()\n        setResult(resultCode, Intent().apply {\n            putExtra(EXTRA_SETTINGS_STATES, SafeParcelableSerializer.serializeToBytes(states))\n        })\n        finish()\n    }\n\n    override fun onBackPressed() {\n        finishResult(RESULT_CANCELED)\n    }\n\n    override fun onCancel(dialog: DialogInterface?) {\n        finishResult(RESULT_CANCELED)\n    }\n\n    override fun onClick(dialog: DialogInterface?, which: Int) {\n        Log.d(TAG, \"Not yet implemented: onClick\")\n        when (which) {\n            DialogInterface.BUTTON_NEGATIVE -> finishResult(RESULT_CANCELED)\n            DialogInterface.BUTTON_POSITIVE -> handleContinue()\n        }\n    }\n\n    companion object {\n        private val locationPermissions = listOfNotNull(\n            Manifest.permission.ACCESS_COARSE_LOCATION,\n            Manifest.permission.ACCESS_FINE_LOCATION,\n            if (SDK_INT >= 29) Manifest.permission.ACCESS_BACKGROUND_LOCATION else null\n        )\n    }\n}"
  },
  {
    "path": "play-services-location/core/src/main/kotlin/org/microg/gms/location/ui/ConfigurationRequiredReceiver.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage org.microg.gms.location.ui\n\nimport android.content.BroadcastReceiver\nimport android.content.Context\nimport android.content.Intent\nimport android.content.pm.PackageManager\nimport android.net.Uri\nimport android.os.Build.VERSION.SDK_INT\nimport org.microg.gms.location.ACTION_CONFIGURATION_REQUIRED\nimport org.microg.gms.location.CONFIGURATION_FIELD_ONLINE_SOURCE\nimport org.microg.gms.location.EXTRA_CONFIGURATION\nimport androidx.core.app.NotificationChannelCompat\nimport androidx.core.app.NotificationCompat\nimport androidx.core.app.NotificationManagerCompat\nimport androidx.core.app.PendingIntentCompat\nimport org.microg.gms.location.core.R\n\nclass ConfigurationRequiredReceiver : BroadcastReceiver() {\n    override fun onReceive(context: Context, intent: Intent) {\n        if (intent.action == ACTION_CONFIGURATION_REQUIRED) {\n            if (SDK_INT >= 23 && context.checkSelfPermission(android.Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) return\n            val channel = NotificationChannelCompat.Builder(\"location\", NotificationManagerCompat.IMPORTANCE_DEFAULT)\n                .setName(context.getString(R.string.service_name_location)).build()\n            NotificationManagerCompat.from(context).createNotificationChannel(channel)\n            val notification = NotificationCompat.Builder(context, channel.id)\n                .setContentTitle(context.getText(R.string.notification_config_required_title))\n                .setSmallIcon(R.drawable.ic_location)\n                .setAutoCancel(true)\n            when (intent.getStringExtra(EXTRA_CONFIGURATION)) {\n                CONFIGURATION_FIELD_ONLINE_SOURCE -> {\n                    val notifyIntent = Intent(Intent.ACTION_VIEW, Uri.parse(\"x-gms-settings://location\"))\n                        .apply {\n                            `package` = context.packageName\n                            putExtra(EXTRA_CONFIGURATION, CONFIGURATION_FIELD_ONLINE_SOURCE)\n                        }\n                    notification.setContentText(context.getText(R.string.notification_config_required_text_online_sources))\n                        .setStyle(NotificationCompat.BigTextStyle())\n                        .setContentIntent(PendingIntentCompat.getActivity(context, CONFIGURATION_FIELD_ONLINE_SOURCE.hashCode(), notifyIntent, 0, true))\n                }\n                else -> return\n            }\n            NotificationManagerCompat.from(context).notify(CONFIGURATION_FIELD_ONLINE_SOURCE.hashCode(), notification.build())\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-location/core/src/main/kotlin/org/microg/gms/location/ui/LocationAllAppsFragment.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.ui\n\nimport android.os.Bundle\nimport android.text.format.DateUtils\nimport androidx.appcompat.content.res.AppCompatResources\nimport androidx.core.os.bundleOf\nimport androidx.lifecycle.lifecycleScope\nimport androidx.navigation.fragment.findNavController\nimport androidx.preference.Preference\nimport androidx.preference.PreferenceCategory\nimport androidx.preference.PreferenceFragmentCompat\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\nimport org.microg.gms.location.manager.LocationAppsDatabase\nimport org.microg.gms.ui.AppIconPreference\nimport org.microg.gms.ui.getApplicationInfoIfExists\nimport org.microg.gms.ui.navigate\nimport org.microg.gms.location.core.R\n\nclass LocationAllAppsFragment : PreferenceFragmentCompat() {\n    private lateinit var progress: Preference\n    private lateinit var locationApps: PreferenceCategory\n    private lateinit var database: LocationAppsDatabase\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        database = LocationAppsDatabase(requireContext())\n    }\n\n    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {\n        addPreferencesFromResource(R.xml.preferences_location_all_apps)\n        progress = preferenceScreen.findPreference(\"pref_location_apps_all_progress\") ?: progress\n        locationApps = preferenceScreen.findPreference(\"prefcat_location_apps\") ?: locationApps\n    }\n\n    override fun onResume() {\n        super.onResume()\n        updateContent()\n    }\n\n    override fun onPause() {\n        super.onPause()\n        database.close()\n    }\n\n\n    private fun updateContent() {\n        lifecycleScope.launchWhenResumed {\n            val context = requireContext()\n            val apps = withContext(Dispatchers.IO) {\n                val res = database.listAppsByAccessTime().map { app ->\n                    app to context.packageManager.getApplicationInfoIfExists(app.first)\n                }.map { (app, applicationInfo) ->\n                    val pref = AppIconPreference(context)\n                    pref.title = applicationInfo?.loadLabel(context.packageManager) ?: app.first\n                    pref.summary = getString(R.string.location_app_last_access_at, DateUtils.getRelativeTimeSpanString(app.second))\n                    pref.icon = applicationInfo?.loadIcon(context.packageManager) ?: AppCompatResources.getDrawable(context, android.R.mipmap.sym_def_app_icon)\n                    pref.onPreferenceClickListener = Preference.OnPreferenceClickListener {\n                        findNavController().navigate(requireContext(), R.id.openLocationAppDetailsFromAll, bundleOf(\"package\" to app.first))\n                        true\n                    }\n                    pref.key = \"pref_location_app_\" + app.first\n                    pref\n                }.sortedBy {\n                    it.title.toString().toLowerCase()\n                }.mapIndexed { idx, pair ->\n                    pair.order = idx\n                    pair\n                }\n                database.close()\n                res\n            }\n            locationApps.removeAll()\n            locationApps.isVisible = true\n            for (app in apps) {\n                locationApps.addPreference(app)\n            }\n            progress.isVisible = false\n        }\n    }\n}"
  },
  {
    "path": "play-services-location/core/src/main/kotlin/org/microg/gms/location/ui/LocationAppFragment.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.ui\n\nimport android.annotation.SuppressLint\nimport android.content.Intent\nimport android.location.Geocoder\nimport android.net.Uri\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.Bundle\nimport android.text.format.DateUtils\nimport android.util.Log\nimport androidx.lifecycle.lifecycleScope\nimport androidx.preference.Preference\nimport androidx.preference.PreferenceCategory\nimport androidx.preference.PreferenceFragmentCompat\nimport androidx.preference.TwoStatePreference\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\nimport org.microg.gms.location.core.R\nimport org.microg.gms.location.manager.LocationAppsDatabase\nimport org.microg.gms.ui.AppHeadingPreference\nimport kotlin.coroutines.resume\nimport kotlin.coroutines.resumeWithException\nimport kotlin.coroutines.suspendCoroutine\n\nclass LocationAppFragment : PreferenceFragmentCompat() {\n    private lateinit var appHeadingPreference: AppHeadingPreference\n    private lateinit var lastLocationCategory: PreferenceCategory\n    private lateinit var lastLocation: Preference\n    private lateinit var lastLocationMap: LocationMapPreference\n    private lateinit var forceCoarse: TwoStatePreference\n    private lateinit var database: LocationAppsDatabase\n\n    private val packageName: String?\n        get() = arguments?.getString(\"package\")\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        database = LocationAppsDatabase(requireContext())\n    }\n\n    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {\n        addPreferencesFromResource(R.xml.preferences_location_app_details)\n    }\n\n    @SuppressLint(\"RestrictedApi\")\n    override fun onBindPreferences() {\n        appHeadingPreference = preferenceScreen.findPreference(\"pref_location_app_heading\") ?: appHeadingPreference\n        lastLocationCategory = preferenceScreen.findPreference(\"prefcat_location_app_last_location\") ?: lastLocationCategory\n        lastLocation = preferenceScreen.findPreference(\"pref_location_app_last_location\") ?: lastLocation\n        lastLocationMap = preferenceScreen.findPreference(\"pref_location_app_last_location_map\") ?: lastLocationMap\n        forceCoarse = preferenceScreen.findPreference(\"pref_location_app_force_coarse\") ?: forceCoarse\n        forceCoarse.setOnPreferenceChangeListener { _, newValue ->\n            packageName?.let { database.setForceCoarse(it, newValue as Boolean); true } == true\n        }\n    }\n\n    override fun onResume() {\n        super.onResume()\n        updateContent()\n    }\n\n    override fun onPause() {\n        super.onPause()\n        database.close()\n    }\n\n    fun Double.toStringWithDigits(digits: Int): String {\n        val s = this.toString()\n        val i = s.indexOf('.')\n        if (i <= 0 || s.length - i - 1 < digits) return s\n        if (digits == 0) return s.substring(0, i)\n        return s.substring(0, s.indexOf('.') + digits + 1)\n    }\n\n    fun updateContent() {\n        val context = requireContext()\n        lifecycleScope.launchWhenResumed {\n            appHeadingPreference.packageName = packageName\n            forceCoarse.isChecked = packageName?.let { database.getForceCoarse(it) } == true\n            val location = packageName?.let { database.getAppLocation(it) }\n            if (location != null) {\n                lastLocationCategory.isVisible = true\n                lastLocation.title = DateUtils.getRelativeTimeSpanString(location.time)\n                val intent = Intent(Intent.ACTION_VIEW, Uri.parse(\"geo:${location.latitude},${location.longitude}\"))\n                if (context.packageManager.queryIntentActivities(intent, 0).isNotEmpty()) {\n                    lastLocation.intent = intent\n                } else {\n                    lastLocation.isSelectable = false\n                }\n                lastLocationMap.location = location\n                val address = try {\n                    if (SDK_INT > 33) {\n                        suspendCoroutine { continuation ->\n                            try {\n                                Geocoder(context).getFromLocation(location.latitude, location.longitude, 1) {\n                                    continuation.resume(it.firstOrNull())\n                                }\n                            } catch (e: Exception) {\n                                continuation.resumeWithException(e)\n                            }\n                        }\n                    } else {\n                        withContext(Dispatchers.IO) { Geocoder(context).getFromLocation(location.latitude, location.longitude, 1)?.firstOrNull() }\n                    }\n                } catch (e: Exception) {\n                    Log.w(TAG, e)\n                    null\n                }\n                if (address != null) {\n                    val addressLine = StringBuilder()\n                    var i = 0\n                    addressLine.append(address.getAddressLine(i))\n                    while (addressLine.length < 32 && address.maxAddressLineIndex > i) {\n                        i++\n                        addressLine.append(\", \")\n                        addressLine.append(address.getAddressLine(i))\n                    }\n                    lastLocation.summary = addressLine.toString()\n                } else {\n                    lastLocation.summary = \"${location.latitude.toStringWithDigits(6)}, ${location.longitude.toStringWithDigits(6)}\"\n                }\n            } else {\n                lastLocationCategory.isVisible = false\n            }\n        }\n    }\n}"
  },
  {
    "path": "play-services-location/core/src/main/kotlin/org/microg/gms/location/ui/LocationMapPreference.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.ui\n\nimport android.content.Context\nimport android.location.Location\nimport android.util.AttributeSet\nimport android.util.Log\nimport android.view.View\nimport android.view.ViewGroup\nimport android.view.ViewGroup.LayoutParams\nimport android.widget.FrameLayout\nimport androidx.preference.Preference\nimport androidx.preference.PreferenceViewHolder\nimport com.google.android.gms.maps.CameraUpdateFactory\nimport com.google.android.gms.maps.GoogleMapOptions\nimport com.google.android.gms.maps.MapView\nimport com.google.android.gms.maps.model.CameraPosition\nimport com.google.android.gms.maps.model.Circle\nimport com.google.android.gms.maps.model.CircleOptions\nimport com.google.android.gms.maps.model.LatLng\nimport org.microg.gms.location.core.R\nimport org.microg.gms.ui.resolveColor\nimport kotlin.math.log2\n\nclass LocationMapPreference : Preference {\n    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)\n    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)\n    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)\n    constructor(context: Context) : super(context)\n\n    init {\n        layoutResource = R.layout.preference_full_container\n    }\n\n    var location: Location? = null\n        set(value) {\n            field = value\n            notifyChanged()\n        }\n\n    private var mapView: View? = null\n    private var circle1: Any? = null\n    private var circle2: Any? = null\n\n    override fun onBindViewHolder(holder: PreferenceViewHolder) {\n        super.onBindViewHolder(holder)\n        holder.isDividerAllowedAbove = false\n        holder.isDividerAllowedBelow = false\n        if (location != null) {\n            if (isAvailable) {\n                val latLng = LatLng(location!!.latitude, location!!.longitude)\n                val camera = CameraPosition.fromLatLngZoom(latLng, (21 - log2(location!!.accuracy)).coerceIn(2f, 22f))\n                val container = holder.itemView as ViewGroup\n                if (mapView == null) {\n                    val options = GoogleMapOptions().liteMode(true).scrollGesturesEnabled(false).zoomGesturesEnabled(false).camera(camera)\n                    mapView = MapView(context, options)\n                    mapView?.layoutParams = FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, (height * context.resources.displayMetrics.density).toInt())\n                    container.addView(mapView)\n                    (mapView as MapView).onCreate(null)\n                } else {\n                    (mapView as MapView).getMapAsync {\n                        it.moveCamera(CameraUpdateFactory.newCameraPosition(camera))\n                    }\n                }\n                (circle1 as? Circle?)?.remove()\n                (circle2 as? Circle?)?.remove()\n                (mapView as MapView).getMapAsync {\n                    val strokeColor = (context.resolveColor(androidx.appcompat.R.attr.colorAccent) ?: 0xff009688L.toInt())\n                    val fillColor = strokeColor and 0x60ffffff\n                    circle1 = it.addCircle(CircleOptions().center(latLng).radius(location!!.accuracy.toDouble()).fillColor(fillColor).strokeWidth(1f).strokeColor(strokeColor))\n                    circle2 = it.addCircle(CircleOptions().center(latLng).radius(location!!.accuracy.toDouble() * 2).fillColor(fillColor).strokeWidth(1f).strokeColor(strokeColor))\n                }\n            } else {\n                Log.d(TAG, \"MapView not available\")\n            }\n        } else if (mapView != null) {\n            (mapView as MapView).onDestroy()\n            (mapView?.parent as? ViewGroup?)?.removeView(mapView)\n            circle1 = null\n            circle2 = null\n            mapView = null\n        }\n    }\n\n    override fun onDetached() {\n        super.onDetached()\n        if (mapView != null) {\n            (mapView as MapView).onDestroy()\n            circle1 = null\n            circle2 = null\n            mapView = null\n        }\n    }\n\n    companion object {\n        const val height = 200f\n\n        val isAvailable: Boolean\n            get() = try {\n                Class.forName(\"com.google.android.gms.maps.MapView\")\n                true\n            } catch (e: ClassNotFoundException) {\n                false\n            }\n    }\n}"
  },
  {
    "path": "play-services-location/core/src/main/kotlin/org/microg/gms/location/ui/LocationPreferencesFragment.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.ui\n\nimport android.app.Activity\nimport android.app.Dialog\nimport android.content.Intent\nimport android.location.LocationManager\nimport android.net.Uri\nimport android.os.*\nimport android.os.Build.VERSION.SDK_INT\nimport android.text.Html\nimport android.text.SpannableStringBuilder\nimport android.text.method.LinkMovementMethod\nimport android.util.Log\nimport android.view.*\nimport android.view.Menu.NONE\nimport android.widget.*\nimport androidx.core.content.getSystemService\nimport androidx.core.os.bundleOf\nimport androidx.core.view.setPadding\nimport androidx.lifecycle.lifecycleScope\nimport androidx.navigation.NavController\nimport androidx.navigation.fragment.findNavController\nimport androidx.preference.Preference\nimport androidx.preference.PreferenceCategory\nimport androidx.preference.PreferenceFragmentCompat\nimport androidx.preference.TwoStatePreference\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\nimport org.microg.gms.location.*\nimport org.microg.gms.location.core.R\nimport org.microg.gms.location.manager.LocationAppsDatabase\nimport org.microg.gms.location.network.OnlineSource\nimport org.microg.gms.location.network.effectiveEndpoint\nimport org.microg.gms.location.network.onlineSource\nimport org.microg.gms.ui.AppIconPreference\nimport org.microg.gms.ui.buildAlertDialog\nimport org.microg.gms.ui.getApplicationInfoIfExists\nimport org.microg.gms.ui.navigate\n\nprivate const val REQUEST_CODE_IMPORT_FILE = 5715515\n\nclass LocationPreferencesFragment : PreferenceFragmentCompat() {\n    private lateinit var locationApps: PreferenceCategory\n    private lateinit var locationAppsAll: Preference\n    private lateinit var locationAppsNone: Preference\n    private lateinit var networkProviderCategory: PreferenceCategory\n    private lateinit var wifiIchnaea: TwoStatePreference\n    private lateinit var wifiMoving: TwoStatePreference\n    private lateinit var wifiLearning: TwoStatePreference\n    private lateinit var cellIchnaea: TwoStatePreference\n    private lateinit var cellLearning: TwoStatePreference\n    private lateinit var nominatim: TwoStatePreference\n    private lateinit var database: LocationAppsDatabase\n\n    init {\n        setHasOptionsMenu(true)\n    }\n\n    companion object {\n        private const val MENU_ICHNAEA_URL = Menu.FIRST\n        private const val MENU_IMPORT_EXPORT = Menu.FIRST + 1\n    }\n\n    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {\n        if (requireContext().hasNetworkLocationServiceBuiltIn()) {\n            menu.add(NONE, MENU_ICHNAEA_URL, NONE, R.string.pref_location_source_title)\n            menu.add(NONE, MENU_IMPORT_EXPORT, NONE, R.string.pref_location_import_export_title)\n        }\n        super.onCreateOptionsMenu(menu, inflater)\n    }\n\n    override fun onOptionsItemSelected(item: MenuItem): Boolean {\n        if (item.itemId == MENU_ICHNAEA_URL) {\n            openOnlineSourceSelector()\n            return true\n        }\n        if (item.itemId == MENU_IMPORT_EXPORT) {\n            openImportExportDialog()\n            return true\n        }\n        return super.onOptionsItemSelected(item)\n    }\n\n    private val messenger by lazy {\n        Messenger(object : Handler(Looper.getMainLooper()) {\n            override fun handleMessage(msg: Message) {\n                try {\n                    when (msg.data.getString(EXTRA_DIRECTION)) {\n                        DIRECTION_EXPORT -> {\n                            val name = msg.data.getString(EXTRA_NAME)\n                            val fileUri = msg.data.getParcelable<Uri>(EXTRA_URI)\n                            if (fileUri != null) {\n                                val sendIntent: Intent = Intent(Intent.ACTION_SEND).apply {\n                                    putExtra(Intent.EXTRA_STREAM, fileUri)\n                                    addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)\n                                    type = \"application/vnd.microg.location.$name+csv+gzip\"\n                                }\n\n                                startActivity(Intent.createChooser(sendIntent, null))\n                            }\n                            currentDialog?.dismiss()\n                        }\n\n                        DIRECTION_IMPORT -> {\n                            val counter = msg.arg1\n                            Toast.makeText(requireContext(), getString(R.string.location_data_import_result_toast, counter), Toast.LENGTH_SHORT).show()\n                            currentDialog?.dismiss()\n                        }\n                    }\n                } catch (e: Exception) {\n                    Log.w(TAG, e)\n                }\n            }\n        })\n    }\n\n    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {\n        if (requestCode == REQUEST_CODE_IMPORT_FILE) {\n            if (resultCode == Activity.RESULT_OK && data?.data != null) {\n                val intent = Intent(ACTION_NETWORK_IMPORT_EXPORT)\n                intent.`package` = requireContext().packageName\n                intent.putExtra(EXTRA_DIRECTION, DIRECTION_IMPORT)\n                intent.putExtra(EXTRA_MESSENGER, messenger)\n                intent.putExtra(EXTRA_URI, data.data)\n                requireContext().startService(intent)\n            } else {\n                currentDialog?.dismiss()\n            }\n        } else {\n            super.onActivityResult(requestCode, resultCode, data)\n        }\n    }\n\n    private val Int.dp\n        get() =  (this * resources.displayMetrics.density).toInt()\n\n    private var currentDialog: Dialog? = null\n\n    private fun openImportExportDialog() {\n        val listView = ListView(requireContext()).apply {\n            setPadding(8.dp, 16.dp, 8.dp, 16.dp)\n            adapter = ArrayAdapter<String>(requireContext(), android.R.layout.simple_list_item_1).apply {\n                add(requireContext().getString(R.string.location_data_export_wifi_title))\n                add(requireContext().getString(R.string.location_data_export_cell_title))\n                add(requireContext().getString(R.string.location_data_import_title))\n            }\n        }\n        val progress = ProgressBar(requireContext()).apply {\n            layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)\n            setPadding(20.dp)\n            isIndeterminate = true\n            visibility = View.GONE\n        }\n        val view = FrameLayout(requireContext()).apply {\n            addView(listView)\n            addView(progress)\n        }\n        currentDialog = requireContext().buildAlertDialog()\n            .setTitle(R.string.pref_location_import_export_title)\n            .setView(view)\n            .show()\n        listView.setOnItemClickListener { _, _, position, _ ->\n            if (position == 0 || position == 1) {\n                val intent = Intent(ACTION_NETWORK_IMPORT_EXPORT)\n                intent.`package` = requireContext().packageName\n                intent.putExtra(EXTRA_DIRECTION, DIRECTION_EXPORT)\n                intent.putExtra(EXTRA_NAME, if (position == 0) NAME_WIFI else NAME_CELL)\n                intent.putExtra(EXTRA_MESSENGER, messenger)\n                requireContext().startService(intent)\n            } else if (position == 2) {\n                val openIntent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {\n                    addCategory(Intent.CATEGORY_OPENABLE)\n                    type = \"*/*\"\n                }\n                startActivityForResult(openIntent, REQUEST_CODE_IMPORT_FILE)\n            }\n            listView.visibility = View.INVISIBLE\n            progress.visibility = View.VISIBLE\n            currentDialog?.setCancelable(false)\n        }\n    }\n\n    private fun openOnlineSourceSelector(callback: () -> Unit = {}) {\n        val view = LinearLayout(requireContext())\n        view.setPadding(0, 16.dp, 0, 0)\n        view.orientation = LinearLayout.VERTICAL\n        val settings = LocationSettings(requireContext())\n        val currentSourceId = settings.onlineSource?.id\n        val unselectHandlerMap = mutableMapOf<String, () -> Unit>()\n        var selectedSourceId = currentSourceId\n        val customView = layoutInflater.inflate(R.layout.preference_location_custom_url, null)\n        customView.findViewById<EditText>(android.R.id.edit).setText(settings.customEndpoint)\n        customView.visibility = View.GONE\n        for (source in OnlineSource.ALL) {\n            val title = when {\n                source.name != null -> source.name\n                source.id == OnlineSource.ID_CUSTOM -> getText(R.string.pref_location_custom_source_title)\n                else -> source.id\n            }\n            val sourceDescription = source.host.takeIf { source.name != it }\n            val sourceTerms = source.terms?.let { Html.fromHtml(\"<a href=\\\"${it}\\\">${getText(R.string.pref_location_source_terms)}</a>\") }\n            val description = when {\n                sourceDescription != null && sourceTerms != null -> SpannableStringBuilder().append(sourceDescription).append(\" · \").append(sourceTerms)\n                sourceDescription != null -> sourceDescription\n                sourceTerms != null -> sourceTerms\n                else -> null\n            }\n            val subView = layoutInflater.inflate(R.layout.preference_location_online_source, null)\n            subView.findViewById<TextView>(android.R.id.title).text = title\n            if (description != null) {\n                subView.findViewById<TextView>(android.R.id.text1).text = description\n                if (sourceTerms != null) subView.findViewById<TextView>(android.R.id.text1).movementMethod = LinkMovementMethod.getInstance()\n            } else {\n                subView.findViewById<TextView>(android.R.id.text1).visibility = View.GONE\n            }\n            if (source.suggested) subView.findViewById<View>(R.id.suggested_tag).visibility = View.VISIBLE\n            unselectHandlerMap[source.id] = {\n                subView.findViewById<ImageView>(R.id.radio_button).setImageResource(org.microg.gms.base.core.R.drawable.ic_radio_unchecked)\n                if (source.id == OnlineSource.ID_CUSTOM) customView.visibility = View.GONE\n            }\n            val selectedHandler = {\n                for (entry in unselectHandlerMap) {\n                    if (entry.key != source.id) {\n                        entry.value.invoke()\n                    }\n                }\n                if (source.id == OnlineSource.ID_CUSTOM) customView.visibility = View.VISIBLE\n                subView.findViewById<ImageView>(R.id.radio_button).setImageResource(org.microg.gms.base.core.R.drawable.ic_radio_checked)\n                selectedSourceId = source.id\n            }\n            if (currentSourceId == source.id) selectedHandler.invoke()\n            subView.setOnClickListener { selectedHandler.invoke() }\n            view.addView(subView)\n        }\n        view.addView(customView)\n\n        requireContext().buildAlertDialog()\n            .setTitle(R.string.pref_location_source_title)\n            .setPositiveButton(android.R.string.ok) { _, _ ->\n                if (selectedSourceId == OnlineSource.ID_CUSTOM) {\n                    settings.customEndpoint = customView.findViewById<EditText>(android.R.id.edit).text.toString()\n                }\n                settings.onlineSourceId = selectedSourceId\n            }\n            .setNegativeButton(android.R.string.cancel) { _, _ ->  }\n            .setOnDismissListener { callback() }\n            .setView(view)\n            .show()\n    }\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        database = LocationAppsDatabase(requireContext())\n    }\n\n    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {\n        addPreferencesFromResource(R.xml.preferences_location)\n\n        locationApps = preferenceScreen.findPreference(\"prefcat_location_apps\") ?: locationApps\n        locationAppsAll = preferenceScreen.findPreference(\"pref_location_apps_all\") ?: locationAppsAll\n        locationAppsNone = preferenceScreen.findPreference(\"pref_location_apps_none\") ?: locationAppsNone\n        networkProviderCategory = preferenceScreen.findPreference(\"prefcat_location_network_provider\") ?: networkProviderCategory\n        wifiIchnaea = preferenceScreen.findPreference(\"pref_location_wifi_mls_enabled\") ?: wifiIchnaea\n        wifiMoving = preferenceScreen.findPreference(\"pref_location_wifi_moving_enabled\") ?: wifiMoving\n        wifiLearning = preferenceScreen.findPreference(\"pref_location_wifi_learning_enabled\") ?: wifiLearning\n        cellIchnaea = preferenceScreen.findPreference(\"pref_location_cell_mls_enabled\") ?: cellIchnaea\n        cellLearning = preferenceScreen.findPreference(\"pref_location_cell_learning_enabled\") ?: cellLearning\n        nominatim = preferenceScreen.findPreference(\"pref_geocoder_nominatim_enabled\") ?: nominatim\n\n        locationAppsAll.setOnPreferenceClickListener {\n            findNavController().navigate(requireContext(), R.id.openAllLocationApps)\n            true\n        }\n        fun configureChangeListener(preference: TwoStatePreference, listener: (Boolean) -> Unit) {\n            preference.setOnPreferenceChangeListener { _, newValue ->\n                listener(newValue as Boolean)\n                true\n            }\n        }\n        configureChangeListener(wifiIchnaea) {\n            val settings = LocationSettings(requireContext())\n            if (!it || settings.effectiveEndpoint != null) {\n                settings.wifiIchnaea = it\n            } else {\n                openOnlineSourceSelector {\n                    if (settings.effectiveEndpoint != null) {\n                        settings.wifiIchnaea = true\n                    } else {\n                        wifiIchnaea.isChecked = false\n                    }\n                }\n            }\n        }\n        configureChangeListener(wifiMoving) { LocationSettings(requireContext()).wifiMoving = it }\n        configureChangeListener(wifiLearning) { LocationSettings(requireContext()).wifiLearning = it }\n        configureChangeListener(cellIchnaea) {\n            val settings = LocationSettings(requireContext())\n            if (!it || settings.effectiveEndpoint != null) {\n                settings.cellIchnaea = it\n            } else {\n                openOnlineSourceSelector {\n                    if (settings.effectiveEndpoint != null) {\n                        settings.cellIchnaea = true\n                    } else {\n                        cellIchnaea.isChecked = false\n                    }\n                }\n            }\n        }\n        configureChangeListener(cellLearning) { LocationSettings(requireContext()).cellLearning = it }\n        configureChangeListener(nominatim) { LocationSettings(requireContext()).geocoderNominatim = it }\n\n        networkProviderCategory.isVisible = requireContext().hasNetworkLocationServiceBuiltIn()\n        wifiLearning.isVisible =\n            SDK_INT >= 17 && requireContext().getSystemService<LocationManager>()?.allProviders.orEmpty().contains(LocationManager.GPS_PROVIDER)\n        cellLearning.isVisible =\n            SDK_INT >= 17 && requireContext().getSystemService<LocationManager>()?.allProviders.orEmpty().contains(LocationManager.GPS_PROVIDER)\n    }\n\n    override fun onResume() {\n        super.onResume()\n        runCatching { updateContent() }.onFailure { database.close() }\n        arguments?.let {\n            if (it.containsKey(NavController.KEY_DEEP_LINK_INTENT)) {\n                val intent = it.getParcelable<Intent>(NavController.KEY_DEEP_LINK_INTENT)\n                when (intent?.getStringExtra(EXTRA_CONFIGURATION)) {\n                    CONFIGURATION_FIELD_ONLINE_SOURCE -> openOnlineSourceSelector()\n                }\n            }\n        }\n    }\n\n    override fun onPause() {\n        super.onPause()\n        database.close()\n    }\n\n    private fun updateContent() {\n        lifecycleScope.launchWhenResumed {\n            val context = requireContext()\n            wifiIchnaea.isChecked = LocationSettings(context).wifiIchnaea\n            wifiMoving.isChecked = LocationSettings(context).wifiMoving\n            wifiLearning.isChecked = LocationSettings(context).wifiLearning\n            cellIchnaea.isChecked = LocationSettings(context).cellIchnaea\n            cellLearning.isChecked = LocationSettings(context).cellLearning\n            nominatim.isChecked = LocationSettings(context).geocoderNominatim\n            val (apps, showAll) = withContext(Dispatchers.IO) {\n                val apps = database.listAppsByAccessTime()\n                val res = apps.map { app ->\n                    app to context.packageManager.getApplicationInfoIfExists(app.first)\n                }.mapNotNull { (app, info) ->\n                    if (info == null) null else app to info\n                }.take(3).mapIndexed { idx, (app, applicationInfo) ->\n                    val pref = AppIconPreference(context)\n                    pref.order = idx\n                    pref.applicationInfo = applicationInfo\n                    pref.onPreferenceClickListener = Preference.OnPreferenceClickListener {\n                        findNavController().navigate(requireContext(), R.id.openLocationAppDetails, bundleOf(\"package\" to app.first))\n                        true\n                    }\n                    pref.key = \"pref_location_app_\" + app.first\n                    pref\n                }.let { it to (it.size < apps.size) }\n                database.close()\n                res\n            }\n            locationAppsAll.isVisible = showAll\n            locationApps.removeAll()\n            for (app in apps) {\n                locationApps.addPreference(app)\n            }\n            if (showAll) {\n                locationApps.addPreference(locationAppsAll)\n            } else if (apps.isEmpty()) {\n                locationApps.addPreference(locationAppsNone)\n            }\n        }\n    }\n}"
  },
  {
    "path": "play-services-location/core/src/main/kotlin/org/microg/gms/location/ui/extensions.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location.ui\n\nconst val TAG = \"LocationUi\"\n\n"
  },
  {
    "path": "play-services-location/core/src/main/res/drawable/ic_gps.xml",
    "content": "<!--\n  ~ SPDX-FileCopyrightText: 2019 The Android Open Source Project\n  ~ SPDX-FileCopyrightText: 2024 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<vector android:height=\"24dp\"\n    android:tint=\"?attr/colorAccent\"\n    android:viewportHeight=\"24\"\n    android:viewportWidth=\"24\"\n    android:width=\"24dp\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M12,8c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM20.94,11c-0.46,-4.17 -3.77,-7.48 -7.94,-7.94L13,1h-2v2.06C6.83,3.52 3.52,6.83 3.06,11L1,11v2h2.06c0.46,4.17 3.77,7.48 7.94,7.94L11,23h2v-2.06c4.17,-0.46 7.48,-3.77 7.94,-7.94L23,13v-2h-2.06zM12,19c-3.87,0 -7,-3.13 -7,-7s3.13,-7 7,-7 7,3.13 7,7 -3.13,7 -7,7z\" />\n</vector>\n"
  },
  {
    "path": "play-services-location/core/src/main/res/drawable/ic_location.xml",
    "content": "<!--\n  ~ SPDX-FileCopyrightText: 2019 The Android Open Source Project\n  ~ SPDX-FileCopyrightText: 2024 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<vector android:height=\"24dp\"\n    android:tint=\"?attr/colorAccent\"\n    android:viewportHeight=\"24\"\n    android:viewportWidth=\"24\"\n    android:width=\"24dp\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M12,2C8.13,2 5,5.13 5,9c0,5.25 7,13 7,13s7,-7.75 7,-13c0,-3.87 -3.13,-7 -7,-7zM12,11.5c-1.38,0 -2.5,-1.12 -2.5,-2.5s1.12,-2.5 2.5,-2.5 2.5,1.12 2.5,2.5 -1.12,2.5 -2.5,2.5z\" />\n</vector>\n"
  },
  {
    "path": "play-services-location/core/src/main/res/layout/location_settings_dialog.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2024 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<ScrollView 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    android:layout_weight=\"1\"\n    android:fillViewport=\"true\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        android:layout_marginBottom=\"16dp\">\n\n        <TextView\n            android:id=\"@+id/message_title\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"16dp\"\n            android:visibility=\"gone\"\n            android:textStyle=\"bold\"\n            android:paddingLeft=\"24dp\"\n            android:paddingRight=\"24dp\"\n            style=\"?android:textAppearanceMedium\" />\n\n        <TextView\n            android:id=\"@+id/message\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"16dp\"\n            android:paddingLeft=\"24dp\"\n            android:paddingRight=\"24dp\"\n            android:text=\"@string/location_settings_dialog_message_title_to_continue\"\n            style=\"?android:attr/textAppearanceMedium\" />\n\n        <LinearLayout\n            android:id=\"@+id/messages\"\n            android:orientation=\"vertical\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:paddingLeft=\"24dp\"\n            android:paddingRight=\"24dp\">\n\n            <TextView\n                android:layout_gravity=\"top\"\n                android:id=\"@+id/details_start\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"16dp\"\n                android:text=\"@string/location_settings_dialog_message_details_start_paragraph\" />\n\n            <TextView\n                android:layout_gravity=\"bottom\"\n                android:id=\"@+id/details_end\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"16dp\"\n                android:text=\"@string/location_settings_dialog_message_details_end_paragraph\" />\n\n        </LinearLayout>\n\n    </LinearLayout>\n\n</ScrollView>"
  },
  {
    "path": "play-services-location/core/src/main/res/layout/location_settings_dialog_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2024 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"horizontal\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:layout_marginTop=\"16dp\">\n\n    <ImageView\n        android:layout_gravity=\"top\"\n        android:id=\"@android:id/icon\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:paddingStart=\"0dp\"\n        android:paddingEnd=\"16dp\" />\n\n    <TextView\n        android:layout_gravity=\"top\"\n        android:id=\"@android:id/text1\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\" />\n</LinearLayout>"
  },
  {
    "path": "play-services-location/core/src/main/res/layout/preference_full_container.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:paddingLeft=\"16dip\"\n    android:paddingRight=\"16dip\"\n    android:layout_height=\"wrap_content\">\n\n</FrameLayout>"
  },
  {
    "path": "play-services-location/core/src/main/res/layout/preference_location_custom_url.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2024 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<ScrollView 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    android:layout_weight=\"1\"\n    android:fillViewport=\"true\">\n\n    <LinearLayout\n        android:orientation=\"vertical\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:paddingLeft=\"24dp\"\n        android:paddingRight=\"24dp\">\n\n        <TextView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/pref_location_custom_url_summary\" />\n\n        <TextView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"16dp\"\n            android:text=\"@string/pref_location_custom_url_details\" />\n\n        <com.google.android.material.textfield.TextInputLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"16dp\"\n            android:hint=\"@string/pref_location_custom_url_input_hint\"\n            app:placeholderText=\"https://example.com/?key=example\">\n\n            <com.google.android.material.textfield.TextInputEditText\n                android:id=\"@android:id/edit\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\" />\n\n        </com.google.android.material.textfield.TextInputLayout>\n    </LinearLayout>\n</ScrollView>\n"
  },
  {
    "path": "play-services-location/core/src/main/res/layout/preference_location_online_source.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2024 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<androidx.constraintlayout.widget.ConstraintLayout 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:padding=\"8dp\"\n    android:orientation=\"horizontal\"\n    android:clickable=\"true\">\n\n    <ImageView\n        android:src=\"@drawable/ic_radio_unchecked\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintBottom_toBottomOf=\"@android:id/text1\"\n        android:id=\"@+id/radio_button\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginStart=\"4dp\"\n        android:padding=\"12dp\" />\n\n    <TextView\n        android:id=\"@android:id/title\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:textAppearance=\"?attr/textAppearanceListItem\"\n        app:layout_constraintStart_toEndOf=\"@+id/radio_button\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintHorizontal_bias=\"0\"\n        android:layout_marginStart=\"4dp\"\n        tools:text=\"Positon\" />\n\n    <androidx.constraintlayout.widget.ConstraintLayout\n        android:id=\"@+id/suggested_tag\"\n        android:visibility=\"gone\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        app:layout_constraintStart_toEndOf=\"@android:id/title\"\n        app:layout_constraintTop_toTopOf=\"@android:id/title\"\n        app:layout_constraintBottom_toBottomOf=\"@android:id/title\"\n        android:layout_marginStart=\"4dp\"\n        android:measureAllChildren=\"false\"\n        tools:visibility=\"visible\">\n\n        <View\n            android:background=\"?attr/colorAccent\"\n            android:alpha=\"0.2\"\n            app:layout_constraintStart_toStartOf=\"parent\"\n            app:layout_constraintTop_toTopOf=\"parent\"\n            app:layout_constraintEnd_toEndOf=\"parent\"\n            app:layout_constraintBottom_toBottomOf=\"parent\"\n            android:layout_width=\"0dip\"\n            android:layout_height=\"0dip\" />\n\n        <TextView\n            app:layout_constraintStart_toStartOf=\"parent\"\n            app:layout_constraintTop_toTopOf=\"parent\"\n            android:paddingHorizontal=\"4dp\"\n            android:paddingVertical=\"2dp\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/pref_location_source_suggested\"\n            android:textAppearance=\"?attr/textAppearanceListItemSecondary\"\n            android:textColor=\"?attr/colorAccent\" />\n\n    </androidx.constraintlayout.widget.ConstraintLayout>\n\n    <TextView\n        android:id=\"@android:id/text1\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        app:layout_constraintTop_toBottomOf=\"@android:id/title\"\n        app:layout_constraintStart_toStartOf=\"@android:id/title\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintHorizontal_bias=\"0\"\n        android:layout_marginBottom=\"4dp\"\n        android:textAppearance=\"?attr/textAppearanceListItemSecondary\"\n        tools:text=\"positon.xyz · Terms of Use\" />\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "play-services-location/core/src/main/res/navigation/nav_location.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<navigation 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    app:startDestination=\"@id/locationPreferencesFragment\"\n    android:id=\"@+id/nav_location\">\n\n    <fragment\n        android:id=\"@+id/locationPreferencesFragment\"\n        android:name=\"org.microg.gms.location.ui.LocationPreferencesFragment\"\n        android:label=\"@string/service_name_location\">\n        <deepLink\n            app:uri=\"x-gms-settings://location\" />\n        <action\n            android:id=\"@+id/openAllLocationApps\"\n            app:destination=\"@id/locationAllAppsPreferencesFragment\" />\n        <action\n            android:id=\"@+id/openLocationAppDetails\"\n            app:destination=\"@id/locationAppFragment\" />\n    </fragment>\n\n    <fragment\n        android:id=\"@+id/locationAllAppsPreferencesFragment\"\n        android:name=\"org.microg.gms.location.ui.LocationAllAppsFragment\"\n        android:label=\"@string/fragment_location_apps_title\">\n        <action\n            android:id=\"@+id/openLocationAppDetailsFromAll\"\n            app:destination=\"@id/locationAppFragment\" />\n    </fragment>\n\n    <fragment\n        android:id=\"@+id/locationAppFragment\"\n        android:name=\"org.microg.gms.location.ui.LocationAppFragment\"\n        android:label=\"@string/fragment_location_apps_title\">\n        <argument\n            android:name=\"package\"\n            app:argType=\"string\" />\n    </fragment>\n\n</navigation>"
  },
  {
    "path": "play-services-location/core/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"service_name_location\">Location</string>\n    <string name=\"prefcat_location_apps_title\">Recent access</string>\n    <string name=\"prefcat_location_wifi_title\">Wi-Fi location</string>\n    <string name=\"prefcat_location_cell_title\">Mobile network location</string>\n    <string name=\"prefcat_geocoder_title\">Address resolver</string>\n    <string name=\"pref_location_wifi_online_enabled_title\">Request from online service</string>\n    <string name=\"pref_location_wifi_online_enabled_summary\">Fetch Wi-Fi-based location from online location service.</string>\n    <string name=\"pref_location_wifi_moving_enabled_title\">Request from Hotspot</string>\n    <string name=\"pref_location_wifi_moving_enabled_summary\">Fetch Wi-Fi location directly from supported hotspots when connected.</string>\n    <string name=\"pref_location_wifi_learning_enabled_title\">Remember from GPS</string>\n    <string name=\"pref_location_wifi_learning_enabled_summary\">Store Wi-Fi locations locally when GPS is used.</string>\n    <string name=\"pref_location_cell_online_enabled_title\">Request from online service</string>\n    <string name=\"pref_location_cell_online_enabled_summary\">Fetch mobile network cell tower locations from online location service.</string>\n    <string name=\"pref_location_cell_learning_enabled_title\">Remember from GPS</string>\n    <string name=\"pref_location_cell_learning_enabled_summary\">Store mobile network locations locally when GPS is used.</string>\n    <string name=\"pref_geocoder_nominatim_enabled_title\">Use Nominatim</string>\n    <string name=\"pref_geocoder_nominatim_enabled_summary\">Resolve addresses using OpenStreetMap Nominatim.</string>\n\n    <string name=\"fragment_location_apps_title\">Apps with location access</string>\n    <string name=\"location_app_last_access_at\">Last access: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n\n    <string name=\"pref_location_app_force_coarse_title\">Force coarse location</string>\n    <string name=\"pref_location_app_force_coarse_summary\">Always return coarse locations to this app, ignoring its permission level.</string>\n    <string name=\"prefcat_app_last_location\">Last reported location</string>\n\n    <string name=\"location_settings_dialog_message_title_for_better_experience\">For better experience, turn on device location, which uses microG\\'s location service</string>\n    <string name=\"location_settings_dialog_message_title_to_continue\">To continue, turn on device location, which uses microG\\'s location service</string>\n    <string name=\"location_settings_dialog_message_details_start_paragraph\">Your device will need to:</string>\n    <string name=\"location_settings_dialog_message_location_services_gps_and_nlp\">Use GPS, Wi‑Fi, cell networks, and sensors</string>\n    <string name=\"location_settings_dialog_message_grant_permissions\">Grant location permissions to microG Service</string>\n    <string name=\"location_settings_dialog_message_gls_consent\">Use microG location service; as part of this service, microG may collect location data periodically and use this data in an anonymous way to improve location accuracy and location-based services.</string>\n\n    <string name=\"location_settings_dialog_message_details_end_paragraph\">For details, go to the location settings.</string>\n    <string name=\"location_settings_dialog_btn_cancel\">No thanks</string>\n    <string name=\"location_settings_dialog_btn_sure\">OK</string>\n\n    <string name=\"pref_location_custom_url_summary\">This allows setting a custom service URL. Invalid values can result in location services being unresponsive or entirely unavailable.</string>\n    <string name=\"pref_location_custom_url_details\">The /v1/geolocate path is automatically appended. If the location provider requires a key, it can be appended as a query parameter to the root URL.</string>\n    <string name=\"pref_location_custom_url_input_hint\">Custom service URL</string>\n    <string name=\"pref_location_custom_source_title\">Custom</string>\n    <string name=\"pref_location_source_title\">Select online location service</string>\n    <string name=\"pref_location_source_terms\">Terms / Privacy</string>\n    <string name=\"pref_location_source_suggested\">Suggested</string>\n    <string name=\"pref_location_import_export_title\">Import or export location data</string>\n\n    <string name=\"notification_config_required_title\">Configuration required</string>\n    <string name=\"notification_config_required_text_online_sources\">To continue using online location services, you need to select a location data service.</string>\n\n    <string name=\"location_data_export_wifi_title\">Export local Wi-Fi location database</string>\n    <string name=\"location_data_export_cell_title\">Export local cell tower location database</string>\n    <string name=\"location_data_import_title\">Import location data from file</string>\n    <string name=\"location_data_import_result_toast\">Imported %1$d records.</string>\n\n</resources>"
  },
  {
    "path": "play-services-location/core/src/main/res/values-ar/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_name_location\">الموقع</string>\n    <string name=\"prefcat_location_apps_title\">الوصول الأخير</string>\n    <string name=\"prefcat_location_cell_title\">موقع شبكة الجوال</string>\n    <string name=\"prefcat_geocoder_title\">محلل العناوين</string>\n    <string name=\"prefcat_location_wifi_title\">موقع شبكة الـ Wi-Fi</string>\n    <string name=\"pref_location_wifi_online_enabled_title\">طلب من خدمة عبر الإنترنت</string>\n    <string name=\"pref_location_wifi_online_enabled_summary\">حصول على موقع شبكة الـ Wi-Fi من خدمة تحديد الموقع عبر الإنترنت.</string>\n    <string name=\"pref_location_wifi_moving_enabled_title\">طلب من نقطة الاتصال</string>\n    <string name=\"pref_location_wifi_learning_enabled_summary\">تخزين مواقع الـ Wi-Fi محلياً عند استخدام GPS.</string>\n    <string name=\"pref_location_wifi_learning_enabled_title\">تذكُّر من GPS</string>\n    <string name=\"pref_location_cell_online_enabled_title\">طلب من خدمة عبر الإنترنت</string>\n    <string name=\"pref_location_cell_online_enabled_summary\">حصول على مواقع الأبراج الخلوية لشبكة الجوال من خدمة تحديد الموقع من خدمة عبر اﻹنترنت.</string>\n    <string name=\"pref_location_cell_learning_enabled_title\">تذكُّر من GPS</string>\n    <string name=\"pref_location_cell_learning_enabled_summary\">تخزين مواقع شبكة الجوال محلياً عند استخدام GPS.</string>\n    <string name=\"pref_geocoder_nominatim_enabled_title\">استخدام نوميناتيم</string>\n    <string name=\"pref_geocoder_nominatim_enabled_summary\">حلّ العناوين باستخدام خدمة نوميناتيم من خريطة الشارع المفتوحة.</string>\n    <string name=\"fragment_location_apps_title\">تطبيقات ذات إمكانية الوصول إلى الموقع</string>\n    <string name=\"location_app_last_access_at\">آخر وصول: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"pref_location_app_force_coarse_title\">استخدام الموقع التقريبي دائمًا</string>\n    <string name=\"pref_location_app_force_coarse_summary\">قم دائمًا بتقديم المواقع التقريبي لهذا التطبيق، مع تجاهل مستوى الإذن الخاص به.</string>\n    <string name=\"location_settings_dialog_message_title_for_better_experience\">للحصول على تجربة أفضل، قم بتشغيل موقع الجهاز، والذي يستخدم خدمة تحديد الموقع لمايكرو-جي</string>\n    <string name=\"location_settings_dialog_message_title_to_continue\">للمتابعة، قم بتشغيل موقع الجهاز، والذي يستخدم خدمة تحديد الموقع لمايكرو-جي</string>\n    <string name=\"location_settings_dialog_message_details_start_paragraph\">سيحتاج جهازك إلى:</string>\n    <string name=\"location_settings_dialog_message_location_services_gps_and_nlp\">استخدام GPS، وWi-Fi، وشبكة الجوال، والمستشعرات</string>\n    <string name=\"location_settings_dialog_message_grant_permissions\">منح أذونات الموقع لخدمة مايكرو-جي</string>\n    <string name=\"location_settings_dialog_btn_cancel\">لا شكرًا</string>\n    <string name=\"location_settings_dialog_btn_sure\">موافق</string>\n    <string name=\"location_settings_dialog_message_gls_consent\">استخدام خدمة تحديد الموقع لمايكرو-جي؛ كجزء من هذه الخدمة، قد يقوم مايكرو-جي بجمع بيانات الموقع بشكل دوري ومُخفي للمصدر واستخدام هذه البيانات لتحسين دقة الموقع والخدمات القائمة على الموقع.</string>\n    <string name=\"pref_location_source_title\">اختر خدمة تحديد الموقع عبر الإنترنت</string>\n    <string name=\"pref_location_custom_url_input_hint\">رابط مخصص للخدمة</string>\n    <string name=\"pref_location_custom_source_title\">مخصص</string>\n    <string name=\"pref_location_custom_url_summary\">يسمح هذا بتعيين رابط مخصص للخدمة. القيم غير الصالحة قد تؤدي إلى عدم استجابة خدمات الموقع.</string>\n    <string name=\"pref_location_source_terms\">الشروط / الخصوصية</string>\n    <string name=\"pref_location_source_suggested\">مقترح</string>\n    <string name=\"pref_location_import_export_title\">استيراد أو تصدير بيانات الموقع</string>\n    <string name=\"notification_config_required_title\">التهيئة مطلوبة</string>\n    <string name=\"notification_config_required_text_online_sources\">لمتابعة استخدام خدمات الموقع عبر الإنترنت، تحتاج إلى تحديد خدمة بيانات الموقع.</string>\n    <string name=\"location_data_export_wifi_title\">تصدير قاعدة بيانات مواقع الـ Wi-Fi المحلية</string>\n    <string name=\"location_data_export_cell_title\">تصدير قاعدة بيانات مواقع الأبراج الخلوية المحلية</string>\n    <string name=\"location_data_import_result_toast\">تم استيراد %1$d سِجِل.</string>\n    <string name=\"pref_location_wifi_moving_enabled_summary\">حصول على موقع شبكة الـ Wi-Fi مباشرةً من نقاط الاتصال المدعومة عند الاتصال بها.</string>\n    <string name=\"location_settings_dialog_message_details_end_paragraph\">لمزيد من التفاصيل، انتقل إلى إعدادات الموقع.</string>\n    <string name=\"pref_location_custom_url_details\">يتم إلحاق المسار \\\"v1/geolocate/\\\" تلقائيًا. إذا كان موفِّر خدمة الموقع يتطلب مفتاحًا، فيمكن الحاقه كمعلمة استعلام إلى جذر الرابط.</string>\n    <string name=\"location_data_import_title\">استيراد بيانات الموقع من ملف</string>\n    <string name=\"prefcat_app_last_location\">آخر موقع تم الإبلاغ عنه</string>\n</resources>\n"
  },
  {
    "path": "play-services-location/core/src/main/res/values-ast/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=\"pref_location_wifi_learning_enabled_summary\">Atroxa llocalmente la llocalización de les redes Wi-Fi al usar el GPS.</string>\n    <string name=\"location_app_last_access_at\">Últimu accesu: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"pref_location_cell_learning_enabled_summary\">Atroxa la llocalización de la rede móvil cuando s\\'usa\\'l GPS.</string>\n    <string name=\"fragment_location_apps_title\">Aplicaciones con accesu a la llocalización</string>\n    <string name=\"pref_location_app_force_coarse_summary\">Siempres devuelve llocalizaciones aproximaes a esta aplicación, inorando\\'l so nivel de permisos.</string>\n    <string name=\"pref_location_wifi_moving_enabled_summary\">Recupera direutamente la llocalización de los puntos Wi-Fi compatibles al conectase.</string>\n    <string name=\"prefcat_location_cell_title\">Llocalización pela rede móvil</string>\n    <string name=\"pref_location_wifi_moving_enabled_title\">Solicitar al puntu Wi-Fi</string>\n    <string name=\"pref_location_app_force_coarse_title\">Forciar la llocalización aproximada</string>\n    <string name=\"pref_geocoder_nominatim_enabled_title\">Usar Nominatim</string>\n    <string name=\"service_name_location\">Llocalización</string>\n    <string name=\"prefcat_location_apps_title\">Accesu recién</string>\n    <string name=\"pref_geocoder_nominatim_enabled_summary\">Resuelve direiciones con OpenStreetMap Nominatim.</string>\n    <string name=\"prefcat_location_wifi_title\">Llocalización per Wi-Fi</string>\n    <string name=\"prefcat_geocoder_title\">Resolvedor de direiciones</string>\n</resources>"
  },
  {
    "path": "play-services-location/core/src/main/res/values-az/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_name_location\">Məkan</string>\n    <string name=\"prefcat_location_apps_title\">Son giriş</string>\n    <string name=\"prefcat_location_wifi_title\">Wi-Fi məkanı</string>\n    <string name=\"prefcat_location_cell_title\">Mobil şəbəkə məkanı</string>\n    <string name=\"prefcat_geocoder_title\">Ünvan qəbuledici</string>\n    <string name=\"pref_location_wifi_moving_enabled_title\">Hotspot-dan sorğu</string>\n    <string name=\"pref_location_wifi_moving_enabled_summary\">Qoşulduqda Wi-Fi məkanını birbaşa dəstəklənən Hotspots-dan əldə edin.</string>\n    <string name=\"pref_location_wifi_learning_enabled_title\">GPS-dən xatırla</string>\n    <string name=\"pref_location_wifi_learning_enabled_summary\">GPS istifadə edildikdə Wi-Fi məkanların yerli olaraq saxla.</string>\n    <string name=\"pref_location_cell_learning_enabled_title\">GPS-dən xatırla</string>\n    <string name=\"pref_location_cell_learning_enabled_summary\">GPS istifadə edildikdə mobil şəbəkə yerlərin yerli olaraq saxla.</string>\n    <string name=\"pref_geocoder_nominatim_enabled_title\">Nominatim istifadə et</string>\n    <string name=\"fragment_location_apps_title\">Məkan girişi olan tətbiqlər</string>\n    <string name=\"location_app_last_access_at\">Son giriş: <xliff:g example=\"Dünən, 02:20 PM\"> %1$s</xliff:g></string>\n    <string name=\"pref_location_app_force_coarse_title\">Kobud yeri zorla</string>\n    <string name=\"pref_location_app_force_coarse_summary\">İcazə səviyyəsinə məhəl qoymadan həmişə bu tətbiqə kobud yerləri qaytarın.</string>\n    <string name=\"location_settings_dialog_message_title_to_continue\">Davam etmək üçün microG-nin məkan xidmətin istifadə edən cihaz məkanın aktiv et</string>\n    <string name=\"location_settings_dialog_message_details_start_paragraph\">Cihazınız aşağıdakıları tələb edəcək:</string>\n    <string name=\"location_settings_dialog_message_location_services_gps_and_nlp\">GPS, Wi‑Fi, mobil şəbəkələr və sensorları istifadə edin</string>\n    <string name=\"location_settings_dialog_message_grant_permissions\">microG Xidmətinə məkan icazələri ver</string>\n    <string name=\"location_settings_dialog_message_details_end_paragraph\">Təfərrüatlar üçün məkan tənzimləmələrinə keçin.</string>\n    <string name=\"location_settings_dialog_btn_cancel\">Xeyr, təşəkkür</string>\n    <string name=\"location_settings_dialog_btn_sure\">Oldu</string>\n    <string name=\"pref_location_custom_url_details\">/v1/geolocate yolu avtomatik olaraq əlavə olunur. Məkan təminatçısı açar tələb edirsə, o, kök URL-ə sorğu faktoru kimi əlavə edilə bilər.</string>\n    <string name=\"pref_location_custom_url_input_hint\">Fərdi xidmət URL-i</string>\n    <string name=\"pref_geocoder_nominatim_enabled_summary\">OpenStreetMap Nominatim istifadə edərək ünvanları qəbul et.</string>\n    <string name=\"location_settings_dialog_message_title_for_better_experience\">Daha yaxşı təcrübə üçün microG-nin məkan xidmətin istifadə edən cihazın məkanın aktiv et</string>\n    <string name=\"pref_location_custom_url_summary\">Bu, fərdi xidmət URL-i təyin etməyə imkan verir. Yanlış dəyərlər məkan xidmətlərinin cavab verməməsi və ya tamamilə əlçatan olmaması ilə nəticələnə bilər.</string>\n    <string name=\"location_settings_dialog_message_gls_consent\">microG məkan xidmətin istifadə edin; bu xidmətin bir hissəsi kimi microG məkan məlumatını vaxtaşırı toplaya və məkan dəqiqliyini və məkan əsaslı xidmətləri təkmilləşdirmək üçün bu məlumatı gizli şəkildə istifadə edə bilər.</string>\n</resources>"
  },
  {
    "path": "play-services-location/core/src/main/res/values-be/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=\"location_app_last_access_at\">Апошні доступ: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"prefcat_location_wifi_title\">Месцазнаходжанне па Wi-Fi</string>\n    <string name=\"prefcat_location_cell_title\">Месцазнаходжанне па мабільнай сетцы</string>\n    <string name=\"prefcat_geocoder_title\">Апрацоўшчык адраса</string>\n    <string name=\"pref_location_wifi_learning_enabled_title\">Запамінаць каардынаты GPS</string>\n    <string name=\"pref_location_wifi_learning_enabled_summary\">Запамінаць размяшчэнне кропак Wi-Fi грунтуючыся на дадзеных GPS.</string>\n    <string name=\"pref_geocoder_nominatim_enabled_summary\">Вызначаць адрасы выкарыстоўваючы сэрвіс OpenStreetMap Nominatim.</string>\n    <string name=\"service_name_location\">Месцазнаходжанне</string>\n    <string name=\"prefcat_location_apps_title\">Нядаўнія запыты</string>\n    <string name=\"pref_location_wifi_moving_enabled_title\">Апытваць кропкі Hotspot</string>\n    <string name=\"pref_location_wifi_moving_enabled_summary\">Атрымліваць месцазнаходжанне напрамую ад падтрымліваемых Wi-Fi кропак (Hotspot).</string>\n    <string name=\"pref_location_cell_learning_enabled_title\">Запамінаць каардынаты GPS</string>\n    <string name=\"pref_location_cell_learning_enabled_summary\">Захоўваць размяшчэнне вышак сотавай сувязі падчас працы GPS.</string>\n    <string name=\"pref_geocoder_nominatim_enabled_title\">Выкарыстоўваць Nominatim</string>\n    <string name=\"fragment_location_apps_title\">Прыкладанні з доступам да месцазнаходжання</string>\n    <string name=\"pref_location_app_force_coarse_title\">Прымусова выкарыстоўваць прыкладнае месцазнаходжанне</string>\n    <string name=\"pref_location_app_force_coarse_summary\">Заўсёды даваць прыкладнаю прыкладнае месцазнаходжанне, ігнаруючы яго ўзровень дазволаў.</string>\n    <string name=\"location_settings_dialog_message_details_end_paragraph\">Для атрымання падрабязнай інфармацыі перайдзіце ў налады месцазнаходжання.</string>\n    <string name=\"location_settings_dialog_message_title_to_continue\">Каб працягнуць, уключыце вызначэнне месцазнаходжання, з выкарыстаннем службы вызначэння месцазнаходжання microG</string>\n    <string name=\"location_settings_dialog_message_details_start_paragraph\">Вашай прыладзе патрабуецца:</string>\n    <string name=\"location_settings_dialog_message_location_services_gps_and_nlp\">Выкарыстанне GPS, Wi-Fi, сотавых сетак і датчыкаў</string>\n    <string name=\"location_settings_dialog_message_gls_consent\">Выкарыстанне службы вызначэння месцазнаходжання; у рамках работы гэтай службы microG можа перыядычна ананімна збіраць і выкарыстоўваць дадзеныя аб месцазнаходжанні для павышэння дакладнасці вызначэння месцазнаходжання і паслуг на аснове месцазнаходжання.</string>\n    <string name=\"location_settings_dialog_btn_cancel\">Не, дзякуй</string>\n    <string name=\"location_settings_dialog_btn_sure\">ОК</string>\n    <string name=\"location_settings_dialog_message_title_for_better_experience\">Для паляпшэння вынікаў, уключыце вызначэнне месцазнаходжання, якое выкарыстоўвае службу вызначэння месцазнаходжання microG</string>\n    <string name=\"pref_location_custom_url_summary\">Гэты параметр дазваляе наладзіць URL-адрас службы. Няправільныя значэнні могуць прывесці да таго, што службы вызначэння месцазнаходжання перастануць адказваць на запыты або будуць цалкам недаступныя.</string>\n    <string name=\"pref_location_custom_url_details\">Шлях /v1/geocate будзе дададзены аўтаматычна. Калі правайдэру месцазнаходжання патрабуецца ключ, яго можна дадаць да каранёвага URL-адрасу ў якасці параметра запыту.</string>\n    <string name=\"pref_location_custom_url_input_hint\">Карыстальніцкі адрас службы</string>\n    <string name=\"location_settings_dialog_message_grant_permissions\">Дазволіць сэрвісам microG доступ да месцазнаходжання</string>\n    <string name=\"pref_location_cell_online_enabled_title\">Апытваць анлайн сэрвіс</string>\n    <string name=\"pref_location_custom_source_title\">Карыстальніцкі</string>\n    <string name=\"pref_location_source_terms\">Умовы / Канфідэнцыяльнасць</string>\n    <string name=\"pref_location_source_suggested\">Рэкамендаваны</string>\n    <string name=\"notification_config_required_title\">Патрабуецца настройка</string>\n    <string name=\"location_data_export_wifi_title\">Экспартаваць лакальную базу месцазнаходжання Wi-Fi</string>\n    <string name=\"location_data_export_cell_title\">Экспартаваць лакальную базу месцазнаходжанняў сотавых вышак</string>\n    <string name=\"location_data_import_result_toast\">Імпартавана %1$d запісаў.</string>\n    <string name=\"pref_location_wifi_online_enabled_title\">Апытваць анлайн сэрвіс</string>\n    <string name=\"pref_location_cell_online_enabled_summary\">Вызначаць месцазнаходжанне грунтуючыся на базах сотавых вышак анлайн-сэрвісу вызначэння месцазнаходжання.</string>\n    <string name=\"pref_location_wifi_online_enabled_summary\">Вызначаць месцазнаходжанне грунтуючыся на базах Wi-Fi анлайн-сэрвісу вызначэння месцазнаходжання.</string>\n    <string name=\"pref_location_source_title\">Абярыце онлай службу вызначэння месцазнаходжання</string>\n    <string name=\"pref_location_import_export_title\">Імпарт або экспарт даных аб месцазнаходжанні</string>\n    <string name=\"notification_config_required_text_online_sources\">Каб працягнуць выкарыстанне анлайн-сэрвісаў вызначэння месцазнаходжання, вам неабходна абраць сэрвіс вызначэння месцазнаходжання.</string>\n    <string name=\"location_data_import_title\">Імпарт даных аб месцазнаходжанні з файла</string>\n</resources>"
  },
  {
    "path": "play-services-location/core/src/main/res/values-bn/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n</resources>"
  },
  {
    "path": "play-services-location/core/src/main/res/values-ca/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_name_location\">Ubicació</string>\n    <string name=\"prefcat_location_apps_title\">Accés recent</string>\n    <string name=\"prefcat_location_wifi_title\">Ubicació Wi-Fi</string>\n    <string name=\"prefcat_location_cell_title\">Ubicació de la xarxa mòbil</string>\n    <string name=\"prefcat_geocoder_title\">Resolutor d\\'adreces</string>\n    <string name=\"pref_location_wifi_online_enabled_title\">Sol·licitud del servei en línia</string>\n    <string name=\"pref_location_wifi_online_enabled_summary\">Obtén la ubicació basada en Wi-Fi des d\\'un servei d\\'ubicació en línia.</string>\n    <string name=\"pref_location_wifi_moving_enabled_title\">Sol·licitud des d\\'un punt d\\'accés</string>\n    <string name=\"pref_location_wifi_moving_enabled_summary\">Obtén la ubicació Wi-Fi directament dels punts d\\'accés compatibles quan es connecten.</string>\n    <string name=\"pref_location_wifi_learning_enabled_title\">Recordar del GPS</string>\n    <string name=\"pref_location_wifi_learning_enabled_summary\">Desa les ubicacions Wi-Fi localment quan s\\'utilitza el GPS.</string>\n    <string name=\"pref_location_cell_online_enabled_title\">Sol·licitud del servei en línia</string>\n    <string name=\"pref_location_cell_online_enabled_summary\">Obtén les ubicacions de les antenes de la xarxa mòbil del servei d\\'ubicació en línia.</string>\n    <string name=\"pref_location_cell_learning_enabled_title\">Recordar del GPS</string>\n    <string name=\"location_app_last_access_at\">Últim accés: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"pref_location_app_force_coarse_title\">Forçar la ubicació aproximada</string>\n    <string name=\"pref_location_app_force_coarse_summary\">Tornar sempre les ubicacions aproximades a aquesta aplicació, ignorant el nivell de permís.</string>\n    <string name=\"prefcat_app_last_location\">Última ubicació reportada</string>\n    <string name=\"location_settings_dialog_message_title_for_better_experience\">Per a una millor experiència, activeu la ubicació del dispositiu, que utilitza el servei d\\'ubicació del microG</string>\n    <string name=\"location_settings_dialog_message_title_to_continue\">Per continuar, activeu la ubicació del dispositiu, que utilitza el servei d\\'ubicació del microG</string>\n    <string name=\"location_settings_dialog_message_details_start_paragraph\">El vostre dispositiu haurà de:</string>\n    <string name=\"location_settings_dialog_message_location_services_gps_and_nlp\">Utilitza el GPS, el Wi-Fi, les xarxes mòbils i els sensors</string>\n    <string name=\"location_settings_dialog_message_grant_permissions\">Atorgar permisos d\\'ubicació al servei microG</string>\n    <string name=\"location_settings_dialog_message_gls_consent\">Utilitza el servei d\\'ubicació del microG; com a part d\\'aquest servei, microG pot recollir dades d\\'ubicació periòdicament i utilitzar aquestes dades de manera anònima per millorar la precisió de la ubicació i els serveis basats en la ubicació.</string>\n    <string name=\"location_settings_dialog_message_details_end_paragraph\">Per a més detalls, aneu a la configuració de la ubicació.</string>\n    <string name=\"location_settings_dialog_btn_cancel\">No, gràcies</string>\n    <string name=\"location_settings_dialog_btn_sure\">D\\'acord</string>\n    <string name=\"pref_location_custom_url_summary\">Això permet establir una URL de servei personalitzada. Els valors invàlids poden fer que els serveis d\\'ubicació no contestin o estiguin completament indisponibles.</string>\n    <string name=\"pref_location_custom_url_details\">El camí /v1/geolocate s\\'afegeix automàticament. Si el proveïdor d\\'ubicació requereix una clau, aquesta es pot afegir com a paràmetre de consulta a la URL arrel.</string>\n    <string name=\"pref_location_custom_url_input_hint\">URL de servei personalitzada</string>\n    <string name=\"pref_location_cell_learning_enabled_summary\">Desa ubicacions de la xarxa mòbil localment quan s\\'utilitza el GPS.</string>\n    <string name=\"pref_geocoder_nominatim_enabled_title\">Utilitzar Nominatim</string>\n    <string name=\"pref_geocoder_nominatim_enabled_summary\">Resol les adreces utilitzant OpenStreetMap Nominatim.</string>\n    <string name=\"fragment_location_apps_title\">Aplicacions amb accés d\\'ubicació</string>\n    <string name=\"pref_location_custom_source_title\">Personalitzat</string>\n    <string name=\"pref_location_source_title\">Seleccioneu el servei d\\'ubicació en línia</string>\n    <string name=\"pref_location_source_terms\">Condicions / Privacitat</string>\n    <string name=\"pref_location_source_suggested\">Suggerit</string>\n    <string name=\"pref_location_import_export_title\">Importar o exportar dades d\\'ubicació</string>\n    <string name=\"notification_config_required_title\">Configuració necessària</string>\n    <string name=\"notification_config_required_text_online_sources\">Per continuar utilitzant els serveis d\\'ubicació en línia, heu de seleccionar un servei de dades d\\'ubicació.</string>\n    <string name=\"location_data_export_wifi_title\">Exportar la base de dades local de la ubicació Wi-Fi</string>\n    <string name=\"location_data_export_cell_title\">Exportar la base de dades local de la ubicació de les antenes de telefonia mòbil</string>\n    <string name=\"location_data_import_title\">Importar les dades d\\'ubicació des d\\'un fitxer</string>\n    <string name=\"location_data_import_result_toast\">S\\'han importat %1$d registres.</string>\n</resources>\n"
  },
  {
    "path": "play-services-location/core/src/main/res/values-cs/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_name_location\">Poloha</string>\n    <string name=\"prefcat_location_apps_title\">Nedávný přístup</string>\n    <string name=\"prefcat_location_wifi_title\">Poloha pomocí Wi-Fi</string>\n    <string name=\"pref_location_wifi_moving_enabled_summary\">Získat polohu založenou na Wi-Fi přímo z podporovaných hotspotů po jejich připojení.</string>\n    <string name=\"pref_location_wifi_learning_enabled_summary\">Lokálně ukládat polohy Wi-Fi při použití GPS.</string>\n    <string name=\"pref_location_cell_learning_enabled_summary\">Lokálně ukládat polohy mobilních sítí při použití GPS.</string>\n    <string name=\"pref_geocoder_nominatim_enabled_title\">Použít službu Nominatim</string>\n    <string name=\"fragment_location_apps_title\">Aplikace s přístupem k poloze</string>\n    <string name=\"location_app_last_access_at\">Poslední přístup: <xliff:g example=\"včera v 14:20\">%1$s</xliff:g></string>\n    <string name=\"pref_location_app_force_coarse_title\">Vynutit přibližnou polohu</string>\n    <string name=\"pref_location_app_force_coarse_summary\">Této aplikaci vždy vrátit přibližnou polohu, nezávisle na její úrovni oprávnění.</string>\n    <string name=\"location_settings_dialog_message_title_for_better_experience\">Pro lepší zážitek povolte polohu zařízení, která používá službu polohy microG</string>\n    <string name=\"location_settings_dialog_message_details_start_paragraph\">Vaše zařízení musí:</string>\n    <string name=\"location_settings_dialog_message_location_services_gps_and_nlp\">Používat GPS, Wi-Fi, mobilní sítě a senzory</string>\n    <string name=\"location_settings_dialog_message_grant_permissions\">Udělit oprávnění polohy Službě microG</string>\n    <string name=\"location_settings_dialog_message_details_end_paragraph\">Pro více informací viz nastavení polohy.</string>\n    <string name=\"location_settings_dialog_btn_cancel\">Ne, díky</string>\n    <string name=\"location_settings_dialog_btn_sure\">OK</string>\n    <string name=\"pref_location_custom_url_summary\">Tato možnost umožní nastavení vlastní adresy služby. Neplatné hodnoty mohou způsobit, že služby umístění nebudou odpovídat nebo zcela nedostupné.</string>\n    <string name=\"pref_location_custom_url_details\">Cesta /v1/geolocate je přidána automaticky. Pokud poskytovatel polohy vyžaduje klíč, přidejte jej jako parametr dotazu k základní adrese URL.</string>\n    <string name=\"prefcat_location_cell_title\">Poloha pomocí mobilní sítě</string>\n    <string name=\"prefcat_geocoder_title\">Překladač adres</string>\n    <string name=\"pref_location_wifi_moving_enabled_title\">Vyžádat z hotspotu</string>\n    <string name=\"pref_location_wifi_learning_enabled_title\">Zapamatovat z GPS</string>\n    <string name=\"pref_location_cell_learning_enabled_title\">Zapamatovat z GPS</string>\n    <string name=\"pref_geocoder_nominatim_enabled_summary\">Překládat adresy pomocí služby OpenStreetMap Nominatim.</string>\n    <string name=\"location_settings_dialog_message_title_to_continue\">Pro pokračování povolte polohu zařízení, která používá službu polohy microG</string>\n    <string name=\"location_settings_dialog_message_gls_consent\">Použít službu polohy microG; jako součást této služby může microG pravidelně sbírat data o poloze a anonymně tato data používat pro zlepšení přesnosti polohy a služeb založených na poloze.</string>\n    <string name=\"pref_location_custom_url_input_hint\">Vlastní adresa služby</string>\n    <string name=\"pref_location_wifi_online_enabled_title\">Požadavek z online služby</string>\n    <string name=\"pref_location_wifi_online_enabled_summary\">Získat polohu založenou na Wi-Fi z online polohovacích služeb.</string>\n    <string name=\"pref_location_source_suggested\">Doporučená</string>\n    <string name=\"pref_location_import_export_title\">Importovat nebo exportovat polohová data</string>\n    <string name=\"notification_config_required_text_online_sources\">Pro pokračování v používání online polohových služeb musíte vybrat službu polohových dat.</string>\n    <string name=\"location_data_export_wifi_title\">Exportovat místní databázi lokací Wi-Fi</string>\n    <string name=\"pref_location_cell_online_enabled_title\">Požadavek z online služby</string>\n    <string name=\"pref_location_cell_online_enabled_summary\">Získání polohy věží mobilní sítě z online lokalizační služby.</string>\n    <string name=\"pref_location_source_terms\">Podmínky / Soukromí</string>\n    <string name=\"pref_location_custom_source_title\">Vlastní</string>\n    <string name=\"notification_config_required_title\">Vyžadováno nastavení</string>\n    <string name=\"pref_location_source_title\">Vybrat online polohovací službu</string>\n    <string name=\"location_data_export_cell_title\">Exportovat místní databázi poloh mobilních věží</string>\n    <string name=\"location_data_import_title\">Importovat polohová data ze souboru</string>\n    <string name=\"location_data_import_result_toast\">Importováno %1$d záznamů.</string>\n    <string name=\"prefcat_app_last_location\">Poslední nahlášená poloha</string>\n</resources>\n"
  },
  {
    "path": "play-services-location/core/src/main/res/values-de/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=\"prefcat_location_cell_title\">Funkzellen-basierte Ortung</string>\n    <string name=\"service_name_location\">Standort</string>\n    <string name=\"prefcat_location_apps_title\">Kürzliche Standortzugriffe</string>\n    <string name=\"prefcat_location_wifi_title\">WLAN-basierte Ortung</string>\n    <string name=\"prefcat_geocoder_title\">Adressauflösung</string>\n    <string name=\"pref_location_wifi_learning_enabled_summary\">WLAN-Standorte lokal speichern, wenn GPS verwendet wird.</string>\n    <string name=\"location_app_last_access_at\">Letzter Zugriff: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"fragment_location_apps_title\">Apps mit Standortzugriff</string>\n    <string name=\"pref_location_wifi_moving_enabled_title\">Anfrage von Hotspot</string>\n    <string name=\"pref_location_app_force_coarse_title\">Grobe Ortung erzwingen</string>\n    <string name=\"pref_geocoder_nominatim_enabled_title\">Nominatim verwenden</string>\n    <string name=\"pref_geocoder_nominatim_enabled_summary\">Adressen mit OpenStreetMap Nominatim auflösen.</string>\n    <string name=\"pref_location_wifi_moving_enabled_summary\">Wi-Fi-Standort direkt von unterstützten Hotspots abrufen, wenn eine Verbindung besteht.</string>\n    <string name=\"pref_location_wifi_learning_enabled_title\">Von GPS merken</string>\n    <string name=\"pref_location_cell_learning_enabled_title\">Von GPS merken</string>\n    <string name=\"pref_location_cell_learning_enabled_summary\">Mobilfunkstandorte lokal speichern, wenn GPS verwendet wird.</string>\n    <string name=\"pref_location_app_force_coarse_summary\">Immer grobe Standorte an diese App zurückgeben, ohne Rücksicht auf die Berechtigungsstufe.</string>\n    <string name=\"location_settings_dialog_btn_cancel\">Nein danke</string>\n    <string name=\"location_settings_dialog_btn_sure\">OK</string>\n    <string name=\"location_settings_dialog_message_grant_permissions\">Erteilen von Standortberechtigungen für den microG-Dienst</string>\n    <string name=\"location_settings_dialog_message_details_start_paragraph\">Das muss dein Gerät können:</string>\n    <string name=\"location_settings_dialog_message_location_services_gps_and_nlp\">Nutzung von GPS, Wi-Fi, Mobilfunknetzen und Sensoren</string>\n    <string name=\"location_settings_dialog_message_title_for_better_experience\">Schalte die Geräteortung, die den microG-Standortdienst nutzt, für eine bessere Erfahrung ein</string>\n    <string name=\"location_settings_dialog_message_title_to_continue\">Schalte zum Fortfahren die Geräteortung, die den microG-Standortdienst nutzt, ein</string>\n    <string name=\"location_settings_dialog_message_details_end_paragraph\">Einzelheiten dazu findest du in den Standorteinstellungen.</string>\n    <string name=\"location_settings_dialog_message_gls_consent\">Nutzung des microG-Standortdienstes; im Rahmen dieses Dienstes kann microG in regelmäßigen Abständen Standortdaten sammeln und diese Daten in anonymer Form zur Verbesserung der Standortgenauigkeit und der standortbezogenen Dienste verwenden.</string>\n    <string name=\"pref_location_custom_url_input_hint\">Benutzerdefinierte Dienst-URL</string>\n    <string name=\"pref_location_custom_url_summary\">Dies ermöglicht die Einstellung einer benutzerdefinierten Dienst-URL. Ungültige Werte können dazu führen, dass Standortdienste nicht mehr reagieren oder gar nicht mehr verfügbar sind.</string>\n    <string name=\"pref_location_custom_url_details\">Der Pfad /v1/geolocate wird automatisch angehängt. Wenn der Standortdienstanbieter einen Schlüssel benötigt, kann dieser als Abfrageparameter an die Stamm-URL angehängt werden.</string>\n    <string name=\"pref_location_wifi_online_enabled_title\">Online-Dienst abfragen</string>\n    <string name=\"pref_location_wifi_online_enabled_summary\">Wi-Fi-Standort von einem Online-Standortdienst abrufen.</string>\n    <string name=\"pref_location_cell_online_enabled_title\">Online-Dienst abfragen</string>\n    <string name=\"pref_location_cell_online_enabled_summary\">Standorte von Mobilfunkmasten von einem Online-Standortdienst abrufen.</string>\n    <string name=\"pref_location_custom_source_title\">Benutzerdefiniert</string>\n    <string name=\"pref_location_source_title\">Online-Standortdienst auswählen</string>\n    <string name=\"pref_location_source_terms\">Bedingungen / Datenschutz</string>\n    <string name=\"pref_location_source_suggested\">Empfohlen</string>\n    <string name=\"pref_location_import_export_title\">Standortdaten im- oder exportieren</string>\n    <string name=\"notification_config_required_title\">Konfiguration erforderlich</string>\n    <string name=\"location_data_export_wifi_title\">Lokale Wi-Fi-Standort-Datenbank exportieren</string>\n    <string name=\"location_data_import_result_toast\">%1$d Einträge importiert.</string>\n    <string name=\"notification_config_required_text_online_sources\">Um weiterhin den Online-Standortdienst zu nutzen, muss ein Standortdienst ausgewählt werden.</string>\n    <string name=\"location_data_export_cell_title\">Lokale Funkzellen-Standort-Datenbank exportieren</string>\n    <string name=\"location_data_import_title\">Standortdaten aus Datei importieren</string>\n    <string name=\"prefcat_app_last_location\">Letzter gemeldeter Standort</string>\n</resources>\n"
  },
  {
    "path": "play-services-location/core/src/main/res/values-eo/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources></resources>"
  },
  {
    "path": "play-services-location/core/src/main/res/values-es/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_name_location\">Ubicación</string>\n    <string name=\"prefcat_location_apps_title\">Acceso reciente</string>\n    <string name=\"location_app_last_access_at\">Último acceso: <xliff:g example=\"Ayer, 02:20 p.m.\">%1$s</xliff:g></string>\n    <string name=\"prefcat_location_wifi_title\">Ubicación por Wi-Fi</string>\n    <string name=\"prefcat_location_cell_title\">Ubicación por red móvil</string>\n    <string name=\"prefcat_geocoder_title\">Resolución de direcciones</string>\n    <string name=\"pref_location_wifi_moving_enabled_title\">Solicitud desde punto de acceso</string>\n    <string name=\"pref_location_wifi_moving_enabled_summary\">Obtenga la ubicación Wi-Fi directamente de los puntos de acceso compatibles cuando se conecte.</string>\n    <string name=\"pref_location_wifi_learning_enabled_title\">Recordar desde el GPS</string>\n    <string name=\"pref_location_wifi_learning_enabled_summary\">Almacena localmente las ubicaciones wifi cuando se utiliza el GPS.</string>\n    <string name=\"pref_location_cell_learning_enabled_title\">Recordar desde el GPS</string>\n    <string name=\"pref_location_cell_learning_enabled_summary\">Almacena localmente las ubicaciones de la red móvil cuando se utiliza el GPS.</string>\n    <string name=\"pref_geocoder_nominatim_enabled_title\">Usar Nominatim</string>\n    <string name=\"pref_geocoder_nominatim_enabled_summary\">Resolver direcciones utilizando OpenStreetMap Nominatim.</string>\n    <string name=\"fragment_location_apps_title\">Aplicaciones con acceso de ubicación</string>\n    <string name=\"pref_location_app_force_coarse_title\">Forzar ubicación aproximada</string>\n    <string name=\"pref_location_app_force_coarse_summary\">Devuelve siempre ubicaciones aproximadas a esta aplicación, ignorando su nivel de permiso.</string>\n    <string name=\"location_settings_dialog_message_details_start_paragraph\">Su dispositivo deberá:</string>\n    <string name=\"location_settings_dialog_message_details_end_paragraph\">Para obtener más información, vaya a la configuración de la ubicación.</string>\n    <string name=\"location_settings_dialog_btn_cancel\">No, gracias</string>\n    <string name=\"location_settings_dialog_btn_sure\">De acuerdo</string>\n    <string name=\"location_settings_dialog_message_title_to_continue\">Para continuar, active la ubicación del dispositivo, que utiliza el servicio de ubicación de microG</string>\n    <string name=\"location_settings_dialog_message_location_services_gps_and_nlp\">Utilizar GPS, Wi-Fi, redes móviles y sensores</string>\n    <string name=\"location_settings_dialog_message_gls_consent\">Utilizar el servicio de ubicación de microG; como parte de este servicio, microG puede recopilar datos de ubicación periódicamente y utilizar estos datos de forma anónima para mejorar la precisión de la ubicación y los servicios basados en la ubicación.</string>\n    <string name=\"location_settings_dialog_message_title_for_better_experience\">Para una mejor experiencia, active la ubicación del dispositivo, que utiliza el servicio de ubicación de microG</string>\n    <string name=\"pref_location_custom_url_summary\">Permite establecer una URL de servicio personalizada. Los valores no válidos pueden provocar que los servicios de localización no respondan o no estén disponibles por completo.</string>\n    <string name=\"pref_location_custom_url_input_hint\">URL del servicio personalizado</string>\n    <string name=\"pref_location_custom_url_details\">La ruta /v1/geolocate se añade automáticamente. Si el proveedor de localización requiere una clave, puede añadirse como parámetro de consulta a la URL raíz.</string>\n    <string name=\"location_settings_dialog_message_grant_permissions\">Otorgar permisos de ubicación al servicio microG</string>\n    <string name=\"pref_location_cell_online_enabled_title\">Solicitud desde servicio en línea</string>\n    <string name=\"pref_location_custom_source_title\">Personalizado</string>\n    <string name=\"pref_location_source_title\">Seleccione el servicio de ubicación en línea</string>\n    <string name=\"pref_location_source_terms\">Términos/privacidad</string>\n    <string name=\"pref_location_source_suggested\">Sugerencia</string>\n    <string name=\"pref_location_import_export_title\">Importar o exportar datos de ubicación</string>\n    <string name=\"notification_config_required_title\">Configuración obligatoria</string>\n    <string name=\"notification_config_required_text_online_sources\">Para seguir utilizando los servicios de ubicación en línea, debe seleccionar un servicio de datos de ubicación.</string>\n    <string name=\"location_data_export_wifi_title\">Exportar base de datos de ubicaciones de wifi local</string>\n    <string name=\"location_data_export_cell_title\">Exportar base de datos de ubicación de torres de telefonía móvil locales</string>\n    <string name=\"location_data_import_title\">Importar datos de ubicación desde un archivo</string>\n    <string name=\"location_data_import_result_toast\">Se importaron %1$d registros.</string>\n    <string name=\"pref_location_wifi_online_enabled_title\">Solicitud del servicio en línea</string>\n    <string name=\"pref_location_wifi_online_enabled_summary\">Obtenga la ubicación basada en wifi del servicio de ubicación en línea.</string>\n    <string name=\"pref_location_cell_online_enabled_summary\">Obtén la ubicación de las torres de telefonía móvil de un servicio de ubicación en línea.</string>\n    <string name=\"prefcat_app_last_location\">Última ubicación informada</string>\n</resources>\n"
  },
  {
    "path": "play-services-location/core/src/main/res/values-fa/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=\"pref_location_wifi_moving_enabled_summary\">دریافت مکان وای‌فای مستقیماً از هات‌اسپات‌های پشتیبانی‌شده هنگام اتصال.</string>\n    <string name=\"pref_location_wifi_learning_enabled_title\">یادسپاری از مکان‌یاب</string>\n    <string name=\"pref_location_wifi_learning_enabled_summary\">نگه‌داری مکان‌های وای‌فای به‌صورت محلی هنگام به‌کارگیری مکان‌یاب.</string>\n    <string name=\"pref_location_cell_online_enabled_title\">درخواست از خدمت آنلاین</string>\n    <string name=\"pref_location_cell_online_enabled_summary\">دریافت مکان‌های دکل‌های شبکه همراه از خدمت مکان‌یابی آنلاین.</string>\n    <string name=\"pref_location_cell_learning_enabled_title\">یادسپاری از مکان‌یاب</string>\n    <string name=\"pref_location_cell_learning_enabled_summary\">نگه‌داری مکان‌های شبکه همراه به‌صورت محلی هنگام به‌کارگیری مکان‌یاب.</string>\n    <string name=\"pref_geocoder_nominatim_enabled_title\">به‌کارگیری نومیناتیم</string>\n    <string name=\"pref_geocoder_nominatim_enabled_summary\">حل نشانی‌ها با به‌کارگیری نومیناتیم اوپن‌استریت‌مپ.</string>\n    <string name=\"fragment_location_apps_title\">برنامه‌های دارای دسترسی مکان</string>\n    <string name=\"location_app_last_access_at\">آخرین دسترسی: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"pref_location_app_force_coarse_title\">اجبار به مکان تقریبی</string>\n    <string name=\"pref_location_app_force_coarse_summary\">همیشه مکان‌های تقریبی به این برنامه بازگردانده شود، بدون توجه به سطح دسترسی آن.</string>\n    <string name=\"prefcat_app_last_location\">آخرین مکان گزارش‌شده</string>\n    <string name=\"pref_location_wifi_online_enabled_title\">درخواست از خدمت آنلاین</string>\n    <string name=\"prefcat_geocoder_title\">حل‌کننده نشانی</string>\n    <string name=\"pref_location_wifi_online_enabled_summary\">دریافت مکان مبتنی بر وای‌فای از خدمت مکان‌یابی آنلاین.</string>\n    <string name=\"pref_location_wifi_moving_enabled_title\">درخواست از هات‌اسپات</string>\n    <string name=\"location_settings_dialog_message_details_start_paragraph\">دستگاه شما باید:</string>\n    <string name=\"location_settings_dialog_message_title_for_better_experience\">برای تجربه بهتر، مکان‌یابی دستگاه را روشن کنید که از خدمت مکان‌یابی میکروجی استفاده می‌کند</string>\n    <string name=\"location_settings_dialog_message_title_to_continue\">برای ادامه، مکان‌یابی دستگاه را روشن کنید که از خدمت مکان‌یابی میکروجی استفاده می‌کند</string>\n    <string name=\"service_name_location\">مکان‌یابی</string>\n    <string name=\"prefcat_location_apps_title\">دسترسی‌های اخیر</string>\n    <string name=\"prefcat_location_wifi_title\">مکان‌یابی وای‌فای</string>\n    <string name=\"prefcat_location_cell_title\">مکان‌یابی شبکه همراه</string>\n    <string name=\"location_settings_dialog_btn_cancel\">نه، سپاس</string>\n    <string name=\"location_data_import_result_toast\">وارد شد %1$d ثبت.</string>\n    <string name=\"location_settings_dialog_message_grant_permissions\">دسترسی‌های مکان را به خدمت میکروجی بدهید</string>\n    <string name=\"location_settings_dialog_message_location_services_gps_and_nlp\">از مکان‌یاب، وای‌فای، شبکه‌های همراه، و حسگرها استفاده کند</string>\n    <string name=\"location_settings_dialog_message_gls_consent\">از خدمت مکان‌یابی میکروجی استفاده کند؛ به‌عنوان بخشی از این خدمت، میکروجی ممکن است داده‌های مکان را به‌صورت دوره‌ای گردآوری کند و از این داده‌ها به‌صورت ناشناس برای بهبود دقت مکان‌یابی و خدمات بر پایه مکان استفاده کند.</string>\n    <string name=\"location_settings_dialog_message_details_end_paragraph\">برای جزئیات، به تنظیمات مکان بروید.</string>\n    <string name=\"location_settings_dialog_btn_sure\">باشه</string>\n    <string name=\"pref_location_custom_url_summary\">این امکان تنظیم نشانی خدمت سفارشی را فراهم می‌کند. مقادیر نامعتبر ممکن است باعث عدم پاسخگویی یا کاملاً در دسترس نبودن خدمات مکان‌یابی شوند.</string>\n    <string name=\"pref_location_custom_url_details\">مسیر /v1/geolocate به‌صورت خودکار افزوده می‌شود. اگر فراهم‌کننده مکان به کلید نیاز داشته باشد، می‌توان آن را به‌عنوان پارامتر پرس‌وجو به نشانی پایه افزود.</string>\n    <string name=\"pref_location_custom_url_input_hint\">نشانی خدمت سفارشی</string>\n    <string name=\"pref_location_custom_source_title\">سفارشی</string>\n    <string name=\"pref_location_source_title\">انتخاب خدمت مکان‌یابی آنلاین</string>\n    <string name=\"pref_location_source_terms\">شرایط / حریم خصوصی</string>\n    <string name=\"pref_location_source_suggested\">پیشنهادشده</string>\n    <string name=\"pref_location_import_export_title\">وارد کردن یا برون‌ریزی داده‌های مکان</string>\n    <string name=\"notification_config_required_title\">نیاز به پیکربندی</string>\n    <string name=\"notification_config_required_text_online_sources\">برای ادامه به‌کارگیری خدمات مکان‌یابی آنلاین، باید یک خدمت داده مکان انتخاب کنید.</string>\n    <string name=\"location_data_export_wifi_title\">برون‌ریزی پایگاه داده مکان وای‌فای محلی</string>\n    <string name=\"location_data_export_cell_title\">برون‌ریزی پایگاه داده مکان دکل‌های همراه محلی</string>\n    <string name=\"location_data_import_title\">وارد کردن داده‌های مکان از پرونده</string>\n</resources>\n"
  },
  {
    "path": "play-services-location/core/src/main/res/values-fi/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"prefcat_location_apps_title\">Viimeaikainen käyttö</string>\n    <string name=\"prefcat_location_wifi_title\">Wi-Fi-sijainti</string>\n    <string name=\"service_name_location\">Sijainti</string>\n    <string name=\"prefcat_location_cell_title\">Mobiiliverkkosijainti</string>\n    <string name=\"prefcat_geocoder_title\">Osoitteen selvittäjä</string>\n    <string name=\"pref_location_wifi_online_enabled_title\">Pyydä verkkopalvelusta</string>\n    <string name=\"pref_location_wifi_online_enabled_summary\">Hae Wi-Fi-pohjainen sijainti verkkosijaintipalvelusta.</string>\n    <string name=\"pref_location_wifi_moving_enabled_title\">Pyydä Hotspotilta</string>\n    <string name=\"pref_location_wifi_moving_enabled_summary\">Hae Wi-Fi-sijainti suoraan tuetuista hotspoteista joihin yhdistät.</string>\n    <string name=\"pref_location_wifi_learning_enabled_title\">Muista GPS-sijainnit</string>\n</resources>\n"
  },
  {
    "path": "play-services-location/core/src/main/res/values-fil/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_name_location\">Lokasyon</string>\n    <string name=\"prefcat_location_apps_title\">Kamakailang pag-access</string>\n    <string name=\"prefcat_location_wifi_title\">Wi-Fi na lokasyon</string>\n    <string name=\"prefcat_geocoder_title\">Resolver ng address</string>\n    <string name=\"pref_location_wifi_moving_enabled_title\">Ihiling mula sa Hotspot</string>\n    <string name=\"pref_location_wifi_moving_enabled_summary\">Direktang kunin ang lokasyon ng Wi-Fi mula sa mga sinusuportahang hotspot kapag nakakonekta.</string>\n    <string name=\"pref_location_wifi_learning_enabled_title\">Tandaan mula sa GPS</string>\n    <string name=\"pref_location_cell_learning_enabled_title\">Tandaan mula sa GPS</string>\n    <string name=\"pref_location_cell_learning_enabled_summary\">Mag-imbak ng mga lokasyon ng mobile network nang lokal kapag ginamit ang GPS.</string>\n    <string name=\"pref_geocoder_nominatim_enabled_summary\">I-resolve ang mga address gamit ng OpenStreetMap Nominatim.</string>\n    <string name=\"fragment_location_apps_title\">Mga app na may access sa lokasyon</string>\n    <string name=\"location_app_last_access_at\">Huling pag-access: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"pref_location_app_force_coarse_title\">Pilitin ang magaspang na lokasyon</string>\n    <string name=\"location_settings_dialog_message_details_start_paragraph\">Kakailanganin ng iyong device na:</string>\n    <string name=\"location_settings_dialog_message_location_services_gps_and_nlp\">Gumamit ng GPS, Wi‑Fi, mga cell network, at mga sensor</string>\n    <string name=\"location_settings_dialog_message_gls_consent\">Gamitin ang serbisyo ng lokasyon ng microG; bilang bahagi ng serbisyong ito, maaring pana-panahong kolektahin ng microG ang data ng lokasyon at gamitin ang data na ito sa isang hindi kilalang paraan upang mapabuti ang katumpakan ng lokasyon at mga serbisyong nakabatay sa lokasyon.</string>\n    <string name=\"location_settings_dialog_message_details_end_paragraph\">Para sa mga detalye, pumunta sa mga setting ng lokasyon.</string>\n    <string name=\"location_settings_dialog_btn_cancel\">Hindi, salamat</string>\n    <string name=\"location_settings_dialog_btn_sure\">OK</string>\n    <string name=\"prefcat_location_cell_title\">Mobile network na lokasyon</string>\n    <string name=\"pref_location_wifi_learning_enabled_summary\">Mag-imbak ng mga lokasyon ng Wi-Fi nang lokal kapag ginamit ang GPS.</string>\n    <string name=\"pref_geocoder_nominatim_enabled_title\">Gamitin ang Nominatim</string>\n    <string name=\"pref_location_app_force_coarse_summary\">Palaging ibalik ang mga magaspang na lokasyon sa app na ito, hindi pinapansin ang antas ng pahintulot nito.</string>\n    <string name=\"location_settings_dialog_message_title_for_better_experience\">Para sa mas magandang karanasan, buksan ang lokasyon ng device, na gumagamit ng serbisyo ng lokasyon ng microG</string>\n    <string name=\"location_settings_dialog_message_title_to_continue\">Para magpatuloy, buksan ang lokasyon ng device, na gumagamit ng serbisyo ng lokasyon ng microG</string>\n    <string name=\"pref_location_custom_url_summary\">Nagbibigay-daan sa pagtakda ng custom na URL ng serbisyo. Ang mga hindi wastong value ay maaring magdulot na ang mga serbisyo ng lokasyon na hindi tumugon o hindi available.</string>\n    <string name=\"pref_location_custom_url_details\">Ang /v1/geolocate na path ay awtomatikong dinudugtungan. Kapag ang provider ng lokasyon ay nangangailangan ng key, maari itong dugtungan bilang query parameter sa root URL.</string>\n    <string name=\"pref_location_custom_url_input_hint\">Custom na URL ng serbisyo</string>\n    <string name=\"location_settings_dialog_message_grant_permissions\">Ibigay ang mga pahintulot ng lokasyon sa Serbisyo ng microG</string>\n    <string name=\"pref_location_wifi_online_enabled_summary\">Kunin ang naka-base sa Wi-Fi na lokasyon mula sa online na serbisyo ng lokasyon.</string>\n    <string name=\"location_data_import_title\">I-import ang data ng lokasyon mula sa file</string>\n    <string name=\"pref_location_wifi_online_enabled_title\">Ihiling mula sa online na serbisyo</string>\n    <string name=\"pref_location_cell_online_enabled_title\">Ihiling mula sa online na serbisyo</string>\n    <string name=\"pref_location_cell_online_enabled_summary\">Kunin ang mga lokasyon ng mga mobile network cell tower mula sa online na serbisyo ng lokasyon.</string>\n    <string name=\"pref_location_custom_source_title\">Pasadya</string>\n    <string name=\"pref_location_source_title\">Pumili ng online na serbisyo ng lokasyon</string>\n    <string name=\"pref_location_source_terms\">Mga Tuntunin / Privacy</string>\n    <string name=\"pref_location_source_suggested\">Inimumungkahi</string>\n    <string name=\"pref_location_import_export_title\">I-import o i-export ang data ng lokasyon</string>\n    <string name=\"notification_config_required_title\">Nangangailangan ng configuration</string>\n    <string name=\"notification_config_required_text_online_sources\">Para magpatuloy sa paggagamit ng online na serbisyo ng lokasyon, kailangan mong pumili ng serbisyo ng data ng lokasyon.</string>\n    <string name=\"location_data_export_wifi_title\">I-export ang lokal na database ng lokasyon ng Wi-Fi</string>\n    <string name=\"location_data_export_cell_title\">I-export ang lokal na database ng lokasyon ng cell tower</string>\n    <string name=\"location_data_import_result_toast\">Naka-import ng %1$d mga record.</string>\n    <string name=\"prefcat_app_last_location\">Huling naiulat na lokasyon</string>\n</resources>\n"
  },
  {
    "path": "play-services-location/core/src/main/res/values-fr/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_name_location\">Localisation</string>\n    <string name=\"prefcat_location_apps_title\">Accès récents</string>\n    <string name=\"prefcat_location_wifi_title\">Localisation basée sur le Wi-Fi</string>\n    <string name=\"prefcat_location_cell_title\">Localisation basée sur le réseau mobile</string>\n    <string name=\"prefcat_geocoder_title\">Résolution d\\'adresses</string>\n    <string name=\"location_settings_dialog_message_title_to_continue\">Pour continuer, activez la localisation de l\\'appareil, le service de localisation de microG sera utilisé</string>\n    <string name=\"pref_location_wifi_online_enabled_title\">Obtention via un service en ligne</string>\n    <string name=\"pref_location_wifi_online_enabled_summary\">Récupérer la localisation des réseaux Wi-Fi depuis un service de localisation en ligne.</string>\n    <string name=\"pref_location_wifi_moving_enabled_summary\">Récupérer la localisation des réseaux Wi-Fi depuis une connexion hot-spot supportée.</string>\n    <string name=\"pref_location_wifi_learning_enabled_title\">Mémorisation depuis le GPS</string>\n    <string name=\"pref_location_wifi_learning_enabled_summary\">Enregistrer sur l\\'appareil la localisation des réseaux Wi-Fi lorsque le GPS est utilisé.</string>\n    <string name=\"pref_location_cell_online_enabled_title\">Obtention via un service en ligne</string>\n    <string name=\"pref_location_cell_online_enabled_summary\">Récupérer la localisation des tours du réseau mobile depuis un service de localisation en ligne.</string>\n    <string name=\"pref_location_cell_learning_enabled_title\">Mémorisation depuis le GPS</string>\n    <string name=\"pref_location_cell_learning_enabled_summary\">Enregistrer sur l\\'appareil la localisation des tours du réseau mobile lorsque le GPS est utilisé.</string>\n    <string name=\"pref_geocoder_nominatim_enabled_title\">Utiliser Nominatim</string>\n    <string name=\"pref_geocoder_nominatim_enabled_summary\">Déterminer les adresses en utilisant Nominatim d\\'OpenStreetMap.</string>\n    <string name=\"fragment_location_apps_title\">Applis ayant accès à la localisation</string>\n    <string name=\"pref_location_app_force_coarse_summary\">Toujours fournir une localisation approximative à cette appli, et ignorer son niveau de permission.</string>\n    <string name=\"location_app_last_access_at\">Dernier accès : <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"pref_location_app_force_coarse_title\">Forcer la localisation approximative</string>\n    <string name=\"location_settings_dialog_message_location_services_gps_and_nlp\">GPS, Wi-Fi, réseaux mobiles et capteurs</string>\n    <string name=\"location_settings_dialog_message_grant_permissions\">Accorder aux services microG l\\'accès à la localisation</string>\n    <string name=\"location_settings_dialog_message_details_start_paragraph\">Votre appareil va utiliser :</string>\n    <string name=\"location_settings_dialog_btn_cancel\">Non merci</string>\n    <string name=\"location_settings_dialog_btn_sure\">OK</string>\n    <string name=\"pref_location_custom_source_title\">Personnalisée</string>\n    <string name=\"pref_location_source_title\">Choisir le service de localisation en ligne</string>\n    <string name=\"pref_location_source_terms\">Termes et confidentialité</string>\n    <string name=\"pref_location_source_suggested\">Suggéré</string>\n    <string name=\"pref_location_import_export_title\">Importer/exporter les données de localisation</string>\n    <string name=\"notification_config_required_title\">Configuration requise</string>\n    <string name=\"notification_config_required_text_online_sources\">Pour continuer à utiliser les services de localisation en ligne, vous devez choisir un service de données de localisation.</string>\n    <string name=\"location_data_export_wifi_title\">Exporter la base de données locale de la localisation basée sur le Wi-Fi</string>\n    <string name=\"location_data_export_cell_title\">Exporter la base de données locale de la localisation des tours du réseau mobile</string>\n    <string name=\"location_data_import_title\">Importer les données de localisation depuis un fichier</string>\n    <string name=\"location_data_import_result_toast\">%1$d enregistrements importés.</string>\n    <string name=\"location_settings_dialog_message_title_for_better_experience\">Pour une meilleure expérience, activez la localisation de l\\'appareil, le service de localisation de microG sera utilisé</string>\n    <string name=\"location_settings_dialog_message_details_end_paragraph\">Pour plus de détails, consultez les paramètres de localisation.</string>\n    <string name=\"pref_location_wifi_moving_enabled_title\">Obtention via hot-spot</string>\n    <string name=\"location_settings_dialog_message_gls_consent\">Utiliser le service de localisation de microG. Via l\\'utilisation de ce service, microG peut collecter périodiquement les données de localisation et les utiliser de façon anonyme pour améliorer la précision de la localisation et des services basés sur la localisation.</string>\n    <string name=\"pref_location_custom_url_details\">Le chemin de géolocalisation /v1/ est automatiquement attaché. Si le fournisseur de localisation exige une clé, elle peut être rattachée en tant que paramètre de la requête à l\\'URL racine.</string>\n    <string name=\"pref_location_custom_url_summary\">Ceci permet de modifier l\\'URL du service. Une valeur incorrecte peut causer une perte de réactivité des services de localisation, voire leur indisponibilité totale.</string>\n    <string name=\"pref_location_custom_url_input_hint\">URL personnalisée du service</string>\n    <string name=\"prefcat_app_last_location\">Dernière localisation reportée</string>\n</resources>\n"
  },
  {
    "path": "play-services-location/core/src/main/res/values-ga/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_name_location\">Suíomh</string>\n    <string name=\"pref_location_cell_online_enabled_title\">Iarratas ó sheirbhís ar líne</string>\n    <string name=\"location_settings_dialog_message_location_services_gps_and_nlp\">Úsáid GPS, Wi-Fi, líonraí cille, agus braiteoirí</string>\n    <string name=\"location_settings_dialog_btn_sure\">Ceart go leor</string>\n    <string name=\"notification_config_required_title\">Cumraíocht de dhíth</string>\n    <string name=\"location_data_import_title\">Iompórtáil sonraí suímh ó chomhad</string>\n    <string name=\"location_data_import_result_toast\">Iompórtáladh %1$d taifead.</string>\n    <string name=\"prefcat_location_cell_title\">Suíomh líonra soghluaiste</string>\n    <string name=\"pref_location_cell_learning_enabled_title\">Cuimhnigh ó GPS</string>\n    <string name=\"pref_location_cell_learning_enabled_summary\">Déan láithreacha líonra soghluaiste a stóráil go háitiúil nuair a úsáidtear GPS.</string>\n    <string name=\"prefcat_location_apps_title\">Rochtain le déanaí</string>\n    <string name=\"prefcat_location_wifi_title\">Suíomh Wi-Fi</string>\n    <string name=\"prefcat_geocoder_title\">Réititheoir seoltaí</string>\n    <string name=\"pref_location_wifi_online_enabled_summary\">Faigh suíomh bunaithe ar Wi-Fi ón tseirbhís suímh ar líne.</string>\n    <string name=\"pref_location_wifi_moving_enabled_title\">Iarratas ó Hotspot</string>\n    <string name=\"pref_location_wifi_moving_enabled_summary\">Faigh suíomh Wi-Fi go díreach ó hotspots a dtacaítear leo nuair atá tú ceangailte.</string>\n    <string name=\"pref_location_wifi_online_enabled_title\">Iarratas ó sheirbhís ar líne</string>\n    <string name=\"pref_location_wifi_learning_enabled_title\">Cuimhnigh ó GPS</string>\n    <string name=\"pref_location_wifi_learning_enabled_summary\">Stóráil suíomhanna Wi-Fi go háitiúil nuair a úsáidtear GPS.</string>\n    <string name=\"pref_location_cell_online_enabled_summary\">Faigh láithreacha túir cille líonra soghluaiste ón tseirbhís suímh ar líne.</string>\n    <string name=\"pref_geocoder_nominatim_enabled_summary\">Réitigh seoltaí le OpenStreetMap Nominatim.</string>\n    <string name=\"fragment_location_apps_title\">Aipeanna le rochtain suímh</string>\n    <string name=\"pref_geocoder_nominatim_enabled_title\">Úsáid Nominatim</string>\n    <string name=\"pref_location_app_force_coarse_title\">Fórsa suíomh garbh</string>\n    <string name=\"location_app_last_access_at\">An rochtain dheireanach: <xliff:g example=\"Inné, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"pref_location_app_force_coarse_summary\">Cuir láithreacha garbha ar ais chuig an aip seo i gcónaí, gan aird a thabhairt ar a leibhéal ceada.</string>\n    <string name=\"location_settings_dialog_message_title_for_better_experience\">Chun taithí níos fearr a fháil, cuir suíomh an ghléis ar siúl, a úsáideann seirbhís suímh microG</string>\n    <string name=\"location_settings_dialog_message_title_to_continue\">Chun leanúint ar aghaidh, cuir suíomh gléis ar siúl, a úsáideann seirbhís suíomhanna microG</string>\n    <string name=\"location_settings_dialog_message_details_start_paragraph\">Beidh ar do ghléas:</string>\n    <string name=\"location_settings_dialog_message_grant_permissions\">Ceadanna suímh a dheonú do Sheirbhís MicroG</string>\n    <string name=\"location_settings_dialog_message_gls_consent\">Úsáid seirbhís suímh microG; mar chuid den tseirbhís seo, féadfaidh MicroG sonraí suímh a bhailiú go tréimhsiúil agus na sonraí seo a úsáid ar bhealach anaithnid chun cruinneas suímh agus seirbhísí bunaithe ar shuíomh a fheabhsú.</string>\n    <string name=\"location_settings_dialog_message_details_end_paragraph\">Le haghaidh sonraí, téigh go dtí na socruithe suímh.</string>\n    <string name=\"location_settings_dialog_btn_cancel\">Níl go raibh maith agat</string>\n    <string name=\"pref_location_custom_url_summary\">Ligeann sé seo URL seirbhíse saincheaptha a shocrú. Is féidir le luachanna neamhbhailí a bheith mar thoradh ar sheirbhísí suímh a bheith neamhfhreagrach nó gan a bheith ar fáil go hiomlán.</string>\n    <string name=\"pref_location_source_title\">Roghnaigh seirbhís suímh ar líne</string>\n    <string name=\"pref_location_custom_url_input_hint\">URL seirbhíse saincheaptha</string>\n    <string name=\"pref_location_custom_source_title\">Saincheaptha</string>\n    <string name=\"pref_location_source_terms\">Téarmaí / Príobháideacht</string>\n    <string name=\"pref_location_custom_url_details\">Cuirtear an cosán /v1/geolocate i gceangal go huathoibríoch. Má tá eochair ag teastáil ó sholáthraí an tsuímh, is féidir í a chur i gceangal leis an bhfréamh-URL mar pharaiméadar fiosrúcháin.</string>\n    <string name=\"pref_location_source_suggested\">Molta</string>\n    <string name=\"notification_config_required_text_online_sources\">Chun leanúint ar aghaidh ag úsáid seirbhísí suímh ar líne, ní mór duit seirbhís sonraí suímh a roghnú.</string>\n    <string name=\"location_data_export_wifi_title\">Easpórtáil bunachar sonraí suímh Wi-Fi áitiúil</string>\n    <string name=\"pref_location_import_export_title\">Iompórtáil nó easpórtáil sonraí suímh</string>\n    <string name=\"location_data_export_cell_title\">Easpórtáil bunachar sonraí suímh túr cille áitiúil</string>\n    <string name=\"prefcat_app_last_location\">An suíomh is déanaí a tuairiscíodh</string>\n</resources>\n"
  },
  {
    "path": "play-services-location/core/src/main/res/values-hu/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"service_name_location\">Hely</string>\n    <string name=\"prefcat_location_apps_title\">Legutóbbi hozzáférés</string>\n    <string name=\"prefcat_location_wifi_title\">Wi-Fi helymeghatározás</string>\n    <string name=\"prefcat_location_cell_title\">Mobilhálózati helymeghatározás</string>\n    <string name=\"prefcat_geocoder_title\">Hely felkereső</string>\n    <string name=\"pref_location_wifi_online_enabled_title\">Online szolgáltatásokból lekérés engedélyezése</string>\n    <string name=\"pref_location_wifi_online_enabled_summary\">Wi-Fi-alapú helyadatok online helyszolgáltatóktól való lekérdezése.</string>\n    <string name=\"pref_location_wifi_moving_enabled_title\">Hotspot-ok használata</string>\n    <string name=\"pref_location_wifi_moving_enabled_summary\">Wi-Fi helyadatok direkt lekérése támogatott hotspot-októl amikor csatlakoztatva vannak.</string>\n    <string name=\"pref_location_wifi_learning_enabled_title\">Megjegyzés GPS alapján</string>\n    <string name=\"pref_location_wifi_learning_enabled_summary\">Wi-Fi helyadatok lokális tárolása amikor GPS használatban van.</string>\n</resources>\n"
  },
  {
    "path": "play-services-location/core/src/main/res/values-in/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_name_location\">Lokasi</string>\n    <string name=\"prefcat_location_apps_title\">Akses terbaru</string>\n    <string name=\"prefcat_location_wifi_title\">Lokasi Wi-Fi</string>\n    <string name=\"prefcat_location_cell_title\">Lokasi jaringan seluler</string>\n    <string name=\"prefcat_geocoder_title\">Penyelesaian alamat</string>\n    <string name=\"pref_location_wifi_online_enabled_title\">Permohonan dari layanan online</string>\n    <string name=\"pref_location_wifi_online_enabled_summary\">Mendapatkan lokasi berbasis Wi-Fi dari layanan lokasi online.</string>\n    <string name=\"pref_location_wifi_moving_enabled_title\">Permohonan dari Hotspot</string>\n    <string name=\"pref_location_wifi_moving_enabled_summary\">Mendapatkan lokasi Wi-Fi secara langsung dari hotspot yang didukung saat terhubung.</string>\n    <string name=\"pref_location_wifi_learning_enabled_title\">Ingat dari GPS</string>\n    <string name=\"pref_location_wifi_learning_enabled_summary\">Simpan lokasi Wi-Fi secara lokal saat GPS digunakan.</string>\n    <string name=\"pref_location_cell_online_enabled_title\">Permohonan dari layanan online</string>\n    <string name=\"pref_location_cell_online_enabled_summary\">Mendapatkan lokasi menara seluler jaringan seluler dari layanan lokasi online.</string>\n    <string name=\"pref_location_cell_learning_enabled_title\">Ingat dari GPS</string>\n    <string name=\"pref_location_cell_learning_enabled_summary\">Simpan lokasi jaringan seluler secara lokal saat GPS digunakan.</string>\n    <string name=\"pref_geocoder_nominatim_enabled_title\">Gunakan Nominatim</string>\n    <string name=\"pref_geocoder_nominatim_enabled_summary\">Resolusi alamat menggunakan OpenStreetMap Nominatim.</string>\n    <string name=\"fragment_location_apps_title\">Aplikasi yang memiliki akses ke lokasi</string>\n    <string name=\"location_app_last_access_at\">Akses terakhir: <xliff:g example=\"Kemarin, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"pref_location_app_force_coarse_title\">Tentukan lokasi kasar</string>\n    <string name=\"pref_location_app_force_coarse_summary\">Selalu kembalikan lokasi kasar ke aplikasi ini, mengabaikan tingkat izinnya.</string>\n    <string name=\"prefcat_app_last_location\">Lokasi terakhir yang dilaporkan</string>\n    <string name=\"location_settings_dialog_message_title_for_better_experience\">Untuk pengalaman yang lebih baik, aktifkan lokasi perangkat, yang menggunakan layanan lokasi microG</string>\n    <string name=\"location_settings_dialog_message_title_to_continue\">Untuk melanjutkan, aktifkan lokasi perangkat, yang menggunakan layanan lokasi microG</string>\n    <string name=\"location_settings_dialog_message_details_start_paragraph\">Perangkat Anda perlu:</string>\n    <string name=\"location_settings_dialog_message_location_services_gps_and_nlp\">Gunakan GPS, Wi-Fi, jaringan seluler, dan sensor</string>\n    <string name=\"location_settings_dialog_message_grant_permissions\">Berikan izin lokasi kepada layanan microG</string>\n    <string name=\"location_settings_dialog_message_gls_consent\">Gunakan layanan lokasi microG; sebagai bagian dari layanan ini, microG dapat mengumpulkan data lokasi secara berkala dan menggunakan data tersebut secara anonim untuk meningkatkan akurasi lokasi dan layanan berbasis lokasi.</string>\n    <string name=\"location_settings_dialog_message_details_end_paragraph\">Untuk detailnya, buka pengaturan lokasi.</string>\n    <string name=\"location_settings_dialog_btn_cancel\">Tidak, terima kasih</string>\n    <string name=\"location_settings_dialog_btn_sure\">Oke</string>\n    <string name=\"pref_location_custom_url_summary\">Hal ini memungkinkan pengaturan URL layanan kustom. Nilai yang tidak valid dapat menyebabkan layanan lokasi menjadi tidak responsif atau bahkan tidak tersedia sama sekali.</string>\n    <string name=\"pref_location_custom_url_details\">Path /v1/geolocate ditambahkan secara otomatis. Jika penyedia lokasi memerlukan kunci, kunci tersebut dapat ditambahkan sebagai parameter kueri ke URL akar.</string>\n    <string name=\"pref_location_custom_url_input_hint\">URL Layanan Khusus</string>\n    <string name=\"pref_location_custom_source_title\">Kustom</string>\n    <string name=\"pref_location_source_title\">Pilih layanan lokasi online</string>\n    <string name=\"pref_location_source_terms\">Ketentuan / Privasi</string>\n    <string name=\"pref_location_source_suggested\">Disarankan</string>\n    <string name=\"pref_location_import_export_title\">Impor atau ekspor data lokasi</string>\n    <string name=\"notification_config_required_title\">Konfigurasi diperlukan</string>\n    <string name=\"notification_config_required_text_online_sources\">Untuk terus menggunakan layanan lokasi online, Anda perlu memilih layanan data lokasi.</string>\n    <string name=\"location_data_export_wifi_title\">Ekspor basis data lokasi Wi-Fi lokal</string>\n    <string name=\"location_data_export_cell_title\">Ekspor basis data lokasi menara seluler lokal</string>\n    <string name=\"location_data_import_title\">Impor data lokasi dari file</string>\n    <string name=\"location_data_import_result_toast\">Impor %1$d catatan.</string>\n</resources>\n"
  },
  {
    "path": "play-services-location/core/src/main/res/values-is/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_name_location\">Staðsetning</string>\n    <string name=\"prefcat_location_apps_title\">Nýlegur aðgangur</string>\n    <string name=\"prefcat_location_wifi_title\">Wi-Fi staðsetning</string>\n    <string name=\"prefcat_location_cell_title\">Staðsetning farsímanets</string>\n    <string name=\"pref_location_wifi_online_enabled_title\">Biðja um frá netþjónustu</string>\n    <string name=\"pref_location_cell_online_enabled_title\">Biðja um frá netþjónustu</string>\n    <string name=\"location_settings_dialog_message_details_start_paragraph\">Tækið þitt mun þurfa að:</string>\n    <string name=\"location_settings_dialog_message_location_services_gps_and_nlp\">Nota GPS, Wi‑Fi, farsímanet og skynjara</string>\n    <string name=\"location_settings_dialog_message_details_end_paragraph\">Til að skoða nánar skaltu fara í staðsetningarstillingar.</string>\n    <string name=\"pref_location_source_title\">Veldu staðsetningaþjónustu</string>\n    <string name=\"location_data_import_title\">Flytja staðsetningargögn inn úr skrá</string>\n    <string name=\"location_data_import_result_toast\">Flutti inn %1$d færslur.</string>\n    <string name=\"prefcat_geocoder_title\">Uppfletting heimilisfanga</string>\n    <string name=\"pref_location_wifi_moving_enabled_title\">Biðja um frá tengipunkti</string>\n    <string name=\"pref_location_wifi_learning_enabled_title\">Muna frá GPS</string>\n    <string name=\"pref_location_cell_learning_enabled_title\">Muna frá GPS</string>\n    <string name=\"pref_geocoder_nominatim_enabled_title\">Nota Nominatim</string>\n    <string name=\"fragment_location_apps_title\">Forrit með aðgang að staðsetningu</string>\n    <string name=\"pref_location_app_force_coarse_title\">Þvinga grófa staðsetningu</string>\n    <string name=\"location_settings_dialog_message_grant_permissions\">Virkja heimildir fyrir staðsetningu til microG-þjónustu</string>\n    <string name=\"location_settings_dialog_btn_cancel\">Nei takk</string>\n    <string name=\"location_settings_dialog_btn_sure\">Í lagi</string>\n    <string name=\"pref_location_custom_url_input_hint\">Sérsniðin slóð þjónustu</string>\n    <string name=\"pref_location_custom_source_title\">Sérsniðið</string>\n    <string name=\"pref_location_source_terms\">Skilmálar og meðferð persónuupplýsinga</string>\n    <string name=\"pref_location_source_suggested\">Tillaga</string>\n    <string name=\"pref_location_import_export_title\">Flytja inn/út staðsetningargögn</string>\n    <string name=\"notification_config_required_title\">Staðfestingar krafist</string>\n    <string name=\"pref_geocoder_nominatim_enabled_summary\">Fletta upp heimilisföngum með OpenStreetMap Nominatim.</string>\n    <string name=\"location_app_last_access_at\">Síðasti aðgangur: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"location_settings_dialog_message_title_for_better_experience\">Til að hlutirnir virki betur, skaltu kveikja á staðsetningu tækisins, sem notar staðsetningaþjónustu microG</string>\n    <string name=\"location_data_export_wifi_title\">Flytja út gagnagrunn Wi-Fi-staðsetninga af tölvunni</string>\n    <string name=\"location_settings_dialog_message_title_to_continue\">Til að halda áfram, skaltu kveikja á staðsetningu tækisins, sem notar staðsetningaþjónustu microG</string>\n    <string name=\"notification_config_required_text_online_sources\">Til að halda áfram að nota staðsetningaþjónustur á netinu, þarftu að velja þjónustu fyrir staðsetningagögn.</string>\n    <string name=\"location_data_export_cell_title\">Flytja út gagnagrunn endurvarpastaðsetninga af tölvunni</string>\n    <string name=\"pref_location_wifi_online_enabled_summary\">Sækja staðsetningu byggða á Wi-Fi frá staðsetningarþjónustum á netinu.</string>\n    <string name=\"pref_location_wifi_moving_enabled_summary\">Sækja staðsetningu byggða á Wi-Fi beint frá tengdum aðgangspunktum.</string>\n    <string name=\"pref_location_wifi_learning_enabled_summary\">Geyma staðsetningar byggðar á Wi-Fi á tækinu þegar GPS er notað.</string>\n    <string name=\"pref_location_app_force_coarse_summary\">Ávallt skila grófum staðsetningum til þessa forrits, og hunsa þannig heimildastig þess.</string>\n    <string name=\"pref_location_cell_online_enabled_summary\">Sækja staðsetningar farsímaendurvarpa frá staðsetningarþjónustum á netinu.</string>\n    <string name=\"pref_location_cell_learning_enabled_summary\">Geyma staðsetningar farsímaneta á tækinu þegar GPS er notað.</string>\n    <string name=\"location_settings_dialog_message_gls_consent\">Notaðu microG-staðsetningarþjónustu; sem hluta þessara þjónustu, gæti microG öðru hverju safnað staðsetningargögnum og notað þau gögn á nafnlausan hátt til að bæta nákvæmni staðsetninga og áreiðanleika staðsetningartengdra þjónustna.</string>\n    <string name=\"pref_location_custom_url_summary\">Þetta gerir kleift að setja sérsniðna slóð þjónustu. Ógildar slóðir geta valdi því að staðsetningarþjónustur svari ekki eða verði ekki tiltækar.</string>\n    <string name=\"pref_location_custom_url_details\">Slóðinni /v1/geolocate er sjálfkrafa bætt aftanvið. Ef staðsetningarveitan krefst lykils, má bæta honum við aftan við rótarslóðina sem fyrirspurnarviðfangi.</string>\n    <string name=\"prefcat_app_last_location\">Síðasta uppgefna staðsetning</string>\n</resources>\n"
  },
  {
    "path": "play-services-location/core/src/main/res/values-it/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_name_location\">Geolocalizzazione</string>\n    <string name=\"prefcat_location_apps_title\">Accessi recenti</string>\n    <string name=\"location_app_last_access_at\">Ultimo accesso: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"fragment_location_apps_title\">Applicazioni con accesso alla posizione</string>\n    <string name=\"pref_location_app_force_coarse_summary\">Fornisci sempre la posizione approssimativa a quest\\'app, ignorando il suo livello di autorizzazione.</string>\n    <string name=\"pref_location_app_force_coarse_title\">Forza l\\'uso della posizione approssimativa</string>\n    <string name=\"pref_location_wifi_learning_enabled_summary\">Salva sul dispositivo le informazioni sulla posizione delle reti Wi-Fi quando il GPS è in uso.</string>\n    <string name=\"pref_location_cell_learning_enabled_summary\">Salva sul dispositivo le informazioni sulla posizione delle reti cellulari quando il GPS è in uso.</string>\n    <string name=\"pref_location_cell_learning_enabled_title\">Deduci dal GPS</string>\n    <string name=\"pref_location_wifi_learning_enabled_title\">Deduci dal GPS</string>\n    <string name=\"pref_location_wifi_moving_enabled_summary\">Ottieni una geolocalizzazione basata sul Wi-Fi direttamente da un hotspot che la supporta, quando connesso.</string>\n    <string name=\"prefcat_location_cell_title\">Geolocalizzazione basata sulla rete cellulare</string>\n    <string name=\"pref_location_wifi_moving_enabled_title\">Richiedi agli hotspot</string>\n    <string name=\"pref_geocoder_nominatim_enabled_title\">Usa Nominatim</string>\n    <string name=\"pref_geocoder_nominatim_enabled_summary\">Cerca gli indirizzi usando OpenStreetMap Nominatim.</string>\n    <string name=\"prefcat_location_wifi_title\">Geolocalizzazione basata sul Wi-Fi</string>\n    <string name=\"prefcat_geocoder_title\">Ricerca degli indirizzi</string>\n    <string name=\"location_settings_dialog_btn_sure\">OK</string>\n    <string name=\"location_settings_dialog_btn_cancel\">No, grazie</string>\n    <string name=\"location_settings_dialog_message_details_end_paragraph\">Per ulteriori dettagli, vai alle impostazioni di geolocalizzazione.</string>\n    <string name=\"pref_location_custom_url_details\">Il percorso /v1/geolocate viene aggiunto automaticamente. Se il provider di posizione richiede una chiave, questa può essere aggiunta come parametro di query all\\'URL radice.</string>\n    <string name=\"location_settings_dialog_message_grant_permissions\">Consentire l\\'accesso alla posizione al servizio di microG</string>\n    <string name=\"location_settings_dialog_message_gls_consent\">Utilizzando il servizio di geolocalizzazione di microG, quest\\'ultimo potrebbe raccogliere periodicamente dati sulla posizione e utilizzare tali dati in modo anonimo per migliorare l\\'accuratezza della posizione e i servizi basati sulla posizione.</string>\n    <string name=\"location_settings_dialog_message_details_start_paragraph\">Il tuo dispositivo dovrà:</string>\n    <string name=\"location_settings_dialog_message_location_services_gps_and_nlp\">Utilizzare il GPS, le reti Wi-Fi, le reti cellulari e i sensori</string>\n    <string name=\"location_settings_dialog_message_title_for_better_experience\">Per una migliore esperienza, attiva la posizione del dispositivo, che utilizza il servizio di geolocalizzazione di microG</string>\n    <string name=\"location_settings_dialog_message_title_to_continue\">Per continuare, attiva la posizione del dispositivo, che utilizza il servizio di geolocalizzazione di microG</string>\n    <string name=\"pref_location_custom_url_summary\">Qui è possibile impostare l\\'URL di un servizio personalizzato. Valori non validi possono rendere i servizi di geolocalizzazione instabili o completamente non disponibili.</string>\n    <string name=\"pref_location_custom_url_input_hint\">URL del servizio personalizzato</string>\n    <string name=\"pref_location_wifi_online_enabled_title\">Richiedi al servizio online</string>\n    <string name=\"pref_location_wifi_online_enabled_summary\">Ottieni una geolocalizzazione basata sul Wi-Fi dal servizio di localizzazione online.</string>\n    <string name=\"pref_location_cell_online_enabled_title\">Richiedi al servizio online</string>\n    <string name=\"pref_location_cell_online_enabled_summary\">Ottieni la posizione delle antenne delle reti cellulari dal servizio di localizzazione online.</string>\n    <string name=\"pref_location_source_title\">Seleziona il servizio di localizzazione online</string>\n    <string name=\"pref_location_source_terms\">Termini / Privacy</string>\n    <string name=\"pref_location_source_suggested\">Consigliato</string>\n    <string name=\"pref_location_custom_source_title\">Personalizzato</string>\n    <string name=\"pref_location_import_export_title\">Importa o esporta i dati delle posizioni</string>\n    <string name=\"notification_config_required_title\">Configurazione richiesta</string>\n    <string name=\"notification_config_required_text_online_sources\">Per continuare a utilizzare i servizi di localizzazione online, è necessario selezionare un servizio di localizzazione.</string>\n    <string name=\"location_data_export_wifi_title\">Esporta il database locale delle posizioni delle reti Wi-Fi</string>\n    <string name=\"location_data_import_title\">Importa i dati delle posizioni da file</string>\n    <string name=\"location_data_export_cell_title\">Esporta il database locale delle posizioni delle antenne delle reti cellulari</string>\n    <string name=\"location_data_import_result_toast\">%1$d voci importate.</string>\n    <string name=\"prefcat_app_last_location\">Ultima posizione segnalata</string>\n</resources>\n"
  },
  {
    "path": "play-services-location/core/src/main/res/values-iw/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"service_name_location\">מיקום</string>\n    <string name=\"prefcat_geocoder_title\">מפענח כתובות</string>\n</resources>\n"
  },
  {
    "path": "play-services-location/core/src/main/res/values-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=\"location_settings_dialog_message_title_to_continue\">続行するには、デバイスの位置情報をオンにしてください。これはmicroGの位置情報サービスを使用します</string>\n    <string name=\"location_settings_dialog_message_gls_consent\">microG 位置情報サービスを利用します。このサービスの一環として、 microG は定期的に位置情報を収集し、位置情報の精度と位置情報サービスの改善のために、このデータを匿名化した形で利用する場合があります。</string>\n    <string name=\"location_settings_dialog_btn_cancel\">結構です</string>\n    <string name=\"location_settings_dialog_btn_sure\">OK</string>\n    <string name=\"location_settings_dialog_message_title_for_better_experience\">より良い体験のため、デバイスの位置情報をオンにしてください。これは microG の位置情報サービスを利用します</string>\n    <string name=\"location_settings_dialog_message_location_services_gps_and_nlp\">GPS、Wi-Fi、モバイルネットワーク、センサーを利用する</string>\n    <string name=\"location_settings_dialog_message_details_end_paragraph\">詳細については、位置情報設定をご覧ください。</string>\n    <string name=\"service_name_location\">ロケーション</string>\n    <string name=\"prefcat_location_apps_title\">最近のアクセス</string>\n    <string name=\"prefcat_location_wifi_title\">Wi-Fi ロケーション</string>\n    <string name=\"prefcat_location_cell_title\">モバイルネットワークロケーション</string>\n    <string name=\"pref_location_wifi_moving_enabled_title\">ホットスポットからのリクエスト</string>\n    <string name=\"pref_location_wifi_moving_enabled_summary\">接続時に対応ホットスポットからWi-Fiロケーションを直接取得します。</string>\n    <string name=\"pref_location_wifi_learning_enabled_summary\">GPS使用時にWi-Fiロケーションをローカルに保存します。</string>\n    <string name=\"fragment_location_apps_title\">位置情報にアクセスできるアプリ</string>\n    <string name=\"pref_location_wifi_learning_enabled_title\">GPSを保存</string>\n    <string name=\"pref_geocoder_nominatim_enabled_title\">Nominatim を使用する</string>\n    <string name=\"pref_location_source_terms\">利用規約とプライバシー</string>\n    <string name=\"prefcat_geocoder_title\">アドレス解決機能</string>\n    <string name=\"pref_location_wifi_online_enabled_title\">オンラインサービスからのリクエスト</string>\n    <string name=\"pref_location_wifi_online_enabled_summary\">オンライン位置情報サービスからWi-Fiベースの位置情報を取得する。</string>\n    <string name=\"pref_location_cell_online_enabled_title\">オンラインサービスからのリクエスト</string>\n    <string name=\"pref_location_cell_online_enabled_summary\">オンライン位置情報サービスからモバイルネットワーク基地局の位置を取得する。</string>\n    <string name=\"pref_location_cell_learning_enabled_summary\">GPSが使用されている場合、モバイルネットワークの位置情報をローカルに保存する。</string>\n    <string name=\"pref_location_cell_learning_enabled_title\">GPSを記憶する</string>\n    <string name=\"pref_geocoder_nominatim_enabled_summary\">OpenStreetMap Nominatim を使用してアドレスを解決する。</string>\n    <string name=\"location_app_last_access_at\">最終アクセス: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"pref_location_app_force_coarse_title\">おおよその位置を指定する</string>\n    <string name=\"pref_location_app_force_coarse_summary\">常に大まかな位置情報をこのアプリに返すようにし、権限を無視する。</string>\n    <string name=\"prefcat_app_last_location\">最後に報告された位置</string>\n    <string name=\"location_settings_dialog_message_details_start_paragraph\">あなたのデバイスには以下が必要となります：</string>\n    <string name=\"location_settings_dialog_message_grant_permissions\">microG サービスに位置情報のアクセス許可を付与する</string>\n    <string name=\"pref_location_custom_url_summary\">これによりカスタムサービスURLを設定できます。無効な値を設定すると、位置情報サービスが応答しなくなるか、完全に利用できなくなる可能性があります。</string>\n    <string name=\"pref_location_custom_url_details\">/v1/geolocate パスは自動的に追加されます。位置情報プロバイダーがキーを必要とする場合、ルートURLにクエリパラメータとして追加できます。</string>\n    <string name=\"pref_location_custom_url_input_hint\">カスタムサービスURL</string>\n    <string name=\"pref_location_custom_source_title\">カスタム</string>\n    <string name=\"pref_location_source_title\">オンライン位置情報サービスを選択</string>\n    <string name=\"pref_location_source_suggested\">推奨</string>\n    <string name=\"pref_location_import_export_title\">位置データのインポートまたはエクスポート</string>\n    <string name=\"notification_config_required_title\">設定が必要です</string>\n    <string name=\"notification_config_required_text_online_sources\">オンライン位置情報サービスを継続して利用するには、位置情報データサービスを選択する必要があります。</string>\n    <string name=\"location_data_export_wifi_title\">ローカルWi-Fi位置情報データベースをエクスポートする</string>\n    <string name=\"location_data_export_cell_title\">ローカルな携帯電話基地局位置データベースをエクスポートする</string>\n    <string name=\"location_data_import_title\">ファイルから位置データをインポートする</string>\n    <string name=\"location_data_import_result_toast\">%1$d 件のレコードをインポートしました。</string>\n</resources>\n"
  },
  {
    "path": "play-services-location/core/src/main/res/values-ko/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_name_location\">위치</string>\n    <string name=\"prefcat_location_apps_title\">최근 접근</string>\n    <string name=\"prefcat_location_wifi_title\">Wi-Fi 위치</string>\n    <string name=\"prefcat_location_cell_title\">모바일 네트워크 위치</string>\n    <string name=\"prefcat_geocoder_title\">주소 확인기</string>\n    <string name=\"pref_location_wifi_online_enabled_title\">온라인 서비스에 요청</string>\n    <string name=\"pref_location_wifi_online_enabled_summary\">온라인 위치 서비스에서 Wi-Fi 기반 위치를 불러옵니다.</string>\n    <string name=\"pref_location_wifi_moving_enabled_title\">핫스팟에서 요청</string>\n    <string name=\"pref_location_wifi_learning_enabled_title\">GPS로 기억하기</string>\n    <string name=\"pref_location_wifi_learning_enabled_summary\">GPS를 사용 중일때 기기에 Wi-Fi 위치를 저장합니다.</string>\n    <string name=\"pref_location_cell_online_enabled_title\">온라인 서비스에서 요청</string>\n    <string name=\"pref_location_cell_learning_enabled_title\">GPS로 기억하기</string>\n    <string name=\"pref_location_cell_learning_enabled_summary\">GPS를 사용 중일때 기기에 모바일 네트워크 위치를 저장합니다.</string>\n    <string name=\"pref_geocoder_nominatim_enabled_title\">Nominatim 사용</string>\n    <string name=\"location_settings_dialog_btn_cancel\">괜찮습니다</string>\n    <string name=\"notification_config_required_title\">설정 필요</string>\n    <string name=\"pref_location_wifi_moving_enabled_summary\">연결된 지원되는 핫스팟에서 Wi-Fi 위치를 직접 가져옵니다.</string>\n    <string name=\"pref_location_cell_online_enabled_summary\">온라인 위치 서비스에서 모바일 네트워크 기지국 위치를 불러옵니다.</string>\n    <string name=\"pref_geocoder_nominatim_enabled_summary\">OpenStreetMap Nominatim으로 주소를 확인합니다.</string>\n    <string name=\"fragment_location_apps_title\">위치 권한이 있는 앱</string>\n    <string name=\"location_app_last_access_at\">마지막 접근: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"pref_location_app_force_coarse_title\">대략적인 위치 강제 사용</string>\n    <string name=\"pref_location_app_force_coarse_summary\">이 앱의 권한 수준을 무시하고, 항상 대략적인 위치를 반환합니다.</string>\n    <string name=\"prefcat_app_last_location\">마지막으로 보고된 위치</string>\n    <string name=\"location_settings_dialog_message_title_for_better_experience\">더 나은 경험을 위해, microG의 위치 서비스를 사용하는 위치 설정를 켜세요</string>\n    <string name=\"location_settings_dialog_message_title_to_continue\">계속하려면, microG의 위치 서비스를 사용하는 위치 설정를 켜세요</string>\n    <string name=\"location_settings_dialog_message_details_start_paragraph\">기기에서 다음이 필요합니다:</string>\n    <string name=\"location_settings_dialog_message_location_services_gps_and_nlp\">GPS, Wi-Fi, 셀룰러 네트워크, 센서 사용</string>\n    <string name=\"location_settings_dialog_message_grant_permissions\">microG 서비스에게 위치 권한 부여</string>\n    <string name=\"location_settings_dialog_message_gls_consent\">microG 위치 서비스를 사용; 이 서비스의 일환으로 microG는 주기적으로 위치 데이터를 수집하고 이 데이터를 익명의 방식으로 사용하여 위치 정확성과 위치 기반 서비스를 개선할 수 있습니다.</string>\n    <string name=\"location_settings_dialog_message_details_end_paragraph\">자세한 내용은 위치 설정에서 참조해주세요.</string>\n    <string name=\"location_settings_dialog_btn_sure\">확인</string>\n    <string name=\"pref_location_custom_url_summary\">사용자 지정 서비스 URL을 설정할 수 있습니다. 잘못된 값은 위치 서비스가 응답하지 않거나 완전히 사용할 수 없게 만들 수 있습니다.</string>\n    <string name=\"pref_location_custom_url_details\">/v1/geolocate 경로가 자동으로 추가됩니다. 위치 제공자가 키를 필요로 하는 경우 루트 URL에 쿼리 매개변수로 추가할 수 있습니다.</string>\n    <string name=\"pref_location_custom_url_input_hint\">사용자 지정 서비스 URL</string>\n    <string name=\"pref_location_custom_source_title\">사용자 지정</string>\n    <string name=\"pref_location_source_title\">온라인 위치 서비스 선택</string>\n    <string name=\"pref_location_source_terms\">약관 / 개인정보 보호 정책</string>\n    <string name=\"pref_location_source_suggested\">추천</string>\n    <string name=\"pref_location_import_export_title\">위치 데이터 가져오기 또는 내보내기</string>\n    <string name=\"notification_config_required_text_online_sources\">온라인 위치 서비스를 계속 사용하려면, 위치 데이터 서비스를 선택해야 합니다.</string>\n    <string name=\"location_data_export_wifi_title\">로컬 Wi-Fi 위치 데이터베이스 내보내기</string>\n    <string name=\"location_data_export_cell_title\">로컬 기지국 위치 데이터베이스 내보내기</string>\n    <string name=\"location_data_import_title\">파일에서 위치 데이터 가져오기</string>\n    <string name=\"location_data_import_result_toast\">%1$d개의 기록을 가져왔습니다.</string>\n</resources>\n"
  },
  {
    "path": "play-services-location/core/src/main/res/values-lv/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources></resources>"
  },
  {
    "path": "play-services-location/core/src/main/res/values-lzh/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources></resources>"
  },
  {
    "path": "play-services-location/core/src/main/res/values-ml/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"service_name_location\">സ്ഥലം</string>\n    <string name=\"prefcat_location_apps_title\">സമീപകാല ആക്‌സസ്</string>\n    <string name=\"prefcat_location_wifi_title\">വൈഫൈ ലൊക്കേഷൻ</string>\n    <string name=\"prefcat_location_cell_title\">മൊബൈൽ നെറ്റ്‌വർക്ക് ലൊക്കേഷൻ</string>\n    <string name=\"prefcat_geocoder_title\">വിലാസ പരിഹാരി</string>\n    <string name=\"pref_location_wifi_online_enabled_title\">ഓൺലൈൻ സേവനത്തിൽ നിന്നുള്ള അഭ്യർത്ഥന</string>\n    <string name=\"pref_location_wifi_online_enabled_summary\">ഓൺലൈൻ ലൊക്കേഷൻ സേവനത്തിൽ നിന്ന് വൈഫൈ അടിസ്ഥാനമാക്കിയുള്ള ലൊക്കേഷൻ ലഭ്യമാക്കുക.</string>\n    <string name=\"pref_location_wifi_moving_enabled_title\">ഹോട്ട്‌സ്‌പോട്ടിൽ നിന്നുള്ള അഭ്യർത്ഥന</string>\n    <string name=\"pref_location_wifi_moving_enabled_summary\">കണക്റ്റുചെയ്യുമ്പോൾ പിന്തുണയ്ക്കുന്ന ഹോട്ട്‌സ്‌പോട്ടുകളിൽ നിന്ന് നേരിട്ട് വൈഫൈ ലൊക്കേഷൻ ലഭ്യമാക്കുക.</string>\n</resources>\n"
  },
  {
    "path": "play-services-location/core/src/main/res/values-nb-rNO/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=\"pref_location_wifi_learning_enabled_summary\">Lagre Wi-Fi-posisjoner lokalt når GPS brukes.</string>\n    <string name=\"location_app_last_access_at\">Sist brukt: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"pref_location_cell_learning_enabled_summary\">Lagre mobilnettverksposisjoner lokalt når GPS brukes.</string>\n    <string name=\"fragment_location_apps_title\">Programmer med posisjonstilgang</string>\n    <string name=\"pref_location_app_force_coarse_summary\">Alltid gi grov posisjonsnøyaktighet til appen, uavhengig av dets tilgangsnivå.</string>\n    <string name=\"pref_location_cell_learning_enabled_title\">Husk fra GPS</string>\n    <string name=\"pref_location_wifi_learning_enabled_title\">Husk fra GPS</string>\n    <string name=\"pref_location_wifi_moving_enabled_summary\">Hent Wi-Fi-posisjon direkte fra støttede mobile nettverksdelinger når tilkoblet.</string>\n    <string name=\"prefcat_location_cell_title\">Mobilnettverksposisjonering</string>\n    <string name=\"pref_location_wifi_moving_enabled_title\">Forespørsel fra mobil nettverksdeling</string>\n    <string name=\"pref_location_app_force_coarse_title\">Påtving omtrentlig posisjon</string>\n    <string name=\"pref_geocoder_nominatim_enabled_title\">Bruk Nominatim</string>\n    <string name=\"service_name_location\">Posisjon</string>\n    <string name=\"prefcat_location_apps_title\">Nylig tilgang</string>\n    <string name=\"pref_geocoder_nominatim_enabled_summary\">Utled adresser ved bruk av OpenStreetMap Nominatim.</string>\n    <string name=\"prefcat_location_wifi_title\">Wi-Fi-posisjonering</string>\n    <string name=\"prefcat_geocoder_title\">Adresseutleder</string>\n    <string name=\"pref_location_wifi_online_enabled_title\">Forespør fra tjeneste på nettet</string>\n    <string name=\"pref_location_wifi_online_enabled_summary\">Hent Wi-Fi-lokasjon fra en nettverkstjeneste.</string>\n    <string name=\"pref_location_cell_online_enabled_title\">Forespørsel fra nettverkstjeneste</string>\n    <string name=\"prefcat_app_last_location\">Siste rapporterte posisjon</string>\n    <string name=\"location_settings_dialog_message_details_start_paragraph\">Enheten din trenger å:</string>\n    <string name=\"location_settings_dialog_message_location_services_gps_and_nlp\">Bruke GPS. Wi-Fi, mobilnett og sensorer</string>\n    <string name=\"location_settings_dialog_message_grant_permissions\">Gi tilgang til lokasjonstjenester til microG-tjenestene</string>\n    <string name=\"location_settings_dialog_btn_cancel\">Nei takk</string>\n    <string name=\"location_settings_dialog_btn_sure\">OK</string>\n    <string name=\"pref_location_cell_online_enabled_summary\">Hente lokasjoner til mobilnettets master fra stedstjenester på nettet.</string>\n    <string name=\"location_settings_dialog_message_title_for_better_experience\">For en bedre opplevelse, skru på stedstjenester, som bruker microGs stedstjeneste</string>\n    <string name=\"location_settings_dialog_message_title_to_continue\">For å fortsette, skru på stedstjenester, som bruker microGs stedstjenester</string>\n    <string name=\"location_settings_dialog_message_details_end_paragraph\">For mer informasjon, se stedstjenesteinnstillingene.</string>\n    <string name=\"pref_location_custom_url_input_hint\">Brukerdefinert tjeneste-URL</string>\n    <string name=\"pref_location_custom_source_title\">Brukerdefinert</string>\n    <string name=\"pref_location_source_title\">Velg stedstjeneste på nettet</string>\n    <string name=\"pref_location_source_terms\">Vilkår / Personvern</string>\n    <string name=\"pref_location_source_suggested\">Foreslått</string>\n    <string name=\"pref_location_import_export_title\">Importer eller eksporter lokasjonsdata</string>\n    <string name=\"notification_config_required_title\">Konfigurasjon påkrevd</string>\n    <string name=\"location_data_import_title\">Importer lokasjonsdata fra fil</string>\n    <string name=\"location_data_import_result_toast\">Importerte %1$d oppslag.</string>\n    <string name=\"location_settings_dialog_message_gls_consent\">Bruk microGs stedstjenester; gjennom denne tjenester samler microG inn lokasjonsdata periodisk og bruker disse dataene anonymt for å prøve å forbedre presisjon og lokasjonsbaserte tjenester.</string>\n    <string name=\"pref_location_custom_url_summary\">Her kan du angi en brukerdefinert tjeneste-URL. Ugyldige verdier kan føre til at lokasjonstjenestene kan slutte å fungere riktig.</string>\n    <string name=\"pref_location_custom_url_details\">/v1/geolocate-stien legges til automatisk. Hvis lokasjonstjenesten trenger en nøkkel, kan den legges til som et spørringsparameter til rot-URL-en.</string>\n    <string name=\"notification_config_required_text_online_sources\">For å fortsette å bruke nettbaserte stedstjenester, må du velge en lokasjonsdatatjeneste.</string>\n    <string name=\"location_data_export_wifi_title\">Eksporter lokal Wi-Fi-lokasjonsdatabase</string>\n    <string name=\"location_data_export_cell_title\">Eksporter lokal mobilmast-lokasjonsdatabase</string>\n</resources>\n"
  },
  {
    "path": "play-services-location/core/src/main/res/values-nl/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"pref_location_wifi_online_enabled_title\">Verzoek van online service</string>\n    <string name=\"pref_location_cell_online_enabled_title\">Verzoek van online service</string>\n    <string name=\"pref_location_cell_online_enabled_summary\">Locaties van mobiele zendmasten van online locatieservices ophalen.</string>\n    <string name=\"pref_location_wifi_online_enabled_summary\">Wi-Fi-gebaseerde locatie ophalen van online locatiedienst.</string>\n    <string name=\"prefcat_location_apps_title\">Recente toegang</string>\n    <string name=\"pref_location_wifi_moving_enabled_title\">Verzoek van Hotspot</string>\n    <string name=\"pref_location_wifi_learning_enabled_title\">Onthouden van GPS</string>\n    <string name=\"pref_location_wifi_moving_enabled_summary\">Haal Wi-Fi-locatie direct op van ondersteunde hotspots wanneer je verbinding hebt.</string>\n    <string name=\"pref_geocoder_nominatim_enabled_title\">Gebruik Nominatim</string>\n    <string name=\"pref_location_cell_learning_enabled_summary\">Locaties van mobiele netwerken lokaal opslaan wanneer GPS wordt gebruikt.</string>\n    <string name=\"pref_geocoder_nominatim_enabled_summary\">Adressen oplossen met OpenStreetMap Nominatim.</string>\n    <string name=\"pref_location_wifi_learning_enabled_summary\">Wi-Fi-locaties lokaal opslaan wanneer GPS wordt gebruikt.</string>\n    <string name=\"pref_location_cell_learning_enabled_title\">Onthouden van GPS</string>\n    <string name=\"location_settings_dialog_message_title_for_better_experience\">Voor een betere ervaring kunt u de locatie van het apparaat inschakelen, die gebruikmaakt van de locatieservice van microG.</string>\n    <string name=\"location_settings_dialog_message_title_to_continue\">Om verder te gaan, schakel je de apparaatlocatie in. Deze maakt gebruik van de locatieservice van microG.</string>\n    <string name=\"location_settings_dialog_message_details_start_paragraph\">Uw apparaat moet aan de volgende eisen voldoen:</string>\n</resources>\n"
  },
  {
    "path": "play-services-location/core/src/main/res/values-pl/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=\"pref_location_wifi_learning_enabled_summary\">Przechowuj lokalizacje Wi-Fi podczas korzystania z GPS.</string>\n    <string name=\"location_app_last_access_at\">Ostatni dostęp: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"pref_location_cell_learning_enabled_summary\">Przechowuj lokalizacje sieci mobilnej lokalnie podczas korzystania z GPS.</string>\n    <string name=\"fragment_location_apps_title\">Aplikacje z dostępem do lokalizacji</string>\n    <string name=\"pref_location_app_force_coarse_summary\">Zawsze zwracaj przybliżoną lokalizację dla tej aplikacji, niezależnie od jej poziomu uprawnień.</string>\n    <string name=\"pref_location_cell_learning_enabled_title\">Pamiętaj z GPS</string>\n    <string name=\"pref_location_wifi_learning_enabled_title\">Pamiętaj z GPS</string>\n    <string name=\"pref_location_wifi_moving_enabled_summary\">Ustal lokalizację przez Wi-Fi bezpośrednio na podstawie wspieranych punktów dostępowych przy połączeniu.</string>\n    <string name=\"prefcat_location_cell_title\">Lokalizacja przez sieć mobilną</string>\n    <string name=\"pref_location_wifi_moving_enabled_title\">Żądaj od punktów dostępowych</string>\n    <string name=\"pref_location_app_force_coarse_title\">Wymuś przybliżoną lokalizację</string>\n    <string name=\"pref_geocoder_nominatim_enabled_title\">Używaj Nominatim</string>\n    <string name=\"service_name_location\">Lokalizacja</string>\n    <string name=\"prefcat_location_apps_title\">Ostatni dostęp</string>\n    <string name=\"pref_geocoder_nominatim_enabled_summary\">Rozwiązuj adresy używając OpenStreetMap Nominatim.</string>\n    <string name=\"prefcat_location_wifi_title\">Lokalizacja przez Wi-Fi</string>\n    <string name=\"prefcat_geocoder_title\">Rozwiązywanie adresów</string>\n    <string name=\"location_settings_dialog_message_details_end_paragraph\">Szczegółowe informacje można znaleźć w ustawieniach lokalizacji.</string>\n    <string name=\"location_settings_dialog_message_title_for_better_experience\">Aby uzyskać lepsze efekty, włącz lokalizację urządzenia, która korzysta z usługi lokalizacji microG</string>\n    <string name=\"location_settings_dialog_message_title_to_continue\">Aby kontynuować, włącz lokalizację urządzenia, która korzysta z usługi lokalizacji microG</string>\n    <string name=\"location_settings_dialog_message_details_start_paragraph\">Urządzenie będzie musiało:</string>\n    <string name=\"location_settings_dialog_message_location_services_gps_and_nlp\">Korzystać z GPS, Wi-Fi, sieci komórkowych oraz czujników</string>\n    <string name=\"location_settings_dialog_message_gls_consent\">Korzystanie z usługi lokalizacji microG. W ramach tej usługi microG może okresowo gromadzić dane o lokalizacji i wykorzystywać te dane w sposób anonimowy w celu poprawy dokładności lokalizacji i usług opartych na lokalizacji.</string>\n    <string name=\"location_settings_dialog_btn_cancel\">Nie, dziękuję</string>\n    <string name=\"location_settings_dialog_btn_sure\">OK</string>\n    <string name=\"pref_location_custom_url_details\">Ścieżka geolokalizacji /v1/ jest dołączana automatycznie. Jeśli dostawca lokalizacji wymaga klucza, można go dołączyć jako parametr zapytania do głównego adresu URL.</string>\n    <string name=\"pref_location_custom_url_input_hint\">Własna usługa URL</string>\n    <string name=\"pref_location_custom_url_summary\">Umożliwia to ustawienie własnej usługi URL. Nieprawidłowe wartości mogą spowodować, że usługi lokalizacji nie będą odpowiadać lub będą całkowicie niedostępne.</string>\n    <string name=\"location_settings_dialog_message_grant_permissions\">Udziel uprawnień do lokalizacji usłudze microG</string>\n    <string name=\"pref_location_cell_online_enabled_title\">Korzystaj z usług online</string>\n    <string name=\"pref_location_wifi_online_enabled_title\">Korzystaj z usług online</string>\n    <string name=\"pref_location_source_terms\">Regulamin / Prywatność</string>\n    <string name=\"notification_config_required_title\">Wymagana konfiguracja</string>\n    <string name=\"notification_config_required_text_online_sources\">Aby kontynuować korzystanie z usług lokalizacji online, należy wybrać usługę danych lokalizacji.</string>\n    <string name=\"location_data_export_wifi_title\">Eksportuj lokalną bazę danych lokalizacji Wi-Fi</string>\n    <string name=\"location_data_export_cell_title\">Eksportuj lokalną bazę danych lokalizacji wież komórkowych</string>\n    <string name=\"location_data_import_title\">Importuj dane lokalizacji z pliku</string>\n    <string name=\"pref_location_cell_online_enabled_summary\">Pobieraj lokalizację poprzez sieć komórkową z usług lokalizacji online.</string>\n    <string name=\"pref_location_source_title\">Wybierz usługę lokalizacji online</string>\n    <string name=\"pref_location_source_suggested\">Sugerowane</string>\n    <string name=\"pref_location_import_export_title\">Importuj lub eksportuj dane lokalizacji</string>\n    <string name=\"location_data_import_result_toast\">Ilość zaimportowanych wpisów: %1$d.</string>\n    <string name=\"pref_location_wifi_online_enabled_summary\">Pobieraj lokalizację poprzez Wi-Fi z usług lokalizacji sieciowej.</string>\n    <string name=\"pref_location_custom_source_title\">Własne</string>\n    <string name=\"prefcat_app_last_location\">Ostatnio zgłoszona lokalizacja</string>\n</resources>\n"
  },
  {
    "path": "play-services-location/core/src/main/res/values-pt/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_name_location\">Localização</string>\n    <string name=\"prefcat_location_apps_title\">Acesso recente</string>\n    <string name=\"prefcat_location_wifi_title\">Localização por Wi-Fi</string>\n    <string name=\"prefcat_location_cell_title\">Localização por redes móveis</string>\n    <string name=\"prefcat_geocoder_title\">Tradutor de endereço</string>\n    <string name=\"pref_location_wifi_online_enabled_title\">Solicitar do serviço online</string>\n    <string name=\"pref_location_wifi_online_enabled_summary\">Buscar localização por Wi-Fi por meio de um serviço online.</string>\n    <string name=\"pref_location_wifi_moving_enabled_title\">Solicitar do ponto de acesso</string>\n    <string name=\"pref_location_wifi_moving_enabled_summary\">Buscar localização por Wi-Fi diretamente do ponto de acesso conectado, se suportado.</string>\n    <string name=\"pref_location_wifi_learning_enabled_title\">Lembrar do GPS</string>\n    <string name=\"pref_location_wifi_learning_enabled_summary\">Armazenar dados de localização de redes Wi-Fi localmente no uso do GPS.</string>\n    <string name=\"pref_location_cell_online_enabled_title\">Solicitar do serviço online</string>\n    <string name=\"pref_location_cell_online_enabled_summary\">Buscar localização por redes móveis por meio de um serviço online.</string>\n    <string name=\"pref_location_cell_learning_enabled_title\">Lembrar do GPS</string>\n    <string name=\"pref_location_cell_learning_enabled_summary\">Armazenar dados de localização de redes móveis localmente no uso do GPS.</string>\n    <string name=\"pref_geocoder_nominatim_enabled_title\">Usar Nominatim</string>\n    <string name=\"pref_geocoder_nominatim_enabled_summary\">Traduzir endereços usando o Nominatim do OpenStreetMap.</string>\n    <string name=\"fragment_location_apps_title\">Apps com acesso à localização</string>\n    <string name=\"location_app_last_access_at\">Último acesso: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"pref_location_app_force_coarse_title\">Forçar localização geral</string>\n    <string name=\"pref_location_app_force_coarse_summary\">Sempre responder com localizações gerais para esta app, ignorando o seu nível de permissão.</string>\n    <string name=\"prefcat_app_last_location\">Última localização relatada</string>\n    <string name=\"location_settings_dialog_message_title_for_better_experience\">Para uma experiência melhor, ative a localização do dispositivo, que utiliza o serviço de localização do microG</string>\n    <string name=\"location_settings_dialog_message_title_to_continue\">Para continuar, ative a localização do dispositivo, que utiliza o serviço de localização do microG</string>\n    <string name=\"location_settings_dialog_message_details_start_paragraph\">O seu dispositivo precisa:</string>\n    <string name=\"location_settings_dialog_message_location_services_gps_and_nlp\">Usar GPS, Wi-Fi, redes móveis e sensores</string>\n    <string name=\"location_settings_dialog_message_grant_permissions\">Permitir permissões de localização aos Serviços microG</string>\n    <string name=\"location_settings_dialog_message_gls_consent\">Utilizar o serviço de localização do microG; como parte deste serviço, o microG poderá coletar dados de localização periodicamente e utilizar estes dados de forma anônima para melhorar a precisão da localização e serviços baseados na localização.</string>\n    <string name=\"location_settings_dialog_message_details_end_paragraph\">Para mais pormenores, veja as configurações de localização.</string>\n    <string name=\"location_settings_dialog_btn_cancel\">Não, obrigado</string>\n    <string name=\"location_settings_dialog_btn_sure\">OK</string>\n    <string name=\"pref_location_custom_url_summary\">Isto permite que configure uma URL para um serviço customizado. Valores inválidos podem resultar nos serviços de localização ficando sem resposta ou completamente indisponíveis.</string>\n    <string name=\"pref_location_custom_url_details\">O caminho \\\"/v1/geolocate\\\" é anexado automaticamente. Se o provedor de localização requer o uso de uma chave, ela pode ser anexada como um parâmetro de consulta na URL raiz.</string>\n    <string name=\"pref_location_custom_url_input_hint\">URL do serviço customizado</string>\n    <string name=\"pref_location_custom_source_title\">Customizado</string>\n    <string name=\"pref_location_source_title\">Escolher serviço online</string>\n    <string name=\"pref_location_source_terms\">Termos / Privacidade</string>\n    <string name=\"pref_location_source_suggested\">Sugerido</string>\n    <string name=\"pref_location_import_export_title\">Importar/exportar dados de local</string>\n    <string name=\"notification_config_required_title\">Configuração necessária</string>\n    <string name=\"notification_config_required_text_online_sources\">Para continuar usando os serviços de localização online, precisa selecionar um serviço de dados de localização.</string>\n    <string name=\"location_data_export_wifi_title\">Exportar base de dados local de localização por Wi-Fi</string>\n    <string name=\"location_data_export_cell_title\">Exportar base de dados local de localização por redes móveis</string>\n    <string name=\"location_data_import_title\">Importar dados de localização por ficheiro</string>\n    <string name=\"location_data_import_result_toast\">%1$d relatórios importados.</string>\n</resources>\n"
  },
  {
    "path": "play-services-location/core/src/main/res/values-pt-rBR/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_name_location\">Localização</string>\n    <string name=\"prefcat_location_apps_title\">Acesso recente</string>\n    <string name=\"prefcat_location_wifi_title\">Localização por Wi-Fi</string>\n    <string name=\"prefcat_location_cell_title\">Localização por redes móveis</string>\n    <string name=\"prefcat_geocoder_title\">Tradutor de endereço</string>\n    <string name=\"pref_location_wifi_moving_enabled_title\">Solicitar do ponto de acesso</string>\n    <string name=\"pref_location_wifi_moving_enabled_summary\">Buscar localização por Wi-Fi diretamente do ponto de acesso conectado, se suportado.</string>\n    <string name=\"pref_location_wifi_learning_enabled_title\">Lembrar do GPS</string>\n    <string name=\"pref_location_wifi_learning_enabled_summary\">Armazenar dados de localização de redes Wi-Fi localmente no uso do GPS.</string>\n    <string name=\"pref_location_cell_learning_enabled_title\">Lembrar do GPS</string>\n    <string name=\"pref_location_cell_learning_enabled_summary\">Armazenar dados de localização de redes móveis localmente no uso do GPS.</string>\n    <string name=\"pref_geocoder_nominatim_enabled_title\">Usar Nominatim</string>\n    <string name=\"pref_geocoder_nominatim_enabled_summary\">Traduzir endereços usando o Nominatim do OpenStreetMap.</string>\n    <string name=\"fragment_location_apps_title\">Apps com acesso à localização</string>\n    <string name=\"location_app_last_access_at\">Último acesso: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"pref_location_app_force_coarse_title\">Forçar localização geral</string>\n    <string name=\"pref_location_app_force_coarse_summary\">Sempre responder com localizações gerais para este app, ignorando seu nível de permissão.</string>\n    <string name=\"location_settings_dialog_message_gls_consent\">Utilizar o serviço de localização do microG; como parte deste serviço, o microG poderá coletar dados de localização periodicamente e utilizar estes dados de forma anônima para melhorar a precisão da localização e serviços baseados na localização.</string>\n    <string name=\"location_settings_dialog_btn_cancel\">Não, obrigado</string>\n    <string name=\"location_settings_dialog_message_title_to_continue\">Para continuar, ative a localização do dispositivo, que utiliza o serviço de localização do microG</string>\n    <string name=\"location_settings_dialog_message_details_start_paragraph\">Seu dispositivo precisa:</string>\n    <string name=\"location_settings_dialog_message_location_services_gps_and_nlp\">Usar GPS, Wi-Fi, redes móveis, e sensores</string>\n    <string name=\"location_settings_dialog_message_details_end_paragraph\">Para mais detalhes, veja as configurações de localização.</string>\n    <string name=\"location_settings_dialog_btn_sure\">OK</string>\n    <string name=\"location_settings_dialog_message_title_for_better_experience\">Para uma experiência melhor, ative a localização do dispositivo, que utiliza o serviço de localização do microG</string>\n    <string name=\"pref_location_custom_url_input_hint\">URL do serviço customizado</string>\n    <string name=\"pref_location_custom_url_summary\">Isto permite que você configure uma URL para um serviço customizado. Valores inválidos podem resultar nos serviços de localização ficando sem resposta ou completamente indisponíveis.</string>\n    <string name=\"pref_location_custom_url_details\">O caminho \\\"/v1/geolocate\\\" é anexado automaticamente. Se o provedor de localização requer o uso de uma chave, ela pode ser anexada como um parâmetro de consulta na URL raiz.</string>\n    <string name=\"location_settings_dialog_message_grant_permissions\">Permitir permissões de localização aos Serviços microG</string>\n    <string name=\"pref_location_wifi_online_enabled_title\">Solicitar do serviço online</string>\n    <string name=\"pref_location_cell_online_enabled_title\">Solicitar do serviço online</string>\n    <string name=\"pref_location_cell_online_enabled_summary\">Buscar localização por redes móveis por meio de um serviço online.</string>\n    <string name=\"pref_location_custom_source_title\">Customizado</string>\n    <string name=\"pref_location_source_title\">Escolher serviço online</string>\n    <string name=\"pref_location_source_terms\">Termos / Privacidade</string>\n    <string name=\"notification_config_required_title\">Configuração necessária</string>\n    <string name=\"location_data_export_wifi_title\">Exportar banco de dados local de localização por Wi-Fi</string>\n    <string name=\"location_data_export_cell_title\">Exportar banco de dados local de localização por redes móveis</string>\n    <string name=\"location_data_import_title\">Importar dados de localização por arquivo</string>\n    <string name=\"pref_location_wifi_online_enabled_summary\">Buscar localização por Wi-Fi por meio de um serviço online.</string>\n    <string name=\"pref_location_source_suggested\">Sugerido</string>\n    <string name=\"pref_location_import_export_title\">Importar/exportar dados de local.</string>\n    <string name=\"notification_config_required_text_online_sources\">Para continuar usando os serviços de localização online, você precisa selecionar um serviço de dados de localização.</string>\n    <string name=\"location_data_import_result_toast\">%1$d relatórios importados.</string>\n    <string name=\"prefcat_app_last_location\">Última localização relatada</string>\n</resources>\n"
  },
  {
    "path": "play-services-location/core/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=\"pref_location_wifi_learning_enabled_summary\">Stochează locațiile Wi-Fi local când este utilizat GPS-ul.</string>\n    <string name=\"location_app_last_access_at\">Ultima accesare: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"pref_location_cell_learning_enabled_summary\">Stochează local locațiile rețelei mobile atunci când este utilizat GPS-ul.</string>\n    <string name=\"fragment_location_apps_title\">Aplicații cu acces la locație</string>\n    <string name=\"pref_location_app_force_coarse_summary\">Returnează întotdeauna locații aproximative acestei aplicații, ignorând nivelul de permisiune.</string>\n    <string name=\"pref_location_cell_learning_enabled_title\">Memorizează de la GPS</string>\n    <string name=\"pref_location_wifi_learning_enabled_title\">Memorizează de la GPS</string>\n    <string name=\"pref_location_wifi_moving_enabled_summary\">Preia locația Wi-Fi direct din hotspot-urile acceptate atunci când ești conectat.</string>\n    <string name=\"prefcat_location_cell_title\">Localizare prin rețelele mobile</string>\n    <string name=\"pref_location_wifi_moving_enabled_title\">Solicită de la Hotspot</string>\n    <string name=\"pref_location_app_force_coarse_title\">Forțează locația aproximativă</string>\n    <string name=\"pref_geocoder_nominatim_enabled_title\">Utilizează Nominatim</string>\n    <string name=\"service_name_location\">Localizare</string>\n    <string name=\"prefcat_location_apps_title\">Accesată recent</string>\n    <string name=\"pref_geocoder_nominatim_enabled_summary\">Preia adresele folosind OpenStreetMap Nominatim.</string>\n    <string name=\"prefcat_location_wifi_title\">Localizare Wi-Fi</string>\n    <string name=\"prefcat_geocoder_title\">Căutare adrese</string>\n    <string name=\"location_settings_dialog_message_title_to_continue\">Pentru a continua, activează locația dispozitivului, care utilizează serviciul de localizare microG</string>\n    <string name=\"location_settings_dialog_message_location_services_gps_and_nlp\">Folosească receptorul GPS, Wi-Fi, rețelele celulare și senzorii</string>\n    <string name=\"location_settings_dialog_message_details_end_paragraph\">Pentru detalii, accesează setările locației.</string>\n    <string name=\"location_settings_dialog_btn_sure\">Bine</string>\n    <string name=\"location_settings_dialog_message_details_start_paragraph\">Dispozitivul va trebui să:</string>\n    <string name=\"location_settings_dialog_message_gls_consent\">Utilizează serviciul de localizare microG; ca parte a acestui serviciu, microG poate colecta periodic date despre locație și poate utiliza aceste date într-un mod anonim pentru a îmbunătăți acuratețea locației și serviciile bazate pe locație.</string>\n    <string name=\"location_settings_dialog_btn_cancel\">Nu, mulțumesc</string>\n    <string name=\"location_settings_dialog_message_title_for_better_experience\">Pentru o experiență mai bună, activează locația dispozitivului, care utilizează serviciul de localizare microG</string>\n    <string name=\"pref_location_custom_url_summary\">Aceasta permite setarea unei adrese URL de serviciu personalizată. Valorile nevalide pot face ca serviciile de localizare să nu răspundă sau să fie complet indisponibile.</string>\n    <string name=\"pref_location_custom_url_details\">Calea /v1/geolocate este atașată automat. Dacă furnizorul de locație necesită o cheie, aceasta poate fi atașată ca parametru de interogare la adresa URL rădăcină.</string>\n    <string name=\"pref_location_custom_url_input_hint\">Adresa URL personalizată a serviciului</string>\n    <string name=\"location_settings_dialog_message_grant_permissions\">Acordă permisiunile de localizare pentru serviciile microG</string>\n    <string name=\"pref_location_wifi_online_enabled_title\">Solicitare de la serviciul online</string>\n    <string name=\"pref_location_cell_online_enabled_title\">Solicitare de la serviciul online</string>\n    <string name=\"pref_location_cell_online_enabled_summary\">Se determină locația pe baza bazelor de date ale turnurilor rețelelor celulare ale unui serviciu de localizare online.</string>\n    <string name=\"pref_location_import_export_title\">Import sau export date locație</string>\n    <string name=\"notification_config_required_title\">Configurație necesară</string>\n    <string name=\"pref_location_wifi_online_enabled_summary\">Se determină locația pe baza bazelor de date Wi-Fi ale unui serviciu de localizare online.</string>\n    <string name=\"pref_location_custom_source_title\">Personalizat</string>\n    <string name=\"pref_location_source_title\">Selectează serviciul de localizare online</string>\n    <string name=\"pref_location_source_terms\">Termeni / Confidențialitate</string>\n    <string name=\"pref_location_source_suggested\">Sugerat</string>\n    <string name=\"notification_config_required_text_online_sources\">Pentru a continua să utilizezi serviciile de localizare online, trebuie să selectezi un serviciu de date despre locație.</string>\n    <string name=\"location_data_export_wifi_title\">Exportă baza de date locală cu locații Wi-Fi</string>\n    <string name=\"location_data_export_cell_title\">Exportă baza de date locală a locațiilor turnurilor rețelelor celulare</string>\n    <string name=\"location_data_import_title\">Importă datele despre locație dintr-un fișier</string>\n    <string name=\"location_data_import_result_toast\">S-au importat %1$d înregistrări.</string>\n    <string name=\"prefcat_app_last_location\">Ultima locație raportată</string>\n</resources>\n"
  },
  {
    "path": "play-services-location/core/src/main/res/values-ru/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=\"location_app_last_access_at\">Последний доступ: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"pref_location_app_force_coarse_summary\">Всегда давать приложению примерное местоположение, игнорируя его уровень разрешений.</string>\n    <string name=\"service_name_location\">Местоположение</string>\n    <string name=\"prefcat_location_apps_title\">Недавние запросы</string>\n    <string name=\"prefcat_location_wifi_title\">Местоположение по Wi-Fi</string>\n    <string name=\"prefcat_geocoder_title\">Обработчик адреса</string>\n    <string name=\"pref_location_wifi_moving_enabled_title\">Опрашивать точки Hotspot</string>\n    <string name=\"pref_location_wifi_moving_enabled_summary\">Получать местоположение напрямую от поддерживаемых Wi-Fi точек (Hotspot).</string>\n    <string name=\"pref_location_wifi_learning_enabled_title\">Запоминать координаты GPS</string>\n    <string name=\"pref_location_wifi_learning_enabled_summary\">Запоминать расположение точек Wi-Fi основываясь на данных GPS.</string>\n    <string name=\"pref_location_cell_learning_enabled_summary\">Сохранять расположение вышек сотовой связи во время работы GPS.</string>\n    <string name=\"pref_geocoder_nominatim_enabled_title\">Использовать Nominatim</string>\n    <string name=\"pref_geocoder_nominatim_enabled_summary\">Определять адреса используя сервис OpenStreetMap Nominatim.</string>\n    <string name=\"fragment_location_apps_title\">Приложения с доступом к местоположению</string>\n    <string name=\"pref_location_app_force_coarse_title\">Принудительно использовать примерное местоположение</string>\n    <string name=\"pref_location_cell_learning_enabled_title\">Запоминать координаты GPS</string>\n    <string name=\"prefcat_location_cell_title\">Местоположения по мобильной сети</string>\n    <string name=\"location_settings_dialog_message_details_start_paragraph\">Вашему устройству требуется:</string>\n    <string name=\"location_settings_dialog_message_details_end_paragraph\">Для получения подробной информации перейдите в настройки местоположения.</string>\n    <string name=\"location_settings_dialog_btn_sure\">ОК</string>\n    <string name=\"location_settings_dialog_message_title_to_continue\">Чтобы продолжить, включите определение местоположения устройства с помощью службы определения местоположения microG</string>\n    <string name=\"location_settings_dialog_message_location_services_gps_and_nlp\">Использование GPS, Wi-Fi, сотовых сетей и датчиков</string>\n    <string name=\"location_settings_dialog_message_gls_consent\">Использование службы определения местоположения; в рамках работы этой службы microG может периодически анонимно собирать и использовать данные о местоположении для повышения точности определения местоположения и услуг на основе местоположения.</string>\n    <string name=\"location_settings_dialog_btn_cancel\">Нет, спасибо</string>\n    <string name=\"location_settings_dialog_message_title_for_better_experience\">Для улучшения результатов, включите определение местоположения, которое использует службу определения местоположения microG</string>\n    <string name=\"pref_location_custom_url_summary\">Этот параметр позволяет настроить URL-адрес службы. Неверные значения могут привести к тому, что службы определения местоположения перестанут отвечать на запросы или будут полностью недоступны.</string>\n    <string name=\"pref_location_custom_url_details\">Путь /v1/geocate будет добавлен автоматически. Если провайдеру местоположения требуется ключ, его можно добавить к корневому URL-адресу в качестве параметра запроса.</string>\n    <string name=\"pref_location_custom_url_input_hint\">Пользовательский адрес службы</string>\n    <string name=\"location_settings_dialog_message_grant_permissions\">Разрешить сервисам microG доступ к местоположению</string>\n    <string name=\"pref_location_wifi_online_enabled_title\">Опрашивать онлайн сервис</string>\n    <string name=\"pref_location_cell_online_enabled_title\">Опрашивать онлайн сервис</string>\n    <string name=\"pref_location_cell_online_enabled_summary\">Определять местоположение основываясь на базах сотовых вышек онлайн-сервиса определения местоположения.</string>\n    <string name=\"pref_location_wifi_online_enabled_summary\">Определять местоположение основываясь на базах Wi-Fi онлайн-сервиса определения местоположения.</string>\n    <string name=\"pref_location_custom_source_title\">Пользовательский</string>\n    <string name=\"pref_location_source_terms\">Условия / Конфиденциальность</string>\n    <string name=\"pref_location_import_export_title\">Импорт или экспорт данных о местоположении</string>\n    <string name=\"pref_location_source_title\">Выберите онлайн-службу определения местоположения</string>\n    <string name=\"pref_location_source_suggested\">Рекомендованный</string>\n    <string name=\"notification_config_required_title\">Требуется настройка</string>\n    <string name=\"location_data_export_wifi_title\">Экспортировать локальную базу местоположений Wi-Fi</string>\n    <string name=\"location_data_export_cell_title\">Экспортировать локальную базу местоположений сотовых вышек</string>\n    <string name=\"location_data_import_result_toast\">Импортировано %1$d записей.</string>\n    <string name=\"notification_config_required_text_online_sources\">Чтобы продолжить использование онлайн-сервисов определения местоположения, вам необходимо выбрать сервис определения местоположения.</string>\n    <string name=\"location_data_import_title\">Импорт данных о местоположении из файла</string>\n    <string name=\"prefcat_app_last_location\">Последнее сообщенное местоположение</string>\n</resources>\n"
  },
  {
    "path": "play-services-location/core/src/main/res/values-sl/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n</resources>"
  },
  {
    "path": "play-services-location/core/src/main/res/values-sr/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=\"pref_location_wifi_learning_enabled_summary\">Локално чувајте Wi-Fi локације када се користи GPS.</string>\n    <string name=\"location_app_last_access_at\">Последњи приступ: <xliff:g example=\"Yesterday, 02:20 PM\"> %1$s</xliff:g></string>\n    <string name=\"pref_location_cell_learning_enabled_summary\">Локално чувајте локације мобилне мреже када се користи GPS.</string>\n    <string name=\"fragment_location_apps_title\">Апликације са приступом локацији</string>\n    <string name=\"pref_location_app_force_coarse_summary\">Увек враћајте грубе локације овој апликацији, игноришући њен ниво дозволе.</string>\n    <string name=\"pref_location_cell_learning_enabled_title\">Запамти из GPS-а</string>\n    <string name=\"pref_location_wifi_learning_enabled_title\">Запамти из GPS-а</string>\n    <string name=\"pref_location_wifi_moving_enabled_summary\">Добавите Wi-Fi локацију директно са подржаних приступних тачака када сте повезани.</string>\n    <string name=\"prefcat_location_cell_title\">Локација мобилне мреже</string>\n    <string name=\"pref_location_wifi_moving_enabled_title\">Захтевај из Hotspot-а</string>\n    <string name=\"pref_location_app_force_coarse_title\">Присили грубу локацију</string>\n    <string name=\"pref_geocoder_nominatim_enabled_title\">Користи Nominatim</string>\n    <string name=\"service_name_location\">Локација</string>\n    <string name=\"prefcat_location_apps_title\">Недавни приступ</string>\n    <string name=\"pref_geocoder_nominatim_enabled_summary\">Решите адресе користећи OpenStreetMap Nominatim.</string>\n    <string name=\"prefcat_location_wifi_title\">Wi-Fi локација</string>\n    <string name=\"prefcat_geocoder_title\">Решавач адреса</string>\n    <string name=\"location_settings_dialog_btn_cancel\">Не, хвала</string>\n    <string name=\"location_settings_dialog_btn_sure\">У реду</string>\n    <string name=\"location_settings_dialog_message_title_to_continue\">Да бисте наставили, укључите локацију уређаја који користи услугу локације microG-а</string>\n    <string name=\"location_settings_dialog_message_details_start_paragraph\">Ваш уређај мораће да:</string>\n    <string name=\"location_settings_dialog_message_gls_consent\">Користите microG услугу локације; као део ове услуге, microG може периодично прикупљати податке о локацији и користити ове податке на анониман начин да побољша тачност локације и услуге засноване на локацији.</string>\n    <string name=\"location_settings_dialog_message_location_services_gps_and_nlp\">Користите GPS, Wi-Fi, мобилне податке и сензоре</string>\n    <string name=\"location_settings_dialog_message_details_end_paragraph\">За детаље, идите на подешавања локације.</string>\n    <string name=\"location_settings_dialog_message_title_for_better_experience\">За боље искуство, укључите локацију уређаја који користи услугу локације microG-а</string>\n    <string name=\"pref_location_custom_url_summary\">Ово омогућава постављање прилагођеног URL-а услуге. Неважеће вредности могу довести до тога да услуге локације не реагују или буду потпуно недоступне.</string>\n    <string name=\"pref_location_custom_url_details\">Путања /v1/geolocate се аутоматски додаје. Ако пружалац локације захтева кључ, он се може додати као параметар упита основном URL-у.</string>\n    <string name=\"pref_location_custom_url_input_hint\">Прилагођен URL услуге</string>\n    <string name=\"location_settings_dialog_message_grant_permissions\">Дајте дозволе за локацију microG услузи</string>\n    <string name=\"pref_location_wifi_online_enabled_title\">Захтевај од онлајн услуге</string>\n    <string name=\"pref_location_custom_source_title\">Прилагођено</string>\n    <string name=\"pref_location_source_suggested\">Предложено</string>\n    <string name=\"notification_config_required_text_online_sources\">Да бисте наставили да користите онлајн услуге локације, потребно је да изаберете услугу података о локацији.</string>\n    <string name=\"location_data_export_wifi_title\">Извоз локалне базе података Wi-Fi локације</string>\n    <string name=\"location_data_export_cell_title\">Извоз локалне базе података локације базних торњева</string>\n    <string name=\"location_data_import_title\">Увоз података о локацији из фајла</string>\n    <string name=\"location_data_import_result_toast\">Увезено %1$d записа.</string>\n    <string name=\"pref_location_wifi_online_enabled_summary\">Добијте локацију засновану на Wi-Fi-ју од онлајн услуге локације.</string>\n    <string name=\"pref_location_cell_online_enabled_title\">Захтевај од онлајн услуге</string>\n    <string name=\"pref_location_cell_online_enabled_summary\">Добијте локације торњева мобилне мреже од онлајн услуге локације.</string>\n    <string name=\"pref_location_source_title\">Избор онлајн услуге локације</string>\n    <string name=\"pref_location_source_terms\">Услови / Приватност</string>\n    <string name=\"pref_location_import_export_title\">Увоз или извоз података о локацији</string>\n    <string name=\"notification_config_required_title\">Потребно је подешавање</string>\n    <string name=\"prefcat_app_last_location\">Последња пријављена локација</string>\n</resources>\n"
  },
  {
    "path": "play-services-location/core/src/main/res/values-sv/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=\"pref_location_wifi_learning_enabled_summary\">Lagra Wi-Fi-platser lokalt när GPS används.</string>\n    <string name=\"location_app_last_access_at\">Senaste åtkomst: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"pref_location_cell_learning_enabled_summary\">Lagra mobilnätverksplatser lokalt när GPS används.</string>\n    <string name=\"fragment_location_apps_title\">Appar med platsåtkomst</string>\n    <string name=\"pref_location_app_force_coarse_summary\">Returnera alltid grov platsprecition till denna app, utan att ta hänsyn till dess behörighetsnivå.</string>\n    <string name=\"pref_location_cell_learning_enabled_title\">Komihåg från GPS</string>\n    <string name=\"pref_location_wifi_learning_enabled_title\">Komihåg från GPS</string>\n    <string name=\"pref_location_wifi_moving_enabled_summary\">Hämta Wi-Fi-plats direkt från de anslutningspunkter som stöds, när du är ansluten.</string>\n    <string name=\"prefcat_location_cell_title\">Mobilnätverksplats</string>\n    <string name=\"pref_location_wifi_moving_enabled_title\">Begär av anslutningspunkt</string>\n    <string name=\"pref_location_app_force_coarse_title\">Framtvinga grov placering</string>\n    <string name=\"pref_geocoder_nominatim_enabled_title\">Använd Nominatim</string>\n    <string name=\"service_name_location\">Plats</string>\n    <string name=\"prefcat_location_apps_title\">Senaste åtkomst</string>\n    <string name=\"pref_geocoder_nominatim_enabled_summary\">Lös ut adresser med hjälp av OpenStreetMap Nominatim.</string>\n    <string name=\"prefcat_location_wifi_title\">Wi-Fi-plats</string>\n    <string name=\"prefcat_geocoder_title\">Adresslösare</string>\n    <string name=\"location_settings_dialog_message_title_to_continue\">För att fortsätta, slå på enhetens platstjänst, som använder mikroG:s platsservice</string>\n    <string name=\"location_settings_dialog_message_details_start_paragraph\">Din enhet behöver:</string>\n    <string name=\"location_settings_dialog_message_location_services_gps_and_nlp\">Använda GPS, Wi-Fi, mobilnät och sensorer</string>\n    <string name=\"location_settings_dialog_btn_sure\">OK</string>\n    <string name=\"location_settings_dialog_message_gls_consent\">Använd microG:s platstjänst. Som en del av denna tjänst kan mikroG samla in platsdata regelbundet och använda dessa data på ett anonymt sätt för att förbättra platsens noggrannhet och platsbaserade tjänster.</string>\n    <string name=\"location_settings_dialog_message_details_end_paragraph\">Gå till platsinställningarna för detaljerad info.</string>\n    <string name=\"location_settings_dialog_btn_cancel\">Nej tack!</string>\n    <string name=\"location_settings_dialog_message_title_for_better_experience\">För en bättre upplevelse, slå på enhetens platstjänst, som använder mikroG:s platsservice</string>\n    <string name=\"location_settings_dialog_message_grant_permissions\">Tilldela platsbehörighet för microG Service</string>\n    <string name=\"pref_location_custom_url_details\">Sökvägen /v1/geolocate läggs till automatiskt. Om leverantören av platsinformation kräver en nyckel, kan den läggas till som en frågeparameter i rot-URL:en.</string>\n    <string name=\"pref_location_custom_url_summary\">På detta sätt kan du ange en anpassad tjänst-URL. Ogiltiga värden kan leda till att platstjänster inte svarar eller är helt otillgängliga.</string>\n    <string name=\"pref_location_custom_url_input_hint\">Anpassad service-URL</string>\n    <string name=\"pref_location_cell_online_enabled_title\">Förfrågan från online-tjänst</string>\n    <string name=\"pref_location_wifi_online_enabled_title\">Förfrågan från online-tjänst</string>\n    <string name=\"pref_location_wifi_online_enabled_summary\">Hämta Wi-Fi-baserad plats från platstjänst online.</string>\n    <string name=\"pref_location_cell_online_enabled_summary\">Hämta mobila nätverks mastplatser från platstjänster online.</string>\n    <string name=\"pref_location_custom_source_title\">Anpassat</string>\n    <string name=\"pref_location_source_title\">Välj platstjänst online</string>\n    <string name=\"pref_location_source_terms\">Villkor / Integritet</string>\n    <string name=\"notification_config_required_title\">Konfiguration krävs</string>\n    <string name=\"notification_config_required_text_online_sources\">För att fortsätta använda platstjänster online måste du välja en platsdatatjänst.</string>\n    <string name=\"location_data_export_wifi_title\">Exportera lokal Wi-Fi-platsdatabas</string>\n    <string name=\"location_data_export_cell_title\">Exportera lokal platsdatabas för mobilmaster</string>\n    <string name=\"location_data_import_title\">Importera platsdata från fil</string>\n    <string name=\"location_data_import_result_toast\">Importerade %1$d poster.</string>\n    <string name=\"pref_location_source_suggested\">Föreslagen</string>\n    <string name=\"pref_location_import_export_title\">Importera eller exportera platsdata</string>\n    <string name=\"prefcat_app_last_location\">Senast rapporterad plats</string>\n</resources>\n"
  },
  {
    "path": "play-services-location/core/src/main/res/values-ta/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_name_location\">இடம்</string>\n    <string name=\"prefcat_location_apps_title\">அண்மைக் கால அணுகல்</string>\n    <string name=\"prefcat_location_wifi_title\">வைஃபை இடம்</string>\n    <string name=\"prefcat_location_cell_title\">மொபைல் பிணையம் இருப்பிடம்</string>\n    <string name=\"prefcat_geocoder_title\">முகவரி தீர்வி</string>\n    <string name=\"pref_location_wifi_online_enabled_title\">நிகழ்நிலை சேவையிலிருந்து கோரிக்கை</string>\n    <string name=\"pref_location_wifi_moving_enabled_title\">ஆட்ச்பாட்டிலிருந்து கோரிக்கை</string>\n    <string name=\"pref_location_wifi_moving_enabled_summary\">இணைக்கும்போது ஆதரிக்கப்பட்ட ஆட்ச்பாட்களிலிருந்து நேரடியாக வைஃபை இருப்பிடத்தைப் பெறுங்கள்.</string>\n    <string name=\"pref_location_cell_learning_enabled_summary\">சி.பி.எச் பயன்படுத்தப்படும்போது மொபைல் பிணையம் இருப்பிடங்களை உள்நாட்டில் சேமிக்கவும்.</string>\n    <string name=\"pref_geocoder_nominatim_enabled_title\">குறிப்பாக பயன்படுத்தவும்</string>\n    <string name=\"pref_geocoder_nominatim_enabled_summary\">OpenStreetMap Nominatim ஐப் பயன்படுத்தி முகவரிகளைத் தீர்க்கவும்.</string>\n    <string name=\"fragment_location_apps_title\">இருப்பிட அணுகலுடன் பயன்பாடுகள்</string>\n    <string name=\"pref_location_app_force_coarse_summary\">இந்த பயன்பாட்டிற்கு எப்போதும் கரடுமுரடான இடங்களைத் திருப்பி, அதன் இசைவு மட்டத்தை புறக்கணித்து.</string>\n    <string name=\"location_settings_dialog_message_title_for_better_experience\">சிறந்த அனுபவத்திற்கு, மைக்ரோசின் இருப்பிட சேவையைப் பயன்படுத்தும் சாதன இருப்பிடத்தை இயக்கவும்</string>\n    <string name=\"location_settings_dialog_message_title_to_continue\">தொடர, மைக்ரோசின் இருப்பிட சேவையைப் பயன்படுத்தும் சாதன இருப்பிடத்தை இயக்கவும்</string>\n    <string name=\"location_settings_dialog_message_details_start_paragraph\">உங்கள் சாதனம் தேவைப்படும்:</string>\n    <string name=\"location_settings_dialog_message_location_services_gps_and_nlp\">சி.பி.எச், வை - ஃபி, செல் நெட்வொர்க்குகள் மற்றும் சென்சார்களைப் பயன்படுத்தவும்</string>\n    <string name=\"location_settings_dialog_message_grant_permissions\">மைக்ரோக் சேவைக்கு இருப்பிட அனுமதிகளை வழங்கவும்</string>\n    <string name=\"location_settings_dialog_message_details_end_paragraph\">விவரங்களுக்கு, இருப்பிட அமைப்புகளுக்குச் செல்லவும்.</string>\n    <string name=\"location_settings_dialog_btn_cancel\">நன்றி இல்லை</string>\n    <string name=\"location_settings_dialog_btn_sure\">சரி</string>\n    <string name=\"location_settings_dialog_message_gls_consent\">மைக்ரோ டிரா இருப்பிட சேவையைப் பயன்படுத்துங்கள்; இந்த சேவையின் ஒரு பகுதியாக, மைக்ரோக் இருப்பிடத் தரவை அவ்வப்போது சேகரித்து, இருப்பிட துல்லியம் மற்றும் இருப்பிட அடிப்படையிலான சேவைகளை மேம்படுத்த இந்தத் தரவை அநாமதேய வழியில் பயன்படுத்தலாம்.</string>\n    <string name=\"pref_location_custom_url_summary\">இது தனிப்பயன் பணி முகவரி ஐ அமைக்க அனுமதிக்கிறது. தவறான மதிப்புகள் இருப்பிட சேவைகள் பதிலளிக்காதவை அல்லது முற்றிலும் கிடைக்கவில்லை.</string>\n    <string name=\"pref_location_custom_url_details\">/வி 1 /சியோலோகேட் பாதை தானாகவே சேர்க்கப்படுகிறது. இருப்பிட வழங்குநருக்கு ஒரு விசை தேவைப்பட்டால், அதை ரூட் முகவரி க்கு வினவல் அளவுருவாக சேர்க்கலாம்.</string>\n    <string name=\"pref_location_custom_url_input_hint\">தனிப்பயன் பணி முகவரி</string>\n    <string name=\"pref_location_custom_source_title\">தனிப்பயன்</string>\n    <string name=\"pref_location_source_title\">நிகழ்நிலை இருப்பிட சேவையைத் தேர்ந்தெடுக்கவும்</string>\n    <string name=\"pref_location_source_terms\">விதிமுறைகள் / தனியுரிமை</string>\n    <string name=\"pref_location_source_suggested\">பரிந்துரைக்கப்பட்டது</string>\n    <string name=\"pref_location_import_export_title\">இருப்பிட தரவை இறக்குமதி செய்யுங்கள் அல்லது ஏற்றுமதி செய்க</string>\n    <string name=\"notification_config_required_title\">உள்ளமைவு தேவை</string>\n    <string name=\"notification_config_required_text_online_sources\">நிகழ்நிலை இருப்பிட சேவைகளைப் பயன்படுத்த, நீங்கள் இருப்பிட தரவு சேவையைத் தேர்ந்தெடுக்க வேண்டும்.</string>\n    <string name=\"location_data_export_wifi_title\">உள்ளக வைஃபை இருப்பிட தரவுத்தளத்தை ஏற்றுமதி செய்யுங்கள்</string>\n    <string name=\"location_data_export_cell_title\">உள்ளக செல் கோபுர இருப்பிட தரவுத்தளத்தை ஏற்றுமதி செய்யுங்கள்</string>\n    <string name=\"location_data_import_title\">கோப்பிலிருந்து இருப்பிட தரவை இறக்குமதி செய்யுங்கள்</string>\n    <string name=\"location_data_import_result_toast\">இறக்குமதி செய்யப்பட்ட %1$d பதிவுகள்.</string>\n    <string name=\"pref_location_wifi_online_enabled_summary\">நிகழ்நிலை இருப்பிட சேவையிலிருந்து வைஃபை அடிப்படையிலான இருப்பிடத்தைப் பெறுங்கள்.</string>\n    <string name=\"pref_location_wifi_learning_enabled_title\">சி.பி.எச்சிலிருந்து நினைவில் கொள்ளுங்கள்</string>\n    <string name=\"pref_location_wifi_learning_enabled_summary\">சி.பி.எச் பயன்படுத்தப்படும்போது உள்நாட்டில் வைஃபை இடங்களை சேமிக்கவும்.</string>\n    <string name=\"pref_location_cell_online_enabled_title\">நிகழ்நிலை சேவையிலிருந்து கோரிக்கை</string>\n    <string name=\"pref_location_cell_online_enabled_summary\">நிகழ்நிலை இருப்பிட சேவையிலிருந்து மொபைல் பிணையம் செல் கோபுர இருப்பிடங்களைப் பெறுங்கள்.</string>\n    <string name=\"pref_location_cell_learning_enabled_title\">சி.பி.எச்சிலிருந்து நினைவில் கொள்ளுங்கள்</string>\n    <string name=\"pref_location_app_force_coarse_title\">கரடுமுரடான இருப்பிடத்தை கட்டாயப்படுத்துங்கள்</string>\n    <string name=\"location_app_last_access_at\">கடைசி அணுகல்: &lt;xliff: g எடுத்துக்காட்டு = \\\"நேற்று, 02:20 PM\\\"&gt;%1$s &lt;/xliff: g&gt;</string>\n    <string name=\"prefcat_app_last_location\">கடைசியாக அறிவிக்கப்பட்ட இடம்</string>\n</resources>\n"
  },
  {
    "path": "play-services-location/core/src/main/res/values-th/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=\"prefcat_location_cell_title\">ตำแหน่งเครือข่ายมือถือ</string>\n    <string name=\"pref_location_wifi_online_enabled_title\">การร้องขอจากบริการออนไลน์</string>\n    <string name=\"pref_location_wifi_moving_enabled_title\">คำขอจาก Hotspot</string>\n    <string name=\"pref_location_wifi_learning_enabled_title\">จดจำจาก GPS</string>\n    <string name=\"pref_location_wifi_learning_enabled_summary\">จัดเก็บตำแหน่ง Wi-Fi ไว้ในเครื่องเมื่อใช้งาน GPS</string>\n    <string name=\"pref_location_cell_online_enabled_summary\">ดึงตำแหน่งจากเสาของเครือข่ายมือถือจากบริการระบุตำแหน่งออนไลน์</string>\n    <string name=\"pref_geocoder_nominatim_enabled_summary\">แก้ไขที่อยู่โดยใช้ พิกัดภูมิศาสตร์ ของ OpenStreetMap</string>\n    <string name=\"pref_geocoder_nominatim_enabled_title\">ใช้งานพิกัดทางภูมิศาสตร์</string>\n    <string name=\"location_app_last_access_at\">เข้าถึงล่าสุด: <xliff:g example=\"เมื่อวาน, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"pref_location_app_force_coarse_title\">ตำแหน่งคร่าวๆ</string>\n    <string name=\"pref_location_app_force_coarse_summary\">ส่งตำแหน่งคร่าวๆ ให้กับแอปนี้เสมอ โดยไม่สนใจระดับของการอนุญาต</string>\n    <string name=\"location_settings_dialog_message_location_services_gps_and_nlp\">ใช้ GPS, Wi-Fi, เครือข่ายมือถือ และเซ็นเซอร์</string>\n    <string name=\"location_settings_dialog_message_grant_permissions\">ให้สิทธิ์เข้าถึงตำแหน่งแก่บริการ microG</string>\n    <string name=\"location_settings_dialog_message_details_end_paragraph\">สำหรับรายละเอียด ให้ไปที่การตั้งค่าตำแหน่ง</string>\n    <string name=\"location_settings_dialog_btn_cancel\">ไม่ล่ะ ขอบคุณ</string>\n    <string name=\"location_settings_dialog_btn_sure\">ตกลง</string>\n    <string name=\"service_name_location\">ตำแหน่ง</string>\n    <string name=\"prefcat_location_apps_title\">การเข้าถึงล่าสุด</string>\n    <string name=\"prefcat_location_wifi_title\">ตำแหน่งของ Wi-Fi</string>\n    <string name=\"prefcat_geocoder_title\">ตัวแก้ไขที่อยู่</string>\n    <string name=\"pref_location_wifi_online_enabled_summary\">ดึงข้อมูลตำแหน่งที่ใช้ Wi-Fi จากบริการระบุตำแหน่งออนไลน์</string>\n    <string name=\"pref_location_wifi_moving_enabled_summary\">ดึงข้อมูลตำแหน่ง Wi-Fi โดยตรงจาก Hotspot ที่รองรับเมื่อเชื่อมต่อ</string>\n    <string name=\"pref_location_cell_online_enabled_title\">คำขอจากบริการออนไลน์</string>\n    <string name=\"location_settings_dialog_message_title_to_continue\">หากต้องการดำเนินการต่อ ให้เปิดตำแหน่งอุปกรณ์ซึ่งใช้บริการตำแหน่งของ microG</string>\n    <string name=\"location_settings_dialog_message_details_start_paragraph\">อุปกรณ์ของคุณจะต้อง:</string>\n    <string name=\"pref_location_cell_learning_enabled_summary\">จัดเก็บตำแหน่งเครือข่ายมือถือในเครื่องเมื่อใช้ GPS</string>\n    <string name=\"pref_location_cell_learning_enabled_title\">จดจำจาก GPS</string>\n    <string name=\"fragment_location_apps_title\">แอพที่เข้าถึงตำแหน่งได้</string>\n    <string name=\"location_settings_dialog_message_title_for_better_experience\">เพื่อประสบการณ์ที่ดีขึ้น ให้เปิดตำแหน่งอุปกรณ์ซึ่งใช้บริการตำแหน่งของ microG</string>\n    <string name=\"location_settings_dialog_message_gls_consent\">ใช้บริการระบุตำแหน่ง microG ในฐานะส่วนหนึ่งของบริการนี้ microG อาจรวบรวมข้อมูลตำแหน่งเป็นระยะ ๆ และใช้ข้อมูลนี้ในลักษณะที่ไม่ระบุชื่อเพื่อปรับปรุงความแม่นยำของตำแหน่งและบริการตามตำแหน่ง</string>\n    <string name=\"pref_location_custom_url_summary\">ช่วยให้สามารถตั้งค่า URL ที่กำหนดเองได้ URL ค่าที่ไม่ถูกต้องอาจส่งผลให้บริการระบุตำแหน่งไม่ตอบสนองหรือไม่พร้อมใช้งาน</string>\n    <string name=\"pref_location_custom_url_details\">เส้นทาง /v1/geolocate จะถูกผนวกโดยอัตโนมัติ หากผู้ให้บริการตำแหน่งต้องการคีย์ ก็สามารถผนวกเป็นพารามิเตอร์การค้นหาในจุดแรกสุดของ URL ได้</string>\n    <string name=\"pref_location_custom_url_input_hint\">URL บริการที่กำหนดเอง</string>\n    <string name=\"pref_location_custom_source_title\">กำหนดเอง</string>\n    <string name=\"pref_location_source_title\">เลือกบริการระบุตำแหน่งออนไลน์</string>\n    <string name=\"pref_location_source_terms\">เงื่อนไข/ความเป็นส่วนตัว</string>\n    <string name=\"pref_location_source_suggested\">ข้อเสนอแนะ</string>\n    <string name=\"pref_location_import_export_title\">นำเข้าหรือส่งออกข้อมูลตำแหน่งที่ตั้ง</string>\n    <string name=\"notification_config_required_title\">จำเป็นต้องมีการกำหนดค่า</string>\n    <string name=\"notification_config_required_text_online_sources\">หากต้องการใช้งานบริการระบุตำแหน่งออนไลน์ต่อไป คุณจะต้องเลือกบริการข้อมูลระบุตำแหน่ง</string>\n    <string name=\"location_data_export_wifi_title\">ส่งออกฐานข้อมูลตำแหน่ง Wi-Fi ในพื้นที่</string>\n    <string name=\"location_data_export_cell_title\">ส่งออกฐานข้อมูลตำแหน่งเสาโทรศัพท์มือถือในพื้นที่</string>\n    <string name=\"location_data_import_title\">นำเข้าข้อมูลตำแหน่งจากไฟล์</string>\n    <string name=\"location_data_import_result_toast\">นำเข้า %1$d บันทึก</string>\n    <string name=\"prefcat_app_last_location\">รายงานตำแหน่งล่าสุด</string>\n</resources>\n"
  },
  {
    "path": "play-services-location/core/src/main/res/values-tr/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_name_location\">Konum</string>\n    <string name=\"prefcat_location_wifi_title\">Wi-Fi üzerinden konum</string>\n    <string name=\"prefcat_location_cell_title\">Mobil ağ üzerinden konum</string>\n    <string name=\"prefcat_geocoder_title\">Adres çözümleyicisi</string>\n    <string name=\"pref_location_wifi_online_enabled_title\">Çevrimiçi servisten iste</string>\n    <string name=\"pref_location_wifi_learning_enabled_title\">GPS\\'ten hatırla</string>\n    <string name=\"pref_location_wifi_moving_enabled_title\">Mobil erişim noktalarından iste</string>\n    <string name=\"pref_location_wifi_learning_enabled_summary\">GPS kullanıldığında Wi-Fi konumlarını yerelde sakla.</string>\n    <string name=\"pref_location_wifi_online_enabled_summary\">Çevrimiçi servisten Wi-Fi tabanlı konumu iste.</string>\n    <string name=\"pref_location_cell_online_enabled_summary\">Çevrimiçi servisten mobil ağ istasyonlarının konumunu iste.</string>\n    <string name=\"pref_geocoder_nominatim_enabled_title\">Nominatim\\'i kullan</string>\n    <string name=\"fragment_location_apps_title\">Konum erişimine sahip uygulamalar</string>\n    <string name=\"pref_location_cell_learning_enabled_summary\">GPS kullanıldığında mobil şebeke konumlarını yerel olarak sakla.</string>\n    <string name=\"location_settings_dialog_message_details_start_paragraph\">Cihazınız şun(lar)a ihtiyaç duyuyor:</string>\n    <string name=\"pref_location_app_force_coarse_title\">Yaklaşık konum vermeye zorla</string>\n    <string name=\"pref_location_app_force_coarse_summary\">Uygulamaya verilen izinden bağımsız olarak, bu uygulamaya her zaman yaklaşık konum sağla.</string>\n    <string name=\"location_settings_dialog_message_title_for_better_experience\">Daha iyi bir deneyim için, microG\\'nin konum servislerinden yararlanan cihaz konumunu etkinleştirin</string>\n    <string name=\"location_settings_dialog_message_location_services_gps_and_nlp\">GPS, Wi-Fi, mobil ağlar ve sensörleri kullanmasına</string>\n    <string name=\"location_settings_dialog_message_details_end_paragraph\">Detaylar için, konum ayarlarına gidin.</string>\n    <string name=\"location_settings_dialog_btn_cancel\">Hayır, teşekkürler</string>\n    <string name=\"location_settings_dialog_btn_sure\">Tamam</string>\n    <string name=\"pref_location_custom_url_summary\">Bu, özel bir servis sağlayıcısı URL\\'si belirtmenize olanak tanır. Yanlış ayarlama sonucunda, konum servisleri yanıt vermeyi durdurabilir veya tamamen mevcut olmayabilir.</string>\n    <string name=\"location_settings_dialog_message_gls_consent\">microG konum servislerini kullanın; bu servisin bir parçası olarak, microG periyodik olarak konum verisi toplayabilir ve bu verileri anonim bir şekilde konum doğruluğunu iyileştirmek ve daha iyi bir konum tabanlı servis sunmak için kullanabilir.</string>\n    <string name=\"pref_location_source_terms\">Koşullar / Gizlilik</string>\n    <string name=\"pref_location_source_suggested\">Önerilen</string>\n    <string name=\"pref_location_custom_url_details\">Belirtilen URL\\'ye /v1/geolocate yolu kendiliğinden eklenecektir. Konum sağlayıcısı, eğer bir erişim anahtarına ihtiyaç duyuyor ise kök URL\\'ye sorgu parametresi olarak eklenebilir.</string>\n    <string name=\"notification_config_required_text_online_sources\">Çevrimiçi konum hizmetlerini kullanmak için öncelikle bir konum veri sağlayıcısı seçmeniz gerekiyor.</string>\n    <string name=\"location_data_export_wifi_title\">Yerel Wi-Fi konum veritabanını dışarı aktar</string>\n    <string name=\"location_data_export_cell_title\">Yerel baz istasyonu konum veritabanını dışarı aktar</string>\n    <string name=\"location_data_import_title\">Dosyadan konum verisini içeri aktar</string>\n    <string name=\"location_data_import_result_toast\">%1$d kayıt içe aktarıldı.</string>\n    <string name=\"prefcat_location_apps_title\">Son erişim</string>\n    <string name=\"pref_location_cell_online_enabled_title\">Çevrimiçi servisten iste</string>\n    <string name=\"location_app_last_access_at\">Son erişim: <xliff:g example=\"Dün, 02:20 ÖS\">%1$s</xliff:g></string>\n    <string name=\"pref_location_custom_source_title\">Özel</string>\n    <string name=\"pref_location_import_export_title\">Konum verisini içe veya dışarı aktar</string>\n    <string name=\"location_settings_dialog_message_grant_permissions\">microG Servisleri\\'ne konum izninin verilmesine</string>\n    <string name=\"pref_location_custom_url_input_hint\">Özel hizmet URL\\'si</string>\n    <string name=\"notification_config_required_title\">Ayarlama gerekiyor</string>\n    <string name=\"pref_location_source_title\">Çevrimiçi konum sağlayıcısı seç</string>\n    <string name=\"pref_geocoder_nominatim_enabled_summary\">Adresleri OpenStreetMap Nominatim hizmeti ile çöz.</string>\n    <string name=\"pref_location_cell_learning_enabled_title\">GPS\\'ten hatırla</string>\n    <string name=\"pref_location_wifi_moving_enabled_summary\">Bağlanıldığında Wi-Fi konumunu direkt olarak desteklenen mobil erişim noktalarından (hotspot) al.</string>\n    <string name=\"location_settings_dialog_message_title_to_continue\">Devam etmek için, microG\\'nin konum servislerinden yararlanan cihaz konumunu etkinleştirin</string>\n    <string name=\"prefcat_app_last_location\">Son bildirilen konum</string>\n</resources>\n"
  },
  {
    "path": "play-services-location/core/src/main/res/values-ug/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=\"pref_location_wifi_online_enabled_title\">توردىكى مۇلازىمەتتىن ئىلتىماس قىلىدۇ</string>\n    <string name=\"pref_location_wifi_online_enabled_summary\">توردىكى ئورۇن ئۇچۇرى مۇلازىمىتىدىن Wi-Fi ئاساسىدىكى ئورۇن ئۇچۇرىغا ئېرىشىدۇ.</string>\n    <string name=\"pref_location_wifi_moving_enabled_title\">قىزىق نۇقتىدىن ئىلتىماس قىلىدۇ</string>\n    <string name=\"pref_location_wifi_moving_enabled_summary\">قوللايدىغان قىزىق نۇقتىغا باغلانغاندا، قىزىق نۇقتىدىن Wi-Fi ئورۇن ئۇچۇرىغا ئېرىشىدۇ.</string>\n    <string name=\"pref_location_wifi_learning_enabled_title\">GPS تىن ئەستە تۇتىدۇ</string>\n    <string name=\"pref_location_wifi_learning_enabled_summary\">GPS ئىشلەتكەندە Wi-Fi ئورۇن ئۇچۇرىنى يەرلىكتە ساقلايدۇ.</string>\n    <string name=\"pref_location_cell_online_enabled_title\">توردىكى مۇلازىمەتتىن ئىلتىماس قىلىدۇ</string>\n    <string name=\"pref_location_cell_online_enabled_summary\">توردىكى ئورۇن ئۇچۇرى مۇلازىمىتىدىن كۆچمە تور سىگنال مۇنارىنىڭ ئورۇن ئۇچۇرىغا ئېرىشىدۇ.</string>\n    <string name=\"pref_location_cell_learning_enabled_title\">GPS تىن ئەستە تۇتىدۇ</string>\n    <string name=\"pref_location_cell_learning_enabled_summary\">GPS ئىشلەتكەندە كۆچمە تور ئورۇن ئۇچۇرىنى يەرلىكتە ساقلايدۇ.</string>\n    <string name=\"pref_geocoder_nominatim_enabled_title\">Nominatim ئىشلىتىدۇ</string>\n    <string name=\"pref_geocoder_nominatim_enabled_summary\">OpenStreetMap Nominatim مۇلازىمىتىنى ئىشلىتىپ ئادرېسنى يېشىدۇ.</string>\n    <string name=\"fragment_location_apps_title\">ئورۇن ئۇچۇرىنى زىيارەت قىلىش ئىجازىتى بار ئەپ</string>\n    <string name=\"pref_location_app_force_coarse_title\">مەجبۇرىي تەخمىنىي ئورنى</string>\n    <string name=\"pref_location_app_force_coarse_summary\">ئەپنىڭ ئورۇن ئىجازەت دەرىجىسىگە پەرۋا قىلمايدۇ، ھەمىشە تەخمىنىي ئورۇن ئۇچۇرىنى تەمىنلەيدۇ.</string>\n    <string name=\"location_settings_dialog_message_title_for_better_experience\">تېخىمۇ ياخشى ئىشلىتىش تەسىراتىغا ئېرىشىش ئۈچۈن، ئۈسكۈنىنىڭ ئورۇن ئۇچۇرىنى ئېچىپ، microG نىڭ ئورۇن ئۇچۇرى مۇلازىمىتىنى ئىشلىتىدۇ</string>\n    <string name=\"location_settings_dialog_message_title_to_continue\">داۋاملاشتۇرۇش ئۈچۈن، ئۈسكۈنىنىڭ ئورۇن ئۇچۇرىنى ئېچىپ، microG نىڭ ئورۇن ئۇچۇرى مۇلازىمىتىنى ئىشلىتىدۇ</string>\n    <string name=\"location_settings_dialog_message_details_start_paragraph\">ئۈسكۈنىڭىزنى ئېھتىياجى:</string>\n    <string name=\"location_settings_dialog_message_location_services_gps_and_nlp\">GPS، Wi‑Fi، كۆچمە تور ۋە سەزگۈچ</string>\n    <string name=\"location_settings_dialog_message_grant_permissions\">microG مۇلازىمىتىگە ئورۇن ئۇچۇرى ئىجازىتىنى بېرىدۇ</string>\n    <string name=\"location_settings_dialog_message_gls_consent\">microG ئورۇن ئۇچۇرى مۇلازىمىتىنى ئىشلىتىش: مۇلازىمەتنىڭ بىر قىسمى بولۇش سۈپىتى بىلەن، microG قەرەللىك ھالدا ئورۇن ئۇچۇرى سانلىق مەلۇماتىنى توپلىشى مۇمكىن، نامسىز ئۇسۇلدا ئىشلىتىپ، ئورۇن ئۇچۇرىدىكى دەللىكنى ئاشۇرىدۇ ھەمدە جۇغراپىيەلىك ئورۇن ئۇچۇرى مۇلازىمىتىنى ياخشىلايدۇ.</string>\n    <string name=\"pref_location_source_terms\">شەرت / شەخسىيەت</string>\n    <string name=\"pref_location_source_suggested\">تەۋسىيە قىلىنغان</string>\n    <string name=\"pref_location_import_export_title\">ئورۇن سانلىق مەلۇماتىنى ئەكىر ياكى چىقار</string>\n    <string name=\"notification_config_required_title\">زۆرۈر سەپلىمە</string>\n    <string name=\"pref_location_source_title\">توردىكى ئورۇن ئۇچۇرى مۇلازىمىتى تاللىنىدۇ</string>\n    <string name=\"notification_config_required_text_online_sources\">توردىكى ئورۇن مۇلازىمىتىنى ئىشلىتىشنى داۋاملاشتۇرۇشتا، ئورۇن ئۇچۇرى سانلىق مەلۇمات مۇلازىمىتىدىن بىرنى تاللىشىڭىز كېرەك.</string>\n    <string name=\"location_data_export_wifi_title\">يەرلىك Wi-Fi ئورۇن ئۇچۇر مۇلازىمىتى ساندانىنى چىقىرىدۇ</string>\n    <string name=\"location_data_export_cell_title\">يەرلىك كۆچمە تور مۇنارىنىڭ ئورۇن ئۇچۇرى ساندانىنى چىقىرىدۇ</string>\n    <string name=\"location_data_import_title\">ھۆججەتتىن ئورۇن ئۇچۇرى سانلىق مەلۇماتىنى ئەكىرىدۇ</string>\n    <string name=\"location_data_import_result_toast\">%1$d خاتىرىنى ئەكىردى.</string>\n    <string name=\"service_name_location\">ئورنى</string>\n    <string name=\"prefcat_location_apps_title\">يېقىنقى زىيارەت</string>\n    <string name=\"prefcat_location_wifi_title\">Wi-Fi ئورۇن ئۇچۇر مۇلازىمىتى</string>\n    <string name=\"prefcat_location_cell_title\">كۆچمە تور ئورۇن ئۇچۇرى</string>\n    <string name=\"prefcat_geocoder_title\">ئادرېس يەشكۈچ</string>\n    <string name=\"location_app_last_access_at\">ئاخىرقى زىيارەت: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"location_settings_dialog_message_details_end_paragraph\">تەپسىلاتى ئۈچۈن، ئورۇن تەڭشىكىگە يۆتكىلىڭ.</string>\n    <string name=\"location_settings_dialog_btn_cancel\">ياق، رەھمەت</string>\n    <string name=\"location_settings_dialog_btn_sure\">جەزملە</string>\n    <string name=\"pref_location_custom_url_summary\">بۇ ئىختىيارى مۇلازىمەت تور ئادرېسى تەڭشىكىگە يول قويىدۇ. ئىناۋەتسىز قىممەت ئورۇن ئۇچۇرى مۇلازىمىتىنىڭ ئىنكاسى ياكى پۈتۈنلەي ئىشلەتكىلى بولماسلىقىنى كەلتۈرۈپ چىقىرىشى مۇمكىن.</string>\n    <string name=\"pref_location_custom_url_details\">/v1/geolocate يولى ئۆزلۈكىدىن قوشۇلىدۇ. ئەگەر ئورۇن مۇلازىمىتىنى تەمىنلىگۈچى شىفىرلىق ئاچقۇچ تەلەپ قىلسا، ئۇنى سۈرۈشتۈرۈش پارامېتىرى سۈپىتىدە غول تور ئادرېسىغا قوشقىلى بولىدۇ.</string>\n    <string name=\"pref_location_custom_url_input_hint\">ئىختىيارى مۇلازىمەت تور ئادرېسى</string>\n    <string name=\"pref_location_custom_source_title\">ئىختىيارى</string>\n    <string name=\"prefcat_app_last_location\">ئاخىرقى قېتىم دوكلات قىلىنغان ئورۇن</string>\n</resources>\n"
  },
  {
    "path": "play-services-location/core/src/main/res/values-uk/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=\"pref_location_wifi_learning_enabled_summary\">Зберігати розташування Wi-Fi локально, коли використовується GPS.</string>\n    <string name=\"location_app_last_access_at\">Останній доступ: <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"pref_location_cell_learning_enabled_summary\">Зберігайте місця розташування мобільних мереж локально, коли використовується GPS.</string>\n    <string name=\"fragment_location_apps_title\">Застосунки з доступом до місця розташування</string>\n    <string name=\"pref_location_app_force_coarse_summary\">Завжди повертайте грубі розташування до цього застоаунку, ігноруючи його рівень дозволів.</string>\n    <string name=\"pref_location_cell_learning_enabled_title\">Запам\\'ятати з GPS</string>\n    <string name=\"pref_location_wifi_learning_enabled_title\">Запам\\'ятати з GPS</string>\n    <string name=\"pref_location_wifi_moving_enabled_summary\">Отримати розташування Wi-Fi безпосередньо з підтримуваних гарячих точок при з\\'єднанні.</string>\n    <string name=\"prefcat_location_cell_title\">Розташування мобільної мережі</string>\n    <string name=\"pref_location_wifi_moving_enabled_title\">Запит від Hotspot</string>\n    <string name=\"pref_location_app_force_coarse_title\">Примусове грубе розташування</string>\n    <string name=\"pref_geocoder_nominatim_enabled_title\">Використовувати Nominatim</string>\n    <string name=\"service_name_location\">Розташування</string>\n    <string name=\"prefcat_location_apps_title\">Нещодавній доступ</string>\n    <string name=\"pref_geocoder_nominatim_enabled_summary\">Визначення адрес за допомогою OpenStreetMap Nominatim.</string>\n    <string name=\"prefcat_location_wifi_title\">Розташування Wi-Fi</string>\n    <string name=\"prefcat_geocoder_title\">Розв\\'язувач адрес</string>\n    <string name=\"location_settings_dialog_message_title_for_better_experience\">Для кращої роботи увімкніть функцію визначення місцеположення пристрою, яка використовує службу визначення місцеположення microG</string>\n    <string name=\"location_settings_dialog_message_title_to_continue\">Щоб продовжити, увімкніть визначення місцеположення пристрою, який використовує службу визначення місцеположення microG</string>\n    <string name=\"location_settings_dialog_btn_sure\">Гаразд</string>\n    <string name=\"location_settings_dialog_message_gls_consent\">Використання сервісу визначення місцеположення microG; в рамках цього сервісу microG може періодично збирати дані про ваше перебування та використовувати ці дані анонімно для підвищення точності визначення місцеположення та надання послуг на основі координат.</string>\n    <string name=\"location_settings_dialog_message_details_start_paragraph\">Пристрій повинен буде:</string>\n    <string name=\"location_settings_dialog_message_location_services_gps_and_nlp\">Використання GPS, Wi-Fi, мобільні мережі та датників</string>\n    <string name=\"location_settings_dialog_message_details_end_paragraph\">Щоб подробиць, перейдіть до налаштувань місцеположення.</string>\n    <string name=\"location_settings_dialog_btn_cancel\">Ні, дякую</string>\n    <string name=\"pref_location_custom_url_summary\">Це дозволяє встановити власну URL-адресу служби. Неправильні значення можуть призвести до того, що служби визначення місцеположення не відповідатимуть або будуть недоступні.</string>\n    <string name=\"pref_location_custom_url_details\">Шлях /v1/geolocate буде додано автоматично. Якщо постачальник послуг з визначення місцяположення вимагає ключ, його можна додати як параметр запиту до кореневої URL-адреси.</string>\n    <string name=\"pref_location_custom_url_input_hint\">Власна URL-адреса служби</string>\n    <string name=\"location_settings_dialog_message_grant_permissions\">Надайте сервісу microG доступ до місцеположення</string>\n    <string name=\"pref_location_wifi_online_enabled_summary\">Отримувати місцеположення на основі Wi-Fi мережевого сервісу визначення розташування.</string>\n    <string name=\"pref_location_cell_online_enabled_title\">Запит від мережевого сервісу</string>\n    <string name=\"pref_location_cell_online_enabled_summary\">Отримувати розташування веж мобільного зв\\'язку з мережевого сервісу визначення розташування.</string>\n    <string name=\"pref_location_custom_source_title\">Власний</string>\n    <string name=\"pref_location_source_title\">Виберіть мережевий сервіс визначення розташування</string>\n    <string name=\"pref_location_source_terms\">Умови / Приватність</string>\n    <string name=\"pref_location_import_export_title\">Імпортувати або експортувати дані про розташування</string>\n    <string name=\"location_data_export_wifi_title\">Експортувати локальну базу даних розташування Wi-Fi</string>\n    <string name=\"location_data_import_title\">Імпортувати дані про розташування з файлу</string>\n    <string name=\"location_data_import_result_toast\">Імпортовано %1$d записів.</string>\n    <string name=\"notification_config_required_text_online_sources\">Щоб продовжити користуватися мережевими сервісами визначення розташування, вам потрібно вибрати сервіс даних про розташування.</string>\n    <string name=\"pref_location_wifi_online_enabled_title\">Запит від мережевого сервісу</string>\n    <string name=\"location_data_export_cell_title\">Експортувати локальну базу даних розташування стільникових веж</string>\n    <string name=\"pref_location_source_suggested\">Запропоновано</string>\n    <string name=\"notification_config_required_title\">Потрібне налаштування</string>\n    <string name=\"prefcat_app_last_location\">Останнє зареєстроване розташування</string>\n</resources>\n"
  },
  {
    "path": "play-services-location/core/src/main/res/values-vi/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_name_location\">Vị trí</string>\n    <string name=\"prefcat_location_apps_title\">Truy cập gần đây</string>\n    <string name=\"pref_location_wifi_online_enabled_summary\">Lấy vị trí dựa trên Wi-Fi từ dịch vụ định vị trực tuyến.</string>\n    <string name=\"pref_location_wifi_online_enabled_title\">Yêu cầu từ dịch vụ trực tuyến</string>\n    <string name=\"pref_location_wifi_learning_enabled_summary\">Lưu trữ vị trí Wi-Fi cục bộ khi sử dụng GPS.</string>\n    <string name=\"pref_location_cell_online_enabled_title\">Yêu cầu từ dịch vụ trực tuyến</string>\n    <string name=\"pref_location_cell_online_enabled_summary\">Lấy vị trí trạm phát sóng di động từ dịch vụ định vị trực tuyến.</string>\n    <string name=\"pref_location_cell_learning_enabled_title\">Ghi nhớ từ GPS</string>\n    <string name=\"pref_location_cell_learning_enabled_summary\">Lưu trữ vị trí mạng di động cục bộ khi sử dụng GPS.</string>\n    <string name=\"pref_location_app_force_coarse_summary\">Luôn trả về vị trí không chính xác cho ứng dụng này, bỏ qua mức độ quyền của ứng dụng.</string>\n    <string name=\"location_settings_dialog_message_title_for_better_experience\">Để có trải nghiệm tốt hơn, hãy bật chức năng định vị thiết bị và sử dụng dịch vụ định vị của microG</string>\n    <string name=\"location_settings_dialog_message_grant_permissions\">Cấp quyền vị trí cho Dịch vụ microG</string>\n    <string name=\"pref_location_custom_source_title\">Tuỳ chỉnh</string>\n    <string name=\"pref_location_source_title\">Chọn dịch vụ định vị trực tuyến</string>\n    <string name=\"pref_location_source_terms\">Điều khoản/Quyền riêng tư</string>\n    <string name=\"pref_location_source_suggested\">Đề xuất</string>\n    <string name=\"pref_location_import_export_title\">Nhập hoặc xuất dữ liệu vị trí</string>\n    <string name=\"notification_config_required_title\">Cấu hình yêu cầu</string>\n    <string name=\"notification_config_required_text_online_sources\">Để tiếp tục sử dụng dịch vụ định vị trực tuyến, bạn cần chọn một dịch vụ dữ liệu vị trí.</string>\n    <string name=\"location_data_export_wifi_title\">Xuất cơ sở dữ liệu vị trí Wi-Fi cục bộ</string>\n    <string name=\"location_data_export_cell_title\">Xuất cơ sở dữ liệu vị trí trạm phát sóng di động địa phương</string>\n    <string name=\"location_data_import_title\">Nhập dữ liệu vị trí từ tệp</string>\n    <string name=\"location_data_import_result_toast\">Đã nhập %1$d bản ghi.</string>\n    <string name=\"prefcat_location_wifi_title\">Vị trí Wi-Fi</string>\n    <string name=\"prefcat_location_cell_title\">Vị trí dữ liệu di động</string>\n    <string name=\"prefcat_geocoder_title\">Bộ phân giải địa chỉ</string>\n    <string name=\"pref_location_wifi_learning_enabled_title\">Ghi nhớ từ GPS</string>\n    <string name=\"pref_location_wifi_moving_enabled_title\">Yêu cầu từ Hotspot</string>\n    <string name=\"pref_location_wifi_moving_enabled_summary\">Lấy vị trí Wi-Fi trực tiếp từ các điểm phát sóng được hỗ trợ khi đã kết nối.</string>\n    <string name=\"pref_geocoder_nominatim_enabled_summary\">Phân giải địa chỉ bằng OpenStreetMap Nominatim.</string>\n    <string name=\"pref_geocoder_nominatim_enabled_title\">Sử dụng Nominatim</string>\n    <string name=\"location_app_last_access_at\">Lần truy cập cuối: <xliff:g example=\"Hôm qua, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"pref_location_app_force_coarse_title\">Buộc vị trí không chính xác</string>\n    <string name=\"fragment_location_apps_title\">Ứng dụng có quyền truy cập vị trí</string>\n    <string name=\"location_settings_dialog_message_details_start_paragraph\">Thiết bị của bạn cần phải:</string>\n    <string name=\"location_settings_dialog_message_title_to_continue\">Để có thể tiếp tục, hãy bật chức năng định vị thiết bị và sử dụng dịch vụ định vị của microG</string>\n    <string name=\"location_settings_dialog_message_location_services_gps_and_nlp\">Sử dụng GPS, Wi‑Fi, dữ liệu di động và cảm biến</string>\n    <string name=\"location_settings_dialog_message_details_end_paragraph\">Để biết chi tiết, hãy vào phần cài đặt vị trí.</string>\n    <string name=\"location_settings_dialog_btn_cancel\">Không, cảm ơn</string>\n    <string name=\"location_settings_dialog_message_gls_consent\">Sử dụng dịch vụ định vị microG; như một phần của dịch vụ này, microG có thể thu thập dữ liệu vị trí theo định kỳ và sử dụng dữ liệu này theo cách ẩn danh để cải thiện độ chính xác của vị trí và các dịch vụ dựa trên vị trí.</string>\n    <string name=\"location_settings_dialog_btn_sure\">ĐƯỢC RỒI</string>\n    <string name=\"pref_location_custom_url_input_hint\">URL dịch vụ tùy chỉnh</string>\n    <string name=\"pref_location_custom_url_summary\">Điều này cho phép thiết lập URL dịch vụ tùy chỉnh. Các giá trị không hợp lệ có thể khiến dịch vụ vị trí không phản hồi hoặc hoàn toàn không khả dụng.</string>\n    <string name=\"pref_location_custom_url_details\">Đường dẫn /v1/geocate được tự động thêm vào. Nếu nhà cung cấp vị trí yêu cầu khóa, khóa này có thể được thêm vào như một tham số truy vấn vào URL gốc.</string>\n    <string name=\"prefcat_app_last_location\">Vị trí được báo cáo cuối cùng</string>\n</resources>\n"
  },
  {
    "path": "play-services-location/core/src/main/res/values-zh-rCN/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=\"pref_location_wifi_learning_enabled_summary\">使用 GPS 时，在本地存储 Wi-Fi 网络的位置信息。</string>\n    <string name=\"location_app_last_access_at\">最后访问于<xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"pref_location_cell_learning_enabled_summary\">使用 GPS 时，在本地存储移动网络的位置信息。</string>\n    <string name=\"fragment_location_apps_title\">可访问位置信息的应用</string>\n    <string name=\"pref_location_app_force_coarse_summary\">忽略应用的位置权限级别，总是向其提供大致的位置信息。</string>\n    <string name=\"pref_location_cell_learning_enabled_title\">从 GPS 处学习</string>\n    <string name=\"pref_location_wifi_learning_enabled_title\">从 GPS 处学习</string>\n    <string name=\"pref_location_wifi_moving_enabled_summary\">当连接到受支持的热点网络时，从上游热点直接获取 Wi-Fi 位置信息。</string>\n    <string name=\"prefcat_location_cell_title\">基于移动网络的位置信息</string>\n    <string name=\"pref_location_wifi_moving_enabled_title\">从热点获取</string>\n    <string name=\"pref_location_app_force_coarse_title\">总是提供大致的位置</string>\n    <string name=\"pref_geocoder_nominatim_enabled_title\">使用 Nominatim</string>\n    <string name=\"service_name_location\">位置信息</string>\n    <string name=\"prefcat_location_apps_title\">最近访问</string>\n    <string name=\"pref_geocoder_nominatim_enabled_summary\">使用 OpenStreetMap Nominatim 服务解析地址。</string>\n    <string name=\"prefcat_location_wifi_title\">基于 Wi-Fi 的位置服务</string>\n    <string name=\"prefcat_geocoder_title\">地址解析器</string>\n    <string name=\"location_settings_dialog_message_title_for_better_experience\">为了获得更好的体验，请开启设备定位，该功能使用 microG 的位置服务</string>\n    <string name=\"location_settings_dialog_message_title_to_continue\">要继续，请打开使用 microG 定位服务的设备定位</string>\n    <string name=\"location_settings_dialog_message_details_start_paragraph\">您的设备将需要:</string>\n    <string name=\"location_settings_dialog_message_location_services_gps_and_nlp\">使用 GPS 、WLAN 、移动网络和传感器</string>\n    <string name=\"location_settings_dialog_message_gls_consent\">使用 microG 位置服务；作为服务的一部分，microG 可能会定期收集位置数据，并以匿名方式使用这类数据，从而提高位置信息的精准度并改善基于地理位置的服务。</string>\n    <string name=\"location_settings_dialog_message_details_end_paragraph\">有关详细信息，请访问位置信息设置。</string>\n    <string name=\"location_settings_dialog_btn_cancel\">不用了</string>\n    <string name=\"location_settings_dialog_btn_sure\">确定</string>\n    <string name=\"pref_location_custom_url_summary\">这设置允许自定义服务 URL。 无效值可能会导致位置服务无响应或完全不可用。</string>\n    <string name=\"pref_location_custom_url_details\">/v1/geolocate路径会自动添加。如果位置提供商需要密钥，则可以将其作为查询参数附加到根URL。</string>\n    <string name=\"pref_location_custom_url_input_hint\">自定义服务URL</string>\n    <string name=\"location_settings_dialog_message_grant_permissions\">向 microG 服务授予位置权限</string>\n    <string name=\"pref_location_wifi_online_enabled_summary\">从在线位置服务获取基于Wi-Fi的位置。</string>\n    <string name=\"pref_location_cell_online_enabled_title\">来自在线服务的请求</string>\n    <string name=\"pref_location_cell_online_enabled_summary\">从在线位置服务获取基于移动网络的位置。</string>\n    <string name=\"pref_location_custom_source_title\">自定义</string>\n    <string name=\"pref_location_source_title\">选择在线定位服务</string>\n    <string name=\"pref_location_source_terms\">条款/隐私</string>\n    <string name=\"pref_location_source_suggested\">建议</string>\n    <string name=\"pref_location_import_export_title\">导入或导出位置数据</string>\n    <string name=\"notification_config_required_title\">需要的配置</string>\n    <string name=\"location_data_export_cell_title\">导出本地基站位置数据库</string>\n    <string name=\"location_data_import_title\">从文件导入位置数据</string>\n    <string name=\"location_data_import_result_toast\">已导入 %1$d 条记录。</string>\n    <string name=\"pref_location_wifi_online_enabled_title\">来自在线服务的请求</string>\n    <string name=\"notification_config_required_text_online_sources\">要继续使用在线位置服务，您需要选择一个位置数据服务。</string>\n    <string name=\"location_data_export_wifi_title\">导出本地 Wi-Fi 位置数据库</string>\n    <string name=\"prefcat_app_last_location\">最后报告的位置</string>\n</resources>\n"
  },
  {
    "path": "play-services-location/core/src/main/res/values-zh-rTW/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=\"location_settings_dialog_message_gls_consent\">使用 microG 定位服務；作為此服務的一部分，microG 可能會定期收集位置資料，並以匿名方式使用這些資料，以提升定位準確度及位置相關服務的品質。</string>\n    <string name=\"pref_location_wifi_moving_enabled_summary\">當連線到支援的熱點時直接從其獲取 Wi-Fi 位置資訊。</string>\n    <string name=\"prefcat_location_apps_title\">最近存取</string>\n    <string name=\"location_data_export_wifi_title\">匯出本地 Wi-Fi 位置資料庫</string>\n    <string name=\"pref_location_custom_url_input_hint\">自定義服務 URL</string>\n    <string name=\"pref_location_wifi_online_enabled_title\">向線上服務發出請求</string>\n    <string name=\"pref_location_wifi_online_enabled_summary\">從線上定位服務獲取基於 Wi-Fi 的位置資訊。</string>\n    <string name=\"pref_location_cell_online_enabled_title\">向線上服務發出請求</string>\n    <string name=\"pref_location_cell_online_enabled_summary\">從線上定位服務獲取基於行動網路訊號塔的位置資訊。</string>\n    <string name=\"pref_location_cell_learning_enabled_title\">從 GPS 學習</string>\n    <string name=\"pref_location_cell_learning_enabled_summary\">使用 GPS 時，在本地儲存行動網路的位置資訊。</string>\n    <string name=\"pref_geocoder_nominatim_enabled_summary\">使用 OpenStreetMap Nominatim 解析地址。</string>\n    <string name=\"fragment_location_apps_title\">可存取位置資訊的應用程式</string>\n    <string name=\"location_app_last_access_at\">最後存取於 <xliff:g example=\"Yesterday, 02:20 PM\">%1$s</xliff:g></string>\n    <string name=\"pref_location_app_force_coarse_title\">強制概略位置</string>\n    <string name=\"pref_location_app_force_coarse_summary\">永遠提供概略位置給此應用程式，無視其權限等級。</string>\n    <string name=\"prefcat_app_last_location\">上次回報位置</string>\n    <string name=\"location_settings_dialog_message_title_for_better_experience\">為了獲得更好的使用體驗，請開啟裝置定位功能，這將使用 microG 的定位服務</string>\n    <string name=\"location_settings_dialog_message_title_to_continue\">若要繼續，請開啟裝置定位功能，這將使用 microG 的定位服務</string>\n    <string name=\"location_settings_dialog_message_details_start_paragraph\">您的設備將需要：</string>\n    <string name=\"location_settings_dialog_message_location_services_gps_and_nlp\">使用 GPS、Wi-Fi、行動網路以及感應器</string>\n    <string name=\"location_settings_dialog_message_grant_permissions\">授予位置存取權限給 microG Service</string>\n    <string name=\"location_settings_dialog_message_details_end_paragraph\">有關詳細資訊，請造訪位置設定。</string>\n    <string name=\"location_settings_dialog_btn_cancel\">不用了</string>\n    <string name=\"location_settings_dialog_btn_sure\">確定</string>\n    <string name=\"pref_location_custom_url_summary\">這可讓您自定義的服務 URL。不正確的設定可能會導致定位服務沒有回應或完全無法使用。</string>\n    <string name=\"pref_location_custom_url_details\">系統會自動附加 /v1/geolocate 路徑。如果定位服務提供者需要金鑰，可以將金鑰作為查詢參數附加在根網址後面。</string>\n    <string name=\"pref_location_custom_source_title\">自定義</string>\n    <string name=\"pref_location_source_title\">選擇線上定位服務</string>\n    <string name=\"pref_location_source_terms\">隱私權與條款</string>\n    <string name=\"pref_location_source_suggested\">建議</string>\n    <string name=\"pref_location_import_export_title\">匯入或匯出位置資料</string>\n    <string name=\"notification_config_required_title\">需要設置</string>\n    <string name=\"notification_config_required_text_online_sources\">若要繼續使用線上定位服務，您需要選擇一個位置資料服務。</string>\n    <string name=\"location_data_export_cell_title\">匯出本地電信基地台位置資料庫</string>\n    <string name=\"location_data_import_title\">從檔案匯入位置資料</string>\n    <string name=\"location_data_import_result_toast\">已匯入 %1$d 筆紀錄。</string>\n    <string name=\"pref_location_wifi_learning_enabled_title\">從 GPS 學習</string>\n    <string name=\"pref_location_wifi_learning_enabled_summary\">使用 GPS 時，在本地儲存 Wi-Fi 的位置資訊。</string>\n    <string name=\"pref_geocoder_nominatim_enabled_title\">使用 Nominatim</string>\n    <string name=\"service_name_location\">位置</string>\n    <string name=\"prefcat_location_wifi_title\">Wi-Fi 位置</string>\n    <string name=\"prefcat_location_cell_title\">行動網路位置</string>\n    <string name=\"prefcat_geocoder_title\">地址解析器</string>\n    <string name=\"pref_location_wifi_moving_enabled_title\">從熱點獲取</string>\n</resources>\n"
  },
  {
    "path": "play-services-location/core/src/main/res/xml/preferences_location.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<PreferenceScreen 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    <PreferenceCategory\n        android:key=\"prefcat_location_apps\"\n        android:title=\"@string/prefcat_location_apps_title\"\n        app:iconSpaceReserved=\"false\">\n        <Preference\n            android:enabled=\"false\"\n            android:key=\"pref_location_apps_none\"\n            android:title=\"@string/list_no_item_none\" />\n        <Preference\n            android:icon=\"@drawable/ic_expand_apps\"\n            android:key=\"pref_location_apps_all\"\n            android:order=\"5\"\n            android:title=\"@string/list_item_see_all\" />\n    </PreferenceCategory>\n    <PreferenceCategory\n        android:key=\"prefcat_location_network_provider\"\n        android:layout=\"@layout/preference_category_no_label\"\n        app:iconSpaceReserved=\"false\">\n        <PreferenceCategory\n            android:key=\"prefcat_location_wifi\"\n            android:title=\"@string/prefcat_location_wifi_title\"\n            app:iconSpaceReserved=\"false\">\n            <SwitchPreferenceCompat\n                android:defaultValue=\"true\"\n                android:persistent=\"false\"\n                android:key=\"pref_location_wifi_mls_enabled\"\n                android:title=\"@string/pref_location_wifi_online_enabled_title\"\n                android:summary=\"@string/pref_location_wifi_online_enabled_summary\"\n                app:iconSpaceReserved=\"false\" />\n            <SwitchPreferenceCompat\n                android:defaultValue=\"true\"\n                android:persistent=\"false\"\n                android:key=\"pref_location_wifi_moving_enabled\"\n                android:title=\"@string/pref_location_wifi_moving_enabled_title\"\n                android:summary=\"@string/pref_location_wifi_moving_enabled_summary\"\n                app:iconSpaceReserved=\"false\" />\n            <SwitchPreferenceCompat\n                android:defaultValue=\"true\"\n                android:persistent=\"false\"\n                android:key=\"pref_location_wifi_learning_enabled\"\n                android:title=\"@string/pref_location_wifi_learning_enabled_title\"\n                android:summary=\"@string/pref_location_wifi_learning_enabled_summary\"\n                app:iconSpaceReserved=\"false\" />\n        </PreferenceCategory>\n        <PreferenceCategory\n            android:key=\"prefcat_location_cells\"\n            android:title=\"@string/prefcat_location_cell_title\"\n            app:iconSpaceReserved=\"false\">\n            <SwitchPreferenceCompat\n                android:defaultValue=\"true\"\n                android:persistent=\"false\"\n                android:key=\"pref_location_cell_mls_enabled\"\n                android:title=\"@string/pref_location_cell_online_enabled_title\"\n                android:summary=\"@string/pref_location_cell_online_enabled_summary\"\n                app:iconSpaceReserved=\"false\" />\n            <SwitchPreferenceCompat\n                android:defaultValue=\"true\"\n                android:persistent=\"false\"\n                android:key=\"pref_location_cell_learning_enabled\"\n                android:title=\"@string/pref_location_cell_learning_enabled_title\"\n                android:summary=\"@string/pref_location_cell_learning_enabled_summary\"\n                app:iconSpaceReserved=\"false\" />\n        </PreferenceCategory>\n        <PreferenceCategory\n            android:key=\"prefcat_geocoder\"\n            android:title=\"@string/prefcat_geocoder_title\"\n            app:iconSpaceReserved=\"false\">\n            <SwitchPreferenceCompat\n                android:defaultValue=\"true\"\n                android:persistent=\"false\"\n                android:key=\"pref_geocoder_nominatim_enabled\"\n                android:title=\"@string/pref_geocoder_nominatim_enabled_title\"\n                android:summary=\"@string/pref_geocoder_nominatim_enabled_summary\"\n                app:iconSpaceReserved=\"false\" />\n        </PreferenceCategory>\n    </PreferenceCategory>\n</PreferenceScreen>"
  },
  {
    "path": "play-services-location/core/src/main/res/xml/preferences_location_all_apps.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\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    <Preference\n        android:key=\"pref_location_apps_all_progress\"\n        android:layout=\"@layout/preference_progress_bar\"\n        app:allowDividerBelow=\"false\" />\n    <PreferenceCategory\n        android:key=\"prefcat_location_apps\"\n        android:layout=\"@layout/preference_category_no_label\"\n        app:isPreferenceVisible=\"false\"\n        tools:isPreferenceVisible=\"true\" />\n\n</PreferenceScreen>"
  },
  {
    "path": "play-services-location/core/src/main/res/xml/preferences_location_app_details.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<PreferenceScreen 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    <org.microg.gms.ui.AppHeadingPreference\n        android:key=\"pref_location_app_heading\"\n        tools:icon=\"@android:mipmap/sym_def_app_icon\"\n        tools:title=\"@tools:sample/lorem\"\n        app:allowDividerBelow=\"false\" />\n    <PreferenceCategory android:layout=\"@layout/preference_category_no_label\">\n        <SwitchPreferenceCompat\n            android:key=\"pref_location_app_force_coarse\"\n            android:title=\"@string/pref_location_app_force_coarse_title\"\n            android:summary=\"@string/pref_location_app_force_coarse_summary\"\n            android:persistent=\"false\"\n            app:iconSpaceReserved=\"false\" />\n    </PreferenceCategory>\n    <PreferenceCategory\n        android:key=\"prefcat_location_app_last_location\"\n        android:title=\"@string/prefcat_app_last_location\"\n        app:iconSpaceReserved=\"false\">\n        <Preference\n            android:key=\"pref_location_app_last_location\"\n            tools:title=\"Yesterday, 00:30:23\"\n            tools:summary=\"Pl. Charles de Gaulle, 75008 Paris, France\"\n            android:persistent=\"false\"\n            app:iconSpaceReserved=\"false\" />\n        <org.microg.gms.location.ui.LocationMapPreference\n            android:key=\"pref_location_app_last_location_map\"\n            android:selectable=\"false\"\n            android:persistent=\"false\" />\n    </PreferenceCategory>\n</PreferenceScreen>"
  },
  {
    "path": "play-services-location/core/system-api/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\n\ndependencies {\n    implementation \"androidx.annotation:annotation:$annotationVersion\"\n}\n\nandroid {\n    namespace \"org.microg.gms.location.sysapi\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n}"
  },
  {
    "path": "play-services-location/core/system-api/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest />"
  },
  {
    "path": "play-services-location/core/system-api/src/main/java/android/location/GeocoderParams.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2010, The Android Open Source Project\n * SPDX-FileCopyrightText: 2014, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage android.location;\n\nimport android.content.Context;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\n\nimport java.util.Locale;\n\n/**\n * This class contains extra parameters to pass to an IGeocodeProvider\n * implementation from the Geocoder class.  Currently this contains the\n * language, country and variant information from the Geocoder's locale\n * as well as the Geocoder client's package name for geocoder server\n * logging.  This information is kept in a separate class to allow for\n * future expansion of the IGeocodeProvider interface.\n *\n * @hide\n */\npublic class GeocoderParams implements Parcelable {\n    /**\n     * This object is only constructed by the Geocoder class\n     *\n     * @hide\n     */\n    public GeocoderParams(Context context, Locale locale) {\n    }\n\n    /**\n     * Returns the client UID.\n     */\n    @RequiresApi(33)\n    public int getClientUid() {\n        return 0;\n    }\n\n    /**\n     * returns the package name of the Geocoder's client\n     */\n    public String getClientPackage() {\n        return null;\n    }\n\n    /**\n     * Returns the client attribution tag.\n     */\n    @RequiresApi(33)\n    public @Nullable String getClientAttributionTag() {\n        return null;\n    }\n\n    /**\n     * returns the Geocoder's locale\n     */\n    public Locale getLocale() {\n        return null;\n    }\n\n    public static final Parcelable.Creator<GeocoderParams> CREATOR =\n            new Parcelable.Creator<GeocoderParams>() {\n                public GeocoderParams createFromParcel(Parcel in) {\n                    return null;\n                }\n\n                public GeocoderParams[] newArray(int size) {\n                    return null;\n                }\n            };\n\n    public int describeContents() {\n        return 0;\n    }\n\n    public void writeToParcel(Parcel parcel, int flags) {\n    }\n}\n"
  },
  {
    "path": "play-services-location/core/system-api/src/main/java/android/location/Geofence.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2012, The Android Open Source Project\n * SPDX-FileCopyrightText: 2014, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage android.location;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\n/**\n * Represents a geographical boundary, also known as a geofence.\n *\n * <p>Currently only circular geofences are supported and they do not support altitude changes.\n *\n * @hide\n */\npublic final class Geofence implements Parcelable {\n    /** @hide */\n    public static final int TYPE_HORIZONTAL_CIRCLE = 1;\n\n    private final int mType;\n    private final double mLatitude;\n    private final double mLongitude;\n    private final float mRadius;\n\n    /**\n     * Create a circular geofence (on a flat, horizontal plane).\n     *\n     * @param latitude latitude in degrees, between -90 and +90 inclusive\n     * @param longitude longitude in degrees, between -180 and +180 inclusive\n     * @param radius radius in meters\n     * @return a new geofence\n     * @throws IllegalArgumentException if any parameters are out of range\n     */\n    public static Geofence createCircle(double latitude, double longitude, float radius) {\n        return new Geofence(latitude, longitude, radius);\n    }\n\n    private Geofence(double latitude, double longitude, float radius) {\n        checkRadius(radius);\n        checkLatLong(latitude, longitude);\n        mType = TYPE_HORIZONTAL_CIRCLE;\n        mLatitude = latitude;\n        mLongitude = longitude;\n        mRadius = radius;\n    }\n\n    /** @hide */\n    public int getType() {\n        return mType;\n    }\n\n    /** @hide */\n    public double getLatitude() {\n        return mLatitude;\n    }\n\n    /** @hide */\n    public double getLongitude() {\n        return mLongitude;\n    }\n\n    /** @hide */\n    public float getRadius() {\n        return mRadius;\n    }\n\n    private static void checkRadius(float radius) {\n        if (radius <= 0) {\n            throw new IllegalArgumentException(\"invalid radius: \" + radius);\n        }\n    }\n\n    private static void checkLatLong(double latitude, double longitude) {\n        if (latitude > 90.0 || latitude < -90.0) {\n            throw new IllegalArgumentException(\"invalid latitude: \" + latitude);\n        }\n        if (longitude > 180.0 || longitude < -180.0) {\n            throw new IllegalArgumentException(\"invalid longitude: \" + longitude);\n        }\n    }\n\n    private static void checkType(int type) {\n        if (type != TYPE_HORIZONTAL_CIRCLE) {\n            throw new IllegalArgumentException(\"invalid type: \" + type);\n        }\n    }\n\n    public static final Parcelable.Creator<Geofence> CREATOR = new Parcelable.Creator<Geofence>() {\n        @Override\n        public Geofence createFromParcel(Parcel in) {\n            int type = in.readInt();\n            double latitude = in.readDouble();\n            double longitude = in.readDouble();\n            float radius = in.readFloat();\n            checkType(type);\n            return Geofence.createCircle(latitude, longitude, radius);\n        }\n        @Override\n        public Geofence[] newArray(int size) {\n            return new Geofence[size];\n        }\n    };\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(Parcel parcel, int flags) {\n        parcel.writeInt(mType);\n        parcel.writeDouble(mLatitude);\n        parcel.writeDouble(mLongitude);\n        parcel.writeFloat(mRadius);\n    }\n\n    private static String typeToString(int type) {\n        switch (type) {\n            case TYPE_HORIZONTAL_CIRCLE:\n                return \"CIRCLE\";\n            default:\n                checkType(type);\n                return null;\n        }\n    }\n\n    @Override\n    public String toString() {\n        return String.format(\"Geofence[%s %.6f, %.6f %.0fm]\",\n                typeToString(mType), mLatitude, mLongitude, mRadius);\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        long temp;\n        temp = Double.doubleToLongBits(mLatitude);\n        result = prime * result + (int) (temp ^ (temp >>> 32));\n        temp = Double.doubleToLongBits(mLongitude);\n        result = prime * result + (int) (temp ^ (temp >>> 32));\n        result = prime * result + Float.floatToIntBits(mRadius);\n        result = prime * result + mType;\n        return result;\n    }\n\n    /**\n     * Two geofences are equal if they have identical properties.\n     */\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj)\n            return true;\n        if (obj == null)\n            return false;\n        if (!(obj instanceof Geofence))\n            return false;\n        Geofence other = (Geofence) obj;\n        if (mRadius != other.mRadius)\n            return false;\n        if (mLatitude != other.mLatitude)\n            return false;\n        if (mLongitude != other.mLongitude)\n            return false;\n        if (mType != other.mType)\n            return false;\n        return true;\n    }\n}\n"
  },
  {
    "path": "play-services-location/core/system-api/src/main/java/android/location/Location.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2007, The Android Open Source Project\n * SPDX-FileCopyrightText: 2014, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage android.location;\n\nimport android.os.Bundle;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.util.Printer;\n\n/**\n * A data class representing a geographic location.\n * <p/>\n * <p>A location can consist of a latitude, longitude, timestamp,\n * and other information such as bearing, altitude and velocity.\n * <p/>\n * <p>All locations generated by the {@link LocationManager} are\n * guaranteed to have a valid latitude, longitude, and timestamp\n * (both UTC time and elapsed real-time since boot), all other\n * parameters are optional.\n */\npublic class Location implements Parcelable {\n    /**\n     * Constant used to specify formatting of a latitude or longitude\n     * in the form \"[+-]DDD.DDDDD where D indicates degrees.\n     */\n    public static final int FORMAT_DEGREES = 0;\n\n    /**\n     * Constant used to specify formatting of a latitude or longitude\n     * in the form \"[+-]DDD:MM.MMMMM\" where D indicates degrees and\n     * M indicates minutes of arc (1 minute = 1/60th of a degree).\n     */\n    public static final int FORMAT_MINUTES = 1;\n\n    /**\n     * Constant used to specify formatting of a latitude or longitude\n     * in the form \"DDD:MM:SS.SSSSS\" where D indicates degrees, M\n     * indicates minutes of arc, and S indicates seconds of arc (1\n     * minute = 1/60th of a degree, 1 second = 1/3600th of a degree).\n     */\n    public static final int FORMAT_SECONDS = 2;\n\n    /**\n     * Bundle key for a version of the location that has been fed through\n     * LocationFudger. Allows location providers to flag locations as being\n     * safe for use with ACCESS_COARSE_LOCATION permission.\n     *\n     * @hide\n     */\n    public static final String EXTRA_COARSE_LOCATION = \"coarseLocation\";\n\n    /**\n     * Bundle key for a version of the location containing no GPS data.\n     * Allows location providers to flag locations as being safe to\n     * feed to LocationFudger.\n     *\n     * @hide\n     */\n    public static final String EXTRA_NO_GPS_LOCATION = \"noGPSLocation\";\n\n    /**\n     * Construct a new Location with a named provider.\n     * <p/>\n     * <p>By default time, latitude and longitude are 0, and the location\n     * has no bearing, altitude, speed, accuracy or extras.\n     *\n     * @param provider the name of the provider that generated this location\n     */\n    public Location(String provider) {\n    }\n\n    /**\n     * Construct a new Location object that is copied from an existing one.\n     */\n    public Location(Location l) {\n    }\n\n    /**\n     * Sets the contents of the location to the values from the given location.\n     */\n    public void set(Location l) {\n    }\n\n    /**\n     * Clears the contents of the location.\n     */\n    public void reset() {\n    }\n\n    /**\n     * Converts a coordinate to a String representation. The outputType\n     * may be one of FORMAT_DEGREES, FORMAT_MINUTES, or FORMAT_SECONDS.\n     * The coordinate must be a valid double between -180.0 and 180.0.\n     *\n     * @throws IllegalArgumentException if coordinate is less than\n     *                                  -180.0, greater than 180.0, or is not a number.\n     * @throws IllegalArgumentException if outputType is not one of\n     *                                  FORMAT_DEGREES, FORMAT_MINUTES, or FORMAT_SECONDS.\n     */\n    public static String convert(double coordinate, int outputType) {\n        return null;\n    }\n\n    /**\n     * Converts a String in one of the formats described by\n     * FORMAT_DEGREES, FORMAT_MINUTES, or FORMAT_SECONDS into a\n     * double.\n     *\n     * @throws NullPointerException     if coordinate is null\n     * @throws IllegalArgumentException if the coordinate is not\n     *                                  in one of the valid formats.\n     */\n    public static double convert(String coordinate) {\n        return 0;\n    }\n\n    private static void computeDistanceAndBearing(double lat1, double lon1,\n            double lat2, double lon2, float[] results) {\n    }\n\n    /**\n     * Computes the approximate distance in meters between two\n     * locations, and optionally the initial and final bearings of the\n     * shortest path between them.  Distance and bearing are defined using the\n     * WGS84 ellipsoid.\n     * <p/>\n     * <p> The computed distance is stored in results[0].  If results has length\n     * 2 or greater, the initial bearing is stored in results[1]. If results has\n     * length 3 or greater, the final bearing is stored in results[2].\n     *\n     * @param startLatitude  the starting latitude\n     * @param startLongitude the starting longitude\n     * @param endLatitude    the ending latitude\n     * @param endLongitude   the ending longitude\n     * @param results        an array of floats to hold the results\n     * @throws IllegalArgumentException if results is null or has length < 1\n     */\n    public static void distanceBetween(double startLatitude, double startLongitude,\n            double endLatitude, double endLongitude, float[] results) {\n    }\n\n    /**\n     * Returns the approximate distance in meters between this\n     * location and the given location.  Distance is defined using\n     * the WGS84 ellipsoid.\n     *\n     * @param dest the destination location\n     * @return the approximate distance in meters\n     */\n    public float distanceTo(Location dest) {\n        return 0;\n    }\n\n    /**\n     * Returns the approximate initial bearing in degrees East of true\n     * North when traveling along the shortest path between this\n     * location and the given location.  The shortest path is defined\n     * using the WGS84 ellipsoid.  Locations that are (nearly)\n     * antipodal may produce meaningless results.\n     *\n     * @param dest the destination location\n     * @return the initial bearing in degrees\n     */\n    public float bearingTo(Location dest) {\n        return 0;\n    }\n\n    /**\n     * Returns the name of the provider that generated this fix.\n     *\n     * @return the provider, or null if it has not been set\n     */\n    public String getProvider() {\n        return null;\n    }\n\n    /**\n     * Sets the name of the provider that generated this fix.\n     */\n    public void setProvider(String provider) {\n    }\n\n    /**\n     * Return the UTC time of this fix, in milliseconds since January 1, 1970.\n     * <p/>\n     * <p>Note that the UTC time on a device is not monotonic: it\n     * can jump forwards or backwards unpredictably. So always use\n     * {@link #getElapsedRealtimeNanos} when calculating time deltas.\n     * <p/>\n     * <p>On the other hand, {@link #getTime} is useful for presenting\n     * a human readable time to the user, or for carefully comparing\n     * location fixes across reboot or across devices.\n     * <p/>\n     * <p>All locations generated by the {@link LocationManager}\n     * are guaranteed to have a valid UTC time, however remember that\n     * the system time may have changed since the location was generated.\n     *\n     * @return time of fix, in milliseconds since January 1, 1970.\n     */\n    public long getTime() {\n        return 0;\n    }\n\n    /**\n     * Set the UTC time of this fix, in milliseconds since January 1,\n     * 1970.\n     *\n     * @param time UTC time of this fix, in milliseconds since January 1, 1970\n     */\n    public void setTime(long time) {\n    }\n\n    /**\n     * Return the time of this fix, in elapsed real-time since system boot.\n     * <p/>\n     * <p>This value can be reliably compared to\n     * {@link android.os.SystemClock#elapsedRealtimeNanos},\n     * to calculate the age of a fix and to compare Location fixes. This\n     * is reliable because elapsed real-time is guaranteed monotonic for\n     * each system boot and continues to increment even when the system\n     * is in deep sleep (unlike {@link #getTime}.\n     * <p/>\n     * <p>All locations generated by the {@link LocationManager}\n     * are guaranteed to have a valid elapsed real-time.\n     *\n     * @return elapsed real-time of fix, in nanoseconds since system boot.\n     */\n    public long getElapsedRealtimeNanos() {\n        return 0;\n    }\n\n    /**\n     * Set the time of this fix, in elapsed real-time since system boot.\n     *\n     * @param time elapsed real-time of fix, in nanoseconds since system boot.\n     */\n    public void setElapsedRealtimeNanos(long time) {\n    }\n\n    /**\n     * Get the latitude, in degrees.\n     * <p/>\n     * <p>All locations generated by the {@link LocationManager}\n     * will have a valid latitude.\n     */\n    public double getLatitude() {\n        return 0;\n    }\n\n    /**\n     * Set the latitude, in degrees.\n     */\n    public void setLatitude(double latitude) {\n    }\n\n    /**\n     * Get the longitude, in degrees.\n     * <p/>\n     * <p>All locations generated by the {@link LocationManager}\n     * will have a valid longitude.\n     */\n    public double getLongitude() {\n        return 0;\n    }\n\n    /**\n     * Set the longitude, in degrees.\n     */\n    public void setLongitude(double longitude) {\n    }\n\n    /**\n     * True if this location has an altitude.\n     */\n    public boolean hasAltitude() {\n        return false;\n    }\n\n    /**\n     * Get the altitude if available, in meters above the WGS 84 reference\n     * ellipsoid.\n     * <p/>\n     * <p>If this location does not have an altitude then 0.0 is returned.\n     */\n    public double getAltitude() {\n        return 0;\n    }\n\n    /**\n     * Set the altitude, in meters above the WGS 84 reference ellipsoid.\n     * <p/>\n     * <p>Following this call {@link #hasAltitude} will return true.\n     */\n    public void setAltitude(double altitude) {\n    }\n\n    /**\n     * Remove the altitude from this location.\n     * <p/>\n     * <p>Following this call {@link #hasAltitude} will return false,\n     * and {@link #getAltitude} will return 0.0.\n     */\n    public void removeAltitude() {\n    }\n\n    /**\n     * True if this location has a speed.\n     */\n    public boolean hasSpeed() {\n        return false;\n    }\n\n    /**\n     * Get the speed if it is available, in meters/second over ground.\n     * <p/>\n     * <p>If this location does not have a speed then 0.0 is returned.\n     */\n    public float getSpeed() {\n        return 0;\n    }\n\n    /**\n     * Set the speed, in meters/second over ground.\n     * <p/>\n     * <p>Following this call {@link #hasSpeed} will return true.\n     */\n    public void setSpeed(float speed) {\n    }\n\n    /**\n     * Remove the speed from this location.\n     * <p/>\n     * <p>Following this call {@link #hasSpeed} will return false,\n     * and {@link #getSpeed} will return 0.0.\n     */\n    public void removeSpeed() {\n    }\n\n    /**\n     * True if this location has a bearing.\n     */\n    public boolean hasBearing() {\n        return false;\n    }\n\n    /**\n     * Get the bearing, in degrees.\n     * <p/>\n     * <p>Bearing is the horizontal direction of travel of this device,\n     * and is not related to the device orientation. It is guaranteed to\n     * be in the range (0.0, 360.0] if the device has a bearing.\n     * <p/>\n     * <p>If this location does not have a bearing then 0.0 is returned.\n     */\n    public float getBearing() {\n        return 0;\n    }\n\n    /**\n     * Set the bearing, in degrees.\n     * <p/>\n     * <p>Bearing is the horizontal direction of travel of this device,\n     * and is not related to the device orientation.\n     * <p/>\n     * <p>The input will be wrapped into the range (0.0, 360.0].\n     */\n    public void setBearing(float bearing) {\n    }\n\n    /**\n     * Remove the bearing from this location.\n     * <p/>\n     * <p>Following this call {@link #hasBearing} will return false,\n     * and {@link #getBearing} will return 0.0.\n     */\n    public void removeBearing() {\n    }\n\n    /**\n     * True if this location has an accuracy.\n     * <p/>\n     * <p>All locations generated by the {@link LocationManager} have an\n     * accuracy.\n     */\n    public boolean hasAccuracy() {\n        return false;\n    }\n\n    /**\n     * Get the estimated accuracy of this location, in meters.\n     * <p/>\n     * <p>We define accuracy as the radius of 68% confidence. In other\n     * words, if you draw a circle centered at this location's\n     * latitude and longitude, and with a radius equal to the accuracy,\n     * then there is a 68% probability that the true location is inside\n     * the circle.\n     * <p/>\n     * <p>In statistical terms, it is assumed that location errors\n     * are random with a normal distribution, so the 68% confidence circle\n     * represents one standard deviation. Note that in practice, location\n     * errors do not always follow such a simple distribution.\n     * <p/>\n     * <p>This accuracy estimation is only concerned with horizontal\n     * accuracy, and does not indicate the accuracy of bearing,\n     * velocity or altitude if those are included in this Location.\n     * <p/>\n     * <p>If this location does not have an accuracy, then 0.0 is returned.\n     * All locations generated by the {@link LocationManager} include\n     * an accuracy.\n     */\n    public float getAccuracy() {\n        return 0;\n    }\n\n    /**\n     * Set the estimated accuracy of this location, meters.\n     * <p/>\n     * <p>See {@link #getAccuracy} for the definition of accuracy.\n     * <p/>\n     * <p>Following this call {@link #hasAccuracy} will return true.\n     */\n    public void setAccuracy(float accuracy) {\n    }\n\n    /**\n     * Remove the accuracy from this location.\n     * <p/>\n     * <p>Following this call {@link #hasAccuracy} will return false, and\n     * {@link #getAccuracy} will return 0.0.\n     */\n    public void removeAccuracy() {\n    }\n\n    /**\n     * Return true if this Location object is complete.\n     * <p/>\n     * <p>A location object is currently considered complete if it has\n     * a valid provider, accuracy, wall-clock time and elapsed real-time.\n     * <p/>\n     * <p>All locations supplied by the {@link LocationManager} to\n     * applications must be complete.\n     *\n     * @hide\n     * @see #makeComplete\n     */\n    public boolean isComplete() {\n        return false;\n    }\n\n    /**\n     * Helper to fill incomplete fields.\n     * <p/>\n     * <p>Used to assist in backwards compatibility with\n     * Location objects received from applications.\n     *\n     * @hide\n     * @see #isComplete\n     */\n    public void makeComplete() {\n    }\n\n    /**\n     * Returns additional provider-specific information about the\n     * location fix as a Bundle.  The keys and values are determined\n     * by the provider.  If no additional information is available,\n     * null is returned.\n     * <p/>\n     * <p> A number of common key/value pairs are listed\n     * below. Providers that use any of the keys on this list must\n     * provide the corresponding value as described below.\n     * <p/>\n     * <ul>\n     * <li> satellites - the number of satellites used to derive the fix\n     * </ul>\n     */\n    public Bundle getExtras() {\n        return null;\n    }\n\n    /**\n     * Sets the extra information associated with this fix to the\n     * given Bundle.\n     */\n    public void setExtras(Bundle extras) {\n    }\n\n    public void dump(Printer pw, String prefix) {\n    }\n\n    public static final Parcelable.Creator<Location> CREATOR =\n            new Parcelable.Creator<Location>() {\n                @Override\n                public Location createFromParcel(Parcel in) {\n                    return null;\n                }\n\n                @Override\n                public Location[] newArray(int size) {\n                    return null;\n                }\n            };\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(Parcel parcel, int flags) {\n    }\n\n    /**\n     * Returns one of the optional extra {@link Location}s that can be attached\n     * to this Location.\n     *\n     * @param key the key associated with the desired extra Location\n     * @return the extra Location, or null if unavailable\n     * @hide\n     */\n    public Location getExtraLocation(String key) {\n        return null;\n    }\n\n    /**\n     * Attaches an extra {@link Location} to this Location.\n     *\n     * @param key      the key associated with the Location extra\n     * @param location the Location to attach\n     * @hide\n     */\n    public void setExtraLocation(String key, Location value) {\n    }\n\n    /**\n     * Returns true if the Location came from a mock provider.\n     *\n     * @return true if this Location came from a mock provider, false otherwise\n     */\n    public boolean isFromMockProvider() {\n        return false;\n    }\n\n    /**\n     * Flag this Location as having come from a mock provider or not.\n     *\n     * @param isFromMockProvider true if this Location came from a mock provider, false otherwise\n     * @hide\n     */\n    public void setIsFromMockProvider(boolean isFromMockProvider) {\n    }\n}\n"
  },
  {
    "path": "play-services-location/core/system-api/src/main/java/android/location/LocationManager.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2007, The Android Open Source Project\n * SPDX-FileCopyrightText: 2014, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage android.location;\n\nimport android.app.PendingIntent;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.os.Looper;\n\nimport java.util.List;\n\n/**\n * This class provides access to the system location services.  These\n * services allow applications to obtain periodic updates of the\n * device's geographical location, or to fire an application-specified\n * {@link Intent} when the device enters the proximity of a given\n * geographical location.\n * <p/>\n * <p>You do not\n * instantiate this class directly; instead, retrieve it through\n * {@link android.content.Context#getSystemService\n * Context.getSystemService(Context.LOCATION_SERVICE)}.\n * <p/>\n * <p class=\"note\">Unless noted, all Location API methods require\n * the {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} or\n * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permissions.\n * If your application only has the coarse permission then it will not have\n * access to the GPS or passive location providers. Other providers will still\n * return location results, but the update rate will be throttled and the exact\n * location will be obfuscated to a coarse level of accuracy.\n */\n@SuppressWarnings(\"deprecation\")\npublic class LocationManager {\n\n    /**\n     * Name of the network location provider.\n     * <p>This provider determines location based on\n     * availability of cell tower and WiFi access points. Results are retrieved\n     * by means of a network lookup.\n     */\n    public static final String NETWORK_PROVIDER = \"network\";\n\n    /**\n     * Name of the GPS location provider.\n     * <p/>\n     * <p>This provider determines location using\n     * satellites. Depending on conditions, this provider may take a while to return\n     * a location fix. Requires the permission\n     * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.\n     * <p/>\n     * <p> The extras Bundle for the GPS location provider can contain the\n     * following key/value pairs:\n     * <ul>\n     * <li> satellites - the number of satellites used to derive the fix\n     * </ul>\n     */\n    public static final String GPS_PROVIDER = \"gps\";\n\n    /**\n     * A special location provider for receiving locations without actually initiating\n     * a location fix.\n     * <p/>\n     * <p>This provider can be used to passively receive location updates\n     * when other applications or services request them without actually requesting\n     * the locations yourself.  This provider will return locations generated by other\n     * providers.  You can query the {@link Location#getProvider()} method to determine\n     * the origin of the location update. Requires the permission\n     * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}, although if the GPS is\n     * not enabled this provider might only return coarse fixes.\n     */\n    public static final String PASSIVE_PROVIDER = \"passive\";\n\n    /**\n     * Name of the Fused location provider.\n     * <p/>\n     * <p>This provider combines inputs for all possible location sources\n     * to provide the best possible Location fix. It is implicitly\n     * used for all API's that involve the {@link LocationRequest}\n     * object.\n     *\n     * @hide\n     */\n    public static final String FUSED_PROVIDER = \"fused\";\n\n    /**\n     * Key used for the Bundle extra holding a boolean indicating whether\n     * a proximity alert is entering (true) or exiting (false)..\n     */\n    public static final String KEY_PROXIMITY_ENTERING = \"entering\";\n\n    /**\n     * Key used for a Bundle extra holding an Integer status value\n     * when a status change is broadcast using a PendingIntent.\n     */\n    public static final String KEY_STATUS_CHANGED = \"status\";\n\n    /**\n     * Key used for a Bundle extra holding an Boolean status value\n     * when a provider enabled/disabled event is broadcast using a PendingIntent.\n     */\n    public static final String KEY_PROVIDER_ENABLED = \"providerEnabled\";\n\n    /**\n     * Key used for a Bundle extra holding a Location value\n     * when a location change is broadcast using a PendingIntent.\n     */\n    public static final String KEY_LOCATION_CHANGED = \"location\";\n\n    /**\n     * Broadcast intent action indicating that the GPS has either been\n     * enabled or disabled. An intent extra provides this state as a boolean,\n     * where {@code true} means enabled.\n     *\n     * @hide\n     * @see #EXTRA_GPS_ENABLED\n     */\n    public static final String GPS_ENABLED_CHANGE_ACTION =\n            \"android.location.GPS_ENABLED_CHANGE\";\n\n    /**\n     * Broadcast intent action when the configured location providers\n     * change. For use with {@link #isProviderEnabled(String)}. If you're interacting with the\n     * {@link android.provider.Settings.Secure#LOCATION_MODE} API, use {@link #MODE_CHANGED_ACTION}\n     * instead.\n     */\n    public static final String PROVIDERS_CHANGED_ACTION =\n            \"android.location.PROVIDERS_CHANGED\";\n\n    /**\n     * Broadcast intent action when {@link android.provider.Settings.Secure#LOCATION_MODE} changes.\n     * For use with the {@link android.provider.Settings.Secure#LOCATION_MODE} API.\n     * If you're interacting with {@link #isProviderEnabled(String)}, use\n     * {@link #PROVIDERS_CHANGED_ACTION} instead.\n     * <p/>\n     * In the future, there may be mode changes that do not result in\n     * {@link #PROVIDERS_CHANGED_ACTION} broadcasts.\n     */\n    public static final String MODE_CHANGED_ACTION = \"android.location.MODE_CHANGED\";\n\n    /**\n     * Broadcast intent action indicating that the GPS has either started or\n     * stopped receiving GPS fixes. An intent extra provides this state as a\n     * boolean, where {@code true} means that the GPS is actively receiving fixes.\n     *\n     * @hide\n     * @see #EXTRA_GPS_ENABLED\n     */\n    public static final String GPS_FIX_CHANGE_ACTION =\n            \"android.location.GPS_FIX_CHANGE\";\n\n    /**\n     * The lookup key for a boolean that indicates whether GPS is enabled or\n     * disabled. {@code true} means GPS is enabled. Retrieve it with\n     * {@link android.content.Intent#getBooleanExtra(String, boolean)}.\n     *\n     * @hide\n     */\n    public static final String EXTRA_GPS_ENABLED = \"enabled\";\n\n    /**\n     * Broadcast intent action indicating that a high power location requests\n     * has either started or stopped being active.  The current state of\n     * active location requests should be read from AppOpsManager using\n     * {@code OP_MONITOR_HIGH_POWER_LOCATION}.\n     *\n     * @hide\n     */\n    public static final String HIGH_POWER_REQUEST_CHANGE_ACTION =\n            \"android.location.HIGH_POWER_REQUEST_CHANGE\";\n\n    /**\n     * @hide - hide this constructor because it has a parameter\n     * of type ILocationManager, which is a system private class. The\n     * right way to create an instance of this class is using the\n     * factory Context.getSystemService.\n     */\n    public LocationManager(Context context, Object service) {\n    }\n\n    /**\n     * Returns a list of the names of all known location providers.\n     * <p>All providers are returned, including ones that are not permitted to\n     * be accessed by the calling activity or are currently disabled.\n     *\n     * @return list of Strings containing names of the provider\n     */\n    public List<String> getAllProviders() {\n        return null;\n    }\n\n    /**\n     * Returns a list of the names of location providers.\n     *\n     * @param enabledOnly if true then only the providers which are currently\n     *                    enabled are returned.\n     * @return list of Strings containing names of the providers\n     */\n    public List<String> getProviders(boolean enabledOnly) {\n        return null;\n    }\n\n    /**\n     * Returns the information associated with the location provider of the\n     * given name, or null if no provider exists by that name.\n     *\n     * @param name the provider name\n     * @return a LocationProvider, or null\n     * @throws IllegalArgumentException if name is null or does not exist\n     * @throws SecurityException        if the caller is not permitted to access the\n     *                                  given provider.\n     */\n    public LocationProvider getProvider(String name) {\n        return null;\n    }\n\n    /**\n     * Returns a list of the names of LocationProviders that satisfy the given\n     * criteria, or null if none do.  Only providers that are permitted to be\n     * accessed by the calling activity will be returned.\n     *\n     * @param criteria    the criteria that the returned providers must match\n     * @param enabledOnly if true then only the providers which are currently\n     *                    enabled are returned.\n     * @return list of Strings containing names of the providers\n     */\n    public List<String> getProviders(Criteria criteria, boolean enabledOnly) {\n        return null;\n    }\n\n    /**\n     * Returns the name of the provider that best meets the given criteria. Only providers\n     * that are permitted to be accessed by the calling activity will be\n     * returned.  If several providers meet the criteria, the one with the best\n     * accuracy is returned.  If no provider meets the criteria,\n     * the criteria are loosened in the following sequence:\n     * <p/>\n     * <ul>\n     * <li> power requirement\n     * <li> accuracy\n     * <li> bearing\n     * <li> speed\n     * <li> altitude\n     * </ul>\n     * <p/>\n     * <p> Note that the requirement on monetary cost is not removed\n     * in this process.\n     *\n     * @param criteria    the criteria that need to be matched\n     * @param enabledOnly if true then only a provider that is currently enabled is returned\n     * @return name of the provider that best matches the requirements\n     */\n    public String getBestProvider(Criteria criteria, boolean enabledOnly) {\n        return null;\n    }\n\n    /**\n     * Register for location updates using the named provider, and a\n     * pending intent.\n     * <p/>\n     * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}\n     * for more detail on how to use this method.\n     *\n     * @param provider    the name of the provider with which to register\n     * @param minTime     minimum time interval between location updates, in milliseconds\n     * @param minDistance minimum distance between location updates, in meters\n     * @param listener    a {@link LocationListener} whose\n     *                    {@link LocationListener#onLocationChanged} method will be called for\n     *                    each location update\n     * @throws IllegalArgumentException if provider is null or doesn't exist\n     *                                  on this device\n     * @throws IllegalArgumentException if listener is null\n     * @throws RuntimeException         if the calling thread has no Looper\n     * @throws SecurityException        if no suitable permission is present\n     */\n    public void requestLocationUpdates(String provider, long minTime, float minDistance,\n            LocationListener listener) {\n    }\n\n    /**\n     * Register for location updates using the named provider, and a callback on\n     * the specified looper thread.\n     * <p/>\n     * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}\n     * for more detail on how to use this method.\n     *\n     * @param provider    the name of the provider with which to register\n     * @param minTime     minimum time interval between location updates, in milliseconds\n     * @param minDistance minimum distance between location updates, in meters\n     * @param listener    a {@link LocationListener} whose\n     *                    {@link LocationListener#onLocationChanged} method will be called for\n     *                    each location update\n     * @param looper      a Looper object whose message queue will be used to\n     *                    implement the callback mechanism, or null to make callbacks on the calling\n     *                    thread\n     * @throws IllegalArgumentException if provider is null or doesn't exist\n     * @throws IllegalArgumentException if listener is null\n     * @throws SecurityException        if no suitable permission is present\n     */\n    public void requestLocationUpdates(String provider, long minTime, float minDistance,\n            LocationListener listener, Looper looper) {\n    }\n\n    /**\n     * Register for location updates using a Criteria, and a callback\n     * on the specified looper thread.\n     * <p/>\n     * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}\n     * for more detail on how to use this method.\n     *\n     * @param minTime     minimum time interval between location updates, in milliseconds\n     * @param minDistance minimum distance between location updates, in meters\n     * @param criteria    contains parameters for the location manager to choose the\n     *                    appropriate provider and parameters to compute the location\n     * @param listener    a {@link LocationListener} whose\n     *                    {@link LocationListener#onLocationChanged} method will be called for\n     *                    each location update\n     * @param looper      a Looper object whose message queue will be used to\n     *                    implement the callback mechanism, or null to make callbacks on the calling\n     *                    thread\n     * @throws IllegalArgumentException if criteria is null\n     * @throws IllegalArgumentException if listener is null\n     * @throws SecurityException        if no suitable permission is present\n     */\n    public void requestLocationUpdates(long minTime, float minDistance, Criteria criteria,\n            LocationListener listener, Looper looper) {\n    }\n\n    /**\n     * Register for location updates using the named provider, and a\n     * pending intent.\n     * <p/>\n     * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}\n     * for more detail on how to use this method.\n     *\n     * @param provider    the name of the provider with which to register\n     * @param minTime     minimum time interval between location updates, in milliseconds\n     * @param minDistance minimum distance between location updates, in meters\n     * @param intent      a {@link PendingIntent} to be sent for each location update\n     * @throws IllegalArgumentException if provider is null or doesn't exist\n     *                                  on this device\n     * @throws IllegalArgumentException if intent is null\n     * @throws SecurityException        if no suitable permission is present\n     */\n    public void requestLocationUpdates(String provider, long minTime, float minDistance,\n            PendingIntent intent) {\n    }\n\n    /**\n     * Register for location updates using a Criteria and pending intent.\n     * <p/>\n     * <p>The <code>requestLocationUpdates()</code> and\n     * <code>requestSingleUpdate()</code> register the current activity to be\n     * updated periodically by the named provider, or by the provider matching\n     * the specified {@link Criteria}, with location and status updates.\n     * <p/>\n     * <p> It may take a while to receive the first location update. If\n     * an immediate location is required, applications may use the\n     * {@link #getLastKnownLocation(String)} method.\n     * <p/>\n     * <p> Location updates are received either by {@link LocationListener}\n     * callbacks, or by broadcast intents to a supplied {@link PendingIntent}.\n     * <p/>\n     * <p> If the caller supplied a pending intent, then location updates\n     * are sent with a key of {@link #KEY_LOCATION_CHANGED} and a\n     * {@link android.location.Location} value.\n     * <p/>\n     * <p> The location update interval can be controlled using the minTime parameter.\n     * The elapsed time between location updates will never be less than\n     * minTime, although it can be more depending on the Location Provider\n     * implementation and the update interval requested by other applications.\n     * <p/>\n     * <p> Choosing a sensible value for minTime is important to conserve\n     * battery life. Each location update requires power from\n     * GPS, WIFI, Cell and other radios. Select a minTime value as high as\n     * possible while still providing a reasonable user experience.\n     * If your application is not in the foreground and showing\n     * location to the user then your application should avoid using an active\n     * provider (such as {@link #NETWORK_PROVIDER} or {@link #GPS_PROVIDER}),\n     * but if you insist then select a minTime of 5 * 60 * 1000 (5 minutes)\n     * or greater. If your application is in the foreground and showing\n     * location to the user then it is appropriate to select a faster\n     * update interval.\n     * <p/>\n     * <p> The minDistance parameter can also be used to control the\n     * frequency of location updates. If it is greater than 0 then the\n     * location provider will only send your application an update when\n     * the location has changed by at least minDistance meters, AND\n     * at least minTime milliseconds have passed. However it is more\n     * difficult for location providers to save power using the minDistance\n     * parameter, so minTime should be the primary tool to conserving battery\n     * life.\n     * <p/>\n     * <p> If your application wants to passively observe location\n     * updates triggered by other applications, but not consume\n     * any additional power otherwise, then use the {@link #PASSIVE_PROVIDER}\n     * This provider does not actively turn on or modify active location\n     * providers, so you do not need to be as careful about minTime and\n     * minDistance. However if your application performs heavy work\n     * on a location update (such as network activity) then you should\n     * select non-zero values for minTime and/or minDistance to rate-limit\n     * your update frequency in the case another application enables a\n     * location provider with extremely fast updates.\n     * <p/>\n     * <p>In case the provider is disabled by the user, updates will stop,\n     * and a provider availability update will be sent.\n     * As soon as the provider is enabled again,\n     * location updates will immediately resume and a provider availability\n     * update sent. Providers can also send status updates, at any time,\n     * with extra's specific to the provider. If a callback was supplied\n     * then status and availability updates are via\n     * {@link LocationListener#onProviderDisabled},\n     * {@link LocationListener#onProviderEnabled} or\n     * {@link LocationListener#onStatusChanged}. Alternately, if a\n     * pending intent was supplied then status and availability updates\n     * are broadcast intents with extra keys of\n     * {@link #KEY_PROVIDER_ENABLED} or {@link #KEY_STATUS_CHANGED}.\n     * <p/>\n     * <p> If a {@link LocationListener} is used but with no Looper specified\n     * then the calling thread must already\n     * be a {@link android.os.Looper} thread such as the main thread of the\n     * calling Activity. If a Looper is specified with a {@link LocationListener}\n     * then callbacks are made on the supplied Looper thread.\n     * <p/>\n     * <p class=\"note\"> Prior to Jellybean, the minTime parameter was\n     * only a hint, and some location provider implementations ignored it.\n     * From Jellybean and onwards it is mandatory for Android compatible\n     * devices to observe both the minTime and minDistance parameters.\n     *\n     * @param minTime     minimum time interval between location updates, in milliseconds\n     * @param minDistance minimum distance between location updates, in meters\n     * @param criteria    contains parameters for the location manager to choose the\n     *                    appropriate provider and parameters to compute the location\n     * @param intent      a {@link PendingIntent} to be sent for each location update\n     * @throws IllegalArgumentException if criteria is null\n     * @throws IllegalArgumentException if intent is null\n     * @throws SecurityException        if no suitable permission is present\n     */\n    public void requestLocationUpdates(long minTime, float minDistance, Criteria criteria,\n            PendingIntent intent) {\n    }\n\n    /**\n     * Register for a single location update using the named provider and\n     * a callback.\n     * <p/>\n     * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}\n     * for more detail on how to use this method.\n     *\n     * @param provider the name of the provider with which to register\n     * @param listener a {@link LocationListener} whose\n     *                 {@link LocationListener#onLocationChanged} method will be called when\n     *                 the location update is available\n     * @param looper   a Looper object whose message queue will be used to\n     *                 implement the callback mechanism, or null to make callbacks on the calling\n     *                 thread\n     * @throws IllegalArgumentException if provider is null or doesn't exist\n     * @throws IllegalArgumentException if listener is null\n     * @throws SecurityException        if no suitable permission is present\n     */\n    public void requestSingleUpdate(String provider, LocationListener listener, Looper looper) {\n    }\n\n    /**\n     * Register for a single location update using a Criteria and\n     * a callback.\n     * <p/>\n     * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}\n     * for more detail on how to use this method.\n     *\n     * @param criteria contains parameters for the location manager to choose the\n     *                 appropriate provider and parameters to compute the location\n     * @param listener a {@link LocationListener} whose\n     *                 {@link LocationListener#onLocationChanged} method will be called when\n     *                 the location update is available\n     * @param looper   a Looper object whose message queue will be used to\n     *                 implement the callback mechanism, or null to make callbacks on the calling\n     *                 thread\n     * @throws IllegalArgumentException if criteria is null\n     * @throws IllegalArgumentException if listener is null\n     * @throws SecurityException        if no suitable permission is present\n     */\n    public void requestSingleUpdate(Criteria criteria, LocationListener listener, Looper looper) {\n    }\n\n    /**\n     * Register for a single location update using a named provider and pending intent.\n     * <p/>\n     * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}\n     * for more detail on how to use this method.\n     *\n     * @param provider the name of the provider with which to register\n     * @param intent   a {@link PendingIntent} to be sent for the location update\n     * @throws IllegalArgumentException if provider is null or doesn't exist\n     * @throws IllegalArgumentException if intent is null\n     * @throws SecurityException        if no suitable permission is present\n     */\n    public void requestSingleUpdate(String provider, PendingIntent intent) {\n    }\n\n    /**\n     * Register for a single location update using a Criteria and pending intent.\n     * <p/>\n     * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}\n     * for more detail on how to use this method.\n     *\n     * @param criteria contains parameters for the location manager to choose the\n     *                 appropriate provider and parameters to compute the location\n     * @param intent   a {@link PendingIntent} to be sent for the location update\n     * @throws IllegalArgumentException if provider is null or doesn't exist\n     * @throws IllegalArgumentException if intent is null\n     * @throws SecurityException        if no suitable permission is present\n     */\n    public void requestSingleUpdate(Criteria criteria, PendingIntent intent) {\n    }\n\n    /**\n     * Register for fused location updates using a LocationRequest and callback.\n     * <p/>\n     * <p>Upon a location update, the system delivers the new {@link Location} to the\n     * provided {@link LocationListener}, by calling its {@link\n     * LocationListener#onLocationChanged} method.</p>\n     * <p/>\n     * <p>The system will automatically select and enable the best providers\n     * to compute a location for your application. It may use only passive\n     * locations, or just a single location source, or it may fuse together\n     * multiple location sources in order to produce the best possible\n     * result, depending on the quality of service requested in the\n     * {@link LocationRequest}.\n     * <p/>\n     * <p>LocationRequest can be null, in which case the system will choose\n     * default, low power parameters for location updates. You will occasionally\n     * receive location updates as available, without a major power impact on the\n     * system. If your application just needs an occasional location update\n     * without any strict demands, then pass a null LocationRequest.\n     * <p/>\n     * <p>Only one LocationRequest can be registered for each unique callback\n     * or pending intent. So a subsequent request with the same callback or\n     * pending intent will over-write the previous LocationRequest.\n     * <p/>\n     * <p> If a pending intent is supplied then location updates\n     * are sent with a key of {@link #KEY_LOCATION_CHANGED} and a\n     * {@link android.location.Location} value. If a callback is supplied\n     * then location updates are made using the\n     * {@link LocationListener#onLocationChanged} callback, on the specified\n     * Looper thread. If a {@link LocationListener} is used\n     * but with a null Looper then the calling thread must already\n     * be a {@link android.os.Looper} thread (such as the main thread) and\n     * callbacks will occur on this thread.\n     * <p/>\n     * <p> Provider status updates and availability updates are deprecated\n     * because the system is performing provider fusion on the applications\n     * behalf. So {@link LocationListener#onProviderDisabled},\n     * {@link LocationListener#onProviderEnabled}, {@link LocationListener#onStatusChanged}\n     * will not be called, and intents with extra keys of\n     * {@link #KEY_PROVIDER_ENABLED} or {@link #KEY_STATUS_CHANGED} will not\n     * be received.\n     * <p/>\n     * <p> To unregister for Location updates, use: {@link #removeUpdates(LocationListener)}.\n     *\n     * @param request  quality of service required, null for default low power\n     * @param listener a {@link LocationListener} whose\n     *                 {@link LocationListener#onLocationChanged} method will be called when\n     *                 the location update is available\n     * @param looper   a Looper object whose message queue will be used to\n     *                 implement the callback mechanism, or null to make callbacks on the calling\n     *                 thread\n     * @throws IllegalArgumentException if listener is null\n     * @throws SecurityException        if no suitable permission is present\n     * @hide\n     */\n    public void requestLocationUpdates(LocationRequest request, LocationListener listener,\n            Looper looper) {\n    }\n\n    /**\n     * Register for fused location updates using a LocationRequest and a pending intent.\n     * <p/>\n     * <p>Upon a location update, the system delivers the new {@link Location} with your provided\n     * {@link PendingIntent}, as the value for {@link LocationManager#KEY_LOCATION_CHANGED}\n     * in the intent's extras.</p>\n     * <p/>\n     * <p> To unregister for Location updates, use: {@link #removeUpdates(PendingIntent)}.\n     * <p/>\n     * <p> See {@link #requestLocationUpdates(LocationRequest, LocationListener, Looper)}\n     * for more detail.\n     *\n     * @param request quality of service required, null for default low power\n     * @param intent  a {@link PendingIntent} to be sent for the location update\n     * @throws IllegalArgumentException if intent is null\n     * @throws SecurityException        if no suitable permission is present\n     * @hide\n     */\n    public void requestLocationUpdates(LocationRequest request, PendingIntent intent) {\n    }\n\n    /**\n     * Removes all location updates for the specified LocationListener.\n     * <p/>\n     * <p>Following this call, updates will no longer\n     * occur for this listener.\n     *\n     * @param listener listener object that no longer needs location updates\n     * @throws IllegalArgumentException if listener is null\n     */\n    public void removeUpdates(LocationListener listener) {\n    }\n\n    /**\n     * Removes all location updates for the specified pending intent.\n     * <p/>\n     * <p>Following this call, updates will no longer for this pending intent.\n     *\n     * @param intent pending intent object that no longer needs location updates\n     * @throws IllegalArgumentException if intent is null\n     */\n    public void removeUpdates(PendingIntent intent) {\n    }\n\n    /**\n     * Set a proximity alert for the location given by the position\n     * (latitude, longitude) and the given radius.\n     * <p/>\n     * <p> When the device\n     * detects that it has entered or exited the area surrounding the\n     * location, the given PendingIntent will be used to create an Intent\n     * to be fired.\n     * <p/>\n     * <p> The fired Intent will have a boolean extra added with key\n     * {@link #KEY_PROXIMITY_ENTERING}. If the value is true, the device is\n     * entering the proximity region; if false, it is exiting.\n     * <p/>\n     * <p> Due to the approximate nature of position estimation, if the\n     * device passes through the given area briefly, it is possible\n     * that no Intent will be fired.  Similarly, an Intent could be\n     * fired if the device passes very close to the given area but\n     * does not actually enter it.\n     * <p/>\n     * <p> After the number of milliseconds given by the expiration\n     * parameter, the location manager will delete this proximity\n     * alert and no longer monitor it.  A value of -1 indicates that\n     * there should be no expiration time.\n     * <p/>\n     * <p> Internally, this method uses both {@link #NETWORK_PROVIDER}\n     * and {@link #GPS_PROVIDER}.\n     * <p/>\n     * <p>Before API version 17, this method could be used with\n     * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} or\n     * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}.\n     * From API version 17 and onwards, this method requires\n     * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission.\n     *\n     * @param latitude   the latitude of the central point of the\n     *                   alert region\n     * @param longitude  the longitude of the central point of the\n     *                   alert region\n     * @param radius     the radius of the central point of the\n     *                   alert region, in meters\n     * @param expiration time for this proximity alert, in milliseconds,\n     *                   or -1 to indicate no expiration\n     * @param intent     a PendingIntent that will be used to generate an Intent to\n     *                   fire when entry to or exit from the alert region is detected\n     * @throws SecurityException if {@link android.Manifest.permission#ACCESS_FINE_LOCATION}\n     *                           permission is not present\n     */\n    public void addProximityAlert(double latitude, double longitude, float radius, long expiration,\n            PendingIntent intent) {\n    }\n\n    /**\n     * Add a geofence with the specified LocationRequest quality of service.\n     * <p/>\n     * <p> When the device\n     * detects that it has entered or exited the area surrounding the\n     * location, the given PendingIntent will be used to create an Intent\n     * to be fired.\n     * <p/>\n     * <p> The fired Intent will have a boolean extra added with key\n     * {@link #KEY_PROXIMITY_ENTERING}. If the value is true, the device is\n     * entering the proximity region; if false, it is exiting.\n     * <p/>\n     * <p> The geofence engine fuses results from all location providers to\n     * provide the best balance between accuracy and power. Applications\n     * can choose the quality of service required using the\n     * {@link LocationRequest} object. If it is null then a default,\n     * low power geo-fencing implementation is used. It is possible to cross\n     * a geo-fence without notification, but the system will do its best\n     * to detect, using {@link LocationRequest} as a hint to trade-off\n     * accuracy and power.\n     * <p/>\n     * <p> The power required by the geofence engine can depend on many factors,\n     * such as quality and interval requested in {@link LocationRequest},\n     * distance to nearest geofence and current device velocity.\n     *\n     * @param request quality of service required, null for default low power\n     * @param fence   a geographical description of the geofence area\n     * @param intent  pending intent to receive geofence updates\n     * @throws IllegalArgumentException if fence is null\n     * @throws IllegalArgumentException if intent is null\n     * @throws SecurityException        if {@link android.Manifest.permission#ACCESS_FINE_LOCATION}\n     *                                  permission is not present\n     * @hide\n     */\n    public void addGeofence(LocationRequest request, Geofence fence, PendingIntent intent) {\n    }\n\n    /**\n     * Removes the proximity alert with the given PendingIntent.\n     * <p/>\n     * <p>Before API version 17, this method could be used with\n     * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} or\n     * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}.\n     * From API version 17 and onwards, this method requires\n     * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission.\n     *\n     * @param intent the PendingIntent that no longer needs to be notified of\n     *               proximity alerts\n     * @throws IllegalArgumentException if intent is null\n     * @throws SecurityException        if {@link android.Manifest.permission#ACCESS_FINE_LOCATION}\n     *                                  permission is not present\n     */\n    public void removeProximityAlert(PendingIntent intent) {\n    }\n\n    /**\n     * Remove a single geofence.\n     * <p/>\n     * <p>This removes only the specified geofence associated with the\n     * specified pending intent. All other geofences remain unchanged.\n     *\n     * @param fence  a geofence previously passed to {@link #addGeofence}\n     * @param intent a pending intent previously passed to {@link #addGeofence}\n     * @throws IllegalArgumentException if fence is null\n     * @throws IllegalArgumentException if intent is null\n     * @throws SecurityException        if {@link android.Manifest.permission#ACCESS_FINE_LOCATION}\n     *                                  permission is not present\n     * @hide\n     */\n    public void removeGeofence(Geofence fence, PendingIntent intent) {\n    }\n\n    /**\n     * Remove all geofences registered to the specified pending intent.\n     *\n     * @param intent a pending intent previously passed to {@link #addGeofence}\n     * @throws IllegalArgumentException if intent is null\n     * @throws SecurityException        if {@link android.Manifest.permission#ACCESS_FINE_LOCATION}\n     *                                  permission is not present\n     * @hide\n     */\n    public void removeAllGeofences(PendingIntent intent) {\n    }\n\n    /**\n     * Returns the current enabled/disabled status of the given provider.\n     * <p/>\n     * <p>If the user has enabled this provider in the Settings menu, true\n     * is returned otherwise false is returned\n     * <p/>\n     * <p>Callers should instead use\n     * {@link android.provider.Settings.Secure#LOCATION_MODE}\n     * unless they depend on provider-specific APIs such as\n     * {@link #requestLocationUpdates(String, long, float, LocationListener)}.\n     * <p/>\n     * <p/>\n     * Before API version {@link android.os.Build.VERSION_CODES#LOLLIPOP}, this\n     * method would throw {@link SecurityException} if the location permissions\n     * were not sufficient to use the specified provider.\n     *\n     * @param provider the name of the provider\n     * @return true if the provider exists and is enabled\n     * @throws IllegalArgumentException if provider is null\n     */\n    public boolean isProviderEnabled(String provider) {\n        return false;\n    }\n\n    /**\n     * Get the last known location.\n     * <p/>\n     * <p>This location could be very old so use\n     * {@link Location#getElapsedRealtimeNanos} to calculate its age. It can\n     * also return null if no previous location is available.\n     * <p/>\n     * <p>Always returns immediately.\n     *\n     * @return The last known location, or null if not available\n     * @throws SecurityException if no suitable permission is present\n     * @hide\n     */\n    public Location getLastLocation() {\n        return null;\n    }\n\n    /**\n     * Returns a Location indicating the data from the last known\n     * location fix obtained from the given provider.\n     * <p/>\n     * <p> This can be done\n     * without starting the provider.  Note that this location could\n     * be out-of-date, for example if the device was turned off and\n     * moved to another location.\n     * <p/>\n     * <p> If the provider is currently disabled, null is returned.\n     *\n     * @param provider the name of the provider\n     * @return the last known location for the provider, or null\n     * @throws SecurityException        if no suitable permission is present\n     * @throws IllegalArgumentException if provider is null or doesn't exist\n     */\n    public Location getLastKnownLocation(String provider) {\n        return null;\n    }\n\n    // --- Mock provider support ---\n    // TODO: It would be fantastic to deprecate mock providers entirely, and replace\n    // with something closer to LocationProviderBase.java\n\n    /**\n     * Creates a mock location provider and adds it to the set of active providers.\n     *\n     * @param name the provider name\n     * @throws SecurityException        if the ACCESS_MOCK_LOCATION permission is not present\n     *                                  or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION\n     *                                  Settings.Secure.ALLOW_MOCK_LOCATION} system setting is not enabled\n     * @throws IllegalArgumentException if a provider with the given name already exists\n     */\n    public void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite,\n            boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude,\n            boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) {\n    }\n\n    /**\n     * Removes the mock location provider with the given name.\n     *\n     * @param provider the provider name\n     * @throws SecurityException        if the ACCESS_MOCK_LOCATION permission is not present\n     *                                  or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION\n     *                                  Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled\n     * @throws IllegalArgumentException if no provider with the given name exists\n     */\n    public void removeTestProvider(String provider) {\n    }\n\n    /**\n     * Sets a mock location for the given provider.\n     * <p>This location will be used in place of any actual location from the provider.\n     * The location object must have a minimum number of fields set to be\n     * considered a valid LocationProvider Location, as per documentation\n     * on {@link Location} class.\n     *\n     * @param provider the provider name\n     * @param loc      the mock location\n     * @throws SecurityException        if the ACCESS_MOCK_LOCATION permission is not present\n     *                                  or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION\n     *                                  Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled\n     * @throws IllegalArgumentException if no provider with the given name exists\n     * @throws IllegalArgumentException if the location is incomplete\n     */\n    public void setTestProviderLocation(String provider, Location loc) {\n    }\n\n    /**\n     * Removes any mock location associated with the given provider.\n     *\n     * @param provider the provider name\n     * @throws SecurityException        if the ACCESS_MOCK_LOCATION permission is not present\n     *                                  or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION\n     *                                  Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled\n     * @throws IllegalArgumentException if no provider with the given name exists\n     */\n    public void clearTestProviderLocation(String provider) {\n    }\n\n    /**\n     * Sets a mock enabled value for the given provider.  This value will be used in place\n     * of any actual value from the provider.\n     *\n     * @param provider the provider name\n     * @param enabled  the mock enabled value\n     * @throws SecurityException        if the ACCESS_MOCK_LOCATION permission is not present\n     *                                  or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION\n     *                                  Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled\n     * @throws IllegalArgumentException if no provider with the given name exists\n     */\n    public void setTestProviderEnabled(String provider, boolean enabled) {\n    }\n\n    /**\n     * Removes any mock enabled value associated with the given provider.\n     *\n     * @param provider the provider name\n     * @throws SecurityException        if the ACCESS_MOCK_LOCATION permission is not present\n     *                                  or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION\n     *                                  Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled\n     * @throws IllegalArgumentException if no provider with the given name exists\n     */\n    public void clearTestProviderEnabled(String provider) {\n    }\n\n    /**\n     * Sets mock status values for the given provider.  These values will be used in place\n     * of any actual values from the provider.\n     *\n     * @param provider   the provider name\n     * @param status     the mock status\n     * @param extras     a Bundle containing mock extras\n     * @param updateTime the mock update time\n     * @throws SecurityException        if the ACCESS_MOCK_LOCATION permission is not present\n     *                                  or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION\n     *                                  Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled\n     * @throws IllegalArgumentException if no provider with the given name exists\n     */\n    public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {\n    }\n\n    /**\n     * Removes any mock status values associated with the given provider.\n     *\n     * @param provider the provider name\n     * @throws SecurityException        if the ACCESS_MOCK_LOCATION permission is not present\n     *                                  or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION\n     *                                  Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled\n     * @throws IllegalArgumentException if no provider with the given name exists\n     */\n    public void clearTestProviderStatus(String provider) {\n    }\n\n    // --- GPS-specific support ---\n\n    /**\n     * Adds a GPS status listener.\n     *\n     * @param listener GPS status listener object to register\n     * @return true if the listener was successfully added\n     * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present\n     */\n    public boolean addGpsStatusListener(GpsStatus.Listener listener) {\n        return false;\n    }\n\n    /**\n     * Removes a GPS status listener.\n     *\n     * @param listener GPS status listener object to remove\n     */\n    public void removeGpsStatusListener(GpsStatus.Listener listener) {\n    }\n\n    /**\n     * Adds an NMEA listener.\n     *\n     * @param listener a {@link GpsStatus.NmeaListener} object to register\n     * @return true if the listener was successfully added\n     * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present\n     */\n    public boolean addNmeaListener(GpsStatus.NmeaListener listener) {\n        return false;\n    }\n\n    /**\n     * Removes an NMEA listener.\n     *\n     * @param listener a {@link GpsStatus.NmeaListener} object to remove\n     */\n    public void removeNmeaListener(GpsStatus.NmeaListener listener) {\n    }\n\n//    /**\n//     * Adds a GPS Measurement listener.\n//     *\n//     * @param listener a {@link GpsMeasurementsEvent.Listener} object to register.\n//     * @return {@code true} if the listener was successfully registered, {@code false} otherwise.\n//     * @hide\n//     */\n//    public boolean addGpsMeasurementListener(GpsMeasurementsEvent.Listener listener) {\n//        return false;\n//    }\n//\n//    /**\n//     * Removes a GPS Measurement listener.\n//     *\n//     * @param listener a {@link GpsMeasurementsEvent.Listener} object to remove.\n//     * @hide\n//     */\n//    public void removeGpsMeasurementListener(GpsMeasurementsEvent.Listener listener) {\n//    }\n//\n//    /**\n//     * Adds a GPS Navigation Message listener.\n//     *\n//     * @param listener a {@link GpsNavigationMessageEvent.Listener} object to register.\n//     * @return {@code true} if the listener was successfully registered, {@code false} otherwise.\n//     * @hide\n//     */\n//    public boolean addGpsNavigationMessageListener(GpsNavigationMessageEvent.Listener listener) {\n//        return false;\n//    }\n//\n//    /**\n//     * Removes a GPS Navigation Message listener.\n//     *\n//     * @param listener a {@link GpsNavigationMessageEvent.Listener} object to remove.\n//     * @hide\n//     */\n//    public void removeGpsNavigationMessageListener(\n//            GpsNavigationMessageEvent.Listener listener) {\n//    }\n\n    /**\n     * Retrieves information about the current status of the GPS engine.\n     * This should only be called from the {@link GpsStatus.Listener#onGpsStatusChanged}\n     * callback to ensure that the data is copied atomically.\n     * <p/>\n     * The caller may either pass in a {@link GpsStatus} object to set with the latest\n     * status information, or pass null to create a new {@link GpsStatus} object.\n     *\n     * @param status object containing GPS status details, or null.\n     * @return status object containing updated GPS status.\n     */\n    public GpsStatus getGpsStatus(GpsStatus status) {\n        return null;\n    }\n\n    /**\n     * Sends additional commands to a location provider.\n     * Can be used to support provider specific extensions to the Location Manager API\n     *\n     * @param provider name of the location provider.\n     * @param command  name of the command to send to the provider.\n     * @param extras   optional arguments for the command (or null).\n     *                 The provider may optionally fill the extras Bundle with results from the command.\n     * @return true if the command succeeds.\n     */\n    public boolean sendExtraCommand(String provider, String command, Bundle extras) {\n        return false;\n    }\n\n    /**\n     * Used by NetInitiatedActivity to report user response\n     * for network initiated GPS fix requests.\n     *\n     * @hide\n     */\n    public boolean sendNiResponse(int notifId, int userResponse) {\n        return false;\n    }\n}\n"
  },
  {
    "path": "play-services-location/core/system-api/src/main/java/android/location/LocationRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2012, The Android Open Source Project\n * SPDX-FileCopyrightText: 2014, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage android.location;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.os.SystemClock;\nimport android.os.WorkSource;\n\n/**\n * A data object that contains quality of service parameters for requests\n * to the {@link LocationManager}.\n * <p/>\n * <p>LocationRequest objects are used to request a quality of service\n * for location updates from the Location Manager.\n * <p/>\n * <p>For example, if your application wants high accuracy location\n * it should create a location request with {@link #setQuality} set to\n * {@link #ACCURACY_FINE} or {@link #POWER_HIGH}, and it should set\n * {@link #setInterval} to less than one second. This would be\n * appropriate for mapping applications that are showing your location\n * in real-time.\n * <p/>\n * <p>At the other extreme, if you want negligible power\n * impact, but to still receive location updates when available, then use\n * {@link #setQuality} with {@link #POWER_NONE}. With this request your\n * application will not trigger (and therefore will not receive any\n * power blame) any location updates, but will receive locations\n * triggered by other applications. This would be appropriate for\n * applications that have no firm requirement for location, but can\n * take advantage when available.\n * <p/>\n * <p>In between these two extremes is a very common use-case, where\n * applications definitely want to receive\n * updates at a specified interval, and can receive them faster when\n * available, but still want a low power impact. These applications\n * should consider {@link #POWER_LOW} combined with a faster\n * {@link #setFastestInterval} (such as 1 minute) and a slower\n * {@link #setInterval} (such as 60 minutes). They will only be assigned\n * power blame for the interval set by {@link #setInterval}, but can\n * still receive locations triggered by other applications at a rate up\n * to {@link #setFastestInterval}. This style of request is appropriate for\n * many location aware applications, including background usage. Do be\n * careful to also throttle {@link #setFastestInterval} if you perform\n * heavy-weight work after receiving an update - such as using the network.\n * <p/>\n * <p>Activities should strongly consider removing all location\n * request when entering the background\n * (for example at {@link android.app.Activity#onPause}), or\n * at least swap the request to a larger interval and lower quality.\n * Future version of the location manager may automatically perform background\n * throttling on behalf of applications.\n * <p/>\n * <p>Applications cannot specify the exact location sources that are\n * used by Android's <em>Fusion Engine</em>. In fact, the system\n * may have multiple location sources (providers) running and may\n * fuse the results from several sources into a single Location object.\n * <p/>\n * <p>Location requests from applications with\n * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} and not\n * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} will\n * be automatically throttled to a slower interval, and the location\n * object will be obfuscated to only show a coarse level of accuracy.\n * <p/>\n * <p>All location requests are considered hints, and you may receive\n * locations that are more accurate, less accurate, and slower\n * than requested.\n *\n * @hide\n */\n@SuppressWarnings(\"WrongConstant\")\npublic final class LocationRequest implements Parcelable {\n    /**\n     * Used with {@link #setQuality} to request the most accurate locations available.\n     * <p/>\n     * <p>This may be up to 1 meter accuracy, although this is implementation dependent.\n     */\n    public static final int ACCURACY_FINE = 100;\n\n    /**\n     * Used with {@link #setQuality} to request \"block\" level accuracy.\n     * <p/>\n     * <p>Block level accuracy is considered to be about 100 meter accuracy,\n     * although this is implementation dependent. Using a coarse accuracy\n     * such as this often consumes less power.\n     */\n    public static final int ACCURACY_BLOCK = 102;\n\n    /**\n     * Used with {@link #setQuality} to request \"city\" level accuracy.\n     * <p/>\n     * <p>City level accuracy is considered to be about 10km accuracy,\n     * although this is implementation dependent. Using a coarse accuracy\n     * such as this often consumes less power.\n     */\n    public static final int ACCURACY_CITY = 104;\n\n    /**\n     * Used with {@link #setQuality} to require no direct power impact (passive locations).\n     * <p/>\n     * <p>This location request will not trigger any active location requests,\n     * but will receive locations triggered by other applications. Your application\n     * will not receive any direct power blame for location work.\n     */\n    public static final int POWER_NONE = 200;\n\n    /**\n     * Used with {@link #setQuality} to request low power impact.\n     * <p/>\n     * <p>This location request will avoid high power location work where\n     * possible.\n     */\n    public static final int POWER_LOW = 201;\n\n    /**\n     * Used with {@link #setQuality} to allow high power consumption for location.\n     * <p/>\n     * <p>This location request will allow high power location work.\n     */\n    public static final int POWER_HIGH = 203;\n\n    /**\n     * Create a location request with default parameters.\n     * <p/>\n     * <p>Default parameters are for a low power, slowly updated location.\n     * It can then be adjusted as required by the applications before passing\n     * to the {@link LocationManager}\n     *\n     * @return a new location request\n     */\n    public static LocationRequest create() {\n        return null;\n    }\n\n    /**\n     * @hide\n     */\n    public static LocationRequest createFromDeprecatedProvider(String provider, long minTime,\n            float minDistance, boolean singleShot) {\n        return null;\n    }\n\n    /**\n     * @hide\n     */\n    public static LocationRequest createFromDeprecatedCriteria(Criteria criteria, long minTime,\n            float minDistance, boolean singleShot) {\n        return null;\n    }\n\n    /**\n     * @hide\n     */\n    public LocationRequest() {\n    }\n\n    /**\n     * @hide\n     */\n    public LocationRequest(LocationRequest src) {\n    }\n\n    /**\n     * Set the quality of the request.\n     * <p/>\n     * <p>Use with a accuracy constant such as {@link #ACCURACY_FINE}, or a power\n     * constant such as {@link #POWER_LOW}. You cannot request both and accuracy and\n     * power, only one or the other can be specified. The system will then\n     * maximize accuracy or minimize power as appropriate.\n     * <p/>\n     * <p>The quality of the request is a strong hint to the system for which\n     * location sources to use. For example, {@link #ACCURACY_FINE} is more likely\n     * to use GPS, and {@link #POWER_LOW} is more likely to use WIFI & Cell tower\n     * positioning, but it also depends on many other factors (such as which sources\n     * are available) and is implementation dependent.\n     * <p/>\n     * <p>{@link #setQuality} and {@link #setInterval} are the most important parameters\n     * on a location request.\n     *\n     * @param quality an accuracy or power constant\n     * @return the same object, so that setters can be chained\n     * @throws InvalidArgumentException if the quality constant is not valid\n     */\n    public LocationRequest setQuality(int quality) {\n        return null;\n    }\n\n    /**\n     * Get the quality of the request.\n     *\n     * @return an accuracy or power constant\n     */\n    public int getQuality() {\n        return 0;\n    }\n\n    /**\n     * Set the desired interval for active location updates, in milliseconds.\n     * <p/>\n     * <p>The location manager will actively try to obtain location updates\n     * for your application at this interval, so it has a\n     * direct influence on the amount of power used by your application.\n     * Choose your interval wisely.\n     * <p/>\n     * <p>This interval is inexact. You may not receive updates at all (if\n     * no location sources are available), or you may receive them\n     * slower than requested. You may also receive them faster than\n     * requested (if other applications are requesting location at a\n     * faster interval). The fastest rate that that you will receive\n     * updates can be controlled with {@link #setFastestInterval}.\n     * <p/>\n     * <p>Applications with only the coarse location permission may have their\n     * interval silently throttled.\n     * <p/>\n     * <p>An interval of 0 is allowed, but not recommended, since\n     * location updates may be extremely fast on future implementations.\n     * <p/>\n     * <p>{@link #setQuality} and {@link #setInterval} are the most important parameters\n     * on a location request.\n     *\n     * @param millis desired interval in millisecond, inexact\n     * @return the same object, so that setters can be chained\n     * @throws InvalidArgumentException if the interval is less than zero\n     */\n    public LocationRequest setInterval(long millis) {\n        return null;\n    }\n\n    /**\n     * Get the desired interval of this request, in milliseconds.\n     *\n     * @return desired interval in milliseconds, inexact\n     */\n    public long getInterval() {\n        return 0;\n    }\n\n    /**\n     * Explicitly set the fastest interval for location updates, in\n     * milliseconds.\n     * <p/>\n     * <p>This controls the fastest rate at which your application will\n     * receive location updates, which might be faster than\n     * {@link #setInterval} in some situations (for example, if other\n     * applications are triggering location updates).\n     * <p/>\n     * <p>This allows your application to passively acquire locations\n     * at a rate faster than it actively acquires locations, saving power.\n     * <p/>\n     * <p>Unlike {@link #setInterval}, this parameter is exact. Your\n     * application will never receive updates faster than this value.\n     * <p/>\n     * <p>If you don't call this method, a fastest interval\n     * will be selected for you. It will be a value faster than your\n     * active interval ({@link #setInterval}).\n     * <p/>\n     * <p>An interval of 0 is allowed, but not recommended, since\n     * location updates may be extremely fast on future implementations.\n     * <p/>\n     * <p>If {@link #setFastestInterval} is set slower than {@link #setInterval},\n     * then your effective fastest interval is {@link #setInterval}.\n     *\n     * @param millis fastest interval for updates in milliseconds, exact\n     * @return the same object, so that setters can be chained\n     * @throws InvalidArgumentException if the interval is less than zero\n     */\n    public LocationRequest setFastestInterval(long millis) {\n        return null;\n    }\n\n    /**\n     * Get the fastest interval of this request, in milliseconds.\n     * <p/>\n     * <p>The system will never provide location updates faster\n     * than the minimum of {@link #getFastestInterval} and\n     * {@link #getInterval}.\n     *\n     * @return fastest interval in milliseconds, exact\n     */\n    public long getFastestInterval() {\n        return 0;\n    }\n\n    /**\n     * Set the duration of this request, in milliseconds.\n     * <p/>\n     * <p>The duration begins immediately (and not when the request\n     * is passed to the location manager), so call this method again\n     * if the request is re-used at a later time.\n     * <p/>\n     * <p>The location manager will automatically stop updates after\n     * the request expires.\n     * <p/>\n     * <p>The duration includes suspend time. Values less than 0\n     * are allowed, but indicate that the request has already expired.\n     *\n     * @param millis duration of request in milliseconds\n     * @return the same object, so that setters can be chained\n     */\n    public LocationRequest setExpireIn(long millis) {\n        return null;\n    }\n\n    /**\n     * Set the request expiration time, in millisecond since boot.\n     * <p/>\n     * <p>This expiration time uses the same time base as {@link SystemClock#elapsedRealtime}.\n     * <p/>\n     * <p>The location manager will automatically stop updates after\n     * the request expires.\n     * <p/>\n     * <p>The duration includes suspend time. Values before {@link SystemClock#elapsedRealtime}\n     * are allowed,  but indicate that the request has already expired.\n     *\n     * @param millis expiration time of request, in milliseconds since boot including suspend\n     * @return the same object, so that setters can be chained\n     */\n    public LocationRequest setExpireAt(long millis) {\n        return null;\n    }\n\n    /**\n     * Get the request expiration time, in milliseconds since boot.\n     * <p/>\n     * <p>This value can be compared to {@link SystemClock#elapsedRealtime} to determine\n     * the time until expiration.\n     *\n     * @return expiration time of request, in milliseconds since boot including suspend\n     */\n    public long getExpireAt() {\n        return 0;\n    }\n\n    /**\n     * Set the number of location updates.\n     * <p/>\n     * <p>By default locations are continuously updated until the request is explicitly\n     * removed, however you can optionally request a set number of updates.\n     * For example, if your application only needs a single fresh location,\n     * then call this method with a value of 1 before passing the request\n     * to the location manager.\n     *\n     * @param numUpdates the number of location updates requested\n     * @return the same object, so that setters can be chained\n     * @throws InvalidArgumentException if numUpdates is 0 or less\n     */\n    public LocationRequest setNumUpdates(int numUpdates) {\n        return null;\n    }\n\n    /**\n     * Get the number of updates requested.\n     * <p/>\n     * <p>By default this is {@link Integer#MAX_VALUE}, which indicates that\n     * locations are updated until the request is explicitly removed.\n     *\n     * @return number of updates\n     */\n    public int getNumUpdates() {\n        return 0;\n    }\n\n    /**\n     * @hide\n     */\n    public void decrementNumUpdates() {\n    }\n\n    /**\n     * @hide\n     */\n    public LocationRequest setProvider(String provider) {\n        return null;\n    }\n\n    /**\n     * @hide\n     */\n    public String getProvider() {\n        return null;\n    }\n\n    /**\n     * @hide\n     */\n    public LocationRequest setSmallestDisplacement(float meters) {\n        return null;\n    }\n\n    /**\n     * @hide\n     */\n    public float getSmallestDisplacement() {\n        return 0;\n    }\n\n    /**\n     * Sets the WorkSource to use for power blaming of this location request.\n     * <p/>\n     * <p>No permissions are required to make this call, however the LocationManager\n     * will throw a SecurityException when requesting location updates if the caller\n     * doesn't have the {@link android.Manifest.permission#UPDATE_DEVICE_STATS} permission.\n     *\n     * @param workSource WorkSource defining power blame for this location request.\n     * @hide\n     */\n    public void setWorkSource(WorkSource workSource) {\n    }\n\n    /**\n     * @hide\n     */\n    public WorkSource getWorkSource() {\n        return null;\n    }\n\n    /**\n     * Sets whether or not this location request should be hidden from AppOps.\n     * <p/>\n     * <p>Hiding a location request from AppOps will remove user visibility in the UI as to this\n     * request's existence.  It does not affect power blaming in the Battery page.\n     * <p/>\n     * <p>No permissions are required to make this call, however the LocationManager\n     * will throw a SecurityException when requesting location updates if the caller\n     * doesn't have the {@link android.Manifest.permission#UPDATE_APP_OPS_STATS} permission.\n     *\n     * @param hideFromAppOps If true AppOps won't keep track of this location request.\n     * @hide\n     * @see android.app.AppOpsManager\n     */\n    public void setHideFromAppOps(boolean hideFromAppOps) {\n    }\n\n    /**\n     * @hide\n     */\n    public boolean getHideFromAppOps() {\n        return false;\n    }\n\n    public static final Parcelable.Creator<LocationRequest> CREATOR =\n            new Parcelable.Creator<LocationRequest>() {\n                @Override\n                public LocationRequest createFromParcel(Parcel in) {\n                    return null;\n                }\n\n                @Override\n                public LocationRequest[] newArray(int size) {\n                    return null;\n                }\n            };\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(Parcel parcel, int flags) {\n    }\n\n    /**\n     * @hide\n     */\n    public static String qualityToString(int quality) {\n        return null;\n    }\n}\n"
  },
  {
    "path": "play-services-location/core/system-api/src/main/java/android/net/wifi/WifiScanner.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2008, The Android Open Source Project\n * SPDX-FileCopyrightText: 2014, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage android.net.wifi;\n\nimport android.Manifest;\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.os.Binder;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.os.Looper;\nimport android.os.Message;\nimport android.os.Messenger;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.os.Process;\nimport android.os.RemoteException;\nimport android.os.WorkSource;\nimport android.text.TextUtils;\nimport android.util.Log;\nimport android.util.SparseArray;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresPermission;\nimport androidx.annotation.RequiresApi;\nimport androidx.annotation.VisibleForTesting;\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.Objects;\nimport java.util.concurrent.Executor;\n\n/**\n * This class provides a way to scan the Wifi universe around the device\n *\n * @hide\n */\npublic class WifiScanner {\n\n    /**\n     * @hide\n     */\n    public static final int WIFI_BAND_INDEX_24_GHZ = 0;\n    /**\n     * @hide\n     */\n    public static final int WIFI_BAND_INDEX_5_GHZ = 1;\n    /**\n     * @hide\n     */\n    public static final int WIFI_BAND_INDEX_5_GHZ_DFS_ONLY = 2;\n    /**\n     * @hide\n     */\n    public static final int WIFI_BAND_INDEX_6_GHZ = 3;\n    /**\n     * @hide\n     */\n    public static final int WIFI_BAND_INDEX_60_GHZ = 4;\n    /**\n     * @hide\n     */\n    public static final int WIFI_BAND_COUNT = 5;\n\n    /**\n     * @hide\n     */\n    @Retention(RetentionPolicy.SOURCE)\n    @IntDef(value = {\n            WIFI_BAND_INDEX_24_GHZ,\n            WIFI_BAND_INDEX_5_GHZ,\n            WIFI_BAND_INDEX_5_GHZ_DFS_ONLY,\n            WIFI_BAND_INDEX_6_GHZ,\n            WIFI_BAND_INDEX_60_GHZ})\n    public @interface WifiBandIndex {\n    }\n\n    /**\n     * no band specified; use channel list instead\n     */\n    public static final int WIFI_BAND_UNSPECIFIED = 0;\n    /**\n     * 2.4 GHz band\n     */\n    public static final int WIFI_BAND_24_GHZ = 1 << WIFI_BAND_INDEX_24_GHZ;\n    /**\n     * 5 GHz band excluding DFS channels\n     */\n    public static final int WIFI_BAND_5_GHZ = 1 << WIFI_BAND_INDEX_5_GHZ;\n    /**\n     * DFS channels from 5 GHz band only\n     */\n    public static final int WIFI_BAND_5_GHZ_DFS_ONLY = 1 << WIFI_BAND_INDEX_5_GHZ_DFS_ONLY;\n    /**\n     * 6 GHz band\n     */\n    public static final int WIFI_BAND_6_GHZ = 1 << WIFI_BAND_INDEX_6_GHZ;\n    /**\n     * 60 GHz band\n     */\n    public static final int WIFI_BAND_60_GHZ = 1 << WIFI_BAND_INDEX_60_GHZ;\n\n    /**\n     * Combination of bands\n     * Note that those are only the common band combinations,\n     * other combinations can be created by combining any of the basic bands above\n     */\n    /**\n     * Both 2.4 GHz band and 5 GHz band; no DFS channels\n     */\n    public static final int WIFI_BAND_BOTH = WIFI_BAND_24_GHZ | WIFI_BAND_5_GHZ;\n    /**\n     * 2.4Ghz band + DFS channels from 5 GHz band only\n     *\n     * @hide\n     */\n    public static final int WIFI_BAND_24_GHZ_WITH_5GHZ_DFS =\n            WIFI_BAND_24_GHZ | WIFI_BAND_5_GHZ_DFS_ONLY;\n    /**\n     * 5 GHz band including DFS channels\n     */\n    public static final int WIFI_BAND_5_GHZ_WITH_DFS = WIFI_BAND_5_GHZ | WIFI_BAND_5_GHZ_DFS_ONLY;\n    /**\n     * Both 2.4 GHz band and 5 GHz band; with DFS channels\n     */\n    public static final int WIFI_BAND_BOTH_WITH_DFS =\n            WIFI_BAND_24_GHZ | WIFI_BAND_5_GHZ | WIFI_BAND_5_GHZ_DFS_ONLY;\n    /**\n     * 2.4 GHz band and 5 GHz band (no DFS channels) and 6 GHz\n     */\n    public static final int WIFI_BAND_24_5_6_GHZ = WIFI_BAND_BOTH | WIFI_BAND_6_GHZ;\n    /**\n     * 2.4 GHz band and 5 GHz band; with DFS channels and 6 GHz\n     */\n    public static final int WIFI_BAND_24_5_WITH_DFS_6_GHZ =\n            WIFI_BAND_BOTH_WITH_DFS | WIFI_BAND_6_GHZ;\n    /**\n     * @hide\n     */\n    public static final int WIFI_BAND_24_5_6_60_GHZ =\n            WIFI_BAND_24_5_6_GHZ | WIFI_BAND_60_GHZ;\n    /**\n     * @hide\n     */\n    public static final int WIFI_BAND_24_5_WITH_DFS_6_60_GHZ =\n            WIFI_BAND_24_5_6_60_GHZ | WIFI_BAND_5_GHZ_DFS_ONLY;\n\n    /**\n     * @hide\n     */\n    @Retention(RetentionPolicy.SOURCE)\n    @IntDef(value = {\n            WIFI_BAND_UNSPECIFIED,\n            WIFI_BAND_24_GHZ,\n            WIFI_BAND_5_GHZ,\n            WIFI_BAND_BOTH,\n            WIFI_BAND_5_GHZ_DFS_ONLY,\n            WIFI_BAND_24_GHZ_WITH_5GHZ_DFS,\n            WIFI_BAND_5_GHZ_WITH_DFS,\n            WIFI_BAND_BOTH_WITH_DFS,\n            WIFI_BAND_6_GHZ,\n            WIFI_BAND_24_5_6_GHZ,\n            WIFI_BAND_24_5_WITH_DFS_6_GHZ,\n            WIFI_BAND_60_GHZ,\n            WIFI_BAND_24_5_6_60_GHZ,\n            WIFI_BAND_24_5_WITH_DFS_6_60_GHZ})\n    public @interface WifiBand {\n    }\n\n    /**\n     * All bands\n     *\n     * @hide\n     */\n    public static final int WIFI_BAND_ALL = (1 << WIFI_BAND_COUNT) - 1;\n\n    /**\n     * Minimum supported scanning period\n     */\n    public static final int MIN_SCAN_PERIOD_MS = 1000;\n    /**\n     * Maximum supported scanning period\n     */\n    public static final int MAX_SCAN_PERIOD_MS = 1024000;\n\n    /**\n     * No Error\n     */\n    public static final int REASON_SUCCEEDED = 0;\n    /**\n     * Unknown error\n     */\n    public static final int REASON_UNSPECIFIED = -1;\n    /**\n     * Invalid listener\n     */\n    public static final int REASON_INVALID_LISTENER = -2;\n    /**\n     * Invalid request\n     */\n    public static final int REASON_INVALID_REQUEST = -3;\n    /**\n     * Invalid request\n     */\n    public static final int REASON_NOT_AUTHORIZED = -4;\n    /**\n     * An outstanding request with the same listener hasn't finished yet.\n     */\n    public static final int REASON_DUPLICATE_REQEUST = -5;\n\n    /**\n     * @hide\n     */\n    public static final String GET_AVAILABLE_CHANNELS_EXTRA = \"Channels\";\n\n    /**\n     * This constant is used for {@link ScanSettings#setRnrSetting(int)}.\n     * <p>\n     * Scan 6Ghz APs co-located with 2.4/5Ghz APs using Reduced Neighbor Report (RNR) if the 6Ghz\n     * band is explicitly requested to be scanned and the current country code supports scanning\n     * of at least one 6Ghz channel. The 6Ghz band is explicitly requested if the\n     * ScanSetting.band parameter is set to one of:\n     * <li> {@link #WIFI_BAND_6_GHZ} </li>\n     * <li> {@link #WIFI_BAND_24_5_6_GHZ} </li>\n     * <li> {@link #WIFI_BAND_24_5_WITH_DFS_6_GHZ} </li>\n     * <li> {@link #WIFI_BAND_24_5_6_60_GHZ} </li>\n     * <li> {@link #WIFI_BAND_24_5_WITH_DFS_6_60_GHZ} </li>\n     * <li> {@link #WIFI_BAND_ALL} </li>\n     **/\n    public static final int WIFI_RNR_ENABLED_IF_WIFI_BAND_6_GHZ_SCANNED = 0;\n    /**\n     * This constant is used for {@link ScanSettings#setRnrSetting(int)}.\n     * <p>\n     * Request to scan 6Ghz APs co-located with 2.4/5Ghz APs using Reduced Neighbor Report (RNR)\n     * when the current country code supports scanning of at least one 6Ghz channel.\n     **/\n    public static final int WIFI_RNR_ENABLED = 1;\n    /**\n     * This constant is used for {@link ScanSettings#setRnrSetting(int)}.\n     * <p>\n     * Do not request to scan 6Ghz APs co-located with 2.4/5Ghz APs using\n     * Reduced Neighbor Report (RNR)\n     **/\n    public static final int WIFI_RNR_NOT_NEEDED = 2;\n\n    /**\n     * @hide\n     */\n    @Retention(RetentionPolicy.SOURCE)\n    @IntDef(value = {\n            WIFI_RNR_ENABLED_IF_WIFI_BAND_6_GHZ_SCANNED,\n            WIFI_RNR_ENABLED,\n            WIFI_RNR_NOT_NEEDED})\n    public @interface RnrSetting {\n    }\n\n    /**\n     * Generic action callback invocation interface\n     *\n     * @hide\n     */\n    public static interface ActionListener {\n        public void onSuccess();\n\n        public void onFailure(int reason, String description);\n    }\n\n    /**\n     * Test if scan is a full scan. i.e. scanning all available bands.\n     * For backward compatibility, since some apps don't include 6GHz or 60Ghz in their requests\n     * yet, lacking 6GHz or 60Ghz band does not cause the result to be false.\n     *\n     * @param bandsScanned bands that are fully scanned\n     * @param excludeDfs   when true, DFS band is excluded from the check\n     * @return true if all bands are scanned, false otherwise\n     * @hide\n     */\n    public static boolean isFullBandScan(@WifiBand int bandsScanned, boolean excludeDfs) {\n        return (bandsScanned | WIFI_BAND_6_GHZ | WIFI_BAND_60_GHZ\n                | (excludeDfs ? WIFI_BAND_5_GHZ_DFS_ONLY : 0))\n                == WIFI_BAND_ALL;\n    }\n\n    /**\n     * Returns a list of all the possible channels for the given band(s).\n     *\n     * @param band one of the WifiScanner#WIFI_BAND_* constants, e.g. {@link #WIFI_BAND_24_GHZ}\n     * @return a list of all the frequencies, in MHz, for the given band(s) e.g. channel 1 is\n     * 2412, or null if an error occurred.\n     * @hide\n     */\n    @NonNull\n    @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)\n    public List<Integer> getAvailableChannels(int band) {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * provides channel specification for scanning\n     */\n    public static class ChannelSpec {\n        /**\n         * channel frequency in MHz; for example channel 1 is specified as 2412\n         */\n        public int frequency;\n        /**\n         * if true, scan this channel in passive fashion.\n         * This flag is ignored on DFS channel specification.\n         *\n         * @hide\n         */\n        public boolean passive;                                    /* ignored on DFS channels */\n        /**\n         * how long to dwell on this channel\n         *\n         * @hide\n         */\n        public int dwellTimeMS;                                    /* not supported for now */\n\n        /**\n         * default constructor for channel spec\n         */\n        public ChannelSpec(int frequency) {\n            this.frequency = frequency;\n            passive = false;\n            dwellTimeMS = 0;\n        }\n    }\n\n    /**\n     * reports {@link ScanListener#onResults} when underlying buffers are full\n     * this is simply the lack of the {@link #REPORT_EVENT_AFTER_EACH_SCAN} flag\n     *\n     * @deprecated It is not supported anymore.\n     */\n    @Deprecated\n    public static final int REPORT_EVENT_AFTER_BUFFER_FULL = 0;\n    /**\n     * reports {@link ScanListener#onResults} after each scan\n     */\n    public static final int REPORT_EVENT_AFTER_EACH_SCAN = (1 << 0);\n    /**\n     * reports {@link ScanListener#onFullResult} whenever each beacon is discovered\n     */\n    public static final int REPORT_EVENT_FULL_SCAN_RESULT = (1 << 1);\n    /**\n     * Do not place scans in the chip's scan history buffer\n     */\n    public static final int REPORT_EVENT_NO_BATCH = (1 << 2);\n\n    /**\n     * Optimize the scan for lower latency.\n     *\n     * @see ScanSettings#type\n     */\n    public static final int SCAN_TYPE_LOW_LATENCY = 0;\n    /**\n     * Optimize the scan for lower power usage.\n     *\n     * @see ScanSettings#type\n     */\n    public static final int SCAN_TYPE_LOW_POWER = 1;\n    /**\n     * Optimize the scan for higher accuracy.\n     *\n     * @see ScanSettings#type\n     */\n    public static final int SCAN_TYPE_HIGH_ACCURACY = 2;\n    /**\n     * Max valid value of SCAN_TYPE_\n     *\n     * @hide\n     */\n    public static final int SCAN_TYPE_MAX = 2;\n\n    /**\n     * {@hide}\n     */\n    public static final String SCAN_PARAMS_SCAN_SETTINGS_KEY = \"ScanSettings\";\n    /**\n     * {@hide}\n     */\n    public static final String SCAN_PARAMS_WORK_SOURCE_KEY = \"WorkSource\";\n    /**\n     * {@hide}\n     */\n    public static final String REQUEST_PACKAGE_NAME_KEY = \"PackageName\";\n    /**\n     * {@hide}\n     */\n    public static final String REQUEST_FEATURE_ID_KEY = \"FeatureId\";\n\n    /**\n     * scan configuration parameters to be sent to {@link #startBackgroundScan}\n     */\n    public static class ScanSettings implements Parcelable {\n        /**\n         * Hidden network to be scanned for.\n         */\n        public static class HiddenNetwork {\n            /**\n             * SSID of the network\n             */\n            @NonNull\n            public final String ssid;\n\n            /**\n             * Default constructor for HiddenNetwork.\n             */\n            public HiddenNetwork(@NonNull String ssid) {\n                this.ssid = ssid;\n            }\n        }\n\n        /**\n         * one of the WIFI_BAND values\n         */\n        public int band;\n        /**\n         * one of the {@code WIFI_RNR_*} values.\n         */\n        private int mRnrSetting = WIFI_RNR_ENABLED_IF_WIFI_BAND_6_GHZ_SCANNED;\n\n        /**\n         * See {@link #set6GhzPscOnlyEnabled}\n         */\n        private boolean mEnable6GhzPsc = false;\n\n        /**\n         * list of channels; used when band is set to WIFI_BAND_UNSPECIFIED\n         */\n        public ChannelSpec[] channels;\n        /**\n         * List of hidden networks to scan for. Explicit probe requests are sent out for such\n         * networks during scan. Only valid for single scan requests.\n         */\n        @NonNull\n        public final List<HiddenNetwork> hiddenNetworks = new ArrayList<>();\n        /**\n         * period of background scan; in millisecond, 0 => single shot scan\n         *\n         * @deprecated Background scan support has always been hardware vendor dependent. This\n         * support may not be present on newer devices. Use {@link #startScan(ScanSettings,\n         * ScanListener)} instead for single scans.\n         */\n        @Deprecated\n        public int periodInMs;\n        /**\n         * must have a valid REPORT_EVENT value\n         *\n         * @deprecated Background scan support has always been hardware vendor dependent. This\n         * support may not be present on newer devices. Use {@link #startScan(ScanSettings,\n         * ScanListener)} instead for single scans.\n         */\n        @Deprecated\n        public int reportEvents;\n        /**\n         * defines number of bssids to cache from each scan\n         *\n         * @deprecated Background scan support has always been hardware vendor dependent. This\n         * support may not be present on newer devices. Use {@link #startScan(ScanSettings,\n         * ScanListener)} instead for single scans.\n         */\n        @Deprecated\n        public int numBssidsPerScan;\n        /**\n         * defines number of scans to cache; use it with REPORT_EVENT_AFTER_BUFFER_FULL\n         * to wake up at fixed interval\n         *\n         * @deprecated Background scan support has always been hardware vendor dependent. This\n         * support may not be present on newer devices. Use {@link #startScan(ScanSettings,\n         * ScanListener)} instead for single scans.\n         */\n        @Deprecated\n        public int maxScansToCache;\n        /**\n         * if maxPeriodInMs is non zero or different than period, then this bucket is\n         * a truncated binary exponential backoff bucket and the scan period will grow\n         * exponentially as per formula: actual_period(N) = period * (2 ^ (N/stepCount))\n         * to maxPeriodInMs\n         *\n         * @deprecated Background scan support has always been hardware vendor dependent. This\n         * support may not be present on newer devices. Use {@link #startScan(ScanSettings,\n         * ScanListener)} instead for single scans.\n         */\n        @Deprecated\n        public int maxPeriodInMs;\n        /**\n         * for truncated binary exponential back off bucket, number of scans to perform\n         * for a given period\n         *\n         * @deprecated Background scan support has always been hardware vendor dependent. This\n         * support may not be present on newer devices. Use {@link #startScan(ScanSettings,\n         * ScanListener)} instead for single scans.\n         */\n        @Deprecated\n        public int stepCount;\n        /**\n         * Flag to indicate if the scan settings are targeted for PNO scan.\n         * {@hide}\n         */\n        public boolean isPnoScan;\n        public int type = SCAN_TYPE_LOW_LATENCY;\n        /**\n         * This scan request may ignore location settings while receiving scans. This should only\n         * be used in emergency situations.\n         * {@hide}\n         */\n        public boolean ignoreLocationSettings;\n        /**\n         * This scan request will be hidden from app-ops noting for location information. This\n         * should only be used by FLP/NLP module on the device which is using the scan results to\n         * compute results for behalf on their clients. FLP/NLP module using this flag should ensure\n         * that they note in app-ops the eventual delivery of location information computed using\n         * these results to their client .\n         * {@hide}\n         */\n        public boolean hideFromAppOps;\n\n        /**\n         * Configure whether it is needed to scan 6Ghz non Preferred Scanning Channels when scanning\n         * {@link #WIFI_BAND_6_GHZ}. If set to true and a band that contains\n         * {@link #WIFI_BAND_6_GHZ} is configured for scanning, then only scan 6Ghz PSC channels in\n         * addition to any other bands configured for scanning. Note, 6Ghz non-PSC channels that\n         * are co-located with 2.4/5Ghz APs could still be scanned via the\n         * {@link #setRnrSetting(int)} API.\n         *\n         * <p>\n         * For example, given a ScanSettings with band set to {@link #WIFI_BAND_24_5_WITH_DFS_6_GHZ}\n         * If this API is set to \"true\" then the ScanSettings is configured to scan all of 2.4Ghz\n         * + all of 5Ghz(DFS and non-DFS) + 6Ghz PSC channels. If this API is set to \"false\", then\n         * the ScanSetting is configured to scan all of 2.4Ghz + all of 5Ghz(DFS and non_DFS)\n         * + all of 6Ghz channels.\n         *\n         * @param enable true to only scan 6Ghz PSC channels, false to scan all 6Ghz channels.\n         */\n        @RequiresApi(Build.VERSION_CODES.S)\n        public void set6GhzPscOnlyEnabled(boolean enable) {\n            throw new UnsupportedOperationException();\n        }\n\n        /**\n         * See {@link #set6GhzPscOnlyEnabled}\n         */\n        @RequiresApi(Build.VERSION_CODES.S)\n        public boolean is6GhzPscOnlyEnabled() {\n            throw new UnsupportedOperationException();\n        }\n\n        /**\n         * Configure when to scan 6Ghz APs co-located with 2.4/5Ghz APs using Reduced\n         * Neighbor Report (RNR).\n         *\n         * @param rnrSetting one of the {@code WIFI_RNR_*} values\n         */\n        @RequiresApi(Build.VERSION_CODES.S)\n        public void setRnrSetting(@RnrSetting int rnrSetting) {\n            throw new UnsupportedOperationException();\n        }\n\n        /**\n         * See {@link #setRnrSetting}\n         */\n        @RequiresApi(Build.VERSION_CODES.S)\n        public @RnrSetting int getRnrSetting() {\n            throw new UnsupportedOperationException();\n        }\n\n        /**\n         * Implement the Parcelable interface {@hide}\n         */\n        public int describeContents() {\n            return 0;\n        }\n\n        /**\n         * Implement the Parcelable interface {@hide}\n         */\n        public void writeToParcel(Parcel dest, int flags) {\n            throw new UnsupportedOperationException();\n        }\n\n        /**\n         * Implement the Parcelable interface {@hide}\n         */\n        public static final @NonNull Creator<ScanSettings> CREATOR =\n                new Creator<ScanSettings>() {\n                    public ScanSettings createFromParcel(Parcel in) {\n                        throw new UnsupportedOperationException();\n                    }\n\n                    public ScanSettings[] newArray(int size) {\n                        return new ScanSettings[size];\n                    }\n                };\n    }\n\n    /**\n     * All the information garnered from a single scan\n     */\n    public static class ScanData implements Parcelable {\n        /**\n         * scan identifier\n         */\n        private int mId;\n        /**\n         * additional information about scan\n         * 0 => no special issues encountered in the scan\n         * non-zero => scan was truncated, so results may not be complete\n         */\n        private int mFlags;\n        /**\n         * Indicates the buckets that were scanned to generate these results.\n         * This is not relevant to WifiScanner API users and is used internally.\n         * {@hide}\n         */\n        private int mBucketsScanned;\n        /**\n         * Bands scanned. One of the WIFI_BAND values.\n         * Will be {@link #WIFI_BAND_UNSPECIFIED} if the list of channels do not fully cover\n         * any of the bands.\n         * {@hide}\n         */\n        private int mScannedBands;\n        /**\n         * all scan results discovered in this scan, sorted by timestamp in ascending order\n         */\n        private final List<ScanResult> mResults;\n\n        ScanData() {\n            mResults = new ArrayList<>();\n        }\n\n        public ScanData(int id, int flags, ScanResult[] results) {\n            mId = id;\n            mFlags = flags;\n            mResults = new ArrayList<>(Arrays.asList(results));\n        }\n\n        /**\n         * {@hide}\n         */\n        public ScanData(int id, int flags, int bucketsScanned, int bandsScanned,\n                        ScanResult[] results) {\n            this(id, flags, bucketsScanned, bandsScanned, new ArrayList<>(Arrays.asList(results)));\n        }\n\n        /**\n         * {@hide}\n         */\n        public ScanData(int id, int flags, int bucketsScanned, int bandsScanned,\n                        List<ScanResult> results) {\n            mId = id;\n            mFlags = flags;\n            mBucketsScanned = bucketsScanned;\n            mScannedBands = bandsScanned;\n            mResults = results;\n        }\n\n        public ScanData(ScanData s) {\n            throw new UnsupportedOperationException();\n        }\n\n        public int getId() {\n            return mId;\n        }\n\n        public int getFlags() {\n            return mFlags;\n        }\n\n        /**\n         * {@hide}\n         */\n        public int getBucketsScanned() {\n            return mBucketsScanned;\n        }\n\n        /**\n         * Retrieve the bands that were fully scanned for this ScanData instance. \"fully\" here\n         * refers to all the channels available in the band based on the current regulatory\n         * domain.\n         *\n         * @return Bitmask of {@link #WIFI_BAND_24_GHZ}, {@link #WIFI_BAND_5_GHZ},\n         * {@link #WIFI_BAND_5_GHZ_DFS_ONLY}, {@link #WIFI_BAND_6_GHZ} & {@link #WIFI_BAND_60_GHZ}\n         * values. Each bit is set only if all the channels in the corresponding band is scanned.\n         * Will be {@link #WIFI_BAND_UNSPECIFIED} if the list of channels do not fully cover\n         * any of the bands.\n         * <p>\n         * For ex:\n         * <li> Scenario 1:  Fully scanned 2.4Ghz band, partially scanned 5Ghz band\n         * - Returns {@link #WIFI_BAND_24_GHZ}\n         * </li>\n         * <li> Scenario 2:  Partially scanned 2.4Ghz band and 5Ghz band\n         * - Returns {@link #WIFI_BAND_UNSPECIFIED}\n         * </li>\n         * </p>\n         */\n        public @WifiBand int getScannedBands() {\n            return getScannedBandsInternal();\n        }\n\n        /**\n         * Same as {@link #getScannedBands()}. For use in the wifi stack without version check.\n         * <p>\n         * {@hide}\n         */\n        public @WifiBand int getScannedBandsInternal() {\n            return mScannedBands;\n        }\n\n        public ScanResult[] getResults() {\n            return mResults.toArray(new ScanResult[0]);\n        }\n\n        /**\n         * {@hide}\n         */\n        public void addResults(@NonNull ScanResult[] newResults) {\n            throw new UnsupportedOperationException();\n        }\n\n        /**\n         * {@hide}\n         */\n        public void addResults(@NonNull ScanData s) {\n            mScannedBands |= s.mScannedBands;\n            mFlags |= s.mFlags;\n            addResults(s.getResults());\n        }\n\n        /**\n         * {@hide}\n         */\n        public boolean isFullBandScanResults() {\n            return (mScannedBands & WifiScanner.WIFI_BAND_24_GHZ) != 0\n                    && (mScannedBands & WifiScanner.WIFI_BAND_5_GHZ) != 0;\n        }\n\n        /**\n         * Implement the Parcelable interface {@hide}\n         */\n        public int describeContents() {\n            return 0;\n        }\n\n        /**\n         * Implement the Parcelable interface {@hide}\n         */\n        public void writeToParcel(Parcel dest, int flags) {\n            throw new UnsupportedOperationException();\n        }\n\n        /**\n         * Implement the Parcelable interface {@hide}\n         */\n        public static final @NonNull Creator<ScanData> CREATOR =\n                new Creator<ScanData>() {\n                    public ScanData createFromParcel(Parcel in) {\n                        throw new UnsupportedOperationException();\n                    }\n\n                    public ScanData[] newArray(int size) {\n                        return new ScanData[size];\n                    }\n                };\n    }\n\n    public static class ParcelableScanData implements Parcelable {\n\n        public ScanData mResults[];\n\n        public ParcelableScanData(ScanData[] results) {\n            mResults = results;\n        }\n\n        public ScanData[] getResults() {\n            return mResults;\n        }\n\n        /**\n         * Implement the Parcelable interface {@hide}\n         */\n        public int describeContents() {\n            return 0;\n        }\n\n        /**\n         * Implement the Parcelable interface {@hide}\n         */\n        public void writeToParcel(Parcel dest, int flags) {\n            if (mResults != null) {\n                dest.writeInt(mResults.length);\n                for (int i = 0; i < mResults.length; i++) {\n                    ScanData result = mResults[i];\n                    result.writeToParcel(dest, flags);\n                }\n            } else {\n                dest.writeInt(0);\n            }\n        }\n\n        /**\n         * Implement the Parcelable interface {@hide}\n         */\n        public static final @NonNull Creator<ParcelableScanData> CREATOR =\n                new Creator<ParcelableScanData>() {\n                    public ParcelableScanData createFromParcel(Parcel in) {\n                        int n = in.readInt();\n                        ScanData results[] = new ScanData[n];\n                        for (int i = 0; i < n; i++) {\n                            results[i] = ScanData.CREATOR.createFromParcel(in);\n                        }\n                        return new ParcelableScanData(results);\n                    }\n\n                    public ParcelableScanData[] newArray(int size) {\n                        return new ParcelableScanData[size];\n                    }\n                };\n    }\n\n    public static class ParcelableScanResults implements Parcelable {\n\n        public ScanResult mResults[];\n\n        public ParcelableScanResults(ScanResult[] results) {\n            mResults = results;\n        }\n\n        public ScanResult[] getResults() {\n            return mResults;\n        }\n\n        /**\n         * Implement the Parcelable interface {@hide}\n         */\n        public int describeContents() {\n            return 0;\n        }\n\n        /**\n         * Implement the Parcelable interface {@hide}\n         */\n        public void writeToParcel(Parcel dest, int flags) {\n            if (mResults != null) {\n                dest.writeInt(mResults.length);\n                for (int i = 0; i < mResults.length; i++) {\n                    ScanResult result = mResults[i];\n                    result.writeToParcel(dest, flags);\n                }\n            } else {\n                dest.writeInt(0);\n            }\n        }\n\n        /**\n         * Implement the Parcelable interface {@hide}\n         */\n        public static final @NonNull Creator<ParcelableScanResults> CREATOR =\n                new Creator<ParcelableScanResults>() {\n                    public ParcelableScanResults createFromParcel(Parcel in) {\n                        throw new UnsupportedOperationException();\n                    }\n\n                    public ParcelableScanResults[] newArray(int size) {\n                        return new ParcelableScanResults[size];\n                    }\n                };\n    }\n\n    /**\n     * {@hide}\n     */\n    public static final String PNO_PARAMS_PNO_SETTINGS_KEY = \"PnoSettings\";\n    /**\n     * {@hide}\n     */\n    public static final String PNO_PARAMS_SCAN_SETTINGS_KEY = \"ScanSettings\";\n\n    /**\n     * PNO scan configuration parameters to be sent to {@link #startPnoScan}.\n     * Note: This structure needs to be in sync with |wifi_epno_params| struct in gscan HAL API.\n     * {@hide}\n     */\n    public static class PnoSettings implements Parcelable {\n        /**\n         * Pno network to be added to the PNO scan filtering.\n         * {@hide}\n         */\n        public static class PnoNetwork {\n            /*\n             * Pno flags bitmask to be set in {@link #PnoNetwork.flags}\n             */\n            /**\n             * Whether directed scan needs to be performed (for hidden SSIDs)\n             */\n            public static final byte FLAG_DIRECTED_SCAN = (1 << 0);\n            /**\n             * Whether PNO event shall be triggered if the network is found on A band\n             */\n            public static final byte FLAG_A_BAND = (1 << 1);\n            /**\n             * Whether PNO event shall be triggered if the network is found on G band\n             */\n            public static final byte FLAG_G_BAND = (1 << 2);\n            /**\n             * Whether strict matching is required\n             * If required then the firmware must store the network's SSID and not just a hash\n             */\n            public static final byte FLAG_STRICT_MATCH = (1 << 3);\n            /**\n             * If this SSID should be considered the same network as the currently connected\n             * one for scoring.\n             */\n            public static final byte FLAG_SAME_NETWORK = (1 << 4);\n\n            /*\n             * Code for matching the beacon AUTH IE - additional codes. Bitmask to be set in\n             * {@link #PnoNetwork.authBitField}\n             */\n            /**\n             * Open Network\n             */\n            public static final byte AUTH_CODE_OPEN = (1 << 0);\n            /**\n             * WPA_PSK or WPA2PSK\n             */\n            public static final byte AUTH_CODE_PSK = (1 << 1);\n            /**\n             * any EAPOL\n             */\n            public static final byte AUTH_CODE_EAPOL = (1 << 2);\n\n            /**\n             * SSID of the network\n             */\n            public String ssid;\n            /**\n             * Bitmask of the FLAG_XXX\n             */\n            public byte flags = 0;\n            /**\n             * Bitmask of the ATUH_XXX\n             */\n            public byte authBitField = 0;\n            /**\n             * frequencies on which the particular network needs to be scanned for\n             */\n            public int[] frequencies = {};\n\n            /**\n             * default constructor for PnoNetwork\n             */\n            public PnoNetwork(String ssid) {\n                this.ssid = ssid;\n            }\n\n            @Override\n            public int hashCode() {\n                return Objects.hash(ssid, flags, authBitField);\n            }\n\n            @Override\n            public boolean equals(Object obj) {\n                if (this == obj) {\n                    return true;\n                }\n                if (!(obj instanceof PnoNetwork)) {\n                    return false;\n                }\n                PnoNetwork lhs = (PnoNetwork) obj;\n                return TextUtils.equals(this.ssid, lhs.ssid)\n                        && this.flags == lhs.flags\n                        && this.authBitField == lhs.authBitField;\n            }\n        }\n\n        /**\n         * Connected vs Disconnected PNO flag {@hide}\n         */\n        public boolean isConnected;\n        /**\n         * Minimum 5GHz RSSI for a BSSID to be considered\n         */\n        public int min5GHzRssi;\n        /**\n         * Minimum 2.4GHz RSSI for a BSSID to be considered\n         */\n        public int min24GHzRssi;\n        /**\n         * Minimum 6GHz RSSI for a BSSID to be considered\n         */\n        public int min6GHzRssi;\n        /**\n         * Pno Network filter list\n         */\n        public PnoNetwork[] networkList;\n\n        /**\n         * Implement the Parcelable interface {@hide}\n         */\n        public int describeContents() {\n            return 0;\n        }\n\n        /**\n         * Implement the Parcelable interface {@hide}\n         */\n        public void writeToParcel(Parcel dest, int flags) {\n            dest.writeInt(isConnected ? 1 : 0);\n            dest.writeInt(min5GHzRssi);\n            dest.writeInt(min24GHzRssi);\n            dest.writeInt(min6GHzRssi);\n            if (networkList != null) {\n                dest.writeInt(networkList.length);\n                for (int i = 0; i < networkList.length; i++) {\n                    dest.writeString(networkList[i].ssid);\n                    dest.writeByte(networkList[i].flags);\n                    dest.writeByte(networkList[i].authBitField);\n                    dest.writeIntArray(networkList[i].frequencies);\n                }\n            } else {\n                dest.writeInt(0);\n            }\n        }\n\n        /**\n         * Implement the Parcelable interface {@hide}\n         */\n        public static final @NonNull Creator<PnoSettings> CREATOR =\n                new Creator<PnoSettings>() {\n                    public PnoSettings createFromParcel(Parcel in) {\n                        PnoSettings settings = new PnoSettings();\n                        settings.isConnected = in.readInt() == 1;\n                        settings.min5GHzRssi = in.readInt();\n                        settings.min24GHzRssi = in.readInt();\n                        settings.min6GHzRssi = in.readInt();\n                        int numNetworks = in.readInt();\n                        settings.networkList = new PnoNetwork[numNetworks];\n                        for (int i = 0; i < numNetworks; i++) {\n                            String ssid = in.readString();\n                            PnoNetwork network = new PnoNetwork(ssid);\n                            network.flags = in.readByte();\n                            network.authBitField = in.readByte();\n                            network.frequencies = in.createIntArray();\n                            settings.networkList[i] = network;\n                        }\n                        return settings;\n                    }\n\n                    public PnoSettings[] newArray(int size) {\n                        return new PnoSettings[size];\n                    }\n                };\n\n    }\n\n    /**\n     * interface to get scan events on; specify this on {@link #startBackgroundScan} or\n     * {@link #startScan}\n     */\n    public interface ScanListener extends ActionListener {\n        /**\n         * Framework co-ordinates scans across multiple apps; so it may not give exactly the\n         * same period requested. If period of a scan is changed; it is reported by this event.\n         *\n         * @deprecated Background scan support has always been hardware vendor dependent. This\n         * support may not be present on newer devices. Use {@link #startScan(ScanSettings,\n         * ScanListener)} instead for single scans.\n         */\n        @Deprecated\n        public void onPeriodChanged(int periodInMs);\n\n        /**\n         * reports results retrieved from background scan and single shot scans\n         */\n        public void onResults(ScanData[] results);\n\n        /**\n         * reports full scan result for each access point found in scan\n         */\n        public void onFullResult(ScanResult fullScanResult);\n    }\n\n    /**\n     * interface to get PNO scan events on; specify this on {@link #startDisconnectedPnoScan} and\n     * {@link #startConnectedPnoScan}.\n     * {@hide}\n     */\n    public interface PnoScanListener extends ScanListener {\n        /**\n         * Invoked when one of the PNO networks are found in scan results.\n         */\n        void onPnoNetworkFound(ScanResult[] results);\n    }\n\n    /**\n     * Enable/Disable wifi scanning.\n     *\n     * @param enable set to true to enable scanning, set to false to disable all types of scanning.\n     * @see WifiManager#ACTION_WIFI_SCAN_AVAILABILITY_CHANGED\n     * {@hide}\n     */\n    public void setScanningEnabled(boolean enable) {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Register a listener that will receive results from all single scans.\n     * Either the {@link ScanListener#onSuccess()} or  {@link ScanListener#onFailure(int, String)}\n     * method will be called once when the listener is registered.\n     * Afterwards (assuming onSuccess was called), all subsequent single scan results will be\n     * delivered to the listener. It is possible that onFullResult will not be called for all\n     * results of the first scan if the listener was registered during the scan.\n     *\n     * @param executor the Executor on which to run the callback.\n     * @param listener specifies the object to report events to. This object is also treated as a\n     *                 key for this request, and must also be specified to cancel the request.\n     *                 Multiple requests should also not share this object.\n     * @throws SecurityException if the caller does not have permission.\n     */\n    @RequiresPermission(anyOf = {\n            Manifest.permission.LOCATION_HARDWARE})\n    public void registerScanListener(@NonNull Executor executor,\n                                     @NonNull ScanListener listener) {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Overload of {@link #registerScanListener(Executor, ScanListener)} that executes the callback\n     * synchronously.\n     *\n     * @hide\n     */\n    public void registerScanListener(@NonNull ScanListener listener) {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Deregister a listener for ongoing single scans\n     *\n     * @param listener specifies which scan to cancel; must be same object as passed in {@link\n     *                 #registerScanListener}\n     */\n    public void unregisterScanListener(@NonNull ScanListener listener) {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Check whether the Wi-Fi subsystem has started a scan and is waiting for scan results.\n     *\n     * @return true if a scan initiated via\n     * {@link WifiScanner#startScan(ScanSettings, ScanListener)} or\n     * {@link WifiManager#startScan()} is in progress.\n     * false if there is currently no scanning initiated by {@link WifiScanner} or\n     * {@link WifiManager}, but it's still possible the wifi radio is scanning for\n     * another reason.\n     * @hide\n     */\n    @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)\n    public boolean isScanning() {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * start wifi scan in background\n     *\n     * @param settings specifies various parameters for the scan; for more information look at\n     *                 {@link ScanSettings}\n     * @param listener specifies the object to report events to. This object is also treated as a\n     *                 key for this scan, and must also be specified to cancel the scan. Multiple\n     *                 scans should also not share this object.\n     */\n    @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)\n    public void startBackgroundScan(ScanSettings settings, ScanListener listener) {\n        startBackgroundScan(settings, listener, null);\n    }\n\n    /**\n     * start wifi scan in background\n     *\n     * @param settings   specifies various parameters for the scan; for more information look at\n     *                   {@link ScanSettings}\n     * @param workSource WorkSource to blame for power usage\n     * @param listener   specifies the object to report events to. This object is also treated as a\n     *                   key for this scan, and must also be specified to cancel the scan. Multiple\n     *                   scans should also not share this object.\n     * @deprecated Background scan support has always been hardware vendor dependent. This support\n     * may not be present on newer devices. Use {@link #startScan(ScanSettings, ScanListener)}\n     * instead for single scans.\n     */\n    @Deprecated\n    @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)\n    public void startBackgroundScan(ScanSettings settings, ScanListener listener,\n                                    WorkSource workSource) {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * stop an ongoing wifi scan\n     *\n     * @param listener specifies which scan to cancel; must be same object as passed in {@link\n     *                 #startBackgroundScan}\n     * @deprecated Background scan support has always been hardware vendor dependent. This support\n     * may not be present on newer devices. Use {@link #startScan(ScanSettings, ScanListener)}\n     * instead for single scans.\n     */\n    @Deprecated\n    @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)\n    public void stopBackgroundScan(ScanListener listener) {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * reports currently available scan results on appropriate listeners\n     *\n     * @return true if all scan results were reported correctly\n     * @deprecated Background scan support has always been hardware vendor dependent. This support\n     * may not be present on newer devices. Use {@link #startScan(ScanSettings, ScanListener)}\n     * instead for single scans.\n     */\n    @Deprecated\n    @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)\n    public boolean getScanResults() {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * starts a single scan and reports results asynchronously\n     *\n     * @param settings specifies various parameters for the scan; for more information look at\n     *                 {@link ScanSettings}\n     * @param listener specifies the object to report events to. This object is also treated as a\n     *                 key for this scan, and must also be specified to cancel the scan. Multiple\n     *                 scans should also not share this object.\n     */\n    @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)\n    public void startScan(ScanSettings settings, ScanListener listener) {\n        startScan(settings, listener, null);\n    }\n\n    /**\n     * starts a single scan and reports results asynchronously\n     *\n     * @param settings   specifies various parameters for the scan; for more information look at\n     *                   {@link ScanSettings}\n     * @param listener   specifies the object to report events to. This object is also treated as a\n     *                   key for this scan, and must also be specified to cancel the scan. Multiple\n     *                   scans should also not share this object.\n     * @param workSource WorkSource to blame for power usage\n     */\n    @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)\n    public void startScan(ScanSettings settings, ScanListener listener, WorkSource workSource) {\n        startScan(settings, null, listener, workSource);\n    }\n\n    /**\n     * starts a single scan and reports results asynchronously\n     *\n     * @param settings   specifies various parameters for the scan; for more information look at\n     *                   {@link ScanSettings}\n     * @param executor   the Executor on which to run the callback.\n     * @param listener   specifies the object to report events to. This object is also treated as a\n     *                   key for this scan, and must also be specified to cancel the scan. Multiple\n     *                   scans should also not share this object.\n     * @param workSource WorkSource to blame for power usage\n     * @hide\n     */\n    @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)\n    public void startScan(ScanSettings settings, @Nullable Executor executor,\n                          ScanListener listener, WorkSource workSource) {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * stops an ongoing single shot scan; only useful after {@link #startScan} if onResults()\n     * hasn't been called on the listener, ignored otherwise\n     *\n     * @param listener\n     */\n    @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)\n    public void stopScan(ScanListener listener) {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Retrieve the most recent scan results from a single scan request.\n     */\n    @NonNull\n    @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)\n    public List<ScanResult> getSingleScanResults() {\n        throw new UnsupportedOperationException();\n    }\n\n    private void startPnoScan(ScanSettings scanSettings, PnoSettings pnoSettings, int key) {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Start wifi connected PNO scan\n     *\n     * @param scanSettings specifies various parameters for the scan; for more information look at\n     *                     {@link ScanSettings}\n     * @param pnoSettings  specifies various parameters for PNO; for more information look at\n     *                     {@link PnoSettings}\n     * @param executor     the Executor on which to run the callback.\n     * @param listener     specifies the object to report events to. This object is also treated as a\n     *                     key for this scan, and must also be specified to cancel the scan. Multiple\n     *                     scans should also not share this object.\n     *                     {@hide}\n     */\n    public void startConnectedPnoScan(ScanSettings scanSettings, PnoSettings pnoSettings,\n                                      @NonNull Executor executor, PnoScanListener listener) {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Start wifi disconnected PNO scan\n     *\n     * @param scanSettings specifies various parameters for the scan; for more information look at\n     *                     {@link ScanSettings}\n     * @param pnoSettings  specifies various parameters for PNO; for more information look at\n     *                     {@link PnoSettings}\n     * @param listener     specifies the object to report events to. This object is also treated as a\n     *                     key for this scan, and must also be specified to cancel the scan. Multiple\n     *                     scans should also not share this object.\n     *                     {@hide}\n     */\n    public void startDisconnectedPnoScan(ScanSettings scanSettings, PnoSettings pnoSettings,\n                                         @NonNull Executor executor, PnoScanListener listener) {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Stop an ongoing wifi PNO scan\n     *\n     * @param listener specifies which scan to cancel; must be same object as passed in {@link\n     *                 #startPnoScan}\n     *                 {@hide}\n     */\n    public void stopPnoScan(ScanListener listener) {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * specifies information about an access point of interest\n     */\n    @Deprecated\n    public static class BssidInfo {\n        /**\n         * bssid of the access point; in XX:XX:XX:XX:XX:XX format\n         */\n        public String bssid;\n        /**\n         * low signal strength threshold; more information at {@link ScanResult#level}\n         */\n        public int low;                                            /* minimum RSSI */\n        /**\n         * high signal threshold; more information at {@link ScanResult#level}\n         */\n        public int high;                                           /* maximum RSSI */\n        /**\n         * channel frequency (in KHz) where you may find this BSSID\n         */\n        public int frequencyHint;\n    }\n\n    /**\n     * @hide\n     */\n    @Deprecated\n    public static class WifiChangeSettings implements Parcelable {\n        public int rssiSampleSize;                          /* sample size for RSSI averaging */\n        public int lostApSampleSize;                        /* samples to confirm AP's loss */\n        public int unchangedSampleSize;                     /* samples to confirm no change */\n        public int minApsBreachingThreshold;                /* change threshold to trigger event */\n        public int periodInMs;                              /* scan period in millisecond */\n        public BssidInfo[] bssidInfos;\n\n        /**\n         * Implement the Parcelable interface {@hide}\n         */\n        public int describeContents() {\n            return 0;\n        }\n\n        /**\n         * Implement the Parcelable interface {@hide}\n         */\n        public void writeToParcel(Parcel dest, int flags) {\n        }\n\n        /**\n         * Implement the Parcelable interface {@hide}\n         */\n        public static final @NonNull Creator<WifiChangeSettings> CREATOR =\n                new Creator<WifiChangeSettings>() {\n                    public WifiChangeSettings createFromParcel(Parcel in) {\n                        return new WifiChangeSettings();\n                    }\n\n                    public WifiChangeSettings[] newArray(int size) {\n                        return new WifiChangeSettings[size];\n                    }\n                };\n\n    }\n\n    /**\n     * configure WifiChange detection\n     *\n     * @param rssiSampleSize           number of samples used for RSSI averaging\n     * @param lostApSampleSize         number of samples to confirm an access point's loss\n     * @param unchangedSampleSize      number of samples to confirm there are no changes\n     * @param minApsBreachingThreshold minimum number of access points that need to be\n     *                                 out of range to detect WifiChange\n     * @param periodInMs               indicates period of scan to find changes\n     * @param bssidInfos               access points to watch\n     */\n    @Deprecated\n    @SuppressLint(\"RequiresPermission\")\n    public void configureWifiChange(\n            int rssiSampleSize,                             /* sample size for RSSI averaging */\n            int lostApSampleSize,                           /* samples to confirm AP's loss */\n            int unchangedSampleSize,                        /* samples to confirm no change */\n            int minApsBreachingThreshold,                   /* change threshold to trigger event */\n            int periodInMs,                                 /* period of scan */\n            BssidInfo[] bssidInfos                          /* signal thresholds to cross */\n    ) {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * interface to get wifi change events on; use this on {@link #startTrackingWifiChange}\n     */\n    @Deprecated\n    public interface WifiChangeListener extends ActionListener {\n        /**\n         * indicates that changes were detected in wifi environment\n         *\n         * @param results indicate the access points that exhibited change\n         */\n        public void onChanging(ScanResult[] results);           /* changes are found */\n\n        /**\n         * indicates that no wifi changes are being detected for a while\n         *\n         * @param results indicate the access points that are bing monitored for change\n         */\n        public void onQuiescence(ScanResult[] results);         /* changes settled down */\n    }\n\n    /**\n     * track changes in wifi environment\n     *\n     * @param listener object to report events on; this object must be unique and must also be\n     *                 provided on {@link #stopTrackingWifiChange}\n     */\n    @Deprecated\n    @SuppressLint(\"RequiresPermission\")\n    public void startTrackingWifiChange(WifiChangeListener listener) {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * stop tracking changes in wifi environment\n     *\n     * @param listener object that was provided to report events on {@link\n     *                 #stopTrackingWifiChange}\n     */\n    @Deprecated\n    @SuppressLint(\"RequiresPermission\")\n    public void stopTrackingWifiChange(WifiChangeListener listener) {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * @hide\n     */\n    @Deprecated\n    @SuppressLint(\"RequiresPermission\")\n    public void configureWifiChange(WifiChangeSettings settings) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Deprecated\n    public static interface BssidListener extends ActionListener {\n        /**\n         * indicates that access points were found by on going scans\n         *\n         * @param results list of scan results, one for each access point visible currently\n         */\n        public void onFound(ScanResult[] results);\n\n        /**\n         * indicates that access points were missed by on going scans\n         *\n         * @param results list of scan results, for each access point that is not visible anymore\n         */\n        public void onLost(ScanResult[] results);\n    }\n\n    /**\n     * @hide\n     */\n    @Deprecated\n    public static class HotlistSettings implements Parcelable {\n        public BssidInfo[] bssidInfos;\n        public int apLostThreshold;\n\n        /**\n         * Implement the Parcelable interface {@hide}\n         */\n        public int describeContents() {\n            return 0;\n        }\n\n        /**\n         * Implement the Parcelable interface {@hide}\n         */\n        public void writeToParcel(Parcel dest, int flags) {\n        }\n\n        /**\n         * Implement the Parcelable interface {@hide}\n         */\n        public static final @NonNull Creator<HotlistSettings> CREATOR =\n                new Creator<HotlistSettings>() {\n                    public HotlistSettings createFromParcel(Parcel in) {\n                        HotlistSettings settings = new HotlistSettings();\n                        return settings;\n                    }\n\n                    public HotlistSettings[] newArray(int size) {\n                        return new HotlistSettings[size];\n                    }\n                };\n    }\n\n    /**\n     * set interesting access points to find\n     *\n     * @param bssidInfos      access points of interest\n     * @param apLostThreshold number of scans needed to indicate that AP is lost\n     * @param listener        object provided to report events on; this object must be unique and must\n     *                        also be provided on {@link #stopTrackingBssids}\n     */\n    @Deprecated\n    @SuppressLint(\"RequiresPermission\")\n    public void startTrackingBssids(BssidInfo[] bssidInfos,\n                                    int apLostThreshold, BssidListener listener) {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * remove tracking of interesting access points\n     *\n     * @param listener same object provided in {@link #startTrackingBssids}\n     */\n    @Deprecated\n    @SuppressLint(\"RequiresPermission\")\n    public void stopTrackingBssids(BssidListener listener) {\n        throw new UnsupportedOperationException();\n    }\n\n\n    /* private members and methods */\n\n    private static final String TAG = \"WifiScanner\";\n    private static final boolean DBG = false;\n\n    /* commands for Wifi Service */\n    private static final int BASE;\n\n    static {\n        if (1==1) throw new UnsupportedOperationException();\n        BASE = 0;\n    }\n\n    /**\n     * @hide\n     */\n    public static final int CMD_START_BACKGROUND_SCAN = BASE + 2;\n    /**\n     * @hide\n     */\n    public static final int CMD_STOP_BACKGROUND_SCAN = BASE + 3;\n    /**\n     * @hide\n     */\n    public static final int CMD_GET_SCAN_RESULTS = BASE + 4;\n    /**\n     * @hide\n     */\n    public static final int CMD_SCAN_RESULT = BASE + 5;\n    /**\n     * @hide\n     */\n    public static final int CMD_OP_SUCCEEDED = BASE + 17;\n    /**\n     * @hide\n     */\n    public static final int CMD_OP_FAILED = BASE + 18;\n    /**\n     * @hide\n     */\n    public static final int CMD_FULL_SCAN_RESULT = BASE + 20;\n    /**\n     * @hide\n     */\n    public static final int CMD_START_SINGLE_SCAN = BASE + 21;\n    /**\n     * @hide\n     */\n    public static final int CMD_STOP_SINGLE_SCAN = BASE + 22;\n    /**\n     * @hide\n     */\n    public static final int CMD_SINGLE_SCAN_COMPLETED = BASE + 23;\n    /**\n     * @hide\n     */\n    public static final int CMD_START_PNO_SCAN = BASE + 24;\n    /**\n     * @hide\n     */\n    public static final int CMD_STOP_PNO_SCAN = BASE + 25;\n    /**\n     * @hide\n     */\n    public static final int CMD_PNO_NETWORK_FOUND = BASE + 26;\n    /**\n     * @hide\n     */\n    public static final int CMD_REGISTER_SCAN_LISTENER = BASE + 27;\n    /**\n     * @hide\n     */\n    public static final int CMD_DEREGISTER_SCAN_LISTENER = BASE + 28;\n    /**\n     * @hide\n     */\n    public static final int CMD_GET_SINGLE_SCAN_RESULTS = BASE + 29;\n    /**\n     * @hide\n     */\n    public static final int CMD_ENABLE = BASE + 30;\n    /**\n     * @hide\n     */\n    public static final int CMD_DISABLE = BASE + 31;\n\n    private Context mContext;\n\n    private static final int INVALID_KEY = 0;\n    private int mListenerKey = 1;\n\n    private final SparseArray mListenerMap = new SparseArray();\n    private final SparseArray<Executor> mExecutorMap = new SparseArray<>();\n    private final Object mListenerMapLock = new Object();\n\n\n\n    // Add a listener into listener map. If the listener already exists, return INVALID_KEY and\n    // send an error message to internal handler; Otherwise add the listener to the listener map and\n    // return the key of the listener.\n    private int addListener(ActionListener listener, Executor executor) {\n        throw new UnsupportedOperationException();\n    }\n\n    private int putListener(Object listener) {\n        if (listener == null) return INVALID_KEY;\n        int key;\n        synchronized (mListenerMapLock) {\n            do {\n                key = mListenerKey++;\n            } while (key == INVALID_KEY);\n            mListenerMap.put(key, listener);\n        }\n        return key;\n    }\n\n    private static class ListenerWithExecutor {\n        @Nullable\n        final Object mListener;\n        @Nullable\n        final Executor mExecutor;\n\n        ListenerWithExecutor(@Nullable Object listener, @Nullable Executor executor) {\n            mListener = listener;\n            mExecutor = executor;\n        }\n    }\n\n    private ListenerWithExecutor getListenerWithExecutor(int key) {\n        if (key == INVALID_KEY) return new ListenerWithExecutor(null, null);\n        synchronized (mListenerMapLock) {\n            Object listener = mListenerMap.get(key);\n            Executor executor = mExecutorMap.get(key);\n            return new ListenerWithExecutor(listener, executor);\n        }\n    }\n\n    private int getListenerKey(Object listener) {\n        if (listener == null) return INVALID_KEY;\n        synchronized (mListenerMapLock) {\n            int index = mListenerMap.indexOfValue(listener);\n            if (index == -1) {\n                return INVALID_KEY;\n            } else {\n                return mListenerMap.keyAt(index);\n            }\n        }\n    }\n\n    private Object removeListener(int key) {\n        if (key == INVALID_KEY) return null;\n        synchronized (mListenerMapLock) {\n            Object listener = mListenerMap.get(key);\n            mListenerMap.remove(key);\n            mExecutorMap.remove(key);\n            return listener;\n        }\n    }\n\n    private int removeListener(Object listener) {\n        int key = getListenerKey(listener);\n        if (key == INVALID_KEY) {\n            Log.e(TAG, \"listener cannot be found\");\n            return key;\n        }\n        synchronized (mListenerMapLock) {\n            mListenerMap.remove(key);\n            mExecutorMap.remove(key);\n            return key;\n        }\n    }\n\n    /**\n     * @hide\n     */\n    @VisibleForTesting\n    public Handler getInternalHandler() {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * @hide\n     */\n    public static class OperationResult implements Parcelable {\n        public int reason;\n        public String description;\n\n        public OperationResult(int reason, String description) {\n            this.reason = reason;\n            this.description = description;\n        }\n\n        /**\n         * Implement the Parcelable interface {@hide}\n         */\n        public int describeContents() {\n            return 0;\n        }\n\n        /**\n         * Implement the Parcelable interface {@hide}\n         */\n        public void writeToParcel(Parcel dest, int flags) {\n            dest.writeInt(reason);\n            dest.writeString(description);\n        }\n\n        /**\n         * Implement the Parcelable interface {@hide}\n         */\n        public static final @NonNull Creator<OperationResult> CREATOR =\n                new Creator<OperationResult>() {\n                    public OperationResult createFromParcel(Parcel in) {\n                        int reason = in.readInt();\n                        String description = in.readString();\n                        return new OperationResult(reason, description);\n                    }\n\n                    public OperationResult[] newArray(int size) {\n                        return new OperationResult[size];\n                    }\n                };\n    }\n\n    private class ServiceHandler extends Handler {\n        ServiceHandler(Looper looper) {\n            super(looper);\n        }\n\n        @Override\n        public void handleMessage(Message msg) {\n            throw new UnsupportedOperationException();\n        }\n    }\n}"
  },
  {
    "path": "play-services-location/core/system-api/src/main/java/com/android/internal/location/ProviderProperties.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2021 The Android Open Source Project\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.android.internal.location;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\n/**\n * A Parcelable containing (legacy) location provider properties.\n * This object is just used inside the framework and system services.\n *\n * @hide\n */\npublic final class ProviderProperties implements Parcelable {\n    /**\n     * True if provider requires access to a\n     * data network (e.g., the Internet), false otherwise.\n     */\n    public final boolean mRequiresNetwork;\n\n    /**\n     * True if the provider requires access to a\n     * satellite-based positioning system (e.g., GPS), false\n     * otherwise.\n     */\n    public final boolean mRequiresSatellite;\n\n    /**\n     * True if the provider requires access to an appropriate\n     * cellular network (e.g., to make use of cell tower IDs), false\n     * otherwise.\n     */\n    public final boolean mRequiresCell;\n\n    /**\n     * True if the use of this provider may result in a\n     * monetary charge to the user, false if use is free.  It is up to\n     * each provider to give accurate information. Cell (network) usage\n     * is not considered monetary cost.\n     */\n    public final boolean mHasMonetaryCost;\n\n    /**\n     * True if the provider is able to provide altitude\n     * information, false otherwise.  A provider that reports altitude\n     * under most circumstances but may occasionally not report it\n     * should return true.\n     */\n    public final boolean mSupportsAltitude;\n\n    /**\n     * True if the provider is able to provide speed\n     * information, false otherwise.  A provider that reports speed\n     * under most circumstances but may occasionally not report it\n     * should return true.\n     */\n    public final boolean mSupportsSpeed;\n\n    /**\n     * True if the provider is able to provide bearing\n     * information, false otherwise.  A provider that reports bearing\n     * under most circumstances but may occasionally not report it\n     * should return true.\n     */\n    public final boolean mSupportsBearing;\n\n    /**\n     * Power requirement for this provider.\n     *\n     * @return the power requirement for this provider, as one of the\n     * constants Criteria.POWER_*.\n     */\n    public final int mPowerRequirement;\n\n    /**\n     * Constant describing the horizontal accuracy returned\n     * by this provider.\n     *\n     * @return the horizontal accuracy for this provider, as one of the\n     * constants Criteria.ACCURACY_COARSE or Criteria.ACCURACY_FINE\n     */\n    public final int mAccuracy;\n\n    public ProviderProperties(boolean mRequiresNetwork,\n            boolean mRequiresSatellite, boolean mRequiresCell, boolean mHasMonetaryCost,\n            boolean mSupportsAltitude, boolean mSupportsSpeed, boolean mSupportsBearing,\n            int mPowerRequirement, int mAccuracy) {\n        this.mRequiresNetwork = mRequiresNetwork;\n        this.mRequiresSatellite = mRequiresSatellite;\n        this.mRequiresCell = mRequiresCell;\n        this.mHasMonetaryCost = mHasMonetaryCost;\n        this.mSupportsAltitude = mSupportsAltitude;\n        this.mSupportsSpeed = mSupportsSpeed;\n        this.mSupportsBearing = mSupportsBearing;\n        this.mPowerRequirement = mPowerRequirement;\n        this.mAccuracy = mAccuracy;\n    }\n\n    public static final Parcelable.Creator<ProviderProperties> CREATOR =\n            new Parcelable.Creator<ProviderProperties>() {\n                @Override\n                public ProviderProperties createFromParcel(Parcel in) {\n                    return null;\n                }\n\n                @Override\n                public ProviderProperties[] newArray(int size) {\n                    return null;\n                }\n            };\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(Parcel parcel, int flags) {\n    }\n}\n"
  },
  {
    "path": "play-services-location/core/system-api/src/main/java/com/android/internal/location/ProviderRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2012, The Android Open Source Project\n * SPDX-FileCopyrightText: 2014, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.android.internal.location;\n\nimport android.location.LocationRequest;\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport java.util.List;\n\n/**\n * @hide\n */\npublic final class ProviderRequest implements Parcelable {\n    /**\n     * Location reporting is requested (true)\n     */\n    public boolean reportLocation = false;\n\n    /**\n     * The smallest requested interval\n     */\n    public long interval = Long.MAX_VALUE;\n\n    /**\n     * A more detailed set of requests.\n     * <p>Location Providers can optionally use this to\n     * fine tune location updates, for example when there\n     * is a high power slow interval request and a\n     * low power fast interval request.\n     */\n    public List<LocationRequest> locationRequests = null;\n\n    public ProviderRequest() {\n    }\n\n    public static final Parcelable.Creator<ProviderRequest> CREATOR =\n            new Parcelable.Creator<ProviderRequest>() {\n                @Override\n                public ProviderRequest createFromParcel(Parcel in) {\n                    return null;\n                }\n\n                @Override\n                public ProviderRequest[] newArray(int size) {\n                    return null;\n                }\n            };\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(Parcel parcel, int flags) {\n    }\n}\n"
  },
  {
    "path": "play-services-location/core/system-api/src/main/java/com/android/location/provider/GeocodeProvider.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2010, The Android Open Source Project\n * SPDX-FileCopyrightText: 2014, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.android.location.provider;\n\nimport android.location.Address;\nimport android.location.GeocoderParams;\nimport android.os.IBinder;\n\nimport java.util.List;\n\n/**\n * Base class for geocode providers implemented as unbundled services.\n * <p/>\n * <p>Geocode providers can be implemented as services and return the result of\n * {@link GeocodeProvider#getBinder()} in its getBinder() method.\n * <p/>\n * <p>IMPORTANT: This class is effectively a public API for unbundled\n * applications, and must remain API stable. See README.txt in the root\n * of this package for more information.\n */\npublic abstract class GeocodeProvider {\n    /**\n     * This method is overridden to implement the\n     * {@link android.location.Geocoder#getFromLocation(double, double, int)} method.\n     * Classes implementing this method should not hold a reference to the params parameter.\n     */\n    public abstract String onGetFromLocation(double latitude, double longitude, int maxResults,\n            GeocoderParams params, List<Address> addrs);\n\n    /**\n     * This method is overridden to implement the\n     * {@link android.location.Geocoder#getFromLocationName(String, int, double, double, double, double)} method.\n     * Classes implementing this method should not hold a reference to the params parameter.\n     */\n    public abstract String onGetFromLocationName(String locationName,\n            double lowerLeftLatitude, double lowerLeftLongitude,\n            double upperRightLatitude, double upperRightLongitude, int maxResults,\n            GeocoderParams params, List<Address> addrs);\n\n    /**\n     * Returns the Binder interface for the geocode provider.\n     * This is intended to be used for the onBind() method of\n     * a service that implements a geocoder service.\n     *\n     * @return the IBinder instance for the provider\n     */\n    public IBinder getBinder() {\n        return null;\n    }\n}\n"
  },
  {
    "path": "play-services-location/core/system-api/src/main/java/com/android/location/provider/LocationProvider.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2010, The Android Open Source Project\n * SPDX-FileCopyrightText: 2014, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.android.location.provider;\n\nimport android.location.Criteria;\nimport android.location.Location;\nimport android.os.Bundle;\nimport android.os.IBinder;\nimport android.os.WorkSource;\n\n/**\n * An abstract superclass for location providers that are implemented\n * outside of the core android platform.\n * Location providers can be implemented as services and return the result of\n * {@link LocationProvider#getBinder()} in its getBinder() method.\n *\n * @hide\n */\npublic abstract class LocationProvider {\n\n    public LocationProvider() {\n    }\n\n    /**\n     * Returns the Binder interface for the location provider.\n     * This is intended to be used for the onBind() method of\n     * a service that implements a location provider service.\n     *\n     * @return the IBinder instance for the provider\n     */\n    public IBinder getBinder() {\n        return null;\n    }\n\n    /**\n     * Used by the location provider to report new locations.\n     *\n     * @param location new Location to report\n     *                 <p/>\n     *                 Requires the android.permission.INSTALL_LOCATION_PROVIDER permission.\n     */\n    public void reportLocation(Location location) {\n    }\n\n    /**\n     * Returns true if the provider requires access to a\n     * data network (e.g., the Internet), false otherwise.\n     */\n    public abstract boolean onRequiresNetwork();\n\n    /**\n     * Returns true if the provider requires access to a\n     * satellite-based positioning system (e.g., GPS), false\n     * otherwise.\n     */\n    public abstract boolean onRequiresSatellite();\n\n    /**\n     * Returns true if the provider requires access to an appropriate\n     * cellular network (e.g., to make use of cell tower IDs), false\n     * otherwise.\n     */\n    public abstract boolean onRequiresCell();\n\n    /**\n     * Returns true if the use of this provider may result in a\n     * monetary charge to the user, false if use is free.  It is up to\n     * each provider to give accurate information.\n     */\n    public abstract boolean onHasMonetaryCost();\n\n    /**\n     * Returns true if the provider is able to provide altitude\n     * information, false otherwise.  A provider that reports altitude\n     * under most circumstances but may occassionally not report it\n     * should return true.\n     */\n    public abstract boolean onSupportsAltitude();\n\n    /**\n     * Returns true if the provider is able to provide speed\n     * information, false otherwise.  A provider that reports speed\n     * under most circumstances but may occassionally not report it\n     * should return true.\n     */\n    public abstract boolean onSupportsSpeed();\n\n    /**\n     * Returns true if the provider is able to provide bearing\n     * information, false otherwise.  A provider that reports bearing\n     * under most circumstances but may occassionally not report it\n     * should return true.\n     */\n    public abstract boolean onSupportsBearing();\n\n    /**\n     * Returns the power requirement for this provider.\n     *\n     * @return the power requirement for this provider, as one of the\n     * constants Criteria.POWER_REQUIREMENT_*.\n     */\n    public abstract int onGetPowerRequirement();\n\n    /**\n     * Returns true if this provider meets the given criteria,\n     * false otherwise.\n     */\n    public abstract boolean onMeetsCriteria(Criteria criteria);\n\n    /**\n     * Returns a constant describing horizontal accuracy of this provider.\n     * If the provider returns finer grain or exact location,\n     * {@link Criteria#ACCURACY_FINE} is returned, otherwise if the\n     * location is only approximate then {@link Criteria#ACCURACY_COARSE}\n     * is returned.\n     */\n    public abstract int onGetAccuracy();\n\n    /**\n     * Enables the location provider\n     */\n    public abstract void onEnable();\n\n    /**\n     * Disables the location provider\n     */\n    public abstract void onDisable();\n\n    /**\n     * Returns a information on the status of this provider.\n     * {@link android.location.LocationProvider#OUT_OF_SERVICE} is returned if the provider is\n     * out of service, and this is not expected to change in the near\n     * future; {@link android.location.LocationProvider#TEMPORARILY_UNAVAILABLE} is returned if\n     * the provider is temporarily unavailable but is expected to be\n     * available shortly; and {@link android.location.LocationProvider#AVAILABLE} is returned\n     * if the provider is currently available.\n     * <p/>\n     * <p> If extras is non-null, additional status information may be\n     * added to it in the form of provider-specific key/value pairs.\n     */\n    public abstract int onGetStatus(Bundle extras);\n\n    /**\n     * Returns the time at which the status was last updated. It is the\n     * responsibility of the provider to appropriately set this value using\n     * {@link android.os.SystemClock#elapsedRealtime SystemClock.elapsedRealtime()}.\n     * there is a status update that it wishes to broadcast to all its\n     * listeners. The provider should be careful not to broadcast\n     * the same status again.\n     *\n     * @return time of last status update in millis since last reboot\n     */\n    public abstract long onGetStatusUpdateTime();\n\n    /**\n     * Returns debugging information about the location provider.\n     *\n     * @return string describing the internal state of the location provider, or null.\n     */\n    public abstract String onGetInternalState();\n\n    /**\n     * Notifies the location provider that clients are listening for locations.\n     * Called with enable set to true when the first client is added and\n     * called with enable set to false when the last client is removed.\n     * This allows the provider to prepare for receiving locations,\n     * and to shut down when no clients are remaining.\n     *\n     * @param enable true if location tracking should be enabled.\n     */\n    public abstract void onEnableLocationTracking(boolean enable);\n\n    /**\n     * Notifies the location provider of the smallest minimum time between updates amongst\n     * all clients that are listening for locations.  This allows the provider to reduce\n     * the frequency of updates to match the requested frequency.\n     *\n     * @param minTime the smallest minTime value over all listeners for this provider.\n     * @param ws      the source this work is coming from.\n     */\n    public abstract void onSetMinTime(long minTime, WorkSource ws);\n\n    /**\n     * Updates the network state for the given provider. This function must\n     * be overwritten if {@link android.location.LocationProvider#requiresNetwork} returns true.\n     * The state is {@link android.location.LocationProvider#TEMPORARILY_UNAVAILABLE} (disconnected)\n     * OR {@link android.location.LocationProvider#AVAILABLE} (connected or connecting).\n     *\n     * @param state data state\n     */\n    @SuppressWarnings(\"deprecation\")\n    public abstract void onUpdateNetworkState(int state, android.net.NetworkInfo info);\n\n    /**\n     * Informs the provider when a new location has been computed by a different\n     * location provider.  This is intended to be used as aiding data for the\n     * receiving provider.\n     *\n     * @param location new location from other location provider\n     */\n    public abstract void onUpdateLocation(Location location);\n\n    /**\n     * Implements addditional location provider specific additional commands.\n     *\n     * @param command name of the command to send to the provider.\n     * @param extras  optional arguments for the command (or null).\n     *                The provider may optionally fill the extras Bundle with results from the command.\n     * @return true if the command succeeds.\n     */\n    public abstract boolean onSendExtraCommand(String command, Bundle extras);\n\n    /**\n     * Notifies the location provider when a new client is listening for locations.\n     *\n     * @param uid user ID of the new client.\n     * @param ws  a WorkSource representation of the client.\n     */\n    public abstract void onAddListener(int uid, WorkSource ws);\n\n    /**\n     * Notifies the location provider when a client is no longer listening for locations.\n     *\n     * @param uid user ID of the client no longer listening.\n     * @param ws  a WorkSource representation of the client.\n     */\n    public abstract void onRemoveListener(int uid, WorkSource ws);\n}\n"
  },
  {
    "path": "play-services-location/core/system-api/src/main/java/com/android/location/provider/LocationProviderBase.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2010, The Android Open Source Project\n * SPDX-FileCopyrightText: 2014, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.android.location.provider;\n\nimport android.content.Context;\nimport android.location.Location;\nimport android.location.LocationManager;\nimport android.location.LocationProvider;\nimport android.location.provider.ProviderProperties;\nimport android.os.Build.VERSION_CODES;\nimport android.os.Bundle;\nimport android.os.IBinder;\nimport android.os.WorkSource;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\n\nimport java.io.FileDescriptor;\nimport java.io.PrintWriter;\nimport java.util.List;\n\n/**\n * Base class for location providers implemented as unbundled services.\n *\n * <p>The network location provider must export a service with action\n * \"com.android.location.service.v2.NetworkLocationProvider\"\n * and a valid minor version in a meta-data field on the service, and\n * then return the result of {@link #getBinder()} on service binding.\n *\n * <p>The fused location provider must export a service with action\n * \"com.android.location.service.FusedLocationProvider\"\n * and a valid minor version in a meta-data field on the service, and\n * then return the result of {@link #getBinder()} on service binding.\n *\n * <p>IMPORTANT: This class is effectively a public API for unbundled\n * applications, and must remain API stable. See README.txt in the root\n * of this package for more information.\n *\n * @deprecated This class is not part of the standard API surface - use\n * {@link android.location.provider.LocationProviderBase} instead.\n */\n@Deprecated\npublic abstract class LocationProviderBase {\n\n    /**\n     * Callback to be invoked when a flush operation is complete and all flushed locations have been\n     * reported.\n     */\n    protected interface OnFlushCompleteCallback {\n\n        /**\n         * Should be invoked once the flush is complete.\n         */\n        void onFlushComplete();\n    }\n\n    /**\n     * Bundle key for a version of the location containing no GPS data.\n     * Allows location providers to flag locations as being safe to\n     * feed to LocationFudger.\n     *\n     * @deprecated Do not use from Android R onwards.\n     */\n    @Deprecated\n    public static final String EXTRA_NO_GPS_LOCATION = \"noGPSLocation\";\n\n    /**\n     * Name of the Fused location provider.\n     *\n     * <p>This provider combines inputs for all possible location sources\n     * to provide the best possible Location fix.\n     */\n    public static final String FUSED_PROVIDER = LocationManager.FUSED_PROVIDER;\n\n    final String mTag;\n    @Nullable\n    final String mAttributionTag;\n    final IBinder mBinder;\n\n\n    volatile ProviderProperties mProperties;\n    volatile boolean mAllowed;\n\n    /**\n     * @deprecated Prefer\n     * {@link #LocationProviderBase(Context, String, ProviderPropertiesUnbundled)}.\n     */\n    @Deprecated\n    public LocationProviderBase(String tag, ProviderPropertiesUnbundled properties) {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * This constructor associates the feature id of the given context with this location provider.\n     * The location service may afford special privileges to incoming calls identified as belonging\n     * to this location provider.\n     */\n    @RequiresApi(VERSION_CODES.R)\n    public LocationProviderBase(Context context, String tag,\n                                ProviderPropertiesUnbundled properties) {\n        throw new UnsupportedOperationException();\n    }\n\n    public IBinder getBinder() {\n        return mBinder;\n    }\n\n    /**\n     * @deprecated Use {@link #setAllowed(boolean)} instead.\n     */\n    @Deprecated\n    @RequiresApi(VERSION_CODES.Q)\n    public void setEnabled(boolean enabled) {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Sets whether this provider is currently allowed or not. Note that this is specific to the\n     * provider only, and is not related to global location settings. This is a hint to the Location\n     * Manager that this provider will generally be unable to fulfill incoming requests. This\n     * provider may still receive callbacks to onSetRequest while not allowed, and must decide\n     * whether to attempt to satisfy those requests or not.\n     *\n     * <p>Some guidelines: providers should set their own allowed/disallowed status based only on\n     * state \"owned\" by that provider. For instance, providers should not take into account the\n     * state of the location master setting when setting themselves allowed or disallowed, as this\n     * state is not owned by a particular provider. If a provider requires some additional user\n     * consent that is particular to the provider, this should be use to set the allowed/disallowed\n     * state. If the provider proxies to another provider, the child provider's allowed/disallowed\n     * state should be taken into account in the parent's allowed state. For most providers, it is\n     * expected that they will be always allowed.\n     */\n    @RequiresApi(VERSION_CODES.R)\n    public void setAllowed(boolean allowed) {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Sets the provider properties that may be queried by clients. Generally speaking, providers\n     * should try to avoid changing their properties after construction.\n     */\n    @RequiresApi(VERSION_CODES.Q)\n    public void setProperties(ProviderPropertiesUnbundled properties) {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Sets a list of additional packages that should be considered as part of this location\n     * provider for the purposes of generating locations. This should generally only be used when\n     * another package may issue location requests on behalf of this package in the course of\n     * providing location. This will inform location services to treat the other packages as\n     * location providers as well.\n     *\n     * @deprecated On Android R and above this has no effect.\n     */\n    @Deprecated\n    @RequiresApi(VERSION_CODES.Q)\n    public void setAdditionalProviderPackages(List<String> packageNames) {}\n\n    /**\n     * @deprecated Use {@link #isAllowed()} instead.\n     */\n    @Deprecated\n    @RequiresApi(VERSION_CODES.Q)\n    public boolean isEnabled() {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Returns true if this provider is allowed. Providers start as allowed on construction.\n     */\n    @RequiresApi(VERSION_CODES.R)\n    public boolean isAllowed() {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Reports a new location from this provider.\n     */\n    public void reportLocation(@NonNull Location location) {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Reports a new batch of locations from this provider. Locations must be ordered in the list\n     * from earliest first to latest last.\n     */\n    public void reportLocations(@NonNull List<Location> locations) {\n        throw new UnsupportedOperationException();\n    }\n\n    protected void onInit() {\n        // call once so that providers designed for APIs pre-Q are not broken\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * @deprecated This callback will be invoked once when the provider is created to maintain\n     * backwards compatibility with providers not designed for Android Q and above. This method\n     * should only be implemented in location providers that need to support SDKs below Android Q.\n     * Even in this case, it is usually unnecessary to implement this callback with the correct\n     * design. This method may be removed in the future.\n     */\n    @Deprecated\n    protected void onEnable() {}\n\n    /**\n     * @deprecated This callback will be never be invoked on Android Q and above. This method should\n     * only be implemented in location providers that need to support SDKs below Android Q. Even in\n     * this case, it is usually unnecessary to implement this callback with the correct design. This\n     * method may be removed in the future.\n     */\n    @Deprecated\n    protected void onDisable() {}\n\n    /**\n     * Set the {@link ProviderRequestUnbundled} requirements for this provider. Each call to this method\n     * overrides all previous requests. This method might trigger the provider to start returning\n     * locations, or to stop returning locations, depending on the parameters in the request.\n     */\n    protected abstract void onSetRequest(ProviderRequestUnbundled request, WorkSource source);\n\n    /**\n     * Requests a flush of any pending batched locations. The callback must always be invoked once\n     * per invocation, and should be invoked after {@link #reportLocation(Location)} or\n     * {@link #reportLocations(List)} has been invoked with any flushed locations. The callback may\n     * be invoked immediately if no locations are flushed.\n     */\n    protected void onFlush(OnFlushCompleteCallback callback) {\n        callback.onFlushComplete();\n    }\n\n    /**\n     * @deprecated This callback will never be invoked on Android Q and above. This method may be\n     * removed in the future. Prefer to dump provider state via the containing service instead.\n     */\n    @Deprecated\n    protected void onDump(FileDescriptor fd, PrintWriter pw, String[] args) {}\n\n    /**\n     * This method will no longer be invoked.\n     *\n     * @deprecated This callback will be never be invoked on Android Q and above. This method should\n     * only be implemented in location providers that need to support SDKs below Android Q. This\n     * method may be removed in the future.\n     */\n    @Deprecated\n    protected int onGetStatus(Bundle extras) {\n        return LocationProvider.AVAILABLE;\n    }\n\n    /**\n     * This method will no longer be invoked.\n     *\n     * @deprecated This callback will be never be invoked on Android Q and above. This method should\n     * only be implemented in location providers that need to support SDKs below Android Q. This\n     * method may be removed in the future.\n     */\n    @Deprecated\n    protected long onGetStatusUpdateTime() {\n        return 0;\n    }\n\n    /**\n     * Implements location provider specific custom commands. The return value will be ignored on\n     * Android Q and above.\n     */\n    protected boolean onSendExtraCommand(@Nullable String command, @Nullable Bundle extras) {\n        return false;\n    }\n}"
  },
  {
    "path": "play-services-location/core/system-api/src/main/java/com/android/location/provider/LocationRequestUnbundled.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2012, The Android Open Source Project\n * SPDX-FileCopyrightText: 2014, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.android.location.provider;\n\nimport android.location.LocationRequest;\n\n/**\n * This class is an interface to LocationRequests for unbundled applications.\n * <p/>\n * <p>IMPORTANT: This class is effectively a public API for unbundled\n * applications, and must remain API stable. See README.txt in the root\n * of this package for more information.\n */\npublic final class LocationRequestUnbundled {\n    /**\n     * Returned by {@link #getQuality} when requesting the most accurate locations available.\n     * <p/>\n     * <p>This may be up to 1 meter accuracy, although this is implementation dependent.\n     */\n    public static final int ACCURACY_FINE = LocationRequest.ACCURACY_FINE;\n\n    /**\n     * Returned by {@link #getQuality} when requesting \"block\" level accuracy.\n     * <p/>\n     * <p>Block level accuracy is considered to be about 100 meter accuracy,\n     * although this is implementation dependent. Using a coarse accuracy\n     * such as this often consumes less power.\n     */\n    public static final int ACCURACY_BLOCK = LocationRequest.ACCURACY_BLOCK;\n\n    /**\n     * Returned by {@link #getQuality} when requesting \"city\" level accuracy.\n     * <p/>\n     * <p>City level accuracy is considered to be about 10km accuracy,\n     * although this is implementation dependent. Using a coarse accuracy\n     * such as this often consumes less power.\n     */\n    public static final int ACCURACY_CITY = LocationRequest.ACCURACY_CITY;\n\n    /**\n     * Returned by {@link #getQuality} when requiring no direct power impact (passive locations).\n     * <p/>\n     * <p>This location request will not trigger any active location requests,\n     * but will receive locations triggered by other applications. Your application\n     * will not receive any direct power blame for location work.\n     */\n    public static final int POWER_NONE = LocationRequest.POWER_NONE;\n\n    /**\n     * Returned by {@link #getQuality} when requesting low power impact.\n     * <p/>\n     * <p>This location request will avoid high power location work where\n     * possible.\n     */\n    public static final int POWER_LOW = LocationRequest.POWER_LOW;\n\n    /**\n     * Returned by {@link #getQuality} when allowing high power consumption for location.\n     * <p/>\n     * <p>This location request will allow high power location work.\n     */\n    public static final int POWER_HIGH = LocationRequest.POWER_HIGH;\n\n    /**\n     * Get the desired interval of this request, in milliseconds.\n     *\n     * @return desired interval in milliseconds, inexact\n     */\n    public long getInterval() {\n        return 0;\n    }\n\n    /**\n     * Get the fastest interval of this request, in milliseconds.\n     * <p/>\n     * <p>The system will never provide location updates faster\n     * than the minimum of {@link #getFastestInterval} and\n     * {@link #getInterval}.\n     *\n     * @return fastest interval in milliseconds, exact\n     */\n    public long getFastestInterval() {\n        return 0;\n    }\n\n    /**\n     * Get the quality of the request.\n     *\n     * @return an accuracy or power constant\n     */\n    public int getQuality() {\n        return 0;\n    }\n\n    /**\n     * Get the minimum distance between location updates, in meters.\n     *\n     * @return minimum distance between location updates in meters\n     */\n    public float getSmallestDisplacement() {\n        return 0;\n    }\n}\n"
  },
  {
    "path": "play-services-location/core/system-api/src/main/java/com/android/location/provider/ProviderPropertiesUnbundled.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2012, The Android Open Source Project\n * SPDX-FileCopyrightText: 2014, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.android.location.provider;\n\nimport com.android.internal.location.ProviderProperties;\n\n/**\n * This class is an interface to Provider Properties for unbundled applications.\n * <p/>\n * <p>IMPORTANT: This class is effectively a public API for unbundled\n * applications, and must remain API stable. See README.txt in the root\n * of this package for more information.\n */\npublic final class ProviderPropertiesUnbundled {\n    public static ProviderPropertiesUnbundled create(boolean requiresNetwork,\n            boolean requiresSatellite, boolean requiresCell, boolean hasMonetaryCost,\n            boolean supportsAltitude, boolean supportsSpeed, boolean supportsBearing,\n            int powerRequirement, int accuracy) {\n        return null;\n    }\n\n    public ProviderProperties getProviderProperties() {\n        return null;\n    }\n}\n"
  },
  {
    "path": "play-services-location/core/system-api/src/main/java/com/android/location/provider/ProviderRequestUnbundled.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2012 The Android Open Source Project\n * SPDX-FileCopyrightText: 2014 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.android.location.provider;\n\nimport android.os.Build;\nimport android.os.WorkSource;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.RequiresApi;\nimport com.android.internal.location.ProviderRequest;\n\nimport java.util.List;\n\n/**\n * This class is an interface to Provider Requests for unbundled applications.\n * <p/>\n * <p>IMPORTANT: This class is effectively a public API for unbundled\n * applications, and must remain API stable. See README.txt in the root\n * of this package for more information.\n */\npublic final class ProviderRequestUnbundled {\n    public static long INTERVAL_DISABLED;\n    public ProviderRequestUnbundled(ProviderRequest request) {\n    }\n\n    /**\n     * True if this is an active request with a valid location reporting interval, false if this\n     * request is inactive and does not require any locations to be reported.\n     */\n    public boolean getReportLocation() {\n        return false;\n    }\n\n    /**\n     * The interval at which a provider should report location. Will return\n     * {@link #INTERVAL_DISABLED} for an inactive request.\n     */\n    public long getInterval() {\n        return 0;\n    }\n\n    /**\n     * The quality hint for this location request. The quality hint informs the provider how it\n     * should attempt to manage any accuracy vs power tradeoffs while attempting to satisfy this\n     * provider request.\n     */\n    @RequiresApi(Build.VERSION_CODES.S)\n    public int getQuality() {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * The maximum time any location update may be delayed, and thus grouped with following updates\n     * to enable location batching. If the maximum update delay is equal to or greater than\n     * twice the interval, then the provider may provide batched results if possible. The maximum\n     * batch size a provider is allowed to return is the maximum update delay divided by the\n     * interval.\n     */\n    @RequiresApi(Build.VERSION_CODES.S)\n    public long getMaxUpdateDelayMillis() {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Whether any applicable hardware low power modes should be used to satisfy this request.\n     */\n    @RequiresApi(Build.VERSION_CODES.S)\n    public boolean isLowPower() {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Whether the provider should ignore all location settings, user consents, power restrictions\n     * or any other restricting factors and always satisfy this request to the best of their\n     * ability. This should only be used in case of a user initiated emergency.\n     */\n    @RequiresApi(Build.VERSION_CODES.Q)\n    public boolean isLocationSettingsIgnored() {\n        throw new UnsupportedOperationException();\n    }\n\n\n    /**\n     * The full list of location requests contributing to this provider request.\n     *\n     * @deprecated Do not use.\n     */\n    @Deprecated\n    public @NonNull List<LocationRequestUnbundled> getLocationRequests() {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * The power blame for this provider request.\n     */\n    @RequiresApi(Build.VERSION_CODES.S)\n    public @NonNull WorkSource getWorkSource() {\n        throw new UnsupportedOperationException();\n    }\n}\n"
  },
  {
    "path": "play-services-location/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<manifest />\n"
  },
  {
    "path": "play-services-location/src/main/aidl/com/google/android/gms/location/ActivityRecognitionRequest.aidl",
    "content": "package com.google.android.gms.location;\n\nparcelable ActivityRecognitionRequest;"
  },
  {
    "path": "play-services-location/src/main/aidl/com/google/android/gms/location/ActivityRecognitionResult.aidl",
    "content": "package com.google.android.gms.location;\n\nparcelable ActivityRecognitionResult;"
  },
  {
    "path": "play-services-location/src/main/aidl/com/google/android/gms/location/ActivityTransitionRequest.aidl",
    "content": "package com.google.android.gms.location;\n\nparcelable ActivityTransitionRequest;"
  },
  {
    "path": "play-services-location/src/main/aidl/com/google/android/gms/location/CurrentLocationRequest.aidl",
    "content": "package com.google.android.gms.location;\n\nparcelable CurrentLocationRequest;\n"
  },
  {
    "path": "play-services-location/src/main/aidl/com/google/android/gms/location/DeviceOrientation.aidl",
    "content": "package com.google.android.gms.location;\n\nparcelable DeviceOrientation;\n"
  },
  {
    "path": "play-services-location/src/main/aidl/com/google/android/gms/location/GeofencingRequest.aidl",
    "content": "package com.google.android.gms.location;\n\nparcelable GeofencingRequest;\n"
  },
  {
    "path": "play-services-location/src/main/aidl/com/google/android/gms/location/GestureRequest.aidl",
    "content": "package com.google.android.gms.location;\n\nparcelable GestureRequest;\n"
  },
  {
    "path": "play-services-location/src/main/aidl/com/google/android/gms/location/IDeviceOrientationListener.aidl",
    "content": "package com.google.android.gms.location;\n\nimport com.google.android.gms.location.DeviceOrientation;\n\ninterface IDeviceOrientationListener {\n    oneway void onDeviceOrientationChanged(in DeviceOrientation deviceOrientation);\n}\n"
  },
  {
    "path": "play-services-location/src/main/aidl/com/google/android/gms/location/ILocationCallback.aidl",
    "content": "package com.google.android.gms.location;\n\nimport android.location.Location;\n\nimport com.google.android.gms.location.LocationAvailability;\nimport com.google.android.gms.location.LocationResult;\n\ninterface ILocationCallback {\n    oneway void onLocationResult(in LocationResult result) = 0;\n    oneway void onLocationAvailability(in LocationAvailability availability) = 1;\n    oneway void cancel() = 2;\n}\n"
  },
  {
    "path": "play-services-location/src/main/aidl/com/google/android/gms/location/ILocationListener.aidl",
    "content": "package com.google.android.gms.location;\n\nimport android.location.Location;\n\ninterface ILocationListener {\n    oneway void onLocationChanged(in Location location) = 0;\n    oneway void cancel() = 1;\n}\n"
  },
  {
    "path": "play-services-location/src/main/aidl/com/google/android/gms/location/LastLocationRequest.aidl",
    "content": "package com.google.android.gms.location;\n\nparcelable LastLocationRequest;\n"
  },
  {
    "path": "play-services-location/src/main/aidl/com/google/android/gms/location/LocationAvailability.aidl",
    "content": "package com.google.android.gms.location;\n\nparcelable LocationAvailability;\n"
  },
  {
    "path": "play-services-location/src/main/aidl/com/google/android/gms/location/LocationAvailabilityRequest.aidl",
    "content": "package com.google.android.gms.location;\n\nparcelable LocationAvailabilityRequest;\n"
  },
  {
    "path": "play-services-location/src/main/aidl/com/google/android/gms/location/LocationRequest.aidl",
    "content": "package com.google.android.gms.location;\n\nparcelable LocationRequest;\n"
  },
  {
    "path": "play-services-location/src/main/aidl/com/google/android/gms/location/LocationResult.aidl",
    "content": "package com.google.android.gms.location;\n\nparcelable LocationResult;\n"
  },
  {
    "path": "play-services-location/src/main/aidl/com/google/android/gms/location/LocationSettingsRequest.aidl",
    "content": "package com.google.android.gms.location;\n\nparcelable LocationSettingsRequest;\n"
  },
  {
    "path": "play-services-location/src/main/aidl/com/google/android/gms/location/LocationSettingsResult.aidl",
    "content": "package com.google.android.gms.location;\n\nparcelable LocationSettingsResult;\n"
  },
  {
    "path": "play-services-location/src/main/aidl/com/google/android/gms/location/LocationStatus.aidl",
    "content": "package com.google.android.gms.location;\n\nparcelable LocationStatus;\n"
  },
  {
    "path": "play-services-location/src/main/aidl/com/google/android/gms/location/SleepSegmentRequest.aidl",
    "content": "package com.google.android.gms.location;\n\nparcelable SleepSegmentRequest;\n"
  },
  {
    "path": "play-services-location/src/main/aidl/com/google/android/gms/location/internal/DeviceOrientationRequestUpdateData.aidl",
    "content": "package com.google.android.gms.location.internal;\n\nparcelable DeviceOrientationRequestUpdateData;\n"
  },
  {
    "path": "play-services-location/src/main/aidl/com/google/android/gms/location/internal/FusedLocationProviderResult.aidl",
    "content": "package com.google.android.gms.location.internal;\n\nparcelable FusedLocationProviderResult;\n"
  },
  {
    "path": "play-services-location/src/main/aidl/com/google/android/gms/location/internal/IBooleanStatusCallback.aidl",
    "content": "package com.google.android.gms.location.internal;\n\nimport com.google.android.gms.common.api.Status;\n\ninterface IBooleanStatusCallback {\n    void onBooleanStatus(in Status status, boolean bool);\n}\n"
  },
  {
    "path": "play-services-location/src/main/aidl/com/google/android/gms/location/internal/IFusedLocationProviderCallback.aidl",
    "content": "package com.google.android.gms.location.internal;\n\nimport com.google.android.gms.location.internal.FusedLocationProviderResult;\n\ninterface IFusedLocationProviderCallback {\n    oneway void onFusedLocationProviderResult(in FusedLocationProviderResult result) = 0;\n    oneway void cancel() = 1;\n}\n"
  },
  {
    "path": "play-services-location/src/main/aidl/com/google/android/gms/location/internal/IGeofencerCallbacks.aidl",
    "content": "package com.google.android.gms.location.internal;\n\nimport android.app.PendingIntent;\n\ninterface IGeofencerCallbacks {\n    oneway void onAddGeofenceResult(int statusCode, in String[] requestIds) = 0;\n    oneway void onRemoveGeofencesByRequestIdsResult(int statusCode, in String[] requestIds) = 1;\n    oneway void onRemoveGeofencesByPendingIntentResult(int statusCode, in PendingIntent pendingIntent) = 2;\n}\n"
  },
  {
    "path": "play-services-location/src/main/aidl/com/google/android/gms/location/internal/IGoogleLocationManagerService.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.location.internal;\n\nimport android.app.PendingIntent;\nimport android.location.Location;\nimport android.os.Bundle;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.common.api.internal.IStatusCallback;\nimport com.google.android.gms.common.internal.ICancelToken;\nimport com.google.android.gms.location.internal.DeviceOrientationRequestUpdateData;\nimport com.google.android.gms.location.internal.IBooleanStatusCallback;\nimport com.google.android.gms.location.internal.IFusedLocationProviderCallback;\nimport com.google.android.gms.location.internal.IGeofencerCallbacks;\nimport com.google.android.gms.location.internal.ILocationStatusCallback;\nimport com.google.android.gms.location.internal.ISettingsCallbacks;\nimport com.google.android.gms.location.internal.LocationReceiver;\nimport com.google.android.gms.location.internal.LocationRequestInternal;\nimport com.google.android.gms.location.internal.LocationRequestUpdateData;\nimport com.google.android.gms.location.internal.ParcelableGeofence;\nimport com.google.android.gms.location.internal.RemoveGeofencingRequest;\nimport com.google.android.gms.location.internal.SetGoogleLocationAccuracyRequest;\nimport com.google.android.gms.location.ActivityRecognitionResult;\nimport com.google.android.gms.location.ActivityRecognitionRequest;\nimport com.google.android.gms.location.ActivityTransitionRequest;\nimport com.google.android.gms.location.CurrentLocationRequest;\nimport com.google.android.gms.location.GeofencingRequest;\nimport com.google.android.gms.location.GestureRequest;\nimport com.google.android.gms.location.ILocationListener;\nimport com.google.android.gms.location.LastLocationRequest;\nimport com.google.android.gms.location.LocationAvailability;\nimport com.google.android.gms.location.LocationAvailabilityRequest;\nimport com.google.android.gms.location.LocationRequest;\nimport com.google.android.gms.location.LocationSettingsRequest;\nimport com.google.android.gms.location.LocationStatus;\nimport com.google.android.gms.location.SleepSegmentRequest;\n\ninterface IGoogleLocationManagerService {\n\n    void addGeofencesWithCallback(in GeofencingRequest request, in PendingIntent pendingIntent, IStatusCallback callback) = 96;\n    void removeGeofencesWithCallback(in RemoveGeofencingRequest request, IStatusCallback callback) = 97;\n\n    void requestActivityTransitionUpdates(in ActivityTransitionRequest request, in PendingIntent pendingIntent, IStatusCallback callback) = 71;\n    void requestActivityUpdates(long detectionIntervalMillis, boolean triggerUpdates, in PendingIntent callbackIntent) = 4;\n    void requestActivityUpdatesWithCallback(in ActivityRecognitionRequest request, in PendingIntent pendingIntent, IStatusCallback callback) = 69;\n    void removeActivityTransitionUpdates(in PendingIntent pendingIntent, IStatusCallback callback) = 72;\n    void removeActivityUpdates(in PendingIntent callbackIntent) = 5;\n\n    void getLastLocationWithReceiver(in LastLocationRequest request, in LocationReceiver receiver) = 89;\n\n    ICancelToken getCurrentLocationWithReceiver(in CurrentLocationRequest request, in LocationReceiver receiver) = 91;\n\n    void requestLocationUpdatesWithCallback(in LocationReceiver receiver, in LocationRequest request, IStatusCallback callback) = 87;\n    void removeLocationUpdatesWithCallback(in LocationReceiver receiver, IStatusCallback callback) = 88;\n\n    void flushLocations(IFusedLocationProviderCallback callback) = 66;\n\n    void getLocationAvailabilityWithReceiver(in LocationAvailabilityRequest request, in LocationReceiver receiver) = 90;\n\n    void setMockModeWithCallback(boolean mockMode, IStatusCallback callback) = 83;\n    void setMockLocationWithCallback(in Location mockLocation, IStatusCallback callback) = 84;\n\n    void requestSleepSegmentUpdates(in PendingIntent pendingIntent, in SleepSegmentRequest request, IStatusCallback callback) = 78;\n    void removeSleepSegmentUpdates(in PendingIntent pendingIntent, IStatusCallback callback) = 68;\n\n    void requestLocationSettingsDialog(in LocationSettingsRequest settingsRequest, ISettingsCallbacks callback, String packageName) = 62;\n\n    void updateDeviceOrientationRequest(in DeviceOrientationRequestUpdateData request) = 74;\n\n    void isGoogleLocationAccuracyEnabled(in IBooleanStatusCallback callback) = 94;\n\n    // deprecated\n    // these are marked as deprecated in latest version of play-services-location client library and will likely move to outdated eventually\n\n    void addGeofences(in GeofencingRequest request, in PendingIntent pendingIntent, IGeofencerCallbacks callbacks) = 56;\n    void removeGeofences(in RemoveGeofencingRequest request, IGeofencerCallbacks callback) = 73;\n\n    Location getLastLocation() = 6;\n    void getLastLocationWithRequest(in LastLocationRequest request, ILocationStatusCallback callback) = 81;\n\n    ICancelToken getCurrentLocation(in CurrentLocationRequest request, ILocationStatusCallback callback) = 86;\n\n    void updateLocationRequest(in LocationRequestUpdateData locationRequestUpdateData) = 58;\n\n    LocationAvailability getLocationAvailabilityWithPackage(String packageName) = 33;\n\n    void setMockMode(boolean mockMode) = 11;\n    void setMockLocation(in Location mockLocation) = 12;\n\n    // outdated or private\n    // these are not present in latest version of play-services-location client library but might be in use by outdated apps or apps with private API access\n\n    void addGeofencesList(in List<ParcelableGeofence> geofences, in PendingIntent pendingIntent, IGeofencerCallbacks callbacks, String packageName) = 0;\n    void removeGeofencesByIntent(in PendingIntent pendingIntent, IGeofencerCallbacks callbacks, String packageName) = 1;\n    void removeGeofencesById(in String[] geofenceRequestIds, IGeofencerCallbacks callbacks, String packageName) = 2;\n    void removeAllGeofences(IGeofencerCallbacks callbacks, String packageName) = 3;\n\n    ActivityRecognitionResult getLastActivity(String packageName) = 63;\n\n    Location getLastLocationWithPackage(String packageName) = 20;\n    Location getLastLocationWith(String s) = 79;\n\n    void requestLocationUpdatesWithListener(in LocationRequest request, ILocationListener listener) = 7;\n    void requestLocationUpdatesWithPackage(in LocationRequest request, ILocationListener listener, String packageName) = 19;\n    void requestLocationUpdatesWithIntent(in LocationRequest request, in PendingIntent callbackIntent) = 8;\n    void requestLocationUpdatesInternalWithListener(in LocationRequestInternal request, ILocationListener listener) = 51;\n    void requestLocationUpdatesInternalWithIntent(in LocationRequestInternal request, in PendingIntent callbackIntent) = 52;\n    void removeLocationUpdatesWithListener(ILocationListener listener) = 9;\n    void removeLocationUpdatesWithIntent(in PendingIntent callbackIntent) = 10;\n\n//    void injectLocation(in Location mockLocation, int injectionType) = 25;\n//    void injectLocationWithCallback(in Location mockLocation, int injectionType, IStatusCallback callback) = 85;\n\n    void setGoogleLocationAccuracy(in SetGoogleLocationAccuracyRequest request, IStatusCallback callback) = 95;\n\n    // unsupported\n\n//    void iglms14(in LatLngBounds var1, int var2, in PlaceFilter var3, in PlacesParams var4, IPlacesCallbacks var5) = 13;\n//    void iglms15(String var1, in PlacesParams var2, IPlacesCallbacks var3) = 14;\n//    void iglms16(in LatLng var1, in PlaceFilter var2, in PlacesParams var3, IPlacesCallbacks var4) = 15;\n//    void iglms17(in PlaceFilter var1, in PlacesParams var2, IPlacesCallbacks var3) = 16;\n//    void iglms18(in PlaceRequest var1, in PlacesParams var2, in PendingIntent var3) = 17;\n//    void iglms19(in PlacesParams var1, in PendingIntent var2) = 18;\n\n//    void iglms25(in PlaceReport var1, in PlacesParams var2) = 24;\n\n//    void iglms42(String var1, in PlacesParams var2, IPlacesCallbacks var3) = 41;\n\n//    void iglms46(in UserAddedPlace var1, in PlacesParams var2, IPlacesCallbacks var3) = 45;\n//    void iglms47(in LatLngBounds var1, int var2, String var3, in PlaceFilter var4, in PlacesParams var5, IPlacesCallbacks var6) = 46;\n//    void iglms48(in NearbyAlertRequest var1, in PlacesParams var2, in PendingIntent var3) = 47;\n//    void iglms49(in PlacesParams var1, in PendingIntent var2) = 48;\n//    void iglms50(in UserDataType var1, in LatLngBounds var2, in List var3, in PlacesParams var4, IPlacesCallbacks var5) = 49;\n//    IBinder iglms51() = 50;\n\n//    IBinder iglms54() = 53;\n//    void iglms55(String var1, in LatLngBounds var2, in AutocompleteFilter var3, in PlacesParams var4, IPlacesCallbacks var5) = 54;\n\n//    void iglms58(in List var1, in PlacesParams var2, IPlacesCallbacks var3) = 57;\n\n//    Status requestGestureUpdates(in GestureRequest request, in PendingIntent pendingIntent) = 59;\n//    Status iglms61(in PendingIntent pendingIntent) = 60;\n\n//    void iglms65(in PendingIntent pendingIntent, IStatusCallback callback) = 64;\n//    void iglms66(in PendingIntent pendingIntent, IStatusCallback callback) = 65;\n\n//    void iglms68(in PendingIntent pendingIntent, IStatusCallback callback) = 67;\n\n//    void iglms71(IStatusCallback callback) = 70;\n\n//    void iglms76(in PendingIntent pendingIntent) = 75;\n//    boolean setActivityRecognitionMode(int mode) = 76;\n//    int getActivityRecognitionMode() = 77;\n}\n"
  },
  {
    "path": "play-services-location/src/main/aidl/com/google/android/gms/location/internal/ILocationAvailabilityStatusCallback.aidl",
    "content": "package com.google.android.gms.location.internal;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.location.LocationAvailability;\n\ninterface ILocationAvailabilityStatusCallback {\n    void onLocationAvailabilityStatus(in Status status, in LocationAvailability location);\n}\n"
  },
  {
    "path": "play-services-location/src/main/aidl/com/google/android/gms/location/internal/ILocationStatusCallback.aidl",
    "content": "package com.google.android.gms.location.internal;\n\nimport android.location.Location;\nimport com.google.android.gms.common.api.Status;\n\ninterface ILocationStatusCallback {\n    void onLocationStatus(in Status status, in Location location);\n}\n"
  },
  {
    "path": "play-services-location/src/main/aidl/com/google/android/gms/location/internal/ISettingsCallbacks.aidl",
    "content": "package com.google.android.gms.location.internal;\n\nimport com.google.android.gms.location.LocationSettingsResult;\n\ninterface ISettingsCallbacks {\n    void onLocationSettingsResult(in LocationSettingsResult result);\n}\n"
  },
  {
    "path": "play-services-location/src/main/aidl/com/google/android/gms/location/internal/LocationReceiver.aidl",
    "content": "package com.google.android.gms.location.internal;\n\nparcelable LocationReceiver;\n"
  },
  {
    "path": "play-services-location/src/main/aidl/com/google/android/gms/location/internal/LocationRequestInternal.aidl",
    "content": "package com.google.android.gms.location.internal;\n\nparcelable LocationRequestInternal;\n"
  },
  {
    "path": "play-services-location/src/main/aidl/com/google/android/gms/location/internal/LocationRequestUpdateData.aidl",
    "content": "package com.google.android.gms.location.internal;\n\nparcelable LocationRequestUpdateData;\n"
  },
  {
    "path": "play-services-location/src/main/aidl/com/google/android/gms/location/internal/ParcelableGeofence.aidl",
    "content": "package com.google.android.gms.location.internal;\n\nparcelable ParcelableGeofence;"
  },
  {
    "path": "play-services-location/src/main/aidl/com/google/android/gms/location/internal/RemoveGeofencingRequest.aidl",
    "content": "package com.google.android.gms.location.internal;\n\nparcelable RemoveGeofencingRequest;\n"
  },
  {
    "path": "play-services-location/src/main/aidl/com/google/android/gms/location/internal/SetGoogleLocationAccuracyRequest.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.location.internal;\n\nparcelable SetGoogleLocationAccuracyRequest;\n"
  },
  {
    "path": "play-services-location/src/main/aidl/com/google/android/gms/location/reporting/OptInRequest.aidl",
    "content": "package com.google.android.gms.location.reporting;\n\nparcelable OptInRequest;\n"
  },
  {
    "path": "play-services-location/src/main/aidl/com/google/android/gms/location/reporting/ReportingState.aidl",
    "content": "package com.google.android.gms.location.reporting;\n\nparcelable ReportingState;"
  },
  {
    "path": "play-services-location/src/main/aidl/com/google/android/gms/location/reporting/SendDataRequest.aidl",
    "content": "package com.google.android.gms.location.reporting;\n\nparcelable SendDataRequest;\n"
  },
  {
    "path": "play-services-location/src/main/aidl/com/google/android/gms/location/reporting/UlrPrivateModeRequest.aidl",
    "content": "package com.google.android.gms.location.reporting;\n\nparcelable UlrPrivateModeRequest;\n"
  },
  {
    "path": "play-services-location/src/main/aidl/com/google/android/gms/location/reporting/UploadRequest.aidl",
    "content": "package com.google.android.gms.location.reporting;\n\nparcelable UploadRequest;"
  },
  {
    "path": "play-services-location/src/main/aidl/com/google/android/gms/location/reporting/UploadRequestResult.aidl",
    "content": "package com.google.android.gms.location.reporting;\n\nparcelable UploadRequestResult;"
  },
  {
    "path": "play-services-location/src/main/aidl/com/google/android/gms/location/reporting/internal/IReportingService.aidl",
    "content": "package com.google.android.gms.location.reporting.internal;\n\nimport android.accounts.Account;\n//import com.google.android.gms.location.places.PlaceReport;\nimport com.google.android.gms.location.reporting.OptInRequest;\nimport com.google.android.gms.location.reporting.ReportingState;\nimport com.google.android.gms.location.reporting.SendDataRequest;\nimport com.google.android.gms.location.reporting.UlrPrivateModeRequest;\nimport com.google.android.gms.location.reporting.UploadRequest;\nimport com.google.android.gms.location.reporting.UploadRequestResult;\n\ninterface IReportingService {\n    ReportingState getReportingState(in Account account) = 0;\n    int tryOptInAccount(in Account account) = 1;\n    UploadRequestResult requestUpload(in UploadRequest request) = 2;\n    int cancelUploadRequest(long l) = 3;\n//    int reportDeviceAtPlace(in Account account, in PlaceReport report) = 4;\n    int tryOptIn(in OptInRequest request) = 5;\n    int sendData(in SendDataRequest request) = 6;\n    int requestPrivateMode(in UlrPrivateModeRequest request) = 7;\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/ActivityRecognition.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2017 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.location;\n\nimport android.app.Activity;\nimport android.content.Context;\n\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.GoogleApiClient;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.location.ActivityRecognitionApiClientBuilder;\nimport org.microg.gms.location.ActivityRecognitionApiImpl;\n\n/**\n * The main entry point for activity recognition integration.\n */\n@PublicApi\npublic class ActivityRecognition {\n    public static final String CLIENT_NAME = \"activity_recognition\";\n\n    /**\n     * Token to pass to {@link GoogleApiClient.Builder#addApi(Api)} to enable ActivityRecognition.\n     *\n     * @deprecated Use {@link ActivityRecognitionClient} instead.\n     */\n    @Deprecated\n    public static final Api<Api.ApiOptions.NoOptions> API = new Api<Api.ApiOptions.NoOptions>(new ActivityRecognitionApiClientBuilder());\n\n    /**\n     * Entry point to the activity recognition APIs.\n     *\n     * @deprecated Use {@link ActivityRecognitionClient} instead.\n     */\n    @Deprecated\n    public static final ActivityRecognitionApi ActivityRecognitionApi = new ActivityRecognitionApiImpl();\n\n    /**\n     * Create a new instance of {@link ActivityRecognitionClient} for use in an {@link Activity}.\n     */\n    public static ActivityRecognitionClient getClient (Activity activity) {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Create a new instance of {@link ActivityRecognitionClient} for use in a non-activity {@link Context}.\n     */\n    public static ActivityRecognitionClient getClient (Context context) {\n        throw new UnsupportedOperationException();\n    }\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/ActivityRecognitionApi.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2017 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.location;\n\nimport android.app.PendingIntent;\nimport android.os.Bundle;\n\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;\nimport com.google.android.gms.common.api.PendingResult;\nimport com.google.android.gms.common.api.Status;\n\n/**\n * The main entry point for interacting with activity recognition.\n * <p>\n * The methods must be used in conjunction with a GoogleApiClient. E.g.\n * <pre>\n *  new GoogleApiClient.Builder(context)\n *          .addApi(ActivityRecognition.API)\n *          .addConnectionCallbacks(this)\n *          .addOnConnectionFailedListener(this)\n *          .build()\n * </pre>\n *\n * @deprecated Use the GoogleApi-based API {@link ActivityRecognitionClient} instead.\n */\npublic interface ActivityRecognitionApi {\n    /**\n     * Removes all activity updates for the specified PendingIntent.\n     * <p>\n     * Calling this function requires the com.google.android.gms.permission.ACTIVITY_RECOGNITION\n     * permission.\n     *\n     * @param client         An existing GoogleApiClient. It must be connected at the time of this\n     *                       call, which is normally achieved by calling {@link GoogleApiClient#connect()}\n     *                       and waiting for {@link ConnectionCallbacks#onConnected(Bundle)} to be\n     *                       called.\n     * @param callbackIntent the PendingIntent that was used in {@code #requestActivityUpdates(GoogleApiClient, long, PendingIntent)}\n     *                       or is equal as defined by {@link Object#equals(Object)}.\n     * @return a PendingResult for the call, check {@link Status#isSuccess()} to determine if it\n     * was successful.\n     */\n    PendingResult<Status> removeActivityUpdates(GoogleApiClient client, PendingIntent callbackIntent);\n\n    /**\n     * Register for activity recognition updates.\n     * <p>\n     * The activities are detected by periodically waking up the device and reading short bursts of\n     * sensor data. It only makes use of low power sensors in order to keep the power usage to a\n     * minimum. For example, it can detect if the user is currently on foot, in a car, on a bicycle\n     * or still. See {@link DetectedActivity} for more details.\n     * <p>\n     * The activity detection update interval can be controlled with the detectionIntervalMillis\n     * parameter. Larger values will result in fewer activity detections while improving battery\n     * life. Smaller values will result in more frequent activity detections but will consume more\n     * power since the device must be woken up more frequently. {@code Long.MAX_VALUE} means it only\n     * monitors the results requested by other clients without consuming additional power.\n     * <p>\n     * Activities may be received more frequently than the detectionIntervalMillis parameter if\n     * another application has also requested activity updates at a faster rate. It may also receive\n     * updates faster when the activity detection service receives a signal that the current\n     * activity may change, such as if the device has been still for a long period of time and is\n     * then unplugged from a phone charger.\n     * <p>\n     * Activities may arrive several seconds after the requested detectionIntervalMillis if the\n     * activity detection service requires more samples to make a more accurate prediction.\n     * <p>\n     * To conserve battery, activity reporting may stop when the device is 'STILL' for an extended\n     * period of time. It will resume once the device moves again. This only happens on devices that\n     * support the Sensor.TYPE_SIGNIFICANT_MOTION hardware.\n     * <p>\n     * Beginning in API 21, activities may be received less frequently than the\n     * detectionIntervalMillis parameter if the device is in power save mode and the screen is off.\n     * <p>\n     * A common use case is that an application wants to monitor activities in the background and\n     * perform an action when a specific activity is detected. To do this without needing a service\n     * that is always on in the background consuming resources, detected activities are delivered\n     * via an intent. The application specifies a PendingIntent callback (typically an\n     * IntentService) which will be called with an intent when activities are detected. The intent\n     * recipient can extract the {@link ActivityRecognitionResult} using {@link ActivityRecognitionResult#extractResult(android.content.Intent)}.\n     * See the documentation of {@link PendingIntent} for more details.\n     * <p>\n     * Any requests previously registered with {@link #requestActivityUpdates(GoogleApiClient, long, PendingIntent)}\n     * that have the same PendingIntent (as defined by {@link Object#equals(Object)}) will be\n     * replaced by this request.\n     * <p>\n     * Calling this function requires the com.google.android.gms.permission.ACTIVITY_RECOGNITION\n     * permission.\n     *\n     * @param client                  An existing GoogleApiClient. It must be connected at the time\n     *                                of this call, which is normally achieved by calling {@link GoogleApiClient#connect()}\n     *                                and waiting for {@link ConnectionCallbacks#onConnected(Bundle)}\n     *                                to be called.\n     * @param detectionIntervalMillis the desired time between activity detections. Larger values\n     *                                will result in fewer activity detections while improving\n     *                                battery life. A value of 0 will result in activity detections\n     *                                at the fastest possible rate.\n     * @param callbackIntent          a PendingIntent to be sent for each activity detection.\n     * @return a PendingResult for the call, check {@link Status#isSuccess()} to determine if it\n     * was successful.\n     */\n    PendingResult<Status> requestActivityUpdates(GoogleApiClient client, long detectionIntervalMillis, PendingIntent callbackIntent);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/ActivityRecognitionClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.location;\n\nimport android.app.PendingIntent;\n\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.ApiException;\nimport com.google.android.gms.common.api.HasApiKey;\nimport com.google.android.gms.tasks.Task;\n\n/**\n * The main entry point for interacting with activity recognition.\n * <p>\n * Activity Recognition provides the following APIs: the <b>Activity Recognition Transition API</b>, the <b>Activity\n * Recognition Sampling API</b>, and the <b>Activity Recognition Sleep API</b>.\n */\npublic interface ActivityRecognitionClient extends HasApiKey<Api.ApiOptions.NoOptions> {\n    /**\n     * Removes activity transition updates associated with the given {@code pendingIntent}.\n     * <p>\n     * To call this function, a different permission is required depending on your Android API level:\n     * <ul>\n     *     <li>For Android 10 (API level 29) and later: {@code android.permission.ACTIVITY_RECOGNITION} permission</li>\n     *     <li>For Android 9 (API level 28) and earlier: {@code com.google.android.gms.permission.ACTIVITY_RECOGNITION} permission</li>\n     * </ul>\n     *\n     * @param pendingIntent the associated {@link PendingIntent} of the activity transition request which is to be removed\n     * @return a {@link Task} for apps to check the status of the call. If the task fails, the status code for the\n     * failure can be found by examining {@link ApiException#getStatusCode()}.\n     */\n    Task<Void> removeActivityTransitionUpdates(PendingIntent pendingIntent);\n\n    /**\n     * Removes all activity updates for the specified PendingIntent.\n     * <p>\n     * To call this function, a different permission is required depending on your Android API level:\n     * <ul>\n     *     <li>For Android 10 (API level 29) and later: {@code android.permission.ACTIVITY_RECOGNITION} permission</li>\n     *     <li>For Android 9 (API level 28) and earlier: {@code com.google.android.gms.permission.ACTIVITY_RECOGNITION} permission</li>\n     * </ul>\n     *\n     * @param callbackIntent the PendingIntent that was used in {@link #requestActivityUpdates(long, PendingIntent)} or\n     *                       is equal as defined by {@link PendingIntent#equals(Object)}.\n     * @return a {@link Task} for apps to check the status of the call. If the task fails, the status code for the\n     * failure can be found by examining {@link ApiException#getStatusCode()}.\n     */\n    Task<Void> removeActivityUpdates(PendingIntent callbackIntent);\n\n    /**\n     * Removes all sleep segment detection updates for the specified {@code PendingIntent}.\n     *\n     * @param callbackIntent the PendingIntent that was used in {@link #requestSleepSegmentUpdates(PendingIntent, SleepSegmentRequest)}\n     *                       or is equal as defined by {@link PendingIntent#equals(Object)}.\n     * @return a {@link Task} for apps to check the status of the call. If the task fails, the status code for the\n     * failure can be found by examining {@link ApiException#getStatusCode()}.\n     */\n    Task<Void> removeSleepSegmentUpdates(PendingIntent callbackIntent);\n\n    /**\n     * Activity Recognition Transition API provides an ability for apps to subscribe to activity transitional conditions (enter, exit). For example, a\n     * messaging app that wants to build a distraction free driving experiences can ask -- tell me when user has entered the vehicle or exited the vehicle. It\n     * doesn't have to worry about user being {@link DetectedActivity#STILL} at the traffic signal, or any other transient activities while in vehicle\n     * ({@link DetectedActivity#IN_VEHICLE}), that is, the API will fence around the activity boundaries using Activity Recognition Filtering.\n     *\n     * @param activityTransitionRequest the interested activity transitions\n     * @param pendingIntent             the {@link PendingIntent} used to generate the callback intent when one of the interested transition has happened\n     * @return a {@link Task} for apps to check the status of the call. If the task fails, the status code for the\n     * failure can be found by examining {@link ApiException#getStatusCode()}.\n     */\n    Task<Void> requestActivityTransitionUpdates(ActivityTransitionRequest activityTransitionRequest, PendingIntent pendingIntent);\n\n    /**\n     * Register for activity recognition updates.\n     * <p>\n     * The activities are detected by periodically waking up the device and reading short bursts of sensor data. It only makes use of low power sensors in order\n     * to keep the power usage to a minimum. For example, it can detect if the user is currently on foot, in a car, on a bicycle or still. See\n     * {@link DetectedActivity} for more details.\n     *\n     * @param detectionIntervalMillis the desired time between activity detections. Larger values will result in fewer activity detections while improving\n     *                                battery life. A value of 0 will result in activity detections at the fastest possible rate. Note that a fast rate can\n     *                                result in excessive device wakelocks and power consumption.\n     * @param callbackIntent          a PendingIntent to be sent for each activity detection.\n     * @return a {@link Task} for apps to check the status of the call. If the task fails, the status code for the\n     * failure can be found by examining {@link ApiException#getStatusCode()}.\n     */\n    Task<Void> requestActivityUpdates(long detectionIntervalMillis, PendingIntent callbackIntent);\n\n    /**\n     * Registers for detected user sleep time ({@code SleepSegmentEvent}) and/or periodic sleep activity classification results ({@code SleepClassifyEvent})\n     * based on the data type specified in {@link SleepSegmentRequest}. It is advised to the apps to re-register after device reboot or app upgrade, from a\n     * receiver that handles {@code android.intent.action.BOOT_COMPLETED} and {@code android.intent.action.MY_PACKAGE_REPLACED} events.\n     *\n     * @param callbackIntent      a PendingIntent to be sent for each sleep segment or classification result\n     * @param sleepSegmentRequest a {@link SleepSegmentRequest} that specifies whether to receive both {@code SleepSegmentEvent}s and\n     *                            {@code SleepClassifyEvent}s, or {@code SleepSegmentEvent}s only, or {@code SleepClassifyEvent}s only.\n     * @return a {@link Task} for apps to check the status of the call. If the task fails, the status code for the\n     * failure can be found by examining {@link ApiException#getStatusCode()}.\n     */\n    Task<Void> requestSleepSegmentUpdates(PendingIntent callbackIntent, SleepSegmentRequest sleepSegmentRequest);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/ActivityRecognitionRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.location;\n\nimport android.os.WorkSource;\nimport androidx.annotation.Nullable;\nimport org.microg.gms.common.Hide;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n@Hide\npublic class ActivityRecognitionRequest extends AutoSafeParcelable {\n    @Field(1)\n    public long intervalMillis;\n    @Field(2)\n    public boolean triggerUpdate;\n    @Field(3)\n    @Nullable\n    public WorkSource workSource;\n    @Field(4)\n    @Nullable\n    public String tag;\n    @Field(5)\n    @Nullable\n    public int[] nonDefaultActivities;\n    @Field(6)\n    public boolean requestSensorData;\n    @Field(7)\n    @Nullable\n    public String accountName;\n    @Field(8)\n    public long maxReportLatencyMillis;\n    @Field(9)\n    @Nullable\n    public String contextAttributionTag;\n\n    public static final Creator<ActivityRecognitionRequest> CREATOR = new AutoCreator<>(ActivityRecognitionRequest.class);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/ActivityRecognitionResult.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.location;\n\nimport android.content.Intent;\nimport android.os.Bundle;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableSerializer;\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\nimport java.util.Collections;\nimport java.util.List;\n\n/**\n * Result of an activity recognition.\n * <p>\n * It contains a list of activities that a user may have been doing at a particular time. The activities are sorted by\n * the most probable activity first. A confidence is associated with each activity which indicates how likely that\n * activity is.\n * <p>\n * {@link #getMostProbableActivity()} will return the most probable activity of the user at the time that activity\n * recognition was run.\n */\n@PublicApi\npublic class ActivityRecognitionResult extends AutoSafeParcelable {\n    public static final Creator<ActivityRecognitionResult> CREATOR = new AutoCreator<>(ActivityRecognitionResult.class);\n\n    @PublicApi(exclude = true)\n    public static final String EXTRA_ACTIVITY_RESULT = \"com.google.android.location.internal.EXTRA_ACTIVITY_RESULT\";\n    @PublicApi(exclude = true)\n    public static final String EXTRA_ACTIVITY_RESULT_LIST = \"com.google.android.location.internal.EXTRA_ACTIVITY_RESULT_LIST\";\n\n    @Field(1000)\n    private int versionCode = 2;\n    @Field(value = 1, subClass = DetectedActivity.class)\n    private List<DetectedActivity> probableActivities;\n    @Field(2)\n    private long time;\n    @Field(3)\n    private long elapsedRealtimeMillis;\n    @Field(5)\n    private Bundle extras;\n\n    private ActivityRecognitionResult() {\n\n    }\n\n    /**\n     * Constructs an ActivityRecognitionResult.\n     *\n     * @param probableActivities    the activities that were detected, sorted by confidence (most probable first).\n     * @param time                  the UTC time of this detection, in milliseconds since January 1, 1970.\n     * @param elapsedRealtimeMillis milliseconds since boot\n     */\n    public ActivityRecognitionResult(List<DetectedActivity> probableActivities, long time, long elapsedRealtimeMillis) {\n        this.probableActivities = probableActivities;\n        this.time = time;\n        this.elapsedRealtimeMillis = elapsedRealtimeMillis;\n    }\n\n    /**\n     * Constructs an ActivityRecognitionResult from a single activity.\n     *\n     * @param mostProbableActivity  the most probable activity of the device.\n     * @param time                  the UTC time of this detection, in milliseconds since January 1, 1970.\n     * @param elapsedRealtimeMillis milliseconds since boot\n     */\n    public ActivityRecognitionResult(DetectedActivity mostProbableActivity, long time, long elapsedRealtimeMillis) {\n        this(Collections.singletonList(mostProbableActivity), time, elapsedRealtimeMillis);\n    }\n\n    /**\n     * Extracts the ActivityRecognitionResult from an Intent.\n     * <p>\n     * This is a utility function which extracts the ActivityRecognitionResult from the extras of an Intent that was\n     * sent from the activity detection service.\n     *\n     * @return an ActivityRecognitionResult, or {@code null} if the intent doesn't contain an ActivityRecognitionResult.\n     */\n    public static ActivityRecognitionResult extractResult(Intent intent) {\n        if (intent.hasExtra(EXTRA_ACTIVITY_RESULT_LIST)) {\n            intent.setExtrasClassLoader(ActivityRecognitionResult.class.getClassLoader());\n            List<ActivityRecognitionResult> list = intent.getParcelableArrayListExtra(EXTRA_ACTIVITY_RESULT_LIST);\n            if (list != null && !list.isEmpty())\n                return list.get(list.size() - 1);\n        }\n        if (intent.hasExtra(EXTRA_ACTIVITY_RESULT)) {\n            Bundle extras = intent.getExtras();\n            extras.setClassLoader(ActivityRecognitionResult.class.getClassLoader());\n            Object res = extras.get(EXTRA_ACTIVITY_RESULT);\n            if (res instanceof ActivityRecognitionResult)\n                return (ActivityRecognitionResult) res;\n            if (res instanceof byte[])\n                return SafeParcelableSerializer.deserializeFromBytes((byte[]) res, CREATOR);\n        }\n        return null;\n    }\n\n    /**\n     * Returns the confidence of the given activity type.\n     */\n    public int getActivityConfidence(int activityType) {\n        for (DetectedActivity activity : probableActivities) {\n            if (activity.getType() == activityType)\n                return activity.getConfidence();\n        }\n        return 0;\n    }\n\n    /**\n     * Returns the elapsed real time of this detection in milliseconds since boot, including time spent in sleep as\n     * obtained by SystemClock.elapsedRealtime().\n     */\n    public long getElapsedRealtimeMillis() {\n        return elapsedRealtimeMillis;\n    }\n\n    /**\n     * Returns the most probable activity of the user.\n     */\n    public DetectedActivity getMostProbableActivity() {\n        return probableActivities.get(0);\n    }\n\n    /**\n     * Returns the list of activities that were detected with the confidence value associated with each activity.\n     * The activities are sorted by most probable activity first.\n     * <p>\n     * The sum of the confidences of all detected activities this method returns does not have to be <= 100 since some\n     * activities are not mutually exclusive (for example, you can be walking while in a bus) and some activities are\n     * hierarchical (ON_FOOT is a generalization of WALKING and RUNNING).\n     */\n    public List<DetectedActivity> getProbableActivities() {\n        return probableActivities;\n    }\n\n    /**\n     * Returns the UTC time of this detection, in milliseconds since January 1, 1970.\n     */\n    public long getTime() {\n        return time;\n    }\n\n    /**\n     * Returns true if an Intent contains an ActivityRecognitionResult.\n     * <p>\n     * This is a utility function that can be called from inside an intent receiver to make sure the received intent is\n     * from activity recognition.\n     *\n     * @return true if the intent contains an ActivityRecognitionResult, false otherwise or the given intent is null\n     */\n    public static boolean hasResult(Intent intent) {\n        if (intent == null) return false;\n        if (intent.hasExtra(EXTRA_ACTIVITY_RESULT)) return true;\n        intent.setExtrasClassLoader(ActivityRecognitionResult.class.getClassLoader());\n        List<ActivityRecognitionResult> list = intent.getParcelableArrayListExtra(EXTRA_ACTIVITY_RESULT_LIST);\n        return list != null && !list.isEmpty();\n    }\n\n    @NonNull\n    public String toString() {\n        return \"ActivityRecognitionResult [probableActivities=\" + probableActivities + \", timeMillis\" + time + \", elapsedRealtimeMillis=\" + elapsedRealtimeMillis + \"]\";\n    }\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/ActivityTransition.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.location;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.util.Objects;\n\n/**\n * Represents an activity and the transition of it. For instance start to walk; stop running etc.\n */\npublic class ActivityTransition extends AutoSafeParcelable {\n    /**\n     * User enters the given activity.\n     */\n    public static final int ACTIVITY_TRANSITION_ENTER = 0;\n    /**\n     * User exits the given activity.\n     */\n    public static final int ACTIVITY_TRANSITION_EXIT = 1;\n\n    @Field(1)\n    private int activityType;\n    @Field(2)\n    private @SupportedActivityTransition int transitionType;\n\n    private ActivityTransition() {\n    }\n\n    private ActivityTransition(int activityType, @SupportedActivityTransition int transitionType) {\n        this.activityType = activityType;\n        this.transitionType = transitionType;\n    }\n\n    /**\n     * Gets the type of the activity to be detected.\n     */\n    public int getActivityType() {\n        return activityType;\n    }\n\n    /**\n     * Gets the interested transition type. It's one of the ACTIVITY_TRANSITION_xxx constants.\n     */\n    public @SupportedActivityTransition int getTransitionType() {\n        return transitionType;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hashCode(new Object[]{activityType, transitionType});\n    }\n\n    @Override\n    public boolean equals(@Nullable Object obj) {\n        return obj instanceof ActivityTransition && ((ActivityTransition) obj).activityType == activityType && ((ActivityTransition) obj).transitionType == transitionType;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return \"ActivityTransition [mActivityType=\" + activityType + \", mTransitionType=\" + transitionType + \"]\";\n    }\n\n    /**\n     * Activity transition constants annotation.\n     */\n    @Target({ElementType.TYPE_USE})\n    @Retention(RetentionPolicy.SOURCE)\n    @IntDef({ACTIVITY_TRANSITION_ENTER, ACTIVITY_TRANSITION_EXIT})\n    public @interface SupportedActivityTransition {\n    }\n\n    /**\n     * The builder to help create an {@link ActivityTransition} object.\n     */\n    public static class Builder {\n        private int activityType;\n        private int transitionType;\n\n        /**\n         * Adds an interested transition type.\n         *\n         * @param transition the interested transition type. It's one of the ACTIVITY_TRANSITION_xxx constants.\n         * @return this builder\n         */\n        public ActivityTransition.Builder setActivityTransition(int transition) {\n            this.transitionType = transition;\n            return this;\n        }\n\n        /**\n         * Sets the type of the activity to be detected.\n         *\n         * @param activityType the type of the activity to be detected. It's one of the constant in {@link DetectedActivity}.\n         * @return this builder\n         */\n        public ActivityTransition.Builder setActivityType(int activityType) {\n            this.activityType = activityType;\n            return this;\n        }\n\n        public ActivityTransition build() {\n            return new ActivityTransition(activityType, transitionType);\n        }\n    }\n\n    public static final Creator<ActivityTransition> CREATOR = new AutoCreator<>(ActivityTransition.class);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/ActivityTransitionEvent.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.location;\n\nimport androidx.annotation.NonNull;\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\nimport java.util.Objects;\n\n/**\n * Represents an activity transition event, for example start to walk, stop running etc.\n */\n@PublicApi\npublic class ActivityTransitionEvent extends AutoSafeParcelable {\n    @Field(1)\n    private int activityType;\n    @Field(2)\n    private int transitionType;\n    @Field(3)\n    private long elapsedRealtimeNanos;\n\n    private ActivityTransitionEvent() {\n    }\n\n    /**\n     * Creates an activity transition event.\n     *\n     * @param activityType         the type of the activity of this transition\n     * @param transitionType       the type of transition\n     * @param elapsedRealtimeNanos the elapsed realtime when this transition happened\n     */\n    public ActivityTransitionEvent(int activityType, int transitionType, long elapsedRealtimeNanos) {\n        this.activityType = activityType;\n        this.transitionType = transitionType;\n        this.elapsedRealtimeNanos = elapsedRealtimeNanos;\n    }\n\n    /**\n     * Gets the type of the activity of this transition. It's one of activity types defined in {@link DetectedActivity}.\n     */\n    public int getActivityType() {\n        return activityType;\n    }\n\n    /**\n     * Gets the elapsed realtime when this transition happened. Note that the event may happen in the past which means this timestamp may be much smaller than\n     * the current time.\n     */\n    public long getElapsedRealTimeNanos() {\n        return elapsedRealtimeNanos;\n    }\n\n    /**\n     * Gets the type of the transition. It's one of the transition types defined in {@link ActivityTransition}.\n     */\n    public int getTransitionType() {\n        return transitionType;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hashCode(new Object[]{activityType, transitionType, elapsedRealtimeNanos});\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof ActivityTransitionEvent)) return false;\n\n        ActivityTransitionEvent that = (ActivityTransitionEvent) o;\n\n        if (activityType != that.activityType) return false;\n        if (transitionType != that.transitionType) return false;\n        return elapsedRealtimeNanos == that.elapsedRealtimeNanos;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return \"ActivityType \" + activityType + \" TransitionType \" + transitionType + \" ElapsedRealTimeNanos \" + elapsedRealtimeNanos;\n    }\n\n    public static final Creator<ActivityTransitionEvent> CREATOR = new AutoCreator<>(ActivityTransitionEvent.class);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/ActivityTransitionRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.location;\n\nimport android.content.Intent;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.ClientIdentity;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableSerializer;\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\nimport java.util.*;\n\n/**\n * The request object for apps to get notified when user's activity changes.\n */\n@PublicApi\npublic class ActivityTransitionRequest extends AutoSafeParcelable {\n    private static final String EXTRA = \"com.google.android.location.internal.EXTRA_ACTIVITY_TRANSITION_REQUEST\";\n\n    @Field(value = 1, subClass = ActivityTransition.class)\n    private List<ActivityTransition> activityTransitions;\n    @Field(2)\n    private String tag;\n    @Field(value = 3, subClass = ClientIdentity.class)\n    private List<ClientIdentity> clients;\n    @Field(4)\n    private String contextAttributionTag;\n\n    /**\n     * The comparator used to determine if two transitions are the same. It's different from {@link ActivityTransition#equals(Object)} because in the future we\n     * may add latency to activity transition and the latency value should not be compared against.\n     */\n    public static final Comparator<ActivityTransition> IS_SAME_TRANSITION = new Comparator<ActivityTransition>() {\n        @Override\n        public int compare(ActivityTransition o1, ActivityTransition o2) {\n            int res = Integer.compare(o1.getActivityType(), o2.getActivityType());\n            if (res != 0) return res;\n            res = Integer.compare(o1.getTransitionType(), o2.getTransitionType());\n            return res;\n        }\n    };\n\n    private ActivityTransitionRequest() {\n    }\n\n    /**\n     * Creates an {@link ActivityTransitionRequest} object by specifying a list of interested activity transitions.\n     *\n     * @param transitions a list of interested activity transitions\n     * @throws NullPointerException     if {@code transitions} is {@code null}\n     * @throws IllegalArgumentException if {@code transitions} is an empty list or if there are duplicated transitions in this list\n     */\n    public ActivityTransitionRequest(List<ActivityTransition> transitions) {\n        if (transitions == null) throw new NullPointerException(\"transitions can't be null\");\n        if (transitions.isEmpty()) throw new IllegalArgumentException(\"transitions can't be empty.\");\n        Set<ActivityTransition> set = new TreeSet<ActivityTransition>(IS_SAME_TRANSITION);\n        set.addAll(transitions);\n        if (transitions.size() != set.size()) throw new IllegalArgumentException(\"Found duplicated transition\");\n        this.activityTransitions = Collections.unmodifiableList(transitions);\n    }\n\n    /**\n     * Serializes this request to the given intent.\n     *\n     * @param intent the intent to serailize this object to\n     */\n    public void serializeToIntentExtra(Intent intent) {\n        intent.putExtra(EXTRA, SafeParcelableSerializer.serializeToBytes(this));\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        ActivityTransitionRequest that = (ActivityTransitionRequest) o;\n\n        if (!Objects.equals(activityTransitions, that.activityTransitions)) return false;\n        if (!Objects.equals(tag, that.tag)) return false;\n        if (!Objects.equals(clients, that.clients)) return false;\n        return Objects.equals(contextAttributionTag, that.contextAttributionTag);\n    }\n\n    @Override\n    public int hashCode() {\n        int result = activityTransitions != null ? activityTransitions.hashCode() : 0;\n        result = 31 * result + (tag != null ? tag.hashCode() : 0);\n        result = 31 * result + (clients != null ? clients.hashCode() : 0);\n        result = 31 * result + (contextAttributionTag != null ? contextAttributionTag.hashCode() : 0);\n        return result;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return \"ActivityTransitionRequest [mTransitions=\" + activityTransitions + \", mTag=\" + tag + \", mClients\" + clients + \", mAttributionTag=\" + contextAttributionTag + \"]\";\n    }\n\n    public static final Creator<ActivityTransitionRequest> CREATOR = new AutoCreator<>(ActivityTransitionRequest.class);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/ActivityTransitionResult.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.location;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableSerializer;\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\nimport java.util.Collections;\nimport java.util.List;\n\n/**\n * Represents the result of activity transitions.\n */\n@PublicApi\npublic class ActivityTransitionResult extends AutoSafeParcelable {\n    private static final String EXTRA = \"com.google.android.location.internal.EXTRA_ACTIVITY_TRANSITION_RESULT\";\n\n    @Field(value = 1, subClass = ActivityTransitionEvent.class)\n    @NonNull\n    private List<ActivityTransitionEvent> transitionEvents;\n    @Field(2)\n    private Bundle extras;\n\n    /**\n     * Constructs a result by specifying a list of transition events.\n     *\n     * @param transitionEvents the transition events\n     * @throws NullPointerException     if {@code transitionEvents} is {@code null}\n     * @throws IllegalArgumentException if the events in {@code transitionEvents} are not in ascending order of time\n     */\n    public ActivityTransitionResult(List<ActivityTransitionEvent> transitionEvents) {\n        if (transitionEvents == null) throw new NullPointerException(\"transitionEvents list can't be null.\");\n        for (int i = 1; i < transitionEvents.size(); i++) {\n            if (transitionEvents.get(i).getElapsedRealTimeNanos() < transitionEvents.get(i - 1).getElapsedRealTimeNanos())\n                throw new IllegalArgumentException();\n        }\n        this.transitionEvents = Collections.unmodifiableList(transitionEvents);\n    }\n\n    /**\n     * Gets all the activity transition events in this result. The events are in ascending order of time, and may include events in the past.\n     */\n    public List<ActivityTransitionEvent> getTransitionEvents() {\n        return transitionEvents;\n    }\n\n    /**\n     * Extracts the {@link ActivityTransitionResult} from the given {@link Intent}.\n     *\n     * @param intent the {@link Intent} to extract the result from\n     * @return the {@link ActivityTransitionResult} included in the given intent or return {@code null} if no such result is found in the given intent\n     */\n    public static ActivityTransitionResult extractResult(Intent intent) {\n        if (!hasResult(intent)) return null;\n        return SafeParcelableSerializer.deserializeFromBytes(intent.getByteArrayExtra(EXTRA), CREATOR);\n    }\n\n    /**\n     * Checks if the intent contains an {@link ActivityTransitionResult}.\n     */\n    public static boolean hasResult(Intent intent) {\n        return intent != null && intent.hasExtra(EXTRA);\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        ActivityTransitionResult that = (ActivityTransitionResult) o;\n\n        return transitionEvents.equals(that.transitionEvents);\n    }\n\n    @Override\n    public int hashCode() {\n        return transitionEvents.hashCode();\n    }\n\n    public static final Creator<ActivityTransitionResult> CREATOR = new AutoCreator<>(ActivityTransitionResult.class);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/CurrentLocationRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.location;\n\nimport android.os.WorkSource;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.location.internal.ClientIdentity;\nimport com.google.android.gms.tasks.CancellationToken;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.location.GranularityUtil;\nimport org.microg.gms.location.PriorityUtil;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n/**\n * An encapsulation of various parameters for requesting the current location through FusedLocationProviderClient.\n *\n * @see FusedLocationProviderClient#getCurrentLocation(CurrentLocationRequest, CancellationToken)\n */\n@PublicApi\npublic class CurrentLocationRequest extends AutoSafeParcelable {\n    @Field(1)\n    private long maxUpdateAgeMillis;\n    @Field(2)\n    private @Granularity int granularity;\n    @Field(3)\n    private @Priority int priority;\n    @Field(4)\n    private long durationMillis;\n    @Field(5)\n    private boolean bypass;\n    @Field(6)\n    private WorkSource workSource;\n    @Field(7)\n    private @ThrottleBehavior int throttleBehavior;\n    @Field(8)\n    private String moduleId;\n    @Field(9)\n    private ClientIdentity impersonation;\n\n    private CurrentLocationRequest() {\n        maxUpdateAgeMillis = Long.MAX_VALUE;\n        granularity = Granularity.GRANULARITY_PERMISSION_LEVEL;\n        priority = Priority.PRIORITY_BALANCED_POWER_ACCURACY;\n        durationMillis = Long.MAX_VALUE;\n        workSource = new WorkSource();\n        throttleBehavior = ThrottleBehavior.THROTTLE_BACKGROUND;\n    }\n\n    /**\n     * The duration in milliseconds of the location request used to derive the current location if no historical location satisfies the current location\n     * request. If this duration expires with no location, the current location request will return a null location. The current location request may fail and\n     * return a null location after a shorter duration (ie, the given duration may be capped internally), but never a longer duration.\n     */\n    public long getDurationMillis() {\n        return durationMillis;\n    }\n\n    /**\n     * The {@link Granularity} of locations returned for this request. This controls whether fine or coarse locations may be returned.\n     */\n    public @Granularity int getGranularity() {\n        return granularity;\n    }\n\n    /**\n     * The maximum age of any location returned for this request. A value of 0 indicates that only freshly derived locations will be returned, and no\n     * historical locations will ever be returned. A value Long.MAX_VALUE represents an effectively unbounded maximum age.\n     * <p>\n     * NOTE: This parameter applies only to historical locations. Freshly derived locations should almost always have timestamps close to the present time -\n     * however it is possible under unlikely conditions for location derivation to take longer than expected, in which case freshly derived locations may have\n     * slightly older timestamps.\n     */\n    public long getMaxUpdateAgeMillis() {\n        return maxUpdateAgeMillis;\n    }\n\n    /**\n     * The {@link Priority} of the location request used to derive the current location if no historical location satisfies the current location request.\n     */\n    public @Priority int getPriority() {\n        return priority;\n    }\n\n    /**\n     * A builder for {@link CurrentLocationRequest}.\n     */\n    public static class Builder {\n        private long maxUpdateAgeMillis;\n        private @Granularity int granularity;\n        private @Priority int priority;\n        private long durationMillis;\n        private boolean bypass;\n        private @ThrottleBehavior int throttleBehavior;\n        @Nullable\n        private String moduleId;\n        @Nullable\n        private WorkSource workSource;\n        @Nullable\n        private ClientIdentity impersonation;\n\n        /**\n         * Constructs a new builder with default values.\n         */\n        public Builder() {\n            this.maxUpdateAgeMillis = 60000L;\n            this.granularity = Granularity.GRANULARITY_PERMISSION_LEVEL;\n            this.priority = Priority.PRIORITY_BALANCED_POWER_ACCURACY;\n            this.durationMillis = Long.MAX_VALUE;\n            this.bypass = false;\n            this.throttleBehavior = ThrottleBehavior.THROTTLE_BACKGROUND;\n            this.moduleId = null;\n            this.workSource = null;\n            this.impersonation = null;\n        }\n\n        /**\n         * Constructs a new builder with values copied from the given {@link CurrentLocationRequest}.\n         */\n        public Builder(CurrentLocationRequest request) {\n            this.maxUpdateAgeMillis = request.getMaxUpdateAgeMillis();\n            this.granularity = request.getGranularity();\n            this.priority = request.getPriority();\n            this.durationMillis = request.getDurationMillis();\n            this.bypass = request.isBypass();\n            this.throttleBehavior = request.getThrottleBehavior();\n            this.moduleId = request.getModuleId();\n            this.workSource = new WorkSource(request.getWorkSource());\n            this.impersonation = request.getImpersonation();\n        }\n\n        /**\n         * Builds a new {@link CurrentLocationRequest}.\n         */\n        @NonNull\n        public CurrentLocationRequest build() {\n            CurrentLocationRequest request = new CurrentLocationRequest();\n            request.maxUpdateAgeMillis = maxUpdateAgeMillis;\n            request.granularity = granularity;\n            request.priority = priority;\n            request.durationMillis = durationMillis;\n            request.bypass = bypass;\n            request.throttleBehavior = throttleBehavior;\n            request.moduleId = moduleId;\n            request.workSource = new WorkSource(workSource);\n            request.impersonation = impersonation;\n            return request;\n        }\n\n        /**\n         * Sets the duration in milliseconds of the location request used to derive the current location if no historical location satisfies the current\n         * location request. If this duration expires with no location, the current location request will return a null location. The current location request\n         * may fail and return a null location after a shorter duration, but never a longer duration.\n         * <p>\n         * NOTE: Internally, this duration may be capped with what the Fused Location Provider believes is a reasonable maximum duration until it is unlikely\n         * that any current location can be derived. This value is usually around roughly 30 seconds.\n         * <p>\n         * The default value is {@link Long#MAX_VALUE}.\n         */\n        public CurrentLocationRequest.Builder setDurationMillis(long durationMillis) {\n            if (durationMillis <= 0) throw new IllegalArgumentException(\"durationMillis must be greater than 0\");\n            this.durationMillis = durationMillis;\n            return this;\n        }\n\n        /**\n         * Sets the {@link Granularity} of locations returned for this request. This controls whether fine or coarse locations may be returned.\n         * <p>\n         * The default value is {@link Granularity#GRANULARITY_PERMISSION_LEVEL}.\n         */\n        public CurrentLocationRequest.Builder setGranularity(@Granularity int granularity) {\n            GranularityUtil.checkValidGranularity(granularity);\n            this.granularity = granularity;\n            return this;\n        }\n\n        /**\n         * Sets the maximum age of any location returned for this request. A value of 0 indicates that only freshly derived locations will be returned, and no\n         * historical locations will ever be returned. A value {@link Long#MAX_VALUE} represents an effectively unbounded maximum age.\n         * <p>\n         * NOTE: This parameter applies only to historical locations. Freshly derived locations should almost always have timestamps close to the present time -\n         * however it is possible under unlikely conditions for location derivation to take longer than expected, in which case freshly derived locations may\n         * have slightly older timestamps.\n         * <p>\n         * The default value is 1 minute. Do not rely on the default value always being 1 minute as this may change without notice.\n         */\n        public CurrentLocationRequest.Builder setMaxUpdateAgeMillis(long maxUpdateAgeMillis) {\n            if (maxUpdateAgeMillis < 0) throw new IllegalArgumentException(\"maxUpdateAgeMillis must be greater than or equal to 0\");\n            this.maxUpdateAgeMillis = maxUpdateAgeMillis;\n            return this;\n        }\n\n        /**\n         * Sets the {@link Priority} of the location request used to derive the current location if no historical location satisfies the current location\n         * request.\n         * <p>\n         * The default value is {@link Priority#PRIORITY_BALANCED_POWER_ACCURACY}.\n         */\n        public CurrentLocationRequest.Builder setPriority(@Priority int priority) {\n            PriorityUtil.checkValidPriority(priority);\n            this.priority = priority;\n            return this;\n        }\n\n        @Hide\n        public CurrentLocationRequest.Builder setBypass(boolean bypass) {\n            this.bypass = bypass;\n            return this;\n        }\n\n        @Hide\n        public CurrentLocationRequest.Builder setThrottleBehavior(int throttleBehavior) {\n            this.throttleBehavior = throttleBehavior;\n            return this;\n        }\n\n        @Hide\n        public CurrentLocationRequest.Builder setModuleId(@Nullable String moduleId) {\n            this.moduleId = moduleId;\n            return this;\n        }\n\n        @Hide\n        public CurrentLocationRequest.Builder setWorkSource(@Nullable WorkSource workSource) {\n            this.workSource = workSource;\n            return this;\n        }\n\n        @Hide\n        public CurrentLocationRequest.Builder setImpersonation(@Nullable ClientIdentity impersonation) {\n            this.impersonation = impersonation;\n            return this;\n        }\n    }\n\n    @Hide\n    public boolean isBypass() {\n        return bypass;\n    }\n\n    @Hide\n    public @ThrottleBehavior int getThrottleBehavior() {\n        return throttleBehavior;\n    }\n\n    @Hide\n    public String getModuleId() {\n        return moduleId;\n    }\n\n    @Hide\n    public WorkSource getWorkSource() {\n        return workSource;\n    }\n\n    @Hide\n    public ClientIdentity getImpersonation() {\n        return impersonation;\n    }\n\n    public static final Creator<CurrentLocationRequest> CREATOR = new AutoCreator<>(CurrentLocationRequest.class);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/DetectedActivity.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2017 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.location;\n\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\n/**\n * The detected activity of the device with an associated confidence. See {@link ActivityRecognitionApi}\n * for details on how to obtain a {@link DetectedActivity}.\n */\n@PublicApi\npublic class DetectedActivity extends AutoSafeParcelable {\n\n    /**\n     * The device is in a vehicle, such as a car.\n     */\n    public static final int IN_VEHICLE = 0;\n\n    /**\n     * The device is on a bicycle.\n     */\n    public static final int ON_BICYCLE = 1;\n\n    /**\n     * The device is on a user who is walking or running.\n     */\n    public static final int ON_FOOT = 2;\n\n    /**\n     * The device is on a user who is running. This is a sub-activity of ON_FOOT.\n     */\n    public static final int RUNNING = 8;\n\n    /**\n     * The device is still (not moving).\n     */\n    public static final int STILL = 3;\n\n    /**\n     * The device angle relative to gravity changed significantly. This often occurs when a device\n     * is picked up from a desk or a user who is sitting stands up.\n     */\n    public static final int TILTING = 5;\n\n    /**\n     * Unable to detect the current activity.\n     */\n    public static final int UNKNOWN = 4;\n\n    /**\n     * The device is on a user who is walking. This is a sub-activity of ON_FOOT.\n     */\n    public static final int WALKING = 7;\n\n    @Field(1000)\n    private int versionCode = 1;\n\n    @Field(1)\n    private int type;\n\n    @Field(2)\n    private int confidence;\n\n    private DetectedActivity() {\n    }\n\n\n    /**\n     * Constructs a DetectedActivity.\n     *\n     * @param activityType the activity that was detected.\n     * @param confidence   value from 0 to 100 indicating how likely it is that the user is performing this activity.\n     */\n    public DetectedActivity(int activityType, int confidence) {\n        this.type = activityType;\n        this.confidence = confidence;\n    }\n\n    /**\n     * Returns a value from 0 to 100 indicating the likelihood that the user is performing this\n     * activity.\n     * <p>\n     * The larger the value, the more consistent the data used to perform the classification is\n     * with the detected activity.\n     * <p>\n     * This value will be <= 100. It means that larger values indicate that it's likely that the\n     * detected activity is correct, while a value of <= 50 indicates that there may be another\n     * activity that is just as or more likely.\n     * <p>\n     * Multiple activities may have high confidence values. For example, the ON_FOOT may have a\n     * confidence of 100 while the RUNNING activity may have a confidence of 95. The sum of the\n     * confidences of all detected activities for a classification does not have to be <= 100 since\n     * some activities are not mutually exclusive (for example, you can be walking while in a bus)\n     * and some activities are hierarchical (ON_FOOT is a generalization of WALKING and RUNNING).\n     */\n    public int getConfidence() {\n        return confidence;\n    }\n\n    /**\n     * Returns the type of activity that was detected.\n     */\n    public int getType() {\n        return type;\n    }\n\n    @Override\n    public String toString() {\n        return \"DetectedActivity [type=\" + typeToString(getType()) + \", confidence=\" + getConfidence() + \"]\";\n    }\n\n    @Hide\n    public static String typeToString(int type) {\n        switch (type) {\n            case 0:\n                return \"IN_VEHICLE\";\n            case 1:\n                return \"ON_BICYCLE\";\n            case 2:\n                return \"ON_FOOT\";\n            case 3:\n                return \"STILL\";\n            case 4:\n                return \"UNKNOWN\";\n            case 5:\n                return \"TILTING\";\n            case 6:\n            default:\n                return Integer.toString(type);\n            case 7:\n                return \"WALKING\";\n            case 8:\n                return \"RUNNING\";\n        }\n    }\n\n    public static final Creator<DetectedActivity> CREATOR = new AutoCreator<DetectedActivity>(DetectedActivity.class);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/DeviceOrientation.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.location;\n\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.utils.ToStringHelper;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\nimport java.util.Arrays;\n\n@Hide\npublic class DeviceOrientation extends AutoSafeParcelable {\n    @Field(1)\n    private float[] attitude = new float[4];\n    @Field(2)\n    private int attitudeConfidence = -1;\n    @Field(3)\n    private int magConfidence = -1;\n    @Field(4)\n    private float headingDegrees = Float.NaN;\n    @Field(5)\n    private float headingErrorDegrees = Float.NaN;\n    @Field(6)\n    public long elapsedRealtimeNanos = 0;\n    @Field(7)\n    private byte fieldsMask = 0;\n    @Field(8)\n    private float conservativeHeadingErrorVonMisesKappa = Float.NaN;\n\n    public float[] getAttitude() {\n        if (hasAttitude()) return attitude;\n        return new float[4];\n    }\n\n    public void setAttitude(float[] attitude) {\n        if (attitude.length != 4) throw new IllegalArgumentException();\n        this.attitude = attitude;\n        fieldsMask = (byte) (fieldsMask | 0x10);\n    }\n\n    public int getAttitudeConfidence() {\n        if (hasAttitudeConfidence()) return attitudeConfidence;\n        return -1;\n    }\n\n    public void setAttitudeConfidence(int attitudeConfidence) {\n        this.attitudeConfidence = attitudeConfidence;\n        fieldsMask = (byte) (fieldsMask | 0x1);\n    }\n\n    public int getMagConfidence() {\n        if (hasMagConfidence()) return magConfidence;\n        return -1;\n    }\n\n    public void setMagConfidence(int magConfidence) {\n        this.magConfidence = magConfidence;\n        fieldsMask = (byte) (fieldsMask | 0x2);\n    }\n\n    public float getHeadingDegrees() {\n        if (hasHeadingDegrees()) return headingDegrees;\n        return Float.NaN;\n    }\n\n    public void setHeadingDegrees(float headingDegrees) {\n        headingDegrees = headingDegrees % 360f + 0f;\n        if (headingDegrees < 0) {\n            headingDegrees += 360f;\n        }\n        this.headingDegrees = headingDegrees;\n        fieldsMask = (byte) (fieldsMask | 0x4);\n    }\n\n    public float getHeadingErrorDegrees() {\n        if (hasHeadingErrorDegrees()) return headingErrorDegrees;\n        return Float.NaN;\n    }\n\n    public void setHeadingErrorDegrees(float headingErrorDegrees) {\n        this.headingErrorDegrees = headingErrorDegrees;\n        fieldsMask = (byte) (fieldsMask | 0x8);\n    }\n\n    public float getConservativeHeadingErrorVonMisesKappa() {\n        if (hasConservativeHeadingErrorVonMisesKappa()) return conservativeHeadingErrorVonMisesKappa;\n        return Float.NaN;\n    }\n\n    public void setConservativeHeadingErrorVonMisesKappa(float conservativeHeadingErrorVonMisesKappa) {\n        this.conservativeHeadingErrorVonMisesKappa = conservativeHeadingErrorVonMisesKappa;\n        fieldsMask = (byte) (fieldsMask | 0x20);\n    }\n\n    public final boolean hasAttitude() {\n        return (fieldsMask & 0x10) != 0;\n    }\n\n    public final boolean hasAttitudeConfidence() {\n        return (fieldsMask & 0x1) != 0;\n    }\n\n    public final boolean hasConservativeHeadingErrorVonMisesKappa() {\n        return (fieldsMask & 0x20) != 0;\n    }\n\n    public final boolean hasHeadingDegrees() {\n        return (fieldsMask & 0x4) != 0;\n    }\n\n    public final boolean hasHeadingErrorDegrees() {\n        return (fieldsMask & 0x8) != 0;\n    }\n\n    public final boolean hasMagConfidence() {\n        return (fieldsMask & 0x2) != 0;\n    }\n\n    @Override\n    public String toString() {\n        ToStringHelper helper = ToStringHelper.name(\"DeviceOrientation\");\n        if (hasAttitude()) helper.field(\"attitude\", Arrays.toString(attitude));\n        if (hasAttitudeConfidence()) helper.field(\"attitudeConfidence\", attitudeConfidence);\n        if (hasMagConfidence()) helper.field(\"magConfidence\", magConfidence);\n        if (hasHeadingDegrees()) helper.field(\"headingDegrees\", headingDegrees);\n        if (hasHeadingErrorDegrees()) helper.field(\"headingErrorDegrees\", headingErrorDegrees);\n        if (hasConservativeHeadingErrorVonMisesKappa()) helper.field(\"conservativeHeadingErrorVonMisesKappa\", conservativeHeadingErrorVonMisesKappa);\n        helper.field(\"elapsedRealtimeNanos\", elapsedRealtimeNanos);\n        return helper.end();\n    }\n\n    public static final Creator<DeviceOrientation> CREATOR = new AutoCreator<DeviceOrientation>(DeviceOrientation.class);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/DeviceOrientationRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.location;\n\nimport android.os.SystemClock;\n\nimport org.microg.gms.common.Hide;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n@Hide\npublic class DeviceOrientationRequest extends AutoSafeParcelable {\n    @Field(1)\n    public boolean shouldUseMag = true;\n    @Field(2)\n    public long minimumSamplingPeriodUs = 50000;\n    @Field(3)\n    public float smallestAngleChangeRadians = 0.0f;\n    @Field(4)\n    public long expirationTime = Long.MAX_VALUE;\n    @Field(5)\n    public int numUpdates = Integer.MAX_VALUE;\n    @Field(6)\n    public boolean enableVelocity = false;\n\n    @Override\n    public String toString() {\n        StringBuilder sb = new StringBuilder();\n        sb.append(\"Request[shouldUseMag=\").append(shouldUseMag);\n        sb.append(\" minimumSamplingPeriod=\").append(minimumSamplingPeriodUs).append(\"us\");\n        sb.append(\" smallesAngleChange=\").append(smallestAngleChangeRadians).append(\"rad\");\n        if (expirationTime != Long.MAX_VALUE)\n            sb.append(\" expireIn=\").append(expirationTime - SystemClock.elapsedRealtime()).append(\"ms\");\n        if (numUpdates != Integer.MAX_VALUE)\n            sb.append(\" num=\").append(numUpdates);\n        if (enableVelocity)\n            sb.append(\" withVelocity\");\n        sb.append(\"]\");\n        return sb.toString();\n    }\n\n    public static final Creator<DeviceOrientationRequest> CREATOR = new AutoCreator<DeviceOrientationRequest>(DeviceOrientationRequest.class);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/FusedLocationProviderApi.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2015 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.location;\n\nimport android.app.PendingIntent;\nimport android.content.Intent;\nimport android.location.Location;\nimport android.location.LocationManager;\nimport android.os.Bundle;\nimport android.os.Looper;\n\nimport android.provider.Settings;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresPermission;\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.PendingResult;\nimport com.google.android.gms.common.api.Status;\n\nimport static android.Manifest.permission.ACCESS_COARSE_LOCATION;\nimport static android.Manifest.permission.ACCESS_FINE_LOCATION;\n\n/**\n * The main entry point for interacting with the fused location provider.\n * <p>\n * The methods must be used in conjunction with a {@link GoogleApiClient}.\n *\n * @deprecated Use the GoogleApi-based API {@link FusedLocationProviderClient} instead.\n */\n@Deprecated\npublic interface FusedLocationProviderApi {\n    /**\n     * Key used for a Bundle extra holding a {@link Location} value when a location change is broadcast using a PendingIntent.\n     *\n     * @deprecated Use {@link LocationResult#hasResult(Intent)} and {@link LocationResult#extractResult(Intent)}.\n     * You may also receive {@link LocationAvailability} in the Intent which you can access using\n     * {@link LocationAvailability#hasLocationAvailability(Intent)} and {@link LocationAvailability#extractLocationAvailability(Intent)}.\n     */\n    @Deprecated\n    @NonNull\n    String KEY_LOCATION_CHANGED = \"com.google.android.location.LOCATION\";\n    /**\n     * Key used for the Bundle extra in {@link Location} object holding a boolean indicating whether the location was\n     * set using {@link #setMockLocation(GoogleApiClient, Location)}. If the value is false this extra is not set.\n     *\n     * @deprecated Prefer to use {@link LocationCompat#isMock()} from the compat libraries.\n     */\n    @NonNull\n    String KEY_MOCK_LOCATION = \"mockLocation\";\n\n    /**\n     * Flushes any locations currently being batched and sends them to all registered {@link LocationListener}s,\n     * {@link LocationCallback}s, and {@link PendingIntent}s. This call is only useful when batching is specified using\n     * {@link LocationRequest#setMaxWaitTime(long)}, otherwise locations are already delivered immediately when available.\n     * <p>\n     * When the returned {@link PendingResult} is complete, then you can assume that any pending batched locations have already been delivered.\n     */\n    @NonNull\n    PendingResult<Status> flushLocations(GoogleApiClient client);\n\n    /**\n     * Returns the best most recent location currently available.\n     * <p>\n     * If a location is not available, which should happen very rarely, null will be returned. The best accuracy\n     * available while respecting the location permissions will be returned.\n     * <p>\n     * This method provides a simplified way to get location. It is particularly well suited for applications that do\n     * not require an accurate location and that do not want to maintain extra logic for location updates.\n     *\n     * @param client An existing GoogleApiClient. If not connected null will be returned.\n     */\n    @Nullable\n    @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})\n    Location getLastLocation(GoogleApiClient client);\n\n    /**\n     * Returns the availability of location data. When {@link LocationAvailability#isLocationAvailable()} returns true,\n     * then the location returned by {@link #getLastLocation(GoogleApiClient)} will be reasonably up to date within the\n     * hints specified by the active LocationRequests.\n     * <p>\n     * If the client isn't connected to Google Play services and the request times out, null is returned.\n     * <p>\n     * Note it's always possible for {@link #getLastLocation(GoogleApiClient)} to return null even when this method\n     * returns true (e.g. location settings were disabled between calls).\n     *\n     * @param client An existing GoogleApiClient. If not connected null will be returned.\n     */\n    @Nullable\n    @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})\n    LocationAvailability getLocationAvailability(GoogleApiClient client);\n\n    /**\n     * Removes all location updates for the given pending intent.\n     * <p>\n     * It is possible for this call to cancel the PendingIntent under some circumstances.\n     *\n     * @param client         An existing GoogleApiClient. It must be connected at the time of this call, which is normally\n     *                       achieved by calling {@link GoogleApiClient#connect()} and waiting for {@link GoogleApiClient.ConnectionCallbacks#onConnected(Bundle)} to be called.\n     * @param callbackIntent The PendingIntent that was used in {@link #requestLocationUpdates(GoogleApiClient, LocationRequest, PendingIntent)}\n     *                       or is equal as defined by {@link PendingIntent#equals(Object)}.\n     * @return a PendingResult for the call, check {@link Status#isSuccess()} to determine if it was successful.\n     */\n    @NonNull\n    PendingResult<Status> removeLocationUpdates(GoogleApiClient client, PendingIntent callbackIntent);\n\n    /**\n     * Removes all location updates for the given location listener.\n     *\n     * @param client   An existing GoogleApiClient. It must be connected at the time of this call, which is normally achieved by calling\n     *                 {@link GoogleApiClient#connect()} and waiting for {@link GoogleApiClient.ConnectionCallbacks#onConnected} to be called.\n     * @param listener The listener to remove.\n     * @return a PendingResult for the call, check {@link Status#isSuccess()} to determine if it was successful.\n     */\n    @NonNull\n    PendingResult<Status> removeLocationUpdates(GoogleApiClient client, LocationListener listener);\n\n    /**\n     * Removes all location updates for the given location result listener.\n     *\n     * @param client   An existing GoogleApiClient. It must be connected at the time of this call, which is normally achieved by calling\n     *                 {@link GoogleApiClient#connect()} and waiting for {@link GoogleApiClient.ConnectionCallbacks#onConnected} to be called.\n     * @param callback The callback to remove.\n     * @return a PendingResult for the call, check {@link Status#isSuccess()} to determine if it was successful.\n     */\n    @NonNull\n    PendingResult<Status> removeLocationUpdates(GoogleApiClient client, LocationCallback callback);\n\n    /**\n     * Requests location updates.\n     * <p>\n     * This method is suited for the foreground use cases, more specifically for requesting locations while being connected to {@link GoogleApiClient}. For\n     * background use cases, the {@link PendingIntent} version of the method is recommended, see\n     * {@link #requestLocationUpdates(GoogleApiClient, LocationRequest, PendingIntent)}.\n     * <p>\n     * Any previous LocationRequests registered on this LocationListener will be replaced.\n     * <p>\n     * Callbacks for LocationListener will be made on the calling thread, which must already be a prepared looper thread, such as the main thread of the\n     * calling Activity. The variant of this method with a {@link Looper} is recommended for cases where the callback needs to happen on a specific thread. See\n     * {@link #requestLocationUpdates(GoogleApiClient, LocationRequest, LocationListener, Looper)}.\n     *\n     * @param client   An existing GoogleApiClient. It must be connected at the time of this call, which is normally achieved by calling\n     *                 {@link GoogleApiClient#connect()} and waiting for {@link GoogleApiClient.ConnectionCallbacks#onConnected} to be called.\n     * @param request  The location request for the updates.\n     * @param listener The listener for the location updates.\n     * @return a PendingResult for the call, check {@link Status#isSuccess()} to determine if it was successful.\n     * @throws IllegalStateException If this method is executed in a thread that has not called Looper.prepare().\n     */\n    @NonNull\n    @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})\n    PendingResult<Status> requestLocationUpdates(GoogleApiClient client, LocationRequest request, LocationListener listener);\n\n    /**\n     * Requests location updates with a callback on the specified Looper thread.\n     * <p>\n     * This method is suited for the foreground use cases,more specifically for requesting locations while being connected to {@link GoogleApiClient}. For\n     * background use cases, the {@link PendingIntent} version of the method is recommended, see\n     * {@link #requestLocationUpdates(GoogleApiClient, LocationRequest, PendingIntent)}.\n     * <p>\n     * Any previous LocationRequests registered on this LocationListener will be replaced.\n     * <p>\n     * Callbacks for {@link LocationCallback} will be made on the specified thread, which must already be a prepared looper thread.\n     *\n     * @param client   An existing GoogleApiClient. It must be connected at the time of this call, which is normally achieved by calling\n     *                 {@link GoogleApiClient#connect()} and waiting for {@link GoogleApiClient.ConnectionCallbacks#onConnected} to be called.\n     * @param request  The location request for the updates.\n     * @param callback The callback for the location updates.\n     * @param looper   The Looper object whose message queue will be used to implement the callback mechanism, or null to make callbacks on the calling thread.\n     * @return a PendingResult for the call, check {@link Status#isSuccess()} to determine if it was successful.\n     * @throws IllegalStateException If looper is null and this method is executed in a thread that has not called Looper.prepare().\n     */\n    @NonNull\n    @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})\n    PendingResult<Status> requestLocationUpdates(GoogleApiClient client, LocationRequest request, LocationCallback callback, Looper looper);\n\n    /**\n     * Requests location updates with a callback on the specified Looper thread.\n     * <p>\n     * This method is suited for the foreground use cases,more specifically for requesting locations while being connected to {@link GoogleApiClient}. For\n     * background use cases, the {@link PendingIntent} version of the method is recommended, see\n     * {@link #requestLocationUpdates(GoogleApiClient, LocationRequest, PendingIntent)}.\n     * <p>\n     * Any previous LocationRequests registered on this LocationListener will be replaced.\n     * <p>\n     * Callbacks for LocationListener will be made on the specified thread, which must already be a prepared looper thread. For cases where the callback can\n     * happen on the calling thread, the variant of this method without a {@link Looper} can be used.\n     *\n     * @param client   An existing GoogleApiClient. It must be connected at the time of this call, which is normally achieved by calling\n     *                 {@link GoogleApiClient#connect()} and waiting for {@link GoogleApiClient.ConnectionCallbacks#onConnected} to be called.\n     * @param request  The location request for the updates.\n     * @param listener The listener for the location updates.\n     * @param looper   The Looper object whose message queue will be used to implement the callback mechanism, or null to make callbacks on the calling thread.\n     * @return a PendingResult for the call, check {@link Status#isSuccess()} to determine if it was successful.\n     * @throws IllegalStateException If looper is null and this method is executed in a thread that has not called Looper.prepare().\n     */\n    @NonNull\n    @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})\n    PendingResult<Status> requestLocationUpdates(GoogleApiClient client, LocationRequest request, LocationListener listener, Looper looper);\n\n    /**\n     * Requests location updates with a callback on the specified PendingIntent.\n     * <p>\n     * This method is suited for the background use cases, more specifically for receiving location updates, even when the app has been killed by the system.\n     * In order to do so, use a {@link PendingIntent} for a started service. For foreground use cases, the {@link LocationListener} version of the method is\n     * recommended, see {@link #requestLocationUpdates(GoogleApiClient, LocationRequest, LocationListener)}.\n     * <p>\n     * Any previously registered requests that have the same PendingIntent (as defined by {@link PendingIntent#equals(Object)}) will be replaced by this\n     * request.\n     * <p>\n     * Both {@link LocationResult} and {@link LocationAvailability} are sent to the given PendingIntent. You can extract data from an Intent using\n     * {@link LocationResult#hasResult(Intent)}, {@link LocationResult#extractResult(Intent)}, {@link LocationAvailability#hasLocationAvailability(Intent)},\n     * and {@link LocationAvailability#extractLocationAvailability(Intent)}.\n     *\n     * @param client         An existing GoogleApiClient. It must be connected at the time of this call, which is normally achieved by calling\n     *                       {@link GoogleApiClient#connect()} and waiting for {@link GoogleApiClient.ConnectionCallbacks#onConnected} to be called.\n     * @param request        The location request for the updates.\n     * @param callbackIntent A pending intent to be sent for each location update.\n     * @return a PendingResult for the call, check {@link Status#isSuccess()} to determine if it was successful.\n     */\n    @NonNull\n    @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})\n    PendingResult<Status> requestLocationUpdates(GoogleApiClient client, LocationRequest request, PendingIntent callbackIntent);\n\n    /**\n     * Sets the mock location to be used for the location provider. This location will be used in place of any actual locations from the underlying providers\n     * (network or gps).\n     * <p>\n     * {@link #setMockMode(GoogleApiClient, boolean)} must be called and set to true prior to calling this method.\n     * <p>\n     * Care should be taken in specifying the timestamps as many applications require them to be monotonically increasing.\n     *\n     * @param client       An existing GoogleApiClient. It must be connected at the time of this call, which is normally achieved by calling\n     *                     {@link GoogleApiClient#connect()} and waiting for {@link GoogleApiClient.ConnectionCallbacks#onConnected} to be called.\n     * @param mockLocation The mock location. Must have a minimum number of fields set to be considered a valid location, as per documentation in the\n     *                     {@link Location} class.\n     * @return a PendingResult for the call, check {@link Status#isSuccess()} to determine if it was successful.\n     * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present or the {@link Settings.Secure#ALLOW_MOCK_LOCATION} system setting is\n     *                           not enabled.\n     */\n    @NonNull\n    PendingResult<Status> setMockLocation(GoogleApiClient client, Location mockLocation);\n\n    /**\n     * Sets whether or not the location provider is in mock mode.\n     * <p>\n     * The underlying providers (network and gps) will be stopped (except by direct {@link LocationManager} access), and only locations specified in\n     * {@link #setMockLocation(GoogleApiClient, Location)} will be reported. This will affect all location clients connected using the\n     * {@link FusedLocationProviderApi}, including geofencer clients (i.e. geofences can be triggered based on mock locations).\n     * <p>\n     * The client must remain connected in order for mock mode to remain active. If the client dies the system will return to its normal state.\n     * <p>\n     * Calls are not nested, and mock mode will be set directly regardless of previous calls.\n     *\n     * @param client     An existing GoogleApiClient. It must be connected at the time of this call, which is normally achieved by calling\n     *                   {@link GoogleApiClient#connect()} and waiting for {@link GoogleApiClient.ConnectionCallbacks#onConnected} to be called.\n     * @param isMockMode If true the location provider will be set to mock mode. If false it will be returned to its normal state.\n     * @return a PendingResult for the call, check {@link Status#isSuccess()} to determine if it was successful.\n     * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present or the {@link Settings.Secure#ALLOW_MOCK_LOCATION} system setting is\n     *                           not enabled.\n     */\n    @NonNull\n    PendingResult<Status> setMockMode(GoogleApiClient client, boolean isMockMode);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/FusedLocationProviderClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.location;\n\nimport android.Manifest;\nimport android.app.PendingIntent;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.location.Location;\nimport android.os.Looper;\n\nimport android.provider.Settings;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresPermission;\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.GoogleApi;\nimport com.google.android.gms.tasks.CancellationToken;\nimport com.google.android.gms.tasks.Task;\n\nimport org.microg.gms.common.PublicApi;\n\nimport java.util.concurrent.Executor;\n\nimport static android.Manifest.permission.ACCESS_COARSE_LOCATION;\nimport static android.Manifest.permission.ACCESS_FINE_LOCATION;\n\n/**\n * The main entry point for interacting with the Fused Location Provider (FLP). In order to obtain an instance of this\n * class, see {@link LocationServices}.\n * <p>\n * In order to use most location APIs, clients are required to hold either the\n * {@link Manifest.permission#ACCESS_COARSE_LOCATION} permission or the {@link Manifest.permission#ACCESS_FINE_LOCATION}.\n * Clients holding only the coarse permission will receive locations that have been obfuscated to hide the device's\n * exact location, and only reveal the approximate area of the device. In addition, clients with only the coarse\n * permission will receive location updates at a throttled rate. Applications which do not require an exact location to\n * work (such as a weather app for instance) are encouraged to use only the coarse permission. From Android 12 onwards,\n * the user may force any app to use coarse location, so apps should test carefully their behavior with only the coarse\n * location permission to ensure everything works as expected.\n * <p>\n * If clients have only the coarse or fine location permission, they will not receive locations while they are in the\n * background. Whether an app is in the background or foreground is normally determined by whether it is currently\n * showing any UI to the user. Apps may also use a foreground location service to maintain their foreground status when\n * they would normally be in the background.\n * <p>\n * If clients also hold the {@link Manifest.permission#ACCESS_BACKGROUND_LOCATION} permission, they may receive\n * locations while in the background even if the above conditions are not met.\n * <p>\n * There are several types of use cases for location. One of the most common is simply obtaining a single location in\n * order to determine where the device is now, and continue from there. The\n * {@link #getCurrentLocation(CurrentLocationRequest, CancellationToken)} API is designed with exactly this use case in\n * mind. On the other hand, if repeated location updates are required, such as when tracking the user's location over\n * time, {@link #requestLocationUpdates(LocationRequest, Executor, LocationListener)} or one of its variants is better\n * suited. Clients are encourage to familiarize themselves with the full range of APIs available in this class to\n * understand which is best suited for their needs.\n */\n@PublicApi\npublic abstract class FusedLocationProviderClient extends GoogleApi<Api.ApiOptions.NoOptions> {\n    @PublicApi(exclude = true)\n    protected FusedLocationProviderClient(Context context) {\n        super(context, LocationServices.API, Api.ApiOptions.NO_OPTIONS);\n    }\n\n    /**\n     * Key used for the Bundle extra in {@link Location} object indicating whether this is a mock location.\n     *\n     * @deprecated Use {@link Location#isMock()} on Android S and above, otherwise use {@link LocationCompat#isMock()}\n     * from the compat libraries instead.\n     */\n    @Deprecated\n    @NonNull\n    public static String KEY_MOCK_LOCATION = \"mockLocation\";\n\n    /**\n     * Key used for the Bundle extra in {@link Location} object holding a float indicating the estimated vertical\n     * accuracy of the location, in meters.\n     *\n     * @deprecated Use {@link Location#getVerticalAccuracyMeters()} on Android O and above, otherwise use\n     * {@link LocationCompat#getVerticalAccuracyMeters()} from the compat libraries instead.\n     */\n    @Deprecated\n    @NonNull\n    public static String KEY_VERTICAL_ACCURACY = \"verticalAccuracy\";\n\n    /**\n     * Flushes any locations currently being batched and sends them to all registered {@link LocationListener}s,\n     * {@link LocationCallback}s, and {@link PendingIntent}s. This call is only useful when batching is specified using\n     * {@link LocationRequest#setMaxWaitTime(long)}, otherwise locations are already delivered immediately when available.\n     * <p>\n     * When the returned {@link Task} is complete, then you can assume that any pending batched locations have already been\n     * delivered.\n     */\n    @NonNull\n    public abstract Task<Void> flushLocations();\n\n    /**\n     * Returns a single location fix representing the best estimate of the current location of the device. This may return a cached location if a recent enough\n     * location fix exists, or may compute a fresh location. If unable to retrieve a current location fix, null will be returned.\n     * <p>\n     * Clients may supply an optional {@link CancellationToken} which may be used to cancel the request.\n     *\n     * @param priority          {@link Priority} used to obtain location\n     * @param cancellationToken optional {@link CancellationToken} to cancel the request\n     */\n    @NonNull\n    @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})\n    public abstract Task<Location> getCurrentLocation(int priority, @Nullable CancellationToken cancellationToken);\n\n    /**\n     * Returns a single location fix representing the best estimate of the current location of the device. This may return a historical location if a recent\n     * enough location fix exists, or may compute a fresh location. If unable to retrieve a current location fix, null will be returned.\n     * <p>\n     * Clients may supply an optional {@link CancellationToken} which may be used to cancel the request.\n     *\n     * @param request           {@link CurrentLocationRequest} with parameters detailing how to obtain the current location\n     * @param cancellationToken optional {@link CancellationToken} to cancel the request\n     */\n    @NonNull\n    @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})\n    public abstract Task<Location> getCurrentLocation(@NonNull CurrentLocationRequest request, @Nullable CancellationToken cancellationToken);\n\n    /**\n     * Returns the most recent historical location currently available according to the given request. Will return null if no matching historical location is\n     * available.\n     */\n    @NonNull\n    @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})\n    public abstract Task<Location> getLastLocation(@NonNull LastLocationRequest request);\n\n    /**\n     * Returns the most recent historical location currently available. Will return null if no historical location is available. The historical location may\n     * be of an arbitrary age, so clients should check how old the location is to see if it suits their purposes.\n     */\n    @NonNull\n    @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})\n    public abstract Task<Location> getLastLocation();\n\n    /**\n     * Returns the estimated availability of location data. If {@link LocationAvailability#isLocationAvailable()} returns true then it is likely (but not\n     * guaranteed) that Fused Location Provider APIs will be able to derive and return fresh location updates. If\n     * {@link LocationAvailability#isLocationAvailable()} returns false, then it is likely (but not guaranteed) that Fused Location Provider APIs will be\n     * unable to derive and return fresh location updates, though there may be historical locations available.\n     */\n    @NonNull\n    @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})\n    public abstract Task<LocationAvailability> getLocationAvailability();\n\n    /**\n     * Removes all location updates for the given listener.\n     */\n    @NonNull\n    public abstract Task<Void> removeLocationUpdates(@NonNull LocationListener listener);\n\n    /**\n     * Removes all location updates for the given callback.\n     */\n    @NonNull\n    public abstract Task<Void> removeLocationUpdates(@NonNull LocationCallback callback);\n\n    /**\n     * Removes all location updates for the given pending intent.\n     */\n    @NonNull\n    public abstract Task<Void> removeLocationUpdates(@NonNull PendingIntent pendingIntent);\n\n    /**\n     * Requests location updates with the given request and results delivered to the given listener on the specified {@link Looper}. A\n     * previous request for location updates for the same listener will be replaced by this request. If the location request has a\n     * priority higher than {@link Priority#PRIORITY_PASSIVE}, a wakelock may be held on the client's behalf while delivering locations.\n     * <p>\n     * Use {@link #removeLocationUpdates(LocationListener)} to stop location updates once no longer needed.\n     * <p>\n     * Depending on the arguments passed in through the {@link LocationRequest}, locations from the past may be delivered when\n     * the listener is first registered. Clients should ensure they are checking location timestamps appropriately if necessary.\n     * <p>\n     * If the given Looper is null, the Looper associated with the calling thread will be used instead.\n     *\n     * @throws IllegalStateException if {@code looper} is null and the calling thread has not called {@link Looper#prepare()}\n     */\n    @NonNull\n    @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})\n    public abstract Task<Void> requestLocationUpdates(@NonNull LocationRequest request, @NonNull LocationListener listener, @Nullable Looper looper);\n\n    /**\n     * Requests location updates with the given request and results delivered to the given callback on the specified {@link Executor}.\n     * A previous request for location updates for the same callback will be replaced by this request. If the location request has\n     * a priority higher than {@link Priority#PRIORITY_PASSIVE}, a wakelock may be held on the client's behalf while delivering\n     * locations. A wakelock will not be held while delivering availability updates.\n     * <p>\n     * Use {@link #removeLocationUpdates(LocationCallback)} to stop location updates once no longer needed.\n     * <p>\n     * Depending on the arguments passed in through the {@link LocationRequest}, locations from the past may be delivered when\n     * the callback is first registered. Clients should ensure they are checking location timestamps appropriately if necessary.\n     */\n    @NonNull\n    @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})\n    public abstract Task<Void> requestLocationUpdates(@NonNull LocationRequest request, @NonNull Executor executor, @NonNull LocationCallback callback);\n\n    /**\n     * Requests location updates with the given request and results delivered to the given listener on the specified {@link Executor}.\n     *\n     * @see #requestLocationUpdates(LocationRequest, LocationListener, Looper)\n     */\n    @NonNull\n    @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})\n    public abstract Task<Void> requestLocationUpdates(@NonNull LocationRequest request, @NonNull Executor executor, @NonNull LocationListener listener);\n\n    /**\n     * Requests location updates with the given request and results delivered to the given callback on the specified\n     * {@link Looper}. A previous request for location updates for the same callback will be replaced by this request.\n     * If the location request has a priority higher than {@link Priority#PRIORITY_PASSIVE}, a wakelock may be held on\n     * the client's behalf while delivering locations. A wakelock will not be held while delivering availability\n     * updates.\n     * <p>\n     * Use {@link #removeLocationUpdates(LocationCallback)} to stop location updates once no longer needed.\n     * <p>\n     * Depending on the arguments passed in through the {@link LocationRequest}, locations from the past may be\n     * delivered when the callback is first registered. Clients should ensure they are checking location timestamps\n     * appropriately if necessary.\n     * <p>\n     * If the given {@link Looper} is null, the Looper associated with the calling thread will be used instead.\n     *\n     * @throws IllegalStateException if looper is null and the calling thread has not called {@link Looper#prepare()}\n     */\n    @NonNull\n    @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})\n    public abstract Task<Void> requestLocationUpdates(@NonNull LocationRequest request, @NonNull LocationCallback callback, @Nullable Looper looper);\n\n    /**\n     * Requests location updates with the given request and results delivered via the specified {@link PendingIntent}. A previous\n     * request for location updates for the same pending intent will be replaced by this request. If the location request has a\n     * priority higher than {@link Priority#PRIORITY_PASSIVE}, a wakelock may be held on the client's behalf while delivering\n     * locations. A wakelock will not be held while delivering availability updates.\n     * <p>\n     * Location updates should be extracted from the received {@link Intent} via {@link LocationResult#hasResult(Intent)} and\n     * {@link LocationResult#extractResult(Intent)}. Availability updates should be extracted from the {@link Intent} via\n     * {@link LocationAvailability#hasLocationAvailability(Intent)} and\n     * {@link LocationAvailability#extractLocationAvailability(Intent)}.\n     * <p>\n     * This method is suited for receiving location updates in the background, even when the receiving app may have been\n     * killed by the system. Using a {@link PendingIntent} allows the target component to be started and receive location updates.\n     * For foreground use cases prefer to listen for location updates via a listener or callback instead of a pending intent.\n     * <p>\n     * {@link PendingIntent} location requests are automatically removed when the client application is reset (for example, when the\n     * client application is upgraded, restarted, removed, or force-quit), or if the pending intent is canceled.\n     * <p>\n     * Use {@link #removeLocationUpdates(PendingIntent)} to stop location updates once no longer needed.\n     * <p>\n     * Depending on the arguments passed in through the {@link LocationRequest}, locations from the past may be delivered when\n     * the callback is first registered. Clients should ensure they are checking location timestamps appropriately if necessary.\n     */\n    @NonNull\n    @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})\n    public abstract Task<Void> requestLocationUpdates(@NonNull LocationRequest request, @NonNull PendingIntent pendingIntent);\n\n    /**\n     * Sets the mock location of the Fused Location Provider.\n     * <p>\n     * Delivers the given location to the FLP as if it was coming from an underlying location source. Normal FLP logic around receiving and delivering location\n     * will generally apply. For this reason the timestamps of the location should be set appropriately, as the FLP may expect monotonically increasing\n     * timestamps. When this location is reported to FLP clients it will be marked as a mock location (see {@link Location#isMock()} or\n     * {@link LocationCompat#isMock()} from the compat libraries).\n     * <p>\n     * This API can only be successfully used while the FLP is in mock mode. Clients must fulfill the same security requirements as for\n     * {@link #setMockMode(boolean)} as well.\n     *\n     * @param location valid location to set as the next FLP location\n     * @throws SecurityException if security requirements are not met\n     */\n    @NonNull\n    public abstract Task<Void> setMockLocation(@NonNull Location location);\n\n    /**\n     * Sets whether or not the Fused Location Provider is in mock mode.\n     * <p>\n     * Entering mock mode clears the FLP's cached locations, and ensures that the FLP will only report locations set through {@link #setMockLocation(Location)}.\n     * Exiting mock mode will clear any mock locations set from the FLP's cache as well. Mock mode affects all location clients using the FLP, including\n     * location clients in other processes and derivative APIs such as geofencing and so forth. Because this affects all FLP usage, clients should always\n     * ensure they properly set the mock mode to false when finished.\n     * <p>\n     * Successfully using this API on devices running Android M+ requires the client to request the {@code android.permission.ACCESS_MOCK_LOCATION} permission\n     * and to be selected as the mock location app within the device developer settings. Using this API on pre-M devices requires the\n     * {@link Settings.Secure#ALLOW_MOCK_LOCATION} setting to be enabled.\n     *\n     * @param mockMode the mock mode state to set for the Fused Location Provider APIs\n     * @throws SecurityException if security requirements are not met\n     */\n    @NonNull\n    public abstract Task<Void> setMockMode(boolean mockMode);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/Geofence.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2017 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.location;\n\nimport android.os.SystemClock;\n\nimport androidx.annotation.FloatRange;\nimport androidx.annotation.IntDef;\nimport androidx.annotation.IntRange;\nimport com.google.android.gms.location.internal.ParcelableGeofence;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Represents a geographical region, also known as a geofence. Geofences can be monitored by\n * geofencer service. And when the user crosses the boundary of a geofence, an alert will be\n * generated.\n */\npublic interface Geofence {\n    int GEOFENCE_TRANSITION_DWELL = 4;\n\n    /**\n     * The transition type indicating that the user enters the geofence(s).\n     */\n    int GEOFENCE_TRANSITION_ENTER = 1;\n\n    /**\n     * The transition type indicating that the user exits the geofence(s).\n     */\n    int GEOFENCE_TRANSITION_EXIT = 2;\n\n    /**\n     * Expiration value that indicates the geofence should never expire.\n     */\n    long NEVER_EXPIRE = -1L;\n\n    /**\n     * Returns the expiration elapsed realtime of geofence in milliseconds, or {@link #NEVER_EXPIRE} if there's no expiration. When positive, this geofence will\n     * be removed automatically after that time.\n     */\n    long getExpirationTime();\n\n    /**\n     * Returns latitude in degrees, between -90 and +90 inclusive.\n     */\n    double getLatitude();\n\n    /**\n     * Returns the delay between {@link #GEOFENCE_TRANSITION_ENTER} and {@link #GEOFENCE_TRANSITION_DWELL} in milliseconds.\n     */\n    int getLoiteringDelay();\n\n    /**\n     * Returns longitude in degrees, between -180 and +180 inclusive.\n     */\n    double getLongitude();\n\n    /**\n     * Returns the best-effort description of how soon should the callback be called when the transition associated with the geofence is triggered,\n     * in milliseconds.\n     */\n    int getNotificationResponsiveness();\n\n    /**\n     * Returns radius in meters.\n     */\n    float getRadius();\n\n    /**\n     * Returns the request ID of this geofence. The request ID is a string to identify this geofence\n     * inside your application. When two geofences with the same requestId are monitored, the new\n     * one will replace the old one regardless the geographical region these two geofences\n     * represent.\n     */\n    String getRequestId();\n\n    /**\n     * Returns the transition types of interest as a bitwise-OR of {@code GEOFENCE_TRANSITION_} flags.\n     */\n    @TransitionTypes int getTransitionTypes();\n\n    /**\n     * A builder that builds {@link Geofence}.\n     */\n    class Builder {\n        private int regionType = -1;\n        private double latitude;\n        private double longitude;\n        private float radius;\n        private long expirationTime = Long.MIN_VALUE;\n        private int loiteringDelay = -1;\n        private int notificationResponsiveness;\n        private String requestId;\n        private @TransitionTypes int transitionTypes;\n\n        /**\n         * Creates a geofence object.\n         *\n         * @throws IllegalArgumentException if any parameters are not set or out of range\n         */\n        public Geofence build() throws IllegalArgumentException {\n            if (requestId == null) {\n                throw new IllegalArgumentException(\"Request ID not set.\");\n            } else if (transitionTypes == 0) {\n                throw new IllegalArgumentException(\"Transition types not set.\");\n            } else if ((transitionTypes & GEOFENCE_TRANSITION_DWELL) > 0 && loiteringDelay < 0) {\n                throw new IllegalArgumentException(\"Non-negative loitering delay needs to be set when transition types include GEOFENCE_TRANSITION_DWELLING.\");\n            } else if (expirationTime == Long.MIN_VALUE) {\n                throw new IllegalArgumentException(\"Expiration not set.\");\n            } else if (regionType == -1) {\n                throw new IllegalArgumentException(\"Geofence region not set.\");\n            } else if (notificationResponsiveness < 0) {\n                throw new IllegalArgumentException(\"Notification responsiveness should be nonnegative.\");\n            } else {\n                return new ParcelableGeofence(requestId, expirationTime, regionType, latitude, longitude, radius, transitionTypes, notificationResponsiveness, loiteringDelay);\n            }\n        }\n\n        /**\n         * Sets the region of this geofence. The geofence represents a circular area on a flat, horizontal plane.\n         *\n         * @param latitude  latitude in degrees, between -90 and +90 inclusive\n         * @param longitude longitude in degrees, between -180 and +180 inclusive\n         * @param radius    radius in meters\n         */\n        public Builder setCircularRegion(@FloatRange(from = -90.0d, to = 90.0d) double latitude, @FloatRange(from = -180.0d, to = 180.0d) double longitude, @FloatRange(from = 0.0d, fromInclusive = false) float radius) {\n            this.regionType = 1;\n            this.latitude = latitude;\n            this.longitude = longitude;\n            this.radius = radius;\n            return this;\n        }\n\n        /**\n         * Sets the expiration duration of geofence. This geofence will be removed automatically\n         * after this period of time.\n         *\n         * @param durationMillis time for this proximity alert, in milliseconds, or {@link #NEVER_EXPIRE}\n         *                       to indicate no expiration. When positive, this geofence will be\n         *                       removed automatically after this amount of time.\n         */\n        public Builder setExpirationDuration(long durationMillis) {\n            if (durationMillis < 0) {\n                expirationTime = -1;\n            } else {\n                expirationTime = SystemClock.elapsedRealtime() + durationMillis;\n            }\n            return this;\n        }\n\n        public Builder setLoiteringDelay(int loiteringDelayMs) {\n            this.loiteringDelay = loiteringDelayMs;\n            return this;\n        }\n\n        /**\n         * Sets the best-effort notification responsiveness of the geofence. Defaults to 0. Setting\n         * a big responsiveness value, for example 5 minutes, can save power significantly. However,\n         * setting a very small responsiveness value, for example 5 seconds, doesn't necessarily\n         * mean you will get notified right after the user enters or exits a geofence: internally,\n         * the geofence might adjust the responsiveness value to save power when needed.\n         *\n         * @param notificationResponsivenessMs notificationResponsivenessMs\t(milliseconds) defines\n         *                                     the best-effort description of how soon should the\n         *                                     callback be called when the transition associated\n         *                                     with the Geofence is triggered. For instance, if set\n         *                                     to 300000 milliseconds the callback will be called 5\n         *                                     minutes within entering or exiting the geofence.\n         */\n        public Builder setNotificationResponsiveness(@IntRange(from = 0) int notificationResponsivenessMs) {\n            this.notificationResponsiveness = notificationResponsivenessMs;\n            return this;\n        }\n\n        /**\n         * Sets the request ID of the geofence. Request ID is a string to identify this geofence\n         * inside your application. When two geofences with the same requestId are monitored, the\n         * new one will replace the old one regardless the geographical region these two geofences\n         * represent.\n         *\n         * @param requestId the request ID. The length of the string can be up to 100 characters.\n         */\n        public Builder setRequestId(String requestId) {\n            this.requestId = requestId;\n            return this;\n        }\n\n        /**\n         * Sets the transition types of interest. Alerts are only generated for the given transition\n         * types.\n         *\n         * @param transitionTypes geofence transition types of interest, as a bitwise-OR of\n         *                        GEOFENCE_TRANSITION_ flags.\n         */\n        public Builder setTransitionTypes(@TransitionTypes int transitionTypes) {\n            this.transitionTypes = transitionTypes;\n            return this;\n        }\n    }\n\n    /**\n     * Geofence transition event.\n     */\n    @Target({ElementType.TYPE_USE})\n    @Retention(RetentionPolicy.SOURCE)\n    @IntDef({GEOFENCE_TRANSITION_ENTER, GEOFENCE_TRANSITION_EXIT, GEOFENCE_TRANSITION_DWELL})\n    @interface GeofenceTransition {\n\n    }\n\n    /**\n     * Geofence transition types of interest, as either 0 or a bitwise-OR of {@code GEOFENCE_TRANSITION_} flags.\n     */\n    @Target({ElementType.TYPE_USE})\n    @Retention(RetentionPolicy.SOURCE)\n    @IntDef(value = {GEOFENCE_TRANSITION_ENTER, GEOFENCE_TRANSITION_EXIT, GEOFENCE_TRANSITION_DWELL}, flag = true)\n    @interface TransitionTypes {\n\n    }\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/GeofenceStatusCodes.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2017 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.location;\n\nimport android.app.PendingIntent;\nimport com.google.android.gms.common.api.CommonStatusCodes;\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.Status;\n\n/**\n * Geofence specific status codes, for use in {@link Status#getStatusCode()}\n */\npublic class GeofenceStatusCodes extends CommonStatusCodes {\n    /**\n     * Geofence service is not available now. Typically this is because the user turned off location access in settings > location access.\n     */\n    public static final int GEOFENCE_NOT_AVAILABLE = 1000;\n\n    /**\n     * Your app has registered more than 100 geofences. Remove unused ones before adding new geofences.\n     */\n    public static final int GEOFENCE_TOO_MANY_GEOFENCES = 1001;\n\n    /**\n     * You have provided more than 5 different PendingIntents to the {@link GeofencingApi#addGeofences(GoogleApiClient, GeofencingRequest, PendingIntent)} call.\n     */\n    public static final int GEOFENCE_TOO_MANY_PENDING_INTENTS = 1002;\n\n    /**\n     * The client doesn't have sufficient location permission to perform geofencing operations.\n     */\n    public static final int GEOFENCE_INSUFFICIENT_LOCATION_PERMISSION = 1004;\n\n    /**\n     * Your app has been adding Geofences too frequently.\n     */\n    public static final int GEOFENCE_REQUEST_TOO_FREQUENT = 1005;\n\n    /**\n     * Returns an untranslated debug (not user-friendly!) string based on the current status code.\n     */\n    public static String getStatusCodeString(int statusCode) {\n        switch (statusCode) {\n            case GEOFENCE_NOT_AVAILABLE:\n                return \"GEOFENCE_NOT_AVAILABLE\";\n            case GEOFENCE_TOO_MANY_GEOFENCES:\n                return \"GEOFENCE_TOO_MANY_GEOFENCES\";\n            case GEOFENCE_TOO_MANY_PENDING_INTENTS:\n                return \"GEOFENCE_TOO_MANY_PENDING_INTENTS\";\n            case GEOFENCE_INSUFFICIENT_LOCATION_PERMISSION:\n                return \"GEOFENCE_INSUFFICIENT_LOCATION_PERMISSION\";\n            case GEOFENCE_REQUEST_TOO_FREQUENT:\n                return \"GEOFENCE_REQUEST_TOO_FREQUENT\";\n            default:\n                return CommonStatusCodes.getStatusCodeString(statusCode);\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/GeofencingApi.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.location;\n\nimport android.app.PendingIntent;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.RequiresPermission;\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.PendingResult;\nimport com.google.android.gms.common.api.Status;\n\nimport java.util.List;\n\nimport static android.Manifest.permission.ACCESS_FINE_LOCATION;\n\n/**\n * The main entry point for interacting with the geofencing APIs.\n * <p>\n * The methods must be used in conjunction with a GoogleApiClient. E.g.\n * <pre>\n *  new GoogleApiClient.Builder(context)\n *          .addApi(LocationServices.API)\n *          .addConnectionCallbacks(this)\n *          .addOnConnectionFailedListener(this)\n *          .build()\n * </pre>\n */\n@Deprecated\npublic interface GeofencingApi {\n    @NonNull\n    @RequiresPermission(ACCESS_FINE_LOCATION)\n    PendingResult<Status> addGeofences(GoogleApiClient client, GeofencingRequest geofencingRequest, PendingIntent pendingIntent);\n\n    @Deprecated\n    @NonNull\n    @RequiresPermission(ACCESS_FINE_LOCATION)\n    PendingResult<Status> addGeofences(GoogleApiClient client, List<Geofence> geofences, PendingIntent pendingIntent);\n\n    @NonNull\n    PendingResult<Status> removeGeofences(GoogleApiClient client, List<String> geofenceRequestIds);\n\n    @NonNull\n    PendingResult<Status> removeGeofences(GoogleApiClient client, PendingIntent pendingIntent);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/GeofencingClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.location;\n\nimport android.app.Activity;\n\nimport android.app.PendingIntent;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.RequiresPermission;\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.HasApiKey;\nimport com.google.android.gms.tasks.Task;\n\nimport java.util.List;\n\nimport static android.Manifest.permission.ACCESS_FINE_LOCATION;\n\n/**\n * The main entry point for interacting with the geofencing APIs.\n * <p>\n * Get an instance of this client via {@link LocationServices#getGeofencingClient(Activity)}.\n * <p>\n * All methods are thread safe.\n */\npublic interface GeofencingClient extends HasApiKey<Api.ApiOptions.NoOptions> {\n    @NonNull\n    @RequiresPermission(ACCESS_FINE_LOCATION)\n    Task<Void> addGeofences(GeofencingRequest geofencingRequest, PendingIntent pendingIntent);\n\n    @NonNull\n    Task<Void> removeGeofences(List<String> geofenceRequestIds);\n\n    @NonNull\n    Task<Void> removeGeofences(PendingIntent pendingIntent);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/GeofencingEvent.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2017 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.location;\n\nimport android.annotation.SuppressLint;\nimport android.content.Intent;\nimport android.location.Location;\n\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableSerializer;\nimport com.google.android.gms.location.internal.ParcelableGeofence;\n\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.common.PublicApi;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Represents an event from the GeofencingApi API. The event can be\n * <p>\n * A geofence triggering event generated when a geofence transition happens.\n * An error happens after geofences are registered and being monitored.\n */\n@PublicApi\npublic class GeofencingEvent {\n    @Hide\n    public static final String EXTRA_ERROR_CODE = \"gms_error_code\";\n    @Hide\n    public static final String EXTRA_TRIGGERING_LOCATION = \"com.google.android.location.intent.extra.triggering_location\";\n    @Hide\n    public static final String EXTRA_TRANSITION = \"com.google.android.location.intent.extra.transition\";\n    @Hide\n    public static final String EXTRA_GEOFENCE_LIST = \"com.google.android.location.intent.extra.geofence_list\";\n\n    private int errorCode;\n    private @Geofence.GeofenceTransition int geofenceTransition;\n    private List<Geofence> triggeringGeofences;\n    private Location triggeringLocation;\n\n    /**\n     * Creates a {@link GeofencingEvent} object from the given intent.\n     *\n     * @param intent the intent to extract the geofencing event data from\n     * @return a {@link GeofencingEvent} object or {@code null} if the given intent is {@code null}\n     */\n\n    public static GeofencingEvent fromIntent(Intent intent) {\n        if (intent == null) {\n            return null;\n        }\n        GeofencingEvent event = new GeofencingEvent();\n        event.errorCode = intent.getIntExtra(EXTRA_ERROR_CODE, -1);\n        event.geofenceTransition = validate(intent.getIntExtra(EXTRA_TRANSITION, -1));\n        ArrayList<byte[]> parceledGeofences = (ArrayList<byte[]>) intent.getSerializableExtra(EXTRA_GEOFENCE_LIST);\n        if (parceledGeofences != null) {\n            event.triggeringGeofences = new ArrayList<Geofence>();\n            for (byte[] parceledGeofence : parceledGeofences) {\n                event.triggeringGeofences.add(SafeParcelableSerializer.deserializeFromBytes(parceledGeofence, ParcelableGeofence.CREATOR));\n            }\n        }\n        event.triggeringLocation = intent.getParcelableExtra(EXTRA_TRIGGERING_LOCATION);\n        return event;\n    }\n\n    @SuppressLint(\"WrongConstant\")\n    private static @Geofence.GeofenceTransition int validate(@Geofence.GeofenceTransition int geofenceTransition) {\n        if (geofenceTransition != Geofence.GEOFENCE_TRANSITION_ENTER && geofenceTransition != Geofence.GEOFENCE_TRANSITION_EXIT && geofenceTransition != Geofence.GEOFENCE_TRANSITION_DWELL) {\n            return -1;\n        }\n        return geofenceTransition;\n    }\n\n    /**\n     * Returns the error code that explains the error that triggered the intent specified in\n     * {@link #fromIntent(Intent)}.\n     *\n     * @return the error code specified in {@link GeofenceStatusCodes} or {@code -1} if\n     * {@link #hasError()} returns false.\n     */\n    public int getErrorCode() {\n        return errorCode;\n    }\n\n    /**\n     * Returns the transition type of the geofence transition alert.\n     *\n     * @return -1 if the intent specified in {@link #fromIntent(Intent)} is not generated for a\n     * transition alert; Otherwise returns the GEOFENCE_TRANSITION_ flags value defined in\n     * {@link Geofence}.\n     */\n    public @Geofence.GeofenceTransition int getGeofenceTransition() {\n        return geofenceTransition;\n    }\n\n\n    /**\n     * Returns a list of geofences that triggered this geofence transition alert.\n     *\n     * @return a list of geofences that triggered this geofence transition alert or {@code null} if\n     * the intent specified in {@link #fromIntent(Intent)} is not generated for a geofence\n     * transition alert\n     */\n    public List<Geofence> getTriggeringGeofences() {\n        return triggeringGeofences;\n    }\n\n    /**\n     * Gets the location that triggered the geofence transition. Triggering location is only\n     * available if the calling app links against Google Play services 5.0 SDK.\n     *\n     * @return the location that triggered this geofence alert or {@code null} if it's not included\n     * in the intent specified in {@link #fromIntent(Intent)}\n     */\n    public Location getTriggeringLocation() {\n        return triggeringLocation;\n    }\n\n    /**\n     * Whether an error triggered this intent.\n     *\n     * @return {@code true} if an error triggered the intent specified in\n     * {@link #fromIntent(Intent)}, otherwise {@code false}\n     */\n    public boolean hasError() {\n        return errorCode != -1;\n    }\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/GeofencingRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2017 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.location;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.location.internal.ParcelableGeofence;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Specifies the list of geofences to be monitored and how the geofence notifications should be reported.\n * <p>\n * Refer to {@link GeofencingClient#addGeofences(GeofencingRequest, android.app.PendingIntent)} on how to monitor geofences.\n */\npublic class GeofencingRequest extends AutoSafeParcelable {\n    /**\n     * A flag indicating that geofencing service should trigger {@link Geofence#GEOFENCE_TRANSITION_ENTER} notification at the moment when the geofence is\n     * added and if the device is already inside that geofence.\n     */\n    public static final int INITIAL_TRIGGER_ENTER = 1;\n    /**\n     * A flag indicating that geofencing service should trigger {@link Geofence#GEOFENCE_TRANSITION_EXIT} notification at the moment when the geofence is\n     * added and if the device is already outside that geofence.\n     */\n    public static final int INITIAL_TRIGGER_EXIT = 2;\n    /**\n     * A flag indicating that geofencing service should trigger {@link Geofence#GEOFENCE_TRANSITION_DWELL} notification at the moment when the geofence is\n     * added and if the device is already inside that geofence for some time.\n     */\n    public static final int INITIAL_TRIGGER_DWELL = 4;\n\n    @Field(value = 1, subClass = ParcelableGeofence.class)\n    private List<Geofence> geofences;\n    @Field(2)\n    private @InitialTrigger int initialTrigger;\n    @Field(3)\n    private String tag = \"\";\n    @Field(4)\n    @Nullable\n    private String contextAttributionTag;\n\n    /**\n     * Gets the list of geofences to be monitored.\n     *\n     * @return the list of geofences to be monitored\n     */\n    public List<Geofence> getGeofences() {\n        return geofences;\n    }\n\n    /**\n     * Gets the triggering behavior at the moment when the geofences are added.\n     *\n     * @return the triggering behavior at the moment when the geofences are added. It's a bit-wise of {@link #INITIAL_TRIGGER_ENTER},\n     * {@link #INITIAL_TRIGGER_EXIT}, and {@link #INITIAL_TRIGGER_DWELL}.\n     */\n    public @InitialTrigger int getInitialTrigger() {\n        return initialTrigger;\n    }\n\n\n    /**\n     * The triggering behavior at the moment when the geofences are added. It's either 0, or a bit-wise OR of {@link GeofencingRequest#INITIAL_TRIGGER_ENTER},\n     * {@link GeofencingRequest#INITIAL_TRIGGER_EXIT}, and {@link GeofencingRequest#INITIAL_TRIGGER_DWELL}.\n     */\n    @Target({ElementType.TYPE_USE})\n    @Retention(RetentionPolicy.SOURCE)\n    @IntDef(value = {INITIAL_TRIGGER_ENTER, INITIAL_TRIGGER_EXIT, INITIAL_TRIGGER_DWELL}, flag = true)\n    @interface InitialTrigger {\n\n    }\n\n    /**\n     * A builder that builds {@link GeofencingRequest}.\n     */\n    public static class Builder {\n        private List<Geofence> geofences = new ArrayList<>();\n        private @InitialTrigger int initialTrigger = INITIAL_TRIGGER_ENTER | INITIAL_TRIGGER_DWELL;\n\n        /**\n         * Adds a geofence to be monitored by geofencing service.\n         *\n         * @param geofence the geofence to be monitored. The geofence must be built with {@link Geofence.Builder}.\n         * @return the builder object itself for method chaining\n         * @throws IllegalArgumentException if the geofence is not built with {@link Geofence.Builder}.\n         * @throws NullPointerException     if the given geofence is null\n         */\n        @NonNull\n        public GeofencingRequest.Builder addGeofence(Geofence geofence) {\n            if (geofence == null) throw new NullPointerException(\"geofence can't be null.\");\n            if (!(geofence instanceof ParcelableGeofence)) throw new IllegalArgumentException(\"Geofence must be created using Geofence.Builder.\");\n            geofences.add(geofence);\n            return this;\n        }\n\n        /**\n         * Adds all the geofences in the given list to be monitored by geofencing service.\n         *\n         * @param geofences the geofences to be monitored. The geofences in the list must be built with {@link Geofence.Builder}.\n         * @return the builder object itself for method chaining\n         * @throws IllegalArgumentException if the geofence is not built with {@link Geofence.Builder}.\n         */\n        @NonNull\n        public GeofencingRequest.Builder addGeofences(List<Geofence> geofences) {\n            if (geofences != null) {\n                for (Geofence geofence : geofences) {\n                    if (geofence != null) addGeofence(geofence);\n                }\n            }\n            return this;\n        }\n\n        /**\n         * Sets the geofence notification behavior at the moment when the geofences are added. The default behavior is\n         * {@link GeofencingRequest#INITIAL_TRIGGER_ENTER} and {@link GeofencingRequest#INITIAL_TRIGGER_DWELL}.\n         *\n         * @param initialTrigger the notification behavior. It's a bit-wise of {@link GeofencingRequest#INITIAL_TRIGGER_ENTER} and/or\n         *                       {@link GeofencingRequest#INITIAL_TRIGGER_EXIT} and/or {@link GeofencingRequest#INITIAL_TRIGGER_DWELL}. When\n         *                       {@code initialTrigger} is set to 0 ({@code setInitialTrigger(0)}), initial trigger would be disabled.\n         * @return the builder object itself for method chaining\n         */\n        public GeofencingRequest.Builder setInitialTrigger(@InitialTrigger int initialTrigger) {\n            this.initialTrigger = initialTrigger;\n            return this;\n        }\n\n        /**\n         * Builds the {@link GeofencingRequest} object.\n         *\n         * @return a {@link GeofencingRequest} object\n         * @throws IllegalArgumentException if no geofence has been added to this list\n         */\n        public GeofencingRequest build() {\n            if (geofences.isEmpty()) throw new IllegalArgumentException(\"No geofence has been added to this request.\");\n            GeofencingRequest request = new GeofencingRequest();\n            request.geofences = geofences;\n            request.initialTrigger = initialTrigger;\n            return request;\n        }\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return \"GeofencingRequest[geofences=\" + this.geofences + \", initialTrigger=\" + this.initialTrigger + \", tag=\" + this.tag + \", attributionTag=\" + this.contextAttributionTag + \"]\";\n    }\n\n    public static final Creator<GeofencingRequest> CREATOR = new AutoCreator<>(GeofencingRequest.class);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/GestureRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.location;\n\nimport org.microg.gms.common.Hide;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n@Hide\npublic class GestureRequest extends AutoSafeParcelable {\n    public static final Creator<GestureRequest> CREATOR = new AutoCreator<GestureRequest>(GestureRequest.class);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/Granularity.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.location;\n\nimport android.Manifest;\nimport androidx.annotation.IntDef;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Location granularity levels to be used with APIs within FusedLocationProviderClient.\n */\n@Target({ElementType.TYPE_USE})\n@Retention(RetentionPolicy.SOURCE)\n@IntDef({Granularity.GRANULARITY_PERMISSION_LEVEL, Granularity.GRANULARITY_COARSE, Granularity.GRANULARITY_FINE})\npublic @interface Granularity {\n    /**\n     * The desired location granularity should correspond to the client permission level. The client will be delivered fine\n     * locations while it has the {@link Manifest.permission#ACCESS_FINE_LOCATION} permission, coarse locations while it has\n     * only the {@link Manifest.permission#ACCESS_COARSE_LOCATION} permission, and no location if it lacks either.\n     */\n    int GRANULARITY_PERMISSION_LEVEL = 0;\n    /**\n     * The desired location granularity is always coarse, regardless of the client permission level. The client will be delivered\n     * coarse locations while it has the {@link Manifest.permission#ACCESS_FINE_LOCATION} or\n     * {@link Manifest.permission#ACCESS_COARSE_LOCATION} permission, and no location if it lacks either.\n     */\n    int GRANULARITY_COARSE = 1;\n    /**\n     * The desired location granularity is always fine, regardless of the client permission level. The client will be delivered fine\n     * locations while it has the {@link Manifest.permission#ACCESS_FINE_LOCATION}, and no location if it lacks that permission.\n     */\n    int GRANULARITY_FINE = 2;\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/LastLocationRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.location;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.location.internal.ClientIdentity;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.location.GranularityUtil;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\nimport java.util.Objects;\n\n/**\n * An encapsulation of various parameters for requesting a (cached) last location through {@link FusedLocationProviderClient}.\n *\n * @see FusedLocationProviderClient#getLastLocation(LastLocationRequest)\n */\npublic class LastLocationRequest extends AutoSafeParcelable {\n    @Field(1)\n    private long maxUpdateAgeMillis;\n    @Field(2)\n    private @Granularity int granularity;\n    @Field(3)\n    private boolean bypass;\n    @Field(4)\n    @Nullable\n    private String moduleId;\n    @Field(5)\n    @Nullable\n    private ClientIdentity impersonation;\n\n    private LastLocationRequest() {\n        maxUpdateAgeMillis = Long.MAX_VALUE;\n        granularity = Granularity.GRANULARITY_PERMISSION_LEVEL;\n    }\n\n\n    /**\n     * The {@link Granularity} of locations returned for this request. This controls whether fine or coarse locations may be returned.\n     */\n    public @Granularity int getGranularity() {\n        return granularity;\n    }\n\n    /**\n     * The maximum age of any location returned for this request. A value of {@link Long#MAX_VALUE} represents an effectively unbounded maximum age.\n     */\n    public long getMaxUpdateAgeMillis() {\n        return maxUpdateAgeMillis;\n    }\n\n    /**\n     * A builder for {@link LastLocationRequest}.\n     */\n    public static class Builder {\n        private long maxUpdateAgeMillis;\n        private @Granularity int granularity;\n        private boolean bypass;\n        @Nullable\n        private String moduleId;\n        @Nullable\n        private ClientIdentity impersonation;\n\n        /**\n         * Constructs a new builder with default values.\n         */\n        public Builder() {\n            maxUpdateAgeMillis = Long.MAX_VALUE;\n            granularity = Granularity.GRANULARITY_PERMISSION_LEVEL;\n        }\n\n        /**\n         * Constructs a new builder with values copied from the given {@link LastLocationRequest}.\n         */\n        public Builder(@NonNull LastLocationRequest request) {\n            this.maxUpdateAgeMillis = request.getMaxUpdateAgeMillis();\n            this.granularity = request.getGranularity();\n            this.bypass = request.isBypass();\n            this.moduleId = request.getModuleId();\n            this.impersonation = request.getImpersonation();\n        }\n\n        /**\n         * Sets the {@link Granularity} of locations returned for this request. This controls whether fine or coarse locations may be returned.\n         * <p>\n         * The default value is {@link Granularity#GRANULARITY_PERMISSION_LEVEL}.\n         */\n        public LastLocationRequest.Builder setGranularity(@Granularity int granularity) {\n            GranularityUtil.checkValidGranularity(granularity);\n            this.granularity = granularity;\n            return this;\n        }\n\n        /**\n         * Sets the maximum age of any location returned for this request. A value of {@link Long#MAX_VALUE} represents an effectively unbounded maximum age.\n         * <p>\n         * The default value is {@link Long#MAX_VALUE}.\n         */\n        public LastLocationRequest.Builder setMaxUpdateAgeMillis(long maxUpdateAgeMillis) {\n            if (maxUpdateAgeMillis <= 0) throw new IllegalArgumentException(\"maxUpdateAgeMillis must be greater than 0\");\n            this.maxUpdateAgeMillis = maxUpdateAgeMillis;\n            return this;\n        }\n\n        /**\n         * Builds a new {@link LastLocationRequest}.\n         */\n        public LastLocationRequest build() {\n            LastLocationRequest request = new LastLocationRequest();\n            request.maxUpdateAgeMillis = maxUpdateAgeMillis;\n            request.granularity = granularity;\n            request.bypass = bypass;\n            request.moduleId = moduleId;\n            request.impersonation = impersonation;\n            return request;\n        }\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof LastLocationRequest)) return false;\n\n        LastLocationRequest request = (LastLocationRequest) o;\n\n        if (maxUpdateAgeMillis != request.maxUpdateAgeMillis) return false;\n        if (granularity != request.granularity) return false;\n        if (bypass != request.bypass) return false;\n        if (!Objects.equals(moduleId, request.moduleId)) return false;\n        return Objects.equals(impersonation, request.impersonation);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hashCode(new Object[]{this.maxUpdateAgeMillis, this.granularity, this.bypass});\n    }\n\n    @Hide\n    public boolean isBypass() {\n        return bypass;\n    }\n\n    @Hide\n    @Nullable\n    public String getModuleId() {\n        return moduleId;\n    }\n\n    @Hide\n    @Nullable\n    public ClientIdentity getImpersonation() {\n        return impersonation;\n    }\n\n    public static final Creator<LastLocationRequest> CREATOR = new AutoCreator<>(LastLocationRequest.class);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/LocationAvailability.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2015 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.location;\n\nimport android.content.Intent;\n\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\nimport java.util.Arrays;\n\n/**\n * Information on the availability of location data.\n */\n@PublicApi\npublic class LocationAvailability extends AutoSafeParcelable {\n    private static final String EXTRA_KEY = \"com.google.android.gms.location.EXTRA_LOCATION_AVAILABILITY\";\n\n    @Hide\n    public static LocationAvailability AVAILABLE = new LocationAvailability(0, 1, 1, 0, null);\n    @Hide\n    public static LocationAvailability UNAVAILABLE = new LocationAvailability(1000, 1, 1, 0, null);\n\n    @Hide\n    public static final int STATUS_SUCCESSFUL = 0;\n    @Hide\n    public static final int STATUS_UNKNOWN = 1;\n    @Hide\n    public static final int STATUS_TIMED_OUT_ON_SCAN = 2;\n    @Hide\n    public static final int STATUS_NO_INFO_IN_DATABASE = 3;\n    @Hide\n    public static final int STATUS_INVALID_SCAN = 4;\n    @Hide\n    public static final int STATUS_UNABLE_TO_QUERY_DATABASE = 5;\n    @Hide\n    public static final int STATUS_SCANS_DISABLED_IN_SETTINGS = 6;\n    @Hide\n    public static final int STATUS_LOCATION_DISABLED_IN_SETTINGS = 7;\n    @Hide\n    public static final int STATUS_IN_PROGRESS = 8;\n\n    @Field(1000)\n    private int versionCode = 2;\n\n    @Field(1)\n    @Hide\n    public int cellStatus;\n\n    @Field(2)\n    @Hide\n    public int wifiStatus;\n\n    @Field(3)\n    @Hide\n    public long elapsedRealtimeNs;\n\n    @Field(4)\n    @Hide\n    public int locationStatus;\n\n    @Field(5)\n    @Hide\n    public NetworkLocationStatus[] batchedStatus;\n\n    private LocationAvailability() {\n    }\n\n    @Hide\n    public LocationAvailability(int locationStatus, int cellStatus, int wifiStatus, long elapsedRealtimeNs, NetworkLocationStatus[] batchedStatus) {\n        this.locationStatus = locationStatus;\n        this.cellStatus = cellStatus;\n        this.wifiStatus = wifiStatus;\n        this.elapsedRealtimeNs = elapsedRealtimeNs;\n        this.batchedStatus = batchedStatus;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (o instanceof LocationAvailability) {\n            LocationAvailability other = (LocationAvailability) o;\n            return other.cellStatus == cellStatus && other.wifiStatus == wifiStatus && other.elapsedRealtimeNs == elapsedRealtimeNs && other.locationStatus == locationStatus;\n        }\n        return false;\n    }\n\n    /**\n     * Extracts the {@link LocationAvailability} from an Intent.\n     *\n     * @return a {@link LocationAvailability}, or null if the Intent doesn't contain this data.\n     */\n    public static LocationAvailability extractLocationAvailability(Intent intent) {\n        if (!hasLocationAvailability(intent)) {\n            return null;\n        }\n        return intent.getParcelableExtra(EXTRA_KEY);\n    }\n\n    /**\n     * Returns true if an Intent contains a {@link LocationAvailability}.\n     *\n     * @return true if the intent contains a {@link LocationAvailability}, false otherwise.\n     */\n    public static boolean hasLocationAvailability(Intent intent) {\n        return intent != null && intent.hasExtra(EXTRA_KEY);\n    }\n\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(new Object[]{locationStatus, cellStatus, wifiStatus, elapsedRealtimeNs});\n    }\n\n    /**\n     * Returns true if the device location is generally available.\n     */\n    public boolean isLocationAvailable() {\n        return locationStatus < 1000;\n    }\n\n    @Override\n    public String toString() {\n        return \"LocationAvailability[\" + isLocationAvailable() + \"]\";\n    }\n\n    public static final Creator<LocationAvailability> CREATOR = new AutoCreator<LocationAvailability>(LocationAvailability.class);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/LocationAvailabilityRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.location;\n\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.location.internal.ClientIdentity;\nimport org.microg.gms.common.Hide;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n@Hide\npublic class LocationAvailabilityRequest extends AutoSafeParcelable {\n    @Field(1)\n    public boolean bypass;\n    @Field(2)\n    @Nullable\n    public ClientIdentity impersonation;\n    public static final Creator<LocationAvailabilityRequest> CREATOR = new AutoCreator<>(LocationAvailabilityRequest.class);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/LocationCallback.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.location;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * A callback for receiving notifications from the {@link FusedLocationProviderClient}.\n */\n@PublicApi\npublic abstract class LocationCallback {\n    /**\n     * Called when there is a change in the availability of location data.\n     * <p>\n     * When {@link LocationAvailability#isLocationAvailable()} returns false it generally indicates that further\n     * invocations of {@link #onLocationResult(LocationResult)} are unlikely until something changes with the device's\n     * settings or environment. When {@link LocationAvailability#isLocationAvailable()} returns true it generally\n     * indicates that further invocations of {@link #onLocationResult(LocationResult)} are likely, and fresh locations\n     * can be expected.\n     *\n     * @param availability The latest location availability.\n     */\n    public void onLocationAvailability(LocationAvailability availability) {\n\n    }\n\n    /**\n     * Called when a new {@link LocationResult} is available. The locations within the location result will generally\n     * be as fresh as possible given the parameters of the associated {@link LocationRequest} and the state of the\n     * device, but this does not imply that they will always represent the current location. Clients may wish to\n     * reference the time associated with each location.\n     *\n     * @param result The latest location result.\n     */\n    public void onLocationResult(LocationResult result) {\n\n    }\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/LocationClient.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.location;\n\nimport android.app.PendingIntent;\nimport android.content.Context;\nimport android.location.Location;\nimport android.os.Looper;\n\nimport androidx.annotation.RequiresPermission;\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.PendingResult;\n\nimport org.microg.gms.common.ForwardConnectionCallbacks;\nimport org.microg.gms.common.ForwardConnectionFailedListener;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.common.api.AbstractPlayServicesClient;\n\nimport static android.Manifest.permission.ACCESS_COARSE_LOCATION;\nimport static android.Manifest.permission.ACCESS_FINE_LOCATION;\n\n/**\n * This class is deprecated as of play services 6.5, do not use it in production systems,\n * it's just a forwarder for the {@link FusedLocationProviderApi}.\n */\n@Deprecated\n@Hide\npublic class LocationClient extends AbstractPlayServicesClient {\n    public static final String KEY_LOCATION_CHANGED = \"com.google.android.location.LOCATION\";\n\n    public LocationClient(Context context, ConnectionCallbacks callbacks,\n            OnConnectionFailedListener connectionFailedListener) {\n        super(new GoogleApiClient.Builder(context)\n                .addApi(LocationServices.API)\n                .addConnectionCallbacks(new ForwardConnectionCallbacks(callbacks))\n                .addOnConnectionFailedListener(new ForwardConnectionFailedListener\n                        (connectionFailedListener))\n                .build());\n    }\n\n    @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})\n    public Location getLastLocation() {\n        assertConnected();\n        return LocationServices.FusedLocationApi.getLastLocation(googleApiClient);\n    }\n\n    @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})\n    public void requestLocationUpdates(LocationRequest request,\n            LocationListener listener) {\n        assertConnected();\n        LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, request,\n                listener).await();\n    }\n\n    @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})\n    public void requestLocationUpdates(LocationRequest request,\n            LocationListener listener, Looper looper) {\n        assertConnected();\n        LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, request,\n                listener, looper).await();\n    }\n\n    @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})\n    public void requestLocationUpdates(LocationRequest request,\n            PendingIntent callbackIntent) {\n        assertConnected();\n        LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, request,\n                callbackIntent).await();\n    }\n\n    public void removeLocationUpdates(LocationListener listener) {\n        assertConnected();\n        LocationServices.FusedLocationApi.removeLocationUpdates(googleApiClient, listener).await();\n    }\n\n    public void removeLocationUpdates(PendingIntent callbackIntent) {\n        assertConnected();\n        LocationServices.FusedLocationApi.removeLocationUpdates(googleApiClient,\n                callbackIntent).await();\n    }\n\n    public void setMockMode(boolean isMockMode) {\n        assertConnected();\n        LocationServices.FusedLocationApi.setMockMode(googleApiClient, isMockMode).await();\n    }\n\n    public void setMockLocation(Location mockLocation) {\n        assertConnected();\n        LocationServices.FusedLocationApi.setMockLocation(googleApiClient, mockLocation).await();\n    }\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/LocationListener.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.location;\n\nimport android.location.Location;\nimport androidx.annotation.NonNull;\n\n/**\n * Used for receiving notifications from the {@link FusedLocationProviderApi} when the location has\n * changed. The methods are called if the LocationListener has been registered with the location\n * client.\n */\npublic interface LocationListener {\n\n    /**\n     * Called when the location has changed.\n     *\n     * @param location The updated location.\n     */\n    public void onLocationChanged(@NonNull Location location);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/LocationRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2015 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.location;\n\nimport android.Manifest;\nimport android.os.SystemClock;\n\nimport android.os.WorkSource;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresPermission;\nimport com.google.android.gms.location.internal.ClientIdentity;\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.location.GranularityUtil;\nimport org.microg.gms.location.PriorityUtil;\nimport org.microg.gms.location.ThrottleBehaviorUtil;\nimport org.microg.gms.utils.WorkSourceUtil;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\nimport java.util.Arrays;\nimport java.util.Objects;\n\n/**\n * A data object that contains quality of service parameters for requests to the\n * FusedLocationProviderApi.\n * <p/>\n * LocationRequest objects are used to request a quality of service for location updates from the\n * FusedLocationProviderApi.\n * <p/>\n * For example, if your application wants high accuracy location it should create a location\n * request with {@link #setPriority(int)} set to {@link #PRIORITY_HIGH_ACCURACY} and\n * {@link #setInterval(long)} to 5 seconds. This would be appropriate for mapping applications that\n * are showing your location in real-time.\n * <p/>\n * At the other extreme, if you want negligible power impact, but to still receive location updates\n * when available, then create a location request with {@link #setPriority(int)} set to\n * {@link #PRIORITY_NO_POWER}. With this request your application will not trigger (and therefore\n * will not receive any power blame) any location updates, but will receive locations triggered by\n * other applications. This would be appropriate for applications that have no firm requirement for\n * location, but can take advantage when available.\n * <p/>\n * In between these two extremes is a very common use-case, where applications definitely want to\n * receive updates at a specified interval, and can receive them faster when available, but still\n * want a low power impact. These applications should consider\n * {@link #PRIORITY_BALANCED_POWER_ACCURACY} combined with a faster\n * {@link #setFastestInterval(long)} (such as 1 minute) and a slower {@link #setInterval(long)}\n * (such as 60 minutes). They will only be assigned power blame for the interval set by\n * {@link #setInterval(long)}, but can still receive locations triggered by other applications at a\n * rate up to {@link #setFastestInterval(long)}. This style of request is appropriate for many\n * location aware applications, including background usage. Do be careful to also throttle\n * {@link #setFastestInterval(long)} if you perform heavy-weight work after receiving an update -\n * such as using the network.\n * <p/>\n * Activities should strongly consider removing all location request when entering the background\n * (for example at {@link android.app.Activity#onPause()}), or at least swap the request to a\n * larger interval and lower quality.\n * <p/>\n * Applications cannot specify the exact location sources, such as GPS, that are used by the\n * LocationClient. In fact, the system may have multiple location sources (providers) running and\n * may fuse the results from several sources into a single Location object.\n * <p/>\n * Location requests from applications with\n * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} and not\n * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} will be automatically throttled to a\n * slower interval, and the location object will be obfuscated to only show a coarse level of\n * accuracy.\n * <p/>\n * All location requests are considered hints, and you may receive locations that are more/less\n * accurate, and faster/slower than requested.\n */\npublic class LocationRequest extends AutoSafeParcelable {\n\n    /**\n     * @deprecated Use {@link Priority#PRIORITY_BALANCED_POWER_ACCURACY} instead.\n     */\n    @Deprecated\n    public static final int PRIORITY_BALANCED_POWER_ACCURACY = 102;\n    /**\n     * @deprecated Use {@link Priority#PRIORITY_HIGH_ACCURACY} instead.\n     */\n    @Deprecated\n    public static final int PRIORITY_HIGH_ACCURACY = 100;\n    /**\n     * @deprecated Use {@link Priority#PRIORITY_LOW_POWER} instead.\n     */\n    @Deprecated\n    public static final int PRIORITY_LOW_POWER = 104;\n    /**\n     * @deprecated Use {@link Priority#PRIORITY_PASSIVE} instead.\n     */\n    @Deprecated\n    public static final int PRIORITY_NO_POWER = 105;\n\n    @Field(1000)\n    private int versionCode = 1;\n    @Field(1)\n    @Priority\n    private int priority;\n    @Field(2)\n    private long intervalMillis;\n    @Field(3)\n    private long minUpdateIntervalMillis;\n    @Field(4)\n    @Deprecated\n    private boolean explicitFastestInterval;\n    @Field(5)\n    @Deprecated\n    private long expirationTime;\n    @Field(6)\n    private int maxUpdates;\n    @Field(7)\n    private float minUpdateDistanceMeters;\n    @Field(8)\n    private long maxUpdateDelayMillis;\n    @Field(9)\n    private boolean waitForAccurateLocation;\n    @Field(10)\n    private long durationMillis;\n    @Field(11)\n    private long maxUpdateAgeMillis;\n    @Field(12)\n    @Granularity\n    private int granularity;\n    @Field(13)\n    @ThrottleBehavior\n    private int throttleBehavior;\n    @Field(14)\n    @Nullable\n    private String moduleId;\n    @Field(15)\n    private boolean bypass;\n    @Field(16)\n    @NonNull\n    private WorkSource workSource;\n    @Field(17)\n    @Nullable\n    private ClientIdentity impersonation;\n\n    @Deprecated\n    public LocationRequest() {\n        this.priority = Priority.PRIORITY_BALANCED_POWER_ACCURACY;\n        this.intervalMillis = 3600000;\n        this.minUpdateIntervalMillis = 600000;\n        this.maxUpdateDelayMillis = 0;\n        this.durationMillis = Long.MAX_VALUE;\n        this.maxUpdates = Integer.MAX_VALUE;\n        this.minUpdateDistanceMeters = 0;\n        this.waitForAccurateLocation = false;\n        this.maxUpdateAgeMillis = -1;\n        this.granularity = Granularity.GRANULARITY_PERMISSION_LEVEL;\n        this.throttleBehavior = ThrottleBehavior.THROTTLE_BACKGROUND;\n        this.bypass = false;\n        this.workSource = new WorkSource();\n\n        // deprecated\n        this.explicitFastestInterval = false;\n        this.expirationTime = Long.MAX_VALUE;\n    }\n\n    /**\n     * @deprecated Use {@link LocationRequest.Builder} instead. May be removed in a future release.\n     */\n    @Deprecated\n    public static LocationRequest create() {\n        return new LocationRequest();\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (!(o instanceof LocationRequest)) return false;\n        LocationRequest other = (LocationRequest) o;\n\n        if (this.priority != other.priority) return false;\n        if (this.intervalMillis != other.intervalMillis && !isPassive()) return false;\n        if (this.minUpdateIntervalMillis != other.minUpdateIntervalMillis) return false;\n        if (isBatched() != other.isBatched()) return false;\n        if (this.maxUpdateDelayMillis != other.maxUpdateDelayMillis && isBatched()) return false;\n        if (this.durationMillis != other.durationMillis) return false;\n        if (this.maxUpdates != other.maxUpdates) return false;\n        if (this.minUpdateDistanceMeters != other.minUpdateDistanceMeters) return false;\n        if (this.waitForAccurateLocation != other.waitForAccurateLocation) return false;\n        if (this.granularity != other.granularity) return false;\n        if (this.throttleBehavior != other.throttleBehavior) return false;\n        if (this.workSource.equals(other.workSource)) return false;\n        if (!Objects.equals(this.moduleId, other.moduleId)) return false;\n        if (!Objects.equals(this.impersonation, other.impersonation)) return false;\n\n        return true;\n    }\n\n    /**\n     * The duration of this request. A location request will not receive any locations after it has expired, and will be removed\n     * shortly thereafter. A value of {@link Long#MAX_VALUE} implies an infinite duration.\n     */\n    public long getDurationMillis() {\n        return durationMillis;\n    }\n\n    /**\n     * @deprecated Use {@link #getDurationMillis()} instead. Using this method will return the duration added to the current elapsed realtime, which\n     * may give unexpected results. May be removed in a future release.\n     */\n    @Deprecated\n    public long getExpirationTime() {\n        return expirationTime;\n    }\n\n    /**\n     * @deprecated Use {@link #getMinUpdateIntervalMillis()} instead. May be removed in a future release.\n     */\n    @Deprecated\n    public long getFastestInterval() {\n        return getMinUpdateIntervalMillis();\n    }\n\n    /**\n     * The {@link Granularity} of locations returned for this request. This controls whether fine or coarse locations may be returned.\n     */\n    @Granularity\n    public int getGranularity() {\n        return granularity;\n    }\n\n    @Nullable\n    @PublicApi(exclude = true)\n    public ClientIdentity getImpersonation() {\n        return impersonation;\n    }\n\n    /**\n     * @deprecated Use {@link #getIntervalMillis()} instead. May be removed in a future release.\n     */\n    @Deprecated\n    public long getInterval() {\n        return intervalMillis;\n    }\n\n    /**\n     * The desired interval of location updates. Location updates may arrive faster than this interval (but no faster than\n     * specified by {@link #getMinUpdateIntervalMillis()}) or slower than this interval (if the request is being throttled for\n     * example).\n     */\n    public long getIntervalMillis() {\n        return intervalMillis;\n    }\n\n    /**\n     * The maximum age of an initial historical location delivered for this request. A value of 0 indicates that no initial historical\n     * location will be delivered, only freshly derived locations. A value {@link Long#MAX_VALUE} represents an effectively unbounded\n     * maximum age.\n     */\n    public long getMaxUpdateAgeMillis() {\n        if (maxUpdateAgeMillis == Builder.IMPLICIT_MAX_UPDATE_AGE) return intervalMillis;\n        return maxUpdateAgeMillis;\n    }\n\n    /**\n     * The longest a location update may be delayed. This parameter controls location batching behavior. If this is set to a value\n     * at least 2x larger than the interval specified by {@link #getIntervalMillis()}, then a device may (but is not required to) save\n     * power by delivering locations in batches. If clients do not require immediate delivery, consider setting this value as high\n     * as is reasonable to allow for additional power savings.\n     * <p>\n     * For example, if a request is made with a 2s interval and a 10s maximum update delay, this implies that the device may\n     * choose to deliver batches of 5 locations every 10s (where each location should represent a point in time ~2s after the\n     * previous).\n     * <p>\n     * Support for batching may vary by device type, so simply allowing batching via this parameter does not imply a client will\n     * receive batched results on all devices.\n     * <p>\n     * {@link FusedLocationProviderClient#flushLocations()} may be used to flush locations that have been batched, but not\n     * delivered yet.\n     */\n    public long getMaxUpdateDelayMillis() {\n        return maxUpdateDelayMillis;\n    }\n\n    /**\n     * The maximum number of updates delivered to this request. A location request will not receive any locations after the\n     * maximum number of updates has been reached, and will be removed shortly thereafter. A value of {@link Integer#MAX_VALUE}\n     * implies an unlimited number of updates.\n     */\n    public int getMaxUpdates() {\n        return maxUpdates;\n    }\n\n    /**\n     * @deprecated Use {@link #getMaxUpdateDelayMillis()} instead. May be removed in a future release.\n     */\n    @Deprecated\n    public long getMaxWaitTime() {\n        return getMaxUpdateDelayMillis();\n    }\n\n    /**\n     * The minimum distance required between consecutive location updates. If a derived location update is not at least the\n     * specified distance away from the previous location update delivered to the client, it will not be delivered. This may also\n     * allow additional power savings under some circumstances.\n     */\n    public float getMinUpdateDistanceMeters() {\n        return minUpdateDistanceMeters;\n    }\n\n    /**\n     * The fastest allowed interval of location updates. Location updates may arrive faster than the desired interval\n     * ({@link #getIntervalMillis()}), but will never arrive faster than specified here. FLP APIs make some allowance for jitter with\n     * the minimum update interval, so clients need not worry about location updates that arrive a couple milliseconds too early\n     * being rejected.\n     */\n    public long getMinUpdateIntervalMillis() {\n        if (minUpdateIntervalMillis == Builder.IMPLICIT_MIN_UPDATE_INTERVAL) return intervalMillis;\n        return minUpdateIntervalMillis;\n    }\n\n    @PublicApi(exclude = true)\n    @Nullable\n    public String getModuleId() {\n        return moduleId;\n    }\n\n    /**\n     * @deprecated Use {@link #getMaxUpdates()} instead. May be removed in a future release.\n     */\n    @Deprecated\n    public int getNumUpdates() {\n        return getMaxUpdates();\n    }\n\n    /**\n     * The {@link Priority} of the location request.\n     */\n    @Priority\n    public int getPriority() {\n        return priority;\n    }\n\n    /**\n     * @deprecated Use {@link #getMinUpdateDistanceMeters()} instead.\n     */\n    @Deprecated\n    public float getSmallestDisplacement() {\n        return getMinUpdateDistanceMeters();\n    }\n\n    @PublicApi(exclude = true)\n    @ThrottleBehavior\n    public int getThrottleBehavior() {\n        return throttleBehavior;\n    }\n\n    @PublicApi(exclude = true)\n    public WorkSource getWorkSource() {\n        return workSource;\n    }\n\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(new Object[]{priority, intervalMillis, minUpdateIntervalMillis, workSource});\n    }\n\n    /**\n     * True if this request allows batching (i.e. {@link #getMaxUpdateDelayMillis()} is at least 2x {@link #getIntervalMillis()}).\n     */\n    public boolean isBatched() {\n        return maxUpdateDelayMillis > 0 && maxUpdateDelayMillis > intervalMillis * 2;\n    }\n\n    @PublicApi(exclude = true)\n    public boolean isBypass() {\n        return bypass;\n    }\n\n    /**\n     * @deprecated Do not use. May be removed in a future release.\n     */\n    @Deprecated\n    public boolean isFastestIntervalExplicitlySet() {\n        return true;\n    }\n\n    /**\n     * True if the priority is {@link Priority#PRIORITY_PASSIVE}.\n     */\n    public boolean isPassive() {\n        return priority == Priority.PRIORITY_PASSIVE;\n    }\n\n    /**\n     * If this request is {@link Priority#PRIORITY_HIGH_ACCURACY}, this will delay delivery of initial low accuracy locations for a\n     * small amount of time in case a high accuracy location can be delivered instead.\n     */\n    public boolean isWaitForAccurateLocation() {\n        return waitForAccurateLocation;\n    }\n\n    /**\n     * @deprecated Use {@link LocationRequest.Builder#setDurationMillis(long)} instead. May be removed in a future release.\n     */\n    @Deprecated\n    @NonNull\n    public LocationRequest setExpirationDuration(long durationMillis) {\n        if (durationMillis <= 0) throw new IllegalArgumentException(\"durationMillis must be greater than 0\");\n        this.durationMillis = durationMillis;\n        return this;\n    }\n\n    /**\n     * @deprecated Use {@link LocationRequest.Builder#setDurationMillis(long)} instead. Using this method will express the expiration time in\n     * terms of duration, which may give unexpected results. May be removed in a future release.\n     */\n    @Deprecated\n    @NonNull\n    public LocationRequest setExpirationTime(long elapsedRealtime) {\n        this.durationMillis = Math.max(1, elapsedRealtime - SystemClock.elapsedRealtime());\n        return this;\n    }\n\n    /**\n     * @deprecated Use {@link LocationRequest.Builder#setMinUpdateIntervalMillis(long)} instead. May be removed in a future release.\n     */\n    @Deprecated\n    @NonNull\n    public LocationRequest setFastestInterval(long fastestIntervalMillis) throws IllegalArgumentException {\n        if (fastestIntervalMillis < 0) throw new IllegalArgumentException(\"illegal fastest interval: \" + fastestIntervalMillis);\n        this.minUpdateIntervalMillis = fastestIntervalMillis;\n        explicitFastestInterval = true; // FIXME: Remove\n        return this;\n    }\n\n    /**\n     * @deprecated Use {@link LocationRequest.Builder#setIntervalMillis(long)} instead. May be removed in a future release.\n     */\n    @Deprecated\n    @NonNull\n    public LocationRequest setInterval(long intervalMillis) throws IllegalArgumentException {\n        if (intervalMillis < 0) throw new IllegalArgumentException(\"intervalMillis must be greater than or equal to 0\");\n        if (this.minUpdateIntervalMillis == this.intervalMillis / 6) {\n            this.minUpdateIntervalMillis = intervalMillis / 6;\n        }\n        if (this.maxUpdateAgeMillis == this.intervalMillis) {\n            this.maxUpdateAgeMillis = intervalMillis;\n        }\n        this.intervalMillis = intervalMillis;\n        return this;\n    }\n\n    /**\n     * @deprecated Use {@link LocationRequest.Builder#setMaxUpdateDelayMillis(long)} instead. May be removed in a future release.\n     */\n    @Deprecated\n    @NonNull\n    public LocationRequest setMaxWaitTime(long maxWaitTimeMillis) throws IllegalArgumentException {\n        if (maxWaitTimeMillis < 0) throw new IllegalArgumentException(\"illegal max wait time: \" + maxWaitTimeMillis);\n        maxUpdateDelayMillis = maxWaitTimeMillis;\n        return this;\n    }\n\n    /**\n     * @deprecated Use {@link LocationRequest.Builder#setMaxUpdates(int)} instead. May be removed in a future release.\n     */\n    @Deprecated\n    @NonNull\n    public LocationRequest setNumUpdates(int maxUpdates) throws IllegalArgumentException {\n        if (maxUpdates <= 0) throw new IllegalArgumentException(\"invalid numUpdates: \" + maxUpdates);\n        this.maxUpdates = maxUpdates;\n        return this;\n    }\n\n    /**\n     * @deprecated Use {@link LocationRequest.Builder#setPriority(int)} instead. May be removed in a future release.\n     */\n    @Deprecated\n    @NonNull\n    public LocationRequest setPriority(@Priority int priority) {\n        PriorityUtil.checkValidPriority(priority);\n        this.priority = priority;\n        return this;\n    }\n\n    /**\n     * @deprecated Use {@link LocationRequest.Builder#setMinUpdateDistanceMeters(float)} instead. May be removed in a future release.\n     */\n    @Deprecated\n    @NonNull\n    public LocationRequest setSmallestDisplacement(float smallestDisplacementMeters) {\n        if (smallestDisplacementMeters < 0) throw new IllegalArgumentException(\"invalid displacement: \" + smallestDisplacementMeters);\n        this.minUpdateDistanceMeters = smallestDisplacementMeters;\n        return this;\n    }\n\n    /**\n     * @deprecated Use {@link LocationRequest.Builder#setWaitForAccurateLocation(boolean)} instead. May be removed in a future release.\n     */\n    @Deprecated\n    @NonNull\n    public LocationRequest setWaitForAccurateLocation(boolean waitForAccurateLocation) {\n        this.waitForAccurateLocation = waitForAccurateLocation;\n        return this;\n    }\n\n    @Override\n    @NonNull\n    public String toString() {\n        StringBuilder sb = new StringBuilder();\n        sb.append(\"Request[\");\n        if (isPassive()) {\n            sb.append(PriorityUtil.priorityToString(priority));\n        } else {\n            sb.append(\"@\");\n            sb.append(intervalMillis).append(\"ms\");\n            if (isBatched()) {\n                sb.append(\"/\");\n                sb.append(maxUpdateDelayMillis).append(\"ms\");\n            }\n            sb.append(\" \").append(PriorityUtil.priorityToString(priority));\n        }\n        if (isPassive() || minUpdateIntervalMillis != intervalMillis)\n            sb.append(\", minUpdateInterval=\").append(minUpdateIntervalMillis).append(\"ms\");\n        if (minUpdateDistanceMeters > 0)\n            sb.append(\", minUpdateDistance=\").append(minUpdateDistanceMeters).append(\"m\");\n        if (!isPassive() ? maxUpdateAgeMillis != intervalMillis : maxUpdateAgeMillis != Long.MAX_VALUE)\n            sb.append(\", maxUpdateAge=\").append(maxUpdateAgeMillis).append(\"ms\");\n        if (durationMillis != Long.MAX_VALUE)\n            sb.append(\", duration=\").append(durationMillis).append(\"ms\");\n        if (maxUpdates != Integer.MAX_VALUE)\n            sb.append(\", maxUpdates\").append(maxUpdates);\n        if (throttleBehavior != 0)\n            sb.append(\", \").append(ThrottleBehaviorUtil.throttleBehaviorToString(throttleBehavior));\n        if (granularity != 0)\n            sb.append(\", \").append(GranularityUtil.granularityToString(granularity));\n        if (waitForAccurateLocation)\n            sb.append(\", waitForAccurateLocation\");\n        if (bypass)\n            sb.append(\", bypass\");\n        if (moduleId != null)\n            sb.append(\", moduleId=\").append(moduleId);\n        if (!WorkSourceUtil.isEmpty(workSource))\n            sb.append(\", \").append(workSource);\n        if (impersonation != null)\n            sb.append(\", impersonation=\").append(impersonation);\n        sb.append(\"]\");\n        return sb.toString();\n    }\n\n    /**\n     * Builder for {@link LocationRequest}.\n     */\n    public static final class Builder {\n        /**\n         * Represents a maximum update age that is the same as the interval.\n         */\n        public static final long IMPLICIT_MAX_UPDATE_AGE = -1;\n        /**\n         * Represents a minimum update interval that is the same as the interval.\n         */\n        public static final long IMPLICIT_MIN_UPDATE_INTERVAL = -1;\n\n        @Priority\n        private int priority;\n        private long intervalMillis;\n        private long minUpdateIntervalMillis;\n        private long maxUpdateDelayMillis;\n        private long durationMillis;\n        private int maxUpdates;\n        private float minUpdateDistanceMeters;\n        private boolean waitForAccurateLocation;\n        private long maxUpdateAgeMillis;\n        @Granularity\n        private int granularity;\n        @ThrottleBehavior\n        private int throttleBehavior;\n        @Nullable\n        private String moduleId;\n        private boolean bypass;\n        @Nullable\n        private WorkSource workSource;\n        @Nullable\n        private ClientIdentity impersonation;\n\n        /**\n         * Constructs a Builder with the given interval, and default values for all other fields.\n         */\n        public Builder(long intervalMillis) {\n            this(Priority.PRIORITY_BALANCED_POWER_ACCURACY, intervalMillis);\n        }\n\n        /**\n         * Constructs a Builder with the given priority and interval, and default values for all other fields.\n         */\n        public Builder(@Priority int priority, long intervalMillis) {\n            if (intervalMillis < 0) throw new IllegalArgumentException(\"intervalMillis must be greater than or equal to 0\");\n            PriorityUtil.checkValidPriority(priority);\n            this.priority = priority;\n            this.intervalMillis = intervalMillis;\n            this.minUpdateIntervalMillis = IMPLICIT_MIN_UPDATE_INTERVAL;\n            this.maxUpdateDelayMillis = 0;\n            this.durationMillis = Long.MAX_VALUE;\n            this.maxUpdates = Integer.MAX_VALUE;\n            this.minUpdateDistanceMeters = 0;\n            this.waitForAccurateLocation = true;\n            this.maxUpdateAgeMillis = IMPLICIT_MAX_UPDATE_AGE;\n            this.granularity = Granularity.GRANULARITY_PERMISSION_LEVEL;\n            this.throttleBehavior = ThrottleBehavior.THROTTLE_BACKGROUND;\n            this.moduleId = null;\n            this.bypass = false;\n            this.workSource = null;\n            this.impersonation = null;\n        }\n\n        /**\n         * Constructs a Builder with values copied from the given {@link LocationRequest}.\n         */\n        public Builder(LocationRequest request) {\n            this.priority = request.getPriority();\n            this.intervalMillis = request.getIntervalMillis();\n            this.minUpdateIntervalMillis = request.getMinUpdateIntervalMillis();\n            this.maxUpdateDelayMillis = request.getMaxUpdateDelayMillis();\n            this.durationMillis = request.getDurationMillis();\n            this.maxUpdates = request.getMaxUpdates();\n            this.minUpdateDistanceMeters = request.getMinUpdateDistanceMeters();\n            this.waitForAccurateLocation = request.isWaitForAccurateLocation();\n            this.maxUpdateAgeMillis = request.getMaxUpdateAgeMillis();\n            this.granularity = request.getGranularity();\n            this.throttleBehavior = request.getThrottleBehavior();\n            this.moduleId = request.getModuleId();\n            this.bypass = request.isBypass();\n            this.workSource = request.getWorkSource();\n            this.impersonation = request.getImpersonation();\n        }\n\n        /**\n         * Builds a new {@link LocationRequest}.\n         */\n        @NonNull\n        public LocationRequest build() {\n            LocationRequest request = new LocationRequest();\n            request.priority = priority;\n            request.intervalMillis = intervalMillis;\n            if (minUpdateIntervalMillis == IMPLICIT_MIN_UPDATE_INTERVAL) {\n                request.minUpdateIntervalMillis = intervalMillis;\n            } else {\n                request.minUpdateIntervalMillis = priority == Priority.PRIORITY_PASSIVE ? minUpdateIntervalMillis : Math.min(intervalMillis, minUpdateIntervalMillis);\n            }\n            request.maxUpdateDelayMillis = Math.max(maxUpdateDelayMillis, intervalMillis);\n            request.durationMillis = durationMillis;\n            request.maxUpdates = maxUpdates;\n            request.minUpdateDistanceMeters = minUpdateDistanceMeters;\n            request.waitForAccurateLocation = waitForAccurateLocation;\n            request.maxUpdateAgeMillis = maxUpdateAgeMillis != IMPLICIT_MAX_UPDATE_AGE ? maxUpdateAgeMillis : intervalMillis;\n            request.granularity = granularity;\n            request.throttleBehavior = throttleBehavior;\n            request.moduleId = moduleId;\n            request.bypass = bypass;\n            request.workSource = workSource;\n            request.impersonation = impersonation;\n            return request;\n        }\n\n        @NonNull\n        @PublicApi(exclude = true)\n        @RequiresPermission(anyOf = {\"android.permission.WRITE_SECURE_SETTINGS\", \"android.permission.LOCATION_BYPASS\"})\n        public Builder setBypass(boolean bypass) {\n            this.bypass = bypass;\n            return this;\n        }\n\n        /**\n         * Sets the duration of this request. A location request will not receive any locations after it has expired, and will be\n         * removed shortly thereafter. A value of {@link Long#MAX_VALUE} implies an infinite duration.\n         * <p>\n         * The default value is {@link Long#MAX_VALUE}.\n         */\n        @NonNull\n        public Builder setDurationMillis(long durationMillis) {\n            if (durationMillis <= 0) throw new IllegalArgumentException(\"intervalMillis must be greater than 0\");\n            this.durationMillis = durationMillis;\n            return this;\n        }\n\n        /**\n         * Sets the {@link Granularity} of locations returned for this request. This controls whether fine or coarse locations may be\n         * returned.\n         * <p>\n         * The default value is {@link Granularity#GRANULARITY_PERMISSION_LEVEL}.\n         */\n        @NonNull\n        public Builder setGranularity(@Granularity int granularity) {\n            GranularityUtil.checkValidGranularity(granularity);\n            this.granularity = granularity;\n            return this;\n        }\n\n        /**\n         * Sets the desired interval of location updates. Location updates may arrive faster than this interval (but no faster than\n         * specified by {@link #setMinUpdateIntervalMillis(long)}) or slower than this interval (if the request is being throttled for\n         * example).\n         */\n        @NonNull\n        public Builder setIntervalMillis(long intervalMillis) {\n            if (intervalMillis < 0) throw new IllegalArgumentException(\"intervalMillis must be greater than or equal to 0\");\n            this.intervalMillis = intervalMillis;\n            return this;\n        }\n\n        /**\n         * Sets the maximum age of an initial historical location delivered for this request. A value of 0 indicates that no initial\n         * historical location will be delivered, only freshly derived locations. A value {@link Long#MAX_VALUE} represents an effectively\n         * unbounded maximum age.\n         * <p>\n         * This may be set to the special value {@link #IMPLICIT_MAX_UPDATE_AGE} in which case the maximum update age will always be\n         * the same as the interval.\n         * <p>\n         * The default value is {@link #IMPLICIT_MAX_UPDATE_AGE}.\n         */\n        @NonNull\n        public Builder setMaxUpdateAgeMillis(long maxUpdateAgeMillis) {\n            if (maxUpdateAgeMillis < 0 && maxUpdateAgeMillis != IMPLICIT_MAX_UPDATE_AGE)\n                throw new IllegalArgumentException(\"maxUpdateAgeMillis must be greater than or equal to 0, or IMPLICIT_MAX_UPDATE_AGE\");\n            this.maxUpdateAgeMillis = maxUpdateAgeMillis;\n            return this;\n        }\n\n        /**\n         * Sets the longest a location update may be delayed. This parameter controls location batching behavior. If this is set to a\n         * value at least 2x larger than the interval specified by {@link #setIntervalMillis(long)}, then a device may (but is not required\n         * to) save power by delivering locations in batches. If clients do not require immediate delivery, consider setting this value\n         * as high as is reasonable to allow for additional power savings. When the {@link LocationRequest} is built, the maximum\n         * update delay will be set to the max of the provided maximum update delay and the interval. This normalizes requests\n         * without batching to have the maximum update delay equal to the interval.\n         * <p>\n         * For example, if a request is made with a 2s interval and a 10s maximum update delay, this implies that the device may\n         * choose to deliver batches of 5 locations every 10s (where each location in a batch represents a point in time ~2s after\n         * the previous).\n         * <p>\n         * Support for batching may vary by device hardware, so simply allowing batching via this parameter does not imply a client\n         * will receive batched results on all devices.\n         * <p>\n         * {@link FusedLocationProviderClient#flushLocations()} may be used to flush locations that have been batched, but not\n         * delivered yet.\n         * <p>\n         * The default value is 0.\n         */\n        @NonNull\n        public Builder setMaxUpdateDelayMillis(long maxUpdateDelayMillis) {\n            if (maxUpdateDelayMillis < 0) throw new IllegalArgumentException(\"maxUpdateDelayMillis must be greater than or equal to 0\");\n            this.maxUpdateDelayMillis = maxUpdateDelayMillis;\n            return this;\n        }\n\n        /**\n         * Sets the maximum number of updates delivered to this request. A location request will not receive any locations after the\n         * maximum number of updates has been reached, and will be removed shortly thereafter. A value of {@link Integer#MAX_VALUE}\n         * implies an unlimited number of updates.\n         * <p>\n         * The default value is {@link Integer#MAX_VALUE}.\n         */\n        @NonNull\n        public Builder setMaxUpdates(int maxUpdates) {\n            if (maxUpdates <= 0) throw new IllegalArgumentException(\"maxUpdates must be greater than 0\");\n            this.maxUpdates = maxUpdates;\n            return this;\n        }\n\n        /**\n         * Sets the minimum distance required between consecutive location updates. If a derived location update is not at least\n         * the specified distance away from the previous location update delivered to the client, it will not be delivered. This may\n         * also allow additional power savings under some circumstances.\n         * <p>\n         * The default value is 0.\n         */\n        @NonNull\n        public Builder setMinUpdateDistanceMeters(float minUpdateDistanceMeters) {\n            if (minUpdateDistanceMeters < 0) throw new IllegalArgumentException(\"minUpdateDistanceMeters must be greater than or equal to 0\");\n            this.minUpdateDistanceMeters = minUpdateDistanceMeters;\n            return this;\n        }\n\n        /**\n         * Sets the fastest allowed interval of location updates. Location updates may arrive faster than the desired interval\n         * ({@link #setIntervalMillis(long)}), but will never arrive faster than specified here.\n         * <p>\n         * This may be set to the special value {@link #IMPLICIT_MIN_UPDATE_INTERVAL} in which case the minimum update interval will\n         * be the same as the interval. {@link FusedLocationProviderClient} APIs make some allowance for jitter with the minimum\n         * update interval, so clients need not worry about location updates that arrive a couple milliseconds too early being\n         * rejected.\n         * <p>\n         * The default value is {@link #IMPLICIT_MIN_UPDATE_INTERVAL}.\n         */\n        @NonNull\n        public Builder setMinUpdateIntervalMillis(long minUpdateIntervalMillis) {\n            if (minUpdateIntervalMillis < 0 && minUpdateIntervalMillis != IMPLICIT_MIN_UPDATE_INTERVAL)\n                throw new IllegalArgumentException(\"minUpdateIntervalMillis must be greater than or equal to 0, or IMPLICIT_MIN_UPDATE_INTERVAL\");\n            this.minUpdateIntervalMillis = minUpdateIntervalMillis;\n            return this;\n        }\n\n        @NonNull\n        @Deprecated\n        @PublicApi(exclude = true)\n        public Builder setModuleId(@Nullable String moduleId) {\n            this.moduleId = moduleId;\n            return this;\n        }\n\n        /**\n         * Sets the {@link Priority} of the location request.\n         * <p>\n         * The default value is {@link Priority#PRIORITY_BALANCED_POWER_ACCURACY}.\n         */\n        @NonNull\n        public Builder setPriority(@Priority int priority) {\n            PriorityUtil.checkValidPriority(priority);\n            this.priority = priority;\n            return this;\n        }\n\n        @NonNull\n        @PublicApi(exclude = true)\n        public Builder setThrottleBehavior(@ThrottleBehavior int throttleBehavior) {\n            ThrottleBehaviorUtil.checkValidThrottleBehavior(throttleBehavior);\n            this.throttleBehavior = throttleBehavior;\n            return this;\n        }\n\n        /**\n         * If set to true and this request is {@link Priority#PRIORITY_HIGH_ACCURACY}, this will delay delivery of initial low accuracy\n         * locations for a small amount of time in case a high accuracy location can be delivered instead.\n         * <p>\n         * The default value is true.\n         */\n        @NonNull\n        public Builder setWaitForAccurateLocation(boolean waitForAccurateLocation) {\n            this.waitForAccurateLocation = waitForAccurateLocation;\n            return this;\n        }\n\n        @NonNull\n        @PublicApi(exclude = true)\n        @RequiresPermission(Manifest.permission.UPDATE_DEVICE_STATS)\n        public Builder setWorkSource(@Nullable WorkSource workSource) {\n            this.workSource = workSource;\n            return this;\n        }\n    }\n\n\n    public static final Creator<LocationRequest> CREATOR = new AutoCreator<LocationRequest>(LocationRequest.class);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/LocationResult.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2015 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.location;\n\nimport android.content.Intent;\nimport android.location.Location;\n\nimport androidx.annotation.NonNull;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n@PublicApi\npublic class LocationResult extends AutoSafeParcelable {\n    @PublicApi(exclude = true)\n    public static final String EXTRA_LOCATION_RESULT = \"com.google.android.gms.location.EXTRA_LOCATION_RESULT\";\n\n    @Field(1000)\n    private int versionCode = 2;\n\n    @Field(value = 1, subClass = Location.class)\n    public final List<Location> locations;\n\n    private LocationResult() {\n        this.locations = new ArrayList<>();\n    }\n\n    private LocationResult(List<Location> locations) {\n        this.locations = locations;\n    }\n\n    /**\n     * Creates a {@link LocationResult} for the given locations.\n     */\n    public static LocationResult create(List<Location> locations) {\n        return new LocationResult(locations);\n    }\n\n    /**\n     * Extracts the {@link LocationResult} from an Intent.\n     * <p>\n     * This is a utility function which extracts the {@link LocationResult} from the extras of an Intent that was sent\n     * from the fused location provider.\n     *\n     * @return a {@link LocationResult}, or {@code null} if the Intent doesn't contain a result.\n     */\n    public static LocationResult extractResult(Intent intent) {\n        if (!hasResult(intent)) return null;\n        return intent.getExtras().getParcelable(EXTRA_LOCATION_RESULT);\n    }\n\n    /**\n     * Returns true if an Intent contains a {@link LocationResult}.\n     * <p>\n     * This is a utility function that can be called from inside an intent receiver to make sure the received intent is\n     * from the fused location provider.\n     *\n     * @return true if the intent contains a {@link LocationResult}, false otherwise.\n     */\n    public static boolean hasResult(Intent intent) {\n        if (intent == null) return false;\n        return intent.hasExtra(EXTRA_LOCATION_RESULT);\n    }\n\n    /**\n     * Returns the most recent location available in this result, or null if no locations are available.\n     */\n    public Location getLastLocation() {\n        if (locations.isEmpty()) return null;\n        return locations.get(locations.size() - 1);\n    }\n\n    /**\n     * Returns locations computed, ordered from oldest to newest.\n     * <p>\n     * No duplicate locations will be returned to any given listener (i.e. locations will not overlap in time between\n     * subsequent calls to a listener).\n     */\n    @NonNull\n    public List<Location> getLocations() {\n        return locations;\n    }\n\n    @Override\n    public String toString() {\n        return \"LocationResult[locations: \" + locations + \"]\";\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) return true;\n        if (!(obj instanceof LocationResult)) return false;\n\n        LocationResult that = (LocationResult) obj;\n        if (that.locations.size() != locations.size()) return false;\n        for (int i = 0; i < that.locations.size(); i++) {\n            if (that.locations.get(i).getTime() != locations.get(i).getTime()) return false;\n        }\n\n        return true;\n    }\n\n    @Override\n    public int hashCode() {\n        int result = 17;\n        for (Location location : locations) {\n            long time = location.getTime();\n            result = (result * 31) + ((int) (time ^ (time >>> 32)));\n        }\n        return result;\n    }\n\n    public static final Creator<LocationResult> CREATOR = new AutoCreator<LocationResult>(LocationResult.class);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/LocationServices.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2015 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.location;\n\nimport android.app.Activity;\nimport android.content.Context;\n\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.GoogleApiClient;\n\nimport org.microg.gms.location.FusedLocationProviderApiImpl;\nimport org.microg.gms.location.FusedLocationProviderClientImpl;\nimport org.microg.gms.location.GeofencingApiImpl;\nimport org.microg.gms.location.GeofencingClientImpl;\nimport org.microg.gms.location.LocationServicesApiClientBuilder;\nimport org.microg.gms.location.SettingsApiImpl;\nimport org.microg.gms.location.SettingsClientImpl;\n\n/**\n * The main entry point for location services integration.\n */\npublic class LocationServices {\n    /**\n     * Token to pass to {@link GoogleApiClient.Builder#addApi(Api)} to enable LocationServices.\n     *\n     * @deprecated Use {@link FusedLocationProviderClient} instead.\n     */\n    @Deprecated\n    public static final Api<Api.ApiOptions.NoOptions> API = new Api<Api.ApiOptions.NoOptions>(new LocationServicesApiClientBuilder());\n\n    /**\n     * Old entry point to the Fused Location Provider APIs.\n     *\n     * @deprecated Use {@link FusedLocationProviderClient} instead.\n     */\n    @Deprecated\n    public static final FusedLocationProviderApi FusedLocationApi = new FusedLocationProviderApiImpl();\n\n    /**\n     * Old entry point to the geofencing APIs.\n     *\n     * @deprecated Use {@link GeofencingClient} instead.\n     */\n    @Deprecated\n    public static final GeofencingApi GeofencingApi = new GeofencingApiImpl();\n\n    /**\n     * Old entry point to the location settings APIs.\n     *\n     * @deprecated Use {@link SettingsClient} instead.\n     */\n    @Deprecated\n    public static final SettingsApi SettingsApi = new SettingsApiImpl();\n\n    /**\n     * Create a new instance of {@link FusedLocationProviderClient} for use in an {@link Activity}.\n     * Error resolutions will be automatically launched from the provided Activity, displaying UI when necessary.\n     */\n    public static FusedLocationProviderClient getFusedLocationProviderClient(Activity activity) {\n        return new FusedLocationProviderClientImpl(activity);\n    }\n\n    /**\n     * Create a new instance of {@link FusedLocationProviderClient} for use in a non-activity {@link Context}.\n     * Error resolutions will be automatically launched from the provided Context, displaying system tray notifications\n     * when necessary.\n     */\n    public static FusedLocationProviderClient getFusedLocationProviderClient(Context context) {\n        return new FusedLocationProviderClientImpl(context);\n    }\n\n    /**\n     * Create a new instance of {@link GeofencingClient} for use in an {@link Activity}.\n     * Error resolutions will be automatically launched from the provided Activity, displaying UI when necessary.\n     */\n    public static GeofencingClient getGeofencingClient(Activity activity) {\n        return new GeofencingClientImpl(activity);\n    }\n\n    /**\n     * Create a new instance of {@link GeofencingClient} for use in a non-activity {@link Context}.\n     * Error resolutions will be automatically launched from the provided Context, displaying system tray notifications\n     * when necessary.\n     */\n    public static GeofencingClient getGeofencingClient(Context context) {\n        return new GeofencingClientImpl(context);\n    }\n\n    /**\n     * Create a new instance of {@link SettingsClient} for use in an {@link Activity}.\n     * Error resolutions will be automatically launched from the provided Activity, displaying UI when necessary.\n     */\n    public static SettingsClient getSettingsClient(Activity activity) {\n        return new SettingsClientImpl(activity);\n    }\n\n    /**\n     * Create a new instance of {@link SettingsClient} for use in a non-activity {@link Context}.\n     * Error resolutions will be automatically launched from the provided Context, displaying system tray notifications\n     * when necessary.\n     */\n    public static SettingsClient getSettingsClient(Context context) {\n        return new SettingsClientImpl(context);\n    }\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/LocationSettingsConfiguration.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.location;\n\nimport org.microg.gms.common.Hide;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n@Hide\npublic class LocationSettingsConfiguration extends AutoSafeParcelable {\n    @Field(1)\n    public String justificationText;\n    @Field(2)\n    public String experimentId;\n    @Field(5)\n    public String titleText;\n\n    public static final Creator<LocationSettingsConfiguration> CREATOR = new AutoCreator<>(LocationSettingsConfiguration.class);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/LocationSettingsRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2015 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.location;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.utils.ToStringHelper;\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\n\n/**\n * Specifies the types of location services the client is interested in using. Settings will be checked for optimal functionality\n * of all requested services. Use {@link LocationSettingsRequest.Builder} to construct this object.\n */\n@PublicApi\n@SafeParcelable.Class\npublic class LocationSettingsRequest extends AbstractSafeParcelable {\n    @Field(1000)\n    int versionCode = 2;\n\n    @Field(value = 1, subClass = LocationRequest.class)\n    @Hide\n    public final List<LocationRequest> requests;\n\n    @Field(2)\n    @Hide\n    public final boolean alwaysShow;\n\n    @Field(3)\n    @Hide\n    public final boolean needBle;\n\n    @Field(5)\n    @Hide\n    @Nullable\n    public final LocationSettingsConfiguration configuration;\n\n    @Constructor\n    LocationSettingsRequest(@Param(1) List<LocationRequest> requests, @Param(2) boolean alwaysShow, @Param(3) boolean needBle, @Param(5) @Nullable LocationSettingsConfiguration configuration) {\n        this.requests = requests;\n        this.alwaysShow = alwaysShow;\n        this.needBle = needBle;\n        this.configuration = configuration;\n    }\n\n    /**\n     * A builder that builds {@link LocationSettingsRequest}.\n     */\n    public static class Builder {\n        private List<LocationRequest> requests = new ArrayList<LocationRequest>();\n        private boolean alwaysShow = false;\n        private boolean needBle = false;\n\n        /**\n         * Adds a collection of {@link LocationRequest}s that the client is interested in. Settings\n         * will be checked for optimal performance of all {@link LocationRequest}s.\n         */\n        public Builder addAllLocationRequests(Collection<LocationRequest> requests) {\n            this.requests.addAll(requests);\n            return this;\n        }\n\n        /**\n         * Adds one {@link LocationRequest} that the client is interested in. Settings will be\n         * checked for optimal performance of all {@link LocationRequest}s.\n         */\n        public Builder addLocationRequest(LocationRequest request) {\n            requests.add(request);\n            return this;\n        }\n\n        /**\n         * Creates a LocationSettingsRequest that can be used with SettingsApi.\n         */\n        public LocationSettingsRequest build() {\n            return new LocationSettingsRequest(requests, alwaysShow, needBle, null);\n        }\n\n        /**\n         * Whether or not location is required by the calling app in order to continue. Set this to\n         * true if location is required to continue and false if having location provides better\n         * results, but is not required. This changes the wording/appearance of the dialog\n         * accordingly.\n         */\n        public Builder setAlwaysShow(boolean show) {\n            alwaysShow = show;\n            return this;\n        }\n\n        /**\n         * Sets whether the client wants BLE scan to be enabled. When this flag is set to true, if\n         * the platform supports BLE scan mode and Bluetooth is off, the dialog will prompt the\n         * user to enable BLE scan. If the platform doesn't support BLE scan mode, the dialog will\n         * prompt to enable Bluetooth.\n         */\n        public Builder setNeedBle(boolean needBle) {\n            this.needBle = needBle;\n            return this;\n        }\n    }\n\n    @Hide\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"LocationSettingsRequest\")\n                .value(requests)\n                .field(\"alwaysShow\", alwaysShow)\n                .field(\"needBle\", needBle)\n                .end();\n    }\n\n    public static final SafeParcelableCreatorAndWriter<LocationSettingsRequest> CREATOR = findCreator(LocationSettingsRequest.class);\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/LocationSettingsResponse.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.location;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.ResolvableApiException;\nimport com.google.android.gms.common.api.Response;\nimport com.google.android.gms.tasks.Task;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Successful response of checking settings via {@link SettingsApi#checkLocationSettings(GoogleApiClient, LocationSettingsRequest)}.\n * <p>\n * If a {@link Task} with this response type fails, it will receive a {@link ResolvableApiException} which may be able to resolve the failure.\n * See {@link SettingsClient} for more details.\n * <p>\n * The current location settings states can be accessed via {@link #getLocationSettingsStates()}. See {@link LocationSettingsStates} for more details.\n */\npublic class LocationSettingsResponse extends Response<LocationSettingsResult> {\n    /**\n     * Retrieves the location settings states.\n     */\n    @Nullable\n    public LocationSettingsStates getLocationSettingsStates() {\n        return getResult().getLocationSettingsStates();\n    }\n\n    @Hide\n    public LocationSettingsResponse(@NonNull LocationSettingsResult result) {\n        super(result);\n    }\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/LocationSettingsResult.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2015 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.location;\n\nimport android.app.Activity;\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.Result;\nimport com.google.android.gms.common.api.Status;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Result of checking settings via {@link SettingsApi#checkLocationSettings(GoogleApiClient, LocationSettingsRequest)},\n * indicates whether a dialog should be shown to ask the user's consent to change their\n * settings.\n * <p>\n * The method {@link #getStatus()} can be used to confirm if the request was successful. If the current location settings don't\n * satisfy the app's requirements and the user has permission to change the settings, the app could use\n * {@link Status#startResolutionForResult(Activity, int)} to start an intent to show a dialog, asking for user's consent to\n * change the settings.\n * <p>\n * The current location settings states can be accessed via {@link #getLocationSettingsStates()}. See\n * {@link LocationSettingsStates} for more details.\n */\n@PublicApi\n@SafeParcelable.Class\npublic class LocationSettingsResult extends AbstractSafeParcelable implements Result {\n\n    @Field(1000)\n    int versionCode = 1;\n\n    @Field(value = 1, getterName = \"getStatus\")\n    @NonNull\n    private final Status status;\n\n    @Field(value = 2, getterName = \"getLocationSettingsStates\")\n    @Nullable\n    private final LocationSettingsStates settings;\n\n\n    /**\n     * Retrieves the location settings states.\n     */\n    @Nullable\n    public LocationSettingsStates getLocationSettingsStates() {\n        return settings;\n    }\n\n    @Override\n    @NonNull\n    public Status getStatus() {\n        return status;\n    }\n\n    @Hide\n    @Constructor\n    public LocationSettingsResult(@Param(1) @NonNull Status status, @Param(2) @Nullable LocationSettingsStates settings) {\n        this.settings = settings;\n        this.status = status;\n    }\n\n    @Hide\n    public LocationSettingsResult(@NonNull Status status) {\n        this(status, null);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<LocationSettingsResult> CREATOR = findCreator(LocationSettingsResult.class);\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/LocationSettingsStates.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2015 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.location;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableSerializer;\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Stores the current states of all location-related settings.\n */\n@PublicApi\n@SafeParcelable.Class\npublic class LocationSettingsStates extends AbstractSafeParcelable {\n\n    @Field(1000)\n    int versionCode = 2;\n\n    @Field(value = 1, getterName = \"isGpsUsable\")\n    private final boolean gpsUsable;\n\n    @Field(value = 2, getterName = \"isNetworkLocationUsable\")\n    private final boolean networkLocationUsable;\n\n    @Field(value = 3, getterName = \"isBleUsable\")\n    private final boolean bleUsable;\n\n    @Field(value = 4, getterName = \"isGpsPresent\")\n    private final boolean gpsPresent;\n\n    @Field(value = 5, getterName = \"isNetworkLocationPresent\")\n    private final boolean networkLocationPresent;\n\n    @Field(value = 6, getterName = \"isBlePresent\")\n    private final boolean blePresent;\n\n    /**\n     * Whether BLE is present on the device.\n     */\n    public boolean isBlePresent() {\n        return blePresent;\n    }\n\n    /**\n     * Whether BLE is enabled and is usable by the app.\n     */\n    public boolean isBleUsable() {\n        return bleUsable;\n    }\n\n    /**\n     * Whether GPS provider is present on the device.\n     */\n    public boolean isGpsPresent() {\n        return gpsPresent;\n    }\n\n    /**\n     * Whether GPS provider is enabled and is usable by the app.\n     */\n    public boolean isGpsUsable() {\n        return gpsUsable;\n    }\n\n    /**\n     * Whether location is present on the device.\n     * <p>\n     * This method returns true when either GPS or network location provider is present.\n     */\n    public boolean isLocationPresent() {\n        return isGpsPresent() || isNetworkLocationPresent();\n    }\n\n    /**\n     * Whether location is enabled and is usable by the app.\n     * <p>\n     * This method returns true when either GPS or network location provider is usable.\n     */\n    public boolean isLocationUsable() {\n        return isGpsUsable() || isNetworkLocationUsable();\n    }\n\n    /**\n     * Whether network location provider is present on the device.\n     */\n    public boolean isNetworkLocationPresent() {\n        return networkLocationPresent;\n    }\n\n    /**\n     * Whether network location provider is enabled and usable by the app.\n     */\n    public boolean isNetworkLocationUsable() {\n        return networkLocationUsable;\n    }\n\n    @Constructor\n    public LocationSettingsStates(@Param(1) boolean gpsUsable, @Param(2) boolean networkLocationUsable, @Param(3) boolean bleUsable, @Param(4) boolean gpsPresent, @Param(5) boolean networkLocationPresent, @Param(6) boolean blePresent) {\n        this.gpsUsable = gpsUsable;\n        this.networkLocationUsable = networkLocationUsable;\n        this.bleUsable = bleUsable;\n        this.gpsPresent = gpsPresent;\n        this.networkLocationPresent = networkLocationPresent;\n        this.blePresent = blePresent;\n    }\n\n    /**\n     * Retrieves the location settings states from the intent extras. When the location settings dialog finishes, you can use this\n     * method to retrieve the current location settings states from the intent in your\n     * {@link Activity#onActivityResult(int, int, Intent)}.\n     */\n    public static LocationSettingsStates fromIntent(Intent intent) {\n        byte[] bytes = intent.getByteArrayExtra(EXTRA_NAME);\n        if (bytes == null) return null;\n        return SafeParcelableSerializer.deserializeFromBytes(bytes, CREATOR);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<LocationSettingsStates> CREATOR = findCreator(LocationSettingsStates.class);\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    private static final String EXTRA_NAME = \"com.google.android.gms.location.LOCATION_SETTINGS_STATES\";\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/LocationSettingsStatusCodes.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2017 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.location;\n\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.api.CommonStatusCodes;\nimport com.google.android.gms.common.api.Status;\n\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Location settings specific status codes, for use in {@link Status#getStatusCode()}\n */\n@PublicApi\npublic class LocationSettingsStatusCodes extends CommonStatusCodes {\n    /**\n     * Location settings can't be changed to meet the requirements, no dialog pops up\n     */\n    public static final int SETTINGS_CHANGE_UNAVAILABLE = 8502;\n\n    @NonNull\n    @Hide\n    public static String getStatusCodeString(int statusCode) {\n        switch (statusCode) {\n            case SETTINGS_CHANGE_UNAVAILABLE:\n                return \"SETTINGS_CHANGE_UNAVAILABLE\";\n            case 8500:\n            case 8501:\n            case 8503:\n            case 8505:\n                return \"INTERNAL_LOCATION_SETTINGS_STATUS_CODE\";\n            default:\n                return CommonStatusCodes.getStatusCodeString(statusCode);\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/LocationStatus.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.location;\n\nimport org.microg.gms.common.Hide;\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\nimport java.util.Arrays;\n\n@Hide\npublic class LocationStatus extends AutoSafeParcelable {\n    public static final int STATUS_SUCCESSFUL = 0;\n    public static final int STATUS_UNKNOWN = 1;\n    public static final int STATUS_TIMED_OUT_ON_SCAN = 2;\n    public static final int STATUS_NO_INFO_IN_DATABASE = 3;\n    public static final int STATUS_INVALID_SCAN = 4;\n    public static final int STATUS_UNABLE_TO_QUERY_DATABASE = 5;\n    public static final int STATUS_SCANS_DISABLED_IN_SETTINGS = 6;\n    public static final int STATUS_LOCATION_DISABLED_IN_SETTINGS = 7;\n    public static final int STATUS_IN_PROGRESS = 8;\n    @SafeParceled(1000)\n    private int versionCode = 1;\n    @SafeParceled(1)\n    int cellStatus;\n    @SafeParceled(2)\n    int wifiStatus;\n    @SafeParceled(3)\n    long elapsedRealtimeNanos;\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o)\n            return true;\n        if (o == null || getClass() != o.getClass())\n            return false;\n\n        LocationStatus that = (LocationStatus) o;\n\n        if (cellStatus != that.cellStatus)\n            return false;\n        if (elapsedRealtimeNanos != that.elapsedRealtimeNanos)\n            return false;\n        if (wifiStatus != that.wifiStatus)\n            return false;\n\n        return true;\n    }\n\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(new Object[] { cellStatus, wifiStatus, elapsedRealtimeNanos });\n    }\n\n    private String statusToString(int status) {\n        switch (status) {\n            case STATUS_SUCCESSFUL:\n                return \"STATUS_SUCCESSFUL\";\n            case STATUS_UNKNOWN:\n            default:\n                return \"STATUS_UNKNOWN\";\n            case STATUS_TIMED_OUT_ON_SCAN:\n                return \"STATUS_TIMED_OUT_ON_SCAN\";\n            case STATUS_NO_INFO_IN_DATABASE:\n                return \"STATUS_NO_INFO_IN_DATABASE\";\n            case STATUS_INVALID_SCAN:\n                return \"STATUS_INVALID_SCAN\";\n            case STATUS_UNABLE_TO_QUERY_DATABASE:\n                return \"STATUS_UNABLE_TO_QUERY_DATABASE\";\n            case STATUS_SCANS_DISABLED_IN_SETTINGS:\n                return \"STATUS_SCANS_DISABLED_IN_SETTINGS\";\n            case STATUS_LOCATION_DISABLED_IN_SETTINGS:\n                return \"STATUS_LOCATION_DISABLED_IN_SETTINGS\";\n            case STATUS_IN_PROGRESS:\n                return \"STATUS_IN_PROGRESS\";\n        }\n    }\n\n    public static final Creator<LocationStatus> CREATOR = new AutoCreator<LocationStatus>(LocationStatus.class);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/LocationStatusCodes.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2017 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.location;\n\nimport android.app.PendingIntent;\n\n/**\n * Status codes that can be returned to listeners to indicate the success or failure of an operation.\n * @deprecated Use {@link GeofenceStatusCodes}\n */\n@Deprecated\npublic class LocationStatusCodes {\n    /**\n     * The operation was successful.\n     */\n    public static final int SUCCESS = 0;\n    /**\n     * An unspecified error occurred; no more specific information is available. The device logs may provide additional\n     * data.\n     */\n    public static final int ERROR = 1;\n    /**\n     * Geofence service is not available now. Typically this is because the user turned off location access in\n     * settings > location access.\n     */\n    public static final int GEOFENCE_NOT_AVAILABLE = 1000;\n    /**\n     * Your app has registered more than 100 geofences. Remove unused ones before adding new geofences.\n     */\n    public static final int GEOFENCE_TOO_MANY_GEOFENCES = 1001;\n    /**\n     * You have provided more than 5 different PendingIntents to the {@link GeofencingApi#addGeofences(com.google.android.gms.common.api.GoogleApiClient, GeofencingRequest, PendingIntent)} call.\n     */\n    public static final int GEOFENCE_TOO_MANY_PENDING_INTENTS = 1002;\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/NetworkLocationStatus.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.location;\n\nimport org.microg.gms.common.Hide;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n@Hide\npublic class NetworkLocationStatus extends AutoSafeParcelable {\n    @Field(1)\n    public int wifiStatus;\n    @Field(2)\n    public int cellStatus;\n    @Field(3)\n    public long systemTimeMs;\n    @Field(4)\n    public long elapsedRealtimeNs;\n\n    public NetworkLocationStatus() {\n    }\n\n    public NetworkLocationStatus(int wifiStatus, int cellStatus, long systemTimeMs, long elapsedRealtimeNs) {\n        this.wifiStatus = wifiStatus;\n        this.cellStatus = cellStatus;\n        this.systemTimeMs = systemTimeMs;\n        this.elapsedRealtimeNs = elapsedRealtimeNs;\n    }\n\n    public static final Creator<NetworkLocationStatus> CREATOR = new AutoCreator<>(NetworkLocationStatus.class);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/Priority.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.location;\n\nimport androidx.annotation.IntDef;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Location power vs accuracy priority levels to be used with APIs within {@link FusedLocationProviderClient}.\n * <p>\n * Priority values have been intentionally chosen to match the framework QUALITY constants, and the values are specified\n * such that higher priorities should always have lower values and vice versa.\n */\n@Target({ElementType.TYPE_USE})\n@Retention(RetentionPolicy.SOURCE)\n@IntDef({Priority.PRIORITY_HIGH_ACCURACY, Priority.PRIORITY_BALANCED_POWER_ACCURACY, Priority.PRIORITY_LOW_POWER, Priority.PRIORITY_PASSIVE})\npublic @interface Priority {\n    /**\n     * Requests a tradeoff that favors highly accurate locations at the possible expense of additional power usage.\n     */\n    int PRIORITY_HIGH_ACCURACY = 100;\n\n    /**\n     * Requests a tradeoff that is balanced between location accuracy and power usage.\n     */\n    int PRIORITY_BALANCED_POWER_ACCURACY = 102;\n\n    /**\n     * Requests a tradeoff that favors low power usage at the possible expense of location accuracy.\n     */\n    int PRIORITY_LOW_POWER = 104;\n\n    /**\n     * Ensures that no extra power will be used to derive locations. This enforces that the request will act as a passive listener\n     * that will only receive \"free\" locations calculated on behalf of other clients, and no locations will be calculated on behalf of\n     * only this request.\n     */\n    int PRIORITY_PASSIVE = 105;\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/SettingsApi.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2017 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.location;\n\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.PendingResult;\n\n/**\n * The main entry point for interacting with the location settings-enabler APIs.\n * <p>\n * This API makes it easy for an app to ensure that the device's system settings are properly\n * configured for the app's location needs.\n *\n * @deprecated Use GoogleApi-based API {@link SettingsClient} instead.\n */\n@Deprecated\npublic interface SettingsApi {\n    /**\n     * Checks if the relevant system settings are enabled on the device to carry out the desired\n     * location requests.\n     *\n     * @param client                  an existing GoogleApiClient. It does not need to be connected\n     *                                at the time of this call, but the result will be delayed until\n     *                                the connection is complete.\n     * @param locationSettingsRequest an object that contains all the location requirements that the\n     *                                client is interested in.\n     * @return result containing the status of the request.\n     */\n    PendingResult<LocationSettingsResult> checkLocationSettings(GoogleApiClient client, LocationSettingsRequest locationSettingsRequest);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/SettingsClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.location;\n\nimport android.location.LocationManager;\nimport android.provider.Settings;\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.HasApiKey;\nimport com.google.android.gms.tasks.Task;\n\n/**\n * The main entry point for interacting with the location settings-enabler APIs.\n * <p>\n * This API makes it easy for an app to ensure that the device's system settings are properly configured for the app's\n * location needs.\n */\npublic interface SettingsClient extends HasApiKey<Api.ApiOptions.NoOptions> {\n    /**\n     * Checks if the relevant system settings are enabled on the device to carry out the desired location requests.\n     *\n     * @param locationSettingsRequest an object that contains all the location requirements that the client is interested in.\n     */\n    Task<LocationSettingsResponse> checkLocationSettings(LocationSettingsRequest locationSettingsRequest);\n\n    /**\n     * Returns true if the Google Location Accuracy setting is currently enabled. This setting is required for Fused Location\n     * Provider APIs to be able to generate network (wifi, cell, etc) based locations. If Google Play services is chosen as the\n     * platform {@link LocationManager#NETWORK_PROVIDER} (this is the case on all GMS compliant devices, which constitute the\n     * vast majority of the Android ecosystem), then this setting is also required for the platform\n     * {@link LocationManager#NETWORK_PROVIDER} to be enabled.\n     * <p>\n     * On Android P and above devices, the Google Location Accuracy setting may be found under location settings. Below\n     * Android P, Google Location Accuracy is tied to the device location mode - it will be enabled if the device is in\n     * {@link Settings.Secure#LOCATION_MODE_BATTERY_SAVING} or {@link Settings.Secure#LOCATION_MODE_HIGH_ACCURACY}, and\n     * disabled in {@link Settings.Secure#LOCATION_MODE_SENSORS_ONLY}.\n     */\n    Task<Boolean> isGoogleLocationAccuracyEnabled();\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/SleepClassifyEvent.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.location;\n\nimport android.content.Intent;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\nimport java.util.List;\n\n/**\n * Represents a sleep classification event including the classification timestamp, the sleep confidence, and the\n * supporting data such as device motion and ambient light level. Classification events are reported at a regular\n * intervals, such as every 10 minutes.\n */\npublic class SleepClassifyEvent extends AutoSafeParcelable {\n    public static final Creator<SleepClassifyEvent> CREATOR = new AutoCreator<>(SleepClassifyEvent.class);\n\n    /**\n     * Extracts the {@code SleepClassifyEvent} from an {@code Intent}.\n     *\n     * @param intent the {@code Intent} to extract from\n     * @return a list of {@link SleepClassifyEvent}s if the intent has events, or an empty list if the intent doesn't\n     * contain any events.\n     */\n    public static List<SleepClassifyEvent> extractEvents(Intent intent) {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Returns a sleep confidence value between 0 and 100. Higher values indicate that the user is more likely sleeping,\n     * while lower values indicate that the user is more likely awake.\n     */\n    public int getConfidence() {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Returns the brightness of the space around the device, based on the device's ambient light sensor readings. Value\n     * ranges from 1 to 6, inclusive. Higher values indicate brighter surroundings, while lower values indicate darker\n     * surroundings.\n     */\n    public int getLight() {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Returns the amount of device motion, based on the device's accelerometer readings. Value ranges from 1 to 6,\n     * inclusive. Higher values indicate more movement of the device.\n     */\n    public int getMotion() {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Returns the UNIX epoch time when the event happened, expressed as the number of milliseconds since 1/1/1970 UTC.\n     */\n    public long getTimestampMillis() {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Checks whether the {@code Intent} has any {@code SleepClassifyEvent}.\n     *\n     * @param intent the {@code Intent} to extract from\n     * @return true if the Intent has events\n     */\n    public static boolean hasEvents(Intent intent) {\n        throw new UnsupportedOperationException();\n    }\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/SleepSegmentEvent.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.location;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n/**\n * Represents the result of segmenting sleep after the user is awake.\n */\npublic class SleepSegmentEvent extends AutoSafeParcelable {\n    /**\n     * Successfully detected sleep segment in the past day.\n     */\n    public static final int STATUS_SUCCESSFUL = 0;\n    /**\n     * Sleep segment was detected, but there was some missing data near the detected sleep segment. This could happen\n     * for a variety of reasons, including the following: the user turned off their device, the user delayed logging\n     * into their device after a system reboot or system upgrade, or an event occurred that paused the detection.\n     */\n    public static final int STATUS_MISSING_DATA = 1;\n    /**\n     * Sleep segment is not detected in the past day, or there isn't enough confidence that the user slept during the\n     * past day. This could happen for a variety of reasons, including the following: too much missing data, the user\n     * sleeps with the light, the user interacts with their device often, or the user's device doesn't support the\n     * sensors needed for sleep detection.\n     */\n    public static final int STATUS_NOT_DETECTED = 2;\n\n    public static final Creator<SleepSegmentEvent> CREATOR = new AutoCreator<>(SleepSegmentEvent.class);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/SleepSegmentRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.location;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n/**\n * A request object that specifies what data to receive from the Sleep API. Defaults to {@code SEGMENT_AND_CLASSIFY_EVENTS}.\n */\npublic class SleepSegmentRequest extends AutoSafeParcelable {\n    /**\n     * Requests both the {@code SleepSegmentEvent} and the {@code SleepClassifyEvent}.\n     */\n    public static final int SEGMENT_AND_CLASSIFY_EVENTS = 0;\n    /**\n     * Requests {@code SleepSegmentEvent} only.\n     */\n    public static final int SEGMENT_EVENTS_ONLY = 1;\n    /**\n     * Requests {@code SleepClassifyEvent} only.\n     */\n    public static final int CLASSIFY_EVENTS_ONLY = 2;\n\n    public static final Creator<SleepSegmentRequest> CREATOR = new AutoCreator<>(SleepSegmentRequest.class);\n\n    @Field(2)\n    private int requestedDataType;\n\n    private SleepSegmentRequest() {\n\n    }\n\n    /**\n     * Constructs a {@link SleepSegmentRequest} indicating what type of data is being requested.\n     *\n     * @param requestedDataType The type of data to receive pending intents for; valid values are\n     *                          {@link #SEGMENT_AND_CLASSIFY_EVENTS}, {@link #SEGMENT_EVENTS_ONLY}, and {@link #CLASSIFY_EVENTS_ONLY}.\n     */\n    public SleepSegmentRequest(int requestedDataType) {\n        this.requestedDataType = requestedDataType;\n    }\n\n    public boolean equals(Object o) {\n        return o instanceof SleepSegmentRequest && ((SleepSegmentRequest) o).requestedDataType == requestedDataType;\n    }\n\n    /**\n     * Creates a default request that registers for both {@code SleepSegmentEvent} and {@code SleepClassifyEvent} data.\n     */\n    public static SleepSegmentRequest getDefaultSleepSegmentRequest() {\n        return new SleepSegmentRequest(SEGMENT_AND_CLASSIFY_EVENTS);\n    }\n\n    /**\n     * Returns the requested data type, which is one of {@link #SEGMENT_AND_CLASSIFY_EVENTS}, {@link #SEGMENT_EVENTS_ONLY},\n     * or {@link #CLASSIFY_EVENTS_ONLY}.\n     */\n    public int getRequestedDataType() {\n        return requestedDataType;\n    }\n\n    @Override\n    public int hashCode() {\n        return requestedDataType;\n    }\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/ThrottleBehavior.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.location;\n\nimport androidx.annotation.IntDef;\nimport org.microg.gms.common.Hide;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Target({ElementType.TYPE_USE})\n@Retention(RetentionPolicy.SOURCE)\n@IntDef({ThrottleBehavior.THROTTLE_BACKGROUND, ThrottleBehavior.THROTTLE_ALWAYS, ThrottleBehavior.THROTTLE_NEVER})\n@Hide\npublic @interface ThrottleBehavior {\n    int THROTTLE_BACKGROUND = 0;\n    int THROTTLE_ALWAYS = 1;\n    int THROTTLE_NEVER = 2;\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/internal/ClientIdentity.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.location.internal;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.Feature;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.utils.ToStringHelper;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Objects;\n\n@Hide\npublic class ClientIdentity extends AutoSafeParcelable {\n    @Field(1)\n    public int uid;\n    @Field(2)\n    public int pid;\n    @Field(3)\n    public String packageName;\n    @Field(4)\n    @Nullable\n    public String attributionTag;\n    @Field(5)\n    public int clientSdkVersion;\n    @Field(6)\n    @Nullable\n    public String listenerId;\n    @Field(7)\n    @Nullable\n    public ClientIdentity impersonator;\n    @Field(8)\n    public List<Feature> clientFeatures = Collections.emptyList();\n\n    private ClientIdentity() {}\n\n    public ClientIdentity(String packageName) {\n        this.packageName = packageName;\n    }\n\n    @Override\n    public final boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof ClientIdentity)) return false;\n\n        ClientIdentity that = (ClientIdentity) o;\n        return uid == that.uid && pid == that.pid && clientSdkVersion == that.clientSdkVersion && Objects.equals(packageName, that.packageName) && Objects.equals(attributionTag, that.attributionTag) && Objects.equals(listenerId, that.listenerId) && Objects.equals(impersonator, that.impersonator) && Objects.equals(clientFeatures, that.clientFeatures);\n    }\n\n    @Override\n    public int hashCode() {\n        int result = uid;\n        result = 31 * result + pid;\n        result = 31 * result + Objects.hashCode(packageName);\n        result = 31 * result + Objects.hashCode(attributionTag);\n        result = 31 * result + clientSdkVersion;\n        result = 31 * result + Objects.hashCode(listenerId);\n        result = 31 * result + Objects.hashCode(impersonator);\n        result = 31 * result + Objects.hashCode(clientFeatures);\n        return result;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"ClientIdentity\").value(uid).value(packageName).end();\n    }\n\n    public static final Creator<ClientIdentity> CREATOR = new AutoCreator<>(ClientIdentity.class);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/internal/DeviceOrientationRequestInternal.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.location.internal;\n\nimport com.google.android.gms.common.internal.ClientIdentity;\nimport com.google.android.gms.location.DeviceOrientationRequest;\n\nimport org.microg.gms.common.Hide;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\nimport java.util.List;\n\n@Hide\npublic class DeviceOrientationRequestInternal extends AutoSafeParcelable {\n\n    @Field(1)\n    public DeviceOrientationRequest request;\n\n    @Field(value = 2, subClass = ClientIdentity.class)\n    public List<ClientIdentity> clients;\n\n    @Field(3)\n    public String tag;\n\n    @Override\n    public String toString() {\n        return \"DeviceOrientationRequestInternal{\" +\n                \"request=\" + request +\n                \", clients=\" + clients +\n                \", tag='\" + tag + '\\'' +\n                '}';\n    }\n\n    public static final Creator<DeviceOrientationRequestInternal> CREATOR = new AutoCreator<DeviceOrientationRequestInternal>(DeviceOrientationRequestInternal.class);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/internal/DeviceOrientationRequestUpdateData.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.location.internal;\n\nimport com.google.android.gms.location.IDeviceOrientationListener;\n\nimport org.microg.gms.common.Hide;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n@Hide\npublic class DeviceOrientationRequestUpdateData extends AutoSafeParcelable {\n    public static final int REQUEST_UPDATES = 1;\n    public static final int REMOVE_UPDATES = 2;\n\n    @Field(1)\n    public int opCode;\n\n    @Field(2)\n    public DeviceOrientationRequestInternal request;\n\n    @Field(3)\n    public IDeviceOrientationListener listener;\n\n    @Field(4)\n    public IFusedLocationProviderCallback fusedLocationProviderCallback;\n\n    @Override\n    public String toString() {\n        return \"DeviceOrientationRequestUpdateData{\" +\n                \"opCode=\" + opCode +\n                \", request=\" + request +\n                \", listener=\" + (listener != null ? listener.asBinder() : null) +\n                \", fusedLocationProviderCallback=\" + (fusedLocationProviderCallback != null ? fusedLocationProviderCallback.asBinder() : null) +\n                '}';\n    }\n\n    public static final Creator<DeviceOrientationRequestUpdateData> CREATOR = new AutoCreator<DeviceOrientationRequestUpdateData>(DeviceOrientationRequestUpdateData.class);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/internal/FusedLocationProviderResult.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.location.internal;\n\nimport com.google.android.gms.common.api.Status;\n\nimport org.microg.gms.common.Hide;\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\n@Hide\npublic class FusedLocationProviderResult extends AutoSafeParcelable {\n    public static final FusedLocationProviderResult SUCCESS = FusedLocationProviderResult.create(Status.SUCCESS);\n\n    @SafeParceled(1000)\n    private int versionCode = 1;\n\n    @SafeParceled(1)\n    public Status status;\n\n    public static FusedLocationProviderResult create(Status status) {\n        FusedLocationProviderResult result = new FusedLocationProviderResult();\n        result.status = status;\n        return result;\n    }\n\n    public static final Creator<FusedLocationProviderResult> CREATOR = new AutoCreator<FusedLocationProviderResult>(FusedLocationProviderResult.class);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/internal/LocationReceiver.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.location.internal;\n\nimport android.app.PendingIntent;\nimport android.os.IBinder;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.location.ILocationCallback;\nimport com.google.android.gms.location.ILocationListener;\nimport org.microg.gms.common.Hide;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n@Hide\npublic class LocationReceiver extends AutoSafeParcelable {\n    public static final int TYPE_LISTENER = 1;\n    public static final int TYPE_CALLBACK = 2;\n    public static final int TYPE_PENDING_INTENT = 3;\n    public static final int TYPE_STATUS_CALLBACK = 4;\n    public static final int TYPE_AVAILABILITY_STATUS_CALLBACK = 5;\n\n    @Field(1)\n    public int type;\n    @Field(2)\n    @Nullable\n    public IBinder oldBinderReceiver;\n    @Field(3)\n    @Nullable\n    public IBinder binderReceiver;\n    @Field(4)\n    @Nullable\n    public PendingIntent pendingIntentReceiver;\n    @Field(5)\n    @Nullable\n    public String moduleId;\n    @Field(6)\n    @Nullable\n    public String listenerId;\n\n    private LocationReceiver() {\n    }\n\n    public LocationReceiver(@NonNull ILocationListener listener) {\n        this(listener, null);\n    }\n\n    public LocationReceiver(@NonNull ILocationListener listener, @Nullable String listenerId) {\n        type = TYPE_LISTENER;\n        binderReceiver = listener.asBinder();\n        this.listenerId = listenerId;\n    }\n\n    public LocationReceiver(@NonNull ILocationCallback callback) {\n        this(callback, null);\n    }\n\n    public LocationReceiver(@NonNull ILocationCallback callback, @Nullable String listenerId) {\n        type = TYPE_CALLBACK;\n        binderReceiver = callback.asBinder();\n        this.listenerId = listenerId;\n    }\n\n    public LocationReceiver(@NonNull PendingIntent pendingIntent) {\n        this(pendingIntent, null);\n    }\n\n    public LocationReceiver(@NonNull PendingIntent pendingIntent, @Nullable String listenerId) {\n        type = TYPE_PENDING_INTENT;\n        pendingIntentReceiver = pendingIntent;\n        this.listenerId = listenerId;\n    }\n\n    public LocationReceiver(@NonNull ILocationStatusCallback callback) {\n        this(callback, null);\n    }\n\n    public LocationReceiver(@NonNull ILocationStatusCallback callback, @Nullable String listenerId) {\n        type = TYPE_STATUS_CALLBACK;\n        binderReceiver = callback.asBinder();\n        this.listenerId = listenerId;\n    }\n\n    public LocationReceiver(@NonNull ILocationAvailabilityStatusCallback callback) {\n        type = TYPE_AVAILABILITY_STATUS_CALLBACK;\n        binderReceiver = callback.asBinder();\n    }\n\n    public ILocationListener getListener() {\n        if (type != TYPE_LISTENER) throw new IllegalStateException();\n        return ILocationListener.Stub.asInterface(binderReceiver);\n    }\n\n    public ILocationCallback getCallback() {\n        if (type != TYPE_CALLBACK) throw new IllegalStateException();\n        return ILocationCallback.Stub.asInterface(binderReceiver);\n    }\n\n    public ILocationStatusCallback getStatusCallback() {\n        if (type != TYPE_STATUS_CALLBACK) throw new IllegalStateException();\n        return ILocationStatusCallback.Stub.asInterface(binderReceiver);\n    }\n\n    public ILocationAvailabilityStatusCallback getAvailabilityStatusCallback() {\n        if (type != TYPE_AVAILABILITY_STATUS_CALLBACK) throw new IllegalStateException();\n        return ILocationAvailabilityStatusCallback.Stub.asInterface(binderReceiver);\n    }\n\n    public static final Creator<LocationReceiver> CREATOR = new AutoCreator<>(LocationReceiver.class);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/internal/LocationRequestInternal.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.location.internal;\n\nimport android.annotation.SuppressLint;\nimport android.os.WorkSource;\nimport com.google.android.gms.common.internal.ClientIdentity;\nimport com.google.android.gms.location.Granularity;\nimport com.google.android.gms.location.LocationRequest;\n\nimport com.google.android.gms.location.ThrottleBehavior;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.utils.WorkSourceUtil;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\nimport java.util.List;\n\n@Hide\npublic class LocationRequestInternal extends AutoSafeParcelable {\n\n    @Field(1000)\n    private int versionCode = 1;\n\n    @Field(1)\n    private LocationRequest request;\n\n    @Field(2)\n    @Deprecated\n    public boolean requestNlpDebugInfo;\n\n    @Field(3)\n    @Deprecated\n    public boolean restorePendingIntentListeners;\n\n    @Field(4)\n    @Deprecated\n    public boolean triggerUpdate;\n\n    @Field(value = 5, subClass = ClientIdentity.class)\n    @Deprecated\n    public List<ClientIdentity> clients;\n\n    @Field(6)\n    @Deprecated\n    public String tag;\n\n    @Field(7)\n    @Deprecated\n    public boolean hideFromAppOps;\n\n    @Field(8)\n    @Deprecated\n    public boolean forceCoarseLocation;\n\n    @Field(9)\n    @Deprecated\n    public boolean exemptFromThrottle;\n\n    @Field(10)\n    @Deprecated\n    public String moduleId;\n\n    @Field(11)\n    @Deprecated\n    public boolean bypass;\n\n    @Field(12)\n    @Deprecated\n    public boolean waitForAccurateLocation;\n\n    @Field(13)\n    @Deprecated\n    public String contextAttributeTag;\n\n    @Field(14)\n    @Deprecated\n    public long maxUpdateAgeMillis = Long.MAX_VALUE;\n\n    @Override\n    public String toString() {\n        return \"LocationRequestInternal{\" +\n                \"request=\" + request +\n                \", requestNlpDebugInfo=\" + requestNlpDebugInfo +\n                \", restorePendingIntentListeners=\" + restorePendingIntentListeners +\n                \", triggerUpdate=\" + triggerUpdate +\n                \", clients=\" + clients +\n                \", tag='\" + tag + '\\'' +\n                \", hideFromAppOps=\" + hideFromAppOps +\n                \", forceCoarseLocation=\" + forceCoarseLocation +\n                \", exemptFromThrottle=\" + exemptFromThrottle +\n                \", moduleId=\" + moduleId +\n                \", locationSettingsIgnored=\" + bypass +\n                \", inaccurateLocationsDelayed=\" + waitForAccurateLocation +\n                \", contextAttributeTag=\" + contextAttributeTag +\n                '}';\n    }\n\n    public LocationRequestInternal() {\n    }\n\n    public LocationRequestInternal(LocationRequest request) {\n        this.request = request;\n    }\n\n    @SuppressLint(\"MissingPermission\")\n    public LocationRequest getRequest() {\n        LocationRequest.Builder builder = new LocationRequest.Builder(this.request);\n        if (clients != null) {\n            if (clients.isEmpty()) {\n                builder.setWorkSource(null);\n            } else {\n                WorkSource workSource = new WorkSource();\n                for (ClientIdentity client : clients) {\n                    WorkSourceUtil.add(workSource, client.uid, client.packageName);\n                }\n            }\n        }\n        if (forceCoarseLocation) builder.setGranularity(Granularity.GRANULARITY_COARSE);\n        if (exemptFromThrottle) builder.setThrottleBehavior(ThrottleBehavior.THROTTLE_NEVER);\n        if (moduleId != null) builder.setModuleId(moduleId);\n        else if (contextAttributeTag != null) builder.setModuleId(contextAttributeTag);\n        if (bypass) builder.setBypass(true);\n        if (waitForAccurateLocation) builder.setWaitForAccurateLocation(true);\n        if (maxUpdateAgeMillis != Long.MAX_VALUE) builder.setMaxUpdateAgeMillis(maxUpdateAgeMillis);\n        return builder.build();\n    }\n\n    public static final Creator<LocationRequestInternal> CREATOR = new AutoCreator<LocationRequestInternal>(LocationRequestInternal.class);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/internal/LocationRequestUpdateData.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.location.internal;\n\nimport android.app.PendingIntent;\n\nimport com.google.android.gms.location.ILocationCallback;\nimport com.google.android.gms.location.ILocationListener;\n\nimport org.microg.gms.common.Hide;\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\n@Hide\npublic class LocationRequestUpdateData extends AutoSafeParcelable {\n\n    public static final int REQUEST_UPDATES = 1;\n    public static final int REMOVE_UPDATES = 2;\n\n    @Field(1000)\n    private int versionCode;\n\n    @Field(1)\n    public int opCode;\n\n    @Field(2)\n    public LocationRequestInternal request;\n\n    @Field(3)\n    public ILocationListener listener;\n\n    @Field(4)\n    public PendingIntent pendingIntent;\n\n    @Field(5)\n    public ILocationCallback callback;\n\n    @Field(6)\n    public IFusedLocationProviderCallback fusedLocationProviderCallback;\n\n    @Field(8)\n    public String listenerId;\n\n    @Override\n    public String toString() {\n        return \"LocationRequestUpdateData{\" +\n                \"opCode=\" + opCode +\n                \", request=\" + request +\n                \", listener=\" + (listener != null ? listener.asBinder() : null) +\n                \", pendingIntent=\" + pendingIntent +\n                \", callback=\" + (callback != null ? callback.asBinder() : null) +\n                \", fusedLocationProviderCallback=\" + (fusedLocationProviderCallback != null ? fusedLocationProviderCallback.asBinder() : null) +\n                '}';\n    }\n\n    public static final Creator<LocationRequestUpdateData> CREATOR = new AutoCreator<LocationRequestUpdateData>(LocationRequestUpdateData.class);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/internal/ParcelableGeofence.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2017 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.location.internal;\n\nimport com.google.android.gms.location.Geofence;\n\nimport org.microg.gms.common.Hide;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n@Hide\npublic class ParcelableGeofence extends AutoSafeParcelable implements Geofence {\n\n    @Field(1000)\n    private int versionCode = 1;\n\n    @Field(1)\n    public String requestId;\n\n    @Field(2)\n    public long expirationTime;\n\n    @Field(3)\n    public int regionType;\n\n    @Field(4)\n    public double latitude;\n\n    @Field(5)\n    public double longitude;\n\n    @Field(6)\n    public float radius;\n\n    @Field(7)\n    public @TransitionTypes int transitionTypes;\n\n    @Field(8)\n    public int notificationResponsiveness;\n\n    @Field(9)\n    public int loiteringDelay;\n\n    private ParcelableGeofence() {\n        notificationResponsiveness = 0;\n        loiteringDelay = -1;\n    }\n\n    public ParcelableGeofence(String requestId, long expirationTime, int regionType, double latitude, double longitude, float radius, @TransitionTypes int transitionTypes, int notificationResponsiveness, int loiteringDelay) {\n        this.requestId = requestId;\n        this.expirationTime = expirationTime;\n        this.regionType = regionType;\n        this.latitude = latitude;\n        this.longitude = longitude;\n        this.radius = radius;\n        this.transitionTypes = transitionTypes;\n        this.notificationResponsiveness = notificationResponsiveness;\n        this.loiteringDelay = loiteringDelay;\n    }\n\n    @Override\n    public String getRequestId() {\n        return requestId;\n    }\n\n    @Override\n    public long getExpirationTime() {\n        return expirationTime;\n    }\n\n    @Override\n    public double getLatitude() {\n        return latitude;\n    }\n\n    @Override\n    public double getLongitude() {\n        return longitude;\n    }\n\n    @Override\n    public float getRadius() {\n        return radius;\n    }\n\n    @Override\n    public @TransitionTypes int getTransitionTypes() {\n        return transitionTypes;\n    }\n\n    @Override\n    public int getNotificationResponsiveness() {\n        return notificationResponsiveness;\n    }\n\n    @Override\n    public int getLoiteringDelay() {\n        return loiteringDelay;\n    }\n\n    public static final Creator<ParcelableGeofence> CREATOR = new AutoCreator<ParcelableGeofence>(ParcelableGeofence.class);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/internal/RemoveGeofencingRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.location.internal;\n\nimport android.app.PendingIntent;\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport java.util.List;\n\n@SafeParcelable.Class\npublic class RemoveGeofencingRequest extends AbstractSafeParcelable {\n    @Field(1)\n    @Nullable\n    public final List<String> geofenceIds;\n    @Field(2)\n    @Nullable\n    public final PendingIntent pendingIntent;\n    @Field(3)\n    public final String tag;\n\n    @Constructor\n    public RemoveGeofencingRequest(@Nullable @Param(1) List<String> geofenceIds, @Nullable @Param(2) PendingIntent pendingIntent, @Param(3) String tag) {\n        this.geofenceIds = geofenceIds;\n        this.pendingIntent = pendingIntent;\n        this.tag = tag;\n    }\n\n    public static RemoveGeofencingRequest byGeofenceIds(@NonNull List<String> geofenceIds) {\n        return new RemoveGeofencingRequest(geofenceIds, null, \"\");\n    }\n\n    public static RemoveGeofencingRequest byPendingIntent(@NonNull PendingIntent pendingIntent) {\n        return new RemoveGeofencingRequest(null, pendingIntent, \"\");\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel parcel, int i) {\n        CREATOR.writeToParcel(this, parcel, i);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<RemoveGeofencingRequest> CREATOR = findCreator(RemoveGeofencingRequest.class);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/internal/SetGoogleLocationAccuracyRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.location.internal;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class SetGoogleLocationAccuracyRequest extends AbstractSafeParcelable {\n    @Field(1)\n    public final boolean networkLocationOptIn;\n    @Field(2)\n    public final int settingSource;\n    @Field(3)\n    public final byte[] uiConsentBytes; //Used for Audit reporting, can be converted into proto\n    @Field(4)\n    public final byte[] auditTokenBytes; //Used for Audit reporting, can be converted into proto\n\n    @Constructor\n    public SetGoogleLocationAccuracyRequest(@Param(1) boolean networkLocationOptIn, @Param(2) int settingSource,\n                                            @Param(3) byte[] uiConsentBytes, @Param(4) byte[] auditTokenBytes) {\n        this.networkLocationOptIn = networkLocationOptIn;\n        this.settingSource = settingSource;\n        this.uiConsentBytes = uiConsentBytes;\n        this.auditTokenBytes = auditTokenBytes;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"SetGoogleLocationAccuracyRequest\")\n                .field(\"networkLocationOptIn\", networkLocationOptIn)\n                .field(\"settingSource\", settingSource)\n                .field(\"uiConsentBytes\", uiConsentBytes)\n                .field(\"auditTokenBytes\", auditTokenBytes)\n                .end();\n    }\n\n    public static final SafeParcelableCreatorAndWriter<SetGoogleLocationAccuracyRequest> CREATOR = findCreator(SetGoogleLocationAccuracyRequest.class);\n}"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/reporting/OptInRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.location.reporting;\n\nimport android.accounts.Account;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class OptInRequest extends AutoSafeParcelable {\n    @Field(2)\n    public Account account;\n    @Field(3)\n    public String tag;\n    @Field(4)\n    public String auditToken;\n\n    public static final Creator<OptInRequest> CREATOR = new AutoCreator<OptInRequest>(OptInRequest.class);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/reporting/ReportingState.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.location.reporting;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class ReportingState extends AbstractSafeParcelable {\n    @Field(1)\n    @Deprecated\n    int versionCode = 2;\n    @Field(2)\n    public final int reportingEnabled;\n    @Field(3)\n    public final int historyEnabled;\n    @Field(4)\n    public final boolean allowed;\n    @Field(5)\n    public final boolean active;\n    @Field(6)\n    @Deprecated\n    boolean defer;\n    @Field(7)\n    public final int expectedOptInResult;\n    @Field(8)\n    public final Integer deviceTag;\n    @Field(9)\n    public final int expectedOptInResultAssumingLocationEnabled;\n    @Field(10)\n    public final boolean canAccessSettings;\n    @Field(11)\n    public final boolean hasMigratedToOdlh;\n\n    @Constructor\n    public ReportingState(@Param(2) int reportingEnabled, @Param(3) int historyEnabled, @Param(4) boolean allowed, @Param(5) boolean active, @Param(7) int expectedOptInResult, @Param(9) int expectedOptInResultAssumingLocationEnabled, @Param(8) Integer deviceTag, @Param(10) boolean canAccessSettings, @Param(11) boolean hasMigratedToOdlh) {\n        this.reportingEnabled = reportingEnabled;\n        this.historyEnabled = historyEnabled;\n        this.allowed = allowed;\n        this.active = active;\n        this.expectedOptInResult = expectedOptInResult;\n        this.expectedOptInResultAssumingLocationEnabled = expectedOptInResultAssumingLocationEnabled;\n        this.deviceTag = deviceTag;\n        this.canAccessSettings = canAccessSettings;\n        this.hasMigratedToOdlh = hasMigratedToOdlh;\n    }\n\n    public int getDeviceTag() throws SecurityException {\n        if (this.deviceTag == null) throw new SecurityException(\"Device tag restricted to approved apps\");\n        return deviceTag;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"ReportingState\")\n                .field(\"reportingEnabled\", reportingEnabled)\n                .field(\"historyEnabled\", historyEnabled)\n                .field(\"allowed\", allowed)\n                .field(\"active\", active)\n                .field(\"expectedOptInResult\", expectedOptInResult)\n                .field(\"deviceTag\", deviceTag == null ? \"(hidden-from-unauthorized-caller)\" : deviceTag.intValue())\n                .field(\"expectedOptInResultAssumingLocationEnabled\", expectedOptInResultAssumingLocationEnabled)\n                .field(\"canAccessSettings\", canAccessSettings)\n                .field(\"hasMigratedToOdlh\", hasMigratedToOdlh)\n                .end();\n    }\n\n    public static final SafeParcelableCreatorAndWriter<ReportingState> CREATOR = findCreator(ReportingState.class);\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/reporting/SendDataRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.location.reporting;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class SendDataRequest extends AutoSafeParcelable {\n    @Field(1)\n    public String dataType;\n    @Field(2)\n    public byte[] data;\n\n    public static final Creator<SendDataRequest> CREATOR = new AutoCreator<SendDataRequest>(SendDataRequest.class);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/reporting/UlrPrivateModeRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.location.reporting;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class UlrPrivateModeRequest extends AutoSafeParcelable {\n    @Field(1)\n    public String tag;\n    @Field(2)\n    public boolean privateMode;\n\n    public static final Creator<UlrPrivateModeRequest> CREATOR = new AutoCreator<UlrPrivateModeRequest>(UlrPrivateModeRequest.class);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/reporting/UploadRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.location.reporting;\n\nimport android.accounts.Account;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class UploadRequest extends AutoSafeParcelable {\n    @SafeParceled(1)\n    public int versionCode = 1;\n    @SafeParceled(2)\n    public Account account;\n    @SafeParceled(3)\n    public String reason;\n    @SafeParceled(4)\n    public long durationMillis;\n    @SafeParceled(5)\n    public long movingLatencyMillis;\n    @SafeParceled(6)\n    public long stationaryLatencyMillis;\n    @SafeParceled(7)\n    public String appSpecificKey;\n\n    public static final Creator<UploadRequest> CREATOR = new AutoCreator<UploadRequest>(UploadRequest.class);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/com/google/android/gms/location/reporting/UploadRequestResult.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.location.reporting;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class UploadRequestResult extends AutoSafeParcelable {\n    @SafeParceled(1)\n    public int versionCode = 1;\n    @SafeParceled(2)\n    public int resultCode;\n    @SafeParceled(3)\n    public long requestId;\n\n    public UploadRequestResult() {\n    }\n\n    public static final Creator<UploadRequestResult> CREATOR = new AutoCreator<UploadRequestResult>(UploadRequestResult.class);\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/org/microg/gms/location/ActivityRecognitionApiClientBuilder.java",
    "content": "/*\n * Copyright (C) 2017 microG Project Team\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 org.microg.gms.location;\n\nimport android.content.Context;\nimport android.os.Looper;\n\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.Api.ApiOptions.NoOptions;\n\nimport org.microg.gms.common.api.ApiClientBuilder;\nimport com.google.android.gms.common.internal.ClientSettings;\nimport com.google.android.gms.common.api.internal.ConnectionCallbacks;\nimport com.google.android.gms.common.api.internal.OnConnectionFailedListener;\n\npublic class ActivityRecognitionApiClientBuilder implements ApiClientBuilder<NoOptions> {\n    @Override\n    public Api.Client build(NoOptions options, Context context, Looper looper, ClientSettings clientSettings, ConnectionCallbacks callbacks, OnConnectionFailedListener connectionFailedListener) {\n        return new ActivityRecognitionClientImpl(context, callbacks, connectionFailedListener);\n    }\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/org/microg/gms/location/ActivityRecognitionApiImpl.java",
    "content": "/*\n * Copyright (C) 2017 microG Project Team\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 org.microg.gms.location;\n\nimport android.app.PendingIntent;\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.PendingResult;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.location.ActivityRecognition;\nimport com.google.android.gms.location.ActivityRecognitionApi;\n\nimport org.microg.gms.common.GmsConnector;\n\npublic class ActivityRecognitionApiImpl implements ActivityRecognitionApi {\n    private static final String TAG = \"GmsActivityApiImpl\";\n\n    @Override\n    public PendingResult<Status> removeActivityUpdates(GoogleApiClient client, final PendingIntent callbackIntent) {\n        return callVoid(client, new Runnable() {\n            @Override\n            public void run(ActivityRecognitionClientImpl client) throws RemoteException {\n                client.removeActivityUpdates(callbackIntent);\n            }\n        });\n    }\n\n    @Override\n    public PendingResult<Status> requestActivityUpdates(GoogleApiClient client, final long detectionIntervalMillis, final PendingIntent callbackIntent) {\n        return callVoid(client, new Runnable() {\n            @Override\n            public void run(ActivityRecognitionClientImpl client) throws RemoteException {\n                client.requestActivityUpdates(detectionIntervalMillis, callbackIntent);\n            }\n        });\n    }\n\n    private PendingResult<Status> callVoid(GoogleApiClient client, final Runnable runnable) {\n        return GmsConnector.call(client, ActivityRecognition.API, new GmsConnector.Callback<ActivityRecognitionClientImpl, Status>() {\n            @Override\n            public void onClientAvailable(ActivityRecognitionClientImpl client, ResultProvider<Status> resultProvider) throws RemoteException {\n                runnable.run(client);\n                resultProvider.onResultAvailable(Status.SUCCESS);\n            }\n        });\n    }\n\n    private interface Runnable {\n        void run(ActivityRecognitionClientImpl client) throws RemoteException;\n    }\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/org/microg/gms/location/ActivityRecognitionClientImpl.java",
    "content": "/*\n * Copyright (C) 2017 microG Project Team\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 org.microg.gms.location;\n\nimport android.app.PendingIntent;\nimport android.content.Context;\nimport android.os.RemoteException;\n\nimport com.google.android.gms.common.api.internal.ConnectionCallbacks;\nimport com.google.android.gms.common.api.internal.OnConnectionFailedListener;\n\npublic class ActivityRecognitionClientImpl extends GoogleLocationManagerClient {\n    public ActivityRecognitionClientImpl(Context context, ConnectionCallbacks callbacks, OnConnectionFailedListener connectionFailedListener) {\n        super(context, callbacks, connectionFailedListener);\n    }\n\n    public void requestActivityUpdates(long detectionIntervalMillis, PendingIntent callbackIntent) throws RemoteException {\n        getServiceInterface().requestActivityUpdates(detectionIntervalMillis, true, callbackIntent);\n    }\n\n    public void removeActivityUpdates(PendingIntent callbackIntent) throws RemoteException {\n        getServiceInterface().removeActivityUpdates(callbackIntent);\n    }\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/org/microg/gms/location/FusedLocationProviderApiImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.location;\n\nimport android.app.PendingIntent;\nimport android.location.Location;\nimport android.os.Looper;\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.PendingResult;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.location.FusedLocationProviderApi;\nimport com.google.android.gms.location.LocationAvailability;\nimport com.google.android.gms.location.LocationCallback;\nimport com.google.android.gms.location.LocationListener;\nimport com.google.android.gms.location.LocationRequest;\nimport com.google.android.gms.location.LocationServices;\n\nimport org.microg.gms.common.GmsConnector;\n\n@SuppressWarnings(\"deprecation\")\npublic class FusedLocationProviderApiImpl implements FusedLocationProviderApi {\n    private static final String TAG = \"GmsFusedApiImpl\";\n\n    @Override\n    public PendingResult<Status> flushLocations(GoogleApiClient client) {\n        return null;\n    }\n\n    @Override\n    public Location getLastLocation(GoogleApiClient client) {\n        try {\n            return LocationClientImpl.get(client).getLastLocation();\n        } catch (RemoteException e) {\n            Log.w(TAG, e);\n            return null;\n        }\n    }\n\n    @Override\n    public LocationAvailability getLocationAvailability(GoogleApiClient client) {\n        try {\n            return LocationClientImpl.get(client).getLocationAvailability();\n        } catch (RemoteException e) {\n            Log.w(TAG, e);\n            return null;\n        }\n    }\n\n    @Override\n    public PendingResult<Status> requestLocationUpdates(GoogleApiClient client,\n                                                final LocationRequest request, final LocationListener listener) {\n        return callVoid(client, new Runnable() {\n            @Override\n            public void run(LocationClientImpl client) throws RemoteException {\n                client.requestLocationUpdates(request, listener);\n            }\n        });\n    }\n\n    @Override\n    public PendingResult<Status> requestLocationUpdates(GoogleApiClient client, LocationRequest request, LocationCallback callback, Looper looper) {\n        Looper currentLooper = looper == null ? Looper.myLooper() : looper;\n        return callVoid(client, new Runnable() {\n            @Override\n            public void run(LocationClientImpl client) throws RemoteException {\n                client.requestLocationUpdates(request, callback, currentLooper);\n            }\n        });\n    }\n\n    @Override\n    public PendingResult<Status> requestLocationUpdates(GoogleApiClient client,\n                                                final LocationRequest request, final LocationListener listener,\n                                                final Looper looper) {\n        Looper currentLooper = looper == null ? Looper.myLooper() : looper;\n        return callVoid(client, new Runnable() {\n            @Override\n            public void run(LocationClientImpl client) throws RemoteException {\n                client.requestLocationUpdates(request, listener, currentLooper);\n            }\n        });\n    }\n\n    @Override\n    public PendingResult<Status> requestLocationUpdates(GoogleApiClient client,\n                                                final LocationRequest request, final PendingIntent callbackIntent) {\n        return callVoid(client, new Runnable() {\n            @Override\n            public void run(LocationClientImpl client) throws RemoteException {\n                client.requestLocationUpdates(request, callbackIntent);\n            }\n        });\n    }\n\n    @Override\n    public PendingResult<Status> removeLocationUpdates(GoogleApiClient client,\n                                               final LocationListener listener) {\n        return callVoid(client, new Runnable() {\n            @Override\n            public void run(LocationClientImpl client) throws RemoteException {\n                client.removeLocationUpdates(listener);\n            }\n        });\n    }\n\n    @Override\n    public PendingResult<Status> removeLocationUpdates(GoogleApiClient client, LocationCallback callback) {\n        return callVoid(client, new Runnable() {\n            @Override\n            public void run(LocationClientImpl client) throws RemoteException {\n                client.removeLocationUpdates(callback);\n            }\n        });\n    }\n\n    @Override\n    public PendingResult<Status> removeLocationUpdates(GoogleApiClient client,\n                                               final PendingIntent callbackIntent) {\n        return callVoid(client, new Runnable() {\n            @Override\n            public void run(LocationClientImpl client) throws RemoteException {\n                client.removeLocationUpdates(callbackIntent);\n            }\n        });\n    }\n\n    @Override\n    public PendingResult<Status> setMockMode(GoogleApiClient client, final boolean isMockMode) {\n        return callVoid(client, new Runnable() {\n            @Override\n            public void run(LocationClientImpl client) throws RemoteException {\n                client.setMockMode(isMockMode);\n            }\n        });\n    }\n\n    @Override\n    public PendingResult<Status> setMockLocation(GoogleApiClient client, final Location mockLocation) {\n        return callVoid(client, new Runnable() {\n            @Override\n            public void run(LocationClientImpl client) throws RemoteException {\n                client.setMockLocation(mockLocation);\n            }\n        });\n    }\n\n    private PendingResult<Status> callVoid(GoogleApiClient client, final Runnable runnable) {\n        return GmsConnector.call(client, LocationServices.API, new GmsConnector.Callback<LocationClientImpl, Status>() {\n            @Override\n            public void onClientAvailable(LocationClientImpl client, ResultProvider<Status> resultProvider) throws RemoteException {\n                runnable.run(client);\n                resultProvider.onResultAvailable(Status.SUCCESS);\n            }\n        });\n    }\n\n    private interface Runnable {\n        void run(LocationClientImpl client) throws RemoteException;\n    }\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/org/microg/gms/location/FusedLocationProviderClientImpl.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location;\n\nimport android.app.PendingIntent;\nimport android.content.Context;\nimport android.location.Location;\nimport android.os.Looper;\n\nimport android.util.Log;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.location.*;\nimport com.google.android.gms.tasks.CancellationToken;\nimport com.google.android.gms.tasks.Task;\n\nimport org.microg.gms.common.api.ReturningGoogleApiCall;\nimport org.microg.gms.common.api.PendingGoogleApiCall;\nimport org.microg.gms.common.api.VoidReturningGoogleApiCall;\n\nimport java.util.concurrent.Executor;\n\npublic class FusedLocationProviderClientImpl extends FusedLocationProviderClient {\n    public FusedLocationProviderClientImpl(Context context) {\n        super(context);\n    }\n\n    @NonNull\n    public Task<Void> flushLocations() {\n        return scheduleTask((ReturningGoogleApiCall<Void, LocationClientImpl>) (client) -> null);\n    }\n\n    @NonNull\n    @Override\n    public Task<Location> getCurrentLocation(int priority, CancellationToken cancellationToken) {\n        return null;\n    }\n\n    @NonNull\n    @Override\n    public Task<Location> getCurrentLocation(@NonNull CurrentLocationRequest request, CancellationToken cancellationToken) {\n        return null;\n    }\n\n    @NonNull\n    @Override\n    public Task<Location> getLastLocation(@NonNull LastLocationRequest request) {\n        return null;\n    }\n\n    @NonNull\n    public Task<Location> getLastLocation() {\n        return scheduleTask((ReturningGoogleApiCall<Location, LocationClientImpl>) LocationClientImpl::getLastLocation);\n    }\n\n    @NonNull\n    @Override\n    public Task<LocationAvailability> getLocationAvailability() {\n        return scheduleTask((ReturningGoogleApiCall<LocationAvailability, LocationClientImpl>) LocationClientImpl::getLocationAvailability);\n    }\n\n    @NonNull\n    @Override\n    public Task<Void> removeLocationUpdates(@NonNull LocationListener listener) {\n        return scheduleTask((VoidReturningGoogleApiCall<LocationClientImpl>) (client) -> client.removeLocationUpdates(listener));\n    }\n\n    @NonNull\n    @Override\n    public Task<Void> removeLocationUpdates(@NonNull PendingIntent pendingIntent) {\n        return scheduleTask((VoidReturningGoogleApiCall<LocationClientImpl>) (client) -> client.removeLocationUpdates(pendingIntent));\n    }\n\n    @NonNull\n    @Override\n    public Task<Void> requestLocationUpdates(@NonNull LocationRequest request, @NonNull LocationListener listener, @Nullable Looper looper) {\n        Looper currentLooper = looper == null ? Looper.myLooper() : looper;\n        if (currentLooper == null) throw new IllegalStateException(\"looper is null and the calling thread has not called Looper.prepare()\");\n        return scheduleTask((VoidReturningGoogleApiCall<LocationClientImpl>) (client) -> client.requestLocationUpdates(request, listener, currentLooper));\n    }\n\n    @NonNull\n    @Override\n    public Task<Void> requestLocationUpdates(@NonNull LocationRequest request, @NonNull Executor executor, @NonNull LocationCallback callback) {\n        return scheduleTask((VoidReturningGoogleApiCall<LocationClientImpl>) (client) -> client.requestLocationUpdates(request, executor, callback));\n    }\n\n    @NonNull\n    @Override\n    public Task<Void> requestLocationUpdates(@NonNull LocationRequest request, @NonNull Executor executor, @NonNull LocationListener listener) {\n        return scheduleTask((VoidReturningGoogleApiCall<LocationClientImpl>) (client) -> client.requestLocationUpdates(request, executor, listener));\n    }\n\n    @NonNull\n    @Override\n    public Task<Void> requestLocationUpdates(@NonNull LocationRequest request, @NonNull LocationCallback callback, Looper looper) {\n        Looper currentLooper = looper == null ? Looper.myLooper() : looper;\n        if (currentLooper == null) throw new IllegalStateException(\"looper is null and the calling thread has not called Looper.prepare()\");\n        return scheduleTask((VoidReturningGoogleApiCall<LocationClientImpl>) (client) -> client.requestLocationUpdates(request, callback, currentLooper));\n    }\n\n    @NonNull\n    @Override\n    public Task<Void> requestLocationUpdates(@NonNull LocationRequest request, @NonNull PendingIntent pendingIntent) {\n        return scheduleTask((VoidReturningGoogleApiCall<LocationClientImpl>) (client) -> client.requestLocationUpdates(request, pendingIntent));\n    }\n\n    @NonNull\n    @Override\n    public Task<Void> setMockLocation(@NonNull Location location) {\n        return scheduleTask((VoidReturningGoogleApiCall<LocationClientImpl>) (client) -> client.setMockLocation(location));\n    }\n\n    @NonNull\n    @Override\n    public Task<Void> setMockMode(boolean mockMode) {\n        return scheduleTask((VoidReturningGoogleApiCall<LocationClientImpl>) (client) -> client.setMockMode(mockMode));\n    }\n\n    @NonNull\n    @Override\n    public Task<Void> removeLocationUpdates(@NonNull LocationCallback callback) {\n        return scheduleTask((VoidReturningGoogleApiCall<LocationClientImpl>) (client) -> client.removeLocationUpdates(callback));\n    }\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/org/microg/gms/location/GeofencingApiImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.location;\n\nimport android.app.PendingIntent;\nimport android.os.RemoteException;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.PendingResult;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.location.Geofence;\nimport com.google.android.gms.location.GeofencingApi;\nimport com.google.android.gms.location.GeofencingRequest;\nimport com.google.android.gms.location.LocationServices;\nimport com.google.android.gms.location.internal.IGeofencerCallbacks;\nimport com.google.android.gms.location.internal.ParcelableGeofence;\n\nimport org.microg.gms.common.GmsConnector;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class GeofencingApiImpl implements GeofencingApi {\n    @Override\n    public PendingResult<Status> addGeofences(GoogleApiClient client, final GeofencingRequest geofencingRequest, final PendingIntent pendingIntent) {\n        return callGeofencer(client, new Runnable() {\n            @Override\n            public void run(LocationClientImpl client, IGeofencerCallbacks callbacks) throws RemoteException {\n                client.addGeofences(geofencingRequest, pendingIntent, callbacks);\n            }\n        });\n    }\n\n    @Override\n    public PendingResult<Status> addGeofences(GoogleApiClient client, final List<Geofence> geofences, final PendingIntent pendingIntent) {\n        final List<ParcelableGeofence> geofenceList = new ArrayList<ParcelableGeofence>();\n        for (Geofence geofence : geofences) {\n            if (geofence instanceof ParcelableGeofence) geofenceList.add((ParcelableGeofence) geofence);\n        }\n        return callGeofencer(client, new Runnable() {\n            @Override\n            public void run(LocationClientImpl client, IGeofencerCallbacks callbacks) throws RemoteException {\n                client.addGeofences(geofenceList, pendingIntent, callbacks);\n            }\n        });\n    }\n\n    @Override\n    public PendingResult<Status> removeGeofences(GoogleApiClient client, final List<String> geofenceRequestIds) {\n        return callGeofencer(client, new Runnable() {\n            @Override\n            public void run(LocationClientImpl client, IGeofencerCallbacks callbacks) throws RemoteException {\n                client.removeGeofences(geofenceRequestIds, callbacks);\n            }\n        });\n    }\n\n    @Override\n    public PendingResult<Status> removeGeofences(GoogleApiClient client, final PendingIntent pendingIntent) {\n        return callGeofencer(client, new Runnable() {\n            @Override\n            public void run(LocationClientImpl client, IGeofencerCallbacks callbacks) throws RemoteException {\n                client.removeGeofences(pendingIntent, callbacks);\n            }\n        });\n    }\n\n    @NonNull\n    private IGeofencerCallbacks.Stub createGeofencerCallbacks(final GmsConnector.Callback.ResultProvider<Status> resultProvider) {\n        return new IGeofencerCallbacks.Stub(){\n            @Override\n            public void onAddGeofenceResult(int statusCode, String[] requestIds) throws RemoteException {\n                resultProvider.onResultAvailable(new Status(statusCode));\n            }\n\n            @Override\n            public void onRemoveGeofencesByRequestIdsResult(int statusCode, String[] requestIds) throws RemoteException {\n                resultProvider.onResultAvailable(new Status(statusCode));\n            }\n\n            @Override\n            public void onRemoveGeofencesByPendingIntentResult(int statusCode, PendingIntent pendingIntent) throws RemoteException {\n                resultProvider.onResultAvailable(new Status(statusCode));\n            }\n        };\n    }\n\n    private PendingResult<Status> callGeofencer(GoogleApiClient client, final Runnable runnable) {\n        return GmsConnector.call(client, LocationServices.API, new GmsConnector.Callback<LocationClientImpl, Status>() {\n            @Override\n            public void onClientAvailable(LocationClientImpl client, ResultProvider<Status> resultProvider) throws RemoteException {\n                runnable.run(client, createGeofencerCallbacks(resultProvider));\n            }\n        });\n    }\n\n    private interface Runnable {\n        void run(LocationClientImpl client, IGeofencerCallbacks callbacks) throws RemoteException;\n    }\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/org/microg/gms/location/GeofencingClientImpl.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location;\n\nimport android.app.PendingIntent;\nimport android.content.Context;\n\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.GoogleApi;\nimport com.google.android.gms.location.GeofencingClient;\nimport com.google.android.gms.location.GeofencingRequest;\nimport com.google.android.gms.location.LocationServices;\nimport com.google.android.gms.tasks.Task;\n\nimport java.util.List;\n\npublic class GeofencingClientImpl extends GoogleApi<Api.ApiOptions.NoOptions> implements GeofencingClient {\n    public GeofencingClientImpl(Context context) {\n        super(context, LocationServices.API, Api.ApiOptions.NO_OPTIONS);\n    }\n\n    @NonNull\n    @Override\n    public Task<Void> addGeofences(GeofencingRequest geofencingRequest, PendingIntent pendingIntent) {\n        return null;\n    }\n\n    @NonNull\n    @Override\n    public Task<Void> removeGeofences(List<String> geofenceRequestIds) {\n        return null;\n    }\n\n    @NonNull\n    @Override\n    public Task<Void> removeGeofences(PendingIntent pendingIntent) {\n        return null;\n    }\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/org/microg/gms/location/GoogleLocationManagerClient.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.location;\n\nimport android.content.Context;\nimport android.os.Bundle;\nimport android.os.IBinder;\nimport android.os.RemoteException;\n\nimport com.google.android.gms.common.internal.IGmsServiceBroker;\nimport com.google.android.gms.location.internal.IGoogleLocationManagerService;\n\nimport org.microg.gms.common.Constants;\nimport org.microg.gms.common.GmsClient;\nimport org.microg.gms.common.GmsService;\nimport com.google.android.gms.common.api.internal.ConnectionCallbacks;\nimport com.google.android.gms.common.api.internal.OnConnectionFailedListener;\n\npublic abstract class GoogleLocationManagerClient extends GmsClient<IGoogleLocationManagerService> {\n    public GoogleLocationManagerClient(Context context, ConnectionCallbacks\n            callbacks, OnConnectionFailedListener connectionFailedListener) {\n        super(context, callbacks, connectionFailedListener, GmsService.GOOGLE_LOCATION_MANAGER.ACTION);\n    }\n\n    @Override\n    protected IGoogleLocationManagerService interfaceFromBinder(IBinder binder) {\n        return IGoogleLocationManagerService.Stub.asInterface(binder);\n    }\n\n    @Override\n    protected void onConnectedToBroker(IGmsServiceBroker broker, GmsCallbacks callbacks)\n            throws RemoteException {\n        Bundle bundle = new Bundle();\n        bundle.putString(\"client_name\", \"locationServices\");\n        broker.getGoogleLocationManagerService(callbacks, Constants.GMS_VERSION_CODE,\n                getContext().getPackageName(), bundle);\n    }\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/org/microg/gms/location/GranularityUtil.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location;\n\nimport com.google.android.gms.location.Granularity;\nimport com.google.android.gms.location.Priority;\n\npublic class GranularityUtil {\n    public static boolean isValidGranularity(int granularity) {\n        switch (granularity) {\n            default:\n                return false;\n            case Granularity.GRANULARITY_PERMISSION_LEVEL:\n            case Granularity.GRANULARITY_COARSE:\n            case Granularity.GRANULARITY_FINE:\n                return true;\n        }\n    }\n\n    public static int checkValidGranularity(int granularity) {\n        if (!isValidGranularity(granularity)) {\n            throw new IllegalArgumentException(\"granularity \" + granularity + \" must be a Granularity.GRANULARITY_* constant\");\n        }\n        return granularity;\n    }\n\n    public static String granularityToString(int granularity) {\n        switch (granularity) {\n            case Granularity.GRANULARITY_PERMISSION_LEVEL:\n                return \"GRANULARITY_PERMISSION_LEVEL\";\n            case Granularity.GRANULARITY_COARSE:\n                return \"GRANULARITY_COARSE\";\n            case Granularity.GRANULARITY_FINE:\n                return \"GRANULARITY_FINE\";\n            default:\n                throw new IllegalArgumentException();\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/org/microg/gms/location/LocationClientImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.location;\n\nimport android.app.PendingIntent;\nimport android.content.Context;\nimport android.location.Location;\nimport android.os.Handler;\nimport android.os.Looper;\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.location.GeofencingRequest;\nimport com.google.android.gms.location.ILocationListener;\nimport com.google.android.gms.location.LocationAvailability;\nimport com.google.android.gms.location.LocationCallback;\nimport com.google.android.gms.location.LocationListener;\nimport com.google.android.gms.location.LocationRequest;\nimport com.google.android.gms.location.LocationResult;\nimport com.google.android.gms.location.LocationServices;\nimport com.google.android.gms.location.internal.IGeofencerCallbacks;\nimport com.google.android.gms.location.internal.ParcelableGeofence;\n\nimport com.google.android.gms.common.api.internal.ConnectionCallbacks;\nimport org.microg.gms.common.api.GoogleApiClientImpl;\nimport com.google.android.gms.common.api.internal.OnConnectionFailedListener;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.Executor;\n\npublic class LocationClientImpl extends GoogleLocationManagerClient {\n    private static final String TAG = \"GmsLocationClientImpl\";\n    private Map<LocationListener, ILocationListener> listenerMap = new HashMap<LocationListener, ILocationListener>();\n    private Map<LocationCallback, ILocationListener> callbackMap = new HashMap<LocationCallback, ILocationListener>();\n\n\n    public LocationClientImpl(Context context, ConnectionCallbacks callbacks,\n                              OnConnectionFailedListener connectionFailedListener) {\n        super(context, callbacks, connectionFailedListener);\n        Log.d(TAG, \"<init>\");\n    }\n\n    public static LocationClientImpl get(GoogleApiClient apiClient) {\n        if (apiClient instanceof GoogleApiClientImpl) {\n            return (LocationClientImpl) ((GoogleApiClientImpl) apiClient)\n                    .getApiConnection(LocationServices.API);\n        }\n        return null;\n    }\n\n    public void addGeofences(GeofencingRequest request, PendingIntent pendingIntent, IGeofencerCallbacks callbacks) throws RemoteException {\n        getServiceInterface().addGeofences(request, pendingIntent, callbacks);\n    }\n\n    public void addGeofences(List<ParcelableGeofence> request, PendingIntent pendingIntent, IGeofencerCallbacks callbacks) throws RemoteException {\n        getServiceInterface().addGeofencesList(request, pendingIntent, callbacks, getContext().getPackageName());\n    }\n\n    public void removeGeofences(List<String> geofenceRequestIds, IGeofencerCallbacks callbacks) throws RemoteException {\n        getServiceInterface().removeGeofencesById(geofenceRequestIds.toArray(new String[geofenceRequestIds.size()]), callbacks, getContext().getPackageName());\n    }\n\n    public void removeGeofences(PendingIntent pendingIntent, IGeofencerCallbacks callbacks) throws RemoteException {\n        getServiceInterface().removeGeofencesByIntent(pendingIntent, callbacks, getContext().getPackageName());\n    }\n\n    public Location getLastLocation() throws RemoteException {\n        return getServiceInterface().getLastLocationWithPackage(getContext().getPackageName());\n    }\n\n    public LocationAvailability getLocationAvailability() throws RemoteException {\n        return getServiceInterface().getLocationAvailabilityWithPackage(getContext().getPackageName());\n    }\n\n    public void requestLocationUpdates(LocationRequest request, final LocationListener listener)\n            throws RemoteException {\n        if (!listenerMap.containsKey(listener)) {\n            listenerMap.put(listener, new ILocationListener.Stub() {\n                @Override\n                public void onLocationChanged(Location location) throws RemoteException {\n                    listener.onLocationChanged(location);\n                }\n\n                @Override\n                public void cancel() throws RemoteException {\n\n                }\n            });\n        }\n        getServiceInterface().requestLocationUpdatesWithPackage(request, listenerMap.get(listener), getContext().getPackageName());\n    }\n\n    public void requestLocationUpdates(LocationRequest request, PendingIntent pendingIntent)\n            throws RemoteException {\n        getServiceInterface().requestLocationUpdatesWithIntent(request, pendingIntent);\n    }\n\n    public void requestLocationUpdates(LocationRequest request, LocationListener listener, @NonNull Looper looper) throws RemoteException {\n        final Handler handler = new Handler(looper);\n        requestLocationUpdates(request, handler::post, listener);\n    }\n\n    public void requestLocationUpdates(LocationRequest request, Executor executor, LocationListener listener) throws RemoteException {\n        if (!listenerMap.containsKey(listener)) {\n            listenerMap.put(listener, new ILocationListener.Stub() {\n                @Override\n                public void onLocationChanged(Location location) throws RemoteException {\n                    executor.execute(() -> listener.onLocationChanged(location));\n                }\n\n                @Override\n                public void cancel() throws RemoteException {\n\n                }\n            });\n        }\n        getServiceInterface().requestLocationUpdatesWithPackage(request, listenerMap.get(listener), getContext().getPackageName());\n    }\n\n    public void requestLocationUpdates(LocationRequest request, LocationCallback callback, @NonNull Looper looper) throws RemoteException {\n        final Handler handler = new Handler(looper);\n        requestLocationUpdates(request, handler::post, callback);\n    }\n\n    public void requestLocationUpdates(LocationRequest request, Executor executor, LocationCallback callback) throws RemoteException {\n        if (!callbackMap.containsKey(callback)) {\n            callbackMap.put(callback, new ILocationListener.Stub() {\n                @Override\n                public void onLocationChanged(Location location) throws RemoteException {\n                    executor.execute(() -> callback.onLocationResult(LocationResult.create(Collections.singletonList(location))));\n                }\n\n                @Override\n                public void cancel() throws RemoteException {\n\n                }\n            });\n        }\n        getServiceInterface().requestLocationUpdatesWithPackage(request, callbackMap.get(callback), getContext().getPackageName());\n    }\n\n    public void removeLocationUpdates(LocationListener listener) throws RemoteException {\n        getServiceInterface().removeLocationUpdatesWithListener(listenerMap.get(listener));\n    }\n\n    public void removeLocationUpdates(LocationCallback callback) throws RemoteException {\n        getServiceInterface().removeLocationUpdatesWithListener(callbackMap.get(callback));\n    }\n\n    public void removeLocationUpdates(PendingIntent pendingIntent) throws RemoteException {\n        getServiceInterface().removeLocationUpdatesWithIntent(pendingIntent);\n    }\n\n    public void setMockMode(boolean isMockMode) throws RemoteException {\n        getServiceInterface().setMockMode(isMockMode);\n    }\n\n    public void setMockLocation(Location mockLocation) throws RemoteException {\n        getServiceInterface().setMockLocation(mockLocation);\n    }\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/org/microg/gms/location/LocationServicesApiClientBuilder.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.location;\n\nimport android.content.Context;\nimport android.os.Looper;\n\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.Api.ApiOptions.NoOptions;\n\nimport org.microg.gms.common.api.ApiClientBuilder;\nimport com.google.android.gms.common.internal.ClientSettings;\nimport com.google.android.gms.common.api.internal.ConnectionCallbacks;\nimport com.google.android.gms.common.api.internal.OnConnectionFailedListener;\n\npublic class LocationServicesApiClientBuilder implements ApiClientBuilder<NoOptions> {\n    @Override\n    public Api.Client build(NoOptions options, Context context, Looper looper, ClientSettings clientSettings, ConnectionCallbacks callbacks, OnConnectionFailedListener connectionFailedListener) {\n        return new LocationClientImpl(context, callbacks, connectionFailedListener);\n    }\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/org/microg/gms/location/PriorityUtil.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location;\n\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.location.Priority;\n\npublic class PriorityUtil {\n    public static boolean isValidPriority(@Priority int priority) {\n        switch (priority) {\n            default:\n                return false;\n            case Priority.PRIORITY_HIGH_ACCURACY:\n            case Priority.PRIORITY_BALANCED_POWER_ACCURACY:\n            case Priority.PRIORITY_LOW_POWER:\n            case Priority.PRIORITY_PASSIVE:\n                return true;\n        }\n    }\n\n    public static int checkValidPriority(@Priority int priority) {\n        if (!isValidPriority(priority)) {\n            throw new IllegalArgumentException(\"priority \" + priority + \" must be a Priority.PRIORITY_* constant\");\n        }\n        return priority;\n    }\n\n    @NonNull\n    public static String priorityToString(@Priority int priority) {\n        switch (priority) {\n            case Priority.PRIORITY_HIGH_ACCURACY:\n                return \"HIGH_ACCURACY\";\n            case Priority.PRIORITY_BALANCED_POWER_ACCURACY:\n                return \"BALANCED_POWER_ACCURACY\";\n            case Priority.PRIORITY_LOW_POWER:\n                return \"LOW_POWER\";\n            case Priority.PRIORITY_PASSIVE:\n                return \"PASSIVE\";\n            default:\n                throw new IllegalArgumentException();\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/org/microg/gms/location/SettingsApiImpl.java",
    "content": "/*\n * Copyright (C) 2017 microG Project Team\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 org.microg.gms.location;\n\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.PendingResult;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.location.LocationSettingsRequest;\nimport com.google.android.gms.location.LocationSettingsResult;\nimport com.google.android.gms.location.SettingsApi;\n\nimport org.microg.gms.common.api.InstantPendingResult;\n\npublic class SettingsApiImpl implements SettingsApi {\n    @Override\n    public PendingResult<LocationSettingsResult> checkLocationSettings(GoogleApiClient client, LocationSettingsRequest locationSettingsRequest) {\n        return new InstantPendingResult<LocationSettingsResult>(new LocationSettingsResult(Status.CANCELED));\n    }\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/org/microg/gms/location/SettingsClientImpl.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location;\n\nimport android.content.Context;\n\nimport android.os.RemoteException;\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.GoogleApi;\nimport com.google.android.gms.location.*;\nimport com.google.android.gms.location.internal.ISettingsCallbacks;\nimport com.google.android.gms.tasks.Task;\nimport com.google.android.gms.tasks.TaskCompletionSource;\nimport com.google.android.gms.tasks.Tasks;\nimport org.microg.gms.common.api.PendingGoogleApiCall;\n\npublic class SettingsClientImpl extends GoogleApi<Api.ApiOptions.NoOptions> implements SettingsClient {\n    public SettingsClientImpl(Context context) {\n        super(context, LocationServices.API, Api.ApiOptions.NO_OPTIONS);\n    }\n\n    @Override\n    public Task<LocationSettingsResponse> checkLocationSettings(LocationSettingsRequest locationSettingsRequest) {\n        return scheduleTask((PendingGoogleApiCall<LocationSettingsResponse, LocationClientImpl>) (client, completionSource) -> client.getServiceInterface().requestLocationSettingsDialog(locationSettingsRequest, new ISettingsCallbacks.Stub() {\n            @Override\n            public void onLocationSettingsResult(LocationSettingsResult result) {\n                completionSource.setResult(new LocationSettingsResponse(result));\n            }\n        }, null));\n    }\n\n    @Override\n    public Task<Boolean> isGoogleLocationAccuracyEnabled() {\n        return Tasks.forResult(true); // TODO\n    }\n}\n"
  },
  {
    "path": "play-services-location/src/main/java/org/microg/gms/location/ThrottleBehaviorUtil.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.location;\n\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.location.ThrottleBehavior;\n\npublic class ThrottleBehaviorUtil {\n    public static boolean isValidThrottleBehavior(@ThrottleBehavior int throttleBehavior) {\n        switch (throttleBehavior) {\n            default:\n                return false;\n            case ThrottleBehavior.THROTTLE_BACKGROUND:\n            case ThrottleBehavior.THROTTLE_ALWAYS:\n            case ThrottleBehavior.THROTTLE_NEVER:\n                return true;\n        }\n    }\n\n    public static int checkValidThrottleBehavior(@ThrottleBehavior int throttleBehavior) {\n        if (!isValidThrottleBehavior(throttleBehavior)) {\n            throw new IllegalArgumentException(\"throttle behavior \" + throttleBehavior + \" must be a ThrottleBehavior.THROTTLE_* constant\");\n        }\n        return throttleBehavior;\n    }\n\n    @NonNull\n    public static String throttleBehaviorToString(@ThrottleBehavior int throttleBehavior) {\n        switch (throttleBehavior) {\n            case ThrottleBehavior.THROTTLE_BACKGROUND:\n                return \"THROTTLE_BACKGROUND\";\n            case ThrottleBehavior.THROTTLE_ALWAYS:\n                return \"THROTTLE_ALWAYS\";\n            case ThrottleBehavior.THROTTLE_NEVER:\n                return \"THROTTLE_NEVER\";\n            default:\n                throw new IllegalArgumentException();\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-maps/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\nandroid {\n    namespace \"com.google.android.gms.maps\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n}\n\napply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG implementation of play-services-maps'\n\ndependencies {\n    // Dependencies from play-services-maps:18.1.0\n    api \"androidx.fragment:fragment:1.0.0\"\n    api project(\":play-services-base\")\n    api project(\":play-services-basement\")\n\n    annotationProcessor project(\":safe-parcel-processor\")\n}\n"
  },
  {
    "path": "play-services-maps/core/hms/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'kotlin-android'\n\ndependencies {\n    implementation project(':play-services-base-core')\n    implementation project(':play-services-maps')\n\n    implementation 'com.huawei.hms:maps:6.9.0.300'\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion\"\n}\n\nandroid {\n    namespace \"org.microg.gms.maps.hms\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n        buildConfigField \"String\", \"HMSMAP_KEY\", \"\\\"${localProperties.getProperty(\"hmsmap.key\", \"\")}\\\"\"\n\n        ndk {\n            abiFilters \"armeabi\", \"armeabi-v7a\", \"arm64-v8a\"\n        }\n    }\n\n    buildFeatures {\n        buildConfig = true\n    }\n\n    sourceSets {\n        main.java.srcDirs += 'src/main/kotlin'\n    }\n\n    lintOptions {\n        disable 'GradleCompatible'\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled true\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n\n    kotlinOptions {\n        jvmTarget = 1.8\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/hms/proguard-rules.pro",
    "content": "-ignorewarnings\n-keepattributes *Annotation*\n-keepattributes Exceptions\n-keepattributes InnerClasses\n-keepattributes Signature\n-keepattributes SourceFile,LineNumberTable\n-keep class com.huawei.hianalytics.**{*;}\n-keep class com.huawei.updatesdk.**{*;}\n-keep class com.huawei.hms.**{*;}"
  },
  {
    "path": "play-services-maps/core/hms/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n    <uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\" />\n    <uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\" />\n    <uses-permission android:name=\"android.permission.READ_PHONE_STATE\" />\n    <uses-permission android:name=\"android.permission.WAKE_LOCK\" />\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" />\n    <uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\" />\n    <uses-permission android:name=\"android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS\" />\n    <uses-permission android:name=\"android.permission.RECEIVE_BOOT_COMPLETED\" />\n\n    <uses-sdk tools:overrideLibrary=\"com.huawei.hms.maps,com.huawei.android.hms.base,com.huawei.hms.feature.dynamic,com.huawei.hms.base.availableupdate,com.huawei.hms.stats,com.huawei.hms.base.ui,com.huawei.hms.base.device,com.huawei.hms.log,com.huawei.hmf.tasks,com.huawei.hms.framework.network.grs,com.huawei.hms.hatool,com.huawei.hms.framework.network.frameworkcompat,com.huawei.hms.framework.common\" />\n\n    <application />\n\n</manifest>"
  },
  {
    "path": "play-services-maps/core/hms/src/main/assets/.gitignore",
    "content": "agconnect-services.json\n"
  },
  {
    "path": "play-services-maps/core/hms/src/main/java/com/google/android/gms/dynamite/descriptors/com/google/android/gms/maps_dynamite/ModuleDescriptor.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.dynamite.descriptors.com.google.android.gms.maps_dynamite;\n\nimport androidx.annotation.Keep;\n\n@Keep\npublic class ModuleDescriptor {\n    public static final String MODULE_ID = \"com.google.android.gms.maps_dynamite\";\n    public static final int MODULE_VERSION = 1;\n}\n"
  },
  {
    "path": "play-services-maps/core/hms/src/main/java/com/google/android/gms/maps/internal/CreatorImpl.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.maps.internal;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.content.res.Resources;\nimport android.os.Parcel;\nimport android.os.RemoteException;\nimport androidx.annotation.Keep;\nimport android.util.Log;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.dynamic.ObjectWrapper;\nimport com.google.android.gms.maps.GoogleMapOptions;\nimport com.google.android.gms.maps.StreetViewPanoramaOptions;\nimport com.google.android.gms.maps.model.internal.IBitmapDescriptorFactoryDelegate;\n\nimport org.microg.gms.maps.hms.CameraUpdateFactoryImpl;\nimport org.microg.gms.maps.hms.MapFragmentImpl;\nimport org.microg.gms.maps.hms.MapViewImpl;\nimport org.microg.gms.maps.hms.StreetViewPanoramaFragmentImpl;\nimport org.microg.gms.maps.hms.StreetViewPanoramaViewImpl;\nimport org.microg.gms.maps.hms.model.BitmapDescriptorFactoryImpl;\n\n@Keep\npublic class CreatorImpl extends ICreator.Stub {\n    private static final String TAG = \"GmsMapCreator\";\n    public static volatile int VERSION = Integer.MAX_VALUE;\n\n    @Override\n    public void init(IObjectWrapper resources) {\n        initV2(resources, 0);\n    }\n\n    @Override\n    public IMapFragmentDelegate newMapFragmentDelegate(IObjectWrapper activity) {\n        return new MapFragmentImpl(ObjectWrapper.unwrapTyped(activity, Activity.class));\n    }\n\n    @Override\n    public IMapViewDelegate newMapViewDelegate(IObjectWrapper context, GoogleMapOptions options) {\n        return new MapViewImpl(ObjectWrapper.unwrapTyped(context, Context.class), options);\n    }\n\n    @Override\n    public ICameraUpdateFactoryDelegate newCameraUpdateFactoryDelegate() {\n        return new CameraUpdateFactoryImpl();\n    }\n\n    @Override\n    public IBitmapDescriptorFactoryDelegate newBitmapDescriptorFactoryDelegate() {\n        return BitmapDescriptorFactoryImpl.INSTANCE;\n    }\n\n    @Override\n    public void initV2(IObjectWrapper resources, int flags) {\n        BitmapDescriptorFactoryImpl.INSTANCE.initialize(ObjectWrapper.unwrapTyped(resources, Resources.class));\n        VERSION = flags;\n        //ResourcesContainer.set((Resources) ObjectWrapper.unwrap(resources));\n        Log.d(TAG, \"initV2 \" + flags);\n    }\n\n    @Override\n    public IStreetViewPanoramaViewDelegate newStreetViewPanoramaViewDelegate(IObjectWrapper context, StreetViewPanoramaOptions options) {\n        return new StreetViewPanoramaViewImpl(ObjectWrapper.unwrapTyped(context, Context.class));\n    }\n\n    @Override\n    public IStreetViewPanoramaFragmentDelegate newStreetViewPanoramaFragmentDelegate(IObjectWrapper activity) {\n        return new StreetViewPanoramaFragmentImpl(ObjectWrapper.unwrapTyped(activity, Activity.class));\n    }\n\n    @Override\n    public int getRendererType() throws RemoteException {\n        return 2;\n    }\n\n    @Override\n    public void logInitialization(IObjectWrapper context, int preferredRenderer) throws RemoteException {\n        Log.d(TAG, \"HMS-based Map initialized (preferred renderer was \" + preferredRenderer + \")\");\n    }\n\n    @Override\n    public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {\n        if (super.onTransact(code, data, reply, flags)) return true;\n        Log.d(TAG, \"onTransact [unknown]: \" + code + \", \" + data + \", \" + flags);\n        return false;\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/hms/src/main/kotlin/org/microg/gms/maps/hms/CameraUpdateFactory.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.maps.hms\n\nimport android.graphics.Point\nimport android.os.Parcel\nimport android.util.Log\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.ObjectWrapper\nimport com.google.android.gms.maps.internal.ICameraUpdateFactoryDelegate\nimport com.google.android.gms.maps.model.CameraPosition\nimport com.google.android.gms.maps.model.LatLng\nimport com.google.android.gms.maps.model.LatLngBounds\nimport com.huawei.hms.maps.CameraUpdateFactory\nimport org.microg.gms.maps.hms.utils.toHms\nimport org.microg.gms.maps.hms.utils.toHmsZoom\n\nclass CameraUpdateFactoryImpl : ICameraUpdateFactoryDelegate.Stub() {\n\n    override fun zoomIn(): IObjectWrapper = ObjectWrapper.wrap(CameraUpdateFactory.zoomIn())\n    override fun zoomOut(): IObjectWrapper = ObjectWrapper.wrap(CameraUpdateFactory.zoomOut())\n\n    override fun zoomTo(zoom: Float): IObjectWrapper =\n            ObjectWrapper.wrap(CameraUpdateFactory.zoomTo(toHmsZoom(zoom)))\n\n    override fun zoomBy(zoomDelta: Float): IObjectWrapper =\n            ObjectWrapper.wrap(CameraUpdateFactory.zoomBy(zoomDelta))\n\n    override fun zoomByWithFocus(zoomDelta: Float, x: Int, y: Int): IObjectWrapper =\n            ObjectWrapper.wrap(CameraUpdateFactory.zoomBy(zoomDelta, Point(x, y)))\n\n    override fun newCameraPosition(cameraPosition: CameraPosition): IObjectWrapper =\n            ObjectWrapper.wrap(CameraUpdateFactory.newCameraPosition(cameraPosition.toHms()))\n\n    override fun newLatLng(latLng: LatLng): IObjectWrapper =\n            ObjectWrapper.wrap(CameraUpdateFactory.newLatLng(latLng.toHms()))\n\n    override fun newLatLngZoom(latLng: LatLng, zoom: Float): IObjectWrapper =\n            ObjectWrapper.wrap(CameraUpdateFactory.newLatLngZoom(latLng.toHms(),\n                toHmsZoom(zoom)\n            ))\n\n    override fun newLatLngBounds(bounds: LatLngBounds, padding: Int): IObjectWrapper =\n            ObjectWrapper.wrap(CameraUpdateFactory.newLatLngBounds(bounds.toHms(), padding))\n\n    override fun scrollBy(x: Float, y: Float): IObjectWrapper {\n        Log.d(TAG, \"scrollBy: $x, $y\")\n        // gms map: A positive value moves the camera downwards\n        // hms map: A positive value moves the camera upwards\n        return ObjectWrapper.wrap(CameraUpdateFactory.scrollBy(x, -y))\n    }\n\n    override fun newLatLngBoundsWithSize(bounds: LatLngBounds, width: Int, height: Int, padding: Int): IObjectWrapper =\n        ObjectWrapper.wrap(CameraUpdateFactory.newLatLngBounds(bounds.toHms(), width, height, padding))\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =\n            if (super.onTransact(code, data, reply, flags)) {\n                true\n            } else {\n                Log.d(TAG, \"onTransact [unknown]: $code, $data, $flags\"); false\n            }\n\n    companion object {\n        private val TAG = \"GmsCameraUpdate\"\n    }\n}\n\n\n"
  },
  {
    "path": "play-services-maps/core/hms/src/main/kotlin/org/microg/gms/maps/hms/GoogleMap.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.maps.hms\n\nimport android.content.Context\nimport android.graphics.Bitmap\nimport android.location.Location\nimport android.os.*\nimport android.os.Build.VERSION.SDK_INT\nimport android.util.DisplayMetrics\nimport android.util.Log\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.FrameLayout\nimport android.widget.ImageView\nimport android.widget.LinearLayout\nimport android.widget.RelativeLayout\nimport androidx.annotation.IdRes\nimport androidx.annotation.Keep\nimport androidx.collection.LongSparseArray\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.ObjectWrapper\nimport com.google.android.gms.dynamic.unwrap\nimport com.google.android.gms.maps.GoogleMap.MAP_TYPE_TERRAIN\nimport com.google.android.gms.maps.GoogleMapOptions\nimport com.google.android.gms.maps.internal.*\nimport com.google.android.gms.maps.model.*\nimport com.google.android.gms.maps.model.internal.*\nimport com.huawei.hms.maps.CameraUpdate\nimport com.huawei.hms.maps.HuaweiMap\nimport com.huawei.hms.maps.MapView\nimport com.huawei.hms.maps.MapsInitializer\nimport com.huawei.hms.maps.OnMapReadyCallback\nimport com.huawei.hms.maps.TextureMapView\nimport com.huawei.hms.maps.internal.IOnIndoorStateChangeListener\nimport com.huawei.hms.maps.internal.IOnInfoWindowCloseListener\nimport com.huawei.hms.maps.internal.IOnInfoWindowLongClickListener\nimport com.huawei.hms.maps.internal.IOnPoiClickListener\nimport com.huawei.hms.maps.model.Marker\nimport org.microg.gms.maps.hms.model.*\nimport org.microg.gms.maps.hms.utils.*\nimport java.util.concurrent.CopyOnWriteArrayList\nimport java.util.concurrent.atomic.AtomicBoolean\n\n\nprivate fun <T : Any> LongSparseArray<T>.values() = (0 until size()).mapNotNull { valueAt(it) }\n\nfun runOnMainLooper(forceQueue: Boolean = false, method: () -> Unit) {\n    if (!forceQueue && Looper.myLooper() == Looper.getMainLooper()) {\n        method()\n    } else {\n        Handler(Looper.getMainLooper()).post {\n            method()\n        }\n    }\n}\n\nclass GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) : IGoogleMapDelegate.Stub() {\n\n    internal val mapContext = MapContext(context)\n\n    val view: FrameLayout\n    var map: HuaweiMap? = null\n        private set\n    val dpiFactor: Float\n        get() = context.resources.displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT\n\n    private var mapView: MapView? = null\n    private var created = false\n    private var initialized = false\n    private var loaded = false\n    private val mapLock = Object()\n    private var latLngBounds: LatLngBounds? = null\n\n    private val internalOnInitializedCallbackList = CopyOnWriteArrayList<OnMapReadyCallback>()\n    private val initializedCallbackList = CopyOnWriteArrayList<IOnMapReadyCallback>()\n    private var loadedCallback: IOnMapLoadedCallback? = null\n    private var cameraChangeListener: IOnCameraChangeListener? = null\n    private var cameraMoveListener: IOnCameraMoveListener? = null\n    private var cameraMoveCanceledListener: IOnCameraMoveCanceledListener? = null\n    private var cameraMoveStartedListener: IOnCameraMoveStartedListener? = null\n    private var cameraIdleListener: IOnCameraIdleListener? = null\n    private var mapClickListener: IOnMapClickListener? = null\n    private var mapLongClickListener: IOnMapLongClickListener? = null\n\n    private val groundOverlays = mutableMapOf<String, GroundOverlayImpl>()\n    private val polylines = mutableMapOf<String, PolylineImpl>()\n    private val polygons = mutableMapOf<String, PolygonImpl>()\n    private val circles = mutableMapOf<String, CircleImpl>()\n    private val tileOverlays = mutableMapOf<String, TileOverlayImpl>()\n\n    private var storedMapType: Int = options.mapType\n    val waitingCameraUpdates = mutableListOf<CameraUpdate>()\n\n    private var markerId = 0L\n    val markers = mutableMapOf<String, MarkerImpl>()\n\n    private var projectionImpl: ProjectionImpl? = null\n    private var inDeveloperAnimation = false\n\n    init {\n        BitmapDescriptorFactoryImpl.initialize(context.resources)\n        runOnMainLooper {\n            MapsInitializer.setApiKey(BuildConfig.HMSMAP_KEY)\n        }\n\n        this.view = object : FrameLayout(mapContext) {\n            private val fakeWatermark = ImageView(mapContext).apply {\n                tag = \"GoogleWatermark\"\n                visibility = GONE\n            }\n            private val fakeCompass = View(mapContext).apply {\n                tag = \"GoogleMapCompass\"\n                visibility = GONE\n            }\n            private val fakeZoomInButton = View(mapContext).apply {\n                tag = \"GoogleMapZoomInButton\"\n                visibility = GONE\n            }\n            private val fakeZoomOutButton = View(mapContext).apply {\n                tag = \"GoogleMapZoomOutButton\"\n                visibility = GONE\n            }\n            private val fakeMyLocationButton = View(mapContext).apply {\n                tag = \"GoogleMapMyLocationButton\"\n                visibility = GONE\n            }\n\n            private val fakeZoomButtonRoot = LinearLayout(mapContext).apply {\n                addView(fakeZoomInButton)\n                addView(fakeZoomOutButton)\n                visibility = GONE\n            }\n\n            private val mapButtonRoot = RelativeLayout(mapContext).apply {\n                addView(fakeZoomButtonRoot)\n                addView(fakeMyLocationButton)\n                addView(fakeCompass)\n                addView(fakeWatermark)\n                visibility = GONE\n            }\n\n            override fun onAttachedToWindow() {\n                super.onAttachedToWindow()\n                addView(mapButtonRoot)\n            }\n\n            override fun onDetachedFromWindow() {\n                super.onDetachedFromWindow()\n                removeView(mapButtonRoot)\n            }\n\n            @Keep\n            fun <T : View> findViewTraversal(@IdRes id: Int): T? {\n                if (1 == id) {\n                    return try {\n                        @Suppress(\"UNCHECKED_CAST\")\n                        mapButtonRoot as T\n                    } catch (e: ClassCastException) {\n                        null\n                    }\n                }\n                if (2 == id) {\n                    return try {\n                        @Suppress(\"UNCHECKED_CAST\")\n                        fakeMyLocationButton as T\n                    } catch (e: ClassCastException) {\n                        null\n                    }\n                }\n                return null\n            }\n\n            @Keep\n            fun <T : View> findViewWithTagTraversal(tag: Any): T? {\n                if (\"GoogleWatermark\" == tag) {\n                    return try {\n                        @Suppress(\"UNCHECKED_CAST\")\n                        fakeWatermark as T\n                    } catch (e: ClassCastException) {\n                        null\n                    }\n                }\n                if (\"GoogleMapCompass\" == tag) {\n                    return try {\n                        @Suppress(\"UNCHECKED_CAST\")\n                        fakeCompass as T\n                    } catch (e: ClassCastException) {\n                        null\n                    }\n                }\n                if (\"GoogleMapZoomInButton\" == tag) {\n                    return try {\n                        @Suppress(\"UNCHECKED_CAST\")\n                        fakeZoomInButton as T\n                    } catch (e: ClassCastException) {\n                        null\n                    }\n                }\n                if (\"GoogleMapZoomOutButton\" == tag) {\n                    return try {\n                        @Suppress(\"UNCHECKED_CAST\")\n                        fakeZoomOutButton as T\n                    } catch (e: ClassCastException) {\n                        null\n                    }\n                }\n                if (\"GoogleMapMyLocationButton\" == tag) {\n                    return try {\n                        @Suppress(\"UNCHECKED_CAST\")\n                        fakeMyLocationButton as T\n                    } catch (e: ClassCastException) {\n                        null\n                    }\n                }\n                return null\n            }\n        }\n    }\n\n    override fun getCameraPosition(): CameraPosition {\n        return map?.cameraPosition?.toGms() ?: CameraPosition(LatLng(0.0, 0.0), 0f, 0f, 0f)\n    }\n    override fun getMaxZoomLevel(): Float = toHmsZoom(map?.maxZoomLevel ?: 18.toFloat())\n    override fun getMinZoomLevel(): Float = toHmsZoom(map?.minZoomLevel ?: 3.toFloat())\n\n    override fun moveCamera(cameraUpdate: IObjectWrapper?) {\n        val update = cameraUpdate.unwrap<CameraUpdate>() ?: return\n        synchronized(mapLock) {\n            if (initialized) {\n                this.map?.moveCamera(update)\n            } else {\n                waitingCameraUpdates.add(update)\n            }\n        }\n    }\n\n    override fun animateCamera(cameraUpdate: IObjectWrapper?) {\n        val update = cameraUpdate.unwrap<CameraUpdate>() ?: return\n        synchronized(mapLock) {\n            if (initialized) {\n                this.map?.animateCamera(update)\n            } else {\n                waitingCameraUpdates.add(update)\n            }\n        }\n    }\n\n    override fun animateCameraWithCallback(cameraUpdate: IObjectWrapper?, callback: ICancelableCallback?) {\n        val update = cameraUpdate.unwrap<CameraUpdate>() ?: return\n        synchronized(mapLock) {\n            if (initialized) {\n                Log.d(TAG, \"animateCameraWithCallback start \")\n                inDeveloperAnimation = true\n                this.map?.animateCamera(update, object : HuaweiMap.CancelableCallback {\n                    override fun onFinish() {\n                        Log.d(TAG, \"animateCameraWithCallback onFinish: \")\n                        inDeveloperAnimation = false\n                        callback?.onFinish()\n                    }\n\n                    override fun onCancel() {\n                        Log.d(TAG, \"animateCameraWithCallback onCancel: \")\n                        inDeveloperAnimation = false\n                        callback?.onCancel()\n                    }\n                })\n            } else {\n                waitingCameraUpdates.add(update)\n                afterInitialize { callback?.onFinish() }\n            }\n        }\n    }\n\n    override fun animateCameraWithDurationAndCallback(\n            cameraUpdate: IObjectWrapper?,\n            duration: Int,\n            callback: ICancelableCallback?\n    ) {\n        val update = cameraUpdate.unwrap<CameraUpdate>() ?: return\n        synchronized(mapLock) {\n            if (initialized) {\n                Log.d(TAG, \"animateCameraWithDurationAndCallback\")\n                this.map?.animateCamera(update, duration, callback?.toHms())\n            } else {\n                waitingCameraUpdates.add(update)\n                afterInitialize { callback?.onFinish() }\n            }\n        }\n    }\n\n    override fun stopAnimation() = map?.stopAnimation() ?: Unit\n\n    override fun setMapStyle(options: MapStyleOptions?): Boolean {\n        Log.d(TAG, \"setMapStyle: \")\n        val bool = options?.toHms(mapContext).let {\n            map?.setMapStyle(it)\n        }\n        Log.d(TAG, \"setMapStyle: bool: $bool\")\n        return true == bool\n    }\n\n    override fun setMinZoomPreference(minZoom: Float) = afterInitialize {\n        it.setMinZoomPreference(toHmsZoom(minZoom))\n    }\n\n    override fun setMaxZoomPreference(maxZoom: Float) = afterInitialize {\n        it.setMaxZoomPreference(toHmsZoom(maxZoom))\n    }\n\n    override fun resetMinMaxZoomPreference() = afterInitialize {\n        it.setMinZoomPreference(3.toFloat())\n        it.setMaxZoomPreference(18.toFloat())\n    }\n\n    override fun setLatLngBoundsForCameraTarget(bounds: LatLngBounds?) = afterInitialize {\n        if (latLngBounds == null || bounds == null || latLngBounds!! != bounds) {\n            latLngBounds = bounds\n            it.setLatLngBoundsForCameraTarget(bounds?.toHms())\n        }\n    }\n\n    override fun addPolyline(options: PolylineOptions): IPolylineDelegate? {\n        val polyline = map?.addPolyline(options.toHms()) ?: return null\n        val polylineImpl = PolylineImpl(polyline, options)\n        polylines[polylineImpl.id] = polylineImpl\n        return polylineImpl\n    }\n\n    override fun addPolygon(options: PolygonOptions): IPolygonDelegate? {\n        val polygon = map?.addPolygon(options.toHms()) ?: return null\n        val polygonImpl = PolygonImpl(polygon)\n        polygons[polygonImpl.id] = polygonImpl\n        return polygonImpl\n    }\n\n    override fun addMarker(options: MarkerOptions): IMarkerDelegate {\n        val marker = MarkerImpl(this, \"m${markerId++}\", options)\n        if (map != null) {\n            marker.update()\n        } else {\n            markers[marker.id] = marker\n        }\n        return marker\n    }\n\n    override fun addGroundOverlay(options: GroundOverlayOptions): IGroundOverlayDelegate? {\n        Log.d(TAG, \"Method: addGroundOverlay\")\n        if (options.width <= 0 && options.height <= 0 && options.bounds == null) {\n            Log.w(TAG, \"addGroundOverlay options Parameters do not meet requirements\")\n            return null\n        }\n        val groundOverlay = map?.addGroundOverlay(options.toHms()) ?: return null\n        val groundOverlayImpl = GroundOverlayImpl(groundOverlay)\n        groundOverlays[groundOverlayImpl.id] = groundOverlayImpl\n        return groundOverlayImpl\n    }\n\n    override fun addTileOverlay(options: TileOverlayOptions): ITileOverlayDelegate? {\n        Log.d(TAG, \"Method: addTileOverlay\")\n        val tileOverlay = map?.addTileOverlay(options.toHms()) ?: return null\n        val tileOverlayImpl = TileOverlayImpl(tileOverlay)\n        tileOverlays[tileOverlayImpl.id] = tileOverlayImpl\n        return tileOverlayImpl\n    }\n\n    override fun addCircle(options: CircleOptions): ICircleDelegate? {\n        val circle = map?.addCircle(options.toHms()) ?: return null\n        val circleImpl = CircleImpl(circle)\n        circles[circleImpl.id] = circleImpl\n        return circleImpl\n    }\n\n    override fun clear() {\n        map?.clear()\n    }\n\n\n    override fun getMapType(): Int {\n        return map?.mapType ?: storedMapType\n    }\n\n    override fun setMapType(type: Int) {\n        storedMapType = type\n        applyMapType()\n    }\n\n    fun applyMapType() {\n        // TODO: Serve map styles locally\n        Log.d(TAG, \"Method: applyMapType -> $storedMapType\")\n        when (storedMapType) {\n            MAP_TYPE_TERRAIN -> map?.mapType = HuaweiMap.MAP_TYPE_TERRAIN\n            // MAP_TYPE_SATELLITE, MAP_TYPE_HYBRID, MAP_TYPE_NONE, MAP_TYPE_NORMAL,\n            else -> map?.mapType = HuaweiMap.MAP_TYPE_NORMAL\n        }\n        // map?.let { BitmapDescriptorFactoryImpl.registerMap(it) }\n    }\n\n    override fun isTrafficEnabled(): Boolean {\n        return map?.isTrafficEnabled ?: false\n    }\n\n    override fun setTrafficEnabled(traffic: Boolean) = afterInitialize {\n        Log.d(TAG, \"setTrafficEnabled\")\n        it.isTrafficEnabled = traffic\n    }\n\n    override fun isIndoorEnabled(): Boolean {\n        Log.d(TAG, \"isIndoorEnabled\")\n        return map?.isIndoorEnabled ?: false\n    }\n\n    override fun setIndoorEnabled(indoor: Boolean) = afterInitialize {\n        Log.d(TAG, \"setIndoorEnabled\")\n        it.isIndoorEnabled = indoor\n    }\n\n    override fun isMyLocationEnabled(): Boolean {\n        return map?.isMyLocationEnabled ?: false\n    }\n\n    override fun setMyLocationEnabled(myLocation: Boolean) = afterInitialize {\n        Log.d(TAG, \"setMyLocationEnabled $myLocation\")\n        it.isMyLocationEnabled = myLocation\n    }\n\n    override fun getMyLocation(): Location? {\n        Log.d(TAG, \"deprecated Method: getMyLocation\")\n        return null\n    }\n\n    override fun setLocationSource(locationSource: ILocationSourceDelegate?) = afterInitialize {\n        Log.d(TAG, \"unimplemented Method: setLocationSource\")\n    }\n\n    override fun setContentDescription(desc: String?) = afterInitialize {\n        Log.d(TAG, \"setContentDescription desc -> $desc\")\n        it.setContentDescription(desc)\n    }\n\n    override fun getUiSettings(): IUiSettingsDelegate =\n        map?.uiSettings?.let { UiSettingsImpl(it, view) } ?: UiSettingsCache(view).also {\n            internalOnInitializedCallbackList.add(it.getMapReadyCallback())\n        }\n\n    override fun getProjection(): IProjectionDelegate {\n        return projectionImpl ?: map?.projection?.let {\n            val experiment = try {\n                map?.cameraPosition?.tilt == 0.0f && map?.cameraPosition?.bearing == 0.0f\n            } catch (e: Exception) {\n                Log.w(TAG, e);false\n            }\n            ProjectionImpl(it, experiment)\n        }?.also { projectionImpl = it } ?: DummyProjection()\n    }\n\n    override fun setOnCameraChangeListener(listener: IOnCameraChangeListener?) = afterInitialize {\n        Log.d(TAG, \"setOnCameraChangeListener\");\n        cameraChangeListener = listener\n    }\n\n    override fun setOnCircleClickListener(listener: IOnCircleClickListener?) = afterInitialize { hmap ->\n        Log.d(TAG, \"setOnCircleClickListener\")\n        hmap.setOnCircleClickListener { listener?.onCircleClick(circles[it.id]) }\n    }\n\n    override fun setOnGroundOverlayClickListener(listener: IOnGroundOverlayClickListener?) =\n            afterInitialize { hmap ->\n                Log.d(TAG, \"Method: setOnGroundOverlayClickListener\")\n                hmap.setOnGroundOverlayClickListener { listener?.onGroundOverlayClick(groundOverlays[it.id]) }\n            }\n\n    override fun setOnInfoWindowLongClickListener(listener: com.google.android.gms.maps.internal.IOnInfoWindowLongClickListener?) =\n            afterInitialize {\n                Log.d(TAG, \"Not yet implemented setInfoWindowLongClickListener\")\n            }\n\n    fun setOnIndoorStateChangeListener(listener: IOnIndoorStateChangeListener?) {\n        Log.d(TAG, \"unimplemented Method: setOnIndoorStateChangeListener\")\n    }\n\n    override fun setOnMapClickListener(listener: IOnMapClickListener?) = afterInitialize {\n        mapClickListener = listener\n        it.setOnMapClickListener { latlng ->\n            try {\n                mapClickListener?.onMapClick(latlng.toGms())\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n            }\n        }\n    }\n\n    override fun setOnMapLongClickListener(listener: IOnMapLongClickListener?) = afterInitialize {\n        mapLongClickListener = listener\n        it.setOnMapLongClickListener { latlng ->\n            try {\n                mapLongClickListener?.onMapLongClick(latlng.toGms())\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n            }\n        }\n    }\n\n    override fun setOnMarkerClickListener(listener: IOnMarkerClickListener?) = afterInitialize { hmap ->\n        hmap.setOnMarkerClickListener {\n            Log.d(\"GmsGoogleMap\", \"setOnMarkerClickListener marker id -> ${it.id}\")\n            listener?.onMarkerClick(markers[it.id]) ?: false\n        }\n    }\n\n    override fun setOnMarkerDragListener(listener: IOnMarkerDragListener?) = afterInitialize {\n        it.setOnMarkerDragListener(object : HuaweiMap.OnMarkerDragListener {\n            override fun onMarkerDragStart(p0: Marker?) {\n                listener?.onMarkerDragStart(markers[p0?.id])\n            }\n\n            override fun onMarkerDrag(p0: Marker?) {\n                listener?.onMarkerDrag(markers[p0?.id])\n            }\n\n            override fun onMarkerDragEnd(p0: Marker?) {\n                listener?.onMarkerDragEnd(markers[p0?.id])\n            }\n        })\n    }\n\n    override fun setOnInfoWindowClickListener(listener: IOnInfoWindowClickListener?) = afterInitialize { hmap ->\n        Log.d(TAG, \"setOnInfoWindowClickListener\")\n        hmap.setOnInfoWindowClickListener { listener?.onInfoWindowClick(markers[it.id]) }\n    }\n\n    fun setOnInfoWindowCloseListener(listener: IOnInfoWindowCloseListener?) {\n        Log.d(TAG, \"unimplemented Method: setOnInfoWindowCloseListener\")\n    }\n\n    fun setOnInfoWindowLongClickListener(listener: IOnInfoWindowLongClickListener?) {\n        Log.d(TAG, \"unimplemented Method: setOnInfoWindowLongClickListener\")\n    }\n\n    override fun setInfoWindowAdapter(adapter: IInfoWindowAdapter?) = afterInitialize {\n        Log.d(TAG, \"setInfoWindowAdapter\")\n        it.setInfoWindowAdapter(object : HuaweiMap.InfoWindowAdapter {\n            override fun getInfoContents(p0: Marker?): View? {\n                return adapter?.getInfoContents(markers[p0?.id]).unwrap<View>()\n            }\n\n            override fun getInfoWindow(p0: Marker?): View? {\n                return adapter?.getInfoWindow(markers[p0?.id]).unwrap<View>()\n            }\n\n        })\n    }\n\n    override fun setOnMyLocationChangeListener(listener: IOnMyLocationChangeListener?) = afterInitialize {\n        Log.d(TAG, \"deprecated Method: setOnMyLocationChangeListener\")\n    }\n\n    override fun setOnMyLocationButtonClickListener(listener: IOnMyLocationButtonClickListener?) = afterInitialize {\n        Log.d(TAG, \"setOnMyLocationButtonClickListener\")\n        it.setOnMyLocationButtonClickListener { listener?.onMyLocationButtonClick() ?: false }\n    }\n\n    override fun setOnMyLocationClickListener(listener: IOnMyLocationClickListener?) = afterInitialize { hmap ->\n        Log.d(TAG, \"setOnMyLocationClickListener\")\n        hmap.setOnMyLocationClickListener { listener?.onMyLocationClick(it) }\n    }\n\n    fun setOnPoiClickListener(listener: IOnPoiClickListener?) {\n        Log.d(TAG, \"unimplemented Method: setOnPoiClickListener\")\n    }\n\n    override fun setOnPolygonClickListener(listener: IOnPolygonClickListener?) = afterInitialize { hmap ->\n        Log.d(TAG, \"setOnPolygonClickListener\")\n        hmap.setOnPolygonClickListener { listener?.onPolygonClick(polygons[it.id]) }\n    }\n\n    override fun setOnInfoWindowCloseListener(listener: com.google.android.gms.maps.internal.IOnInfoWindowCloseListener?) =\n            afterInitialize {\n                Log.d(TAG, \"Not yet implemented setInfoWindowCloseListener\")\n            }\n\n\n    override fun setOnPolylineClickListener(listener: IOnPolylineClickListener?) = afterInitialize { hmap ->\n        Log.d(TAG, \"unimplemented Method: setOnPolylineClickListener\")\n        hmap.setOnPolylineClickListener { listener?.onPolylineClick(polylines[it.id]) }\n    }\n\n    override fun snapshot(callback: ISnapshotReadyCallback, bitmap: IObjectWrapper?) = afterInitialize {\n        Log.d(TAG, \"taking snapshot now\")\n        val hmsBitmap = bitmap.unwrap<Bitmap>()\n        Log.d(TAG, \"provided bitmap. $hmsBitmap\")\n        val hmsCallback = HuaweiMap.SnapshotReadyCallback { result ->\n                runOnMainLooper {\n                    Log.d(TAG, \"take snapshot end. $result\")\n                    if (CreatorImpl.VERSION < SNAPSHOT_OLD_VERSION_CODE) {\n                        callback.onBitmapReady(result)\n                    } else callback.onBitmapWrappedReady(ObjectWrapper.wrap(result))\n                }\n        }\n        if (hmsBitmap != null) it.snapshot(hmsCallback, hmsBitmap) else it.snapshot(hmsCallback)\n    }\n\n    override fun snapshotForTest(callback: ISnapshotReadyCallback) = afterInitialize {\n        Log.d(TAG, \"snapshotForTest\")\n        val hmsCallback = HuaweiMap.SnapshotReadyCallback { p0 -> callback.onBitmapReady(p0) }\n        it.snapshot(hmsCallback)\n    }\n\n    override fun setPadding(left: Int, top: Int, right: Int, bottom: Int) = afterInitialize {\n        Log.d(TAG, \"setPadding: $left $top $right $bottom\")\n        it.setPadding(left, top, right, bottom)\n    }\n\n    override fun isBuildingsEnabled(): Boolean {\n        Log.d(TAG, \"isBuildingsEnabled\")\n        return map?.isBuildingsEnabled ?: true\n    }\n\n    override fun setBuildingsEnabled(buildings: Boolean) = afterInitialize {\n        Log.d(TAG, \"setBuildingsEnabled: $buildings\")\n        it.isBuildingsEnabled = buildings\n    }\n\n    override fun setOnMapLoadedCallback(callback: IOnMapLoadedCallback?) {\n        if (callback != null) {\n            synchronized(mapLock) {\n                if (loaded) {\n                    Log.d(TAG, \"Invoking callback instantly, as map is loaded\")\n                    try {\n                        scheduleExecute { callback.onMapLoaded() }\n                    } catch (e: Exception) {\n                        Log.w(TAG, e)\n                    }\n                } else {\n                    Log.d(TAG, \"Delay callback invocation, as map is not yet loaded\")\n                    loadedCallback = callback\n                }\n            }\n        } else {\n            loadedCallback = null\n        }\n    }\n\n    override fun setCameraMoveStartedListener(listener: IOnCameraMoveStartedListener?) = afterInitialize { hmap ->\n        Log.d(TAG, \"setCameraMoveStartedListener\")\n        cameraMoveStartedListener = listener\n        hmap.setOnCameraMoveStartedListener {\n            if (it == HuaweiMap.OnCameraMoveStartedListener.REASON_DEVELOPER_ANIMATION && inDeveloperAnimation) {\n                Log.d(TAG, \"onCameraMoveStarted <inDeveloperAnimation> skipped: 1st \")\n                return@setOnCameraMoveStartedListener\n            }\n            try {\n                Log.d(TAG, \"Listener: onCameraMoveStarted: \")\n                cameraMoveStartedListener?.onCameraMoveStarted(it)\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n            }\n        }\n    }\n\n    override fun setCameraMoveListener(listener: IOnCameraMoveListener?) = afterInitialize {\n        Log.d(TAG, \"setCameraMoveListener\")\n        cameraMoveListener = listener\n        it.setOnCameraMoveListener {\n            try {\n                Log.d(TAG, \"Listener: onCameraMove: \")\n                if (SDK_INT >= 26) {\n                    mapView?.let { it.parent?.onDescendantInvalidated(it, it) }\n                }\n                map?.let { projectionImpl?.updateProjectionState(it.cameraPosition, it.projection) }\n                cameraMoveListener?.onCameraMove()\n                cameraChangeListener?.onCameraChange(map?.cameraPosition?.toGms())\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n            }\n        }\n    }\n\n    override fun setCameraMoveCanceledListener(listener: IOnCameraMoveCanceledListener?) = afterInitialize {\n        Log.d(TAG, \"setCameraMoveCanceledListener\")\n        cameraMoveCanceledListener = listener\n        it.setOnCameraMoveCanceledListener {\n            try {\n                Log.d(TAG, \"setOnCameraMoveCanceledListener: \")\n                cameraMoveCanceledListener?.onCameraMoveCanceled()\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n            }\n        }\n    }\n\n    override fun setCameraIdleListener(listener: IOnCameraIdleListener?) = afterInitialize {\n        Log.d(TAG, \"setCameraIdleListener\")\n        cameraIdleListener = listener\n    }\n\n    override fun getTestingHelper(): IObjectWrapper? {\n        Log.d(TAG, \"unimplemented Method: getTestingHelper\")\n        return null\n    }\n\n    override fun setWatermarkEnabled(watermark: Boolean) {\n        Log.d(TAG, \"unimplemented Method: setWatermarkEnabled\")\n    }\n\n    override fun useViewLifecycleWhenInFragment(): Boolean {\n        Log.d(TAG, \"unimplemented Method: useViewLifecycleWhenInFragment\")\n        return false\n    }\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        if (!created) {\n            Log.d(TAG_LOGO, \"create: ${context.packageName},\\n$options\")\n            MapsInitializer.initialize(mapContext)\n            val mapView = runCatching { \n                TextureMapView(mapContext, options.toHms())\n            }.onFailure {\n                Log.w(TAG, \"onCreate: init TextureMapView error \", it)\n            }.getOrDefault(MapView(mapContext, options.toHms())).apply { visibility = View.INVISIBLE }\n            this.mapView = mapView\n            view.addView(mapView)\n            mapView.onCreate(savedInstanceState?.toHms())\n            mapView.getMapAsync(this::initMap)\n\n            created = true\n            runOnMainLooper(forceQueue = true) { tryRunUserInitializedCallbacks(\"onCreate\") }\n        }\n    }\n\n    private fun fakeWatermark(method: () -> Unit) {\n        Log.d(TAG_LOGO, \"start -> $view\")\n        val view1 = view.getChildAt(0) as? ViewGroup\n        val view2 = view1?.getChildAt(0) as? ViewGroup\n        val view4 = view2?.getChildAt(1)\n        Log.d(TAG_LOGO, view4?.toString() ?: \"view4 is null\")\n        if (view4 is LinearLayout) {\n            view4.visibility = View.GONE\n            method()\n        } else {\n            Log.d(TAG_LOGO, \"LinearLayout not found\")\n        }\n    }\n\n    private fun getAllChildViews(view: View, index: Int): List<View>? {\n        Log.d(TAG_LOGO, \"getAllChildViews: $index, $view\")\n        if (view is LinearLayout) {\n            Log.d(TAG_LOGO, \"legal: $index\")\n            view.visibility = View.GONE\n        }\n        val allChildren: MutableList<View> = ArrayList()\n        if (view is ViewGroup) {\n            val vp = view\n            for (i in 0 until vp.childCount) {\n                val viewChild = vp.getChildAt(i)\n                Log.d(TAG_LOGO, \"child:$index, $i, $viewChild\")\n                allChildren.add(viewChild)\n                allChildren.addAll(getAllChildViews(viewChild, index + 1)!!)\n            }\n        }\n        return allChildren\n    }\n\n    private fun initMap(map: HuaweiMap) {\n        if (this.map != null && initialized) return\n\n        loaded = true\n        this.map = map\n\n        map.setOnCameraIdleListener {\n            Log.d(TAG, \"initMap: onCameraIdle: \")\n            try {\n                cameraChangeListener?.onCameraChange(map.cameraPosition.toGms())\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n            }\n\n            try {\n                cameraIdleListener?.onCameraIdle()\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n            }\n        }\n\n        map.setOnCameraMoveListener {\n            Log.d(TAG, \"initMap: onCameraMove: \")\n            try {\n                if (SDK_INT >= 26) {\n                    mapView?.let { it.parent?.onDescendantInvalidated(it, it) }\n                }\n                map.let { projectionImpl?.updateProjectionState(it.cameraPosition, it.projection) }\n                cameraMoveListener?.onCameraMove()\n                cameraChangeListener?.onCameraChange(map.cameraPosition?.toGms())\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n            }\n        }\n        map.setOnCameraMoveStartedListener {\n            Log.d(TAG, \"initMap: onCameraMoveStarted: $it\")\n            try {\n                cameraMoveStartedListener?.onCameraMoveStarted(it)\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n            }\n        }\n        map.setOnCameraMoveCanceledListener {\n            Log.d(TAG, \"initMap: onCameraMoveCanceled: \")\n            try {\n                cameraMoveCanceledListener?.onCameraMoveCanceled()\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n            }\n        }\n        map.setOnMapClickListener { latlng ->\n            try {\n                if (options.liteMode) {\n                    val parentView = view.parent?.parent\n                    // TODO hms not support disable click listener when liteMode, this just fix for teams\n                    if (parentView != null && parentView::class.qualifiedName.equals(\"com.microsoft.teams.location.ui.map.MapViewLite\")) {\n                        val clickView = parentView as ViewGroup\n                        clickView.performClick()\n                        return@setOnMapClickListener\n                    }\n                }\n                mapClickListener?.onMapClick(latlng.toGms())\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n            }\n        }\n        map.setOnMapLongClickListener { latlng ->\n            try {\n                if (options.liteMode) {\n                    val parentView = view.parent?.parent\n                    // TODO hms not support disable click listener when liteMode, this just fix for teams\n                    if (parentView != null && parentView::class.qualifiedName.equals(\"com.microsoft.teams.location.ui.map.MapViewLite\")) {\n                        val clickView = parentView as ViewGroup\n                        clickView.performLongClick()\n                        return@setOnMapLongClickListener\n                    }\n                }\n                mapLongClickListener?.onMapLongClick(latlng.toGms())\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n            }\n        }\n\n        synchronized(mapLock) {\n            initialized = true\n            markers.filter { it.key.startsWith(\"m\") }.forEach { it.value.update() }\n            waitingCameraUpdates.forEach { map.moveCamera(it) }\n            val initializedCallbacks = ArrayList(internalOnInitializedCallbackList)\n            Log.d(TAG, \"Invoking ${initializedCallbacks.size} internal callbacks now that the true map is initialized\")\n            for (callback in initializedCallbacks) {\n                callback.onMapReady(map)\n            }\n            internalOnInitializedCallbackList.clear()\n            fakeWatermark { Log.d(TAG_LOGO, \"fakeWatermark success\") }\n            scheduleExecute { loadedCallback?.onMapLoaded() }\n\n            mapView?.visibility = View.VISIBLE\n        }\n\n        tryRunUserInitializedCallbacks(tag = \"initMap\")\n    }\n\n    override fun onResume() {\n        mapView?.visibility = View.VISIBLE\n        mapView?.onResume()\n    }\n    override fun onPause() = mapView?.onPause() ?: Unit\n    override fun onDestroy() {\n        Log.d(TAG, \"onDestroy\")\n        initializedCallbackList.clear()\n        internalOnInitializedCallbackList.clear()\n        circles.map { it.value.remove() }\n        circles.clear()\n        polylines.map { it.value.remove() }\n        polylines.clear()\n        polygons.map { it.value.remove() }\n        polygons.clear()\n        markers.map { it.value.remove() }\n        markers.clear()\n//        BitmapDescriptorFactoryImpl.unregisterMap(map)\n        view.removeView(mapView)\n        // TODO can crash?\n        mapView?.onDestroy()\n        mapView = null\n\n        // Don't make it null; this object is not deleted immediately, and it may want to access map.* stuff\n        //map = null\n\n        created = false\n        initialized = false\n        loaded = false\n    }\n\n    override fun onStart() {\n        mapView?.onStart()\n    }\n\n    override fun onStop() {\n        mapView?.visibility = View.INVISIBLE\n        mapView?.onStop()\n    }\n\n    override fun onEnterAmbient(bundle: Bundle?) {\n        Log.d(TAG, \"unimplemented Method: onEnterAmbient\")\n    }\n\n    override fun onExitAmbient() {\n        Log.d(TAG, \"unimplemented Method: onExitAmbient\")\n    }\n\n    override fun onLowMemory() = mapView?.onLowMemory() ?: Unit\n    override fun onSaveInstanceState(outState: Bundle) {\n        val newBundle = Bundle()\n        mapView?.onSaveInstanceState(newBundle)\n        outState.putAll(newBundle.toGms())\n    }\n\n    fun getMapAsync(callback: IOnMapReadyCallback) {\n        synchronized(mapLock) {\n            initializedCallbackList.add(callback)\n        }\n        tryRunUserInitializedCallbacks(\"getMapAsync\")\n    }\n\n    private fun afterInitialize(runnable: (HuaweiMap) -> Unit) {\n        synchronized(mapLock) {\n            if (initialized) {\n                runnable(map!!)\n            } else {\n                internalOnInitializedCallbackList.add(OnMapReadyCallback {\n                    runnable(it)\n                })\n            }\n        }\n    }\n\n    private var isInvokingInitializedCallbacks = AtomicBoolean(false)\n    private fun tryRunUserInitializedCallbacks(tag: String = \"\") {\n\n        synchronized(mapLock) {\n            if (initializedCallbackList.isEmpty()) return\n        }\n\n        val runCallbacks = {\n            val callbacks = synchronized(mapLock) {\n                ArrayList(initializedCallbackList)\n                    .also { initializedCallbackList.clear() }\n            }\n\n            callbacks.forEach {\n                try {\n                    it.onMapReady(this)\n                } catch (e: Exception) {\n                    Log.w(TAG, e)\n                }\n            }\n        }\n\n        if (initialized && map != null) {\n            Log.d(\"$TAG:$tag\", \"Invoking callback now, as map is initialized\")\n            val wasCallbackActive = isInvokingInitializedCallbacks.getAndSet(true)\n            runOnMainLooper(forceQueue = wasCallbackActive) {\n                scheduleExecute { runCallbacks() }\n            }\n            if (!wasCallbackActive) isInvokingInitializedCallbacks.set(false)\n        } else {\n            Log.d(\n                    \"$TAG:$tag\",\n                    \"Initialized callbacks could not be run at this point, as the map view has not been created yet.\"\n            )\n        }\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =\n            if (super.onTransact(code, data, reply, flags)) {\n                Log.d(TAG, \"onTransact: $code, $data, $flags\")\n                true\n            } else {\n                Log.w(TAG, \"onTransact [unknown]: $code, $data, $flags\"); false\n            }\n\n\n    private fun scheduleExecute(block:() -> Unit) {\n        Handler(Looper.getMainLooper()).postDelayed({\n            try { block.invoke() } catch (_: Exception) {}\n        }, ON_MAP_CALLBACK_DELAY)\n    }\n\n    companion object {\n        private const val TAG = \"GmsGoogleMap\"\n        private const val SNAPSHOT_OLD_VERSION_CODE = 4000000\n\n        private const val TAG_LOGO = \"fakeWatermark\"\n        private const val ON_MAP_CALLBACK_DELAY = 300L\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/hms/src/main/kotlin/org/microg/gms/maps/hms/MapFragment.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.maps.hms\n\nimport android.app.Activity\nimport android.os.Bundle\nimport android.os.Parcel\nimport android.util.Log\nimport android.view.ViewGroup\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.ObjectWrapper\nimport com.google.android.gms.maps.GoogleMapOptions\nimport com.google.android.gms.maps.internal.IGoogleMapDelegate\nimport com.google.android.gms.maps.internal.IMapFragmentDelegate\nimport com.google.android.gms.maps.internal.IOnMapReadyCallback\n\nclass MapFragmentImpl(private val activity: Activity) : IMapFragmentDelegate.Stub() {\n\n    private var map: GoogleMapImpl? = null\n    private var options: GoogleMapOptions? = null\n    private var readyCallbackList: MutableList<IOnMapReadyCallback> = mutableListOf()\n\n    override fun onInflate(activity: IObjectWrapper, options: GoogleMapOptions, savedInstanceState: Bundle?) {\n        Log.d(TAG, \"onInflate: $options\")\n        this.options = options\n        map?.options = options\n    }\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        if (options == null) {\n            options = savedInstanceState?.getParcelable(\"MapOptions\")\n        }\n        if (options == null) {\n            options = GoogleMapOptions()\n        }\n        Log.d(TAG, \"onCreate $this : $options \")\n        if (map == null) {\n            map = GoogleMapImpl(activity, options ?: GoogleMapOptions())\n        }\n    }\n\n    override fun onCreateView(layoutInflater: IObjectWrapper, container: IObjectWrapper, savedInstanceState: Bundle?): IObjectWrapper {\n        if (options == null) {\n            options = savedInstanceState?.getParcelable(\"MapOptions\")\n        }\n        Log.d(TAG, \"onCreateView: ${options?.camera?.target}\")\n        if (map == null) {\n            map = GoogleMapImpl(activity, options ?: GoogleMapOptions())\n        }\n        Log.d(TAG, \"onCreateView $this : $options\")\n        map!!.onCreate(savedInstanceState)\n        readyCallbackList.forEach { map!!.getMapAsync(it) }\n        readyCallbackList.clear()\n        val view = map!!.view\n        val parent = view.parent as ViewGroup?\n        parent?.removeView(view)\n        return ObjectWrapper.wrap(view)\n    }\n\n    override fun getMap(): IGoogleMapDelegate? = map\n    override fun onEnterAmbient(bundle: Bundle?) = map?.onEnterAmbient(bundle) ?: Unit\n    override fun onExitAmbient() = map?.onExitAmbient() ?: Unit\n    override fun onStart() = map?.onStart() ?: Unit\n    override fun onStop() = map?.onStop() ?: Unit\n    override fun onResume() = map?.onResume() ?: Unit\n    override fun onPause() = map?.onPause() ?: Unit\n    override fun onLowMemory() = map?.onLowMemory() ?: Unit\n    override fun isReady(): Boolean = this.map != null\n    override fun getMapAsync(callback: IOnMapReadyCallback) {\n        Log.d(TAG, \"getMapAsync: map: $map\")\n        if (map == null) {\n            readyCallbackList.add(callback)\n            return\n        }\n        map?.getMapAsync(callback)\n    }\n\n    override fun onDestroyView() {\n        Log.d(TAG, \"onDestroyView: $this : $options\")\n        if (options?.useViewLifecycleInFragment == true) {\n            map?.onDestroy()\n            map = null\n        }\n    }\n\n    override fun onDestroy() {\n        Log.d(TAG, \"onDestroy: $this\")\n        map?.onDestroy()\n        map = null\n        options = null\n    }\n\n    override fun onSaveInstanceState(outState: Bundle) {\n        if (options != null) {\n            outState.putParcelable(\"MapOptions\", options)\n        }\n        map?.onSaveInstanceState(outState)\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean {\n        if (super.onTransact(code, data, reply, flags)) {\n            return true\n        } else {\n            Log.d(TAG, \"onTransact [unknown]: $code, $data, $flags\")\n            return false\n        }\n    }\n\n    companion object {\n        private val TAG = \"GmsMapFragment\"\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/hms/src/main/kotlin/org/microg/gms/maps/hms/MapView.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.maps.hms\n\nimport android.content.Context\nimport android.os.Bundle\nimport android.os.Parcel\nimport android.util.Log\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.ObjectWrapper\nimport com.google.android.gms.maps.GoogleMapOptions\nimport com.google.android.gms.maps.internal.IGoogleMapDelegate\nimport com.google.android.gms.maps.internal.IMapViewDelegate\nimport com.google.android.gms.maps.internal.IOnMapReadyCallback\n\nclass MapViewImpl(private val context: Context, options: GoogleMapOptions?) : IMapViewDelegate.Stub() {\n\n    private var options: GoogleMapOptions = options ?: GoogleMapOptions()\n    private var map: GoogleMapImpl? = null\n    private var readyCallbackList: MutableList<IOnMapReadyCallback> = mutableListOf()\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        Log.d(TAG, \"onCreate: $options\")\n        if (map == null) {\n            map = GoogleMapImpl(context, options)\n        }\n        map!!.onCreate(savedInstanceState)\n        readyCallbackList.forEach { map!!.getMapAsync(it) }\n        readyCallbackList.clear()\n    }\n\n    override fun getMap(): IGoogleMapDelegate? = map\n    override fun onEnterAmbient(bundle: Bundle?) = map?.onEnterAmbient(bundle) ?: Unit\n    override fun onExitAmbient() = map?.onExitAmbient() ?: Unit\n    override fun onStart() = map?.onStart() ?: Unit\n    override fun onStop() = map?.onStop() ?: Unit\n    override fun onResume() = map?.onResume() ?: Unit\n    override fun onPause() = map?.onPause() ?: Unit\n    override fun onDestroy() {\n        map?.onDestroy()\n        map = null\n    }\n\n    override fun onLowMemory() = map?.onLowMemory() ?: Unit\n    override fun onSaveInstanceState(outState: Bundle) = map?.onSaveInstanceState(outState) ?: Unit\n    override fun getView(): IObjectWrapper = ObjectWrapper.wrap(map?.view)\n    override fun getMapAsync(callback: IOnMapReadyCallback) {\n        Log.d(TAG, \"getMapAsync: map: $map\")\n        if (map == null) {\n            readyCallbackList.add(callback)\n            return\n        }\n        map?.getMapAsync(callback)\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =\n            if (super.onTransact(code, data, reply, flags)) {\n                true\n            } else {\n                Log.d(TAG, \"onTransact [unknown]: $code, $data, $flags\"); false\n            }\n\n    companion object {\n        private val TAG = \"GmsMapView\"\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/hms/src/main/kotlin/org/microg/gms/maps/hms/Projection.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.maps.hms\n\nimport android.graphics.Point\nimport android.util.Log\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.ObjectWrapper\nimport com.google.android.gms.dynamic.unwrap\nimport com.google.android.gms.maps.internal.IProjectionDelegate\nimport com.google.android.gms.maps.model.LatLng\nimport com.google.android.gms.maps.model.LatLngBounds\nimport com.google.android.gms.maps.model.VisibleRegion\nimport com.huawei.hms.maps.Projection\nimport com.huawei.hms.maps.model.CameraPosition\nimport org.microg.gms.maps.hms.utils.toGms\nimport org.microg.gms.maps.hms.utils.toHms\nimport kotlin.math.roundToInt\n\nprivate const val TAG = \"GmsProjectionImpl\"\n\nclass ProjectionImpl(private var projection: Projection, private var withoutTiltOrBearing: Boolean) : IProjectionDelegate.Stub() {\n    private var lastVisibleRegion: VisibleRegion? = null\n    private var visibleRegion = projection.visibleRegion\n\n    private var farLeft: Point? = visibleRegion.farLeft?.let { projection.toScreenLocation(it) }\n    private var farRight: Point? = visibleRegion.farRight?.let { projection.toScreenLocation(it) }\n    private var nearLeft: Point? = visibleRegion.nearLeft?.let { projection.toScreenLocation(it) }\n\n    private var farLeftLat = visibleRegion.farLeft?.latitude ?: 0.0\n    private var nearLeftLat = visibleRegion.nearLeft?.latitude ?: 0.0\n    private var farLeftLng = visibleRegion.farLeft?.longitude ?: 0.0\n    private var farRightLng = visibleRegion.farRight?.longitude ?: 0.0\n    private var farLeftX = farLeft?.x ?: 0\n    private var farLeftY = farLeft?.y ?: 0\n    private var farRightX = farRight?.x ?: (farLeftX + 1)\n    private var nearLeftY = nearLeft?.y ?: (farLeftY + 1)\n\n    fun updateProjectionState(cameraPosition: CameraPosition, projection: Projection) {\n        val tilt = cameraPosition.tilt\n        val bearing = cameraPosition.bearing\n        val useFast = tilt < 1f && (bearing % 360f < 1f || bearing % 360f > 359f)\n        Log.d(TAG, \"updateProjectionState: useFastMode: $useFast\")\n\n        visibleRegion = projection.visibleRegion\n        withoutTiltOrBearing = useFast\n\n        farLeft = visibleRegion.farLeft?.let { projection.toScreenLocation(it) }\n        farRight = visibleRegion.farRight?.let { projection.toScreenLocation(it) }\n        nearLeft = visibleRegion.nearLeft?.let { projection.toScreenLocation(it) }\n\n        farLeftLat = visibleRegion.farLeft?.latitude ?: 0.0\n        nearLeftLat = visibleRegion.nearLeft?.latitude ?: 0.0\n        farLeftLng = visibleRegion.farLeft?.longitude ?: 0.0\n        farRightLng = visibleRegion.farRight?.longitude ?: 0.0\n        farLeftX = farLeft?.x ?: 0\n        farLeftY = farLeft?.y ?: 0\n        farRightX = farRight?.x ?: (farLeftX + 1)\n        nearLeftY = nearLeft?.y ?: (farLeftY + 1)\n    }\n\n    private fun isInvalid(): Boolean {\n        return farLeftX == farRightX || farLeftY == nearLeftY || (farRightX == 1 && farLeftX == 0) || (nearLeftY == 1 && farLeftY == 0)\n    }\n\n    override fun fromScreenLocation(obj: IObjectWrapper?): LatLng? = try {\n        obj.unwrap<Point>()?.let {\n            if (withoutTiltOrBearing && farLeft != null && farRight != null && nearLeft != null) {\n                if (isInvalid()) {\n                    Log.w(TAG, \"Invalid projection layout, fallback to SDK\")\n                    projection.fromScreenLocation(Point(it)).toGms()\n                } else {\n                    val xPercent = (it.x.toFloat() - farLeftX) / (farRightX - farLeftX)\n                    val yPercent = (it.y.toFloat() - farLeftY) / (nearLeftY - farLeftY)\n\n                    val lon = farLeftLng + xPercent * (farRightLng - farLeftLng)\n                    val lat = farLeftLat + yPercent * (nearLeftLat - farLeftLat)\n\n                    Log.d(TAG, \"fromScreenLocation: $it -> lat: $lat lon: $lon\")\n\n                    LatLng(lat, lon)\n                }\n            } else {\n                projection.fromScreenLocation(Point(it)).toGms()\n            }\n        }\n    } catch (e: Exception) {\n        Log.d(TAG, \"fromScreenLocation() error\", e)\n        LatLng(0.0, 0.0)\n    }\n\n    override fun toScreenLocation(latLng: LatLng?): IObjectWrapper = try {\n        ObjectWrapper.wrap(latLng?.toHms()?.let {\n            if (withoutTiltOrBearing && farLeft != null && farRight != null && nearLeft != null) {\n                if (isInvalid()) {\n                    Log.w(TAG, \"Invalid projection layout, fallback to SDK\")\n                    projection.toScreenLocation(it).let { p -> Point(p.x, p.y) }\n                } else {\n                    val xPercent = (it.longitude - farLeftLng) / (farRightLng - farLeftLng)\n                    val yPercent = (it.latitude - farLeftLat) / (nearLeftLat - farLeftLat)\n\n                    val x = farLeftX + xPercent * (farRightX - farLeftX)\n                    val y = farLeftY + yPercent * (nearLeftY - farLeftY)\n\n                    Log.d(TAG, \"toScreenLocation: $latLng -> x: $x y: $y\")\n\n                    Point(x.roundToInt(), y.roundToInt())\n                }\n            } else {\n                projection.toScreenLocation(it).let { p -> Point(p.x, p.y) }\n            }\n        })\n    } catch (e: Exception) {\n        Log.d(TAG, \"toScreenLocation() error\", e)\n        ObjectWrapper.wrap(Point(0, 0))\n    }\n\n    override fun getVisibleRegion(): VisibleRegion? {\n        if (visibleRegion.farLeft.latitude.isNaN() || visibleRegion.farLeft.longitude.isNaN()) {\n            return lastVisibleRegion\n        }\n        lastVisibleRegion = visibleRegion.toGms()\n        Log.d(TAG, \"getVisibleRegion: $visibleRegion\")\n        return lastVisibleRegion\n    }\n}\n\nclass DummyProjection : IProjectionDelegate.Stub() {\n    override fun fromScreenLocation(obj: IObjectWrapper?): LatLng {\n        Log.d(TAG, \"Map not initialized when calling getProjection(). Cannot calculate fromScreenLocation\")\n        return LatLng(0.0, 0.0)\n    }\n\n    override fun toScreenLocation(latLng: LatLng?): IObjectWrapper {\n        Log.d(TAG, \"Map not initialized when calling getProjection(). Cannot calculate toScreenLocation\")\n        return ObjectWrapper.wrap(Point(0, 0))\n    }\n\n    override fun getVisibleRegion(): VisibleRegion {\n        Log.d(TAG, \"Map not initialized when calling getProjection(). Cannot calculate getVisibleRegion\")\n        return VisibleRegion(LatLngBounds(LatLng(0.0, 0.0), LatLng(0.0, 0.0)))\n    }\n}"
  },
  {
    "path": "play-services-maps/core/hms/src/main/kotlin/org/microg/gms/maps/hms/StreetViewPanoramaFragment.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.maps.hms\n\nimport android.app.Activity\nimport android.os.Bundle\nimport android.widget.TextView\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.ObjectWrapper\nimport com.google.android.gms.maps.StreetViewPanoramaOptions\nimport com.google.android.gms.maps.internal.IOnStreetViewPanoramaReadyCallback\nimport com.google.android.gms.maps.internal.IStreetViewPanoramaDelegate\nimport com.google.android.gms.maps.internal.IStreetViewPanoramaFragmentDelegate\n\nclass StreetViewPanoramaFragmentImpl(private val activity: Activity) : IStreetViewPanoramaFragmentDelegate.Stub() {\n\n    override fun getStreetViewPanorama(): IStreetViewPanoramaDelegate? {\n        return null\n    }\n\n    override fun onInflate(activity: IObjectWrapper?, options: StreetViewPanoramaOptions?, savedInstanceState: Bundle?) {\n    }\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n    }\n\n    override fun onCreateView(layoutInflater: IObjectWrapper?, container: IObjectWrapper?, savedInstanceState: Bundle?): IObjectWrapper {\n        return ObjectWrapper.wrap(TextView(activity))\n    }\n\n    override fun onResume() {\n    }\n\n    override fun onPause() {\n    }\n\n    override fun onDestroyView() {\n    }\n\n    override fun onDestroy() {\n    }\n\n    override fun onLowMemory() {\n    }\n\n    override fun onSaveInstanceState(outState: Bundle?) {\n    }\n\n    override fun isReady(): Boolean = true\n\n    override fun getStreetViewPanoramaAsync(callback: IOnStreetViewPanoramaReadyCallback?) {\n    }\n\n    override fun onStart() {\n    }\n\n    override fun onStop() {\n    }\n\n}"
  },
  {
    "path": "play-services-maps/core/hms/src/main/kotlin/org/microg/gms/maps/hms/StreetViewPanoramaView.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.maps.hms\n\nimport android.content.Context\nimport android.os.Bundle\nimport android.widget.TextView\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.ObjectWrapper\nimport com.google.android.gms.maps.internal.IOnStreetViewPanoramaReadyCallback\nimport com.google.android.gms.maps.internal.IStreetViewPanoramaDelegate\nimport com.google.android.gms.maps.internal.IStreetViewPanoramaViewDelegate\n\nclass StreetViewPanoramaViewImpl(private val context: Context) : IStreetViewPanoramaViewDelegate.Stub() {\n\n    override fun getStreetViewPanorama(): IStreetViewPanoramaDelegate? {\n        return null\n    }\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n    }\n\n    override fun onResume() {\n    }\n\n    override fun onPause() {\n    }\n\n    override fun onDestroy() {\n    }\n\n    override fun onLowMemory() {\n    }\n\n    override fun onSaveInstanceState(outState: Bundle?) {\n    }\n\n    override fun getView(): IObjectWrapper? {\n        return ObjectWrapper.wrap(TextView(context))\n    }\n\n    override fun getStreetViewPanoramaAsync(callback: IOnStreetViewPanoramaReadyCallback?) {\n    }\n\n    override fun onStart() {\n    }\n\n    override fun onStop() {\n    }\n\n}"
  },
  {
    "path": "play-services-maps/core/hms/src/main/kotlin/org/microg/gms/maps/hms/UiSettings.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.maps.hms\n\nimport android.os.Parcel\nimport android.util.Log\nimport android.view.ViewGroup\nimport com.google.android.gms.maps.internal.IUiSettingsDelegate\nimport com.huawei.hms.maps.OnMapReadyCallback\nimport com.huawei.hms.maps.UiSettings\nimport org.microg.gms.maps.hms.utils.MapUiController\nimport org.microg.gms.maps.hms.utils.MapUiElement\n\nprivate const val TAG = \"GmsMapsUiSettings\"\n\n/**\n * This class \"implements\" unimplemented methods to avoid duplication in subclasses\n */\nabstract class AbstractUiSettings(rootView: ViewGroup) : IUiSettingsDelegate.Stub() {\n\n    protected val mapUiController = MapUiController(rootView)\n\n    init {\n        mapUiController.initUiStates(\n            mapOf(\n                MapUiElement.MyLocationButton to false,\n                MapUiElement.ZoomView to false,\n                MapUiElement.CompassView to false\n            )\n        )\n    }\n\n    override fun setZoomControlsEnabled(zoom: Boolean) {\n        Log.d(TAG, \"unimplemented Method: setZoomControlsEnabled\")\n    }\n\n    override fun setMyLocationButtonEnabled(locationButton: Boolean) {\n        Log.d(TAG, \"unimplemented Method: setMyLocationButtonEnabled\")\n    }\n\n    override fun isZoomControlsEnabled(): Boolean {\n        Log.d(TAG, \"unimplemented Method: isZoomControlsEnabled\")\n        return false\n    }\n\n    override fun isMyLocationButtonEnabled(): Boolean {\n        Log.d(TAG, \"unimplemented Method: isMyLocationButtonEnabled\")\n        return false\n    }\n\n    override fun setIndoorLevelPickerEnabled(indoorLevelPicker: Boolean) {\n        Log.d(TAG, \"unimplemented Method: setIndoorLevelPickerEnabled\")\n    }\n\n    override fun isIndoorLevelPickerEnabled(): Boolean {\n        Log.d(TAG, \"unimplemented Method: isIndoorLevelPickerEnabled\")\n        return false\n    }\n\n    override fun setMapToolbarEnabled(mapToolbar: Boolean) {\n        Log.d(TAG, \"unimplemented Method: setMapToolbarEnabled\")\n    }\n\n    override fun isMapToolbarEnabled(): Boolean {\n        Log.d(TAG, \"unimplemented Method: isMapToolbarEnabled\")\n        return false\n    }\n\n    override fun setScrollGesturesEnabledDuringRotateOrZoom(scrollDuringZoom: Boolean) {\n        Log.d(TAG, \"unimplemented Method: setScrollGesturesEnabledDuringRotateOrZoom\")\n    }\n\n    override fun isScrollGesturesEnabledDuringRotateOrZoom(): Boolean {\n        Log.d(TAG, \"unimplemented Method: isScrollGesturesEnabledDuringRotateOrZoom\")\n        return true\n    }\n}\n\nclass UiSettingsImpl(private val uiSettings: UiSettings, rootView: ViewGroup) : AbstractUiSettings(rootView) {\n\n    init {\n        uiSettings.isZoomControlsEnabled = false\n        uiSettings.isCompassEnabled = false\n        uiSettings.isMyLocationButtonEnabled = false\n    }\n\n    override fun setZoomControlsEnabled(zoom: Boolean) {\n        Log.d(TAG, \"setZoomControlsEnabled: $zoom\")\n        uiSettings.isZoomControlsEnabled = zoom\n        mapUiController.setUiEnabled(MapUiElement.ZoomView, zoom)\n    }\n\n    override fun setCompassEnabled(compass: Boolean) {\n        Log.d(TAG, \"setCompassEnabled: $compass\")\n        uiSettings.isCompassEnabled = compass\n        mapUiController.setUiEnabled(MapUiElement.CompassView, compass)\n    }\n\n    override fun setMyLocationButtonEnabled(locationButton: Boolean) {\n        Log.d(TAG, \"setMyLocationButtonEnabled: $locationButton\")\n        uiSettings.isMyLocationButtonEnabled = locationButton\n        mapUiController.setUiEnabled(MapUiElement.MyLocationButton, locationButton)\n    }\n\n    override fun setScrollGesturesEnabled(scrollGestures: Boolean) {\n        uiSettings.isScrollGesturesEnabled = scrollGestures\n    }\n\n    override fun setZoomGesturesEnabled(zoomGestures: Boolean) {\n        uiSettings.isZoomGesturesEnabled = zoomGestures\n    }\n\n    override fun setTiltGesturesEnabled(tiltGestures: Boolean) {\n        uiSettings.isTiltGesturesEnabled = tiltGestures\n    }\n\n    override fun setRotateGesturesEnabled(rotateGestures: Boolean) {\n        uiSettings.isRotateGesturesEnabled = rotateGestures\n    }\n\n    override fun setAllGesturesEnabled(gestures: Boolean) {\n        uiSettings.setAllGesturesEnabled(gestures)\n    }\n\n    override fun isZoomControlsEnabled(): Boolean {\n        Log.d(TAG, \"isZoomControlsEnabled\")\n        return uiSettings.isZoomControlsEnabled\n    }\n\n    override fun isCompassEnabled(): Boolean = uiSettings.isCompassEnabled\n\n    override fun isMyLocationButtonEnabled(): Boolean {\n        Log.d(TAG, \"isMyLocationButtonEnabled\")\n        return uiSettings.isMyLocationButtonEnabled\n    }\n\n    override fun isScrollGesturesEnabled(): Boolean = uiSettings.isScrollGesturesEnabled\n\n    override fun isZoomGesturesEnabled(): Boolean = uiSettings.isZoomGesturesEnabled\n\n    override fun isTiltGesturesEnabled(): Boolean = uiSettings.isTiltGesturesEnabled\n\n    override fun isRotateGesturesEnabled(): Boolean = uiSettings.isRotateGesturesEnabled\n\n    override fun setIndoorLevelPickerEnabled(indoorLevelPicker: Boolean) {\n        Log.d(TAG, \"setIndoorLevelPickerEnabled: $indoorLevelPicker\")\n        uiSettings.isIndoorLevelPickerEnabled = indoorLevelPicker\n    }\n\n    override fun isIndoorLevelPickerEnabled(): Boolean {\n        Log.d(TAG, \"isIndoorLevelPickerEnabled\")\n        return uiSettings.isIndoorLevelPickerEnabled\n    }\n\n    override fun setMapToolbarEnabled(mapToolbar: Boolean) {\n        Log.d(TAG, \"setMapToolbarEnabled: $mapToolbar\")\n        uiSettings.isMapToolbarEnabled = mapToolbar\n    }\n\n    override fun isMapToolbarEnabled(): Boolean {\n        Log.d(TAG, \"isMapToolbarEnabled\")\n        return uiSettings.isMapToolbarEnabled\n    }\n\n    override fun setScrollGesturesEnabledDuringRotateOrZoom(scrollDuringZoom: Boolean) {\n        Log.d(TAG, \"setScrollGesturesEnabledDuringRotateOrZoom: $scrollDuringZoom\")\n        uiSettings.isScrollGesturesEnabledDuringRotateOrZoom = scrollDuringZoom\n    }\n\n    override fun isScrollGesturesEnabledDuringRotateOrZoom(): Boolean {\n        Log.d(TAG, \"isScrollGesturesEnabledDuringRotateOrZoom\")\n        return uiSettings.isScrollGesturesEnabledDuringRotateOrZoom\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =\n        if (super.onTransact(code, data, reply, flags)) {\n            true\n        } else {\n            Log.d(TAG, \"onTransact [unknown]: $code, $data, $flags\"); false\n        }\n}\n\nclass UiSettingsCache(rootView: ViewGroup) : AbstractUiSettings(rootView) {\n\n    private var compass: Boolean? = null\n    private var scrollGestures: Boolean? = null\n    private var zoomGestures: Boolean? = null\n    private var tiltGestures: Boolean? = null\n    private var rotateGestures: Boolean? = null\n    private var otherGestures: Boolean? = null\n\n    private var isZoomControlsEnabled: Boolean? = null\n    private var isMyLocationButtonEnabled: Boolean? = null\n    private var isAllGesturesEnabled: Boolean? = null\n    private var isIndoorLevelPickerEnabled: Boolean? = null\n    private var isMapToolbarEnabled: Boolean? = null\n    private var isScrollGesturesEnabledDuringRotateOrZoom: Boolean? = null\n\n    override fun setMapToolbarEnabled(mapToolbar: Boolean) {\n        Log.d(TAG, \"setMapToolbarEnabled: $mapToolbar\")\n        this.isMapToolbarEnabled = mapToolbar\n    }\n\n    override fun isMapToolbarEnabled(): Boolean {\n        Log.d(TAG, \"isMapToolbarEnabled\")\n        return isMapToolbarEnabled ?: true\n    }\n\n    override fun setScrollGesturesEnabledDuringRotateOrZoom(scrollDuringZoom: Boolean) {\n        Log.d(TAG, \"setScrollGesturesEnabledDuringRotateOrZoom: $scrollDuringZoom\")\n        this.isScrollGesturesEnabledDuringRotateOrZoom = scrollDuringZoom\n    }\n\n    override fun isScrollGesturesEnabledDuringRotateOrZoom(): Boolean {\n        Log.d(TAG, \"isScrollGesturesEnabledDuringRotateOrZoom\")\n        return isScrollGesturesEnabledDuringRotateOrZoom ?: true\n    }\n\n    override fun setIndoorLevelPickerEnabled(indoorLevelPicker: Boolean) {\n        Log.d(TAG, \"setIndoorLevelPickerEnabled: $indoorLevelPicker\")\n        this.isIndoorLevelPickerEnabled = indoorLevelPicker\n    }\n\n    override fun isIndoorLevelPickerEnabled(): Boolean {\n        Log.d(TAG, \"isIndoorLevelPickerEnabled\")\n        return isIndoorLevelPickerEnabled ?: true\n    }\n\n    override fun setMyLocationButtonEnabled(locationButton: Boolean) {\n        Log.d(TAG, \"setMyLocationButtonEnabled: $locationButton\")\n        this.isMyLocationButtonEnabled = locationButton\n    }\n\n    override fun isMyLocationButtonEnabled(): Boolean {\n        Log.d(TAG, \"isMyLocationButtonEnabled\")\n        return isMyLocationButtonEnabled ?: true\n    }\n\n    override fun setZoomControlsEnabled(zoom: Boolean) {\n        Log.d(TAG, \"setZoomControlsEnabled: $zoom\")\n        this.isZoomControlsEnabled = zoom\n    }\n\n    override fun isZoomControlsEnabled(): Boolean {\n        Log.d(TAG, \"isZoomControlsEnabled\")\n        return isZoomControlsEnabled ?: true\n    }\n\n    override fun setCompassEnabled(compass: Boolean) {\n        this.compass = compass\n    }\n\n    override fun setScrollGesturesEnabled(scrollGestures: Boolean) {\n        this.scrollGestures = scrollGestures\n    }\n\n    override fun setZoomGesturesEnabled(zoomGestures: Boolean) {\n        this.zoomGestures = zoomGestures\n    }\n\n    override fun setTiltGesturesEnabled(tiltGestures: Boolean) {\n        this.tiltGestures = tiltGestures\n    }\n\n    override fun setRotateGesturesEnabled(rotateGestures: Boolean) {\n        this.rotateGestures = rotateGestures\n    }\n\n    override fun setAllGesturesEnabled(gestures: Boolean) {\n        isAllGesturesEnabled = gestures\n        // Simulate MapLibre's UiSettings behavior\n        isScrollGesturesEnabled = gestures\n        isRotateGesturesEnabled = gestures\n        isTiltGesturesEnabled = gestures\n        isZoomGesturesEnabled = gestures\n\n        // Other gestures toggles double tap and quick zoom gestures\n        otherGestures = gestures\n    }\n\n    override fun isCompassEnabled(): Boolean {\n        return compass ?: true\n    }\n\n    override fun isScrollGesturesEnabled(): Boolean {\n        return scrollGestures ?: true\n    }\n\n    override fun isZoomGesturesEnabled(): Boolean {\n        return zoomGestures ?: true\n    }\n\n    override fun isTiltGesturesEnabled(): Boolean {\n        return tiltGestures ?: true\n    }\n\n    override fun isRotateGesturesEnabled(): Boolean {\n        return rotateGestures ?: true\n    }\n\n    fun getMapReadyCallback(): OnMapReadyCallback = OnMapReadyCallback { map ->\n        val uiSettings = map.uiSettings\n        uiSettings.isZoomControlsEnabled = false\n        uiSettings.isCompassEnabled = false\n        uiSettings.isMyLocationButtonEnabled = false\n\n        compass?.let {\n            uiSettings.isCompassEnabled = it\n            mapUiController.setUiEnabled(MapUiElement.CompassView, it)\n        }\n        scrollGestures?.let { uiSettings.isScrollGesturesEnabled = it }\n        zoomGestures?.let { uiSettings.isZoomGesturesEnabled = it }\n        tiltGestures?.let { uiSettings.isTiltGesturesEnabled = it }\n        rotateGestures?.let { uiSettings.isRotateGesturesEnabled = it }\n        isAllGesturesEnabled?.let { uiSettings.setAllGesturesEnabled(it) }\n\n        isZoomControlsEnabled?.let {\n            uiSettings.isZoomControlsEnabled = it\n            mapUiController.setUiEnabled(MapUiElement.ZoomView, it)\n        }\n        isMyLocationButtonEnabled?.let {\n            uiSettings.isMyLocationButtonEnabled = it\n            mapUiController.setUiEnabled(MapUiElement.MyLocationButton, it)\n        }\n        isIndoorLevelPickerEnabled?.let { uiSettings.isIndoorLevelPickerEnabled = it }\n        isMapToolbarEnabled?.let { uiSettings.isMapToolbarEnabled = it }\n        isScrollGesturesEnabledDuringRotateOrZoom?.let { uiSettings.isScrollGesturesEnabledDuringRotateOrZoom = it }\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/hms/src/main/kotlin/org/microg/gms/maps/hms/model/BitmapDescriptorFactory.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.maps.hms.model\n\nimport android.content.res.Resources\nimport android.graphics.*\nimport android.os.Parcel\nimport android.util.Log\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.ObjectWrapper\nimport com.google.android.gms.maps.model.internal.IBitmapDescriptorFactoryDelegate\nimport com.huawei.hms.maps.model.BitmapDescriptorFactory\n\nobject BitmapDescriptorFactoryImpl : IBitmapDescriptorFactoryDelegate.Stub() {\n    private val TAG = \"GmsMapBitmap\"\n    private var resources: Resources? = null\n\n    fun initialize(resources: Resources?) {\n        BitmapDescriptorFactoryImpl.resources = resources ?: BitmapDescriptorFactoryImpl.resources\n    }\n\n    override fun fromResource(resourceId: Int): IObjectWrapper? {\n        return BitmapFactory.decodeResource(resources, resourceId)?.let {\n            ObjectWrapper.wrap(BitmapDescriptorFactory.fromBitmap(it))\n        }\n    }\n\n    override fun fromAsset(assetName: String): IObjectWrapper? {\n        return resources?.assets?.open(assetName)?.let {\n            BitmapFactory.decodeStream(it)\n                ?.let { ObjectWrapper.wrap(BitmapDescriptorFactory.fromBitmap(it)) }\n        }\n    }\n\n    override fun fromFile(fileName: String): IObjectWrapper? {\n        return BitmapFactory.decodeFile(fileName)\n            ?.let { ObjectWrapper.wrap(BitmapDescriptorFactory.fromBitmap(it)) }\n    }\n\n    override fun defaultMarker(): IObjectWrapper? {\n        return ObjectWrapper.wrap(BitmapDescriptorFactory.defaultMarker())\n    }\n\n    override fun defaultMarkerWithHue(hue: Float): IObjectWrapper? {\n        return ObjectWrapper.wrap(BitmapDescriptorFactory.defaultMarker(hue))\n    }\n\n    override fun fromBitmap(bitmap: Bitmap): IObjectWrapper? {\n        return ObjectWrapper.wrap(BitmapDescriptorFactory.fromBitmap(bitmap))\n    }\n\n    override fun fromPath(absolutePath: String): IObjectWrapper? {\n        return BitmapFactory.decodeFile(absolutePath)\n            ?.let { ObjectWrapper.wrap(BitmapDescriptorFactory.fromBitmap(it)) }\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =\n            if (super.onTransact(code, data, reply, flags)) {\n                true\n            } else {\n                Log.d(TAG, \"onTransact [unknown]: $code, $data, $flags\"); false\n            }\n}\n"
  },
  {
    "path": "play-services-maps/core/hms/src/main/kotlin/org/microg/gms/maps/hms/model/Circle.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.maps.hms.model\n\nimport android.os.Parcel\nimport android.util.Log\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.ObjectWrapper\nimport com.google.android.gms.dynamic.unwrap\nimport com.google.android.gms.maps.model.LatLng\nimport com.google.android.gms.maps.model.PatternItem\nimport com.google.android.gms.maps.model.internal.ICircleDelegate\nimport com.huawei.hms.maps.model.Circle\nimport org.microg.gms.maps.hms.utils.toGms\nimport org.microg.gms.maps.hms.utils.toHms\n\nclass CircleImpl(private val circle: Circle) : ICircleDelegate.Stub() {\n    private var tag: Any? = null\n\n    override fun remove() {\n        circle.remove()\n    }\n\n    override fun getId(): String = circle.id\n\n    override fun setCenter(center: LatLng) {\n        circle.center = center.toHms()\n    }\n\n    override fun getCenter(): LatLng = circle.center.toGms()\n\n    override fun setRadius(radius: Double) {\n        circle.radius = radius\n    }\n\n    override fun getRadius(): Double = circle.radius\n\n    override fun setStrokeWidth(width: Float) {\n        circle.strokeWidth = width\n    }\n\n    override fun getStrokeWidth(): Float = circle.strokeWidth\n\n    override fun setStrokeColor(color: Int) {\n        circle.strokeColor = color\n    }\n\n    override fun getStrokeColor(): Int = circle.strokeColor\n\n    override fun setTag(tag: IObjectWrapper) {\n        this.tag = tag.unwrap()\n    }\n\n    override fun getTag(): IObjectWrapper? {\n        return ObjectWrapper.wrap(this.tag)\n    }\n\n    override fun setStrokePattern(pattern: List<PatternItem>?) {\n        circle.strokePattern = pattern?.map { it.toHms() }\n    }\n\n    override fun getStrokePattern(): List<PatternItem>? {\n        return circle.strokePattern?.map { it.toGms() }\n    }\n\n    override fun setFillColor(color: Int) {\n        circle.fillColor = color\n    }\n\n    override fun getFillColor(): Int = circle.fillColor\n\n    override fun setZIndex(zIndex: Float) {\n        circle.zIndex = zIndex\n    }\n\n    override fun getZIndex(): Float = circle.zIndex\n\n    override fun setVisible(visible: Boolean) {\n        circle.isVisible = visible\n    }\n\n    override fun isVisible(): Boolean = circle.isVisible\n\n    override fun setClickable(clickable: Boolean) {\n        circle.isClickable = clickable\n    }\n\n    override fun isClickable(): Boolean {\n        return circle.isClickable\n    }\n\n    override fun equalsRemote(other: ICircleDelegate?): Boolean = equals(other)\n\n    override fun hashCodeRemote(): Int = hashCode()\n\n    override fun hashCode(): Int {\n        return id.hashCode()\n    }\n\n    override fun toString(): String {\n        return id\n    }\n\n    override fun equals(other: Any?): Boolean {\n        if (other is CircleImpl) {\n            return other.id == id\n        }\n        return false\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =\n            if (super.onTransact(code, data, reply, flags)) {\n                true\n            } else {\n                Log.d(TAG, \"onTransact [unknown]: $code, $data, $flags\"); false\n            }\n\n    companion object {\n        val TAG = \"GmsMapCircle\"\n    }\n}"
  },
  {
    "path": "play-services-maps/core/hms/src/main/kotlin/org/microg/gms/maps/hms/model/GroundOverlay.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.maps.hms.model\n\nimport android.os.Parcel\nimport android.util.Log\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.ObjectWrapper\nimport com.google.android.gms.dynamic.unwrap\nimport com.google.android.gms.maps.model.LatLng\nimport com.google.android.gms.maps.model.LatLngBounds\nimport com.google.android.gms.maps.model.internal.IGroundOverlayDelegate\nimport com.huawei.hms.maps.model.GroundOverlay\nimport org.microg.gms.maps.hms.utils.toGms\nimport org.microg.gms.maps.hms.utils.toHms\n\nclass GroundOverlayImpl(private val groundOverlay: GroundOverlay) : IGroundOverlayDelegate.Stub() {\n    private var tag: Any? = null\n\n    override fun getId(): String {\n        return groundOverlay.id\n    }\n\n    override fun getPosition(): LatLng? {\n        return groundOverlay.position?.toGms()\n    }\n\n    override fun setPosition(pos: LatLng?) {\n        pos?.let { groundOverlay.position = it.toHms() }\n    }\n\n    override fun getWidth(): Float {\n        return groundOverlay.width\n    }\n\n    override fun getHeight(): Float {\n        return groundOverlay.height\n    }\n\n    override fun setDimensions(width: Float, height: Float) {\n        groundOverlay.setDimensions(width, height)\n    }\n\n    override fun getBounds(): LatLngBounds? {\n        return groundOverlay.bounds?.toGms()\n    }\n\n    override fun getBearing(): Float {\n        return groundOverlay.bearing\n    }\n\n    override fun setBearing(bearing: Float) {\n        groundOverlay.bearing = bearing\n    }\n\n    override fun setZIndex(zIndex: Float) {\n        groundOverlay.zIndex = zIndex\n    }\n\n    override fun getZIndex(): Float {\n        return groundOverlay.zIndex\n    }\n\n    override fun isVisible(): Boolean {\n        return groundOverlay.isVisible\n    }\n\n    override fun setVisible(visible: Boolean) {\n        groundOverlay.isVisible = visible\n    }\n\n    override fun getTransparency(): Float {\n        return groundOverlay.transparency\n    }\n\n    override fun setTransparency(transparency: Float) {\n        groundOverlay.transparency = transparency\n    }\n\n    override fun setDimension(dimension: Float) {\n        groundOverlay.setDimensions(dimension)\n    }\n\n    override fun setPositionFromBounds(bounds: LatLngBounds?) {\n        bounds?.let { groundOverlay.setPositionFromBounds(it.toHms()) }\n    }\n\n    override fun getTag(): IObjectWrapper? {\n        return ObjectWrapper.wrap(this.tag)\n    }\n\n    override fun isClickable(): Boolean = groundOverlay.isClickable\n\n    override fun setClickable(clickable: Boolean) {\n        groundOverlay.isClickable = clickable\n    }\n\n    override fun setImage(obj: IObjectWrapper?) {\n        groundOverlay.setImage(obj.unwrap())\n    }\n\n    override fun setTag(tag: IObjectWrapper) {\n        this.tag = tag.unwrap()\n    }\n\n    override fun equalsRemote(other: IGroundOverlayDelegate?): Boolean {\n        return this == other\n    }\n\n    override fun hashCode(): Int {\n        return groundOverlay.hashCode()\n    }\n\n    override fun hashCodeRemote(): Int {\n        return hashCode()\n    }\n\n//    override fun todo(obj: IObjectWrapper?) {\n//        Log.d(TAG, \"Not yet implemented\")\n//    }\n\n    override fun equals(other: Any?): Boolean {\n        return groundOverlay == other\n    }\n\n    override fun remove() {\n        Log.d(TAG, \"Method: remove\")\n        groundOverlay.remove()\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =\n        if (super.onTransact(code, data, reply, flags)) {\n            true\n        } else {\n            Log.d(TAG, \"onTransact [unknown]: $code, $data, $flags\"); false\n        }\n\n    companion object {\n        private val TAG = \"GmsMapGroundOverlay\"\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/hms/src/main/kotlin/org/microg/gms/maps/hms/model/Marker.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.maps.hms.model\n\nimport android.os.Parcel\nimport android.util.Log\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.ObjectWrapper\nimport com.google.android.gms.dynamic.unwrap\nimport com.google.android.gms.maps.model.LatLng\nimport com.google.android.gms.maps.model.MarkerOptions\nimport com.google.android.gms.maps.model.internal.IMarkerDelegate\nimport com.huawei.hms.maps.model.Marker\nimport org.microg.gms.maps.hms.GoogleMapImpl\nimport org.microg.gms.maps.hms.utils.toGms\nimport org.microg.gms.maps.hms.utils.toHms\n\nclass MarkerImpl(private val mapImpl: GoogleMapImpl, private val id: String, private val options: MarkerOptions) : IMarkerDelegate.Stub() {\n    private var marker: Marker? = null\n    private var tag: Any? = null\n\n    @Synchronized\n    fun update() {\n        marker = mapImpl.map?.addMarker(options.toHms())?.also {\n            mapImpl.markers[it.id] = this\n        }\n    }\n\n    override fun remove() {\n        marker?.remove()\n    }\n\n    override fun getId(): String = marker?.id ?: id\n\n    override fun setPosition(position: LatLng?) {\n        marker?.position = position?.toHms()\n    }\n\n    override fun getPosition(): LatLng? {\n        return marker?.position?.toGms()\n    }\n\n    override fun setTitle(title: String?) {\n        marker?.title = title\n    }\n\n    override fun getTitle(): String? = marker?.title\n\n    override fun setSnippet(snippet: String?) {\n        marker?.snippet = snippet\n    }\n\n    override fun getSnippet(): String? = marker?.snippet\n\n    override fun setDraggable(draggable: Boolean) {\n        marker?.isDraggable = draggable\n    }\n\n    override fun isDraggable(): Boolean = marker?.isDraggable ?: false\n\n    override fun showInfoWindow() {\n        marker?.showInfoWindow()\n    }\n\n    override fun hideInfoWindow() {\n        marker?.hideInfoWindow()\n    }\n\n    override fun isInfoWindowShown(): Boolean {\n        return marker?.isInfoWindowShown ?: false\n    }\n\n    override fun setVisible(visible: Boolean) {\n        marker?.isVisible = visible\n    }\n\n    override fun isVisible(): Boolean = marker?.isVisible ?: false\n\n    override fun equals(other: Any?): Boolean {\n        if (this === other) return true\n        if (other is IMarkerDelegate) return other.id == id\n        return false\n    }\n\n    override fun equalsRemote(other: IMarkerDelegate?): Boolean = equals(other)\n\n    override fun hashCode(): Int {\n        return id.hashCode()\n    }\n\n    override fun toString(): String {\n        return \"$id ($title)\"\n    }\n\n    override fun hashCodeRemote(): Int = hashCode()\n\n    override fun setIcon(obj: IObjectWrapper?) {\n        marker?.setIcon(obj.unwrap())\n    }\n\n    override fun setAnchor(x: Float, y: Float) {\n        marker?.setMarkerAnchor(x, y)\n    }\n\n    override fun setFlat(flat: Boolean) {\n        marker?.isFlat = flat\n    }\n\n    override fun isFlat(): Boolean {\n        return marker?.isFlat ?: false\n    }\n\n    override fun setRotation(rotation: Float) {\n        marker?.rotation = rotation\n    }\n\n    override fun getRotation(): Float = marker?.rotation ?: 0f\n\n    override fun setInfoWindowAnchor(x: Float, y: Float) {\n        marker?.setInfoWindowAnchor(x, y)\n    }\n\n    override fun setAlpha(alpha: Float) {\n        marker?.alpha = alpha\n    }\n\n    override fun getAlpha(): Float = marker?.alpha ?: 0f\n\n    override fun setZIndex(zIndex: Float) {\n        marker?.zIndex = zIndex\n    }\n\n    override fun getZIndex(): Float = marker?.zIndex ?: 0f\n\n    override fun setTag(obj: IObjectWrapper?) {\n        this.tag = obj.unwrap()\n    }\n\n    override fun getTag(): IObjectWrapper = ObjectWrapper.wrap(this.tag)\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =\n        if (super.onTransact(code, data, reply, flags)) {\n            true\n        } else {\n            Log.d(TAG, \"onTransact [unknown]: $code, $data, $flags\"); false\n        }\n\n    companion object {\n        private val TAG = \"GmsMapMarker\"\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/hms/src/main/kotlin/org/microg/gms/maps/hms/model/Polygon.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.maps.hms.model\n\nimport android.os.Parcel\nimport android.util.Log\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.ObjectWrapper\nimport com.google.android.gms.dynamic.unwrap\nimport com.google.android.gms.maps.model.LatLng\nimport com.google.android.gms.maps.model.PatternItem\nimport com.google.android.gms.maps.model.internal.IPolygonDelegate\nimport com.huawei.hms.maps.model.Polygon\nimport org.microg.gms.maps.hms.utils.toGms\nimport org.microg.gms.maps.hms.utils.toHms\nimport org.microg.gms.utils.warnOnTransactionIssues\n\nclass PolygonImpl(private val polygon: Polygon) : IPolygonDelegate.Stub() {\n    private var tag: Any? = null\n\n    override fun remove() {\n        polygon.remove()\n    }\n\n    override fun getId(): String = polygon.id\n\n    override fun setPoints(points: List<LatLng>) {\n        polygon.points = points.map { it.toHms() }\n    }\n\n    override fun getPoints(): List<LatLng> = polygon.points.map { it.toGms() }\n\n    override fun setHoles(holes: List<Any?>?) {\n        if (holes == null) {\n            polygon.holes = emptyList()\n        } else {\n            val outHmsHoles: MutableList<MutableList<com.huawei.hms.maps.model.LatLng>> =\n                ArrayList()\n            for (out in holes) {\n                if (out is List<*>) {\n                    val inHmsHoles: MutableList<com.huawei.hms.maps.model.LatLng> = ArrayList()\n                    for (inn in out) {\n                        if (inn is LatLng) {\n                            inHmsHoles.add(inn.toHms())\n                        }\n                    }\n                    outHmsHoles.add(inHmsHoles)\n                }\n            }\n            polygon.holes = outHmsHoles\n        }\n    }\n\n    override fun getHoles(): List<Any?> {\n        val outHoles = polygon.holes ?: return emptyList()\n        val outGmsHoles: MutableList<MutableList<LatLng>> = ArrayList()\n        for (inHoles in outHoles) {\n            if (inHoles != null) {\n                val inGmsHoles: MutableList<LatLng> = ArrayList()\n                for (inHole in inHoles) {\n                    inGmsHoles.add(inHole.toGms())\n                }\n                outGmsHoles.add(inGmsHoles)\n            }\n        }\n        return outGmsHoles\n    }\n\n    override fun setStrokeWidth(width: Float) {\n        polygon.strokeWidth = width\n    }\n\n    override fun getStrokeWidth(): Float = polygon.strokeWidth\n\n    override fun setStrokeColor(color: Int) {\n        polygon.strokeColor = color\n    }\n\n    override fun getStrokeColor(): Int = polygon.strokeColor\n\n    override fun setFillColor(color: Int) {\n        polygon.fillColor = color\n    }\n\n    override fun getFillColor(): Int {\n        return polygon.fillColor\n    }\n\n    override fun setZIndex(zIndex: Float) {\n        polygon.zIndex = zIndex\n    }\n\n    override fun getZIndex(): Float {\n        return polygon.zIndex\n    }\n\n    override fun setVisible(visible: Boolean) {\n        polygon.isVisible = visible\n    }\n\n    override fun isVisible(): Boolean {\n        return polygon.isVisible\n    }\n\n    override fun setGeodesic(geod: Boolean) {\n        polygon.isGeodesic = geod\n    }\n\n    override fun isGeodesic(): Boolean {\n        return polygon.isGeodesic\n    }\n\n    override fun getStrokeJointType(): Int {\n        return polygon.strokeJointType\n    }\n\n    override fun getStrokePattern(): List<PatternItem>? {\n        return polygon.strokePattern?.map { it.toGms() }\n    }\n\n    override fun getTag(): IObjectWrapper {\n        return ObjectWrapper.wrap(this.tag)\n    }\n\n    override fun isClickable(): Boolean {\n        return polygon.isClickable\n    }\n\n    override fun setClickable(clickable: Boolean) {\n        polygon.isClickable = clickable\n    }\n\n    override fun setStrokeJointType(jointType: Int) {\n        polygon.strokeJointType = jointType\n    }\n\n    override fun setStrokePattern(pattern: List<PatternItem>?) {\n        polygon.strokePattern = pattern?.map { it.toHms() }\n    }\n\n    override fun setTag(tag: IObjectWrapper?) {\n        this.tag = tag.unwrap()\n    }\n\n    override fun equalsRemote(other: IPolygonDelegate?): Boolean = equals(other)\n\n    override fun hashCodeRemote(): Int = hashCode()\n\n    override fun hashCode(): Int {\n        return id.hashCode()\n    }\n\n    override fun toString(): String {\n        return id\n    }\n\n    override fun equals(other: Any?): Boolean {\n        if (other is PolygonImpl) {\n            return other.id == id\n        }\n        return false\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = warnOnTransactionIssues(code, reply, flags) { super.onTransact(code, data, reply, flags) }\n\n    companion object {\n        private val TAG = \"GmsMapPolygon\"\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/hms/src/main/kotlin/org/microg/gms/maps/hms/model/Polyline.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.maps.hms.model\n\nimport android.os.Parcel\nimport android.util.Log\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.ObjectWrapper\nimport com.google.android.gms.dynamic.unwrap\nimport com.google.android.gms.maps.model.*\nimport com.google.android.gms.maps.model.BitmapDescriptor\nimport com.google.android.gms.maps.model.CustomCap\nimport com.google.android.gms.maps.model.LatLng\nimport com.google.android.gms.maps.model.PatternItem\nimport com.google.android.gms.maps.model.PolylineOptions\nimport com.google.android.gms.maps.model.internal.IPolylineDelegate\nimport com.huawei.hms.maps.model.*\nimport com.huawei.hms.maps.model.ButtCap as HmsButtCap\nimport com.huawei.hms.maps.model.Cap as HmsCap\nimport com.huawei.hms.maps.model.CustomCap as HmsCustomCap\nimport com.huawei.hms.maps.model.RoundCap as HmsRoundCap\nimport com.huawei.hms.maps.model.SquareCap as HmsSquareCap\nimport com.huawei.hms.maps.model.LatLng as HmsLatLng\nimport org.microg.gms.maps.hms.utils.toGms\nimport org.microg.gms.maps.hms.utils.toGmsPolylineWidth\nimport org.microg.gms.maps.hms.utils.toHms\nimport org.microg.gms.maps.hms.utils.toHmsPolylineWidth\n\nclass PolylineImpl(private val polyline: Polyline, polylineOptions: PolylineOptions) : IPolylineDelegate.Stub() {\n    private var tag: Any? = null\n    private val linePoints = arrayListOf<LatLng>()\n    private var lastPointsHash: Int = 0\n\n    private val toHmsCache = mutableMapOf<LatLng, HmsLatLng>()\n    private fun List<LatLng>.toHmsList(): List<HmsLatLng> {\n        return this.map { latLng ->\n            toHmsCache.getOrPut(latLng) { latLng.toHms() }\n        }\n    }\n\n    override fun remove() {\n        linePoints.clear()\n        toHmsCache.clear()\n        polyline.remove()\n    }\n\n    override fun getId(): String = polyline.id\n\n    override fun setPoints(points: List<LatLng>) {\n        if (linePoints.size == points.size && linePoints == points) {\n            Log.d(TAG, \"setPoints skipped: identical points\")\n            return\n        }\n\n        val newHash = points.hashCode()\n        if (newHash == lastPointsHash) {\n            Log.d(TAG, \"setPoints skipped: hash unchanged\")\n            return\n        }\n        lastPointsHash = newHash\n\n        linePoints.clear()\n        linePoints.addAll(points)\n        polyline.points = linePoints.toHmsList()\n        Log.d(TAG, \"setPoints updated, size=${linePoints.size}\")\n    }\n\n    override fun getPoints(): List<LatLng> {\n        return linePoints\n    }\n\n    override fun setWidth(width: Float) {\n        polyline.width = toHmsPolylineWidth(width)\n    }\n\n    override fun getWidth(): Float {\n        return toGmsPolylineWidth(polyline.width)\n    }\n\n    override fun setColor(color: Int) {\n        polyline.color = color\n    }\n\n    override fun getColor(): Int {\n        return polyline.color\n    }\n\n    override fun setZIndex(zIndex: Float) {\n        Log.d(TAG, \"setZIndex: $zIndex\")\n        polyline.zIndex = zIndex\n    }\n\n    override fun getZIndex(): Float {\n        Log.d(TAG, \"getZIndex\")\n        return polyline.zIndex\n    }\n\n    override fun setVisible(visible: Boolean) {\n        polyline.isVisible = visible\n    }\n\n    override fun isVisible(): Boolean {\n        return polyline.isVisible\n    }\n\n    override fun setGeodesic(geod: Boolean) {\n        Log.d(TAG, \"setGeodesic: $geod\")\n        polyline.isGeodesic = geod\n    }\n\n    override fun isGeodesic(): Boolean {\n        Log.d(TAG, \"isGeodesic\")\n        return polyline.isGeodesic\n    }\n\n    override fun setClickable(clickable: Boolean) {\n        Log.d(TAG, \"setClickable: $clickable\")\n        polyline.isClickable = clickable\n    }\n\n    override fun isClickable(): Boolean {\n        Log.d(TAG, \"isClickable\")\n        return polyline.isClickable\n    }\n\n    override fun equalsRemote(other: IPolylineDelegate?): Boolean = equals(other)\n\n    override fun hashCodeRemote(): Int = hashCode()\n\n    override fun hashCode(): Int {\n        return id.hashCode()\n    }\n\n    override fun toString(): String {\n        return id\n    }\n\n    override fun equals(other: Any?): Boolean {\n        if (other is PolylineImpl) {\n            return other.id == id\n        }\n        return false\n    }\n\n    override fun getPattern(): List<PatternItem>? {\n        Log.d(TAG, \"Method: getStrokePattern\")\n        return polyline.pattern?.map { it.toGms() }\n    }\n\n    override fun getTag(): IObjectWrapper {\n        return ObjectWrapper.wrap(this.tag)\n    }\n\n    override fun setJointType(jointType: Int) {\n        polyline.jointType = jointType\n    }\n\n    override fun getJointType(): Int {\n        return polyline.jointType\n    }\n\n    override fun setPattern(pattern: List<PatternItem>?) {\n        Log.d(TAG, \"Method: setStrokePattern\")\n        polyline.pattern = pattern?.map { it.toHms() }\n    }\n\n    override fun setTag(tag: IObjectWrapper?) {\n        this.tag = tag.unwrap()\n    }\n\n    override fun setEndCap(endCap: Cap) {\n        polyline.endCap = endCap.toHms()\n    }\n\n    override fun getEndCap(): Cap {\n        return polyline.endCap.toGms()\n    }\n\n    override fun setStartCap(startCap: Cap) {\n        polyline.startCap = startCap.toHms()\n    }\n\n    override fun getStartCap(): Cap {\n        return polyline.startCap.toGms()\n    }\n\n    private fun Cap.toHms(): HmsCap {\n        return when (this) {\n            is ButtCap -> HmsButtCap()\n            is SquareCap -> HmsSquareCap()\n            is RoundCap -> HmsRoundCap()\n            is CustomCap -> HmsCustomCap(bitmapDescriptor.remoteObject.unwrap(), refWidth)\n            else -> HmsButtCap()\n        }\n    }\n\n    private fun com.huawei.hms.maps.model.Cap.toGms(): Cap {\n        return when (this) {\n            is HmsButtCap -> ButtCap()\n            is HmsSquareCap -> SquareCap()\n            is HmsRoundCap -> RoundCap()\n            is HmsCustomCap -> CustomCap(BitmapDescriptor(ObjectWrapper.wrap(bitmapDescriptor)), refWidth)\n            else -> ButtCap()\n        }\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =\n        if (super.onTransact(code, data, reply, flags)) {\n            true\n        } else {\n            Log.d(TAG, \"onTransact [unknown]: $code, $data, $flags\"); false\n        }\n\n    companion object {\n        private val TAG = \"GmsMapPolyline\"\n    }\n}"
  },
  {
    "path": "play-services-maps/core/hms/src/main/kotlin/org/microg/gms/maps/hms/model/TileOverlay.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.maps.hms.model\n\nimport android.os.Parcel\nimport android.util.Log\nimport com.google.android.gms.maps.model.internal.ITileOverlayDelegate\nimport com.huawei.hms.maps.model.TileOverlay\n\nclass TileOverlayImpl(private val tileOverlay: TileOverlay) : ITileOverlayDelegate.Stub() {\n\n    override fun clearTileCache() {\n        tileOverlay.clearTileCache()\n    }\n\n    override fun equals(other: Any?): Boolean {\n        return tileOverlay == other\n    }\n\n    override fun getFadeIn(): Boolean {\n        return tileOverlay.fadeIn\n    }\n\n    override fun getId(): String {\n        return tileOverlay.id\n    }\n\n    override fun getTransparency(): Float {\n        return tileOverlay.transparency\n    }\n\n    override fun getZIndex(): Float {\n        return tileOverlay.zIndex\n    }\n\n    override fun hashCode(): Int {\n        return tileOverlay.hashCode()\n    }\n\n    override fun isVisible(): Boolean {\n        return tileOverlay.isVisible\n    }\n\n    override fun remove() {\n        return tileOverlay.remove()\n    }\n\n    override fun setFadeIn(fadeIn: Boolean) {\n        tileOverlay.fadeIn = fadeIn\n    }\n\n    override fun setTransparency(transparency: Float) {\n        tileOverlay.transparency = transparency\n    }\n\n    override fun setVisible(visible: Boolean) {\n        tileOverlay.isVisible = visible\n    }\n\n    override fun setZIndex(zIndex: Float) {\n        tileOverlay.zIndex = zIndex\n    }\n\n    override fun equalsRemote(other: ITileOverlayDelegate): Boolean = tileOverlay == (other as? TileOverlayImpl)?.tileOverlay\n    override fun hashCodeRemote(): Int = tileOverlay.hashCode()\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =\n        if (super.onTransact(code, data, reply, flags)) {\n            Log.e(TAG, \"onTransact [known]: $code, $data, $flags\")\n            true\n        } else {\n            Log.d(TAG, \"onTransact [unknown]: $code, $data, $flags\"); false\n        }\n\n    companion object {\n        private val TAG = \"GmsMapTileOverlay\"\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/hms/src/main/kotlin/org/microg/gms/maps/hms/utils/MapContext.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.maps.hms.utils\n\nimport android.content.Context\nimport android.content.ContextWrapper\nimport android.content.Intent\nimport android.content.SharedPreferences\nimport android.view.LayoutInflater\nimport androidx.annotation.RequiresApi\nimport com.huawei.hms.maps.MapClientIdentify\nimport com.huawei.hms.maps.utils.MapClientUtil\nimport org.microg.gms.common.Constants\nimport java.io.File\n\nclass MapContext(private val context: Context) : ContextWrapper(context.createPackageContext(Constants.GMS_PACKAGE_NAME, Context.CONTEXT_INCLUDE_CODE or Context.CONTEXT_IGNORE_SECURITY)) {\n    private var layoutInflater: LayoutInflater? = null\n    private val appContext: Context\n        get() = context.applicationContext ?: context\n\n    override fun getApplicationContext(): Context {\n        return this\n    }\n\n    override fun getCacheDir(): File {\n        val cacheDir = File(appContext.cacheDir, \"com.google.android.gms\")\n        cacheDir.mkdirs()\n        return cacheDir\n    }\n\n    override fun getFilesDir(): File {\n        val filesDir = File(appContext.filesDir, \"com.google.android.gms\")\n        filesDir.mkdirs()\n        return filesDir\n    }\n\n    override fun getClassLoader(): ClassLoader {\n        return MapContext::class.java.classLoader!!\n    }\n\n    override fun getPackageName(): String {\n        // Use original package name for requests not from HMS MapClientIdentify\n        val stackTrace = Thread.currentThread().stackTrace\n        if (stackTrace.any { it.className == MapClientUtil::class.java.name || it.className == MapClientIdentify::class.java.name }) return Constants.GMS_PACKAGE_NAME\n        return appContext.packageName\n    }\n\n    override fun getSharedPreferences(name: String?, mode: Int): SharedPreferences {\n        return appContext.getSharedPreferences(\"com.google.android.gms_$name\", mode)\n    }\n\n    override fun getSystemService(name: String): Any? {\n        if (name == Context.LAYOUT_INFLATER_SERVICE) {\n            if (layoutInflater == null) {\n                layoutInflater = super.getSystemService(name) as LayoutInflater\n                layoutInflater?.cloneInContext(this)?.let { layoutInflater = it }\n            }\n            if (layoutInflater != null) {\n                return layoutInflater\n            }\n        }\n        return context.getSystemService(name)\n    }\n\n    override fun startActivity(intent: Intent?) {\n        context.startActivity(intent)\n    }\n\n    @RequiresApi(24)\n    override fun createDeviceProtectedStorageContext(): Context {\n        return appContext.createDeviceProtectedStorageContext()\n    }\n\n    companion object {\n        val TAG = \"GmsMapContext\"\n    }\n}"
  },
  {
    "path": "play-services-maps/core/hms/src/main/kotlin/org/microg/gms/maps/hms/utils/MapUiController.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.maps.hms.utils\n\nimport android.view.View\nimport android.view.ViewGroup\n\nenum class MapUiElement(val classType: String) {\n    MyLocationButton(\"MyLocationButton\"),\n    ZoomView(\"ZoomView\"),\n    CompassView(\"CompassView\")\n}\n\nclass MapUiController(private val rootView: ViewGroup) {\n\n    private val uiViews = mutableMapOf<MapUiElement, View>()\n    private val uiStates = mutableMapOf<MapUiElement, Boolean>()\n\n    init {\n        MapUiElement.entries.forEach { element ->\n            rootView.waitForChild(element.classType) { view ->\n                uiViews[element] = view\n                val uiEnabled = isUiEnabled(element)\n                view.isEnabled = uiEnabled\n                view.alpha = if (uiEnabled) 1f else 0f\n            }\n        }\n    }\n\n    fun setUiEnabled(element: MapUiElement, enabled: Boolean) {\n        uiStates[element] = enabled\n        uiViews[element]?.alpha = if (enabled) 1f else 0f\n        uiViews[element]?.isEnabled = enabled\n    }\n\n    fun isUiEnabled(element: MapUiElement): Boolean {\n        return uiStates[element] ?: true\n    }\n\n    fun initUiStates(states: Map<MapUiElement, Boolean>) {\n        states.forEach { (element, enabled) ->\n            setUiEnabled(element, enabled)\n        }\n    }\n}\n\nprivate fun ViewGroup.waitForChild(classType: String, onReady: (View) -> Unit) {\n    for (i in 0 until childCount) {\n        val child = getChildAt(i)\n        if (child.javaClass.name.contains(classType)) {\n            onReady(child)\n            return\n        }\n        if (child is ViewGroup) {\n            child.waitForChild(classType, onReady)\n        }\n    }\n\n    setOnHierarchyChangeListener(object : ViewGroup.OnHierarchyChangeListener {\n        override fun onChildViewAdded(parent: View?, child: View?) {\n            if (child?.javaClass?.name?.contains(classType) == true) {\n                onReady(child)\n            }\n        }\n\n        override fun onChildViewRemoved(parent: View?, child: View?) {}\n    })\n}"
  },
  {
    "path": "play-services-maps/core/hms/src/main/kotlin/org/microg/gms/maps/hms/utils/typeConverter.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.maps.hms.utils\n\nimport android.content.res.Configuration\nimport android.os.Bundle\nimport com.google.android.gms.dynamic.unwrap\nimport com.google.android.gms.maps.GoogleMapOptions\nimport com.google.android.gms.maps.internal.ICancelableCallback\nimport com.huawei.hms.maps.HuaweiMap\nimport com.huawei.hms.maps.HuaweiMapOptions\nimport com.huawei.hms.maps.model.*\nimport org.microg.gms.maps.hms.R\nimport com.google.android.gms.maps.model.CameraPosition as GmsCameraPosition\nimport com.google.android.gms.maps.model.CircleOptions as GmsCircleOptions\nimport com.google.android.gms.maps.model.Dash as GmsDash\nimport com.google.android.gms.maps.model.Dot as GmsDot\nimport com.google.android.gms.maps.model.Gap as GmsGap\nimport com.google.android.gms.maps.model.GroundOverlayOptions as GmsGroundOverlayOptions\nimport com.google.android.gms.maps.model.LatLng as GmsLatLng\nimport com.google.android.gms.maps.model.LatLngBounds as GmsLatLngBounds\nimport com.google.android.gms.maps.model.MapStyleOptions as GmsMapStyleOptions\nimport com.google.android.gms.maps.model.MarkerOptions as GmsMarkerOptions\nimport com.google.android.gms.maps.model.PatternItem as GmsPatternItem\nimport com.google.android.gms.maps.model.PolygonOptions as GmsPolygonOptions\nimport com.google.android.gms.maps.model.PolylineOptions as GmsPolylineOptions\nimport com.google.android.gms.maps.model.Tile as GmsTile\nimport com.google.android.gms.maps.model.TileOverlayOptions as GmsTileOverlayOptions\nimport com.google.android.gms.maps.model.VisibleRegion as GmsVisibleRegion\n\nfun GmsCameraPosition.toHms(): CameraPosition {\n    return CameraPosition.Builder().target(target.toHms()).zoom(toHmsZoom(zoom)).tilt(tilt)\n        .bearing(toHmsBearing(bearing)).build()\n}\n\nfun GmsCircleOptions.toHms(): CircleOptions =\n    CircleOptions().center(center.toHms()).clickable(isClickable).fillColor(fillColor)\n        .radius(radius).strokeColor(strokeColor).strokeWidth(strokeWidth).visible(isVisible)\n        .zIndex(zIndex)\n\nfun GmsPatternItem.toHms(): PatternItem {\n    return when (this) {\n        is GmsDash -> Dash(length)\n        is GmsDot -> Dot()\n        is GmsGap -> Gap(length)\n        else -> PatternItem(0,0f)\n    }\n}\n\nfun GoogleMapOptions.toHms(): HuaweiMapOptions {\n    val huaweiMapOptions = HuaweiMapOptions()\n    camera?.let { huaweiMapOptions.camera(camera?.toHms()) }\n    if (maxZoomPreference != 0f) {\n        huaweiMapOptions.maxZoomPreference(toHmsZoom(maxZoomPreference))\n    }\n    if (minZoomPreference != 0f) {\n        huaweiMapOptions.minZoomPreference(toHmsZoom(minZoomPreference))\n    }\n    latLngBoundsForCameraTarget?.let {\n        huaweiMapOptions.latLngBoundsForCameraTarget(\n            latLngBoundsForCameraTarget?.toHms()\n        )\n    }\n\n    return huaweiMapOptions\n        .compassEnabled(isCompassEnabled)\n        .liteMode(liteMode)\n//        .mapType(mapType)\n        .rotateGesturesEnabled(rotateGesturesEnabled == true)\n        .scrollGesturesEnabled(scrollGesturesEnabled == true)\n        .tiltGesturesEnabled(tiltGesturesEnabled == true)\n        .useViewLifecycleInFragment(useViewLifecycleInFragment == true)\n        .zOrderOnTop(zOrderOnTop == true)\n        .zoomControlsEnabled(zoomControlsEnabled == true)\n        .zoomGesturesEnabled(zoomGesturesEnabled == true)\n}\n\nfun GmsLatLng.toHms(): LatLng =\n    LatLng(latitude, longitude)\n\nfun GmsLatLngBounds.toHms(): LatLngBounds =\n    LatLngBounds(\n        LatLng(if(southwest.latitude.isNaN()) 0.0 else southwest.latitude, if(southwest.longitude.isNaN()) 0.0 else southwest.longitude),\n        LatLng(if(northeast.latitude.isNaN()) 0.0 else northeast.latitude, if(northeast.longitude.isNaN()) 0.0 else northeast.longitude)\n    )\n\nfun ICancelableCallback.toHms(): HuaweiMap.CancelableCallback =\n    object : HuaweiMap.CancelableCallback {\n        override fun onFinish() = this@toHms.onFinish()\n        override fun onCancel() = this@toHms.onCancel()\n    }\n\nfun GmsMarkerOptions.toHms(): MarkerOptions {\n    val markerOptions = MarkerOptions()\n    icon?.let { markerOptions.icon(it.remoteObject.unwrap()) }\n    return markerOptions.alpha(alpha).anchorMarker(anchorU, anchorV).draggable(isDraggable)\n        .flat(isFlat).infoWindowAnchor(infoWindowAnchorU, infoWindowAnchorV)\n        .position(position.toHms()).rotation(rotation).snippet(snippet).title(title)\n        .visible(isVisible).zIndex(zIndex)\n}\n\nfun GmsGroundOverlayOptions.toHms(): GroundOverlayOptions {\n    val groundOverlayOptions = GroundOverlayOptions()\n    groundOverlayOptions.anchor(anchorU, anchorV).bearing(bearing)\n        .clickable(isClickable)\n        .image(image.remoteObject.unwrap())\n        .visible(isVisible)\n        .zIndex(zIndex)\n    location?.let {\n        if (height > 0) {\n            groundOverlayOptions.position(it.toHms(), width, height)\n        } else {\n            groundOverlayOptions.position(it.toHms(), width)\n        }\n    }\n    bounds?.let { groundOverlayOptions.positionFromBounds(it.toHms()) }\n    return groundOverlayOptions\n}\n\nfun GmsTileOverlayOptions.toHms(): TileOverlayOptions {\n    return TileOverlayOptions().tileProvider(tileProvider?.let { TileProvider { x, y, zoom -> it.getTile(x, y, zoom)?.toHms() } })\n        .fadeIn(fadeIn)\n        .visible(isVisible)\n        .transparency(transparency)\n        .zIndex(zIndex)\n}\n\nfun GmsTile.toHms(): Tile = Tile(width, height, data)\n\nfun GmsPolygonOptions.toHms(): PolygonOptions {\n    val polygonOptions = PolygonOptions()\n    holes?.map {\n        val hole = it?.map { it?.toHms() }\n        polygonOptions.addHole(hole)\n    }\n    return polygonOptions.addAll(points.map { it.toHms() })\n        .clickable(isClickable)\n        .fillColor(fillColor)\n        .geodesic(isGeodesic)\n        .strokeColor(strokeColor).strokeJointType(strokeJointType).strokeWidth(strokeWidth)\n        .visible(isVisible)\n        .zIndex(zIndex)\n}\n\nfun GmsPolylineOptions.toHms(): PolylineOptions {\n    val polylineOptions = PolylineOptions()\n    polylineOptions.addAll(points.map { it.toHms() })\n    return polylineOptions.clickable(isClickable).color(color).geodesic(isGeodesic)\n        .jointType(jointType).visible(isVisible).width(toHmsPolylineWidth(width)).zIndex(zIndex)\n}\n\nfun toHmsPolylineWidth(gmsWidth: Float): Float = gmsWidth / 3\n\nfun toHmsZoom(gmsZoom: Float?): Float {\n    if (gmsZoom == null) {\n        return 3f\n    }\n    if (gmsZoom < 3) {\n        return 3f\n    } else if (gmsZoom > 18) {\n        return 18f\n    }\n    return gmsZoom\n}\n\nfun toHmsBearing(gmsBearing: Float): Float {\n    return 360 - gmsBearing\n}\n\nfun Bundle.toHms(): Bundle {\n    val newBundle = Bundle(this)\n    val oldLoader = newBundle.classLoader\n    newBundle.classLoader = GmsLatLng::class.java.classLoader\n    for (key in newBundle.keySet()) {\n        when (val value = newBundle.get(key)) {\n            is GmsCameraPosition -> newBundle.putParcelable(key, value.toHms())\n            is GmsLatLng -> newBundle.putParcelable(key, value.toHms())\n            is GmsLatLngBounds -> newBundle.putParcelable(key, value.toHms())\n            is Bundle -> newBundle.putBundle(key, value.toHms())\n        }\n    }\n    newBundle.classLoader = oldLoader\n    return newBundle\n}\n\nfun CameraPosition.toGms(): GmsCameraPosition =\n    GmsCameraPosition(target.toGms(), zoom, tilt, bearing)\n\nfun PatternItem.toGms(): GmsPatternItem = when (this) {\n    is Dot -> GmsDot()\n    is Dash -> GmsDash(length)\n    is Gap  -> GmsGap(length)\n    else -> GmsGap(0f)\n}\n\nfun LatLng.toGms(): GmsLatLng = GmsLatLng(latitude, longitude)\n\nfun LatLngBounds.toGms(): GmsLatLngBounds = GmsLatLngBounds(\n    GmsLatLng(southwest.latitude, southwest.longitude),\n    GmsLatLng(northeast.latitude, northeast.longitude)\n)\n\nfun VisibleRegion.toGms(): GmsVisibleRegion =\n    GmsVisibleRegion(\n        nearLeft.toGms(),\n        nearRight.toGms(),\n        farLeft.toGms(),\n        farRight.toGms(),\n        latLngBounds.toGms()\n    )\n\nfun toGmsPolylineWidth(hmsWidth: Float): Float = hmsWidth * 3\n\nfun Bundle.toGms(): Bundle {\n    val newBundle = Bundle(this)\n    val oldLoader = newBundle.classLoader\n    newBundle.classLoader = LatLng::class.java.classLoader\n    for (key in newBundle.keySet()) {\n        when (val value = newBundle.get(key)) {\n            is CameraPosition -> newBundle.putParcelable(key, value.toGms())\n            is LatLng -> newBundle.putParcelable(key, value.toGms())\n            is LatLngBounds -> newBundle.putParcelable(key, value.toGms())\n            is Bundle -> newBundle.putBundle(key, value.toGms())\n        }\n    }\n    newBundle.classLoader = oldLoader\n    return newBundle\n}\n\nfun GmsMapStyleOptions.toHms(context: MapContext): MapStyleOptions {\n    val nightMode = context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK\n    if (nightMode == Configuration.UI_MODE_NIGHT_YES) {\n        return MapStyleOptions.loadRawResourceStyle(context, R.raw.mapstyle_night_hms)\n    }\n    return MapStyleOptions.loadRawResourceStyle(context, R.raw.mapstyle_grayscale_hms)\n}"
  },
  {
    "path": "play-services-maps/core/hms/src/main/res/raw/mapstyle_grayscale_hms.json",
    "content": "[\n  {\n    \"featureType\": \"all\",\n    \"elementType\": \"geometry\",\n    \"stylers\": [\n      {\n        \"color\": \"#f5f5f5\"\n      }\n    ]\n  },\n  {\n    \"featureType\": \"all\",\n    \"elementType\": \"labels.icon\",\n    \"stylers\": [\n      {\n        \"saturation\": -100\n      }\n    ]\n  },\n  {\n    \"featureType\": \"all\",\n    \"elementType\": \"labels.text\",\n    \"stylers\": [\n      {\n        \"saturation\": -100\n      }\n    ]\n  },\n  {\n    \"featureType\": \"poi\",\n    \"elementType\": \"geometry\",\n    \"stylers\": [\n      {\n        \"color\": \"#eeeeee\"\n      }\n    ]\n  },\n  {\n    \"featureType\": \"poi.park\",\n    \"elementType\": \"geometry\",\n    \"stylers\": [\n      {\n        \"color\": \"#e5e5e5\"\n      }\n    ]\n  },\n  {\n    \"featureType\": \"road\",\n    \"elementType\": \"geometry\",\n    \"stylers\": [\n      {\n        \"color\": \"#ffffff\"\n      }\n    ]\n  },\n  {\n    \"featureType\": \"road.highway\",\n    \"elementType\": \"geometry\",\n    \"stylers\": [\n      {\n        \"color\": \"#dadada\"\n      }\n    ]\n  },\n  {\n    \"featureType\": \"road.highway\",\n    \"elementType\": \"labels.icon\",\n    \"stylers\": [\n      {\n        \"lightness\": 30\n      }\n    ]\n  },\n  {\n    \"featureType\": \"transit.line\",\n    \"elementType\": \"geometry\",\n    \"stylers\": [\n      {\n        \"color\": \"#e5e5e5\"\n      }\n    ]\n  },\n  {\n    \"featureType\": \"transit.station\",\n    \"elementType\": \"geometry\",\n    \"stylers\": [\n      {\n        \"color\": \"#eeeeee\"\n      }\n    ]\n  },\n  {\n    \"featureType\": \"water\",\n    \"elementType\": \"geometry\",\n    \"stylers\": [\n      {\n        \"color\": \"#c9c9c9\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "play-services-maps/core/hms/src/main/res/raw/mapstyle_night_hms.json",
    "content": "[\n  {\n    \"mapFeature\": \"all\",\n    \"options\": \"geometry\",\n    \"paint\": {\n      \"color\": \"#25292B\"\n    }\n  },\n  {\n    \"mapFeature\": \"all\",\n    \"options\": \"labels.text.stroke\",\n    \"paint\": {\n      \"color\": \"#25292B\"\n    }\n  },\n  {\n    \"mapFeature\": \"all\",\n    \"options\": \"labels.icon\",\n    \"paint\": {\n      \"icon-type\": \"night\"\n    }\n  },\n  {\n    \"mapFeature\": \"administrative\",\n    \"options\": \"labels.text.fill\",\n    \"paint\": {\n      \"color\": \"#E0D5C7\"\n    }\n  },\n  {\n    \"mapFeature\": \"administrative.country\",\n    \"options\": \"geometry\",\n    \"paint\": {\n      \"color\": \"#787272\"\n    }\n  },\n  {\n    \"mapFeature\": \"administrative.province\",\n    \"options\": \"geometry\",\n    \"paint\": {\n      \"color\": \"#666262\"\n    }\n  },\n  {\n    \"mapFeature\": \"administrative.province\",\n    \"options\": \"labels.text.fill\",\n    \"paint\": {\n      \"color\": \"#928C82\"\n    }\n  },\n  {\n    \"mapFeature\": \"administrative.district\",\n    \"options\": \"labels.text.fill\",\n    \"paint\": {\n      \"color\": \"#AAA59E\"\n    }\n  },\n  {\n    \"mapFeature\": \"administrative.locality\",\n    \"options\": \"labels.text.fill\",\n    \"paint\": {\n      \"color\": \"#928C82\"\n    }\n  },\n  {\n    \"mapFeature\": \"landcover.parkland.natural\",\n    \"visibility\": false,\n    \"options\": \"geometry\",\n    \"paint\": {\n      \"color\": \"#25292B\"\n    }\n  },\n  {\n    \"mapFeature\": \"landcover.parkland.public-garden\",\n    \"options\": \"geometry\",\n    \"paint\": {\n      \"color\": \"#283631\"\n    }\n  },\n  {\n    \"mapFeature\": \"landcover.parkland.human-made\",\n    \"visibility\": false,\n    \"options\": \"geometry\",\n    \"paint\": {\n      \"color\": \"#25292B\"\n    }\n  },\n  {\n    \"mapFeature\": \"landcover.parkland.public-garden\",\n    \"options\": \"labels.text.fill\",\n    \"paint\": {\n      \"color\": \"#8BAA7F\"\n    }\n  },\n  {\n    \"mapFeature\": \"landcover.hospital\",\n    \"options\": \"geometry\",\n    \"paint\": {\n      \"color\": \"#382B2B\"\n    }\n  },\n  {\n    \"mapFeature\": \"landcover\",\n    \"options\": \"labels.text.fill\",\n    \"paint\": {\n      \"color\": \"#928C82\"\n    }\n  },\n  {\n    \"mapFeature\": \"poi.shopping\",\n    \"options\": \"labels.text.fill\",\n    \"paint\": {\n      \"color\": \"#9C8C5F\"\n    }\n  },\n  {\n    \"mapFeature\": \"landcover.human-made.building\",\n    \"visibility\": false,\n    \"options\": \"labels.text.fill\",\n    \"paint\": {\n      \"color\": \"#000000\"\n    }\n  },\n  {\n    \"mapFeature\": \"poi.tourism\",\n    \"options\": \"labels.text.fill\",\n    \"paint\": {\n      \"color\": \"#578C8C\"\n    }\n  },\n  {\n    \"mapFeature\": \"poi.beauty\",\n    \"options\": \"labels.text.fill\",\n    \"paint\": {\n      \"color\": \"#9E7885\"\n    }\n  },\n  {\n    \"mapFeature\": \"poi.leisure\",\n    \"options\": \"labels.text.fill\",\n    \"paint\": {\n      \"color\": \"#916A91\"\n    }\n  },\n  {\n    \"mapFeature\": \"poi.eating&drinking\",\n    \"options\": \"labels.text.fill\",\n    \"paint\": {\n      \"color\": \"#996E50\"\n    }\n  },\n  {\n    \"mapFeature\": \"poi.lodging\",\n    \"options\": \"labels.text.fill\",\n    \"paint\": {\n      \"color\": \"#A3678F\"\n    }\n  },\n  {\n    \"mapFeature\": \"poi.health-care\",\n    \"options\": \"labels.text.fill\",\n    \"paint\": {\n      \"color\": \"#B07373\"\n    }\n  },\n  {\n    \"mapFeature\": \"poi.public-service\",\n    \"options\": \"labels.text.fill\",\n    \"paint\": {\n      \"color\": \"#5F7299\"\n    }\n  },\n  {\n    \"mapFeature\": \"poi.business\",\n    \"options\": \"labels.text.fill\",\n    \"paint\": {\n      \"color\": \"#6B6B9D\"\n    }\n  },\n  {\n    \"mapFeature\": \"poi.automotive\",\n    \"options\": \"labels.text.fill\",\n    \"paint\": {\n      \"color\": \"#6B6B9D\"\n    }\n  },\n  {\n    \"mapFeature\": \"poi.sports.outdoor\",\n    \"options\": \"labels.text.fill\",\n    \"paint\": {\n      \"color\": \"#597A52\"\n    }\n  },\n  {\n    \"mapFeature\": \"poi.sports.other\",\n    \"options\": \"labels.text.fill\",\n    \"paint\": {\n      \"color\": \"#3E90AB\"\n    }\n  },\n  {\n    \"mapFeature\": \"poi.natural\",\n    \"options\": \"labels.text.fill\",\n    \"paint\": {\n      \"color\": \"#597A52\"\n    }\n  },\n  {\n    \"mapFeature\": \"poi.miscellaneous\",\n    \"options\": \"labels.text.fill\",\n    \"paint\": {\n      \"color\": \"#A7ADB0\"\n    }\n  },\n  {\n    \"mapFeature\": \"road.highway\",\n    \"options\": \"labels.text.fill\",\n    \"paint\": {\n      \"color\": \"#E3CAA2\"\n    }\n  },\n  {\n    \"mapFeature\": \"road.national\",\n    \"options\": \"labels.text.fill\",\n    \"paint\": {\n      \"color\": \"#A7ADB0\"\n    }\n  },\n  {\n    \"mapFeature\": \"road.province\",\n    \"options\": \"labels.text.fill\",\n    \"paint\": {\n      \"color\": \"#A7ADB0\"\n    }\n  },\n  {\n    \"mapFeature\": \"road.city-arterial\",\n    \"options\": \"labels.text.fill\",\n    \"paint\": {\n      \"color\": \"#808689\"\n    }\n  },\n  {\n    \"mapFeature\": \"road.minor-road\",\n    \"options\": \"labels.text.fill\",\n    \"paint\": {\n      \"color\": \"#808689\"\n    }\n  },\n  {\n    \"mapFeature\": \"road.sidewalk\",\n    \"options\": \"labels.text.fill\",\n    \"paint\": {\n      \"color\": \"#808689\"\n    }\n  },\n  {\n    \"mapFeature\": \"road.highway.country\",\n    \"options\": \"geometry.fill\",\n    \"paint\": {\n      \"color\": \"#8C7248\"\n    }\n  },\n  {\n    \"mapFeature\": \"road.highway.city\",\n    \"options\": \"geometry.fill\",\n    \"paint\": {\n      \"color\": \"#706148\"\n    }\n  },\n  {\n    \"mapFeature\": \"road.national\",\n    \"options\": \"geometry.fill\",\n    \"paint\": {\n      \"color\": \"#444A4D\"\n    }\n  },\n  {\n    \"mapFeature\": \"road.province\",\n    \"options\": \"geometry.fill\",\n    \"paint\": {\n      \"color\": \"#444A4D\"\n    }\n  },\n  {\n    \"mapFeature\": \"road.city-arterial\",\n    \"options\": \"geometry.fill\",\n    \"paint\": {\n      \"color\": \"#434B4F\"\n    }\n  },\n  {\n    \"mapFeature\": \"road.minor-road\",\n    \"options\": \"geometry.fill\",\n    \"paint\": {\n      \"color\": \"#434B4F\"\n    }\n  },\n  {\n    \"mapFeature\": \"road.sidewalk\",\n    \"options\": \"geometry.fill\",\n    \"paint\": {\n      \"color\": \"#434B4F\"\n    }\n  },\n  {\n    \"mapFeature\": \"transit\",\n    \"options\": \"labels.text.fill\",\n    \"paint\": {\n      \"color\": \"#4F81B3\"\n    }\n  },\n  {\n    \"mapFeature\": \"transit.railway\",\n    \"options\": \"geometry\",\n    \"paint\": {\n      \"color\": \"#5B2E57\"\n    }\n  },\n  {\n    \"mapFeature\": \"transit.ferry-line\",\n    \"options\": \"geometry\",\n    \"paint\": {\n      \"color\": \"#364D67\"\n    }\n  },\n  {\n    \"mapFeature\": \"transit.airport\",\n    \"options\": \"geometry\",\n    \"paint\": {\n      \"color\": \"#2C3235\"\n    }\n  },\n  {\n    \"mapFeature\": \"water\",\n    \"options\": \"geometry\",\n    \"paint\": {\n      \"color\": \"#243850\"\n    }\n  },\n  {\n    \"mapFeature\": \"water\",\n    \"options\": \"labels.text.fill\",\n    \"paint\": {\n      \"color\": \"#4C6481\"\n    }\n  },\n  {\n    \"mapFeature\": \"trafficInfo.smooth\",\n    \"options\": \"geometry\",\n    \"paint\": {\n      \"color\": \"#348734\"\n    }\n  },\n  {\n    \"mapFeature\": \"trafficInfo.amble\",\n    \"options\": \"geometry\",\n    \"paint\": {\n      \"color\": \"#947000\"\n    }\n  },\n  {\n    \"mapFeature\": \"trafficInfo.congestion\",\n    \"options\": \"geometry\",\n    \"paint\": {\n      \"color\": \"#A4281E\"\n    }\n  },\n  {\n    \"mapFeature\": \"trafficInfo.extremelycongestion\",\n    \"options\": \"geometry\",\n    \"paint\": {\n      \"color\": \"#7A120B\"\n    }\n  }\n]"
  },
  {
    "path": "play-services-maps/core/hms/src/main/res/values/strings.xml",
    "content": "<resources></resources>"
  },
  {
    "path": "play-services-maps/core/mapbox/build.gradle",
    "content": "/*\n * Copyright 2013-2019 microG Project Team\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\napply plugin: 'com.android.library'\napply plugin: 'kotlin-android'\n\ndependencies {\n    implementation project(':play-services-maps')\n    implementation project(':play-services-base-core')\n    implementation project(':play-services-location')\n    implementation(\"org.maplibre.gl:android-sdk:10.2.0\")\n    implementation(\"org.maplibre.gl:android-plugin-annotation-v9:2.0.1\") {\n        exclude group: 'com.google.android.gms'\n    }\n    implementation 'org.maplibre.gl:android-sdk-turf:5.9.0'\n\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion\"\n}\n\ndef execResult(...args) {\n    def stdout = new ByteArrayOutputStream()\n    exec {\n        commandLine args\n        standardOutput = stdout\n    }\n    return stdout.toString().trim()\n}\n\nandroid {\n    namespace \"org.microg.gms.maps.mapbox\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        buildConfig = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n        buildConfigField \"String\", \"MAPBOX_KEY\", \"\\\"${localProperties.getProperty(\"mapbox.key\", System.getenv('MAPBOX_VECTOR_TILES_KEY') ?: \"\")}\\\"\"\n        buildConfigField \"String\", \"STADIA_KEY\", \"\\\"${localProperties.getProperty(\"stadia.key\", System.getenv('STADIA_API_KEY') ?: \"\")}\\\"\"\n\n        ndk {\n            abiFilters \"armeabi\", \"armeabi-v7a\", \"arm64-v8a\", \"x86\", \"x86_64\"\n        }\n    }\n\n    sourceSets {\n        main.java.srcDirs += 'src/main/kotlin'\n    }\n\n    lintOptions {\n        disable 'GradleCompatible'\n    }\n\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n\n    kotlinOptions {\n        jvmTarget = 1.8\n    }\n}\n\nif (file('user.gradle').exists()) {\n    apply from: 'user.gradle'\n}\n"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2019 microG Project Team\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<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n          xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>\n    <uses-permission android:name=\"android.permission.INTERNET\"/>\n    <uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>\n    <uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>\n    <uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>\n    <uses-permission android:name=\"android.permission.WAKE_LOCK\"/>\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>\n    <uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\"/>\n    <uses-permission android:name=\"android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS\"/>\n    <uses-permission android:name=\"android.permission.RECEIVE_BOOT_COMPLETED\"/>\n\n    <uses-sdk tools:overrideLibrary=\"com.mapbox.mapboxsdk, com.mapbox.mapboxsdk.plugins.annotation\" />\n\n    <application />\n\n</manifest>\n"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/10240-10495.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b10240-10495"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/10496-10751.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b10496-10751"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/10752-11007.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b10752-11007"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/11008-11263.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b11008-11263"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/11264-11519.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b11264-11519"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/11520-11775.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b11520-11775"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/11776-12031.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b11776-12031"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/12032-12287.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b12032-12287"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/12288-12543.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b12288-12543"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/12544-12799.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b12544-12799"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/12800-13055.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b12800-13055"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/13056-13311.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b13056-13311"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/13312-13567.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b13312-13567"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/13568-13823.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b13568-13823"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/13824-14079.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b13824-14079"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/14080-14335.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b14080-14335"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/14336-14591.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b14336-14591"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/14592-14847.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b14592-14847"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/14848-15103.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b14848-15103"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/15104-15359.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b15104-15359"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/1536-1791.pbf",
    "content": "\n\u0018\n\u000bRoboto Bold\u0012\t1536-1791"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/15360-15615.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b15360-15615"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/15616-15871.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b15616-15871"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/15872-16127.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b15872-16127"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/16128-16383.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b16128-16383"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/16384-16639.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b16384-16639"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/16640-16895.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b16640-16895"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/16896-17151.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b16896-17151"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/17152-17407.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b17152-17407"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/17408-17663.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b17408-17663"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/17664-17919.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b17664-17919"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/1792-2047.pbf",
    "content": "\n\u0018\n\u000bRoboto Bold\u0012\t1792-2047"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/17920-18175.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b17920-18175"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/18176-18431.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b18176-18431"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/18432-18687.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b18432-18687"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/18688-18943.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b18688-18943"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/18944-19199.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b18944-19199"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/19200-19455.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b19200-19455"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/19456-19711.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b19456-19711"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/19712-19967.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b19712-19967"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/19968-20223.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b19968-20223"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/20224-20479.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b20224-20479"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/2048-2303.pbf",
    "content": "\n\u0018\n\u000bRoboto Bold\u0012\t2048-2303"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/20480-20735.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b20480-20735"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/20736-20991.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b20736-20991"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/20992-21247.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b20992-21247"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/21248-21503.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b21248-21503"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/21504-21759.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b21504-21759"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/21760-22015.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b21760-22015"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/22016-22271.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b22016-22271"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/22272-22527.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b22272-22527"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/22528-22783.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b22528-22783"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/22784-23039.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b22784-23039"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/2304-2559.pbf",
    "content": "\n\u0018\n\u000bRoboto Bold\u0012\t2304-2559"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/23040-23295.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b23040-23295"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/23296-23551.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b23296-23551"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/23552-23807.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b23552-23807"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/23808-24063.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b23808-24063"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/24064-24319.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b24064-24319"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/24320-24575.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b24320-24575"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/24576-24831.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b24576-24831"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/24832-25087.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b24832-25087"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/25088-25343.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b25088-25343"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/25344-25599.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b25344-25599"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/2560-2815.pbf",
    "content": "\n\u0018\n\u000bRoboto Bold\u0012\t2560-2815"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/25600-25855.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b25600-25855"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/25856-26111.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b25856-26111"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/26112-26367.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b26112-26367"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/26368-26623.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b26368-26623"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/26624-26879.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b26624-26879"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/26880-27135.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b26880-27135"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/27136-27391.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b27136-27391"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/27392-27647.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b27392-27647"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/27648-27903.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b27648-27903"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/27904-28159.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b27904-28159"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/2816-3071.pbf",
    "content": "\n\u0018\n\u000bRoboto Bold\u0012\t2816-3071"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/28160-28415.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b28160-28415"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/28416-28671.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b28416-28671"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/28672-28927.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b28672-28927"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/28928-29183.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b28928-29183"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/29184-29439.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b29184-29439"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/29440-29695.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b29440-29695"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/29696-29951.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b29696-29951"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/29952-30207.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b29952-30207"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/30208-30463.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b30208-30463"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/30464-30719.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b30464-30719"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/3072-3327.pbf",
    "content": "\n\u0018\n\u000bRoboto Bold\u0012\t3072-3327"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/30720-30975.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b30720-30975"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/30976-31231.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b30976-31231"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/31232-31487.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b31232-31487"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/31488-31743.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b31488-31743"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/31744-31999.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b31744-31999"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/32000-32255.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b32000-32255"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/32256-32511.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b32256-32511"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/32512-32767.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b32512-32767"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/32768-33023.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b32768-33023"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/33024-33279.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b33024-33279"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/3328-3583.pbf",
    "content": "\n\u0018\n\u000bRoboto Bold\u0012\t3328-3583"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/33280-33535.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b33280-33535"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/33536-33791.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b33536-33791"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/33792-34047.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b33792-34047"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/34048-34303.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b34048-34303"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/34304-34559.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b34304-34559"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/34560-34815.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b34560-34815"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/34816-35071.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b34816-35071"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/35072-35327.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b35072-35327"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/35328-35583.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b35328-35583"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/35584-35839.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b35584-35839"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/3584-3839.pbf",
    "content": "\n\u0018\n\u000bRoboto Bold\u0012\t3584-3839"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/35840-36095.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b35840-36095"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/36096-36351.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b36096-36351"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/36352-36607.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b36352-36607"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/36608-36863.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b36608-36863"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/36864-37119.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b36864-37119"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/37120-37375.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b37120-37375"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/37376-37631.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b37376-37631"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/37632-37887.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b37632-37887"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/37888-38143.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b37888-38143"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/38144-38399.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b38144-38399"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/3840-4095.pbf",
    "content": "\n\u0018\n\u000bRoboto Bold\u0012\t3840-4095"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/38400-38655.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b38400-38655"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/38656-38911.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b38656-38911"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/38912-39167.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b38912-39167"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/39168-39423.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b39168-39423"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/39424-39679.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b39424-39679"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/39680-39935.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b39680-39935"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/39936-40191.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b39936-40191"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/40192-40447.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b40192-40447"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/40448-40703.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b40448-40703"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/40704-40959.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b40704-40959"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/4096-4351.pbf",
    "content": "\n\u0018\n\u000bRoboto Bold\u0012\t4096-4351"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/40960-41215.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b40960-41215"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/41216-41471.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b41216-41471"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/41472-41727.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b41472-41727"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/41728-41983.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b41728-41983"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/41984-42239.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b41984-42239"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/42240-42495.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b42240-42495"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/42496-42751.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b42496-42751"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/42752-43007.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b42752-43007"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/43008-43263.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b43008-43263"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/43264-43519.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b43264-43519"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/4352-4607.pbf",
    "content": "\n\u0018\n\u000bRoboto Bold\u0012\t4352-4607"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/43520-43775.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b43520-43775"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/43776-44031.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b43776-44031"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/44032-44287.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b44032-44287"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/44288-44543.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b44288-44543"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/44544-44799.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b44544-44799"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/44800-45055.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b44800-45055"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/45056-45311.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b45056-45311"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/45312-45567.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b45312-45567"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/45568-45823.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b45568-45823"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/45824-46079.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b45824-46079"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/4608-4863.pbf",
    "content": "\n\u0018\n\u000bRoboto Bold\u0012\t4608-4863"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/46080-46335.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b46080-46335"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/46336-46591.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b46336-46591"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/46592-46847.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b46592-46847"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/46848-47103.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b46848-47103"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/47104-47359.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b47104-47359"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/47360-47615.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b47360-47615"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/47616-47871.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b47616-47871"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/47872-48127.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b47872-48127"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/48128-48383.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b48128-48383"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/48384-48639.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b48384-48639"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/4864-5119.pbf",
    "content": "\n\u0018\n\u000bRoboto Bold\u0012\t4864-5119"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/48640-48895.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b48640-48895"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/48896-49151.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b48896-49151"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/49152-49407.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b49152-49407"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/49408-49663.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b49408-49663"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/49664-49919.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b49664-49919"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/49920-50175.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b49920-50175"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/50176-50431.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b50176-50431"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/50432-50687.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b50432-50687"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/50688-50943.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b50688-50943"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/50944-51199.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b50944-51199"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/5120-5375.pbf",
    "content": "\n\u0018\n\u000bRoboto Bold\u0012\t5120-5375"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/51200-51455.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b51200-51455"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/51456-51711.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b51456-51711"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/51712-51967.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b51712-51967"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/51968-52223.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b51968-52223"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/52224-52479.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b52224-52479"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/52480-52735.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b52480-52735"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/52736-52991.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b52736-52991"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/52992-53247.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b52992-53247"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/53248-53503.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b53248-53503"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/53504-53759.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b53504-53759"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/5376-5631.pbf",
    "content": "\n\u0018\n\u000bRoboto Bold\u0012\t5376-5631"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/53760-54015.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b53760-54015"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/54016-54271.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b54016-54271"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/54272-54527.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b54272-54527"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/54528-54783.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b54528-54783"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/54784-55039.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b54784-55039"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/55040-55295.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b55040-55295"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/55296-55551.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b55296-55551"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/55552-55807.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b55552-55807"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/55808-56063.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b55808-56063"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/56064-56319.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b56064-56319"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/5632-5887.pbf",
    "content": "\n\u0018\n\u000bRoboto Bold\u0012\t5632-5887"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/56320-56575.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b56320-56575"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/56576-56831.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b56576-56831"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/56832-57087.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b56832-57087"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/57088-57343.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b57088-57343"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/57344-57599.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b57344-57599"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/57600-57855.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b57600-57855"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/57856-58111.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b57856-58111"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/58112-58367.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b58112-58367"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/58368-58623.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b58368-58623"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/58624-58879.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b58624-58879"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/5888-6143.pbf",
    "content": "\n\u0018\n\u000bRoboto Bold\u0012\t5888-6143"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/58880-59135.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b58880-59135"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/59136-59391.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b59136-59391"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/59392-59647.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b59392-59647"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/59648-59903.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b59648-59903"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/59904-60159.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b59904-60159"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/60160-60415.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b60160-60415"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/60416-60671.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b60416-60671"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/60672-60927.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b60672-60927"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/60928-61183.pbf",
    "content": "\n\u0003\n\u000bRoboto Bold\u0012\u000b60928-61183\u001a\u0001\b\u0003\u0012\u0001\u001f7KY^_^YK7\u001f7Kcv}~}vdK7KdvvdKYvvY^~̳~^_߼_^~ʹ~_YvwYKdvwdK7Kdv~~vdK7\u001f7LZ___ZL7\u001f7LdwweL7KdwwdLZwûwZ_~߸__߻_^}İ}^YvvYKcv}}vcK7KY^___^YK7\u0018\u0005 \u000e(\u00020\r8\u0007\u001a\u0001\b\u0003\u0012\u00018LZ__Z___ZL7Leww~weLZwwZ_ğĽ__Οß__Οß__Οß__Οß__~_ZwwZLdww~~wdK7LZ__Z^__ZK7\u0018\u0006 \u0006(\u00020\u00138\u0007"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/61184-61439.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b61184-61439"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/6144-6399.pbf",
    "content": "\n\u0018\n\u000bRoboto Bold\u0012\t6144-6399"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/61440-61695.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b61440-61695"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/61696-61951.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b61696-61951"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/61952-62207.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b61952-62207"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/62208-62463.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b62208-62463"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/62464-62719.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b62464-62719"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/62720-62975.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b62720-62975"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/63232-63487.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b63232-63487"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/63488-63743.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b63488-63743"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/63744-63999.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b63744-63999"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/6400-6655.pbf",
    "content": "\n\u0018\n\u000bRoboto Bold\u0012\t6400-6655"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/64000-64255.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b64000-64255"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/64512-64767.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b64512-64767"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/64768-65023.pbf",
    "content": "\n\u001a\n\u000bRoboto Bold\u0012\u000b64768-65023"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/6656-6911.pbf",
    "content": "\n\u0018\n\u000bRoboto Bold\u0012\t6656-6911"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/6912-7167.pbf",
    "content": "\n\u0018\n\u000bRoboto Bold\u0012\t6912-7167"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/7168-7423.pbf",
    "content": "\n\u0018\n\u000bRoboto Bold\u0012\t7168-7423"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/7424-7679.pbf",
    "content": "\n\u0018\n\u000bRoboto Bold\u0012\t7424-7679"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/8960-9215.pbf",
    "content": "\n\u0018\n\u000bRoboto Bold\u0012\t8960-9215"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/9216-9471.pbf",
    "content": "\n\u0018\n\u000bRoboto Bold\u0012\t9216-9471"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/9728-9983.pbf",
    "content": "\n\u0018\n\u000bRoboto Bold\u0012\t9728-9983"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Bold/9984-10239.pbf",
    "content": "\n\u0019\n\u000bRoboto Bold\u0012\n9984-10239"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/10240-10495.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b10240-10495"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/10496-10751.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b10496-10751"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/10752-11007.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b10752-11007"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/11008-11263.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b11008-11263"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/11264-11519.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b11264-11519"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/11520-11775.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b11520-11775"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/11776-12031.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b11776-12031"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/12032-12287.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b12032-12287"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/12288-12543.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b12288-12543"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/12544-12799.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b12544-12799"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/12800-13055.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b12800-13055"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/13056-13311.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b13056-13311"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/13312-13567.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b13312-13567"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/13568-13823.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b13568-13823"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/13824-14079.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b13824-14079"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/14080-14335.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b14080-14335"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/14336-14591.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b14336-14591"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/14592-14847.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b14592-14847"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/14848-15103.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b14848-15103"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/15104-15359.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b15104-15359"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/1536-1791.pbf",
    "content": "\n\u001a\n\rRoboto Medium\u0012\t1536-1791"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/15360-15615.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b15360-15615"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/15616-15871.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b15616-15871"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/15872-16127.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b15872-16127"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/16128-16383.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b16128-16383"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/16384-16639.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b16384-16639"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/16640-16895.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b16640-16895"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/16896-17151.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b16896-17151"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/17152-17407.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b17152-17407"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/17408-17663.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b17408-17663"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/17664-17919.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b17664-17919"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/1792-2047.pbf",
    "content": "\n\u001a\n\rRoboto Medium\u0012\t1792-2047"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/17920-18175.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b17920-18175"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/18176-18431.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b18176-18431"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/18432-18687.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b18432-18687"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/18688-18943.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b18688-18943"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/18944-19199.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b18944-19199"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/19200-19455.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b19200-19455"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/19456-19711.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b19456-19711"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/19712-19967.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b19712-19967"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/19968-20223.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b19968-20223"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/20224-20479.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b20224-20479"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/2048-2303.pbf",
    "content": "\n\u001a\n\rRoboto Medium\u0012\t2048-2303"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/20480-20735.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b20480-20735"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/20736-20991.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b20736-20991"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/20992-21247.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b20992-21247"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/21248-21503.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b21248-21503"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/21504-21759.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b21504-21759"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/21760-22015.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b21760-22015"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/22016-22271.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b22016-22271"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/22272-22527.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b22272-22527"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/22528-22783.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b22528-22783"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/22784-23039.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b22784-23039"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/2304-2559.pbf",
    "content": "\n\u001a\n\rRoboto Medium\u0012\t2304-2559"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/23040-23295.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b23040-23295"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/23296-23551.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b23296-23551"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/23552-23807.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b23552-23807"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/23808-24063.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b23808-24063"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/24064-24319.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b24064-24319"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/24320-24575.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b24320-24575"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/24576-24831.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b24576-24831"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/24832-25087.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b24832-25087"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/25088-25343.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b25088-25343"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/25344-25599.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b25344-25599"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/2560-2815.pbf",
    "content": "\n\u001a\n\rRoboto Medium\u0012\t2560-2815"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/25600-25855.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b25600-25855"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/25856-26111.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b25856-26111"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/26112-26367.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b26112-26367"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/26368-26623.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b26368-26623"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/26624-26879.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b26624-26879"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/26880-27135.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b26880-27135"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/27136-27391.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b27136-27391"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/27392-27647.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b27392-27647"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/27648-27903.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b27648-27903"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/27904-28159.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b27904-28159"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/2816-3071.pbf",
    "content": "\n\u001a\n\rRoboto Medium\u0012\t2816-3071"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/28160-28415.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b28160-28415"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/28416-28671.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b28416-28671"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/28672-28927.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b28672-28927"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/28928-29183.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b28928-29183"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/29184-29439.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b29184-29439"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/29440-29695.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b29440-29695"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/29696-29951.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b29696-29951"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/29952-30207.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b29952-30207"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/30208-30463.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b30208-30463"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/30464-30719.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b30464-30719"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/3072-3327.pbf",
    "content": "\n\u001a\n\rRoboto Medium\u0012\t3072-3327"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/30720-30975.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b30720-30975"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/30976-31231.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b30976-31231"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/31232-31487.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b31232-31487"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/31488-31743.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b31488-31743"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/31744-31999.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b31744-31999"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/32000-32255.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b32000-32255"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/32256-32511.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b32256-32511"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/32512-32767.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b32512-32767"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/32768-33023.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b32768-33023"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/33024-33279.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b33024-33279"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/3328-3583.pbf",
    "content": "\n\u001a\n\rRoboto Medium\u0012\t3328-3583"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/33280-33535.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b33280-33535"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/33536-33791.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b33536-33791"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/33792-34047.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b33792-34047"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/34048-34303.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b34048-34303"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/34304-34559.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b34304-34559"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/34560-34815.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b34560-34815"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/34816-35071.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b34816-35071"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/35072-35327.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b35072-35327"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/35328-35583.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b35328-35583"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/35584-35839.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b35584-35839"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/3584-3839.pbf",
    "content": "\n\u001a\n\rRoboto Medium\u0012\t3584-3839"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/35840-36095.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b35840-36095"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/36096-36351.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b36096-36351"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/36352-36607.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b36352-36607"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/36608-36863.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b36608-36863"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/36864-37119.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b36864-37119"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/37120-37375.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b37120-37375"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/37376-37631.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b37376-37631"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/37632-37887.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b37632-37887"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/37888-38143.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b37888-38143"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/38144-38399.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b38144-38399"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/3840-4095.pbf",
    "content": "\n\u001a\n\rRoboto Medium\u0012\t3840-4095"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/38400-38655.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b38400-38655"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/38656-38911.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b38656-38911"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/38912-39167.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b38912-39167"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/39168-39423.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b39168-39423"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/39424-39679.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b39424-39679"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/39680-39935.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b39680-39935"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/39936-40191.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b39936-40191"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/40192-40447.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b40192-40447"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/40448-40703.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b40448-40703"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/40704-40959.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b40704-40959"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/4096-4351.pbf",
    "content": "\n\u001a\n\rRoboto Medium\u0012\t4096-4351"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/40960-41215.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b40960-41215"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/41216-41471.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b41216-41471"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/41472-41727.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b41472-41727"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/41728-41983.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b41728-41983"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/41984-42239.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b41984-42239"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/42240-42495.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b42240-42495"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/42496-42751.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b42496-42751"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/42752-43007.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b42752-43007"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/43008-43263.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b43008-43263"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/43264-43519.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b43264-43519"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/4352-4607.pbf",
    "content": "\n\u001a\n\rRoboto Medium\u0012\t4352-4607"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/43520-43775.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b43520-43775"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/43776-44031.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b43776-44031"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/44032-44287.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b44032-44287"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/44288-44543.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b44288-44543"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/44544-44799.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b44544-44799"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/44800-45055.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b44800-45055"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/45056-45311.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b45056-45311"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/45312-45567.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b45312-45567"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/45568-45823.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b45568-45823"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/45824-46079.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b45824-46079"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/4608-4863.pbf",
    "content": "\n\u001a\n\rRoboto Medium\u0012\t4608-4863"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/46080-46335.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b46080-46335"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/46336-46591.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b46336-46591"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/46592-46847.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b46592-46847"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/46848-47103.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b46848-47103"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/47104-47359.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b47104-47359"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/47360-47615.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b47360-47615"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/47616-47871.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b47616-47871"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/47872-48127.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b47872-48127"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/48128-48383.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b48128-48383"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/48384-48639.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b48384-48639"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/4864-5119.pbf",
    "content": "\n\u001a\n\rRoboto Medium\u0012\t4864-5119"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/48640-48895.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b48640-48895"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/48896-49151.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b48896-49151"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/49152-49407.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b49152-49407"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/49408-49663.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b49408-49663"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/49664-49919.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b49664-49919"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/49920-50175.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b49920-50175"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/50176-50431.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b50176-50431"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/50432-50687.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b50432-50687"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/50688-50943.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b50688-50943"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/50944-51199.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b50944-51199"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/5120-5375.pbf",
    "content": "\n\u001a\n\rRoboto Medium\u0012\t5120-5375"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/51200-51455.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b51200-51455"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/51456-51711.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b51456-51711"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/51712-51967.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b51712-51967"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/51968-52223.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b51968-52223"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/52224-52479.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b52224-52479"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/52480-52735.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b52480-52735"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/52736-52991.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b52736-52991"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/52992-53247.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b52992-53247"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/53248-53503.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b53248-53503"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/53504-53759.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b53504-53759"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/5376-5631.pbf",
    "content": "\n\u001a\n\rRoboto Medium\u0012\t5376-5631"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/53760-54015.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b53760-54015"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/54016-54271.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b54016-54271"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/54272-54527.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b54272-54527"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/54528-54783.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b54528-54783"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/54784-55039.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b54784-55039"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/55040-55295.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b55040-55295"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/55296-55551.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b55296-55551"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/55552-55807.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b55552-55807"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/55808-56063.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b55808-56063"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/56064-56319.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b56064-56319"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/5632-5887.pbf",
    "content": "\n\u001a\n\rRoboto Medium\u0012\t5632-5887"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/56320-56575.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b56320-56575"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/56576-56831.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b56576-56831"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/56832-57087.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b56832-57087"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/57088-57343.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b57088-57343"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/57344-57599.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b57344-57599"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/57600-57855.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b57600-57855"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/57856-58111.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b57856-58111"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/58112-58367.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b58112-58367"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/58368-58623.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b58368-58623"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/58624-58879.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b58624-58879"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/5888-6143.pbf",
    "content": "\n\u001a\n\rRoboto Medium\u0012\t5888-6143"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/58880-59135.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b58880-59135"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/59136-59391.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b59136-59391"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/59392-59647.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b59392-59647"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/59648-59903.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b59648-59903"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/59904-60159.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b59904-60159"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/60160-60415.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b60160-60415"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/60416-60671.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b60416-60671"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/60672-60927.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b60672-60927"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/60928-61183.pbf",
    "content": "\n\u0003\n\rRoboto Medium\u0012\u000b60928-61183\u001a\u0001\b\u0003\u0012\u0001\n\u001f7KY^YK:/\u001f\u001f8Lcv}vcYK77Lew}vcKKdwvYYvǯ}^^~ߴ~_Yvǯ}^KdwvY7Lew}vcK\u001f8Lcv}vcYK7\u001f7KY^^^YK7\u001f/Kcv}~}vcK7:YvvcKKd}vYYvɰ}^^}ߴ~_Yvů}^KdwvY7Lew}vcK\u001f8LZ___^YK7\u0018\u0005 \u000e(\u00020\r8\u0007\u001a\u0001\b\u0003\u0012\u00018LZ__Z^__ZL8Leww~weLZwwZ_ğĿ__ߟƟ__ߟƟ__ߟƟ__ߟƟ___ZwwZLeww}weL8LZ__Z^__ZL7\u0018\u0006 \u0006(\u00020\u00138\u0007"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/61184-61439.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b61184-61439"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/6144-6399.pbf",
    "content": "\n\u001a\n\rRoboto Medium\u0012\t6144-6399"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/61440-61695.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b61440-61695"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/61696-61951.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b61696-61951"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/61952-62207.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b61952-62207"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/62208-62463.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b62208-62463"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/62464-62719.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b62464-62719"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/62720-62975.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b62720-62975"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/63232-63487.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b63232-63487"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/63488-63743.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b63488-63743"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/63744-63999.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b63744-63999"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/6400-6655.pbf",
    "content": "\n\u001a\n\rRoboto Medium\u0012\t6400-6655"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/64000-64255.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b64000-64255"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/64512-64767.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b64512-64767"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/64768-65023.pbf",
    "content": "\n\u001c\n\rRoboto Medium\u0012\u000b64768-65023"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/6656-6911.pbf",
    "content": "\n\u001a\n\rRoboto Medium\u0012\t6656-6911"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/6912-7167.pbf",
    "content": "\n\u001a\n\rRoboto Medium\u0012\t6912-7167"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/7168-7423.pbf",
    "content": "\n\u001a\n\rRoboto Medium\u0012\t7168-7423"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/7424-7679.pbf",
    "content": "\n\u001a\n\rRoboto Medium\u0012\t7424-7679"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/8960-9215.pbf",
    "content": "\n\u001a\n\rRoboto Medium\u0012\t8960-9215"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/9216-9471.pbf",
    "content": "\n\u001a\n\rRoboto Medium\u0012\t9216-9471"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/9728-9983.pbf",
    "content": "\n\u001a\n\rRoboto Medium\u0012\t9728-9983"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Medium/9984-10239.pbf",
    "content": "\n\u001b\n\rRoboto Medium\u0012\n9984-10239"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/10240-10495.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b10240-10495"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/10496-10751.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b10496-10751"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/10752-11007.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b10752-11007"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/11008-11263.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b11008-11263"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/11264-11519.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b11264-11519"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/11520-11775.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b11520-11775"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/11776-12031.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b11776-12031"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/12032-12287.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b12032-12287"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/12288-12543.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b12288-12543"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/12544-12799.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b12544-12799"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/12800-13055.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b12800-13055"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/13056-13311.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b13056-13311"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/13312-13567.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b13312-13567"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/13568-13823.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b13568-13823"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/13824-14079.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b13824-14079"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/14080-14335.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b14080-14335"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/14336-14591.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b14336-14591"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/14592-14847.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b14592-14847"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/14848-15103.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b14848-15103"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/15104-15359.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b15104-15359"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/1536-1791.pbf",
    "content": "\n\u001b\n\u000eRoboto Regular\u0012\t1536-1791"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/15360-15615.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b15360-15615"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/15616-15871.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b15616-15871"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/15872-16127.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b15872-16127"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/16128-16383.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b16128-16383"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/16384-16639.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b16384-16639"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/16640-16895.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b16640-16895"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/16896-17151.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b16896-17151"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/17152-17407.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b17152-17407"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/17408-17663.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b17408-17663"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/17664-17919.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b17664-17919"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/1792-2047.pbf",
    "content": "\n\u001b\n\u000eRoboto Regular\u0012\t1792-2047"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/17920-18175.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b17920-18175"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/18176-18431.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b18176-18431"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/18432-18687.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b18432-18687"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/18688-18943.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b18688-18943"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/18944-19199.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b18944-19199"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/19200-19455.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b19200-19455"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/19456-19711.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b19456-19711"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/19712-19967.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b19712-19967"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/19968-20223.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b19968-20223"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/20224-20479.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b20224-20479"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/2048-2303.pbf",
    "content": "\n\u001b\n\u000eRoboto Regular\u0012\t2048-2303"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/20480-20735.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b20480-20735"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/20736-20991.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b20736-20991"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/20992-21247.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b20992-21247"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/21248-21503.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b21248-21503"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/21504-21759.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b21504-21759"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/21760-22015.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b21760-22015"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/22016-22271.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b22016-22271"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/22272-22527.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b22272-22527"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/22528-22783.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b22528-22783"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/22784-23039.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b22784-23039"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/2304-2559.pbf",
    "content": "\n\u001b\n\u000eRoboto Regular\u0012\t2304-2559"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/23040-23295.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b23040-23295"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/23296-23551.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b23296-23551"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/23552-23807.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b23552-23807"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/23808-24063.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b23808-24063"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/24064-24319.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b24064-24319"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/24320-24575.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b24320-24575"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/24576-24831.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b24576-24831"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/24832-25087.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b24832-25087"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/25088-25343.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b25088-25343"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/25344-25599.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b25344-25599"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/2560-2815.pbf",
    "content": "\n\u001b\n\u000eRoboto Regular\u0012\t2560-2815"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/25600-25855.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b25600-25855"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/25856-26111.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b25856-26111"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/26112-26367.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b26112-26367"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/26368-26623.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b26368-26623"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/26624-26879.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b26624-26879"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/26880-27135.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b26880-27135"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/27136-27391.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b27136-27391"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/27392-27647.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b27392-27647"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/27648-27903.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b27648-27903"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/27904-28159.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b27904-28159"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/2816-3071.pbf",
    "content": "\n\u001b\n\u000eRoboto Regular\u0012\t2816-3071"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/28160-28415.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b28160-28415"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/28416-28671.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b28416-28671"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/28672-28927.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b28672-28927"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/28928-29183.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b28928-29183"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/29184-29439.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b29184-29439"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/29440-29695.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b29440-29695"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/29696-29951.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b29696-29951"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/29952-30207.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b29952-30207"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/30208-30463.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b30208-30463"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/30464-30719.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b30464-30719"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/3072-3327.pbf",
    "content": "\n\u001b\n\u000eRoboto Regular\u0012\t3072-3327"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/30720-30975.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b30720-30975"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/30976-31231.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b30976-31231"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/31232-31487.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b31232-31487"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/31488-31743.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b31488-31743"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/31744-31999.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b31744-31999"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/32000-32255.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b32000-32255"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/32256-32511.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b32256-32511"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/32512-32767.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b32512-32767"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/32768-33023.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b32768-33023"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/33024-33279.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b33024-33279"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/3328-3583.pbf",
    "content": "\n\u001b\n\u000eRoboto Regular\u0012\t3328-3583"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/33280-33535.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b33280-33535"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/33536-33791.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b33536-33791"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/33792-34047.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b33792-34047"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/34048-34303.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b34048-34303"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/34304-34559.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b34304-34559"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/34560-34815.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b34560-34815"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/34816-35071.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b34816-35071"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/35072-35327.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b35072-35327"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/35328-35583.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b35328-35583"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/35584-35839.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b35584-35839"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/3584-3839.pbf",
    "content": "\n\u001b\n\u000eRoboto Regular\u0012\t3584-3839"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/35840-36095.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b35840-36095"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/36096-36351.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b36096-36351"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/36352-36607.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b36352-36607"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/36608-36863.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b36608-36863"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/36864-37119.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b36864-37119"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/37120-37375.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b37120-37375"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/37376-37631.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b37376-37631"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/37632-37887.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b37632-37887"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/37888-38143.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b37888-38143"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/38144-38399.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b38144-38399"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/3840-4095.pbf",
    "content": "\n\u001b\n\u000eRoboto Regular\u0012\t3840-4095"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/38400-38655.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b38400-38655"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/38656-38911.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b38656-38911"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/38912-39167.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b38912-39167"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/39168-39423.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b39168-39423"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/39424-39679.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b39424-39679"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/39680-39935.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b39680-39935"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/39936-40191.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b39936-40191"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/40192-40447.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b40192-40447"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/40448-40703.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b40448-40703"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/40704-40959.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b40704-40959"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/4096-4351.pbf",
    "content": "\n\u001b\n\u000eRoboto Regular\u0012\t4096-4351"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/40960-41215.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b40960-41215"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/41216-41471.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b41216-41471"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/41472-41727.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b41472-41727"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/41728-41983.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b41728-41983"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/41984-42239.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b41984-42239"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/42240-42495.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b42240-42495"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/42496-42751.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b42496-42751"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/43008-43263.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b43008-43263"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/43264-43519.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b43264-43519"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/4352-4607.pbf",
    "content": "\n\u001b\n\u000eRoboto Regular\u0012\t4352-4607"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/43520-43775.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b43520-43775"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/44032-44287.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b44032-44287"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/44288-44543.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b44288-44543"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/44544-44799.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b44544-44799"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/44800-45055.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b44800-45055"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/45056-45311.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b45056-45311"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/45312-45567.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b45312-45567"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/45568-45823.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b45568-45823"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/45824-46079.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b45824-46079"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/4608-4863.pbf",
    "content": "\n\u001b\n\u000eRoboto Regular\u0012\t4608-4863"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/46080-46335.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b46080-46335"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/46336-46591.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b46336-46591"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/46592-46847.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b46592-46847"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/46848-47103.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b46848-47103"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/47104-47359.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b47104-47359"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/47360-47615.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b47360-47615"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/47616-47871.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b47616-47871"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/47872-48127.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b47872-48127"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/48128-48383.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b48128-48383"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/48384-48639.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b48384-48639"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/4864-5119.pbf",
    "content": "\n\u001b\n\u000eRoboto Regular\u0012\t4864-5119"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/48640-48895.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b48640-48895"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/48896-49151.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b48896-49151"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/49152-49407.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b49152-49407"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/49408-49663.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b49408-49663"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/49664-49919.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b49664-49919"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/49920-50175.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b49920-50175"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/50176-50431.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b50176-50431"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/50432-50687.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b50432-50687"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/50688-50943.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b50688-50943"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/50944-51199.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b50944-51199"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/5120-5375.pbf",
    "content": "\n\u001b\n\u000eRoboto Regular\u0012\t5120-5375"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/51200-51455.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b51200-51455"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/51456-51711.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b51456-51711"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/51712-51967.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b51712-51967"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/51968-52223.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b51968-52223"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/52224-52479.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b52224-52479"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/52480-52735.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b52480-52735"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/52736-52991.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b52736-52991"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/52992-53247.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b52992-53247"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/53248-53503.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b53248-53503"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/53504-53759.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b53504-53759"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/5376-5631.pbf",
    "content": "\n\u001b\n\u000eRoboto Regular\u0012\t5376-5631"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/53760-54015.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b53760-54015"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/54016-54271.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b54016-54271"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/54272-54527.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b54272-54527"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/54528-54783.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b54528-54783"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/54784-55039.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b54784-55039"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/55040-55295.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b55040-55295"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/55296-55551.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b55296-55551"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/55552-55807.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b55552-55807"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/55808-56063.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b55808-56063"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/56064-56319.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b56064-56319"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/5632-5887.pbf",
    "content": "\n\u001b\n\u000eRoboto Regular\u0012\t5632-5887"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/56320-56575.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b56320-56575"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/56576-56831.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b56576-56831"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/56832-57087.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b56832-57087"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/57088-57343.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b57088-57343"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/57344-57599.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b57344-57599"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/57600-57855.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b57600-57855"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/57856-58111.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b57856-58111"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/58112-58367.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b58112-58367"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/58368-58623.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b58368-58623"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/58624-58879.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b58624-58879"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/5888-6143.pbf",
    "content": "\n\u001b\n\u000eRoboto Regular\u0012\t5888-6143"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/58880-59135.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b58880-59135"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/59136-59391.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b59136-59391"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/59392-59647.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b59392-59647"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/59648-59903.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b59648-59903"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/59904-60159.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b59904-60159"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/60160-60415.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b60160-60415"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/60416-60671.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b60416-60671"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/60672-60927.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b60672-60927"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/60928-61183.pbf",
    "content": "\n\u0003\n!Roboto Regular, Open Sans Regular\u0012\u000b60929-60930\u001a\u0001\b\u0003\u0012\u00018LZ___ZL7LewweLZwwZ_ɻ__ȟ__ķ_ZwwZLdwwdL7LZ___ZL7\u001f0;???;0\u001f7KY___YK7Kdw~~wdKYwwY_~~__ǟ__ο_ZwwZLewweL8Lcv}vcL8\u001f7KY^YK7\u001f\u0018\u0003 \u000e(\u00040\u000f8\u0006\u001a\u0001\b\u0003\u0012\u00018LZ__Z^__ZL7Leww}weLZwwZ_ßż__͟__͟__͟__͟___ZwwZLeww}wdL7LZ__Z^__ZL7\u0018\u0006 \u0006(\u00020\u00138\u0007"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/61184-61439.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b61184-61439"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/6144-6399.pbf",
    "content": "\n\u001b\n\u000eRoboto Regular\u0012\t6144-6399"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/61440-61695.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b61440-61695"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/61696-61951.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b61696-61951"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/61952-62207.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b61952-62207"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/62208-62463.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b62208-62463"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/62464-62719.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b62464-62719"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/62720-62975.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b62720-62975"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/62976-63231.pbf",
    "content": "\n\u0001\n!Roboto Regular, Open Sans Regular\u0012\u000b63171-63171\u001a~\b\u0003\u0012n7KY^__^YK7Kcv}}vcKYvvY^}ȯ}^^~ΟvY_ȟcK_߻_?_¯}^>ZwvY:Ldw}vcK/7LZ__^YK7\u001f\u0018\u0004 \u0005(\u00020'8\u0006"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/63232-63487.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b63232-63487"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/63488-63743.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b63488-63743"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/63744-63999.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b63744-63999"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/6400-6655.pbf",
    "content": "\n\u001b\n\u000eRoboto Regular\u0012\t6400-6655"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/64000-64255.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b64000-64255"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/64512-64767.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b64512-64767"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/64768-65023.pbf",
    "content": "\n\u001d\n\u000eRoboto Regular\u0012\u000b64768-65023"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/6656-6911.pbf",
    "content": "\n\u001b\n\u000eRoboto Regular\u0012\t6656-6911"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/6912-7167.pbf",
    "content": "\n\u001b\n\u000eRoboto Regular\u0012\t6912-7167"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/7168-7423.pbf",
    "content": "\n\u001b\n\u000eRoboto Regular\u0012\t7168-7423"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/7424-7679.pbf",
    "content": "\n\u001b\n\u000eRoboto Regular\u0012\t7424-7679"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/8960-9215.pbf",
    "content": "\n\u001b\n\u000eRoboto Regular\u0012\t8960-9215"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/9216-9471.pbf",
    "content": "\n\u001b\n\u000eRoboto Regular\u0012\t9216-9471"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/9728-9983.pbf",
    "content": "\n\u001b\n\u000eRoboto Regular\u0012\t9728-9983"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/Roboto Regular/9984-10239.pbf",
    "content": "\n\u001c\n\u000eRoboto Regular\u0012\n9984-10239"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/sprites.json",
    "content": "{\n  \"capital\": {\n    \"height\": 14,\n    \"pixelRatio\": 1,\n    \"width\": 14,\n    \"x\": 485,\n    \"y\": 64\n  },\n  \"city\": {\n    \"height\": 14,\n    \"pixelRatio\": 1,\n    \"width\": 14,\n    \"x\": 485,\n    \"y\": 78\n  },\n  \"poi_generic\": {\n    \"height\": 93,\n    \"pixelRatio\": 1,\n    \"width\": 64,\n    \"x\": 0,\n    \"y\": 0\n  },\n  \"poi_generic_blue\": {\n    \"height\": 93,\n    \"pixelRatio\": 1,\n    \"width\": 64,\n    \"x\": 0,\n    \"y\": 93\n  },\n  \"poi_generic_green\": {\n    \"height\": 93,\n    \"pixelRatio\": 1,\n    \"width\": 64,\n    \"x\": 64,\n    \"y\": 0\n  },\n  \"poi_generic_orange\": {\n    \"height\": 93,\n    \"pixelRatio\": 1,\n    \"width\": 64,\n    \"x\": 64,\n    \"y\": 93\n  },\n  \"poi_generic_purple\": {\n    \"height\": 93,\n    \"pixelRatio\": 1,\n    \"width\": 64,\n    \"x\": 128,\n    \"y\": 0\n  },\n  \"poi_generic_red\": {\n    \"height\": 93,\n    \"pixelRatio\": 1,\n    \"width\": 64,\n    \"x\": 128,\n    \"y\": 93\n  },\n  \"poi_generic_teal\": {\n    \"height\": 93,\n    \"pixelRatio\": 1,\n    \"width\": 64,\n    \"x\": 192,\n    \"y\": 0\n  },\n  \"poi_grocery\": {\n    \"height\": 93,\n    \"pixelRatio\": 1,\n    \"width\": 64,\n    \"x\": 192,\n    \"y\": 93\n  },\n  \"poi_lodging\": {\n    \"height\": 93,\n    \"pixelRatio\": 1,\n    \"width\": 64,\n    \"x\": 256,\n    \"y\": 0\n  },\n  \"poi_museum\": {\n    \"height\": 93,\n    \"pixelRatio\": 1,\n    \"width\": 64,\n    \"x\": 256,\n    \"y\": 93\n  },\n  \"poi_res\": {\n    \"height\": 93,\n    \"pixelRatio\": 1,\n    \"width\": 64,\n    \"x\": 320,\n    \"y\": 0\n  },\n  \"poi_restaurant\": {\n    \"height\": 93,\n    \"pixelRatio\": 1,\n    \"width\": 64,\n    \"x\": 320,\n    \"y\": 93\n  },\n  \"poi_theatre\": {\n    \"height\": 93,\n    \"pixelRatio\": 1,\n    \"width\": 64,\n    \"x\": 384,\n    \"y\": 0\n  },\n  \"shield_de-motorway_2\": {\n    \"height\": 19,\n    \"pixelRatio\": 1,\n    \"width\": 30,\n    \"x\": 384,\n    \"y\": 144\n  },\n  \"shield_de-motorway_3\": {\n    \"height\": 19,\n    \"pixelRatio\": 1,\n    \"width\": 32,\n    \"x\": 384,\n    \"y\": 125\n  },\n  \"shield_rectangle-blue_2\": {\n    \"height\": 16,\n    \"pixelRatio\": 1,\n    \"width\": 26,\n    \"x\": 483,\n    \"y\": 137\n  },\n  \"shield_rectangle-blue_3\": {\n    \"height\": 16,\n    \"pixelRatio\": 1,\n    \"width\": 31,\n    \"x\": 452,\n    \"y\": 137\n  },\n  \"shield_rectangle-blue_4\": {\n    \"height\": 16,\n    \"pixelRatio\": 1,\n    \"width\": 36,\n    \"x\": 472,\n    \"y\": 105\n  },\n  \"shield_rectangle-blue_5\": {\n    \"height\": 16,\n    \"pixelRatio\": 1,\n    \"width\": 41,\n    \"x\": 384,\n    \"y\": 109\n  },\n  \"shield_rectangle-blue_6\": {\n    \"height\": 16,\n    \"pixelRatio\": 1,\n    \"width\": 44,\n    \"x\": 384,\n    \"y\": 93\n  },\n  \"shield_rectangle-green_2\": {\n    \"height\": 16,\n    \"pixelRatio\": 1,\n    \"width\": 26,\n    \"x\": 485,\n    \"y\": 0\n  },\n  \"shield_rectangle-green_3\": {\n    \"height\": 16,\n    \"pixelRatio\": 1,\n    \"width\": 31,\n    \"x\": 414,\n    \"y\": 153\n  },\n  \"shield_rectangle-green_4\": {\n    \"height\": 16,\n    \"pixelRatio\": 1,\n    \"width\": 36,\n    \"x\": 466,\n    \"y\": 121\n  },\n  \"shield_rectangle-red_2\": {\n    \"height\": 16,\n    \"pixelRatio\": 1,\n    \"width\": 26,\n    \"x\": 485,\n    \"y\": 16\n  },\n  \"shield_rectangle-red_3\": {\n    \"height\": 16,\n    \"pixelRatio\": 1,\n    \"width\": 31,\n    \"x\": 445,\n    \"y\": 153\n  },\n  \"shield_rectangle-white_2\": {\n    \"height\": 16,\n    \"pixelRatio\": 1,\n    \"width\": 26,\n    \"x\": 485,\n    \"y\": 32\n  },\n  \"shield_rectangle-white_3\": {\n    \"height\": 16,\n    \"pixelRatio\": 1,\n    \"width\": 31,\n    \"x\": 476,\n    \"y\": 153\n  },\n  \"shield_rectangle-white_4\": {\n    \"height\": 16,\n    \"pixelRatio\": 1,\n    \"width\": 36,\n    \"x\": 416,\n    \"y\": 137\n  },\n  \"shield_rectangle-white_5\": {\n    \"height\": 16,\n    \"pixelRatio\": 1,\n    \"width\": 41,\n    \"x\": 425,\n    \"y\": 121\n  },\n  \"shield_rectangle-white_6\": {\n    \"height\": 16,\n    \"pixelRatio\": 1,\n    \"width\": 44,\n    \"x\": 428,\n    \"y\": 105\n  },\n  \"shield_rectangle-yellow_2\": {\n    \"height\": 16,\n    \"pixelRatio\": 1,\n    \"width\": 26,\n    \"x\": 485,\n    \"y\": 48\n  },\n  \"shield_rectangle-yellow_3\": {\n    \"height\": 16,\n    \"pixelRatio\": 1,\n    \"width\": 31,\n    \"x\": 384,\n    \"y\": 169\n  },\n  \"shield_us-interstate_2\": {\n    \"height\": 35,\n    \"pixelRatio\": 1,\n    \"width\": 37,\n    \"x\": 448,\n    \"y\": 0\n  },\n  \"shield_us-interstate_3\": {\n    \"height\": 35,\n    \"pixelRatio\": 1,\n    \"width\": 37,\n    \"x\": 448,\n    \"y\": 35\n  },\n  \"shield_us-interstate_4\": {\n    \"height\": 35,\n    \"pixelRatio\": 1,\n    \"width\": 37,\n    \"x\": 448,\n    \"y\": 70\n  }\n}"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/sprites@2x.json",
    "content": "{\n  \"capital\": {\n    \"height\": 28,\n    \"pixelRatio\": 2,\n    \"width\": 28,\n    \"x\": 970,\n    \"y\": 128\n  },\n  \"city\": {\n    \"height\": 28,\n    \"pixelRatio\": 2,\n    \"width\": 28,\n    \"x\": 970,\n    \"y\": 156\n  },\n  \"poi_generic\": {\n    \"height\": 186,\n    \"pixelRatio\": 2,\n    \"width\": 128,\n    \"x\": 0,\n    \"y\": 0\n  },\n  \"poi_generic_blue\": {\n    \"height\": 186,\n    \"pixelRatio\": 2,\n    \"width\": 128,\n    \"x\": 0,\n    \"y\": 186\n  },\n  \"poi_generic_green\": {\n    \"height\": 186,\n    \"pixelRatio\": 2,\n    \"width\": 128,\n    \"x\": 128,\n    \"y\": 0\n  },\n  \"poi_generic_orange\": {\n    \"height\": 186,\n    \"pixelRatio\": 2,\n    \"width\": 128,\n    \"x\": 128,\n    \"y\": 186\n  },\n  \"poi_generic_purple\": {\n    \"height\": 186,\n    \"pixelRatio\": 2,\n    \"width\": 128,\n    \"x\": 256,\n    \"y\": 0\n  },\n  \"poi_generic_red\": {\n    \"height\": 186,\n    \"pixelRatio\": 2,\n    \"width\": 128,\n    \"x\": 256,\n    \"y\": 186\n  },\n  \"poi_generic_teal\": {\n    \"height\": 186,\n    \"pixelRatio\": 2,\n    \"width\": 128,\n    \"x\": 384,\n    \"y\": 0\n  },\n  \"poi_grocery\": {\n    \"height\": 186,\n    \"pixelRatio\": 2,\n    \"width\": 128,\n    \"x\": 384,\n    \"y\": 186\n  },\n  \"poi_lodging\": {\n    \"height\": 186,\n    \"pixelRatio\": 2,\n    \"width\": 128,\n    \"x\": 512,\n    \"y\": 0\n  },\n  \"poi_museum\": {\n    \"height\": 186,\n    \"pixelRatio\": 2,\n    \"width\": 128,\n    \"x\": 512,\n    \"y\": 186\n  },\n  \"poi_res\": {\n    \"height\": 186,\n    \"pixelRatio\": 2,\n    \"width\": 128,\n    \"x\": 640,\n    \"y\": 0\n  },\n  \"poi_restaurant\": {\n    \"height\": 186,\n    \"pixelRatio\": 2,\n    \"width\": 128,\n    \"x\": 640,\n    \"y\": 186\n  },\n  \"poi_theatre\": {\n    \"height\": 186,\n    \"pixelRatio\": 2,\n    \"width\": 128,\n    \"x\": 768,\n    \"y\": 0\n  },\n  \"shield_de-motorway_2\": {\n    \"height\": 38,\n    \"pixelRatio\": 2,\n    \"width\": 60,\n    \"x\": 768,\n    \"y\": 288\n  },\n  \"shield_de-motorway_3\": {\n    \"height\": 38,\n    \"pixelRatio\": 2,\n    \"width\": 64,\n    \"x\": 768,\n    \"y\": 250\n  },\n  \"shield_rectangle-blue_2\": {\n    \"height\": 32,\n    \"pixelRatio\": 2,\n    \"width\": 52,\n    \"x\": 966,\n    \"y\": 274\n  },\n  \"shield_rectangle-blue_3\": {\n    \"height\": 32,\n    \"pixelRatio\": 2,\n    \"width\": 62,\n    \"x\": 904,\n    \"y\": 274\n  },\n  \"shield_rectangle-blue_4\": {\n    \"height\": 32,\n    \"pixelRatio\": 2,\n    \"width\": 72,\n    \"x\": 944,\n    \"y\": 210\n  },\n  \"shield_rectangle-blue_5\": {\n    \"height\": 32,\n    \"pixelRatio\": 2,\n    \"width\": 82,\n    \"x\": 768,\n    \"y\": 218\n  },\n  \"shield_rectangle-blue_6\": {\n    \"height\": 32,\n    \"pixelRatio\": 2,\n    \"width\": 88,\n    \"x\": 768,\n    \"y\": 186\n  },\n  \"shield_rectangle-green_2\": {\n    \"height\": 32,\n    \"pixelRatio\": 2,\n    \"width\": 52,\n    \"x\": 970,\n    \"y\": 0\n  },\n  \"shield_rectangle-green_3\": {\n    \"height\": 32,\n    \"pixelRatio\": 2,\n    \"width\": 62,\n    \"x\": 828,\n    \"y\": 306\n  },\n  \"shield_rectangle-green_4\": {\n    \"height\": 32,\n    \"pixelRatio\": 2,\n    \"width\": 72,\n    \"x\": 932,\n    \"y\": 242\n  },\n  \"shield_rectangle-red_2\": {\n    \"height\": 32,\n    \"pixelRatio\": 2,\n    \"width\": 52,\n    \"x\": 970,\n    \"y\": 32\n  },\n  \"shield_rectangle-red_3\": {\n    \"height\": 32,\n    \"pixelRatio\": 2,\n    \"width\": 62,\n    \"x\": 890,\n    \"y\": 306\n  },\n  \"shield_rectangle-white_2\": {\n    \"height\": 32,\n    \"pixelRatio\": 2,\n    \"width\": 52,\n    \"x\": 970,\n    \"y\": 64\n  },\n  \"shield_rectangle-white_3\": {\n    \"height\": 32,\n    \"pixelRatio\": 2,\n    \"width\": 62,\n    \"x\": 952,\n    \"y\": 306\n  },\n  \"shield_rectangle-white_4\": {\n    \"height\": 32,\n    \"pixelRatio\": 2,\n    \"width\": 72,\n    \"x\": 832,\n    \"y\": 274\n  },\n  \"shield_rectangle-white_5\": {\n    \"height\": 32,\n    \"pixelRatio\": 2,\n    \"width\": 82,\n    \"x\": 850,\n    \"y\": 242\n  },\n  \"shield_rectangle-white_6\": {\n    \"height\": 32,\n    \"pixelRatio\": 2,\n    \"width\": 88,\n    \"x\": 856,\n    \"y\": 210\n  },\n  \"shield_rectangle-yellow_2\": {\n    \"height\": 32,\n    \"pixelRatio\": 2,\n    \"width\": 52,\n    \"x\": 970,\n    \"y\": 96\n  },\n  \"shield_rectangle-yellow_3\": {\n    \"height\": 32,\n    \"pixelRatio\": 2,\n    \"width\": 62,\n    \"x\": 768,\n    \"y\": 338\n  },\n  \"shield_us-interstate_2\": {\n    \"height\": 70,\n    \"pixelRatio\": 2,\n    \"width\": 74,\n    \"x\": 896,\n    \"y\": 0\n  },\n  \"shield_us-interstate_3\": {\n    \"height\": 70,\n    \"pixelRatio\": 2,\n    \"width\": 74,\n    \"x\": 896,\n    \"y\": 70\n  },\n  \"shield_us-interstate_4\": {\n    \"height\": 70,\n    \"pixelRatio\": 2,\n    \"width\": 74,\n    \"x\": 896,\n    \"y\": 140\n  }\n}"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/style-mapbox-outdoors-v12.json",
    "content": "{\n    \"name\": \"Mapbox Outdoors\",\n    \"sprite\": \"mapbox://sprites/mapbox/outdoors-v12\",\n    \"glyphs\": \"mapbox://fonts/mapbox/{fontstack}/{range}.pbf\",\n    \"center\": [\n        9.1,\n        42.2\n    ],\n    \"zoom\": 7.5,\n    \"fog\": {\n        \"range\": [\n            1,\n            20\n        ],\n        \"color\": [\n            \"interpolate\",\n            [\n                \"linear\"\n            ],\n            [\n                \"zoom\"\n            ],\n            4,\n            \"hsl(200, 100%, 100%)\",\n            6,\n            \"hsl(200, 50%, 90%)\"\n        ],\n        \"high-color\": [\n            \"interpolate\",\n            [\n                \"linear\"\n            ],\n            [\n                \"zoom\"\n            ],\n            4,\n            \"hsl(200, 100%, 60%)\",\n            6,\n            \"hsl(310, 60%, 80%)\"\n        ],\n        \"space-color\": [\n            \"interpolate\",\n            [\n                \"exponential\",\n                1.2\n            ],\n            [\n                \"zoom\"\n            ],\n            4,\n            \"hsl(205, 10%, 10%)\",\n            6,\n            \"hsl(205, 60%, 50%)\"\n        ],\n        \"horizon-blend\": [\n            \"interpolate\",\n            [\n                \"exponential\",\n                1.2\n            ],\n            [\n                \"zoom\"\n            ],\n            4,\n            0.01,\n            6,\n            0.1\n        ],\n        \"star-intensity\": [\n            \"interpolate\",\n            [\n                \"exponential\",\n                1.2\n            ],\n            [\n                \"zoom\"\n            ],\n            4,\n            0.1,\n            6,\n            0\n        ]\n    },\n    \"projection\": {\n        \"name\": \"globe\"\n    },\n    \"visibility\": \"public\",\n    \"version\": 8,\n    \"layers\": [\n        {\n            \"id\": \"land\",\n            \"type\": \"background\",\n            \"layout\": {},\n            \"minzoom\": 0,\n            \"paint\": {\n                \"background-color\": \"hsl(60, 20%, 85%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"land-and-water\",\n                \"mapbox:group\": \"Land & water, land\",\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"landcover\",\n            \"type\": \"fill\",\n            \"source\": \"composite\",\n            \"source-layer\": \"landcover\",\n            \"minzoom\": 0,\n            \"maxzoom\": 12,\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"wood\",\n                    \"hsla(103, 50%, 60%, 0.8)\",\n                    \"scrub\",\n                    \"hsla(98, 47%, 68%, 0.6)\",\n                    \"crop\",\n                    \"hsla(68, 55%, 70%, 0.6)\",\n                    \"grass\",\n                    \"hsla(98, 50%, 74%, 0.6)\",\n                    \"snow\",\n                    \"hsl(205, 45%, 95%)\",\n                    \"hsl(98, 48%, 67%)\"\n                ],\n                \"fill-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    0.8,\n                    12,\n                    0\n                ],\n                \"fill-antialias\": false\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"land-and-water\",\n                \"mapbox:group\": \"Land & water, land\",\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"national-park\",\n            \"type\": \"fill\",\n            \"source\": \"composite\",\n            \"source-layer\": \"landuse_overlay\",\n            \"minzoom\": 5,\n            \"filter\": [\n                \"==\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                \"national_park\"\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": \"hsl(98, 38%, 68%)\",\n                \"fill-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    5,\n                    0,\n                    6,\n                    0.6,\n                    12,\n                    0.2\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"land-and-water\",\n                \"mapbox:group\": \"Land & water, land\",\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"national-park_tint-band\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"landuse_overlay\",\n            \"minzoom\": 9,\n            \"filter\": [\n                \"==\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                \"national_park\"\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsl(98, 38%, 68%)\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    1,\n                    14,\n                    8\n                ],\n                \"line-blur\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    1,\n                    14,\n                    8\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"land-and-water\",\n                \"mapbox:group\": \"Land & water, land\",\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"landuse\",\n            \"type\": \"fill\",\n            \"source\": \"composite\",\n            \"source-layer\": \"landuse\",\n            \"minzoom\": 5,\n            \"filter\": [\n                \"all\",\n                [\n                    \">=\",\n                    [\n                        \"to-number\",\n                        [\n                            \"get\",\n                            \"sizerank\"\n                        ]\n                    ],\n                    0\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"agriculture\",\n                        \"wood\",\n                        \"grass\",\n                        \"scrub\",\n                        \"glacier\",\n                        \"pitch\",\n                        \"sand\"\n                    ],\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        false,\n                        11,\n                        true\n                    ],\n                    \"residential\",\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        true,\n                        10,\n                        false\n                    ],\n                    [\n                        \"park\",\n                        \"airport\"\n                    ],\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        false,\n                        8,\n                        [\n                            \"case\",\n                            [\n                                \"==\",\n                                [\n                                    \"get\",\n                                    \"sizerank\"\n                                ],\n                                1\n                            ],\n                            true,\n                            false\n                        ],\n                        10,\n                        true\n                    ],\n                    [\n                        \"facility\",\n                        \"industrial\"\n                    ],\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        false,\n                        12,\n                        true\n                    ],\n                    \"rock\",\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        false,\n                        11,\n                        true\n                    ],\n                    \"cemetery\",\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        false,\n                        11,\n                        true\n                    ],\n                    \"school\",\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        false,\n                        11,\n                        true\n                    ],\n                    \"hospital\",\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        false,\n                        11,\n                        true\n                    ],\n                    \"commercial_area\",\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        false,\n                        11,\n                        true\n                    ],\n                    false\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"-\",\n                        [\n                            \"to-number\",\n                            [\n                                \"get\",\n                                \"sizerank\"\n                            ]\n                        ],\n                        [\n                            \"interpolate\",\n                            [\n                                \"exponential\",\n                                1.5\n                            ],\n                            [\n                                \"zoom\"\n                            ],\n                            12,\n                            0,\n                            18,\n                            14\n                        ]\n                    ],\n                    14\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        \"wood\",\n                        \"hsla(103, 50%, 60%, 0.8)\",\n                        \"scrub\",\n                        \"hsla(98, 47%, 68%, 0.6)\",\n                        \"agriculture\",\n                        \"hsla(98, 50%, 74%, 0.6)\",\n                        \"park\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"type\"\n                            ],\n                            [\n                                \"garden\",\n                                \"playground\",\n                                \"zoo\"\n                            ],\n                            \"hsl(98, 38%, 68%)\",\n                            \"hsl(98, 55%, 70%)\"\n                        ],\n                        \"grass\",\n                        \"hsla(98, 50%, 74%, 0.6)\",\n                        \"airport\",\n                        \"hsl(230, 40%, 82%)\",\n                        \"cemetery\",\n                        \"hsl(98, 45%, 75%)\",\n                        \"glacier\",\n                        \"hsl(205, 45%, 95%)\",\n                        \"hospital\",\n                        \"hsl(20, 45%, 82%)\",\n                        \"pitch\",\n                        \"hsl(88, 65%, 75%)\",\n                        \"sand\",\n                        \"hsl(69, 60%, 72%)\",\n                        \"rock\",\n                        \"hsl(60, 0%, 85%)\",\n                        \"school\",\n                        \"hsl(40, 45%, 78%)\",\n                        \"commercial_area\",\n                        \"hsl(55, 45%, 85%)\",\n                        \"residential\",\n                        \"hsl(60, 7%, 87%)\",\n                        [\n                            \"facility\",\n                            \"industrial\"\n                        ],\n                        \"hsl(230, 20%, 85%)\",\n                        \"hsl(60, 22%, 72%)\"\n                    ],\n                    16,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        \"wood\",\n                        \"hsla(103, 50%, 60%, 0.8)\",\n                        \"scrub\",\n                        \"hsla(98, 47%, 68%, 0.6)\",\n                        \"agriculture\",\n                        \"hsla(98, 50%, 74%, 0.6)\",\n                        \"park\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"type\"\n                            ],\n                            [\n                                \"garden\",\n                                \"playground\",\n                                \"zoo\"\n                            ],\n                            \"hsl(98, 38%, 68%)\",\n                            \"hsl(98, 55%, 70%)\"\n                        ],\n                        \"grass\",\n                        \"hsla(98, 50%, 74%, 0.6)\",\n                        \"airport\",\n                        \"hsl(230, 40%, 82%)\",\n                        \"cemetery\",\n                        \"hsl(98, 45%, 75%)\",\n                        \"glacier\",\n                        \"hsl(205, 45%, 95%)\",\n                        \"hospital\",\n                        \"hsl(20, 45%, 82%)\",\n                        \"pitch\",\n                        \"hsl(88, 65%, 75%)\",\n                        \"sand\",\n                        \"hsl(69, 60%, 72%)\",\n                        \"rock\",\n                        \"hsla(60, 0%, 85%, 0.5)\",\n                        \"school\",\n                        \"hsl(40, 45%, 78%)\",\n                        \"commercial_area\",\n                        \"hsla(55, 45%, 85%, 0.5)\",\n                        [\n                            \"facility\",\n                            \"industrial\"\n                        ],\n                        \"hsl(230, 20%, 85%)\",\n                        \"hsl(60, 22%, 72%)\"\n                    ]\n                ],\n                \"fill-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        \"residential\",\n                        0.8,\n                        0.2\n                    ],\n                    10,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        \"residential\",\n                        0,\n                        1\n                    ]\n                ],\n                \"fill-antialias\": false\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"land-and-water\",\n                \"mapbox:group\": \"Land & water, land\",\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"pitch-outline\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"landuse\",\n            \"minzoom\": 15,\n            \"filter\": [\n                \"==\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                \"pitch\"\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsl(88, 60%, 65%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"land-and-water\",\n                \"mapbox:group\": \"Land & water, land\",\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"waterway-shadow\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"waterway\",\n            \"minzoom\": 10,\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    11,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    11,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-color\": \"hsl(224, 79%, 69%)\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.3\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"canal\",\n                            \"river\"\n                        ],\n                        0.1,\n                        0\n                    ],\n                    20,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"canal\",\n                            \"river\"\n                        ],\n                        8,\n                        3\n                    ]\n                ],\n                \"line-translate\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.2\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    7,\n                    [\n                        \"literal\",\n                        [\n                            0,\n                            0\n                        ]\n                    ],\n                    16,\n                    [\n                        \"literal\",\n                        [\n                            -1,\n                            -1\n                        ]\n                    ]\n                ],\n                \"line-translate-anchor\": \"viewport\",\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    0,\n                    8.5,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"land-and-water\",\n                \"mapbox:group\": \"Land & water, water\",\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"water-shadow\",\n            \"type\": \"fill\",\n            \"source\": \"composite\",\n            \"source-layer\": \"water\",\n            \"minzoom\": 10,\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": \"hsl(224, 79%, 69%)\",\n                \"fill-translate\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.2\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    7,\n                    [\n                        \"literal\",\n                        [\n                            0,\n                            0\n                        ]\n                    ],\n                    16,\n                    [\n                        \"literal\",\n                        [\n                            -1,\n                            -1\n                        ]\n                    ]\n                ],\n                \"fill-translate-anchor\": \"viewport\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"land-and-water\",\n                \"mapbox:group\": \"Land & water, water\",\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"waterway\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"waterway\",\n            \"minzoom\": 8,\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    11,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    11,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-color\": \"hsl(205, 75%, 70%)\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.3\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"canal\",\n                            \"river\"\n                        ],\n                        0.1,\n                        0\n                    ],\n                    20,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"canal\",\n                            \"river\"\n                        ],\n                        8,\n                        3\n                    ]\n                ],\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    0,\n                    8.5,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"land-and-water\",\n                \"mapbox:group\": \"Land & water, water\",\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"water\",\n            \"type\": \"fill\",\n            \"source\": \"composite\",\n            \"source-layer\": \"water\",\n            \"minzoom\": 0,\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": \"hsl(205, 75%, 70%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"land-and-water\",\n                \"mapbox:group\": \"Land & water, water\",\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"water-depth\",\n            \"type\": \"fill\",\n            \"source\": \"composite\",\n            \"source-layer\": \"depth\",\n            \"minzoom\": 0,\n            \"maxzoom\": 8,\n            \"layout\": {},\n            \"paint\": {\n                \"fill-antialias\": false,\n                \"fill-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    6,\n                    [\n                        \"interpolate\",\n                        [\n                            \"linear\"\n                        ],\n                        [\n                            \"get\",\n                            \"min_depth\"\n                        ],\n                        0,\n                        \"hsla(205, 75%, 70%, 0.35)\",\n                        200,\n                        \"hsla(205, 75%, 63%, 0.35)\",\n                        7000,\n                        \"hsla(205, 75%, 56%, 0.35)\"\n                    ],\n                    8,\n                    [\n                        \"interpolate\",\n                        [\n                            \"linear\"\n                        ],\n                        [\n                            \"get\",\n                            \"min_depth\"\n                        ],\n                        0,\n                        \"hsla(205, 75%, 70%, 0)\",\n                        200,\n                        \"hsla(205, 75%, 63%, 0)\",\n                        7000,\n                        \"hsla(205, 75%, 53%, 0)\"\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"land-and-water\",\n                \"mapbox:group\": \"Land & water, water\",\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"wetland\",\n            \"type\": \"fill\",\n            \"source\": \"composite\",\n            \"source-layer\": \"landuse_overlay\",\n            \"minzoom\": 5,\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"wetland\",\n                    \"wetland_noveg\"\n                ],\n                true,\n                false\n            ],\n            \"paint\": {\n                \"fill-color\": \"hsl(194, 38%, 74%)\",\n                \"fill-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    10,\n                    0.25,\n                    10.5,\n                    0.15\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"land-and-water\",\n                \"mapbox:group\": \"Land & water, water\",\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"wetland-pattern\",\n            \"type\": \"fill\",\n            \"source\": \"composite\",\n            \"source-layer\": \"landuse_overlay\",\n            \"minzoom\": 5,\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"wetland\",\n                    \"wetland_noveg\"\n                ],\n                true,\n                false\n            ],\n            \"paint\": {\n                \"fill-color\": \"hsl(194, 38%, 74%)\",\n                \"fill-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    10,\n                    0,\n                    10.5,\n                    1\n                ],\n                \"fill-pattern\": \"wetland\",\n                \"fill-translate-anchor\": \"viewport\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"land-and-water\",\n                \"mapbox:group\": \"Land & water, water\",\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"hillshade\",\n            \"type\": \"fill\",\n            \"source\": \"composite\",\n            \"source-layer\": \"hillshade\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"==\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        \"shadow\"\n                    ],\n                    11,\n                    true\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"level\"\n                    ],\n                    89,\n                    true,\n                    78,\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        false,\n                        5,\n                        true\n                    ],\n                    67,\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        false,\n                        9,\n                        true\n                    ],\n                    56,\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        false,\n                        6,\n                        true\n                    ],\n                    94,\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        false,\n                        11,\n                        true\n                    ],\n                    90,\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        false,\n                        12,\n                        true\n                    ],\n                    false\n                ]\n            ],\n            \"minzoom\": 0,\n            \"maxzoom\": 16,\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        \"shadow\",\n                        \"hsla(66, 38%, 17%, 0.08)\",\n                        \"hsla(60, 20%, 95%, 0.14)\"\n                    ],\n                    16,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        \"shadow\",\n                        \"hsla(66, 38%, 17%, 0)\",\n                        \"hsla(60, 20%, 95%, 0)\"\n                    ]\n                ],\n                \"fill-antialias\": false\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"terrain\",\n                \"mapbox:group\": \"Terrain, land\",\n                \"microg:gms-type-feature\": \"landscape.natural.terrain\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"contour-line\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"contour\",\n            \"minzoom\": 11,\n            \"filter\": [\n                \"!=\",\n                [\n                    \"get\",\n                    \"index\"\n                ],\n                -1\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    11,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"index\"\n                        ],\n                        [\n                            1,\n                            2\n                        ],\n                        0.15,\n                        0.3\n                    ],\n                    13,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"index\"\n                        ],\n                        [\n                            1,\n                            2\n                        ],\n                        0.3,\n                        0.5\n                    ]\n                ],\n                \"line-color\": \"hsl(60, 10%, 35%)\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    13,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"index\"\n                        ],\n                        [\n                            1,\n                            2\n                        ],\n                        0.5,\n                        0.6\n                    ],\n                    16,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"index\"\n                        ],\n                        [\n                            1,\n                            2\n                        ],\n                        0.8,\n                        1.2\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"terrain\",\n                \"mapbox:group\": \"Terrain, land\",\n                \"microg:gms-type-feature\": \"landscape.natural.terrain\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"land-structure-polygon\",\n            \"type\": \"fill\",\n            \"source\": \"composite\",\n            \"source-layer\": \"structure\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"land\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"Polygon\"\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": \"hsl(60, 20%, 85%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"land-and-water\",\n                \"mapbox:group\": \"Land & water, built\",\n                \"microg:gms-type-feature\": \"landscape.natural.terrain\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"land-structure-line\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"structure\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"land\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": \"square\"\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.99\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.75,\n                    20,\n                    40\n                ],\n                \"line-color\": \"hsl(60, 20%, 85%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"land-and-water\",\n                \"mapbox:group\": \"Land & water, built\",\n                \"microg:gms-type-feature\": \"landscape.natural.terrain\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"aeroway-polygon\",\n            \"type\": \"fill\",\n            \"source\": \"composite\",\n            \"source-layer\": \"aeroway\",\n            \"minzoom\": 11,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    [\n                        \"runway\",\n                        \"taxiway\",\n                        \"helipad\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"Polygon\"\n                ]\n            ],\n            \"paint\": {\n                \"fill-color\": \"hsl(230, 36%, 74%)\",\n                \"fill-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    10,\n                    0,\n                    11,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"transit\",\n                \"mapbox:group\": \"Transit, built\",\n                \"microg:gms-type-feature\": \"transit.station.airport\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"aeroway-line\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"aeroway\",\n            \"minzoom\": 9,\n            \"filter\": [\n                \"==\",\n                [\n                    \"geometry-type\"\n                ],\n                \"LineString\"\n            ],\n            \"paint\": {\n                \"line-color\": \"hsl(230, 36%, 74%)\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"type\"\n                        ],\n                        \"runway\",\n                        1,\n                        0.5\n                    ],\n                    18,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"type\"\n                        ],\n                        \"runway\",\n                        80,\n                        20\n                    ]\n                ],\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    10,\n                    0,\n                    11,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"transit\",\n                \"mapbox:group\": \"Transit, built\",\n                \"microg:gms-type-feature\": \"transit.station.airport\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"building\",\n            \"type\": \"fill\",\n            \"source\": \"composite\",\n            \"source-layer\": \"building\",\n            \"minzoom\": 15,\n            \"filter\": [\n                \"all\",\n                [\n                    \"!=\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    \"building:part\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"underground\"\n                    ],\n                    \"false\"\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": \"hsl(50, 15%, 75%)\",\n                \"fill-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    0,\n                    16,\n                    1\n                ],\n                \"fill-outline-color\": \"hsl(60, 10%, 65%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"buildings\",\n                \"mapbox:group\": \"Buildings, built\",\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"building-underground\",\n            \"type\": \"fill\",\n            \"source\": \"composite\",\n            \"source-layer\": \"building\",\n            \"minzoom\": 15,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"underground\"\n                    ],\n                    \"true\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"Polygon\"\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": \"hsl(260, 60%, 85%)\",\n                \"fill-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    0,\n                    16,\n                    0.5\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"buildings\",\n                \"mapbox:group\": \"Buildings, built\",\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"tunnel-minor-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"track\"\n                    ],\n                    true,\n                    \"service\",\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        false,\n                        14,\n                        true\n                    ],\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.8,\n                    22,\n                    2\n                ],\n                \"line-color\": \"hsl(60, 3%, 57%)\",\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    18,\n                    10,\n                    22,\n                    100\n                ],\n                \"line-dasharray\": [\n                    3,\n                    3\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, tunnels-case\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"tunnel-street-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"street\",\n                        \"street_limited\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.8,\n                    22,\n                    2\n                ],\n                \"line-color\": \"hsl(60, 3%, 57%)\",\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.5,\n                    18,\n                    20,\n                    22,\n                    200\n                ],\n                \"line-opacity\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    14,\n                    1\n                ],\n                \"line-dasharray\": [\n                    3,\n                    3\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, tunnels-case\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"tunnel-minor-link-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary_link\",\n                        \"secondary_link\",\n                        \"tertiary_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.8,\n                    22,\n                    2\n                ],\n                \"line-color\": \"hsl(60, 10%, 70%)\",\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.4,\n                    18,\n                    18,\n                    22,\n                    180\n                ],\n                \"line-opacity\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    11,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, tunnels-case\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"tunnel-secondary-tertiary-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 11,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"secondary\",\n                        \"tertiary\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    22,\n                    2\n                ],\n                \"line-color\": \"hsl(60, 3%, 57%)\",\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0,\n                    18,\n                    26,\n                    22,\n                    260\n                ],\n                \"line-dasharray\": [\n                    3,\n                    3\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, tunnels-case\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"tunnel-primary-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 10,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"primary\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    22,\n                    2\n                ],\n                \"line-color\": \"hsl(60, 3%, 57%)\",\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0.8,\n                    18,\n                    28,\n                    22,\n                    280\n                ],\n                \"line-dasharray\": [\n                    3,\n                    3\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, tunnels-case\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"tunnel-major-link-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 12,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"motorway_link\",\n                        \"trunk_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.8,\n                    22,\n                    2\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\",\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.8,\n                    18,\n                    20,\n                    22,\n                    200\n                ],\n                \"line-dasharray\": [\n                    3,\n                    3\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, tunnels-case\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"tunnel-motorway-trunk-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"motorway\",\n                        \"trunk\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    22,\n                    2\n                ],\n                \"line-color\": \"hsl(60, 10%, 82%)\",\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0.8,\n                    18,\n                    30,\n                    22,\n                    300\n                ],\n                \"line-dasharray\": [\n                    3,\n                    3\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, tunnels-case\",\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"tunnel-path-trail\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"path\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    [\n                        \"hiking\",\n                        \"mountain_bike\",\n                        \"trail\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    1,\n                    18,\n                    4\n                ],\n                \"line-color\": \"hsl(60, 32%, 90%)\",\n                \"line-dasharray\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            5,\n                            0.5\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            4,\n                            0.5\n                        ]\n                    ],\n                    16,\n                    [\n                        \"literal\",\n                        [\n                            4,\n                            0.45\n                        ]\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., tunnels\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"tunnel-path-cycleway-piste\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 12,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"path\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    [\n                        \"cycleway\",\n                        \"piste\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    1,\n                    18,\n                    4\n                ],\n                \"line-color\": \"hsl(60, 32%, 90%)\",\n                \"line-dasharray\": [\n                    10,\n                    0\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., tunnels\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"tunnel-path\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"path\"\n                ],\n                [\n                    \"!=\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    \"steps\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    1,\n                    18,\n                    4\n                ],\n                \"line-color\": \"hsl(60, 32%, 90%)\",\n                \"line-dasharray\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            1.75,\n                            1\n                        ]\n                    ],\n                    16,\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0.75\n                        ]\n                    ],\n                    17,\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0.5\n                        ]\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., tunnels\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"tunnel-steps\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    \"steps\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    1,\n                    16,\n                    1.6,\n                    18,\n                    6\n                ],\n                \"line-color\": \"hsl(60, 32%, 90%)\",\n                \"line-dasharray\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            1.75,\n                            1\n                        ]\n                    ],\n                    16,\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0.75\n                        ]\n                    ],\n                    17,\n                    [\n                        \"literal\",\n                        [\n                            0.3,\n                            0.3\n                        ]\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., tunnels\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"tunnel-pedestrian\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"pedestrian\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.5,\n                    18,\n                    12\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\",\n                \"line-dasharray\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            1.5,\n                            0.4\n                        ]\n                    ],\n                    16,\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0.2\n                        ]\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., tunnels\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"tunnel-construction\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"construction\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    2,\n                    18,\n                    20,\n                    22,\n                    200\n                ],\n                \"line-color\": \"hsl(60, 10%, 70%)\",\n                \"line-dasharray\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            0.4,\n                            0.8\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            0.3,\n                            0.6\n                        ]\n                    ],\n                    16,\n                    [\n                        \"literal\",\n                        [\n                            0.2,\n                            0.3\n                        ]\n                    ],\n                    17,\n                    [\n                        \"literal\",\n                        [\n                            0.2,\n                            0.25\n                        ]\n                    ],\n                    18,\n                    [\n                        \"literal\",\n                        [\n                            0.15,\n                            0.15\n                        ]\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, tunnels\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"tunnel-minor\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"track\"\n                    ],\n                    true,\n                    \"service\",\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        false,\n                        14,\n                        true\n                    ],\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    18,\n                    10,\n                    22,\n                    100\n                ],\n                \"line-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"street_limited\",\n                    \"hsl(60, 22%, 80%)\",\n                    \"hsl(0, 0%, 95%)\"\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, tunnels\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"tunnel-minor-link\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary_link\",\n                        \"secondary_link\",\n                        \"tertiary_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    13,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    13,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.4,\n                    18,\n                    18,\n                    22,\n                    180\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, tunnels\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"tunnel-major-link\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 12,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"motorway_link\",\n                        \"trunk_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.8,\n                    18,\n                    20,\n                    22,\n                    200\n                ],\n                \"line-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"motorway_link\",\n                    \"hsl(15, 100%, 85%)\",\n                    \"hsl(35, 78%, 85%)\"\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, tunnels\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"tunnel-street\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"street\",\n                        \"street_limited\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.5,\n                    18,\n                    20,\n                    22,\n                    200\n                ],\n                \"line-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"street_limited\",\n                    \"hsl(60, 22%, 80%)\",\n                    \"hsl(0, 0%, 95%)\"\n                ],\n                \"line-opacity\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    14,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, tunnels\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"tunnel-street-low\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"maxzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"street\",\n                        \"street_limited\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.5,\n                    18,\n                    20,\n                    22,\n                    200\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, tunnels\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"tunnel-secondary-tertiary\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"secondary\",\n                        \"tertiary\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0,\n                    18,\n                    26,\n                    22,\n                    260\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, tunnels\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"tunnel-primary\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"primary\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0.8,\n                    18,\n                    28,\n                    22,\n                    280\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, tunnels\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"tunnel-motorway-trunk\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"motorway\",\n                        \"trunk\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0.8,\n                    18,\n                    30,\n                    22,\n                    300\n                ],\n                \"line-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"motorway\",\n                    \"hsl(15, 100%, 85%)\",\n                    \"hsl(35, 78%, 85%)\"\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, tunnels\",\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"tunnel-oneway-arrow-blue\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 16,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"oneway\"\n                    ],\n                    \"true\"\n                ],\n                [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"primary\",\n                            \"secondary\",\n                            \"street\",\n                            \"street_limited\",\n                            \"tertiary\"\n                        ],\n                        true,\n                        false\n                    ],\n                    16,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"primary\",\n                            \"secondary\",\n                            \"tertiary\",\n                            \"street\",\n                            \"street_limited\",\n                            \"primary_link\",\n                            \"secondary_link\",\n                            \"tertiary_link\",\n                            \"service\",\n                            \"track\"\n                        ],\n                        true,\n                        false\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"symbol-placement\": \"line\",\n                \"icon-image\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"oneway-small\",\n                    18,\n                    \"oneway-large\"\n                ],\n                \"symbol-spacing\": 200,\n                \"icon-rotation-alignment\": \"map\",\n                \"icon-allow-overlap\": true,\n                \"icon-ignore-placement\": true\n            },\n            \"paint\": {},\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, tunnels\",\n                \"microg:gms-type-feature\": \"road\",\n                \"microg:gms-type-element\": \"labels.icon\"\n            }\n        },\n        {\n            \"id\": \"tunnel-oneway-arrow-white\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 16,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"tunnel\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"motorway\",\n                        \"motorway_link\",\n                        \"trunk\",\n                        \"trunk_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"oneway\"\n                    ],\n                    \"true\"\n                ]\n            ],\n            \"layout\": {\n                \"symbol-placement\": \"line\",\n                \"icon-image\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"oneway-white-small\",\n                    18,\n                    \"oneway-white-large\"\n                ],\n                \"symbol-spacing\": 200,\n                \"icon-rotation-alignment\": \"map\",\n                \"icon-allow-overlap\": true,\n                \"icon-ignore-placement\": true\n            },\n            \"paint\": {},\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, tunnels\",\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"labels.icon\"\n            }\n        },\n        {\n            \"id\": \"cliff\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"structure\",\n            \"minzoom\": 15,\n            \"filter\": [\n                \"==\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                \"cliff\"\n            ],\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    0,\n                    15.25,\n                    1\n                ],\n                \"line-width\": 10,\n                \"line-pattern\": \"cliff\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"terrain\",\n                \"mapbox:group\": \"Terrain, surface\",\n                \"microg:gms-type-feature\": \"landscape.natural.terrain\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"ferry\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 8,\n            \"filter\": [\n                \"==\",\n                [\n                    \"get\",\n                    \"type\"\n                ],\n                \"ferry\"\n            ],\n            \"paint\": {\n                \"line-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    \"hsl(214, 68%, 63%)\",\n                    17,\n                    \"hsl(239, 68%, 63%)\"\n                ],\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.5,\n                    20,\n                    1\n                ],\n                \"line-dasharray\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0\n                        ]\n                    ],\n                    13,\n                    [\n                        \"literal\",\n                        [\n                            12,\n                            4\n                        ]\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"transit\",\n                \"mapbox:group\": \"Transit, ferries\",\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"ferry-auto\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 8,\n            \"filter\": [\n                \"==\",\n                [\n                    \"get\",\n                    \"type\"\n                ],\n                \"ferry_auto\"\n            ],\n            \"paint\": {\n                \"line-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    \"hsl(214, 68%, 63%)\",\n                    17,\n                    \"hsl(239, 68%, 63%)\"\n                ],\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.5,\n                    20,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"transit\",\n                \"mapbox:group\": \"Transit, ferries\",\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"road-pedestrian-polygon-fill\",\n            \"type\": \"fill\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"path\",\n                        \"pedestrian\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"case\",\n                    [\n                        \"has\",\n                        \"layer\"\n                    ],\n                    [\n                        \">=\",\n                        [\n                            \"get\",\n                            \"layer\"\n                        ],\n                        0\n                    ],\n                    true\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"Polygon\"\n                ]\n            ],\n            \"paint\": {\n                \"fill-color\": \"hsl(60, 20%, 85%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"road-pedestrian-polygon-pattern\",\n            \"type\": \"fill\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 16,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"path\",\n                        \"pedestrian\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"case\",\n                    [\n                        \"has\",\n                        \"layer\"\n                    ],\n                    [\n                        \">=\",\n                        [\n                            \"get\",\n                            \"layer\"\n                        ],\n                        0\n                    ],\n                    true\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"Polygon\"\n                ]\n            ],\n            \"paint\": {\n                \"fill-pattern\": \"pedestrian-polygon\",\n                \"fill-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    16,\n                    0,\n                    17,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"road-path-bg\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 12,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"path\"\n                ],\n                [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"!\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"type\"\n                            ],\n                            [\n                                \"steps\",\n                                \"sidewalk\",\n                                \"crossing\"\n                            ],\n                            true,\n                            false\n                        ]\n                    ],\n                    16,\n                    [\n                        \"!=\",\n                        [\n                            \"get\",\n                            \"type\"\n                        ],\n                        \"steps\"\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    2,\n                    18,\n                    7\n                ],\n                \"line-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    \"piste\",\n                    \"hsl(215, 80%, 48%)\",\n                    [\n                        \"mountain_bike\",\n                        \"hiking\",\n                        \"trail\",\n                        \"cycleway\",\n                        \"footway\",\n                        \"path\",\n                        \"bridleway\"\n                    ],\n                    \"hsl(35, 80%, 48%)\",\n                    \"hsl(60, 1%, 64%)\"\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"road-steps-bg\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    \"steps\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    2,\n                    17,\n                    4.6,\n                    18,\n                    7\n                ],\n                \"line-color\": \"hsl(35, 80%, 48%)\",\n                \"line-opacity\": 0.75\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"road-pedestrian-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"pedestrian\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"case\",\n                    [\n                        \"has\",\n                        \"layer\"\n                    ],\n                    [\n                        \">=\",\n                        [\n                            \"get\",\n                            \"layer\"\n                        ],\n                        0\n                    ],\n                    true\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    2,\n                    18,\n                    14.5\n                ],\n                \"line-color\": \"hsl(60, 10%, 70%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"road-path-trail\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 12,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"path\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    [\n                        \"hiking\",\n                        \"mountain_bike\",\n                        \"trail\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    1,\n                    18,\n                    4\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\",\n                \"line-dasharray\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            5,\n                            0.5\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            4,\n                            0.5\n                        ]\n                    ],\n                    16,\n                    [\n                        \"literal\",\n                        [\n                            4,\n                            0.45\n                        ]\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"road-path-cycleway-piste\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 12,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"path\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    [\n                        \"cycleway\",\n                        \"piste\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    1,\n                    18,\n                    4\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\",\n                \"line-dasharray\": [\n                    10,\n                    0\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"road-path\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 12,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"path\"\n                ],\n                [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"!\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"type\"\n                            ],\n                            [\n                                \"steps\",\n                                \"sidewalk\",\n                                \"crossing\"\n                            ],\n                            true,\n                            false\n                        ]\n                    ],\n                    16,\n                    [\n                        \"!=\",\n                        [\n                            \"get\",\n                            \"type\"\n                        ],\n                        \"steps\"\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    13,\n                    0.5,\n                    14,\n                    1,\n                    15,\n                    1,\n                    18,\n                    4\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\",\n                \"line-dasharray\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            4,\n                            0.3\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            1.75,\n                            0.3\n                        ]\n                    ],\n                    16,\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0.3\n                        ]\n                    ],\n                    17,\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0.25\n                        ]\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"road-steps\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    \"steps\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    1,\n                    16,\n                    1.6,\n                    18,\n                    6\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\",\n                \"line-dasharray\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            1.75,\n                            1\n                        ]\n                    ],\n                    16,\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0.75\n                        ]\n                    ],\n                    17,\n                    [\n                        \"literal\",\n                        [\n                            0.3,\n                            0.3\n                        ]\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"road-pedestrian\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 12,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"pedestrian\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"case\",\n                    [\n                        \"has\",\n                        \"layer\"\n                    ],\n                    [\n                        \">=\",\n                        [\n                            \"get\",\n                            \"layer\"\n                        ],\n                        0\n                    ],\n                    true\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.5,\n                    18,\n                    12\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\",\n                \"line-dasharray\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            1.5,\n                            0.4\n                        ]\n                    ],\n                    16,\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0.2\n                        ]\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"golf-hole-line\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 16,\n            \"filter\": [\n                \"==\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                \"golf\"\n            ],\n            \"paint\": {\n                \"line-color\": \"hsl(98, 26%, 56%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., surface\",\n                \"microg:gms-type-feature\": \"poi.attraction\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"road-polygon\",\n            \"type\": \"fill\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 12,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary\",\n                        \"secondary\",\n                        \"tertiary\",\n                        \"primary_link\",\n                        \"secondary_link\",\n                        \"tertiary_link\",\n                        \"trunk\",\n                        \"trunk_link\",\n                        \"street\",\n                        \"street_limited\",\n                        \"track\",\n                        \"service\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"Polygon\"\n                ]\n            ],\n            \"paint\": {\n                \"fill-color\": \"hsl(0, 0%, 95%)\",\n                \"fill-outline-color\": \"hsl(60, 10%, 70%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface\",\n                \"microg:gms-type-feature\": \"road\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"turning-feature-outline\",\n            \"type\": \"circle\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 15,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"turning_circle\",\n                        \"turning_loop\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"Point\"\n                ]\n            ],\n            \"paint\": {\n                \"circle-radius\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    4.5,\n                    16,\n                    8,\n                    18,\n                    20,\n                    22,\n                    200\n                ],\n                \"circle-color\": \"hsl(0, 0%, 95%)\",\n                \"circle-stroke-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    0.8,\n                    16,\n                    1.2,\n                    18,\n                    2\n                ],\n                \"circle-stroke-color\": \"hsl(60, 10%, 70%)\",\n                \"circle-pitch-alignment\": \"map\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface\",\n                \"microg:gms-type-feature\": \"road\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"road-minor-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"track\"\n                    ],\n                    true,\n                    \"service\",\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        false,\n                        14,\n                        true\n                    ],\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.8,\n                    22,\n                    2\n                ],\n                \"line-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"track\",\n                    \"hsl(35, 80%, 48%)\",\n                    \"hsl(60, 10%, 70%)\"\n                ],\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    18,\n                    10,\n                    22,\n                    100\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"road-street-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"street\",\n                        \"street_limited\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.8,\n                    22,\n                    2\n                ],\n                \"line-color\": \"hsl(60, 10%, 70%)\",\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.5,\n                    18,\n                    20,\n                    22,\n                    200\n                ],\n                \"line-opacity\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    14,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"road-minor-link-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary_link\",\n                        \"secondary_link\",\n                        \"tertiary_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.8,\n                    22,\n                    2\n                ],\n                \"line-color\": \"hsl(60, 10%, 70%)\",\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.4,\n                    18,\n                    18,\n                    22,\n                    180\n                ],\n                \"line-opacity\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    11,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"road-secondary-tertiary-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 11,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"secondary\",\n                        \"tertiary\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.8,\n                    22,\n                    2\n                ],\n                \"line-color\": \"hsl(60, 10%, 70%)\",\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0,\n                    18,\n                    26,\n                    22,\n                    260\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"road-primary-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 10,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"primary\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    22,\n                    2\n                ],\n                \"line-color\": \"hsl(60, 10%, 70%)\",\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0.8,\n                    18,\n                    28,\n                    22,\n                    280\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"road-major-link-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 12,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"motorway_link\",\n                        \"trunk_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.8,\n                    22,\n                    2\n                ],\n                \"line-color\": \"hsl(60, 10%, 82%)\",\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.8,\n                    18,\n                    20,\n                    22,\n                    200\n                ],\n                \"line-opacity\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    11,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"road-motorway-trunk-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 3,\n            \"filter\": [\n                \"all\",\n                [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"motorway\",\n                            \"trunk\"\n                        ],\n                        true,\n                        false\n                    ],\n                    5,\n                    [\n                        \"all\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ],\n                            [\n                                \"motorway\",\n                                \"trunk\"\n                            ],\n                            true,\n                            false\n                        ],\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"structure\"\n                            ],\n                            [\n                                \"none\",\n                                \"ford\"\n                            ],\n                            true,\n                            false\n                        ]\n                    ]\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    22,\n                    2\n                ],\n                \"line-color\": \"hsl(60, 10%, 82%)\",\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0.8,\n                    18,\n                    30,\n                    22,\n                    300\n                ],\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0,\n                    3.5,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface\",\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"turning-feature\",\n            \"type\": \"circle\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 15,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"turning_circle\",\n                        \"turning_loop\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"Point\"\n                ]\n            ],\n            \"paint\": {\n                \"circle-radius\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    4.5,\n                    16,\n                    8,\n                    18,\n                    20,\n                    22,\n                    200\n                ],\n                \"circle-color\": \"hsl(0, 0%, 95%)\",\n                \"circle-pitch-alignment\": \"map\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface\",\n                \"microg:gms-type-feature\": \"road\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"road-construction\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"construction\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    2,\n                    18,\n                    20,\n                    22,\n                    200\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\",\n                \"line-dasharray\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            0.4,\n                            0.8\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            0.3,\n                            0.6\n                        ]\n                    ],\n                    16,\n                    [\n                        \"literal\",\n                        [\n                            0.2,\n                            0.3\n                        ]\n                    ],\n                    17,\n                    [\n                        \"literal\",\n                        [\n                            0.2,\n                            0.25\n                        ]\n                    ],\n                    18,\n                    [\n                        \"literal\",\n                        [\n                            0.15,\n                            0.15\n                        ]\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"road-minor\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"track\"\n                    ],\n                    true,\n                    \"service\",\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        false,\n                        14,\n                        true\n                    ],\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    18,\n                    10,\n                    22,\n                    100\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"road-minor-link\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 12,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary_link\",\n                        \"secondary_link\",\n                        \"tertiary_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    13,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    13,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.4,\n                    18,\n                    18,\n                    22,\n                    180\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"road-major-link\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 12,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"motorway_link\",\n                        \"trunk_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    13,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    13,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.8,\n                    18,\n                    20,\n                    22,\n                    200\n                ],\n                \"line-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"motorway_link\",\n                    \"hsl(15, 100%, 75%)\",\n                    \"hsl(35, 89%, 75%)\"\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"road-street\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"street\",\n                        \"street_limited\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.5,\n                    18,\n                    20,\n                    22,\n                    200\n                ],\n                \"line-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"street_limited\",\n                    \"hsl(60, 22%, 80%)\",\n                    \"hsl(0, 0%, 95%)\"\n                ],\n                \"line-opacity\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    14,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"road-street-low\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 11,\n            \"maxzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"street\",\n                        \"street_limited\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.5,\n                    18,\n                    20,\n                    22,\n                    200\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"road-secondary-tertiary\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 9,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"secondary\",\n                        \"tertiary\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0,\n                    18,\n                    26,\n                    22,\n                    260\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"road-primary\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 6,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"primary\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0.8,\n                    18,\n                    28,\n                    22,\n                    280\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"road-motorway-trunk\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 3,\n            \"filter\": [\n                \"all\",\n                [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"motorway\",\n                            \"trunk\"\n                        ],\n                        true,\n                        false\n                    ],\n                    5,\n                    [\n                        \"all\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ],\n                            [\n                                \"motorway\",\n                                \"trunk\"\n                            ],\n                            true,\n                            false\n                        ],\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"structure\"\n                            ],\n                            [\n                                \"none\",\n                                \"ford\"\n                            ],\n                            true,\n                            false\n                        ]\n                    ]\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    13,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    13,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0.8,\n                    18,\n                    30,\n                    22,\n                    300\n                ],\n                \"line-color\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        \"motorway\",\n                        \"hsl(15, 88%, 69%)\",\n                        \"trunk\",\n                        \"hsl(35, 81%, 59%)\",\n                        \"hsl(60, 18%, 85%)\"\n                    ],\n                    9,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        \"motorway\",\n                        \"hsl(15, 100%, 75%)\",\n                        \"hsl(35, 89%, 75%)\"\n                    ]\n                ],\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0,\n                    3.5,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface\",\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"road-rail\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"major_rail\",\n                        \"minor_rail\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"paint\": {\n                \"line-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    13,\n                    \"hsl(75, 25%, 68%)\",\n                    16,\n                    \"hsl(60, 0%, 56%)\"\n                ],\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.5,\n                    20,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"transit\",\n                \"mapbox:group\": \"Transit, surface\",\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"road-rail-tracks\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"major_rail\",\n                        \"minor_rail\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"paint\": {\n                \"line-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    13,\n                    \"hsl(75, 25%, 68%)\",\n                    16,\n                    \"hsl(60, 0%, 56%)\"\n                ],\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    4,\n                    20,\n                    8\n                ],\n                \"line-dasharray\": [\n                    0.1,\n                    15\n                ],\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    13.75,\n                    0,\n                    14,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"transit\",\n                \"mapbox:group\": \"Transit, surface\",\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"level-crossing\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 16,\n            \"filter\": [\n                \"==\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                \"level_crossing\"\n            ],\n            \"layout\": {\n                \"icon-image\": \"level-crossing\",\n                \"icon-rotation-alignment\": \"map\",\n                \"icon-allow-overlap\": true,\n                \"icon-ignore-placement\": true\n            },\n            \"paint\": {},\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface-icons\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"labels.icon\"\n            }\n        },\n        {\n            \"id\": \"road-oneway-arrow-blue\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 16,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"oneway\"\n                    ],\n                    \"true\"\n                ],\n                [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"primary\",\n                            \"secondary\",\n                            \"tertiary\",\n                            \"street\",\n                            \"street_limited\"\n                        ],\n                        true,\n                        false\n                    ],\n                    16,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"primary\",\n                            \"secondary\",\n                            \"tertiary\",\n                            \"street\",\n                            \"street_limited\",\n                            \"primary_link\",\n                            \"secondary_link\",\n                            \"tertiary_link\",\n                            \"service\",\n                            \"track\"\n                        ],\n                        true,\n                        false\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"symbol-placement\": \"line\",\n                \"icon-image\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"oneway-small\",\n                    18,\n                    \"oneway-large\"\n                ],\n                \"symbol-spacing\": 200,\n                \"icon-rotation-alignment\": \"map\",\n                \"icon-allow-overlap\": true,\n                \"icon-ignore-placement\": true\n            },\n            \"paint\": {},\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface-icons\",\n                \"microg:gms-type-feature\": \"road\",\n                \"microg:gms-type-element\": \"labels.icon\"\n            }\n        },\n        {\n            \"id\": \"road-oneway-arrow-white\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 16,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"oneway\"\n                    ],\n                    \"true\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"motorway\",\n                        \"trunk\",\n                        \"motorway_link\",\n                        \"trunk_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"none\",\n                        \"ford\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"symbol-placement\": \"line\",\n                \"icon-image\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"oneway-white-small\",\n                    18,\n                    \"oneway-white-large\"\n                ],\n                \"symbol-spacing\": 200,\n                \"icon-rotation-alignment\": \"map\",\n                \"icon-allow-overlap\": true,\n                \"icon-ignore-placement\": true\n            },\n            \"paint\": {},\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface-icons\",\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"labels.icon\"\n            }\n        },\n        {\n            \"id\": \"crosswalks\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"structure\",\n            \"minzoom\": 17,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    \"crosswalk\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"Point\"\n                ]\n            ],\n            \"layout\": {\n                \"icon-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    16,\n                    0.1,\n                    18,\n                    0.2,\n                    19,\n                    0.5,\n                    22,\n                    1.5\n                ],\n                \"icon-image\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"crosswalk-small\",\n                    18,\n                    \"crosswalk-large\"\n                ],\n                \"icon-rotate\": [\n                    \"get\",\n                    \"direction\"\n                ],\n                \"icon-rotation-alignment\": \"map\",\n                \"icon-allow-overlap\": true,\n                \"icon-ignore-placement\": true\n            },\n            \"paint\": {},\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, surface-icons\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"labels.icon\"\n            }\n        },\n        {\n            \"id\": \"gate-fence-hedge\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"structure\",\n            \"minzoom\": 16,\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"gate\",\n                    \"fence\",\n                    \"hedge\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"hedge\",\n                    \"hsl(98, 32%, 56%)\",\n                    \"hsl(60, 25%, 63%)\"\n                ],\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    16,\n                    1,\n                    20,\n                    3\n                ],\n                \"line-opacity\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"gate\",\n                    0.5,\n                    1\n                ],\n                \"line-dasharray\": [\n                    1,\n                    2,\n                    5,\n                    2,\n                    1,\n                    2\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., barriers-bridges\",\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"bridge-path-bg\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"path\"\n                ],\n                [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"!\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"type\"\n                            ],\n                            [\n                                \"steps\",\n                                \"sidewalk\",\n                                \"crossing\"\n                            ],\n                            true,\n                            false\n                        ]\n                    ],\n                    16,\n                    [\n                        \"!=\",\n                        [\n                            \"get\",\n                            \"type\"\n                        ],\n                        \"steps\"\n                    ]\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    2,\n                    18,\n                    7\n                ],\n                \"line-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    \"piste\",\n                    \"hsl(215, 80%, 48%)\",\n                    [\n                        \"mountain_bike\",\n                        \"hiking\",\n                        \"trail\",\n                        \"cycleway\",\n                        \"footway\",\n                        \"path\",\n                        \"bridleway\"\n                    ],\n                    \"hsl(35, 80%, 48%)\",\n                    \"hsl(60, 1%, 64%)\"\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., barriers-bridges\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"bridge-steps-bg\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    \"steps\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    2,\n                    17,\n                    4.6,\n                    18,\n                    7\n                ],\n                \"line-color\": \"hsl(35, 80%, 48%)\",\n                \"line-opacity\": 0.75\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., barriers-bridges\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"bridge-pedestrian-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"pedestrian\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    2,\n                    18,\n                    14.5\n                ],\n                \"line-color\": \"hsl(60, 10%, 70%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., barriers-bridges\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"bridge-path-trail\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"path\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    [\n                        \"hiking\",\n                        \"mountain_bike\",\n                        \"trail\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    1,\n                    18,\n                    4\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\",\n                \"line-dasharray\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            5,\n                            0.5\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            4,\n                            0.5\n                        ]\n                    ],\n                    16,\n                    [\n                        \"literal\",\n                        [\n                            4,\n                            0.45\n                        ]\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., barriers-bridges\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"bridge-path-cycleway-piste\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"path\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    [\n                        \"cycleway\",\n                        \"piste\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    1,\n                    18,\n                    4\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\",\n                \"line-dasharray\": [\n                    10,\n                    0\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., barriers-bridges\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"bridge-path\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"path\"\n                ],\n                [\n                    \"!=\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    \"steps\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    1,\n                    18,\n                    4\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\",\n                \"line-dasharray\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            4,\n                            0.3\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            1.75,\n                            0.3\n                        ]\n                    ],\n                    16,\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0.3\n                        ]\n                    ],\n                    17,\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0.25\n                        ]\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., barriers-bridges\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"bridge-steps\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    \"steps\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    1,\n                    16,\n                    1.6,\n                    18,\n                    6\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\",\n                \"line-dasharray\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            1.75,\n                            1\n                        ]\n                    ],\n                    16,\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0.75\n                        ]\n                    ],\n                    17,\n                    [\n                        \"literal\",\n                        [\n                            0.3,\n                            0.3\n                        ]\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., barriers-bridges\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"bridge-pedestrian\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"pedestrian\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.5,\n                    18,\n                    12\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\",\n                \"line-dasharray\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            1.5,\n                            0.4\n                        ]\n                    ],\n                    16,\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0.2\n                        ]\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., barriers-bridges\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"gate-label\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"structure\",\n            \"minzoom\": 16,\n            \"filter\": [\n                \"==\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                \"gate\"\n            ],\n            \"layout\": {\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    \"gate\",\n                    \"gate\",\n                    \"lift_gate\",\n                    \"lift-gate\",\n                    \"\"\n                ]\n            },\n            \"paint\": {},\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., barriers-bridges\",\n                \"microg:gms-type-feature\": \"road\",\n                \"microg:gms-type-element\": \"labels.icon\"\n            }\n        },\n        {\n            \"id\": \"bridge-minor-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"track\"\n                    ],\n                    true,\n                    \"service\",\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        false,\n                        14,\n                        true\n                    ],\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.8,\n                    22,\n                    2\n                ],\n                \"line-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"track\",\n                    \"hsl(35, 80%, 48%)\",\n                    \"hsl(60, 10%, 70%)\"\n                ],\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    18,\n                    10,\n                    22,\n                    100\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"bridge-street-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"street\",\n                        \"street_limited\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.8,\n                    22,\n                    2\n                ],\n                \"line-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"track\",\n                    \"hsl(35, 80%, 48%)\",\n                    \"hsl(60, 10%, 70%)\"\n                ],\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.5,\n                    18,\n                    20,\n                    22,\n                    200\n                ],\n                \"line-opacity\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    14,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"bridge-minor-link-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary_link\",\n                        \"secondary_link\",\n                        \"tertiary_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.8,\n                    22,\n                    2\n                ],\n                \"line-color\": \"hsl(60, 10%, 70%)\",\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.4,\n                    18,\n                    18,\n                    22,\n                    180\n                ],\n                \"line-opacity\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    11,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"bridge-secondary-tertiary-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 11,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"secondary\",\n                        \"tertiary\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    22,\n                    2\n                ],\n                \"line-color\": \"hsl(60, 10%, 70%)\",\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0,\n                    18,\n                    26,\n                    22,\n                    260\n                ],\n                \"line-opacity\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    10,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"bridge-primary-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 10,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"primary\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    22,\n                    2\n                ],\n                \"line-color\": \"hsl(60, 10%, 70%)\",\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0.8,\n                    18,\n                    28,\n                    22,\n                    280\n                ],\n                \"line-opacity\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    10,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"bridge-major-link-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 12,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"motorway_link\",\n                        \"trunk_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"layer\"\n                    ],\n                    1\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.8,\n                    22,\n                    2\n                ],\n                \"line-color\": \"hsl(60, 10%, 82%)\",\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.8,\n                    18,\n                    20,\n                    22,\n                    200\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"bridge-motorway-trunk-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"motorway\",\n                        \"trunk\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"layer\"\n                    ],\n                    1\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    22,\n                    2\n                ],\n                \"line-color\": \"hsl(60, 10%, 82%)\",\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0.8,\n                    18,\n                    30,\n                    22,\n                    300\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"bridge-construction\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"construction\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    2,\n                    18,\n                    20,\n                    22,\n                    200\n                ],\n                \"line-color\": \"hsl(60, 10%, 70%)\",\n                \"line-dasharray\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            0.4,\n                            0.8\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            0.3,\n                            0.6\n                        ]\n                    ],\n                    16,\n                    [\n                        \"literal\",\n                        [\n                            0.2,\n                            0.3\n                        ]\n                    ],\n                    17,\n                    [\n                        \"literal\",\n                        [\n                            0.2,\n                            0.25\n                        ]\n                    ],\n                    18,\n                    [\n                        \"literal\",\n                        [\n                            0.15,\n                            0.15\n                        ]\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"bridge-minor\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"track\"\n                    ],\n                    true,\n                    \"service\",\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        false,\n                        14,\n                        true\n                    ],\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    18,\n                    10,\n                    22,\n                    100\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"bridge-minor-link\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary_link\",\n                        \"secondary_link\",\n                        \"tertiary_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.4,\n                    18,\n                    18,\n                    22,\n                    180\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"bridge-major-link\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 12,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"motorway_link\",\n                        \"trunk_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"layer\"\n                    ],\n                    1\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    13,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.8,\n                    18,\n                    20,\n                    22,\n                    200\n                ],\n                \"line-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"motorway_link\",\n                    \"hsl(15, 100%, 75%)\",\n                    \"hsl(35, 89%, 75%)\"\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"bridge-street\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"street\",\n                        \"street_limited\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.5,\n                    18,\n                    20,\n                    22,\n                    200\n                ],\n                \"line-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"street_limited\",\n                    \"hsl(60, 22%, 80%)\",\n                    \"hsl(0, 0%, 95%)\"\n                ],\n                \"line-opacity\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    14,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"bridge-street-low\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"maxzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"street\",\n                        \"street_limited\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ],\n                \"line-join\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"miter\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.5,\n                    18,\n                    20,\n                    22,\n                    200\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"bridge-secondary-tertiary\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"secondary\",\n                        \"tertiary\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0,\n                    18,\n                    26,\n                    22,\n                    260\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"bridge-primary\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"primary\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0.8,\n                    18,\n                    28,\n                    22,\n                    280\n                ],\n                \"line-color\": \"hsl(0, 0%, 95%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"bridge-motorway-trunk\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"motorway\",\n                        \"trunk\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"layer\"\n                    ],\n                    1\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0.8,\n                    18,\n                    30,\n                    22,\n                    300\n                ],\n                \"line-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"motorway\",\n                    \"hsl(15, 100%, 75%)\",\n                    \"hsl(35, 89%, 75%)\"\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"bridge-major-link-2-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 12,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \">=\",\n                    [\n                        \"get\",\n                        \"layer\"\n                    ],\n                    2\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"motorway_link\",\n                        \"trunk_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.8,\n                    22,\n                    2\n                ],\n                \"line-color\": \"hsl(60, 10%, 82%)\",\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.8,\n                    18,\n                    20,\n                    22,\n                    200\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"bridge-motorway-trunk-2-case\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \">=\",\n                    [\n                        \"get\",\n                        \"layer\"\n                    ],\n                    2\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"motorway\",\n                        \"trunk\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    22,\n                    2\n                ],\n                \"line-color\": \"hsl(60, 10%, 82%)\",\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0.8,\n                    18,\n                    30,\n                    22,\n                    300\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"bridge-major-link-2\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 12,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \">=\",\n                    [\n                        \"get\",\n                        \"layer\"\n                    ],\n                    2\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"motorway_link\",\n                        \"trunk_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    13,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    0.8,\n                    18,\n                    20,\n                    22,\n                    200\n                ],\n                \"line-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"motorway_link\",\n                    \"hsl(15, 100%, 75%)\",\n                    \"hsl(35, 89%, 75%)\"\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"bridge-motorway-trunk-2\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \">=\",\n                    [\n                        \"get\",\n                        \"layer\"\n                    ],\n                    2\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"motorway\",\n                        \"trunk\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"butt\",\n                    14,\n                    \"round\"\n                ]\n            },\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0.8,\n                    18,\n                    30,\n                    22,\n                    300\n                ],\n                \"line-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"motorway\",\n                    \"hsl(15, 100%, 75%)\",\n                    \"hsl(35, 89%, 75%)\"\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"bridge-oneway-arrow-blue\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 16,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"oneway\"\n                    ],\n                    \"true\"\n                ],\n                [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"primary\",\n                            \"secondary\",\n                            \"tertiary\",\n                            \"street\",\n                            \"street_limited\"\n                        ],\n                        true,\n                        false\n                    ],\n                    16,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"primary\",\n                            \"secondary\",\n                            \"tertiary\",\n                            \"street\",\n                            \"street_limited\",\n                            \"primary_link\",\n                            \"secondary_link\",\n                            \"tertiary_link\",\n                            \"service\",\n                            \"track\"\n                        ],\n                        true,\n                        false\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"symbol-placement\": \"line\",\n                \"icon-image\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"oneway-small\",\n                    18,\n                    \"oneway-large\"\n                ],\n                \"symbol-spacing\": 200,\n                \"icon-rotation-alignment\": \"map\",\n                \"icon-allow-overlap\": true,\n                \"icon-ignore-placement\": true\n            },\n            \"paint\": {},\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road\",\n                \"microg:gms-type-element\": \"labels.icon\"\n            }\n        },\n        {\n            \"id\": \"bridge-oneway-arrow-white\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 16,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"motorway\",\n                        \"trunk\",\n                        \"motorway_link\",\n                        \"trunk_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"oneway\"\n                    ],\n                    \"true\"\n                ]\n            ],\n            \"layout\": {\n                \"symbol-placement\": \"line\",\n                \"icon-image\": \"oneway-white-small\",\n                \"symbol-spacing\": 200,\n                \"icon-rotation-alignment\": \"map\",\n                \"icon-allow-overlap\": true,\n                \"icon-ignore-placement\": true\n            },\n            \"paint\": {},\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, bridges\",\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"labels.icon\"\n            }\n        },\n        {\n            \"id\": \"bridge-rail\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"major_rail\",\n                        \"minor_rail\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"paint\": {\n                \"line-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    13,\n                    \"hsl(75, 25%, 68%)\",\n                    16,\n                    \"hsl(60, 0%, 56%)\"\n                ],\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.5,\n                    20,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"transit\",\n                \"mapbox:group\": \"Transit, bridges\",\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"bridge-rail-tracks\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    \"bridge\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"major_rail\",\n                        \"minor_rail\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"paint\": {\n                \"line-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    13,\n                    \"hsl(75, 25%, 68%)\",\n                    16,\n                    \"hsl(60, 0%, 56%)\"\n                ],\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    4,\n                    20,\n                    8\n                ],\n                \"line-dasharray\": [\n                    0.1,\n                    15\n                ],\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    13.75,\n                    0,\n                    14,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"transit\",\n                \"mapbox:group\": \"Transit, bridges\",\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"aerialway\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 12,\n            \"filter\": [\n                \"==\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                \"aerialway\"\n            ],\n            \"paint\": {\n                \"line-color\": \"hsl(230, 50%, 60%)\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    20,\n                    2\n                ],\n                \"line-dasharray\": [\n                    4,\n                    1\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"transit\",\n                \"mapbox:group\": \"Transit, elevated\",\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"admin-1-boundary-bg\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"admin\",\n            \"minzoom\": 7,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"admin_level\"\n                    ],\n                    1\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"maritime\"\n                    ],\n                    \"false\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"worldview\"\n                    ],\n                    [\n                        \"all\",\n                        \"US\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"paint\": {\n                \"line-color\": \"hsl(350, 90%, 88%)\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    3,\n                    12,\n                    6\n                ],\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    7,\n                    0,\n                    8,\n                    0.5\n                ],\n                \"line-dasharray\": [\n                    1,\n                    0\n                ],\n                \"line-blur\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0,\n                    12,\n                    3\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"admin-boundaries\",\n                \"mapbox:group\": \"Administrative boundaries, admin\",\n                \"microg:gms-type-feature\": \"administrative.province\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"admin-0-boundary-bg\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"admin\",\n            \"minzoom\": 1,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"admin_level\"\n                    ],\n                    0\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"maritime\"\n                    ],\n                    \"false\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"worldview\"\n                    ],\n                    [\n                        \"all\",\n                        \"US\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    4,\n                    12,\n                    8\n                ],\n                \"line-color\": \"hsl(350, 90%, 88%)\",\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0,\n                    4,\n                    0.5\n                ],\n                \"line-blur\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0,\n                    12,\n                    2\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"admin-boundaries\",\n                \"mapbox:group\": \"Administrative boundaries, admin\",\n                \"microg:gms-type-feature\": \"administrative.country\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"admin-1-boundary\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"admin\",\n            \"minzoom\": 2,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"admin_level\"\n                    ],\n                    1\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"maritime\"\n                    ],\n                    \"false\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"worldview\"\n                    ],\n                    [\n                        \"all\",\n                        \"US\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-dasharray\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            2,\n                            0\n                        ]\n                    ],\n                    7,\n                    [\n                        \"literal\",\n                        [\n                            2,\n                            2,\n                            6,\n                            2\n                        ]\n                    ]\n                ],\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0.3,\n                    12,\n                    1.5\n                ],\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    2,\n                    0,\n                    3,\n                    1\n                ],\n                \"line-color\": \"hsl(350, 30%, 55%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"admin-boundaries\",\n                \"mapbox:group\": \"Administrative boundaries, admin\",\n                \"microg:gms-type-feature\": \"administrative.province\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"admin-0-boundary\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"admin\",\n            \"minzoom\": 1,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"admin_level\"\n                    ],\n                    0\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"disputed\"\n                    ],\n                    \"false\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"maritime\"\n                    ],\n                    \"false\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"worldview\"\n                    ],\n                    [\n                        \"all\",\n                        \"US\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsl(350, 30%, 50%)\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0.5,\n                    12,\n                    2\n                ],\n                \"line-dasharray\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            2,\n                            0\n                        ]\n                    ],\n                    7,\n                    [\n                        \"literal\",\n                        [\n                            2,\n                            2,\n                            6,\n                            2\n                        ]\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"admin-boundaries\",\n                \"mapbox:group\": \"Administrative boundaries, admin\",\n                \"microg:gms-type-feature\": \"administrative.country\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"admin-0-boundary-disputed\",\n            \"type\": \"line\",\n            \"source\": \"composite\",\n            \"source-layer\": \"admin\",\n            \"minzoom\": 1,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"disputed\"\n                    ],\n                    \"true\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"admin_level\"\n                    ],\n                    0\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"maritime\"\n                    ],\n                    \"false\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"worldview\"\n                    ],\n                    [\n                        \"all\",\n                        \"US\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"paint\": {\n                \"line-color\": \"hsl(350, 30%, 50%)\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    0.5,\n                    12,\n                    2\n                ],\n                \"line-dasharray\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            3,\n                            2,\n                            5\n                        ]\n                    ],\n                    7,\n                    [\n                        \"literal\",\n                        [\n                            2,\n                            1.5\n                        ]\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"admin-boundaries\",\n                \"mapbox:group\": \"Administrative boundaries, admin\",\n                \"microg:gms-type-feature\": \"administrative.country\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"contour-label\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"contour\",\n            \"minzoom\": 11,\n            \"filter\": [\n                \"any\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"index\"\n                    ],\n                    10\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"index\"\n                    ],\n                    5\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"ele\"\n                    ],\n                    \" m\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-pitch-alignment\": \"viewport\",\n                \"text-max-angle\": 25,\n                \"text-padding\": 5,\n                \"text-font\": [\n                    \"DIN Pro Medium\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    9.5,\n                    20,\n                    12\n                ]\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(60, 10%, 35%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-color\": \"hsl(60, 10%, 85%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"terrain\",\n                \"mapbox:group\": \"Terrain, terrain-labels\",\n                \"microg:gms-type-feature\": \"landscape.natural.terrain\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"id\": \"building-entrance\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"structure\",\n            \"minzoom\": 18,\n            \"filter\": [\n                \"==\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                \"entrance\"\n            ],\n            \"layout\": {\n                \"icon-image\": \"marker\",\n                \"text-field\": [\n                    \"get\",\n                    \"ref\"\n                ],\n                \"text-size\": 10,\n                \"text-offset\": [\n                    0,\n                    -0.5\n                ],\n                \"text-font\": [\n                    \"DIN Pro Italic\",\n                    \"Arial Unicode MS Regular\"\n                ]\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(60, 8%, 38%)\",\n                \"text-halo-color\": \"hsl(60, 13%, 77%)\",\n                \"text-halo-width\": 1,\n                \"icon-opacity\": 0.4\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"buildings\",\n                \"mapbox:group\": \"Buildings, building-labels\",\n                \"microg:gms-type-feature\": \"poi\",\n                \"microg:gms-type-element\": \"labels.icon\"\n            }\n        },\n        {\n            \"id\": \"building-number-label\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"housenum_label\",\n            \"minzoom\": 17,\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"house_num\"\n                ],\n                \"text-font\": [\n                    \"DIN Pro Italic\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-padding\": 4,\n                \"text-max-width\": 7,\n                \"text-size\": 10\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(60, 8%, 38%)\",\n                \"text-halo-color\": \"hsl(60, 13%, 77%)\",\n                \"text-halo-width\": 1\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"buildings\",\n                \"mapbox:group\": \"Buildings, building-labels\",\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"id\": \"block-number-label\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"place_label\",\n            \"minzoom\": 16,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"settlement_subdivision\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    \"block\"\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"name\"\n                ],\n                \"text-font\": [\n                    \"DIN Pro Italic\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-max-width\": 7,\n                \"text-size\": 11\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(60, 18%, 44%)\",\n                \"text-halo-color\": \"hsl(60, 17%, 84%)\",\n                \"text-halo-width\": 0.5,\n                \"text-halo-blur\": 0.5\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"buildings\",\n                \"mapbox:group\": \"Buildings, building-labels\",\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"id\": \"road-label\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 10,\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"motorway\",\n                            \"trunk\",\n                            \"primary\",\n                            \"secondary\",\n                            \"tertiary\"\n                        ],\n                        true,\n                        false\n                    ],\n                    12,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"motorway\",\n                            \"trunk\",\n                            \"primary\",\n                            \"secondary\",\n                            \"tertiary\",\n                            \"street\",\n                            \"street_limited\",\n                            \"track\"\n                        ],\n                        true,\n                        false\n                    ],\n                    15,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"path\",\n                            \"pedestrian\",\n                            \"golf\",\n                            \"ferry\",\n                            \"aerialway\"\n                        ],\n                        false,\n                        true\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    10,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"motorway\",\n                            \"trunk\",\n                            \"primary\",\n                            \"secondary\",\n                            \"tertiary\"\n                        ],\n                        10,\n                        [\n                            \"motorway_link\",\n                            \"trunk_link\",\n                            \"primary_link\",\n                            \"secondary_link\",\n                            \"tertiary_link\",\n                            \"street\",\n                            \"street_limited\",\n                            \"track\"\n                        ],\n                        9,\n                        6.5\n                    ],\n                    18,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"motorway\",\n                            \"trunk\",\n                            \"primary\",\n                            \"secondary\",\n                            \"tertiary\"\n                        ],\n                        16,\n                        [\n                            \"motorway_link\",\n                            \"trunk_link\",\n                            \"primary_link\",\n                            \"secondary_link\",\n                            \"tertiary_link\",\n                            \"street\",\n                            \"street_limited\",\n                            \"track\"\n                        ],\n                        14,\n                        13\n                    ]\n                ],\n                \"text-max-angle\": 30,\n                \"text-font\": [\n                    \"DIN Pro Regular\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-padding\": 1,\n                \"text-rotation-alignment\": \"map\",\n                \"text-pitch-alignment\": \"viewport\",\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-letter-spacing\": 0.01\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(0,0%, 0%)\",\n                \"text-halo-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"motorway\",\n                        \"trunk\"\n                    ],\n                    \"hsla(60, 25%, 100%, 0.75)\",\n                    \"hsl(60, 25%, 100%)\"\n                ],\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, road-labels\",\n                \"microg:gms-type-feature\": \"road\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"id\": \"road-intersection\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 15,\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"intersection\"\n                ],\n                [\n                    \"has\",\n                    \"name\"\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"icon-image\": \"intersection\",\n                \"icon-text-fit\": \"both\",\n                \"icon-text-fit-padding\": [\n                    1,\n                    2,\n                    1,\n                    2\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.2\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    9,\n                    18,\n                    12\n                ],\n                \"text-font\": [\n                    \"DIN Pro Bold\",\n                    \"Arial Unicode MS Bold\"\n                ]\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(230, 36%, 64%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, road-labels\",\n                \"microg:gms-type-feature\": \"road\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"id\": \"road-number-shield\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 6,\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"reflen\"\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"reflen\"\n                    ],\n                    6\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"pedestrian\",\n                        \"service\"\n                    ],\n                    false,\n                    true\n                ],\n                [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"==\",\n                        [\n                            \"geometry-type\"\n                        ],\n                        \"Point\"\n                    ],\n                    11,\n                    [\n                        \">\",\n                        [\n                            \"get\",\n                            \"len\"\n                        ],\n                        5000\n                    ],\n                    12,\n                    [\n                        \">\",\n                        [\n                            \"get\",\n                            \"len\"\n                        ],\n                        2500\n                    ],\n                    13,\n                    [\n                        \">\",\n                        [\n                            \"get\",\n                            \"len\"\n                        ],\n                        1000\n                    ],\n                    14,\n                    true\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": 9,\n                \"icon-image\": [\n                    \"case\",\n                    [\n                        \"has\",\n                        \"shield_beta\"\n                    ],\n                    [\n                        \"coalesce\",\n                        [\n                            \"image\",\n                            [\n                                \"concat\",\n                                [\n                                    \"get\",\n                                    \"shield_beta\"\n                                ],\n                                \"-\",\n                                [\n                                    \"to-string\",\n                                    [\n                                        \"get\",\n                                        \"reflen\"\n                                    ]\n                                ]\n                            ]\n                        ],\n                        [\n                            \"image\",\n                            [\n                                \"concat\",\n                                \"default-\",\n                                [\n                                    \"to-string\",\n                                    [\n                                        \"get\",\n                                        \"reflen\"\n                                    ]\n                                ]\n                            ]\n                        ]\n                    ],\n                    [\n                        \"concat\",\n                        [\n                            \"get\",\n                            \"shield\"\n                        ],\n                        \"-\",\n                        [\n                            \"to-string\",\n                            [\n                                \"get\",\n                                \"reflen\"\n                            ]\n                        ]\n                    ]\n                ],\n                \"icon-rotation-alignment\": \"viewport\",\n                \"text-max-angle\": 38,\n                \"symbol-spacing\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    11,\n                    400,\n                    14,\n                    600\n                ],\n                \"text-font\": [\n                    \"DIN Pro Bold\",\n                    \"Arial Unicode MS Bold\"\n                ],\n                \"symbol-placement\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"point\",\n                    11,\n                    \"line\"\n                ],\n                \"text-rotation-alignment\": \"viewport\",\n                \"text-field\": [\n                    \"get\",\n                    \"ref\"\n                ],\n                \"text-letter-spacing\": 0.05\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"case\",\n                    [\n                        \"all\",\n                        [\n                            \"has\",\n                            \"shield_text_color_beta\"\n                        ],\n                        [\n                            \"to-boolean\",\n                            [\n                                \"coalesce\",\n                                [\n                                    \"image\",\n                                    [\n                                        \"concat\",\n                                        [\n                                            \"get\",\n                                            \"shield_beta\"\n                                        ],\n                                        \"-\",\n                                        [\n                                            \"to-string\",\n                                            [\n                                                \"get\",\n                                                \"reflen\"\n                                            ]\n                                        ]\n                                    ]\n                                ],\n                                \"\"\n                            ]\n                        ]\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"shield_text_color_beta\"\n                        ],\n                        \"white\",\n                        \"hsl(0, 0%, 100%)\",\n                        \"yellow\",\n                        \"hsl(50, 63%, 70%)\",\n                        \"orange\",\n                        \"hsl(25, 63%, 75%)\",\n                        \"blue\",\n                        \"hsl(230, 36%, 44%)\",\n                        \"red\",\n                        \"hsl(0, 54%, 59%)\",\n                        \"green\",\n                        \"hsl(140, 46%, 37%)\",\n                        \"hsl(230, 11%, 13%)\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"shield_text_color\"\n                        ],\n                        \"white\",\n                        \"hsl(0, 0%, 100%)\",\n                        \"yellow\",\n                        \"hsl(50, 63%, 70%)\",\n                        \"orange\",\n                        \"hsl(25, 63%, 75%)\",\n                        \"blue\",\n                        \"hsl(230, 36%, 44%)\",\n                        \"red\",\n                        \"hsl(0, 54%, 59%)\",\n                        \"green\",\n                        \"hsl(140, 46%, 37%)\",\n                        \"hsl(230, 11%, 13%)\"\n                    ]\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, road-labels\",\n                \"microg:gms-type-feature\": \"road\",\n                \"microg:gms-type-element\": \"labels.icon\"\n            }\n        },\n        {\n            \"id\": \"road-exit-shield\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"motorway_junction\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"reflen\"\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"reflen\"\n                    ],\n                    9\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"ref\"\n                ],\n                \"text-size\": 9,\n                \"icon-image\": [\n                    \"concat\",\n                    \"motorway-exit-\",\n                    [\n                        \"to-string\",\n                        [\n                            \"get\",\n                            \"reflen\"\n                        ]\n                    ]\n                ],\n                \"text-font\": [\n                    \"DIN Pro Bold\",\n                    \"Arial Unicode MS Bold\"\n                ]\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(0, 0%, 100%)\",\n                \"text-translate\": [\n                    0,\n                    0\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"road-network\",\n                \"mapbox:group\": \"Road network, road-labels\",\n                \"microg:gms-type-feature\": \"road\",\n                \"microg:gms-type-element\": \"labels.icon\"\n            }\n        },\n        {\n            \"id\": \"path-pedestrian-label\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 12,\n            \"filter\": [\n                \"all\",\n                [\n                    \"case\",\n                    [\n                        \"has\",\n                        \"layer\"\n                    ],\n                    [\n                        \">=\",\n                        [\n                            \"get\",\n                            \"layer\"\n                        ],\n                        0\n                    ],\n                    true\n                ],\n                [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"pedestrian\"\n                        ],\n                        true,\n                        false\n                    ],\n                    15,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"path\",\n                            \"pedestrian\"\n                        ],\n                        true,\n                        false\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    10,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        \"pedestrian\",\n                        9,\n                        6.5\n                    ],\n                    18,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        \"pedestrian\",\n                        14,\n                        13\n                    ]\n                ],\n                \"text-max-angle\": 30,\n                \"text-font\": [\n                    \"DIN Pro Regular\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-padding\": 1,\n                \"text-rotation-alignment\": \"map\",\n                \"text-pitch-alignment\": \"viewport\",\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-letter-spacing\": 0.01\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(0,0%, 0%)\",\n                \"text-halo-color\": \"hsl(60, 25%, 100%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., walking-cycling-labels\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"id\": \"golf-hole-label\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 16,\n            \"filter\": [\n                \"==\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                \"golf\"\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"DIN Pro Medium\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-size\": 12\n            },\n            \"paint\": {\n                \"text-halo-color\": \"hsl(98, 60%, 55%)\",\n                \"text-halo-width\": 0.5,\n                \"text-halo-blur\": 0.5,\n                \"text-color\": \"hsl(100, 80%, 18%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"walking-cycling\",\n                \"mapbox:group\": \"Walking, cycling, etc., walking-cycling-labels\",\n                \"microg:gms-type-feature\": \"poi.attraction\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"id\": \"ferry-aerialway-label\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 15,\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                \"aerialway\",\n                true,\n                \"ferry\",\n                true,\n                false\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    10,\n                    6.5,\n                    18,\n                    13\n                ],\n                \"text-max-angle\": 30,\n                \"text-font\": [\n                    \"DIN Pro Regular\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-padding\": 1,\n                \"text-rotation-alignment\": \"map\",\n                \"text-pitch-alignment\": \"viewport\",\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-letter-spacing\": 0.01\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"ferry\",\n                    \"hsl(205, 43%, 100%)\",\n                    \"hsl(230, 50%, 60%)\"\n                ],\n                \"text-halo-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"ferry\",\n                    \"hsl(205, 75%, 70%)\",\n                    \"hsl(60, 20%, 100%)\"\n                ],\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"transit\",\n                \"mapbox:group\": \"Transit, ferry-aerialway-labels\",\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"id\": \"waterway-label\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"natural_label\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"canal\",\n                        \"river\",\n                        \"stream\",\n                        \"disputed_canal\",\n                        \"disputed_river\",\n                        \"disputed_stream\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"worldview\"\n                        ],\n                        [\n                            \"all\",\n                            \"US\"\n                        ],\n                        true,\n                        false\n                    ],\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"text-font\": [\n                    \"DIN Pro Italic\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-max-angle\": 30,\n                \"symbol-spacing\": [\n                    \"interpolate\",\n                    [\n                        \"linear\",\n                        1\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    250,\n                    17,\n                    400\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    13,\n                    12,\n                    18,\n                    18\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-pitch-alignment\": \"viewport\",\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(205, 43%, 90%)\",\n                \"text-halo-color\": \"hsla(60, 17%, 84%, 0.5)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"natural-features\",\n                \"mapbox:group\": \"Natural features, natural-labels\",\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"id\": \"natural-line-label\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"natural-features\",\n                \"mapbox:group\": \"Natural features, natural-labels\",\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"natural_label\",\n            \"minzoom\": 4,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"glacier\",\n                        \"landform\",\n                        \"disputed_glacier\",\n                        \"disputed_landform\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"worldview\"\n                        ],\n                        [\n                            \"all\",\n                            \"US\"\n                        ],\n                        true,\n                        false\n                    ],\n                    false\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    4\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"sizerank\"\n                        ],\n                        18,\n                        5,\n                        12\n                    ],\n                    17,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"sizerank\"\n                        ],\n                        18,\n                        13,\n                        12\n                    ]\n                ],\n                \"text-max-angle\": 30,\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"DIN Pro Medium\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"symbol-placement\": \"line-center\",\n                \"text-pitch-alignment\": \"viewport\"\n            },\n            \"paint\": {\n                \"text-halo-width\": 0.5,\n                \"text-halo-color\": \"hsl(60, 17%, 84%)\",\n                \"text-halo-blur\": 0.5,\n                \"text-color\": \"hsl(340, 10%, 38%)\"\n            }\n        },\n        {\n            \"id\": \"natural-point-label\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"natural_label\",\n            \"minzoom\": 4,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"dock\",\n                        \"glacier\",\n                        \"landform\",\n                        \"water_feature\",\n                        \"wetland\",\n                        \"disputed_dock\",\n                        \"disputed_glacier\",\n                        \"disputed_landform\",\n                        \"disputed_water_feature\",\n                        \"disputed_wetland\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"worldview\"\n                        ],\n                        [\n                            \"all\",\n                            \"US\"\n                        ],\n                        true,\n                        false\n                    ],\n                    false\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    4\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"Point\"\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"sizerank\"\n                        ],\n                        18,\n                        5,\n                        12\n                    ],\n                    17,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"sizerank\"\n                        ],\n                        18,\n                        13,\n                        12\n                    ]\n                ],\n                \"icon-image\": [\n                    \"get\",\n                    \"maki\"\n                ],\n                \"text-font\": [\n                    \"DIN Pro Medium\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-offset\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"sizerank\"\n                        ],\n                        [\n                            \"literal\",\n                            [\n                                0,\n                                0\n                            ]\n                        ],\n                        5,\n                        [\n                            \"literal\",\n                            [\n                                0,\n                                0.8\n                            ]\n                        ]\n                    ],\n                    17,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"sizerank\"\n                        ],\n                        [\n                            \"literal\",\n                            [\n                                0,\n                                0\n                            ]\n                        ],\n                        13,\n                        [\n                            \"literal\",\n                            [\n                                0,\n                                0.8\n                            ]\n                        ]\n                    ]\n                ],\n                \"text-anchor\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"sizerank\"\n                        ],\n                        \"center\",\n                        5,\n                        \"top\"\n                    ],\n                    17,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"sizerank\"\n                        ],\n                        \"center\",\n                        13,\n                        \"top\"\n                    ]\n                ],\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"icon-opacity\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"sizerank\"\n                        ],\n                        0,\n                        5,\n                        1\n                    ],\n                    17,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"sizerank\"\n                        ],\n                        0,\n                        13,\n                        1\n                    ]\n                ],\n                \"text-halo-color\": \"hsl(60, 20%, 100%)\",\n                \"text-halo-width\": 0.5,\n                \"text-halo-blur\": 0.5,\n                \"text-color\": \"hsl(340, 10%, 38%)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"natural-features\",\n                \"mapbox:group\": \"Natural features, natural-labels\",\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"id\": \"water-line-label\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"natural-features\",\n                \"mapbox:group\": \"Natural features, natural-labels\",\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"natural_label\",\n            \"minzoom\": 1,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"bay\",\n                        \"ocean\",\n                        \"reservoir\",\n                        \"sea\",\n                        \"water\",\n                        \"disputed_bay\",\n                        \"disputed_ocean\",\n                        \"disputed_reservoir\",\n                        \"disputed_sea\",\n                        \"disputed_water\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"worldview\"\n                        ],\n                        [\n                            \"all\",\n                            \"US\"\n                        ],\n                        true,\n                        false\n                    ],\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"LineString\"\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"*\",\n                        [\n                            \"-\",\n                            16,\n                            [\n                                \"sqrt\",\n                                [\n                                    \"get\",\n                                    \"sizerank\"\n                                ]\n                            ]\n                        ],\n                        1\n                    ],\n                    22,\n                    [\n                        \"*\",\n                        [\n                            \"-\",\n                            22,\n                            [\n                                \"sqrt\",\n                                [\n                                    \"get\",\n                                    \"sizerank\"\n                                ]\n                            ]\n                        ],\n                        1\n                    ]\n                ],\n                \"text-max-angle\": 30,\n                \"text-letter-spacing\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"ocean\",\n                    0.25,\n                    [\n                        \"sea\",\n                        \"bay\"\n                    ],\n                    0.15,\n                    0\n                ],\n                \"text-font\": [\n                    \"DIN Pro Italic\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"symbol-placement\": \"line-center\",\n                \"text-pitch-alignment\": \"viewport\",\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"bay\",\n                        \"ocean\",\n                        \"sea\"\n                    ],\n                    \"hsl(205, 71%, 90%)\",\n                    \"hsl(205, 43%, 90%)\"\n                ],\n                \"text-halo-color\": \"hsla(60, 17%, 84%, 0.5)\"\n            }\n        },\n        {\n            \"id\": \"water-point-label\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"natural_label\",\n            \"minzoom\": 1,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"bay\",\n                        \"ocean\",\n                        \"reservoir\",\n                        \"sea\",\n                        \"water\",\n                        \"disputed_bay\",\n                        \"disputed_ocean\",\n                        \"disputed_reservoir\",\n                        \"disputed_sea\",\n                        \"disputed_water\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"worldview\"\n                        ],\n                        [\n                            \"all\",\n                            \"US\"\n                        ],\n                        true,\n                        false\n                    ],\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"Point\"\n                ]\n            ],\n            \"layout\": {\n                \"text-line-height\": 1.3,\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"*\",\n                        [\n                            \"-\",\n                            16,\n                            [\n                                \"sqrt\",\n                                [\n                                    \"get\",\n                                    \"sizerank\"\n                                ]\n                            ]\n                        ],\n                        1\n                    ],\n                    22,\n                    [\n                        \"*\",\n                        [\n                            \"-\",\n                            22,\n                            [\n                                \"sqrt\",\n                                [\n                                    \"get\",\n                                    \"sizerank\"\n                                ]\n                            ]\n                        ],\n                        1\n                    ]\n                ],\n                \"text-font\": [\n                    \"DIN Pro Italic\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-letter-spacing\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"ocean\",\n                    0.25,\n                    [\n                        \"bay\",\n                        \"sea\"\n                    ],\n                    0.15,\n                    0.01\n                ],\n                \"text-max-width\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"ocean\",\n                    4,\n                    \"sea\",\n                    5,\n                    [\n                        \"bay\",\n                        \"water\"\n                    ],\n                    7,\n                    10\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"bay\",\n                        \"ocean\",\n                        \"sea\"\n                    ],\n                    \"hsl(205, 71%, 90%)\",\n                    \"hsl(205, 43%, 90%)\"\n                ],\n                \"text-halo-color\": \"hsla(60, 17%, 84%, 0.5)\"\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"natural-features\",\n                \"mapbox:group\": \"Natural features, natural-labels\",\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"id\": \"poi-label\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"poi_label\",\n            \"minzoom\": 6,\n            \"filter\": [\n                \"<=\",\n                [\n                    \"get\",\n                    \"filterrank\"\n                ],\n                [\n                    \"+\",\n                    [\n                        \"step\",\n                        [\n                            \"zoom\"\n                        ],\n                        0,\n                        16,\n                        1,\n                        17,\n                        2\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        \"food_and_drink_stores\",\n                        3,\n                        \"historic\",\n                        3,\n                        \"landmark\",\n                        3,\n                        \"medical\",\n                        3,\n                        \"motorist\",\n                        3,\n                        \"park_like\",\n                        4,\n                        \"sport_and_leisure\",\n                        4,\n                        \"visitor_amenities\",\n                        4,\n                        2\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"sizerank\"\n                        ],\n                        18,\n                        5,\n                        12\n                    ],\n                    17,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"sizerank\"\n                        ],\n                        18,\n                        13,\n                        12\n                    ]\n                ],\n                \"icon-image\": [\n                    \"case\",\n                    [\n                        \"has\",\n                        \"maki_beta\"\n                    ],\n                    [\n                        \"coalesce\",\n                        [\n                            \"image\",\n                            [\n                                \"get\",\n                                \"maki_beta\"\n                            ]\n                        ],\n                        [\n                            \"image\",\n                            [\n                                \"get\",\n                                \"maki\"\n                            ]\n                        ]\n                    ],\n                    [\n                        \"image\",\n                        [\n                            \"get\",\n                            \"maki\"\n                        ]\n                    ]\n                ],\n                \"text-font\": [\n                    \"DIN Pro Medium\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-offset\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"sizerank\"\n                        ],\n                        [\n                            \"literal\",\n                            [\n                                0,\n                                0\n                            ]\n                        ],\n                        5,\n                        [\n                            \"literal\",\n                            [\n                                0,\n                                0.8\n                            ]\n                        ]\n                    ],\n                    17,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"sizerank\"\n                        ],\n                        [\n                            \"literal\",\n                            [\n                                0,\n                                0\n                            ]\n                        ],\n                        13,\n                        [\n                            \"literal\",\n                            [\n                                0,\n                                0.8\n                            ]\n                        ]\n                    ]\n                ],\n                \"text-anchor\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"sizerank\"\n                        ],\n                        \"center\",\n                        5,\n                        \"top\"\n                    ],\n                    17,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"sizerank\"\n                        ],\n                        \"center\",\n                        13,\n                        \"top\"\n                    ]\n                ],\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"icon-opacity\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"sizerank\"\n                        ],\n                        0,\n                        5,\n                        1\n                    ],\n                    17,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"sizerank\"\n                        ],\n                        0,\n                        13,\n                        1\n                    ]\n                ],\n                \"text-halo-color\": \"hsl(60, 20%, 100%)\",\n                \"text-halo-width\": 0.5,\n                \"text-halo-blur\": 0.5,\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    \"food_and_drink\",\n                    \"hsl(35, 80%, 38%)\",\n                    \"park_like\",\n                    \"hsl(100, 80%, 18%)\",\n                    \"education\",\n                    \"hsl(30, 60%, 28%)\",\n                    \"medical\",\n                    \"hsl(10, 60%, 43%)\",\n                    \"sport_and_leisure\",\n                    \"hsl(210, 60%, 38%)\",\n                    \"hsl(340, 10%, 38%)\"\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"point-of-interest-labels\",\n                \"mapbox:group\": \"Point of interest labels, poi-labels\",\n                \"microg:gms-type-feature\": \"poi\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"id\": \"transit-label\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"transit_stop_label\",\n            \"minzoom\": 12,\n            \"filter\": [\n                \"step\",\n                [\n                    \"zoom\"\n                ],\n                [\n                    \"all\",\n                    [\n                        \"<=\",\n                        [\n                            \"get\",\n                            \"filterrank\"\n                        ],\n                        4\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"mode\"\n                        ],\n                        \"rail\",\n                        true,\n                        \"metro_rail\",\n                        true,\n                        false\n                    ],\n                    [\n                        \"!=\",\n                        [\n                            \"get\",\n                            \"stop_type\"\n                        ],\n                        \"entrance\"\n                    ]\n                ],\n                14,\n                [\n                    \"all\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"mode\"\n                        ],\n                        \"rail\",\n                        true,\n                        \"metro_rail\",\n                        true,\n                        false\n                    ],\n                    [\n                        \"!=\",\n                        [\n                            \"get\",\n                            \"stop_type\"\n                        ],\n                        \"entrance\"\n                    ]\n                ],\n                15,\n                [\n                    \"all\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"mode\"\n                        ],\n                        \"rail\",\n                        true,\n                        \"metro_rail\",\n                        true,\n                        \"ferry\",\n                        true,\n                        \"light_rail\",\n                        true,\n                        false\n                    ],\n                    [\n                        \"!=\",\n                        [\n                            \"get\",\n                            \"stop_type\"\n                        ],\n                        \"entrance\"\n                    ]\n                ],\n                16,\n                [\n                    \"all\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"mode\"\n                        ],\n                        \"bus\",\n                        false,\n                        true\n                    ],\n                    [\n                        \"!=\",\n                        [\n                            \"get\",\n                            \"stop_type\"\n                        ],\n                        \"entrance\"\n                    ]\n                ],\n                17,\n                [\n                    \"!=\",\n                    [\n                        \"get\",\n                        \"stop_type\"\n                    ],\n                    \"entrance\"\n                ],\n                19,\n                true\n            ],\n            \"layout\": {\n                \"text-size\": 12,\n                \"icon-image\": [\n                    \"get\",\n                    \"network\"\n                ],\n                \"text-font\": [\n                    \"DIN Pro Medium\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-justify\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"stop_type\"\n                    ],\n                    \"entrance\",\n                    \"left\",\n                    \"center\"\n                ],\n                \"text-offset\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"stop_type\"\n                    ],\n                    \"entrance\",\n                    [\n                        \"literal\",\n                        [\n                            1,\n                            0\n                        ]\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            0,\n                            0.8\n                        ]\n                    ]\n                ],\n                \"text-anchor\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"stop_type\"\n                    ],\n                    \"entrance\",\n                    \"left\",\n                    \"top\"\n                ],\n                \"text-field\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"\",\n                    13,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"mode\"\n                        ],\n                        [\n                            \"rail\",\n                            \"metro_rail\"\n                        ],\n                        [\n                            \"coalesce\",\n                            [\n                                \"get\",\n                                \"name_en\"\n                            ],\n                            [\n                                \"get\",\n                                \"name\"\n                            ]\n                        ],\n                        \"\"\n                    ],\n                    14,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"mode\"\n                        ],\n                        [\n                            \"bus\",\n                            \"bicycle\"\n                        ],\n                        \"\",\n                        [\n                            \"coalesce\",\n                            [\n                                \"get\",\n                                \"name_en\"\n                            ],\n                            [\n                                \"get\",\n                                \"name\"\n                            ]\n                        ]\n                    ],\n                    18,\n                    [\n                        \"coalesce\",\n                        [\n                            \"get\",\n                            \"name_en\"\n                        ],\n                        [\n                            \"get\",\n                            \"name\"\n                        ]\n                    ]\n                ],\n                \"text-letter-spacing\": 0.01,\n                \"text-max-width\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"stop_type\"\n                    ],\n                    \"entrance\",\n                    15,\n                    9\n                ]\n            },\n            \"paint\": {\n                \"text-halo-color\": \"hsl(60, 20%, 100%)\",\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"network\"\n                    ],\n                    \"tokyo-metro\",\n                    \"hsl(180, 30%, 30%)\",\n                    \"mexico-city-metro\",\n                    \"hsl(25, 63%, 63%)\",\n                    [\n                        \"barcelona-metro\",\n                        \"delhi-metro\",\n                        \"hong-kong-mtr\",\n                        \"milan-metro\",\n                        \"osaka-subway\"\n                    ],\n                    \"hsl(0, 57%, 47%)\",\n                    [\n                        \"boston-t\",\n                        \"washington-metro\"\n                    ],\n                    \"hsl(230, 11%, 20%)\",\n                    [\n                        \"chongqing-rail-transit\",\n                        \"kiev-metro\",\n                        \"singapore-mrt\",\n                        \"taipei-metro\"\n                    ],\n                    \"hsl(140, 56%, 25%)\",\n                    \"hsl(230, 50%, 60%)\"\n                ],\n                \"text-halo-blur\": 0.5,\n                \"text-halo-width\": 0.5\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"transit\",\n                \"mapbox:group\": \"Transit, transit-labels\",\n                \"microg:gms-type-feature\": \"transit.station.bus\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"id\": \"airport-label\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"airport_label\",\n            \"minzoom\": 8,\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"military\",\n                    \"civil\",\n                    \"disputed_military\",\n                    \"disputed_civil\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"worldview\"\n                    ],\n                    [\n                        \"all\",\n                        \"US\"\n                    ],\n                    true,\n                    false\n                ],\n                false\n            ],\n            \"layout\": {\n                \"text-line-height\": 1.1,\n                \"text-size\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"sizerank\"\n                    ],\n                    18,\n                    9,\n                    12\n                ],\n                \"icon-image\": [\n                    \"get\",\n                    \"maki\"\n                ],\n                \"text-font\": [\n                    \"DIN Pro Medium\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-offset\": [\n                    0,\n                    0.8\n                ],\n                \"text-rotation-alignment\": \"viewport\",\n                \"text-anchor\": \"top\",\n                \"text-field\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"sizerank\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"has\",\n                            \"ref\"\n                        ],\n                        [\n                            \"concat\",\n                            [\n                                \"get\",\n                                \"ref\"\n                            ],\n                            \" -\\n\",\n                            [\n                                \"coalesce\",\n                                [\n                                    \"get\",\n                                    \"name_en\"\n                                ],\n                                [\n                                    \"get\",\n                                    \"name\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"coalesce\",\n                            [\n                                \"get\",\n                                \"name_en\"\n                            ],\n                            [\n                                \"get\",\n                                \"name\"\n                            ]\n                        ]\n                    ],\n                    15,\n                    [\n                        \"get\",\n                        \"ref\"\n                    ]\n                ],\n                \"text-letter-spacing\": 0.01,\n                \"text-max-width\": 9\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(230, 40%, 55%)\",\n                \"text-halo-color\": \"hsl(60, 20%, 100%)\",\n                \"text-halo-width\": 1\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"transit\",\n                \"mapbox:group\": \"Transit, transit-labels\",\n                \"microg:gms-type-feature\": \"transit.station.airport\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"id\": \"settlement-subdivision-label\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"place_label\",\n            \"minzoom\": 10,\n            \"maxzoom\": 15,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"settlement_subdivision\",\n                        \"disputed_settlement_subdivision\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"worldview\"\n                        ],\n                        [\n                            \"all\",\n                            \"US\"\n                        ],\n                        true,\n                        false\n                    ],\n                    false\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    3\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-transform\": \"uppercase\",\n                \"text-font\": [\n                    \"DIN Pro Regular\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-letter-spacing\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    \"suburb\",\n                    0.15,\n                    0.05\n                ],\n                \"text-max-width\": 7,\n                \"text-padding\": 3,\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"cubic-bezier\",\n                        0.5,\n                        0,\n                        1,\n                        1\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    11,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"type\"\n                        ],\n                        \"suburb\",\n                        11,\n                        10.5\n                    ],\n                    15,\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"type\"\n                        ],\n                        \"suburb\",\n                        15,\n                        14\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-halo-color\": \"hsla(60, 25%, 100%, 0.75)\",\n                \"text-halo-width\": 1,\n                \"text-color\": \"hsl(230, 29%, 36%)\",\n                \"text-halo-blur\": 0.5\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"place-labels\",\n                \"mapbox:group\": \"Place labels, place-labels\",\n                \"microg:gms-type-feature\": \"administrative.neighborhood\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"id\": \"settlement-minor-label\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"place_label\",\n            \"minzoom\": 2,\n            \"maxzoom\": 13,\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    3\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"settlement\",\n                        \"disputed_settlement\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"worldview\"\n                        ],\n                        [\n                            \"all\",\n                            \"US\"\n                        ],\n                        true,\n                        false\n                    ],\n                    false\n                ],\n                [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \">\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        6\n                    ],\n                    4,\n                    [\n                        \">=\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        7\n                    ],\n                    6,\n                    [\n                        \">=\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        8\n                    ],\n                    7,\n                    [\n                        \">=\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        10\n                    ],\n                    10,\n                    [\n                        \">=\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        11\n                    ],\n                    11,\n                    [\n                        \">=\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        13\n                    ],\n                    12,\n                    [\n                        \">=\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        15\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"symbol-sort-key\": [\n                    \"get\",\n                    \"symbolrank\"\n                ],\n                \"icon-image\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"==\",\n                            [\n                                \"get\",\n                                \"capital\"\n                            ],\n                            2\n                        ],\n                        \"border-dot-13\",\n                        [\n                            \"step\",\n                            [\n                                \"get\",\n                                \"symbolrank\"\n                            ],\n                            \"dot-11\",\n                            9,\n                            \"dot-10\",\n                            11,\n                            \"dot-9\"\n                        ]\n                    ],\n                    8,\n                    \"\"\n                ],\n                \"text-font\": [\n                    \"DIN Pro Regular\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-radial-offset\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"capital\"\n                        ],\n                        2,\n                        0.6,\n                        0.55\n                    ],\n                    8,\n                    0\n                ],\n                \"text-anchor\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"get\",\n                        \"text_anchor\"\n                    ],\n                    8,\n                    \"center\"\n                ],\n                \"text-justify\": \"auto\",\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-max-width\": 7,\n                \"text-line-height\": 1.1,\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"cubic-bezier\",\n                        0.2,\n                        0,\n                        0.9,\n                        1\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        11,\n                        9,\n                        10\n                    ],\n                    6,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        14,\n                        9,\n                        12,\n                        12,\n                        10\n                    ],\n                    8,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        16,\n                        9,\n                        14,\n                        12,\n                        12,\n                        15,\n                        10\n                    ],\n                    13,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        22,\n                        9,\n                        20,\n                        12,\n                        16,\n                        15,\n                        14\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(230, 29%, 0%)\",\n                \"text-halo-color\": \"hsl(60, 25%, 100%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"place-labels\",\n                \"mapbox:group\": \"Place labels, place-labels\",\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"id\": \"settlement-major-label\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"place_label\",\n            \"minzoom\": 2,\n            \"maxzoom\": 15,\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    3\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"settlement\",\n                        \"disputed_settlement\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"worldview\"\n                        ],\n                        [\n                            \"all\",\n                            \"US\"\n                        ],\n                        true,\n                        false\n                    ],\n                    false\n                ],\n                [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    false,\n                    2,\n                    [\n                        \"<=\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        6\n                    ],\n                    4,\n                    [\n                        \"<\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        7\n                    ],\n                    6,\n                    [\n                        \"<\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        8\n                    ],\n                    7,\n                    [\n                        \"<\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        10\n                    ],\n                    10,\n                    [\n                        \"<\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        11\n                    ],\n                    11,\n                    [\n                        \"<\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        13\n                    ],\n                    12,\n                    [\n                        \"<\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        15\n                    ],\n                    13,\n                    [\n                        \">=\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        11\n                    ],\n                    14,\n                    [\n                        \">=\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        15\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"symbol-sort-key\": [\n                    \"get\",\n                    \"symbolrank\"\n                ],\n                \"icon-image\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"==\",\n                            [\n                                \"get\",\n                                \"capital\"\n                            ],\n                            2\n                        ],\n                        \"border-dot-13\",\n                        [\n                            \"step\",\n                            [\n                                \"get\",\n                                \"symbolrank\"\n                            ],\n                            \"dot-11\",\n                            9,\n                            \"dot-10\",\n                            11,\n                            \"dot-9\"\n                        ]\n                    ],\n                    8,\n                    \"\"\n                ],\n                \"text-font\": [\n                    \"DIN Pro Medium\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-radial-offset\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"capital\"\n                        ],\n                        2,\n                        0.6,\n                        0.55\n                    ],\n                    8,\n                    0\n                ],\n                \"text-anchor\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"get\",\n                        \"text_anchor\"\n                    ],\n                    8,\n                    \"center\"\n                ],\n                \"text-justify\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"text_anchor\"\n                        ],\n                        [\n                            \"left\",\n                            \"bottom-left\",\n                            \"top-left\"\n                        ],\n                        \"left\",\n                        [\n                            \"right\",\n                            \"bottom-right\",\n                            \"top-right\"\n                        ],\n                        \"right\",\n                        \"center\"\n                    ],\n                    8,\n                    \"center\"\n                ],\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-max-width\": 7,\n                \"text-line-height\": 1.1,\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"cubic-bezier\",\n                        0.2,\n                        0,\n                        0.9,\n                        1\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    3,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        13,\n                        6,\n                        11\n                    ],\n                    6,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        18,\n                        6,\n                        16,\n                        7,\n                        14\n                    ],\n                    8,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        20,\n                        9,\n                        16,\n                        10,\n                        14\n                    ],\n                    15,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        24,\n                        9,\n                        20,\n                        12,\n                        16,\n                        15,\n                        14\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(230, 29%, 0%)\",\n                \"text-halo-color\": \"hsl(60, 25%, 100%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"place-labels\",\n                \"mapbox:group\": \"Place labels, place-labels\",\n                \"microg:gms-type-feature\": \"administrative.land_parcel\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"id\": \"state-label\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"place_label\",\n            \"minzoom\": 3,\n            \"maxzoom\": 9,\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"state\",\n                    \"disputed_state\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"worldview\"\n                    ],\n                    [\n                        \"all\",\n                        \"US\"\n                    ],\n                    true,\n                    false\n                ],\n                false\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"cubic-bezier\",\n                        0.85,\n                        0.7,\n                        0.65,\n                        1\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    4,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        9,\n                        6,\n                        8,\n                        7,\n                        7\n                    ],\n                    9,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        21,\n                        6,\n                        16,\n                        7,\n                        14\n                    ]\n                ],\n                \"text-transform\": \"uppercase\",\n                \"text-font\": [\n                    \"DIN Pro Bold\",\n                    \"Arial Unicode MS Bold\"\n                ],\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-letter-spacing\": 0.15,\n                \"text-max-width\": 6\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(230, 29%, 0%)\",\n                \"text-halo-color\": \"hsl(60, 25%, 100%)\",\n                \"text-halo-width\": 1,\n                \"text-opacity\": 0.5\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"place-labels\",\n                \"mapbox:group\": \"Place labels, place-labels\",\n                \"microg:gms-type-feature\": \"administrative.province\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"id\": \"country-label\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"place_label\",\n            \"minzoom\": 1,\n            \"maxzoom\": 10,\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"country\",\n                    \"disputed_country\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"worldview\"\n                    ],\n                    [\n                        \"all\",\n                        \"US\"\n                    ],\n                    true,\n                    false\n                ],\n                false\n            ],\n            \"layout\": {\n                \"icon-image\": \"\",\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-line-height\": 1.1,\n                \"text-max-width\": 6,\n                \"text-font\": [\n                    \"DIN Pro Medium\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-radial-offset\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    0.6,\n                    8,\n                    0\n                ],\n                \"text-justify\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"text_anchor\"\n                        ],\n                        [\n                            \"left\",\n                            \"bottom-left\",\n                            \"top-left\"\n                        ],\n                        \"left\",\n                        [\n                            \"right\",\n                            \"bottom-right\",\n                            \"top-right\"\n                        ],\n                        \"right\",\n                        \"center\"\n                    ],\n                    7,\n                    \"auto\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"cubic-bezier\",\n                        0.2,\n                        0,\n                        0.7,\n                        1\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    1,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        11,\n                        4,\n                        9,\n                        5,\n                        8\n                    ],\n                    9,\n                    [\n                        \"step\",\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ],\n                        22,\n                        4,\n                        19,\n                        5,\n                        17\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"icon-opacity\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"has\",\n                            \"text_anchor\"\n                        ],\n                        1,\n                        0\n                    ],\n                    7,\n                    0\n                ],\n                \"text-color\": \"hsl(230, 29%, 0%)\",\n                \"text-halo-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    2,\n                    \"hsla(60, 25%, 100%, 0.75)\",\n                    3,\n                    \"hsl(60, 25%, 100%)\"\n                ],\n                \"text-halo-width\": 1.25\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"place-labels\",\n                \"mapbox:group\": \"Place labels, place-labels\",\n                \"microg:gms-type-feature\": \"administrative.country\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"id\": \"continent-label\",\n            \"type\": \"symbol\",\n            \"source\": \"composite\",\n            \"source-layer\": \"natural_label\",\n            \"minzoom\": 0.75,\n            \"maxzoom\": 3,\n            \"filter\": [\n                \"==\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                \"continent\"\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-line-height\": 1.1,\n                \"text-max-width\": 6,\n                \"text-font\": [\n                    \"DIN Pro Medium\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        0.5\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    10,\n                    2.5,\n                    15\n                ],\n                \"text-transform\": \"uppercase\",\n                \"text-letter-spacing\": 0.05\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(230, 29%, 0%)\",\n                \"text-halo-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    \"hsla(60, 25%, 100%, 0.75)\",\n                    3,\n                    \"hsl(60, 25%, 100%)\"\n                ],\n                \"text-halo-width\": 1.5,\n                \"text-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    0.8,\n                    1.5,\n                    0.5,\n                    2.5,\n                    0\n                ]\n            },\n            \"metadata\": {\n                \"mapbox:featureComponent\": \"place-labels\",\n                \"mapbox:group\": \"Place labels, place-labels\",\n                \"microg:gms-type-feature\": \"administrative.country\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        }\n    ],\n    \"sources\": {\n        \"composite\": {\n            \"url\": \"mapbox://mapbox.mapbox-streets-v8,mapbox.mapbox-terrain-v2,mapbox.mapbox-bathymetry-v2\",\n            \"type\": \"vector\"\n        }\n    },\n    \"created\": \"1970-01-01T00:00:00.000Z\",\n    \"modified\": \"1970-01-01T00:00:00.000Z\",\n    \"owner\": \"mapbox\",\n    \"id\": \"outdoors-v12\",\n    \"draft\": false\n}\n"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/style-microg-normal-mapbox.json",
    "content": "{\n    \"version\": 8,\n    \"name\": \"Mountain View Full\",\n    \"metadata\": {\n        \"mapbox:origin\": \"basic-template\",\n        \"mapbox:autocomposite\": true,\n        \"mapbox:type\": \"template\",\n        \"mapbox:sdk-support\": {\n            \"js\": \"0.50.0\",\n            \"android\": \"6.7.0\",\n            \"ios\": \"4.6.0\"\n        },\n        \"mapbox:trackposition\": false,\n        \"mapbox:groups\": {\n            \"f51b507d2a17e572c70a5db74b0fec7e\": {\n                \"name\": \"Base\",\n                \"collapsed\": false\n            },\n            \"3f48b8dc54ff2e6544b9ef9cedbf2990\": {\n                \"name\": \"Streets\",\n                \"collapsed\": true\n            },\n            \"29bb589e8d1b9b402583363648b70302\": {\n                \"name\": \"Buildings\",\n                \"collapsed\": true\n            },\n            \"3c26e9cbc75335c6f0ba8de5439cf1fa\": {\n                \"name\": \"Country borders\",\n                \"collapsed\": true\n            },\n            \"7b44201d7f1682d99f7140188aff23ce\": {\n                \"name\": \"Labels\",\n                \"collapsed\": true\n            },\n            \"24306bdccbff03e2ee08d5d1a4ca7312\": {\n                \"name\": \"Street name\",\n                \"collapsed\": true\n            },\n            \"124a9d7a8e5226775d947c592110dfad\": {\n                \"name\": \"POI\",\n                \"collapsed\": true\n            }\n        },\n        \"mapbox:uiParadigm\": \"layers\"\n    },\n    \"center\": [\n        12.819420849458652,\n        50.03325860617235\n    ],\n    \"zoom\": 3.315829104862067,\n    \"bearing\": 0,\n    \"pitch\": 1.5,\n    \"light\": {\n        \"intensity\": 0.5,\n        \"color\": \"hsl(0, 0%, 100%)\",\n        \"anchor\": \"viewport\"\n    },\n    \"sources\": {\n        \"composite\": {\n            \"url\": \"mapbox://mapbox.mapbox-streets-v8,mapbox.mapbox-terrain-v2\",\n            \"type\": \"vector\"\n        }\n    },\n    \"sprite\": \"mapbox://sprites/microg/cjui4020201oo1fmca7yuwbor/8fkcj5fgn4mftlzuak3guz1f9\",\n    \"glyphs\": \"mapbox://fonts/microg/{fontstack}/{range}.pbf\",\n    \"layers\": [\n        {\n            \"id\": \"background\",\n            \"type\": \"background\",\n            \"layout\": {},\n            \"paint\": {\n                \"background-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    4,\n                    \"hsl(43, 30%, 91%)\",\n                    5,\n                    \"hsl(0, 0%, 96%)\",\n                    8,\n                    \"hsl(0, 0%, 96%)\",\n                    9,\n                    \"#efeee8\",\n                    16,\n                    \"hsl(0, 0%, 95%)\",\n                    18,\n                    \"#f8f9fb\"\n                ]\n            },\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"grass\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"landcover\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"grass\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    \"hsl(124, 30%, 90%)\",\n                    11,\n                    \"hsl(107, 30%, 94%)\",\n                    12.5,\n                    \"hsl(107, 30%, 94%)\",\n                    13.5,\n                    \"hsl(45, 12%, 93%)\"\n                ]\n            }\n        },\n        {\n            \"id\": \"forrest\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"landcover\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"wood\",\n                    \"scrub\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    \"hsl(124, 42%, 86%)\",\n                    11,\n                    \"hsl(107, 47%, 94%)\",\n                    12.5,\n                    \"hsl(107, 47%, 94%)\",\n                    13.5,\n                    \"hsl(45, 12%, 93%)\"\n                ]\n            }\n        },\n        {\n            \"id\": \"national_park\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"landuse_overlay\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"national_park\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": \"hsl(106, 58%, 85%)\"\n            }\n        },\n        {\n            \"id\": \"snow\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"landcover\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"snow\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": \"#f9fafc\"\n            }\n        },\n        {\n            \"id\": \"hillshade\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"landscape.natural.terrain\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"hillshade\",\n            \"layout\": {},\n            \"paint\": {\n                \"fill-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    0.03,\n                    13,\n                    0\n                ]\n            }\n        },\n        {\n            \"id\": \"park\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"poi.park\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"landuse\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"park\",\n                    \"scrub\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": \"#c1ecaf\"\n            }\n        },\n        {\n            \"id\": \"pitch\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"landscape.natural.terrain\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"landuse\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"pitch\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": \"#c8efbb\"\n            }\n        },\n        {\n            \"id\": \"landuse\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"landuse\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"airport\",\n                    \"school\",\n                    \"hospital\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": \"hsl(202, 26%, 94%)\"\n            }\n        },\n        {\n            \"id\": \"river\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"water\",\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": \"hsl(206, 100%, 83%)\"\n            }\n        },\n        {\n            \"id\": \"path\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"path\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    [\n                        \"platform\",\n                        \"steps\"\n                    ],\n                    false,\n                    true\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsl(118, 34%, 66%)\",\n                \"line-dasharray\": [\n                    4,\n                    2\n                ]\n            }\n        },\n        {\n            \"id\": \"steps\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"path\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    [\n                        \"steps\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsl(118, 5%, 66%)\",\n                \"line-dasharray\": [\n                    1,\n                    1\n                ],\n                \"line-gap-width\": 1\n            }\n        },\n        {\n            \"id\": \"platform\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"transit.station.rail\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    [\n                        \"platform\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    false,\n                    true\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    \"hsl(2, 20%, 92%)\",\n                    16,\n                    \"hsl(2, 95%, 92%)\"\n                ],\n                \"fill-outline-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    \"hsl(1, 10%, 76%)\",\n                    16,\n                    \"hsl(1, 74%, 76%)\"\n                ],\n                \"fill-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0,\n                    16,\n                    1\n                ]\n            }\n        },\n        {\n            \"id\": \"primary_tunnel_border\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary_link\",\n                        \"primary\",\n                        \"motorway_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    7,\n                    0,\n                    8,\n                    1,\n                    12,\n                    4,\n                    14,\n                    6,\n                    16,\n                    10,\n                    22,\n                    64\n                ],\n                \"line-color\": \"#cbcccd\"\n            }\n        },\n        {\n            \"id\": \"primary_tunnel\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary_link\",\n                        \"primary\",\n                        \"motorway_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    1,\n                    12,\n                    4,\n                    14,\n                    6,\n                    16,\n                    10,\n                    22,\n                    64\n                ],\n                \"line-color\": \"hsl(0, 0%, 89%)\"\n            }\n        },\n        {\n            \"id\": \"aeroway\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"transit.station.airport\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"aeroway\",\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsla(0, 0%, 0%, 0.1)\"\n            }\n        },\n        {\n            \"id\": \"service_road\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"service\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsla(0, 0%, 0%, 0.1)\"\n            }\n        },\n        {\n            \"id\": \"pedestrian_border\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"pedestrian\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"has\",\n                    \"name\"\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    13,\n                    1,\n                    16,\n                    4,\n                    22,\n                    32\n                ],\n                \"line-color\": \"#e3e3e3\",\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12.5,\n                    0,\n                    13.5,\n                    1\n                ]\n            }\n        },\n        {\n            \"id\": \"street_border\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"street\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    1,\n                    16,\n                    6,\n                    22,\n                    40\n                ],\n                \"line-color\": \"#e3e3e3\"\n            }\n        },\n        {\n            \"id\": \"secondary_border\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"secondary\",\n                    \"secondary_link\",\n                    \"tertiary_link\",\n                    \"tertiary\",\n                    \"trunk_link\",\n                    \"trunk\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    10,\n                    1,\n                    17,\n                    10,\n                    22,\n                    48\n                ],\n                \"line-color\": \"#e3e3e3\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    16,\n                    1,\n                    20,\n                    2\n                ]\n            }\n        },\n        {\n            \"id\": \"primary_border\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary_link\",\n                        \"primary\",\n                        \"motorway_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    false,\n                    true\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": \"round\"\n            },\n            \"paint\": {\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    1,\n                    16,\n                    8,\n                    22,\n                    64\n                ],\n                \"line-color\": \"#ecd283\"\n            }\n        },\n        {\n            \"id\": \"motorway_border\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"motorway\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    1,\n                    15.5,\n                    8,\n                    22,\n                    78\n                ],\n                \"line-color\": \"#ecd283\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    1,\n                    15,\n                    2\n                ]\n            }\n        },\n        {\n            \"id\": \"railway\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"major_rail\",\n                        \"minor_rail\",\n                        \"service_rail\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    false,\n                    true\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsl(220, 4%, 85%)\"\n            }\n        },\n        {\n            \"id\": \"pedestrian\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"pedestrian\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    [\n                        \"platform\"\n                    ],\n                    false,\n                    true\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"#ffffff\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    13,\n                    1,\n                    16,\n                    4,\n                    22,\n                    32\n                ],\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12.5,\n                    0,\n                    13.5,\n                    1\n                ]\n            }\n        },\n        {\n            \"id\": \"street\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"street\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"#ffffff\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    1,\n                    16,\n                    6,\n                    22,\n                    40\n                ]\n            }\n        },\n        {\n            \"id\": \"secondary\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"secondary\",\n                    \"secondary_link\",\n                    \"trunk_link\",\n                    \"tertiary\",\n                    \"tertiary_link\",\n                    \"trunk\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"#ffffff\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    10,\n                    1,\n                    17,\n                    10,\n                    22,\n                    48\n                ]\n            }\n        },\n        {\n            \"id\": \"primary\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary_link\",\n                        \"primary\",\n                        \"motorway_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    false,\n                    true\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"hsl(50, 100%, 75%)\",\n                    7,\n                    \"hsl(50, 100%, 85%)\"\n                ],\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    1,\n                    16,\n                    8,\n                    22,\n                    64\n                ]\n            }\n        },\n        {\n            \"id\": \"motorway\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"motorway\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"#ffeba3\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    1,\n                    15.5,\n                    8,\n                    22,\n                    78\n                ]\n            }\n        },\n        {\n            \"id\": \"primary_bridge_border\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary_link\",\n                        \"primary\",\n                        \"motorway_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"bridge\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    1,\n                    16,\n                    8,\n                    22,\n                    64\n                ],\n                \"line-color\": \"hsl(45, 73%, 72%)\"\n            }\n        },\n        {\n            \"id\": \"primary_bridge\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary_link\",\n                        \"primary\",\n                        \"motorway_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"bridge\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"hsl(50, 100%, 75%)\",\n                    7,\n                    \"hsl(50, 100%, 85%)\"\n                ],\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    1,\n                    16,\n                    8,\n                    22,\n                    64\n                ]\n            }\n        },\n        {\n            \"id\": \"building\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"29bb589e8d1b9b402583363648b70302\",\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"building\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"type\"\n                ],\n                [\n                    \"roof\"\n                ],\n                false,\n                true\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    [\n                        \"store\",\n                        \"retail\",\n                        \"church\",\n                        \"kiosk\",\n                        \"civic\",\n                        \"hotel\",\n                        \"supermarket\",\n                        \"pub\",\n                        \"dormitory\"\n                    ],\n                    \"hsl(33, 100%, 96%)\",\n                    \"#ededed\"\n                ],\n                \"fill-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    0,\n                    17,\n                    1\n                ]\n            }\n        },\n        {\n            \"id\": \"building_border\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"29bb589e8d1b9b402583363648b70302\",\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"building\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"type\"\n                ],\n                [\n                    \"roof\"\n                ],\n                false,\n                true\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    [\n                        \"store\",\n                        \"retail\",\n                        \"church\",\n                        \"kiosk\",\n                        \"civic\",\n                        \"commercial\",\n                        \"hotel\",\n                        \"supermarket\",\n                        \"pub\"\n                    ],\n                    \"#f8e1c7\",\n                    \"#dcdcdc\"\n                ],\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    0,\n                    17,\n                    1\n                ]\n            }\n        },\n        {\n            \"id\": \"building_3d\",\n            \"type\": \"fill-extrusion\",\n            \"metadata\": {\n                \"mapbox:group\": \"29bb589e8d1b9b402583363648b70302\",\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"building\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"extrude\"\n                ],\n                [\n                    \"true\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"fill-extrusion-height\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    0,\n                    16,\n                    [\n                        \"get\",\n                        \"height\"\n                    ]\n                ],\n                \"fill-extrusion-opacity\": 0.3,\n                \"fill-extrusion-color\": \"hsl(0, 0%, 93%)\"\n            }\n        },\n        {\n            \"id\": \"admin_0\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3c26e9cbc75335c6f0ba8de5439cf1fa\",\n                \"microg:gms-type-feature\": \"administrative.country\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"admin\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maritime\"\n                    ],\n                    [\n                        \"false\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"admin_level\"\n                    ],\n                    [\n                        0\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": [\n                    \"case\",\n                    [\n                        \"==\",\n                        [\n                            \"get\",\n                            \"disputed\"\n                        ],\n                        true\n                    ],\n                    \"hsl(0, 24%, 48%)\",\n                    \"#787a7b\"\n                ]\n            }\n        },\n        {\n            \"id\": \"admin_1\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3c26e9cbc75335c6f0ba8de5439cf1fa\",\n                \"microg:gms-type-feature\": \"administrative.province\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"admin\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maritime\"\n                    ],\n                    [\n                        \"false\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"admin_level\"\n                    ],\n                    [\n                        1\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": [\n                    \"case\",\n                    [\n                        \"==\",\n                        [\n                            \"get\",\n                            \"disputed\"\n                        ],\n                        true\n                    ],\n                    \"hsl(0, 24%, 48%)\",\n                    \"#787a7b\"\n                ],\n                \"line-dasharray\": [\n                    1,\n                    1\n                ]\n            }\n        },\n        {\n            \"id\": \"river_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"natural_label\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"river\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"symbol-placement\": \"line\",\n                \"symbol-spacing\": 500,\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ]\n            },\n            \"paint\": {\n                \"text-color\": \"#5083c1\",\n                \"text-halo-color\": \"#5083c1\",\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"city_label_right\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"place_label\",\n            \"maxzoom\": 8,\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    [\n                        \"/\",\n                        [\n                            \"zoom\"\n                        ],\n                        3\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"settlement\",\n                        \"settlement_subdivision\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-optional\": true,\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"-\",\n                        14,\n                        [\n                            \"max\",\n                            0,\n                            [\n                                \"-\",\n                                [\n                                    \"get\",\n                                    \"symbolrank\"\n                                ],\n                                8\n                            ]\n                        ]\n                    ],\n                    22,\n                    [\n                        \"-\",\n                        20,\n                        [\n                            \"/\",\n                            [\n                                \"get\",\n                                \"symbolrank\"\n                            ],\n                            4\n                        ]\n                    ]\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"capital\"\n                    ],\n                    [\n                        0,\n                        2\n                    ],\n                    \"capital\",\n                    \"city\"\n                ],\n                \"text-font\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"symbolrank\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\"\n                        ]\n                    ],\n                    10,\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Regular\"\n                        ]\n                    ]\n                ],\n                \"text-justify\": \"left\",\n                \"text-offset\": [\n                    0.5,\n                    0.1\n                ],\n                \"icon-size\": [\n                    \"/\",\n                    5,\n                    [\n                        \"get\",\n                        \"symbolrank\"\n                    ]\n                ],\n                \"text-anchor\": \"left\",\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"*\",\n                                [\n                                    \"get\",\n                                    \"symbolrank\"\n                                ],\n                                2\n                            ],\n                            5\n                        ],\n                        \"%)\"\n                    ],\n                    22,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"get\",\n                                \"symbolrank\"\n                            ],\n                            25\n                        ],\n                        \"%)\"\n                    ]\n                ],\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"text-halo-color\": \"hsl(0, 0%, 100%)\",\n                \"icon-opacity\": 0.8\n            }\n        },\n        {\n            \"id\": \"city_label_left\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"place_label\",\n            \"maxzoom\": 8,\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    [\n                        \"/\",\n                        [\n                            \"zoom\"\n                        ],\n                        3\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"settlement\",\n                        \"settlement_subdivision\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"-\",\n                        14,\n                        [\n                            \"max\",\n                            0,\n                            [\n                                \"-\",\n                                [\n                                    \"get\",\n                                    \"symbolrank\"\n                                ],\n                                8\n                            ]\n                        ]\n                    ],\n                    22,\n                    [\n                        \"-\",\n                        20,\n                        [\n                            \"/\",\n                            [\n                                \"get\",\n                                \"symbolrank\"\n                            ],\n                            4\n                        ]\n                    ]\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"capital\"\n                    ],\n                    [\n                        0,\n                        2\n                    ],\n                    \"capital\",\n                    \"city\"\n                ],\n                \"text-font\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"symbolrank\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\"\n                        ]\n                    ],\n                    10,\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Regular\"\n                        ]\n                    ]\n                ],\n                \"text-justify\": \"right\",\n                \"text-offset\": [\n                    -0.5,\n                    0.1\n                ],\n                \"icon-size\": [\n                    \"/\",\n                    5,\n                    [\n                        \"get\",\n                        \"symbolrank\"\n                    ]\n                ],\n                \"text-anchor\": \"right\",\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"*\",\n                                [\n                                    \"get\",\n                                    \"symbolrank\"\n                                ],\n                                2\n                            ],\n                            5\n                        ],\n                        \"%)\"\n                    ],\n                    22,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"get\",\n                                \"symbolrank\"\n                            ],\n                            25\n                        ],\n                        \"%)\"\n                    ]\n                ],\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"text-halo-color\": \"hsl(0, 0%, 100%)\",\n                \"icon-opacity\": 0.8\n            }\n        },\n        {\n            \"id\": \"city_label_below\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"place_label\",\n            \"maxzoom\": 8,\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    [\n                        \"/\",\n                        [\n                            \"zoom\"\n                        ],\n                        3\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"settlement\",\n                        \"settlement_subdivision\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"-\",\n                        14,\n                        [\n                            \"max\",\n                            0,\n                            [\n                                \"-\",\n                                [\n                                    \"get\",\n                                    \"symbolrank\"\n                                ],\n                                8\n                            ]\n                        ]\n                    ],\n                    22,\n                    [\n                        \"-\",\n                        20,\n                        [\n                            \"/\",\n                            [\n                                \"get\",\n                                \"symbolrank\"\n                            ],\n                            4\n                        ]\n                    ]\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"capital\"\n                    ],\n                    [\n                        0,\n                        2\n                    ],\n                    \"capital\",\n                    \"city\"\n                ],\n                \"text-font\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"symbolrank\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\"\n                        ]\n                    ],\n                    10,\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Regular\"\n                        ]\n                    ]\n                ],\n                \"text-offset\": [\n                    0,\n                    0.4\n                ],\n                \"icon-size\": [\n                    \"/\",\n                    5,\n                    [\n                        \"get\",\n                        \"symbolrank\"\n                    ]\n                ],\n                \"text-anchor\": \"top\",\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"*\",\n                                [\n                                    \"get\",\n                                    \"symbolrank\"\n                                ],\n                                2\n                            ],\n                            5\n                        ],\n                        \"%)\"\n                    ],\n                    22,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"get\",\n                                \"symbolrank\"\n                            ],\n                            25\n                        ],\n                        \"%)\"\n                    ]\n                ],\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"text-halo-color\": \"hsl(0, 0%, 100%)\",\n                \"icon-opacity\": 0.8\n            }\n        },\n        {\n            \"id\": \"city_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"place_label\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    [\n                        \"/\",\n                        [\n                            \"zoom\"\n                        ],\n                        3\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"settlement\",\n                        \"settlement_subdivision\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"-\",\n                        14,\n                        [\n                            \"max\",\n                            0,\n                            [\n                                \"-\",\n                                [\n                                    \"get\",\n                                    \"symbolrank\"\n                                ],\n                                8\n                            ]\n                        ]\n                    ],\n                    22,\n                    [\n                        \"-\",\n                        20,\n                        [\n                            \"/\",\n                            [\n                                \"get\",\n                                \"symbolrank\"\n                            ],\n                            4\n                        ]\n                    ]\n                ],\n                \"icon-image\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"capital\"\n                        ],\n                        [\n                            0,\n                            2\n                        ],\n                        \"capital\",\n                        \"city\"\n                    ],\n                    8,\n                    \"\"\n                ],\n                \"text-transform\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"symbolrank\"\n                    ],\n                    \"none\",\n                    15,\n                    \"uppercase\"\n                ],\n                \"text-font\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"symbolrank\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\"\n                        ]\n                    ],\n                    10,\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Regular\"\n                        ]\n                    ]\n                ],\n                \"text-offset\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            0,\n                            -0.2\n                        ]\n                    ],\n                    8,\n                    [\n                        \"literal\",\n                        [\n                            0,\n                            0\n                        ]\n                    ]\n                ],\n                \"icon-size\": [\n                    \"/\",\n                    5,\n                    [\n                        \"get\",\n                        \"symbolrank\"\n                    ]\n                ],\n                \"text-anchor\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"bottom\",\n                    8,\n                    \"center\"\n                ],\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-letter-spacing\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"get\",\n                        \"symbolrank\"\n                    ],\n                    0,\n                    0,\n                    8,\n                    0,\n                    12,\n                    0.1,\n                    16,\n                    0.2\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"*\",\n                                [\n                                    \"get\",\n                                    \"symbolrank\"\n                                ],\n                                2\n                            ],\n                            5\n                        ],\n                        \"%)\"\n                    ],\n                    22,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"get\",\n                                \"symbolrank\"\n                            ],\n                            25\n                        ],\n                        \"%)\"\n                    ]\n                ],\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"text-halo-color\": \"hsl(0, 0%, 100%)\",\n                \"icon-opacity\": 0.8\n            }\n        },\n        {\n            \"id\": \"park_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"poi.park\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"poi_label\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maki\"\n                    ],\n                    [\n                        \"park\",\n                        \"cemetery\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"sizerank\"\n                    ],\n                    10\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-size\": 14\n            },\n            \"paint\": {\n                \"text-color\": \"#297925\",\n                \"text-halo-color\": \"hsl(0, 0%, 100%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"road-number-shield\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road\",\n                \"microg:gms-type-element\": \"labels.icon\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"ref\"\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"reflen\"\n                    ],\n                    6\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": 9,\n                \"icon-image\": [\n                    \"case\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"shield\"\n                        ],\n                        [\n                            \"de-motorway\",\n                            \"rectangle-green\",\n                            \"rectangle-yellow\",\n                            \"rectangle-white\",\n                            \"rectangle-blue\",\n                            \"rectangle-red\",\n                            \"us-interstate\"\n                        ],\n                        true,\n                        false\n                    ],\n                    [\n                        \"concat\",\n                        \"shield_\",\n                        [\n                            \"get\",\n                            \"shield\"\n                        ],\n                        \"_\",\n                        [\n                            \"get\",\n                            \"reflen\"\n                        ]\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"shield_text_color\"\n                        ],\n                        [\n                            \"white\"\n                        ],\n                        true,\n                        false\n                    ],\n                    [\n                        \"concat\",\n                        \"shield_rectangle-blue_\",\n                        [\n                            \"get\",\n                            \"reflen\"\n                        ]\n                    ],\n                    [\n                        \"concat\",\n                        \"shield_rectangle-white_\",\n                        [\n                            \"get\",\n                            \"reflen\"\n                        ]\n                    ]\n                ],\n                \"icon-rotation-alignment\": \"viewport\",\n                \"text-font\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"shield_text_color\"\n                    ],\n                    [\n                        \"white\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Bold\"\n                        ]\n                    ],\n                    [\n                        \"black\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\"\n                        ]\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Bold\"\n                        ]\n                    ]\n                ],\n                \"symbol-placement\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"point\",\n                    11,\n                    \"line\"\n                ],\n                \"text-offset\": [\n                    0,\n                    0.1\n                ],\n                \"text-rotation-alignment\": \"viewport\",\n                \"icon-size\": 0.75,\n                \"text-field\": [\n                    \"get\",\n                    \"ref\"\n                ],\n                \"text-letter-spacing\": 0.05\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"case\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"shield_text_color\"\n                        ],\n                        [\n                            \"white\"\n                        ],\n                        true,\n                        false\n                    ],\n                    \"#ffffff\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"shield_text_color\"\n                        ],\n                        [\n                            \"black\"\n                        ],\n                        true,\n                        false\n                    ],\n                    \"hsl(0, 0%, 7%)\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"shield_text_color\"\n                        ],\n                        [\n                            \"yellow\"\n                        ],\n                        true,\n                        false\n                    ],\n                    \"hsl(50, 100%, 70%)\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"shield_text_color\"\n                        ],\n                        [\n                            \"orange\"\n                        ],\n                        true,\n                        false\n                    ],\n                    \"hsl(25, 100%, 75%)\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"shield_text_color\"\n                        ],\n                        [\n                            \"blue\"\n                        ],\n                        true,\n                        false\n                    ],\n                    \"hsl(230, 48%, 34%)\",\n                    \"#ffffff\"\n                ]\n            }\n        },\n        {\n            \"id\": \"country_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"administrative.country\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"place_label\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"country\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {\n                \"text-letter-spacing\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    1,\n                    0,\n                    3,\n                    0.15\n                ],\n                \"text-font\": [\n                    \"Roboto Medium\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.2\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    1,\n                    12,\n                    7,\n                    [\n                        \"/\",\n                        100,\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ]\n                    ]\n                ],\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(0, 0%, 10%)\",\n                \"text-halo-color\": \"hsl(0, 0%, 100%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"text-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    6,\n                    1,\n                    7,\n                    0\n                ]\n            }\n        },\n        {\n            \"id\": \"pedestrian_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 16,\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"pedestrian\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    [\n                        \"platform\"\n                    ],\n                    false,\n                    true\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"name\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    17,\n                    10,\n                    22,\n                    14\n                ],\n                \"text-padding\": 5\n            },\n            \"paint\": {\n                \"text-color\": \"#575757\",\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"street_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"street\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"name\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    6,\n                    16,\n                    10\n                ],\n                \"text-padding\": 5\n            },\n            \"paint\": {\n                \"text-color\": \"#575757\",\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"secondary_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"secondary\",\n                        \"secondary_link\",\n                        \"tertiary_link\",\n                        \"tertiary\",\n                        \"trunk_link\",\n                        \"trunk\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"name\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    8,\n                    16,\n                    13\n                ],\n                \"symbol-spacing\": 300,\n                \"text-padding\": 25\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(196, 0%, 34%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"primary_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary\",\n                        \"primary_link\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"name\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    10,\n                    18,\n                    14\n                ],\n                \"symbol-spacing\": 800,\n                \"text-padding\": 50\n            },\n            \"paint\": {\n                \"text-color\": \"#6e481d\",\n                \"text-halo-width\": 1,\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"poi_label_below\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"124a9d7a8e5226775d947c592110dfad\",\n                \"microg:gms-type-element\": \"labels.text\",\n                \"microg:gms-type-feature\": \"poi\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"poi_label\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    [\n                        \"/\",\n                        [\n                            \"zoom\"\n                        ],\n                        3.5\n                    ]\n                ],\n                [\n                    \"!\",\n                    [\n                        \"all\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"maki\"\n                            ],\n                            [\n                                \"park\",\n                                \"cemetery\"\n                            ],\n                            true,\n                            false\n                        ],\n                        [\n                            \"<=\",\n                            [\n                                \"get\",\n                                \"sizerank\"\n                            ],\n                            10\n                        ]\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-optional\": true,\n                \"text-line-height\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    15,\n                    1.2\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    13,\n                    15,\n                    14\n                ],\n                \"icon-offset\": [\n                    0,\n                    -36\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maki\"\n                    ],\n                    [\n                        \"museum\",\n                        \"lodging\",\n                        \"theatre\",\n                        \"grocery\",\n                        \"restaurant\"\n                    ],\n                    [\n                        \"concat\",\n                        \"poi_\",\n                        [\n                            \"get\",\n                            \"maki\"\n                        ]\n                    ],\n                    [\n                        \"fitness-centre\",\n                        \"golf\",\n                        \"campsite\",\n                        \"bowling-alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic-site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog-park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"poi_generic_green\",\n                    [\n                        \"bank\",\n                        \"parking\",\n                        \"parking-garage\"\n                    ],\n                    \"poi_generic_purple\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\"\n                    ],\n                    \"poi_generic_orange\",\n                    [\n                        \"alcohol-shop\",\n                        \"shop\",\n                        \"shoe\",\n                        \"convenience\",\n                        \"clothing-store\",\n                        \"jewelry-store\"\n                    ],\n                    \"poi_generic_blue\",\n                    [\n                        \"casino\",\n                        \"castle\",\n                        \"art-gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music\",\n                        \"monument\"\n                    ],\n                    \"poi_generic_teal\",\n                    [\n                        \"hospital\",\n                        \"doctor\"\n                    ],\n                    \"poi_generic_red\",\n                    [\n                        \"restaurant-pizza\",\n                        \"restaurant-seafood\",\n                        \"restaurant-noodle\",\n                        \"fast-food\",\n                        \"ice-cream\"\n                    ],\n                    \"poi_restaurant\",\n                    \"poi_generic\"\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-offset\": [\n                    0,\n                    0.5\n                ],\n                \"icon-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.25,\n                    15,\n                    0.32\n                ],\n                \"text-anchor\": \"top\",\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maki\"\n                    ],\n                    [\n                        \"museum\",\n                        \"casino\",\n                        \"castle\",\n                        \"theatre\",\n                        \"art-gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music\",\n                        \"monument\"\n                    ],\n                    \"hsl(186, 78%, 44%)\",\n                    [\n                        \"lodging\"\n                    ],\n                    \"#df7db1\",\n                    [\n                        \"fitness-centre\",\n                        \"golf\",\n                        \"campsite\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic-site\",\n                        \"zoo\",\n                        \"dog-park\",\n                        \"stadium\",\n                        \"bowling-alley\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"hsl(117, 53%, 31%)\",\n                    [\n                        \"restaurant-pizza\",\n                        \"restaurant-seafood\",\n                        \"restaurant\",\n                        \"restaurant-noodle\",\n                        \"bar\",\n                        \"cafe\",\n                        \"fast-food\",\n                        \"bakery\",\n                        \"ice-cream\"\n                    ],\n                    \"#c77d57\",\n                    [\n                        \"shop\",\n                        \"shoe\",\n                        \"alcohol-shop\",\n                        \"convenience\",\n                        \"grocery\",\n                        \"clothing-store\",\n                        \"jewelry-store\"\n                    ],\n                    \"hsl(213, 40%, 48%)\",\n                    [\n                        \"bank\",\n                        \"parking\",\n                        \"parking-garage\"\n                    ],\n                    \"#737b9b\",\n                    [\n                        \"hospital\",\n                        \"doctor\"\n                    ],\n                    \"#a47172\",\n                    \"#67747b\"\n                ],\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1,\n                \"icon-translate\": [\n                    0,\n                    0\n                ],\n                \"text-translate\": [\n                    0,\n                    0\n                ],\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"poi_label_above\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"124a9d7a8e5226775d947c592110dfad\",\n                \"microg:gms-type-element\": \"labels.text\",\n                \"microg:gms-type-feature\": \"poi\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"poi_label\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    [\n                        \"/\",\n                        [\n                            \"zoom\"\n                        ],\n                        3.5\n                    ]\n                ],\n                [\n                    \"!\",\n                    [\n                        \"all\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"maki\"\n                            ],\n                            [\n                                \"park\",\n                                \"cemetery\"\n                            ],\n                            true,\n                            false\n                        ],\n                        [\n                            \"<=\",\n                            [\n                                \"get\",\n                                \"sizerank\"\n                            ],\n                            10\n                        ]\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-optional\": true,\n                \"text-line-height\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    15,\n                    1.2\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    13,\n                    15,\n                    14\n                ],\n                \"icon-offset\": [\n                    0,\n                    -36\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maki\"\n                    ],\n                    [\n                        \"museum\",\n                        \"lodging\",\n                        \"theatre\",\n                        \"grocery\",\n                        \"restaurant\"\n                    ],\n                    [\n                        \"concat\",\n                        \"poi_\",\n                        [\n                            \"get\",\n                            \"maki\"\n                        ]\n                    ],\n                    [\n                        \"fitness-centre\",\n                        \"golf\",\n                        \"campsite\",\n                        \"bowling-alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic-site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog-park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"poi_generic_green\",\n                    [\n                        \"bank\",\n                        \"parking\",\n                        \"parking-garage\"\n                    ],\n                    \"poi_generic_purple\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\"\n                    ],\n                    \"poi_generic_orange\",\n                    [\n                        \"alcohol-shop\",\n                        \"shop\",\n                        \"shoe\",\n                        \"convenience\",\n                        \"clothing-store\",\n                        \"jewelry-store\"\n                    ],\n                    \"poi_generic_blue\",\n                    [\n                        \"casino\",\n                        \"castle\",\n                        \"art-gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music\",\n                        \"monument\"\n                    ],\n                    \"poi_generic_teal\",\n                    [\n                        \"hospital\",\n                        \"doctor\"\n                    ],\n                    \"poi_generic_red\",\n                    [\n                        \"restaurant-pizza\",\n                        \"restaurant-seafood\",\n                        \"restaurant-noodle\",\n                        \"fast-food\",\n                        \"ice-cream\"\n                    ],\n                    \"poi_restaurant\",\n                    \"poi_generic\"\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-offset\": [\n                    0,\n                    -2\n                ],\n                \"icon-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.25,\n                    15,\n                    0.32\n                ],\n                \"text-anchor\": \"bottom\",\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maki\"\n                    ],\n                    [\n                        \"museum\",\n                        \"casino\",\n                        \"castle\",\n                        \"theatre\",\n                        \"art-gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music\",\n                        \"monument\"\n                    ],\n                    \"hsl(186, 78%, 44%)\",\n                    [\n                        \"lodging\"\n                    ],\n                    \"#df7db1\",\n                    [\n                        \"fitness-centre\",\n                        \"golf\",\n                        \"campsite\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic-site\",\n                        \"zoo\",\n                        \"dog-park\",\n                        \"stadium\",\n                        \"bowling-alley\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"hsl(117, 53%, 31%)\",\n                    [\n                        \"restaurant-pizza\",\n                        \"restaurant-seafood\",\n                        \"restaurant\",\n                        \"restaurant-noodle\",\n                        \"bar\",\n                        \"cafe\",\n                        \"fast-food\",\n                        \"bakery\",\n                        \"ice-cream\"\n                    ],\n                    \"#c77d57\",\n                    [\n                        \"shop\",\n                        \"shoe\",\n                        \"alcohol-shop\",\n                        \"convenience\",\n                        \"grocery\",\n                        \"clothing-store\",\n                        \"jewelry-store\"\n                    ],\n                    \"hsl(213, 40%, 48%)\",\n                    [\n                        \"bank\",\n                        \"parking\",\n                        \"parking-garage\"\n                    ],\n                    \"#737b9b\",\n                    [\n                        \"hospital\",\n                        \"doctor\"\n                    ],\n                    \"#a47172\",\n                    \"#67747b\"\n                ],\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1,\n                \"icon-translate\": [\n                    0,\n                    0\n                ],\n                \"text-translate\": [\n                    0,\n                    0\n                ],\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"poi_label_left\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"124a9d7a8e5226775d947c592110dfad\",\n                \"microg:gms-type-element\": \"labels.text\",\n                \"microg:gms-type-feature\": \"poi\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"poi_label\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    [\n                        \"/\",\n                        [\n                            \"zoom\"\n                        ],\n                        3.5\n                    ]\n                ],\n                [\n                    \"!\",\n                    [\n                        \"all\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"maki\"\n                            ],\n                            [\n                                \"park\",\n                                \"cemetery\"\n                            ],\n                            true,\n                            false\n                        ],\n                        [\n                            \"<=\",\n                            [\n                                \"get\",\n                                \"sizerank\"\n                            ],\n                            10\n                        ]\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-line-height\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    15,\n                    1.2\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    13,\n                    15,\n                    14\n                ],\n                \"icon-offset\": [\n                    0,\n                    -36\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maki\"\n                    ],\n                    [\n                        \"museum\",\n                        \"lodging\",\n                        \"theatre\",\n                        \"grocery\",\n                        \"restaurant\"\n                    ],\n                    [\n                        \"concat\",\n                        \"poi_\",\n                        [\n                            \"get\",\n                            \"maki\"\n                        ]\n                    ],\n                    [\n                        \"fitness-centre\",\n                        \"golf\",\n                        \"campsite\",\n                        \"bowling-alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic-site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog-park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"poi_generic_green\",\n                    [\n                        \"bank\",\n                        \"parking\",\n                        \"parking-garage\"\n                    ],\n                    \"poi_generic_purple\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\"\n                    ],\n                    \"poi_generic_orange\",\n                    [\n                        \"alcohol-shop\",\n                        \"shop\",\n                        \"shoe\",\n                        \"convenience\",\n                        \"clothing-store\",\n                        \"jewelry-store\"\n                    ],\n                    \"poi_generic_blue\",\n                    [\n                        \"casino\",\n                        \"castle\",\n                        \"art-gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music\",\n                        \"monument\"\n                    ],\n                    \"poi_generic_teal\",\n                    [\n                        \"hospital\",\n                        \"doctor\"\n                    ],\n                    \"poi_generic_red\",\n                    [\n                        \"restaurant-pizza\",\n                        \"restaurant-seafood\",\n                        \"restaurant-noodle\",\n                        \"fast-food\",\n                        \"ice-cream\"\n                    ],\n                    \"poi_restaurant\",\n                    \"poi_generic\"\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-justify\": \"right\",\n                \"text-offset\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    [\n                        \"literal\",\n                        [\n                            -1.1,\n                            -0.7\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            -1.1,\n                            -0.9\n                        ]\n                    ]\n                ],\n                \"icon-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.25,\n                    15,\n                    0.32\n                ],\n                \"text-anchor\": \"right\",\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maki\"\n                    ],\n                    [\n                        \"museum\",\n                        \"casino\",\n                        \"castle\",\n                        \"theatre\",\n                        \"art-gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music\",\n                        \"monument\"\n                    ],\n                    \"hsl(186, 78%, 44%)\",\n                    [\n                        \"lodging\"\n                    ],\n                    \"#df7db1\",\n                    [\n                        \"fitness-centre\",\n                        \"golf\",\n                        \"campsite\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic-site\",\n                        \"zoo\",\n                        \"dog-park\",\n                        \"stadium\",\n                        \"bowling-alley\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"hsl(117, 53%, 31%)\",\n                    [\n                        \"restaurant-pizza\",\n                        \"restaurant-seafood\",\n                        \"restaurant\",\n                        \"restaurant-noodle\",\n                        \"bar\",\n                        \"cafe\",\n                        \"fast-food\",\n                        \"bakery\",\n                        \"ice-cream\"\n                    ],\n                    \"#c77d57\",\n                    [\n                        \"shop\",\n                        \"shoe\",\n                        \"alcohol-shop\",\n                        \"convenience\",\n                        \"grocery\",\n                        \"clothing-store\",\n                        \"jewelry-store\"\n                    ],\n                    \"hsl(213, 40%, 48%)\",\n                    [\n                        \"bank\",\n                        \"parking\",\n                        \"parking-garage\"\n                    ],\n                    \"#737b9b\",\n                    [\n                        \"hospital\",\n                        \"doctor\"\n                    ],\n                    \"#a47172\",\n                    \"#67747b\"\n                ],\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1,\n                \"icon-translate\": [\n                    0,\n                    0\n                ],\n                \"text-translate\": [\n                    0,\n                    0\n                ],\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"poi_label_right\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"124a9d7a8e5226775d947c592110dfad\",\n                \"microg:gms-type-element\": \"labels.text\",\n                \"microg:gms-type-feature\": \"poi\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"poi_label\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    [\n                        \"/\",\n                        [\n                            \"zoom\"\n                        ],\n                        3.5\n                    ]\n                ],\n                [\n                    \"!\",\n                    [\n                        \"all\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"maki\"\n                            ],\n                            [\n                                \"park\",\n                                \"cemetery\"\n                            ],\n                            true,\n                            false\n                        ],\n                        [\n                            \"<=\",\n                            [\n                                \"get\",\n                                \"sizerank\"\n                            ],\n                            10\n                        ]\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-line-height\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    15,\n                    1.2\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    13,\n                    15,\n                    14\n                ],\n                \"icon-offset\": [\n                    0,\n                    -36\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maki\"\n                    ],\n                    [\n                        \"museum\",\n                        \"lodging\",\n                        \"theatre\",\n                        \"grocery\",\n                        \"restaurant\"\n                    ],\n                    [\n                        \"concat\",\n                        \"poi_\",\n                        [\n                            \"get\",\n                            \"maki\"\n                        ]\n                    ],\n                    [\n                        \"fitness-centre\",\n                        \"golf\",\n                        \"campsite\",\n                        \"bowling-alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic-site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog-park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"poi_generic_green\",\n                    [\n                        \"bank\",\n                        \"parking\",\n                        \"parking-garage\"\n                    ],\n                    \"poi_generic_purple\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\"\n                    ],\n                    \"poi_generic_orange\",\n                    [\n                        \"alcohol-shop\",\n                        \"shop\",\n                        \"shoe\",\n                        \"convenience\",\n                        \"clothing-store\",\n                        \"jewelry-store\"\n                    ],\n                    \"poi_generic_blue\",\n                    [\n                        \"casino\",\n                        \"castle\",\n                        \"art-gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music\",\n                        \"monument\"\n                    ],\n                    \"poi_generic_teal\",\n                    [\n                        \"hospital\",\n                        \"doctor\"\n                    ],\n                    \"poi_generic_red\",\n                    [\n                        \"restaurant-pizza\",\n                        \"restaurant-seafood\",\n                        \"restaurant-noodle\",\n                        \"fast-food\",\n                        \"ice-cream\"\n                    ],\n                    \"poi_restaurant\",\n                    \"poi_generic\"\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-justify\": \"left\",\n                \"text-offset\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    [\n                        \"literal\",\n                        [\n                            1.1,\n                            -0.7\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            1.1,\n                            -0.9\n                        ]\n                    ]\n                ],\n                \"icon-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.25,\n                    15,\n                    0.32\n                ],\n                \"text-anchor\": \"left\",\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maki\"\n                    ],\n                    [\n                        \"museum\",\n                        \"casino\",\n                        \"castle\",\n                        \"theatre\",\n                        \"art-gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music\",\n                        \"monument\"\n                    ],\n                    \"hsl(186, 78%, 44%)\",\n                    [\n                        \"lodging\"\n                    ],\n                    \"#df7db1\",\n                    [\n                        \"fitness-centre\",\n                        \"golf\",\n                        \"campsite\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic-site\",\n                        \"zoo\",\n                        \"dog-park\",\n                        \"stadium\",\n                        \"bowling-alley\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"hsl(117, 53%, 31%)\",\n                    [\n                        \"restaurant-pizza\",\n                        \"restaurant-seafood\",\n                        \"restaurant\",\n                        \"restaurant-noodle\",\n                        \"bar\",\n                        \"cafe\",\n                        \"fast-food\",\n                        \"bakery\",\n                        \"ice-cream\"\n                    ],\n                    \"#c77d57\",\n                    [\n                        \"shop\",\n                        \"shoe\",\n                        \"alcohol-shop\",\n                        \"convenience\",\n                        \"grocery\",\n                        \"clothing-store\",\n                        \"jewelry-store\"\n                    ],\n                    \"hsl(213, 40%, 48%)\",\n                    [\n                        \"bank\",\n                        \"parking\",\n                        \"parking-garage\"\n                    ],\n                    \"#737b9b\",\n                    [\n                        \"hospital\",\n                        \"doctor\"\n                    ],\n                    \"#a47172\",\n                    \"#67747b\"\n                ],\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1,\n                \"icon-translate\": [\n                    0,\n                    0\n                ],\n                \"text-translate\": [\n                    0,\n                    0\n                ],\n                \"text-halo-blur\": 1\n            }\n        }\n    ],\n    \"created\": \"2019-04-15T08:41:40.148Z\",\n    \"modified\": \"2020-09-05T19:42:03.856Z\",\n    \"id\": \"cjui4020201oo1fmca7yuwbor\",\n    \"owner\": \"microg\",\n    \"visibility\": \"public\",\n    \"protected\": false,\n    \"draft\": false\n}\n"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/style-microg-normal-stadia.json",
    "content": "{\n    \"version\": 8,\n    \"name\": \"Mountain View Full\",\n    \"metadata\": {\n        \"mapbox:origin\": \"basic-template\",\n        \"mapbox:autocomposite\": true,\n        \"mapbox:type\": \"template\",\n        \"mapbox:sdk-support\": {\n            \"js\": \"0.50.0\",\n            \"android\": \"6.7.0\",\n            \"ios\": \"4.6.0\"\n        },\n        \"mapbox:trackposition\": false,\n        \"mapbox:groups\": {\n            \"f51b507d2a17e572c70a5db74b0fec7e\": {\n                \"name\": \"Base\",\n                \"collapsed\": false\n            },\n            \"3f48b8dc54ff2e6544b9ef9cedbf2990\": {\n                \"name\": \"Streets\",\n                \"collapsed\": true\n            },\n            \"29bb589e8d1b9b402583363648b70302\": {\n                \"name\": \"Buildings\",\n                \"collapsed\": true\n            },\n            \"3c26e9cbc75335c6f0ba8de5439cf1fa\": {\n                \"name\": \"Country borders\",\n                \"collapsed\": true\n            },\n            \"7b44201d7f1682d99f7140188aff23ce\": {\n                \"name\": \"Labels\",\n                \"collapsed\": true\n            },\n            \"24306bdccbff03e2ee08d5d1a4ca7312\": {\n                \"name\": \"Street name\",\n                \"collapsed\": true\n            },\n            \"124a9d7a8e5226775d947c592110dfad\": {\n                \"name\": \"POI\",\n                \"collapsed\": true\n            }\n        },\n        \"mapbox:uiParadigm\": \"layers\",\n        \"maputnik:renderer\": \"mbgljs\"\n    },\n    \"center\": [\n        12.819420849458652,\n        50.03325860617235\n    ],\n    \"zoom\": 3.315829104862067,\n    \"bearing\": 0,\n    \"pitch\": 1.5,\n    \"light\": {\n        \"intensity\": 0.5,\n        \"color\": \"hsl(0, 0%, 100%)\",\n        \"anchor\": \"viewport\"\n    },\n    \"sources\": {\n        \"openmaptiles\": {\n            \"type\": \"vector\",\n            \"url\": \"https://tiles.stadiamaps.com/data/openmaptiles.json\"\n        },\n        \"terrain\": {\n            \"type\": \"raster-dem\",\n            \"tiles\": [\n                \"https://tiles.stadiamaps.com/data/terrarium/{z}/{x}/{y}.png\"\n            ],\n            \"minzoom\": 0,\n            \"maxzoom\": 12,\n            \"tileSize\": 256,\n            \"encoding\": \"terrarium\"\n        },\n        \"global\": {\n            \"type\": \"vector\",\n            \"tiles\": [\n                \"https://tiles.stadiamaps.com/data/global_landcover_v1/{z}/{x}/{y}.pbf\"\n            ],\n            \"minzoom\": 0,\n            \"maxzoom\": 6\n        }\n    },\n    \"sprite\": \"asset://sprites\",\n    \"glyphs\": \"asset://{fontstack}/{range}.pbf\",\n    \"layers\": [\n        {\n            \"id\": \"background\",\n            \"type\": \"background\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"background-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    4,\n                    \"hsl(43, 30%, 91%)\",\n                    5,\n                    \"hsl(0, 0%, 96%)\",\n                    8,\n                    \"hsl(0, 0%, 96%)\",\n                    9,\n                    \"#efeee8\",\n                    16,\n                    \"hsl(0, 0%, 95%)\",\n                    18,\n                    \"#f8f9fb\"\n                ]\n            }\n        },\n        {\n            \"id\": \"global_grass\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\",\n                \"maputnik:comment\": \"Stadia specific\"\n            },\n            \"source\": \"global\",\n            \"source-layer\": \"global_landcover\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"grass\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    \"hsl(124, 30%, 90%)\",\n                    11,\n                    \"hsl(107, 30%, 94%)\",\n                    12.5,\n                    \"hsl(107, 30%, 94%)\",\n                    13.5,\n                    \"hsl(45, 12%, 93%)\"\n                ]\n            }\n        },\n        {\n            \"id\": \"grass\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"landcover\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"grass\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    \"hsl(124, 30%, 90%)\",\n                    11,\n                    \"hsl(107, 30%, 94%)\",\n                    12.5,\n                    \"hsl(107, 30%, 94%)\",\n                    13.5,\n                    \"hsl(45, 12%, 93%)\"\n                ]\n            }\n        },\n        {\n            \"id\": \"global_forest\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\",\n                \"maputnik:comment\": \"Stadia specific\"\n            },\n            \"source\": \"global\",\n            \"source-layer\": \"global_landcover\",\n            \"filter\": [\n                \"==\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                \"wood\"\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    \"hsl(124, 42%, 86%)\",\n                    11,\n                    \"hsl(107, 47%, 94%)\",\n                    12.5,\n                    \"hsl(107, 47%, 94%)\",\n                    13.5,\n                    \"hsl(45, 12%, 93%)\"\n                ]\n            }\n        },\n        {\n            \"id\": \"forrest\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"landcover\",\n            \"filter\": [\n                \"==\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                \"wood\"\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    \"hsl(124, 42%, 86%)\",\n                    11,\n                    \"hsl(107, 47%, 94%)\",\n                    12.5,\n                    \"hsl(107, 47%, 94%)\",\n                    13.5,\n                    \"hsl(45, 12%, 93%)\"\n                ]\n            }\n        },\n        {\n            \"id\": \"national_park\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"park\",\n            \"filter\": [\n                \"all\"\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": \"hsl(106, 58%, 85%)\",\n                \"fill-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    1,\n                    11.5,\n                    0\n                ]\n            }\n        },\n        {\n            \"id\": \"global_snow\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"global\",\n            \"source-layer\": \"global_landcover\",\n            \"minzoom\": 0,\n            \"maxzoom\": 6,\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"ice\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": \"#f9fafc\"\n            }\n        },\n        {\n            \"id\": \"snow\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"landcover\",\n            \"minzoom\": 6,\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"ice\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": \"#f9fafc\"\n            }\n        },\n        {\n            \"id\": \"hillshade\",\n            \"type\": \"hillshade\",\n            \"source\": \"terrain\",\n            \"maxzoom\": 12,\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"hillshade-illumination-anchor\": \"viewport\",\n                \"hillshade-exaggeration\": 0.1\n            },\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.natural.terrain\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"park\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"poi.park\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"landcover\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"subclass\"\n                ],\n                [\n                    \"scrub\",\n                    \"park\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": \"#c1ecaf\"\n            }\n        },\n        {\n            \"id\": \"pitch\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"landscape.natural.terrain\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"landuse\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"pitch\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": \"#c8efbb\"\n            }\n        },\n        {\n            \"id\": \"landuse\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"f51b507d2a17e572c70a5db74b0fec7e\",\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"landuse\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"school\",\n                    \"hospital\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": \"hsl(202, 26%, 94%)\"\n            }\n        },\n        {\n            \"id\": \"airport\",\n            \"type\": \"fill\",\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"aeroway\",\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": \"hsl(202, 26%, 94%)\"\n            },\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"transit.station.airport\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"path\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\",\n                \"maputnik:comment\": \"unpaved paths\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"minzoom\": 14,\n            \"maxzoom\": 24,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"path\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsl(118, 34%, 66%)\",\n                \"line-dasharray\": [\n                    4,\n                    2\n                ]\n            }\n        },\n        {\n            \"id\": \"waterway-other\",\n            \"type\": \"line\",\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"waterway\",\n            \"filter\": [\n                \"!in\",\n                \"class\",\n                \"canal\",\n                \"river\",\n                \"stream\"\n            ],\n            \"layout\": {\n                \"line-cap\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"hsl(206, 100%, 83%)\",\n                \"line-width\": {\n                    \"base\": 1.3,\n                    \"stops\": [\n                        [\n                            13,\n                            0.5\n                        ],\n                        [\n                            20,\n                            2\n                        ]\n                    ]\n                }\n            },\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"waterway-stream-canal\",\n            \"type\": \"line\",\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"waterway\",\n            \"filter\": [\n                \"in\",\n                \"class\",\n                \"canal\",\n                \"stream\"\n            ],\n            \"layout\": {\n                \"line-cap\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"hsl(206, 100%, 83%)\",\n                \"line-width\": {\n                    \"base\": 1.3,\n                    \"stops\": [\n                        [\n                            13,\n                            0.5\n                        ],\n                        [\n                            20,\n                            6\n                        ]\n                    ]\n                }\n            },\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"waterway-river\",\n            \"type\": \"line\",\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"waterway\",\n            \"filter\": [\n                \"==\",\n                \"class\",\n                \"river\"\n            ],\n            \"layout\": {\n                \"line-cap\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"hsl(206, 100%, 83%)\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            10,\n                            0.8\n                        ],\n                        [\n                            20,\n                            6\n                        ]\n                    ]\n                }\n            },\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"water-offset\",\n            \"type\": \"fill\",\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"water\",\n            \"minzoom\": 6,\n            \"maxzoom\": 8,\n            \"filter\": [\n                \"==\",\n                \"$type\",\n                \"Polygon\"\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": \"hsl(206, 100%, 83%)\",\n                \"fill-opacity\": 1,\n                \"fill-translate\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            6,\n                            [\n                                2,\n                                0\n                            ]\n                        ],\n                        [\n                            8,\n                            [\n                                0,\n                                0\n                            ]\n                        ]\n                    ]\n                }\n            },\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"water\",\n            \"type\": \"fill\",\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"water\",\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": \"hsl(206, 100%, 83%)\"\n            },\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"steps\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"subclass\"\n                ],\n                [\n                    \"steps\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsl(118, 5%, 66%)\",\n                \"line-dasharray\": [\n                    1,\n                    1\n                ],\n                \"line-gap-width\": 1\n            }\n        },\n        {\n            \"id\": \"platform\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"transit.station.rail\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"platform\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"brunnel\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    false,\n                    true\n                ]\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    \"hsl(2, 20%, 92%)\",\n                    16,\n                    \"hsl(2, 95%, 92%)\"\n                ],\n                \"fill-outline-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    \"hsl(1, 10%, 76%)\",\n                    16,\n                    \"hsl(1, 74%, 76%)\"\n                ],\n                \"fill-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0,\n                    16,\n                    1\n                ]\n            }\n        },\n        {\n            \"id\": \"primary_tunnel_border\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"brun\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    7,\n                    0,\n                    8,\n                    1,\n                    12,\n                    4,\n                    14,\n                    6,\n                    16,\n                    10,\n                    22,\n                    64\n                ],\n                \"line-color\": \"#cbcccd\"\n            }\n        },\n        {\n            \"id\": \"primary_tunnel\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"brunnel\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    1,\n                    12,\n                    4,\n                    14,\n                    6,\n                    16,\n                    10,\n                    22,\n                    64\n                ],\n                \"line-color\": \"hsl(0, 0%, 89%)\"\n            }\n        },\n        {\n            \"id\": \"aeroway\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"transit.station.airport\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"aeroway\",\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"line-color\": \"hsla(0, 0%, 0%, 0.1)\"\n            }\n        },\n        {\n            \"id\": \"service_road\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"service\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsla(0, 0%, 0%, 0.1)\"\n            }\n        },\n        {\n            \"id\": \"pedestrian_border\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"pedestrian\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"surface\"\n                    ],\n                    \"paved\"\n                ]\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    13,\n                    1,\n                    16,\n                    4,\n                    22,\n                    32\n                ],\n                \"line-color\": \"#e3e3e3\",\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12.5,\n                    0,\n                    13.5,\n                    1\n                ]\n            }\n        },\n        {\n            \"id\": \"street_border\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"minor\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    1,\n                    16,\n                    6,\n                    22,\n                    40\n                ],\n                \"line-color\": \"#e3e3e3\"\n            }\n        },\n        {\n            \"id\": \"secondary_border\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\",\n                \"maputnik:comment\": \"ok\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"secondary\",\n                    \"tertiary\",\n                    \"trunk\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    10,\n                    1,\n                    17,\n                    10,\n                    22,\n                    48\n                ],\n                \"line-color\": \"#e3e3e3\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    16,\n                    1,\n                    20,\n                    2\n                ]\n            }\n        },\n        {\n            \"id\": \"primary_border\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"brunnel\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    false,\n                    true\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": \"round\"\n            },\n            \"paint\": {\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    1,\n                    16,\n                    8,\n                    22,\n                    64\n                ],\n                \"line-color\": \"#ecd283\"\n            }\n        },\n        {\n            \"id\": \"motorway_border\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"motorway\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    1,\n                    15.5,\n                    8,\n                    22,\n                    78\n                ],\n                \"line-color\": \"#ecd283\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    1,\n                    15,\n                    2\n                ]\n            }\n        },\n        {\n            \"id\": \"railway\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"any\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"rail\"\n                        ],\n                        true,\n                        false\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"subclass\"\n                        ],\n                        [\n                            \"light_rail\",\n                            \"tram\"\n                        ],\n                        true,\n                        false\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"brunnel\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    false,\n                    true\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsl(220, 4%, 85%)\"\n            }\n        },\n        {\n            \"id\": \"pedestrian\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"pedestrian\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"surface\"\n                    ],\n                    \"paved\"\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"#ffffff\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    13,\n                    1,\n                    16,\n                    4,\n                    22,\n                    32\n                ],\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12.5,\n                    0,\n                    13.5,\n                    1\n                ]\n            }\n        },\n        {\n            \"id\": \"street\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"minor\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"#ffffff\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    1,\n                    16,\n                    6,\n                    22,\n                    40\n                ]\n            }\n        },\n        {\n            \"id\": \"secondary\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"secondary\",\n                    \"tertiary\",\n                    \"trunk\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"#ffffff\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    10,\n                    1,\n                    17,\n                    10,\n                    22,\n                    48\n                ]\n            }\n        },\n        {\n            \"id\": \"primary\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"brunnel\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    false,\n                    true\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"hsl(50, 100%, 75%)\",\n                    7,\n                    \"hsl(50, 100%, 85%)\"\n                ],\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    1,\n                    16,\n                    8,\n                    22,\n                    64\n                ]\n            }\n        },\n        {\n            \"id\": \"motorway\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"motorway\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"#ffeba3\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    1,\n                    15.5,\n                    8,\n                    22,\n                    78\n                ]\n            }\n        },\n        {\n            \"id\": \"primary_bridge_border\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"brunnel\"\n                    ],\n                    [\n                        \"bridge\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-gap-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    1,\n                    16,\n                    8,\n                    22,\n                    64\n                ],\n                \"line-color\": \"hsl(45, 73%, 72%)\"\n            }\n        },\n        {\n            \"id\": \"primary_bridge\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"brunnel\"\n                    ],\n                    [\n                        \"bridge\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"hsl(50, 100%, 75%)\",\n                    7,\n                    \"hsl(50, 100%, 85%)\"\n                ],\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    1,\n                    16,\n                    8,\n                    22,\n                    64\n                ]\n            }\n        },\n        {\n            \"id\": \"building\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"29bb589e8d1b9b402583363648b70302\",\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"building\",\n            \"filter\": [\n                \"all\"\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": \"#ededed\",\n                \"fill-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    0,\n                    17,\n                    1\n                ]\n            }\n        },\n        {\n            \"id\": \"building_border\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"29bb589e8d1b9b402583363648b70302\",\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"geometry.stroke\",\n                \"maputnik:comment\": \"#f8e1c7 for store, retail, church, kiosk, civic, commercial, hotel, supermarket, pub could not be ported (no appropriate metadata in `building` style spec)\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"building\",\n            \"filter\": [\n                \"all\"\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    [\n                        \"store\",\n                        \"retail\",\n                        \"church\",\n                        \"kiosk\",\n                        \"civic\",\n                        \"commercial\",\n                        \"hotel\",\n                        \"supermarket\",\n                        \"pub\"\n                    ],\n                    \"#f8e1c7\",\n                    \"#dcdcdc\"\n                ],\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    0,\n                    17,\n                    1\n                ]\n            }\n        },\n        {\n            \"id\": \"building_3d\",\n            \"type\": \"fill-extrusion\",\n            \"metadata\": {\n                \"mapbox:group\": \"29bb589e8d1b9b402583363648b70302\",\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"building\",\n            \"filter\": [\n                \"!=\",\n                [\n                    \"get\",\n                    \"hide_3d\"\n                ],\n                true\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"fill-extrusion-height\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    0,\n                    16,\n                    [\n                        \"get\",\n                        \"render_height\"\n                    ]\n                ],\n                \"fill-extrusion-opacity\": 0.3,\n                \"fill-extrusion-color\": \"hsl(0, 0%, 93%)\"\n            }\n        },\n        {\n            \"id\": \"admin_0\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3c26e9cbc75335c6f0ba8de5439cf1fa\",\n                \"microg:gms-type-feature\": \"administrative.country\",\n                \"microg:gms-type-element\": \"geometry.stroke\",\n                \"maputnik:comment\": \"maritime=false filter could not be ported due to missing attributes in `boundary` layer\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"boundary\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"admin_level\"\n                    ],\n                    [\n                        2\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"!=\",\n                    [\n                        \"get\",\n                        \"maritime\"\n                    ],\n                    1\n                ]\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"line-color\": [\n                    \"case\",\n                    [\n                        \"==\",\n                        [\n                            \"get\",\n                            \"disputed\"\n                        ],\n                        1\n                    ],\n                    \"hsl(0, 24%, 48%)\",\n                    \"#787a7b\"\n                ]\n            }\n        },\n        {\n            \"id\": \"admin_1\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3c26e9cbc75335c6f0ba8de5439cf1fa\",\n                \"microg:gms-type-feature\": \"administrative.province\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"boundary\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"admin_level\"\n                    ],\n                    [\n                        3,\n                        4\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"!=\",\n                    [\n                        \"get\",\n                        \"maritime\"\n                    ],\n                    1\n                ]\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"line-color\": [\n                    \"case\",\n                    [\n                        \"==\",\n                        [\n                            \"get\",\n                            \"disputed\"\n                        ],\n                        1\n                    ],\n                    \"hsl(0, 24%, 48%)\",\n                    \"#787a7b\"\n                ],\n                \"line-dasharray\": [\n                    1,\n                    1\n                ]\n            }\n        },\n        {\n            \"id\": \"river_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"waterway\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"river\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"symbol-placement\": \"line\",\n                \"symbol-spacing\": 500,\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ]\n            },\n            \"paint\": {\n                \"text-color\": \"#5083c1\",\n                \"text-halo-color\": \"#5083c1\",\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"city_label_right\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"maxzoom\": 8,\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    [\n                        \"*\",\n                        [\n                            \"zoom\"\n                        ],\n                        1.5\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"city\",\n                        \"town\",\n                        \"village\",\n                        \"hamlet\",\n                        \"suburb\",\n                        \"quarter\",\n                        \"neighbourhood\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-optional\": false,\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"-\",\n                        14,\n                        [\n                            \"max\",\n                            0,\n                            [\n                                \"-\",\n                                [\n                                    \"get\",\n                                    \"rank\"\n                                ],\n                                8\n                            ]\n                        ]\n                    ],\n                    22,\n                    [\n                        \"-\",\n                        20,\n                        [\n                            \"/\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            4\n                        ]\n                    ]\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"capital\"\n                    ],\n                    [\n                        2\n                    ],\n                    \"capital\",\n                    \"city\"\n                ],\n                \"text-font\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\"\n                        ]\n                    ],\n                    10,\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Regular\"\n                        ]\n                    ]\n                ],\n                \"text-justify\": \"left\",\n                \"text-offset\": [\n                    0.5,\n                    0.1\n                ],\n                \"icon-size\": [\n                    \"/\",\n                    6,\n                    [\n                        \"+\",\n                        [\n                            \"get\",\n                            \"rank\"\n                        ],\n                        7\n                    ]\n                ],\n                \"text-anchor\": \"left\",\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"*\",\n                                [\n                                    \"get\",\n                                    \"rank\"\n                                ],\n                                2\n                            ],\n                            5\n                        ],\n                        \"%)\"\n                    ],\n                    22,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            25\n                        ],\n                        \"%)\"\n                    ]\n                ],\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"text-halo-color\": \"hsl(0, 0%, 100%)\",\n                \"icon-opacity\": 0.8\n            }\n        },\n        {\n            \"id\": \"city_label_left\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"maxzoom\": 8,\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    [\n                        \"*\",\n                        [\n                            \"zoom\"\n                        ],\n                        1.5\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"city\",\n                        \"town\",\n                        \"village\",\n                        \"hamlet\",\n                        \"suburb\",\n                        \"quarter\",\n                        \"neighbourhood\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"-\",\n                        14,\n                        [\n                            \"max\",\n                            0,\n                            [\n                                \"-\",\n                                [\n                                    \"get\",\n                                    \"rank\"\n                                ],\n                                8\n                            ]\n                        ]\n                    ],\n                    22,\n                    [\n                        \"-\",\n                        20,\n                        [\n                            \"/\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            4\n                        ]\n                    ]\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"capital\"\n                    ],\n                    [\n                        2\n                    ],\n                    \"capital\",\n                    \"city\"\n                ],\n                \"text-font\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\"\n                        ]\n                    ],\n                    10,\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Regular\"\n                        ]\n                    ]\n                ],\n                \"text-justify\": \"right\",\n                \"text-offset\": [\n                    -0.5,\n                    0.1\n                ],\n                \"icon-size\": [\n                    \"/\",\n                    6,\n                    [\n                        \"+\",\n                        [\n                            \"get\",\n                            \"rank\"\n                        ],\n                        7\n                    ]\n                ],\n                \"text-anchor\": \"right\",\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"*\",\n                                [\n                                    \"get\",\n                                    \"rank\"\n                                ],\n                                2\n                            ],\n                            5\n                        ],\n                        \"%)\"\n                    ],\n                    22,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            25\n                        ],\n                        \"%)\"\n                    ]\n                ],\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"text-halo-color\": \"hsl(0, 0%, 100%)\",\n                \"icon-opacity\": 0.8\n            }\n        },\n        {\n            \"id\": \"city_label_below\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"maxzoom\": 8,\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    [\n                        \"/\",\n                        [\n                            \"zoom\"\n                        ],\n                        3\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"city\",\n                        \"town\",\n                        \"village\",\n                        \"hamlet\",\n                        \"suburb\",\n                        \"quarter\",\n                        \"neighbourhood\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"-\",\n                        14,\n                        [\n                            \"max\",\n                            0,\n                            [\n                                \"-\",\n                                [\n                                    \"get\",\n                                    \"rank\"\n                                ],\n                                8\n                            ]\n                        ]\n                    ],\n                    22,\n                    [\n                        \"-\",\n                        20,\n                        [\n                            \"/\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            4\n                        ]\n                    ]\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"capital\"\n                    ],\n                    [\n                        2\n                    ],\n                    \"capital\",\n                    \"city\"\n                ],\n                \"text-font\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\"\n                        ]\n                    ],\n                    10,\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Regular\"\n                        ]\n                    ]\n                ],\n                \"text-offset\": [\n                    0,\n                    0.4\n                ],\n                \"icon-size\": [\n                    \"/\",\n                    6,\n                    [\n                        \"+\",\n                        [\n                            \"get\",\n                            \"rank\"\n                        ],\n                        7\n                    ]\n                ],\n                \"text-anchor\": \"top\",\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"*\",\n                                [\n                                    \"get\",\n                                    \"rank\"\n                                ],\n                                2\n                            ],\n                            5\n                        ],\n                        \"%)\"\n                    ],\n                    22,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            25\n                        ],\n                        \"%)\"\n                    ]\n                ],\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"text-halo-color\": \"hsl(0, 0%, 100%)\",\n                \"icon-opacity\": 0.8\n            }\n        },\n        {\n            \"id\": \"city_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    [\n                        \"*\",\n                        [\n                            \"zoom\"\n                        ],\n                        1.5\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"city\",\n                        \"town\",\n                        \"village\",\n                        \"hamlet\",\n                        \"suburb\",\n                        \"quarter\",\n                        \"neighbourhood\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"-\",\n                        14,\n                        [\n                            \"max\",\n                            0,\n                            [\n                                \"-\",\n                                [\n                                    \"get\",\n                                    \"rank\"\n                                ],\n                                8\n                            ]\n                        ]\n                    ],\n                    22,\n                    [\n                        \"-\",\n                        20,\n                        [\n                            \"/\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            4\n                        ]\n                    ]\n                ],\n                \"icon-image\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"capital\"\n                        ],\n                        [\n                            2\n                        ],\n                        \"capital\",\n                        \"city\"\n                    ],\n                    8,\n                    \"\"\n                ],\n                \"text-transform\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    \"none\",\n                    15,\n                    \"uppercase\"\n                ],\n                \"text-font\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\"\n                        ]\n                    ],\n                    10,\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Regular\"\n                        ]\n                    ]\n                ],\n                \"text-offset\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            0,\n                            -0.2\n                        ]\n                    ],\n                    8,\n                    [\n                        \"literal\",\n                        [\n                            0,\n                            0\n                        ]\n                    ]\n                ],\n                \"icon-size\": [\n                    \"/\",\n                    6,\n                    [\n                        \"+\",\n                        [\n                            \"get\",\n                            \"rank\"\n                        ],\n                        7\n                    ]\n                ],\n                \"text-anchor\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"bottom\",\n                    8,\n                    \"center\"\n                ],\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-letter-spacing\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    0,\n                    0,\n                    8,\n                    0,\n                    12,\n                    0.1,\n                    16,\n                    0.2\n                ],\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"*\",\n                                [\n                                    \"get\",\n                                    \"rank\"\n                                ],\n                                2\n                            ],\n                            5\n                        ],\n                        \"%)\"\n                    ],\n                    22,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            25\n                        ],\n                        \"%)\"\n                    ]\n                ],\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"text-halo-color\": \"hsl(0, 0%, 100%)\",\n                \"icon-opacity\": 0.8\n            }\n        },\n        {\n            \"id\": \"park_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"poi.park\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"poi\",\n            \"minzoom\": 17,\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"park\",\n                        \"cemetery\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    250\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-size\": 14\n            },\n            \"paint\": {\n                \"text-color\": \"#297925\",\n                \"text-halo-color\": \"hsl(0, 0%, 100%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"road-number-shield\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road\",\n                \"microg:gms-type-element\": \"labels.icon\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation_name\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"ref\"\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"ref_length\"\n                    ],\n                    6\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": 9,\n                \"icon-image\": [\n                    \"case\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"network\"\n                        ],\n                        [\n                            \"us-interstate\"\n                        ],\n                        true,\n                        false\n                    ],\n                    [\n                        \"concat\",\n                        \"shield_\",\n                        [\n                            \"get\",\n                            \"network\"\n                        ],\n                        \"_\",\n                        [\n                            \"get\",\n                            \"ref_length\"\n                        ]\n                    ],\n                    [\n                        \"concat\",\n                        \"shield_rectangle-white_\",\n                        [\n                            \"get\",\n                            \"ref_length\"\n                        ]\n                    ]\n                ],\n                \"icon-rotation-alignment\": \"viewport\",\n                \"text-font\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"shield_text_color\"\n                    ],\n                    [\n                        \"white\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Bold\"\n                        ]\n                    ],\n                    [\n                        \"black\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\"\n                        ]\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Bold\"\n                        ]\n                    ]\n                ],\n                \"symbol-placement\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"point\",\n                    11,\n                    \"line\"\n                ],\n                \"text-offset\": [\n                    0,\n                    0.1\n                ],\n                \"text-rotation-alignment\": \"viewport\",\n                \"icon-size\": 0.75,\n                \"text-field\": [\n                    \"get\",\n                    \"ref\"\n                ],\n                \"text-letter-spacing\": 0.05,\n                \"visibility\": \"visible\",\n                \"icon-padding\": 10\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"case\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"network\"\n                        ],\n                        [\n                            \"us-interstate\"\n                        ],\n                        true,\n                        false\n                    ],\n                    \"#ffffff\",\n                    \"#000000\"\n                ]\n            }\n        },\n        {\n            \"id\": \"country_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"administrative.country\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"country\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {\n                \"text-letter-spacing\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    1,\n                    0,\n                    3,\n                    0.15\n                ],\n                \"text-font\": [\n                    \"Roboto Medium\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.2\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    1,\n                    12,\n                    7,\n                    [\n                        \"/\",\n                        30,\n                        [\n                            \"get\",\n                            \"rank\"\n                        ]\n                    ]\n                ],\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(0, 0%, 10%)\",\n                \"text-halo-color\": \"hsl(0, 0%, 100%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"text-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    6,\n                    1,\n                    7,\n                    0\n                ]\n            }\n        },\n        {\n            \"id\": \"pedestrian_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation_name\",\n            \"minzoom\": 16,\n            \"filter\": [\n                \"any\",\n                [\n                    \"all\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"subclass\"\n                        ],\n                        [\n                            \"pedestrian\"\n                        ],\n                        true,\n                        false\n                    ],\n                    [\n                        \"==\",\n                        [\n                            \"get\",\n                            \"surface\"\n                        ],\n                        \"paved\"\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    \"platform\",\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"name\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    17,\n                    10,\n                    22,\n                    14\n                ],\n                \"text-padding\": 5\n            },\n            \"paint\": {\n                \"text-color\": \"#575757\",\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"street_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation_name\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"minor\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"name\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    6,\n                    16,\n                    10\n                ],\n                \"text-padding\": 5\n            },\n            \"paint\": {\n                \"text-color\": \"#575757\",\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"secondary_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation_name\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"secondary\",\n                        \"tertiary\",\n                        \"trunk\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"name\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    8,\n                    16,\n                    13\n                ],\n                \"symbol-spacing\": 300,\n                \"text-padding\": 25\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(196, 0%, 34%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"primary_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation_name\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"name\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    10,\n                    18,\n                    14\n                ],\n                \"symbol-spacing\": 800,\n                \"text-padding\": 50\n            },\n            \"paint\": {\n                \"text-color\": \"#6e481d\",\n                \"text-halo-width\": 1,\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"poi_label_below\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"124a9d7a8e5226775d947c592110dfad\",\n                \"microg:gms-type-element\": \"labels.text\",\n                \"microg:gms-type-feature\": \"poi\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"poi\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"bus\",\n                        \"railway\"\n                    ],\n                    false,\n                    true\n                ],\n                [\n                    \"any\",\n                    [\n                        \"!=\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ],\n                            [\n                                \"park\",\n                                \"cemetery\"\n                            ],\n                            true,\n                            false\n                        ],\n                        [\n                            \"<=\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            250\n                        ]\n                    ],\n                    [\n                        \">=\",\n                        [\n                            \"zoom\"\n                        ],\n                        16\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-optional\": false,\n                \"text-line-height\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    15,\n                    1.2\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    13,\n                    15,\n                    14\n                ],\n                \"icon-offset\": [\n                    0,\n                    -36\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"museum\",\n                        \"theatre\",\n                        \"restaurant\"\n                    ],\n                    [\n                        \"concat\",\n                        \"poi_\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ]\n                    ],\n                    [\n                        \"fitness_centre\",\n                        \"golf_course\",\n                        \"camp_site\",\n                        \"bowling_alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic_site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog_park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"poi_generic_green\",\n                    [\n                        \"bank\",\n                        \"atm\",\n                        \"parking\",\n                        \"toilets\",\n                        \"garages\"\n                    ],\n                    \"poi_generic_purple\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\"\n                    ],\n                    \"poi_generic_orange\",\n                    [\n                        \"casino\",\n                        \"castle\",\n                        \"gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music_venue\",\n                        \"monument\"\n                    ],\n                    \"poi_generic_teal\",\n                    [\n                        \"hospital\",\n                        \"doctors\"\n                    ],\n                    \"poi_generic_red\",\n                    [\n                        \"fast_food\",\n                        \"ice_cream\"\n                    ],\n                    \"poi_restaurant\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"lodging\",\n                            \"grocery\"\n                        ],\n                        [\n                            \"concat\",\n                            \"poi_\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ]\n                        ],\n                        [\n                            \"clothing_store\",\n                            \"shop\"\n                        ],\n                        \"poi_generic_blue\",\n                        \"poi_generic\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-offset\": [\n                    0,\n                    0.5\n                ],\n                \"icon-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.25,\n                    15,\n                    0.32\n                ],\n                \"text-anchor\": \"top\",\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-padding\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    30,\n                    17,\n                    5\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"fitness_centre\",\n                        \"golf_course\",\n                        \"camp_site\",\n                        \"bowling_alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic_site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog_park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"hsl(117, 53%, 31%)\",\n                    [\n                        \"bank\",\n                        \"atm\",\n                        \"parking\",\n                        \"toilets\",\n                        \"garages\"\n                    ],\n                    \"#737b9b\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\",\n                        \"fast_food\",\n                        \"restaurant\",\n                        \"ice_cream\"\n                    ],\n                    \"#c77d57\",\n                    [\n                        \"museum\",\n                        \"theatre\",\n                        \"casino\",\n                        \"castle\",\n                        \"gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music_venue\",\n                        \"monument\"\n                    ],\n                    \"hsl(186, 78%, 44%)\",\n                    [\n                        \"hospital\",\n                        \"doctors\"\n                    ],\n                    \"#a47172\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"lodging\"\n                        ],\n                        \"#df7db1\",\n                        [\n                            \"grocery\",\n                            \"clothing_store\",\n                            \"shop\"\n                        ],\n                        \"hsl(213, 40%, 48%)\",\n                        \"#67747b\"\n                    ]\n                ],\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1,\n                \"icon-translate\": [\n                    0,\n                    0\n                ],\n                \"text-translate\": [\n                    0,\n                    0\n                ],\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"poi_label_above\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"124a9d7a8e5226775d947c592110dfad\",\n                \"microg:gms-type-element\": \"labels.text\",\n                \"microg:gms-type-feature\": \"poi\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"poi\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"bus\",\n                        \"railway\"\n                    ],\n                    false,\n                    true\n                ],\n                [\n                    \"any\",\n                    [\n                        \"!=\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ],\n                            [\n                                \"park\",\n                                \"cemetery\"\n                            ],\n                            true,\n                            false\n                        ],\n                        [\n                            \"<=\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            250\n                        ]\n                    ],\n                    [\n                        \">=\",\n                        [\n                            \"zoom\"\n                        ],\n                        16\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-optional\": false,\n                \"text-line-height\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    15,\n                    1.2\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    13,\n                    15,\n                    14\n                ],\n                \"icon-offset\": [\n                    0,\n                    -36\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"museum\",\n                        \"theatre\",\n                        \"restaurant\"\n                    ],\n                    [\n                        \"concat\",\n                        \"poi_\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ]\n                    ],\n                    [\n                        \"fitness_centre\",\n                        \"golf_course\",\n                        \"camp_site\",\n                        \"bowling_alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic_site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog_park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"poi_generic_green\",\n                    [\n                        \"bank\",\n                        \"atm\",\n                        \"parking\",\n                        \"toilets\",\n                        \"garages\"\n                    ],\n                    \"poi_generic_purple\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\"\n                    ],\n                    \"poi_generic_orange\",\n                    [\n                        \"casino\",\n                        \"castle\",\n                        \"gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music_venue\",\n                        \"monument\"\n                    ],\n                    \"poi_generic_teal\",\n                    [\n                        \"hospital\",\n                        \"doctors\"\n                    ],\n                    \"poi_generic_red\",\n                    [\n                        \"fast_food\",\n                        \"ice_cream\"\n                    ],\n                    \"poi_restaurant\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"lodging\",\n                            \"grocery\"\n                        ],\n                        [\n                            \"concat\",\n                            \"poi_\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ]\n                        ],\n                        [\n                            \"clothing_store\",\n                            \"shop\"\n                        ],\n                        \"poi_generic_blue\",\n                        \"poi_generic\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-offset\": [\n                    0,\n                    -2\n                ],\n                \"icon-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.25,\n                    15,\n                    0.32\n                ],\n                \"text-anchor\": \"bottom\",\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-padding\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    30,\n                    17,\n                    5\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"fitness_centre\",\n                        \"golf_course\",\n                        \"camp_site\",\n                        \"bowling_alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic_site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog_park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"hsl(117, 53%, 31%)\",\n                    [\n                        \"bank\",\n                        \"atm\",\n                        \"parking\",\n                        \"toilets\",\n                        \"garages\"\n                    ],\n                    \"#737b9b\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\",\n                        \"fast_food\",\n                        \"restaurant\",\n                        \"ice_cream\"\n                    ],\n                    \"#c77d57\",\n                    [\n                        \"museum\",\n                        \"theatre\",\n                        \"casino\",\n                        \"castle\",\n                        \"gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music_venue\",\n                        \"monument\"\n                    ],\n                    \"hsl(186, 78%, 44%)\",\n                    [\n                        \"hospital\",\n                        \"doctors\"\n                    ],\n                    \"#a47172\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"lodging\"\n                        ],\n                        \"#df7db1\",\n                        [\n                            \"grocery\",\n                            \"clothing_store\",\n                            \"shop\"\n                        ],\n                        \"hsl(213, 40%, 48%)\",\n                        \"#67747b\"\n                    ]\n                ],\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1,\n                \"icon-translate\": [\n                    0,\n                    0\n                ],\n                \"text-translate\": [\n                    0,\n                    0\n                ],\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"poi_label_left\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"124a9d7a8e5226775d947c592110dfad\",\n                \"microg:gms-type-element\": \"labels.text\",\n                \"microg:gms-type-feature\": \"poi\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"poi\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"bus\",\n                        \"railway\"\n                    ],\n                    false,\n                    true\n                ],\n                [\n                    \"any\",\n                    [\n                        \"!=\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ],\n                            [\n                                \"park\",\n                                \"cemetery\"\n                            ],\n                            true,\n                            false\n                        ],\n                        [\n                            \"<=\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            250\n                        ]\n                    ],\n                    [\n                        \">=\",\n                        [\n                            \"zoom\"\n                        ],\n                        16\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-line-height\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    15,\n                    1.2\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    13,\n                    15,\n                    14\n                ],\n                \"icon-offset\": [\n                    0,\n                    -36\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"museum\",\n                        \"theatre\",\n                        \"restaurant\"\n                    ],\n                    [\n                        \"concat\",\n                        \"poi_\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ]\n                    ],\n                    [\n                        \"fitness_centre\",\n                        \"golf_course\",\n                        \"camp_site\",\n                        \"bowling_alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic_site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog_park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"poi_generic_green\",\n                    [\n                        \"bank\",\n                        \"atm\",\n                        \"parking\",\n                        \"toilets\",\n                        \"garages\"\n                    ],\n                    \"poi_generic_purple\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\"\n                    ],\n                    \"poi_generic_orange\",\n                    [\n                        \"casino\",\n                        \"castle\",\n                        \"gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music_venue\",\n                        \"monument\"\n                    ],\n                    \"poi_generic_teal\",\n                    [\n                        \"hospital\",\n                        \"doctors\"\n                    ],\n                    \"poi_generic_red\",\n                    [\n                        \"fast_food\",\n                        \"ice_cream\"\n                    ],\n                    \"poi_restaurant\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"lodging\",\n                            \"grocery\"\n                        ],\n                        [\n                            \"concat\",\n                            \"poi_\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ]\n                        ],\n                        [\n                            \"clothing_store\",\n                            \"shop\"\n                        ],\n                        \"poi_generic_blue\",\n                        \"poi_generic\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-justify\": \"right\",\n                \"text-offset\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    [\n                        \"literal\",\n                        [\n                            -1.1,\n                            -0.7\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            -1.1,\n                            -0.9\n                        ]\n                    ]\n                ],\n                \"icon-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.25,\n                    15,\n                    0.32\n                ],\n                \"text-anchor\": \"right\",\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-padding\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    30,\n                    17,\n                    5\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"fitness_centre\",\n                        \"golf_course\",\n                        \"camp_site\",\n                        \"bowling_alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic_site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog_park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"hsl(117, 53%, 31%)\",\n                    [\n                        \"bank\",\n                        \"atm\",\n                        \"parking\",\n                        \"toilets\",\n                        \"garages\"\n                    ],\n                    \"#737b9b\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\",\n                        \"fast_food\",\n                        \"restaurant\",\n                        \"ice_cream\"\n                    ],\n                    \"#c77d57\",\n                    [\n                        \"museum\",\n                        \"theatre\",\n                        \"casino\",\n                        \"castle\",\n                        \"gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music_venue\",\n                        \"monument\"\n                    ],\n                    \"hsl(186, 78%, 44%)\",\n                    [\n                        \"hospital\",\n                        \"doctors\"\n                    ],\n                    \"#a47172\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"lodging\"\n                        ],\n                        \"#df7db1\",\n                        [\n                            \"grocery\",\n                            \"clothing_store\",\n                            \"shop\"\n                        ],\n                        \"hsl(213, 40%, 48%)\",\n                        \"#67747b\"\n                    ]\n                ],\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1,\n                \"icon-translate\": [\n                    0,\n                    0\n                ],\n                \"text-translate\": [\n                    0,\n                    0\n                ],\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"poi_label_right\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"124a9d7a8e5226775d947c592110dfad\",\n                \"microg:gms-type-element\": \"labels.text\",\n                \"microg:gms-type-feature\": \"poi\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"poi\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"bus\",\n                        \"railway\"\n                    ],\n                    false,\n                    true\n                ],\n                [\n                    \"any\",\n                    [\n                        \"!=\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ],\n                            [\n                                \"park\",\n                                \"cemetery\"\n                            ],\n                            true,\n                            false\n                        ],\n                        [\n                            \"<=\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            250\n                        ]\n                    ],\n                    [\n                        \">=\",\n                        [\n                            \"zoom\"\n                        ],\n                        16\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-line-height\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    15,\n                    1.2\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    13,\n                    15,\n                    14\n                ],\n                \"icon-offset\": [\n                    0,\n                    -36\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"museum\",\n                        \"theatre\",\n                        \"restaurant\"\n                    ],\n                    [\n                        \"concat\",\n                        \"poi_\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ]\n                    ],\n                    [\n                        \"fitness_centre\",\n                        \"golf_course\",\n                        \"camp_site\",\n                        \"bowling_alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic_site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog_park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"poi_generic_green\",\n                    [\n                        \"bank\",\n                        \"atm\",\n                        \"parking\",\n                        \"toilets\",\n                        \"garages\"\n                    ],\n                    \"poi_generic_purple\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\"\n                    ],\n                    \"poi_generic_orange\",\n                    [\n                        \"casino\",\n                        \"castle\",\n                        \"gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music_venue\",\n                        \"monument\"\n                    ],\n                    \"poi_generic_teal\",\n                    [\n                        \"hospital\",\n                        \"doctors\"\n                    ],\n                    \"poi_generic_red\",\n                    [\n                        \"fast_food\",\n                        \"ice_cream\"\n                    ],\n                    \"poi_restaurant\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"lodging\",\n                            \"grocery\"\n                        ],\n                        [\n                            \"concat\",\n                            \"poi_\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ]\n                        ],\n                        [\n                            \"clothing_store\",\n                            \"shop\"\n                        ],\n                        \"poi_generic_blue\",\n                        \"poi_generic\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-justify\": \"left\",\n                \"text-offset\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    [\n                        \"literal\",\n                        [\n                            1.1,\n                            -0.7\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            1.1,\n                            -0.9\n                        ]\n                    ]\n                ],\n                \"icon-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.25,\n                    15,\n                    0.32\n                ],\n                \"text-anchor\": \"left\",\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-padding\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    30,\n                    17,\n                    5\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"fitness_centre\",\n                        \"golf_course\",\n                        \"camp_site\",\n                        \"bowling_alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic_site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog_park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"hsl(117, 53%, 31%)\",\n                    [\n                        \"bank\",\n                        \"atm\",\n                        \"parking\",\n                        \"toilets\",\n                        \"garages\"\n                    ],\n                    \"#737b9b\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\",\n                        \"fast_food\",\n                        \"restaurant\",\n                        \"ice_cream\"\n                    ],\n                    \"#c77d57\",\n                    [\n                        \"museum\",\n                        \"theatre\",\n                        \"casino\",\n                        \"castle\",\n                        \"gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music_venue\",\n                        \"monument\"\n                    ],\n                    \"hsl(186, 78%, 44%)\",\n                    [\n                        \"hospital\",\n                        \"doctors\"\n                    ],\n                    \"#a47172\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"lodging\"\n                        ],\n                        \"#df7db1\",\n                        [\n                            \"grocery\",\n                            \"clothing_store\",\n                            \"shop\"\n                        ],\n                        \"hsl(213, 40%, 48%)\",\n                        \"#67747b\"\n                    ]\n                ],\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1,\n                \"icon-translate\": [\n                    0,\n                    0\n                ],\n                \"text-translate\": [\n                    0,\n                    0\n                ],\n                \"text-halo-blur\": 1\n            }\n        }\n    ],\n    \"created\": \"2019-04-15T08:41:40.148Z\",\n    \"modified\": \"2020-09-05T19:42:03.856Z\",\n    \"id\": \"cjui4020201oo1fmca7yuwbor\",\n    \"owner\": \"microg\",\n    \"visibility\": \"public\",\n    \"protected\": false,\n    \"draft\": false\n}\n"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/style-microg-satellite-mapbox.json",
    "content": "{\n    \"version\": 8,\n    \"name\": \"Mountain View Satellite\",\n    \"metadata\": {\n        \"mapbox:origin\": \"basic-template\",\n        \"mapbox:autocomposite\": true,\n        \"mapbox:type\": \"template\",\n        \"mapbox:sdk-support\": {\n            \"js\": \"0.50.0\",\n            \"android\": \"6.7.0\",\n            \"ios\": \"4.6.0\"\n        },\n        \"mapbox:trackposition\": false,\n        \"mapbox:groups\": {\n            \"f51b507d2a17e572c70a5db74b0fec7e\": {\n                \"name\": \"Base\",\n                \"collapsed\": true\n            },\n            \"3f48b8dc54ff2e6544b9ef9cedbf2990\": {\n                \"name\": \"Streets\",\n                \"collapsed\": false\n            },\n            \"29bb589e8d1b9b402583363648b70302\": {\n                \"name\": \"Buildings\",\n                \"collapsed\": true\n            },\n            \"3c26e9cbc75335c6f0ba8de5439cf1fa\": {\n                \"name\": \"Country borders\",\n                \"collapsed\": true\n            },\n            \"7b44201d7f1682d99f7140188aff23ce\": {\n                \"name\": \"Labels\",\n                \"collapsed\": true\n            },\n            \"24306bdccbff03e2ee08d5d1a4ca7312\": {\n                \"name\": \"Street name\",\n                \"collapsed\": false\n            },\n            \"124a9d7a8e5226775d947c592110dfad\": {\n                \"name\": \"POI\",\n                \"collapsed\": true\n            }\n        },\n        \"mapbox:uiParadigm\": \"layers\"\n    },\n    \"center\": [\n        12.819420849458652,\n        50.03325860617235\n    ],\n    \"zoom\": 3.315829104862067,\n    \"bearing\": 0,\n    \"pitch\": 1.5,\n    \"light\": {\n        \"intensity\": 0.5,\n        \"color\": \"hsl(0, 0%, 0%)\"\n    },\n    \"sources\": {\n        \"mapbox://mapbox.satellite\": {\n            \"url\": \"mapbox://mapbox.satellite\",\n            \"type\": \"raster\",\n            \"tileSize\": 256\n        },\n        \"composite\": {\n            \"url\": \"mapbox://mapbox.mapbox-streets-v8,mapbox.mapbox-terrain-v2\",\n            \"type\": \"vector\"\n        }\n    },\n    \"sprite\": \"mapbox://sprites/microg/cjxgloted25ap1ct4uex7m6hi/8fkcj5fgn4mftlzuak3guz1f9\",\n    \"glyphs\": \"mapbox://fonts/microg/{fontstack}/{range}.pbf\",\n    \"layers\": [\n        {\n            \"id\": \"background\",\n            \"type\": \"raster\",\n            \"source\": \"mapbox://mapbox.satellite\",\n            \"layout\": {},\n            \"paint\": {},\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"path\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"path\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    [\n                        \"platform\",\n                        \"steps\"\n                    ],\n                    false,\n                    true\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsl(118, 34%, 66%)\",\n                \"line-dasharray\": [\n                    4,\n                    2\n                ],\n                \"line-opacity\": 0.3\n            }\n        },\n        {\n            \"id\": \"steps\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"path\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    [\n                        \"steps\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsl(118, 5%, 66%)\",\n                \"line-dasharray\": [\n                    1,\n                    1\n                ],\n                \"line-gap-width\": 1,\n                \"line-opacity\": 0.3\n            }\n        },\n        {\n            \"id\": \"platform\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"transit.station.rail\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"type\"\n                ],\n                [\n                    \"platform\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"fill-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    \"hsl(2, 20%, 92%)\",\n                    16,\n                    \"hsl(2, 95%, 92%)\"\n                ],\n                \"fill-outline-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    \"hsl(1, 10%, 76%)\",\n                    16,\n                    \"hsl(1, 74%, 76%)\"\n                ],\n                \"fill-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0,\n                    16,\n                    0.3\n                ]\n            }\n        },\n        {\n            \"id\": \"primary_tunnel\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary_link\",\n                        \"primary\",\n                        \"motorway_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    1,\n                    12,\n                    4,\n                    14,\n                    6,\n                    16,\n                    10,\n                    22,\n                    64\n                ],\n                \"line-color\": \"hsl(0, 0%, 89%)\",\n                \"line-opacity\": 0.3\n            }\n        },\n        {\n            \"id\": \"aeroway\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"transit.station.airport\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"aeroway\",\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsla(0, 0%, 0%, 0.1)\",\n                \"line-opacity\": 0.3\n            }\n        },\n        {\n            \"id\": \"service_road\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"service\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsla(0, 0%, 0%, 0.1)\",\n                \"line-opacity\": 0.3\n            }\n        },\n        {\n            \"id\": \"railway\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"major_rail\",\n                    \"minor_rail\",\n                    \"service_rail\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsl(220, 4%, 85%)\",\n                \"line-opacity\": 0.3\n            }\n        },\n        {\n            \"id\": \"pedestrian\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"pedestrian\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    [\n                        \"platform\"\n                    ],\n                    false,\n                    true\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsl(0, 0%, 100%)\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    13,\n                    1,\n                    16,\n                    4,\n                    22,\n                    32\n                ],\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12.5,\n                    0,\n                    13.5,\n                    0.3\n                ]\n            }\n        },\n        {\n            \"id\": \"street\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"street\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsl(0, 0%, 100%)\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    1,\n                    16,\n                    6,\n                    22,\n                    40\n                ],\n                \"line-opacity\": 0.3\n            }\n        },\n        {\n            \"id\": \"secondary\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"secondary\",\n                    \"secondary_link\",\n                    \"trunk_link\",\n                    \"tertiary\",\n                    \"tertiary_link\",\n                    \"trunk\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsl(0, 0%, 100%)\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    10,\n                    1,\n                    17,\n                    10,\n                    22,\n                    48\n                ],\n                \"line-opacity\": 0.3\n            }\n        },\n        {\n            \"id\": \"primary\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary_link\",\n                        \"primary\",\n                        \"motorway_link\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"structure\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    false,\n                    true\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"hsl(50, 100%, 75%)\",\n                    7,\n                    \"hsl(50, 100%, 85%)\"\n                ],\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    1,\n                    16,\n                    8,\n                    22,\n                    64\n                ],\n                \"line-opacity\": 0.3\n            }\n        },\n        {\n            \"id\": \"motorway\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"motorway\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsl(47, 100%, 82%)\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    1,\n                    15.5,\n                    8,\n                    22,\n                    78\n                ],\n                \"line-opacity\": 0.3\n            }\n        },\n        {\n            \"id\": \"admin_0\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3c26e9cbc75335c6f0ba8de5439cf1fa\",\n                \"microg:gms-type-feature\": \"administrative.country\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"admin\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maritime\"\n                    ],\n                    [\n                        \"false\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"admin_level\"\n                    ],\n                    [\n                        0\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": [\n                    \"case\",\n                    [\n                        \"==\",\n                        [\n                            \"get\",\n                            \"disputed\"\n                        ],\n                        true\n                    ],\n                    \"hsl(0, 24%, 85%)\",\n                    \"hsl(200, 1%, 85%)\"\n                ]\n            }\n        },\n        {\n            \"id\": \"admin_1\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3c26e9cbc75335c6f0ba8de5439cf1fa\",\n                \"microg:gms-type-feature\": \"administrative.province\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"admin\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maritime\"\n                    ],\n                    [\n                        \"false\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"admin_level\"\n                    ],\n                    [\n                        1\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": [\n                    \"case\",\n                    [\n                        \"==\",\n                        [\n                            \"get\",\n                            \"disputed\"\n                        ],\n                        true\n                    ],\n                    \"hsl(0, 24%, 85%)\",\n                    \"hsl(200, 1%, 85%)\"\n                ],\n                \"line-dasharray\": [\n                    1,\n                    1\n                ]\n            }\n        },\n        {\n            \"id\": \"river_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"natural_label\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"river\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"symbol-placement\": \"line\",\n                \"symbol-spacing\": 500,\n                \"text-font\": [\n                    \"Roboto Regular\",\n                    \"Arial Unicode MS Regular\"\n                ]\n            },\n            \"paint\": {\n                \"text-color\": \"#5083c1\",\n                \"text-halo-color\": \"#5083c1\",\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"city_label_right\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"place_label\",\n            \"maxzoom\": 8,\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    [\n                        \"/\",\n                        [\n                            \"zoom\"\n                        ],\n                        4\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"settlement\",\n                        \"settlement_subdivision\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-optional\": true,\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"-\",\n                        14,\n                        [\n                            \"max\",\n                            0,\n                            [\n                                \"-\",\n                                [\n                                    \"get\",\n                                    \"symbolrank\"\n                                ],\n                                8\n                            ]\n                        ]\n                    ],\n                    22,\n                    [\n                        \"-\",\n                        20,\n                        [\n                            \"/\",\n                            [\n                                \"get\",\n                                \"symbolrank\"\n                            ],\n                            4\n                        ]\n                    ]\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"capital\"\n                    ],\n                    [\n                        0,\n                        2\n                    ],\n                    \"capital\",\n                    \"city\"\n                ],\n                \"text-font\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"symbolrank\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\",\n                            \"Arial Unicode MS Regular\"\n                        ]\n                    ],\n                    10,\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Regular\",\n                            \"Arial Unicode MS Regular\"\n                        ]\n                    ]\n                ],\n                \"text-justify\": \"left\",\n                \"text-offset\": [\n                    0.5,\n                    0.1\n                ],\n                \"icon-size\": [\n                    \"/\",\n                    5,\n                    [\n                        \"get\",\n                        \"symbolrank\"\n                    ]\n                ],\n                \"text-anchor\": \"left\",\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"-\",\n                            100,\n                            [\n                                \"*\",\n                                [\n                                    \"get\",\n                                    \"symbolrank\"\n                                ],\n                                2\n                            ]\n                        ],\n                        \"%)\"\n                    ],\n                    22,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"-\",\n                                100,\n                                [\n                                    \"get\",\n                                    \"symbolrank\"\n                                ]\n                            ],\n                            5\n                        ],\n                        \"%)\"\n                    ]\n                ],\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"icon-opacity\": 0.8,\n                \"text-halo-color\": \"hsl(0, 1%, 0%)\"\n            }\n        },\n        {\n            \"id\": \"city_label_left\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"place_label\",\n            \"maxzoom\": 8,\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    [\n                        \"/\",\n                        [\n                            \"zoom\"\n                        ],\n                        4\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"settlement\",\n                        \"settlement_subdivision\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"-\",\n                        14,\n                        [\n                            \"max\",\n                            0,\n                            [\n                                \"-\",\n                                [\n                                    \"get\",\n                                    \"symbolrank\"\n                                ],\n                                8\n                            ]\n                        ]\n                    ],\n                    22,\n                    [\n                        \"-\",\n                        20,\n                        [\n                            \"/\",\n                            [\n                                \"get\",\n                                \"symbolrank\"\n                            ],\n                            4\n                        ]\n                    ]\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"capital\"\n                    ],\n                    [\n                        0,\n                        2\n                    ],\n                    \"capital\",\n                    \"city\"\n                ],\n                \"text-font\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"symbolrank\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\",\n                            \"Arial Unicode MS Regular\"\n                        ]\n                    ],\n                    10,\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Regular\",\n                            \"Arial Unicode MS Regular\"\n                        ]\n                    ]\n                ],\n                \"text-justify\": \"right\",\n                \"text-offset\": [\n                    -0.5,\n                    0.1\n                ],\n                \"icon-size\": [\n                    \"/\",\n                    5,\n                    [\n                        \"get\",\n                        \"symbolrank\"\n                    ]\n                ],\n                \"text-anchor\": \"right\",\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"-\",\n                            100,\n                            [\n                                \"*\",\n                                [\n                                    \"get\",\n                                    \"symbolrank\"\n                                ],\n                                2\n                            ]\n                        ],\n                        \"%)\"\n                    ],\n                    22,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"-\",\n                                100,\n                                [\n                                    \"get\",\n                                    \"symbolrank\"\n                                ]\n                            ],\n                            5\n                        ],\n                        \"%)\"\n                    ]\n                ],\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"icon-opacity\": 0.8,\n                \"text-halo-color\": \"hsl(0, 1%, 0%)\"\n            }\n        },\n        {\n            \"id\": \"city_label_below\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"place_label\",\n            \"maxzoom\": 8,\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    [\n                        \"/\",\n                        [\n                            \"zoom\"\n                        ],\n                        4\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"settlement\",\n                        \"settlement_subdivision\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"-\",\n                        14,\n                        [\n                            \"max\",\n                            0,\n                            [\n                                \"-\",\n                                [\n                                    \"get\",\n                                    \"symbolrank\"\n                                ],\n                                8\n                            ]\n                        ]\n                    ],\n                    22,\n                    [\n                        \"-\",\n                        20,\n                        [\n                            \"/\",\n                            [\n                                \"get\",\n                                \"symbolrank\"\n                            ],\n                            4\n                        ]\n                    ]\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"capital\"\n                    ],\n                    [\n                        0,\n                        2\n                    ],\n                    \"capital\",\n                    \"city\"\n                ],\n                \"text-font\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"symbolrank\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\",\n                            \"Arial Unicode MS Regular\"\n                        ]\n                    ],\n                    10,\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Regular\",\n                            \"Arial Unicode MS Regular\"\n                        ]\n                    ]\n                ],\n                \"text-offset\": [\n                    0,\n                    0.4\n                ],\n                \"icon-size\": [\n                    \"/\",\n                    5,\n                    [\n                        \"get\",\n                        \"symbolrank\"\n                    ]\n                ],\n                \"text-anchor\": \"top\",\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"-\",\n                            100,\n                            [\n                                \"*\",\n                                [\n                                    \"get\",\n                                    \"symbolrank\"\n                                ],\n                                2\n                            ]\n                        ],\n                        \"%)\"\n                    ],\n                    22,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"-\",\n                                100,\n                                [\n                                    \"get\",\n                                    \"symbolrank\"\n                                ]\n                            ],\n                            5\n                        ],\n                        \"%)\"\n                    ]\n                ],\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"icon-opacity\": 0.8,\n                \"text-halo-color\": \"hsl(0, 1%, 0%)\"\n            }\n        },\n        {\n            \"id\": \"city_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"place_label\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    [\n                        \"/\",\n                        [\n                            \"zoom\"\n                        ],\n                        4\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"settlement\",\n                        \"settlement_subdivision\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"-\",\n                        14,\n                        [\n                            \"max\",\n                            0,\n                            [\n                                \"-\",\n                                [\n                                    \"get\",\n                                    \"symbolrank\"\n                                ],\n                                8\n                            ]\n                        ]\n                    ],\n                    22,\n                    [\n                        \"-\",\n                        20,\n                        [\n                            \"/\",\n                            [\n                                \"get\",\n                                \"symbolrank\"\n                            ],\n                            4\n                        ]\n                    ]\n                ],\n                \"icon-image\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"capital\"\n                        ],\n                        [\n                            0,\n                            2\n                        ],\n                        \"capital\",\n                        \"city\"\n                    ],\n                    8,\n                    \"\"\n                ],\n                \"text-transform\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"symbolrank\"\n                    ],\n                    \"none\",\n                    15,\n                    \"uppercase\"\n                ],\n                \"text-font\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"symbolrank\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\",\n                            \"Arial Unicode MS Regular\"\n                        ]\n                    ],\n                    10,\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Regular\",\n                            \"Arial Unicode MS Regular\"\n                        ]\n                    ]\n                ],\n                \"text-offset\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            0,\n                            -0.2\n                        ]\n                    ],\n                    8,\n                    [\n                        \"literal\",\n                        [\n                            0,\n                            0\n                        ]\n                    ]\n                ],\n                \"icon-size\": [\n                    \"/\",\n                    5,\n                    [\n                        \"get\",\n                        \"symbolrank\"\n                    ]\n                ],\n                \"text-anchor\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"bottom\",\n                    8,\n                    \"center\"\n                ],\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-letter-spacing\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"get\",\n                        \"symbolrank\"\n                    ],\n                    0,\n                    0,\n                    8,\n                    0,\n                    12,\n                    0.1,\n                    16,\n                    0.2\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"-\",\n                            100,\n                            [\n                                \"*\",\n                                [\n                                    \"get\",\n                                    \"symbolrank\"\n                                ],\n                                2\n                            ]\n                        ],\n                        \"%)\"\n                    ],\n                    22,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"+\",\n                            [\n                                \"-\",\n                                100,\n                                [\n                                    \"get\",\n                                    \"symbolrank\"\n                                ]\n                            ],\n                            5\n                        ],\n                        \"%)\"\n                    ]\n                ],\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"icon-opacity\": 0.8,\n                \"text-halo-color\": \"hsl(0, 1%, 0%)\"\n            }\n        },\n        {\n            \"id\": \"park_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"poi.park\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"poi_label\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maki\"\n                    ],\n                    [\n                        \"park\",\n                        \"cemetery\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"sizerank\"\n                    ],\n                    10\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-size\": 14\n            },\n            \"paint\": {\n                \"text-color\": \"#297925\",\n                \"text-halo-color\": \"hsl(0, 0%, 100%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"road-number-shield\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"labels.icon\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"ref\"\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"reflen\"\n                    ],\n                    6\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": 9,\n                \"icon-image\": [\n                    \"case\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"shield\"\n                        ],\n                        [\n                            \"de-motorway\",\n                            \"rectangle-green\",\n                            \"rectangle-yellow\",\n                            \"rectangle-white\",\n                            \"rectangle-blue\",\n                            \"rectangle-red\",\n                            \"us-interstate\"\n                        ],\n                        true,\n                        false\n                    ],\n                    [\n                        \"concat\",\n                        \"shield_\",\n                        [\n                            \"get\",\n                            \"shield\"\n                        ],\n                        \"_\",\n                        [\n                            \"get\",\n                            \"reflen\"\n                        ]\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"shield_text_color\"\n                        ],\n                        [\n                            \"white\"\n                        ],\n                        true,\n                        false\n                    ],\n                    [\n                        \"concat\",\n                        \"shield_rectangle-blue_\",\n                        [\n                            \"get\",\n                            \"reflen\"\n                        ]\n                    ],\n                    [\n                        \"concat\",\n                        \"shield_rectangle-white_\",\n                        [\n                            \"get\",\n                            \"reflen\"\n                        ]\n                    ]\n                ],\n                \"icon-rotation-alignment\": \"viewport\",\n                \"text-font\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"shield_text_color\"\n                    ],\n                    [\n                        \"white\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"DIN Offc Pro Bold\",\n                            \"Arial Unicode MS Regular\"\n                        ]\n                    ],\n                    [\n                        \"black\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"DIN Offc Pro Medium\",\n                            \"Arial Unicode MS Regular\"\n                        ]\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"DIN Offc Pro Bold\",\n                            \"Arial Unicode MS Regular\"\n                        ]\n                    ]\n                ],\n                \"symbol-placement\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"point\",\n                    11,\n                    \"line\"\n                ],\n                \"text-rotation-alignment\": \"viewport\",\n                \"icon-size\": 0.75,\n                \"text-field\": [\n                    \"get\",\n                    \"ref\"\n                ],\n                \"text-letter-spacing\": 0.05\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"case\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"shield_text_color\"\n                        ],\n                        [\n                            \"white\"\n                        ],\n                        true,\n                        false\n                    ],\n                    \"#ffffff\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"shield_text_color\"\n                        ],\n                        [\n                            \"black\"\n                        ],\n                        true,\n                        false\n                    ],\n                    \"hsl(0, 0%, 7%)\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"shield_text_color\"\n                        ],\n                        [\n                            \"yellow\"\n                        ],\n                        true,\n                        false\n                    ],\n                    \"hsl(50, 100%, 70%)\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"shield_text_color\"\n                        ],\n                        [\n                            \"orange\"\n                        ],\n                        true,\n                        false\n                    ],\n                    \"hsl(25, 100%, 75%)\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"shield_text_color\"\n                        ],\n                        [\n                            \"blue\"\n                        ],\n                        true,\n                        false\n                    ],\n                    \"hsl(230, 48%, 34%)\",\n                    \"#ffffff\"\n                ]\n            }\n        },\n        {\n            \"id\": \"country_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"administrative.country\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"place_label\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"country\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {\n                \"text-letter-spacing\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    1,\n                    0,\n                    3,\n                    0.15\n                ],\n                \"text-font\": [\n                    \"Roboto Medium\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.2\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    1,\n                    12,\n                    7,\n                    [\n                        \"/\",\n                        100,\n                        [\n                            \"get\",\n                            \"symbolrank\"\n                        ]\n                    ]\n                ],\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    6,\n                    1,\n                    7,\n                    0\n                ],\n                \"text-color\": \"hsl(0, 0%, 90%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"text-halo-color\": \"hsl(0, 1%, 0%)\"\n            }\n        },\n        {\n            \"id\": \"pedestrian_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"minzoom\": 16,\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"pedestrian\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"type\"\n                    ],\n                    [\n                        \"platform\"\n                    ],\n                    false,\n                    true\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"name\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-font\": [\n                    \"Roboto Regular\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    17,\n                    10,\n                    22,\n                    14\n                ],\n                \"text-padding\": 5\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(0, 0%, 86%)\",\n                \"text-halo-color\": \"hsl(0, 1%, 0%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"street_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"street\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"name\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-font\": [\n                    \"Roboto Regular\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    6,\n                    16,\n                    10\n                ],\n                \"text-padding\": 5\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(0, 0%, 86%)\",\n                \"text-halo-color\": \"hsl(0, 1%, 0%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"secondary_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"secondary\",\n                        \"secondary_link\",\n                        \"tertiary_link\",\n                        \"tertiary\",\n                        \"trunk_link\",\n                        \"trunk\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"name\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-font\": [\n                    \"Roboto Regular\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    8,\n                    16,\n                    13\n                ],\n                \"symbol-spacing\": 300,\n                \"text-padding\": 25\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(196, 0%, 86%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-color\": \"hsl(0, 1%, 0%)\",\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"primary_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"road\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary\",\n                        \"primary_link\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"name\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-font\": [\n                    \"Roboto Regular\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    10,\n                    18,\n                    14\n                ],\n                \"symbol-spacing\": 800,\n                \"text-padding\": 50\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(32, 58%, 93%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-color\": \"hsl(0, 1%, 0%)\",\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"poi_label_below\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"124a9d7a8e5226775d947c592110dfad\",\n                \"microg:gms-type-feature\": \"poi\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"poi_label\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    [\n                        \"/\",\n                        [\n                            \"zoom\"\n                        ],\n                        4\n                    ]\n                ],\n                [\n                    \"!\",\n                    [\n                        \"all\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"maki\"\n                            ],\n                            [\n                                \"park\",\n                                \"cemetery\"\n                            ],\n                            true,\n                            false\n                        ],\n                        [\n                            \"<=\",\n                            [\n                                \"get\",\n                                \"sizerank\"\n                            ],\n                            10\n                        ]\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-optional\": true,\n                \"text-line-height\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    15,\n                    1.2\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    13,\n                    15,\n                    14\n                ],\n                \"icon-offset\": [\n                    0,\n                    -36\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maki\"\n                    ],\n                    [\n                        \"museum\",\n                        \"lodging\",\n                        \"theatre\",\n                        \"grocery\",\n                        \"restaurant\"\n                    ],\n                    [\n                        \"concat\",\n                        \"poi_\",\n                        [\n                            \"get\",\n                            \"maki\"\n                        ]\n                    ],\n                    [\n                        \"fitness-centre\",\n                        \"golf\",\n                        \"campsite\",\n                        \"bowling-alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic-site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog-park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"poi_generic_green\",\n                    [\n                        \"bank\",\n                        \"parking\",\n                        \"parking-garage\"\n                    ],\n                    \"poi_generic_purple\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\"\n                    ],\n                    \"poi_generic_orange\",\n                    [\n                        \"alcohol-shop\",\n                        \"shop\",\n                        \"shoe\",\n                        \"convenience\",\n                        \"clothing-store\",\n                        \"jewelry-store\"\n                    ],\n                    \"poi_generic_blue\",\n                    [\n                        \"casino\",\n                        \"castle\",\n                        \"art-gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music\",\n                        \"monument\"\n                    ],\n                    \"poi_generic_teal\",\n                    [\n                        \"hospital\",\n                        \"doctor\"\n                    ],\n                    \"poi_generic_red\",\n                    [\n                        \"restaurant-pizza\",\n                        \"restaurant-seafood\",\n                        \"restaurant-noodle\",\n                        \"fast-food\",\n                        \"ice-cream\"\n                    ],\n                    \"poi_restaurant\",\n                    \"poi_generic\"\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-offset\": [\n                    0,\n                    0.5\n                ],\n                \"icon-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.25,\n                    15,\n                    0.32\n                ],\n                \"text-anchor\": \"top\",\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maki\"\n                    ],\n                    [\n                        \"museum\",\n                        \"casino\",\n                        \"castle\",\n                        \"theatre\",\n                        \"art-gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music\",\n                        \"monument\"\n                    ],\n                    \"hsl(186, 78%, 65%)\",\n                    [\n                        \"lodging\"\n                    ],\n                    \"#df7db1\",\n                    [\n                        \"fitness-centre\",\n                        \"golf\",\n                        \"campsite\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic-site\",\n                        \"zoo\",\n                        \"dog-park\",\n                        \"stadium\",\n                        \"bowling-alley\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"hsl(117, 53%, 65%)\",\n                    [\n                        \"restaurant-pizza\",\n                        \"restaurant-seafood\",\n                        \"restaurant\",\n                        \"restaurant-noodle\",\n                        \"bar\",\n                        \"cafe\",\n                        \"fast-food\",\n                        \"bakery\",\n                        \"ice-cream\"\n                    ],\n                    \"hsl(20, 50%, 65%)\",\n                    [\n                        \"shop\",\n                        \"shoe\",\n                        \"alcohol-shop\",\n                        \"convenience\",\n                        \"grocery\",\n                        \"clothing-store\",\n                        \"jewelry-store\"\n                    ],\n                    \"hsl(213, 40%, 65%)\",\n                    [\n                        \"bank\",\n                        \"parking\",\n                        \"parking-garage\"\n                    ],\n                    \"hsl(228, 17%, 65%)\",\n                    [\n                        \"hospital\",\n                        \"doctor\"\n                    ],\n                    \"hsl(359, 22%, 65%)\",\n                    \"hsl(201, 9%, 80%)\"\n                ],\n                \"text-halo-color\": \"hsl(0, 1%, 0%)\",\n                \"text-halo-width\": 1,\n                \"icon-translate\": [\n                    0,\n                    0\n                ],\n                \"text-translate\": [\n                    0,\n                    0\n                ],\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"poi_label_above\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"124a9d7a8e5226775d947c592110dfad\",\n                \"microg:gms-type-feature\": \"poi\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"poi_label\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    [\n                        \"/\",\n                        [\n                            \"zoom\"\n                        ],\n                        4\n                    ]\n                ],\n                [\n                    \"!\",\n                    [\n                        \"all\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"maki\"\n                            ],\n                            [\n                                \"park\",\n                                \"cemetery\"\n                            ],\n                            true,\n                            false\n                        ],\n                        [\n                            \"<=\",\n                            [\n                                \"get\",\n                                \"sizerank\"\n                            ],\n                            10\n                        ]\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-optional\": true,\n                \"text-line-height\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    15,\n                    1.2\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    13,\n                    15,\n                    14\n                ],\n                \"icon-offset\": [\n                    0,\n                    -36\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maki\"\n                    ],\n                    [\n                        \"museum\",\n                        \"lodging\",\n                        \"theatre\",\n                        \"grocery\",\n                        \"restaurant\"\n                    ],\n                    [\n                        \"concat\",\n                        \"poi_\",\n                        [\n                            \"get\",\n                            \"maki\"\n                        ]\n                    ],\n                    [\n                        \"fitness-centre\",\n                        \"golf\",\n                        \"campsite\",\n                        \"bowling-alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic-site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog-park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"poi_generic_green\",\n                    [\n                        \"bank\",\n                        \"parking\",\n                        \"parking-garage\"\n                    ],\n                    \"poi_generic_purple\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\"\n                    ],\n                    \"poi_generic_orange\",\n                    [\n                        \"alcohol-shop\",\n                        \"shop\",\n                        \"shoe\",\n                        \"convenience\",\n                        \"clothing-store\",\n                        \"jewelry-store\"\n                    ],\n                    \"poi_generic_blue\",\n                    [\n                        \"casino\",\n                        \"castle\",\n                        \"art-gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music\",\n                        \"monument\"\n                    ],\n                    \"poi_generic_teal\",\n                    [\n                        \"hospital\",\n                        \"doctor\"\n                    ],\n                    \"poi_generic_red\",\n                    [\n                        \"restaurant-pizza\",\n                        \"restaurant-seafood\",\n                        \"restaurant-noodle\",\n                        \"fast-food\",\n                        \"ice-cream\"\n                    ],\n                    \"poi_restaurant\",\n                    \"poi_generic\"\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-offset\": [\n                    0,\n                    -2\n                ],\n                \"icon-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.25,\n                    15,\n                    0.32\n                ],\n                \"text-anchor\": \"bottom\",\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maki\"\n                    ],\n                    [\n                        \"museum\",\n                        \"casino\",\n                        \"castle\",\n                        \"theatre\",\n                        \"art-gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music\",\n                        \"monument\"\n                    ],\n                    \"hsl(186, 78%, 65%)\",\n                    [\n                        \"lodging\"\n                    ],\n                    \"#df7db1\",\n                    [\n                        \"fitness-centre\",\n                        \"golf\",\n                        \"campsite\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic-site\",\n                        \"zoo\",\n                        \"dog-park\",\n                        \"stadium\",\n                        \"bowling-alley\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"hsl(117, 53%, 65%)\",\n                    [\n                        \"restaurant-pizza\",\n                        \"restaurant-seafood\",\n                        \"restaurant\",\n                        \"restaurant-noodle\",\n                        \"bar\",\n                        \"cafe\",\n                        \"fast-food\",\n                        \"bakery\",\n                        \"ice-cream\"\n                    ],\n                    \"hsl(20, 50%, 65%)\",\n                    [\n                        \"shop\",\n                        \"shoe\",\n                        \"alcohol-shop\",\n                        \"convenience\",\n                        \"grocery\",\n                        \"clothing-store\",\n                        \"jewelry-store\"\n                    ],\n                    \"hsl(213, 40%, 65%)\",\n                    [\n                        \"bank\",\n                        \"parking\",\n                        \"parking-garage\"\n                    ],\n                    \"hsl(228, 17%, 65%)\",\n                    [\n                        \"hospital\",\n                        \"doctor\"\n                    ],\n                    \"hsl(359, 22%, 65%)\",\n                    \"hsl(201, 9%, 80%)\"\n                ],\n                \"text-halo-color\": \"hsl(0, 1%, 0%)\",\n                \"text-halo-width\": 1,\n                \"icon-translate\": [\n                    0,\n                    0\n                ],\n                \"text-translate\": [\n                    0,\n                    0\n                ],\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"poi_label_left\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"124a9d7a8e5226775d947c592110dfad\",\n                \"microg:gms-type-feature\": \"poi\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"poi_label\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    [\n                        \"/\",\n                        [\n                            \"zoom\"\n                        ],\n                        4\n                    ]\n                ],\n                [\n                    \"!\",\n                    [\n                        \"all\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"maki\"\n                            ],\n                            [\n                                \"park\",\n                                \"cemetery\"\n                            ],\n                            true,\n                            false\n                        ],\n                        [\n                            \"<=\",\n                            [\n                                \"get\",\n                                \"sizerank\"\n                            ],\n                            10\n                        ]\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-line-height\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    15,\n                    1.2\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    13,\n                    15,\n                    14\n                ],\n                \"icon-offset\": [\n                    0,\n                    -36\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maki\"\n                    ],\n                    [\n                        \"museum\",\n                        \"lodging\",\n                        \"theatre\",\n                        \"grocery\",\n                        \"restaurant\"\n                    ],\n                    [\n                        \"concat\",\n                        \"poi_\",\n                        [\n                            \"get\",\n                            \"maki\"\n                        ]\n                    ],\n                    [\n                        \"fitness-centre\",\n                        \"golf\",\n                        \"campsite\",\n                        \"bowling-alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic-site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog-park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"poi_generic_green\",\n                    [\n                        \"bank\",\n                        \"parking\",\n                        \"parking-garage\"\n                    ],\n                    \"poi_generic_purple\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\"\n                    ],\n                    \"poi_generic_orange\",\n                    [\n                        \"alcohol-shop\",\n                        \"shop\",\n                        \"shoe\",\n                        \"convenience\",\n                        \"clothing-store\",\n                        \"jewelry-store\"\n                    ],\n                    \"poi_generic_blue\",\n                    [\n                        \"casino\",\n                        \"castle\",\n                        \"art-gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music\",\n                        \"monument\"\n                    ],\n                    \"poi_generic_teal\",\n                    [\n                        \"hospital\",\n                        \"doctor\"\n                    ],\n                    \"poi_generic_red\",\n                    [\n                        \"restaurant-pizza\",\n                        \"restaurant-seafood\",\n                        \"restaurant-noodle\",\n                        \"fast-food\",\n                        \"ice-cream\"\n                    ],\n                    \"poi_restaurant\",\n                    \"poi_generic\"\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-justify\": \"right\",\n                \"text-offset\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    [\n                        \"literal\",\n                        [\n                            -1.1,\n                            -0.7\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            -1.1,\n                            -0.9\n                        ]\n                    ]\n                ],\n                \"icon-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.25,\n                    15,\n                    0.32\n                ],\n                \"text-anchor\": \"right\",\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maki\"\n                    ],\n                    [\n                        \"museum\",\n                        \"casino\",\n                        \"castle\",\n                        \"theatre\",\n                        \"art-gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music\",\n                        \"monument\"\n                    ],\n                    \"hsl(186, 78%, 65%)\",\n                    [\n                        \"lodging\"\n                    ],\n                    \"#df7db1\",\n                    [\n                        \"fitness-centre\",\n                        \"golf\",\n                        \"campsite\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic-site\",\n                        \"zoo\",\n                        \"dog-park\",\n                        \"stadium\",\n                        \"bowling-alley\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"hsl(117, 53%, 65%)\",\n                    [\n                        \"restaurant-pizza\",\n                        \"restaurant-seafood\",\n                        \"restaurant\",\n                        \"restaurant-noodle\",\n                        \"bar\",\n                        \"cafe\",\n                        \"fast-food\",\n                        \"bakery\",\n                        \"ice-cream\"\n                    ],\n                    \"hsl(20, 50%, 65%)\",\n                    [\n                        \"shop\",\n                        \"shoe\",\n                        \"alcohol-shop\",\n                        \"convenience\",\n                        \"grocery\",\n                        \"clothing-store\",\n                        \"jewelry-store\"\n                    ],\n                    \"hsl(213, 40%, 65%)\",\n                    [\n                        \"bank\",\n                        \"parking\",\n                        \"parking-garage\"\n                    ],\n                    \"hsl(228, 17%, 65%)\",\n                    [\n                        \"hospital\",\n                        \"doctor\"\n                    ],\n                    \"hsl(359, 22%, 65%)\",\n                    \"hsl(201, 9%, 80%)\"\n                ],\n                \"text-halo-color\": \"hsl(0, 1%, 0%)\",\n                \"text-halo-width\": 1,\n                \"icon-translate\": [\n                    0,\n                    0\n                ],\n                \"text-translate\": [\n                    0,\n                    0\n                ],\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"poi_label_right\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"124a9d7a8e5226775d947c592110dfad\",\n                \"microg:gms-type-feature\": \"poi\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"composite\",\n            \"source-layer\": \"poi_label\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"filterrank\"\n                    ],\n                    [\n                        \"/\",\n                        [\n                            \"zoom\"\n                        ],\n                        4\n                    ]\n                ],\n                [\n                    \"!\",\n                    [\n                        \"all\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"maki\"\n                            ],\n                            [\n                                \"park\",\n                                \"cemetery\"\n                            ],\n                            true,\n                            false\n                        ],\n                        [\n                            \"<=\",\n                            [\n                                \"get\",\n                                \"sizerank\"\n                            ],\n                            10\n                        ]\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-line-height\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    15,\n                    1.2\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    13,\n                    15,\n                    14\n                ],\n                \"icon-offset\": [\n                    0,\n                    -36\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maki\"\n                    ],\n                    [\n                        \"museum\",\n                        \"lodging\",\n                        \"theatre\",\n                        \"grocery\",\n                        \"restaurant\"\n                    ],\n                    [\n                        \"concat\",\n                        \"poi_\",\n                        [\n                            \"get\",\n                            \"maki\"\n                        ]\n                    ],\n                    [\n                        \"fitness-centre\",\n                        \"golf\",\n                        \"campsite\",\n                        \"bowling-alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic-site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog-park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"poi_generic_green\",\n                    [\n                        \"bank\",\n                        \"parking\",\n                        \"parking-garage\"\n                    ],\n                    \"poi_generic_purple\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\"\n                    ],\n                    \"poi_generic_orange\",\n                    [\n                        \"alcohol-shop\",\n                        \"shop\",\n                        \"shoe\",\n                        \"convenience\",\n                        \"clothing-store\",\n                        \"jewelry-store\"\n                    ],\n                    \"poi_generic_blue\",\n                    [\n                        \"casino\",\n                        \"castle\",\n                        \"art-gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music\",\n                        \"monument\"\n                    ],\n                    \"poi_generic_teal\",\n                    [\n                        \"hospital\",\n                        \"doctor\"\n                    ],\n                    \"poi_generic_red\",\n                    [\n                        \"restaurant-pizza\",\n                        \"restaurant-seafood\",\n                        \"restaurant-noodle\",\n                        \"fast-food\",\n                        \"ice-cream\"\n                    ],\n                    \"poi_restaurant\",\n                    \"poi_generic\"\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\",\n                    \"Arial Unicode MS Regular\"\n                ],\n                \"text-justify\": \"left\",\n                \"text-offset\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    [\n                        \"literal\",\n                        [\n                            1.1,\n                            -0.7\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            1.1,\n                            -0.9\n                        ]\n                    ]\n                ],\n                \"icon-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.25,\n                    15,\n                    0.32\n                ],\n                \"text-anchor\": \"left\",\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"maki\"\n                    ],\n                    [\n                        \"museum\",\n                        \"casino\",\n                        \"castle\",\n                        \"theatre\",\n                        \"art-gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music\",\n                        \"monument\"\n                    ],\n                    \"hsl(186, 78%, 65%)\",\n                    [\n                        \"lodging\"\n                    ],\n                    \"#df7db1\",\n                    [\n                        \"fitness-centre\",\n                        \"golf\",\n                        \"campsite\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic-site\",\n                        \"zoo\",\n                        \"dog-park\",\n                        \"stadium\",\n                        \"bowling-alley\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"hsl(117, 53%, 65%)\",\n                    [\n                        \"restaurant-pizza\",\n                        \"restaurant-seafood\",\n                        \"restaurant\",\n                        \"restaurant-noodle\",\n                        \"bar\",\n                        \"cafe\",\n                        \"fast-food\",\n                        \"bakery\",\n                        \"ice-cream\"\n                    ],\n                    \"hsl(20, 50%, 65%)\",\n                    [\n                        \"shop\",\n                        \"shoe\",\n                        \"alcohol-shop\",\n                        \"convenience\",\n                        \"grocery\",\n                        \"clothing-store\",\n                        \"jewelry-store\"\n                    ],\n                    \"hsl(213, 40%, 65%)\",\n                    [\n                        \"bank\",\n                        \"parking\",\n                        \"parking-garage\"\n                    ],\n                    \"hsl(228, 17%, 65%)\",\n                    [\n                        \"hospital\",\n                        \"doctor\"\n                    ],\n                    \"hsl(359, 22%, 65%)\",\n                    \"hsl(201, 9%, 80%)\"\n                ],\n                \"text-halo-color\": \"hsl(0, 1%, 0%)\",\n                \"text-halo-width\": 1,\n                \"icon-translate\": [\n                    0,\n                    0\n                ],\n                \"text-translate\": [\n                    0,\n                    0\n                ],\n                \"text-halo-blur\": 1\n            }\n        }\n    ],\n    \"created\": \"2019-06-28T21:20:23.628Z\",\n    \"modified\": \"2020-09-05T20:08:11.990Z\",\n    \"id\": \"cjxgloted25ap1ct4uex7m6hi\",\n    \"owner\": \"microg\",\n    \"visibility\": \"public\",\n    \"protected\": false,\n    \"draft\": false\n}\n"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/style-microg-satellite-stadia.json",
    "content": "{\n    \"version\": 8,\n    \"name\": \"Mountain View Full\",\n    \"metadata\": {\n        \"mapbox:origin\": \"basic-template\",\n        \"mapbox:autocomposite\": true,\n        \"mapbox:type\": \"template\",\n        \"mapbox:sdk-support\": {\n            \"js\": \"0.50.0\",\n            \"android\": \"6.7.0\",\n            \"ios\": \"4.6.0\"\n        },\n        \"mapbox:trackposition\": false,\n        \"mapbox:groups\": {\n            \"f51b507d2a17e572c70a5db74b0fec7e\": {\n                \"name\": \"Base\",\n                \"collapsed\": false\n            },\n            \"3f48b8dc54ff2e6544b9ef9cedbf2990\": {\n                \"name\": \"Streets\",\n                \"collapsed\": true\n            },\n            \"29bb589e8d1b9b402583363648b70302\": {\n                \"name\": \"Buildings\",\n                \"collapsed\": true\n            },\n            \"3c26e9cbc75335c6f0ba8de5439cf1fa\": {\n                \"name\": \"Country borders\",\n                \"collapsed\": true\n            },\n            \"7b44201d7f1682d99f7140188aff23ce\": {\n                \"name\": \"Labels\",\n                \"collapsed\": true\n            },\n            \"24306bdccbff03e2ee08d5d1a4ca7312\": {\n                \"name\": \"Street name\",\n                \"collapsed\": true\n            },\n            \"124a9d7a8e5226775d947c592110dfad\": {\n                \"name\": \"POI\",\n                \"collapsed\": true\n            }\n        },\n        \"mapbox:uiParadigm\": \"layers\",\n        \"maputnik:renderer\": \"mbgljs\"\n    },\n    \"center\": [\n        12.819420849458652,\n        50.03325860617235\n    ],\n    \"zoom\": 3.315829104862067,\n    \"bearing\": 0,\n    \"pitch\": 1.5,\n    \"light\": {\n        \"intensity\": 0.5,\n        \"color\": \"hsl(0, 0%, 100%)\",\n        \"anchor\": \"viewport\"\n    },\n    \"sources\": {\n        \"openmaptiles\": {\n            \"type\": \"vector\",\n            \"url\": \"https://tiles.stadiamaps.com/data/openmaptiles.json\"\n        },\n        \"satellite\": {\n            \"attribution\": \"© CNES, Distribution Airbus DS, © Airbus DS, © PlanetObserver (Contains Copernicus Data)\",\n            \"type\": \"raster\",\n            \"tiles\": [\n                \"https://tiles.stadiamaps.com/data/satellite/{z}/{x}/{y}.jpg\"\n            ],\n            \"minzoom\": 0,\n            \"maxzoom\": 24\n        }\n    },\n    \"sprite\": \"asset://sprites\",\n    \"glyphs\": \"asset://{fontstack}/{range}.pbf\",\n    \"layers\": [\n        {\n            \"id\": \"background\",\n            \"type\": \"background\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"background-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    4,\n                    \"hsl(43, 30%, 91%)\",\n                    5,\n                    \"hsl(0, 0%, 96%)\",\n                    8,\n                    \"hsl(0, 0%, 96%)\",\n                    9,\n                    \"#efeee8\",\n                    16,\n                    \"hsl(0, 0%, 95%)\",\n                    18,\n                    \"#f8f9fb\"\n                ]\n            }\n        },\n        {\n            \"id\": \"satellite\",\n            \"type\": \"raster\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"satellite\"\n        },\n        {\n            \"id\": \"path\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\",\n                \"maputnik:comment\": \"unpaved paths\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"minzoom\": 14,\n            \"maxzoom\": 24,\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"path\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsl(118, 34%, 66%)\",\n                \"line-dasharray\": [\n                    4,\n                    2\n                ],\n                \"line-opacity\": 0.3\n            }\n        },\n        {\n            \"id\": \"steps\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"subclass\"\n                ],\n                [\n                    \"steps\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsl(118, 5%, 66%)\",\n                \"line-dasharray\": [\n                    1,\n                    1\n                ],\n                \"line-gap-width\": 1,\n                \"line-opacity\": 0.3\n            }\n        },\n        {\n            \"id\": \"platform\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"transit.station.rail\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"platform\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"brunnel\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    false,\n                    true\n                ]\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    \"hsl(2, 20%, 92%)\",\n                    16,\n                    \"hsl(2, 95%, 92%)\"\n                ],\n                \"fill-outline-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    15,\n                    \"hsl(1, 10%, 76%)\",\n                    16,\n                    \"hsl(1, 74%, 76%)\"\n                ],\n                \"fill-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0,\n                    16,\n                    0.3\n                ]\n            }\n        },\n        {\n            \"id\": \"primary_tunnel\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"brunnel\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    1,\n                    12,\n                    4,\n                    14,\n                    6,\n                    16,\n                    10,\n                    22,\n                    64\n                ],\n                \"line-color\": \"hsl(0, 0%, 89%)\",\n                \"line-opacity\": 0.3\n            }\n        },\n        {\n            \"id\": \"aeroway\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"transit.station.airport\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"aeroway\",\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"line-color\": \"hsla(0, 0%, 0%, 0.1)\",\n                \"line-opacity\": 0.3\n            }\n        },\n        {\n            \"id\": \"service_road\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"service\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsla(0, 0%, 0%, 0.1)\",\n                \"line-opacity\": 0.3\n            }\n        },\n        {\n            \"id\": \"railway\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"any\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"rail\"\n                        ],\n                        true,\n                        false\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"subclass\"\n                        ],\n                        [\n                            \"light_rail\",\n                            \"tram\"\n                        ],\n                        true,\n                        false\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"brunnel\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    false,\n                    true\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"hsl(220, 4%, 85%)\",\n                \"line-opacity\": 0.3\n            }\n        },\n        {\n            \"id\": \"pedestrian\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"pedestrian\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"surface\"\n                    ],\n                    \"paved\"\n                ]\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"#ffffff\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    13,\n                    1,\n                    16,\n                    4,\n                    22,\n                    32\n                ],\n                \"line-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12.5,\n                    0,\n                    13.5,\n                    0.3\n                ]\n            }\n        },\n        {\n            \"id\": \"street\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"minor\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"#ffffff\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    12,\n                    1,\n                    16,\n                    6,\n                    22,\n                    40\n                ],\n                \"line-opacity\": 0.3\n            }\n        },\n        {\n            \"id\": \"secondary\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"secondary\",\n                    \"tertiary\",\n                    \"trunk\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"#ffffff\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    10,\n                    1,\n                    17,\n                    10,\n                    22,\n                    48\n                ],\n                \"line-opacity\": 0.3\n            }\n        },\n        {\n            \"id\": \"primary\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"brunnel\"\n                    ],\n                    [\n                        \"tunnel\"\n                    ],\n                    false,\n                    true\n                ]\n            ],\n            \"layout\": {\n                \"line-cap\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"hsl(50, 100%, 75%)\",\n                    7,\n                    \"hsl(50, 100%, 85%)\"\n                ],\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    9,\n                    1,\n                    16,\n                    8,\n                    22,\n                    64\n                ],\n                \"line-opacity\": 0.3\n            }\n        },\n        {\n            \"id\": \"motorway\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3f48b8dc54ff2e6544b9ef9cedbf2990\",\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"motorway\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {},\n            \"paint\": {\n                \"line-color\": \"#ffeba3\",\n                \"line-width\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    1,\n                    15.5,\n                    8,\n                    22,\n                    78\n                ],\n                \"line-opacity\": 0.3\n            }\n        },\n        {\n            \"id\": \"admin_0\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3c26e9cbc75335c6f0ba8de5439cf1fa\",\n                \"microg:gms-type-feature\": \"administrative.country\",\n                \"microg:gms-type-element\": \"geometry.stroke\",\n                \"maputnik:comment\": \"maritime=false filter could not be ported due to missing attributes in `boundary` layer\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"boundary\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"admin_level\"\n                    ],\n                    [\n                        2\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"!=\",\n                    [\n                        \"get\",\n                        \"maritime\"\n                    ],\n                    1\n                ]\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"line-color\": [\n                    \"case\",\n                    [\n                        \"==\",\n                        [\n                            \"get\",\n                            \"disputed\"\n                        ],\n                        1\n                    ],\n                    \"hsl(0, 24%, 48%)\",\n                    \"hsl(200, 0%, 80%)\"\n                ]\n            }\n        },\n        {\n            \"id\": \"admin_1\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"mapbox:group\": \"3c26e9cbc75335c6f0ba8de5439cf1fa\",\n                \"microg:gms-type-feature\": \"administrative.province\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"boundary\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"admin_level\"\n                    ],\n                    [\n                        3,\n                        4\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"!=\",\n                    [\n                        \"get\",\n                        \"maritime\"\n                    ],\n                    1\n                ]\n            ],\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"line-color\": [\n                    \"case\",\n                    [\n                        \"==\",\n                        [\n                            \"get\",\n                            \"disputed\"\n                        ],\n                        1\n                    ],\n                    \"hsl(0, 24%, 48%)\",\n                    \"hsl(200, 0%, 80%)\"\n                ],\n                \"line-dasharray\": [\n                    1,\n                    1\n                ]\n            }\n        },\n        {\n            \"id\": \"river_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"waterway\",\n            \"minzoom\": 13,\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"river\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"symbol-placement\": \"line\",\n                \"symbol-spacing\": 500,\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ]\n            },\n            \"paint\": {\n                \"text-color\": \"#5083c1\",\n                \"text-halo-color\": \"#5083c1\",\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"city_label_right\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"maxzoom\": 8,\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    [\n                        \"*\",\n                        [\n                            \"zoom\"\n                        ],\n                        1.5\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"city\",\n                        \"town\",\n                        \"village\",\n                        \"hamlet\",\n                        \"suburb\",\n                        \"quarter\",\n                        \"neighbourhood\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-optional\": false,\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"-\",\n                        14,\n                        [\n                            \"max\",\n                            0,\n                            [\n                                \"-\",\n                                [\n                                    \"get\",\n                                    \"rank\"\n                                ],\n                                8\n                            ]\n                        ]\n                    ],\n                    22,\n                    [\n                        \"-\",\n                        20,\n                        [\n                            \"/\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            4\n                        ]\n                    ]\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"capital\"\n                    ],\n                    [\n                        2\n                    ],\n                    \"capital\",\n                    \"city\"\n                ],\n                \"text-font\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\"\n                        ]\n                    ],\n                    10,\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Regular\"\n                        ]\n                    ]\n                ],\n                \"text-justify\": \"left\",\n                \"text-offset\": [\n                    0.5,\n                    0.1\n                ],\n                \"icon-size\": [\n                    \"/\",\n                    6,\n                    [\n                        \"+\",\n                        [\n                            \"get\",\n                            \"rank\"\n                        ],\n                        7\n                    ]\n                ],\n                \"text-anchor\": \"left\",\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"-\",\n                            100,\n                            [\n                                \"+\",\n                                [\n                                    \"*\",\n                                    [\n                                        \"get\",\n                                        \"rank\"\n                                    ],\n                                    2\n                                ],\n                                5\n                            ]\n                        ],\n                        \"%)\"\n                    ],\n                    22,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"-\",\n                            100,\n                            [\n                                \"+\",\n                                [\n                                    \"get\",\n                                    \"rank\"\n                                ],\n                                25\n                            ]\n                        ],\n                        \"%)\"\n                    ]\n                ],\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"text-halo-color\": \"hsl(0, 0%, 0%)\",\n                \"icon-opacity\": 0.8\n            }\n        },\n        {\n            \"id\": \"city_label_left\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"maxzoom\": 8,\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    [\n                        \"*\",\n                        [\n                            \"zoom\"\n                        ],\n                        1.5\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"city\",\n                        \"town\",\n                        \"village\",\n                        \"hamlet\",\n                        \"suburb\",\n                        \"quarter\",\n                        \"neighbourhood\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"-\",\n                        14,\n                        [\n                            \"max\",\n                            0,\n                            [\n                                \"-\",\n                                [\n                                    \"get\",\n                                    \"rank\"\n                                ],\n                                8\n                            ]\n                        ]\n                    ],\n                    22,\n                    [\n                        \"-\",\n                        20,\n                        [\n                            \"/\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            4\n                        ]\n                    ]\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"capital\"\n                    ],\n                    [\n                        2\n                    ],\n                    \"capital\",\n                    \"city\"\n                ],\n                \"text-font\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\"\n                        ]\n                    ],\n                    10,\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Regular\"\n                        ]\n                    ]\n                ],\n                \"text-justify\": \"right\",\n                \"text-offset\": [\n                    -0.5,\n                    0.1\n                ],\n                \"icon-size\": [\n                    \"/\",\n                    6,\n                    [\n                        \"+\",\n                        [\n                            \"get\",\n                            \"rank\"\n                        ],\n                        7\n                    ]\n                ],\n                \"text-anchor\": \"right\",\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"-\",\n                            100,\n                            [\n                                \"+\",\n                                [\n                                    \"*\",\n                                    [\n                                        \"get\",\n                                        \"rank\"\n                                    ],\n                                    2\n                                ],\n                                5\n                            ]\n                        ],\n                        \"%)\"\n                    ],\n                    22,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"-\",\n                            100,\n                            [\n                                \"+\",\n                                [\n                                    \"get\",\n                                    \"rank\"\n                                ],\n                                25\n                            ]\n                        ],\n                        \"%)\"\n                    ]\n                ],\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"text-halo-color\": \"hsl(0, 0%, 1%)\",\n                \"icon-opacity\": 0.8\n            }\n        },\n        {\n            \"id\": \"city_label_below\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"maxzoom\": 8,\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    [\n                        \"/\",\n                        [\n                            \"zoom\"\n                        ],\n                        3\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"city\",\n                        \"town\",\n                        \"village\",\n                        \"hamlet\",\n                        \"suburb\",\n                        \"quarter\",\n                        \"neighbourhood\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"-\",\n                        14,\n                        [\n                            \"max\",\n                            0,\n                            [\n                                \"-\",\n                                [\n                                    \"get\",\n                                    \"rank\"\n                                ],\n                                8\n                            ]\n                        ]\n                    ],\n                    22,\n                    [\n                        \"-\",\n                        20,\n                        [\n                            \"/\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            4\n                        ]\n                    ]\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"capital\"\n                    ],\n                    [\n                        2\n                    ],\n                    \"capital\",\n                    \"city\"\n                ],\n                \"text-font\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\"\n                        ]\n                    ],\n                    10,\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Regular\"\n                        ]\n                    ]\n                ],\n                \"text-offset\": [\n                    0,\n                    0.4\n                ],\n                \"icon-size\": [\n                    \"/\",\n                    6,\n                    [\n                        \"+\",\n                        [\n                            \"get\",\n                            \"rank\"\n                        ],\n                        7\n                    ]\n                ],\n                \"text-anchor\": \"top\",\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"-\",\n                            100,\n                            [\n                                \"+\",\n                                [\n                                    \"*\",\n                                    [\n                                        \"get\",\n                                        \"rank\"\n                                    ],\n                                    2\n                                ],\n                                5\n                            ]\n                        ],\n                        \"%)\"\n                    ],\n                    22,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"-\",\n                            100,\n                            [\n                                \"+\",\n                                [\n                                    \"get\",\n                                    \"rank\"\n                                ],\n                                25\n                            ]\n                        ],\n                        \"%)\"\n                    ]\n                ],\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"text-halo-color\": \"hsl(0, 0%, 0%)\",\n                \"icon-opacity\": 0.8\n            }\n        },\n        {\n            \"id\": \"city_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    [\n                        \"*\",\n                        [\n                            \"zoom\"\n                        ],\n                        1.5\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"city\",\n                        \"town\",\n                        \"village\",\n                        \"hamlet\",\n                        \"suburb\",\n                        \"quarter\",\n                        \"neighbourhood\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"-\",\n                        14,\n                        [\n                            \"max\",\n                            0,\n                            [\n                                \"-\",\n                                [\n                                    \"get\",\n                                    \"rank\"\n                                ],\n                                8\n                            ]\n                        ]\n                    ],\n                    22,\n                    [\n                        \"-\",\n                        20,\n                        [\n                            \"/\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            4\n                        ]\n                    ]\n                ],\n                \"icon-image\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"capital\"\n                        ],\n                        [\n                            2\n                        ],\n                        \"capital\",\n                        \"city\"\n                    ],\n                    8,\n                    \"\"\n                ],\n                \"text-transform\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    \"none\",\n                    15,\n                    \"uppercase\"\n                ],\n                \"text-font\": [\n                    \"step\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\"\n                        ]\n                    ],\n                    10,\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Regular\"\n                        ]\n                    ]\n                ],\n                \"text-offset\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            0,\n                            -0.2\n                        ]\n                    ],\n                    8,\n                    [\n                        \"literal\",\n                        [\n                            0,\n                            0\n                        ]\n                    ]\n                ],\n                \"icon-size\": [\n                    \"/\",\n                    6,\n                    [\n                        \"+\",\n                        [\n                            \"get\",\n                            \"rank\"\n                        ],\n                        7\n                    ]\n                ],\n                \"text-anchor\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"bottom\",\n                    8,\n                    \"center\"\n                ],\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-letter-spacing\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    0,\n                    0,\n                    8,\n                    0,\n                    12,\n                    0.1,\n                    16,\n                    0.2\n                ],\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    0,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"-\",\n                            100,\n                            [\n                                \"+\",\n                                [\n                                    \"*\",\n                                    [\n                                        \"get\",\n                                        \"rank\"\n                                    ],\n                                    2\n                                ],\n                                5\n                            ]\n                        ],\n                        \"%)\"\n                    ],\n                    22,\n                    [\n                        \"concat\",\n                        \"hsl(213, 11%, \",\n                        [\n                            \"-\",\n                            100,\n                            [\n                                \"+\",\n                                [\n                                    \"get\",\n                                    \"rank\"\n                                ],\n                                25\n                            ]\n                        ],\n                        \"%)\"\n                    ]\n                ],\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"text-halo-color\": \"hsl(0, 0%, 0%)\",\n                \"icon-opacity\": 0.8\n            }\n        },\n        {\n            \"id\": \"park_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"7b44201d7f1682d99f7140188aff23ce\",\n                \"microg:gms-type-feature\": \"poi.park\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"poi\",\n            \"minzoom\": 17,\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"park\",\n                        \"cemetery\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    250\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-size\": 14\n            },\n            \"paint\": {\n                \"text-color\": \"#297925\",\n                \"text-halo-color\": \"hsl(0, 0%, 100%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"road-number-shield\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road\",\n                \"microg:gms-type-element\": \"labels.icon\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation_name\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"ref\"\n                ],\n                [\n                    \"<=\",\n                    [\n                        \"get\",\n                        \"ref_length\"\n                    ],\n                    6\n                ]\n            ],\n            \"layout\": {\n                \"text-size\": 9,\n                \"icon-image\": [\n                    \"case\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"network\"\n                        ],\n                        [\n                            \"us-interstate\"\n                        ],\n                        true,\n                        false\n                    ],\n                    [\n                        \"concat\",\n                        \"shield_\",\n                        [\n                            \"get\",\n                            \"network\"\n                        ],\n                        \"_\",\n                        [\n                            \"get\",\n                            \"ref_length\"\n                        ]\n                    ],\n                    [\n                        \"concat\",\n                        \"shield_rectangle-white_\",\n                        [\n                            \"get\",\n                            \"ref_length\"\n                        ]\n                    ]\n                ],\n                \"icon-rotation-alignment\": \"viewport\",\n                \"text-font\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"shield_text_color\"\n                    ],\n                    [\n                        \"white\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Bold\"\n                        ]\n                    ],\n                    [\n                        \"black\"\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Medium\"\n                        ]\n                    ],\n                    [\n                        \"literal\",\n                        [\n                            \"Roboto Bold\"\n                        ]\n                    ]\n                ],\n                \"symbol-placement\": [\n                    \"step\",\n                    [\n                        \"zoom\"\n                    ],\n                    \"point\",\n                    11,\n                    \"line\"\n                ],\n                \"text-offset\": [\n                    0,\n                    0.1\n                ],\n                \"text-rotation-alignment\": \"viewport\",\n                \"icon-size\": 0.75,\n                \"text-field\": [\n                    \"get\",\n                    \"ref\"\n                ],\n                \"text-letter-spacing\": 0.05,\n                \"visibility\": \"visible\",\n                \"icon-padding\": 10\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"case\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"network\"\n                        ],\n                        [\n                            \"us-interstate\"\n                        ],\n                        true,\n                        false\n                    ],\n                    \"#ffffff\",\n                    \"#000000\"\n                ]\n            }\n        },\n        {\n            \"id\": \"country_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"administrative.country\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"filter\": [\n                \"match\",\n                [\n                    \"get\",\n                    \"class\"\n                ],\n                [\n                    \"country\"\n                ],\n                true,\n                false\n            ],\n            \"layout\": {\n                \"text-letter-spacing\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    1,\n                    0,\n                    3,\n                    0.15\n                ],\n                \"text-font\": [\n                    \"Roboto Medium\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"exponential\",\n                        1.2\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    1,\n                    12,\n                    7,\n                    [\n                        \"/\",\n                        30,\n                        [\n                            \"get\",\n                            \"rank\"\n                        ]\n                    ]\n                ],\n                \"text-field\": [\n                    \"coalesce\",\n                    [\n                        \"get\",\n                        \"name_en\"\n                    ],\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(0, 0%, 90%)\",\n                \"text-halo-color\": \"hsl(0, 0%, 0%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1,\n                \"text-opacity\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    6,\n                    1,\n                    7,\n                    0\n                ]\n            }\n        },\n        {\n            \"id\": \"pedestrian_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation_name\",\n            \"minzoom\": 16,\n            \"filter\": [\n                \"any\",\n                [\n                    \"all\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"subclass\"\n                        ],\n                        [\n                            \"pedestrian\"\n                        ],\n                        true,\n                        false\n                    ],\n                    [\n                        \"==\",\n                        [\n                            \"get\",\n                            \"surface\"\n                        ],\n                        \"paved\"\n                    ]\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    \"platform\",\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"name\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    17,\n                    10,\n                    22,\n                    14\n                ],\n                \"text-padding\": 5\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(0, 0%, 86%)\",\n                \"text-halo-color\": \"#000000\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"street_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation_name\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"minor\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"name\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    6,\n                    16,\n                    10\n                ],\n                \"text-padding\": 5\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(0, 0%, 86%)\",\n                \"text-halo-color\": \"#000000\",\n                \"text-halo-width\": 1,\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"secondary_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation_name\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"secondary\",\n                        \"tertiary\",\n                        \"trunk\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"name\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    8,\n                    16,\n                    13\n                ],\n                \"symbol-spacing\": 300,\n                \"text-padding\": 25\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(0, 0%, 86%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-color\": \"#000000\",\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"primary_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"24306bdccbff03e2ee08d5d1a4ca7312\",\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"labels.text\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation_name\",\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"primary\"\n                    ],\n                    true,\n                    false\n                ]\n            ],\n            \"layout\": {\n                \"text-field\": [\n                    \"get\",\n                    \"name\"\n                ],\n                \"symbol-placement\": \"line\",\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    8,\n                    10,\n                    18,\n                    14\n                ],\n                \"symbol-spacing\": 800,\n                \"text-padding\": 50\n            },\n            \"paint\": {\n                \"text-color\": \"hsl(32, 58%, 93%)\",\n                \"text-halo-width\": 1,\n                \"text-halo-color\": \"#000000\",\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"poi_label_below\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"124a9d7a8e5226775d947c592110dfad\",\n                \"microg:gms-type-element\": \"labels.text\",\n                \"microg:gms-type-feature\": \"poi\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"poi\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"bus\",\n                        \"railway\"\n                    ],\n                    false,\n                    true\n                ],\n                [\n                    \"any\",\n                    [\n                        \"!=\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ],\n                            [\n                                \"park\",\n                                \"cemetery\"\n                            ],\n                            true,\n                            false\n                        ],\n                        [\n                            \"<=\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            250\n                        ]\n                    ],\n                    [\n                        \">=\",\n                        [\n                            \"zoom\"\n                        ],\n                        16\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-optional\": false,\n                \"text-line-height\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    15,\n                    1.2\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    13,\n                    15,\n                    14\n                ],\n                \"icon-offset\": [\n                    0,\n                    -36\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"museum\",\n                        \"theatre\",\n                        \"restaurant\"\n                    ],\n                    [\n                        \"concat\",\n                        \"poi_\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ]\n                    ],\n                    [\n                        \"fitness_centre\",\n                        \"golf_course\",\n                        \"camp_site\",\n                        \"bowling_alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic_site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog_park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"poi_generic_green\",\n                    [\n                        \"bank\",\n                        \"atm\",\n                        \"parking\",\n                        \"toilets\",\n                        \"garages\"\n                    ],\n                    \"poi_generic_purple\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\"\n                    ],\n                    \"poi_generic_orange\",\n                    [\n                        \"casino\",\n                        \"castle\",\n                        \"gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music_venue\",\n                        \"monument\"\n                    ],\n                    \"poi_generic_teal\",\n                    [\n                        \"hospital\",\n                        \"doctors\"\n                    ],\n                    \"poi_generic_red\",\n                    [\n                        \"fast_food\",\n                        \"ice_cream\"\n                    ],\n                    \"poi_restaurant\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"lodging\",\n                            \"grocery\"\n                        ],\n                        [\n                            \"concat\",\n                            \"poi_\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ]\n                        ],\n                        [\n                            \"clothing_store\",\n                            \"shop\"\n                        ],\n                        \"poi_generic_blue\",\n                        \"poi_generic\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-offset\": [\n                    0,\n                    0.5\n                ],\n                \"icon-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.25,\n                    15,\n                    0.32\n                ],\n                \"text-anchor\": \"top\",\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-padding\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    30,\n                    17,\n                    5\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"fitness_centre\",\n                        \"golf_course\",\n                        \"camp_site\",\n                        \"bowling_alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic_site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog_park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"hsl(117, 53%, 65%)\",\n                    [\n                        \"bank\",\n                        \"atm\",\n                        \"parking\",\n                        \"toilets\",\n                        \"garages\"\n                    ],\n                    \"hsl(228, 17%, 65%)\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\",\n                        \"fast_food\",\n                        \"restaurant\",\n                        \"ice_cream\"\n                    ],\n                    \"hsl(20, 50%, 65%)\",\n                    [\n                        \"museum\",\n                        \"theatre\",\n                        \"casino\",\n                        \"castle\",\n                        \"gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music_venue\",\n                        \"monument\"\n                    ],\n                    \"hsl(186, 78%, 65%)\",\n                    [\n                        \"hospital\",\n                        \"doctors\"\n                    ],\n                    \"hsl(359, 22%, 65%)\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"lodging\"\n                        ],\n                        \"#df7db1\",\n                        [\n                            \"grocery\",\n                            \"clothing_store\",\n                            \"shop\"\n                        ],\n                        \"hsl(213, 40%, 65%)\",\n                        \"hsl(201, 9%, 80%)\"\n                    ]\n                ],\n                \"text-halo-color\": \"#000000\",\n                \"text-halo-width\": 1,\n                \"icon-translate\": [\n                    0,\n                    0\n                ],\n                \"text-translate\": [\n                    0,\n                    0\n                ],\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"poi_label_above\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"124a9d7a8e5226775d947c592110dfad\",\n                \"microg:gms-type-element\": \"labels.text\",\n                \"microg:gms-type-feature\": \"poi\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"poi\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"bus\",\n                        \"railway\"\n                    ],\n                    false,\n                    true\n                ],\n                [\n                    \"any\",\n                    [\n                        \"!=\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ],\n                            [\n                                \"park\",\n                                \"cemetery\"\n                            ],\n                            true,\n                            false\n                        ],\n                        [\n                            \"<=\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            250\n                        ]\n                    ],\n                    [\n                        \">=\",\n                        [\n                            \"zoom\"\n                        ],\n                        16\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-optional\": false,\n                \"text-line-height\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    15,\n                    1.2\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    13,\n                    15,\n                    14\n                ],\n                \"icon-offset\": [\n                    0,\n                    -36\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"museum\",\n                        \"theatre\",\n                        \"restaurant\"\n                    ],\n                    [\n                        \"concat\",\n                        \"poi_\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ]\n                    ],\n                    [\n                        \"fitness_centre\",\n                        \"golf_course\",\n                        \"camp_site\",\n                        \"bowling_alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic_site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog_park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"poi_generic_green\",\n                    [\n                        \"bank\",\n                        \"atm\",\n                        \"parking\",\n                        \"toilets\",\n                        \"garages\"\n                    ],\n                    \"poi_generic_purple\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\"\n                    ],\n                    \"poi_generic_orange\",\n                    [\n                        \"casino\",\n                        \"castle\",\n                        \"gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music_venue\",\n                        \"monument\"\n                    ],\n                    \"poi_generic_teal\",\n                    [\n                        \"hospital\",\n                        \"doctors\"\n                    ],\n                    \"poi_generic_red\",\n                    [\n                        \"fast_food\",\n                        \"ice_cream\"\n                    ],\n                    \"poi_restaurant\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"lodging\",\n                            \"grocery\"\n                        ],\n                        [\n                            \"concat\",\n                            \"poi_\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ]\n                        ],\n                        [\n                            \"clothing_store\",\n                            \"shop\"\n                        ],\n                        \"poi_generic_blue\",\n                        \"poi_generic\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-offset\": [\n                    0,\n                    -2\n                ],\n                \"icon-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.25,\n                    15,\n                    0.32\n                ],\n                \"text-anchor\": \"bottom\",\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-padding\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    30,\n                    17,\n                    5\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"fitness_centre\",\n                        \"golf_course\",\n                        \"camp_site\",\n                        \"bowling_alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic_site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog_park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"hsl(117, 53%, 65%)\",\n                    [\n                        \"bank\",\n                        \"atm\",\n                        \"parking\",\n                        \"toilets\",\n                        \"garages\"\n                    ],\n                    \"hsl(228, 17%, 65%)\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\",\n                        \"fast_food\",\n                        \"restaurant\",\n                        \"ice_cream\"\n                    ],\n                    \"hsl(20, 50%, 65%)\",\n                    [\n                        \"museum\",\n                        \"theatre\",\n                        \"casino\",\n                        \"castle\",\n                        \"gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music_venue\",\n                        \"monument\"\n                    ],\n                    \"hsl(186, 78%, 65%)\",\n                    [\n                        \"hospital\",\n                        \"doctors\"\n                    ],\n                    \"hsl(359, 22%, 65%)\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"lodging\"\n                        ],\n                        \"#df7db1\",\n                        [\n                            \"grocery\",\n                            \"clothing_store\",\n                            \"shop\"\n                        ],\n                        \"hsl(213, 40%, 65%)\",\n                        \"hsl(201, 9%, 80%)\"\n                    ]\n                ],\n                \"text-halo-color\": \"#000000\",\n                \"text-halo-width\": 1,\n                \"icon-translate\": [\n                    0,\n                    0\n                ],\n                \"text-translate\": [\n                    0,\n                    0\n                ],\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"poi_label_left\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"124a9d7a8e5226775d947c592110dfad\",\n                \"microg:gms-type-element\": \"labels.text\",\n                \"microg:gms-type-feature\": \"poi\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"poi\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"bus\",\n                        \"railway\"\n                    ],\n                    false,\n                    true\n                ],\n                [\n                    \"any\",\n                    [\n                        \"!=\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ],\n                            [\n                                \"park\",\n                                \"cemetery\"\n                            ],\n                            true,\n                            false\n                        ],\n                        [\n                            \"<=\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            250\n                        ]\n                    ],\n                    [\n                        \">=\",\n                        [\n                            \"zoom\"\n                        ],\n                        16\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-line-height\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    15,\n                    1.2\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    13,\n                    15,\n                    14\n                ],\n                \"icon-offset\": [\n                    0,\n                    -36\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"museum\",\n                        \"theatre\",\n                        \"restaurant\"\n                    ],\n                    [\n                        \"concat\",\n                        \"poi_\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ]\n                    ],\n                    [\n                        \"fitness_centre\",\n                        \"golf_course\",\n                        \"camp_site\",\n                        \"bowling_alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic_site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog_park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"poi_generic_green\",\n                    [\n                        \"bank\",\n                        \"atm\",\n                        \"parking\",\n                        \"toilets\",\n                        \"garages\"\n                    ],\n                    \"poi_generic_purple\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\"\n                    ],\n                    \"poi_generic_orange\",\n                    [\n                        \"casino\",\n                        \"castle\",\n                        \"gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music_venue\",\n                        \"monument\"\n                    ],\n                    \"poi_generic_teal\",\n                    [\n                        \"hospital\",\n                        \"doctors\"\n                    ],\n                    \"poi_generic_red\",\n                    [\n                        \"fast_food\",\n                        \"ice_cream\"\n                    ],\n                    \"poi_restaurant\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"lodging\",\n                            \"grocery\"\n                        ],\n                        [\n                            \"concat\",\n                            \"poi_\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ]\n                        ],\n                        [\n                            \"clothing_store\",\n                            \"shop\"\n                        ],\n                        \"poi_generic_blue\",\n                        \"poi_generic\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-justify\": \"right\",\n                \"text-offset\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    [\n                        \"literal\",\n                        [\n                            -1.1,\n                            -0.7\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            -1.1,\n                            -0.9\n                        ]\n                    ]\n                ],\n                \"icon-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.25,\n                    15,\n                    0.32\n                ],\n                \"text-anchor\": \"right\",\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-padding\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    30,\n                    17,\n                    5\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"fitness_centre\",\n                        \"golf_course\",\n                        \"camp_site\",\n                        \"bowling_alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic_site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog_park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"hsl(117, 53%, 65%)\",\n                    [\n                        \"bank\",\n                        \"atm\",\n                        \"parking\",\n                        \"toilets\",\n                        \"garages\"\n                    ],\n                    \"hsl(228, 17%, 65%)\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\",\n                        \"fast_food\",\n                        \"restaurant\",\n                        \"ice_cream\"\n                    ],\n                    \"hsl(20, 50%, 65%)\",\n                    [\n                        \"museum\",\n                        \"theatre\",\n                        \"casino\",\n                        \"castle\",\n                        \"gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music_venue\",\n                        \"monument\"\n                    ],\n                    \"hsl(186, 78%, 65%)\",\n                    [\n                        \"hospital\",\n                        \"doctors\"\n                    ],\n                    \"hsl(359, 22%, 65%)\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"lodging\"\n                        ],\n                        \"#df7db1\",\n                        [\n                            \"grocery\",\n                            \"clothing_store\",\n                            \"shop\"\n                        ],\n                        \"hsl(213, 40%, 65%)\",\n                        \"hsl(201, 9%, 80%)\"\n                    ]\n                ],\n                \"text-halo-color\": \"#000000\",\n                \"text-halo-width\": 1,\n                \"icon-translate\": [\n                    0,\n                    0\n                ],\n                \"text-translate\": [\n                    0,\n                    0\n                ],\n                \"text-halo-blur\": 1\n            }\n        },\n        {\n            \"id\": \"poi_label_right\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"mapbox:group\": \"124a9d7a8e5226775d947c592110dfad\",\n                \"microg:gms-type-element\": \"labels.text\",\n                \"microg:gms-type-feature\": \"poi\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"poi\",\n            \"minzoom\": 14,\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"bus\",\n                        \"railway\"\n                    ],\n                    false,\n                    true\n                ],\n                [\n                    \"any\",\n                    [\n                        \"!=\",\n                        [\n                            \"match\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ],\n                            [\n                                \"park\",\n                                \"cemetery\"\n                            ],\n                            true,\n                            false\n                        ],\n                        [\n                            \"<=\",\n                            [\n                                \"get\",\n                                \"rank\"\n                            ],\n                            250\n                        ]\n                    ],\n                    [\n                        \">=\",\n                        [\n                            \"zoom\"\n                        ],\n                        16\n                    ]\n                ]\n            ],\n            \"layout\": {\n                \"text-line-height\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    1,\n                    15,\n                    1.2\n                ],\n                \"text-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    13,\n                    15,\n                    14\n                ],\n                \"icon-offset\": [\n                    0,\n                    -36\n                ],\n                \"icon-image\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"museum\",\n                        \"theatre\",\n                        \"restaurant\"\n                    ],\n                    [\n                        \"concat\",\n                        \"poi_\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ]\n                    ],\n                    [\n                        \"fitness_centre\",\n                        \"golf_course\",\n                        \"camp_site\",\n                        \"bowling_alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic_site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog_park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"poi_generic_green\",\n                    [\n                        \"bank\",\n                        \"atm\",\n                        \"parking\",\n                        \"toilets\",\n                        \"garages\"\n                    ],\n                    \"poi_generic_purple\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\"\n                    ],\n                    \"poi_generic_orange\",\n                    [\n                        \"casino\",\n                        \"castle\",\n                        \"gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music_venue\",\n                        \"monument\"\n                    ],\n                    \"poi_generic_teal\",\n                    [\n                        \"hospital\",\n                        \"doctors\"\n                    ],\n                    \"poi_generic_red\",\n                    [\n                        \"fast_food\",\n                        \"ice_cream\"\n                    ],\n                    \"poi_restaurant\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"lodging\",\n                            \"grocery\"\n                        ],\n                        [\n                            \"concat\",\n                            \"poi_\",\n                            [\n                                \"get\",\n                                \"class\"\n                            ]\n                        ],\n                        [\n                            \"clothing_store\",\n                            \"shop\"\n                        ],\n                        \"poi_generic_blue\",\n                        \"poi_generic\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Roboto Regular\"\n                ],\n                \"text-justify\": \"left\",\n                \"text-offset\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    [\n                        \"literal\",\n                        [\n                            1.1,\n                            -0.7\n                        ]\n                    ],\n                    15,\n                    [\n                        \"literal\",\n                        [\n                            1.1,\n                            -0.9\n                        ]\n                    ]\n                ],\n                \"icon-size\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    0.25,\n                    15,\n                    0.32\n                ],\n                \"text-anchor\": \"left\",\n                \"text-field\": [\n                    \"to-string\",\n                    [\n                        \"get\",\n                        \"name\"\n                    ]\n                ],\n                \"text-padding\": [\n                    \"interpolate\",\n                    [\n                        \"linear\"\n                    ],\n                    [\n                        \"zoom\"\n                    ],\n                    14,\n                    30,\n                    17,\n                    5\n                ]\n            },\n            \"paint\": {\n                \"text-color\": [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"subclass\"\n                    ],\n                    [\n                        \"fitness_centre\",\n                        \"golf_course\",\n                        \"camp_site\",\n                        \"bowling_alley\",\n                        \"park\",\n                        \"garden\",\n                        \"farm\",\n                        \"picnic_site\",\n                        \"zoo\",\n                        \"stadium\",\n                        \"dog_park\",\n                        \"pitch\",\n                        \"cemetery\"\n                    ],\n                    \"hsl(117, 53%, 65%)\",\n                    [\n                        \"bank\",\n                        \"atm\",\n                        \"parking\",\n                        \"toilets\",\n                        \"garages\"\n                    ],\n                    \"hsl(228, 17%, 65%)\",\n                    [\n                        \"bar\",\n                        \"cafe\",\n                        \"bakery\",\n                        \"fast_food\",\n                        \"restaurant\",\n                        \"ice_cream\"\n                    ],\n                    \"hsl(20, 50%, 65%)\",\n                    [\n                        \"museum\",\n                        \"theatre\",\n                        \"casino\",\n                        \"castle\",\n                        \"gallery\",\n                        \"attraction\",\n                        \"cinema\",\n                        \"music_venue\",\n                        \"monument\"\n                    ],\n                    \"hsl(186, 78%, 65%)\",\n                    [\n                        \"hospital\",\n                        \"doctors\"\n                    ],\n                    \"hsl(359, 22%, 65%)\",\n                    [\n                        \"match\",\n                        [\n                            \"get\",\n                            \"class\"\n                        ],\n                        [\n                            \"lodging\"\n                        ],\n                        \"#df7db1\",\n                        [\n                            \"grocery\",\n                            \"clothing_store\",\n                            \"shop\"\n                        ],\n                        \"hsl(213, 40%, 65%)\",\n                        \"hsl(201, 9%, 80%)\"\n                    ]\n                ],\n                \"text-halo-color\": \"#000000\",\n                \"text-halo-width\": 1,\n                \"icon-translate\": [\n                    0,\n                    0\n                ],\n                \"text-translate\": [\n                    0,\n                    0\n                ],\n                \"text-halo-blur\": 1\n            }\n        }\n    ],\n    \"created\": \"2019-04-15T08:41:40.148Z\",\n    \"modified\": \"2020-09-05T19:42:03.856Z\",\n    \"id\": \"cjui4020201oo1fmca7yuwbor\",\n    \"owner\": \"microg\",\n    \"visibility\": \"public\",\n    \"protected\": false,\n    \"draft\": false\n}\n"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/assets/style-stadia-outdoors.json",
    "content": "{\n    \"bearing\": 0,\n    \"center\": [\n        8.542,\n        47.372\n    ],\n    \"glyphs\": \"https://tiles.stadiamaps.com/fonts/{fontstack}/{range}.pbf\",\n    \"layers\": [\n        {\n            \"id\": \"background\",\n            \"paint\": {\n                \"background-color\": \"#f9f3ea\"\n            },\n            \"type\": \"background\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"==\",\n                \"subclass\",\n                \"glacier\"\n            ],\n            \"id\": \"landcover-glacier\",\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": \"#fff\",\n                \"fill-opacity\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            0,\n                            0.9\n                        ],\n                        [\n                            10,\n                            0.3\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"landcover\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"==\",\n                \"$type\",\n                \"Polygon\"\n            ],\n            \"id\": \"park\",\n            \"paint\": {\n                \"fill-color\": \"#d8e8c8\",\n                \"fill-opacity\": {\n                    \"base\": 1.8,\n                    \"stops\": [\n                        [\n                            6,\n                            0.5\n                        ],\n                        [\n                            12,\n                            0.2\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"park\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"==\",\n                \"class\",\n                \"cemetery\"\n            ],\n            \"id\": \"landuse-cemetery\",\n            \"paint\": {\n                \"fill-color\": \"#e0e4dd\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"landuse\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"==\",\n                \"class\",\n                \"railway\"\n            ],\n            \"id\": \"landuse-railway\",\n            \"paint\": {\n                \"fill-color\": \"hsla(30, 19%, 90%, 0.4)\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"landuse\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"in\",\n                \"class\",\n                \"public_park\",\n                \"national_park\",\n                \"nature_reserve\"\n            ],\n            \"id\": \"landcover-grass-park\",\n            \"paint\": {\n                \"fill-antialias\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            0,\n                            false\n                        ],\n                        [\n                            9,\n                            true\n                        ]\n                    ]\n                },\n                \"fill-color\": \"#d5e8c2\",\n                \"fill-outline-color\": \"hsla(0, 0%, 0%, 0.1)\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"park\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"poi.park\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"class\",\n                    \"rock\"\n                ]\n            ],\n            \"id\": \"landcover-rock\",\n            \"paint\": {\n                \"fill-color\": \"hsla(0, 0%, 85%, 1)\",\n                \"fill-opacity\": 1,\n                \"fill-outline-color\": \"hsla(0, 0%, 0%, 0.1)\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"landcover\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"class\",\n                    \"sand\"\n                ]\n            ],\n            \"id\": \"landcover-sand\",\n            \"paint\": {\n                \"fill-color\": \"hsla(44, 70%, 87%, 1)\",\n                \"fill-opacity\": 1,\n                \"fill-outline-color\": \"hsla(0, 0%, 0%, 0.1)\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"landcover\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"==\",\n                \"class\",\n                \"wetland\"\n            ],\n            \"id\": \"landcover-wetland\",\n            \"paint\": {\n                \"fill-antialias\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            0,\n                            false\n                        ],\n                        [\n                            9,\n                            true\n                        ]\n                    ]\n                },\n                \"fill-color\": \"#3D85C6\",\n                \"fill-opacity\": 0.075,\n                \"fill-outline-color\": \"hsla(0, 0%, 0%, 0.03)\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"landcover\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"==\",\n                \"class\",\n                \"wood\"\n            ],\n            \"id\": \"landcover-wood\",\n            \"paint\": {\n                \"fill-antialias\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            0,\n                            false\n                        ],\n                        [\n                            9,\n                            true\n                        ]\n                    ]\n                },\n                \"fill-color\": \"#90d86c\",\n                \"fill-opacity\": 0.15,\n                \"fill-outline-color\": \"hsla(0, 0%, 0%, 0.2)\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"landcover\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"==\",\n                \"class\",\n                \"grass\"\n            ],\n            \"id\": \"landcover-grass\",\n            \"paint\": {\n                \"fill-color\": \"#d8e8c8\",\n                \"fill-opacity\": 1\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"landcover\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"!in\",\n                \"class\",\n                \"canal\",\n                \"river\",\n                \"stream\"\n            ],\n            \"id\": \"waterway-other\",\n            \"layout\": {\n                \"line-cap\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#a0c8f0\",\n                \"line-width\": {\n                    \"base\": 1.3,\n                    \"stops\": [\n                        [\n                            13,\n                            0.5\n                        ],\n                        [\n                            20,\n                            2\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"waterway\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"in\",\n                \"class\",\n                \"canal\",\n                \"stream\"\n            ],\n            \"id\": \"waterway-stream-canal\",\n            \"layout\": {\n                \"line-cap\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#a0c8f0\",\n                \"line-width\": {\n                    \"base\": 1.3,\n                    \"stops\": [\n                        [\n                            13,\n                            0.5\n                        ],\n                        [\n                            20,\n                            6\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"waterway\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"==\",\n                \"class\",\n                \"river\"\n            ],\n            \"id\": \"waterway-river\",\n            \"layout\": {\n                \"line-cap\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#a0c8f0\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            10,\n                            0.8\n                        ],\n                        [\n                            20,\n                            6\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"waterway\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"in\",\n                    \"admin_level\",\n                    4\n                ],\n                [\n                    \"!=\",\n                    \"maritime\",\n                    1\n                ]\n            ],\n            \"id\": \"boundary-land-level-4\",\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#9e9cab\",\n                \"line-dasharray\": [\n                    4,\n                    2,\n                    2,\n                    2\n                ],\n                \"line-opacity\": 0.5,\n                \"line-width\": {\n                    \"base\": 1.4,\n                    \"stops\": [\n                        [\n                            4,\n                            0.4\n                        ],\n                        [\n                            5,\n                            0.8\n                        ],\n                        [\n                            12,\n                            2.5\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"boundary\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"administrative.province\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"admin_level\",\n                    2\n                ],\n                [\n                    \"!=\",\n                    \"maritime\",\n                    1\n                ],\n                [\n                    \"!=\",\n                    \"disputed\",\n                    1\n                ]\n            ],\n            \"id\": \"boundary-land-level-2\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"hsl(248, 7%, 66%)\",\n                \"line-width\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            0,\n                            0.6\n                        ],\n                        [\n                            4,\n                            1.4\n                        ],\n                        [\n                            5,\n                            2\n                        ],\n                        [\n                            12,\n                            4\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"boundary\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"administrative.country\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"!=\",\n                    \"maritime\",\n                    1\n                ],\n                [\n                    \"==\",\n                    \"disputed\",\n                    1\n                ]\n            ],\n            \"id\": \"boundary-land-disputed\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"hsl(248, 7%, 70%)\",\n                \"line-dasharray\": [\n                    1,\n                    3\n                ],\n                \"line-width\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            0,\n                            0.6\n                        ],\n                        [\n                            4,\n                            1.4\n                        ],\n                        [\n                            5,\n                            2\n                        ],\n                        [\n                            12,\n                            4\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"boundary\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"administrative.country\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"==\",\n                \"$type\",\n                \"Polygon\"\n            ],\n            \"id\": \"water-offset\",\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"maxzoom\": 8,\n            \"minzoom\": 6,\n            \"paint\": {\n                \"fill-color\": \"#a0c8f0\",\n                \"fill-opacity\": 1,\n                \"fill-translate\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            6,\n                            [\n                                2,\n                                0\n                            ]\n                        ],\n                        [\n                            8,\n                            [\n                                0,\n                                0\n                            ]\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"water\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"water\",\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": \"hsl(210, 60%, 80%)\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"water\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"==\",\n                \"$type\",\n                \"Polygon\"\n            ],\n            \"id\": \"park-outline\",\n            \"layout\": {},\n            \"minzoom\": 6,\n            \"paint\": {\n                \"line-color\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            6,\n                            \"hsla(96, 40%, 49%, 0.36)\"\n                        ],\n                        [\n                            8,\n                            \"hsla(96, 40%, 49%, 0.66)\"\n                        ]\n                    ]\n                },\n                \"line-dasharray\": [\n                    3,\n                    3\n                ]\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"park\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"poi.park\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"==\",\n                \"subclass\",\n                \"ice_shelf\"\n            ],\n            \"id\": \"landcover-ice-shelf\",\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": \"#fff\",\n                \"fill-opacity\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            0,\n                            0.9\n                        ],\n                        [\n                            10,\n                            0.3\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"landcover\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"id\": \"building\",\n            \"paint\": {\n                \"fill-antialias\": true,\n                \"fill-color\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            15.5,\n                            \"#f2eae2\"\n                        ],\n                        [\n                            16,\n                            \"#dfdbd7\"\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"building\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"id\": \"building-top\",\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-color\": \"#f2eae2\",\n                \"fill-opacity\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            13,\n                            0\n                        ],\n                        [\n                            16,\n                            1\n                        ]\n                    ]\n                },\n                \"fill-outline-color\": \"#dfdbd7\",\n                \"fill-translate\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            14,\n                            [\n                                0,\n                                0\n                            ]\n                        ],\n                        [\n                            16,\n                            [\n                                -2,\n                                -2\n                            ]\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"building\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"tunnel\"\n                ],\n                [\n                    \"in\",\n                    \"class\",\n                    \"service\",\n                    \"track\"\n                ]\n            ],\n            \"id\": \"tunnel-service-track-casing\",\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#cfcdca\",\n                \"line-dasharray\": [\n                    0.5,\n                    0.25\n                ],\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            15,\n                            1\n                        ],\n                        [\n                            16,\n                            4\n                        ],\n                        [\n                            20,\n                            11\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"tunnel\"\n                ],\n                [\n                    \"==\",\n                    \"class\",\n                    \"minor\"\n                ]\n            ],\n            \"id\": \"tunnel-minor-casing\",\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#cfcdca\",\n                \"line-opacity\": {\n                    \"stops\": [\n                        [\n                            12,\n                            0\n                        ],\n                        [\n                            12.5,\n                            1\n                        ]\n                    ]\n                },\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            12,\n                            0.5\n                        ],\n                        [\n                            13,\n                            1\n                        ],\n                        [\n                            14,\n                            4\n                        ],\n                        [\n                            20,\n                            15\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"tunnel\"\n                ],\n                [\n                    \"in\",\n                    \"class\",\n                    \"secondary\",\n                    \"tertiary\"\n                ]\n            ],\n            \"id\": \"tunnel-secondary-tertiary-casing\",\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#e9ac77\",\n                \"line-opacity\": 1,\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            8,\n                            1.5\n                        ],\n                        [\n                            20,\n                            17\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"tunnel\"\n                ],\n                [\n                    \"in\",\n                    \"class\",\n                    \"primary\",\n                    \"trunk\"\n                ]\n            ],\n            \"id\": \"tunnel-trunk-primary-casing\",\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#e9ac77\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            5,\n                            0.4\n                        ],\n                        [\n                            6,\n                            0.6\n                        ],\n                        [\n                            7,\n                            1.5\n                        ],\n                        [\n                            20,\n                            22\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"tunnel\"\n                ],\n                [\n                    \"==\",\n                    \"class\",\n                    \"motorway\"\n                ]\n            ],\n            \"id\": \"tunnel-motorway-casing\",\n            \"layout\": {\n                \"line-join\": \"round\",\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"line-color\": \"#e9ac77\",\n                \"line-dasharray\": [\n                    0.5,\n                    0.25\n                ],\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            5,\n                            0.4\n                        ],\n                        [\n                            6,\n                            0.6\n                        ],\n                        [\n                            7,\n                            1.5\n                        ],\n                        [\n                            20,\n                            22\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ],\n                [\n                    \"all\",\n                    [\n                        \"==\",\n                        \"brunnel\",\n                        \"tunnel\"\n                    ],\n                    [\n                        \"in\",\n                        \"class\",\n                        \"path\",\n                        \"footway\"\n                    ]\n                ]\n            ],\n            \"id\": \"tunnel-path\",\n            \"paint\": {\n                \"line-color\": \"#cba\",\n                \"line-dasharray\": [\n                    1.5,\n                    0.75\n                ],\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            15,\n                            1.2\n                        ],\n                        [\n                            20,\n                            4\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"tunnel\"\n                ],\n                [\n                    \"in\",\n                    \"class\",\n                    \"service\",\n                    \"track\"\n                ]\n            ],\n            \"id\": \"tunnel-service-track\",\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#fff\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            15.5,\n                            0\n                        ],\n                        [\n                            16,\n                            2\n                        ],\n                        [\n                            20,\n                            7.5\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"tunnel\"\n                ],\n                [\n                    \"==\",\n                    \"class\",\n                    \"minor_road\"\n                ]\n            ],\n            \"id\": \"tunnel-minor\",\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#fff\",\n                \"line-opacity\": 1,\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            13.5,\n                            0\n                        ],\n                        [\n                            14,\n                            2.5\n                        ],\n                        [\n                            20,\n                            11.5\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"tunnel\"\n                ],\n                [\n                    \"in\",\n                    \"class\",\n                    \"secondary\",\n                    \"tertiary\"\n                ]\n            ],\n            \"id\": \"tunnel-secondary-tertiary\",\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#fff4c6\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            6.5,\n                            0\n                        ],\n                        [\n                            7,\n                            0.5\n                        ],\n                        [\n                            20,\n                            10\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"tunnel\"\n                ],\n                [\n                    \"in\",\n                    \"class\",\n                    \"primary\",\n                    \"trunk\"\n                ]\n            ],\n            \"id\": \"tunnel-trunk-primary\",\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#fff4c6\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            6.5,\n                            0\n                        ],\n                        [\n                            7,\n                            0.5\n                        ],\n                        [\n                            20,\n                            18\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"tunnel\"\n                ],\n                [\n                    \"==\",\n                    \"class\",\n                    \"motorway\"\n                ]\n            ],\n            \"id\": \"tunnel-motorway\",\n            \"layout\": {\n                \"line-join\": \"round\",\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"line-color\": \"#ffdaa6\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            6.5,\n                            0\n                        ],\n                        [\n                            7,\n                            0.5\n                        ],\n                        [\n                            20,\n                            18\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"tunnel\"\n                ],\n                [\n                    \"==\",\n                    \"class\",\n                    \"rail\"\n                ]\n            ],\n            \"id\": \"tunnel-railway\",\n            \"paint\": {\n                \"line-color\": \"#bbb\",\n                \"line-dasharray\": [\n                    2,\n                    2\n                ],\n                \"line-width\": {\n                    \"base\": 1.4,\n                    \"stops\": [\n                        [\n                            14,\n                            0.4\n                        ],\n                        [\n                            15,\n                            0.75\n                        ],\n                        [\n                            20,\n                            2\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"in\",\n                    \"class\",\n                    \"ferry\"\n                ]\n            ],\n            \"id\": \"ferry\",\n            \"layout\": {\n                \"line-join\": \"round\",\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"line-color\": \"rgba(108, 159, 182, 1)\",\n                \"line-dasharray\": [\n                    2,\n                    2\n                ],\n                \"line-width\": 1.1\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"in\",\n                    \"class\",\n                    \"taxiway\"\n                ]\n            ],\n            \"id\": \"aeroway-taxiway-casing\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\",\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 12,\n            \"paint\": {\n                \"line-color\": \"rgba(153, 153, 153, 1)\",\n                \"line-opacity\": 1,\n                \"line-width\": {\n                    \"base\": 1.5,\n                    \"stops\": [\n                        [\n                            11,\n                            2\n                        ],\n                        [\n                            17,\n                            12\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"aeroway\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"in\",\n                    \"class\",\n                    \"runway\"\n                ]\n            ],\n            \"id\": \"aeroway-runway-casing\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\",\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 12,\n            \"paint\": {\n                \"line-color\": \"rgba(153, 153, 153, 1)\",\n                \"line-opacity\": 1,\n                \"line-width\": {\n                    \"base\": 1.5,\n                    \"stops\": [\n                        [\n                            11,\n                            5\n                        ],\n                        [\n                            17,\n                            55\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"aeroway\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"transit.station.airport\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"Polygon\"\n                ],\n                [\n                    \"in\",\n                    \"class\",\n                    \"runway\",\n                    \"taxiway\"\n                ]\n            ],\n            \"id\": \"aeroway-area\",\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 4,\n            \"paint\": {\n                \"fill-color\": \"rgba(255, 255, 255, 1)\",\n                \"fill-opacity\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            13,\n                            0\n                        ],\n                        [\n                            14,\n                            1\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"aeroway\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"transit.station.airport\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"in\",\n                    \"class\",\n                    \"taxiway\"\n                ],\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ]\n            ],\n            \"id\": \"aeroway-taxiway\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\",\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 4,\n            \"paint\": {\n                \"line-color\": \"rgba(255, 255, 255, 1)\",\n                \"line-opacity\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            11,\n                            0\n                        ],\n                        [\n                            12,\n                            1\n                        ]\n                    ]\n                },\n                \"line-width\": {\n                    \"base\": 1.5,\n                    \"stops\": [\n                        [\n                            11,\n                            1\n                        ],\n                        [\n                            17,\n                            10\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"aeroway\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"in\",\n                    \"class\",\n                    \"runway\"\n                ],\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ]\n            ],\n            \"id\": \"aeroway-runway\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\",\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 4,\n            \"paint\": {\n                \"line-color\": \"rgba(255, 255, 255, 1)\",\n                \"line-opacity\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            11,\n                            0\n                        ],\n                        [\n                            12,\n                            1\n                        ]\n                    ]\n                },\n                \"line-width\": {\n                    \"base\": 1.5,\n                    \"stops\": [\n                        [\n                            11,\n                            4\n                        ],\n                        [\n                            17,\n                            50\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"aeroway\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"transit.station.airport\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"==\",\n                \"$type\",\n                \"Polygon\"\n            ],\n            \"id\": \"highway-area\",\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"fill-antialias\": false,\n                \"fill-color\": \"hsla(0, 0%, 89%, 0.56)\",\n                \"fill-opacity\": 0.9,\n                \"fill-outline-color\": \"#cfcdca\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"fill\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"!in\",\n                    \"brunnel\",\n                    \"bridge\",\n                    \"tunnel\"\n                ],\n                [\n                    \"==\",\n                    \"class\",\n                    \"motorway_link\"\n                ]\n            ],\n            \"id\": \"highway-motorway-link-casing\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\"\n            },\n            \"minzoom\": 12,\n            \"paint\": {\n                \"line-color\": \"#e9ac77\",\n                \"line-opacity\": 1,\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            12,\n                            1\n                        ],\n                        [\n                            13,\n                            3\n                        ],\n                        [\n                            14,\n                            4\n                        ],\n                        [\n                            20,\n                            15\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"!in\",\n                    \"brunnel\",\n                    \"bridge\",\n                    \"tunnel\"\n                ],\n                [\n                    \"in\",\n                    \"class\",\n                    \"primary_link\",\n                    \"secondary_link\",\n                    \"tertiary_link\",\n                    \"trunk_link\"\n                ]\n            ],\n            \"id\": \"highway-link-casing\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\",\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 13,\n            \"paint\": {\n                \"line-color\": \"#e9ac77\",\n                \"line-opacity\": 1,\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            12,\n                            1\n                        ],\n                        [\n                            13,\n                            3\n                        ],\n                        [\n                            14,\n                            4\n                        ],\n                        [\n                            20,\n                            15\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ],\n                [\n                    \"all\",\n                    [\n                        \"!=\",\n                        \"brunnel\",\n                        \"tunnel\"\n                    ],\n                    [\n                        \"in\",\n                        \"class\",\n                        \"minor\",\n                        \"service\",\n                        \"track\"\n                    ]\n                ]\n            ],\n            \"id\": \"highway-minor-casing\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#cfcdca\",\n                \"line-opacity\": {\n                    \"stops\": [\n                        [\n                            12,\n                            0\n                        ],\n                        [\n                            12.5,\n                            1\n                        ]\n                    ]\n                },\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            12,\n                            0.5\n                        ],\n                        [\n                            13,\n                            1\n                        ],\n                        [\n                            14,\n                            4\n                        ],\n                        [\n                            20,\n                            15\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"!in\",\n                    \"brunnel\",\n                    \"bridge\",\n                    \"tunnel\"\n                ],\n                [\n                    \"in\",\n                    \"class\",\n                    \"secondary\",\n                    \"tertiary\"\n                ]\n            ],\n            \"id\": \"highway-secondary-tertiary-casing\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\",\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"line-color\": \"#e9ac77\",\n                \"line-opacity\": 1,\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            6,\n                            1.5\n                        ],\n                        [\n                            20,\n                            17\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"!in\",\n                    \"brunnel\",\n                    \"bridge\",\n                    \"tunnel\"\n                ],\n                [\n                    \"in\",\n                    \"class\",\n                    \"primary\"\n                ]\n            ],\n            \"id\": \"highway-primary-casing\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\",\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 5,\n            \"paint\": {\n                \"line-color\": \"#e9ac77\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            5,\n                            0.5\n                        ],\n                        [\n                            8,\n                            0.6\n                        ],\n                        [\n                            9,\n                            1.5\n                        ],\n                        [\n                            20,\n                            22\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"!in\",\n                    \"brunnel\",\n                    \"bridge\",\n                    \"tunnel\"\n                ],\n                [\n                    \"in\",\n                    \"class\",\n                    \"trunk\"\n                ]\n            ],\n            \"id\": \"highway-trunk-casing\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\",\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 5,\n            \"paint\": {\n                \"line-color\": \"#e9ac77\",\n                \"line-opacity\": {\n                    \"stops\": [\n                        [\n                            5,\n                            0\n                        ],\n                        [\n                            6,\n                            1\n                        ]\n                    ]\n                },\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            5,\n                            0\n                        ],\n                        [\n                            6,\n                            0.6\n                        ],\n                        [\n                            7,\n                            1.5\n                        ],\n                        [\n                            20,\n                            22\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"!in\",\n                    \"brunnel\",\n                    \"bridge\",\n                    \"tunnel\"\n                ],\n                [\n                    \"==\",\n                    \"class\",\n                    \"motorway\"\n                ]\n            ],\n            \"id\": \"highway-motorway-casing\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\",\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 4,\n            \"paint\": {\n                \"line-color\": \"#e9ac77\",\n                \"line-opacity\": {\n                    \"stops\": [\n                        [\n                            4,\n                            0\n                        ],\n                        [\n                            5,\n                            1\n                        ]\n                    ]\n                },\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            4,\n                            0\n                        ],\n                        [\n                            5,\n                            0.4\n                        ],\n                        [\n                            6,\n                            0.6\n                        ],\n                        [\n                            7,\n                            1.5\n                        ],\n                        [\n                            20,\n                            22\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ],\n                [\n                    \"all\",\n                    [\n                        \"!in\",\n                        \"brunnel\",\n                        \"bridge\",\n                        \"tunnel\"\n                    ],\n                    [\n                        \"in\",\n                        \"class\",\n                        \"path\",\n                        \"footway\"\n                    ]\n                ]\n            ],\n            \"id\": \"highway-path\",\n            \"paint\": {\n                \"line-color\": \"#cba\",\n                \"line-dasharray\": {\n                    \"stops\": [\n                        [\n                            13,\n                            [\n                                1,\n                                0.5\n                            ]\n                        ],\n                        [\n                            14,\n                            [\n                                2,\n                                1\n                            ]\n                        ],\n                        [\n                            20,\n                            [\n                                3,\n                                1\n                            ]\n                        ]\n                    ]\n                },\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            13,\n                            1\n                        ],\n                        [\n                            14,\n                            2\n                        ],\n                        [\n                            20,\n                            4\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"!in\",\n                    \"brunnel\",\n                    \"bridge\",\n                    \"tunnel\"\n                ],\n                [\n                    \"==\",\n                    \"class\",\n                    \"motorway_link\"\n                ]\n            ],\n            \"id\": \"highway-motorway-link\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\"\n            },\n            \"minzoom\": 12,\n            \"paint\": {\n                \"line-color\": \"#e5b87e\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            12.5,\n                            0\n                        ],\n                        [\n                            13,\n                            1.5\n                        ],\n                        [\n                            14,\n                            2.5\n                        ],\n                        [\n                            20,\n                            11.5\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"!in\",\n                    \"brunnel\",\n                    \"bridge\",\n                    \"tunnel\"\n                ],\n                [\n                    \"in\",\n                    \"class\",\n                    \"primary_link\",\n                    \"secondary_link\",\n                    \"tertiary_link\",\n                    \"trunk_link\"\n                ]\n            ],\n            \"id\": \"highway-link\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\",\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 13,\n            \"paint\": {\n                \"line-color\": \"#e5d7a0\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            12.5,\n                            0\n                        ],\n                        [\n                            13,\n                            1.5\n                        ],\n                        [\n                            14,\n                            2.5\n                        ],\n                        [\n                            20,\n                            11.5\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"in\",\n                    \"class\",\n                    \"downhill\",\n                    \"nordic\"\n                ],\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ]\n            ],\n            \"id\": \"ski-slopes-line\",\n            \"minzoom\": 11,\n            \"paint\": {\n                \"line-blur\": 0.5,\n                \"line-color\": \"rgba(75, 122, 195, 1)\",\n                \"line-dasharray\": [\n                    3,\n                    2\n                ],\n                \"line-width\": {\n                    \"stops\": [\n                        [\n                            10,\n                            1\n                        ],\n                        [\n                            13,\n                            1.5\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"piste\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"poi.sports_complex\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ],\n                [\n                    \"all\",\n                    [\n                        \"!=\",\n                        \"brunnel\",\n                        \"tunnel\"\n                    ],\n                    [\n                        \"in\",\n                        \"class\",\n                        \"minor\",\n                        \"service\",\n                        \"track\"\n                    ]\n                ]\n            ],\n            \"id\": \"highway-minor\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#fff\",\n                \"line-opacity\": 1,\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            13.5,\n                            0\n                        ],\n                        [\n                            14,\n                            2.5\n                        ],\n                        [\n                            20,\n                            11.5\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"!in\",\n                    \"brunnel\",\n                    \"bridge\",\n                    \"tunnel\"\n                ],\n                [\n                    \"in\",\n                    \"class\",\n                    \"secondary\",\n                    \"tertiary\"\n                ]\n            ],\n            \"id\": \"highway-secondary-tertiary\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\",\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"line-color\": \"#e5d7a0\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            6.5,\n                            0\n                        ],\n                        [\n                            8,\n                            0.5\n                        ],\n                        [\n                            20,\n                            13\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ],\n                [\n                    \"all\",\n                    [\n                        \"!in\",\n                        \"brunnel\",\n                        \"bridge\",\n                        \"tunnel\"\n                    ],\n                    [\n                        \"in\",\n                        \"class\",\n                        \"primary\"\n                    ]\n                ]\n            ],\n            \"id\": \"highway-primary\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\",\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"line-color\": \"#e5d7a0\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            5,\n                            0.1\n                        ],\n                        [\n                            9,\n                            0.5\n                        ],\n                        [\n                            20,\n                            18\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ],\n                [\n                    \"all\",\n                    [\n                        \"!in\",\n                        \"brunnel\",\n                        \"bridge\",\n                        \"tunnel\"\n                    ],\n                    [\n                        \"in\",\n                        \"class\",\n                        \"trunk\"\n                    ]\n                ]\n            ],\n            \"id\": \"highway-trunk\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\",\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"line-color\": \"#e5d7a0\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            6.5,\n                            0\n                        ],\n                        [\n                            7,\n                            0.5\n                        ],\n                        [\n                            20,\n                            18\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ],\n                [\n                    \"all\",\n                    [\n                        \"!in\",\n                        \"brunnel\",\n                        \"bridge\",\n                        \"tunnel\"\n                    ],\n                    [\n                        \"==\",\n                        \"class\",\n                        \"motorway\"\n                    ]\n                ]\n            ],\n            \"id\": \"highway-motorway\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"line-join\": \"round\",\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 5,\n            \"paint\": {\n                \"line-color\": \"#e5b87e\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            6.5,\n                            0\n                        ],\n                        [\n                            7,\n                            0.5\n                        ],\n                        [\n                            20,\n                            10\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ],\n                [\n                    \"all\",\n                    [\n                        \"==\",\n                        \"class\",\n                        \"transit\"\n                    ],\n                    [\n                        \"!in\",\n                        \"brunnel\",\n                        \"tunnel\"\n                    ]\n                ]\n            ],\n            \"id\": \"railway-transit\",\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"line-color\": \"hsla(0, 0%, 73%, 0.77)\",\n                \"line-width\": {\n                    \"base\": 1.4,\n                    \"stops\": [\n                        [\n                            14,\n                            0.4\n                        ],\n                        [\n                            20,\n                            1\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ],\n                [\n                    \"all\",\n                    [\n                        \"==\",\n                        \"class\",\n                        \"transit\"\n                    ],\n                    [\n                        \"!in\",\n                        \"brunnel\",\n                        \"tunnel\"\n                    ]\n                ]\n            ],\n            \"id\": \"railway-transit-hatching\",\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"line-color\": \"hsla(0, 0%, 73%, 0.68)\",\n                \"line-dasharray\": [\n                    0.2,\n                    8\n                ],\n                \"line-width\": {\n                    \"base\": 1.4,\n                    \"stops\": [\n                        [\n                            14.5,\n                            0\n                        ],\n                        [\n                            15,\n                            2\n                        ],\n                        [\n                            20,\n                            6\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ],\n                [\n                    \"all\",\n                    [\n                        \"==\",\n                        \"class\",\n                        \"rail\"\n                    ],\n                    [\n                        \"has\",\n                        \"service\"\n                    ]\n                ]\n            ],\n            \"id\": \"railway-service\",\n            \"paint\": {\n                \"line-color\": \"hsla(0, 0%, 73%, 0.77)\",\n                \"line-width\": {\n                    \"base\": 1.4,\n                    \"stops\": [\n                        [\n                            14,\n                            0.4\n                        ],\n                        [\n                            20,\n                            1\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ],\n                [\n                    \"all\",\n                    [\n                        \"==\",\n                        \"class\",\n                        \"rail\"\n                    ],\n                    [\n                        \"has\",\n                        \"service\"\n                    ]\n                ]\n            ],\n            \"id\": \"railway-service-hatching\",\n            \"layout\": {\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"line-color\": \"hsla(0, 0%, 73%, 0.68)\",\n                \"line-dasharray\": [\n                    0.2,\n                    8\n                ],\n                \"line-width\": {\n                    \"base\": 1.4,\n                    \"stops\": [\n                        [\n                            14.5,\n                            0\n                        ],\n                        [\n                            15,\n                            2\n                        ],\n                        [\n                            20,\n                            6\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ],\n                [\n                    \"all\",\n                    [\n                        \"!has\",\n                        \"service\"\n                    ],\n                    [\n                        \"!in\",\n                        \"brunnel\",\n                        \"bridge\",\n                        \"tunnel\"\n                    ],\n                    [\n                        \"==\",\n                        \"class\",\n                        \"rail\"\n                    ]\n                ]\n            ],\n            \"id\": \"railway\",\n            \"paint\": {\n                \"line-color\": \"#bbb\",\n                \"line-width\": {\n                    \"base\": 1.4,\n                    \"stops\": [\n                        [\n                            14,\n                            0.4\n                        ],\n                        [\n                            15,\n                            0.75\n                        ],\n                        [\n                            20,\n                            2\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ],\n                [\n                    \"all\",\n                    [\n                        \"!has\",\n                        \"service\"\n                    ],\n                    [\n                        \"!in\",\n                        \"brunnel\",\n                        \"bridge\",\n                        \"tunnel\"\n                    ],\n                    [\n                        \"==\",\n                        \"class\",\n                        \"rail\"\n                    ]\n                ]\n            ],\n            \"id\": \"railway-hatching\",\n            \"paint\": {\n                \"line-color\": \"#bbb\",\n                \"line-dasharray\": [\n                    0.2,\n                    8\n                ],\n                \"line-width\": {\n                    \"base\": 1.4,\n                    \"stops\": [\n                        [\n                            14.5,\n                            0\n                        ],\n                        [\n                            15,\n                            3\n                        ],\n                        [\n                            20,\n                            8\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"bridge\"\n                ],\n                [\n                    \"==\",\n                    \"class\",\n                    \"motorway_link\"\n                ]\n            ],\n            \"id\": \"bridge-motorway-link-casing\",\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#e9ac77\",\n                \"line-opacity\": 1,\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            12,\n                            1\n                        ],\n                        [\n                            13,\n                            3\n                        ],\n                        [\n                            14,\n                            4\n                        ],\n                        [\n                            20,\n                            15\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"bridge\"\n                ],\n                [\n                    \"in\",\n                    \"class\",\n                    \"primary_link\",\n                    \"secondary_link\",\n                    \"tertiary_link\",\n                    \"trunk_link\"\n                ]\n            ],\n            \"id\": \"bridge-link-casing\",\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#e9ac77\",\n                \"line-opacity\": 1,\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            12,\n                            1\n                        ],\n                        [\n                            13,\n                            3\n                        ],\n                        [\n                            14,\n                            4\n                        ],\n                        [\n                            20,\n                            15\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"bridge\"\n                ],\n                [\n                    \"in\",\n                    \"class\",\n                    \"secondary\",\n                    \"tertiary\"\n                ]\n            ],\n            \"id\": \"bridge-secondary-tertiary-casing\",\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#e9ac77\",\n                \"line-opacity\": 1,\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            8,\n                            1.5\n                        ],\n                        [\n                            20,\n                            28\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"bridge\"\n                ],\n                [\n                    \"in\",\n                    \"class\",\n                    \"primary\",\n                    \"trunk\"\n                ]\n            ],\n            \"id\": \"bridge-trunk-primary-casing\",\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"hsl(28, 76%, 67%)\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            5,\n                            0.4\n                        ],\n                        [\n                            6,\n                            0.6\n                        ],\n                        [\n                            7,\n                            1.5\n                        ],\n                        [\n                            20,\n                            26\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"bridge\"\n                ],\n                [\n                    \"==\",\n                    \"class\",\n                    \"motorway\"\n                ]\n            ],\n            \"id\": \"bridge-motorway-casing\",\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#e9ac77\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            5,\n                            0.4\n                        ],\n                        [\n                            6,\n                            0.6\n                        ],\n                        [\n                            7,\n                            1.5\n                        ],\n                        [\n                            20,\n                            22\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ],\n                [\n                    \"all\",\n                    [\n                        \"==\",\n                        \"brunnel\",\n                        \"bridge\"\n                    ],\n                    [\n                        \"in\",\n                        \"class\",\n                        \"path\",\n                        \"footway\"\n                    ]\n                ]\n            ],\n            \"id\": \"bridge-path-casing\",\n            \"paint\": {\n                \"line-color\": \"#f8f4f0\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            15,\n                            1.2\n                        ],\n                        [\n                            20,\n                            18\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.stroke\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ],\n                [\n                    \"all\",\n                    [\n                        \"==\",\n                        \"brunnel\",\n                        \"bridge\"\n                    ],\n                    [\n                        \"in\",\n                        \"class\",\n                        \"path\",\n                        \"footway\"\n                    ]\n                ]\n            ],\n            \"id\": \"bridge-path\",\n            \"paint\": {\n                \"line-color\": \"#cba\",\n                \"line-dasharray\": [\n                    1.5,\n                    0.75\n                ],\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            15,\n                            1.2\n                        ],\n                        [\n                            20,\n                            4\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"bridge\"\n                ],\n                [\n                    \"==\",\n                    \"class\",\n                    \"motorway_link\"\n                ]\n            ],\n            \"id\": \"bridge-motorway-link\",\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#e5b87e\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            12.5,\n                            0\n                        ],\n                        [\n                            13,\n                            1.5\n                        ],\n                        [\n                            14,\n                            2.5\n                        ],\n                        [\n                            20,\n                            11.5\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"bridge\"\n                ],\n                [\n                    \"in\",\n                    \"class\",\n                    \"primary_link\",\n                    \"secondary_link\",\n                    \"tertiary_link\",\n                    \"trunk_link\"\n                ]\n            ],\n            \"id\": \"bridge-link\",\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#e5d7a0\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            12.5,\n                            0\n                        ],\n                        [\n                            13,\n                            1.5\n                        ],\n                        [\n                            14,\n                            2.5\n                        ],\n                        [\n                            20,\n                            11.5\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"bridge\"\n                ],\n                [\n                    \"in\",\n                    \"class\",\n                    \"secondary\",\n                    \"tertiary\"\n                ]\n            ],\n            \"id\": \"bridge-secondary-tertiary\",\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#e5d7a0\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            6.5,\n                            0\n                        ],\n                        [\n                            7,\n                            0.5\n                        ],\n                        [\n                            20,\n                            20\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"bridge\"\n                ],\n                [\n                    \"in\",\n                    \"class\",\n                    \"primary\",\n                    \"trunk\"\n                ]\n            ],\n            \"id\": \"bridge-trunk-primary\",\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#e5d7a0\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            6.5,\n                            0\n                        ],\n                        [\n                            7,\n                            0.5\n                        ],\n                        [\n                            20,\n                            18\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"bridge\"\n                ],\n                [\n                    \"==\",\n                    \"class\",\n                    \"motorway\"\n                ]\n            ],\n            \"id\": \"bridge-motorway\",\n            \"layout\": {\n                \"line-join\": \"round\"\n            },\n            \"paint\": {\n                \"line-color\": \"#e5b87e\",\n                \"line-width\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            6.5,\n                            0\n                        ],\n                        [\n                            7,\n                            0.5\n                        ],\n                        [\n                            20,\n                            18\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.arterial\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"bridge\"\n                ],\n                [\n                    \"==\",\n                    \"class\",\n                    \"rail\"\n                ]\n            ],\n            \"id\": \"bridge-railway\",\n            \"paint\": {\n                \"line-color\": \"#bbb\",\n                \"line-width\": {\n                    \"base\": 1.4,\n                    \"stops\": [\n                        [\n                            14,\n                            0.4\n                        ],\n                        [\n                            15,\n                            0.75\n                        ],\n                        [\n                            20,\n                            2\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"brunnel\",\n                    \"bridge\"\n                ],\n                [\n                    \"==\",\n                    \"class\",\n                    \"rail\"\n                ]\n            ],\n            \"id\": \"bridge-railway-hatching\",\n            \"paint\": {\n                \"line-color\": \"#bbb\",\n                \"line-dasharray\": [\n                    0.2,\n                    8\n                ],\n                \"line-width\": {\n                    \"base\": 1.4,\n                    \"stops\": [\n                        [\n                            14.5,\n                            0\n                        ],\n                        [\n                            15,\n                            3\n                        ],\n                        [\n                            20,\n                            8\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.man_made\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"==\",\n                \"class\",\n                \"cable_car\"\n            ],\n            \"id\": \"cablecar\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 11,\n            \"paint\": {\n                \"line-color\": \"hsl(0, 0%, 70%)\",\n                \"line-width\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            11,\n                            1\n                        ],\n                        [\n                            19,\n                            2.5\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"==\",\n                \"class\",\n                \"cable_car\"\n            ],\n            \"id\": \"cablecar-dash\",\n            \"layout\": {\n                \"line-cap\": \"round\",\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 11,\n            \"paint\": {\n                \"line-color\": \"hsl(0, 0%, 70%)\",\n                \"line-dasharray\": [\n                    2,\n                    3\n                ],\n                \"line-width\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            11,\n                            3\n                        ],\n                        [\n                            19,\n                            5.5\n                        ]\n                    ]\n                }\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation\",\n            \"type\": \"line\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"transit.line\",\n                \"microg:gms-type-element\": \"geometry.fill\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ],\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"!=\",\n                    \"name\",\n                    \"\"\n                ]\n            ],\n            \"id\": \"waterway-name\",\n            \"layout\": {\n                \"symbol-placement\": \"line\",\n                \"symbol-spacing\": 350,\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"name:latin\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"all\",\n                            [\n                                \"has\",\n                                \"name:nonlatin\"\n                            ],\n                            [\n                                \"is-supported-script\",\n                                [\n                                    \"get\",\n                                    \"name:nonlatin\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"concat\",\n                            \" \",\n                            [\n                                \"get\",\n                                \"name:nonlatin\"\n                            ]\n                        ],\n                        \"\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Stadia Italic\"\n                ],\n                \"text-letter-spacing\": 0.2,\n                \"text-max-width\": 5,\n                \"text-pitch-alignment\": \"viewport\",\n                \"text-rotation-alignment\": \"map\",\n                \"text-size\": 14\n            },\n            \"minzoom\": 13,\n            \"paint\": {\n                \"text-color\": \"#115AA7\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"waterway\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"Point\"\n                ],\n                [\n                    \"!in\",\n                    \"class\",\n                    \"ocean\"\n                ]\n            ],\n            \"id\": \"water-name-other\",\n            \"layout\": {\n                \"symbol-placement\": \"point\",\n                \"symbol-spacing\": 150,\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"name:latin\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"all\",\n                            [\n                                \"has\",\n                                \"name:nonlatin\"\n                            ],\n                            [\n                                \"is-supported-script\",\n                                [\n                                    \"get\",\n                                    \"name:nonlatin\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"concat\",\n                            \"\\n\",\n                            [\n                                \"get\",\n                                \"name:nonlatin\"\n                            ]\n                        ],\n                        \"\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Stadia Italic\"\n                ],\n                \"text-letter-spacing\": 0.2,\n                \"text-line-height\": 1.55,\n                \"text-max-width\": 5,\n                \"text-size\": {\n                    \"stops\": [\n                        [\n                            0,\n                            10\n                        ],\n                        [\n                            6,\n                            14\n                        ]\n                    ]\n                },\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 1,\n            \"paint\": {\n                \"text-color\": \"#115AA7\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"water_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"Point\"\n                ],\n                [\n                    \"==\",\n                    \"class\",\n                    \"ocean\"\n                ]\n            ],\n            \"id\": \"water-name-ocean\",\n            \"layout\": {\n                \"symbol-avoid-edges\": true,\n                \"symbol-placement\": \"point\",\n                \"symbol-spacing\": 350,\n                \"text-field\": \"{name:latin}\",\n                \"text-font\": [\n                    \"Stadia Italic\"\n                ],\n                \"text-letter-spacing\": 0.2,\n                \"text-max-width\": 5,\n                \"text-size\": 14\n            },\n            \"paint\": {\n                \"text-color\": \"#115AA7\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"water_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"Point\"\n                ],\n                [\n                    \">=\",\n                    \"rank\",\n                    25\n                ]\n            ],\n            \"id\": \"poi-level-3\",\n            \"layout\": {\n                \"icon-image\": \"{class}_11\",\n                \"symbol-avoid-edges\": true,\n                \"text-anchor\": \"top\",\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"name:latin\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"all\",\n                            [\n                                \"has\",\n                                \"name:nonlatin\"\n                            ],\n                            [\n                                \"is-supported-script\",\n                                [\n                                    \"get\",\n                                    \"name:nonlatin\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"concat\",\n                            \"\\n\",\n                            [\n                                \"get\",\n                                \"name:nonlatin\"\n                            ]\n                        ],\n                        \"\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Stadia Semibold\"\n                ],\n                \"text-line-height\": 1.55,\n                \"text-max-width\": 9,\n                \"text-offset\": [\n                    0,\n                    0.6\n                ],\n                \"text-padding\": 2,\n                \"text-size\": 12\n            },\n            \"minzoom\": 16,\n            \"paint\": {\n                \"text-color\": \"#666\",\n                \"text-halo-blur\": 0.5,\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"poi\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"poi\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"Point\"\n                ],\n                [\n                    \"<=\",\n                    \"rank\",\n                    24\n                ],\n                [\n                    \">=\",\n                    \"rank\",\n                    15\n                ]\n            ],\n            \"id\": \"poi-level-2\",\n            \"layout\": {\n                \"icon-image\": \"{class}_11\",\n                \"symbol-avoid-edges\": true,\n                \"text-anchor\": \"top\",\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"name:latin\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"all\",\n                            [\n                                \"has\",\n                                \"name:nonlatin\"\n                            ],\n                            [\n                                \"is-supported-script\",\n                                [\n                                    \"get\",\n                                    \"name:nonlatin\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"concat\",\n                            \"\\n\",\n                            [\n                                \"get\",\n                                \"name:nonlatin\"\n                            ]\n                        ],\n                        \"\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Stadia Semibold\"\n                ],\n                \"text-line-height\": 1.55,\n                \"text-max-width\": 9,\n                \"text-offset\": [\n                    0,\n                    0.6\n                ],\n                \"text-padding\": 2,\n                \"text-size\": 12\n            },\n            \"minzoom\": 15,\n            \"paint\": {\n                \"text-color\": \"#666\",\n                \"text-halo-blur\": 0.5,\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"poi\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"poi\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"Point\"\n                ],\n                [\n                    \"<=\",\n                    \"rank\",\n                    14\n                ],\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"!=\",\n                    \"name\",\n                    \"\"\n                ]\n            ],\n            \"id\": \"poi-level-1\",\n            \"layout\": {\n                \"icon-image\": \"{class}_11\",\n                \"symbol-avoid-edges\": true,\n                \"text-anchor\": \"top\",\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"name:latin\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"all\",\n                            [\n                                \"has\",\n                                \"name:nonlatin\"\n                            ],\n                            [\n                                \"is-supported-script\",\n                                [\n                                    \"get\",\n                                    \"name:nonlatin\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"concat\",\n                            \"\\n\",\n                            [\n                                \"get\",\n                                \"name:nonlatin\"\n                            ]\n                        ],\n                        \"\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Stadia Semibold\"\n                ],\n                \"text-line-height\": 1.55,\n                \"text-max-width\": 9,\n                \"text-offset\": [\n                    0,\n                    0.6\n                ],\n                \"text-padding\": 2,\n                \"text-size\": 12\n            },\n            \"minzoom\": 14,\n            \"paint\": {\n                \"text-color\": \"#666\",\n                \"text-halo-blur\": 0.5,\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"poi\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"poi\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"Point\"\n                ],\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"!=\",\n                    \"name\",\n                    \"\"\n                ],\n                [\n                    \"==\",\n                    \"class\",\n                    \"railway\"\n                ],\n                [\n                    \"==\",\n                    \"subclass\",\n                    \"station\"\n                ]\n            ],\n            \"id\": \"poi-railway\",\n            \"layout\": {\n                \"icon-allow-overlap\": false,\n                \"icon-ignore-placement\": false,\n                \"icon-image\": \"{class}_11\",\n                \"icon-optional\": false,\n                \"symbol-avoid-edges\": true,\n                \"text-allow-overlap\": false,\n                \"text-anchor\": \"top\",\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"name:latin\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"all\",\n                            [\n                                \"has\",\n                                \"name:nonlatin\"\n                            ],\n                            [\n                                \"is-supported-script\",\n                                [\n                                    \"get\",\n                                    \"name:nonlatin\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"concat\",\n                            \"\\n\",\n                            [\n                                \"get\",\n                                \"name:nonlatin\"\n                            ]\n                        ],\n                        \"\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Stadia Regular\"\n                ],\n                \"text-ignore-placement\": false,\n                \"text-line-height\": 1.55,\n                \"text-max-width\": 9,\n                \"text-offset\": [\n                    0,\n                    0.6\n                ],\n                \"text-optional\": true,\n                \"text-padding\": 2,\n                \"text-size\": 12\n            },\n            \"minzoom\": 13,\n            \"paint\": {\n                \"text-color\": \"#666\",\n                \"text-halo-blur\": 0.5,\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"poi\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"transit.station\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"in\",\n                \"class\",\n                \"path\",\n                \"footway\"\n            ],\n            \"id\": \"highway-name-path\",\n            \"layout\": {\n                \"symbol-placement\": \"line\",\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"name:latin\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"all\",\n                            [\n                                \"has\",\n                                \"name:nonlatin\"\n                            ],\n                            [\n                                \"is-supported-script\",\n                                [\n                                    \"get\",\n                                    \"name:nonlatin\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"concat\",\n                            \" \",\n                            [\n                                \"get\",\n                                \"name:nonlatin\"\n                            ]\n                        ],\n                        \"\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Stadia Regular\"\n                ],\n                \"text-pitch-alignment\": \"viewport\",\n                \"text-rotation-alignment\": \"map\",\n                \"text-size\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            13,\n                            12\n                        ],\n                        [\n                            14,\n                            13\n                        ]\n                    ]\n                }\n            },\n            \"minzoom\": 15.5,\n            \"paint\": {\n                \"text-color\": \"hsl(30, 23%, 62%)\",\n                \"text-halo-color\": \"#f8f4f0\",\n                \"text-halo-width\": 0.5\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"id\": \"ski-slopes-label\",\n            \"layout\": {\n                \"icon-pitch-alignment\": \"auto\",\n                \"symbol-placement\": \"line-center\",\n                \"text-anchor\": \"bottom\",\n                \"text-field\": \"{name}\",\n                \"text-font\": [\n                    \"Stadia Regular\"\n                ],\n                \"text-keep-upright\": true,\n                \"text-size\": 12\n            },\n            \"minzoom\": 13,\n            \"paint\": {\n                \"text-color\": \"rgba(75, 122, 195, 1)\",\n                \"text-halo-blur\": 0.5,\n                \"text-halo-color\": \"rgba(255, 255, 255, 1)\",\n                \"text-halo-width\": 1\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"piste\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"poi.sports_complex\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ],\n                [\n                    \"in\",\n                    \"class\",\n                    \"minor\",\n                    \"service\",\n                    \"track\"\n                ]\n            ],\n            \"id\": \"highway-name-minor\",\n            \"layout\": {\n                \"symbol-placement\": \"line\",\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"name:latin\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"all\",\n                            [\n                                \"has\",\n                                \"name:nonlatin\"\n                            ],\n                            [\n                                \"is-supported-script\",\n                                [\n                                    \"get\",\n                                    \"name:nonlatin\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"concat\",\n                            \" \",\n                            [\n                                \"get\",\n                                \"name:nonlatin\"\n                            ]\n                        ],\n                        \"\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Stadia Regular\"\n                ],\n                \"text-pitch-alignment\": \"viewport\",\n                \"text-rotation-alignment\": \"map\",\n                \"text-size\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            13,\n                            12\n                        ],\n                        [\n                            14,\n                            13\n                        ]\n                    ]\n                }\n            },\n            \"minzoom\": 15,\n            \"paint\": {\n                \"text-color\": \"#765\",\n                \"text-halo-blur\": 0.5,\n                \"text-halo-width\": 1\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.local\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"in\",\n                \"class\",\n                \"primary\",\n                \"secondary\",\n                \"tertiary\",\n                \"trunk\"\n            ],\n            \"id\": \"highway-name-major\",\n            \"layout\": {\n                \"symbol-placement\": \"line\",\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"name:latin\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"all\",\n                            [\n                                \"has\",\n                                \"name:nonlatin\"\n                            ],\n                            [\n                                \"is-supported-script\",\n                                [\n                                    \"get\",\n                                    \"name:nonlatin\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"concat\",\n                            \" \",\n                            [\n                                \"get\",\n                                \"name:nonlatin\"\n                            ]\n                        ],\n                        \"\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Stadia Regular\"\n                ],\n                \"text-pitch-alignment\": \"viewport\",\n                \"text-rotation-alignment\": \"map\",\n                \"text-size\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            13,\n                            12\n                        ],\n                        [\n                            14,\n                            13\n                        ]\n                    ]\n                }\n            },\n            \"minzoom\": 12.2,\n            \"paint\": {\n                \"text-color\": \"#765\",\n                \"text-halo-blur\": 0.5,\n                \"text-halo-width\": 1\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    \"ref_length\",\n                    6\n                ],\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ],\n                [\n                    \"!in\",\n                    \"network\",\n                    \"us-interstate\",\n                    \"us-highway\",\n                    \"us-state\"\n                ]\n            ],\n            \"id\": \"highway-shield-other\",\n            \"layout\": {\n                \"icon-image\": \"road_{ref_length}\",\n                \"icon-rotation-alignment\": \"viewport\",\n                \"icon-size\": 1,\n                \"symbol-avoid-edges\": true,\n                \"symbol-placement\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            10,\n                            \"point\"\n                        ],\n                        [\n                            11,\n                            \"line\"\n                        ]\n                    ]\n                },\n                \"text-field\": \"{ref}\",\n                \"text-font\": [\n                    \"Stadia Semibold\"\n                ],\n                \"text-rotation-alignment\": \"viewport\",\n                \"text-size\": 10\n            },\n            \"minzoom\": 8,\n            \"paint\": {},\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"labels.icon\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    \"ref_length\",\n                    6\n                ],\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ],\n                [\n                    \"in\",\n                    \"network\",\n                    \"us-interstate\"\n                ]\n            ],\n            \"id\": \"highway-shield-us-interstate\",\n            \"layout\": {\n                \"icon-image\": \"{network}_{ref_length}\",\n                \"icon-rotation-alignment\": \"viewport\",\n                \"icon-size\": 1,\n                \"symbol-avoid-edges\": true,\n                \"symbol-placement\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            7,\n                            \"point\"\n                        ],\n                        [\n                            7,\n                            \"line\"\n                        ],\n                        [\n                            8,\n                            \"line\"\n                        ]\n                    ]\n                },\n                \"text-field\": \"{ref}\",\n                \"text-font\": [\n                    \"Stadia Semibold\"\n                ],\n                \"text-rotation-alignment\": \"viewport\",\n                \"text-size\": 10\n            },\n            \"minzoom\": 7,\n            \"paint\": {\n                \"text-color\": \"rgba(0, 0, 0, 1)\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"labels.icon\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"<=\",\n                    \"ref_length\",\n                    6\n                ],\n                [\n                    \"==\",\n                    \"$type\",\n                    \"LineString\"\n                ],\n                [\n                    \"in\",\n                    \"network\",\n                    \"us-highway\",\n                    \"us-state\"\n                ]\n            ],\n            \"id\": \"highway-shield-us-other\",\n            \"layout\": {\n                \"icon-image\": \"{network}_{ref_length}\",\n                \"icon-rotation-alignment\": \"viewport\",\n                \"icon-size\": 1,\n                \"symbol-avoid-edges\": true,\n                \"symbol-placement\": {\n                    \"base\": 1,\n                    \"stops\": [\n                        [\n                            10,\n                            \"point\"\n                        ],\n                        [\n                            11,\n                            \"line\"\n                        ]\n                    ]\n                },\n                \"text-field\": \"{ref}\",\n                \"text-font\": [\n                    \"Stadia Semibold\"\n                ],\n                \"text-rotation-alignment\": \"viewport\",\n                \"text-size\": 10\n            },\n            \"minzoom\": 9,\n            \"paint\": {\n                \"text-color\": \"rgba(0, 0, 0, 1)\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"transportation_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"road.highway\",\n                \"microg:gms-type-element\": \"labels.icon\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"has\",\n                    \"iata\"\n                ]\n            ],\n            \"id\": \"airport-label-major\",\n            \"layout\": {\n                \"icon-image\": \"airport_11\",\n                \"icon-size\": 1,\n                \"text-anchor\": \"top\",\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"name:latin\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"all\",\n                            [\n                                \"has\",\n                                \"name:nonlatin\"\n                            ],\n                            [\n                                \"is-supported-script\",\n                                [\n                                    \"get\",\n                                    \"name:nonlatin\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"concat\",\n                            \"\\n\",\n                            [\n                                \"get\",\n                                \"name:nonlatin\"\n                            ]\n                        ],\n                        \"\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Stadia Regular\"\n                ],\n                \"text-line-height\": 1.55,\n                \"text-max-width\": 9,\n                \"text-offset\": [\n                    0,\n                    0.6\n                ],\n                \"text-optional\": true,\n                \"text-padding\": 2,\n                \"text-size\": 12,\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 10,\n            \"paint\": {\n                \"text-color\": \"#666\",\n                \"text-halo-blur\": 0.5,\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"aerodrome_label\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"transit.station.airport\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"!in\",\n                \"class\",\n                \"city\",\n                \"town\",\n                \"village\",\n                \"country\",\n                \"continent\"\n            ],\n            \"id\": \"place-other\",\n            \"layout\": {\n                \"symbol-avoid-edges\": true,\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"name:latin\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"all\",\n                            [\n                                \"has\",\n                                \"name:nonlatin\"\n                            ],\n                            [\n                                \"is-supported-script\",\n                                [\n                                    \"get\",\n                                    \"name:nonlatin\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"concat\",\n                            \"\\n\",\n                            [\n                                \"get\",\n                                \"name:nonlatin\"\n                            ]\n                        ],\n                        \"\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Stadia Semibold\"\n                ],\n                \"text-letter-spacing\": 0.1,\n                \"text-line-height\": 1.55,\n                \"text-max-width\": 9,\n                \"text-size\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            12,\n                            10\n                        ],\n                        [\n                            15,\n                            14\n                        ]\n                    ]\n                },\n                \"text-transform\": \"uppercase\",\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 12,\n            \"paint\": {\n                \"text-color\": \"#633\",\n                \"text-halo-color\": \"rgba(255,255,255,0.8)\",\n                \"text-halo-width\": 1.2\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"administrative.neighborhood\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"==\",\n                \"class\",\n                \"village\"\n            ],\n            \"id\": \"place-village\",\n            \"layout\": {\n                \"symbol-avoid-edges\": true,\n                \"symbol-spacing\": 350,\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"name:latin\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"all\",\n                            [\n                                \"has\",\n                                \"name:nonlatin\"\n                            ],\n                            [\n                                \"is-supported-script\",\n                                [\n                                    \"get\",\n                                    \"name:nonlatin\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"concat\",\n                            \"\\n\",\n                            [\n                                \"get\",\n                                \"name:nonlatin\"\n                            ]\n                        ],\n                        \"\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Stadia Regular\"\n                ],\n                \"text-line-height\": 1.55,\n                \"text-max-width\": 8,\n                \"text-size\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            10,\n                            12\n                        ],\n                        [\n                            15,\n                            22\n                        ]\n                    ]\n                },\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 11,\n            \"paint\": {\n                \"text-color\": \"#333\",\n                \"text-halo-color\": \"rgba(255,255,255,0.8)\",\n                \"text-halo-width\": 1.2\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"administrative.neighborhood\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"Point\"\n                ],\n                [\n                    \"<=\",\n                    \"rank\",\n                    2\n                ],\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"!=\",\n                    \"name\",\n                    \"\"\n                ]\n            ],\n            \"id\": \"mountain-peaks\",\n            \"layout\": {\n                \"icon-image\": \"mountain_11\",\n                \"symbol-avoid-edges\": true,\n                \"text-anchor\": \"top\",\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"name:latin\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"all\",\n                            [\n                                \"has\",\n                                \"name:nonlatin\"\n                            ],\n                            [\n                                \"is-supported-script\",\n                                [\n                                    \"get\",\n                                    \"name:nonlatin\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"concat\",\n                            \"\\n\",\n                            [\n                                \"get\",\n                                \"name:nonlatin\"\n                            ]\n                        ],\n                        \"\"\n                    ],\n                    \"\\n\",\n                    [\n                        \"to-string\",\n                        [\n                            \"get\",\n                            \"ele\"\n                        ]\n                    ],\n                    \" m\"\n                ],\n                \"text-font\": [\n                    \"Stadia Regular\"\n                ],\n                \"text-line-height\": 1.55,\n                \"text-max-width\": 9,\n                \"text-offset\": [\n                    0,\n                    0.6\n                ],\n                \"text-padding\": 2,\n                \"text-size\": 12\n            },\n            \"minzoom\": 9,\n            \"paint\": {\n                \"text-color\": \"#666\",\n                \"text-halo-blur\": 0.5,\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"mountain_peak\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"$type\",\n                    \"Point\"\n                ],\n                [\n                    \">=\",\n                    \"ele\",\n                    2500\n                ],\n                [\n                    \"has\",\n                    \"name\"\n                ],\n                [\n                    \"!=\",\n                    \"name\",\n                    \"\"\n                ],\n                [\n                    \"<=\",\n                    \"rank\",\n                    1\n                ]\n            ],\n            \"id\": \"mountain-peaks-important\",\n            \"layout\": {\n                \"icon-image\": \"mountain_11\",\n                \"symbol-avoid-edges\": true,\n                \"text-anchor\": \"top\",\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"name:latin\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"all\",\n                            [\n                                \"has\",\n                                \"name:nonlatin\"\n                            ],\n                            [\n                                \"is-supported-script\",\n                                [\n                                    \"get\",\n                                    \"name:nonlatin\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"concat\",\n                            \"\\n\",\n                            [\n                                \"get\",\n                                \"name:nonlatin\"\n                            ]\n                        ],\n                        \"\"\n                    ],\n                    \"\\n\",\n                    [\n                        \"to-string\",\n                        [\n                            \"get\",\n                            \"ele\"\n                        ]\n                    ],\n                    \" m\"\n                ],\n                \"text-font\": [\n                    \"Stadia Semibold\"\n                ],\n                \"text-line-height\": 1.55,\n                \"text-max-width\": 9,\n                \"text-offset\": [\n                    0,\n                    0.6\n                ],\n                \"text-padding\": 2,\n                \"text-size\": 12\n            },\n            \"maxzoom\": 9,\n            \"minzoom\": 7,\n            \"paint\": {\n                \"text-color\": \"#666\",\n                \"text-halo-blur\": 0.5,\n                \"text-halo-color\": \"#ffffff\",\n                \"text-halo-width\": 1\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"mountain_peak\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"landscape.natural.landcover\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"==\",\n                \"class\",\n                \"town\"\n            ],\n            \"id\": \"place-town\",\n            \"layout\": {\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"name:latin\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"all\",\n                            [\n                                \"has\",\n                                \"name:nonlatin\"\n                            ],\n                            [\n                                \"is-supported-script\",\n                                [\n                                    \"get\",\n                                    \"name:nonlatin\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"concat\",\n                            \"\\n\",\n                            [\n                                \"get\",\n                                \"name:nonlatin\"\n                            ]\n                        ],\n                        \"\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Stadia Regular\"\n                ],\n                \"text-line-height\": 1.55,\n                \"text-max-width\": 8,\n                \"text-size\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            10,\n                            14\n                        ],\n                        [\n                            15,\n                            22\n                        ]\n                    ]\n                },\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"text-color\": \"#333\",\n                \"text-halo-color\": \"rgba(255,255,255,0.8)\",\n                \"text-halo-width\": 1.2\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"match\",\n                    [\n                        \"get\",\n                        \"class\"\n                    ],\n                    [\n                        \"nature_reserve\",\n                        \"protected_area\"\n                    ],\n                    true,\n                    false\n                ],\n                [\n                    \"==\",\n                    [\n                        \"geometry-type\"\n                    ],\n                    \"Point\"\n                ],\n                [\n                    \"==\",\n                    [\n                        \"get\",\n                        \"rank\"\n                    ],\n                    1\n                ],\n                [\n                    \"!\",\n                    [\n                        \"any\",\n                        [\n                            \"in\",\n                            \"Open Access Land\",\n                            [\n                                \"get\",\n                                \"name\"\n                            ]\n                        ],\n                        [\n                            \"in\",\n                            \"State Game Land\",\n                            [\n                                \"get\",\n                                \"name\"\n                            ]\n                        ]\n                    ]\n                ]\n            ],\n            \"id\": \"park-reserve\",\n            \"layout\": {\n                \"symbol-avoid-edges\": true,\n                \"symbol-placement\": \"point\",\n                \"text-anchor\": \"center\",\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"name:latin\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"all\",\n                            [\n                                \"has\",\n                                \"name:nonlatin\"\n                            ],\n                            [\n                                \"is-supported-script\",\n                                [\n                                    \"get\",\n                                    \"name:nonlatin\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"concat\",\n                            \"\\n\",\n                            [\n                                \"get\",\n                                \"name:nonlatin\"\n                            ]\n                        ],\n                        \"\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Stadia Italic\"\n                ],\n                \"text-justify\": \"center\",\n                \"text-line-height\": 1.55,\n                \"text-max-width\": 10,\n                \"text-padding\": 2,\n                \"text-size\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            8,\n                            12\n                        ],\n                        [\n                            13,\n                            14\n                        ]\n                    ]\n                },\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 8,\n            \"paint\": {\n                \"text-color\": \"rgba(102, 51, 1, 1)\",\n                \"text-halo-color\": \"rgba(255,255,255,0.8)\",\n                \"text-halo-width\": 1\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"park\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"poi.park\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"class\",\n                    \"national_park\"\n                ],\n                [\n                    \"==\",\n                    \"$type\",\n                    \"Point\"\n                ],\n                [\n                    \"==\",\n                    \"rank\",\n                    1\n                ]\n            ],\n            \"id\": \"park-national\",\n            \"layout\": {\n                \"symbol-avoid-edges\": true,\n                \"symbol-placement\": \"point\",\n                \"text-anchor\": \"center\",\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"name:latin\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"all\",\n                            [\n                                \"has\",\n                                \"name:nonlatin\"\n                            ],\n                            [\n                                \"is-supported-script\",\n                                [\n                                    \"get\",\n                                    \"name:nonlatin\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"concat\",\n                            \"\\n\",\n                            [\n                                \"get\",\n                                \"name:nonlatin\"\n                            ]\n                        ],\n                        \"\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Stadia Italic\"\n                ],\n                \"text-justify\": \"center\",\n                \"text-line-height\": 1.55,\n                \"text-max-width\": 10,\n                \"text-padding\": 2,\n                \"text-size\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            6,\n                            12\n                        ],\n                        [\n                            8,\n                            14\n                        ],\n                        [\n                            12,\n                            16\n                        ]\n                    ]\n                },\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 6,\n            \"paint\": {\n                \"text-color\": \"rgba(102, 51, 1, 1)\",\n                \"text-halo-color\": \"rgba(255,255,255,0.8)\",\n                \"text-halo-width\": 1\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"park\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"poi.park\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"==\",\n                \"$type\",\n                \"LineString\"\n            ],\n            \"id\": \"water-name-lakeline\",\n            \"layout\": {\n                \"symbol-placement\": \"line\",\n                \"symbol-spacing\": 250,\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"name:latin\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"all\",\n                            [\n                                \"has\",\n                                \"name:nonlatin\"\n                            ],\n                            [\n                                \"is-supported-script\",\n                                [\n                                    \"get\",\n                                    \"name:nonlatin\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"concat\",\n                            \" \",\n                            [\n                                \"get\",\n                                \"name:nonlatin\"\n                            ]\n                        ],\n                        \"\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Stadia Italic\"\n                ],\n                \"text-letter-spacing\": 0.2,\n                \"text-line-height\": 1.55,\n                \"text-max-width\": 5,\n                \"text-pitch-alignment\": \"viewport\",\n                \"text-rotation-alignment\": \"map\",\n                \"text-size\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            0,\n                            10\n                        ],\n                        [\n                            14,\n                            14\n                        ]\n                    ]\n                }\n            },\n            \"paint\": {\n                \"text-color\": \"#115AA7\"\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"water_name\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"water\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"!=\",\n                    \"capital\",\n                    2\n                ],\n                [\n                    \"==\",\n                    \"class\",\n                    \"city\"\n                ]\n            ],\n            \"id\": \"place-city\",\n            \"layout\": {\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"name:latin\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"all\",\n                            [\n                                \"has\",\n                                \"name:nonlatin\"\n                            ],\n                            [\n                                \"is-supported-script\",\n                                [\n                                    \"get\",\n                                    \"name:nonlatin\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"concat\",\n                            \"\\n\",\n                            [\n                                \"get\",\n                                \"name:nonlatin\"\n                            ]\n                        ],\n                        \"\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Stadia Semibold\"\n                ],\n                \"text-line-height\": 1.55,\n                \"text-max-width\": 8,\n                \"text-size\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            7,\n                            14\n                        ],\n                        [\n                            11,\n                            24\n                        ]\n                    ]\n                },\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"text-color\": \"#333\",\n                \"text-halo-color\": \"rgba(255,255,255,0.8)\",\n                \"text-halo-width\": 1.2\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"capital\",\n                    2\n                ],\n                [\n                    \"==\",\n                    \"class\",\n                    \"city\"\n                ]\n            ],\n            \"id\": \"place-city-capital\",\n            \"layout\": {\n                \"icon-image\": \"star_11\",\n                \"icon-size\": 0.8,\n                \"text-anchor\": \"left\",\n                \"text-field\": [\n                    \"concat\",\n                    [\n                        \"get\",\n                        \"name:latin\"\n                    ],\n                    [\n                        \"case\",\n                        [\n                            \"all\",\n                            [\n                                \"has\",\n                                \"name:nonlatin\"\n                            ],\n                            [\n                                \"is-supported-script\",\n                                [\n                                    \"get\",\n                                    \"name:nonlatin\"\n                                ]\n                            ]\n                        ],\n                        [\n                            \"concat\",\n                            \"\\n\",\n                            [\n                                \"get\",\n                                \"name:nonlatin\"\n                            ]\n                        ],\n                        \"\"\n                    ]\n                ],\n                \"text-font\": [\n                    \"Stadia Semibold\"\n                ],\n                \"text-line-height\": 1.55,\n                \"text-max-width\": 8,\n                \"text-offset\": [\n                    0.4,\n                    0\n                ],\n                \"text-size\": {\n                    \"base\": 1.2,\n                    \"stops\": [\n                        [\n                            7,\n                            14\n                        ],\n                        [\n                            11,\n                            24\n                        ]\n                    ]\n                },\n                \"visibility\": \"visible\"\n            },\n            \"paint\": {\n                \"text-color\": \"#333\",\n                \"text-halo-color\": \"rgba(255,255,255,0.8)\",\n                \"text-halo-width\": 1.2\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"administrative.locality\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"class\",\n                    \"country\"\n                ],\n                [\n                    \">=\",\n                    \"rank\",\n                    3\n                ],\n                [\n                    \"!has\",\n                    \"iso_a2\"\n                ]\n            ],\n            \"id\": \"place-country-other\",\n            \"layout\": {\n                \"symbol-avoid-edges\": true,\n                \"text-field\": \"{name:latin}\",\n                \"text-font\": [\n                    \"Stadia Italic\"\n                ],\n                \"text-max-width\": 6.25,\n                \"text-size\": {\n                    \"stops\": [\n                        [\n                            3,\n                            11\n                        ],\n                        [\n                            7,\n                            17\n                        ]\n                    ]\n                },\n                \"text-transform\": \"uppercase\",\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 1,\n            \"paint\": {\n                \"text-color\": \"#334\",\n                \"text-halo-blur\": 1,\n                \"text-halo-color\": \"rgba(255,255,255,0.8)\",\n                \"text-halo-width\": 2\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"administrative.province\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"class\",\n                    \"country\"\n                ],\n                [\n                    \">=\",\n                    \"rank\",\n                    3\n                ],\n                [\n                    \"has\",\n                    \"iso_a2\"\n                ]\n            ],\n            \"id\": \"place-country-3\",\n            \"layout\": {\n                \"text-field\": \"{name:latin}\",\n                \"text-font\": [\n                    \"Stadia Bold\"\n                ],\n                \"text-max-width\": 6.25,\n                \"text-size\": {\n                    \"stops\": [\n                        [\n                            3,\n                            11\n                        ],\n                        [\n                            7,\n                            17\n                        ]\n                    ]\n                },\n                \"text-transform\": \"uppercase\",\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 1,\n            \"paint\": {\n                \"text-color\": \"#334\",\n                \"text-halo-blur\": 1,\n                \"text-halo-color\": \"rgba(255,255,255,0.8)\",\n                \"text-halo-width\": 2\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"administrative.province\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"class\",\n                    \"country\"\n                ],\n                [\n                    \"==\",\n                    \"rank\",\n                    2\n                ],\n                [\n                    \"has\",\n                    \"iso_a2\"\n                ]\n            ],\n            \"id\": \"place-country-2\",\n            \"layout\": {\n                \"text-field\": \"{name:latin}\",\n                \"text-font\": [\n                    \"Stadia Bold\"\n                ],\n                \"text-max-width\": 6.25,\n                \"text-size\": {\n                    \"stops\": [\n                        [\n                            2,\n                            11\n                        ],\n                        [\n                            5,\n                            17\n                        ]\n                    ]\n                },\n                \"text-transform\": \"uppercase\",\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 1,\n            \"paint\": {\n                \"text-color\": \"#334\",\n                \"text-halo-blur\": 1,\n                \"text-halo-color\": \"rgba(255,255,255,0.8)\",\n                \"text-halo-width\": 2\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"administrative.province\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"all\",\n                [\n                    \"==\",\n                    \"class\",\n                    \"country\"\n                ],\n                [\n                    \"==\",\n                    \"rank\",\n                    1\n                ],\n                [\n                    \"has\",\n                    \"iso_a2\"\n                ]\n            ],\n            \"id\": \"place-country-1\",\n            \"layout\": {\n                \"text-field\": \"{name:latin}\",\n                \"text-font\": [\n                    \"Stadia Bold\"\n                ],\n                \"text-max-width\": 6.25,\n                \"text-size\": {\n                    \"stops\": [\n                        [\n                            1,\n                            11\n                        ],\n                        [\n                            4,\n                            17\n                        ]\n                    ]\n                },\n                \"text-transform\": \"uppercase\",\n                \"visibility\": \"visible\"\n            },\n            \"minzoom\": 1,\n            \"paint\": {\n                \"text-color\": \"#334\",\n                \"text-halo-blur\": 1,\n                \"text-halo-color\": \"rgba(255,255,255,0.8)\",\n                \"text-halo-width\": 2\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"administrative.country\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        },\n        {\n            \"filter\": [\n                \"==\",\n                \"class\",\n                \"continent\"\n            ],\n            \"id\": \"place-continent\",\n            \"layout\": {\n                \"text-field\": \"{name:latin}\",\n                \"text-font\": [\n                    \"Stadia Bold\"\n                ],\n                \"text-max-width\": 6.25,\n                \"text-size\": 14,\n                \"text-transform\": \"uppercase\",\n                \"visibility\": \"visible\"\n            },\n            \"maxzoom\": 1,\n            \"paint\": {\n                \"text-color\": \"#334\",\n                \"text-halo-blur\": 1,\n                \"text-halo-color\": \"rgba(255,255,255,0.8)\",\n                \"text-halo-width\": 2\n            },\n            \"source\": \"openmaptiles\",\n            \"source-layer\": \"place\",\n            \"type\": \"symbol\",\n            \"metadata\": {\n                \"microg:gms-type-feature\": \"administrative.land_parcel\",\n                \"microg:gms-type-element\": \"labels.text\"\n            }\n        }\n    ],\n    \"metadata\": {\n        \"mapbox:autocomposite\": false,\n        \"openmaptiles:version\": \"3.x\"\n    },\n    \"name\": \"Outdoors\",\n    \"pitch\": 0,\n    \"sources\": {\n        \"openmaptiles\": {\n            \"type\": \"vector\",\n            \"url\": \"https://tiles.stadiamaps.com/data/openmaptiles.json\"\n        }\n    },\n    \"sprite\": \"https://tiles.stadiamaps.com/styles/outdoors/sprite\",\n    \"version\": 8,\n    \"zoom\": 11.6\n}\n"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/java/com/google/android/gms/dynamite/descriptors/com/google/android/gms/maps_dynamite/ModuleDescriptor.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.dynamite.descriptors.com.google.android.gms.maps_dynamite;\n\nimport androidx.annotation.Keep;\n\n@Keep\npublic class ModuleDescriptor {\n    public static final String MODULE_ID = \"com.google.android.gms.maps_dynamite\";\n    public static final int MODULE_VERSION = 1;\n}\n"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/java/com/google/android/gms/maps/internal/CreatorImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.maps.internal;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.content.res.Resources;\nimport android.os.Parcel;\nimport android.os.RemoteException;\nimport androidx.annotation.Keep;\nimport android.util.Log;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.dynamic.ObjectWrapper;\nimport com.google.android.gms.maps.GoogleMapOptions;\nimport com.google.android.gms.maps.StreetViewPanoramaOptions;\nimport com.google.android.gms.maps.model.internal.IBitmapDescriptorFactoryDelegate;\n\nimport org.microg.gms.maps.mapbox.CameraUpdateFactoryImpl;\nimport org.microg.gms.maps.mapbox.MapFragmentImpl;\nimport org.microg.gms.maps.mapbox.MapViewImpl;\nimport org.microg.gms.maps.mapbox.StreetViewPanoramaFragmentImpl;\nimport org.microg.gms.maps.mapbox.StreetViewPanoramaViewImpl;\nimport org.microg.gms.maps.mapbox.model.BitmapDescriptorFactoryImpl;\n\n@Keep\npublic class CreatorImpl extends ICreator.Stub {\n    private static final String TAG = \"GmsMapCreator\";\n\n    @Override\n    public void init(IObjectWrapper resources) {\n        initV2(resources, 0);\n    }\n\n    @Override\n    public IMapFragmentDelegate newMapFragmentDelegate(IObjectWrapper activity) {\n        return new MapFragmentImpl(ObjectWrapper.unwrapTyped(activity, Activity.class));\n    }\n\n    @Override\n    public IMapViewDelegate newMapViewDelegate(IObjectWrapper context, GoogleMapOptions options) {\n        return new MapViewImpl(ObjectWrapper.unwrapTyped(context, Context.class), options);\n    }\n\n    @Override\n    public ICameraUpdateFactoryDelegate newCameraUpdateFactoryDelegate() {\n        return new CameraUpdateFactoryImpl();\n    }\n\n    @Override\n    public IBitmapDescriptorFactoryDelegate newBitmapDescriptorFactoryDelegate() {\n        return BitmapDescriptorFactoryImpl.INSTANCE;\n    }\n\n    @Override\n    public void initV2(IObjectWrapper resources, int flags) {\n        BitmapDescriptorFactoryImpl.INSTANCE.initialize(ObjectWrapper.unwrapTyped(resources, Resources.class), null);\n        //ResourcesContainer.set((Resources) ObjectWrapper.unwrap(resources));\n        Log.d(TAG, \"initV2 \" + flags);\n    }\n\n    @Override\n    public IStreetViewPanoramaViewDelegate newStreetViewPanoramaViewDelegate(IObjectWrapper context, StreetViewPanoramaOptions options) {\n        return new StreetViewPanoramaViewImpl(ObjectWrapper.unwrapTyped(context, Context.class));\n    }\n\n    @Override\n    public IStreetViewPanoramaFragmentDelegate newStreetViewPanoramaFragmentDelegate(IObjectWrapper activity) {\n        return new StreetViewPanoramaFragmentImpl(ObjectWrapper.unwrapTyped(activity, Activity.class));\n    }\n\n    @Override\n    public int getRendererType() throws RemoteException {\n        return 2;\n    }\n\n    @Override\n    public void logInitialization(IObjectWrapper context, int preferredRenderer) throws RemoteException {\n        Log.d(TAG, \"Mapbox-based Map initialized (preferred renderer was \" + preferredRenderer + \")\");\n    }\n\n    @Override\n    public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {\n        if (super.onTransact(code, data, reply, flags)) return true;\n        Log.d(TAG, \"onTransact [unknown]: \" + code + \", \" + data + \", \" + flags);\n        return false;\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/java/com/mapbox/android/accounts/v1/MapboxAccounts.java",
    "content": "package com.mapbox.android.accounts.v1;\n\nimport java.util.UUID;\n\n/**\n * This class is used from within the Mapbox library\n */\n@SuppressWarnings(\"unused\")\npublic class MapboxAccounts {\n    public final static String SKU_ID_MAPS_MAUS = \"00\";\n    private final static String MAPS_SKU_PREFIX = \"100\";\n\n    /**\n     * Generates random UUID without hyphens\n     */\n    public static String obtainEndUserId() {\n        String uuid = UUID.randomUUID().toString();\n        return uuid.substring(0, 8) + uuid.substring(9, 13) + uuid.substring(14, 18) + uuid.substring(19, 23) + uuid.substring(24, 36);\n    }\n\n    /**\n     * Generates a SKU which is the user id prefixed with 100 and base-36 encoded timestamp\n     */\n    public static String obtainMapsSkuUserToken(String userId) {\n        String stamp = Long.toString(System.currentTimeMillis(), 36);\n        return MAPS_SKU_PREFIX + stamp + userId;\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/AbstractGoogleMap.kt",
    "content": "package org.microg.gms.maps.mapbox\n\nimport android.content.Context\nimport android.location.Location\nimport android.os.Bundle\nimport android.util.DisplayMetrics\nimport android.util.Log\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.ObjectWrapper\nimport com.google.android.gms.maps.internal.*\nimport com.mapbox.mapboxsdk.location.engine.LocationEngineCallback\nimport com.mapbox.mapboxsdk.location.engine.LocationEngineResult\nimport org.microg.gms.maps.mapbox.model.AbstractMarker\nimport org.microg.gms.maps.mapbox.model.DefaultInfoWindowAdapter\nimport org.microg.gms.maps.mapbox.model.InfoWindow\nimport org.microg.gms.maps.mapbox.utils.MapContext\n\nabstract class AbstractGoogleMap(context: Context) : IGoogleMapDelegate.Stub() {\n\n    internal val mapContext = MapContext(context)\n\n    val dpiFactor: Float\n        get() = mapContext.resources.displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT\n\n    internal var currentInfoWindow: InfoWindow? = null\n    internal var infoWindowAdapter: IInfoWindowAdapter = DefaultInfoWindowAdapter(mapContext)\n    internal var onInfoWindowClickListener: IOnInfoWindowClickListener? = null\n    internal var onInfoWindowLongClickListener: IOnInfoWindowLongClickListener? = null\n    internal var onInfoWindowCloseListener: IOnInfoWindowCloseListener? = null\n\n    internal var mapClickListener: IOnMapClickListener? = null\n    internal var mapLongClickListener: IOnMapLongClickListener? = null\n    internal var markerClickListener: IOnMarkerClickListener? = null\n    internal var circleClickListener: IOnCircleClickListener? = null\n\n    internal var myLocationChangeListener: IOnMyLocationChangeListener? = null\n\n    internal val locationEngineCallback = object : LocationEngineCallback<LocationEngineResult> {\n        override fun onSuccess(result: LocationEngineResult?) {\n            result?.lastLocation?.let { location ->\n                Log.d(TAG, \"myLocationChanged: $location\")\n                myLocationChangeListener?.onMyLocationChanged(ObjectWrapper.wrap(location))\n\n                onLocationUpdate(location)\n            }\n        }\n        override fun onFailure(e: Exception) {\n            Log.e(TAG, \"Failed to obtain location update\", e)\n        }\n    }\n\n\n    internal abstract fun showInfoWindow(marker: AbstractMarker): Boolean\n\n    internal abstract fun onLocationUpdate(location: Location)\n\n    override fun setOnInfoWindowClickListener(listener: IOnInfoWindowClickListener?) {\n        onInfoWindowClickListener = listener\n    }\n\n    override fun setOnInfoWindowLongClickListener(listener: IOnInfoWindowLongClickListener?) {\n        onInfoWindowLongClickListener = listener\n    }\n\n    override fun setOnInfoWindowCloseListener(listener: IOnInfoWindowCloseListener?) {\n        onInfoWindowCloseListener = listener\n    }\n\n    override fun setInfoWindowAdapter(adapter: IInfoWindowAdapter?) {\n        infoWindowAdapter = adapter ?: DefaultInfoWindowAdapter(mapContext)\n    }\n\n    override fun setOnMapClickListener(listener: IOnMapClickListener?) {\n        mapClickListener = listener\n    }\n\n    override fun setOnMapLongClickListener(listener: IOnMapLongClickListener?) {\n        mapLongClickListener = listener\n    }\n\n    override fun setOnMarkerClickListener(listener: IOnMarkerClickListener?) {\n        markerClickListener = listener\n    }\n\n    override fun setOnCircleClickListener(listener: IOnCircleClickListener?) {\n        circleClickListener = listener\n    }\n\n    override fun setOnPolygonClickListener(listener: IOnPolygonClickListener?) {\n        Log.d(TAG, \"Not yet implemented: setOnPolygonClickListener\")\n    }\n\n    override fun setOnPolylineClickListener(listener: IOnPolylineClickListener?) {\n        Log.d(TAG, \"Not yet implemented: setOnPolylineClickListener\")\n    }\n\n    override fun setOnGroundOverlayClickListener(listener: IOnGroundOverlayClickListener?) {\n        Log.d(TAG, \"Not yet implemented: setOnGroundOverlayClickListener\")\n    }\n\n    override fun setOnMyLocationClickListener(listener: IOnMyLocationClickListener?) {\n        Log.d(TAG, \"Not yet implemented: setOnMyLocationClickListener\")\n    }\n\n    override fun getMyLocation(): Location? {\n        Log.d(TAG, \"unimplemented Method: getMyLocation\")\n        return null\n    }\n\n    override fun setLocationSource(locationSource: ILocationSourceDelegate?) {\n        Log.d(TAG, \"unimplemented Method: setLocationSource\")\n    }\n\n    override fun setOnMyLocationChangeListener(listener: IOnMyLocationChangeListener?) {\n        myLocationChangeListener = listener\n    }\n\n    override fun setOnMyLocationButtonClickListener(listener: IOnMyLocationButtonClickListener?) {\n        Log.d(TAG, \"unimplemented Method: setOnMyLocationButtonClickListener\")\n    }\n\n    override fun getTestingHelper(): IObjectWrapper {\n        Log.d(TAG, \"unimplemented Method: getTestingHelper\")\n        return ObjectWrapper.wrap(null)\n    }\n\n    override fun isBuildingsEnabled(): Boolean {\n        Log.d(TAG, \"unimplemented Method: isBuildingsEnabled\")\n        return false\n    }\n\n    override fun setBuildingsEnabled(buildings: Boolean) {\n        Log.d(TAG, \"unimplemented Method: setBuildingsEnabled\")\n    }\n\n    override fun useViewLifecycleWhenInFragment(): Boolean {\n        Log.d(TAG, \"unimplemented Method: useViewLifecycleWhenInFragment\")\n        return false\n    }\n\n    override fun onEnterAmbient(bundle: Bundle?) {\n        Log.d(TAG, \"unimplemented Method: onEnterAmbient\")\n    }\n\n    override fun onExitAmbient() {\n        Log.d(TAG, \"unimplemented Method: onExitAmbient\")\n    }\n\n    override fun isTrafficEnabled(): Boolean {\n        Log.d(TAG, \"unimplemented Method: isTrafficEnabled\")\n        return false\n    }\n\n    override fun setTrafficEnabled(traffic: Boolean) {\n        Log.d(TAG, \"unimplemented Method: setTrafficEnabled\")\n\n    }\n\n    override fun isIndoorEnabled(): Boolean {\n        Log.d(TAG, \"unimplemented Method: isIndoorEnabled\")\n        return false\n    }\n\n    override fun setIndoorEnabled(indoor: Boolean) {\n        Log.d(TAG, \"unimplemented Method: setIndoorEnabled\")\n    }\n\n    companion object {\n        val TAG = \"GmsMapAbstract\"\n    }\n}"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/CameraBoundsWithSizeUpdate.kt",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 org.microg.gms.maps.mapbox\n\nimport android.util.Log\nimport com.google.android.gms.maps.internal.IGoogleMapDelegate\nimport com.mapbox.mapboxsdk.camera.CameraPosition\nimport com.mapbox.mapboxsdk.camera.CameraUpdate\nimport com.mapbox.mapboxsdk.geometry.LatLngBounds\nimport com.mapbox.mapboxsdk.maps.MapboxMap\nimport java.util.*\n\ninternal class CameraBoundsWithSizeUpdate(val bounds: LatLngBounds, val width: Int, val height: Int, val padding: IntArray) : LiteModeCameraUpdate, CameraUpdate {\n\n    constructor(bounds: LatLngBounds, width: Int, height: Int, paddingLeft: Int, paddingTop: Int = paddingLeft, paddingRight: Int = paddingLeft, paddingBottom: Int = paddingTop) : this(bounds, width, height, intArrayOf(paddingLeft, paddingTop, paddingRight, paddingBottom)) {}\n\n    override fun getLiteModeCameraPosition(map: IGoogleMapDelegate) = null\n\n    override fun getLiteModeCameraBounds() = bounds\n\n    override fun getCameraPosition(map: MapboxMap): CameraPosition? {\n        val padding = this.padding.clone()\n\n        val mapPadding = map.cameraPosition.padding\n        mapPadding?.let {\n            for (i in 0..3) {\n                padding[i] += it[i].toInt()\n            }\n        }\n\n        val widthPadding = ((map.width - width) / 2).toInt()\n        val heightPadding = ((map.height - height) / 2).toInt()\n        padding[0] += widthPadding\n        padding[1] += heightPadding\n        padding[2] += widthPadding\n        padding[3] += heightPadding\n\n        Log.d(TAG, \"map ${map.width} ${map.height}, set $width $height -> ${Arrays.toString(padding)}\")\n        return map.getCameraForLatLngBounds(bounds, padding)?.let {\n            CameraPosition.Builder(it)\n                .apply {\n                    mapPadding?.let {\n                        padding(it)\n                    }\n                }.build()\n        }\n\n    }\n\n    override fun equals(other: Any?): Boolean {\n        if (this === other) {\n            return true\n        }\n        if (other == null || other !is CameraBoundsWithSizeUpdate?) {\n            return false\n        }\n\n        val that = other as CameraBoundsWithSizeUpdate? ?: return false\n\n        if (bounds != that.bounds) {\n            return false\n        }\n\n        if (Arrays.equals(padding, that.padding)) {\n            return false\n        }\n\n        if (height != that.height || width != that.width) {\n            return false\n        }\n\n        return true\n    }\n\n    override fun hashCode(): Int {\n        var result = bounds.hashCode()\n        result = 31 * result + Arrays.hashCode(padding)\n        result = 31 * result + height.hashCode()\n        result = 31 * result + width.hashCode()\n        return result\n    }\n\n    override fun toString(): String {\n        return (\"CameraBoundsWithSizeUpdate{\"\n                + \"bounds=\" + bounds\n                + \", padding=\" + Arrays.toString(padding)\n                + '}'.toString())\n    }\n\n    companion object {\n        const val TAG = \"GmsMapCameraBounds\"\n    }\n}"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/CameraUpdateFactory.kt",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 org.microg.gms.maps.mapbox\n\nimport android.graphics.Point\nimport android.graphics.PointF\nimport android.os.Parcel\nimport android.util.Log\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.ObjectWrapper\nimport com.google.android.gms.maps.internal.ICameraUpdateFactoryDelegate\nimport com.google.android.gms.maps.internal.IGoogleMapDelegate\nimport com.google.android.gms.maps.model.CameraPosition\nimport com.google.android.gms.maps.model.LatLng\nimport com.google.android.gms.maps.model.LatLngBounds\nimport com.mapbox.mapboxsdk.camera.CameraUpdate\nimport com.mapbox.mapboxsdk.camera.CameraUpdateFactory\nimport com.mapbox.mapboxsdk.maps.MapboxMap\nimport org.microg.gms.maps.mapbox.utils.toMapbox\n\nclass CameraUpdateFactoryImpl : ICameraUpdateFactoryDelegate.Stub() {\n\n    override fun zoomIn(): IObjectWrapper = ObjectWrapper.wrap(ZoomByCameraUpdate(1f))\n    override fun zoomOut(): IObjectWrapper = ObjectWrapper.wrap(ZoomByCameraUpdate(-1f))\n\n    override fun zoomTo(zoom: Float): IObjectWrapper = ObjectWrapper.wrap(ZoomToCameraUpdate(zoom))\n\n    override fun zoomBy(zoomDelta: Float): IObjectWrapper =\n            ObjectWrapper.wrap(ZoomByCameraUpdate(zoomDelta)).also {\n                Log.d(TAG, \"zoomBy\")\n            }\n\n    override fun zoomByWithFocus(zoomDelta: Float, x: Int, y: Int): IObjectWrapper =\n            ObjectWrapper.wrap(ZoomByWithFocusCameraUpdate(zoomDelta, x, y)).also {\n                Log.d(TAG, \"zoomByWithFocus\")\n            }\n\n    override fun newCameraPosition(cameraPosition: CameraPosition): IObjectWrapper =\n            ObjectWrapper.wrap(NewCameraPositionCameraUpdate(cameraPosition)).also {\n                Log.d(TAG, \"newCameraPosition\")\n            }\n\n    override fun newLatLng(latLng: LatLng): IObjectWrapper =\n            ObjectWrapper.wrap(NewLatLngCameraUpdate(latLng)).also {\n                Log.d(TAG, \"newLatLng\")\n            }\n\n    override fun newLatLngZoom(latLng: LatLng, zoom: Float): IObjectWrapper =\n            ObjectWrapper.wrap(NewLatLngZoomCameraUpdate(latLng, zoom)).also {\n                Log.d(TAG, \"newLatLngZoom\")\n            }\n\n    override fun newLatLngBounds(bounds: LatLngBounds, padding: Int): IObjectWrapper =\n            ObjectWrapper.wrap(NewLatLngBoundsCameraUpdate(bounds, padding)).also {\n                Log.d(TAG, \"newLatLngBounds\")\n            }\n\n    override fun scrollBy(x: Float, y: Float): IObjectWrapper {\n        Log.d(TAG, \"unimplemented Method: scrollBy\")\n        return ObjectWrapper.wrap(NoCameraUpdate())\n    }\n\n    override fun newLatLngBoundsWithSize(bounds: LatLngBounds, width: Int, height: Int, padding: Int): IObjectWrapper =\n        ObjectWrapper.wrap(CameraBoundsWithSizeUpdate(bounds.toMapbox(), width, height, padding)).also {\n            Log.d(TAG, \"newLatLngBoundsWithSize\")\n        }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =\n            if (super.onTransact(code, data, reply, flags)) {\n                true\n            } else {\n                Log.d(TAG, \"onTransact [unknown]: $code, $data, $flags\"); false\n            }\n\n    private inner class NoCameraUpdate : CameraUpdate, LiteModeCameraUpdate {\n        override fun getCameraPosition(mapboxMap: MapboxMap): com.mapbox.mapboxsdk.camera.CameraPosition? =\n                mapboxMap.cameraPosition\n\n        override fun getLiteModeCameraPosition(map: IGoogleMapDelegate): CameraPosition = map.cameraPosition\n    }\n\n    companion object {\n        private val TAG = \"GmsCameraUpdate\"\n    }\n}\n\ninterface LiteModeCameraUpdate {\n    fun getLiteModeCameraPosition(map: IGoogleMapDelegate): CameraPosition?\n\n    fun getLiteModeCameraBounds(): com.mapbox.mapboxsdk.geometry.LatLngBounds? = null\n}\n\nclass ZoomToCameraUpdate(private val zoom: Float) : LiteModeCameraUpdate, CameraUpdate {\n    override fun getLiteModeCameraPosition(map: IGoogleMapDelegate): CameraPosition =\n        CameraPosition.Builder(map.cameraPosition).zoom(zoom).build()\n\n    override fun getCameraPosition(mapboxMap: MapboxMap): com.mapbox.mapboxsdk.camera.CameraPosition? =\n        CameraUpdateFactory.zoomTo(zoom.toDouble() - 1.0).getCameraPosition(mapboxMap)\n\n}\n\nclass ZoomByCameraUpdate(private val delta: Float) : LiteModeCameraUpdate, CameraUpdate {\n    override fun getLiteModeCameraPosition(map: IGoogleMapDelegate): CameraPosition =\n        CameraPosition.Builder(map.cameraPosition).zoom(map.cameraPosition.zoom + delta).build()\n\n    override fun getCameraPosition(mapboxMap: MapboxMap): com.mapbox.mapboxsdk.camera.CameraPosition? =\n        CameraUpdateFactory.zoomBy(delta.toDouble()).getCameraPosition(mapboxMap)\n\n}\n\nclass ZoomByWithFocusCameraUpdate(private val delta: Float, private val x: Int, private val y: Int) : LiteModeCameraUpdate,\n    CameraUpdate {\n    override fun getLiteModeCameraPosition(map: IGoogleMapDelegate): CameraPosition =\n        CameraPosition.Builder(map.cameraPosition).zoom(map.cameraPosition.zoom + delta)\n            .target(map.projection.fromScreenLocation(ObjectWrapper.wrap(PointF(x.toFloat(), y.toFloat())))).build()\n\n    override fun getCameraPosition(mapboxMap: MapboxMap): com.mapbox.mapboxsdk.camera.CameraPosition? =\n        CameraUpdateFactory.zoomBy(delta.toDouble(), Point(x, y)).getCameraPosition(mapboxMap)\n}\n\nclass NewCameraPositionCameraUpdate(private val cameraPosition: CameraPosition) : LiteModeCameraUpdate, CameraUpdate {\n    override fun getLiteModeCameraPosition(map: IGoogleMapDelegate): CameraPosition = this.cameraPosition\n\n    override fun getCameraPosition(mapboxMap: MapboxMap): com.mapbox.mapboxsdk.camera.CameraPosition? =\n        this.cameraPosition.toMapbox().takeIf { it.target != null }\n}\n\nclass NewLatLngCameraUpdate(private val latLng: LatLng) : LiteModeCameraUpdate, CameraUpdate {\n    override fun getLiteModeCameraPosition(map: IGoogleMapDelegate): CameraPosition =\n        CameraPosition.Builder(map.cameraPosition).target(latLng).build()\n\n    override fun getCameraPosition(mapboxMap: MapboxMap): com.mapbox.mapboxsdk.camera.CameraPosition? =\n        CameraUpdateFactory.newLatLng(latLng.toMapbox()).getCameraPosition(mapboxMap)\n}\n\nclass NewLatLngZoomCameraUpdate(private val latLng: LatLng, private val zoom: Float) : LiteModeCameraUpdate, CameraUpdate {\n    override fun getLiteModeCameraPosition(map: IGoogleMapDelegate): CameraPosition =\n        CameraPosition.Builder(map.cameraPosition).target(latLng).zoom(zoom).build()\n\n    override fun getCameraPosition(mapboxMap: MapboxMap): com.mapbox.mapboxsdk.camera.CameraPosition? =\n        CameraUpdateFactory.newLatLngZoom(latLng.toMapbox(), zoom - 1.0).getCameraPosition(mapboxMap)\n}\n\nclass NewLatLngBoundsCameraUpdate(private val bounds: LatLngBounds, internal val padding: Int) : LiteModeCameraUpdate,\n    CameraUpdate {\n\n    override fun getLiteModeCameraPosition(map: IGoogleMapDelegate): CameraPosition? = null\n\n    override fun getLiteModeCameraBounds() = bounds.toMapbox()\n\n    override fun getCameraPosition(mapboxMap: MapboxMap): com.mapbox.mapboxsdk.camera.CameraPosition? =\n        CameraUpdateFactory.newLatLngBounds(bounds.toMapbox(), padding).getCameraPosition(mapboxMap)\n}"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/GoogleLocationEngine.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.maps.mapbox\n\nimport android.app.PendingIntent\nimport android.content.Context\nimport android.os.Looper\nimport com.google.android.gms.location.LocationListener\nimport com.google.android.gms.location.LocationRequest\nimport com.google.android.gms.location.LocationServices\nimport com.google.android.gms.location.Priority\nimport com.mapbox.mapboxsdk.location.engine.LocationEngine\nimport com.mapbox.mapboxsdk.location.engine.LocationEngineCallback\nimport com.mapbox.mapboxsdk.location.engine.LocationEngineRequest\nimport com.mapbox.mapboxsdk.location.engine.LocationEngineResult\n\nclass GoogleLocationEngine(context: Context) : LocationEngine {\n    private val listenerMap: MutableMap<LocationEngineCallback<LocationEngineResult>, LocationListener> = hashMapOf()\n    private val client = LocationServices.getFusedLocationProviderClient(context)\n\n    override fun getLastLocation(callback: LocationEngineCallback<LocationEngineResult>) {\n        client.lastLocation.addOnCompleteListener {\n            if (it.isSuccessful) callback.onSuccess(LocationEngineResult.create(it.result))\n            else callback.onFailure(it.exception)\n        }\n    }\n\n    override fun requestLocationUpdates(request: LocationEngineRequest, callback: LocationEngineCallback<LocationEngineResult>, looper: Looper?) {\n        listenerMap[callback] = listenerMap[callback] ?: LocationListener { callback.onSuccess(LocationEngineResult.create(it)) }\n        client.requestLocationUpdates(\n            LocationRequest.Builder(request.interval)\n                .setPriority(\n                    when (request.priority) {\n                        LocationEngineRequest.PRIORITY_HIGH_ACCURACY -> Priority.PRIORITY_HIGH_ACCURACY\n                        LocationEngineRequest.PRIORITY_BALANCED_POWER_ACCURACY -> Priority.PRIORITY_BALANCED_POWER_ACCURACY\n                        LocationEngineRequest.PRIORITY_LOW_POWER -> Priority.PRIORITY_LOW_POWER\n                        LocationEngineRequest.PRIORITY_NO_POWER -> Priority.PRIORITY_PASSIVE\n                        else -> Priority.PRIORITY_BALANCED_POWER_ACCURACY\n                    }\n                )\n                .setMinUpdateDistanceMeters(request.displacement)\n                .setMinUpdateIntervalMillis(request.fastestInterval)\n                .setMaxUpdateDelayMillis(request.maxWaitTime)\n                .build(), listenerMap[callback]!!, looper\n        )\n    }\n\n    override fun requestLocationUpdates(request: LocationEngineRequest, pendingIntent: PendingIntent?) {\n        throw UnsupportedOperationException()\n    }\n\n    override fun removeLocationUpdates(callback: LocationEngineCallback<LocationEngineResult>) {\n        listenerMap[callback]?.let { client.removeLocationUpdates(it) }\n        listenerMap.remove(callback)\n    }\n\n    override fun removeLocationUpdates(pendingIntent: PendingIntent?) {\n        throw UnsupportedOperationException()\n    }\n}"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/GoogleMap.kt",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 org.microg.gms.maps.mapbox\n\nimport android.annotation.SuppressLint\nimport android.content.Context\nimport android.graphics.Bitmap\nimport android.location.Location\nimport android.os.*\nimport androidx.annotation.IdRes\nimport androidx.annotation.Keep\nimport android.util.Log\nimport android.view.Gravity\nimport android.view.View\nimport android.widget.FrameLayout\nimport android.widget.RelativeLayout\nimport androidx.collection.LongSparseArray\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.ObjectWrapper\nimport com.google.android.gms.maps.GoogleMapOptions\nimport com.google.android.gms.maps.internal.*\nimport com.google.android.gms.maps.model.*\nimport com.google.android.gms.maps.model.CircleOptions\nimport com.google.android.gms.maps.model.internal.*\nimport com.mapbox.mapboxsdk.LibraryLoader\nimport com.mapbox.mapboxsdk.Mapbox\nimport com.mapbox.mapboxsdk.R\nimport com.mapbox.mapboxsdk.camera.CameraUpdate\nimport com.mapbox.mapboxsdk.constants.MapboxConstants\nimport com.mapbox.mapboxsdk.location.LocationComponentActivationOptions\nimport com.mapbox.mapboxsdk.location.LocationComponentOptions\nimport com.mapbox.mapboxsdk.location.modes.CameraMode\nimport com.mapbox.mapboxsdk.location.modes.RenderMode\nimport com.mapbox.mapboxsdk.maps.MapView\nimport com.mapbox.mapboxsdk.maps.MapboxMap\nimport com.mapbox.mapboxsdk.maps.Style\nimport com.mapbox.mapboxsdk.plugins.annotation.*\nimport com.mapbox.mapboxsdk.plugins.annotation.Annotation\nimport com.mapbox.mapboxsdk.style.layers.Property.LINE_CAP_ROUND\nimport com.google.android.gms.dynamic.unwrap\nimport com.google.android.gms.maps.GoogleMap\nimport com.mapbox.mapboxsdk.WellKnownTileServer\nimport org.microg.gms.maps.mapbox.model.InfoWindow\nimport org.microg.gms.maps.mapbox.model.getInfoWindowViewFor\nimport com.mapbox.mapboxsdk.camera.CameraUpdateFactory\nimport com.mapbox.mapboxsdk.location.engine.*\nimport com.mapbox.mapboxsdk.maps.OnMapReadyCallback\nimport org.microg.gms.maps.mapbox.model.*\nimport org.microg.gms.maps.mapbox.utils.MultiArchLoader\nimport org.microg.gms.maps.mapbox.utils.toGms\nimport org.microg.gms.maps.mapbox.utils.toMapbox\nimport java.util.concurrent.atomic.AtomicBoolean\n\nprivate fun <T : Any> LongSparseArray<T>.values() = (0 until size()).mapNotNull { valueAt(it) }\n\nfun runOnMainLooper(forceQueue: Boolean = false, method: () -> Unit) {\n    if (!forceQueue && Looper.myLooper() == Looper.getMainLooper()) {\n        method()\n    } else {\n        Handler(Looper.getMainLooper()).post {\n            method()\n        }\n    }\n}\n\nclass GoogleMapImpl(context: Context, var options: GoogleMapOptions) : AbstractGoogleMap(context) {\n\n    val view: FrameLayout\n    var map: MapboxMap? = null\n        private set\n\n    private var mapView: MapView? = null\n    private var created = false\n    private var initialized = false\n    private var loaded = false\n    private val mapLock = Object()\n\n    private val internalOnInitializedCallbackList = mutableListOf<OnMapReadyCallback>()\n    private val userOnInitializedCallbackList = mutableListOf<IOnMapReadyCallback>()\n    private var loadedCallback: IOnMapLoadedCallback? = null\n    private var cameraChangeListener: IOnCameraChangeListener? = null\n    private var cameraMoveListener: IOnCameraMoveListener? = null\n    private var cameraMoveCanceledListener: IOnCameraMoveCanceledListener? = null\n    private var cameraMoveStartedListener: IOnCameraMoveStartedListener? = null\n    private var cameraIdleListener: IOnCameraIdleListener? = null\n    private var markerDragListener: IOnMarkerDragListener? = null\n\n    var lineManager: LineManager? = null\n    val pendingLines = mutableSetOf<Markup<Line, LineOptions>>()\n    var lineId = 0L\n\n    var fillManager: FillManager? = null\n    val pendingFills = mutableSetOf<Markup<Fill, FillOptions>>()\n    val circles = mutableMapOf<Long, CircleImpl>()\n    var fillId = 0L\n\n    var symbolManager: SymbolManager? = null\n    val pendingMarkers = mutableSetOf<MarkerImpl>()\n    val markers = mutableMapOf<Long, MarkerImpl>()\n    var markerId = 0L\n\n    val pendingBitmaps = mutableMapOf<String, Bitmap>()\n\n    var groundId = 0L\n    var tileId = 0L\n\n    var storedMapType: Int = options.mapType\n    var mapStyle: MapStyleOptions? = null\n    val waitingCameraUpdates = mutableListOf<CameraUpdate>()\n    var locationEnabled: Boolean = false\n\n    val defaultLocationEngine = GoogleLocationEngine(context)\n    var locationEngine: LocationEngine = defaultLocationEngine\n\n    var isStarted = false\n\n    init {\n        BitmapDescriptorFactoryImpl.initialize(mapContext.resources, context.resources)\n        LibraryLoader.setLibraryLoader(MultiArchLoader(mapContext, context))\n        runOnMainLooper {\n            Mapbox.getInstance(mapContext, BuildConfig.MAPBOX_KEY, WellKnownTileServer.Mapbox)\n        }\n\n\n        val fakeWatermark = View(mapContext)\n        fakeWatermark.tag = \"GoogleWatermark\"\n        fakeWatermark.layoutParams = object : RelativeLayout.LayoutParams(0, 0) {\n            @SuppressLint(\"RtlHardcoded\")\n            override fun addRule(verb: Int, subject: Int) {\n                super.addRule(verb, subject)\n                val rules = this.rules\n                var gravity = 0\n                if (rules[RelativeLayout.ALIGN_PARENT_BOTTOM] == RelativeLayout.TRUE) gravity = gravity or Gravity.BOTTOM\n                if (rules[RelativeLayout.ALIGN_PARENT_TOP] == RelativeLayout.TRUE) gravity = gravity or Gravity.TOP\n                if (rules[RelativeLayout.ALIGN_PARENT_LEFT] == RelativeLayout.TRUE) gravity = gravity or Gravity.LEFT\n                if (rules[RelativeLayout.ALIGN_PARENT_RIGHT] == RelativeLayout.TRUE) gravity = gravity or Gravity.RIGHT\n                if (rules[RelativeLayout.ALIGN_PARENT_START] == RelativeLayout.TRUE) gravity = gravity or Gravity.START\n                if (rules[RelativeLayout.ALIGN_PARENT_END] == RelativeLayout.TRUE) gravity = gravity or Gravity.END\n                map?.uiSettings?.logoGravity = gravity\n            }\n\n            override fun setMargins(left: Int, top: Int, right: Int, bottom: Int) {\n                super.setMargins(left, top, right, bottom)\n                map?.uiSettings?.setLogoMargins(left, top, right, bottom)\n            }\n        }\n        val fakeCompass = View(mapContext)\n        fakeCompass.tag = \"GoogleMapCompass\"\n        fakeCompass.layoutParams = object : RelativeLayout.LayoutParams(0, 0) {\n            @SuppressLint(\"RtlHardcoded\")\n            override fun addRule(verb: Int, subject: Int) {\n                super.addRule(verb, subject)\n                val rules = this.rules\n                var gravity = 0\n                if (rules[RelativeLayout.ALIGN_PARENT_BOTTOM] == RelativeLayout.TRUE) gravity = gravity or Gravity.BOTTOM\n                if (rules[RelativeLayout.ALIGN_PARENT_TOP] == RelativeLayout.TRUE) gravity = gravity or Gravity.TOP\n                if (rules[RelativeLayout.ALIGN_PARENT_LEFT] == RelativeLayout.TRUE) gravity = gravity or Gravity.LEFT\n                if (rules[RelativeLayout.ALIGN_PARENT_RIGHT] == RelativeLayout.TRUE) gravity = gravity or Gravity.RIGHT\n                if (rules[RelativeLayout.ALIGN_PARENT_START] == RelativeLayout.TRUE) gravity = gravity or Gravity.START\n                if (rules[RelativeLayout.ALIGN_PARENT_END] == RelativeLayout.TRUE) gravity = gravity or Gravity.END\n                map?.uiSettings?.compassGravity = gravity\n            }\n\n            override fun setMargins(left: Int, top: Int, right: Int, bottom: Int) {\n                super.setMargins(left, top, right, bottom)\n                map?.uiSettings?.setCompassMargins(left, top, right, bottom)\n            }\n        }\n        this.view = object : FrameLayout(mapContext) {\n            @Keep\n            fun <T : View> findViewTraversal(@IdRes id: Int): T? {\n                return null\n            }\n\n            @Keep\n            fun <T : View> findViewWithTagTraversal(tag: Any): T? {\n                if (\"GoogleWatermark\" == tag) {\n                    return try {\n                        @Suppress(\"UNCHECKED_CAST\")\n                        fakeWatermark as T\n                    } catch (e: ClassCastException) {\n                        null\n                    }\n                }\n                if (\"GoogleMapCompass\" == tag) {\n                    return try {\n                        @Suppress(\"UNCHECKED_CAST\")\n                        fakeCompass as T\n                    } catch (e: ClassCastException) {\n                        null\n                    }\n                }\n                return null\n            }\n        }\n    }\n\n    override fun getCameraPosition(): CameraPosition =\n        map?.cameraPosition?.toGms() ?: CameraPosition(LatLng(0.0, 0.0), 0f, 0f, 0f)\n\n    override fun getMaxZoomLevel(): Float = (map?.maxZoomLevel?.toFloat() ?: 20f) + 1f\n    override fun getMinZoomLevel(): Float = (map?.minZoomLevel?.toFloat() ?: 0f) + 1f\n\n    override fun moveCamera(cameraUpdate: IObjectWrapper?) {\n        val update = cameraUpdate.unwrap<CameraUpdate>() ?: return\n        synchronized(mapLock) {\n            if (initialized) {\n                this.map?.moveCamera(update)\n            } else {\n                waitingCameraUpdates.add(update)\n            }\n        }\n    }\n\n    override fun animateCamera(cameraUpdate: IObjectWrapper?) {\n        val update = cameraUpdate.unwrap<CameraUpdate>() ?: return\n        synchronized(mapLock) {\n            if (initialized) {\n                this.map?.animateCamera(update)\n            } else {\n                waitingCameraUpdates.add(update)\n            }\n        }\n    }\n\n    fun afterInitialize(runnable: (MapboxMap) -> Unit) {\n        synchronized(mapLock) {\n            if (initialized) {\n                runnable(map!!)\n            } else {\n                internalOnInitializedCallbackList.add(OnMapReadyCallback {\n                    runnable(it)\n                })\n            }\n        }\n    }\n\n    override fun animateCameraWithCallback(cameraUpdate: IObjectWrapper?, callback: ICancelableCallback?) {\n        val update = cameraUpdate.unwrap<CameraUpdate>() ?: return\n        synchronized(mapLock) {\n            if (initialized) {\n                this.map?.animateCamera(update, callback?.toMapbox())\n            } else {\n                waitingCameraUpdates.add(update)\n                afterInitialize { callback?.onFinish() }\n            }\n        }\n    }\n\n    override fun animateCameraWithDurationAndCallback(cameraUpdate: IObjectWrapper?, duration: Int, callback: ICancelableCallback?) {\n        val update = cameraUpdate.unwrap<CameraUpdate>() ?: return\n        synchronized(mapLock) {\n            if (initialized) {\n                this.map?.animateCamera(update, duration, callback?.toMapbox())\n            } else {\n                waitingCameraUpdates.add(update)\n                afterInitialize { callback?.onFinish() }\n            }\n        }\n    }\n\n    override fun stopAnimation() = map?.cancelTransitions() ?: Unit\n\n    override fun setMapStyle(options: MapStyleOptions?): Boolean {\n        Log.d(TAG, \"setMapStyle options: \" + options?.getJson())\n        mapStyle = options\n        applyMapStyle()\n        return true\n    }\n\n    override fun setMinZoomPreference(minZoom: Float) = afterInitialize {\n        it.setMinZoomPreference(minZoom.toDouble() - 1)\n    }\n\n    override fun setMaxZoomPreference(maxZoom: Float) = afterInitialize {\n        it.setMaxZoomPreference(maxZoom.toDouble() - 1)\n    }\n\n    override fun resetMinMaxZoomPreference() = afterInitialize {\n        it.setMinZoomPreference(MapboxConstants.MINIMUM_ZOOM.toDouble())\n        it.setMaxZoomPreference(MapboxConstants.MAXIMUM_ZOOM.toDouble())\n    }\n\n    override fun setLatLngBoundsForCameraTarget(bounds: LatLngBounds?) = afterInitialize {\n        it.setLatLngBoundsForCameraTarget(bounds?.toMapbox())\n    }\n\n    override fun addPolyline(options: PolylineOptions): IPolylineDelegate? {\n        val line = PolylineImpl(this, \"l${lineId++}\", options)\n        synchronized(this) {\n            val lineManager = lineManager\n            if (lineManager == null) {\n                pendingLines.add(line)\n            } else {\n                line.update(lineManager)\n            }\n        }\n        return line\n    }\n\n\n    override fun addPolygon(options: PolygonOptions): IPolygonDelegate? {\n        val fill = PolygonImpl(this, \"p${fillId++}\", options)\n        synchronized(this) {\n            val fillManager = fillManager\n            if (fillManager == null) {\n                pendingFills.add(fill)\n            } else {\n                fill.update(fillManager)\n            }\n\n            val lineManager = lineManager\n            if (lineManager == null) {\n                pendingLines.addAll(fill.strokes)\n            } else {\n                for (stroke in fill.strokes) stroke.update(lineManager)\n            }\n        }\n        return fill\n    }\n\n    override fun addMarker(options: MarkerOptions): IMarkerDelegate {\n        val marker = MarkerImpl(this, \"m${markerId++}\", options)\n        synchronized(this) {\n            val symbolManager = symbolManager\n            if (symbolManager == null) {\n                pendingMarkers.add(marker)\n            } else {\n                marker.update(symbolManager)\n            }\n        }\n        return marker\n    }\n\n    override fun addGroundOverlay(options: GroundOverlayOptions): IGroundOverlayDelegate? {\n        Log.d(TAG, \"unimplemented Method: addGroundOverlay\")\n        return GroundOverlayImpl(this, \"g${groundId++}\", options)\n    }\n\n    override fun addTileOverlay(options: TileOverlayOptions): ITileOverlayDelegate? {\n        Log.d(TAG, \"unimplemented Method: addTileOverlay\")\n        return TileOverlayImpl(this, \"t${tileId++}\", options)\n    }\n\n    override fun addCircle(options: CircleOptions): ICircleDelegate {\n        val circle = CircleImpl(this, \"c${fillId++}\", options)\n        synchronized(this) {\n            val fillManager = fillManager\n            if (fillManager == null) {\n                pendingFills.add(circle)\n            } else {\n                circle.update(fillManager)\n            }\n            val lineManager = lineManager\n            if (lineManager == null) {\n                pendingLines.add(circle.line)\n            } else {\n                circle.line.update(lineManager)\n            }\n            circle.strokePattern?.let {\n                addBitmap(\n                    it.getName(circle.strokeColor, circle.strokeWidth),\n                    it.makeBitmap(circle.strokeColor, circle.strokeWidth)\n                )\n            }\n        }\n        return circle\n    }\n\n    override fun clear() {\n        lineManager?.let { clear(it) }\n        fillManager?.let { clear(it) }\n        symbolManager?.let { clear(it) }\n    }\n\n    fun <T : Annotation<*>> clear(manager: AnnotationManager<*, T, *, *, *, *>) {\n        val annotations = manager.getAnnotations()\n        var i = 0\n        while (i < annotations.size()) {\n            val key = annotations.keyAt(i)\n            val value = annotations[key]\n            if (value is T) manager.delete(value)\n            else i++\n        }\n    }\n\n    override fun getMapType(): Int {\n        return storedMapType\n    }\n\n    override fun setMapType(type: Int) {\n        storedMapType = type\n        applyMapStyle()\n    }\n\n    fun applyMapStyle() {\n        val lines = lineManager?.annotations?.values()\n        val fills = fillManager?.annotations?.values()\n        val symbols = symbolManager?.annotations?.values()\n        val update: (Style) -> Unit = {\n            lines?.let { runCatching { lineManager?.update(it) } }\n            fills?.let { runCatching { fillManager?.update(it) } }\n            symbols?.let { runCatching { symbolManager?.update(it) } }\n        }\n\n        map?.setStyle(\n            getStyle(mapContext, storedMapType, mapStyle),\n            update\n        )\n\n        map?.let { BitmapDescriptorFactoryImpl.registerMap(it) }\n\n    }\n\n    override fun setWatermarkEnabled(watermark: Boolean) = afterInitialize {\n        it.uiSettings.isLogoEnabled = watermark\n    }\n\n    override fun isMyLocationEnabled(): Boolean {\n        return locationEnabled\n    }\n\n    override fun setMyLocationEnabled(myLocation: Boolean) {\n        synchronized(mapLock) {\n            locationEnabled = myLocation\n            if (!loaded) return\n            try {\n                updateLocationEngineListener(myLocation)\n            } catch (e: SecurityException) {\n                Log.w(TAG, e)\n                locationEnabled = false\n            }\n        }\n    }\n\n    private fun updateLocationEngineListener(myLocation: Boolean) {\n        map?.locationComponent?.let {\n            if (it.isLocationComponentActivated) {\n                it.isLocationComponentEnabled = myLocation\n                if (myLocation) {\n                    it.locationEngine?.requestLocationUpdates(it.locationEngineRequest, locationEngineCallback, Looper.getMainLooper())\n                } else {\n                    it.locationEngine?.removeLocationUpdates(locationEngineCallback)\n                }\n            }\n        }\n    }\n\n    override fun setLocationSource(locationSource: ILocationSourceDelegate?) {\n        synchronized(mapLock) {\n            updateLocationEngineListener(false)\n            locationEngine = locationSource?.let { SourceLocationEngine(it) } ?: defaultLocationEngine\n            if (!loaded) return\n            if (map?.locationComponent?.isLocationComponentActivated == true) {\n                map?.locationComponent?.locationEngine = locationEngine\n            }\n            updateLocationEngineListener(locationEnabled)\n        }\n    }\n\n    override fun getMyLocation(): Location? {\n        synchronized(mapLock) {\n            return map?.locationComponent?.lastKnownLocation\n        }\n    }\n\n    override fun onLocationUpdate(location: Location) {\n        // no action necessary, as the location component will automatically place a marker on the map\n    }\n\n    override fun setContentDescription(desc: String?) {\n        mapView?.contentDescription = desc\n    }\n\n    override fun getUiSettings(): IUiSettingsDelegate =\n        map?.uiSettings?.let { UiSettingsImpl(it) } ?: UiSettingsCache().also {\n            // Apply cached UI settings after map is initialized\n            internalOnInitializedCallbackList.add(it.getMapReadyCallback())\n        }\n\n    override fun getProjection(): IProjectionDelegate = map?.projection?.let {\n        val experiment = try {\n            map?.cameraPosition?.tilt == 0.0 && map?.cameraPosition?.bearing == 0.0\n        } catch (e: Exception) {\n            Log.w(TAG, e); false\n        }\n        ProjectionImpl(it, experiment)\n    } ?: DummyProjection()\n\n    override fun setOnCameraChangeListener(listener: IOnCameraChangeListener?) {\n        cameraChangeListener = listener\n    }\n\n    override fun setOnMarkerDragListener(listener: IOnMarkerDragListener?) {\n        markerDragListener = listener\n    }\n\n    override fun snapshot(callback: ISnapshotReadyCallback, bitmap: IObjectWrapper?) {\n        val map = map\n        if (map == null) {\n            // Snapshot cannot be taken\n            Log.e(TAG, \"snapshot could not be taken because map is null\")\n            runOnMainLooper { callback.onBitmapWrappedReady(ObjectWrapper.wrap(null)) }\n        } else {\n            if (!isStarted) {\n                Log.w(TAG, \"Caller did not call onStart() before taking snapshot. Calling onStart() now, for snapshot not to fail.\")\n                // Snapshots fail silently if onStart had not been called. This is the case with Signal.\n                onStart()\n                isStarted = true\n            }\n\n            Log.d(TAG, \"taking snapshot now\")\n\n            map.snapshot {\n                runOnMainLooper {\n                    Log.d(TAG, \"snapshot ready, providing to application\")\n                    callback.onBitmapWrappedReady(ObjectWrapper.wrap(it))\n                }\n            }\n        }\n    }\n\n    override fun snapshotForTest(callback: ISnapshotReadyCallback?) {\n        Log.d(TAG, \"Not yet implemented: snapshotForTest\")\n    }\n\n    override fun setPadding(left: Int, top: Int, right: Int, bottom: Int) = afterInitialize { map ->\n        Log.d(TAG, \"setPadding: $left $top $right $bottom\")\n        val padding = map.cameraPosition.padding\n        if (padding == null || padding[0] != left.toDouble() || padding[1] != top.toDouble() || padding[2] != right.toDouble() || padding[3] != bottom.toDouble()) {\n            // Don't send camera update if we already got these paddings\n            CameraUpdateFactory.paddingTo(left.toDouble(), top.toDouble(), right.toDouble(), bottom.toDouble())\n                .let { map.moveCamera(it) }\n        }\n\n        val fourDp = mapView?.context?.resources?.getDimension(R.dimen.maplibre_four_dp)?.toInt()\n                ?: 0\n        val ninetyTwoDp = mapView?.context?.resources?.getDimension(R.dimen.maplibre_ninety_two_dp)?.toInt()\n                ?: 0\n        map.uiSettings.setLogoMargins(left + fourDp, top + fourDp, right + fourDp, bottom + fourDp)\n        map.uiSettings.setCompassMargins(left + fourDp, top + fourDp, right + fourDp, bottom + fourDp)\n        map.uiSettings.setAttributionMargins(left + ninetyTwoDp, top + fourDp, right + fourDp, bottom + fourDp)\n    }\n\n    override fun setOnMapLoadedCallback(callback: IOnMapLoadedCallback?) {\n        if (callback != null) {\n            synchronized(mapLock) {\n                if (loaded) {\n                    callback.scheduleExecute()\n                } else {\n                    Log.d(TAG, \"Delay callback invocation, as map is not yet loaded\")\n                    loadedCallback = callback\n                }\n            }\n        } else {\n            loadedCallback = null\n        }\n    }\n\n    override fun setCameraMoveStartedListener(listener: IOnCameraMoveStartedListener?) {\n        cameraMoveStartedListener = listener\n    }\n\n    override fun setCameraMoveListener(listener: IOnCameraMoveListener?) {\n        cameraMoveListener = listener\n    }\n\n    override fun setCameraMoveCanceledListener(listener: IOnCameraMoveCanceledListener?) {\n        cameraMoveCanceledListener = listener\n    }\n\n    override fun setCameraIdleListener(listener: IOnCameraIdleListener?) {\n        cameraIdleListener = listener\n    }\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        if (!created) {\n            Log.d(TAG, \"create\");\n            val mapView = MapView(mapContext).apply { visibility = View.INVISIBLE }\n            this.mapView = mapView\n            view.addView(mapView)\n            mapView.onCreate(savedInstanceState?.toMapbox())\n            mapView.getMapAsync(this::initMap)\n            created = true\n            runOnMainLooper(forceQueue = true) { tryRunUserInitializedCallbacks(\"onCreate\") }\n        }\n    }\n\n    private fun hasSymbolAt(latlng: com.mapbox.mapboxsdk.geometry.LatLng): Boolean {\n        val point = map?.projection?.toScreenLocation(latlng) ?: return false\n        val features = map?.queryRenderedFeatures(point, symbolManager?.layerId)\n                ?: return false\n        return features.isNotEmpty()\n    }\n\n    private fun initMap(map: MapboxMap) {\n        if (this.map != null) return\n        this.map = map\n\n        map.addOnCameraIdleListener {\n            try {\n                cameraChangeListener?.onCameraChange(map.cameraPosition.toGms())\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n            }\n            try {\n                cameraIdleListener?.onCameraIdle()\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n            }\n        }\n        map.addOnCameraMoveListener {\n            try {\n                cameraMoveListener?.onCameraMove()\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n            }\n            currentInfoWindow?.update()\n        }\n        map.addOnCameraMoveStartedListener {\n            try {\n                val reason = when (it) {\n                    MapboxMap.OnCameraMoveStartedListener.REASON_API_GESTURE -> GoogleMap.OnCameraMoveStartedListener.REASON_GESTURE\n                    MapboxMap.OnCameraMoveStartedListener.REASON_API_ANIMATION -> GoogleMap.OnCameraMoveStartedListener.REASON_API_ANIMATION\n                    MapboxMap.OnCameraMoveStartedListener.REASON_DEVELOPER_ANIMATION -> GoogleMap.OnCameraMoveStartedListener.REASON_DEVELOPER_ANIMATION\n                    else -> 0\n                }\n                cameraMoveStartedListener?.onCameraMoveStarted(reason)\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n            }\n        }\n        map.addOnCameraMoveCancelListener {\n            try {\n                cameraMoveCanceledListener?.onCameraMoveCanceled()\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n            }\n        }\n        map.addOnMapClickListener { latlng ->\n            try {\n                if (!hasSymbolAt(latlng)) {\n                    mapClickListener?.onMapClick(latlng.toGms())\n                    currentInfoWindow?.close()\n                    currentInfoWindow = null\n                }\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n            }\n            false\n        }\n        map.addOnMapLongClickListener { latlng ->\n            try {\n                mapLongClickListener?.let { if (!hasSymbolAt(latlng)) it.onMapLongClick(latlng.toGms()); }\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n            }\n            false\n        }\n\n        applyMapStyle()\n        options.minZoomPreference?.let { if (it != 0f) map.setMinZoomPreference(it.toDouble()) }\n        options.maxZoomPreference?.let { if (it != 0f) map.setMaxZoomPreference(it.toDouble()) }\n        options.latLngBoundsForCameraTarget?.let { map.setLatLngBoundsForCameraTarget(it.toMapbox()) }\n        options.compassEnabled?.let { map.uiSettings.isCompassEnabled = it }\n        options.rotateGesturesEnabled?.let { map.uiSettings.isRotateGesturesEnabled = it }\n        options.scrollGesturesEnabled?.let { map.uiSettings.isScrollGesturesEnabled = it }\n        options.tiltGesturesEnabled?.let { map.uiSettings.isTiltGesturesEnabled = it }\n        options.camera?.let { map.cameraPosition = it.toMapbox() }\n\n        synchronized(mapLock) {\n            initialized = true\n            waitingCameraUpdates.forEach { map.moveCamera(it) }\n            val initializedCallbackList = ArrayList(internalOnInitializedCallbackList)\n            Log.d(TAG, \"Invoking ${initializedCallbackList.size} internal callbacks now that the true map is initialized\")\n            for (callback in initializedCallbackList) {\n                callback.onMapReady(map)\n            }\n        }\n\n        // No effect if no initialized callbacks are present.\n        tryRunUserInitializedCallbacks(tag = \"initMap\")\n\n        map.getStyle {\n            mapView?.let { view ->\n                if (loaded) return@let\n                val symbolManager: SymbolManager\n                val lineManager: LineManager\n                val fillManager: FillManager\n\n                synchronized(mapLock) {\n                    fillManager = FillManager(view, map, it)\n                    symbolManager = SymbolManager(view, map, it)\n                    lineManager = LineManager(view, map, it)\n                    lineManager.lineCap = LINE_CAP_ROUND\n\n                    this.symbolManager = symbolManager\n                    this.lineManager = lineManager\n                    this.fillManager = fillManager\n                }\n                symbolManager.iconAllowOverlap = true\n                symbolManager.addClickListener {\n                    val marker = markers[it.id]\n                    try {\n                        if (markers[it.id]?.let { markerClickListener?.onMarkerClick(it) } == true) {\n                            return@addClickListener true\n                        }\n                    } catch (e: Exception) {\n                        Log.w(TAG, e)\n                        return@addClickListener false\n                    }\n\n                    marker?.let { showInfoWindow(it) } == true\n                }\n                symbolManager.addDragListener(object : OnSymbolDragListener {\n                    override fun onAnnotationDragStarted(annotation: Symbol?) {\n                        try {\n                            markers[annotation?.id]?.let { markerDragListener?.onMarkerDragStart(it) }\n                        } catch (e: Exception) {\n                            Log.w(TAG, e)\n                        }\n                    }\n\n                    override fun onAnnotationDrag(annotation: Symbol?) {\n                        try {\n                            annotation?.let { symbol ->\n                                markers[symbol.id]?.let { marker ->\n                                    marker.setPositionWhileDragging(symbol.latLng.toGms())\n                                    markerDragListener?.onMarkerDrag(marker)\n                                }\n                            }\n                        } catch (e: Exception) {\n                            Log.w(TAG, e)\n                        }\n                    }\n\n                    override fun onAnnotationDragFinished(annotation: Symbol?) {\n                        mapView?.post {\n                        try {\n                            markers[annotation?.id]?.let { markerDragListener?.onMarkerDragEnd(it) }\n                        } catch (e: Exception) {\n                            Log.w(TAG, e)\n                        }\n                        }\n                    }\n                })\n                fillManager.addClickListener { fill ->\n                    try {\n                        circles[fill.id]?.let { circle ->\n                            if (circle.isClickable) {\n                                circleClickListener?.let {\n                                    it.onCircleClick(circle)\n                                    return@addClickListener true\n                                }\n                            }\n                        }\n                    } catch (e: Exception) {\n                        Log.w(TAG, e)\n                    }\n                    false\n                }\n                pendingFills.forEach { it.update(fillManager) }\n                pendingFills.clear()\n                pendingLines.forEach { it.update(lineManager) }\n                pendingLines.clear()\n                pendingMarkers.forEach { it.update(symbolManager) }\n                pendingMarkers.clear()\n\n                pendingBitmaps.forEach { map -> it.addImage(map.key, map.value) }\n                pendingBitmaps.clear()\n\n                map.locationComponent.apply {\n                    activateLocationComponent(LocationComponentActivationOptions.builder(mapContext, it)\n                            .locationEngine(this@GoogleMapImpl.locationEngine)\n                            .useSpecializedLocationLayer(true)\n                            .locationComponentOptions(LocationComponentOptions.builder(mapContext).pulseEnabled(true).build())\n                            .build())\n                    cameraMode = CameraMode.NONE\n                    renderMode = RenderMode.COMPASS\n                    setMaxAnimationFps(2)\n                }\n\n                synchronized(mapLock) {\n                    loaded = true\n                    loadedCallback?.scheduleExecute()\n                }\n\n                isMyLocationEnabled = locationEnabled\n\n                view.visibility = View.VISIBLE\n            }\n        }\n    }\n\n    override fun showInfoWindow(marker: AbstractMarker): Boolean {\n        infoWindowAdapter.getInfoWindowViewFor(marker, mapContext)?.let { infoView ->\n            currentInfoWindow?.close()\n            currentInfoWindow = InfoWindow(infoView, this, marker).also { infoWindow ->\n                mapView?.let { infoWindow.open(it) }\n            }\n            return true\n        }\n        return false\n    }\n\n    internal fun addBitmap(name: String, bitmap: Bitmap) {\n        val map = map\n        if (map != null) {\n            map.getStyle {\n                it.addImage(name, bitmap)\n            }\n        } else {\n            pendingBitmaps[name] = bitmap\n        }\n    }\n\n    override fun onResume() {\n        Log.d(TAG, \"onResume\")\n        mapView?.visibility = View.VISIBLE\n        if (!isStarted) {\n            // onStart was not called, invoke mapView.onStart() now\n            mapView?.onStart()\n        }\n        mapView?.onResume()\n        map?.locationComponent?.let {\n            if (it.isLocationComponentEnabled) {\n                it.locationEngine?.requestLocationUpdates(it.locationEngineRequest, locationEngineCallback, Looper.getMainLooper())\n            }\n        }\n    }\n    override fun onPause() {\n        Log.d(TAG, \"onPause\")\n        map?.locationComponent?.let {\n            if (it.isLocationComponentEnabled) {\n                it.locationEngine?.removeLocationUpdates(locationEngineCallback)\n            }\n        }\n        mapView?.onPause()\n        if (!isStarted) {\n            // onStart was not called, invoke mapView.onStop() now\n            mapView?.onStop()\n        }\n    }\n    override fun onDestroy() {\n        Log.d(TAG, \"onDestroy\");\n        userOnInitializedCallbackList.clear()\n        lineManager?.onDestroy()\n        lineManager = null\n        fillManager?.onDestroy()\n        fillManager = null\n        circles.clear()\n        symbolManager?.onDestroy()\n        symbolManager = null\n        currentInfoWindow?.close()\n        pendingMarkers.clear()\n        markers.clear()\n        BitmapDescriptorFactoryImpl.unregisterMap(map)\n        view.removeView(mapView)\n        // TODO can crash?\n        mapView?.onDestroy()\n        mapView = null\n\n        map = null\n\n        created = false\n        initialized = false\n        loaded = false\n    }\n\n    override fun onStart() {\n        Log.d(TAG, \"onStart\")\n        isStarted = true\n        mapView?.onStart()\n    }\n\n    override fun onStop() {\n        Log.d(TAG, \"onStop\")\n        mapView?.visibility = View.INVISIBLE\n        isStarted = false\n        mapView?.onStop()\n    }\n\n    override fun onLowMemory() = mapView?.onLowMemory() ?: Unit\n\n    override fun onSaveInstanceState(outState: Bundle) {\n        val newBundle = Bundle()\n        mapView?.onSaveInstanceState(newBundle)\n        outState.putAll(newBundle.toGms())\n    }\n\n    fun getMapAsync(callback: IOnMapReadyCallback) {\n        synchronized(mapLock) {\n            userOnInitializedCallbackList.add(callback)\n        }\n        tryRunUserInitializedCallbacks(\"getMapAsync\")\n    }\n\n    /**\n     * Per docs, `onMapLoaded` shall only be called when the map has finished loading,\n     * and some apps like Signal location sharing rely on this to behave accordingly.\n     * However, MapLibre does not provide proper `onMapLoaded` callbacks.\n     *\n     * Workaround: schedule map loaded callback for a certain time in the future.\n     */\n    private fun IOnMapLoadedCallback.scheduleExecute() {\n        Log.d(TAG, \"Scheduling executing of OnMapLoadedCallback in ${ON_MAP_LOADED_CALLBACK_DELAY}ms, as map is now initialized.\")\n        Handler(Looper.getMainLooper()).postDelayed({\n            Log.d(TAG, \"Executing scheduled onMapLoaded callback\")\n\n            try {\n                this.onMapLoaded()\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n            }\n\n        }, ON_MAP_LOADED_CALLBACK_DELAY)\n    }\n\n    private var isInvokingInitializedCallbacks = AtomicBoolean(false)\n\n    fun tryRunUserInitializedCallbacks(tag: String = \"\") {\n\n        synchronized(mapLock) {\n            if (userOnInitializedCallbackList.isEmpty()) return\n        }\n\n        val runCallbacks = {\n            val callbacks = synchronized(mapLock) {\n                ArrayList(userOnInitializedCallbackList)\n                    .also { userOnInitializedCallbackList.clear() }\n            }\n\n            callbacks.forEach {\n                try {\n                    it.onMapReady(this)\n                } catch (e: Exception) {\n                    Log.w(TAG, e)\n                }\n            }\n        }\n\n        val map = map\n        if (initialized && map != null) {\n            // Call all callbacks immediately, as map is ready\n            Log.d(\"$TAG:$tag\", \"Invoking callback now, as map is initialized\")\n            val wasCallbackActive = isInvokingInitializedCallbacks.getAndSet(true)\n            runOnMainLooper(forceQueue = wasCallbackActive) {\n                runCallbacks()\n            }\n            if (!wasCallbackActive) isInvokingInitializedCallbacks.set(false)\n        } else if (mapView?.isShown == false) {\n            /* If map is hidden, an app (e.g. Dott) may expect it to initialize anyway and\n             * will not show the map until it is initialized. However, we should not call\n             * the callback before onCreate is started (we know this is the case if mapView is\n             * null), otherwise that results in other problems (e.g. Gas Now app not\n             * initializing).\n             */\n            runOnMainLooper(forceQueue = true) {\n                Log.d(\"$TAG:$tag\", \"Invoking callback now: map cannot be initialized because it is not shown (yet)\")\n                runCallbacks()\n            }\n        } else {\n            Log.d(\"$TAG:$tag\", \"Initialized callbacks could not be run at this point, as the map view has not been created yet.\")\n            // Will be retried after initialization.\n        }\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =\n            if (super.onTransact(code, data, reply, flags)) {\n                true\n            } else {\n                Log.d(TAG, \"onTransact [unknown]: $code, $data, $flags\"); false\n            }\n\n    companion object {\n        private const val TAG = \"GmsMap\"\n        private const val ON_MAP_LOADED_CALLBACK_DELAY = 500L\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/LiteGoogleMap.kt",
    "content": "package org.microg.gms.maps.mapbox\n\nimport android.Manifest\nimport android.content.ActivityNotFoundException\nimport android.content.Context\nimport android.content.Intent\nimport android.content.Intent.ACTION_VIEW\nimport android.content.pm.PackageManager\nimport android.graphics.PointF\nimport android.location.Location\nimport android.net.Uri\nimport android.os.Bundle\nimport android.os.Handler\nimport android.os.Looper\nimport android.util.Log\nimport android.view.View\nimport android.view.ViewGroup.LayoutParams.MATCH_PARENT\nimport android.widget.FrameLayout\nimport android.widget.ImageView\nimport androidx.annotation.UiThread\nimport androidx.core.app.ActivityCompat\nimport androidx.core.content.ContextCompat\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.ObjectWrapper\nimport com.google.android.gms.dynamic.unwrap\nimport com.google.android.gms.maps.GoogleMapOptions\nimport com.google.android.gms.maps.internal.*\nimport com.google.android.gms.maps.model.*\nimport com.google.android.gms.maps.model.internal.*\nimport com.mapbox.mapboxsdk.Mapbox\nimport com.mapbox.mapboxsdk.WellKnownTileServer\nimport com.mapbox.mapboxsdk.location.engine.*\nimport com.mapbox.mapboxsdk.plugins.annotation.SymbolOptions\nimport com.mapbox.mapboxsdk.snapshotter.MapSnapshot\nimport com.mapbox.mapboxsdk.snapshotter.MapSnapshotter\nimport com.mapbox.mapboxsdk.style.layers.*\nimport com.mapbox.mapboxsdk.style.sources.GeoJsonSource\nimport com.mapbox.turf.TurfConstants.UNIT_METERS\nimport com.mapbox.turf.TurfMeasurement\nimport org.microg.gms.maps.mapbox.model.*\nimport org.microg.gms.maps.mapbox.utils.toGms\nimport org.microg.gms.maps.mapbox.utils.toMapbox\nimport org.microg.gms.maps.mapbox.utils.toPoint\nimport java.util.concurrent.atomic.AtomicBoolean\nimport kotlin.math.max\nimport kotlin.math.roundToInt\n\n// From com.mapbox.mapboxsdk.location.LocationComponent\nconst val DEFAULT_INTERVAL_MILLIS = 1000L\nconst val DEFAULT_FASTEST_INTERVAL_MILLIS = 1000L\n\nclass MetaSnapshot(\n    val snapshot: MapSnapshot,\n    val cameraPosition: CameraPosition,\n    val cameraBounds: com.mapbox.mapboxsdk.geometry.LatLngBounds?,\n    val width: Int,\n    val height: Int,\n    val paddingRight: Int,\n    val paddingTop: Int,\n    val dpi: Float\n) {\n    fun latLngForPixelFixed(point: PointF) = snapshot.latLngForPixel(\n        PointF(\n            point.x / dpi, point.y / dpi\n        )\n    )\n}\n\nclass LiteGoogleMapImpl(context: Context, var options: GoogleMapOptions) : AbstractGoogleMap(context) {\n\n    internal val view: FrameLayout = FrameLayout(mapContext)\n    val map: ImageView\n\n    private var created = false\n\n    private var cameraPosition: CameraPosition = options.camera ?: CameraPosition.fromLatLngZoom(LatLng(0.0, 0.0), 2f)\n    private var cameraBounds: com.mapbox.mapboxsdk.geometry.LatLngBounds? = null\n\n    private var mapType: Int = options.mapType\n    private var mapStyle: MapStyleOptions? = null\n\n    private var currentSnapshotter: MapSnapshotter? = null\n\n    private var lastSnapshot: MetaSnapshot? = null\n\n    private var lastTouchPosition = PointF(0f, 0f)\n\n    private val afterNextDrawCallback = mutableListOf<() -> Unit>()\n    private var cameraChangeListener: IOnCameraChangeListener? = null\n\n    private var myLocationEnabled = false\n    private var myLocation: Location? = null\n    private val defaultLocationEngine = GoogleLocationEngine(context)\n    private var locationEngine: LocationEngine = defaultLocationEngine\n\n    internal val markers: MutableList<LiteMarkerImpl> = mutableListOf()\n    internal val polygons: MutableList<LitePolygonImpl> = mutableListOf()\n    internal val polylines: MutableList<AbstractPolylineImpl> = mutableListOf()\n    internal val circles: MutableList<LiteCircleImpl> = mutableListOf()\n\n    private var nextObjectId = 0\n\n    private var showWatermark = true\n\n    private val updatePosted = AtomicBoolean(false)\n\n    init {\n        map = ImageView(mapContext).apply {\n            layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)\n        }\n\n        view.addView(map)\n\n        view.addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->\n            postUpdateSnapshot()\n            currentInfoWindow?.update()\n        }\n\n        BitmapDescriptorFactoryImpl.initialize(mapContext.resources, context.resources)\n\n        // noinspection ClickableViewAccessibility; touch listener only has side effects\n        map.setOnTouchListener { _, event ->\n            lastTouchPosition = PointF(event.x + map.paddingLeft, event.y + map.paddingTop)\n            false\n        }\n\n        map.setOnClickListener {\n\n            // Test if clickable\n            if ((view.parent as View?)?.isClickable == false) return@setOnClickListener\n\n            lastSnapshot?.let { meta ->\n                // Calculate marker hitboxes\n                for (marker in markers.filter { it.isVisible }) {\n\n                    marker.getIconDimensions()?.let { iconDimensions -> // consider only markers with icon\n                        val anchorPoint = meta.snapshot.pixelForLatLng(marker.position.toMapbox())\n\n                        val leftX = anchorPoint.x - marker.anchor[0] * iconDimensions[0]\n                        val topY = anchorPoint.y - marker.anchor[1] * iconDimensions[1]\n\n                        if (lastTouchPosition.x >= leftX && lastTouchPosition.x <= leftX + iconDimensions[0]\n                            && lastTouchPosition.y >= topY && lastTouchPosition.y <= topY + iconDimensions[1]) {\n                            // Marker was clicked\n                            if (markerClickListener?.onMarkerClick(marker) == true) {\n                                currentInfoWindow?.close()\n                                currentInfoWindow = null\n                                return@setOnClickListener\n                            } else if (showInfoWindow(marker)) {\n                                return@setOnClickListener\n                            }\n                        }\n                    }\n                }\n\n                currentInfoWindow?.close()\n                currentInfoWindow = null\n\n                // Test if circle was clicked\n                for (circle in circles.filter { it.isVisible && it.isClickable }) {\n                    Log.d(TAG, \"last touch ${lastTouchPosition.x}, ${lastTouchPosition.y}, turf ${TurfMeasurement.distance(\n                        circle.center.toPoint(),\n                        meta.latLngForPixelFixed(lastTouchPosition).toPoint(),\n                        UNIT_METERS\n                    )}, radius ${circle.radiusInMeters}\")\n                    if (TurfMeasurement.distance(\n                        circle.center.toPoint(),\n                        meta.latLngForPixelFixed(lastTouchPosition).toPoint(),\n                        UNIT_METERS\n                    ) <= circle.radiusInMeters) {\n                        // Circle was clicked\n                        circleClickListener?.onCircleClick(circle)\n                        return@setOnClickListener\n                    }\n                }\n\n                val clickedPosition = meta.latLngForPixelFixed(lastTouchPosition)\n                val clickListenerConsumedClick = mapClickListener?.let {\n                    it.onMapClick(clickedPosition.toGms())\n                    true\n                } ?: false\n\n                if (clickListenerConsumedClick) return@setOnClickListener\n\n                // else open external map at clicked location\n                val intent =\n                    Intent(ACTION_VIEW, Uri.parse(\"geo:${clickedPosition.latitude},${clickedPosition.longitude}\"))\n\n                try {\n                    context.startActivity(intent)\n                } catch (e: ActivityNotFoundException) {\n                    Log.e(TAG, \"No compatible mapping application installed. Not handling click.\")\n                }\n            }\n\n\n        }\n        map.setOnLongClickListener {\n            mapLongClickListener?.onMapLongClick(\n                lastSnapshot?.latLngForPixelFixed(lastTouchPosition)?.toGms() ?: LatLng(0.0, 0.0)\n            )\n            mapLongClickListener != null\n        }\n    }\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        if (!created) {\n\n            Mapbox.getInstance(mapContext, BuildConfig.MAPBOX_KEY, WellKnownTileServer.Mapbox)\n\n            if (savedInstanceState?.containsKey(BUNDLE_CAMERA_POSITION) == true) {\n                cameraPosition = savedInstanceState.getParcelable(BUNDLE_CAMERA_POSITION)!!\n                cameraBounds = (savedInstanceState.getParcelable(BUNDLE_CAMERA_BOUNDS) as LatLngBounds?)?.toMapbox()\n            }\n\n            postUpdateSnapshot()\n\n            created = true\n        }\n    }\n\n    internal fun postUpdateSnapshot() {\n        if (updatePosted.compareAndSet(false, true)) {\n            Handler(Looper.getMainLooper()).post {\n                updatePosted.set(false)\n                updateSnapshot()\n            }\n        }\n    }\n\n    @UiThread\n    private fun updateSnapshot() {\n\n        val cameraPosition = cameraPosition\n        val dpi = dpiFactor\n\n        val cameraBounds = cameraBounds\n\n        val pixelWidth = map.width\n        val pixelHeight = map.height\n\n        val styleBuilder = getStyle(mapContext, mapType, mapStyle, styleFromFileWorkaround = true)\n\n        // Add visible polygons (before polylines, so that they are drawn below their strokes)\n        for (polygon in polygons.filter { it.isVisible }) {\n            styleBuilder.withLayer(\n                FillLayer(\"l${polygon.id}\", polygon.id).withProperties(\n                    PropertyFactory.fillColor(polygon.fillColor)\n                )\n            ).withSource(\n                GeoJsonSource(polygon.id, polygon.annotationOptions.geometry)\n            )\n        }\n\n        // Add visible polylines\n        for (polyline in polylines.filter { it.isVisible }) {\n            styleBuilder.withLayer(\n                LineLayer(\"l${polyline.id}\", polyline.id).withProperties(\n                    PropertyFactory.lineWidth(polyline.width),\n                    PropertyFactory.lineColor(polyline.color),\n                    PropertyFactory.lineCap(Property.LINE_CAP_ROUND)\n                )\n            ).withSource(\n                GeoJsonSource(polyline.id, polyline.annotationOptions.geometry)\n            )\n        }\n\n        // Add circles\n        for (circle in circles.filter { it.isVisible }) {\n            styleBuilder.withLayer(FillLayer(\"l${circle.id}c\", circle.id).withProperties(\n                PropertyFactory.fillColor(circle.fillColor)\n            )).withSource(GeoJsonSource(circle.id, circle.annotationOptions.geometry))\n\n            styleBuilder.withLayer(LineLayer(\"l${circle.id}s\", \"${circle.id}s\").withProperties(\n                PropertyFactory.lineWidth(circle.strokeWidth),\n                PropertyFactory.lineColor(circle.strokeColor),\n                PropertyFactory.lineCap(Property.LINE_CAP_ROUND),\n            ).apply {\n                circle.strokePattern?.let {\n                    val name = it.getName(circle.strokeColor, circle.strokeWidth, dpi)\n                    withProperties(PropertyFactory.linePattern(name))\n                    styleBuilder.withImage(name, it.makeBitmap(circle.strokeColor, circle.strokeWidth, dpi))\n                }\n            }).withSource(GeoJsonSource(\"${circle.id}s\", circle.line.annotationOptions.geometry))\n        }\n\n        // Add markers\n        BitmapDescriptorFactoryImpl.put(styleBuilder)\n        for (marker in markers.filter { it.isVisible }) {\n            val layer = SymbolLayer(\"l${marker.id}\", marker.id).withProperties(\n                PropertyFactory.symbolSortKey(marker.zIndex),\n                PropertyFactory.iconAllowOverlap(true)\n            )\n            marker.icon?.applyTo(layer, marker.anchor, dpi)\n            styleBuilder.withLayer(layer).withSource(\n                GeoJsonSource(marker.id, marker.annotationOptions.geometry)\n            )\n        }\n\n        // Add location overlay\n        if (myLocationEnabled) myLocation?.let {\n            val indicator = ContextCompat.getDrawable(mapContext, R.drawable.location_dot)!!\n            styleBuilder.withImage(\"locationIndicator\", indicator)\n            val layer = SymbolLayer(\"location\", \"locationSource\").withProperties(\n                PropertyFactory.iconAllowOverlap(true),\n                PropertyFactory.iconImage(\"locationIndicator\"),\n                PropertyFactory.iconAnchor(Property.ICON_ANCHOR_TOP_LEFT),\n                PropertyFactory.iconOffset(arrayOf(\n                    0.5f * indicator.minimumWidth / dpi, 0.5f * indicator.minimumHeight / dpi\n                ))\n            )\n            styleBuilder.withLayer(layer).withSource(\n                GeoJsonSource(\n                    \"locationSource\",\n                    SymbolOptions().withLatLng(com.mapbox.mapboxsdk.geometry.LatLng(it.latitude, it.longitude)).geometry\n                )\n            )\n        }\n\n        val dpiWidth = max(pixelWidth / dpi, 1f).roundToInt()\n        val dpiHeight = max(pixelHeight / dpi, 1f).roundToInt()\n\n        val snapshotter = MapSnapshotter(\n            mapContext, MapSnapshotter.Options(dpiWidth, dpiHeight)\n                .withCameraPosition(this@LiteGoogleMapImpl.cameraPosition.toMapbox())\n                .apply {\n                    // if camera bounds are set, overwrite camera position\n                    cameraBounds?.let { withRegion(it) }\n                }\n                .withStyleBuilder(styleBuilder)\n                .withLogo(showWatermark)\n                .withPixelRatio(dpi)\n        )\n\n        synchronized(this) {\n            this.currentSnapshotter?.cancel()\n            this.currentSnapshotter = snapshotter\n        }\n\n        snapshotter.start({\n\n            val cameraPositionChanged = cameraPosition != lastSnapshot?.cameraPosition || (cameraBounds != lastSnapshot?.cameraBounds)\n\n            lastSnapshot = MetaSnapshot(\n                it, cameraPosition, cameraBounds, pixelWidth, pixelHeight, view.paddingRight, view.paddingTop, dpi\n            )\n            map.setImageBitmap(it.bitmap)\n\n            ArrayList(afterNextDrawCallback)\n                .also { afterNextDrawCallback.clear() }\n                .forEach { it() }\n\n            if (cameraPositionChanged) {\n                // Notify apps that new projection is now available\n                cameraChangeListener?.onCameraChange(cameraPosition)\n            }\n\n            currentInfoWindow?.update()\n\n            synchronized(this) {\n                this.currentSnapshotter = null\n            }\n\n        }, null)\n    }\n\n    fun getMapAsync(callback: IOnMapReadyCallback) {\n        if (lastSnapshot != null) {\n            Log.d(TAG, \"Invoking callback instantly, as a snapshot is ready\")\n            callback.onMapReady(this)\n        } else {\n            Log.d(TAG, \"Delay callback invocation, as snapshot has not been rendered yet\")\n            afterNextDrawCallback.add { callback.onMapReady(this) }\n        }\n    }\n\n    override fun getCameraPosition(): CameraPosition = cameraPosition\n\n    override fun getMaxZoomLevel() = 21f\n\n    override fun getMinZoomLevel() = 1f\n\n    override fun moveCamera(cameraUpdate: IObjectWrapper?): Unit = cameraUpdate.unwrap<LiteModeCameraUpdate>()?.let {\n        cameraPosition = it.getLiteModeCameraPosition(this) ?: cameraPosition\n        cameraBounds = it.getLiteModeCameraBounds()\n\n        postUpdateSnapshot()\n    } ?: Unit\n\n    override fun animateCamera(cameraUpdate: IObjectWrapper?) = moveCamera(cameraUpdate)\n\n    override fun animateCameraWithCallback(cameraUpdate: IObjectWrapper?, callback: ICancelableCallback?) {\n        moveCamera(cameraUpdate)\n        Log.d(TAG, \"animateCameraWithCallback: animation not possible in lite mode, invoking callback instantly\")\n        callback?.onFinish()\n    }\n\n    override fun animateCameraWithDurationAndCallback(\n        cameraUpdate: IObjectWrapper?, duration: Int, callback: ICancelableCallback?\n    ) = animateCameraWithCallback(cameraUpdate, callback)\n\n    override fun stopAnimation() {\n        Log.d(TAG, \"stopAnimation: animation not possible in lite mode\")\n    }\n\n    override fun addPolyline(options: PolylineOptions): IPolylineDelegate {\n        return LitePolylineImpl(this, \"polyline${nextObjectId++}\", options).also { polylines.add(it) }\n    }\n\n    override fun addPolygon(options: PolygonOptions): IPolygonDelegate {\n        return LitePolygonImpl(\n            \"polygon${nextObjectId++}\", options, this\n        ).also {\n            polygons.add(it)\n            polylines.addAll(it.strokes)\n            postUpdateSnapshot()\n        }\n    }\n\n    override fun addMarker(options: MarkerOptions): IMarkerDelegate {\n        return LiteMarkerImpl(\"marker${nextObjectId++}\", options, this).also {\n            markers.add(it)\n            postUpdateSnapshot()\n        }\n    }\n\n    override fun addGroundOverlay(options: GroundOverlayOptions?): IGroundOverlayDelegate? {\n        Log.d(TAG, \"addGroundOverlay: not supported in lite mode\")\n        return null\n    }\n\n    override fun addTileOverlay(options: TileOverlayOptions?): ITileOverlayDelegate? {\n        Log.d(TAG, \"addTileOverlay: not supported in lite mode\")\n        return null\n    }\n\n    override fun clear() {\n        polylines.clear()\n        polygons.clear()\n        markers.clear()\n        circles.clear()\n        postUpdateSnapshot()\n    }\n\n    override fun getMapType(): Int {\n        return mapType\n    }\n\n    override fun setMapType(type: Int) {\n        mapType = type\n        postUpdateSnapshot()\n    }\n\n    override fun isTrafficEnabled(): Boolean {\n        Log.d(TAG, \"isTrafficEnabled: traffic not supported in lite mode\")\n        return false\n    }\n\n    override fun setTrafficEnabled(traffic: Boolean) {\n        Log.d(TAG, \"setTrafficEnabled: traffic not supported in lite mode\")\n    }\n\n    override fun isIndoorEnabled(): Boolean {\n        Log.d(TAG, \"isIndoorEnabled: indoor not supported in lite mode\")\n        return false\n    }\n\n    override fun setIndoorEnabled(indoor: Boolean) {\n        Log.d(TAG, \"setIndoorEnabled: indoor not supported in lite mode\")\n    }\n\n    override fun isMyLocationEnabled(): Boolean = myLocationEnabled\n\n    override fun setMyLocationEnabled(myLocation: Boolean) {\n        if (!myLocationEnabled && myLocation) {\n            activateLocationProvider()\n        } else if (myLocationEnabled && !myLocation) {\n            deactivateLocationProvider()\n        } // else situation is unchanged\n        myLocationEnabled = myLocation\n    }\n\n    private fun activateLocationProvider() {\n        // Activate only if sufficient permissions\n        if (ActivityCompat.checkSelfPermission(\n                mapContext, Manifest.permission.ACCESS_FINE_LOCATION\n            ) == PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(\n                mapContext, Manifest.permission.ACCESS_COARSE_LOCATION\n            ) == PackageManager.PERMISSION_GRANTED\n        ) {\n            locationEngine.requestLocationUpdates(\n                LocationEngineRequest.Builder(DEFAULT_INTERVAL_MILLIS)\n                    .setFastestInterval(DEFAULT_FASTEST_INTERVAL_MILLIS)\n                    .setPriority(LocationEngineRequest.PRIORITY_HIGH_ACCURACY)\n                    .build(), locationEngineCallback, Looper.getMainLooper()\n            )\n\n        } else {\n            Log.w(TAG, \"Called setMyLocationEnabled(true) without sufficient permissions. Not showing location.\")\n        }\n    }\n\n    private fun deactivateLocationProvider() {\n        locationEngine.removeLocationUpdates(locationEngineCallback)\n    }\n\n    override fun setLocationSource(locationSource: ILocationSourceDelegate?) {\n        if (myLocationEnabled) deactivateLocationProvider()\n        locationEngine = locationSource?.let { SourceLocationEngine(it) } ?: defaultLocationEngine\n        if (myLocationEnabled) activateLocationProvider()\n    }\n\n    override fun onLocationUpdate(location: Location) {\n        this@LiteGoogleMapImpl.myLocation = location\n        postUpdateSnapshot()\n    }\n\n    override fun getUiSettings(): IUiSettingsDelegate {\n        Log.d(TAG, \"UI settings have no effect\")\n        return UiSettingsCache()\n    }\n\n    /**\n     * Gets a projection snapshot. This means that, in accordance to the docs, the projection object\n     * will represent the map as it is seen at the point in time that the projection is queried, and\n     * not updated later on.\n     */\n    override fun getProjection(): IProjectionDelegate = lastSnapshot?.let { LiteProjection(it) } ?: DummyProjection()\n\n    override fun setOnCameraChangeListener(listener: IOnCameraChangeListener?) {\n        cameraChangeListener = listener\n    }\n\n    override fun setOnMarkerDragListener(listener: IOnMarkerDragListener?) {\n        Log.d(TAG, \"setOnMarkerDragListener: marker drag is not supported in lite mode\")\n    }\n\n    override fun addCircle(options: CircleOptions): ICircleDelegate {\n        return LiteCircleImpl(this, \"circle${nextObjectId++}\", options).also { circles.add(it) }\n    }\n\n    override fun snapshot(callback: ISnapshotReadyCallback?, bitmap: IObjectWrapper?) {\n        val lastSnapshot = lastSnapshot\n        if (lastSnapshot == null) {\n            afterNextDrawCallback.add {\n                callback?.onBitmapWrappedReady(ObjectWrapper.wrap(this@LiteGoogleMapImpl.lastSnapshot!!.snapshot.bitmap))\n            }\n        } else {\n            callback?.onBitmapWrappedReady(ObjectWrapper.wrap(lastSnapshot.snapshot.bitmap))\n        }\n    }\n\n    override fun snapshotForTest(callback: ISnapshotReadyCallback?) {\n        Log.d(TAG, \"Not yet implemented: snapshotForTest\")\n    }\n\n    override fun setPadding(left: Int, top: Int, right: Int, bottom: Int) {\n        view.setPadding(left, top, right, bottom)\n        postUpdateSnapshot()\n    }\n\n    override fun isBuildingsEnabled(): Boolean {\n        Log.d(TAG, \"isBuildingsEnabled: never enabled in light mode\")\n        return false\n    }\n\n    override fun setBuildingsEnabled(buildings: Boolean) {\n        Log.d(TAG, \"setBuildingsEnabled: cannot be enabled in light mode\")\n    }\n\n    override fun setOnMapLoadedCallback(callback: IOnMapLoadedCallback?) = callback?.let { onMapLoadedCallback ->\n        if (lastSnapshot != null) {\n            Log.d(TAG, \"Invoking map loaded callback instantly, as a snapshot is ready\")\n            onMapLoadedCallback.onMapLoaded()\n        }\n        else {\n            Log.d(TAG, \"Delaying map loaded callback, as snapshot has not been taken yet\")\n            afterNextDrawCallback.add { onMapLoadedCallback.onMapLoaded() }\n        }\n        Unit\n    } ?: Unit\n\n    override fun setWatermarkEnabled(watermark: Boolean) {\n        showWatermark = watermark\n    }\n\n    override fun showInfoWindow(marker: AbstractMarker): Boolean {\n        infoWindowAdapter.getInfoWindowViewFor(marker, mapContext)?.let { infoView ->\n            currentInfoWindow?.close()\n            currentInfoWindow = InfoWindow(infoView, this, marker).also { infoWindow ->\n                infoWindow.open(view)\n            }\n            return true\n        }\n        return false\n    }\n\n    override fun onResume() {\n        if (myLocationEnabled) activateLocationProvider()\n    }\n\n    override fun onPause() {\n        synchronized(this) {\n            currentSnapshotter?.cancel()\n            currentSnapshotter = null\n        }\n        deactivateLocationProvider()\n    }\n\n    override fun onDestroy() {\n        view.removeView(map)\n    }\n\n    override fun onLowMemory() {\n    }\n\n    override fun onSaveInstanceState(outState: Bundle) {\n        outState.putParcelable(BUNDLE_CAMERA_POSITION, cameraPosition)\n        outState.putParcelable(BUNDLE_CAMERA_BOUNDS, cameraBounds?.toGms())\n    }\n\n    override fun setContentDescription(desc: String?) {\n        view.contentDescription = desc\n    }\n\n    override fun setMapStyle(options: MapStyleOptions?): Boolean {\n        Log.d(TAG, \"setMapStyle options: \" + options?.getJson())\n        mapStyle = options\n\n        return true\n    }\n\n    override fun setMinZoomPreference(minZoom: Float) {\n        Log.d(TAG, \"setMinZoomPreference: no interactivity in lite mode\")\n    }\n\n    override fun setMaxZoomPreference(maxZoom: Float) {\n        Log.d(TAG, \"setMaxZoomPreference: no interactivity in lite mode\")\n    }\n\n    override fun resetMinMaxZoomPreference() {\n        Log.d(TAG, \"resetMinMaxZoomPreference: no interactivity in lite mode\")\n    }\n\n    override fun setLatLngBoundsForCameraTarget(bounds: LatLngBounds?) {\n        Log.d(TAG, \"setLatLngBoundsForCameraTarget: no interactivity in lite mode\")\n    }\n\n    override fun setCameraMoveStartedListener(listener: IOnCameraMoveStartedListener?) {\n        Log.d(TAG, \"setCameraMoveStartedListener: event not supported in lite mode\")\n    }\n\n    override fun setCameraMoveListener(listener: IOnCameraMoveListener?) {\n        Log.d(TAG, \"setCameraMoveListener: event not supported in lite mode\")\n\n    }\n\n    override fun setCameraMoveCanceledListener(listener: IOnCameraMoveCanceledListener?) {\n        Log.d(TAG, \"setCameraMoveCanceledListener: event not supported in lite mode\")\n    }\n\n    override fun setCameraIdleListener(listener: IOnCameraIdleListener?) {\n        Log.d(TAG, \"setCameraIdleListener: event not supported in lite mode\")\n    }\n\n    override fun onStart() {\n    }\n\n    override fun onStop() {\n    }\n\n    companion object {\n        private val TAG = \"GmsMapLite\"\n        private val BUNDLE_CAMERA_POSITION = \"camera\"\n        private val BUNDLE_CAMERA_BOUNDS = \"cameraBounds\"\n    }\n}\n\n"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/MapFragment.kt",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 org.microg.gms.maps.mapbox\n\nimport android.app.Activity\nimport android.os.Bundle\nimport android.os.Parcel\nimport android.util.Base64\nimport android.util.Log\nimport android.view.View\nimport android.view.ViewGroup\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.ObjectWrapper\nimport com.google.android.gms.maps.GoogleMapOptions\nimport com.google.android.gms.maps.internal.IGoogleMapDelegate\nimport com.google.android.gms.maps.internal.IMapFragmentDelegate\nimport com.google.android.gms.maps.internal.IOnMapReadyCallback\n\nclass MapFragmentImpl(private val activity: Activity) : IMapFragmentDelegate.Stub() {\n\n    private var map: IGoogleMapDelegate? = null\n    private var options: GoogleMapOptions? = null\n\n    override fun onInflate(activity: IObjectWrapper, options: GoogleMapOptions, savedInstanceState: Bundle?) {\n        this.options = options\n        map?.apply {\n            if (this is GoogleMapImpl) {\n                this.options = options\n            } else if (this is LiteGoogleMapImpl) {\n                this.options = options\n            }\n        }\n    }\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        if (options == null) {\n            options = savedInstanceState?.getParcelable(\"MapOptions\")\n        }\n        if (options == null) {\n            options = GoogleMapOptions()\n        }\n        if (options?.liteMode == true) {\n            map = LiteGoogleMapImpl(activity, options ?: GoogleMapOptions())\n        } else {\n            map = GoogleMapImpl(activity, options ?: GoogleMapOptions())\n        }\n    }\n\n    override fun onCreateView(layoutInflater: IObjectWrapper, container: IObjectWrapper, savedInstanceState: Bundle?): IObjectWrapper {\n        if (options == null) {\n            options = savedInstanceState?.getParcelable(\"MapOptions\")\n        }\n        Log.d(TAG, \"onCreateView: ${options?.camera?.target}\")\n        if (map == null) {\n            map = if (options?.liteMode == true) {\n                LiteGoogleMapImpl(activity, options ?: GoogleMapOptions())\n            } else {\n                GoogleMapImpl(activity, options ?: GoogleMapOptions())\n            }\n        }\n        map!!.apply {\n            onCreate(savedInstanceState)\n\n            val view = when (this) {\n                is GoogleMapImpl -> this.view\n                is LiteGoogleMapImpl -> this.view\n                else -> null\n            }\n\n            val parent = view?.parent as ViewGroup?\n            parent?.removeView(view)\n            return ObjectWrapper.wrap(view)\n        }\n    }\n\n    override fun getMap(): IGoogleMapDelegate? = map\n    override fun onEnterAmbient(bundle: Bundle?) = map?.onEnterAmbient(bundle) ?: Unit\n    override fun onExitAmbient() = map?.onExitAmbient() ?: Unit\n    override fun onStart() = map?.onStart() ?: Unit\n    override fun onStop() = map?.onStop() ?: Unit\n    override fun onResume() = map?.onResume() ?: Unit\n    override fun onPause() = map?.onPause() ?: Unit\n    override fun onLowMemory() = map?.onLowMemory() ?: Unit\n    override fun isReady(): Boolean = this.map != null\n    override fun getMapAsync(callback: IOnMapReadyCallback) = map?.let {\n        if (it is GoogleMapImpl) it.getMapAsync(callback)\n        else if (it is LiteGoogleMapImpl) it.getMapAsync(callback)\n    } ?: Unit\n\n    override fun onDestroyView() {\n        map?.onDestroy()\n    }\n\n    override fun onDestroy() {\n        map?.onDestroy()\n        map = null\n        options = null\n    }\n\n    override fun onSaveInstanceState(outState: Bundle) {\n        if (options != null) {\n            outState.putParcelable(\"MapOptions\", options)\n        }\n        map?.onSaveInstanceState(outState)\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean {\n        if (super.onTransact(code, data, reply, flags)) {\n            return true\n        } else {\n            Log.d(TAG, \"onTransact [unknown]: $code, $data, $flags\")\n            return false\n        }\n    }\n\n    companion object {\n        private val TAG = \"GmsMapFragment\"\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/MapView.kt",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 org.microg.gms.maps.mapbox\n\nimport android.content.Context\nimport android.os.Bundle\nimport android.os.Parcel\nimport android.util.Log\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.ObjectWrapper\nimport com.google.android.gms.maps.GoogleMapOptions\nimport com.google.android.gms.maps.internal.IGoogleMapDelegate\nimport com.google.android.gms.maps.internal.IMapViewDelegate\nimport com.google.android.gms.maps.internal.IOnMapReadyCallback\n\nclass MapViewImpl(private val context: Context, options: GoogleMapOptions?) : IMapViewDelegate.Stub() {\n\n    private val options: GoogleMapOptions = options ?: GoogleMapOptions()\n    private var map: IGoogleMapDelegate? = null\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        Log.d(TAG, \"onCreate: ${options?.camera?.target}\")\n        map = if (options.liteMode) {\n            LiteGoogleMapImpl(context, options)\n        } else {\n            GoogleMapImpl(context, options)\n        }.apply {\n            this.onCreate(savedInstanceState)\n        }\n    }\n\n    override fun getMap(): IGoogleMapDelegate? = map\n    override fun onEnterAmbient(bundle: Bundle?) = map?.onEnterAmbient(bundle) ?: Unit\n    override fun onExitAmbient() = map?.onExitAmbient() ?: Unit\n    override fun onStart() = map?.onStart() ?: Unit\n    override fun onStop() = map?.onStop() ?: Unit\n    override fun onResume() = map?.onResume() ?: Unit\n    override fun onPause() = map?.onPause() ?: Unit\n    override fun onDestroy() {\n        map?.onDestroy()\n        map = null\n    }\n\n    override fun onLowMemory() = map?.onLowMemory() ?: Unit\n    override fun onSaveInstanceState(outState: Bundle) = map?.onSaveInstanceState(outState) ?: Unit\n    override fun getView(): IObjectWrapper = ObjectWrapper.wrap(\n        map?.let {\n            when (it) {\n                is GoogleMapImpl -> it.view\n                is LiteGoogleMapImpl -> it.view\n                else -> null\n            }\n        }\n    )\n\n    override fun getMapAsync(callback: IOnMapReadyCallback) = map?.let {\n        when (it) {\n            is GoogleMapImpl -> it.getMapAsync(callback)\n            is LiteGoogleMapImpl -> it.getMapAsync(callback)\n            else -> null\n        }\n    } ?: Unit\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =\n            if (super.onTransact(code, data, reply, flags)) {\n                true\n            } else {\n                Log.d(TAG, \"onTransact [unknown]: $code, $data, $flags\"); false\n            }\n\n    companion object {\n        private val TAG = \"GmsMapView\"\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/Pattern.kt",
    "content": "package org.microg.gms.maps.mapbox\n\nimport android.graphics.Bitmap\nimport android.graphics.Canvas\nimport android.graphics.Paint\nimport android.graphics.RectF\nimport com.google.android.gms.maps.model.Dash\nimport com.google.android.gms.maps.model.Dot\nimport com.google.android.gms.maps.model.Gap\nimport com.google.android.gms.maps.model.PatternItem\nimport kotlin.math.max\n\nfun PatternItem.getName(): String = when (this) {\n    is Dash -> \"dash${this.length}\"\n    is Gap -> \"gap${this.length}\"\n    is Dot -> \"dot\"\n    else -> this.javaClass.name\n}\n\n/**\n * Name of pattern, to identify it after it is added to map\n */\nfun List<PatternItem>.getName(color: Int, strokeWidth: Float, skew: Float = 1f) = if (isEmpty()) {\n    \"solid-${color}\"\n} else {joinToString(\"-\") {\n        it.getName()\n    } + \"-${color}-width${strokeWidth}-skew${skew}\"\n}\n\n/**\n * Gets width that a bitmap for this pattern item would have if the pattern's bitmap\n * were to be drawn with respect to aspect ratio onto a canvas with height 1.\n */\nfun PatternItem.getWidth(strokeWidth: Float, skew: Float): Float = when (this) {\n    is Dash -> this.length\n    is Gap -> this.length\n    is Dot -> strokeWidth * skew\n    else -> 1f\n}\n\n/**\n * Gets width that a bitmap for this pattern would have if it were to be drawn\n * with respect to aspect ratio onto a canvas with height 1.\n */\nfun List<PatternItem>.getWidth(strokeWidth: Float, skew: Float) = map { it.getWidth(strokeWidth, skew) }.sum()\n\nfun List<PatternItem>.makeBitmap(color: Int, strokeWidth: Float, skew: Float = 1f): Bitmap = makeBitmap(Paint().apply {\n    setColor(color)\n    style = Paint.Style.FILL\n}, strokeWidth, skew)\n\n\nfun List<PatternItem>.makeBitmap(paint: Paint, strokeWidth: Float, skew: Float): Bitmap {\n\n    // Pattern aspect ratio is not respected by renderer\n    val width = getWidth(strokeWidth, skew).toInt()\n    val height = (strokeWidth * skew).toInt() // avoids squished image bugs\n\n    // For empty list or nonsensical input (zero-width items)\n    if (width == 0 || height == 0) {\n        val nonZeroHeight = max(1f, strokeWidth)\n        return Bitmap.createBitmap(1, nonZeroHeight.toInt(), Bitmap.Config.ARGB_8888).also {\n            Canvas(it).drawRect(0f, 0f, nonZeroHeight, nonZeroHeight, paint)\n        }\n    }\n\n    val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)\n    val canvas = Canvas(bitmap)\n\n    var drawCursor = 0f\n    for (item in this) {\n        val rect = RectF(\n            drawCursor,\n            0f,\n            drawCursor + item.getWidth(strokeWidth, skew),\n            strokeWidth * skew\n        )\n        when (item) {\n            is Dash -> canvas.drawRect(rect, paint)\n            // is Gap -> do nothing, only move cursor\n            is Dot -> canvas.drawOval(rect, paint)\n        }\n\n        drawCursor += item.getWidth(strokeWidth, skew)\n    }\n\n    return bitmap\n}\n"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/Projection.kt",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 org.microg.gms.maps.mapbox\n\nimport android.graphics.Point\nimport android.graphics.PointF\nimport android.util.Log\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.ObjectWrapper\nimport com.google.android.gms.maps.internal.IProjectionDelegate\nimport com.google.android.gms.maps.model.LatLng\nimport com.google.android.gms.maps.model.VisibleRegion\nimport com.mapbox.mapboxsdk.maps.Projection\nimport com.google.android.gms.dynamic.unwrap\nimport com.google.android.gms.maps.model.LatLngBounds\nimport org.microg.gms.maps.mapbox.utils.toGms\nimport org.microg.gms.maps.mapbox.utils.toMapbox\nimport kotlin.math.roundToInt\n\nval ZERO_LAT_LNG = com.mapbox.mapboxsdk.geometry.LatLng(0.0, 0.0)\n\n// TODO: Do calculations using backed up locations instead of live (which requires UI thread)\nclass ProjectionImpl(private val projection: Projection, private val withoutTiltOrBearing: Boolean) : IProjectionDelegate.Stub() {\n    private val visibleRegion = projection.getVisibleRegion(false)\n    private val farLeft = visibleRegion.farLeft?.let { projection.toScreenLocation(it) }\n    private val farRight = visibleRegion.farRight?.let { projection.toScreenLocation(it) }\n    private val nearLeft = visibleRegion.nearLeft?.let { projection.toScreenLocation(it) }\n    private val nearRight = visibleRegion.nearRight?.let { projection.toScreenLocation(it) }\n\n    override fun fromScreenLocation(obj: IObjectWrapper?): LatLng? = try {\n        obj.unwrap<Point>()?.let {\n            if (withoutTiltOrBearing && farLeft != null && farRight != null && nearLeft != null) {\n                val xPercent = (it.x.toFloat() - farLeft.x) / (farRight.x - farLeft.x)\n                val yPercent = (it.y.toFloat() - farLeft.y) / (nearLeft.y - farLeft.y)\n                val lon = (visibleRegion.farLeft?.longitude ?: 0.0) + xPercent *\n                        ((visibleRegion.farRight?.longitude ?: 0.0) - (visibleRegion.farLeft?.longitude ?: 0.0))\n                val lat = (visibleRegion.farLeft?.latitude?: 0.0) + yPercent *\n                        ((visibleRegion.nearLeft?.latitude?: 0.0) - (visibleRegion.farLeft?.latitude?: 0.0))\n                LatLng(lat, lon)\n            } else {\n                projection.fromScreenLocation(PointF(it)).toGms()\n            }\n        }\n    } catch (e: Exception) {\n        Log.d(TAG, \"fromScreenLocation() used from outside UI thread on map with tilt or bearing, expect bugs\")\n        LatLng(0.0, 0.0)\n    }\n\n    override fun toScreenLocation(latLng: LatLng?): IObjectWrapper = try {\n        ObjectWrapper.wrap(latLng?.toMapbox()?.let {\n            if (withoutTiltOrBearing && farLeft != null && farRight != null && nearLeft != null) {\n                val xPercent = (it.longitude - (visibleRegion.farLeft?.longitude ?: 0.0)) /\n                            ((visibleRegion.farRight?.longitude ?: 0.0) - (visibleRegion.farLeft?.longitude ?: 0.0))\n                val yPercent = (it.latitude - (visibleRegion.farLeft?.latitude ?: 0.0)) /\n                        ((visibleRegion.nearLeft?.latitude ?: 0.0) - (visibleRegion.farLeft?.latitude ?: 0.0))\n                val x = farLeft.x + xPercent * (farRight.x - farLeft.x)\n                val y = farLeft.y + yPercent * (nearLeft.y - farLeft.y)\n                Point(x.roundToInt(), y.roundToInt()).also { p -> Log.d(TAG, \"$p vs.\\n${projection.toScreenLocation(it).let { Point(it.x.roundToInt(), it.y.roundToInt()) }}\") }\n            } else {\n                projection.toScreenLocation(it).let { Point(it.x.roundToInt(), it.y.roundToInt()) }\n            }\n        })\n    } catch (e: Exception) {\n        Log.d(TAG, \"toScreenLocation() used from outside UI thread on map with tilt or bearing, expect bugs\")\n        ObjectWrapper.wrap(Point(0, 0))\n    }\n\n    override fun getVisibleRegion(): VisibleRegion = visibleRegion.toGms()\n\n    companion object {\n        private val TAG = \"GmsMapProjection\"\n    }\n}\n\nclass LiteProjection(private val snapshot: MetaSnapshot) : IProjectionDelegate.Stub() {\n\n    private fun fromScreenLocationAfterPadding(point: Point?): LatLng =\n        point?.let { snapshot.latLngForPixelFixed(PointF(point)).toGms() } ?: LatLng(0.0, 0.0)\n\n    override fun fromScreenLocation(obj: IObjectWrapper?): LatLng = fromScreenLocationAfterPadding(obj.unwrap<Point?>()?.let {\n        Point((it.x - snapshot.paddingRight), (it.y - snapshot.paddingRight))\n    })\n\n    override fun toScreenLocation(latLng: LatLng?): IObjectWrapper =\n        ObjectWrapper.wrap(snapshot.snapshot.pixelForLatLng(latLng?.toMapbox()).let {\n            Point(it.x.roundToInt() + snapshot.paddingRight, it.y.roundToInt() + snapshot.paddingTop)\n        })\n\n    override fun getVisibleRegion(): VisibleRegion {\n        val nearLeft = fromScreenLocationAfterPadding(Point(0, snapshot.height))\n        val nearRight = fromScreenLocationAfterPadding(Point(snapshot.width, snapshot.height))\n        val farLeft = fromScreenLocationAfterPadding(Point(0, 0))\n        val farRight = fromScreenLocationAfterPadding(Point(snapshot.width, 0))\n\n        return VisibleRegion(nearLeft, nearRight, farLeft, farRight, LatLngBounds(nearLeft, farRight))\n    }\n}\n\nclass DummyProjection : IProjectionDelegate.Stub() {\n    override fun fromScreenLocation(obj: IObjectWrapper?): LatLng {\n        Log.d(TAG, \"Map not initialized when calling getProjection(). Cannot calculate fromScreenLocation\")\n        return LatLng(0.0, 0.0)\n    }\n\n    override fun toScreenLocation(latLng: LatLng?): IObjectWrapper {\n        Log.d(TAG, \"Map not initialized when calling getProjection(). Cannot calculate toScreenLocation\")\n        return ObjectWrapper.wrap(Point(0, 0))\n    }\n\n    override fun getVisibleRegion(): VisibleRegion {\n        Log.d(TAG, \"Map not initialized when calling getProjection(). Cannot calculate getVisibleRegion\")\n        return VisibleRegion(LatLngBounds(LatLng(0.0, 0.0), LatLng(0.0, 0.0)))\n    }\n\n    companion object {\n        private val TAG = \"GmsMapDummyProjection\"\n    }\n}"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/SourceLocationEngine.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.maps.mapbox\n\nimport android.app.PendingIntent\nimport android.location.Location\nimport android.os.Handler\nimport android.os.Looper\nimport android.util.Log\nimport com.google.android.gms.maps.internal.ILocationSourceDelegate\nimport com.google.android.gms.maps.internal.IOnLocationChangeListener\nimport com.mapbox.mapboxsdk.location.engine.LocationEngine\nimport com.mapbox.mapboxsdk.location.engine.LocationEngineCallback\nimport com.mapbox.mapboxsdk.location.engine.LocationEngineRequest\nimport com.mapbox.mapboxsdk.location.engine.LocationEngineResult\n\nclass SourceLocationEngine(private val locationSource: ILocationSourceDelegate) : LocationEngine, IOnLocationChangeListener.Stub() {\n    val callbacks: MutableSet<Pair<LocationEngineCallback<LocationEngineResult>, Handler>> = hashSetOf()\n    var lastLocation: Location? = null\n    var active: Boolean = false\n\n    override fun getLastLocation(callback: LocationEngineCallback<LocationEngineResult>) {\n        callback.onSuccess(LocationEngineResult.create(lastLocation))\n    }\n\n    override fun requestLocationUpdates(request: LocationEngineRequest, callback: LocationEngineCallback<LocationEngineResult>, looper: Looper?) {\n        callbacks.add(callback to Handler(looper ?: Looper.myLooper() ?: Looper.getMainLooper()))\n        if (!active) {\n            active = true\n            try {\n                locationSource.activate(this)\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n            }\n        }\n    }\n\n    override fun requestLocationUpdates(request: LocationEngineRequest, pendingIntent: PendingIntent?) {\n        throw UnsupportedOperationException()\n    }\n\n    override fun removeLocationUpdates(callback: LocationEngineCallback<LocationEngineResult>) {\n        callbacks.removeAll { it.first == callback }\n        if (callbacks.isEmpty() && active) {\n            active = false\n            try {\n                locationSource.deactivate()\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n            }\n        }\n    }\n\n    override fun removeLocationUpdates(pendingIntent: PendingIntent?) {\n        throw UnsupportedOperationException()\n    }\n\n    override fun onLocationChanged(location: Location?) {\n        lastLocation = location\n        for ((callback, handler) in callbacks) {\n            handler.post {\n                callback.onSuccess(LocationEngineResult.create(location))\n            }\n        }\n    }\n}"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/StreetViewPanoramaFragment.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.maps.mapbox\n\nimport android.app.Activity\nimport android.os.Bundle\nimport android.widget.TextView\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.ObjectWrapper\nimport com.google.android.gms.maps.StreetViewPanoramaOptions\nimport com.google.android.gms.maps.internal.IOnStreetViewPanoramaReadyCallback\nimport com.google.android.gms.maps.internal.IStreetViewPanoramaDelegate\nimport com.google.android.gms.maps.internal.IStreetViewPanoramaFragmentDelegate\n\nclass StreetViewPanoramaFragmentImpl(private val activity: Activity) : IStreetViewPanoramaFragmentDelegate.Stub() {\n\n    override fun getStreetViewPanorama(): IStreetViewPanoramaDelegate? {\n        return null\n    }\n\n    override fun onInflate(activity: IObjectWrapper?, options: StreetViewPanoramaOptions?, savedInstanceState: Bundle?) {\n    }\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n    }\n\n    override fun onCreateView(layoutInflater: IObjectWrapper?, container: IObjectWrapper?, savedInstanceState: Bundle?): IObjectWrapper {\n        return ObjectWrapper.wrap(TextView(activity))\n    }\n\n    override fun onResume() {\n    }\n\n    override fun onPause() {\n    }\n\n    override fun onDestroyView() {\n    }\n\n    override fun onDestroy() {\n    }\n\n    override fun onLowMemory() {\n    }\n\n    override fun onSaveInstanceState(outState: Bundle?) {\n    }\n\n    override fun isReady(): Boolean = true\n\n    override fun getStreetViewPanoramaAsync(callback: IOnStreetViewPanoramaReadyCallback?) {\n    }\n\n    override fun onStart() {\n    }\n\n    override fun onStop() {\n    }\n\n}"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/StreetViewPanoramaView.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.maps.mapbox\n\nimport android.content.Context\nimport android.os.Bundle\nimport android.widget.TextView\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.ObjectWrapper\nimport com.google.android.gms.maps.internal.IOnStreetViewPanoramaReadyCallback\nimport com.google.android.gms.maps.internal.IStreetViewPanoramaDelegate\nimport com.google.android.gms.maps.internal.IStreetViewPanoramaViewDelegate\n\nclass StreetViewPanoramaViewImpl(private val context: Context) : IStreetViewPanoramaViewDelegate.Stub() {\n\n    override fun getStreetViewPanorama(): IStreetViewPanoramaDelegate? {\n        return null\n    }\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n    }\n\n    override fun onResume() {\n    }\n\n    override fun onPause() {\n    }\n\n    override fun onDestroy() {\n    }\n\n    override fun onLowMemory() {\n    }\n\n    override fun onSaveInstanceState(outState: Bundle?) {\n    }\n\n    override fun getView(): IObjectWrapper? {\n        return ObjectWrapper.wrap(TextView(context))\n    }\n\n    override fun getStreetViewPanoramaAsync(callback: IOnStreetViewPanoramaReadyCallback?) {\n    }\n\n    override fun onStart() {\n    }\n\n    override fun onStop() {\n    }\n\n}"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/Styles.kt",
    "content": "package org.microg.gms.maps.mapbox\n\nimport android.graphics.Color\nimport android.os.Build.VERSION.SDK_INT\nimport android.util.Log\nimport androidx.annotation.ColorInt\nimport androidx.annotation.FloatRange\nimport androidx.core.graphics.ColorUtils\nimport com.google.android.gms.maps.GoogleMap\nimport com.google.android.gms.maps.model.MapStyleOptions\nimport com.google.gson.Gson\nimport com.google.gson.JsonSyntaxException\nimport com.google.gson.annotations.SerializedName\nimport com.mapbox.mapboxsdk.maps.Style\nimport org.json.JSONArray\nimport org.json.JSONObject\nimport org.microg.gms.maps.mapbox.utils.MapContext\nimport java.io.File\nimport java.io.IOException\nimport java.lang.NumberFormatException\nimport kotlin.math.pow\nimport kotlin.math.roundToInt\n\nconst val TAG = \"GmsMapStyles\"\nconst val KEY_METADATA_FEATURE_TYPE = \"microg:gms-type-feature\"\nconst val KEY_METADATA_ELEMENT_TYPE = \"microg:gms-type-element\"\n\nconst val KEY_SOURCES = \"sources\"\nconst val KEY_LAYERS = \"layers\"\n\nconst val SELECTOR_ALL = \"all\"\nconst val SELECTOR_ELEMENT_LABEL_TEXT_FILL = \"labels.text.fill\"\nconst val SELECTOR_ELEMENT_LABEL_TEXT_STROKE = \"labels.text.stroke\"\nconst val SELECTOR_ELEMENT_GEOMETRY_STROKE = \"geometry.stroke\"\nconst val KEY_LAYER_METADATA = \"metadata\"\nconst val KEY_LAYER_PAINT = \"paint\"\n\nconst val KEY_SOURCE_URL = \"url\"\nconst val KEY_SOURCE_TILES = \"tiles\"\n\n\nfun getStyle(\n    context: MapContext, mapType: Int, styleOptions: MapStyleOptions?, styleFromFileWorkaround: Boolean = false\n): Style.Builder {\n\n    val styleJson = JSONObject(\n        context.assets.open(\n            if (BuildConfig.STADIA_KEY.isNotEmpty()) when (mapType) {\n                GoogleMap.MAP_TYPE_SATELLITE, GoogleMap.MAP_TYPE_HYBRID -> \"style-microg-satellite-stadia.json\"\n                GoogleMap.MAP_TYPE_TERRAIN -> \"style-stadia-outdoors.json\"\n                //MAP_TYPE_NONE, MAP_TYPE_NORMAL,\n                else -> \"style-microg-normal-stadia.json\"\n            } else when (mapType) {\n                GoogleMap.MAP_TYPE_SATELLITE, GoogleMap.MAP_TYPE_HYBRID -> \"style-microg-satellite-mapbox.json\"\n                GoogleMap.MAP_TYPE_TERRAIN -> \"style-mapbox-outdoors-v12.json\"\n                //MAP_TYPE_NONE, MAP_TYPE_NORMAL,\n                else -> \"style-microg-normal-mapbox.json\"\n            }\n        ).bufferedReader().readText()\n    )\n\n    // Inject API key\n    if (BuildConfig.STADIA_KEY.isNotEmpty()) {\n        val sourceArray = styleJson.getJSONObject(KEY_SOURCES)\n        for (key in sourceArray.keys()) {\n            val sourceObject = sourceArray.getJSONObject(key)\n            if (sourceObject.has(KEY_SOURCE_URL)) {\n                sourceObject.put(KEY_SOURCE_URL, \"${sourceObject[KEY_SOURCE_URL]}?api_key=${BuildConfig.STADIA_KEY}\")\n            }\n            if (sourceObject.has(KEY_SOURCE_TILES)) {\n                val tilesArray = sourceObject.getJSONArray(KEY_SOURCE_TILES)\n                for (i in 0 until tilesArray.length()) {\n                    tilesArray.put(i, \"${tilesArray.getString(i)}?api_key=${BuildConfig.STADIA_KEY}\")\n                }\n            }\n        }\n    }\n\n    styleOptions?.apply(styleJson)\n\n    return if (styleFromFileWorkaround) {\n        val temporaryFile = File(context.cacheDir, styleJson.hashCode().toString())\n\n        if (!temporaryFile.exists()) {\n            temporaryFile.createNewFile()\n        }\n\n        try {\n            temporaryFile.bufferedWriter().use {\n                it.write(styleJson.toString())\n            }\n            Log.d(TAG, \"file:/${temporaryFile.absolutePath}\")\n            Style.Builder().fromUri(\"file:/${temporaryFile.absolutePath}\")\n        } catch (e: IOException) {\n            e.printStackTrace()\n            Style.Builder().fromUri(getFallbackStyleOnlineUri(mapType))\n        }\n    } else {\n        Style.Builder().fromJson(styleJson.toString())\n    }\n}\n\n\nfun getFallbackStyleOnlineUri(mapType: Int) = when (mapType) {\n    GoogleMap.MAP_TYPE_SATELLITE -> \"mapbox://styles/microg/cjxgloted25ap1ct4uex7m6hi\"\n    GoogleMap.MAP_TYPE_TERRAIN -> \"mapbox://styles/mapbox/outdoors-v12\"\n    GoogleMap.MAP_TYPE_HYBRID -> \"mapbox://styles/microg/cjxgloted25ap1ct4uex7m6hi\"\n    //MAP_TYPE_NONE, MAP_TYPE_NORMAL,\n    else -> \"mapbox://styles/microg/cjui4020201oo1fmca7yuwbor\"\n}\n\nfun MapStyleOptions.apply(style: JSONObject) {\n    try {\n        Gson().fromJson(json, Array<StyleOperation>::class.java)?.let { styleOperations ->\n\n            val layerArray = style.getJSONArray(KEY_LAYERS)\n\n            // Apply operations in order\n            operations@ for (operation in styleOperations.map { it.toNonNull() }) {\n                if (!operation.isValid()) {\n                    Log.w(TAG, \"Operating is invalid: $operation\")\n                    continue\n                }\n\n                var applied = 0\n\n                // Reverse direction allows removing hidden layers\n                layers@ for (i in layerArray.length() - 1 downTo 0) {\n\n                    val layer = layerArray.getJSONObject(i)\n                    if (layer.layerHasRequiredFields()) {\n\n                        if (operation.isValid() && layer.matchesOperation(operation)) {\n                            applied++\n\n                            if (layer.layerShouldBeRemoved(operation)) {\n                                layerArray.removeCompat(i)\n                            } else {\n                                layer.applyOperation(operation)\n                            }\n                        }\n                    }\n                }\n\n                Log.v(TAG, \"Operation applied to $applied layers: ${Gson().toJson(operation)}\")\n            }\n        }\n\n\n    } catch (e: JsonSyntaxException) {\n        e.printStackTrace()\n    }\n}\n\ndata class StyleOperation(val featureType: String?, val elementType: String?, val stylers: Array<Styler>?)\n\ndata class NonNullStyleOperation(val featureType: String, val elementType: String, val stylers: Array<Styler>)\n\nclass Styler(\n    val hue: String?,\n    @FloatRange(from = -100.0, to = 100.0) val saturation: Float?,\n    @FloatRange(from = -100.0, to = 100.0) val lightness: Float?,\n    @FloatRange(from = 0.01, to = 10.0) val gamma: Float?,\n    @SerializedName(\"invert_lightness\") val invertLightness: Boolean?,\n    val visibility: String?,\n    val color: String?,\n    //val weight: Int?\n)\n\n/**\n * Constructs a `NonNullStyleOperation` out of the `StyleOperation` while filling null fields with\n * default values.\n */\nfun StyleOperation.toNonNull() =\n    NonNullStyleOperation(featureType ?: SELECTOR_ALL, elementType ?: SELECTOR_ALL, stylers ?: emptyArray())\n\n/**\n * Returns false iff the operation is invalid.\n *\n * There is one invalid selector that is tested for – per docs:\n * \"`administrative` selects all administrative areas. Styling affects only\n * the labels of administrative areas, not the geographical borders or fill.\"\n */\nfun NonNullStyleOperation.isValid() = !(featureType.startsWith(\"administrative\") &&\n        elementType.startsWith(\"geometry\"))\n\n/**\n * True iff the layer represented by the JSON object should be modified according to the stylers in the operation.\n *\n * Layer metadata always has the most concrete category, while operation applies to all subcategories as well.\n * Therefore, we test if the operation is a substring of the layer's metadata – i.e. the layer's metadata contains\n * (more concretely: starts with) the operation's selector.\n */\nfun JSONObject.matchesOperation(operation: NonNullStyleOperation) =\n    (getJSONObject(KEY_LAYER_METADATA).getString(KEY_METADATA_FEATURE_TYPE).startsWith(operation.featureType)\n            || operation.featureType == \"all\")\n    && (getJSONObject(KEY_LAYER_METADATA).getString(KEY_METADATA_ELEMENT_TYPE).startsWith(operation.elementType)\n            || getJSONObject(KEY_LAYER_METADATA).getString(KEY_METADATA_ELEMENT_TYPE) == \"labels.text\"  && operation.elementType == SELECTOR_ELEMENT_LABEL_TEXT_FILL\n            || getJSONObject(KEY_LAYER_METADATA).getString(KEY_METADATA_ELEMENT_TYPE) == \"labels.text\"  && operation.elementType == SELECTOR_ELEMENT_LABEL_TEXT_STROKE\n            || operation.elementType == \"all\")\n\n\n/**\n * Layer has fields that allow applying style operations.\n */\nfun JSONObject.layerHasRequiredFields() = has(KEY_LAYER_PAINT) && has(KEY_LAYER_METADATA) &&\n        getJSONObject(KEY_LAYER_METADATA).let { it.has(KEY_METADATA_FEATURE_TYPE) && it.has(KEY_METADATA_ELEMENT_TYPE) }\n\n/**\n * True iff the layer represented by the JSON object should be removed according to the provided style operation.\n */\nfun JSONObject.layerShouldBeRemoved(operation: NonNullStyleOperation) =\n    // A styler sets the layer to be invisible\n    operation.stylers.any { it.visibility == \"off\" } ||\n        // A styler sets the layer to simplified and we are working with a label\n        (getJSONObject(KEY_LAYER_METADATA).getString(KEY_METADATA_ELEMENT_TYPE) == SELECTOR_ELEMENT_GEOMETRY_STROKE && operation.stylers.any { it.visibility == \"simplified\" })\n\n/**\n * Applies the provided style operation to the layer represented by the JSON object.\n */\nfun JSONObject.applyOperation(operation: NonNullStyleOperation) = operation.stylers.forEach { styler ->\n    val paintJson = getJSONObject(KEY_LAYER_PAINT)\n    val metadataJson = getJSONObject(KEY_LAYER_METADATA)\n    if (styler.isColorChange()) {\n        when (operation.elementType) {\n            SELECTOR_ELEMENT_LABEL_TEXT_FILL -> styler.applyTextFill(paintJson)\n            SELECTOR_ELEMENT_LABEL_TEXT_STROKE -> styler.applyTextOutline(paintJson)\n            else -> styler.traverse(paintJson)\n        }\n    }\n    if (styler.visibility == \"simplified\" && metadataJson.getString(KEY_METADATA_ELEMENT_TYPE) == \"labels.text\") {\n        paintJson.remove(\"text-halo-blur\")\n        paintJson.remove(\"text-halo-color\")\n    }\n}\n\n/**\n * Returns true if string is likely to contain a color.\n */\nfun String.isColor() = ((startsWith(\"hsl(\") || startsWith(\"hsla(\")  || startsWith(\"rgba(\")) && endsWith(\")\")) || startsWith(\"#\")\n\n/**\n * Can parse colors in the format '#rrggbb', '#aarrggbb', 'hsl(h, s, l)', and 'rgba(r, g, b, a)'\n * Returns 0 and prints to log if an invalid color is provided.\n */\n@ColorInt\nfun String.parseColor(): Int {\n    if (startsWith(\"#\") && length in listOf(7, 9)) {\n        return Color.parseColor(this)\n    } else if (startsWith(\"hsl(\")) {\n        val hslArray = replace(\"hsl(\", \"\").replace(\")\", \"\").split(\", \")\n        if (hslArray.size != 3) {\n            Log.w(TAG, \"Invalid color `$this`\")\n            return 0\n        }\n\n        return try {\n            ColorUtils.HSLToColor(\n                floatArrayOf(\n                    hslArray[0].toFloat(),\n                    hslArray[1].parseFloat(),\n                    hslArray[2].parseFloat()\n                )\n            )\n        } catch (e: NumberFormatException) {\n            Log.w(TAG, \"Invalid color `$this`\")\n            0\n        }\n    } else if (startsWith(\"hsla(\")) {\n        val hslArray = replace(\"hsla(\", \"\").replace(\")\", \"\").split(\", \")\n        if (hslArray.size != 4) {\n            Log.w(TAG, \"Invalid color `$this`\")\n            return 0\n        }\n\n        return try {\n            ColorUtils.setAlphaComponent(\n                ColorUtils.HSLToColor(\n                    floatArrayOf(\n                        hslArray[0].toFloat(), hslArray[1].parseFloat(), hslArray[2].parseFloat()\n                    )\n                ), (hslArray[3].parseFloat() * 255).roundToInt()\n            )\n        } catch (e: NumberFormatException) {\n            Log.w(TAG, \"Invalid color `$this`\")\n            0\n        }\n\n    } else if (startsWith(\"rgba(\")) {\n        return com.mapbox.mapboxsdk.utils.ColorUtils.rgbaToColor(this)\n    }\n\n    Log.w(TAG, \"Invalid color `$this`\")\n    return 0\n}\n\n/**\n * Formats color int in such a format that it MapLibre's rendering engine understands it.\n */\nfun Int.colorToString() = com.mapbox.mapboxsdk.utils.ColorUtils.colorToRgbaString(this)\n\n/**\n * Can parse string values that contain '%'.\n */\nfun String.parseFloat(): Float {\n    return if (contains(\"%\")) {\n        replace(\"%\", \"\").toFloat() / 100f\n    } else {\n        toFloat()\n    }\n}\n\n/**\n * Applies operation specified by styler to the provided color int, and returns\n * a new, corresponding color int.\n */\n@ColorInt\nfun Styler.applyColorChanges(color: Int): Int {\n    // There may only be one operation per styler per docs.\n\n    hue?.let { hue ->\n        // Extract hue from input color\n        val hslResult = FloatArray(3)\n        ColorUtils.colorToHSL(hue.parseColor(), hslResult)\n\n        val hueDegree = hslResult[0]\n\n        // Apply hue to layer color\n        ColorUtils.colorToHSL(color, hslResult)\n        hslResult[0] = hueDegree\n        return ColorUtils.setAlphaComponent(ColorUtils.HSLToColor(hslResult), Color.alpha(color))\n    }\n\n    lightness?.let { lightness ->\n        // Apply lightness to layer color\n        val hsl = FloatArray(3)\n        ColorUtils.colorToHSL(color, hsl)\n        hsl[2] = if (lightness < 0) {\n            // Increase darkness. Percentage amount = relative reduction of is-lightness.\n            (lightness / 100 + 1) * hsl[2]\n        } else {\n            // Increase brightness. Percentage amount = relative reduction of difference between is-lightness and 1.0.\n            hsl[2] + (lightness / 100) * (1 - hsl[2])\n        }\n        return ColorUtils.setAlphaComponent(ColorUtils.HSLToColor(hsl), Color.alpha(color))\n    }\n\n    saturation?.let { saturation ->\n        // Apply saturation to layer color\n        val hsl = FloatArray(3)\n        ColorUtils.colorToHSL(color, hsl)\n        hsl[1] = if (saturation < 0) {\n            // Reduce intensity. Percentage amount = relative reduction of is-saturation.\n            (saturation / 100 + 1) * hsl[1]\n        } else {\n            // Increase intensity. Percentage amount = relative reduction of difference between is-saturation and 1.0.\n            hsl[1] + (saturation / 100) * (1 - hsl[1])\n        }\n\n        return ColorUtils.setAlphaComponent(ColorUtils.HSLToColor(hsl), Color.alpha(color))\n    }\n\n    gamma?.let { gamma ->\n        // Apply gamma to layer color\n        val hsl = FloatArray(3)\n        ColorUtils.colorToHSL(color, hsl)\n        hsl[2] = hsl[2].toDouble().pow(gamma.toDouble()).toFloat()\n\n        return ColorUtils.setAlphaComponent(ColorUtils.HSLToColor(hsl), Color.alpha(color))\n    }\n\n    if (invertLightness == true) {\n        // Invert layer color's lightness\n        val hsl = FloatArray(3)\n        ColorUtils.colorToHSL(color, hsl)\n        hsl[2] = 1 - hsl[2]\n\n        return ColorUtils.setAlphaComponent(ColorUtils.HSLToColor(hsl), Color.alpha(color))\n    }\n\n    this.color?.let {\n        return it.parseColor()\n    }\n\n    Log.w(TAG, \"No applicable operation\")\n    return color\n}\n\nfun Styler.isColorChange(): Boolean = hue != null || lightness!= null || saturation != null || gamma != null || invertLightness != null || color != null\n\n/**\n * Traverse JSON object and replace any color strings according to styler\n */\nfun Styler.traverse(json: JSONObject) {\n    // Traverse layer and replace any color strings\n    json.keys().forEach { key ->\n        json.get(key).let {\n            when (it) {\n                is JSONObject -> traverse(it)\n                is JSONArray -> traverse(it)\n                is String -> if (it.isColor()) {\n                    json.put(key, applyColorChanges(it.parseColor()).colorToString())\n                }\n            }\n        }\n    }\n}\n\n/**\n * Traverse array and replace any color strings according to styler\n */\nfun Styler.traverse(array: JSONArray) {\n    for (i in 0 until array.length()) {\n        array.get(i).let {\n            when (it) {\n                is JSONObject -> traverse(it)\n                is JSONArray -> traverse(it)\n                is String -> if (it.isColor()) {\n                    array.put(i, applyColorChanges(it.parseColor()).colorToString())\n                }\n            }\n        }\n    }\n}\n\nfun Styler.applyTextFill(paint: JSONObject) {\n    if (paint.has(\"text-color\")) when (val textColor = paint.get(\"text-color\")) {\n        is JSONObject -> traverse(textColor)\n        is JSONArray -> traverse(textColor)\n        is String -> paint.put(\"text-color\", applyColorChanges(textColor.parseColor()).colorToString())\n    }\n}\n\nfun Styler.applyTextOutline(paint: JSONObject) {\n    if (paint.has(\"text-halo-color\")) when (val textOutline = paint.get(\"text-halo-color\")) {\n        is JSONObject -> traverse(textOutline)\n        is JSONArray -> traverse(textOutline)\n        is String -> paint.put(\"text-halo-color\", applyColorChanges(textOutline.parseColor()).colorToString())\n    }\n}\n\nfun JSONArray.removeCompat(index: Int) =\n    if (SDK_INT >= 19) {\n        remove(index)\n        this\n    } else {\n        val field = JSONArray::class.java.getDeclaredField(\"values\")\n        field.isAccessible = true\n        val list = field.get(this) as MutableList<*>\n        list.removeAt(index)\n        this\n    }"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/UiSettings.kt",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 org.microg.gms.maps.mapbox\n\nimport android.os.Parcel\nimport android.util.Log\n\nimport com.google.android.gms.maps.internal.IUiSettingsDelegate\nimport com.mapbox.mapboxsdk.maps.OnMapReadyCallback\nimport com.mapbox.mapboxsdk.maps.UiSettings\n\n/**\n * This class \"implements\" unimplemented methods to avoid duplication in subclasses\n */\nabstract class AbstractUiSettings : IUiSettingsDelegate.Stub() {\n    override fun setZoomControlsEnabled(zoom: Boolean) {\n        Log.d(TAG, \"unimplemented Method: setZoomControlsEnabled\")\n    }\n\n    override fun setMyLocationButtonEnabled(locationButton: Boolean) {\n        Log.d(TAG, \"unimplemented Method: setMyLocationButtonEnabled\")\n    }\n\n    override fun isZoomControlsEnabled(): Boolean {\n        Log.d(TAG, \"unimplemented Method: isZoomControlsEnabled\")\n        return false\n    }\n\n    override fun isMyLocationButtonEnabled(): Boolean {\n        Log.d(TAG, \"unimplemented Method: isMyLocationButtonEnabled\")\n        return false\n    }\n\n    override fun setIndoorLevelPickerEnabled(indoorLevelPicker: Boolean) {\n        Log.d(TAG, \"unimplemented Method: setIndoorLevelPickerEnabled\")\n    }\n\n    override fun isIndoorLevelPickerEnabled(): Boolean {\n        Log.d(TAG, \"unimplemented Method: isIndoorLevelPickerEnabled\")\n        return false\n    }\n\n    override fun setMapToolbarEnabled(mapToolbar: Boolean) {\n        Log.d(TAG, \"unimplemented Method: setMapToolbarEnabled\")\n    }\n\n    override fun isMapToolbarEnabled(): Boolean {\n        Log.d(TAG, \"unimplemented Method: isMapToolbarEnabled\")\n        return false\n    }\n\n    override fun setScrollGesturesEnabledDuringRotateOrZoom(scrollDuringZoom: Boolean) {\n        Log.d(TAG, \"unimplemented Method: setScrollGesturesEnabledDuringRotateOrZoom\")\n    }\n\n    override fun isScrollGesturesEnabledDuringRotateOrZoom(): Boolean {\n        Log.d(TAG, \"unimplemented Method: isScrollGesturesEnabledDuringRotateOrZoom\")\n        return true\n    }\n\n    companion object {\n        private val TAG = \"GmsMapsUi\"\n    }\n}\n\nclass UiSettingsImpl(private val uiSettings: UiSettings) : AbstractUiSettings() {\n\n\n    override fun setCompassEnabled(compass: Boolean) {\n        uiSettings.isCompassEnabled = compass\n    }\n\n    override fun setScrollGesturesEnabled(scrollGestures: Boolean) {\n        uiSettings.isScrollGesturesEnabled = scrollGestures\n    }\n\n    override fun setZoomGesturesEnabled(zoomGestures: Boolean) {\n        uiSettings.isZoomGesturesEnabled = zoomGestures\n    }\n\n    override fun setTiltGesturesEnabled(tiltGestures: Boolean) {\n        uiSettings.isTiltGesturesEnabled = tiltGestures\n    }\n\n    override fun setRotateGesturesEnabled(rotateGestures: Boolean) {\n        uiSettings.isRotateGesturesEnabled = rotateGestures\n    }\n\n    override fun setAllGesturesEnabled(gestures: Boolean) {\n        uiSettings.setAllGesturesEnabled(gestures)\n    }\n\n    override fun isCompassEnabled(): Boolean = uiSettings.isCompassEnabled\n\n    override fun isScrollGesturesEnabled(): Boolean = uiSettings.isScrollGesturesEnabled\n\n    override fun isZoomGesturesEnabled(): Boolean = uiSettings.isZoomGesturesEnabled\n\n    override fun isTiltGesturesEnabled(): Boolean = uiSettings.isTiltGesturesEnabled\n\n    override fun isRotateGesturesEnabled(): Boolean = uiSettings.isRotateGesturesEnabled\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =\n            if (super.onTransact(code, data, reply, flags)) {\n                true\n            } else {\n                Log.d(TAG, \"onTransact [unknown]: $code, $data, $flags\"); false\n            }\n\n    companion object {\n        private val TAG = \"GmsMapsUiImpl\"\n    }\n}\n\nclass UiSettingsCache : AbstractUiSettings() {\n\n    private var compass: Boolean? = null\n    private var scrollGestures: Boolean? = null\n    private var zoomGestures: Boolean? = null\n    private var tiltGestures: Boolean? = null\n    private var rotateGestures: Boolean? = null\n    private var otherGestures: Boolean? = null\n\n    override fun setCompassEnabled(compass: Boolean) {\n        this.compass = compass\n    }\n\n    override fun setScrollGesturesEnabled(scrollGestures: Boolean) {\n        this.scrollGestures = scrollGestures\n    }\n\n    override fun setZoomGesturesEnabled(zoomGestures: Boolean) {\n        this.zoomGestures = zoomGestures\n    }\n\n    override fun setTiltGesturesEnabled(tiltGestures: Boolean) {\n        this.tiltGestures = tiltGestures\n    }\n\n    override fun setRotateGesturesEnabled(rotateGestures: Boolean) {\n        this.rotateGestures = rotateGestures\n    }\n\n    override fun setAllGesturesEnabled(gestures: Boolean) {\n        // Simulate MapLibre's UiSettings behavior\n        isScrollGesturesEnabled = gestures\n        isRotateGesturesEnabled = gestures\n        isTiltGesturesEnabled = gestures\n        isZoomGesturesEnabled = gestures\n\n        // Other gestures toggles double tap and quick zoom gestures\n        otherGestures = gestures\n    }\n\n    override fun isCompassEnabled(): Boolean {\n        return compass ?: true\n    }\n\n    override fun isScrollGesturesEnabled(): Boolean {\n        return scrollGestures ?: true\n    }\n\n    override fun isZoomGesturesEnabled(): Boolean {\n        return zoomGestures ?: true\n    }\n\n    override fun isTiltGesturesEnabled(): Boolean {\n        return tiltGestures ?: true\n    }\n\n    override fun isRotateGesturesEnabled(): Boolean {\n        return rotateGestures ?: true\n    }\n\n    fun getMapReadyCallback(): OnMapReadyCallback = OnMapReadyCallback { map ->\n        val uiSettings = map.uiSettings\n        compass?.let { uiSettings.isCompassEnabled = it }\n        scrollGestures?.let { uiSettings.isScrollGesturesEnabled = it }\n        zoomGestures?.let { uiSettings.isZoomGesturesEnabled = it }\n        tiltGestures?.let { uiSettings.isTiltGesturesEnabled = it }\n        rotateGestures?.let { uiSettings.isRotateGesturesEnabled = it }\n        otherGestures?.let {\n            uiSettings.isDoubleTapGesturesEnabled = it\n            uiSettings.isQuickZoomGesturesEnabled = it\n        }\n    }\n}"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/BitmapDescriptor.kt",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 org.microg.gms.maps.mapbox.model\n\nimport android.graphics.Color\nimport android.graphics.PointF\nimport android.util.Log\nimport com.mapbox.mapboxsdk.plugins.annotation.Symbol\nimport com.mapbox.mapboxsdk.plugins.annotation.SymbolOptions\nimport com.mapbox.mapboxsdk.style.layers.Property.ICON_ANCHOR_TOP_LEFT\nimport com.mapbox.mapboxsdk.style.layers.PropertyFactory\nimport com.mapbox.mapboxsdk.style.layers.SymbolLayer\nimport com.mapbox.mapboxsdk.utils.ColorUtils\n\nopen class BitmapDescriptorImpl(val id: String, internal val size: FloatArray) {\n    open fun applyTo(options: SymbolOptions, anchor: FloatArray, dpiFactor: Float): SymbolOptions {\n        return options.withIconImage(id).withIconAnchor(ICON_ANCHOR_TOP_LEFT).withIconOffset(arrayOf(-anchor[0] * size[0] / dpiFactor, -anchor[1] * size[1] / dpiFactor))\n    }\n\n    open fun applyTo(symbol: Symbol, anchor: FloatArray, dpiFactor: Float) {\n        symbol.iconAnchor = ICON_ANCHOR_TOP_LEFT\n        symbol.iconOffset = PointF(-anchor[0] * size[0] / dpiFactor, -anchor[1] * size[1] / dpiFactor)\n        symbol.iconImage = id\n    }\n\n    open fun applyTo(symbolLayer: SymbolLayer, anchor: FloatArray, dpiFactor: Float) {\n        symbolLayer.withProperties(\n            PropertyFactory.iconAnchor(ICON_ANCHOR_TOP_LEFT),\n            PropertyFactory.iconOffset(arrayOf(-anchor[0] * size[0] / dpiFactor, -anchor[1] * size[1] / dpiFactor)),\n            PropertyFactory.iconImage(id)\n        )\n    }\n\n    protected fun finalize() {\n        BitmapDescriptorFactoryImpl.disposeDescriptor(id)\n    }\n\n    override fun toString(): String {\n        return \"[BitmapDescriptor $id]\"\n    }\n}\n\nclass ColorBitmapDescriptorImpl(id: String, size: FloatArray, val hue: Float) : BitmapDescriptorImpl(id, size) {\n    override fun applyTo(options: SymbolOptions, anchor: FloatArray, dpiFactor: Float): SymbolOptions = super.applyTo(options, anchor, dpiFactor).withIconColor(ColorUtils.colorToRgbaString(Color.HSVToColor(floatArrayOf(hue, 1.0f, 0.5f))))\n    override fun applyTo(symbol: Symbol, anchor: FloatArray, dpiFactor: Float) {\n        super.applyTo(symbol, anchor, dpiFactor)\n        symbol.setIconColor(Color.HSVToColor(floatArrayOf(hue, 1.0f, 0.5f)))\n    }\n}"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/BitmapDescriptorFactory.kt",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 org.microg.gms.maps.mapbox.model\n\nimport android.content.res.Resources\nimport android.graphics.*\nimport android.os.Parcel\nimport android.util.Log\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.ObjectWrapper\nimport com.google.android.gms.maps.model.internal.IBitmapDescriptorFactoryDelegate\nimport com.mapbox.mapboxsdk.maps.MapboxMap\nimport com.mapbox.mapboxsdk.maps.Style\nimport org.microg.gms.maps.mapbox.R\nimport org.microg.gms.maps.mapbox.runOnMainLooper\nimport org.microg.gms.utils.toHexString\nimport java.nio.ByteBuffer\nimport java.security.MessageDigest\n\n\nobject BitmapDescriptorFactoryImpl : IBitmapDescriptorFactoryDelegate.Stub() {\n    private val TAG = \"GmsMapBitmap\"\n    private var resources: Resources? = null\n    private var mapResources: Resources? = null\n    private val maps = hashSetOf<MapboxMap>()\n    private val bitmaps = hashMapOf<String, Bitmap>()\n    private val refCount = hashMapOf<String, Int>()\n\n    fun initialize(mapResources: Resources?, resources: Resources?) {\n        BitmapDescriptorFactoryImpl.mapResources = mapResources ?: resources\n        BitmapDescriptorFactoryImpl.resources = resources ?: mapResources\n    }\n\n    fun registerMap(map: MapboxMap) {\n        Log.d(TAG, \"registerMap\")\n        map.getStyle {\n            synchronized(bitmaps) {\n                it.addImages(bitmaps)\n            }\n        }\n        maps.add(map)\n    }\n\n    fun unregisterMap(map: MapboxMap?) {\n        maps.remove(map)\n    }\n\n    fun put(style: Style.Builder) {\n        synchronized(bitmaps) {\n            for (bitmap in bitmaps) {\n                style.withImage(bitmap.key, bitmap.value)\n            }\n        }\n    }\n\n    fun bitmapSize(id: String): FloatArray =\n        bitmaps[id]?.let { floatArrayOf(it.width.toFloat(), it.height.toFloat()) }\n            ?: floatArrayOf(0f, 0f)\n\n    fun disposeDescriptor(id: String) {\n        synchronized(refCount) {\n            if (refCount.containsKey(id)) {\n                val old = refCount[id]!!\n                if (old > 1) {\n                    refCount[id] = old - 1;\n                    return\n                }\n            }\n        }\n        unregisterBitmap(id)\n    }\n\n    private fun unregisterBitmap(id: String) {\n        synchronized(bitmaps) {\n            if (!bitmaps.containsKey(id)) return\n            bitmaps.remove(id)\n        }\n\n        for (map in maps) {\n            map.getStyle {\n                runOnMainLooper {\n                    try {\n                        it.removeImage(id)\n                    } catch (e: Exception) {\n                        Log.w(TAG, e)\n                    }\n                }\n            }\n        }\n\n        refCount.remove(id)\n    }\n\n    private fun registerBitmap(id: String, descriptorCreator: (id: String, size: FloatArray) -> BitmapDescriptorImpl = { id, size -> BitmapDescriptorImpl(id, size) }, bitmapCreator: () -> Bitmap?): IObjectWrapper {\n        val bitmap: Bitmap? = synchronized(bitmaps) {\n            if (bitmaps.contains(id)) return@synchronized null\n            val bitmap = bitmapCreator()\n            if (bitmap == null) {\n                Log.w(TAG, \"Failed to register bitmap $id, creator returned null\")\n                return@synchronized null\n            }\n            bitmaps[id] = bitmap\n            bitmap\n        }\n\n        if (bitmap != null) {\n            for (map in maps) {\n                map.getStyle {\n                    runOnMainLooper {\n                        it.addImage(id, bitmap)\n                    }\n                }\n            }\n        }\n\n        synchronized(refCount) {\n            refCount[id] = (refCount[id] ?: 0) + 1\n        }\n\n        return ObjectWrapper.wrap(descriptorCreator(id, bitmapSize(id)))\n    }\n\n    override fun fromResource(resourceId: Int): IObjectWrapper = registerBitmap(\"resource-$resourceId\") {\n        val bitmap = BitmapFactory.decodeResource(resources, resourceId)\n        if (bitmap == null) {\n            try {\n                Log.d(TAG, \"Resource $resourceId not found in $resources (${resources?.getResourceName(resourceId)})\")\n            } catch (e: Resources.NotFoundException) {\n                Log.d(TAG, \"Resource $resourceId not found in $resources\")\n            }\n        }\n        bitmap\n    }\n\n    override fun fromAsset(assetName: String): IObjectWrapper = registerBitmap(\"asset-$assetName\") {\n        resources?.assets?.open(assetName)?.let { BitmapFactory.decodeStream(it) }\n    }\n\n    override fun fromFile(fileName: String): IObjectWrapper = registerBitmap(\"file-$fileName\") {\n        BitmapFactory.decodeFile(fileName)\n    }\n\n    override fun defaultMarker(): IObjectWrapper = registerBitmap(\"marker\") {\n        BitmapFactory.decodeResource(mapResources, R.drawable.maps_default_marker)\n    }\n\n    private fun adjustHue(cm: ColorMatrix, value: Float) {\n        var value = value\n        value = cleanValue(value, 180f) / 180f * Math.PI.toFloat()\n        if (value == 0f) {\n            return\n        }\n        val cosVal = Math.cos(value.toDouble()).toFloat()\n        val sinVal = Math.sin(value.toDouble()).toFloat()\n        val lumR = 0.213f\n        val lumG = 0.715f\n        val lumB = 0.072f\n        val mat = floatArrayOf(lumR + cosVal * (1 - lumR) + sinVal * -lumR, lumG + cosVal * -lumG + sinVal * -lumG, lumB + cosVal * -lumB + sinVal * (1 - lumB), 0f, 0f, lumR + cosVal * -lumR + sinVal * 0.143f, lumG + cosVal * (1 - lumG) + sinVal * 0.140f, lumB + cosVal * -lumB + sinVal * -0.283f, 0f, 0f, lumR + cosVal * -lumR + sinVal * -(1 - lumR), lumG + cosVal * -lumG + sinVal * lumG, lumB + cosVal * (1 - lumB) + sinVal * lumB, 0f, 0f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 0f, 0f, 1f)\n        cm.postConcat(ColorMatrix(mat))\n    }\n\n    private fun cleanValue(p_val: Float, p_limit: Float): Float {\n        return Math.min(p_limit, Math.max(-p_limit, p_val))\n    }\n\n    override fun defaultMarkerWithHue(hue: Float): IObjectWrapper? {\n        return registerBitmap(\"marker-${hue.toInt()}\", { id, size -> ColorBitmapDescriptorImpl(id, size, hue) }) {\n            val bitmap = BitmapFactory.decodeResource(mapResources, R.drawable.maps_default_marker).copy(Bitmap.Config.ARGB_8888, true)\n            val paint = Paint()\n            val matrix = ColorMatrix()\n            val huex = hue % 360f\n            adjustHue(matrix, if (huex > 180f) huex - 360f else huex)\n            paint.setColorFilter(ColorMatrixColorFilter(matrix))\n\n            val canvas = Canvas(bitmap)\n            canvas.drawBitmap(bitmap, 0f, 0f, paint)\n            bitmap\n        }\n    }\n\n    private fun Bitmap.sha256(): String {\n        val bytes = ByteArray(rowBytes * height)\n        copyPixelsToBuffer(ByteBuffer.wrap(bytes))\n        return MessageDigest.getInstance(\"SHA-256\").digest(bytes).toHexString()\n    }\n\n    override fun fromBitmap(bitmap: Bitmap): IObjectWrapper = registerBitmap(\"bitmap-${bitmap.sha256()}\") { bitmap }\n\n    override fun fromPath(absolutePath: String): IObjectWrapper = registerBitmap(\"path-$absolutePath\") { BitmapFactory.decodeFile(absolutePath) }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =\n        if (super.onTransact(code, data, reply, flags)) {\n            true\n        } else {\n            Log.d(TAG, \"onTransact [unknown]: $code, $data, $flags\"); false\n        }\n}\n"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Circle.kt",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 org.microg.gms.maps.mapbox.model\n\nimport android.os.Parcel\nimport android.util.Log\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.ObjectWrapper\nimport com.google.android.gms.dynamic.unwrap\nimport com.google.android.gms.maps.model.Dash\nimport com.google.android.gms.maps.model.LatLng\nimport com.google.android.gms.maps.model.PatternItem\nimport com.google.android.gms.maps.model.internal.ICircleDelegate\nimport com.mapbox.geojson.LineString\nimport com.mapbox.geojson.Point\nimport com.mapbox.mapboxsdk.plugins.annotation.*\nimport com.mapbox.mapboxsdk.utils.ColorUtils\nimport com.mapbox.turf.TurfConstants\nimport com.mapbox.turf.TurfConstants.UNIT_METERS\nimport com.mapbox.turf.TurfMeasurement\nimport com.mapbox.turf.TurfMeta\nimport com.mapbox.turf.TurfTransformation\nimport org.microg.gms.maps.mapbox.GoogleMapImpl\nimport org.microg.gms.maps.mapbox.LiteGoogleMapImpl\nimport org.microg.gms.maps.mapbox.utils.toPoint\nimport org.microg.gms.maps.mapbox.getName\nimport org.microg.gms.maps.mapbox.makeBitmap\nimport com.google.android.gms.maps.model.CircleOptions as GmsCircleOptions\n\nval NORTH_POLE: Point = Point.fromLngLat(0.0, 90.0)\nval SOUTH_POLE: Point = Point.fromLngLat(0.0, -90.0)\n\n/**\n * Amount of points to be used in the polygon that approximates the circle.\n */\nconst val CIRCLE_POLYGON_STEPS = 256\n\nabstract class AbstractCircle(\n    private val id: String, options: GmsCircleOptions, private val dpiFactor: Function0<Float>\n) : ICircleDelegate.Stub() {\n\n    internal var center: LatLng = options.center\n    internal var radiusInMeters: Double = options.radius // unlike MapLibre's circles, which only work with pixel radii\n    internal var strokeWidth: Float = options.strokeWidth\n    internal var strokeColor: Int = options.strokeColor\n    internal var fillColor: Int = options.fillColor\n    internal var visible: Boolean = options.isVisible\n    internal var clickable: Boolean = options.isClickable\n    internal var strokePattern: MutableList<PatternItem>? = options.strokePattern\n    internal var tag: Any? = null\n\n    internal val line: Markup<Line, LineOptions> = object : Markup<Line, LineOptions> {\n        override var annotation: Line? = null\n        override val annotationOptions: LineOptions\n            get() = LineOptions()\n                .withGeometry(\n                    LineString.fromLngLats(\n                        makeOutlineLatLngs()\n                    )\n                ).withLineWidth(strokeWidth / dpiFactor())\n                .withLineColor(ColorUtils.colorToRgbaString(strokeColor))\n                .withLineOpacity(if (visible) 1f else 0f)\n                .apply {\n                    strokePattern?.let {\n                        withLinePattern(it.getName(strokeColor, strokeWidth))\n                    }\n                }\n\n        override var removed: Boolean = false\n    }\n\n    val annotationOptions: FillOptions\n        get() =\n            FillOptions()\n                .withGeometry(makePolygon())\n                .withFillColor(ColorUtils.colorToRgbaString(fillColor))\n                .withFillOpacity(if (visible && !wrapsAroundPoles()) 1f else 0f)\n\n    internal abstract fun update()\n\n    internal fun makePolygon() = TurfTransformation.circle(\n        Point.fromLngLat(center.longitude, center.latitude), radiusInMeters, CIRCLE_POLYGON_STEPS, TurfConstants.UNIT_METERS\n    )\n\n    /**\n     * Google's \"map renderer is unable to draw the circle fill if the circle encompasses\n     * either the North or South pole\" (though it does so incorrectly anyway)\n     */\n    internal fun wrapsAroundPoles() = center.toPoint().let {\n        TurfMeasurement.distance(\n            it, NORTH_POLE, UNIT_METERS\n        ) < radiusInMeters || TurfMeasurement.distance(\n            it, SOUTH_POLE, UNIT_METERS\n        ) < radiusInMeters\n    }\n\n    internal fun makeOutlineLatLngs(): MutableList<Point> {\n        val pointList = TurfMeta.coordAll(\n            makePolygon(), wrapsAroundPoles()\n        )\n        // Circles around the poles are tricky to draw (https://github.com/mapbox/mapbox-gl-js/issues/11235).\n        // We modify our lines such to match the way Mapbox / MapLibre draws them.\n        // This results in a small gap somewhere in the line, but avoids an incorrect horizontal line.\n\n        val centerPoint = center.toPoint()\n\n        if (!centerPoint.equals(NORTH_POLE) && TurfMeasurement.distance(centerPoint, NORTH_POLE, UNIT_METERS) < radiusInMeters) {\n            // Wraps around North Pole\n            for (i in 0 until pointList.size) {\n                // We want to have the north-most points at the start and end\n                if (pointList[0].latitude() > pointList[1].latitude() && pointList[pointList.size - 1].latitude() > pointList[pointList.size - 2].latitude()) {\n                    return pointList\n                } else {\n                    // Cycle point list\n                    val zero = pointList.removeFirst()\n                    pointList.add(zero)\n                }\n            }\n        }\n\n        if (!centerPoint.equals(SOUTH_POLE) && TurfMeasurement.distance(centerPoint, SOUTH_POLE, UNIT_METERS) < radiusInMeters) {\n            // Wraps around South Pole\n            for (i in 0 until pointList.size) {\n                // We want to have the south-most points at the start and end\n                if (pointList[0].latitude() < pointList[1].latitude() && pointList[pointList.size - 1].latitude() < pointList[pointList.size - 2].latitude()) {\n                    return pointList\n                } else {\n                    // Cycle point list\n                    val last = pointList.removeAt(pointList.size - 1)\n                    pointList.add(0, last)\n                }\n            }\n        }\n\n        // In this case no changes were made\n        return pointList\n    }\n\n    override fun getId(): String = id\n\n    override fun setCenter(center: LatLng) {\n        this.center = center\n        update()\n\n    }\n\n    override fun getCenter(): LatLng = center\n\n    override fun setRadius(radius: Double) {\n        this.radiusInMeters = radius\n        update()\n    }\n\n    override fun getRadius(): Double = radiusInMeters\n\n    override fun setStrokeWidth(width: Float) {\n        this.strokeWidth = width\n        update()\n    }\n\n    override fun getStrokeWidth(): Float = strokeWidth\n\n    override fun setStrokeColor(color: Int) {\n        this.strokeColor = color\n        update()\n    }\n\n    override fun getStrokeColor(): Int = strokeColor\n\n    override fun setFillColor(color: Int) {\n        this.fillColor = color\n        update()\n    }\n\n    override fun getFillColor(): Int = fillColor\n\n    override fun setZIndex(zIndex: Float) {\n        Log.d(TAG, \"unimplemented Method: setZIndex\")\n    }\n\n    override fun getZIndex(): Float {\n        Log.d(TAG, \"unimplemented Method: getZIndex\")\n        return 0f\n    }\n\n    override fun setVisible(visible: Boolean) {\n        this.visible = visible\n        update()\n    }\n\n    override fun isVisible(): Boolean = visible\n\n    override fun equalsRemote(other: ICircleDelegate?): Boolean = equals(other)\n\n    override fun hashCodeRemote(): Int = hashCode()\n\n    override fun setClickable(clickable: Boolean) {\n        this.clickable = clickable\n    }\n\n    override fun isClickable(): Boolean {\n        return clickable\n    }\n\n    override fun setStrokePattern(pattern: MutableList<PatternItem>?) {\n        this.strokePattern = pattern\n        update()\n    }\n\n\n    override fun getStrokePattern(): MutableList<PatternItem>? {\n        return strokePattern\n    }\n\n    override fun setTag(o: IObjectWrapper) {\n        this.tag = o.unwrap()\n    }\n\n    override fun getTag(): IObjectWrapper = ObjectWrapper.wrap(tag)\n\n    override fun hashCode(): Int {\n        return id.hashCode()\n    }\n\n    override fun toString(): String {\n        return id\n    }\n\n    override fun equals(other: Any?): Boolean {\n        if (other is CircleImpl) {\n            return other.id == id\n        }\n        return false\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =\n        if (super.onTransact(code, data, reply, flags)) {\n            true\n        } else {\n            Log.d(TAG, \"onTransact [unknown]: $code, $data, $flags\"); false\n        }\n\n    companion object {\n        val TAG = \"GmsMapAbstractCircle\"\n    }\n}\n\nclass CircleImpl(private val map: GoogleMapImpl, private val id: String, options: GmsCircleOptions) :\n    AbstractCircle(id, options, { map.dpiFactor }), Markup<Fill, FillOptions> {\n\n    override var annotation: Fill? = null\n    override var removed: Boolean = false\n\n    override fun update() {\n        val polygon = makePolygon()\n\n        // Extracts points from generated polygon in expected format\n        annotation?.let {\n            it.latLngs = FillOptions().withGeometry(polygon).latLngs\n            it.setFillColor(fillColor)\n            it.fillOpacity = if (visible && !wrapsAroundPoles()) 1f else 0f\n        }\n\n        line.annotation?.let {\n            it.latLngs = makeOutlineLatLngs().map { point ->\n                com.mapbox.mapboxsdk.geometry.LatLng(\n                    point.latitude(),\n                    point.longitude()\n                )\n            }\n\n            it.lineWidth = strokeWidth / map.dpiFactor\n\n            (strokePattern ?: emptyList()).let { pattern ->\n                val bitmapName = pattern.getName(strokeColor, strokeWidth)\n                map.addBitmap(bitmapName, pattern.makeBitmap(strokeColor, strokeWidth))\n                line.annotation?.linePattern = bitmapName\n            }\n            map.lineManager?.let { line.update(it) }\n\n            it.setLineColor(strokeColor)\n        }\n\n        map.fillManager?.let { update(it) }\n        map.lineManager?.let { line.update(it) }\n    }\n\n    override fun remove() {\n        removed = true\n        line.removed = true\n        map.fillManager?.let { update(it) }\n        map.lineManager?.let { line.update(it) }\n    }\n\n\n    override fun update(manager: AnnotationManager<*, Fill, FillOptions, *, *, *>) {\n        synchronized(this) {\n            val id = annotation?.id\n            if (removed && id != null) {\n                map.circles.remove(id)\n            }\n            super.update(manager)\n            val annotation = annotation\n            if (annotation != null && id == null) {\n                map.circles[annotation.id] = this\n            }\n        }\n    }\n\n    companion object {\n        val TAG = \"GmsMapCircle\"\n    }\n}\n\nclass LiteCircleImpl(private val map: LiteGoogleMapImpl, id: String, options: GmsCircleOptions) :\n    AbstractCircle(id, options, { map.dpiFactor }) {\n    override fun update() {\n        map.postUpdateSnapshot()\n    }\n\n    override fun remove() {\n        map.circles.remove(this)\n    }\n\n}"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/GroundOverlay.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.maps.mapbox.model\n\nimport android.os.Parcel\nimport android.util.Log\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.ObjectWrapper\nimport com.google.android.gms.dynamic.unwrap\nimport com.google.android.gms.maps.model.GroundOverlayOptions\nimport com.google.android.gms.maps.model.LatLng\nimport com.google.android.gms.maps.model.LatLngBounds\nimport com.google.android.gms.maps.model.internal.IGroundOverlayDelegate\nimport org.microg.gms.maps.mapbox.GoogleMapImpl\nimport org.microg.gms.utils.warnOnTransactionIssues\nimport kotlin.math.cos\nimport kotlin.math.min\n\nclass GroundOverlayImpl(private val map: GoogleMapImpl, private val id: String, options: GroundOverlayOptions) : IGroundOverlayDelegate.Stub() {\n    private val image: BitmapDescriptorImpl? = options.image?.remoteObject?.unwrap()\n    private var location: LatLng? = options.location\n    private var width: Float = options.width\n    private var height: Float = options.height\n    private var bounds: LatLngBounds? = options.bounds\n    private var bearing: Float = options.bearing\n    private var zIndex: Float = options.zIndex\n    private var visible: Boolean = options.isVisible\n    private var transparency: Float = options.transparency\n    private var anchorU: Float = options.anchorU\n    private var anchorV: Float = options.anchorV\n    private var clickable: Boolean = options.isClickable\n    private var tag: Any? = null\n\n    init {\n        // Compute missing values\n        if (height < 0 || height.isNaN()) {\n            val imageHeight = image?.size?.getOrNull(0) ?: -1f\n            val imageWidth = image?.size?.getOrNull(1) ?: -1f\n            if (imageHeight >= 0 && imageWidth > 0) {\n                height = (imageHeight / imageWidth) * width\n            }\n        }\n        if (bounds == null && width >= 0 && height >= 0 && location != null) {\n            val latitudeSpan = Math.toDegrees(height.toDouble() / EARTH_RADIUS)\n            val longitudeSpan = min(Math.toDegrees(width.toDouble() / (cos(Math.toRadians(location!!.latitude)) * EARTH_RADIUS)), 359.999999)\n            val north = location!!.latitude + (latitudeSpan * anchorV)\n            val south = location!!.latitude - (latitudeSpan * (1.0 - anchorV))\n            val west = location!!.longitude - (longitudeSpan * anchorU)\n            val east = location!!.longitude + (longitudeSpan * (1.0 - anchorU))\n            bounds = LatLngBounds(LatLng(south, west), LatLng(north, east))\n        }\n        if (location == null && bounds != null) {\n            val north = bounds!!.northeast.latitude\n            val south = bounds!!.southwest.latitude\n            var east = bounds!!.northeast.longitude\n            val west = bounds!!.southwest.longitude\n            while (east < west) east += 360.0\n            location = LatLng((1.0 - anchorV) * north + anchorV * south, (1.0 - anchorU) * west + anchorU * east)\n        }\n    }\n\n    override fun getId(): String {\n        return id\n    }\n\n    override fun getPosition(): LatLng? {\n        return location\n    }\n\n    override fun setPosition(pos: LatLng?) {\n        this.location = pos\n    }\n\n    override fun getWidth(): Float {\n        return width\n    }\n\n    override fun getHeight(): Float {\n        return height\n    }\n\n    override fun setDimensions(width: Float, height: Float) {\n        this.width = width\n        this.height = height\n    }\n\n    override fun getBounds(): LatLngBounds? {\n        return bounds\n    }\n\n    override fun getBearing(): Float {\n        return bearing\n    }\n\n    override fun setBearing(bearing: Float) {\n        this.bearing = bearing\n    }\n\n    override fun setZIndex(zIndex: Float) {\n        this.zIndex = zIndex\n    }\n\n    override fun getZIndex(): Float {\n        return zIndex\n    }\n\n    override fun isVisible(): Boolean {\n        return visible\n    }\n\n    override fun setVisible(visible: Boolean) {\n        this.visible = visible\n    }\n\n    override fun getTransparency(): Float {\n        return transparency\n    }\n\n    override fun setTransparency(transparency: Float) {\n        this.transparency = transparency\n    }\n\n    override fun setDimension(dimension: Float) {\n        Log.w(TAG, \"unimplemented Method: setDimension\")\n    }\n\n    override fun setPositionFromBounds(bounds: LatLngBounds?) {\n        this.bounds = bounds\n    }\n\n    override fun setClickable(clickable: Boolean) {\n        this.clickable = clickable\n    }\n\n    override fun isClickable(): Boolean {\n        return clickable\n    }\n\n    override fun setImage(img: IObjectWrapper?) {\n        Log.d(TAG, \"Not yet implemented: setImage\")\n    }\n\n    override fun setTag(o: IObjectWrapper?) {\n        this.tag = o.unwrap()\n    }\n\n    override fun getTag(): IObjectWrapper = ObjectWrapper.wrap(tag)\n\n    override fun equalsRemote(other: IGroundOverlayDelegate?): Boolean {\n        return this.equals(other)\n    }\n\n    override fun hashCode(): Int {\n        return id.hashCode()\n    }\n\n    override fun hashCodeRemote(): Int {\n        return hashCode()\n    }\n\n    override fun remove() {\n        Log.w(TAG, \"unimplemented Method: remove\")\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n\n    companion object {\n        private const val TAG = \"GroundOverlay\"\n        private const val EARTH_RADIUS = 6371009.0\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/InfoWindow.kt",
    "content": "package org.microg.gms.maps.mapbox.model\n\nimport android.graphics.Point\nimport android.graphics.PointF\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.View.VISIBLE\nimport android.view.ViewGroup\nimport android.view.ViewManager\nimport android.widget.FrameLayout\nimport android.widget.TextView\nimport androidx.core.content.ContextCompat\nimport androidx.core.view.ViewCompat\nimport com.google.android.gms.dynamic.ObjectWrapper\nimport com.google.android.gms.dynamic.unwrap\nimport com.google.android.gms.maps.internal.IInfoWindowAdapter\nimport com.google.android.gms.maps.model.internal.IMarkerDelegate\nimport com.mapbox.android.gestures.Utils\nimport org.microg.gms.maps.mapbox.AbstractGoogleMap\nimport org.microg.gms.maps.mapbox.GoogleMapImpl\nimport org.microg.gms.maps.mapbox.R\nimport org.microg.gms.maps.mapbox.utils.MapContext\nimport org.microg.gms.maps.mapbox.utils.toMapbox\nimport kotlin.math.*\n\n/**\n * `InfoWindow` is a tooltip shown when a [MarkerImpl] is tapped. Only\n * one info window is displayed at a time. When the user clicks on a marker, the currently open info\n * window will be closed and the new info window will be displayed. If the user clicks the same\n * marker while its info window is currently open, the info window will be reopened.\n *\n * The info window is drawn oriented against the device's screen, centered above its associated\n * marker, unless a different info window anchor is set. The default info window contains the title\n * in bold and snippet text below the title.\n * If neither is set, no default info window is shown.\n *\n * Based on Mapbox's / MapLibre's [com.mapbox.mapboxsdk.annotations.InfoWindow].\n *\n */\n\nfun IInfoWindowAdapter.getInfoWindowViewFor(marker: IMarkerDelegate, mapContext: MapContext): View? {\n    getInfoWindow(marker).unwrap<View?>()?.let { view ->\n        return view.apply {\n            // Remove any previous parents mistakenly added by the client\n            parent?.let { (it as ViewManager).removeView(this) }\n        }\n    }\n\n    getInfoContents(marker).unwrap<View>()?.let { view ->\n        // Detach from previous BubbleLayout parent, if exists\n        view.parent?.let { (it as ViewManager).removeView(view) }\n\n        return FrameLayout(view.context).apply {\n            ViewCompat.setBackground(this, ContextCompat.getDrawable(mapContext, R.drawable.maps_default_bubble))\n            val fourDp = Utils.dpToPx(4f)\n            ViewCompat.setElevation(this, fourDp)\n            setPadding(fourDp.toInt(), fourDp.toInt(), fourDp.toInt(), fourDp.toInt() * 3)\n            addView(view)\n        }\n    }\n\n    // When a custom adapter is used, but both methods return null, the default adapter must be used\n    if (this !is DefaultInfoWindowAdapter) {\n        return DefaultInfoWindowAdapter(mapContext).getInfoWindowViewFor(marker, mapContext)\n    }\n\n    return null\n}\n\nclass InfoWindow internal constructor(\n    private val view: View, private val map: AbstractGoogleMap, internal val marker: AbstractMarker\n) {\n    private var coordinates: PointF = PointF(0f, 0f)\n    var isVisible = false\n\n    init {\n        view.setOnClickListener {\n            map.onInfoWindowClickListener?.onInfoWindowClick(marker)\n        }\n        view.setOnLongClickListener {\n            map.onInfoWindowLongClickListener?.onInfoWindowLongClick(marker)\n            true\n        }\n    }\n\n    fun open(mapView: FrameLayout) {\n        val layoutParams: FrameLayout.LayoutParams = FrameLayout.LayoutParams(\n            FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT\n        )\n        view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)\n\n        close(true) // if it was already opened\n        mapView.addView(view, layoutParams)\n        isVisible = true\n\n        // Set correct position\n        update()\n    }\n\n    /**\n     * Close this [InfoWindow] if it is visible, otherwise calling this will do nothing.\n     *\n     * @param silent `OnInfoWindowCloseListener` is only called if `silent` is `false`\n     */\n    fun close(silent: Boolean = false) {\n        if (isVisible) {\n            isVisible = false\n            (view.parent as ViewGroup?)?.removeView(view)\n            if (!silent) {\n                map.onInfoWindowCloseListener?.onInfoWindowClose(marker)\n            }\n        }\n    }\n\n    /**\n     * Updates the position of the displayed view.\n     */\n    fun update() {\n\n        if (map is GoogleMapImpl) {\n            map.map?.projection?.toScreenLocation(marker.position.toMapbox())?.let {\n                coordinates = it\n            }\n        } else {\n            map.projection.toScreenLocation(marker.position)?.let {\n                coordinates = PointF(it.unwrap<Point>()!!)\n            }\n        }\n\n        val iconDimensions = marker.getIconDimensions()\n        val width = iconDimensions?.get(0) ?: 0f\n        val height = iconDimensions?.get(1) ?: 0f\n\n        view.x =\n            coordinates.x - view.measuredWidth / 2f + sin(Math.toRadians(marker.rotation.toDouble())).toFloat() * width * marker.infoWindowAnchor[0]\n        view.y = coordinates.y - view.measuredHeight - max(\n            height * cos(Math.toRadians(marker.rotation.toDouble())).toFloat() * marker.infoWindowAnchor[1], 0f\n        )\n    }\n}\n\nclass DefaultInfoWindowAdapter(val context: MapContext) : IInfoWindowAdapter {\n    override fun asBinder() = null\n\n    override fun getInfoWindow(marker: IMarkerDelegate?): ObjectWrapper<View> {\n\n        if (marker == null) return ObjectWrapper.wrap(null)\n\n        val showDefaultMarker = (marker.title != null) || (marker.snippet != null)\n\n        return if (!showDefaultMarker) ObjectWrapper.wrap(null)\n        else ObjectWrapper.wrap(\n            LayoutInflater.from(context).inflate(R.layout.maps_default_bubble_layout, null, false).apply {\n\n                marker.title?.let {\n                    val titleTextView = findViewById<TextView>(R.id.title)\n                    titleTextView.text = it\n                    titleTextView.visibility = VISIBLE\n                }\n\n                marker.snippet?.let {\n                    val snippetTextView = findViewById<TextView>(R.id.snippet)\n                    snippetTextView.text = it\n                    snippetTextView.visibility = VISIBLE\n                }\n            }\n        )\n    }\n\n    override fun getInfoContents(marker: IMarkerDelegate?) = null\n}"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Marker.kt",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 org.microg.gms.maps.mapbox.model\n\nimport android.os.Parcel\nimport android.util.Log\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.ObjectWrapper\nimport com.google.android.gms.maps.model.LatLng\nimport com.google.android.gms.maps.model.MarkerOptions\nimport com.google.android.gms.maps.model.internal.IMarkerDelegate\nimport com.mapbox.mapboxsdk.plugins.annotation.AnnotationManager\nimport com.mapbox.mapboxsdk.plugins.annotation.Symbol\nimport com.mapbox.mapboxsdk.plugins.annotation.SymbolOptions\nimport com.google.android.gms.dynamic.unwrap\nimport com.google.android.gms.maps.model.BitmapDescriptorFactory\nimport org.microg.gms.maps.mapbox.AbstractGoogleMap\nimport org.microg.gms.maps.mapbox.GoogleMapImpl\nimport org.microg.gms.maps.mapbox.LiteGoogleMapImpl\nimport org.microg.gms.maps.mapbox.utils.toMapbox\n\nabstract class AbstractMarker(\n    private val id: String, options: MarkerOptions, private val map: AbstractGoogleMap\n) : IMarkerDelegate.Stub() {\n\n    internal var position: LatLng = options.position\n    internal var visible: Boolean = options.isVisible\n    internal var anchor: FloatArray = floatArrayOf(options.anchorU, options.anchorV)\n    internal var infoWindowAnchor: FloatArray = floatArrayOf(0.5f, 1f)\n    internal var icon: BitmapDescriptorImpl =\n        options.icon?.remoteObject.unwrap() ?:\n        BitmapDescriptorFactoryImpl.defaultMarker().unwrap<BitmapDescriptorImpl>()!!\n    internal var alpha: Float = options.alpha\n    internal var title: String? = options.title\n    internal var snippet: String? = options.snippet\n    internal var zIndex: Float = options.zIndex\n    internal var tag: IObjectWrapper? = null\n    internal open var draggable = false\n\n    val annotationOptions: SymbolOptions\n        get() {\n            val symbolOptions = SymbolOptions()\n                .withIconOpacity(if (visible) alpha else 0f)\n                .withIconRotate(rotation)\n                .withSymbolSortKey(zIndex)\n                .withDraggable(draggable)\n\n            position.let { symbolOptions.withLatLng(it.toMapbox()) }\n            icon?.applyTo(symbolOptions, anchor, map.dpiFactor)\n            return symbolOptions\n        }\n\n    internal abstract fun update()\n\n    override fun getId(): String = id\n\n    override fun setPosition(position: LatLng?) {\n        this.position = position ?: return\n        update()\n    }\n\n    override fun getPosition(): LatLng = position\n\n    override fun setIcon(obj: IObjectWrapper?) {\n        this.icon = obj?.unwrap<BitmapDescriptorImpl>() ?: BitmapDescriptorFactoryImpl.defaultMarker().unwrap()!!\n        update()\n    }\n\n    override fun setVisible(visible: Boolean) {\n        this.visible = visible\n        update()\n    }\n\n    override fun setTitle(title: String?) {\n        this.title = title\n        update()\n    }\n\n    override fun getTitle(): String? = title\n\n    override fun getSnippet(): String? = snippet\n\n    override fun isVisible(): Boolean = visible\n\n    override fun setAnchor(x: Float, y: Float) {\n        anchor = floatArrayOf(x, y)\n        update()\n    }\n\n    override fun setAlpha(alpha: Float) {\n        this.alpha = alpha\n        update()\n    }\n\n    override fun getAlpha(): Float = alpha\n\n    override fun setZIndex(zIndex: Float) {\n        this.zIndex = zIndex\n        update()\n    }\n\n    override fun getZIndex(): Float = zIndex\n\n    fun getIconDimensions(): FloatArray? {\n        return icon?.size\n    }\n\n    override fun showInfoWindow() {\n        if (isInfoWindowShown) {\n            // Per docs, don't call `onWindowClose` if info window is re-opened programmatically\n            map.currentInfoWindow?.close(silent = true)\n        }\n        map.showInfoWindow(this)\n    }\n\n    override fun hideInfoWindow() {\n        if (isInfoWindowShown) {\n            map.currentInfoWindow?.close()\n            map.currentInfoWindow = null\n        }\n    }\n\n    override fun isInfoWindowShown(): Boolean {\n        return map.currentInfoWindow?.marker == this\n    }\n\n    override fun setTag(obj: IObjectWrapper?) {\n        this.tag = obj\n    }\n\n    override fun getTag(): IObjectWrapper? = tag ?: ObjectWrapper.wrap(null)\n\n    override fun setSnippet(snippet: String?) {\n        this.snippet = snippet\n    }\n\n    override fun equalsRemote(other: IMarkerDelegate?): Boolean = equals(other)\n\n    override fun hashCodeRemote(): Int = hashCode()\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =\n        if (super.onTransact(code, data, reply, flags)) {\n            true\n        } else {\n            Log.d(TAG, \"onTransact [unknown]: $code, $data, $flags\"); false\n        }\n\n    companion object {\n        private val TAG = \"GmsMapAbstractMarker\"\n    }\n}\n\nclass MarkerImpl(private val map: GoogleMapImpl, private val id: String, options: MarkerOptions) :\n    AbstractMarker(id, options, map), Markup<Symbol, SymbolOptions> {\n\n    internal var rotation: Float = options.rotation\n    override var draggable: Boolean = options.isDraggable\n\n    override var annotation: Symbol? = null\n    override var removed: Boolean = false\n\n    override fun remove() {\n        removed = true\n        map.symbolManager?.let { update(it) }\n    }\n\n    override fun update() {\n        annotation?.let {\n            it.latLng = position.toMapbox()\n            it.isDraggable = draggable\n            it.iconOpacity = if (visible) alpha else 0f\n            it.symbolSortKey = zIndex\n            icon?.applyTo(it, anchor, map.dpiFactor)\n        }\n        map.symbolManager?.let { update(it) }\n    }\n\n    override fun update(manager: AnnotationManager<*, Symbol, SymbolOptions, *, *, *>) {\n        synchronized(this) {\n            val id = annotation?.id\n            if (removed && id != null) {\n                map.markers.remove(id)\n            }\n            super.update(manager)\n            val annotation = annotation\n            if (annotation != null && id == null) {\n                map.markers[annotation.id] = this\n            }\n        }\n    }\n\n    override fun setPosition(position: LatLng?) {\n        super.setPosition(position)\n        map.currentInfoWindow?.update()\n    }\n\n    /**\n     * New position is already reflected on map while if drag is in progress. Calling\n     * `symbolManager.update` would interrupt the drag.\n     */\n    internal fun setPositionWhileDragging(position: LatLng) {\n        this.position = position\n        map.currentInfoWindow?.update()\n    }\n\n    override fun setTitle(title: String?) {\n        super.setTitle(title)\n        map.currentInfoWindow?.let {\n            if (it.marker == this) it.close()\n        }\n    }\n\n    override fun setSnippet(snippet: String?) {\n        super.setSnippet(snippet)\n        map.currentInfoWindow?.let {\n            if (it.marker == this) it.close()\n        }\n    }\n\n    override fun setDraggable(draggable: Boolean) {\n        this.draggable = draggable\n        map.symbolManager?.let { update(it) }\n    }\n\n    override fun isDraggable(): Boolean = draggable\n\n    override fun equals(other: Any?): Boolean {\n        if (this === other) return true\n        if (other is IMarkerDelegate) return other.id == id\n        return false\n    }\n\n    override fun hashCode(): Int {\n        return id.hashCode()\n    }\n\n    override fun toString(): String {\n        return \"$id ($title)\"\n    }\n\n    override fun setAnchor(x: Float, y: Float) {\n        super.setAnchor(x, y)\n        map.currentInfoWindow?.update()\n    }\n\n    override fun setFlat(flat: Boolean) {\n        Log.d(TAG, \"unimplemented Method: setFlat\")\n    }\n\n    override fun isFlat(): Boolean {\n        Log.d(TAG, \"unimplemented Method: isFlat\")\n        return false\n    }\n\n    override fun setRotation(rotation: Float) {\n        this.rotation = rotation\n        annotation?.iconRotate = rotation\n        map.symbolManager?.let { update(it) }\n        map.currentInfoWindow?.update()\n    }\n\n    override fun getRotation(): Float = rotation\n\n    override fun setInfoWindowAnchor(x: Float, y: Float) {\n        infoWindowAnchor = floatArrayOf(x, y)\n        map.currentInfoWindow?.update()\n    }\n\n    companion object {\n        private val TAG = \"GmsMapMarker\"\n    }\n}\n\nclass LiteMarkerImpl(id: String, options: MarkerOptions, private val map: LiteGoogleMapImpl) :\n    AbstractMarker(id, options, map) {\n    override fun remove() {\n        map.markers.remove(this)\n        map.postUpdateSnapshot()\n    }\n\n    override fun update() {\n        map.postUpdateSnapshot()\n    }\n\n    override fun setDraggable(drag: Boolean) {\n        Log.d(TAG, \"setDraggable: not available in lite mode\")\n    }\n\n    override fun isDraggable(): Boolean {\n        Log.d(TAG, \"isDraggable: markers are never draggable in lite mode\")\n        return false\n    }\n\n    override fun setFlat(flat: Boolean) {\n        Log.d(TAG, \"setFlat: not available in lite mode\")\n    }\n\n    override fun isFlat(): Boolean {\n        Log.d(TAG, \"isFlat: markers in lite mode can never be flat\")\n        return false\n    }\n\n    override fun setRotation(rotation: Float) {\n        Log.d(TAG, \"setRotation: not available in lite mode\")\n    }\n\n    override fun getRotation(): Float {\n        Log.d(TAG, \"setRotation: markers in lite mode can never be rotated\")\n        return 0f\n    }\n\n    override fun setInfoWindowAnchor(x: Float, y: Float) {\n        infoWindowAnchor = floatArrayOf(x, y)\n        map.currentInfoWindow?.update()\n    }\n\n    companion object {\n        private val TAG = \"GmsMapMarkerLite\"\n    }\n}"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Markup.kt",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 org.microg.gms.maps.mapbox.model\n\nimport android.util.Log\nimport com.mapbox.mapboxsdk.plugins.annotation.Annotation\nimport com.mapbox.mapboxsdk.plugins.annotation.AnnotationManager\nimport com.mapbox.mapboxsdk.plugins.annotation.Options\n\ninterface Markup<T : Annotation<*>, S : Options<T>> {\n    var annotation: T?\n    val annotationOptions: S\n    var removed: Boolean\n\n    fun update(manager: AnnotationManager<*, T, S, *, *, *>) {\n        synchronized(this) {\n            if (removed && annotation != null) {\n                manager.delete(annotation)\n                annotation = null\n            } else if (annotation != null) {\n                manager.update(annotation)\n            } else if (!removed) {\n                annotation = manager.create(annotationOptions)\n            }\n        }\n    }\n\n    companion object {\n        private val TAG = \"GmsMapMarkup\"\n    }\n}"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Polygon.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2019 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.maps.mapbox.model\n\nimport android.os.Parcel\nimport android.util.Log\nimport androidx.annotation.CallSuper\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.ObjectWrapper\nimport com.google.android.gms.maps.model.LatLng\nimport com.google.android.gms.maps.model.PatternItem\nimport com.google.android.gms.maps.model.PolygonOptions\nimport com.google.android.gms.maps.model.PolylineOptions\nimport com.google.android.gms.maps.model.internal.IPolygonDelegate\nimport com.mapbox.mapboxsdk.plugins.annotation.Fill\nimport com.mapbox.mapboxsdk.plugins.annotation.FillOptions\nimport com.mapbox.mapboxsdk.utils.ColorUtils\nimport org.microg.gms.maps.mapbox.GoogleMapImpl\nimport org.microg.gms.maps.mapbox.LiteGoogleMapImpl\nimport org.microg.gms.maps.mapbox.utils.toMapbox\nimport org.microg.gms.utils.warnOnTransactionIssues\n\nabstract class AbstractPolygon(private val id: String, options: PolygonOptions) : IPolygonDelegate.Stub() {\n    internal var points = ArrayList(options.points.orEmpty())\n    internal var holes: List<List<LatLng>> = ArrayList(options.holes.map { ArrayList(it.orEmpty()) })\n    internal var fillColor = options.fillColor\n    internal var strokeColor = options.strokeColor\n    internal var strokeWidth = options.strokeWidth\n    internal var strokeJointType = options.strokeJointType\n    internal var strokePattern = ArrayList(options.strokePattern.orEmpty())\n    internal var visible: Boolean = options.isVisible\n    internal var clickable: Boolean = options.isClickable\n    internal var tag: IObjectWrapper? = null\n\n    val annotationOptions: FillOptions\n        get() = FillOptions()\n            .withLatLngs(mutableListOf(points.map { it.toMapbox() }).plus(holes.map { it.map { it.toMapbox() } }))\n            .withFillColor(ColorUtils.colorToRgbaString(fillColor))\n            .withFillOpacity(if (visible) 1f else 0f)\n\n    internal abstract val strokes: MutableList<out AbstractPolylineImpl>\n\n    internal abstract fun update()\n\n    @CallSuper\n    override fun remove() {\n        for (stroke in strokes) stroke.remove()\n    }\n\n    override fun getId(): String = id\n\n    override fun setPoints(points: List<LatLng>) {\n        this.points = ArrayList(points)\n        strokes[0].setPoints(points)\n        update()\n    }\n\n    override fun getPoints(): List<LatLng> = points\n\n    internal abstract fun addPolyline(id: String, options: PolylineOptions)\n\n    override fun setHoles(holes: List<Any?>?) {\n        this.holes = if (holes == null) emptyList() else ArrayList(holes.mapNotNull { if (it is List<*>) it.mapNotNull { if (it is LatLng) it else null }.let { if (it.isNotEmpty()) it else null } else null })\n        while (strokes.size > this.holes.size + 1) {\n            val last = strokes.last()\n            last.remove()\n            strokes.remove(last)\n        }\n        strokes.forEachIndexed { idx, it -> if (idx > 0) it.points = this.holes[idx - 1] }\n        if (this.holes.size + 1 > strokes.size) {\n            try {\n                this.holes.subList(strokes.size, this.holes.size - 1).mapIndexed { idx, it ->\n                    addPolyline(\n                        \"$id-stroke-hole-${strokes.size + idx}\",\n                        PolylineOptions().color(strokeColor).width(strokeWidth).addAll(it)\n                    )\n                }\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n            }\n        }\n    }\n\n    override fun getHoles(): List<List<LatLng>> = holes\n\n\n    override fun setStrokeWidth(width: Float) {\n        strokeWidth = width\n        strokes.forEach { it.setWidth(width) }\n        update()\n    }\n\n    override fun getStrokeWidth(): Float = strokeWidth\n\n    override fun setStrokeColor(color: Int) {\n        strokeColor = color\n        strokes.forEach { it.setColor(color) }\n        update()\n    }\n\n    override fun getStrokeColor(): Int = strokeColor\n\n    override fun setFillColor(color: Int) {\n        fillColor = color\n        update()\n    }\n\n    override fun getFillColor(): Int = fillColor\n\n    override fun setZIndex(zIndex: Float) {\n        Log.d(TAG, \"unimplemented Method: setZIndex\")\n    }\n\n    override fun getZIndex(): Float {\n        Log.d(TAG, \"unimplemented Method: getZIndex\")\n        return 0f\n    }\n\n    override fun setVisible(visible: Boolean) {\n        this.visible = visible\n        update()\n    }\n\n    override fun isVisible(): Boolean = visible\n\n    override fun setGeodesic(geod: Boolean) {\n        Log.d(TAG, \"unimplemented Method: setGeodesic\")\n    }\n\n    override fun isGeodesic(): Boolean {\n        Log.d(TAG, \"unimplemented Method: isGeodesic\")\n        return false\n    }\n\n    override fun setClickable(click: Boolean) {\n        clickable = click\n    }\n\n    override fun isClickable(): Boolean = clickable\n\n    override fun setStrokeJointType(type: Int) {\n        strokeJointType = type\n        update()\n    }\n\n    override fun getStrokeJointType(): Int = strokeJointType\n\n    override fun setStrokePattern(items: MutableList<PatternItem>?) {\n        strokePattern = ArrayList(items.orEmpty())\n        update()\n    }\n\n    override fun getStrokePattern(): MutableList<PatternItem> = strokePattern\n\n    override fun setTag(obj: IObjectWrapper?) {\n        tag = obj\n    }\n\n    override fun getTag(): IObjectWrapper = tag ?: ObjectWrapper.wrap(null)\n\n    override fun equalsRemote(other: IPolygonDelegate?): Boolean = equals(other)\n\n    override fun hashCodeRemote(): Int = hashCode()\n\n    override fun hashCode(): Int {\n        return id.hashCode()\n    }\n\n    override fun equals(other: Any?): Boolean {\n        if (other is AbstractPolygon) {\n            return other.id == id\n        }\n        return false\n    }\n\n    override fun toString(): String {\n        return id\n    }\n\n    companion object {\n        private val TAG = \"GmsMapAbstractPolygon\"\n    }\n}\n\nclass PolygonImpl(private val map: GoogleMapImpl, id: String, options: PolygonOptions) :\n    AbstractPolygon(id, options), Markup<Fill, FillOptions> {\n\n\n    override val strokes = (listOf(\n        PolylineImpl(\n            map, \"$id-stroke-main\", PolylineOptions().color(strokeColor).width(strokeWidth).addAll(\n                (points + points.firstOrNull()).filterNotNull()\n            )\n        )\n    ) + holes.mapIndexed { idx, holePoints ->\n        PolylineImpl(\n            map, \"$id-stroke-hole-$idx\", PolylineOptions().color(strokeColor).width(strokeWidth).addAll(\n                (holePoints + holePoints.firstOrNull()).filterNotNull()\n            )\n        )\n    }).toMutableList()\n\n    override var annotation: Fill? = null\n    override var removed: Boolean = false\n\n    override fun remove() {\n        removed = true\n        map.fillManager?.let { update(it) }\n        super.remove()\n    }\n\n    override fun update() {\n        annotation?.let {\n            it.latLngs = mutableListOf(points.map { it.toMapbox() }).plus(holes.map { it.map { it.toMapbox() } })\n            it.setFillColor(fillColor)\n            it.fillOpacity = if (visible) 1f else 0f\n            it.latLngs = mutableListOf(points.map { it.toMapbox() }).plus(this.holes.map { it.map { it.toMapbox() } })\n        }\n        map.fillManager?.let { update(it) }\n    }\n\n    override fun addPolyline(id: String, options: PolylineOptions) {\n        strokes.add(PolylineImpl(map, id, options))\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = warnOnTransactionIssues(code, reply, flags) { super.onTransact(code, data, reply, flags) }\n\n    companion object {\n        private val TAG = \"GmsMapPolygon\"\n    }\n}\n\nclass LitePolygonImpl(id: String, options: PolygonOptions, private val map: LiteGoogleMapImpl) : AbstractPolygon(id, options) {\n\n    override val strokes: MutableList<AbstractPolylineImpl> = (listOf(\n        LitePolylineImpl(\n            map, \"$id-stroke-main\", PolylineOptions().color(strokeColor).width(strokeWidth).addAll(\n                (points + points.firstOrNull()).filterNotNull()\n            )\n        )\n    ) + holes.mapIndexed { idx, holePoints ->\n        LitePolylineImpl(\n            map, \"$id-stroke-hole-$idx\", PolylineOptions().color(strokeColor).width(strokeWidth).addAll(\n                (holePoints + holePoints.firstOrNull()).filterNotNull()\n            )\n        )\n    }).toMutableList()\n\n\n    override fun remove() {\n        super.remove()\n        map.polygons.remove(this)\n        map.postUpdateSnapshot()\n    }\n\n    override fun update() {\n        map.postUpdateSnapshot()\n    }\n\n    override fun addPolyline(id: String, options: PolylineOptions) {\n        strokes.add(LitePolylineImpl(map, id, options))\n    }\n}"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Polyline.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2019 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.maps.mapbox.model\n\nimport android.os.Parcel\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.ObjectWrapper\nimport com.google.android.gms.maps.model.Cap\nimport com.google.android.gms.maps.model.LatLng\nimport com.google.android.gms.maps.model.PatternItem\nimport com.google.android.gms.maps.model.internal.IPolylineDelegate\nimport com.mapbox.mapboxsdk.plugins.annotation.Line\nimport com.mapbox.mapboxsdk.plugins.annotation.LineOptions\nimport com.mapbox.mapboxsdk.utils.ColorUtils\nimport org.microg.gms.maps.mapbox.GoogleMapImpl\nimport org.microg.gms.maps.mapbox.LiteGoogleMapImpl\nimport org.microg.gms.maps.mapbox.utils.toMapbox\nimport org.microg.gms.utils.warnOnTransactionIssues\nimport com.google.android.gms.maps.model.PolylineOptions as GmsLineOptions\n\nabstract class AbstractPolylineImpl(private val id: String, options: GmsLineOptions, private val dpiFactor: Function0<Float>) : IPolylineDelegate.Stub() {\n    internal var points: List<LatLng> = ArrayList(options.points)\n    internal var width = options.width\n    internal var jointType = options.jointType\n    internal var pattern = ArrayList(options.pattern.orEmpty())\n    internal var color = options.color\n    internal var visible: Boolean = options.isVisible\n    internal var clickable: Boolean = options.isClickable\n    internal var tag: IObjectWrapper? = null\n    internal var startCap: Cap = options.startCap\n    internal var endCap: Cap = options.endCap\n    internal var geodesic = options.isGeodesic\n    internal var zIndex = options.zIndex\n\n    val annotationOptions: LineOptions\n        get() = LineOptions()\n            .withLatLngs(points.map { it.toMapbox() })\n            .withLineWidth(width / dpiFactor.invoke())\n            .withLineColor(ColorUtils.colorToRgbaString(color))\n            .withLineOpacity(if (visible) 1f else 0f)\n\n    internal abstract fun update()\n\n    override fun getId(): String = id\n\n    override fun setPoints(points: List<LatLng>) {\n        this.points = ArrayList(points)\n        update()\n    }\n\n    override fun getPoints(): List<LatLng> = points\n\n    override fun setWidth(width: Float) {\n        this.width = width\n        update()\n    }\n\n    override fun getWidth(): Float = width\n\n    override fun setColor(color: Int) {\n        this.color = color\n        update()\n    }\n\n    override fun getColor(): Int = color\n\n    override fun setZIndex(zIndex: Float) {\n        this.zIndex = zIndex\n    }\n\n    override fun getZIndex(): Float = zIndex\n\n    override fun setVisible(visible: Boolean) {\n        this.visible = visible\n        update()\n    }\n\n    override fun isVisible(): Boolean = visible\n\n    override fun setGeodesic(geod: Boolean) {\n        this.geodesic = geod\n    }\n\n    override fun isGeodesic(): Boolean = geodesic\n\n    override fun setStartCap(startCap: Cap) {\n        this.startCap = startCap\n    }\n\n    override fun getStartCap(): Cap = startCap\n\n    override fun setEndCap(endCap: Cap) {\n        this.endCap = endCap\n    }\n\n    override fun getEndCap(): Cap = endCap\n\n    override fun equalsRemote(other: IPolylineDelegate?): Boolean = equals(other)\n\n    override fun hashCodeRemote(): Int = hashCode()\n\n    override fun setClickable(clickable: Boolean) {\n        this.clickable = clickable\n    }\n\n    override fun isClickable(): Boolean = clickable\n\n    override fun setJointType(jointType: Int) {\n        this.jointType = jointType\n    }\n\n    override fun getJointType(): Int = jointType\n\n    override fun setPattern(pattern: MutableList<PatternItem>?) {\n        this.pattern = ArrayList(pattern.orEmpty())\n    }\n\n    override fun getPattern(): MutableList<PatternItem> = pattern\n\n    override fun setTag(tag: IObjectWrapper?) {\n        this.tag = tag\n    }\n\n    override fun getTag(): IObjectWrapper = tag ?: ObjectWrapper.wrap(null)\n\n    override fun hashCode(): Int {\n        return id.hashCode()\n    }\n\n    override fun equals(other: Any?): Boolean {\n        if (other is AbstractPolylineImpl) {\n            return other.id == id\n        }\n        return false\n    }\n\n    override fun toString(): String {\n        return id\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n\n    companion object {\n        const val TAG = \"GmsPolylineAbstract\"\n    }\n}\n\nclass PolylineImpl(private val map: GoogleMapImpl, id: String, options: GmsLineOptions) :\n    AbstractPolylineImpl(id, options, { map.dpiFactor }), Markup<Line, LineOptions> {\n\n    override var annotation: Line? = null\n    override var removed: Boolean = false\n\n    override fun remove() {\n        removed = true\n        map.lineManager?.let { update(it) }\n    }\n\n    override fun update() {\n        annotation?.apply {\n            latLngs = points.map { it.toMapbox() }\n            lineWidth = width / map.dpiFactor\n            setLineColor(color)\n            lineOpacity = if (visible) 1f else 0f\n        }\n        map.lineManager?.let { update(it) }\n    }\n\n    companion object {\n        private val TAG = \"GmsMapPolyline\"\n    }\n}\n\nclass LitePolylineImpl(private val map: LiteGoogleMapImpl, id: String, options: GmsLineOptions) :\n    AbstractPolylineImpl(id, options, { map.dpiFactor }) {\n    override fun remove() {\n        map.polylines.remove(this)\n        map.postUpdateSnapshot()\n    }\n\n    override fun update() {\n        map.postUpdateSnapshot()\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/TileOverlay.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.maps.mapbox.model\n\nimport android.os.Parcel\nimport android.util.Log\nimport com.google.android.gms.maps.model.TileOverlayOptions\nimport com.google.android.gms.maps.model.internal.ITileOverlayDelegate\nimport org.microg.gms.maps.mapbox.GoogleMapImpl\nimport org.microg.gms.utils.warnOnTransactionIssues\n\nclass TileOverlayImpl(private val map: GoogleMapImpl, private val id: String, options: TileOverlayOptions) : ITileOverlayDelegate.Stub() {\n    private var zIndex = options.zIndex\n    private var visible = options.isVisible\n    private var fadeIn = options.fadeIn\n    private var transparency = options.transparency\n\n    override fun remove() {\n        Log.d(TAG, \"Not yet implemented: remove\")\n    }\n\n    override fun clearTileCache() {\n        Log.d(TAG, \"Not yet implemented: clearTileCache\")\n    }\n\n    override fun getId(): String = id\n\n    override fun setZIndex(zIndex: Float) {\n        this.zIndex = zIndex\n    }\n\n    override fun getZIndex(): Float = zIndex\n\n    override fun setVisible(visible: Boolean) {\n        this.visible = visible\n    }\n\n    override fun isVisible(): Boolean = visible\n\n    override fun equalsRemote(other: ITileOverlayDelegate?): Boolean = this == other\n\n    override fun hashCodeRemote(): Int = hashCode()\n\n    override fun setFadeIn(fadeIn: Boolean) {\n        this.fadeIn = fadeIn\n    }\n\n    override fun getFadeIn(): Boolean = fadeIn\n\n    override fun setTransparency(transparency: Float) {\n        this.transparency = transparency\n    }\n\n    override fun getTransparency(): Float = transparency\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n\n    companion object {\n        private const val TAG = \"TileOverlay\"\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/utils/MapContext.kt",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 org.microg.gms.maps.mapbox.utils\n\nimport android.content.Context\nimport android.content.ContextWrapper\nimport android.content.Intent\nimport android.content.SharedPreferences\nimport android.view.LayoutInflater\nimport org.microg.gms.common.Constants\nimport java.io.File\n\nclass MapContext(private val context: Context) : ContextWrapper(context.createPackageContext(Constants.GMS_PACKAGE_NAME, Context.CONTEXT_INCLUDE_CODE or Context.CONTEXT_IGNORE_SECURITY)) {\n    private var layoutInflater: LayoutInflater? = null\n    private val appContext: Context\n        get() = context.applicationContext ?: context\n\n    override fun getApplicationContext(): Context {\n        return this\n    }\n\n    override fun getCacheDir(): File {\n        val cacheDir = File(appContext.cacheDir, \"com.google.android.gms\")\n        cacheDir.mkdirs()\n        return cacheDir\n    }\n\n    override fun getFilesDir(): File {\n        val filesDir = File(appContext.filesDir, \"com.google.android.gms\")\n        filesDir.mkdirs()\n        return filesDir\n    }\n\n    override fun getPackageName(): String {\n        return appContext.packageName\n    }\n\n    override fun getClassLoader(): ClassLoader {\n        return MapContext::class.java.classLoader!!\n    }\n\n    override fun getSharedPreferences(name: String?, mode: Int): SharedPreferences {\n        return appContext.getSharedPreferences(\"com.google.android.gms_$name\", mode)\n    }\n\n    override fun getSystemService(name: String): Any? {\n        if (name == Context.LAYOUT_INFLATER_SERVICE) {\n            if (layoutInflater == null) {\n                layoutInflater = super.getSystemService(name) as LayoutInflater\n                layoutInflater?.cloneInContext(this)?.let { layoutInflater = it }\n            }\n            if (layoutInflater != null) {\n                return layoutInflater\n            }\n        }\n        return context.getSystemService(name)\n    }\n\n    override fun startActivity(intent: Intent?) {\n        intent?.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)\n        context.startActivity(intent)\n    }\n\n    companion object {\n        val TAG = \"GmsMapContext\"\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/utils/MultiArchLoader.kt",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 org.microg.gms.maps.mapbox.utils\n\nimport android.annotation.SuppressLint\nimport android.content.Context\nimport android.content.pm.ApplicationInfo\nimport android.util.Log\nimport com.mapbox.mapboxsdk.LibraryLoader\nimport org.microg.gms.common.Constants\nimport org.microg.gms.common.PackageUtils\nimport java.io.*\nimport java.util.zip.ZipFile\n\nclass MultiArchLoader(private val mapContext: Context, private val appContext: Context) : LibraryLoader() {\n    @SuppressLint(\"UnsafeDynamicallyLoadedCode\")\n    override fun load(name: String) {\n        try {\n            val otherAppInfo = mapContext.packageManager.getApplicationInfo(appContext.packageName, 0)\n            var primaryCpuAbi = ApplicationInfo::class.java.getField(\"primaryCpuAbi\").get(otherAppInfo) as String?\n            if (primaryCpuAbi == \"armeabi\") {\n                primaryCpuAbi = \"armeabi-v7a\"\n            }\n            if (primaryCpuAbi != null) {\n                val path = \"lib/$primaryCpuAbi/lib$name.so\"\n                val cacheFile = File(\"${appContext.cacheDir.absolutePath}/.gmscore/$path\")\n                cacheFile.parentFile?.mkdirs()\n                val cacheFileStamp = File(\"${appContext.cacheDir.absolutePath}/.gmscore/$path.stamp\")\n                val cacheVersion = kotlin.runCatching { cacheFileStamp.readText() }.getOrNull()\n                // TODO: Use better version indicator\n                val mapVersion = PackageUtils.versionName(mapContext, Constants.GMS_PACKAGE_NAME)\n                val apkFile = File(mapContext.packageCodePath)\n                if (!cacheFile.exists() || cacheVersion == null || cacheVersion != mapVersion) {\n                    val zipFile = ZipFile(apkFile)\n                    val entry = zipFile.getEntry(path)\n                    if (entry != null) {\n                        copyInputStream(zipFile.getInputStream(entry), FileOutputStream(cacheFile))\n                    } else {\n                        Log.d(TAG, \"Can't load native library: $path does not exist in $apkFile\")\n                    }\n                    cacheFileStamp.writeText(mapVersion.toString())\n                }\n                Log.d(TAG, \"Loading $name from ${cacheFile.getPath()}\")\n                System.load(cacheFile.absolutePath)\n                return\n            }\n        } catch (e: Exception) {\n            Log.w(TAG, e)\n        }\n        Log.d(TAG, \"Loading native $name\")\n        System.loadLibrary(name)\n    }\n\n    @Throws(IOException::class)\n    private fun copyInputStream(inp: InputStream, out: OutputStream) {\n        val buffer = ByteArray(1024)\n        var len: Int = inp.read(buffer)\n        while (len >= 0) {\n            out.write(buffer, 0, len)\n            len = inp.read(buffer)\n        }\n\n        inp.close()\n        out.close()\n    }\n\n    companion object {\n        private val TAG = \"GmsMultiArchLoader\"\n    }\n\n}\n"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/utils/typeConverter.kt",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 org.microg.gms.maps.mapbox.utils\n\nimport android.os.Bundle\nimport android.util.Log\nimport com.google.android.gms.maps.internal.ICancelableCallback\nimport com.mapbox.geojson.Point\nimport com.mapbox.mapboxsdk.camera.CameraPosition\nimport com.mapbox.mapboxsdk.geometry.LatLng\nimport com.mapbox.mapboxsdk.geometry.LatLngBounds\nimport com.mapbox.mapboxsdk.geometry.VisibleRegion\nimport com.mapbox.mapboxsdk.maps.MapboxMap\nimport org.microg.gms.maps.mapbox.TAG\nimport com.google.android.gms.maps.model.CameraPosition as GmsCameraPosition\nimport com.google.android.gms.maps.model.LatLng as GmsLatLng\nimport com.google.android.gms.maps.model.LatLngBounds as GmsLatLngBounds\nimport com.google.android.gms.maps.model.VisibleRegion as GmsVisibleRegion\n\nfun GmsLatLng.toMapbox(): LatLng =\n        LatLng(latitude, longitude)\n\nfun GmsLatLng.toPoint() = Point.fromLngLat(latitude, longitude)\n\nfun GmsLatLngBounds.toMapbox(): LatLngBounds =\n    LatLngBounds.from(this.northeast.latitude, this.northeast.longitude + if (this.northeast.longitude < this.southwest.longitude) 360.0 else 0.0, this.southwest.latitude, this.southwest.longitude)\n\nfun GmsCameraPosition.toMapbox(): CameraPosition =\n        CameraPosition.Builder()\n                .target(target.takeIf { it.longitude.isFinite() && it.latitude.isFinite() }?.toMapbox())\n                .zoom(zoom.toDouble() - 1.0)\n                .tilt(tilt.toDouble())\n                .bearing(bearing.toDouble())\n                .build()\n\nfun ICancelableCallback.toMapbox(): MapboxMap.CancelableCallback =\n        object : MapboxMap.CancelableCallback {\n            override fun onFinish() = this@toMapbox.onFinish()\n            override fun onCancel() = this@toMapbox.onCancel()\n        }\n\n\nfun Bundle.toMapbox(): Bundle {\n    val newBundle = Bundle(this)\n    val oldLoader = newBundle.classLoader\n    newBundle.classLoader = GmsLatLng::class.java.classLoader\n    for (key in newBundle.keySet()) {\n        val value = newBundle.get(key)\n        when (value) {\n            is GmsCameraPosition -> newBundle.putParcelable(key, value.toMapbox())\n            is GmsLatLng -> newBundle.putParcelable(key, value.toMapbox())\n            is GmsLatLngBounds -> newBundle.putParcelable(key, value.toMapbox())\n            is Bundle -> newBundle.putBundle(key, value.toMapbox())\n        }\n    }\n    newBundle.classLoader = oldLoader\n    return newBundle\n}\n\nfun LatLng.toGms(): GmsLatLng = GmsLatLng(latitude, longitude)\n\nfun LatLng.toPoint(): Point = Point.fromLngLat(latitude, longitude)\n\nfun LatLngBounds.toGms(): GmsLatLngBounds = GmsLatLngBounds(southWest.toGms(), northEast.toGms())\n\nfun CameraPosition.toGms(): GmsCameraPosition =\n        GmsCameraPosition(target?.toGms(), zoom.toFloat() + 1.0f, tilt.toFloat(), bearing.toFloat())\n\nfun Bundle.toGms(): Bundle {\n    val newBundle = Bundle(this)\n    val oldLoader = newBundle.classLoader\n    newBundle.classLoader = LatLng::class.java.classLoader\n    for (key in newBundle.keySet()) {\n        val value = newBundle.get(key)\n        when (value) {\n            is CameraPosition -> newBundle.putParcelable(key, value.toGms())\n            is LatLng -> newBundle.putParcelable(key, value.toGms())\n            is LatLngBounds -> newBundle.putParcelable(key, value.toGms())\n            is Bundle -> newBundle.putBundle(key, value.toGms())\n        }\n    }\n    newBundle.classLoader = oldLoader\n    return newBundle\n}\n\nfun VisibleRegion.toGms(): GmsVisibleRegion =\n        GmsVisibleRegion(nearLeft?.toGms(), nearRight?.toGms(), farLeft?.toGms(), farRight?.toGms(), latLngBounds.toGms())\n"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/res/drawable/location_dot.xml",
    "content": "<vector android:height=\"17.987968dp\" android:viewportHeight=\"149.5\"\n    android:viewportWidth=\"149.6\" android:width=\"18dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"#39ADCC\" android:pathData=\"M74.8,74.8m-69.8,0a69.8,69.8 0,1 1,139.6 0a69.8,69.8 0,1 1,-139.6 0\"/>\n    <path android:fillColor=\"#FFFFFF\" android:pathData=\"M74.8,149.5C33.6,149.5 0,116 0,74.7 0,33.4 33.6,0 74.8,0c41.2,0 74.8,33.5 74.8,74.8 0,41.3 -33.5,74.7 -74.8,74.7zM74.8,10c-35.7,0 -64.8,29 -64.8,64.8 0,35.7 29,64.8 64.8,64.8 35.7,0 64.8,-29 64.8,-64.8C139.6,39.1 110.5,10 74.8,10Z\"/>\n</vector>\n"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/res/drawable/maps_default_bubble.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Based on https://stackoverflow.com/a/27607600/20044811 by TTransmit, CC BY-SA 3.0 -->\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\" >\n\n    <item\n        android:bottom=\"8dp\"\n        tools:width=\"100dp\"\n        tools:height=\"50dp\">\n        <shape android:shape=\"rectangle\">\n            <solid android:color=\"#ffffff\"/>\n            <corners\n                android:topLeftRadius=\"2dp\"\n                android:topRightRadius=\"2dp\"\n                android:bottomRightRadius=\"2dp\"\n                android:bottomLeftRadius=\"2dp\"/>\n        </shape>\n    </item>\n\n    <item\n        android:gravity=\"bottom|center_horizontal\">\n        <vector\n            android:width=\"8dp\"\n            android:height=\"8dp\"\n            android:viewportWidth=\"50.0\"\n            android:viewportHeight=\"50.0\">\n            <path\n                android:pathData=\"M25,50 50,0 0,0z\"\n                android:fillColor=\"#ffffff\"/>\n        </vector>\n    </item>\n\n</layer-list>"
  },
  {
    "path": "play-services-maps/core/mapbox/src/main/res/layout/maps_default_bubble_layout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout 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:paddingBottom=\"12dp\"\n    android:paddingTop=\"4dp\"\n    android:paddingLeft=\"4dp\"\n    android:paddingRight=\"4dp\"\n    android:background=\"@drawable/maps_default_bubble\"\n    android:elevation=\"4dp\">\n\n    <TextView\n        android:id=\"@+id/title\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center_horizontal\"\n        android:textStyle=\"bold\"\n        android:textColor=\"?android:attr/textColorPrimary\"\n        android:visibility=\"gone\"\n        tools:text=\"Melbourne\"\n        tools:visibility=\"visible\" />\n\n    <TextView\n        android:id=\"@+id/snippet\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center_horizontal\"\n        android:visibility=\"gone\"\n        tools:text=\"Population: 4,137,400\"\n        tools:visibility=\"visible\" />\n\n</LinearLayout>"
  },
  {
    "path": "play-services-maps/core/vtm/build.gradle",
    "content": "/*\n * Copyright 2013-2019 microG Project Team\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\napply plugin: \"com.android.library\"\n\ndependencies {\n    implementation project(\":play-services-maps\")\n\n    implementation \"org.microg:vtm-android:0.9.1-mod\"\n    implementation \"org.microg:vtm-android:0.9.1-mod:natives-armeabi\"\n    implementation \"org.microg:vtm-android:0.9.1-mod:natives-armeabi-v7a\"\n    implementation \"org.microg:vtm-android:0.9.1-mod:natives-arm64-v8a\"\n    implementation \"org.microg:vtm-android:0.9.1-mod:natives-x86\"\n    implementation \"org.microg:vtm-android:0.9.1-mod:natives-x86_64\"\n    implementation \"org.microg:vtm-extras:0.9.1-mod\"\n    implementation \"org.microg:vtm-jts:0.9.1-mod\"\n    implementation project(\":play-services-maps-core-vtm-microg-theme\")\n\n    implementation \"androidx.appcompat:appcompat:$appcompatVersion\"\n}\n\ndef execResult(...args) {\n    def stdout = new ByteArrayOutputStream()\n    exec {\n        commandLine args\n        standardOutput = stdout\n    }\n    return stdout.toString().trim()\n}\n\nandroid {\n    namespace \"org.microg.gms.maps.vtm\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    defaultConfig {\n        versionName version\n\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n\n        ndk {\n            abiFilters \"armeabi\", \"armeabi-v7a\", \"arm64-v8a\", \"x86\", \"x86_64\"\n        }\n    }\n\n    lintOptions {\n        disable \"MissingTranslation\", \"InvalidPackage\", \"BatteryLife\", \"ImpliedQuantity\", \"MissingQuantity\"\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled true\n        }\n    }\n\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n}\n\nif (file(\"user.gradle\").exists()) {\n    apply from: \"user.gradle\"\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/microg-theme/build.gradle",
    "content": "apply plugin: 'java'\n\ndependencies {\n    implementation \"org.microg:vtm:0.9.1-mod\"\n}\n\nsourceSets {\n    main {\n        java {\n            srcDir 'src'\n        }\n        resources {\n            srcDir 'resources'\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/microg-theme/resources/assets/styles/microg.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<rendertheme base-text-scale=\"1.25\" map-background=\"#EAEAEA\"\n             version=\"1\" xmlns=\"http://opensciencemap.org/rendertheme\"\n             xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n             xsi:schemaLocation=\"http://opensciencemap.org/rendertheme https://raw.githubusercontent.com/mapsforge/vtm/master/resources/rendertheme.xsd\">\n\n    <style-line cap=\"butt\" fix=\"true\" id=\"fix\" width=\"1.0\"/>\n\n    <style-text fill=\"#AA333333\" id=\"road:z12\" k=\"name\" priority=\"2\" size=\"16\" stroke=\"#eeeeee\"\n                stroke-width=\"5.0\"/>\n    <style-text fill=\"#AA333333\" id=\"road:z13\" k=\"name\" priority=\"3\" size=\"16\" stroke=\"#eeeeee\"\n                stroke-width=\"5.0\"/>\n    <style-text fill=\"#AA333333\" id=\"road:z14\" k=\"name\" priority=\"4\" size=\"16\" stroke=\"#eeeeee\"\n                stroke-width=\"5.0\"/>\n    <style-text fill=\"#AA333333\" id=\"road:z16\" k=\"name\" priority=\"6\" size=\"16\" stroke=\"#eeeeee\"\n                stroke-width=\"5.0\"/>\n    <style-text fill=\"#FF783B03\" id=\"road:orange\" k=\"name\" priority=\"6\" size=\"16\" stroke=\"#eeeeee\"\n                stroke-width=\"5.0\"/>\n\n    <style-text style=\"bold\" caption=\"true\" fill=\"#000000\" id=\"park\" k=\"name\" priority=\"0\"\n                size=\"17\" stroke=\"#eeeeee\" stroke-width=\"5.0\"/>\n\n    <style-text caption=\"true\" dy=\"-14\" fill=\"#00afff\" id=\"transit\" k=\"name\" priority=\"5\" size=\"16\"\n                stroke=\"#eeeeee\" stroke-width=\"5.0\"/>\n    <style-text caption=\"true\" dy=\"-10\" fill=\"#00afff\" id=\"transit-small\" k=\"name\" priority=\"5\"\n                size=\"16\" stroke=\"#eeeeee\" stroke-width=\"5.0\"/>\n\n    <style-area fill=\"#33AA0000\" id=\"debug\" stroke=\"#FF0000\" stroke-width=\"1\"/>\n    <style-line id=\"debug\" stroke=\"#00FF00\"/>\n\n    <style-line id=\"building\" stroke=\"#dcdcdc\" use=\"fix\" width=\"1.0\"/>\n    <style-line id=\"building-poi\" stroke=\"#EBD5AA\" use=\"fix\" width=\"1.0\"/>\n    <style-line id=\"sub-building\" stipple=\"10\" stipple-stroke=\"#00000000\" stipple-width=\"1.0\"\n                use=\"building\"/>\n    <style-area fill=\"#fff2f2f2\" id=\"building\" mesh=\"true\"/>\n    <style-area fill=\"#ffFAEDD4\" id=\"building-poi\" mesh=\"true\"/>\n\n    <style-line cap=\"square\" id=\"road-fix\" use=\"fix\"/>\n\n    <style-line id=\"tertiary:z12\" stroke=\"#ffffff\" use=\"fix\" width=\"1.0\"/>\n    <style-line id=\"secondary:z12\" stroke=\"#ffffff\" use=\"fix\" width=\"1.0\"/>\n    <style-line id=\"trunk:z12\" stroke=\"#FFF1B9\" use=\"fix\" width=\"1.0\"/>\n    <style-line id=\"primary:z12\" stroke=\"#ffebaf\" use=\"fix\" width=\"1.0\"/>\n    <style-line id=\"motorway_link:z12\" stroke=\"#fde7c4\" use=\"fix\" width=\"1.0\"/>\n    <style-line id=\"motorway:z12\" stroke=\"#fed89d\" use=\"fix\" width=\"1.5\"/>\n\n    <style-line id=\"walkway:z18\" stroke=\"#ffffff\" width=\"0.3\"/>\n    <style-line id=\"pedestrian:z18\" stroke=\"#ffffff\" width=\"0.7\"/>\n    <style-line id=\"residential:z18\" stroke=\"#ffffff\" width=\"1.0\"/>\n    <style-line id=\"tertiary:z18\" stroke=\"#ffffff\" width=\"1.2\"/>\n    <style-line id=\"secondary:z18\" stroke=\"#ffffff\" width=\"1.4\"/>\n    <style-line id=\"trunk:z18\" stroke=\"#FFF1B9\" width=\"1.6\"/>\n    <style-line id=\"primary:z18\" stroke=\"#ffebaf\" width=\"1.6\"/>\n    <style-line id=\"motorway_link:z18\" stroke=\"#fde7c4\" width=\"1.1\"/>\n    <style-line id=\"motorway:z18\" stroke=\"#fed89d\" width=\"2.0\"/>\n\n    <style-line fix=\"true\" id=\"river:z14\" stroke=\"#A3CCFF\" width=\"1.5\"/>\n    <style-line fix=\"true\" id=\"river:z18\" stroke=\"#A3CCFF\" width=\"2.5\"/>\n    <style-line fix=\"true\" id=\"waterstream:z14\" stroke=\"#A3CCFF\" width=\"1.0\"/>\n    <style-line fix=\"true\" id=\"waterstream:z18\" stroke=\"#A3CCFF\" width=\"2.0\"/>\n\n    <style-area fill=\"#CBE6A3\" id=\"green\"/>\n    <style-area blend=\"10\" blend-fill=\"#D6E9B9\" fill=\"#D4E4C9\" id=\"lightgreen\"/>\n    <style-area blend=\"10\" blend-fill=\"#DDE6D5\" fill=\"#D4E4C9\" id=\"graygreen\"/>\n    <style-area blend=\"10\" blend-fill=\"#DAE8D1\" fill=\"#D4E4C9\" id=\"sportgreen\"/>\n    <style-area blend=\"17\" blend-fill=\"#EAEAEA\" fill=\"#EFE4D6\" id=\"city\"/>\n    <style-area fill=\"#CEE7A5\" id=\"national_park\"/>\n    <style-area fill=\"#F9EDF1\" id=\"medical\"/>\n    <style-area fill=\"#E4E4DF\" id=\"education\"/>\n    <style-area fill=\"#EAEAEA\" id=\"residential\"/>\n\n    <m closed=\"yes\" k=\"boundary\" v=\"administrative\">\n        <m k=\"place\" v=\"suburb\">\n            <area use=\"residential\"/>\n        </m>\n    </m>\n\n    <m closed=\"yes\" k=\"landuse\" v=\"residential|commercial\">\n        <area use=\"residential\"/>\n    </m>\n\n    <m closed=\"yes\" k=\"leisure\" v=\"playing_fields|pitch|sports_centre|stadium\">\n        <area use=\"sportgreen\"/>\n    </m>\n\n    <m closed=\"yes\" k=\"landuse\" v=\"forest\">\n        <area use=\"lightgreen\"/>\n    </m>\n\n    <m closed=\"yes\" k=\"leisure\" v=\"park|garden\">\n        <area use=\"lightgreen\"/>\n        <text use=\"park\"/>\n    </m>\n\n    <m closed=\"yes\" k=\"leisure\" v=\"golf_course|miniature_golf\">\n        <area use=\"graygreen\"/>\n    </m>\n\n    <m closed=\"yes\" k=\"landuse\" v=\"cemetery\">\n        <area use=\"lightgreen\"/>\n    </m>\n\n    <m closed=\"yes\" k=\"amenity\" v=\"grave_yard\">\n        <area use=\"lightgreen\"/>\n    </m>\n\n    <m closed=\"yes\" k=\"boundary\" v=\"national_park\">\n        <area use=\"national_park\"/>\n        <text use=\"park\"/>\n    </m>\n\n    <m closed=\"yes\" k=\"leisure\" v=\"nature_reserve\">\n        <area use=\"national_park\"/>\n        <text use=\"park\"/>\n    </m>\n\n    <m closed=\"yes\" k=\"landuse\" v=\"retail\">\n        <area use=\"city\"/>\n    </m>\n\n    <m closed=\"yes\" k=\"amenity\" v=\"marketplace\">\n        <area use=\"city\"/>\n    </m>\n\n    <m closed=\"yes\" k=\"highway\" v=\"pedestrian\">\n        <area use=\"city\"/>\n    </m>\n\n    <m closed=\"yes\" k=\"shop\" v=\"mall\">\n        <area use=\"city\"/>\n    </m>\n\n    <m closed=\"yes\" k=\"amenity\" v=\"college|university|school|kindergarten\">\n        <area use=\"education\"/>\n    </m>\n\n    <m closed=\"yes\" k=\"amenity\" v=\"hospital|clinic\">\n        <area use=\"medical\"/>\n    </m>\n\n    <m closed=\"no\" k=\"boundary\" v=\"administrative\">\n        <m k=\"admin_level\" v=\"1|2\">\n            <line fix=\"true\" stroke=\"#555555\" width=\"2.0\"/>\n        </m>\n        <m k=\"admin_level\" v=\"3|4\" zoom-min=\"7\">\n            <line fix=\"true\" stipple=\"20\" stipple-stroke=\"#00888888\" stroke=\"#88888888\"\n                  width=\"1.5\"/>\n        </m>\n    </m>\n\n    <m k=\"waterway\">\n        <m k=\"waterway\" v=\"stream|drain|ditch\">\n            <m zoom-max=\"15\">\n                <m k=\"tunnel\" v=\"~|no\">\n                    <line use=\"waterstream:z14\"/>\n                </m>\n                <m k=\"tunnel\" v=\"yes\">\n                    <line stipple=\"10\" stipple-stroke=\"#00000000\" stipple-width=\"1.0\"\n                          use=\"waterstream:z14\"/>\n                </m>\n            </m>\n            <m zoom-min=\"15\">\n                <m k=\"tunnel\" v=\"~|no\">\n                    <line use=\"waterstream:z18\"/>\n                </m>\n                <m k=\"tunnel\" v=\"yes\">\n                    <line stipple=\"10\" stipple-stroke=\"#00000000\" stipple-width=\"1.0\"\n                          use=\"waterstream:z14\"/>\n                </m>\n            </m>\n        </m>\n        <m k=\"waterway\" v=\"river|canal\">\n            <m zoom-max=\"15\" zoom-min=\"12\">\n                <m k=\"tunnel\" v=\"~|no\">\n                    <line use=\"river:z14\"/>\n                </m>\n                <m k=\"tunnel\" v=\"yes\">\n                    <line stipple=\"10\" stipple-stroke=\"#00000000\" stipple-width=\"1.0\"\n                          use=\"river:z14\"/>\n                </m>\n            </m>\n            <m zoom-min=\"15\">\n                <m k=\"tunnel\" v=\"~|no\">\n                    <line use=\"river:z18\"/>\n                </m>\n                <m k=\"tunnel\" v=\"yes\">\n                    <line stipple=\"10\" stipple-stroke=\"#00000000\" stipple-width=\"1.0\"\n                          use=\"river:z18\"/>\n                </m>\n            </m>\n        </m>\n    </m>\n\n    <m closed=\"yes\" k=\"natural\" v=\"water\">\n        <area fill=\"#A3CCFF\"/>\n    </m>\n\n    <m e=\"way\">\n        <outline-layer fix=\"true\" id=\"motorway:z12\" stroke=\"#7ac87800\" width=\"1.2\"/>\n        <outline-layer fix=\"true\" id=\"motorway_link:z12\" stroke=\"#47fea200\" width=\"0.8\"/>\n        <outline-layer fix=\"true\" id=\"trunk:z12\" stroke=\"#65ca9f00\" width=\"1.4\"/>\n        <outline-layer fix=\"true\" id=\"motorway:z18\" stroke=\"#7ac87800\" width=\"1.8\"/>\n        <outline-layer fix=\"true\" id=\"motorway_link:z18\" stroke=\"#47fea200\" width=\"1.2\"/>\n        <outline-layer fix=\"true\" id=\"trunk:z18\" stroke=\"#65ca9f00\" width=\"1.8\"/>\n        <!--<outline-layer id=\"primary\" stroke=\"#aa7f7700\" width=\"0.1\"/>-->\n\n        <m k=\"highway\">\n            <m k=\"area\" v=\"~|no|false\">\n                <m k=\"tunnel\" v=\"yes|true\">\n                    <m k=\"highway\" v=\"path|cycleway|footway|track|steps\">\n                        <line stipple=\"1\" stipple-stroke=\"#00000000\" use=\"walkway:z18\"/>\n                    </m>\n                    <m k=\"highway\" v=\"trunk_link|motorway_link\">\n                        <m zoom-max=\"13\">\n                            <line outline=\"motorway_link:z12\" stroke=\"#E0DEDA\"\n                                  use=\"motorway_link:z12\"/>\n                        </m>\n                        <m zoom-min=\"13\">\n                            <line outline=\"motorway_link:z18\" stroke=\"#E0DEDA\"\n                                  use=\"motorway_link:z18\"/>\n                        </m>\n                    </m>\n                    <m k=\"highway\" v=\"pedestrian\">\n                        <line fade=\"13\" stroke=\"#E0DEDA\" use=\"pedestrian:z18\"/>\n                    </m>\n                    <m k=\"highway\" v=\"residential|road|living_street|unclassified\">\n                        <line fade=\"13\" stroke=\"#E0DEDA\" use=\"residential:z18\"/>\n                    </m>\n                    <m k=\"highway\" v=\"tertiary|secondary_link\">\n                        <line stroke=\"#E0DEDA\" use=\"tertiary:z12\"/>\n                        <line stroke=\"#E0DEDA\" use=\"tertiary:z18\"/>\n                    </m>\n                    <m k=\"highway\" v=\"secondary|primary_link\">\n                        <line stroke=\"#E0DEDA\" use=\"secondary:z12\"/>\n                        <line stroke=\"#E0DEDA\" use=\"secondary:z18\"/>\n                    </m>\n                    <m k=\"highway\" v=\"trunk|primary\">\n                        <m zoom-max=\"13\">\n                            <line outline=\"trunk:z12\" stroke=\"#E0DEDA\" use=\"trunk:z12\"/>\n                        </m>\n                        <m zoom-min=\"13\">\n                            <line outline=\"trunk:z18\" stroke=\"#E0DEDA\" use=\"trunk:z18\"/>\n                        </m>\n                    </m>\n                    <m k=\"highway\" v=\"motorway\">\n                        <m zoom-max=\"13\">\n                            <line outline=\"motorway:z12\" stroke=\"#E0DEDA\" use=\"motorway:z12\"/>\n                        </m>\n                        <m zoom-min=\"13\">\n                            <line outline=\"motorway:z12\" stroke=\"#E0DEDA\" use=\"motorway:z18\"/>\n                        </m>\n                        <outline outline=\"motorway\"/>\n                    </m>\n                </m>\n\n                <m k=\"tunnel|bridge\" v=\"~|no\">\n                    <m k=\"highway\" v=\"service\">\n                        <m k=\"service\" v=\"driveway|alley\">\n                            <line use=\"walkway:z18\"/>\n                            <text use=\"road:z16\"/>\n                        </m>\n                    </m>\n                    <m k=\"highway\" v=\"path|cycleway|footway|track|steps\">\n                        <line use=\"walkway:z18\"/>\n                        <text use=\"road:z16\"/>\n                    </m>\n                    <m k=\"highway\" v=\"trunk_link|motorway_link\">\n                        <m zoom-max=\"13\">\n                            <line outline=\"motorway_link:z12\" use=\"motorway_link:z12\"/>\n                        </m>\n                        <m zoom-min=\"13\">\n                            <line outline=\"motorway_link:z18\" use=\"motorway_link:z18\"/>\n                        </m>\n                    </m>\n                    <m k=\"highway\" v=\"residential|road|living_street|pedestrian|unclassified\">\n                        <m k=\"highway\" v=\"pedestrian\">\n                            <line fade=\"13\" use=\"pedestrian:z18\"/>\n                        </m>\n                        <m k=\"highway\" v=\"-|pedestrian\">\n                            <line fade=\"13\" use=\"residential:z18\"/>\n                        </m>\n                        <m zoom-min=\"14\">\n                            <text use=\"road:z14\"/>\n                        </m>\n                    </m>\n                    <m k=\"highway\" v=\"tertiary|secondary_link\">\n                        <line use=\"tertiary:z12\"/>\n                        <line use=\"tertiary:z18\"/>\n                        <m zoom-min=\"13\">\n                            <text use=\"road:z13\"/>\n                        </m>\n                    </m>\n                    <m k=\"highway\" v=\"secondary|primary_link\">\n                        <line use=\"secondary:z12\"/>\n                        <line use=\"secondary:z18\"/>\n                        <m zoom-min=\"12\">\n                            <text use=\"road:z12\"/>\n                        </m>\n                    </m>\n                    <m k=\"highway\" v=\"primary\">\n                        <m zoom-max=\"13\">\n                            <line outline=\"trunk:z12\" use=\"primary:z12\"/>\n                        </m>\n                        <m zoom-min=\"13\">\n                            <line outline=\"trunk:z18\" use=\"primary:z18\"/>\n                        </m>\n                        <m zoom-min=\"12\">\n                            <text use=\"road:orange\"/>\n                        </m>\n                        <!-- disabled for mapsforge/vtm#193\n                        <text caption=\"true\" fill=\"#111111\" k=\"ref\" priority=\"2\" size=\"10\"\n                              stroke=\"#FFDC36\" stroke-width=\"16.0\"/>\n                              -->\n                    </m>\n                    <m k=\"highway\" v=\"trunk\">\n                        <m zoom-max=\"13\">\n                            <line outline=\"trunk:z12\" use=\"trunk:z12\"/>\n                        </m>\n                        <m zoom-min=\"13\">\n                            <line outline=\"trunk:z18\" use=\"trunk:z18\"/>\n                        </m>\n                        <m zoom-min=\"12\">\n                            <text use=\"road:orange\"/>\n                        </m>\n                        <!-- disabled for mapsforge/vtm#193\n                        <text caption=\"true\" fill=\"#111111\" k=\"ref\" priority=\"2\" size=\"10\"\n                              stroke=\"#FFDC36\" stroke-width=\"16.0\"/>\n                              -->\n                    </m>\n                    <m k=\"highway\" v=\"motorway\">\n                        <m zoom-max=\"13\">\n                            <line outline=\"motorway:z12\" use=\"motorway:z12\"/>\n                        </m>\n                        <m zoom-min=\"13\">\n                            <line outline=\"motorway:z18\" use=\"motorway:z18\"/>\n                        </m>\n                        <!-- disabled for mapsforge/vtm#193\n                        <text caption=\"true\" fill=\"#eeeeee\" k=\"ref\" priority=\"2\" size=\"14\"\n                              stroke=\"#E79608\" stroke-width=\"16.0\"/>\n                              -->\n                        <outline outline=\"motorway\"/>\n                    </m>\n                </m>\n\n                <m k=\"bridge\">\n                    <outline-layer id=\"bridge\" stroke=\"#88202020\" width=\"0.08\"/>\n                    <m k=\"bridge\" v=\"-|no|false\">\n\n                        <m k=\"area\" v=\"~|no|false\">\n\n                            <m v=\"track|footway|path|cycleway|steps\">\n                                <line cap=\"butt\" outline=\"bridge\" use=\"walkway:z18\"/>\n                            </m>\n\n                            <m select=\"first\">\n                                <m v=\"footway|cycleway|track|path|bridleway\">\n                                    <line use=\"walkway:z18\"/>\n                                </m>\n                                <!--<m v=\"construction\">\n                                    <line cap=\"square\" outline=\"bridge\" use=\"construction\" />\n                                </m>\n                                <m v=\"service\">\n                                    <line cap=\"square\" outline=\"bridge\" use=\"highway-service\" />\n                                </m>-->\n                            </m>\n\n                            <m select=\"first\">\n                                <m v=\"byway|pedestrian\">\n                                    <line outline=\"bridge\" use=\"pedestrian:z18\"/>\n                                    <text use=\"road:z16\"/>\n                                </m>\n                                <m v=\"residential|road|unclassified|living_street\">\n                                    <line outline=\"bridge\" use=\"residential:z18\"/>\n                                    <text use=\"road:z14\"/>\n                                </m>\n                            </m>\n\n                            <m select=\"first\">\n                                <m v=\"tertiary|secondary_link\">\n                                    <line cap=\"square\" outline=\"bridge\" use=\"tertiary:z18\"/>\n                                    <text use=\"road:z13\"/>\n                                </m>\n                                <m v=\"trunk_link|motorway_link\">\n                                    <m zoom-max=\"13\">\n                                        <line cap=\"square\" outline=\"bridge\"\n                                              use=\"motorway_link:z12\"/>\n                                    </m>\n                                    <m zoom-min=\"13\">\n                                        <line cap=\"square\" outline=\"bridge\"\n                                              use=\"motorway_link:z18\"/>\n                                    </m>\n                                </m>\n                                <m v=\"secondary|primary_link\">\n                                    <line cap=\"square\" outline=\"bridge\" use=\"secondary:z18\"/>\n                                    <text use=\"road:z12\"/>\n                                </m>\n                                <m v=\"trunk|primary\">\n                                    <m zoom-max=\"13\">\n                                        <line cap=\"square\" outline=\"bridge\" use=\"trunk:z12\"/>\n                                    </m>\n                                    <m zoom-min=\"13\">\n                                        <line cap=\"square\" outline=\"bridge\" use=\"trunk:z18\"/>\n                                    </m>\n                                </m>\n                                <m v=\"motorway\">\n                                    <m zoom-max=\"13\">\n                                        <line cap=\"square\" outline=\"bridge\" use=\"motorway:z12\"/>\n                                    </m>\n                                    <m zoom-min=\"13\">\n                                        <line cap=\"square\" outline=\"bridge\" use=\"motorway:z18\"/>\n                                    </m>\n                                </m>\n                            </m>\n                        </m>\n\n                        <m k=\"area\" select=\"first\" v=\"yes|true\">\n                            <m v=\"footway\" zoom-min=\"15\">\n                                <area fill=\"#fefefe\"/>\n                                <line cap=\"butt\" stroke=\"#c0c0c0\" width=\"0.15\"/>\n                            </m>\n                            <m v=\"pedestrian|service|unclassified|residential|road|living_street\"\n                               zoom-min=\"13\">\n                                <area fill=\"#eeffffff\"/>\n                                <line cap=\"butt\" fix=\"true\" stroke=\"#c0c0c0\" width=\"1.0\"/>\n                            </m>\n                        </m>\n                    </m>\n                </m>\n            </m>\n        </m>\n    </m>\n\n    <m k=\"railway\" v=\"tram|light_rail|subway|narrow_gauge|rail\">\n        <m k=\"tunnel\" v=\"~|no\">\n            <line stipple=\"20\" stipple-stroke=\"#AAAAAA\" stipple-width=\"0.1\" stroke=\"#CCCCCC\"\n                  use=\"fix\"\n                  width=\"0.1\"/>\n        </m>\n        <m k=\"tunnel\" v=\"yes\">\n            <line stipple=\"20\" stipple-stroke=\"#AAAAAA\" stipple-width=\"1.0\" stroke=\"#00000000\"\n                  use=\"fix\"/>\n        </m>\n    </m>\n\n    <m k=\"highway|railway|public_transport\" v=\"platform\">\n        <m k=\"tunnel\" v=\"~|no\">\n            <line use=\"building\"/>\n            <area use=\"building\"/>\n        </m>\n        <m k=\"tunnel\" v=\"yes\">\n            <line use=\"sub-building\"/>\n        </m>\n    </m>\n\n    <m k=\"building\">\n        <m k=\"indoor|tunnel\" v=\"yes\" zoom-min=\"17\">\n            <line use=\"sub-building\"/>\n        </m>\n        <m k=\"indoor|tunnel\" v=\"~|no\" zoom-min=\"17\">\n            <line use=\"building\"/>\n            <m k=\"shop\" v=\"~\">\n                <m closed=\"yes\">\n                    <area use=\"building\"/>\n                </m>\n                <!--<extrusion line-color=\"#ffdcdcdc\" side-color=\"#66dcdcdc\" top-color=\"#f2f2f2\"/>-->\n            </m>\n            <m k=\"shop\" v=\"mall\">\n                <m closed=\"yes\">\n                    <area use=\"building-poi\"/>\n                </m>\n            </m>\n            <caption style=\"bold\" fill=\"#4040ff\" k=\"name\" priority=\"9\" size=\"14\"\n                     stroke=\"#ffffff\" stroke-width=\"2.0\"/>\n            <caption style=\"bold\" fill=\"#606060\" k=\"addr:housenumber\" priority=\"10\" size=\"10\"\n                     stroke=\"#ffffff\" stroke-width=\"2.0\"/>\n        </m>\n    </m>\n\n    <m e=\"node\" select=\"first\">\n        <m k=\"place\">\n            <m v=\"suburb\" zoom-max=\"16\" zoom-min=\"9\">\n                <caption fill=\"#8B7F5F\" k=\"name\" priority=\"4\" size=\"17\"\n                         stroke=\"#EAEAEA\" stroke-width=\"5.0\"/>\n            </m>\n            <m v=\"village\" zoom-max=\"15\" zoom-min=\"9\">\n                <caption fill=\"#8B7F5F\" k=\"name\" priority=\"3\" size=\"17\" stroke=\"#EAEAEA\"\n                         stroke-width=\"5.0\"/>\n            </m>\n            <m v=\"island\" zoom-min=\"10\">\n                <caption style=\"bold\" fill=\"#000000\" k=\"name\" priority=\"1\" size=\"20\"\n                         stroke=\"#EAEAEA\" stroke-width=\"5.0\"/>\n            </m>\n            <m v=\"town\">\n                <m zoom-max=\"15\" zoom-min=\"13\">\n                    <caption fill=\"#8B7F5F\" k=\"name\" priority=\"1\" size=\"23\" stroke=\"#EAEAEA\"\n                             stroke-width=\"5.0\"/>\n                </m>\n                <m zoom-max=\"13\" zoom-min=\"9\">\n                    <caption fill=\"#615942\" k=\"name\" priority=\"1\" size=\"19\"\n                             stroke=\"#EAEAEA\" stroke-width=\"5.0\"/>\n                </m>\n                <m zoom-max=\"9\">\n                    <caption fill=\"#000000\" k=\"name\" priority=\"1\" size=\"16\"\n                             stroke=\"#EAEAEA\" stroke-width=\"5.0\"/>\n                </m>\n            </m>\n            <m v=\"city\">\n                <m zoom-max=\"15\" zoom-min=\"13\">\n                    <caption fill=\"#615942\" k=\"name\" priority=\"1\" size=\"24\" stroke=\"#EAEAEA\"\n                             stroke-width=\"5.0\"/>\n                </m>\n                <m zoom-max=\"13\" zoom-min=\"9\">\n                    <caption fill=\"#000000\" k=\"name\" priority=\"1\" size=\"24\"\n                             stroke=\"#EAEAEA\" stroke-width=\"5.0\"/>\n                </m>\n                <m zoom-max=\"9\">\n                    <caption dy=\"14\" fill=\"#000000\" k=\"name\" priority=\"1\" size=\"19\"\n                             stroke=\"#EAEAEA\" stroke-width=\"5.0\"\n                             symbol=\"assets:symbols/dot_white.svg\"/>\n                </m>\n            </m>\n            <m v=\"country\" zoom-max=\"9\">\n                <caption style=\"bold\" fill=\"#000000\" k=\"name\" priority=\"0\" size=\"20\"\n                         stroke=\"#EAEAEA\" stroke-width=\"5.0\"/>\n            </m>\n        </m>\n        <m k=\"railway\">\n            <m v=\"station\">\n                <m zoom-max=\"16\">\n                    <text use=\"transit-small\"/>\n                    <symbol src=\"assets:symbols/transit/train_station_small.svg\"/>\n                </m>\n                <m zoom-min=\"16\">\n                    <text use=\"transit\"/>\n                    <symbol src=\"assets:symbols/transit/train_station.svg\"/>\n                </m>\n            </m>\n        </m>\n\n        <m k=\"addr:housenumber\" zoom-min=\"18\">\n            <caption style=\"bold\" fill=\"#606060\" k=\"addr:housenumber\" size=\"10\" stroke=\"#EAEAEA\"\n                     stroke-width=\"2.0\"/>\n        </m>\n    </m>\n\n</rendertheme>\n"
  },
  {
    "path": "play-services-maps/core/vtm/microg-theme/src/org/oscim/theme/MicrogThemes.java",
    "content": "package org.oscim.theme;\n\nimport org.oscim.backend.AssetAdapter;\n\nimport java.io.InputStream;\n\npublic enum MicrogThemes implements ThemeFile {\n\n    DEFAULT(\"styles/microg.xml\");\n    // TODO: night theme\n\n    private final String mPath;\n\n    MicrogThemes(String path) {\n        mPath = path;\n    }\n\n    @Override\n    public XmlRenderThemeMenuCallback getMenuCallback() {\n        return null;\n    }\n\n    @Override\n    public String getRelativePathPrefix() {\n        return \"\";\n    }\n\n    @Override\n    public InputStream getRenderThemeAsStream() {\n        return AssetAdapter.readFileAsStream(mPath);\n    }\n\n    @Override\n    public void setMenuCallback(XmlRenderThemeMenuCallback menuCallback) {\n    }\n\n    @Override\n    public boolean isMapsforgeTheme() {\n        return false;\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2019 microG Project Team\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<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n          xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>\n    <uses-permission android:name=\"android.permission.INTERNET\"/>\n    <uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>\n    <uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>\n    <uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>\n    <uses-permission android:name=\"android.permission.WAKE_LOCK\"/>\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>\n    <uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\"/>\n    <uses-permission android:name=\"android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS\"/>\n    <uses-permission android:name=\"android.permission.RECEIVE_BOOT_COMPLETED\"/>\n\n    <application>\n        <provider\n            android:name=\".data.SharedTileProvider\"\n            android:authorities=\"org.microg.gms.maps.vtm.tile\"\n            android:enabled=\"true\"\n            android:exported=\"true\"/>\n    </application>\n\n</manifest>\n"
  },
  {
    "path": "play-services-maps/core/vtm/src/main/java/com/google/android/gms/maps/internal/CreatorImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.maps.internal;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.content.res.Resources;\nimport android.os.Parcel;\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport androidx.annotation.Keep;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.dynamic.ObjectWrapper;\nimport com.google.android.gms.maps.GoogleMapOptions;\nimport com.google.android.gms.maps.StreetViewPanoramaOptions;\nimport com.google.android.gms.maps.model.internal.IBitmapDescriptorFactoryDelegate;\n\nimport org.microg.gms.maps.vtm.MapFragmentImpl;\nimport org.microg.gms.maps.vtm.MapViewImpl;\nimport org.microg.gms.maps.vtm.ResourcesContainer;\nimport org.microg.gms.maps.vtm.StreetViewPanoramaFragmentImpl;\nimport org.microg.gms.maps.vtm.StreetViewPanoramaViewImpl;\nimport org.microg.gms.maps.vtm.bitmap.BitmapDescriptorFactoryImpl;\nimport org.microg.gms.maps.vtm.camera.CameraUpdateFactoryImpl;\n\n@Keep\npublic class CreatorImpl extends ICreator.Stub {\n    private static final String TAG = \"GmsMapCreator\";\n\n    @Override\n    public void init(IObjectWrapper resources) throws RemoteException {\n        initV2(resources, 0);\n    }\n\n    @Override\n    public IMapFragmentDelegate newMapFragmentDelegate(IObjectWrapper activity) throws RemoteException {\n        return new MapFragmentImpl((Activity) ObjectWrapper.unwrap(activity));\n    }\n\n    @Override\n    public IMapViewDelegate newMapViewDelegate(IObjectWrapper context, GoogleMapOptions options) throws RemoteException {\n        return new MapViewImpl((Context) ObjectWrapper.unwrap(context), options);\n    }\n\n    @Override\n    public ICameraUpdateFactoryDelegate newCameraUpdateFactoryDelegate() throws RemoteException {\n        return CameraUpdateFactoryImpl.get();\n    }\n\n    @Override\n    public IBitmapDescriptorFactoryDelegate newBitmapDescriptorFactoryDelegate() throws RemoteException {\n        return new BitmapDescriptorFactoryImpl();\n    }\n\n    @Override\n    public void initV2(IObjectWrapper resources, int flags) throws RemoteException {\n        ResourcesContainer.set((Resources) ObjectWrapper.unwrap(resources));\n    }\n\n    @Override\n    public IStreetViewPanoramaViewDelegate newStreetViewPanoramaViewDelegate(IObjectWrapper context, StreetViewPanoramaOptions options) {\n        return new StreetViewPanoramaViewImpl((Activity) ObjectWrapper.unwrap(context));\n    }\n\n    @Override\n    public IStreetViewPanoramaFragmentDelegate newStreetViewPanoramaFragmentDelegate(IObjectWrapper activity) {\n        return new StreetViewPanoramaFragmentImpl((Activity) ObjectWrapper.unwrap(activity));\n    }\n\n    @Override\n    public int getRendererType() throws RemoteException {\n        return 1;\n    }\n\n    @Override\n    public void logInitialization(IObjectWrapper context, int preferredRenderer) throws RemoteException {\n        Log.d(TAG, \"VTM-based Map initialized (preferred renderer was \" + preferredRenderer + \")\");\n    }\n\n    @Override\n    public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {\n        if (super.onTransact(code, data, reply, flags)) return true;\n        Log.d(TAG, \"onTransact [unknown]: \" + code + \", \" + data + \", \" + flags);\n        return false;\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/src/main/java/org/microg/gms/maps/vtm/ApplicationContextWrapper.java",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 org.microg.gms.maps.vtm;\n\nimport android.content.Context;\nimport android.content.ContextWrapper;\nimport android.content.pm.PackageManager;\n\nimport org.microg.gms.common.Constants;\n\npublic class ApplicationContextWrapper extends ContextWrapper {\n    private Context applicationContext;\n\n    public ApplicationContextWrapper(Context base, Context applicationContext) {\n        super(base);\n        this.applicationContext = applicationContext;\n    }\n\n    public static ApplicationContextWrapper gmsContextWithAttachedApplicationContext(Context applicationContext) {\n        try {\n            Context context = applicationContext.createPackageContext(Constants.GMS_PACKAGE_NAME, CONTEXT_INCLUDE_CODE & CONTEXT_IGNORE_SECURITY);\n            return new ApplicationContextWrapper(context, applicationContext);\n        } catch (PackageManager.NameNotFoundException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public static ApplicationContextWrapper matchingApplicationContext(Context context) {\n        return new ApplicationContextWrapper(context, context);\n    }\n\n    @Override\n    public Context getApplicationContext() {\n        return applicationContext;\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/src/main/java/org/microg/gms/maps/vtm/BackendMap.java",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 org.microg.gms.maps.vtm;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.graphics.Canvas;\nimport android.graphics.Paint;\nimport android.os.RemoteException;\nimport android.util.Log;\nimport android.view.View;\n\nimport com.google.android.gms.maps.internal.ISnapshotReadyCallback;\nimport com.google.android.gms.maps.model.CameraPosition;\n\nimport org.microg.gms.maps.vtm.camera.CameraUpdate;\nimport org.microg.gms.maps.vtm.markup.DrawableMarkup;\nimport org.microg.gms.maps.vtm.markup.MarkerItemMarkup;\nimport org.microg.gms.maps.vtm.markup.Markup;\nimport org.oscim.backend.GL;\nimport org.oscim.backend.GLAdapter;\nimport org.oscim.core.MapPosition;\nimport org.oscim.core.Point;\nimport org.oscim.event.Event;\nimport org.oscim.event.MotionEvent;\nimport org.oscim.layers.marker.ItemizedLayer;\nimport org.oscim.layers.marker.MarkerItem;\nimport org.oscim.layers.vector.geometries.Drawable;\nimport org.oscim.map.Viewport;\n\nimport java.nio.IntBuffer;\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\nimport javax.microedition.khronos.opengles.GL10;\n\npublic class BackendMap implements ItemizedLayer.OnItemGestureListener<MarkerItem>, org.oscim.map.Map.InputListener, org.oscim.map.Map.UpdateListener {\n    private final static String TAG = \"GmsMapBackend\";\n\n    private final Context context;\n    private final BackendMapView mapView;\n    private final ContainerLayout container;\n    private final CameraUpdateListener cameraUpdateListener;\n    private final Map<String, Markup> markupMap = new HashMap<String, Markup>();\n    private final List<DrawableMarkup> drawableMarkups = new ArrayList<DrawableMarkup>();\n    private MarkerItemMarkup currentlyDraggedItem;\n    private float dragLastX = -1;\n    private float dragLastY = -1;\n\n    public BackendMap(Context context, final CameraUpdateListener cameraUpdateListener) {\n        this.context = context;\n        this.cameraUpdateListener = cameraUpdateListener;\n        mapView = new BackendMapView(context);\n        mapView.items().setOnItemGestureListener(this);\n        mapView.map().input.bind(this);\n        mapView.map().events.bind(this);\n        container = new ContainerLayout(context);\n        container.addView(mapView);\n    }\n\n    public Viewport getViewport() {\n        return mapView.map().viewport();\n    }\n\n    public void destroy() {\n        mapView.map().destroy();\n    }\n\n    public void onResume() {\n        mapView.onResume();\n    }\n\n    public void onPause() {\n        mapView.onPause();\n    }\n\n    public MapPosition getMapPosition() {\n        return mapView.map().getMapPosition();\n    }\n\n    public View getView() {\n        return container;\n    }\n\n    public boolean hasBuilding() {\n        return mapView.map().layers().contains(mapView.buildings());\n    }\n\n    public void setBuildings(boolean buildingsEnabled) {\n        if (!hasBuilding() && buildingsEnabled) {\n            mapView.map().layers().add(mapView.buildings());\n        } else if (hasBuilding() && !buildingsEnabled) {\n            mapView.map().layers().remove(mapView.buildings());\n        }\n        redraw();\n    }\n\n    public void redraw() {\n        mapView.map().updateMap(true);\n    }\n\n    public void applyCameraUpdate(CameraUpdate cameraUpdate) {\n        cameraUpdate.apply(mapView.map());\n    }\n\n    public void applyCameraUpdateAnimated(CameraUpdate cameraUpdate, int durationMs) {\n        cameraUpdate.applyAnimated(mapView.map(), durationMs);\n    }\n\n    public void stopAnimation() {\n        mapView.map().animator().cancel();\n    }\n\n    public synchronized <T extends DrawableMarkup> T add(T markup) {\n        if (markup == null) return null;\n        drawableMarkups.add(markup);\n        Collections.sort(drawableMarkups, new Comparator<DrawableMarkup>() {\n            @Override\n            public int compare(DrawableMarkup lhs, DrawableMarkup rhs) {\n                return Float.compare(lhs.getZIndex(), rhs.getZIndex());\n            }\n        });\n        updateDrawableLayer();\n        redraw();\n        return markup;\n    }\n\n    private synchronized void updateDrawableLayer() {\n        mapView.drawables().clear();\n        for (DrawableMarkup markup : drawableMarkups) {\n            Drawable drawable = markup.getDrawable(mapView.map());\n            if (drawable != null) {\n                mapView.drawables().add(drawable);\n            }\n        }\n    }\n\n    public synchronized <T extends MarkerItemMarkup> T add(T markup) {\n        if (markup == null) return null;\n        markupMap.put(markup.getId(), markup);\n        MarkerItem item = markup.getMarkerItem(context);\n        mapView.items().addItem(item);\n        redraw();\n        return markup;\n    }\n\n    public synchronized void clear() {\n        markupMap.clear();\n        mapView.items().removeAllItems();\n        drawableMarkups.clear();\n        mapView.drawables().clear();\n        redraw();\n    }\n\n    public synchronized void remove(Markup markup) {\n        if (markup instanceof MarkerItemMarkup) {\n            markupMap.remove(markup.getId());\n            MarkerItem toRemove = getByUid(markup.getId());\n            if (toRemove != null) mapView.items().removeItem(toRemove);\n        } else if (markup instanceof DrawableMarkup) {\n            drawableMarkups.remove(markup);\n            updateDrawableLayer();\n            mapView.drawables().update();\n        }\n        redraw();\n    }\n\n    private MarkerItem getByUid(String uid) {\n        for (MarkerItem markerItem : mapView.items().getItemList()) {\n            if (markerItem.getUid().equals(uid)) {\n                return markerItem;\n            }\n        }\n        return null;\n    }\n\n    public synchronized void update(Markup markup) {\n        if (markup == null) return;\n        if (markup instanceof MarkerItemMarkup) {\n            MarkerItem item = getByUid(markup.getId());\n            if (item != null) {\n                mapView.items().removeItem(item);\n            }\n            item = ((MarkerItemMarkup) markup).getMarkerItem(context);\n            if (item != null) {\n                mapView.items().addItem(item);\n            }\n        } else if (markup instanceof DrawableMarkup) {\n            updateDrawableLayer();\n            mapView.drawables().update();\n        }\n        redraw();\n    }\n\n    @Override\n    public boolean onItemSingleTapUp(int index, MarkerItem item) {\n        Markup markup = markupMap.get(item.getUid());\n        if (markup != null) {\n            if (markup.onClick()) return true;\n        }\n        return false;\n    }\n\n    @Override\n    public boolean onItemLongPress(int index, MarkerItem item) {\n        Markup markup = markupMap.get(item.getUid());\n        if (((MarkerItemMarkup) markup).isDraggable()) {\n            currentlyDraggedItem = (MarkerItemMarkup) markup;\n            currentlyDraggedItem.onDragStart();\n            return false;\n        } else {\n            Log.d(TAG, \"onItemLongPress: \" + markup);\n            return false;\n        }\n    }\n\n    @Override\n    public void onInputEvent(Event event, MotionEvent motionEvent) {\n        if ((motionEvent.getAction() == MotionEvent.ACTION_CANCEL || motionEvent.getAction() == MotionEvent.ACTION_UP) && currentlyDraggedItem != null) {\n            currentlyDraggedItem.onDragStop();\n            currentlyDraggedItem = null;\n        }\n        if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {\n            dragLastX = motionEvent.getX();\n            dragLastY = motionEvent.getY();\n        }\n        if (motionEvent.getAction() == MotionEvent.ACTION_MOVE && currentlyDraggedItem != null) {\n            Point out = new Point();\n            mapView.map().viewport().toScreenPoint(GmsMapsTypeHelper.fromLatLng(currentlyDraggedItem.getPosition()), out);\n            out.x += mapView.getWidth() / 2;\n            out.y += mapView.getHeight() / 2;\n            float mx = motionEvent.getX() - dragLastX;\n            float my = motionEvent.getY() - dragLastY;\n            currentlyDraggedItem.setPosition(GmsMapsTypeHelper.toLatLng(mapView.map().viewport().fromScreenPoint((float) out.getX() + mx, (float) out.getY() + my)));\n            currentlyDraggedItem.onDragProgress();\n            dragLastX += mx;\n            dragLastY += my;\n        }\n    }\n\n    public void snapshot(final Bitmap bitmap, final ISnapshotReadyCallback callback) {\n        mapView.queueEvent(new Runnable() {\n            @Override\n            public void run() {\n                Bitmap surface = createBitmapFromGLSurface(0, 0, mapView.getWidth(), mapView.getHeight(), GLAdapter.gl);\n                final Bitmap result;\n                if (bitmap != null) {\n                    Canvas c = new Canvas(bitmap);\n                    c.drawBitmap(surface, 0, 0, new Paint());\n                    result = bitmap;\n                } else {\n                    result = surface;\n                }\n                mapView.getHandler().post(new Runnable() {\n                    @Override\n                    public void run() {\n                        Log.d(TAG, \"snapshot result: \" + result);\n                        try {\n                            callback.onBitmapReady(result);\n                        } catch (RemoteException e) {\n                            Log.w(TAG, e);\n                        }\n                    }\n                });\n            }\n        });\n    }\n\n    private Bitmap createBitmapFromGLSurface(int x, int y, int w, int h, GL gl) {\n        int bitmapBuffer[] = new int[w * h];\n        int bitmapSource[] = new int[w * h];\n        IntBuffer intBuffer = IntBuffer.wrap(bitmapBuffer);\n        intBuffer.position(0);\n\n        try {\n            gl.readPixels(x, y, w, h, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, intBuffer);\n            int offset1, offset2;\n            for (int i = 0; i < h; i++) {\n                offset1 = i * w;\n                offset2 = (h - i - 1) * w;\n                for (int j = 0; j < w; j++) {\n                    int texturePixel = bitmapBuffer[offset1 + j];\n                    int blue = (texturePixel >> 16) & 0xff;\n                    int red = (texturePixel << 16) & 0x00ff0000;\n                    int pixel = (texturePixel & 0xff00ff00) | red | blue;\n                    bitmapSource[offset2 + j] = pixel;\n                }\n            }\n        } catch (Exception e) {\n            Log.e(TAG, \"createBitmapFromGLSurface: \" + e.getMessage(), e);\n            return null;\n        }\n\n        return Bitmap.createBitmap(bitmapSource, w, h, Bitmap.Config.ARGB_8888);\n    }\n\n    public void setZoomGesturesEnabled(boolean enabled) {\n        mapView.map().getEventLayer().enableZoom(enabled);\n    }\n\n    public void setScrollGesturesEnabled(boolean enabled) {\n        mapView.map().getEventLayer().enableMove(enabled);\n    }\n\n    public void setRotateGesturesEnabled(boolean enabled) {\n        mapView.map().getEventLayer().enableRotation(enabled);\n    }\n\n    public void setTiltGesturesEnabled(boolean enabled) {\n        mapView.map().getEventLayer().enableTilt(enabled);\n    }\n\n    @Override\n    public void onMapEvent(Event event, MapPosition mapPosition) {\n        if (event == org.oscim.map.Map.ANIM_END || event == org.oscim.map.Map.POSITION_EVENT || event == org.oscim.map.Map.MOVE_EVENT)\n            cameraUpdateListener.onCameraUpdate(GmsMapsTypeHelper.toCameraPosition(mapPosition));\n    }\n\n    public interface CameraUpdateListener {\n        void onCameraUpdate(CameraPosition cameraPosition);\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/src/main/java/org/microg/gms/maps/vtm/BackendMapView.java",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 org.microg.gms.maps.vtm;\n\nimport android.content.Context;\nimport android.content.ContextWrapper;\nimport android.content.pm.ApplicationInfo;\nimport android.graphics.BitmapFactory;\nimport android.util.AttributeSet;\nimport android.util.Log;\n\nimport org.microg.gms.maps.vtm.data.SharedTileCache;\nimport org.microg.gms.maps.vtm.markup.ClearableVectorLayer;\nimport org.microg.gms.maps.vtm.R;\nimport org.oscim.android.AndroidAssets;\nimport org.oscim.android.MapView;\nimport org.oscim.android.canvas.AndroidBitmap;\nimport org.oscim.layers.marker.ItemizedLayer;\nimport org.oscim.layers.marker.MarkerItem;\nimport org.oscim.layers.marker.MarkerSymbol;\nimport org.oscim.layers.tile.buildings.BuildingLayer;\nimport org.oscim.layers.tile.vector.VectorTileLayer;\nimport org.oscim.layers.tile.vector.labeling.LabelLayer;\nimport org.oscim.map.Layers;\nimport org.oscim.theme.MicrogThemes;\nimport org.oscim.tiling.ITileCache;\nimport org.oscim.tiling.source.oscimap4.OSciMap4TileSource;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.Enumeration;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipFile;\n\npublic class BackendMapView extends MapView {\n    private static final String TAG = \"GmsMapView\";\n\n    private static boolean nativeLibLoaded = false;\n    private LabelLayer labels;\n    private BuildingLayer buildings;\n    private ItemizedLayer<MarkerItem> items;\n    private ClearableVectorLayer drawables;\n\n    static synchronized Context loadNativeLib(Context context) {\n        try {\n            if (nativeLibLoaded) return context;\n            ApplicationInfo otherAppInfo = context.getPackageManager().getApplicationInfo(context.getApplicationContext().getPackageName(), 0);\n\n            String primaryCpuAbi = (String) ApplicationInfo.class.getField(\"primaryCpuAbi\").get(otherAppInfo);\n            if (primaryCpuAbi != null) {\n                String path = \"lib/\" + primaryCpuAbi + \"/libvtm-jni.so\";\n                File cacheFile = new File(context.getApplicationContext().getCacheDir().getAbsolutePath() + \"/.gmscore/\" + path);\n                cacheFile.getParentFile().mkdirs();\n                File apkFile = new File(context.getPackageCodePath());\n                if (!cacheFile.exists() || cacheFile.lastModified() < apkFile.lastModified()) {\n                    ZipFile zipFile = new ZipFile(apkFile);\n                    ZipEntry entry = zipFile.getEntry(path);\n                    if (entry != null) {\n                        copyInputStream(zipFile.getInputStream(entry), new FileOutputStream(cacheFile));\n                    } else {\n                        Log.d(TAG, \"Can't load native library: \" + path + \" does not exist in \" + apkFile);\n                    }\n                }\n                Log.d(TAG, \"Loading vtm-jni from \" + cacheFile.getPath());\n                System.load(cacheFile.getAbsolutePath());\n                nativeLibLoaded = true;\n            }\n        } catch (Exception e) {\n            Log.w(TAG, e);\n        }\n        if (!nativeLibLoaded) {\n            Log.d(TAG, \"Loading native vtm-jni\");\n            System.loadLibrary(\"vtm-jni\");\n            nativeLibLoaded = true;\n        }\n        return context;\n    }\n\n    private static final void copyInputStream(InputStream in, OutputStream out) throws IOException {\n        byte[] buffer = new byte[1024];\n        int len;\n\n        while ((len = in.read(buffer)) >= 0)\n            out.write(buffer, 0, len);\n\n        in.close();\n        out.close();\n    }\n\n    @Override\n    public void onResume() {\n        super.onResume();\n    }\n\n    @Override\n    public void onPause() {\n        super.onPause();\n    }\n\n    public BackendMapView(Context context) {\n        super(loadNativeLib(context));\n        if (context instanceof ContextWrapper) {\n            AndroidAssets.init(ApplicationContextWrapper.matchingApplicationContext(((ContextWrapper) context).getBaseContext()));\n        }\n        initialize();\n    }\n\n    public BackendMapView(Context context, AttributeSet attributeSet) {\n        super(loadNativeLib(context), attributeSet);\n        initialize();\n    }\n\n    ItemizedLayer<MarkerItem> items() {\n        return items;\n    }\n\n    BuildingLayer buildings() {\n        return buildings;\n    }\n\n    ClearableVectorLayer drawables() {\n        return drawables;\n    }\n\n    private void initialize() {\n        ITileCache cache = new SharedTileCache(getContext());\n        cache.setCacheSize(512 * (1 << 10));\n        OSciMap4TileSource tileSource = new OSciMap4TileSource();\n        tileSource.setCache(cache);\n        VectorTileLayer baseLayer = map().setBaseMap(tileSource);\n        Layers layers = map().layers();\n        layers.add(drawables = new ClearableVectorLayer(map()));\n        layers.add(labels = new LabelLayer(map(), baseLayer));\n        layers.add(buildings = new BuildingLayer(map(), baseLayer));\n        layers.add(items = new ItemizedLayer<MarkerItem>(map(), new MarkerSymbol(\n                new AndroidBitmap(BitmapFactory.decodeResource(getContext().getResources(), R.drawable.nop)), 0.5F, 1)));\n        map().setTheme(MicrogThemes.DEFAULT);\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/src/main/java/org/microg/gms/maps/vtm/ContainerLayout.java",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 org.microg.gms.maps.vtm;\n\nimport android.content.Context;\nimport android.widget.FrameLayout;\n\nimport org.oscim.utils.ThreadUtils;\n\npublic class ContainerLayout extends FrameLayout {\n    public ContainerLayout(Context context) {\n        super(context);\n    }\n\n    @Override\n    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {\n        ThreadUtils.init();\n        super.onLayout(changed, left, top, right, bottom);\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/src/main/java/org/microg/gms/maps/vtm/GmsMapsTypeHelper.java",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 org.microg.gms.maps.vtm;\n\nimport com.google.android.gms.maps.model.CameraPosition;\nimport com.google.android.gms.maps.model.LatLng;\nimport com.google.android.gms.maps.model.LatLngBounds;\n\nimport org.oscim.core.BoundingBox;\nimport org.oscim.core.Box;\nimport org.oscim.core.GeoPoint;\nimport org.oscim.core.MapPosition;\nimport org.oscim.core.MercatorProjection;\n\npublic class GmsMapsTypeHelper {\n    public static android.graphics.Point toPoint(org.oscim.core.Point in) {\n        return new android.graphics.Point((int) in.getX(), (int) in.getY());\n    }\n\n    public static GeoPoint fromLatLng(LatLng latLng) {\n        return new GeoPoint(latLng.latitude, latLng.longitude);\n    }\n\n    public static LatLng toLatLng(GeoPoint geoPoint) {\n        return new LatLng(geoPoint.getLatitude(), geoPoint.getLongitude());\n    }\n\n    public static LatLngBounds toLatLngBounds(Box box) {\n        double minLon = MercatorProjection.toLongitude(box.xmin);\n        double maxLon = MercatorProjection.toLongitude(box.xmax);\n        double minLat = MercatorProjection.toLatitude(box.ymax);\n        double maxLat = MercatorProjection.toLatitude(box.ymin);\n        if (Double.isNaN(minLon) || Double.isNaN(maxLon) || Double.isNaN(minLat) || Double.isNaN(maxLat))\n            minLon = maxLon = minLat = maxLat = 0;\n        return new LatLngBounds(new LatLng(minLat, minLon), new LatLng(maxLat, maxLon));\n    }\n\n    public static org.oscim.core.Point fromPoint(android.graphics.Point point) {\n        return new org.oscim.core.Point(point.x, point.y);\n    }\n\n    public static CameraPosition toCameraPosition(MapPosition mapPosition) {\n        return new CameraPosition(new LatLng(mapPosition.getLatitude(), mapPosition.getLongitude()),\n                toZoom(mapPosition.getScale()), mapPosition.getTilt(),\n                toBearing(mapPosition.getBearing()));\n    }\n\n    public static MapPosition fromCameraPosition(CameraPosition cameraPosition) {\n        MapPosition mapPosition = new MapPosition(cameraPosition.target.latitude,\n                cameraPosition.target.longitude, fromZoom(cameraPosition.zoom));\n        mapPosition.setTilt(cameraPosition.tilt);\n        mapPosition.setBearing(fromBearing(cameraPosition.bearing));\n        return mapPosition;\n    }\n\n    public static BoundingBox fromLatLngBounds(LatLngBounds bounds) {\n        return new BoundingBox(bounds.southwest.latitude, bounds.southwest.longitude,\n                bounds.northeast.latitude, bounds.northeast.longitude);\n    }\n\n    public static float fromBearing(float bearing) {\n        return -bearing;\n    }\n\n    public static float toBearing(float bearing) {\n        return -bearing;\n    }\n\n    public static double fromZoom(float zoom) {\n        return Math.pow(2, zoom);\n    }\n\n    public static float toZoom(double scale) {\n        return (float) (Math.log(scale) / Math.log(2));\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/src/main/java/org/microg/gms/maps/vtm/GoogleMapImpl.java",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 org.microg.gms.maps.vtm;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.location.Criteria;\nimport android.location.Location;\nimport android.location.LocationListener;\nimport android.location.LocationManager;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.os.Looper;\nimport android.os.Parcel;\nimport android.os.RemoteException;\nimport android.util.Log;\nimport android.view.View;\n\nimport androidx.core.content.ContextCompat;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.dynamic.ObjectWrapper;\nimport com.google.android.gms.maps.GoogleMapOptions;\nimport com.google.android.gms.maps.internal.*;\nimport com.google.android.gms.maps.model.CameraPosition;\nimport com.google.android.gms.maps.model.CircleOptions;\nimport com.google.android.gms.maps.model.GroundOverlayOptions;\nimport com.google.android.gms.maps.model.LatLngBounds;\nimport com.google.android.gms.maps.model.MarkerOptions;\nimport com.google.android.gms.maps.model.MapStyleOptions;\nimport com.google.android.gms.maps.model.PolygonOptions;\nimport com.google.android.gms.maps.model.PolylineOptions;\nimport com.google.android.gms.maps.model.TileOverlayOptions;\nimport com.google.android.gms.maps.model.internal.ICircleDelegate;\nimport com.google.android.gms.maps.model.internal.IGroundOverlayDelegate;\nimport com.google.android.gms.maps.model.internal.IMarkerDelegate;\nimport com.google.android.gms.maps.model.internal.IPolygonDelegate;\nimport com.google.android.gms.maps.model.internal.IPolylineDelegate;\nimport com.google.android.gms.maps.model.internal.ITileOverlayDelegate;\n\nimport org.microg.gms.maps.vtm.camera.CameraUpdate;\nimport org.microg.gms.maps.vtm.camera.MapPositionCameraUpdate;\nimport org.microg.gms.maps.vtm.markup.CircleImpl;\nimport org.microg.gms.maps.vtm.markup.GroundOverlayImpl;\nimport org.microg.gms.maps.vtm.markup.MarkerImpl;\nimport org.microg.gms.maps.vtm.markup.Markup;\nimport org.microg.gms.maps.vtm.markup.PolygonImpl;\nimport org.microg.gms.maps.vtm.markup.PolylineImpl;\nimport org.microg.gms.maps.vtm.markup.TileOverlayImpl;\n\nimport static android.Manifest.permission.ACCESS_COARSE_LOCATION;\nimport static android.Manifest.permission.ACCESS_FINE_LOCATION;\nimport static android.content.pm.PackageManager.PERMISSION_GRANTED;\n\npublic class GoogleMapImpl extends IGoogleMapDelegate.Stub\n        implements UiSettingsImpl.UiSettingsListener, Markup.MarkupListener, BackendMap.CameraUpdateListener {\n    private static final String TAG = \"GmsMapImpl\";\n\n    private final GoogleMapOptions options;\n    private final Context context;\n    private final BackendMap backendMap;\n    private final UiSettingsImpl uiSettings;\n    private final ProjectionImpl projection;\n\n    private int markerCounter = 0;\n    private int circleCounter = 0;\n    private int polylineCounter = 0;\n    private int polygonCounter = 0;\n\n    private IOnMarkerClickListener onMarkerClickListener;\n    private IOnMarkerDragListener onMarkerDragListener;\n    private IOnCameraChangeListener onCameraChangeListener;\n    private IOnMyLocationChangeListener onMyLocationChangeListener;\n\n    private Criteria criteria;\n    private Location myLocation;\n    private LocationListener listener = new LocationListener() {\n        @Override\n        public void onLocationChanged(Location location) {\n            // TODO: Actually do my location overlay\n            myLocation = location;\n            if (onMyLocationChangeListener != null && location != null) {\n                try {\n                    onMyLocationChangeListener.onMyLocationChanged(ObjectWrapper.wrap(location));\n                } catch (RemoteException e) {\n                    e.printStackTrace();\n                }\n            }\n        }\n\n        @Override\n        public void onStatusChanged(String provider, int status, Bundle extras) {\n        }\n\n        @Override\n        public void onProviderEnabled(String provider) {\n        }\n\n        @Override\n        public void onProviderDisabled(String provider) {\n        }\n    };\n\n    private GoogleMapImpl(Context context, GoogleMapOptions options) {\n        this.context = context;\n        Context appContext = context;\n        if (appContext.getApplicationContext() != null)\n            appContext = appContext.getApplicationContext();\n        Context wrappedContext = ApplicationContextWrapper.gmsContextWithAttachedApplicationContext(appContext);\n        backendMap = new BackendMap(wrappedContext, this);\n        uiSettings = new UiSettingsImpl(this);\n        projection = new ProjectionImpl(backendMap.getViewport());\n        this.options = options;\n\n        criteria = new Criteria();\n        criteria.setAccuracy(Criteria.ACCURACY_COARSE);\n        criteria.setPowerRequirement(Criteria.POWER_MEDIUM);\n\n        if (options != null) initFromOptions();\n    }\n\n    public synchronized static GoogleMapImpl create(Context context, GoogleMapOptions options) {\n        return new GoogleMapImpl(context, options);\n    }\n\n    private void initFromOptions() {\n        try {\n            uiSettings.setCompassEnabled(options.getCompassEnabled());\n            uiSettings.setRotateGesturesEnabled(options.isRotateGesturesEnabled());\n            uiSettings.setTiltGesturesEnabled(options.isTiltGesturesEnabled());\n            uiSettings.setScrollGesturesEnabled(options.isScrollGesturesEnabled());\n            uiSettings.setZoomControlsEnabled(options.isZoomControlsEnabled());\n            uiSettings.setZoomGesturesEnabled(options.isZoomGesturesEnabled());\n            if (options.getCamera() != null) {\n                backendMap.applyCameraUpdate(MapPositionCameraUpdate.directMapPosition(GmsMapsTypeHelper.fromCameraPosition(options.getCamera())));\n            }\n        } catch (RemoteException e) {\n            // Never happens: not remote\n        }\n    }\n\n    public void onDestroy() {\n        backendMap.destroy();\n    }\n\n    @Override\n    public void onLowMemory() throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: onLowMemory\");\n\n    }\n\n    @Override\n    public boolean useViewLifecycleWhenInFragment() throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: useViewLifecycleWhenInFragment\");\n        return false;\n    }\n\n    @Override\n    public void onSaveInstanceState(Bundle outState) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: onSaveInstanceState\");\n\n    }\n\n    @Override\n    public void setContentDescription(String desc) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: setContentDescription\");\n\n    }\n\n    @Override\n    public void snapshotForTest(ISnapshotReadyCallback callback) throws RemoteException {\n\n    }\n\n    @Override\n    public void onEnterAmbient(Bundle bundle) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: onEnterAmbient\");\n\n    }\n\n    @Override\n    public void onExitAmbient() throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: onExitAmbient\");\n\n    }\n\n    @Override\n    public void setOnGroundOverlayClickListener(IOnGroundOverlayClickListener listener) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: setOnGroundOverlayClickListener\");\n    }\n\n    @Override\n    public void setOnPolygonClickListener(IOnPolygonClickListener listener) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: setOnPolygonClickListener\");\n    }\n\n    @Override\n    public void setOnPolylineClickListener(IOnPolylineClickListener listener) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: setOnPolylineClickListener\");\n    }\n\n    @Override\n    public void setOnCircleClickListener(IOnCircleClickListener listener) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: setCircleClickListener\");\n    }\n\n    @Override\n    public boolean setMapStyle(MapStyleOptions options) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: setMapStyle\");\n        return true;\n    }\n\n    @Override\n    public void setMinZoomPreference(float minZoom) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: setMinZoomPreference\");\n\n    }\n\n    @Override\n    public void setMaxZoomPreference(float maxZoom) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: setMaxZoomPreference\");\n\n    }\n\n    @Override\n    public void resetMinMaxZoomPreference() throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: resetMinMaxZoomPreference\");\n\n    }\n\n    @Override\n    public void setLatLngBoundsForCameraTarget(LatLngBounds bounds) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: setLatLngBoundsForCameraTarget\");\n\n    }\n\n    public void onResume() {\n        backendMap.onResume();\n    }\n\n    public void onPause() {\n        backendMap.onPause();\n    }\n\n    public View getView() {\n        return backendMap.getView();\n    }\n\n    private String getNextMarkerId() {\n        return \"m\" + markerCounter++;\n    }\n\n    private String getNextCircleId() {\n        return \"c\" + circleCounter++;\n    }\n\n    private String getNextPolylineId() {\n        return \"l\" + polylineCounter++;\n    }\n\n    private String getNextPolygonId() {\n        return \"p\" + polygonCounter++;\n    }\n    \n    /*\n    Camera\n     */\n\n    @Override\n    public CameraPosition getCameraPosition() throws RemoteException {\n        return GmsMapsTypeHelper.toCameraPosition(backendMap.getMapPosition());\n    }\n\n    @Override\n    public float getMaxZoomLevel() throws RemoteException {\n        return (float) backendMap.getViewport().limitScale(Double.MIN_VALUE);\n    }\n\n    @Override\n    public float getMinZoomLevel() throws RemoteException {\n        return (float) backendMap.getViewport().limitScale(Double.MAX_VALUE);\n    }\n\n    @Override\n    public void moveCamera(IObjectWrapper cameraUpdate) throws RemoteException {\n        CameraUpdate camUpdate = (CameraUpdate) ObjectWrapper.unwrap(cameraUpdate);\n        backendMap.applyCameraUpdate(camUpdate);\n    }\n\n    @Override\n    public void animateCamera(IObjectWrapper cameraUpdate) throws RemoteException {\n        CameraUpdate camUpdate = (CameraUpdate) ObjectWrapper.unwrap(cameraUpdate);\n        backendMap.applyCameraUpdateAnimated(camUpdate, 1000);\n    }\n\n    @Override\n    public void animateCameraWithCallback(IObjectWrapper cameraUpdate, ICancelableCallback callback)\n            throws RemoteException {\n        CameraUpdate camUpdate = (CameraUpdate) ObjectWrapper.unwrap(cameraUpdate);\n        backendMap.applyCameraUpdateAnimated(camUpdate, 1000);\n    }\n\n    @Override\n    public void animateCameraWithDurationAndCallback(IObjectWrapper cameraUpdate, int duration,\n                                                     ICancelableCallback callback) throws RemoteException {\n        CameraUpdate camUpdate = (CameraUpdate) ObjectWrapper.unwrap(cameraUpdate);\n        backendMap.applyCameraUpdateAnimated(camUpdate, duration);\n    }\n\n    @Override\n    public IProjectionDelegate getProjection() throws RemoteException {\n        return projection;\n    }\n\n    @Override\n    public void stopAnimation() throws RemoteException {\n        backendMap.stopAnimation();\n    }\n\n    @Override\n    public void onCameraUpdate(CameraPosition cameraPosition) {\n        if (onCameraChangeListener != null) {\n            try {\n                onCameraChangeListener.onCameraChange(cameraPosition);\n            } catch (RemoteException e) {\n                Log.w(TAG, e);\n            }\n        }\n    }\n    \n    /*\n    Markers, polylines, polygons, overlays, etc\n     */\n\n    @Override\n    public ICircleDelegate addCircle(CircleOptions options) throws RemoteException {\n        return backendMap.add(new CircleImpl(getNextCircleId(), options, this));\n    }\n\n    @Override\n    public IPolylineDelegate addPolyline(PolylineOptions options) throws RemoteException {\n        return backendMap.add(new PolylineImpl(getNextPolylineId(), options, this));\n    }\n\n    @Override\n    public IPolygonDelegate addPolygon(PolygonOptions options) throws RemoteException {\n        return backendMap.add(new PolygonImpl(getNextPolygonId(), options, this));\n    }\n\n    @Override\n    public IMarkerDelegate addMarker(MarkerOptions options) throws RemoteException {\n        return backendMap.add(new MarkerImpl(getNextMarkerId(), options, this));\n    }\n\n    @Override\n    public IGroundOverlayDelegate addGroundOverlay(GroundOverlayOptions options)\n            throws RemoteException {\n        Log.d(TAG, \"not yet usable: addGroundOverlay\");\n        return new GroundOverlayImpl(options); // TODO\n    }\n\n    @Override\n    public ITileOverlayDelegate addTileOverlay(TileOverlayOptions options) throws RemoteException {\n        Log.d(TAG, \"not yet usable: addTileOverlay\");\n        return new TileOverlayImpl(); // TODO\n    }\n\n    @Override\n    public void setInfoWindowAdapter(IInfoWindowAdapter adapter) throws RemoteException {\n        Log.d(TAG, \"not yet usable: setInfoWindowAdapter\");\n    }\n\n    @Override\n    public void clear() throws RemoteException {\n        backendMap.clear();\n        markerCounter = 0;\n        circleCounter = 0;\n        polylineCounter = 0;\n        polygonCounter = 0;\n    }\n\n    @Override\n    public void update(Markup markup) {\n        backendMap.update(markup);\n    }\n\n    @Override\n    public void remove(Markup markup) {\n        backendMap.remove(markup);\n    }\n\n    @Override\n    public boolean onClick(Markup markup) {\n        if (markup instanceof IMarkerDelegate) {\n            if (onMarkerClickListener != null) {\n                try {\n                    if (onMarkerClickListener.onMarkerClick((IMarkerDelegate) markup))\n                        return true;\n                } catch (RemoteException e) {\n                    Log.w(TAG, e);\n                }\n            }\n            // TODO: open InfoWindow\n        }\n        return false;\n    }\n\n    @Override\n    public void onDragStart(Markup markup) {\n        backendMap.setScrollGesturesEnabled(false);\n        backendMap.setRotateGesturesEnabled(false);\n        backendMap.setTiltGesturesEnabled(false);\n        backendMap.setZoomGesturesEnabled(false);\n        if (markup instanceof IMarkerDelegate) {\n            if (onMarkerDragListener != null) {\n                try {\n                    onMarkerDragListener.onMarkerDragStart((IMarkerDelegate) markup);\n                } catch (RemoteException e) {\n                    Log.w(TAG, e);\n                }\n            }\n        }\n    }\n\n    @Override\n    public void onDragStop(Markup markup) {\n        try {\n            backendMap.setScrollGesturesEnabled(uiSettings.isScrollGesturesEnabled());\n            backendMap.setRotateGesturesEnabled(uiSettings.isRotateGesturesEnabled());\n            backendMap.setTiltGesturesEnabled(uiSettings.isTiltGesturesEnabled());\n            backendMap.setZoomGesturesEnabled(uiSettings.isZoomGesturesEnabled());\n        } catch (RemoteException e) {\n            // Never happens, is local.\n        }\n        if (markup instanceof IMarkerDelegate) {\n            if (onMarkerDragListener != null) {\n                try {\n                    onMarkerDragListener.onMarkerDragEnd((IMarkerDelegate) markup);\n                } catch (RemoteException e) {\n                    Log.w(TAG, e);\n                }\n            }\n        }\n    }\n\n    @Override\n    public void onDragProgress(Markup markup) {\n        if (markup instanceof IMarkerDelegate) {\n            if (onMarkerDragListener != null) {\n                try {\n                    onMarkerDragListener.onMarkerDrag((IMarkerDelegate) markup);\n                } catch (RemoteException e) {\n                    Log.w(TAG, e);\n                }\n            }\n        }\n    }\n    \n    /*\n    Map options\n     */\n\n    @Override\n    public int getMapType() throws RemoteException {\n        return 0;\n    }\n\n    @Override\n    public void setMapType(int type) throws RemoteException {\n\n    }\n\n    @Override\n    public boolean isTrafficEnabled() throws RemoteException {\n        return false;\n    }\n\n    @Override\n    public void setTrafficEnabled(boolean traffic) throws RemoteException {\n        Log.w(TAG, \"Traffic not yet supported\");\n    }\n\n    @Override\n    public boolean isIndoorEnabled() throws RemoteException {\n        return false;\n    }\n\n    @Override\n    public void setIndoorEnabled(boolean indoor) throws RemoteException {\n        Log.w(TAG, \"Indoor not yet supported\");\n    }\n\n    @Override\n    public boolean isMyLocationEnabled() throws RemoteException {\n        return false;\n    }\n\n    @Override\n    public void setMyLocationEnabled(boolean myLocation) throws RemoteException {\n        Log.w(TAG, \"MyLocation not yet supported\");\n        boolean hasPermission = ContextCompat.checkSelfPermission(context, ACCESS_COARSE_LOCATION) == PERMISSION_GRANTED\n                || ContextCompat.checkSelfPermission(context, ACCESS_FINE_LOCATION) == PERMISSION_GRANTED;\n        if (!hasPermission) {\n            throw new SecurityException(\"Neither \" + ACCESS_COARSE_LOCATION + \" nor \" + ACCESS_FINE_LOCATION + \" granted.\");\n        }\n        LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);\n        if (myLocation) {\n            locationManager.requestLocationUpdates(5000, 10, criteria, listener, Looper.getMainLooper());\n        } else {\n            locationManager.removeUpdates(listener);\n        }\n    }\n\n    @Override\n    public boolean isBuildingsEnabled() throws RemoteException {\n        return backendMap.hasBuilding();\n    }\n\n    @Override\n    public void setBuildingsEnabled(boolean buildingsEnabled) throws RemoteException {\n        backendMap.setBuildings(buildingsEnabled);\n    }\n    \n    /*\n    Ui Settings\n     */\n\n    @Override\n    public IUiSettingsDelegate getUiSettings() throws RemoteException {\n        Log.d(TAG, \"getUiSettings: \" + uiSettings);\n        return uiSettings;\n    }\n\n    @Override\n    public void onUiSettingsChanged(UiSettingsImpl settings) throws RemoteException {\n        if (settings.isCompassEnabled()) {\n            Log.w(TAG, \"Compass not yet supported\");\n        }\n        if (settings.isMyLocationButtonEnabled()) {\n            Log.w(TAG, \"MyLocationButton not yet supported\");\n        }\n        if (settings.isZoomControlsEnabled()) {\n            Log.w(TAG, \"ZoomControls not yet supported\");\n        }\n        backendMap.setScrollGesturesEnabled(settings.isScrollGesturesEnabled());\n        backendMap.setRotateGesturesEnabled(settings.isRotateGesturesEnabled());\n        backendMap.setTiltGesturesEnabled(settings.isTiltGesturesEnabled());\n        backendMap.setZoomGesturesEnabled(settings.isZoomGesturesEnabled());\n    }\n    \n    /*\n    Listener and callback setters\n     */\n\n    @Override\n    public void setOnCameraChangeListener(IOnCameraChangeListener listener) throws RemoteException {\n        Log.d(TAG, \"setOnCameraChangeListener\");\n        this.onCameraChangeListener = listener;\n    }\n\n    @Override\n    public void setOnMapClickListener(IOnMapClickListener listener) throws RemoteException {\n        Log.d(TAG, \"setOnMapClickListener: not supported\");\n    }\n\n    @Override\n    public void setOnMapLongClickListener(IOnMapLongClickListener listener) throws RemoteException {\n        Log.d(TAG, \"setOnMapLongClickListener: not supported\");\n    }\n\n    @Override\n    public void setOnMarkerClickListener(IOnMarkerClickListener listener) throws RemoteException {\n        Log.d(TAG, \"setOnMarkerClickListener\");\n        this.onMarkerClickListener = listener;\n    }\n\n    @Override\n    public void setOnMarkerDragListener(IOnMarkerDragListener listener) throws RemoteException {\n        Log.d(TAG, \"setOnMarkerDragListener\");\n        this.onMarkerDragListener = listener;\n    }\n\n    @Override\n    public void setOnInfoWindowClickListener(IOnInfoWindowClickListener listener)\n            throws RemoteException {\n        Log.d(TAG, \"setOnInfoWindowClickListener: not supported\");\n    }\n\n    @Override\n    public void setOnMyLocationChangeListener(IOnMyLocationChangeListener listener)\n            throws RemoteException {\n        Log.d(TAG, \"setOnMyLocationChangeListener\");\n        this.onMyLocationChangeListener = listener;\n    }\n\n    @Override\n    public void setOnMyLocationButtonClickListener(IOnMyLocationButtonClickListener listener)\n            throws RemoteException {\n        Log.d(TAG, \"setOnMyLocationButtonClickListener: not supported\");\n    }\n\n    @Override\n    public void setOnMapLoadedCallback(final IOnMapLoadedCallback callback) throws RemoteException {\n        Log.d(TAG, \"setOnMapLoadedCallback\");\n        new Handler(context.getMainLooper()).postDelayed(new Runnable() {\n            @Override\n            public void run() {\n                Log.d(TAG, \"Announce map loaded\");\n                if (callback != null) {\n                    try {\n                        callback.onMapLoaded();\n                    } catch (RemoteException e) {\n                        Log.w(TAG, e);\n                    }\n                }\n            }\n        }, 5000);\n    }\n\n    @Override\n    public void setWatermarkEnabled(boolean watermark) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: setWatermarkEnabled\");\n\n    }\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: onCreate\");\n\n    }\n\n    @Override\n    public void setCameraMoveStartedListener(IOnCameraMoveStartedListener listener) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: setCameraMoveStartedListener\");\n\n    }\n\n    @Override\n    public void setCameraMoveListener(IOnCameraMoveListener listener) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: setCameraMoveListener\");\n\n    }\n\n    @Override\n    public void setCameraMoveCanceledListener(IOnCameraMoveCanceledListener listener) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: setCameraMoveCanceledListener\");\n\n    }\n\n    @Override\n    public void setCameraIdleListener(IOnCameraIdleListener listener) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: setCameraIdleListener\");\n\n    }\n\n    @Override\n    public void setOnInfoWindowLongClickListener(IOnInfoWindowLongClickListener listener) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: setOnInfoWindowLongClickListener\");\n    }\n\n    @Override\n    public void setOnInfoWindowCloseListener(IOnInfoWindowCloseListener listener) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: setOnInfoWindowCloseListener\");\n    }\n\n    @Override\n    public void onStart() throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: onStart\");\n\n    }\n\n    @Override\n    public void onStop() throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: onStop\");\n\n    }\n\n    @Override\n    public void setOnMyLocationClickListener(IOnMyLocationClickListener listener) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: setOnMyLocationClickListener\");\n    }\n    \n    /*\n    Misc\n     */\n\n    @Override\n    public IObjectWrapper getTestingHelper() throws RemoteException {\n        return null;\n    }\n\n    @Override\n    public void snapshot(ISnapshotReadyCallback callback, IObjectWrapper bitmap)\n            throws RemoteException {\n        Bitmap b = (Bitmap) ObjectWrapper.unwrap(bitmap);\n        Log.d(TAG, \"snapshot!: \" + b);\n        backendMap.snapshot(b, callback);\n    }\n\n    @Override\n    public void setPadding(int left, int top, int right, int bottom) throws RemoteException {\n        getView().setPadding(left, top, right, bottom);\n    }\n\n    @Override\n    public Location getMyLocation() throws RemoteException {\n        return myLocation;\n    }\n\n    @Override\n    public void setLocationSource(ILocationSourceDelegate locationSource) throws RemoteException {\n        Log.d(TAG, \"setLocationSource: \" + locationSource);\n    }\n\n    @Override\n    public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {\n        if (super.onTransact(code, data, reply, flags)) return true;\n        Log.d(TAG, \"onTransact [unknown]: \" + code + \", \" + data + \", \" + flags);\n        return false;\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/src/main/java/org/microg/gms/maps/vtm/MapFragmentImpl.java",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 org.microg.gms.maps.vtm;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.os.Parcel;\nimport android.os.RemoteException;\nimport android.util.Log;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.dynamic.ObjectWrapper;\nimport com.google.android.gms.maps.GoogleMapOptions;\nimport com.google.android.gms.maps.internal.IGoogleMapDelegate;\nimport com.google.android.gms.maps.internal.IMapFragmentDelegate;\nimport com.google.android.gms.maps.internal.IOnMapReadyCallback;\n\npublic class MapFragmentImpl extends IMapFragmentDelegate.Stub {\n    private static final String TAG = \"GmsMapFragImpl\";\n\n    private GoogleMapImpl map;\n    private GoogleMapOptions options;\n    private Activity activity;\n\n    public MapFragmentImpl(Activity activity) {\n        this.activity = activity;\n    }\n\n    private GoogleMapImpl myMap() {\n        if (map == null) {\n            Log.d(TAG, \"GoogleMap instance created\");\n            LayoutInflater inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);\n            map = GoogleMapImpl.create(inflater.getContext(), options);\n        }\n        return map;\n    }\n\n    @Override\n    public IGoogleMapDelegate getMap() throws RemoteException {\n        Log.d(TAG, \"getMap\");\n        return myMap();\n    }\n\n    @Override\n    public void onInflate(IObjectWrapper activity, GoogleMapOptions options,\n                          Bundle savedInstanceState) throws RemoteException {\n        if (options != null) this.options = options;\n        Log.d(TAG, \"onInflate\");\n    }\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) throws RemoteException {\n        Log.d(TAG, \"onCreate\");\n        //myMap().onCreate(savedInstanceState);\n        // TOOD: Certainly does not belong here and this way\n        Bundle mapState = savedInstanceState.getBundle(\"map_state\");\n        if (mapState != null) {\n            mapState.setClassLoader(GoogleMapOptions.class.getClassLoader());\n            GoogleMapOptions options = mapState.getParcelable(\"MapOptions\");\n            if (options != null) this.options = options;\n        }\n    }\n\n    @Override\n    public IObjectWrapper onCreateView(IObjectWrapper layoutInflater, IObjectWrapper container,\n                                       Bundle savedInstanceState) throws RemoteException {\n        Log.d(TAG, \"onCreateView\");\n        if (map == null) {\n            LayoutInflater inflater = (LayoutInflater) ObjectWrapper.unwrap(layoutInflater);\n            map = GoogleMapImpl.create(inflater.getContext(), options);\n            //map.onCreate(savedInstanceState);\n        } else {\n            View view = map.getView();\n            if (view.getParent() instanceof ViewGroup) {\n                ((ViewGroup) view.getParent()).removeView(view);\n            }\n        }\n        return ObjectWrapper.wrap(myMap().getView());\n    }\n\n    @Override\n    public void onResume() throws RemoteException {\n        Log.d(TAG, \"onResume\");\n        myMap().onResume();\n    }\n\n    @Override\n    public void onPause() throws RemoteException {\n        Log.d(TAG, \"onPause\");\n        myMap().onPause();\n    }\n\n    @Override\n    public void onDestroyView() throws RemoteException {\n        Log.d(TAG, \"onDestroyView\");\n    }\n\n    @Override\n    public void onDestroy() throws RemoteException {\n        Log.d(TAG, \"onDestroy\");\n        myMap().onDestroy();\n    }\n\n    @Override\n    public void onLowMemory() throws RemoteException {\n        Log.d(TAG, \"onLowMemory\");\n    }\n\n    @Override\n    public void onEnterAmbient(Bundle bundle) throws RemoteException {\n        map.onEnterAmbient(bundle);\n    }\n\n    @Override\n    public void onExitAmbient() throws RemoteException {\n        map.onExitAmbient();\n    }\n\n    @Override\n    public void onStart() throws RemoteException {\n        map.onStart();\n    }\n\n    @Override\n    public void onStop() throws RemoteException {\n        map.onStop();\n    }\n\n    @Override\n    public void onSaveInstanceState(Bundle outState) throws RemoteException {\n        Log.d(TAG, \"onSaveInstanceState: \" + outState);\n        //myMap().onSaveInstanceState(outState);\n    }\n\n    @Override\n    public boolean isReady() throws RemoteException {\n        Log.d(TAG, \"isReady\");\n        return map != null;\n    }\n\n    @Override\n    public void getMapAsync(final IOnMapReadyCallback callback) throws RemoteException {\n        new Handler(activity.getMainLooper()).post(new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    callback.onMapReady(myMap());\n                } catch (RemoteException e) {\n                    Log.w(TAG, e);\n                }\n            }\n        });\n    }\n\n    @Override\n    public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {\n        if (super.onTransact(code, data, reply, flags)) return true;\n        Log.d(TAG, \"onTransact [unknown]: \" + code + \", \" + data + \", \" + flags);\n        return false;\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/src/main/java/org/microg/gms/maps/vtm/MapViewImpl.java",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 org.microg.gms.maps.vtm;\n\nimport android.content.Context;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.os.Parcel;\nimport android.os.RemoteException;\nimport android.util.Log;\nimport android.view.LayoutInflater;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.dynamic.ObjectWrapper;\nimport com.google.android.gms.maps.GoogleMapOptions;\nimport com.google.android.gms.maps.internal.IGoogleMapDelegate;\nimport com.google.android.gms.maps.internal.IMapViewDelegate;\nimport com.google.android.gms.maps.internal.IOnMapReadyCallback;\n\npublic class MapViewImpl extends IMapViewDelegate.Stub {\n    private static final String TAG = \"GmsMapViewImpl\";\n\n    private GoogleMapImpl map;\n    private GoogleMapOptions options;\n    private Context context;\n    private IOnMapReadyCallback readyCallback;\n\n    public MapViewImpl(Context context, GoogleMapOptions options) {\n        this.context = context;\n        this.options = options;\n    }\n\n    private GoogleMapImpl myMap() {\n        if (map == null) {\n            Log.d(TAG, \"GoogleMap instance created\");\n            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);\n            map = GoogleMapImpl.create(inflater.getContext(), options);\n        }\n        return map;\n    }\n\n    @Override\n    public IGoogleMapDelegate getMap() throws RemoteException {\n        Log.d(TAG, \"getMap\");\n        return myMap();\n    }\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) throws RemoteException {\n        //myMap().onCreate(savedInstanceState);\n        Log.d(TAG, \"onCreate\");\n    }\n\n    @Override\n    public void onResume() throws RemoteException {\n        Log.d(TAG, \"onResume\");\n\n        myMap().onResume();\n        if (readyCallback != null) {\n            try {\n                readyCallback.onMapReady(map);\n                readyCallback = null;\n            } catch (Exception e) {\n                Log.w(TAG, e);\n            }\n        }\n    }\n\n    @Override\n    public void onPause() throws RemoteException {\n        Log.d(TAG, \"onPause\");\n        myMap().onPause();\n    }\n\n    @Override\n    public void onDestroy() throws RemoteException {\n        Log.d(TAG, \"onDestroy\");\n        myMap().onDestroy();\n    }\n\n    @Override\n    public void onLowMemory() throws RemoteException {\n        Log.d(TAG, \"onLowMemory\");\n    }\n\n    @Override\n    public void onSaveInstanceState(Bundle outState) throws RemoteException {\n        Log.d(TAG, \"onSaveInstanceState: \" + outState);\n    }\n\n    @Override\n    public IObjectWrapper getView() throws RemoteException {\n        return ObjectWrapper.wrap(myMap().getView());\n    }\n\n    @Override\n    public void getMapAsync(final IOnMapReadyCallback callback) throws RemoteException {\n        Log.d(TAG, \"getMapAsync\");\n        new Handler(context.getMainLooper()).post(new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    callback.onMapReady(myMap());\n                } catch (RemoteException e) {\n                    Log.w(TAG, e);\n                }\n            }\n        });\n    }\n\n    @Override\n    public void onEnterAmbient(Bundle bundle) throws RemoteException {\n        map.onEnterAmbient(bundle);\n    }\n\n    @Override\n    public void onExitAmbient() throws RemoteException {\n        map.onExitAmbient();\n    }\n\n    @Override\n    public void onStart() throws RemoteException {\n        map.onStart();\n    }\n\n    @Override\n    public void onStop() throws RemoteException {\n        map.onStop();\n    }\n\n    @Override\n    public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {\n        if (super.onTransact(code, data, reply, flags)) return true;\n        Log.d(TAG, \"onTransact [unknown]: \" + code + \", \" + data + \", \" + flags);\n        return false;\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/src/main/java/org/microg/gms/maps/vtm/ProjectionImpl.java",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 org.microg.gms.maps.vtm;\n\nimport android.os.RemoteException;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.dynamic.ObjectWrapper;\nimport com.google.android.gms.maps.internal.IProjectionDelegate;\nimport com.google.android.gms.maps.model.LatLng;\nimport com.google.android.gms.maps.model.VisibleRegion;\n\nimport org.oscim.core.Point;\nimport org.oscim.map.Viewport;\n\npublic class ProjectionImpl extends IProjectionDelegate.Stub {\n    private Viewport viewport;\n    private float[] extents = new float[8];\n\n    public ProjectionImpl(Viewport viewport) {\n        this.viewport = viewport;\n    }\n\n    @Override\n    public LatLng fromScreenLocation(IObjectWrapper obj) throws RemoteException {\n        Point point = GmsMapsTypeHelper\n                .fromPoint((android.graphics.Point) ObjectWrapper.unwrap(obj));\n        return GmsMapsTypeHelper\n                .toLatLng(viewport.fromScreenPoint((float) point.x, (float) point.y));\n    }\n\n    @Override\n    public IObjectWrapper toScreenLocation(LatLng latLng) throws RemoteException {\n        Point point = new Point();\n        viewport.toScreenPoint(GmsMapsTypeHelper.fromLatLng(latLng), point);\n        return ObjectWrapper.wrap(GmsMapsTypeHelper.toPoint(point));\n    }\n\n    @Override\n    public VisibleRegion getVisibleRegion() throws RemoteException {\n        viewport.getMapExtents(extents, 0);\n        // TODO: Support non-flat map extents\n        return new VisibleRegion(GmsMapsTypeHelper.toLatLngBounds(viewport.getBBox(null, 0)));\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/src/main/java/org/microg/gms/maps/vtm/ResourcesContainer.java",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 org.microg.gms.maps.vtm;\n\nimport android.content.res.Resources;\n\npublic class ResourcesContainer {\n    private static Resources resources;\n\n    public static void set(Resources resources) {\n        ResourcesContainer.resources = resources;\n    }\n\n    public static Resources get() {\n        if (resources == null) {\n            throw new IllegalStateException(\"Resources have not been initialized\");\n        } else {\n            return resources;\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/src/main/java/org/microg/gms/maps/vtm/StreetViewPanoramaFragmentImpl.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.maps.vtm;\n\nimport android.app.Activity;\nimport android.os.Bundle;\nimport android.os.RemoteException;\nimport android.widget.TextView;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.dynamic.ObjectWrapper;\nimport com.google.android.gms.maps.StreetViewPanoramaOptions;\nimport com.google.android.gms.maps.internal.IOnStreetViewPanoramaReadyCallback;\nimport com.google.android.gms.maps.internal.IStreetViewPanoramaDelegate;\nimport com.google.android.gms.maps.internal.IStreetViewPanoramaFragmentDelegate;\n\npublic class StreetViewPanoramaFragmentImpl extends IStreetViewPanoramaFragmentDelegate.Stub {\n\n    private Activity mActivity;\n\n    public StreetViewPanoramaFragmentImpl(Activity activity) {\n        this.mActivity = activity;\n    }\n\n    @Override\n    public IStreetViewPanoramaDelegate getStreetViewPanorama() throws RemoteException {\n        return null;\n    }\n\n    @Override\n    public void onInflate(IObjectWrapper activity, StreetViewPanoramaOptions options, Bundle savedInstanceState) throws RemoteException {\n\n    }\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) throws RemoteException {\n\n    }\n\n    @Override\n    public IObjectWrapper onCreateView(IObjectWrapper layoutInflater, IObjectWrapper container, Bundle savedInstanceState) throws RemoteException {\n        return ObjectWrapper.wrap(new TextView(mActivity));\n    }\n\n    @Override\n    public void onResume() throws RemoteException {\n\n    }\n\n    @Override\n    public void onPause() throws RemoteException {\n\n    }\n\n    @Override\n    public void onDestroyView() throws RemoteException {\n\n    }\n\n    @Override\n    public void onDestroy() throws RemoteException {\n\n    }\n\n    @Override\n    public void onLowMemory() throws RemoteException {\n\n    }\n\n    @Override\n    public void onSaveInstanceState(Bundle outState) throws RemoteException {\n\n    }\n\n    @Override\n    public boolean isReady() throws RemoteException {\n        return false;\n    }\n\n    @Override\n    public void getStreetViewPanoramaAsync(IOnStreetViewPanoramaReadyCallback callback) throws RemoteException {\n\n    }\n\n    @Override\n    public void onStart() throws RemoteException {\n\n    }\n\n    @Override\n    public void onStop() throws RemoteException {\n\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/src/main/java/org/microg/gms/maps/vtm/StreetViewPanoramaViewImpl.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.maps.vtm;\n\nimport android.app.Activity;\nimport android.os.Bundle;\nimport android.os.RemoteException;\nimport android.widget.TextView;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.dynamic.ObjectWrapper;\nimport com.google.android.gms.maps.internal.IOnStreetViewPanoramaReadyCallback;\nimport com.google.android.gms.maps.internal.IStreetViewPanoramaDelegate;\nimport com.google.android.gms.maps.internal.IStreetViewPanoramaViewDelegate;\n\npublic class StreetViewPanoramaViewImpl extends IStreetViewPanoramaViewDelegate.Stub {\n\n    private Activity mActivity;\n\n    public StreetViewPanoramaViewImpl(Activity activity) {\n        this.mActivity = activity;\n    }\n\n    @Override\n    public IStreetViewPanoramaDelegate getStreetViewPanorama() throws RemoteException {\n        return null;\n    }\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) throws RemoteException {\n\n    }\n\n    @Override\n    public void onResume() throws RemoteException {\n\n    }\n\n    @Override\n    public void onPause() throws RemoteException {\n\n    }\n\n    @Override\n    public void onDestroy() throws RemoteException {\n\n    }\n\n    @Override\n    public void onLowMemory() throws RemoteException {\n\n    }\n\n    @Override\n    public void onSaveInstanceState(Bundle outState) throws RemoteException {\n\n    }\n\n    @Override\n    public IObjectWrapper getView() throws RemoteException {\n        return ObjectWrapper.wrap(new TextView(mActivity));\n    }\n\n    @Override\n    public void getStreetViewPanoramaAsync(IOnStreetViewPanoramaReadyCallback callback) throws RemoteException {\n\n    }\n\n    @Override\n    public void onStart() throws RemoteException {\n\n    }\n\n    @Override\n    public void onStop() throws RemoteException {\n\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/src/main/java/org/microg/gms/maps/vtm/UiSettingsImpl.java",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 org.microg.gms.maps.vtm;\n\nimport android.os.RemoteException;\nimport com.google.android.gms.maps.internal.IUiSettingsDelegate;\n\npublic class UiSettingsImpl extends IUiSettingsDelegate.Stub {\n    private boolean zoomControlsEnabled;\n    private boolean compassEnabled;\n    private boolean myLocationButtonEnabled;\n    private boolean scrollGesturesEnabled = true;\n    private boolean zoomGesturesEnabled = true;\n    private boolean tiltGesturesEnabled = true;\n    private boolean rotateGesturesEnabled = true;\n    private boolean allGesturesEnabled = true;\n    private boolean indoorLevelPickerEnabled = false;\n    private boolean mapToolbarEnabled = false;\n    private boolean scrollGesturesEnabledDuringRotateOrZoom = true;\n    \n    private UiSettingsListener listener;\n\n    public UiSettingsImpl() {\n    }\n\n    public UiSettingsImpl(UiSettingsListener listener) {\n        this.listener = listener;\n    }\n\n    public void setListener(UiSettingsListener listener) {\n        this.listener = listener;\n    }\n\n    @Override\n    public void setZoomControlsEnabled(boolean zoomControlsEnabled) throws RemoteException {\n        this.zoomControlsEnabled = zoomControlsEnabled;\n        listener.onUiSettingsChanged(this);\n    }\n\n    @Override\n    public void setCompassEnabled(boolean compassEnabled) throws RemoteException {\n        this.compassEnabled = compassEnabled;\n        listener.onUiSettingsChanged(this);\n    }\n\n    @Override\n    public void setMyLocationButtonEnabled(boolean myLocationButtonEnabled) throws RemoteException {\n        this.myLocationButtonEnabled = myLocationButtonEnabled;\n        listener.onUiSettingsChanged(this);\n    }\n\n    @Override\n    public void setScrollGesturesEnabled(boolean scrollGesturesEnabled) throws RemoteException {\n        this.scrollGesturesEnabled = scrollGesturesEnabled;\n        listener.onUiSettingsChanged(this);\n    }\n\n    @Override\n    public void setZoomGesturesEnabled(boolean zoomGestures) throws RemoteException {\n        this.zoomGesturesEnabled = zoomGestures;\n        listener.onUiSettingsChanged(this);\n    }\n\n    @Override\n    public void setTiltGesturesEnabled(boolean tiltGesturesEnabled) throws RemoteException {\n        this.tiltGesturesEnabled = tiltGesturesEnabled;\n        listener.onUiSettingsChanged(this);\n    }\n\n    @Override\n    public void setRotateGesturesEnabled(boolean rotateGesturesEnabled) throws RemoteException {\n        this.rotateGesturesEnabled = rotateGesturesEnabled;\n        listener.onUiSettingsChanged(this);\n    }\n\n    @Override\n    public void setAllGesturesEnabled(boolean gestures) throws RemoteException {\n        scrollGesturesEnabled = gestures;\n        zoomGesturesEnabled = gestures;\n        tiltGesturesEnabled = gestures;\n        rotateGesturesEnabled = gestures;\n        listener.onUiSettingsChanged(this);\n    }\n\n    @Override\n    public boolean isZoomControlsEnabled() throws RemoteException {\n        return zoomControlsEnabled;\n    }\n\n    @Override\n    public boolean isCompassEnabled() throws RemoteException {\n        return compassEnabled;\n    }\n\n    @Override\n    public boolean isMyLocationButtonEnabled() throws RemoteException {\n        return myLocationButtonEnabled;\n    }\n\n    @Override\n    public boolean isScrollGesturesEnabled() throws RemoteException {\n        return scrollGesturesEnabled;\n    }\n\n    @Override\n    public boolean isZoomGesturesEnabled() throws RemoteException {\n        return zoomGesturesEnabled;\n    }\n\n    @Override\n    public boolean isTiltGesturesEnabled() throws RemoteException {\n        return tiltGesturesEnabled;\n    }\n\n    @Override\n    public boolean isRotateGesturesEnabled() throws RemoteException {\n        return rotateGesturesEnabled;\n    }\n\n    @Override\n    public void setIndoorLevelPickerEnabled(boolean indoorLevelPicker) throws RemoteException {\n        this.indoorLevelPickerEnabled = indoorLevelPicker;\n        listener.onUiSettingsChanged(this);\n    }\n\n    @Override\n    public boolean isIndoorLevelPickerEnabled() throws RemoteException {\n        return indoorLevelPickerEnabled;\n    }\n\n    @Override\n    public void setMapToolbarEnabled(boolean mapToolbar) throws RemoteException {\n        this.mapToolbarEnabled = mapToolbar;\n        listener.onUiSettingsChanged(this);\n    }\n\n    @Override\n    public boolean isMapToolbarEnabled() throws RemoteException {\n        return mapToolbarEnabled;\n    }\n\n    @Override\n    public void setScrollGesturesEnabledDuringRotateOrZoom(boolean scrollDuringZoom) throws RemoteException {\n        this.scrollGesturesEnabledDuringRotateOrZoom = scrollDuringZoom;\n        listener.onUiSettingsChanged(this);\n    }\n\n    @Override\n    public boolean isScrollGesturesEnabledDuringRotateOrZoom() throws RemoteException {\n        return scrollGesturesEnabledDuringRotateOrZoom;\n    }\n\n    public static interface UiSettingsListener {\n        void onUiSettingsChanged(UiSettingsImpl settings) throws RemoteException;\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/src/main/java/org/microg/gms/maps/vtm/bitmap/AbstractBitmapDescriptor.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.maps.vtm.bitmap;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\n\npublic abstract class AbstractBitmapDescriptor {\n\n    private Bitmap bitmap;\n\n    protected abstract Bitmap generateBitmap(Context context);\n\n    public Bitmap loadBitmap(Context context) {\n        if (bitmap == null) {\n            synchronized (this) {\n                if (bitmap == null)\n                    bitmap = generateBitmap(context);\n            }\n        }\n        return bitmap;\n    }\n\n    public Bitmap getBitmap() {\n        return bitmap;\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/src/main/java/org/microg/gms/maps/vtm/bitmap/AssetBitmapDescriptor.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.maps.vtm.bitmap;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\n\nimport java.io.IOException;\n\npublic class AssetBitmapDescriptor extends AbstractBitmapDescriptor {\n    private String assetName;\n\n    public AssetBitmapDescriptor(String assetName) {\n        this.assetName = assetName;\n    }\n\n    @Override\n    protected Bitmap generateBitmap(Context context) {\n        try {\n            return BitmapFactory.decodeStream(context.getAssets().open(assetName));\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/src/main/java/org/microg/gms/maps/vtm/bitmap/BitmapBitmapDescriptor.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.maps.vtm.bitmap;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\n\npublic class BitmapBitmapDescriptor extends AbstractBitmapDescriptor {\n    private Bitmap bitmap;\n\n    public BitmapBitmapDescriptor(Bitmap bitmap) {\n        this.bitmap = bitmap;\n    }\n\n    @Override\n    public Bitmap getBitmap() {\n        return bitmap;\n    }\n\n    @Override\n    public Bitmap generateBitmap(Context context) {\n        return bitmap;\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/src/main/java/org/microg/gms/maps/vtm/bitmap/BitmapDescriptorFactoryImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.maps.vtm.bitmap;\n\nimport android.graphics.Bitmap;\nimport android.os.Parcel;\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.dynamic.ObjectWrapper;\nimport com.google.android.gms.maps.model.internal.IBitmapDescriptorFactoryDelegate;\n\npublic class BitmapDescriptorFactoryImpl extends IBitmapDescriptorFactoryDelegate.Stub {\n    private static final String TAG = \"GmsBitmapDescFactory\";\n\n    @Override\n    public IObjectWrapper fromResource(int resourceId) throws RemoteException {\n        return ObjectWrapper.wrap(new ResourceBitmapDescriptor(resourceId));\n    }\n\n    @Override\n    public IObjectWrapper fromAsset(String assetName) throws RemoteException {\n        return ObjectWrapper.wrap(new AssetBitmapDescriptor(assetName));\n    }\n\n    @Override\n    public IObjectWrapper fromFile(String fileName) throws RemoteException {\n        return ObjectWrapper.wrap(new FileBitmapDescriptor(fileName));\n    }\n\n    @Override\n    public IObjectWrapper defaultMarker() throws RemoteException {\n        return ObjectWrapper.wrap(DefaultBitmapDescriptor.DEFAULT_DESCRIPTOR);\n    }\n\n    @Override\n    public IObjectWrapper defaultMarkerWithHue(float hue) throws RemoteException {\n        return ObjectWrapper.wrap(new DefaultBitmapDescriptor(hue));\n    }\n\n    @Override\n    public IObjectWrapper fromBitmap(Bitmap bitmap) throws RemoteException {\n        return ObjectWrapper.wrap(new BitmapBitmapDescriptor(bitmap));\n    }\n\n    @Override\n    public IObjectWrapper fromPath(String absolutePath) throws RemoteException {\n        return ObjectWrapper.wrap(new PathBitmapDescriptor(absolutePath));\n    }\n\n    @Override\n    public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {\n        if (super.onTransact(code, data, reply, flags)) return true;\n        Log.d(TAG, \"onTransact [unknown]: \" + code + \", \" + data + \", \" + flags);\n        return false;\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/src/main/java/org/microg/gms/maps/vtm/bitmap/BitmapDescriptorImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.maps.vtm.bitmap;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.util.Log;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.dynamic.ObjectWrapper;\nimport com.google.android.gms.maps.model.BitmapDescriptor;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\npublic class BitmapDescriptorImpl {\n    private BitmapDescriptor descriptor;\n    private boolean loadStarted = false;\n    private Set<Runnable> waitingForLoad = new HashSet<Runnable>();\n\n    public BitmapDescriptorImpl(IObjectWrapper remoteObject) {\n        this(new BitmapDescriptor(remoteObject));\n    }\n\n    public BitmapDescriptorImpl(BitmapDescriptor descriptor) {\n        this.descriptor = descriptor;\n    }\n\n    public BitmapDescriptorImpl() {\n        this(new ObjectWrapper<DefaultBitmapDescriptor>(new DefaultBitmapDescriptor(0)));\n    }\n\n    public AbstractBitmapDescriptor getDescriptor() {\n        if (descriptor.getRemoteObject() == null)\n            return null;\n        Object unwrap = ObjectWrapper.unwrap(descriptor.getRemoteObject());\n        if (unwrap instanceof AbstractBitmapDescriptor) {\n            return ((AbstractBitmapDescriptor) unwrap);\n        } else {\n            return null;\n        }\n    }\n\n    public Bitmap getBitmap() {\n        if (getDescriptor() != null) {\n            return getDescriptor().getBitmap();\n        }\n        return null;\n    }\n\n    public synchronized boolean loadBitmapAsync(final Context context, Runnable after) {\n        if (getBitmap() != null) {\n            return false;\n        }\n        waitingForLoad.add(after);\n        if (loadStarted)\n            return true;\n        loadStarted = true;\n        if (getDescriptor() != null) {\n            new Thread(new Runnable() {\n                @Override\n                public void run() {\n                    Log.d(\"BitmapDescriptor\", \"Start loading \" + getDescriptor());\n                    if (getDescriptor().loadBitmap(context) != null) {\n                        Set<Runnable> waitingForLoad;\n                        synchronized (BitmapDescriptorImpl.this) {\n                            waitingForLoad = BitmapDescriptorImpl.this.waitingForLoad;\n                        }\n                        for (Runnable after : waitingForLoad) {\n                            after.run();\n                        }\n                    }\n                    Log.d(\"BitmapDescriptor\", \"Done loading \" + getDescriptor());\n                }\n            }).start();\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/src/main/java/org/microg/gms/maps/vtm/bitmap/DefaultBitmapDescriptor.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.maps.vtm.bitmap;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.graphics.Canvas;\nimport android.graphics.ColorFilter;\nimport android.graphics.ColorMatrix;\nimport android.graphics.ColorMatrixColorFilter;\nimport android.graphics.Paint;\n\nimport com.google.android.gms.dynamic.ObjectWrapper;\n\nimport org.microg.gms.maps.vtm.ResourcesContainer;\nimport org.microg.gms.maps.vtm.R;\n\npublic class DefaultBitmapDescriptor extends AbstractBitmapDescriptor {\n    public static final DefaultBitmapDescriptor DEFAULT_DESCRIPTOR = new DefaultBitmapDescriptor(0);\n    public static final BitmapDescriptorImpl DEFAULT_DESCRIPTOR_IMPL = new BitmapDescriptorImpl(ObjectWrapper.wrap(DEFAULT_DESCRIPTOR));\n    public static final int DEGREES = 360;\n\n    private final float hue;\n\n    public DefaultBitmapDescriptor(float hue) {\n        this.hue = hue > 180 ? -DEGREES + hue : hue;\n    }\n\n    @Override\n    public Bitmap generateBitmap(Context context) {\n        Bitmap source;\n        if (this == DEFAULT_DESCRIPTOR) {\n            source = BitmapFactory.decodeResource(ResourcesContainer.get(), R.drawable.maps_default_marker);\n        } else {\n            source = DEFAULT_DESCRIPTOR.loadBitmap(context);\n        }\n        if (hue % DEGREES == 0) return source;\n        Paint paint = new Paint();\n        paint.setColorFilter(adjustHue(hue));\n        Bitmap bitmap = Bitmap.createBitmap(source.getWidth(), source.getHeight(), source.getConfig());\n        Canvas canvas = new Canvas(bitmap);\n        canvas.drawBitmap(source, 0, 0, paint);\n        return bitmap;\n    }\n\n    /**\n     * Creates a HUE ajustment ColorFilter\n     * <p/>\n     * see http://groups.google.com/group/android-developers/browse_thread/thread/9e215c83c3819953\n     * see http://gskinner.com/blog/archives/2007/12/colormatrix_cla.html\n     *\n     * @param value degrees to shift the hue.\n     */\n    public static ColorFilter adjustHue(float value) {\n        ColorMatrix cm = new ColorMatrix();\n        adjustHue(cm, value);\n        return new ColorMatrixColorFilter(cm);\n    }\n\n    /**\n     * see http://groups.google.com/group/android-developers/browse_thread/thread/9e215c83c3819953\n     * see http://gskinner.com/blog/archives/2007/12/colormatrix_cla.html\n     */\n    public static void adjustHue(ColorMatrix cm, float value) {\n        value = cleanValue(value, 180f) / 180f * (float) Math.PI;\n        if (value == 0) {\n            return;\n        }\n        float cosVal = (float) Math.cos(value);\n        float sinVal = (float) Math.sin(value);\n        float lumR = 0.213f;\n        float lumG = 0.715f;\n        float lumB = 0.072f;\n        float[] mat = new float[]{lumR + cosVal * (1 - lumR) + sinVal * (-lumR),\n                lumG + cosVal * (-lumG) + sinVal * (-lumG),\n                lumB + cosVal * (-lumB) + sinVal * (1 - lumB), 0, 0,\n                lumR + cosVal * (-lumR) + sinVal * (0.143f),\n                lumG + cosVal * (1 - lumG) + sinVal * (0.140f),\n                lumB + cosVal * (-lumB) + sinVal * (-0.283f), 0, 0,\n                lumR + cosVal * (-lumR) + sinVal * (-(1 - lumR)),\n                lumG + cosVal * (-lumG) + sinVal * (lumG),\n                lumB + cosVal * (1 - lumB) + sinVal * (lumB),\n                0, 0, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 0f, 0f, 1f};\n        cm.postConcat(new ColorMatrix(mat));\n    }\n\n    protected static float cleanValue(float p_val, float p_limit) {\n        return Math.min(p_limit, Math.max(-p_limit, p_val));\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/src/main/java/org/microg/gms/maps/vtm/bitmap/FileBitmapDescriptor.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.maps.vtm.bitmap;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\n\npublic class FileBitmapDescriptor extends AbstractBitmapDescriptor {\n    private String fileName;\n\n    public FileBitmapDescriptor(String fileName) {\n        this.fileName = fileName;\n    }\n\n    @Override\n    public Bitmap generateBitmap(Context context) {\n        return BitmapFactory.decodeFile(fileName);\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/src/main/java/org/microg/gms/maps/vtm/bitmap/PathBitmapDescriptor.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.maps.vtm.bitmap;\n\npublic class PathBitmapDescriptor {\n    public PathBitmapDescriptor(String absolutePath) {\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/src/main/java/org/microg/gms/maps/vtm/bitmap/ResourceBitmapDescriptor.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.maps.vtm.bitmap;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.graphics.Canvas;\nimport android.graphics.drawable.BitmapDrawable;\nimport android.graphics.drawable.Drawable;\n\nimport androidx.core.content.ContextCompat;\n\npublic class ResourceBitmapDescriptor extends AbstractBitmapDescriptor {\n    private int resourceId;\n\n    public ResourceBitmapDescriptor(int resourceId) {\n        this.resourceId = resourceId;\n    }\n\n    @Override\n    public Bitmap generateBitmap(Context context) {\n        return drawableToBitmap(context, ContextCompat.getDrawable(context.getApplicationContext(), resourceId));\n    }\n\n    public static Bitmap drawableToBitmap(Context context, Drawable drawable) {\n        if (drawable instanceof BitmapDrawable) {\n            return ((BitmapDrawable) drawable).getBitmap();\n        }\n\n        if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {\n            return DefaultBitmapDescriptor.DEFAULT_DESCRIPTOR.loadBitmap(context);\n        }\n\n        Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);\n        Canvas canvas = new Canvas(bitmap);\n        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());\n        drawable.draw(canvas);\n\n        return bitmap;\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/src/main/java/org/microg/gms/maps/vtm/camera/CameraUpdate.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.maps.vtm.camera;\n\nimport org.oscim.map.Map;\n\npublic interface CameraUpdate {\n    void apply(Map map);\n    void applyAnimated(Map map, int duration);\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/src/main/java/org/microg/gms/maps/vtm/camera/CameraUpdateFactoryImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.maps.vtm.camera;\n\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.dynamic.ObjectWrapper;\nimport com.google.android.gms.maps.internal.ICameraUpdateFactoryDelegate;\nimport com.google.android.gms.maps.model.CameraPosition;\nimport com.google.android.gms.maps.model.LatLng;\nimport com.google.android.gms.maps.model.LatLngBounds;\n\nimport org.microg.gms.maps.vtm.GmsMapsTypeHelper;\nimport org.oscim.core.MapPosition;\nimport org.oscim.map.Map;\n\npublic class CameraUpdateFactoryImpl extends ICameraUpdateFactoryDelegate.Stub {\n    private static final String TAG = \"GmsMapCamUpdateFactory\";\n\n    private CameraUpdateFactoryImpl() {\n\n    }\n\n    private static CameraUpdateFactoryImpl instance;\n    public static CameraUpdateFactoryImpl get() {\n        if (instance == null) {\n            instance = new CameraUpdateFactoryImpl();\n        }\n        return instance;\n    }\n\n    @Override\n    public IObjectWrapper zoomIn() throws RemoteException {\n        Log.d(TAG, \"zoomIn\");\n        return new ObjectWrapper<CameraUpdate>(new MapPositionCameraUpdate() {\n\n            @Override\n            MapPosition getMapPosition(Map map) {\n                MapPosition mapPosition = map.getMapPosition();\n                mapPosition.setScale(GmsMapsTypeHelper.fromZoom(\n                        GmsMapsTypeHelper.toZoom(mapPosition.getScale()) + 1));\n                return mapPosition;\n            }\n        });\n    }\n\n    @Override\n    public IObjectWrapper zoomOut() throws RemoteException {\n        Log.d(TAG, \"zoomOut\");\n        return new ObjectWrapper<CameraUpdate>(new MapPositionCameraUpdate() {\n            @Override\n            MapPosition getMapPosition(Map map) {\n                MapPosition mapPosition = map.getMapPosition();\n                mapPosition.setScale(GmsMapsTypeHelper.fromZoom(\n                        GmsMapsTypeHelper.toZoom(mapPosition.getScale()) - 1));\n                return mapPosition;\n            }\n        });\n    }\n\n    @Override\n    public IObjectWrapper scrollBy(final float x, final float y) throws RemoteException {\n        Log.d(TAG, \"scrollBy\");\n        return new ObjectWrapper<CameraUpdate>(new MapPositionCameraUpdate() {\n            @Override\n            MapPosition getMapPosition(Map map) {\n                MapPosition mapPosition = map.getMapPosition();\n                mapPosition.setPosition(map.viewport()\n                        .fromScreenPoint((float) (map.getWidth() / 2.0 + x),\n                                (float) (map.getHeight() / 2.0 + y)));\n                return mapPosition;\n            }\n        });\n    }\n\n    @Override\n    public IObjectWrapper zoomTo(final float zoom) throws RemoteException {\n        Log.d(TAG, \"zoomTo\");\n        return new ObjectWrapper<CameraUpdate>(new MapPositionCameraUpdate() {\n            @Override\n            MapPosition getMapPosition(Map map) {\n                MapPosition mapPosition = map.getMapPosition();\n                mapPosition.setScale(GmsMapsTypeHelper.fromZoom(zoom));\n                return mapPosition;\n            }\n        });\n    }\n\n    @Override\n    public IObjectWrapper zoomBy(final float zoomDelta) throws RemoteException {\n        Log.d(TAG, \"zoomBy\");\n        return new ObjectWrapper<CameraUpdate>(new MapPositionCameraUpdate() {\n            @Override\n            MapPosition getMapPosition(Map map) {\n                MapPosition mapPosition = map.getMapPosition();\n                mapPosition.setScale(GmsMapsTypeHelper.fromZoom(\n                        GmsMapsTypeHelper.toZoom(mapPosition.getScale()) + zoomDelta));\n                return mapPosition;\n            }\n        });\n    }\n\n    @Override\n    public IObjectWrapper zoomByWithFocus(final float zoomDelta, int x, int y)\n            throws RemoteException {\n        Log.d(TAG, \"zoomByWithFocus\");\n        return new ObjectWrapper<CameraUpdate>(new MapPositionCameraUpdate() {\n            @Override\n            MapPosition getMapPosition(Map map) {\n                MapPosition mapPosition = map.getMapPosition();\n                mapPosition.setScale(GmsMapsTypeHelper.fromZoom(\n                        GmsMapsTypeHelper.toZoom(mapPosition.getScale()) + zoomDelta));\n                Log.w(TAG, \"zoomBy with focus not yet supported\"); // TODO\n                return mapPosition;\n            }\n        });\n    }\n\n    @Override\n    public IObjectWrapper newCameraPosition(final CameraPosition cameraPosition)\n            throws RemoteException {\n        Log.d(TAG, \"newCameraPosition\");\n        return new ObjectWrapper<CameraUpdate>(new MapPositionCameraUpdate() {\n            @Override\n            MapPosition getMapPosition(Map map) {\n                return GmsMapsTypeHelper.fromCameraPosition(cameraPosition);\n            }\n        });\n    }\n\n    @Override\n    public IObjectWrapper newLatLng(final LatLng latLng) throws RemoteException {\n        Log.d(TAG, \"newLatLng\");\n        return new ObjectWrapper<CameraUpdate>(new MapPositionCameraUpdate() {\n            @Override\n            MapPosition getMapPosition(Map map) {\n                MapPosition mapPosition = map.getMapPosition();\n                mapPosition.setPosition(GmsMapsTypeHelper.fromLatLng(latLng));\n                return mapPosition;\n            }\n        });\n    }\n\n    @Override\n    public IObjectWrapper newLatLngZoom(final LatLng latLng, final float zoom)\n            throws RemoteException {\n        Log.d(TAG, \"newLatLngZoom\");\n        return new ObjectWrapper<CameraUpdate>(new MapPositionCameraUpdate() {\n            @Override\n            MapPosition getMapPosition(Map map) {\n                MapPosition mapPosition = map.getMapPosition();\n                mapPosition.setPosition(GmsMapsTypeHelper.fromLatLng(latLng));\n                mapPosition.setScale(GmsMapsTypeHelper.fromZoom(zoom));\n                return mapPosition;\n            }\n        });\n    }\n\n    @Override\n    public IObjectWrapper newLatLngBounds(final LatLngBounds bounds, int padding) throws RemoteException {\n        Log.d(TAG, \"newLatLngBounds\");\n        return new ObjectWrapper<CameraUpdate>(new MapPositionCameraUpdate() {\n            @Override\n            MapPosition getMapPosition(Map map) {\n                MapPosition mapPosition = map.getMapPosition();\n                mapPosition.setByBoundingBox(GmsMapsTypeHelper.fromLatLngBounds(bounds),\n                        map.getWidth(), map.getHeight());\n                return mapPosition;\n            }\n        });\n    }\n\n    @Override\n    public IObjectWrapper newLatLngBoundsWithSize(final LatLngBounds bounds, final int width, final int height, int padding)\n            throws RemoteException {\n        Log.d(TAG, \"newLatLngBoundsWithSize\");\n        return new ObjectWrapper<CameraUpdate>(new MapPositionCameraUpdate() {\n            @Override\n            MapPosition getMapPosition(Map map) {\n                MapPosition mapPosition = map.getMapPosition();\n                mapPosition.setByBoundingBox(GmsMapsTypeHelper.fromLatLngBounds(bounds),\n                        width, height);\n                return mapPosition;\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/src/main/java/org/microg/gms/maps/vtm/camera/MapPositionCameraUpdate.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.maps.vtm.camera;\n\nimport org.oscim.core.MapPosition;\nimport org.oscim.map.Map;\n\npublic abstract class MapPositionCameraUpdate implements CameraUpdate {\n\n    abstract MapPosition getMapPosition(Map map);\n\n    @Override\n    public void apply(Map map) {\n        map.setMapPosition(getMapPosition(map));\n    }\n\n    @Override\n    public void applyAnimated(Map map, int duration) {\n        map.animator().animateTo(duration, getMapPosition(map));\n    }\n\n    public static CameraUpdate directMapPosition(final MapPosition position) {\n        return new MapPositionCameraUpdate() {\n            @Override\n            MapPosition getMapPosition(Map map) {\n                return position;\n            }\n        };\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/src/main/java/org/microg/gms/maps/vtm/camera/NoCameraUpdate.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.maps.vtm.camera;\n\nimport org.oscim.map.Map;\n\npublic class NoCameraUpdate implements CameraUpdate {\n    @Override\n    public void apply(Map map) {\n\n    }\n\n    @Override\n    public void applyAnimated(Map map, int duration) {\n\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/src/main/java/org/microg/gms/maps/vtm/data/SharedTileCache.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.maps.vtm.data;\n\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.database.Cursor;\n\nimport org.oscim.core.Tile;\nimport org.oscim.tiling.ITileCache;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.ArrayList;\n\npublic class SharedTileCache implements ITileCache {\n    private final ArrayList<ByteArrayOutputStream> cacheBuffers;\n    private final Context context;\n\n    public SharedTileCache(Context context) {\n        this.context = context;\n        this.cacheBuffers = new ArrayList<ByteArrayOutputStream>();\n    }\n\n    @Override\n    public TileWriter writeTile(Tile tile) {\n        ByteArrayOutputStream os;\n        synchronized (this.cacheBuffers) {\n            if (this.cacheBuffers.isEmpty()) {\n                os = new ByteArrayOutputStream('耀');\n            } else {\n                os = this.cacheBuffers.remove(this.cacheBuffers.size() - 1);\n            }\n        }\n\n        return new CacheTileWriter(tile, os);\n    }\n\n    public void saveTile(Tile tile, ByteArrayOutputStream data, boolean success) {\n        byte[] bytes = null;\n        if (success) {\n            bytes = data.toByteArray();\n        }\n\n        synchronized (this.cacheBuffers) {\n            data.reset();\n            this.cacheBuffers.add(data);\n        }\n\n        if (success) {\n            ContentValues values = new ContentValues();\n            values.put(\"x\", tile.tileX);\n            values.put(\"y\", tile.tileY);\n            values.put(\"z\", tile.zoomLevel);\n            values.put(\"time\", 0);\n            values.put(\"last_access\", 0);\n            values.put(\"data\", bytes);\n            context.getContentResolver().insert(SharedTileProvider.PROVIDER_URI, values);\n        }\n    }\n\n    @Override\n    public TileReader getTile(Tile tile) {\n        Cursor cursor = context.getContentResolver().query(SharedTileProvider.PROVIDER_URI, new String[]{\"data\"}, \"z=? AND x=? AND y=?\", new String[]{String.valueOf(tile.zoomLevel), String.valueOf(tile.tileX), String.valueOf(tile.tileY)}, null);\n        if (cursor != null) {\n            if (!cursor.moveToFirst()) {\n                cursor.close();\n                return null;\n            } else {\n                ByteArrayInputStream in = new ByteArrayInputStream(cursor.getBlob(0));\n                cursor.close();\n                return new CacheTileReader(tile, in);\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public void setCacheSize(long l) {\n\n    }\n\n    class CacheTileWriter implements TileWriter {\n        final ByteArrayOutputStream os;\n        final Tile tile;\n\n        CacheTileWriter(Tile tile, ByteArrayOutputStream os) {\n            this.tile = tile;\n            this.os = os;\n        }\n\n        public Tile getTile() {\n            return tile;\n        }\n\n        public OutputStream getOutputStream() {\n            return os;\n        }\n\n        public void complete(boolean success) {\n            saveTile(tile, os, success);\n        }\n    }\n\n    class CacheTileReader implements TileReader {\n        final InputStream is;\n        final Tile tile;\n\n        public CacheTileReader(Tile tile, InputStream is) {\n            this.tile = tile;\n            this.is = is;\n        }\n\n        public Tile getTile() {\n            return tile;\n        }\n\n        public InputStream getInputStream() {\n            return is;\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/src/main/java/org/microg/gms/maps/vtm/data/SharedTileProvider.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.maps.vtm.data;\n\nimport android.content.ContentProvider;\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.database.sqlite.SQLiteDatabase;\nimport android.database.sqlite.SQLiteOpenHelper;\nimport android.net.Uri;\n\n/*\n * TODO: Writing to cache should be protected, tiles should be downloaded by service instead of client app.\n */\npublic class SharedTileProvider extends ContentProvider {\n    private static final String DB_NAME = \"tilecache.db\";\n    public static final String PROVIDER_NAME = \"org.microg.gms.maps.vtm.tile\";\n    public static final Uri PROVIDER_URI = Uri.parse(\"content://\" + PROVIDER_NAME);\n\n    private SQLiteHelper sqLiteHelper;\n\n    public SharedTileProvider() {\n    }\n\n    @Override\n    public int delete(Uri uri, String selection, String[] selectionArgs) {\n        // Implement this to handle requests to delete one or more rows.\n        throw new UnsupportedOperationException(\"Not yet implemented\");\n    }\n\n    @Override\n    public String getType(Uri uri) {\n        return \"vnd.android.cursor.item/org.microg.gms.map.tile\";\n    }\n\n    @Override\n    public Uri insert(Uri uri, ContentValues values) {\n        sqLiteHelper.getWritableDatabase().insert(\"tiles\", null, values);\n        return PROVIDER_URI;\n    }\n\n    @Override\n    public boolean onCreate() {\n        sqLiteHelper = new SQLiteHelper(getContext(), DB_NAME);\n        return true;\n    }\n\n    @Override\n    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {\n        return sqLiteHelper.getReadableDatabase().query(\"tiles\", projection, selection, selectionArgs, null, null, sortOrder);\n    }\n\n    @Override\n    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {\n        return sqLiteHelper.getWritableDatabase().update(\"tiles\", values, selection, selectionArgs);\n    }\n\n    class SQLiteHelper extends SQLiteOpenHelper {\n        private static final int DATABASE_VERSION = 1;\n        private static final String TILE_SCHEMA = \"CREATE TABLE tiles(x INTEGER NOT NULL,y INTEGER NOT NULL,z INTEGER NOT NULL,time LONG NOT NULL,last_access LONG NOT NULL,data BLOB,PRIMARY KEY(x,y,z));\";\n\n        public SQLiteHelper(Context context, String dbName) {\n            super(context, dbName, null, DATABASE_VERSION);\n        }\n\n        public void onCreate(SQLiteDatabase db) {\n            db.execSQL(TILE_SCHEMA);\n        }\n\n        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {\n            db.execSQL(\"DROP TABLE IF EXISTS tiles\");\n            this.onCreate(db);\n        }\n\n        public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {\n            this.onUpgrade(db, oldVersion, newVersion);\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/src/main/java/org/microg/gms/maps/vtm/markup/CircleImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.maps.vtm.markup;\n\nimport android.os.RemoteException;\n\nimport android.util.Log;\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.dynamic.ObjectWrapper;\nimport com.google.android.gms.maps.model.CircleOptions;\nimport com.google.android.gms.maps.model.LatLng;\nimport com.google.android.gms.maps.model.PatternItem;\nimport com.google.android.gms.maps.model.internal.ICircleDelegate;\n\nimport org.microg.gms.maps.vtm.GmsMapsTypeHelper;\nimport org.oscim.layers.vector.geometries.CircleDrawable;\nimport org.oscim.layers.vector.geometries.Drawable;\nimport org.oscim.layers.vector.geometries.Style;\nimport org.oscim.map.Map;\n\nimport java.util.List;\n\npublic class CircleImpl extends ICircleDelegate.Stub implements DrawableMarkup {\n\n    private static final String TAG = \"GmsMapCircle\";\n\n    private final String id;\n    private final CircleOptions options;\n    private final MarkupListener listener;\n    private boolean removed = false;\n\n    public CircleImpl(String id, CircleOptions options, MarkupListener listener) {\n        this.id = id;\n        this.listener = listener;\n        this.options = options == null ? new CircleOptions() : options;\n    }\n\n    @Override\n    public void remove() throws RemoteException {\n        listener.remove(this);\n        removed = true;\n    }\n\n    @Override\n    public String getId() {\n        return id;\n    }\n\n    @Override\n    public void setCenter(LatLng center) throws RemoteException {\n        options.center(center);\n        listener.update(this);\n    }\n\n    @Override\n    public LatLng getCenter() throws RemoteException {\n        return options.getCenter();\n    }\n\n    @Override\n    public void setRadius(double radius) throws RemoteException {\n        options.radius(radius);\n        listener.update(this);\n    }\n\n    @Override\n    public double getRadius() throws RemoteException {\n        return options.getRadius();\n    }\n\n    @Override\n    public void setStrokeWidth(float width) throws RemoteException {\n        options.strokeWidth(width);\n        listener.update(this);\n    }\n\n    @Override\n    public float getStrokeWidth() throws RemoteException {\n        return options.getStrokeWidth();\n    }\n\n    @Override\n    public void setStrokeColor(int color) throws RemoteException {\n        options.strokeColor(color);\n        listener.update(this);\n    }\n\n    @Override\n    public int getStrokeColor() throws RemoteException {\n        return options.getStrokeColor();\n    }\n\n    @Override\n    public void setFillColor(int color) throws RemoteException {\n        options.fillColor(color);\n        listener.update(this);\n    }\n\n    @Override\n    public int getFillColor() throws RemoteException {\n        return options.getFillColor();\n    }\n\n    @Override\n    public void setZIndex(float zIndex) throws RemoteException {\n        options.zIndex(zIndex);\n        listener.update(this);\n    }\n\n    @Override\n    public float getZIndex() {\n        return options.getZIndex();\n    }\n\n    @Override\n    public void setVisible(boolean visible) throws RemoteException {\n        options.visible(visible);\n        listener.update(this);\n    }\n\n    @Override\n    public boolean isVisible() {\n        return options.isVisible();\n    }\n\n    @Override\n    public boolean equalsRemote(ICircleDelegate other) throws RemoteException {\n        return other != null && other.getId().equals(getId());\n    }\n\n    @Override\n    public int hashCodeRemote() throws RemoteException {\n        return id.hashCode();\n    }\n\n    @Override\n    public void setClickable(boolean clickable) throws RemoteException {\n        Log.d(TAG, \"unimplemented method: setClickable\");\n    }\n\n    @Override\n    public boolean isClickable() throws RemoteException {\n        return false;\n    }\n\n    @Override\n    public void setStrokePattern(List<PatternItem> object) throws RemoteException {\n        Log.d(TAG, \"unimplemented method: setStrokePattern\");\n    }\n\n    @Override\n    public List<PatternItem> getStrokePattern() throws RemoteException {\n        Log.d(TAG, \"unimplemented method: getStrokePattern\");\n        return null;\n    }\n\n    @Override\n    public void setTag(IObjectWrapper object) throws RemoteException {\n        Log.d(TAG, \"unimplemented method: setTag\");\n    }\n\n    @Override\n    public IObjectWrapper getTag() throws RemoteException {\n        Log.d(TAG, \"unimplemented method: getTag\");\n        return ObjectWrapper.wrap(null);\n    }\n\n    @Override\n    public boolean onClick() {\n        return listener.onClick(this);\n    }\n\n    @Override\n    public void onDragStart() {\n        listener.onDragStart(this);\n    }\n\n    @Override\n    public void onDragStop() {\n        listener.onDragStop(this);\n    }\n\n    @Override\n    public void onDragProgress() {\n        listener.onDragProgress(this);\n    }\n\n    @Override\n    public Drawable getDrawable(Map map) {\n        if (!isVisible() || removed) return null;\n        return new CircleDrawable(\n                GmsMapsTypeHelper.fromLatLng(options.getCenter()),\n                options.getRadius() / 1000.0,\n                Style.builder()\n                        .strokeColor(options.getStrokeColor())\n                        .fillAlpha(1)\n                        .fillColor(options.getFillColor())\n                        .strokeWidth(options.getStrokeWidth()).build());\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/src/main/java/org/microg/gms/maps/vtm/markup/ClearableVectorLayer.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.maps.vtm.markup;\n\nimport org.oscim.layers.vector.VectorLayer;\nimport org.oscim.map.Map;\n\npublic class ClearableVectorLayer extends VectorLayer {\n    public ClearableVectorLayer(Map map) {\n        super(map);\n    }\n\n    public void clear() {\n        mDrawables.clear();\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/src/main/java/org/microg/gms/maps/vtm/markup/DrawableMarkup.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.maps.vtm.markup;\n\nimport org.oscim.layers.vector.geometries.Drawable;\nimport org.oscim.map.Map;\n\npublic interface DrawableMarkup extends Markup {\n    float getZIndex();\n\n    Drawable getDrawable(Map map);\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/src/main/java/org/microg/gms/maps/vtm/markup/GroundOverlayImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.maps.vtm.markup;\n\nimport android.os.RemoteException;\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.maps.model.GroundOverlayOptions;\nimport com.google.android.gms.maps.model.LatLng;\nimport com.google.android.gms.maps.model.LatLngBounds;\nimport com.google.android.gms.maps.model.internal.IGroundOverlayDelegate;\n\npublic class GroundOverlayImpl extends IGroundOverlayDelegate.Stub {\n    private LatLng position;\n    private float transparency;\n    private float zIndex;\n    private boolean visible;\n    private String id;\n    private float width;\n    private float height;\n    private float bearing;\n\n    public GroundOverlayImpl(GroundOverlayOptions options) {\n        \n    }\n\n    @Override\n    public void remove() throws RemoteException {\n\n    }\n\n    @Override\n    public String getId() throws RemoteException {\n        return id;\n    }\n\n    @Override\n    public void setPosition(LatLng pos) throws RemoteException {\n        this.position = pos;\n    }\n\n    @Override\n    public LatLng getPosition() throws RemoteException {\n        return position;\n    }\n\n    @Override\n    public void setDimension(float dimension) throws RemoteException {\n        setDimensions(dimension, dimension);\n    }\n\n    @Override\n    public void setDimensions(float width, float height) throws RemoteException {\n        this.width = width;\n        this.height = height;\n    }\n\n    @Override\n    public float getWidth() throws RemoteException {\n        return width;\n    }\n\n    @Override\n    public float getHeight() throws RemoteException {\n        return height;\n    }\n\n    @Override\n    public void setPositionFromBounds(LatLngBounds bounds) throws RemoteException {\n\n    }\n\n    @Override\n    public LatLngBounds getBounds() throws RemoteException {\n        return null;\n    }\n\n    @Override\n    public void setBearing(float bearing) throws RemoteException {\n        this.bearing = bearing;\n    }\n\n    @Override\n    public float getBearing() throws RemoteException {\n        return bearing;\n    }\n\n    @Override\n    public void setZIndex(float zIndex) throws RemoteException {\n        this.zIndex = zIndex;\n    }\n\n    @Override\n    public float getZIndex() throws RemoteException {\n        return zIndex;\n    }\n\n    @Override\n    public void setVisible(boolean visible) throws RemoteException {\n        this.visible = visible;\n    }\n\n    @Override\n    public boolean isVisible() throws RemoteException {\n        return visible;\n    }\n\n    @Override\n    public void setTransparency(float transparency) throws RemoteException {\n        this.transparency = transparency;\n    }\n\n    @Override\n    public float getTransparency() throws RemoteException {\n        return transparency;\n    }\n\n    @Override\n    public boolean equalsRemote(IGroundOverlayDelegate other) throws RemoteException {\n        return other != null && other.getId().equals(getId());\n    }\n\n    @Override\n    public int hashCodeRemote() throws RemoteException {\n        return id.hashCode();\n    }\n\n    @Override\n    public void setImage(IObjectWrapper img) throws RemoteException {\n\n    }\n\n    @Override\n    public void setClickable(boolean clickable) throws RemoteException {\n\n    }\n\n    @Override\n    public boolean isClickable() throws RemoteException {\n        return false;\n    }\n\n    @Override\n    public void setTag(IObjectWrapper obj) throws RemoteException {\n\n    }\n\n    @Override\n    public IObjectWrapper getTag() throws RemoteException {\n        return null;\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/src/main/java/org/microg/gms/maps/vtm/markup/InfoWindow.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.maps.vtm.markup;\n\nimport android.content.Context;\nimport android.view.View;\nimport android.widget.FrameLayout;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\nimport com.google.android.gms.maps.model.internal.IMarkerDelegate;\nimport org.microg.gms.maps.vtm.GoogleMapImpl;\nimport org.microg.gms.maps.vtm.ResourcesContainer;\nimport org.microg.gms.maps.vtm.R;\n\nimport static android.os.Build.VERSION.SDK_INT;\nimport static android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1;\n\npublic class InfoWindow {\n    private static final String TAG = InfoWindow.class.getName();\n    private Context context;\n    private View window;\n    private GoogleMapImpl map;\n    private MarkerImpl marker;\n\n    public InfoWindow(Context context, final GoogleMapImpl map, final MarkerImpl marker) {\n        super();\n        this.context = context;\n        this.map = map;\n        this.marker = marker;\n    }\n\n    public void setWindow(View view) {\n        window = view;\n        if (window != null) {\n            window.measure(0, 0);\n        }\n    }\n\n    public boolean isComplete() {\n        return window != null;\n    }\n\n    public void setContent(View view) {\n        if (view == null)\n            return;\n        setWindow(new DefaultWindow(view));\n    }\n\n    public void buildDefault() {\n        if (marker.getTitle() != null)\n            setContent(new DefaultContent());\n    }\n\n    public void destroy() {\n        if (window instanceof DefaultWindow) {\n            ((DefaultWindow) window).removeAllViews();\n        }\n    }\n\n    public IMarkerDelegate getMarker() {\n        return marker;\n    }\n\n    /*\n    @Override\n    public void draw(Canvas canvas, MapView mapView, boolean shadow) {\n        if (window != null && marker.getHeight() != -1 && !shadow) {\n            try {\n                Log.d(TAG, \"draw InfoWindow\");\n                window.measure(0, 0);\n                window.layout(0, 0, window.getMeasuredWidth(), window.getMeasuredHeight());\n                //Point point = mapView.getProjection().toPixels(marker.getPosition().toGeoPoint(), null);\n                \n                // osmdroid 4.1 bugfix\n                Point zero = mapView.getProjection().toPixels(new GeoPoint(0, 0), null);\n                point.offset(-zero.x, -zero.y);\n                \n\n                \n                point.offset(-window.getMeasuredWidth() / 2, -window.getMeasuredHeight() - marker.getHeight());\n                Log.d(TAG, point.toString());\n                canvas.save();\n                canvas.translate(point.x, point.y);\n                window.draw(canvas);\n                canvas.restore();\n            } catch (Exception e) {\n                // This is not remote...\n            }\n        }\n    }\n\n    @Override\n    public boolean onTap(GeoPoint p, MapView mapView) {\n        try {\n            IOnInfoWindowClickListener listener = null; //map.getInfoWindowClickListener();\n            if (listener != null) {\n                Point clickPoint = mapView.getProjection().toPixels(p, null);\n                Point markerPoint = mapView.getProjection().toPixels(marker.getPosition().toGeoPoint(), null);\n                Rect rect = new Rect(markerPoint.x - (window.getMeasuredWidth() / 2),\n                        markerPoint.y - marker.getHeight() - window.getMeasuredHeight(),\n                        markerPoint.x + (window.getMeasuredWidth() / 2),\n                        markerPoint.y - marker.getHeight());\n                if (rect.contains(clickPoint.x, clickPoint.y)) {\n                    try {\n                        listener.onInfoWindowClick(marker);\n                    } catch (RemoteException e) {\n                        Log.w(TAG, e);\n                    }\n                    return true;\n                }\n                \n            }\n        } catch (Exception e) {\n            // This is not remote...\n        }\n        return false;\n    }\n*/\n\n    private class DefaultWindow extends FrameLayout {\n        @SuppressWarnings(\"deprecation\")\n        public DefaultWindow(View view) {\n            super(context);\n            addView(view);\n            if (SDK_INT > ICE_CREAM_SANDWICH_MR1) {\n                setBackground(ResourcesContainer.get().getDrawable(R.drawable.maps_default_window));\n            } else {\n                setBackgroundDrawable(ResourcesContainer.get().getDrawable(R.drawable.maps_default_window));\n            }\n        }\n    }\n\n    private class DefaultContent extends LinearLayout {\n        public DefaultContent() {\n            super(context);\n            setOrientation(LinearLayout.VERTICAL);\n            TextView title = new TextView(context);\n            title.setTextAppearance(context,\n                    android.R.style.TextAppearance_DeviceDefault_Medium_Inverse);\n            title.setText(marker.getTitle());\n            addView(title);\n            if (marker.getSnippet() != null) {\n                TextView snippet = new TextView(context);\n                snippet.setTextAppearance(context,\n                        android.R.style.TextAppearance_DeviceDefault_Inverse);\n                snippet.setText(marker.getSnippet());\n                addView(snippet);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/src/main/java/org/microg/gms/maps/vtm/markup/MarkerImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.maps.vtm.markup;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.dynamic.ObjectWrapper;\nimport com.google.android.gms.maps.model.LatLng;\nimport com.google.android.gms.maps.model.MarkerOptions;\nimport com.google.android.gms.maps.model.internal.IMarkerDelegate;\n\nimport org.microg.gms.maps.vtm.GmsMapsTypeHelper;\nimport org.microg.gms.maps.vtm.bitmap.BitmapDescriptorImpl;\nimport org.microg.gms.maps.vtm.bitmap.DefaultBitmapDescriptor;\nimport org.oscim.android.canvas.AndroidBitmap;\nimport org.oscim.layers.marker.MarkerItem;\nimport org.oscim.layers.marker.MarkerSymbol;\n\npublic class MarkerImpl extends IMarkerDelegate.Stub implements MarkerItemMarkup {\n    private static final String TAG = \"GmsMapMarkerImpl\";\n\n    private final String id;\n    private final MarkerOptions options;\n    private final MarkupListener listener;\n    private BitmapDescriptorImpl icon;\n    private AndroidBitmap oldBitmap;\n    private boolean removed = false;\n    private IObjectWrapper tag = null;\n\n    public MarkerImpl(String id, MarkerOptions options, MarkupListener listener) {\n        this.id = id;\n        this.listener = listener;\n        this.options = options == null ? new MarkerOptions() : options;\n        if (options.getPosition() == null) {\n            options.position(new LatLng(0, 0));\n        }\n        icon = options.getIcon() == null ? null : new BitmapDescriptorImpl(options.getIcon());\n        Log.d(TAG, \"New marker \" + id + \" with title \" + options.getTitle() + \" @ \" +\n                options.getPosition());\n    }\n\n    @Override\n    public void remove() {\n        listener.remove(this);\n        removed = true;\n        icon = null;\n        oldBitmap = null;\n    }\n\n    @Override\n    public String getId() {\n        return id;\n    }\n\n    @Override\n    public void setPosition(LatLng pos) {\n        options.position(pos);\n        listener.update(this);\n    }\n\n    @Override\n    public LatLng getPosition() {\n        return options.getPosition();\n    }\n\n    @Override\n    public void setTitle(String title) {\n        options.title(title);\n        listener.update(this);\n    }\n\n    @Override\n    public String getTitle() {\n        return options.getTitle();\n    }\n\n    @Override\n    public void setSnippet(String snippet) {\n        options.snippet(snippet);\n    }\n\n    @Override\n    public String getSnippet() {\n        return options.getSnippet();\n    }\n\n    @Override\n    public void setDraggable(boolean drag) {\n        options.draggable(drag);\n    }\n\n    @Override\n    public boolean isDraggable() {\n        return options.isDraggable();\n    }\n\n    @Override\n    public void showInfoWindow() {\n\n    }\n\n    @Override\n    public void hideInfoWindow() {\n\n    }\n\n    @Override\n    public boolean isInfoWindowShown() {\n        return false;\n    }\n\n    @Override\n    public void setVisible(boolean visible) {\n        options.visible(visible);\n    }\n\n    @Override\n    public boolean isVisible() {\n        return options.isVisible();\n    }\n\n    @Override\n    public boolean equalsRemote(IMarkerDelegate other) throws RemoteException {\n        return other != null && other.getId().equals(getId());\n    }\n\n    @Override\n    public int hashCodeRemote() {\n        return hashCode();\n    }\n\n    @Override\n    public int hashCode() {\n        return super.hashCode();\n    }\n\n    @Override\n    public void setIcon(IObjectWrapper obj) {\n        if (obj == null) {\n            icon = new BitmapDescriptorImpl();\n        } else {\n            icon = new BitmapDescriptorImpl(obj);\n        }\n        listener.update(this);\n    }\n\n    @Override\n    public void setAnchor(float x, float y) {\n        options.anchor(x, y);\n        listener.update(this);\n    }\n\n    @Override\n    public void setFlat(boolean flat) {\n        options.flat(flat);\n        listener.update(this);\n    }\n\n    @Override\n    public boolean isFlat() {\n        return options.isFlat();\n    }\n\n    @Override\n    public void setRotation(float rotation) {\n        options.rotation(rotation);\n        listener.update(this);\n    }\n\n    @Override\n    public float getRotation() {\n        return options.getRotation();\n    }\n\n    @Override\n    public void setInfoWindowAnchor(float x, float y) {\n        options.infoWindowAnchor(x, y);\n    }\n\n    @Override\n    public void setAlpha(float alpha) {\n        options.alpha(alpha);\n        listener.update(this);\n    }\n\n    @Override\n    public float getAlpha() {\n        return options.getAlpha();\n    }\n\n    public int getHeight() {\n        Bitmap bitmap = icon.getBitmap();\n        if (bitmap == null)\n            return -1;\n        return bitmap.getHeight();\n    }\n\n    @Override\n    public boolean onClick() {\n        return listener.onClick(this);\n    }\n\n    @Override\n    public void onDragStart() {\n        listener.onDragStart(this);\n    }\n\n    @Override\n    public void onDragStop() {\n        listener.onDragStop(this);\n    }\n\n    @Override\n    public void onDragProgress() {\n        listener.onDragProgress(this);\n    }\n\n    @Override\n    public MarkerItem getMarkerItem(Context context) {\n        if (removed) return null;\n        MarkerItem item = new MarkerItem(getId(), getTitle(), getSnippet(),\n                GmsMapsTypeHelper.fromLatLng(getPosition()));\n        BitmapDescriptorImpl icon = this.icon;\n        if (icon == null)\n            icon = DefaultBitmapDescriptor.DEFAULT_DESCRIPTOR_IMPL;\n        if (icon.getBitmap() != null) {\n            oldBitmap = new AndroidBitmap(icon.getBitmap());\n            prepareMarkerIcon(item);\n        } else {\n            if (!icon.loadBitmapAsync(context, new Runnable() {\n                @Override\n                public void run() {\n                    listener.update(MarkerImpl.this);\n                }\n            })) {\n                // Was loaded since last check...\n                oldBitmap = new AndroidBitmap(icon.getBitmap());\n                prepareMarkerIcon(item);\n            }\n            // Keep old icon while loading new\n            if (oldBitmap != null) {\n                prepareMarkerIcon(item);\n            }\n        }\n        return item;\n    }\n\n    private void prepareMarkerIcon(MarkerItem item) {\n        item.setMarker(new MarkerSymbol(oldBitmap, options.getAnchorU(), options.getAnchorV(), !options.isFlat()));\n    }\n\n    @Override\n    public void setZIndex(float zIndex) {\n        options.zIndex(zIndex);\n    }\n\n    @Override\n    public float getZIndex() {\n        return options.getZIndex();\n    }\n\n    @Override\n    public void setTag(IObjectWrapper obj) {\n        this.tag = obj;\n    }\n\n    @Override\n    public IObjectWrapper getTag() {\n        return this.tag == null ? ObjectWrapper.wrap(null) : this.tag;\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/src/main/java/org/microg/gms/maps/vtm/markup/MarkerItemMarkup.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.maps.vtm.markup;\n\nimport android.content.Context;\n\nimport com.google.android.gms.maps.model.LatLng;\n\nimport org.oscim.layers.marker.MarkerItem;\n\npublic interface MarkerItemMarkup extends Markup {\n    MarkerItem getMarkerItem(Context context);\n\n    boolean isDraggable();\n\n    LatLng getPosition();\n\n    void setPosition(LatLng latLng);\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/src/main/java/org/microg/gms/maps/vtm/markup/Markup.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.maps.vtm.markup;\n\npublic interface Markup {\n    String getId();\n\n    boolean onClick();\n\n    void onDragStart();\n    void onDragStop();\n    void onDragProgress();\n\n    interface MarkupListener {\n        void update(Markup markup);\n\n        void remove(Markup markup);\n\n        boolean onClick(Markup markup);\n\n        void onDragStart(Markup markup);\n\n        void onDragStop(Markup markup);\n\n        void onDragProgress(Markup markup);\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/src/main/java/org/microg/gms/maps/vtm/markup/PolygonImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.maps.vtm.markup;\n\nimport android.os.RemoteException;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.maps.model.LatLng;\nimport com.google.android.gms.maps.model.PatternItem;\nimport com.google.android.gms.maps.model.PolygonOptions;\nimport com.google.android.gms.maps.model.internal.IPolygonDelegate;\n\nimport org.microg.gms.maps.vtm.GmsMapsTypeHelper;\nimport org.oscim.core.GeoPoint;\nimport org.oscim.layers.vector.geometries.Drawable;\nimport org.oscim.layers.vector.geometries.PolygonDrawable;\nimport org.oscim.layers.vector.geometries.Style;\nimport org.oscim.map.Map;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class PolygonImpl extends IPolygonDelegate.Stub implements DrawableMarkup {\n    private static final String TAG = \"GmsMapsPolygonImpl\";\n\n    private final String id;\n    private final PolygonOptions options;\n    private final MarkupListener listener;\n    private boolean removed = false;\n\n    public PolygonImpl(String id, PolygonOptions options, MarkupListener listener) {\n        this.id = id;\n        this.options = options;\n        this.listener = listener;\n    }\n\n    @Override\n    public void remove() throws RemoteException {\n        listener.remove(this);\n        removed = true;\n    }\n\n    @Override\n    public String getId() {\n        return id;\n    }\n\n    @Override\n    public boolean onClick() {\n        return listener.onClick(this);\n    }\n\n    @Override\n    public void onDragStart() {\n        listener.onDragStart(this);\n    }\n\n    @Override\n    public void onDragStop() {\n        listener.onDragStop(this);\n    }\n\n    @Override\n    public void onDragProgress() {\n        listener.onDragProgress(this);\n    }\n\n    @Override\n    public void setPoints(List<LatLng> points) throws RemoteException {\n        options.getPoints().clear();\n        options.getPoints().addAll(points);\n        listener.update(this);\n    }\n\n    @Override\n    public List<LatLng> getPoints() throws RemoteException {\n        return options.getPoints();\n    }\n\n    @Override\n    public void setHoles(List holes) throws RemoteException {\n        options.getHoles().clear();\n        options.getHoles().addAll(holes);\n        listener.update(this);\n    }\n\n    @Override\n    public List getHoles() throws RemoteException {\n        return options.getHoles();\n    }\n\n    @Override\n    public void setStrokeWidth(float width) throws RemoteException {\n        options.strokeWidth(width);\n        listener.update(this);\n    }\n\n    @Override\n    public float getStrokeWidth() {\n        return options.getStrokeWidth();\n    }\n\n    @Override\n    public void setStrokeColor(int color) throws RemoteException {\n        options.strokeColor(color);\n        listener.update(this);\n    }\n\n    @Override\n    public int getStrokeColor() {\n        return options.getStrokeColor();\n    }\n\n    @Override\n    public void setFillColor(int color) throws RemoteException {\n        options.fillColor(color);\n        listener.update(this);\n    }\n\n    @Override\n    public int getFillColor() {\n        return options.getFillColor();\n    }\n\n    @Override\n    public void setZIndex(float zIndex) throws RemoteException {\n        options.zIndex(zIndex);\n        listener.update(this);\n    }\n\n    @Override\n    public float getZIndex() {\n        return options.getZIndex();\n    }\n\n    @Override\n    public Drawable getDrawable(Map map) {\n        if (!isVisible() || removed) return null;\n        List<GeoPoint> points = new ArrayList<GeoPoint>();\n        for (LatLng point : options.getPoints()) {\n            points.add(GmsMapsTypeHelper.fromLatLng(point));\n        }\n        if (points.size() < 3 || (points.size() == 3 && points.get(2).equals(points.get(0)))) {\n            // Need at least 3 distinguished points to draw a polygon\n            return null;\n        }\n        // TODO: holes\n        return new PolygonDrawable(points, Style.builder()\n                .fillAlpha(1)\n                .strokeColor(getStrokeColor())\n                .strokeWidth(getStrokeWidth())\n                .fillColor(getFillColor())\n                .build());\n    }\n\n    @Override\n    public void setVisible(boolean visible) throws RemoteException {\n        options.visible(visible);\n        listener.update(this);\n    }\n\n    @Override\n    public boolean isVisible() {\n        return options.isVisible();\n    }\n\n    @Override\n    public void setGeodesic(boolean geod) throws RemoteException {\n        options.geodesic(geod);\n        listener.update(this);\n    }\n\n    @Override\n    public boolean isGeodesic() throws RemoteException {\n        return options.isGeodesic();\n    }\n\n    @Override\n    public boolean equalsRemote(IPolygonDelegate other) throws RemoteException {\n        return other != null && other.getId().equals(getId());\n    }\n\n    @Override\n    public int hashCodeRemote() throws RemoteException {\n        return id.hashCode();\n    }\n\n    // Not implemented\n    @Override\n    public void setClickable(boolean click) throws RemoteException {\n\n    }\n\n    @Override\n    public boolean isClickable() throws RemoteException {\n        return false;\n    }\n\n    @Override\n    public void setStrokeJointType(int type) throws RemoteException {\n\n    }\n\n    @Override\n    public int getStrokeJointType() throws RemoteException {\n        return 0;\n    }\n\n    @Override\n    public void setStrokePattern(List<PatternItem> items) throws RemoteException {\n\n    }\n\n    @Override\n    public List<PatternItem> getStrokePattern() throws RemoteException {\n        return null;\n    }\n\n    @Override\n    public void setTag(IObjectWrapper obj) throws RemoteException {\n\n    }\n\n    @Override\n    public IObjectWrapper getTag() throws RemoteException {\n        return null;\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/src/main/java/org/microg/gms/maps/vtm/markup/PolylineImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.maps.vtm.markup;\n\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.maps.model.Cap;\nimport com.google.android.gms.maps.model.LatLng;\nimport com.google.android.gms.maps.model.PatternItem;\nimport com.google.android.gms.maps.model.PolylineOptions;\nimport com.google.android.gms.maps.model.internal.IPolylineDelegate;\n\nimport org.microg.gms.maps.vtm.GmsMapsTypeHelper;\nimport org.oscim.core.GeoPoint;\nimport org.oscim.layers.vector.geometries.Drawable;\nimport org.oscim.layers.vector.geometries.LineDrawable;\nimport org.oscim.layers.vector.geometries.Style;\nimport org.oscim.map.Map;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class PolylineImpl extends IPolylineDelegate.Stub implements DrawableMarkup {\n    private static final String TAG = \"GmsMapsPolylineImpl\";\n\n    private final String id;\n    private final PolylineOptions options;\n    private final MarkupListener listener;\n    private boolean removed = false;\n\n    public PolylineImpl(String id, PolylineOptions options, MarkupListener listener) {\n        this.id = id;\n        this.options = options == null ? new PolylineOptions() : options;\n        this.listener = listener;\n    }\n\n    @Override\n    public void remove() {\n        listener.remove(this);\n        removed = true;\n    }\n\n    @Override\n    public String getId() {\n        return id;\n    }\n\n    @Override\n    public boolean onClick() {\n        return listener.onClick(this);\n    }\n\n    @Override\n    public void onDragStart() {\n        listener.onDragStart(this);\n    }\n\n    @Override\n    public void onDragStop() {\n        listener.onDragStop(this);\n    }\n\n    @Override\n    public void onDragProgress() {\n        listener.onDragProgress(this);\n    }\n\n    @Override\n    public void setPoints(List<LatLng> points) {\n        options.getPoints().clear();\n        options.getPoints().addAll(points);\n        listener.update(this);\n    }\n\n    @Override\n    public List<LatLng> getPoints() {\n        return options.getPoints();\n    }\n\n    @Override\n    public void setWidth(float width) {\n        options.width(width);\n        listener.update(this);\n    }\n\n    @Override\n    public float getWidth() {\n        return options.getWidth();\n    }\n\n    @Override\n    public void setColor(int color) {\n        this.options.color(color);\n        listener.update(this);\n    }\n\n    @Override\n    public int getColor() {\n        return options.getColor();\n    }\n\n    @Override\n    public void setZIndex(float zIndex) {\n        options.zIndex(zIndex);\n        listener.update(this);\n    }\n\n    @Override\n    public float getZIndex() {\n        return options.getZIndex();\n    }\n\n    @Override\n    public void setVisible(boolean visible) {\n        options.visible(visible);\n        listener.update(this);\n    }\n\n    @Override\n    public boolean isVisible() {\n        return options.isVisible();\n    }\n\n    @Override\n    public void setGeodesic(boolean geod) {\n        options.geodesic(geod);\n        listener.update(this);\n    }\n\n    @Override\n    public boolean isGeodesic() {\n        return options.isGeodesic();\n    }\n\n    @Override\n    public boolean equalsRemote(IPolylineDelegate other) throws RemoteException {\n        Log.d(TAG, \"equalsRemote\");\n        return other != null && other.getId().equals(getId());\n    }\n\n    @Override\n    public int hashCodeRemote() {\n        Log.d(TAG, \"hashcodeRemote\");\n        return id.hashCode();\n    }\n\n    // Not implemented\n    @Override\n    public void setClickable(boolean clickable) throws RemoteException {\n\n    }\n\n    @Override\n    public boolean isClickable() throws RemoteException {\n        return false;\n    }\n\n    @Override\n    public void setStartCap(Cap startCap) throws RemoteException {\n\n    }\n\n    @Override\n    public Cap getStartCap() throws RemoteException {\n        return null;\n    }\n\n    @Override\n    public void setEndCap(Cap endCap) throws RemoteException {\n\n    }\n\n    @Override\n    public Cap getEndCap() throws RemoteException {\n        return null;\n    }\n\n    @Override\n    public void setJointType(int jointType) throws RemoteException {\n\n    }\n\n    @Override\n    public int getJointType() throws RemoteException {\n        return 0;\n    }\n\n    @Override\n    public void setPattern(List<PatternItem> pattern) throws RemoteException {\n\n    }\n\n    @Override\n    public List<PatternItem> getPattern() throws RemoteException {\n        return null;\n    }\n\n    @Override\n    public void setTag(IObjectWrapper tag) throws RemoteException {\n\n    }\n\n    @Override\n    public IObjectWrapper getTag() throws RemoteException {\n        return null;\n    }\n\n    @Override\n    public Drawable getDrawable(Map map) {\n        if (!isVisible() || removed) return null;\n        if (options.getPoints().size() < 2) {\n            // You hardly draw a line with less than two points\n            return null;\n        }\n        List<GeoPoint> points = new ArrayList<GeoPoint>();\n        for (LatLng point : options.getPoints()) {\n            points.add(GmsMapsTypeHelper.fromLatLng(point));\n        }\n        return new LineDrawable(points, Style.builder().strokeColor(getColor()).strokeWidth(getWidth()).build());\n    }\n}\n"
  },
  {
    "path": "play-services-maps/core/vtm/src/main/java/org/microg/gms/maps/vtm/markup/TileOverlayImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.maps.vtm.markup;\n\nimport android.os.RemoteException;\nimport com.google.android.gms.maps.model.internal.ITileOverlayDelegate;\n\npublic class TileOverlayImpl extends ITileOverlayDelegate.Stub {\n    @Override\n    public void remove() throws RemoteException {\n\n    }\n\n    @Override\n    public void clearTileCache() throws RemoteException {\n\n    }\n\n    @Override\n    public String getId() throws RemoteException {\n        return null;\n    }\n\n    @Override\n    public void setZIndex(float zIndex) throws RemoteException {\n\n    }\n\n    @Override\n    public float getZIndex() throws RemoteException {\n        return 0;\n    }\n\n    @Override\n    public void setVisible(boolean visible) throws RemoteException {\n\n    }\n\n    @Override\n    public boolean isVisible() throws RemoteException {\n        return false;\n    }\n\n    @Override\n    public boolean equalsRemote(ITileOverlayDelegate other) throws RemoteException {\n        return false;\n    }\n\n    @Override\n    public int hashCodeRemote() throws RemoteException {\n        return 0;\n    }\n\n    @Override\n    public void setFadeIn(boolean fadeIn) throws RemoteException {\n\n    }\n\n    @Override\n    public boolean getFadeIn() throws RemoteException {\n        return false;\n    }\n\n    @Override\n    public void setTransparency(float transparency) throws RemoteException {\n\n    }\n\n    @Override\n    public float getTransparency() throws RemoteException {\n        return 0;\n    }\n}\n"
  },
  {
    "path": "play-services-maps/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <!-- Include required permissions for Google Maps API to run. -->\n    <uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>\n    <uses-permission android:name=\"android.permission.INTERNET\"/>\n\n    <uses-feature android:glEsVersion=\"0x00020000\" android:required=\"true\"/>\n\n    <queries>\n        <package android:name=\"com.google.android.apps.maps\"/>\n    </queries>\n\n    <application>\n        <uses-library android:name=\"org.apache.http.legacy\"\n                      android:required=\"false\"/>\n    </application>\n</manifest>\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/GoogleMapOptions.aidl",
    "content": "package com.google.android.gms.maps;\n\nparcelable GoogleMapOptions;\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/StreetViewPanoramaOptions.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.maps;\n\nparcelable StreetViewPanoramaOptions;\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/ICameraUpdateFactoryDelegate.aidl",
    "content": "package com.google.android.gms.maps.internal;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.maps.model.CameraPosition;\nimport com.google.android.gms.maps.model.LatLng;\nimport com.google.android.gms.maps.model.LatLngBounds;\n\ninterface ICameraUpdateFactoryDelegate {\n    IObjectWrapper zoomIn();\n    IObjectWrapper zoomOut();\n    IObjectWrapper scrollBy(float x, float y);\n    IObjectWrapper zoomTo(float zoom);\n    IObjectWrapper zoomBy(float zoomDelta);\n    IObjectWrapper zoomByWithFocus(float zoomDelta, int x, int y);\n    IObjectWrapper newCameraPosition(in CameraPosition cameraPosition);\n    IObjectWrapper newLatLng(in LatLng latLng);\n    IObjectWrapper newLatLngZoom(in LatLng latLng, float zoom);\n    IObjectWrapper newLatLngBounds(in LatLngBounds bounds, int padding);\n    IObjectWrapper newLatLngBoundsWithSize(in LatLngBounds bounds, int width, int height, int padding);\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/ICancelableCallback.aidl",
    "content": "package com.google.android.gms.maps.internal;\n\ninterface ICancelableCallback {\n    void onFinish();\n    void onCancel();\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/ICreator.aidl",
    "content": "package com.google.android.gms.maps.internal;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.maps.GoogleMapOptions;\nimport com.google.android.gms.maps.StreetViewPanoramaOptions;\nimport com.google.android.gms.maps.internal.IMapFragmentDelegate;\nimport com.google.android.gms.maps.internal.IMapViewDelegate;\nimport com.google.android.gms.maps.internal.ICameraUpdateFactoryDelegate;\nimport com.google.android.gms.maps.internal.IStreetViewPanoramaFragmentDelegate;\nimport com.google.android.gms.maps.internal.IStreetViewPanoramaViewDelegate;\nimport com.google.android.gms.maps.model.internal.IBitmapDescriptorFactoryDelegate;\n\ninterface ICreator {\n    void init(IObjectWrapper resources) = 0;\n    IMapFragmentDelegate newMapFragmentDelegate(IObjectWrapper activity) = 1;\n    IMapViewDelegate newMapViewDelegate(IObjectWrapper context, in GoogleMapOptions options) = 2;\n    ICameraUpdateFactoryDelegate newCameraUpdateFactoryDelegate() = 3;\n    IBitmapDescriptorFactoryDelegate newBitmapDescriptorFactoryDelegate() = 4;\n    void initV2(IObjectWrapper resources, int versionCode) = 5;\n    IStreetViewPanoramaViewDelegate newStreetViewPanoramaViewDelegate(IObjectWrapper context, in StreetViewPanoramaOptions options) = 6;\n    IStreetViewPanoramaFragmentDelegate newStreetViewPanoramaFragmentDelegate(IObjectWrapper activity) = 7;\n    int getRendererType() = 8;\n    void logInitialization(IObjectWrapper context, int preferredRenderer) = 9;\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IGoogleMapDelegate.aidl",
    "content": "package com.google.android.gms.maps.internal;\n\nimport android.location.Location;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.maps.model.CameraPosition;\nimport com.google.android.gms.maps.internal.ICancelableCallback;\nimport com.google.android.gms.maps.internal.ILocationSourceDelegate;\nimport com.google.android.gms.maps.internal.IUiSettingsDelegate;\nimport com.google.android.gms.maps.internal.IProjectionDelegate;\nimport com.google.android.gms.maps.internal.IOnCameraChangeListener;\nimport com.google.android.gms.maps.internal.IOnCameraIdleListener;\nimport com.google.android.gms.maps.internal.IOnCameraMoveCanceledListener;\nimport com.google.android.gms.maps.internal.IOnCameraMoveListener;\nimport com.google.android.gms.maps.internal.IOnCameraMoveStartedListener;\nimport com.google.android.gms.maps.internal.IOnCircleClickListener;\nimport com.google.android.gms.maps.internal.IOnMapClickListener;\nimport com.google.android.gms.maps.internal.IOnMapLongClickListener;\nimport com.google.android.gms.maps.internal.IOnMarkerClickListener;\nimport com.google.android.gms.maps.internal.IOnMarkerDragListener;\nimport com.google.android.gms.maps.internal.IOnInfoWindowClickListener;\nimport com.google.android.gms.maps.internal.IOnInfoWindowCloseListener;\nimport com.google.android.gms.maps.internal.IOnInfoWindowLongClickListener;\nimport com.google.android.gms.maps.internal.IInfoWindowAdapter;\nimport com.google.android.gms.maps.internal.IOnMapLoadedCallback;\nimport com.google.android.gms.maps.internal.IOnMyLocationChangeListener;\nimport com.google.android.gms.maps.internal.IOnMyLocationClickListener;\nimport com.google.android.gms.maps.internal.IOnMyLocationButtonClickListener;\nimport com.google.android.gms.maps.internal.IOnGroundOverlayClickListener;\nimport com.google.android.gms.maps.internal.IOnPolygonClickListener;\nimport com.google.android.gms.maps.internal.IOnPolylineClickListener;\nimport com.google.android.gms.maps.internal.ISnapshotReadyCallback;\nimport com.google.android.gms.maps.model.CircleOptions;\nimport com.google.android.gms.maps.model.GroundOverlayOptions;\nimport com.google.android.gms.maps.model.LatLngBounds;\nimport com.google.android.gms.maps.model.MarkerOptions;\nimport com.google.android.gms.maps.model.MapStyleOptions;\nimport com.google.android.gms.maps.model.PolygonOptions;\nimport com.google.android.gms.maps.model.PolylineOptions;\nimport com.google.android.gms.maps.model.TileOverlayOptions;\nimport com.google.android.gms.maps.model.internal.ICircleDelegate;\nimport com.google.android.gms.maps.model.internal.IGroundOverlayDelegate;\nimport com.google.android.gms.maps.model.internal.IIndoorBuildingDelegate;\nimport com.google.android.gms.maps.model.internal.IMarkerDelegate;\nimport com.google.android.gms.maps.model.internal.IPolygonDelegate;\nimport com.google.android.gms.maps.model.internal.IPolylineDelegate;\nimport com.google.android.gms.maps.model.internal.ITileOverlayDelegate;\n\ninterface IGoogleMapDelegate {\n    CameraPosition getCameraPosition() = 0;\n\n    float getMaxZoomLevel() = 1;\n    float getMinZoomLevel() = 2;\n\n    void moveCamera(IObjectWrapper cameraUpdate) = 3;\n    void animateCamera(IObjectWrapper cameraUpdate) = 4;\n    void animateCameraWithCallback(IObjectWrapper cameraUpdate, ICancelableCallback callback) = 5;\n    void animateCameraWithDurationAndCallback(IObjectWrapper cameraUpdate, int duration, ICancelableCallback callback) = 6;\n    void stopAnimation() = 7;\n\n    IPolylineDelegate addPolyline(in PolylineOptions options) = 8;\n    IPolygonDelegate addPolygon(in PolygonOptions options) = 9;\n    IMarkerDelegate addMarker(in MarkerOptions options) = 10;\n    IGroundOverlayDelegate addGroundOverlay(in GroundOverlayOptions options) = 11;\n    ITileOverlayDelegate addTileOverlay(in TileOverlayOptions options) = 12;\n\n    void clear() = 13;\n\n    int getMapType() = 14;\n    void setMapType(int type) = 15;\n    boolean isTrafficEnabled() = 16;\n    void setTrafficEnabled(boolean traffic) = 17;\n    boolean isIndoorEnabled() = 18;\n    void setIndoorEnabled(boolean indoor) = 19;\n\n    boolean isMyLocationEnabled() = 20;\n    void setMyLocationEnabled(boolean myLocation) = 21;\n    Location getMyLocation() = 22;\n    void setLocationSource(ILocationSourceDelegate locationSource) = 23;\n\n    IUiSettingsDelegate getUiSettings() = 24;\n    IProjectionDelegate getProjection() = 25;\n\n    void setOnCameraChangeListener(IOnCameraChangeListener listener) = 26;\n    void setOnMapClickListener(IOnMapClickListener listener) = 27;\n    void setOnMapLongClickListener(IOnMapLongClickListener listener) = 28;\n    void setOnMarkerClickListener(IOnMarkerClickListener listener) = 29;\n    void setOnMarkerDragListener(IOnMarkerDragListener listener) = 30;\n    void setOnInfoWindowClickListener(IOnInfoWindowClickListener listener) = 31;\n    void setInfoWindowAdapter(IInfoWindowAdapter adapter) = 32;\n\n    IObjectWrapper getTestingHelper() = 33;\n\n    ICircleDelegate addCircle(in CircleOptions options) = 34;\n\n    void setOnMyLocationChangeListener(IOnMyLocationChangeListener listener) = 35;\n    void setOnMyLocationButtonClickListener(IOnMyLocationButtonClickListener listener) = 36;\n\n    void snapshot(ISnapshotReadyCallback callback, IObjectWrapper bitmap) = 37;\n\n    void setPadding(int left, int top, int right, int bottom) = 38;\n\n    boolean isBuildingsEnabled() = 39;\n    void setBuildingsEnabled(boolean buildings) = 40;\n\n    void setOnMapLoadedCallback(IOnMapLoadedCallback callback) = 41;\n\n    //IIndoorBuildingDelegate getFocusedBuilding() = 43;\n    //void setIndoorStateChangeListener(IOnIndoorStateChangeListener listener) = 44;\n\n    void setWatermarkEnabled(boolean watermark) = 50;\n\n    //void getMapAsync(IOnMapReadyCallback callback) = 52;\n    void onCreate(in Bundle savedInstanceState) = 53;\n    void onResume() = 54;\n    void onPause() = 55;\n    void onDestroy() = 56;\n    void onLowMemory() = 57;\n    boolean useViewLifecycleWhenInFragment() = 58;\n    void onSaveInstanceState(out Bundle outState) = 59;\n\n    void setContentDescription(String desc) = 60;\n\n    void snapshotForTest(ISnapshotReadyCallback callback) = 70;\n\n    //void setPoiClickListener(IOnPoiClickListener listener) = 79;\n    void onEnterAmbient(in Bundle bundle) = 80;\n    void onExitAmbient() = 81;\n\n    void setOnGroundOverlayClickListener(IOnGroundOverlayClickListener listener) = 82;\n    void setOnInfoWindowLongClickListener(IOnInfoWindowLongClickListener listener) = 83;\n    void setOnPolygonClickListener(IOnPolygonClickListener listener) = 84;\n    void setOnInfoWindowCloseListener(IOnInfoWindowCloseListener listener) = 85;\n    void setOnPolylineClickListener(IOnPolylineClickListener listener) = 86;\n    void setOnCircleClickListener(IOnCircleClickListener listener) = 88;\n\n    boolean setMapStyle(in MapStyleOptions options) = 90;\n    void setMinZoomPreference(float minZoom) = 91;\n    void setMaxZoomPreference(float maxZoom) = 92;\n    void resetMinMaxZoomPreference() = 93;\n    void setLatLngBoundsForCameraTarget(in LatLngBounds bounds) = 94;\n\n    void setCameraMoveStartedListener(IOnCameraMoveStartedListener listener) = 95;\n    void setCameraMoveListener(IOnCameraMoveListener listener) = 96;\n    void setCameraMoveCanceledListener(IOnCameraMoveCanceledListener listener) = 97;\n    void setCameraIdleListener(IOnCameraIdleListener listener) = 98;\n\n    void onStart() = 100;\n    void onStop() = 101;\n\n    void setOnMyLocationClickListener(IOnMyLocationClickListener listener) = 106;\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IInfoWindowAdapter.aidl",
    "content": "package com.google.android.gms.maps.internal;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.maps.model.internal.IMarkerDelegate;\n\ninterface IInfoWindowAdapter {\n    IObjectWrapper getInfoWindow(IMarkerDelegate marker);\n    IObjectWrapper getInfoContents(IMarkerDelegate marker);\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/ILocationSourceDelegate.aidl",
    "content": "package com.google.android.gms.maps.internal;\n\nimport com.google.android.gms.maps.internal.IOnLocationChangeListener;\n\ninterface ILocationSourceDelegate {\n    void activate(IOnLocationChangeListener listener) = 0;\n    void deactivate() = 1;\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IMapFragmentDelegate.aidl",
    "content": "package com.google.android.gms.maps.internal;\n\nimport android.os.Bundle;\n\nimport com.google.android.gms.maps.internal.IGoogleMapDelegate;\nimport com.google.android.gms.maps.internal.IOnMapReadyCallback;\nimport com.google.android.gms.maps.GoogleMapOptions;\nimport com.google.android.gms.dynamic.IObjectWrapper;\n\ninterface IMapFragmentDelegate {\n    IGoogleMapDelegate getMap();\n    void onInflate(IObjectWrapper activity, in GoogleMapOptions options, in Bundle savedInstanceState);\n    void onCreate(in Bundle savedInstanceState);\n    IObjectWrapper onCreateView(IObjectWrapper layoutInflater, IObjectWrapper container, in Bundle savedInstanceState);\n    void onResume();\n    void onPause();\n    void onDestroyView();\n    void onDestroy();\n    void onLowMemory();\n    void onSaveInstanceState(inout Bundle outState);\n    boolean isReady();\n    void getMapAsync(IOnMapReadyCallback callback);\n    void onEnterAmbient(in Bundle bundle);\n    void onExitAmbient();\n    void onStart();\n    void onStop();\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IMapViewDelegate.aidl",
    "content": "package com.google.android.gms.maps.internal;\n\nimport android.os.Bundle;\n\nimport com.google.android.gms.maps.internal.IGoogleMapDelegate;\nimport com.google.android.gms.maps.internal.IOnMapReadyCallback;\nimport com.google.android.gms.dynamic.IObjectWrapper;\n\ninterface IMapViewDelegate {\n    IGoogleMapDelegate getMap();\n    void onCreate(in Bundle savedInstanceState);\n    void onResume();\n    void onPause();\n    void onDestroy();\n    void onLowMemory();\n    void onSaveInstanceState(inout Bundle outState);\n    IObjectWrapper getView();\n    void getMapAsync(IOnMapReadyCallback callback);\n    void onEnterAmbient(in Bundle bundle);\n    void onExitAmbient();\n    void onStart();\n    void onStop();\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IOnCameraChangeListener.aidl",
    "content": "package com.google.android.gms.maps.internal;\n\nimport com.google.android.gms.maps.model.CameraPosition;\n\ninterface IOnCameraChangeListener {\n    void onCameraChange(in CameraPosition update);\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IOnCameraIdleListener.aidl",
    "content": "package com.google.android.gms.maps.internal;\n\ninterface IOnCameraIdleListener {\n    void onCameraIdle();\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IOnCameraMoveCanceledListener.aidl",
    "content": "package com.google.android.gms.maps.internal;\n\ninterface IOnCameraMoveCanceledListener {\n    void onCameraMoveCanceled();\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IOnCameraMoveListener.aidl",
    "content": "package com.google.android.gms.maps.internal;\n\ninterface IOnCameraMoveListener {\n    void onCameraMove();\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IOnCameraMoveStartedListener.aidl",
    "content": "package com.google.android.gms.maps.internal;\n\ninterface IOnCameraMoveStartedListener {\n    void onCameraMoveStarted(int i);\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IOnCircleClickListener.aidl",
    "content": "package com.google.android.gms.maps.internal;\n\nimport com.google.android.gms.maps.model.internal.ICircleDelegate;\n\ninterface IOnCircleClickListener {\n    void onCircleClick(ICircleDelegate circle);\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IOnGroundOverlayClickListener.aidl",
    "content": "package com.google.android.gms.maps.internal;\n\nimport com.google.android.gms.maps.model.internal.IGroundOverlayDelegate;\n\ninterface IOnGroundOverlayClickListener {\n    void onGroundOverlayClick(IGroundOverlayDelegate groundOverlay);\n}"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IOnIndoorStateChangeListener.aidl",
    "content": "package com.google.android.gms.maps.internal;\n\ninterface IOnIndoorStateChangeListener {\n    void onIndoorBuildingFocused() = 0;\n    void onIndoorLevelActivated() = 1;\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IOnInfoWindowClickListener.aidl",
    "content": "package com.google.android.gms.maps.internal;\n\nimport com.google.android.gms.maps.model.internal.IMarkerDelegate;\n\ninterface IOnInfoWindowClickListener {\n    void onInfoWindowClick(IMarkerDelegate marker);\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IOnInfoWindowCloseListener.aidl",
    "content": "package com.google.android.gms.maps.internal;\n\nimport com.google.android.gms.maps.model.internal.IMarkerDelegate;\n\ninterface IOnInfoWindowCloseListener {\n    void onInfoWindowClose(IMarkerDelegate marker);\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IOnInfoWindowLongClickListener.aidl",
    "content": "package com.google.android.gms.maps.internal;\n\nimport com.google.android.gms.maps.model.internal.IMarkerDelegate;\n\ninterface IOnInfoWindowLongClickListener {\n    void onInfoWindowLongClick(IMarkerDelegate marker);\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IOnLocationChangeListener.aidl",
    "content": "package com.google.android.gms.maps.internal;\n\nimport android.location.Location;\n\ninterface IOnLocationChangeListener {\n    void onLocationChanged(in Location location) = 1;\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IOnMapClickListener.aidl",
    "content": "package com.google.android.gms.maps.internal;\n\nimport com.google.android.gms.maps.model.LatLng;\n\ninterface IOnMapClickListener {\n    void onMapClick(in LatLng latLng);\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IOnMapLoadedCallback.aidl",
    "content": "package com.google.android.gms.maps.internal;\n\ninterface IOnMapLoadedCallback {\n    void onMapLoaded();\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IOnMapLongClickListener.aidl",
    "content": "package com.google.android.gms.maps.internal;\n\nimport com.google.android.gms.maps.model.LatLng;\n\ninterface IOnMapLongClickListener {\n    void onMapLongClick(in LatLng latLng);\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IOnMapReadyCallback.aidl",
    "content": "package com.google.android.gms.maps.internal;\n\nimport com.google.android.gms.maps.internal.IGoogleMapDelegate;\n\ninterface IOnMapReadyCallback {\n    void onMapReady(IGoogleMapDelegate map);\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IOnMarkerClickListener.aidl",
    "content": "package com.google.android.gms.maps.internal;\n\nimport com.google.android.gms.maps.model.internal.IMarkerDelegate;\n\ninterface IOnMarkerClickListener {\n    boolean onMarkerClick(IMarkerDelegate marker);\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IOnMarkerDragListener.aidl",
    "content": "package com.google.android.gms.maps.internal;\n\nimport com.google.android.gms.maps.model.internal.IMarkerDelegate;\n\ninterface IOnMarkerDragListener {\n    void onMarkerDragStart(IMarkerDelegate marker) = 0;\n    void onMarkerDrag(IMarkerDelegate marker) = 1;\n    void onMarkerDragEnd(IMarkerDelegate marker) = 2;\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IOnMyLocationButtonClickListener.aidl",
    "content": "package com.google.android.gms.maps.internal;\n\ninterface IOnMyLocationButtonClickListener {\n    boolean onMyLocationButtonClick();\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IOnMyLocationChangeListener.aidl",
    "content": "package com.google.android.gms.maps.internal;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\n\ninterface IOnMyLocationChangeListener {\n    void onMyLocationChanged(IObjectWrapper location);\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IOnMyLocationClickListener.aidl",
    "content": "package com.google.android.gms.maps.internal;\n\nimport android.location.Location;\n\ninterface IOnMyLocationClickListener {\n    void onMyLocationClick(in Location location);\n}"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IOnPolygonClickListener.aidl",
    "content": "package com.google.android.gms.maps.internal;\n\nimport com.google.android.gms.maps.model.internal.IPolygonDelegate;\n\ninterface IOnPolygonClickListener {\n    void onPolygonClick(IPolygonDelegate polygon);\n}"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IOnPolylineClickListener.aidl",
    "content": "package com.google.android.gms.maps.internal;\n\nimport com.google.android.gms.maps.model.internal.IPolylineDelegate;\n\ninterface IOnPolylineClickListener {\n    void onPolylineClick(IPolylineDelegate polyline);\n}"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IOnStreetViewPanoramaCameraChangeListener.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.maps.internal;\n\nimport com.google.android.gms.maps.model.StreetViewPanoramaCamera;\n\ninterface IOnStreetViewPanoramaCameraChangeListener {\n    void onStreetViewPanoramaCameraChange(in StreetViewPanoramaCamera camera);\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IOnStreetViewPanoramaChangeListener.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.maps.internal;\n\nimport com.google.android.gms.maps.model.StreetViewPanoramaLocation;\n\ninterface IOnStreetViewPanoramaChangeListener {\n    void onStreetViewPanoramaChange(in StreetViewPanoramaLocation location);\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IOnStreetViewPanoramaClickListener.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.maps.internal;\n\nimport com.google.android.gms.maps.model.StreetViewPanoramaOrientation;\n\ninterface IOnStreetViewPanoramaClickListener {\n    void onStreetViewPanoramaClick(in StreetViewPanoramaOrientation orientation);\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IOnStreetViewPanoramaLongClickListener.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.maps.internal;\n\nimport com.google.android.gms.maps.model.StreetViewPanoramaOrientation;\n\ninterface IOnStreetViewPanoramaLongClickListener {\n    void onStreetViewPanoramaLongClick(in StreetViewPanoramaOrientation orientation);\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IOnStreetViewPanoramaReadyCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.maps.internal;\n\nimport com.google.android.gms.maps.internal.IStreetViewPanoramaDelegate;\n\ninterface IOnStreetViewPanoramaReadyCallback {\n    void onStreetViewPanoramaReady(IStreetViewPanoramaDelegate streetView);\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IProjectionDelegate.aidl",
    "content": "package com.google.android.gms.maps.internal;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.maps.model.LatLng;\nimport com.google.android.gms.maps.model.VisibleRegion;\n\ninterface IProjectionDelegate {\n    LatLng fromScreenLocation(IObjectWrapper obj);\n    IObjectWrapper toScreenLocation(in LatLng latLng);\n    VisibleRegion getVisibleRegion();\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/ISnapshotReadyCallback.aidl",
    "content": "package com.google.android.gms.maps.internal;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport android.graphics.Bitmap;\n\ninterface ISnapshotReadyCallback {\n    void onBitmapReady(in Bitmap bitmap);\n    void onBitmapWrappedReady(IObjectWrapper wrapper);\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IStreetViewPanoramaDelegate.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.maps.internal;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.maps.internal.IOnStreetViewPanoramaCameraChangeListener;\nimport com.google.android.gms.maps.internal.IOnStreetViewPanoramaChangeListener;\nimport com.google.android.gms.maps.internal.IOnStreetViewPanoramaClickListener;\nimport com.google.android.gms.maps.internal.IOnStreetViewPanoramaLongClickListener;\nimport com.google.android.gms.maps.model.LatLng;\nimport com.google.android.gms.maps.model.StreetViewPanoramaCamera;\nimport com.google.android.gms.maps.model.StreetViewPanoramaLocation;\nimport com.google.android.gms.maps.model.StreetViewPanoramaOrientation;\nimport com.google.android.gms.maps.model.StreetViewSource;\n\ninterface IStreetViewPanoramaDelegate {\n    void enableZoom(boolean enableZoom) = 0;\n    void enablePanning(boolean enablePanning) = 1;\n    void enableUserNavigation(boolean enableUserNavigation) = 2;\n    void enableStreetNames(boolean enableStreetNames) = 3;\n    boolean isZoomGesturesEnabled() = 4;\n    boolean isPanningGesturesEnabled() = 5;\n    boolean isUserNavigationEnabled() = 6;\n    boolean isStreetNamesEnabled() = 7;\n    void animateTo(in StreetViewPanoramaCamera streetViewPanoramaCamera, long duration) = 8;\n    StreetViewPanoramaCamera getPanoramaCamera() = 9;\n    void setPositionWithID(String panoramaId) = 10;\n    void setPosition(in LatLng position) = 11;\n    void setPositionWithRadius(in LatLng position, int radius) = 12;\n    StreetViewPanoramaLocation getStreetViewPanoramaLocation() = 13;\n    void setOnStreetViewPanoramaChangeListener(IOnStreetViewPanoramaChangeListener listener) = 14;\n    void setOnStreetViewPanoramaCameraChangeListener(IOnStreetViewPanoramaCameraChangeListener listener) = 15;\n    void setOnStreetViewPanoramaClickListener(IOnStreetViewPanoramaClickListener listener) = 16;\n    StreetViewPanoramaOrientation pointToOrientation(in IObjectWrapper point) = 17;\n    IObjectWrapper orientationToPoint(in StreetViewPanoramaOrientation orientation) = 18;\n    void setOnStreetViewPanoramaLongClickListener(IOnStreetViewPanoramaLongClickListener listener) = 19;\n    void setPositionWithSource(in LatLng position, in StreetViewSource source) = 20;\n    void setPositionWithRadiusAndSource(in LatLng position, int radius, in StreetViewSource source) = 21;\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IStreetViewPanoramaFragmentDelegate.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.maps.internal;\n\nimport android.os.Bundle;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.maps.StreetViewPanoramaOptions;\nimport com.google.android.gms.maps.internal.IOnStreetViewPanoramaReadyCallback;\nimport com.google.android.gms.maps.internal.IStreetViewPanoramaDelegate;\n\ninterface IStreetViewPanoramaFragmentDelegate {\n    IStreetViewPanoramaDelegate getStreetViewPanorama() = 0;\n    void onInflate(IObjectWrapper activity, in StreetViewPanoramaOptions options, in Bundle savedInstanceState) = 1;\n    void onCreate(in Bundle savedInstanceState) = 2;\n    IObjectWrapper onCreateView(IObjectWrapper layoutInflater, IObjectWrapper container, in Bundle savedInstanceState) = 3;\n    void onResume() = 4;\n    void onPause() = 5;\n    void onDestroyView() = 6;\n    void onDestroy() = 7;\n    void onLowMemory() = 8;\n    void onSaveInstanceState(inout Bundle outState) = 9;\n    boolean isReady() = 10;\n    void getStreetViewPanoramaAsync(IOnStreetViewPanoramaReadyCallback callback) = 11;\n    void onStart() = 12;\n    void onStop() = 13;\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IStreetViewPanoramaViewDelegate.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.maps.internal;\n\nimport android.os.Bundle;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.maps.internal.IOnStreetViewPanoramaReadyCallback;\nimport com.google.android.gms.maps.internal.IStreetViewPanoramaDelegate;\n\ninterface IStreetViewPanoramaViewDelegate {\n    IStreetViewPanoramaDelegate getStreetViewPanorama() = 0;\n    void onCreate(in Bundle savedInstanceState) = 1;\n    void onResume() = 2;\n    void onPause() = 3;\n    void onDestroy() = 4;\n    void onLowMemory() = 5;\n    void onSaveInstanceState(inout Bundle outState) = 6;\n    IObjectWrapper getView() = 7;\n    void getStreetViewPanoramaAsync(IOnStreetViewPanoramaReadyCallback callback) = 8;\n    void onStart() = 9;\n    void onStop() = 10;\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/internal/IUiSettingsDelegate.aidl",
    "content": "package com.google.android.gms.maps.internal;\n\ninterface IUiSettingsDelegate {\n    void setZoomControlsEnabled(boolean zoom);\n    void setCompassEnabled(boolean compass);\n    void setMyLocationButtonEnabled(boolean locationButton);\n    void setScrollGesturesEnabled(boolean scrollGestures);\n    void setZoomGesturesEnabled(boolean zoomGestures);\n    void setTiltGesturesEnabled(boolean tiltGestures);\n    void setRotateGesturesEnabled(boolean rotateGestures);\n    void setAllGesturesEnabled(boolean gestures);\n    boolean isZoomControlsEnabled();\n    boolean isCompassEnabled();\n    boolean isMyLocationButtonEnabled();\n    boolean isScrollGesturesEnabled();\n    boolean isZoomGesturesEnabled();\n    boolean isTiltGesturesEnabled();\n    boolean isRotateGesturesEnabled();\n    void setIndoorLevelPickerEnabled(boolean indoorLevelPicker);\n    boolean isIndoorLevelPickerEnabled();\n    void setMapToolbarEnabled(boolean mapToolbar);\n    boolean isMapToolbarEnabled();\n    void setScrollGesturesEnabledDuringRotateOrZoom(boolean scrollDuringZoom);\n    boolean isScrollGesturesEnabledDuringRotateOrZoom();\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/model/CameraPosition.aidl",
    "content": "package com.google.android.gms.maps.model;\n\nparcelable CameraPosition;\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/model/Cap.aidl",
    "content": "package com.google.android.gms.maps.model;\n\nparcelable Cap;\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/model/CircleOptions.aidl",
    "content": "package com.google.android.gms.maps.model;\n\nparcelable CircleOptions;\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/model/Dash.aidl",
    "content": "package com.google.android.gms.maps.model;\n\nparcelable Dash;\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/model/Dot.aidl",
    "content": "package com.google.android.gms.maps.model;\n\nparcelable Dot;\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/model/Gap.aidl",
    "content": "package com.google.android.gms.maps.model;\n\nparcelable Gap;\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/model/GroundOverlayOptions.aidl",
    "content": "package com.google.android.gms.maps.model;\n\nparcelable GroundOverlayOptions;\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/model/LatLng.aidl",
    "content": "package com.google.android.gms.maps.model;\n\nparcelable LatLng;\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/model/LatLngBounds.aidl",
    "content": "package com.google.android.gms.maps.model;\n\nparcelable LatLngBounds;"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/model/MapStyleOptions.aidl",
    "content": "package com.google.android.gms.maps.model;\n\nparcelable MapStyleOptions;\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/model/MarkerOptions.aidl",
    "content": "package com.google.android.gms.maps.model;\n\nparcelable MarkerOptions;\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/model/PatternItem.aidl",
    "content": "package com.google.android.gms.maps.model;\n\nparcelable PatternItem;\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/model/PolygonOptions.aidl",
    "content": "package com.google.android.gms.maps.model;\n\nparcelable PolygonOptions;\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/model/PolylineOptions.aidl",
    "content": "package com.google.android.gms.maps.model;\n\nparcelable PolylineOptions;\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/model/StreetViewPanoramaCamera.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.maps.model;\n\nparcelable StreetViewPanoramaCamera;\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/model/StreetViewPanoramaLocation.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.maps.model;\n\nparcelable StreetViewPanoramaLocation;\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/model/StreetViewPanoramaOrientation.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.maps.model;\n\nparcelable StreetViewPanoramaOrientation;\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/model/StreetViewSource.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.maps.model;\n\nparcelable StreetViewSource;\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/model/StyleSpan.aidl",
    "content": "package com.google.android.gms.maps.model;\n\nparcelable StyleSpan;\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/model/Tile.aidl",
    "content": "package com.google.android.gms.maps.model;\n\nparcelable Tile;\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/model/TileOverlayOptions.aidl",
    "content": "package com.google.android.gms.maps.model;\n\nparcelable TileOverlayOptions;\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/model/VisibleRegion.aidl",
    "content": "package com.google.android.gms.maps.model;\n\nparcelable VisibleRegion;\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/model/internal/IBitmapDescriptorFactoryDelegate.aidl",
    "content": "package com.google.android.gms.maps.model.internal;\n\nimport android.graphics.Bitmap;\nimport com.google.android.gms.dynamic.IObjectWrapper;\n\ninterface IBitmapDescriptorFactoryDelegate {\n    IObjectWrapper fromResource(int resourceId);\n    IObjectWrapper fromAsset(String assetName);\n    IObjectWrapper fromFile(String fileName);\n    IObjectWrapper defaultMarker();\n    IObjectWrapper defaultMarkerWithHue(float hue);\n    IObjectWrapper fromBitmap(in Bitmap bitmap);\n    IObjectWrapper fromPath(String absolutePath);\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/model/internal/ICircleDelegate.aidl",
    "content": "package com.google.android.gms.maps.model.internal;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.maps.model.LatLng;\nimport com.google.android.gms.maps.model.PatternItem;\n\ninterface ICircleDelegate {\n    void remove();\n    String getId();\n    void setCenter(in LatLng center);\n    LatLng getCenter();\n    void setRadius(double radius);\n    double getRadius();\n    void setStrokeWidth(float width);\n    float getStrokeWidth();\n    void setStrokeColor(int color);\n    int getStrokeColor();\n    void setFillColor(int color);\n    int getFillColor();\n    void setZIndex(float zIndex);\n    float getZIndex();\n    void setVisible(boolean visible);\n    boolean isVisible();\n    boolean equalsRemote(ICircleDelegate other);\n    int hashCodeRemote();\n    void setClickable(boolean clickable);\n    boolean isClickable();\n    void setStrokePattern(in List<PatternItem> items);\n    List<PatternItem> getStrokePattern();\n    void setTag(IObjectWrapper object);\n    IObjectWrapper getTag();\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/model/internal/IGroundOverlayDelegate.aidl",
    "content": "package com.google.android.gms.maps.model.internal;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.maps.model.LatLng;\nimport com.google.android.gms.maps.model.LatLngBounds;\n\ninterface IGroundOverlayDelegate {\n    void remove() = 0;\n    String getId() = 1;\n    void setPosition(in LatLng pos) = 2;\n    LatLng getPosition() = 3;\n    void setDimension(float dimension) = 4;\n    void setDimensions(float width, float height) = 5;\n    float getWidth() = 6;\n    float getHeight() = 7;\n    void setPositionFromBounds(in LatLngBounds bounds) = 8;\n    LatLngBounds getBounds() = 9;\n    void setBearing(float bearing) = 10;\n    float getBearing() = 11;\n    void setZIndex(float zIndex) = 12;\n    float getZIndex() = 13;\n    void setVisible(boolean visible) = 14;\n    boolean isVisible() = 15;\n    void setTransparency(float transparency) = 16;\n    float getTransparency() = 17;\n    boolean equalsRemote(IGroundOverlayDelegate other) = 18;\n    int hashCodeRemote() = 19;\n    void setImage(IObjectWrapper img) = 20;\n    void setClickable(boolean clickable) = 21;\n    boolean isClickable() = 22;\n    void setTag(IObjectWrapper obj) = 23;\n    IObjectWrapper getTag() = 24;\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/model/internal/IIndoorBuildingDelegate.aidl",
    "content": "package com.google.android.gms.maps.model.internal;\n\ninterface IIndoorBuildingDelegate {\n    int getActiveLevelIndex() = 0;\n    int getDefaultLevelIndex() = 1;\n    List<IBinder> getLevels() = 2; // IIndoorLevelDelegate's\n    boolean isUnderground() = 3;\n    boolean equalsRemote(IIndoorBuildingDelegate other) = 4;\n    int hashCodeRemote() = 5;\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/model/internal/IIndoorLevelDelegate.aidl",
    "content": "package com.google.android.gms.maps.model.internal;\n\ninterface IIndoorLevelDelegate {\n    String getName() = 0;\n    String getShortName() = 1;\n    void activate() = 2;\n    boolean equalsRemote(IIndoorLevelDelegate other) = 3;\n    int hashCodeRemote() = 4;\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/model/internal/IMarkerDelegate.aidl",
    "content": "package com.google.android.gms.maps.model.internal;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.maps.model.LatLng;\n\ninterface IMarkerDelegate {\n    void remove();\n    String getId();\n    void setPosition(in LatLng pos);\n    LatLng getPosition();\n    void setTitle(String title);\n    String getTitle();\n    void setSnippet(String snippet);\n    String getSnippet();\n    void setDraggable(boolean drag);\n    boolean isDraggable();\n    void showInfoWindow();\n    void hideInfoWindow();\n    boolean isInfoWindowShown();\n    void setVisible(boolean visible);\n    boolean isVisible();\n    boolean equalsRemote(IMarkerDelegate other);\n    int hashCodeRemote();\n    void setIcon(IObjectWrapper obj);\n    void setAnchor(float x, float y);\n    void setFlat(boolean flat);\n    boolean isFlat();\n    void setRotation(float rotation);\n    float getRotation();\n    void setInfoWindowAnchor(float x, float y);\n    void setAlpha(float alpha);\n    float getAlpha();\n    void setZIndex(float zIndex);\n    float getZIndex();\n    void setTag(IObjectWrapper obj);\n    IObjectWrapper getTag();\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/model/internal/IPolygonDelegate.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2015 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.maps.model.internal;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.maps.model.LatLng;\nimport com.google.android.gms.maps.model.PatternItem;\n\ninterface IPolygonDelegate {\n    void remove() = 0;\n    String getId() = 1;\n    void setPoints(in List<LatLng> points) = 2;\n    List<LatLng> getPoints() = 3;\n    void setHoles(in List holes) = 4;\n    List getHoles() = 5;\n    void setStrokeWidth(float width) = 6;\n    float getStrokeWidth() = 7;\n    void setStrokeColor(int color) = 8;\n    int getStrokeColor() = 9;\n    void setFillColor(int color) = 10;\n    int getFillColor() = 11;\n    void setZIndex(float zIndex) = 12;\n    float getZIndex() = 13;\n    void setVisible(boolean visible) = 14;\n    boolean isVisible() = 15;\n    void setGeodesic(boolean geod) = 16;\n    boolean isGeodesic() = 17;\n    boolean equalsRemote(IPolygonDelegate other) = 18;\n    int hashCodeRemote() = 19;\n    void setClickable(boolean click) = 20;\n    boolean isClickable() = 21;\n    void setStrokeJointType(int type) = 22;\n    int getStrokeJointType() = 23;\n    void setStrokePattern(in List<PatternItem> items) = 24;\n    List<PatternItem> getStrokePattern() = 25;\n    void setTag(IObjectWrapper obj) = 26;\n    IObjectWrapper getTag() = 27;\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/model/internal/IPolylineDelegate.aidl",
    "content": "package com.google.android.gms.maps.model.internal;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.maps.model.Cap;\nimport com.google.android.gms.maps.model.LatLng;\nimport com.google.android.gms.maps.model.PatternItem;\nimport com.google.android.gms.maps.model.StyleSpan;\n\ninterface IPolylineDelegate {\n    void remove() = 0;\n    String getId() = 1;\n    void setPoints(in List<LatLng> points) = 2;\n    List<LatLng> getPoints() = 3;\n    void setWidth(float width) = 4;\n    float getWidth() = 5;\n    void setColor(int color) = 6;\n    int getColor() = 7;\n    void setZIndex(float zIndex) = 8;\n    float getZIndex() = 9;\n    void setVisible(boolean visible) = 10;\n    boolean isVisible() = 11;\n    void setGeodesic(boolean geod) = 12;\n    boolean isGeodesic() = 13;\n    boolean equalsRemote(IPolylineDelegate other) = 14;\n    int hashCodeRemote() = 15;\n    void setClickable(boolean clickable) = 16;\n    boolean isClickable() = 17;\n    void setStartCap(in Cap startCap) = 18;\n    Cap getStartCap() = 19;\n    void setEndCap(in Cap endCap) = 20;\n    Cap getEndCap() = 21;\n    void setJointType(int jointType) = 22;\n    int getJointType() = 23;\n    void setPattern(in List<PatternItem> pattern) = 24;\n    List<PatternItem> getPattern() = 25;\n    void setTag(IObjectWrapper tag) = 26;\n    IObjectWrapper getTag() = 27;\n    //void setSpans(in List<StyleSpan> spans) = 28;\n    //List<StyleSpan> getSpans() = 29\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/model/internal/ITileOverlayDelegate.aidl",
    "content": "package com.google.android.gms.maps.model.internal;\n\ninterface ITileOverlayDelegate {\n    void remove() = 0;\n    void clearTileCache() = 1;\n    String getId() = 2;\n    void setZIndex(float zIndex) = 3;\n    float getZIndex() = 4;\n    void setVisible(boolean visible) = 5;\n    boolean isVisible() = 6;\n    boolean equalsRemote(ITileOverlayDelegate other) = 7;\n    int hashCodeRemote() = 8;\n    void setFadeIn(boolean fadeIn) = 9;\n    boolean getFadeIn() = 10;\n    void setTransparency(float transparency) = 11;\n    float getTransparency() = 12;\n}\n"
  },
  {
    "path": "play-services-maps/src/main/aidl/com/google/android/gms/maps/model/internal/ITileProviderDelegate.aidl",
    "content": "package com.google.android.gms.maps.model.internal;\n\nimport com.google.android.gms.maps.model.Tile;\n\ninterface ITileProviderDelegate {\n    Tile getTile(int x, int y, int zoom);\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/CameraUpdate.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.maps;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Defines a camera move. An object of this type can be used to modify a map's camera by calling {@link GoogleMap#animateCamera(CameraUpdate)},\n * {@link GoogleMap#animateCamera(CameraUpdate, GoogleMap.CancelableCallback)} or {@link GoogleMap#moveCamera(CameraUpdate)}.\n * <p>\n * To obtain a {@link CameraUpdate} use the factory class {@link CameraUpdateFactory}.\n */\n@PublicApi\npublic class CameraUpdate {\n    IObjectWrapper wrapped;\n\n    CameraUpdate(IObjectWrapper wrapped) {\n        this.wrapped = wrapped;\n    }\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/CameraUpdateFactory.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.maps;\n\nimport android.os.RemoteException;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.maps.internal.ICameraUpdateFactoryDelegate;\nimport com.google.android.gms.maps.model.CameraPosition;\nimport org.microg.gms.common.Hide;\n\n/**\n * A class containing methods for creating {@link CameraUpdate} objects that change a map's camera. To modify the map's camera, call\n * {@link GoogleMap#animateCamera(CameraUpdate)}, {@link GoogleMap#animateCamera(CameraUpdate, GoogleMap.CancelableCallback)} or\n * {@link GoogleMap#moveCamera(CameraUpdate)}, using a {@link CameraUpdate} object created with this class.\n */\npublic class CameraUpdateFactory {\n    private static ICameraUpdateFactoryDelegate delegate;\n    @Hide\n    public static void setDelegate(@NonNull ICameraUpdateFactoryDelegate delegate) {\n        CameraUpdateFactory.delegate = delegate;\n    }\n    private static ICameraUpdateFactoryDelegate getDelegate() {\n        if (delegate == null) throw new IllegalStateException(\"CameraUpdateFactory is not initialized\");\n        return delegate;\n    }\n\n    /**\n     * Returns a {@link CameraUpdate} that moves the camera to a specified {@link CameraPosition}. In effect, this creates a transformation from the\n     * {@link CameraPosition} object's latitude, longitude, zoom level, bearing and tilt.\n     *\n     * @param cameraPosition The requested position. Must not be {@code null}.\n     * @return a {@link CameraUpdate} containing the transformation.\n     */\n    public static CameraUpdate newCameraPosition(@NonNull CameraPosition cameraPosition) {\n        try {\n            return new CameraUpdate(getDelegate().newCameraPosition(cameraPosition));\n        } catch (RemoteException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/GoogleMap.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.maps;\n\nimport android.os.RemoteException;\nimport android.view.View;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.maps.internal.ICancelableCallback;\nimport com.google.android.gms.maps.internal.IGoogleMapDelegate;\nimport com.google.android.gms.maps.model.CameraPosition;\nimport com.google.android.gms.maps.model.Circle;\nimport com.google.android.gms.maps.model.CircleOptions;\nimport com.google.android.gms.maps.model.RuntimeRemoteException;\nimport org.microg.gms.common.Hide;\n\n/**\n * This is the main class of the Google Maps SDK for Android and is the entry point for all methods related to the map. You cannot instantiate a\n * {@link GoogleMap} object directly, rather, you must obtain one from the {@code getMapAsync()} method on a {@link MapFragment} or {@link MapView} that you\n * have added to your application.\n * <p>\n * Note: Similar to a {@link View} object, a {@link GoogleMap} can only be read and modified from the Android UI thread. Calling {@link GoogleMap} methods from\n * another thread will result in an exception.\n * <p>\n * You can adjust the viewpoint of a map by changing the position of the camera (as opposed to moving the map). You can use the map's camera to set parameters\n * such as location, zoom level, tilt angle, and bearing.\n */\npublic class GoogleMap {\n    /**\n     * No base map tiles.\n     */\n    public static final int MAP_TYPE_NONE = 0;\n    /**\n     * Basic maps.\n     */\n    public static final int MAP_TYPE_NORMAL = 1;\n    /**\n     * Satellite maps with no labels.\n     */\n    public static final int MAP_TYPE_SATELLITE = 2;\n    /**\n     * Terrain maps.\n     */\n    public static final int MAP_TYPE_TERRAIN = 3;\n    /**\n     * Satellite maps with a transparent layer of major streets.\n     */\n    public static final int MAP_TYPE_HYBRID = 4;\n\n    private final IGoogleMapDelegate delegate;\n\n    @Hide\n    public GoogleMap(IGoogleMapDelegate delegate) {\n        this.delegate = delegate;\n    }\n\n    private IGoogleMapDelegate getDelegate() {\n        return delegate;\n    }\n\n    public Circle addCircle(CircleOptions options) {\n        try {\n            return new Circle(getDelegate().addCircle(options));\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    /**\n     * Animates the movement of the camera from the current position to the position defined in the update. During the animation, a call to\n     * {@link #getCameraPosition()} returns an intermediate location of the camera.\n     * <p>\n     * See CameraUpdateFactory for a set of updates.\n     *\n     * @param update The change that should be applied to the camera.\n     */\n    public void animateCamera(CameraUpdate update) {\n        try {\n            getDelegate().animateCamera(update.wrapped);\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    /**\n     * Animates the movement of the camera from the current position to the position defined in the update and calls an optional callback on completion. See\n     * {@link CameraUpdateFactory} for a set of updates.\n     * <p>\n     * During the animation, a call to {@link #getCameraPosition()} returns an intermediate location of the camera.\n     *\n     * @param update   The change that should be applied to the camera.\n     * @param callback The callback to invoke from the Android UI thread when the animation stops. If the animation completes normally,\n     *                 {@link GoogleMap.CancelableCallback#onFinish()} is called; otherwise, {@link GoogleMap.CancelableCallback#onCancel()} is called. Do not\n     *                 update or animate the camera from within {@link GoogleMap.CancelableCallback#onCancel()}.\n     */\n    public void animateCamera(CameraUpdate update, @Nullable GoogleMap.CancelableCallback callback) {\n        try {\n            getDelegate().animateCameraWithCallback(update.wrapped, new ICancelableCallback.Stub() {\n                @Override\n                public void onFinish() throws RemoteException {\n                    if (callback != null) {\n                        callback.onFinish();\n                    }\n                }\n\n                @Override\n                public void onCancel() throws RemoteException {\n                    if (callback != null) {\n                        callback.onCancel();\n                    }\n                }\n            });\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    /**\n     * Gets the current position of the camera.\n     * <p>\n     * The {@link CameraPosition} returned is a snapshot of the current position, and will not automatically update when the camera moves.\n     *\n     * @return The current position of the Camera.\n     */\n    public CameraPosition getCameraPosition() {\n        try {\n            return getDelegate().getCameraPosition();\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    /**\n     * Repositions the camera according to the instructions defined in the update. The move is instantaneous, and a subsequent {@link #getCameraPosition()} will\n     * reflect the new position. See {@link CameraUpdateFactory} for a set of updates.\n     *\n     * @param update The change that should be applied to the camera.\n     */\n    public void moveCamera(CameraUpdate update) {\n        try {\n            getDelegate().moveCamera(update.wrapped);\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    /**\n     * A callback interface for reporting when a task is complete or canceled.\n     */\n    public interface CancelableCallback {\n        /**\n         * Invoked when a task is canceled.\n         */\n        void onCancel();\n\n        /**\n         * Invoked when a task is complete.\n         */\n        void onFinish();\n    }\n\n    /**\n     * Callback interface for when the camera motion starts.\n     */\n    public interface OnCameraMoveStartedListener {\n        /**\n         * Camera motion initiated in response to user gestures on the map. For example: pan, tilt, pinch to zoom, or rotate.\n         */\n        int REASON_GESTURE = 1;\n        /**\n         * Non-gesture animation initiated in response to user actions. For example: zoom buttons, my location button, or marker clicks.\n         */\n        int REASON_API_ANIMATION = 2;\n        /**\n         * Developer initiated animation.\n         */\n        int REASON_DEVELOPER_ANIMATION = 3;\n\n        /**\n         * Called when the camera starts moving after it has been idle or when the reason for camera motion has changed.\n         * Do not update or animate the camera from within this method.\n         * <p>\n         * This is called on the Android UI thread.\n         *\n         * @param reason The reason for the camera change. Possible values:\n         *               <ul>\n         *                   <li>{@link #REASON_GESTURE}: User gestures on the map.</li>\n         *                   <li>{@link #REASON_API_ANIMATION}: Default animations resulting from user interaction.</li>\n         *                   <li>{@link #REASON_DEVELOPER_ANIMATION}: Developer animations.</li>\n         *               </ul>\n         */\n        void onCameraMoveStarted(int reason);\n    }\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/GoogleMapOptions.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2015 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.maps;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.util.AttributeSet;\nimport android.view.SurfaceView;\nimport androidx.annotation.ColorInt;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.maps.model.CameraPosition;\nimport com.google.android.gms.maps.model.LatLngBounds;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n/**\n * Defines configuration GoogleMapOptions for a {@link GoogleMap}. These options can be used when adding a map to your application programmatically\n * (as opposed to via XML). If you are using a {@link MapFragment}, you can pass these options in using the static factory method\n * {@link MapFragment#newInstance(GoogleMapOptions)}. If you are using a {@link MapView}, you can pass these options in using the constructor\n * {@link MapView#MapView(Context, GoogleMapOptions)}.\n * <p>\n * If you add a map using XML, then you can apply these options using custom XML tags.\n */\npublic final class GoogleMapOptions extends AutoSafeParcelable {\n    @Field(1)\n    private int versionCode;\n    @Field(2)\n    private int zOrderOnTop;\n    @Field(3)\n    private boolean useViewLifecycleInFragment;\n    @Field(4)\n    private int mapType;\n    @Field(5)\n    @Nullable\n    private CameraPosition camera;\n    @Field(6)\n    private boolean zoomControlsEnabled;\n    @Field(7)\n    private boolean compassEnabled;\n    @Field(8)\n    private boolean scrollGesturesEnabled = true;\n    @Field(9)\n    private boolean zoomGesturesEnabled = true;\n    @Field(10)\n    private boolean tiltGesturesEnabled = true;\n    @Field(11)\n    private boolean rotateGesturesEnabled = true;\n    @Field(12)\n    private int liteMode = 0;\n    @Field(14)\n    private boolean mapToobarEnabled = false;\n    @Field(15)\n    private boolean ambientEnabled = false;\n    @Field(16)\n    private float minZoom;\n    @Field(17)\n    private float maxZoom;\n    @Field(18)\n    @Nullable\n    private LatLngBounds boundsForCamera;\n    @Field(19)\n    private boolean scrollGesturesEnabledDuringRotateOrZoom = true;\n    @Field(20)\n    @ColorInt\n    @Nullable\n    private Integer backgroundColor;\n    @Field(21)\n    @Nullable\n    private String mapId;\n\n    /**\n     * Creates a new GoogleMapOptions object.\n     */\n    public GoogleMapOptions() {\n    }\n\n    /**\n     * Creates a {@code GoogleMapsOptions} from the {@link AttributeSet}.\n     */\n    public static @Nullable GoogleMapOptions createFromAttributes(@Nullable Context context, @Nullable AttributeSet attrs) {\n        if (context == null || attrs == null) return null;\n        GoogleMapOptions options = new GoogleMapOptions();\n        TypedArray obtainAttributes = context.getResources().obtainAttributes(attrs, R.styleable.MapAttrs);\n        // TODO: Handle attributes\n        if (obtainAttributes.hasValue(R.styleable.MapAttrs_mapType)) {\n//            options.mapType(obtainAttributes.getInt(R.styleable.MapAttrs_mapType, -1));\n        }\n        obtainAttributes.recycle();\n        return options;\n    }\n\n    /**\n     * Specifies whether ambient-mode styling should be enabled. The default value is {@code false}.\n     * When enabled, ambient-styled maps can be displayed when an Ambiactive device enters ambient mode.\n     */\n    @NonNull\n    public GoogleMapOptions ambientEnabled(boolean enabled) {\n        this.ambientEnabled = enabled;\n        return this;\n    }\n\n    /**\n     * Sets the map background color. This is the color that shows underneath map tiles and displays whenever the renderer does not have a tile available for\n     * a portion of the viewport.\n     *\n     * @param backgroundColor the color to show in the background of the map. If {@code null} is supplied then the map uses the default renderer background color.\n     */\n    @NonNull\n    public GoogleMapOptions backgroundColor(@Nullable @ColorInt Integer backgroundColor) {\n        this.backgroundColor = backgroundColor;\n        return this;\n    }\n\n    /**\n     * Specifies the initial camera position for the map (specify null to use the default camera position).\n     */\n    @NonNull\n    public GoogleMapOptions camera(@Nullable CameraPosition camera) {\n        this.camera = camera;\n        return this;\n    }\n\n    /**\n     * Specifies whether the compass should be enabled. See {@link UiSettings#setCompassEnabled(boolean)} for more details. The default value is {@code true}.\n     */\n    @NonNull\n    public GoogleMapOptions compassEnabled(boolean enabled) {\n        this.compassEnabled = enabled;\n        return this;\n    }\n\n    /**\n     * Specifies a LatLngBounds to constrain the camera target, so that when users scroll and pan the map, the camera target does not move outside these bounds.\n     * <p>\n     * See {@link GoogleMap#setLatLngBoundsForCameraTarget(LatLngBounds)} for details.\n     */\n    @NonNull\n    public GoogleMapOptions latLngBoundsForCameraTarget(@Nullable LatLngBounds llbounds) {\n        this.boundsForCamera = llbounds;\n        return this;\n    }\n\n    /**\n     * Specifies whether the map should be created in lite mode. The default value is {@code false}. If lite mode is enabled, maps will load as static images.\n     * This improves performance in the case where a lot of maps need to be displayed at the same time, for example in a scrolling list, however lite-mode maps\n     * cannot be panned or zoomed by the user, or tilted or rotated at all.\n     */\n    @NonNull\n    public GoogleMapOptions liteMode(boolean enabled) {\n        this.liteMode = enabled ? 1 : 0;\n        return this;\n    }\n\n    /**\n     * Specifies the map's ID.\n     */\n    @NonNull\n    public GoogleMapOptions mapId(@NonNull String mapId) {\n        this.mapId = mapId;\n        return this;\n    }\n\n    /**\n     * Specifies whether the mapToolbar should be enabled. See {@link UiSettings#setMapToolbarEnabled(boolean)} for more details.\n     * The default value is {@code true}.\n     */\n    @NonNull\n    public GoogleMapOptions mapToolbarEnabled(boolean enabled) {\n        this.mapToobarEnabled = enabled;\n        return this;\n    }\n\n    /**\n     * Specifies a change to the initial map type.\n     */\n    @NonNull\n    public GoogleMapOptions mapType(int mapType) {\n        this.mapType = mapType;\n        return this;\n    }\n\n    /**\n     * Specifies a preferred upper bound for camera zoom.\n     * <p>\n     * See {@link GoogleMap#setMaxZoomPreference(float)} for details.\n     */\n    @NonNull\n    public GoogleMapOptions maxZoomPreference(float maxZoomPreference) {\n        this.maxZoom = maxZoomPreference;\n        return this;\n    }\n\n    /**\n     * Specifies a preferred lower bound for camera zoom.\n     * <p>\n     * See {@link GoogleMap#setMinZoomPreference(float)} for details.\n     */\n    @NonNull\n    public GoogleMapOptions minZoomPreference(float minZoomPreference) {\n        this.minZoom = minZoomPreference;\n        return this;\n    }\n\n    /**\n     * Specifies whether rotate gestures should be enabled. See {@link UiSettings#setRotateGesturesEnabled(boolean)} for more details.\n     * The default value is {@code true}.\n     */\n    @NonNull\n    public GoogleMapOptions rotateGesturesEnabled(boolean enabled) {\n        this.rotateGesturesEnabled = enabled;\n        return this;\n    }\n\n    /**\n     * Specifies whether scroll gestures should be enabled. See {@link UiSettings#setScrollGesturesEnabled(boolean)} for more details.\n     * The default value is {@code true}.\n     */\n    @NonNull\n    public GoogleMapOptions scrollGesturesEnabled(boolean enabled) {\n        this.scrollGesturesEnabled = enabled;\n        return this;\n    }\n\n    /**\n     * Specifies whether scroll gestures should be enabled during rotate and zoom gestures.\n     * See {@link UiSettings#setScrollGesturesEnabledDuringRotateOrZoom(boolean)} for more details. The default value is {@code true}.\n     */\n    @NonNull\n    public GoogleMapOptions scrollGesturesEnabledDuringRotateOrZoom(boolean enabled) {\n        this.scrollGesturesEnabledDuringRotateOrZoom = enabled;\n        return this;\n    }\n\n    /**\n     * Specifies whether tilt gestures should be enabled. See {@link UiSettings#setTiltGesturesEnabled(boolean)} for more details.\n     * The default value is {@code true}.\n     */\n    @NonNull\n    public GoogleMapOptions tiltGesturesEnabled(boolean enabled) {\n        this.tiltGesturesEnabled = enabled;\n        return this;\n    }\n\n    /**\n     * When using a {@link MapFragment}, this flag specifies whether the lifecycle of the map should be tied to the fragment's view or the fragment itself.\n     * The default value is {@code false}, tying the lifecycle of the map to the fragment.\n     * <p>\n     * Using the lifecycle of the fragment allows faster rendering of the map when the fragment is detached and reattached, because the underlying GL context\n     * is preserved. This has the cost that detaching the fragment, but not destroying it, will not release memory used by the map.\n     * <p>\n     * Using the lifecycle of a fragment's view means that a map is not reused when the fragment is detached and reattached. This will cause the map to\n     * re-render from scratch, which can take a few seconds. It also means that while a fragment is detached, and therefore has no view, all {@link GoogleMap}\n     * methods will throw {@link NullPointerException}.\n     */\n    @NonNull\n    public GoogleMapOptions useViewLifecycleInFragment(boolean useViewLifecycleInFragment) {\n        this.useViewLifecycleInFragment = useViewLifecycleInFragment;\n        return this;\n    }\n\n    /**\n     * Control whether the map view's surface is placed on top of its window. See {@link SurfaceView#setZOrderOnTop(boolean)} for more details.\n     * Note that this will cover all other views that could appear on the map (e.g., the zoom controls, the my location button).\n     */\n    @NonNull\n    public GoogleMapOptions zOrderOnTop(boolean zOrderOnTop) {\n        this.zOrderOnTop = zOrderOnTop ? 1 : 0;\n        return this;\n    }\n\n    /**\n     * Specifies whether the zoom controls should be enabled. See {@link UiSettings#setZoomControlsEnabled(boolean)} for more details.\n     * The default value is {@code true}.\n     */\n    @NonNull\n    public GoogleMapOptions zoomControlsEnabled(boolean enabled) {\n        this.zoomControlsEnabled = enabled;\n        return this;\n    }\n\n    /**\n     * Specifies whether zoom gestures should be enabled. See {@link UiSettings#setZoomGesturesEnabled(boolean)} for more details.\n     * The default value is {@code true}.\n     */\n    @NonNull\n    public GoogleMapOptions zoomGesturesEnabled(boolean enabled) {\n        this.zoomGesturesEnabled = enabled;\n        return this;\n    }\n\n    /**\n     * @return the {@code ambientEnabled} option, or {@code null} if unspecified.\n     */\n    public Boolean getAmbientEnabled() {\n        return ambientEnabled;\n    }\n\n    /**\n     * @return the current backgroundColor for the map, or null if unspecified.\n     */\n    public Integer getBackgroundColor() {\n        return backgroundColor;\n    }\n\n    /**\n     * @return the camera option, or {@code null} if unspecified.\n     */\n    @Nullable\n    public CameraPosition getCamera() {\n        return camera;\n    }\n\n    /**\n     * @return the {@code compassEnabled} option, or {@code null} if unspecified.\n     */\n    @Nullable\n    public Boolean getCompassEnabled() {\n        return compassEnabled;\n    }\n\n    /**\n     * @return the {@code LatLngBounds} used to constrain the camera target, or {@code null} if unspecified.\n     */\n    @Nullable\n    public LatLngBounds getLatLngBoundsForCameraTarget() {\n        return boundsForCamera;\n    }\n\n    /**\n     * @return the {@code liteMode} option, or {@code null} if unspecified.\n     */\n    @Nullable\n    public boolean getLiteMode() {\n        // Is encoded as `-1` if null, `0` if false, `1` if true. The default is false.\n        return liteMode == 1;\n    }\n\n    /**\n     * @return the {@code mapId}, or {@code null} if unspecified.\n     */\n    @Nullable\n    public String getMapId() {\n        return mapId;\n    }\n\n    /**\n     * @return the {@code mapToolbarEnabled} option, or {@code null} if unspecified.\n     */\n    @Nullable\n    public Boolean getMapToolbarEnabled() {\n        return mapToobarEnabled;\n    }\n\n    /**\n     * @return the {@code mapType} option, or -1 if unspecified.\n     */\n    public int getMapType() {\n        return mapType;\n    }\n\n    /**\n     * @return the maximum zoom level preference, or {@code null} if unspecified.\n     */\n    @Nullable\n    public Float getMaxZoomPreference() {\n        return maxZoom;\n    }\n\n    /**\n     * @return the minimum zoom level preference, or {@code null} if unspecified.\n     */\n    @Nullable\n    public Float getMinZoomPreference() {\n        return minZoom;\n    }\n\n    /**\n     * @return the {@code rotateGesturesEnabled} option, or {@code null} if unspecified.\n     */\n    @Nullable\n    public Boolean getRotateGesturesEnabled() {\n        return rotateGesturesEnabled;\n    }\n\n    /**\n     * @return the {@code scrollGesturesEnabled} option, or {@code null} if unspecified.\n     */\n    @Nullable\n    public Boolean getScrollGesturesEnabled() {\n        return scrollGesturesEnabled;\n    }\n\n    /**\n     * @return the {@code scrollGesturesEnabledDuringRotateOrZoom} option, or {@code null} if unspecified.\n     */\n    @Nullable\n    public Boolean getScrollGesturesEnabledDuringRotateOrZoom() {\n        return scrollGesturesEnabledDuringRotateOrZoom;\n    }\n\n    /**\n     * @return the {@code tiltGesturesEnabled} option, or {@code null} if unspecified.\n     */\n    @Nullable\n    public Boolean getTiltGesturesEnabled() {\n        return tiltGesturesEnabled;\n    }\n\n    /**\n     * @return the {@code useViewLifecycleInFragment} option, or {@code null} if unspecified.\n     */\n    @Nullable\n    public Boolean getUseViewLifecycleInFragment() {\n        return useViewLifecycleInFragment;\n    }\n\n    /**\n     * @return the {@code zOrderOnTop} option, or {@code null} if unspecified.\n     */\n    @Nullable\n    public Boolean getZOrderOnTop() {\n        return zOrderOnTop == 1; // TODO\n    }\n\n    /**\n     * @return the {@code zoomControlsEnabled} option, or {@code null} if unspecified.\n     */\n    @Nullable\n    public Boolean getZoomControlsEnabled() {\n        return zoomControlsEnabled;\n    }\n\n    /**\n     * @return the {@code zoomGesturesEnabled} option, or {@code null} if unspecified.\n     */\n    @Nullable\n    public Boolean getZoomGesturesEnabled() {\n        return zoomGesturesEnabled;\n    }\n\n    @Deprecated\n    public boolean isCompassEnabled() {\n        return compassEnabled;\n    }\n\n    @Deprecated\n    public boolean isZoomControlsEnabled() {\n        return zoomControlsEnabled;\n    }\n\n    @Deprecated\n    public boolean isScrollGesturesEnabled() {\n        return scrollGesturesEnabled;\n    }\n\n    @Deprecated\n    public boolean isZoomGesturesEnabled() {\n        return zoomGesturesEnabled;\n    }\n\n    @Deprecated\n    public boolean isTiltGesturesEnabled() {\n        return tiltGesturesEnabled;\n    }\n\n    @Deprecated\n    public boolean isRotateGesturesEnabled() {\n        return rotateGesturesEnabled;\n    }\n\n\n    public static Creator<GoogleMapOptions> CREATOR = new AutoCreator<GoogleMapOptions>(GoogleMapOptions.class);\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/MapFragment.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.maps;\n\nimport android.app.Fragment;\n\npublic class MapFragment extends Fragment {\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/MapView.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.maps;\n\nimport android.app.Activity;\nimport android.app.Fragment;\nimport android.content.Context;\nimport android.os.Bundle;\nimport android.util.AttributeSet;\nimport android.widget.FrameLayout;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport org.microg.gms.maps.MapViewLifecycleHelper;\n\n/**\n * A View which displays a map. When focused, it will capture keypresses and touch gestures to move the map.\n * <p>\n * Users of this class must forward all the life cycle methods from the {@link Activity} or {@link Fragment} containing this view to the corresponding ones in\n * this class.\n * <p>\n * A {@link GoogleMap} must be acquired using {@link #getMapAsync(OnMapReadyCallback)}.\n * The {@link MapView} automatically initializes the maps system and the view.\n */\npublic class MapView extends FrameLayout {\n    private final MapViewLifecycleHelper helper;\n\n    public MapView(@NonNull Context context) {\n        super(context);\n        helper = new MapViewLifecycleHelper(this, context, null);\n        setClickable(true);\n    }\n\n    public MapView(@NonNull Context context, @Nullable AttributeSet attrs) {\n        super(context, attrs);\n        helper = new MapViewLifecycleHelper(this, context, GoogleMapOptions.createFromAttributes(context, attrs));\n        setClickable(true);\n    }\n\n    public MapView(@NonNull Context context, @NonNull AttributeSet attrs, int defStyle) {\n        super(context, attrs, defStyle);\n        helper = new MapViewLifecycleHelper(this, context, GoogleMapOptions.createFromAttributes(context, attrs));\n        setClickable(true);\n    }\n\n    /**\n     * Constructs MapView with {@link GoogleMapOptions}.\n     *\n     * @param options configuration GoogleMapOptions for a {@link GoogleMap}, or {@code null} to use the default options.\n     */\n    public MapView(@NonNull Context context, @Nullable GoogleMapOptions options) {\n        super(context);\n        helper = new MapViewLifecycleHelper(this, context, options);\n        setClickable(true);\n    }\n\n    /**\n     * Returns a instance of the {@link GoogleMap} through the callback, ready to be used.\n     * <p>\n     * Note that:\n     * <ul>\n     * <li>This method must be called from the main thread.</li>\n     * <li>The callback will be executed in the main thread.</li>\n     * <li>In the case where Google Play services is not installed on the user's device, the callback will not be triggered until the user installs it.</li>\n     * <li>The GoogleMap object provided by the callback is never null.</li>\n     * </ul>\n     *\n     * @param callback The callback object that will be triggered when the map is ready to be used.\n     */\n    public void getMapAsync(OnMapReadyCallback callback) {\n        helper.getMapAsync(callback);\n    }\n\n    /**\n     * You must call this method from the parent Activity/Fragment's corresponding method.\n     */\n    public void onCreate(Bundle savedInstanceState) {\n        helper.onCreate(savedInstanceState);\n    }\n\n    /**\n     * You must call this method from the parent Activity/Fragment's corresponding method.\n     */\n    public void onDestroy() {\n        helper.onDestroy();\n    }\n\n    /**\n     * You must call this method from the parent WearableActivity's corresponding method.\n     */\n    public void onEnterAmbient(Bundle ambientDetails) {\n        if (helper.getDelegate() != null) {\n            helper.getDelegate().onEnterAmbient(ambientDetails);\n        }\n    }\n\n    /**\n     * You must call this method from the parent WearableActivity's corresponding method.\n     */\n    public void onExitAmbient() {\n        if (helper.getDelegate() != null) {\n            helper.getDelegate().onExitAmbient();\n        }\n    }\n\n    /**\n     * You must call this method from the parent Activity/Fragment's corresponding method.\n     */\n    public void onLowMemory() {\n        helper.onLowMemory();\n    }\n\n    /**\n     * You must call this method from the parent Activity/Fragment's corresponding method.\n     */\n    public void onPause() {\n        helper.onPause();\n    }\n\n    /**\n     * You must call this method from the parent Activity/Fragment's corresponding method.\n     */\n    public void onResume() {\n        helper.onResume();\n    }\n\n    /**\n     * You must call this method from the parent Activity/Fragment's corresponding method.\n     * <p>\n     * Provides a {@link Bundle} to store the state of the View before it gets destroyed.\n     * It can later be retrieved when {@link #onCreate(Bundle)} is called again.\n     */\n    public void onSaveInstanceState(Bundle outState) {\n        helper.onSaveInstanceState(outState);\n    }\n\n    /**\n     * You must call this method from the parent Activity/Fragment's corresponding method.\n     */\n    public void onStart() {\n        helper.onStart();\n    }\n\n    /**\n     * You must call this method from the parent Activity/Fragment's corresponding method.\n     */\n    public void onStop() {\n        helper.onStop();\n    }\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/MapsInitializer.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.maps;\n\nimport android.app.Application;\nimport android.content.Context;\nimport android.os.Bundle;\nimport android.os.RemoteException;\nimport android.util.Log;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.api.CommonStatusCodes;\nimport com.google.android.gms.dynamic.ObjectWrapper;\nimport com.google.android.gms.maps.internal.ICreator;\nimport com.google.android.gms.maps.model.BitmapDescriptorFactory;\nimport com.google.android.gms.maps.model.RuntimeRemoteException;\nimport org.microg.gms.maps.MapsContextLoader;\n\n/**\n * Use this class to initialize the Maps SDK for Android if features need to be used before obtaining a map.\n * It must be called because some classes such as BitmapDescriptorFactory and CameraUpdateFactory need to be initialized.\n * <p>\n * If you are using {@link MapFragment} or {@link MapView} and have already obtained a (non-null) {@link GoogleMap} by calling {@code getMapAsync()} on either\n * of these classes and waiting for the {@code onMapReady(GoogleMap map)} callback, then you do not need to worry about this class.\n */\npublic class MapsInitializer {\n    private static final String TAG = \"MapsInitializer\";\n    private static boolean initialized = false;\n    private static Renderer renderer = Renderer.LEGACY;\n\n    /**\n     * Initializes the Maps SDK for Android so that its classes are ready for use. If you are using {@link MapFragment} or {@link MapView} and have\n     * already obtained a (non-null) {@link GoogleMap} by calling {@code getMapAsync()} on either of these classes, then it is not necessary to call this.\n     *\n     * @param context Required to fetch the necessary SDK resources and code. Must not be {@code null}.\n     * @return A ConnectionResult error code.\n     */\n    public static synchronized int initialize(@NonNull Context context) {\n        return initialize(context, null, null);\n    }\n\n    /**\n     * Specifies which {@link MapsInitializer.Renderer} type you prefer to use to initialize the Maps SDK for Android, and provides a callback to receive the\n     * actual {@link MapsInitializer.Renderer} type. This call will initialize the Maps SDK for Android, so that its classes are ready for use. The callback\n     * will be triggered when the Maps SDK is initialized.\n     * <p>\n     * The Maps SDK only initializes once per Application lifecycle. Only the first call of this method or {@link #initialize(Context)} takes effect.\n     * If you are using {@link MapFragment} or {@link MapView} and have already obtained a (non-null) {@link GoogleMap} by calling {@code getMapAsync()} on\n     * either of these classes, then this call will have no effect other than triggering the callback for the initialized {@link MapsInitializer.Renderer}.\n     * To make renderer preference meaningful, you must call this method before {@link #initialize(Context)}, and before {@link MapFragment#onCreate(Bundle)}\n     * and {@link MapView#onCreate(Bundle)}. It's recommended to do this in {@link Application#onCreate()}.\n     * <p>\n     * Note the following:\n     * <ul>\n     * <li>Use {@code LATEST} to request the new renderer. No action is necessary if you prefer to use the legacy renderer.</li>\n     * <li>The latest renderer may not always be returned due to various reasons, including not enough memory, unsupported Android version, or routine downtime.</li>\n     * <li>The new renderer will eventually become the default renderer through a progressive rollout. At that time, you will need to request {@code LEGACY} in\n     * order to continue using the legacy renderer.</li>\n     * </ul>\n     *\n     * @param context           Required to fetch the necessary SDK resources and code. Must not be {@code null}.\n     * @param preferredRenderer Which {@link MapsInitializer.Renderer} type you prefer to use for your application.\n     *                          If {@code null} is provided, the default preference is taken.\n     * @param callback          The callback that the Maps SDK triggers when it informs you about which renderer type was actually loaded.\n     *                          You can define what you want to do differently according to the maps renderer that is loaded.\n     * @return A ConnectionResult error code.\n     */\n    public static synchronized int initialize(@NonNull Context context, @Nullable MapsInitializer.Renderer preferredRenderer, @Nullable OnMapsSdkInitializedCallback callback) {\n        Log.d(TAG, \"preferredRenderer: \" + preferredRenderer);\n        if (initialized) {\n            if (callback != null) {\n                callback.onMapsSdkInitialized(renderer);\n            }\n            return CommonStatusCodes.SUCCESS;\n        }\n        try {\n            ICreator creator = MapsContextLoader.getCreator(context, preferredRenderer);\n            try {\n                CameraUpdateFactory.setDelegate(creator.newCameraUpdateFactoryDelegate());\n                BitmapDescriptorFactory.setDelegate(creator.newBitmapDescriptorFactoryDelegate());\n                int preferredRendererInt = 0;\n                if (preferredRenderer != null) {\n                    if (preferredRenderer == Renderer.LEGACY) preferredRendererInt = 1;\n                    else if (preferredRenderer == Renderer.LATEST) preferredRendererInt = 2;\n                }\n                try {\n                    if (creator.getRendererType() == 2) {\n                        renderer = Renderer.LATEST;\n                    }\n                    creator.logInitialization(ObjectWrapper.wrap(context), preferredRendererInt);\n                } catch (RemoteException e) {\n                    Log.e(TAG, \"Failed to retrieve renderer type or log initialization.\", e);\n                }\n                Log.d(TAG, \"loadedRenderer: \" + renderer);\n                if (callback != null) {\n                    callback.onMapsSdkInitialized(renderer);\n                }\n                return CommonStatusCodes.SUCCESS;\n            } catch (RemoteException e) {\n                throw new RuntimeRemoteException(e);\n            }\n        } catch (Exception e) {\n            return CommonStatusCodes.INTERNAL_ERROR;\n        }\n    }\n\n    /**\n     * Enables you to specify which {@link MapsInitializer.Renderer} you prefer to use for your application {@code LATEST} or {@code LEGACY}.\n     * It also informs you which maps {@link MapsInitializer.Renderer} is actually used for your application.\n     */\n    public enum Renderer {\n        LEGACY, LATEST\n    }\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/OnMapReadyCallback.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.maps;\n\nimport android.view.View;\nimport android.view.ViewTreeObserver;\nimport com.google.android.gms.maps.model.LatLngBounds;\n\n/**\n * Callback interface for when the map is ready to be used.\n * <p>\n * Once an instance of this interface is set on a {@link MapFragment} or {@link MapView} object, the {@link #onMapReady(GoogleMap)} method is triggered when\n * the map is ready to be used and provides a non-null instance of {@link GoogleMap}.\n * <p>\n * If required services are not installed on the device, the user will be prompted to install it, and the {@link #onMapReady(GoogleMap)} method will only be\n * triggered when the user has installed it and returned to the app.\n */\npublic interface OnMapReadyCallback {\n    /**\n     * Called when the map is ready to be used.\n     * <p>\n     * Note that this does not guarantee that the map has undergone layout. Therefore, the map's size may not have been determined by the time the callback\n     * method is called. If you need to know the dimensions or call a method in the API that needs to know the dimensions, get the map's {@link View} and\n     * register an {@link ViewTreeObserver.OnGlobalLayoutListener} as well.\n     * <p>\n     * Do not chain the {@code OnMapReadyCallback} and {@code OnGlobalLayoutListener} listeners, but instead register and wait for both callbacks independently,\n     * since the callbacks can be fired in any order.\n     * <p>\n     * As an example, if you want to update the map's camera using a {@link LatLngBounds} without dimensions, you should wait until both\n     * {@code OnMapReadyCallback} and {@code OnGlobalLayoutListener} have completed. Otherwise there is a race condition that could trigger an\n     * {@link IllegalStateException}.\n     *\n     * @param googleMap A non-null instance of a GoogleMap associated with the {@link MapFragment} or {@link MapView} that defines the callback.\n     */\n    void onMapReady(GoogleMap googleMap);\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/OnMapsSdkInitializedCallback.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.maps;\n\n/**\n * Callback interface used by the Maps SDK to inform you which maps {@link MapsInitializer.Renderer} type has been loaded for your application.\n */\npublic interface OnMapsSdkInitializedCallback {\n    /**\n     * The Maps SDK calls this method to inform you which maps {@link MapsInitializer.Renderer} has been loaded for your application.\n     * <p>\n     * You can implement this method to define configurations or operations that are specific to each {@link MapsInitializer.Renderer} type.\n     *\n     * @param renderer The actual maps {@link MapsInitializer.Renderer} the maps SDK has loaded for your application.\n     */\n    void onMapsSdkInitialized(MapsInitializer.Renderer renderer);\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/OnStreetViewPanoramaReadyCallback.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.maps;\n\n/**\n * Callback interface for when the Street View panorama is ready to be used.\n * <p>\n * Once an instance of this interface is set on a {@link StreetViewPanoramaFragment} or {@link StreetViewPanoramaView} object, the\n * {@link #onStreetViewPanoramaReady(StreetViewPanorama)} method is triggered when the panorama is ready to be used and provides a non-null\n * instance of {@link StreetViewPanorama}.\n * <p>\n * If Google Play services is not installed on the device, the user is prompted to install it, and the\n * {@link #onStreetViewPanoramaReady(StreetViewPanorama)} method will only be triggered when the user has installed it and returned to the app.\n */\npublic interface OnStreetViewPanoramaReadyCallback {\n    /**\n     * Called when the Street View panorama is ready to be used.\n     *\n     * @param panorama A non-null instance of a StreetViewPanorama associated with the {@link StreetViewPanoramaFragment} or {@link StreetViewPanoramaView} that\n     *                 defines the callback.\n     */\n    void onStreetViewPanoramaReady(StreetViewPanorama panorama);\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/StreetViewPanorama.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.maps;\n\nimport android.graphics.Point;\nimport android.os.RemoteException;\nimport android.view.View;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.dynamic.ObjectWrapper;\nimport com.google.android.gms.maps.internal.*;\nimport com.google.android.gms.maps.model.*;\nimport org.microg.gms.common.Hide;\n\n/**\n * This is the main class of the Street View feature in the Google Maps SDK for Android and is the entry point for all methods related to Street\n * View panoramas. You cannot instantiate a {@link StreetViewPanorama} object directly, rather, you must obtain one from the\n * {@code #getStreetViewPanoramaAsync()} method on a {@link StreetViewPanoramaFragment} or {@link StreetViewPanoramaView} that you have added to\n * your application.\n * <p>\n * Note: Similar to a {@link View} object, a {@link StreetViewPanorama} can only be read and modified from the main thread. Calling\n * {@link StreetViewPanorama} methods from another thread will result in an exception.\n */\npublic class StreetViewPanorama {\n    private final IStreetViewPanoramaDelegate delegate;\n\n    @Hide\n    public StreetViewPanorama(@NonNull IStreetViewPanoramaDelegate delegate) {\n        this.delegate = delegate;\n    }\n\n    private IStreetViewPanoramaDelegate getDelegate() {\n        return delegate;\n    }\n\n    /**\n     * Changes the current camera position, orientation and zoom, to a given position over a specified duration\n     *\n     * @param camera   The camera position to animate to. Must not be {@code null}.\n     * @param duration The length of time, in milliseconds, it takes to transition from the current camera position to the given one\n     */\n    public void animateTo(@NonNull StreetViewPanoramaCamera camera, long duration) {\n        try {\n            getDelegate().animateTo(camera, duration);\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    /**\n     * Returns the current location of the user and information regarding the current panorama's adjacent panoramas\n     *\n     * @return The current location of the user\n     */\n    @NonNull\n    public StreetViewPanoramaLocation getLocation() {\n        try {\n            return getDelegate().getStreetViewPanoramaLocation();\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    /**\n     * Returns the current orientation and zoom\n     *\n     * @return The current camera\n     */\n    @NonNull\n    public StreetViewPanoramaCamera getPanoramaCamera() {\n        try {\n            return getDelegate().getPanoramaCamera();\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    /**\n     * Returns whether or not the panning gestures are enabled for the user\n     *\n     * @return {@code true} if panning gestures are enabled\n     */\n    public boolean isPanningGesturesEnabled() {\n        try {\n            return getDelegate().isPanningGesturesEnabled();\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    /**\n     * Returns whether or not the street names appear on the panorama\n     *\n     * @return {@code true} if street names are shown\n     */\n    public boolean isStreetNamesEnabled() {\n        try {\n            return getDelegate().isStreetNamesEnabled();\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    /**\n     * Returns whether or not the zoom gestures are enabled for the user\n     *\n     * @return {@code true} if zoom gestures are enabled\n     */\n    public boolean isUserNavigationEnabled() {\n        try {\n            return getDelegate().isUserNavigationEnabled();\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    /**\n     * Returns whether or not the zoom gestures are enabled for the user\n     *\n     * @return {@code true} if zoom gestures are enabled\n     */\n    public boolean isZoomGesturesEnabled() {\n        try {\n            return getDelegate().isZoomGesturesEnabled();\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    /**\n     * Returns a screen location that corresponds to an orientation ({@link StreetViewPanoramaOrientation}). The screen location is in screen pixels\n     * (not display pixels) relative to the top left of the Street View panorama (not of the whole screen).\n     *\n     * @param orientation A {@link StreetViewPanoramaOrientation} on the Street View panorama to convert to a screen location.\n     * @return A {@link Point} representing the screen location in screen pixels. Returns {@code null} if the orientation is unable to be projected on the screen\n     * (e.g. behind the user's field of view)\n     */\n    public Point orientationToPoint(StreetViewPanoramaOrientation orientation) {\n        try {\n            IObjectWrapper orientationToPoint = getDelegate().orientationToPoint(orientation);\n            if (orientationToPoint == null) {\n                return null;\n            }\n            return (Point) ObjectWrapper.unwrap(orientationToPoint);\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    /**\n     * Returns the orientation that corresponds to a screen location. The screen location is specified in screen pixels (not display pixels) relative to\n     * the top left of the Street View panorama (not the top left of the whole screen).\n     *\n     * @param point A {@link Point} on the screen in screen pixels.\n     * @return The {@link StreetViewPanoramaOrientation} corresponding to the point on the screen, or {@code null} if the Street View panorama has not\n     * been initialized or if the given point is not a valid point on the screen\n     */\n    public StreetViewPanoramaOrientation pointToOrientation(Point point) {\n        try {\n            return getDelegate().pointToOrientation(ObjectWrapper.wrap(point));\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    /**\n     * Sets a callback that's invoked when the camera changes\n     *\n     * @param listener The callback that's invoked when the camera changes. To unset the callback, use {@code null}.\n     */\n    public final void setOnStreetViewPanoramaCameraChangeListener(OnStreetViewPanoramaCameraChangeListener listener) {\n        try {\n            getDelegate().setOnStreetViewPanoramaCameraChangeListener(new IOnStreetViewPanoramaCameraChangeListener.Stub() {\n                @Override\n                public void onStreetViewPanoramaCameraChange(StreetViewPanoramaCamera camera) throws RemoteException {\n                    listener.onStreetViewPanoramaCameraChange(camera);\n                }\n            });\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    /**\n     * Sets a callback that's invoked when the panorama changes\n     *\n     * @param listener The callback that's invoked when the panorama changes. To unset the callback, use {@code null}.\n     */\n    public final void setOnStreetViewPanoramaChangeListener(OnStreetViewPanoramaChangeListener listener) {\n        try {\n            getDelegate().setOnStreetViewPanoramaChangeListener(new IOnStreetViewPanoramaChangeListener.Stub() {\n                @Override\n                public void onStreetViewPanoramaChange(StreetViewPanoramaLocation location) throws RemoteException {\n                    listener.onStreetViewPanoramaChange(location);\n                }\n            });\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    /**\n     * Sets a callback that's invoked when the panorama is tapped.\n     *\n     * @param listener The callback that's invoked when the panorama is tapped. To unset the callback, use {@code null}.\n     */\n    public final void setOnStreetViewPanoramaClickListener(OnStreetViewPanoramaClickListener listener) {\n        try {\n            getDelegate().setOnStreetViewPanoramaClickListener(new IOnStreetViewPanoramaClickListener.Stub() {\n                @Override\n                public void onStreetViewPanoramaClick(StreetViewPanoramaOrientation orientation) throws RemoteException {\n                    listener.onStreetViewPanoramaClick(orientation);\n                }\n            });\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    /**\n     * Sets a callback that's invoked when the panorama is long-pressed.\n     *\n     * @param listener The callback that's invoked when the panorama is long-pressed. To unset the callback, use {@code null}.\n     */\n    public final void setOnStreetViewPanoramaLongClickListener(OnStreetViewPanoramaLongClickListener listener) {\n        try {\n            getDelegate().setOnStreetViewPanoramaLongClickListener(new IOnStreetViewPanoramaLongClickListener.Stub() {\n                @Override\n                public void onStreetViewPanoramaLongClick(StreetViewPanoramaOrientation orientation) throws RemoteException {\n                    listener.onStreetViewPanoramaLongClick(orientation);\n                }\n            });\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    /**\n     * Sets whether the user is able to use panning gestures\n     *\n     * @param enablePanning {@code true} if users are allowed to use panning gestures\n     */\n    public void setPanningGesturesEnabled(boolean enablePanning) {\n        try {\n            getDelegate().enablePanning(enablePanning);\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    /**\n     * Sets the StreetViewPanorama to a given location\n     *\n     * @param position Latitude and longitude of the desired location. Must not be {@code null}.\n     * @param source   StreetViewSource specifies the source of panoramas to search. If source is {@code null}, use the default.\n     */\n    public void setPosition(LatLng position, StreetViewSource source) {\n        try {\n            getDelegate().setPositionWithSource(position, source);\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    /**\n     * Sets the StreetViewPanorama to a given location\n     *\n     * @param position Latitude and longitude of the desired location. Should not be {@code null}.\n     */\n    public void setPosition(LatLng position) {\n        try {\n            getDelegate().setPosition(position);\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    /**\n     * Sets the StreetViewPanorama to a given location\n     *\n     * @param position Latitude and longitude of the desired location. Must not be {@code null}.\n     * @param radius   Radius, specified in meters, that defines the area in which to search for a panorama, centered on the given latitude and longitude\n     */\n    public void setPosition(LatLng position, int radius) {\n        try {\n            getDelegate().setPositionWithRadius(position, radius);\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    /**\n     * Sets the StreetViewPanorama to a given location\n     *\n     * @param position Latitude and longitude of the desired location. Must not be {@code null}.\n     * @param radius   Radius, specified in meters, that defines the area in which to search for a panorama, centered on the given latitude and longitude\n     * @param source   StreetViewSource specifies the source of panoramas to search. If source is {@code null}, use the default.\n     */\n    public void setPosition(LatLng position, int radius, StreetViewSource source) {\n        try {\n            getDelegate().setPositionWithRadiusAndSource(position, radius, source);\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    /**\n     * Sets the StreetViewPanorama to a given location\n     *\n     * @param panoId Panorama ID of the desired location. Must not be {@code null}.\n     */\n    public void setPosition(String panoId) {\n        try {\n            getDelegate().setPositionWithID(panoId);\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    /**\n     * Sets whether the user is able to see street names on panoramas\n     *\n     * @param enableStreetNames {@code true} if users are able to see street names on panoramas\n     */\n    public void setStreetNamesEnabled(boolean enableStreetNames) {\n        try {\n            getDelegate().enableStreetNames(enableStreetNames);\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    /**\n     * Sets whether the user is able to move to another panorama\n     *\n     * @param enableUserNavigation {@code true} if users are allowed to move to another panorama\n     */\n    public void setUserNavigationEnabled(boolean enableUserNavigation) {\n        try {\n            getDelegate().enableUserNavigation(enableUserNavigation);\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    /**\n     * Sets whether the user is able to use zoom gestures\n     *\n     * @param enableZoom {@code true} if users are allowed to use zoom gestures\n     */\n    public void setZoomGesturesEnabled(boolean enableZoom) {\n        try {\n            getDelegate().enableZoom(enableZoom);\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    /**\n     * A listener for when the StreetViewPanoramaCamera changes\n     */\n    public interface OnStreetViewPanoramaCameraChangeListener {\n        /**\n         * Called when the user makes changes to the camera on the panorama or if the camera is changed programmatically. Implementations of this\n         * method are always invoked on the main thread.\n         *\n         * @param camera The position the camera has changed to\n         */\n        void onStreetViewPanoramaCameraChange(StreetViewPanoramaCamera camera);\n    }\n\n    /**\n     * A listener for when the Street View panorama loads a new panorama\n     */\n    public interface OnStreetViewPanoramaChangeListener {\n        /**\n         * The StreetViewPanorama performs an animated transition from one location to another when the user performs a manual navigation action. This callback is called when the transition animation has occurred and the rendering of the first panorama has occurred. This callback also occurs when the developer sets a position and the rendering of the first panorama has occurred. It is possible that not all the panoramas have loaded when this callback is activated. Implementations of this method are always invoked on the main thread.\n         *\n         * @param location Location the StreetViewPanorama is changed to. null if it is an invalid panorama\n         */\n        void onStreetViewPanoramaChange(StreetViewPanoramaLocation location);\n    }\n\n    /**\n     * Callback interface for when the user taps on the panorama.\n     * <p>\n     * Listeners will be invoked on the main thread\n     */\n    public interface OnStreetViewPanoramaClickListener {\n        /**\n         * Called when the user makes a tap gesture on the panorama, but only if none of the overlays of the panorama handled the gesture.\n         * Implementations of this method are always invoked on the main thread.\n         *\n         * @param orientation The tilt and bearing values corresponding to the point on the screen where the user tapped. These values have an absolute value within a\n         *                    specific panorama, and are independent of the current orientation of the camera.\n         */\n        void onStreetViewPanoramaClick(StreetViewPanoramaOrientation orientation);\n    }\n\n    /**\n     * Callback interface for when the user long presses on the panorama.\n     * <p>\n     * Listeners will be invoked on the main thread\n     */\n    public interface OnStreetViewPanoramaLongClickListener {\n        /**\n         * Called when the user makes a long-press gesture on the panorama, but only if none of the overlays of the panorama handled the gesture.\n         * Implementations of this method are always invoked on the main thread.\n         *\n         * @param orientation The tilt and bearing values corresponding to the point on the screen where the user long-pressed. These values have an absolute value within a\n         *                    specific panorama, and are independent of the current orientation of the camera.\n         */\n        void onStreetViewPanoramaLongClick(StreetViewPanoramaOrientation orientation);\n    }\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/StreetViewPanoramaFragment.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.maps;\n\nimport android.app.Fragment;\n\npublic class StreetViewPanoramaFragment extends Fragment {\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/StreetViewPanoramaOptions.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.maps;\n\nimport android.content.Context;\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.maps.model.LatLng;\nimport com.google.android.gms.maps.model.StreetViewPanoramaCamera;\nimport com.google.android.gms.maps.model.StreetViewSource;\nimport org.microg.gms.utils.ToStringHelper;\n\n/**\n * Defines configuration PanoramaOptions for a {@link StreetViewPanorama}. These options can be used when adding a panorama to your\n * application programmatically. If you are using a {@link StreetViewPanoramaFragment}, you can pass these options in using the static factory\n * method {@link StreetViewPanoramaFragment#newInstance(StreetViewPanoramaOptions)}. If you are using a {@link StreetViewPanoramaView},\n * you can pass these options in using the constructor {@link StreetViewPanoramaView#StreetViewPanoramaView(Context, StreetViewPanoramaOptions)}.\n */\n@SafeParcelable.Class\npublic class StreetViewPanoramaOptions extends AbstractSafeParcelable {\n    @Nullable\n    @Field(value = 2, getterName = \"getStreetViewPanoramaCamera\")\n    private StreetViewPanoramaCamera panoramaCamera;\n    @Nullable\n    @Field(value = 3, getterName = \"getPanoramaId\")\n    private String panoramaId;\n    @Nullable\n    @Field(value = 4, getterName = \"getPosition\")\n    private LatLng position;\n    @Nullable\n    @Field(value = 5, getterName = \"getRadius\")\n    private Integer radius;\n    @Nullable\n    @Field(value = 6, getterName = \"getUserNavigationEnabled\")\n    private Boolean userNavigationEnabled = true;\n    @Nullable\n    @Field(value = 7, getterName = \"getZoomGesturesEnabled\")\n    private Boolean zoomGesturesEnabled = true;\n    @Nullable\n    @Field(value = 8, getterName = \"getPanningGesturesEnabled\")\n    private Boolean panningGesturesEnabled = true;\n    @Nullable\n    @Field(value = 9, getterName = \"getStreetNamesEnabled\")\n    private Boolean streetNamesEnabled = true;\n    @Nullable\n    @Field(value = 10, getterName = \"getUseViewLifecycleInFragment\")\n    private Boolean useViewLifecycleInFragment = false;\n    @Field(value = 11, getterName = \"getSource\")\n    private StreetViewSource source = StreetViewSource.DEFAULT;\n\n    /**\n     * Creates a new StreetViewPanoramaOptions object.\n     */\n    public StreetViewPanoramaOptions() {\n    }\n\n    @Constructor\n    StreetViewPanoramaOptions(@Nullable @Param(2) StreetViewPanoramaCamera panoramaCamera, @Nullable @Param(3) String panoramaId, @Nullable @Param(4) LatLng position, @Nullable @Param(5) Integer radius, @Nullable @Param(6) Boolean userNavigationEnabled, @Nullable @Param(7) Boolean zoomGesturesEnabled, @Nullable @Param(8) Boolean panningGesturesEnabled, @Nullable @Param(9) Boolean streetNamesEnabled, @Nullable @Param(10) Boolean useViewLifecycleInFragment, @Param(11) StreetViewSource source) {\n        this.panoramaCamera = panoramaCamera;\n        this.panoramaId = panoramaId;\n        this.position = position;\n        this.radius = radius;\n        this.userNavigationEnabled = userNavigationEnabled;\n        this.zoomGesturesEnabled = zoomGesturesEnabled;\n        this.panningGesturesEnabled = panningGesturesEnabled;\n        this.streetNamesEnabled = streetNamesEnabled;\n        this.useViewLifecycleInFragment = useViewLifecycleInFragment;\n        this.source = source;\n    }\n\n    /**\n     * Returns {@code true} if users are initially able to pan via gestures on Street View panoramas.\n     */\n    @Nullable\n    public Boolean getPanningGesturesEnabled() {\n        return panningGesturesEnabled;\n    }\n\n    /**\n     * Returns the initial panorama ID for the Street View panorama, or {@code null} if unspecified.\n     */\n    @Nullable\n    public String getPanoramaId() {\n        return panoramaId;\n    }\n\n    /**\n     * Returns the initial position for the Street View panorama, or {@code null} if unspecified.\n     */\n    @Nullable\n    public LatLng getPosition() {\n        return position;\n    }\n\n    /**\n     * Returns the initial radius used to search for a Street View panorama, or {@code null} if unspecified.\n     */\n    @Nullable\n    public Integer getRadius() {\n        return radius;\n    }\n\n    /**\n     * Returns the source filter used to search for a Street View panorama, or {@link StreetViewSource#DEFAULT} if unspecified.\n     */\n    @NonNull\n    public StreetViewSource getSource() {\n        return source;\n    }\n\n    /**\n     * Returns {@code true} if users are initially able to see street names on Street View panoramas.\n     */\n    @Nullable\n    public Boolean getStreetNamesEnabled() {\n        return streetNamesEnabled;\n    }\n\n    /**\n     * Returns the initial camera for the Street View panorama, or {@code null} if unspecified.\n     */\n    @Nullable\n    public StreetViewPanoramaCamera getStreetViewPanoramaCamera() {\n        return panoramaCamera;\n    }\n\n    /**\n     * Returns the useViewLifecycleInFragment option, or {@code null} if unspecified.\n     */\n    @Nullable\n    public Boolean getUseViewLifecycleInFragment() {\n        return useViewLifecycleInFragment;\n    }\n\n    /**\n     * Returns {@code true} if users are initially able to move to different Street View panoramas.\n     */\n    @Nullable\n    public Boolean getUserNavigationEnabled() {\n        return userNavigationEnabled;\n    }\n\n    /**\n     * Returns {@code true} if users are initially able to zoom via gestures on Street View panoramas.\n     */\n    @Nullable\n    public Boolean getZoomGesturesEnabled() {\n        return zoomGesturesEnabled;\n    }\n\n    /**\n     * Toggles the ability for users to use pan around on panoramas using gestures. See\n     * {@link StreetViewPanorama#setPanningGesturesEnabled(boolean)} for more details. The default is {@code true}\n     */\n    @NonNull\n    public StreetViewPanoramaOptions panningGesturesEnabled(boolean enabled) {\n        this.panningGesturesEnabled = enabled;\n        return this;\n    }\n\n    /**\n     * Specifies the initial camera for the Street View panorama.\n     */\n    @NonNull\n    public StreetViewPanoramaOptions panoramaCamera(StreetViewPanoramaCamera camera) {\n        this.panoramaCamera = camera;\n        return this;\n    }\n\n    /**\n     * Specifies the initial position for the Street View panorama based on a panorama id. The position set by the panoramaID takes precedence\n     * over a position set by a LatLng.\n     */\n    @NonNull\n    public StreetViewPanoramaOptions panoramaId(String panoId) {\n        panoramaId = panoId;\n        return this;\n    }\n\n    /**\n     * Specifies the initial position for the Street View panorama based upon location. The position set by the panoramaID, if set, takes precedence\n     * over a position set by a LatLng.\n     */\n    @NonNull\n    public StreetViewPanoramaOptions position(LatLng position) {\n        this.position = position;\n        return this;\n    }\n\n    /**\n     * Specifies the initial position for the Street View panorama based upon location, radius and source. The position set by the panoramaID, if\n     * set, takes precedence over a position set by a LatLng.\n     */\n    @NonNull\n    public StreetViewPanoramaOptions position(LatLng position, Integer radius, StreetViewSource source) {\n        this.position = position;\n        this.radius = radius;\n        this.source = source;\n        return this;\n    }\n\n    /**\n     * Specifies the initial position for the Street View panorama based upon location and radius. The position set by the panoramaID, if set, takes\n     * precedence over a position set by a LatLng.\n     */\n    @NonNull\n    public StreetViewPanoramaOptions position(LatLng position, Integer radius) {\n        this.position = position;\n        this.radius = radius;\n        return this;\n    }\n\n    /**\n     * Specifies the initial position for the Street View panorama based upon location and source. The position set by the panoramaID, if set, takes\n     * precedence over a position set by a LatLng.\n     */\n    @NonNull\n    public StreetViewPanoramaOptions position(LatLng position, StreetViewSource source) {\n        this.position = position;\n        this.source = source;\n        return this;\n    }\n\n    /**\n     * Toggles the ability for users to see street names on panoramas. See {@link StreetViewPanorama#setStreetNamesEnabled(boolean)} for more\n     * details. The default is {@code true}\n     */\n    @NonNull\n    public StreetViewPanoramaOptions streetNamesEnabled(boolean enabled) {\n        this.streetNamesEnabled = enabled;\n        return this;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"StreetViewPanoramaOptions\")\n                .field(\"PanoramaId\", panoramaId)\n                .field(\"Position\", position)\n                .field(\"Radius\", radius)\n                .field(\"Source\", source)\n                .field(\"StreetViewPanoramaCamera\", panoramaCamera)\n                .field(\"UserNavigationEnabled\", userNavigationEnabled)\n                .field(\"ZoomGesturesEnabled\", zoomGesturesEnabled)\n                .field(\"PanningGesturesEnabled\", panningGesturesEnabled)\n                .field(\"StreetNamesEnabled\", streetNamesEnabled)\n                .field(\"UseViewLifecycleInFragment\", useViewLifecycleInFragment)\n                .end();\n    }\n\n    /**\n     * When using a {@link StreetViewPanoramaFragment}, this flag specifies whether the lifecycle of the Street View panorama should be tied to the\n     * fragment's view or the fragment itself. The default value is {@code false}, tying the lifecycle of the Street View panorama to the fragment.\n     * <p>\n     * Using the lifecycle of the fragment allows faster rendering of the Street View panorama when the fragment is detached and reattached,\n     * because the underlying GL context is preserved. This has the cost that detaching the fragment, but not destroying it, will not release memory\n     * used by the panorama.\n     * <p>\n     * Using the lifecycle of a fragment's view means that a Street View panorama is not reused when the fragment is detached and reattached.\n     * This will cause the map to re-render from scratch, which can take a few seconds. It also means that while a fragment is detached, and\n     * therefore has no view, all {@link StreetViewPanorama} methods will throw {@link NullPointerException}.\n     */\n    @NonNull\n    public StreetViewPanoramaOptions useViewLifecycleInFragment(boolean useViewLifecycleInFragment) {\n        this.useViewLifecycleInFragment = useViewLifecycleInFragment;\n        return this;\n    }\n\n    /**\n     * Toggles the ability for users to move between panoramas. See {@link StreetViewPanorama#setUserNavigationEnabled(boolean)} for more\n     * details. The default is {@code true}\n     */\n    @NonNull\n    public StreetViewPanoramaOptions userNavigationEnabled(boolean enabled) {\n        this.userNavigationEnabled = enabled;\n        return this;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    /**\n     * Toggles the ability for users to zoom on panoramas using gestures. See {@link StreetViewPanorama#setZoomGesturesEnabled(boolean)} for\n     * more details. The default is {@code true}\n     */\n    @NonNull\n    public StreetViewPanoramaOptions zoomGesturesEnabled(boolean enabled) {\n        this.zoomGesturesEnabled = enabled;\n        return this;\n    }\n\n    public static final SafeParcelableCreatorAndWriter<StreetViewPanoramaOptions> CREATOR = findCreator(StreetViewPanoramaOptions.class);\n\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/StreetViewPanoramaView.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.maps;\n\nimport android.app.Activity;\nimport android.app.Fragment;\nimport android.content.Context;\nimport android.os.Bundle;\nimport android.util.AttributeSet;\nimport android.widget.FrameLayout;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport org.microg.gms.maps.StreetViewPanoramaViewLifecycleHelper;\n\n/**\n * A View which displays a Street View panorama (with data obtained from the Google Maps service). When focused, it captures keypresses\n * and touch gestures to move the panorama.\n * <p>\n * Users of this class must forward all the life cycle methods from the {@link Activity} or {@link Fragment} containing this view to the corresponding ones\n * in this class.\n * <p>\n * A StreetViewPanorama must be acquired using {@link #getStreetViewPanoramaAsync(OnStreetViewPanoramaReadyCallback)}. The\n * {@link StreetViewPanoramaView} automatically initializes the Street View system and the view.\n */\npublic class StreetViewPanoramaView extends FrameLayout {\n    private final StreetViewPanoramaViewLifecycleHelper helper;\n\n    public StreetViewPanoramaView(@NonNull Context context) {\n        super(context);\n        this.helper = new StreetViewPanoramaViewLifecycleHelper(this, context, null);\n    }\n\n    public StreetViewPanoramaView(@NonNull Context context, @Nullable AttributeSet attrs) {\n        super(context, attrs);\n        this.helper = new StreetViewPanoramaViewLifecycleHelper(this, context, null);\n    }\n\n    public StreetViewPanoramaView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        this.helper = new StreetViewPanoramaViewLifecycleHelper(this, context, null);\n    }\n\n    /**\n     * @param context The context that will show the view. Must not be {@code null}.\n     * @param options Configuration options for the new view. The view will be configured with default values if {@code options} is {@code null} or any option field is left {@code null}.\n     */\n    public StreetViewPanoramaView(@NonNull Context context, StreetViewPanoramaOptions options) {\n        super(context);\n        this.helper = new StreetViewPanoramaViewLifecycleHelper(this, context, options);\n    }\n\n    /**\n     * Sets a callback object which will be triggered when the {@link StreetViewPanorama} instance is ready to be used.\n     *\n     * @param callback The callback object that will be triggered when the panorama is ready to be used. Must not be {@code null}.\n     */\n    public void getStreetViewPanoramaAsync(OnStreetViewPanoramaReadyCallback callback) {\n        helper.getStreetViewPanoramaAsync(callback);\n    }\n\n    /**\n     * You must call this method from the parent Activity/Fragment's corresponding method.\n     */\n    public final void onCreate(Bundle savedInstanceState) {\n        helper.onCreate(savedInstanceState);\n    }\n\n    /**\n     * You must call this method from the parent Activity/Fragment's corresponding method.\n     */\n    public void onDestroy() {\n        helper.onDestroy();\n    }\n\n    /**\n     * You must call this method from the parent Activity/Fragment's corresponding method.\n     */\n    public final void onLowMemory() {\n        helper.onLowMemory();\n    }\n\n    /**\n     * You must call this method from the parent Activity/Fragment's corresponding method.\n     */\n    public final void onPause() {\n        helper.onPause();\n    }\n\n    /**\n     * You must call this method from the parent Activity/Fragment's corresponding method.\n     */\n    public void onResume() {\n        helper.onResume();\n    }\n\n    /**\n     * You must call this method from the parent Activity/Fragment's corresponding method.\n     */\n    public final void onSaveInstanceState(Bundle outState) {\n        helper.onSaveInstanceState(outState);\n    }\n\n    /**\n     * You must call this method from the parent Activity/Fragment's corresponding method.\n     */\n    public void onStart() {\n        helper.onStart();\n    }\n\n    /**\n     * You must call this method from the parent Activity/Fragment's corresponding method.\n     */\n    public void onStop() {\n        helper.onStop();\n    }\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/model/BitmapDescriptor.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.maps.model;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Defines an image. For a marker, it can be used to set the image of the marker icon. For a ground\n * overlay, it can be used to set the image to place on the surface of the earth.\n */\n@PublicApi\npublic class BitmapDescriptor {\n    private final IObjectWrapper remoteObject;\n\n    public BitmapDescriptor(IObjectWrapper remoteObject) {\n        this.remoteObject = remoteObject;\n    }\n\n    public IObjectWrapper getRemoteObject() {\n        return remoteObject;\n    }\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/model/BitmapDescriptorFactory.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.maps.model;\n\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.maps.CameraUpdateFactory;\nimport com.google.android.gms.maps.internal.ICameraUpdateFactoryDelegate;\nimport com.google.android.gms.maps.model.internal.IBitmapDescriptorFactoryDelegate;\nimport org.microg.gms.common.Hide;\n\npublic class BitmapDescriptorFactory {\n    private static IBitmapDescriptorFactoryDelegate delegate;\n    @Hide\n    public static void setDelegate(@NonNull IBitmapDescriptorFactoryDelegate delegate) {\n        BitmapDescriptorFactory.delegate = delegate;\n    }\n    private static IBitmapDescriptorFactoryDelegate getDelegate() {\n        if (delegate == null) throw new IllegalStateException(\"CameraUpdateFactory is not initialized\");\n        return delegate;\n    }\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/model/ButtCap.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.maps.model;\n\nimport androidx.annotation.NonNull;\n\n/**\n * Cap that is squared off exactly at the start or end vertex of a {@link Polyline} with solid stroke pattern, equivalent to having no\n * additional cap beyond the start or end vertex. This is the default cap type at start and end vertices of {@link Polyline}s with\n * solid stroke pattern.\n */\npublic class ButtCap extends Cap {\n    /**\n     * Constructs a {@code ButtCap}.\n     */\n    public ButtCap() {\n        super(0, null, null);\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return \"[ButtCap]\";\n    }\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/model/CameraPosition.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.maps.model;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\nimport java.util.Arrays;\n\n/**\n * An immutable class that aggregates all camera position parameters.\n */\n@PublicApi\npublic final class CameraPosition extends AutoSafeParcelable {\n    @SafeParceled(1)\n    private int versionCode = 1;\n    /**\n     * The location that the camera is pointing at.\n     */\n    @SafeParceled(2)\n    public final LatLng target;\n    /**\n     * Zoom level near the center of the screen.\n     * See {@link Builder#zoom(float)} for the definition of the camera's zoom level.\n     */\n    @SafeParceled(3)\n    public final float zoom;\n    /**\n     * The angle, in degrees, of the camera angle from the nadir (directly facing the Earth).\n     * See {@link Builder#tilt(float)} for details of restrictions on the range of values.\n     */\n    @SafeParceled(4)\n    public final float tilt;\n    /**\n     * Direction that the camera is pointing in, in degrees clockwise from north.\n     */\n    @SafeParceled(5)\n    public final float bearing;\n\n    /**\n     * This constructor is dirty setting the final fields to make the compiler happy.\n     * In fact, those are replaced by their real values later using SafeParcelUtil.\n     */\n    private CameraPosition() {\n        target = null;\n        zoom = tilt = bearing = 0;\n    }\n\n    /**\n     * Constructs a CameraPosition.\n     *\n     * @param target  The target location to align with the center of the screen.\n     * @param zoom    Zoom level at target. See {@link #zoom} for details of restrictions.\n     * @param tilt    The camera angle, in degrees, from the nadir (directly down). See\n     *                {@link #tilt} for details of restrictions.\n     * @param bearing Direction that the camera is pointing in, in degrees clockwise from north.\n     *                This value will be normalized to be within 0 degrees inclusive and 360\n     *                degrees exclusive.\n     * @throws NullPointerException     if {@code target} is {@code null}\n     * @throws IllegalArgumentException if {@code tilt} is outside range of {@code 0} to {@code 90}\n     *                                  degrees inclusive\n     */\n    public CameraPosition(LatLng target, float zoom, float tilt, float bearing)\n            throws NullPointerException, IllegalArgumentException {\n        if (target == null) {\n            throw new NullPointerException(\"null camera target\");\n        }\n        this.target = target;\n        this.zoom = zoom;\n        if (tilt < 0 || 90 < tilt) {\n            throw new IllegalArgumentException(\"Tilt needs to be between 0 and 90 inclusive\");\n        }\n        this.tilt = tilt;\n        if (bearing <= 0) {\n            bearing += 360;\n        }\n        this.bearing = bearing % 360;\n    }\n\n    /**\n     * Creates a builder for a camera position.\n     */\n    public static Builder builder() {\n        return new Builder();\n    }\n\n    /**\n     * Creates a builder for a camera position, initialized to a given position.\n     */\n    public static Builder builder(CameraPosition camera) {\n        return new Builder(camera);\n    }\n\n    /**\n     * Creates a CameraPostion from the attribute set\n     *\n     * @throws UnsupportedOperationException\n     */\n    public static CameraPosition createFromAttributes(Context context, AttributeSet attrs) {\n        return null; // TODO\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o)\n            return true;\n        if (o == null || getClass() != o.getClass())\n            return false;\n\n        CameraPosition that = (CameraPosition) o;\n\n        if (Float.compare(that.bearing, bearing) != 0)\n            return false;\n        if (Float.compare(that.tilt, tilt) != 0)\n            return false;\n        if (Float.compare(that.zoom, zoom) != 0)\n            return false;\n        if (!target.equals(that.target))\n            return false;\n\n        return true;\n    }\n\n    /**\n     * Constructs a CameraPosition pointed for a particular target and zoom level. The resultant\n     * bearing is North, and the viewing angle is perpendicular to the Earth's surface. i.e.,\n     * directly facing the Earth's surface, with the top of the screen pointing North.\n     *\n     * @param target The target location to align with the center of the screen.\n     * @param zoom   Zoom level at target. See {@link Builder#zoom(float)} for details on the range\n     *               the value will be clamped to. The larger the value the more zoomed in the\n     *               camera is.\n     */\n    public static final CameraPosition fromLatLngZoom(LatLng target, float zoom) {\n        return builder().target(target).zoom(zoom).build();\n    }\n\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(new Object[] { target, zoom, tilt, bearing });\n    }\n\n    @Override\n    public String toString() {\n        return \"CameraPosition{\" +\n                \"target=\" + target +\n                \", zoom=\" + zoom +\n                \", tilt=\" + tilt +\n                \", bearing=\" + bearing +\n                '}';\n    }\n\n    public static Creator<CameraPosition> CREATOR = new AutoCreator<CameraPosition>(CameraPosition.class);\n\n    /**\n     * Builds camera position.\n     */\n    public static final class Builder {\n        private LatLng target;\n        private float zoom;\n        private float tilt;\n        private float bearing;\n\n        public Builder() {\n        }\n\n        public Builder(CameraPosition previous) {\n            target = previous.target;\n            zoom = previous.zoom;\n            tilt = previous.tilt;\n            bearing = previous.bearing;\n        }\n\n        /**\n         * Sets the direction that the camera is pointing in, in degrees clockwise from north.\n         */\n        public Builder bearing(float bearing) {\n            this.bearing = bearing;\n            return this;\n        }\n\n        /**\n         * Builds a {@link CameraPosition}.\n         */\n        public CameraPosition build() {\n            return new CameraPosition(target, zoom, tilt, bearing);\n        }\n\n        /**\n         * Sets the location that the camera is pointing at.\n         */\n        public Builder target(LatLng target) {\n            this.target = target;\n            return this;\n        }\n\n        /**\n         * Sets the angle, in degrees, of the camera from the nadir (directly facing the Earth).\n         * When changing the camera position for a map, this value is restricted depending on the\n         * zoom level of the camera. The restrictions are as follows:\n         * <ul>\n         * <li>For zoom levels less than 10 the maximum is 30.</li>\n         * <li>For zoom levels from 10 to 14 the maximum increases linearly from 30 to 45 (e.g. at\n         * zoom level 12, the maximum is 37.5).</li>\n         * <li>For zoom levels from 14 to 15.5 the maximum increases linearly from 45 to 67.5.</li>\n         * <li>For zoom levels greater than 15.5 the maximum is 67.5.</li>\n         * </ul>\n         * The minimum is always 0 (directly down). If you specify a value outside this range and try to move the camera to this camera position it will be clamped to these bounds.\n         */\n        public Builder tilt(float tilt) {\n            this.tilt = tilt;\n            return this;\n        }\n\n        /**\n         * Sets the zoom level of the camera. Zoom level is defined such that at zoom level 0, the\n         * whole world is approximately 256dp wide (assuming that the camera is not tilted).\n         * Increasing the zoom level by 1 doubles the width of the world on the screen. Hence at\n         * zoom level N, the width of the world is approximately 256 * 2 N dp, i.e., at zoom level\n         * 2, the whole world is approximately 1024dp wide.\n         * <p/>\n         * When changing the camera position for a map, the zoom level of the camera is restricted\n         * to a certain range depending on various factors including location, map type and map\n         * size. Note that the camera zoom need not be an integer value.\n         */\n        public Builder zoom(float zoom) {\n            this.zoom = zoom;\n            return this;\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/model/Cap.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.maps.model;\n\nimport android.os.IBinder;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\nimport java.util.Objects;\n\n/**\n * Immutable cap that can be applied at the start or end vertex of a {@link Polyline}.\n */\npublic class Cap extends AutoSafeParcelable {\n    @Field(2)\n    public final int type;\n    @Field(3)\n    @Nullable\n    private final IBinder bitmap;\n    /**\n     * Descriptor of the bitmap to be overlaid at the start or end vertex.\n     */\n    @Nullable\n    private final BitmapDescriptor bitmapDescriptor;\n    /**\n     * Reference stroke width (in pixels) - the stroke width for which the cap bitmap at its native dimension is designed.\n     * The default reference stroke width is 10 pixels.\n     */\n    @Field(4)\n    @Nullable\n    private final Float refWidth;\n\n    private Cap() {\n        type = 0;\n        bitmap = null;\n        bitmapDescriptor = null;\n        refWidth = 0.0f;\n    }\n\n    protected Cap(int type, @Nullable BitmapDescriptor bitmapDescriptor, @Nullable Float refWidth) {\n        this.type = type;\n        this.bitmap = bitmapDescriptor == null ? null : bitmapDescriptor.getRemoteObject().asBinder();\n        this.bitmapDescriptor = bitmapDescriptor;\n        this.refWidth = refWidth;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return \"[Cap: type=\" + type + \"]\";\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof Cap)) return false;\n\n        Cap cap = (Cap) o;\n\n        if (type != cap.type) return false;\n        if (!Objects.equals(bitmapDescriptor, cap.bitmapDescriptor)) return false;\n        return Objects.equals(refWidth, cap.refWidth);\n    }\n\n    @Override\n    public int hashCode() {\n        int result = type;\n        result = 31 * result + (bitmapDescriptor != null ? bitmapDescriptor.hashCode() : 0);\n        result = 31 * result + (refWidth != null ? refWidth.hashCode() : 0);\n        return result;\n    }\n\n    public static final Creator<Cap> CREATOR = new AutoCreator<Cap>(Cap.class) {\n        @Override\n        public Cap createFromParcel(Parcel parcel) {\n            Cap item = super.createFromParcel(parcel);\n            switch (item.type) {\n                case 0:\n                    return new ButtCap();\n                case 1:\n                    return new SquareCap();\n                case 2:\n                    return new RoundCap();\n                case 3:\n                    if (item.refWidth != null) {\n                        return new CustomCap(item.bitmapDescriptor, item.refWidth);\n                    } else {\n                        return new CustomCap(item.bitmapDescriptor);\n                    }\n                default:\n                    return item;\n            }\n        }\n    };\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/model/Circle.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.maps.model;\n\nimport android.os.RemoteException;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.maps.model.internal.ICircleDelegate;\nimport org.microg.gms.common.Hide;\n\nimport java.util.List;\n\n/**\n * A circle on the earth's surface (spherical cap).\n */\npublic class Circle {\n    private final ICircleDelegate delegate;\n\n    @Hide\n    public Circle(ICircleDelegate delegate) {\n        this.delegate = delegate;\n    }\n\n    @NonNull\n    public LatLng getCenter() {\n        try {\n            return this.delegate.getCenter();\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    public int getFillColor() {\n        try {\n            return this.delegate.getFillColor();\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    @NonNull\n    public String getId() {\n        try {\n            return this.delegate.getId();\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    public double getRadius() {\n        try {\n            return this.delegate.getRadius();\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    @Nullable\n    public List<PatternItem> getStrokePattern() {\n        throw new UnsupportedOperationException();\n    }\n\n    public int getStrokeColor() {\n        try {\n            return this.delegate.getStrokeColor();\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    public float getStrokeWidth() {\n        try {\n            return this.delegate.getStrokeWidth();\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    @Nullable\n    public Object getTag() {\n        throw new UnsupportedOperationException();\n    }\n\n    public float getZIndex() {\n        try {\n            return this.delegate.getZIndex();\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    public boolean isClickable() {\n        throw new UnsupportedOperationException();\n    }\n\n    public boolean isVisible() {\n        try {\n            return this.delegate.isVisible();\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    public void remove() {\n        try {\n            this.delegate.remove();\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    public void setCenter(@NonNull LatLng center) {\n        try {\n            this.delegate.setCenter(center);\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    public void setClickable(boolean clickable) {\n        throw new UnsupportedOperationException();\n    }\n\n    public void setFillColor(int color) {\n        try {\n            this.delegate.setFillColor(color);\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    public void setRadius(double radius) {\n        try {\n            this.delegate.setRadius(radius);\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    public void setStrokeColor(int color) {\n        try {\n            this.delegate.setStrokeColor(color);\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    public void setStrokePattern(@Nullable List<PatternItem> pattern) {\n        throw new UnsupportedOperationException();\n    }\n\n    public void setStrokeWidth(float width) {\n        try {\n            this.delegate.setStrokeWidth(width);\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    public void setTag(@Nullable Object tag) {\n        throw new UnsupportedOperationException();\n    }\n\n    public void setVisible(boolean visible) {\n        try {\n            this.delegate.setVisible(visible);\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    public void setZIndex(float zIndex) {\n        try {\n            this.delegate.setZIndex(zIndex);\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/model/CircleOptions.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.maps.model;\n\nimport android.graphics.Color;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\n/**\n * Defines options for a Circle.\n */\n@PublicApi\npublic class CircleOptions extends AutoSafeParcelable {\n    @Field(1)\n    private int versionCode;\n    @Field(2)\n    private LatLng center;\n    @Field(3)\n    private double radius = 0.0d;\n    @Field(4)\n    private float strokeWidth = 10.0f;\n    @Field(5)\n    private int strokeColor = Color.BLACK;\n    @Field(6)\n    private int fillColor = Color.TRANSPARENT;\n    @Field(7)\n    private float zIndex = 0.0f;\n    @Field(8)\n    private boolean visible = true;\n    @Field(9)\n    private boolean clickable = false;\n    @Field(10)\n    private List<PatternItem> strokePattern = null;\n\n    /**\n     * Creates circle options.\n     */\n    public CircleOptions() {\n    }\n\n    /**\n     * Sets the center using a {@link LatLng}.\n     * <p/>\n     * The center must not be {@code null}.\n     * <p/>\n     * This method is mandatory because there is no default center.\n     *\n     * @param center The geographic center as a {@link LatLng}.\n     * @return this {@link CircleOptions} object\n     */\n    public CircleOptions center(LatLng center) {\n        this.center = center;\n        return this;\n    }\n\n    /**\n     * Sets the fill color.\n     * <p/>\n     * The fill color is the color inside the circle, in the integer format specified by\n     * {@link Color}. If TRANSPARENT is used then no fill is drawn.\n     * <p/>\n     * By default the fill color is transparent ({@code 0x00000000}).\n     *\n     * @param color color in the {@link Color} format\n     * @return this {@link CircleOptions} object\n     */\n    public CircleOptions fillColor(int color) {\n        this.fillColor = color;\n        return this;\n    }\n\n    /**\n     * Returns the center as a {@link LatLng}.\n     *\n     * @return The geographic center as a {@link LatLng}.\n     */\n    public LatLng getCenter() {\n        return center;\n    }\n\n    /**\n     * Returns the fill color.\n     *\n     * @return The color in the {@link Color} format.\n     */\n    public int getFillColor() {\n        return fillColor;\n    }\n\n    /**\n     * Returns the circle's radius, in meters.\n     *\n     * @return The radius in meters.\n     */\n    public double getRadius() {\n        return radius;\n    }\n\n    /**\n     * Returns the stroke color.\n     *\n     * @return The color in the {@link Color} format.\n     */\n    public int getStrokeColor() {\n        return strokeColor;\n    }\n\n    /**\n     * Returns the stroke width.\n     *\n     * @return The width in screen pixels.\n     */\n    public float getStrokeWidth() {\n        return strokeWidth;\n    }\n\n    /**\n     * Returns the zIndex.\n     *\n     * @return The zIndex value.\n     */\n    public float getZIndex() {\n        return zIndex;\n    }\n\n    /**\n     * Checks whether the circle is visible.\n     *\n     * @return {code true} if the circle is visible; {@code false} if it is invisible.\n     */\n    public boolean isVisible() {\n        return visible;\n    }\n\n    /**\n     * Gets the clickability setting for the circle.\n     *\n     * @return {@code true} if the circle is clickable; {@code false} if it is not.\n     */\n    public boolean isClickable() {\n        return clickable;\n    }\n\n    /**\n     * Sets the radius in meters.\n     * <p/>\n     * The radius must be zero or greater. The default radius is zero.\n     *\n     * @param radius radius in meters\n     * @return this {@link CircleOptions} object\n     */\n    public CircleOptions radius(double radius) {\n        this.radius = radius;\n        return this;\n    }\n\n    /**\n     * Sets the stroke color.\n     * <p/>\n     * The stroke color is the color of this circle's outline, in the integer format specified by\n     * {@link Color}. If TRANSPARENT is used then no outline is drawn.\n     * <p/>\n     * By default the stroke color is black ({@code 0xff000000}).\n     *\n     * @param color color in the {@link Color} format\n     * @return this {@link CircleOptions} object\n     */\n    public CircleOptions strokeColor(int color) {\n        this.strokeColor = color;\n        return this;\n    }\n\n    /**\n     * Sets the stroke width.\n     * <p/>\n     * The stroke width is the width (in screen pixels) of the circle's outline. It must be zero or\n     * greater. If it is zero then no outline is drawn.\n     * <p/>\n     * The default width is 10 pixels.\n     *\n     * @param width width in screen pixels\n     * @return this {@link CircleOptions} object\n     */\n    public CircleOptions strokeWidth(float width) {\n        this.strokeWidth = width;\n        return this;\n    }\n\n    /**\n     * Sets the visibility.\n     * <p/>\n     * If this circle is not visible then it is not drawn, but all other state is preserved.\n     *\n     * @param visible {@code false} to make this circle invisible\n     * @return this {@link CircleOptions} object\n     */\n    public CircleOptions visible(boolean visible) {\n        this.visible = visible;\n        return this;\n    }\n\n    /**\n     * Sets the zIndex.\n     * <p/>\n     * Overlays (such as circles) with higher zIndices are drawn above those with lower indices.\n     * <p/>\n     * By default the zIndex is {@code 0.0}.\n     *\n     * @param zIndex zIndex value\n     * @return this {@link CircleOptions} object\n     */\n    public CircleOptions zIndex(float zIndex) {\n        this.zIndex = zIndex;\n        return this;\n    }\n\n    /**\n     * Specifies whether this circle is clickable. The default setting is {@code false}.\n     *\n     * @param clickable\n     * @return this {@code CircleOptions} object with a new clickability setting.\n     */\n    public CircleOptions clickable(boolean clickable) {\n        this.clickable = clickable;\n        return this;\n    }\n\n    /**\n     * Specifies a stroke pattern for the circle's outline. The default stroke pattern is solid, represented by {@code null}.\n     *\n     * @return this {@link CircleOptions} object with a new stroke pattern set.\n     */\n    public CircleOptions strokePattern(List<PatternItem> pattern) {\n        this.strokePattern = pattern;\n        return this;\n    }\n\n    /**\n     * Gets the stroke pattern set in this {@link CircleOptions} object for the circle's outline.\n     *\n     * @return the stroke pattern of the circle's outline.\n     */\n    public List<PatternItem> getStrokePattern() {\n        return strokePattern;\n    }\n\n    public static Creator<CircleOptions> CREATOR = new AutoCreator<CircleOptions>(CircleOptions.class);\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/model/CustomCap.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.maps.model;\n\nimport androidx.annotation.NonNull;\n\n/**\n * Bitmap overlay centered at the start or end vertex of a {@link Polyline}, orientated according to the direction of the line's first\n * or last edge and scaled with respect to the line's stroke width. {@code CustomCap} can be applied to {@link Polyline} with any stroke pattern.\n */\npublic class CustomCap extends Cap {\n    @NonNull\n    public final BitmapDescriptor bitmapDescriptor;\n    public final Float refWidth;\n\n    /**\n     * Constructs a new {@code CustomCap}.\n     *\n     * @param bitmapDescriptor Descriptor of the bitmap to be used. Must not be {@code null}.\n     * @param refWidth         Stroke width, in pixels, for which the cap bitmap at its native dimension is designed. Must be positive.\n     */\n    public CustomCap(@NonNull BitmapDescriptor bitmapDescriptor, float refWidth) {\n        super(3, bitmapDescriptor, refWidth);\n        this.bitmapDescriptor = bitmapDescriptor;\n        this.refWidth = refWidth;\n    }\n\n    /**\n     * Constructs a new {@code CustomCap} with default reference stroke width of 10 pixels (equal to the default stroke width, see\n     * {@link PolylineOptions#width(float)}).\n     *\n     * @param bitmapDescriptor Descriptor of the bitmap to be used. Must not be {@code null}.\n     */\n    public CustomCap(@NonNull BitmapDescriptor bitmapDescriptor) {\n        super(3, bitmapDescriptor, null);\n        this.bitmapDescriptor = bitmapDescriptor;\n        this.refWidth = null;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return \"[CustomCap bitmapDescriptor=\" + bitmapDescriptor + \" refWidth=\" + refWidth + \"]\";\n    }\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/model/Dash.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.maps.model;\n\nimport androidx.annotation.NonNull;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * An immutable class representing a dash used in the stroke pattern for a Polyline or the outline of a Polygon or Circle.\n */\n@PublicApi\npublic final class Dash extends PatternItem {\n    /**\n     * Length in pixels (non-negative).\n     */\n    public final float length;\n\n    /**\n     * Constructs a {@code Dash}.\n     * @param length Length in pixels. Negative value will be clamped to zero.\n     */\n    public Dash(float length) {\n        super(0, Math.max(length, 0));\n        this.length = Math.max(length, 0);\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return \"[Dash: length=\" + length + \"]\";\n    }\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/model/Dot.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.maps.model;\n\nimport androidx.annotation.NonNull;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * An immutable class representing a dot used in the stroke pattern for a Polyline or the outline of a Polygon or Circle.\n */\n@PublicApi\npublic final class Dot extends PatternItem {\n    /**\n     * Constructs a {@code Dot}.\n     */\n    public Dot() {\n        super(1, null);\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return \"[Dot]\";\n    }\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/model/Gap.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.maps.model;\n\nimport androidx.annotation.NonNull;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * An immutable class representing a gap used in the stroke pattern for a Polyline or the outline of a Polygon or Circle.\n */\n@PublicApi\npublic final class Gap extends PatternItem {\n    /**\n     * Length in pixels (non-negative).\n     */\n    public final float length;\n\n    /**\n     * Constructs a {@code Gap}.\n     * @param length Length in pixels. Negative value will be clamped to zero.\n     */\n    public Gap(float length) {\n        super(2, Math.max(length, 0));\n        this.length = Math.max(length, 0);\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return \"[Gap: length=\" + length + \"]\";\n    }\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/model/GroundOverlayOptions.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2015 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.maps.model;\n\nimport android.os.IBinder;\n\nimport com.google.android.gms.dynamic.ObjectWrapper;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n/**\n * Defines options for a ground overlay.\n */\n@PublicApi\npublic class GroundOverlayOptions extends AutoSafeParcelable {\n    /**\n     * Flag for when no dimension is specified for the height.\n     */\n    public static final float NO_DIMENSION = -1;\n\n    @Field(1)\n    private int versionCode;\n    @Field(2)\n    private IBinder image;\n    private BitmapDescriptor imageDescriptor;\n    @Field(3)\n    private LatLng location;\n    @Field(4)\n    private float width;\n    @Field(5)\n    private float height = NO_DIMENSION;\n    @Field(6)\n    private LatLngBounds bounds;\n    @Field(7)\n    private float bearing;\n    @Field(8)\n    private float zIndex;\n    @Field(9)\n    private boolean visible = true;\n    @Field(10)\n    private float transparency = 0.0f;\n    @Field(11)\n    private float anchorU = 0.5f;\n    @Field(12)\n    private float anchorV = 0.5f;\n    @Field(13)\n    private boolean clickable = false;\n\n    /**\n     * Creates a new set of ground overlay options.\n     */\n    public GroundOverlayOptions() {\n    }\n\n    /**\n     * Specifies the anchor to be at a particular point in the image.\n     * <p/>\n     * The anchor specifies the point in the image that aligns with the ground overlay's location.\n     * <p/>\n     * The anchor point is specified in the continuous space [0.0, 1.0] x [0.0, 1.0], where (0, 0)\n     * is the top-left corner of the image, and (1, 1) is the bottom-right corner.\n     *\n     * @param u u-coordinate of the anchor, as a ratio of the image width (in the range [0, 1])\n     * @param v v-coordinate of the anchor, as a ratio of the image height (in the range [0, 1])\n     * @return this {@link GroundOverlayOptions} object with a new anchor set.\n     */\n    public GroundOverlayOptions anchor(float u, float v) {\n        this.anchorU = u;\n        this.anchorV = v;\n        return this;\n    }\n\n    /**\n     * Specifies the bearing of the ground overlay in degrees clockwise from north. The rotation is\n     * performed about the anchor point. If not specified, the default is 0 (i.e., up on the image\n     * points north).\n     * <p/>\n     * If a ground overlay with position set using {@link #positionFromBounds(LatLngBounds)} is\n     * rotated, its size will preserved and it will no longer be guaranteed to fit inside the\n     * bounds.\n     *\n     * @param bearing the bearing in degrees clockwise from north. Values outside the range\n     *                [0, 360) will be normalized.\n     * @return this {@link GroundOverlayOptions} object with a new bearing set.\n     */\n    public GroundOverlayOptions bearing(float bearing) {\n        this.bearing = bearing;\n        return this;\n    }\n\n    /**\n     * Specifies whether the ground overlay is clickable. The default clickability is {@code false}.\n     *\n     * @param clickable The new clickability setting.\n     * @return this {@link GroundOverlayOptions} object with a new clickability setting.\n     */\n    public GroundOverlayOptions clickable(boolean clickable) {\n        this.clickable = clickable;\n        return this;\n    }\n\n    /**\n     * Horizontal distance, normalized to [0, 1], of the anchor from the left edge.\n     *\n     * @return the u value of the anchor.\n     */\n    public float getAnchorU() {\n        return anchorU;\n    }\n\n    /**\n     * Vertical distance, normalized to [0, 1], of the anchor from the top edge.\n     *\n     * @return the v value of the anchor.\n     */\n    public float getAnchorV() {\n        return anchorV;\n    }\n\n    /**\n     * Gets the bearing set for this options object.\n     *\n     * @return the bearing of the ground overlay.\n     */\n    public float getBearing() {\n        return bearing;\n    }\n\n    /**\n     * Gets the bounds set for this options object.\n     *\n     * @return the bounds of the ground overlay. This will be {@code null} if the position was set\n     * using {@link #position(LatLng, float)} or {@link #position(LatLng, float, float)}\n     */\n    public LatLngBounds getBounds() {\n        return bounds;\n    }\n\n    /**\n     * Gets the height set for this options object.\n     *\n     * @return the height of the ground overlay.\n     */\n    public float getHeight() {\n        return height;\n    }\n\n    /**\n     * Gets the image set for this options object.\n     *\n     * @return the image of the ground overlay.\n     */\n    public BitmapDescriptor getImage() {\n        if (imageDescriptor == null && image != null) {\n            imageDescriptor = new BitmapDescriptor(ObjectWrapper.asInterface(image));\n        }\n        return imageDescriptor;\n    }\n\n    /**\n     * Gets the location set for this options object.\n     *\n     * @return the location to place the anchor of the ground overlay. This will be {@code null}\n     * if the position was set using {@link #positionFromBounds(LatLngBounds)}.\n     */\n    public LatLng getLocation() {\n        return location;\n    }\n\n    /**\n     * Gets the transparency set for this options object.\n     *\n     * @return the transparency of the ground overlay.\n     */\n    public float getTransparency() {\n        return transparency;\n    }\n\n    /**\n     * Gets the width set for this options object.\n     *\n     * @return the width of the ground overlay.\n     */\n    public float getWidth() {\n        return width;\n    }\n\n    /**\n     * Gets the zIndex set for this options object.\n     *\n     * @return the zIndex of the ground overlay.\n     */\n    public float getZIndex() {\n        return zIndex;\n    }\n\n    /**\n     * Specifies the image for this ground overlay.\n     * <p/>\n     * To load an image as a texture (which is used to draw the image on a map), it must be\n     * converted into an image with sides that are powers of two. This is so that a mipmap can be\n     * created in order to render the texture at various zoom levels - see\n     * <a href=\"http://en.wikipedia.org/wiki/Mipmap\">Mipmap (Wikipedia)</a> for details. Hence, to\n     * conserve memory by avoiding this conversion, it is advised that the dimensions of the image\n     * are powers of two.\n     *\n     * @param image the {@link BitmapDescriptor} to use for this ground overlay\n     * @return this {@link GroundOverlayOptions} object with a new image set.\n     */\n    public GroundOverlayOptions image(BitmapDescriptor image) {\n        this.imageDescriptor = image;\n        this.image = imageDescriptor.getRemoteObject().asBinder();\n        return this;\n    }\n\n    /**\n     * Gets the clickability setting for this {@link GroundOverlayOptions} object.\n     *\n     * @return {@code true} if the ground overlay is clickable; {@code false} if it is not.\n     */\n    public boolean isClickable() {\n        return clickable;\n    }\n\n    /**\n     * Gets the visibility setting for this options object.\n     *\n     * @return {@code true} if the ground overlay is to be visible; {@code false} if it is not.\n     */\n    public boolean isVisible() {\n        return visible;\n    }\n\n    /**\n     * Specifies the position for this ground overlay using an anchor point (a {@link LatLng}),\n     * width and height (both in meters). When rendered, the image will be scaled to fit the\n     * dimensions specified (i.e., its proportions will not necessarily be preserved).\n     *\n     * @param location the location on the map {@code LatLng} to which the anchor point in the\n     *                 given image will remain fixed. The anchor will remain fixed to the position\n     *                 on the ground when transformations are applied (e.g., setDimensions,\n     *                 setBearing, etc.).\n     * @param width    the width of the overlay (in meters)\n     * @param height   the height of the overlay (in meters)\n     * @return this {@link GroundOverlayOptions} object with a new position set.\n     * @throws IllegalArgumentException if anchor is null\n     * @throws IllegalArgumentException if width or height are negative\n     * @throws IllegalStateException    if the position was already set using\n     *                                  {@link #positionFromBounds(LatLngBounds)}\n     */\n    public GroundOverlayOptions position(LatLng location, float width, float height)\n            throws IllegalArgumentException, IllegalStateException {\n        position(location, width);\n        if (height < 0)\n            throw new IllegalArgumentException(\"height must not be negative\");\n        this.height = height;\n        return this;\n    }\n\n    /**\n     * Specifies the position for this ground overlay using an anchor point (a {@link LatLng}) and\n     * the width (in meters). When rendered, the image will retain its proportions from the bitmap,\n     * i.e., the height will be calculated to preserve the original proportions of the image.\n     *\n     * @param location the location on the map {@link LatLng} to which the anchor point in the\n     *                 given image will remain fixed. The anchor will remain fixed to the position\n     *                 on the ground when transformations are applied (e.g., setDimensions,\n     *                 setBearing, etc.).\n     * @param width    the width of the overlay (in meters). The height will be determined\n     *                 automatically based on the image proportions.\n     * @return this {@link GroundOverlayOptions} object with a new position set.\n     * @throws IllegalArgumentException if anchor is null\n     * @throws IllegalArgumentException if width is negative\n     * @throws IllegalStateException    if the position was already set using\n     *                                  {@link #positionFromBounds(LatLngBounds)}\n     */\n    public GroundOverlayOptions position(LatLng location, float width)\n            throws IllegalArgumentException, IllegalStateException {\n        if (location == null)\n            throw new IllegalArgumentException(\"location must not be null\");\n        if (width < 0)\n            throw new IllegalArgumentException(\"width must not be negative\");\n        if (bounds != null)\n            throw new IllegalStateException(\"Position already set using positionFromBounds()\");\n        this.location = location;\n        this.width = width;\n        return this;\n    }\n\n    /**\n     * Specifies the position for this ground overlay. When rendered, the image will be scaled to\n     * fit the bounds (i.e., its proportions will not necessarily be preserved).\n     *\n     * @param bounds a {@link LatLngBounds} in which to place the ground overlay\n     * @return this {@link GroundOverlayOptions} object with a new position set.\n     * @throws IllegalStateException if the position was already set using\n     *                               {@link #position(LatLng, float)} or\n     *                               {@link #position(LatLng, float, float)}\n     */\n    public GroundOverlayOptions positionFromBounds(LatLngBounds bounds)\n            throws IllegalStateException {\n        if (location != null)\n            throw new IllegalStateException(\"Position already set using position()\");\n        this.bounds = bounds;\n        return this;\n    }\n\n    /**\n     * Specifies the transparency of the ground overlay. The default transparency is {code 0}\n     * (opaque).\n     *\n     * @param transparency a float in the range {@code [0..1]} where {@code 0} means that the\n     *                     ground overlay is opaque and {code 1} means that the ground overlay is\n     *                     transparent\n     * @return this {@link GroundOverlayOptions} object with a new visibility setting.\n     * @throws IllegalArgumentException if the transparency is outside the range [0..1].\n     */\n    public GroundOverlayOptions transparency(float transparency) throws IllegalArgumentException {\n        if (transparency < 0 || transparency > 1)\n            throw new IllegalArgumentException(\"transparency must be in range [0..1]\");\n        this.transparency = transparency;\n        return this;\n    }\n\n    /**\n     * Specifies the visibility for the ground overlay. The default visibility is {@code true}.\n     *\n     * @return this {@link GroundOverlayOptions} object with a new visibility setting.\n     */\n    public GroundOverlayOptions visible(boolean visible) {\n        this.visible = visible;\n        return this;\n    }\n\n    /**\n     * Specifies the ground overlay's zIndex, i.e., the order in which it will be drawn. See the\n     * documentation at the top of this class for more information about zIndex.\n     *\n     * @return this {@link GroundOverlayOptions} object with a new zIndex set.\n     */\n    public GroundOverlayOptions zIndex(float zIndex) {\n        this.zIndex = zIndex;\n        return this;\n    }\n\n    public static Creator<GroundOverlayOptions> CREATOR = new AutoCreator<GroundOverlayOptions>(GroundOverlayOptions.class);\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/model/JointType.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.maps.model;\n\n/**\n * Joint types for Polyline and outline of Polygon.\n */\npublic final class JointType {\n    /**\n     * Default: Mitered joint, with fixed pointed extrusion equal to half the stroke width on the outside of the joint.\n     */\n    public static final int DEFAULT = 0;\n    /**\n     * Flat bevel on the outside of the joint.\n     */\n    public static final int BEVEL = 1;\n    /**\n     * Rounded on the outside of the joint by an arc of radius equal to half the stroke width, centered at the vertex.\n     */\n    public static final int ROUND = 2;\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/model/LatLng.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.maps.model;\n\nimport android.os.Parcel;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.PublicApi;\n\n/**\n * An immutable class representing a pair of latitude and longitude coordinates, stored as degrees.\n */\n@PublicApi\n@SafeParcelable.Class\npublic final class LatLng extends AbstractSafeParcelable {\n    @Field(1)\n    int versionCode = 1;\n    /**\n     * Latitude, in degrees. This value is in the range [-90, 90].\n     */\n    @Field(2)\n    public final double latitude;\n    /**\n     * Longitude, in degrees. This value is in the range [-180, 180).\n     */\n    @Field(3)\n    public final double longitude;\n\n    /**\n     * This constructor is dirty setting the final fields to make the compiler happy.\n     * In fact, those are replaced by their real values later using SafeParcelUtil.\n     */\n    private LatLng() {\n        latitude = longitude = 0;\n    }\n\n    @Constructor\n    LatLng(@Param(1) int versionCode, @Param(2) double latitude, @Param(3) double longitude) {\n        this.versionCode = versionCode;\n        this.latitude = latitude;\n        this.longitude = longitude;\n    }\n\n    /**\n     * Constructs a LatLng with the given latitude and longitude, measured in degrees.\n     *\n     * @param latitude  The point's latitude. This will be clamped to between -90 degrees and\n     *                  +90 degrees inclusive.\n     * @param longitude The point's longitude. This will be normalized to be within -180 degrees\n     *                  inclusive and +180 degrees exclusive.\n     */\n    public LatLng(double latitude, double longitude) {\n        this.latitude = Math.max(-90, Math.min(90, latitude));\n        if ((-180 <= longitude) && (longitude < 180)) {\n            this.longitude = longitude;\n        } else {\n            this.longitude = ((360 + (longitude - 180) % 360) % 360 - 180);\n        }\n    }\n\n    /**\n     * Tests if this LatLng is equal to another.\n     * <p/>\n     * Two points are considered equal if and only if their latitudes are bitwise equal and their\n     * longitudes are bitwise equal. This means that two {@link LatLng}s that are very near, in\n     * terms of geometric distance, might not be considered {@code .equal()}.\n     */\n    @Override\n    public boolean equals(Object o) {\n        if (this == o)\n            return true;\n        if (o == null || getClass() != o.getClass())\n            return false;\n\n        LatLng latLng = (LatLng) o;\n\n        if (Double.compare(latLng.latitude, latitude) != 0)\n            return false;\n        if (Double.compare(latLng.longitude, longitude) != 0)\n            return false;\n\n        return true;\n    }\n\n    @Override\n    public final int hashCode() {\n        long tmp1 = Double.doubleToLongBits(latitude);\n        int tmp2 = 31 + (int) (tmp1 ^ tmp1 >>> 32);\n        tmp1 = Double.doubleToLongBits(longitude);\n        return tmp2 * 31 + (int) (tmp1 ^ tmp1 >>> 32);\n    }\n\n    @Override\n    public String toString() {\n        return \"lat/lng: (\" + latitude + \",\" + longitude + \")\";\n    }\n\n    @Override\n    public void writeToParcel(Parcel out, int flags) {\n        CREATOR.writeToParcel(this, out, flags);\n    }\n\n    public static SafeParcelableCreatorAndWriter<LatLng> CREATOR = findCreator(LatLng.class);\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/model/LatLngBounds.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.maps.model;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\nimport java.util.Arrays;\n\n/**\n * An immutable class representing a latitude/longitude aligned rectangle.\n */\n@PublicApi\npublic final class LatLngBounds extends AutoSafeParcelable {\n    @SafeParceled(1)\n    private int versionCode = 1;\n    /**\n     * Southwest corner of the bound.\n     */\n    @SafeParceled(2)\n    public final LatLng southwest;\n    /**\n     * Northeast corner of the bound.\n     */\n    @SafeParceled(3)\n    public final LatLng northeast;\n\n    /**\n     * This constructor is dirty setting the final fields to make the compiler happy.\n     * In fact, those are replaced by their real values later using SafeParcelUtil.\n     */\n    private LatLngBounds() {\n        southwest = northeast = null;\n    }\n\n    /**\n     * Creates a new bounds based on a southwest and a northeast corner.\n     * <p/>\n     * The bounds conceptually includes all points where:\n     * <ul>\n     * <li>the latitude is in the range [northeast.latitude, southwest.latitude];</li>\n     * <li>the longitude is in the range [southwest.longtitude, northeast.longitude]\n     * if southwest.longtitude ≤ northeast.longitude; and</li>\n     * <li>the longitude is in the range [southwest.longitude, 180) ∪ [-180, northeast.longitude]\n     * if southwest.longtitude > northeast.longitude.</li>\n     * </ul>\n     *\n     * @param southwest southwest corner\n     * @param northeast northeast corner\n     * @throws IllegalArgumentException if the latitude of the northeast corner is below the\n     *                                  latitude of the southwest corner.\n     */\n    public LatLngBounds(LatLng southwest, LatLng northeast) throws IllegalArgumentException {\n        if (northeast.latitude < southwest.latitude)\n            throw new IllegalArgumentException(\"latitude of northeast corner must not be\" +\n                    \" lower than latitude of southwest corner\");\n        this.southwest = southwest;\n        this.northeast = northeast;\n    }\n\n    /**\n     * Creates a new builder.\n     */\n    public Builder builder() {\n        return new Builder();\n    }\n\n    /**\n     * Returns whether this contains the given {@link LatLng}.\n     *\n     * @param point the {@link LatLng} to test\n     * @return {@code true} if this contains the given point; {@code false} if not.\n     */\n    public boolean contains(LatLng point) {\n        return containsLatitude(point.latitude) && containsLongitude(point.longitude);\n    }\n\n    private boolean containsLatitude(double latitude) {\n        return southwest.latitude <= latitude && latitude <= northeast.latitude;\n    }\n\n    private boolean containsLongitude(double longitude) {\n        return southwest.longitude <= northeast.longitude ? (\n                southwest.longitude <= longitude && longitude <= northeast.longitude\n        ) : (\n                southwest.longitude >= longitude && longitude < 180 ||\n                        longitude >= -180 && longitude <= northeast.longitude\n        );\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o)\n            return true;\n        if (o == null || getClass() != o.getClass())\n            return false;\n\n        LatLngBounds that = (LatLngBounds) o;\n\n        if (!northeast.equals(that.northeast))\n            return false;\n        if (!southwest.equals(that.southwest))\n            return false;\n\n        return true;\n    }\n\n    /**\n     * Returns the center of this {@link LatLngBounds}. The center is simply the average of the\n     * coordinates (taking into account if it crosses the antimeridian). This is approximately the\n     * geographical center (it would be exact if the Earth were a perfect sphere). It will not\n     * necessarily be the center of the rectangle as drawn on the map due to the Mercator\n     * projection.\n     *\n     * @return A {@link LatLng} that is the center of the {@link LatLngBounds}.\n     */\n    public LatLng getCenter() {\n        double lat = (southwest.latitude + northeast.latitude) / 2.0;\n        double lon = (southwest.longitude + northeast.longitude) / 2.0 +\n                southwest.longitude <= northeast.latitude ? 0 : 180.0;\n        return new LatLng(lat, lon);\n    }\n\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(new Object[] { southwest, northeast });\n    }\n\n    /**\n     * Returns a new {@link LatLngBounds} that extends this {@link LatLngBounds} to include the\n     * given {@link LatLng}. This will return the smallest LatLngBounds that contains both this\n     * and the extra point.\n     * <p/>\n     * In particular, it will consider extending the bounds both in the eastward and westward\n     * directions (one of which may cross the antimeridian) and choose the smaller of the two. In\n     * the case that both directions result in a LatLngBounds of the same size, this will extend\n     * it in the eastward direction.\n     *\n     * @param point a {@link LatLng} to be included in the new bounds\n     * @return A new {@link LatLngBounds} that contains this and the extra point.\n     */\n    public LatLngBounds including(LatLng point) {\n        double latMin = Math.min(southwest.latitude, point.latitude);\n        double latMax = Math.max(northeast.latitude, point.latitude);\n        double lonMin = southwest.longitude;\n        double lonMax = northeast.longitude;\n        if (!containsLongitude(point.longitude)) {\n            if ((southwest.longitude - point.longitude + 360.0) % 360.0 <\n                    (point.longitude - northeast.longitude + 360.0D) % 360.0D) {\n                lonMin = point.longitude;\n            } else {\n                lonMax = point.longitude;\n            }\n        }\n        return new LatLngBounds(new LatLng(latMin, lonMin), new LatLng(latMax, lonMax));\n    }\n\n    @Override\n    public String toString() {\n        return \"LatLngBounds{\" +\n                \"southwest=\" + southwest +\n                \", northeast=\" + northeast +\n                '}';\n    }\n\n    public static Creator<LatLngBounds> CREATOR = new AutoCreator<LatLngBounds>(LatLngBounds.class);\n\n    /**\n     * This is a builder that is able to create a minimum bound based on a set of LatLng points.\n     */\n    public static final class Builder {\n        private LatLngBounds bounds;\n\n        public Builder() {\n\n        }\n\n        /**\n         * Creates the LatLng bounds.\n         *\n         * @throws IllegalStateException if no points have been included.\n         */\n        public LatLngBounds build() throws IllegalStateException {\n            if (bounds == null)\n                throw new IllegalStateException(\n                        \"You must not call build() before adding points to the Builder\");\n            return bounds;\n        }\n\n        /**\n         * Includes this point for building of the bounds. The bounds will be extended in a\n         * minimum way to include this point.\n         * <p/>\n         * More precisely, it will consider extending the bounds both in the eastward and westward\n         * directions (one of which may cross the antimeridian) and choose the smaller of the two.\n         * In the case that both directions result in a LatLngBounds of the same size, this will\n         * extend it in the eastward direction. For example, adding points (0, -179) and (1, 179)\n         * will create a bound crossing the 180 longitude.\n         *\n         * @param point A {@link LatLng} to be included in the bounds.\n         * @return This builder object with a new point added.\n         */\n        public Builder include(LatLng point) {\n            if (bounds == null) {\n                bounds = new LatLngBounds(point, point);\n            } else {\n                bounds = bounds.including(point);\n            }\n            return this;\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/model/MapStyleOptions.java",
    "content": "/*\n * Copyright (C) 2020 e Foundation\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 com.google.android.gms.maps.model;\n\nimport android.os.IBinder;\nimport com.google.android.gms.dynamic.ObjectWrapper;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\n@PublicApi\npublic class MapStyleOptions extends AutoSafeParcelable {\n\n    @SafeParceled(1)\n    private int versionCode = 1;\n    @SafeParceled(2)\n    private String json;\n\n    public MapStyleOptions() {\n    }\n\n    public MapStyleOptions (String json) {\n        this.json = json;\n    }\n\n    public String getJson() {\n        return this.json;\n    }\n\n    public static Creator<MapStyleOptions> CREATOR = new AutoCreator<MapStyleOptions>(MapStyleOptions.class);\n\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/model/MarkerOptions.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.maps.model;\n\nimport android.os.IBinder;\nimport com.google.android.gms.dynamic.ObjectWrapper;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\n@PublicApi\npublic class MarkerOptions extends AutoSafeParcelable {\n\n    @SafeParceled(1)\n    private int versionCode = 1;\n    @SafeParceled(2)\n    private LatLng position;\n    @SafeParceled(3)\n    private String title;\n    @SafeParceled(4)\n    private String snippet;\n    /**\n     * This is a IBinder to the remote BitmapDescriptor created using BitmapDescriptorFactory\n     */\n    @SafeParceled(5)\n    private IBinder iconBinder;\n    private BitmapDescriptor icon;\n    @SafeParceled(6)\n    private float anchorU = 0.5F;\n    @SafeParceled(7)\n    private float anchorV = 1F;\n    @SafeParceled(8)\n    private boolean draggable;\n    @SafeParceled(9)\n    private boolean visible;\n    @SafeParceled(10)\n    private boolean flat;\n    @SafeParceled(11)\n    private float rotation = 0F;\n    @SafeParceled(12)\n    private float infoWindowAnchorU = 0F;\n    @SafeParceled(13)\n    private float infoWindowAnchorV = 1F;\n    @SafeParceled(14)\n    private float alpha = 1F;\n    @SafeParceled(15)\n    private float zIndex = 0F;\n\n    /**\n     * Creates a new set of marker options.\n     */\n    public MarkerOptions() {\n    }\n\n    /**\n     * Sets the alpha (opacity) of the marker. This is a value from 0 to 1, where 0 means the\n     * marker is completely transparent and 1 means the marker is completely opaque.\n     *\n     * @return the object for which the method was called, with the new alpha set.\n     */\n    public MarkerOptions alpha(float alpha) {\n        this.alpha = alpha;\n        return this;\n    }\n\n    /**\n     * Specifies the anchor to be at a particular point in the marker image.\n     * <p/>\n     * The anchor specifies the point in the icon image that is anchored to the marker's position\n     * on the Earth's surface.\n     * <p/>\n     * The anchor point is specified in the continuous space [0.0, 1.0] x [0.0, 1.0], where (0, 0)\n     * is the top-left corner of the image, and (1, 1) is the bottom-right corner. The anchoring\n     * point in a W x H image is the nearest discrete grid point in a (W + 1) x (H + 1) grid,\n     * obtained by scaling the then rounding. For example, in a 4 x 2 image, the anchor point\n     * (0.7, 0.6) resolves to the grid point at (3, 1).\n     *\n     * @param u u-coordinate of the anchor, as a ratio of the image width (in the range [0, 1])\n     * @param v v-coordinate of the anchor, as a ratio of the image height (in the range [0, 1])\n     * @return the object for which the method was called, with the new anchor set.\n     */\n    public MarkerOptions anchor(float u, float v) {\n        this.anchorU = u;\n        this.anchorV = v;\n        return this;\n    }\n\n    /**\n     * Sets the draggability for the marker.\n     *\n     * @return the object for which the method was called, with the new draggable state set.\n     */\n    public MarkerOptions draggable(boolean draggable) {\n        this.draggable = draggable;\n        return this;\n    }\n\n    /**\n     * Sets whether this marker should be flat against the map true or a billboard facing the\n     * camera false. If the marker is flat against the map, it will remain stuck to the map as the\n     * camera rotates and tilts but will still remain the same size as the camera zooms, unlike a\n     * GroundOverlay. If the marker is a billboard, it will always be drawn facing the camera\n     * and will rotate and tilt with the camera. The default value is false.\n     *\n     * @return the object for which the method was called, with the new flat state set.\n     */\n    public MarkerOptions flat(boolean flat) {\n        this.flat = flat;\n        return this;\n    }\n\n    /**\n     * Gets the alpha set for this MarkerOptions object.\n     *\n     * @return the alpha of the marker in the range [0, 1].\n     */\n    public float getAlpha() {\n        return alpha;\n    }\n\n    /**\n     * Horizontal distance, normalized to [0, 1], of the anchor from the left edge.\n     *\n     * @return the u value of the anchor.\n     */\n    public float getAnchorU() {\n        return anchorU;\n    }\n\n    /**\n     * Vertical distance, normalized to [0, 1], of the anchor from the top edge.\n     *\n     * @return the v value of the anchor.\n     */\n    public float getAnchorV() {\n        return anchorV;\n    }\n\n    /**\n     * Gets the custom icon set for this MarkerOptions object.\n     *\n     * @return An {@link BitmapDescriptor} representing the custom icon, or {@code null} if no\n     * custom icon is set.\n     */\n    public BitmapDescriptor getIcon() {\n        if (icon == null && iconBinder != null) {\n            icon = new BitmapDescriptor(ObjectWrapper.asInterface(iconBinder));\n        }\n        return icon;\n    }\n\n    /**\n     * Horizontal distance, normalized to [0, 1], of the info window anchor from the left edge.\n     *\n     * @return the u value of the info window anchor.\n     */\n    public float getInfoWindowAnchorU() {\n        return infoWindowAnchorU;\n    }\n\n    /**\n     * Vertical distance, normalized to [0, 1], of the info window anchor from the top edge.\n     *\n     * @return the v value of the info window anchor.\n     */\n    public float getInfoWindowAnchorV() {\n        return infoWindowAnchorV;\n    }\n\n    /**\n     * Returns the position set for this MarkerOptions object.\n     *\n     * @return A {@link LatLng} object specifying the marker's current position.\n     */\n    public LatLng getPosition() {\n        return position;\n    }\n\n    /**\n     * Gets the rotation set for this MarkerOptions object.\n     *\n     * @return the rotation of the marker in degrees clockwise from the default position.\n     */\n    public float getRotation() {\n        return rotation;\n    }\n\n    /**\n     * Gets the snippet set for this MarkerOptions object.\n     *\n     * @return A string containing the marker's snippet.\n     */\n    public String getSnippet() {\n        return snippet;\n    }\n\n    /**\n     * Gets the title set for this MarkerOptions object.\n     *\n     * @return A string containing the marker's title.\n     */\n    public String getTitle() {\n        return title;\n    }\n\n    /**\n     * Sets the icon for the marker.\n     *\n     * @param icon if null, the default marker is used.\n     * @return the object for which the method was called, with the new icon set.\n     */\n    public MarkerOptions icon(BitmapDescriptor icon) {\n        this.icon = icon;\n        this.iconBinder = icon == null ? null : icon.getRemoteObject().asBinder();\n        return this;\n    }\n\n    /**\n     * Specifies the anchor point of the info window on the marker image. This is specified in the\n     * same coordinate system as the anchor. See {@link MarkerOptions#anchor(float, float)} for\n     * more details. The default is the top middle of the image.\n     *\n     * @param u u-coordinate of the info window anchor, as a ratio of the image width (in the range [0, 1])\n     * @param v v-coordinate of the info window anchor, as a ratio of the image height (in the range [0, 1])\n     * @return the object for which the method was called, with the new info window anchor set.\n     */\n    public MarkerOptions infoWindowAnchor(float u, float v) {\n        this.infoWindowAnchorU = u;\n        this.infoWindowAnchorV = v;\n        return this;\n    }\n\n    /**\n     * Gets the draggability setting for this MarkerOptions object.\n     *\n     * @return {@code true} if the marker is draggable; otherwise, returns {@code false}.\n     */\n    public boolean isDraggable() {\n        return draggable;\n    }\n\n    /**\n     * Gets the flat setting for this MarkerOptions object.\n     *\n     * @return {@code true} if the marker is flat against the map; {@code false} if the marker\n     * should face the camera.\n     */\n    public boolean isFlat() {\n        return flat;\n    }\n\n    /**\n     * Gets the visibility setting for this MarkerOptions object.\n     *\n     * @return {@code true} if the marker is visible; otherwise, returns {@code false}.\n     */\n    public boolean isVisible() {\n        return visible;\n    }\n\n    /**\n     * Sets the location for the marker.\n     *\n     * @return the object for which the method was called, with the new position set.\n     */\n    public MarkerOptions position(LatLng position) {\n        this.position = position;\n        return this;\n    }\n\n    /**\n     * Sets the rotation of the marker in degrees clockwise about the marker's anchor point. The\n     * axis of rotation is perpendicular to the marker. A rotation of 0 corresponds to the default\n     * position of the marker. When the marker is flat on the map, the default position is North\n     * aligned and the rotation is such that the marker always remains flat on the map. When the\n     * marker is a billboard, the default position is pointing up and the rotation is such that\n     * the marker is always facing the camera. The default value is 0.\n     *\n     * @return the object for which the method was called, with the new rotation set.\n     */\n    public MarkerOptions rotation(float rotation) {\n        this.rotation = rotation;\n        return this;\n    }\n\n    /**\n     * Sets the snippet for the marker.\n     *\n     * @return the object for which the method was called, with the new snippet set.\n     */\n    public MarkerOptions snippet(String snippet) {\n        this.snippet = snippet;\n        return this;\n    }\n\n    /**\n     * Sets the title for the marker.\n     *\n     * @return the object for which the method was called, with the new title set.\n     */\n    public MarkerOptions title(String title) {\n        this.title = title;\n        return this;\n    }\n\n    /**\n     * Sets the visibility for the marker.\n     *\n     * @return the object for which the method was called, with the new visibility state set.\n     */\n    public MarkerOptions visible(boolean visible) {\n        this.visible = visible;\n        return this;\n    }\n\n    public MarkerOptions zIndex(float zIndex) {\n        this.zIndex = zIndex;\n        return this;\n    }\n\n    public float getZIndex() {\n        return this.zIndex;\n    }\n\n    public static Creator<MarkerOptions> CREATOR = new AutoCreator<MarkerOptions>(MarkerOptions.class);\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/model/PatternItem.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.maps.model;\n\nimport android.os.Parcel;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n/**\n * Immutable item used in the stroke pattern for a Polyline or the outline of a Polygon or Circle.\n */\n@PublicApi\npublic class PatternItem extends AutoSafeParcelable {\n    @Field(2)\n    private int type;\n    @Field(3)\n    private Float length;\n\n    private PatternItem() {\n    }\n\n    @PublicApi(exclude = true)\n    PatternItem(int type, Float length) {\n        this.type = type;\n        this.length = length;\n    }\n\n    @Override\n    public String toString() {\n        return \"[PatternItem: type=\" + type + \" length=\" + length + \"]\";\n    }\n\n    public static final Creator<PatternItem> CREATOR = new AutoCreator<PatternItem>(PatternItem.class) {\n        @Override\n        public PatternItem createFromParcel(Parcel parcel) {\n            PatternItem item = super.createFromParcel(parcel);\n            switch (item.type) {\n                case 0:\n                    return new Dash(item.length);\n                case 1:\n                    return new Dot();\n                case 2:\n                    return new Gap(item.length);\n                default:\n                    return item;\n            }\n        }\n    };\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/model/PolygonOptions.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2015 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.maps.model;\n\nimport android.graphics.Color;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Defines options for a polygon.\n * <p>\n * For more information, read the <a href=\"https://developers.google.com/maps/documentation/android-sdk/shapes\">Shapes</a> developer guide.\n */\n@PublicApi\npublic class PolygonOptions extends AutoSafeParcelable {\n    @Field(1)\n    private int versionCode = 1;\n    @Field(value = 2, subClass = LatLng.class)\n    private List<LatLng> points = new ArrayList<LatLng>();\n    @Field(value = 3, subClass = LatLng.class, useValueParcel = true)\n    private List<List<LatLng>> holes = new ArrayList<List<LatLng>>();\n    @Field(4)\n    private float strokeWidth = 10;\n    @Field(5)\n    private int strokeColor = Color.BLACK;\n    @Field(6)\n    private int fillColor = Color.BLACK;\n    @Field(7)\n    private float zIndex = 0;\n    @Field(8)\n    private boolean visible = true;\n    @Field(9)\n    private boolean geodesic = false;\n    @Field(10)\n    private boolean clickable = false;\n    @Field(11)\n    private int strokeJointType = JointType.DEFAULT;\n    @Field(value = 12, subClass = PatternItem.class)\n    private List<PatternItem> strokePattern = null;\n\n    /**\n     * Creates polygon options.\n     */\n    public PolygonOptions() {\n    }\n\n    /**\n     * Adds vertices to the outline of the polygon being built.\n     *\n     * @param points an array of {@link LatLng}s that are added to the outline of the polygon. Must not be {@code null}.\n     * @return this {@link PolygonOptions} object with the given points added to the outline.\n     */\n    public PolygonOptions add(LatLng... points) {\n        for (LatLng point : points) {\n            this.points.add(point);\n        }\n        return this;\n    }\n\n    /**\n     * Adds a vertex to the outline of the polygon being built.\n     *\n     * @param point a {@link LatLng} that is added to the outline of the polygon. Must not be {@code null}.\n     * @return this {@link PolygonOptions} object with the given point added to the outline.\n     */\n    public PolygonOptions add(LatLng point) {\n        points.add(point);\n        return this;\n    }\n\n    /**\n     * Adds vertices to the outline of the polygon being built.\n     *\n     * @param points a list of {@link LatLng}s that are added to the outline of the polygon. Must not be {@code null}.\n     * @return this {@link PolygonOptions} object with the given points added to the outline.\n     */\n    public PolygonOptions add(Iterable<LatLng> points) {\n        for (LatLng point : points) {\n            this.points.add(point);\n        }\n        return this;\n    }\n\n    /**\n     * Adds a hole to the polygon being built.\n     *\n     * @param points an iterable of {@link LatLng}s that represents a hole. Must not be {@code null}.\n     * @return this {@link PolygonOptions} object with the given hole added.\n     */\n    public PolygonOptions addHole(Iterable<LatLng> points) {\n        ArrayList<LatLng> hole = new ArrayList<LatLng>();\n        for (LatLng point : points) {\n            hole.add(point);\n        }\n        holes.add(hole);\n        return this;\n    }\n\n    /**\n     * Specifies whether this polygon is clickable. The default setting is {@code false}\n     *\n     * @return this {@link PolygonOptions} object with a new clickability setting.\n     */\n    public PolygonOptions clickable(boolean clickable) {\n        this.clickable = clickable;\n        return this;\n    }\n\n    /**\n     * Specifies the polygon's fill color, as 32-bit ARGB. The default color is black ({@code 0xff000000}).\n     *\n     * @return this {@link PolygonOptions} object with a new fill color set.\n     */\n    public PolygonOptions fillColor(int color) {\n        this.fillColor = color;\n        return this;\n    }\n\n    /**\n     * Specifies whether to draw each segment of this polygon as a geodesic. The default setting is {@code false}\n     *\n     * @return this {@link PolygonOptions} object with a new geodesic setting.\n     */\n    public PolygonOptions geodesic(boolean geodesic) {\n        this.geodesic = geodesic;\n        return this;\n    }\n\n    /**\n     * Gets the fill color set for this {@link PolygonOptions} object.\n     *\n     * @return the fill color of the polygon in screen pixels.\n     */\n    public int getFillColor() {\n        return fillColor;\n    }\n\n    /**\n     * Gets the holes set for this {@link PolygonOptions} object.\n     *\n     * @return the list of {@code List<LatLng>}s specifying the holes of the polygon.\n     */\n    public List<List<LatLng>> getHoles() {\n        return holes;\n    }\n\n    /**\n     * Gets the outline set for this {@link PolygonOptions} object.\n     *\n     * @return the list of {@link LatLng}s specifying the vertices of the outline of the polygon.\n     */\n    public List<LatLng> getPoints() {\n        return points;\n    }\n\n    /**\n     * Gets the stroke color set for this {@link PolygonOptions} object.\n     *\n     * @return the stroke color of the polygon in screen pixels.\n     */\n    public int getStrokeColor() {\n        return strokeColor;\n    }\n\n    /**\n     * Gets the stroke joint type set in this {@link PolygonOptions} object for all vertices of the polygon's outline. See {@link JointType} for possible values.\n     *\n     * @return the stroke joint type of the polygon's outline.\n     */\n    public int getStrokeJointType() {\n        return strokeJointType;\n    }\n\n    /**\n     * Gets the stroke pattern set in this {@link PolygonOptions} object for the polygon's outline.\n     *\n     * @return the stroke pattern of the polygon's outline.\n     */\n    public List<PatternItem> getStrokePattern() {\n        return strokePattern;\n    }\n\n    /**\n     * Gets the stroke width set for this {@link PolygonOptions} object.\n     *\n     * @return the stroke width of the polygon in screen pixels.\n     */\n    public float getStrokeWidth() {\n        return strokeWidth;\n    }\n\n    /**\n     * Gets the zIndex set for this {@link PolygonOptions} object.\n     *\n     * @return the zIndex of the polygon.\n     */\n    public float getZIndex() {\n        return zIndex;\n    }\n\n    /**\n     * Gets the clickability setting for this {@link PolygonOptions} object.\n     *\n     * @return {@code true} if the polygon is clickable; {@code false} if it is not.\n     */\n    public boolean isClickable() {\n        return clickable;\n    }\n\n    /**\n     * Gets the geodesic setting for this {@link PolygonOptions} object.\n     *\n     * @return {@code true} if the polygon segments should be geodesics; {@code false} if they should not be.\n     */\n    public boolean isGeodesic() {\n        return geodesic;\n    }\n\n    /**\n     * Gets the visibility setting for this {@link PolygonOptions} object.\n     *\n     * @return {@code true} if the polygon is to be visible; {@code false} if it is not.\n     */\n    public boolean isVisible() {\n        return visible;\n    }\n\n    /**\n     * Specifies the polygon's stroke color, as 32-bit ARGB. The default color is black ({@code 0xff000000}).\n     *\n     * @return this {@link PolygonOptions} object with a new stroke color set.\n     */\n    public PolygonOptions strokeColor(int color) {\n        this.strokeColor = color;\n        return this;\n    }\n\n    /**\n     * Specifies the joint type for all vertices of the polygon's outline.\n     * <p>\n     * See {@link JointType} for allowed values. The default value {@link JointType#DEFAULT} will be used if joint type\n     * is undefined or is not one of the allowed values.\n     *\n     * @return this {@link PolygonOptions} object with a new stroke joint type set.\n     */\n    public PolygonOptions strokeJointType(int jointType) {\n        this.strokeJointType = jointType;\n        return this;\n    }\n\n    /**\n     * Specifies a stroke pattern for the polygon's outline. The default stroke pattern is solid, represented by {@code null}.\n     *\n     * @return this {@link PolygonOptions} object with a new stroke pattern set.\n     */\n    public PolygonOptions strokePattern(List<PatternItem> pattern) {\n        this.strokePattern = pattern;\n        return this;\n    }\n\n    /**\n     * Specifies the polygon's stroke width, in display pixels. The default width is 10.\n     *\n     * @return this {@link PolygonOptions} object with a new stroke width set.\n     */\n    public PolygonOptions strokeWidth(float width) {\n        this.strokeWidth = width;\n        return this;\n    }\n\n    /**\n     * Specifies the visibility for the polygon. The default visibility is true.\n     *\n     * @return this {@link PolygonOptions} object with a new visibility setting.\n     */\n    public PolygonOptions visible(boolean visible) {\n        this.visible = visible;\n        return this;\n    }\n\n    /**\n     * Specifies the polygon's zIndex, i.e., the order in which it will be drawn. See the documentation at the top of this class for more information about zIndex.\n     *\n     * @return this {@link PolygonOptions} object with a new zIndex set.\n     */\n    public PolygonOptions zIndex(float zIndex) {\n        this.zIndex = zIndex;\n        return this;\n    }\n\n    public static Creator<PolygonOptions> CREATOR = new AutoCreator<PolygonOptions>(PolygonOptions.class);\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/model/PolylineOptions.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2015 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.maps.model;\n\nimport android.graphics.Color;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\n/**\n * Defines options for a polyline.\n */\n@PublicApi\npublic class PolylineOptions extends AutoSafeParcelable {\n    @Field(1)\n    private int versionCode = 1;\n    @Field(value = 2, subClass = LatLng.class)\n    @NonNull\n    private List<LatLng> points = new ArrayList<>();\n    @Field(3)\n    private float width = 10.0f;\n    @Field(4)\n    private int color = Color.BLACK;\n    @Field(5)\n    private float zIndex = 0;\n    @Field(6)\n    private boolean visible = true;\n    @Field(7)\n    private boolean geodesic = false;\n    @Field(8)\n    private boolean clickable = false;\n    @Field(9)\n    @NonNull\n    private Cap startCap = new ButtCap();\n    @Field(10)\n    @NonNull\n    private Cap endCap = new ButtCap();\n    @Field(11)\n    private int jointType = JointType.DEFAULT;\n    @Field(value = 12, subClass = PatternItem.class)\n    @Nullable\n    private List<PatternItem> pattern = null;\n    @Field(value = 13, subClass = StyleSpan.class)\n    @NonNull\n    private List<StyleSpan> spans = new ArrayList<>();\n\n    /**\n     * Creates polyline options.\n     */\n    public PolylineOptions() {\n    }\n\n    /**\n     * Adds vertices to the end of the polyline being built.\n     *\n     * @param points an array of {@link LatLng}s that are added to the end of the polyline. Must not be {@code null}.\n     * @return this {@link PolylineOptions} object with the given points on the end.\n     */\n    public PolylineOptions add(LatLng... points) {\n        this.points.addAll(Arrays.asList(points));\n        return this;\n    }\n\n    /**\n     * Adds a vertex to the end of the polyline being built.\n     *\n     * @param point a {@link LatLng} that is added to the end of the polyline. Must not be {@code null}.\n     * @return this {@link PolylineOptions} object with the given point on the end.\n     */\n    public PolylineOptions add(LatLng point) {\n        points.add(point);\n        return this;\n    }\n\n    /**\n     * Adds vertices to the end of the polyline being built.\n     *\n     * @param points a list of {@link LatLng}s that are added to the end of the polyline. Must not be {@code null}.\n     * @return this {@link PolylineOptions} object with the given points on the end.\n     */\n    public PolylineOptions addAll(Iterable<LatLng> points) {\n        for (LatLng point : points) {\n            this.points.add(point);\n        }\n        return this;\n    }\n\n    /**\n     * Adds new style spans to the polyline being built.\n     *\n     * @param spans the style spans that will be added to the polyline.\n     * @return this {@link PolylineOptions} object with new style spans added.\n     */\n    public PolylineOptions addAllSpans(Iterable<StyleSpan> spans) {\n        for (StyleSpan span : spans) {\n            this.spans.add(span);\n        }\n        return this;\n    }\n\n    /**\n     * Adds a new style span to the polyline being built.\n     *\n     * @param span the style span that will be added to the polyline.\n     * @return this {@link PolylineOptions} object with new style span added.\n     */\n    public PolylineOptions addSpan(StyleSpan span) {\n        this.spans.add(span);\n        return this;\n    }\n\n    /**\n     * Adds new style spans to the polyline being built.\n     *\n     * @param spans the style spans that will be added to the polyline.\n     * @return this {@link PolylineOptions} object with new style spans added.\n     */\n    public PolylineOptions addSpan(StyleSpan... spans) {\n        this.spans.addAll(Arrays.asList(spans));\n        return this;\n    }\n\n    /**\n     * Specifies whether this polyline is clickable. The default setting is {@code false}\n     *\n     * @return this {@link PolylineOptions} object with a new clickability setting.\n     */\n    public PolylineOptions clickable(boolean clickable) {\n        this.clickable = clickable;\n        return this;\n    }\n\n    /**\n     * Sets the color of the polyline as a 32-bit ARGB color. The default color is black ({@code 0xff000000}).\n     *\n     * @return this {@link PolylineOptions} object with a new color set.\n     */\n    public PolylineOptions color(int color) {\n        this.color = color;\n        return this;\n    }\n\n    /**\n     * Sets the cap at the end vertex of the polyline. The default end cap is {@link ButtCap}.\n     *\n     * @return this {@link PolylineOptions} object with a new end cap set.\n     */\n    public PolylineOptions endCap(@NonNull Cap endCap) {\n        this.endCap = endCap;\n        return this;\n    }\n\n    /**\n     * Specifies whether to draw each segment of this polyline as a geodesic. The default setting is {@code false}\n     *\n     * @return this {@link PolylineOptions} object with a new geodesic setting.\n     */\n    public PolylineOptions geodesic(boolean geodesic) {\n        this.geodesic = geodesic;\n        return this;\n    }\n\n    /**\n     * Gets the color set for this {@link PolylineOptions} object.\n     *\n     * @return the color of the polyline in ARGB format.\n     */\n    public int getColor() {\n        return color;\n    }\n\n    /**\n     * Gets the cap set for the end vertex in this {@link PolylineOptions} object.\n     *\n     * @return the end cap of the polyline.\n     */\n    public Cap getEndCap() {\n        return endCap;\n    }\n\n    /**\n     * Gets the joint type set in this {@link PolylineOptions} object for all vertices except the start and end vertices.\n     * See {@link JointType} for possible values.\n     *\n     * @return the joint type of the polyline.\n     */\n    public int getJointType() {\n        return jointType;\n    }\n\n    /**\n     * Gets the stroke pattern set in this {@link PolylineOptions} object for the polyline.\n     *\n     * @return the stroke pattern of the polyline.\n     */\n    public List<PatternItem> getPattern() {\n        return pattern;\n    }\n\n    /**\n     * Gets the points set for this {@link PolylineOptions} object.\n     *\n     * @return the list of {@link LatLng}s specifying the vertices of the polyline.\n     */\n    public List<LatLng> getPoints() {\n        return points;\n    }\n\n    @Hide\n    public List<StyleSpan> getSpans() {\n        return spans;\n    }\n\n    /**\n     * Gets the cap set for the start vertex in this {@link PolylineOptions} object.\n     *\n     * @return the start cap of the polyline.\n     */\n    public Cap getStartCap() {\n        return startCap;\n    }\n\n    /**\n     * Gets the width set for this {@link PolylineOptions} object.\n     *\n     * @return the width of the polyline in screen pixels.\n     */\n    public float getWidth() {\n        return width;\n    }\n\n    /**\n     * Gets the zIndex set for this {@link PolylineOptions} object.\n     *\n     * @return the zIndex of the polyline.\n     */\n    public float getZIndex() {\n        return zIndex;\n    }\n\n    /**\n     * Gets the clickability setting for this {@link PolylineOptions} object.\n     *\n     * @return {@code true} if the polyline is clickable; {@code false} if it is not.\n     */\n    public boolean isClickable() {\n        return clickable;\n    }\n\n    /**\n     * Gets the geodesic setting for this {@link PolylineOptions} object.\n     *\n     * @return {@code true} if the polyline segments should be geodesics; {@code false} they should not be.\n     */\n    public boolean isGeodesic() {\n        return geodesic;\n    }\n\n    /**\n     * Gets the visibility setting for this {@link PolylineOptions} object.\n     *\n     * @return {@code true} if the polyline is visible; {@code false} if it is not.\n     */\n    public boolean isVisible() {\n        return visible;\n    }\n\n    /**\n     * Sets the joint type for all vertices of the polyline except the start and end vertices.\n     * <p>\n     * See {@link JointType} for allowed values. The default value {@link JointType#DEFAULT} will be used if joint type is undefined or is\n     * not one of the allowed values.\n     *\n     * @return this {@link PolylineOptions} object with a new joint type set.\n     */\n    public PolylineOptions jointType(int jointType) {\n        this.jointType = jointType;\n        return this;\n    }\n\n    /**\n     * Sets the stroke pattern for the polyline. The default stroke pattern is solid, represented by {@code null}.\n     *\n     * @return this {@link PolylineOptions} object with a new stroke pattern set.\n     */\n    public PolylineOptions pattern(@Nullable List<PatternItem> pattern) {\n        this.pattern = pattern;\n        return this;\n    }\n\n    /**\n     * Sets the cap at the start vertex of the polyline. The default start cap is {@link ButtCap}.\n     *\n     * @return this {@link PolylineOptions} object with a new start cap set.\n     */\n    public PolylineOptions startCap(@NonNull Cap startCap) {\n        this.startCap = startCap;\n        return this;\n    }\n\n    /**\n     * Specifies the visibility for the polyline. The default visibility is {@code true}.\n     *\n     * @return this {@link PolylineOptions} object with a new visibility setting.\n     */\n    public PolylineOptions visible(boolean visible) {\n        this.visible = visible;\n        return this;\n    }\n\n    /**\n     * Sets the width of the polyline in screen pixels. The default is {@code 10}.\n     *\n     * @return this {@link PolylineOptions} object with a new width set.\n     */\n    public PolylineOptions width(float width) {\n        this.width = width;\n        return this;\n    }\n\n    /**\n     * Specifies the polyline's zIndex, i.e., the order in which it will be drawn.\n     *\n     * @return this {@link PolylineOptions} object with a new zIndex set.\n     */\n    public PolylineOptions zIndex(float zIndex) {\n        this.zIndex = zIndex;\n        return this;\n    }\n\n    public static Creator<PolylineOptions> CREATOR = new AutoCreator<PolylineOptions>(PolylineOptions.class);\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/model/RoundCap.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.maps.model;\n\nimport androidx.annotation.NonNull;\n\n/**\n * Cap that is a semicircle with radius equal to half the stroke width, centered at the start or end vertex of a {@link Polyline} with solid stroke pattern.\n */\npublic class RoundCap extends Cap {\n    /**\n     * Constructs a {@code RoundCap}.\n     */\n    public RoundCap() {\n        super(2, null, null);\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return \"[RoundCap]\";\n    }\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/model/RuntimeRemoteException.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.maps.model;\n\nimport android.os.RemoteException;\nimport androidx.annotation.NonNull;\n\n/**\n * A RuntimeException wrapper for RemoteException. Thrown when normally there is something seriously wrong and there is no way to recover.\n */\npublic class RuntimeRemoteException extends RuntimeException {\n    public RuntimeRemoteException(@NonNull RemoteException e) {\n        super(e);\n    }\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/model/SquareCap.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.maps.model;\n\nimport androidx.annotation.NonNull;\n\n/**\n * Cap that is squared off after extending half the stroke width beyond the start or end vertex of a {@link Polyline} with solid stroke pattern.\n */\npublic class SquareCap extends Cap {\n    /**\n     * Constructs a {@code SquareCap}.\n     */\n    public SquareCap() {\n        super(1, null, null);\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return \"[SquareCap]\";\n    }\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/model/StampStyle.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.maps.model;\n\nimport android.os.IBinder;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class StampStyle extends AutoSafeParcelable {\n    @Field(2)\n    private IBinder stamp;\n    private BitmapDescriptor stampDescriptor;\n\n    public static final Creator<StampStyle> CREATOR = new AutoCreator<>(StampStyle.class);\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/model/StreetViewPanoramaCamera.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2015 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.maps.model;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.Objects;\n\n/**\n * An immutable class that aggregates all camera position parameters.\n */\n@SafeParcelable.Class\npublic class StreetViewPanoramaCamera extends AbstractSafeParcelable {\n\n    /**\n     * Zoom level near the centre of the screen. See {@link StreetViewPanoramaCamera.Builder#zoom} for the definition of the camera's zoom level.\n     */\n    @Field(2)\n    public final float zoom;\n\n    /**\n     * The angle, in degrees, of the camera from the horizon of the panorama. See {@link StreetViewPanoramaCamera.Builder#tilt} for details of\n     * restrictions on the range of values.\n     */\n    @Field(3)\n    public final float tilt;\n\n    /**\n     * Direction that the camera is pointing in, in degrees clockwise from north.\n     */\n    @Field(4)\n    public final float bearing;\n\n    /**\n     * Constructs a StreetViewPanoramaCamera.\n     *\n     * @param zoom    Zoom level of the camera to the panorama. See {@link StreetViewPanoramaCamera.Builder#zoom} for details of restrictions.\n     * @param tilt    The camera angle, in degrees, from the horizon of the panorama. See {@link StreetViewPanoramaCamera.Builder#tilt} for details of restrictions.\n     * @param bearing Direction that the camera is pointing in, in degrees clockwise from north. This value will be normalized to be within 0 degrees inclusive and 360\n     *                degrees exclusive.\n     * @throws IllegalArgumentException if {@code tilt} is outside the range of -90 to 90 degrees inclusive.\n     */\n    @Constructor\n    public StreetViewPanoramaCamera(@Param(2) float zoom, @Param(3) float tilt, @Param(4) float bearing) throws IllegalArgumentException {\n        if (tilt < -90.0f || tilt > 90.0f) throw new IllegalArgumentException();\n        this.zoom = zoom;\n        this.tilt = tilt;\n        this.bearing = (bearing < 0.0f ? (bearing % 360.0f) + 360.0f : bearing) % 360.0f;\n    }\n\n    /**\n     * Creates a builder for a Street View panorama camera.\n     */\n    @NonNull\n    public static Builder builder() {\n        return new Builder();\n    }\n\n    /**\n     * Creates a builder for a Street View panorama camera.\n     *\n     * @param camera The camera that will be set to the builder. Must not be {@code null}.\n     */\n    @NonNull\n    public static Builder builder(@NonNull StreetViewPanoramaCamera camera) {\n        return new Builder(camera);\n    }\n\n    @Override\n    public final boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof StreetViewPanoramaCamera)) return false;\n\n        StreetViewPanoramaCamera that = (StreetViewPanoramaCamera) o;\n        return zoom == that.zoom && tilt == that.tilt && bearing == that.bearing;\n    }\n\n    /**\n     * Returns the particular camera's tilt and bearing as an orientation\n     *\n     * @return orientation Tilt and bearing of the camera\n     */\n    @NonNull\n    public StreetViewPanoramaOrientation getOrientation() {\n        return new StreetViewPanoramaOrientation(tilt, bearing);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hashCode(new Object[]{this.zoom, this.tilt, this.bearing});\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"StreetViewPanoramaCamera\")\n                .field(\"zoom\", zoom)\n                .field(\"tilt\", tilt)\n                .field(\"bearing\", bearing)\n                .end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<StreetViewPanoramaCamera> CREATOR = findCreator(StreetViewPanoramaCamera.class);\n\n    /**\n     * Builds panorama cameras.\n     */\n    public static class Builder {\n        public float zoom;\n        public float tilt;\n        public float bearing;\n\n        /**\n         * Creates an empty builder.\n         */\n        public Builder() {\n        }\n\n        /**\n         * Creates a builder with an existing {@link StreetViewPanoramaCamera}.\n         *\n         * @param camera The existing camera to initialize the builder. Must not be {@code null}.\n         */\n        public Builder(StreetViewPanoramaCamera camera) {\n            this.zoom = camera.zoom;\n            this.tilt = camera.tilt;\n            this.bearing = camera.bearing;\n        }\n\n        /**\n         * Sets the direction that the camera is pointing in, in degrees clockwise from north.\n         */\n        @NonNull\n        public Builder bearing(float bearing) {\n            this.bearing = bearing;\n            return this;\n        }\n\n        /**\n         * Sets the camera tilt and bearing based upon the given orientation's tilt and bearing.\n         *\n         * @param orientation The orientation to be set for the builder. Must not be {@code null}.\n         */\n        @NonNull\n        public Builder orientation(@NonNull StreetViewPanoramaOrientation orientation) {\n            this.tilt = orientation.tilt;\n            this.bearing = orientation.bearing;\n            return this;\n        }\n\n        /**\n         * Sets the angle, in degrees, of the camera from the horizon of the panorama. This value is restricted to being between -90 (directly down) and\n         * 90 (directly up).\n         */\n        @NonNull\n        public Builder tilt(float tilt) {\n            this.tilt = tilt;\n            return this;\n        }\n\n        /**\n         * Sets the zoom level of the camera. The original zoom level is set at 0. A zoom of 1 would double the magnification. The zoom is clamped\n         * between 0 and the maximum zoom level. The maximum zoom level can vary based upon the panorama. Clamped means that any value\n         * falling outside this range will be set to the closest extreme that falls within the range. For example, a value of -1 will be set to 0. Another\n         * example: If the maximum zoom for the panorama is 19, and the value is given as 20, it will be set to 19. Note that the camera zoom need not\n         * be an integer value.\n         */\n        @NonNull\n        public Builder zoom(float zoom) {\n            this.zoom = zoom;\n            return this;\n        }\n\n        /**\n         * Builds a {@link StreetViewPanoramaCamera}.\n         */\n        public StreetViewPanoramaCamera build() {\n            return new StreetViewPanoramaCamera(zoom, tilt, bearing);\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/model/StreetViewPanoramaLink.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2015 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.maps.model;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.Objects;\n\n/**\n * An immutable class that represents a link to another Street View panorama.\n */\n@SafeParcelable.Class\npublic class StreetViewPanoramaLink extends AbstractSafeParcelable {\n    /**\n     * Panorama ID of the linked Street View panorama\n     */\n    @NonNull\n    @Field(2)\n    public final String panoId;\n    /**\n     * The direction of the linked Street View panorama, in degrees clockwise from north\n     */\n    @Field(3)\n    public final float bearing;\n\n    @Constructor\n    StreetViewPanoramaLink(@NonNull @Param(2) String panoId, @Param(3) float bearing) {\n        this.panoId = panoId;\n        this.bearing = (bearing < 0.0f ? (bearing % 360.0f) + 360.0f : bearing) % 360.0f;\n    }\n\n    @Override\n    public final boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof StreetViewPanoramaLink)) return false;\n\n        StreetViewPanoramaLink that = (StreetViewPanoramaLink) o;\n        return bearing == that.bearing && panoId.equals(that.panoId);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hashCode(new Object[]{this.panoId, this.bearing});\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"StreetViewPanoramaLink\")\n                .field(\"panoId\", panoId)\n                .field(\"bearing\", bearing)\n                .end();\n    }\n\n    public static final SafeParcelableCreatorAndWriter<StreetViewPanoramaLink> CREATOR = findCreator(StreetViewPanoramaLink.class);\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/model/StreetViewPanoramaLocation.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2015 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.maps.model;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.Objects;\n\n/**\n * An immutable class that contains details of the user's current Street View panorama\n */\n@SafeParcelable.Class\npublic class StreetViewPanoramaLocation extends AbstractSafeParcelable {\n    /**\n     * Array of {@link StreetViewPanoramaLink} able to be reached from the current position\n     */\n    @NonNull\n    @Field(2)\n    public final StreetViewPanoramaLink[] links;\n    /**\n     * The location of the current Street View panorama\n     */\n    @NonNull\n    @Field(3)\n    public final LatLng position;\n    /**\n     * The panorama ID of the current Street View panorama\n     */\n    @NonNull\n    @Field(4)\n    public final String panoId;\n\n    /**\n     * Constructs a StreetViewPanoramaLocation.\n     *\n     * @param links    List of {@link StreetViewPanoramaLink} reachable from the current position. Must not be {@code null}.\n     * @param position The location of the current Street View panorama. Must not be {@code null}.\n     * @param panoId   Identification string for the current Street View panorama. Must not be {@code null}.\n     */\n    @Constructor\n    public StreetViewPanoramaLocation(@NonNull @Param(2) StreetViewPanoramaLink[] links, @NonNull @Param(3) LatLng position, @NonNull @Param(4) String panoId) {\n        this.links = links;\n        this.position = position;\n        this.panoId = panoId;\n    }\n\n    @Override\n    public final boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof StreetViewPanoramaLocation)) return false;\n\n        StreetViewPanoramaLocation that = (StreetViewPanoramaLocation) o;\n        return position.equals(that.position) && panoId.equals(that.panoId);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hashCode(new Object[]{this.position, this.panoId});\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"StreetViewPanoramaLocation\")\n                .field(\"panoId\", panoId)\n                .field(\"position\", position)\n                .end();\n    }\n\n    public static final SafeParcelableCreatorAndWriter<StreetViewPanoramaLocation> CREATOR = findCreator(StreetViewPanoramaLocation.class);\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/model/StreetViewPanoramaOrientation.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2015 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.maps.model;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.Objects;\n\n/**\n * An immutable class that aggregates all user point of view parameters.\n */\n@SafeParcelable.Class\npublic class StreetViewPanoramaOrientation extends AbstractSafeParcelable {\n\n    /**\n     * The angle, in degrees, of the orientation. See {@link StreetViewPanoramaOrientation.Builder#tilt} for details of restrictions on the range of\n     * values.\n     */\n    @Field(2)\n    public final float tilt;\n    /**\n     * Direction of the orientation, in degrees clockwise from north.\n     */\n    @Field(3)\n    public final float bearing;\n\n    /**\n     * Constructs a StreetViewPanoramaOrientation.\n     *\n     * @param tilt    The angle, in degrees, of the orientation. See {@link StreetViewPanoramaOrientation.Builder#tilt} for details of restrictions.\n     * @param bearing Direction of the orientation, in degrees clockwise from north. This value will be normalized to be within 0 degrees inclusive and 360 degrees\n     *                exclusive.\n     * @throws IllegalArgumentException if {@code tilt} is outside the range of -90 to 90 degrees inclusive.\n     */\n    @Constructor\n    public StreetViewPanoramaOrientation(@Param(2) float tilt, @Param(3) float bearing) throws IllegalArgumentException {\n        if (tilt < -90.0f || tilt > 90.0f) throw new IllegalArgumentException();\n        this.tilt = tilt;\n        this.bearing = (bearing < 0.0f ? (bearing % 360.0f) + 360.0f : bearing) % 360.0f;\n    }\n\n    /**\n     * Creates a builder for a Street View panorama orientation.\n     */\n    @NonNull\n    public static Builder builder() {\n        return new Builder();\n    }\n\n    /**\n     * Creates a builder for a Street View panorama orientation\n     *\n     * @param orientation must not be {@code null}.\n     */\n    @NonNull\n    public static Builder builder(@NonNull StreetViewPanoramaOrientation orientation) {\n        return new Builder(orientation);\n    }\n\n    @Override\n    public final boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof StreetViewPanoramaOrientation)) return false;\n\n        StreetViewPanoramaOrientation that = (StreetViewPanoramaOrientation) o;\n        return tilt == that.tilt && bearing == that.bearing;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hashCode(new Object[]{this.tilt, this.bearing});\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"StreetViewPanoramaOrientation\")\n                .field(\"tilt\", tilt)\n                .field(\"bearing\", bearing)\n                .end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<StreetViewPanoramaOrientation> CREATOR = findCreator(StreetViewPanoramaOrientation.class);\n\n    /**\n     * Builds Street View panorama orientations.\n     */\n    public static final class Builder {\n        public float bearing;\n        public float tilt;\n\n        /**\n         * Creates an empty builder.\n         */\n        public Builder() {\n        }\n\n        /**\n         * Creates a builder with an existing {@link StreetViewPanoramaOrientation}.\n         *\n         * @param previous The existing orientation to initialize the builder with. Must not be {@code null}.\n         */\n        public Builder(@NonNull StreetViewPanoramaOrientation previous) {\n            this.bearing = previous.bearing;\n            this.tilt = previous.tilt;\n        }\n\n        /**\n         * Sets the direction of the orientation, in degrees clockwise from north.\n         */\n        @NonNull\n        public Builder bearing(float bearing) {\n            this.bearing = bearing;\n            return this;\n        }\n\n        /**\n         * Sets the angle, in degrees, of the orientation This value is restricted to being between -90 (directly down) and 90 (directly up).\n         */\n        @NonNull\n        public Builder tilt(float tilt) {\n            this.tilt = tilt;\n            return this;\n        }\n\n        /**\n         * Builds a {@link StreetViewPanoramaOrientation}.\n         */\n        @NonNull\n        public StreetViewPanoramaOrientation build() {\n            return new StreetViewPanoramaOrientation(this.tilt, this.bearing);\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/model/StreetViewSource.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.maps.model;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.maps.StreetViewPanorama;\nimport com.google.android.gms.maps.StreetViewPanoramaOptions;\n\n/**\n * Identifiers to limit Street View searches to selected sources. See {@link StreetViewPanorama#setPosition(LatLng, StreetViewSource)},\n * {@link StreetViewPanorama#setPosition(LatLng, int, StreetViewSource)}, {@link StreetViewPanoramaOptions#position(LatLng, Integer, StreetViewSource)} or\n * {@link StreetViewPanoramaOptions#position(LatLng, StreetViewSource)}.\n */\n@SafeParcelable.Class\npublic class StreetViewSource extends AbstractSafeParcelable {\n\n    /**\n     * Default: Uses the default sources of Street View, searches will not be limited to specific sources.\n     */\n    public static final StreetViewSource DEFAULT = new StreetViewSource(0);\n    /**\n     * Limits Street View searches to outdoor collections. Indoor collections are not included in search results. Note also that the search only\n     * returns panoramas where it's possible to determine whether they're indoors or outdoors. For example, photo spheres are not returned\n     * because it's unknown whether they are indoors or outdoors.\n     */\n    public static final StreetViewSource OUTDOOR = new StreetViewSource(1);\n\n    @Field(2)\n    final int type;\n\n    @Constructor\n    StreetViewSource(@Param(2) int type) {\n        this.type = type;\n    }\n\n    @Override\n    public final boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof StreetViewSource)) return false;\n\n        StreetViewSource that = (StreetViewSource) o;\n        return type == that.type;\n    }\n\n    @Override\n    public int hashCode() {\n        return type;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        switch (type) {\n            case 0:\n                return \"StreetViewSource:DEFAULT\";\n            case 1:\n                return \"StreetViewSource:OUTDOOR\";\n            default:\n                return \"StreetViewSource:UNKNOWN(\" + type + \")\";\n        }\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<StreetViewSource> CREATOR = findCreator(StreetViewSource.class);\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/model/StrokeStyle.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.maps.model;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class StrokeStyle extends AutoSafeParcelable {\n    @Field(2)\n    private float width;\n    @Field(3)\n    private int color;\n    @Field(4)\n    private int toColor;\n    @Field(5)\n    private boolean isVisible;\n    @Field(6)\n    private StampStyle stamp;\n\n    public static final Creator<StrokeStyle> CREATOR = new AutoCreator<>(StrokeStyle.class);\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/model/StyleSpan.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.maps.model;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class StyleSpan extends AutoSafeParcelable {\n    @Field(2)\n    private StrokeStyle style;\n    @Field(3)\n    private double segments;\n\n    public double getSegments() {\n        return segments;\n    }\n\n    public StrokeStyle getStyle() {\n        return style;\n    }\n\n    public static final Creator<StyleSpan> CREATOR = new AutoCreator<>(StyleSpan.class);\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/model/Tile.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.maps.model;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\n/**\n * Contains information about a Tile that is returned by a {@link TileProvider}.\n * TODO SafeParceled\n */\n@PublicApi\npublic class Tile extends AutoSafeParcelable {\n    @SafeParceled(1)\n    private int versionCode = 1;\n    /**\n     * The width of the image encoded by {@link #data} in pixels.\n     */\n    @SafeParceled(2)\n    public final int width;\n    /**\n     * The height of the image encoded by {@link #data} in pixels.\n     */\n    @SafeParceled(3)\n    public final int height;\n    /**\n     * A byte array containing the image data. The image will be created from this data by calling\n     * {@link android.graphics.BitmapFactory#decodeByteArray(byte[], int, int)}.\n     */\n    @SafeParceled(4)\n    public final byte[] data;\n\n    private Tile() {\n        width = height = 0;\n        data = null;\n    }\n\n    /**\n     * Constructs a {@link Tile}.\n     *\n     * @param width  the width of the image in pixels\n     * @param height the height of the image in pixels\n     * @param data   A byte array containing the image data. The image will be created from this\n     *               data by calling\n     *               {@link android.graphics.BitmapFactory#decodeByteArray(byte[], int, int)}.\n     */\n    public Tile(int width, int height, byte[] data) {\n        this.width = width;\n        this.height = height;\n        this.data = data;\n    }\n\n    public static Creator<Tile> CREATOR = new AutoCreator<Tile>(Tile.class);\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/model/TileOverlayOptions.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2015 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.maps.model;\n\nimport android.os.IBinder;\nimport android.os.RemoteException;\n\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.maps.model.internal.ITileProviderDelegate;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n/**\n * Defines options for a TileOverlay.\n */\n@PublicApi\npublic class TileOverlayOptions extends AutoSafeParcelable {\n\n    @Field(1)\n    private int versionCode = 1;\n    /**\n     * This is a IBinder to the {@link #tileProvider}, built using {@link ITileProviderDelegate}.\n     */\n    @Field(2)\n    private IBinder tileProviderBinder;\n    private TileProvider tileProvider;\n    @Field(3)\n    private boolean visible = true;\n    @Field(4)\n    private float zIndex;\n    @Field(5)\n    private boolean fadeIn = true;\n    @Field(6)\n    private float transparency = 0.0f;\n\n    /**\n     * Creates a new set of tile overlay options.\n     */\n    public TileOverlayOptions() {\n    }\n\n    /**\n     * Specifies whether the tiles should fade in. The default is {@code true}.\n     *\n     * @return this {@link TileOverlayOptions} object with a new fadeIn setting.\n     */\n    public TileOverlayOptions fadeIn(boolean fadeIn) {\n        this.fadeIn = fadeIn;\n        return this;\n    }\n\n    /**\n     * Gets whether the tiles should fade in.\n     *\n     * @return {@code true} if the tiles are to fade in; {@code false} if it is not.\n     */\n    public boolean getFadeIn() {\n        return fadeIn;\n    }\n\n    /**\n     * Gets the tile provider set for this {@link TileOverlayOptions} object.\n     *\n     * @return the {@link TileProvider} of the tile overlay.\n     */\n    public TileProvider getTileProvider() {\n        if (tileProvider == null && tileProviderBinder != null) {\n            ITileProviderDelegate delegate = ITileProviderDelegate.Stub.asInterface(tileProviderBinder);\n            this.tileProvider = new TileProvider() {\n                @Override\n                public Tile getTile(int x, int y, int zoom) {\n                    try {\n                        return delegate.getTile(x, y, zoom);\n                    } catch (RemoteException e) {\n                        return null;\n                    }\n                }\n            };\n        }\n        return tileProvider;\n    }\n\n    /**\n     * Gets the transparency set for this {@link TileOverlayOptions} object.\n     *\n     * @return the transparency of the tile overlay.\n     */\n    public float getTransparency() {\n        return transparency;\n    }\n\n    /**\n     * Gets the zIndex set for this {@link TileOverlayOptions} object.\n     *\n     * @return the zIndex of the tile overlay.\n     */\n    public float getZIndex() {\n        return zIndex;\n    }\n\n    /**\n     * Gets the visibility setting for this {@link TileOverlayOptions} object.\n     *\n     * @return {@code true} if the tile overlay is to be visible; {@code false} if it is not.\n     */\n    public boolean isVisible() {\n        return visible;\n    }\n\n    /**\n     * Specifies the tile provider to use for this tile overlay.\n     *\n     * @param tileProvider the {@link TileProvider} to use for this tile overlay.\n     * @return the object for which the method was called, with the new tile provider set.\n     */\n    public TileOverlayOptions tileProvider(@NonNull final TileProvider tileProvider) {\n        this.tileProvider = tileProvider;\n        this.tileProviderBinder = new ITileProviderDelegate.Stub() {\n            @Override\n            public Tile getTile(int x, int y, int zoom) throws RemoteException {\n                return tileProvider.getTile(x, y, zoom);\n            }\n        };\n        return this;\n    }\n\n    /**\n     * Specifies the transparency of the tile overlay. The default transparency is {@code 0} (opaque).\n     *\n     * @param transparency a float in the range {@code [0..1]} where {@code 0} means that the tile overlay is opaque and {@code 1} means that the tile overlay is transparent.\n     * @return this {@link TileOverlayOptions} object with a new transparency setting.\n     * @throws IllegalArgumentException if the transparency is outside the range [0..1].\n     */\n    public TileOverlayOptions transparency(float transparency) {\n        if (transparency < 0.0f || transparency > 1.0f) throw new IllegalArgumentException(\"Transparency must be in the range [0..1]\");\n        this.transparency = transparency;\n        return this;\n    }\n\n    /**\n     * Specifies the visibility for the tile overlay. The default visibility is {@code true}.\n     *\n     * @return this {@link TileOverlayOptions} object with a new visibility setting.\n     */\n    public TileOverlayOptions visible(boolean visible) {\n        this.visible = visible;\n        return this;\n    }\n\n    /**\n     * Specifies the tile overlay's zIndex, i.e., the order in which it will be drawn where\n     * overlays with larger values are drawn above those with lower values. See the documentation\n     * at the top of this class for more information about zIndex.\n     *\n     * @return this {@link TileOverlayOptions} object with a new zIndex set.\n     */\n    public TileOverlayOptions zIndex(float zIndex) {\n        this.zIndex = zIndex;\n        return this;\n    }\n\n    public static Creator<TileOverlayOptions> CREATOR = new AutoCreator<TileOverlayOptions>(TileOverlayOptions.class);\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/model/TileProvider.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.maps.model;\n\n/**\n * An interface for a class that provides the tile images for a TileOverlay. For information about\n * the tile coordinate system, see TileOverlay.\n * <p/>\n * Calls to methods in this interface might be made from multiple threads so implementations of\n * this interface must be threadsafe.\n */\npublic interface TileProvider {\n    public static final Tile NO_TILE = new Tile(-1, -1, null);\n\n    /**\n     * Returns the tile to be used for this tile coordinate.\n     *\n     * @param x    The x coordinate of the tile. This will be in the range [0, 2^(zoom - 1)] inclusive.\n     * @param y    The y coordinate of the tile. This will be in the range [0, 2^(zoom - 1)] inclusive.\n     * @param zoom The zoom level of the tile.\n     * @return the {@link Tile} to be used for this tile coordinate. If you do not wish to provide\n     * a tile for this tile coordinate, return {@link #NO_TILE}. If the tile could not be found at\n     * this point in time, return null and further requests might be made with an exponential\n     * backoff.\n     */\n    public Tile getTile(int x, int y, int zoom);\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/model/VisibleRegion.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.maps.model;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\n@PublicApi\npublic class VisibleRegion extends AutoSafeParcelable {\n    @SafeParceled(1)\n    private int versionCode;\n    @SafeParceled(2)\n    private LatLng nearLeft;\n    @SafeParceled(3)\n    private LatLng nearRight;\n    @SafeParceled(4)\n    private LatLng farLeft;\n    @SafeParceled(5)\n    private LatLng farRight;\n    @SafeParceled(6)\n    private LatLngBounds bounds;\n\n    private VisibleRegion() {\n    }\n\n    public VisibleRegion(int versionCode, LatLng nearLeft, LatLng nearRight, LatLng farLeft,\n            LatLng farRight, LatLngBounds bounds) {\n        this.versionCode = versionCode;\n        this.nearLeft = nearLeft;\n        this.nearRight = nearRight;\n        this.farLeft = farLeft;\n        this.farRight = farRight;\n        this.bounds = bounds;\n    }\n\n    public VisibleRegion(LatLng nearLeft, LatLng nearRight, LatLng farLeft, LatLng farRight,\n            LatLngBounds bounds) {\n        this(1, nearLeft, nearRight, farLeft, farRight, bounds);\n    }\n\n    /**\n     * This is assuming that the visible region matches the bounds, which means that it's a north\n     * orientated top view\n     */\n    public VisibleRegion(LatLngBounds bounds) {\n        this(bounds.southwest, new LatLng(bounds.southwest.latitude, bounds.northeast.longitude),\n                new LatLng(bounds.northeast.latitude, bounds.southwest.longitude), bounds.northeast,\n                bounds);\n    }\n\n    public static Creator<VisibleRegion> CREATOR = new AutoCreator<VisibleRegion>(VisibleRegion.class);\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/model/package-info.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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/**\n * Contains the Google Maps Android API model classes.\n */\npackage com.google.android.gms.maps.model;\n"
  },
  {
    "path": "play-services-maps/src/main/java/com/google/android/gms/maps/package-info.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n/**\n * Contains the Google Maps SDK for Android classes.\n */\npackage com.google.android.gms.maps;\n"
  },
  {
    "path": "play-services-maps/src/main/java/org/microg/gms/maps/MapLifecycleDelegate.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.maps;\n\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.dynamic.LifecycleDelegate;\nimport com.google.android.gms.maps.OnMapReadyCallback;\n\npublic interface MapLifecycleDelegate extends LifecycleDelegate {\n    void getMapAsync(@NonNull OnMapReadyCallback callback);\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/org/microg/gms/maps/MapViewDelegate.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.maps;\n\nimport android.app.Activity;\nimport android.os.Bundle;\nimport android.os.RemoteException;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.dynamic.ObjectWrapper;\nimport com.google.android.gms.maps.GoogleMap;\nimport com.google.android.gms.maps.OnMapReadyCallback;\nimport com.google.android.gms.maps.internal.IGoogleMapDelegate;\nimport com.google.android.gms.maps.internal.IMapViewDelegate;\nimport com.google.android.gms.maps.internal.IOnMapReadyCallback;\nimport com.google.android.gms.maps.model.RuntimeRemoteException;\n\npublic class MapViewDelegate implements MapLifecycleDelegate {\n    private final ViewGroup container;\n    private final IMapViewDelegate delegate;\n    private View view;\n\n    public MapViewDelegate(ViewGroup container, IMapViewDelegate delegate) {\n        this.container = container;\n        this.delegate = delegate;\n    }\n\n    @Override\n    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup parent, @Nullable Bundle savedInstanceState) {\n        throw new UnsupportedOperationException(\"onCreateView not allowed on MapViewDelegate\");\n    }\n\n    @Override\n    public void onCreate(@Nullable Bundle savedInstanceState) {\n        try {\n            Bundle temp = new Bundle();\n            MapsBundleHelper.transfer(savedInstanceState, temp);\n            delegate.onCreate(temp);\n            MapsBundleHelper.transfer(temp, savedInstanceState);\n            view = (View) ObjectWrapper.unwrap(delegate.getView());\n            container.removeAllViews();\n            container.addView(view);\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    @Override\n    public void onDestroy() {\n        try {\n            delegate.onDestroy();\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    @Override\n    public void onDestroyView() {\n        throw new UnsupportedOperationException(\"onDestroyView not allowed on MapViewDelegate\");\n    }\n\n    public void onEnterAmbient(Bundle bundle) {\n        try {\n            Bundle temp = new Bundle();\n            MapsBundleHelper.transfer(bundle, temp);\n            delegate.onEnterAmbient(temp);\n            MapsBundleHelper.transfer(temp, bundle);\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    public void onExitAmbient() {\n        try {\n            delegate.onExitAmbient();\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    @Override\n    public void onInflate(@NonNull Activity activity, @NonNull Bundle options, @Nullable Bundle onInflate) {\n        throw new UnsupportedOperationException(\"onInflate not allowed on MapViewDelegate\");\n    }\n\n    @Override\n    public void onLowMemory() {\n        try {\n            delegate.onLowMemory();\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    @Override\n    public void onPause() {\n        try {\n            delegate.onPause();\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    @Override\n    public void onResume() {\n        try {\n            delegate.onResume();\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    @Override\n    public void onSaveInstanceState(@NonNull Bundle outState) {\n        try {\n            Bundle temp = new Bundle();\n            MapsBundleHelper.transfer(outState, temp);\n            delegate.onSaveInstanceState(temp);\n            MapsBundleHelper.transfer(temp, outState);\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    @Override\n    public void onStart() {\n        try {\n            delegate.onStart();\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    @Override\n    public void onStop() {\n        try {\n            delegate.onStop();\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    @Override\n    public void getMapAsync(@NonNull OnMapReadyCallback callback) {\n        try {\n            delegate.getMapAsync(new IOnMapReadyCallback.Stub() {\n                @Override\n                public void onMapReady(IGoogleMapDelegate map) throws RemoteException {\n                    callback.onMapReady(new GoogleMap(map));\n                }\n            });\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/org/microg/gms/maps/MapViewLifecycleHelper.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.maps;\n\nimport android.content.Context;\nimport android.view.ViewGroup;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.dynamic.DeferredLifecycleHelper;\nimport com.google.android.gms.dynamic.ObjectWrapper;\nimport com.google.android.gms.dynamic.OnDelegateCreatedListener;\nimport com.google.android.gms.maps.GoogleMapOptions;\nimport com.google.android.gms.maps.MapsInitializer;\nimport com.google.android.gms.maps.OnMapReadyCallback;\nimport com.google.android.gms.maps.internal.IMapViewDelegate;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class MapViewLifecycleHelper extends DeferredLifecycleHelper<MapViewDelegate> {\n    private final ViewGroup container;\n    private final Context context;\n    private final GoogleMapOptions options;\n    private final List<OnMapReadyCallback> pendingMapReadyCallbacks = new ArrayList<>();\n\n    public MapViewLifecycleHelper(ViewGroup container, Context context, GoogleMapOptions options) {\n        this.container = container;\n        this.context = context;\n        this.options = options;\n    }\n\n    public final void getMapAsync(OnMapReadyCallback callback) {\n        if (getDelegate() != null) {\n            getDelegate().getMapAsync(callback);\n        } else {\n            this.pendingMapReadyCallbacks.add(callback);\n        }\n    }\n\n    @Override\n    protected void createDelegate(@NonNull OnDelegateCreatedListener<MapViewDelegate> listener) {\n        if (getDelegate() != null) return;\n        try {\n            MapsInitializer.initialize(context);\n            IMapViewDelegate delegate = MapsContextLoader.getCreator(context, null).newMapViewDelegate(ObjectWrapper.wrap(context), options);\n            listener.onDelegateCreated(new MapViewDelegate(container, delegate));\n            for (OnMapReadyCallback callback : pendingMapReadyCallbacks) {\n                getDelegate().getMapAsync(callback);\n            }\n            pendingMapReadyCallbacks.clear();\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/org/microg/gms/maps/MapsBundleHelper.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.maps;\n\nimport android.os.Bundle;\nimport android.os.Parcelable;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\npublic class MapsBundleHelper {\n    @NonNull\n    private static ClassLoader getClassLoader() {\n        return MapsBundleHelper.class.getClassLoader();\n    }\n\n    public static Parcelable getParcelableFromMapStateBundle(@Nullable Bundle bundle, String key) {\n        ClassLoader classLoader = getClassLoader();\n        bundle.setClassLoader(classLoader);\n        Bundle mapStateBundle = bundle.getBundle(\"map_state\");\n        if (mapStateBundle == null) {\n            return null;\n        }\n        mapStateBundle.setClassLoader(classLoader);\n        return mapStateBundle.getParcelable(key);\n    }\n\n    public static void setParcelableInMapStateBundle(Bundle bundle, String key, @Nullable Parcelable parcelable) {\n        ClassLoader classLoader = getClassLoader();\n        bundle.setClassLoader(classLoader);\n        Bundle mapStateBundle = bundle.getBundle(\"map_state\");\n        if (mapStateBundle == null) {\n            mapStateBundle = new Bundle();\n        }\n        mapStateBundle.setClassLoader(classLoader);\n        mapStateBundle.putParcelable(key, parcelable);\n        bundle.putBundle(\"map_state\", mapStateBundle);\n    }\n\n    public static void transfer(@Nullable Bundle src, @Nullable Bundle dest) {\n        if (src == null || dest == null) {\n            return;\n        }\n        Parcelable parcelableFromMapStateBundle = getParcelableFromMapStateBundle(src, \"MapOptions\");\n        if (parcelableFromMapStateBundle != null) {\n            setParcelableInMapStateBundle(dest, \"MapOptions\", parcelableFromMapStateBundle);\n        }\n        Parcelable parcelableFromMapStateBundle2 = getParcelableFromMapStateBundle(src, \"StreetViewPanoramaOptions\");\n        if (parcelableFromMapStateBundle2 != null) {\n            setParcelableInMapStateBundle(dest, \"StreetViewPanoramaOptions\", parcelableFromMapStateBundle2);\n        }\n        Parcelable parcelableFromMapStateBundle3 = getParcelableFromMapStateBundle(src, \"camera\");\n        if (parcelableFromMapStateBundle3 != null) {\n            setParcelableInMapStateBundle(dest, \"camera\", parcelableFromMapStateBundle3);\n        }\n        if (src.containsKey(\"position\")) {\n            dest.putString(\"position\", src.getString(\"position\"));\n        }\n        if (src.containsKey(\"com.google.android.wearable.compat.extra.LOWBIT_AMBIENT\")) {\n            dest.putBoolean(\"com.google.android.wearable.compat.extra.LOWBIT_AMBIENT\", src.getBoolean(\"com.google.android.wearable.compat.extra.LOWBIT_AMBIENT\", false));\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/org/microg/gms/maps/MapsContextLoader.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.maps;\n\nimport android.content.Context;\nimport android.os.IBinder;\nimport android.os.RemoteException;\nimport android.util.Log;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.GooglePlayServicesUtil;\nimport com.google.android.gms.dynamic.ObjectWrapper;\nimport com.google.android.gms.dynamite.DynamiteModule;\nimport com.google.android.gms.maps.MapsInitializer;\nimport com.google.android.gms.maps.internal.ICreator;\nimport com.google.android.gms.maps.model.RuntimeRemoteException;\nimport org.microg.gms.common.Constants;\n\npublic class MapsContextLoader {\n    private static final String TAG = \"MapsContextLoader\";\n    private static final String DYNAMITE_MODULE_DEFAULT = \"com.google.android.gms.maps_dynamite\";\n    private static final String DYNAMITE_MODULE_LEGACY = \"com.google.android.gms.maps_legacy_dynamite\";\n    private static final String DYNAMITE_MODULE_LATEST = \"com.google.android.gms.maps_core_dynamite\";\n\n    private static Context mapsContext;\n    private static ICreator creator;\n\n    private static Context getMapsContext(Context context, @Nullable MapsInitializer.Renderer preferredRenderer) {\n        if (mapsContext == null) {\n            String moduleName;\n            if (preferredRenderer == null) {\n                moduleName = DYNAMITE_MODULE_DEFAULT;\n            } else if (preferredRenderer == MapsInitializer.Renderer.LEGACY) {\n                moduleName = DYNAMITE_MODULE_LEGACY;\n            } else if (preferredRenderer == MapsInitializer.Renderer.LATEST) {\n                moduleName = DYNAMITE_MODULE_LATEST;\n            } else {\n                moduleName = DYNAMITE_MODULE_DEFAULT;\n            }\n            Context mapsContext;\n            try {\n                mapsContext = DynamiteModule.load(context, DynamiteModule.PREFER_REMOTE, moduleName).getModuleContext();\n            } catch (Exception e) {\n                if (!moduleName.equals(DYNAMITE_MODULE_DEFAULT)) {\n                    try {\n                        Log.d(TAG, \"Attempting to load maps_dynamite again.\");\n                        mapsContext = DynamiteModule.load(context, DynamiteModule.PREFER_REMOTE, DYNAMITE_MODULE_DEFAULT).getModuleContext();\n                    } catch (Exception e2) {\n                        Log.e(TAG, \"Failed to load maps module, use pre-Chimera\", e2);\n                        mapsContext = GooglePlayServicesUtil.getRemoteContext(context);\n                    }\n                } else {\n                    Log.e(TAG, \"Failed to load maps module, use pre-Chimera\", e);\n                    mapsContext = GooglePlayServicesUtil.getRemoteContext(context);\n                }\n            }\n            MapsContextLoader.mapsContext = mapsContext;\n        }\n        return mapsContext;\n    }\n\n    public static ICreator getCreator(Context context, @Nullable MapsInitializer.Renderer preferredRenderer) {\n        Log.d(TAG, \"preferredRenderer: \" + preferredRenderer);\n        if (creator == null) {\n            Log.d(TAG, \"Making Creator dynamically\");\n            try {\n                Context mapsContext = getMapsContext(context, preferredRenderer);\n                Class<?> clazz = mapsContext.getClassLoader().loadClass(\"com.google.android.gms.maps.internal.CreatorImpl\");\n                creator = ICreator.Stub.asInterface((IBinder) clazz.newInstance());\n                creator.initV2(ObjectWrapper.wrap(mapsContext.getResources()), Constants.GMS_VERSION_CODE);\n            } catch (ClassNotFoundException e) {\n                throw new IllegalStateException(\"Unable to find dynamic class com.google.android.gms.maps.internal.CreatorImpl\");\n            } catch (IllegalAccessException e) {\n                throw new IllegalStateException(\"Unable to call the default constructor of com.google.android.gms.maps.internal.CreatorImpl\");\n            } catch (InstantiationException e) {\n                throw new IllegalStateException(\"Unable to instantiate the dynamic class com.google.android.gms.maps.internal.CreatorImpl\");\n            } catch (RemoteException e) {\n                throw new RuntimeRemoteException(e);\n            }\n        }\n        return creator;\n    }\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/org/microg/gms/maps/StreetViewLifecycleDelegate.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.maps;\n\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.dynamic.LifecycleDelegate;\nimport com.google.android.gms.maps.OnStreetViewPanoramaReadyCallback;\n\npublic interface StreetViewLifecycleDelegate extends LifecycleDelegate {\n    void getStreetViewPanoramaAsync(@NonNull OnStreetViewPanoramaReadyCallback callback);\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/org/microg/gms/maps/StreetViewPanoramaViewDelegate.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.maps;\n\nimport android.app.Activity;\nimport android.os.Bundle;\nimport android.os.RemoteException;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.dynamic.ObjectWrapper;\nimport com.google.android.gms.maps.OnStreetViewPanoramaReadyCallback;\nimport com.google.android.gms.maps.StreetViewPanorama;\nimport com.google.android.gms.maps.internal.*;\nimport com.google.android.gms.maps.model.RuntimeRemoteException;\n\npublic class StreetViewPanoramaViewDelegate implements StreetViewLifecycleDelegate {\n    private final ViewGroup container;\n    private final IStreetViewPanoramaViewDelegate delegate;\n    private View view;\n\n    public StreetViewPanoramaViewDelegate(ViewGroup container, IStreetViewPanoramaViewDelegate delegate) {\n        this.container = container;\n        this.delegate = delegate;\n    }\n\n    @Override\n    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup parent, @Nullable Bundle savedInstanceState) {\n        throw new UnsupportedOperationException(\"onCreateView not allowed on StreetViewPanoramaViewDelegate\");\n    }\n\n    @Override\n    public void onCreate(@Nullable Bundle savedInstanceState) {\n        try {\n            Bundle temp = new Bundle();\n            MapsBundleHelper.transfer(savedInstanceState, temp);\n            delegate.onCreate(temp);\n            MapsBundleHelper.transfer(temp, savedInstanceState);\n            view = (View) ObjectWrapper.unwrap(delegate.getView());\n            container.removeAllViews();\n            container.addView(view);\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    @Override\n    public void onDestroy() {\n        try {\n            delegate.onDestroy();\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    @Override\n    public void onDestroyView() {\n        throw new UnsupportedOperationException(\"onDestroyView not allowed on StreetViewPanoramaViewDelegate\");\n    }\n\n    @Override\n    public void onInflate(@NonNull Activity activity, @NonNull Bundle options, @Nullable Bundle onInflate) {\n        throw new UnsupportedOperationException(\"onInflate not allowed on StreetViewPanoramaViewDelegate\");\n    }\n\n    @Override\n    public void onLowMemory() {\n        try {\n            delegate.onLowMemory();\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    @Override\n    public void onPause() {\n        try {\n            delegate.onPause();\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    @Override\n    public void onResume() {\n        try {\n            delegate.onResume();\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    @Override\n    public void onSaveInstanceState(@NonNull Bundle outState) {\n        try {\n            Bundle temp = new Bundle();\n            MapsBundleHelper.transfer(outState, temp);\n            delegate.onSaveInstanceState(temp);\n            MapsBundleHelper.transfer(temp, outState);\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    @Override\n    public void onStart() {\n        try {\n            delegate.onStart();\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    @Override\n    public void onStop() {\n        try {\n            delegate.onStop();\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n\n    @Override\n    public void getStreetViewPanoramaAsync(@NonNull OnStreetViewPanoramaReadyCallback callback) {\n        try {\n            delegate.getStreetViewPanoramaAsync(new IOnStreetViewPanoramaReadyCallback.Stub() {\n                @Override\n                public void onStreetViewPanoramaReady(IStreetViewPanoramaDelegate streetViewPanorama) throws RemoteException {\n                    callback.onStreetViewPanoramaReady(new StreetViewPanorama(streetViewPanorama));\n                }\n            });\n        } catch (RemoteException e) {\n            throw new RuntimeRemoteException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-maps/src/main/java/org/microg/gms/maps/StreetViewPanoramaViewLifecycleHelper.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.maps;\n\nimport android.content.Context;\nimport android.view.ViewGroup;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.dynamic.DeferredLifecycleHelper;\nimport com.google.android.gms.dynamic.ObjectWrapper;\nimport com.google.android.gms.dynamic.OnDelegateCreatedListener;\nimport com.google.android.gms.maps.MapsInitializer;\nimport com.google.android.gms.maps.OnStreetViewPanoramaReadyCallback;\nimport com.google.android.gms.maps.StreetViewPanoramaOptions;\nimport com.google.android.gms.maps.internal.IStreetViewPanoramaViewDelegate;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class StreetViewPanoramaViewLifecycleHelper extends DeferredLifecycleHelper<StreetViewPanoramaViewDelegate> {\n    private final ViewGroup container;\n    private final Context context;\n    private final StreetViewPanoramaOptions options;\n    private final List<OnStreetViewPanoramaReadyCallback> pendingStreetViewReadyCallbacks = new ArrayList<>();\n\n    public StreetViewPanoramaViewLifecycleHelper(ViewGroup container, Context context, StreetViewPanoramaOptions options) {\n        this.container = container;\n        this.context = context;\n        this.options = options;\n    }\n\n    public final void getStreetViewPanoramaAsync(OnStreetViewPanoramaReadyCallback callback) {\n        if (getDelegate() != null) {\n            getDelegate().getStreetViewPanoramaAsync(callback);\n        } else {\n            this.pendingStreetViewReadyCallbacks.add(callback);\n        }\n    }\n\n    @Override\n    protected void createDelegate(@NonNull OnDelegateCreatedListener<StreetViewPanoramaViewDelegate> listener) {\n        if (getDelegate() != null) return;\n        try {\n            MapsInitializer.initialize(context);\n            IStreetViewPanoramaViewDelegate delegate = MapsContextLoader.getCreator(context, null).newStreetViewPanoramaViewDelegate(ObjectWrapper.wrap(context), options);\n            listener.onDelegateCreated(new StreetViewPanoramaViewDelegate(container, delegate));\n            for (OnStreetViewPanoramaReadyCallback callback : pendingStreetViewReadyCallbacks) {\n                getDelegate().getStreetViewPanoramaAsync(callback);\n            }\n            pendingStreetViewReadyCallbacks.clear();\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-maps/src/main/res/values/maps_attrs.xml",
    "content": "<!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<resources>\n    <declare-styleable name=\"MapAttrs\">\n        <attr name=\"mapType\">\n            <enum name=\"none\" value=\"0\" />\n            <enum name=\"normal\" value=\"1\" />\n            <enum name=\"satellite\" value=\"2\" />\n            <enum name=\"terrain\" value=\"3\" />\n            <enum name=\"hybrid\" value=\"4\" />\n        </attr>\n        <attr name=\"cameraBearing\" format=\"float\" />\n        <attr name=\"cameraTargetLat\" format=\"float\" />\n        <attr name=\"cameraTargetLng\" format=\"float\" />\n        <attr name=\"cameraTilt\" format=\"float\" />\n        <attr name=\"cameraZoom\" format=\"float\" />\n        <attr name=\"liteMode\" format=\"boolean\" />\n        <attr name=\"uiCompass\" format=\"boolean\" />\n        <attr name=\"uiRotateGestures\" format=\"boolean\" />\n        <attr name=\"uiScrollGestures\" format=\"boolean\" />\n        <attr name=\"uiScrollGesturesDuringRotateOrZoom\" format=\"boolean\" />\n        <attr name=\"uiTiltGestures\" format=\"boolean\" />\n        <attr name=\"uiZoomControls\" format=\"boolean\" />\n        <attr name=\"uiZoomGestures\" format=\"boolean\" />\n        <attr name=\"useViewLifecycle\" format=\"boolean\" />\n        <attr name=\"zOrderOnTop\" format=\"boolean\" />\n        <attr name=\"uiMapToolbar\" format=\"boolean\" />\n        <attr name=\"ambientEnabled\" format=\"boolean\" />\n        <attr name=\"cameraMinZoomPreference\" format=\"float\" />\n        <attr name=\"cameraMaxZoomPreference\" format=\"float\" />\n        <attr name=\"latLngBoundsSouthWestLatitude\" format=\"float\" />\n        <attr name=\"latLngBoundsSouthWestLongitude\" format=\"float\" />\n        <attr name=\"latLngBoundsNorthEastLatitude\" format=\"float\" />\n        <attr name=\"latLngBoundsNorthEastLongitude\" format=\"float\" />\n        <attr name=\"backgroundColor\" format=\"color\" />\n        <attr name=\"mapId\" format=\"string\" />\n    </declare-styleable>\n</resources>"
  },
  {
    "path": "play-services-measurement-base/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\nandroid {\n    namespace \"com.google.android.gms.measurement_base\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n}\n\napply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG implementation of play-services-clearcut'\n\ndependencies {\n    // Dependencies from play-services-measurement-base:21.2.0\n    api project(':play-services-basement')\n\n    annotationProcessor project(\":safe-parcel-processor\")\n}\n"
  },
  {
    "path": "play-services-measurement-base/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest />"
  },
  {
    "path": "play-services-measurement-base/src/main/aidl/com/google/android/gms/measurement/api/internal/IAppMeasurementDynamiteService.aidl",
    "content": "package com.google.android.gms.measurement.api.internal;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.measurement.api.internal.IBundleReceiver;\nimport com.google.android.gms.measurement.api.internal.IDynamiteUploadBatchesCallback;\nimport com.google.android.gms.measurement.api.internal.IEventHandlerProxy;\nimport com.google.android.gms.measurement.api.internal.IStringProvider;\nimport com.google.android.gms.measurement.api.internal.InitializationParams;\nimport com.google.android.gms.measurement.api.internal.ScionActivityInfo;\n\ninterface IAppMeasurementDynamiteService {\n    void initialize(in IObjectWrapper context, in InitializationParams params, long eventTimeMillis) = 0;\n    void logEvent(String origin, String name, in Bundle params, boolean z, boolean z2, long eventTimeMillis) = 1;\n    void logEventAndBundle(String origin, String name, in Bundle params, IBundleReceiver receiver, long eventTimeMillis) = 2;\n    void setUserProperty(String origin, String name, in IObjectWrapper value, boolean z, long eventTimeMillis) = 3;\n    void getUserProperties(String origin, String propertyNamePrefix, boolean includeInternal, IBundleReceiver receiver) = 4;\n    void getMaxUserProperties(String origin, IBundleReceiver receiver) = 5;\n    void setUserId(String userId, long eventTimeMillis) = 6;\n    void setConditionalUserProperty(in Bundle bundle, long eventTimeMillis) = 7;\n    void clearConditionalUserProperty(String name, String eventName, in Bundle bundle) = 8;\n    void getConditionalUserProperties(String origin, String propertyNamePrefix, IBundleReceiver receiver) = 9;\n    void setMeasurementEnabled(boolean measurementEnabled, long eventTimeMillis) = 10;\n    void resetAnalyticsData(long eventTimeMillis) = 11;\n    void setMinimumSessionDuration(long minimumSessionDuration) = 12;\n    void setSessionTimeoutDuration(long sessionTimeoutDuration) = 13;\n    void setCurrentScreen(in IObjectWrapper obj, String screenName, String className, long eventTimeMillis) = 14;\n    void getCurrentScreenName(IBundleReceiver receiver) = 15;\n    void getCurrentScreenClass(IBundleReceiver receiver) = 16;\n    void setInstanceIdProvider(IStringProvider provider) = 17;\n    void getCachedAppInstanceId(IBundleReceiver receiver) = 18;\n    void getAppInstanceId(IBundleReceiver receiver) = 19;\n    void getGmpAppId(IBundleReceiver receiver) = 20;\n    void generateEventId(IBundleReceiver receiver) = 21;\n    void beginAdUnitExposure(String adUnitId, long eventElapsedRealtime) = 22;\n    void endAdUnitExposure(String adUnitId, long eventElapsedRealtime) = 23;\n    void onActivityStarted(in IObjectWrapper activity, long eventElapsedRealtime) = 24;\n    void onActivityStopped(in IObjectWrapper activity, long eventElapsedRealtime) = 25;\n    void onActivityCreated(in IObjectWrapper activity, in Bundle savedInstanceState, long eventElapsedRealtime) = 26;\n    void onActivityDestroyed(in IObjectWrapper activity, long eventElapsedRealtime) = 27;\n    void onActivityPaused(in IObjectWrapper activity, long eventElapsedRealtime) = 28;\n    void onActivityResumed(in IObjectWrapper activity, long eventElapsedRealtime) = 29;\n    void onActivitySaveInstanceState(in IObjectWrapper activity, IBundleReceiver receiver, long eventElapsedRealtime) = 30;\n    void performAction(in Bundle bundle, IBundleReceiver receiver, long eventTimeMillis) = 31;\n    void logHealthData(int i, String str, in IObjectWrapper obj, in IObjectWrapper obj2, in IObjectWrapper obj3) = 32;\n    void setEventInterceptor(IEventHandlerProxy eventHandler) = 33;\n    void registerOnMeasurementEventListener(IEventHandlerProxy eventHandler) = 34;\n    void unregisterOnMeasurementEventListener(IEventHandlerProxy eventHandler) = 35;\n    void initForTests(in Map map) = 36;\n    void getTestFlag(IBundleReceiver receiver, int i) = 37;\n    void setDataCollectionEnabled(boolean dataCollectionEnabled) = 38;\n    void isDataCollectionEnabled(IBundleReceiver receiver) = 39;\n\n    void setDefaultEventParameters(in Bundle bundle) = 41;\n    void clearMeasurementEnabled(long eventTimeMillis) = 42;\n    void setConsent(in Bundle bundle, long eventTimeMillis) = 43;\n    void setConsentThirdParty(in Bundle bundle, long eventTimeMillis) = 44;\n    void getSessionId(IBundleReceiver receiver) = 45;\n\n    void setSgtmDebugInfo(in Intent intent) = 47;\n\n    void setCurrentScreenByScionActivityInfo(in ScionActivityInfo info, String screenName, String className, long eventElapsedRealtime) = 49;\n    void onActivityStartedByScionActivityInfo(in ScionActivityInfo info, long eventElapsedRealtime) = 50;\n    void onActivityStoppedByScionActivityInfo(in ScionActivityInfo info, long eventElapsedRealtime) = 51;\n    void onActivityCreatedByScionActivityInfo(in ScionActivityInfo info, in Bundle savedInstanceState, long eventElapsedRealtime) = 52;\n    void onActivityDestroyedByScionActivityInfo(in ScionActivityInfo info, long eventElapsedRealtime) = 53;\n    void onActivityPausedByScionActivityInfo(in ScionActivityInfo info, long eventElapsedRealtime) = 54;\n    void onActivityResumedByScionActivityInfo(in ScionActivityInfo info, long eventElapsedRealtime) = 55;\n    void onActivitySaveInstanceStateByScionActivityInfo(in ScionActivityInfo info, IBundleReceiver receiver, long eventElapsedRealtime) = 56;\n    void retrieveAndUploadBatches(IDynamiteUploadBatchesCallback callback) = 57;\n}\n"
  },
  {
    "path": "play-services-measurement-base/src/main/aidl/com/google/android/gms/measurement/api/internal/IBundleReceiver.aidl",
    "content": "package com.google.android.gms.measurement.api.internal;\n\ninterface IBundleReceiver {\n    void onBundle(in Bundle bundle);\n}\n"
  },
  {
    "path": "play-services-measurement-base/src/main/aidl/com/google/android/gms/measurement/api/internal/IDynamiteUploadBatchesCallback.aidl",
    "content": "package com.google.android.gms.measurement.api.internal;\n\ninterface IDynamiteUploadBatchesCallback {\n    void onUploadBatches();\n}\n"
  },
  {
    "path": "play-services-measurement-base/src/main/aidl/com/google/android/gms/measurement/api/internal/IEventHandlerProxy.aidl",
    "content": "package com.google.android.gms.measurement.api.internal;\n\ninterface IEventHandlerProxy {\n    void f1(String s1, String s2, in Bundle bundle, long j) = 0;\n    int f2() = 1;\n}\n"
  },
  {
    "path": "play-services-measurement-base/src/main/aidl/com/google/android/gms/measurement/api/internal/IStringProvider.aidl",
    "content": "package com.google.android.gms.measurement.api.internal;\n\ninterface IStringProvider {\n}\n"
  },
  {
    "path": "play-services-measurement-base/src/main/aidl/com/google/android/gms/measurement/api/internal/InitializationParams.aidl",
    "content": "package com.google.android.gms.measurement.api.internal;\n\nparcelable InitializationParams;\n"
  },
  {
    "path": "play-services-measurement-base/src/main/aidl/com/google/android/gms/measurement/api/internal/ScionActivityInfo.aidl",
    "content": "package com.google.android.gms.measurement.api.internal;\n\nparcelable ScionActivityInfo;\n"
  },
  {
    "path": "play-services-measurement-base/src/main/java/com/google/android/gms/measurement/api/internal/InitializationParams.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.measurement.api.internal;\n\nimport android.os.Bundle;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class InitializationParams extends AbstractSafeParcelable {\n    @Field(1)\n    public long field1;\n    @Field(2)\n    public long field2;\n    @Field(3)\n    public boolean field3;\n    @Field(4)\n    public String field4;\n    @Field(5)\n    public String field5;\n    @Field(6)\n    public String field6;\n    @Field(7)\n    public Bundle field7;\n    @Field(8)\n    public String field8;\n\n    @Override\n    @NonNull\n    public String toString() {\n        return \"InitializationParams{\" +\n                \"field1=\" + field1 +\n                \", field2=\" + field2 +\n                \", field3=\" + field3 +\n                \", field4='\" + field4 + '\\'' +\n                \", field5='\" + field5 + '\\'' +\n                \", field6='\" + field6 + '\\'' +\n                \", field7=\" + field7 +\n                \", field8='\" + field8 + '\\'' +\n                '}';\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<InitializationParams> CREATOR = findCreator(InitializationParams.class);\n}\n"
  },
  {
    "path": "play-services-measurement-base/src/main/java/com/google/android/gms/measurement/api/internal/ScionActivityInfo.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.measurement.api.internal;\n\nimport android.content.Intent;\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class ScionActivityInfo extends AbstractSafeParcelable {\n    @Field(1)\n    public final int id;\n    @Field(2)\n    public final String className;\n    @Field(3)\n    public final Intent intent;\n\n    @Constructor\n    public ScionActivityInfo(@Param(1) int id, @Param(2) String className, @Param(3) Intent intent) {\n        this.id = id;\n        this.className = className;\n        this.intent = intent;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<ScionActivityInfo> CREATOR = findCreator(ScionActivityInfo.class);\n}\n"
  },
  {
    "path": "play-services-mlkit/barcode-scanning/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\nandroid {\n    namespace \"com.google.mlkit.vision.barcode\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n}\n\napply from: '../../gradle/publish-android.gradle'\n\ndescription = 'microG implementation of play-services-mlkit-barcode-scanning'\n\ndependencies {\n    // Dependencies from play-services-mlkit-barcode-scanning:18.3.0\n    //api \"com.google.android.datatransport:transport-api:2.2.1\"\n    //api \"com.google.android.datatransport:transport-backend-cct:2.3.3\"\n    //api \"com.google.android.datatransport:transport-runtime:2.2.6\"\n    api project(':play-services-base')\n    api project(':play-services-basement')\n    api project(':play-services-tasks')\n    //api \"com.google.android.odml:image:1.0.0-beta1\"\n    //api \"com.google.firebase:firebase-components:16.1.0\"\n    //api \"com.google.firebase:firebase-encoders:16.1.0\"\n    //api \"com.google.firebase:firebase-encoders-json:17.1.0\"\n    //api \"com.google.mlkit:barcode-scanning-common:17.0.0\"\n    //api \"com.google.mlkit:common:18.9.0\"\n    //api \"com.google.mlkit:vision-common:17.3.0\"\n    //api \"com.google.mlkit:vision-interfaces:16.2.0\"\n\n    annotationProcessor project(\":safe-parcel-processor\")\n}\n"
  },
  {
    "path": "play-services-mlkit/barcode-scanning/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <application />\n</manifest>"
  },
  {
    "path": "play-services-mlkit/barcode-scanning/src/main/aidl/com/google/mlkit/vision/barcode/aidls/IBarcodeScanner.aidl",
    "content": "package com.google.mlkit.vision.barcode.aidls;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.mlkit.vision.barcode.internal.Barcode;\nimport com.google.mlkit.vision.barcode.internal.ImageMetadata;\n\ninterface IBarcodeScanner {\n    void init() = 0;\n    void close() = 1;\n    List<Barcode> detect(IObjectWrapper image, in ImageMetadata metadata) = 2;\n}"
  },
  {
    "path": "play-services-mlkit/barcode-scanning/src/main/aidl/com/google/mlkit/vision/barcode/aidls/IBarcodeScannerCreator.aidl",
    "content": "package com.google.mlkit.vision.barcode.aidls;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.mlkit.vision.barcode.aidls.IBarcodeScanner;\nimport com.google.mlkit.vision.barcode.internal.BarcodeScannerOptions;\n\ninterface IBarcodeScannerCreator {\n    IBarcodeScanner create(IObjectWrapper wrappedContext, in BarcodeScannerOptions options) = 0;\n}"
  },
  {
    "path": "play-services-mlkit/barcode-scanning/src/main/aidl/com/google/mlkit/vision/barcode/internal/Barcode.aidl",
    "content": "package com.google.mlkit.vision.barcode.internal;\n\nparcelable Barcode;"
  },
  {
    "path": "play-services-mlkit/barcode-scanning/src/main/aidl/com/google/mlkit/vision/barcode/internal/BarcodeScannerOptions.aidl",
    "content": "package com.google.mlkit.vision.barcode.internal;\n\nparcelable BarcodeScannerOptions;"
  },
  {
    "path": "play-services-mlkit/barcode-scanning/src/main/aidl/com/google/mlkit/vision/barcode/internal/ImageMetadata.aidl",
    "content": "package com.google.mlkit.vision.barcode.internal;\n\nparcelable ImageMetadata;"
  },
  {
    "path": "play-services-mlkit/barcode-scanning/src/main/java/com/google/mlkit/vision/barcode/internal/Address.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.mlkit.vision.barcode.internal;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class Address extends AbstractSafeParcelable {\n    @Field(1)\n    public int type;\n    @Field(2)\n    public String[] addressLines;\n\n    // TODO: Copied from com.google.mlkit.vision.barcode.common.Barcode.Address\n    public static final int UNKNOWN = 0;\n    public static final int WORK = 1;\n    public static final int HOME = 2;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<Address> CREATOR = findCreator(Address.class);\n}\n"
  },
  {
    "path": "play-services-mlkit/barcode-scanning/src/main/java/com/google/mlkit/vision/barcode/internal/Barcode.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.mlkit.vision.barcode.internal;\n\nimport android.graphics.Point;\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class Barcode extends AbstractSafeParcelable {\n    @Field(1)\n    public int format;\n    @Field(2)\n    public String displayValue;\n    @Field(3)\n    public String rawValue;\n    @Field(4)\n    public byte[] rawBytes;\n    @Field(5)\n    public Point[] cornerPoints;\n    @Field(6)\n    public int valueType;\n    @Field(7)\n    public Email email;\n    @Field(8)\n    public Phone phone;\n    @Field(9)\n    public Sms sms;\n    @Field(10)\n    public WiFi wifi;\n    @Field(11)\n    public UrlBookmark urlBookmark;\n    @Field(12)\n    public GeoPoint geoPoint;\n    @Field(13)\n    public CalendarEvent calendarEvent;\n    @Field(14)\n    public ContactInfo contactInfo;\n    @Field(15)\n    public DriverLicense driverLicense;\n\n    // TODO: Copied from com.google.mlkit.vision.barcode.common.Barcode\n    public static final int UNKNOWN_FORMAT = -1;\n    public static final int ALL_FORMATS = 0;\n    public static final int CODE_128 = 1;\n    public static final int CODE_39 = 2;\n    public static final int CODE_93 = 4;\n    public static final int CODABAR = 8;\n    public static final int DATA_MATRIX = 16;\n    public static final int EAN_13 = 32;\n    public static final int EAN_8 = 64;\n    public static final int ITF = 128;\n    public static final int QR_CODE = 256;\n    public static final int UPC_A = 512;\n    public static final int UPC_E = 1024;\n    public static final int PDF417 = 2048;\n    public static final int AZTEC = 4096;\n\n    public static final int UNKNOWN_TYPE = 0;\n    public static final int CONTACT_INFO = 1;\n    public static final int EMAIL = 2;\n    public static final int ISBN = 3;\n    public static final int PHONE = 4;\n    public static final int PRODUCT = 5;\n    public static final int SMS = 6;\n    public static final int TEXT = 7;\n    public static final int URL = 8;\n    public static final int WIFI = 9;\n    public static final int GEO = 10;\n    public static final int CALENDAR_EVENT = 11;\n    public static final int DRIVER_LICENSE = 12;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<Barcode> CREATOR = findCreator(Barcode.class);\n}\n"
  },
  {
    "path": "play-services-mlkit/barcode-scanning/src/main/java/com/google/mlkit/vision/barcode/internal/BarcodeScannerOptions.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.mlkit.vision.barcode.internal;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class BarcodeScannerOptions extends AbstractSafeParcelable {\n    @Field(1)\n    public int supportedFormats;\n    @Field(2)\n    public boolean allPotentialBarcodesEnabled;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<BarcodeScannerOptions> CREATOR = findCreator(BarcodeScannerOptions.class);\n}\n"
  },
  {
    "path": "play-services-mlkit/barcode-scanning/src/main/java/com/google/mlkit/vision/barcode/internal/CalendarDateTime.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.mlkit.vision.barcode.internal;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class CalendarDateTime extends AbstractSafeParcelable {\n    @Field(1)\n    public int year;\n    @Field(2)\n    public int month;\n    @Field(3)\n    public int day;\n    @Field(4)\n    public int hours;\n    @Field(5)\n    public int minutes;\n    @Field(6)\n    public int seconds;\n    @Field(7)\n    public boolean isUtc;\n    @Field(8)\n    @Nullable\n    public String rawValue;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<CalendarDateTime> CREATOR = findCreator(CalendarDateTime.class);\n}\n"
  },
  {
    "path": "play-services-mlkit/barcode-scanning/src/main/java/com/google/mlkit/vision/barcode/internal/CalendarEvent.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.mlkit.vision.barcode.internal;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class CalendarEvent extends AbstractSafeParcelable {\n    @Field(1)\n    public String summary;\n    @Field(2)\n    public String description;\n    @Field(3)\n    public String location;\n    @Field(4)\n    public String organizer;\n    @Field(5)\n    public String status;\n    @Field(6)\n    public CalendarDateTime start;\n    @Field(7)\n    public CalendarDateTime end;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<CalendarEvent> CREATOR = findCreator(CalendarEvent.class);\n}\n"
  },
  {
    "path": "play-services-mlkit/barcode-scanning/src/main/java/com/google/mlkit/vision/barcode/internal/ContactInfo.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.mlkit.vision.barcode.internal;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class ContactInfo extends AbstractSafeParcelable {\n    @Field(1)\n    @Nullable\n    public PersonName name;\n    @Field(2)\n    @Nullable\n    public String organization;\n    @Field(3)\n    @Nullable\n    public String title;\n    @Field(4)\n    @Nullable\n    public Phone[] phones;\n    @Field(5)\n    @Nullable\n    public Email[] emails;\n    @Field(6)\n    @Nullable\n    public String[] urls;\n    @Field(7)\n    @Nullable\n    public Address[] addresses;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<ContactInfo> CREATOR = findCreator(ContactInfo.class);\n}\n"
  },
  {
    "path": "play-services-mlkit/barcode-scanning/src/main/java/com/google/mlkit/vision/barcode/internal/DriverLicense.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.mlkit.vision.barcode.internal;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class DriverLicense extends AbstractSafeParcelable {\n    @Field(1)\n    @Nullable\n    public String documentType;\n    @Field(2)\n    @Nullable\n    public String firstName;\n    @Field(3)\n    @Nullable\n    public String middleName;\n    @Field(4)\n    @Nullable\n    public String listName;\n    @Field(5)\n    @Nullable\n    public String gender;\n    @Field(6)\n    @Nullable\n    public String addressStreet;\n    @Field(7)\n    @Nullable\n    public String addressCity;\n    @Field(8)\n    @Nullable\n    public String addressState;\n    @Field(9)\n    @Nullable\n    public String addressZip;\n    @Field(10)\n    @Nullable\n    public String licenseNumber;\n    @Field(11)\n    @Nullable\n    public String issueDate;\n    @Field(12)\n    @Nullable\n    public String expiryDate;\n    @Field(13)\n    @Nullable\n    public String birthDate;\n    @Field(14)\n    @Nullable\n    public String issuingCountry;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<DriverLicense> CREATOR = findCreator(DriverLicense.class);\n}\n"
  },
  {
    "path": "play-services-mlkit/barcode-scanning/src/main/java/com/google/mlkit/vision/barcode/internal/Email.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.mlkit.vision.barcode.internal;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class Email extends AbstractSafeParcelable {\n    @Field(1)\n    public int type;\n    @Field(2)\n    public String address;\n    @Field(3)\n    public String subject;\n    @Field(4)\n    public String body;\n\n    // TODO: Copied from com.google.mlkit.vision.barcode.common.Barcode.Email\n    public static final int UNKNOWN = 0;\n    public static final int WORK = 1;\n    public static final int HOME = 2;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<Email> CREATOR = findCreator(Email.class);\n}\n"
  },
  {
    "path": "play-services-mlkit/barcode-scanning/src/main/java/com/google/mlkit/vision/barcode/internal/GeoPoint.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.mlkit.vision.barcode.internal;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class GeoPoint extends AbstractSafeParcelable {\n    @Field(1)\n    public double lat;\n    @Field(2)\n    public double lng;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<GeoPoint> CREATOR = findCreator(GeoPoint.class);\n}\n"
  },
  {
    "path": "play-services-mlkit/barcode-scanning/src/main/java/com/google/mlkit/vision/barcode/internal/ImageMetadata.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.mlkit.vision.barcode.internal;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class ImageMetadata extends AbstractSafeParcelable {\n    @Field(1)\n    public int format;\n    @Field(2)\n    public int width;\n    @Field(3)\n    public int height;\n    @Field(4)\n    public int rotation;\n    @Field(5)\n    public long timestamp;\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"ImageMetadata\")\n                .field(\"format\", format)\n                .field(\"width\", width)\n                .field(\"height\", height)\n                .field(\"rotation\", rotation)\n                .field(\"timestamp\", timestamp)\n                .end();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<ImageMetadata> CREATOR = findCreator(ImageMetadata.class);\n}\n"
  },
  {
    "path": "play-services-mlkit/barcode-scanning/src/main/java/com/google/mlkit/vision/barcode/internal/PersonName.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.mlkit.vision.barcode.internal;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class PersonName extends AbstractSafeParcelable {\n    @Field(1)\n    @Nullable\n    public String formattedName;\n    @Field(2)\n    @Nullable\n    public String pronunciation;\n    @Field(3)\n    @Nullable\n    public String prefix;\n    @Field(4)\n    @Nullable\n    public String first;\n    @Field(5)\n    @Nullable\n    public String middle;\n    @Field(6)\n    @Nullable\n    public String last;\n    @Field(7)\n    @Nullable\n    public String suffix;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<PersonName> CREATOR = findCreator(PersonName.class);\n}\n"
  },
  {
    "path": "play-services-mlkit/barcode-scanning/src/main/java/com/google/mlkit/vision/barcode/internal/Phone.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.mlkit.vision.barcode.internal;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class Phone extends AbstractSafeParcelable {\n    @Field(1)\n    public int type;\n    @Field(2)\n    public String number;\n\n    // TODO: Copied from com.google.mlkit.vision.barcode.common.Barcode.Phone\n    public static final int UNKNOWN = 0;\n    public static final int WORK = 1;\n    public static final int HOME = 2;\n    public static final int FAX = 3;\n    public static final int MOBILE = 4;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<Phone> CREATOR = findCreator(Phone.class);\n}\n"
  },
  {
    "path": "play-services-mlkit/barcode-scanning/src/main/java/com/google/mlkit/vision/barcode/internal/Sms.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.mlkit.vision.barcode.internal;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class Sms extends AbstractSafeParcelable {\n    @Field(1)\n    public String message;\n    @Field(2)\n    public String phoneNumber;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<Sms> CREATOR = findCreator(Sms.class);\n}\n"
  },
  {
    "path": "play-services-mlkit/barcode-scanning/src/main/java/com/google/mlkit/vision/barcode/internal/UrlBookmark.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.mlkit.vision.barcode.internal;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class UrlBookmark extends AbstractSafeParcelable {\n    @Field(1)\n    public String title;\n    @Field(2)\n    public String url;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<UrlBookmark> CREATOR = findCreator(UrlBookmark.class);\n}\n"
  },
  {
    "path": "play-services-mlkit/barcode-scanning/src/main/java/com/google/mlkit/vision/barcode/internal/WiFi.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.mlkit.vision.barcode.internal;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class WiFi extends AbstractSafeParcelable {\n    @Field(1)\n    public String ssid;\n    @Field(2)\n    public String password;\n    @Field(3)\n    public int encryptionType;\n\n    // TODO: Copied from com.google.mlkit.vision.barcode.common.Barcode.WiFi\n    public static final int OPEN = 1;\n    public static final int WPA = 2;\n    public static final int WEP = 3;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<WiFi> CREATOR = findCreator(WiFi.class);\n}\n"
  },
  {
    "path": "play-services-mlkit/face-detection/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\nandroid {\n    namespace \"com.google.mlkit.vision.face\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n}\n\napply from: '../../gradle/publish-android.gradle'\n\ndescription = 'microG implementation of play-services-mlkit-face-detection'\n\ndependencies {\n    // Dependencies from play-services-mlkit-face-detection:17.1.0\n    api project(':play-services-base')\n    api project(':play-services-basement')\n    api project(':play-services-tasks')\n\n    annotationProcessor project(\":safe-parcel-processor\")\n}\n"
  },
  {
    "path": "play-services-mlkit/face-detection/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <application />\n</manifest>"
  },
  {
    "path": "play-services-mlkit/face-detection/src/main/aidl/com/google/mlkit/vision/face/FaceDetectionOptions.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.mlkit.vision.face;\n\nparcelable FaceDetectionOptions;"
  },
  {
    "path": "play-services-mlkit/face-detection/src/main/aidl/com/google/mlkit/vision/face/FrameMetadataParcel.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.mlkit.vision.face;\n\nparcelable FrameMetadataParcel;"
  },
  {
    "path": "play-services-mlkit/face-detection/src/main/aidl/com/google/mlkit/vision/face/aidls/FaceParcel.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.mlkit.vision.face.aidls;\n\nparcelable FaceParcel;"
  },
  {
    "path": "play-services-mlkit/face-detection/src/main/aidl/com/google/mlkit/vision/face/aidls/IFaceDetector.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.mlkit.vision.face.aidls;\n\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport java.util.List;\nimport com.google.mlkit.vision.face.FrameMetadataParcel;\nimport com.google.mlkit.vision.face.aidls.FaceParcel;\n\ninterface IFaceDetector {\n    void initDetector() = 0;\n    void close() = 1;\n    List<FaceParcel> detectFaces(IObjectWrapper wrapper, in FrameMetadataParcel metadata) = 2;\n}"
  },
  {
    "path": "play-services-mlkit/face-detection/src/main/aidl/com/google/mlkit/vision/face/aidls/IFaceDetectorCreator.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.mlkit.vision.face.aidls;\n\nimport com.google.mlkit.vision.face.aidls.IFaceDetector;\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.mlkit.vision.face.FaceDetectionOptions;\n\ninterface IFaceDetectorCreator {\n    IFaceDetector newFaceDetector(IObjectWrapper context, in FaceDetectionOptions faceDetectionOptions) = 0;\n}"
  },
  {
    "path": "play-services-mlkit/face-detection/src/main/java/com/google/mlkit/vision/face/Face.java",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.mlkit.vision.face;\n\nimport android.graphics.Rect;\n\nimport android.util.SparseArray;\nimport androidx.annotation.NonNull;\n\nimport androidx.annotation.Nullable;\nimport com.google.mlkit.vision.face.aidls.ContourParcel;\nimport com.google.mlkit.vision.face.aidls.FaceParcel;\nimport com.google.mlkit.vision.face.aidls.LandmarkParcel;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class Face {\n    @NonNull\n    private final Rect boundingBox;\n    private final int trackingId;\n    private final float rightEyeOpenProbability;\n    private final float leftEyeOpenProbability;\n    private final float smileProbability;\n    private final float eulerX;\n    private final float eulerY;\n    private final float eulerZ;\n    @NonNull\n    private final SparseArray<FaceLandmark> landmarks = new SparseArray<>();\n    @NonNull\n    private final SparseArray<FaceContour> contours = new SparseArray<>();\n\n    private static boolean isValidLandmarkType(int landmarkType) {\n        return landmarkType == 0 || landmarkType == 1 || (landmarkType >= 3 && landmarkType <= 7) || (landmarkType >= 9 && landmarkType <= 11);\n    }\n\n    private static boolean isValidContourType(int contourType) {\n        return contourType >= 1 && contourType <= 15;\n    }\n\n    @Hide\n    public Face(FaceParcel faceParcel) {\n        boundingBox = faceParcel.boundingBox;\n        trackingId = faceParcel.id;\n        for (LandmarkParcel landmarkParcel : faceParcel.landmarkParcelList) {\n            if (isValidLandmarkType(landmarkParcel.type)) {\n                landmarks.put(landmarkParcel.type, new FaceLandmark(landmarkParcel.type, landmarkParcel.position));\n            }\n        }\n        for (ContourParcel contourParcel : faceParcel.contourParcelList) {\n            if (isValidContourType(contourParcel.type)) {\n                contours.put(contourParcel.type, new FaceContour(contourParcel.type, contourParcel.pointsList));\n            }\n        }\n        eulerX = faceParcel.tiltAngle;\n        eulerY = faceParcel.panAngle;\n        eulerZ = faceParcel.rollAngle;\n        smileProbability = faceParcel.smileProbability;\n        leftEyeOpenProbability = faceParcel.leftEyeOpenProbability;\n        rightEyeOpenProbability = faceParcel.rightEyeOpenProbability;\n    }\n\n    /**\n     * Gets a list of all available {@link FaceContour}s. All {@link FaceContour}s are defined in {@link FaceContour.ContourType}. If no contours are available, an\n     * empty list is returned.\n     */\n    @NonNull\n    public List<FaceContour> getAllContours() {\n        List<FaceContour> list = new ArrayList<>();\n        for (int i = 0; i < contours.size(); i++) {\n            list.add(contours.valueAt(i));\n        }\n        return list;\n    }\n\n    /**\n     * Gets a list of all available {@link FaceLandmark}s. All possible {@link FaceLandmark}s are defined in {@link FaceLandmark.LandmarkType}. If no landmarks are\n     * available, an empty list is returned.\n     */\n    @NonNull\n    public List<FaceLandmark> getAllLandmarks() {\n        List<FaceLandmark> list = new ArrayList<>();\n        for (int i = 0; i < landmarks.size(); i++) {\n            list.add(landmarks.valueAt(i));\n        }\n        return list;\n    }\n\n    /**\n     * Returns the {@code NonNull} axis-aligned bounding rectangle of the detected face.\n     */\n    @NonNull\n    public Rect getBoundingBox() {\n        return boundingBox;\n    }\n\n    /**\n     * Gets contour based on the provided {@link FaceContour.ContourType}. It returns {@code null} if the contour is not available.\n     */\n    @Nullable\n    public FaceContour getContour(@FaceContour.ContourType int contourType) {\n        return contours.get(contourType);\n    }\n\n    /**\n     * Returns the rotation of the face about the horizontal axis of the image, in degrees. Positive euler X is the face is looking up.\n     *\n     * @return the rotation of the face about the horizontal axis of the image\n     */\n    public Float getHeadEulerAngleX() {\n        return eulerX;\n    }\n\n    /**\n     * Returns the rotation of the face about the vertical axis of the image, in degrees. Positive euler y is when the face turns toward the right side\n     * of the image that is being processed.\n     *\n     * @return the rotation of the face about the vertical axis of the image\n     */\n    public Float getHeadEulerAngleY() {\n        return eulerY;\n    }\n\n    /**\n     * Returns the rotation of the face about the axis pointing out of the image, in degrees. Positive euler z is a counter-clockwise rotation within the image plane.\n     */\n    public Float getHeadEulerAngleZ() {\n        return eulerZ;\n    }\n\n    /**\n     * Gets a {@link FaceLandmark} based on the provided {@link FaceLandmark.LandmarkType}. It returns {@code null} if the landmark type is not available.\n     */\n    public FaceLandmark getLandmark(@FaceLandmark.LandmarkType int landmarkType) {\n        return landmarks.get(landmarkType);\n    }\n\n    /**\n     * Returns a value between 0.0 and 1.0 giving a probability that the face's left eye is open. This returns {@code null} if the probability was not\n     * computed. The probability is not computed if classification is not enabled via\n     * {@link FaceDetectorOptions.Builder#setClassificationMode(int)} or the feature is not available.\n     */\n    public Float getLeftEyeOpenProbability() {\n        if (leftEyeOpenProbability < 0.0f || leftEyeOpenProbability > 1.0f) {\n            return null;\n        }\n        return leftEyeOpenProbability;\n    }\n\n    /**\n     * Returns a value between 0.0 and 1.0 giving a probability that the face's right eye is open. This returns {@code null} if the probability was not\n     * computed. The probability is not computed if classification is not enabled via\n     * {@link FaceDetectorOptions.Builder#setClassificationMode(int)} or the feature is not available.\n     */\n    public Float getRightEyeOpenProbability() {\n        if (rightEyeOpenProbability < 0.0f || rightEyeOpenProbability > 1.0f) {\n            return null;\n        }\n        return rightEyeOpenProbability;\n    }\n\n    /**\n     * Returns a value between 0.0 and 1.0 giving a probability that the face is smiling. This returns {@code null} if the probability was not computed.\n     * The probability is not computed if classification is not enabled via {@link FaceDetectorOptions.Builder#setClassificationMode(int)} or the\n     * required landmarks are not found.\n     */\n    public Float getSmilingProbability() {\n        if (smileProbability < 0.0f || smileProbability > 1.0f) {\n            return null;\n        }\n        return smileProbability;\n    }\n\n    /**\n     * Returns the tracking ID if the tracking is enabled. Otherwise, returns {@code null}.\n     */\n    public Integer getTrackingId() {\n        if (trackingId == -1) {\n            return null;\n        }\n        return trackingId;\n    }\n\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"Face\")\n                .field(\"boundingBox\", boundingBox)\n                .field(\"trackingId\", trackingId)\n                .field(\"rightEyeOpenProbability\", rightEyeOpenProbability)\n                .field(\"leftEyeOpenProbability\", leftEyeOpenProbability)\n                .field(\"smileProbability\", smileProbability)\n                .field(\"eulerX\", eulerX)\n                .field(\"eulerY\", eulerY)\n                .field(\"eulerZ\", eulerZ)\n                .field(\"landmarks\", landmarks)\n                .field(\"contours\", contours)\n                .toString();\n    }\n}\n"
  },
  {
    "path": "play-services-mlkit/face-detection/src/main/java/com/google/mlkit/vision/face/FaceContour.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.mlkit.vision.face;\n\nimport android.graphics.PointF;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\n\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.List;\n\n/**\n * Represent a face contour. A contour is a list of points on a detected face, such as the mouth.\n * <p>\n * When 'left' and 'right' are used, they are relative to the subject in the image. For example, the {@link #LEFT_EYE} landmark is the subject's left eye,\n * not the eye that is on the left when viewing the image.\n */\npublic class FaceContour {\n\n    /**\n     * The outline of the subject's face.\n     */\n    public static final int FACE = 1;\n    /**\n     * The top outline of the subject's left eyebrow.\n     */\n    public static final int LEFT_EYEBROW_TOP = 2;\n    /**\n     * The bottom outline of the subject's left eyebrow.\n     */\n    public static final int LEFT_EYEBROW_BOTTOM = 3;\n    /**\n     * The top outline of the subject's right eyebrow.\n     */\n    public static final int RIGHT_EYEBROW_TOP = 4;\n    /**\n     * The bottom outline of the subject's right eyebrow.\n     */\n    public static final int RIGHT_EYEBROW_BOTTOM = 5;\n    /**\n     * The outline of the subject's left eye.\n     */\n    public static final int LEFT_EYE = 6;\n    /**\n     * The outline of the subject's right eye.\n     */\n    public static final int RIGHT_EYE = 7;\n    /**\n     * The top outline of the subject's upper lip.\n     */\n    public static final int UPPER_LIP_TOP = 8;\n    /**\n     * The bottom outline of the subject's upper lip.\n     */\n    public static final int UPPER_LIP_BOTTOM = 9;\n    /**\n     * The top outline of the subject's lower lip.\n     */\n    public static final int LOWER_LIP_TOP = 10;\n    /**\n     * The bottom outline of the subject's lower lip.\n     */\n    public static final int LOWER_LIP_BOTTOM = 11;\n    /**\n     * the outline of the subject's nose bridge.\n     */\n    public static final int NOSE_BRIDGE = 12;\n    /**\n     * The outline of the subject's nose bridge.\n     */\n    public static final int NOSE_BOTTOM = 13;\n    /**\n     * The center of the left cheek.\n     */\n    public static final int LEFT_CHEEK = 14;\n    /**\n     * The center of the right cheek.\n     */\n    public static final int RIGHT_CHEEK = 15;\n\n    @Retention(RetentionPolicy.CLASS)\n    @IntDef(value = {FACE, LEFT_EYEBROW_TOP, LEFT_EYEBROW_BOTTOM, RIGHT_EYEBROW_TOP, RIGHT_EYEBROW_BOTTOM, LEFT_EYE, RIGHT_EYE, UPPER_LIP_TOP, UPPER_LIP_BOTTOM, LOWER_LIP_TOP, LOWER_LIP_BOTTOM, NOSE_BRIDGE, NOSE_BOTTOM, LEFT_CHEEK, RIGHT_CHEEK})\n    public @interface ContourType {\n    }\n\n    private final @ContourType int type;\n    @NonNull\n    private final List<PointF> points;\n\n    FaceContour(@ContourType int type, @NonNull List<PointF> points) {\n        this.type = type;\n        this.points = points;\n    }\n\n    /**\n     * Gets the {@link FaceContour.ContourType} type.\n     */\n    @FaceContour.ContourType\n    public int getFaceContourType() {\n        return type;\n    }\n\n    /**\n     * Gets a list of 2D points for this face contour, where (0, 0) is the upper-left corner of the image. The point is guaranteed to be within the\n     * bounds of the image.\n     */\n    @NonNull\n    public List<PointF> getPoints() {\n        return points;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"FaceContour\").field(\"type\", type).field(\"points\", points.toArray()).toString();\n    }\n}\n"
  },
  {
    "path": "play-services-mlkit/face-detection/src/main/java/com/google/mlkit/vision/face/FaceDetectionOptions.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.mlkit.vision.face;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.concurrent.Executor;\n\n@SafeParcelable.Class\npublic class FaceDetectionOptions extends AbstractSafeParcelable {\n\n    public static final int CLASSIFICATION_MODE_ALL = 2;\n    public static final int CLASSIFICATION_MODE_NONE = 1;\n    public static final int CONTOUR_MODE_ALL = 2;\n    public static final int CONTOUR_MODE_NONE = 1;\n    public static final int LANDMARK_MODE_ALL = 2;\n    public static final int LANDMARK_MODE_NONE = 1;\n    public static final int PERFORMANCE_MODE_ACCURATE = 2;\n    public static final int PERFORMANCE_MODE_FAST = 1;\n\n    @Retention(RetentionPolicy.CLASS)\n    @IntDef(value = {CLASSIFICATION_MODE_NONE, CLASSIFICATION_MODE_ALL})\n    public @interface ClassificationMode {\n    }\n\n    @Retention(RetentionPolicy.CLASS)\n    @IntDef(value = {CONTOUR_MODE_NONE, CONTOUR_MODE_ALL})\n    public @interface ContourMode {\n    }\n\n    @Retention(RetentionPolicy.CLASS)\n    @IntDef(value = {LANDMARK_MODE_NONE, LANDMARK_MODE_ALL})\n    public @interface LandmarkMode {\n    }\n\n    @Retention(RetentionPolicy.CLASS)\n    @IntDef(value = {PERFORMANCE_MODE_FAST, PERFORMANCE_MODE_ACCURATE})\n    public @interface PerformanceMode {\n    }\n\n    @Field(1)\n    private final int landmarkMode;\n    @Field(2)\n    private final int contourMode;\n    @Field(3)\n    private final int classificationMode;\n    @Field(4)\n    private final int performanceMode;\n    @Field(5)\n    private final boolean trackingEnabled;\n    @Field(6)\n    private final float minFaceSize;\n    private Executor executor;\n\n    @Constructor\n    FaceDetectionOptions(@Param(1) int landmarkMode, @Param(2) int contourMode, @Param(3) int classificationMode, @Param(4) int performanceMode, @Param(5) boolean trackingEnabled, @Param(6) float minFaceSize) {\n        this.landmarkMode = landmarkMode;\n        this.contourMode = contourMode;\n        this.classificationMode = classificationMode;\n        this.performanceMode = performanceMode;\n        this.trackingEnabled = trackingEnabled;\n        this.minFaceSize = minFaceSize;\n    }\n\n    public Executor getExecutor() {\n        return executor;\n    }\n\n    public void setExecutor(Executor executor) {\n        this.executor = executor;\n    }\n\n    public static class Builder {\n        private int landmarkMode;\n        private int contourMode;\n        private int classificationMode;\n        private int performanceMode;\n        private boolean trackingEnabled;\n        private float minFaceSize;\n        private Executor executor;\n\n        public Builder enableTracking(boolean enable) {\n            this.trackingEnabled = enable;\n            return this;\n        }\n\n        public Builder setClassificationMode(@ClassificationMode int mode) {\n            this.classificationMode = mode;\n            return this;\n        }\n\n        public Builder setContourMode(@ContourMode int mode) {\n            this.contourMode = mode;\n            return this;\n        }\n\n        public Builder setExecutor(Executor executor) {\n            this.executor = executor;\n            return this;\n        }\n\n        public Builder setLandmarkMode(@LandmarkMode int mode) {\n            this.landmarkMode = mode;\n            return this;\n        }\n\n        public Builder setMinFaceSize(float minFaceSize) {\n            this.minFaceSize = minFaceSize;\n            return this;\n        }\n\n        public Builder setPerformanceMode(@PerformanceMode int mode) {\n            this.performanceMode = mode;\n            return this;\n        }\n\n        public FaceDetectionOptions build() {\n            FaceDetectionOptions faceDetectionOptions = new FaceDetectionOptions(landmarkMode, contourMode, classificationMode, performanceMode, trackingEnabled, minFaceSize);\n            if (executor != null) {\n                faceDetectionOptions.setExecutor(executor);\n            }\n            return faceDetectionOptions;\n        }\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<FaceDetectionOptions> CREATOR = findCreator(FaceDetectionOptions.class);\n\n}\n"
  },
  {
    "path": "play-services-mlkit/face-detection/src/main/java/com/google/mlkit/vision/face/FaceLandmark.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.mlkit.vision.face;\n\nimport android.graphics.PointF;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\n\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\n/**\n * Represent a face landmark. A landmark is a point on a detected face, such as an eye, nose, or mouth.\n * <p>\n * When 'left' and 'right' are used, they are relative to the subject in the image. For example, the {@link #LEFT_EYE} landmark is the subject's left eye,\n * not the eye that is on the left when viewing the image.\n */\npublic class FaceLandmark {\n    /**\n     * The center of the subject's bottom lip.\n     */\n    public static final int MOUTH_BOTTOM = 0;\n    /**\n     * The midpoint between the subject's left mouth corner and the outer corner of the subject's left eye. For full profile faces, this becomes the\n     * centroid of the nose base, nose tip, left ear lobe and left ear tip.\n     */\n    public static final int LEFT_CHEEK = 1;\n    /**\n     * The midpoint of the subject's left ear tip and left ear lobe.\n     */\n    public static final int LEFT_EAR = 3;\n    /**\n     * The center of the subject's left eye cavity.\n     */\n    public static final int LEFT_EYE = 4;\n    /**\n     * The subject's left mouth corner where the lips meet.\n     */\n    public static final int MOUTH_LEFT = 5;\n    /**\n     * The midpoint between the subject's nostrils where the nose meets the face.\n     */\n    public static final int NOSE_BASE = 6;\n    /**\n     * The midpoint between the subject's right mouth corner and the outer corner of the subject's right eye. For full profile faces, this becomes the\n     * centroid of the nose base, nose tip, right ear lobe and right ear tip.\n     */\n    public static final int RIGHT_CHEEK = 7;\n    /**\n     * The midpoint of the subject's right ear tip and right ear lobe.\n     */\n    public static final int RIGHT_EAR = 9;\n    /**\n     * The center of the subject's right eye cavity.\n     */\n    public static final int RIGHT_EYE = 10;\n    /**\n     * The subject's right mouth corner where the lips meet.\n     */\n    public static final int MOUTH_RIGHT = 11;\n\n    @Retention(RetentionPolicy.CLASS)\n    @IntDef(value = {MOUTH_BOTTOM, LEFT_CHEEK, LEFT_EAR, LEFT_EYE, MOUTH_LEFT, NOSE_BASE, RIGHT_CHEEK, RIGHT_EAR, RIGHT_EYE, MOUTH_RIGHT})\n    public @interface LandmarkType {\n    }\n\n    private final @LandmarkType int type;\n    @NonNull\n    private final PointF position;\n\n    FaceLandmark(@LandmarkType int type, @NonNull PointF position) {\n        this.type = type;\n        this.position = position;\n    }\n\n    /**\n     * Gets the {@link FaceLandmark.LandmarkType} type.\n     */\n    @LandmarkType\n    public int getLandmarkType() {\n        return type;\n    }\n\n    /**\n     * Gets a 2D point for landmark position, where (0, 0) is the upper-left corner of the image. The point is guaranteed to be within the bounds of\n     * the image.\n     */\n    @NonNull\n    public PointF getPosition() {\n        return position;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"FaceLandmark\").field(\"type\", type).field(\"position\", position).toString();\n    }\n}\n"
  },
  {
    "path": "play-services-mlkit/face-detection/src/main/java/com/google/mlkit/vision/face/FrameMetadataParcel.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.mlkit.vision.face;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class FrameMetadataParcel extends AbstractSafeParcelable {\n\n    @Field(1)\n    public int format;\n    @Field(2)\n    public int width;\n    @Field(3)\n    public int height;\n    @Field(4)\n    public int rotation;\n    @Field(5)\n    public long timestampMillis;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<FrameMetadataParcel> CREATOR = findCreator(FrameMetadataParcel.class);\n\n}\n"
  },
  {
    "path": "play-services-mlkit/face-detection/src/main/java/com/google/mlkit/vision/face/aidls/ContourParcel.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.mlkit.vision.face.aidls;\n\nimport android.graphics.PointF;\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport java.util.List;\n\n@SafeParcelable.Class\npublic class ContourParcel extends AbstractSafeParcelable {\n    @Field(1)\n    public final int type;\n    @Field(2)\n    public final List<PointF> pointsList;\n\n    @Constructor\n    public ContourParcel(@Param(1) int type, @Param(2) List<PointF> pointsList) {\n        this.type = type;\n        this.pointsList = pointsList;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<ContourParcel> CREATOR = findCreator(ContourParcel.class);\n}\n"
  },
  {
    "path": "play-services-mlkit/face-detection/src/main/java/com/google/mlkit/vision/face/aidls/FaceParcel.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.mlkit.vision.face.aidls;\n\nimport android.graphics.Rect;\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport java.util.List;\n\n@SafeParcelable.Class\npublic class FaceParcel extends AbstractSafeParcelable {\n    @Field(1)\n    public final int id;\n\n    @Field(2)\n    public final Rect boundingBox;\n\n    @Field(3)\n    public final float rollAngle;\n\n    @Field(4)\n    public final float panAngle;\n\n    @Field(5)\n    public final float tiltAngle;\n\n    @Field(6)\n    public final float leftEyeOpenProbability;\n\n    @Field(7)\n    public final float rightEyeOpenProbability;\n\n    @Field(8)\n    public final float smileProbability;\n\n    @Field(9)\n    public final float confidenceScore;\n\n    @Field(10)\n    public final List<LandmarkParcel> landmarkParcelList;\n\n    @Field(11)\n    public final List<ContourParcel> contourParcelList;\n\n    @Constructor\n    public FaceParcel(@Param(1) int id, @Param(2) Rect boundingBox, @Param(3) float rollAngle, @Param(4) float panAngle, @Param(5) float tiltAngle, @Param(6) float leftEyeOpenProbability, @Param(7) float rightEyeOpenProbability, @Param(8) float smileProbability, @Param(9) float confidenceScore, @Param(10) List<LandmarkParcel> landmarkParcelList, @Param(11) List<ContourParcel> contourParcelList) {\n        this.id = id;\n        this.boundingBox = boundingBox;\n        this.rollAngle = rollAngle;\n        this.panAngle = panAngle;\n        this.tiltAngle = tiltAngle;\n        this.leftEyeOpenProbability = leftEyeOpenProbability;\n        this.rightEyeOpenProbability = rightEyeOpenProbability;\n        this.smileProbability = smileProbability;\n        this.confidenceScore = confidenceScore;\n        this.landmarkParcelList = landmarkParcelList;\n        this.contourParcelList = contourParcelList;\n    }\n\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<FaceParcel> CREATOR = findCreator(FaceParcel.class);\n}\n"
  },
  {
    "path": "play-services-mlkit/face-detection/src/main/java/com/google/mlkit/vision/face/aidls/LandmarkParcel.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.mlkit.vision.face.aidls;\n\nimport android.graphics.PointF;\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class LandmarkParcel extends AbstractSafeParcelable {\n    @Field(1)\n    public final int type;\n    @Field(2)\n    public final PointF position;\n\n    @Constructor\n    public LandmarkParcel(@Param(1) int type, @Param(2) PointF position) {\n        this.type = type;\n        this.position = position;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<LandmarkParcel> CREATOR = findCreator(LandmarkParcel.class);\n}\n"
  },
  {
    "path": "play-services-nearby/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2020 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\nandroid {\n    namespace \"com.google.android.gms.nearby\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n}\n\napply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG implementation of play-services-nearby'\n\ndependencies {\n    // Dependencies from play-services-nearby:18.0.2\n    api \"androidx.collection:collection:1.0.0\"\n    api \"androidx.core:core:1.0.0\"\n    api project(':play-services-base')\n    api project(':play-services-basement')\n    api project(':play-services-tasks')\n}\n"
  },
  {
    "path": "play-services-nearby/core/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'com.squareup.wire'\napply plugin: 'kotlin-android'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\ndependencies {\n    api project(':play-services-nearby')\n\n    implementation project(':play-services-base-core')\n\n    implementation \"androidx.annotation:annotation:$annotationVersion\"\n    implementation \"androidx.lifecycle:lifecycle-service:$lifecycleVersion\"\n    implementation \"androidx.lifecycle:lifecycle-runtime-ktx:$lifecycleVersion\"\n    implementation \"androidx.navigation:navigation-fragment-ktx:$navigationVersion\"\n    implementation \"androidx.navigation:navigation-ui-ktx:$navigationVersion\"\n    implementation \"androidx.preference:preference:$preferenceVersion\"\n\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion\"\n    implementation \"org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutineVersion\"\n    implementation \"org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutineVersion\"\n\n    implementation \"com.squareup.wire:wire-runtime:$wireVersion\"\n\n    testImplementation 'junit:junit:4.13.2'\n}\n\nandroid {\n    namespace \"org.microg.gms.nearby.core\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    buildFeatures {\n        dataBinding = true\n    }\n\n    sourceSets {\n        main {\n            java.srcDirs = ['src/main/kotlin']\n        }\n    }\n\n    lintOptions {\n        disable 'MissingTranslation', 'GetLocales'\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n\n    kotlinOptions {\n        jvmTarget = 1.8\n    }\n}\n\nwire {\n    kotlin {}\n}\n\napply from: '../../gradle/publish-android.gradle'\n\ndescription = 'microG service implementation for play-services-nearby'\n"
  },
  {
    "path": "play-services-nearby/core/package/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'kotlin-android'\n\ndependencies {\n    implementation project(':play-services-base-core')\n    implementation project(':play-services-nearby-core')\n    implementation \"androidx.navigation:navigation-fragment-ktx:$navigationVersion\"\n    implementation \"androidx.navigation:navigation-ui-ktx:$navigationVersion\"\n    implementation \"androidx.preference:preference:$preferenceVersion\"\n}\n\nandroid {\n    namespace \"org.microg.gms.nearby.core.pkg\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    sourceSets {\n        main {\n            java.srcDirs = ['src/main/kotlin']\n        }\n    }\n\n    lintOptions {\n        disable 'MissingTranslation'\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n\n    kotlinOptions {\n        jvmTarget = 1.8\n    }\n}\n"
  },
  {
    "path": "play-services-nearby/core/package/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <uses-permission android:name=\"android.permission.BLUETOOTH\" />\n    <uses-permission android:name=\"android.permission.BLUETOOTH_ADMIN\" />\n    <uses-permission android:name=\"android.permission.BLUETOOTH_ADVERTISE\" />\n    <uses-permission android:name=\"android.permission.BLUETOOTH_CONNECT\" />\n    <uses-permission android:name=\"android.permission.BLUETOOTH_SCAN\" />\n\n    <uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\" />\n    <uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\" />\n    <uses-permission android:name=\"android.permission.ACCESS_BACKGROUND_LOCATION\" />\n\n    <permission\n        android:name=\"com.google.android.gms.nearby.exposurenotification.EXPOSURE_CALLBACK\"\n        android:protectionLevel=\"normal\" />\n\n    <application>\n        <meta-data\n            android:name=\"org.microg.gms.ui.settings.entry:nearby-exposurenotifications\"\n            android:value=\"org.microg.gms.nearby.exposurenotification.ui.ExposureNotificationsSettingsProvider\" />\n    </application>\n</manifest>"
  },
  {
    "path": "play-services-nearby/core/package/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ui/ExposureNotificationsSettingsProvider.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.nearby.exposurenotification.ui\n\nimport android.content.Context\nimport android.content.Intent\nimport android.net.Uri\nimport android.os.Build.VERSION.SDK_INT\nimport androidx.annotation.Keep\nimport androidx.appcompat.content.res.AppCompatResources\nimport androidx.navigation.NavController\nimport com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient\nimport org.microg.gms.ui.settings.SettingsProvider\nimport org.microg.gms.nearby.core.R\nimport org.microg.gms.nearby.exposurenotification.ExposureDatabase\nimport org.microg.gms.nearby.exposurenotification.ExposurePreferences\nimport org.microg.gms.ui.settings.SettingsProvider.Companion.Entry\nimport org.microg.gms.ui.settings.SettingsProvider.Companion.Group.OTHER\n\n@Keep\nobject ExposureNotificationsSettingsProvider : SettingsProvider {\n    override fun getEntriesStatic(context: Context): List<Entry> {\n        if (SDK_INT < 21) return emptyList()\n        if (!ExposurePreferences(context).enabled) return emptyList()\n        return getEntries(context)\n    }\n\n    override suspend fun getEntriesDynamic(context: Context): List<Entry> {\n        if (SDK_INT < 21) return emptyList()\n        if (!ExposurePreferences(context).enabled) {\n            if (ExposureDatabase.with(context) { it.isEmpty }) {\n                return emptyList()\n            }\n        }\n        return getEntries(context)\n    }\n\n    private fun getEntries(context: Context) = listOf(\n        Entry(\n            key = \"pref_exposure\",\n            group = OTHER,\n            navigationId = R.id.exposureNotificationsFragment,\n            title = context.getString(R.string.service_name_exposure),\n            summary = if (ExposurePreferences(context).enabled) {\n                context.getString(org.microg.gms.base.core.R.string.service_status_enabled_short)\n            } else {\n                context.getString(org.microg.gms.base.core.R.string.service_status_disabled_short)\n            },\n            icon = AppCompatResources.getDrawable(context, R.drawable.ic_virus_outline)\n        )\n    )\n\n    override fun preProcessSettingsIntent(intent: Intent) {\n        if (ExposureNotificationClient.ACTION_EXPOSURE_NOTIFICATION_SETTINGS == intent.action && intent.data == null) {\n            intent.data = Uri.parse(\"x-gms-settings://exposure-notifications\")\n        }\n    }\n\n    override fun extendNavigation(navController: NavController) {\n        navController.graph.addAll(navController.navInflater.inflate(R.navigation.nav_nearby))\n    }\n}"
  },
  {
    "path": "play-services-nearby/core/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2020 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <uses-permission android:name=\"android.permission.RECEIVE_BOOT_COMPLETED\" />\n    <uses-permission android:name=\"com.google.android.gms.nearby.exposurenotification.EXPOSURE_CALLBACK\" />\n    <uses-permission android:name=\"android.permission.POST_NOTIFICATIONS\" />\n\n    <application>\n\n        <!-- Exposure Notifications -->\n\n        <service\n            android:name=\"org.microg.gms.nearby.exposurenotification.ScannerService\"\n            android:process=\":persistent\" />\n        <service\n            android:name=\"org.microg.gms.nearby.exposurenotification.AdvertiserService\"\n            android:process=\":persistent\" />\n        <service\n            android:name=\"org.microg.gms.nearby.exposurenotification.CleanupService\"\n            android:process=\":persistent\" />\n        <service\n            android:name=\"org.microg.gms.nearby.exposurenotification.NotifyService\"\n            android:process=\":persistent\" />\n\n        <service\n            android:name=\"org.microg.gms.nearby.exposurenotification.ExposureNotificationService\"\n            android:process=\":persistent\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.nearby.exposurenotification.START\" />\n            </intent-filter>\n        </service>\n\n        <receiver\n            android:name=\"org.microg.gms.nearby.exposurenotification.ServiceTrigger\"\n            android:process=\":persistent\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.BOOT_COMPLETED\" />\n\n                <action android:name=\"android.intent.action.MY_PACKAGE_REPLACED\" />\n                <action android:name=\"android.intent.action.PACKAGE_RESTARTED\" />\n            </intent-filter>\n        </receiver>\n\n        <provider\n            android:name=\"org.microg.gms.nearby.exposurenotification.ExposureFileProvider\"\n            android:authorities=\"${applicationId}.microg.exposure.export\"\n            android:exported=\"false\"\n            android:grantUriPermissions=\"true\">\n            <meta-data\n                android:name=\"android.support.FILE_PROVIDER_PATHS\"\n                android:resource=\"@xml/preferences_exposure_notifications_exportedfiles\" />\n        </provider>\n\n        <activity\n            android:name=\"org.microg.gms.nearby.exposurenotification.ui.ExposureNotificationsConfirmActivity\"\n            android:exported=\"false\"\n            android:process=\":ui\"\n            android:theme=\"@style/Theme.AppCompat.DayNight.Dialog.Alert.NoActionBar\">\n            <intent-filter>\n                <action android:name=\"org.microg.gms.nearby.exposurenotification.CONFIRM\" />\n            </intent-filter>\n        </activity>\n        <activity\n            android:name=\"org.microg.gms.nearby.exposurenotification.ui.ExposureNotificationsSettingsActivity\"\n            android:exported=\"false\"\n            android:process=\":ui\"\n            android:theme=\"@style/Theme.AppCompat.DayNight\">\n            <intent-filter android:priority=\"-100\">\n                <action android:name=\"com.google.android.gms.settings.EXPOSURE_NOTIFICATION_SETTINGS\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </activity>\n    </application>\n</manifest>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/AdvertiserService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.nearby.exposurenotification\n\nimport android.annotation.SuppressLint\nimport android.annotation.TargetApi\nimport android.app.AlarmManager\nimport android.app.PendingIntent.FLAG_ONE_SHOT\nimport android.app.PendingIntent.FLAG_UPDATE_CURRENT\nimport android.bluetooth.BluetoothAdapter.*\nimport android.bluetooth.le.*\nimport android.bluetooth.le.AdvertiseSettings.*\nimport android.content.BroadcastReceiver\nimport android.content.Context\nimport android.content.Intent\nimport android.content.IntentFilter\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.Handler\nimport android.os.Looper\nimport android.os.SystemClock\nimport android.util.Log\nimport androidx.core.app.PendingIntentCompat\nimport androidx.lifecycle.LifecycleService\nimport androidx.lifecycle.lifecycleScope\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\nimport org.microg.gms.common.ForegroundServiceContext\nimport org.microg.gms.common.ForegroundServiceInfo\nimport java.io.FileDescriptor\nimport java.io.PrintWriter\nimport java.nio.ByteBuffer\nimport java.util.*\n\n@TargetApi(21)\n@ForegroundServiceInfo(\"Exposure Notification\")\nclass AdvertiserService : LifecycleService() {\n    private val version = VERSION_1_1\n    private var advertising = false\n    private var wantStartAdvertising = false\n    private val advertiser: BluetoothLeAdvertiser?\n        get() = getDefaultAdapter()?.bluetoothLeAdvertiser\n    private val alarmManager: AlarmManager\n        get() = getSystemService(Context.ALARM_SERVICE) as AlarmManager\n    private val callback: AdvertiseCallback = object : AdvertiseCallback() {\n        override fun onStartSuccess(settingsInEffect: AdvertiseSettings?) {\n            Log.d(TAG, \"Advertising active for ${settingsInEffect?.timeout}ms\")\n        }\n\n        override fun onStartFailure(errorCode: Int) {\n            Log.w(TAG, \"Advertising failed: $errorCode\")\n            stopOrRestartAdvertising()\n        }\n    }\n\n    @TargetApi(23)\n    private var setCallback: Any? = null\n    private val trigger = object : BroadcastReceiver() {\n        override fun onReceive(context: Context?, intent: Intent?) {\n            if (intent?.action == ACTION_STATE_CHANGED) {\n                when (intent.getIntExtra(EXTRA_STATE, -1)) {\n                    STATE_TURNING_OFF, STATE_OFF -> stopOrRestartAdvertising()\n                    STATE_ON -> startAdvertisingIfNeeded()\n                }\n            }\n        }\n    }\n    private val handler = Handler(Looper.getMainLooper())\n    private val startLaterRunnable = Runnable { startAdvertisingIfNeeded() }\n\n    override fun onCreate() {\n        super.onCreate()\n        registerReceiver(trigger, IntentFilter().apply { addAction(ACTION_STATE_CHANGED) })\n    }\n\n    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {\n        ForegroundServiceContext.completeForegroundService(this, intent, TAG)\n        Log.d(TAG, \"AdvertisingService.start: $intent\")\n        super.onStartCommand(intent, flags, startId)\n        if (intent?.action == ACTION_RESTART_ADVERTISING && advertising) {\n            stopOrRestartAdvertising()\n        } else {\n            startAdvertisingIfNeeded()\n        }\n        return START_STICKY\n    }\n\n    override fun onDestroy() {\n        super.onDestroy()\n        unregisterReceiver(trigger)\n        stopOrRestartAdvertising()\n        handler.removeCallbacks(startLaterRunnable)\n    }\n\n    private fun startAdvertisingIfNeeded() {\n        if (ExposurePreferences(this).enabled) {\n            lifecycleScope.launchWhenStarted {\n                withContext(Dispatchers.IO) {\n                    startAdvertising()\n                }\n            }\n        } else {\n            stopSelf()\n        }\n    }\n\n    private var lastStartTime = System.currentTimeMillis()\n    private var sendingBytes = ByteArray(0)\n    private var starting = false\n\n    @SuppressLint(\"MissingPermission\")\n    private suspend fun startAdvertising() {\n        val advertiser = synchronized(this) {\n            if (advertising || starting) return\n            val advertiser = advertiser ?: return\n            wantStartAdvertising = false\n            starting = true\n            advertiser\n        }\n        try {\n            val aemBytes = when (version) {\n                VERSION_1_0 -> byteArrayOf(\n                        version, // Version and flags\n                        currentDeviceInfo.txPowerCorrection, // TX power\n                        0x00, // Reserved\n                        0x00  // Reserved\n                )\n                VERSION_1_1 -> byteArrayOf(\n                        (version + currentDeviceInfo.confidence.toByte() * 4).toByte(), // Version and flags\n                        currentDeviceInfo.txPowerCorrection, // TX power\n                        0x00, // Reserved\n                        0x00  // Reserved\n                )\n                else -> return\n            }\n            var nextSend = nextKeyMillis.coerceAtLeast(10000)\n            val payload = ExposureDatabase.with(this@AdvertiserService) { database ->\n                database.generateCurrentPayload(aemBytes)\n            }\n            val data = AdvertiseData.Builder().addServiceUuid(SERVICE_UUID).addServiceData(SERVICE_UUID, payload).build()\n            Log.i(TAG, \"Starting advertiser\")\n            if (SDK_INT >= 26) {\n                setCallback = SetCallback()\n                val params = AdvertisingSetParameters.Builder()\n                        .setInterval(AdvertisingSetParameters.INTERVAL_MEDIUM)\n                        .setLegacyMode(true)\n                        .setTxPowerLevel(AdvertisingSetParameters.TX_POWER_LOW)\n                        .setConnectable(false)\n                        .build()\n                try {\n                    advertiser.startAdvertisingSet(params, data, null, null, null, setCallback as AdvertisingSetCallback)\n                } catch (e: SecurityException) {\n                    Log.e(TAG, \"Couldn't start advertising: Need android.permission.BLUETOOTH_ADVERTISE permission.\", )\n                }\n            } else {\n                nextSend = nextSend.coerceAtMost(180000)\n                val settings = Builder()\n                        .setTimeout(nextSend.toInt())\n                        .setAdvertiseMode(ADVERTISE_MODE_BALANCED)\n                        .setTxPowerLevel(ADVERTISE_TX_POWER_LOW)\n                        .setConnectable(false)\n                        .build()\n                try {\n                    advertiser.startAdvertising(settings, data, callback)\n                } catch (e: SecurityException) {\n                    Log.e(TAG, \"Couldn't start advertising.\", )\n                }\n            }\n            synchronized(this) { advertising = true }\n            sendingBytes = payload\n            lastStartTime = System.currentTimeMillis()\n            scheduleRestartAdvertising(nextSend)\n        } finally {\n            synchronized(this) { starting = false }\n        }\n    }\n\n    override fun dump(fd: FileDescriptor?, writer: PrintWriter?, args: Array<out String>?) {\n        writer?.println(\"Advertising: $advertising\")\n        try {\n            val startTime = lastStartTime\n            val bytes = sendingBytes\n            val (uuid, aem) = ByteBuffer.wrap(bytes).let { UUID(it.long, it.long) to it.int }\n            writer?.println(\"\"\"\n                Last advertising:\n                    Since: ${Date(startTime)}\n                    RPI: $uuid\n                    Version: 0x${version.toString(16)}\n                    TX Power: ${currentDeviceInfo.txPowerCorrection}\n                    AEM: 0x${aem.toLong().let { if (it < 0) 0x100000000L + it else it }.toString(16)}\n                \"\"\".trimIndent())\n        } catch (e: Exception) {\n            writer?.println(\"Last advertising: ${e.message ?: e.toString()}\")\n        }\n    }\n\n    private fun scheduleRestartAdvertising(nextSend: Long) {\n        val intent = Intent(this, AdvertiserService::class.java).apply { action = ACTION_RESTART_ADVERTISING }\n        val pendingIntent = PendingIntentCompat.getService(this, ACTION_RESTART_ADVERTISING.hashCode(), intent, FLAG_ONE_SHOT or FLAG_UPDATE_CURRENT, false)!!\n        when {\n            SDK_INT >= 23 ->\n                alarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + nextSend, pendingIntent)\n            else ->\n                alarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + nextSend, pendingIntent)\n        }\n    }\n\n    @Synchronized\n    @SuppressLint(\"MissingPermission\")\n    private fun stopOrRestartAdvertising() {\n        if (!advertising) return\n        Log.i(TAG, \"Stopping advertiser\")\n        advertising = false\n        if (SDK_INT >= 26) {\n            wantStartAdvertising = true\n            try {\n                advertiser?.stopAdvertisingSet(setCallback as AdvertisingSetCallback)\n            } catch (e: SecurityException) {\n                Log.i(TAG, \"Tried calling stopAdvertisingSet without android.permission.BLUETOOTH_ADVERTISE permission.\", )\n            }\n        } else {\n            try {\n                advertiser?.stopAdvertising(callback)\n            } catch (e: SecurityException) {\n                Log.i(TAG, \"stopAdvertising() failed with a SecurityException. Maybe some permissions are missing?\", )\n            }\n        }\n        handler.postDelayed(startLaterRunnable, 1000)\n    }\n\n    @TargetApi(26)\n    inner class SetCallback : AdvertisingSetCallback() {\n        override fun onAdvertisingSetStarted(advertisingSet: AdvertisingSet?, txPower: Int, status: Int) {\n            Log.d(TAG, \"Advertising active, status=$status\")\n        }\n\n        override fun onAdvertisingSetStopped(advertisingSet: AdvertisingSet?) {\n            Log.d(TAG, \"Advertising stopped\")\n            if (wantStartAdvertising) {\n                startAdvertisingIfNeeded()\n            } else {\n                stopOrRestartAdvertising()\n            }\n        }\n    }\n\n\n    companion object {\n        private const val ACTION_RESTART_ADVERTISING = \"org.microg.gms.nearby.exposurenotification.RESTART_ADVERTISING\"\n\n        fun isNeeded(context: Context): Boolean {\n            return ExposurePreferences(context).enabled\n        }\n\n        fun isSupported(context: Context): Boolean? {\n            val adapter = getDefaultAdapter()\n            return when {\n                adapter == null -> false\n                SDK_INT >= 26 && (adapter.isLeExtendedAdvertisingSupported || adapter.isLePeriodicAdvertisingSupported) -> true\n                adapter.state != STATE_ON -> null\n                adapter.bluetoothLeAdvertiser != null -> true\n                else -> false\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-nearby/core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/CleanupService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.nearby.exposurenotification\n\nimport android.app.AlarmManager\nimport android.app.PendingIntent.FLAG_ONE_SHOT\nimport android.app.PendingIntent.FLAG_UPDATE_CURRENT\nimport android.content.Context\nimport android.content.Intent\nimport android.util.Log\nimport androidx.core.app.PendingIntentCompat\nimport androidx.lifecycle.LifecycleService\nimport androidx.lifecycle.lifecycleScope\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.delay\nimport kotlinx.coroutines.launch\nimport kotlinx.coroutines.withContext\nimport org.microg.gms.common.ForegroundServiceContext\nimport org.microg.gms.common.ForegroundServiceInfo\n\n@ForegroundServiceInfo(\"Exposure Notification\")\nclass CleanupService : LifecycleService() {\n    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {\n        ForegroundServiceContext.completeForegroundService(this, intent, TAG)\n        Log.d(TAG, \"CleanupService.start: $intent\")\n        super.onStartCommand(intent, flags, startId)\n        if (isNeeded(this, true)) {\n            lifecycleScope.launchWhenStarted {\n                withContext(Dispatchers.IO) {\n                    var workPending = true\n                    while (workPending) {\n                        ExposureDatabase.with(this@CleanupService) {\n                            workPending = !it.dailyCleanup()\n                        }\n                        if (workPending) delay(5000L)\n                    }\n                    ExposurePreferences(this@CleanupService).lastCleanup = System.currentTimeMillis()\n                }\n                stop()\n            }\n        } else {\n            stop()\n        }\n        return START_NOT_STICKY\n    }\n\n    fun stop() {\n        val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager\n        val pendingIntent = PendingIntentCompat.getService(applicationContext, CleanupService::class.java.name.hashCode(), Intent(applicationContext, CleanupService::class.java), FLAG_ONE_SHOT or FLAG_UPDATE_CURRENT, false)!!\n        alarmManager.set(AlarmManager.RTC, ExposurePreferences(this).lastCleanup + CLEANUP_INTERVAL, pendingIntent)\n        stopSelf()\n    }\n\n    companion object {\n        fun isNeeded(context: Context, now: Boolean = false): Boolean {\n            return ExposurePreferences(context).let {\n                (it.enabled && !now) || it.lastCleanup < System.currentTimeMillis() - CLEANUP_INTERVAL\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-nearby/core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/Constants.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.nearby.exposurenotification\n\nimport android.os.ParcelUuid\nimport com.google.android.gms.nearby.exposurenotification.CalibrationConfidence\nimport java.util.*\n\nconst val TAG = \"ExposureNotification\"\nval SERVICE_UUID = ParcelUuid(UUID.fromString(\"0000FD6F-0000-1000-8000-00805F9B34FB\"))\n\nconst val SCANNING_INTERVAL = 3 * 60 // Google uses 5m, but we use a slightly different scanning and reporting system\nconst val SCANNING_INTERVAL_MS = SCANNING_INTERVAL * 1000L\nconst val SCANNING_TIME = 20 // Google uses 4s + 13s (if Bluetooth is used by something else)\nconst val SCANNING_TIME_MS = SCANNING_TIME * 1000L\n\nconst val ROLLING_WINDOW_LENGTH = 10 * 60\nconst val ROLLING_WINDOW_LENGTH_MS = ROLLING_WINDOW_LENGTH * 1000L\nconst val ROLLING_PERIOD = 144\nconst val ALLOWED_KEY_OFFSET_MS = 60 * 60 * 1000L\nconst val MINIMUM_EXPOSURE_DURATION_MS = 0L\nconst val KEEP_DAYS = 14\n\nconst val ACTION_CONFIRM = \"org.microg.gms.nearby.exposurenotification.CONFIRM\"\nconst val KEY_CONFIRM_ACTION = \"action\"\nconst val KEY_CONFIRM_RECEIVER = \"receiver\"\nconst val KEY_CONFIRM_PACKAGE = \"package\"\nconst val CONFIRM_ACTION_START = \"start\"\nconst val CONFIRM_ACTION_STOP = \"stop\"\nconst val CONFIRM_ACTION_KEYS = \"keys\"\nconst val CONFIRM_PERMISSION_VALIDITY = 60 * 60 * 1000L\n\nconst val PERMISSION_EXPOSURE_CALLBACK = \"com.google.android.gms.nearby.exposurenotification.EXPOSURE_CALLBACK\"\n\nconst val TX_POWER_LOW = -15\n\nconst val ADVERTISER_OFFSET = 60 * 1000\nconst val CLEANUP_INTERVAL = 24 * 60 * 60 * 1000L\n\nconst val VERSION_1_0: Byte = 0x40\nconst val VERSION_1_1: Byte = 0x50\n\nconst val NOTIFICATION_UPDATE_ACTION = \"org.microg.gms.nearby.UPDATE_NOTIFICATION\"\n"
  },
  {
    "path": "play-services-nearby/core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/Crypto.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.nearby.exposurenotification\n\nimport android.annotation.TargetApi\nimport android.util.Log\nimport com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey\nimport java.nio.ByteBuffer\nimport java.nio.ByteOrder\nimport java.nio.charset.StandardCharsets\nimport java.security.SecureRandom\nimport java.util.*\nimport javax.crypto.Cipher\nimport javax.crypto.Mac\nimport javax.crypto.spec.IvParameterSpec\nimport javax.crypto.spec.SecretKeySpec\nimport kotlin.math.floor\n\nprivate const val RPIK_HKDF_INFO = \"EN-RPIK\"\nprivate const val RPIK_ALGORITHM = \"AES\"\n\nprivate const val AEMK_HKDF_INFO = \"EN-AEMK\"\nprivate const val AEMK_ALGORITHM = \"AES\"\n\nprivate const val HKDF_ALGORITHM = \"HmacSHA256\"\nprivate const val HKDF_LENGTH = 16\nprivate const val HASH_LENGTH = 32\n\nprivate const val RPID_ALGORITHM = \"AES/ECB/NoPadding\"\nprivate const val RPID_PREFIX = \"EN-RPI\"\nprivate const val AES_BLOCK_SIZE = 16\n\nprivate const val AEM_ALGORITHM = \"AES/CTR/NoPadding\"\n\nval currentIntervalNumber: Int\n    get() = floor(System.currentTimeMillis() / 1000.0 / ROLLING_WINDOW_LENGTH).toInt()\n\nval currentDayRollingStartNumber: Int\n    get() = getDayRollingStartNumber(currentIntervalNumber)\n\nfun getDayRollingStartNumber(intervalNumber: Int) = (floor(intervalNumber.toDouble() / ROLLING_PERIOD).toLong() * ROLLING_PERIOD).toInt()\nfun getPeriodInDay(intervalNumber: Int) = intervalNumber - getDayRollingStartNumber(intervalNumber)\n\nval nextKeyMillis: Long\n    get() {\n        val currentWindowStart = currentIntervalNumber.toLong() * ROLLING_WINDOW_LENGTH_MS\n        val currentWindowEnd = currentWindowStart + ROLLING_WINDOW_LENGTH_MS\n        return (currentWindowEnd - System.currentTimeMillis()).coerceAtLeast(0)\n    }\n\nfun generateTemporaryExposureKey(intervalNumber: Int): TemporaryExposureKey.TemporaryExposureKeyBuilder = TemporaryExposureKey.TemporaryExposureKeyBuilder().apply {\n    var keyData = ByteArray(16)\n    SecureRandom().nextBytes(keyData)\n    setKeyData(keyData)\n    setRollingStartIntervalNumber(intervalNumber)\n    setRollingPeriod((ROLLING_PERIOD - getPeriodInDay(intervalNumber)))\n}\n\nfun generateCurrentDayTemporaryExposureKey(): TemporaryExposureKey = generateTemporaryExposureKey(currentDayRollingStartNumber).build()\nfun generateIntraDayTemporaryExposureKey(intervalNumber: Int = currentIntervalNumber): TemporaryExposureKey = generateTemporaryExposureKey(intervalNumber).build()\n\n@TargetApi(21)\nfun TemporaryExposureKey.generateRpiKey(): SecretKeySpec {\n    return SecretKeySpec(hkdf(keyData, null, RPIK_HKDF_INFO.toByteArray(StandardCharsets.UTF_8)), RPIK_ALGORITHM)\n}\n\n@TargetApi(21)\nfun TemporaryExposureKey.generateAemKey(): SecretKeySpec {\n    return SecretKeySpec(hkdf(keyData, null, AEMK_HKDF_INFO.toByteArray(StandardCharsets.UTF_8)), AEMK_ALGORITHM)\n}\n\n@TargetApi(21)\nfun TemporaryExposureKey.generateRpiId(intervalNumber: Int): ByteArray {\n    val cipher = Cipher.getInstance(RPID_ALGORITHM)\n    cipher.init(Cipher.ENCRYPT_MODE, generateRpiKey())\n    val data = ByteBuffer.allocate(AES_BLOCK_SIZE).order(ByteOrder.LITTLE_ENDIAN).apply {\n        put(RPID_PREFIX.toByteArray(StandardCharsets.UTF_8))\n        position(12)\n        putInt(intervalNumber)\n    }.array()\n    return cipher.doFinal(data)\n}\n\n@TargetApi(21)\nfun TemporaryExposureKey.generateAllRpiIds(): ByteArray {\n    val cipher = Cipher.getInstance(RPID_ALGORITHM)\n    cipher.init(Cipher.ENCRYPT_MODE, generateRpiKey())\n    val data = ByteBuffer.allocate(AES_BLOCK_SIZE * rollingPeriod).order(ByteOrder.LITTLE_ENDIAN).apply {\n        val prefix = RPID_PREFIX.toByteArray(StandardCharsets.UTF_8)\n        for (i in 0 until rollingPeriod) {\n            put(prefix)\n            position(i * 16 + 12)\n            putInt(rollingStartIntervalNumber + i)\n        }\n    }.array()\n    return cipher.doFinal(data)\n}\n\nfun TemporaryExposureKey.cryptAem(rpi: ByteArray, metadata: ByteArray): ByteArray {\n    val cipher = Cipher.getInstance(AEM_ALGORITHM)\n    cipher.init(Cipher.ENCRYPT_MODE, generateAemKey(), IvParameterSpec(rpi))\n    return cipher.doFinal(metadata)\n}\n\nfun TemporaryExposureKey.generatePayload(intervalNumber: Int, metadata: ByteArray): ByteArray {\n    val rpi = generateRpiId(intervalNumber)\n    val aem = cryptAem(rpi, metadata)\n    return rpi + aem\n}\n\nprivate fun hkdf(inputKeyingMaterial: ByteArray, inputSalt: ByteArray?, info: ByteArray): ByteArray {\n    val mac = Mac.getInstance(HKDF_ALGORITHM)\n    val salt = if (inputSalt == null || inputSalt.isEmpty()) ByteArray(HASH_LENGTH) else inputSalt\n    mac.init(SecretKeySpec(salt, HKDF_ALGORITHM))\n    val pseudoRandomKey = mac.doFinal(inputKeyingMaterial)\n    mac.init(SecretKeySpec(pseudoRandomKey, HKDF_ALGORITHM))\n    mac.update(info)\n    return Arrays.copyOf(mac.doFinal(byteArrayOf(0x01)), HKDF_LENGTH)\n}\n"
  },
  {
    "path": "play-services-nearby/core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/DeviceInfo.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0 AND CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage org.microg.gms.nearby.exposurenotification\n\nimport android.os.Build.DEVICE\nimport android.os.Build.MANUFACTURER\nimport android.os.Build.MODEL\nimport android.util.Log\nimport com.google.android.gms.nearby.exposurenotification.CalibrationConfidence\nimport kotlin.math.roundToInt\n\ndata class DeviceInfo(val oem: String, val device: String, val model: String, val rssiCorrection: Byte, val txPowerCorrection: Byte, @CalibrationConfidence val confidence: Int = CalibrationConfidence.MEDIUM)\n\nprivate var knownDeviceInfo: DeviceInfo? = null\n\nfun averageCurrentDeviceInfo(oem: String, device: String, model: String, deviceInfos: List<DeviceInfo>, @CalibrationConfidence confidence: Int = CalibrationConfidence.LOW): DeviceInfo =\n        DeviceInfo(oem, device, model, deviceInfos.map { it.rssiCorrection }.average().roundToInt().toByte(), deviceInfos.map { it.txPowerCorrection }.average().roundToInt().toByte(), confidence)\n\nval currentDeviceInfo: DeviceInfo\n    get() {\n        var deviceInfo = knownDeviceInfo\n        if (deviceInfo == null) {\n            // Note: Custom ROMs sometimes have slightly different model information, so we have some flexibility for those\n            val byOem = allDeviceInfos.filter { it.oem.equalsIgnoreCase(MANUFACTURER) }\n            val byDevice = allDeviceInfos.filter { it.device.equalsIgnoreCase(DEVICE) }\n            val byModel = allDeviceInfos.filter { it.model.equalsIgnoreCase(MODEL) }\n            val exactMatch = byOem.find { it.device.equalsIgnoreCase(DEVICE) && it.model.equalsIgnoreCase(MODEL) }\n            deviceInfo = when {\n                exactMatch != null -> {\n                    // Exact match, use provided confidence\n                    exactMatch\n                }\n                byModel.isNotEmpty() || byDevice.isNotEmpty() -> {\n                    // We have data from \"sister devices\", that's way better than taking the OEM average\n                    averageCurrentDeviceInfo(MANUFACTURER, DEVICE, MODEL, (byDevice + byModel).distinct(), CalibrationConfidence.MEDIUM)\n                }\n                byOem.isNotEmpty() -> {\n                    // Fallback to OEM average\n                    averageCurrentDeviceInfo(MANUFACTURER, DEVICE, MODEL, byOem, CalibrationConfidence.LOW)\n                }\n                else -> {\n                    // Fallback to all device average\n                    averageCurrentDeviceInfo(MANUFACTURER, DEVICE, MODEL, allDeviceInfos, CalibrationConfidence.LOWEST)\n                }\n            }\n            Log.i(TAG, \"Selected $deviceInfo\")\n            knownDeviceInfo = deviceInfo\n        }\n        return deviceInfo\n    }\n\nval averageDeviceInfo: DeviceInfo\n    get() = averageCurrentDeviceInfo(MANUFACTURER, DEVICE, MODEL, allDeviceInfos, CalibrationConfidence.LOWEST)\n\n@Suppress(\"PLATFORM_CLASS_MAPPED_TO_KOTLIN\")\nprivate fun String.equalsIgnoreCase(other: String): Boolean = (this as java.lang.String).equalsIgnoreCase(other)\n\n/*\n * Derived from en-calibration-2020-12-14.csv published via\n * https://developers.google.com/android/exposure-notifications/ble-attenuation-computation#device-list\n */\nval allDeviceInfos = listOf(\n        DeviceInfo(\"asus\", \"ASUS_A001\", \"ASUS_A001\", 9, -25, 3),\n        DeviceInfo(\"asus\", \"ASUS_I001_1\", \"ASUS_I001D\", 4, -28, 3),\n        DeviceInfo(\"asus\", \"ASUS_I002D\", \"ASUS_I002D\", 7, -37, 3),\n        DeviceInfo(\"asus\", \"ASUS_I003_1\", \"ASUS_I003DD\", 1, -32, 3),\n        DeviceInfo(\"asus\", \"ASUS_I01WD\", \"ASUS_I01WD\", 5, -27, 3),\n        DeviceInfo(\"asus\", \"ASUS_X008_1\", \"ASUS_X008DC\", 0, -21, 3),\n        DeviceInfo(\"asus\", \"ASUS_X00T_3\", \"ASUS_X00TD\", 2, -26, 3),\n        DeviceInfo(\"asus\", \"ASUS_X018_4\", \"ASUS_X018D\", 2, -22, 3),\n        DeviceInfo(\"asus\", \"ASUS_X01BD_1\", \"ASUS_X01BDA\", 2, -25, 3),\n        DeviceInfo(\"asus\", \"ASUS_Z010_CD\", \"ASUS_Z010D\", 2, -18, 3),\n        DeviceInfo(\"asus\", \"ASUS_Z01F_1\", \"ASUS_Z01FD\", 5, -20, 3),\n        DeviceInfo(\"asus\", \"ASUS_Z01QD_1\", \"ASUS_Z01QD\", 3, -25, 3),\n        DeviceInfo(\"asus\", \"ASUS_Z01R_1\", \"ASUS_Z01RD\", 4, -26, 3),\n        DeviceInfo(\"asus\", \"P027\", \"P027\", 4, -20, 3),\n        DeviceInfo(\"blackberry\", \"bbe100\", \"BBE100-4\", 6, -27, 3),\n        DeviceInfo(\"blu\", \"Grand_M\", \"Grand M\", -1, -21, 3),\n        DeviceInfo(\"blu\", \"Studio_Mega\", \"Studio Mega\", 6, -28, 3),\n        DeviceInfo(\"blu\", \"Tank_Xtreme_4_0\", \"Tank Xtreme 4.0\", 1, -24, 3),\n        DeviceInfo(\"blu\", \"BLU_VIVO_5\", \"VIVO 5\", 5, -24, 3),\n        DeviceInfo(\"blu\", \"V0270WW\", \"Vivo ONE\", 4, -25, 3),\n        DeviceInfo(\"coolpad\", \"CP8722\", \"Coolpad 8722V\", 0, -20, 3),\n        DeviceInfo(\"docomo\", \"SO-41A\", \"SO-41A\", 2, -31, 3),\n        DeviceInfo(\"essential products\", \"mata\", \"PH-1\", 7, -24, 3),\n        DeviceInfo(\"google\", \"sailfish\", \"Pixel\", -3, -26, 3),\n        DeviceInfo(\"google\", \"blueline\", \"Pixel 3\", 5, -33, 3),\n        DeviceInfo(\"google\", \"sargo\", \"Pixel 3a\", 2, -29, 3),\n        DeviceInfo(\"google\", \"bonito\", \"Pixel 3a XL\", 2, -28, 3),\n        DeviceInfo(\"google\", \"flame\", \"Pixel 4\", 8, -30, 3),\n        DeviceInfo(\"google\", \"coral\", \"Pixel 4 XL\", 7, -26, 3),\n        DeviceInfo(\"google\", \"sunfish\", \"Pixel 4a\", 1, -30, 3),\n        DeviceInfo(\"google\", \"redfin\", \"Pixel 5\", 5, -25, 3),\n        DeviceInfo(\"google\", \"marlin\", \"Pixel XL\", -2, -26, 3),\n        DeviceInfo(\"google\", \"gobo\", \"gobo_512\", 2, -22, 3),\n        DeviceInfo(\"htc\", \"htc_pmewhl\", \"2PS64\", -1, -31, 3),\n        DeviceInfo(\"htc\", \"htc_pmewl\", \"HTC 10\", 1, -31, 3),\n        DeviceInfo(\"htc\", \"htc_pmeuhl\", \"HTC 10\", 2, -33, 3),\n        DeviceInfo(\"htc\", \"htc_a16ul\", \"HTC Desire 530\", 5, -28, 3),\n        DeviceInfo(\"htc\", \"htc_ocnwhl\", \"HTC U11\", 2, -21, 3),\n        DeviceInfo(\"htc\", \"htc_ocndugl\", \"HTC U11\", 2, -27, 3),\n        DeviceInfo(\"htc\", \"htc_ocmdugl\", \"HTC U11 plus\", 3, -28, 3),\n        DeviceInfo(\"htc\", \"htc_imldugl\", \"HTC U12 life\", 2, -23, 3),\n        DeviceInfo(\"htc\", \"htc_imedugl\", \"HTC U12+\", 7, -33, 3),\n        DeviceInfo(\"htc\", \"htc_ocedugl\", \"HTC_U-1u\", -5, -29, 3),\n        DeviceInfo(\"htc\", \"htc_ocndugl\", \"HTC_U-3u\", 5, -23, 3),\n        DeviceInfo(\"huawei\", \"HWANE\", \"ANE-LX3\", 3, -3, 3),\n        DeviceInfo(\"huawei\", \"HWCLT\", \"CLT-L09\", -1, -30, 3),\n        DeviceInfo(\"huawei\", \"HWCOR\", \"COR-L29\", 2, -5, 3),\n        DeviceInfo(\"huawei\", \"HWDRA-MG\", \"DRA-LX3\", 4, -24, 3),\n        DeviceInfo(\"huawei\", \"HWTIT-L6735\", \"HUAWEI TIT-AL00\", 4, -10, 3),\n        DeviceInfo(\"huawei\", \"HW-01K\", \"HW-01K\", -1, -32, 3),\n        DeviceInfo(\"huawei\", \"hwfdra04l\", \"HWT31\", 3, -24, 3),\n        DeviceInfo(\"huawei\", \"HNKIW-Q\", \"KIW-L24\", 7, -25, 3),\n        DeviceInfo(\"huawei\", \"HWMHA\", \"MHA-L29\", 2, -27, 3),\n        DeviceInfo(\"huawei\", \"HWNEO\", \"NEO-L29\", -3, -28, 3),\n        DeviceInfo(\"huawei\", \"angler\", \"Nexus 6P\", 6, -27, 3),\n        DeviceInfo(\"huawei\", \"HWPIC\", \"PIC-AL00\", -1, -3, 3),\n        DeviceInfo(\"huawei\", \"HWPRA-H\", \"PRA-LX1\", 1, -3, 3),\n        DeviceInfo(\"huawei\", \"HWWAS-H\", \"WAS-LX3\", 2, -4, 3),\n        DeviceInfo(\"infinix\", \"Infinix-X627STU\", \"Infinix X627\", 3, -27, 3),\n        DeviceInfo(\"infinix\", \"Infinix-X650\", \"Infinix X650\", 1, -26, 3),\n        DeviceInfo(\"infinix\", \"Infinix-X650C\", \"Infinix X650C\", 3, -30, 3),\n        DeviceInfo(\"infinix\", \"Infinix-X653\", \"Infinix X653\", 4, -24, 3),\n        DeviceInfo(\"infinix\", \"Infinix-X653C\", \"Infinix X653C\", -1, -23, 3),\n        DeviceInfo(\"itel\", \"itel-A32F\", \"itel A32F\", 3, -26, 3),\n        DeviceInfo(\"itel\", \"itel-L5503\", \"itel L5503\", -3, -6, 3),\n        DeviceInfo(\"itel\", \"itel-L6005\", \"itel L6005\", -4, -1, 3),\n        DeviceInfo(\"itel\", \"itel-W5504\", \"itel W5504\", -1, -11, 3),\n        DeviceInfo(\"lava\", \"Z50\", \"Z50\", 6, -26, 3),\n        DeviceInfo(\"leagoo\", \"T5c\", \"T5c\", -29, -23, 3),\n        DeviceInfo(\"lenovo\", \"A1010a20\", \"Lenovo A1010a20\", 2, -25, 3),\n        DeviceInfo(\"lenovo\", \"A6600d40\", \"Lenovo A6600d40\", 3, -26, 3),\n        DeviceInfo(\"lenovo\", \"guamp\", \"Lenovo K12 Note\", 1, -18, 3),\n        DeviceInfo(\"lenovo\", \"K33a42\", \"Lenovo K33a42\", 3, -29, 3),\n        DeviceInfo(\"lenovo\", \"K33a48\", \"Lenovo K33a48\", 3, -27, 3),\n        DeviceInfo(\"lenovo\", \"seoul\", \"Lenovo K520\", 4, -20, 3),\n        DeviceInfo(\"lenovo\", \"k52_e78\", \"Lenovo K52e78\", 0, -18, 3),\n        DeviceInfo(\"lenovo\", \"K53a48\", \"Lenovo K53a48\", 5, -29, 3),\n        DeviceInfo(\"lenovo\", \"brady_f\", \"Lenovo K8\", 4, -22, 3),\n        DeviceInfo(\"lenovo\", \"manning\", \"Lenovo K8 Note\", 4, -26, 3),\n        DeviceInfo(\"lenovo\", \"jd2018\", \"Lenovo L78011\", 1, -21, 3),\n        DeviceInfo(\"lenovo\", \"P2a42\", \"Lenovo P2a42\", 3, -19, 3),\n        DeviceInfo(\"lenovo\", \"TB3-710I\", \"Lenovo TB3-710I\", 3, -26, 3),\n        DeviceInfo(\"lenovo\", \"zoom_tdd\", \"Lenovo Z90-3\", 5, -22, 3),\n        DeviceInfo(\"letv\", \"le_s2_ww\", \"Le X527\", 4, -21, 3),\n        DeviceInfo(\"lge\", \"lv0\", \"LG-AS110\", 6, -24, 3),\n        DeviceInfo(\"lge\", \"p1\", \"LG-F500L\", -3, -24, 3),\n        DeviceInfo(\"lge\", \"h1\", \"LG-F700L\", 9, -28, 3),\n        DeviceInfo(\"lge\", \"c50\", \"LG-H345\", 3, -21, 3),\n        DeviceInfo(\"lge\", \"g4stylus\", \"LG-H634\", 3, -21, 3),\n        DeviceInfo(\"lge\", \"p1\", \"LG-H815\", -3, -25, 3),\n        DeviceInfo(\"lge\", \"mme0n\", \"LG-K100\", 2, -23, 3),\n        DeviceInfo(\"lge\", \"mm1v\", \"LG-K350\", 1, -21, 3),\n        DeviceInfo(\"lge\", \"m253\", \"LG-K430\", 2, -22, 3),\n        DeviceInfo(\"lge\", \"k5\", \"LG-K500\", 6, -22, 3),\n        DeviceInfo(\"lge\", \"ph1\", \"LG-K540\", 6, -22, 3),\n        DeviceInfo(\"lge\", \"mlv5\", \"LG-M250\", 3, -22, 3),\n        DeviceInfo(\"lge\", \"mlv1\", \"LG-X230\", 2, -23, 3),\n        DeviceInfo(\"lge\", \"mlv3\", \"LG-X240\", 1, -22, 3),\n        DeviceInfo(\"lge\", \"e7iilte\", \"LGLK430\", 2, -18, 3),\n        DeviceInfo(\"lge\", \"me0\", \"LGLS450\", 5, -24, 3),\n        DeviceInfo(\"lge\", \"joan\", \"LGM-V300L\", 4, -21, 3),\n        DeviceInfo(\"lge\", \"anna\", \"LGM-X800L\", 6, -13, 3),\n        DeviceInfo(\"lge\", \"p1\", \"LGUS991\", -4, -25, 3),\n        DeviceInfo(\"lge\", \"mdh30xlm\", \"LM-K500\", 6, -30, 3),\n        DeviceInfo(\"lge\", \"mh3\", \"LM-Q620\", 7, -33, 3),\n        DeviceInfo(\"lge\", \"mdh50lm\", \"LM-Q730\", 4, -30, 3),\n        DeviceInfo(\"lge\", \"phoenix_sprout\", \"LM-Q910\", 4, -24, 3),\n        DeviceInfo(\"lge\", \"timelm\", \"LM-V600\", -1, -33, 3),\n        DeviceInfo(\"lge\", \"cv1\", \"LM-X210\", 4, -18, 3),\n        DeviceInfo(\"lge\", \"bullhead\", \"Nexus 5X\", -6, -25, 3),\n        DeviceInfo(\"lge\", \"h1\", \"RS988\", 8, -3, 3),\n        DeviceInfo(\"lge\", \"lucye\", \"VS988\", -3, -8, 3),\n        DeviceInfo(\"lge\", \"elsa\", \"VS995\", 6, -3, 3),\n        DeviceInfo(\"meizu\", \"mx4\", \"MX4\", 5, -5, 3),\n        DeviceInfo(\"motorola\", \"athene_f\", \"Moto G (4)\", 0, -17, 3),\n        DeviceInfo(\"motorola\", \"cedric\", \"Moto G (5)\", 3, -19, 3),\n        DeviceInfo(\"motorola\", \"potter_n\", \"Moto G (5) Plus\", 6, -20, 3),\n        DeviceInfo(\"motorola\", \"potter\", \"Moto G (5) Plus\", 3, -19, 3),\n        DeviceInfo(\"motorola\", \"sanders\", \"Moto G (5S) Plus\", 4, -19, 3),\n        DeviceInfo(\"motorola\", \"harpia\", \"Moto G Play\", 5, -23, 3),\n        DeviceInfo(\"motorola\", \"albus\", \"Moto Z2 Play\", 3, -18, 3),\n        DeviceInfo(\"motorola\", \"osprey_uds\", \"MotoG3\", 5, -21, 3),\n        DeviceInfo(\"motorola\", \"shamu\", \"Nexus 6\", 10, -29, 3),\n        DeviceInfo(\"motorola\", \"clark\", \"XT1575\", 0, -30, 3),\n        DeviceInfo(\"motorola\", \"harpia\", \"XT1609\", 5, -22, 3),\n        DeviceInfo(\"motorola\", \"addison\", \"XT1635-01\", 5, -19, 3),\n        DeviceInfo(\"motorola\", \"griffin\", \"XT1650\", -3, -26, 3),\n        DeviceInfo(\"motorola\", \"taido_row\", \"XT1706\", 8, -27, 3),\n        DeviceInfo(\"motorola\", \"pettyl\", \"moto e5 play\", 1, -27, 3),\n        DeviceInfo(\"motorola\", \"rjames_f\", \"moto e5 play\", 3, -18, 3),\n        DeviceInfo(\"motorola\", \"kiev\", \"moto g 5G\", 4, -26, 3),\n        DeviceInfo(\"motorola\", \"nairo\", \"moto g 5G plus\", -3, -26, 3),\n        DeviceInfo(\"motorola\", \"sofiap_sprout\", \"moto g pro\", 4, -34, 3),\n        DeviceInfo(\"motorola\", \"jeter\", \"moto g(6) play\", 3, -20, 3),\n        DeviceInfo(\"motorola\", \"river\", \"moto g(7)\", 4, -23, 3),\n        DeviceInfo(\"motorola\", \"channel\", \"moto g(7) play\", 6, -32, 3),\n        DeviceInfo(\"motorola\", \"lake_n\", \"moto g(7) plus\", 3, -23, 3),\n        DeviceInfo(\"motorola\", \"doha_n\", \"moto g(8) plus\", 3, -23, 3),\n        DeviceInfo(\"motorola\", \"odessa\", \"moto g(9) plus\", 5, -33, 3),\n        DeviceInfo(\"motorola\", \"cebu\", \"moto g(9) power\", -2, -16, 3),\n        DeviceInfo(\"motorola\", \"payton\", \"moto x4\", 2, -23, 3),\n        DeviceInfo(\"motorola\", \"messi\", \"moto z3\", 4, -26, 3),\n        DeviceInfo(\"motorola\", \"foles\", \"moto z4\", 8, -30, 3),\n        DeviceInfo(\"motorola\", \"racer\", \"motorola edge\", -2, -27, 3),\n        DeviceInfo(\"motorola\", \"burton\", \"motorola edge plus\", 8, -35, 3),\n        DeviceInfo(\"motorola\", \"deen_sprout\", \"motorola one\", 4, -21, 3),\n        DeviceInfo(\"motorola\", \"def\", \"motorola one hyper\", 4, -23, 3),\n        DeviceInfo(\"motorola\", \"chef_sprout\", \"motorola one power\", 2, -22, 3),\n        DeviceInfo(\"nokia\", \"FRT\", \"Nokia 1\", 2, -24, 3),\n        DeviceInfo(\"nokia\", \"ANT\", \"Nokia 1 Plus\", 1, -20, 3),\n        DeviceInfo(\"nokia\", \"E2M\", \"Nokia 2.1\", 0, -28, 3),\n        DeviceInfo(\"nokia\", \"IRM_sprout\", \"Nokia 2.3\", -3, -21, 3),\n        DeviceInfo(\"nokia\", \"ES2_sprout\", \"Nokia 3.1\", 6, -23, 3),\n        DeviceInfo(\"nokia\", \"ROON_sprout\", \"Nokia 3.1 Plus\", 0, -24, 3),\n        DeviceInfo(\"nokia\", \"DPL_sprout\", \"Nokia 3.2\", 4, -32, 3),\n        DeviceInfo(\"nokia\", \"PAN_sprout\", \"Nokia 4.2\", 7, -36, 3),\n        DeviceInfo(\"nokia\", \"CO2_sprout\", \"Nokia 5.1\", 6, -25, 3),\n        DeviceInfo(\"nokia\", \"PL2_sprout\", \"Nokia 6.1\", 8, -28, 3),\n        DeviceInfo(\"nokia\", \"DRG_sprout\", \"Nokia 6.1 Plus\", 6, -27, 3),\n        DeviceInfo(\"nokia\", \"B2N_sprout\", \"Nokia 7 plus\", 2, -20, 3),\n        DeviceInfo(\"nokia\", \"CTL_sprout\", \"Nokia 7.1\", 6, -24, 3),\n        DeviceInfo(\"nokia\", \"DDV_sprout\", \"Nokia 7.2\", 3, -7, 3),\n        DeviceInfo(\"nokia\", \"A1N_sprout\", \"Nokia 8 Sirocco\", 12, -30, 3),\n        DeviceInfo(\"nokia\", \"PNX_sprout\", \"Nokia 8.1\", 5, -24, 3),\n        DeviceInfo(\"nokia\", \"BGT_sprout\", \"Nokia 8.3 5G\", 5, -23, 3),\n        DeviceInfo(\"nokia\", \"AOP_sprout\", \"Nokia 9\", 7, -25, 3),\n        DeviceInfo(\"nokia\", \"RKU\", \"Nokia C1\", -7, -3, 3),\n        DeviceInfo(\"nokia\", \"NB1\", \"TA-1012\", 5, -22, 3),\n        DeviceInfo(\"nokia\", \"PLE\", \"TA-1025\", 2, -17, 3),\n        DeviceInfo(\"nokia\", \"PL2\", \"TA-1054\", 7, -26, 3),\n        DeviceInfo(\"nokia 5.1 plus\", \"Panda_00WW\", \"PDA_sprout\", 5, -28, 3),\n        DeviceInfo(\"oneplus\", \"OnePlus7\", \"GM1900\", 3, -17, 3),\n        DeviceInfo(\"oneplus\", \"OnePlus7Pro\", \"GM1910\", 3, -18, 3),\n        DeviceInfo(\"oneplus\", \"OnePlus7T\", \"HD1905\", 1, -16, 3),\n        DeviceInfo(\"oneplus\", \"OnePlus7TPro\", \"HD1911\", 0, -17, 3),\n        DeviceInfo(\"oneplus\", \"OnePlus8\", \"IN2011\", 4, -27, 3),\n        DeviceInfo(\"oneplus\", \"OnePlus8Pro\", \"IN2025\", 6, -29, 3),\n        DeviceInfo(\"oneplus\", \"OnePlus8T\", \"KB2003\", 5, -31, 3),\n        DeviceInfo(\"oneplus\", \"OnePlus5\", \"ONEPLUS A5000\", 6, -25, 3),\n        DeviceInfo(\"oneplus\", \"OnePlus5T\", \"ONEPLUS A5010\", 3, -22, 3),\n        DeviceInfo(\"oneplus\", \"OnePlus6\", \"ONEPLUS A6000\", 3, -23, 3),\n        DeviceInfo(\"oneplus\", \"OnePlus6\", \"ONEPLUS A6003\", 4, -29, 3),\n        DeviceInfo(\"oneplus\", \"OnePlus6T\", \"ONEPLUS A6010\", 2, -19, 3),\n        DeviceInfo(\"oneplus\", \"OnePlus6T\", \"ONEPLUS A6013\", 1, -21, 3),\n        DeviceInfo(\"oppo\", \"CPH1715\", \"CPH1715\", 2, -25, 3),\n        DeviceInfo(\"oppo\", \"CPH1717\", \"CPH1717\", -4, -18, 3),\n        DeviceInfo(\"oppo\", \"CPH1721\", \"CPH1721\", -1, -20, 3),\n        DeviceInfo(\"oppo\", \"CPH1723\", \"CPH1723\", 3, -24, 3),\n        DeviceInfo(\"oppo\", \"CPH1803\", \"CPH1803\", -1, -17, 3),\n        DeviceInfo(\"oppo\", \"CPH1823\", \"CPH1823\", -2, -21, 3),\n        DeviceInfo(\"oppo\", \"OP4845\", \"CPH1919\", 3, -24, 3),\n        DeviceInfo(\"oppo\", \"CPH1920\", \"CPH1920\", -2, -24, 3),\n        DeviceInfo(\"oppo\", \"OP4B79L1\", \"CPH1931\", 4, -32, 3),\n        DeviceInfo(\"oppo\", \"OP4B65L1\", \"CPH1945\", -1, -26, 3),\n        DeviceInfo(\"oppo\", \"OP4863\", \"CPH1969\", 2, -27, 3),\n        DeviceInfo(\"oppo\", \"OP48A1L1\", \"CPH1979\", 0, -36, 3),\n        DeviceInfo(\"oppo\", \"OP4C4BL1\", \"CPH1989\", -4, -21, 3),\n        DeviceInfo(\"oppo\", \"OP4C2DL1\", \"CPH2009\", 4, -26, 3),\n        DeviceInfo(\"oppo\", \"OP4BA1L1\", \"CPH2023\", 9, -37, 3),\n        DeviceInfo(\"orange\", \"Neva_play\", \"Orange Neva play\", -1, -12, 3),\n        DeviceInfo(\"orange\", \"Neva_zen\", \"Orange Neva zen\", -5, -3, 3),\n        DeviceInfo(\"orbic\", \"RC555L\", \"RC555L\", 5, -26, 3),\n        DeviceInfo(\"razer\", \"cheryl\", \"Phone\", 7, -26, 3),\n        DeviceInfo(\"razer\", \"aura\", \"Phone 2\", 3, -24, 3),\n        DeviceInfo(\"redmi\", \"olivelite\", \"Redmi 8A\", 5, -30, 3),\n        DeviceInfo(\"redmi\", \"lavender\", \"Redmi Note 7\", 5, -29, 3),\n        DeviceInfo(\"redmi\", \"ginkgo\", \"Redmi Note 8\", 4, -19, 3),\n        DeviceInfo(\"samsung\", \"poseidonlteatt\", \"SAMSUNG-SM-G891A\", 4, -27, 3),\n        DeviceInfo(\"samsung\", \"klteatt\", \"SAMSUNG-SM-G900A\", 9, -23, 3),\n        DeviceInfo(\"samsung\", \"heroqlteaio\", \"SAMSUNG-SM-G930AZ\", 11, -33, 3),\n        DeviceInfo(\"samsung\", \"hero2qlteatt\", \"SAMSUNG-SM-G935A\", 10, -33, 3),\n        DeviceInfo(\"samsung\", \"SC-02J\", \"SC-02J\", 11, -31, 3),\n        DeviceInfo(\"samsung\", \"SC-02K\", \"SC-02K\", 11, -29, 3),\n        DeviceInfo(\"samsung\", \"SC-02L\", \"SC-02L\", 5, -23, 3),\n        DeviceInfo(\"samsung\", \"SC-03K\", \"SC-03K\", 15, -34, 3),\n        DeviceInfo(\"samsung\", \"SCV33\", \"SCV33\", 7, -29, 3),\n        DeviceInfo(\"samsung\", \"SCV36\", \"SCV36\", 9, -24, 3),\n        DeviceInfo(\"samsung\", \"a10e\", \"SM-A102U\", 6, -25, 3),\n        DeviceInfo(\"samsung\", \"a10\", \"SM-A105F\", 3, -23, 3),\n        DeviceInfo(\"samsung\", \"a10\", \"SM-A105FN\", 4, -25, 3),\n        DeviceInfo(\"samsung\", \"a10\", \"SM-A105G\", 2, -23, 3),\n        DeviceInfo(\"samsung\", \"a10\", \"SM-A105M\", 1, -23, 3),\n        DeviceInfo(\"samsung\", \"a10s\", \"SM-A107F\", 5, -30, 3),\n        DeviceInfo(\"samsung\", \"a20e\", \"SM-A202F\", 2, -26, 3),\n        DeviceInfo(\"samsung\", \"a20\", \"SM-A205F\", 3, -26, 3),\n        DeviceInfo(\"samsung\", \"a20\", \"SM-A205G\", 2, -24, 3),\n        DeviceInfo(\"samsung\", \"a20p\", \"SM-A205U\", 23, -47, 3),\n        DeviceInfo(\"samsung\", \"a20s\", \"SM-A207F\", 8, -32, 3),\n        DeviceInfo(\"samsung\", \"a3ulte\", \"SM-A300FU\", 6, -23, 3),\n        DeviceInfo(\"samsung\", \"a30\", \"SM-A305F\", 4, -23, 3),\n        DeviceInfo(\"samsung\", \"a30s\", \"SM-A307FN\", 2, -26, 3),\n        DeviceInfo(\"samsung\", \"a3y17lte\", \"SM-A320FL\", -10, -23, 3),\n        DeviceInfo(\"samsung\", \"a40\", \"SM-A405FN\", 2, -23, 3),\n        DeviceInfo(\"samsung\", \"a50\", \"SM-A505F\", 0, -20, 3),\n        DeviceInfo(\"samsung\", \"a50\", \"SM-A505FM\", 3, -20, 3),\n        DeviceInfo(\"samsung\", \"a50\", \"SM-A505FN\", -2, -20, 3),\n        DeviceInfo(\"samsung\", \"a5xelte\", \"SM-A510F\", 6, -2, 3),\n        DeviceInfo(\"samsung\", \"a5xelte\", \"SM-A510M\", 3, -1, 3),\n        DeviceInfo(\"samsung\", \"a51\", \"SM-A515F\", 2, -28, 3),\n        DeviceInfo(\"samsung\", \"a5y17lte\", \"SM-A520F\", -6, -25, 3),\n        DeviceInfo(\"samsung\", \"jackpotlte\", \"SM-A530F\", 2, -23, 3),\n        DeviceInfo(\"samsung\", \"a6lte\", \"SM-A600FN\", 8, -35, 3),\n        DeviceInfo(\"samsung\", \"a70q\", \"SM-A705FN\", 5, -33, 3),\n        DeviceInfo(\"samsung\", \"a7xelte\", \"SM-A710F\", 5, -5, 3),\n        DeviceInfo(\"samsung\", \"a7y18lte\", \"SM-A750F\", 4, -24, 3),\n        DeviceInfo(\"samsung\", \"a7y18lte\", \"SM-A750FN\", 5, -26, 3),\n        DeviceInfo(\"samsung\", \"a7y18lte\", \"SM-A750GN\", 6, -23, 3),\n        DeviceInfo(\"samsung\", \"a9y18qltechn\", \"SM-A9200\", 5, -24, 3),\n        DeviceInfo(\"samsung\", \"a9y18qlte\", \"SM-A920F\", 4, -21, 3),\n        DeviceInfo(\"samsung\", \"c5proltechn\", \"SM-C5010\", 9, -26, 3),\n        DeviceInfo(\"samsung\", \"jadeltechn\", \"SM-C7100\", 8, -26, 3),\n        DeviceInfo(\"samsung\", \"elitexlte\", \"SM-G1650\", 6, -30, 3),\n        DeviceInfo(\"samsung\", \"grandpplte\", \"SM-G532M\", 4, -24, 3),\n        DeviceInfo(\"samsung\", \"on5xelte\", \"SM-G570F\", 7, -24, 3),\n        DeviceInfo(\"samsung\", \"on5xelte\", \"SM-G570M\", 2, -24, 3),\n        DeviceInfo(\"samsung\", \"o7ltechn\", \"SM-G6000\", 3, -22, 3),\n        DeviceInfo(\"samsung\", \"on7xelte\", \"SM-G610F\", 7, 2, 3),\n        DeviceInfo(\"samsung\", \"on7xreflte\", \"SM-G611F\", 6, -2, 3),\n        DeviceInfo(\"samsung\", \"slte\", \"SM-G850F\", 17, -33, 3),\n        DeviceInfo(\"samsung\", \"astarqltechn\", \"SM-G8850\", 3, -24, 3),\n        DeviceInfo(\"samsung\", \"astarqlteskt\", \"SM-G885S\", 1, -24, 3),\n        DeviceInfo(\"samsung\", \"cruiserlteatt\", \"SM-G892A\", 8, -24, 3),\n        DeviceInfo(\"samsung\", \"klte\", \"SM-G900F\", 12, -24, 3),\n        DeviceInfo(\"samsung\", \"zeroflte\", \"SM-G920F\", 9, -25, 3),\n        DeviceInfo(\"samsung\", \"zeroflte\", \"SM-G920I\", 7, -24, 3),\n        DeviceInfo(\"samsung\", \"zerofltetmo\", \"SM-G920T\", 8, -24, 3),\n        DeviceInfo(\"samsung\", \"zerolte\", \"SM-G925F\", 8, -25, 3),\n        DeviceInfo(\"samsung\", \"zerolte\", \"SM-G925I\", 4, -23, 3),\n        DeviceInfo(\"samsung\", \"herolte\", \"SM-G930F\", 9, -33, 3),\n        DeviceInfo(\"samsung\", \"heroqltespr\", \"SM-G930P\", 7, -32, 3),\n        DeviceInfo(\"samsung\", \"heroqlteusc\", \"SM-G930R4\", 12, -35, 3),\n        DeviceInfo(\"samsung\", \"heroqltevzw\", \"SM-G930V\", 9, -32, 3),\n        DeviceInfo(\"samsung\", \"hero2qltechn\", \"SM-G9350\", 8, -31, 3),\n        DeviceInfo(\"samsung\", \"hero2lte\", \"SM-G935F\", 11, -33, 3),\n        DeviceInfo(\"samsung\", \"hero2qltespr\", \"SM-G935P\", 8, -31, 3),\n        DeviceInfo(\"samsung\", \"hero2qlteusc\", \"SM-G935R4\", 9, -29, 3),\n        DeviceInfo(\"samsung\", \"hero2qltetmo\", \"SM-G935T\", 4, -28, 3),\n        DeviceInfo(\"samsung\", \"hero2qltevzw\", \"SM-G935V\", 14, -34, 3),\n        DeviceInfo(\"samsung\", \"dreamlte\", \"SM-G950F\", 12, -29, 3),\n        DeviceInfo(\"samsung\", \"dreamlteks\", \"SM-G950N\", 11, -27, 3),\n        DeviceInfo(\"samsung\", \"dreamqlteue\", \"SM-G950U1\", 10, -27, 3),\n        DeviceInfo(\"samsung\", \"dreamqltecan\", \"SM-G950W\", 9, -24, 3),\n        DeviceInfo(\"samsung\", \"dream2lte\", \"SM-G955F\", 9, -26, 3),\n        DeviceInfo(\"samsung\", \"dream2lteks\", \"SM-G955N\", 10, -26, 3),\n        DeviceInfo(\"samsung\", \"dream2qlteue\", \"SM-G955U1\", 10, -26, 3),\n        DeviceInfo(\"samsung\", \"dream2qltecan\", \"SM-G955W\", 8, -23, 3),\n        DeviceInfo(\"samsung\", \"starqltechn\", \"SM-G9600\", 4, -22, 3),\n        DeviceInfo(\"samsung\", \"starlte\", \"SM-G960F\", 8, -28, 3),\n        DeviceInfo(\"samsung\", \"starlteks\", \"SM-G960N\", 7, -28, 3),\n        DeviceInfo(\"samsung\", \"starqltesq\", \"SM-G960U\", 5, -21, 3),\n        DeviceInfo(\"samsung\", \"starqlteue\", \"SM-G960U1\", 4, -19, 3),\n        DeviceInfo(\"samsung\", \"star2qltechn\", \"SM-G9650\", 7, -26, 3),\n        DeviceInfo(\"samsung\", \"star2lte\", \"SM-G965F\", 8, -27, 3),\n        DeviceInfo(\"samsung\", \"star2lteks\", \"SM-G965N\", 9, -25, 3),\n        DeviceInfo(\"samsung\", \"star2qltesq\", \"SM-G965U\", 8, -25, 3),\n        DeviceInfo(\"samsung\", \"star2qlteue\", \"SM-G965U1\", 6, -24, 3),\n        DeviceInfo(\"samsung\", \"beyond1\", \"SM-G973F\", 2, -29, 3),\n        DeviceInfo(\"samsung\", \"beyond1q\", \"SM-G973U\", -1, -26, 3),\n        DeviceInfo(\"samsung\", \"beyond2\", \"SM-G975F\", 1, -26, 3),\n        DeviceInfo(\"samsung\", \"beyond2q\", \"SM-G975U\", 0, -24, 3),\n        DeviceInfo(\"samsung\", \"beyondx\", \"SM-G977N\", 0, -26, 3),\n        DeviceInfo(\"samsung\", \"beyondxq\", \"SM-G977P\", -3, -34, 3),\n        DeviceInfo(\"samsung\", \"j1qltevzw\", \"SM-J100VPP\", 6, -22, 3),\n        DeviceInfo(\"samsung\", \"j2y18lte\", \"SM-J250F\", 3, -27, 3),\n        DeviceInfo(\"samsung\", \"j2corelte\", \"SM-J260F\", 5, -25, 3),\n        DeviceInfo(\"samsung\", \"j2corelte\", \"SM-J260G\", 7, -27, 3),\n        DeviceInfo(\"samsung\", \"j2corelte\", \"SM-J260M\", 6, -25, 3),\n        DeviceInfo(\"samsung\", \"j3ltevzw\", \"SM-J320V\", 1, -17, 3),\n        DeviceInfo(\"samsung\", \"j3popelteue\", \"SM-J327U\", 6, -24, 3),\n        DeviceInfo(\"samsung\", \"j3y17ltelgt\", \"SM-J330F\", 3, -24, 3),\n        DeviceInfo(\"samsung\", \"j3y17lte\", \"SM-J330FN\", 4, -28, 3),\n        DeviceInfo(\"samsung\", \"j3y17ltelgt\", \"SM-J330L\", 2, -22, 3),\n        DeviceInfo(\"samsung\", \"j3topeltevzw\", \"SM-J337V\", 0, -19, 3),\n        DeviceInfo(\"samsung\", \"j4lte\", \"SM-J400F\", 6, -27, 3),\n        DeviceInfo(\"samsung\", \"j4lte\", \"SM-J400M\", 8, -27, 3),\n        DeviceInfo(\"samsung\", \"j4primelte\", \"SM-J415F\", 3, -29, 3),\n        DeviceInfo(\"samsung\", \"j4primelte\", \"SM-J415G\", 4, -28, 3),\n        DeviceInfo(\"samsung\", \"j5lte\", \"SM-J500F\", 4, -19, 3),\n        DeviceInfo(\"samsung\", \"j53g\", \"SM-J500H\", -1, -18, 3),\n        DeviceInfo(\"samsung\", \"j5lte\", \"SM-J500M\", 2, -18, 3),\n        DeviceInfo(\"samsung\", \"j5xnlte\", \"SM-J510FN\", 1, -18, 3),\n        DeviceInfo(\"samsung\", \"j5xnlte\", \"SM-J510GN\", 3, -19, 3),\n        DeviceInfo(\"samsung\", \"j5xnlte\", \"SM-J510MN\", 3, -20, 3),\n        DeviceInfo(\"samsung\", \"j5y17lte\", \"SM-J530F\", 8, -33, 3),\n        DeviceInfo(\"samsung\", \"j6lte\", \"SM-J600FN\", 7, -24, 3),\n        DeviceInfo(\"samsung\", \"j6primelte\", \"SM-J610F\", 3, -27, 3),\n        DeviceInfo(\"samsung\", \"j6primelte\", \"SM-J610G\", 3, -28, 3),\n        DeviceInfo(\"samsung\", \"j7velte\", \"SM-J701F\", 8, -3, 3),\n        DeviceInfo(\"samsung\", \"j7popltevzw\", \"SM-J727V\", 4, -20, 3),\n        DeviceInfo(\"samsung\", \"j7y17lte\", \"SM-J730F\", 6, -33, 3),\n        DeviceInfo(\"samsung\", \"j7y17lte\", \"SM-J730FM\", 7, -34, 3),\n        DeviceInfo(\"samsung\", \"j7y17ltektt\", \"SM-J730K\", 4, -30, 3),\n        DeviceInfo(\"samsung\", \"j8y18lte\", \"SM-J810F\", 5, -29, 3),\n        DeviceInfo(\"samsung\", \"j8y18lte\", \"SM-J810M\", 5, -32, 3),\n        DeviceInfo(\"samsung\", \"m20lte\", \"SM-M205F\", 3, -22, 3),\n        DeviceInfo(\"samsung\", \"trelte\", \"SM-N910C\", 11, -31, 3),\n        DeviceInfo(\"samsung\", \"tblte\", \"SM-N915G\", 7, -24, 3),\n        DeviceInfo(\"samsung\", \"noblelte\", \"SM-N9208\", 4, -29, 3),\n        DeviceInfo(\"samsung\", \"noblelte\", \"SM-N920C\", 5, -30, 3),\n        DeviceInfo(\"samsung\", \"greatlte\", \"SM-N950F\", 8, -24, 3),\n        DeviceInfo(\"samsung\", \"greatlteks\", \"SM-N950N\", 6, -24, 3),\n        DeviceInfo(\"samsung\", \"greatqlte\", \"SM-N950U\", 9, -25, 3),\n        DeviceInfo(\"samsung\", \"greatqlteue\", \"SM-N950U1\", 9, -26, 3),\n        DeviceInfo(\"samsung\", \"crownlte\", \"SM-N960F\", 7, -28, 3),\n        DeviceInfo(\"samsung\", \"crownlteks\", \"SM-N960N\", 9, -27, 3),\n        DeviceInfo(\"samsung\", \"crownqltesq\", \"SM-N960U\", 5, -24, 3),\n        DeviceInfo(\"samsung\", \"crownqlteue\", \"SM-N960U1\", 5, -24, 3),\n        DeviceInfo(\"samsung\", \"j3topeltetfnvzw\", \"SM-S367VL\", 3, -21, 3),\n        DeviceInfo(\"samsung\", \"j7popqltetfnvzw\", \"SM-S727VL\", 4, -18, 3),\n        DeviceInfo(\"samsung\", \"gt58wifi\", \"SM-T350\", 2, -18, 3),\n        DeviceInfo(\"samsung\", \"gtesveltevzw\", \"SM-T378V\", 1, -20, 3),\n        DeviceInfo(\"samsung\", \"gta2swifi\", \"SM-T380\", 4, -19, 3),\n        DeviceInfo(\"samsung\", \"gta2swifichn\", \"SM-T380C\", 4, -20, 3),\n        DeviceInfo(\"samsung\", \"gta2sltechn\", \"SM-T385C\", 4, -20, 3),\n        DeviceInfo(\"samsung\", \"gta2sltektt\", \"SM-T385K\", 3, -18, 3),\n        DeviceInfo(\"samsung\", \"gta2sltelgt\", \"SM-T385L\", 2, -19, 3),\n        DeviceInfo(\"samsung\", \"gtactive2wifi\", \"SM-T390\", -11, -23, 3),\n        DeviceInfo(\"samsung\", \"gtactive2lte\", \"SM-T395\", -8, -26, 3),\n        DeviceInfo(\"samsung\", \"gtaxlwifi\", \"SM-T580\", -12, -22, 3),\n        DeviceInfo(\"samsung\", \"gts3lwifi\", \"SM-T820\", -10, -23, 3),\n        DeviceInfo(\"samsung\", \"gts3lltevzw\", \"SM-T827V\", 0, -22, 3),\n        DeviceInfo(\"samsung\", \"gts4lltevzw\", \"SM-T837V\", 1, -20, 3),\n        DeviceInfo(\"sg\", \"OI6\", \"A001SH\", 9, -32, 3),\n        DeviceInfo(\"sharp\", \"eve_sprout\", \"507SH\", 6, -29, 3),\n        DeviceInfo(\"sharp\", \"SG509SH\", \"509SH\", 3, -34, 3),\n        DeviceInfo(\"sharp\", \"SG704SH\", \"704SH\", 5, -32, 3),\n        DeviceInfo(\"sharp\", \"kaleido_sprout\", \"S1\", 3, -22, 3),\n        DeviceInfo(\"sharp\", \"rome_sprout\", \"S3-SH\", 5, -39, 3),\n        DeviceInfo(\"sharp\", \"zeon_sprout\", \"S5-SH\", 2, -25, 3),\n        DeviceInfo(\"sharp\", \"SH-01K\", \"SH-01K\", 4, -34, 3),\n        DeviceInfo(\"sharp\", \"SH-01L\", \"SH-01L\", 3, -25, 3),\n        DeviceInfo(\"sharp\", \"SH-01M\", \"SH-01M\", 7, -27, 3),\n        DeviceInfo(\"sharp\", \"SH-02J\", \"SH-02J\", 5, -34, 3),\n        DeviceInfo(\"sharp\", \"SH-02M\", \"SH-02M\", 5, -29, 3),\n        DeviceInfo(\"sharp\", \"SH-03J\", \"SH-03J\", 6, -24, 3),\n        DeviceInfo(\"sharp\", \"SH-03K\", \"SH-03K\", 4, -28, 3),\n        DeviceInfo(\"sharp\", \"SH-04H\", \"SH-04H\", 1, -36, 3),\n        DeviceInfo(\"sharp\", \"SH-04L\", \"SH-04L\", 5, -27, 3),\n        DeviceInfo(\"sharp\", \"SH-51A\", \"SH-51A\", 4, -41, 3),\n        DeviceInfo(\"sharp\", \"SHV36\", \"SHV36\", 6, -36, 3),\n        DeviceInfo(\"sharp\", \"HUR\", \"SHV39\", 5, -22, 3),\n        DeviceInfo(\"sm-j415f\", \"j4primeltedx\", \"j4primelte\", 4, -26, 3),\n        DeviceInfo(\"softbank\", \"Z8851S\", \"902ZT\", 6, -34, 3),\n        DeviceInfo(\"sony\", \"601SO\", \"601SO\", 1, -36, 3),\n        DeviceInfo(\"sony\", \"602SO\", \"602SO\", -3, -30, 3),\n        DeviceInfo(\"sony\", \"701SO\", \"701SO\", 6, -26, 3),\n        DeviceInfo(\"sony\", \"E6603\", \"E6603\", 10, -26, 3),\n        DeviceInfo(\"sony\", \"E6633\", \"E6633\", 13, -26, 3),\n        DeviceInfo(\"sony\", \"F5121\", \"F5121\", 8, -34, 3),\n        DeviceInfo(\"sony\", \"F8131\", \"F8131\", 1, -32, 3),\n        DeviceInfo(\"sony\", \"F8331\", \"F8331\", -2, -29, 3),\n        DeviceInfo(\"sony\", \"F8332\", \"F8332\", -2, -31, 3),\n        DeviceInfo(\"sony\", \"G3123\", \"G3123\", 4, -24, 3),\n        DeviceInfo(\"sony\", \"G3223\", \"G3223\", 8, -27, 3),\n        DeviceInfo(\"sony\", \"G8141\", \"G8141\", 11, -34, 3),\n        DeviceInfo(\"sony\", \"G8142\", \"G8142\", 10, -27, 3),\n        DeviceInfo(\"sony\", \"G8232\", \"G8232\", 0, -34, 3),\n        DeviceInfo(\"sony\", \"G8341\", \"G8341\", 10, -31, 3),\n        DeviceInfo(\"sony\", \"G8342\", \"G8342\", 9, -28, 3),\n        DeviceInfo(\"sony\", \"G8441\", \"G8441\", 5, -24, 3),\n        DeviceInfo(\"sony\", \"H4113\", \"H4113\", 9, -31, 3),\n        DeviceInfo(\"sony\", \"H8216\", \"H8216\", 5, -31, 3),\n        DeviceInfo(\"sony\", \"H8266\", \"H8266\", 6, -30, 3),\n        DeviceInfo(\"sony\", \"H8296\", \"H8296\", 8, -32, 3),\n        DeviceInfo(\"sony\", \"H8314\", \"H8314\", 9, -33, 3),\n        DeviceInfo(\"sony\", \"H8324\", \"H8324\", 9, -33, 3),\n        DeviceInfo(\"sony\", \"H8416\", \"H8416\", 6, -30, 3),\n        DeviceInfo(\"sony\", \"I3113\", \"I3113\", 4, -28, 3),\n        DeviceInfo(\"sony\", \"I4213\", \"I4213\", 8, -29, 3),\n        DeviceInfo(\"sony\", \"I4312\", \"I4312\", 4, -31, 3),\n        DeviceInfo(\"sony\", \"SO-01J\", \"SO-01J\", 0, -32, 3),\n        DeviceInfo(\"sony\", \"SO-01K\", \"SO-01K\", 7, -29, 3),\n        DeviceInfo(\"sony\", \"SO-01L\", \"SO-01L\", 5, -32, 3),\n        DeviceInfo(\"sony\", \"SO-02L\", \"SO-02L\", 3, -26, 3),\n        DeviceInfo(\"sony\", \"SO-03J\", \"SO-03J\", 0, -34, 3),\n        DeviceInfo(\"sony\", \"SO-03K\", \"SO-03K\", 5, -29, 3),\n        DeviceInfo(\"sony\", \"SO-03L\", \"SO-03L\", 7, -28, 3),\n        DeviceInfo(\"sony\", \"SO-04J\", \"SO-04J\", 10, -31, 3),\n        DeviceInfo(\"sony\", \"SO-05K\", \"SO-05K\", 8, -31, 3),\n        DeviceInfo(\"sony\", \"SO-51A\", \"SO-51A\", 4, -45, 3),\n        DeviceInfo(\"sony\", \"SOV33\", \"SOV33\", -3, -33, 3),\n        DeviceInfo(\"sony\", \"SOV34\", \"SOV34\", -2, -32, 3),\n        DeviceInfo(\"sony\", \"SOV36\", \"SOV36\", 8, -27, 3),\n        DeviceInfo(\"sony\", \"SOV41\", \"SOV41\", 3, -25, 3),\n        DeviceInfo(\"sony\", \"SOV42\", \"SOV42\", 4, -29, 3),\n        DeviceInfo(\"sony\", \"XQ-AD51\", \"XQ-AD51\", 6, -31, 3),\n        DeviceInfo(\"sprint\", \"htc_acawhl\", \"2PYB2\", 10, -27, 3),\n        DeviceInfo(\"tcl\", \"A5A_INFINI\", \"5086D\", 3, -26, 3),\n        DeviceInfo(\"tcl\", \"T1_LITE\", \"T770B\", 4, -34, 3),\n        DeviceInfo(\"tcl\", \"T1\", \"T780H\", 5, -33, 3),\n        DeviceInfo(\"tcl\", \"Seattle\", \"T790Y\", 2, -32, 3),\n        DeviceInfo(\"tcl\", \"T1_PRO\", \"T799H\", 1, -31, 3),\n        DeviceInfo(\"tct (alcatel)\", \"Pixi4-4\", \"4034D\", 13, -40, 3),\n        DeviceInfo(\"tct (alcatel)\", \"Seoul\", \"5002D_EEA\", 2, -33, 3),\n        DeviceInfo(\"tct (alcatel)\", \"PIXI3_45_4G\", \"5017O\", 5, -29, 3),\n        DeviceInfo(\"tct (alcatel)\", \"Faraday\", \"5024A\", -6, -6, 3),\n        DeviceInfo(\"tct (alcatel)\", \"A3A_XL_3G\", \"5026A\", 0, -26, 3),\n        DeviceInfo(\"tct (alcatel)\", \"TokyoPro\", \"5029E\", -2, -24, 3),\n        DeviceInfo(\"tct (alcatel)\", \"Jakarta\", \"5030D_EEA\", -8, -6, 3),\n        DeviceInfo(\"tct (alcatel)\", \"Morgan_4G\", \"5032W\", 2, -29, 3),\n        DeviceInfo(\"tct (alcatel)\", \"U3A_PLUS_4G\", \"5033M\", 3, -26, 3),\n        DeviceInfo(\"tct (alcatel)\", \"U50A_ATT\", \"5041C\", 2, -24, 3),\n        DeviceInfo(\"tct (alcatel)\", \"BUZZ6T4G\", \"5044P\", 9, -33, 3),\n        DeviceInfo(\"tct (alcatel)\", \"PIXI4_5_4G\", \"5045F\", 19, -43, 3),\n        DeviceInfo(\"tct (alcatel)\", \"mickey6t\", \"5049G\", 2, -26, 3),\n        DeviceInfo(\"tct (alcatel)\", \"Mickey6TVZW\", \"5049S\", 3, -26, 3),\n        DeviceInfo(\"tct (alcatel)\", \"Mickey6TTMO\", \"5049Z\", 5, -29, 3),\n        DeviceInfo(\"tct (alcatel)\", \"A3A_PLUS\", \"5058A\", 4, -27, 3),\n        DeviceInfo(\"tct (alcatel)\", \"U5A_PLUS_4G\", \"5059A\", 1, -20, 3),\n        DeviceInfo(\"tct (alcatel)\", \"Milan\", \"5061K\", 2, -30, 3),\n        DeviceInfo(\"tct (alcatel)\", \"shine_lite\", \"5080X\", 4, -27, 3),\n        DeviceInfo(\"tct (alcatel)\", \"A3A_XL_4G\", \"5099U\", 2, -27, 3),\n        DeviceInfo(\"tct (alcatel)\", \"FERMI_TF\", \"A501DL\", 1, -24, 3),\n        DeviceInfo(\"tct (alcatel)\", \"U50A_PLUS_TF\", \"A502DL\", 5, -27, 3),\n        DeviceInfo(\"tct (alcatel)\", \"BUZZ6T4GTFUMTS\", \"A574BL\", 3, -28, 3),\n        DeviceInfo(\"tct (alcatel)\", \"FERMI_ATT\", \"Alcatel_5005R\", 2, -25, 3),\n        DeviceInfo(\"tct (alcatel)\", \"BUZZ6T4GGOPHONE\", \"Alcatel_5044R\", 4, -28, 3),\n        DeviceInfo(\"tct (alcatel)\", \"U50A_PLUS_ATT\", \"Alcatel_5059R\", 3, -27, 3),\n        DeviceInfo(\"tecno\", \"TECNO-BA2\", \"TECNO BA2\", 3, -27, 3),\n        DeviceInfo(\"tecno\", \"TECNO-BB4k\", \"TECNO BB4k\", 6, -28, 3),\n        DeviceInfo(\"tecno\", \"TECNO-CC6\", \"TECNO CC6\", 0, -28, 3),\n        DeviceInfo(\"tecno\", \"TECNO-CC7\", \"TECNO CC7\", 1, -25, 3),\n        DeviceInfo(\"tecno\", \"TECNO-CE9\", \"TECNO CE9\", 3, -27, 3),\n        DeviceInfo(\"tecno\", \"TECNO-CF7\", \"TECNO CF7\", 3, -11, 3),\n        DeviceInfo(\"tecno\", \"TECNO-KB7j\", \"TECNO KB7j\", 5, -29, 3),\n        DeviceInfo(\"tecno\", \"TECNO-KC1\", \"TECNO KC1\", 7, -28, 3),\n        DeviceInfo(\"tecno\", \"TECNO-KC2\", \"TECNO KC2\", 9, -33, 3),\n        DeviceInfo(\"tecno\", \"TECNO-KC6\", \"TECNO KC6\", 4, -28, 3),\n        DeviceInfo(\"tecno\", \"TECNO-KC8\", \"TECNO KC8\", 4, -28, 3),\n        DeviceInfo(\"tecno\", \"TECNO-LC6\", \"TECNO LC6\", 2, -31, 3),\n        DeviceInfo(\"tesla\", \"SS0801\", \"AC2003\", 1, -29, 3),\n        DeviceInfo(\"vivo\", \"1723\", \"vivo 1723\", 4, -20, 3),\n        DeviceInfo(\"vivo\", \"1804\", \"vivo 1804\", 5, -26, 3),\n        DeviceInfo(\"vodafone\", \"VFD610\", \"VFD 610\", 7, -29, 3),\n        DeviceInfo(\"xiaomi\", \"cancro\", \"MI 4W\", 4, -21, 3),\n        DeviceInfo(\"xiaomi\", \"gemini\", \"MI 5\", -2, -27, 3),\n        DeviceInfo(\"xiaomi\", \"capricorn\", \"MI 5s\", -4, -26, 3),\n        DeviceInfo(\"xiaomi\", \"natrium\", \"MI 5s Plus\", -3, -23, 3),\n        DeviceInfo(\"xiaomi\", \"sagit\", \"MI 6\", 2, -22, 3),\n        DeviceInfo(\"xiaomi\", \"dipper\", \"MI 8\", 1, -22, 3),\n        DeviceInfo(\"xiaomi\", \"platina\", \"MI 8 Lite\", 1, -21, 3),\n        DeviceInfo(\"xiaomi\", \"equuleus\", \"MI 8 Pro\", 1, -30, 3),\n        DeviceInfo(\"xiaomi\", \"nitrogen\", \"MI MAX 3\", 3, -24, 3),\n        DeviceInfo(\"xiaomi\", \"virgo\", \"MI NOTE LTE\", 9, -23, 3),\n        DeviceInfo(\"xiaomi\", \"lithium\", \"MIX\", -2, -27, 3),\n        DeviceInfo(\"xiaomi\", \"davinci\", \"Mi 9T\", 3, -31, 3),\n        DeviceInfo(\"xiaomi\", \"tissot_sprout\", \"Mi A1\", 1, -18, 3),\n        DeviceInfo(\"xiaomi\", \"jasmine_sprout\", \"Mi A2\", 2, -23, 3),\n        DeviceInfo(\"xiaomi\", \"daisy_sprout\", \"Mi A2 Lite\", 4, -21, 3),\n        DeviceInfo(\"xiaomi\", \"laurel_sprout\", \"Mi A3\", 1, -19, 3),\n        DeviceInfo(\"xiaomi\", \"chiron\", \"Mi MIX 2\", 6, -24, 3),\n        DeviceInfo(\"xiaomi\", \"polaris\", \"Mi MIX 2S\", 1, -19, 3),\n        DeviceInfo(\"xiaomi\", \"scorpio\", \"Mi Note 2\", -2, -25, 3),\n        DeviceInfo(\"xiaomi\", \"ido\", \"Redmi 3\", 3, -21, 3),\n        DeviceInfo(\"xiaomi\", \"land\", \"Redmi 3S\", -1, -25, 3),\n        DeviceInfo(\"xiaomi\", \"santoni\", \"Redmi 4X\", -1, -23, 3),\n        DeviceInfo(\"xiaomi\", \"rosy\", \"Redmi 5\", 4, -31, 3),\n        DeviceInfo(\"xiaomi\", \"riva\", \"Redmi 5A\", 3, -29, 3),\n        DeviceInfo(\"xiaomi\", \"cereus\", \"Redmi 6\", 1, -25, 3),\n        DeviceInfo(\"xiaomi\", \"sakura_india\", \"Redmi 6 Pro\", 5, -21, 3),\n        DeviceInfo(\"xiaomi\", \"cactus\", \"Redmi 6A\", 2, -27, 3),\n        DeviceInfo(\"xiaomi\", \"onc\", \"Redmi 7\", 4, -30, 3),\n        DeviceInfo(\"xiaomi\", \"pine\", \"Redmi 7A\", 4, -34, 3),\n        DeviceInfo(\"xiaomi\", \"olive\", \"Redmi 8\", 10, -31, 3),\n        DeviceInfo(\"xiaomi\", \"tiare\", \"Redmi Go\", 5, -31, 3),\n        DeviceInfo(\"xiaomi\", \"kenzo\", \"Redmi Note 3\", 5, -22, 3),\n        DeviceInfo(\"xiaomi\", \"whyred\", \"Redmi Note 5\", 1, -20, 3),\n        DeviceInfo(\"xiaomi\", \"tulip\", \"Redmi Note 6 Pro\", 4, -29, 3),\n        DeviceInfo(\"xiaomi\", \"violet\", \"Redmi Note 7 Pro\", 4, -30, 3),\n        DeviceInfo(\"xiaomi\", \"ysl\", \"Redmi S2\", 4, -29, 3),\n        DeviceInfo(\"zte\", \"P809F15\", \"BLADE A6 MAX\", 4, -28, 3),\n        DeviceInfo(\"zte\", \"P450L10\", \"BLADE V9\", 7, -31, 3),\n        DeviceInfo(\"zte\", \"P963F50\", \"Blade A5 2020-T\", -3, -11, 3),\n        DeviceInfo(\"zte\", \"Z6350T\", \"Blade A7S 2020-T\", -4, 1, 3),\n        DeviceInfo(\"zte\", \"Z6351O\", \"P650 Pro\", -4, 0, 3),\n        DeviceInfo(\"zte\", \"T86\", \"T86\", 3, -29, 3),\n        DeviceInfo(\"zte\", \"Z3351\", \"Z3351S\", 3, -25, 3),\n        DeviceInfo(\"zte\", \"Z5151\", \"Z5151V\", 6, -33, 3),\n        DeviceInfo(\"zte\", \"Z5156\", \"Z5156CC\", 0, -25, 3),\n        DeviceInfo(\"zte\", \"Z5157\", \"Z5157V\", -1, -24, 3),\n        DeviceInfo(\"zte\", \"Z6201\", \"Z6201V\", 12, -36, 3),\n        DeviceInfo(\"zte\", \"Z6250\", \"Z6250CC\", 0, -25, 3),\n        DeviceInfo(\"zte\", \"Z6530\", \"Z6530V\", 15, -39, 3),\n        DeviceInfo(\"zte\", \"camellia\", \"Z833\", 3, -25, 3),\n        DeviceInfo(\"zte\", \"Z7750R\", \"ZR01\", 16, -36, 3),\n        DeviceInfo(\"zte\", \"P963F05\", \"ZTE 8010\", -3, -2, 3),\n        DeviceInfo(\"zte\", \"P963F05\", \"ZTE 8010RU\", -3, -2, 3),\n        DeviceInfo(\"zte\", \"P671F60\", \"ZTE 9000\", 4, -28, 3),\n        DeviceInfo(\"zte\", \"P683S10\", \"ZTE 9000N\", 9, -31, 3),\n        DeviceInfo(\"zte\", \"P845A01\", \"ZTE A2019G Pro\", 8, -26, 3),\n        DeviceInfo(\"zte\", \"P855A02\", \"ZTE A2020 Pro\", 6, -25, 3),\n        DeviceInfo(\"zte\", \"P855A01\", \"ZTE A2020G Pro\", 8, -28, 3),\n        DeviceInfo(\"zte\", \"P855A21\", \"ZTE A2020N3 Pro\", 6, -26, 3),\n        DeviceInfo(\"zte\", \"P855A03_NA\", \"ZTE A2020U Pro\", 6, -26, 3),\n        DeviceInfo(\"zte\", \"P725A12\", \"ZTE A2021\", 9, -29, 3),\n        DeviceInfo(\"zte\", \"P725A11\", \"ZTE A2021G\", -1, -29, 3),\n        DeviceInfo(\"zte\", \"P725A12\", \"ZTE A2021H\", 0, -28, 3),\n        DeviceInfo(\"zte\", \"P725A02\", \"ZTE A2121\", 9, -31, 3),\n        DeviceInfo(\"zte\", \"P618A01\", \"ZTE A2121E\", 1, -26, 3),\n        DeviceInfo(\"zte\", \"P963F03\", \"ZTE A7020\", -3, -4, 3),\n        DeviceInfo(\"zte\", \"P963F03\", \"ZTE A7020RU\", -3, -4, 3),\n        DeviceInfo(\"zte\", \"P932F20\", \"ZTE Blade A3 2019\", -4, -4, 3),\n        DeviceInfo(\"zte\", \"P932F50\", \"ZTE Blade A3 2020\", -4, -7, 3),\n        DeviceInfo(\"zte\", \"P932K30\", \"ZTE Blade A3 2020\", -5, -4, 3),\n        DeviceInfo(\"zte\", \"P963F50\", \"ZTE Blade A5 2020\", -3, -10, 3),\n        DeviceInfo(\"zte\", \"P662F02\", \"ZTE Blade A7s\", 2, -27, 3),\n        DeviceInfo(\"zte\", \"P731K30\", \"ZTE Blade L130\", -5, -5, 3),\n        DeviceInfo(\"zte\", \"P731F50\", \"ZTE Blade L210\", -4, -2, 3),\n        DeviceInfo(\"zte\", \"P731F50\", \"ZTE Blade L210RU\", -4, -5, 3),\n        DeviceInfo(\"zte\", \"P671F20\", \"ZTE Blade V10\", 7, -31, 3),\n        DeviceInfo(\"zte\", \"P963F01\", \"ZTE Blade V10 Vita\", -3, -10, 3)\n)\n"
  },
  {
    "path": "play-services-nearby/core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ExposureDatabase.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.nearby.exposurenotification\n\nimport android.annotation.TargetApi\nimport android.content.ContentValues\nimport android.content.Context\nimport android.content.Intent\nimport android.database.DatabaseUtils\nimport android.database.sqlite.SQLiteCursor\nimport android.database.sqlite.SQLiteDatabase\nimport android.database.sqlite.SQLiteDatabase.CONFLICT_IGNORE\nimport android.database.sqlite.SQLiteOpenHelper\nimport android.database.sqlite.SQLiteQueryBuilder\nimport android.net.Uri\nimport android.os.Parcel\nimport android.os.Parcelable\nimport android.util.Log\nimport androidx.core.content.FileProvider\nimport com.google.android.gms.nearby.exposurenotification.*\nimport kotlinx.coroutines.*\nimport okio.ByteString\nimport org.microg.gms.common.PackageUtils\nimport java.io.File\nimport java.lang.Runnable\nimport java.nio.ByteBuffer\nimport java.util.*\nimport java.util.concurrent.*\nimport kotlin.experimental.and\n\n@TargetApi(21)\nclass ExposureDatabase private constructor(private val context: Context) : SQLiteOpenHelper(context, DB_NAME, null, DB_VERSION) {\n    private val createdAt: Exception = Exception(\"Database ${hashCode()} created\")\n    private var refCount = 1\n\n    init {\n        setWriteAheadLoggingEnabled(true)\n    }\n\n    override fun onConfigure(db: SQLiteDatabase) {\n        super.onConfigure(db)\n        db.setForeignKeyConstraintsEnabled(true)\n    }\n\n    override fun onCreate(db: SQLiteDatabase) {\n        onUpgrade(db, 0, DB_VERSION)\n    }\n\n    override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {\n        Log.d(TAG, \"Upgrading database from $oldVersion to $newVersion\")\n        if (oldVersion < 1) {\n            Log.d(TAG, \"Creating tables for version >= 1\")\n            db.execSQL(\"CREATE TABLE IF NOT EXISTS $TABLE_ADVERTISEMENTS(rpi BLOB NOT NULL, aem BLOB NOT NULL, timestamp INTEGER NOT NULL, rssi INTEGER NOT NULL, duration INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(rpi, timestamp));\")\n            db.execSQL(\"CREATE INDEX IF NOT EXISTS index_${TABLE_ADVERTISEMENTS}_rpi ON $TABLE_ADVERTISEMENTS(rpi);\")\n            db.execSQL(\"CREATE INDEX IF NOT EXISTS index_${TABLE_ADVERTISEMENTS}_timestamp ON $TABLE_ADVERTISEMENTS(timestamp);\")\n            db.execSQL(\"CREATE TABLE IF NOT EXISTS $TABLE_APP_LOG(package TEXT NOT NULL, timestamp INTEGER NOT NULL, method TEXT NOT NULL, args TEXT);\")\n            db.execSQL(\"CREATE INDEX IF NOT EXISTS index_${TABLE_APP_LOG}_package_timestamp ON $TABLE_APP_LOG(package, timestamp);\")\n            db.execSQL(\"CREATE TABLE IF NOT EXISTS $TABLE_TEK(keyData BLOB NOT NULL, rollingStartNumber INTEGER NOT NULL, rollingPeriod INTEGER NOT NULL);\")\n        }\n        if (oldVersion < 3) {\n            Log.d(TAG, \"Creating tables for version >= 3\")\n            db.execSQL(\"CREATE TABLE $TABLE_APP_PERMS(package TEXT NOT NULL, sig TEXT NOT NULL, perm TEXT NOT NULL, timestamp INTEGER NOT NULL);\")\n        }\n        if (oldVersion < 5) {\n            Log.d(TAG, \"Creating tables for version >= 5\")\n            db.execSQL(\"CREATE TABLE IF NOT EXISTS $TABLE_TOKENS(tid INTEGER PRIMARY KEY, package TEXT NOT NULL, token TEXT NOT NULL, timestamp INTEGER NOT NULL, configuration BLOB, diagnosisKeysDataMap BLOB);\")\n            db.execSQL(\"CREATE UNIQUE INDEX IF NOT EXISTS index_${TABLE_TOKENS}_package_token ON $TABLE_TOKENS(package, token);\")\n            db.execSQL(\"CREATE TABLE IF NOT EXISTS $TABLE_TEK_CHECK_SINGLE(tcsid INTEGER PRIMARY KEY, keyData BLOB NOT NULL, rollingStartNumber INTEGER NOT NULL, rollingPeriod INTEGER NOT NULL, matched INTEGER);\")\n            db.execSQL(\"CREATE UNIQUE INDEX IF NOT EXISTS index_${TABLE_TEK_CHECK_SINGLE}_key ON $TABLE_TEK_CHECK_SINGLE(keyData, rollingStartNumber, rollingPeriod);\")\n            db.execSQL(\"CREATE TABLE IF NOT EXISTS $TABLE_TEK_CHECK_SINGLE_TOKEN(tcsid INTEGER REFERENCES $TABLE_TEK_CHECK_SINGLE(tcsid) ON DELETE CASCADE, tid INTEGER REFERENCES $TABLE_TOKENS(tid) ON DELETE CASCADE, transmissionRiskLevel INTEGER NOT NULL, reportType INTEGER NOT NULL, daysSinceOnsetOfSymptoms INTEGER NOT NULL, UNIQUE(tcsid, tid));\")\n            db.execSQL(\"CREATE INDEX IF NOT EXISTS index_${TABLE_TEK_CHECK_SINGLE_TOKEN}_tid ON $TABLE_TEK_CHECK_SINGLE_TOKEN(tid);\")\n            db.execSQL(\"CREATE TABLE IF NOT EXISTS $TABLE_TEK_CHECK_FILE(tcfid INTEGER PRIMARY KEY, hash TEXT NOT NULL, endTimestamp INTEGER NOT NULL, keys INTEGER NOT NULL);\")\n            db.execSQL(\"CREATE UNIQUE INDEX IF NOT EXISTS index_${TABLE_TEK_CHECK_FILE}_hash ON $TABLE_TEK_CHECK_FILE(hash);\")\n            db.execSQL(\"CREATE TABLE IF NOT EXISTS $TABLE_TEK_CHECK_FILE_TOKEN(tcfid INTEGER REFERENCES $TABLE_TEK_CHECK_FILE(tcfid) ON DELETE CASCADE, tid INTEGER REFERENCES $TABLE_TOKENS(tid) ON DELETE CASCADE, UNIQUE(tcfid, tid));\")\n            db.execSQL(\"CREATE INDEX IF NOT EXISTS index_${TABLE_TEK_CHECK_FILE_TOKEN}_tid ON $TABLE_TEK_CHECK_FILE_TOKEN(tid);\")\n            db.execSQL(\"CREATE TABLE IF NOT EXISTS $TABLE_TEK_CHECK_FILE_MATCH(tcfid INTEGER REFERENCES $TABLE_TEK_CHECK_FILE(tcfid) ON DELETE CASCADE, keyData BLOB NOT NULL, rollingStartNumber INTEGER NOT NULL, rollingPeriod INTEGER NOT NULL, transmissionRiskLevel INTEGER NOT NULL, reportType INTEGER NOT NULL, daysSinceOnsetOfSymptoms INTEGER NOT NULL, UNIQUE(tcfid, keyData, rollingStartNumber, rollingPeriod));\")\n            db.execSQL(\"CREATE INDEX IF NOT EXISTS index_${TABLE_TEK_CHECK_FILE_MATCH}_tcfid ON $TABLE_TEK_CHECK_FILE_MATCH(tcfid);\")\n            db.execSQL(\"CREATE INDEX IF NOT EXISTS index_${TABLE_TEK_CHECK_FILE_MATCH}_key ON $TABLE_TEK_CHECK_FILE_MATCH(keyData, rollingStartNumber, rollingPeriod);\")\n        }\n        if (oldVersion < 9) {\n            Log.d(TAG, \"Creating tables for version >= 9\")\n            db.execSQL(\"CREATE TABLE IF NOT EXISTS $TABLE_APP(package TEXT NOT NULL, sig TEXT NOT NULL, PRIMARY KEY (package, sig));\")\n        }\n        if (oldVersion in 5 until 7) {\n            Log.d(TAG, \"Altering tables for version >= 7\")\n            db.execSQL(\"ALTER TABLE $TABLE_TOKENS ADD COLUMN diagnosisKeysDataMap BLOB;\")\n        }\n        if (oldVersion in 5 until 11) {\n            Log.d(TAG, \"Altering tables for version >= 11\")\n            db.execSQL(\"ALTER TABLE $TABLE_TEK_CHECK_SINGLE_TOKEN ADD COLUMN reportType INTEGER NOT NULL DEFAULT ${ReportType.UNKNOWN};\")\n            db.execSQL(\"ALTER TABLE $TABLE_TEK_CHECK_SINGLE_TOKEN ADD COLUMN daysSinceOnsetOfSymptoms INTEGER NOT NULL DEFAULT ${TemporaryExposureKey.DAYS_SINCE_ONSET_OF_SYMPTOMS_UNKNOWN};\")\n            db.execSQL(\"ALTER TABLE $TABLE_TEK_CHECK_FILE_MATCH ADD COLUMN reportType INTEGER NOT NULL DEFAULT ${ReportType.UNKNOWN};\")\n            db.execSQL(\"ALTER TABLE $TABLE_TEK_CHECK_FILE_MATCH ADD COLUMN daysSinceOnsetOfSymptoms INTEGER NOT NULL DEFAULT ${TemporaryExposureKey.DAYS_SINCE_ONSET_OF_SYMPTOMS_UNKNOWN};\")\n        }\n        if (oldVersion in 1 until 5) {\n            Log.d(TAG, \"Dropping legacy tables from version < 5\")\n            db.execSQL(\"DROP TABLE IF EXISTS $TABLE_CONFIGURATIONS;\")\n            db.execSQL(\"DROP TABLE IF EXISTS $TABLE_DIAGNOSIS;\")\n            db.execSQL(\"DROP TABLE IF EXISTS $TABLE_TEK_CHECK;\")\n        }\n        if (oldVersion in 1 until 6) {\n            Log.d(TAG, \"Fixing invalid rssi values from version < 6\")\n            // There's no bluetooth chip with a sensitivity that would result in rssi -200, so this would be invalid.\n            // RSSI of -100 is already extremely low and thus is a good \"default\" value\n            db.execSQL(\"UPDATE $TABLE_ADVERTISEMENTS SET rssi = -100 WHERE rssi < -200;\")\n        }\n        if (oldVersion in 5 until 7) {\n            Log.d(TAG, \"Clearing non-matching tek cache from version < 7\")\n            // Entries might be invalid due to previously missing support for new bluetooth AEM format\n            db.execSQL(\"DELETE FROM $TABLE_TEK_CHECK_FILE WHERE tcfid NOT IN (SELECT tcfid FROM $TABLE_TEK_CHECK_FILE_MATCH);\")\n        }\n        if (oldVersion in 1 until 9) {\n            Log.d(TAG, \"Migrating authorized apps from version < 9\")\n            val pm = context.packageManager\n            db.query(true, TABLE_APP_LOG, arrayOf(\"package\"), null, null, null, null, null, null).use { cursor ->\n                while (cursor.moveToNext()) {\n                    val packageName = cursor.getString(0)\n                    val signatureDigest = PackageUtils.firstSignatureDigest(pm, packageName)\n                    if (signatureDigest != null) {\n                        db.insertWithOnConflict(TABLE_APP, \"NULL\", ContentValues().apply {\n                            put(\"package\", packageName)\n                            put(\"sig\", signatureDigest)\n                        }, CONFLICT_IGNORE)\n                    }\n                }\n            }\n        }\n        if (oldVersion == 9) {\n            Log.d(TAG, \"Get rid of isEnabled log entries\")\n            db.delete(TABLE_APP_LOG, \"method = ?\", arrayOf(\"isEnabled\"));\n        }\n        if (oldVersion == 11) {\n            Log.d(TAG, \"Fixing invalid rssi values from version 11 with release 0.2.23\")\n            // Setting the RSSI to -75. This is obviously not the correct value, but is still way better estimate\n            // than 0, based on the measurements shown in https://github.com/microg/GmsCore/issues/1655\n            db.execSQL(\"UPDATE $TABLE_ADVERTISEMENTS SET rssi = -75 WHERE rssi = 0 AND duration > 0\")\n        }\n        Log.d(TAG, \"Finished database upgrade\")\n    }\n\n    fun SQLiteDatabase.delete(table: String, whereClause: String, args: LongArray): Int =\n            compileStatement(\"DELETE FROM $table WHERE $whereClause\").use {\n                args.forEachIndexed { idx, l -> it.bindLong(idx + 1, l) }\n                it.executeUpdateDelete()\n            }\n\n    fun dailyCleanup(): Boolean = writableDatabase.run {\n        val start = System.currentTimeMillis()\n        val rollingStartTime = currentDayRollingStartNumber.toLong() * ROLLING_WINDOW_LENGTH_MS - TimeUnit.DAYS.toMillis(KEEP_DAYS.toLong())\n        val advertisements = delete(TABLE_ADVERTISEMENTS, \"timestamp < ?\", longArrayOf(rollingStartTime))\n        Log.d(TAG, \"Deleted on daily cleanup: $advertisements adv\")\n        if (start + MAX_DELETE_TIME < System.currentTimeMillis()) return@run false\n        val appLogEntries = delete(TABLE_APP_LOG, \"timestamp < ?\", longArrayOf(rollingStartTime))\n        Log.d(TAG, \"Deleted on daily cleanup: $appLogEntries applogs\")\n        if (start + MAX_DELETE_TIME < System.currentTimeMillis()) return@run false\n        val tokens = delete(TABLE_TOKENS, \"timestamp < ?\", longArrayOf(rollingStartTime))\n        Log.d(TAG, \"Deleted on daily cleanup: $tokens tokens\")\n        if (start + MAX_DELETE_TIME < System.currentTimeMillis()) return@run false\n        val temporaryExposureKeys = delete(TABLE_TEK, \"(rollingStartNumber + rollingPeriod) < ?\", longArrayOf(rollingStartTime / ROLLING_WINDOW_LENGTH_MS))\n        Log.d(TAG, \"Deleted on daily cleanup: $temporaryExposureKeys teks\")\n        if (start + MAX_DELETE_TIME < System.currentTimeMillis()) return@run false\n        val singleCheckedTemporaryExposureKeys = delete(TABLE_TEK_CHECK_SINGLE, \"rollingStartNumber < ?\", longArrayOf(rollingStartTime / ROLLING_WINDOW_LENGTH_MS - ROLLING_PERIOD))\n        Log.d(TAG, \"Deleted on daily cleanup: $singleCheckedTemporaryExposureKeys tcss\")\n        if (start + MAX_DELETE_TIME < System.currentTimeMillis()) return@run false\n        val fileCheckedTemporaryExposureKeys = delete(TABLE_TEK_CHECK_FILE, \"endTimestamp < ?\", longArrayOf(rollingStartTime))\n        Log.d(TAG, \"Deleted on daily cleanup: $fileCheckedTemporaryExposureKeys tcfs\")\n        if (start + MAX_DELETE_TIME < System.currentTimeMillis()) return@run false\n        val appPerms = delete(TABLE_APP_PERMS, \"timestamp < ?\", longArrayOf(System.currentTimeMillis() - CONFIRM_PERMISSION_VALIDITY))\n        Log.d(TAG, \"Deleted on daily cleanup: $appPerms perms\")\n        if (start + MAX_DELETE_TIME < System.currentTimeMillis()) return@run false\n        execSQL(\"VACUUM;\")\n        Log.d(TAG, \"Done vacuuming\")\n        return@run true\n    }\n\n    fun grantPermission(packageName: String, signatureDigest: String, permission: String, timestamp: Long = System.currentTimeMillis()) = writableDatabase.run {\n        insert(TABLE_APP_PERMS, \"NULL\", ContentValues().apply {\n            put(\"package\", packageName)\n            put(\"sig\", signatureDigest)\n            put(\"perm\", permission)\n            put(\"timestamp\", timestamp)\n        })\n    }\n\n    fun hasPermission(packageName: String, signatureDigest: String, permission: String, maxAge: Long = CONFIRM_PERMISSION_VALIDITY) = readableDatabase.run {\n        query(TABLE_APP_PERMS, arrayOf(\"MAX(timestamp)\"), \"package = ? AND sig = ? and perm = ?\", arrayOf(packageName, signatureDigest, permission), null, null, null).use { cursor ->\n            cursor.moveToNext() && cursor.getLong(0) + maxAge > System.currentTimeMillis()\n        }\n    }\n\n    fun noteAdvertisement(rpi: ByteArray, aem: ByteArray, rssi: Int, timestamp: Long = Date().time) = writableDatabase.run {\n        val update = compileStatement(\"UPDATE $TABLE_ADVERTISEMENTS SET rssi = IFNULL(((rssi * duration) + (? * MAX(0, ? - timestamp - duration))) / MAX(duration, ? - timestamp), -100), duration = MAX(duration, ? - timestamp) WHERE rpi = ? AND timestamp > ? AND timestamp < ?\").run {\n            bindLong(1, rssi.toLong())\n            bindLong(2, timestamp)\n            bindLong(3, timestamp)\n            bindLong(4, timestamp)\n            bindBlob(5, rpi)\n            bindLong(6, timestamp - ALLOWED_KEY_OFFSET_MS)\n            bindLong(7, timestamp + ALLOWED_KEY_OFFSET_MS)\n            executeUpdateDelete()\n        }\n        if (update <= 0) {\n            insert(TABLE_ADVERTISEMENTS, \"NULL\", ContentValues().apply {\n                put(\"rpi\", rpi)\n                put(\"aem\", aem)\n                put(\"timestamp\", timestamp)\n                put(\"rssi\", rssi)\n                put(\"duration\", MINIMUM_EXPOSURE_DURATION_MS)\n            })\n        }\n    }\n\n    fun deleteAllCollectedAdvertisements() = writableDatabase.run {\n        delete(TABLE_ADVERTISEMENTS, null, null)\n        delete(TABLE_TEK_CHECK_FILE_MATCH, null, null)\n        update(TABLE_TEK_CHECK_SINGLE, ContentValues().apply {\n            put(\"matched\", 0)\n        }, null, null)\n    }\n\n    fun authorizeApp(packageName: String?, signatureDigest: String? = PackageUtils.firstSignatureDigest(context, packageName)) = writableDatabase.run {\n        if (packageName == null || signatureDigest == null) return@run\n        insertWithOnConflict(TABLE_APP, \"NULL\", ContentValues().apply {\n            put(\"package\", packageName)\n            put(\"sig\", signatureDigest)\n        }, CONFLICT_IGNORE)\n    }\n\n    fun isAppAuthorized(packageName: String?, signatureDigest: String? = PackageUtils.firstSignatureDigest(context, packageName)): Boolean = readableDatabase.run {\n        if (packageName == null || signatureDigest == null) return@run false\n        query(TABLE_APP, arrayOf(\"package\"), \"package = ? AND sig = ?\", arrayOf(packageName, signatureDigest), null, null, null).use { cursor ->\n            return@use cursor.moveToNext()\n        }\n    }\n\n    fun noteAppAction(packageName: String, method: String, args: String? = null, timestamp: Long = Date().time) = writableDatabase.run {\n        insert(TABLE_APP_LOG, \"NULL\", ContentValues().apply {\n            put(\"package\", packageName)\n            put(\"timestamp\", timestamp)\n            put(\"method\", method)\n            put(\"args\", args)\n        })\n    }\n\n    private fun storeOwnKey(key: TemporaryExposureKey, database: SQLiteDatabase = writableDatabase) = database.run {\n        insert(TABLE_TEK, \"NULL\", ContentValues().apply {\n            put(\"keyData\", key.keyData)\n            put(\"rollingStartNumber\", key.rollingStartIntervalNumber)\n            put(\"rollingPeriod\", key.rollingPeriod)\n        })\n    }\n\n    private fun getTekCheckSingleId(key: TemporaryExposureKey, mayInsert: Boolean = false, database: SQLiteDatabase = if (mayInsert) writableDatabase else readableDatabase): Long? = database.run {\n        if (mayInsert) {\n            insertWithOnConflict(TABLE_TEK_CHECK_SINGLE, \"NULL\", ContentValues().apply {\n                put(\"keyData\", key.keyData)\n                put(\"rollingStartNumber\", key.rollingStartIntervalNumber)\n                put(\"rollingPeriod\", key.rollingPeriod)\n            }, CONFLICT_IGNORE)\n        }\n        compileStatement(\"SELECT tcsid FROM $TABLE_TEK_CHECK_SINGLE WHERE keyData = ? AND rollingStartNumber = ? AND rollingPeriod = ?\").use {\n            it.bindBlob(1, key.keyData)\n            it.bindLong(2, key.rollingStartIntervalNumber.toLong())\n            it.bindLong(3, key.rollingPeriod.toLong())\n            it.simpleQueryForLong()\n        }\n    }\n\n    fun getTokenId(packageName: String, token: String, database: SQLiteDatabase = readableDatabase) = database.run {\n        query(TABLE_TOKENS, arrayOf(\"tid\"), \"package = ? AND token = ?\", arrayOf(packageName, token), null, null, null, null).use { cursor ->\n            if (cursor.moveToNext()) {\n                cursor.getLong(0)\n            } else {\n                null\n            }\n        }\n    }\n\n    fun getOrCreateTokenId(packageName: String, token: String, database: SQLiteDatabase = writableDatabase) = database.run {\n        val tid = getTokenId(packageName, token, this)\n        if (tid != null) {\n            tid\n        } else {\n            insert(TABLE_TOKENS, \"NULL\", ContentValues().apply {\n                put(\"package\", packageName)\n                put(\"token\", token)\n                put(\"timestamp\", System.currentTimeMillis())\n            })\n            getTokenId(packageName, token, this)\n        }\n    }\n\n    private fun storeSingleDiagnosisKey(tid: Long, key: TemporaryExposureKey, database: SQLiteDatabase = writableDatabase) = database.run {\n        val tcsid = getTekCheckSingleId(key, true, database)\n        insert(TABLE_TEK_CHECK_SINGLE_TOKEN, \"NULL\", ContentValues().apply {\n            put(\"tid\", tid)\n            put(\"tcsid\", tcsid)\n            put(\"transmissionRiskLevel\", key.transmissionRiskLevel)\n            put(\"reportType\", key.reportType)\n            put(\"daysSinceOnsetOfSymptoms\", key.daysSinceOnsetOfSymptoms)\n        })\n    }\n\n    fun batchStoreSingleDiagnosisKey(tid: Long, keys: List<TemporaryExposureKey>, database: SQLiteDatabase = writableDatabase) = database.run {\n        beginTransactionNonExclusive()\n        try {\n            keys.forEach { storeSingleDiagnosisKey(tid, it, database) }\n            setTransactionSuccessful()\n        } finally {\n            endTransaction()\n        }\n    }\n\n    fun getDiagnosisFileId(hash: ByteArray, database: SQLiteDatabase = readableDatabase) = database.run {\n        val hexHash = ByteString.of(*hash).hex()\n        query(TABLE_TEK_CHECK_FILE, arrayOf(\"tcfid\"), \"hash = ?\", arrayOf(hexHash), null, null, null, null).use { cursor ->\n            if (cursor.moveToNext()) {\n                cursor.getLong(0)\n            } else {\n                null\n            }\n        }\n    }\n\n    fun storeDiagnosisFileUsed(tid: Long, tcfid: Long, database: SQLiteDatabase = writableDatabase) = database.run {\n        insert(TABLE_TEK_CHECK_FILE_TOKEN, \"NULL\", ContentValues().apply {\n            put(\"tid\", tid)\n            put(\"tcfid\", tcfid)\n        })\n    }\n\n    fun storeDiagnosisFileUsed(tid: Long, hash: ByteArray, database: SQLiteDatabase = writableDatabase) = database.run {\n        val hexHash = ByteString.of(*hash).hex()\n        query(TABLE_TEK_CHECK_FILE, arrayOf(\"tcfid\", \"keys\"), \"hash = ?\", arrayOf(hexHash), null, null, null, null).use { cursor ->\n            if (cursor.moveToNext()) {\n                insertWithOnConflict(TABLE_TEK_CHECK_FILE_TOKEN, \"NULL\", ContentValues().apply {\n                    put(\"tid\", tid)\n                    put(\"tcfid\", cursor.getLong(0))\n                }, CONFLICT_IGNORE)\n                cursor.getLong(1)\n            } else {\n                null\n            }\n        }\n    }\n\n    private fun listSingleDiagnosisKeysPendingSearch(tid: Long, database: SQLiteDatabase = readableDatabase) = database.run {\n        rawQuery(\"\"\"\n            SELECT $TABLE_TEK_CHECK_SINGLE.keyData, $TABLE_TEK_CHECK_SINGLE.rollingStartNumber, $TABLE_TEK_CHECK_SINGLE.rollingPeriod\n            FROM $TABLE_TEK_CHECK_SINGLE_TOKEN\n            LEFT JOIN $TABLE_TEK_CHECK_SINGLE ON $TABLE_TEK_CHECK_SINGLE.tcsid = $TABLE_TEK_CHECK_SINGLE_TOKEN.tcsid\n            WHERE \n                $TABLE_TEK_CHECK_SINGLE_TOKEN.tid = ? AND\n                $TABLE_TEK_CHECK_SINGLE.matched IS NULL\n                \"\"\", arrayOf(tid.toString())).use { cursor ->\n            val list = arrayListOf<TemporaryExposureKey>()\n            while (cursor.moveToNext()) {\n                list.add(TemporaryExposureKey.TemporaryExposureKeyBuilder()\n                        .setKeyData(cursor.getBlob(0))\n                        .setRollingStartIntervalNumber(cursor.getLong(1).toInt())\n                        .setRollingPeriod(cursor.getLong(2).toInt())\n                        .build())\n            }\n            list\n        }\n    }\n\n    private fun applySingleDiagnosisKeySearchResult(key: TemporaryExposureKey, matched: Boolean, database: SQLiteDatabase = writableDatabase) = database.run {\n        compileStatement(\"UPDATE $TABLE_TEK_CHECK_SINGLE SET matched = ? WHERE keyData = ? AND rollingStartNumber = ? AND rollingPeriod = ?;\").use {\n            it.bindLong(1, if (matched) 1 else 0)\n            it.bindBlob(2, key.keyData)\n            it.bindLong(3, key.rollingStartIntervalNumber.toLong())\n            it.bindLong(4, key.rollingPeriod.toLong())\n            it.executeUpdateDelete()\n        }\n    }\n\n    private fun applyDiagnosisFileKeySearchResult(tcfid: Long, key: TemporaryExposureKey, database: SQLiteDatabase = writableDatabase) = database.run {\n        insert(TABLE_TEK_CHECK_FILE_MATCH, \"NULL\", ContentValues().apply {\n            put(\"tcfid\", tcfid)\n            put(\"keyData\", key.keyData)\n            put(\"rollingStartNumber\", key.rollingStartIntervalNumber)\n            put(\"rollingPeriod\", key.rollingPeriod)\n            put(\"transmissionRiskLevel\", key.transmissionRiskLevel)\n            put(\"reportType\", key.reportType)\n            put(\"daysSinceOnsetOfSymptoms\", key.daysSinceOnsetOfSymptoms)\n        })\n    }\n\n    private fun listMatchedSingleDiagnosisKeys(tid: Long, database: SQLiteDatabase = readableDatabase) = database.run {\n        rawQuery(\"\"\"\n            SELECT $TABLE_TEK_CHECK_SINGLE.keyData, $TABLE_TEK_CHECK_SINGLE.rollingStartNumber, $TABLE_TEK_CHECK_SINGLE.rollingPeriod, $TABLE_TEK_CHECK_SINGLE_TOKEN.transmissionRiskLevel, $TABLE_TEK_CHECK_SINGLE_TOKEN.reportType, $TABLE_TEK_CHECK_SINGLE_TOKEN.daysSinceOnsetOfSymptoms\n            FROM $TABLE_TEK_CHECK_SINGLE_TOKEN\n            JOIN $TABLE_TEK_CHECK_SINGLE ON $TABLE_TEK_CHECK_SINGLE.tcsid = $TABLE_TEK_CHECK_SINGLE_TOKEN.tcsid\n            WHERE \n                $TABLE_TEK_CHECK_SINGLE_TOKEN.tid = ? AND\n                $TABLE_TEK_CHECK_SINGLE.matched = 1\n                \"\"\", arrayOf(tid.toString())).use { cursor ->\n            val list = arrayListOf<TemporaryExposureKey>()\n            while (cursor.moveToNext()) {\n                list.add(TemporaryExposureKey.TemporaryExposureKeyBuilder()\n                        .setKeyData(cursor.getBlob(0))\n                        .setRollingStartIntervalNumber(cursor.getLong(1).toInt())\n                        .setRollingPeriod(cursor.getLong(2).toInt())\n                        .setTransmissionRiskLevel(cursor.getLong(3).toInt())\n                        .setReportType(cursor.getLong(4).toInt())\n                        .setDaysSinceOnsetOfSymptoms(cursor.getLong(5).toInt())\n                        .build())\n            }\n            list\n        }\n    }\n\n    private fun listMatchedFileDiagnosisKeys(tid: Long, database: SQLiteDatabase = readableDatabase) = database.run {\n        rawQuery(\"\"\"\n            SELECT $TABLE_TEK_CHECK_FILE_MATCH.keyData, $TABLE_TEK_CHECK_FILE_MATCH.rollingStartNumber, $TABLE_TEK_CHECK_FILE_MATCH.rollingPeriod, $TABLE_TEK_CHECK_FILE_MATCH.transmissionRiskLevel, $TABLE_TEK_CHECK_FILE_MATCH.reportType, $TABLE_TEK_CHECK_FILE_MATCH.daysSinceOnsetOfSymptoms\n            FROM $TABLE_TEK_CHECK_FILE_TOKEN\n            JOIN $TABLE_TEK_CHECK_FILE_MATCH ON $TABLE_TEK_CHECK_FILE_MATCH.tcfid = $TABLE_TEK_CHECK_FILE_TOKEN.tcfid\n            WHERE \n                $TABLE_TEK_CHECK_FILE_TOKEN.tid = ?\n                \"\"\", arrayOf(tid.toString())).use { cursor ->\n            val list = arrayListOf<TemporaryExposureKey>()\n            while (cursor.moveToNext()) {\n                list.add(TemporaryExposureKey.TemporaryExposureKeyBuilder()\n                        .setKeyData(cursor.getBlob(0))\n                        .setRollingStartIntervalNumber(cursor.getLong(1).toInt())\n                        .setRollingPeriod(cursor.getLong(2).toInt())\n                        .setTransmissionRiskLevel(cursor.getLong(3).toInt())\n                        .setReportType(cursor.getLong(4).toInt())\n                        .setDaysSinceOnsetOfSymptoms(cursor.getLong(5).toInt())\n                        .build())\n            }\n            list\n        }\n    }\n\n    fun finishSingleMatching(tid: Long, database: SQLiteDatabase = writableDatabase): Int {\n        val workQueue = LinkedBlockingQueue<Runnable>()\n        val poolSize = Runtime.getRuntime().availableProcessors()\n        val executor = ThreadPoolExecutor(poolSize, poolSize, 1, TimeUnit.SECONDS, workQueue)\n        val futures = arrayListOf<Future<*>>()\n        val keys = listSingleDiagnosisKeysPendingSearch(tid, database)\n        val oldestRpi = oldestRpi\n        for (key in keys) {\n            if ((key.rollingStartIntervalNumber + key.rollingPeriod).toLong() * ROLLING_WINDOW_LENGTH_MS + ALLOWED_KEY_OFFSET_MS < oldestRpi) {\n                // Early ignore because key is older than since we started scanning.\n                applySingleDiagnosisKeySearchResult(key, false, database)\n            } else {\n                futures.add(executor.submit {\n                    applySingleDiagnosisKeySearchResult(key, findMeasuredExposures(key).isNotEmpty(), database)\n                })\n            }\n        }\n        for (future in futures) {\n            future.get()\n        }\n        executor.shutdown()\n        return keys.size\n    }\n\n    fun finishFileMatching(tid: Long, hash: ByteArray, endTimestamp: Long, keys: List<TemporaryExposureKey>, updates: List<TemporaryExposureKey>, database: SQLiteDatabase = writableDatabase) = database.run {\n        beginTransactionNonExclusive()\n        try {\n            insert(TABLE_TEK_CHECK_FILE, \"NULL\", ContentValues().apply {\n                put(\"hash\", ByteString.of(*hash).hex())\n                put(\"endTimestamp\", endTimestamp)\n                put(\"keys\", keys.size + updates.size)\n            })\n            val tcfid = getDiagnosisFileId(hash, this) ?: return\n            val workQueue = LinkedBlockingQueue<Runnable>()\n            val poolSize = Runtime.getRuntime().availableProcessors()\n            val executor = ThreadPoolExecutor(poolSize, poolSize, 1, TimeUnit.SECONDS, workQueue)\n            val futures = arrayListOf<Future<TemporaryExposureKey?>>()\n            val oldestRpi = oldestRpi\n            var ignored = 0\n            var processed = 0\n            var found = 0\n            var riskLogged = -1\n            var startLogged = -1\n            for (key in keys) {\n                if (key.transmissionRiskLevel > riskLogged || key.rollingStartIntervalNumber > startLogged) {\n                    riskLogged = key.transmissionRiskLevel\n                    startLogged = key.rollingStartIntervalNumber\n                    Log.d(TAG, \"First key with risk ${key.transmissionRiskLevel}: ${ByteString.of(*key.keyData).hex()} starts ${key.rollingStartIntervalNumber}\")\n                }\n                if ((key.rollingStartIntervalNumber + key.rollingPeriod).toLong() * ROLLING_WINDOW_LENGTH_MS + ALLOWED_KEY_OFFSET_MS < oldestRpi) {\n                    // Early ignore because key is older than since we started scanning.\n                    ignored++;\n                } else {\n                    futures.add(executor.submit(Callable {\n                        processed++\n                        if (findMeasuredExposures(key).isNotEmpty()) {\n                            key\n                        } else {\n                            null\n                        }\n                    }))\n                }\n            }\n            for (future in futures) {\n                future.get()?.let {\n                    applyDiagnosisFileKeySearchResult(tcfid, it, this)\n                    found++\n                }\n            }\n            Log.d(TAG, \"Processed $processed keys, found $found matches, ignored $ignored keys that are older than our scanning efforts ($oldestRpi)\")\n            executor.shutdown()\n            for (update in updates) {\n                val matched = compileStatement(\"SELECT COUNT(tcsid) FROM $TABLE_TEK_CHECK_FILE_MATCH WHERE keyData = ? AND rollingStartNumber = ? AND rollingPeriod = ?\").use {\n                    it.bindBlob(1, update.keyData)\n                    it.bindLong(2, update.rollingStartIntervalNumber.toLong())\n                    it.bindLong(3, update.rollingPeriod.toLong())\n                    it.simpleQueryForLong()\n                }\n                if (matched > 0) {\n                    applyDiagnosisFileKeySearchResult(tcfid, update, this)\n                }\n            }\n            insert(TABLE_TEK_CHECK_FILE_TOKEN, \"NULL\", ContentValues().apply {\n                put(\"tid\", tid)\n                put(\"tcfid\", tcfid)\n            })\n            setTransactionSuccessful()\n        } finally {\n            endTransaction()\n        }\n    }\n\n    private fun findAllSingleMeasuredExposures(tid: Long, database: SQLiteDatabase = readableDatabase): List<MeasuredExposure> {\n        return listMatchedSingleDiagnosisKeys(tid, database).flatMap { findMeasuredExposures(it, database) }\n    }\n\n    private fun findAllFileMeasuredExposures(tid: Long, database: SQLiteDatabase = readableDatabase): List<MeasuredExposure> {\n        return listMatchedFileDiagnosisKeys(tid, database).flatMap { findMeasuredExposures(it, database) }\n    }\n\n    fun findAllMeasuredExposures(tid: Long, database: SQLiteDatabase = readableDatabase) = findAllSingleMeasuredExposures(tid, database) + findAllFileMeasuredExposures(tid, database)\n\n    private fun findMeasuredExposures(key: TemporaryExposureKey, database: SQLiteDatabase = readableDatabase): List<MeasuredExposure> {\n        val allRpis = key.generateAllRpiIds()\n        val rpis = (0 until key.rollingPeriod).map { i ->\n            val pos = i * 16\n            allRpis.sliceArray(pos until (pos + 16))\n        }\n        val measures = findExposures(rpis, key.rollingStartIntervalNumber.toLong() * ROLLING_WINDOW_LENGTH_MS - ALLOWED_KEY_OFFSET_MS, (key.rollingStartIntervalNumber.toLong() + key.rollingPeriod) * ROLLING_WINDOW_LENGTH_MS + ALLOWED_KEY_OFFSET_MS, database)\n        return measures.filter {\n            val index = rpis.indexOfFirst { rpi -> rpi.contentEquals(it.rpi) }\n            val targetTimestamp = (key.rollingStartIntervalNumber + index).toLong() * ROLLING_WINDOW_LENGTH_MS\n            it.timestamp >= targetTimestamp - ALLOWED_KEY_OFFSET_MS && it.timestamp <= targetTimestamp + ROLLING_WINDOW_LENGTH_MS + ALLOWED_KEY_OFFSET_MS\n        }.mapNotNull {\n            val decrypted = key.cryptAem(it.rpi, it.aem)\n            val version = (decrypted[0] and 0xf0.toByte())\n            val txPower = if (decrypted.size >= 4 && version >= VERSION_1_0) decrypted[1].toInt() else averageDeviceInfo.txPowerCorrection.toInt()\n            val confidence = if (decrypted.size >= 4 && version >= VERSION_1_1) ((decrypted[0] and 0xc) / 4) else (averageDeviceInfo.confidence)\n            if (version > VERSION_1_1) {\n                Log.w(TAG, \"Unknown AEM version: 0x${version.toString(16)}\")\n            }\n            MeasuredExposure(it.timestamp, it.duration, it.rssi, txPower, confidence, key)\n        }\n    }\n\n    private fun findExposures(rpis: List<ByteArray>, minTime: Long, maxTime: Long, database: SQLiteDatabase = readableDatabase): List<PlainExposure> = database.run {\n        if (rpis.isEmpty()) return emptyList()\n        val qs = rpis.map { \"?\" }.joinToString(\",\")\n        queryWithFactory({ _, cursorDriver, editTable, query ->\n            query.bindLong(1, minTime)\n            query.bindLong(2, maxTime)\n            rpis.forEachIndexed { index, rpi ->\n                query.bindBlob(index + 3, rpi)\n            }\n            SQLiteCursor(cursorDriver, editTable, query)\n        }, false, TABLE_ADVERTISEMENTS, arrayOf(\"rpi\", \"aem\", \"timestamp\", \"duration\", \"rssi\"), \"timestamp > ? AND timestamp < ? AND rpi IN ($qs)\", null, null, null, null, null).use { cursor ->\n            val list = arrayListOf<PlainExposure>()\n            while (cursor.moveToNext()) {\n                list.add(PlainExposure(cursor.getBlob(0), cursor.getBlob(1), cursor.getLong(2), cursor.getLong(3), cursor.getInt(4)))\n            }\n            list\n        }\n    }\n\n    fun findExposure(rpi: ByteArray, minTime: Long, maxTime: Long): PlainExposure? = readableDatabase.run {\n        queryWithFactory({ _, cursorDriver, editTable, query ->\n            query.bindBlob(1, rpi)\n            query.bindLong(2, minTime)\n            query.bindLong(3, maxTime)\n            SQLiteCursor(cursorDriver, editTable, query)\n        }, false, TABLE_ADVERTISEMENTS, arrayOf(\"aem\", \"timestamp\", \"duration\", \"rssi\"), \"rpi = ? AND timestamp > ? AND timestamp < ?\", null, null, null, null, null).use { cursor ->\n            if (cursor.moveToNext()) {\n                PlainExposure(rpi, cursor.getBlob(0), cursor.getLong(1), cursor.getLong(2), cursor.getInt(3))\n            } else {\n                null\n            }\n        }\n    }\n\n    private fun findOwnKeyAt(intervalNumber: Int, database: SQLiteDatabase = readableDatabase): TemporaryExposureKey? = database.run {\n        val dayRollingStartNumber = getDayRollingStartNumber(intervalNumber)\n        query(TABLE_TEK, arrayOf(\"keyData\", \"rollingStartNumber\", \"rollingPeriod\"), \"rollingStartNumber >= ? AND (rollingStartNumber + rollingPeriod) < ?\", arrayOf(dayRollingStartNumber.toString(), intervalNumber.toString()), null, null, \"rollingStartNumber DESC\").use { cursor ->\n            if (cursor.moveToNext()) {\n                TemporaryExposureKey.TemporaryExposureKeyBuilder()\n                        .setKeyData(cursor.getBlob(0))\n                        .setRollingStartIntervalNumber(cursor.getLong(1).toInt())\n                        .setRollingPeriod(cursor.getLong(2).toInt())\n                        .build()\n            } else {\n                null\n            }\n        }\n    }\n\n    fun Parcelable.marshall(): ByteArray {\n        val parcel = Parcel.obtain()\n        writeToParcel(parcel, 0)\n        val bytes = parcel.marshall()\n        parcel.recycle()\n        return bytes\n    }\n\n    fun <T> Parcelable.Creator<T>.unmarshall(data: ByteArray): T {\n        val parcel = Parcel.obtain()\n        parcel.unmarshall(data, 0, data.size)\n        parcel.setDataPosition(0)\n        val res = createFromParcel(parcel)\n        parcel.recycle()\n        return res\n    }\n\n    fun storeConfiguration(packageName: String, token: String, configuration: ExposureConfiguration, database: SQLiteDatabase = writableDatabase) = database.run {\n        val update = update(TABLE_TOKENS, ContentValues().apply { put(\"configuration\", configuration.marshall()) }, \"package = ? AND token = ?\", arrayOf(packageName, token))\n        if (update <= 0) {\n            insert(TABLE_TOKENS, \"NULL\", ContentValues().apply {\n                put(\"package\", packageName)\n                put(\"token\", token)\n                put(\"timestamp\", System.currentTimeMillis())\n                put(\"configuration\", configuration.marshall())\n            })\n        }\n        getTokenId(packageName, token, database)\n    }\n\n    fun storeConfiguration(packageName: String, token: String, mapping: DiagnosisKeysDataMapping, database: SQLiteDatabase = writableDatabase) = database.run {\n        val update = update(TABLE_TOKENS, ContentValues().apply { put(\"diagnosisKeysDataMap\", mapping.marshall()) }, \"package = ? AND token = ?\", arrayOf(packageName, token))\n        if (update <= 0) {\n            insert(TABLE_TOKENS, \"NULL\", ContentValues().apply {\n                put(\"package\", packageName)\n                put(\"token\", token)\n                put(\"timestamp\", System.currentTimeMillis())\n                put(\"diagnosisKeysDataMap\", mapping.marshall())\n            })\n        }\n        getTokenId(packageName, token, database)\n    }\n\n    fun loadConfiguration(packageName: String, token: String, database: SQLiteDatabase = readableDatabase): Triple<Long, ExposureConfiguration?, DiagnosisKeysDataMapping?>? = database.run {\n        query(TABLE_TOKENS, arrayOf(\"tid\", \"configuration\", \"diagnosisKeysDataMap\"), \"package = ? AND token = ?\", arrayOf(packageName, token), null, null, null, null).use { cursor ->\n            if (cursor.moveToNext()) {\n                val configuration = try {ExposureConfiguration.CREATOR.unmarshall(cursor.getBlob(1)) } catch (e: Exception) { null }\n                val diagnosisKeysDataMapping = try { DiagnosisKeysDataMapping.CREATOR.unmarshall(cursor.getBlob(2)) }  catch (e: Exception) { null }\n                Triple(cursor.getLong(0), configuration, diagnosisKeysDataMapping)\n            } else {\n                null\n            }\n        }\n    }\n\n    fun exportKeys(database: SQLiteDatabase = writableDatabase): List<TemporaryExposureKey> = database.run {\n        database.beginTransactionNonExclusive()\n        try {\n            val intervalNumber = currentIntervalNumber\n            val key = findOwnKeyAt(intervalNumber, database)\n            if (key != null && intervalNumber != key.rollingStartIntervalNumber) {\n                // Rotate key\n                update(TABLE_TEK, ContentValues().apply {\n                    put(\"rollingPeriod\", intervalNumber - key.rollingStartIntervalNumber)\n                }, \"rollingStartNumber = ?\", arrayOf(key.rollingStartIntervalNumber.toString()))\n                storeOwnKey(generateCurrentDayTemporaryExposureKey(), database)\n            }\n            database.setTransactionSuccessful()\n            val startRollingNumber = (getDayRollingStartNumber(intervalNumber) - 14 * ROLLING_PERIOD)\n            query(TABLE_TEK, arrayOf(\"keyData\", \"rollingStartNumber\", \"rollingPeriod\"), \"rollingStartNumber >= ? AND (rollingStartNumber + rollingPeriod) <= ?\", arrayOf(startRollingNumber.toString(), intervalNumber.toString()), null, null, null).use { cursor ->\n                val list = arrayListOf<TemporaryExposureKey>()\n                while (cursor.moveToNext()) {\n                    list.add(TemporaryExposureKey.TemporaryExposureKeyBuilder()\n                            .setKeyData(cursor.getBlob(0))\n                            .setRollingStartIntervalNumber(cursor.getLong(1).toInt())\n                            .setRollingPeriod(cursor.getLong(2).toInt())\n                            .build())\n                }\n                list\n            }\n        } finally {\n            database.endTransaction()\n        }\n    }\n\n    val rpiHourHistogram: Set<ExposureScanSummary>\n        get() = readableDatabase.run {\n            rawQuery(\"SELECT round(timestamp/(60*60*1000))*60*60*1000, COUNT(*), COUNT(*) FROM $TABLE_ADVERTISEMENTS WHERE timestamp > ? GROUP BY round(timestamp/(60*60*1000)) ORDER BY timestamp ASC;\", arrayOf((System.currentTimeMillis() - (14 * 24 * 60 * 60 * 1000L)).toString())).use { cursor ->\n                val set = hashSetOf<ExposureScanSummary>()\n                while (cursor.moveToNext()) {\n                    set.add(ExposureScanSummary(cursor.getLong(0), cursor.getInt(1), cursor.getInt(2)))\n                }\n                set\n            }\n        }\n\n    val hourRpiCount: Long\n        get() = readableDatabase.run {\n            rawQuery(\"SELECT COUNT(*) FROM $TABLE_ADVERTISEMENTS WHERE timestamp > ?;\", arrayOf((Date().time - (60 * 60 * 1000)).toString())).use { cursor ->\n                if (cursor.moveToNext()) {\n                    cursor.getLong(0)\n                } else {\n                    0L\n                }\n            }\n        }\n\n    val oldestRpi: Long\n        get() = readableDatabase.run {\n            query(TABLE_ADVERTISEMENTS, arrayOf(\"MIN(timestamp)\"), null, null, null, null, null).use { cursor ->\n                if (cursor.moveToNext()) {\n                    cursor.getLong(0).let { if (it == 0L) System.currentTimeMillis() else it }\n                } else {\n                    System.currentTimeMillis()\n                }\n            }\n        }\n\n    val appList: List<String>\n        get() = readableDatabase.run {\n            query(true, TABLE_APP_LOG, arrayOf(\"package\"), null, null, null, null, \"timestamp DESC\", null).use { cursor ->\n                val list = arrayListOf<String>()\n                while (cursor.moveToNext()) {\n                    list.add(cursor.getString(0))\n                }\n                list\n            }\n        }\n\n    val isEmpty: Boolean\n        get() = readableDatabase.run {\n            Log.d(TAG, \"${DatabaseUtils.queryNumEntries(this, TABLE_ADVERTISEMENTS)}, ${DatabaseUtils.queryNumEntries(this, TABLE_APP_LOG)}, ${DatabaseUtils.queryNumEntries(this, TABLE_TEK)}, ${DatabaseUtils.queryNumEntries(this, TABLE_TOKENS)}\")\n            DatabaseUtils.queryNumEntries(this, TABLE_ADVERTISEMENTS) == 0L &&\n                    DatabaseUtils.queryNumEntries(this, TABLE_APP_LOG) == 0L &&\n                    DatabaseUtils.queryNumEntries(this, TABLE_TEK) == 0L &&\n                    DatabaseUtils.queryNumEntries(this, TABLE_TOKENS) == 0L\n        }\n\n    fun countMethodCalls(packageName: String, method: String): Int = readableDatabase.run {\n        query(TABLE_APP_LOG, arrayOf(\"COUNT(*)\"), \"package = ? AND method = ? AND timestamp > ?\", arrayOf(packageName, method, (System.currentTimeMillis() - TimeUnit.DAYS.toMillis(KEEP_DAYS.toLong())).toString()), null, null, null, null).use { cursor ->\n            if (cursor.moveToNext()) {\n                cursor.getInt(0)\n            } else {\n                0\n            }\n        }\n    }\n\n    fun lastMethodCall(packageName: String, method: String): Long? = readableDatabase.run {\n        query(TABLE_APP_LOG, arrayOf(\"MAX(timestamp)\"), \"package = ? AND method = ?\", arrayOf(packageName, method), null, null, null, null).use { cursor ->\n            if (cursor.moveToNext()) {\n                cursor.getLong(0)\n            } else {\n                null\n            }\n        }\n    }\n\n    fun lastMethodCallArgs(packageName: String, method: String): String? = readableDatabase.run {\n        query(TABLE_APP_LOG, arrayOf(\"args\"), \"package = ? AND method = ?\", arrayOf(packageName, method), null, null, \"timestamp DESC\", \"1\").use { cursor ->\n            if (cursor.moveToNext()) {\n                cursor.getString(0)\n            } else {\n                null\n            }\n        }\n    }\n\n    fun countDiagnosisKeysInvolved(tid: Long): Long = readableDatabase.run {\n        val fromFile = rawQuery(\"SELECT SUM($TABLE_TEK_CHECK_FILE.keys) AS keys FROM $TABLE_TEK_CHECK_FILE_TOKEN JOIN $TABLE_TEK_CHECK_FILE ON $TABLE_TEK_CHECK_FILE_TOKEN.tcfid = $TABLE_TEK_CHECK_FILE.tcfid WHERE $TABLE_TEK_CHECK_FILE_TOKEN.tid = $tid;\", null).use { cursor ->\n            if (cursor.moveToNext()) {\n                cursor.getLong(0)\n            } else {\n                0\n            }\n        }\n        val single = rawQuery(\"SELECT COUNT(*) as keys FROM $TABLE_TEK_CHECK_SINGLE_TOKEN WHERE $TABLE_TEK_CHECK_SINGLE_TOKEN.tid = $tid;\", null).use { cursor ->\n            if (cursor.moveToNext()) {\n                cursor.getLong(0)\n            } else {\n                0\n            }\n        }\n        return fromFile + single\n    }\n\n    fun methodUsageHistogram(packageName: String): List<Pair<String, Int>> = readableDatabase.run {\n        val list = arrayListOf<Pair<String, Int>>()\n        rawQuery(\"SELECT method, COUNT(*) AS count FROM $TABLE_APP_LOG WHERE package = ? GROUP BY method;\", arrayOf(packageName)).use { cursor ->\n            while (cursor.moveToNext()) {\n                list.add(cursor.getString(0) to cursor.getInt(1))\n            }\n        }\n        list.sortedByDescending { it.second }\n    }\n\n    private fun ensureTemporaryExposureKey(): TemporaryExposureKey = writableDatabase.let { database ->\n        database.beginTransactionNonExclusive()\n        try {\n            var key = findOwnKeyAt(currentIntervalNumber, database)\n            if (key == null) {\n                key = generateCurrentDayTemporaryExposureKey()\n                storeOwnKey(key, database)\n            }\n            database.setTransactionSuccessful()\n            key\n        } finally {\n            database.endTransaction()\n        }\n    }\n\n    val currentRpiId: UUID?\n        get() {\n            val key = findOwnKeyAt(currentIntervalNumber) ?: return null\n            val buffer = ByteBuffer.wrap(key.generateRpiId(currentIntervalNumber))\n            return UUID(buffer.long, buffer.long)\n        }\n\n    fun generateCurrentPayload(metadata: ByteArray) = ensureTemporaryExposureKey().generatePayload(currentIntervalNumber, metadata)\n\n    override fun getWritableDatabase(): SQLiteDatabase {\n        requirePrimary(this)\n        return super.getWritableDatabase()\n    }\n\n    @Synchronized\n    fun ref(): ExposureDatabase {\n        refCount++\n        return this\n    }\n\n    @Synchronized\n    fun unref() {\n        refCount--\n        if (refCount == 0) {\n            clearInstance(this)\n            close()\n        } else if (refCount < 0) {\n            throw IllegalStateException(\"ref/unref mismatch\")\n        }\n    }\n\n    companion object {\n        private const val DB_NAME = \"exposure.db\"\n        private const val DB_VERSION = 12\n        private const val DB_SIZE_TOO_LARGE = 256L * 1024 * 1024\n        private const val MAX_DELETE_TIME = 5000L\n        private const val TABLE_ADVERTISEMENTS = \"advertisements\"\n        private const val TABLE_APP = \"app\"\n        private const val TABLE_APP_LOG = \"app_log\"\n        private const val TABLE_TEK = \"tek\"\n        private const val TABLE_APP_PERMS = \"app_perms\"\n        private const val TABLE_TOKENS = \"tokens\"\n        private const val TABLE_TEK_CHECK_SINGLE = \"tek_check_single\"\n        private const val TABLE_TEK_CHECK_SINGLE_TOKEN = \"tek_check_single_token\"\n        private const val TABLE_TEK_CHECK_FILE = \"tek_check_file\"\n        private const val TABLE_TEK_CHECK_FILE_TOKEN = \"tek_check_file_token\"\n        private const val TABLE_TEK_CHECK_FILE_MATCH = \"tek_check_file_match\"\n\n        @Deprecated(message = \"No longer supported\")\n        private const val TABLE_TEK_CHECK = \"tek_check\"\n\n        @Deprecated(message = \"No longer supported\")\n        private const val TABLE_DIAGNOSIS = \"diagnosis\"\n\n        @Deprecated(message = \"No longer supported\")\n        private const val TABLE_CONFIGURATIONS = \"configurations\"\n\n        private var deferredInstance: Deferred<ExposureDatabase>? = null\n        private var deferredRefCount: Int = 0\n        private var instance: ExposureDatabase? = null\n\n        @Synchronized\n        private fun requirePrimary(database: ExposureDatabase) {\n            if (database != instance) {\n                throw IllegalStateException(\"Operation requires ${database.hashCode()} to be a primary database instance, but ${instance?.hashCode()} is primary\", database.createdAt)\n            }\n        }\n\n        @Synchronized\n        private fun clearInstance(database: ExposureDatabase, errorOnNull: Boolean = true) {\n            if (database == instance) {\n                if (deferredRefCount == 0) {\n                    deferredInstance = null\n                    instance = null\n                }\n            } else if (errorOnNull || instance != null) {\n                throw IllegalStateException(\"Tried to remove database instance ${database.hashCode()}, but ${instance?.hashCode()} is primary\", database.createdAt)\n            }\n        }\n\n        @Synchronized\n        private fun getDeferredInstance(): Pair<Deferred<ExposureDatabase>, Boolean> {\n            val deferredInstance = deferredInstance\n            deferredRefCount++\n            return when {\n                deferredInstance != null -> deferredInstance to false\n                instance != null -> throw IllegalStateException(\"No deferred database instance, but instance ${instance?.hashCode()} is primary\", instance?.createdAt)\n                else -> {\n                    val newInstance = CompletableDeferred<ExposureDatabase>()\n                    this.deferredInstance = newInstance\n                    newInstance to true\n                }\n            }\n        }\n\n        @Synchronized\n        private fun unrefDeferredInstance() {\n            deferredRefCount--;\n        }\n\n        @Synchronized\n        private fun completeInstance(database: ExposureDatabase) {\n            if (instance != null) {\n                throw IllegalStateException(\"Tried to make ${database.hashCode()} the primary, but ${instance?.hashCode()} is currently primary\", instance?.createdAt)\n            }\n            instance = database\n        }\n\n        private fun prepareDatabaseMigration(context: Context): Pair<File, File> {\n            val dbFile = context.getDatabasePath(DB_NAME)\n            val dbWalFile = context.getDatabasePath(\"$DB_NAME-wal\")\n            val dbMigrateFile = context.getDatabasePath(\"$DB_NAME-migrate\")\n            val dbMigrateWalFile = context.getDatabasePath(\"$DB_NAME-migrate-wal\")\n            if (dbFile.length() + dbWalFile.length() > DB_SIZE_TOO_LARGE) {\n                Log.d(TAG, \"Database file is larger than $DB_SIZE_TOO_LARGE, force clean up\")\n                if (dbFile.exists()) dbFile.renameTo(dbMigrateFile)\n                if (dbWalFile.exists()) dbWalFile.renameTo(dbMigrateWalFile)\n            }\n            return dbMigrateFile to dbMigrateWalFile\n        }\n\n        private fun finishDatabaseMigration(database: ExposureDatabase, dbMigrateFile: File, dbMigrateWalFile: File) {\n            if (dbMigrateFile.exists()) {\n                val writableDatabase = database.writableDatabase\n                writableDatabase.execSQL(\"ATTACH DATABASE '${dbMigrateFile.absolutePath}' AS old;\")\n                writableDatabase.beginTransaction()\n                try {\n                    Log.d(TAG, \"Migrating advertisements and TEKs from old database file\")\n                    writableDatabase.execSQL(\"INSERT INTO $TABLE_ADVERTISEMENTS SELECT * FROM old.$TABLE_ADVERTISEMENTS;\")\n                    writableDatabase.execSQL(\"INSERT INTO $TABLE_TEK SELECT * FROM old.$TABLE_TEK;\")\n                    Log.d(TAG, \"Migration finished successfully\")\n                    writableDatabase.setTransactionSuccessful()\n                } finally {\n                    writableDatabase.endTransaction()\n                    writableDatabase.execSQL(\"DETACH DATABASE old;\")\n                }\n            }\n            dbMigrateFile.delete()\n            dbMigrateWalFile.delete()\n        }\n\n        suspend fun ref(context: Context): ExposureDatabase {\n            val (instance, new) = getDeferredInstance()\n            try {\n                if (new) {\n                    val newInstance = instance as CompletableDeferred\n                    try {\n                        val (dbMigrateFile, dbMigrateWalFile) = prepareDatabaseMigration(context)\n                        val database = ExposureDatabase(context.applicationContext)\n                        try {\n                            completeInstance(database)\n                            finishDatabaseMigration(database, dbMigrateFile, dbMigrateWalFile)\n                            newInstance.complete(database)\n                            return database\n                        } catch (e: Exception) {\n                            clearInstance(database, false)\n                            database.close()\n                            throw e\n                        }\n                    } catch (e: Exception) {\n                        newInstance.completeExceptionally(e)\n                        throw e;\n                    }\n                } else {\n                    return instance.await().ref()\n                }\n            } finally {\n                unrefDeferredInstance()\n            }\n        }\n\n        fun export(context: Context) {\n            // FileProvider cannot directly access /databases, so we have to copy the database first\n            // In addition, we filter out only the Advertisements table to not export sensitive TEKs\n\n            // Create a new database which will store only the Advertisements table\n            val exportDir = File(context.getCacheDir(), \"exposureDatabase\")\n            exportDir.mkdir()\n            val exportFile = File(exportDir, \"exposure.db\")\n            if (exportFile.delete()) {\n                Log.d(\"EN-DB-Exporter\", \"Deleted old export database.\")\n            }\n            val db = SQLiteDatabase.openOrCreateDatabase(exportFile, null)\n\n            // Attach the full database to the new empty db\n            val databaseFile = context.getDatabasePath(DB_NAME);\n            db.execSQL(\"ATTACH '$databaseFile' AS fulldb;\")\n\n            // copy TABLE_ADVERTISEMENTS over\n            db.execSQL(\"CREATE TABLE $TABLE_ADVERTISEMENTS AS SELECT * FROM fulldb.$TABLE_ADVERTISEMENTS;\")\n\n            // Detach original db, close new db\n            db.execSQL(\"DETACH DATABASE fulldb;\")\n            db.close()\n\n            // Use the FileProvider to get a content URI for the new DB\n            val fileUri: Uri? = try {\n                FileProvider.getUriForFile(context,\"${context.packageName}.microg.exposure.export\", exportFile)\n            } catch (e: IllegalArgumentException) {\n                Log.e(\"EN-DB-Exporter\", \"The database file can't be shared: $exportFile $e\")\n                null\n            }\n\n            // Open a sharesheet\n            if (fileUri != null) {\n                // Grant temporary read permission to the content URI\n                val sendIntent: Intent = Intent().apply {\n                    action = Intent.ACTION_SEND\n                    putExtra(Intent.EXTRA_STREAM, fileUri)\n                    addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)\n                    type = \"application/vnd.microg.exposure+sqlite3\"\n                }\n\n                val shareIntent = Intent.createChooser(sendIntent, null)\n                context.startActivity(shareIntent)\n            }\n        }\n\n        @Deprecated(message = \"Sync database access is slow\", replaceWith = ReplaceWith(\"with(context, call)\"))\n        fun <T> withSync(context: Context, call: (ExposureDatabase) -> T): T {\n            val it = runBlocking { ref(context) }\n            try {\n                return call(it)\n            } finally {\n                it.unref()\n            }\n        }\n\n        suspend fun <T> with(context: Context, call: suspend (ExposureDatabase) -> T): T = withContext(Dispatchers.IO) {\n            val it = ref(context)\n            try {\n                call(it)\n            } finally {\n                it.unref()\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-nearby/core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ExposureFileProvider.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.nearby.exposurenotification\n\nimport androidx.core.content.FileProvider\n\nclass ExposureFileProvider : FileProvider()\n"
  },
  {
    "path": "play-services-nearby/core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ExposureNotificationService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.nearby.exposurenotification\n\nimport android.content.pm.PackageManager\nimport android.os.Build.VERSION.SDK_INT\nimport android.util.Log\nimport com.google.android.gms.common.Feature\nimport com.google.android.gms.common.internal.ConnectionInfo\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport com.google.android.gms.nearby.exposurenotification.ExposureNotificationStatusCodes.*\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.common.PackageUtils\n\nclass ExposureNotificationService : BaseService(TAG, GmsService.NEARBY_EXPOSURE_NOTIFICATION) {\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        PackageUtils.getAndCheckCallingPackage(this, request.packageName)\n\n        fun checkPermission(permission: String): String? {\n            if (checkCallingPermission(permission) != PackageManager.PERMISSION_GRANTED) {\n                callback.onPostInitComplete(FAILED_UNAUTHORIZED, null, null)\n                return null\n            }\n            return permission\n        }\n\n        if (request.packageName != packageName) {\n            checkPermission(\"android.permission.BLUETOOTH\") ?: return\n        }\n\n        if (SDK_INT < 21) {\n            callback.onPostInitComplete(FAILED_NOT_SUPPORTED, null, null)\n            return\n        }\n\n        Log.d(TAG, \"handleServiceRequest: \" + request.packageName)\n        callback.onPostInitCompleteWithConnectionInfo(SUCCESS, ExposureNotificationServiceImpl(this, lifecycle, request.packageName), ConnectionInfo().apply {\n            // Note: this is just a list of all possible features as of 1.7.1-eap\n            features = arrayOf(\n                    Feature(\"nearby_exposure_notification\", 3),\n                    Feature(\"nearby_exposure_notification_1p\", 1),\n                    Feature(\"nearby_exposure_notification_get_version\", 1),\n                    Feature(\"nearby_exposure_notification_get_calibration_confidence\", 1),\n                    Feature(\"nearby_exposure_notification_get_day_summaries\", 1),\n                    Feature(\"nearby_exposure_notification_get_status\", 1),\n                    Feature(\"nearby_exposure_notification_diagnosis_keys_data_mapping\", 1),\n                    Feature(\"nearby_exposure_notification_diagnosis_key_file_supplier\", 1),\n                    Feature(\"nearby_exposure_notification_package_configuration\", 1),\n                    Feature(\"nearby_exposure_notification_preauthorize_key_release\", 1)\n            )\n        })\n    }\n}\n"
  },
  {
    "path": "play-services-nearby/core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ExposureNotificationServiceImpl.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.nearby.exposurenotification\n\nimport android.annotation.TargetApi\nimport android.app.Activity\nimport android.app.PendingIntent\nimport android.bluetooth.BluetoothAdapter\nimport android.content.ComponentName\nimport android.content.Context\nimport android.content.Intent\nimport android.location.LocationManager\nimport android.os.*\nimport android.util.Base64\nimport android.util.Log\nimport androidx.core.app.PendingIntentCompat\nimport androidx.core.location.LocationManagerCompat\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.LifecycleCoroutineScope\nimport androidx.lifecycle.LifecycleOwner\nimport androidx.lifecycle.lifecycleScope\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.nearby.exposurenotification.*\nimport com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient.*\nimport com.google.android.gms.nearby.exposurenotification.ExposureNotificationStatusCodes.*\nimport com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey.DAYS_SINCE_ONSET_OF_SYMPTOMS_UNKNOWN\nimport com.google.android.gms.nearby.exposurenotification.internal.*\nimport kotlinx.coroutines.CoroutineScope\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.Job\nimport kotlinx.coroutines.withContext\nimport org.json.JSONArray\nimport org.json.JSONObject\nimport org.microg.gms.common.Constants\nimport org.microg.gms.common.PackageUtils\nimport org.microg.gms.nearby.exposurenotification.proto.TEKSignatureList\nimport org.microg.gms.nearby.exposurenotification.proto.TemporaryExposureKeyExport\nimport org.microg.gms.nearby.exposurenotification.proto.TemporaryExposureKeyProto\nimport org.microg.gms.utils.warnOnTransactionIssues\nimport java.io.File\nimport java.io.InputStream\nimport java.security.KeyFactory\nimport java.security.MessageDigest\nimport java.security.Signature\nimport java.security.spec.X509EncodedKeySpec\nimport java.util.zip.ZipEntry\nimport java.util.zip.ZipFile\nimport kotlin.math.max\nimport kotlin.math.roundToInt\nimport kotlin.random.Random\n\n@TargetApi(21)\nclass ExposureNotificationServiceImpl(private val context: Context, override val lifecycle: Lifecycle, private val packageName: String) : INearbyExposureNotificationService.Stub(), LifecycleOwner {\n\n    // Table of back-end public keys, used to verify the signature of the diagnosed TEKs.\n    // The table is indexed by package names.\n    private val backendPubKeyForPackage = mapOf<String, String>(\n            \"ch.admin.bag.dp3t.dev\" to\n                    \"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEsFcEnOPY4AOAKkpv9HSdW2BrhUCWwL15Hpqu5zHaWy1Wno2KR8G6dYJ8QO0uZu1M6j8z6NGXFVZcpw7tYeXAqQ==\",\n            \"ch.admin.bag.dp3t.test\" to\n                    \"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEsFcEnOPY4AOAKkpv9HSdW2BrhUCWwL15Hpqu5zHaWy1Wno2KR8G6dYJ8QO0uZu1M6j8z6NGXFVZcpw7tYeXAqQ==\",\n            \"ch.admin.bag.dp3t.abnahme\" to\n                    \"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEsFcEnOPY4AOAKkpv9HSdW2BrhUCWwL15Hpqu5zHaWy1Wno2KR8G6dYJ8QO0uZu1M6j8z6NGXFVZcpw7tYeXAqQ==\",\n            \"ch.admin.bag.dp3t\" to\n                    \"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEK2k9nZ8guo7JP2ELPQXnUkqDyjjJmYmpt9Zy0HPsiGXCdI3SFmLr204KNzkuITppNV5P7+bXRxiiY04NMrEITg==\",\n            // CWA, see https://github.com/corona-warn-app/cwa-documentation/issues/740#issuecomment-963223074\n            \"de.rki.coronawarnapp\" to\n                    \"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEc7DEstcUIRcyk35OYDJ95/hTg3UVhsaDXKT0zK7NhHPXoyzipEnOp3GyNXDVpaPi3cAfQmxeuFMZAIX2+6A5Xg==\",\n            // CCTG uses CWA infrastucture\n            \"de.corona.tracing\" to\n                    \"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEc7DEstcUIRcyk35OYDJ95/hTg3UVhsaDXKT0zK7NhHPXoyzipEnOp3GyNXDVpaPi3cAfQmxeuFMZAIX2+6A5Xg==\",\n            // CCTG-Test builds don't have access any staging infrastructure, so again CWA key\n            \"de.corona.tracing.test\" to\n                    \"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEc7DEstcUIRcyk35OYDJ95/hTg3UVhsaDXKT0zK7NhHPXoyzipEnOp3GyNXDVpaPi3cAfQmxeuFMZAIX2+6A5Xg==\",\n        )\n\n    // Back-end public key for this package\n    private val backendPublicKey = backendPubKeyForPackage[packageName]?.let {\n        try {\n            KeyFactory.getInstance(\"EC\").generatePublic(X509EncodedKeySpec(Base64.decode(it, Base64.DEFAULT)))\n        } catch (e: Exception) {\n            Log.w(TAG, \"Failed to retrieve back-end public key for ${packageName}: \" + e.message)\n            null\n        }\n    }\n\n    // Table of supported signature algorithms for the diagnosed TEKs.\n    // The table is indexed by ASN.1 OIDs as specified in https://tools.ietf.org/html/rfc5758#section-3.2\n    private val sigAlgoForOid = mapOf<String, Function0<Signature>>(\n            \"1.2.840.10045.4.3.2\" to { Signature.getInstance(\"SHA256withECDSA\") },\n            \"1.2.840.10045.4.3.4\" to { Signature.getInstance(\"SHA512withECDSA\") },\n    )\n\n    private fun LifecycleCoroutineScope.launchSafely(block: suspend CoroutineScope.() -> Unit): Job = launchWhenStarted { try { block() } catch (e: Exception) { Log.w(TAG, \"Error in coroutine\", e) } }\n\n    private fun pendingConfirm(permission: String): PendingIntent {\n        val intent = Intent(ACTION_CONFIRM)\n        intent.`package` = context.packageName\n        intent.putExtra(KEY_CONFIRM_PACKAGE, packageName)\n        intent.putExtra(KEY_CONFIRM_ACTION, permission)\n        intent.putExtra(KEY_CONFIRM_RECEIVER, object : ResultReceiver(null) {\n            override fun onReceiveResult(resultCode: Int, resultData: Bundle?) {\n                if (resultCode == Activity.RESULT_OK) {\n                    tempGrantedPermissions.add(packageName to permission)\n                }\n            }\n        })\n        try {\n            intent.component = ComponentName(context, context.packageManager.resolveActivity(intent, 0)?.activityInfo?.name!!)\n        } catch (e: Exception) {\n            Log.w(TAG, e)\n        }\n        Log.d(TAG, \"Pending: $intent\")\n        val pi = PendingIntentCompat.getActivity(context, permission.hashCode(), intent, PendingIntent.FLAG_ONE_SHOT, false)!!\n        Log.d(TAG, \"Pending: $pi\")\n        return pi\n    }\n\n    private fun hasConfirmActivity(): Boolean {\n        val intent = Intent(ACTION_CONFIRM)\n        intent.`package` = context.packageName\n        return try {\n            context.packageManager.resolveActivity(intent, 0) != null\n        } catch (e: Exception) {\n            false\n        }\n    }\n\n    private suspend fun confirmPermission(permission: String, force: Boolean = false): Status {\n        return ExposureDatabase.with(context) { database ->\n            when {\n                tempGrantedPermissions.contains(packageName to permission) -> {\n                    database.grantPermission(packageName, PackageUtils.firstSignatureDigest(context, packageName)!!, permission)\n                    tempGrantedPermissions.remove(packageName to permission)\n                    Status.SUCCESS\n                }\n                !force && database.hasPermission(packageName, PackageUtils.firstSignatureDigest(context, packageName)!!, permission) -> {\n                    Status.SUCCESS\n                }\n                !hasConfirmActivity() -> {\n                    Status.SUCCESS\n                }\n                else -> {\n                    Status(RESOLUTION_REQUIRED, \"Permission EN#$permission required.\", pendingConfirm(permission))\n                }\n            }\n        }\n    }\n\n    override fun getVersion(params: GetVersionParams) {\n        params.callback.onResult(Status.SUCCESS, VERSION_FULL)\n    }\n\n    override fun getCalibrationConfidence(params: GetCalibrationConfidenceParams) {\n        params.callback.onResult(Status.SUCCESS, currentDeviceInfo.confidence)\n    }\n\n    override fun start(params: StartParams) {\n        lifecycleScope.launchSafely {\n            val isAuthorized = ExposureDatabase.with(context) { it.isAppAuthorized(packageName) }\n            val adapter = BluetoothAdapter.getDefaultAdapter()\n            val status = if (isAuthorized && ExposurePreferences(context).enabled) {\n                Status.SUCCESS\n            } else if (adapter == null) {\n                Status(FAILED_NOT_SUPPORTED, \"No Bluetooth Adapter available.\")\n            } else {\n                val status = confirmPermission(CONFIRM_ACTION_START, !adapter.isEnabled)\n                if (status.isSuccess) {\n                    val context = context\n                    adapter.enableAsync(context)\n                    ExposurePreferences(context).enabled = true\n                    ExposureDatabase.with(context) { database ->\n                        database.authorizeApp(packageName)\n                        database.noteAppAction(packageName, \"start\")\n                    }\n                }\n                status\n            }\n            try {\n                params.callback.onResult(status)\n            } catch (e: Exception) {\n                Log.w(TAG, \"Callback failed\", e)\n            }\n        }\n    }\n\n    override fun stop(params: StopParams) {\n        lifecycleScope.launchSafely {\n            val isAuthorized = ExposureDatabase.with(context) { database ->\n                database.isAppAuthorized(packageName).also {\n                    if (it) database.noteAppAction(packageName, \"stop\")\n                }\n            }\n            if (isAuthorized) {\n                ExposurePreferences(context).enabled = false\n            }\n            try {\n                params.callback.onResult(Status.SUCCESS)\n            } catch (e: Exception) {\n                Log.w(TAG, \"Callback failed\", e)\n            }\n        }\n    }\n\n    override fun isEnabled(params: IsEnabledParams) {\n        lifecycleScope.launchSafely {\n            val isAuthorized = ExposureDatabase.with(context) { database ->\n                database.isAppAuthorized(packageName)\n            }\n            try {\n                params.callback.onResult(Status.SUCCESS, isAuthorized && ExposurePreferences(context).enabled)\n            } catch (e: Exception) {\n                Log.w(TAG, \"Callback failed\", e)\n            }\n        }\n    }\n\n    override fun getTemporaryExposureKeyHistory(params: GetTemporaryExposureKeyHistoryParams) {\n        lifecycleScope.launchSafely {\n            val status = confirmPermission(CONFIRM_ACTION_KEYS)\n            val response = when {\n                status.isSuccess -> ExposureDatabase.with(context) { database ->\n                    database.authorizeApp(packageName)\n                    database.exportKeys()\n                }\n                else -> emptyList()\n            }\n\n            ExposureDatabase.with(context) { database ->\n                database.noteAppAction(packageName, \"getTemporaryExposureKeyHistory\", JSONObject().apply {\n                    put(\"result\", status.statusCode)\n                    put(\"response_keys_size\", response.size)\n                }.toString())\n            }\n            try {\n                params.callback.onResult(status, response)\n            } catch (e: Exception) {\n                Log.w(TAG, \"Callback failed\", e)\n            }\n        }\n    }\n\n    private fun TemporaryExposureKeyProto.toKey(): TemporaryExposureKey = TemporaryExposureKey.TemporaryExposureKeyBuilder()\n            .setKeyData(key_data?.toByteArray() ?: throw IllegalArgumentException(\"key data missing\"))\n            .setRollingStartIntervalNumber(rolling_start_interval_number\n                    ?: throw IllegalArgumentException(\"rolling start interval number missing\"))\n            .setRollingPeriod(rolling_period ?: throw IllegalArgumentException(\"rolling period missing\"))\n            .setTransmissionRiskLevel(transmission_risk_level ?: 0)\n            .build()\n\n    private fun InputStream.copyToFile(outputFile: File) {\n        outputFile.outputStream().use { output ->\n            copyTo(output)\n            output.flush()\n        }\n    }\n\n    private fun MessageDigest.digest(file: File): ByteArray = file.inputStream().use { input ->\n        val buf = ByteArray(4096)\n        var bytes = input.read(buf)\n        while (bytes != -1) {\n            update(buf, 0, bytes)\n            bytes = input.read(buf)\n        }\n        digest()\n    }\n\n    private fun ExposureConfiguration?.orDefault() = this\n            ?: ExposureConfiguration.ExposureConfigurationBuilder().build()\n\n    private suspend fun buildExposureSummary(token: String): ExposureSummary = ExposureDatabase.with(context) { database ->\n        if (!database.isAppAuthorized(packageName)) {\n            // Not providing summary if app not authorized\n            Log.d(TAG, \"$packageName not yet authorized\")\n            return@with ExposureSummary.ExposureSummaryBuilder().build()\n        }\n        val pair = database.loadConfiguration(packageName, token)\n        val (configuration, exposures) = if (pair != null) {\n            pair.second.orDefault() to database.findAllMeasuredExposures(pair.first).merge()\n        } else {\n            ExposureConfiguration.ExposureConfigurationBuilder().build() to emptyList()\n        }\n\n        ExposureSummary.ExposureSummaryBuilder()\n                .setDaysSinceLastExposure(exposures.map { it.daysSinceExposure }.minOrNull()?.toInt() ?: 0)\n                .setMatchedKeyCount(exposures.map { it.key }.distinct().size)\n                .setMaximumRiskScore(exposures.map { it.getRiskScore(configuration) }.maxOrNull()?.toInt() ?: 0)\n                .setAttenuationDurations(intArrayOf(\n                        exposures.map { it.getAttenuationDurations(configuration)[0] }.sum(),\n                        exposures.map { it.getAttenuationDurations(configuration)[1] }.sum(),\n                        exposures.map { it.getAttenuationDurations(configuration)[2] }.sum()\n                ))\n                .setSummationRiskScore(exposures.map { it.getRiskScore(configuration) }.sum())\n                .build()\n    }\n\n    override fun provideDiagnosisKeys(params: ProvideDiagnosisKeysParams) {\n        val token = params.token ?: TOKEN_A\n        Log.w(TAG, \"provideDiagnosisKeys() with $packageName/$token\")\n        lifecycleScope.launchSafely {\n            val tid = ExposureDatabase.with(context) { database ->\n                val configuration = params.configuration\n                if (configuration != null) {\n                    database.storeConfiguration(packageName, token, configuration)\n                } else {\n                    database.getOrCreateTokenId(packageName, token)\n                }\n            }\n            if (tid == null) {\n                Log.w(TAG, \"Unknown token without configuration: $packageName/$token\")\n                try {\n                    params.callback.onResult(Status.INTERNAL_ERROR)\n                } catch (e: Exception) {\n                    Log.w(TAG, \"Callback failed\", e)\n                }\n                return@launchSafely\n            }\n            ExposureDatabase.with(context) { database ->\n                val start = System.currentTimeMillis()\n\n                // keys\n                params.keys?.let { database.batchStoreSingleDiagnosisKey(tid, it) }\n\n                var keys = params.keys?.size ?: 0\n\n                // Key files\n                val todoKeyFiles = arrayListOf<Pair<File, ByteArray>>()\n                for (file in params.keyFiles.orEmpty()) {\n                    try {\n                        val cacheFile = File(context.cacheDir, \"en-keyfile-${System.currentTimeMillis()}-${Random.nextInt()}.zip\")\n                        ParcelFileDescriptor.AutoCloseInputStream(file).use { it.copyToFile(cacheFile) }\n                        val hash = MessageDigest.getInstance(\"SHA-256\").digest(cacheFile)\n                        val storedKeys = database.storeDiagnosisFileUsed(tid, hash)\n                        if (storedKeys != null) {\n                            keys += storedKeys.toInt()\n                            cacheFile.delete()\n                        } else {\n                            todoKeyFiles.add(cacheFile to hash)\n                        }\n                    } catch (e: Exception) {\n                        Log.w(TAG, \"Failed parsing file\", e)\n                    }\n                }\n                params.keyFileSupplier?.let { keyFileSupplier ->\n                    Log.d(TAG, \"Using key file supplier\")\n                    try {\n                        while (keyFileSupplier.isAvailable && keyFileSupplier.hasNext()) {\n                            withContext(Dispatchers.IO) {\n                                try {\n                                    val cacheFile = File(context.cacheDir, \"en-keyfile-${System.currentTimeMillis()}-${Random.nextLong()}.zip\")\n                                    ParcelFileDescriptor.AutoCloseInputStream(keyFileSupplier.next()).use { it.copyToFile(cacheFile) }\n                                    val hash = MessageDigest.getInstance(\"SHA-256\").digest(cacheFile)\n                                    val storedKeys = database.storeDiagnosisFileUsed(tid, hash)\n                                    if (storedKeys != null) {\n                                        keys += storedKeys.toInt()\n                                        cacheFile.delete()\n                                    } else {\n                                        todoKeyFiles.add(cacheFile to hash)\n                                    }\n                                } catch (e: Exception) {\n                                    Log.w(TAG, \"Failed parsing file\", e)\n                                }\n                            }\n                        }\n                    } catch (e: Exception) {\n                        Log.w(TAG, \"Disconnected from key file supplier\", e)\n                    }\n                }\n\n                if (todoKeyFiles.size > 0) {\n                    val time = (System.currentTimeMillis() - start).coerceAtLeast(1).toDouble() / 1000.0\n                    Log.d(TAG, \"$packageName/$token processed $keys keys (${todoKeyFiles.size} files pending) in ${time}s -> ${(keys.toDouble() / time * 1000).roundToInt().toDouble() / 1000.0} keys/s\")\n                }\n\n                Handler(Looper.getMainLooper()).post {\n                    try {\n                        params.callback.onResult(Status.SUCCESS)\n                    } catch (e: Exception) {\n                        Log.w(TAG, \"Callback failed\", e)\n                    }\n                }\n\n                var newKeys = if (params.keys != null) database.finishSingleMatching(tid) else 0\n                for ((cacheFile, hash) in todoKeyFiles) {\n                    withContext(Dispatchers.IO) {\n                        if (backendPublicKey != null && !verifyKeyFile(cacheFile)) {\n                            Log.w(TAG, \"Skipping non-verified key file\")\n                            return@withContext\n                        }\n                        try {\n                            ZipFile(cacheFile).use { zip ->\n                                for (entry in zip.entries()) {\n                                    if (entry.name == \"export.bin\") {\n                                        val stream = zip.getInputStream(entry)\n                                        val prefix = ByteArray(16)\n                                        var totalBytesRead = 0\n                                        var bytesRead = 0\n                                        while (bytesRead != -1 && totalBytesRead < prefix.size) {\n                                            bytesRead = stream.read(prefix, totalBytesRead, prefix.size - totalBytesRead)\n                                            if (bytesRead > 0) {\n                                                totalBytesRead += bytesRead\n                                            }\n                                        }\n                                        if (totalBytesRead == prefix.size && String(prefix).trim() == \"EK Export v1\") {\n                                            val export = TemporaryExposureKeyExport.ADAPTER.decode(stream)\n                                            database.finishFileMatching(tid, hash, export.end_timestamp?.let { it * 1000 }\n                                                    ?: System.currentTimeMillis(), export.keys.map { it.toKey() }, export.revised_keys.map { it.toKey() })\n                                            keys += export.keys.size + export.revised_keys.size\n                                            newKeys += export.keys.size\n                                        } else {\n                                            Log.d(TAG, \"export.bin had invalid prefix\")\n                                        }\n                                    }\n                                }\n                            }\n                            cacheFile.delete()\n                        } catch (e: Exception) {\n                            Log.w(TAG, \"Failed parsing file\", e)\n                        }\n                    }\n                }\n\n                val time = (System.currentTimeMillis() - start).coerceAtLeast(1).toDouble() / 1000.0\n                Log.d(TAG, \"$packageName/$token processed $keys keys ($newKeys new) in ${time}s -> ${(keys.toDouble() / time * 1000).roundToInt().toDouble() / 1000.0} keys/s\")\n\n                database.noteAppAction(packageName, \"provideDiagnosisKeys\", JSONObject().apply {\n                    put(\"request_token\", token)\n                    put(\"request_keys_size\", params.keys?.size)\n                    put(\"request_keyFiles_size\", params.keyFiles?.size)\n                    put(\"request_keys_count\", keys)\n                }.toString())\n\n                if (!database.isAppAuthorized(packageName)) {\n                    // Not sending results via broadcast if app not authorized\n                    Log.d(TAG, \"$packageName not yet authorized\")\n                    return@with\n                }\n\n                val exposureSummary = buildExposureSummary(token)\n\n                try {\n                    val intent = if (exposureSummary.matchedKeyCount > 0) {\n                        Intent(ACTION_EXPOSURE_STATE_UPDATED)\n                    } else {\n                        Intent(ACTION_EXPOSURE_NOT_FOUND)\n                    }\n                    if (token != TOKEN_A) {\n                        intent.putExtra(EXTRA_EXPOSURE_SUMMARY, exposureSummary)\n                    }\n                    intent.putExtra(EXTRA_TOKEN, token)\n                    intent.`package` = packageName\n                    Log.d(TAG, \"Sending $intent\")\n                    context.sendOrderedBroadcast(intent, null)\n                } catch (e: Exception) {\n                    Log.w(TAG, \"Callback failed\", e)\n                }\n            }\n        }\n    }\n\n    private fun verifyKeyFile(file: File): Boolean {\n        try {\n            ZipFile(file).use { zip ->\n                var dataEntry: ZipEntry? = null\n                var sigEntry: ZipEntry? = null\n\n                for (entry in zip.entries()) {\n                    when (entry.name) {\n                        \"export.bin\" ->\n                            if (dataEntry != null) {\n                                throw Exception(\"Zip archive contains more than one 'export.bin' entry\")\n                            } else {\n                                dataEntry = entry\n                            }\n                        \"export.sig\" ->\n                            if (sigEntry != null) {\n                                throw Exception(\"Zip archive contains more than one 'export.sig' entry\")\n                            } else {\n                                sigEntry = entry\n                            }\n                        else -> throw Exception(\"Unexpected entry in zip archive: ${entry.name}\")\n                    }\n                }\n                when {\n                    dataEntry == null -> throw Exception(\"Zip archive does not contain 'export.bin'\")\n                    sigEntry == null -> throw Exception(\"Zip archive does not contain 'export.sin'\")\n                }\n\n                val sigStream = zip.getInputStream(sigEntry)\n                val sigList = TEKSignatureList.ADAPTER.decode(sigStream)\n\n                for (sig in sigList.signatures) {\n                    Log.d(TAG, \"Verifying signature ${sig.batch_num}/${sig.batch_size}\")\n                    val sigInfo = sig.signature_info ?: throw Exception(\"Signature information is missing\")\n                    Log.d(TAG, \"Signature info: algo=${sigInfo.signature_algorithm} key={id=${sigInfo.verification_key_id}, version=${sigInfo.verification_key_version}}\")\n\n                    val signature = sig.signature?.toByteArray() ?: throw Exception(\"Signature contents is missing\")\n                    val sigVerifier = (sigAlgoForOid.get(sigInfo.signature_algorithm) ?: throw Exception(\"Signature algorithm not supported: ${sigInfo.signature_algorithm}\"))()\n                    sigVerifier.initVerify(backendPublicKey)\n\n                    val stream = zip.getInputStream(dataEntry)\n                    val buf = ByteArray(1024)\n                    var nbRead = 0\n                    while (nbRead != -1) {\n                        nbRead = stream.read(buf)\n                        if (nbRead > 0) {\n                            sigVerifier.update(buf, 0, nbRead)\n                        }\n                    }\n\n                    if (!sigVerifier.verify(signature)) {\n                        throw Exception(\"Signature does not verify\")\n                    }\n                }\n            }\n        } catch (e: Exception) {\n            Log.w(TAG, \"Key file verification failed: \" + e.message)\n            return false\n        }\n\n        Log.i(TAG, \"Key file verification successful\")\n        return true\n    }\n\n    override fun getExposureSummary(params: GetExposureSummaryParams) {\n        lifecycleScope.launchSafely {\n            val response = buildExposureSummary(params.token)\n\n            ExposureDatabase.with(context) { database ->\n                database.noteAppAction(packageName, \"getExposureSummary\", JSONObject().apply {\n                    put(\"request_token\", params.token)\n                    put(\"response_days_since\", response.daysSinceLastExposure)\n                    put(\"response_matched_keys\", response.matchedKeyCount)\n                    put(\"response_max_risk\", response.maximumRiskScore)\n                    put(\"response_attenuation_durations\", JSONArray().apply {\n                        response.attenuationDurationsInMinutes.forEach { put(it) }\n                    })\n                    put(\"response_summation_risk\", response.summationRiskScore)\n                }.toString())\n            }\n            try {\n                params.callback.onResult(Status.SUCCESS, response)\n            } catch (e: Exception) {\n                Log.w(TAG, \"Callback failed\", e)\n            }\n        }\n    }\n\n    override fun getExposureInformation(params: GetExposureInformationParams) {\n        lifecycleScope.launchSafely {\n            ExposureDatabase.with(context) { database ->\n                val pair = database.loadConfiguration(packageName, params.token)\n                val response = if (pair != null && database.isAppAuthorized(packageName)) {\n                    database.findAllMeasuredExposures(pair.first).merge().map {\n                        it.toExposureInformation(pair.second.orDefault())\n                    }\n                } else {\n                    // Not providing information if app not authorized\n                    Log.d(TAG, \"$packageName not yet authorized\")\n                    emptyList()\n                }\n\n                database.noteAppAction(packageName, \"getExposureInformation\", JSONObject().apply {\n                    put(\"request_token\", params.token)\n                    put(\"response_size\", response.size)\n                }.toString())\n                try {\n                    params.callback.onResult(Status.SUCCESS, response)\n                } catch (e: Exception) {\n                    Log.w(TAG, \"Callback failed\", e)\n                }\n            }\n        }\n    }\n\n    private fun ScanInstance.Builder.apply(subExposure: MergedSubExposure): ScanInstance.Builder {\n        return this\n                .setSecondsSinceLastScan(subExposure.duration.coerceAtMost(5 * 60).toInt())\n                .setMinAttenuationDb(subExposure.attenuation) // FIXME: We use the average for both, because we don't store the minimum attenuation yet\n                .setTypicalAttenuationDb(subExposure.attenuation)\n    }\n\n    private fun List<MergedSubExposure>.toScanInstances(): List<ScanInstance> {\n        val res = arrayListOf<ScanInstance>()\n        for (subExposure in this) {\n            res.add(ScanInstance.Builder().apply(subExposure).build())\n            if (subExposure.duration > 5 * 60 * 1000L) {\n                res.add(ScanInstance.Builder().apply(subExposure).setSecondsSinceLastScan((subExposure.duration - 5 * 60).coerceAtMost(5 * 60).toInt()).build())\n            }\n        }\n        return res\n    }\n\n    private fun DiagnosisKeysDataMapping?.orDefault() = this ?: DiagnosisKeysDataMapping()\n\n    private suspend fun getExposureWindowsInternal(token: String = TOKEN_A): List<ExposureWindow> {\n        val (exposures, mapping) = ExposureDatabase.with(context) { database ->\n            val triple = database.loadConfiguration(packageName, token)\n            if (triple != null && database.isAppAuthorized(packageName)) {\n                database.findAllMeasuredExposures(triple.first).merge() to triple.third.orDefault()\n            } else {\n                // Not providing windows if app not authorized\n                Log.d(TAG, \"$packageName not yet authorized\")\n                emptyList<MergedExposure>() to DiagnosisKeysDataMapping()\n            }\n        }\n        return exposures.map {\n            val infectiousness =\n                    if (it.key.daysSinceOnsetOfSymptoms == DAYS_SINCE_ONSET_OF_SYMPTOMS_UNKNOWN)\n                        mapping.infectiousnessWhenDaysSinceOnsetMissing\n                    else\n                        mapping.daysSinceOnsetToInfectiousness[it.key.daysSinceOnsetOfSymptoms]\n                                ?: Infectiousness.NONE\n            val reportType =\n                    if (it.key.reportType == ReportType.UNKNOWN)\n                        mapping.reportTypeWhenMissing\n                    else\n                        it.key.reportType\n\n            ExposureWindow.Builder()\n                    .setCalibrationConfidence(it.confidence)\n                    .setDateMillisSinceEpoch(it.key.rollingStartIntervalNumber.toLong() * ROLLING_WINDOW_LENGTH_MS)\n                    .setInfectiousness(infectiousness)\n                    .setReportType(reportType)\n                    .setScanInstances(it.subs.toScanInstances())\n                    .build()\n        }\n    }\n\n    override fun getExposureWindows(params: GetExposureWindowsParams) {\n        lifecycleScope.launchSafely {\n            val response = getExposureWindowsInternal(params.token ?: TOKEN_A)\n\n            ExposureDatabase.with(context) { database ->\n                database.noteAppAction(packageName, \"getExposureWindows\", JSONObject().apply {\n                    put(\"request_token\", params.token)\n                    put(\"response_size\", response.size)\n                }.toString())\n            }\n\n            try {\n                params.callback.onResult(Status.SUCCESS, response)\n            } catch (e: Exception) {\n                Log.w(TAG, \"Callback failed\", e)\n            }\n        }\n    }\n\n    private fun DailySummariesConfig.bucketFor(attenuation: Int): Int {\n        if (attenuation < attenuationBucketThresholdDb[0]) return 0\n        if (attenuation < attenuationBucketThresholdDb[1]) return 1\n        if (attenuation < attenuationBucketThresholdDb[2]) return 2\n        return 3\n    }\n\n    private fun DailySummariesConfig.weightedDurationFor(attenuation: Int, seconds: Int): Double {\n        return attenuationBucketWeights[bucketFor(attenuation)] * seconds\n    }\n\n    private fun Collection<DailySummary.ExposureSummaryData>.sum(): DailySummary.ExposureSummaryData {\n        return DailySummary.ExposureSummaryData(map { it.maximumScore }.maxOrNull()\n                ?: 0.0, sumByDouble { it.scoreSum }, sumByDouble { it.weightedDurationSum })\n    }\n\n    override fun getDailySummaries(params: GetDailySummariesParams) {\n        lifecycleScope.launchSafely {\n            val response = getExposureWindowsInternal().groupBy { it.dateMillisSinceEpoch }.map {\n                val map = arrayListOf<DailySummary.ExposureSummaryData>()\n                for (i in 0 until ReportType.VALUES) {\n                    map[i] = DailySummary.ExposureSummaryData(0.0, 0.0, 0.0)\n                }\n                for (entry in it.value.groupBy { it.reportType }) {\n                    for (window in entry.value) {\n                        val weightedDuration = window.scanInstances.map { params.config.weightedDurationFor(it.typicalAttenuationDb, it.secondsSinceLastScan) }.sum()\n                        val score = (params.config.reportTypeWeights[window.reportType] ?: 1.0) *\n                                (params.config.infectiousnessWeights[window.infectiousness] ?: 1.0) *\n                                weightedDuration\n                        if (score >= params.config.minimumWindowScore) {\n                            map[entry.key] = DailySummary.ExposureSummaryData(max(map[entry.key].maximumScore, score), map[entry.key].scoreSum + score, map[entry.key].weightedDurationSum + weightedDuration)\n                        }\n                    }\n                }\n                DailySummary((it.key / (1000L * 60 * 60 * 24)).toInt(), map, map.sum())\n            }\n\n            ExposureDatabase.with(context) { database ->\n                database.noteAppAction(packageName, \"getDailySummaries\", JSONObject().apply {\n                    put(\"response_size\", response.size)\n                }.toString())\n            }\n\n            try {\n                params.callback.onResult(Status.SUCCESS, response)\n            } catch (e: Exception) {\n                Log.w(TAG, \"Callback failed\", e)\n            }\n        }\n    }\n\n    override fun setDiagnosisKeysDataMapping(params: SetDiagnosisKeysDataMappingParams) {\n        lifecycleScope.launchSafely {\n            ExposureDatabase.with(context) { database ->\n                database.storeConfiguration(packageName, TOKEN_A, params.mapping)\n                database.noteAppAction(packageName, \"setDiagnosisKeysDataMapping\")\n            }\n            try {\n                params.callback.onResult(Status.SUCCESS)\n            } catch (e: Exception) {\n                Log.w(TAG, \"Callback failed\", e)\n            }\n        }\n    }\n\n    override fun getDiagnosisKeysDataMapping(params: GetDiagnosisKeysDataMappingParams) {\n        lifecycleScope.launchSafely {\n            val mapping = ExposureDatabase.with(context) { database ->\n                val triple = database.loadConfiguration(packageName, TOKEN_A)\n                database.noteAppAction(packageName, \"getDiagnosisKeysDataMapping\")\n                triple?.third\n            }\n            try {\n                params.callback.onResult(Status.SUCCESS, mapping.orDefault())\n            } catch (e: Exception) {\n                Log.w(TAG, \"Callback failed\", e)\n            }\n        }\n    }\n\n    override fun getPackageConfiguration(params: GetPackageConfigurationParams) {\n        Log.w(TAG, \"Not yet implemented: getPackageConfiguration\")\n        lifecycleScope.launchSafely {\n            ExposureDatabase.with(context) { database ->\n                database.noteAppAction(packageName, \"getPackageConfiguration\")\n            }\n            try {\n                params.callback.onResult(Status.SUCCESS, PackageConfiguration.PackageConfigurationBuilder().setValues(Bundle.EMPTY).build())\n            } catch (e: Exception) {\n                Log.w(TAG, \"Callback failed\", e)\n            }\n        }\n    }\n\n    override fun getStatus(params: GetStatusParams) {\n        lifecycleScope.launchSafely {\n            val isAuthorized = ExposureDatabase.with(context) { database ->\n                database.noteAppAction(packageName, \"getStatus\")\n                database.isAppAuthorized(packageName)\n            }\n            val flags = hashSetOf<ExposureNotificationStatus>()\n            val adapter = BluetoothAdapter.getDefaultAdapter()\n            if (adapter == null || !adapter.isEnabled) {\n                flags.add(ExposureNotificationStatus.BLUETOOTH_DISABLED)\n                flags.add(ExposureNotificationStatus.BLUETOOTH_SUPPORT_UNKNOWN)\n            } else if (Build.VERSION.SDK_INT < 21) {\n                flags.add(ExposureNotificationStatus.EN_NOT_SUPPORT)\n            } else if (adapter.bluetoothLeScanner == null){\n                flags.add(ExposureNotificationStatus.HW_NOT_SUPPORT)\n            }\n            if (!LocationManagerCompat.isLocationEnabled(context.getSystemService(Context.LOCATION_SERVICE) as LocationManager)) {\n                flags.add(ExposureNotificationStatus.LOCATION_DISABLED)\n            }\n            if (!isAuthorized) {\n                flags.add(ExposureNotificationStatus.NO_CONSENT)\n            }\n            if (isAuthorized && ExposurePreferences(context).enabled) {\n                flags.add(ExposureNotificationStatus.ACTIVATED)\n            } else {\n                flags.add(ExposureNotificationStatus.INACTIVATED)\n            }\n            try {\n                params.callback.onResult(Status.SUCCESS, ExposureNotificationStatus.setToFlags(flags))\n            } catch (e: Exception) {\n                Log.w(TAG, \"Callback failed\", e)\n            }\n        }\n    }\n\n    override fun requestPreAuthorizedTemporaryExposureKeyHistory(params: RequestPreAuthorizedTemporaryExposureKeyHistoryParams) {\n        // TODO: Proper implementation\n        lifecycleScope.launchSafely {\n            params.callback.onResult(Status.CANCELED)\n        }\n    }\n\n    override fun requestPreAuthorizedTemporaryExposureKeyRelease(params: RequestPreAuthorizedTemporaryExposureKeyReleaseParams) {\n        // TODO: Proper implementation\n        lifecycleScope.launchSafely {\n            params.callback.onResult(Status(FAILED_KEY_RELEASE_NOT_PREAUTHORIZED))\n        }\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n\n    companion object {\n        private val tempGrantedPermissions: MutableSet<Pair<String, String>> = hashSetOf()\n        private const val VERSION = 18\n        private const val VERSION_FULL = VERSION.toLong() * 1000000000L + Constants.GMS_VERSION_CODE\n    }\n}\n"
  },
  {
    "path": "play-services-nearby/core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ExposurePreferences.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.nearby.exposurenotification\n\nimport android.content.Context\nimport android.content.Intent\nimport org.microg.gms.settings.SettingsContract.Exposure.getContentUri\nimport org.microg.gms.settings.SettingsContract.Exposure.LAST_CLEANUP\nimport org.microg.gms.settings.SettingsContract.Exposure.SCANNER_ENABLED\nimport org.microg.gms.settings.SettingsContract.getSettings\nimport org.microg.gms.settings.SettingsContract.setSettings\n\nclass ExposurePreferences(private val context: Context) {\n\n    var enabled\n        get() = getSettings(context, getContentUri(context), arrayOf(SCANNER_ENABLED)) { c ->\n            c.getInt(0) != 0\n        }\n        set(newStatus) {\n            val changed = enabled != newStatus\n            setSettings(context, getContentUri(context)) {\n                put(SCANNER_ENABLED, newStatus)\n            }\n            if (!changed) return\n            if (newStatus) {\n                context.sendOrderedBroadcast(Intent(context, ServiceTrigger::class.java), null)\n            } else {\n                context.stopService(Intent(context, ScannerService::class.java))\n                context.stopService(Intent(context, AdvertiserService::class.java))\n            }\n        }\n\n    var lastCleanup\n        get() = getSettings(context, getContentUri(context), arrayOf(LAST_CLEANUP)) { c ->\n            c.getLong(0)\n        }\n        set(value) = setSettings(context, getContentUri(context)) {\n            put(LAST_CLEANUP, value)\n        }\n\n}\n"
  },
  {
    "path": "play-services-nearby/core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/Extensions.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.nearby.exposurenotification\n\nimport android.annotation.SuppressLint\nimport android.bluetooth.BluetoothAdapter\nimport android.content.BroadcastReceiver\nimport android.content.Context\nimport android.content.Intent\nimport android.content.IntentFilter\nimport android.util.Log\nimport kotlinx.coroutines.CompletableDeferred\nimport kotlinx.coroutines.withTimeout\n\n@SuppressLint(\"MissingPermission\")\nsuspend fun BluetoothAdapter.enableAsync(context: Context): Boolean {\n    val deferred = CompletableDeferred<Unit>()\n    val receiver: BroadcastReceiver = object : BroadcastReceiver() {\n        override fun onReceive(receiverContext: Context?, intent: Intent?) {\n            if (intent?.action == BluetoothAdapter.ACTION_STATE_CHANGED) {\n                val state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR)\n                if (state == BluetoothAdapter.STATE_ON) deferred.complete(Unit)\n            }\n        }\n    }\n    context.registerReceiver(receiver, IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED))\n    if (!isEnabled) {\n        try {\n            enable()\n            withTimeout(5000) { deferred.await() }\n        } catch (e: Exception) {\n            Log.w(TAG, \"Failed enabling Bluetooth\")\n        }\n    }\n    context.unregisterReceiver(receiver)\n    return isEnabled\n}\n"
  },
  {
    "path": "play-services-nearby/core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/MeasuredExposure.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.nearby.exposurenotification\n\nimport android.util.Log\nimport com.google.android.gms.nearby.exposurenotification.*\nimport java.util.concurrent.TimeUnit\n\ndata class ExposureScanSummary(val time: Long, val rpis: Int, val records: Int)\n\ndata class PlainExposure(val rpi: ByteArray, val aem: ByteArray, val timestamp: Long, val duration: Long, val rssi: Int)\n\ndata class MeasuredExposure(val timestamp: Long, val duration: Long, val rssi: Int, val txPower: Int, @CalibrationConfidence val confidence: Int, val key: TemporaryExposureKey) {\n    val attenuation\n        get() = txPower - (rssi + currentDeviceInfo.rssiCorrection)\n}\n\nfun List<MeasuredExposure>.merge(): List<MergedExposure> {\n    val keys = map { it.key }.distinct()\n    val result = arrayListOf<MergedExposure>()\n    for (key in keys) {\n        var merged: MergedExposure? = null\n        for (exposure in filter { it.key == key }.distinctBy { it.timestamp }.sortedBy { it.timestamp }) {\n            if (merged != null && merged.timestamp + MergedExposure.MAXIMUM_DURATION > exposure.timestamp) {\n                merged += exposure\n            } else {\n                if (merged != null) {\n                    result.add(merged)\n                }\n                merged = MergedExposure(key, exposure.timestamp, exposure.txPower, exposure.confidence, listOf(MergedSubExposure(exposure.attenuation, exposure.duration)))\n            }\n            if (merged.durationInMinutes >= 30) {\n                result.add(merged)\n                merged = null\n            }\n        }\n        if (merged != null) {\n            result.add(merged)\n        }\n    }\n    return result\n}\n\ndata class MergedSubExposure(val attenuation: Int, val duration: Long)\n\ndata class MergedExposure internal constructor(val key: TemporaryExposureKey, val timestamp: Long, val txPower: Int, @CalibrationConfidence val confidence: Int, val subs: List<MergedSubExposure>) {\n    @RiskLevel\n    val transmissionRiskLevel: Int\n        get() = key.transmissionRiskLevel\n\n    val durationInMinutes\n        get() = TimeUnit.MILLISECONDS.toMinutes(subs.map { it.duration }.sum())\n\n    val daysSinceExposure\n        get() = TimeUnit.MILLISECONDS.toDays(System.currentTimeMillis() - timestamp)\n\n    val attenuation\n        get() = if (subs.map { it.duration }.sum() == 0L) subs[0].attenuation else (subs.map { it.attenuation * it.duration }.sum().toDouble() / subs.map { it.duration }.sum().toDouble()).toInt()\n\n    fun getAttenuationRiskScore(configuration: ExposureConfiguration): Int {\n        return when {\n            attenuation > 73 -> configuration.attenuationScores[0]\n            attenuation > 63 -> configuration.attenuationScores[1]\n            attenuation > 51 -> configuration.attenuationScores[2]\n            attenuation > 33 -> configuration.attenuationScores[3]\n            attenuation > 27 -> configuration.attenuationScores[4]\n            attenuation > 15 -> configuration.attenuationScores[5]\n            attenuation > 10 -> configuration.attenuationScores[6]\n            else -> configuration.attenuationScores[7]\n        }\n    }\n\n    fun getDaysSinceLastExposureRiskScore(configuration: ExposureConfiguration): Int {\n        return when {\n            daysSinceExposure >= 14 -> configuration.daysSinceLastExposureScores[0]\n            daysSinceExposure >= 12 -> configuration.daysSinceLastExposureScores[1]\n            daysSinceExposure >= 10 -> configuration.daysSinceLastExposureScores[2]\n            daysSinceExposure >= 8 -> configuration.daysSinceLastExposureScores[3]\n            daysSinceExposure >= 6 -> configuration.daysSinceLastExposureScores[4]\n            daysSinceExposure >= 4 -> configuration.daysSinceLastExposureScores[5]\n            daysSinceExposure >= 2 -> configuration.daysSinceLastExposureScores[6]\n            else -> configuration.daysSinceLastExposureScores[7]\n        }\n    }\n\n    fun getDurationRiskScore(configuration: ExposureConfiguration): Int {\n        return when {\n            durationInMinutes == 0L -> configuration.durationScores[0]\n            durationInMinutes <= 5 -> configuration.durationScores[1]\n            durationInMinutes <= 10 -> configuration.durationScores[2]\n            durationInMinutes <= 15 -> configuration.durationScores[3]\n            durationInMinutes <= 20 -> configuration.durationScores[4]\n            durationInMinutes <= 25 -> configuration.durationScores[5]\n            durationInMinutes <= 30 -> configuration.durationScores[6]\n            else -> configuration.durationScores[7]\n        }\n    }\n\n    fun getTransmissionRiskScore(configuration: ExposureConfiguration): Int {\n        return when (transmissionRiskLevel) {\n            RiskLevel.RISK_LEVEL_LOWEST -> configuration.transmissionRiskScores[0]\n            RiskLevel.RISK_LEVEL_LOW -> configuration.transmissionRiskScores[1]\n            RiskLevel.RISK_LEVEL_LOW_MEDIUM -> configuration.transmissionRiskScores[2]\n            RiskLevel.RISK_LEVEL_MEDIUM -> configuration.transmissionRiskScores[3]\n            RiskLevel.RISK_LEVEL_MEDIUM_HIGH -> configuration.transmissionRiskScores[4]\n            RiskLevel.RISK_LEVEL_HIGH -> configuration.transmissionRiskScores[5]\n            RiskLevel.RISK_LEVEL_VERY_HIGH -> configuration.transmissionRiskScores[6]\n            RiskLevel.RISK_LEVEL_HIGHEST -> configuration.transmissionRiskScores[7]\n            else -> 1\n        }\n    }\n\n    fun getRiskScore(configuration: ExposureConfiguration): Int {\n        val risk = getAttenuationRiskScore(configuration) * getDaysSinceLastExposureRiskScore(configuration) * getDurationRiskScore(configuration) * getTransmissionRiskScore(configuration)\n        Log.d(TAG, \"Risk score calculation: ${getAttenuationRiskScore(configuration)} * ${getDaysSinceLastExposureRiskScore(configuration)} * ${getDurationRiskScore(configuration)} * ${getTransmissionRiskScore(configuration)} = $risk\")\n        if (risk < configuration.minimumRiskScore) return 0\n        return risk\n    }\n\n    fun getAttenuationDurations(configuration: ExposureConfiguration): IntArray {\n        return intArrayOf(\n                TimeUnit.MILLISECONDS.toMinutes(subs.filter { it.attenuation < configuration.durationAtAttenuationThresholds[0] }.map { it.duration }.sum()).toInt(),\n                TimeUnit.MILLISECONDS.toMinutes(subs.filter { it.attenuation >= configuration.durationAtAttenuationThresholds[0] && it.attenuation < configuration.durationAtAttenuationThresholds[1] }.map { it.duration }.sum()).toInt(),\n                TimeUnit.MILLISECONDS.toMinutes(subs.filter { it.attenuation >= configuration.durationAtAttenuationThresholds[1] }.map { it.duration }.sum()).toInt()\n        )\n    }\n\n    fun toExposureInformation(configuration: ExposureConfiguration): ExposureInformation =\n            ExposureInformation.ExposureInformationBuilder()\n                    .setDateMillisSinceEpoch(key.rollingStartIntervalNumber.toLong() * ROLLING_WINDOW_LENGTH_MS)\n                    .setDurationMinutes(durationInMinutes.toInt())\n                    .setAttenuationValue(attenuation)\n                    .setTransmissionRiskLevel(transmissionRiskLevel)\n                    .setTotalRiskScore(getRiskScore(configuration))\n                    .setAttenuationDurations(getAttenuationDurations(configuration))\n                    .build()\n\n    operator fun plus(exposure: MeasuredExposure): MergedExposure = copy(subs = subs + MergedSubExposure(exposure.attenuation, exposure.duration))\n\n    companion object {\n        const val MAXIMUM_DURATION = 30 * 60 * 1000\n    }\n}\n"
  },
  {
    "path": "play-services-nearby/core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/NotifyService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.nearby.exposurenotification\n\nimport android.annotation.TargetApi\nimport android.app.*\nimport android.app.PendingIntent.FLAG_UPDATE_CURRENT\nimport android.bluetooth.BluetoothAdapter\nimport android.content.BroadcastReceiver\nimport android.content.Context\nimport android.content.Intent\nimport android.content.IntentFilter\nimport android.content.pm.PackageManager\nimport android.graphics.Color\nimport android.location.LocationManager\nimport android.os.Build.VERSION.SDK_INT\nimport android.util.Log\nimport android.util.TypedValue\nimport androidx.core.app.NotificationCompat\nimport androidx.core.app.NotificationManagerCompat\nimport androidx.core.app.PendingIntentCompat\nimport androidx.core.content.ContextCompat\nimport androidx.core.location.LocationManagerCompat\nimport androidx.lifecycle.LifecycleService\nimport com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient\nimport org.microg.gms.common.ForegroundServiceContext\nimport org.microg.gms.common.ForegroundServiceInfo\nimport org.microg.gms.nearby.core.R\n\n@ForegroundServiceInfo(\"Exposure Notification\")\nclass NotifyService : LifecycleService() {\n    private val notificationId = NotifyService::class.java.name.hashCode()\n    private val trigger = object : BroadcastReceiver() {\n        override fun onReceive(context: Context, intent: Intent?) {\n            updateNotification()\n        }\n    }\n\n    @TargetApi(26)\n    private fun createNotificationChannel(): String {\n        val channel = NotificationChannel(\"exposure-notifications\", \"Exposure Notifications\", NotificationManager.IMPORTANCE_HIGH)\n        channel.setSound(null, null)\n        channel.lockscreenVisibility = Notification.VISIBILITY_PUBLIC\n        channel.setShowBadge(true)\n        if (SDK_INT >= 29) {\n            channel.setAllowBubbles(false)\n        }\n        channel.vibrationPattern = longArrayOf(0)\n        getSystemService(NotificationManager::class.java).createNotificationChannel(channel)\n        return channel.id\n    }\n\n    @TargetApi(21)\n    private fun updateNotification() {\n        val location = !LocationManagerCompat.isLocationEnabled(getSystemService(Context.LOCATION_SERVICE) as LocationManager)\n        val bluetooth = BluetoothAdapter.getDefaultAdapter()?.state.let { it != BluetoothAdapter.STATE_ON && it != BluetoothAdapter.STATE_TURNING_ON }\n        val nearbyPermissions = arrayOf(\"android.permission.BLUETOOTH_ADVERTISE\", \"android.permission.BLUETOOTH_SCAN\")\n        val permissionNeedsHandling = SDK_INT >= 31 && nearbyPermissions.any {\n            ContextCompat.checkSelfPermission(this, it) != PackageManager.PERMISSION_GRANTED\n        }\n        Log.d( TAG,\"notify: location: $location, bluetooth: $bluetooth, permissionNeedsHandling: $permissionNeedsHandling\")\n\n        val text: String = when {\n            permissionNeedsHandling -> getString(R.string.exposure_notify_off_nearby)\n            location && bluetooth -> getString(R.string.exposure_notify_off_bluetooth_location)\n            location -> getString(R.string.exposure_notify_off_location)\n            bluetooth -> getString(R.string.exposure_notify_off_bluetooth)\n            else -> {\n                NotificationManagerCompat.from(this).cancel(notificationId)\n                return\n            }\n        }\n\n        if (SDK_INT >= 26) {\n            NotificationCompat.Builder(this, createNotificationChannel())\n        } else {\n            NotificationCompat.Builder(this)\n        }.apply {\n            val typedValue = TypedValue()\n            try {\n                var resolved = theme.resolveAttribute(androidx.appcompat.R.attr.colorError, typedValue, true)\n                if (!resolved && SDK_INT >= 26) resolved = theme.resolveAttribute(android.R.attr.colorError, typedValue, true)\n                color = if (resolved) {\n                    ContextCompat.getColor(this@NotifyService, typedValue.resourceId)\n                } else {\n                    Color.RED\n                }\n                if (SDK_INT >= 26) setColorized(true)\n            } catch (e: Exception) {\n                // Ignore\n            }\n            setSmallIcon(R.drawable.ic_virus_outline)\n            setContentTitle(getString(R.string.exposure_notify_off_title))\n            setContentText(text)\n            setStyle(NotificationCompat.BigTextStyle())\n            try {\n                val intent = Intent(ExposureNotificationClient.ACTION_EXPOSURE_NOTIFICATION_SETTINGS).apply { `package` = packageName }\n                intent.resolveActivity(packageManager)\n                setContentIntent(PendingIntentCompat.getActivity(this@NotifyService, notificationId, Intent(ExposureNotificationClient.ACTION_EXPOSURE_NOTIFICATION_SETTINGS).apply { `package` = packageName }, FLAG_UPDATE_CURRENT, false))\n            } catch (e: Exception) {\n                // Ignore\n            }\n        }.let {\n            NotificationManagerCompat.from(this).notify(notificationId, it.build())\n        }\n    }\n\n    override fun onCreate() {\n        super.onCreate()\n        registerReceiver(trigger, IntentFilter().apply {\n            addAction(BluetoothAdapter.ACTION_STATE_CHANGED)\n            if (SDK_INT >= 19) addAction(LocationManager.MODE_CHANGED_ACTION)\n            addAction(LocationManager.PROVIDERS_CHANGED_ACTION)\n            addAction(NOTIFICATION_UPDATE_ACTION)\n        })\n    }\n\n    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {\n        ForegroundServiceContext.completeForegroundService(this, intent, TAG)\n        Log.d(TAG, \"NotifyService.start: $intent\")\n        super.onStartCommand(intent, flags, startId)\n        updateNotification()\n        return Service.START_STICKY\n    }\n\n    override fun onDestroy() {\n        super.onDestroy()\n        NotificationManagerCompat.from(this).cancel(notificationId)\n        unregisterReceiver(trigger)\n    }\n\n    companion object {\n        fun isNeeded(context: Context): Boolean {\n            return ExposurePreferences(context).let { it.enabled }\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-nearby/core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ScannerService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.nearby.exposurenotification\n\nimport android.annotation.SuppressLint\nimport android.annotation.TargetApi\nimport android.app.AlarmManager\nimport android.app.PendingIntent.FLAG_ONE_SHOT\nimport android.app.PendingIntent.FLAG_UPDATE_CURRENT\nimport android.bluetooth.BluetoothAdapter.*\nimport android.bluetooth.le.*\nimport android.content.BroadcastReceiver\nimport android.content.Context\nimport android.content.Intent\nimport android.content.IntentFilter\nimport android.os.*\nimport android.util.Log\nimport androidx.core.app.PendingIntentCompat\nimport androidx.lifecycle.LifecycleService\nimport androidx.lifecycle.lifecycleScope\nimport org.microg.gms.common.ForegroundServiceContext\nimport org.microg.gms.common.ForegroundServiceInfo\nimport java.io.FileDescriptor\nimport java.io.PrintWriter\nimport java.util.*\n\n@TargetApi(21)\n@ForegroundServiceInfo(\"Exposure Notification\")\nclass ScannerService : LifecycleService() {\n    private var scanning = false\n    private var lastStartTime = 0L\n    private var seenAdvertisements = 0L\n    private var lastAdvertisement = 0L\n    private val callback = object : ScanCallback() {\n        override fun onScanResult(callbackType: Int, result: ScanResult?) {\n            result?.let { onScanResult(it) }\n        }\n\n        override fun onBatchScanResults(results: MutableList<ScanResult>) {\n            for (result in results) {\n                onScanResult(result)\n            }\n        }\n\n        override fun onScanFailed(errorCode: Int) {\n            Log.w(TAG, \"onScanFailed: $errorCode\")\n            stopScan()\n        }\n    }\n    private val trigger = object : BroadcastReceiver() {\n        override fun onReceive(context: Context?, intent: Intent?) {\n            if (intent?.action == ACTION_STATE_CHANGED) {\n                when (intent.getIntExtra(EXTRA_STATE, -1)) {\n                    STATE_TURNING_OFF, STATE_OFF -> stopScan()\n                    STATE_ON -> startScanIfNeeded()\n                }\n            }\n        }\n    }\n    private val handler = Handler(Looper.getMainLooper())\n    private val stopLaterRunnable = Runnable { stopScan() }\n\n    // Wake lock for the duration of scan. Otherwise we might fall asleep while scanning\n    // resulting in potentially very long scan times\n    private val wakeLock: PowerManager.WakeLock by lazy {\n        powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, ScannerService::class.java.canonicalName).apply { setReferenceCounted(false) }\n    }\n\n    private val scanner: BluetoothLeScanner?\n        get() = getDefaultAdapter()?.bluetoothLeScanner\n    private val alarmManager: AlarmManager\n        get() = getSystemService(Context.ALARM_SERVICE) as AlarmManager\n    private val powerManager: PowerManager\n        get() = getSystemService(Context.POWER_SERVICE) as PowerManager\n\n    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {\n        ForegroundServiceContext.completeForegroundService(this, intent, TAG)\n        Log.d(TAG, \"ScannerService.start: $intent\")\n        super.onStartCommand(intent, flags, startId)\n        startScanIfNeeded()\n        return START_STICKY\n    }\n\n    fun onScanResult(result: ScanResult) {\n        val data = result.scanRecord?.serviceData?.get(SERVICE_UUID) ?: return\n        if (data.size < 16) return // Ignore invalid advertisements\n        seenAdvertisements++\n        lastAdvertisement = System.currentTimeMillis()\n        lifecycleScope.launchWhenStarted {\n            ExposureDatabase.with(this@ScannerService) { database ->\n                database.noteAdvertisement(data.sliceArray(0..15), data.drop(16).toByteArray(), result.rssi)\n            }\n        }\n    }\n\n    fun startScanIfNeeded() {\n        if (ExposurePreferences(this).enabled) {\n            startScan()\n        } else {\n            stopSelf()\n        }\n    }\n\n    override fun onCreate() {\n        super.onCreate()\n        registerReceiver(trigger, IntentFilter().apply { addAction(ACTION_STATE_CHANGED) })\n    }\n\n    override fun onDestroy() {\n        super.onDestroy()\n        unregisterReceiver(trigger)\n        stopScan()\n    }\n\n    @SuppressLint(\"WakelockTimeout\", \"MissingPermission\")\n    @Synchronized\n    private fun startScan() {\n        if (scanning) return\n        val scanner = scanner ?: return\n        Log.i(TAG, \"Starting scanner for service $SERVICE_UUID for ${SCANNING_TIME_MS}ms\")\n        seenAdvertisements = 0\n        wakeLock.acquire()\n        try {\n            scanner.startScan(\n                    listOf(ScanFilter.Builder()\n                            .setServiceUuid(SERVICE_UUID)\n                            .setServiceData(SERVICE_UUID, byteArrayOf(0), byteArrayOf(0))\n                            .build()),\n                    ScanSettings.Builder().build(),\n                    callback\n            )\n        } catch (e: SecurityException) {\n            Log.e(TAG, \"Couldn't start ScannerService, need android.permission.BLUETOOTH_SCAN permission.\")\n        }\n        scanning = true\n        lastStartTime = System.currentTimeMillis()\n        handler.postDelayed(stopLaterRunnable, SCANNING_TIME_MS)\n    }\n\n    @SuppressLint(\"MissingPermission\")\n    @Synchronized\n    private fun stopScan() {\n        if (!scanning) return\n        Log.i(TAG, \"Stopping scanner for service $SERVICE_UUID, had seen $seenAdvertisements advertisements\")\n        handler.removeCallbacks(stopLaterRunnable)\n        scanning = false\n        try {\n            scanner?.stopScan(callback)\n        } catch (e: Exception) {\n            // Ignored\n        }\n        if (ExposurePreferences(this).enabled) {\n            scheduleStartScan(((lastStartTime + SCANNING_INTERVAL_MS) - System.currentTimeMillis()).coerceIn(0, SCANNING_INTERVAL_MS))\n        }\n        wakeLock.release()\n    }\n\n    private fun scheduleStartScan(nextScan: Long) {\n        val intent = Intent(this, ScannerService::class.java)\n        val pendingIntent = PendingIntentCompat.getService(this, ScannerService::class.java.hashCode(), intent, FLAG_ONE_SHOT or FLAG_UPDATE_CURRENT, false)!!\n        if (Build.VERSION.SDK_INT >= 23) {\n            // Note: there is no setWindowAndAllowWhileIdle()\n            alarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + nextScan, pendingIntent)\n        } else {\n            alarmManager.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + nextScan - SCANNING_TIME_MS / 2, SCANNING_TIME_MS, pendingIntent)\n        }\n    }\n\n    override fun dump(fd: FileDescriptor?, writer: PrintWriter?, args: Array<out String>?) {\n        writer?.println(\"Scanning now: $scanning\")\n        writer?.println(\"Last scan start: ${Date(lastStartTime)}\")\n        if (Build.VERSION.SDK_INT >= 29) {\n            writer?.println(\"Scan stop pending: ${handler.hasCallbacks(stopLaterRunnable)}\")\n        }\n        writer?.println(\"Seen advertisements since last scan start: $seenAdvertisements\")\n        writer?.println(\"Last advertisement seen: ${Date(lastAdvertisement)}\")\n    }\n\n    companion object {\n        fun isNeeded(context: Context): Boolean {\n            return ExposurePreferences(context).enabled\n        }\n\n        fun isSupported(context: Context): Boolean? {\n            val adapter = getDefaultAdapter()\n            return when {\n                adapter == null -> false\n                adapter.state != STATE_ON -> null\n                adapter.bluetoothLeScanner != null -> true\n                else -> false\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-nearby/core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ServiceInfo.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.nearby.exposurenotification\n\nimport android.content.Context\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\nimport java.io.Serializable\n\ndata class ServiceInfo(val configuration: ServiceConfiguration) : Serializable\n\ndata class ServiceConfiguration(val enabled: Boolean) : Serializable {\n    fun saveToPrefs(context: Context) {\n        ExposurePreferences(context).enabled = enabled\n    }\n}\n\nprivate fun ExposurePreferences.toConfiguration(): ServiceConfiguration = ServiceConfiguration(enabled)\n\nsuspend fun getExposureNotificationsServiceInfo(context: Context): ServiceInfo =\n    withContext(Dispatchers.IO) {\n        ServiceInfo(ExposurePreferences(context).toConfiguration())\n    }\n\nsuspend fun setExposureNotificationsServiceConfiguration(context: Context, configuration: ServiceConfiguration) =\n    withContext(Dispatchers.IO) {\n        ExposurePreferences(context).enabled = configuration.enabled\n    }\n"
  },
  {
    "path": "play-services-nearby/core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ServiceTrigger.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.nearby.exposurenotification\n\nimport android.annotation.SuppressLint\nimport android.content.BroadcastReceiver\nimport android.content.Context\nimport android.content.Intent\nimport android.util.Log\nimport org.microg.gms.common.ForegroundServiceContext\n\nclass ServiceTrigger : BroadcastReceiver() {\n    @SuppressLint(\"UnsafeProtectedBroadcastReceiver\")\n    override fun onReceive(context: Context, intent: Intent?) {\n        Log.d(TAG, \"ServiceTrigger: $intent\")\n        val serviceContext = ForegroundServiceContext(context)\n        if (ScannerService.isNeeded(context)) {\n            Log.d(TAG, \"Trigger ${ScannerService::class.java}\")\n            serviceContext.startService(Intent(context, ScannerService::class.java))\n        }\n        if (AdvertiserService.isNeeded(context)) {\n            Log.d(TAG, \"Trigger ${AdvertiserService::class.java}\")\n            serviceContext.startService(Intent(context, AdvertiserService::class.java))\n        }\n        if (CleanupService.isNeeded(context)) {\n            Log.d(TAG, \"Trigger ${CleanupService::class.java}\")\n            serviceContext.startService(Intent(context, CleanupService::class.java))\n        }\n        if (NotifyService.isNeeded(context)) {\n            Log.d(TAG, \"Trigger ${NotifyService::class.java}\")\n            serviceContext.startService(Intent(context, NotifyService::class.java))\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-nearby/core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ui/DotChartPreference.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.nearby.exposurenotification.ui\n\nimport android.content.Context\nimport android.util.AttributeSet\nimport androidx.preference.Preference\nimport androidx.preference.PreferenceViewHolder\nimport org.microg.gms.nearby.core.R\nimport org.microg.gms.nearby.exposurenotification.ExposureScanSummary\n\nclass DotChartPreference : Preference {\n    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)\n    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)\n    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)\n    constructor(context: Context) : super(context)\n\n    init {\n        layoutResource = R.layout.preference_dot_chart\n    }\n\n    private lateinit var chart: DotChartView\n    var data: Set<ExposureScanSummary> = emptySet()\n        set(value) {\n            field = value\n            if (this::chart.isInitialized) {\n                chart.data = data\n            }\n        }\n\n    override fun onBindViewHolder(holder: PreferenceViewHolder) {\n        super.onBindViewHolder(holder)\n        chart = holder.itemView as? DotChartView ?: holder.findViewById(R.id.dot_chart) as DotChartView\n        chart.data = data\n    }\n\n}\n"
  },
  {
    "path": "play-services-nearby/core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ui/DotChartView.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.nearby.exposurenotification.ui\n\nimport android.annotation.SuppressLint\nimport android.annotation.TargetApi\nimport android.content.Context\nimport android.graphics.*\nimport android.os.Build.VERSION.SDK_INT\nimport android.text.format.DateFormat\nimport android.text.format.DateUtils\nimport android.util.AttributeSet\nimport android.view.MotionEvent\nimport android.view.View\nimport org.microg.gms.nearby.exposurenotification.ExposureScanSummary\nimport org.microg.gms.nearby.core.R\nimport org.microg.gms.ui.resolveColor\nimport java.text.SimpleDateFormat\nimport java.util.*\nimport kotlin.math.max\nimport kotlin.math.min\n\n\nclass DotChartView : View {\n    @TargetApi(21)\n    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)\n    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)\n    constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)\n    constructor(context: Context?) : super(context)\n\n    var data: Set<ExposureScanSummary>? = null\n        @SuppressLint(\"SimpleDateFormat\")\n        set(value) {\n            field = value\n            val displayData = hashMapOf<Int, Pair<String, MutableMap<Int, Int>>>()\n            val now = System.currentTimeMillis()\n            val min = now - 14 * 24 * 60 * 60 * 1000L\n            val date = Date(min)\n            val dateFormat = DateFormat.getMediumDateFormat(context)\n            val hourFormat = SimpleDateFormat(\"H\")\n            val lowest = dateFormat.parse(dateFormat.format(date))?.time ?: date.time\n            fun formatDateForView(date: Date) = DateUtils.formatDateTime(context, date.time, DateUtils.FORMAT_ABBREV_MONTH or DateUtils.FORMAT_NO_YEAR)\n            for (day in 0 until 15) {\n                date.time = now - (14 - day) * 24 * 60 * 60 * 1000L\n                displayData[day] = formatDateForView(date) to hashMapOf()\n            }\n            fun dayByDate(date: Date) : Int? {\n                val dateString = formatDateForView(date)\n                return displayData.entries.firstOrNull { it.value.first == dateString }?.key\n            }\n            if (value != null) {\n                for (summary in value) {\n                    val off = summary.time - lowest\n                    if (off < 0) continue\n                    val totalHours = (off / 1000 / 60 / 60).toInt()\n                    date.time = summary.time\n                    val day = dayByDate(date) ?: (totalHours / 24)\n                    val hour = hourFormat.format(date).toIntOrNull() ?: (totalHours % 24)\n                    displayData[day]?.second?.set(hour, (displayData[day]?.second?.get(hour) ?: 0) + summary.rpis)\n                }\n            }\n            for (hour in 0..((min - lowest) / 1000 / 60 / 60).toInt()) {\n                displayData[0]?.second?.set(hour, displayData[0]?.second?.get(hour) ?: -1)\n            }\n            for (hour in ((min - lowest) / 1000 / 60 / 60).toInt() until 24) {\n                displayData[14]?.second?.set(hour, displayData[14]?.second?.get(hour) ?: -1)\n            }\n            this.displayData = displayData\n            this.displayDataList = displayData.values.map { it.second.values }.flatten().sorted()\n            invalidate()\n        }\n\n    private var displayData: Map<Int, Pair<String, Map<Int, Int>>> = emptyMap()\n    private var displayDataList: List<Int> = emptyList()\n    private val drawPaint = Paint()\n    private val drawTempRect = RectF()\n    private val fontPaint = Paint()\n    private val fontTempRect = Rect()\n\n    fun Canvas.drawMyRect(x: Float, y: Float, width: Float, height: Float, color: Int) {\n        drawTempRect.set(x + drawPaint.strokeWidth, y + drawPaint.strokeWidth, x + width - drawPaint.strokeWidth, y + height - drawPaint.strokeWidth)\n        if (Color.alpha(color) >= 80) {\n            drawPaint.style = Paint.Style.FILL_AND_STROKE\n            drawPaint.color = color\n            drawRoundRect(drawTempRect, 2f, 2f, drawPaint)\n            drawPaint.style = Paint.Style.FILL\n        } else {\n            drawPaint.color = color or (80 shl 24) and (80 shl 24 or 0xffffff)\n            drawPaint.style = Paint.Style.STROKE\n            drawRoundRect(drawTempRect, 2f, 2f, drawPaint)\n            drawPaint.style = Paint.Style.FILL\n            drawPaint.color = color\n            drawRoundRect(drawTempRect, 2f, 2f, drawPaint)\n        }\n    }\n\n    private fun <T> List<T>.relativePosition(element: T): Double? = indexOf(element).takeIf { it >= 0 }?.toDouble()?.let { it / size.toDouble() }\n\n    private var focusPoint: PointF? = null\n    override fun onDraw(canvas: Canvas) {\n        if (data == null) data = emptySet()\n        val d = resources.displayMetrics.scaledDensity\n        fontPaint.textSize = 10 * d\n        fontPaint.isAntiAlias = true\n        drawPaint.isAntiAlias = true\n        drawPaint.strokeWidth = 2f\n        val innerPadding = 2 * d\n        var maxTextWidth = 0\n        var maxTextHeight = 0\n        for (dateString in displayData.values.map { it.first }) {\n            fontPaint.getTextBounds(dateString, 0, dateString.length, fontTempRect)\n            maxTextWidth = max(maxTextWidth, fontTempRect.width())\n            maxTextHeight = max(maxTextHeight, fontTempRect.height())\n        }\n\n        val legendLeft = max(56 * d, maxTextWidth + 8 * d)\n        val legendBottom = maxTextHeight + 8 * d\n        val subHeight = maxTextHeight + 4 * d + paddingBottom\n\n        val distHeight = (height - innerPadding * 14 - paddingTop - paddingBottom - legendBottom - subHeight).toDouble()\n        val distWidth = (width - innerPadding * 23 - paddingLeft - paddingRight - legendLeft).toDouble()\n        val perHeight = distHeight / 15.0\n        val perWidth = distWidth / 24.0\n\n        val maxValue = displayDataList.last()\n        val accentColor = context.resolveColor(androidx.appcompat.R.attr.colorAccent) ?: 0\n        val fontColor = context.resolveColor(android.R.attr.textColorSecondary) ?: 0\n        val grayBoxColor = fontColor or (255 shl 24) and (80 shl 24 or 0xffffff)\n        fontPaint.textAlign = Paint.Align.RIGHT\n        fontPaint.color = fontColor\n        var focusDay = -1\n        var focusHour = -1\n        for (day in 0 until 15) {\n            val (dateString, hours) = displayData[day] ?: \"\" to emptyMap()\n            val top = day * (perHeight + innerPadding) + paddingTop\n            if (day % 2 == 0) {\n                canvas.drawText(dateString, (paddingLeft + legendLeft - 8 * d), (top + perHeight / 2.0 + maxTextHeight / 2.0).toFloat(), fontPaint)\n            }\n            focusPoint?.let { if (it.y > top && it.y < top + perHeight) focusDay = day }\n            for (hour in 0 until 24) {\n                val value = hours[hour]\n                val left = hour * (perWidth + innerPadding) + paddingLeft + legendLeft\n                when {\n                    value == null -> {\n                        canvas.drawMyRect(left.toFloat(), top.toFloat(), perWidth.toFloat(), perHeight.toFloat(), grayBoxColor)\n                    }\n                    maxValue == 0 -> {\n                        canvas.drawMyRect(left.toFloat(), top.toFloat(), perWidth.toFloat(), perHeight.toFloat(), accentColor and 0xffffff)\n                    }\n                    value >= 0 -> {\n                        val byBucket = ((displayDataList.relativePosition(value) ?: 0.0) * 180.0).toInt()\n                        val byMax = (value.toDouble() / maxValue.toDouble() * 80.0).toInt()\n                        val alpha = max(0, min(byBucket + byMax, 255))\n                        canvas.drawMyRect(left.toFloat(), top.toFloat(), perWidth.toFloat(), perHeight.toFloat(), accentColor and (alpha shl 24 or 0xffffff))\n                    }\n                }\n                if (focusDay == day && (value == null || value >= 0)) focusPoint?.let {\n                    if (it.x > left && it.x < left + perWidth) {\n                        focusHour = hour\n                        canvas.drawMyRect(left.toFloat(), top.toFloat(), perWidth.toFloat(), perHeight.toFloat(), accentColor and 0xffffff)\n                    }\n                }\n            }\n        }\n        val legendTop = 15 * (perHeight + innerPadding) + paddingTop + maxTextHeight + 8 * d\n        fontPaint.textAlign = Paint.Align.CENTER\n        for (hour in 0 until 24) {\n            if (hour % 3 == 0) {\n                val left = hour * (perWidth + innerPadding) + paddingLeft + legendLeft + perWidth / 2.0\n                canvas.drawText(\"${hour}:00\", left.toFloat(), legendTop.toFloat(), fontPaint)\n            }\n        }\n\n        val subTop = legendTop + paddingBottom\n        val subLeft = paddingLeft + legendLeft\n\n        canvas.drawMyRect(subLeft, subTop.toFloat(), perWidth.toFloat(), perHeight.toFloat(), grayBoxColor)\n\n        val strNoRecords = context.getString(R.string.pref_exposure_rpis_histogram_legend_no_records)\n        fontPaint.textAlign = Paint.Align.LEFT\n        fontPaint.getTextBounds(strNoRecords, 0, strNoRecords.length, fontTempRect)\n        canvas.drawText(strNoRecords, (subLeft + perWidth + 4 * d).toFloat(), (subTop + perHeight / 2.0 + fontTempRect.height() / 2.0).toFloat(), fontPaint)\n\n        if (maxValue >= 0) {\n            canvas.drawMyRect((subLeft + (perWidth + innerPadding) * 1 + 12 * d + fontTempRect.width()).toFloat(), subTop.toFloat(), perWidth.toFloat(), perHeight.toFloat(), accentColor and 0xffffff)\n            canvas.drawMyRect((subLeft + (perWidth + innerPadding) * 2 + 12 * d + fontTempRect.width()).toFloat(), subTop.toFloat(), perWidth.toFloat(), perHeight.toFloat(), accentColor and (80 shl 24 or 0xffffff))\n            canvas.drawMyRect((subLeft + (perWidth + innerPadding) * 3 + 12 * d + fontTempRect.width()).toFloat(), subTop.toFloat(), perWidth.toFloat(), perHeight.toFloat(), accentColor and (170 shl 24 or 0xffffff))\n            canvas.drawMyRect((subLeft + (perWidth + innerPadding) * 4 + 12 * d + fontTempRect.width()).toFloat(), subTop.toFloat(), perWidth.toFloat(), perHeight.toFloat(), accentColor)\n\n            val strRecords = context.getString(R.string.pref_exposure_rpis_histogram_legend_records, \"0 - $maxValue\")\n            canvas.drawText(strRecords, (subLeft + (perWidth + innerPadding) * 4 + 16 * d + fontTempRect.width() + perWidth).toFloat(), (subTop + perHeight / 2.0 + fontTempRect.height() / 2.0).toFloat(), fontPaint)\n        }\n\n        if (focusHour != -1 && SDK_INT >= 23) {\n            val floatingColor = context.resolveColor(androidx.appcompat.R.attr.colorBackgroundFloating) ?: 0\n            val line1 = \"${displayData[focusDay]?.first}, $focusHour:00\"\n            val line2 = displayData[focusDay]?.second?.get(focusHour)?.let { context.getString(R.string.pref_exposure_rpis_histogram_legend_records, it.toString()) }\n                    ?: strNoRecords\n            fontPaint.textSize = 14 * d\n            fontPaint.isFakeBoldText = true\n            fontPaint.getTextBounds(line1, 0, line1.length, fontTempRect)\n            var fontWidth = fontTempRect.width()\n            val line1Height = fontTempRect.height() + innerPadding\n            fontPaint.isFakeBoldText = false\n            fontPaint.getTextBounds(line2, 0, line2.length, fontTempRect)\n            fontWidth = max(fontWidth, fontTempRect.width())\n            val totalHeight = line1Height + innerPadding + fontTempRect.height()\n            drawPaint.color = floatingColor\n            drawPaint.style = Paint.Style.FILL_AND_STROKE\n            val refTop = focusDay * (perHeight + innerPadding) + paddingTop + perHeight / 2\n            val refLeft = focusHour * (perWidth + innerPadding) + paddingLeft + legendLeft\n            if (refLeft - fontWidth < 50 * d) {\n                // To the right\n                drawTempRect.set((refLeft + perWidth + innerPadding).toFloat(), (refTop - innerPadding - 5 * d - totalHeight / 2f).toFloat(), (refLeft + perWidth + innerPadding + 10 * d + fontWidth).toFloat(), (refTop + innerPadding + 5 * d + totalHeight / 2f).toFloat())\n            } else {\n                // To the left\n                drawTempRect.set((refLeft - innerPadding - 10 * d - fontWidth).toFloat(), (refTop - innerPadding - 5 * d - totalHeight / 2f).toFloat(), (refLeft - innerPadding).toFloat(), (refTop + innerPadding + 5 * d + totalHeight / 2f).toFloat())\n            }\n            canvas.drawRoundRect(drawTempRect, drawPaint.strokeWidth, drawPaint.strokeWidth, drawPaint)\n            val path = Path()\n            if (refLeft - fontWidth < 50 * d) {\n                // To the right\n                val off = refLeft + perWidth + innerPadding + drawPaint.strokeWidth\n                val corr = (perWidth / 2 - innerPadding + drawPaint.strokeWidth)\n                path.moveTo(off.toFloat(), (refTop - corr).toFloat())\n                path.lineTo((refLeft + perWidth / 2).toFloat(), refTop.toFloat())\n                path.lineTo(off.toFloat(), (refTop + corr).toFloat())\n            } else {\n                // To the left\n                val off = refLeft - innerPadding - drawPaint.strokeWidth\n                val corr = (perWidth / 2 - innerPadding + drawPaint.strokeWidth)\n                path.moveTo(off.toFloat(), (refTop - corr).toFloat())\n                path.lineTo((refLeft + perWidth / 2).toFloat(), refTop.toFloat())\n                path.lineTo(off.toFloat(), (refTop + corr).toFloat())\n            }\n            drawPaint.style = Paint.Style.STROKE\n            drawPaint.color = accentColor and (130 shl 24 or 0xffffff)\n            canvas.drawRoundRect(drawTempRect, drawPaint.strokeWidth, drawPaint.strokeWidth, drawPaint)\n\n            drawPaint.color = floatingColor\n            drawPaint.style = Paint.Style.FILL_AND_STROKE\n            path.fillType = Path.FillType.EVEN_ODD\n            canvas.drawPath(path, drawPaint)\n            drawPaint.style = Paint.Style.STROKE\n            drawPaint.color = accentColor and (130 shl 24 or 0xffffff)\n            path.fillType = Path.FillType.EVEN_ODD\n            canvas.drawPath(path, drawPaint)\n\n            canvas.drawText(line2, drawTempRect.left + 5 * d, drawTempRect.top + 5 * d + totalHeight, fontPaint)\n            fontPaint.isFakeBoldText = true\n            canvas.drawText(line1, drawTempRect.left + 5 * d, drawTempRect.top + 5 * d + line1Height, fontPaint)\n            fontPaint.isFakeBoldText = false\n        }\n    }\n\n    private val removeFocusPoint = Runnable { unfocus() }\n\n    fun unfocus() {\n        focusPoint = null\n        invalidate()\n    }\n\n    override fun onTouchEvent(event: MotionEvent): Boolean {\n        when (event.actionMasked) {\n            MotionEvent.ACTION_UP, MotionEvent.ACTION_POINTER_UP, MotionEvent.ACTION_CANCEL -> {\n                postDelayed(removeFocusPoint, POPUP_DELAY)\n                return true\n            }\n            MotionEvent.ACTION_DOWN, MotionEvent.ACTION_POINTER_DOWN, MotionEvent.ACTION_MOVE -> {\n                removeCallbacks(removeFocusPoint)\n                focusPoint = PointF(event.x, event.y)\n                invalidate()\n                return true\n            }\n        }\n        return false\n    }\n\n    companion object {\n        const val POPUP_DELAY = 3000L\n    }\n}\n"
  },
  {
    "path": "play-services-nearby/core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ui/ExposureNotificationsAppFragment.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.nearby.exposurenotification.ui\n\nimport android.content.Intent\nimport android.net.Uri\nimport android.os.Bundle\nimport android.provider.Settings\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport androidx.appcompat.content.res.AppCompatResources\nimport androidx.fragment.app.Fragment\nimport androidx.lifecycle.lifecycleScope\nimport org.microg.gms.nearby.core.databinding.ExposureNotificationsAppFragmentBinding\nimport org.microg.gms.nearby.core.R\nimport org.microg.gms.ui.getApplicationInfoIfExists\n\nclass ExposureNotificationsAppFragment : Fragment(R.layout.exposure_notifications_app_fragment) {\n    private lateinit var binding: ExposureNotificationsAppFragmentBinding\n    val packageName: String?\n        get() = arguments?.getString(\"package\")\n\n    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {\n        binding = ExposureNotificationsAppFragmentBinding.inflate(inflater, container, false)\n        binding.callbacks = object : ExposureNotificationsAppFragmentCallbacks {\n            override fun onAppClicked() {\n                val intent = Intent()\n                intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS\n                val uri: Uri = Uri.fromParts(\"package\", packageName, null)\n                intent.data = uri\n                context!!.startActivity(intent)\n            }\n        }\n        childFragmentManager.findFragmentById(R.id.sub_preferences)?.arguments = arguments\n        return binding.root\n    }\n\n    override fun onResume() {\n        super.onResume()\n        val context = requireContext()\n        lifecycleScope.launchWhenResumed {\n            val pm = context.packageManager\n            val applicationInfo = pm.getApplicationInfoIfExists(packageName)\n            binding.appName = applicationInfo?.loadLabel(pm)?.toString() ?: packageName\n            binding.appIcon = applicationInfo?.loadIcon(pm)\n                    ?: AppCompatResources.getDrawable(context, android.R.mipmap.sym_def_app_icon)\n        }\n    }\n}\n\ninterface ExposureNotificationsAppFragmentCallbacks {\n    fun onAppClicked()\n}\n"
  },
  {
    "path": "play-services-nearby/core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ui/ExposureNotificationsAppPreferencesFragment.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.nearby.exposurenotification.ui\n\nimport android.annotation.SuppressLint\nimport android.content.Intent\nimport android.os.Bundle\nimport android.text.format.DateUtils\nimport android.widget.TextView\nimport androidx.core.content.ContextCompat\nimport androidx.core.text.HtmlCompat\nimport androidx.lifecycle.lifecycleScope\nimport androidx.preference.Preference\nimport androidx.preference.PreferenceCategory\nimport androidx.preference.PreferenceFragmentCompat\nimport androidx.preference.PreferenceViewHolder\nimport com.google.android.gms.nearby.exposurenotification.ExposureConfiguration\nimport org.json.JSONObject\nimport org.microg.gms.nearby.core.R\nimport org.microg.gms.nearby.exposurenotification.ExposureDatabase\nimport org.microg.gms.nearby.exposurenotification.merge\n\nclass ExposureNotificationsAppPreferencesFragment : PreferenceFragmentCompat() {\n    private lateinit var open: Preference\n    private lateinit var reportedExposures: PreferenceCategory\n    private lateinit var reportedExposuresNone: Preference\n    private lateinit var reportedExposuresUpdated: Preference\n    private lateinit var apiUsage: Preference\n    private val packageName: String?\n        get() = arguments?.getString(\"package\")\n\n    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {\n        addPreferencesFromResource(R.xml.preferences_exposure_notifications_app)\n    }\n\n    @SuppressLint(\"RestrictedApi\")\n    override fun onBindPreferences() {\n        open = preferenceScreen.findPreference(\"pref_exposure_app_open\") ?: open\n        reportedExposures = preferenceScreen.findPreference(\"prefcat_exposure_app_report\") ?: reportedExposures\n        reportedExposuresNone = preferenceScreen.findPreference(\"pref_exposure_app_report_none\")\n                ?: reportedExposuresNone\n        reportedExposuresUpdated = preferenceScreen.findPreference(\"pref_exposure_app_report_updated\")\n                ?: reportedExposuresUpdated\n        apiUsage = preferenceScreen.findPreference(\"pref_exposure_app_api_usage\") ?: apiUsage\n        open.onPreferenceClickListener = Preference.OnPreferenceClickListener {\n            try {\n                packageName?.let {\n                    context?.packageManager?.getLaunchIntentForPackage(it)?.let { intent ->\n                        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)\n                        context?.startActivity(intent)\n                    }\n                }\n            } catch (ignored: Exception) {\n            }\n            true\n        }\n    }\n\n    override fun onResume() {\n        super.onResume()\n        updateContent()\n    }\n\n    private fun ExposureConfiguration?.orDefault() = this\n            ?: ExposureConfiguration.ExposureConfigurationBuilder().build()\n\n    private fun formatRelativeDateTimeString(time: Long): CharSequence? =\n            DateUtils.getRelativeDateTimeString(\n                    requireContext(),\n                    time,\n                    DateUtils.DAY_IN_MILLIS,\n                    DateUtils.DAY_IN_MILLIS * 2,\n                    0\n            )\n\n    fun updateContent() {\n        packageName?.let { packageName ->\n            lifecycleScope.launchWhenResumed {\n                data class NTuple4<T1, T2, T3, T4>(val t1: T1, val t2: T2, val t3: T3, val t4: T4)\n                val (mergedExposures, keysInvolved, lastCheckTime, methodUsageHistogram) = ExposureDatabase.with(requireContext()) { database ->\n                    val methodUsageHistogram = database.methodUsageHistogram(packageName)\n\n                    val token = database.lastMethodCallArgs(packageName, \"provideDiagnosisKeys\")?.let { JSONObject(it).getString(\"request_token\") }\n                            ?: return@with NTuple4(null, null, null, methodUsageHistogram)\n                    val lastCheckTime = database.lastMethodCall(packageName, \"provideDiagnosisKeys\")\n                            ?: return@with NTuple4(null, null, null, methodUsageHistogram)\n                    val config = database.loadConfiguration(packageName, token)\n                            ?: return@with NTuple4(null, null, null, methodUsageHistogram)\n                    val mergedExposures = database.findAllMeasuredExposures(config.first).merge().sortedBy { it.timestamp }\n                    val keysInvolved = database.countDiagnosisKeysInvolved(config.first)\n                    NTuple4(mergedExposures, keysInvolved, lastCheckTime, methodUsageHistogram)\n                }\n\n                reportedExposures.removeAll()\n                reportedExposures.addPreference(reportedExposuresNone)\n                if (mergedExposures.isNullOrEmpty()) {\n                    reportedExposuresNone.isVisible = true\n                } else {\n                    reportedExposuresNone.isVisible = false\n                    for (exposure in mergedExposures) {\n                        val minAttenuation = exposure.subs.map { it.attenuation }.minOrNull() ?: exposure.attenuation\n                        val nearby = exposure.attenuation < 63 || minAttenuation < 55\n                        val distanceString = if (nearby) getString(R.string.pref_exposure_app_report_entry_distance_close) else getString(R.string.pref_exposure_app_report_entry_distance_far)\n                        val durationString = if (exposure.durationInMinutes < 5) getString(R.string.pref_exposure_app_report_entry_time_short) else getString(R.string.pref_exposure_app_report_entry_time_about, exposure.durationInMinutes)\n                        val preference = object : Preference(requireContext()) {\n                            override fun onBindViewHolder(holder: PreferenceViewHolder) {\n                                val titleView = holder.findViewById(android.R.id.title) as? TextView\n                                val titleViewTextColor = titleView?.textColors\n                                super.onBindViewHolder(holder)\n                                if (titleViewTextColor != null) titleView.setTextColor(titleViewTextColor)\n                            }\n                        }\n                        preference.icon = ContextCompat.getDrawable(requireContext(), R.drawable.ic_alert)\n                        preference.title = DateUtils.formatDateRange(requireContext(), exposure.timestamp, exposure.timestamp + exposure.durationInMinutes * 60 * 1000L, DateUtils.FORMAT_SHOW_TIME or DateUtils.FORMAT_SHOW_DATE or DateUtils.FORMAT_SHOW_WEEKDAY or DateUtils.FORMAT_ABBREV_WEEKDAY)\n                        preference.summary = getString(R.string.pref_exposure_app_report_entry_combined, durationString, distanceString)\n                        preference.isSelectable = false\n                        reportedExposures.addPreference(preference)\n                    }\n                }\n\n                reportedExposuresUpdated.isVisible = lastCheckTime != null\n                reportedExposuresUpdated.title = if (lastCheckTime != null) getString(R.string.pref_exposure_app_report_updated_title, DateUtils.getRelativeDateTimeString(requireContext(), lastCheckTime, DateUtils.DAY_IN_MILLIS, DateUtils.DAY_IN_MILLIS * 2, 0)) else null\n                reportedExposuresUpdated.summary = getString(R.string.pref_exposure_app_last_report_summary_diagnosis_keys, keysInvolved?.toInt()\n                        ?: 0)\n                reportedExposures.addPreference(reportedExposuresUpdated)\n\n                val apiUsageSummary = methodUsageHistogram.map {\n                    getString(R.string.pref_exposure_app_api_usage_summary_line, it.second, it.first.let { \"<small><tt>$it</tt></small>\" })\n                }.joinToString(\"<br>\").takeIf { it.isNotEmpty() }\n                apiUsage.isVisible = apiUsageSummary != null\n                apiUsage.summary = HtmlCompat.fromHtml(apiUsageSummary.orEmpty(), HtmlCompat.FROM_HTML_MODE_COMPACT).trim()\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-nearby/core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ui/ExposureNotificationsConfirmActivity.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.nearby.exposurenotification.ui\n\nimport android.Manifest.permission.*\nimport android.annotation.SuppressLint\nimport android.bluetooth.BluetoothAdapter\nimport android.content.Context\nimport android.content.Intent\nimport android.content.pm.PackageInfo.REQUESTED_PERMISSION_NEVER_FOR_LOCATION\nimport android.content.pm.PackageManager\nimport android.content.pm.PackageManager.PERMISSION_GRANTED\nimport android.location.LocationManager\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.Bundle\nimport android.os.ResultReceiver\nimport android.provider.Settings\nimport android.view.View\nimport android.widget.Button\nimport android.widget.TextView\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.core.content.ContextCompat.checkSelfPermission\nimport androidx.core.location.LocationManagerCompat\nimport androidx.lifecycle.lifecycleScope\nimport org.microg.gms.nearby.core.R\nimport org.microg.gms.nearby.exposurenotification.*\nimport org.microg.gms.ui.getApplicationInfoIfExists\n\n\nclass ExposureNotificationsConfirmActivity : AppCompatActivity() {\n    private var resultCode: Int = RESULT_CANCELED\n        set(value) {\n            setResult(value)\n            field = value\n        }\n    private val receiver: ResultReceiver?\n        get() = intent.getParcelableExtra(KEY_CONFIRM_RECEIVER)\n    private val action: String?\n        get() = intent.getStringExtra(KEY_CONFIRM_ACTION)\n    private val targetPackageName: String?\n        get() = intent.getStringExtra(KEY_CONFIRM_PACKAGE)\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        setContentView(R.layout.exposure_notifications_confirm_activity)\n        val applicationInfo = packageManager.getApplicationInfoIfExists(targetPackageName)\n        val selfApplicationInfo = packageManager.getApplicationInfoIfExists(packageName)\n        when (action) {\n            CONFIRM_ACTION_START -> {\n                findViewById<TextView>(android.R.id.title).text = getString(R.string.exposure_confirm_start_title)\n                findViewById<TextView>(android.R.id.summary).text = getString(R.string.exposure_confirm_start_summary, applicationInfo?.loadLabel(packageManager)\n                        ?: targetPackageName)\n                findViewById<Button>(android.R.id.button1).text = getString(R.string.exposure_confirm_start_button)\n                findViewById<TextView>(R.id.grant_permission_summary).text = getString(R.string.exposure_confirm_permission_description, selfApplicationInfo?.loadLabel(packageManager)\n                        ?: packageName)\n                checkPermissions()\n                checkBluetooth()\n                checkLocation()\n            }\n            CONFIRM_ACTION_STOP -> {\n                findViewById<TextView>(android.R.id.title).text = getString(R.string.exposure_confirm_stop_title)\n                findViewById<TextView>(android.R.id.summary).text = getString(R.string.exposure_confirm_stop_summary)\n                findViewById<Button>(android.R.id.button1).text = getString(R.string.exposure_confirm_stop_button)\n            }\n            CONFIRM_ACTION_KEYS -> {\n                findViewById<TextView>(android.R.id.title).text = getString(R.string.exposure_confirm_keys_title, applicationInfo?.loadLabel(packageManager)\n                        ?: targetPackageName)\n                findViewById<TextView>(android.R.id.summary).text = getString(R.string.exposure_confirm_keys_summary)\n                findViewById<Button>(android.R.id.button1).text = getString(R.string.exposure_confirm_keys_button)\n            }\n            else -> {\n                resultCode = RESULT_CANCELED\n                finish()\n            }\n        }\n        findViewById<Button>(android.R.id.button1).setOnClickListener {\n            resultCode = RESULT_OK\n            finish()\n        }\n        findViewById<Button>(android.R.id.button2).setOnClickListener {\n            resultCode = RESULT_CANCELED\n            finish()\n        }\n        findViewById<Button>(R.id.grant_permission_button).setOnClickListener {\n            requestPermissions()\n        }\n        findViewById<Button>(R.id.grant_background_location_button).setOnClickListener {\n            requestBackgroundLocation()\n        }\n        findViewById<Button>(R.id.enable_bluetooth_button).setOnClickListener {\n            requestBluetooth()\n        }\n        findViewById<Button>(R.id.enable_location_button).setOnClickListener {\n            requestLocation()\n        }\n    }\n\n    override fun onResume() {\n        super.onResume()\n        if (permissionNeedsHandling) checkPermissions()\n        if (bluetoothNeedsHandling) checkBluetooth()\n        if (locationNeedsHandling) checkLocation()\n    }\n\n    private fun updateButton() {\n        findViewById<Button>(android.R.id.button1).isEnabled =\n            !permissionNeedsHandling && !backgroundLocationNeedsHandling && !bluetoothNeedsHandling && !locationNeedsHandling\n    }\n\n    // Permissions\n    private var permissionNeedsHandling: Boolean = false\n    private var backgroundLocationNeedsHandling: Boolean = false\n    private var permissionRequestCode = 33\n    private fun getRequiredPermissions(): Array<String> {\n        return when {\n            SDK_INT >= 31 -> {\n                // We only need bluetooth permission on 31+ if it's \"strongly asserted\" that we won't use bluetooth for\n                // location. Otherwise, we also need LOCATION permissions. See\n                // https://developer.android.com/guide/topics/connectivity/bluetooth/permissions#assert-never-for-location\n                try {\n                    val packageInfo = packageManager.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS)\n                    val bluetoothScanIndex = packageInfo.requestedPermissions!!.indexOf(BLUETOOTH_SCAN)\n                    if (packageInfo.requestedPermissionsFlags!![bluetoothScanIndex] and REQUESTED_PERMISSION_NEVER_FOR_LOCATION > 0) {\n                        return arrayOf(BLUETOOTH_ADVERTISE, BLUETOOTH_SCAN)\n                    }\n                } catch (e: Exception) {\n                    // Ignore\n                }\n                arrayOf(\n                    BLUETOOTH_ADVERTISE,\n                    BLUETOOTH_SCAN,\n                    ACCESS_COARSE_LOCATION,\n                    ACCESS_FINE_LOCATION\n                )\n            }\n            SDK_INT == 29 -> {\n                // We only can directly request background location permission on 29.\n                // We need it on 30 (and possibly later) as well, but it has to be requested in a two\n                // step process, see https://fosstodon.org/@utf8equalsX/104359649537615235\n                arrayOf(\n                    ACCESS_BACKGROUND_LOCATION,\n                    ACCESS_COARSE_LOCATION,\n                    ACCESS_FINE_LOCATION\n                )\n            }\n            else -> {\n                // Below 29 or equals 30\n                arrayOf(\n                    ACCESS_COARSE_LOCATION,\n                    ACCESS_FINE_LOCATION\n                )\n            }\n        }\n    }\n\n    private fun checkPermissions() {\n        val permissions = getRequiredPermissions()\n        permissionNeedsHandling = SDK_INT >= 23 && permissions.any {\n            checkSelfPermission(this, it) != PERMISSION_GRANTED\n        }\n\n        backgroundLocationNeedsHandling = SDK_INT >= 30\n                && ACCESS_FINE_LOCATION in permissions\n                && checkSelfPermission(this, ACCESS_FINE_LOCATION) == PERMISSION_GRANTED\n                && checkSelfPermission(this, ACCESS_BACKGROUND_LOCATION) != PERMISSION_GRANTED\n\n        findViewById<View>(R.id.grant_permission_view).visibility =\n            if (permissionNeedsHandling) View.VISIBLE else View.GONE\n        findViewById<View>(R.id.grant_background_location_view).visibility =\n            if (!permissionNeedsHandling && backgroundLocationNeedsHandling) View.VISIBLE else View.GONE\n        updateButton()\n    }\n\n    private fun requestPermissions() {\n        if (SDK_INT >= 23) {\n            requestPermissions(getRequiredPermissions(), ++permissionRequestCode)\n        }\n    }\n\n    private fun requestBackgroundLocation() {\n        if (SDK_INT >= 29) {\n            requestPermissions(arrayOf(ACCESS_BACKGROUND_LOCATION), ++permissionRequestCode)\n        }\n    }\n\n    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {\n        super.onRequestPermissionsResult(requestCode, permissions, grantResults)\n        if (requestCode == this.permissionRequestCode) checkPermissions()\n    }\n\n    // Bluetooth\n    private var bluetoothNeedsHandling: Boolean = false\n    private var bluetoothRequestCode = 112\n    private fun checkBluetooth() {\n        val adapter = BluetoothAdapter.getDefaultAdapter()\n        bluetoothNeedsHandling = adapter?.isEnabled != true\n        findViewById<View>(R.id.enable_bluetooth_view).visibility = if (adapter?.isEnabled == false) View.VISIBLE else View.GONE\n        updateButton()\n    }\n\n    private fun requestBluetooth() {\n        val adapter = BluetoothAdapter.getDefaultAdapter()\n        findViewById<View>(R.id.enable_bluetooth_spinner).visibility = View.VISIBLE\n        findViewById<View>(R.id.enable_bluetooth_button).visibility = View.INVISIBLE\n        lifecycleScope.launchWhenStarted {\n            if (adapter != null && !adapter.enableAsync(this@ExposureNotificationsConfirmActivity)) {\n                requestBluetoothViaIntent()\n            } else {\n                checkBluetooth()\n            }\n            findViewById<View>(R.id.enable_bluetooth_spinner).visibility = View.INVISIBLE\n            findViewById<View>(R.id.enable_bluetooth_button).visibility = View.VISIBLE\n        }\n    }\n\n    @SuppressLint(\"MissingPermission\")\n    private fun requestBluetoothViaIntent() {\n        val intent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)\n        try {\n            startActivityForResult(intent, ++bluetoothRequestCode)\n        } catch (e: Exception) {\n            // Ignored\n        }\n    }\n\n    // Location\n    private var locationNeedsHandling: Boolean = false\n    private var locationRequestCode = 231\n    private fun checkLocation() {\n        locationNeedsHandling = !LocationManagerCompat.isLocationEnabled(getSystemService(Context.LOCATION_SERVICE) as LocationManager)\n        findViewById<View>(R.id.enable_location_view).visibility = if (locationNeedsHandling) View.VISIBLE else View.GONE\n        updateButton()\n    }\n\n    private fun requestLocation() {\n        val intent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)\n        startActivityForResult(intent, ++locationRequestCode)\n    }\n\n    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {\n        super.onActivityResult(requestCode, resultCode, data)\n        if (requestCode == bluetoothRequestCode) checkBluetooth()\n    }\n\n    override fun finish() {\n        receiver?.send(resultCode, Bundle())\n        super.finish()\n    }\n}\n"
  },
  {
    "path": "play-services-nearby/core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ui/ExposureNotificationsFragment.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.nearby.exposurenotification.ui\n\nimport android.annotation.SuppressLint\nimport android.bluetooth.BluetoothAdapter\nimport android.content.Context.LOCATION_SERVICE\nimport android.content.Intent\nimport android.content.pm.PackageManager\nimport android.location.LocationManager\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.Bundle\nimport android.os.Handler\nimport android.provider.Settings\nimport androidx.core.content.ContextCompat\nimport androidx.core.location.LocationManagerCompat\nimport androidx.core.os.bundleOf\nimport androidx.lifecycle.lifecycleScope\nimport androidx.navigation.fragment.findNavController\nimport androidx.preference.Preference\nimport androidx.preference.PreferenceCategory\nimport androidx.preference.PreferenceFragmentCompat\nimport org.microg.gms.nearby.core.R\nimport org.microg.gms.nearby.exposurenotification.*\nimport org.microg.gms.ui.AppIconPreference\nimport org.microg.gms.ui.SwitchBarPreference\nimport org.microg.gms.ui.getApplicationInfoIfExists\nimport org.microg.gms.ui.navigate\n\n\nclass ExposureNotificationsFragment : PreferenceFragmentCompat() {\n    private lateinit var switchBarPreference: SwitchBarPreference\n    private lateinit var exposureEnableInfo: Preference\n    private lateinit var exposureBluetoothOff: Preference\n    private lateinit var exposureLocationOff: Preference\n    private lateinit var exposureNearbyNotGranted: Preference\n    private lateinit var exposureBluetoothUnsupported: Preference\n    private lateinit var exposureBluetoothNoAdvertisement: Preference\n    private lateinit var exposureApps: PreferenceCategory\n    private lateinit var exposureAppsNone: Preference\n    private lateinit var collectedRpis: Preference\n    private lateinit var advertisingId: Preference\n    private var turningBluetoothOn: Boolean = false\n    private val handler = Handler()\n    private val updateStatusRunnable = Runnable { updateStatus() }\n    private val updateContentRunnable = Runnable { updateContent() }\n    private var permissionRequestCode = 33\n\n    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {\n        addPreferencesFromResource(R.xml.preferences_exposure_notifications)\n    }\n\n    @SuppressLint(\"RestrictedApi\")\n    override fun onBindPreferences() {\n        switchBarPreference = preferenceScreen.findPreference(\"pref_exposure_enabled\") ?: switchBarPreference\n        exposureEnableInfo = preferenceScreen.findPreference(\"pref_exposure_enable_info\") ?: exposureEnableInfo\n        exposureBluetoothOff = preferenceScreen.findPreference(\"pref_exposure_error_bluetooth_off\") ?: exposureBluetoothOff\n        exposureLocationOff = preferenceScreen.findPreference(\"pref_exposure_error_location_off\") ?: exposureLocationOff\n        exposureNearbyNotGranted = preferenceScreen.findPreference(\"pref_exposure_error_nearby_not_granted\") ?: exposureNearbyNotGranted\n        exposureBluetoothUnsupported = preferenceScreen.findPreference(\"pref_exposure_error_bluetooth_unsupported\") ?: exposureBluetoothUnsupported\n        exposureBluetoothNoAdvertisement = preferenceScreen.findPreference(\"pref_exposure_error_bluetooth_no_advertise\") ?: exposureBluetoothNoAdvertisement\n        exposureApps = preferenceScreen.findPreference(\"prefcat_exposure_apps\") ?: exposureApps\n        exposureAppsNone = preferenceScreen.findPreference(\"pref_exposure_apps_none\") ?: exposureAppsNone\n        collectedRpis = preferenceScreen.findPreference(\"pref_exposure_collected_rpis\") ?: collectedRpis\n        advertisingId = preferenceScreen.findPreference(\"pref_exposure_advertising_id\") ?: advertisingId\n\n        switchBarPreference.setOnPreferenceChangeListener { _, newValue ->\n            val newStatus = newValue as Boolean\n            ExposurePreferences(requireContext()).enabled = newStatus\n            true\n        }\n\n        exposureLocationOff.onPreferenceClickListener = Preference.OnPreferenceClickListener {\n            val intent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)\n            startActivity(intent)\n            true\n        }\n\n        exposureBluetoothOff.onPreferenceClickListener = Preference.OnPreferenceClickListener {\n            lifecycleScope.launchWhenStarted {\n                turningBluetoothOn = true\n                it.isVisible = false\n                val adapter = BluetoothAdapter.getDefaultAdapter()\n                if (adapter != null && !adapter.enableAsync(requireContext())) {\n                    turningBluetoothOn = false\n                    val intent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)\n                    startActivityForResult(intent, 144)\n                } else {\n                    turningBluetoothOn = false\n                    updateStatus()\n                }\n            }\n            true\n        }\n\n        exposureNearbyNotGranted.onPreferenceClickListener = Preference.OnPreferenceClickListener {\n            val nearbyPermissions = arrayOf(\"android.permission.BLUETOOTH_ADVERTISE\", \"android.permission.BLUETOOTH_SCAN\")\n            requestPermissions(nearbyPermissions, ++permissionRequestCode)\n            true\n        }\n\n        collectedRpis.onPreferenceClickListener = Preference.OnPreferenceClickListener {\n            findNavController().navigate(requireContext(), R.id.openExposureRpis)\n            true\n        }\n    }\n\n    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {\n        super.onRequestPermissionsResult(requestCode, permissions, grantResults)\n        if (requestCode == this.permissionRequestCode) {\n            updateStatus()\n            // Tell the NotifyService that it should update the notification\n            val intent = Intent(NOTIFICATION_UPDATE_ACTION)\n            requireContext().sendBroadcast(intent)\n        }\n    }\n\n    override fun onResume() {\n        super.onResume()\n\n        updateStatus()\n        updateContent()\n    }\n\n    override fun onPause() {\n        super.onPause()\n\n        handler.removeCallbacks(updateStatusRunnable)\n        handler.removeCallbacks(updateContentRunnable)\n    }\n\n    private fun updateStatus() {\n        val appContext = requireContext().applicationContext\n        lifecycleScope.launchWhenResumed {\n            handler.postDelayed(updateStatusRunnable, UPDATE_STATUS_INTERVAL)\n            val enabled = getExposureNotificationsServiceInfo(appContext).configuration.enabled\n            exposureEnableInfo.isVisible = !enabled\n\n            val bluetoothSupported = ScannerService.isSupported(appContext)\n            val advertisingSupported = if (bluetoothSupported == true) AdvertiserService.isSupported(appContext) else bluetoothSupported\n\n            val nearbyPermissions = arrayOf(\"android.permission.BLUETOOTH_ADVERTISE\", \"android.permission.BLUETOOTH_SCAN\")\n            // Expresses implication (API 31+ → all new permissions granted) ≡ (¬API 31+ | all new permissions granted)\n            val nearbyPermissionsGranted = SDK_INT < 31 || nearbyPermissions.all {\n                ContextCompat.checkSelfPermission(appContext, it) == PackageManager.PERMISSION_GRANTED\n            }\n            exposureNearbyNotGranted.isVisible = enabled && !nearbyPermissionsGranted\n            exposureLocationOff.isVisible = enabled && bluetoothSupported != false && !LocationManagerCompat.isLocationEnabled(appContext.getSystemService(LOCATION_SERVICE) as LocationManager)\n            exposureBluetoothOff.isVisible = enabled && bluetoothSupported == null && !turningBluetoothOn\n            exposureBluetoothUnsupported.isVisible = enabled && bluetoothSupported == false\n            exposureBluetoothNoAdvertisement.isVisible = enabled && bluetoothSupported == true && advertisingSupported != true\n\n            advertisingId.isVisible = enabled && advertisingSupported == true\n        }\n    }\n\n    private fun updateContent() {\n        val context = requireContext()\n        lifecycleScope.launchWhenResumed {\n            handler.postDelayed(updateContentRunnable, UPDATE_CONTENT_INTERVAL)\n            val (apps, lastHourKeys, currentId) = ExposureDatabase.with(context) { database ->\n                val apps = database.appList.map { packageName ->\n                    context.packageManager.getApplicationInfoIfExists(packageName)\n                }.filterNotNull().mapIndexed { idx, applicationInfo ->\n                    val pref = AppIconPreference(context)\n                    pref.order = idx\n                    pref.applicationInfo = applicationInfo\n                    pref.onPreferenceClickListener = Preference.OnPreferenceClickListener {\n                        findNavController().navigate(requireContext(), R.id.openExposureAppDetails, bundleOf(\n                                \"package\" to applicationInfo.packageName\n                        ))\n                        true\n                    }\n                    pref.key = \"pref_exposure_app_\" + applicationInfo.packageName\n                    pref\n                }\n                val lastHourKeys = database.hourRpiCount\n                val currentId = database.currentRpiId\n                Triple(apps, lastHourKeys, currentId)\n            }\n            collectedRpis.summary = getString(R.string.pref_exposure_collected_rpis_summary, lastHourKeys)\n            if (currentId != null) {\n                advertisingId.isVisible = true\n                advertisingId.summary = currentId.toString()\n            } else {\n                advertisingId.isVisible = false\n            }\n            exposureApps.removeAll()\n            if (apps.isEmpty()) {\n                exposureApps.addPreference(exposureAppsNone)\n            } else {\n                for (app in apps) {\n                    exposureApps.addPreference(app)\n                }\n            }\n        }\n    }\n\n    companion object {\n        private const val UPDATE_STATUS_INTERVAL = 1000L\n        private const val UPDATE_CONTENT_INTERVAL = 60000L\n    }\n}\n"
  },
  {
    "path": "play-services-nearby/core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ui/ExposureNotificationsRpisFragment.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.nearby.exposurenotification.ui\n\nimport android.annotation.SuppressLint\nimport android.annotation.TargetApi\nimport android.os.Bundle\nimport android.view.LayoutInflater\nimport android.view.ViewGroup\nimport androidx.appcompat.app.AlertDialog\nimport androidx.lifecycle.lifecycleScope\nimport androidx.preference.Preference\nimport androidx.preference.PreferenceCategory\nimport androidx.preference.PreferenceFragmentCompat\nimport androidx.recyclerview.widget.RecyclerView\nimport org.microg.gms.nearby.core.R\nimport org.microg.gms.nearby.exposurenotification.ExposureDatabase\nimport org.microg.gms.ui.buildAlertDialog\n\n@TargetApi(21)\nclass ExposureNotificationsRpisFragment : PreferenceFragmentCompat() {\n    private lateinit var histogramCategory: PreferenceCategory\n    private lateinit var histogram: DotChartPreference\n    private lateinit var deleteAll: Preference\n    private lateinit var exportDb: Preference\n\n    override fun onCreateRecyclerView(\n        inflater: LayoutInflater,\n        parent: ViewGroup,\n        savedInstanceState: Bundle?\n    ): RecyclerView {\n        return super.onCreateRecyclerView(inflater, parent, savedInstanceState).apply {\n            // Allow drawing under system navbar / status bar\n            fitsSystemWindows = true\n            clipToPadding = false\n        }\n    }\n\n    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {\n        addPreferencesFromResource(R.xml.preferences_exposure_notifications_rpis)\n    }\n\n    @SuppressLint(\"RestrictedApi\")\n    override fun onBindPreferences() {\n        histogramCategory = preferenceScreen.findPreference(\"prefcat_exposure_rpi_histogram\") ?: histogramCategory\n        histogram = preferenceScreen.findPreference(\"pref_exposure_rpi_histogram\") ?: histogram\n        deleteAll = preferenceScreen.findPreference(\"pref_exposure_rpi_delete_all\") ?: deleteAll\n        exportDb = preferenceScreen.findPreference(\"pref_exposure_export_database\") ?: exportDb\n        deleteAll.onPreferenceClickListener = Preference.OnPreferenceClickListener {\n            requireContext().buildAlertDialog()\n                    .setTitle(R.string.pref_exposure_rpi_delete_all_title)\n                    .setView(R.layout.exposure_notifications_confirm_delete)\n                    .setPositiveButton(R.string.pref_exposure_rpi_delete_all_warning_confirm_button) { _, _ ->\n                        lifecycleScope.launchWhenStarted {\n                            ExposureDatabase.with(requireContext()) { it.deleteAllCollectedAdvertisements() }\n                            updateChart()\n                        }\n                    }\n                    .setNegativeButton(android.R.string.cancel) { _, _ -> }\n                    .create()\n                    .show()\n            true\n        }\n        exportDb.onPreferenceClickListener = Preference.OnPreferenceClickListener {\n            ExposureDatabase.export(requireContext())\n            true\n        }\n    }\n\n    override fun onResume() {\n        super.onResume()\n        updateChart()\n    }\n\n    fun updateChart() {\n        val appContext = requireContext().applicationContext\n        lifecycleScope.launchWhenResumed {\n            val rpiHourHistogram = ExposureDatabase.with(appContext) { database -> database.rpiHourHistogram }\n            val totalRpiCount = rpiHourHistogram.map { it.rpis }.sum()\n            deleteAll.isEnabled = totalRpiCount > 0\n            histogramCategory.title = getString(R.string.prefcat_exposure_rpis_histogram_title, totalRpiCount)\n            histogram.data = rpiHourHistogram\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-nearby/core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ui/ExposureNotificationsSettingsActivity.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage org.microg.gms.nearby.exposurenotification.ui\n\nimport android.os.Bundle\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.navigation.NavController\nimport androidx.navigation.fragment.NavHostFragment\nimport androidx.navigation.ui.AppBarConfiguration\nimport androidx.navigation.ui.NavigationUI\nimport org.microg.gms.nearby.core.R\n\nclass ExposureNotificationsSettingsActivity : AppCompatActivity() {\n    private var appBarConfiguration: AppBarConfiguration? = null\n\n    private val navController: NavController\n        get() = (supportFragmentManager.findFragmentById(R.id.navhost) as NavHostFragment?)!!.navController\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        setContentView(R.layout.exposure_notifications_settings_activity)\n        appBarConfiguration = AppBarConfiguration.Builder(navController.graph).build()\n        NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration!!)\n    }\n\n    override fun onSupportNavigateUp(): Boolean {\n        return NavigationUI.navigateUp(navController, appBarConfiguration!!) || super.onSupportNavigateUp()\n    }\n}\n"
  },
  {
    "path": "play-services-nearby/core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ui/Utils.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.nearby.exposurenotification.ui\n\nimport android.view.View\nimport androidx.annotation.AttrRes\nimport androidx.databinding.BindingAdapter\nimport org.microg.gms.ui.resolveColor\n\n@BindingAdapter(\"app:backgroundColorAttr\")\nfun View.setBackgroundColorAttribute(@AttrRes resId: Int) = context.resolveColor(resId)?.let { setBackgroundColor(it) }\n"
  },
  {
    "path": "play-services-nearby/core/src/main/proto/TemporaryExposureKeyFile.proto",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, Google\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are derived from work created and shared by Google and used\n *         according to the terms described in the Apache License, Version 2.0.\n *         See https://developers.google.com/android/exposure-notifications/exposure-key-file-format\n */\n\nsyntax = \"proto2\";\npackage org.microg.gms.nearby.exposurenotification.proto;\n\nmessage TemporaryExposureKeyExport {\n  // Time window of keys in this batch based on arrival to server, in UTC seconds.\n  optional fixed64 start_timestamp = 1;\n  optional fixed64 end_timestamp = 2;\n  // Region for which these keys came from, such as country.\n  optional string region = 3;\n  // For example, file 2 in batch size of 10. Ordinal, 1-based numbering.\n  // Note: Not yet supported on iOS.\n  optional int32 batch_num = 4;\n  optional int32 batch_size = 5;\n  // Information about associated signatures\n  repeated SignatureInfo signature_infos = 6;\n  // The TemporaryExposureKeys for initial release of keys.\n  // Keys should be included in this list for initial release,\n  // whereas revised or revoked keys should go in revised_keys.\n  repeated TemporaryExposureKeyProto keys = 7;\n  // TemporaryExposureKeys that have changed status.\n  // Keys should be included in this list if they have changed status\n  // or have been revoked.\n  repeated TemporaryExposureKeyProto revised_keys = 8;\n}\n\nmessage SignatureInfo {\n  // The first two fields have been deprecated\n  reserved 1, 2;\n  reserved \"app_bundle_id\", \"android_package\";\n  // Key version for rollovers\n  // Must be in character class [a-zA-Z0-9_]. For example, 'v1'\n  optional string verification_key_version = 3;\n  // Alias with which to identify public key to be used for verification\n  // Must be in character class [a-zA-Z0-9_.]\n  // For cross-compatibility with Apple, you can use your region's three-digit\n  // mobile country code (MCC). If your region has more than one MCC, choose the\n  // one that Apple has configured.\n  optional string verification_key_id = 4;\n  // ASN.1 OID for Algorithm Identifier. For example, `1.2.840.10045.4.3.2'\n  optional string signature_algorithm = 5;\n}\n\nmessage TemporaryExposureKeyProto {\n  // Key of infected user\n  optional bytes key_data = 1;\n  // Varying risk associated with a key depending on diagnosis method\n  optional int32 transmission_risk_level = 2 [deprecated = true];\n  // The interval number since epoch for which a key starts\n  optional int32 rolling_start_interval_number = 3;\n  // Increments of 10 minutes describing how long a key is valid\n  optional int32 rolling_period = 4\n  [default = 144]; // defaults to 24 hours\n  // Data type representing why this key was published.\n  enum ReportType {\n    UNKNOWN = 0;  // Never returned by the client API.\n    CONFIRMED_TEST = 1;\n    CONFIRMED_CLINICAL_DIAGNOSIS = 2;\n    SELF_REPORT = 3;\n    RECURSIVE = 4;  // Reserved for future use.\n    REVOKED = 5;  // Used to revoke a key, never returned by client API.\n  }\n\n  // Type of diagnosis associated with a key.\n  optional ReportType report_type = 5;\n\n  // Number of days elapsed between symptom onset and the TEK being used.\n  // E.g. 2 means TEK is 2 days after onset of symptoms.\n  optional sint32 days_since_onset_of_symptoms = 6;\n}\n\nmessage TEKSignatureList {\n  repeated TEKSignature signatures = 1;\n}\n\nmessage TEKSignature {\n  // Info about the signing key, version, algorithm, etc. Only the\n  // verification_key_id, verification_key_version, and\n  // signature_algorithm fields within signature_info are read.\n  optional SignatureInfo signature_info = 1;\n  // E.g., Batch 2 of 10 - these fields are ignored on android in favor of the\n  // batch fields within TemporaryExposureKeyExport\n  optional int32 batch_num = 2;\n  optional int32 batch_size = 3;\n  // Signature in X9.62 format (ASN.1 SEQUENCE of two INTEGER fields)\n  optional bytes signature = 4;\n}\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/drawable/ic_alert.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2019, The Android Open Source Project\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:tint=\"?attr/colorAccent\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n    <path\n        android:fillColor=\"#000\"\n        android:pathData=\"M11,15H13V17H11V15M11,7H13V13H11V7M12,2C6.47,2 2,6.5 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M12,20A8,8 0 0,1 4,12A8,8 0 0,1 12,4A8,8 0 0,1 20,12A8,8 0 0,1 12,20Z\" />\n</vector>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/drawable/ic_bluetooth_off.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2019, The Android Open Source Project\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:tint=\"?attr/colorAccent\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n    <path\n        android:fillColor=\"#000\"\n        android:pathData=\"M13,5.83L14.88,7.71L13.28,9.31L14.69,10.72L17.71,7.7L12,2H11V7.03L13,9.03M5.41,4L4,5.41L10.59,12L5,17.59L6.41,19L11,14.41V22H12L16.29,17.71L18.59,20L20,18.59M13,18.17V14.41L14.88,16.29\" />\n</vector>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/drawable/ic_location_off.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2019, Austin Andrews\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:tint=\"?attr/colorAccent\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n    <path\n        android:fillColor=\"#000\"\n        android:pathData=\"M16.37,16.1L11.75,11.47L11.64,11.36L3.27,3L2,4.27L5.18,7.45C5.06,7.95 5,8.46 5,9C5,14.25 12,22 12,22C12,22 13.67,20.15 15.37,17.65L18.73,21L20,19.72M12,6.5A2.5,2.5 0 0,1 14.5,9C14.5,9.73 14.17,10.39 13.67,10.85L17.3,14.5C18.28,12.62 19,10.68 19,9A7,7 0 0,0 12,2C10,2 8.24,2.82 6.96,4.14L10.15,7.33C10.61,6.82 11.26,6.5 12,6.5Z\" />\n</vector>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/drawable/ic_outline_location_on.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/colorAccent\">\n  <path\n      android:fillColor=\"#000\"\n      android:pathData=\"M12,2C8.13,2 5,5.13 5,9c0,5.25 7,13 7,13s7,-7.75 7,-13c0,-3.87 -3.13,-7 -7,-7zM7,9c0,-2.76 2.24,-5 5,-5s5,2.24 5,5c0,2.88 -2.88,7.19 -5,9.88C9.92,16.21 7,11.85 7,9z\"/>\n  <path\n      android:fillColor=\"#000\"\n      android:pathData=\"M12,9m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0\"/>\n</vector>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/drawable/ic_virus_outline.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, Michael Irigoyen\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:tint=\"?attr/colorAccent\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n    <path\n        android:fillColor=\"#000\"\n        android:pathData=\"M12 0.5C11.03 0.5 10.25 1.28 10.25 2.25C10.25 2.84 10.55 3.37 11 3.68V5.08C10.1 5.21 9.26 5.5 8.5 5.94L7.39 4.35C7.58 3.83 7.53 3.23 7.19 2.75C6.84 2.26 6.3 2 5.75 2C5.4 2 5.05 2.1 4.75 2.32C3.96 2.87 3.76 3.96 4.32 4.75C4.66 5.24 5.2 5.5 5.75 5.5L6.93 7.18C6.5 7.61 6.16 8.09 5.87 8.62C5.67 8.54 5.46 8.5 5.25 8.5C4.8 8.5 4.35 8.67 4 9C3.33 9.7 3.33 10.8 4 11.5C4.29 11.77 4.64 11.92 5 12L5 12C5 12.54 5.07 13.06 5.18 13.56L3.87 13.91C3.56 13.65 3.16 13.5 2.75 13.5C2.6 13.5 2.44 13.5 2.29 13.56C1.36 13.81 0.809 14.77 1.06 15.71C1.27 16.5 2 17 2.75 17C2.9 17 3.05 17 3.21 16.94C3.78 16.78 4.21 16.36 4.39 15.84L5.9 15.43C6.35 16.22 6.95 16.92 7.65 17.5L6.55 19.5C6 19.58 5.5 19.89 5.21 20.42C4.75 21.27 5.07 22.33 5.92 22.79C6.18 22.93 6.47 23 6.75 23C7.37 23 7.97 22.67 8.29 22.08C8.57 21.56 8.56 20.96 8.31 20.47L9.38 18.5C10.19 18.82 11.07 19 12 19C12.06 19 12.12 19 12.18 19C12.05 19.26 12 19.56 12 19.88C12.08 20.8 12.84 21.5 13.75 21.5C13.79 21.5 13.84 21.5 13.88 21.5C14.85 21.42 15.57 20.58 15.5 19.62C15.46 19.12 15.21 18.68 14.85 18.39C15.32 18.18 15.77 17.91 16.19 17.6L18.53 19.94C18.43 20.5 18.59 21.07 19 21.5C19.35 21.83 19.8 22 20.25 22S21.15 21.83 21.5 21.5C22.17 20.8 22.17 19.7 21.5 19C21.15 18.67 20.7 18.5 20.25 18.5C20.15 18.5 20.05 18.5 19.94 18.53L17.6 16.19C18.09 15.54 18.47 14.8 18.71 14H19.82C20.13 14.45 20.66 14.75 21.25 14.75C22.22 14.75 23 13.97 23 13S22.22 11.25 21.25 11.25C20.66 11.25 20.13 11.55 19.82 12H19C19 10.43 18.5 9 17.6 7.81L18.94 6.47C19.05 6.5 19.15 6.5 19.25 6.5C19.7 6.5 20.15 6.33 20.5 6C21.17 5.31 21.17 4.2 20.5 3.5C20.15 3.17 19.7 3 19.25 3S18.35 3.17 18 3.5C17.59 3.93 17.43 4.5 17.53 5.06L16.19 6.4C15.27 5.71 14.19 5.25 13 5.08V3.68C13.45 3.37 13.75 2.84 13.75 2.25C13.75 1.28 12.97 0.5 12 0.5M12 17C9.24 17 7 14.76 7 12S9.24 7 12 7 17 9.24 17 12 14.76 17 12 17M10.5 9C9.67 9 9 9.67 9 10.5S9.67 12 10.5 12 12 11.33 12 10.5 11.33 9 10.5 9M14 13C13.45 13 13 13.45 13 14C13 14.55 13.45 15 14 15C14.55 15 15 14.55 15 14C15 13.45 14.55 13 14 13Z\" />\n</vector>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/layout/exposure_notifications_app_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<layout 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    <data>\n\n        <variable\n            name=\"appName\"\n            type=\"String\" />\n\n        <variable\n            name=\"appIcon\"\n            type=\"android.graphics.drawable.Drawable\" />\n\n        <variable\n            name=\"callbacks\"\n            type=\"org.microg.gms.nearby.exposurenotification.ui.ExposureNotificationsAppFragmentCallbacks\" />\n    </data>\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\">\n\n        <RelativeLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:background=\"?attr/colorPrimary\"\n            android:paddingStart=\"?attr/listPreferredItemPaddingStart\"\n            android:paddingLeft=\"?attr/listPreferredItemPaddingLeft\"\n            android:paddingTop=\"24dp\"\n            android:paddingEnd=\"?attr/listPreferredItemPaddingEnd\"\n            android:paddingRight=\"?attr/listPreferredItemPaddingRight\"\n            android:paddingBottom=\"16dp\">\n\n            <LinearLayout\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_centerHorizontal=\"true\"\n                android:gravity=\"center_horizontal\"\n                android:onClick='@{() -> callbacks.onAppClicked()}'\n                android:orientation=\"vertical\">\n\n                <ImageView\n                    android:id=\"@+id/icon\"\n                    android:layout_width=\"48dp\"\n                    android:layout_height=\"48dp\"\n                    android:antialias=\"true\"\n                    android:scaleType=\"fitCenter\"\n                    android:src=\"@{appIcon}\"\n                    tools:src=\"@android:mipmap/sym_def_app_icon\" />\n\n                <TextView\n                    android:id=\"@+id/title\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginTop=\"8dp\"\n                    android:ellipsize=\"marquee\"\n                    android:gravity=\"center\"\n                    android:singleLine=\"false\"\n                    android:text='@{appName}'\n                    android:textAppearance=\"@style/TextAppearance.AppCompat.Subhead\"\n                    android:textColor=\"?android:attr/textColorPrimary\"\n                    android:textSize=\"20sp\"\n                    tools:text=\"@tools:sample/lorem\" />\n            </LinearLayout>\n        </RelativeLayout>\n\n        <androidx.fragment.app.FragmentContainerView\n            android:id=\"@+id/sub_preferences\"\n            android:name=\"org.microg.gms.nearby.exposurenotification.ui.ExposureNotificationsAppPreferencesFragment\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"0dp\"\n            android:layout_weight=\"1\"/>\n    </LinearLayout>\n</layout>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/layout/exposure_notifications_confirm_activity.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<LinearLayout 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:animateLayoutChanges=\"true\"\n    android:orientation=\"vertical\">\n\n    <TextView\n        android:id=\"@android:id/title\"\n        style=\"@style/TextAppearance.AppCompat.Medium\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:paddingLeft=\"16dp\"\n        android:paddingTop=\"24dp\"\n        android:paddingRight=\"16dp\"\n        android:paddingBottom=\"8dp\"\n        android:textColor=\"?android:attr/textColorPrimary\"\n        tools:text=\"@string/exposure_confirm_start_title\" />\n\n    <ScrollView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\">\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:animateLayoutChanges=\"true\"\n            android:orientation=\"vertical\">\n\n            <TextView\n                android:id=\"@android:id/summary\"\n                style=\"@style/TextAppearance.AppCompat.Small\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:padding=\"16dp\"\n                tools:text=\"Your phone needs to use Bluetooth to securely collect and share IDs with other phones that are nearby.\\n\\nCorona Warn can notify you if you were exposed to someone who reported to be diagnosed positive.\\n\\nThe date, duration, and signal strength associated with an exposure will be shared with the app.\" />\n\n            <RelativeLayout\n                android:id=\"@+id/grant_permission_view\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginBottom=\"8dp\"\n                android:background=\"?attr/colorAccent\"\n                android:clipToPadding=\"false\"\n                android:paddingLeft=\"16dp\"\n                android:paddingTop=\"16dp\"\n                android:paddingRight=\"16dp\"\n                android:paddingBottom=\"8dp\"\n                android:visibility=\"gone\"\n                tools:visibility=\"visible\">\n\n                <ImageView\n                    android:id=\"@+id/grant_permission_icon\"\n                    android:layout_width=\"24dp\"\n                    android:layout_height=\"24dp\"\n                    android:layout_alignTop=\"@id/grant_permission_summary\"\n                    android:layout_alignBottom=\"@id/grant_permission_summary\"\n                    android:layout_alignParentLeft=\"true\"\n                    android:layout_centerVertical=\"true\"\n                    android:src=\"@drawable/ic_alert\"\n                    app:tint=\"?attr/colorPrimary\" />\n\n                <TextView\n                    android:id=\"@+id/grant_permission_summary\"\n                    style=\"@style/TextAppearance.AppCompat.Small.Inverse\"\n                    android:layout_width=\"0dip\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_alignParentRight=\"true\"\n                    android:layout_marginLeft=\"16dp\"\n                    android:layout_toRightOf=\"@id/grant_permission_icon\"\n                    android:layout_weight=\"1\"\n                    android:text=\"@string/exposure_confirm_permission_description\" />\n\n                <Button\n                    android:id=\"@+id/grant_permission_button\"\n                    style=\"@style/Widget.AppCompat.Button.Borderless\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_below=\"@id/grant_permission_summary\"\n                    android:layout_alignLeft=\"@id/grant_permission_summary\"\n                    android:layout_marginLeft=\"-16dp\"\n                    android:text=\"@string/exposure_confirm_permission_button\"\n                    android:textColor=\"?android:attr/textColorPrimaryInverse\" />\n            </RelativeLayout>\n\n            <RelativeLayout\n                android:id=\"@+id/grant_background_location_view\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginBottom=\"8dp\"\n                android:background=\"?attr/colorAccent\"\n                android:clipToPadding=\"false\"\n                android:paddingLeft=\"16dp\"\n                android:paddingTop=\"16dp\"\n                android:paddingRight=\"16dp\"\n                android:paddingBottom=\"8dp\"\n                android:visibility=\"gone\"\n                tools:visibility=\"visible\">\n\n                <ImageView\n                    android:id=\"@+id/grant_background_location_icon\"\n                    android:layout_width=\"24dp\"\n                    android:layout_height=\"24dp\"\n                    android:layout_alignTop=\"@id/grant_background_location_summary\"\n                    android:layout_alignBottom=\"@id/grant_background_location_summary\"\n                    android:layout_alignParentLeft=\"true\"\n                    android:layout_centerVertical=\"true\"\n                    android:src=\"@drawable/ic_outline_location_on\"\n                    app:tint=\"?attr/colorPrimary\" />\n\n                <TextView\n                    android:id=\"@+id/grant_background_location_summary\"\n                    style=\"@style/TextAppearance.AppCompat.Small.Inverse\"\n                    android:layout_width=\"0dip\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_alignParentRight=\"true\"\n                    android:layout_marginLeft=\"16dp\"\n                    android:layout_toRightOf=\"@id/grant_background_location_icon\"\n                    android:layout_weight=\"1\"\n                    android:text=\"@string/exposure_grant_background_location_description\"/>\n\n                <Button\n                    android:id=\"@+id/grant_background_location_button\"\n                    style=\"@style/Widget.AppCompat.Button.Borderless\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_below=\"@id/grant_background_location_summary\"\n                    android:layout_alignLeft=\"@id/grant_background_location_summary\"\n                    android:layout_marginLeft=\"-16dp\"\n                    android:text=\"@string/exposure_grant_background_location_button\"\n                    android:textColor=\"?android:attr/textColorPrimaryInverse\" />\n            </RelativeLayout>\n\n            <RelativeLayout\n                android:id=\"@+id/enable_bluetooth_view\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginBottom=\"8dp\"\n                android:background=\"?attr/colorAccent\"\n                android:clipToPadding=\"false\"\n                android:paddingLeft=\"16dp\"\n                android:paddingTop=\"16dp\"\n                android:paddingRight=\"16dp\"\n                android:paddingBottom=\"8dp\"\n                android:visibility=\"gone\"\n                tools:visibility=\"visible\">\n\n                <ImageView\n                    android:id=\"@+id/enable_bluetooth_icon\"\n                    android:layout_width=\"24dp\"\n                    android:layout_height=\"24dp\"\n                    android:layout_alignTop=\"@id/enable_bluetooth_summary\"\n                    android:layout_alignBottom=\"@id/enable_bluetooth_summary\"\n                    android:layout_alignParentLeft=\"true\"\n                    android:layout_centerVertical=\"true\"\n                    android:src=\"@drawable/ic_bluetooth_off\"\n                    app:tint=\"?attr/colorPrimary\" />\n\n                <TextView\n                    android:id=\"@+id/enable_bluetooth_summary\"\n                    style=\"@style/TextAppearance.AppCompat.Small.Inverse\"\n                    android:layout_width=\"0dip\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_alignParentRight=\"true\"\n                    android:layout_marginLeft=\"16dp\"\n                    android:layout_toRightOf=\"@id/enable_bluetooth_icon\"\n                    android:layout_weight=\"1\"\n                    android:text=\"@string/exposure_confirm_bluetooth_description\" />\n\n                <Button\n                    android:id=\"@+id/enable_bluetooth_button\"\n                    style=\"@style/Widget.AppCompat.Button.Borderless\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_below=\"@id/enable_bluetooth_summary\"\n                    android:layout_alignLeft=\"@id/enable_bluetooth_summary\"\n                    android:layout_marginLeft=\"-16dp\"\n                    android:text=\"@string/exposure_confirm_button\"\n                    android:textColor=\"?android:attr/textColorPrimaryInverse\" />\n\n                <ProgressBar\n                    android:id=\"@+id/enable_bluetooth_spinner\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_alignLeft=\"@id/enable_bluetooth_button\"\n                    android:layout_alignTop=\"@id/enable_bluetooth_button\"\n                    android:layout_alignRight=\"@id/enable_bluetooth_button\"\n                    android:layout_alignBottom=\"@id/enable_bluetooth_button\"\n                    android:indeterminate=\"true\"\n                    android:indeterminateTint=\"?attr/colorPrimary\"\n                    android:padding=\"8dp\"\n                    android:visibility=\"invisible\" />\n            </RelativeLayout>\n\n            <RelativeLayout\n                android:id=\"@+id/enable_location_view\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginBottom=\"8dp\"\n                android:background=\"?attr/colorAccent\"\n                android:clipToPadding=\"false\"\n                android:paddingLeft=\"16dp\"\n                android:paddingTop=\"16dp\"\n                android:paddingRight=\"16dp\"\n                android:paddingBottom=\"8dp\"\n                android:visibility=\"gone\"\n                tools:visibility=\"visible\">\n\n                <ImageView\n                    android:id=\"@+id/enable_location_icon\"\n                    android:layout_width=\"24dp\"\n                    android:layout_height=\"24dp\"\n                    android:layout_alignTop=\"@id/enable_location_summary\"\n                    android:layout_alignBottom=\"@id/enable_location_summary\"\n                    android:layout_alignParentLeft=\"true\"\n                    android:layout_centerVertical=\"true\"\n                    android:src=\"@drawable/ic_location_off\"\n                    app:tint=\"?attr/colorPrimary\" />\n\n                <TextView\n                    android:id=\"@+id/enable_location_summary\"\n                    style=\"@style/TextAppearance.AppCompat.Small.Inverse\"\n                    android:layout_width=\"0dip\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_alignParentRight=\"true\"\n                    android:layout_marginLeft=\"16dp\"\n                    android:layout_toRightOf=\"@id/enable_location_icon\"\n                    android:layout_weight=\"1\"\n                    android:text=\"@string/exposure_confirm_location_description\" />\n\n                <Button\n                    android:id=\"@+id/enable_location_button\"\n                    style=\"@style/Widget.AppCompat.Button.Borderless\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_below=\"@id/enable_location_summary\"\n                    android:layout_alignLeft=\"@id/enable_location_summary\"\n                    android:layout_marginLeft=\"-16dp\"\n                    android:text=\"@string/exposure_confirm_button\"\n                    android:textColor=\"?android:attr/textColorPrimaryInverse\" />\n            </RelativeLayout>\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:gravity=\"end\"\n                android:paddingLeft=\"8dp\"\n                android:paddingTop=\"0dp\"\n                android:paddingRight=\"8dp\"\n                android:paddingBottom=\"8dp\">\n\n                <Button\n                    android:id=\"@android:id/button2\"\n                    style=\"@style/Widget.AppCompat.Button.Borderless.Colored\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:text=\"@android:string/cancel\" />\n\n                <Button\n                    android:id=\"@android:id/button1\"\n                    style=\"@style/Widget.AppCompat.Button.Borderless.Colored\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:text=\"@android:string/ok\" />\n            </LinearLayout>\n        </LinearLayout>\n    </ScrollView>\n</LinearLayout>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/layout/exposure_notifications_confirm_delete.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<FrameLayout 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\n    <TextView\n        android:padding=\"?attr/dialogPreferredPadding\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/pref_exposure_rpi_delete_all_warning\" />\n</FrameLayout>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/layout/exposure_notifications_settings_activity.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<LinearLayout 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    android:orientation=\"vertical\">\n\n    <androidx.fragment.app.FragmentContainerView\n        android:id=\"@+id/navhost\"\n        android:name=\"androidx.navigation.fragment.NavHostFragment\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        app:defaultNavHost=\"true\"\n        app:navGraph=\"@navigation/nav_nearby\" />\n</LinearLayout>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/layout/preference_dot_chart.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<org.microg.gms.nearby.exposurenotification.ui.DotChartView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/dot_chart\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"230dp\"\n    android:orientation=\"vertical\"\n    android:padding=\"16dp\" />\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/navigation/nav_nearby.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<navigation 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/nav_nearby\"\n    app:startDestination=\"@id/exposureNotificationsFragment\"\n    tools:ignore=\"UnusedNavigation\">\n\n    <fragment\n        android:id=\"@+id/exposureNotificationsFragment\"\n        android:name=\"org.microg.gms.nearby.exposurenotification.ui.ExposureNotificationsFragment\"\n        android:label=\"@string/service_name_exposure\"\n        tools:layout=\"@layout/exposure_notifications_fragment\">\n        <deepLink\n            app:action=\"com.google.android.gms.settings.EXPOSURE_NOTIFICATION_SETTINGS\"\n            app:uri=\"x-gms-settings://exposure-notifications\" />\n\n        <action\n            android:id=\"@+id/openExposureRpis\"\n            app:destination=\"@id/exposureNotificationsRpisFragment\" />\n        <action\n            android:id=\"@+id/openExposureAppDetails\"\n            app:destination=\"@id/exposureNotificationsAppFragment\" />\n    </fragment>\n\n    <fragment\n        android:id=\"@+id/exposureNotificationsRpisFragment\"\n        android:name=\"org.microg.gms.nearby.exposurenotification.ui.ExposureNotificationsRpisFragment\"\n        android:label=\"@string/pref_exposure_collected_rpis_title\">\n        <deepLink\n            app:action=\"ACTION_VIEW\"\n            app:uri=\"x-gms-settings://exposure-notifications-rpis\" />\n    </fragment>\n\n    <fragment\n        android:id=\"@+id/exposureNotificationsAppFragment\"\n        android:name=\"org.microg.gms.nearby.exposurenotification.ui.ExposureNotificationsAppFragment\"\n        android:label=\"@string/service_name_exposure\"\n        tools:layout=\"@layout/exposure_notifications_app_fragment\">\n        <argument\n            android:name=\"package\"\n            app:argType=\"string\" />\n    </fragment>\n</navigation>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"exposure_notify_off_title\">Exposure Notifications inactive</string>\n    <string name=\"exposure_notify_off_bluetooth\">Bluetooth needs to be enabled to receive Exposure Notifications.</string>\n    <string name=\"exposure_notify_off_location\">Location access is required to receive Exposure Notifications.</string>\n    <string name=\"exposure_notify_off_bluetooth_location\">Bluetooth and Location access need to be enabled to receive Exposure Notifications.</string>\n    <string name=\"exposure_notify_off_nearby\">Exposure Notifications require additional permissions to work</string>\n\n    <string name=\"service_name_exposure\">Exposure Notifications</string>\n    <string name=\"pref_exposure_enable_info_summary\">To enable Exposure Notifications, open any app supporting it.</string>\n    <string name=\"pref_exposure_error_bluetooth_off_title\">Enable Bluetooth</string>\n    <string name=\"pref_exposure_error_location_off_title\">Open Location settings</string>\n    <string name=\"pref_exposure_error_bluetooth_unsupported_summary\">Unfortunately, your device is not compatible with Exposure Notifications.</string>\n    <string name=\"pref_exposure_error_bluetooth_no_advertise_summary\">Unfortunately, your device is only partially compatible with Exposure Notifications. You can be notified for risk contacts but won\\'t be able to notify others.</string>\n    <string name=\"prefcat_exposure_apps_title\">Apps using Exposure Notifications</string>\n    <string name=\"pref_exposure_collected_rpis_title\">Collected IDs</string>\n    <string name=\"pref_exposure_collected_rpis_summary\"><xliff:g example=\"63\">%1$d</xliff:g> IDs in last hour</string>\n    <string name=\"pref_exposure_advertising_id_title\">Currently broadcasted ID</string>\n    <string name=\"prefcat_exposure_app_report_title\">Reported exposures</string>\n    <string name=\"pref_exposure_app_report_updated_title\">Updated: <xliff:g example=\"Today, 14:02\">%1$s</xliff:g></string>\n    <string name=\"pref_exposure_app_report_entry_time_short\">Less than 5 minutes</string>\n    <string name=\"pref_exposure_app_report_entry_time_about\">About <xliff:g example=\"13\">%1$d</xliff:g> minutes</string>\n    <string name=\"pref_exposure_app_report_entry_distance_close\">nearby exposure</string>\n    <string name=\"pref_exposure_app_report_entry_distance_far\">distant exposure</string>\n    <string name=\"pref_exposure_app_report_entry_combined\"><xliff:g example=\"About 12 minutes\">%1$s</xliff:g>, <xliff:g example=\"distant exposure\">%2$s</xliff:g></string>\n    <string name=\"pref_exposure_app_last_report_summary_diagnosis_keys\">Processed <xliff:g example=\"121031\">%1$d</xliff:g> diagnosis keys.</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_no\">No exposure encounters reported.</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_prefix\">Reported <xliff:g example=\"3\">%1$d</xliff:g> exposure encounters:</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_line\"><xliff:g example=\"Yesterday, 12:00 - 14:00\">%1$s</xliff:g>, risk score <xliff:g example=\"99\">%2$d</xliff:g></string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_suffix\">Note: The risk score is defined by the app. High numbers can refer to low risk or vice-versa.</string>\n    <string name=\"pref_exposure_app_api_usage_title\">API usage in the last 14 days</string>\n    <string name=\"pref_exposure_app_api_usage_summary_line\"><xliff:g example=\"12\">%1$d</xliff:g> calls to <xliff:g example=\"provideDiagnosisKeys\">%2$s</xliff:g></string>\n    <string name=\"prefcat_exposure_rpis_histogram_title\"><xliff:g example=\"230\">%1$d</xliff:g> IDs collected</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_no_records\">No records</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_records\"><xliff:g example=\"0 - 50\">%1$s</xliff:g> IDs per hour</string>\n    <string name=\"pref_exposure_rpi_delete_all_title\">Delete</string>\n    <string name=\"pref_exposure_rpi_delete_all_summary\">Delete all collected IDs</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning\">Deleting collected IDs will make it impossible to notify you in case any of your contacts of the last 14 days is diagnosed.</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning_confirm_button\">Delete anyways</string>\n    <string name=\"pref_exposure_rpi_export_title\">Export</string>\n    <string name=\"pref_exposure_rpi_export_summary\">Export collected IDs for extended analysis with another app.</string>\n    <string name=\"pref_exposure_info_summary\">\"Exposure Notifications API allows apps to notify you if you were exposed to someone who reported to be diagnosed positive.\n\nThe date, duration, and signal strength associated with an exposure will be shared with the corresponding app.\"</string>\n    <string name=\"pref_exposure_rpis_details_summary\">\"While Exposure Notification API is enabled, your device passively collects IDs (called Rolling Proximity Identifiers, or RPIs) from nearby devices.\n\nWhen device owners report to be diagnosed positive, their IDs can be shared. Your device checks if any of the known diagnosed IDs matches any of the collected IDs and calculates your infection risk.\"</string>\n\n    <string name=\"exposure_enable_switch\">Use Exposure Notifications</string>\n    <string name=\"exposure_confirm_start_title\">Turn on Exposure Notifications?</string>\n    <string name=\"exposure_confirm_start_summary\">\"Your phone needs to use Bluetooth to securely collect and share IDs with other phones that are nearby.\n\n<xliff:g example=\"Corona-Warn\">%1$s</xliff:g> can notify you if you were exposed to someone who reported to be diagnosed positive.\n\nThe date, duration, and signal strength associated with an exposure will be shared with the app.\"</string>\n    <string name=\"exposure_confirm_start_button\">Turn on</string>\n    <string name=\"exposure_confirm_stop_title\">Turn off Exposure Notifications?</string>\n    <string name=\"exposure_confirm_stop_summary\">After disabling Exposure Notifications, you will no longer be notified when you were exposed to someone who reported to be diagnosed positive.</string>\n    <string name=\"exposure_confirm_stop_button\">Turn off</string>\n    <string name=\"exposure_confirm_keys_title\">Share your IDs with <xliff:g example=\"Corona-Warn\">%1$s</xliff:g>?</string>\n    <string name=\"exposure_confirm_keys_summary\">\"Your IDs from the last 14 days will be used to help notify others that you&apos;ve been near about potential exposure.\n\nYour identity or test result won&apos;t be shared with other people.\"</string>\n    <string name=\"exposure_confirm_keys_button\">Share</string>\n    <string name=\"exposure_confirm_permission_description\"><xliff:g example=\"microG Services\">%1$s</xliff:g> needs additional permissions.</string>\n    <string name=\"exposure_confirm_permission_button\">Grant</string>\n    <string name=\"exposure_confirm_bluetooth_description\">Bluetooth needs to be enabled.</string>\n    <string name=\"exposure_confirm_location_description\">Location access is required.</string>\n    <string name=\"exposure_confirm_button\">Enable</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_title\">New Permissions required</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_description\">Tap to grant required permissions to Exposure Notifications</string>\n    <string name=\"exposure_grant_background_location_description\">Almost there! You will need to enable background location access by selecting the \\'Allow all the time\\' option on the next screen. Then press back.</string>\n    <string name=\"exposure_grant_background_location_button\">Update Settings</string>\n</resources>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-ar/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=\"pref_exposure_collected_rpis_title\">المعرفات المجمّعة</string>\n    <string name=\"pref_exposure_error_bluetooth_no_advertise_summary\">للأسف، جهازك متوافق جزئياً فقط مع نظام إشعارات التعرض. يمكنك الحصول على إشعارات لجهات الاتصال المعرِّضة للخطر ولكن لن تتمكن من إشعار الآخرين.</string>\n    <string name=\"prefcat_exposure_apps_title\">التطبيقات التي تستخدم إشعارات التعرض</string>\n    <string name=\"prefcat_exposure_app_report_title\">حالات التعرض المبلغ عنها</string>\n    <string name=\"pref_exposure_app_last_report_summary_diagnosis_keys\">تمت معالجة <xliff:g example=\"121031\">%1$d</xliff:g> مفتاح تشخيص.</string>\n    <string name=\"pref_exposure_error_bluetooth_off_title\">تفعيل البلوتوث</string>\n    <string name=\"pref_exposure_error_location_off_title\">فتح إعدادات الموقع</string>\n    <string name=\"pref_exposure_error_bluetooth_unsupported_summary\">للأسف، جهازك غير متوافق مع إشعارات التعرض.</string>\n    <string name=\"pref_exposure_collected_rpis_summary\"><xliff:g example=\"63\">(%1$d)</xliff:g> معرّف في الساعة اﻷخيرة</string>\n    <string name=\"pref_exposure_advertising_id_title\">المعرّف المستخدم حاليًا</string>\n    <string name=\"pref_exposure_app_report_updated_title\">تم التحديث: <xliff:g example=\"Today, 14:02\">%1$s</xliff:g></string>\n    <string name=\"pref_exposure_app_report_entry_time_short\">أقل من 5 دقائق</string>\n    <string name=\"pref_exposure_app_report_entry_time_about\">حول <xliff:g example=\"13\">%1$d</xliff:g> دقيقة</string>\n    <string name=\"pref_exposure_app_report_entry_distance_far\">تعرض بعيد</string>\n    <string name=\"pref_exposure_app_report_entry_combined\"><xliff:g example=\"About 12 minutes\">%1$s</xliff:g> ،<xliff:g example=\"distant exposure\">%2$s</xliff:g></string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_no\">لم يتم الإبلاغ عن أي لقاءات تعرض.</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_prefix\">تم اﻹبلاغ عن <xliff:g example=\"3\">%1$d</xliff:g> لقاءات تعرض:</string>\n    <string name=\"pref_exposure_app_report_entry_distance_close\">تعرض قريب</string>\n    <string name=\"exposure_notify_off_title\">إشعارات التعرض غير نشطة</string>\n    <string name=\"exposure_notify_off_bluetooth\">يجب تمكين البلوتوث لتلقي إشعارات التعرض.</string>\n    <string name=\"exposure_notify_off_location\">يلزم الوصول إلى الموقع لتلقي إشعارات التعرض.</string>\n    <string name=\"exposure_notify_off_bluetooth_location\">يجب تمكين Bluetooth والوصول إلى الموقع لتلقي إشعارات التعرض.</string>\n    <string name=\"exposure_notify_off_nearby\">متتطلب إشعارات التعرض أذونات إضافية للعمل</string>\n    <string name=\"service_name_exposure\">إشعارات التعرض</string>\n    <string name=\"pref_exposure_enable_info_summary\">لتمكين إشعارات التعرض، افتح أي تطبيق يدعمها.</string>\n    <string name=\"pref_exposure_app_api_usage_title\">استخدام الـ API في آخر 14 يومًا</string>\n    <string name=\"pref_exposure_app_api_usage_summary_line\"><xliff:g example=\"12\">%1$d</xliff:g> يكلم <xliff:g example=\"provideDiagnosisKeys\">%2$s</xliff:g></string>\n    <string name=\"prefcat_exposure_rpis_histogram_title\"><xliff:g example=\"230\">%1$d</xliff:g> مُعَرِّفًا جمع</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_no_records\">لا توجد سجلات</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_records\"><xliff:g example=\"0 - 50\">%1$s</xliff:g> مُعَرِّفًا في الساعة</string>\n    <string name=\"pref_exposure_rpi_delete_all_title\">حذف</string>\n    <string name=\"pref_exposure_rpi_delete_all_summary\">حذف كل مُعَرِّفٍ جُمِع</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning\">حذف المُعَرِّفات المجمعة سيؤدي إلى استحالة اشعارك في حالة تشخيص إصابة أي من جهات اتصالك خلال آخر 14 يومًا.</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning_confirm_button\">بهمش يا زلمه إحذف</string>\n    <string name=\"pref_exposure_rpi_export_title\">تصدير</string>\n    <string name=\"pref_exposure_rpi_export_summary\">تصدير المُعَرِّفات المجمعة لتحليلها بشكل موسع باستخدام تطبيق آخر.</string>\n    <string name=\"exposure_confirm_start_button\">تشغيل</string>\n    <string name=\"exposure_confirm_stop_button\">إطفاء</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_line\"><xliff:g example=\"Yesterday, 12:00 - 14:00\">%1$s</xliff:g>، درجة المخاطرة <xliff:g example=\"99\">%2$d</xliff:g></string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_suffix\">ملاحظة: يتم تحديد درجة المخاطرة بواسطة التطبيق. قد تشير الأرقام المرتفعة إلى مخاطرة منخفضة والعكس صحيح.</string>\n</resources>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-ast/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources></resources>"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-az/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=\"pref_exposure_error_bluetooth_off_title\">Bluetooth-u Aktiv edin</string>\n    <string name=\"pref_exposure_error_location_off_title\">Məkan tənzimləmələrin açın</string>\n    <string name=\"pref_exposure_collected_rpis_title\">Toplanmış ID-lər</string>\n    <string name=\"pref_exposure_collected_rpis_summary\"><xliff:g example=\"63\">%1$d</xliff:g> Son bir saatda ID-lər</string>\n    <string name=\"exposure_notify_off_title\">Təmas Bildirişləri Qeyri-aktivdir</string>\n    <string name=\"exposure_notify_off_bluetooth\">Təmas Bildirişlərini Qəbul Etmək Üçün Bluetooth Aktivləşdirilməlidir.</string>\n    <string name=\"exposure_notify_off_location\">Təmas Bildirişlərini almaq üçün məkan girişi tələb olunur.</string>\n    <string name=\"exposure_notify_off_bluetooth_location\">Təmas Bildirişlərin qəbul etmək üçün Bluetooth və Məkan girişi aktivləşdirilməlidir.</string>\n    <string name=\"exposure_notify_off_nearby\">Təmas Bildirişləri işləmək üçün əlavə icazələr tələb edir</string>\n    <string name=\"service_name_exposure\">Təmas Bildirişləri</string>\n    <string name=\"pref_exposure_enable_info_summary\">Təmas Bildirişlərin aktivləşdirmək üçün onu dəstəkləyən hansısa tətbiqi aç.</string>\n    <string name=\"pref_exposure_error_bluetooth_unsupported_summary\">Təəssüf ki, cihazınız Təmas Bildirişləri ilə uyğun gəlmir.</string>\n    <string name=\"pref_exposure_error_bluetooth_no_advertise_summary\">Təəssüf ki, cihazınız Təmas Bildirişləri ilə yalnız qismən uyğun gəlir. Siz təhlükəli kontaktlar barədə xəbərdar ola bilərsiniz, lakin başqalarını xəbərdar edə bilməyəcəksiniz.</string>\n    <string name=\"prefcat_exposure_apps_title\">Təmas Bildirişlərin istifadə edən tətbiqlər</string>\n    <string name=\"pref_exposure_app_report_entry_time_short\">5 dəqiqədən az</string>\n    <string name=\"pref_exposure_app_report_entry_time_about\">Haqqında <xliff:g example=\"13\"> %1$d</xliff:g> dəqiqə</string>\n    <string name=\"pref_exposure_app_last_report_summary_diagnosis_keys\">Emal edilib <xliff:g example=\"121031\"> %1$d</xliff:g> diaqnoz açarları.</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_suffix\">Qeyd: Risk balı tətbiq tərəfindən təyin edilir. Yüksək rəqəmlər aşağı riskə və ya əksinə aid ola bilər.</string>\n    <string name=\"pref_exposure_app_api_usage_title\">Son 14 gündə API istifadəsi</string>\n    <string name=\"pref_exposure_app_api_usage_summary_line\"><xliff:g example=\"12\">%1$d</xliff:g> -a səslənir <xliff:g example=\"provideDiagnosisKeys\"> %2$s</xliff:g></string>\n    <string name=\"prefcat_exposure_rpis_histogram_title\"><xliff:g example=\"230\">%1$d</xliff:g> ID toplandı</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_no_records\">Qeydlər yoxdur</string>\n    <string name=\"pref_exposure_rpi_delete_all_title\">Sil</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning_confirm_button\">Yenə də silin</string>\n    <string name=\"pref_exposure_rpi_export_title\">İxrac et</string>\n    <string name=\"pref_exposure_info_summary\">Təmas Bildirişləri API-si, müsbət diaqnoz qoyulduğunu bildirən birisi ilə təmasda olmusunuzsa, tətbiqlərə sizi xəbərdar etməyə icazə verir.\n\\n\n\\nTəmas ilə əlaqəli tarix, müddət və siqnal gücü müvafiq tətbiq ilə paylaşılacaq.</string>\n    <string name=\"exposure_enable_switch\">Təmas Bildirişlərin istifadə et</string>\n    <string name=\"exposure_confirm_start_title\">Təmas Bildirişləri aktiv edilsin?</string>\n    <string name=\"pref_exposure_app_report_entry_distance_far\">uzaq təmas</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_no\">Təmas ilə bağlı məlumat verilməyib.</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_prefix\">Məlumat verildi <xliff:g example=\"3\"> %1$d</xliff:g> təmas qarşılaşmaları:</string>\n    <string name=\"pref_exposure_app_report_entry_distance_close\">yaxın təmas</string>\n    <string name=\"prefcat_exposure_app_report_title\">Bildirilən yoluxmalar</string>\n    <string name=\"pref_exposure_advertising_id_title\">Hazırda yayımlanan ID</string>\n    <string name=\"pref_exposure_app_report_updated_title\">Yenilənib: <xliff:g example=\"Bugün, 14:02\"> %1$s</xliff:g></string>\n    <string name=\"pref_exposure_app_report_entry_combined\"><xliff:g example=\"About 12 dəqiqə\">%1$s</xliff:g> ,<xliff:g example=\"uzaq təmas\"> %2$s</xliff:g></string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_line\"><xliff:g example=\"Dünən, 12:00 - 14:00\">%1$s</xliff:g> , risk hesabı<xliff:g example=\"99\"> %2$d</xliff:g></string>\n    <string name=\"pref_exposure_rpis_histogram_legend_records\"><xliff:g example=\"0 - 50\">%1$s</xliff:g> Saatda ID</string>\n    <string name=\"pref_exposure_rpi_delete_all_summary\">Bütün toplanmış ID-ləri silin</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning\">Toplanmış ID-lərin silinməsi, son 14 gündə kontaktlarınızdan kiməsə diaqnoz qoyulduğu halda sizə məlumat verməyi qeyri-mümkün edəcək.</string>\n    <string name=\"pref_exposure_rpi_export_summary\">Başqa tətbiqlə uzadılmış təhlil üçün toplanmış ID-ləri ixrac edin.</string>\n    <string name=\"pref_exposure_rpis_details_summary\">Təmas Bildirişi API\\'si aktiv olduqda, cihazınız yavaş şəkildə yaxınlıqdakı cihazlardan ID-ləri (Yüklənən Yaxınlıq İdentifikatorları və ya RPI adlanır) toplayır. \n\\n\n\\nCihaz sahibləri diaqnozun müsbət olduğunu bildirdikdə, onların ID-ləri paylaşıla bilər. Cihazınız məlum diaqnoz qoyulmuş ID-lərin, toplanmış ID-lərin hər hansı birinə uyğun olub-olmadığını yoxlayır və yoluxma riskinizi hesablayır.</string>\n</resources>"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-be/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"exposure_notify_off_title\">Паведамленні аб рызыцы інфікавання не актыўныя</string>\n    <string name=\"exposure_notify_off_bluetooth\">Bluetooth павінен быць уключаны, каб прымаць паведамленні аб рызыцы інфікавання.</string>\n    <string name=\"exposure_notify_off_location\">Доступ да месцазнаходжання абавязковы, каб прымаць паведамленні аб рызыцы інфікавання.</string>\n    <string name=\"exposure_notify_off_bluetooth_location\">Bluetooth і вызначэнне месцазнаходжання павінны быць уключаны, каб прымаць паведамленні аб рызыцы інфікавання.</string>\n    <string name=\"exposure_notify_off_nearby\">Паведамленням аб рызыцы інфікавання для працы патрабуюцца дадатковыя дазволы</string>\n    <string name=\"service_name_exposure\">Паведамленні аб рызыцы інфікавання</string>\n    <string name=\"pref_exposure_enable_info_summary\">Каб уключыць паведамленні аб рызыцы інфікавання запусціце любое прыкладанне, якое іх падтрымлівае.</string>\n    <string name=\"pref_exposure_error_bluetooth_off_title\">Ўключыць Bluetooth</string>\n    <string name=\"pref_exposure_error_location_off_title\">Адкрыць налады месцазнаходжаньня</string>\n    <string name=\"pref_exposure_error_bluetooth_unsupported_summary\">На жаль ваша прылада несумяшчальна з паведамленнямі аб рызыцы інфікавання.</string>\n    <string name=\"pref_exposure_error_bluetooth_no_advertise_summary\">На жаль ваша прылада толькі часткова сумяшчальна з паведамленнямі аб рызыцы інфікавання. Вы можаце атрымліваць паведамленні аб небяспечных кантактах, але не зможаце апавяшчаць іншых.</string>\n    <string name=\"prefcat_exposure_apps_title\">Прыкладанні якія выкарыстоўваюць апавяшчэння аб рызыцы інфікавання</string>\n    <string name=\"pref_exposure_collected_rpis_title\">Сабраныя ідэнтыфікатары</string>\n    <string name=\"pref_exposure_collected_rpis_summary\"><xliff:g example=\"63\">%1$d</xliff:g> олькасць ідэнтыфікатараў за апошнюю гадзіну</string>\n    <string name=\"pref_exposure_advertising_id_title\">Трансліруемы ў цяперашні час ідэнтыфікатар</string>\n    <string name=\"prefcat_exposure_app_report_title\">Паведамленні пра ўзаемадзеянні</string>\n    <string name=\"pref_exposure_app_report_updated_title\">Абноўлена: <xliff:g example=\"Today, 14:02\">%1$s</xliff:g></string>\n    <string name=\"pref_exposure_app_report_entry_time_short\">Менш за пяць хвілін назад</string>\n    <string name=\"pref_exposure_app_report_entry_time_about\">Каля <xliff:g example=\"13\">%1$d</xliff:g> хвілін</string>\n    <string name=\"pref_exposure_app_report_entry_distance_close\">ўзаемадзеянні побач</string>\n    <string name=\"pref_exposure_app_report_entry_distance_far\">ўзаемадзеянні далёка</string>\n    <string name=\"pref_exposure_app_report_entry_combined\"><xliff:g example=\"About 12 minutes\">%1$s</xliff:g>, <xliff:g example=\"distant exposure\">%2$s</xliff:g></string>\n    <string name=\"pref_exposure_app_last_report_summary_diagnosis_keys\">Апрацавана <xliff:g example=\"121031\">%1$d</xliff:g> дыягнастычных ключоў.</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_no\">Паведамленні аб небяспечных кантактах адсутнічаюць.</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_prefix\">Паведамлена пра <xliff:g example=\"3\">%1$d</xliff:g> небяспечных кантактах:</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_line\"><xliff:g example=\"Yesterday, 12:00 - 14:00\">%1$s</xliff:g>, ацэнка рызыкі <xliff:g example=\"99\">%2$d</xliff:g></string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_suffix\">Увага: Ацэнка рызыкі вызначаецца прыкладаннем. Высокія лічбы могуць казаць, як аб нізкай рызыцы так і наадварот.</string>\n    <string name=\"pref_exposure_app_api_usage_title\">Выкарыстанне API за апошнія 14 дзён</string>\n    <string name=\"pref_exposure_app_api_usage_summary_line\"><xliff:g example=\"12\">%1$d</xliff:g> запытаў да <xliff:g example=\"provideDiagnosisKeys\">%2$s</xliff:g></string>\n    <string name=\"prefcat_exposure_rpis_histogram_title\"><xliff:g example=\"230\">%1$d</xliff:g> ідэнтыфікатараў сабрана</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_no_records\">Няма запісаў</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_records\"><xliff:g example=\"0 - 50\">%1$s</xliff:g> Ідэнтыфікатараў у гадзіну</string>\n    <string name=\"pref_exposure_rpi_delete_all_title\">Выдаліць</string>\n    <string name=\"pref_exposure_rpi_delete_all_summary\">Выдаліць усе сабраныя ідэнтыфікатары</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning\">Выдаленне сабраных ідэнтыфікатараў прывядзе да немагчымасці інфармавання у выпадку, калі ў аднаго з вашых кантактаў за апошнія 14 дзён будзе пацверджаны дыягназ.</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning_confirm_button\">Усё роўна выдаліць</string>\n    <string name=\"pref_exposure_rpi_export_title\">Экспартаваць</string>\n    <string name=\"pref_exposure_rpi_export_summary\">Экспартаваць сабраныя ідэнтыфікатары для пашыранага аналізу ў іншым прыкладанні.</string>\n    <string name=\"pref_exposure_info_summary\">\"API паведамленняў аб рызыцы інфікавання (Exposure Notifications API) дазваляе прыкладанням апавяшчаць вас, калі вы сутыкнуліся з кімсьці, у каго быў пацверджаны дыягназ.\n\nДата, працягласць і магутнасць сігналу, звязаныя з уздзеяннем, будуць перададзены адпаведным прыкладанням.\"</string>\n    <string name=\"pref_exposure_rpis_details_summary\">\"Пакуль API паведамленняў аб рызыцы інфікавання уключаны, ваша прылада пасіўна збірае ідэнтыфікатары (званыя слізгальнымі ідэнтыфікатарамі збліжэння або RPI) з суседніх прылад.\n\nКалі ўладальнікі прылад паведамляюць аб пацверджаным дыягназе, іх ідэнтыфікатары могуць быць распаўсюджаныя. Ваша прылада правярае, ці адпавядае якой-небудзь з вядомых ідэнтыфікатараў з пацьвердзіць дыягназам любому з сабраных вамі ідэнтыфікатараў, і разлічвае рызыку заражэння.\"</string>\n    <string name=\"exposure_enable_switch\">Выкарыстоўваць паведамленні аб рызыцы інфікавання</string>\n    <string name=\"exposure_confirm_start_title\">Ўключыць паведамленні аб рызыцы інфікавання?</string>\n    <string name=\"exposure_confirm_start_summary\">\"Ваш тэлефон павінен выкарыстоўваць Bluetooth для бяспечнага збору і распаўсюджвання ідэнтыфікатараў іншым тэлефонам, якія знаходзяцца паблізу.\n\n<xliff:g example=\"Corona-Warn\">%1$s</xliff:g> можа паведаміць вас, калі вы перасякаліся з кімсьці, у каго быў пацьверджаны дыягназ.\n\nДата, працягласць і магутнасць сігналу, звязаныя з кантактам, будуць перададзеныя прыкладанню.\"</string>\n    <string name=\"exposure_confirm_start_button\">Ўключыць</string>\n    <string name=\"exposure_confirm_stop_title\">Выключыць паведамленні аб рызыцы інфікавання?</string>\n    <string name=\"exposure_confirm_stop_summary\">Пасля адключэння паведамленняў вы больш не будзеце атрымліваць паведамленні аб кантактах з кімсьці, у каго быў пацьверджаны дыягназ.</string>\n    <string name=\"exposure_confirm_stop_button\">Выключыць</string>\n    <string name=\"exposure_confirm_keys_title\">Дзяліцца вашымі ідэнтыфікатарамі з <xliff:g example=\"Corona-Warn\">%1$s</xliff:g>?</string>\n    <string name=\"exposure_confirm_keys_summary\">\"Вашы ідэнтыфікатары за апошнія 14 дзён будуць выкарыстоўвацца для паведамлення іншых пра тое, што вы былі паблізу патэнцыйнай небяспекі.\n\nВаша асоба або вынік тэсту не будуць перададзены іншым людзям.\"</string>\n    <string name=\"exposure_confirm_keys_button\">Падзяліцца</string>\n    <string name=\"exposure_confirm_permission_description\">Для <xliff:g example=\"microG Services\">%1$s</xliff:g> патрабуюцца дадатковыя дазволы.</string>\n    <string name=\"exposure_confirm_permission_button\">Даць дазвол</string>\n    <string name=\"exposure_confirm_bluetooth_description\">Bluetooth павінен быць уключаны.</string>\n    <string name=\"exposure_confirm_location_description\">патрабуецца доступ да месцазнаходжання.</string>\n    <string name=\"exposure_confirm_button\">Уключыць</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_title\">Патрабуецца дадатковы дазвол</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_description\">Націсніце, каб даць неабходныя дазволы апавяшчэнням аб рызыцы інфікавання</string>\n    <string name=\"exposure_grant_background_location_description\">Амаль гатова! Вам трэба будзе ўключыць фонавы доступ да месцазнаходжання, выбраўшы опцыю \\'Дазволіць у любым рэжыме\\' на наступным экране. Потым вярніцеся назад.</string>\n    <string name=\"exposure_grant_background_location_button\">Абнавіць налады</string>\n</resources>"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-bn/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n</resources>"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-ca/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=\"exposure_notify_off_title\">Notificacions d\\'exposició desactivades</string>\n    <string name=\"exposure_notify_off_bluetooth\">El Bluetooth té que estar activat per rebre notificacions d\\'exposició.</string>\n    <string name=\"exposure_notify_off_location\">Es necessita el permís d\\'ubicació per rebre notificacions d\\'exposició.</string>\n    <string name=\"exposure_notify_off_bluetooth_location\">Cal activar el Bluetooth i l\\'accés a la ubicació per rebre notificacions d\\'exposició.</string>\n    <string name=\"exposure_notify_off_nearby\">Les notificacions d\\'exposició requereixen permisos addicionals per funcionar</string>\n    <string name=\"service_name_exposure\">Notificacions d\\'exposició</string>\n    <string name=\"pref_exposure_enable_info_summary\">Per activar les notificacions d\\'exposició, obriu qualsevol aplicació compatible.</string>\n    <string name=\"pref_exposure_error_bluetooth_off_title\">Activa el Bluetooth</string>\n    <string name=\"pref_exposure_error_location_off_title\">Obrir la configuració de la ubicació</string>\n    <string name=\"pref_exposure_error_bluetooth_unsupported_summary\">Malauradament, el vostre dispositiu no és compatible amb les notificacions d\\'exposició.</string>\n    <string name=\"pref_exposure_error_bluetooth_no_advertise_summary\">Malauradament, el vostre dispositiu només és parcialment compatible amb les notificacions d\\'exposició. Podeu rebre notificacions de contactes de risc, però no podreu notificar els altres.</string>\n    <string name=\"prefcat_exposure_apps_title\">Aplicacions que utilitzen notificacions d\\'exposició</string>\n    <string name=\"pref_exposure_collected_rpis_title\">Identificadors recollits</string>\n    <string name=\"pref_exposure_collected_rpis_summary\"><xliff:g example=\"63\">%1$d</xliff:g> identificadors en l\\'última hora</string>\n    <string name=\"pref_exposure_advertising_id_title\">Identificador actualment emès</string>\n    <string name=\"pref_exposure_app_report_entry_time_about\">Sobre <xliff:g example=\"13\">%1$d</xliff:g> minuts</string>\n    <string name=\"pref_exposure_app_report_entry_distance_close\">exposició de proximitat</string>\n    <string name=\"pref_exposure_app_report_entry_distance_far\">exposició a distància</string>\n    <string name=\"pref_exposure_app_report_entry_combined\"><xliff:g example=\"About 12 minutes\">%1$s</xliff:g>, <xliff:g example=\"distant exposure\">%2$s</xliff:g></string>\n    <string name=\"pref_exposure_app_last_report_summary_diagnosis_keys\">S\\'ha processat <xliff:g example=\"121031\">%1$d</xliff:g> claus de diagnòstic.</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_no\">No s\\'han notificat contactes d\\'exposició.</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_prefix\">Inicis d\\'exposició notificats <xliff:g example=\"3\">%1$d</xliff:g>:</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_line\"><xliff:g example=\"Yesterday, 12:00 - 14:00\">%1$s</xliff:g>, puntuació de risc <xliff:g example=\"99\">%2$d</xliff:g></string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_suffix\">Nota: La puntuació de risc la defineix l\\'aplicació. Els valors alts poden referir-se a un risc baix o viceversa.</string>\n    <string name=\"pref_exposure_app_api_usage_title\">Ús de l\\'API en els darrers 14 dies</string>\n    <string name=\"pref_exposure_app_api_usage_summary_line\"><xliff:g example=\"12\">%1$d</xliff:g> trucades a <xliff:g example=\"provideDiagnosisKeys\">%2$s</xliff:g></string>\n    <string name=\"prefcat_exposure_rpis_histogram_title\"><xliff:g example=\"230\">%1$d</xliff:g> identificadors recollits</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_no_records\">No hi ha cap registre</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_records\"><xliff:g example=\"0 - 50\">%1$s</xliff:g> identificadors per hora</string>\n    <string name=\"pref_exposure_rpi_delete_all_title\">Esborrar</string>\n    <string name=\"pref_exposure_rpi_delete_all_summary\">Esborrar tots els identificadors recollits</string>\n    <string name=\"prefcat_exposure_app_report_title\">Exposicions reportades</string>\n    <string name=\"pref_exposure_app_report_updated_title\">Actualitzat: <xliff:g example=\"Today, 14:02\">%1$s</xliff:g></string>\n    <string name=\"pref_exposure_app_report_entry_time_short\">Menys de 5 minuts</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning\">Esborrar els identificadors recollits farà que sigui impossible notificar-vos si algun dels vostres contactes dels darrers 14 dies és diagnosticat.</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning_confirm_button\">Suprimeix igualment</string>\n    <string name=\"pref_exposure_rpi_export_title\">Exportar</string>\n    <string name=\"pref_exposure_rpi_export_summary\">Exporta els identificadors recollits per analitzar extensament amb altra aplicació.</string>\n    <string name=\"pref_exposure_info_summary\">L\\'API de notificacions d\\'exposició permet que les aplicacions us notifiquin si heu estat exposat a algú que ha informat d\\'haver donat positiu.\\n\\nLa data, la durada i la intensitat del senyal associades a una exposició es compartiran amb l\\'aplicació corresponent.</string>\n    <string name=\"pref_exposure_rpis_details_summary\">Mentre l\\'API de notificació d\\'exposició està activada, el dispositiu recull identificadors passivament (anomenats identificadors de proximitat rotatius, o RPIs) dels dispositius propers.\\n\\nQuan els propietaris dels dispositius informen que han donat positiu, els seus identificadors es poden compartir. El dispositiu comprova si algun dels identificadors diagnosticats coneguts coincideix amb algun dels identificadors recollits i calcula el risc d\\'infecció.</string>\n    <string name=\"exposure_enable_switch\">Utilitzar notificacions d\\'exposició</string>\n    <string name=\"exposure_confirm_start_title\">Activar les notificacions d\\'exposició?</string>\n    <string name=\"exposure_confirm_start_summary\">El telèfon ha d\\'utilitzar Bluetooth per recopilar i compartir de manera segura les identificacions amb altres telèfons propers.\\n\\n<xliff:g example=\"Corona-Warn\">%1$s</xliff:g> us pot notificar si heu estat en contacte amb algú que ha informat que li han diagnosticat positiu.\\n\\nLa data, la durada i la intensitat del senyal associades a una exposició es compartiran amb l\\'aplicació.</string>\n    <string name=\"exposure_confirm_start_button\">Encén</string>\n    <string name=\"exposure_confirm_stop_title\">Apagar les notificacions d\\'exposició?</string>\n    <string name=\"exposure_confirm_stop_summary\">En desactivar les notificacions d\\'exposició ja no rebràs notificacions quan hageu estat en contacte amb algú que hagi informat d\\'un diagnòstic positiu.</string>\n    <string name=\"exposure_confirm_stop_button\">Apagar</string>\n    <string name=\"exposure_confirm_keys_title\">Compartir les vostres dades amb <xliff:g example=\"Corona-Warn\">%1$s</xliff:g>\\?</string>\n    <string name=\"exposure_confirm_keys_summary\">Les vostres identificacions dels darrers 14 dies s\\'utilitzaran per ajudar a notificar a altres persones que heu estat a prop d\\'una possible exposició.\\n\\nLa vostra identitat o el resultat de la prova no es compartiran amb altres persones.</string>\n    <string name=\"exposure_confirm_keys_button\">Compartir</string>\n    <string name=\"exposure_confirm_permission_description\"><xliff:g example=\"microG Services\">%1$s</xliff:g> necessita permisos addicionals.</string>\n    <string name=\"exposure_confirm_permission_button\">Concedir</string>\n    <string name=\"exposure_confirm_bluetooth_description\">El Bluetooth ha d\\'estar activat.</string>\n    <string name=\"exposure_confirm_location_description\">Es requereix accés d\\'ubicació.</string>\n    <string name=\"exposure_confirm_button\">Activar</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_title\">Es necessiten permisos nous</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_description\">Toqueu per concedir els permisos necessaris a les notificacions d\\'exposició</string>\n    <string name=\"exposure_grant_background_location_description\">Casi estem! Hauràs d\\'activar l\\'accés a la ubicació en segon pla seleccionant l\\'opció «Permetre sempre» a la pantalla següent. Després, prem el botó de tornada.</string>\n    <string name=\"exposure_grant_background_location_button\">Paràmetres d\\'actualització</string>\n</resources>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-cs/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=\"exposure_notify_off_title\">Oznámení o možném kontaktu nejsou aktivní</string>\n    <string name=\"exposure_notify_off_bluetooth\">Pro získávání oznámení o možném kontaktu musíte povolit Bluetooth.</string>\n    <string name=\"exposure_notify_off_location\">Pro získávání oznámení o možném kontaktu je vyžadován přístup k poloze.</string>\n    <string name=\"exposure_notify_off_nearby\">Oznámení o možném kontaktu vyžadují dodatečná oprávnění pro správnou funkčnost</string>\n    <string name=\"service_name_exposure\">Oznámení o možném kontaktu</string>\n    <string name=\"pref_exposure_enable_info_summary\">Pro zapnutí oznámení o možném kontaktu otevřete podporovanou aplikaci.</string>\n    <string name=\"prefcat_exposure_apps_title\">Aplikace používající oznámení o možném kontaktu</string>\n    <string name=\"pref_exposure_collected_rpis_title\">Nasbíraná ID</string>\n    <string name=\"pref_exposure_collected_rpis_summary\"><xliff:g example=\"63\">%1$d</xliff:g> ID v poslední hodině</string>\n    <string name=\"pref_exposure_advertising_id_title\">Aktuálně vysílané ID</string>\n    <string name=\"prefcat_exposure_app_report_title\">Nahlášené kontakty</string>\n    <string name=\"pref_exposure_app_report_updated_title\">Aktualizováno: <xliff:g example=\"dnes, 14:02\">%1$s</xliff:g></string>\n    <string name=\"pref_exposure_app_report_entry_time_short\">Méně než 5 minut</string>\n    <string name=\"pref_exposure_app_report_entry_time_about\">Asi <xliff:g example=\"13\">%1$d</xliff:g> minut</string>\n    <string name=\"pref_exposure_app_report_entry_distance_close\">blízký kontakt</string>\n    <string name=\"pref_exposure_app_report_entry_distance_far\">vzdálený kontakt</string>\n    <string name=\"pref_exposure_app_report_entry_combined\"><xliff:g example=\"Asi 12 minut\">%1$s</xliff:g>, <xliff:g example=\"vzdálený kontakt\">%2$s</xliff:g></string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_no\">Nenahlášeny žádné kontakty.</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_prefix\">Nahlášeno <xliff:g example=\"3\">%1$d</xliff:g> kontaktů:</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_line\"><xliff:g example=\"Včera, 12:00 - 14:00\">%1$s</xliff:g>, rizikové skóre <xliff:g example=\"99\">%2$d</xliff:g></string>\n    <string name=\"pref_exposure_app_api_usage_summary_line\"><xliff:g example=\"12\">%1$d</xliff:g> volání na <xliff:g example=\"provideDiagnosisKeys\">%2$s</xliff:g></string>\n    <string name=\"prefcat_exposure_rpis_histogram_title\"><xliff:g example=\"230\">%1$d</xliff:g> nasbíraných ID</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_no_records\">Žádné záznamy</string>\n    <string name=\"pref_exposure_rpi_delete_all_title\">Odstranit</string>\n    <string name=\"pref_exposure_rpi_delete_all_summary\">Odstranit všechna nasbíraná ID</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning\">Odstraněním nasbíraných ID znemožníte upozornění v případě, že byl v posledních 14 dnech diagnostikován některý z vašich kontaktů.</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning_confirm_button\">Přesto odstranit</string>\n    <string name=\"pref_exposure_rpi_export_title\">Exportovat</string>\n    <string name=\"pref_exposure_rpi_export_summary\">Exportovat nasbíraná ID pro rozšířenou analýzu v jiné aplikaci.</string>\n    <string name=\"exposure_enable_switch\">Používat oznámení o možném kontaktu</string>\n    <string name=\"exposure_confirm_start_title\">Zapnout oznámení o možném kontaktu?</string>\n    <string name=\"exposure_confirm_start_summary\">Váš telefon potřebuje používat Bluetooth pro bezpečné sbírání a sdílení ID s ostatními telefony, které jsou v okolí.\\n\\nAplikace <xliff:g example=\"eRouška\">%1$s</xliff:g> vám může oznámit, zda jste se setkali s někým, kdo byl nahlášen jako pozitivní.\\n\\nDatum, doba trvání a síla signálu spojené s kontaktem budou sdíleny s touto aplikací.</string>\n    <string name=\"exposure_confirm_start_button\">Zapnout</string>\n    <string name=\"exposure_confirm_stop_title\">Vypnout oznámení o možném kontaktu?</string>\n    <string name=\"exposure_confirm_stop_summary\">Po vypnutí oznámení o možném kontaktu již nebudete upozorněni, zda jste se setkali s někým, kdo byl nahlášen jako pozitivní.</string>\n    <string name=\"exposure_confirm_stop_button\">Vypnout</string>\n    <string name=\"exposure_confirm_keys_title\">Chcete sdílet vaše ID s aplikací <xliff:g example=\"eRouška\">%1$s</xliff:g>\\?</string>\n    <string name=\"exposure_confirm_keys_button\">Sdílet</string>\n    <string name=\"exposure_confirm_permission_description\"><xliff:g example=\"Služby microG\">%1$s</xliff:g> vyžadují dodatečná oprávnění.</string>\n    <string name=\"exposure_confirm_permission_button\">Udělit</string>\n    <string name=\"exposure_confirm_bluetooth_description\">Je třeba povolit Bluetooth.</string>\n    <string name=\"exposure_confirm_location_description\">Je vyžadován přístup k poloze.</string>\n    <string name=\"exposure_confirm_button\">Zapnout</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_description\">Klepněte pro udělení požadovaných oprávnění službe oznámení o možném kontaktu</string>\n    <string name=\"exposure_grant_background_location_description\">Skoro hotovo! Povolte prosím přístup k poloze na pozadí klepnutím na možnost„Povolit vždy“ na další obrazovce. Poté se vraťte zpět.</string>\n    <string name=\"exposure_notify_off_bluetooth_location\">Pro získávání oznámení o možném kontaktu je vyžadován přístup k Bluetooth a k poloze.</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_records\"><xliff:g example=\"0 - 50\">%1$s</xliff:g> ID za hodinu</string>\n    <string name=\"pref_exposure_error_bluetooth_off_title\">Zapnout Bluetooth</string>\n    <string name=\"pref_exposure_error_bluetooth_unsupported_summary\">Vaše zařízení bohužel není kompatibilní s oznámeními o možném kontaktu.</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_suffix\">Poznámka: rizikové skóre je definováno aplikací. Vysoká čísla mohou znamenat nízké riziko nebo naopak.</string>\n    <string name=\"pref_exposure_error_location_off_title\">Otevřít nastavení polohy</string>\n    <string name=\"pref_exposure_app_api_usage_title\">Využití API v posledních 14 dnech</string>\n    <string name=\"pref_exposure_info_summary\">Rozhraní API oznámení o možném kontaktu umožňuje aplikacím vás upozornit, pokud jste se setkali s někým, kdo byl nahlášen jako pozitivní.\n\\n\n\\nDatum, doba trvání a síla signálu spojené s kontaktem budou sdíleny s odpovídající aplikací.</string>\n    <string name=\"pref_exposure_error_bluetooth_no_advertise_summary\">Vaše zařízení je bohužel jen částečně kompatibilní s oznámeními o možném kontaktu. Budete upozorněni na rizikové kontakty, nebudete ale moci upozornit ostatní.</string>\n    <string name=\"pref_exposure_rpis_details_summary\">Při povoleném rozhraní API oznámení o možném kontaktu bude vaše zařízení pasivně získávat ID (nazývané Rolling Proximity Identifiers, neboli RPI) z okolních zařízení.\n\\n\n\\nJakmile bude majitel zařízení nahlášen jako pozitivní, může být sdíleno jeho ID. Vaše zařízení kontroluje, zda se některé ze známých ID shoduje s nasbíranými ID a vypočítá riziko vašeho nakažení.</string>\n    <string name=\"pref_exposure_app_last_report_summary_diagnosis_keys\">Zpracováno <xliff:g example=\"121031\">%1$d</xliff:g> diagnostických klíčů.</string>\n    <string name=\"exposure_confirm_keys_summary\">Vaše ID z posledních 14 dnů budou použita pro pomoc s upozorněním lidí, poblíž kterých jste se nacházeli, o možném kontaktu.\n\\n\n\\nVaše identita nebo výsledek testu nebudou s ostatními lidmi sdíleny.</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_title\">Vyžadována nová oprávnění</string>\n    <string name=\"exposure_grant_background_location_button\">Upravit nastavení</string>\n</resources>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-de/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"exposure_notify_off_title\">Expositionsbenachrichtigungen deaktiviert</string>\n    <string name=\"exposure_notify_off_bluetooth\">Bluetooth muss eingeschaltet sein, um Expositionsbenachrichtigungen zu nutzen.</string>\n    <string name=\"exposure_notify_off_location\">Standortzugriff muss eingeschaltet sein, um Expositionsbenachrichtigungen zu nutzen.</string>\n    <string name=\"exposure_notify_off_bluetooth_location\">Bluetooth und Standortzugriff müssen eingeschaltet sein, um Expositionsbenachrichtigungen zu nutzen.</string>\n    <string name=\"service_name_exposure\">Expositionsbenachrichtigungen</string>\n    <string name=\"pref_exposure_enable_info_summary\">Um Expositionsbenachrichtigungen zu aktivieren, öffne eine beliebige App, die diese unterstützt.</string>\n    <string name=\"pref_exposure_error_bluetooth_off_title\">Bluetooth einschalten</string>\n    <string name=\"pref_exposure_error_location_off_title\">Standortzugriff verwalten</string>\n    <string name=\"pref_exposure_error_bluetooth_unsupported_summary\">Leider ist dein Gerät nicht mit Expositionsbenachrichtigungen kompatibel.</string>\n    <string name=\"pref_exposure_error_bluetooth_no_advertise_summary\">Leider ist dein Gerät nicht vollständig mit Expositionsbenachrichtigungen kompatibel. Du wirst Warnungen über Risikokontakte erhalten, aber nicht andere benachrichtigen können.</string>\n    <string name=\"prefcat_exposure_apps_title\">Apps, die Expositionsbenachrichtigungen nutzen</string>\n    <string name=\"pref_exposure_collected_rpis_title\">Gesammelte IDs</string>\n    <string name=\"pref_exposure_collected_rpis_summary\"><xliff:g example=\"63\">%1$d</xliff:g> IDs in den letzten 60 Minuten</string>\n    <string name=\"pref_exposure_advertising_id_title\">Aktuell verwendete ID</string>\n    <string name=\"prefcat_exposure_app_report_title\">Gemeldete Begegnungen</string>\n    <string name=\"pref_exposure_app_report_updated_title\">Aktualisiert: <xliff:g example=\"Today, 14:02\">%1$s</xliff:g></string>\n    <string name=\"pref_exposure_app_report_entry_time_short\">Kürzer als 5 Minuten</string>\n    <string name=\"pref_exposure_app_report_entry_time_about\">Etwa <xliff:g example=\"13\">%1$d</xliff:g> Minuten</string>\n    <string name=\"pref_exposure_app_report_entry_distance_close\">nahe Begegnung</string>\n    <string name=\"pref_exposure_app_report_entry_distance_far\">entfernte Begegnung</string>\n    <string name=\"pref_exposure_app_report_entry_combined\"><xliff:g example=\"About 12 minutes\">%1$s</xliff:g>, <xliff:g example=\"distant exposure\">%2$s</xliff:g></string>\n    <string name=\"pref_exposure_app_last_report_summary_diagnosis_keys\"><xliff:g example=\"121031\">%1$d</xliff:g> Diagnoseschlüssel verarbeitet.</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_no\">Keine Risiko-Begegnung erfasst.</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_prefix\"><xliff:g example=\"3\">%1$d</xliff:g> Risiko-Begegnungen:</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_line\"><xliff:g example=\"Gestern, 12:00 - 12:30\">%1$s</xliff:g>, Risiko-Level <xliff:g example=\"99\">%2$d</xliff:g></string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_suffix\">Hinweis: Der Risiko-Level wird durch die App bestimmt. Hohe Werte können ein niedriges Risiko bedeuten oder andersherum.</string>\n    <string name=\"pref_exposure_app_api_usage_title\">Nutzung der API in den letzten 14 Tagen</string>\n    <string name=\"pref_exposure_app_api_usage_summary_line\"><xliff:g example=\"12\">%1$d</xliff:g> Aufrufe von <xliff:g example=\"provideDiagnosisKeys\">%2$s</xliff:g></string>\n    <string name=\"prefcat_exposure_rpis_histogram_title\"><xliff:g example=\"230\">%1$d</xliff:g> gesammelte IDs</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_no_records\">Keine Daten</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_records\"><xliff:g example=\"0 - 50\">%1$s</xliff:g> IDs pro Stunde</string>\n    <string name=\"pref_exposure_rpi_delete_all_title\">Löschen</string>\n    <string name=\"pref_exposure_rpi_delete_all_summary\">Alle gesammelten IDs löschen</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning\">Nach dem Löschen der gesammelten IDs kannst du nicht mehr informiert werden, falls einer deiner Kontakte der letzten 14 Tage positiv getested wurde.</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning_confirm_button\">Trotzdem löschen</string>\n    <string name=\"pref_exposure_rpi_export_title\">Exportieren</string>\n    <string name=\"pref_exposure_rpi_export_summary\">Exportiere gesammelte IDs zur weiteren Analyse mit einer anderen App.</string>\n    <string name=\"pref_exposure_info_summary\">Die API für Expositionsbenachrichtigungen ermöglicht es Apps, dich zu benachrichtigen, falls du Kontakt zu einer positiv getesteten Person hattest.\n\\n\n\\nDas Datum, die Zeitdauer und die Signalstärke, die dem Kontakt zugeordnet sind, werden mit der zugehörigen App geteilt.</string>\n    <string name=\"pref_exposure_rpis_details_summary\">Während die Exposure Notification API aktiviert ist, sammelt das Gerät passiv IDs (Rolling Proximity Identifiers bzw. RPIs) von Geräten in der Nähe.\\n\\nSobald die Eigentümer von Geräten positiv getestet wurden, können ihre IDs geteilt werden. Dein Gerät prüft, ob eine gespeicherte ID zu einer positiv getesteten Person gehört, und berechnet das Infektionsrisiko.</string>\n    <string name=\"exposure_enable_switch\">Expositionsbenachrichtigungen nutzen</string>\n    <string name=\"exposure_confirm_start_title\">Expositionsbenachrichtigungen einschalten?</string>\n    <string name=\"exposure_confirm_start_summary\">\"Dein Smartphone benötigt Bluetooth, um IDs von anderen Personen sicher zu teilen und zu speichern.\n\n<xliff:g example=\"Corona-Warn\">%1$s</xliff:g> kann dich benachrichtigen, falls du Kontakt zu einer positiv getesteten Person hattest.\n\nDas Datum, die Zeitdauer und die Signalstärke, die einem Kontakt zugeordnet wurden werden mit der App geteilt.\"</string>\n    <string name=\"exposure_confirm_start_button\">Einschalten</string>\n    <string name=\"exposure_confirm_stop_title\">Expositionsbenachrichtigungen ausschalten?</string>\n    <string name=\"exposure_confirm_stop_summary\">Nach dem Deaktivieren von Expositionsbenachrichtigungen wirst du nicht mehr benachrichtigt, falls du Kontakt mit einer positiv getesteten Person hattest.</string>\n    <string name=\"exposure_confirm_stop_button\">Deaktivieren</string>\n    <string name=\"exposure_confirm_keys_title\">IDs mit <xliff:g example=\"Corona-Warn\">%1$s</xliff:g> teilen?</string>\n    <string name=\"exposure_confirm_keys_summary\">\"Deine IDs der letzten Tage werden genutzt, um Nutzer, die in den letzten 14 Tagen mit dir Kontakt hatten, zu benachrichtigen.\n\nDeine Identität oder das Testergebnis werden nicht geteilt.\"</string>\n    <string name=\"exposure_confirm_keys_button\">Teilen</string>\n    <string name=\"exposure_confirm_permission_description\"><xliff:g example=\"microG Services\">%1$s</xliff:g> benötigt zusätzliche Berechtigungen.</string>\n    <string name=\"exposure_confirm_permission_button\">Erteilen</string>\n    <string name=\"exposure_confirm_bluetooth_description\">Bluetooth muss eingeschaltet sein.</string>\n    <string name=\"exposure_confirm_location_description\">Standortzugriff muss eingeschaltet sein.</string>\n    <string name=\"exposure_confirm_button\">Aktivieren</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_title\">Neue Berechtigung benötigt</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_description\">Tippe hier, um die erforderlichen Berechtigungen für Expositionsbenachrichtigungen zu erteilen</string>\n    <string name=\"exposure_grant_background_location_description\">Fast geschafft! Du musst den Zugriff auf den Standort im Hintergrund erlauben, indem du auf dem nächsten Bildschirm „Immer zulassen“ auswählst und dann hierher zurückkommst.</string>\n    <string name=\"exposure_grant_background_location_button\">Einstellungen Öffnen</string>\n    <string name=\"exposure_notify_off_nearby\">Expositionsbenachrichtigungen erfordern zusätzliche Berechtigungen, um zu funktionieren</string>\n</resources>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-eo/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources></resources>"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-es/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"exposure_notify_off_title\">Notificaciones de Exposición inactivas</string>\n    <string name=\"exposure_notify_off_bluetooth\">El Bluetooth debe estar activado para recibir notificaciones de exposición.</string>\n    <string name=\"exposure_notify_off_location\">El acceso a la ubicación es necesario para recibir las Notificaciones de Exposición.</string>\n    <string name=\"exposure_notify_off_bluetooth_location\">El acceso al Bluetooth y a la ubicación debe activarse para recibir notificaciones de exposición.</string>\n    <string name=\"service_name_exposure\">Notificaciones de Exposición</string>\n    <string name=\"pref_exposure_enable_info_summary\">Para activar las notificaciones de exposición, abra cualquier aplicación que las admita.</string>\n    <string name=\"pref_exposure_error_bluetooth_off_title\">Activar el Bluetooth</string>\n    <string name=\"pref_exposure_error_location_off_title\">Abrir Configuración de la ubicación</string>\n    <string name=\"pref_exposure_error_bluetooth_unsupported_summary\">Desafortunadamente, su dispositivo no es compatible con las Notificaciones de Exposición.</string>\n    <string name=\"pref_exposure_error_bluetooth_no_advertise_summary\">Desafortunadamente, su dispositivo solo es parcialmente compatible con las notificaciones de exposición. Puede recibir notificaciones de contactos de riesgo pero no podrá notificar a los demás.</string>\n    <string name=\"prefcat_exposure_apps_title\">Aplicaciones que utilizan Notificaciones de exposición</string>\n    <string name=\"pref_exposure_collected_rpis_title\">Identificaciones recogidas</string>\n    <string name=\"pref_exposure_collected_rpis_summary\"><xliff:g example=\"63\">%1$d</xliff:g> identificaciones en la última hora</string>\n    <string name=\"pref_exposure_advertising_id_title\">Identificación actualmente emitida</string>\n    <string name=\"prefcat_exposure_app_report_title\">Exposiciones reportadas</string>\n    <string name=\"pref_exposure_app_report_updated_title\">Actualizado: <xliff:g example=\"Hoy, 14:02\">%1$s</xliff:g></string>\n    <string name=\"pref_exposure_app_report_entry_time_short\">Menos de 5 minutos</string>\n    <string name=\"pref_exposure_app_report_entry_distance_close\">exposición cercana</string>\n    <string name=\"pref_exposure_app_report_entry_distance_far\">exposición lejana</string>\n    <string name=\"pref_exposure_app_report_entry_combined\"><xliff:g example=\"Alrededor de 12 minutes\">%1$s</xliff:g>, <xliff:g example=\"de exposición a distancia\">%2$s</xliff:g></string>\n    <string name=\"pref_exposure_app_report_entry_time_about\">Alrededor de <xliff:g example=\"13\">%1$d</xliff:g> minutos</string>\n    <string name=\"pref_exposure_app_last_report_summary_diagnosis_keys\">Procesadas <xliff:g example=\"121031\">%1$d</xliff:g> claves de diagnóstico.</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_no\">No se ha informado de ningún encuentro de exposición.</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_prefix\">Reportados <xliff:g example=\"3\">%1$d</xliff:g> encuentros de exposición:</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_line\"><xliff:g example=\"Ayer, 12:00 - 14:00\">%1$s</xliff:g>, puntuación de riesgo <xliff:g example=\"99\">%2$d</xliff:g></string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_suffix\">Nota: La puntuación de riesgo está definida por la aplicación. Los números altos pueden referirse a un riesgo bajo o viceversa.</string>\n    <string name=\"pref_exposure_app_api_usage_title\">El uso de la API en los últimos 14 días</string>\n    <string name=\"pref_exposure_app_api_usage_summary_line\"><xliff:g example=\"12\">%1$d</xliff:g> peticiones a <xliff:g example=\"provideDiagnosisKeys\">%2$s</xliff:g></string>\n    <string name=\"prefcat_exposure_rpis_histogram_title\"><xliff:g example=\"230\">%1$d</xliff:g> identificaciones recogidas</string>\n    <string name=\"pref_exposure_rpi_delete_all_title\">Eliminar</string>\n    <string name=\"pref_exposure_rpi_delete_all_summary\">Eliminar todas las identificaciones recogidas</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning\">Eliminar las identificaciones recogidas hará imposible notificarle en caso de que alguno de sus contactos de los últimos 14 días sea diagnosticado.</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning_confirm_button\">Eliminar de todas formas</string>\n    <string name=\"pref_exposure_rpi_export_title\">Exportar</string>\n    <string name=\"pref_exposure_rpi_export_summary\">Exportar identificaciones recogidas para su análisis ampliado con otra aplicación.</string>\n    <string name=\"pref_exposure_info_summary\">La API de notificaciones de exposición permite que las aplicaciones le notifiquen si ha estado expuesto a alguien con diagnóstico positivo.\\n\\nLa fecha, la duración y la intensidad de la señal asociadas a una exposición se compartirán con la app correspondiente.</string>\n    <string name=\"pref_exposure_rpis_details_summary\">Mientras la API de notificación de exposición está activada, el dispositivo recopila de forma pasiva identificadores (denominados identificadores de proximidad móviles o RPI) de los dispositivos cercanos.\\n\\nCuando los propietarios de los dispositivos informan de un diagnóstico positivo, sus ID pueden compartirse. Su dispositivo comprueba si alguno de los ID diagnosticados conocidos coincide con alguno de los ID recopilados y calcula su riesgo de infección.</string>\n    <string name=\"exposure_enable_switch\">Usar notificaciones de exposición</string>\n    <string name=\"exposure_confirm_start_title\">¿Encender las Notificaciones de Exposición?</string>\n    <string name=\"exposure_confirm_start_summary\">El teléfono debe usar el Bluetooth para recopilar y compartir de manera segura las identificaciones con otros teléfonos que estén cerca.\\n\\n<xliff:g example=\"Corona-Warn\">%1$s</xliff:g> puede notificarle si se ha expuesto a alguien que informó ser diagnosticado como positivo.\\n\\nLa fecha, la duración y la intensidad de la señal asociadas a una exposición se compartirán con la aplicación.</string>\n    <string name=\"exposure_confirm_start_button\">Encender</string>\n    <string name=\"exposure_confirm_stop_title\">¿Apagar las notificaciones de exposición?</string>\n    <string name=\"exposure_confirm_stop_summary\">Después de desactivar las Notificaciones de Exposición, ya no se le notificará cuando haya estado expuesto a alguien que haya informado de que ha sido diagnosticado como positivo.</string>\n    <string name=\"exposure_confirm_stop_button\">Apagar</string>\n    <string name=\"exposure_confirm_keys_title\">¿Quiere compartir sus identificaciones con <xliff:g example=\"Corona-Warn\">%1$s</xliff:g>\\?</string>\n    <string name=\"exposure_confirm_keys_summary\">Sus identificaciones de los últimos 14 días se utilizarán para ayudar a notificar a otras personas que ha estado cerca de una posible exposición.\\n\\nSu identidad o el resultado de la prueba no se compartirán con otras personas.</string>\n    <string name=\"exposure_confirm_keys_button\">Compartir</string>\n    <string name=\"exposure_confirm_permission_description\"><xliff:g example=\"microG Services\">%1$s</xliff:g> necesita permisos adicionales.</string>\n    <string name=\"exposure_confirm_permission_button\">Conceder</string>\n    <string name=\"exposure_confirm_bluetooth_description\">El Bluetooth debe estar activado.</string>\n    <string name=\"exposure_confirm_location_description\">Se requiere acceso a la ubicación.</string>\n    <string name=\"exposure_confirm_button\">Activar</string>\n    <string name=\"exposure_grant_background_location_description\">Ya casi termina. Debe activar el acceso a la ubicación en segundo plano seleccionando la opción «Permitir todo el tiempo» en la próxima pantalla. Luego vuelva aquí.</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_no_records\">Sin registros</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_records\"><xliff:g example=\"0 - 50\">%1$s</xliff:g> IDs por hora</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_title\">Se requieren nuevos permisos</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_description\">Pulse para conceder los permisos necesarios para mostrar notificaciones</string>\n    <string name=\"exposure_notify_off_nearby\">Las notificaciones de exposición requieren permisos adicionales para funcionar</string>\n    <string name=\"exposure_grant_background_location_button\">Actualizar configuración</string>\n</resources>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-fa/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=\"pref_exposure_app_last_report_summary_diagnosis_keys\">پردازش <xliff:g example=\"121031\">%1$d</xliff:g> کلید تشخیص.</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_prefix\">گزارش <xliff:g example=\"3\">%1$d</xliff:g> مواجهه نزدیکی:</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_line\"><xliff:g example=\"Yesterday, 12:00 - 14:00\">%1$s</xliff:g>، امتیاز خطر <xliff:g example=\"99\">%2$d</xliff:g></string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_suffix\">یادداشت: امتیاز خطر توسط برنامه تعریف می‌شود. اعداد بالا ممکن است به خطر کم یا وارون اشاره کنند.</string>\n    <string name=\"pref_exposure_app_api_usage_title\">استفاده از API در ۱۴ روز گذشته</string>\n    <string name=\"prefcat_exposure_rpis_histogram_title\"><xliff:g example=\"230\">%1$d</xliff:g> شناسه گردآوری‌شده</string>\n    <string name=\"pref_exposure_app_api_usage_summary_line\"><xliff:g example=\"12\">%1$d</xliff:g> فراخوانی به <xliff:g example=\"provideDiagnosisKeys\">%2$s</xliff:g></string>\n    <string name=\"pref_exposure_rpis_histogram_legend_no_records\">بدون ثبت</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_records\"><xliff:g example=\"0 - 50\">%1$s</xliff:g> شناسه در ساعت</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning_confirm_button\">به‌هرحال پاک کن</string>\n    <string name=\"pref_exposure_rpi_export_title\">برون‌ریزی</string>\n    <string name=\"pref_exposure_rpi_export_summary\">برون‌ریزی شناسه‌های گردآوری‌شده برای تحلیل پیشرفته با برنامه دیگر.</string>\n    <string name=\"exposure_notify_off_nearby\">آگاه‌سازهای نزدیکی برای کارکرد به دسترسی‌های افزوده نیاز دارند</string>\n    <string name=\"pref_exposure_advertising_id_title\">شناسه در حال پخش</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_no\">هیچ مواجهه نزدیکی گزارش نشده است.</string>\n    <string name=\"pref_exposure_rpi_delete_all_title\">پاک کردن</string>\n    <string name=\"pref_exposure_rpi_delete_all_summary\">پاک کردن همه شناسه‌های گردآوری‌شده</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning\">پاک کردن شناسه‌های گردآوری‌شده، آگاه‌سازی شما را در صورت تشخیص مثبت یکی از تماس‌های ۱۴ روز گذشته غیرممکن می‌کند.</string>\n    <string name=\"exposure_enable_switch\">استفاده از آگاه‌سازهای نزدیکی</string>\n    <string name=\"pref_exposure_info_summary\">API آگاه‌سازهای نزدیکی به برنامه‌ها اجازه می‌دهد اگر با فردی که تشخیص مثبت گزارش کرده مواجه شده‌اید، شما را آگاه کنند.\\n\\nتاریخ، مدت، و قدرت سیگنال مرتبط با مواجهه با برنامه مربوطه هم‌رسانی خواهد شد.</string>\n    <string name=\"exposure_confirm_stop_title\">آگاه‌سازهای نزدیکی خاموش شوند؟</string>\n    <string name=\"exposure_confirm_keys_button\">هم‌رسانی</string>\n    <string name=\"exposure_confirm_location_description\">دسترسی به مکان لازم است.</string>\n    <string name=\"exposure_confirm_button\">فعال کردن</string>\n    <string name=\"exposure_notify_off_title\">آگاه‌سازهای نزدیکی غیرفعال</string>\n    <string name=\"exposure_notify_off_bluetooth\">برای دریافت آگاه‌سازهای نزدیکی، بلوتوث باید فعال باشد.</string>\n    <string name=\"exposure_notify_off_location\">برای دریافت آگاه‌سازهای نزدیکی، دسترسی به مکان لازم است.</string>\n    <string name=\"exposure_notify_off_bluetooth_location\">برای دریافت آگاه‌سازهای نزدیکی، بلوتوث و دسترسی به مکان باید فعال باشند.</string>\n    <string name=\"service_name_exposure\">آگاه‌سازهای نزدیکی</string>\n    <string name=\"pref_exposure_enable_info_summary\">برای فعال‌سازی آگاه‌سازهای نزدیکی، هر برنامه‌ای که از آن پشتیبانی می‌کند را باز کنید.</string>\n    <string name=\"pref_exposure_error_bluetooth_off_title\">فعال‌سازی بلوتوث</string>\n    <string name=\"pref_exposure_error_location_off_title\">باز کردن تنظیمات مکان</string>\n    <string name=\"pref_exposure_error_bluetooth_unsupported_summary\">متأسفانه، دستگاه شما با آگاه‌سازهای نزدیکی سازگار نیست.</string>\n    <string name=\"pref_exposure_error_bluetooth_no_advertise_summary\">متأسفانه، دستگاه شما تنها به‌صورت جزئی با آگاه‌سازهای نزدیکی سازگار است. می‌توانید برای تماس‌های پرخطر آگاه شوید، اما نمی‌توانید دیگران را آگاه کنید.</string>\n    <string name=\"prefcat_exposure_apps_title\">برنامه‌های استفاده‌کننده از آگاه‌سازهای نزدیکی</string>\n    <string name=\"pref_exposure_collected_rpis_title\">شناسه‌های گردآوری‌شده</string>\n    <string name=\"pref_exposure_collected_rpis_summary\"><xliff:g example=\"63\">%1$d</xliff:g> شناسه در ساعت گذشته</string>\n    <string name=\"prefcat_exposure_app_report_title\">گزارش‌های نزدیکی</string>\n    <string name=\"pref_exposure_app_report_updated_title\">به‌روزرسانی‌شده: <xliff:g example=\"Today, 14:02\">%1$s</xliff:g></string>\n    <string name=\"pref_exposure_app_report_entry_time_short\">کمتر از ۵ دقیقه</string>\n    <string name=\"pref_exposure_app_report_entry_time_about\">حدود <xliff:g example=\"13\">%1$d</xliff:g> دقیقه</string>\n    <string name=\"pref_exposure_app_report_entry_distance_close\">نزدیکی نزدیک</string>\n    <string name=\"pref_exposure_app_report_entry_distance_far\">نزدیکی دور</string>\n    <string name=\"pref_exposure_app_report_entry_combined\"><xliff:g example=\"About 12 minutes\">%1$s</xliff:g>، <xliff:g example=\"distant exposure\">%2$s</xliff:g></string>\n    <string name=\"exposure_confirm_start_title\">آگاه‌سازهای نزدیکی روشن شوند؟</string>\n    <string name=\"exposure_confirm_start_button\">روشن کردن</string>\n    <string name=\"exposure_confirm_stop_summary\">پس از غیرفعال کردن آگاه‌سازهای نزدیکی، دیگر وقتی با فردی که تشخیص مثبت گزارش کرده مواجه شده‌اید، آگاه نخواهید شد.</string>\n    <string name=\"exposure_confirm_stop_button\">خاموش کردن</string>\n    <string name=\"exposure_confirm_keys_title\">شناسه‌های شما با <xliff:g example=\"Corona-Warn\">%1$s</xliff:g> هم‌رسانی شوند؟</string>\n    <string name=\"exposure_confirm_permission_description\"><xliff:g example=\"microG Services\">%1$s</xliff:g> به دسترسی‌های افزوده نیاز دارد.</string>\n    <string name=\"exposure_confirm_bluetooth_description\">بلوتوث باید فعال باشد.</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_title\">نیاز به دسترسی‌های جدید</string>\n    <string name=\"exposure_grant_background_location_description\">تقریباً آماده است! باید دسترسی به مکان در پس‌زمینه را با انتخاب گزینه «همیشه اجازه بده» در صفحه بعدی فعال کنید. سپس بازگشت کنید.</string>\n    <string name=\"exposure_grant_background_location_button\">به‌روزرسانی تنظیمات</string>\n    <string name=\"pref_exposure_rpis_details_summary\">هنگامی که API آگاه‌سازهای نزدیکی فعال است، دستگاه شما به‌صورت غیرفعال شناسه‌ها (به‌نام شناسه‌های نزدیکی چرخشی یا RPIs) را از دستگاه‌های نزدیک گردآوری می‌کند\\n\\n وقتی صاحبان دستگاه تشخیص مثبت گزارش کنند، شناسه‌هایشان می‌توانند هم‌رسانی شوند. دستگاه شما بررسی می‌کند که آیا شناسه‌های تشخیص‌شده با شناسه‌های گردآوری‌شده هم‌خوانی دارند و خطر عفونت شما را محاسبه می‌کند.</string>\n    <string name=\"exposure_confirm_start_summary\">تلفن شما برای گردآوری و هم‌رسانی امن شناسه‌ها با تلفن‌های نزدیک نیاز به استفاده از بلوتوث دارد.\\n\\n<xliff:g example=\"Corona-Warn\">%1$s</xliff:g> می‌تواند اگر با فردی که تشخیص مثبت گزارش کرده مواجه شده‌اید، شما را آگاه کند.\\n\\nتاریخ، مدت، و قدرت سیگنال مرتبط با مواجهه با برنامه هم‌رسانی خواهد شد.</string>\n    <string name=\"exposure_confirm_keys_summary\">شناسه‌های شما از ۱۴ روز گذشته برای کمک به آگاه‌سازی دیگران که نزدیک شما بوده‌اند درباره مواجهه احتمالی استفاده خواهند شد.\\n\\nهویت یا نتیجه آزمایش شما با دیگران هم‌رسانی نخواهد شد.</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_description\">برای دادن دسترسی‌های لازم به آگاه‌سازهای نزدیکی بزنید</string>\n    <string name=\"exposure_confirm_permission_button\">دادن</string>\n</resources>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-fi/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources></resources>"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-fil/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources></resources>"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-fr/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=\"exposure_notify_off_title\">Notifications d\\'exposition inactives</string>\n    <string name=\"pref_exposure_error_bluetooth_no_advertise_summary\">Malheureusement, votre appareil est seulement partiellement compatible avec les notifications d\\'exposition. Vous pouvez être notifié des contacts à risque mais vous ne pourrez pas notifier les autres.</string>\n    <string name=\"pref_exposure_collected_rpis_summary\"><xliff:g example=\"63\">%1$d</xliff:g> IDs dans la dernière heure</string>\n    <string name=\"exposure_notify_off_bluetooth\">Le Bluetooth doit être activé pour recevoir les notifications d\\'exposition.</string>\n    <string name=\"exposure_notify_off_location\">L\\'accès à la localisation est nécessaire pour recevoir les notifications d\\'exposition.</string>\n    <string name=\"exposure_notify_off_bluetooth_location\">Le Bluetooth et l\\'accès à la localisation doivent être activés pour recevoir les notifications d\\'exposition.</string>\n    <string name=\"exposure_notify_off_nearby\">Les notifications d\\'exposition nécessitent des permissions additionnelles pour fonctionner</string>\n    <string name=\"service_name_exposure\">Notifications d\\'exposition</string>\n    <string name=\"pref_exposure_error_location_off_title\">Ouvrir les paramètres de localisation</string>\n    <string name=\"pref_exposure_error_bluetooth_off_title\">Activer le Bluetooth</string>\n    <string name=\"pref_exposure_enable_info_summary\">Pour activer les notifications d\\'exposition, ouvrez une appli les prenant en charge.</string>\n    <string name=\"pref_exposure_error_bluetooth_unsupported_summary\">Malheureusement, votre appareil n\\'est pas compatible avec les notifications d\\'exposition.</string>\n    <string name=\"prefcat_exposure_apps_title\">Applis utilisant les notifications d\\'exposition</string>\n    <string name=\"pref_exposure_collected_rpis_title\">IDs collectés</string>\n    <string name=\"pref_exposure_app_report_entry_time_about\">Il y a <xliff:g example=\"13\">%1$d</xliff:g> minutes environ</string>\n    <string name=\"pref_exposure_app_last_report_summary_diagnosis_keys\">Traité <xliff:g example=\"121031\">%1$d</xliff:g> clés de diagnostic.</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_prefix\"><xliff:g example=\"3\">%1$d</xliff:g> expositions à risque rapportées :</string>\n    <string name=\"exposure_confirm_keys_title\">Partager vos IDs avec <xliff:g example=\"Corona-Warn\">%1$s</xliff:g> ?</string>\n    <string name=\"exposure_confirm_permission_description\"><xliff:g example=\"microG Services\">%1$s</xliff:g> nécessite des autorisations supplémentaires.</string>\n    <string name=\"pref_exposure_app_report_updated_title\">Mis à jour : <xliff:g example=\"Aujourd'hui, 14:02\">%1$s</xliff:g></string>\n    <string name=\"pref_exposure_app_report_entry_combined\"><xliff:g example=\"Il y a 12 minutes environ\">%1$s</xliff:g>, <xliff:g example=\"exposition distante\">%2$s</xliff:g></string>\n    <string name=\"pref_exposure_rpis_histogram_legend_records\"><xliff:g example=\"0 - 50\">%1$s</xliff:g> IDs par heure</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_line\"><xliff:g example=\"Hier, 12:00 - 14:00\">%1$s</xliff:g>, score de risque<xliff:g example=\"99\">%2$d</xliff:g></string>\n    <string name=\"pref_exposure_app_api_usage_summary_line\"><xliff:g example=\"12\">%1$d</xliff:g> appelle à <xliff:g example=\"provideDiagnosisKeys\">%2$s</xliff:g></string>\n    <string name=\"prefcat_exposure_rpis_histogram_title\"><xliff:g example=\"230\">%1$d</xliff:g> IDs collectés</string>\n    <string name=\"exposure_confirm_start_summary\">Votre téléphone a besoin d\\'utiliser le Bluetooth pour collecter et partager de manière sécurisée les IDs avec les autres appareils à proximité.\\n\\n<xliff:g example=\"Corona-Warn\">%1$s</xliff:g> peut vous notifier si vous avez été exposé à une personne ayant indiqué un diagnostic positif. \\n\\nLa date, la durée et la force du signal liées à une exposition seront partagées avec cette application.</string>\n    <string name=\"exposure_confirm_stop_summary\">En désactivant les Notifications d’exposition, vous ne serez plus informé si vous avez été exposé à une personne ayant indiqué un diagnostic positif.</string>\n    <string name=\"exposure_confirm_button\">Activer</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_title\">Nouvelles autorisations nécessaires</string>\n    <string name=\"pref_exposure_advertising_id_title\">ID actuellement diffusé</string>\n    <string name=\"pref_exposure_app_report_entry_time_short\">Moins de 5 minutes</string>\n    <string name=\"pref_exposure_app_report_entry_distance_far\">Exposition distante</string>\n    <string name=\"pref_exposure_app_report_entry_distance_close\">Exposition proche</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_description\">Appuyez pour accorder les autorisations nécessaires aux Notifications d\\'exposition</string>\n    <string name=\"prefcat_exposure_app_report_title\">Expositions rapportées</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_no\">Pas de rencontres à risque rapportées.</string>\n    <string name=\"pref_exposure_app_api_usage_title\">Usage de l\\'API sur les 14 derniers jours</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_suffix\">Note : Le score de risque est défini par l\\'appli. Une valeur élevée peut faire référence à un risque faible et vice-versa.</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_no_records\">Pas d\\'enregistrements</string>\n    <string name=\"pref_exposure_rpi_delete_all_title\">Supprimer</string>\n    <string name=\"pref_exposure_rpi_delete_all_summary\">Supprimer tous les IDs collectés</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning\">La suppression des IDs collectés rendra impossible de vous informer en cas de diagnostic positif d\\'un contact sur les 14 derniers jours.</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning_confirm_button\">Supprimer quand même</string>\n    <string name=\"pref_exposure_rpi_export_title\">Exporter</string>\n    <string name=\"pref_exposure_rpi_export_summary\">Exporter les IDs collectés pour analyse étendue via une autre appli.</string>\n    <string name=\"pref_exposure_info_summary\">L\\'API Notifications d\\'exposition permet aux applis de vous informer si vous avez été exposé à une personne ayant indiqué un diagnostique positif.\n\\n\n\\nLa date, la durée et la force du signal liées à une exposition seront partagées avec l\\'appli correspondante.</string>\n    <string name=\"pref_exposure_rpis_details_summary\">Quand l\\'API Notifications d\\'exposition est activée, votre appareil collecte de manière passive les IDs (appelés identifiants roulants de proximité) des appareils à proximité.\n\\n\n\\nLorsque des utilisateurs indiquent un diagnostic positif, leur ID peut être partagé. Votre appareil compare les IDs collectés aux IDs diagnostiqués positifs connus et calcule votre risque d\\'infection.</string>\n    <string name=\"exposure_enable_switch\">Utiliser les Notifications d\\'exposition</string>\n    <string name=\"exposure_confirm_start_title\">Activer les Notifications d\\'exposition ?</string>\n    <string name=\"exposure_confirm_start_button\">Activer</string>\n    <string name=\"exposure_confirm_stop_title\">Désactiver les Notifications d\\'exposition ?</string>\n    <string name=\"exposure_confirm_stop_button\">Désactiver</string>\n    <string name=\"exposure_confirm_keys_summary\">Vos IDs des 14 derniers jours seront utilisés dans le but d\\'informer les autres que vous avez été proche d\\'une exposition potentielle.\n\\n\n\\nVotre identité ou vos résultats de test ne seront pas partagés avec d\\'autres personnes.</string>\n    <string name=\"exposure_confirm_keys_button\">Partager</string>\n    <string name=\"exposure_confirm_permission_button\">Accorder</string>\n    <string name=\"exposure_confirm_bluetooth_description\">Le Bluetooth doit être activé.</string>\n    <string name=\"exposure_confirm_location_description\">L\\'accès à la localisation est nécessaire.</string>\n    <string name=\"exposure_grant_background_location_description\">On y est presque ! Vous aurez besoin d\\'activer la localisation en arrière-plan en sélectionnant \\\"Toujours autorisé\\\" sur l\\'écran suivant. Puis revenez en arrière.</string>\n    <string name=\"exposure_grant_background_location_button\">Modifier les paramètres</string>\n</resources>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-ga/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=\"pref_exposure_error_bluetooth_unsupported_summary\">Ar an drochuair, níl do ghléas comhoiriúnach le Fógraí Nochta.</string>\n    <string name=\"pref_exposure_collected_rpis_title\">Aitheantas bailithe</string>\n    <string name=\"pref_exposure_app_report_entry_distance_close\">nochtadh in aice láimhe</string>\n    <string name=\"pref_exposure_app_report_entry_distance_far\">nochtadh i bhfad i gcéin</string>\n    <string name=\"pref_exposure_app_last_report_summary_diagnosis_keys\">Próiseáladh <xliff:g example=\"121031\">%1$d</xliff:g> eochracha diagnóis.</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_no\">Níor tuairiscíodh aon teagmháil nochta.</string>\n    <string name=\"prefcat_exposure_rpis_histogram_title\"><xliff:g example=\"230\">%1$d</xliff:g> IDs bailithe</string>\n    <string name=\"pref_exposure_rpi_delete_all_summary\">Scrios gach aitheantas bailithe</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning_confirm_button\">Scrios mar sin féin</string>\n    <string name=\"exposure_confirm_start_button\">Cas ar</string>\n    <string name=\"exposure_confirm_stop_title\">An bhfuil fonn ort Fógraí Nochta a mhúchadh?</string>\n    <string name=\"exposure_confirm_stop_summary\">Tar éis Fógraí Nochta a dhíchumasú, ní thabharfar fógra duit a thuilleadh nuair a nochtaíodh tú do dhuine a thuairiscigh go raibh diagnóis deimhneach aige.</string>\n    <string name=\"exposure_confirm_bluetooth_description\">Ní mór Bluetooth a chumasú.</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_description\">Tapáil chun na ceadanna riachtanacha d\\'Fhógraí Nochta a dheonú</string>\n    <string name=\"pref_exposure_info_summary\">Ligeann API Fógraí Nochta aipeanna fógra a thabhairt duit má bhí tú nochta do dhuine a thuairiscigh go raibh diagnóis deimhneach aige.\n\\n\n\\nRoinnfear an dáta, an fad agus an neart comhartha a bhaineann le nochtadh leis an aip chomhfhreagrach.</string>\n    <string name=\"exposure_notify_off_bluetooth\">Ní mór Bluetooth a chumasú chun Fógraí Nochta a fháil.</string>\n    <string name=\"exposure_notify_off_title\">Fógraí Nochta neamhghníomhach</string>\n    <string name=\"exposure_notify_off_location\">Teastaíonn rochtain ar shuíomh chun Fógraí Nochta a fháil.</string>\n    <string name=\"exposure_notify_off_bluetooth_location\">Ní mór rochtain Bluetooth agus Suíomh a chumasú chun Fógraí Nochta a fháil.</string>\n    <string name=\"service_name_exposure\">Fógraí Nochta</string>\n    <string name=\"exposure_notify_off_nearby\">Teastaíonn ceadanna breise ó Fhógraí Nochta chun oibriú</string>\n    <string name=\"pref_exposure_error_bluetooth_off_title\">Cumasaigh Bluetooth</string>\n    <string name=\"pref_exposure_enable_info_summary\">Chun Fógraí Nochta a chumasú, oscail aon aip a thacaíonn leis.</string>\n    <string name=\"pref_exposure_error_location_off_title\">Oscail socruithe Suíomh</string>\n    <string name=\"pref_exposure_app_api_usage_summary_line\">Glaonn <xliff:g example=\"12\">%1$d</xliff:g> chuig <xliff:g example=\"soláthraighEochrachaDiagnóisithe\">%2$s</xliff:g></string>\n    <string name=\"pref_exposure_error_bluetooth_no_advertise_summary\">Ar an drochuair, níl do ghléas comhoiriúnach ach go páirteach le Fógraí Nochta. Is féidir tú a chur ar an eolas le haghaidh teagmhálaithe riosca ach ní bheidh tú in ann fógra a thabhairt do dhaoine eile.</string>\n    <string name=\"prefcat_exposure_apps_title\">Aipeanna a úsáideann Fógraí Nochta</string>\n    <string name=\"pref_exposure_collected_rpis_summary\"><xliff:g example=\"63\">%1$d</xliff:g> aitheantais san uair dheireanach</string>\n    <string name=\"pref_exposure_advertising_id_title\">Aitheantas arna chraoladh faoi láthair</string>\n    <string name=\"prefcat_exposure_app_report_title\">Nochtuithe tuairiscithe</string>\n    <string name=\"pref_exposure_app_report_updated_title\">Nuashonraithe: <xliff:g example=\"Inniu, 14:02\">%1$s</xliff:g></string>\n    <string name=\"pref_exposure_app_report_entry_time_short\">Níos lú ná 5 nóiméad</string>\n    <string name=\"pref_exposure_app_report_entry_time_about\">Timpeall <xliff:g example=\"13\">%1$d</xliff:g> nóiméad</string>\n    <string name=\"pref_exposure_app_report_entry_combined\"><xliff:g example=\"Thart ar 12 nóiméad\">%1$s</xliff:g>, <xliff:g example=\"nochtadh i bhfad i gcéin\">%2$s</xliff:g></string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_prefix\">Tuairiscíodh gur tharla nochtadh <xliff:g example=\"3\">%1$d</xliff:g>:</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_line\"><xliff:g example=\"Inné, 12:00 - 14:00\">%1$s</xliff:g>, scór riosca <xliff:g example=\"99\">%2$d</xliff:g></string>\n    <string name=\"pref_exposure_rpis_histogram_legend_no_records\">Uimh taifid</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_suffix\">Nóta: Tá an scór riosca sainmhínithe ag an app. Is féidir le huimhreacha arda tagairt do riosca íseal nó vice-versa.</string>\n    <string name=\"pref_exposure_app_api_usage_title\">Úsáid API le 14 lá anuas</string>\n    <string name=\"exposure_confirm_start_title\">Cuir Fógraí Nochta ar siúl?</string>\n    <string name=\"exposure_confirm_keys_title\">Comhroinn do chuid aitheantais le <xliff:g example=\"Corona-Warn\">%1$s</xliff:g>\\?</string>\n    <string name=\"exposure_confirm_keys_button\">Comhroinn</string>\n    <string name=\"exposure_confirm_permission_description\">Tá ceadanna breise ag teastáil ó <xliff:g example=\"MicroG Services\">%1$s</xliff:g>.</string>\n    <string name=\"exposure_confirm_permission_button\">Deontas</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_title\">Ceadanna Nua ag teastáil</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_records\"><xliff:g example=\"0 - 50\">%1$s</xliff:g> aitheantais in aghaidh na huaire</string>\n    <string name=\"pref_exposure_rpi_delete_all_title\">Scrios</string>\n    <string name=\"pref_exposure_rpi_export_title\">Easpórtáil</string>\n    <string name=\"exposure_confirm_start_summary\">Caithfidh do ghuthán Bluetooth a úsáid chun aitheantóirí a bhailiú agus a roinnt go slán le fóin eile atá in aice láimhe.\\n\\nIs féidir le <xliff:g example=\"Corona-Warn\">%1$s</xliff:g> fógra a thabhairt duit má bhí tú nochtaithe do dhuine a thuairiscigh go raibh diagnóis dhearfach aige.\\n\\nRoinnfear an dáta, an fad agus neart an chomhartha a bhaineann le nochtadh leis an aip.</string>\n    <string name=\"exposure_confirm_keys_summary\">Úsáidfear d\\'aitheantais le 14 lá anuas chun cabhrú le daoine eile a chur ar an eolas go raibh tú gar do nochtadh féideartha.\n\\n\n\\nNí roinnfear d\\'aitheantas nó toradh tástála le daoine eile.</string>\n    <string name=\"exposure_confirm_location_description\">Tá rochtain suímh ag teastáil.</string>\n    <string name=\"exposure_confirm_button\">Cumasaigh</string>\n    <string name=\"exposure_grant_background_location_description\">Beagnach ann! Beidh ort rochtain ar shuíomh cúlra a chumasú tríd an rogha \\'Ceadaigh an t-am ar fad\\' a roghnú ar an gcéad scáileán eile. Ansin brúigh ar ais.</string>\n    <string name=\"exposure_grant_background_location_button\">Nuashonraigh Socruithe</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning\">Má scriosann tú na haitheantais a bailíodh ní bheidh sé indéanta fógra a thabhairt duit i gcás go ndéanfar diagnóis ar aon duine de do theagmhálaithe le 14 lá anuas.</string>\n    <string name=\"pref_exposure_rpi_export_summary\">Easpórtáil aitheantais bailithe le haghaidh anailíse leathnaithe le haip eile.</string>\n    <string name=\"pref_exposure_rpis_details_summary\">Cé go bhfuil an API Fógra Nochtadh cumasaithe, bailíonn do ghléas aitheantais go héighníomhach (ar a dtugtar Aitheantóirí Cóngaracht Rollta, nó RPIanna) ó ghléasanna in aice láimhe.\n\\n\n\\nNuair a thuairiscíonn úinéirí gléasanna go bhfuil siad dearfach, is féidir a n-aitheantais a roinnt. Seiceálann do ghléas má mheaitseálann aon cheann de na haitheantais aitheanta aon cheann de na haitheantais a bailíodh agus ríomhann sé do riosca ionfhabhtaithe.</string>\n    <string name=\"exposure_enable_switch\">Úsáid Fógraí Nochta</string>\n    <string name=\"exposure_confirm_stop_button\">Múch</string>\n</resources>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-hu/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"exposure_notify_off_bluetooth\">A Bluetooth be kell legyen kapcsolva, hogy kitettségi értesítéseket kapjon.</string>\n    <string name=\"exposure_notify_off_title\">Kitettségi értesítés inaktív</string>\n    <string name=\"exposure_notify_off_location\">Helyadatok engedély szükséges a kitettségi értesítések fogadásához.</string>\n    <string name=\"exposure_notify_off_bluetooth_location\">Bluetooth és hely hozzáférés be kell legyen kapcsolva, hogy kitettségi értesítéseket kapj.</string>\n</resources>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-in/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=\"exposure_notify_off_title\">Notifikasi Paparan tidak aktif</string>\n    <string name=\"exposure_notify_off_bluetooth\">Bluetooth harus diaktifkan untuk menerima Notifikasi Paparan.</string>\n    <string name=\"exposure_notify_off_location\">Akses lokasi diperlukan untuk menerima Pemberitahuan Paparan.</string>\n    <string name=\"exposure_notify_off_bluetooth_location\">Bluetooth dan akses lokasi harus diaktifkan untuk menerima pemberitahuan paparan.</string>\n    <string name=\"exposure_notify_off_nearby\">Pemberitahuan Paparan memerlukan izin tambahan untuk berfungsi</string>\n    <string name=\"service_name_exposure\">Pemberitahuan Paparan</string>\n    <string name=\"pref_exposure_enable_info_summary\">Untuk mengaktifkan Pemberitahuan Paparan, buka aplikasi apa pun yang mendukung fitur ini.</string>\n    <string name=\"pref_exposure_error_bluetooth_off_title\">Aktifkan Bluetooth</string>\n    <string name=\"pref_exposure_error_location_off_title\">Buka Pengaturan Lokasi</string>\n    <string name=\"pref_exposure_error_bluetooth_unsupported_summary\">Sayangnya, perangkat Anda tidak kompatibel dengan Pemberitahuan Paparan.</string>\n    <string name=\"pref_exposure_error_bluetooth_no_advertise_summary\">Sayangnya, perangkat Anda hanya kompatibel sebagian dengan Pemberitahuan Paparan. Anda dapat menerima pemberitahuan untuk kontak berisiko, tetapi tidak dapat memberitahu orang lain.</string>\n    <string name=\"prefcat_exposure_apps_title\">Aplikasi yang menggunakan Pemberitahuan Paparan</string>\n    <string name=\"pref_exposure_collected_rpis_title\">ID yang dikumpulkan</string>\n    <string name=\"pref_exposure_collected_rpis_summary\"><xliff:g example=\"63\">%1$d</xliff:g> ID dalam satu jam terakhir</string>\n    <string name=\"pref_exposure_advertising_id_title\">Saat ini ditayangkan ID</string>\n    <string name=\"prefcat_exposure_app_report_title\">Paparan yang dilaporkan</string>\n    <string name=\"pref_exposure_app_report_updated_title\">Diperbarui: <xliff:g example=\"Hari ini, 14:02\">%1$s</xliff:g></string>\n    <string name=\"pref_exposure_app_report_entry_time_short\">Kurang dari 5 menit</string>\n    <string name=\"pref_exposure_app_report_entry_time_about\">Sekitar <xliff:g example=\"13\">%1$d</xliff:g> menit</string>\n    <string name=\"pref_exposure_app_report_entry_distance_close\">paparan di sekitar</string>\n    <string name=\"pref_exposure_app_report_entry_distance_far\">paparan jarak jauh</string>\n    <string name=\"pref_exposure_app_report_entry_combined\"><xliff:g contoh=\"Sekitar 12 menit\">%1$s</xliff:g>, <xliff:g contoh=\"paparan jarak jauh\">%2$s</xliff:g></string>\n    <string name=\"pref_exposure_app_last_report_summary_diagnosis_keys\">Kunci diagnosis yang diproses <xliff:g example=\"121031\">%1$d</xliff:g>.</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_no\">Tidak ada laporan tentang paparan yang terjadi.</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_prefix\">Dilaporkan <xliff:g example=\"3\">%1$d</xliff:g> insiden paparan:</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_line\"><xliff:g example=\"Kemarin, 12:00 - 14:00\">%1$s</xliff:g>, skor risiko <xliff:g example=\"99\">%2$d</xliff:g></string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_suffix\">Catatan: Skor risiko ditentukan oleh aplikasi. Angka yang tinggi dapat mengacu pada risiko rendah atau sebaliknya.</string>\n    <string name=\"pref_exposure_app_api_usage_title\">Penggunaan API dalam 14 hari terakhir</string>\n    <string name=\"pref_exposure_app_api_usage_summary_line\"><xliff:g example=\"12\">%1$d</xliff:g> panggilan ke <xliff:g example=\"provideDiagnosisKeys\">%2$s</xliff:g></string>\n    <string name=\"prefcat_exposure_rpis_histogram_title\"><xliff:g example=\"230\">%1$d</xliff:g> ID yang dikumpulkan</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_no_records\">Tidak ada catatan</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_records\"><xliff:g example=\"0 - 50\">%1$s</xliff:g> ID per jam</string>\n    <string name=\"pref_exposure_rpi_delete_all_title\">Hapus</string>\n    <string name=\"pref_exposure_rpi_delete_all_summary\">Hapus semua ID yang telah dikumpulkan</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning\">Menghapus ID yang telah dikumpulkan akan membuat kami tidak dapat memberitahu Anda jika salah satu kontak Anda dalam 14 hari terakhir didiagnosis.</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning_confirm_button\">Hapus saja</string>\n    <string name=\"pref_exposure_rpi_export_title\">Ekspor</string>\n    <string name=\"pref_exposure_rpi_export_summary\">Ekspor ID yang telah dikumpulkan untuk analisis lebih lanjut menggunakan aplikasi lain.</string>\n    <string name=\"pref_exposure_info_summary\">API Pemberitahuan Paparan memungkinkan aplikasi untuk memberi tahu Anda jika Anda terpapar dengan seseorang yang dilaporkan telah didiagnosis positif.\\n\\nTanggal, durasi, dan kekuatan sinyal yang terkait dengan paparan akan dibagikan dengan aplikasi yang bersangkutan.</string>\n    <string name=\"pref_exposure_rpis_details_summary\">Saat API Pemberitahuan Paparan diaktifkan, perangkat Anda secara pasif mengumpulkan ID (yang disebut Rolling Proximity Identifiers, atau RPIs) dari perangkat terdekat.\\n\\nKetika pemilik perangkat melaporkan bahwa mereka telah didiagnosis positif, ID mereka dapat dibagikan. Perangkat Anda memeriksa apakah ada ID yang telah didiagnosis positif yang cocok dengan ID yang dikumpulkan dan menghitung risiko infeksi Anda.</string>\n    <string name=\"exposure_enable_switch\">Gunakan Pemberitahuan Paparan</string>\n    <string name=\"exposure_confirm_start_title\">Aktifkan Pemberitahuan Paparan?</string>\n    <string name=\"exposure_confirm_start_summary\">Ponsel Anda perlu menggunakan Bluetooth untuk mengumpulkan dan berbagi ID secara aman dengan ponsel lain yang berada di dekatnya.\\n\\n<xliff:g example=\"Corona-Warn\">%1$s</xliff:g> dapat memberi tahu Anda jika Anda terpapar dengan seseorang yang dilaporkan positif terinfeksi.\\n\\nTanggal, durasi, dan kekuatan sinyal yang terkait dengan paparan akan dibagikan dengan aplikasi.</string>\n    <string name=\"exposure_confirm_start_button\">Nyalakan</string>\n    <string name=\"exposure_confirm_stop_title\">Mematikan Pemberitahuan Paparan?</string>\n    <string name=\"exposure_confirm_stop_summary\">Setelah menonaktifkan Pemberitahuan Paparan, Anda tidak akan lagi menerima pemberitahuan ketika Anda terpapar dengan seseorang yang dilaporkan telah didiagnosis positif.</string>\n    <string name=\"exposure_confirm_stop_button\">Matikan</string>\n    <string name=\"exposure_confirm_keys_title\">Bagikan ID Anda dengan <xliff:g example=\"Corona-Warn\">%1$s</xliff:g>\\?</string>\n    <string name=\"exposure_confirm_keys_summary\">ID Anda dari 14 hari terakhir akan digunakan untuk membantu memberitahu orang lain bahwa Anda pernah berada di dekat mereka terkait potensi paparan.\\n\\nIdentitas atau hasil tes Anda tidak akan dibagikan kepada orang lain.</string>\n    <string name=\"exposure_confirm_keys_button\">Bagikan</string>\n    <string name=\"exposure_confirm_permission_description\"><xliff:g example=\"microG Services\">%1$s</xliff:g> memerlukan izin tambahan.</string>\n    <string name=\"exposure_confirm_permission_button\">Berikan</string>\n    <string name=\"exposure_confirm_bluetooth_description\">Bluetooth harus diaktifkan.</string>\n    <string name=\"exposure_confirm_location_description\">Akses lokasi diperlukan.</string>\n    <string name=\"exposure_confirm_button\">Aktifkan</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_title\">Izin baru diperlukan</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_description\">Ketuk untuk memberikan izin yang diperlukan untuk Pemberitahuan Paparan</string>\n    <string name=\"exposure_grant_background_location_description\">Sudah hampir selesai! Anda perlu mengaktifkan akses lokasi latar belakang dengan memilih opsi ‘Izinkan sepanjang waktu’ pada layar berikutnya. Kemudian tekan tombol kembali.</string>\n    <string name=\"exposure_grant_background_location_button\">Perbarui Pengaturan</string>\n</resources>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-is/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources></resources>"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-it/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"exposure_notify_off_title\">Notifiche di esposizione al virus non attive</string>\n    <string name=\"exposure_notify_off_bluetooth\">Il Bluetooth dev\\'essere attivato per poter ricevere le notifiche di esposizione al virus.</string>\n    <string name=\"exposure_notify_off_location\">È necessario attivare la geolocalizzazione per poter ricevere le notifiche di esposizione al virus.</string>\n    <string name=\"exposure_notify_off_bluetooth_location\">È necessario attivare il Bluetooth e la geolocalizzazione per poter ricevere le notifiche di esposizione al virus.</string>\n    <string name=\"exposure_notify_off_nearby\">Le notifiche di esposizione al virus richiedono ulteriori permessi per funzionare</string>\n    <string name=\"service_name_exposure\">Notifiche di esposizione al virus</string>\n    <string name=\"pref_exposure_enable_info_summary\">Per abilitare le notifiche di esposizione al virus, apri qualsiasi applicazione che le supporti.</string>\n    <string name=\"prefcat_exposure_apps_title\">Applicazioni che utilizzano le notifiche di esposizione al virus</string>\n    <string name=\"pref_exposure_collected_rpis_title\">Identificativi univoci raccolti</string>\n    <string name=\"pref_exposure_collected_rpis_summary\"><xliff:g example=\"63\">%1$d</xliff:g> identificativi univoci nell\\'ultima ora</string>\n    <string name=\"pref_exposure_advertising_id_title\">Identificativi univoci attualmente trasmessi</string>\n    <string name=\"pref_exposure_app_last_report_summary_diagnosis_keys\">Processate <xliff:g example=\"121031\">%1$d</xliff:g> chiavi di diagnosi.</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_no\">Nessuna esposizione al virus riscontrata.</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_prefix\">Riscontrate <xliff:g example=\"3\">%1$d</xliff:g> esposizioni:</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_line\"><xliff:g example=\"Yesterday, 12:00 - 14:00\">%1$s</xliff:g>, punteggio di rischio <xliff:g example=\"99\">%2$d</xliff:g></string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_suffix\">Nota: Il punteggio di rischio è definito dall\\'applicazione. Punteggi elevati possono riferirsi a un rischio basso o viceversa.</string>\n    <string name=\"pref_exposure_app_api_usage_title\">Utilizzo della API negli ultimi 14 giorni</string>\n    <string name=\"pref_exposure_app_api_usage_summary_line\"><xliff:g example=\"12\">%1$d</xliff:g> chiamate a <xliff:g example=\"provideDiagnosisKeys\">%2$s</xliff:g></string>\n    <string name=\"prefcat_exposure_rpis_histogram_title\"><xliff:g example=\"230\">%1$d</xliff:g> identificativi univoci raccolti</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning\">Eliminando tutti gli identificativi univoci raccolti non sarà possibile notificarti nel caso in cui uno dei tuoi contatti degli ultimi 14 giorni sia stato diagnosticato positivo al virus.</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning_confirm_button\">Elimina comunque</string>\n    <string name=\"pref_exposure_info_summary\">L\\'API per le notifiche di esposizione al virus permette alle applicazioni di notificarti nel caso in cui tu sia stato esposto a qualcuno che ha riportato di essere stato diagnosticato positivo al virus.\\n\\nData, durata e potenza del segnale associati a una esposizione verranno condivisi con l\\'applicazione relativa.</string>\n    <string name=\"pref_exposure_rpis_details_summary\">Quando l\\'API per le notifiche di esposizione al virus è abilitata, il tuo dispositivo raccoglie passivamente degli identificativi univoci (chiamati Identificatori di Prossimità a Rotazione, o RPI) dai dispositivi vicini.\\n\\nQuando i possessori dei dispositivi riportano di essere stati diagnosticati positivi al virus, i loro identificativi univoci possono essere condivisi. Il tuo dispositivo verifica se tra gli identificativi univoci diagnosticati positivi al virus vi sono corrispondenze con quelli raccolti e calcola il tuo punteggio di rischio.</string>\n    <string name=\"exposure_enable_switch\">Utilizza le notifiche di esposizione al virus</string>\n    <string name=\"exposure_confirm_start_title\">Abilitare le notifiche di esposizione al virus?</string>\n    <string name=\"exposure_confirm_start_summary\">Il tuo dispositivo richiede l\\'utilizzo del Bluetooth per raccogliere e condividere in modo sicuro gli identificativi univoci con altri dispositivi vicini.\\n\\n<xliff:g example=\"Corona-Warn\">%1$s</xliff:g> può notificarti nel caso in cui tu sia stato esposto a qualcuno che ha riportato di essere stato diagnosticato positivo al virus.\\n\\nData, durata e potenza del segnale associati a una esposizione al virus verranno condivisi con l\\'applicazione.</string>\n    <string name=\"exposure_confirm_start_button\">Abilita</string>\n    <string name=\"exposure_confirm_stop_title\">Disabilitare le notifiche di esposizione al virus?</string>\n    <string name=\"exposure_confirm_stop_summary\">Dopo aver disabilitato le notifiche di esposizione al virus, non verrai più notificato nel caso in cui tu sia stato esposto a qualcuno che ha riportato di essere stato diagnosticato positivo.</string>\n    <string name=\"exposure_confirm_stop_button\">Disabilita</string>\n    <string name=\"exposure_confirm_keys_title\">Vuoi condividere i tuoi identificativi univoci con <xliff:g example=\"Corona-Warn\">%1$s</xliff:g>?</string>\n    <string name=\"exposure_confirm_keys_summary\">I tuoi identificativi univoci degli ultimi 14 giorni saranno utilizzati per aiutare a notificare altri se sei stato potenzialmente esposto al virus.\\n\\nLa tua identità o il risultato del test non saranno condivisi con altre persone.</string>\n    <string name=\"exposure_confirm_keys_button\">Condividi</string>\n    <string name=\"exposure_confirm_permission_description\"><xliff:g example=\"microG Services\">%1$s</xliff:g> richiede ulteriori permessi.</string>\n    <string name=\"exposure_confirm_permission_button\">Consenti</string>\n    <string name=\"pref_exposure_rpi_delete_all_summary\">Elimina tutti gli identificativi univoci raccolti</string>\n    <string name=\"pref_exposure_rpi_delete_all_title\">Elimina</string>\n    <string name=\"pref_exposure_rpi_export_title\">Esporta</string>\n    <string name=\"exposure_confirm_button\">Attiva</string>\n    <string name=\"pref_exposure_error_bluetooth_off_title\">Attiva il Bluetooth</string>\n    <string name=\"exposure_confirm_bluetooth_description\">Il Bluetooth dev\\'essere attivato.</string>\n    <string name=\"pref_exposure_app_report_entry_time_short\">Meno di 5 minuti</string>\n    <string name=\"pref_exposure_app_report_entry_time_about\">Circa <xliff:g example=\"13\">%1$d</xliff:g> minuti</string>\n    <string name=\"pref_exposure_app_report_entry_distance_close\">esposizione ravvicinata</string>\n    <string name=\"pref_exposure_app_report_entry_distance_far\">esposizione a distanza</string>\n    <string name=\"pref_exposure_app_report_entry_combined\"><xliff:g example=\"About 12 minutes\">%1$s</xliff:g>, <xliff:g example=\"distant exposure\">%2$s</xliff:g></string>\n    <string name=\"pref_exposure_app_report_updated_title\">Ultimo aggiornamento: <xliff:g example=\"Today, 14:02\">%1$s</xliff:g></string>\n    <string name=\"pref_exposure_rpi_export_summary\">Esporta gli identificativi univoci raccolti per analizzarli con un\\'altra app.</string>\n    <string name=\"exposure_confirm_location_description\">È necessario attivare la geolocalizzazione.</string>\n    <string name=\"pref_exposure_error_bluetooth_unsupported_summary\">Il tuo dispositivo non è compatibile con le notifiche di esposizione al virus.</string>\n    <string name=\"pref_exposure_error_bluetooth_no_advertise_summary\">Il tuo dispositivo è compatibile soltanto parzialmente con le notifiche di esposizione al virus. Potrai essere notificato in caso di contatti a rischio, ma non sarai in grado di notificare gli altri.</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_no_records\">Nessun dato</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_records\"><xliff:g example=\"0 - 50\">%1$s</xliff:g> identificativi in un\\'ora</string>\n    <string name=\"prefcat_exposure_app_report_title\">Esposizioni riscontrate</string>\n    <string name=\"pref_exposure_error_location_off_title\">Apri le impostazioni di geolocalizzazione</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_title\">Sono richiesti nuovi permessi</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_description\">Tocca per consentire i permessi richiesti per le notifiche di esposizione al virus</string>\n    <string name=\"exposure_grant_background_location_description\">Ci sei quasi! Ora dovrai abilitare l\\'accesso alla posizione in background selezionando l\\'opzione \\\"Consenti sempre\\\" nella prossima schermata. Una volta fatto, premi il tasto Indietro.</string>\n    <string name=\"exposure_grant_background_location_button\">Aggiorna impostazioni</string>\n</resources>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-iw/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n</resources>"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-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=\"pref_exposure_error_bluetooth_off_title\">Bluetooth を有効にする</string>\n    <string name=\"pref_exposure_error_location_off_title\">位置情報の設定を開く</string>\n    <string name=\"pref_exposure_collected_rpis_title\">収集されたID</string>\n    <string name=\"pref_exposure_advertising_id_title\">現在のブロードキャストID</string>\n    <string name=\"pref_exposure_rpi_delete_all_title\">削除</string>\n    <string name=\"exposure_confirm_start_button\">オンにする</string>\n    <string name=\"exposure_confirm_stop_button\">オフにする</string>\n    <string name=\"exposure_confirm_keys_button\">共有</string>\n    <string name=\"pref_exposure_rpi_export_title\">エクスポート</string>\n    <string name=\"exposure_confirm_bluetooth_description\">Bluetoothを有効にする必要があります。</string>\n    <string name=\"exposure_confirm_button\">有効</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_title\">新たな権限が必要です</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_description\">タップして、接触通知に必要な許可を付与してください</string>\n    <string name=\"exposure_confirm_stop_title\">接触通知をオフにしますか?</string>\n    <string name=\"exposure_confirm_stop_summary\">接触通知を無効にすると、陽性と報告された人に接触した際のお知らせを受け取れなくなります。</string>\n    <string name=\"exposure_grant_background_location_description\">あと少しです！次の画面で「常に許可」オプションを選択し、バックグラウンド位置情報のアクセスを有効にする必要があります。その後、戻るボタンを押してください。</string>\n    <string name=\"exposure_grant_background_location_button\">設定を更新</string>\n    <string name=\"exposure_notify_off_title\">接触通知が無効です</string>\n    <string name=\"exposure_notify_off_bluetooth\">接触通知を受信するには、Bluetoothを有効にする必要があります。</string>\n    <string name=\"exposure_notify_off_location\">接触通知を受信するには、位置情報のアクセスが必要です。</string>\n    <string name=\"exposure_notify_off_bluetooth_location\">接触通知を受信するには、Bluetoothと位置情報のアクセスを有効にする必要があります。</string>\n    <string name=\"exposure_notify_off_nearby\">接触通知は機能するために追加の許可が必要です</string>\n    <string name=\"service_name_exposure\">接触通知</string>\n    <string name=\"pref_exposure_enable_info_summary\">接触通知を有効にするには、対応しているアプリを開いてください。</string>\n    <string name=\"pref_exposure_error_bluetooth_unsupported_summary\">残念ながら、あなたのデバイスは接触通知に対応していません。</string>\n    <string name=\"pref_exposure_error_bluetooth_no_advertise_summary\">残念ながら、あなたのデバイスは接触通知機能と部分的にのみ互換性があります。リスクのある接触者については通知を受け取れますが、他者への通知はできません。</string>\n    <string name=\"prefcat_exposure_apps_title\">接触通知を利用するアプリ</string>\n    <string name=\"pref_exposure_collected_rpis_summary\">過去一時間のID数: <xliff:g example=\"63\">%1$d</xliff:g></string>\n    <string name=\"prefcat_exposure_app_report_title\">報告された接触</string>\n    <string name=\"pref_exposure_app_report_updated_title\">更新日時: <xliff:g example=\"Today, 14:02\">%1$s</xliff:g></string>\n    <string name=\"pref_exposure_app_report_entry_time_short\">5分未満</string>\n    <string name=\"pref_exposure_app_report_entry_time_about\">約 <xliff:g example=\"13\">%1$d</xliff:g> 分</string>\n    <string name=\"pref_exposure_app_report_entry_distance_close\">近隣の接触</string>\n    <string name=\"pref_exposure_app_report_entry_distance_far\">遠隔接触</string>\n    <string name=\"pref_exposure_app_report_entry_combined\"><xliff:g example=\"About 12 minutes\">%1$s</xliff:g>, <xliff:g example=\"distant exposure\">%2$s</xliff:g></string>\n    <string name=\"pref_exposure_app_last_report_summary_diagnosis_keys\"><xliff:g example=\"121031\">%1$d</xliff:g> 件の診断キーを処理しました。</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_no\">接触事象の報告はありません。</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_prefix\"><xliff:g example=\"3\">%1$d</xliff:g> 件の暴露事例が報告されました。</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_line\"><xliff:g example=\"Yesterday, 12:00 - 14:00\">%1$s</xliff:g>, リスクスコア <xliff:g example=\"99\">%2$d</xliff:g></string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_suffix\">注：リスクスコアはアプリによって定義されます。数値が高い場合でもリスクが低いことを示す場合があり、その逆も同様です。</string>\n    <string name=\"pref_exposure_app_api_usage_title\">過去14日間のAPI利用状況</string>\n    <string name=\"pref_exposure_app_api_usage_summary_line\"><xliff:g example=\"12\">%1$d</xliff:g> 回 <xliff:g example=\"provideDiagnosisKeys\">%2$s</xliff:g> に対して行われました</string>\n    <string name=\"prefcat_exposure_rpis_histogram_title\"><xliff:g example=\"230\">%1$d</xliff:g> 件のIDが収集されました</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_no_records\">記録なし</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_records\">一時間あたり <xliff:g example=\"0 - 50\">%1$s</xliff:g> 件のID</string>\n    <string name=\"pref_exposure_rpi_delete_all_summary\">収集したIDをすべて削除する</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning\">収集したIDを削除すると、過去14日間の接触者の中に新型コロナウイルス感染症の陽性者が確認された場合に通知できなくなります。</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning_confirm_button\">とにかく削除する</string>\n    <string name=\"pref_exposure_rpi_export_summary\">収集したIDをエクスポートし、別のアプリで詳細な分析を行う。</string>\n    <string name=\"pref_exposure_info_summary\">接触通知APIは、アプリが、陽性判定を報告した人物に接触した可能性がある場合に通知することを可能にします。\\n\\n接触に関連する日付、接触時間、および信号強度が、対応するアプリと共有されます。</string>\n    <string name=\"pref_exposure_rpis_details_summary\">接触通知 API が有効な間、お使いのデバイスは周囲のデバイスから ID（ローリング近接識別子、RPI と呼ばれる）を受動的に収集します。\\n\\nデバイス所有者が陽性診断を報告すると、その ID が共有される可能性があります。お使いのデバイスは、既知の診断済み ID と収集済み ID のいずれかが一致するかどうかを確認し、感染リスクを算出します。</string>\n    <string name=\"exposure_enable_switch\">接触通知を使用する</string>\n    <string name=\"exposure_confirm_start_title\">接触通知をオンにしますか?</string>\n    <string name=\"exposure_confirm_start_summary\">お使いのスマートフォンは、近くにある他のスマートフォンと安全にIDを収集・共有するためにBluetoothを使用する必要があります。\\n\\n<xliff:g example=\"Corona-Warn\">%1$s</xliff:g>は、陽性判定を報告した人物に接触した可能性がある場合に通知します。\\n\\n接触に関連する日付、接触時間、信号強度がアプリと共有されます。</string>\n    <string name=\"exposure_confirm_keys_title\"><xliff:g example=\"Corona-Warn\">%1$s</xliff:g> とIDを共有しますか?</string>\n    <string name=\"exposure_confirm_keys_summary\">過去14日間のあなたのIDは、あなたが近くにおり感染の可能性があったことを周囲に通知するために使用されます。\\n\\nあなたの身元や検査結果は他の人と共有されることはありません。</string>\n    <string name=\"exposure_confirm_permission_description\"><xliff:g example=\"microG Services\">%1$s</xliff:g> に追加の権限が必要です。</string>\n    <string name=\"exposure_confirm_permission_button\">付与</string>\n    <string name=\"exposure_confirm_location_description\">位置情報へのアクセスが必要です。</string>\n</resources>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-ko/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=\"exposure_notify_off_title\">노출 알림 비활성화됨</string>\n    <string name=\"exposure_notify_off_bluetooth\">노출 알림을 수신하려면 블루투스가 활성화되어야 합니다.</string>\n    <string name=\"exposure_notify_off_location\">노출 알림을 수신하려면 위치 접근이 필요합니다.</string>\n    <string name=\"exposure_notify_off_bluetooth_location\">노출 알림을 수신하려면 블루투스와 위치 접근이 활성화되어야 합니다.</string>\n    <string name=\"exposure_notify_off_nearby\">노출 알림의 작동에 추가적인 권한이 필요합니다</string>\n    <string name=\"service_name_exposure\">노출 알림</string>\n    <string name=\"pref_exposure_enable_info_summary\">노출 알림을 활성화하려면, 지원하는 앱을 열어주세요.</string>\n    <string name=\"pref_exposure_error_bluetooth_off_title\">블루투스 활성화</string>\n    <string name=\"pref_exposure_error_location_off_title\">위치 설정 열기</string>\n    <string name=\"pref_exposure_collected_rpis_title\">수집한 ID</string>\n    <string name=\"pref_exposure_rpi_delete_all_title\">삭제</string>\n    <string name=\"pref_exposure_rpi_export_title\">내보내기</string>\n    <string name=\"exposure_confirm_keys_button\">공유</string>\n    <string name=\"exposure_confirm_permission_button\">승인</string>\n    <string name=\"exposure_confirm_button\">활성화</string>\n    <string name=\"exposure_confirm_start_button\">켜기</string>\n    <string name=\"exposure_confirm_stop_button\">끄기</string>\n    <string name=\"pref_exposure_error_bluetooth_unsupported_summary\">안타깝게도, 이 기기는 노출 알림과 호환되지 않습니다.</string>\n    <string name=\"pref_exposure_error_bluetooth_no_advertise_summary\">안타깝게도, 이 기기는 노출 알림과 부분적으로만 호환됩니다. 노출되었을 때 알림을 받을 수 있지만, 다른 사람에게는 알림을 보낼 수 없습니다.</string>\n    <string name=\"prefcat_exposure_apps_title\">노출 알림을 사용하는 앱</string>\n    <string name=\"pref_exposure_collected_rpis_summary\">지난 1시간 동안 <xliff:g example=\"63\">%1$d</xliff:g>번의 ID</string>\n    <string name=\"pref_exposure_advertising_id_title\">현재 방송 중인 ID</string>\n    <string name=\"prefcat_exposure_app_report_title\">보고된 노출</string>\n    <string name=\"pref_exposure_app_report_updated_title\"><xliff:g example=\"Today, 14:02\">%1$s</xliff:g>에 갱신됨</string>\n    <string name=\"pref_exposure_app_report_entry_time_short\">5분 미만</string>\n    <string name=\"pref_exposure_app_report_entry_time_about\">약 <xliff:g example=\"13\">%1$d</xliff:g>분</string>\n    <string name=\"pref_exposure_app_report_entry_distance_close\">근처 노출</string>\n    <string name=\"pref_exposure_app_report_entry_distance_far\">원거리 노출</string>\n    <string name=\"pref_exposure_app_report_entry_combined\"><xliff:g example=\"About 12 minutes\">%1$s</xliff:g>, <xliff:g example=\"distant exposure\">%2$s</xliff:g></string>\n    <string name=\"pref_exposure_app_last_report_summary_diagnosis_keys\"><xliff:g example=\"121031\">%1$d</xliff:g>개의 진단 키를 처리했습니다.</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_no\">보고된 노출 및 접촉이 없습니다.</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_prefix\">보고된 <xliff:g example=\"3\">%1$d</xliff:g>건의 노출 및 접촉:</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_line\"><xliff:g example=\"Yesterday, 12:00 - 14:00\">%1$s</xliff:g>, 위험도 <xliff:g example=\"99\">%2$d</xliff:g></string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_suffix\">참고: 위험도는 앱에 의해 정의됩니다. 높은 수치는 낮은 위험도 또는 그 반대의 경우를 의미할 수 있습니다.</string>\n    <string name=\"pref_exposure_app_api_usage_title\">지난 14일 동안의 API 사용량</string>\n    <string name=\"pref_exposure_app_api_usage_summary_line\"><xliff:g example=\"provideDiagnosisKeys\">%2$s</xliff:g>로의 호출 <xliff:g example=\"12\">%1$d</xliff:g>번</string>\n    <string name=\"prefcat_exposure_rpis_histogram_title\"><xliff:g example=\"230\">%1$d</xliff:g>개의 ID 수집</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_no_records\">기록 없음</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_records\">시간당 ID <xliff:g example=\"0 - 50\">%1$s</xliff:g>개</string>\n    <string name=\"pref_exposure_rpi_delete_all_summary\">수집된 ID 모두 삭제</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning\">수집된 ID를 모두 삭제하면 지난 14일 동안의 접촉자가 진단된 경우 알림을 받을 수 없습니다.</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning_confirm_button\">삭제하기</string>\n    <string name=\"pref_exposure_rpi_export_summary\">수집된 ID를 다른 앱으로 내보내 분석합니다.</string>\n    <string name=\"pref_exposure_info_summary\">노출 알림 API를 사용하면 양성 판정을 받은 사람에게 노출된 경우 앱이 알려줄 수 있습니다.\\n\\n노출과 관련된 날짜, 기간 및 신호 강도는 해당 앱과 공유됩니다.</string>\n    <string name=\"pref_exposure_rpis_details_summary\">노출 알림 API가 활성화되어 있는 동안, 장치는 주변 장치로부터 ID(롤링 근접 식별자 또는 RPI)를 자동적으로 수집합니다.\\n\\n기기 소유자가 양성 판정을 받았다고 신고하면 ID가 공유됩니다. 귀하의 기기는 알려진 양성으로 진단된 ID 중 기기에서 수집한 ID와 일치하는 ID가 있는지 확인하고 감염 위험도을 계산합니다.</string>\n    <string name=\"exposure_enable_switch\">노출 알림 사용</string>\n    <string name=\"exposure_confirm_start_title\">노출 알림을 활성화할까요?</string>\n    <string name=\"exposure_confirm_start_summary\">휴대폰은 가까운 다른 휴대폰과 ID를 안전하게 수집하고 공유하는 데 블루투스를 필요로 합니다.\\n\\n<xliff:g example=\"Corona-Warn\">%1$s</xliff:g>은/는 양성 판정을 받은 사람에게 노출되었을 경우 알려줄 수 있습니다.\\n\\n노출과 관련된 날짜, 기간 및 신호 강도는 앱과 공유됩니다.</string>\n    <string name=\"exposure_confirm_stop_title\">노출 알림을 비활성화할까요?</string>\n    <string name=\"exposure_confirm_stop_summary\">노출 알림을 비활성화하면, 양성 판정을 받은 사람에게 노출되어도 더 이상 알림을 받지 않습니다.</string>\n    <string name=\"exposure_confirm_keys_title\"><xliff:g example=\"Corona-Warn\">%1$s</xliff:g>와/과 ID를 공유할까요?</string>\n    <string name=\"exposure_confirm_keys_summary\">지난 14일 동안의 ID는 근접해 있던 다른 사람들에게 잠재적인 노출 가능성을 알리는 데 사용됩니다.\\n\\n귀하의 신원이나 검사 결과는 다른 사람들과 공유되지 않습니다.</string>\n    <string name=\"exposure_confirm_permission_description\"><xliff:g example=\"microG Services\">%1$s</xliff:g>이/가 추가적인 권한이 필요합니다.</string>\n    <string name=\"exposure_confirm_bluetooth_description\">블루투스가 켜져 있어야 합니다.</string>\n    <string name=\"exposure_confirm_location_description\">위치 접근이 필요합니다.</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_title\">신규 권한 필요</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_description\">노출 알림에 필요한 권한을 부여하려면 탭하세요</string>\n    <string name=\"exposure_grant_background_location_description\">거의 다 됐어요! 다음 화면에서 \\'항상 허용\\' 옵션을 선택하여 백그라운드 위치 액세스를 활성화해야 합니다. 그 다음 \\'뒤로\\'를 누르세요.</string>\n    <string name=\"exposure_grant_background_location_button\">설정 업데이트</string>\n</resources>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-lv/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources></resources>"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-lzh/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources></resources>"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-ml/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"exposure_notify_off_title\">എക്സ്പോഷർ അറിയിപ്പുകൾ നിഷ്ക്രിയമാണ്</string>\n    <string name=\"exposure_notify_off_bluetooth\">എക്സ്പോഷർ അറിയിപ്പുകൾ ലഭിക്കാൻ ബ്ലൂടൂത്ത് പ്രവർത്തനക്ഷമമാക്കേണ്ടതുണ്ട്.</string>\n    <string name=\"exposure_notify_off_location\">എക്സ്പോഷർ അറിയിപ്പുകൾ ലഭിക്കാൻ ലൊക്കേഷൻ ആക്‌സസ് ആവശ്യമാണ്.</string>\n    <string name=\"exposure_notify_off_bluetooth_location\">എക്സ്പോഷർ അറിയിപ്പുകൾ ലഭിക്കാൻ ബ്ലൂടൂത്തും ലൊക്കേഷൻ ആക്‌സസും പ്രവർത്തനക്ഷമമാക്കേണ്ടതുണ്ട്.</string>\n    <string name=\"exposure_notify_off_nearby\">എക്സ്പോഷർ അറിയിപ്പുകൾ പ്രവർത്തിക്കാൻ അധിക അനുമതികൾ ആവശ്യമാണ്</string>\n    <string name=\"service_name_exposure\">എക്സ്പോഷർ അറിയിപ്പുകൾ</string>\n    <string name=\"pref_exposure_enable_info_summary\">എക്സ്പോഷർ അറിയിപ്പുകൾ പ്രവർത്തനക്ഷമമാക്കാൻ, അതിനെ പിന്തുണയ്ക്കുന്ന ഏതെങ്കിലും ആപ്പ് തുറക്കുക.</string>\n    <string name=\"pref_exposure_error_bluetooth_off_title\">ബ്ലൂടൂത്ത് പ്രവർത്തനക്ഷമമാക്കുക</string>\n    <string name=\"pref_exposure_error_location_off_title\">ലൊക്കേഷൻ ക്രമീകരണങ്ങൾ തുറക്കുക</string>\n</resources>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-nb-rNO/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=\"pref_exposure_error_bluetooth_off_title\">Aktiver Bluetooth</string>\n    <string name=\"pref_exposure_error_location_off_title\">Åpne lokasjonsinnstillinger</string>\n    <string name=\"pref_exposure_app_report_entry_time_short\">Mindre enn 5 minutter</string>\n    <string name=\"pref_exposure_app_report_entry_time_about\">Rundt <xliff:g example=\"13\">%1$d</xliff:g> minutter</string>\n    <string name=\"pref_exposure_app_report_updated_title\">Oppdatert: <xliff:g example=\"Today, 14:02\">%1$s</xliff:g></string>\n    <string name=\"pref_exposure_app_api_usage_title\">API-bruk i løpet av de siste 14 dager</string>\n    <string name=\"exposure_confirm_start_button\">Skru på</string>\n    <string name=\"pref_exposure_rpi_delete_all_title\">Slett</string>\n    <string name=\"pref_exposure_rpi_delete_all_summary\">Slett alle innsamlede ID-er</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning_confirm_button\">Slett alikevel</string>\n    <string name=\"pref_exposure_rpi_export_title\">Eksporter</string>\n    <string name=\"pref_exposure_rpi_export_summary\">Eksporter innsamlede ID-er for analyse i en annen app.</string>\n    <string name=\"exposure_confirm_stop_button\">Skru av</string>\n    <string name=\"exposure_confirm_keys_title\">Del ID-ene dine med <xliff:g example=\"Corona-Warn\">%1$s</xliff:g>\\?</string>\n    <string name=\"pref_exposure_collected_rpis_title\">Innsamlede ID-er</string>\n    <string name=\"pref_exposure_collected_rpis_summary\"><xliff:g example=\"63\">%1$d</xliff:g> ID-er den siste timen</string>\n    <string name=\"exposure_notify_off_title\">Eksponeringsvarsler deaktivert</string>\n    <string name=\"exposure_notify_off_bluetooth\">Bluetooth må være aktivert for å motta eksponeringsvarsler.</string>\n    <string name=\"exposure_notify_off_location\">Lokasjonstjenester må være aktivert for å kunne motta eksponeringsvarsler.</string>\n    <string name=\"exposure_notify_off_bluetooth_location\">Bluetooth og lokasjonstjenester må være aktiverte for å motta eksponeringsvarsler.</string>\n    <string name=\"exposure_notify_off_nearby\">Eksponeringsvarsler trenger flere rettigheter for å fungere</string>\n    <string name=\"service_name_exposure\">Eksponeringsvarsler</string>\n    <string name=\"pref_exposure_enable_info_summary\">For å aktivere eksponeringsvarsler, åpne en app som støtter det.</string>\n    <string name=\"pref_exposure_error_bluetooth_unsupported_summary\">Dessverre støtter ikke enheten din eksponeringsvarsler.</string>\n    <string name=\"pref_exposure_error_bluetooth_no_advertise_summary\">Dessverre er enheten din bare delvis kompatibel med eksponeringsvarsler. Du kan bli varslet for risikokontakter, men kommer ikke til å sende varsler til andre.</string>\n    <string name=\"prefcat_exposure_apps_title\">Apper som bruker eksponeringsvarsler</string>\n    <string name=\"pref_exposure_advertising_id_title\">ID som sendes</string>\n    <string name=\"prefcat_exposure_app_report_title\">Rapporterte eksponeringer</string>\n    <string name=\"pref_exposure_app_report_entry_distance_close\">eksponering i nærheten</string>\n    <string name=\"pref_exposure_app_report_entry_distance_far\">eksponering på avstand</string>\n    <string name=\"pref_exposure_app_report_entry_combined\"><xliff:g example=\"About 12 minutes\">%1$s</xliff:g>, <xliff:g example=\"distant exposure\">%2$s</xliff:g></string>\n    <string name=\"pref_exposure_app_last_report_summary_diagnosis_keys\">Prosesserte <xliff:g example=\"121031\">%1$d</xliff:g> diagnosenøkler.</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_no\">Ingen eksponeringsvarsler rapportert.</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_prefix\">Rapportert <xliff:g example=\"3\">%1$d</xliff:g> eksponeringsvarsler:</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_line\"><xliff:g example=\"Yesterday, 12:00 - 14:00\">%1$s</xliff:g>, risikonivå <xliff:g example=\"99\">%2$d</xliff:g></string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_suffix\">Merk: risikonivået er definert av appen. Høyere tall kan bety lavere risiko, eller det motsatte.</string>\n    <string name=\"pref_exposure_app_api_usage_summary_line\"><xliff:g example=\"12\">%1$d</xliff:g> anrop til <xliff:g example=\"provideDiagnosisKeys\">%2$s</xliff:g></string>\n    <string name=\"prefcat_exposure_rpis_histogram_title\"><xliff:g example=\"230\">%1$d</xliff:g> ID-er samlet inn</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_no_records\">Ingen data</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_records\"><xliff:g example=\"0 - 50\">%1$s</xliff:g> ID-er per time</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning\">Å slette innsamlede ID-er vil gjøre det umulig å varsle deg hvis noen av kontaktene dine får diagnose i løpet av de siste 14 dagene.</string>\n    <string name=\"pref_exposure_info_summary\">Eksponeringsvarsels-API-et lar apper varsle deg hvis du var i nærheten av noen som har fått positiv diagnose.\\n\\nDatoen, varigheten og signalstyrken assosiert med en eksponering vil deles med den gjeldende appen.</string>\n    <string name=\"exposure_enable_switch\">Bruk eksponeringsvarsler</string>\n    <string name=\"exposure_confirm_start_title\">Skru på eksponeringsvarsler?</string>\n    <string name=\"exposure_confirm_stop_title\">Skru av eksponeringsvarsler?</string>\n    <string name=\"exposure_confirm_keys_button\">Del</string>\n    <string name=\"exposure_confirm_permission_button\">Tillat</string>\n    <string name=\"exposure_confirm_bluetooth_description\">Bluetooth må være skrudd på.</string>\n    <string name=\"exposure_confirm_location_description\">Lokasjonstjenester må være skrudd på.</string>\n    <string name=\"exposure_confirm_button\">Skru på</string>\n    <string name=\"exposure_grant_background_location_button\">Oppdater innstillinger</string>\n    <string name=\"pref_exposure_rpis_details_summary\">Mens eksponeringsvarsels-API-et er skrudd på, samler inn enheten din ID-er (kalt Rolling Proximity Identifiers, RPI-er) fra enheter i nærheten.\\n\\nNår en enhets eier får en positiv diagnose, kan ID-en deres deles. Enheten din sjekker om noen av ID-ene som har blitt bekreftet å ha fått diagnose er lik en av ID-ene som enheten din har samlet inn, og regner ut infeksjonsrisikoen din.</string>\n    <string name=\"exposure_confirm_start_summary\">Mobilen din trenger å bruke Bluetooth for å sikkert samle inn og dele ID-er med andre mobiler som er i nærheten.\\n\\n<xliff:g example=\"Corona-Warn\">%1$s</xliff:g> kan varsle deg hvis du var i nærheten av noen som har blitt bekreftet å ha fått positiv diagnose.\\n\\nDatoen, varigheten og signalstyrken forbundet med eksponeringen vil deles med appen.</string>\n    <string name=\"exposure_confirm_stop_summary\">Etter å ha deaktivert eksponeringsvarsler, vil du ikke lenger motta varsler om du har befunnet deg i nærheten av noen som har fått en positiv diagnose.</string>\n    <string name=\"exposure_confirm_keys_summary\">ID-ene dine fra de siste 14 dagene vil bli brukt for å varsle andre som du har vært i nærheten av om en potensiell spredning.\\n\\nIdentiteten din og testresultatet ditt kommer ikke til å deles med andre.</string>\n    <string name=\"exposure_confirm_permission_description\"><xliff:g example=\"microG Services\">%1$s</xliff:g> trenger flere rettigheter.</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_title\">Nye rettigheter kreves</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_description\">Trykk for å gi de forespurte rettighetene til eksponeringsvarsler</string>\n    <string name=\"exposure_grant_background_location_description\">Nesten ferdig! Du må skru på lokasjonstjenester i bakgrunnen ved å velge «Tillat hele tiden» på den neste skjermen. Trykk deretter tilbake.</string>\n</resources>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-nl/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"exposure_notify_off_nearby\">Meldingen vereisen extra machtigingen om te werken</string>\n    <string name=\"exposure_confirm_permission_button\">Toestaan</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_description\">Tik op om de vereiste machtigingen te verlenen voor Meldingen weergeven</string>\n    <string name=\"pref_exposure_rpis_details_summary\">Als Exposure Notification API is ingeschakeld, verzamelt je apparaat passief ID\\'s (Rolling Proximity Identifiers of RPI\\'s genoemd) van apparaten in de buurt.\\n\\nWanneer eigenaars van apparaten melden dat ze positief gediagnosticeerd zijn, kunnen hun ID\\'s gedeeld worden. Uw apparaat controleert of een van de bekende gediagnosticeerde ID\\'s overeenkomt met een van de verzamelde ID\\'s en berekent uw infectierisico.</string>\n    <string name=\"pref_exposure_error_bluetooth_unsupported_summary\">Helaas is uw apparaat niet compatibel met blootstellingsmeldingen.</string>\n    <string name=\"pref_exposure_error_bluetooth_no_advertise_summary\">Helaas is uw apparaat slechts gedeeltelijk compatibel met blootstellingsmeldingen. U kunt wel meldingen ontvangen over risicocontacten, maar u kunt anderen niet zelf op de hoogte stellen.</string>\n</resources>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-pl/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=\"pref_exposure_app_last_report_summary_encounters_prefix\">Wykryto <xliff:g example=\"3\">%1$d</xliff:g> narażeń na kontakt:</string>\n    <string name=\"pref_exposure_app_report_entry_combined\"><xliff:g example=\"About 12 minutes\">%1$s</xliff:g>, <xliff:g example=\"distant exposure\">%2$s</xliff:g></string>\n    <string name=\"pref_exposure_app_api_usage_title\">Użycie API w ciągu ostatnich 14 dni</string>\n    <string name=\"pref_exposure_rpi_export_summary\">Eksportuje zebrane ID dla rozszerzonej analizy przez inną aplikację.</string>\n    <string name=\"exposure_notify_off_bluetooth_location\">Bluetooth i dostęp do lokalizacji muszą być włączone, aby otrzymywać powiadomienia o narażaniu na kontakt.</string>\n    <string name=\"exposure_confirm_stop_button\">Wyłącz</string>\n    <string name=\"pref_exposure_advertising_id_title\">Obecnie nadawany ID</string>\n    <string name=\"exposure_confirm_start_title\">Włączyć powiadomienia o narażaniu na kontakt\\?</string>\n    <string name=\"pref_exposure_error_bluetooth_unsupported_summary\">Niestety twoje urządzenie nie jest kompatybilne z powiadomieniami o narażaniu na kontakt.</string>\n    <string name=\"pref_exposure_collected_rpis_title\">Zebrane ID</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_description\">Dotknij, aby udzielić wymaganych uprawnień dla powiadomień o narażaniu na kontakt</string>\n    <string name=\"pref_exposure_app_report_entry_time_short\">Poniżej 5 minut temu</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_no\">Nie wykryto żadnych narażeń na kontakt.</string>\n    <string name=\"pref_exposure_app_report_entry_distance_far\">daleki kontakt</string>\n    <string name=\"exposure_confirm_keys_title\">Udostępniać Twoje ID aplikacji <xliff:g example=\"Corona-Warn\">%1$s</xliff:g>\\?</string>\n    <string name=\"exposure_enable_switch\">Używaj powiadomień o narażaniu na kontakt</string>\n    <string name=\"pref_exposure_app_last_report_summary_diagnosis_keys\">Przetworzono <xliff:g example=\"121031\">%1$d</xliff:g> kluczy diagnostycznych.</string>\n    <string name=\"pref_exposure_rpi_export_title\">Eksportuj</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_records\"><xliff:g example=\"0 - 50\">%1$s</xliff:g> ID na godzinę</string>\n    <string name=\"exposure_notify_off_title\">Powiadomienia o narażaniu na kontakt są nieaktywne</string>\n    <string name=\"pref_exposure_app_report_updated_title\">Aktualizacja: <xliff:g example=\"Today, 14:02\">%1$s</xliff:g></string>\n    <string name=\"exposure_grant_background_location_button\">Aktualizacja ustawień</string>\n    <string name=\"pref_exposure_error_location_off_title\">Otwórz ustawienia lokalizacji</string>\n    <string name=\"pref_exposure_rpis_details_summary\">W czasie, gdy API powiadomień o narażaniu na kontakt z COVID-19 jest aktywne, twoje urządzenie stale gromadzi identyfikatory (nazywane RPI, ang. „Rolling Proximity Identifiers”) z pobliskich urządzeń.\n\\n\n\\nJeżeli właściciele urządzeń zgłoszą pozytywną diagnozę testu, ich ID mogą być udostępniane. Twoje urządzenie sprawdza, czy żaden z znanych ID z pozytywną diagnozą testu nie znajduje się w zebranych ID i wylicza twoje ryzyko zakażenia.</string>\n    <string name=\"pref_exposure_info_summary\">API powiadomień o narażaniu na kontakt z COVID-19 pozwalają aplikacjom na powiadamianie cię o kontakcie z osobami z pozytywną diagnozą testu na obecność wirusa.\n\\n\n\\nData, okres i siła sygnału związana z narażeniem na kontakt będzie udostępniona odpowiedniej aplikacji.</string>\n    <string name=\"pref_exposure_app_api_usage_summary_line\"><xliff:g example=\"12\">%1$d</xliff:g> rozgłoszeń do <xliff:g example=\"provideDiagnosisKeys\">%2$s</xliff:g></string>\n    <string name=\"pref_exposure_enable_info_summary\">Aby włączyć funkcję powiadomień o narażaniu na kontakt, otwórz dowolną aplikację wspierającą ją.</string>\n    <string name=\"pref_exposure_rpi_delete_all_summary\">Usuń wszystkie zebrane ID</string>\n    <string name=\"exposure_confirm_permission_description\"><xliff:g example=\"microG Services\">%1$s</xliff:g> potrzebuje dodatkowych uprawnień.</string>\n    <string name=\"service_name_exposure\">Powiadomienia o narażaniu na kontakt</string>\n    <string name=\"pref_exposure_app_report_entry_distance_close\">bliski kontakt</string>\n    <string name=\"exposure_confirm_permission_button\">Udziel</string>\n    <string name=\"exposure_notify_off_bluetooth\">Bluetooth musi być włączony, aby otrzymywać powiadomienia o narażaniu na kontakt.</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning_confirm_button\">Usuń mimo tego</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_suffix\">Informacja: Poziom ryzyka jest ustalany przez aplikację. Wysokie liczby mogą oznaczać niskie ryzyko i vice versa.</string>\n    <string name=\"exposure_confirm_location_description\">Dostęp do lokalizacji jest wymagany.</string>\n    <string name=\"pref_exposure_error_bluetooth_no_advertise_summary\">Niestety twoje urządzenie jest tylko częściowo kompatybilne z powiadomieniami o narażaniu na kontakt. Możesz otrzymywać powiadomienia o ryzyku kontaktu, ale nie będziesz w stanie powiadomić innych.</string>\n    <string name=\"exposure_confirm_bluetooth_description\">Bluetooth musi być włączony.</string>\n    <string name=\"exposure_confirm_start_button\">Włącz</string>\n    <string name=\"prefcat_exposure_rpis_histogram_title\"><xliff:g example=\"230\">%1$d</xliff:g> zebranych ID</string>\n    <string name=\"pref_exposure_collected_rpis_summary\"><xliff:g example=\"63\">%1$d</xliff:g> ID w ciągu ostatniej godziny</string>\n    <string name=\"exposure_notify_off_location\">Dostęp do lokalizacji jest wymagany, aby otrzymywać powiadomienia o narażaniu na kontakt.</string>\n    <string name=\"prefcat_exposure_apps_title\">Aplikacje korzystające z powiadomień o narażaniu na kontakt</string>\n    <string name=\"exposure_confirm_stop_summary\">Po wyłączeniu powiadomień o narażeniu, przestaniesz być powiadamiany gdy zostałeś narażony na kontakt z osobą o pozytywnej diagnozie.</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_line\"><xliff:g example=\"Yesterday, 12:00 - 14:00\">%1$s</xliff:g>, poziom ryzyka: <xliff:g example=\"99\">%2$d</xliff:g></string>\n    <string name=\"exposure_confirm_stop_title\">Wyłączyć powiadomienia o narażaniu na kontakt?</string>\n    <string name=\"exposure_confirm_keys_summary\">Twoje identyfikatory w ciągu ostatnich 14 dni zostaną wykorzystane, aby pomóc powiadamiać innych o możliwym wystąpieniu narażenia na kontakt z wirusem.\n\\n\n\\nZarówno Twoja tożsamość jak i wynik testu nie zostanie udostępniona innym osobom.</string>\n    <string name=\"exposure_confirm_start_summary\">Telefon musi korzystać z Bluetooth, aby bezpiecznie gromadzić i udostępniać identyfikatory innym telefonom znajdującym się w pobliżu.\\n\\n<xliff:g example=\"Corona-Warn\">%1$s</xliff:g> może powiadomić użytkownika, jeśli był narażony na kontakt z osobą, u której zdiagnozowano pozytywny wynik.\\n\\nData, czas trwania i siła sygnału związane z ekspozycją zostaną udostępnione aplikacji.</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_no_records\">Brak wpisów</string>\n    <string name=\"pref_exposure_rpi_delete_all_title\">Usuń</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_title\">Wymagane nowe uprawnienia</string>\n    <string name=\"prefcat_exposure_app_report_title\">Wykryte narażenia</string>\n    <string name=\"exposure_notify_off_nearby\">Powiadomienia o narażaniu na kontakt wymagają dodatkowych uprawnień, aby działać prawidłowo</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning\">Usunięcie wszystkich zebranych identyfikatorów sprawi, że niemożliwe stanie się powiadomienie cię w przypadku gdy któryś z twoich kontaktów z ostatnich 14 dni był z osobą o pozytywnej diagnozie.</string>\n    <string name=\"exposure_confirm_keys_button\">Udostępnij</string>\n    <string name=\"exposure_grant_background_location_description\">Prawie gotowe! Musisz teraz udzielić dostępu do lokalizacji w tle poprzez wybranie opcji „Zawsze zezwalaj” na następnym ekranie. Następnie dotknij Wstecz.</string>\n    <string name=\"exposure_confirm_button\">Włącz</string>\n    <string name=\"pref_exposure_error_bluetooth_off_title\">Włącz Bluetooth</string>\n    <string name=\"pref_exposure_app_report_entry_time_about\">Około <xliff:g example=\"13\">%1$d</xliff:g> minut temu</string>\n</resources>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-pt/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=\"exposure_notify_off_title\">Notificações de exposição inativas</string>\n    <string name=\"exposure_notify_off_bluetooth\">O Bluetooth precisa ser ativado para receber notificações de exposição.</string>\n    <string name=\"exposure_notify_off_location\">O acesso à localização é necessário para receber notificações de exposição.</string>\n    <string name=\"exposure_notify_off_bluetooth_location\">O Bluetooth e o acesso à localização precisam estar ativados para receber notificações de exposição.</string>\n    <string name=\"exposure_notify_off_nearby\">As notificações de exposição precisam de permissões adicionais para funcionar</string>\n    <string name=\"service_name_exposure\">Notificações de exposição</string>\n    <string name=\"pref_exposure_enable_info_summary\">Para ativar as notificações de exposição, abra qualquer app que apoio elas.</string>\n    <string name=\"pref_exposure_error_bluetooth_off_title\">Ativar Bluetooth</string>\n    <string name=\"pref_exposure_error_location_off_title\">Abrir as configurações de localização</string>\n    <string name=\"pref_exposure_error_bluetooth_unsupported_summary\">Infelizmente, o seu dispositivo não é compatível com as notificações de exposição.</string>\n    <string name=\"pref_exposure_error_bluetooth_no_advertise_summary\">Infelizmente, o seu dispositivo é somente parcialmente compatível com as notificações de exposição. Poderá ser notificado por contactos de risco, mas não será possível notificar outros.</string>\n    <string name=\"prefcat_exposure_apps_title\">Apps usando as notificações de exposição</string>\n    <string name=\"pref_exposure_collected_rpis_title\">IDs coletados</string>\n    <string name=\"pref_exposure_collected_rpis_summary\"><xliff:g example=\"63\">%1$d</xliff:g> IDs na última hora</string>\n    <string name=\"pref_exposure_advertising_id_title\">ID atualmente transmitido</string>\n    <string name=\"prefcat_exposure_app_report_title\">Exposições reportadas</string>\n    <string name=\"pref_exposure_app_report_updated_title\">Atualizado: <xliff:g example=\"Today, 14:02\">%1$s</xliff:g></string>\n    <string name=\"pref_exposure_app_report_entry_time_short\">Menos que 5 minutos</string>\n    <string name=\"pref_exposure_app_report_entry_time_about\">Em volta de <xliff:g example=\"13\">%1$d</xliff:g> minutos</string>\n    <string name=\"pref_exposure_app_report_entry_distance_close\">exposição próxima</string>\n    <string name=\"pref_exposure_app_report_entry_distance_far\">exposição distante</string>\n    <string name=\"pref_exposure_app_report_entry_combined\"><xliff:g example=\"About 12 minutes\">%1$s</xliff:g>, <xliff:g example=\"distant exposure\">%2$s</xliff:g></string>\n    <string name=\"pref_exposure_app_last_report_summary_diagnosis_keys\"><xliff:g example=\"121031\">%1$d</xliff:g> chaves de diagnóstico processadas.</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_no\">Nenhuma exposição relatada.</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_prefix\"><xliff:g example=\"3\">%1$d</xliff:g> exposições relatadas:</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_line\"><xliff:g example=\"Yesterday, 12:00 - 14:00\">%1$s</xliff:g>, chance de risco <xliff:g example=\"99\">%2$d</xliff:g></string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_suffix\">Observação: A chance de risco é definida pela app. Números altos podem referir-se a pouca chance de risco, ou vice versa.</string>\n    <string name=\"pref_exposure_app_api_usage_title\">Uso da API nos últimos 14 dias</string>\n    <string name=\"pref_exposure_app_api_usage_summary_line\"><xliff:g example=\"12\">%1$d</xliff:g> solicitações para <xliff:g example=\"provideDiagnosisKeys\">%2$s</xliff:g></string>\n    <string name=\"prefcat_exposure_rpis_histogram_title\"><xliff:g example=\"230\">%1$d</xliff:g> IDs coletados</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_no_records\">Não há registos</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_records\"><xliff:g example=\"0 - 50\">%1$s</xliff:g> IDs por hora</string>\n    <string name=\"pref_exposure_rpi_delete_all_title\">Apagar</string>\n    <string name=\"pref_exposure_rpi_delete_all_summary\">Apagar todos os IDs coletados</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning\">Apagar os IDs coletados fará com que seja impossível notificar-lo no caso de algum contacto dos últimos 14 dias seja diagnosticado.</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning_confirm_button\">Apagar mesmo assim</string>\n    <string name=\"pref_exposure_rpi_export_title\">Exportar</string>\n    <string name=\"pref_exposure_rpi_export_summary\">Exportar IDs coletados para análise extensa com outra app.</string>\n    <string name=\"pref_exposure_info_summary\">A API de notificações de exposição permite que apps notifiquem-lo se ficou exposto a alguém que foi relatado a ter um diagnóstico positivo.\\n\\nA data, duração e força do sinal associada com uma exposição será partilhada com a app correspondente.</string>\n    <string name=\"pref_exposure_rpis_details_summary\">Ao ativar a API de notificações de exposição, o seu dispositivo coleta IDs passivamente (chamados de Rolling Proximity Identifiers, ou RPIs) de dispositivos próximos.\\n\\nQuando o dono de um dispositivo relata um diagnóstico positivo, os seus IDs podem serem partilhados. O seu dispositivo verifica que qualquer um dos IDs conhecidos como positivos conferem com IDs coletados e calcula o seu risco de infecção.</string>\n    <string name=\"exposure_enable_switch\">Usar notificações de exposição</string>\n    <string name=\"exposure_confirm_start_title\">Ativar as notificações de exposição?</string>\n    <string name=\"exposure_confirm_start_summary\">O seu dispositivo precisa utilizar o Bluetooth para coletar e partilhar IDs com segurança para dispositivos por perto.\\n\\n<xliff:g example=\"Corona-Warn\">%1$s</xliff:g> pode notificar-lo se foi exposto a alguém que teve um diagnóstico positivo.\\n\\nA data, duração e força do sinal associada com uma exposição será partilhada com a app.</string>\n    <string name=\"exposure_confirm_start_button\">Ligar</string>\n    <string name=\"exposure_confirm_stop_title\">Desativar as notificações de exposição?</string>\n    <string name=\"exposure_confirm_stop_summary\">Após desativar as notificações de exposição, já não será notificado caso foi exposto a alguém com o diagnóstico positivo.</string>\n    <string name=\"exposure_confirm_stop_button\">Desativar</string>\n    <string name=\"exposure_confirm_keys_title\">Partilhar os seus IDs com <xliff:g example=\"Corona-Warn\">%1$s</xliff:g>\\?</string>\n    <string name=\"exposure_confirm_keys_summary\">Os seus IDs dos últimos 14 dias serão utilizados para notificar outros que esteve perto de uma potencial exposição.\\n\\nSua identidade ou resultado de exames não serão partilhados com outras pessoas.</string>\n    <string name=\"exposure_confirm_keys_button\">Partilhar</string>\n    <string name=\"exposure_confirm_permission_description\"><xliff:g example=\"microG Services\">%1$s</xliff:g> precisa de permissões adicionais.</string>\n    <string name=\"exposure_confirm_permission_button\">Conceder</string>\n    <string name=\"exposure_confirm_bluetooth_description\">O Bluetooth precisa ser ativado.</string>\n    <string name=\"exposure_confirm_location_description\">O acesso à localização é necessário.</string>\n    <string name=\"exposure_confirm_button\">Ativar</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_title\">Novas permissões necessárias</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_description\">Toque para permitir permissões necessárias para as notificações de exposição</string>\n    <string name=\"exposure_grant_background_location_description\">Quase chegou! Precisará ativar acesso à localização em segundo plano selecionando a opção \\\"Permitir o tempo todo\\\" no próximo ecrã. E depois volte.</string>\n    <string name=\"exposure_grant_background_location_button\">Atualizar configurações</string>\n</resources>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-pt-rBR/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=\"pref_exposure_app_last_report_summary_encounters_prefix\"><xliff:g example=\"3\">%1$d</xliff:g> exposições relatadas:</string>\n    <string name=\"pref_exposure_app_api_usage_summary_line\"><xliff:g example=\"12\">%1$d</xliff:g> solicitações para <xliff:g example=\"provideDiagnosisKeys\">%2$s</xliff:g></string>\n    <string name=\"prefcat_exposure_rpis_histogram_title\"><xliff:g example=\"230\">%1$d</xliff:g> IDs coletados</string>\n    <string name=\"exposure_confirm_keys_title\">Compartilhar seus IDs com <xliff:g example=\"Corona-Warn\">%1$s</xliff:g>\\?</string>\n    <string name=\"pref_exposure_error_bluetooth_unsupported_summary\">Infelizmente, seu dispositivo não é compatível com as notificações de exposição.</string>\n    <string name=\"pref_exposure_error_bluetooth_no_advertise_summary\">Infelizmente, seu dispositivo é somente parcialmente compatível com as notificações de exposição. Você poderá ser notificado por contatos de risco, mas não será possível notificar outros.</string>\n    <string name=\"prefcat_exposure_apps_title\">Apps usando as notificações de exposição</string>\n    <string name=\"pref_exposure_collected_rpis_title\">IDs coletados</string>\n    <string name=\"pref_exposure_collected_rpis_summary\"><xliff:g example=\"63\">%1$d</xliff:g> IDs na última hora</string>\n    <string name=\"pref_exposure_advertising_id_title\">ID atualmente transmitido</string>\n    <string name=\"prefcat_exposure_app_report_title\">Exposições reportadas</string>\n    <string name=\"pref_exposure_app_report_updated_title\">Atualizado: <xliff:g example=\"Today, 14:02\">%1$s</xliff:g></string>\n    <string name=\"pref_exposure_app_report_entry_time_short\">Menos que 5 minutos</string>\n    <string name=\"pref_exposure_app_report_entry_time_about\">Em volta de <xliff:g example=\"13\">%1$d</xliff:g> minutos</string>\n    <string name=\"pref_exposure_app_report_entry_combined\"><xliff:g example=\"About 12 minutes\">%1$s</xliff:g>, <xliff:g example=\"distant exposure\">%2$s</xliff:g></string>\n    <string name=\"pref_exposure_app_last_report_summary_diagnosis_keys\"><xliff:g example=\"121031\">%1$d</xliff:g> chaves de diagnóstico processadas.</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_line\"><xliff:g example=\"Yesterday, 12:00 - 14:00\">%1$s</xliff:g>, chance de risco <xliff:g example=\"99\">%2$d</xliff:g></string>\n    <string name=\"pref_exposure_rpis_histogram_legend_records\"><xliff:g example=\"0 - 50\">%1$s</xliff:g> IDs por hora</string>\n    <string name=\"exposure_confirm_start_summary\">Seu dispositivo precisa utilizar o Bluetooth para coletar e compartilhar IDs com segurança para dispositivos por perto.\\n\\n<xliff:g example=\"Corona-Warn\">%1$s</xliff:g> pode te notificar se você foi exposto à alguém que teve um diagnóstico positivo.\\n\\nA data, duração, e força do sinal associada com uma exposição será compartilhada com o app.</string>\n    <string name=\"exposure_notify_off_title\">Notificações de exposição inativas</string>\n    <string name=\"exposure_notify_off_bluetooth\">O Bluetooth precisa ser ativado para receber notificações de exposição.</string>\n    <string name=\"exposure_notify_off_location\">O acesso à localização é necessário para receber notificações de exposição.</string>\n    <string name=\"exposure_notify_off_bluetooth_location\">O Bluetooth e o acesso à localização precisam estar ativados para receber notificações de exposição.</string>\n    <string name=\"exposure_notify_off_nearby\">As notificações de exposição precisam de permissões adicionais para funcionar</string>\n    <string name=\"service_name_exposure\">Notificações de exposição</string>\n    <string name=\"pref_exposure_enable_info_summary\">Para ativar as notificações de exposição, abra qualquer app que suporte elas.</string>\n    <string name=\"pref_exposure_error_bluetooth_off_title\">Ativar Bluetooth</string>\n    <string name=\"pref_exposure_error_location_off_title\">Abrir as configurações de localização</string>\n    <string name=\"pref_exposure_app_report_entry_distance_close\">exposição próxima</string>\n    <string name=\"pref_exposure_app_report_entry_distance_far\">exposição distante</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_no\">Nenhuma exposição relatada.</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_suffix\">Observação: A chance de risco é configurada pelo app. Números altos podem se referir a pouca chance de risco, ou vice versa.</string>\n    <string name=\"pref_exposure_app_api_usage_title\">Uso da API nos últimos 14 dias</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_no_records\">Não há registros</string>\n    <string name=\"pref_exposure_rpi_delete_all_title\">Apagar</string>\n    <string name=\"pref_exposure_rpi_delete_all_summary\">Apagar todos os IDs coletados</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning\">Apagar os IDs coletados fará com que seja impossível te notificar no caso de algum contato dos últimos 14 dias seja diagnosticado.</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning_confirm_button\">Apagar mesmo assim</string>\n    <string name=\"pref_exposure_rpi_export_title\">Exportar</string>\n    <string name=\"pref_exposure_rpi_export_summary\">Exportar IDs coletados para análise extensa com outro app.</string>\n    <string name=\"pref_exposure_info_summary\">A API de notificações de exposição permite que apps te notifiquem se você ficou exposto a alguém que foi relatado tendo um diagnóstico positivo.\\n\\nA data, duração, e força do sinal associada com uma exposição será compartilhada com o app correspondente.</string>\n    <string name=\"pref_exposure_rpis_details_summary\">Ao ativar a API de notificações de exposição, seu dispositivo coleta IDs passivamente (chamados de Rolling Proximity Identifiers, ou RPIs) de dispositivos próximos.\\n\\nQuando o dono de um dispositivo relata um diagnóstico positivo, seus IDs podem serem compartilhados. Seu dispositivo verifica que qualquer um dos IDs conhecidos como positivos conferem com IDs coletados e calcula seu risco de infecção.</string>\n    <string name=\"exposure_enable_switch\">Usar notificações de exposição</string>\n    <string name=\"exposure_confirm_start_title\">Ativar as notificações de exposição?</string>\n    <string name=\"exposure_confirm_start_button\">Ativar</string>\n    <string name=\"exposure_confirm_stop_title\">Desativar as notificações de exposição?</string>\n    <string name=\"exposure_confirm_stop_summary\">Após desativar as notificações de exposição, você não será mais notificado caso foi exposto a alguém com o diagnóstico positivo.</string>\n    <string name=\"exposure_confirm_stop_button\">Desativar</string>\n    <string name=\"exposure_confirm_keys_summary\">Seus IDs dos últimos 14 dias serão utilizados para notificar outros que você esteve perto de uma potencial exposição.\\n\\nSua identidade ou resultado de exames não serão compartilhados com outras pessoas.</string>\n    <string name=\"exposure_confirm_keys_button\">Compartilhar</string>\n    <string name=\"exposure_confirm_permission_description\"><xliff:g example=\"microG Services\">%1$s</xliff:g> precisa de permissões adicionais.</string>\n    <string name=\"exposure_confirm_permission_button\">Permitir</string>\n    <string name=\"exposure_confirm_bluetooth_description\">O Bluetooth precisa ser ativado.</string>\n    <string name=\"exposure_confirm_location_description\">O acesso à localização é necessário.</string>\n    <string name=\"exposure_confirm_button\">Ativar</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_title\">Novas permissões necessárias</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_description\">Toque para permitir permissões necessárias para as notificações de exposição</string>\n    <string name=\"exposure_grant_background_location_description\">Quase lá! Você precisará ativar acesso à localização em segundo plano selecionando a opção \\\"Permitir o tempo todo\\\" na próxima tela. E então volte.</string>\n    <string name=\"exposure_grant_background_location_button\">Atualizar configurações</string>\n</resources>\n"
  },
  {
    "path": "play-services-nearby/core/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=\"pref_exposure_app_report_entry_combined\"><xliff:g example=\"About 12 minutes\">%1$s</xliff:g>, <xliff:g example=\"distant exposure\">%2$s</xliff:g></string>\n    <string name=\"exposure_notify_off_bluetooth_location\">Accesul la Bluetooth și la locație trebuie să fie activat pentru a primi notificări de expunere.</string>\n    <string name=\"pref_exposure_advertising_id_title\">ID difuzat în prezent</string>\n    <string name=\"pref_exposure_error_bluetooth_unsupported_summary\">Din păcate, dispozitivul nu este compatibil cu notificări de expunere.</string>\n    <string name=\"pref_exposure_collected_rpis_title\">ID-uri colectate</string>\n    <string name=\"pref_exposure_app_report_entry_time_short\">Mai puțin de 5 minute</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_no\">Nu au fost raportate întâlniri de expunere.</string>\n    <string name=\"pref_exposure_app_report_entry_distance_far\">expunere la distanță</string>\n    <string name=\"pref_exposure_app_last_report_summary_diagnosis_keys\">Au fost procesate <xliff:g example=\"121031\">%1$d</xliff:g> chei de diagnosticare.</string>\n    <string name=\"exposure_notify_off_title\">Notificări de expunere dezactivate</string>\n    <string name=\"pref_exposure_app_report_updated_title\">Actualizat: <xliff:g example=\"Today, 14:02\">%1$s</xliff:g></string>\n    <string name=\"pref_exposure_error_location_off_title\">Deschide setările pentru locație</string>\n    <string name=\"pref_exposure_enable_info_summary\">Pentru a activa notificările de expunere, deschide orice aplicație care o acceptă.</string>\n    <string name=\"service_name_exposure\">Notificări de expunere</string>\n    <string name=\"pref_exposure_app_report_entry_distance_close\">expunere în apropiere</string>\n    <string name=\"exposure_notify_off_bluetooth\">Bluetooth trebuie să fie activat pentru a primi notificări de expunere.</string>\n    <string name=\"pref_exposure_error_bluetooth_no_advertise_summary\">Din păcate, dispozitivul este doar parțial compatibil cu notificările de expunere. Poți fi notificat pentru contacte cu risc, dar nu vei putea notifica pe alții.</string>\n    <string name=\"pref_exposure_collected_rpis_summary\"><xliff:g example=\"63\">%1$d</xliff:g> ID-uri în ultima oră</string>\n    <string name=\"exposure_notify_off_location\">Accesul la locație este necesar pentru a primi notificări de expunere.</string>\n    <string name=\"prefcat_exposure_apps_title\">Aplicații care utilizează notificări de expunere</string>\n    <string name=\"prefcat_exposure_app_report_title\">Expunerile raportate</string>\n    <string name=\"exposure_notify_off_nearby\">Notificările de expunere necesită permisiuni suplimentare pentru a funcționa</string>\n    <string name=\"pref_exposure_error_bluetooth_off_title\">Activează Bluetooth</string>\n    <string name=\"pref_exposure_app_report_entry_time_about\">Aproximativ <xliff:g example=\"13\">%1$d</xliff:g> minute</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_prefix\">Au fost raportate <xliff:g example=\"3\">%1$d</xliff:g> întâlniri de expunere:</string>\n    <string name=\"pref_exposure_app_api_usage_title\">Utilizarea API-ului în ultimele 14 zile</string>\n    <string name=\"pref_exposure_rpi_export_summary\">Exportă ID-urile colectate pentru o analiză extinsă cu o altă aplicație.</string>\n    <string name=\"pref_exposure_rpi_export_title\">Export</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_records\"><xliff:g example=\"0 - 50\">%1$s</xliff:g> ID-uri pe oră</string>\n    <string name=\"pref_exposure_info_summary\">Exposure Notifications API permite aplicațiilor să te anunțe dacă ai fost expus la cineva care a raportat că a fost diagnosticat pozitiv.\n\\n\n\\nData, durata și puterea semnalului asociate cu o expunere vor fi partajate cu aplicația corespunzătoare.</string>\n    <string name=\"pref_exposure_app_api_usage_summary_line\"><xliff:g example=\"12\">%1$d</xliff:g> apeluri la <xliff:g example=\"provideDiagnosisKeys\">%2$s</xliff:g></string>\n    <string name=\"pref_exposure_rpi_delete_all_summary\">Șterge toate ID-urile colectate</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning_confirm_button\">Șterge oricum</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_suffix\">Notă: scorul de risc este definit de aplicație. Cifrele mari se pot referi la un risc scăzut sau invers.</string>\n    <string name=\"prefcat_exposure_rpis_histogram_title\"><xliff:g example=\"230\">%1$d</xliff:g> ID-uri colectate</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_line\"><xliff:g example=\"Yesterday, 12:00 - 14:00\">%1$s</xliff:g>, scor de risc <xliff:g example=\"99\">%2$d</xliff:g></string>\n    <string name=\"pref_exposure_rpis_histogram_legend_no_records\">Nicio înregistrare</string>\n    <string name=\"pref_exposure_rpi_delete_all_title\">Șterge</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning\">Ștergerea ID-urilor colectate va face imposibilă anunțarea în cazul în care vreunul dintre contacte din ultimele 14 zile este diagnosticat.</string>\n    <string name=\"exposure_confirm_start_title\">Activezi notificările de expunere\\?</string>\n    <string name=\"exposure_enable_switch\">Utilizează notificări de expunere</string>\n    <string name=\"pref_exposure_rpis_details_summary\">În timp ce API-ul Exposure Notification este activat, dispozitivul colectează pasiv ID-uri (numite Rolling Proximity Identifiers sau RPI) de la dispozitivele din apropiere.\n\\n\n\\nCând proprietarii de dispozitive raportează că sunt diagnosticați pozitivi, ID-urile lor pot fi partajate. Dispozitivul verifică dacă vreunul dintre ID-urile diagnosticate cunoscute se potrivește cu oricare dintre ID-urile colectate și calculează riscul de infecție.</string>\n    <string name=\"exposure_confirm_start_summary\">Telefonul trebuie să utilizeze Bluetooth pentru a colecta și a partaja ID-uri în siguranță cu alte telefoane din apropiere.\\n\\n<xliff:g example=\"Corona-Warn\">%1$s</xliff:g> poate anunța dacă ai fost expus la cineva care a raportat că a fost diagnosticat pozitiv.\\n\\nData, durata și puterea semnalului asociate cu o expunere vor fi partajate cu aplicația.</string>\n    <string name=\"exposure_confirm_stop_title\">Dezactivezi notificările de expunere?</string>\n    <string name=\"exposure_confirm_stop_button\">Oprire</string>\n    <string name=\"exposure_confirm_stop_summary\">După dezactivarea notificărilor de expunere, nu vei mai fi notificat când ai fost expus la cineva care a raportat că a fost diagnosticat pozitiv.</string>\n    <string name=\"exposure_confirm_start_button\">Pornește</string>\n    <string name=\"exposure_confirm_keys_button\">Distribuie</string>\n    <string name=\"exposure_confirm_permission_button\">Acordă</string>\n    <string name=\"exposure_confirm_button\">Activează</string>\n    <string name=\"exposure_confirm_keys_title\">Partajezi ID-urile cu <xliff:g example=\"Corona-Warn\">%1$s</xliff:g>\\?</string>\n    <string name=\"exposure_confirm_keys_summary\">ID-urile tale din ultimele 14 zile vor fi folosite pentru a-i anunța pe alții că ai fost aproape despre o potențială expunere.\n\\n\n\\nIdentitatea sau rezultatul testului nu vor fi partajate altor persoane.</string>\n    <string name=\"exposure_grant_background_location_description\">Aproape gata! Va trebui să activezi accesul la locația de fundal selectând opțiunea „Permite tot timpul” pe ecranul următor. Apoi apasă înapoi.</string>\n    <string name=\"exposure_confirm_permission_description\"><xliff:g example=\"microG Services\">%1$s</xliff:g> necesită permisiuni suplimentare.</string>\n    <string name=\"exposure_confirm_bluetooth_description\">Bluetooth trebuie să fie activat.</string>\n    <string name=\"exposure_confirm_location_description\">Este necesar accesul la locație.</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_title\">Sunt necesare permisiuni noi</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_description\">Atinge pentru a acorda permisiunile necesare notificărilor de expunere</string>\n    <string name=\"exposure_grant_background_location_button\">Actualizare setări</string>\n</resources>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-ru/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"exposure_notify_off_title\">Уведомления о риске инфицирования не активны</string>\n    <string name=\"exposure_notify_off_bluetooth\">Bluetooth должен быть включён, чтобы принимать уведомления о риске инфицирования.</string>\n    <string name=\"exposure_notify_off_location\">Доступ к местоположению обязателен, чтобы принимать уведомления о риске инфицирования.</string>\n    <string name=\"exposure_notify_off_bluetooth_location\">Bluetooth и определение местоположения должны быть включены, чтобы принимать уведомления о риске инфицирования.</string>\n    <string name=\"exposure_notify_off_nearby\">Уведомлениям о риске инфицирования для работы требуются дополнительные разрешения</string>\n    <string name=\"service_name_exposure\">Уведомления о риске инфицирования</string>\n    <string name=\"pref_exposure_enable_info_summary\">Чтобы включить уведомления о риске инфицирования запустите любое приложение, которое их поддерживает.</string>\n    <string name=\"pref_exposure_error_bluetooth_off_title\">Включить Bluetooth</string>\n    <string name=\"pref_exposure_error_location_off_title\">Открыть настройки местоположения</string>\n    <string name=\"pref_exposure_error_bluetooth_unsupported_summary\">К сожалению ваше устройство несовместимо с уведомлениями о риске инфицирования.</string>\n    <string name=\"pref_exposure_error_bluetooth_no_advertise_summary\">К сожалению ваше устройство лишь частично совместимо с уведомлениями о риске инфицирования. Вы можете получать уведомления об опасных контактах, но не сможете уведомлять других.</string>\n    <string name=\"prefcat_exposure_apps_title\">Приложения использующие уведомления о риске инфицирования</string>\n    <string name=\"pref_exposure_collected_rpis_title\">Собранные идентификаторы</string>\n    <string name=\"pref_exposure_collected_rpis_summary\"><xliff:g example=\"63\">%1$d</xliff:g> Количество идентификаторов за последний час</string>\n    <string name=\"pref_exposure_advertising_id_title\">Транслируемый в настоящее время идентификатор</string>\n    <string name=\"prefcat_exposure_app_report_title\">Сообщения о взаимодействиях</string>\n    <string name=\"pref_exposure_app_report_updated_title\">Обновлено: <xliff:g example=\"Today, 14:02\">%1$s</xliff:g></string>\n    <string name=\"pref_exposure_app_report_entry_time_short\">Менее пяти минут назад</string>\n    <string name=\"pref_exposure_app_report_entry_time_about\">Около <xliff:g example=\"13\">%1$d</xliff:g> минут</string>\n    <string name=\"pref_exposure_app_report_entry_distance_close\">взаимодействия рядом</string>\n    <string name=\"pref_exposure_app_report_entry_distance_far\">взаимодействия далеко</string>\n    <string name=\"pref_exposure_app_report_entry_combined\"><xliff:g example=\"About 12 minutes\">%1$s</xliff:g>, <xliff:g example=\"distant exposure\">%2$s</xliff:g></string>\n    <string name=\"pref_exposure_app_last_report_summary_diagnosis_keys\">Обработано <xliff:g example=\"121031\">%1$d</xliff:g> диагностических ключей.</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_no\">Сообщения об опасных контактах отсутствуют.</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_prefix\">Сообщено о <xliff:g example=\"3\">%1$d</xliff:g> опасных контактах:</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_line\"><xliff:g example=\"Yesterday, 12:00 - 14:00\">%1$s</xliff:g>, оценка риска <xliff:g example=\"99\">%2$d</xliff:g></string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_suffix\">Примечание: Оценка риска определяется приложением. Высокие числа могут говорить, как о низком риске так и наоборот.</string>\n    <string name=\"pref_exposure_app_api_usage_title\">Использование API за последние 14 дней</string>\n    <string name=\"pref_exposure_app_api_usage_summary_line\"><xliff:g example=\"12\">%1$d</xliff:g> запросов к <xliff:g example=\"provideDiagnosisKeys\">%2$s</xliff:g></string>\n    <string name=\"prefcat_exposure_rpis_histogram_title\"><xliff:g example=\"230\">%1$d</xliff:g> идентификаторов собрано</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_no_records\">Нет записей</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_records\"><xliff:g example=\"0 - 50\">%1$s</xliff:g> Идентификаторов в час</string>\n    <string name=\"pref_exposure_rpi_delete_all_title\">Удалить</string>\n    <string name=\"pref_exposure_rpi_delete_all_summary\">Удалить все собранные идентификаторы</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning\">Удаление собранных идентификаторов приведёт к невозможности информирования в случае, если у одного из ваших контактов за последние 14 дней окажется положительный диагноз.</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning_confirm_button\">Всё равно удалить</string>\n    <string name=\"pref_exposure_rpi_export_title\">Экспортировать</string>\n    <string name=\"pref_exposure_rpi_export_summary\">Экспортировать собранные идентификаторы для расширенного анализа в стороннем приложении.</string>\n    <string name=\"pref_exposure_info_summary\">\"API Уведомлений о риске инфицирования (Exposure Notifications API) позволяет приложениям уведомлять вас, если вы столкнулись с кем-то, у кого был положительный диагноз.\n\nДата, продолжительность и мощность сигнала, связанные с воздействием, будут переданы соответствующему приложению.\"</string>\n    <string name=\"pref_exposure_rpis_details_summary\">\"Пока API уведомлений о риске инфицирования включен, ваше устройство пассивно собирает идентификаторы (называемые скользящими идентификаторами сближения или RPI) с соседних устройств.\n\nКогда владельцы устройств сообщают о положительном диагнозе, их идентификаторы могут быть распространены. Ваше устройство проверяет, соответствует ли какой-либо из известных идентификаторов с подтверждённым диагнозом любому из собранных вами идентификаторов, и рассчитывает риск заражения.\"</string>\n    <string name=\"exposure_enable_switch\">Использовать уведомления о риске инфицирования</string>\n    <string name=\"exposure_confirm_start_title\">Включить уведомлений о риске инфицирования?</string>\n    <string name=\"exposure_confirm_start_summary\">\"Ваш телефон должен использовать Bluetooth для безопасного сбора и распространения идентификаторов другим телефонам, находящимся поблизости.\n\n<xliff:g example=\"Corona-Warn\">%1$s</xliff:g> может уведомить вас, если вы пересекались с кем-то, у кого был подтверждён положительный диагноз.\n\nДата, продолжительность и мощность сигнала, связанные с контактом, будут переданы приложению.\"</string>\n    <string name=\"exposure_confirm_start_button\">Включить</string>\n    <string name=\"exposure_confirm_stop_title\">Выключить уведомления о риске инфицирования?</string>\n    <string name=\"exposure_confirm_stop_summary\">После отключения уведомлений вы больше не будете получать уведомления о контактах с кем-то, у кого был положительный диагноз.</string>\n    <string name=\"exposure_confirm_stop_button\">Выключить</string>\n    <string name=\"exposure_confirm_keys_title\">Делиться вашими идентификаторами с <xliff:g example=\"Corona-Warn\">%1$s</xliff:g>?</string>\n    <string name=\"exposure_confirm_keys_summary\">\"Ваши идентификаторы за последние 14 дней будут использоваться для уведомления других о том, что вы были вблизи потенциальной опасности.\n\nВаша личность или результат теста не будут переданы другим людям.\"</string>\n    <string name=\"exposure_confirm_keys_button\">Поделиться</string>\n    <string name=\"exposure_confirm_permission_description\">Для <xliff:g example=\"microG Services\">%1$s</xliff:g> требуются дополнительные разрешения.</string>\n    <string name=\"exposure_confirm_permission_button\">Предоставить</string>\n    <string name=\"exposure_confirm_bluetooth_description\">Bluetooth должен быть включён.</string>\n    <string name=\"exposure_confirm_location_description\">требуется доступ к местоположению.</string>\n    <string name=\"exposure_confirm_button\">Включить</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_title\">Требуется дополнительное разрешение</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_description\">Нажмите, чтобы предоставить необходимые разрешения уведомлениям о риске инфицирования</string>\n    <string name=\"exposure_grant_background_location_description\">Почти готово! Вам нужно будет включить фоновый доступ к местоположению, выбрав опцию \\'Разрешить в любом режиме\\' на следующем экране. Затем вернитесь назад.</string>\n    <string name=\"exposure_grant_background_location_button\">Обновить настройки</string>\n</resources>"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-sl/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n</resources>"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-sr/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=\"pref_exposure_app_last_report_summary_encounters_prefix\">Пријављено <xliff:g example=\"3\"> %1$d</xliff:g> случајева изложености:</string>\n    <string name=\"pref_exposure_app_report_entry_combined\"><xliff:g example=\"About 12 minutes\">%1$s</xliff:g>, <xliff:g example=\"distant exposure\">%2$s</xliff:g></string>\n    <string name=\"pref_exposure_app_api_usage_title\">Употреба API-ја у последњих 14 дана</string>\n    <string name=\"pref_exposure_rpi_export_summary\">Извезите прикупљене ID-ове за проширену анализу помоћу друге апликације.</string>\n    <string name=\"exposure_notify_off_bluetooth_location\">Bluetooth и приступ локацији морају бити омогућени да бисте примали обавештења о изложености.</string>\n    <string name=\"exposure_confirm_stop_button\">Искључи</string>\n    <string name=\"pref_exposure_advertising_id_title\">Тренутно емитовани ID</string>\n    <string name=\"exposure_confirm_start_title\">Укључити обавештења о изложености\\?</string>\n    <string name=\"pref_exposure_error_bluetooth_unsupported_summary\">Нажалост, ваш уређај није компатибилан са обавештењима о изложености.</string>\n    <string name=\"pref_exposure_collected_rpis_title\">Прикупљени ID-ови</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_description\">Додирните да бисте дали потребне дозволе за обавештења о изложености</string>\n    <string name=\"pref_exposure_app_report_entry_time_short\">Мање од 5 минута</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_no\">Нема пријављених случајева изложености.</string>\n    <string name=\"pref_exposure_app_report_entry_distance_far\">удаљена изложеност</string>\n    <string name=\"exposure_confirm_keys_title\">Делити ваш ID са <xliff:g example=\"Corona-Warn\"> %1$s</xliff:g>\\?</string>\n    <string name=\"exposure_enable_switch\">Користи обавештења о изложености</string>\n    <string name=\"pref_exposure_app_last_report_summary_diagnosis_keys\">Обрађено <xliff:g example=\"121031\"> %1$d</xliff:g> кључева за дијагнозу.</string>\n    <string name=\"pref_exposure_rpi_export_title\">Извоз</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_records\"><xliff:g example=\"0 - 50\">%1$s</xliff:g> ID-ова по сату</string>\n    <string name=\"exposure_notify_off_title\">Обавештења о изложености су неактивна</string>\n    <string name=\"pref_exposure_app_report_updated_title\">Ажурирано: <xliff:g example=\"Today, 14:02\"> %1$s</xliff:g></string>\n    <string name=\"exposure_grant_background_location_button\">Ажурирај подешавања</string>\n    <string name=\"pref_exposure_error_location_off_title\">Отвори подешавања локације</string>\n    <string name=\"pref_exposure_rpis_details_summary\">Док је API за обавештења о изложености омогућен, ваш уређај пасивно прикупља ID-ове (који се називају Rolling Proximity Identifiers или RPI) са оближњих уређаја.\n\\n\n\\nКада власници уређаја пријаве да су позитивни, њихови ID-ови могу да се деле. Ваш уређај проверава да ли се неки од познатих дијагностикованих ID-ова поклапа са било којим од прикупљених ID-ова и израчунава ризик од инфекције.</string>\n    <string name=\"pref_exposure_info_summary\">API за обавештења о изложености (Exposure Notifications API) омогућава апликацијама да вас обавесте ако сте били изложени некоме ко је пријавио да је позитиван.\n\\n\n\\nДатум, трајање и јачина сигнала повезани са изложеношћу ће се делити са одговарајућом апликацијом.</string>\n    <string name=\"pref_exposure_app_api_usage_summary_line\"><xliff:g example=\"12\">%1$d</xliff:g> позива на <xliff:g example=\"provideDiagnosisKeys\">%2$s</xliff:g></string>\n    <string name=\"pref_exposure_enable_info_summary\">Да бисте омогућили обавештења о изложености, отворите било коју апликацију која то подржава.</string>\n    <string name=\"pref_exposure_rpi_delete_all_summary\">Избришите све прикупљене ID-ове</string>\n    <string name=\"exposure_confirm_permission_description\"><xliff:g example=\"microG Services\">%1$s</xliff:g> треба додатне дозволе.</string>\n    <string name=\"service_name_exposure\">Обавештења о изложености</string>\n    <string name=\"pref_exposure_app_report_entry_distance_close\">оближња изложеност</string>\n    <string name=\"exposure_confirm_permission_button\">Дај</string>\n    <string name=\"exposure_notify_off_bluetooth\">Bluetooth треба да буде омогућен да бисте примали обавештења о изложености.</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning_confirm_button\">Избриши свакако</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_suffix\">Напомена: Оцену ризика дефинише апликација. Високи бројеви могу се односити на низак ризик или обрнуто.</string>\n    <string name=\"exposure_confirm_location_description\">Приступ локацији је неопходан.</string>\n    <string name=\"pref_exposure_error_bluetooth_no_advertise_summary\">Нажалост, ваш уређај је само делимично компатибилан са обавештењима о изложености. Можете бити обавештени за ризичне контакте, али нећете моћи да обавестите друге.</string>\n    <string name=\"exposure_confirm_bluetooth_description\">Bluetooth треба да буде омогућен.</string>\n    <string name=\"exposure_confirm_start_button\">Укључи</string>\n    <string name=\"prefcat_exposure_rpis_histogram_title\"><xliff:g example=\"230\">%1$d</xliff:g> ID-ова прикупљено</string>\n    <string name=\"pref_exposure_collected_rpis_summary\"><xliff:g example=\"63\">%1$d</xliff:g> ID-ова у последњем сату</string>\n    <string name=\"exposure_notify_off_location\">Приступ локацији је неопходан да бисте примали обавештења о изложености.</string>\n    <string name=\"prefcat_exposure_apps_title\">Апликације које користе обавештења о изложености</string>\n    <string name=\"exposure_confirm_stop_summary\">Након што онемогућите обавештења о изложености, више нећете бити обавештени када сте били изложени некоме ко је пријавио да је позитиван.</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_line\"><xliff:g example=\"Yesterday, 12:00 - 14:00\">%1$s</xliff:g>, оцена ризика <xliff:g example=\"99\">%2$d</xliff:g></string>\n    <string name=\"exposure_confirm_stop_title\">Искључити обавештења о изложености\\?</string>\n    <string name=\"exposure_confirm_keys_summary\">Ваши ID-ови из последњих 14 дана ће се користити за обавештавање других да сте били у близини о потенцијалној изложености.\n\\n\n\\nВаш идентитет или резултат теста се неће делити са другим људима.</string>\n    <string name=\"exposure_confirm_start_summary\">Ваш телефон мора да користи Bluetooth за безбедно прикупљање и дељење ID-ова са другим телефонима који су у близини.\\n\\n<xliff:g example=\"Corona-Warn\"> %1$s</xliff:g> може да вас обавести ако сте били изложени некоме ко је пријавио да је позитиван.\\n\\nДатум, трајање и јачина сигнала повезани са изложеношћу ће се делити са апликацијом.</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_no_records\">Нема записа</string>\n    <string name=\"pref_exposure_rpi_delete_all_title\">Избриши</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_title\">Нове дозволе су неопходне</string>\n    <string name=\"prefcat_exposure_app_report_title\">Пријављене изложености</string>\n    <string name=\"exposure_notify_off_nearby\">Обавештења о изложености захтевају додатне дозволе за рад</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning\">Брисањем прикупљених ID-ова биће немогуће да вас обавестимо у случају да се дијагностикује било који од ваших контаката у последњих 14 дана.</string>\n    <string name=\"exposure_confirm_keys_button\">Дели</string>\n    <string name=\"exposure_grant_background_location_description\">Скоро готово! Мораћете да омогућите приступ локацији у позадини тако што ћете на следећем екрану изабрати опцију „Дозволи све време“. Затим притисните назад.</string>\n    <string name=\"exposure_confirm_button\">Омогући</string>\n    <string name=\"pref_exposure_error_bluetooth_off_title\">Омогући Bluetooth</string>\n    <string name=\"pref_exposure_app_report_entry_time_about\">Око <xliff:g example=\"13\"> %1$d</xliff:g> минута</string>\n</resources>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-sv/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=\"pref_exposure_app_last_report_summary_encounters_prefix\">Rapporterade <xliff:g example=\"3\">%1$d</xliff:g> exponeringsmöten:</string>\n    <string name=\"pref_exposure_app_report_entry_combined\"><xliff:g example=\"About 12 minutes\">%1$s</xliff:g>, <xliff:g example=\"distant exposure\">%2$s</xliff:g></string>\n    <string name=\"pref_exposure_app_api_usage_title\">API-användning senaste 14 dagarna</string>\n    <string name=\"pref_exposure_rpi_export_summary\">Exportera insamlade ID:n för utökad analys med en annan app.</string>\n    <string name=\"exposure_notify_off_bluetooth_location\">Bluetooth och platsåtkomst måste vara aktiverat för att ta emot exponeringsmeddelanden.</string>\n    <string name=\"exposure_confirm_stop_button\">Stäng av</string>\n    <string name=\"pref_exposure_advertising_id_title\">För närvarande sänt ID</string>\n    <string name=\"exposure_confirm_start_title\">Vill du slå på exponeringsmeddelanden?</string>\n    <string name=\"pref_exposure_error_bluetooth_unsupported_summary\">Din enhet är inte kompatibel med exponeringsmeddelanden.</string>\n    <string name=\"pref_exposure_collected_rpis_title\">Insamlade ID:n</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_description\">Tryck för att bevilja nödvändiga behörigheter för exponeringsmeddelanden</string>\n    <string name=\"pref_exposure_app_report_entry_time_short\">Mindre än 5 minuter</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_no\">Inga exponeringsmöten rapporterade.</string>\n    <string name=\"pref_exposure_app_report_entry_distance_far\">avlägsen exponering</string>\n    <string name=\"exposure_confirm_keys_title\">Dela dina ID:n med <xliff:g example=\"Corona-Warn\">%1$s</xliff:g>\\?</string>\n    <string name=\"exposure_enable_switch\">Använd exponeringsmeddelanden</string>\n    <string name=\"pref_exposure_app_last_report_summary_diagnosis_keys\">Bearbetade <xliff:g example=\"121031\">%1$d</xliff:g> diagnosnycklar.</string>\n    <string name=\"pref_exposure_rpi_export_title\">Exportera</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_records\"><xliff:g example=\"0 - 50\">%1$s</xliff:g> ID:n per timma</string>\n    <string name=\"exposure_notify_off_title\">Exponeringsmeddelanden inaktiv</string>\n    <string name=\"pref_exposure_app_report_updated_title\">Uppdaterat: <xliff:g example=\"Today, 14:02\">%1$s</xliff:g></string>\n    <string name=\"exposure_grant_background_location_button\">Uppdatera inställningar</string>\n    <string name=\"pref_exposure_error_location_off_title\">Öppna platsinställningar</string>\n    <string name=\"pref_exposure_rpis_details_summary\">När API:et för exponeringsmeddelanden är aktiverat samlar enheten passivt in ID:n (kallas RPI:er (Rolling Proximity Identifiers) från enheter i din närhet.\n\\n\n\\nNär enhetsägare rapporterar att de har diagnostiserats positivt kan deras ID:n delas. Enheten kontrollerar om något av de kända diagnostiserade ID:na matchar något av de insamlade ID:na och beräknar infektionsrisken.</string>\n    <string name=\"pref_exposure_info_summary\">Med API:et för avisering om exponering kan appar meddela dig om du har exponerats för någon som har rapporterats positivt diagnostiserad.\n\\n\n\\nDatum, varaktighet och signalstyrka i samband med en exponering kommer att delas med motsvarande app.</string>\n    <string name=\"pref_exposure_app_api_usage_summary_line\"><xliff:g example=\"12\">%1$d</xliff:g> anrop till <xliff:g example=\"provideDiagnosisKeys\">%2$s</xliff:g></string>\n    <string name=\"pref_exposure_enable_info_summary\">För att aktivera exponeringsmeddelanden öppnar du någon app som stödjer det.</string>\n    <string name=\"pref_exposure_rpi_delete_all_summary\">Ta bort alla insamlade ID:n</string>\n    <string name=\"exposure_confirm_permission_description\"><xliff:g example=\"microG Services\">%1$s</xliff:g> behöver ytterligare behörigheter.</string>\n    <string name=\"service_name_exposure\">Exponeringsmeddelanden</string>\n    <string name=\"pref_exposure_app_report_entry_distance_close\">närliggande exponering</string>\n    <string name=\"exposure_confirm_permission_button\">Bevilja</string>\n    <string name=\"exposure_notify_off_bluetooth\">Bluetooth måste vara aktivt för att ta emot exponeringsmeddelanden.</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning_confirm_button\">Ta bort ändå</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_suffix\">Notis: Riskpoängen definieras av appen. Höga siffror kan referera till låg risk och vice versa.</string>\n    <string name=\"exposure_confirm_location_description\">Platsåtkomst krävs.</string>\n    <string name=\"pref_exposure_error_bluetooth_no_advertise_summary\">Din enhet är endast delvis kompatibel med exponeringsmeddelanden. Du kan aviseras för riskkontakter men kommer inte att kunna meddela andra.</string>\n    <string name=\"exposure_confirm_bluetooth_description\">Bluetooth måste aktiveras.</string>\n    <string name=\"exposure_confirm_start_button\">Slå på</string>\n    <string name=\"prefcat_exposure_rpis_histogram_title\"><xliff:g example=\"230\">%1$d</xliff:g> ID:n insamlade</string>\n    <string name=\"pref_exposure_collected_rpis_summary\"><xliff:g example=\"63\">%1$d</xliff:g> ID:n senaste timman</string>\n    <string name=\"exposure_notify_off_location\">Platsåtkomst krävs för att ta emot exponeringsmeddelanden.</string>\n    <string name=\"prefcat_exposure_apps_title\">Appar som använder exponeringsmeddelanden</string>\n    <string name=\"exposure_confirm_stop_summary\">Efter inaktivering av exponeringsmeddelanden kommer du inte längre att meddelas när du exponerats för någon som rapporterats positivt diagnostiserad.</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_line\"><xliff:g example=\"Yesterday, 12:00 - 14:00\">%1$s</xliff:g>, riskpoäng <xliff:g example=\"99\">%2$d</xliff:g></string>\n    <string name=\"exposure_confirm_stop_title\">Vill du slå av exponeringsmeddelanden?</string>\n    <string name=\"exposure_confirm_keys_summary\">Dina ID:n från de senaste 14 dagarna kommer att användas för att informera andra i din närhet, om potentiell exponering.\n\\n\n\\nDin identitet eller testresultat kommer inte att delas med andra människor.</string>\n    <string name=\"exposure_confirm_start_summary\">Din telefon behöver använda blåtand för att säkert identifiera och dela ID:n med andra närliggande telefoner.\\n\\n<xliff:g example=\"Corona-Warn\">%1$s</xliff:g> kan meddela dig om du exponerats för någon som rapporterats positivt diagnostiserad. \\n\\nDatum, varaktighet och signalstyrka i samband med en exponering kommer att delas med appen.</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_no_records\">Inga poster</string>\n    <string name=\"pref_exposure_rpi_delete_all_title\">Ta bort</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_title\">Nya behörigheter krävs</string>\n    <string name=\"prefcat_exposure_app_report_title\">Rapporterade exponeringar</string>\n    <string name=\"exposure_notify_off_nearby\">Exponeringsmeddelanden kräver ytterligare behörigheter för att fungera</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning\">Borttagning av insamlade ID:n kommer att göra det omöjligt att meddela dig om någon av dina kontakter de senaste 14 dagarna diagnostiseras.</string>\n    <string name=\"exposure_confirm_keys_button\">Dela</string>\n    <string name=\"exposure_grant_background_location_description\">Nästan där! Du måste aktivera bakgrundsåtkomst till platsinformation genom att välja alternativet \\\"Tillåt hela tiden\\\" på nästa sida. Tryck sedan tillbaka.</string>\n    <string name=\"exposure_confirm_button\">Aktivera</string>\n    <string name=\"pref_exposure_error_bluetooth_off_title\">Aktivera Bluetooth</string>\n    <string name=\"pref_exposure_app_report_entry_time_about\">Ungefär <xliff:g example=\"13\">%1$d</xliff:g> minuter</string>\n</resources>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-ta/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=\"exposure_notify_off_title\">வெளிப்பாடு அறிவிப்புகள் செயலற்றவை</string>\n    <string name=\"exposure_notify_off_bluetooth\">வெளிப்பாடு அறிவிப்புகளைப் பெற ஊடலை இயக்கப்பட வேண்டும்.</string>\n    <string name=\"exposure_notify_off_location\">வெளிப்பாடு அறிவிப்புகளைப் பெற இருப்பிட அணுகல் தேவை.</string>\n    <string name=\"service_name_exposure\">வெளிப்பாடு அறிவிப்புகள்</string>\n    <string name=\"exposure_confirm_start_button\">இயக்கவும்</string>\n    <string name=\"exposure_confirm_stop_title\">வெளிப்பாடு அறிவிப்புகளை அணைக்கவா?</string>\n    <string name=\"exposure_confirm_stop_button\">அணைக்கவும்</string>\n    <string name=\"exposure_confirm_keys_button\">பங்கு</string>\n    <string name=\"exposure_confirm_permission_button\">மானியம்</string>\n    <string name=\"pref_exposure_app_report_entry_distance_close\">அருகிலுள்ள வெளிப்பாடு</string>\n    <string name=\"pref_exposure_app_report_entry_distance_far\">தொலைதூர வெளிப்பாடு</string>\n    <string name=\"exposure_notify_off_bluetooth_location\">வெளிப்பாடு அறிவிப்புகளைப் பெற ஊடலை மற்றும் இருப்பிட அணுகல் இயக்கப்பட வேண்டும்.</string>\n    <string name=\"exposure_notify_off_nearby\">வெளிப்பாடு அறிவிப்புகளுக்கு வேலை செய்ய கூடுதல் அனுமதிகள் தேவை</string>\n    <string name=\"pref_exposure_enable_info_summary\">வெளிப்பாடு அறிவிப்புகளை இயக்க, அதை ஆதரிக்கும் எந்த பயன்பாட்டையும் திறக்கவும்.</string>\n    <string name=\"pref_exposure_error_bluetooth_off_title\">புளூடூத்தை இயக்கவும்</string>\n    <string name=\"pref_exposure_error_location_off_title\">இருப்பிட அமைப்புகளைத் திறக்கவும்</string>\n    <string name=\"pref_exposure_error_bluetooth_unsupported_summary\">துரதிர்ச்டவசமாக, உங்கள் சாதனம் வெளிப்பாடு அறிவிப்புகளுடன் பொருந்தாது.</string>\n    <string name=\"pref_exposure_error_bluetooth_no_advertise_summary\">துரதிர்ச்டவசமாக, உங்கள் சாதனம் வெளிப்பாடு அறிவிப்புகளுடன் ஓரளவு மட்டுமே இணக்கமானது. இடர் தொடர்புகளுக்கு உங்களுக்கு அறிவிக்கப்படலாம், ஆனால் மற்றவர்களுக்கு அறிவிக்க முடியாது.</string>\n    <string name=\"prefcat_exposure_apps_title\">வெளிப்பாடு அறிவிப்புகளைப் பயன்படுத்தும் பயன்பாடுகள்</string>\n    <string name=\"pref_exposure_collected_rpis_title\">சேகரிக்கப்பட்ட ஐடிஎச்</string>\n    <string name=\"pref_exposure_advertising_id_title\">தற்போது ஒளிபரப்பப்பட்ட ஐடி</string>\n    <string name=\"prefcat_exposure_app_report_title\">அறிவிக்கப்பட்ட வெளிப்பாடுகள்</string>\n    <string name=\"pref_exposure_app_report_entry_time_short\">5 நிமிடங்களுக்கும் குறைவாக</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_no\">வெளிப்பாடு சந்திப்புகள் எதுவும் தெரிவிக்கப்படவில்லை.</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_suffix\">குறிப்பு: இடர் மதிப்பெண் பயன்பாட்டால் வரையறுக்கப்படுகிறது. அதிக எண்கள் குறைந்த ஆபத்தை குறிக்கலாம் அல்லது நேர்மாறாக இருக்கலாம்.</string>\n    <string name=\"pref_exposure_app_api_usage_title\">கடந்த 14 நாட்களில் பநிஇ பயன்பாடு</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_no_records\">பதிவுகள் இல்லை</string>\n    <string name=\"pref_exposure_rpi_delete_all_title\">நீக்கு</string>\n    <string name=\"pref_exposure_rpi_delete_all_summary\">சேகரிக்கப்பட்ட அனைத்து ஐடிகளையும் நீக்கு</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning\">சேகரிக்கப்பட்ட ஐடிகளை நீக்குவது கடந்த 14 நாட்களில் உங்கள் தொடர்புகள் ஏதேனும் கண்டறியப்பட்டால் உங்களுக்குத் தெரிவிக்க இயலாது.</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning_confirm_button\">எப்படியும் நீக்கு</string>\n    <string name=\"pref_exposure_rpi_export_title\">ஏற்றுமதி</string>\n    <string name=\"pref_exposure_rpi_export_summary\">மற்றொரு பயன்பாட்டுடன் நீட்டிக்கப்பட்ட பகுப்பாய்விற்கு சேகரிக்கப்பட்ட ஐடிகளை ஏற்றுமதி செய்யுங்கள்.</string>\n    <string name=\"pref_exposure_info_summary\">வெளிப்பாடு அறிவிப்புகள் பநிஇ நேர்மறையாக கண்டறியப்பட்டதாகக் கூறப்படும் ஒருவரை நீங்கள் வெளிப்படுத்தியிருந்தால் பயன்பாடுகள் உங்களுக்குத் தெரிவிக்க அனுமதிக்கிறது.\\n\\n வெளிப்பாட்டுடன் தொடர்புடைய தேதி, காலம் மற்றும் சமிக்ஞை வலிமை ஆகியவை தொடர்புடைய பயன்பாட்டுடன் பகிரப்படும்.</string>\n    <string name=\"pref_exposure_rpis_details_summary\">வெளிப்பாடு அறிவிப்பு பநிஇ இயக்கப்பட்டிருந்தாலும், அருகிலுள்ள சாதனங்களிலிருந்து உங்கள் சாதனம் செயலற்ற முறையில் ஐடிஎச் (ரோலிங் ப்ராக்சிமிட்டி அடையாளங்காட்டிகள் அல்லது ஆர்.பி.ஐ.எச்) சேகரிக்கிறது.\\n\\n சாதன உரிமையாளர்கள் நேர்மறையாக கண்டறியப்படுவதாக புகாரளிக்கும் போது, அவர்களின் ஐடிகளை பகிரலாம். அறியப்பட்ட கண்டறியப்பட்ட ஐடிஎச் ஏதேனும் சேகரிக்கப்பட்ட ஐடிகளுடன் பொருந்தக்கூடியது மற்றும் உங்கள் தொற்று அபாயத்தை கணக்கிடுகிறது என்றால் உங்கள் சாதனம் சரிபார்க்கிறது.</string>\n    <string name=\"exposure_enable_switch\">வெளிப்பாடு அறிவிப்புகளைப் பயன்படுத்துங்கள்</string>\n    <string name=\"exposure_confirm_start_title\">வெளிப்பாடு அறிவிப்புகளை இயக்கவா?</string>\n    <string name=\"exposure_confirm_stop_summary\">வெளிப்பாடு அறிவிப்புகளை முடக்கிய பிறகு, நேர்மறையானதாகக் கண்டறியப்பட்டதாகக் கூறப்படும் ஒருவருக்கு நீங்கள் வெளிப்படும் போது உங்களுக்கு இனி அறிவிக்கப்படாது.</string>\n    <string name=\"exposure_confirm_keys_summary\">கடந்த 14 நாட்களிலிருந்து உங்கள் ஐடிகள் சாத்தியமான வெளிப்பாடு குறித்து நீங்கள் இருந்ததாக மற்றவர்களுக்கு அறிவிக்க உதவும்.\\n\\n உங்கள் அடையாளம் அல்லது சோதனை முடிவு மற்றவர்களுடன் பகிரப்படாது.</string>\n    <string name=\"exposure_confirm_bluetooth_description\">ஊடலை இயக்கப்பட வேண்டும்.</string>\n    <string name=\"exposure_confirm_location_description\">இருப்பிட அணுகல் தேவை.</string>\n    <string name=\"exposure_confirm_button\">இயக்கு</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_title\">புதிய அனுமதிகள் தேவை</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_description\">வெளிப்பாடு அறிவிப்புகளுக்கு தேவையான அனுமதிகளை வழங்க தட்டவும்</string>\n    <string name=\"exposure_grant_background_location_description\">கிட்டத்தட்ட அங்கே! அடுத்த திரையில் \\'எல்லா நேரத்தையும் அனுமதிக்கவும்\\' விருப்பத்தைத் தேர்ந்தெடுப்பதன் மூலம் பின்னணி இருப்பிட அணுகலை நீங்கள் இயக்க வேண்டும். பின்னர் மீண்டும் அழுத்தவும்.</string>\n    <string name=\"exposure_grant_background_location_button\">அமைப்புகளை புதுப்பிக்கவும்</string>\n    <string name=\"pref_exposure_app_api_usage_summary_line\">&lt;XLIFF: g எடுத்துக்காட்டு = \\\"12\\\"&gt;%1$d &lt;/xliff: g&gt; &lt;xliff: g எடுத்துக்காட்டு = \\\"pandiagnosiskeys\\\"&gt;%2$s &lt;/xliff: g&gt;</string>\n    <string name=\"prefcat_exposure_rpis_histogram_title\">&lt;xliff: g எடுத்துக்காட்டு = \\\"230\\\"&gt;%1$d &lt;/xliff: g&gt; ஐடிகள் சேகரிக்கப்பட்டன</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_records\">&lt;xliff: g எடுத்துக்காட்டு = \\\"0 - 50\\\"&gt;%1$s &lt;/xliff: g&gt; ஒரு மணி நேரத்திற்கு ஐடிஎச்</string>\n    <string name=\"exposure_confirm_start_summary\">உங்கள் தொலைபேசி புளூடூத்தை பாதுகாப்பாக சேகரிக்கவும், அருகிலுள்ள பிற தொலைபேசிகளுடன் ஐடிகளைப் பகிரவும் வேண்டும்.\\n\\n &lt;xliff: g எடுத்துக்காட்டு = \\\"கொரோனா-வார்ன்\\\"&gt;%1$s &lt;/xliff: g&gt; நேர்மறை கண்டறியப்பட்டதாக அறிவித்த ஒருவருக்கு நீங்கள் வெளிப்பட்டால் உங்களுக்கு அறிவிக்க முடியும். வெளிப்பாட்டுடன் தொடர்புடைய தேதி, காலம் மற்றும் சமிக்ஞை வலிமை பயன்பாட்டுடன் பகிரப்படும்.</string>\n    <string name=\"exposure_confirm_permission_description\">&lt;xliff: g எடுத்துக்காட்டு = \\\"மைக்ரோக் சேவைகள்\\\"&gt;%1$s &lt;/xliff: g&gt; கூடுதல் அனுமதிகள் தேவை.</string>\n    <string name=\"pref_exposure_app_report_updated_title\">புதுப்பிக்கப்பட்டது: &lt;xliff: g எடுத்துக்காட்டு = \\\"இன்று, 14:02\\\"&gt;%1$s &lt;/xliff: g&gt;</string>\n    <string name=\"pref_exposure_app_report_entry_time_about\">&lt;Xliff: g எடுத்துக்காட்டு = \\\"13\\\"&gt;%1$d &lt;/xliff: g&gt; நிமிடங்கள்</string>\n    <string name=\"pref_exposure_app_report_entry_combined\">&lt;xliff: g எடுத்துக்காட்டு = \\\"சுமார் 12 நிமிடங்கள்\\\"&gt;%1$s &lt;/xliff: g&gt;, &lt;xliff: g எடுத்துக்காட்டு = \\\"தொலைதூர வெளிப்பாடு\\\"&gt;%2$s &lt;/xliff: g&gt;</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_line\">&lt;xliff: g எடுத்துக்காட்டு = \\\"நேற்று, 12:00 - 14:00\\\"&gt;%1$s &lt;/xliff: g&gt;, இடர் மதிப்பெண் &lt;xliff: g எடுத்துக்காட்டு = \\\"99\\\"&gt;%2$d &lt;/xliff: g&gt;</string>\n    <string name=\"pref_exposure_app_last_report_summary_diagnosis_keys\">செயலாக்கப்பட்ட &lt;xliff: g எடுத்துக்காட்டு = \\\"121031\\\"&gt;%1$d &lt;/xliff: g&gt; நோயறிதல் விசைகள்.</string>\n    <string name=\"pref_exposure_collected_rpis_summary\">&lt;xliff: g எடுத்துக்காட்டு = \\\"63\\\"&gt;%1$d &lt;/xliff: g&gt; ஐடிஎச் கடைசி மணி நேரத்தில்</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_prefix\">அறிவிக்கப்பட்ட &lt;xliff: g எடுத்துக்காட்டு = \\\"3\\\"&gt;%1$d &lt;/xliff: g&gt; வெளிப்பாடு சந்திப்புகள்:</string>\n    <string name=\"exposure_confirm_keys_title\">உங்கள் ஐடிகளை &lt;xliff: g எடுத்துக்காட்டு = \\\"கொரோனா-வார்ன்\\\"&gt;%1$s &lt;/xliff: g&gt; உடன் பகிர்ந்து கொள்ளுங்கள்?</string>\n</resources>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-th/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=\"exposure_notify_off_title\">ระบบแจ้งเตือนเมื่อใกล้ชิดผู้ติดเชื้อ ถูกปิดการใช้งาน</string>\n    <string name=\"exposure_notify_off_bluetooth\">จำเป็นต้องเปิดใช้งาน Bluetooth เพื่อรับข้อมูลจากระบบแจ้งเตือนเมื่อใกล้ชิดผู้ติดเชื้อ</string>\n    <string name=\"exposure_notify_off_location\">จำเป็นต้องเข้าถึงตำแหน่งเพื่อรับข้อมูลจากระบบแจ้งเตือนเมื่อใกล้ชิดผู้ติดเชื้อ</string>\n    <string name=\"exposure_notify_off_bluetooth_location\">จำเป็นต้องเปิดใช้งานบลูทูธและการเข้าถึงตำแหน่งเพื่อรับข้อมูลจากระบบแจ้งเตือนเมื่อใกล้ชิดผู้ติดเชื้อ</string>\n    <string name=\"service_name_exposure\">ระบบแจ้งเตือนเมื่อใกล้ชิดผู้ติดเชื้อ</string>\n    <string name=\"pref_exposure_enable_info_summary\">เพื่อเปิดการใช้งานระบบแจ้งเตือนเมื่อใกล้ชิดผู้ติดเชื้อ ให้เปิดแอปใด ๆ ที่รองรับ</string>\n    <string name=\"pref_exposure_error_bluetooth_off_title\">เปิดใช้งาน Bluetooth</string>\n    <string name=\"pref_exposure_error_bluetooth_no_advertise_summary\">ขออภัย อุปกรณ์ของคุณเข้ากันได้กับการแจ้งเตือนข้อมูลจากระบบแจ้งเตือนเมื่อใกล้ชิดผู้ติดเชื้อเพียงบางส่วนเท่านั้น คุณสามารถรับการแจ้งเตือนเกี่ยวกับผู้ติดต่อที่มีความเสี่ยงได้ แต่จะไม่สามารถแจ้งเตือนผู้อื่นได้</string>\n    <string name=\"pref_exposure_error_bluetooth_unsupported_summary\">ขออภัย อุปกรณ์ของคุณไม่รองรับข้อมูลจากระบบแจ้งเตือนเมื่อใกล้ชิดผู้ติดเชื้อ</string>\n    <string name=\"prefcat_exposure_apps_title\">แอปกำลังใช้ข้อมูลจากระบบแจ้งเตือนเมื่อใกล้ชิดผู้ติดเชื้อ</string>\n    <string name=\"pref_exposure_collected_rpis_title\">เก็บรวบรวมรหัสประจำตัว</string>\n    <string name=\"pref_exposure_advertising_id_title\">รหัสที่กำลังกระจายสัญญาณในปัจจุบัน</string>\n    <string name=\"prefcat_exposure_app_report_title\">การรายงานความเสี่ยงเข้าใกล้ผู้ป่วยติดเชื้อ</string>\n    <string name=\"pref_exposure_app_report_updated_title\">อัปเดต: <xliff:g example=\"วันนี้, 14:02\">%1$s</xliff:g></string>\n    <string name=\"pref_exposure_app_report_entry_time_short\">น้อยกว่า 5 นาที</string>\n    <string name=\"pref_exposure_app_report_entry_time_about\">เกี่ยวกับ <xliff:g example=\"13\">%1$d</xliff:g> นาที</string>\n    <string name=\"pref_exposure_app_report_entry_distance_close\">ความเสี่ยงในบริเวณใกล้เคียง</string>\n    <string name=\"pref_exposure_app_report_entry_distance_far\">ระยะความเสี่ยง</string>\n    <string name=\"pref_exposure_app_report_entry_combined\"><xliff:g example=\"ประมาณ 12 นาที\">%1$s</xliff:g>, <xliff:g example=\"ระยะของความเสี่ยง\">%2$s</xliff:g></string>\n    <string name=\"pref_exposure_app_last_report_summary_diagnosis_keys\">ประมวลผล <xliff:g example=\"121031\">%1$d</xliff:g>กุญแจสำหรับการวินิจฉัยแล้ว</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_prefix\">รายงาน <xliff:g example=\"3\">%1$d</xliff:g> การเข้าปะทะกับผู้ที่มีความเสี่ยงติดเชื้อ:</string>\n    <string name=\"pref_exposure_app_api_usage_title\">การใช้งาน API ในช่วง 14 วันที่ผ่านมา</string>\n    <string name=\"pref_exposure_app_api_usage_summary_line\"><xliff:g example=\"12\">%1$d</xliff:g> เรียกไปยัง <xliff:g example=\"provideDiagnosisKeys\">%2$s</xliff:g></string>\n    <string name=\"pref_exposure_rpis_histogram_legend_records\"><xliff:g example=\"0 - 50\">%1$s</xliff:g> รหัสประจำตัวต่อชั่วโมง</string>\n    <string name=\"pref_exposure_rpi_delete_all_summary\">ลบรหัสประจำตัวทั้งหมด</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning_confirm_button\">ลบต่อไป</string>\n    <string name=\"pref_exposure_rpi_export_title\">ส่งออก</string>\n    <string name=\"pref_exposure_rpi_export_summary\">ส่งออก รหัสประจำตัว ที่เก็บรวบรวมไว้เพื่อการวิเคราะห์เพิ่มเติมด้วยแอปอื่น</string>\n    <string name=\"exposure_enable_switch\">ใช้ระบบแจ้งเตือนเมื่อใกล้ชิดผู้ติดเชื้อ</string>\n    <string name=\"exposure_confirm_start_title\">เปิดใช้งานระบบแจ้งเตือนเมื่อใกล้ชิดผู้ติดเชื้อ?</string>\n    <string name=\"exposure_confirm_start_button\">เปิด</string>\n    <string name=\"exposure_confirm_stop_title\">ปิดระบบแจ้งเตือนเมื่อใกล้ชิดผู้ติดเชื้อ?</string>\n    <string name=\"exposure_confirm_stop_summary\">หลังจากปิดระบบแจ้งเตือนเมื่อใกล้ชิดผู้ติดเชื้อแล้ว คุณจะไม่ได้รับการแจ้งเตือนอีกต่อไปเมื่อคุณสัมผัสกับบุคคลที่รายงานว่าได้รับการวินิจฉัยว่าติดเชื้อ</string>\n    <string name=\"exposure_confirm_stop_button\">ปิด</string>\n    <string name=\"exposure_confirm_keys_title\">แบ่งปัน รหัสประจำตัว ของคุณกับ <xliff:g example=\"เตือนโควิด\">%1$s</xliff:g> ?</string>\n    <string name=\"exposure_confirm_keys_summary\">ข้อมูลประจำตัวของคุณในช่วง 14 วันที่ผ่านมาจะถูกใช้เพื่อแจ้งให้ผู้อื่นทราบว่าคุณอยู่ใกล้ๆ และมีความเสี่ยงต่อการติดเชื้อ\\n\\nข้อมูลประจำตัวหรือผลการทดสอบของคุณจะไม่ถูกเปิดเผยให้ผู้อื่นทราบ</string>\n    <string name=\"exposure_confirm_keys_button\">แบ่งปัน</string>\n    <string name=\"exposure_confirm_permission_button\">อนุญาต</string>\n    <string name=\"exposure_confirm_bluetooth_description\">จำเป็นต้องเปิดใช้งาน Bluetooth</string>\n    <string name=\"exposure_confirm_button\">เปิดใช้งาน</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_title\">ต้องมีการอนุญาตใหม่</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_description\">แตะเพื่อให้สิทธิ์ที่จำเป็นในการใช้ข้อมูลจากระบบแจ้งเตือนเมื่อใกล้ชิดผู้ติดเชื้อ</string>\n    <string name=\"pref_exposure_error_location_off_title\">เปิดการตั้งค่าตำแหน่ง</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_no\">ไม่มีการรายงานความเสี่ยงเข้าใกล้ผู้ติดเชื้อ</string>\n    <string name=\"exposure_notify_off_nearby\">ระบบแจ้งเตือนเมื่อใกล้ชิดผู้ติดเชื้อต้องได้รับอนุญาตเพิ่มเติมจึงจะทำงานได้</string>\n    <string name=\"pref_exposure_collected_rpis_summary\"><xliff:g example=\"63\">%1$d</xliff:g> รหัสประจำตัว ในชั่วโมงที่ผ่านมา</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_line\"><xliff:g example=\"เมื่อวานนี้ 12:00 - 14:00\">%1$s</xliff:g> คะแนนความเสี่ยง <xliff:g example=\"99\">%2$d</xliff:g></string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_suffix\">หมายเหตุ: คะแนนความเสี่ยงถูกกำหนดโดยแอป ตัวเลขสูงอาจหมายถึงความเสี่ยงต่ำหรือในทางกลับกัน</string>\n    <string name=\"prefcat_exposure_rpis_histogram_title\"><xliff:g example=\"230\">%1$d</xliff:g> รวบรวม รหัสประจำตัวแล้ว</string>\n    <string name=\"pref_exposure_rpi_delete_all_title\">ลบ</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_no_records\">ไม่มีข้อมูลบันทึกไว้</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning\">การลบ รหัสประจำตัว ที่เก็บรวบรวมไว้จะทำให้ไม่สามารถแจ้งให้คุณทราบได้ในกรณีที่ผู้ติดต่อของคุณในช่วง 14 วันล่าสุดได้รับการวินิจฉัย</string>\n    <string name=\"pref_exposure_info_summary\">ส่วนเชื่อมต่อกับระบบแจ้งเตือนเมื่อใกล้ชิดผู้ติดเชื้ออนุญาตให้แอปสามารถแจ้งให้คุณทราบหากคุณสัมผัสกับบุคคลที่รายงานว่าได้รับการวินิจฉัยว่าติดเชื้อ\\n\\nวันที่ ระยะเวลา และความแรงของสัญญาณที่เกี่ยวข้องกับการสัมผัสจะถูกแชร์กับแอปที่เกี่ยวข้อง</string>\n    <string name=\"pref_exposure_rpis_details_summary\">ขณะที่เปิดใช้งาน ของส่วนติดต่อของฟังก์ชั่น “ระบบแจ้งเตือนเมื่อใกล้ชิดผู้ติดเชื้อ” อุปกรณ์ของคุณจะทำการรวบรวม รหัสประจำตัว (เรียกว่า Rolling Proximity Identifiers หรือ RPI) จากอุปกรณ์ใกล้เคียงโดยอัตโนมัติ\\n\\nเมื่อเจ้าของอุปกรณ์รายงานว่าได้รับการวินิจฉัยว่าเป็นบวก รหัสประจำตัว ของพวกเขาจะถูกแชร์ได้ อุปกรณ์ของคุณจะทำการตรวจสอบว่ามี รหัสประจำตัว ที่ได้รับการวินิจฉัยที่ทราบแล้วตรงกับ รหัสประจำตัว ที่รวบรวมไว้หรือไม่ และคำนวณความเสี่ยงต่อการติดเชื้อของคุณ</string>\n    <string name=\"exposure_confirm_start_summary\">โทรศัพท์ของคุณจำเป็นต้องใช้ Bluetooth เพื่อรวบรวมและแชร์รหัสประจำตัวกับโทรศัพท์เครื่องอื่นที่อยู่ใกล้เคียงอย่างปลอดภัย\\n\\n<xliff:g example=\"Corona-Warn\">%1$s</xliff:g> สามารถแจ้งเตือนคุณหากคุณสัมผัสกับบุคคลที่รายงานว่าได้รับการวินิจฉัยว่าติดเชื้อ\\n\\nวันที่ ระยะเวลา และความแรงของสัญญาณที่เกี่ยวข้องกับการสัมผัสจะถูกแชร์กับแอป</string>\n    <string name=\"exposure_grant_background_location_button\">อัปเดตการตั้งค่า</string>\n    <string name=\"exposure_confirm_permission_description\"><xliff:g example=\"บริการ microG\">%1$s</xliff:g> ต้องได้รับการอนุญาตเพิ่มเติม</string>\n    <string name=\"exposure_confirm_location_description\">จำเป็นต้องมีการเข้าถึงตำแหน่ง</string>\n    <string name=\"exposure_grant_background_location_description\">เกือบเสร็จแล้ว! คุณจะต้องเปิดใช้งานการเข้าถึงตำแหน่งพื้นหลังโดยเลือกตัวเลือก \\\"อนุญาตตลอดเวลา\\\" ในหน้าจอถัดไป จากนั้นกดย้อนกลับ</string>\n</resources>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-tr/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=\"pref_exposure_error_bluetooth_off_title\">Bluetooth\\'u etkinleştir</string>\n    <string name=\"exposure_notify_off_title\">Temas Bildirimleri devre dışı</string>\n    <string name=\"exposure_notify_off_bluetooth\">Temas Bildirimleri\\'ni almak için Bluetooth\\'un etkinleştirilmesi gerekiyor.</string>\n    <string name=\"exposure_notify_off_location\">Temas Bildirimleri\\'ni almak için konum izinleri gerekiyor.</string>\n    <string name=\"exposure_notify_off_bluetooth_location\">Temas Bildirimleri\\'ni almak için hem Bluetooth hem de konum izinlerinin etkinleştirilmesi gerekiyor.</string>\n    <string name=\"pref_exposure_enable_info_summary\">Temas Bildirimleri\\'ni etkinleştirmek için, bu özelliği kullanan bir uygulamayı açın.</string>\n    <string name=\"pref_exposure_error_location_off_title\">Konum ayarlarını aç</string>\n    <string name=\"prefcat_exposure_apps_title\">Temas Bildirimleri kullanan uygulamalar</string>\n    <string name=\"pref_exposure_collected_rpis_title\">Toplanan kimlikler</string>\n    <string name=\"pref_exposure_error_bluetooth_no_advertise_summary\">Ne yazık ki, cihazınız Temas Bildirimleri\\'ni sadece kısmen destekliyor. Bu da, kendi riskli temaslarınızdan bilgilendirileceğiniz ancak başkalarını bilgilendiremeyeceğiniz anlamına geliyor.</string>\n    <string name=\"pref_exposure_advertising_id_title\">Şu anki yayınlanan kimlik</string>\n    <string name=\"pref_exposure_app_report_entry_time_short\">5 dakikadan az</string>\n    <string name=\"pref_exposure_app_report_entry_distance_close\">yakın temas</string>\n    <string name=\"prefcat_exposure_app_report_title\">Rapor edilen temaslar</string>\n    <string name=\"pref_exposure_app_report_updated_title\">Güncellendi: <xliff:g example=\"Today, 14:02\">%1$s</xliff:g></string>\n    <string name=\"pref_exposure_app_report_entry_combined\"><xliff:g example=\"Yaklaşık 12 dakika\">%1$s</xliff:g>, <xliff:g example=\"yakın temas\">%2$s</xliff:g></string>\n    <string name=\"pref_exposure_app_last_report_summary_diagnosis_keys\"><xliff:g example=\"121031\">%1$d</xliff:g> teşhis anahtarı işlendi.</string>\n    <string name=\"pref_exposure_app_api_usage_title\">Son 14 gün içinde API kullanımı</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_no_records\">Kayıt yok</string>\n    <string name=\"prefcat_exposure_rpis_histogram_title\"><xliff:g example=\"230\">%1$d</xliff:g> kimlik toplandı</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_prefix\"><xliff:g example=\"3\">%1$d</xliff:g> temas karşılaşmaları raporlandı:</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_line\"><xliff:g example=\"Dün, 12:00 - 14:00\">%1$s</xliff:g>, risk skoru <xliff:g example=\"99\">%2$d</xliff:g></string>\n    <string name=\"pref_exposure_rpi_delete_all_title\">Sil</string>\n    <string name=\"pref_exposure_rpi_delete_all_summary\">Toplanan tüm kimlikleri sil</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning_confirm_button\">Yine de sil</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_records\">Saat başı <xliff:g example=\"0 - 50\">%1$s</xliff:g> kimlik</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning\">Toplanan kimliklerin silinmesi, son 14 gün içindeki kişilerinizden herhangi birinin teşhis edilmesi durumunda bilgilendirilmenizi imkansız hale getirecektir.</string>\n    <string name=\"pref_exposure_rpi_export_summary\">Veriler ile analiz yapmak için kullanmak üzere toplanan kimlikleri başka bir uygulama ile dışa aktarın.</string>\n    <string name=\"pref_exposure_info_summary\">Temas Bildirimleri API\\'si, uygulamaların, daha önceden pozitif teşhis olduğu bildirilen kişilerle temas halinde olmanız durumunda sizi bilgilendirmesine olanak tanır.\\n\\nBulunduğunuz temasın, tarihi, süresi, ve sinyal menzili, ilgili uygulama ile paylaşılır.</string>\n    <string name=\"exposure_confirm_start_title\">Temas Bildirimleri\\'ni etkinleştir?</string>\n    <string name=\"exposure_enable_switch\">Temas Bildirimleri\\'ni kullan</string>\n    <string name=\"exposure_confirm_start_summary\">Kimlikleri güvenli bir şekilde toplamak ve yakındaki diğer telefonlarla paylaşmak için telefonunuzun Bluetooth\\'u kullanması gerekir.\\n\\n<xliff:g example=\"Corona-Warn\">%1$s</xliff:g>, pozitif teşhis konduğunu bildiren biriyle temas halindeyseniz sizi bilgilendirebilir.\\n\\nTemasla ilişkili tarih, süre ve sinyal gücü uygulamayla paylaşılacaktır.</string>\n    <string name=\"exposure_confirm_start_button\">Etkinleştir</string>\n    <string name=\"exposure_confirm_stop_title\">Temas Bildirimleri\\'ni devre dışı bırak?</string>\n    <string name=\"exposure_confirm_stop_summary\">Temas Bildirimleri\\'ni devre dışı bırakmanız halinde, pozitif teşhis konulduğu bilinen biri ile temasa geçmeniz durumunda bilgilendirilmeyeceksiniz.</string>\n    <string name=\"exposure_confirm_keys_title\">Kimliklerinizi <xliff:g example=\"Corona-Warn\">%1$s</xliff:g> ile paylaşmak istiyor musunuz?</string>\n    <string name=\"exposure_confirm_permission_button\">Yetkilendir</string>\n    <string name=\"exposure_confirm_location_description\">Konum erişimi gerekiyor.</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_title\">Yeni izinler gerekiyor</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_description\">Temas Bildirimleri\\'ne gerekli izinleri vermek için dokunun</string>\n    <string name=\"exposure_grant_background_location_button\">Ayarları değiştir</string>\n    <string name=\"exposure_confirm_permission_description\"><xliff:g example=\"microG Services\">%1$s</xliff:g> ek izinlere ihtiyaç duyuyor.</string>\n    <string name=\"pref_exposure_collected_rpis_summary\">Son saat içinde <xliff:g example=\"63\">%1$d</xliff:g> kimlik</string>\n    <string name=\"pref_exposure_rpi_export_title\">Dışa aktar</string>\n    <string name=\"exposure_confirm_button\">Etkinleştir</string>\n    <string name=\"exposure_confirm_stop_button\">Devre dışı bırak</string>\n    <string name=\"exposure_confirm_bluetooth_description\">Bluetooth\\'un etkinleştirilmesi gerekiyor.</string>\n    <string name=\"pref_exposure_error_bluetooth_unsupported_summary\">Ne yazık ki, cihazınız Temas Bildirimleri için uyumlu değil.</string>\n    <string name=\"exposure_confirm_keys_button\">Paylaş</string>\n    <string name=\"service_name_exposure\">Temas Bildirimleri</string>\n    <string name=\"pref_exposure_app_report_entry_distance_far\">uzak temas</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_no\">Bildirilen bir temas yok.</string>\n    <string name=\"exposure_notify_off_nearby\">Temas Bildirimleri\\'nin çalışması için ek izinlere ihtiyaç var</string>\n    <string name=\"pref_exposure_app_report_entry_time_about\">Yaklaşık <xliff:g example=\"13\">%1$d</xliff:g> dakika</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_suffix\">Not: Risk skoru uygulama tarafından belirlenir. Yüksek sayılar düşük risk anlamına veya tam tersini olabilir.</string>\n    <string name=\"pref_exposure_rpis_details_summary\">Temas Bildirimleri API\\'si etkin iken, cihazınız yakındaki diğer cihazlardan pasif olarak kimlik toplar. (bu kimlikler, Rolling Identifiers, veya RPI olarak da bilinir)\\n\\nCihaz sahiplerin testi pozitif çıktığı bilindiğinde, kendilerinin kimlikleri paylaşılabilir. Bu sayede, cihazınız, bilinen kimlikler ile toplanan kimlikleri eşleştirir ve enfeksiyon riskinizi hesaplar.</string>\n    <string name=\"exposure_grant_background_location_description\">Neredeyse bitti! Bir sonraki ekranda, arkaplanda konum erişimini vermek için \\'Her zaman izin ver\\' seçeneğini seçin. Ardından geri dönün.</string>\n    <string name=\"pref_exposure_app_api_usage_summary_line\"><xliff:g example=\"provideDiagnosisKeys\">%2$s</xliff:g> için <xliff:g example=\"12\">%1$d</xliff:g> çağrı</string>\n    <string name=\"exposure_confirm_keys_summary\">Son 14 gün içindeki kimlikleriniz, çevrenizdekilere potansiyel temasta bulunduğunuz konusunda haber vermeye yardımcı olmak için kullanılır.\\n\\nKişisel bilgileriniz veya test sonuçlarınız başkaları ile paylaşılmaz.</string>\n</resources>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-ug/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=\"exposure_notify_off_nearby\">ئۇچرىشىش ئۇقتۇرۇشىنىڭ ئىشلىشى ئۈچۈن قوشۇمچە ئىجازەت زۆرۈر</string>\n    <string name=\"service_name_exposure\">ئۇچرىشىش ئۇقتۇرۇشى</string>\n    <string name=\"exposure_notify_off_bluetooth_location\">ئۇچرىشىش ئۇقتۇرۇشى تاپشۇرۇۋېلىشتا كۆكچىش ۋە ئورۇن ئۇچۇرى ئىجازىتى قوزغىتىلىشى كېرەك.</string>\n    <string name=\"pref_exposure_enable_info_summary\">ئۇچرىشىش ئۇقتۇرۇشىنى قوزغىتىشتا، ئۇنى قوللايدىغان خالىغان ئەپنى ئېچىڭ.</string>\n    <string name=\"pref_exposure_error_bluetooth_off_title\">كۆكچىشنى قوزغات</string>\n    <string name=\"pref_exposure_error_location_off_title\">ئورۇن تەڭشىكىنى ئاچىدۇ</string>\n    <string name=\"pref_exposure_error_bluetooth_unsupported_summary\">ئەپسۇسلىنارلىقى، ئۈسكۈنىڭىز ئۇچرىشىش ئۇقتۇرۇشى بىلەن ماسلاشمايدۇ.</string>\n    <string name=\"pref_exposure_error_bluetooth_no_advertise_summary\">ئەپسۇسلىنارلىقى، ئۈسكۈنىڭىز ئۇچرىشىش ئۇقتۇرۇشى بىلەن قىسمەن ماسلىشىدۇ. خەتەر بىلەن ئۇچرىشىش ئۇقتۇرۇشى تاپشۇرۇۋالالايسىز ئەمما باشقىلارغا ئۇقتۇرالمايسىز.</string>\n    <string name=\"prefcat_exposure_apps_title\">ئۇچرىشىش ئۇقتۇرۇشى ئىشلىتىدىغان ئەپ</string>\n    <string name=\"pref_exposure_advertising_id_title\">نۆۋەتتە تارقاتقان كىملىك</string>\n    <string name=\"prefcat_exposure_app_report_title\">دوكلات قىلىنغان ئۇچرىشىش</string>\n    <string name=\"pref_exposure_app_report_entry_time_short\">5 مىنۇتتىن قىسقا</string>\n    <string name=\"pref_exposure_collected_rpis_title\">توپلانغان كىملىك</string>\n    <string name=\"pref_exposure_app_report_entry_distance_close\">يېقىن ئەتراپتىكى ئۇچرىشىش</string>\n    <string name=\"pref_exposure_app_report_entry_distance_far\">يىراقتىن ئۇچرىشىش</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_no\">ھېچقانداق ئۇچراشقۇچى مەلۇم قىلىنمىدى.</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_suffix\">ئەسكەرتىش: خەتەر نومۇرىنى ئەپ بەلگىلەيدۇ. نومۇرى يۇقىرى بولسا خەتەر تۆۋەن بولىدۇ ياكى ئەكسىچە بولسا يۇقىرى بولىدۇ.</string>\n    <string name=\"pref_exposure_app_api_usage_title\">ئۆتكەن 14 كۈندىكى API ئىشلىتىلىشى</string>\n    <string name=\"pref_exposure_rpi_delete_all_title\">ئۆچۈر</string>\n    <string name=\"pref_exposure_rpi_delete_all_summary\">توپلىغان ھەممە كىملىكنى ئۆچۈر</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning\">توپلانغان بارلىق كىملىك ئۆچۈرۈلسە يېقىنقى 14 كۈندە ئۇچراشقانلارغا دىياگنوز قويۇلغان ئەھۋالدا سىزگە خەۋەر قىلغىلى بولمايدۇ.</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_no_records\">خاتىرە يوق</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning_confirm_button\">ئۆچۈرۈۋەر</string>\n    <string name=\"pref_exposure_rpi_export_title\">چىقار</string>\n    <string name=\"pref_exposure_rpi_export_summary\">باشقا ئەپتە تېخىمۇ ئىلگىرىلەپ تەھلىل قىلىش ئۈچۈن توپلانغان كىملىكنى چىقىرىدۇ.</string>\n    <string name=\"pref_exposure_info_summary\">ئۇچرىشىش ئۇقتۇرۇش API سى ئەپنىڭ سىز ئۇچراشقانلارنىڭ ئىچىدە جەزملەپ دىياگنوز قويۇلغانلار بار دەپ مەلۇم قىلىنسا سىزگە ئۇقتۇرۇش قىلىشىغا يول قويىدۇ.\\n\\nئۇچراشقان چېسلا، داۋاملاشقان ۋاقىت ۋە سىگنال كۈچلۈكلۈكى مۇناسىپ ئەپكە ھەمبەھىرلىنىدۇ.</string>\n    <string name=\"exposure_enable_switch\">ئۇچرىشىش ئۇقتۇرۇشىنى ئىشلىتىدۇ</string>\n    <string name=\"exposure_confirm_start_title\">ئۇچرىشىش ئۇقتۇرۇشىنى ئاچامدۇ؟</string>\n    <string name=\"pref_exposure_rpis_details_summary\">ئۇچرىشىش ئۇقتۇرۇش API سى قوزغىتىلغاندا، ئۈسكۈنىڭىز پاسسىپلىق بىلەن يېقىن ئەتراپتىكى ئۈسكۈنىلەردىن كىملىك (دومىلىما يېقىنلىق پەرقلەندۈرگۈچ ياكى RPI دېيىلىدۇ) توپلايدۇ.\\n\\nئۈسكۈنە ئىگىسى جەزملەپ دىياگنوز قويۇلغانلىقى مەلۇم قىلىنسا، ئۇلارنىڭ كىملىكىنى ھەمبەھىرلەشكە بولىدۇ. ئۈسكۈنىڭىز جەزملەپ دىياگنوز قويۇلغانلارنىڭ بەلگىسى توپلىغان كىملىكتە بار يوقلۇقىنى تەكشۈرۈپ، يۇقۇملىنىشىڭىزنىڭ خەتىرىنى ھېسابلايدۇ.</string>\n    <string name=\"exposure_notify_off_title\">ئۇچرىشىش ئۇقتۇرۇشى ئاكتىپسىز</string>\n    <string name=\"exposure_notify_off_bluetooth\">ئۇچرىشىش ئۇقتۇرۇشى تاپشۇرۇۋېلىشتا كۆكچىش قوزغىتىلىشى كېرەك.</string>\n    <string name=\"exposure_notify_off_location\">ئۇچرىشىش ئۇقتۇرۇشى تاپشۇرۇۋېلىشتا ئورۇن ئۇچۇرى ئىجازىتى زۆرۈر.</string>\n    <string name=\"pref_exposure_collected_rpis_summary\">ئاخىرقى بىر سائەتتە <xliff:g example=\"63\">%1$d</xliff:g> كىملىك توپلىدى</string>\n    <string name=\"pref_exposure_app_report_updated_title\">يېڭىلاندى: <xliff:g example=\"Today, 14:02\">%1$s</xliff:g></string>\n    <string name=\"pref_exposure_app_report_entry_time_about\">تەخمىنەن <xliff:g example=\"13\">%1$d</xliff:g> مىنۇت</string>\n    <string name=\"pref_exposure_app_report_entry_combined\"><xliff:g example=\"About 12 minutes\">%1$s</xliff:g>، <xliff:g example=\"distant exposure\">%2$s</xliff:g></string>\n    <string name=\"pref_exposure_app_last_report_summary_diagnosis_keys\">دىياگنوز ئاچقۇچىدىن <xliff:g example=\"121031\">%1$d</xliff:g> بىر تەرەپ قىلىندى.</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_prefix\"><xliff:g example=\"3\">%1$d</xliff:g> ئۇچرىشىش مەلۇم قىلىندى:</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_line\"><xliff:g example=\"Yesterday, 12:00 - 14:00\">%1$s</xliff:g>، risk score <xliff:g example=\"99\">%2$d</xliff:g></string>\n    <string name=\"pref_exposure_app_api_usage_summary_line\"><xliff:g example=\"12\">%1$d</xliff:g> قېتىم چاقىرغىنى <xliff:g example=\"provideDiagnosisKeys\">%2$s</xliff:g></string>\n    <string name=\"prefcat_exposure_rpis_histogram_title\"><xliff:g example=\"230\">%1$d</xliff:g> كىملىك توپلاندى</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_records\">سائىتىگە <xliff:g example=\"0 - 50\">%1$s</xliff:g> كىملىك</string>\n    <string name=\"exposure_confirm_start_summary\">تېلېفونىڭىز كۆكچىشنى ئىشلىتىپ ئەتراپتىكى باشقا تېلېفونلاردىن بىخەتەر ھالدا كىملىك توپلاپ ۋە ھەمبەھىرلەيدۇ.\\n\\nئەگەر سىز ئۇچراشقان بىرەرسى جەزملەپ دىياگنوز قويۇلغان بولسا <xliff:g example=\"Corona-Warn\">%1$s</xliff:g> سىزگە ئۇقتۇرۇش قىلالايدۇ.\\n\\nئۇچراشقان چېسلا، داۋاملىشىش ۋاقتى ۋە سىگنال كۈچلۈكلۈكى باشقا ئەپ بىلەن ھەمبەھىرلىنىدۇ.</string>\n    <string name=\"exposure_confirm_start_button\">ئاچ</string>\n    <string name=\"exposure_confirm_stop_title\">ئۇچرىشىش ئۇقتۇرۇشىنى تاقامدۇ؟</string>\n    <string name=\"exposure_confirm_stop_summary\">ئۇچرىشىش ئۇقتۇرۇشى چەكلەنگەندىن كېيىن، يېقىندا ئۇچراشقانلار ئىچىدە جەزملەپ دىياگنوز قويۇلغانلار دوكلات قىلىنغان بولسا سىز ئۇقتۇرۇش تاپشۇرۇۋالمايسىز.</string>\n    <string name=\"exposure_confirm_stop_button\">تاقا</string>\n    <string name=\"exposure_confirm_keys_summary\">سىزنىڭ يېقىنقى 14 كۈندىكى كىملىكىڭىز ئەتراپىڭىزدىكى كىشىلەرگە سىزنىڭ يوشۇرۇن ئۇچرىشىش كەچمىشىڭىزنى ئۇقتۇرۇشقا ياردەم بېرىدۇ.\\n\\nسىزنىڭ شەخسىي سالاھىيەت ۋە تەكشۈرۈش نەتىجىڭىز باشقىلارغا ھەمبەھىرلەنمەيدۇ.</string>\n    <string name=\"exposure_confirm_keys_button\">ھەمبەھىر</string>\n    <string name=\"exposure_confirm_permission_button\">ئىجازەت</string>\n    <string name=\"exposure_confirm_bluetooth_description\">كۆكچىش قوزغىتىلىشى كېرەك.</string>\n    <string name=\"exposure_confirm_location_description\">ئورۇن ئۇچۇرى زىيارەت ئىجازىتى زۆرۈر.</string>\n    <string name=\"exposure_confirm_button\">قوزغات</string>\n    <string name=\"exposure_confirm_keys_title\"><xliff:g example=\"Corona-Warn\">%1$s</xliff:g> غا كىملىكىڭىزنى ھەمبەھىرلەمدۇ؟</string>\n    <string name=\"exposure_confirm_permission_description\"><xliff:g example=\"microG Services\">%1$s</xliff:g> قوشۇمچە ئىجازەتكە موھتاج.</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_title\">ھېچقانداق ئىجازەت كېرەك ئەمەس</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_description\">چېكىلسە ئۇچرىشىش ئۇقتۇرۇشىغا زۆرۈر ئىجازەت بېرىلىدۇ</string>\n    <string name=\"exposure_grant_background_location_description\">تۈگەي دېدى! كېيىنكى ئېكراندا «ھەمىشە يول قوي» نى تاللاپ ئارقا سۇپىدا ئورۇن ئۇچۇرىنى زىيارەت قىلىش ئىجازىتى بېرىپ، ئاندىن قايت توپچىنى چېكىڭ.</string>\n    <string name=\"exposure_grant_background_location_button\">يېڭىلاش تەڭشىكى</string>\n</resources>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-uk/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=\"pref_exposure_error_bluetooth_off_title\">Ввімкнути Bluetooth</string>\n    <string name=\"exposure_notify_off_bluetooth_location\">Щоб отримувати сповіщення про вплив, потрібно увімкнути Bluetooth і доступ до розташування.</string>\n    <string name=\"exposure_notify_off_title\">Сповіщення про вплив неактивні</string>\n    <string name=\"pref_exposure_error_location_off_title\">Відкрити параметри розташування</string>\n    <string name=\"pref_exposure_enable_info_summary\">Щоб увімкнути сповіщення про вплив, відкрийте будь-який застосунок, що підтримує цю функцію.</string>\n    <string name=\"service_name_exposure\">Сповіщення про вплив</string>\n    <string name=\"exposure_notify_off_bluetooth\">Bluetooth повинен бути включений для отримання повідомлень про експозицію.</string>\n    <string name=\"exposure_notify_off_location\">Для отримання сповіщень про експозицію необхідний доступ до місця розташування.</string>\n    <string name=\"exposure_notify_off_nearby\">Сповіщення про вплив вимагають додаткових дозволів на роботу</string>\n    <string name=\"pref_exposure_error_bluetooth_unsupported_summary\">На жаль, ваш пристрій не сумісний з функцією сповіщень про зараження.</string>\n    <string name=\"pref_exposure_error_bluetooth_no_advertise_summary\">На жаль, ваш пристрій лише частково сумісний зі сповіщеннями про зараження. Ви можете отримувати сповіщення про небезпечні контакти, але не зможете сповіщати інших.</string>\n    <string name=\"pref_exposure_collected_rpis_summary\"><xliff:g example=\"63\">%1$d</xliff:g> ідентифікаторів за останню годину</string>\n    <string name=\"pref_exposure_app_report_updated_title\">Оновлено: <xliff:g example=\"Today, 14:02\">%1$s</xliff:g></string>\n    <string name=\"pref_exposure_app_report_entry_time_about\">Близько <xliff:g example=\"13\">%1$d</xliff:g> хвилин</string>\n    <string name=\"pref_exposure_app_report_entry_combined\"><xliff:g example=\"About 12 minutes\">%1$s</xliff:g>, <xliff:g example=\"distant exposure\">%2$s</xliff:g></string>\n    <string name=\"pref_exposure_app_last_report_summary_diagnosis_keys\">Оброблено <xliff:g example=\"121031\">%1$d</xliff:g> діагностичних ключів.</string>\n    <string name=\"prefcat_exposure_apps_title\">Застосунок, який використовує сповіщення про зараження</string>\n    <string name=\"pref_exposure_collected_rpis_title\">Зібрані ідентифікатори</string>\n    <string name=\"pref_exposure_advertising_id_title\">Поточний ідентифікатор, який транслюється</string>\n    <string name=\"prefcat_exposure_app_report_title\">Виявлені зараження</string>\n    <string name=\"pref_exposure_app_report_entry_time_short\">Менше 5 хвилин тому</string>\n    <string name=\"pref_exposure_app_report_entry_distance_close\">поблизу зараження</string>\n    <string name=\"pref_exposure_app_report_entry_distance_far\">зараження далеко</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_prefix\">Повідомлено про <xliff:g example=\"3\">%1$d</xliff:g> небезпечні контакти:</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_line\"><xliff:g example=\"Yesterday, 12:00 - 14:00\">%1$s</xliff:g>, оцінка ризику <xliff:g example=\"99\">%2$d</xliff:g></string>\n    <string name=\"pref_exposure_app_api_usage_summary_line\"><xliff:g example=\"12\">%1$d</xliff:g> запитів до <xliff:g example=\"provideDiagnosisKeys\">%2$s</xliff:g></string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_no\">Про випадки небезпечних контактів не повідомлялося.</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_suffix\">Примітка: Оцінка ризику визначається застосунком. Високі показники можуть означати низький ризик або навпаки.</string>\n    <string name=\"pref_exposure_app_api_usage_title\">Використання API за останні 14 днів</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_records\"><xliff:g example=\"0 - 50\">%1$s</xliff:g> ID на годину</string>\n    <string name=\"exposure_confirm_permission_description\"><xliff:g example=\"microG Services\">%1$s</xliff:g> потребує додаткових дозволів.</string>\n    <string name=\"prefcat_exposure_rpis_histogram_title\"><xliff:g example=\"230\">%1$d</xliff:g> ID зібрано</string>\n    <string name=\"exposure_confirm_stop_button\">Вимкнути</string>\n    <string name=\"pref_exposure_rpis_details_summary\">Коли API сповіщень про вплив увімкнено, ваш пристрій пасивно збирає ідентифікатори (так звані «рухомі ідентифікатори близькості», Rolling Proximity Identifiers, або RPI) з пристроїв, що знаходяться поруч.\n\\n\n\\nКоли власники пристроїв повідомляють про позитивний результат діагностики, їхні ідентифікатори можна використовувати спільно. Ваш пристрій перевіряє, чи збігається будь-який з відомих діагностованих ідентифікаторів з будь-яким із зібраних ідентифікаторів, і обчислює ризик зараження.</string>\n    <string name=\"exposure_confirm_start_button\">Ввімкнути</string>\n    <string name=\"exposure_confirm_stop_title\">Вимкнути сповіщення про вплив?</string>\n    <string name=\"exposure_confirm_stop_summary\">Після вимкнення сповіщень про вплив ви більше не отримуватимете сповіщень, якщо ви контактували з людиною, яка повідомила про позитивний результат тесту.</string>\n    <string name=\"exposure_grant_background_location_description\">Майже готово! Вам потрібно буде ввімкнути доступ до розташування у фоновому режимі, вибравши параметр «Дозволити постійно» на наступному екрані. Потім поверніться назад.</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_no_records\">Немає записів</string>\n    <string name=\"pref_exposure_rpi_delete_all_title\">Видалити</string>\n    <string name=\"pref_exposure_rpi_delete_all_summary\">Видалити всі зібрані ID</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning\">Видалення зібраних ідентифікаторів унеможливить сповіщення вас у випадку, якщо хтось із ваших контактів за останні 14 днів буде діагностований.</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning_confirm_button\">Всеодно видалити</string>\n    <string name=\"pref_exposure_rpi_export_title\">Експортування</string>\n    <string name=\"pref_exposure_rpi_export_summary\">Експортуйте зібрані ідентифікатори для розширеного аналізу за допомогою іншого застосунку.</string>\n    <string name=\"pref_exposure_info_summary\">API сповіщень про контакт дозволяє застосункам сповіщати вас, якщо ви контактували з людиною, яка повідомила про позитивний результат тесту.\n\\n\n\\nДата, тривалість і рівень сигналу, пов\\'язані з контактом, будуть передані відповідному застосунку.</string>\n    <string name=\"exposure_enable_switch\">Використовувати сповіщення про вплив</string>\n    <string name=\"exposure_confirm_start_title\">Увімкнути сповіщення про вплив?</string>\n    <string name=\"exposure_confirm_start_summary\">Ваш телефон повинен використовувати Bluetooth для безпечного збору та обміну ідентифікаторами з іншими телефонами, які знаходяться поблизу.\\n\\n<xliff:g example=\"Corona-Warn\">%1$s</xliff:g> може сповістити вас, якщо ви зазнали контакту з людиною, яка повідомила про позитивний діагноз.\\n\\nДата, тривалість і рівень сигналу, пов\\'язані з контактом, будуть передані застосунку.</string>\n    <string name=\"exposure_confirm_keys_title\">Поділітися своїми ідентифікаторами з <xliff:g example=\"Corona-Warn\">%1$s</xliff:g>\\?</string>\n    <string name=\"exposure_confirm_keys_summary\">Ваші ідентифікаційні дані за останні 14 днів будуть використані, щоби повідомити інших людей, які перебували поруч з вами, про потенційний ризик зараження.\n\\n\n\\nВаші дані або результати тесту не будуть передані іншим особам.</string>\n    <string name=\"exposure_confirm_keys_button\">Поділитися</string>\n    <string name=\"exposure_confirm_permission_button\">Надати дозвіл</string>\n    <string name=\"exposure_confirm_bluetooth_description\">Bluetooth має бути ввімкнено.</string>\n    <string name=\"exposure_confirm_location_description\">Доступ до розташування є обов\\'язковим.</string>\n    <string name=\"exposure_confirm_button\">Ввімкнути</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_title\">Потрібні нові дозволи</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_description\">Натисніть, щоб надати необхідні дозволи для сповіщень про вплив</string>\n    <string name=\"exposure_grant_background_location_button\">Оновити налаштування</string>\n</resources>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-vi/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=\"exposure_notify_off_title\">Thông báo Tiếp xúc hiện không hoạt động</string>\n    <string name=\"exposure_notify_off_bluetooth\">Cần bật Bluetooth để nhận Thông báo Tiếp xúc.</string>\n    <string name=\"exposure_notify_off_location\">Cần quyền truy cập Vị trí để nhận Thông báo Tiếp xúc.</string>\n    <string name=\"exposure_notify_off_nearby\">Thông báo Tiếp xúc cần thêm các quyền để hoạt động</string>\n    <string name=\"service_name_exposure\">Thông báo Tiếp xúc</string>\n    <string name=\"pref_exposure_error_location_off_title\">Mở cài đặt Vị trí</string>\n    <string name=\"pref_exposure_error_bluetooth_unsupported_summary\">Rất tiếc, thiết bị của bạn không tương thích với Thông báo Tiếp xúc.</string>\n    <string name=\"exposure_notify_off_bluetooth_location\">Cần bật Bluetooth và quyền truy cập Vị trí để nhận Thông báo Tiếp xúc.</string>\n    <string name=\"prefcat_exposure_apps_title\">Ứng dụng sử dụng Thông báo Tiếp xúc</string>\n    <string name=\"pref_exposure_collected_rpis_title\">Các ID đã thu thập</string>\n    <string name=\"pref_exposure_advertising_id_title\">ID đang được phát sóng</string>\n    <string name=\"prefcat_exposure_app_report_title\">Các tiếp xúc đã được báo cáo</string>\n    <string name=\"pref_exposure_app_report_entry_time_short\">Ít hơn 5 phút</string>\n    <string name=\"pref_exposure_app_report_updated_title\">Đã cập nhật: <xliff:g example=\"Hôm nay, 14:02\">%1$s</xliff:g></string>\n    <string name=\"pref_exposure_app_report_entry_time_about\">Khoảng <xliff:g example=\"13\">%1$d</xliff:g> phút</string>\n    <string name=\"pref_exposure_app_report_entry_distance_close\">tiếp xúc gần</string>\n    <string name=\"pref_exposure_app_report_entry_distance_far\">tiếp xúc xa</string>\n    <string name=\"pref_exposure_app_report_entry_combined\"><xliff:g example=\"Khoảng 12 phút\">%1$s</xliff:g>, <xliff:g example=\"tiếp xúc xa\">%2$s</xliff:g></string>\n    <string name=\"pref_exposure_app_last_report_summary_diagnosis_keys\">Đã xử trí khoá chẩn đoán <xliff:g example=\"121031\">%1$d</xliff:g>.</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_no\">Không có trường hợp tiếp xúc nào được báo cáo.</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_suffix\">Lưu ý: Điểm rủi ro được xác định bởi ứng dụng. Số điểm cao có thể liên quan đến rủi ro thấp hoặc ngược lại.</string>\n    <string name=\"pref_exposure_app_api_usage_title\">Sử dụng API trong 14 ngày qua</string>\n    <string name=\"pref_exposure_app_api_usage_summary_line\"><xliff:g example=\"12\">%1$d</xliff:g> gọi đến <xliff:g example=\"provideDiagnosisKeys\">%2$s</xliff:g></string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_prefix\">Đã báo cáo các trường hợp tiếp xúc với <xliff:g example=\"3\">%1$d</xliff:g>:</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_line\"><xliff:g example=\"Hôm qua, 12:00 - 14:00\">%1$s</xliff:g>, điểm rủi ro <xliff:g example=\"99\">%2$d</xliff:g></string>\n    <string name=\"prefcat_exposure_rpis_histogram_title\"><xliff:g example=\"230\">%1$d</xliff:g> ID đã thu thập</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_records\"><xliff:g example=\"0 - 50\">%1$s</xliff:g> ID mỗi giờ</string>\n    <string name=\"pref_exposure_rpi_delete_all_title\">Xoá</string>\n    <string name=\"pref_exposure_rpi_delete_all_summary\">Xoá tất cả ID đã thu thập</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_no_records\">Không có bản ghi</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning\">Việc xóa các ID đã thu thập sẽ khiến bạn không thể nhận thông báo nếu bất kỳ ai trong số các liên lạc của bạn trong 14 ngày qua được chẩn đoán.</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning_confirm_button\">Vẫn xoá</string>\n    <string name=\"pref_exposure_rpi_export_title\">Xuất</string>\n    <string name=\"pref_exposure_rpi_export_summary\">Xuất ID đã thu thập để phân tích mở rộng bằng ứng dụng khác.</string>\n    <string name=\"pref_exposure_rpis_details_summary\">Khi đã kích hoạt API Thông báo Tiếp xúc, thiết bị của bạn sẽ thụ động thu thập các ID (gọi là Rolling Proximity Identifiers, hoặc RPIs) từ các thiết bị gần đó.\\n\\nKhi chủ sở hữu thiết được chẩn đoán dương tính, ID của họ có thể được chia sẻ. Thiết bị của bạn kiểm tra xem có ID nào đã biết được chẩn đoán dương tính trùng khớp với các ID đã thu thập hay không và tính toán mức độ rủi ro nhiễm bệnh của bạn.</string>\n    <string name=\"exposure_enable_switch\">Sử dụng Thông báo Tiếp xúc</string>\n    <string name=\"exposure_confirm_start_title\">Bật Thông báo Tiếp xúc?</string>\n    <string name=\"exposure_confirm_start_button\">Bật</string>\n    <string name=\"exposure_confirm_stop_title\">Tắt Thông báo Tiếp xúc?</string>\n    <string name=\"exposure_confirm_stop_summary\">Sau khi tắt Thông báo Tiếp xúc, bạn sẽ không còn nhận được thông báo khi bạn đã tiếp xúc với ai đó đã được chẩn đoán dương tính.</string>\n    <string name=\"exposure_confirm_stop_button\">Tắt</string>\n    <string name=\"exposure_confirm_keys_title\">Chia sẻ ID của bạn với <xliff:g example=\"Corona-Warn\">%1$s</xliff:g>\\?</string>\n    <string name=\"exposure_confirm_keys_summary\">ID của bạn trong 14 ngày qua sẽ được sử dụng để giúp thông báo cho người khác rằng bạn đã ở gần những trường hợp phơi nhiễm tiềm tàng.\\n\\nDanh tính hoặc kết quả xét nghiệm của bạn sẽ không được chia sẻ với người khác.</string>\n    <string name=\"exposure_confirm_keys_button\">Chia sẻ</string>\n    <string name=\"exposure_confirm_permission_description\"><xliff:g example=\"Dịch vụ microG\">%1$s</xliff:g> cần thêm quyền.</string>\n    <string name=\"exposure_confirm_permission_button\">Cấp quyền</string>\n    <string name=\"exposure_confirm_bluetooth_description\">Cần phải bật Bluetooth.</string>\n    <string name=\"exposure_confirm_location_description\">Cần phải có quyền truy cập vị trí.</string>\n    <string name=\"exposure_confirm_button\">Bật</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_description\">Nhấn để cấp các quyền cần thiết cho Thông báo Tiếp xúc</string>\n    <string name=\"exposure_grant_background_location_description\">Gần xong rồi! Bạn sẽ cần bật quyền truy cập vị trí nền bằng cách chọn tùy chọn \\'Cho phép mọi lúc\\' trên màn hình tiếp theo. Sau đó nhấn quay lại.</string>\n    <string name=\"exposure_grant_background_location_button\">Cập nhật cài đặt</string>\n    <string name=\"pref_exposure_enable_info_summary\">Để bật Thông báo Tiếp xúc, hãy mở bất kỳ ứng dụng nào hỗ trợ tính năng này.</string>\n    <string name=\"pref_exposure_error_bluetooth_off_title\">Bật Bluetooth</string>\n    <string name=\"pref_exposure_error_bluetooth_no_advertise_summary\">Rất tiếc, thiết bị của bạn chỉ tương thích một phần với Thông báo Tiếp xúc. Bạn có thể nhận thông báo về các tiếp xúc có nguy cơ, nhưng sẽ không thể thông báo cho người khác.</string>\n    <string name=\"pref_exposure_collected_rpis_summary\"><xliff:g example=\"63\">%1$d</xliff:g> ID trong giờ qua</string>\n    <string name=\"pref_exposure_info_summary\">API Thông báo Tiếp xúc cho phép các ứng dụng thông báo cho bạn nếu bạn đã tiếp xúc với ai đó được chẩn đoán là dương tính.\\n\\nNgày, thời gian, và cường độ tín hiệu liên quan đến lần tiếp xúc sẽ được chia sẻ với ứng dụng tương ứng.</string>\n    <string name=\"exposure_confirm_start_summary\">Điện thoại của bạn cần sử dụng Bluetooth để thu thập và chia sẻ ID một cách an toàn với các điện thoại khác ở gần.\\n\\n<xliff:g example=\"Corona-Warn\">%1$s</xliff:g> có thể thông báo cho bạn nếu bạn đã tiếp xúc với người được báo cáo là dương tính.\\n\\nNgày, thời gian và cường độ tín hiệu liên quan đến lần tiếp xúc sẽ được chia sẻ với ứng dụng.</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_title\">Cần có Quyền mới</string>\n</resources>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-zh-rCN/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"exposure_notify_off_title\">接触史通知未启用</string>\n    <string name=\"exposure_notify_off_bluetooth\">需要启用蓝牙以接收接触史通知。</string>\n    <string name=\"exposure_notify_off_location\">需要位置访问权限以接收接触史通知。</string>\n    <string name=\"exposure_notify_off_bluetooth_location\">需要启用蓝牙和位置访问权限以接收接触史通知。</string>\n    <string name=\"exposure_notify_off_nearby\">接触史通知需要额外权限来运作</string>\n    <string name=\"service_name_exposure\">接触史通知系统</string>\n    <string name=\"pref_exposure_enable_info_summary\">要启用接触史通知系统，请打开支持该系统的应用。</string>\n    <string name=\"pref_exposure_error_bluetooth_off_title\">启用蓝牙</string>\n    <string name=\"pref_exposure_error_location_off_title\">打开位置设置</string>\n    <string name=\"pref_exposure_error_bluetooth_unsupported_summary\">很抱歉，您的设备与接触史通知系统不兼容。</string>\n    <string name=\"pref_exposure_error_bluetooth_no_advertise_summary\">很抱歉，您的设备与接触史通知系统仅部分兼容。您可以收到接触风险通知，但无法向他人发出通知。</string>\n    <string name=\"prefcat_exposure_apps_title\">使用接触史通知系统的应用</string>\n    <string name=\"pref_exposure_collected_rpis_title\">已收集的标识符</string>\n    <string name=\"pref_exposure_collected_rpis_summary\">最近一小时已收集 <xliff:g example=\"63\">%1$d</xliff:g> 个标识符</string>\n    <string name=\"pref_exposure_advertising_id_title\">当前已广播的标识符</string>\n    <string name=\"prefcat_exposure_app_report_title\">已报告接触史</string>\n    <string name=\"pref_exposure_app_report_updated_title\">最后更新于：<xliff:g example=\"Today, 14:02\">%1$s</xliff:g></string>\n    <string name=\"pref_exposure_app_report_entry_time_short\">不到 5 分钟</string>\n    <string name=\"pref_exposure_app_report_entry_time_about\">约 <xliff:g example=\"13\">%1$d</xliff:g> 分钟</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_no\">没有已报告的接触者。</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_suffix\">注意：风险评分由应用定义。数字更高可能代表低风险，或反之。</string>\n    <string name=\"pref_exposure_app_api_usage_title\">14 天内的 API 使用情况</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_no_records\">无记录</string>\n    <string name=\"pref_exposure_rpi_delete_all_title\">删除</string>\n    <string name=\"pref_exposure_rpi_delete_all_summary\">删除所有已收集的标识符</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning\">删除所有已收集的标识符会导致您无法在最近 14 天内接触过确诊对象时获得通知。</string>\n    <string name=\"pref_exposure_rpi_delete_all_warning_confirm_button\">仍要删除</string>\n    <string name=\"pref_exposure_rpi_export_title\">导出</string>\n    <string name=\"exposure_confirm_button\">启用</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_title\">需要新权限</string>\n    <string name=\"exposure_grant_background_location_button\">更新设置</string>\n    <string name=\"exposure_confirm_stop_button\">关闭</string>\n    <string name=\"exposure_confirm_start_button\">打开</string>\n    <string name=\"exposure_confirm_start_title\">打开接触史通知？</string>\n    <string name=\"exposure_enable_switch\">使用接触史通知</string>\n    <string name=\"pref_exposure_rpis_details_summary\">\"接触史通知启用时，您的设备被动地从附近的设备收集滚动邻近标识符（RPI）。\n\n其他设备拥有者被确诊为阳性时，他们的标识将被共享。您的设备将检查是否曾收集到已知确诊患者的标识，并据此计算您的感染风险。\"</string>\n    <string name=\"pref_exposure_info_summary\">\"接触史通知 API 允许应用在您曾经与新冠肺炎阳性确诊患者接触时通知您。\n\n接触的发生日期、时长和信号强度将被共享给相应的应用。</string>\n    <string name=\"pref_exposure_rpi_export_summary\">导出已收集的标识符以供其他应用进一步分析。</string>\n    <string name=\"exposure_confirm_stop_title\">关闭接触史通知？</string>\n    <string name=\"pref_exposure_app_report_entry_distance_close\">近距离接触</string>\n    <string name=\"pref_exposure_app_report_entry_distance_far\">远距离接触</string>\n    <string name=\"exposure_confirm_permission_description\"><xliff:g example=\"microG Services\">%1$s</xliff:g> 需要额外权限。</string>\n    <string name=\"exposure_confirm_permission_button\">授予权限</string>\n    <string name=\"exposure_confirm_bluetooth_description\">需要打开蓝牙。</string>\n    <string name=\"exposure_confirm_location_description\">需要位置访问权限。</string>\n    <string name=\"exposure_grant_background_location_description\">马上就好！请在下一屏幕中选择“一律允许”以授予后台位置访问权限，然后返回。</string>\n    <string name=\"exposure_confirm_keys_title\">向 <xliff:g example=\"Corona-Warn\">%1$s</xliff:g> 共享您的标识符？</string>\n    <string name=\"exposure_confirm_keys_button\">共享</string>\n    <string name=\"exposure_confirm_stop_summary\">关闭接触史通知后，您将无法在最近接触过确诊对象时获得通知。</string>\n    <string name=\"pref_exposure_error_nearby_not_granted_description\">点击以向接触史通知授予权限</string>\n    <string name=\"exposure_confirm_keys_summary\">您最近 14 天的标识符将被用来帮助向您附近的人通知您的潜在接触史。\n\\n\n\\n不会向他人共享您的个人身份和检测结果。</string>\n    <string name=\"exposure_confirm_start_summary\">\"您的设备需要蓝牙以安全地收集并与附近的其他设备共享标识符。\n\n<xliff:g example=\"Corona-Warn\">%1$s</xliff:g> 可以在您曾与新冠肺炎阳性确诊患者接触时通知您。\n\n接触的发生日期、时长和与信号强度将被共享给相应的应用。\"</string>\n    <string name=\"pref_exposure_rpis_histogram_legend_records\">每小时 <xliff:g example=\"0 - 50\">%1$s</xliff:g> 个标识符</string>\n    <string name=\"prefcat_exposure_rpis_histogram_title\">已收集 <xliff:g example=\"230\">%1$d</xliff:g> 个标识符</string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_line\"><xliff:g example=\"Yesterday, 12:00 - 14:00\">%1$s</xliff:g>，风险评分：<xliff:g example=\"99\">%2$d</xliff:g></string>\n    <string name=\"pref_exposure_app_report_entry_combined\"><xliff:g example=\"About 12 minutes\">%1$s</xliff:g>, <xliff:g example=\"distant exposure\">%2$s</xliff:g></string>\n    <string name=\"pref_exposure_app_last_report_summary_encounters_prefix\">已报告<xliff:g example=\"3\">%1$d</xliff:g>暴露遭遇：</string>\n    <string name=\"pref_exposure_app_api_usage_summary_line\"><xliff:g example=\"12\">%1$d</xliff:g> 联系<xliff:g example=\"provideDiagnosisKeys\">%2$s</xliff:g></string>\n    <string name=\"pref_exposure_app_last_report_summary_diagnosis_keys\">处理<xliff:g example=\"121031\">%1$d</xliff:g>诊断密钥。</string>\n</resources>"
  },
  {
    "path": "play-services-nearby/core/src/main/res/values-zh-rTW/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"exposure_notify_off_title\">暴露通知未激活</string>\n    <string name=\"exposure_notify_off_bluetooth\">需要啟用藍牙才能接收暴露通知。</string>\n    <string name=\"exposure_notify_off_location\">需要位置访问權限才能接收暴露通知。</string>\n</resources>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/xml/preferences_exposure_notifications.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\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    <org.microg.gms.ui.SwitchBarPreference\n        android:title=\"@string/exposure_enable_switch\"\n        android:key=\"pref_exposure_enabled\"\n        android:persistent=\"false\" />\n\n    <Preference\n        android:key=\"pref_exposure_enable_info\"\n        android:selectable=\"false\"\n        android:summary=\"@string/pref_exposure_enable_info_summary\"\n        app:isPreferenceVisible=\"false\"\n        tools:isPreferenceVisible=\"true\" />\n\n    <Preference\n        android:icon=\"@drawable/ic_bluetooth_off\"\n        android:key=\"pref_exposure_error_bluetooth_off\"\n        android:title=\"@string/pref_exposure_error_bluetooth_off_title\"\n        android:summary=\"@string/exposure_confirm_bluetooth_description\"\n        app:isPreferenceVisible=\"false\"\n        tools:isPreferenceVisible=\"true\" />\n\n    <Preference\n        android:icon=\"@drawable/ic_location_off\"\n        android:key=\"pref_exposure_error_location_off\"\n        android:title=\"@string/pref_exposure_error_location_off_title\"\n        android:summary=\"@string/exposure_confirm_location_description\"\n        app:isPreferenceVisible=\"false\"\n        tools:isPreferenceVisible=\"true\" />\n\n    <Preference\n        android:icon=\"@drawable/ic_info_outline\"\n        android:key=\"pref_exposure_error_nearby_not_granted\"\n        android:title=\"@string/pref_exposure_error_nearby_not_granted_title\"\n        android:summary=\"@string/pref_exposure_error_nearby_not_granted_description\"\n        app:isPreferenceVisible=\"false\"\n        tools:isPreferenceVisible=\"true\" />\n\n    <Preference\n        android:icon=\"@drawable/ic_alert\"\n        android:key=\"pref_exposure_error_bluetooth_unsupported\"\n        android:selectable=\"false\"\n        android:summary=\"@string/pref_exposure_error_bluetooth_unsupported_summary\"\n        app:isPreferenceVisible=\"false\"\n        tools:isPreferenceVisible=\"true\" />\n\n    <Preference\n        android:icon=\"@drawable/ic_alert\"\n        android:key=\"pref_exposure_error_bluetooth_no_advertise\"\n        android:selectable=\"false\"\n        android:summary=\"@string/pref_exposure_error_bluetooth_no_advertise_summary\"\n        app:isPreferenceVisible=\"false\"\n        tools:isPreferenceVisible=\"true\" />\n\n    <PreferenceCategory\n        android:key=\"prefcat_exposure_apps\"\n        android:title=\"@string/prefcat_exposure_apps_title\">\n        <Preference\n            android:enabled=\"false\"\n            android:key=\"pref_exposure_apps_none\"\n            android:title=\"@string/list_no_item_none\" />\n    </PreferenceCategory>\n\n    <PreferenceCategory android:layout=\"@layout/preference_category_no_label\">\n        <Preference\n            android:key=\"pref_exposure_collected_rpis\"\n            android:title=\"@string/pref_exposure_collected_rpis_title\"\n            tools:summary=\"@string/pref_exposure_collected_rpis_summary\" />\n        <Preference\n            android:enabled=\"false\"\n            android:key=\"pref_exposure_advertising_id\"\n            android:title=\"@string/pref_exposure_advertising_id_title\"\n            tools:summary=\"9a799d68-925f-4c0c-a73c-b418f22a1250\" />\n    </PreferenceCategory>\n\n    <PreferenceCategory android:layout=\"@layout/preference_category_no_label\">\n        <org.microg.gms.ui.TextPreference\n            android:icon=\"@drawable/ic_info_outline\"\n            android:selectable=\"false\"\n            android:summary=\"@string/pref_exposure_info_summary\" />\n    </PreferenceCategory>\n</PreferenceScreen>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/xml/preferences_exposure_notifications_app.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\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    <PreferenceCategory android:layout=\"@layout/preference_category_no_label\">\n        <Preference\n            android:icon=\"@drawable/ic_open\"\n            android:key=\"pref_exposure_app_open\"\n            android:title=\"@string/open_app\" />\n    </PreferenceCategory>\n    <PreferenceCategory\n        android:key=\"prefcat_exposure_app_report\"\n        android:title=\"@string/prefcat_exposure_app_report_title\">\n        <Preference\n            android:enabled=\"false\"\n            android:key=\"pref_exposure_app_report_none\"\n            android:order=\"0\"\n            android:title=\"@string/list_no_item_none\"\n            app:isPreferenceVisible=\"false\"\n            tools:isPreferenceVisible=\"true\" />\n        <Preference\n            android:enabled=\"false\"\n            android:key=\"pref_exposure_app_report_updated\"\n            android:order=\"100\"\n            android:summary=\"@string/pref_exposure_app_last_report_summary_diagnosis_keys\"\n            android:title=\"@string/pref_exposure_app_report_updated_title\" />\n    </PreferenceCategory>\n    <PreferenceCategory android:layout=\"@layout/preference_category_no_label\">\n        <Preference\n            android:enabled=\"false\"\n            android:key=\"pref_exposure_app_api_usage\"\n            android:title=\"@string/pref_exposure_app_api_usage_title\"\n            tools:summary=\"@string/pref_exposure_app_api_usage_summary_line\" />\n    </PreferenceCategory>\n</PreferenceScreen>\n"
  },
  {
    "path": "play-services-nearby/core/src/main/res/xml/preferences_exposure_notifications_exportedfiles.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<paths>\n    <cache-path name=\"exposureDatabase\" path=\"exposureDatabase\" />\n</paths>"
  },
  {
    "path": "play-services-nearby/core/src/main/res/xml/preferences_exposure_notifications_rpis.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\">\n    <PreferenceCategory\n        android:key=\"prefcat_exposure_rpi_histogram\"\n        tools:title=\"@string/prefcat_exposure_rpis_histogram_title\">\n        <org.microg.gms.nearby.exposurenotification.ui.DotChartPreference\n            android:key=\"pref_exposure_rpi_histogram\"\n            android:selectable=\"false\"\n            tools:layout=\"@layout/preference_dot_chart\" />\n    </PreferenceCategory>\n    <PreferenceCategory android:layout=\"@layout/preference_category_no_label\">\n        <Preference\n            android:key=\"pref_exposure_export_database\"\n            android:summary=\"@string/pref_exposure_rpi_export_summary\"\n            android:title=\"@string/pref_exposure_rpi_export_title\" />\n        <Preference\n            android:key=\"pref_exposure_rpi_delete_all\"\n            android:summary=\"@string/pref_exposure_rpi_delete_all_summary\"\n            android:title=\"@string/pref_exposure_rpi_delete_all_title\" />\n    </PreferenceCategory>\n    <PreferenceCategory android:layout=\"@layout/preference_category_no_label\">\n        <org.microg.gms.ui.TextPreference\n            android:icon=\"@drawable/ic_info_outline\"\n            android:selectable=\"false\"\n            android:summary=\"@string/pref_exposure_rpis_details_summary\" />\n    </PreferenceCategory>\n</PreferenceScreen>\n"
  },
  {
    "path": "play-services-nearby/core/src/test/java/org/microg/gms/nearby/exposurenotification/CryptoTest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.nearby.exposurenotification;\n\n\nimport com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey;\n\nimport junit.framework.TestCase;\n\nimport org.junit.Assert;\n\nimport java.util.Arrays;\n\npublic class CryptoTest extends TestCase {\n    private TemporaryExposureKey key;\n\n    @Override\n    protected void setUp() {\n        key = new TemporaryExposureKey.TemporaryExposureKeyBuilder()\n                .setKeyData(TestVectors.get_TEMPORARY_TRACING_KEY())\n                .setRollingStartIntervalNumber(TestVectors.CTINTERVAL_NUMBER_OF_GENERATED_KEY)\n                .setRollingPeriod(TestVectors.KEY_ROLLING_PERIOD_MULTIPLE_OF_ID_PERIOD)\n                .build();\n    }\n\n    @Override\n    protected void tearDown() {\n        key = null;\n    }\n\n    public void testGenerateRpiKey() {\n        Assert.assertArrayEquals(CryptoKt.generateRpiKey(key).getEncoded(), TestVectors.get_RPIK());\n    }\n\n    public void testGenerateAemKey() {\n        Assert.assertArrayEquals(CryptoKt.generateAemKey(key).getEncoded(), TestVectors.get_AEMK());\n    }\n\n    public void testGenerateRpiId() {\n        for (int i = 0; i < TestVectors.KEY_ROLLING_PERIOD_MULTIPLE_OF_ID_PERIOD; i++) {\n            byte[] gen = CryptoKt.generateRpiId(key, key.getRollingStartIntervalNumber() + i);\n            Assert.assertArrayEquals(gen, TestVectors.ADVERTISED_DATA.get(i).get_RPI());\n        }\n    }\n\n    public void testGeneratePayload() {\n        for (int i = 0; i < TestVectors.KEY_ROLLING_PERIOD_MULTIPLE_OF_ID_PERIOD; i++) {\n            byte[] gen = CryptoKt.generatePayload(key, key.getRollingStartIntervalNumber() + i, TestVectors.get_BLE_METADATA());\n            Assert.assertArrayEquals(gen, TestVectors.ADVERTISED_DATA.get(i).get_merged());\n        }\n    }\n\n    public void testGenerateAllRpiIds() {\n        byte[] all = CryptoKt.generateAllRpiIds(key);\n        for (int i = 0; i < TestVectors.KEY_ROLLING_PERIOD_MULTIPLE_OF_ID_PERIOD; i++) {\n            byte[] ref = CryptoKt.generateRpiId(key, key.getRollingStartIntervalNumber() + i);\n            byte[] gen = Arrays.copyOfRange(all, i * 16, (i + 1) * 16);\n            Assert.assertArrayEquals(gen, ref);\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-nearby/core/src/test/java/org/microg/gms/nearby/exposurenotification/TestVectors.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, Google LLC\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are derived from work created and shared by Google and used\n *         according to the terms described in the Apache License, Version 2.0.\n *         See https://github.com/google/exposure-notifications-internals\n */\n\npackage org.microg.gms.nearby.exposurenotification;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class TestVectors {\n\n    public static byte[] asBytes(int... ints) {\n        byte[] bytes = new byte[ints.length];\n        for (int i = 0; i < ints.length; i++) {\n            int value = ints[i];\n            bytes[i] = (byte) value;\n        }\n        return bytes;\n    }\n\n    /**\n     * Class holding a matched pair of RPI and AEM values.\n     */\n    public static class AdvertisedData {\n        private final byte[] rollingProximityIndicator;\n        private final byte[] associatedEncryptedMetadata;\n\n        AdvertisedData(byte[] rollingProximityIndicator, byte[] associatedEncryptedMetadata) {\n            this.rollingProximityIndicator = rollingProximityIndicator;\n            this.associatedEncryptedMetadata = associatedEncryptedMetadata;\n        }\n\n        public byte[] get_RPI() {\n            return rollingProximityIndicator.clone();\n        }\n\n        public byte[] get_AEM() {\n            return associatedEncryptedMetadata.clone();\n        }\n\n        public byte[] get_merged() {\n            byte[] bytes = new byte[rollingProximityIndicator.length + associatedEncryptedMetadata.length];\n            System.arraycopy(rollingProximityIndicator, 0, bytes, 0, rollingProximityIndicator.length);\n            System.arraycopy(associatedEncryptedMetadata, 0, bytes, rollingProximityIndicator.length, associatedEncryptedMetadata.length);\n            return bytes;\n        }\n    }\n\n    public static byte[] get_TEMPORARY_TRACING_KEY() {\n        return TEMPORARY_TRACING_KEY.clone();\n    }\n\n    public static byte[] get_RPIK() {\n        return RPIK.clone();\n    }\n\n    public static byte[] get_AEMK() {\n        return AEMK.clone();\n    }\n\n    public static byte[] get_BLE_METADATA() {\n        return BLE_METADATA.clone();\n    }\n\n    public static String get_RPIK_HKDF_INFO_STRING() {\n        return \"EN-RPIK\";\n    }\n\n    public static String get_RPI_AES_PADDED_STRING() {\n        return \"EN-RPI\";\n    }\n\n    public static String get_AEMK_HKDF_INFO_STRING() {\n        return \"EN-AEMK\";\n    }\n\n    // From TestVectors.h.txt\n    // ------------------------------------------------------------------------------\n    public static final int KEY_GENERATION_NSECONDS = 1585785600;\n    public static final int CTINTERVAL_NUMBER_OF_GENERATED_KEY = 2642976;\n    public static final int ID_ROLLING_PERIOD_MINUTES = 10;\n    public static final int KEY_ROLLING_PERIOD_MULTIPLE_OF_ID_PERIOD = 144;\n\n    private static final byte[] TEMPORARY_TRACING_KEY =\n            asBytes(\n                    0x75, 0xc7, 0x34, 0xc6, 0xdd, 0x1a, 0x78, 0x2d, 0xe7, 0xa9, 0x65, 0xda, 0x5e, 0xb9, 0x31,\n                    0x25);\n\n    private static final byte[] RPIK =\n            asBytes(\n                    0x18, 0x5a, 0xd9, 0x1d, 0xb6, 0x9e, 0xc7, 0xdd, 0x04, 0x89, 0x60, 0xf1, 0xf3, 0xba, 0x61,\n                    0x75);\n    private static final byte[] AEMK =\n            asBytes(\n                    0xd5, 0x7c, 0x46, 0xaf, 0x7a, 0x1d, 0x83, 0x96, 0x5b, 0x9b, 0xed, 0x8b, 0xd1, 0x52, 0x93,\n                    0x6a);\n    private static final byte[] BLE_METADATA = asBytes(0x40, 0x08, 0x00, 0x00);\n    private static final byte[] RPI0 =\n            asBytes(\n                    0x8b, 0xe6, 0xcd, 0x37, 0x1c, 0x5c, 0x89, 0x16, 0x04, 0xbf, 0xbe, 0x49, 0xdf, 0x84, 0x50,\n                    0x96);\n    private static final byte[] AEM0 = asBytes(0x72, 0x03, 0x38, 0x74);\n    private static final byte[] RPI1 =\n            asBytes(\n                    0x3c, 0x9a, 0x1d, 0xe5, 0xdd, 0x6b, 0x02, 0xaf, 0xa7, 0xfd, 0xed, 0x7b, 0x57, 0x0b, 0x3e,\n                    0x56);\n    private static final byte[] AEM1 = asBytes(0xc2, 0x92, 0x11, 0xb1);\n    private static final byte[] RPI2 =\n            asBytes(\n                    0x24, 0x3f, 0xfe, 0x9a, 0x3b, 0x08, 0xbd, 0xed, 0x30, 0x94, 0xba, 0xc8, 0x63, 0x0b, 0xb8,\n                    0xad);\n    private static final byte[] AEM2 = asBytes(0x6a, 0xdf, 0xad, 0x03);\n    private static final byte[] RPI3 =\n            asBytes(\n                    0xdf, 0xc3, 0xed, 0x26, 0x5e, 0x97, 0xd0, 0xea, 0xbb, 0x63, 0x0e, 0x16, 0x8b, 0x42, 0x14,\n                    0xed);\n    private static final byte[] AEM3 = asBytes(0xf1, 0xe2, 0xf8, 0x0b);\n    private static final byte[] RPI4 =\n            asBytes(\n                    0xb3, 0xb8, 0x5a, 0x69, 0xeb, 0xae, 0xc7, 0x8d, 0xb7, 0x39, 0x85, 0x2d, 0x1f, 0x34, 0xe0,\n                    0xfa);\n    private static final byte[] AEM4 = asBytes(0x56, 0x68, 0xc4, 0x74);\n    private static final byte[] RPI5 =\n            asBytes(\n                    0x29, 0x8a, 0xbd, 0x6f, 0xda, 0xd2, 0x9e, 0xfb, 0xf0, 0xf8, 0x5a, 0x63, 0x95, 0x6c, 0xf1,\n                    0x88);\n    private static final byte[] AEM5 = asBytes(0xf7, 0xb9, 0x7e, 0x84);\n    private static final byte[] RPI6 =\n            asBytes(\n                    0x10, 0x5e, 0x82, 0x21, 0xdd, 0x60, 0x3d, 0x25, 0xb9, 0x4a, 0xba, 0x0c, 0x3c, 0xc8, 0xde,\n                    0xe1);\n    private static final byte[] AEM6 = asBytes(0xee, 0xab, 0xfd, 0xc7);\n    private static final byte[] RPI7 =\n            asBytes(\n                    0x98, 0x88, 0xca, 0x7e, 0x67, 0x38, 0xec, 0x4b, 0xc6, 0xe4, 0x20, 0xb2, 0x0f, 0x87, 0x8b,\n                    0x3a);\n    private static final byte[] AEM7 = asBytes(0x9f, 0x84, 0xa9, 0xa6);\n    private static final byte[] RPI8 =\n            asBytes(\n                    0x86, 0x94, 0xa7, 0x9a, 0xe9, 0x96, 0x71, 0xbe, 0x3f, 0x18, 0xaa, 0xf6, 0xb0, 0x90, 0x65,\n                    0x7a);\n    private static final byte[] AEM8 = asBytes(0xc1, 0x1a, 0xcb, 0x4d);\n    private static final byte[] RPI9 =\n            asBytes(\n                    0xb8, 0xcd, 0xe2, 0x8a, 0xd2, 0x0d, 0x1c, 0xd2, 0xfd, 0xd7, 0x36, 0x9d, 0xc0, 0xc6, 0xf7,\n                    0xc8);\n    private static final byte[] AEM9 = asBytes(0x1f, 0x8d, 0x53, 0xde);\n    private static final byte[] RPI10 =\n            asBytes(\n                    0xf6, 0x01, 0x23, 0xc6, 0x7b, 0xd2, 0xfc, 0x4b, 0x62, 0x00, 0x2b, 0x4b, 0x7d, 0x59, 0x5b,\n                    0xa6);\n    private static final byte[] AEM10 = asBytes(0xe0, 0xa7, 0xf9, 0xf2);\n    private static final byte[] RPI11 =\n            asBytes(\n                    0x8a, 0x84, 0xc8, 0x6e, 0x05, 0xf7, 0xa8, 0x77, 0x2a, 0xae, 0x7a, 0x80, 0x68, 0x6e, 0x1a,\n                    0x1c);\n    private static final byte[] AEM11 = asBytes(0xf4, 0xb7, 0xb0, 0x9d);\n    private static final byte[] RPI12 =\n            asBytes(\n                    0xac, 0x46, 0x1b, 0xf2, 0xb9, 0x3b, 0x0d, 0x90, 0x84, 0x17, 0x46, 0xf5, 0x1a, 0xde, 0xd6,\n                    0xc0);\n    private static final byte[] AEM12 = asBytes(0x73, 0x91, 0xdd, 0x64);\n    private static final byte[] RPI13 =\n            asBytes(\n                    0xf2, 0x56, 0x7e, 0xed, 0x0a, 0xa1, 0xcd, 0xf2, 0xcd, 0x3d, 0x0b, 0xd2, 0x82, 0x52, 0xf1,\n                    0x96);\n    private static final byte[] AEM13 = asBytes(0x12, 0x7d, 0xb0, 0x9e);\n    private static final byte[] RPI14 =\n            asBytes(\n                    0xa2, 0x55, 0x22, 0x5b, 0xaa, 0x9e, 0x37, 0xb7, 0x30, 0xa9, 0x5f, 0x99, 0x7a, 0x69, 0x72,\n                    0xf5);\n    private static final byte[] AEM14 = asBytes(0x43, 0x5e, 0xa5, 0x56);\n    private static final byte[] RPI15 =\n            asBytes(\n                    0x04, 0xcf, 0xae, 0xe4, 0x10, 0x21, 0xcb, 0x7d, 0x4d, 0x02, 0x0b, 0x30, 0x6b, 0x24, 0xbe,\n                    0xa8);\n    private static final byte[] AEM15 = asBytes(0xdc, 0x1f, 0x19, 0x06);\n    private static final byte[] RPI16 =\n            asBytes(\n                    0xf5, 0x37, 0x2b, 0xbc, 0x92, 0xf7, 0x80, 0x59, 0x64, 0x70, 0x1e, 0x87, 0x9b, 0x48, 0xd4,\n                    0x31);\n    private static final byte[] AEM16 = asBytes(0xb3, 0xea, 0xaf, 0xdd);\n    private static final byte[] RPI17 =\n            asBytes(\n                    0xf2, 0xc8, 0x11, 0x54, 0x63, 0x82, 0xb1, 0x0d, 0xf1, 0xac, 0x06, 0xc3, 0x2c, 0x61, 0x7b,\n                    0xa7);\n    private static final byte[] AEM17 = asBytes(0xcd, 0x51, 0x86, 0xf9);\n    private static final byte[] RPI18 =\n            asBytes(\n                    0xf8, 0xf3, 0x44, 0x1f, 0x76, 0x22, 0x3d, 0xac, 0x15, 0xec, 0x6b, 0x35, 0xfd, 0xb2, 0x51,\n                    0x40);\n    private static final byte[] AEM18 = asBytes(0x7f, 0x38, 0x7e, 0x7f);\n    private static final byte[] RPI19 =\n            asBytes(\n                    0xd0, 0x71, 0x83, 0xdb, 0x3c, 0x80, 0x45, 0x08, 0x7d, 0x61, 0xee, 0x9e, 0x73, 0x0c, 0x93,\n                    0x06);\n    private static final byte[] AEM19 = asBytes(0x1a, 0x42, 0xa1, 0x5b);\n    private static final byte[] RPI20 =\n            asBytes(\n                    0xc7, 0x42, 0xdd, 0x9c, 0x96, 0xa3, 0xe6, 0xfa, 0x7c, 0x4f, 0x22, 0x62, 0x1d, 0xac, 0xc2,\n                    0x4d);\n    private static final byte[] AEM20 = asBytes(0x06, 0x39, 0x0d, 0xed);\n    private static final byte[] RPI21 =\n            asBytes(\n                    0x08, 0x23, 0x33, 0xfa, 0xd9, 0xfa, 0x29, 0x2a, 0xb8, 0x99, 0xd6, 0x00, 0x0c, 0x65, 0x97,\n                    0x97);\n    private static final byte[] AEM21 = asBytes(0x0f, 0x01, 0xbc, 0xd7);\n    private static final byte[] RPI22 =\n            asBytes(\n                    0xbe, 0x43, 0x00, 0xda, 0xfb, 0x8d, 0x07, 0xc8, 0x8c, 0xb2, 0xb5, 0x07, 0x7a, 0x06, 0x11,\n                    0x66);\n    private static final byte[] AEM22 = asBytes(0xc7, 0xbf, 0xbb, 0x92);\n    private static final byte[] RPI23 =\n            asBytes(\n                    0x5f, 0xed, 0x1b, 0x4d, 0x3b, 0x3a, 0x13, 0x33, 0x2f, 0x05, 0x44, 0x75, 0x60, 0x35, 0x26,\n                    0x32);\n    private static final byte[] AEM23 = asBytes(0x21, 0x7c, 0x8e, 0x4a);\n    private static final byte[] RPI24 =\n            asBytes(\n                    0xfd, 0x1e, 0xe2, 0xcc, 0x5c, 0x60, 0xe6, 0xee, 0xe6, 0x1f, 0x04, 0x91, 0x9f, 0x67, 0x59,\n                    0xa7);\n    private static final byte[] AEM24 = asBytes(0xee, 0x63, 0x9b, 0xd6);\n    private static final byte[] RPI25 =\n            asBytes(\n                    0x96, 0xad, 0xf5, 0xb8, 0xdc, 0x7e, 0xe7, 0x5d, 0xf4, 0x6f, 0xbd, 0x8a, 0x1f, 0xc4, 0xad,\n                    0x0d);\n    private static final byte[] AEM25 = asBytes(0x60, 0x8c, 0x13, 0x0f);\n    private static final byte[] RPI26 =\n            asBytes(\n                    0xfa, 0x4b, 0xa2, 0x20, 0x6d, 0x42, 0xa1, 0xc8, 0x0d, 0x52, 0x48, 0xae, 0x68, 0x83, 0x09,\n                    0xa4);\n    private static final byte[] AEM26 = asBytes(0x74, 0xb2, 0xc8, 0x73);\n    private static final byte[] RPI27 =\n            asBytes(\n                    0xa5, 0x90, 0xf9, 0x5d, 0xbf, 0x24, 0x02, 0x61, 0xda, 0x10, 0x1a, 0x7c, 0xdb, 0x24, 0xdb,\n                    0xba);\n    private static final byte[] AEM27 = asBytes(0x95, 0x6a, 0x95, 0xeb);\n    private static final byte[] RPI28 =\n            asBytes(\n                    0x67, 0xe8, 0x1b, 0x91, 0xd1, 0xcf, 0x9e, 0x09, 0x58, 0x13, 0x54, 0x29, 0xda, 0xd0, 0x1e,\n                    0x82);\n    private static final byte[] AEM28 = asBytes(0xc6, 0xfa, 0x3c, 0x7a);\n    private static final byte[] RPI29 =\n            asBytes(\n                    0x18, 0x3c, 0xac, 0x22, 0x36, 0xc3, 0xe0, 0x53, 0x3b, 0xe4, 0x70, 0x4d, 0x83, 0x6e, 0x47,\n                    0x55);\n    private static final byte[] AEM29 = asBytes(0xa2, 0xab, 0xc7, 0x03);\n    private static final byte[] RPI30 =\n            asBytes(\n                    0x34, 0x11, 0x62, 0x55, 0x1c, 0x29, 0x31, 0x9b, 0xc5, 0x35, 0x38, 0xed, 0xfc, 0xf2, 0x30,\n                    0x40);\n    private static final byte[] AEM30 = asBytes(0x80, 0x09, 0xb2, 0xaa);\n    private static final byte[] RPI31 =\n            asBytes(\n                    0x22, 0x51, 0x68, 0x70, 0x18, 0x21, 0x4b, 0x65, 0xdd, 0x8e, 0xe8, 0x3e, 0xae, 0xd3, 0x30,\n                    0xab);\n    private static final byte[] AEM31 = asBytes(0xcf, 0xe8, 0x04, 0xcb);\n    private static final byte[] RPI32 =\n            asBytes(\n                    0xa4, 0xcf, 0x6e, 0x50, 0x21, 0x5f, 0xe2, 0x78, 0xcc, 0x5c, 0xff, 0x1b, 0x05, 0x34, 0xa3,\n                    0xe0);\n    private static final byte[] AEM32 = asBytes(0xcb, 0x2a, 0x7e, 0x22);\n    private static final byte[] RPI33 =\n            asBytes(\n                    0xdf, 0x8f, 0x2a, 0xc3, 0x03, 0x23, 0x2b, 0x2e, 0x5b, 0x3e, 0xfd, 0x86, 0x81, 0xaa, 0xa8,\n                    0xdd);\n    private static final byte[] AEM33 = asBytes(0x65, 0x03, 0xa7, 0x27);\n    private static final byte[] RPI34 =\n            asBytes(\n                    0xba, 0x2e, 0x75, 0xd7, 0xf4, 0x8c, 0xf5, 0x5c, 0x0c, 0x86, 0x8f, 0xd4, 0x5c, 0xf1, 0x6b,\n                    0x5c);\n    private static final byte[] AEM34 = asBytes(0x8f, 0x29, 0x78, 0x7e);\n    private static final byte[] RPI35 =\n            asBytes(\n                    0xec, 0x6a, 0x40, 0x05, 0x8d, 0xeb, 0xff, 0xff, 0x3c, 0x51, 0x97, 0x7f, 0x24, 0x56, 0x2e,\n                    0x21);\n    private static final byte[] AEM35 = asBytes(0xb2, 0xad, 0xd3, 0xb7);\n    private static final byte[] RPI36 =\n            asBytes(\n                    0x6a, 0x68, 0xe3, 0x0b, 0x2f, 0xb9, 0x3b, 0x5d, 0xf7, 0x8e, 0xe3, 0xa9, 0xa3, 0x50, 0xa6,\n                    0xce);\n    private static final byte[] AEM36 = asBytes(0x1b, 0xfb, 0x46, 0x0a);\n    private static final byte[] RPI37 =\n            asBytes(\n                    0x8d, 0x33, 0xa7, 0x05, 0x62, 0x62, 0x99, 0x94, 0xf8, 0xdf, 0x99, 0x05, 0x2b, 0x0e, 0xb6,\n                    0x9a);\n    private static final byte[] AEM37 = asBytes(0x8e, 0xcf, 0x07, 0x7b);\n    private static final byte[] RPI38 =\n            asBytes(\n                    0x21, 0x05, 0x3c, 0xcb, 0x8f, 0x92, 0x51, 0x11, 0xe2, 0x54, 0xbd, 0x69, 0x4e, 0x97, 0x94,\n                    0x6b);\n    private static final byte[] AEM38 = asBytes(0x2b, 0xa7, 0x7b, 0x38);\n    private static final byte[] RPI39 =\n            asBytes(\n                    0xe1, 0xc9, 0xcd, 0xf2, 0x0f, 0x90, 0x0a, 0xe6, 0xd2, 0x4b, 0xf7, 0xbc, 0xb4, 0xe6, 0x61,\n                    0x35);\n    private static final byte[] AEM39 = asBytes(0x8c, 0x12, 0x40, 0xde);\n    private static final byte[] RPI40 =\n            asBytes(\n                    0xba, 0xf7, 0x89, 0xf5, 0x50, 0x94, 0x6b, 0x43, 0x10, 0x64, 0x45, 0x07, 0x71, 0xb2, 0xa1,\n                    0x43);\n    private static final byte[] AEM40 = asBytes(0x43, 0x89, 0x99, 0xb6);\n    private static final byte[] RPI41 =\n            asBytes(\n                    0xf7, 0xf9, 0x1e, 0xc2, 0x50, 0x85, 0xd0, 0x35, 0x3e, 0x02, 0x78, 0xe5, 0x98, 0xcc, 0x62,\n                    0x01);\n    private static final byte[] AEM41 = asBytes(0x1d, 0xcb, 0xdc, 0x6e);\n    private static final byte[] RPI42 =\n            asBytes(\n                    0xc8, 0x93, 0x3d, 0x70, 0x22, 0x0b, 0xa9, 0xc8, 0xc1, 0x48, 0x39, 0x3a, 0x39, 0x59, 0xd2,\n                    0x56);\n    private static final byte[] AEM42 = asBytes(0x63, 0x85, 0xff, 0xda);\n    private static final byte[] RPI43 =\n            asBytes(\n                    0xf2, 0x93, 0x2e, 0x6e, 0x6e, 0xf6, 0x0f, 0x0f, 0x5b, 0xbc, 0xe4, 0x39, 0x10, 0x0a, 0x90,\n                    0xe4);\n    private static final byte[] AEM43 = asBytes(0x69, 0x6c, 0x0c, 0xdf);\n    private static final byte[] RPI44 =\n            asBytes(\n                    0x18, 0xf5, 0xd8, 0x10, 0x2a, 0x59, 0x30, 0xd8, 0x02, 0x30, 0xf2, 0xc3, 0x9a, 0x42, 0x66,\n                    0xd6);\n    private static final byte[] AEM44 = asBytes(0x63, 0x84, 0x2b, 0xba);\n    private static final byte[] RPI45 =\n            asBytes(\n                    0xe6, 0x07, 0x5c, 0x28, 0x93, 0x9f, 0xb0, 0xc6, 0x72, 0x46, 0xce, 0x38, 0xc5, 0xff, 0x93,\n                    0x8a);\n    private static final byte[] AEM45 = asBytes(0xb7, 0xe2, 0x2c, 0x60);\n    private static final byte[] RPI46 =\n            asBytes(\n                    0x66, 0x16, 0x88, 0x62, 0xbc, 0x44, 0x5f, 0x48, 0xe5, 0xb0, 0xed, 0x07, 0xe1, 0xdf, 0x3f,\n                    0x5a);\n    private static final byte[] AEM46 = asBytes(0xd2, 0xe7, 0xd6, 0xd8);\n    private static final byte[] RPI47 =\n            asBytes(\n                    0x1d, 0x0a, 0x01, 0xc3, 0x8d, 0xa4, 0xac, 0x41, 0xec, 0x7a, 0x63, 0x8f, 0x5d, 0xf7, 0x05,\n                    0xa9);\n    private static final byte[] AEM47 = asBytes(0x91, 0xbe, 0x92, 0x2c);\n    private static final byte[] RPI48 =\n            asBytes(\n                    0xa7, 0x37, 0x00, 0x1a, 0x2d, 0x2f, 0x80, 0x2c, 0x64, 0x78, 0x9a, 0x99, 0x52, 0xe6, 0xd1,\n                    0xa7);\n    private static final byte[] AEM48 = asBytes(0x7e, 0x04, 0x21, 0xbb);\n    private static final byte[] RPI49 =\n            asBytes(\n                    0x7c, 0x37, 0x25, 0xb6, 0x08, 0x4e, 0x68, 0x1f, 0xb3, 0x4d, 0x26, 0xc3, 0xa3, 0x94, 0xa6,\n                    0x43);\n    private static final byte[] AEM49 = asBytes(0x7e, 0xa5, 0x20, 0x9f);\n    private static final byte[] RPI50 =\n            asBytes(\n                    0x26, 0xd1, 0xf8, 0x36, 0x55, 0x7a, 0x25, 0x9a, 0x81, 0xb5, 0xdb, 0x54, 0x19, 0xc6, 0xa7,\n                    0x29);\n    private static final byte[] AEM50 = asBytes(0x1c, 0x92, 0x06, 0x28);\n    private static final byte[] RPI51 =\n            asBytes(\n                    0xeb, 0xc2, 0xa6, 0x06, 0x28, 0x54, 0xd1, 0xec, 0x62, 0x7b, 0x1f, 0x6e, 0x84, 0x32, 0xe1,\n                    0x66);\n    private static final byte[] AEM51 = asBytes(0x4a, 0x76, 0x46, 0x32);\n    private static final byte[] RPI52 =\n            asBytes(\n                    0x11, 0x32, 0x74, 0xe8, 0x0c, 0x31, 0xcf, 0xcd, 0x81, 0xc2, 0xad, 0x08, 0x64, 0x44, 0x51,\n                    0x78);\n    private static final byte[] AEM52 = asBytes(0x69, 0xa7, 0x49, 0xb6);\n    private static final byte[] RPI53 =\n            asBytes(\n                    0x45, 0x67, 0x97, 0x6c, 0x48, 0xbe, 0x72, 0x59, 0x06, 0x24, 0x7d, 0x0b, 0xd8, 0x1b, 0xb8,\n                    0x11);\n    private static final byte[] AEM53 = asBytes(0x6f, 0x94, 0x85, 0xdb);\n    private static final byte[] RPI54 =\n            asBytes(\n                    0x74, 0x81, 0x54, 0xba, 0x52, 0x3a, 0x1a, 0xa8, 0x10, 0xb7, 0x06, 0x2a, 0x13, 0xe5, 0xaa,\n                    0x68);\n    private static final byte[] AEM54 = asBytes(0x74, 0x78, 0x07, 0x23);\n    private static final byte[] RPI55 =\n            asBytes(\n                    0x30, 0xbc, 0xeb, 0x33, 0x45, 0x74, 0x51, 0x53, 0x35, 0x23, 0x65, 0x99, 0x85, 0x87, 0xcd,\n                    0x10);\n    private static final byte[] AEM55 = asBytes(0x89, 0x17, 0xda, 0x61);\n    private static final byte[] RPI56 =\n            asBytes(\n                    0x8f, 0x2d, 0x7b, 0x87, 0x00, 0xa8, 0x2f, 0xd4, 0x51, 0x4d, 0xfa, 0x42, 0x02, 0xee, 0x29,\n                    0x8f);\n    private static final byte[] AEM56 = asBytes(0xfe, 0xc4, 0xf8, 0xb1);\n    private static final byte[] RPI57 =\n            asBytes(\n                    0x0e, 0x66, 0x49, 0x53, 0x70, 0x0c, 0xdf, 0xc0, 0xd2, 0x79, 0x2f, 0xad, 0xf0, 0x73, 0x29,\n                    0xeb);\n    private static final byte[] AEM57 = asBytes(0x78, 0x1a, 0x3e, 0xaf);\n    private static final byte[] RPI58 =\n            asBytes(\n                    0xf4, 0x49, 0x58, 0xc4, 0xdd, 0x70, 0xd9, 0x96, 0x8a, 0x26, 0xfd, 0x60, 0xba, 0x92, 0x72,\n                    0x90);\n    private static final byte[] AEM58 = asBytes(0xb9, 0x75, 0x9b, 0x61);\n    private static final byte[] RPI59 =\n            asBytes(\n                    0x55, 0xfd, 0x2f, 0x6c, 0xbd, 0xe0, 0xe1, 0x3f, 0xd2, 0x2c, 0x0b, 0x3d, 0xb1, 0x62, 0x28,\n                    0xe5);\n    private static final byte[] AEM59 = asBytes(0x48, 0x3c, 0x94, 0x10);\n    private static final byte[] RPI60 =\n            asBytes(\n                    0x49, 0xf3, 0xf9, 0xd1, 0x24, 0x69, 0xdc, 0xc9, 0xed, 0x35, 0x63, 0x64, 0xc3, 0x00, 0x66,\n                    0xe4);\n    private static final byte[] AEM60 = asBytes(0x2d, 0xa6, 0xeb, 0xac);\n    private static final byte[] RPI61 =\n            asBytes(\n                    0xc5, 0x7d, 0x2d, 0x6e, 0x0d, 0x25, 0xa0, 0x65, 0x1c, 0xd7, 0x27, 0x86, 0xf8, 0xc9, 0x51,\n                    0xce);\n    private static final byte[] AEM61 = asBytes(0x43, 0xea, 0xcf, 0x34);\n    private static final byte[] RPI62 =\n            asBytes(\n                    0x88, 0xef, 0x25, 0x63, 0x51, 0xac, 0x49, 0xdf, 0xd1, 0x5a, 0xb5, 0xa2, 0xde, 0x97, 0xc0,\n                    0x13);\n    private static final byte[] AEM62 = asBytes(0xb9, 0xa1, 0x36, 0x53);\n    private static final byte[] RPI63 =\n            asBytes(\n                    0xd0, 0xfb, 0x6f, 0xd6, 0xdb, 0x89, 0xda, 0x52, 0x36, 0x1f, 0x1a, 0x30, 0xfb, 0x43, 0x6c,\n                    0xe7);\n    private static final byte[] AEM63 = asBytes(0x35, 0x6d, 0xea, 0x55);\n    private static final byte[] RPI64 =\n            asBytes(\n                    0x8a, 0x42, 0xa3, 0x30, 0xf0, 0x19, 0x28, 0xe5, 0x16, 0x31, 0x23, 0x19, 0x81, 0x60, 0x3f,\n                    0xd5);\n    private static final byte[] AEM64 = asBytes(0x35, 0x05, 0xb7, 0xf3);\n    private static final byte[] RPI65 =\n            asBytes(\n                    0x6e, 0x51, 0xb2, 0xa2, 0xae, 0xcb, 0xab, 0x1d, 0xf8, 0x08, 0x26, 0xef, 0x6d, 0x1e, 0x19,\n                    0x58);\n    private static final byte[] AEM65 = asBytes(0x5c, 0x05, 0xcd, 0x94);\n    private static final byte[] RPI66 =\n            asBytes(\n                    0x3c, 0xe6, 0x81, 0xa2, 0x8b, 0x1b, 0xe1, 0x9c, 0x9e, 0x36, 0xb9, 0xc5, 0x80, 0xb1, 0x23,\n                    0xab);\n    private static final byte[] AEM66 = asBytes(0x98, 0x47, 0x45, 0xd6);\n    private static final byte[] RPI67 =\n            asBytes(\n                    0x1e, 0x95, 0x8e, 0xd8, 0x9b, 0x86, 0xb9, 0x89, 0x77, 0xf7, 0x9e, 0x1b, 0x83, 0xf3, 0xd0,\n                    0x5f);\n    private static final byte[] AEM67 = asBytes(0x93, 0xfd, 0xf7, 0x08);\n    private static final byte[] RPI68 =\n            asBytes(\n                    0x1d, 0x66, 0x7b, 0x01, 0xd6, 0x63, 0x4b, 0x5f, 0x3b, 0x6f, 0x33, 0xac, 0x4b, 0x15, 0x0d,\n                    0x23);\n    private static final byte[] AEM68 = asBytes(0xd7, 0x0f, 0x74, 0x4c);\n    private static final byte[] RPI69 =\n            asBytes(\n                    0x67, 0xf2, 0x22, 0x15, 0x6c, 0x51, 0x7d, 0xeb, 0xc0, 0x70, 0x68, 0xcb, 0xc5, 0xee, 0xc1,\n                    0xdd);\n    private static final byte[] AEM69 = asBytes(0x60, 0x57, 0x8c, 0x31);\n    private static final byte[] RPI70 =\n            asBytes(\n                    0xa8, 0x45, 0x4b, 0x9c, 0x94, 0x7d, 0x16, 0x25, 0xee, 0x3f, 0xba, 0x26, 0x07, 0xc2, 0x3a,\n                    0xff);\n    private static final byte[] AEM70 = asBytes(0x79, 0x00, 0xee, 0xad);\n    private static final byte[] RPI71 =\n            asBytes(\n                    0x41, 0x6f, 0xfc, 0x7a, 0x32, 0xfc, 0xfd, 0xa9, 0xa3, 0x16, 0xd0, 0x17, 0x90, 0xe3, 0x19,\n                    0x45);\n    private static final byte[] AEM71 = asBytes(0xc1, 0x22, 0xad, 0x68);\n    private static final byte[] RPI72 =\n            asBytes(\n                    0xc1, 0x9a, 0x30, 0xc3, 0x9c, 0x9c, 0x3a, 0x08, 0x9b, 0xca, 0xdd, 0xe1, 0xc6, 0x69, 0x94,\n                    0x47);\n    private static final byte[] AEM72 = asBytes(0x34, 0x0a, 0xa3, 0x82);\n    private static final byte[] RPI73 =\n            asBytes(\n                    0x78, 0x6d, 0xdf, 0xae, 0x6f, 0xc7, 0x7c, 0x4c, 0x41, 0x0c, 0x4e, 0xc3, 0x2d, 0x34, 0x24,\n                    0x7d);\n    private static final byte[] AEM73 = asBytes(0x67, 0xc6, 0x0d, 0xfb);\n    private static final byte[] RPI74 =\n            asBytes(\n                    0xef, 0x0f, 0xd3, 0xa9, 0x5b, 0x96, 0x61, 0xe1, 0xfc, 0xcb, 0x4e, 0x30, 0xcd, 0xe3, 0x2c,\n                    0x51);\n    private static final byte[] AEM74 = asBytes(0x45, 0x56, 0xb6, 0x73);\n    private static final byte[] RPI75 =\n            asBytes(\n                    0xfc, 0x1f, 0x8a, 0x66, 0xf4, 0x05, 0xcc, 0xb6, 0x3d, 0xc3, 0xe4, 0x82, 0x07, 0xda, 0x77,\n                    0x88);\n    private static final byte[] AEM75 = asBytes(0x9e, 0x4f, 0x1d, 0xb4);\n    private static final byte[] RPI76 =\n            asBytes(\n                    0x0e, 0xac, 0xc2, 0x86, 0x31, 0xb1, 0x0f, 0x44, 0x98, 0x36, 0x86, 0x66, 0x13, 0x0f, 0xf0,\n                    0xc9);\n    private static final byte[] AEM76 = asBytes(0x5b, 0xe0, 0x4e, 0x9d);\n    private static final byte[] RPI77 =\n            asBytes(\n                    0xe8, 0xdb, 0x4a, 0x46, 0x26, 0x38, 0x5a, 0xe6, 0xe3, 0xb2, 0x45, 0x1d, 0x0a, 0x66, 0xed,\n                    0xbf);\n    private static final byte[] AEM77 = asBytes(0x80, 0x6a, 0xf2, 0xf9);\n    private static final byte[] RPI78 =\n            asBytes(\n                    0xc6, 0x00, 0x67, 0x8d, 0x4f, 0xbe, 0x92, 0x45, 0xad, 0x49, 0x73, 0xb1, 0xc8, 0x97, 0x1b,\n                    0xc5);\n    private static final byte[] AEM78 = asBytes(0x7a, 0xf8, 0xd4, 0xfd);\n    private static final byte[] RPI79 =\n            asBytes(\n                    0x08, 0x19, 0x26, 0xc3, 0x61, 0x83, 0x4c, 0x5c, 0x1d, 0x43, 0x19, 0xb8, 0x40, 0xf3, 0x15,\n                    0xae);\n    private static final byte[] AEM79 = asBytes(0xfc, 0x8d, 0xdd, 0xd0);\n    private static final byte[] RPI80 =\n            asBytes(\n                    0x1d, 0x82, 0x9e, 0xaf, 0xa0, 0x42, 0x32, 0xa6, 0xbb, 0x4d, 0x3c, 0x20, 0x22, 0xac, 0x3d,\n                    0x0f);\n    private static final byte[] AEM80 = asBytes(0xda, 0x88, 0x15, 0x68);\n    private static final byte[] RPI81 =\n            asBytes(\n                    0x79, 0x8a, 0xbc, 0xe8, 0xc8, 0xf6, 0x25, 0x10, 0xde, 0x59, 0x5a, 0x99, 0x73, 0xfb, 0x21,\n                    0x8e);\n    private static final byte[] AEM81 = asBytes(0x13, 0x95, 0xcf, 0x7b);\n    private static final byte[] RPI82 =\n            asBytes(\n                    0x61, 0xfc, 0x0d, 0xeb, 0x47, 0x08, 0x4f, 0xda, 0xf1, 0x48, 0x3e, 0x34, 0x2d, 0x73, 0xb1,\n                    0x48);\n    private static final byte[] AEM82 = asBytes(0xd9, 0xe2, 0x5d, 0xb6);\n    private static final byte[] RPI83 =\n            asBytes(\n                    0x49, 0x69, 0xed, 0xd4, 0x0f, 0x3e, 0xab, 0x46, 0x8b, 0x8a, 0x8d, 0x49, 0x68, 0x5a, 0x4e,\n                    0xdd);\n    private static final byte[] AEM83 = asBytes(0xc1, 0xb2, 0x05, 0x97);\n    private static final byte[] RPI84 =\n            asBytes(\n                    0x1d, 0x69, 0xd6, 0xd4, 0x15, 0x8a, 0x31, 0x8f, 0x1d, 0x9c, 0xaf, 0xba, 0x13, 0x58, 0x70,\n                    0x17);\n    private static final byte[] AEM84 = asBytes(0xeb, 0x53, 0x91, 0x99);\n    private static final byte[] RPI85 =\n            asBytes(\n                    0xab, 0x7c, 0x61, 0xf1, 0xcc, 0xa8, 0x13, 0xfd, 0x36, 0xe8, 0xf1, 0xb1, 0xe5, 0xdf, 0x6a,\n                    0x0f);\n    private static final byte[] AEM85 = asBytes(0xc8, 0x1a, 0xb8, 0x54);\n    private static final byte[] RPI86 =\n            asBytes(\n                    0x94, 0xf2, 0x4f, 0xde, 0xc1, 0x7a, 0xa3, 0x1f, 0x74, 0xf2, 0x02, 0xae, 0x4a, 0x68, 0x74,\n                    0xbe);\n    private static final byte[] AEM86 = asBytes(0x46, 0xee, 0x82, 0xdc);\n    private static final byte[] RPI87 =\n            asBytes(\n                    0x6e, 0x5d, 0xe0, 0x25, 0x79, 0xd3, 0xdf, 0xb1, 0x94, 0xcc, 0x7b, 0xd4, 0x92, 0x70, 0x25,\n                    0x3d);\n    private static final byte[] AEM87 = asBytes(0x8a, 0x05, 0x28, 0xbd);\n    private static final byte[] RPI88 =\n            asBytes(\n                    0xfe, 0x3e, 0x1e, 0x36, 0x21, 0x77, 0x3f, 0x18, 0x80, 0x40, 0xaa, 0x5d, 0xb3, 0xff, 0x1d,\n                    0x4e);\n    private static final byte[] AEM88 = asBytes(0x28, 0x03, 0x3a, 0xae);\n    private static final byte[] RPI89 =\n            asBytes(\n                    0xd7, 0x37, 0x6e, 0x0d, 0x77, 0x25, 0x5d, 0xe2, 0x3d, 0x54, 0x0f, 0x02, 0x71, 0x83, 0xf1,\n                    0xba);\n    private static final byte[] AEM89 = asBytes(0xa0, 0x1c, 0xe7, 0x12);\n    private static final byte[] RPI90 =\n            asBytes(\n                    0x64, 0xa7, 0x1e, 0x48, 0xa5, 0x0e, 0x7b, 0x5a, 0x37, 0xac, 0x91, 0x81, 0x6e, 0x2b, 0x0f,\n                    0x53);\n    private static final byte[] AEM90 = asBytes(0xc9, 0xcb, 0x8c, 0x70);\n    private static final byte[] RPI91 =\n            asBytes(\n                    0x0f, 0x22, 0xa2, 0xc0, 0xb6, 0x99, 0xe1, 0x89, 0xd5, 0x9e, 0x30, 0xd1, 0x74, 0x5d, 0x67,\n                    0xd3);\n    private static final byte[] AEM91 = asBytes(0xdb, 0xe6, 0x8f, 0x47);\n    private static final byte[] RPI92 =\n            asBytes(\n                    0xde, 0x87, 0x6b, 0xaf, 0x31, 0x22, 0x8e, 0x3b, 0x7f, 0xe0, 0xf0, 0x8e, 0x1f, 0x38, 0xea,\n                    0x7b);\n    private static final byte[] AEM92 = asBytes(0x4c, 0xb1, 0xd9, 0x4f);\n    private static final byte[] RPI93 =\n            asBytes(\n                    0x8c, 0x69, 0x27, 0xbc, 0xf5, 0xf7, 0xae, 0xe1, 0xee, 0xd8, 0xab, 0xbe, 0x43, 0xe2, 0xe2,\n                    0xd1);\n    private static final byte[] AEM93 = asBytes(0x27, 0x74, 0x06, 0x32);\n    private static final byte[] RPI94 =\n            asBytes(\n                    0xbc, 0x96, 0x83, 0x0f, 0x18, 0x2a, 0x72, 0xc8, 0x9e, 0x65, 0xce, 0xa9, 0xc4, 0x7d, 0x88,\n                    0xc0);\n    private static final byte[] AEM94 = asBytes(0xe8, 0xad, 0xeb, 0x6d);\n    private static final byte[] RPI95 =\n            asBytes(\n                    0x7b, 0x2f, 0xbe, 0x74, 0x6d, 0xd2, 0xda, 0x86, 0xe9, 0x86, 0x6a, 0x0e, 0x6a, 0xad, 0xbc,\n                    0x4d);\n    private static final byte[] AEM95 = asBytes(0xe5, 0x3a, 0x5a, 0xc7);\n    private static final byte[] RPI96 =\n            asBytes(\n                    0x93, 0xe2, 0x0f, 0x14, 0xa1, 0x3d, 0x56, 0x56, 0x75, 0x94, 0xaa, 0x96, 0x23, 0x50, 0xf1,\n                    0x70);\n    private static final byte[] AEM96 = asBytes(0x94, 0x32, 0x42, 0xa4);\n    private static final byte[] RPI97 =\n            asBytes(\n                    0x9e, 0x38, 0x14, 0xf9, 0x51, 0xfa, 0x03, 0x79, 0x6b, 0x9a, 0x66, 0xf8, 0x9a, 0x9f, 0x40,\n                    0x0d);\n    private static final byte[] AEM97 = asBytes(0x06, 0x48, 0xdc, 0x89);\n    private static final byte[] RPI98 =\n            asBytes(\n                    0x95, 0xfa, 0x09, 0x84, 0x5a, 0xa8, 0xd4, 0xb6, 0x00, 0x47, 0xfa, 0xf9, 0x9a, 0xeb, 0xca,\n                    0x0c);\n    private static final byte[] AEM98 = asBytes(0x85, 0x5e, 0x31, 0xb3);\n    private static final byte[] RPI99 =\n            asBytes(\n                    0xef, 0x0a, 0x75, 0x79, 0x33, 0x18, 0x53, 0xb9, 0xeb, 0xc2, 0x50, 0xb4, 0xd6, 0xf3, 0xeb,\n                    0xcc);\n    private static final byte[] AEM99 = asBytes(0x9c, 0x1f, 0x07, 0xc2);\n    private static final byte[] RPI100 =\n            asBytes(\n                    0x7f, 0xe9, 0xa9, 0x0d, 0xe0, 0x0c, 0x9f, 0x07, 0x37, 0xd3, 0xb4, 0x5f, 0xda, 0x65, 0x11,\n                    0x15);\n    private static final byte[] AEM100 = asBytes(0x98, 0x4e, 0x1f, 0xf3);\n    private static final byte[] RPI101 =\n            asBytes(\n                    0x44, 0x3b, 0x7b, 0x5a, 0xb9, 0xa8, 0x6a, 0x1f, 0xee, 0x67, 0xe1, 0x8c, 0xb8, 0xc4, 0x07,\n                    0x64);\n    private static final byte[] AEM101 = asBytes(0xb3, 0xfb, 0xa7, 0xe1);\n    private static final byte[] RPI102 =\n            asBytes(\n                    0xe8, 0xa6, 0xfa, 0x9a, 0x5c, 0xa9, 0xfb, 0x06, 0x1c, 0x4c, 0xdb, 0xe2, 0x17, 0xc6, 0x1d,\n                    0x59);\n    private static final byte[] AEM102 = asBytes(0x3b, 0x6d, 0x9d, 0xe8);\n    private static final byte[] RPI103 =\n            asBytes(\n                    0x08, 0x7a, 0x08, 0x04, 0x06, 0x86, 0xfd, 0x63, 0x5e, 0xf3, 0x89, 0x75, 0x27, 0x41, 0xcc,\n                    0x1f);\n    private static final byte[] AEM103 = asBytes(0xf0, 0x85, 0x55, 0x1c);\n    private static final byte[] RPI104 =\n            asBytes(\n                    0x58, 0x7c, 0x04, 0x86, 0x64, 0x4c, 0xeb, 0x2d, 0x0b, 0x7e, 0xbd, 0xd3, 0x9d, 0xd3, 0xa8,\n                    0x60);\n    private static final byte[] AEM104 = asBytes(0x0a, 0x6b, 0x32, 0x6e);\n    private static final byte[] RPI105 =\n            asBytes(\n                    0xdd, 0x82, 0x7b, 0xa6, 0x0f, 0x8a, 0x35, 0xb1, 0xdd, 0x4e, 0x4c, 0xdf, 0xe4, 0x9c, 0x42,\n                    0x63);\n    private static final byte[] AEM105 = asBytes(0x81, 0xeb, 0x20, 0xe2);\n    private static final byte[] RPI106 =\n            asBytes(\n                    0xcf, 0x23, 0x40, 0x00, 0x08, 0x0a, 0x4e, 0x8d, 0xa8, 0xfe, 0xb5, 0x33, 0xaa, 0x59, 0x04,\n                    0xd3);\n    private static final byte[] AEM106 = asBytes(0x34, 0xd8, 0x6e, 0xe5);\n    private static final byte[] RPI107 =\n            asBytes(\n                    0xc5, 0x0f, 0xb1, 0xec, 0x3e, 0xf5, 0x4e, 0x91, 0x61, 0x78, 0xca, 0x9d, 0x56, 0xee, 0x4f,\n                    0x5c);\n    private static final byte[] AEM107 = asBytes(0xea, 0xea, 0xc3, 0xd2);\n    private static final byte[] RPI108 =\n            asBytes(\n                    0xd4, 0x5f, 0xde, 0x46, 0xf4, 0x67, 0xd7, 0x6e, 0xd2, 0x8d, 0xd4, 0xd2, 0x49, 0x6d, 0xcb,\n                    0x7f);\n    private static final byte[] AEM108 = asBytes(0xea, 0xa6, 0x4a, 0x8e);\n    private static final byte[] RPI109 =\n            asBytes(\n                    0xe9, 0xba, 0xf8, 0x1c, 0x96, 0x1f, 0x51, 0x0d, 0x08, 0xa6, 0x63, 0xc7, 0x52, 0x4f, 0x36,\n                    0xdf);\n    private static final byte[] AEM109 = asBytes(0x1e, 0x2c, 0xa3, 0x7b);\n    private static final byte[] RPI110 =\n            asBytes(\n                    0xe3, 0xb0, 0x2c, 0xc0, 0x31, 0xe1, 0x44, 0xfa, 0xe6, 0x1a, 0x38, 0x99, 0x50, 0x1b, 0x49,\n                    0x21);\n    private static final byte[] AEM110 = asBytes(0x44, 0xc0, 0xd7, 0x06);\n    private static final byte[] RPI111 =\n            asBytes(\n                    0xa7, 0x5e, 0xea, 0x58, 0x23, 0x2e, 0x73, 0x66, 0xce, 0xa1, 0xa0, 0xe7, 0x2d, 0xa0, 0xce,\n                    0xc5);\n    private static final byte[] AEM111 = asBytes(0x5a, 0x8c, 0x79, 0xb7);\n    private static final byte[] RPI112 =\n            asBytes(\n                    0x6a, 0xd7, 0x62, 0x1f, 0xe1, 0xda, 0x01, 0x39, 0xff, 0x8b, 0xad, 0x7f, 0x37, 0x9c, 0xab,\n                    0xf6);\n    private static final byte[] AEM112 = asBytes(0x27, 0x9f, 0x16, 0xb1);\n    private static final byte[] RPI113 =\n            asBytes(\n                    0x6f, 0xe2, 0xac, 0x45, 0xf6, 0x5c, 0x8a, 0xc6, 0x9f, 0xdc, 0x5e, 0xf7, 0xfa, 0x9f, 0xf7,\n                    0xf0);\n    private static final byte[] AEM113 = asBytes(0x4b, 0xd9, 0x07, 0xaa);\n    private static final byte[] RPI114 =\n            asBytes(\n                    0x2f, 0xbe, 0xc6, 0x8f, 0xd2, 0x7d, 0xdd, 0xdb, 0x42, 0x23, 0x04, 0x4e, 0xfc, 0x77, 0x98,\n                    0x51);\n    private static final byte[] AEM114 = asBytes(0x2d, 0xf6, 0xc5, 0xeb);\n    private static final byte[] RPI115 =\n            asBytes(\n                    0x32, 0xbf, 0x68, 0x8a, 0x7c, 0x83, 0x4b, 0xe1, 0xbf, 0xab, 0x7c, 0x8e, 0x0e, 0x58, 0x0a,\n                    0xdb);\n    private static final byte[] AEM115 = asBytes(0x66, 0x85, 0x2d, 0x43);\n    private static final byte[] RPI116 =\n            asBytes(\n                    0xda, 0xe3, 0xa7, 0xd8, 0xc6, 0x24, 0x27, 0xb0, 0x9c, 0x0e, 0x7b, 0xbf, 0x48, 0x9d, 0x34,\n                    0xbd);\n    private static final byte[] AEM116 = asBytes(0x83, 0x6d, 0x3b, 0x95);\n    private static final byte[] RPI117 =\n            asBytes(\n                    0x3c, 0x4b, 0x02, 0xbd, 0x5e, 0xd2, 0x8c, 0x67, 0x82, 0x9c, 0x97, 0x79, 0x10, 0x79, 0xaf,\n                    0xd2);\n    private static final byte[] AEM117 = asBytes(0x27, 0x35, 0xb9, 0x97);\n    private static final byte[] RPI118 =\n            asBytes(\n                    0xe2, 0xfa, 0xea, 0xc3, 0xdb, 0xd1, 0x50, 0xec, 0x8e, 0xa8, 0xe7, 0xb3, 0xe5, 0xbb, 0x84,\n                    0x54);\n    private static final byte[] AEM118 = asBytes(0xd7, 0x1f, 0x97, 0xc2);\n    private static final byte[] RPI119 =\n            asBytes(\n                    0x69, 0x94, 0x2a, 0x72, 0x13, 0xea, 0xf3, 0xc1, 0x4a, 0x69, 0x99, 0x6b, 0xa6, 0xc6, 0xbf,\n                    0xeb);\n    private static final byte[] AEM119 = asBytes(0x53, 0xbc, 0x4d, 0xb5);\n    private static final byte[] RPI120 =\n            asBytes(\n                    0x1c, 0x5c, 0x4d, 0xd2, 0x54, 0x52, 0xe9, 0x7d, 0xd1, 0x87, 0xdd, 0x7c, 0xe1, 0xd1, 0xee,\n                    0x81);\n    private static final byte[] AEM120 = asBytes(0x48, 0xa4, 0xd3, 0x79);\n    private static final byte[] RPI121 =\n            asBytes(\n                    0xfb, 0xf5, 0x60, 0x7a, 0x7c, 0x61, 0x2a, 0xce, 0xd1, 0x60, 0xe7, 0x55, 0xa9, 0x87, 0x26,\n                    0x2d);\n    private static final byte[] AEM121 = asBytes(0xb7, 0x8d, 0xc1, 0xf5);\n    private static final byte[] RPI122 =\n            asBytes(\n                    0x3e, 0x2d, 0xe1, 0x30, 0x70, 0xf2, 0x74, 0x43, 0xd9, 0xba, 0x3e, 0xb4, 0x3f, 0x9a, 0x71,\n                    0xea);\n    private static final byte[] AEM122 = asBytes(0x58, 0x21, 0x70, 0xca);\n    private static final byte[] RPI123 =\n            asBytes(\n                    0x8a, 0x12, 0xd2, 0x5f, 0x00, 0x6f, 0xab, 0x5a, 0x27, 0x07, 0xda, 0x9e, 0x6c, 0x4e, 0x96,\n                    0xbe);\n    private static final byte[] AEM123 = asBytes(0x93, 0x95, 0x94, 0xcc);\n    private static final byte[] RPI124 =\n            asBytes(\n                    0x6f, 0xd9, 0x8c, 0x22, 0xe2, 0x27, 0x83, 0x8e, 0x6f, 0x67, 0x36, 0x97, 0x64, 0x43, 0x77,\n                    0x25);\n    private static final byte[] AEM124 = asBytes(0xc1, 0x4f, 0x5b, 0x11);\n    private static final byte[] RPI125 =\n            asBytes(\n                    0x3d, 0xa2, 0x12, 0xae, 0xbd, 0xb7, 0x8b, 0xa8, 0x19, 0x80, 0x9d, 0x03, 0xc6, 0xcf, 0x56,\n                    0xe2);\n    private static final byte[] AEM125 = asBytes(0x30, 0x09, 0x12, 0xda);\n    private static final byte[] RPI126 =\n            asBytes(\n                    0x8c, 0x48, 0xda, 0x73, 0xe2, 0x9e, 0xff, 0xc9, 0xb7, 0x4b, 0xb0, 0x97, 0x09, 0x6e, 0x0a,\n                    0x0a);\n    private static final byte[] AEM126 = asBytes(0xce, 0x79, 0xc5, 0x0a);\n    private static final byte[] RPI127 =\n            asBytes(\n                    0xe5, 0x3c, 0x68, 0xb4, 0xb0, 0x1c, 0x68, 0xf3, 0x7e, 0x65, 0xa0, 0xdc, 0x8e, 0x67, 0xf4,\n                    0x5d);\n    private static final byte[] AEM127 = asBytes(0xe0, 0x4f, 0x38, 0x67);\n    private static final byte[] RPI128 =\n            asBytes(\n                    0x83, 0x31, 0xdd, 0xe6, 0x36, 0x4b, 0x11, 0x95, 0x27, 0xaf, 0x76, 0xfe, 0xe1, 0x7a, 0xab,\n                    0xcf);\n    private static final byte[] AEM128 = asBytes(0x64, 0x18, 0x7b, 0xdf);\n    private static final byte[] RPI129 =\n            asBytes(\n                    0x8c, 0x14, 0x47, 0x1f, 0x55, 0x71, 0x92, 0x63, 0x96, 0xdd, 0xe6, 0xf7, 0xb7, 0xb3, 0x5b,\n                    0x56);\n    private static final byte[] AEM129 = asBytes(0xe8, 0x7c, 0x05, 0xfd);\n    private static final byte[] RPI130 =\n            asBytes(\n                    0x4e, 0xb6, 0xb2, 0xde, 0xb4, 0x0e, 0x5e, 0xc9, 0xbc, 0x39, 0x83, 0x81, 0x02, 0xa4, 0xf4,\n                    0xf9);\n    private static final byte[] AEM130 = asBytes(0x4e, 0x70, 0x83, 0x25);\n    private static final byte[] RPI131 =\n            asBytes(\n                    0x77, 0xf2, 0x14, 0x1c, 0xef, 0xfd, 0x0a, 0xa3, 0xbe, 0xe4, 0xb6, 0x7c, 0x45, 0x0d, 0x9a,\n                    0xa6);\n    private static final byte[] AEM131 = asBytes(0xa1, 0x57, 0xeb, 0x59);\n    private static final byte[] RPI132 =\n            asBytes(\n                    0x04, 0x3d, 0x78, 0xe2, 0x0c, 0xb5, 0x9c, 0x0b, 0xcb, 0x15, 0x78, 0xff, 0x93, 0xea, 0x54,\n                    0x4a);\n    private static final byte[] AEM132 = asBytes(0x8d, 0x30, 0x43, 0x2a);\n    private static final byte[] RPI133 =\n            asBytes(\n                    0x65, 0xb8, 0xec, 0xc4, 0x56, 0x1c, 0x1c, 0xca, 0x05, 0x3d, 0x81, 0x4f, 0xfd, 0x89, 0x61,\n                    0xd4);\n    private static final byte[] AEM133 = asBytes(0x5b, 0x24, 0x38, 0x90);\n    private static final byte[] RPI134 =\n            asBytes(\n                    0x32, 0xf2, 0x5a, 0x17, 0x24, 0xf2, 0xbd, 0xca, 0xd0, 0x5a, 0xbc, 0x14, 0x82, 0xe1, 0x32,\n                    0x9e);\n    private static final byte[] AEM134 = asBytes(0x74, 0x90, 0xd2, 0x11);\n    private static final byte[] RPI135 =\n            asBytes(\n                    0x20, 0x3b, 0xa3, 0xf3, 0xf7, 0x23, 0x02, 0x66, 0xb9, 0x93, 0xb3, 0xee, 0x7b, 0x2d, 0x86,\n                    0x08);\n    private static final byte[] AEM135 = asBytes(0x1f, 0x01, 0x9d, 0xf2);\n    private static final byte[] RPI136 =\n            asBytes(\n                    0xe5, 0xe7, 0xa4, 0x70, 0x69, 0x21, 0x6e, 0x1a, 0x88, 0x7b, 0x90, 0xef, 0x03, 0x94, 0xa3,\n                    0x5c);\n    private static final byte[] AEM136 = asBytes(0x99, 0xe6, 0x12, 0xb7);\n    private static final byte[] RPI137 =\n            asBytes(\n                    0x3f, 0xfc, 0x8b, 0xb9, 0x1d, 0xbc, 0xd8, 0xee, 0x92, 0x49, 0x48, 0xf5, 0x08, 0x0b, 0x19,\n                    0x0d);\n    private static final byte[] AEM137 = asBytes(0x26, 0x4a, 0x57, 0x7e);\n    private static final byte[] RPI138 =\n            asBytes(\n                    0x32, 0x37, 0x53, 0x91, 0x07, 0x7f, 0xbf, 0x76, 0x86, 0xba, 0xfa, 0x7d, 0xc1, 0x56, 0xbe,\n                    0x1c);\n    private static final byte[] AEM138 = asBytes(0xa8, 0x11, 0xba, 0x62);\n    private static final byte[] RPI139 =\n            asBytes(\n                    0xa8, 0x90, 0x49, 0x65, 0xae, 0xc5, 0xdd, 0xb6, 0x55, 0xe9, 0x70, 0x07, 0xd2, 0x23, 0xdb,\n                    0x48);\n    private static final byte[] AEM139 = asBytes(0x2b, 0x48, 0x33, 0x21);\n    private static final byte[] RPI140 =\n            asBytes(\n                    0x41, 0x5c, 0xf7, 0xaf, 0x1d, 0xc9, 0xfe, 0xac, 0xb3, 0x97, 0x84, 0x88, 0xf5, 0x04, 0x68,\n                    0x93);\n    private static final byte[] AEM140 = asBytes(0xe2, 0xef, 0x53, 0x7e);\n    private static final byte[] RPI141 =\n            asBytes(\n                    0x86, 0xf8, 0xdd, 0xc0, 0xc9, 0x3e, 0x53, 0xe3, 0xa5, 0x82, 0xe6, 0x1f, 0x01, 0xf7, 0xdf,\n                    0x2f);\n    private static final byte[] AEM141 = asBytes(0x71, 0x1d, 0xbf, 0x6d);\n    private static final byte[] RPI142 =\n            asBytes(\n                    0xa6, 0x5e, 0xf7, 0xba, 0x97, 0x52, 0xc4, 0x17, 0x3b, 0xa4, 0x8a, 0x33, 0x84, 0x9c, 0x5e,\n                    0x52);\n    private static final byte[] AEM142 = asBytes(0x59, 0x2d, 0xbc, 0xa8);\n    private static final byte[] RPI143 =\n            asBytes(\n                    0xf4, 0x31, 0xb6, 0x2e, 0xcf, 0x44, 0x31, 0x02, 0xce, 0x4e, 0xd0, 0x40, 0x7d, 0xe5, 0x4b,\n                    0xd4);\n    private static final byte[] AEM143 = asBytes(0x12, 0x15, 0xe5, 0x7e);\n    // ------------------------------------------------------------------------------\n\n    public static final List<AdvertisedData> ADVERTISED_DATA =\n            Collections.unmodifiableList(Arrays.asList(\n                    new AdvertisedData(RPI0, AEM0),\n                    new AdvertisedData(RPI1, AEM1),\n                    new AdvertisedData(RPI2, AEM2),\n                    new AdvertisedData(RPI3, AEM3),\n                    new AdvertisedData(RPI4, AEM4),\n                    new AdvertisedData(RPI5, AEM5),\n                    new AdvertisedData(RPI6, AEM6),\n                    new AdvertisedData(RPI7, AEM7),\n                    new AdvertisedData(RPI8, AEM8),\n                    new AdvertisedData(RPI9, AEM9),\n                    new AdvertisedData(RPI10, AEM10),\n                    new AdvertisedData(RPI11, AEM11),\n                    new AdvertisedData(RPI12, AEM12),\n                    new AdvertisedData(RPI13, AEM13),\n                    new AdvertisedData(RPI14, AEM14),\n                    new AdvertisedData(RPI15, AEM15),\n                    new AdvertisedData(RPI16, AEM16),\n                    new AdvertisedData(RPI17, AEM17),\n                    new AdvertisedData(RPI18, AEM18),\n                    new AdvertisedData(RPI19, AEM19),\n                    new AdvertisedData(RPI20, AEM20),\n                    new AdvertisedData(RPI21, AEM21),\n                    new AdvertisedData(RPI22, AEM22),\n                    new AdvertisedData(RPI23, AEM23),\n                    new AdvertisedData(RPI24, AEM24),\n                    new AdvertisedData(RPI25, AEM25),\n                    new AdvertisedData(RPI26, AEM26),\n                    new AdvertisedData(RPI27, AEM27),\n                    new AdvertisedData(RPI28, AEM28),\n                    new AdvertisedData(RPI29, AEM29),\n                    new AdvertisedData(RPI30, AEM30),\n                    new AdvertisedData(RPI31, AEM31),\n                    new AdvertisedData(RPI32, AEM32),\n                    new AdvertisedData(RPI33, AEM33),\n                    new AdvertisedData(RPI34, AEM34),\n                    new AdvertisedData(RPI35, AEM35),\n                    new AdvertisedData(RPI36, AEM36),\n                    new AdvertisedData(RPI37, AEM37),\n                    new AdvertisedData(RPI38, AEM38),\n                    new AdvertisedData(RPI39, AEM39),\n                    new AdvertisedData(RPI40, AEM40),\n                    new AdvertisedData(RPI41, AEM41),\n                    new AdvertisedData(RPI42, AEM42),\n                    new AdvertisedData(RPI43, AEM43),\n                    new AdvertisedData(RPI44, AEM44),\n                    new AdvertisedData(RPI45, AEM45),\n                    new AdvertisedData(RPI46, AEM46),\n                    new AdvertisedData(RPI47, AEM47),\n                    new AdvertisedData(RPI48, AEM48),\n                    new AdvertisedData(RPI49, AEM49),\n                    new AdvertisedData(RPI50, AEM50),\n                    new AdvertisedData(RPI51, AEM51),\n                    new AdvertisedData(RPI52, AEM52),\n                    new AdvertisedData(RPI53, AEM53),\n                    new AdvertisedData(RPI54, AEM54),\n                    new AdvertisedData(RPI55, AEM55),\n                    new AdvertisedData(RPI56, AEM56),\n                    new AdvertisedData(RPI57, AEM57),\n                    new AdvertisedData(RPI58, AEM58),\n                    new AdvertisedData(RPI59, AEM59),\n                    new AdvertisedData(RPI60, AEM60),\n                    new AdvertisedData(RPI61, AEM61),\n                    new AdvertisedData(RPI62, AEM62),\n                    new AdvertisedData(RPI63, AEM63),\n                    new AdvertisedData(RPI64, AEM64),\n                    new AdvertisedData(RPI65, AEM65),\n                    new AdvertisedData(RPI66, AEM66),\n                    new AdvertisedData(RPI67, AEM67),\n                    new AdvertisedData(RPI68, AEM68),\n                    new AdvertisedData(RPI69, AEM69),\n                    new AdvertisedData(RPI70, AEM70),\n                    new AdvertisedData(RPI71, AEM71),\n                    new AdvertisedData(RPI72, AEM72),\n                    new AdvertisedData(RPI73, AEM73),\n                    new AdvertisedData(RPI74, AEM74),\n                    new AdvertisedData(RPI75, AEM75),\n                    new AdvertisedData(RPI76, AEM76),\n                    new AdvertisedData(RPI77, AEM77),\n                    new AdvertisedData(RPI78, AEM78),\n                    new AdvertisedData(RPI79, AEM79),\n                    new AdvertisedData(RPI80, AEM80),\n                    new AdvertisedData(RPI81, AEM81),\n                    new AdvertisedData(RPI82, AEM82),\n                    new AdvertisedData(RPI83, AEM83),\n                    new AdvertisedData(RPI84, AEM84),\n                    new AdvertisedData(RPI85, AEM85),\n                    new AdvertisedData(RPI86, AEM86),\n                    new AdvertisedData(RPI87, AEM87),\n                    new AdvertisedData(RPI88, AEM88),\n                    new AdvertisedData(RPI89, AEM89),\n                    new AdvertisedData(RPI90, AEM90),\n                    new AdvertisedData(RPI91, AEM91),\n                    new AdvertisedData(RPI92, AEM92),\n                    new AdvertisedData(RPI93, AEM93),\n                    new AdvertisedData(RPI94, AEM94),\n                    new AdvertisedData(RPI95, AEM95),\n                    new AdvertisedData(RPI96, AEM96),\n                    new AdvertisedData(RPI97, AEM97),\n                    new AdvertisedData(RPI98, AEM98),\n                    new AdvertisedData(RPI99, AEM99),\n                    new AdvertisedData(RPI100, AEM100),\n                    new AdvertisedData(RPI101, AEM101),\n                    new AdvertisedData(RPI102, AEM102),\n                    new AdvertisedData(RPI103, AEM103),\n                    new AdvertisedData(RPI104, AEM104),\n                    new AdvertisedData(RPI105, AEM105),\n                    new AdvertisedData(RPI106, AEM106),\n                    new AdvertisedData(RPI107, AEM107),\n                    new AdvertisedData(RPI108, AEM108),\n                    new AdvertisedData(RPI109, AEM109),\n                    new AdvertisedData(RPI110, AEM110),\n                    new AdvertisedData(RPI111, AEM111),\n                    new AdvertisedData(RPI112, AEM112),\n                    new AdvertisedData(RPI113, AEM113),\n                    new AdvertisedData(RPI114, AEM114),\n                    new AdvertisedData(RPI115, AEM115),\n                    new AdvertisedData(RPI116, AEM116),\n                    new AdvertisedData(RPI117, AEM117),\n                    new AdvertisedData(RPI118, AEM118),\n                    new AdvertisedData(RPI119, AEM119),\n                    new AdvertisedData(RPI120, AEM120),\n                    new AdvertisedData(RPI121, AEM121),\n                    new AdvertisedData(RPI122, AEM122),\n                    new AdvertisedData(RPI123, AEM123),\n                    new AdvertisedData(RPI124, AEM124),\n                    new AdvertisedData(RPI125, AEM125),\n                    new AdvertisedData(RPI126, AEM126),\n                    new AdvertisedData(RPI127, AEM127),\n                    new AdvertisedData(RPI128, AEM128),\n                    new AdvertisedData(RPI129, AEM129),\n                    new AdvertisedData(RPI130, AEM130),\n                    new AdvertisedData(RPI131, AEM131),\n                    new AdvertisedData(RPI132, AEM132),\n                    new AdvertisedData(RPI133, AEM133),\n                    new AdvertisedData(RPI134, AEM134),\n                    new AdvertisedData(RPI135, AEM135),\n                    new AdvertisedData(RPI136, AEM136),\n                    new AdvertisedData(RPI137, AEM137),\n                    new AdvertisedData(RPI138, AEM138),\n                    new AdvertisedData(RPI139, AEM139),\n                    new AdvertisedData(RPI140, AEM140),\n                    new AdvertisedData(RPI141, AEM141),\n                    new AdvertisedData(RPI142, AEM142),\n                    new AdvertisedData(RPI143, AEM143)));\n\n    private TestVectors() {\n    }\n}\n\n"
  },
  {
    "path": "play-services-nearby/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <application>\n        <service\n                android:name=\"com.google.android.gms.nearby.exposurenotification.WakeUpService\"\n                android:exported=\"true\"\n                android:permission=\"com.google.android.gms.nearby.exposurenotification.EXPOSURE_CALLBACK\"/>\n    </application>\n</manifest>\n"
  },
  {
    "path": "play-services-nearby/src/main/aidl/com/google/android/gms/nearby/exposurenotification/DailySummary.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification;\n\nparcelable DailySummary;\n"
  },
  {
    "path": "play-services-nearby/src/main/aidl/com/google/android/gms/nearby/exposurenotification/DiagnosisKeysDataMapping.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification;\n\nparcelable DiagnosisKeysDataMapping;\n"
  },
  {
    "path": "play-services-nearby/src/main/aidl/com/google/android/gms/nearby/exposurenotification/ExposureInformation.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification;\n\nparcelable ExposureInformation;\n"
  },
  {
    "path": "play-services-nearby/src/main/aidl/com/google/android/gms/nearby/exposurenotification/ExposureSummary.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification;\n\nparcelable ExposureSummary;\n"
  },
  {
    "path": "play-services-nearby/src/main/aidl/com/google/android/gms/nearby/exposurenotification/ExposureWindow.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification;\n\nparcelable ExposureWindow;\n"
  },
  {
    "path": "play-services-nearby/src/main/aidl/com/google/android/gms/nearby/exposurenotification/PackageConfiguration.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification;\n\nparcelable PackageConfiguration;\n"
  },
  {
    "path": "play-services-nearby/src/main/aidl/com/google/android/gms/nearby/exposurenotification/TemporaryExposureKey.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification;\n\nparcelable TemporaryExposureKey;\n"
  },
  {
    "path": "play-services-nearby/src/main/aidl/com/google/android/gms/nearby/exposurenotification/internal/GetCalibrationConfidenceParams.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nparcelable GetCalibrationConfidenceParams;\n"
  },
  {
    "path": "play-services-nearby/src/main/aidl/com/google/android/gms/nearby/exposurenotification/internal/GetDailySummariesParams.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nparcelable GetDailySummariesParams;\n"
  },
  {
    "path": "play-services-nearby/src/main/aidl/com/google/android/gms/nearby/exposurenotification/internal/GetDiagnosisKeysDataMappingParams.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nparcelable GetDiagnosisKeysDataMappingParams;\n"
  },
  {
    "path": "play-services-nearby/src/main/aidl/com/google/android/gms/nearby/exposurenotification/internal/GetExposureInformationParams.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nparcelable GetExposureInformationParams;\n"
  },
  {
    "path": "play-services-nearby/src/main/aidl/com/google/android/gms/nearby/exposurenotification/internal/GetExposureSummaryParams.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nparcelable GetExposureSummaryParams;\n"
  },
  {
    "path": "play-services-nearby/src/main/aidl/com/google/android/gms/nearby/exposurenotification/internal/GetExposureWindowsParams.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nparcelable GetExposureWindowsParams;\n"
  },
  {
    "path": "play-services-nearby/src/main/aidl/com/google/android/gms/nearby/exposurenotification/internal/GetPackageConfigurationParams.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nparcelable GetPackageConfigurationParams;\n"
  },
  {
    "path": "play-services-nearby/src/main/aidl/com/google/android/gms/nearby/exposurenotification/internal/GetStatusParams.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nparcelable GetStatusParams;\n"
  },
  {
    "path": "play-services-nearby/src/main/aidl/com/google/android/gms/nearby/exposurenotification/internal/GetTemporaryExposureKeyHistoryParams.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nparcelable GetTemporaryExposureKeyHistoryParams;\n"
  },
  {
    "path": "play-services-nearby/src/main/aidl/com/google/android/gms/nearby/exposurenotification/internal/GetVersionParams.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nparcelable GetVersionParams;\n"
  },
  {
    "path": "play-services-nearby/src/main/aidl/com/google/android/gms/nearby/exposurenotification/internal/IBooleanCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nimport com.google.android.gms.common.api.Status;\n\ninterface IBooleanCallback {\n    oneway void onResult(in Status status, boolean result);\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/aidl/com/google/android/gms/nearby/exposurenotification/internal/IDailySummaryListCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.nearby.exposurenotification.DailySummary;\n\ninterface IDailySummaryListCallback {\n    void onResult(in Status status, in List<DailySummary> result);\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/aidl/com/google/android/gms/nearby/exposurenotification/internal/IDiagnosisKeyFileSupplier.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\ninterface IDiagnosisKeyFileSupplier {\n    boolean hasNext();\n    ParcelFileDescriptor next();\n    boolean isAvailable();\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/aidl/com/google/android/gms/nearby/exposurenotification/internal/IDiagnosisKeysDataMappingCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.nearby.exposurenotification.DiagnosisKeysDataMapping;\n\ninterface IDiagnosisKeysDataMappingCallback {\n    void onResult(in Status status, in DiagnosisKeysDataMapping result);\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/aidl/com/google/android/gms/nearby/exposurenotification/internal/IExposureInformationListCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.nearby.exposurenotification.ExposureInformation;\n\ninterface IExposureInformationListCallback {\n    void onResult(in Status status, in List<ExposureInformation> result);\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/aidl/com/google/android/gms/nearby/exposurenotification/internal/IExposureSummaryCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.nearby.exposurenotification.ExposureSummary;\n\ninterface IExposureSummaryCallback {\n    void onResult(in Status status, in ExposureSummary result);\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/aidl/com/google/android/gms/nearby/exposurenotification/internal/IExposureWindowListCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.nearby.exposurenotification.ExposureWindow;\n\ninterface IExposureWindowListCallback {\n    void onResult(in Status status, in List<ExposureWindow> result);\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/aidl/com/google/android/gms/nearby/exposurenotification/internal/IIntCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nimport com.google.android.gms.common.api.Status;\n\ninterface IIntCallback {\n    void onResult(in Status status, int result);\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/aidl/com/google/android/gms/nearby/exposurenotification/internal/ILongCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nimport com.google.android.gms.common.api.Status;\n\ninterface ILongCallback {\n    void onResult(in Status status, long result);\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/aidl/com/google/android/gms/nearby/exposurenotification/internal/INearbyExposureNotificationService.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nimport com.google.android.gms.nearby.exposurenotification.internal.StartParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.StopParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.IsEnabledParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.GetTemporaryExposureKeyHistoryParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.ProvideDiagnosisKeysParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.GetExposureSummaryParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.GetExposureInformationParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.GetExposureWindowsParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.GetVersionParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.GetCalibrationConfidenceParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.GetDailySummariesParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.SetDiagnosisKeysDataMappingParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.GetDiagnosisKeysDataMappingParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.GetStatusParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.GetPackageConfigurationParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.RequestPreAuthorizedTemporaryExposureKeyHistoryParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.RequestPreAuthorizedTemporaryExposureKeyReleaseParams;\n\ninterface INearbyExposureNotificationService{\n    oneway void start(in StartParams params) = 0;\n    oneway void stop(in StopParams params) = 1;\n    oneway void isEnabled(in IsEnabledParams params) = 2;\n    oneway void getTemporaryExposureKeyHistory(in GetTemporaryExposureKeyHistoryParams params) = 3;\n    oneway void provideDiagnosisKeys(in ProvideDiagnosisKeysParams params) = 4;\n    //oneway void getMaxDiagnosisKeyCount(in GetMaxDiagnosisKeyCountParams params) = 5;\n    oneway void getExposureSummary(in GetExposureSummaryParams params) = 6;\n    oneway void getExposureInformation(in GetExposureInformationParams params) = 7;\n    //oneway void resetAllData(in ResetAllDataParams params) = 8;\n    //oneway void resetTemporaryExposureKeys(in ResetTemporaryExposureKeysParams params) = 9;\n    //oneway void startForPackage(in StartForPackageParams params) = 10;\n    //oneway void isEnabledForPackage(in IsEnabledForPackageParams params) = 11;\n    oneway void getExposureWindows(in GetExposureWindowsParams params) = 12;\n    oneway void getVersion(in GetVersionParams params) = 13;\n    oneway void getCalibrationConfidence(in GetCalibrationConfidenceParams params) = 14;\n    oneway void getDailySummaries(in GetDailySummariesParams params) = 15;\n    oneway void setDiagnosisKeysDataMapping(in SetDiagnosisKeysDataMappingParams params) = 16;\n    oneway void getDiagnosisKeysDataMapping(in GetDiagnosisKeysDataMappingParams params) = 17;\n    oneway void getStatus(in GetStatusParams params) = 18;\n    oneway void getPackageConfiguration(in GetPackageConfigurationParams params) = 19;\n    oneway void requestPreAuthorizedTemporaryExposureKeyHistory(in RequestPreAuthorizedTemporaryExposureKeyHistoryParams params) = 20;\n    oneway void requestPreAuthorizedTemporaryExposureKeyRelease(in RequestPreAuthorizedTemporaryExposureKeyReleaseParams params) = 21;\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/aidl/com/google/android/gms/nearby/exposurenotification/internal/IPackageConfigurationCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.nearby.exposurenotification.PackageConfiguration;\n\ninterface IPackageConfigurationCallback {\n    void onResult(in Status status, in PackageConfiguration result);\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/aidl/com/google/android/gms/nearby/exposurenotification/internal/ITemporaryExposureKeyListCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey;\n\ninterface ITemporaryExposureKeyListCallback {\n    void onResult(in Status status, in List<TemporaryExposureKey> result);\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/aidl/com/google/android/gms/nearby/exposurenotification/internal/IsEnabledParams.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nparcelable IsEnabledParams;\n"
  },
  {
    "path": "play-services-nearby/src/main/aidl/com/google/android/gms/nearby/exposurenotification/internal/ProvideDiagnosisKeysParams.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nparcelable ProvideDiagnosisKeysParams;\n"
  },
  {
    "path": "play-services-nearby/src/main/aidl/com/google/android/gms/nearby/exposurenotification/internal/RequestPreAuthorizedTemporaryExposureKeyHistoryParams.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nparcelable RequestPreAuthorizedTemporaryExposureKeyHistoryParams;\n"
  },
  {
    "path": "play-services-nearby/src/main/aidl/com/google/android/gms/nearby/exposurenotification/internal/RequestPreAuthorizedTemporaryExposureKeyReleaseParams.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nparcelable RequestPreAuthorizedTemporaryExposureKeyReleaseParams;\n"
  },
  {
    "path": "play-services-nearby/src/main/aidl/com/google/android/gms/nearby/exposurenotification/internal/SetDiagnosisKeysDataMappingParams.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nparcelable SetDiagnosisKeysDataMappingParams;\n"
  },
  {
    "path": "play-services-nearby/src/main/aidl/com/google/android/gms/nearby/exposurenotification/internal/StartParams.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nparcelable StartParams;\n"
  },
  {
    "path": "play-services-nearby/src/main/aidl/com/google/android/gms/nearby/exposurenotification/internal/StopParams.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nparcelable StopParams;\n"
  },
  {
    "path": "play-services-nearby/src/main/java/com/google/android/gms/nearby/Nearby.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0 AND CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.nearby;\n\nimport android.content.Context;\n\nimport com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.nearby.ExposureNotificationClientImpl;\n\n@PublicApi\npublic class Nearby {\n    public static ExposureNotificationClient getExposureNotificationClient(Context context) {\n        return new ExposureNotificationClientImpl(context);\n    }\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/java/com/google/android/gms/nearby/exposurenotification/CalibrationConfidence.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.nearby.exposurenotification;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Calibration confidence defined for an {@link ExposureWindow}.\n */\n@PublicApi\npublic @interface CalibrationConfidence {\n    /**\n     * No calibration data, using fleet-wide as default options.\n     */\n    int LOWEST = 0;\n    /**\n     * Using average calibration over models from manufacturer.\n     */\n    int LOW = 1;\n    /**\n     * Using single-antenna orientation for a similar model.\n     */\n    int MEDIUM = 2;\n    /**\n     * Using significant calibration data for this model.\n     */\n    int HIGH = 3;\n\n    @PublicApi(exclude = true)\n    int VALUES = 4;\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/java/com/google/android/gms/nearby/exposurenotification/DailySummariesConfig.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.nearby.exposurenotification;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * Configuration of per-day summary of exposures.\n * <p>\n * During summarization the following are computed for each ExposureWindows:\n * <ul>\n * <li>a weighted duration, computed as\n * {@code ( immediateDurationSeconds * immediateDurationWeight ) + ( nearDurationSeconds * nearDurationWeight ) + ( mediumDurationSeconds * mediumDurationWeight ) + ( otherDurationSeconds * otherDurationWeight )}</li>\n * <li>a score, computed as\n * {@code reportTypeWeights[Tek.reportType] * infectiousnessWeights[infectiousness] * weightedDuration}\n * where infectiousness and reportType are set based on the ExposureWindow's diagnosis key and the DiagnosisKeysDataMapping</li>\n * </ul>\n * <p>\n * The {@link ExposureWindow}s are then filtered, removing those with score lower than {@link #getMinimumWindowScore()}.\n * <p>\n * Scores and weighted durations of the {@link ExposureWindow}s that pass the {@link #getMinimumWindowScore()} are then aggregated over a day to compute the maximum and cumulative scores and duration:\n * <ul>\n * <li>sumScore = sum(score of ExposureWindows)</li>\n * <li>maxScore = max(score of ExposureWindows)</li>\n * <li>weightedDurationSum = sum(weighted duration of ExposureWindow)</li>\n * </ul>\n * Note that when the weights are typically around 100% (1.0), both the scores and the weightedDurationSum can be considered as being expressed in seconds. For example, 15 minutes of exposure with all weights equal to 1.0 would be 60 * 15 = 900 (seconds).\n */\n@PublicApi\npublic class DailySummariesConfig extends AutoSafeParcelable {\n    @Field(value = 1, useDirectList = true)\n    private List<Double> reportTypeWeights;\n    @Field(value = 2, useDirectList = true)\n    private List<Double> infectiousnessWeights;\n    @Field(value = 3, useDirectList = true)\n    private List<Integer> attenuationBucketThresholdDb;\n    @Field(value = 4, useDirectList = true)\n    private List<Double> attenuationBucketWeights;\n    @Field(5)\n    private int daysSinceExposureThreshold;\n    @Field(6)\n    private double minimumWindowScore;\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof DailySummariesConfig)) return false;\n\n        DailySummariesConfig that = (DailySummariesConfig) o;\n\n        if (daysSinceExposureThreshold != that.daysSinceExposureThreshold) return false;\n        if (Double.compare(that.minimumWindowScore, minimumWindowScore) != 0) return false;\n        if (reportTypeWeights != null ? !reportTypeWeights.equals(that.reportTypeWeights) : that.reportTypeWeights != null)\n            return false;\n        if (infectiousnessWeights != null ? !infectiousnessWeights.equals(that.infectiousnessWeights) : that.infectiousnessWeights != null)\n            return false;\n        if (attenuationBucketThresholdDb != null ? !attenuationBucketThresholdDb.equals(that.attenuationBucketThresholdDb) : that.attenuationBucketThresholdDb != null)\n            return false;\n        return attenuationBucketWeights != null ? attenuationBucketWeights.equals(that.attenuationBucketWeights) : that.attenuationBucketWeights == null;\n    }\n\n    /**\n     * Thresholds defining the BLE attenuation buckets edges.\n     * <p>\n     * This list must have 3 elements: the immediate, near, and medium thresholds. See attenuationBucketWeights for more information.\n     * <p>\n     * These elements must be between 0 and 255 and come in increasing order.\n     */\n    public List<Integer> getAttenuationBucketThresholdDb() {\n        return attenuationBucketThresholdDb;\n    }\n\n    /**\n     * Scoring weights to associate with ScanInstances depending on the attenuation bucket in which their typicalAttenuationDb falls.\n     * <p>\n     * This list must have 4 elements, corresponding to the weights for the 4 buckets.\n     * <ul>\n     * <li>immediate bucket: -infinity < attenuation <= immediate threshold</li>\n     * <li>near bucket: immediate threshold < attenuation <= near threshold</li>\n     * <li>medium bucket: near threshold < attenuation <= medium threshold</li>\n     * <li>other bucket: medium threshold < attenuation < +infinity</li>\n     * </ul>\n     * Each element must be between 0 and 2.5.\n     */\n    public List<Double> getAttenuationBucketWeights() {\n        return attenuationBucketWeights;\n    }\n\n    /**\n     * Reserved for future use, behavior will be changed in future revisions. No value should be set, or else 0 should be used.\n     */\n    public int getDaysSinceExposureThreshold() {\n        return daysSinceExposureThreshold;\n    }\n\n    /**\n     * Scoring weights to associate with exposures with different Infectiousness.\n     * <p>\n     * This map can include weights for the following Infectiousness values:\n     * <ul>\n     * <li>STANDARD</li>\n     * <li>HIGH</li>\n     * </ul>\n     * Each element must be between 0 and 2.5.\n     */\n    public Map<Integer, Double> getInfectiousnessWeights() {\n        HashMap<Integer, Double> map = new HashMap<>();\n        for (int i = 0; i < infectiousnessWeights.size(); i++) {\n            map.put(i, infectiousnessWeights.get(i));\n        }\n        return map;\n    }\n\n    /**\n     * Minimum score that {@link ExposureWindow}s must reach in order to be included in the {@link DailySummary.ExposureSummaryData}.\n     * <p>\n     * Use 0 to consider all {@link ExposureWindow}s (recommended).\n     */\n    public double getMinimumWindowScore() {\n        return minimumWindowScore;\n    }\n\n    /**\n     * Scoring weights to associate with exposures with different ReportTypes.\n     * <p>\n     * This map can include weights for the following ReportTypes:\n     * <ul>\n     * <li>CONFIRMED_TEST</li>\n     * <li>CONFIRMED_CLINICAL_DIAGNOSIS</li>\n     * <li>SELF_REPORT</li>\n     * <li>RECURSIVE (reserved for future use)</li>\n     * </ul>\n     * Each element must be between 0 and 2.5.\n     */\n    public Map<Integer, Double> getReportTypeWeights() {\n        HashMap<Integer, Double> map = new HashMap<>();\n        for (int i = 0; i < reportTypeWeights.size(); i++) {\n            map.put(i, reportTypeWeights.get(i));\n        }\n        return map;\n    }\n\n    @Override\n    public int hashCode() {\n        int result;\n        long temp;\n        result = reportTypeWeights != null ? reportTypeWeights.hashCode() : 0;\n        result = 31 * result + (infectiousnessWeights != null ? infectiousnessWeights.hashCode() : 0);\n        result = 31 * result + (attenuationBucketThresholdDb != null ? attenuationBucketThresholdDb.hashCode() : 0);\n        result = 31 * result + (attenuationBucketWeights != null ? attenuationBucketWeights.hashCode() : 0);\n        result = 31 * result + daysSinceExposureThreshold;\n        temp = Double.doubleToLongBits(minimumWindowScore);\n        result = 31 * result + (int) (temp ^ (temp >>> 32));\n        return result;\n    }\n\n    /**\n     * A builder for {@link DailySummariesConfig}.\n     */\n    public static class DailySummariesConfigBuilder {\n        private Double[] reportTypeWeights = new Double[ReportType.VALUES];\n        private Double[] infectiousnessWeights = new Double[Infectiousness.VALUES];\n        private List<Integer> attenuationBucketThresholdDb;\n        private List<Double> attenuationBucketWeights;\n        private int daysSinceExposureThreshold;\n        private double minimumWindowScore;\n\n        public DailySummariesConfigBuilder() {\n            Arrays.fill(reportTypeWeights, 0.0);\n            Arrays.fill(infectiousnessWeights, 0.0);\n        }\n\n        public DailySummariesConfig build() {\n            if (attenuationBucketThresholdDb == null)\n                throw new IllegalStateException(\"Must set attenuationBucketThresholdDb\");\n            if (attenuationBucketWeights == null)\n                throw new IllegalStateException(\"Must set attenuationBucketWeights\");\n            DailySummariesConfig config = new DailySummariesConfig();\n            config.reportTypeWeights = Arrays.asList(reportTypeWeights);\n            config.infectiousnessWeights = Arrays.asList(infectiousnessWeights);\n            config.attenuationBucketThresholdDb = attenuationBucketThresholdDb;\n            config.attenuationBucketWeights = attenuationBucketWeights;\n            config.daysSinceExposureThreshold = daysSinceExposureThreshold;\n            config.minimumWindowScore = minimumWindowScore;\n            return config;\n        }\n\n        /**\n         * See {@link #getAttenuationBucketThresholdDb()} and {@link #getAttenuationBucketWeights()}\n         */\n        public DailySummariesConfigBuilder setAttenuationBuckets(List<Integer> thresholds, List<Double> weights) {\n            attenuationBucketThresholdDb = new ArrayList<>(thresholds);\n            attenuationBucketWeights = new ArrayList<>(weights);\n            return this;\n        }\n\n        /**\n         * See {@link #getDaysSinceExposureThreshold()}\n         */\n        public DailySummariesConfigBuilder setDaysSinceExposureThreshold(int daysSinceExposureThreshold) {\n            this.daysSinceExposureThreshold = daysSinceExposureThreshold;\n            return this;\n        }\n\n        /**\n         * See {@link #getInfectiousnessWeights()}\n         */\n        public DailySummariesConfigBuilder setInfectiousnessWeight(@Infectiousness int infectiousness, double weight) {\n            infectiousnessWeights[infectiousness] = weight;\n            return this;\n        }\n\n        /**\n         * See {@link #getMinimumWindowScore()}\n         */\n        public DailySummariesConfigBuilder setMinimumWindowScore(double minimumWindowScore) {\n            this.minimumWindowScore = minimumWindowScore;\n            return this;\n        }\n\n        /**\n         * See {@link #getReportTypeWeights()}\n         */\n        public DailySummariesConfigBuilder setReportTypeWeight(@ReportType int reportType, double weight) {\n            reportTypeWeights[reportType] = weight;\n            return this;\n        }\n    }\n\n    public static final Creator<DailySummariesConfig> CREATOR = new AutoCreator<>(DailySummariesConfig.class);\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/java/com/google/android/gms/nearby/exposurenotification/DailySummary.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.nearby.exposurenotification;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\nimport java.util.List;\n\n/**\n * Daily exposure summary to pass to client side.\n */\n@PublicApi\npublic class DailySummary extends AutoSafeParcelable {\n    @Field(1)\n    private int daysSinceEpoch;\n    @Field(2)\n    private List<ExposureSummaryData> reportSummaries;\n    @Field(3)\n    private ExposureSummaryData summaryData;\n\n    private DailySummary() {\n    }\n\n    @PublicApi(exclude = true)\n    public DailySummary(int daysSinceEpoch, List<ExposureSummaryData> reportSummaries, ExposureSummaryData summaryData) {\n        this.daysSinceEpoch = daysSinceEpoch;\n        this.reportSummaries = reportSummaries;\n        this.summaryData = summaryData;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof DailySummary)) return false;\n\n        DailySummary that = (DailySummary) o;\n\n        if (daysSinceEpoch != that.daysSinceEpoch) return false;\n        if (reportSummaries != null ? !reportSummaries.equals(that.reportSummaries) : that.reportSummaries != null)\n            return false;\n        return summaryData != null ? summaryData.equals(that.summaryData) : that.summaryData == null;\n    }\n\n    /**\n     * Returns days since epoch of the {@link ExposureWindow}s that went into this summary.\n     */\n    public int getDaysSinceEpoch() {\n        return daysSinceEpoch;\n    }\n\n    /**\n     * Summary of all exposures on this day.\n     */\n    public ExposureSummaryData getSummaryData() {\n        return summaryData;\n    }\n\n    /**\n     * Summary of all exposures on this day of a specific diagnosis {@link ReportType}.\n     */\n    public ExposureSummaryData getSummaryDataForReportType(@ReportType int reportType) {\n        return reportSummaries.get(reportType);\n    }\n\n    @Override\n    public int hashCode() {\n        int result = daysSinceEpoch;\n        result = 31 * result + (reportSummaries != null ? reportSummaries.hashCode() : 0);\n        result = 31 * result + (summaryData != null ? summaryData.hashCode() : 0);\n        return result;\n    }\n\n    /**\n     * Stores different scores for specific {@link ReportType}.\n     */\n    public static class ExposureSummaryData extends AutoSafeParcelable {\n        @Field(1)\n        private double maximumScore;\n        @Field(2)\n        private double scoreSum;\n        @Field(3)\n        private double weightedDurationSum;\n\n        private ExposureSummaryData() {\n        }\n\n        @PublicApi(exclude = true)\n        public ExposureSummaryData(double maximumScore, double scoreSum, double weightedDurationSum) {\n            this.maximumScore = maximumScore;\n            this.scoreSum = scoreSum;\n            this.weightedDurationSum = weightedDurationSum;\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (!(o instanceof ExposureSummaryData)) return false;\n\n            ExposureSummaryData that = (ExposureSummaryData) o;\n\n            if (Double.compare(that.maximumScore, maximumScore) != 0) return false;\n            if (Double.compare(that.scoreSum, scoreSum) != 0) return false;\n            return Double.compare(that.weightedDurationSum, weightedDurationSum) == 0;\n        }\n\n        /**\n         * Highest score of all {@link ExposureWindow}s aggregated into this summary.\n         * <p>\n         * See {@link DailySummariesConfig} for more information about how the per-{@link ExposureWindow} score is computed.\n         */\n        public double getMaximumScore() {\n            return maximumScore;\n        }\n\n        /**\n         * Sum of scores for all {@link ExposureWindow}s aggregated into this summary.\n         * <p>\n         * See {@link DailySummariesConfig} for more information about how the per-{@link ExposureWindow} score is computed.\n         */\n        public double getScoreSum() {\n            return scoreSum;\n        }\n\n\n        /**\n         * Sum of weighted durations for all {@link ExposureWindow}s aggregated into this summary.\n         * <p>\n         * See {@link DailySummariesConfig} for more information about how the per-{@link ExposureWindow} score is computed.\n         */\n        public double getWeightedDurationSum() {\n            return weightedDurationSum;\n        }\n\n        @Override\n        public int hashCode() {\n            int result;\n            long temp;\n            temp = Double.doubleToLongBits(maximumScore);\n            result = (int) (temp ^ (temp >>> 32));\n            temp = Double.doubleToLongBits(scoreSum);\n            result = 31 * result + (int) (temp ^ (temp >>> 32));\n            temp = Double.doubleToLongBits(weightedDurationSum);\n            result = 31 * result + (int) (temp ^ (temp >>> 32));\n            return result;\n        }\n\n        public static final Creator<ExposureSummaryData> CREATOR = new AutoCreator<>(ExposureSummaryData.class);\n    }\n\n    public static final Creator<DailySummary> CREATOR = new AutoCreator<>(DailySummary.class);\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/java/com/google/android/gms/nearby/exposurenotification/DiagnosisKeyFileProvider.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.nearby.exposurenotification;\n\nimport org.microg.gms.common.PublicApi;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Provider which holds a list of diagnosis key files and can open/supply them one by one as they are ready to be processed.\n */\n@PublicApi\npublic class DiagnosisKeyFileProvider {\n    private int index;\n    private List<File> files;\n\n    public DiagnosisKeyFileProvider(List<File> files) {\n        this.files = new ArrayList<>(files);\n    }\n\n    @PublicApi(exclude = true)\n    public boolean hasNext() {\n        return files.size() > index;\n    }\n\n    @PublicApi(exclude = true)\n    public File next() {\n        return files.get(index++);\n    }\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/java/com/google/android/gms/nearby/exposurenotification/DiagnosisKeysDataMapping.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.nearby.exposurenotification;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * Mappings from diagnosis keys data to concepts returned by the API.\n */\n@PublicApi\npublic class DiagnosisKeysDataMapping extends AutoSafeParcelable {\n    @Field(value = 1, useDirectList = true)\n    private List<Integer> daysSinceOnsetToInfectiousness = new ArrayList<>();\n    @Field(2)\n    @ReportType\n    private int reportTypeWhenMissing;\n    @Field(3)\n    @Infectiousness\n    private int infectiousnessWhenDaysSinceOnsetMissing;\n\n    /**\n     * Mapping from diagnosisKey.daysSinceOnsetOfSymptoms to {@link Infectiousness}.\n     * <p>\n     * Infectiousness is computed from this mapping and the tek metadata as - daysSinceOnsetToInfectiousness[{@link TemporaryExposureKey#getDaysSinceOnsetOfSymptoms()}], or - {@link #getInfectiousnessWhenDaysSinceOnsetMissing()} if {@link TemporaryExposureKey#getDaysSinceOnsetOfSymptoms()} is {@link TemporaryExposureKey#DAYS_SINCE_ONSET_OF_SYMPTOMS_UNKNOWN}.\n     * <p>\n     * Values of DaysSinceOnsetOfSymptoms that aren't represented in this map are given {@link Infectiousness#NONE} as infectiousness. Exposures with infectiousness equal to {@link Infectiousness#NONE} are dropped.\n     */\n    public Map<Integer, Integer> getDaysSinceOnsetToInfectiousness() {\n        HashMap<Integer, Integer> map = new HashMap<>();\n        for (int i = 0; i < daysSinceOnsetToInfectiousness.size(); i++) {\n            map.put(i, daysSinceOnsetToInfectiousness.get(i));\n        }\n        return map;\n    }\n\n    /**\n     * Infectiousness of TEKs for which onset of symptoms is not set.\n     * <p>\n     * See {@link #getDaysSinceOnsetToInfectiousness()} for more info.\n     */\n    public int getInfectiousnessWhenDaysSinceOnsetMissing() {\n        return infectiousnessWhenDaysSinceOnsetMissing;\n    }\n\n    /**\n     * Report type to default to when a TEK has no report type set.\n     * <p>\n     * This report type gets used when creating the {@link ExposureWindow}s and the {@link DailySummary}s. The system will treat TEKs with missing report types as if they had this provided report type.\n     */\n    public int getReportTypeWhenMissing() {\n        return reportTypeWhenMissing;\n    }\n\n    /**\n     * A builder for {@link DiagnosisKeysDataMapping}.\n     */\n    public static class DiagnosisKeysDataMappingBuilder {\n        private final static int MAX_DAYS = 29;\n        private List<Integer> daysSinceOnsetToInfectiousness;\n        @ReportType\n        private int reportTypeWhenMissing = ReportType.UNKNOWN;\n        @Infectiousness\n        private Integer infectiousnessWhenDaysSinceOnsetMissing;\n\n        public DiagnosisKeysDataMapping build() {\n            if (daysSinceOnsetToInfectiousness == null)\n                throw new IllegalStateException(\"Must set daysSinceOnsetToInfectiousness\");\n            if (reportTypeWhenMissing == ReportType.UNKNOWN)\n                throw new IllegalStateException(\"Must set reportTypeWhenMissing\");\n            if (infectiousnessWhenDaysSinceOnsetMissing == null)\n                throw new IllegalStateException(\"Must set infectiousnessWhenDaysSinceOnsetMissing\");\n            DiagnosisKeysDataMapping mapping = new DiagnosisKeysDataMapping();\n            mapping.daysSinceOnsetToInfectiousness = new ArrayList<>(daysSinceOnsetToInfectiousness);\n            mapping.reportTypeWhenMissing = reportTypeWhenMissing;\n            mapping.infectiousnessWhenDaysSinceOnsetMissing = infectiousnessWhenDaysSinceOnsetMissing;\n            return mapping;\n        }\n\n        public DiagnosisKeysDataMappingBuilder setDaysSinceOnsetToInfectiousness(Map<Integer, Integer> daysSinceOnsetToInfectiousness) {\n            if (daysSinceOnsetToInfectiousness.size() > MAX_DAYS)\n                throw new IllegalArgumentException(\"daysSinceOnsetToInfectiousness exceeds \" + MAX_DAYS + \" days\");\n            Integer[] values = new Integer[MAX_DAYS];\n            Arrays.fill(values, 0);\n            for (Map.Entry<Integer, Integer> entry : daysSinceOnsetToInfectiousness.entrySet()) {\n                if (entry.getKey() > 14) throw new IllegalArgumentException(\"invalid day since onset\");\n                values[entry.getKey() + 14] = entry.getValue();\n            }\n            this.daysSinceOnsetToInfectiousness = Arrays.asList(values);\n            return this;\n        }\n\n        public DiagnosisKeysDataMappingBuilder setInfectiousnessWhenDaysSinceOnsetMissing(@Infectiousness int infectiousnessWhenDaysSinceOnsetMissing) {\n            this.infectiousnessWhenDaysSinceOnsetMissing = infectiousnessWhenDaysSinceOnsetMissing;\n            return this;\n        }\n\n        public DiagnosisKeysDataMappingBuilder setReportTypeWhenMissing(@ReportType int reportTypeWhenMissing) {\n            this.reportTypeWhenMissing = reportTypeWhenMissing;\n            return this;\n        }\n    }\n\n    public static final Creator<DiagnosisKeysDataMapping> CREATOR = new AutoCreator<>(DiagnosisKeysDataMapping.class);\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/java/com/google/android/gms/nearby/exposurenotification/ExposureConfiguration.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0 AND CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.nearby.exposurenotification;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\nimport java.util.Arrays;\n\n@Deprecated\npublic class ExposureConfiguration extends AutoSafeParcelable {\n    @Field(1)\n    private int minimumRiskScore;\n    @Field(2)\n    private int[] attenuationScores;\n    @Field(3)\n    private int attenuationWeight;\n    @Field(4)\n    private int[] daysSinceLastExposureScores;\n    @Field(5)\n    private int daysSinceLastExposureWeight;\n    @Field(6)\n    private int[] durationScores;\n    @Field(7)\n    private int durationWeight;\n    @Field(8)\n    private int[] transmissionRiskScores;\n    @Field(9)\n    private int transmissionRiskWeight;\n    @Field(10)\n    private int[] durationAtAttenuationThresholds;\n\n    private ExposureConfiguration() {\n    }\n\n    ExposureConfiguration(int minimumRiskScore, int[] attenuationScores, int attenuationWeight, int[] daysSinceLastExposureScores, int daysSinceLastExposureWeight, int[] durationScores, int durationWeight, int[] transmissionRiskScores, int transmissionRiskWeight, int[] durationAtAttenuationThresholds) {\n        this.minimumRiskScore = minimumRiskScore;\n        this.attenuationScores = attenuationScores;\n        this.attenuationWeight = attenuationWeight;\n        this.daysSinceLastExposureScores = daysSinceLastExposureScores;\n        this.daysSinceLastExposureWeight = daysSinceLastExposureWeight;\n        this.durationScores = durationScores;\n        this.durationWeight = durationWeight;\n        this.transmissionRiskScores = transmissionRiskScores;\n        this.transmissionRiskWeight = transmissionRiskWeight;\n        this.durationAtAttenuationThresholds = durationAtAttenuationThresholds;\n    }\n\n    public int getMinimumRiskScore() {\n        return minimumRiskScore;\n    }\n\n    public int[] getAttenuationScores() {\n        return Arrays.copyOf(attenuationScores, attenuationScores.length);\n    }\n\n    public int getAttenuationWeight() {\n        return attenuationWeight;\n    }\n\n    public int[] getDaysSinceLastExposureScores() {\n        return Arrays.copyOf(daysSinceLastExposureScores, daysSinceLastExposureScores.length);\n    }\n\n    public int getDaysSinceLastExposureWeight() {\n        return daysSinceLastExposureWeight;\n    }\n\n    public int[] getDurationScores() {\n        return Arrays.copyOf(durationScores, durationScores.length);\n    }\n\n    public int getDurationWeight() {\n        return durationWeight;\n    }\n\n    public int[] getTransmissionRiskScores() {\n        return Arrays.copyOf(transmissionRiskScores, transmissionRiskScores.length);\n    }\n\n    public int getTransmissionRiskWeight() {\n        return transmissionRiskWeight;\n    }\n\n    public int[] getDurationAtAttenuationThresholds() {\n        return Arrays.copyOf(durationAtAttenuationThresholds, durationAtAttenuationThresholds.length);\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        ExposureConfiguration that = (ExposureConfiguration) o;\n\n        if (minimumRiskScore != that.minimumRiskScore) return false;\n        if (attenuationWeight != that.attenuationWeight) return false;\n        if (daysSinceLastExposureWeight != that.daysSinceLastExposureWeight) return false;\n        if (durationWeight != that.durationWeight) return false;\n        if (transmissionRiskWeight != that.transmissionRiskWeight) return false;\n        if (!Arrays.equals(attenuationScores, that.attenuationScores)) return false;\n        if (!Arrays.equals(daysSinceLastExposureScores, that.daysSinceLastExposureScores)) return false;\n        if (!Arrays.equals(durationScores, that.durationScores)) return false;\n        if (!Arrays.equals(transmissionRiskScores, that.transmissionRiskScores)) return false;\n        return Arrays.equals(durationAtAttenuationThresholds, that.durationAtAttenuationThresholds);\n    }\n\n    @Override\n    public int hashCode() {\n        int result = minimumRiskScore;\n        result = 31 * result + Arrays.hashCode(attenuationScores);\n        result = 31 * result + attenuationWeight;\n        result = 31 * result + Arrays.hashCode(daysSinceLastExposureScores);\n        result = 31 * result + daysSinceLastExposureWeight;\n        result = 31 * result + Arrays.hashCode(durationScores);\n        result = 31 * result + durationWeight;\n        result = 31 * result + Arrays.hashCode(transmissionRiskScores);\n        result = 31 * result + transmissionRiskWeight;\n        result = 31 * result + Arrays.hashCode(durationAtAttenuationThresholds);\n        return result;\n    }\n\n    @Override\n    public String toString() {\n        return \"ExposureConfiguration{\" +\n                \"minimumRiskScore=\" + minimumRiskScore +\n                \", attenuationScores=\" + Arrays.toString(attenuationScores) +\n                \", attenuationWeight=\" + attenuationWeight +\n                \", daysSinceLastExposureScores=\" + Arrays.toString(daysSinceLastExposureScores) +\n                \", daysSinceLastExposureWeight=\" + daysSinceLastExposureWeight +\n                \", durationScores=\" + Arrays.toString(durationScores) +\n                \", durationWeight=\" + durationWeight +\n                \", transmissionRiskScores=\" + Arrays.toString(transmissionRiskScores) +\n                \", transmissionRiskWeight=\" + transmissionRiskWeight +\n                \", durationAtAttenuationThresholds=\" + Arrays.toString(durationAtAttenuationThresholds) +\n                '}';\n    }\n\n    public static class ExposureConfigurationBuilder {\n        private int minimumRiskScore = 4;\n        private int[] attenuationScores = new int[]{4, 4, 4, 4, 4, 4, 4, 4};\n        private int attenuationWeight = 50;\n        private int[] daysSinceLastExposureScores = new int[]{4, 4, 4, 4, 4, 4, 4, 4};\n        private int daysSinceLastExposureWeight = 50;\n        private int[] durationScores = new int[]{4, 4, 4, 4, 4, 4, 4, 4};\n        private int durationWeight = 50;\n        private int[] transmissionRiskScores = new int[]{4, 4, 4, 4, 4, 4, 4, 4};\n        private int transmissionRiskWeight = 50;\n        private int[] durationAtAttenuationThresholds = new int[]{50, 74};\n\n        public ExposureConfigurationBuilder setMinimumRiskScore(int minimumRiskScore) {\n            this.minimumRiskScore = minimumRiskScore;\n            return this;\n        }\n\n        public ExposureConfigurationBuilder setAttenuationScores(int... attenuationScores) {\n            this.attenuationScores = Arrays.copyOf(attenuationScores, attenuationScores.length);\n            return this;\n        }\n\n        public ExposureConfigurationBuilder setAttenuationWeight(int attenuationWeight) {\n            this.attenuationWeight = attenuationWeight;\n            return this;\n        }\n\n        public ExposureConfigurationBuilder setDaysSinceLastExposureScores(int... daysSinceLastExposureScores) {\n            this.daysSinceLastExposureScores = Arrays.copyOf(daysSinceLastExposureScores, daysSinceLastExposureScores.length);\n            return this;\n        }\n\n        public ExposureConfigurationBuilder setDaysSinceLastExposureWeight(int daysSinceLastExposureWeight) {\n            this.daysSinceLastExposureWeight = daysSinceLastExposureWeight;\n            return this;\n        }\n\n        public ExposureConfigurationBuilder setDurationScores(int... durationScores) {\n            this.durationScores = Arrays.copyOf(durationScores, durationScores.length);\n            return this;\n        }\n\n        public ExposureConfigurationBuilder setDurationWeight(int durationWeight) {\n            this.durationWeight = durationWeight;\n            return this;\n        }\n\n        public ExposureConfigurationBuilder setTransmissionRiskScores(int... transmissionRiskScores) {\n            this.transmissionRiskScores = Arrays.copyOf(transmissionRiskScores, transmissionRiskScores.length);\n            return this;\n        }\n\n        public ExposureConfigurationBuilder setTransmissionRiskWeight(int transmissionRiskWeight) {\n            this.transmissionRiskWeight = transmissionRiskWeight;\n            return this;\n        }\n\n        public ExposureConfigurationBuilder setDurationAtAttenuationThresholds(int... durationAtAttenuationThresholds) {\n            this.durationAtAttenuationThresholds = Arrays.copyOf(durationAtAttenuationThresholds, durationAtAttenuationThresholds.length);\n            return this;\n        }\n\n        public ExposureConfiguration build() {\n            return new ExposureConfiguration(minimumRiskScore, attenuationScores, attenuationWeight, daysSinceLastExposureScores, daysSinceLastExposureWeight, durationScores, durationWeight, transmissionRiskScores, transmissionRiskWeight, durationAtAttenuationThresholds);\n        }\n    }\n\n    public static final Creator<ExposureConfiguration> CREATOR = new AutoCreator<>(ExposureConfiguration.class);\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/java/com/google/android/gms/nearby/exposurenotification/ExposureInformation.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0 AND CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.nearby.exposurenotification;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\nimport java.util.Arrays;\nimport java.util.Date;\n\n@Deprecated\npublic class ExposureInformation extends AutoSafeParcelable {\n    @Field(1)\n    private long dateMillisSinceEpoch;\n    @Field(2)\n    private int durationMinutes;\n    @Field(3)\n    private int attenuationValue;\n    @Field(4)\n    @RiskLevel\n    private int transmissionRiskLevel;\n    @Field(5)\n    private int totalRiskScore;\n    @Field(6)\n    private int[] attenuationDurationsInMinutes;\n\n    private ExposureInformation() {\n    }\n\n    ExposureInformation(long dateMillisSinceEpoch, int durationMinutes, int attenuationValue, @RiskLevel int transmissionRiskLevel, int totalRiskScore, int[] attenuationDurationsInMinutes) {\n        this.dateMillisSinceEpoch = dateMillisSinceEpoch;\n        this.durationMinutes = durationMinutes;\n        this.attenuationValue = attenuationValue;\n        this.transmissionRiskLevel = transmissionRiskLevel;\n        this.totalRiskScore = totalRiskScore;\n        this.attenuationDurationsInMinutes = attenuationDurationsInMinutes;\n    }\n\n    public long getDateMillisSinceEpoch() {\n        return dateMillisSinceEpoch;\n    }\n\n    public Date getDate() {\n        return new Date(dateMillisSinceEpoch);\n    }\n\n    public int getDurationMinutes() {\n        return durationMinutes;\n    }\n\n    public int getAttenuationValue() {\n        return attenuationValue;\n    }\n\n    @RiskLevel\n    public int getTransmissionRiskLevel() {\n        return transmissionRiskLevel;\n    }\n\n    public int getTotalRiskScore() {\n        return totalRiskScore;\n    }\n\n    public int[] getAttenuationDurationsInMinutes() {\n        return Arrays.copyOf(attenuationDurationsInMinutes, attenuationDurationsInMinutes.length);\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        ExposureInformation that = (ExposureInformation) o;\n\n        if (dateMillisSinceEpoch != that.dateMillisSinceEpoch) return false;\n        if (durationMinutes != that.durationMinutes) return false;\n        if (attenuationValue != that.attenuationValue) return false;\n        if (transmissionRiskLevel != that.transmissionRiskLevel) return false;\n        if (totalRiskScore != that.totalRiskScore) return false;\n        return Arrays.equals(attenuationDurationsInMinutes, that.attenuationDurationsInMinutes);\n    }\n\n    @Override\n    public int hashCode() {\n        int result = (int) (dateMillisSinceEpoch ^ (dateMillisSinceEpoch >>> 32));\n        result = 31 * result + durationMinutes;\n        result = 31 * result + attenuationValue;\n        result = 31 * result + transmissionRiskLevel;\n        result = 31 * result + totalRiskScore;\n        result = 31 * result + Arrays.hashCode(attenuationDurationsInMinutes);\n        return result;\n    }\n\n    @Override\n    public String toString() {\n        return \"ExposureInformation{\" +\n                \"date=\" + getDate() +\n                \", durationMinutes=\" + durationMinutes +\n                \", attenuationValue=\" + attenuationValue +\n                \", transmissionRiskLevel=\" + transmissionRiskLevel +\n                \", totalRiskScore=\" + totalRiskScore +\n                \", attenuationDurationsInMinutes=\" + Arrays.toString(attenuationDurationsInMinutes) +\n                '}';\n    }\n\n    public static class ExposureInformationBuilder {\n        private long dateMillisSinceEpoch;\n        private int durationMinutes;\n        private int attenuationValue;\n        @RiskLevel\n        private int transmissionRiskLevel;\n        private int totalRiskScore;\n        private int[] attenuationDurations = new int[]{0, 0};\n\n        public ExposureInformationBuilder setDateMillisSinceEpoch(long dateMillisSinceEpoch) {\n            this.dateMillisSinceEpoch = dateMillisSinceEpoch;\n            return this;\n        }\n\n        public ExposureInformationBuilder setDurationMinutes(int durationMinutes) {\n            this.durationMinutes = durationMinutes;\n            return this;\n        }\n\n        public ExposureInformationBuilder setAttenuationValue(int attenuationValue) {\n            this.attenuationValue = attenuationValue;\n            return this;\n        }\n\n        public ExposureInformationBuilder setTransmissionRiskLevel(@RiskLevel int transmissionRiskLevel) {\n            this.transmissionRiskLevel = transmissionRiskLevel;\n            return this;\n        }\n\n        public ExposureInformationBuilder setTotalRiskScore(int totalRiskScore) {\n            this.totalRiskScore = totalRiskScore;\n            return this;\n        }\n\n        public ExposureInformationBuilder setAttenuationDurations(int[] attenuationDurations) {\n            this.attenuationDurations = Arrays.copyOf(attenuationDurations, attenuationDurations.length);\n            return this;\n        }\n\n        public ExposureInformation build() {\n            return new ExposureInformation(dateMillisSinceEpoch, durationMinutes, attenuationValue, transmissionRiskLevel, totalRiskScore, attenuationDurations);\n        }\n    }\n\n    public static final Creator<ExposureInformation> CREATOR = new AutoCreator<>(ExposureInformation.class);\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/java/com/google/android/gms/nearby/exposurenotification/ExposureNotificationClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0 AND CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.nearby.exposurenotification;\n\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.HasApiKey;\nimport com.google.android.gms.tasks.Task;\n\nimport org.microg.gms.common.PublicApi;\n\nimport java.io.File;\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * Interface for contact tracing APIs.\n */\n@PublicApi\npublic interface ExposureNotificationClient extends HasApiKey<Api.ApiOptions.NoOptions> {\n    /**\n     * Activity action which shows the exposure notification settings screen.\n     */\n    String ACTION_EXPOSURE_NOTIFICATION_SETTINGS = \"com.google.android.gms.settings.EXPOSURE_NOTIFICATION_SETTINGS\";\n    /**\n     * Action which will be invoked via a BroadcastReceiver as a callback when matching has finished and no matches were found.\n     * Also see {@link #EXTRA_TOKEN}, which will be included in this broadcast.\n     */\n    String ACTION_EXPOSURE_NOT_FOUND = \"com.google.android.gms.exposurenotification.ACTION_EXPOSURE_NOT_FOUND\";\n    /**\n     * Action which will be invoked via a BroadcastReceiver as a callback when the user has an updated exposure status.\n     * Also see {@link #EXTRA_EXPOSURE_SUMMARY} and {@link #EXTRA_TOKEN}, which will be included in this broadcast.\n     */\n    String ACTION_EXPOSURE_STATE_UPDATED = \"com.google.android.gms.exposurenotification.ACTION_EXPOSURE_STATE_UPDATED\";\n    /**\n     * Action broadcast to a client application if {@link #requestPreAuthorizedTemporaryExposureKeyRelease()} has been authorized and the user has unlocked their phone, granting release of their keys after a positive diagnosis.\n     *\n     * This action will include an {@link java.util.ArrayList} of {@link TemporaryExposureKey}s keyed by {@link #EXTRA_TEMPORARY_EXPOSURE_KEY_LIST}.\n     */\n    String ACTION_PRE_AUTHORIZE_RELEASE_PHONE_UNLOCKED = \"com.google.android.gms.exposurenotification.ACTION_PRE_AUTHORIZE_RELEASE_PHONE_UNLOCKED\";\n    /**\n     * Action which will be invoked via a BroadcastReceiver when the user modifies the state of exposure notifications via the Google Settings page.\n     * {@link #EXTRA_SERVICE_STATE} will be included as part of this broadcast.\n     */\n    String ACTION_SERVICE_STATE_UPDATED = \"com.google.android.gms.exposurenotification.ACTION_SERVICE_STATE_UPDATED\";\n    /**\n     * Extra attached to the {@link #ACTION_EXPOSURE_STATE_UPDATED} broadcast, giving a summary of the exposure details detected.\n     * Also see {@link #getExposureSummary(String)}.\n     *\n     * @deprecated {@link ExposureSummary} is no longer provided when using the {@link #getExposureWindows()} API. Instead, use {@link #getDailySummaries(DailySummariesConfig)}.\n     */\n    @Deprecated\n    String EXTRA_EXPOSURE_SUMMARY = \"com.google.android.gms.exposurenotification.EXTRA_EXPOSURE_SUMMARY\";\n    /**\n     * Boolean extra attached to the {@link #ACTION_SERVICE_STATE_UPDATED} broadcast signifying whether the service is enabled or disabled.\n     */\n    String EXTRA_SERVICE_STATE = \"com.google.android.gms.exposurenotification.EXTRA_SERVICE_STATE\";\n    /**\n     * Extra included in the {@link #ACTION_PRE_AUTHORIZE_RELEASE_PHONE_UNLOCKED} broadcast, containing an {@link java.util.ArrayList} of {@link TemporaryExposureKey}s.\n     */\n    String EXTRA_TEMPORARY_EXPOSURE_KEY_LIST = \"com.google.android.gms.exposurenotification.EXTRA_TEMPORARY_EXPOSURE_KEY_LIST\";\n    /**\n     * Extra attached to the {@link #ACTION_EXPOSURE_STATE_UPDATED} broadcast, providing the token associated with the {@link #provideDiagnosisKeys(DiagnosisKeyFileProvider)} request.\n     *\n     * @deprecated Tokens are no longer used. Instead, prefer using the tokenless versions of {@link #provideDiagnosisKeys(DiagnosisKeyFileProvider)}, {@link #getExposureWindows()}, and {@link #getDailySummaries(DailySummariesConfig)}.\n     */\n    @Deprecated\n    String EXTRA_TOKEN = \"com.google.android.gms.exposurenotification.EXTRA_TOKEN\";\n    /**\n     * Token to be used with ExposureWindows API. Must be used with {@link #provideDiagnosisKeys(DiagnosisKeyFileProvider) }request when later using {@link #getExposureWindows()}.\n     *\n     * @deprecated Tokens are no longer used. Instead, prefer using the tokenless versions of {@link #provideDiagnosisKeys(DiagnosisKeyFileProvider)}, {@link #getExposureWindows()}, and {@link #getDailySummaries(DailySummariesConfig)}.\n     */\n    @Deprecated\n    String TOKEN_A = \"TYZWQ32170AXEUVCDW7A\";\n\n    /**\n     * Checks whether the device supports Exposure Notification BLE scanning without requiring location to be enabled first.\n     */\n    boolean deviceSupportsLocationlessScanning();\n\n    /**\n     * Gets {@link CalibrationConfidence} of the current device.\n     */\n    Task<Integer> getCalibrationConfidence();\n\n    /**\n     * Retrieves the per-day exposure summaries associated with the provided configuration.\n     * <p>\n     * A valid configuration must be provided to compute the summaries.\n     */\n    Task<List<DailySummary>> getDailySummaries(DailySummariesConfig dailySummariesConfig);\n\n    /**\n     * Retrieves the current {@link DiagnosisKeysDataMapping}.\n     */\n    Task<DiagnosisKeysDataMapping> getDiagnosisKeysDataMapping();\n\n    /**\n     * Gets detailed information about exposures that have occurred related to the provided token, which should match the token provided in {@link #provideDiagnosisKeys(DiagnosisKeyFileProvider)}.\n     * <p>\n     * When multiple ExposureInformation objects are returned, they can be:\n     * <ul>\n     * <li>Multiple encounters with a single diagnosis key.</li>\n     * <li>Multiple encounters with the same device across key rotation boundaries.</li>\n     * <li>Encounters with multiple devices.</li>\n     * </ul>\n     * Records of calls to this method will be retained and viewable by the user.\n     *\n     * @deprecated When using the ExposureWindow API, use {@link #getExposureWindows()} instead.\n     */\n    @Deprecated\n    Task<List<ExposureInformation>> getExposureInformation(String token);\n\n    /**\n     * Gets a summary of the exposure calculation for the token, which should match the token provided in {@link #provideDiagnosisKeys(DiagnosisKeyFileProvider)}.\n     *\n     * @deprecated When using the ExposureWindow API, use {@link #getDailySummaries(DailySummariesConfig)} instead.\n     */\n    @Deprecated\n    Task<ExposureSummary> getExposureSummary(String token);\n\n    /**\n     * Retrieves the list of exposure windows corresponding to the TEKs given to {@link #provideDiagnosisKeys(DiagnosisKeyFileProvider)}.\n     * <p>\n     * Long exposures to one TEK are split into windows of up to 30 minutes of scans, so a given TEK may lead to several exposure windows if beacon sightings for it spanned more than 30 minutes. The link between them (the fact that they all correspond to the same TEK) is lost because those windows are shuffled before being returned and the underlying TEKs are not exposed by the API.\n     */\n    Task<List<ExposureWindow>> getExposureWindows();\n\n    /**\n     * Retrieves the list of exposure windows corresponding to the TEKs given to provideKeys with token=TOKEN_A.\n     * <p>\n     * Long exposures to one TEK are split into windows of up to 30 minutes of scans, so a given TEK may lead to several exposure windows if beacon sightings for it spanned more than 30 minutes. The link between them (the fact that they all correspond to the same TEK) is lost because those windows are shuffled before being returned and the underlying TEKs are not exposed by the API.\n     * <p>\n     * The provided token must be TOKEN_A.\n     *\n     * @deprecated Tokens are no longer used. Instead, prefer using the tokenless version of {@link #getExposureWindows()}.\n     */\n    @Deprecated\n    Task<List<ExposureWindow>> getExposureWindows(String token);\n\n    /**\n     * Retrieves the associated {@link PackageConfiguration} for the calling package. Note that this value can be null if no configuration was when starting.\n     */\n    Task<PackageConfiguration> getPackageConfiguration();\n\n    /**\n     * Gets the current Exposure Notification status.\n     */\n    Task<Set<ExposureNotificationStatus>> getStatus();\n\n    /**\n     * Gets {@link TemporaryExposureKey} history to be stored on the server.\n     * <p>\n     * This should only be done after proper verification is performed on the client side that the user is diagnosed positive. Each key returned will have an unknown transmission risk level, clients should choose an appropriate risk level for these keys before uploading them to the server.\n     * <p>\n     * The keys provided here will only be from previous days; keys will not be released until after they are no longer an active exposure key.\n     * <p>\n     * This shows a user permission dialog for sharing and uploading data to the server.\n     */\n    Task<List<TemporaryExposureKey>> getTemporaryExposureKeyHistory();\n\n    /**\n     * Gets the current Exposure Notification version.\n     */\n    Task<Long> getVersion();\n\n    /**\n     * Indicates whether contact tracing is currently running for the requesting app.\n     */\n    Task<Boolean> isEnabled();\n\n    /**\n     * Provides a list of diagnosis key files for exposure checking. The files are to be synced from the server. Old diagnosis keys (for example older than 14 days), will be ignored.\n     * <p>\n     * Diagnosis keys will be stored and matching will be performed in the near future, after which you’ll receive a broadcast with the {@link #ACTION_EXPOSURE_STATE_UPDATED} action. If no matches are found, you'll receive an {@link #ACTION_EXPOSURE_NOT_FOUND} action.\n     * <p>\n     * The diagnosis key files must be signed appropriately. Results from this request can also be queried at any time via {@link #getExposureWindows()} and {@link #getDailySummaries(DailySummariesConfig)}.\n     * <p>\n     * After the result Task has returned, keyFiles can be deleted.\n     * <p>\n     * Results remain for 14 days.\n     *\n     * @deprecated Prefer the {@link DiagnosisKeyFileProvider} version of this method instead, which scales better when a large number of files are passed at the same time.\n     */\n    @Deprecated\n    Task<Void> provideDiagnosisKeys(List<File> keyFiles);\n\n    /**\n     * Provides diagnosis key files for exposure checking. The files are to be synced from the server. Old diagnosis keys (for example older than 14 days), will be ignored.\n     * <p>\n     * Diagnosis keys will be stored and matching will be performed in the near future, after which you’ll receive a broadcast with the {@link #ACTION_EXPOSURE_STATE_UPDATED} action. If no matches are found, you'll receive an {@link #ACTION_EXPOSURE_NOT_FOUND} action.\n     * <p>\n     * The diagnosis key files must be signed appropriately. Results from this request can also be queried at any time via {@link #getExposureWindows()} and {@link #getDailySummaries(DailySummariesConfig)}.\n     * <p>\n     * After the result Task has returned, files can be deleted.\n     * <p>\n     * Results remain for 14 days.\n     */\n    Task<Void> provideDiagnosisKeys(DiagnosisKeyFileProvider provider);\n\n    /**\n     * Provides a list of diagnosis key files for exposure checking. The files are to be synced from the server. Old diagnosis keys (for example older than 14 days), will be ignored.\n     * <p>\n     * Diagnosis keys will be stored and matching will be performed in the near future, after which you’ll receive a broadcast with the {@link #ACTION_EXPOSURE_STATE_UPDATED} action. If no matches are found, you'll receive an {@link #ACTION_EXPOSURE_NOT_FOUND} action.\n     * <p>\n     * The diagnosis key files must be signed appropriately. Exposure configuration options can be provided to tune the matching algorithm. A unique token for this batch can also be provided, which will be used to associate the matches with this request as part of {@link #getExposureSummary(String)} and {@link #getExposureInformation(String)}. Alternatively, the same token can be passed in multiple times to concatenate results.\n     * <p>\n     * After the result Task has returned, keyFiles can be deleted.\n     * <p>\n     * Results for a given token remain for 14 days.\n     *\n     * @deprecated Tokens and configuration are no longer used. Instead, prefer using the tokenless, configuration-less version of {@link #provideDiagnosisKeys(DiagnosisKeyFileProvider)}.\n     */\n    @Deprecated\n    Task<Void> provideDiagnosisKeys(List<File> keys, ExposureConfiguration configuration, String token);\n\n    /**\n     * Shows a dialog to the user asking for authorization to get {@link TemporaryExposureKey}s in the background.\n     * <p>\n     * If approved, the client application will be able to call {@link #requestPreAuthorizedTemporaryExposureKeyRelease()} one time in the next 5 days to get a list of {@link TemporaryExposureKey}s for a user which has tested positive.\n     */\n    Task<Void> requestPreAuthorizedTemporaryExposureKeyHistory();\n\n    /**\n     * If consent has previously been requested and granted by the user using {@link #requestPreAuthorizedTemporaryExposureKeyHistory()}, then this method will cause keys to be released to the client application after the screen is unlocked by the user. Keys will be delivered via a broadcast denoted with the {@link #ACTION_PRE_AUTHORIZE_RELEASE_PHONE_UNLOCKED} action.\n     */\n    Task<Void> requestPreAuthorizedTemporaryExposureKeyRelease ();\n\n    /**\n     * Sets the diagnosis keys data mapping if it wasn't already changed recently.\n     * <p>\n     * If called twice within 7 days, the second call will have no effect and will raise an exception with status code FAILED_RATE_LIMITED.\n     */\n    Task<Void> setDiagnosisKeysDataMapping(DiagnosisKeysDataMapping diagnosisKeysMetadataMapping);\n\n    /**\n     * Starts BLE broadcasts and scanning based on the defined protocol.\n     * <p>\n     * If not previously started, this shows a user dialog for consent to start exposure detection and get permission.\n     * <p>\n     * Callbacks regarding exposure status will be provided via a BroadcastReceiver. Clients should register a receiver in their AndroidManifest which can handle the following action:\n     * <ul>\n     * <li>{@code com.google.android.gms.exposurenotification.ACTION_EXPOSURE_STATE_UPDATED}</li>\n     * </ul>\n     * This receiver should also be guarded by the {@code com.google.android.gms.nearby.exposurenotification.EXPOSURE_CALLBACK} permission so that other apps are not able to fake this broadcast.\n     */\n    Task<Void> start();\n\n    /**\n     * Disables advertising and scanning. Contents of the database and keys will remain.\n     * <p>\n     * If the client app has been uninstalled by the user, this will be automatically invoked and the database and keys will be wiped from the device.\n     */\n    Task<Void> stop();\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/java/com/google/android/gms/nearby/exposurenotification/ExposureNotificationStatus.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.nearby.exposurenotification;\n\nimport org.microg.gms.common.PublicApi;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * Detail status for exposure notification service.\n */\n@PublicApi\npublic enum ExposureNotificationStatus {\n    /**\n     * Exposure notification is running.\n     */\n    ACTIVATED,\n    /**\n     * Exposure notification is not running.\n     */\n    INACTIVATED,\n    /**\n     * Bluetooth is not enabled.\n     */\n    BLUETOOTH_DISABLED,\n    /**\n     * Location is not enabled.\n     */\n    LOCATION_DISABLED,\n    /**\n     * User is not consent for the client.\n     */\n    NO_CONSENT,\n    /**\n     * The client is not in approved client list.\n     */\n    NOT_IN_ALLOWLIST,\n    /**\n     * Can't detected the BLE supporting of this device due to bluetooth is not enabled.\n     */\n    BLUETOOTH_SUPPORT_UNKNOWN,\n    /**\n     * Hardware of this device doesn't support exposure notification.\n     */\n    HW_NOT_SUPPORT,\n    /**\n     * There is another client running as active client.\n     */\n    FOCUS_LOST,\n    /**\n     * Device storage is not sufficient for exposure notification.\n     */\n    LOW_STORAGE,\n    /**\n     * Current status is unknown.\n     */\n    UNKNOWN,\n    /**\n     * Exposure notification is not supported.\n     */\n    EN_NOT_SUPPORT,\n    /**\n     * Exposure notification is not supported for current user profile.\n     */\n    USER_PROFILE_NOT_SUPPORT,\n    @Deprecated\n    NOT_IN_WHITELIST\n    ;\n\n    private long flag() {\n        if (this == NOT_IN_WHITELIST) return NOT_IN_ALLOWLIST.flag();\n        return 1 << ordinal();\n    }\n\n    @PublicApi(exclude = true)\n    public static long setToFlags(Set<ExposureNotificationStatus> set) {\n        long res = 0;\n        for (ExposureNotificationStatus status : set) {\n            res |= status.flag();\n        }\n        return res;\n    }\n\n    @PublicApi(exclude = true)\n    public static Set<ExposureNotificationStatus> flagsToSet(long flags) {\n        Set<ExposureNotificationStatus> set = new HashSet<>();\n        for (ExposureNotificationStatus status : values()) {\n            if (status == NOT_IN_WHITELIST) continue;\n            if ((flags & status.flag()) > 0) {\n                set.add(status);\n                if (status == NOT_IN_ALLOWLIST) set.add(NOT_IN_WHITELIST);\n            }\n        }\n        return set;\n    }\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/java/com/google/android/gms/nearby/exposurenotification/ExposureNotificationStatusCodes.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0 AND CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.nearby.exposurenotification;\n\nimport com.google.android.gms.common.api.CommonStatusCodes;\n\npublic class ExposureNotificationStatusCodes extends CommonStatusCodes {\n    public static final int FAILED = 13;\n    public static final int FAILED_ALREADY_STARTED = 39500;\n    public static final int FAILED_NOT_SUPPORTED = 39501;\n    public static final int FAILED_REJECTED_OPT_IN = 39502;\n    public static final int FAILED_SERVICE_DISABLED = 39503;\n    public static final int FAILED_BLUETOOTH_DISABLED = 39504;\n    public static final int FAILED_TEMPORARILY_DISABLED = 39505;\n    public static final int FAILED_DISK_IO = 39506;\n    public static final int FAILED_UNAUTHORIZED = 39507;\n    public static final int FAILED_RATE_LIMITED = 39508;\n    public static final int FAILED_NOT_IN_FOREGROUND = 39509;\n    public static final int FAILED_KEY_RELEASE_NOT_PREAUTHORIZED = 39510;\n\n    public static String getStatusCodeString(final int statusCode) {\n        switch (statusCode) {\n            case FAILED_ALREADY_STARTED:\n                return \"FAILED_ALREADY_STARTED\";\n            case FAILED_NOT_SUPPORTED:\n                return \"FAILED_NOT_SUPPORTED\";\n            case FAILED_REJECTED_OPT_IN:\n                return \"FAILED_REJECTED_OPT_IN\";\n            case FAILED_SERVICE_DISABLED:\n                return \"FAILED_SERVICE_DISABLED\";\n            case FAILED_BLUETOOTH_DISABLED:\n                return \"FAILED_BLUETOOTH_DISABLED\";\n            case FAILED_TEMPORARILY_DISABLED:\n                return \"FAILED_TEMPORARILY_DISABLED\";\n            case FAILED_DISK_IO:\n                return \"FAILED_DISK_IO\";\n            case FAILED_UNAUTHORIZED:\n                return \"FAILED_UNAUTHORIZED\";\n            case FAILED_RATE_LIMITED:\n                return \"FAILED_RATE_LIMITED\";\n            case FAILED_NOT_IN_FOREGROUND:\n                return \"FAILED_NOT_IN_FOREGROUND\";\n            case FAILED_KEY_RELEASE_NOT_PREAUTHORIZED:\n                return \"FAILED_KEY_RELEASE_NOT_PREAUTHORIZED\";\n            default:\n                return CommonStatusCodes.getStatusCodeString(statusCode);\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/java/com/google/android/gms/nearby/exposurenotification/ExposureSummary.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0 AND CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.nearby.exposurenotification;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\nimport java.util.Arrays;\n\n@Deprecated\npublic class ExposureSummary extends AutoSafeParcelable {\n    @Field(1)\n    private int daysSinceLastExposure;\n    @Field(2)\n    private int matchedKeyCount;\n    @Field(3)\n    private int maximumRiskScore;\n    @Field(4)\n    private int[] attenuationDurationsInMinutes;\n    @Field(5)\n    private int summationRiskScore;\n\n    private ExposureSummary() {\n    }\n\n    ExposureSummary(int daysSinceLastExposure, int matchedKeyCount, int maximumRiskScore, int[] attenuationDurationsInMinutes, int summationRiskScore) {\n        this.daysSinceLastExposure = daysSinceLastExposure;\n        this.matchedKeyCount = matchedKeyCount;\n        this.maximumRiskScore = maximumRiskScore;\n        this.attenuationDurationsInMinutes = attenuationDurationsInMinutes;\n        this.summationRiskScore = summationRiskScore;\n    }\n\n    public int getDaysSinceLastExposure() {\n        return daysSinceLastExposure;\n    }\n\n    public int getMatchedKeyCount() {\n        return matchedKeyCount;\n    }\n\n    public int getMaximumRiskScore() {\n        return maximumRiskScore;\n    }\n\n    public int[] getAttenuationDurationsInMinutes() {\n        return Arrays.copyOf(attenuationDurationsInMinutes, attenuationDurationsInMinutes.length);\n    }\n\n    public int getSummationRiskScore() {\n        return summationRiskScore;\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        ExposureSummary that = (ExposureSummary) o;\n\n        if (daysSinceLastExposure != that.daysSinceLastExposure) return false;\n        if (matchedKeyCount != that.matchedKeyCount) return false;\n        if (maximumRiskScore != that.maximumRiskScore) return false;\n        if (summationRiskScore != that.summationRiskScore) return false;\n        return Arrays.equals(attenuationDurationsInMinutes, that.attenuationDurationsInMinutes);\n    }\n\n    @Override\n    public int hashCode() {\n        int result = daysSinceLastExposure;\n        result = 31 * result + matchedKeyCount;\n        result = 31 * result + maximumRiskScore;\n        result = 31 * result + Arrays.hashCode(attenuationDurationsInMinutes);\n        result = 31 * result + summationRiskScore;\n        return result;\n    }\n\n    @Override\n    public String toString() {\n        return \"ExposureSummary{\" +\n                \"daysSinceLastExposure=\" + daysSinceLastExposure +\n                \", matchedKeyCount=\" + matchedKeyCount +\n                \", maximumRiskScore=\" + maximumRiskScore +\n                \", attenuationDurationsInMinutes=\" + Arrays.toString(attenuationDurationsInMinutes) +\n                \", summationRiskScore=\" + summationRiskScore +\n                '}';\n    }\n\n    public static class ExposureSummaryBuilder {\n        private int daysSinceLastExposure;\n        private int matchedKeyCount;\n        private int maximumRiskScore;\n        private int[] attenuationDurations = new int[]{0, 0, 0};\n        private int summationRiskScore;\n\n        public ExposureSummaryBuilder setDaysSinceLastExposure(int daysSinceLastExposure) {\n            this.daysSinceLastExposure = daysSinceLastExposure;\n            return this;\n        }\n\n        public ExposureSummaryBuilder setMatchedKeyCount(int matchedKeyCount) {\n            this.matchedKeyCount = matchedKeyCount;\n            return this;\n        }\n\n        public ExposureSummaryBuilder setMaximumRiskScore(int maximumRiskScore) {\n            this.maximumRiskScore = maximumRiskScore;\n            return this;\n        }\n\n        public ExposureSummaryBuilder setAttenuationDurations(int[] attenuationDurations) {\n            this.attenuationDurations = Arrays.copyOf(attenuationDurations, attenuationDurations.length);\n            return this;\n        }\n\n        public ExposureSummaryBuilder setSummationRiskScore(int summationRiskScore) {\n            this.summationRiskScore = summationRiskScore;\n            return this;\n        }\n\n        public ExposureSummary build() {\n            return new ExposureSummary(daysSinceLastExposure, matchedKeyCount, maximumRiskScore, attenuationDurations, summationRiskScore);\n        }\n    }\n\n    public static final Creator<ExposureSummary> CREATOR = new AutoCreator<>(ExposureSummary.class);\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/java/com/google/android/gms/nearby/exposurenotification/ExposureWindow.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.nearby.exposurenotification;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * A duration of up to 30 minutes during which beacons from a TEK were observed.\n * <p>\n * Each {@link ExposureWindow} corresponds to a single TEK, but one TEK can lead to several {@link ExposureWindow} due to random 15-30 minutes cuts. See {@link ExposureNotificationClient#getExposureWindows()} for more info.\n * <p>\n * The TEK itself isn't exposed by the API.\n */\n@PublicApi\npublic class ExposureWindow extends AutoSafeParcelable {\n    @Field(1)\n    private long dateMillisSinceEpoch;\n    @Field(2)\n    private List<ScanInstance> scanInstances;\n    @Field(3)\n    @ReportType\n    private int reportType;\n    @Field(4)\n    @Infectiousness\n    private int infectiousness;\n    @Field(5)\n    @CalibrationConfidence\n    private int calibrationConfidence;\n\n    private ExposureWindow() {\n    }\n\n    private ExposureWindow(long dateMillisSinceEpoch, List<ScanInstance> scanInstances, int reportType, int infectiousness, int calibrationConfidence) {\n        this.dateMillisSinceEpoch = dateMillisSinceEpoch;\n        this.scanInstances = scanInstances;\n        this.reportType = reportType;\n        this.infectiousness = infectiousness;\n        this.calibrationConfidence = calibrationConfidence;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof ExposureWindow)) return false;\n\n        ExposureWindow that = (ExposureWindow) o;\n\n        if (dateMillisSinceEpoch != that.dateMillisSinceEpoch) return false;\n        if (reportType != that.reportType) return false;\n        if (infectiousness != that.infectiousness) return false;\n        if (calibrationConfidence != that.calibrationConfidence) return false;\n        return scanInstances != null ? scanInstances.equals(that.scanInstances) : that.scanInstances == null;\n    }\n\n    /**\n     * Confidence of the BLE Transmit power calibration of the transmitting device.\n     */\n    @CalibrationConfidence\n    public int getCalibrationConfidence() {\n        return calibrationConfidence;\n    }\n\n    /**\n     * Returns the epoch time in milliseconds the exposure occurred. This will represent the start of a day in UTC.\n     */\n    public long getDateMillisSinceEpoch() {\n        return dateMillisSinceEpoch;\n    }\n\n    /**\n     * Infectiousness of the TEK that caused this exposure, computed from the days since onset of symptoms using the daysToInfectiousnessMapping.\n     */\n    @Infectiousness\n    public int getInfectiousness() {\n        return infectiousness;\n    }\n\n    /**\n     * Report Type of the TEK that caused this exposure\n     * <p>\n     * TEKs with no report type set are returned with reportType=CONFIRMED_TEST.\n     * <p>\n     * TEKs with RECURSIVE report type may be dropped because this report type is reserved for future use.\n     * <p>\n     * TEKs with REVOKED or invalid report types do not lead to exposures.\n     */\n    @ReportType\n    public int getReportType() {\n        return reportType;\n    }\n\n    /**\n     * Sightings of this ExposureWindow, time-ordered.\n     * <p>\n     * Each sighting corresponds to a scan (of a few seconds) during which a beacon with the TEK causing this exposure was observed.\n     */\n    public List<ScanInstance> getScanInstances() {\n        return scanInstances;\n    }\n\n    @Override\n    public int hashCode() {\n        int result = (int) (dateMillisSinceEpoch ^ (dateMillisSinceEpoch >>> 32));\n        result = 31 * result + (scanInstances != null ? scanInstances.hashCode() : 0);\n        result = 31 * result + reportType;\n        result = 31 * result + infectiousness;\n        result = 31 * result + calibrationConfidence;\n        return result;\n    }\n\n    /**\n     * Builder for ExposureWindow.\n     */\n    public static class Builder {\n        private long dateMillisSinceEpoch;\n        private List<ScanInstance> scanInstances;\n        @ReportType\n        private int reportType;\n        @Infectiousness\n        private int infectiousness;\n        @CalibrationConfidence\n        private int calibrationConfidence;\n\n        public ExposureWindow build() {\n            return new ExposureWindow(dateMillisSinceEpoch, scanInstances, reportType, infectiousness, calibrationConfidence);\n        }\n\n        public Builder setCalibrationConfidence(int calibrationConfidence) {\n            this.calibrationConfidence = calibrationConfidence;\n            return this;\n        }\n\n        public Builder setDateMillisSinceEpoch(long dateMillisSinceEpoch) {\n            this.dateMillisSinceEpoch = dateMillisSinceEpoch;\n            return this;\n        }\n\n        public Builder setInfectiousness(@Infectiousness int infectiousness) {\n            this.infectiousness = infectiousness;\n            return this;\n        }\n\n        public Builder setReportType(@ReportType int reportType) {\n            this.reportType = reportType;\n            return this;\n        }\n\n        public Builder setScanInstances(List<ScanInstance> scanInstances) {\n            this.scanInstances = new ArrayList<>(scanInstances);\n            return this;\n        }\n    }\n\n    public static final Creator<ExposureWindow> CREATOR = new AutoCreator<>(ExposureWindow.class);\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/java/com/google/android/gms/nearby/exposurenotification/Infectiousness.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.nearby.exposurenotification;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Infectiousness defined for an {@link ExposureWindow}.\n */\n@PublicApi\npublic @interface Infectiousness {\n    int NONE = 0;\n    int STANDARD = 1;\n    int HIGH = 2;\n\n    @PublicApi(exclude = true)\n    int VALUES = 3;\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/java/com/google/android/gms/nearby/exposurenotification/PackageConfiguration.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification;\n\nimport android.os.Bundle;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n/**\n * Holds configuration values that can be passed onto the client app after it has finished installing via {@link ExposureNotificationClient#getPackageConfiguration()}.\n */\n@PublicApi\npublic class PackageConfiguration extends AutoSafeParcelable {\n    @Field(1)\n    private Bundle values;\n\n    @PublicApi(exclude = true)\n    public PackageConfiguration() {\n    }\n\n    @PublicApi(exclude = true)\n    public PackageConfiguration(Bundle values) {\n        this.values = values;\n    }\n\n    public Bundle getValues() {\n        return values;\n    }\n\n    /**\n     * A builder for {@link PackageConfiguration}.\n     */\n    public static final class PackageConfigurationBuilder {\n        private Bundle values;\n\n        /**\n         * Sets a Bundle containing configuration options.\n         */\n        public PackageConfigurationBuilder setValues(Bundle values) {\n            this.values = values;\n            return this;\n        }\n\n        /**\n         * Builds a {@link PackageConfiguration}.\n         */\n        public PackageConfiguration build() {\n            return new PackageConfiguration(values);\n        }\n    }\n\n    public static final Creator<PackageConfiguration> CREATOR = new AutoCreator<>(PackageConfiguration.class);\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/java/com/google/android/gms/nearby/exposurenotification/ReportType.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.nearby.exposurenotification;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Report type defined for a {@link TemporaryExposureKey}.\n */\n@PublicApi\npublic @interface ReportType {\n    int UNKNOWN = 0;\n    int CONFIRMED_TEST = 1;\n    int CONFIRMED_CLINICAL_DIAGNOSIS = 2;\n    int SELF_REPORT = 3;\n    int RECURSIVE = 4;\n    int REVOKED = 5;\n\n    @PublicApi(exclude = true)\n    int VALUES = 6;\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/java/com/google/android/gms/nearby/exposurenotification/RiskLevel.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0 AND CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.nearby.exposurenotification;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Risk level defined for an {@link TemporaryExposureKey}.\n */\n@PublicApi\npublic @interface RiskLevel {\n    int RISK_LEVEL_INVALID = 0;\n    int RISK_LEVEL_LOWEST = 1;\n    int RISK_LEVEL_LOW = 2;\n    int RISK_LEVEL_LOW_MEDIUM = 3;\n    int RISK_LEVEL_MEDIUM = 4;\n    int RISK_LEVEL_MEDIUM_HIGH = 5;\n    int RISK_LEVEL_HIGH = 6;\n    int RISK_LEVEL_VERY_HIGH = 7;\n    int RISK_LEVEL_HIGHEST = 8;\n\n    @PublicApi(exclude = true)\n    int VALUES = 9;\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/java/com/google/android/gms/nearby/exposurenotification/ScanInstance.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.nearby.exposurenotification;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n/**\n * Information about the sighting of a TEK within a BLE scan (of a few seconds).\n * <p>\n * The TEK itself isn't exposed by the API.\n */\n@PublicApi\npublic class ScanInstance extends AutoSafeParcelable {\n    @Field(1)\n    private int typicalAttenuationDb;\n    @Field(2)\n    private int minAttenuationDb;\n    @Field(3)\n    private int secondsSinceLastScan;\n\n    private ScanInstance() {\n    }\n\n    private ScanInstance(int typicalAttenuationDb, int minAttenuationDb, int secondsSinceLastScan) {\n        this.typicalAttenuationDb = typicalAttenuationDb;\n        this.minAttenuationDb = minAttenuationDb;\n        this.secondsSinceLastScan = secondsSinceLastScan;\n    }\n\n    /**\n     * Minimum attenuation of all of this TEK's beacons received during the scan, in dB.\n     */\n    public int getMinAttenuationDb() {\n        return minAttenuationDb;\n    }\n\n    /**\n     * Seconds elapsed since the previous scan, typically used as a weight.\n     * <p>\n     * Two example uses:\n     * - Summing those values over all sightings of an exposure provides the duration of that exposure.\n     * - Summing those values over all sightings in a given attenuation range and over all exposures recreates the durationAtBuckets of v1.\n     * <p>\n     * Note that the previous scan may not have led to a sighting of that TEK.\n     */\n    public int getSecondsSinceLastScan() {\n        return secondsSinceLastScan;\n    }\n\n    /**\n     * Aggregation of the attenuations of all of this TEK's beacons received during the scan, in dB. This is most likely to be an average in the dB domain.\n     */\n    public int getTypicalAttenuationDb() {\n        return typicalAttenuationDb;\n    }\n\n    /**\n     * Builder for {@link ScanInstance}.\n     */\n    public static class Builder {\n        private int typicalAttenuationDb;\n        private int minAttenuationDb;\n        private int secondsSinceLastScan;\n\n        public ScanInstance build() {\n            return new ScanInstance(typicalAttenuationDb, minAttenuationDb, secondsSinceLastScan);\n        }\n\n        public ScanInstance.Builder setMinAttenuationDb(int minAttenuationDb) {\n            this.minAttenuationDb = minAttenuationDb;\n            return this;\n        }\n\n        public ScanInstance.Builder setSecondsSinceLastScan(int secondsSinceLastScan) {\n            this.secondsSinceLastScan = secondsSinceLastScan;\n            return this;\n        }\n\n        public ScanInstance.Builder setTypicalAttenuationDb(int typicalAttenuationDb) {\n            this.typicalAttenuationDb = typicalAttenuationDb;\n            return this;\n        }\n    }\n\n    public static final Creator<ScanInstance> CREATOR = new AutoCreator<>(ScanInstance.class);\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/java/com/google/android/gms/nearby/exposurenotification/TemporaryExposureKey.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0 AND CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.nearby.exposurenotification;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\nimport java.util.Arrays;\n\n/**\n * A key generated for advertising over a window of time.\n */\npublic class TemporaryExposureKey extends AutoSafeParcelable {\n    @Field(1)\n    private byte[] keyData;\n    @Field(2)\n    private int rollingStartIntervalNumber;\n    @Field(3)\n    @RiskLevel\n    private int transmissionRiskLevel;\n    @Field(4)\n    private int rollingPeriod;\n    @Field(5)\n    @ReportType\n    private int reportType;\n    @Field(6)\n    int daysSinceOnsetOfSymptoms;\n\n    /**\n     * The default value for {@link #getDaysSinceOnsetOfSymptoms()}.\n     *\n     * See {@link DiagnosisKeysDataMapping#getDaysSinceOnsetToInfectiousness()} for more information.\n     */\n    public static final int DAYS_SINCE_ONSET_OF_SYMPTOMS_UNKNOWN = Integer.MAX_VALUE;\n\n    private TemporaryExposureKey() {\n    }\n\n    TemporaryExposureKey(byte[] keyData, int rollingStartIntervalNumber, @RiskLevel int transmissionRiskLevel, int rollingPeriod, @ReportType int reportType, int daysSinceOnsetOfSymptoms) {\n        this.keyData = (keyData == null ? new byte[0] : keyData);\n        this.rollingStartIntervalNumber = rollingStartIntervalNumber;\n        this.transmissionRiskLevel = transmissionRiskLevel;\n        this.rollingPeriod = rollingPeriod;\n        this.reportType = reportType;\n        this.daysSinceOnsetOfSymptoms = daysSinceOnsetOfSymptoms;\n    }\n\n    /**\n     * The randomly generated Temporary Exposure Key information.\n     */\n    public byte[] getKeyData() {\n        return Arrays.copyOf(keyData, keyData.length);\n    }\n\n    /**\n     * A number describing when a key starts. It is equal to startTimeOfKeySinceEpochInSecs / (60 * 10).\n     */\n    public int getRollingStartIntervalNumber() {\n        return rollingStartIntervalNumber;\n    }\n\n    /**\n     * Risk of transmission associated with the person this key came from.\n     */\n    @RiskLevel\n    public int getTransmissionRiskLevel() {\n        return transmissionRiskLevel;\n    }\n\n    /**\n     * A number describing how long a key is valid. It is expressed in increments of 10 minutes (e.g. 144 for 24 hours).\n     */\n    public int getRollingPeriod() {\n        return rollingPeriod;\n    }\n\n    /**\n     * Type of diagnosis associated with a key.\n     */\n    @ReportType\n    public int getReportType() {\n        return reportType;\n    }\n\n    /**\n     * Number of days elapsed between symptom onset and the key being used.\n     * <p>\n     * E.g. 2 means the key is 2 days after onset of symptoms.\n     */\n    public int getDaysSinceOnsetOfSymptoms() {\n        return daysSinceOnsetOfSymptoms;\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        TemporaryExposureKey that = (TemporaryExposureKey) o;\n\n        if (rollingStartIntervalNumber != that.rollingStartIntervalNumber) return false;\n        if (transmissionRiskLevel != that.transmissionRiskLevel) return false;\n        if (rollingPeriod != that.rollingPeriod) return false;\n        if (reportType != that.reportType) return false;\n        if (daysSinceOnsetOfSymptoms != that.daysSinceOnsetOfSymptoms) return false;\n        return Arrays.equals(keyData, that.keyData);\n    }\n\n    @Override\n    public int hashCode() {\n        int result = Arrays.hashCode(keyData);\n        result = 31 * result + rollingStartIntervalNumber;\n        result = 31 * result + transmissionRiskLevel;\n        result = 31 * result + rollingPeriod;\n        result = 31 * result + reportType;\n        result = 31 * result + daysSinceOnsetOfSymptoms;\n        return result;\n    }\n\n    @Override\n    public String toString() {\n        return \"TemporaryExposureKey{\" +\n                \"keyData=\" + Arrays.toString(keyData) +\n                \", rollingStartIntervalNumber=\" + rollingStartIntervalNumber +\n                \", transmissionRiskLevel=\" + transmissionRiskLevel +\n                \", rollingPeriod=\" + rollingPeriod +\n                \", reportType=\" + reportType +\n                \", daysSinceOnsetOfSymptoms=\" + daysSinceOnsetOfSymptoms +\n                '}';\n    }\n\n    /**\n     * A builder for {@link TemporaryExposureKey}.\n     */\n    public static class TemporaryExposureKeyBuilder {\n        private byte[] keyData;\n        private int rollingStartIntervalNumber;\n        @RiskLevel\n        private int transmissionRiskLevel;\n        private int rollingPeriod;\n        @ReportType\n        private int reportType;\n        private int daysSinceOnsetOfSymptoms = DAYS_SINCE_ONSET_OF_SYMPTOMS_UNKNOWN;\n\n        public TemporaryExposureKeyBuilder setKeyData(byte[] keyData) {\n            this.keyData = Arrays.copyOf(keyData, keyData.length);\n            return this;\n        }\n\n        public TemporaryExposureKeyBuilder setRollingStartIntervalNumber(int rollingStartIntervalNumber) {\n            this.rollingStartIntervalNumber = rollingStartIntervalNumber;\n            return this;\n        }\n\n        public TemporaryExposureKeyBuilder setTransmissionRiskLevel(@RiskLevel int transmissionRiskLevel) {\n            this.transmissionRiskLevel = transmissionRiskLevel;\n            return this;\n        }\n\n        public TemporaryExposureKeyBuilder setRollingPeriod(int rollingPeriod) {\n            this.rollingPeriod = rollingPeriod;\n            return this;\n        }\n\n        public TemporaryExposureKeyBuilder setReportType(@ReportType int reportType) {\n            this.reportType = reportType;\n            return this;\n        }\n\n        public TemporaryExposureKeyBuilder setDaysSinceOnsetOfSymptoms(int daysSinceOnsetOfSymptoms) {\n            this.daysSinceOnsetOfSymptoms = daysSinceOnsetOfSymptoms;\n            return this;\n        }\n\n        public TemporaryExposureKey build() {\n            return new TemporaryExposureKey(keyData, rollingStartIntervalNumber, transmissionRiskLevel, rollingPeriod, reportType, daysSinceOnsetOfSymptoms);\n        }\n    }\n\n    public static final Creator<TemporaryExposureKey> CREATOR = new AutoCreator<>(TemporaryExposureKey.class);\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/java/com/google/android/gms/nearby/exposurenotification/WakeUpService.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification;\n\nimport android.app.Service;\nimport android.content.Intent;\nimport android.os.Handler;\nimport android.os.IBinder;\nimport android.os.Messenger;\nimport androidx.annotation.Nullable;\n\npublic class WakeUpService extends Service {\n    @Nullable\n    @Override\n    public IBinder onBind(Intent intent) {\n        return new Messenger(new Handler()).getBinder();\n    }\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/java/com/google/android/gms/nearby/exposurenotification/internal/GetCalibrationConfidenceParams.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class GetCalibrationConfidenceParams extends AutoSafeParcelable {\n    @Field(1)\n    public IIntCallback callback;\n\n    private GetCalibrationConfidenceParams() {}\n\n    public GetCalibrationConfidenceParams(IIntCallback callback) {\n        this.callback = callback;\n    }\n\n    public static final Creator<GetCalibrationConfidenceParams> CREATOR = new AutoCreator<>(GetCalibrationConfidenceParams.class);\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/java/com/google/android/gms/nearby/exposurenotification/internal/GetDailySummariesParams.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nimport com.google.android.gms.nearby.exposurenotification.DailySummariesConfig;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class GetDailySummariesParams extends AutoSafeParcelable {\n    @Field(1)\n    public IDailySummaryListCallback callback;\n    @Field(2)\n    public DailySummariesConfig config;\n\n    private GetDailySummariesParams() {}\n\n    public GetDailySummariesParams(IDailySummaryListCallback callback, DailySummariesConfig config) {\n        this.callback = callback;\n        this.config = config;\n    }\n\n    public static final Creator<GetDailySummariesParams> CREATOR = new AutoCreator<>(GetDailySummariesParams.class);\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/java/com/google/android/gms/nearby/exposurenotification/internal/GetDiagnosisKeysDataMappingParams.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class GetDiagnosisKeysDataMappingParams extends AutoSafeParcelable {\n    @Field(1)\n    public IDiagnosisKeysDataMappingCallback callback;\n\n    private GetDiagnosisKeysDataMappingParams() {}\n\n    public GetDiagnosisKeysDataMappingParams(IDiagnosisKeysDataMappingCallback callback) {\n        this.callback = callback;\n    }\n\n    public static final Creator<GetDiagnosisKeysDataMappingParams> CREATOR = new AutoCreator<>(GetDiagnosisKeysDataMappingParams.class);\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/java/com/google/android/gms/nearby/exposurenotification/internal/GetExposureInformationParams.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class GetExposureInformationParams extends AutoSafeParcelable {\n    @Field(2)\n    public IExposureInformationListCallback callback;\n    @Field(3)\n    public String token;\n\n    private GetExposureInformationParams() {}\n\n    public GetExposureInformationParams(IExposureInformationListCallback callback, String token) {\n        this.callback = callback;\n        this.token = token;\n    }\n\n    public static final Creator<GetExposureInformationParams> CREATOR = new AutoCreator<>(GetExposureInformationParams.class);\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/java/com/google/android/gms/nearby/exposurenotification/internal/GetExposureSummaryParams.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class GetExposureSummaryParams extends AutoSafeParcelable {\n    @Field(2)\n    public IExposureSummaryCallback callback;\n    @Field(3)\n    public String token;\n\n    private GetExposureSummaryParams() {}\n\n    public GetExposureSummaryParams(IExposureSummaryCallback callback, String token) {\n        this.callback = callback;\n        this.token = token;\n    }\n\n    public static final Creator<GetExposureSummaryParams> CREATOR = new AutoCreator<>(GetExposureSummaryParams.class);\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/java/com/google/android/gms/nearby/exposurenotification/internal/GetExposureWindowsParams.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class GetExposureWindowsParams extends AutoSafeParcelable {\n    @Field(1)\n    public IExposureWindowListCallback callback;\n    @Field(2)\n    public String token;\n\n    private GetExposureWindowsParams() {}\n\n    public GetExposureWindowsParams(IExposureWindowListCallback callback, String token) {\n        this.callback = callback;\n        this.token = token;\n    }\n\n    public static final Creator<GetExposureWindowsParams> CREATOR = new AutoCreator<>(GetExposureWindowsParams.class);\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/java/com/google/android/gms/nearby/exposurenotification/internal/GetPackageConfigurationParams.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class GetPackageConfigurationParams extends AutoSafeParcelable {\n    @Field(1)\n    public IPackageConfigurationCallback callback;\n\n    private GetPackageConfigurationParams() {}\n\n    public GetPackageConfigurationParams(IPackageConfigurationCallback callback) {\n        this.callback = callback;\n    }\n\n    public static final Creator<GetPackageConfigurationParams> CREATOR = new AutoCreator<>(GetPackageConfigurationParams.class);\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/java/com/google/android/gms/nearby/exposurenotification/internal/GetStatusParams.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class GetStatusParams extends AutoSafeParcelable {\n    @Field(1)\n    public ILongCallback callback;\n\n    private GetStatusParams() {}\n\n    public GetStatusParams(ILongCallback callback) {\n        this.callback = callback;\n    }\n\n    public static final Creator<GetStatusParams> CREATOR = new AutoCreator<>(GetStatusParams.class);\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/java/com/google/android/gms/nearby/exposurenotification/internal/GetTemporaryExposureKeyHistoryParams.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class GetTemporaryExposureKeyHistoryParams extends AutoSafeParcelable {\n    @Field(2)\n    public ITemporaryExposureKeyListCallback callback;\n\n    private GetTemporaryExposureKeyHistoryParams() {}\n\n    public GetTemporaryExposureKeyHistoryParams(ITemporaryExposureKeyListCallback callback) {\n        this.callback = callback;\n    }\n\n    public static final Creator<GetTemporaryExposureKeyHistoryParams> CREATOR = new AutoCreator<>(GetTemporaryExposureKeyHistoryParams.class);\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/java/com/google/android/gms/nearby/exposurenotification/internal/GetVersionParams.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class GetVersionParams extends AutoSafeParcelable {\n    @Field(1)\n    public ILongCallback callback;\n\n    private GetVersionParams() {\n    }\n\n    public GetVersionParams(ILongCallback callback) {\n        this.callback = callback;\n    }\n\n    public static final Creator<GetVersionParams> CREATOR = new AutoCreator<>(GetVersionParams.class);\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/java/com/google/android/gms/nearby/exposurenotification/internal/IsEnabledParams.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class IsEnabledParams extends AutoSafeParcelable {\n    @Field(2)\n    public IBooleanCallback callback;\n\n    private IsEnabledParams() {\n    }\n\n    public IsEnabledParams(IBooleanCallback callback) {\n        this.callback = callback;\n    }\n\n    public static final Creator<IsEnabledParams> CREATOR = new AutoCreator<>(IsEnabledParams.class);\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/java/com/google/android/gms/nearby/exposurenotification/internal/ProvideDiagnosisKeysParams.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nimport android.os.ParcelFileDescriptor;\n\nimport androidx.annotation.Nullable;\n\nimport com.google.android.gms.common.api.internal.IStatusCallback;\nimport com.google.android.gms.nearby.exposurenotification.ExposureConfiguration;\nimport com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\nimport java.util.List;\n\npublic class ProvideDiagnosisKeysParams extends AutoSafeParcelable {\n    @Field(1)\n    @Nullable\n    public List<TemporaryExposureKey> keys;\n    @Field(2)\n    public IStatusCallback callback;\n    @Field(3)\n    @Nullable\n    public List<ParcelFileDescriptor> keyFiles;\n    @Field(4)\n    @Nullable\n    public ExposureConfiguration configuration;\n    @Field(5)\n    @Nullable\n    public String token;\n    @Field(6)\n    @Nullable\n    public IDiagnosisKeyFileSupplier keyFileSupplier;\n\n    private ProvideDiagnosisKeysParams() {\n    }\n\n    public ProvideDiagnosisKeysParams(IStatusCallback callback, List<TemporaryExposureKey> keys, List<ParcelFileDescriptor> keyFiles, ExposureConfiguration configuration, String token) {\n        this(callback, keyFiles, configuration, token);\n        this.keys = keys;\n    }\n\n    public ProvideDiagnosisKeysParams(IStatusCallback callback, List<ParcelFileDescriptor> keyFiles, ExposureConfiguration configuration, String token) {\n        this.callback = callback;\n        this.keyFiles = keyFiles;\n        this.configuration = configuration;\n        this.token = token;\n    }\n\n    public ProvideDiagnosisKeysParams(IStatusCallback callback, IDiagnosisKeyFileSupplier keyFileSupplier) {\n        this.callback = callback;\n        this.keyFileSupplier = keyFileSupplier;\n    }\n\n    public static final Creator<ProvideDiagnosisKeysParams> CREATOR = new AutoCreator<>(ProvideDiagnosisKeysParams.class);\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/java/com/google/android/gms/nearby/exposurenotification/internal/RequestPreAuthorizedTemporaryExposureKeyHistoryParams.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nimport com.google.android.gms.common.api.internal.IStatusCallback;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class RequestPreAuthorizedTemporaryExposureKeyHistoryParams extends AutoSafeParcelable {\n    @Field(1)\n    public IStatusCallback callback;\n\n    private RequestPreAuthorizedTemporaryExposureKeyHistoryParams() {\n    }\n\n    public RequestPreAuthorizedTemporaryExposureKeyHistoryParams(IStatusCallback callback) {\n        this.callback = callback;\n    }\n\n    public static final Creator<RequestPreAuthorizedTemporaryExposureKeyHistoryParams> CREATOR = new AutoCreator<>(RequestPreAuthorizedTemporaryExposureKeyHistoryParams.class);\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/java/com/google/android/gms/nearby/exposurenotification/internal/RequestPreAuthorizedTemporaryExposureKeyReleaseParams.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nimport com.google.android.gms.common.api.internal.IStatusCallback;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class RequestPreAuthorizedTemporaryExposureKeyReleaseParams extends AutoSafeParcelable {\n    @Field(1)\n    public IStatusCallback callback;\n\n    private RequestPreAuthorizedTemporaryExposureKeyReleaseParams() {\n    }\n\n    public RequestPreAuthorizedTemporaryExposureKeyReleaseParams(IStatusCallback callback) {\n        this.callback = callback;\n    }\n\n    public static final Creator<RequestPreAuthorizedTemporaryExposureKeyReleaseParams> CREATOR = new AutoCreator<>(RequestPreAuthorizedTemporaryExposureKeyReleaseParams.class);\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/java/com/google/android/gms/nearby/exposurenotification/internal/SetDiagnosisKeysDataMappingParams.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nimport com.google.android.gms.common.api.internal.IStatusCallback;\nimport com.google.android.gms.nearby.exposurenotification.DiagnosisKeysDataMapping;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class SetDiagnosisKeysDataMappingParams extends AutoSafeParcelable {\n    @Field(1)\n    public IStatusCallback callback;\n    @Field(2)\n    public DiagnosisKeysDataMapping mapping;\n\n    private SetDiagnosisKeysDataMappingParams() {}\n\n    public SetDiagnosisKeysDataMappingParams(IStatusCallback callback, DiagnosisKeysDataMapping mapping) {\n        this.callback = callback;\n        this.mapping = mapping;\n    }\n\n    public static final Creator<SetDiagnosisKeysDataMappingParams> CREATOR = new AutoCreator<>(SetDiagnosisKeysDataMappingParams.class);\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/java/com/google/android/gms/nearby/exposurenotification/internal/StartParams.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nimport com.google.android.gms.common.api.internal.IStatusCallback;\nimport com.google.android.gms.nearby.exposurenotification.ExposureConfiguration;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class StartParams extends AutoSafeParcelable {\n    @Field(3)\n    public IStatusCallback callback;\n    @Field(4)\n    public ExposureConfiguration configuration;\n\n    private StartParams() {\n    }\n\n    public StartParams(IStatusCallback callback) {\n        this.callback = callback;\n    }\n\n    public static final Creator<StartParams> CREATOR = new AutoCreator<>(StartParams.class);\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/java/com/google/android/gms/nearby/exposurenotification/internal/StopParams.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.nearby.exposurenotification.internal;\n\nimport com.google.android.gms.common.api.internal.IStatusCallback;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class StopParams extends AutoSafeParcelable {\n    @Field(1)\n    public IStatusCallback callback;\n\n    private StopParams() {\n    }\n\n    public StopParams(IStatusCallback callback) {\n        this.callback = callback;\n    }\n\n    public static final Creator<StopParams> CREATOR = new AutoCreator<>(StopParams.class);\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/java/org/microg/gms/nearby/ExposureNotificationApiClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.nearby;\n\nimport android.content.Context;\nimport android.os.IBinder;\nimport android.os.RemoteException;\n\nimport com.google.android.gms.nearby.exposurenotification.internal.GetCalibrationConfidenceParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.GetDailySummariesParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.GetDiagnosisKeysDataMappingParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.GetExposureInformationParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.GetExposureSummaryParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.GetExposureWindowsParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.GetPackageConfigurationParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.GetStatusParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.GetTemporaryExposureKeyHistoryParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.GetVersionParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.INearbyExposureNotificationService;\nimport com.google.android.gms.nearby.exposurenotification.internal.IsEnabledParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.ProvideDiagnosisKeysParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.RequestPreAuthorizedTemporaryExposureKeyHistoryParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.RequestPreAuthorizedTemporaryExposureKeyReleaseParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.SetDiagnosisKeysDataMappingParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.StartParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.StopParams;\n\nimport org.microg.gms.common.GmsClient;\nimport org.microg.gms.common.GmsService;\nimport com.google.android.gms.common.api.internal.ConnectionCallbacks;\nimport com.google.android.gms.common.api.internal.OnConnectionFailedListener;\n\npublic class ExposureNotificationApiClient extends GmsClient<INearbyExposureNotificationService> {\n    public ExposureNotificationApiClient(Context context, ConnectionCallbacks callbacks, OnConnectionFailedListener connectionFailedListener) {\n        super(context, callbacks, connectionFailedListener, GmsService.NEARBY_EXPOSURE_NOTIFICATION.ACTION);\n        serviceId = GmsService.NEARBY_EXPOSURE_NOTIFICATION.SERVICE_ID;\n        requireMicrog = true;\n    }\n\n    @Override\n    protected INearbyExposureNotificationService interfaceFromBinder(IBinder binder) {\n        return INearbyExposureNotificationService.Stub.asInterface(binder);\n    }\n\n    public void getVersion(GetVersionParams params) throws RemoteException {\n        getServiceInterface().getVersion(params);\n    }\n\n    public void getCalibrationConfidence(GetCalibrationConfidenceParams params) throws RemoteException {\n        getServiceInterface().getCalibrationConfidence(params);\n    }\n\n    public void start(StartParams params) throws RemoteException {\n        getServiceInterface().start(params);\n    }\n\n    public void stop(StopParams params) throws RemoteException {\n        getServiceInterface().stop(params);\n    }\n\n    public void isEnabled(IsEnabledParams params) throws RemoteException {\n        getServiceInterface().isEnabled(params);\n    }\n\n    public void getTemporaryExposureKeyHistory(GetTemporaryExposureKeyHistoryParams params) throws RemoteException {\n        getServiceInterface().getTemporaryExposureKeyHistory(params);\n    }\n\n    public void provideDiagnosisKeys(ProvideDiagnosisKeysParams params) throws RemoteException {\n        getServiceInterface().provideDiagnosisKeys(params);\n    }\n\n    public void getExposureSummary(GetExposureSummaryParams params) throws RemoteException {\n        getServiceInterface().getExposureSummary(params);\n    }\n\n    public void getExposureInformation(GetExposureInformationParams params) throws RemoteException {\n        getServiceInterface().getExposureInformation(params);\n    }\n\n    public void getExposureWindows(GetExposureWindowsParams params) throws RemoteException {\n        getServiceInterface().getExposureWindows(params);\n    }\n\n    public void getDailySummaries(GetDailySummariesParams params) throws RemoteException {\n        getServiceInterface().getDailySummaries(params);\n    }\n\n    public void setDiagnosisKeysDataMapping(SetDiagnosisKeysDataMappingParams params) throws RemoteException {\n        getServiceInterface().setDiagnosisKeysDataMapping(params);\n    }\n\n    public void getDiagnosisKeysDataMapping(GetDiagnosisKeysDataMappingParams params) throws RemoteException {\n        getServiceInterface().getDiagnosisKeysDataMapping(params);\n    }\n\n    public void getPackageConfiguration(GetPackageConfigurationParams params) throws RemoteException {\n        getServiceInterface().getPackageConfiguration(params);\n    }\n\n    public void getStatus(GetStatusParams params) throws RemoteException {\n        getServiceInterface().getStatus(params);\n    }\n\n    public void requestPreAuthorizedTemporaryExposureKeyHistory(RequestPreAuthorizedTemporaryExposureKeyHistoryParams params) throws RemoteException {\n        getServiceInterface().requestPreAuthorizedTemporaryExposureKeyHistory(params);\n    }\n\n    public void requestPreAuthorizedTemporaryExposureKeyRelease(RequestPreAuthorizedTemporaryExposureKeyReleaseParams params) throws RemoteException {\n        getServiceInterface().requestPreAuthorizedTemporaryExposureKeyRelease(params);\n    }\n}\n"
  },
  {
    "path": "play-services-nearby/src/main/java/org/microg/gms/nearby/ExposureNotificationClientImpl.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.nearby;\n\nimport android.content.Context;\nimport android.os.ParcelFileDescriptor;\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.ApiException;\nimport com.google.android.gms.common.api.GoogleApi;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.common.api.internal.ApiKey;\nimport com.google.android.gms.common.api.internal.IStatusCallback;\nimport com.google.android.gms.nearby.exposurenotification.DailySummariesConfig;\nimport com.google.android.gms.nearby.exposurenotification.DailySummary;\nimport com.google.android.gms.nearby.exposurenotification.DiagnosisKeyFileProvider;\nimport com.google.android.gms.nearby.exposurenotification.DiagnosisKeysDataMapping;\nimport com.google.android.gms.nearby.exposurenotification.ExposureConfiguration;\nimport com.google.android.gms.nearby.exposurenotification.ExposureInformation;\nimport com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient;\nimport com.google.android.gms.nearby.exposurenotification.ExposureNotificationStatus;\nimport com.google.android.gms.nearby.exposurenotification.ExposureSummary;\nimport com.google.android.gms.nearby.exposurenotification.ExposureWindow;\nimport com.google.android.gms.nearby.exposurenotification.PackageConfiguration;\nimport com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey;\nimport com.google.android.gms.nearby.exposurenotification.internal.GetCalibrationConfidenceParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.GetDailySummariesParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.GetDiagnosisKeysDataMappingParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.GetExposureInformationParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.GetExposureSummaryParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.GetExposureWindowsParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.GetPackageConfigurationParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.GetStatusParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.GetTemporaryExposureKeyHistoryParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.GetVersionParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.IBooleanCallback;\nimport com.google.android.gms.nearby.exposurenotification.internal.IDailySummaryListCallback;\nimport com.google.android.gms.nearby.exposurenotification.internal.IDiagnosisKeyFileSupplier;\nimport com.google.android.gms.nearby.exposurenotification.internal.IDiagnosisKeysDataMappingCallback;\nimport com.google.android.gms.nearby.exposurenotification.internal.IExposureInformationListCallback;\nimport com.google.android.gms.nearby.exposurenotification.internal.IExposureSummaryCallback;\nimport com.google.android.gms.nearby.exposurenotification.internal.IExposureWindowListCallback;\nimport com.google.android.gms.nearby.exposurenotification.internal.IIntCallback;\nimport com.google.android.gms.nearby.exposurenotification.internal.ILongCallback;\nimport com.google.android.gms.nearby.exposurenotification.internal.IPackageConfigurationCallback;\nimport com.google.android.gms.nearby.exposurenotification.internal.ITemporaryExposureKeyListCallback;\nimport com.google.android.gms.nearby.exposurenotification.internal.IsEnabledParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.ProvideDiagnosisKeysParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.RequestPreAuthorizedTemporaryExposureKeyHistoryParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.RequestPreAuthorizedTemporaryExposureKeyReleaseParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.SetDiagnosisKeysDataMappingParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.StartParams;\nimport com.google.android.gms.nearby.exposurenotification.internal.StopParams;\nimport com.google.android.gms.tasks.Task;\n\nimport org.microg.gms.common.api.PendingGoogleApiCall;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Set;\n\npublic class ExposureNotificationClientImpl extends GoogleApi<Api.ApiOptions.NoOptions> implements ExposureNotificationClient {\n    private static final Api<Api.ApiOptions.NoOptions> API = new Api<>((options, context, looper, clientSettings, callbacks, connectionFailedListener) -> new ExposureNotificationApiClient(context, callbacks, connectionFailedListener));\n\n    public ExposureNotificationClientImpl(Context context) {\n        super(context, API, Api.ApiOptions.NO_OPTIONS);\n    }\n\n    private static final String TAG = \"ENClientImpl\";\n\n    @Override\n    public Task<Long> getVersion() {\n        return scheduleTask((PendingGoogleApiCall<Long, ExposureNotificationApiClient>) (client, completionSource) -> {\n            GetVersionParams params = new GetVersionParams(new ILongCallback.Stub() {\n                @Override\n                public void onResult(Status status, long result) {\n                    if (status.isSuccess()) {\n                        completionSource.setResult(result);\n                    } else {\n                        completionSource.setException(new ApiException(status));\n                    }\n                }\n            });\n            try {\n                client.getVersion(params);\n            } catch (Exception e) {\n                completionSource.setException(e);\n            }\n        });\n    }\n\n    @Override\n    public Task<Integer> getCalibrationConfidence() {\n        return scheduleTask((PendingGoogleApiCall<Integer, ExposureNotificationApiClient>) (client, completionSource) -> {\n            GetCalibrationConfidenceParams params = new GetCalibrationConfidenceParams(new IIntCallback.Stub() {\n                @Override\n                public void onResult(Status status, int result) {\n                    if (status.isSuccess()) {\n                        completionSource.setResult(result);\n                    } else {\n                        completionSource.setException(new ApiException(status));\n                    }\n                }\n            });\n            try {\n                client.getCalibrationConfidence(params);\n            } catch (Exception e) {\n                completionSource.setException(e);\n            }\n        });\n    }\n\n    @Override\n    public Task<Void> start() {\n        return scheduleTask((PendingGoogleApiCall<Void, ExposureNotificationApiClient>) (client, completionSource) -> {\n            StartParams params = new StartParams(new IStatusCallback.Stub() {\n                @Override\n                public void onResult(Status status) {\n                    if (status.isSuccess()) {\n                        completionSource.setResult(null);\n                    } else {\n                        completionSource.setException(new ApiException(status));\n                    }\n                }\n            });\n            try {\n                client.start(params);\n            } catch (Exception e) {\n                completionSource.setException(e);\n            }\n        });\n    }\n\n    @Override\n    public Task<Void> stop() {\n        return scheduleTask((PendingGoogleApiCall<Void, ExposureNotificationApiClient>) (client, completionSource) -> {\n            StopParams params = new StopParams(new IStatusCallback.Stub() {\n                @Override\n                public void onResult(Status status) {\n                    if (status.isSuccess()) {\n                        completionSource.setResult(null);\n                    } else {\n                        completionSource.setException(new ApiException(status));\n                    }\n                }\n            });\n            try {\n                client.stop(params);\n            } catch (Exception e) {\n                completionSource.setException(e);\n            }\n        });\n    }\n\n    @Override\n    public Task<Boolean> isEnabled() {\n        return scheduleTask((PendingGoogleApiCall<Boolean, ExposureNotificationApiClient>) (client, completionSource) -> {\n            IsEnabledParams params = new IsEnabledParams(new IBooleanCallback.Stub() {\n                @Override\n                public void onResult(Status status, boolean result) {\n                    if (status.isSuccess()) {\n                        completionSource.setResult(result);\n                    } else {\n                        completionSource.setException(new ApiException(status));\n                    }\n                }\n            });\n            try {\n                client.isEnabled(params);\n            } catch (Exception e) {\n                completionSource.setException(e);\n            }\n        });\n    }\n\n    @Override\n    public Task<List<TemporaryExposureKey>> getTemporaryExposureKeyHistory() {\n        return scheduleTask((PendingGoogleApiCall<List<TemporaryExposureKey>, ExposureNotificationApiClient>) (client, completionSource) -> {\n            GetTemporaryExposureKeyHistoryParams params = new GetTemporaryExposureKeyHistoryParams(new ITemporaryExposureKeyListCallback.Stub() {\n                @Override\n                public void onResult(Status status, List<TemporaryExposureKey> result) {\n                    if (status.isSuccess()) {\n                        completionSource.setResult(result);\n                    } else {\n                        completionSource.setException(new ApiException(status));\n                    }\n                }\n            });\n            try {\n                client.getTemporaryExposureKeyHistory(params);\n            } catch (Exception e) {\n                completionSource.setException(e);\n            }\n        });\n    }\n\n    @Override\n    public Task<Void> provideDiagnosisKeys(List<File> keyFiles, ExposureConfiguration configuration, String token) {\n        return scheduleTask((PendingGoogleApiCall<Void, ExposureNotificationApiClient>) (client, completionSource) -> {\n            List<ParcelFileDescriptor> fds = new ArrayList<>(keyFiles.size());\n            for (File kf: keyFiles) {\n                ParcelFileDescriptor fd;\n                try {\n                    fd = ParcelFileDescriptor.open(kf, ParcelFileDescriptor.MODE_READ_ONLY);\n                } catch (FileNotFoundException e) {\n                    for (ParcelFileDescriptor ofd : fds) {\n                        try {\n                            ofd.close();\n                        } catch (IOException e2) {\n                            Log.w(TAG, \"Failed to close file\", e2);\n                        }\n                    }\n                    completionSource.setException(e);\n                    return;\n                }\n                fds.add(fd);\n            }\n\n            ProvideDiagnosisKeysParams params = new ProvideDiagnosisKeysParams(new IStatusCallback.Stub() {\n                @Override\n                public void onResult(Status status) {\n                    if (status.isSuccess()) {\n                        completionSource.setResult(null);\n                    } else {\n                        completionSource.setException(new ApiException(status));\n                    }\n                }\n            }, fds, configuration, token);\n            try {\n                client.provideDiagnosisKeys(params);\n            } catch (Exception e) {\n                completionSource.setException(e);\n            }\n        });\n    }\n\n    @Override\n    public Task<Void> provideDiagnosisKeys(List<File> keyFiles) {\n        return provideDiagnosisKeys(keyFiles, null, TOKEN_A);\n    }\n\n    @Override\n    public Task<Void> provideDiagnosisKeys(DiagnosisKeyFileProvider provider) {\n        return scheduleTask((PendingGoogleApiCall<Void, ExposureNotificationApiClient>) (client, completionSource) -> {\n            ProvideDiagnosisKeysParams params = new ProvideDiagnosisKeysParams(new IStatusCallback.Stub() {\n                @Override\n                public void onResult(Status status) {\n                    if (status.isSuccess()) {\n                        completionSource.setResult(null);\n                    } else {\n                        completionSource.setException(new ApiException(status));\n                    }\n                }\n            }, new IDiagnosisKeyFileSupplier.Stub() {\n                @Override\n                public boolean hasNext() {\n                    return provider.hasNext();\n                }\n\n                @Override\n                public ParcelFileDescriptor next() {\n                    try {\n                        return ParcelFileDescriptor.open(provider.next(), ParcelFileDescriptor.MODE_READ_ONLY);\n                    } catch (FileNotFoundException e) {\n                        throw new RuntimeException(e);\n                    }\n                }\n\n                @Override\n                public boolean isAvailable() {\n                    return true;\n                }\n            });\n            try {\n                client.provideDiagnosisKeys(params);\n            } catch (Exception e) {\n                completionSource.setException(e);\n            }\n        });\n    }\n\n    @Override\n    public Task<ExposureSummary> getExposureSummary(String token) {\n        return scheduleTask((PendingGoogleApiCall<ExposureSummary, ExposureNotificationApiClient>) (client, completionSource) -> {\n            GetExposureSummaryParams params = new GetExposureSummaryParams(new IExposureSummaryCallback.Stub() {\n                @Override\n                public void onResult(Status status, ExposureSummary result) {\n                    if (status.isSuccess()) {\n                        completionSource.setResult(result);\n                    } else {\n                        completionSource.setException(new ApiException(status));\n                    }\n                }\n            }, token);\n            try {\n                client.getExposureSummary(params);\n            } catch (Exception e) {\n                completionSource.setException(e);\n            }\n        });\n    }\n\n    @Override\n    public Task<List<ExposureInformation>> getExposureInformation(String token) {\n        return scheduleTask((PendingGoogleApiCall<List<ExposureInformation>, ExposureNotificationApiClient>) (client, completionSource) -> {\n            GetExposureInformationParams params = new GetExposureInformationParams(new IExposureInformationListCallback.Stub() {\n                @Override\n                public void onResult(Status status, List<ExposureInformation> result) {\n                    if (status.isSuccess()) {\n                        completionSource.setResult(result);\n                    } else {\n                        completionSource.setException(new ApiException(status));\n                    }\n                }\n            }, token);\n            try {\n                client.getExposureInformation(params);\n            } catch (Exception e) {\n                completionSource.setException(e);\n            }\n        });\n    }\n\n    @Override\n    public Task<List<ExposureWindow>> getExposureWindows(String token) {\n        return scheduleTask((PendingGoogleApiCall<List<ExposureWindow>, ExposureNotificationApiClient>) (client, completionSource) -> {\n            GetExposureWindowsParams params = new GetExposureWindowsParams(new IExposureWindowListCallback.Stub() {\n                @Override\n                public void onResult(Status status, List<ExposureWindow> result) {\n                    if (status.isSuccess()) {\n                        completionSource.setResult(result);\n                    } else {\n                        completionSource.setException(new ApiException(status));\n                    }\n                }\n            }, token);\n            try {\n                client.getExposureWindows(params);\n            } catch (Exception e) {\n                completionSource.setException(e);\n            }\n        });\n    }\n\n    @Override\n    public Task<List<ExposureWindow>> getExposureWindows() {\n        return getExposureWindows(TOKEN_A);\n    }\n\n    @Override\n    public Task<List<DailySummary>> getDailySummaries(DailySummariesConfig dailySummariesConfig) {\n        return scheduleTask((PendingGoogleApiCall<List<DailySummary>, ExposureNotificationApiClient>) (client, completionSource) -> {\n            GetDailySummariesParams params = new GetDailySummariesParams(new IDailySummaryListCallback.Stub() {\n                @Override\n                public void onResult(Status status, List<DailySummary> result) {\n                    if (status.isSuccess()) {\n                        completionSource.setResult(result);\n                    } else {\n                        completionSource.setException(new ApiException(status));\n                    }\n                }\n            }, dailySummariesConfig);\n            try {\n                client.getDailySummaries(params);\n            } catch (Exception e) {\n                completionSource.setException(e);\n            }\n        });\n    }\n\n    @Override\n    public Task<Void> setDiagnosisKeysDataMapping(DiagnosisKeysDataMapping diagnosisKeysMetadataMapping) {\n        return scheduleTask((PendingGoogleApiCall<Void, ExposureNotificationApiClient>) (client, completionSource) -> {\n            SetDiagnosisKeysDataMappingParams params = new SetDiagnosisKeysDataMappingParams(new IStatusCallback.Stub() {\n                @Override\n                public void onResult(Status status) {\n                    if (status.isSuccess()) {\n                        completionSource.setResult(null);\n                    } else {\n                        completionSource.setException(new ApiException(status));\n                    }\n                }\n            }, diagnosisKeysMetadataMapping);\n            try {\n                client.setDiagnosisKeysDataMapping(params);\n            } catch (Exception e) {\n                completionSource.setException(e);\n            }\n        });\n    }\n\n    @Override\n    public Task<DiagnosisKeysDataMapping> getDiagnosisKeysDataMapping() {\n        return scheduleTask((PendingGoogleApiCall<DiagnosisKeysDataMapping, ExposureNotificationApiClient>) (client, completionSource) -> {\n            GetDiagnosisKeysDataMappingParams params = new GetDiagnosisKeysDataMappingParams(new IDiagnosisKeysDataMappingCallback.Stub() {\n                @Override\n                public void onResult(Status status, DiagnosisKeysDataMapping result) {\n                    if (status.isSuccess()) {\n                        completionSource.setResult(result);\n                    } else {\n                        completionSource.setException(new ApiException(status));\n                    }\n                }\n            });\n            try {\n                client.getDiagnosisKeysDataMapping(params);\n            } catch (Exception e) {\n                completionSource.setException(e);\n            }\n        });\n    }\n\n    @Override\n    public Task<PackageConfiguration> getPackageConfiguration() {\n        return scheduleTask((PendingGoogleApiCall<PackageConfiguration, ExposureNotificationApiClient>) (client, completionSource) -> {\n            GetPackageConfigurationParams params = new GetPackageConfigurationParams(new IPackageConfigurationCallback.Stub() {\n                @Override\n                public void onResult(Status status, PackageConfiguration result) {\n                    if (status.isSuccess()) {\n                        completionSource.setResult(result);\n                    } else {\n                        completionSource.setException(new ApiException(status));\n                    }\n                }\n            });\n            try {\n                client.getPackageConfiguration(params);\n            } catch (Exception e) {\n                completionSource.setException(e);\n            }\n        });\n    }\n\n    @Override\n    public Task<Set<ExposureNotificationStatus>> getStatus() {\n        return scheduleTask((PendingGoogleApiCall<Set<ExposureNotificationStatus>, ExposureNotificationApiClient>) (client, completionSource) -> {\n            GetStatusParams params = new GetStatusParams(new ILongCallback.Stub() {\n                @Override\n                public void onResult(Status status, long flags) {\n                    if (status.isSuccess()) {\n                        completionSource.setResult(ExposureNotificationStatus.flagsToSet(flags));\n                    } else {\n                        completionSource.setException(new ApiException(status));\n                    }\n                }\n            });\n            try {\n                client.getStatus(params);\n            } catch (Exception e) {\n                completionSource.setException(e);\n            }\n        });\n    }\n\n    @Override\n    public Task<Void> requestPreAuthorizedTemporaryExposureKeyHistory() {\n        return scheduleTask((PendingGoogleApiCall<Void, ExposureNotificationApiClient>) (client, completionSource) -> {\n            RequestPreAuthorizedTemporaryExposureKeyHistoryParams params = new RequestPreAuthorizedTemporaryExposureKeyHistoryParams(new IStatusCallback.Stub() {\n                @Override\n                public void onResult(Status status) {\n                    if (status.isSuccess()) {\n                        completionSource.setResult(null);\n                    } else {\n                        completionSource.setException(new ApiException(status));\n                    }\n                }\n            });\n            try {\n                client.requestPreAuthorizedTemporaryExposureKeyHistory(params);\n            } catch (Exception e) {\n                completionSource.setException(e);\n            }\n        });\n    }\n\n    @Override\n    public Task<Void> requestPreAuthorizedTemporaryExposureKeyRelease() {\n        return scheduleTask((PendingGoogleApiCall<Void, ExposureNotificationApiClient>) (client, completionSource) -> {\n            RequestPreAuthorizedTemporaryExposureKeyReleaseParams params = new RequestPreAuthorizedTemporaryExposureKeyReleaseParams(new IStatusCallback.Stub() {\n                @Override\n                public void onResult(Status status) {\n                    if (status.isSuccess()) {\n                        completionSource.setResult(null);\n                    } else {\n                        completionSource.setException(new ApiException(status));\n                    }\n                }\n            });\n            try {\n                client.requestPreAuthorizedTemporaryExposureKeyRelease(params);\n            } catch (Exception e) {\n                completionSource.setException(e);\n            }\n        });\n    }\n\n    @Override\n    public boolean deviceSupportsLocationlessScanning() {\n        return false;\n    }\n}\n"
  },
  {
    "path": "play-services-oss-licenses/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\nandroid {\n    namespace \"com.google.android.gms.oss.licenses\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    lintOptions {\n        disable 'MissingTranslation'\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n}\n\napply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG implementation of play-services-oss-licenses'\n\ndependencies {\n    // Dependencies from play-services-oss-licenses:17.0.0\n    api \"androidx.loader:loader:1.0.0\"\n    api project(':play-services-base')\n    api project(':play-services-basement')\n    api project(':play-services-tasks')\n    implementation \"androidx.appcompat:appcompat:1.0.0\"\n}\n"
  },
  {
    "path": "play-services-oss-licenses/core/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'kotlin-android'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\ndependencies {\n    api project(':play-services-base-core')\n    api project(':play-services-oss-licenses')\n}\n\nandroid {\n    namespace \"org.microg.gms.oss.licenses.core\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    sourceSets {\n        main {\n            java.srcDirs = ['src/main/kotlin']\n        }\n    }\n\n    lintOptions {\n        disable 'MissingTranslation'\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n\n    kotlinOptions {\n        jvmTarget = 1.8\n    }\n}\n\napply from: '../../gradle/publish-android.gradle'\n\ndescription = 'microG service implementation for play-services-oss-licenses'\n"
  },
  {
    "path": "play-services-oss-licenses/core/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <application>\n        <service\n            android:name=\".OssLicensesService\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.oss.licenses.service.START\" />\n            </intent-filter>\n        </service>\n    </application>\n</manifest>\n"
  },
  {
    "path": "play-services-oss-licenses/core/src/main/kotlin/org/microg/gms/oss/licenses/core/OssLicensesService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.oss.licenses.core\n\nimport com.google.android.gms.common.api.CommonStatusCodes.SUCCESS\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport com.google.android.gms.oss.licenses.IOSSLicenseService\nimport com.google.android.gms.oss.licenses.License\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\n\nprivate const val TAG = \"OssLicensesService\"\n\nclass OssLicensesService : BaseService(TAG, GmsService.OSS_LICENSES_SERVICE) {\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService?) {\n        callback.onPostInitComplete(SUCCESS, OssLicensesServiceImpl(), null)\n    }\n}\n\nclass OssLicensesServiceImpl : IOSSLicenseService.Stub() {\n\n    override fun getListLayoutPackage(packageName: String?): String? {\n        // Use fallback resources provided by package itself\n        return packageName\n    }\n\n    override fun getLicenseLayoutPackage(packageName: String?): String? {\n        // Use fallback resources provided by package itself\n        return packageName\n    }\n\n    override fun getLicenseDetail(libraryName: String?): String? {\n        // Use license provided by package itself\n        return null\n    }\n\n    override fun getLicenseList(list: MutableList<License>?): List<License> {\n        // Just sort it\n        val newList = arrayListOf<License>()\n        newList.addAll(list.orEmpty())\n        newList.sortBy { it.name }\n        return newList\n    }\n\n}\n"
  },
  {
    "path": "play-services-oss-licenses/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <application>\n        <activity\n            android:name=\"com.google.android.gms.oss.licenses.OssLicensesMenuActivity\"\n            android:label=\"@string/oss_license_title\" />\n        <activity android:name=\"com.google.android.gms.oss.licenses.OssLicensesActivity\" />\n    </application>\n</manifest>\n"
  },
  {
    "path": "play-services-oss-licenses/src/main/aidl/com/google/android/gms/oss/licenses/IOSSLicenseService.aidl",
    "content": "package com.google.android.gms.oss.licenses;\n\nimport com.google.android.gms.oss.licenses.License;\n\ninterface IOSSLicenseService {\n    String getListLayoutPackage(String packageName) = 1;\n    String getLicenseLayoutPackage(String packageName) = 2;\n    String getLicenseDetail(String license) = 3;\n    List<License> getLicenseList(in List<License> list) = 4;\n}\n"
  },
  {
    "path": "play-services-oss-licenses/src/main/aidl/com/google/android/gms/oss/licenses/License.aidl",
    "content": "package com.google.android.gms.oss.licenses;\n\nimport com.google.android.gms.oss.licenses.License;\n\nparcelable License;\n"
  },
  {
    "path": "play-services-oss-licenses/src/main/java/com/google/android/gms/oss/licenses/License.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.oss.licenses;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\npublic class License implements Parcelable, Comparable<License> {\n    public static final Creator<License> CREATOR = new Creator<License>() {\n        @Override\n        public License createFromParcel(Parcel source) {\n            return new License(source);\n        }\n\n        @Override\n        public License[] newArray(int size) {\n            return new License[size];\n        }\n    };\n\n    private final String name;\n    private final long offset;\n    private final int length;\n    private final String path;\n\n    public License(String name, long offset, int length, String path) {\n        this.name = name;\n        this.offset = offset;\n        this.length = length;\n        this.path = path;\n    }\n\n    public License(Parcel parcel) {\n        this.name = parcel.readString();\n        this.offset = parcel.readLong();\n        this.length = parcel.readInt();\n        this.path = parcel.readString();\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public long getOffset() {\n        return offset;\n    }\n\n    public int getLength() {\n        return length;\n    }\n\n    public String getPath() {\n        return path;\n    }\n\n    @Override\n    public int compareTo(License other) {\n        return name.compareToIgnoreCase(other.name);\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(name);\n        dest.writeLong(offset);\n        dest.writeInt(length);\n        dest.writeString(path);\n    }\n\n    @Override\n    public String toString() {\n        return name;\n    }\n}\n"
  },
  {
    "path": "play-services-oss-licenses/src/main/java/com/google/android/gms/oss/licenses/OssLicensesActivity.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.oss.licenses;\n\nimport android.content.res.Resources;\nimport android.os.Bundle;\nimport android.util.Log;\nimport android.view.MenuItem;\nimport android.widget.ScrollView;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.AppCompatActivity;\n\nimport com.google.android.gms.tasks.Task;\nimport com.google.android.gms.tasks.Tasks;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.oss.licenses.LicenseUtil;\n\n/**\n * An Activity used to display the actual content of a license in res/raw/third_party_licenses generated by oss\n * licenses gradle plugin. This activity is invoked by list items from {@link OssLicensesMenuActivity}.\n */\n@PublicApi\npublic class OssLicensesActivity extends AppCompatActivity {\n    private static final String SCROLL_POSITION_EXTRA = \"scroll_pos\";\n    private License license;\n    private TextView textView;\n    private ScrollView scrollView;\n    private int restoredScrollPosition;\n    private boolean destroyed;\n\n    @Override\n    protected void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        destroyed = false;\n        license = getIntent().getParcelableExtra(\"license\");\n        if (getSupportActionBar() != null) {\n            getSupportActionBar().setTitle(this.license.toString());\n            getSupportActionBar().setDisplayShowHomeEnabled(true);\n            getSupportActionBar().setDisplayHomeAsUpEnabled(true);\n            getSupportActionBar().setLogo(null);\n        }\n        OssLicensesServiceImpl service = new OssLicensesServiceImpl(this);\n        Task<String> licenseDetailTask = service.getLicenseDetail(license);\n        Task<String> licenseLayoutPackageTask = service.getLicenseLayoutPackage(getPackageName());\n        Tasks.whenAll(licenseDetailTask, licenseLayoutPackageTask).addOnCompleteListener((nil) -> {\n            if (destroyed || isFinishing()) return;\n\n            // Layout\n            String layoutPackage = getPackageName();\n            if (licenseLayoutPackageTask.isSuccessful()) {\n                layoutPackage = licenseLayoutPackageTask.getResult();\n            }\n            Resources resources;\n            try {\n                resources = getPackageManager().getResourcesForApplication(layoutPackage);\n            } catch (Exception e) {\n                layoutPackage = getPackageName();\n                resources = getResources();\n            }\n            setContentView(getLayoutInflater().inflate(resources.getXml(resources.getIdentifier(\"libraries_social_licenses_license_activity\", \"layout\", layoutPackage)), null, false));\n            textView = findViewById(resources.getIdentifier(\"license_activity_textview\", \"id\", layoutPackage));\n            scrollView = findViewById(resources.getIdentifier(\"license_activity_scrollview\", \"id\", layoutPackage));\n\n            // Text\n            String licenseText = null;\n            if (licenseDetailTask.isSuccessful()) {\n                licenseText = licenseDetailTask.getResult();\n            }\n            if (licenseText == null) {\n                try {\n                    licenseText = LicenseUtil.getLicenseText(this, license);\n                } catch (Exception e) {\n                    // Ignore\n                }\n            }\n            if (licenseText == null) {\n                textView.setText(R.string.license_content_error);\n            } else {\n                textView.setText(licenseText);\n            }\n\n            // Restore scroll position\n            if (restoredScrollPosition != 0) {\n                scrollView.post(() -> scrollView.scrollTo(0, textView.getLayout().getLineTop(textView.getLayout().getLineForOffset(restoredScrollPosition))));\n            }\n        });\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        destroyed = true;\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 onRestoreInstanceState(@NonNull Bundle savedInstanceState) {\n        super.onRestoreInstanceState(savedInstanceState);\n        restoredScrollPosition = savedInstanceState.getInt(SCROLL_POSITION_EXTRA);\n    }\n\n    @Override\n    protected void onSaveInstanceState(@NonNull Bundle outState) {\n        super.onSaveInstanceState(outState);\n        if (textView != null && scrollView != null) {\n            outState.putInt(SCROLL_POSITION_EXTRA, textView.getLayout().getLineStart(textView.getLayout().getLineForVertical(scrollView.getScrollY())));\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-oss-licenses/src/main/java/com/google/android/gms/oss/licenses/OssLicensesMenuActivity.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.oss.licenses;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.res.Resources;\nimport android.os.Bundle;\nimport android.util.Log;\nimport android.view.LayoutInflater;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ArrayAdapter;\nimport android.widget.ListView;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.AppCompatActivity;\nimport androidx.loader.app.LoaderManager;\nimport androidx.loader.content.AsyncTaskLoader;\nimport androidx.loader.content.Loader;\n\nimport com.google.android.gms.tasks.Task;\nimport com.google.android.gms.tasks.Tasks;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.oss.licenses.LicenseUtil;\n\nimport java.util.List;\n\n/**\n * An Activity used to display a list of all third party licenses in res/raw/third_party_license_metadata generated by\n * oss licenses gradle plugin. Click on each item of the list would invoke {@link OssLicensesActivity} to show the\n * actual content of the license.\n */\n@PublicApi\npublic class OssLicensesMenuActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<List<License>> {\n    private static final String TAG = \"OssLicensesMenuActivity\";\n    private static final String EXTRA_TITLE = \"title\";\n    private static final int LOADER_ID = 54321;\n    private static String TITLE;\n\n    private ListView listView;\n    private boolean destroyed;\n    private ArrayAdapter<License> licensesAdapter;\n\n    @Override\n    protected void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        destroyed = false;\n        if (TITLE == null) {\n            Intent intent = getIntent();\n            if (intent != null && intent.hasExtra(EXTRA_TITLE)) {\n                TITLE = intent.getStringExtra(EXTRA_TITLE);\n                Log.w(TAG, \"The intent based title is deprecated. Use OssLicensesMenuActivity.setActivityTitle(title) instead.\");\n            }\n        }\n        if (TITLE != null) {\n            setTitle(TITLE);\n        }\n        if (getSupportActionBar() != null) {\n            getSupportActionBar().setDisplayHomeAsUpEnabled(true);\n        }\n\n        if (LicenseUtil.hasLicenses(this)) {\n            OssLicensesServiceImpl service = new OssLicensesServiceImpl(this);\n            service.getListLayoutPackage(getPackageName()).addOnCompleteListener((layoutPackageTask) -> {\n                if (destroyed || isFinishing()) return;\n\n                // Layout\n                String layoutPackage = getPackageName();\n                if (layoutPackageTask.isSuccessful()) {\n                    layoutPackage = layoutPackageTask.getResult();\n                }\n                Resources resources;\n                try {\n                    resources = getPackageManager().getResourcesForApplication(layoutPackage);\n                } catch (Exception e) {\n                    layoutPackage = getPackageName();\n                    resources = getResources();\n                }\n                setContentView(getLayoutInflater().inflate(resources.getXml(resources.getIdentifier(\"libraries_social_licenses_license_menu_activity\", \"layout\", layoutPackage)), null, false));\n                licensesAdapter = new LicensesAdapter(this, getLayoutInflater(), resources, layoutPackage);\n                listView = findViewById(resources.getIdentifier(\"license_list\", \"id\", layoutPackage));\n                listView.setAdapter(licensesAdapter);\n                listView.setOnItemClickListener((parent, view, position, id) -> {\n                    License license = (License) parent.getItemAtPosition(position);\n                    Intent intent = new Intent(this, OssLicensesActivity.class);\n                    intent.putExtra(\"license\", license);\n                    startActivity(intent);\n                });\n            });\n            LoaderManager.getInstance(this).initLoader(LOADER_ID, null, this);\n        } else {\n            setContentView(R.layout.license_menu_activity_no_licenses);\n        }\n    }\n\n    private static class LicensesAdapter extends ArrayAdapter<License> {\n        private final LayoutInflater layoutInflater;\n        private final Resources resources;\n        private final String layoutPackage;\n\n        public LicensesAdapter(@NonNull Context context, @NonNull LayoutInflater layoutInflater, @NonNull Resources resources, @NonNull String layoutPackage) {\n            super(context, 0);\n            this.layoutInflater = layoutInflater;\n            this.resources = resources;\n            this.layoutPackage = layoutPackage;\n        }\n\n        @NonNull\n        @Override\n        public View getView(int position, @Nullable View view, @NonNull ViewGroup parent) {\n            if (view == null) {\n                view = layoutInflater.inflate(resources.getXml(resources.getIdentifier(\"libraries_social_licenses_license\", \"layout\", layoutPackage)), null, false);\n            }\n            TextView textView = view.findViewById(resources.getIdentifier(\"license\", \"id\", layoutPackage));\n            textView.setText(getItem(position).toString());\n            return view;\n        }\n    }\n\n    @NonNull\n    @Override\n    public Loader<List<License>> onCreateLoader(int id, @Nullable Bundle args) {\n        return new AsyncTaskLoader<List<License>>(getApplicationContext()) {\n            private List<License> storedData;\n\n            @Nullable\n            @Override\n            public List<License> loadInBackground() {\n                List<License> licenses = LicenseUtil.getLicensesFromMetadata(getContext());\n                try {\n                    OssLicensesServiceImpl service = new OssLicensesServiceImpl(getContext());\n                    Task<List<License>> licensesTask = service.getLicenseList(licenses);\n                    return Tasks.await(licensesTask);\n                } catch (Exception e) {\n                    Log.w(TAG, \"Error getting license list from service.\", e);\n                }\n                return licenses;\n            }\n\n            @Override\n            public void deliverResult(@Nullable List<License> data) {\n                this.storedData = data;\n                super.deliverResult(data);\n            }\n\n            @Override\n            protected void onStartLoading() {\n                if (storedData != null) {\n                    deliverResult(storedData);\n                } else {\n                    forceLoad();\n                }\n            }\n\n            @Override\n            protected void onStopLoading() {\n                cancelLoad();\n            }\n        };\n    }\n\n    @Override\n    protected void onDestroy() {\n        destroyed = true;\n        LoaderManager.getInstance(this).destroyLoader(LOADER_ID);\n        super.onDestroy();\n    }\n\n    @Override\n    public void onLoadFinished(@NonNull Loader<List<License>> loader, List<License> data) {\n        licensesAdapter.clear();\n        licensesAdapter.addAll(data);\n        licensesAdapter.notifyDataSetChanged();\n    }\n\n    @Override\n    public void onLoaderReset(@NonNull Loader<List<License>> loader) {\n        licensesAdapter.clear();\n        licensesAdapter.notifyDataSetChanged();\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    /**\n     * Sets the title for {@link OssLicensesMenuActivity}.\n     *\n     * @param title the title for this activity\n     */\n    public static void setActivityTitle(String title) {\n        OssLicensesMenuActivity.TITLE = title;\n    }\n}\n"
  },
  {
    "path": "play-services-oss-licenses/src/main/java/com/google/android/gms/oss/licenses/OssLicensesServiceImpl.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.oss.licenses;\n\nimport android.content.Context;\nimport android.os.RemoteException;\n\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.GoogleApi;\nimport com.google.android.gms.tasks.Task;\n\nimport org.microg.gms.common.api.PendingGoogleApiCall;\nimport org.microg.gms.oss.licenses.OssLicenseServiceApiClient;\n\nimport java.util.List;\n\npublic class OssLicensesServiceImpl extends GoogleApi<Api.ApiOptions.NoOptions> {\n    private static final Api<Api.ApiOptions.NoOptions> API = new Api<>((options, context, looper, clientSettings, callbacks, connectionFailedListener) -> new OssLicenseServiceApiClient(context, callbacks, connectionFailedListener));\n\n    public OssLicensesServiceImpl(Context context) {\n        super(context, API, Api.ApiOptions.NO_OPTIONS);\n    }\n\n    public Task<String> getLicenseLayoutPackage(String packageName) {\n        return scheduleTask((PendingGoogleApiCall<String, OssLicenseServiceApiClient>) (client, completionSource) -> {\n            String result;\n            try {\n                result = client.getLicenseLayoutPackage(packageName);\n            } catch (RemoteException e) {\n                completionSource.setException(e);\n                return;\n            }\n            completionSource.setResult(result);\n        });\n    }\n\n    public Task<String> getListLayoutPackage(String packageName) {\n        return scheduleTask((PendingGoogleApiCall<String, OssLicenseServiceApiClient>) (client, completionSource) -> {\n            String result;\n            try {\n                result = client.getListLayoutPackage(packageName);\n            } catch (RemoteException e) {\n                completionSource.setException(e);\n                return;\n            }\n            completionSource.setResult(result);\n        });\n    }\n\n    public Task<String> getLicenseDetail(License license) {\n        return scheduleTask((PendingGoogleApiCall<String, OssLicenseServiceApiClient>) (client, completionSource) -> {\n            String result;\n            try {\n                result = client.getLicenseDetail(license);\n            } catch (RemoteException e) {\n                completionSource.setException(e);\n                return;\n            }\n            completionSource.setResult(result);\n        });\n    }\n\n    public Task<List<License>> getLicenseList(List<License> licenses) {\n        return scheduleTask((PendingGoogleApiCall<List<License>, OssLicenseServiceApiClient>) (client, completionSource) -> {\n            List<License> result;\n            try {\n                result = client.getLicenseList(licenses);\n            } catch (RemoteException e) {\n                completionSource.setException(e);\n                return;\n            }\n            completionSource.setResult(result);\n        });\n    }\n}\n"
  },
  {
    "path": "play-services-oss-licenses/src/main/java/org/microg/gms/oss/licenses/LicenseUtil.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.oss.licenses;\n\nimport android.content.Context;\nimport android.content.res.Resources;\n\nimport com.google.android.gms.oss.licenses.License;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.UnsupportedEncodingException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\n\npublic class LicenseUtil {\n    public static boolean hasLicenses(Context context) {\n        Resources resources = context.getApplicationContext().getResources();\n        try (InputStream is = resources.openRawResource(resources.getIdentifier(\"third_party_license_metadata\", \"raw\", context.getPackageName()))) {\n            if (is == null || is.available() <= 0) return false;\n        } catch (IOException e) {\n            return false;\n        }\n        try (InputStream is = resources.openRawResource(resources.getIdentifier(\"third_party_licenses\", \"raw\", context.getPackageName()))) {\n            if (is == null || is.available() <= 0) return false;\n        } catch (IOException e) {\n            return false;\n        }\n        return true;\n    }\n\n    public static List<License> getLicensesFromMetadata(Context context) {\n        Resources resources = context.getApplicationContext().getResources();\n        InputStream is = resources.openRawResource(resources.getIdentifier(\"third_party_license_metadata\", \"raw\", context.getPackageName()));\n        String metadata = readStringAndClose(is, Integer.MAX_VALUE);\n        String[] lines = metadata.split(\"\\n\");\n        List<License> licenses = new ArrayList<>(lines.length);\n        for (String line : lines) {\n            int spaceIndex = line.indexOf(' ');\n            String[] position = line.substring(0, spaceIndex).split(\":\");\n            if (spaceIndex <= 0 || position.length != 2) {\n                throw new IllegalStateException(\"Invalid license meta-data line:\\n\" + line);\n            }\n            licenses.add(new License(line.substring(spaceIndex + 1), Long.parseLong(position[0]), Integer.parseInt(position[1]), \"\"));\n        }\n        return licenses;\n    }\n\n    public static String getLicenseText(Context context, License license) {\n        if (license.getPath().isEmpty()) {\n            Resources resources = context.getApplicationContext().getResources();\n            InputStream is = resources.openRawResource(resources.getIdentifier(\"third_party_licenses\", \"raw\", context.getPackageName()));\n            try {\n                if (is.skip(license.getOffset()) != license.getOffset()) {\n                    throw new RuntimeException(\"Failed to read license\");\n                }\n            } catch (IOException e) {\n                throw new RuntimeException(\"Failed to read license\", e);\n            }\n            return readStringAndClose(is, license.getLength());\n        } else {\n            try (JarFile jar = new JarFile(license.getPath())) {\n                JarEntry entry = jar.getJarEntry(\"res/raw/third_party_licenses\");\n                if (entry == null) {\n                    throw new RuntimeException(license.getPath() + \" does not contain res/raw/third_party_licenses\");\n                } else {\n                    InputStream is = jar.getInputStream(entry);\n                    if (is.skip(license.getOffset()) != license.getOffset()) {\n                        throw new RuntimeException(\"Failed to read license\");\n                    }\n                    return readStringAndClose(is, license.getLength());\n                }\n            } catch (IOException e) {\n                throw new RuntimeException(\"Failed to read license\", e);\n            }\n        }\n    }\n\n    private static String readStringAndClose(InputStream is, int bytesToRead) {\n        ByteArrayOutputStream bos = new ByteArrayOutputStream();\n        try {\n            byte[] bytes = new byte[1024];\n            int read;\n            while (bytesToRead > 0 && (read = is.read(bytes, 0, Math.min(bytes.length, bytesToRead))) != -1) {\n                bos.write(bytes, 0, read);\n                bytesToRead -= read;\n            }\n            is.close();\n        } catch (IOException e) {\n            throw new RuntimeException(\"Failed to read license or metadata\", e);\n        }\n        try {\n            return bos.toString(\"UTF-8\");\n        } catch (UnsupportedEncodingException e) {\n            throw new RuntimeException(\"Unsupported encoding UTF8. This should always be supported.\", e);\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-oss-licenses/src/main/java/org/microg/gms/oss/licenses/OssLicenseServiceApiClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.oss.licenses;\n\nimport android.content.Context;\nimport android.os.IBinder;\nimport android.os.RemoteException;\n\nimport com.google.android.gms.oss.licenses.IOSSLicenseService;\nimport com.google.android.gms.oss.licenses.License;\n\nimport org.microg.gms.common.GmsClient;\nimport org.microg.gms.common.GmsService;\nimport com.google.android.gms.common.api.internal.ConnectionCallbacks;\nimport com.google.android.gms.common.api.internal.OnConnectionFailedListener;\n\nimport java.util.List;\n\npublic class OssLicenseServiceApiClient extends GmsClient<IOSSLicenseService> {\n    public OssLicenseServiceApiClient(Context context, ConnectionCallbacks callbacks, OnConnectionFailedListener connectionFailedListener) {\n        super(context, callbacks, connectionFailedListener, GmsService.OSS_LICENSES_SERVICE.ACTION);\n        serviceId = GmsService.OSS_LICENSES_SERVICE.SERVICE_ID;\n    }\n\n    public String getLicenseLayoutPackage(String packageName) throws RemoteException {\n        return getServiceInterface().getLicenseLayoutPackage(packageName);\n    }\n\n    public String getListLayoutPackage(String packageName) throws RemoteException {\n        return getServiceInterface().getListLayoutPackage(packageName);\n    }\n\n    public String getLicenseDetail(License license) throws RemoteException {\n        return getServiceInterface().getLicenseDetail(license.toString());\n    }\n\n    public List<License> getLicenseList(List<License> licenses) throws RemoteException {\n        return getServiceInterface().getLicenseList(licenses);\n    }\n\n    @Override\n    protected IOSSLicenseService interfaceFromBinder(IBinder binder) {\n        return IOSSLicenseService.Stub.asInterface(binder);\n    }\n}\n"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/layout/libraries_social_licenses_license.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <TextView\n        android:id=\"@+id/license\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginHorizontal=\"16dp\"\n        android:layout_marginVertical=\"8dp\"\n        android:ellipsize=\"marquee\"\n        android:fadingEdge=\"horizontal\"\n        android:singleLine=\"true\"\n        android:textAppearance=\"?android:attr/textAppearanceMediumInverse\"\n        android:textColor=\"?android:attr/textColorPrimary\" />\n</FrameLayout>\n"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/layout/libraries_social_licenses_license_activity.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <ScrollView\n        android:id=\"@+id/license_activity_scrollview\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n        <TextView\n            android:id=\"@+id/license_activity_textview\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:autoLink=\"web\"\n            android:paddingHorizontal=\"16dp\"\n            android:paddingVertical=\"8dp\"\n            android:typeface=\"monospace\" />\n    </ScrollView>\n</FrameLayout>\n"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/layout/libraries_social_licenses_license_menu_activity.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <ListView\n        android:id=\"@+id/license_list\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:clipToPadding=\"false\"\n        android:drawSelectorOnTop=\"false\"\n        android:paddingHorizontal=\"16dp\"\n        android:scrollbarAlwaysDrawVerticalTrack=\"true\"\n        android:scrollbarStyle=\"outsideOverlay\" />\n</FrameLayout>\n"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/layout/license_menu_activity_no_licenses.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <TextView\n        android:id=\"@+id/no_licenses_text\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center_horizontal\"\n        android:padding=\"16dp\"\n        android:text=\"@string/no_licenses_available\" />\n</FrameLayout>\n"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<resources>\n    <string name=\"license_content_error\">An error has occurred when fetching the license.</string>\n    <string name=\"no_licenses_available\">This app does not have any open source licenses.</string>\n    <string name=\"oss_license_title\">Open source licenses</string>\n    <!-- The following strings are not used by the library code but must be kept for compatibility,\n         since they may be used by apps that depend on it. -->\n    <string name=\"license_is_loading\">License info is loading.</string>\n    <string name=\"license_list_is_loading\">License list is loading.</string>\n    <string name=\"preferences_license_summary\">License details for open source software</string>\n</resources>\n"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-ar/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_content_error\">حدث خطأ أثناء جلب الترخيص.</string>\n    <string name=\"no_licenses_available\">هذا التطبيق لا يحتوي على أي تراخيص مفتوحة المصدر.</string>\n    <string name=\"oss_license_title\">تراخيص مفتوحة المصدر</string>\n    <string name=\"license_is_loading\">معلومات الترخيص قيد التحميل.</string>\n    <string name=\"license_list_is_loading\">قائمة الترخيص قيد التحميل.</string>\n    <string name=\"preferences_license_summary\">تفاصيل الترخيص للبرمجيات مفتوحة المصدر</string>\n</resources>"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-ast/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_content_error\">Prodúxose un error al dir en cata de la llicencia.</string>\n    <string name=\"oss_license_title\">Llicencies de códigu abiertu</string>\n    <string name=\"preferences_license_summary\">Detalles de la llicencia pal software de códigu abiertu</string>\n    <string name=\"no_licenses_available\">Esta aplicación nun tien nenguna llicencia de códigu abiertu.</string>\n    <string name=\"license_list_is_loading\">La llista de llicencies ta cargando.</string>\n    <string name=\"license_is_loading\">La información de la llicencia ta cargando.</string>\n</resources>"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-az/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_content_error\">Lisenziya alınarkən xəta baş verdi.</string>\n</resources>"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-be/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_list_is_loading\">Загрузка спісу ліцэнзій.</string>\n    <string name=\"preferences_license_summary\">Падрабязнасці аб ліцэнзіях для ПЗ з адкрытым зыходным кодам</string>\n    <string name=\"license_content_error\">Адбылася памылка пры атрыманні ліцэнзіі.</string>\n    <string name=\"no_licenses_available\">У гэтага прыкладання няма ліцэнзій з адчыненым зыходным кодам.</string>\n    <string name=\"oss_license_title\">Ліцэнзіі з адкрытым зыходным кодам</string>\n    <string name=\"license_is_loading\">Загрузка інфармацыі аб ліцэнзіі.</string>\n</resources>"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-bn/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n</resources>"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-ca/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_content_error\">Ha ocorregut un error en obtindre la llicència.</string>\n    <string name=\"no_licenses_available\">Aquesta aplicació no té cap llicència de codi obert.</string>\n    <string name=\"oss_license_title\">Llicències de codi obert</string>\n    <string name=\"license_is_loading\">S\\'està carregant la informació de la llicència.</string>\n    <string name=\"license_list_is_loading\">S\\'està carregant la llista de llicències.</string>\n    <string name=\"preferences_license_summary\">Detalls de la llicència per al programari de codi obert</string>\n</resources>\n"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-cs/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"oss_license_title\">Licence open source</string>\n    <string name=\"license_is_loading\">Načítání informací o licencích.</string>\n    <string name=\"preferences_license_summary\">Podrobnosti o licencích pro open-source software</string>\n    <string name=\"no_licenses_available\">Aplikace nemá žádné licence open source.</string>\n    <string name=\"license_content_error\">Při načítání licence došlo k chybě.</string>\n    <string name=\"license_list_is_loading\">Načítání seznamu licencí.</string>\n</resources>"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-de/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_content_error\">Beim Abrufen der Lizenz ist ein Fehler aufgetreten.</string>\n    <string name=\"oss_license_title\">Open-Source-Lizenzen</string>\n    <string name=\"no_licenses_available\">Diese App hat keine Open-Source-Lizenzen.</string>\n    <string name=\"license_is_loading\">Lizenzinformationen werden geladen.</string>\n    <string name=\"license_list_is_loading\">Lizenzliste wird geladen.</string>\n    <string name=\"preferences_license_summary\">Lizenzdetails für Open-Source-Software</string>\n</resources>"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-eo/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources></resources>"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-es/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_content_error\">Se ha producido un error al obtener la licencia.</string>\n    <string name=\"oss_license_title\">Licencias de código abierto</string>\n    <string name=\"license_is_loading\">La información de la licencia se está cargando.</string>\n    <string name=\"no_licenses_available\">Esta aplicación no tiene ninguna licencia de código abierto.</string>\n    <string name=\"license_list_is_loading\">La lista de licencias se está cargando.</string>\n    <string name=\"preferences_license_summary\">Detalles de la licencia del software de código abierto</string>\n</resources>"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-fa/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_content_error\">هنگام گرفتن پروانه خطایی رخ داده است.</string>\n    <string name=\"license_list_is_loading\">فهرست پروانه‌ها در حال بارگذاری است.</string>\n    <string name=\"no_licenses_available\">این برنامه هیچ پروانه متن باز ندارد.</string>\n    <string name=\"oss_license_title\">پروانه های متن باز</string>\n    <string name=\"preferences_license_summary\">جزئیات پروانه برای برنامه متن باز</string>\n    <string name=\"license_is_loading\">درباره پروانه در حال بارگذاری است.</string>\n</resources>\n"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-fi/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_content_error\">Tapahtui virhe noudettaessa lisenssiä.</string>\n    <string name=\"no_licenses_available\">Tällä ohjelmalla ei ole avoimen lähdekoodin lisenssejä.</string>\n    <string name=\"oss_license_title\">Avoimen lähdekoodin lisenssit</string>\n    <string name=\"license_is_loading\">Lisenssitieto latautuu.</string>\n    <string name=\"license_list_is_loading\">Lisenssilista latautuu.</string>\n    <string name=\"preferences_license_summary\">Lisenssitiedot avoimen lähdekoodin ohjelmistosta</string>\n</resources>\n"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-fil/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_content_error\">Nagkaroon ng error habang kinukuha ang lisensya.</string>\n    <string name=\"no_licenses_available\">Ang app na ito ay walang mga open source na lisensya.</string>\n    <string name=\"oss_license_title\">Mga open source na lisensya</string>\n    <string name=\"license_is_loading\">Naglo-load ang impormasyon ng lisensya.</string>\n    <string name=\"license_list_is_loading\">Naglo-load ang listahan ng lisensya.</string>\n    <string name=\"preferences_license_summary\">Mga detalye ng lisensya para sa open source software</string>\n</resources>"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-fr/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_content_error\">Une erreur s\\'est produite en récupérant la licence.</string>\n    <string name=\"no_licenses_available\">Cette appli n\\'a pas de licences libres.</string>\n    <string name=\"oss_license_title\">Licences libres</string>\n    <string name=\"license_is_loading\">Info sur les licences en cours de chargement.</string>\n    <string name=\"license_list_is_loading\">Liste des licences en cours de chargement.</string>\n    <string name=\"preferences_license_summary\">Détails des licences pour les logiciels libres</string>\n</resources>"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-ga/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_content_error\">Tharla earráid agus an ceadúnas á fháil.</string>\n    <string name=\"no_licenses_available\">Níl aon cheadúnais foinse oscailte ag an aip seo.</string>\n    <string name=\"oss_license_title\">Ceadúnais foinse oscailte</string>\n    <string name=\"license_is_loading\">Tá faisnéis ceadúnais á luchtú.</string>\n    <string name=\"license_list_is_loading\">Tá liosta ceadúnas á lódáil.</string>\n    <string name=\"preferences_license_summary\">Sonraí ceadúnais le haghaidh bogearraí foinse oscailte</string>\n</resources>"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-hu/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_content_error\">Hiba történt a licenc letöltése közben.</string>\n    <string name=\"no_licenses_available\">Az app nem tartalmaz semilyen nyílt forráskódú licencet.</string>\n    <string name=\"oss_license_title\">Nyílt forráskódú licencek</string>\n</resources>\n"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-in/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_content_error\">Terjadi kesalahan saat mengambil lisensi.</string>\n    <string name=\"no_licenses_available\">Aplikasi ini tidak memiliki lisensi sumber terbuka.</string>\n    <string name=\"oss_license_title\">Lisensi sumber terbuka</string>\n    <string name=\"license_is_loading\">Informasi lisensi sedang dimuat.</string>\n    <string name=\"license_list_is_loading\">Daftar lisensi sedang dimuat.</string>\n    <string name=\"preferences_license_summary\">Rincian lisensi untuk perangkat lunak sumber terbuka</string>\n</resources>\n"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-is/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_content_error\">Villa kom upp við að sækja notkunarleyfið.</string>\n    <string name=\"no_licenses_available\">Þetta forrit er ekki með nein opin notkunarleyfi.</string>\n    <string name=\"oss_license_title\">Opin notkunarleyfi</string>\n    <string name=\"license_list_is_loading\">Listi yfir notkunarleyfi er að hlaðast inn.</string>\n    <string name=\"license_is_loading\">Upplýsingar um notkunarleyfi eru að hlaðast inn.</string>\n    <string name=\"preferences_license_summary\">Nánar um notkunarleyfi fyrir opinn hugbúnað</string>\n</resources>"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-it/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_content_error\">Si è verificato un errore durante il recupero della licenza.</string>\n    <string name=\"no_licenses_available\">Questa applicazione non ha licenze open source.</string>\n    <string name=\"oss_license_title\">Licenze open source</string>\n    <string name=\"license_is_loading\">Caricamento delle informazioni della licenza in corso.</string>\n    <string name=\"license_list_is_loading\">Caricamento della lista delle licenze in corso.</string>\n    <string name=\"preferences_license_summary\">Dettagli delle licenze per il software open source</string>\n</resources>"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-iw/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"oss_license_title\">רישיונות קוד פתוח</string>\n    <string name=\"license_list_is_loading\">רשימת הרישיונות נטענת.</string>\n</resources>\n"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-ja/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_content_error\">ライセンスを取得中にエラーが発生しました。</string>\n    <string name=\"oss_license_title\">オープンソースライセンス</string>\n    <string name=\"license_is_loading\">ライセンス情報を読み込み中。</string>\n    <string name=\"license_list_is_loading\">ライセンス一覧を読み込み中。</string>\n    <string name=\"preferences_license_summary\">オープンソースソフトウェアライセンスの詳細</string>\n    <string name=\"no_licenses_available\">このアプリにはオープンソースライセンスがありません。</string>\n</resources>"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-ko/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_content_error\">라이선스를 불러오는 중 오류가 발생했습니다.</string>\n    <string name=\"no_licenses_available\">이 앱은 오픈 소스 라이선스가 없습니다.</string>\n    <string name=\"oss_license_title\">오픈 소스 라이선스</string>\n    <string name=\"license_is_loading\">라이선스 정보를 불러오는 중입니다.</string>\n    <string name=\"license_list_is_loading\">라이선스 목록을 불러오는 중입니다.</string>\n    <string name=\"preferences_license_summary\">오픈 소스 소프트웨어 라이선스 세부 정보</string>\n</resources>\n"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-lv/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_content_error\">Iegūstot licenci, radās kļūda.</string>\n    <string name=\"oss_license_title\">Atvērtā pirmkoda licences</string>\n    <string name=\"license_list_is_loading\">Notiek licenču saraksta ielāde.</string>\n    <string name=\"preferences_license_summary\">Informācija par atklātā pirmkoda programmatūras licencēm</string>\n    <string name=\"license_is_loading\">Notiek licences informācijas ielāde.</string>\n</resources>\n"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-lzh/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources></resources>"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-ml/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_content_error\">ലൈസൻസ് ലഭ്യമാക്കുമ്പോൾ ഒരു പിശക് സംഭവിച്ചു.</string>\n    <string name=\"no_licenses_available\">ഈ ആപ്പിന് ഓപ്പൺ സോഴ്‌സ് ലൈസൻസുകളൊന്നുമില്ല.</string>\n    <string name=\"oss_license_title\">ഓപ്പൺ സോഴ്‌സ് ലൈസൻസുകൾ</string>\n    <string name=\"license_is_loading\">ലൈസൻസ് വിവരങ്ങൾ ലോഡ് ചെയ്യുന്നു.</string>\n    <string name=\"license_list_is_loading\">ലൈസൻസ് ലിസ്റ്റ് ലോഡ് ചെയ്യുന്നു.</string>\n    <string name=\"preferences_license_summary\">ഓപ്പൺ സോഴ്‌സ് സോഫ്റ്റ്‌വെയറിനുള്ള ലൈസൻസ് വിശദാംശങ്ങൾ</string>\n</resources>\n"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-nb-rNO/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_content_error\">En feil oppsto under innhentingen av lisensen.</string>\n    <string name=\"no_licenses_available\">Denne appen har ingen åpne kildekodelisenser.</string>\n    <string name=\"oss_license_title\">Åpne kildekode-lisenser</string>\n    <string name=\"license_is_loading\">Lisensinformasjon lastes inn.</string>\n    <string name=\"license_list_is_loading\">Lisensinformasjon lastes inn.</string>\n    <string name=\"preferences_license_summary\">Lisensinformasjon for programvare med åpen kildekode</string>\n</resources>\n"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-nl/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"oss_license_title\">Open source licenties</string>\n    <string name=\"license_is_loading\">Licentie info wordt geladen.</string>\n    <string name=\"license_list_is_loading\">Licentielijst wordt geladen.</string>\n    <string name=\"preferences_license_summary\">Licentie details voor open source software</string>\n</resources>"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-pl/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_content_error\">Wystąpił błąd podczas pobierania licencji.</string>\n    <string name=\"oss_license_title\">Licencje otwartoźródłowe</string>\n    <string name=\"preferences_license_summary\">Szczegóły licencji dla oprogramowania otwartoźródłowego</string>\n    <string name=\"no_licenses_available\">Ta aplikacja nie zawiera licencji otwartoźródłowych.</string>\n    <string name=\"license_list_is_loading\">Lista licencji jest wczytywana.</string>\n    <string name=\"license_is_loading\">Informacja o licencji jest wczytywana.</string>\n</resources>"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-pt/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_content_error\">Ocorreu um erro ao buscar a licença.</string>\n    <string name=\"no_licenses_available\">Esta app não tem nenhuma licença de código aberto.</string>\n    <string name=\"oss_license_title\">Licenças de código aberto</string>\n    <string name=\"license_is_loading\">As informações da licença estão a carregar.</string>\n    <string name=\"license_list_is_loading\">A lista de licenças está a carregar.</string>\n    <string name=\"preferences_license_summary\">Detalhes de licença de software de código aberto</string>\n</resources>\n"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-pt-rBR/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_is_loading\">As informações da licença estão carregando.</string>\n    <string name=\"license_list_is_loading\">A lista de licenças está carregando.</string>\n    <string name=\"preferences_license_summary\">Detalhes de licença de software de código aberto</string>\n    <string name=\"license_content_error\">Um erro ocorreu ao buscar a licença.</string>\n    <string name=\"no_licenses_available\">Este app não tem nenhuma licença de código aberto.</string>\n    <string name=\"oss_license_title\">Licenças de código aberto</string>\n</resources>\n"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-ro/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_content_error\">A apărut o eroare la preluarea licenței.</string>\n    <string name=\"oss_license_title\">Licențe open source</string>\n    <string name=\"preferences_license_summary\">Detalii de licență pentru software open source</string>\n    <string name=\"no_licenses_available\">Această aplicație nu are licențe open source.</string>\n    <string name=\"license_list_is_loading\">Se încarcă lista de licențe.</string>\n    <string name=\"license_is_loading\">Se încarcă informații despre licență.</string>\n</resources>"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-ru/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_content_error\">Произошла ошибка при получении лицензии.</string>\n    <string name=\"no_licenses_available\">У этого приложения нету лицензий с открытым исходным кодом.</string>\n    <string name=\"oss_license_title\">Лицензии с открытым исходным кодом</string>\n    <string name=\"license_is_loading\">Загрузка информации о лицензии.</string>\n    <string name=\"license_list_is_loading\">Загрузка списка лицензий.</string>\n    <string name=\"preferences_license_summary\">Подробности о лицензиях для ПО с открытым исходным кодом</string>\n</resources>"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-sl/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n</resources>"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-sr/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_content_error\">Дошло је до грешке при добављању лиценце.</string>\n    <string name=\"oss_license_title\">Лиценце отвореног кода</string>\n    <string name=\"preferences_license_summary\">Детаљи лиценце за софтвер отвореног кода</string>\n    <string name=\"no_licenses_available\">Ова апликација нема ниједну лиценцу отвореног кода.</string>\n    <string name=\"license_list_is_loading\">Листа лиценци се учитава.</string>\n    <string name=\"license_is_loading\">Информације о лиценци се учитавају.</string>\n</resources>"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-sv/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_content_error\">Ett fel inträffade vid hämtning av licensen.</string>\n    <string name=\"oss_license_title\">Öppen-källkodslicenser</string>\n    <string name=\"preferences_license_summary\">Licensinformation för öppen-källkodsprogram</string>\n    <string name=\"no_licenses_available\">Denna app har inga öppen-källkodslicenser.</string>\n    <string name=\"license_list_is_loading\">Licenslista läses in.</string>\n    <string name=\"license_is_loading\">Licensinformation läses in.</string>\n</resources>"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-ta/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_content_error\">உரிமத்தைப் பெறும்போது பிழை ஏற்பட்டது.</string>\n    <string name=\"no_licenses_available\">இந்தப் பயன்பாட்டில் திறந்த மூல உரிமங்கள் இல்லை.</string>\n    <string name=\"oss_license_title\">திறந்த மூல உரிமங்கள்</string>\n    <string name=\"license_is_loading\">உரிமத் செய்தி ஏற்றப்படுகிறது.</string>\n    <string name=\"license_list_is_loading\">உரிம பட்டியல் ஏற்றப்படுகிறது.</string>\n    <string name=\"preferences_license_summary\">திறந்த மூல மென்பொருளுக்கான உரிம விவரங்கள்</string>\n</resources>\n"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-th/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"no_licenses_available\">แอปนี้ไม่มีใบอนุญาตโอเพนซอร์สใดๆ</string>\n    <string name=\"license_list_is_loading\">กำลังโหลดรายการใบอนุญาต</string>\n    <string name=\"preferences_license_summary\">รายละเอียดใบอนุญาตสำหรับซอฟต์แวร์โอเพ่นซอร์ส</string>\n    <string name=\"license_content_error\">เกิดข้อผิดพลาดขณะดึงใบอนุญาต</string>\n    <string name=\"oss_license_title\">ใบอนุญาตโอเพ่นซอร์ส</string>\n    <string name=\"license_is_loading\">กำลังโหลดข้อมูลใบอนุญาต</string>\n</resources>"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-tr/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_content_error\">Lisansı yüklemeye çalışırken bir sorunla karşılaşıldı.</string>\n    <string name=\"no_licenses_available\">Bu uygulamanın herhangi bir açık kaynak lisansı yok.</string>\n    <string name=\"oss_license_title\">Açık kaynak lisansları</string>\n    <string name=\"license_list_is_loading\">Lisans listesi yükleniyor.</string>\n    <string name=\"preferences_license_summary\">Açık kaynak yazılım için lisans bilgileri</string>\n    <string name=\"license_is_loading\">Lisans bilgisi yükleniyor.</string>\n</resources>"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-ug/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_content_error\">ئىجازەتنامىگە ئېرىشىۋاتقاندا خاتالىق كۆرۈلدى.</string>\n    <string name=\"no_licenses_available\">بۇ ئەپنىڭ ئوچۇق كودلۇق ئىجازەتنامىسى يوق.</string>\n    <string name=\"oss_license_title\">ئوچۇق كودلۇق ئىجازەتنامە</string>\n    <string name=\"license_is_loading\">ئىجازەتنامە ئۇچۇرى يۈكلىنىۋاتىدۇ.</string>\n    <string name=\"license_list_is_loading\">ئىجازەتنامە تىزىمى يۈكلىنىۋاتىدۇ.</string>\n    <string name=\"preferences_license_summary\">ئوچۇق كودلۇق يۇمشاق دېتالنىڭ ئىجازەت تەپسىلاتى</string>\n</resources>\n"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-uk/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_content_error\">Під час отримання ліцензії сталася помилка.</string>\n    <string name=\"oss_license_title\">Ліцензії з відкритим кодом</string>\n    <string name=\"preferences_license_summary\">Ліцензійні дані для відкритого програмного забезпечення</string>\n    <string name=\"no_licenses_available\">Цей застосунок не має ніяких ліцензій з відкритим кодом.</string>\n    <string name=\"license_list_is_loading\">Список ліцензій завантажується.</string>\n    <string name=\"license_is_loading\">Інформація про ліцензію завантажується.</string>\n</resources>"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-vi/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"oss_license_title\">Giấy phép mã nguồn mở</string>\n    <string name=\"license_is_loading\">Đang tải thông tin giấy phép.</string>\n    <string name=\"license_list_is_loading\">Danh sách giấy phép đang được tải.</string>\n    <string name=\"license_content_error\">Đã xảy ra lỗi khi lấy giấy phép.</string>\n    <string name=\"no_licenses_available\">Ứng dụng này không có bất kỳ giấy phép nguồn mở nào.</string>\n    <string name=\"preferences_license_summary\">Chi tiết giấy phép cho phần mềm mã nguồn mở</string>\n</resources>"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-zh-rCN/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"oss_license_title\">开源许可证</string>\n    <string name=\"license_is_loading\">正在加载许可证信息。</string>\n    <string name=\"license_list_is_loading\">正在加载许可证列表。</string>\n    <string name=\"preferences_license_summary\">开源软件的许可证详细信息</string>\n    <string name=\"license_content_error\">获取许可证时出错。</string>\n    <string name=\"no_licenses_available\">此应用没有任何开源许可证。</string>\n</resources>"
  },
  {
    "path": "play-services-oss-licenses/src/main/res/values-zh-rTW/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_content_error\">獲取授權時發生錯誤。</string>\n    <string name=\"no_licenses_available\">此應用程式沒有任何開源授權。</string>\n    <string name=\"oss_license_title\">開源授權</string>\n    <string name=\"license_is_loading\">正在載入授權資訊。</string>\n    <string name=\"license_list_is_loading\">正在載入授權列表。</string>\n    <string name=\"preferences_license_summary\">開源軟體的授權詳細資訊</string>\n</resources>\n"
  },
  {
    "path": "play-services-panorama/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\nandroid {\n    namespace \"com.google.android.gms.panorama\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n}\n\napply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG implementation of play-services-panorama'\n\ndependencies {\n    // Dependencies from play-services-panorama:17.1.0\n    api project(\":play-services-base\")\n    api project(\":play-services-basement\")\n    api project(\":play-services-tasks\")\n}\n"
  },
  {
    "path": "play-services-panorama/core/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'kotlin-android'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\ndependencies {\n    api project(':play-services-panorama')\n\n    implementation project(':play-services-base-core')\n\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion\"\n    implementation \"org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutineVersion\"\n    implementation \"org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutineVersion\"\n}\n\nandroid {\n    namespace \"org.microg.gms.panorama.core\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    sourceSets {\n        main {\n            java.srcDirs = ['src/main/kotlin']\n        }\n    }\n\n    lintOptions {\n        disable 'MissingTranslation'\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n\n    kotlinOptions {\n        jvmTarget = 1.8\n    }\n}\n\n// Nothing to publish yet\n//apply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG service implementation for play-services-panorama'\n"
  },
  {
    "path": "play-services-panorama/core/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2024 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <application>\n        <service android:name=\"org.microg.gms.panorama.PanoramaService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.panorama.service.START\" />\n            </intent-filter>\n        </service>\n    </application>\n</manifest>\n"
  },
  {
    "path": "play-services-panorama/core/src/main/kotlin/org/microg/gms/panorama/PanoramaService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage org.microg.gms.panorama\n\nimport android.net.Uri\nimport android.os.Bundle\nimport android.util.Log\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport com.google.android.gms.panorama.internal.IPanoramaCallbacks\nimport com.google.android.gms.panorama.internal.IPanoramaService\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\n\nconst val TAG = \"PanoramaService\"\n\nclass PanoramaService : BaseService(TAG, GmsService.PANORAMA) {\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        callback.onPostInitComplete(CommonStatusCodes.SUCCESS, PanoramaServiceImpl().asBinder(), null)\n    }\n}\n\nclass PanoramaServiceImpl : IPanoramaService.Stub() {\n    override fun loadPanoramaInfo(callback: IPanoramaCallbacks?, uri: Uri, bundle: Bundle, needGrantReadUriPermissions: Boolean) {\n        Log.d(TAG, \"Not implemented! $uri bundle:$bundle\")\n        runCatching { callback?.onPanoramaResult(CommonStatusCodes.SUCCESS, null, 0, null) }\n    }\n}\n"
  },
  {
    "path": "play-services-panorama/src/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2024 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest />\n"
  },
  {
    "path": "play-services-panorama/src/main/aidl/com/google/android/gms/panorama/Panorama.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.panorama;\n\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.GoogleApiClient;\n\n/**\n * The main entry point for panorama integration.\n */\n@Deprecated\npublic class Panorama {\n    /**\n     * Token to pass to {@link GoogleApiClient.Builder#addApi(Api)} to enable the Panorama features.\n     */\n    @Deprecated\n    public static final Api<Api.ApiOptions.NoOptions> API = null;\n\n    /**\n     * The entry point for interacting with the Panorama API.\n     */\n    @Deprecated\n    public static final PanoramaApi PanoramaApi = null;\n}\n"
  },
  {
    "path": "play-services-panorama/src/main/aidl/com/google/android/gms/panorama/PanoramaApi.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.panorama;\n\nimport android.content.Intent;\nimport android.net.Uri;\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.PendingResult;\nimport com.google.android.gms.common.api.Result;\n\n/**\n * The main entry point for interacting with Panorama viewer. This class provides methods for obtaining an Intent to view a Panorama.\n */\n@Deprecated\npublic interface PanoramaApi {\n    /**\n     * Loads information about a panorama.\n     *\n     * @param uri the URI of the panorama to load info about. May be a file:, content:, or android_resource: scheme.\n     */\n    @Deprecated\n    PendingResult<PanoramaApi.PanoramaResult> loadPanoramaInfo(GoogleApiClient client, Uri uri);\n\n    /**\n     * Loads information about a panorama from a content provider. This method will also explicitly grant and revoke access to\n     * the URI while the load is happening so images in content providers may be inspected without giving permission to an\n     * entire content provider. The returned viewer intent will also have the {@link Intent#FLAG_GRANT_READ_URI_PERMISSION} set so\n     * the viewer has access.\n     */\n    @Deprecated\n    PendingResult<PanoramaApi.PanoramaResult> loadPanoramaInfoAndGrantAccess(GoogleApiClient client, Uri uri);\n\n    /**\n     * Result interface for loading panorama info.\n     */\n    @Deprecated\n    interface PanoramaResult extends Result {\n        /**\n         * Returns if the image is a panorama this is not null and will launch a viewer when started. If the image is not a panorama this will be null.\n         */\n        @Deprecated\n        Intent getViewerIntent();\n    }\n}\n"
  },
  {
    "path": "play-services-panorama/src/main/aidl/com/google/android/gms/panorama/internal/IPanoramaCallbacks.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.panorama.internal;\n\nimport android.content.Intent;\n\ninterface IPanoramaCallbacks {\n    void onPanoramaResult(int statusCode, in Bundle statusExtras, int unknown, in Intent viewerIntent);\n}"
  },
  {
    "path": "play-services-panorama/src/main/aidl/com/google/android/gms/panorama/internal/IPanoramaService.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.panorama.internal;\n\nimport com.google.android.gms.panorama.internal.IPanoramaCallbacks;\nimport android.os.Bundle;\nimport android.net.Uri;\n\ninterface IPanoramaService {\n    void loadPanoramaInfo(IPanoramaCallbacks callback, in Uri uri, in Bundle bundle, boolean needGrantReadUriPermissions) = 0;\n}"
  },
  {
    "path": "play-services-pay/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\nandroid {\n    namespace \"com.google.android.gms.pay\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n}\n\n// Nothing to publish yet\n//apply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG API for play-services-pay'\n\ndependencies {\n    // Dependencies from play-services-pay:16.5.0\n    implementation \"androidx.activity:activity:1.2.3\"\n    implementation \"androidx.fragment:fragment:1.3.4\"\n    api project(':play-services-base')\n    api project(':play-services-basement')\n    api project(':play-services-tasks')\n\n    annotationProcessor project(':safe-parcel-processor')\n}\n"
  },
  {
    "path": "play-services-pay/core/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'kotlin-android'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\ndependencies {\n    api project(':play-services-pay')\n\n    implementation project(':play-services-base-core')\n\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion\"\n    implementation \"org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutineVersion\"\n    implementation \"org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutineVersion\"\n}\n\nandroid {\n    namespace \"org.microg.gms.pay.core\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    sourceSets {\n        main {\n            java.srcDirs = ['src/main/kotlin']\n        }\n    }\n\n    lintOptions {\n        disable 'MissingTranslation'\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n\n    kotlinOptions {\n        jvmTarget = 1.8\n    }\n}\n\n// Nothing to publish yet\n//apply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG service implementation for play-services-pay'\n"
  },
  {
    "path": "play-services-pay/core/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <application>\n        <activity-alias\n            android:name=\"com.google.android.gms.pay.main.PayActivity\"\n            android:exported=\"true\"\n            android:process=\":ui\"\n            android:targetActivity=\"org.microg.gms.pay.PayActivity\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.pay.PAY\" />\n                <action android:name=\"com.google.android.gms.pay.PAY_OPTIONAL\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </activity-alias>\n        <activity\n            android:name=\"org.microg.gms.pay.PayActivity\"\n            android:exported=\"true\"\n            android:process=\":ui\" />\n\n        <service android:name=\"org.microg.gms.pay.PayService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.pay.service.BIND\" />\n            </intent-filter>\n        </service>\n        <service\n            android:name=\"org.microg.gms.pay.ThirdPartyPayService\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.pay.service.THIRD_PARTY\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </service>\n    </application>\n</manifest>\n"
  },
  {
    "path": "play-services-pay/core/src/main/kotlin/org/microg/gms/pay/PayActivity.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.pay\n\nimport android.app.Activity\nimport android.os.Bundle\nimport android.view.Gravity\nimport android.widget.TextView\n\nclass PayActivity : Activity() {\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        setContentView(TextView(this).apply {\n            text = \"Not yet supported:\\n${intent?.action}\"\n            gravity = Gravity.CENTER\n        })\n    }\n}"
  },
  {
    "path": "play-services-pay/core/src/main/kotlin/org/microg/gms/pay/PayService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.pay\n\nimport android.content.Context\nimport android.os.Parcel\nimport android.util.Base64\nimport android.util.Log\nimport com.google.android.gms.common.Feature\nimport com.google.android.gms.common.api.ApiMetadata\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.internal.ConnectionInfo\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport com.google.android.gms.pay.DataChangeListenerRequest\nimport com.google.android.gms.pay.GetBulletinsRequest\nimport com.google.android.gms.pay.GetClosedLoopCardsFromServerRequest\nimport com.google.android.gms.pay.GetClosedLoopCardsRequest\nimport com.google.android.gms.pay.GetDigitalCarKeysRequest\nimport com.google.android.gms.pay.GetOnboardingInfoRequest\nimport com.google.android.gms.pay.GetPayCapabilitiesRequest\nimport com.google.android.gms.pay.GetPaymentMethodsRequest\nimport com.google.android.gms.pay.GetSortOrderRequest\nimport com.google.android.gms.pay.GetValuablesFromServerRequest\nimport com.google.android.gms.pay.GetValuablesRequest\nimport com.google.android.gms.pay.internal.IPayService\nimport com.google.android.gms.pay.internal.IPayServiceCallbacks\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.common.GooglePackagePermission\nimport org.microg.gms.common.PackageUtils\nimport org.microg.gms.utils.ExtendedPackageInfo\nimport org.microg.gms.utils.toBase64\nimport org.microg.gms.utils.warnOnTransactionIssues\n\nprivate const val TAG = \"PayService\"\n\nclass PayService : BaseService(TAG, GmsService.PAY) {\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        val packageName = PackageUtils.getAndCheckCallingPackage(this, request.packageName)\n            ?: throw IllegalArgumentException(\"Missing package name\")\n        callback.onPostInitCompleteWithConnectionInfo(CommonStatusCodes.SUCCESS, PayServiceImpl(this, packageName), ConnectionInfo().apply {\n            features = arrayOf(\n                Feature(\"pay\", 10),\n                Feature(\"pay_attestation_signal\", 1),\n                Feature(\"pay_pay_capabilities\", 1),\n                Feature(\"pay_feature_check\", 1),\n                Feature(\"pay_get_card_centric_bundle\", 1),\n                Feature(\"pay_get_passes\", 1),\n                Feature(\"pay_get_pay_api_availability_status\", 3),\n                Feature(\"pay_get_se_prepaid_card\", 1),\n                Feature(\"pay_debit_se_prepaid_card\", 1),\n                Feature(\"pay_get_specific_bulletin\", 1),\n                Feature(\"pay_get_transit_cards\", 1),\n                Feature(\"pay_get_wallet_status\", 1),\n                Feature(\"pay_global_actions\", 1),\n                Feature(\"pay_gp3_support\", 1),\n                Feature(\"pay_homescreen_sorting\", 3),\n                Feature(\"pay_homescreen_bulletins\", 2),\n                Feature(\"pay_onboarding\", 2),\n                Feature(\"pay_mark_tos_accepted_for_partner\", 1),\n                Feature(\"pay_move_card_on_other_device\", 1),\n                Feature(\"pay_passes_field_update_notifications\", 1),\n                Feature(\"pay_passes_notifications\", 2),\n                Feature(\"pay_payment_method\", 1),\n                Feature(\"pay_payment_method_action_tokens\", 2),\n                Feature(\"pay_payment_method_server_action\", 1),\n                Feature(\"pay_provision_se_prepaid_card\", 1),\n                Feature(\"pay_request_module\", 1),\n                Feature(\"pay_reverse_purchase\", 1),\n                Feature(\"pay_save_passes\", 5),\n                Feature(\"pay_save_passes_jwt\", 3),\n                Feature(\"pay_save_purchased_card\", 1),\n                Feature(\"pay_sync_bundle\", 2),\n                Feature(\"pay_settings\", 1),\n                Feature(\"pay_topup_se_prepaid_card\", 1),\n                Feature(\"pay_list_commuter_pass_renewal_options_for_se_prepaid_card\", 1),\n                Feature(\"pay_transactions\", 6),\n                Feature(\"pay_update_bundle_with_client_settings\", 1),\n                Feature(\"pay_clock_skew_millis\", 1),\n                Feature(\"pay_se_postpaid_transactions\", 1),\n                Feature(\"pay_se_prepaid_transactions\", 1),\n                Feature(\"pay_get_clock_skew_millis\", 1),\n                Feature(\"pay_renew_commuter_pass_for_se_prepaid_card\", 1),\n                Feature(\"pay_remove_se_postpaid_token\", 1),\n                Feature(\"pay_change_se_postpaid_default_status\", 1),\n                Feature(\"pay_wear_payment_methods\", 2),\n                Feature(\"pay_wear_closed_loop_cards\", 1),\n                Feature(\"pay_perform_wear_operation\", 1),\n                Feature(\"pay_delete_se_prepaid_card\", 1),\n                Feature(\"pay_transit_issuer_tos\", 1),\n                Feature(\"pay_get_se_mfi_prepaid_cards\", 1),\n                Feature(\"pay_get_last_user_present_timestamp\", 1),\n                Feature(\"pay_mdoc\", 7),\n                Feature(\"pay_get_se_feature_readiness_status\", 1),\n                Feature(\"pay_recover_se_card\", 1),\n                Feature(\"pay_set_wallet_item_surfacing\", 2),\n                Feature(\"pay_set_se_transit_default\", 1),\n                Feature(\"pay_get_wallet_bulletins\", 2),\n                Feature(\"pay_mse_operation\", 1),\n                Feature(\"pay_clear_bulletin_interaction_for_dev\", 1),\n                Feature(\"pay_get_pending_intent_for_wallet_on_wear\", 2),\n                Feature(\"pay_get_predefined_rotating_barcode_values\", 1),\n                Feature(\"pay_get_mdl_refresh_timestamps\", 1),\n                Feature(\"pay_store_mdl_refresh_timestamp\", 1),\n                Feature(\"pay_perform_id_card_operation\", 1),\n                Feature(\"pay_block_closed_loop_cards\", 1),\n                Feature(\"pay_delete_data_for_tests\", 1),\n                Feature(\"pay_perform_closed_loop_operation\", 1)\n            )\n        })\n    }\n}\n\nclass PayServiceImpl(private val context: Context, private val packageName: String) : IPayService.Stub() {\n\n    private val isFirstParty\n        get() = ExtendedPackageInfo(context, packageName).hasGooglePackagePermission(GooglePackagePermission.WALLET)\n\n    override fun getValuables(request: GetValuablesRequest?, callbacks: IPayServiceCallbacks?, metadata: ApiMetadata?) {\n        if (!isFirstParty) {\n            callbacks?.onProtoSafeParcelable(Status.INTERNAL_ERROR, null)\n            return\n        }\n        Log.d(TAG, \"Not yet implemented: getValuables($request)\")\n        callbacks?.onProtoSafeParcelable(Status.INTERNAL_ERROR, null)\n    }\n\n    override fun getValuablesFromServer(request: GetValuablesFromServerRequest?, callbacks: IPayServiceCallbacks?, metadata: ApiMetadata?) {\n        if (!isFirstParty) {\n            callbacks?.onProtoSafeParcelable(Status.INTERNAL_ERROR, null)\n            return\n        }\n        Log.d(TAG, \"Not yet implemented: getValuablesFromServer($request)\")\n        callbacks?.onProtoSafeParcelable(Status.INTERNAL_ERROR, null)\n    }\n\n    override fun getClosedLoopCards(request: GetClosedLoopCardsRequest?, callbacks: IPayServiceCallbacks?, metadata: ApiMetadata?) {\n        if (!isFirstParty) {\n            callbacks?.onProtoSafeParcelable(Status.INTERNAL_ERROR, null)\n            return\n        }\n        Log.d(TAG, \"Not yet implemented: getClosedLoopCards($request)\")\n        callbacks?.onProtoSafeParcelable(Status.INTERNAL_ERROR, null)\n    }\n\n    override fun getClosedLoopCardsFromServer(request: GetClosedLoopCardsFromServerRequest?, callbacks: IPayServiceCallbacks?, metadata: ApiMetadata?) {\n        if (!isFirstParty) {\n            callbacks?.onProtoSafeParcelable(Status.INTERNAL_ERROR, null)\n            return\n        }\n        Log.d(TAG, \"Not yet implemented: getClosedLoopCardsFromServer($request)\")\n        callbacks?.onProtoSafeParcelable(Status.INTERNAL_ERROR, null)\n    }\n\n    override fun registerDataChangedListener(request: DataChangeListenerRequest?, callbacks: IPayServiceCallbacks?, metadata: ApiMetadata?) {\n        if (!isFirstParty) return\n        Log.d(TAG, \"Not yet implemented: registerDataChangedListener($request)\")\n    }\n\n    override fun getSortOrder(request: GetSortOrderRequest?, callbacks: IPayServiceCallbacks?, metadata: ApiMetadata?) {\n        if (!isFirstParty) {\n            callbacks?.onGetSortOrderResponse(Status.INTERNAL_ERROR, null)\n            return\n        }\n        Log.d(TAG, \"Not yet implemented: getSortOrder($request)\")\n        callbacks?.onGetSortOrderResponse(Status.INTERNAL_ERROR, null)\n    }\n\n    override fun getPaymentMethods(request: GetPaymentMethodsRequest?, callbacks: IPayServiceCallbacks?, metadata: ApiMetadata?) {\n        if (!isFirstParty) {\n            callbacks?.onProtoSafeParcelable(Status.INTERNAL_ERROR, null)\n            return\n        }\n        Log.d(TAG, \"Not yet implemented: getPaymentMethods($request)\")\n        callbacks?.onProtoSafeParcelable(Status.INTERNAL_ERROR, null)\n    }\n\n    override fun getOnboardingInfo(request: GetOnboardingInfoRequest?, callbacks: IPayServiceCallbacks?, metadata: ApiMetadata?) {\n        if (!isFirstParty) {\n            callbacks?.onProtoSafeParcelable(Status.INTERNAL_ERROR, null)\n            return\n        }\n        Log.d(TAG, \"Not yet implemented: getOnboardingInfo($request)\")\n        callbacks?.onProtoSafeParcelable(Status.INTERNAL_ERROR, null)\n    }\n\n    override fun getPayCapabilities(request: GetPayCapabilitiesRequest?, callbacks: IPayServiceCallbacks?, metadata: ApiMetadata?) {\n        Log.d(TAG, \"Not yet implemented: getPayCapabilities($request)\")\n        callbacks?.onStatus(Status.INTERNAL_ERROR)\n    }\n\n    override fun getDigitalCarKeys(request: GetDigitalCarKeysRequest?, callbacks: IPayServiceCallbacks?, metadata: ApiMetadata?) {\n        if (!isFirstParty) {\n            callbacks?.onProtoSafeParcelable(Status.INTERNAL_ERROR, null)\n            return\n        }\n        Log.d(TAG, \"Not yet implemented: getDigitalCarKeys($request)\")\n        callbacks?.onProtoSafeParcelable(Status.INTERNAL_ERROR, null)\n    }\n\n    override fun getWalletBulletins(request: GetBulletinsRequest?, callbacks: IPayServiceCallbacks?, metadata: ApiMetadata?) {\n        if (!isFirstParty) {\n            callbacks?.onProtoSafeParcelable(Status.INTERNAL_ERROR, null)\n            return\n        }\n        Log.d(TAG, \"Not yet implemented: getWalletBulletins($request)\")\n        callbacks?.onProtoSafeParcelable(Status.INTERNAL_ERROR, null)\n    }\n\n    override fun performIdCard(request: ByteArray?, callbacks: IPayServiceCallbacks?, metadata: ApiMetadata?) {\n        if (!isFirstParty) {\n            callbacks?.onByteArray(Status.INTERNAL_ERROR, null)\n            return\n        }\n        Log.d(TAG, \"Not yet implemented: performIdCard(${request?.toBase64(Base64.NO_WRAP)})\")\n        callbacks?.onByteArray(Status.INTERNAL_ERROR, null)\n    }\n\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =\n        warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n}"
  },
  {
    "path": "play-services-pay/core/src/main/kotlin/org/microg/gms/pay/ThirdPartyPayService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.pay\n\nimport android.util.Log\nimport com.google.android.gms.common.Feature\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.internal.ConnectionInfo\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport com.google.android.gms.pay.CheckReadinessForEmoneyRequest\nimport com.google.android.gms.pay.GetMdocCredentialRequest\nimport com.google.android.gms.pay.GetPayApiAvailabilityStatusRequest\nimport com.google.android.gms.pay.GetPendingIntentForWalletOnWearRequest\nimport com.google.android.gms.pay.NotifyCardTapEventRequest\nimport com.google.android.gms.pay.NotifyEmoneyCardStatusUpdateRequest\nimport com.google.android.gms.pay.PayApiAvailabilityStatus\nimport com.google.android.gms.pay.PushEmoneyCardRequest\nimport com.google.android.gms.pay.SavePassesRequest\nimport com.google.android.gms.pay.SyncBundleRequest\nimport com.google.android.gms.pay.internal.IPayServiceCallbacks\nimport com.google.android.gms.pay.internal.IThirdPartyPayService\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\n\n\nprivate const val TAG = \"ThirdPartyPayService\"\n\nclass ThirdPartyPayService : BaseService(TAG, GmsService.PAY) {\n\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        callback.onPostInitCompleteWithConnectionInfo(CommonStatusCodes.SUCCESS, ThirdPartyPayServiceImpl().asBinder(), ConnectionInfo().apply {\n            features = arrayOf(\n                Feature(\"pay_get_pay_api_availability_status\", 3),\n                Feature(\"pay_save_passes\", 5),\n                Feature(\"pay_save_passes_jwt\", 3),\n                Feature(\"pay_sync_bundle\", 2),\n                Feature(\"pay_get_pending_intent_for_wallet_on_wear\", 2),\n                Feature(\"pay_get_mdoc_credential_pending_intent\", 1),\n                Feature(\"pay_notify_card_tap_event\", 1),\n                Feature(\"pay_check_readiness_for_emoney\", 1),\n                Feature(\"pay_push_emoney_card\", 1),\n                Feature(\"pay_notify_emoney_card_status_update\", 1)\n            )\n        })\n    }\n}\n\nclass ThirdPartyPayServiceImpl : IThirdPartyPayService.Stub() {\n    override fun getPayApiAvailabilityStatus(request: GetPayApiAvailabilityStatusRequest?, callback: IPayServiceCallbacks) {\n        Log.d(TAG, \"onPayApiAvailabilityStatus: Reporting NOT_ELIGIBLE\")\n        callback.onPayApiAvailabilityStatus(Status.SUCCESS, PayApiAvailabilityStatus.NOT_ELIGIBLE)\n    }\n\n    override fun savePasses(request: SavePassesRequest?, callback: IPayServiceCallbacks) {\n        Log.d(TAG, \"savePasses: return SERVICE_MISSING\")\n        callback.onError(Status(CommonStatusCodes.SERVICE_MISSING))\n    }\n\n    override fun syncBundle(request: SyncBundleRequest?, callback: IPayServiceCallbacks?) {\n        Log.d(TAG, \"syncBundle Not yet implemented\")\n    }\n\n    override fun getPendingForWalletOnWear(request: GetPendingIntentForWalletOnWearRequest?, callback: IPayServiceCallbacks?) {\n        Log.d(TAG, \"getPendingForWalletOnWear Not yet implemented\")\n    }\n\n    override fun getMdocCredential(request: GetMdocCredentialRequest?, callback: IPayServiceCallbacks?) {\n        Log.d(TAG, \"getMdocCredential Not yet implemented\")\n    }\n\n    override fun notifyCardTapEvent(request: NotifyCardTapEventRequest?, callback: IPayServiceCallbacks?) {\n        Log.d(TAG, \"notifyCardTapEvent Not yet implemented\")\n    }\n\n    override fun checkReadinessForEmoney(request: CheckReadinessForEmoneyRequest?, callback: IPayServiceCallbacks?) {\n        Log.d(TAG, \"checkReadinessForEmoney Not yet implemented\")\n    }\n\n    override fun pushEmoneyCard(request: PushEmoneyCardRequest?, callback: IPayServiceCallbacks?) {\n        Log.d(TAG, \"pushEmoneyCard Not yet implemented\")\n    }\n\n    override fun notifyEmoneyCardStatusUpdate(request: NotifyEmoneyCardStatusUpdateRequest?, callback: IPayServiceCallbacks?) {\n        Log.d(TAG, \"notifyEmoneyCardStatusUpdate Not yet implemented\")\n    }\n\n}"
  },
  {
    "path": "play-services-pay/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest />\n"
  },
  {
    "path": "play-services-pay/src/main/aidl/com/google/android/gms/pay/CheckReadinessForEmoneyRequest.aidl",
    "content": "package com.google.android.gms.pay;\n\nparcelable CheckReadinessForEmoneyRequest;"
  },
  {
    "path": "play-services-pay/src/main/aidl/com/google/android/gms/pay/DataChangeListenerRequest.aidl",
    "content": "package com.google.android.gms.pay;\n\nparcelable DataChangeListenerRequest;"
  },
  {
    "path": "play-services-pay/src/main/aidl/com/google/android/gms/pay/EmoneyReadiness.aidl",
    "content": "package com.google.android.gms.pay;\n\nparcelable EmoneyReadiness;"
  },
  {
    "path": "play-services-pay/src/main/aidl/com/google/android/gms/pay/GetBulletinsRequest.aidl",
    "content": "package com.google.android.gms.pay;\n\nparcelable GetBulletinsRequest;"
  },
  {
    "path": "play-services-pay/src/main/aidl/com/google/android/gms/pay/GetClosedLoopCardsFromServerRequest.aidl",
    "content": "package com.google.android.gms.pay;\n\nparcelable GetClosedLoopCardsFromServerRequest;"
  },
  {
    "path": "play-services-pay/src/main/aidl/com/google/android/gms/pay/GetClosedLoopCardsRequest.aidl",
    "content": "package com.google.android.gms.pay;\n\nparcelable GetClosedLoopCardsRequest;"
  },
  {
    "path": "play-services-pay/src/main/aidl/com/google/android/gms/pay/GetDigitalCarKeysRequest.aidl",
    "content": "package com.google.android.gms.pay;\n\nparcelable GetDigitalCarKeysRequest;"
  },
  {
    "path": "play-services-pay/src/main/aidl/com/google/android/gms/pay/GetMdocCredentialRequest.aidl",
    "content": "package com.google.android.gms.pay;\n\nparcelable GetMdocCredentialRequest;"
  },
  {
    "path": "play-services-pay/src/main/aidl/com/google/android/gms/pay/GetOnboardingInfoRequest.aidl",
    "content": "package com.google.android.gms.pay;\n\nparcelable GetOnboardingInfoRequest;"
  },
  {
    "path": "play-services-pay/src/main/aidl/com/google/android/gms/pay/GetPayApiAvailabilityStatusRequest.aidl",
    "content": "package com.google.android.gms.pay;\n\nparcelable GetPayApiAvailabilityStatusRequest;"
  },
  {
    "path": "play-services-pay/src/main/aidl/com/google/android/gms/pay/GetPayCapabilitiesRequest.aidl",
    "content": "package com.google.android.gms.pay;\n\nparcelable GetPayCapabilitiesRequest;"
  },
  {
    "path": "play-services-pay/src/main/aidl/com/google/android/gms/pay/GetPaymentMethodsRequest.aidl",
    "content": "package com.google.android.gms.pay;\n\nparcelable GetPaymentMethodsRequest;"
  },
  {
    "path": "play-services-pay/src/main/aidl/com/google/android/gms/pay/GetPendingIntentForWalletOnWearRequest.aidl",
    "content": "package com.google.android.gms.pay;\n\nparcelable GetPendingIntentForWalletOnWearRequest;"
  },
  {
    "path": "play-services-pay/src/main/aidl/com/google/android/gms/pay/GetSortOrderRequest.aidl",
    "content": "package com.google.android.gms.pay;\n\nparcelable GetSortOrderRequest;"
  },
  {
    "path": "play-services-pay/src/main/aidl/com/google/android/gms/pay/GetSortOrderResponse.aidl",
    "content": "package com.google.android.gms.pay;\n\nparcelable GetSortOrderResponse;"
  },
  {
    "path": "play-services-pay/src/main/aidl/com/google/android/gms/pay/GetValuablesFromServerRequest.aidl",
    "content": "package com.google.android.gms.pay;\n\nparcelable GetValuablesFromServerRequest;"
  },
  {
    "path": "play-services-pay/src/main/aidl/com/google/android/gms/pay/GetValuablesRequest.aidl",
    "content": "package com.google.android.gms.pay;\n\nparcelable GetValuablesRequest;"
  },
  {
    "path": "play-services-pay/src/main/aidl/com/google/android/gms/pay/GetWalletStatusResponse.aidl",
    "content": "package com.google.android.gms.pay;\n\nparcelable GetWalletStatusResponse;"
  },
  {
    "path": "play-services-pay/src/main/aidl/com/google/android/gms/pay/NotifyCardTapEventRequest.aidl",
    "content": "package com.google.android.gms.pay;\n\nparcelable NotifyCardTapEventRequest;"
  },
  {
    "path": "play-services-pay/src/main/aidl/com/google/android/gms/pay/NotifyEmoneyCardStatusUpdateRequest.aidl",
    "content": "package com.google.android.gms.pay;\n\nparcelable NotifyEmoneyCardStatusUpdateRequest;"
  },
  {
    "path": "play-services-pay/src/main/aidl/com/google/android/gms/pay/PayApiError.aidl",
    "content": "package com.google.android.gms.pay;\n\nparcelable PayApiError;"
  },
  {
    "path": "play-services-pay/src/main/aidl/com/google/android/gms/pay/ProtoSafeParcelable.aidl",
    "content": "package com.google.android.gms.pay;\n\nparcelable ProtoSafeParcelable;"
  },
  {
    "path": "play-services-pay/src/main/aidl/com/google/android/gms/pay/PushEmoneyCardRequest.aidl",
    "content": "package com.google.android.gms.pay;\n\nparcelable PushEmoneyCardRequest;"
  },
  {
    "path": "play-services-pay/src/main/aidl/com/google/android/gms/pay/SavePassesRequest.aidl",
    "content": "package com.google.android.gms.pay;\n\nparcelable SavePassesRequest;"
  },
  {
    "path": "play-services-pay/src/main/aidl/com/google/android/gms/pay/SyncBundleRequest.aidl",
    "content": "package com.google.android.gms.pay;\n\nparcelable SyncBundleRequest;"
  },
  {
    "path": "play-services-pay/src/main/aidl/com/google/android/gms/pay/internal/IPayService.aidl",
    "content": "package com.google.android.gms.pay.internal;\n\nimport com.google.android.gms.common.api.ApiMetadata;\nimport com.google.android.gms.pay.internal.IPayServiceCallbacks;\nimport com.google.android.gms.pay.DataChangeListenerRequest;\nimport com.google.android.gms.pay.GetBulletinsRequest;\nimport com.google.android.gms.pay.GetClosedLoopCardsRequest;\nimport com.google.android.gms.pay.GetClosedLoopCardsFromServerRequest;\nimport com.google.android.gms.pay.GetDigitalCarKeysRequest;\nimport com.google.android.gms.pay.GetOnboardingInfoRequest;\nimport com.google.android.gms.pay.GetPayCapabilitiesRequest;\nimport com.google.android.gms.pay.GetPaymentMethodsRequest;\nimport com.google.android.gms.pay.GetSortOrderRequest;\nimport com.google.android.gms.pay.GetValuablesRequest;\nimport com.google.android.gms.pay.GetValuablesFromServerRequest;\n\ninterface IPayService {\n\n\n\n    void getValuables(in GetValuablesRequest request, IPayServiceCallbacks callbacks, in ApiMetadata metadata) = 4;\n    void getValuablesFromServer(in GetValuablesFromServerRequest request, IPayServiceCallbacks callbacks, in ApiMetadata metadata) = 5;\n\n    void getClosedLoopCards(in GetClosedLoopCardsRequest request, IPayServiceCallbacks callbacks, in ApiMetadata metadata) = 7;\n    void getClosedLoopCardsFromServer(in GetClosedLoopCardsFromServerRequest request, IPayServiceCallbacks callbacks, in ApiMetadata metadata) = 8;\n\n\n    void registerDataChangedListener(in DataChangeListenerRequest request, IPayServiceCallbacks callbacks, in ApiMetadata metadata) = 11;\n\n\n\n\n\n\n\n\n\n\n\n\n    void getSortOrder(in GetSortOrderRequest request, IPayServiceCallbacks callbacks, in ApiMetadata metadata) = 23;\n\n\n\n\n\n    void getPaymentMethods(in GetPaymentMethodsRequest request, IPayServiceCallbacks callbacks, in ApiMetadata metadata) = 29;\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n    void getOnboardingInfo(in GetOnboardingInfoRequest request, IPayServiceCallbacks callbacks, in ApiMetadata metadata) = 54;\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n    void getPayCapabilities(in GetPayCapabilitiesRequest request, IPayServiceCallbacks callbacks, in ApiMetadata metadata) = 80;\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n    void getDigitalCarKeys(in GetDigitalCarKeysRequest request, IPayServiceCallbacks callbacks, in ApiMetadata metadata) = 101;\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n    void getWalletBulletins(in GetBulletinsRequest request, IPayServiceCallbacks callbacks, in ApiMetadata metadata) = 114;\n\n\n\n\n\n\n\n\n\n\n\n\n    void performIdCard(in byte[] request, IPayServiceCallbacks callbacks, in ApiMetadata metadata) = 128;\n}"
  },
  {
    "path": "play-services-pay/src/main/aidl/com/google/android/gms/pay/internal/IPayServiceCallbacks.aidl",
    "content": "package com.google.android.gms.pay.internal;\n\nimport android.app.PendingIntent;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.pay.EmoneyReadiness;\nimport com.google.android.gms.pay.GetSortOrderResponse;\nimport com.google.android.gms.pay.GetWalletStatusResponse;\nimport com.google.android.gms.pay.PayApiError;\nimport com.google.android.gms.pay.ProtoSafeParcelable;\n\ninterface IPayServiceCallbacks {\n    oneway void onStatus(in Status status) = 1;\n//    oneway void onGetPayGlobalActionCardsResponse(in Status status, in GetPayGlobalActionCardsResponse response) = 2;\n    oneway void onPendingIntent(in Status status, in PendingIntent pendingIntent) = 3;\n    oneway void onProtoSafeParcelable(in Status status, in ProtoSafeParcelable proto) = 4;\n//    oneway void onDataChangeListenerResponse(in DataChangeListenerResponse response) = 5;\n    oneway void onGetSortOrderResponse(in Status status, in GetSortOrderResponse response) = 6;\n    oneway void onBoolean(in Status status, boolean b) = 7;\n//    oneway void onGetTransactionsResponse(in Status status, in GetTransactionsResponse response) = 8;\n    oneway void onPayApiError(in PayApiError error) = 9;\n//    oneway void onGetOutstandingPurchaseOrderIdResponse(in Status status, in GetOutstandingPurchaseOrderIdResponse response) = 10;\n//    oneway void onGetClosedLoopBundleResponse(in Status status, in GetClosedLoopBundleResponse response) = 11;\n//    oneway void onGetPayCardArtResponse(in Status status, in GetPayCardArtResponse response) = 12;\n//    oneway void onSyncTransactionsResponse(in Status status, in SyncTransactionsResponse response) = 13;\n    oneway void onByteArray(in Status status, in byte[] bArr) = 14;\n//    oneway void onGetPassesResponse(in Status status, in GetPassesResponse response) = 15;\n    oneway void onLong(in Status status, long l) = 16;\n    oneway void onError(in Status status) = 17;\n//    oneway void onGp3SupportInfo(in Status status, Gp3SupportInfo info) = 18;\n    oneway void onPayApiAvailabilityStatus(in Status status, int availabilityStatus) = 19;\n//    oneway void onGetTransitCardsResponse(in Status status, in GetTransitCardsResponse response) = 20;\n//    oneway void onGetWalletStatusResonse(in Status status, in GetWalletStatusResponse getWalletStatusResponse) = 21;\n//    oneway void onGetSeFeatureReadinessStatusResponse(in Status status, in GetSeFeatureReadinessStatusResponse response) = 22;\n//    oneway void onSyncTransactionByIdResponse(in Status status, in SyncTransactionByIdResponse response) = 23;\n//    oneway void onGetImagesForValuableResponse(in Status status, in GetImagesForValuableResponse response) = 24;\n    oneway void onEmoneyReadiness(in Status status, in EmoneyReadiness emoneyReadiness) = 25;\n//    oneway void onSaveImagesForValuableResponse(in Status status, in SaveImagesForValuableResponse emoneyReadiness) = 26;\n//    oneway void onGetIntegrityTokenForPixResponse(in Status status, in GetIntegrityTokenForPixResponse emoneyReadiness) = 27;\n}"
  },
  {
    "path": "play-services-pay/src/main/aidl/com/google/android/gms/pay/internal/IThirdPartyPayService.aidl",
    "content": "package com.google.android.gms.pay.internal;\n\nimport com.google.android.gms.pay.GetPayApiAvailabilityStatusRequest;\nimport com.google.android.gms.pay.internal.IPayServiceCallbacks;\nimport com.google.android.gms.pay.SavePassesRequest;\nimport com.google.android.gms.pay.SyncBundleRequest;\nimport com.google.android.gms.pay.CheckReadinessForEmoneyRequest;\nimport com.google.android.gms.pay.GetMdocCredentialRequest;\nimport com.google.android.gms.pay.GetPendingIntentForWalletOnWearRequest;\nimport com.google.android.gms.pay.NotifyCardTapEventRequest;\nimport com.google.android.gms.pay.PushEmoneyCardRequest;\nimport com.google.android.gms.pay.NotifyEmoneyCardStatusUpdateRequest;\n\ninterface IThirdPartyPayService {\n       void getPayApiAvailabilityStatus(in GetPayApiAvailabilityStatusRequest request, in IPayServiceCallbacks callback) = 1; // Reply via onPayApiAvailabilityStatus\n       void savePasses(in SavePassesRequest request, in IPayServiceCallbacks callback) = 2; // Reply via onPendingIntent\n       void syncBundle(in SyncBundleRequest request, in IPayServiceCallbacks callback) = 3;\n       void getPendingForWalletOnWear(in GetPendingIntentForWalletOnWearRequest request, in IPayServiceCallbacks callback) = 4; // Reply via onPendingIntentForWalletOnWear\n       void getMdocCredential(in GetMdocCredentialRequest request, in IPayServiceCallbacks callback) = 5;\n       void notifyCardTapEvent(in NotifyCardTapEventRequest request, in IPayServiceCallbacks callback) = 6; // Reply via onStatus or onPayApiError\n       void checkReadinessForEmoney(in CheckReadinessForEmoneyRequest request, in IPayServiceCallbacks callback) = 7; // Reply via onEmoneyReadiness\n       void pushEmoneyCard(in PushEmoneyCardRequest request, in IPayServiceCallbacks callback) = 8; // Reply via onPendingIntent\n       void notifyEmoneyCardStatusUpdate(in NotifyEmoneyCardStatusUpdateRequest request, in IPayServiceCallbacks callback) = 9; // Reply via onStatus\n}"
  },
  {
    "path": "play-services-pay/src/main/java/com/google/android/gms/pay/CheckReadinessForEmoneyRequest.java",
    "content": "package com.google.android.gms.pay;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\n\n@Hide\n@SafeParcelable.Class\npublic class CheckReadinessForEmoneyRequest extends AbstractSafeParcelable {\n    @Field(1)\n    public String serviceProvider;\n    @Nullable\n    @Field(2)\n    public String accountName;\n\n    @Constructor\n    public CheckReadinessForEmoneyRequest(@Param(1) String serviceProvider, @Nullable @Param(2) String accountName) {\n        this.serviceProvider = serviceProvider;\n        this.accountName = accountName;\n    }\n\n    @Override\n    public void writeToParcel(Parcel out, int flags) {\n        CREATOR.writeToParcel(this, out, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<CheckReadinessForEmoneyRequest> CREATOR = findCreator(CheckReadinessForEmoneyRequest.class);\n}\n"
  },
  {
    "path": "play-services-pay/src/main/java/com/google/android/gms/pay/DataChangeListenerRequest.java",
    "content": "package com.google.android.gms.pay;\n\nimport android.os.Parcel;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class DataChangeListenerRequest extends AbstractSafeParcelable {\n\n    @Override\n    public void writeToParcel(Parcel out, int flags) {\n        CREATOR.writeToParcel(this, out, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<DataChangeListenerRequest> CREATOR = findCreator(DataChangeListenerRequest.class);\n}\n"
  },
  {
    "path": "play-services-pay/src/main/java/com/google/android/gms/pay/EmoneyReadiness.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.pay;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport java.util.Objects;\n\n/**\n * {@link Parcelable} representing an e-money readiness result.\n */\npublic class EmoneyReadiness extends AbstractSafeParcelable {\n    @Field(value = 1, getterName = \"getEmoneyReadinessStatus\")\n    private final @EmoneyReadinessStatus int emoneyReadinessStatus;\n\n    public EmoneyReadiness(@Param(1) @EmoneyReadinessStatus int emoneyReadinessStatus) {\n        this.emoneyReadinessStatus = emoneyReadinessStatus;\n    }\n\n    @Override\n    public final boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof EmoneyReadiness)) return false;\n\n        EmoneyReadiness that = (EmoneyReadiness) o;\n        return emoneyReadinessStatus == that.emoneyReadinessStatus;\n    }\n\n    /**\n     * Gets the int value defined in {@link EmoneyReadinessStatus}.\n     */\n    public @EmoneyReadinessStatus int getEmoneyReadinessStatus() {\n        return emoneyReadinessStatus;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hashCode(new Object[]{emoneyReadinessStatus});\n    }\n\n    @Override\n    public void writeToParcel(Parcel out, int flags) {\n        CREATOR.writeToParcel(this, out, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<EmoneyReadiness> CREATOR = findCreator(EmoneyReadiness.class);\n}\n"
  },
  {
    "path": "play-services-pay/src/main/java/com/google/android/gms/pay/EmoneyReadinessStatus.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.pay;\n\nimport androidx.annotation.IntDef;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * E-money readiness status based on service provider and account.\n */\n@Target({ElementType.TYPE_USE})\n@Retention(RetentionPolicy.SOURCE)\n@IntDef({EmoneyReadinessStatus.FEATURE_NOT_SUPPORTED, EmoneyReadinessStatus.READY, EmoneyReadinessStatus.APP_NOT_INSTALLED, EmoneyReadinessStatus.APP_UPGRADE_NEEDED, EmoneyReadinessStatus.NO_ACTIVE_ACCOUNT, EmoneyReadinessStatus.ACCOUNT_MISMATCH})\npublic @interface EmoneyReadinessStatus {\n    /**\n     * Indicates that the e-money feature is not supported yet or still waiting for launch.\n     */\n    int FEATURE_NOT_SUPPORTED = 0;\n    /**\n     * Indicates that the e-money feature is available and ready to be used.\n     */\n    int READY = 1;\n    /**\n     * Indicates that the Google Wallet app is not installed.\n     */\n    int APP_NOT_INSTALLED = 2;\n    /**\n     * Indicates that the current Google Wallet app version or the Google Play services version needs to be upgraded.\n     */\n    int APP_UPGRADE_NEEDED = 3;\n    /**\n     * Indicates that there is no active account currently in Google Wallet.\n     */\n    int NO_ACTIVE_ACCOUNT = 4;\n    /**\n     * Indicates that the provided account does not match the active account currently in Google Wallet.\n     */\n    int ACCOUNT_MISMATCH = 5;\n}\n"
  },
  {
    "path": "play-services-pay/src/main/java/com/google/android/gms/pay/GetBulletinsRequest.java",
    "content": "package com.google.android.gms.pay;\n\nimport android.os.Parcel;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class GetBulletinsRequest extends AbstractSafeParcelable {\n\n    @Override\n    public void writeToParcel(Parcel out, int flags) {\n        CREATOR.writeToParcel(this, out, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<GetBulletinsRequest> CREATOR = findCreator(GetBulletinsRequest.class);\n}\n"
  },
  {
    "path": "play-services-pay/src/main/java/com/google/android/gms/pay/GetClosedLoopCardsFromServerRequest.java",
    "content": "package com.google.android.gms.pay;\n\nimport android.os.Parcel;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class GetClosedLoopCardsFromServerRequest extends AbstractSafeParcelable {\n\n    @Override\n    public void writeToParcel(Parcel out, int flags) {\n        CREATOR.writeToParcel(this, out, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<GetClosedLoopCardsFromServerRequest> CREATOR = findCreator(GetClosedLoopCardsFromServerRequest.class);\n}\n"
  },
  {
    "path": "play-services-pay/src/main/java/com/google/android/gms/pay/GetClosedLoopCardsRequest.java",
    "content": "package com.google.android.gms.pay;\n\nimport android.os.Parcel;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class GetClosedLoopCardsRequest extends AbstractSafeParcelable {\n\n    @Override\n    public void writeToParcel(Parcel out, int flags) {\n        CREATOR.writeToParcel(this, out, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<GetClosedLoopCardsRequest> CREATOR = findCreator(GetClosedLoopCardsRequest.class);\n}\n"
  },
  {
    "path": "play-services-pay/src/main/java/com/google/android/gms/pay/GetDigitalCarKeysRequest.java",
    "content": "package com.google.android.gms.pay;\n\nimport android.os.Parcel;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class GetDigitalCarKeysRequest extends AbstractSafeParcelable {\n\n    @Override\n    public void writeToParcel(Parcel out, int flags) {\n        CREATOR.writeToParcel(this, out, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<GetDigitalCarKeysRequest> CREATOR = findCreator(GetDigitalCarKeysRequest.class);\n}\n"
  },
  {
    "path": "play-services-pay/src/main/java/com/google/android/gms/pay/GetMdocCredentialRequest.java",
    "content": "package com.google.android.gms.pay;\n\nimport android.os.Parcel;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\n\n@Hide\n@SafeParcelable.Class\npublic class GetMdocCredentialRequest extends AbstractSafeParcelable {\n    @Field(1)\n    public String unknownFieldA;\n    @Field(2)\n    public byte[] unknownFieldB;\n    @Field(5)\n    public byte[] unknownFieldC;\n\n    @Constructor\n    public GetMdocCredentialRequest(@Param(1) String unknownFieldA, @Param(2) byte[] unknownFieldB, @Param(5) byte[] unknownFieldC) {\n        this.unknownFieldA = unknownFieldA;\n        this.unknownFieldB = unknownFieldB;\n        this.unknownFieldC = unknownFieldC;\n    }\n\n    @Override\n    public void writeToParcel(Parcel out, int flags) {\n        CREATOR.writeToParcel(this, out, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<GetMdocCredentialRequest> CREATOR = findCreator(GetMdocCredentialRequest.class);\n}\n"
  },
  {
    "path": "play-services-pay/src/main/java/com/google/android/gms/pay/GetOnboardingInfoRequest.java",
    "content": "package com.google.android.gms.pay;\n\nimport android.os.Parcel;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class GetOnboardingInfoRequest extends AbstractSafeParcelable {\n\n    @Override\n    public void writeToParcel(Parcel out, int flags) {\n        CREATOR.writeToParcel(this, out, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<GetOnboardingInfoRequest> CREATOR = findCreator(GetOnboardingInfoRequest.class);\n}\n"
  },
  {
    "path": "play-services-pay/src/main/java/com/google/android/gms/pay/GetPayApiAvailabilityStatusRequest.java",
    "content": "package com.google.android.gms.pay;\n\nimport android.os.Parcel;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.utils.ToStringHelper;\n\n@Hide\n@SafeParcelable.Class\npublic class GetPayApiAvailabilityStatusRequest extends AbstractSafeParcelable {\n    @Field(1)\n    public int requestType;\n\n    @Constructor\n    public GetPayApiAvailabilityStatusRequest(@Param(1) @PayClient.RequestType int requestType) {\n        this.requestType = requestType;\n    }\n\n    @Override\n    public void writeToParcel(Parcel out, int flags) {\n        CREATOR.writeToParcel(this, out, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<GetPayApiAvailabilityStatusRequest> CREATOR = findCreator(GetPayApiAvailabilityStatusRequest.class);\n\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"GetPayApiAvailabilityStatusRequest\")\n                .field(\"requestType\", requestType)\n                .end();\n    }\n}\n"
  },
  {
    "path": "play-services-pay/src/main/java/com/google/android/gms/pay/GetPayCapabilitiesRequest.java",
    "content": "package com.google.android.gms.pay;\n\nimport android.os.Parcel;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class GetPayCapabilitiesRequest extends AbstractSafeParcelable {\n\n    @Override\n    public void writeToParcel(Parcel out, int flags) {\n        CREATOR.writeToParcel(this, out, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<GetPayCapabilitiesRequest> CREATOR = findCreator(GetPayCapabilitiesRequest.class);\n}\n"
  },
  {
    "path": "play-services-pay/src/main/java/com/google/android/gms/pay/GetPaymentMethodsRequest.java",
    "content": "package com.google.android.gms.pay;\n\nimport android.os.Parcel;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class GetPaymentMethodsRequest extends AbstractSafeParcelable {\n\n    @Override\n    public void writeToParcel(Parcel out, int flags) {\n        CREATOR.writeToParcel(this, out, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<GetPaymentMethodsRequest> CREATOR = findCreator(GetPaymentMethodsRequest.class);\n}\n"
  },
  {
    "path": "play-services-pay/src/main/java/com/google/android/gms/pay/GetPendingIntentForWalletOnWearRequest.java",
    "content": "package com.google.android.gms.pay;\n\nimport android.os.Parcel;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\n\n@Hide\n@SafeParcelable.Class\npublic class GetPendingIntentForWalletOnWearRequest extends AbstractSafeParcelable {\n    @Field(2)\n    public String wearNodeId;\n    @Field(3)\n    public int intentSource;\n\n    @Constructor\n    public GetPendingIntentForWalletOnWearRequest(@Param(2) String wearNodeId, @Param(3) int intentSource) {\n        this.wearNodeId = wearNodeId;\n        this.intentSource = intentSource;\n    }\n\n    @Override\n    public void writeToParcel(Parcel out, int flags) {\n        CREATOR.writeToParcel(this, out, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<GetPendingIntentForWalletOnWearRequest> CREATOR = findCreator(GetPendingIntentForWalletOnWearRequest.class);\n}\n"
  },
  {
    "path": "play-services-pay/src/main/java/com/google/android/gms/pay/GetSortOrderRequest.java",
    "content": "package com.google.android.gms.pay;\n\nimport android.os.Parcel;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class GetSortOrderRequest extends AbstractSafeParcelable {\n\n    @Override\n    public void writeToParcel(Parcel out, int flags) {\n        CREATOR.writeToParcel(this, out, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<GetSortOrderRequest> CREATOR = findCreator(GetSortOrderRequest.class);\n}\n"
  },
  {
    "path": "play-services-pay/src/main/java/com/google/android/gms/pay/GetSortOrderResponse.java",
    "content": "package com.google.android.gms.pay;\n\nimport android.os.Parcel;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class GetSortOrderResponse extends AbstractSafeParcelable {\n\n    @Override\n    public void writeToParcel(Parcel out, int flags) {\n        CREATOR.writeToParcel(this, out, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<GetSortOrderResponse> CREATOR = findCreator(GetSortOrderResponse.class);\n}\n"
  },
  {
    "path": "play-services-pay/src/main/java/com/google/android/gms/pay/GetValuablesFromServerRequest.java",
    "content": "package com.google.android.gms.pay;\n\nimport android.os.Parcel;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class GetValuablesFromServerRequest extends AbstractSafeParcelable {\n\n    @Override\n    public void writeToParcel(Parcel out, int flags) {\n        CREATOR.writeToParcel(this, out, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<GetValuablesFromServerRequest> CREATOR = findCreator(GetValuablesFromServerRequest.class);\n}\n"
  },
  {
    "path": "play-services-pay/src/main/java/com/google/android/gms/pay/GetValuablesRequest.java",
    "content": "package com.google.android.gms.pay;\n\nimport android.os.Parcel;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\n\n@SafeParcelable.Class\npublic class GetValuablesRequest extends AbstractSafeParcelable {\n\n    @Override\n    public void writeToParcel(Parcel out, int flags) {\n        CREATOR.writeToParcel(this, out, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<GetValuablesRequest> CREATOR = findCreator(GetValuablesRequest.class);\n}\n"
  },
  {
    "path": "play-services-pay/src/main/java/com/google/android/gms/pay/GetWalletStatusResponse.java",
    "content": "package com.google.android.gms.pay;\n\nimport android.os.Parcel;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\n\n@Hide\n@SafeParcelable.Class\npublic class GetWalletStatusResponse extends AbstractSafeParcelable {\n    @Field(1)\n    public boolean isWalletUiAvailable;\n    @Field(2)\n    public int[] foundIssues;\n\n    @Constructor\n    public GetWalletStatusResponse(@Param(1) boolean isWalletUiAvailable, @Param(2) int[] foundIssues) {\n        this.isWalletUiAvailable = isWalletUiAvailable;\n        this.foundIssues = foundIssues;\n    }\n\n    @Override\n    public void writeToParcel(Parcel out, int flags) {\n        CREATOR.writeToParcel(this, out, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<GetWalletStatusResponse> CREATOR = findCreator(GetWalletStatusResponse.class);\n}\n"
  },
  {
    "path": "play-services-pay/src/main/java/com/google/android/gms/pay/NotifyCardTapEventRequest.java",
    "content": "package com.google.android.gms.pay;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\n\n@Hide\n@SafeParcelable.Class\npublic class NotifyCardTapEventRequest extends AbstractSafeParcelable {\n    @Nullable\n    @Field(1)\n    public String json;\n\n    @Constructor\n    public NotifyCardTapEventRequest(@Nullable @Param(1) String json) {\n        this.json = json;\n    }\n\n    @Override\n    public void writeToParcel(Parcel out, int flags) {\n        CREATOR.writeToParcel(this, out, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<NotifyCardTapEventRequest> CREATOR = findCreator(NotifyCardTapEventRequest.class);\n}\n"
  },
  {
    "path": "play-services-pay/src/main/java/com/google/android/gms/pay/NotifyEmoneyCardStatusUpdateRequest.java",
    "content": "package com.google.android.gms.pay;\n\nimport android.os.Parcel;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\n\n@Hide\n@SafeParcelable.Class\npublic class NotifyEmoneyCardStatusUpdateRequest extends AbstractSafeParcelable {\n    @Field(1)\n    public String json;\n\n    @Constructor\n    public NotifyEmoneyCardStatusUpdateRequest(@Param(1) String json) {\n        this.json = json;\n    }\n\n    @Override\n    public void writeToParcel(Parcel out, int flags) {\n        CREATOR.writeToParcel(this, out, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<NotifyEmoneyCardStatusUpdateRequest> CREATOR = findCreator(NotifyEmoneyCardStatusUpdateRequest.class);\n}\n"
  },
  {
    "path": "play-services-pay/src/main/java/com/google/android/gms/pay/Pay.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.pay;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport org.microg.gms.pay.PayClientImpl;\n\n/**\n * Entry point for Pay API.\n */\npublic class Pay {\n    /**\n     * Creates a new instance of {@link PayClient} for use in an {@link Activity}. This client should not be used outside of the given {@code Activity}.\n     */\n    public static PayClient getClient(Activity activity) {\n        return new PayClientImpl(activity);\n    }\n\n    /**\n     * Creates a new instance of {@link PayClient} for use in a non-{@code Activity} {@link Context}.\n     */\n    public static PayClient getClient(Context context) {\n        return new PayClientImpl(context);\n    }\n}\n"
  },
  {
    "path": "play-services-pay/src/main/java/com/google/android/gms/pay/PayApiAvailabilityStatus.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.pay;\n\nimport androidx.annotation.IntDef;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Pay API availability status on the device.\n */\n@Target({ElementType.TYPE_USE})\n@Retention(RetentionPolicy.SOURCE)\n@IntDef({PayApiAvailabilityStatus.AVAILABLE, PayApiAvailabilityStatus.NOT_ELIGIBLE})\npublic @interface PayApiAvailabilityStatus {\n    /**\n     * Indicates that the Pay API requested is available and ready to be used.\n     */\n    int AVAILABLE = 0;\n    /**\n     * Indicates that the user is currently not eligible for using the Pay API requested. The user may become eligible in the future.\n     */\n    int NOT_ELIGIBLE = 2;\n}\n"
  },
  {
    "path": "play-services-pay/src/main/java/com/google/android/gms/pay/PayApiError.java",
    "content": "package com.google.android.gms.pay;\n\nimport android.os.Parcel;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\n\n@Hide\n@SafeParcelable.Class\npublic class PayApiError extends AbstractSafeParcelable {\n\n    @Override\n    public void writeToParcel(Parcel out, int flags) {\n        CREATOR.writeToParcel(this, out, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<PayApiError> CREATOR = findCreator(PayApiError.class);\n}\n"
  },
  {
    "path": "play-services-pay/src/main/java/com/google/android/gms/pay/PayClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.pay;\n\nimport android.app.Activity;\nimport android.app.PendingIntent;\nimport androidx.activity.result.ActivityResultLauncher;\nimport androidx.activity.result.IntentSenderRequest;\nimport androidx.annotation.IntDef;\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.HasApiKey;\nimport com.google.android.gms.tasks.Task;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Interface for Pay API.\n */\npublic interface PayClient extends HasApiKey<Api.ApiOptions.NotRequiredOptions> {\n    /**\n     * Debug message passed back in {@code onActivityResult()} when calling {@link #savePasses(String, Activity, int)} or\n     * {@link #savePassesJwt(String, Activity, int)}.\n     */\n    String EXTRA_API_ERROR_MESSAGE = \"extra_api_error_message\";\n\n    /**\n     * Checks the e-money readiness for a service provider and account.\n     * <p>\n     * Important: Only apps on the allowlist for the e-money feature can call this method; otherwise, the result is a failed {@link Task}.\n     *\n     * @param serviceProvider The service provider to check readiness.\n     * @param accountName     The email account to check readiness.\n     * @return One of the possible {@link EmoneyReadinessStatus}.\n     */\n    Task<EmoneyReadiness> checkReadinessForEmoney(String serviceProvider, String accountName);\n\n    /**\n     * Gets the {@link PayApiAvailabilityStatus} of the current user and device.\n     *\n     * @param requestType A {@link PayClient.RequestType} for how the API will be used.\n     * @return One of the possible {@link PayApiAvailabilityStatus}.\n     */\n    Task<@PayApiAvailabilityStatus Integer> getPayApiAvailabilityStatus(@RequestType int requestType);\n\n    /**\n     * Create a {@link PendingIntent} for the Wear Wallet activity. May return an error if pay is not supported in this region or if the watch is not reachable.\n     *\n     * @param wearNodeId   The node id of the watch.\n     * @param intentSource The {@link PayClient.WearWalletIntentSource} that launches the requested page.\n     */\n    Task<PendingIntent> getPendingIntentForWalletOnWear(String wearNodeId, @WearWalletIntentSource int intentSource);\n\n    /**\n     * Provides the product name in this market.\n     */\n    PayClient.ProductName getProductName();\n\n    /**\n     * Notifies Google Play services of a card tap event.\n     * <p>\n     * Only apps on the allowlist can call this method; otherwise, the result is a failed {@link Task}.\n     *\n     * @param eventJson The event details in JSON format.\n     */\n    Task<Void> notifyCardTapEvent(String eventJson);\n\n    /**\n     * Notifies Google Play services if an e-money card has been updated.\n     * <p>\n     * Important: Only apps on the allowlist for the e-money feature can call this method; otherwise, the result is a failed {@link Task}.\n     *\n     * @param json The e-money card status update details in JSON format.\n     */\n    Task<Void> notifyEmoneyCardStatusUpdate(String json);\n\n    /**\n     * Saves an e-money card in JSON format.\n     * <p>\n     * Important: Only apps on the allowlist for the e-money feature can call this method; otherwise, the result is a failed {@link Task}.\n     *\n     * @param json                   The e-money card details in JSON format.\n     * @param activityResultLauncher an {@link ActivityResultLauncher} registered by caller to handle the activity results.\n     */\n    Task<Void> pushEmoneyCard(String json, ActivityResultLauncher<IntentSenderRequest> activityResultLauncher);\n\n    /**\n     * Saves one or multiple passes in a JSON format.\n     * <p>\n     * Must be called from an {@code Activity}.\n     *\n     * @param json        A JSON string request to save one or multiple passes. The JSON format is consistent with the JWT save link format. Refer to\n     *                    Google Pay API for Passes for an overview on how save links are generated. Only focus on how the JSON is formatted.\n     *                    There is no need to sign the JSON string.\n     * @param activity    The {@code Activity} that will receive the callback result.\n     * @param requestCode An integer request code that will be passed back in {@code onActivityResult()}, allowing you to identify whom this result came from.\n     */\n    void savePasses(String json, Activity activity, int requestCode);\n\n    /**\n     * Saves one or multiple passes in a JWT format.\n     * <p>\n     * Must be called from an {@code Activity}.\n     *\n     * @param jwt         A JWT string token to save one or multiple passes. The token format is the same used in the JWT save link format. Refer to\n     *                    Google Pay API for Passes for an overview on how save links are generated.\n     * @param activity    The {@code Activity} that will receive the callback result.\n     * @param requestCode An integer request code that will be passed back in {@code onActivityResult()}, allowing you to identify whom this result came from.\n     */\n    void savePassesJwt(String jwt, Activity activity, int requestCode);\n\n    /**\n     * Indicates what the product is called in this market\n     */\n    enum ProductName {\n        GOOGLE_PAY,\n        GOOGLE_WALLET\n    }\n\n    /**\n     * All possible request types that will be used by callers of {@link PayClient#getPayApiAvailabilityStatus(int)}.\n     */\n    @Target({ElementType.TYPE_USE})\n    @Retention(RetentionPolicy.SOURCE)\n    @IntDef({RequestType.CARD_PROVISIONING_DEEP_LINK, RequestType.SAVE_PASSES, RequestType.SAVE_PASSES_JWT})\n    @interface RequestType {\n        /**\n         * Checks support of card provisioning deep links.\n         */\n        int CARD_PROVISIONING_DEEP_LINK = 1;\n        /**\n         * Checks availability of the {@link PayClient#savePasses(String, Activity, int)} API.\n         */\n        int SAVE_PASSES = 2;\n        /**\n         * Checks availability of the {@link PayClient#savePassesJwt(String, Activity, int)} API.\n         */\n        int SAVE_PASSES_JWT = 3;\n    }\n\n    /**\n     * Possible result codes passed back in {@code onActivityResult()} when calling {@link PayClient#savePasses(String, Activity, int)} or\n     * {@link PayClient#savePassesJwt(String, Activity, int)}. These are in addition to {@link Activity#RESULT_OK} and {@link Activity#RESULT_CANCELED}.\n     */\n    @Target({ElementType.TYPE_USE})\n    @Retention(RetentionPolicy.SOURCE)\n    @IntDef({Activity.RESULT_OK, Activity.RESULT_CANCELED, SavePassesResult.API_UNAVAILABLE, SavePassesResult.SAVE_ERROR, SavePassesResult.INTERNAL_ERROR})\n    @interface SavePassesResult {\n        /**\n         * The {@link PayClient#savePasses(String, Activity, int)} or {@link PayClient#savePassesJwt(String, Activity, int) API is unavailable.\n         * Use {@link PayClient#getPayApiAvailabilityStatus(int)} before calling the API.\n         */\n        int API_UNAVAILABLE = 1;\n        /**\n         * An error occurred while saving the passes. Check {@code EXTRA_API_ERROR_MESSAGE} to debug the issue.\n         */\n        int SAVE_ERROR = 2;\n        /**\n         * Indicates that an internal error occurred while calling the API. Retry the API call. If the error persists assume that the API is not available.\n         */\n        int INTERNAL_ERROR = 3;\n    }\n\n    /**\n     * Intent source for Wear Card Management Activity. Behavior may depend on the source.\n     */\n    @Target({ElementType.TYPE_USE})\n    @Retention(RetentionPolicy.SOURCE)\n    @IntDef({WearWalletIntentSource.OOBE, WearWalletIntentSource.SETTINGS})\n    @interface WearWalletIntentSource {\n        /**\n         * Start Wear Wallet for out of box experience\n         */\n        int OOBE = 20;\n        /**\n         * Start Wear Wallet from settings\n         */\n        int SETTINGS = 21;\n    }\n}\n"
  },
  {
    "path": "play-services-pay/src/main/java/com/google/android/gms/pay/ProtoSafeParcelable.java",
    "content": "package com.google.android.gms.pay;\n\nimport android.os.Parcel;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class ProtoSafeParcelable extends AbstractSafeParcelable {\n    @Field(1)\n    public byte[] data;\n\n    @Constructor\n    public ProtoSafeParcelable(@Param(1) byte[] data) {\n        this.data = data;\n    }\n\n    @Override\n    public void writeToParcel(Parcel out, int flags) {\n        CREATOR.writeToParcel(this, out, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<ProtoSafeParcelable> CREATOR = findCreator(ProtoSafeParcelable.class);\n}\n"
  },
  {
    "path": "play-services-pay/src/main/java/com/google/android/gms/pay/PushEmoneyCardRequest.java",
    "content": "package com.google.android.gms.pay;\n\nimport android.os.Parcel;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\n\n@Hide\n@SafeParcelable.Class\npublic class PushEmoneyCardRequest extends AbstractSafeParcelable {\n    @Field(1)\n    public String json;\n\n    @Constructor\n    public PushEmoneyCardRequest(@Param(1) String json) {\n        this.json = json;\n    }\n\n    @Override\n    public void writeToParcel(Parcel out, int flags) {\n        CREATOR.writeToParcel(this, out, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<PushEmoneyCardRequest> CREATOR = findCreator(PushEmoneyCardRequest.class);\n}\n"
  },
  {
    "path": "play-services-pay/src/main/java/com/google/android/gms/pay/SavePassesRequest.java",
    "content": "package com.google.android.gms.pay;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\n\n@Hide\n@SafeParcelable.Class\npublic class SavePassesRequest extends AbstractSafeParcelable {\n    @Nullable\n    @Field(1)\n    public String json;\n    @Nullable\n    @Field(2)\n    public String jwt;\n\n    @Constructor\n    public SavePassesRequest(@Nullable @Param(1) String json, @Nullable @Param(2) String jwt) {\n        this.json = json;\n        this.jwt = jwt;\n    }\n\n    @Override\n    public void writeToParcel(Parcel out, int flags) {\n        CREATOR.writeToParcel(this, out, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<SavePassesRequest> CREATOR = findCreator(SavePassesRequest.class);\n}\n"
  },
  {
    "path": "play-services-pay/src/main/java/com/google/android/gms/pay/SyncBundleRequest.java",
    "content": "package com.google.android.gms.pay;\n\nimport android.os.Parcel;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.common.Hide;\n\n@Hide\n@SafeParcelable.Class\npublic class SyncBundleRequest extends AbstractSafeParcelable {\n    @Field(1)\n    public String unknownField;\n\n    @Constructor\n    public SyncBundleRequest(@Param(1) String unknownField) {\n        this.unknownField = unknownField;\n    }\n\n    @Override\n    public void writeToParcel(Parcel out, int flags) {\n        CREATOR.writeToParcel(this, out, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<SyncBundleRequest> CREATOR = findCreator(SyncBundleRequest.class);\n}\n"
  },
  {
    "path": "play-services-pay/src/main/java/org/microg/gms/pay/PayApiClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.pay;\n\nimport android.content.Context;\nimport android.os.IBinder;\nimport org.microg.gms.common.GmsClient;\nimport com.google.android.gms.pay.internal.IPayService;\nimport org.microg.gms.common.GmsService;\nimport com.google.android.gms.common.api.internal.ConnectionCallbacks;\nimport com.google.android.gms.common.api.internal.OnConnectionFailedListener;\n\npublic class PayApiClient extends GmsClient<IPayService> {\n    public PayApiClient(Context context, ConnectionCallbacks callbacks, OnConnectionFailedListener connectionFailedListener) {\n        super(context, callbacks, connectionFailedListener, GmsService.PAY.ACTION);\n        serviceId = GmsService.PAY.SERVICE_ID;\n    }\n\n    @Override\n    protected IPayService interfaceFromBinder(IBinder binder) {\n        return IPayService.Stub.asInterface(binder);\n    }\n}\n"
  },
  {
    "path": "play-services-pay/src/main/java/org/microg/gms/pay/PayClientImpl.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.pay;\n\nimport android.app.Activity;\nimport android.app.PendingIntent;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentSender;\nimport android.os.RemoteException;\nimport androidx.activity.result.ActivityResultLauncher;\nimport androidx.activity.result.IntentSenderRequest;\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.ApiException;\nimport com.google.android.gms.common.api.GoogleApi;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.pay.*;\nimport com.google.android.gms.pay.internal.IPayServiceCallbacks;\nimport com.google.android.gms.tasks.Task;\nimport com.google.android.gms.tasks.Tasks;\n\nimport java.lang.ref.WeakReference;\n\npublic class PayClientImpl extends GoogleApi<Api.ApiOptions.NotRequiredOptions> implements PayClient {\n    private static final Api<Api.ApiOptions.NotRequiredOptions> API = new Api<>((options, context, looper, clientSettings, callbacks, connectionFailedListener) -> new ThirdPartyPayApiClient(context, callbacks, connectionFailedListener));\n\n    public PayClientImpl(Context context) {\n        super(context, API, Api.ApiOptions.NO_OPTIONS);\n    }\n\n    @Override\n    public Task<EmoneyReadiness> checkReadinessForEmoney(String serviceProvider, String accountName) {\n        return null;\n    }\n\n    @Override\n    public Task<@PayApiAvailabilityStatus Integer> getPayApiAvailabilityStatus(@RequestType int requestType) {\n        return this.<Integer, ThirdPartyPayApiClient>scheduleTask((client, completionSource) -> {\n            client.getServiceInterface().getPayApiAvailabilityStatus(new GetPayApiAvailabilityStatusRequest(requestType), new PayServiceCallbacks() {\n                @Override\n                public void onPayApiAvailabilityStatus(Status status, int availabilityStatus) {\n                    if (status.isSuccess() && availabilityStatus == 3) {\n                        // Invalid availabilityStatus\n                        completionSource.trySetException(new ApiException(Status.INTERNAL_ERROR));\n                    } else if (availabilityStatus == 1) {\n                        if (status.isSuccess()) {\n                            completionSource.trySetResult(PayApiAvailabilityStatus.NOT_ELIGIBLE);\n                        } else {\n                            completionSource.trySetException(new ApiException(status));\n                        }\n                    } else {\n                        if (status.isSuccess()) {\n                            completionSource.trySetResult(availabilityStatus);\n                        } else {\n                            completionSource.trySetException(new ApiException(status));\n                        }\n                    }\n                }\n            });\n        });\n    }\n\n    @Override\n    public Task<PendingIntent> getPendingIntentForWalletOnWear(String wearNodeId, @WearWalletIntentSource int intentSource) {\n        return null;\n    }\n\n    @Override\n    public ProductName getProductName() {\n        return ProductName.GOOGLE_WALLET;\n    }\n\n    @Override\n    public Task<Void> notifyCardTapEvent(String eventJson) {\n        return null;\n    }\n\n    @Override\n    public Task<Void> notifyEmoneyCardStatusUpdate(String json) {\n        return null;\n    }\n\n    @Override\n    public Task<Void> pushEmoneyCard(String json, ActivityResultLauncher<IntentSenderRequest> activityResultLauncher) {\n        return null;\n    }\n\n    @Override\n    public void savePasses(String json, Activity activity, int requestCode) {\n        savePasses(new SavePassesRequest(json, null), activity, requestCode);\n    }\n\n    @Override\n    public void savePassesJwt(String jwt, Activity activity, int requestCode) {\n        savePasses(new SavePassesRequest(null, jwt), activity, requestCode);\n    }\n\n    private void savePasses(SavePassesRequest request, Activity activity, int requestCode) {\n        // We don't want to keep a reference to the activity to not leak it\n        WeakReference<Activity> weakActivity = new WeakReference<>(activity);\n        PayServiceCallbacks callbacks = new PayServiceCallbacks() {\n            @Override\n            public void onError(Status status) {\n                Activity activity = weakActivity.get();\n                if (activity != null) {\n                    if (status.hasResolution()) {\n                        try {\n                            status.startResolutionForResult(activity, requestCode);\n                        } catch (IntentSender.SendIntentException e) {\n                            // Ignored\n                        }\n                    } else {\n                        PendingIntent resultIntent = activity.createPendingResult(requestCode, new Intent(), PendingIntent.FLAG_ONE_SHOT);\n                        if (resultIntent != null) {\n                            try {\n                                resultIntent.send(status.isSuccess() ? -1 : status.getStatusCode());\n                            } catch (PendingIntent.CanceledException e) {\n                                // Ignored\n                            }\n                        }\n                    }\n                }\n            }\n        };\n        this.<Void, ThirdPartyPayApiClient>scheduleTask((client, completionSource) -> client.getServiceInterface().savePasses(request, callbacks))\n                .addOnFailureListener((exception) -> callbacks.onError(Status.INTERNAL_ERROR));\n    }\n}\n"
  },
  {
    "path": "play-services-pay/src/main/java/org/microg/gms/pay/PayServiceCallbacks.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.pay;\n\nimport android.app.PendingIntent;\nimport android.os.RemoteException;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.pay.EmoneyReadiness;\nimport com.google.android.gms.pay.GetSortOrderResponse;\nimport com.google.android.gms.pay.PayApiError;\nimport com.google.android.gms.pay.ProtoSafeParcelable;\nimport com.google.android.gms.pay.internal.IPayServiceCallbacks;\n\npublic class PayServiceCallbacks extends IPayServiceCallbacks.Stub {\n    @Override\n    public void onStatus(Status status) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void onPendingIntent(Status status, PendingIntent pendingIntent) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void onProtoSafeParcelable(Status status, ProtoSafeParcelable proto) throws RemoteException {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void onGetSortOrderResponse(Status status, GetSortOrderResponse response) throws RemoteException {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void onBoolean(Status status, boolean b) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void onPayApiError(PayApiError error) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void onByteArray(Status status, byte[] bArr) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void onLong(Status status, long l) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void onError(Status status) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void onPayApiAvailabilityStatus(Status status, int i) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void onEmoneyReadiness(Status status, EmoneyReadiness emoneyReadiness) {\n        throw new UnsupportedOperationException();\n    }\n}\n"
  },
  {
    "path": "play-services-pay/src/main/java/org/microg/gms/pay/ThirdPartyPayApiClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.pay;\n\nimport android.content.Context;\nimport android.os.IBinder;\nimport com.google.android.gms.pay.internal.IThirdPartyPayService;\nimport org.microg.gms.common.GmsClient;\nimport org.microg.gms.common.GmsService;\nimport com.google.android.gms.common.api.internal.ConnectionCallbacks;\nimport com.google.android.gms.common.api.internal.OnConnectionFailedListener;\n\npublic class ThirdPartyPayApiClient extends GmsClient<IThirdPartyPayService> {\n    public ThirdPartyPayApiClient(Context context, ConnectionCallbacks callbacks, OnConnectionFailedListener connectionFailedListener) {\n        super(context, callbacks, connectionFailedListener, GmsService.PAY.SECONDARY_ACTIONS[0]);\n        serviceId = GmsService.PAY.SERVICE_ID;\n    }\n\n    @Override\n    protected IThirdPartyPayService interfaceFromBinder(IBinder binder) {\n        return IThirdPartyPayService.Stub.asInterface(binder);\n    }\n}\n"
  },
  {
    "path": "play-services-phenotype/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\ndependencies {\n    // Dependencies from play-services-phenotype:17.0.0\n    api \"androidx.core:core:1.0.0\"\n    api project(':play-services-base')\n    api project(':play-services-basement')\n    api project(':play-services-tasks')\n\n    annotationProcessor project(':safe-parcel-processor')\n}\n\nandroid {\n    namespace \"com.google.android.gms.phenotype\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n}\n\napply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG implementation of play-services-phenotype'\n"
  },
  {
    "path": "play-services-phenotype/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <application />\n</manifest>\n"
  },
  {
    "path": "play-services-phenotype/src/main/java/com/google/android/gms/phenotype/Configuration.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.phenotype;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class Configuration extends AutoSafeParcelable {\n    @Field(2)\n    public int id;\n    @Field(3)\n    public Flag[] flags;\n    @Field(4)\n    public String[] removeNames;\n\n    public static final Creator<Configuration> CREATOR = findCreator(Configuration.class);\n}\n"
  },
  {
    "path": "play-services-phenotype/src/main/java/com/google/android/gms/phenotype/ExperimentTokens.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.phenotype;\n\nimport androidx.annotation.NonNull;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class ExperimentTokens extends AutoSafeParcelable {\n    @Field(2)\n    public String field2;\n    @Field(3)\n    public byte[] direct;\n    @Field(4)\n    public byte[][] gaia;\n    @Field(5)\n    public byte[][] pseudo;\n    @Field(6)\n    public byte[][] always;\n    @Field(7)\n    public byte[][] other;\n    @Field(8)\n    public int[] weak;\n    @Field(9)\n    public byte[][] directs;\n    @Field(10)\n    public int[] genericDimensions;\n    @Field(11)\n    public byte[][] external;\n\n    public static final Creator<ExperimentTokens> CREATOR = findCreator(ExperimentTokens.class);\n}\n"
  },
  {
    "path": "play-services-phenotype/src/main/java/com/google/android/gms/phenotype/Flag.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.phenotype;\n\nimport org.microg.gms.common.Hide;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n@Hide\npublic class Flag extends AutoSafeParcelable {\n    @Field(2)\n    public String name;\n    @Field(3)\n    private long longValue;\n    @Field(4)\n    private boolean boolValue;\n    @Field(5)\n    private double doubleValue;\n    @Field(6)\n    private String stringValue;\n    @Field(7)\n    private byte[] bytesValue;\n    @Field(8)\n    public int dataType;\n    @Field(9)\n    public int flagType;\n\n    private Flag() {\n    }\n\n    public Flag(String name, long longValue, int flagType) {\n        this.name = name;\n        this.longValue = longValue;\n        this.dataType = DATA_TYPE_LONG;\n        this.flagType = flagType;\n    }\n\n    public Flag(String name, boolean boolValue, int flagType) {\n        this.name = name;\n        this.boolValue = boolValue;\n        this.dataType = DATA_TYPE_BOOL;\n        this.flagType = flagType;\n    }\n\n    public Flag(String name, double doubleValue, int flagType) {\n        this.name = name;\n        this.doubleValue = doubleValue;\n        this.dataType = DATA_TYPE_DOUBLE;\n        this.flagType = flagType;\n    }\n\n    public Flag(String name, String stringValue, int flagType) {\n        this.name = name;\n        this.stringValue = stringValue;\n        this.dataType = DATA_TYPE_STRING;\n        this.flagType = flagType;\n    }\n\n    public Flag(String name, byte[] bytesValue, int flagType) {\n        this.name = name;\n        this.bytesValue = bytesValue;\n        this.dataType = DATA_TYPE_BYTES;\n        this.flagType = flagType;\n    }\n\n    public long getLong() {\n        if (dataType == DATA_TYPE_LONG)\n            return longValue;\n        throw new IllegalArgumentException(\"Not a long type\");\n    }\n\n    public boolean getBool() {\n        if (dataType == DATA_TYPE_BOOL)\n            return boolValue;\n        throw new IllegalArgumentException(\"Not a boolean type\");\n    }\n\n    public double getDouble() {\n        if (dataType == DATA_TYPE_DOUBLE)\n            return doubleValue;\n        throw new IllegalArgumentException(\"Not a double type\");\n    }\n\n    public String getString() {\n        if (dataType == DATA_TYPE_STRING)\n            return stringValue;\n        throw new IllegalArgumentException(\"Not a String type\");\n    }\n\n    public byte[] getBytes() {\n        if (dataType == DATA_TYPE_BYTES)\n            return bytesValue;\n        throw new IllegalArgumentException(\"Not a bytes type\");\n    }\n\n    public static final int DATA_TYPE_LONG = 1;\n    public static final int DATA_TYPE_BOOL = 2;\n    public static final int DATA_TYPE_DOUBLE = 3;\n    public static final int DATA_TYPE_STRING = 4;\n    public static final int DATA_TYPE_BYTES = 5;\n\n    public static final Creator<Flag> CREATOR = findCreator(Flag.class);\n}\n"
  },
  {
    "path": "play-services-phenotype/src/main/java/com/google/android/gms/phenotype/GenericDimension.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.phenotype;\n\nimport org.microg.gms.common.Hide;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n@Hide\npublic class GenericDimension extends AutoSafeParcelable {\n    @Field(1)\n    public int a;\n    @Field(2)\n    public int b;\n\n    public static final Creator<GenericDimension> CREATOR = findCreator(GenericDimension.class);\n}\n"
  },
  {
    "path": "play-services-places/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\nandroid {\n    namespace \"com.google.android.gms.location.places\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n}\n\napply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG implementation of play-services-places'\n\ndependencies {\n    // Dependencies from play-services-places:17.0.0\n    api \"androidx.fragment:fragment:1.0.0\"\n    api project(\":play-services-base\")\n    api project(\":play-services-basement\")\n    api project(\":play-services-maps\")\n    //api project(\":play-services-places-report\")\n    api project(\":play-services-tasks\")\n}\n"
  },
  {
    "path": "play-services-places/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2022, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest />\n"
  },
  {
    "path": "play-services-places/src/main/aidl/com/google/android/gms/location/places/AutocompleteFilter.aidl",
    "content": "package com.google.android.gms.location.places;\n\nparcelable AutocompleteFilter;\n"
  },
  {
    "path": "play-services-places/src/main/aidl/com/google/android/gms/location/places/NearbyAlertRequest.aidl",
    "content": "package com.google.android.gms.location.places;\n\nparcelable NearbyAlertRequest;\n"
  },
  {
    "path": "play-services-places/src/main/aidl/com/google/android/gms/location/places/PlaceFilter.aidl",
    "content": "package com.google.android.gms.location.places;\n\nparcelable PlaceFilter;\n"
  },
  {
    "path": "play-services-places/src/main/aidl/com/google/android/gms/location/places/PlaceReport.aidl",
    "content": "package com.google.android.gms.location.places;\n\nparcelable PlaceReport;\n"
  },
  {
    "path": "play-services-places/src/main/aidl/com/google/android/gms/location/places/PlaceRequest.aidl",
    "content": "package com.google.android.gms.location.places;\n\nparcelable PlaceRequest;\n"
  },
  {
    "path": "play-services-places/src/main/aidl/com/google/android/gms/location/places/UserAddedPlace.aidl",
    "content": "package com.google.android.gms.location.places;\n\nparcelable UserAddedPlace;\n"
  },
  {
    "path": "play-services-places/src/main/aidl/com/google/android/gms/location/places/UserDataType.aidl",
    "content": "package com.google.android.gms.location.places;\n\nparcelable UserDataType;\n"
  },
  {
    "path": "play-services-places/src/main/aidl/com/google/android/gms/location/places/internal/IGooglePlaceDetectionService.aidl",
    "content": "package com.google.android.gms.location.places.internal;\n\ninterface IGooglePlaceDetectionService {\n\n}"
  },
  {
    "path": "play-services-places/src/main/aidl/com/google/android/gms/location/places/internal/IGooglePlacesService.aidl",
    "content": "package com.google.android.gms.location.places.internal;\n\ninterface IGooglePlacesService {\n\n}"
  },
  {
    "path": "play-services-places/src/main/aidl/com/google/android/gms/location/places/internal/IPlacesCallbacks.aidl",
    "content": "package com.google.android.gms.location.places.internal;\n\nimport com.google.android.gms.common.data.DataHolder;\n\ninterface IPlacesCallbacks {\n    void X(in DataHolder dataHolder);\n    void Y(in DataHolder dataHolder);\n    void Z(in DataHolder dataHolder);\n}\n"
  },
  {
    "path": "play-services-places/src/main/aidl/com/google/android/gms/location/places/internal/PlacesParams.aidl",
    "content": "package com.google.android.gms.location.places.internal;\n\nparcelable PlacesParams;\n"
  },
  {
    "path": "play-services-places/src/main/java/com/google/android/gms/location/places/AutocompleteFilter.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.location.places;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\n/**\n * TODO usage\n */\npublic class AutocompleteFilter extends AutoSafeParcelable {\n\n    @SafeParceled(1000)\n    private int versionCode = 1;\n\n    public static final Creator<AutocompleteFilter> CREATOR = new AutoCreator<AutocompleteFilter>(AutocompleteFilter.class);\n}\n"
  },
  {
    "path": "play-services-places/src/main/java/com/google/android/gms/location/places/NearbyAlertRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.location.places;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n/**\n * TODO: usage\n */\npublic class NearbyAlertRequest extends AutoSafeParcelable {\n\n    public static final Creator<NearbyAlertRequest> CREATOR = new AutoCreator<NearbyAlertRequest>(NearbyAlertRequest.class);\n}\n"
  },
  {
    "path": "play-services-places/src/main/java/com/google/android/gms/location/places/Place.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.location.places;\n\nimport android.net.Uri;\n\nimport com.google.android.gms.common.data.Freezable;\nimport com.google.android.gms.maps.model.LatLng;\nimport com.google.android.gms.maps.model.LatLngBounds;\n\nimport java.util.List;\nimport java.util.Locale;\n\npublic interface Place extends Freezable<Place> {\n    int TYPE_ACCOUNTING = 1;\n\n    int TYPE_ADMINISTRATIVE_AREA_LEVEL_1 = 1001;\n\n    int TYPE_ADMINISTRATIVE_AREA_LEVEL_2 = 1002;\n\n    int TYPE_ADMINISTRATIVE_AREA_LEVEL_3 = 1003;\n\n    int TYPE_AIRPORT = 2;\n\n    int TYPE_AMUSEMENT_PARK = 3;\n\n    int TYPE_AQUARIUM = 4;\n\n    int TYPE_ART_GALLERY = 5;\n\n    int TYPE_ATM = 6;\n\n    int TYPE_BAKERY = 7;\n\n    int TYPE_BANK = 8;\n\n    int TYPE_BAR = 9;\n\n    int TYPE_BEAUTY_SALON = 10;\n\n    int TYPE_BICYCLE_STORE = 11;\n\n    int TYPE_BOOK_STORE = 12;\n\n    int TYPE_BOWLING_ALLEY = 13;\n\n    int TYPE_BUS_STATION = 14;\n\n    int TYPE_CAFE = 15;\n\n    int TYPE_CAMPGROUND = 16;\n\n    int TYPE_CAR_DEALER = 17;\n\n    int TYPE_CAR_RENTAL = 18;\n\n    int TYPE_CAR_REPAIR = 19;\n\n    int TYPE_CAR_WASH = 20;\n\n    int TYPE_CASINO = 21;\n\n    int TYPE_CEMETERY = 22;\n\n    int TYPE_CHURCH = 23;\n\n    int TYPE_CITY_HALL = 24;\n\n    int TYPE_CLOTHING_STORE = 25;\n\n    int TYPE_COLLOQUIAL_AREA = 1004;\n\n    int TYPE_CONVENIENCE_STORE = 26;\n\n    int TYPE_COUNTRY = 1005;\n\n    int TYPE_COURTHOUSE = 27;\n\n    int TYPE_DENTIST = 28;\n\n    int TYPE_DEPARTMENT_STORE = 29;\n\n    int TYPE_DOCTOR = 30;\n\n    int TYPE_ELECTRICIAN = 31;\n\n    int TYPE_ELECTRONICS_STORE = 32;\n\n    int TYPE_EMBASSY = 33;\n\n    int TYPE_ESTABLISHMENT = 34;\n\n    int TYPE_FINANCE = 35;\n\n    int TYPE_FIRE_STATION = 36;\n\n    int TYPE_FLOOR = 1006;\n\n    int TYPE_FLORIST = 37;\n\n    int TYPE_FOOD = 38;\n\n    int TYPE_FUNERAL_HOME = 39;\n\n    int TYPE_FURNITURE_STORE = 40;\n\n    int TYPE_GAS_STATION = 41;\n\n    int TYPE_GENERAL_CONTRACTOR = 42;\n\n    int TYPE_GEOCODE = 1007;\n\n    int TYPE_GROCERY_OR_SUPERMARKET = 43;\n\n    int TYPE_GYM = 44;\n\n    int TYPE_HAIR_CARE = 45;\n\n    int TYPE_HARDWARE_STORE = 46;\n\n    int TYPE_HEALTH = 47;\n\n    int TYPE_HINDU_TEMPLE = 48;\n\n    int TYPE_HOME_GOODS_STORE = 49;\n\n    int TYPE_HOSPITAL = 50;\n\n    int TYPE_INSURANCE_AGENCY = 51;\n\n    int TYPE_INTERSECTION = 1008;\n\n    int TYPE_JEWELRY_STORE = 52;\n\n    int TYPE_LAUNDRY = 53;\n\n    int TYPE_LAWYER = 54;\n\n    int TYPE_LIBRARY = 55;\n\n    int TYPE_LIQUOR_STORE = 56;\n\n    int TYPE_LOCALITY = 1009;\n\n    int TYPE_LOCAL_GOVERNMENT_OFFICE = 57;\n\n    int TYPE_LOCKSMITH = 58;\n\n    int TYPE_LODGING = 59;\n\n    int TYPE_MEAL_DELIVERY = 60;\n\n    int TYPE_MEAL_TAKEAWAY = 61;\n\n    int TYPE_MOSQUE = 62;\n\n    int TYPE_MOVIE_RENTAL = 63;\n\n    int TYPE_MOVIE_THEATER = 64;\n\n    int TYPE_MOVING_COMPANY = 65;\n\n    int TYPE_MUSEUM = 66;\n\n    int TYPE_NATURAL_FEATURE = 1010;\n\n    int TYPE_NEIGHBORHOOD = 1011;\n\n    int TYPE_NIGHT_CLUB = 67;\n\n    int TYPE_OTHER = 0;\n\n    int TYPE_PAINTER = 68;\n\n    int TYPE_PARK = 69;\n\n    int TYPE_PARKING = 70;\n\n    int TYPE_PET_STORE = 71;\n\n    int TYPE_PHARMACY = 72;\n\n    int TYPE_PHYSIOTHERAPIST = 73;\n\n    int TYPE_PLACE_OF_WORSHIP = 74;\n\n    int TYPE_PLUMBER = 75;\n\n    int TYPE_POINT_OF_INTEREST = 1013;\n\n    int TYPE_POLICE = 76;\n\n    int TYPE_POLITICAL = 1012;\n\n    int TYPE_POSTAL_CODE = 1015;\n\n    int TYPE_POSTAL_CODE_PREFIX = 1016;\n\n    int TYPE_POSTAL_TOWN = 1017;\n\n    int TYPE_POST_BOX = 1014;\n\n    int TYPE_POST_OFFICE = 77;\n\n    int TYPE_PREMISE = 1018;\n\n    int TYPE_REAL_ESTATE_AGENCY = 78;\n\n    int TYPE_RESTAURANT = 79;\n\n    int TYPE_ROOFING_CONTRACTOR = 80;\n\n    int TYPE_ROOM = 1019;\n\n    int TYPE_ROUTE = 1020;\n\n    int TYPE_RV_PARK = 81;\n\n    int TYPE_SCHOOL = 82;\n\n    int TYPE_SHOE_STORE = 83;\n\n    int TYPE_SHOPPING_MALL = 84;\n\n    int TYPE_SPA = 85;\n\n    int TYPE_STADIUM = 86;\n\n    int TYPE_STORAGE = 87;\n\n    int TYPE_STORE = 88;\n\n    int TYPE_STREET_ADDRESS = 1021;\n\n    int TYPE_SUBLOCALITY = 1022;\n\n    int TYPE_SUBLOCALITY_LEVEL_1 = 1023;\n\n    int TYPE_SUBLOCALITY_LEVEL_2 = 1024;\n\n    int TYPE_SUBLOCALITY_LEVEL_3 = 1025;\n\n    int TYPE_SUBLOCALITY_LEVEL_4 = 1026;\n\n    int TYPE_SUBLOCALITY_LEVEL_5 = 1027;\n\n    int TYPE_SUBPREMISE = 1028;\n\n    int TYPE_SUBWAY_STATION = 89;\n\n    int TYPE_SYNAGOGUE = 90;\n\n    int TYPE_SYNTHETIC_GEOCODE = 1029;\n\n    int TYPE_TAXI_STAND = 91;\n\n    int TYPE_TRAIN_STATION = 92;\n\n    int TYPE_TRANSIT_STATION = 1030;\n\n    int TYPE_TRAVEL_AGENCY = 93;\n\n    int TYPE_UNIVERSITY = 94;\n\n    int TYPE_VETERINARY_CARE = 95;\n\n    int TYPE_ZOO = 96;\n\n    /**\n     * Returns a human readable address for this Place. May return null if the address is unknown.\n     * <p/>\n     * The address is localized according to the locale returned by {@link com.google.android.gms.location.places.Place#getLocale()}.\n     */\n    CharSequence getAddress();\n\n    /**\n     * Returns the attributions to be shown to the user if data from the {@link com.google.android.gms.location.places.Place} is used.\n     * <p/>\n     * We recommend placing this information below any place information. See\n     * <a href=\"https://developers.google.com/places/android/attributions#third-party\">Displaying Attributions</a> for more details.\n     *\n     * @return The attributions in HTML format, or null if there are no attributions to display.\n     */\n    CharSequence getAttributions();\n\n    /**\n     * Returns the unique id of this Place.\n     * <p/>\n     * This ID can be passed to {@link com.google.android.gms.location.places.GeoDataApi#getPlaceById(com.google.android.gms.common.api.GoogleApiClient, java.lang.String...)} to lookup the same place at a later\n     * time, but it is not guaranteed that such a lookup will succeed (the place may no longer exist\n     * in our database). It is possible that the returned Place in such a lookup will have a\n     * different ID (so there may be multiple ID's for one given place).\n     */\n    String getId();\n\n    /**\n     * Returns the location of this Place.\n     * <p/>\n     * The location is not necessarily the center of the Place, or any particular entry or exit\n     * point, but some arbitrarily chosen point within the geographic extent of the Place.\n     */\n    LatLng getLatLng();\n\n    /**\n     * Returns the locale in which the names and addresses were localized.\n     */\n    Locale getLocale();\n\n    /**\n     * Returns the name of this Place.\n     * <p/>\n     * The name is localized according to the locale returned by {@link com.google.android.gms.location.places.Place#getLocale()}.\n     */\n    CharSequence getName();\n\n    /**\n     * Returns the place's phone number in international format. Returns null if no phone number is\n     * known, or the place has no phone number.\n     * <p/>\n     * International format includes the country code, and is prefixed with the plus (+) sign. For\n     * example, the international phone number for Google's Mountain View, USA office is +1\n     * 650-253-0000.\n     */\n    CharSequence getPhoneNumber();\n\n    /**\n     * Returns a list of place types for this Place.\n     * <p/>\n     * The elements of this list are drawn from <code>Place.TYPE_*</code> constants, though one should\n     * expect there could be new place types returned that were introduced after an app was\n     * published.\n     */\n    List<Integer> getPlaceTypes();\n\n    /**\n     * Returns the price level for this place on a scale from 0 (cheapest) to 4.\n     * <p/>\n     * If no price level is known, a negative value is returned.\n     * <p/>\n     * The price level of the place, on a scale of 0 to 4. The exact amount indicated by a specific\n     * value will vary from region to region. Price levels are interpreted as follows:\n     */\n    int getPriceLevel();\n\n    /**\n     * Returns the place's rating, from 1.0 to 5.0, based on aggregated user reviews.\n     * <p/>\n     * If no rating is known, a negative value is returned.\n     */\n    float getRating();\n\n    /**\n     * Returns a viewport for displaying this Place. May return null if the size of the place is not\n     * known.\n     * <p/>\n     * This returns a viewport of a size that is suitable for displaying this Place. For example, a\n     * Place representing a store may have a relatively small viewport, while a Place representing a\n     * country may have a very large viewport.\n     */\n    LatLngBounds getViewport();\n\n    /**\n     * Returns the URI of the website of this Place. Returns null if no website is known.\n     * <p/>\n     * This is the URI of the website maintained by the Place, if available. Note this is a\n     * third-party website not affiliated with the Places API.\n     */\n    Uri getWebsiteUri();\n\n}\n"
  },
  {
    "path": "play-services-places/src/main/java/com/google/android/gms/location/places/PlaceFilter.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.location.places;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n/**\n * TODO: usage\n */\npublic class PlaceFilter extends AutoSafeParcelable {\n\n    public static final Creator<PlaceFilter> CREATOR = new AutoCreator<PlaceFilter>(PlaceFilter.class);\n}\n"
  },
  {
    "path": "play-services-places/src/main/java/com/google/android/gms/location/places/PlaceRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.location.places;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n/**\n * TODO: usage\n */\npublic class PlaceRequest extends AutoSafeParcelable {\n    public static final Creator<PlaceRequest> CREATOR = new AutoCreator<PlaceRequest>(PlaceRequest.class);\n}\n"
  },
  {
    "path": "play-services-places/src/main/java/com/google/android/gms/location/places/UserAddedPlace.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.location.places;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\n/**\n * TODO: usage\n */\npublic class UserAddedPlace extends AutoSafeParcelable {\n\n    @SafeParceled(1000)\n    private int versionCode = 1;\n\n    public static final Creator<UserAddedPlace> CREATOR = new AutoCreator<UserAddedPlace>(UserAddedPlace.class);\n}\n"
  },
  {
    "path": "play-services-places/src/main/java/com/google/android/gms/location/places/UserDataType.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.location.places;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n/**\n * TODO: usage\n */\npublic class UserDataType extends AutoSafeParcelable {\n\n    public static final Creator<UserDataType> CREATOR = new AutoCreator<UserDataType>(UserDataType.class);\n}\n"
  },
  {
    "path": "play-services-places/src/main/java/com/google/android/gms/location/places/internal/PlaceImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.location.places.internal;\n\nimport android.net.Uri;\nimport android.os.Bundle;\n\nimport com.google.android.gms.location.places.Place;\nimport com.google.android.gms.maps.model.LatLng;\nimport com.google.android.gms.maps.model.LatLngBounds;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Locale;\n\npublic class PlaceImpl extends AutoSafeParcelable implements Place {\n    @SafeParceled(1000)\n    private int versionCode = 2;\n    @SafeParceled(1)\n    public String id;\n    @SafeParceled(2)\n    public Bundle addressComponents;\n    @SafeParceled(4)\n    public LatLng latLng;\n    @SafeParceled(5)\n    public float levelNumber;\n    @SafeParceled(6)\n    public LatLngBounds viewport;\n    @SafeParceled(7)\n    public String timezoneId;\n    @SafeParceled(8)\n    public Uri websiteUri;\n    @SafeParceled(9)\n    public boolean isPermanentlyClosed;\n    @SafeParceled(10)\n    public float rating;\n    @SafeParceled(11)\n    public int priceLevel;\n    @SafeParceled(12)\n    public long timestampSecs;\n    @SafeParceled(value = 13, subClass = Integer.class)\n    public List<Integer> typesDeprecated = new ArrayList<Integer>();\n    @SafeParceled(14)\n    public String address;\n    @SafeParceled(15)\n    public String phoneNumber;\n    @SafeParceled(16)\n    public String regularOpenHours;\n    @SafeParceled(value = 17, subClass = String.class)\n    public List<String> attributions = new ArrayList<String>();\n    @SafeParceled(19)\n    public String name;\n    @SafeParceled(value = 20, subClass = Integer.class)\n    public List<Integer> placeTypes = new ArrayList<Integer>();\n\n    @Override\n    public CharSequence getAddress() {\n        return address;\n    }\n\n    @Override\n    public CharSequence getAttributions() {\n        return Arrays.toString(attributions.toArray());\n    }\n\n    @Override\n    public String getId() {\n        return id;\n    }\n\n    @Override\n    public LatLng getLatLng() {\n        return latLng;\n    }\n\n    @Override\n    public Locale getLocale() {\n        return Locale.getDefault();\n    }\n\n    @Override\n    public CharSequence getName() {\n        return name;\n    }\n\n    @Override\n    public CharSequence getPhoneNumber() {\n        return phoneNumber;\n    }\n\n    @Override\n    public List<Integer> getPlaceTypes() {\n        return placeTypes;\n    }\n\n    @Override\n    public int getPriceLevel() {\n        return priceLevel;\n    }\n\n    @Override\n    public float getRating() {\n        return rating;\n    }\n\n    @Override\n    public LatLngBounds getViewport() {\n        return viewport;\n    }\n\n    @Override\n    public Uri getWebsiteUri() {\n        return websiteUri;\n    }\n\n    @Override\n    public Place freeze() {\n        return this;\n    }\n\n    @Override\n    public boolean isDataValid() {\n        return true;\n    }\n\n    public static final Creator<PlaceImpl> CREATOR = new AutoSafeParcelable.AutoCreator<PlaceImpl>(PlaceImpl.class);\n}\n"
  },
  {
    "path": "play-services-places/src/main/java/com/google/android/gms/location/places/internal/PlacesParams.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.location.places.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class PlacesParams extends AutoSafeParcelable {\n\n    @SafeParceled(1000)\n    private int versionCode = 1;\n    @SafeParceled(1)\n    public final String clientPackageName;\n    @SafeParceled(2)\n    public final String locale;\n    @SafeParceled(3)\n    public final String accountName;\n    @SafeParceled(4)\n    public final String gCoreClientName;\n\n    private PlacesParams() {\n        clientPackageName = locale = accountName = gCoreClientName = null;\n    }\n\n    public static final Creator<PlacesParams> CREATOR = new AutoCreator<PlacesParams>(PlacesParams.class);\n}\n"
  },
  {
    "path": "play-services-places-placereport/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\nandroid {\n    namespace \"com.google.android.gms.places_placereport\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n}\n\napply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG implementation of play-services-places-placereport'\n\ndependencies {\n    // Dependencies from play-services-places-placereport:17.0.0\n    api project(\":play-services-basement\")\n}\n"
  },
  {
    "path": "play-services-places-placereport/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest />\n"
  },
  {
    "path": "play-services-places-placereport/src/main/java/com/google/android/gms/location/places/PlaceReport.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2017 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.location.places;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\n@PublicApi\npublic class PlaceReport extends AutoSafeParcelable {\n    @SafeParceled(1)\n    private int versionCode;\n    @SafeParceled(2)\n    private String placeId;\n    @SafeParceled(3)\n    private String tag;\n    @SafeParceled(4)\n    private String source;\n\n    public String getPlaceId() {\n        return placeId;\n    }\n\n    public String getTag() {\n        return tag;\n    }\n\n    public static final Creator<PlaceReport> CREATOR = new AutoCreator<PlaceReport>(PlaceReport.class);\n}\n"
  },
  {
    "path": "play-services-recaptcha/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\nandroid {\n    namespace \"com.google.android.gms.recaptcha\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n}\n\napply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG implementation of play-services-recaptcha'\n\ndependencies {\n    // Dependencies from play-services-recaptcha:17.0.1\n    api project(':play-services-base')\n    api project(':play-services-basement')\n    api project(':play-services-tasks')\n}\n"
  },
  {
    "path": "play-services-recaptcha/core/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'com.squareup.wire'\napply plugin: 'kotlin-android'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\ndependencies {\n    implementation project(':play-services-base-core')\n    implementation project(':play-services-droidguard-core')\n    implementation project(':play-services-safetynet-core')\n    implementation project(':play-services-recaptcha')\n    implementation project(':play-services-tasks-ktx')\n\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion\"\n    implementation \"org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutineVersion\"\n    implementation \"org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutineVersion\"\n\n    implementation \"androidx.core:core-ktx:$coreVersion\"\n    implementation \"androidx.lifecycle:lifecycle-runtime-ktx:$lifecycleVersion\"\n    implementation \"androidx.lifecycle:lifecycle-service:$lifecycleVersion\"\n    implementation \"androidx.webkit:webkit:$webkitVersion\"\n\n    implementation \"com.android.volley:volley:$volleyVersion\"\n    implementation \"com.squareup.wire:wire-runtime:$wireVersion\"\n}\n\nwire {\n    kotlin {}\n}\n\nandroid {\n    namespace \"org.microg.gms.recaptcha.core\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    sourceSets {\n        main.java.srcDirs += 'src/main/kotlin'\n    }\n\n    lintOptions {\n        disable 'MissingTranslation'\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n\n    kotlinOptions {\n        jvmTarget = 1.8\n    }\n}\n\napply from: '../../gradle/publish-android.gradle'\n\ndescription = 'microG service implementation for play-services-recaptcha'\n"
  },
  {
    "path": "play-services-recaptcha/core/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2021 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <application>\n        <!-- This service is in :ui process because it may spawn a web view. See https://crbug.com/558377 -->\n        <service android:name=\"org.microg.gms.recaptcha.RecaptchaService\"\n                 android:process=\":ui\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.recaptcha.service.START\"/>\n            </intent-filter>\n        </service>\n    </application>\n</manifest>\n"
  },
  {
    "path": "play-services-recaptcha/core/src/main/kotlin/org/microg/gms/recaptcha/RecaptchaGuardImpl.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.recaptcha\n\nimport android.content.Context\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.LocaleList\nimport android.util.Log\nimport com.android.volley.*\nimport com.android.volley.toolbox.Volley\nimport com.google.android.gms.droidguard.DroidGuardClient\nimport com.google.android.gms.recaptcha.RecaptchaHandle\nimport com.google.android.gms.recaptcha.RecaptchaResultData\nimport com.google.android.gms.recaptcha.internal.ExecuteParams\nimport com.google.android.gms.recaptcha.internal.InitParams\nimport com.google.android.gms.tasks.await\nimport com.squareup.wire.Message\nimport com.squareup.wire.ProtoAdapter\nimport kotlinx.coroutines.CompletableDeferred\nimport org.microg.gms.droidguard.core.VersionUtil\nimport org.microg.gms.utils.singleInstanceOf\nimport java.util.*\nimport kotlin.collections.HashMap\n\nprivate const val TAG = \"RecaptchaGuard\"\n\nclass RecaptchaGuardImpl(private val context: Context, private val packageName: String) : RecaptchaImpl {\n    private val queue = singleInstanceOf { Volley.newRequestQueue(context.applicationContext) }\n    private var lastToken: String? = null\n\n    override suspend fun init(params: InitParams): RecaptchaHandle {\n        val response = ProtobufPostRequest(\n            \"https://www.recaptcha.net/recaptcha/api3/ac\", RecaptchaInitRequest(\n                data_ = RecaptchaInitRequest.Data(\n                    siteKey = params.siteKey,\n                    packageName = packageName,\n                    version = \"${VersionUtil(context).versionCode};${params.version}\"\n                )\n            ), RecaptchaInitResponse.ADAPTER\n        ).sendAndAwait(queue)\n        lastToken = response.token\n        return RecaptchaHandle(params.siteKey, packageName, response.acceptableAdditionalArgs.toList())\n    }\n\n    override suspend fun execute(params: ExecuteParams): RecaptchaResultData {\n        if (params.handle.clientPackageName != null && params.handle.clientPackageName != packageName) throw IllegalArgumentException(\"invalid handle\")\n        val timestamp = System.currentTimeMillis()\n        val additionalArgs = mutableMapOf<String, String>()\n        val guardMap = mutableMapOf<String, String>()\n        for (key in params.action.additionalArgs.keySet()) {\n            val value = params.action.additionalArgs.getString(key)\n                ?: throw Exception(\"Only string values are allowed as an additional arg in RecaptchaAction\")\n            if (key !in params.handle.acceptableAdditionalArgs)\n                throw Exception(\"AdditionalArgs key[ \\\"$key\\\" ] is not accepted by reCATPCHA server\")\n            additionalArgs.put(key, value)\n        }\n        Log.d(TAG, \"Additional arguments: $additionalArgs\")\n        if (lastToken == null) {\n            init(InitParams().apply { siteKey = params.handle.siteKey; version = params.version })\n        }\n        val token = lastToken!!\n        guardMap[\"token\"] = token\n        guardMap[\"action\"] = params.action.toString()\n        guardMap[\"timestamp_millis\"] to timestamp.toString()\n        guardMap.putAll(additionalArgs)\n        if (params.action.verificationHistoryToken != null)\n            guardMap[\"verification_history_token\"] = params.action.verificationHistoryToken\n        val dg = DroidGuardClient.getResults(context, \"recaptcha-android\", guardMap).await()\n        val response = ProtobufPostRequest(\n            \"https://www.recaptcha.net/recaptcha/api3/ae\", RecaptchaExecuteRequest(\n                token = token,\n                action = params.action.toString(),\n                timestamp = timestamp,\n                dg = dg,\n                additionalArgs = additionalArgs,\n                verificationHistoryToken = params.action.verificationHistoryToken\n            ), RecaptchaExecuteResponse.ADAPTER\n        ).sendAndAwait(queue)\n        return RecaptchaResultData(response.token)\n    }\n\n    override suspend fun close(handle: RecaptchaHandle): Boolean {\n        if (handle.clientPackageName != null && handle.clientPackageName != packageName) throw IllegalArgumentException(\"invalid handle\")\n        val closed = lastToken != null\n        lastToken = null\n        return closed\n    }\n}\n\nclass ProtobufPostRequest<I : Message<I, *>, O>(url: String, private val i: I, private val oAdapter: ProtoAdapter<O>) :\n    Request<O>(Request.Method.POST, url, null) {\n    private val deferred = CompletableDeferred<O>()\n\n    override fun getHeaders(): Map<String, String> {\n        val headers = HashMap(super.getHeaders())\n        headers[\"Accept-Language\"] = if (SDK_INT >= 24) LocaleList.getDefault().toLanguageTags() else Locale.getDefault().language\n        return headers\n    }\n\n    override fun getBody(): ByteArray = i.encode()\n\n    override fun getBodyContentType(): String = \"application/x-protobuf\"\n\n    override fun parseNetworkResponse(response: NetworkResponse): Response<O> {\n        try {\n            return Response.success(oAdapter.decode(response.data), null)\n        } catch (e: VolleyError) {\n            return Response.error(e)\n        } catch (e: Exception) {\n            return Response.error(VolleyError())\n        }\n    }\n\n    override fun deliverResponse(response: O) {\n        Log.d(TAG, \"Got response: $response\")\n        deferred.complete(response)\n    }\n\n    override fun deliverError(error: VolleyError) {\n        deferred.completeExceptionally(error)\n    }\n\n    suspend fun await(): O = deferred.await()\n\n    suspend fun sendAndAwait(queue: RequestQueue): O {\n        Log.d(TAG, \"Sending request: $i\")\n        queue.add(this)\n        return await()\n    }\n}"
  },
  {
    "path": "play-services-recaptcha/core/src/main/kotlin/org/microg/gms/recaptcha/RecaptchaImpl.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.recaptcha\n\nimport com.google.android.gms.recaptcha.RecaptchaHandle\nimport com.google.android.gms.recaptcha.RecaptchaResultData\nimport com.google.android.gms.recaptcha.internal.ExecuteParams\nimport com.google.android.gms.recaptcha.internal.InitParams\n\ninterface RecaptchaImpl {\n    suspend fun init(params: InitParams): RecaptchaHandle\n    suspend fun execute(params: ExecuteParams): RecaptchaResultData\n    suspend fun close(handle: RecaptchaHandle): Boolean\n\n    object Unsupported : RecaptchaImpl {\n        override suspend fun init(params: InitParams): RecaptchaHandle {\n            throw UnsupportedOperationException()\n        }\n\n        override suspend fun execute(params: ExecuteParams): RecaptchaResultData {\n            throw UnsupportedOperationException()\n        }\n\n        override suspend fun close(handle: RecaptchaHandle): Boolean {\n            throw UnsupportedOperationException()\n        }\n    }\n}\n\n"
  },
  {
    "path": "play-services-recaptcha/core/src/main/kotlin/org/microg/gms/recaptcha/RecaptchaService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage org.microg.gms.recaptcha\n\nimport android.content.Context\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.Parcel\nimport android.util.Log\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.LifecycleOwner\nimport androidx.lifecycle.lifecycleScope\nimport com.google.android.gms.common.Feature\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.internal.ConnectionInfo\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport com.google.android.gms.recaptcha.RecaptchaAction\nimport com.google.android.gms.recaptcha.RecaptchaHandle\nimport com.google.android.gms.recaptcha.internal.*\nimport kotlinx.coroutines.launch\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.common.PackageUtils\nimport org.microg.gms.droidguard.core.DroidGuardPreferences\nimport org.microg.gms.safetynet.SafetyNetPreferences\nimport org.microg.gms.utils.warnOnTransactionIssues\n\nprivate const val TAG = \"RecaptchaService\"\n\nclass RecaptchaService : BaseService(TAG, GmsService.RECAPTCHA) {\n    private fun getRecaptchaImpl(packageName: String): ArrayList<RecaptchaImpl> {\n        val list = ArrayList<RecaptchaImpl>()\n        if (SafetyNetPreferences.isEnabled(this) && SDK_INT >= 19) {\n            list.add(RecaptchaWebImpl(this, packageName, lifecycle))\n        }\n        if (DroidGuardPreferences.isAvailable(this)) {\n            list.add(RecaptchaGuardImpl(this, packageName))\n        }\n        if (list.isEmpty()) {\n            list.add(RecaptchaImpl.Unsupported)\n        }\n        return list\n    }\n\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        val packageName = PackageUtils.getAndCheckCallingPackage(this, request.packageName)!!\n        val imps = getRecaptchaImpl(packageName)\n        callback.onPostInitCompleteWithConnectionInfo(\n            CommonStatusCodes.SUCCESS,\n            RecaptchaServiceImpl(this, packageName, lifecycle, imps),\n            ConnectionInfo().apply {\n                features = arrayOf(\n                    Feature(\"verify_with_recaptcha_v2_internal\", 1),\n                    Feature(\"init\", 3),\n                    Feature(\"execute\", 5),\n                    Feature(\"close\", 2)\n                )\n            }\n        )\n    }\n}\n\nclass RecaptchaServiceImpl(\n    private val context: Context,\n    private val packageName: String,\n    override val lifecycle: Lifecycle,\n    private val imps: List<RecaptchaImpl>\n) : IRecaptchaService.Stub(), LifecycleOwner {\n\n    private var realRecaptchaImpl: RecaptchaImpl? = null\n\n    override fun verifyWithRecaptcha(callback: IExecuteCallback, siteKey: String, packageName: String) {\n        Log.d(TAG, \"Not yet implemented: verifyWithRecaptcha($siteKey, $packageName)\")\n    }\n\n    override fun init(callback: IInitCallback, siteKey: String) {\n        init2(callback, InitParams().also {\n            it.siteKey = siteKey\n            it.version = LEGACY_VERSION\n        })\n    }\n\n    override fun execute(callback: IExecuteCallback, handle: RecaptchaHandle, action: RecaptchaAction) {\n        execute2(callback, ExecuteParams().also {\n            it.handle = handle\n            it.action = action\n            it.version = LEGACY_VERSION\n        })\n    }\n\n    override fun close(callback: ICloseCallback, handle: RecaptchaHandle) {\n        lifecycleScope.launch {\n            Log.d(TAG, \"close($handle)\")\n            try {\n                if (realRecaptchaImpl == null) {\n                    throw UnsupportedOperationException(\"Method <close> realRecaptchaImpl is null\")\n                }\n                Log.d(TAG, \"close realRecaptchaImpl:${realRecaptchaImpl}\")\n                callback.onClosed(Status.SUCCESS, realRecaptchaImpl!!.close(handle))\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n            }\n        }\n    }\n\n    override fun init2(callback: IInitCallback, params: InitParams) {\n        lifecycleScope.launch {\n            Log.d(TAG, \"init($params)\")\n            try {\n                Log.d(TAG, \"imps size: ${imps.size}\")\n                for (recaptchaImpl in imps) {\n                    Log.d(TAG, \"recaptchaImpl:${recaptchaImpl}\")\n                    val recaptchaHandle = runCatching { recaptchaImpl.init(params) }.getOrNull() ?: continue\n                    realRecaptchaImpl = recaptchaImpl\n                    if (params.version == LEGACY_VERSION) {\n                        callback.onHandle(Status.SUCCESS, recaptchaHandle)\n                    } else {\n                        callback.onResults(Status.SUCCESS, InitResults().also { it.handle = recaptchaHandle })\n                    }\n                    Log.d(TAG, \"realRecaptchaImpl:${realRecaptchaImpl}\")\n                    return@launch\n                }\n                if (realRecaptchaImpl == null) {\n                    throw UnsupportedOperationException(\"Method <init2> realRecaptchaImpl is null\")\n                }\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n                try {\n                    if (params.version == LEGACY_VERSION) {\n                        callback.onHandle(Status.INTERNAL_ERROR, null)\n                    } else {\n                        callback.onResults(Status.INTERNAL_ERROR, InitResults())\n                    }\n                } catch (e: Exception) {\n                    // Ignored\n                }\n            }\n        }\n    }\n\n    override fun execute2(callback: IExecuteCallback, params: ExecuteParams) {\n        Log.d(TAG, \"execute($params)\")\n        lifecycleScope.launch {\n            try {\n                if (realRecaptchaImpl == null) {\n                    throw UnsupportedOperationException(\"Method <execute2> realRecaptchaImpl is null\")\n                }\n                Log.d(TAG, \"execute2 realRecaptchaImpl:${realRecaptchaImpl}\")\n                val data = realRecaptchaImpl!!.execute(params)\n                if (params.version == LEGACY_VERSION) {\n                    callback.onData(Status.SUCCESS, data)\n                } else {\n                    callback.onResults(Status.SUCCESS, ExecuteResults().also { it.data = data })\n                }\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n                try {\n                    if (params.version == LEGACY_VERSION) {\n                        callback.onData(Status.INTERNAL_ERROR, null)\n                    } else {\n                        callback.onResults(Status.INTERNAL_ERROR, ExecuteResults())\n                    }\n                } catch (e: Exception) {\n                    // Ignored\n                }\n            }\n        }\n\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =\n        warnOnTransactionIssues(code, reply, flags, TAG) {\n            super.onTransact(code, data, reply, flags)\n        }\n\n    companion object {\n        const val LEGACY_VERSION = \"16.0.0\"\n    }\n}\n"
  },
  {
    "path": "play-services-recaptcha/core/src/main/kotlin/org/microg/gms/recaptcha/RecaptchaWebImpl.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.recaptcha\n\nimport android.app.Application\nimport android.content.Context\nimport android.content.Intent\nimport android.content.pm.PackageManager\nimport android.media.AudioManager\nimport android.os.BatteryManager\nimport android.os.Handler\nimport android.provider.Settings\nimport android.text.format.DateFormat\nimport android.util.Base64\nimport android.util.Log\nimport android.webkit.JavascriptInterface\nimport android.webkit.WebResourceResponse\nimport android.webkit.WebView\nimport androidx.annotation.Keep\nimport androidx.annotation.RequiresApi\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.LifecycleOwner\nimport androidx.lifecycle.lifecycleScope\nimport androidx.webkit.WebViewClientCompat\nimport com.google.android.gms.recaptcha.RecaptchaHandle\nimport com.google.android.gms.recaptcha.RecaptchaResultData\nimport com.google.android.gms.recaptcha.internal.ExecuteParams\nimport com.google.android.gms.recaptcha.internal.InitParams\nimport com.google.android.gms.tasks.Task\nimport com.google.android.gms.tasks.Tasks\nimport kotlinx.coroutines.delay\nimport kotlinx.coroutines.launch\nimport okio.ByteString\nimport org.microg.gms.profile.Build\nimport org.microg.gms.profile.ProfileManager\nimport org.microg.gms.tasks.TaskImpl\nimport org.microg.gms.utils.toBase64\nimport java.io.ByteArrayInputStream\nimport java.lang.reflect.Array\nimport java.lang.reflect.Constructor\nimport java.lang.reflect.Field\nimport java.lang.reflect.Method\nimport java.lang.reflect.Modifier\nimport java.lang.reflect.Proxy\nimport java.net.URLEncoder\nimport java.nio.ByteBuffer\nimport java.nio.charset.StandardCharsets\nimport java.util.ArrayDeque\nimport java.util.Locale\nimport java.util.Queue\nimport java.util.UUID\nimport java.util.concurrent.atomic.AtomicBoolean\nimport kotlin.coroutines.Continuation\nimport kotlin.coroutines.resume\nimport kotlin.coroutines.resumeWithException\nimport kotlin.coroutines.suspendCoroutine\n\nprivate const val TAG = \"RecaptchaWeb\"\n\n@RequiresApi(19)\nclass RecaptchaWebImpl(private val context: Context, private val packageName: String, override val lifecycle: Lifecycle) : RecaptchaImpl, LifecycleOwner {\n    private var webView: WebView? = null\n    private var lastRequestToken: String? = null\n    private var initFinished = AtomicBoolean(true)\n    private var initContinuation: Continuation<Int>? = null\n    private var executeFinished = AtomicBoolean(true)\n    private var executeContinuation: Continuation<String>? = null\n\n    override suspend fun init(params: InitParams): RecaptchaHandle {\n        lastRequestToken = UUID.randomUUID().toString()\n        ProfileManager.ensureInitialized(context)\n        FakeHandler.setDecryptKeyPrefix(IntArray(0))\n        FakeApplication.context = context\n        FakeApplication.packageNameOverride = packageName\n        suspendCoroutine { continuation ->\n            initFinished.set(false)\n            initContinuation = continuation\n            webView = WebView(context).apply {\n                settings.javaScriptEnabled = true\n                addJavascriptInterface(RNJavaScriptInterface(this@RecaptchaWebImpl, CodeInterpreter(this@RecaptchaWebImpl)), \"RN\")\n                webViewClient = object : WebViewClientCompat() {\n                    fun String.isRecaptchaUrl() = startsWith(\"https://www.recaptcha.net/\") || startsWith(\"https://www.gstatic.com/recaptcha/\")\n\n                    override fun shouldInterceptRequest(view: WebView, url: String): WebResourceResponse? {\n                        if (url.isRecaptchaUrl()) {\n                            return null\n                        }\n                        return WebResourceResponse(\"text/plain\", \"UTF-8\", ByteArrayInputStream(byteArrayOf()))\n                    }\n\n                    override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {\n                        return !url.isRecaptchaUrl()\n                    }\n\n                    override fun onPageFinished(view: WebView?, url: String?) {\n                    }\n                }\n                postUrl(\n                    MWV_URL, (\"\" +\n                            \"k=${URLEncoder.encode(params.siteKey, \"UTF-8\")}&\" +\n                            \"pk=${URLEncoder.encode(packageName, \"UTF-8\")}&\" +\n                            \"mst=ANDROID_ONPLAY&\" +\n                            \"msv=18.1.1&\" +\n                            \"msi=${URLEncoder.encode(lastRequestToken, \"UTF-8\")}&\" +\n                            \"mov=${Build.VERSION.SDK_INT}\"\n                            ).toByteArray()\n                )\n            }\n            lifecycleScope.launch {\n                delay(10000)\n                if (!initFinished.getAndSet(true)) {\n                    try {\n                        continuation.resumeWithException(RuntimeException(\"Timeout reached\"))\n                    } catch (_: Exception) {}\n                }\n            }\n        }\n        initContinuation = null\n        return RecaptchaHandle(params.siteKey, packageName, emptyList())\n    }\n\n    override suspend fun execute(params: ExecuteParams): RecaptchaResultData {\n        if (webView == null) {\n            init(InitParams().apply { siteKey = params.handle.siteKey; version = params.version })\n        }\n        val additionalArgs = mutableMapOf<String, String>()\n        for (key in params.action.additionalArgs.keySet()) {\n            additionalArgs[key] = params.action.additionalArgs.getString(key)!!\n        }\n        val request = RecaptchaExecuteRequest(token = lastRequestToken, action = params.action.toString(), additionalArgs = additionalArgs).encode().toBase64(Base64.URL_SAFE, Base64.NO_WRAP)\n        val token = suspendCoroutine { continuation ->\n            executeFinished.set(false)\n            executeContinuation = continuation\n            eval(\"recaptcha.m.Main.execute(\\\"${request}\\\")\")\n            lifecycleScope.launch {\n                delay(10000)\n                if (!executeFinished.getAndSet(true)) {\n                    try {\n                        continuation.resumeWithException(RuntimeException(\"Timeout reached\"))\n                    } catch (_: Exception) {}\n                }\n            }\n        }\n        return RecaptchaResultData(token)\n    }\n\n    override suspend fun close(handle: RecaptchaHandle): Boolean {\n        if (handle.clientPackageName != null && handle.clientPackageName != packageName) throw IllegalArgumentException(\"invalid handle\")\n        val closed = webView != null\n        webView?.stopLoading()\n        webView?.loadUrl(\"about:blank\")\n        webView = null\n        return closed\n    }\n\n    private fun eval(script: String) {\n        Log.d(TAG, \"eval: $script\")\n        webView?.let {\n            Handler(context.mainLooper).post {\n                it.evaluateJavascript(script, null)\n            }\n        }\n    }\n\n    protected fun finalize() {\n        FakeApplication.packageNameOverride = \"\"\n    }\n\n    companion object {\n        private const val MWV_URL = \"https://www.recaptcha.net/recaptcha/api3/mwv\"\n        private const val DEBUG = false\n        object FakeApplication : Application() {\n            var context: Context\n                get() = baseContext\n                set(value) { try { attachBaseContext(value.applicationContext) } catch (_: Exception) { } }\n            var packageNameOverride: String = \"\"\n            override fun getPackageName(): String {\n                return packageNameOverride\n            }\n        }\n        var codeDecryptKeyPrefix = emptyList<Int>()\n            private set\n\n        class FakeHandler : Exception() {\n            private var cloudProjectNumber: Long? = 0\n            private var nonce: String? = null\n\n            @Keep\n            fun requestIntegrityToken(request: FakeHandler): Task<FakeHandler> {\n                return Tasks.forException(FakeHandler())\n            }\n\n            @Keep\n            fun setCloudProjectNumber(cloudProjectNumber: Long): FakeHandler {\n                this.cloudProjectNumber = cloudProjectNumber\n                return this\n            }\n\n            @Keep\n            fun setNonce(nonce: String): FakeHandler {\n                this.nonce = nonce\n                return this\n            }\n\n            @Keep\n            fun build(): FakeHandler {\n                return this\n            }\n\n            @Keep\n            fun cloudProjectNumber(): Long? {\n                return cloudProjectNumber\n            }\n\n            @Keep\n            fun nonce(): String? {\n                return nonce\n            }\n\n            @Keep\n            fun getErrorCode(): Int = -1\n            \n            companion object {\n                @Keep\n                @JvmStatic\n                fun setDecryptKeyPrefix(newKeyPrefix: IntArray) {\n                    codeDecryptKeyPrefix = newKeyPrefix.asList()\n                }\n\n                @Keep\n                @JvmStatic\n                fun getFakeApplication(): Application = FakeApplication\n\n                @Keep\n                @JvmStatic\n                fun createFakeIntegrityManager(context: Context): FakeHandler {\n                    return FakeHandler()\n                }\n                @Keep\n                @JvmStatic\n                fun createFakeIntegrityTokenRequestBuilder(): FakeHandler {\n                    return FakeHandler()\n                }\n            }\n        }\n\n        private class CodeInterpreter(private val impl: RecaptchaWebImpl) {\n            val dict = mutableMapOf<Int, Any?>()\n            var errorHandler = \"\"\n            var xorSecret = IntRange(0, 127).random().toByte()\n\n            private val intToClassMap = mapOf(\n                1 to java.lang.Integer.TYPE,\n                2 to java.lang.Short.TYPE,\n                3 to java.lang.Byte.TYPE,\n                4 to java.lang.Long.TYPE,\n                5 to java.lang.Character.TYPE,\n                6 to java.lang.Float.TYPE,\n                7 to java.lang.Double.TYPE,\n                8 to java.lang.Boolean.TYPE,\n                9 to FakeHandler::class.java\n            )\n\n            private fun getClass(name: String): Class<*>? = when (name) {\n                \"[I\" -> IntArray::class.java\n                \"[B\" -> ByteArray::class.java\n                \"android.os.Build\" -> Build::class.java\n                \"android.os.Build\\$VERSION\" -> Build.VERSION::class.java\n                \"android.app.ActivityThread\" -> FakeHandler::class.java\n                \"com.google.android.play.core.integrity.IntegrityManager\" -> FakeHandler::class.java\n                \"com.google.android.play.core.integrity.IntegrityManagerFactory\" -> FakeHandler::class.java\n                \"com.google.android.play.core.integrity.IntegrityTokenRequest\" -> FakeHandler::class.java\n                \"com.google.android.play.core.integrity.IntegrityTokenResponse\" -> FakeHandler::class.java\n                \"android.content.Intent\", \"android.content.IntentFilter\", \"android.content.BroadcastReceiver\",\n                \"android.content.Context\", \"android.content.pm.PackageManager\", \"android.content.ContentResolver\",\n                \"java.lang.String\", \"java.lang.CharSequence\", \"java.lang.Long\",\n                \"java.nio.charset.Charset\", \"java.nio.charset.StandardCharsets\",\n                \"android.text.format.DateFormat\", \"java.util.Date\", \"java.util.Locale\", \"java.nio.ByteBuffer\",\n                \"android.os.BatteryManager\", \"android.media.AudioManager\",\n                \"com.google.android.gms.tasks.OnCompleteListener\",\n                \"android.provider.Settings\\$System\" -> Class.forName(name)\n\n                else -> {\n                    Log.w(TAG, \"Not providing class $name\", Exception())\n                    if (DEBUG) Class.forName(name) else null\n                }\n            }\n\n            private fun getMethod(cls: Class<*>, name: String, params: kotlin.Array<Class<*>?>): Method? = when {\n                cls == FakeHandler::class.java && name == \"acx\" -> FakeHandler::class.java.getMethod(\"setDecryptKeyPrefix\", *params)\n                cls == FakeHandler::class.java && name == \"currentApplication\" -> FakeHandler::class.java.getMethod(\"getFakeApplication\", *params)\n                cls == FakeHandler::class.java && name == \"create\" -> FakeHandler::class.java.getMethod(\"createFakeIntegrityManager\", *params)\n                cls == FakeHandler::class.java && name == \"builder\" -> FakeHandler::class.java.getMethod(\"createFakeIntegrityTokenRequestBuilder\", *params)\n                cls == FakeHandler::class.java -> cls.getMethod(name, *params)\n                cls == FakeApplication.javaClass && name == \"getContentResolver\" -> cls.getMethod(name, *params)\n                cls == FakeApplication.javaClass && name == \"getSystemService\" -> cls.getMethod(name, *params)\n                cls == FakeApplication.javaClass && name == \"registerReceiver\" -> cls.getMethod(name, *params)\n                cls == PackageManager::class.java && name == \"checkPermission\" -> cls.getMethod(name, *params)\n                cls == Context::class.java && name == \"checkSelfPermission\" -> cls.getMethod(name, *params)\n                cls == Context::class.java && name == \"getPackageManager\" -> cls.getMethod(name, *params)\n                cls == Context::class.java && name == \"getPackageName\" -> cls.getMethod(name, *params)\n                cls == AudioManager::class.java && name == \"getStreamVolume\" -> cls.getMethod(name, *params)\n                cls == Settings.System::class.java && name == \"getInt\" -> cls.getMethod(name, *params)\n                cls == DateFormat::class.java -> cls.getMethod(name, *params)\n                cls == Locale::class.java -> cls.getMethod(name, *params)\n                cls == Intent::class.java -> cls.getMethod(name, *params)\n                cls == String::class.java -> cls.getMethod(name, *params)\n                cls == ByteBuffer::class.java -> cls.getMethod(name, *params)\n                cls == TaskImpl::class.java -> cls.getMethod(name, *params)\n                name == \"toString\" -> cls.getMethod(name, *params)\n                name == \"parseLong\" -> cls.getMethod(name, *params)\n                else -> {\n                    Log.w(TAG, \"Not providing method $name in ${cls.display()}\", Exception())\n                    if (DEBUG) cls.getMethod(name, *params) else null\n                }\n            }\n\n            private fun getField(cls: Class<*>, name: String): Field? = when {\n                cls == Build::class.java -> cls.getField(name)\n                cls == Build.VERSION::class.java -> cls.getField(name)\n                cls == Settings.System::class.java && cls.getField(name).modifiers.and(Modifier.STATIC) > 0 -> cls.getField(name)\n                cls == BatteryManager::class.java && cls.getField(name).modifiers.and(Modifier.STATIC) > 0 -> cls.getField(name)\n                cls == AudioManager::class.java && cls.getField(name).modifiers.and(Modifier.STATIC) > 0 -> cls.getField(name)\n                cls == StandardCharsets::class.java && cls.getField(name).modifiers.and(Modifier.STATIC) > 0 -> cls.getField(name)\n                else -> {\n                    Log.w(TAG, \"Not providing field $name in ${cls.display()}\", Exception())\n                    if (DEBUG) cls.getField(name) else null\n                }\n            }\n\n            private operator fun Any?.rem(other: Any?): Any? = when {\n                this is IntArray && other is Int -> map { it % other }.toIntArray()\n                else -> throw UnsupportedOperationException(\"rem ${this?.javaClass} % ${other?.javaClass}\")\n            }\n\n            private infix fun Any?.xor(other: Any?): Any? = when {\n                this is String && other is Int -> map { it.code xor other }.toIntArray()\n                this is String && other is Byte -> encodeToByteArray().map { (it.toInt() xor other.toInt()).toByte() }.toByteArray()\n                this is Long && other is Long -> this xor other\n                else -> throw UnsupportedOperationException(\"xor ${this?.javaClass} ^ ${other?.javaClass}\")\n            }\n\n            private fun Any?.join(): Any? = when (this) {\n                is ByteArray -> decodeToString()\n                is CharArray -> concatToString()\n                is IntArray -> joinToString(\",\", \"[\", \"]\")\n                is LongArray -> joinToString(\",\", \"[\", \"]\")\n                is ShortArray -> joinToString(\",\", \"[\", \"]\")\n                is FloatArray -> joinToString(\",\", \"[\", \"]\")\n                is DoubleArray -> joinToString(\",\", \"[\", \"]\")\n                is kotlin.Array<*> -> joinToString(\",\", \"[\", \"]\")\n                is Iterable<*> -> joinToString(\",\", \"[\", \"]\")\n                else -> this\n            }\n\n            private fun String.deXor(): String = map { Char(it.code xor xorSecret.toInt()) }.toCharArray().concatToString()\n\n            private fun Any?.deXor(): Any? = when {\n                this is RecaptchaWebCode.Arg && this.asObject() is String -> this.asObject()!!.deXor()\n                this is String -> this.deXor()\n                else -> this\n            }\n\n            private fun Any.asClass(): Class<*>? = when (this) {\n                is RecaptchaWebCode.Arg -> asObject()!!.asClass()\n                is Int -> intToClassMap[this]!!\n                is String -> getClass(this)\n                is Class<*> -> this\n                else -> throw UnsupportedOperationException(\"$this.asClass()\")\n            }\n\n            private fun Any?.getClass(): Class<*> = when (this) {\n                is RecaptchaWebCode.Arg -> asObject().getClass()\n                is Class<*> -> this\n                null -> Unit.javaClass\n                else -> this.javaClass\n            }\n\n            private fun Any?.display(): String = when (this) {\n                is RecaptchaWebCode.Arg -> asObject().display() + if (index != null) \" (d[$index])\" else \"\"\n                is Int, is Boolean -> \"${this}\"\n                is Byte -> \"${this}b\"\n                is Short -> \"${this}s\"\n                is Long -> \"${this}l\"\n                is Double -> \"${this}d\"\n                is Float -> \"${this}f\"\n                is String -> if (any { !it.isLetterOrDigit() && it !in listOf('.', '=', '-', '_') }) \"<string with complex chars>\" else \"\\\"${this}\\\"\"\n                is Class<*> -> name\n                is Constructor<*> -> \"{new ${declaringClass.name}(${parameterTypes.joinToString { it.name }})}\"\n                is Method -> \"{${declaringClass.name}.$name(${parameterTypes.joinToString { it.name }})}\"\n                is Field -> \"{${declaringClass.name}.$name}\"\n                is IntArray -> joinToString(prefix = \"[\", postfix = \"]\")\n                is ByteArray -> joinToString(prefix = \"[\", postfix = \"]b\")\n                is ShortArray -> joinToString(prefix = \"[\", postfix = \"]s\")\n                is LongArray -> joinToString(prefix = \"[\", postfix = \"]l\")\n                is FloatArray -> joinToString(prefix = \"[\", postfix = \"]f\")\n                is DoubleArray -> joinToString(prefix = \"[\", postfix = \"]d\")\n                is BooleanArray -> joinToString(prefix = \"[\", postfix = \"]\")\n                null -> \"null\"\n                else -> \"@{${this.javaClass.name}}\"\n            }\n\n            private fun RecaptchaWebCode.Arg.asObject(): Any? = when {\n                index != null -> dict[index]\n                bol != null -> bol\n                bt != null -> bt[0]\n                chr != null -> chr[0]\n                sht != null -> sht.toShort()\n                i != null -> i\n                l != null -> l\n                flt != null -> flt\n                dbl != null -> dbl\n                str != null -> str\n                else -> null\n            }\n\n            private fun Any.asListValue(): RecaptchaWebList.Value = when(this) {\n                is Int -> RecaptchaWebList.Value(i = this)\n                is Short -> RecaptchaWebList.Value(sht = this.toInt())\n                is Byte -> RecaptchaWebList.Value(bt = ByteString.of(this))\n                is Long -> RecaptchaWebList.Value(l = this)\n                is Double -> RecaptchaWebList.Value(dbl = this)\n                is Float -> RecaptchaWebList.Value(flt = this)\n                is Boolean -> RecaptchaWebList.Value(bol = this)\n                is Char -> RecaptchaWebList.Value(chr = this.toString())\n                is String -> RecaptchaWebList.Value(str = this)\n                else -> RecaptchaWebList.Value(str = toString())\n            }\n\n            fun execute(code: RecaptchaWebCode) {\n                for (op in code.ops) {\n                    when (op.code) {\n                        1 -> {\n                            // d[i] = a0\n                            if (DEBUG) Log.d(TAG, \"d[${op.arg1}] = ${op.args[0].display()}\")\n                            dict[op.arg1!!] = op.args[0].asObject()\n                        }\n\n                        2 -> {\n                            // d[i] = a0 .. a1\n                            if (DEBUG) Log.d(TAG, \"d[${op.arg1}] = \\\"${op.args[0].display()}${op.args[1].display()}\\\"\")\n                            dict[op.arg1!!] = \"${op.args[0].asObject()}${op.args[1].asObject()}\"\n                        }\n\n                        3 -> {\n                            // d[i] = Class(a0)\n                            val cls = op.args[0].asObject().deXor()?.asClass()\n                            if (DEBUG) Log.d(TAG, \"d[${op.arg1}] = $cls\")\n                            dict[op.arg1!!] = cls\n                        }\n\n                        4 -> {\n                            // d[i] = Class(a0).getConstructor(a1 ...)\n                            val constructor = op.args[0].asClass()!!.getConstructor(*op.args.subList(1, op.args.size).map { it.asClass() }.toTypedArray())\n                            if (DEBUG) Log.d(TAG, \"d[${op.arg1}] = ${constructor.display()}\")\n                            dict[op.arg1!!] = constructor\n                        }\n\n                        5 -> {\n                            // d[i] = Class(a0).getMethod(a1, a2 ...)\n                            val methodName = (op.args[1].asObject().deXor() as String)\n                            val cls = op.args[0].getClass()\n                            val method = getMethod(cls, methodName, op.args.subList(2, op.args.size).map { it.asClass() }.toTypedArray())\n                            if (DEBUG) Log.d(TAG, \"d[${op.arg1}] = ${method.display()}\")\n                            dict[op.arg1!!] = method\n                        }\n\n                        6 -> {\n                            // d[i] = Class(a0).getField(a1)\n                            val fieldName = (op.args[1].asObject().deXor() as String)\n                            val cls = op.args[0].getClass()\n                            val field = getField(cls, fieldName)\n                            if (DEBUG) Log.d(TAG, \"d[${op.arg1}] = ${field.display()}\")\n                            dict[op.arg1!!] = field\n                        }\n\n                        7 -> {\n                            // d[i] = Constructor(a0).newInstance(a1 ...)\n                            if (DEBUG) Log.d(\n                                TAG,\n                                \"d[${op.arg1}] = new ${(op.args[0].asObject() as Constructor<*>).name}(${\n                                    op.args.subList(1, op.args.size).joinToString { it.display() }\n                                })\"\n                            )\n                            dict[op.arg1!!] =\n                                (op.args[0].asObject() as Constructor<*>).newInstance(*op.args.subList(1, op.args.size).map { it.asObject() }.toTypedArray())\n                        }\n\n                        8 -> {\n                            // d[i] = Method(a0).invoke(a1, a2 ...)\n                            if (DEBUG) Log.d(\n                                TAG,\n                                \"d[${op.arg1}] = (${op.args[1].display()}).${(op.args[0].asObject() as Method).name}(${\n                                    op.args.subList(2, op.args.size).joinToString { it.display() }\n                                })\"\n                            )\n                            dict[op.arg1!!] = (op.args[0].asObject() as Method).invoke(\n                                op.args[1].asObject(),\n                                *op.args.subList(2, op.args.size).map { it.asObject() }.toTypedArray()\n                            )\n                        }\n\n                        9 -> {\n                            // d[i] = Method(a0).invoke(null, a1 ...)\n                            if (DEBUG) Log.d(\n                                TAG,\n                                \"d[${op.arg1}] = ${(op.args[0].asObject() as Method).declaringClass.name}.${(op.args[0].asObject() as Method).name}(${\n                                    op.args.subList(\n                                        1,\n                                        op.args.size\n                                    ).joinToString { it.display() }\n                                })\"\n                            )\n                            dict[op.arg1!!] =\n                                (op.args[0].asObject() as Method).invoke(null, *op.args.subList(1, op.args.size).map { it.asObject() }.toTypedArray())\n                        }\n\n                        10 -> {\n                            // d[i] = Field(a0).get(a1)\n                            if (DEBUG) Log.d(TAG, \"d[${op.arg1}] = (${op.args[1].display()}).${(op.args[0].asObject() as Field).name}\")\n                            dict[op.arg1!!] = (op.args[0].asObject() as Field).get(op.args[1].asObject())\n                        }\n\n                        11 -> {\n                            // d[i] = Field(a0).get(null)\n                            if (DEBUG) Log.d(TAG, \"d[${op.arg1}] = ${(op.args[0].asObject() as Field).declaringClass.name}.${(op.args[0].asObject() as Field).name}\")\n                            dict[op.arg1!!] = (op.args[0].asObject() as Field).get(null)\n                        }\n\n                        12 -> {\n                            // Field(a0).set(a1, a2)\n                            if (DEBUG) Log.d(TAG, \"(${op.args[1].display()}).${(op.args[0].asObject() as Field).name} = ${op.args[2].display()}\")\n                            (op.args[0].asObject() as Field).set(op.args[1].asObject(), op.args[2].asObject())\n                        }\n\n                        13 -> {\n                            // Field(a0).set(null, a1)\n                            if (DEBUG) Log.d(\n                                TAG,\n                                \"(${(op.args[0].asObject() as Field).declaringClass.name}).${(op.args[0].asObject() as Field).name} = ${op.args[1].display()}\"\n                            )\n                            (op.args[0].asObject() as Field).set(null, op.args[1].asObject())\n                        }\n\n                        15 -> {\n                            // eval(a0(a1))\n                            impl.eval(\"${op.args[0].str}(\\\"${op.args[1].asObject()}\\\")\")\n                        }\n\n                        17 -> {\n                            // d[i] = new a0[a1]\n                            if (DEBUG) Log.d(TAG, \"d[${op.arg1}] = new ${op.args[0].asClass()!!.name}[${op.args[1].display()}]\")\n                            dict[op.arg1!!] = Array.newInstance(op.args[0].asClass(), op.args[1].asObject() as Int)\n                        }\n\n                        18 -> {\n                            // d[i] = new a1() { * a2(args) { eval(a0(args)); return a3; } }\n                            val callbackName = op.args[0].asObject() as String\n                            val methodName = (op.args[2].asObject() as String).deXor()\n                            val cls = op.args[1].asObject().deXor()?.asClass()\n                            val returnValue = op.args[3].asObject()\n                            val argsTarget = (if (op.args.size == 5) op.args[4].asObject() as? Int else null) ?: -1\n                            if (DEBUG) Log.d(TAG, \"d[${op.arg1}] = new ${cls?.name}() { * ${methodName}(*) { js:$callbackName(*); return ${returnValue.display()}; } }\")\n                            dict[op.arg1!!] =\n                                Proxy.newProxyInstance(cls!!.classLoader, arrayOf(cls)) { obj: Any, method: Method, args: kotlin.Array<Any>? ->\n                                    if (method.name == methodName) {\n                                        if (argsTarget != -1) dict[argsTarget] = args\n                                        val encoded = RecaptchaWebList(args.orEmpty().map { it.asListValue() }).encode().toBase64(Base64.URL_SAFE, Base64.NO_WRAP)\n                                        impl.eval(\"${callbackName}(\\\"$encoded\\\")\")\n                                        returnValue\n                                    } else {\n                                        null\n                                    }\n                                }\n                        }\n\n                        19 -> {\n                            // d[i] = new Queue(a1)\n                            // d[a0] = new a2() { * a3(args) { d[i].add(args); return a4; } }\n                            val methodName = (op.args[3].asObject() as String).deXor()\n                            val maxSize = op.args[1].asObject() as Int\n                            val queue = ArrayDeque<List<Any>>(maxSize)\n                            val limitedQueue = object : Queue<List<Any>> by queue {\n                                override fun add(element: List<Any>?): Boolean {\n                                    if (maxSize == 0) return true\n                                    if (size == maxSize) remove()\n                                    queue.add(element)\n                                    return true\n                                }\n                            }\n                            val returnValue = if (op.args.size == 5) op.args[4].asObject() else null\n                            val cls = op.args[2].asObject().deXor()?.asClass()\n                            dict[op.arg1!!] = limitedQueue\n                            dict[op.args[0].asObject() as Int] = Proxy.newProxyInstance(cls!!.classLoader, arrayOf(cls)) { obj: Any, method: Method, args: kotlin.Array<Any>? ->\n                                if (method.name == methodName) {\n                                    limitedQueue.add(args?.asList().orEmpty())\n                                    returnValue\n                                } else {\n                                    null\n                                }\n                            }\n                        }\n\n                        20 -> {\n                            // unset(d, a0 ...)\n                            if (DEBUG) Log.d(TAG, \"d[${op.args.joinToString { it.index.toString() }}] = @@@\")\n                            for (arg in op.args) {\n                                dict.remove(arg.index)\n                            }\n                        }\n\n                        26 -> {\n                            // e = a0\n                            errorHandler = op.args[0].str!!\n                        }\n\n                        27 -> {\n                            // clear(d)\n                            dict.clear()\n                        }\n\n                        30 -> {\n                            // d[i] = encode(a0 ...)\n                            val res = RecaptchaWebList(op.args.map { it.asObject()!!.asListValue() }).encode().toBase64(Base64.URL_SAFE, Base64.NO_WRAP)\n                            if (DEBUG) Log.d(TAG, \"d[${op.arg1}] = ${res.display()}\")\n                            dict[op.arg1!!] = res\n                        }\n\n                        31 -> {\n                            // a0[a1] = a2\n                            if (DEBUG) Log.d(TAG, \"d[${op.args[0].index}][${op.args[1].display()}] = ${op.args[2].display()}\")\n                            Array.set(op.args[0].asObject()!!, op.args[1].asObject() as Int, op.args[2].asObject())\n                        }\n\n                        32 -> {\n                            // d[i] = a0[a1]\n                            if (DEBUG) Log.d(TAG, \"d[${op.arg1}] = ${op.args[0].display()}[${op.args[1].display()}]\")\n                            val arr = op.args[0].asObject()\n                            val idx = op.args[1].asObject() as Int\n                            val res = when (arr) {\n                                is String -> arr[idx]\n                                is List<*> -> arr[idx]\n                                else -> Array.get(arr, idx)\n                            }\n                            dict[op.arg1!!] = res\n                        }\n\n                        34 -> {\n                            // d[i] = a0 % a1\n                            if (DEBUG) Log.d(TAG, \"d[${op.arg1}] = ${op.args[0].display()} % ${op.args[1].display()}\")\n                            dict[op.arg1!!] = op.args[0].asObject() % op.args[1].asObject()\n                        }\n\n                        35 -> {\n                            // d[i] = a0 ^ a1\n                            if (DEBUG) Log.d(TAG, \"d[${op.arg1}] = ${op.args[0].display()} ^ ${op.args[1].display()}\")\n                            dict[op.arg1!!] = op.args[0].asObject() xor op.args[1].asObject()\n                        }\n\n                        37 -> {\n                            // d[i] = String(a1[*a0])\n                            val str = op.args[1].asObject() as String\n                            val res = (op.args[0].asObject() as IntArray).map { str[it] }.toCharArray().concatToString()\n                            if (DEBUG) Log.d(TAG, \"d[${op.arg1}] = ${res.display()}\")\n                            dict[op.arg1!!] = res\n                        }\n\n                        38 -> {\n                            // x = a0\n                            xorSecret = op.args[0].asObject() as Byte\n                        }\n\n                        39 -> {\n                            // d[i] = join(a0)\n                            val res = op.args[0].asObject().join()\n                            if (DEBUG) Log.d(TAG, \"d[${op.arg1}] = ${res.display()}\")\n                            dict[op.arg1!!] = res\n                        }\n\n                        else -> {\n                            Log.w(TAG, \"Op ${op.encode().toBase64(Base64.URL_SAFE, Base64.NO_WRAP)} not implemented (code=${op.code})\")\n                        }\n                    }\n                }\n            }\n        }\n\n        private class RNJavaScriptInterface(private val impl: RecaptchaWebImpl, private val interpreter: CodeInterpreter) {\n\n            @JavascriptInterface\n            fun zzoed(input: String) {\n                val result = RecaptchaWebResult.ADAPTER.decode(Base64.decode(input, Base64.URL_SAFE))\n                if (DEBUG) Log.d(TAG, \"zzoed: $result\")\n                if (!impl.executeFinished.getAndSet(true) && impl.lastRequestToken == result.requestToken) {\n                    if (result.code == 1 && result.token != null) {\n                        impl.executeContinuation?.resume(result.token)\n                    } else {\n                        impl.executeContinuation?.resumeWithException(RuntimeException(\"Status ${result.code}\"))\n                    }\n                }\n            }\n\n            @JavascriptInterface\n            fun zzoid(input: String) {\n                val status = RecaptchaWebStatusCode.ADAPTER.decode(Base64.decode(input, Base64.URL_SAFE))\n                if (DEBUG) Log.d(TAG, \"zzoid: $status\")\n                if (!impl.initFinished.getAndSet(true)) {\n                    if (status.code != null) {\n                        impl.initContinuation?.resume(status.code)\n                    } else {\n                        impl.initContinuation?.resumeWithException(RuntimeException(\"Status is null\"))\n                    }\n                }\n            }\n\n            @JavascriptInterface\n            fun zzrp(input: String) {\n                val callback = RecaptchaWebEncryptedCallback.ADAPTER.decode(Base64.decode(input, Base64.URL_SAFE))\n                var key = (codeDecryptKeyPrefix + callback.key).reduce { a, b -> a xor b }\n                fun next(): Int {\n                    key = ((key * 4391) + 277) % 32779\n                    return key % 255\n                }\n\n                val decrypted = callback.data_?.map { Char(it.code xor next()) }?.toCharArray()?.concatToString()\n                if (DEBUG) Log.d(TAG, \"zzrp: $decrypted\")\n                val code = RecaptchaWebCode.ADAPTER.decode(Base64.decode(decrypted, Base64.URL_SAFE + Base64.NO_PADDING))\n                interpreter.execute(code)\n            }\n        }\n\n    }\n}"
  },
  {
    "path": "play-services-recaptcha/core/src/main/proto/recaptcha.proto",
    "content": "syntax = \"proto3\";\n\noption java_package = \"org.microg.gms.recaptcha\";\n\nmessage RecaptchaInitRequest {\n  message Data {\n    optional string siteKey = 1;\n    optional string packageName = 2;\n    optional string version = 3;\n  }\n  optional Data data = 2;\n}\n\nmessage RecaptchaInitResponse {\n  optional string token = 1;\n  repeated string acceptableAdditionalArgs = 3;\n}\n\nmessage RecaptchaExecuteRequest {\n  optional string token = 1;\n  optional string action = 2;\n  optional uint64 timestamp = 3;\n  optional string dg = 4;\n  map<string, string> additionalArgs = 5;\n  optional string verificationHistoryToken = 6;\n//  map<int32, bytes> unknown = 7;\n}\n\nmessage RecaptchaExecuteResponse {\n  optional string token = 1;\n}\n\nmessage RecaptchaWebEncryptedCallback {\n  optional string data = 1;\n  repeated int32 key = 2;\n}\n\nmessage RecaptchaWebInvokeMultiParameter {\n  repeated string args = 1;\n}\n\nmessage RecaptchaWebStatusCode {\n  optional int32 code = 1;\n}\n\nmessage RecaptchaWebResult {\n  optional string requestToken = 1;\n  optional string token = 2;\n  optional int32 code = 3;\n}\n\nmessage RecaptchaWebList {\n  message Value {\n    oneof typed {\n      bool bol = 1;\n      bytes bt = 2;\n      string chr = 3;\n      sint32 sht = 4;\n      sint32 i = 5;\n      sint64 l = 7;\n      float flt = 9;\n      double dbl = 10;\n      string str = 11;\n    }\n  }\n  repeated Value values = 1;\n}\n\nmessage RecaptchaWebCode {\n  message Arg {\n    oneof typed {\n      int32 index = 1;\n      bool bol = 2;\n      bytes bt = 3;\n      string chr = 4;\n      sint32 sht = 5;\n      sint32 i = 6;\n      sint64 l = 8;\n      float flt = 10;\n      double dbl = 11;\n      string str = 12;\n    }\n  }\n  message Op {\n    optional int32 code = 1;\n    optional int32 arg1 = 2;\n    repeated Arg args = 3;\n  }\n  repeated Op ops = 1;\n}"
  },
  {
    "path": "play-services-recaptcha/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2022, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<manifest />\n"
  },
  {
    "path": "play-services-recaptcha/src/main/aidl/com/google/android/gms/recaptcha/RecaptchaAction.aidl",
    "content": "package com.google.android.gms.recaptcha;\n\nparcelable RecaptchaAction;\n"
  },
  {
    "path": "play-services-recaptcha/src/main/aidl/com/google/android/gms/recaptcha/RecaptchaHandle.aidl",
    "content": "package com.google.android.gms.recaptcha;\n\nparcelable RecaptchaHandle;\n"
  },
  {
    "path": "play-services-recaptcha/src/main/aidl/com/google/android/gms/recaptcha/RecaptchaResultData.aidl",
    "content": "package com.google.android.gms.recaptcha;\n\nparcelable RecaptchaResultData;\n"
  },
  {
    "path": "play-services-recaptcha/src/main/aidl/com/google/android/gms/recaptcha/internal/ExecuteParams.aidl",
    "content": "package com.google.android.gms.recaptcha.internal;\n\nparcelable ExecuteParams;\n"
  },
  {
    "path": "play-services-recaptcha/src/main/aidl/com/google/android/gms/recaptcha/internal/ExecuteResults.aidl",
    "content": "package com.google.android.gms.recaptcha.internal;\n\nparcelable ExecuteResults;\n"
  },
  {
    "path": "play-services-recaptcha/src/main/aidl/com/google/android/gms/recaptcha/internal/ICloseCallback.aidl",
    "content": "package com.google.android.gms.recaptcha.internal;\n\nimport com.google.android.gms.common.api.Status;\n\ninterface ICloseCallback {\n    oneway void onClosed(in Status status, boolean closed) = 0;\n}\n"
  },
  {
    "path": "play-services-recaptcha/src/main/aidl/com/google/android/gms/recaptcha/internal/IExecuteCallback.aidl",
    "content": "package com.google.android.gms.recaptcha.internal;\n\nimport com.google.android.gms.common.api.Status;\n\nimport com.google.android.gms.recaptcha.RecaptchaResultData;\nimport com.google.android.gms.recaptcha.internal.ExecuteResults;\n\ninterface IExecuteCallback {\n    oneway void onData(in Status status, in RecaptchaResultData data) = 0;\n    oneway void onResults(in Status status, in ExecuteResults results) = 1;\n}\n"
  },
  {
    "path": "play-services-recaptcha/src/main/aidl/com/google/android/gms/recaptcha/internal/IInitCallback.aidl",
    "content": "package com.google.android.gms.recaptcha.internal;\n\nimport com.google.android.gms.common.api.Status;\n\nimport com.google.android.gms.recaptcha.RecaptchaHandle;\nimport com.google.android.gms.recaptcha.internal.InitResults;\n\ninterface IInitCallback {\n    oneway void onHandle(in Status status, in RecaptchaHandle handle) = 0;\n    oneway void onResults(in Status status, in InitResults results) = 1;\n}\n"
  },
  {
    "path": "play-services-recaptcha/src/main/aidl/com/google/android/gms/recaptcha/internal/IRecaptchaService.aidl",
    "content": "package com.google.android.gms.recaptcha.internal;\n\nimport com.google.android.gms.recaptcha.RecaptchaAction;\nimport com.google.android.gms.recaptcha.RecaptchaHandle;\n\nimport com.google.android.gms.recaptcha.internal.ExecuteParams;\nimport com.google.android.gms.recaptcha.internal.InitParams;\n\nimport com.google.android.gms.recaptcha.internal.ICloseCallback;\nimport com.google.android.gms.recaptcha.internal.IExecuteCallback;\nimport com.google.android.gms.recaptcha.internal.IInitCallback;\n\ninterface IRecaptchaService {\n    void verifyWithRecaptcha(IExecuteCallback callback, String siteKey, String packageName) = 0;\n    void init(IInitCallback callback, String siteKey) = 1;\n    void execute(IExecuteCallback callback, in RecaptchaHandle handle, in RecaptchaAction action) = 2;\n    void close(ICloseCallback callback, in RecaptchaHandle handle) = 3;\n    void init2(IInitCallback callback, in InitParams params) = 4;\n    void execute2(IExecuteCallback callback, in ExecuteParams params) = 5;\n}\n"
  },
  {
    "path": "play-services-recaptcha/src/main/aidl/com/google/android/gms/recaptcha/internal/InitParams.aidl",
    "content": "package com.google.android.gms.recaptcha.internal;\n\nparcelable InitParams;\n"
  },
  {
    "path": "play-services-recaptcha/src/main/aidl/com/google/android/gms/recaptcha/internal/InitResults.aidl",
    "content": "package com.google.android.gms.recaptcha.internal;\n\nparcelable InitResults;\n"
  },
  {
    "path": "play-services-recaptcha/src/main/java/com/google/android/gms/recaptcha/HttpStatusException.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.recaptcha;\n\n/**\n * Exception thrown when the server returns a non-200 response code.\n */\npublic class HttpStatusException extends Exception {\n    private int errorHttpStatus;\n\n    /**\n     * Constructs a {@link HttpStatusException} with the specified detail message and error code.\n     *\n     * @param msg             The detail message (which is saved for later retrieval by the {@link #getMessage()} method)\n     * @param errorHttpStatus The status code of the failed HTTP request.\n     */\n    public HttpStatusException(String msg, int errorHttpStatus) {\n        super(msg);\n        this.errorHttpStatus = errorHttpStatus;\n    }\n\n    /**\n     * Returns the status code of a failed HTTP request.\n     */\n    public int getHttpErrorStatus() {\n        return errorHttpStatus;\n    }\n}\n"
  },
  {
    "path": "play-services-recaptcha/src/main/java/com/google/android/gms/recaptcha/Recaptcha.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.recaptcha;\n\nimport android.app.Activity;\nimport android.content.Context;\n\nimport org.microg.gms.recaptcha.RecaptchaClientImpl;\n\n/**\n * The reCAPTCHA API provides access to Google Cloud services that help you protect your app from spam and other\n * abusive actions.\n * <p>\n * To instantiate a reCAPTCHA mobile client, call {@link #getClient(Context)} or {@link #getClient(Activity)}.\n */\npublic class Recaptcha {\n\n    /**\n     * Returns a {@link RecaptchaClient} that is used to access all APIs that are called when the app has a foreground\n     * {@link Activity}.\n     * <p>\n     * Use this method over {@link #getClient(Context)} to improve performance if you plan to make multiple API calls\n     * from your application's foreground {@link Activity}.\n     */\n    public static RecaptchaClient getClient(Activity activity) {\n        return new RecaptchaClientImpl(activity);\n    }\n\n    /**\n     * Returns a {@link RecaptchaClient} that is used to access all APIs that are called without access to a foreground\n     * {@link Activity}.\n     */\n    public static RecaptchaClient getClient(Context context) {\n        return new RecaptchaClientImpl(context);\n    }\n}\n"
  },
  {
    "path": "play-services-recaptcha/src/main/java/com/google/android/gms/recaptcha/RecaptchaAction.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.recaptcha;\n\nimport android.os.Bundle;\n\nimport androidx.annotation.NonNull;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n/**\n * Actions (e.g., login) intended to be protected by reCAPTCHA. An instance of this object should be passed to\n * {@link RecaptchaClient#execute(RecaptchaHandle, RecaptchaAction)}.\n */\npublic class RecaptchaAction extends AutoSafeParcelable {\n    @Field(1)\n    private RecaptchaActionType action;\n    @Field(2)\n    private String customAction;\n    @Field(3)\n    private Bundle additionalArgs;\n    @Field(4)\n    private String verificationHistoryToken;\n\n    private RecaptchaAction() {\n    }\n\n    /**\n     * Creates a {@link RecaptchaAction} instance with a predefined reCAPTCHA action.\n     */\n    public RecaptchaAction(RecaptchaActionType action) {\n        this(action, Bundle.EMPTY);\n    }\n\n    /**\n     * Creates a {@link RecaptchaAction} instance with a predefined reCAPTCHA action and additional arguments.\n     */\n    public RecaptchaAction(RecaptchaActionType action, Bundle additionalArgs) {\n        this.action = action;\n        this.additionalArgs = additionalArgs;\n    }\n\n    /**\n     * Creates a {@link RecaptchaAction} instance with a custom action String.\n     */\n    public RecaptchaAction(String customAction) {\n        this(customAction, Bundle.EMPTY);\n    }\n\n    /**\n     * Creates a {@link RecaptchaAction} instance with a custom action in the form of a String and additional arguments.\n     */\n    public RecaptchaAction(String customAction, Bundle additionalArgs) {\n        this.action = new RecaptchaActionType(RecaptchaActionType.OTHER);\n        this.customAction = customAction;\n        this.additionalArgs = additionalArgs;\n    }\n\n    /**\n     * Gets {@code RecaptchaActionType}.\n     */\n    public RecaptchaActionType getAction() {\n        return action;\n    }\n\n    /**\n     * Gets the additional arg map specified by this action.\n     */\n    public Bundle getAdditionalArgs() {\n        return additionalArgs;\n    }\n\n    /**\n     * Gets custom action that user inputs.\n     */\n    public String getCustomAction() {\n        return customAction;\n    }\n\n    /**\n     * Gets the verification history token specified by this action.\n     */\n    public String getVerificationHistoryToken() {\n        return verificationHistoryToken;\n    }\n\n    /**\n     * Gets the String value of {@code RecaptchaAction}.\n     */\n    @NonNull\n    @Override\n    public String toString() {\n        if (RecaptchaActionType.OTHER.equals(action.name) && customAction != null) {\n            return customAction;\n        } else {\n            return action.name;\n        }\n    }\n\n    public static final Creator<RecaptchaAction> CREATOR = new AutoCreator<>(RecaptchaAction.class);\n}\n"
  },
  {
    "path": "play-services-recaptcha/src/main/java/com/google/android/gms/recaptcha/RecaptchaActionType.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.recaptcha;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n/**\n * Collection of predefined actions used by RecaptchaHandle.\n */\npublic class RecaptchaActionType extends AutoSafeParcelable {\n    @Field(1)\n    String name;\n\n    private RecaptchaActionType() {}\n\n    public RecaptchaActionType(String action) {\n        this.name = action;\n    }\n\n    public static final Creator<RecaptchaActionType> CREATOR = new AutoCreator<>(RecaptchaActionType.class);\n\n    /**\n     * User interaction that needs to be verified while the user is performing the workflow you would like to protect.\n     */\n    public @interface Action {}\n\n    /**\n     * Indicates that the protected action is a login workflow.\n     */\n    public static final String LOGIN = \"login\";\n    /**\n     * When a custom action is specified, reCAPTCHA uses this value automatically.\n     */\n    public static final String OTHER = \"other\";\n    /**\n     * Indicates that the protected action is a signup workflow.\n     */\n    public static final String SIGNUP = \"signup\";\n}\n"
  },
  {
    "path": "play-services-recaptcha/src/main/java/com/google/android/gms/recaptcha/RecaptchaClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.recaptcha;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.tasks.Task;\n\n/**\n * The main entry point for interacting with the reCAPTCHA API.\n */\npublic interface RecaptchaClient {\n    /**\n     * Sends a challenge to an account in order to verify the identity of the user.\n     * <p>\n     * This method can be optionally called if you decide to perform a two factor authentication check on an account.\n     *\n     * @param recaptchaHandle       RecaptchaHandle initialized through {@link #init(String)}.\n     * @param challengeRequestToken The challenge request token obtained through CreateAssessment().\n     * @return A VerificationHandle that can be used with {@link #verifyAccount(String, VerificationHandle)} calls. A\n     * handle is usually valid for a specific time after creation. If an expired handle is returned, meaning the\n     * operation was aborted, {@link VerificationHandle#getOperationAbortedToken()} will return a token that can be\n     * used with the reCAPTCHA Enterprise API CreateAssessment() to get more details.\n     */\n    Task<VerificationHandle> challengeAccount(RecaptchaHandle recaptchaHandle, String challengeRequestToken);\n\n    /**\n     * Closes the initialized RecaptchaHandle.\n     * <p>\n     * Closes the handle if you will not be using it again to save resources.\n     *\n     * @param handle RecaptchaHandle initialized through {@link #init(String)}.\n     * @return true if the handle got closed successfully for the first time, false if there wasn't anything to close\n     * (e.g., the handle was already previously closed).\n     */\n    Task<Boolean> close(RecaptchaHandle handle);\n\n    /**\n     * Returns a score indicating how likely the action was triggered by a real user. A score close to 0 indicates a likely bot, and a score close to 1 indicates a likely human.\n     * <p>\n     * This method should be called every time there is an action to be protected.\n     *\n     * @param handle {@link RecaptchaHandle} initialized through {@link #init(String)}.\n     * @param action User interaction that needs to be protected.\n     */\n    Task<RecaptchaResultData> execute(RecaptchaHandle handle, RecaptchaAction action);\n\n    /**\n     * Prepares and initializes a RecaptchaHandle.\n     *\n     * @param siteKey A site key registered for this app\n     */\n    Task<RecaptchaHandle> init(String siteKey);\n\n    /**\n     * Verifies a PIN against a verification handle obtained through a\n     * {@link #challengeAccount(RecaptchaHandle, String)} call.\n     * <p>\n     * The method should be called to verify a PIN submitted by the user. The returned {@link VerificationResult} will\n     * contain a Status and either a {@link VerificationHandle} or a new reCAPTCHA token.\n     *\n     * @param pin                The fixed-length numerical PIN entered by the user. If a PIN with unexpected length or\n     *                           non numerical characters is entered, a\n     *                           {@link RecaptchaStatusCodes#RECAPTCHA_2FA_INVALID_PIN} error will be returned.\n     * @param verificationHandle A verification handle containing information required to preform the verification\n     *                           operation.\n     * @return A {@link VerificationResult} containing a {@link Status} indicating the status of the of the verification.\n     */\n    Task<VerificationResult> verifyAccount(String pin, VerificationHandle verificationHandle);\n}\n"
  },
  {
    "path": "play-services-recaptcha/src/main/java/com/google/android/gms/recaptcha/RecaptchaHandle.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.recaptcha;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\nimport java.util.Collections;\nimport java.util.List;\n\n/**\n * Information pertaining to reCAPTCHA handle, which is used to identify the initialized reCAPTCHA service.\n */\npublic class RecaptchaHandle extends AutoSafeParcelable {\n    @Field(1)\n    private String siteKey;\n    @Field(2)\n    private String clientPackageName;\n    @Field(3)\n    private List<String> acceptableAdditionalArgs;\n\n    @PublicApi(exclude = true)\n    private RecaptchaHandle() {\n    }\n\n    @PublicApi(exclude = true)\n    public RecaptchaHandle(String siteKey, String clientPackageName, List<String> acceptableAdditionalArgs) {\n        this.siteKey = siteKey;\n        this.clientPackageName = clientPackageName;\n        this.acceptableAdditionalArgs = acceptableAdditionalArgs;\n    }\n\n    /**\n     * Returns a list of strings indicating the additional argument keys that reCAPTCHA server accepts.\n     */\n    public List<String> getAcceptableAdditionalArgs() {\n        return Collections.unmodifiableList(acceptableAdditionalArgs);\n    }\n\n    /**\n     * Returns the package name of the app that calls reCAPTCHA API.\n     */\n    public String getClientPackageName() {\n        return clientPackageName;\n    }\n\n    /**\n     * Returns the reCAPTCHA Site Key you registered to help protect your application.\n     */\n    public String getSiteKey() {\n        return siteKey;\n    }\n\n    public static final Creator<RecaptchaHandle> CREATOR = new AutoCreator<>(RecaptchaHandle.class);\n}\n"
  },
  {
    "path": "play-services-recaptcha/src/main/java/com/google/android/gms/recaptcha/RecaptchaNetworkException.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.recaptcha;\n\nimport java.io.IOException;\n\n/**\n * Exception thrown when the mobile client fails to connect to the reCAPTCHA server.\n */\npublic class RecaptchaNetworkException extends Exception {\n    /**\n     * Constructs a {@link RecaptchaNetworkException} with the specified detail message and {@link IOException}.\n     *\n     * @param msg The detail message (which is saved for later retrieval by the {@link #getMessage()} method)\n     * @param e   The root {@link IOException} that causes the {@link RecaptchaNetworkException}.\n     */\n    public RecaptchaNetworkException(String msg, IOException e) {\n        super(msg, e);\n    }\n}\n"
  },
  {
    "path": "play-services-recaptcha/src/main/java/com/google/android/gms/recaptcha/RecaptchaOptionalObject.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.recaptcha;\n\n/**\n * Class for wrapping an optional object (i.e., an immutable object that may contain a non-null reference to another\n * object) to be used in {@link VerificationResult}.\n */\npublic class RecaptchaOptionalObject<T> {\n    private T object;\n\n    private RecaptchaOptionalObject(T object) {\n        this.object = object;\n    }\n\n    /**\n     * Returns a {@link RecaptchaOptionalObject} wrapping the specified object, which can be {@code null}.\n     */\n    public static <T> RecaptchaOptionalObject<T> ofNullable(T object) {\n        return new RecaptchaOptionalObject<>(object);\n    }\n\n    /**\n     * Returns the wrapped object.\n     */\n    public T orNull() {\n        return object;\n    }\n}\n"
  },
  {
    "path": "play-services-recaptcha/src/main/java/com/google/android/gms/recaptcha/RecaptchaResultData.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.recaptcha;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n/**\n * Information pertaining to reCAPTCHA result data.\n */\npublic class RecaptchaResultData extends AutoSafeParcelable {\n    @Field(1)\n    private String tokenResult;\n\n    private RecaptchaResultData() {\n    }\n\n    public RecaptchaResultData(String token) {\n        this.tokenResult = token;\n    }\n\n    /**\n     * Returns a reCAPTCHA token.\n     */\n    public String getTokenResult() {\n        return tokenResult;\n    }\n\n    public static final Creator<RecaptchaResultData> CREATOR = new AutoCreator<>(RecaptchaResultData.class);\n}\n"
  },
  {
    "path": "play-services-recaptcha/src/main/java/com/google/android/gms/recaptcha/RecaptchaStatusCodes.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.recaptcha;\n\nimport com.google.android.gms.common.api.CommonStatusCodes;\n\n/**\n * Status codes for the reCAPTCHA API.\n */\npublic final class RecaptchaStatusCodes extends CommonStatusCodes {\n    /**\n     * reCAPTCHA feature is disabled.\n     * <p>\n     * Please check if you update Google Play Services on your phone to get our latest reCAPTCHA module code that\n     * matches to the API versions you used in the SDK in your app.\n     */\n    public static final int RECAPTCHA_FEATURE_OFF = 36004;\n    /**\n     * An internal error occurred during two factor authentication calls.\n     * <p>\n     * Please try again in a bit.\n     */\n    public static final int RECAPTCHA_2FA_UNKNOWN = 36005;\n    /**\n     * The challenge account request token has expired.\n     * <p>\n     * Please obtain another request token from the reCAPTCHA Enterprise server.\n     */\n    public static final int RECAPTCHA_2FA_CHALLENGE_EXPIRED = 36006;\n    /**\n     * The challenge account request token is invalid.\n     * <p>\n     * Please verify that you are using the correct token obtained from the reCAPTCHA Enterprise server.\n     */\n    public static final int RECAPTCHA_2FA_INVALID_REQUEST_TOKEN = 36007;\n    /**\n     * The verification PIN has invalid format.\n     * <p>\n     * Please verify that the input PIN is of the right length and only contain numerical characters.\n     */\n    public static final int RECAPTCHA_2FA_INVALID_PIN = 36008;\n    /**\n     * The verification PIN does not match the PIN sent to the challenged account.\n     * <p>\n     * Please try again using a new {@link VerificationHandle}.\n     */\n    public static final int RECAPTCHA_2FA_PIN_MISMATCH = 36009;\n    /**\n     * All allowed verification attempts are exhausted.\n     * <p>\n     * Please restart the verification workflow by calling\n     * {@link RecaptchaClient#execute(RecaptchaHandle, RecaptchaAction)} again to fetch a new reCAPTCHA token, for\n     * retrieving a new challenge token via reCAPTCHA Enterprise API CreateAssessment(), then calling\n     * {@link RecaptchaClient#challengeAccount(RecaptchaHandle, String)}.\n     */\n    public static final int RECAPTCHA_2FA_ATTEMPTS_EXHAUSTED = 36010;\n    /**\n     * The operation was aborted.\n     * <p>\n     * Please use the abortion token with the reCAPTCHA Enterprise server to obtain more information.\n     */\n    public static final int RECAPTCHA_2FA_ABORTED = 36014;\n}\n"
  },
  {
    "path": "play-services-recaptcha/src/main/java/com/google/android/gms/recaptcha/VerificationHandle.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.recaptcha;\n\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\n\n/**\n * Stores the information required to verify an account.\n * <p>\n * This object is only valid for a specific time after creation and it holds all the information needed to validate a\n * PIN using {@link RecaptchaClient#verifyAccount(String, VerificationHandle)}. If an expired handle is returned by\n * {@link RecaptchaClient#challengeAccount(RecaptchaHandle, String)}, then {@link #getOperationAbortedToken()} will\n * return a token that can be used with the reCAPTCHA Enterprise API CreateAssessment() to get more details.\n */\npublic abstract class VerificationHandle implements SafeParcelable {\n    /**\n     * Returns the length of the PIN code.\n     */\n    public abstract int getCodeLength();\n\n    /**\n     * Returns a reCAPTCHA token in the case {@link RecaptchaClient#challengeAccount(RecaptchaHandle, String)}\n     * operation was aborted and an expired {@link VerificationHandle} was returned, otherwise this returns an empty\n     * string. This can be used with the reCAPTCHA Enterprise API CreateAssessment() to retrieve more details.\n     */\n    public abstract String getOperationAbortedToken();\n\n    /**\n     * Returns the site public key you registered for using reCAPTCHA.\n     */\n    public abstract String getSiteKey();\n\n    /**\n     * Returns the validity duration of the object since its creation in minutes.\n     */\n    public abstract long getTimeoutMinutes();\n\n    /**\n     * Returns an encrypted version of the internal verification token that will be used in\n     * {@link RecaptchaClient#verifyAccount(String, VerificationHandle)} call.\n     */\n    public abstract String getVerificationToken();\n\n    /**\n     * Returns a boolean indicating if the {@link VerificationHandle} is valid for\n     * {@link RecaptchaClient#verifyAccount(String, VerificationHandle)} API calls. An invalid handle will cause\n     * {@link RecaptchaClient#verifyAccount(String, VerificationHandle)} calls to fail immediately.\n     */\n    public boolean isValid() {\n        throw new UnsupportedOperationException(\"Not yet implemented\");\n    }\n}\n"
  },
  {
    "path": "play-services-recaptcha/src/main/java/com/google/android/gms/recaptcha/VerificationResult.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.recaptcha;\n\nimport com.google.android.gms.common.api.CommonStatusCodes;\nimport com.google.android.gms.common.api.Status;\n\n/**\n * Immmutable object to hold the result of a verification operation.\n */\npublic abstract class VerificationResult {\n    /**\n     * Returns a status to provide more info on the result of the verification operation.\n     *\n     * @return {@link CommonStatusCodes#SUCCESS} or {@link RecaptchaStatusCodes#RECAPTCHA_2FA_ABORTED} status if the\n     * verification operation succeeded, and non-success status (e.g.\n     * {@link RecaptchaStatusCodes#RECAPTCHA_2FA_PIN_MISMATCH}) if the verification failed with more attempts\n     * available, i.e. user entered wrong pin.\n     */\n    public abstract Status getVerificationStatus();\n\n    /**\n     * Returns an optional containing the reCAPTCHA token if the verification operation was successful or aborted.\n     *\n     * @return the reCAPTCHA token if {@code getVerificationStatus().equals(CommonStatusCodes.SUCCESS)} or\n     * {@code getVerificationStatus().equals RecaptchaStatusCodes.RECAPTCHA_2FA_ABORTED)}, otherwise an empty\n     * {@link RecaptchaOptionalObject}.\n     */\n    public abstract RecaptchaOptionalObject<String> recaptchaToken();\n\n    /**\n     * Returns an optional containing a verification handle if the verification operation failed and the client is allowed to retry.\n     *\n     * @return a verification handle on a failure status, otherwise an empty {@link RecaptchaOptionalObject}.\n     */\n    public abstract RecaptchaOptionalObject<VerificationHandle> verificationHandle();\n}\n"
  },
  {
    "path": "play-services-recaptcha/src/main/java/com/google/android/gms/recaptcha/internal/ExecuteParams.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.recaptcha.internal;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.recaptcha.RecaptchaAction;\nimport com.google.android.gms.recaptcha.RecaptchaHandle;\n\nimport org.microg.gms.utils.ToStringHelper;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class ExecuteParams extends AutoSafeParcelable {\n    @Field(1)\n    public RecaptchaHandle handle;\n    @Field(2)\n    public RecaptchaAction action;\n    @Field(3)\n    public String version;\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"ExecuteParams\")\n                .field(\"handle\", handle)\n                .field(\"action\", action)\n                .field(\"version\", version)\n                .end();\n    }\n\n    public static final Creator<ExecuteParams> CREATOR = new AutoCreator<>(ExecuteParams.class);\n}\n"
  },
  {
    "path": "play-services-recaptcha/src/main/java/com/google/android/gms/recaptcha/internal/ExecuteResults.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.recaptcha.internal;\n\nimport com.google.android.gms.recaptcha.RecaptchaResultData;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class ExecuteResults extends AutoSafeParcelable {\n    @Field(1)\n    public RecaptchaResultData data;\n\n    public static final Creator<ExecuteResults> CREATOR = new AutoCreator<>(ExecuteResults.class);\n}\n"
  },
  {
    "path": "play-services-recaptcha/src/main/java/com/google/android/gms/recaptcha/internal/InitParams.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.recaptcha.internal;\n\nimport androidx.annotation.NonNull;\n\nimport org.microg.gms.utils.ToStringHelper;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class InitParams extends AutoSafeParcelable {\n    @Field(1)\n    public String siteKey;\n    @Field(2)\n    public String version;\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"InitParams\")\n                .field(\"siteKey\", siteKey)\n                .field(\"version\", version)\n                .end();\n    }\n\n    public static final Creator<InitParams> CREATOR = new AutoCreator<>(InitParams.class);\n}\n"
  },
  {
    "path": "play-services-recaptcha/src/main/java/com/google/android/gms/recaptcha/internal/InitResults.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.recaptcha.internal;\n\nimport com.google.android.gms.recaptcha.RecaptchaHandle;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class InitResults extends AutoSafeParcelable {\n    @Field(1)\n    public RecaptchaHandle handle;\n\n    public static final Creator<InitResults> CREATOR = new AutoCreator<>(InitResults.class);\n}\n"
  },
  {
    "path": "play-services-recaptcha/src/main/java/org/microg/gms/recaptcha/RecaptchaClientImpl.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.recaptcha;\n\nimport android.content.Context;\nimport android.os.RemoteException;\n\nimport android.util.Log;\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.GoogleApi;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.recaptcha.Recaptcha;\nimport com.google.android.gms.recaptcha.RecaptchaAction;\nimport com.google.android.gms.recaptcha.RecaptchaClient;\nimport com.google.android.gms.recaptcha.RecaptchaHandle;\nimport com.google.android.gms.recaptcha.RecaptchaResultData;\nimport com.google.android.gms.recaptcha.VerificationHandle;\nimport com.google.android.gms.recaptcha.VerificationResult;\nimport com.google.android.gms.recaptcha.internal.ExecuteParams;\nimport com.google.android.gms.recaptcha.internal.ExecuteResults;\nimport com.google.android.gms.recaptcha.internal.ICloseCallback;\nimport com.google.android.gms.recaptcha.internal.IExecuteCallback;\nimport com.google.android.gms.recaptcha.internal.IInitCallback;\nimport com.google.android.gms.recaptcha.internal.InitParams;\nimport com.google.android.gms.recaptcha.internal.InitResults;\nimport com.google.android.gms.tasks.Task;\nimport com.google.android.gms.tasks.Tasks;\n\nimport org.microg.gms.common.api.PendingGoogleApiCall;\nimport org.microg.gms.tasks.TaskImpl;\n\npublic class RecaptchaClientImpl extends GoogleApi<Api.ApiOptions.NoOptions> implements RecaptchaClient {\n    private int openHandles = 0;\n\n    public RecaptchaClientImpl(Context context) {\n        super(context, new Api<>((options, c, looper, clientSettings, callbacks, connectionFailedListener) -> new RecaptchaGmsClient(c, callbacks, connectionFailedListener)), Api.ApiOptions.NO_OPTIONS);\n    }\n\n    @Override\n    public Task<VerificationHandle> challengeAccount(RecaptchaHandle recaptchaHandle, String challengeRequestToken) {\n        return Tasks.forException(new UnsupportedOperationException());\n    }\n\n    @Override\n    public Task<Boolean> close(RecaptchaHandle handle) {\n        return scheduleTask((PendingGoogleApiCall<Boolean, RecaptchaGmsClient>) (client, completionSource) -> {\n            client.close(new ICloseCallback.Stub() {\n                @Override\n                public void onClosed(Status status, boolean closed) throws RemoteException {\n                    if (status.isSuccess()) {\n                        completionSource.trySetResult(closed);\n                    } else {\n                        completionSource.trySetException(new RuntimeException(status.getStatusMessage()));\n                    }\n                    if (openHandles == 0) {\n                        Log.w(\"RecaptchaClient\", \"Can't mark handle closed if none is open\");\n                        return;\n                    }\n                    openHandles--;\n                    if (openHandles == 0) client.disconnect();\n                }\n            }, handle);\n        });\n    }\n\n    @Override\n    public Task<RecaptchaResultData> execute(RecaptchaHandle handle, RecaptchaAction action) {\n        return scheduleTask((PendingGoogleApiCall<RecaptchaResultData, RecaptchaGmsClient>) (client, completionSource) -> {\n            ExecuteParams params = new ExecuteParams();\n            params.handle = handle;\n            params.action = action;\n            params.version = \"18.1.1\";\n            client.execute(new IExecuteCallback.Stub() {\n                @Override\n                public void onData(Status status, RecaptchaResultData data) throws RemoteException {\n                    if (status.isSuccess()) {\n                        completionSource.trySetResult(data);\n                    } else {\n                        completionSource.trySetException(new RuntimeException(status.getStatusMessage()));\n                    }\n                }\n\n                @Override\n                public void onResults(Status status, ExecuteResults results) throws RemoteException {\n                    if (status.isSuccess()) {\n                        completionSource.trySetResult(results.data);\n                    } else {\n                        completionSource.trySetException(new RuntimeException(status.getStatusMessage()));\n                    }\n                }\n            }, params);\n        });\n    }\n\n    @Override\n    public Task<RecaptchaHandle> init(String siteKey) {\n        openHandles++;\n        return scheduleTask((PendingGoogleApiCall<RecaptchaHandle, RecaptchaGmsClient>) (client, completionSource) -> {\n            InitParams params = new InitParams();\n            params.siteKey = siteKey;\n            params.version = \"18.1.1\";\n            client.init(new IInitCallback.Stub() {\n                @Override\n                public void onHandle(Status status, RecaptchaHandle handle) throws RemoteException {\n                    if (status.isSuccess()) {\n                        completionSource.trySetResult(handle);\n                    } else {\n                        completionSource.trySetException(new RuntimeException(status.getStatusMessage()));\n                    }\n                }\n\n                @Override\n                public void onResults(Status status, InitResults results) throws RemoteException {\n                    if (status.isSuccess()) {\n                        completionSource.trySetResult(results.handle);\n                    } else {\n                        completionSource.trySetException(new RuntimeException(status.getStatusMessage()));\n                    }\n                }\n            }, params);\n        });\n    }\n\n    @Override\n    public Task<VerificationResult> verifyAccount(String pin, VerificationHandle verificationHandle) {\n        return Tasks.forException(new UnsupportedOperationException());\n    }\n}\n"
  },
  {
    "path": "play-services-recaptcha/src/main/java/org/microg/gms/recaptcha/RecaptchaGmsClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.recaptcha;\n\nimport android.content.Context;\nimport android.os.IBinder;\nimport android.os.RemoteException;\n\nimport org.microg.gms.common.GmsClient;\nimport org.microg.gms.common.GmsService;\nimport com.google.android.gms.common.api.internal.ConnectionCallbacks;\nimport com.google.android.gms.common.api.internal.OnConnectionFailedListener;\n\nimport com.google.android.gms.recaptcha.RecaptchaAction;\nimport com.google.android.gms.recaptcha.RecaptchaHandle;\nimport com.google.android.gms.recaptcha.internal.ExecuteParams;\nimport com.google.android.gms.recaptcha.internal.ICloseCallback;\nimport com.google.android.gms.recaptcha.internal.IExecuteCallback;\nimport com.google.android.gms.recaptcha.internal.IInitCallback;\nimport com.google.android.gms.recaptcha.internal.IRecaptchaService;\nimport com.google.android.gms.recaptcha.internal.InitParams;\n\npublic class RecaptchaGmsClient extends GmsClient<IRecaptchaService> {\n    public RecaptchaGmsClient(Context context, ConnectionCallbacks callbacks, OnConnectionFailedListener connectionFailedListener) {\n        super(context, callbacks, connectionFailedListener, GmsService.RECAPTCHA.ACTION);\n        serviceId = GmsService.RECAPTCHA.SERVICE_ID;\n    }\n\n    public void init(IInitCallback callback, String siteKey) throws RemoteException {\n        getServiceInterface().init(callback, siteKey);\n    }\n\n    public void init(IInitCallback callback, InitParams params) throws RemoteException {\n        getServiceInterface().init2(callback, params);\n    }\n\n    public void execute(IExecuteCallback callback, RecaptchaHandle handle, RecaptchaAction action) throws RemoteException {\n        getServiceInterface().execute(callback, handle, action);\n    }\n\n    public void execute(IExecuteCallback callback, ExecuteParams params) throws RemoteException {\n        getServiceInterface().execute2(callback, params);\n    }\n\n    public void close(ICloseCallback callback, RecaptchaHandle handle) throws RemoteException {\n        getServiceInterface().close(callback, handle);\n    }\n\n    @Override\n    protected IRecaptchaService interfaceFromBinder(IBinder binder) {\n        return IRecaptchaService.Stub.asInterface(binder);\n    }\n}\n"
  },
  {
    "path": "play-services-safetynet/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\nandroid {\n    namespace \"com.google.android.gms.safetynet\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n}\n\napply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG implementation of play-services-safetynet'\n\ndependencies {\n    // Dependencies from play-services-safetynet:18.0.1\n    api project(':play-services-base')\n    api project(':play-services-basement')\n    api project(':play-services-tasks')\n}\n"
  },
  {
    "path": "play-services-safetynet/core/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2021 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'com.squareup.wire'\napply plugin: 'kotlin-android'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\ndependencies {\n    api project(':play-services-safetynet')\n\n    implementation project(':play-services-base-core')\n    implementation project(':play-services-droidguard')\n    implementation project(':play-services-droidguard-core')\n    implementation project(':play-services-tasks-ktx')\n\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion\"\n    implementation \"org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutineVersion\"\n    implementation \"org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutineVersion\"\n\n    implementation \"androidx.appcompat:appcompat:$appcompatVersion\"\n    implementation \"androidx.core:core-ktx:$coreVersion\"\n    implementation \"androidx.lifecycle:lifecycle-runtime-ktx:$lifecycleVersion\"\n    implementation \"androidx.lifecycle:lifecycle-service:$lifecycleVersion\"\n    implementation \"androidx.webkit:webkit:$webkitVersion\"\n\n    implementation \"com.android.volley:volley:$volleyVersion\"\n    implementation \"com.squareup.wire:wire-runtime:$wireVersion\"\n}\n\nwire {\n    kotlin {\n        javaInterop = true\n    }\n}\n\nandroid {\n    namespace \"org.microg.gms.safetynet.core\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    sourceSets {\n        main.java.srcDirs += 'src/main/kotlin'\n    }\n\n    lintOptions {\n        disable 'MissingTranslation'\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n\n    kotlinOptions {\n        jvmTarget = 1.8\n    }\n}\n\napply from: '../../gradle/publish-android.gradle'\n\ndescription = 'microG service implementation for play-services-safetynet'\n"
  },
  {
    "path": "play-services-safetynet/core/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2021 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <application>\n        <service android:name=\"org.microg.gms.safetynet.SafetyNetClientService\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.safetynet.service.START\" />\n            </intent-filter>\n        </service>\n        <activity\n            android:name=\"org.microg.gms.safetynet.ReCaptchaActivity\"\n            android:autoRemoveFromRecents=\"true\"\n            android:icon=\"@drawable/ic_recaptcha\"\n            android:process=\":ui\"\n            android:exported=\"false\"\n            android:theme=\"@style/Theme.AppCompat.Light.Dialog.NoActionBar\">\n            <intent-filter>\n                <action android:name=\"org.microg.gms.safetynet.RECAPTCHA_ACTIVITY\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </activity>\n    </application>\n</manifest>\n"
  },
  {
    "path": "play-services-safetynet/core/src/main/java/org/microg/gms/safetynet/Attestation.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2021 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.safetynet;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.content.pm.Signature;\nimport android.util.Base64;\nimport android.util.Log;\n\nimport org.microg.gms.common.Constants;\nimport org.microg.gms.common.PackageUtils;\nimport org.microg.gms.common.Utils;\nimport org.microg.gms.profile.Build;\nimport org.microg.gms.profile.ProfileManager;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.net.HttpURLConnection;\nimport java.net.URL;\nimport java.nio.ByteBuffer;\nimport java.nio.CharBuffer;\nimport java.nio.charset.Charset;\nimport java.nio.charset.CharsetDecoder;\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.zip.GZIPInputStream;\n\nimport okio.ByteString;\n\npublic class Attestation {\n    private static final String TAG = \"GmsSafetyNetAttest\";\n\n    private Context context;\n    private String packageName;\n    private byte[] payload;\n    private String droidGuardResult;\n\n    public Attestation(Context context, String packageName) {\n        this.context = context;\n        this.packageName = packageName;\n    }\n\n    public void setPayload(byte[] payload) {\n        this.payload = payload;\n    }\n\n    public SafetyNetData buildPayload(byte[] nonce) {\n        this.droidGuardResult = null;\n        SafetyNetData payload = new SafetyNetData.Builder()\n                .nonce(ByteString.of(nonce))\n                .currentTimeMs(System.currentTimeMillis())\n                .packageName(packageName)\n                .fileDigest(getPackageFileDigest())\n                .signatureDigest(getPackageSignatures())\n                .gmsVersionCode(Constants.GMS_VERSION_CODE)\n                //.googleCn(false)\n                .seLinuxState(new SELinuxState.Builder().enabled(true).supported(true).build())\n                .suCandidates(Collections.<FileState>emptyList())\n                .build();\n        Log.d(TAG, \"Payload: \"+payload.toString());\n        this.payload = payload.encode();\n        return payload;\n    }\n\n    public byte[] getPayload() {\n        return payload;\n    }\n\n    public String getPayloadHashBase64() {\n        try {\n            MessageDigest digest = getSha256Digest();\n            return Base64.encodeToString(digest.digest(payload), Base64.NO_WRAP);\n        } catch (NoSuchAlgorithmException e) {\n            Log.w(TAG, e);\n            return null;\n        }\n    }\n\n    private static MessageDigest getSha256Digest() throws NoSuchAlgorithmException {\n        return MessageDigest.getInstance(\"SHA-256\");\n    }\n\n    public void setDroidGuardResult(String droidGuardResult) {\n        this.droidGuardResult = droidGuardResult;\n    }\n\n    private ByteString getPackageFileDigest() {\n        try {\n            return ByteString.of(getPackageFileDigest(context, packageName));\n        } catch (Exception e) {\n            Log.w(TAG, e);\n            return null;\n        }\n    }\n\n    public static byte[] getPackageFileDigest(Context context, String packageName) throws Exception {\n        FileInputStream is = new FileInputStream(new File(context.getPackageManager().getApplicationInfo(packageName, 0).sourceDir));\n        MessageDigest digest = getSha256Digest();\n        byte[] data = new byte[4096];\n        while (true) {\n            int read = is.read(data);\n            if (read < 0) break;\n            digest.update(data, 0, read);\n        }\n        is.close();\n        return digest.digest();\n    }\n\n    @SuppressLint(\"PackageManagerGetSignatures\")\n    private List<ByteString> getPackageSignatures() {\n        try {\n            ArrayList<ByteString> res = new ArrayList<>();\n            for (byte[] bytes : getPackageSignatures(context, packageName)) {\n                res.add(ByteString.of(bytes));\n            }\n            return res;\n        } catch (Exception e) {\n            Log.w(TAG, e);\n            return null;\n        }\n    }\n\n    public static byte[][] getPackageSignatures(Context context, String packageName) throws Exception {\n        PackageInfo pi = context.getPackageManager().getPackageInfo(packageName, PackageManager.GET_SIGNATURES);\n        ArrayList<byte[]> res = new ArrayList<>();\n        MessageDigest digest = getSha256Digest();\n        for (Signature signature : pi.signatures) {\n            res.add(digest.digest(signature.toByteArray()));\n        }\n        return res.toArray(new byte[][]{});\n    }\n\n    public String attest(String apiKey) throws IOException {\n        if (payload == null) {\n            throw new IllegalStateException(\"missing payload\");\n        }\n        return attest(new AttestRequest.Builder().safetyNetData(ByteString.of(payload)).droidGuardResult(droidGuardResult).build(), apiKey).result;\n    }\n\n    private AttestResponse attest(AttestRequest request, String apiKey) throws IOException {\n        ProfileManager.ensureInitialized(context);\n        String requestUrl = \"https://www.googleapis.com/androidcheck/v1/attestations/attest?alt=PROTO&key=\" + apiKey;\n        HttpURLConnection connection = (HttpURLConnection) new URL(requestUrl).openConnection();\n        connection.setRequestMethod(\"POST\");\n        connection.setDoInput(true);\n        connection.setDoOutput(true);\n        connection.setRequestProperty(\"content-type\", \"application/x-protobuf\");\n        connection.setRequestProperty(\"Accept-Encoding\", \"gzip\");\n        connection.setRequestProperty(\"X-Android-Package\", packageName);\n        connection.setRequestProperty(\"X-Android-Cert\", PackageUtils.firstSignatureDigest(context, packageName));\n        connection.setRequestProperty(\"User-Agent\", \"SafetyNet/\" + Constants.GMS_VERSION_CODE + \" (\" + Build.DEVICE + \" \" + Build.ID + \"); gzip\");\n\n        OutputStream os = connection.getOutputStream();\n        os.write(request.encode());\n        os.close();\n\n        if (connection.getResponseCode() != 200) {\n            byte[] bytes = null;\n            String ex = null;\n            try {\n                bytes = Utils.readStreamToEnd(connection.getErrorStream());\n                ex = new String(Utils.readStreamToEnd(new GZIPInputStream(new ByteArrayInputStream(bytes))));\n            } catch (Exception e) {\n                if (bytes != null) {\n                    throw new IOException(getBytesAsString(bytes), e);\n                }\n                throw new IOException(connection.getResponseMessage(), e);\n            }\n            throw new IOException(ex);\n        }\n\n        InputStream is = connection.getInputStream();\n        byte[] bytes = Utils.readStreamToEnd(new GZIPInputStream(is));\n        try {\n            return AttestResponse.ADAPTER.decode(bytes);\n        } catch (IOException e) {\n            Log.d(TAG, Base64.encodeToString(bytes, 0));\n            throw e;\n        }\n    }\n\n\n    private String getBytesAsString(byte[] bytes) {\n        if (bytes == null) return \"null\";\n        try {\n            CharsetDecoder d = Charset.forName(\"US-ASCII\").newDecoder();\n            CharBuffer r = d.decode(ByteBuffer.wrap(bytes));\n            return r.toString();\n        } catch (Exception e) {\n            return Base64.encodeToString(bytes, Base64.NO_WRAP);\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-safetynet/core/src/main/kotlin/org/microg/gms/safetynet/ReCaptchaActivity.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2021 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.safetynet\n\nimport android.annotation.SuppressLint\nimport android.content.Intent\nimport android.net.Uri\nimport android.net.http.SslCertificate\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.Bundle\nimport android.os.ResultReceiver\nimport android.util.Base64\nimport android.util.Log\nimport android.view.View\nimport android.view.Window\nimport android.webkit.*\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.lifecycle.lifecycleScope\nimport androidx.webkit.WebViewClientCompat\nimport com.google.android.gms.droidguard.DroidGuardClient\nimport com.google.android.gms.safetynet.SafetyNetStatusCodes.*\nimport com.google.android.gms.tasks.await\nimport org.microg.gms.profile.Build\nimport org.microg.gms.profile.ProfileManager\nimport org.microg.gms.safetynet.core.R\nimport java.io.ByteArrayInputStream\nimport java.net.URLEncoder\nimport java.security.MessageDigest\nimport kotlin.math.min\n\nprivate const val TAG = \"GmsReCAPTCHA\"\n\nprivate fun StringBuilder.appendUrlEncodedParam(key: String, value: String?) = append(\"&\")\n        .append(URLEncoder.encode(key, \"UTF-8\"))\n        .append(\"=\")\n        .append(value?.let { URLEncoder.encode(it, \"UTF-8\") } ?: \"\")\n\nclass ReCaptchaActivity : AppCompatActivity() {\n    private val receiver: ResultReceiver?\n        get() = intent?.getParcelableExtra(\"result\") as ResultReceiver?\n    private val params: String?\n        get() = intent?.getStringExtra(\"params\")\n    private val webView: WebView?\n        get() = findViewById(R.id.recaptcha_webview)\n    private val loading: View?\n        get() = findViewById(R.id.recaptcha_loading)\n    private val density: Float\n        get() = resources.displayMetrics.density\n    private val widthPixels: Int\n        get() = resources.displayMetrics.widthPixels\n    private val heightPixels: Int\n        get() {\n            val base = resources.displayMetrics.heightPixels\n            val statusBarHeightId = resources.getIdentifier(\"status_bar_height\", \"dimen\", \"android\")\n            val statusBarHeight = if (statusBarHeightId > 0) resources.getDimensionPixelSize(statusBarHeightId) else 0\n            return base - statusBarHeight - (density * 20.0).toInt()\n        }\n    private var resultSent: Boolean = false\n\n    @SuppressLint(\"SetJavaScriptEnabled\", \"AddJavascriptInterface\")\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        if (receiver == null || params == null) {\n            finish()\n            return\n        }\n        requestWindowFeature(Window.FEATURE_NO_TITLE)\n        setContentView(R.layout.recaptcha_window)\n        webView?.apply {\n            webViewClient = object : WebViewClientCompat() {\n                fun String.isRecaptchaUrl() = startsWith(\"https://www.gstatic.com/recaptcha/\") || startsWith(\"https://www.google.com/recaptcha/\") || startsWith(\"https://www.google.com/js/bg/\")\n\n                override fun shouldInterceptRequest(view: WebView, url: String): WebResourceResponse? {\n                    if (url.isRecaptchaUrl()) {\n                        return null\n                    }\n                    return WebResourceResponse(\"text/plain\", \"UTF-8\", ByteArrayInputStream(byteArrayOf()))\n                }\n\n                override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {\n                    if (url.startsWith(\"https://support.google.com/recaptcha\")) {\n                        startActivity(Intent(\"android.intent.action.VIEW\", Uri.parse(url)))\n                        finish()\n                        return true\n                    }\n                    return !url.isRecaptchaUrl()\n                }\n            }\n            settings.apply {\n                javaScriptEnabled = true\n                useWideViewPort = true\n                displayZoomControls = false\n                setSupportZoom(false)\n                cacheMode = WebSettings.LOAD_NO_CACHE\n                ProfileManager.ensureInitialized(this@ReCaptchaActivity)\n                userAgentString = Build.generateWebViewUserAgentString(userAgentString)\n            }\n            addJavascriptInterface(ReCaptchaEmbedder(this@ReCaptchaActivity), \"RecaptchaEmbedder\")\n        }\n        lifecycleScope.launchWhenResumed {\n            open()\n        }\n    }\n\n    fun sendErrorResult(errorCode: Int, error: String) = sendResult(errorCode) { putString(\"error\", error); putInt(\"errorCode\", errorCode) }\n\n    fun sendResult(resultCode: Int, v: Bundle.() -> Unit) {\n        receiver?.send(resultCode, Bundle().also(v))\n        resultSent = true\n    }\n\n    override fun finish() {\n        lifecycleScope.launchWhenResumed {\n            webView?.loadUrl(\"javascript: RecaptchaMFrame.shown(0, 0, false);\")\n        }\n        if (!resultSent) {\n            sendErrorResult(CANCELED, \"Cancelled\")\n        }\n        super.finish()\n    }\n\n    fun setWebViewSize(width: Int, height: Int, visible: Boolean) {\n        webView?.apply {\n            layoutParams.width = min(widthPixels, (width * density).toInt())\n            layoutParams.height = min(heightPixels, (height * density).toInt())\n            requestLayout()\n            loadUrl(\"javascript: RecaptchaMFrame.shown(${(layoutParams.width / density).toInt()}, ${(layoutParams.height / density).toInt()}, $visible);\")\n        }\n    }\n\n    suspend fun updateToken(flow: String, params: String) {\n        val map = mapOf(\"contentBinding\" to Base64.encodeToString(MessageDigest.getInstance(\"SHA-256\").digest(params.toByteArray()), Base64.NO_WRAP))\n        val dg = try {\n            DroidGuardClient.getResults(this, flow, map).await()\n        } catch (e: Exception) {\n            Log.w(TAG, e)\n            Base64.encodeToString(\"ERROR : IOException\".toByteArray(), Base64.NO_WRAP + Base64.URL_SAFE + Base64.NO_PADDING)\n        }\n        if (SDK_INT >= 19) {\n            webView?.evaluateJavascript(\"RecaptchaMFrame.token('${URLEncoder.encode(dg, \"UTF-8\")}', '$params');\", null)\n        } else {\n            webView?.loadUrl(\"javascript: RecaptchaMFrame.token('${URLEncoder.encode(dg, \"UTF-8\")}', '$params');\")\n        }\n    }\n\n    suspend fun open() {\n        val params = StringBuilder(params).appendUrlEncodedParam(\"mt\", System.currentTimeMillis().toString()).toString()\n        val map = mapOf(\"contentBinding\" to Base64.encodeToString(MessageDigest.getInstance(\"SHA-256\").digest(params.toByteArray()), Base64.NO_WRAP))\n        val dg = try {\n            DroidGuardClient.getResults(this, \"recaptcha-android-frame\", map).await()\n        } catch (e: Exception) {\n            Log.w(TAG, e)\n            Base64.encodeToString(\"ERROR : IOException\".toByteArray(), Base64.NO_WRAP + Base64.URL_SAFE + Base64.NO_PADDING)\n        }\n        webView?.postUrl(MFRAME_URL, \"mav=1&dg=${URLEncoder.encode(dg, \"UTF-8\")}&mp=${URLEncoder.encode(params, \"UTF-8\")}\".toByteArray())\n    }\n\n    companion object {\n        private const val MFRAME_URL = \"https://www.google.com/recaptcha/api2/mframe\"\n\n        class ReCaptchaEmbedder(val activity: ReCaptchaActivity) {\n            @JavascriptInterface\n            fun challengeReady() {\n                Log.d(TAG, \"challengeReady()\")\n                activity.runOnUiThread { activity.webView?.loadUrl(\"javascript: RecaptchaMFrame.show(${min(activity.widthPixels / activity.density, 400f)}, ${min(activity.heightPixels / activity.density, 400f)});\") }\n            }\n\n            @JavascriptInterface\n            fun getClientAPIVersion() = 1\n\n            @JavascriptInterface\n            fun onChallengeExpired() {\n                Log.d(TAG, \"onChallengeExpired()\")\n            }\n\n            @JavascriptInterface\n            fun onError(errorCode: Int, finish: Boolean) {\n                Log.d(TAG, \"onError($errorCode, $finish)\")\n                when (errorCode) {\n                    1 -> activity.sendErrorResult(ERROR, \"Invalid Input Argument\")\n                    2 -> activity.sendErrorResult(TIMEOUT, \"Session Timeout\")\n                    7 -> activity.sendErrorResult(RECAPTCHA_INVALID_SITEKEY, \"Invalid Site Key\")\n                    8 -> activity.sendErrorResult(RECAPTCHA_INVALID_KEYTYPE, \"Invalid Type of Site Key\")\n                    9 -> activity.sendErrorResult(RECAPTCHA_INVALID_PACKAGE_NAME, \"Invalid Package Name for App\")\n                    else -> activity.sendErrorResult(ERROR, \"error\")\n                }\n                if (finish) activity.finish()\n            }\n\n            @JavascriptInterface\n            fun onResize(width: Int, height: Int) {\n                Log.d(TAG, \"onResize($width, $height)\")\n                if (activity.webView?.visibility == View.VISIBLE) {\n                    activity.runOnUiThread { activity.setWebViewSize(width, height, true) }\n                } else {\n                    activity.runOnUiThread { activity.webView?.loadUrl(\"javascript: RecaptchaMFrame.shown($width, $height, true);\") }\n                }\n            }\n\n            @JavascriptInterface\n            fun onShow(visible: Boolean, width: Int, height: Int) {\n                Log.d(TAG, \"onShow($visible, $width, $height)\")\n                if (width <= 0 && height <= 0) {\n                    activity.runOnUiThread { activity.webView?.loadUrl(\"javascript: RecaptchaMFrame.shown($width, $height, $visible);\") }\n                } else {\n                    activity.runOnUiThread {\n                        activity.setWebViewSize(width, height, visible)\n                        activity.loading?.visibility = if (visible) View.GONE else View.VISIBLE\n                        activity.webView?.visibility = if (visible) View.VISIBLE else View.GONE\n                    }\n                }\n            }\n\n            @JavascriptInterface\n            fun requestToken(s: String, b: Boolean) {\n                Log.d(TAG, \"requestToken($s, $b)\")\n                activity.runOnUiThread {\n                    val cert = activity.webView?.certificate?.let { Base64.encodeToString(SslCertificate.saveState(it).getByteArray(\"x509-certificate\"), Base64.URL_SAFE + Base64.NO_PADDING + Base64.NO_WRAP) }\n                        ?: \"\"\n                    val params = StringBuilder(activity.params).appendUrlEncodedParam(\"c\", s).appendUrlEncodedParam(\"sc\", cert).appendUrlEncodedParam(\"mt\", System.currentTimeMillis().toString()).toString()\n                    val flow = \"recaptcha-android-${if (b) \"verify\" else \"reload\"}\"\n                    activity.lifecycleScope.launchWhenResumed {\n                        activity.updateToken(flow, params)\n                    }\n                }\n            }\n\n            @JavascriptInterface\n            fun verifyCallback(token: String) {\n                Log.d(TAG, \"verifyCallback($token)\")\n                activity.sendResult(0) { putString(\"token\", token) }\n                activity.resultSent = true\n                activity.finish()\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-safetynet/core/src/main/kotlin/org/microg/gms/safetynet/SafetyNetClientService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2021 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage org.microg.gms.safetynet\n\nimport android.content.Context\nimport android.content.Intent\nimport android.database.Cursor\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.Bundle\nimport android.os.Parcel\nimport android.os.ResultReceiver\nimport android.util.Base64\nimport android.util.Log\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.LifecycleOwner\nimport androidx.lifecycle.lifecycleScope\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport com.google.android.gms.droidguard.DroidGuardClient\nimport com.google.android.gms.safetynet.AttestationData\nimport com.google.android.gms.safetynet.HarmfulAppsInfo\nimport com.google.android.gms.safetynet.RecaptchaResultData\nimport com.google.android.gms.safetynet.SafeBrowsingData\nimport com.google.android.gms.safetynet.SafetyNetStatusCodes\nimport com.google.android.gms.safetynet.internal.ISafetyNetCallbacks\nimport com.google.android.gms.safetynet.internal.ISafetyNetService\nimport com.google.android.gms.tasks.await\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.common.GooglePackagePermission\nimport org.microg.gms.common.PackageUtils\nimport org.microg.gms.droidguard.core.DroidGuardPreferences\nimport org.microg.gms.settings.SettingsContract\nimport org.microg.gms.settings.SettingsContract.CheckIn.getContentUri\nimport org.microg.gms.settings.SettingsContract.getSettings\nimport org.microg.gms.utils.warnOnTransactionIssues\nimport java.io.IOException\nimport java.net.URLEncoder\n\nprivate const val TAG = \"GmsSafetyNet\"\nprivate const val DEFAULT_API_KEY = \"AIzaSyDqVnJBjE5ymo--oBJt3On7HQx9xNm1RHA\"\n\nclass SafetyNetClientService : BaseService(TAG, GmsService.SAFETY_NET) {\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        callback.onPostInitComplete(0, SafetyNetClientServiceImpl(this, request.packageName, lifecycle), null)\n    }\n}\n\nprivate fun StringBuilder.appendUrlEncodedParam(key: String, value: String?) = append(\"&\")\n    .append(URLEncoder.encode(key, \"UTF-8\"))\n    .append(\"=\")\n    .append(value?.let { URLEncoder.encode(it, \"UTF-8\") } ?: \"\")\n\nclass SafetyNetClientServiceImpl(\n    private val context: Context,\n    private val packageName: String,\n    override val lifecycle: Lifecycle\n) : ISafetyNetService.Stub(), LifecycleOwner {\n\n    override fun attest(callbacks: ISafetyNetCallbacks, nonce: ByteArray) {\n        attestWithApiKey(callbacks, nonce, DEFAULT_API_KEY)\n    }\n\n    override fun attestWithApiKey(callbacks: ISafetyNetCallbacks, nonce: ByteArray?, apiKey: String) {\n        if (nonce == null) {\n            callbacks.onAttestationResult(Status(SafetyNetStatusCodes.DEVELOPER_ERROR, \"Nonce missing\"), null)\n            return\n        }\n\n        if (!SafetyNetPreferences.isEnabled(context)) {\n            Log.d(TAG, \"ignoring SafetyNet request, SafetyNet is disabled\")\n            callbacks.onAttestationResult(Status(SafetyNetStatusCodes.ERROR, \"Disabled\"), null)\n            return\n        }\n\n        if (!DroidGuardPreferences.isAvailable(context)) {\n            Log.d(TAG, \"ignoring SafetyNet request, DroidGuard is disabled\")\n            callbacks.onAttestationResult(Status(SafetyNetStatusCodes.ERROR, \"Unsupported\"), null)\n            return\n        }\n\n        lifecycleScope.launchWhenStarted {\n            val db = SafetyNetDatabase(context)\n            var requestID: Long = -1\n            try {\n                val attestation = Attestation(context, packageName)\n                val safetyNetData = attestation.buildPayload(nonce)\n\n                requestID = db.insertRecentRequestStart(\n                    SafetyNetRequestType.ATTESTATION,\n                    safetyNetData.packageName,\n                    safetyNetData.nonce?.toByteArray(),\n                    safetyNetData.currentTimeMs ?: 0\n                )\n\n                val data = mapOf(\"contentBinding\" to attestation.payloadHashBase64)\n                val dg = withContext(Dispatchers.IO) { DroidGuardClient.getResults(context, \"attest\", data).await() }\n                attestation.setDroidGuardResult(dg)\n                val jwsResult = withContext(Dispatchers.IO) { attestation.attest(apiKey) }\n\n\n                val jsonData = try {\n                    requireNotNull(jwsResult)\n                    jwsResult.split(\".\").let {\n                        assert(it.size == 3)\n                        return@let Base64.decode(it[1], Base64.URL_SAFE).decodeToString()\n                    }\n                } catch (e: Exception) {\n                    e.printStackTrace()\n                    Log.w(TAG, \"An exception occurred when parsing the JWS token.\")\n                    null\n                }\n\n                db.insertRecentRequestEnd(requestID, Status.SUCCESS, jsonData)\n                callbacks.onAttestationResult(Status.SUCCESS, AttestationData(jwsResult))\n            } catch (e: Exception) {\n                Log.w(TAG, \"Exception during attest: ${e.javaClass.name}\", e)\n                val code = when (e) {\n                    is IOException -> SafetyNetStatusCodes.NETWORK_ERROR\n                    else -> SafetyNetStatusCodes.ERROR\n                }\n                val status = Status(code, e.localizedMessage)\n\n                // This shouldn't happen, but do not update the database if it didn't insert the start of the request\n                if (requestID != -1L) db.insertRecentRequestEnd(requestID, status, null)\n                try {\n                    callbacks.onAttestationResult(Status(code, e.localizedMessage), null)\n                } catch (e: Exception) {\n                    Log.w(TAG, \"Exception while sending error\", e)\n                }\n            }\n            db.close()\n        }\n    }\n\n    override fun getSharedUuid(callbacks: ISafetyNetCallbacks) {\n        PackageUtils.checkPackageUid(context, packageName, getCallingUid())\n        PackageUtils.assertGooglePackagePermission(context, GooglePackagePermission.SAFETYNET)\n\n        // TODO\n        Log.d(TAG, \"dummy Method: getSharedUuid\")\n        callbacks.onSharedUuid(\"aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa\")\n    }\n\n    override fun lookupUri(callbacks: ISafetyNetCallbacks, apiKey: String, threatTypes: IntArray, i: Int, s2: String) {\n        Log.d(TAG, \"unimplemented Method: lookupUri\")\n        callbacks.onSafeBrowsingData(Status.SUCCESS, SafeBrowsingData())\n    }\n\n    override fun enableVerifyApps(callbacks: ISafetyNetCallbacks) {\n        Log.d(TAG, \"dummy Method: enableVerifyApps\")\n        callbacks.onVerifyAppsUserResult(Status.SUCCESS, true)\n    }\n\n    override fun listHarmfulApps(callbacks: ISafetyNetCallbacks) {\n        Log.d(TAG, \"dummy Method: listHarmfulApps\")\n        callbacks.onHarmfulAppsInfo(Status.SUCCESS, HarmfulAppsInfo().apply {\n            lastScanTime = ((System.currentTimeMillis() - VERIFY_APPS_LAST_SCAN_DELAY) / VERIFY_APPS_LAST_SCAN_TIME_ROUNDING) * VERIFY_APPS_LAST_SCAN_TIME_ROUNDING + VERIFY_APPS_LAST_SCAN_OFFSET\n        })\n    }\n\n    override fun verifyWithRecaptcha(callbacks: ISafetyNetCallbacks, siteKey: String?) {\n        if (siteKey == null) {\n            callbacks.onRecaptchaResult(Status(SafetyNetStatusCodes.RECAPTCHA_INVALID_SITEKEY, \"SiteKey missing\"), null)\n            return\n        }\n\n        if (!SafetyNetPreferences.isEnabled(context)) {\n            Log.d(TAG, \"ignoring SafetyNet request, SafetyNet is disabled\")\n            callbacks.onRecaptchaResult(Status(SafetyNetStatusCodes.ERROR, \"Disabled\"), null)\n            return\n        }\n\n        val db = SafetyNetDatabase(context)\n        val requestID = db.insertRecentRequestStart(\n            SafetyNetRequestType.RECAPTCHA,\n            context.packageName,\n            null,\n            System.currentTimeMillis()\n        )\n\n        val intent = Intent(\"org.microg.gms.safetynet.RECAPTCHA_ACTIVITY\")\n        intent.`package` = context.packageName\n        intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)\n        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)\n        intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)\n        val androidId = getSettings(\n            context,\n            getContentUri(context),\n            arrayOf(SettingsContract.CheckIn.ANDROID_ID)\n        ) { cursor: Cursor -> cursor.getLong(0) }\n        val params = StringBuilder()\n\n        val (packageFileDigest, packageSignatures) = try {\n            Pair(\n                Base64.encodeToString(\n                    Attestation.getPackageFileDigest(context, packageName),\n                    Base64.URL_SAFE or Base64.NO_WRAP or Base64.NO_PADDING\n                ),\n                Attestation.getPackageSignatures(context, packageName)\n                    .map { Base64.encodeToString(it, Base64.URL_SAFE or Base64.NO_WRAP or Base64.NO_PADDING) }\n            )\n        } catch (e: Exception) {\n            db.insertRecentRequestEnd(requestID, Status(SafetyNetStatusCodes.ERROR, e.localizedMessage), null)\n            db.close()\n            callbacks.onRecaptchaResult(Status(SafetyNetStatusCodes.ERROR, e.localizedMessage), null)\n            return\n        }\n\n        params.appendUrlEncodedParam(\"k\", siteKey)\n            .appendUrlEncodedParam(\"di\", androidId.toString())\n            .appendUrlEncodedParam(\"pk\", packageName)\n            .appendUrlEncodedParam(\"sv\", SDK_INT.toString())\n            .appendUrlEncodedParam(\"gv\", \"20.47.14 (040306-{{cl}})\")\n            .appendUrlEncodedParam(\"gm\", \"260\")\n            .appendUrlEncodedParam(\"as\", packageFileDigest)\n        for (signature in packageSignatures) {\n            Log.d(TAG, \"Sig: $signature\")\n            params.appendUrlEncodedParam(\"ac\", signature)\n        }\n        params.appendUrlEncodedParam(\"ip\", \"com.android.vending\")\n            .appendUrlEncodedParam(\"av\", false.toString())\n            .appendUrlEncodedParam(\"si\", null)\n        intent.putExtra(\"params\", params.toString())\n        intent.putExtra(\"result\", object : ResultReceiver(null) {\n            override fun onReceiveResult(resultCode: Int, resultData: Bundle) {\n                if (resultCode != 0) {\n                    db.insertRecentRequestEnd(\n                        requestID,\n                        Status(resultData.getInt(\"errorCode\"), resultData.getString(\"error\")),\n                        null\n                    )\n                    db.close()\n                    callbacks.onRecaptchaResult(\n                        Status(resultData.getInt(\"errorCode\"), resultData.getString(\"error\")),\n                        null\n                    )\n                } else {\n                    db.insertRecentRequestEnd(requestID, Status.SUCCESS, resultData.getString(\"token\"))\n                    db.close()\n                    callbacks.onRecaptchaResult(\n                        Status.SUCCESS,\n                        RecaptchaResultData().apply { token = resultData.getString(\"token\") })\n                }\n            }\n        })\n        context.startActivity(intent)\n    }\n\n    override fun initSafeBrowsing(callbacks: ISafetyNetCallbacks) {\n        Log.d(TAG, \"dummy: initSafeBrowsing\")\n        callbacks.onInitSafeBrowsingResult(Status.SUCCESS)\n    }\n\n    override fun shutdownSafeBrowsing() {\n        Log.d(TAG, \"dummy: shutdownSafeBrowsing\")\n    }\n\n    override fun isVerifyAppsEnabled(callbacks: ISafetyNetCallbacks) {\n        Log.d(TAG, \"dummy: isVerifyAppsEnabled\")\n        callbacks.onVerifyAppsUserResult(Status.SUCCESS, true)\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n\n    companion object {\n        // We simulate one scan every day, which will happen at 03:12:02.121 and will be available 32 seconds later\n        const val VERIFY_APPS_LAST_SCAN_DELAY = 32 * 1000L\n        const val VERIFY_APPS_LAST_SCAN_OFFSET = ((3 * 60 + 12) * 60 + 2) * 1000L + 121\n        const val VERIFY_APPS_LAST_SCAN_TIME_ROUNDING = 24 * 60 * 60 * 1000L\n    }\n}\n"
  },
  {
    "path": "play-services-safetynet/core/src/main/kotlin/org/microg/gms/safetynet/SafetyNetDatabase.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2016, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage org.microg.gms.safetynet\n\nimport android.content.ContentValues\nimport android.content.Context\nimport android.database.Cursor\nimport android.database.sqlite.SQLiteDatabase\nimport android.database.sqlite.SQLiteOpenHelper\nimport android.os.Build.VERSION.SDK_INT\nimport android.util.Log\nimport com.google.android.gms.common.api.Status\n\nclass SafetyNetDatabase(context: Context) : SQLiteOpenHelper(context, DB_NAME, null, DB_VERSION) {\n\n    init {\n        if (SDK_INT >= 16) {\n            setWriteAheadLoggingEnabled(true)\n        }\n    }\n\n    override fun onOpen(db: SQLiteDatabase) {\n        if (!db.isReadOnly) clearOldRequests(db)\n    }\n\n    private fun createSafetyNetSummary(cursor: Cursor): SafetyNetSummary {\n        val summary = SafetyNetSummary(\n            SafetyNetRequestType.valueOf(\n                cursor.getString(cursor.getColumnIndexOrThrow(FIELD_REQUEST_TYPE))\n            ),\n            cursor.getString(cursor.getColumnIndexOrThrow(FIELD_PACKAGE_NAME)),\n            cursor.getBlob(cursor.getColumnIndexOrThrow(FIELD_NONCE)),\n            cursor.getLong(cursor.getColumnIndexOrThrow(FIELD_TIMESTAMP))\n        )\n        summary.id = cursor.getInt(cursor.getColumnIndexOrThrow(FIELD_ID))\n        if (cursor.isNull(cursor.getColumnIndexOrThrow(FIELD_RESULT_STATUS_CODE))) return summary\n        summary.responseStatus = Status(\n            cursor.getInt(cursor.getColumnIndexOrThrow(FIELD_RESULT_STATUS_CODE)),\n            cursor.getString(cursor.getColumnIndexOrThrow(FIELD_RESULT_STATUS_MSG))\n        )\n        summary.responseData = cursor.getString(cursor.getColumnIndexOrThrow(FIELD_RESULT_DATA))\n        return summary\n    }\n\n    val recentApps: List<Pair<String, Long>>\n        get() {\n            val db = readableDatabase\n            val cursor = db.query(TABLE_RECENTS, arrayOf(FIELD_PACKAGE_NAME, \"MAX($FIELD_TIMESTAMP)\"), null, null, FIELD_PACKAGE_NAME, null, \"MAX($FIELD_TIMESTAMP) DESC\")\n            if (cursor != null) {\n                val result = ArrayList<Pair<String, Long>>()\n                while (cursor.moveToNext()) {\n                    result.add(cursor.getString(0) to cursor.getLong(1))\n                }\n                cursor.close()\n                return result\n            }\n            return emptyList()\n        }\n\n    fun getRecentRequests(packageName: String): List<SafetyNetSummary> {\n        val db = readableDatabase\n        val cursor = db.query(TABLE_RECENTS, null, \"$FIELD_PACKAGE_NAME = ?\", arrayOf(packageName), null, null, \"$FIELD_TIMESTAMP DESC\")\n        if (cursor != null) {\n            val result: MutableList<SafetyNetSummary> = ArrayList()\n            while (cursor.moveToNext()) {\n                result.add(createSafetyNetSummary(cursor))\n            }\n            cursor.close()\n            return result\n        }\n        return emptyList()\n    }\n\n    fun insertRecentRequestStart(\n        requestType: SafetyNetRequestType,\n        packageName: String?,\n        nonce: ByteArray?,\n        timestamp: Long\n    ): Long {\n        val db = writableDatabase\n        val cv = ContentValues()\n        cv.put(FIELD_REQUEST_TYPE, requestType.name)\n        cv.put(FIELD_PACKAGE_NAME, packageName)\n        cv.put(FIELD_NONCE, nonce)\n        cv.put(FIELD_TIMESTAMP, timestamp)\n        return db.insert(TABLE_RECENTS, null, cv)\n    }\n\n    fun insertRecentRequestEnd(id: Long, status: Status, resultData: String?) {\n        val db = writableDatabase\n        val cv = ContentValues()\n        cv.put(FIELD_RESULT_STATUS_CODE, status.statusCode)\n        cv.put(FIELD_RESULT_STATUS_MSG, status.statusMessage)\n        cv.put(FIELD_RESULT_DATA, resultData)\n        db.update(TABLE_RECENTS, cv, \"$FIELD_ID = ?\", arrayOf(id.toString()))\n    }\n\n    fun clearOldRequests(db: SQLiteDatabase) {\n        val timeout = 1000 * 60 * 60 * 24 * 14 // 14 days\n        val maxRequests = 150\n        var rows = 0\n\n        rows += db.compileStatement(\n            \"DELETE FROM $TABLE_RECENTS WHERE $FIELD_ID NOT IN \" +\n                    \"(SELECT $FIELD_ID FROM $TABLE_RECENTS ORDER BY $FIELD_TIMESTAMP LIMIT $maxRequests)\"\n        ).executeUpdateDelete()\n\n        val sqLiteStatement = db.compileStatement(\"DELETE FROM $TABLE_RECENTS WHERE $FIELD_TIMESTAMP + ? < ?\")\n        sqLiteStatement.bindLong(1, timeout.toLong())\n        sqLiteStatement.bindLong(2, System.currentTimeMillis())\n        rows += sqLiteStatement.executeUpdateDelete()\n\n        if (rows != 0) Log.d(TAG, \"Cleared $rows old request(s)\")\n    }\n\n    fun clearAllRequests() {\n        val db = writableDatabase\n        db.execSQL(\"DELETE FROM $TABLE_RECENTS\")\n    }\n\n    override fun onCreate(db: SQLiteDatabase) {\n        db.execSQL(CREATE_TABLE_RECENTS)\n    }\n\n    override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {\n        throw IllegalStateException(\"Upgrades not supported\")\n    }\n\n    companion object {\n        private val TAG = SafetyNetDatabase::class.java.simpleName\n        private const val DB_NAME = \"snet.db\"\n        private const val DB_VERSION = 1\n        private const val CREATE_TABLE_RECENTS = \"CREATE TABLE recents (\" +\n                \"id INTEGER PRIMARY KEY AUTOINCREMENT ,\" +\n                \"request_type TEXT,\" +\n                \"package_name TEXT,\" +\n                \"nonce TEXT,\" +\n                \"timestamp INTEGER,\" +\n                \"result_status_code INTEGER DEFAULT NULL,\" +\n                \"result_status_msg TEXT DEFAULT NULL,\" +\n                \"result_data TEXT DEFAULT NULL)\"\n        private const val TABLE_RECENTS = \"recents\"\n        private const val FIELD_ID = \"id\"\n        private const val FIELD_REQUEST_TYPE = \"request_type\"\n        private const val FIELD_PACKAGE_NAME = \"package_name\"\n        private const val FIELD_NONCE = \"nonce\"\n        private const val FIELD_TIMESTAMP = \"timestamp\"\n        private const val FIELD_RESULT_STATUS_CODE = \"result_status_code\"\n        private const val FIELD_RESULT_STATUS_MSG = \"result_status_msg\"\n        private const val FIELD_RESULT_DATA = \"result_data\"\n    }\n}\n"
  },
  {
    "path": "play-services-safetynet/core/src/main/kotlin/org/microg/gms/safetynet/SafetyNetPreferences.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2021 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.safetynet\n\nimport android.content.ContentValues\nimport android.content.Context\nimport android.database.Cursor\nimport org.microg.gms.settings.SettingsContract\nimport org.microg.gms.settings.SettingsContract.SafetyNet.ENABLED\n\nobject SafetyNetPreferences {\n    private fun <T> getSettings(context: Context, projection: String, def: T, f: (Cursor) -> T): T {\n        return try {\n            SettingsContract.getSettings(context, SettingsContract.SafetyNet.getContentUri(context), arrayOf(projection), f)\n        } catch (e: Exception) {\n            def\n        }\n    }\n\n    private fun setSettings(context: Context, f: ContentValues.() -> Unit) =\n            SettingsContract.setSettings(context, SettingsContract.SafetyNet.getContentUri(context), f)\n\n    @JvmStatic\n    fun isEnabled(context: Context): Boolean = getSettings(context, ENABLED, false) { it.getInt(0) != 0 }\n\n    @JvmStatic\n    fun setEnabled(context: Context, enabled: Boolean) = setSettings(context) { put(ENABLED, enabled) }\n}\n"
  },
  {
    "path": "play-services-safetynet/core/src/main/kotlin/org/microg/gms/safetynet/SafetyNetRequestType.kt",
    "content": "package org.microg.gms.safetynet\n\nenum class SafetyNetRequestType {\n    ATTESTATION,\n    RECAPTCHA,\n    RECAPTCHA_ENTERPRISE,\n    ;\n}"
  },
  {
    "path": "play-services-safetynet/core/src/main/kotlin/org/microg/gms/safetynet/SafetyNetSummary.kt",
    "content": "package org.microg.gms.safetynet\n\nimport android.os.Parcel\nimport android.os.Parcelable\nimport com.google.android.gms.common.api.Status\nimport kotlin.properties.Delegates\n\ndata class SafetyNetSummary(\n    val requestType: SafetyNetRequestType,\n\n\n    // request data\n    val packageName: String,\n    val nonce: ByteArray?, // null with SafetyNetRequestType::RECAPTCHA\n    val timestamp: Long,\n\n    ) : Parcelable {\n\n    var id by Delegates.notNull<Int>()\n\n    // response data\n    // note : responseStatus do not represent the actual status in case of an attestation, it will be in resultData\n    var responseStatus: Status? = null\n    var responseData: String? = null\n\n    override fun equals(other: Any?): Boolean {\n        if (this === other) return true\n        if (javaClass != other?.javaClass) return false\n\n        other as SafetyNetSummary\n\n        if (requestType != other.requestType) return false\n        if (packageName != other.packageName) return false\n        if (!nonce.contentEquals(other.nonce)) return false\n        if (responseStatus != other.responseStatus) return false\n        if (responseData != other.responseData) return false\n\n        return true\n    }\n\n    override fun hashCode(): Int {\n        var result = requestType.hashCode()\n        result = 31 * result + packageName.hashCode()\n        result = 31 * result + nonce.hashCode()\n        result = 31 * result + (responseStatus?.hashCode() ?: 0)\n        result = 31 * result + (responseData?.hashCode() ?: 0)\n        return result\n    }\n\n\n    // Parcelable implementation\n\n    constructor(parcel: Parcel) : this(\n        SafetyNetRequestType.valueOf(parcel.readString()!!),\n        parcel.readString()!!,\n        parcel.createByteArray(),\n        parcel.readLong()\n    ) {\n        responseStatus = parcel.readParcelable(Status::class.java.classLoader)\n        responseData = parcel.readString()\n    }\n\n    override fun writeToParcel(parcel: Parcel, flags: Int) {\n        parcel.writeString(requestType.name)\n        parcel.writeString(packageName)\n        parcel.writeByteArray(nonce)\n        parcel.writeLong(timestamp)\n        parcel.writeParcelable(responseStatus, flags)\n        parcel.writeString(responseData)\n    }\n\n    override fun describeContents(): Int {\n        return 0\n    }\n\n    companion object CREATOR : Parcelable.Creator<SafetyNetSummary> {\n        override fun createFromParcel(parcel: Parcel): SafetyNetSummary {\n            return SafetyNetSummary(parcel)\n        }\n\n        override fun newArray(size: Int): Array<SafetyNetSummary?> {\n            return arrayOfNulls(size)\n        }\n    }\n\n\n}"
  },
  {
    "path": "play-services-safetynet/core/src/main/proto/safetynet.proto",
    "content": "option java_package = \"org.microg.gms.safetynet\";\n\noption java_outer_classname = \"SafetyNetProto\";\n\nmessage SELinuxState {\n    optional bool supported = 1;\n    optional bool enabled = 2;\n}\n\nmessage FileState {\n    optional string fileName = 1;\n    optional bytes digest = 2;\n}\n\nmessage SafetyNetData {\n    optional bytes nonce = 1;\n    optional string packageName = 2;\n    repeated bytes signatureDigest = 3;\n    optional bytes fileDigest = 4;\n    optional int32 gmsVersionCode = 5;\n    repeated FileState suCandidates = 6;\n    optional SELinuxState seLinuxState = 7;\n    optional int64 currentTimeMs = 8;\n    optional bool googleCn = 9;\n}\n\nmessage AttestRequest {\n    optional bytes safetyNetData = 1;\n    optional string droidGuardResult = 2;\n}\n\nmessage AttestResponse {\n    optional string result = 2;\n}\n"
  },
  {
    "path": "play-services-safetynet/core/src/main/res/drawable/ic_recaptcha.xml",
    "content": "<!--\n  ~ SPDX-FileCopyrightText: 2021, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\"\n    android:width=\"48dp\"\n    android:height=\"48dp\"\n    android:viewportWidth=\"48\"\n    android:viewportHeight=\"48\">\n  <path\n      android:pathData=\"M2,24L2,40.5L5.9387,36.5616a22,22 45,0 0,9.6423 7.7639,22 22,0 0,0 23.9753,-4.7692L31.071,31.071A10,10 0,0 1,24 34,10 10,135 0,1 14.7361,27.7642L18.5,24L14,24Z\"\n      android:strokeWidth=\"0\"\n      android:fillColor=\"#bdbdbd\"\n      android:strokeColor=\"#000000\"/>\n  <path\n      android:pathData=\"M7.5,2 L11.4386,5.9387A22,22 0,0 0,2 24L14,24A10,10 135,0 1,20.236 14.7361L24,18.5L24,14 24,2l-0.0682,0z\"\n      android:strokeWidth=\"0\"\n      android:strokeColor=\"#000000\">\n    <aapt:attr name=\"android:fillColor\">\n      <gradient \n          android:startY=\"24\"\n          android:startX=\"14\"\n          android:endY=\"20.75\"\n          android:endX=\"14.000\"\n          android:type=\"linear\">\n        <item android:offset=\"0\" android:color=\"#FF1E88E5\"/>\n        <item android:offset=\"1\" android:color=\"#FF2196F3\"/>\n      </gradient>\n    </aapt:attr>\n  </path>\n  <path\n      android:pathData=\"M46,7.5 L42.0615,11.4386A22,22 0,0 0,24 2V14a10,10 0,0 1,9.264 6.2358l-3.7641,3.7641h4.5,12v-0.0682z\"\n      android:strokeWidth=\"0\"\n      android:strokeColor=\"#000000\">\n    <aapt:attr name=\"android:fillColor\">\n      <gradient \n          android:startY=\"14\"\n          android:startX=\"24\"\n          android:endY=\"14\"\n          android:endX=\"27.25\"\n          android:type=\"linear\">\n        <item android:offset=\"0\" android:color=\"#FF3949AB\"/>\n        <item android:offset=\"1\" android:color=\"#FF3F51B5\"/>\n      </gradient>\n    </aapt:attr>\n  </path>\n  <path\n      android:pathData=\"M46,7.5 L42.0615,11.4386C37.9491,5.5255 31.2026,2 24,2L46,24v-0.0682z\"\n      android:strokeWidth=\"0\">\n    <aapt:attr name=\"android:fillColor\">\n      <gradient \n          android:startY=\"2\"\n          android:startX=\"24\"\n          android:endY=\"24\"\n          android:endX=\"46\"\n          android:type=\"linear\">\n        <item android:offset=\"0\" android:color=\"#18FFFFFF\"/>\n        <item android:offset=\"1\" android:color=\"#00FFFFFF\"/>\n      </gradient>\n    </aapt:attr>\n  </path>\n</vector>\n"
  },
  {
    "path": "play-services-safetynet/core/src/main/res/layout/recaptcha_window.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2021, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<FrameLayout 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\n    <LinearLayout\n        android:id=\"@+id/recaptcha_loading\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:background=\"@android:color/white\"\n        android:layout_gravity=\"center\"\n        android:gravity=\"center\"\n        android:orientation=\"vertical\">\n\n        <LinearLayout\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center\"\n            android:layout_marginLeft=\"20dip\"\n            android:layout_marginTop=\"20dip\"\n            android:layout_marginRight=\"20dip\"\n            android:layout_marginBottom=\"10sp\"\n            android:gravity=\"center\"\n            android:orientation=\"horizontal\">\n\n            <ImageView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:src=\"@drawable/ic_recaptcha\" />\n\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center\"\n                android:layout_marginStart=\"10sp\"\n                android:layout_marginLeft=\"10sp\"\n                android:text=\"reCAPTCHA\"\n                android:textColor=\"#FF3949AB\"\n                android:textStyle=\"bold\" />\n        </LinearLayout>\n\n        <ProgressBar\n            style=\"?android:progressBarStyleHorizontal\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center_horizontal\"\n            android:layout_marginLeft=\"20dip\"\n            android:layout_marginTop=\"10sp\"\n            android:layout_marginRight=\"20dip\"\n            android:layout_marginBottom=\"20dip\"\n            android:indeterminate=\"true\"\n            android:indeterminateTint=\"#FF3949AB\" />\n\n    </LinearLayout>\n\n    <WebView\n        android:id=\"@+id/recaptcha_webview\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_gravity=\"center_vertical\"\n        android:visibility=\"gone\" />\n</FrameLayout>\n"
  },
  {
    "path": "play-services-safetynet/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2022, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest />\n"
  },
  {
    "path": "play-services-safetynet/src/main/aidl/com/google/android/gms/safetynet/AttestationData.aidl",
    "content": "package com.google.android.gms.safetynet;\n\nparcelable AttestationData;"
  },
  {
    "path": "play-services-safetynet/src/main/aidl/com/google/android/gms/safetynet/HarmfulAppsData.aidl",
    "content": "package com.google.android.gms.safetynet;\n\nparcelable HarmfulAppsData;"
  },
  {
    "path": "play-services-safetynet/src/main/aidl/com/google/android/gms/safetynet/HarmfulAppsInfo.aidl",
    "content": "package com.google.android.gms.safetynet;\n\nparcelable HarmfulAppsInfo;\n"
  },
  {
    "path": "play-services-safetynet/src/main/aidl/com/google/android/gms/safetynet/RecaptchaResultData.aidl",
    "content": "package com.google.android.gms.safetynet;\n\nparcelable RecaptchaResultData;\n"
  },
  {
    "path": "play-services-safetynet/src/main/aidl/com/google/android/gms/safetynet/RemoveHarmfulAppData.aidl",
    "content": "package com.google.android.gms.safetynet;\n\nparcelable RemoveHarmfulAppData;\n"
  },
  {
    "path": "play-services-safetynet/src/main/aidl/com/google/android/gms/safetynet/SafeBrowsingData.aidl",
    "content": "package com.google.android.gms.safetynet;\n\nparcelable SafeBrowsingData;"
  },
  {
    "path": "play-services-safetynet/src/main/aidl/com/google/android/gms/safetynet/internal/ISafetyNetCallbacks.aidl",
    "content": "package com.google.android.gms.safetynet.internal;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.safetynet.AttestationData;\nimport com.google.android.gms.safetynet.HarmfulAppsData;\nimport com.google.android.gms.safetynet.HarmfulAppsInfo;\nimport com.google.android.gms.safetynet.RecaptchaResultData;\nimport com.google.android.gms.safetynet.RemoveHarmfulAppData;\nimport com.google.android.gms.safetynet.SafeBrowsingData;\n\ninterface ISafetyNetCallbacks {\n    oneway void onAttestationResult(in Status status, in AttestationData attestationData) = 0;\n    oneway void onSharedUuid(String s) = 1;\n    oneway void onSafeBrowsingData(in Status status, in SafeBrowsingData safeBrowsingData) = 2;\n    oneway void onVerifyAppsUserResult(in Status status, boolean enabled) = 3;\n    oneway void onHarmfulAppsData(in Status status, in List<HarmfulAppsData> harmfulAppsData) = 4;\n    oneway void onRecaptchaResult(in Status status, in RecaptchaResultData recaptchaResultData) = 5;\n    oneway void onHarmfulAppsInfo(in Status status, in HarmfulAppsInfo harmfulAppsInfo) = 7;\n    oneway void onInitSafeBrowsingResult(in Status status) = 10;\n    oneway void onRemoveHarmfulAppData(in Status status, in RemoveHarmfulAppData removeHarmfulAppData) = 14;\n}\n"
  },
  {
    "path": "play-services-safetynet/src/main/aidl/com/google/android/gms/safetynet/internal/ISafetyNetService.aidl",
    "content": "package com.google.android.gms.safetynet.internal;\n\nimport com.google.android.gms.safetynet.internal.ISafetyNetCallbacks;\n\ninterface ISafetyNetService {\n    void attest(ISafetyNetCallbacks callbacks, in byte[] nonce) = 0;\n    void attestWithApiKey(ISafetyNetCallbacks callbacks, in byte[] nonce, String apiKey) = 6;\n    void getSharedUuid(ISafetyNetCallbacks callbacks) = 1;\n    void lookupUri(ISafetyNetCallbacks callbacks, String apiKey, in int[] threatTypes, int version, String uri) = 2;\n    void enableVerifyApps(ISafetyNetCallbacks callbacks) = 3;\n    void listHarmfulApps(ISafetyNetCallbacks callbacks) = 4;\n    void verifyWithRecaptcha(ISafetyNetCallbacks callbacks, String siteKey) = 5;\n\n//    void fun9(ISafetyNetCallbacks callbacks) = 8;\n//    void fun10(ISafetyNetCallbacks callbacks, String s1, int i1, in byte[] b1) = 9;\n//    void fun11(int i1, in Bundle b1) = 10;\n    void initSafeBrowsing(ISafetyNetCallbacks callbacks) = 11;\n    void shutdownSafeBrowsing() = 12;\n    void isVerifyAppsEnabled(ISafetyNetCallbacks callbacks) = 13;\n//\n//    void fun18(ISafetyNetCallbacks callbacks, int i1, String s1) = 17;\n//    void fun19(ISafetyNetCallbacks callbacks, int i1) = 18;\n//    void removeHarmfulApp(ISafetyNetCallbacks callbacks, String packageName, in byte[] digest) = 19;\n//    void fun21(ISafetyNetCallbacks callbacks, in Bundle b1) = 20;\n}\n"
  },
  {
    "path": "play-services-safetynet/src/main/java/com/google/android/gms/safetynet/AttestationData.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2017 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.safetynet;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class AttestationData extends AutoSafeParcelable {\n    @Field(1)\n    private int versionCode = 1;\n    @Field(2)\n    private String jwsResult;\n\n    private AttestationData() {\n    }\n\n    public AttestationData(String jwsResult) {\n        this.jwsResult = jwsResult;\n    }\n\n    public String getJwsResult() {\n        return jwsResult;\n    }\n\n    public static final Creator<AttestationData> CREATOR = new AutoCreator<AttestationData>(AttestationData.class);\n}\n"
  },
  {
    "path": "play-services-safetynet/src/main/java/com/google/android/gms/safetynet/HarmfulAppsData.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2021 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.safetynet;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n/**\n * APK information pertaining to one potentially harmful app.\n */\n@PublicApi\npublic class HarmfulAppsData extends AutoSafeParcelable {\n    /**\n     * The package name of the potentially harmful app.\n     */\n    @Field(2)\n    public final String apkPackageName;\n    /**\n     * The SHA-256 of the potentially harmful app APK file.\n     */\n    @Field(3)\n    public final byte[] apkSha256;\n    /**\n     * The potentially harmful app category defined in {@link VerifyAppsConstants}.\n     */\n    @Field(4)\n    public final int apkCategory;\n\n    private HarmfulAppsData() {\n        apkPackageName = null;\n        apkSha256 = null;\n        apkCategory = 0;\n    }\n\n    @PublicApi(exclude = true)\n    public HarmfulAppsData(String apkPackageName, byte[] apkSha256, int apkCategory) {\n        this.apkPackageName = apkPackageName;\n        this.apkSha256 = apkSha256;\n        this.apkCategory = apkCategory;\n    }\n\n    public static final Creator<HarmfulAppsData> CREATOR = new AutoCreator<HarmfulAppsData>(HarmfulAppsData.class);\n}\n"
  },
  {
    "path": "play-services-safetynet/src/main/java/com/google/android/gms/safetynet/HarmfulAppsInfo.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2017 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.safetynet;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class HarmfulAppsInfo extends AutoSafeParcelable {\n    @Field(2)\n    public long lastScanTime;\n    @Field(3)\n    public HarmfulAppsData[] harmfulApps = new HarmfulAppsData[0];\n    @Field(4)\n    public int hoursSinceLastScanWithHarmfulApp = -1;\n    @Field(5)\n    public boolean harmfulAppInOtherProfile = false;\n\n    public static final Creator<HarmfulAppsInfo> CREATOR = new AutoCreator<HarmfulAppsInfo>(HarmfulAppsInfo.class);\n}\n"
  },
  {
    "path": "play-services-safetynet/src/main/java/com/google/android/gms/safetynet/RecaptchaResultData.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2017 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.safetynet;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class RecaptchaResultData extends AutoSafeParcelable {\n    @Field(2)\n    public String token;\n\n    public static final Creator<RecaptchaResultData> CREATOR = new AutoCreator<RecaptchaResultData>(RecaptchaResultData.class);\n}\n"
  },
  {
    "path": "play-services-safetynet/src/main/java/com/google/android/gms/safetynet/RemoveHarmfulAppData.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2017 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.safetynet;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class RemoveHarmfulAppData extends AutoSafeParcelable {\n    @Field(2)\n    public int field2;\n    @Field(3)\n    public boolean field3;\n\n    public static final Creator<RemoveHarmfulAppData> CREATOR = new AutoCreator<RemoveHarmfulAppData>(RemoveHarmfulAppData.class);\n}\n"
  },
  {
    "path": "play-services-safetynet/src/main/java/com/google/android/gms/safetynet/SafeBrowsingData.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2017 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.safetynet;\n\nimport android.os.ParcelFileDescriptor;\n\nimport com.google.android.gms.common.data.DataHolder;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\nimport java.io.File;\n\npublic class SafeBrowsingData extends AutoSafeParcelable {\n    @Field(1)\n    public int versionCode = 1;\n    @Field(2)\n    public String metadata;\n    @Field(3)\n    public DataHolder data;\n    @Field(4)\n    public ParcelFileDescriptor fileDescriptor;\n    public byte[] fileContents;\n    @Field(5)\n    public long lastUpdateTime;\n    @Field(6)\n    public byte[] state;\n\n    public static final Creator<SafeBrowsingData> CREATOR = new AutoCreator<SafeBrowsingData>(SafeBrowsingData.class);\n}\n"
  },
  {
    "path": "play-services-safetynet/src/main/java/com/google/android/gms/safetynet/SafetyNet.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.safetynet;\n\nimport android.app.Activity;\nimport android.content.Context;\n\nimport com.google.android.gms.common.api.Api;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.safetynet.SafetyNetApiImpl;\nimport org.microg.gms.safetynet.SafetyNetGmsClient;\n\n/**\n * The SafetyNet API provides access to Google services that help you assess the health and safety of an Android device.\n * <p>\n * To use SafetyNet, call {@link #getClient(Context)} or {@link #getClient(Activity)}.\n */\n@PublicApi\npublic class SafetyNet {\n    /**\n     * The API necessary to use SafetyNet.\n     *\n     * @deprecated use {@link #getClient(Context)} or {@link #getClient(Activity)}.\n     */\n    @Deprecated\n    public static final Api<Api.ApiOptions.NoOptions> API = new Api<>((options, context, looper, clientSettings, callbacks, connectionFailedListener) -> new SafetyNetGmsClient(context, callbacks, connectionFailedListener));;\n\n    /**\n     * The entry point for interacting with the SafetyNet APIs which help assess the health and safety of an Android device.\n     *\n     * @deprecated use {@link #getClient(Context)} or {@link #getClient(Activity)}.\n     */\n    @Deprecated\n    public static final SafetyNetApi SafetyNetApi = new SafetyNetApiImpl();\n\n    /**\n     * Returns a {@link SafetyNetClient} that is used to access all APIs that are called when the app has a\n     * foreground {@link Activity}.\n     * <p>\n     * Use this method over {@link #getClient(Context)} if your app has a foreground Activity and you will be making\n     * multiple API calls to improve performance.\n     */\n    public static SafetyNetClient getClient(Activity activity) {\n        return new SafetyNetClient(activity);\n    }\n\n    /**\n     * Returns a {@link SafetyNetClient} that is used to access all APIs that are called without access to a\n     * foreground {@link Activity}.\n     */\n    public static SafetyNetClient getClient(Context context) {\n        return new SafetyNetClient(context);\n    }\n}\n"
  },
  {
    "path": "play-services-safetynet/src/main/java/com/google/android/gms/safetynet/SafetyNetApi.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.safetynet;\n\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.PendingResult;\nimport com.google.android.gms.common.api.Response;\nimport com.google.android.gms.common.api.Result;\nimport com.google.android.gms.common.api.Status;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * The main entry point for interacting with SafetyNet.\n */\npublic interface SafetyNetApi {\n    /**\n     * Provides user attestation with reCAPTCHA.\n     * <p>\n     * If reCAPTCHA is confident that this is a real user on a real device it will return a token with no challenge.\n     * Otherwise it will provide a visual/audio challenge to attest the humanness of the user before returning a token.\n     * <p>\n     * When you make a request with this API, you must provide your client {@link GoogleApiClient} and site public key\n     * as parameters, and after the request completes, you can get the {@link RecaptchaTokenResult}\n     * from the response.\n     *\n     * @param client  The {@link GoogleApiClient} to service the call. The client must be connected using\n     *                {@link GoogleApiClient#connect()} before invoking this method.\n     * @param siteKey A site public key registered for this app\n     * @deprecated use {@link SafetyNetClient#verifyWithRecaptcha(String)}\n     */\n    @Deprecated\n    PendingResult<RecaptchaTokenResult> verifyWithRecaptcha(GoogleApiClient client, String siteKey);\n\n    /**\n     * Response from {@link SafetyNetClient#attest(byte[], String)} that contains a Compatibility Test Suite\n     * attestation result.\n     * <p>\n     * Use the {@link Result#getStatus()} method to obtain a {@link Status} object. Calling the Status object's\n     * {@link Status#isSuccess} indicates whether or not communication with the service was successful, but does not\n     * indicate if the device has passed the compatibility check. If the request was successful,\n     * {@link AttestationResponse#getJwsResult()} may be used to determine whether the device has passed the\n     * compatibility check.\n     */\n    class AttestationResponse extends Response<AttestationResult> {\n        /**\n         * Gets the JSON Web Signature attestation result.\n         * <p>\n         * Result is in JSON Web Signature format.\n         *\n         * @return JSON Web signature formatted attestation response or {@code null} if an error occurred.\n         */\n        public String getJwsResult() {\n            return getResult().getJwsResult();\n        }\n    }\n\n    @PublicApi(exclude = true)\n    @Deprecated\n    interface AttestationResult extends Result {\n        String getJwsResult();\n    }\n\n    /**\n     * {@link Response} from {@link SafetyNetClient#verifyWithRecaptcha(String)}.\n     * <p>\n     * This Result contains a reCAPTCHA user response token and third party clients should use this token to verify\n     * the user. The token must be validated on the server side to determine whether the user has passed the challenge.\n     */\n    class RecaptchaTokenResponse extends Response<RecaptchaTokenResult> {\n        /**\n         * Gets the reCAPTCHA user response token which must be validated by calling the siteverify method.\n         *\n         * @return A user response token.\n         */\n        public String getTokenResult() {\n            return getResult().getTokenResult();\n        }\n    }\n\n    /**\n     * A Result from {@link #verifyWithRecaptcha(GoogleApiClient, String)}.\n     * <p>\n     * This Result contains a reCAPTCHA user response token and third party clients should use this token to verify\n     * the user. Calling the {@link Status#isSuccess()} will indicate whether or not communication with the service was\n     * successful, but does not indicate if the user has passed the reCAPTCHA challenge. The token must be validated on\n     * the server side to determine whether the user has passed the challenge.\n     *\n     * @deprecated use {@link RecaptchaTokenResponse} returned from {@link SafetyNetClient#verifyWithRecaptcha(String)}.\n     */\n    @Deprecated\n    interface RecaptchaTokenResult extends Result {\n        String getTokenResult();\n    }\n\n    /**\n     * A {@link Response} to get user decisions for the Verify Apps API.\n     */\n    class VerifyAppsUserResponse extends Response<VerifyAppsUserResult> {\n        /**\n         * Returns whether the user has enabled Verify Apps when prompted.\n         * <p>\n         * This method is only meaningful when used with\n         * {@link SafetyNetClient#enableVerifyApps()} or {@link SafetyNetClient#isVerifyAppsEnabled()}.\n         */\n        public boolean isVerifyAppsEnabled() {\n            return getResult().isVerifyAppsEnabled();\n        }\n    }\n\n    /**\n     * A {@link Result} to get user decisions for the Verify Apps API.\n     *\n     * @deprecated use {@link VerifyAppsUserResponse} instead.\n     */\n    @Deprecated\n    interface VerifyAppsUserResult extends Result {\n        /**\n         * Returns whether the user has enabled Verify Apps when prompted.\n         */\n        boolean isVerifyAppsEnabled();\n    }\n}\n"
  },
  {
    "path": "play-services-safetynet/src/main/java/com/google/android/gms/safetynet/SafetyNetClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.safetynet;\n\nimport android.content.Context;\nimport android.os.RemoteException;\n\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.GoogleApi;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.safetynet.internal.ISafetyNetCallbacks;\nimport com.google.android.gms.tasks.Task;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.common.api.PendingGoogleApiCall;\nimport org.microg.gms.safetynet.ISafetyNetCallbacksDefaultStub;\nimport org.microg.gms.safetynet.SafetyNetGmsClient;\n\n/**\n * The main entry point for SafetyNet.\n */\n@PublicApi\npublic class SafetyNetClient extends GoogleApi<Api.ApiOptions.NoOptions> {\n    @PublicApi(exclude = true)\n    SafetyNetClient(Context context) {\n        super(context, SafetyNet.API, Api.ApiOptions.NO_OPTIONS);\n    }\n\n    /**\n     * Provides attestation results for the device.\n     * <p>\n     * An attestation result states whether the device where it is running matches the profile of a device that has\n     * passed Android compatibility testing.\n     * <p>\n     * When you request a compatibility check, you must provide a nonce, which is a random token generated in a\n     * cryptographically secure manner. You can obtain a nonce by generating one within your app each time you make a\n     * compatibility check request. As a more secure option, you can obtain a nonce from your own server, using a\n     * secure connection.\n     * <p>\n     * A nonce used with an attestation request should be at least 16 bytes in length. After you make a request, the\n     * response {@link SafetyNetApi.AttestationResponse} includes your nonce, so you can verify it against the one you\n     * sent. You should only use a nonce value once, for a single request. Use a different nonce for any subsequent\n     * attestation requests.\n     *\n     * @param nonce  A cryptographic nonce used for anti-replay and tracking of requests.\n     * @param apiKey An Android API key obtained through the developer console.\n     */\n    public Task<SafetyNetApi.AttestationResponse> attest(byte[] nonce, String apiKey) {\n        return scheduleTask((PendingGoogleApiCall<SafetyNetApi.AttestationResponse, SafetyNetGmsClient>) (client, completionSource) -> {\n            try {\n                client.attest(new ISafetyNetCallbacksDefaultStub() {\n                    @Override\n                    public void onAttestationResult(Status status, AttestationData attestationData) throws RemoteException {\n                        SafetyNetApi.AttestationResponse response = new SafetyNetApi.AttestationResponse();\n                        response.setResult(new SafetyNetApi.AttestationResult() {\n                            @Override\n                            public String getJwsResult() {\n                                return attestationData.getJwsResult();\n                            }\n\n                            @Override\n                            public Status getStatus() {\n                                return status;\n                            }\n                        });\n                        completionSource.setResult(response);\n                    }\n                }, nonce, apiKey);\n            } catch (Exception e) {\n                completionSource.setException(e);\n            }\n        });\n    }\n\n    /**\n     * Provides user attestation with reCAPTCHA.\n     * <p>\n     * If reCAPTCHA is confident that this is a real user on a real device it will return a token with no challenge.\n     * Otherwise it will provide a visual/audio challenge to attest the humanness of the user before returning a token.\n     *\n     * @param siteKey A site public key registered for this app\n     */\n    public Task<SafetyNetApi.RecaptchaTokenResponse> verifyWithRecaptcha(String siteKey) {\n        return scheduleTask((PendingGoogleApiCall<SafetyNetApi.RecaptchaTokenResponse, SafetyNetGmsClient>) (client, completionSource) -> {\n            try {\n                client.verifyWithRecaptcha(new ISafetyNetCallbacksDefaultStub() {\n                    @Override\n                    public void onRecaptchaResult(Status status, RecaptchaResultData recaptchaResultData) throws RemoteException {\n                        SafetyNetApi.RecaptchaTokenResponse response = new SafetyNetApi.RecaptchaTokenResponse();\n                        response.setResult(new SafetyNetApi.RecaptchaTokenResult() {\n                            @Override\n                            public String getTokenResult() {\n                                if (recaptchaResultData != null) {\n                                    return recaptchaResultData.token;\n                                } else {\n                                    return null;\n                                }\n                            }\n\n                            @Override\n                            public Status getStatus() {\n                                return status;\n                            }\n                        });\n                        completionSource.setResult(response);\n\n                    }\n                }, siteKey);\n            } catch (Exception e) {\n                completionSource.setException(e);\n            }\n        });\n    }\n\n    /**\n     * Prompts the user to enable Verify Apps if it is currently turned off.\n     */\n    public Task<SafetyNetApi.VerifyAppsUserResponse> enableVerifyApps() {\n        return scheduleTask((PendingGoogleApiCall<SafetyNetApi.VerifyAppsUserResponse, SafetyNetGmsClient>) (client, completionSource) -> {\n            try {\n                client.enableVerifyApps(new ISafetyNetCallbacksDefaultStub() {\n                    @Override\n                    public void onVerifyAppsUserResult(Status status, boolean enabled) throws RemoteException {\n                        SafetyNetApi.VerifyAppsUserResponse response = new SafetyNetApi.VerifyAppsUserResponse();\n                        response.setResult(new SafetyNetApi.VerifyAppsUserResult() {\n                            @Override\n                            public boolean isVerifyAppsEnabled() {\n                                return enabled;\n                            }\n\n                            @Override\n                            public Status getStatus() {\n                                return status;\n                            }\n                        });\n                        completionSource.setResult(response);\n                    }\n                });\n            } catch (Exception e) {\n                completionSource.setException(e);\n            }\n        });\n    }\n\n    /**\n     * Determines whether Verify Apps is enabled.\n     */\n    public Task<SafetyNetApi.VerifyAppsUserResponse> isVerifyAppsEnabled() {\n        return scheduleTask((PendingGoogleApiCall<SafetyNetApi.VerifyAppsUserResponse, SafetyNetGmsClient>) (client, completionSource) -> {\n            try {\n                client.isVerifyAppsEnabled(new ISafetyNetCallbacksDefaultStub() {\n                    @Override\n                    public void onVerifyAppsUserResult(Status status, boolean enabled) throws RemoteException {\n                        SafetyNetApi.VerifyAppsUserResponse response = new SafetyNetApi.VerifyAppsUserResponse();\n                        response.setResult(new SafetyNetApi.VerifyAppsUserResult() {\n                            @Override\n                            public boolean isVerifyAppsEnabled() {\n                                return enabled;\n                            }\n\n                            @Override\n                            public Status getStatus() {\n                                return status;\n                            }\n                        });\n                        completionSource.setResult(response);\n                    }\n                });\n            } catch (Exception e) {\n                completionSource.setException(e);\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "play-services-safetynet/src/main/java/com/google/android/gms/safetynet/SafetyNetStatusCodes.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2021 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.safetynet;\n\nimport com.google.android.gms.common.api.CommonStatusCodes;\n\n/**\n * Status codes for the SafetyNet API.\n */\npublic class SafetyNetStatusCodes extends CommonStatusCodes {\n    /**\n     * None of the input threat types to {@code lookupUri(String, String, int...)} are supported.\n     */\n    public static final int SAFE_BROWSING_UNSUPPORTED_THREAT_TYPES = 12000;\n    /**\n     * The API key required for calling {@code lookupUri(String, String, int...)} is missing in the manifest.\n     * <p>\n     * A meta-data name-value pair in the app manifest with the name \"com.google.android.safetynet.API_KEY\" and a value\n     * consisting of the API key from the Google Developers Console is not present.\n     */\n    public static final int SAFE_BROWSING_MISSING_API_KEY = 12001;\n    /**\n     * An internal error occurred causing the call to {@code lookupUri(String, String, int...)} to be unavailable.\n     */\n    public static final int SAFE_BROWSING_API_NOT_AVAILABLE = 12002;\n    /**\n     * Verify Apps is not supported on this device.\n     */\n    public static final int VERIFY_APPS_NOT_AVAILABLE = 12003;\n    /**\n     * An internal error occurred while using the Verify Apps API.\n     */\n    public static final int VERIFY_APPS_INTERNAL_ERROR = 12004;\n    /**\n     * Cannot list potentially harmful apps because Verify Apps is not enabled.\n     * <p>\n     * The developer may call {@code enableVerifyApps()} to request the user turn on Verify Apps.\n     */\n    public static final int VERIFY_APPS_NOT_ENABLED = 12005;\n    /**\n     * User device SDK version is not supported.\n     */\n    public static final int UNSUPPORTED_SDK_VERSION = 12006;\n    /**\n     * Cannot start the reCAPTCHA service because site key parameter is not valid.\n     */\n    public static final int RECAPTCHA_INVALID_SITEKEY = 12007;\n    /**\n     * Cannot start the reCAPTCHA service because type of site key is not valid.\n     * <p>\n     * Please register new site key with the key type set to \"reCAPTCHA Android\"\n     */\n    public static final int RECAPTCHA_INVALID_KEYTYPE = 12008;\n    /**\n     * {@code lookupUri(String, String, int...)} called without first calling {@code initSafeBrowsing()}.\n     */\n    public static final int SAFE_BROWSING_API_NOT_INITIALIZED = 12009;\n    /**\n     * Cannot start the reCAPTCHA service because calling package name is not matched with site key.\n     * <p>\n     * Please add the new package name to your site key via reCAPTCHA Admin Console or choose to disable the package\n     * name validation for your key.\n     */\n    public static final int RECAPTCHA_INVALID_PACKAGE_NAME = 12013;\n}\n"
  },
  {
    "path": "play-services-safetynet/src/main/java/com/google/android/gms/safetynet/VerifyAppsConstants.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2021 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.safetynet;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Constants pertaining to the Verify Apps SafetyNet API.\n */\n@PublicApi\npublic class VerifyAppsConstants {\n    /**\n     * An action that is broadcasted when harmful apps are discovered.\n     */\n    public static final String ACTION_HARMFUL_APPS_FOUND = \"com.google.android.gms.safetynet.action.HARMFUL_APPS_FOUND\";\n    /**\n     * An action that is broadcasted when a harmful app is blocked from installation.\n     */\n    public static final String ACTION_HARMFUL_APP_BLOCKED = \"com.google.android.gms.safetynet.action.HARMFUL_APP_BLOCKED\";\n    /**\n     * An action that is broadcasted when a harmful app is installed.\n     */\n    public static final String ACTION_HARMFUL_APP_INSTALLED = \"com.google.android.gms.safetynet.action.HARMFUL_APP_INSTALLED\";\n\n    public static final int HARMFUL_CATEGORY_RANSOMWARE = 1;\n    public static final int HARMFUL_CATEGORY_PHISHING = 2;\n    public static final int HARMFUL_CATEGORY_TROJAN = 3;\n    public static final int HARMFUL_CATEGORY_UNCOMMON = 4;\n    public static final int HARMFUL_CATEGORY_FRAUDWARE = 5;\n    public static final int HARMFUL_CATEGORY_TOLL_FRAUD = 6;\n    public static final int HARMFUL_CATEGORY_WAP_FRAUD = 7;\n    public static final int HARMFUL_CATEGORY_CALL_FRAUD = 8;\n    public static final int HARMFUL_CATEGORY_BACKDOOR = 9;\n    public static final int HARMFUL_CATEGORY_SPYWARE = 10;\n    public static final int HARMFUL_CATEGORY_GENERIC_MALWARE = 11;\n    public static final int HARMFUL_CATEGORY_HARMFUL_SITE = 12;\n    public static final int HARMFUL_CATEGORY_WINDOWS_MALWARE = 13;\n    public static final int HARMFUL_CATEGORY_HOSTILE_DOWNLOADER = 14;\n    public static final int HARMFUL_CATEGORY_NON_ANDROID_THREAT = 15;\n    public static final int HARMFUL_CATEGORY_ROOTING = 16;\n    public static final int HARMFUL_CATEGORY_PRIVILEGE_ESCALATION = 17;\n    public static final int HARMFUL_CATEGORY_TRACKING = 18;\n    public static final int HARMFUL_CATEGORY_SPAM = 19;\n    public static final int HARMFUL_CATEGORY_DENIAL_OF_SERVICE = 20;\n    public static final int HARMFUL_CATEGORY_DATA_COLLECTION = 21;\n}\n"
  },
  {
    "path": "play-services-safetynet/src/main/java/org/microg/gms/safetynet/ISafetyNetCallbacksDefaultStub.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.safetynet;\n\nimport android.os.RemoteException;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.safetynet.AttestationData;\nimport com.google.android.gms.safetynet.HarmfulAppsData;\nimport com.google.android.gms.safetynet.HarmfulAppsInfo;\nimport com.google.android.gms.safetynet.RecaptchaResultData;\nimport com.google.android.gms.safetynet.RemoveHarmfulAppData;\nimport com.google.android.gms.safetynet.SafeBrowsingData;\nimport com.google.android.gms.safetynet.internal.ISafetyNetCallbacks;\n\nimport java.util.List;\n\npublic class ISafetyNetCallbacksDefaultStub extends ISafetyNetCallbacks.Stub {\n    @Override\n    public void onAttestationResult(Status status, AttestationData attestationData) throws RemoteException {\n    }\n\n    @Override\n    public void onSharedUuid(String s) throws RemoteException {\n    }\n\n    @Override\n    public void onSafeBrowsingData(Status status, SafeBrowsingData safeBrowsingData) throws RemoteException {\n    }\n\n    @Override\n    public void onVerifyAppsUserResult(Status status, boolean enabled) throws RemoteException {\n\n    }\n\n    @Override\n    public void onHarmfulAppsData(Status status, List<HarmfulAppsData> harmfulAppsData) throws RemoteException {\n    }\n\n    @Override\n    public void onRecaptchaResult(Status status, RecaptchaResultData recaptchaResultData) throws RemoteException {\n    }\n\n    @Override\n    public void onHarmfulAppsInfo(Status status, HarmfulAppsInfo harmfulAppsInfo) throws RemoteException {\n    }\n\n    @Override\n    public void onInitSafeBrowsingResult(Status status) throws RemoteException {\n    }\n\n    @Override\n    public void onRemoveHarmfulAppData(Status status, RemoveHarmfulAppData removeHarmfulAppData) throws RemoteException {\n    }\n}\n"
  },
  {
    "path": "play-services-safetynet/src/main/java/org/microg/gms/safetynet/SafetyNetApiImpl.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.safetynet;\n\nimport android.os.RemoteException;\n\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.PendingResult;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.safetynet.RecaptchaResultData;\nimport com.google.android.gms.safetynet.SafetyNet;\nimport com.google.android.gms.safetynet.SafetyNetApi;\nimport com.google.android.gms.safetynet.internal.ISafetyNetCallbacks;\n\nimport org.microg.gms.common.GmsConnector;\n\npublic class SafetyNetApiImpl implements SafetyNetApi {\n    @Override\n    public PendingResult<RecaptchaTokenResult> verifyWithRecaptcha(GoogleApiClient apiClient, String siteKey) {\n        return GmsConnector.call(apiClient, SafetyNet.API, (GmsConnector.Callback<SafetyNetGmsClient, RecaptchaTokenResult>) (client, resultProvider) -> client.verifyWithRecaptcha(new ISafetyNetCallbacksDefaultStub() {\n            @Override\n            public void onRecaptchaResult(Status status, RecaptchaResultData recaptchaResultData) throws RemoteException {\n                resultProvider.onResultAvailable(new RecaptchaTokenResult() {\n                    @Override\n                    public String getTokenResult() {\n                        return recaptchaResultData.token;\n                    }\n\n                    @Override\n                    public Status getStatus() {\n                        return status;\n                    }\n                });\n            }\n        }, siteKey));\n    }\n}\n"
  },
  {
    "path": "play-services-safetynet/src/main/java/org/microg/gms/safetynet/SafetyNetGmsClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.safetynet;\n\nimport android.content.Context;\nimport android.os.IBinder;\nimport android.os.RemoteException;\n\nimport com.google.android.gms.safetynet.internal.ISafetyNetCallbacks;\nimport com.google.android.gms.safetynet.internal.ISafetyNetService;\n\nimport org.microg.gms.common.GmsClient;\nimport org.microg.gms.common.GmsService;\nimport com.google.android.gms.common.api.internal.ConnectionCallbacks;\nimport com.google.android.gms.common.api.internal.OnConnectionFailedListener;\n\npublic class SafetyNetGmsClient extends GmsClient<ISafetyNetService> {\n    public SafetyNetGmsClient(Context context, ConnectionCallbacks callbacks, OnConnectionFailedListener connectionFailedListener) {\n        super(context, callbacks, connectionFailedListener, GmsService.SAFETY_NET.ACTION);\n        serviceId = GmsService.SAFETY_NET.SERVICE_ID;\n    }\n\n    public void attest(ISafetyNetCallbacks callbacks, byte[] nonce, String apiKey) throws RemoteException {\n        getServiceInterface().attestWithApiKey(callbacks, nonce, apiKey);\n    }\n\n    public void verifyWithRecaptcha(ISafetyNetCallbacks callbacks, String siteKey) throws RemoteException {\n        getServiceInterface().verifyWithRecaptcha(callbacks, siteKey);\n    }\n\n    public void enableVerifyApps(ISafetyNetCallbacks callbacks) throws RemoteException {\n        getServiceInterface().enableVerifyApps(callbacks);\n    }\n\n    public void isVerifyAppsEnabled(ISafetyNetCallbacks callbacks) throws RemoteException {\n        getServiceInterface().isVerifyAppsEnabled(callbacks);\n    }\n\n    @Override\n    protected ISafetyNetService interfaceFromBinder(IBinder binder) {\n        return ISafetyNetService.Stub.asInterface(binder);\n    }\n}\n"
  },
  {
    "path": "play-services-tapandpay/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\nandroid {\n    namespace \"com.google.android.gms.tapandpay\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n}\n\n// Nothing to publish yet\n//apply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG API for play-services-tapandpay'\n\ndependencies {\n    api project(':play-services-base')\n\n    implementation \"androidx.annotation:annotation:$annotationVersion\"\n\n    annotationProcessor project(':safe-parcel-processor')\n}\n"
  },
  {
    "path": "play-services-tapandpay/core/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'kotlin-android'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\ndependencies {\n    api project(':play-services-tapandpay')\n\n    implementation project(':play-services-base-core')\n\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion\"\n    implementation \"org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutineVersion\"\n    implementation \"org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutineVersion\"\n}\n\nandroid {\n    namespace \"org.microg.gms.tapandpay.core\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    sourceSets {\n        main {\n            java.srcDirs = ['src/main/kotlin']\n        }\n    }\n\n    lintOptions {\n        disable 'MissingTranslation'\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n\n    kotlinOptions {\n        jvmTarget = 1.8\n    }\n}\n\n// Nothing to publish yet\n//apply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG service implementation for play-services-tapandpay'\n"
  },
  {
    "path": "play-services-tapandpay/core/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2021, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <application>\n        <service android:name=\"org.microg.gms.tapandpay.TapAndPayService\"\n                 android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.tapandpay.service.BIND\"/>\n            </intent-filter>\n        </service>\n    </application>\n</manifest>\n"
  },
  {
    "path": "play-services-tapandpay/core/src/main/kotlin/org/microg/gms/tapandpay/TapAndPayService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage org.microg.gms.tapandpay\n\nimport android.app.KeyguardManager\nimport android.content.Context\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.Bundle\nimport android.os.Parcel\nimport android.util.Base64\nimport android.util.Log\nimport android.util.SparseArray\nimport androidx.core.content.getSystemService\nimport com.google.android.gms.common.Feature\nimport com.google.android.gms.common.api.ApiMetadata\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.internal.ConnectionInfo\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport com.google.android.gms.tapandpay.TapAndPayStatusCodes.TAP_AND_PAY_NO_ACTIVE_WALLET\nimport com.google.android.gms.tapandpay.firstparty.AccountInfo\nimport com.google.android.gms.tapandpay.firstparty.GetActiveAccountResponse\nimport com.google.android.gms.tapandpay.firstparty.GetAllCardsResponse\nimport com.google.android.gms.tapandpay.firstparty.GetSecurityParamsResponse\nimport com.google.android.gms.tapandpay.firstparty.IsDeviceRecentlyUnlockedRequest\nimport com.google.android.gms.tapandpay.firstparty.IsDeviceRecentlyUnlockedResponse\nimport com.google.android.gms.tapandpay.firstparty.LogUserCurrentScreenRequest\nimport com.google.android.gms.tapandpay.firstparty.RefreshSeCardsResponse\nimport com.google.android.gms.tapandpay.firstparty.RegisterServiceListenerRequest\nimport com.google.android.gms.tapandpay.internal.ITapAndPayService\nimport com.google.android.gms.tapandpay.internal.ITapAndPayServiceCallbacks\nimport com.google.android.gms.tapandpay.internal.firstparty.GetActiveAccountRequest\nimport com.google.android.gms.tapandpay.internal.firstparty.GetAllCardsRequest\nimport com.google.android.gms.tapandpay.internal.firstparty.IsDeviceUnlockedForPaymentRequest\nimport com.google.android.gms.tapandpay.internal.firstparty.RefreshSeCardsRequest\nimport com.google.android.gms.tapandpay.internal.firstparty.SetActiveAccountRequest\nimport com.google.android.gms.tapandpay.internal.firstparty.SetSelectedTokenRequest\nimport com.google.android.gms.tapandpay.issuer.ListTokensRequest\nimport com.google.android.gms.tapandpay.issuer.PushTokenizeRequest\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.common.GooglePackagePermission\nimport org.microg.gms.common.PackageUtils\nimport org.microg.gms.utils.ExtendedPackageInfo\nimport org.microg.gms.utils.toBase64\nimport org.microg.gms.utils.warnOnTransactionIssues\n\nprivate const val TAG = \"GmsTapAndPay\"\n\nclass TapAndPayService : BaseService(TAG, GmsService.WALLET_TAP_AND_PAY) {\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        val packageName = PackageUtils.getAndCheckCallingPackage(this, request.packageName)\n            ?: throw IllegalArgumentException(\"Missing package name\")\n        callback.onPostInitCompleteWithConnectionInfo(CommonStatusCodes.SUCCESS, TapAndPayImpl(this, packageName), ConnectionInfo().apply {\n            features = arrayOf(\n                Feature(\"tapandpay\", 1),\n                Feature(\"tapandpay_account_linking\", 1),\n                Feature(\"tapandpay_add_service_listener\", 1),\n                Feature(\"tapandpay_backup_and_restore_tokenize\", 1),\n                Feature(\"tapandpay_block_payment_cards\", 1),\n                Feature(\"tapandpay_check_contactless_eligibility\", 1),\n                Feature(\"tapandpay_check_notification_governance\", 1),\n                Feature(\"tapandpay_dismiss_quick_access_wallet\", 1),\n                Feature(\"tapandpay_enable_secure_keyguard\", 1),\n                Feature(\"tapandpay_felica_tos\", 1),\n                Feature(\"tapandpay_get_active_wallet_infos\", 1L),\n                Feature(\"tapandpay_get_all_cards_for_account\", 1),\n                Feature(\"tapandpay_get_contactless_setup_configuration\", 1),\n                Feature(\"tapandpay_get_data_for_backup\", 1),\n                Feature(\"tapandpay_get_environment\", 1L),\n                Feature(\"tapandpay_get_last_attestation_result\", 1),\n                Feature(\"tapandpay_get_quick_access_tile_status\", 1),\n                Feature(\"tapandpay_get_stable_hardware_id\", 1L),\n                Feature(\"tapandpay_get_token_details\", 1L),\n                Feature(\"tapandpay_get_token_status\", 1L),\n                Feature(\"tapandpay_global_actions\", 1),\n                Feature(\"tapandpay_has_eligible_tokenization_target\", 1L),\n                Feature(\"tapandpay_issuer_api\", 2),\n                Feature(\"tapandpay_issuer_tokenize\", 1),\n                Feature(\"tapandpay_override_payment_network\", 3L),\n                Feature(\"tapandpay_get_parental_consent_intent\", 1L),\n                Feature(\"tapandpay_set_supervised_child_account_type_and_reset_onboarding_info\", 1L),\n                Feature(\"tapandpay_get_is_supervised_child_wallet_user\", 1L),\n                Feature(\"tapandpay_perform_secure_element_management_operation\", 1L),\n                Feature(\"tapandpay_perform_tokenization_operation\", 1L),\n                Feature(\"tapandpay_polling_frame_handler\", 1L),\n                Feature(\"tapandpay_push_tokenize_session\", 6),\n                Feature(\"tapandpay_push_tokenize\", 1L),\n                Feature(\"tapandpay_quick_access_wallet\", 1),\n                Feature(\"tapandpay_report_unlock\", 1L),\n                Feature(\"tapandpay_request_delete_token\", 1L),\n                Feature(\"tapandpay_request_select_token\", 1L),\n                Feature(\"tapandpay_secureelement\", 1),\n                Feature(\"tapandpay_send_wear_request_to_phone\", 1),\n                Feature(\"tapandpay_settings\", 2L),\n                Feature(\"tapandpay_screen_logging\", 1L),\n                Feature(\"tapandpay_show_wear_card_management_view\", 1),\n                Feature(\"tapandpay_sync_device_info\", 1),\n                Feature(\"tapandpay_token_listing\", 3),\n                Feature(\"tapandpay_token_listing_with_request\", 1),\n                Feature(\"tapandpay_tokenize_account\", 1),\n                Feature(\"tapandpay_tokenize_cache\", 1),\n                Feature(\"tapandpay_tokenize_pan\", 1),\n                Feature(\"tapandpay_transmission_event\", 1),\n                Feature(\"tapandpay_wallet_feedback_psd\", 1),\n                Feature(\"tapandpay_wallet_set_tap_doodle_enabled\", 1L),\n                Feature(\"tapandpay_wallet_ui_shown_status\", 1L),\n                Feature(\"tapandpay_set_receives_ineligible_card_notification\", 1L)\n            )\n        })\n    }\n}\n\nclass TapAndPayImpl(private val context: Context, private val packageName: String) : ITapAndPayService.Stub() {\n\n    private val isFirstParty\n        get() = ExtendedPackageInfo(context, packageName).hasGooglePackagePermission(GooglePackagePermission.WALLET)\n\n    private var accountId: String? = null\n    private var accountName: String? = null\n\n    override fun setSelectedToken(request: SetSelectedTokenRequest?, callbacks: ITapAndPayServiceCallbacks?, apiMetadata: ApiMetadata?) {\n        if (!isFirstParty) {\n            callbacks?.onSetSelectedTokenResponse(Status.INTERNAL_ERROR)\n            return\n        }\n        Log.d(TAG, \"Not yet implemented: setSelectedToken($request)\")\n        callbacks?.onSetSelectedTokenResponse(Status.SUCCESS)\n    }\n\n    override fun getAllCards(request: GetAllCardsRequest?, callbacks: ITapAndPayServiceCallbacks, metadata: ApiMetadata?) {\n        Log.d(TAG, \"getAllCards()\")\n        callbacks.onGetAllCardsResponse(Status.SUCCESS, GetAllCardsResponse(emptyArray(), null, null, null, SparseArray(), ByteArray(0)))\n    }\n\n    override fun setActiveAccount(request: SetActiveAccountRequest?, callbacks: ITapAndPayServiceCallbacks?, metadata: ApiMetadata?) {\n        if (!isFirstParty) {\n            callbacks?.onSetActiveAccountResponse(Status.INTERNAL_ERROR)\n            return\n        }\n        Log.d(TAG, \"setActiveAccount(${request?.accountName})\")\n        this.accountId = request?.accountName // TODO: Get actual account id\n        this.accountName = request?.accountName\n        callbacks?.onSetActiveAccountResponse(Status.SUCCESS)\n    }\n\n    override fun getActiveAccount(request: GetActiveAccountRequest?, callbacks: ITapAndPayServiceCallbacks?, metadata: ApiMetadata?) {\n        if (!isFirstParty) {\n            callbacks?.onGetActiveAccountResponse(Status.INTERNAL_ERROR, null)\n            return\n        }\n        val accountInfo = accountId?.let { AccountInfo(accountId, accountName, 1) }\n        Log.d(TAG, \"getActiveAccount() = $accountInfo\")\n        callbacks?.onGetActiveAccountResponse(Status.SUCCESS, GetActiveAccountResponse(accountInfo))\n    }\n\n    override fun registerDataChangedListener(callbacks: ITapAndPayServiceCallbacks, metadata: ApiMetadata?) {\n        Log.d(TAG, \"registerDataChangedListener()\")\n        callbacks.onStatus(Status.SUCCESS)\n    }\n\n    override fun isDeviceUnlockedForPayment(request: IsDeviceUnlockedForPaymentRequest?, callbacks: ITapAndPayServiceCallbacks?, apiMetadata: ApiMetadata?) {\n        if (!isFirstParty) {\n            callbacks?.onHandleStatusPendingIntent(Status.INTERNAL_ERROR, null)\n            return\n        }\n        Log.d(TAG, \"isDeviceUnlockedForPayment($request) = true\")\n        callbacks?.onIsDeviceUnlockedForPaymentResponse(Status.SUCCESS, true)\n    }\n\n    override fun getActiveWalletId(callbacks: ITapAndPayServiceCallbacks, metadata: ApiMetadata?) {\n        Log.d(TAG, \"getActiveWalletId: \")\n        callbacks.onGetActiveWalletIdResponse(Status(TAP_AND_PAY_NO_ACTIVE_WALLET), \"\")\n    }\n\n    override fun getTokenStatus(tokenProvider: Int, issuerTokenId: String, callbacks: ITapAndPayServiceCallbacks, metadata: ApiMetadata?) {\n        Log.d(TAG, \"getTokenStatus($tokenProvider, $issuerTokenId)\")\n        callbacks.onGetTokenStatusResponse(Status(TAP_AND_PAY_NO_ACTIVE_WALLET), null)\n    }\n\n    override fun pushTokenize(request: PushTokenizeRequest?, callbacks: ITapAndPayServiceCallbacks?, apiMetadata: ApiMetadata?) {\n        Log.d(TAG, \"Not yet implemented: pushTokenize($request)\")\n        callbacks?.onHandleStatusPendingIntent(Status(TAP_AND_PAY_NO_ACTIVE_WALLET), null)\n    }\n\n    override fun createWallet(callbacks: ITapAndPayServiceCallbacks?, apiMetadata: ApiMetadata?) {\n        Log.d(TAG, \"Not yet implemented: createWallet\")\n        callbacks?.onHandleStatusPendingIntent(Status(CommonStatusCodes.RESOLUTION_REQUIRED, null, ), Bundle.EMPTY)\n    }\n\n    override fun getStableHardwareId(callbacks: ITapAndPayServiceCallbacks, metadata: ApiMetadata?) {\n        Log.d(TAG, \"getStableHardwareId()\")\n        callbacks.onGetStableHardwareIdResponse(Status.SUCCESS, \"\")\n    }\n\n    override fun getSecurityParams(callbacks: ITapAndPayServiceCallbacks?, apiMetadata: ApiMetadata?) {\n        if (!isFirstParty) {\n            callbacks?.onGetSecurityParamsResponse(Status.INTERNAL_ERROR, GetSecurityParamsResponse(false, false, false, false))\n            return\n        }\n        val isDeviceSecure = runCatching { SDK_INT >= 23 && (context.getSystemService<KeyguardManager>()?.isDeviceSecure ?: false) }.getOrDefault(false)\n        Log.d(TAG, \"getSecurityParams() = $isDeviceSecure\")\n        callbacks?.onGetSecurityParamsResponse(Status.SUCCESS, GetSecurityParamsResponse(isDeviceSecure, false, false, false))\n    }\n\n    override fun refreshSeCards(request: RefreshSeCardsRequest?, callbacks: ITapAndPayServiceCallbacks, metadata: ApiMetadata?) {\n        Log.d(TAG, \"refreshSeCards()\")\n        callbacks.onRefreshSeCardsResponse(Status.SUCCESS, RefreshSeCardsResponse())\n    }\n\n    override fun listTokensDefault(callbacks: ITapAndPayServiceCallbacks, metadata: ApiMetadata?) {\n        listTokens(ListTokensRequest(), callbacks, metadata)\n    }\n\n    override fun tokenization(data: ByteArray?, callbacks: ITapAndPayServiceCallbacks?, apiMetadata: ApiMetadata?) {\n        if (!isFirstParty) {\n            callbacks?.onByteArray(Status.INTERNAL_ERROR, byteArrayOf())\n            return\n        }\n        Log.d(TAG, \"Not yet implemented: tokenization(${data?.toBase64(Base64.NO_WRAP)})\")\n        callbacks?.onByteArray(Status(CommonStatusCodes.DEVELOPER_ERROR, \"Unimplemented\"), byteArrayOf())\n    }\n\n    override fun registerServiceListener(request: RegisterServiceListenerRequest?, callbacks: ITapAndPayServiceCallbacks?, apiMetadata: ApiMetadata?) {\n        Log.d(TAG, \"Not yet implemented: registerServiceListener($request)\")\n        callbacks?.onStatus(Status.SUCCESS)\n    }\n\n    override fun unregisterServiceListener(request: RegisterServiceListenerRequest?, callbacks: ITapAndPayServiceCallbacks?, apiMetadata: ApiMetadata?) {\n        Log.d(TAG, \"Not yet implemented: unregisterServiceListener($request)\")\n        callbacks?.onStatus(Status.SUCCESS)\n    }\n\n    override fun listTokens(request: ListTokensRequest?, callbacks: ITapAndPayServiceCallbacks, metadata: ApiMetadata?) {\n        Log.d(TAG, \"listTokens($request)\")\n        callbacks.onListTokensResponse(Status.SUCCESS, emptyArray())\n    }\n\n    override fun getIsSupervisedChildWalletUser(callbacks: ITapAndPayServiceCallbacks?, apiMetadata: ApiMetadata?) {\n        if (!isFirstParty) {\n            callbacks?.onGetIsSupervisedChildWalletUserResponse(Status.INTERNAL_ERROR, false)\n            return\n        }\n        Log.d(TAG, \"getIsSupervisedChildWalletUser() = false\")\n        callbacks?.onGetIsSupervisedChildWalletUserResponse(Status.SUCCESS, false)\n    }\n\n    override fun logUserCurrentScreen(request: LogUserCurrentScreenRequest?, callbacks: ITapAndPayServiceCallbacks?, apiMetadata: ApiMetadata?) {\n        if (!isFirstParty) {\n            callbacks?.onStatus(Status.INTERNAL_ERROR)\n            return\n        }\n        Log.d(TAG, \"logUserCurrentScreen($request)\")\n        callbacks?.onStatus(Status.SUCCESS)\n    }\n\n    override fun isDeviceRecentlyUnlocked(request: IsDeviceRecentlyUnlockedRequest?, callbacks: ITapAndPayServiceCallbacks?, apiMetadata: ApiMetadata?) {\n        if (!isFirstParty) {\n            callbacks?.onIsDeviceRecentlyUnlockedResponse(Status.INTERNAL_ERROR, null)\n            return\n        }\n        Log.d(TAG, \"isDeviceRecentlyUnlocked($request) = true\")\n        callbacks?.onIsDeviceRecentlyUnlockedResponse(Status.SUCCESS, IsDeviceRecentlyUnlockedResponse(true))\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =\n        warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2021, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest />\n"
  },
  {
    "path": "play-services-tapandpay/src/main/aidl/com/google/android/gms/tapandpay/firstparty/GetActiveAccountResponse.aidl",
    "content": "package com.google.android.gms.tapandpay.firstparty;\n\nparcelable GetActiveAccountResponse;"
  },
  {
    "path": "play-services-tapandpay/src/main/aidl/com/google/android/gms/tapandpay/firstparty/GetAllCardsResponse.aidl",
    "content": "package com.google.android.gms.tapandpay.firstparty;\n\nparcelable GetAllCardsResponse;"
  },
  {
    "path": "play-services-tapandpay/src/main/aidl/com/google/android/gms/tapandpay/firstparty/GetSecurityParamsResponse.aidl",
    "content": "package com.google.android.gms.tapandpay.firstparty;\n\nparcelable GetSecurityParamsResponse;"
  },
  {
    "path": "play-services-tapandpay/src/main/aidl/com/google/android/gms/tapandpay/firstparty/IsDeviceRecentlyUnlockedRequest.aidl",
    "content": "package com.google.android.gms.tapandpay.firstparty;\n\nparcelable IsDeviceRecentlyUnlockedRequest;"
  },
  {
    "path": "play-services-tapandpay/src/main/aidl/com/google/android/gms/tapandpay/firstparty/IsDeviceRecentlyUnlockedResponse.aidl",
    "content": "package com.google.android.gms.tapandpay.firstparty;\n\nparcelable IsDeviceRecentlyUnlockedResponse;"
  },
  {
    "path": "play-services-tapandpay/src/main/aidl/com/google/android/gms/tapandpay/firstparty/LogUserCurrentScreenRequest.aidl",
    "content": "package com.google.android.gms.tapandpay.firstparty;\n\nparcelable LogUserCurrentScreenRequest;"
  },
  {
    "path": "play-services-tapandpay/src/main/aidl/com/google/android/gms/tapandpay/firstparty/RefreshSeCardsResponse.aidl",
    "content": "package com.google.android.gms.tapandpay.firstparty;\n\nparcelable RefreshSeCardsResponse;"
  },
  {
    "path": "play-services-tapandpay/src/main/aidl/com/google/android/gms/tapandpay/firstparty/RegisterServiceListenerRequest.aidl",
    "content": "package com.google.android.gms.tapandpay.firstparty;\n\nparcelable RegisterServiceListenerRequest;"
  },
  {
    "path": "play-services-tapandpay/src/main/aidl/com/google/android/gms/tapandpay/firstparty/TokenStatus.aidl",
    "content": "package com.google.android.gms.tapandpay.firstparty;\n\nparcelable TokenStatus;\n"
  },
  {
    "path": "play-services-tapandpay/src/main/aidl/com/google/android/gms/tapandpay/internal/ITapAndPayService.aidl",
    "content": "package com.google.android.gms.tapandpay.internal;\n\nimport com.google.android.gms.common.api.ApiMetadata;\nimport com.google.android.gms.tapandpay.firstparty.IsDeviceRecentlyUnlockedRequest;\nimport com.google.android.gms.tapandpay.firstparty.LogUserCurrentScreenRequest;\nimport com.google.android.gms.tapandpay.firstparty.RegisterServiceListenerRequest;\nimport com.google.android.gms.tapandpay.internal.ITapAndPayServiceCallbacks;\nimport com.google.android.gms.tapandpay.internal.firstparty.GetActiveAccountRequest;\nimport com.google.android.gms.tapandpay.internal.firstparty.GetAllCardsRequest;\nimport com.google.android.gms.tapandpay.internal.firstparty.RefreshSeCardsRequest;\nimport com.google.android.gms.tapandpay.internal.firstparty.IsDeviceUnlockedForPaymentRequest;\nimport com.google.android.gms.tapandpay.internal.firstparty.SetActiveAccountRequest;\nimport com.google.android.gms.tapandpay.internal.firstparty.SetSelectedTokenRequest;\nimport com.google.android.gms.tapandpay.issuer.ListTokensRequest;\nimport com.google.android.gms.tapandpay.issuer.PushTokenizeRequest;\n\ninterface ITapAndPayService {\n    void setSelectedToken(in SetSelectedTokenRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 0;\n    void getAllCards(in GetAllCardsRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 1;\n//    void deleteToken(in DeleteTokenRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 2;\n//    void firstPartyTokenizePan(in FirstPartyTokenizePanRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 3;\n    void setActiveAccount(in SetActiveAccountRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 4;\n\n\n//    void showSecurityPrompt(in ShowSecurityPromptRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 7;\n    void getActiveAccount(in GetActiveAccountRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 8;\n    void registerDataChangedListener(ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 9;\n    void isDeviceUnlockedForPayment(in IsDeviceUnlockedForPaymentRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 10;\n//    void promptDeviceUnlockForPayment(in PromptDeviceUnlockForPaymentRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 11;\n//    void sendTapEvent(in SendTapEventRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 12;\n//    void getReceivesTransactionNotification(in GetReceivesTransactionNotificationsRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 13;\n//    void setReceivesTransactionNotification(in SetReceivesTransactionNotificationsRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 14;\n//    void retrieveInAppPaymentCredential(in RetrieveInAppPaymentCredentialRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 15;\n\n//    void getActiveCardsForAccount(in GetActiveCardsForAccountRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 17;\n\n//    void getAnalyticsContext(ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 19;\n    void getActiveWalletId(ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 20;\n    void getTokenStatus(int tokenProvider, String issuerTokenId, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 21;\n//    void issuerTokenize(int tokenProvider, String issuerTokenId, String s2, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 22;\n//    void requestSelectToken(int tokenProvider, String issuerTokenId, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 23;\n//    void requestDeleteToken(int tokenProvider, String issuerTokenId, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 24;\n//    void isDeviceUnlockedForInAppPayment(in IsDeviceUnlockedForInAppPaymentRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 25;\n//    void reportInAppTransactionCompleted(in ReportInAppTransactionCompletedRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 26;\n    void pushTokenize(in PushTokenizeRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 27;\n    void createWallet(ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 28;\n    void getStableHardwareId(ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 29;\n//    void getEnvironment(ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 30;\n//    void enablePayOnWear(in EnablePayOnWearRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 31;\n//    void isPayPalAvailable(ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 32;\n    void getSecurityParams(ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 34;\n\n//    void getNotificationSettings(in GetNotificationSettingsRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 36;\n//    void setNotificationSettings(in SetNotificationSettingsRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 37;\n//    void addOtherPaymentOption(in AddOtherPaymentOptionRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 38;\n//    void getAvailableOtherPaymentMethods(in GetAvailableOtherPaymentMethodsRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 39;\n//    void keyguardDismissed(ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 40;\n//    void reportInAppManualUnlock(ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 41;\n//    Status enableNfc(in ApiMetadata apiMetadata) = 42;\n\n\n\n\n\n//    void getSeChipTransactions(in GetSeChipTransactionsRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 48;\n//    void deleteDataForTests(ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 49;\n\n\n//    void disableSelectedToken(in DisableSelectedTokenRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 52;\n//    void setFelicaTosAcceptance(in SetFelicaTosAcceptanceRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 53;\n//    void getFelicaTosAcceptance(in GetFelicaTosAcceptanceRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 54;\n//    void fun55(in byte[] data, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 55;\n    void refreshSeCards(in RefreshSeCardsRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 56;\n//    void tokenizeAccount(in TokenizeAccountRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 57;\n//    void getGlobalActionCards(in GetGlobalActionCardsRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 58;\n//    void selectGlobalActionCard(in SelectGlobalActionCardRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 59;\n//    void fun60(string data, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 60;\n//    void fun61(long data, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 61;\n//    void fun62(ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 62;\n\n//    void syncDeviceInfo(in SyncDeviceInfoRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 64;\n//    void sendTransmissionEvent(in SendTransmissionEventRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 65;\n//    void createPushProvisionSession(in CreatePushProvisionSessionRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 66;\n//    void serverPushProvision(in ServerPushProvisionRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 67;\n//    void getLastAttestationResult(in GetLastAttestationResultRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 68;\n//    void dismissQuickAccessWallet(ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 69;\n//    void getQuickAccessWalletConfig(in GetQuickAccessWalletConfigRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 70;\n//    void setQuickAccessWalletCards(in SetQuickAccessWalletCardsRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 71;\n//    void getContactlessSetupStatus(in GetContactlessSetupStatusRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 72;\n    void listTokensDefault(ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 73;\n//    void isTokenized(in IsTokenizedRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 74;\n//    void checkContactlessEligibility(in CheckContactlessEligibilityRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 75;\n//    void showWearCardManagementView(ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 76;\n    void tokenization(in byte[] data, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 77;\n//    void viewToken(in ViewTokenRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 78;\n//    void sendWearRequestToPairedDevice(in byte[] data, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 79;\n//    void psdLogs(in byte[] data, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 80;\n//    void getTokenDetails(in GetTokenDetailsRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 81;\n//    void setTapDoodleEnabled(in SetTapDoodleEnabledRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 82;\n//    void reportWalletUiShowedTime(ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 83;\n//    void checkWalletUiRecentlyShowed(ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 84;\n//    void reportUnlock(in reportUnlock request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 85;\n//    void enableSecureKeyguard(in EnableSecureKeyguardRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 86;\n//    void setTapAndPaySettings(in SetTapAndPaySettingsRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 87;\n//    void getTapAndPaySettings(in GetTapAndPaySettingsRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 88;\n//    void setOverridePaymentNetwork(in SetOverridePaymentNetworkRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 89;\n//    void getOverridePaymentNetwork(in GetOverridePaymentNetworkRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 90;\n//    void hasEligibleTokenizationTarget(in HasEligibleTokenizationTargetRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 91;\n//    void tokenize(in TokenizeRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 92;\n    void registerServiceListener(in RegisterServiceListenerRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 93;\n    void unregisterServiceListener(in RegisterServiceListenerRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 94;\n//    void getActiveWalletInfos(ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 95;\n//    void managedSecureElement(in byte[] data, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 96;\n//    void getCobadgedShowPaymentNetworkToggle(in GetCobadgedShowPaymentNetworkToggleRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 97;\n//    void requestDeleteToken(in RequestDeleteTokenRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 98;\n//    void requestSelectToken(in RequestSelectTokenRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 99;\n//    void getTokenStatus(in GetTokenStatusRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 100;\n    void listTokens(in ListTokensRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 101;\n//    void getStableHardwareId(in GetStableHardwareIdRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 102;\n//    void getEnvironment(in GetEnvironmentRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 103;\n//    void getParentalConsentIntent(in GetParentalConsentIntentRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 104;\n    void getIsSupervisedChildWalletUser(ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 105;\n//    void getQuickAccessTileStatus(in byte[] data, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 106;\n//    void backupAndRestoreTokenize(in BackupAndRestoreTokenizeRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 107;\n//    void setReceivesIneligibleCardNotification(in SetReceivesIneligibleCardNotificationRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 108;\n//    void getDataForBackup(in GetDataForBackupRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 109;\n//    void checkNotificationGovernance(in byte[] data, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 110;\n//    void sendPollingFrameHandlerEvent(in SendPollingFrameHandlerEventRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 111;\n//    void getPollingFrameHandlerEvent(ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 112;\n//    void setSupervisedChildAccountTypeAndResetOnboardingInfo(in SetSupervisedChildAccountTypeAndResetOnboardingInfoRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 113;\n    void logUserCurrentScreen(in LogUserCurrentScreenRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 114;\n    void isDeviceRecentlyUnlocked(in IsDeviceRecentlyUnlockedRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 115;\n//    void sendWearRequestToPairedDeviceWithString(String data1, in byte[] data2, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 116;\n//    void unifiedTokenization(in UnifiedTokenizationRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 117;\n//    void checkStorageKeyLocally(ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 118;\n//    void setDataStoreEnvironment(in SetDataStoreEnvironmentRequest request, ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 119;\n//    void getPendingPushProvisioningToken(ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 120;\n//    void fun121(ITapAndPayServiceCallbacks callbacks, in ApiMetadata apiMetadata) = 121;\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/aidl/com/google/android/gms/tapandpay/internal/ITapAndPayServiceCallbacks.aidl",
    "content": "package com.google.android.gms.tapandpay.internal;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.tapandpay.firstparty.GetActiveAccountResponse;\nimport com.google.android.gms.tapandpay.firstparty.GetAllCardsResponse;\nimport com.google.android.gms.tapandpay.firstparty.GetSecurityParamsResponse;\nimport com.google.android.gms.tapandpay.firstparty.IsDeviceRecentlyUnlockedResponse;\nimport com.google.android.gms.tapandpay.firstparty.RefreshSeCardsResponse;\nimport com.google.android.gms.tapandpay.issuer.TokenStatus;\nimport com.google.android.gms.tapandpay.issuer.TokenInfo;\n\ninterface ITapAndPayServiceCallbacks {\n    void onSetSelectedTokenResponse(in Status status) = 1;\n    void onHandleStatusPendingIntent(in Status status, in Bundle data) = 2;\n    void onGetAllCardsResponse(in Status status, in GetAllCardsResponse response) = 3;\n    void onDeleteTokenResponse(in Status status) = 4;\n    void onSetActiveAccountResponse(in Status status) = 5;\n\n    void onGetActiveAccountResponse(in Status status, in GetActiveAccountResponse response) = 7;\n    void onStatus(in Status status) = 8;\n    void onDataChanged() = 9;\n    void onIsDeviceUnlockedForPaymentResponse(in Status status, boolean response) = 10;\n    void onSendEventOperationResponse(in Status status) = 11;\n    void onGetReceivesTransactionNotificationsResponse(in Status status, boolean response) = 12;\n    void onSetReceivesTransactionNotificationsResponse(in Status status) = 13;\n//    void onGetActiveCardsForAccountResponse(in Status status, in GetActiveCardsForAccountResponse response) = 14;\n//    void onRetrieveInAppPaymentCredentialResponse(in Status status, in RetrieveInAppPaymentCredentialResponse response) = 16;\n    void onGetAnalyticsContextResponse(in Status status, String response) = 17;\n    void onGetActiveWalletIdResponse(in Status status, String response) = 18;\n    void onGetTokenStatusResponse(in Status status, in TokenStatus response) = 19;\n    void onIsDeviceUnlockedForInAppPaymentResponse(in Status status, boolean response) = 20;\n    void onReportInAppTransactionCompletedResponse(in Status status) = 21;\n    void onGetStableHardwareIdResponse(in Status status, String response) = 22;\n    void onGetEnvironmentResponse(in Status status, String response) = 23;\n    void onEnablePayOnWearResponse(in Status status) = 24;\n    void onIsPayPalAvailableResponse(in Status status, boolean IsPayPalAvailable) = 25;\n    void onGetSecurityParamsResponse(in Status status, in GetSecurityParamsResponse response) = 26;\n//    void onGetNotificationSettingsResponse(in Status status, in GetNotificationSettingsResponse response) = 27;\n    void onSetNotificationSettingsResponse(in Status status) = 28;\n//    void onGetAvailableOtherPaymentMethodsResponse(in Status status, in GetAvailableOtherPaymentMethodsResponse response) = 29;\n//    void onActiveTokensForAccountRetrieved(in Status status, in GetActiveTokensForAccountResponse response) = 30;\n//    void onGetSeChipTransactionsResponse(in Status status, in GetSeChipTransactionsResponse response) = 34;\n//    void onReserveResourceResponse(in Status status, in ReserveResourceResponse response) = 35;\n    void onReleaseResourceResponse(in Status status) = 36;\n    void onDisableSelectedTokenResponse(in Status status) = 37;\n//    void onGetFelicaTosAcceptanceResponse(in Status status, in GetFelicaTosAcceptanceResponse response) = 38;\n    void onSetFelicaTosAcceptanceResponse(in Status status) = 39;\n    void onRefreshSeCardsResponse(in Status status, in RefreshSeCardsResponse response) = 40;\n//    void onGetGlobalActionCardsResponse(in Status status, in GetGlobalActionCardsResponse response) = 41;\n    void onGetLinkingTokenResponse(in Status status, String response) = 42;\n    void onBlockPaymentCardsResponse(in Status status) = 43;\n    void onUnblockPaymentCardsResponse(in Status status) = 44;\n//    void onGetLastAttestationResultResponse(in Status status, in GetLastAttestationResultResponse response) = 45;\n//    void onGetQuickAccessWalletConfigResponse(in Status status, in QuickAccessWalletConfig config) = 46;\n//    void onGetContactlessSetupStatusResponse(in Status status, in GetContactlessSetupStatusResponse response) = 47;\n    void onIsTokenizedResponse(in Status status, boolean response) = 48;\n    void onListTokensResponse(in Status status, in TokenInfo[] response) = 49;\n//    void onCheckContactlessEligibilityResponse(in Status status, in CheckContactlessEligibilityResponse response) = 50;\n    void onByteArray(in Status status, in byte[] proto) = 51;\n//    void onCreatePushProvisionSessionResponse(in Status status, in PushProvisionSessionContext response) = 52;\n    void onTokenPanRetrieved(in Status status, String tokenPan) = 53;\n//    void onCheckWalletUiRecentlyShowedResponse(in Status status, boolean response) = 54;\n//    void onGetPaySettingsResponse(in Status status, in GetTapAndPaySettingsResponse response) = 55;\n//    void onSetOverridePaymentNetworkResponse(in Status status) = 56;\n//    void onGetOverridePaymentNetworkResponse(in Status status, String response) = 57;\n//    void onHasEligibleTokenizationTargetResponse(in Status status, boolean response) = 58;\n//    void onGetActiveWalletInfosResponse(in Status status, in ReachableDeviceWalletInfo[] response) = 59;\n//    void onGetCobadgedShowPaymentNetworkToggleResponse(in Status status, boolean response) = 60;\n//    void onGetParentalConsentIntentResponse(in Status status, in Intent intent) = 61;\n    void onGetIsSupervisedChildWalletUserResponse(in Status status, boolean response) = 62;\n//    void onSetReceivesIneligibleCardNotificationResponse(in Status status) = 63;\n\n//    void onGetPollingFrameHandlerEventResponse(in Status status, in GetPollingFrameHandlerStateResponse response) = 65;\n//    void onSetSupervisedChildAccountTypeAndResetOnboardingInfoResponse(in Status status) = 66;\n    void onIsDeviceRecentlyUnlockedResponse(in Status status, in IsDeviceRecentlyUnlockedResponse response) = 67;\n\n//    void onCheckStorageKeyLocallyResponse(in Status status, boolean response) = 69;\n//    void onGetPendingPushProvisioningTokenResponse(in Status status, in GetPendingPushProvisioningTokenResponse response) = 70;\n//    void onGetIsSupervisedWalletUserResponse(Status status, boolean response) = 71;\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/aidl/com/google/android/gms/tapandpay/internal/firstparty/GetActiveAccountRequest.aidl",
    "content": "package com.google.android.gms.tapandpay.internal.firstparty;\n\nparcelable GetActiveAccountRequest;"
  },
  {
    "path": "play-services-tapandpay/src/main/aidl/com/google/android/gms/tapandpay/internal/firstparty/GetAllCardsRequest.aidl",
    "content": "package com.google.android.gms.tapandpay.internal.firstparty;\n\nparcelable GetAllCardsRequest;"
  },
  {
    "path": "play-services-tapandpay/src/main/aidl/com/google/android/gms/tapandpay/internal/firstparty/IsDeviceUnlockedForPaymentRequest.aidl",
    "content": "package com.google.android.gms.tapandpay.internal.firstparty;\n\nparcelable IsDeviceUnlockedForPaymentRequest;"
  },
  {
    "path": "play-services-tapandpay/src/main/aidl/com/google/android/gms/tapandpay/internal/firstparty/RefreshSeCardsRequest.aidl",
    "content": "package com.google.android.gms.tapandpay.internal.firstparty;\n\nparcelable RefreshSeCardsRequest;"
  },
  {
    "path": "play-services-tapandpay/src/main/aidl/com/google/android/gms/tapandpay/internal/firstparty/SetActiveAccountRequest.aidl",
    "content": "package com.google.android.gms.tapandpay.internal.firstparty;\n\nparcelable SetActiveAccountRequest;"
  },
  {
    "path": "play-services-tapandpay/src/main/aidl/com/google/android/gms/tapandpay/internal/firstparty/SetSelectedTokenRequest.aidl",
    "content": "package com.google.android.gms.tapandpay.internal.firstparty;\n\nparcelable SetSelectedTokenRequest;"
  },
  {
    "path": "play-services-tapandpay/src/main/aidl/com/google/android/gms/tapandpay/issuer/IPushTokenizeRequestCallbacks.aidl",
    "content": "package com.google.android.gms.tapandpay.issuer;\n\ninterface IPushTokenizeRequestCallbacks {\n\n}"
  },
  {
    "path": "play-services-tapandpay/src/main/aidl/com/google/android/gms/tapandpay/issuer/IPushTokenizeResponseCallbacks.aidl",
    "content": "package com.google.android.gms.tapandpay.issuer;\n\ninterface IPushTokenizeResponseCallbacks {\n    \n}"
  },
  {
    "path": "play-services-tapandpay/src/main/aidl/com/google/android/gms/tapandpay/issuer/ListTokensRequest.aidl",
    "content": "package com.google.android.gms.tapandpay.issuer;\n\nparcelable ListTokensRequest;"
  },
  {
    "path": "play-services-tapandpay/src/main/aidl/com/google/android/gms/tapandpay/issuer/PushTokenizeRequest.aidl",
    "content": "package com.google.android.gms.tapandpay.issuer;\n\nparcelable PushTokenizeRequest;"
  },
  {
    "path": "play-services-tapandpay/src/main/aidl/com/google/android/gms/tapandpay/issuer/TokenInfo.aidl",
    "content": "package com.google.android.gms.tapandpay.issuer;\n\nparcelable TokenInfo;\n"
  },
  {
    "path": "play-services-tapandpay/src/main/aidl/com/google/android/gms/tapandpay/issuer/TokenStatus.aidl",
    "content": "package com.google.android.gms.tapandpay.issuer;\n\nparcelable TokenStatus;\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/TapAndPay.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tapandpay;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\npublic abstract class TapAndPay {\n    public static final int CARD_NETWORK_AMEX = 1;\n    public static final int CARD_NETWORK_DISCOVER = 2;\n    public static final int CARD_NETWORK_MASTERCARD = 3;\n    public static final int CARD_NETWORK_VISA = 4;\n    public static final int CARD_NETWORK_INTERAC = 5;\n    public static final int CARD_NETWORK_PRIVATE_LABEL = 6;\n    public static final int CARD_NETWORK_EFTPOS = 7;\n    public static final int CARD_NETWORK_MAESTRO = 8;\n    public static final int CARD_NETWORK_ID = 9;\n    public static final int CARD_NETWORK_QUICPAY = 10;\n    public static final int CARD_NETWORK_JCB = 11;\n    public static final int CARD_NETWORK_ELO = 12;\n    public static final int CARD_NETWORK_MIR = 13;\n\n    @Target({ElementType.TYPE_USE})\n    @Retention(RetentionPolicy.SOURCE)\n    @IntDef({CARD_NETWORK_AMEX, CARD_NETWORK_DISCOVER, CARD_NETWORK_MASTERCARD, CARD_NETWORK_VISA, CARD_NETWORK_INTERAC, CARD_NETWORK_PRIVATE_LABEL, CARD_NETWORK_EFTPOS, CARD_NETWORK_MAESTRO, CARD_NETWORK_ID, CARD_NETWORK_QUICPAY, CARD_NETWORK_JCB, CARD_NETWORK_ELO, CARD_NETWORK_MIR})\n    public @interface CardNetwork {\n    }\n\n    public static final int TOKEN_PROVIDER_AMEX = 2;\n    public static final int TOKEN_PROVIDER_MASTERCARD = 3;\n    public static final int TOKEN_PROVIDER_VISA = 4;\n    public static final int TOKEN_PROVIDER_DISCOVER = 5;\n    public static final int TOKEN_PROVIDER_EFTPOS = 6;\n    public static final int TOKEN_PROVIDER_INTERAC = 7;\n    public static final int TOKEN_PROVIDER_OBERTHUR = 8;\n    public static final int TOKEN_PROVIDER_PAYPAL = 9;\n    public static final int TOKEN_PROVIDER_JCB = 13;\n    public static final int TOKEN_PROVIDER_ELO = 14;\n    public static final int TOKEN_PROVIDER_GEMALTO = 15;\n    public static final int TOKEN_PROVIDER_MIR = 16;\n\n    @Target({ElementType.TYPE_USE})\n    @Retention(RetentionPolicy.SOURCE)\n    @IntDef({TOKEN_PROVIDER_AMEX, TOKEN_PROVIDER_MASTERCARD, TOKEN_PROVIDER_VISA, TOKEN_PROVIDER_DISCOVER, TOKEN_PROVIDER_EFTPOS, TOKEN_PROVIDER_INTERAC, TOKEN_PROVIDER_OBERTHUR, TOKEN_PROVIDER_PAYPAL, TOKEN_PROVIDER_JCB, TOKEN_PROVIDER_ELO, TOKEN_PROVIDER_GEMALTO, TOKEN_PROVIDER_MIR})\n    public @interface TokenServiceProvider {\n    }\n\n    public static final int TOKEN_STATE_UNTOKENIZED = 1;\n    public static final int TOKEN_STATE_PENDING = 2;\n    public static final int TOKEN_STATE_NEEDS_IDENTITY_VERIFICATION = 3;\n    public static final int TOKEN_STATE_SUSPENDED = 4;\n    public static final int TOKEN_STATE_ACTIVE = 5;\n    public static final int TOKEN_STATE_FELICA_PENDING_PROVISIONING = 6;\n\n    @Target({ElementType.TYPE_USE})\n    @Retention(RetentionPolicy.SOURCE)\n    @IntDef({TOKEN_STATE_UNTOKENIZED, TOKEN_STATE_PENDING, TOKEN_STATE_NEEDS_IDENTITY_VERIFICATION, TOKEN_STATE_SUSPENDED, TOKEN_STATE_ACTIVE, TOKEN_STATE_FELICA_PENDING_PROVISIONING})\n    public @interface TokenState {\n    }\n\n\n    @NonNull\n    public static final String EXTRA_CARD_RESULT = \"extra_card_result\";\n\n    @NonNull\n    public static final String EXTRA_ISSUER_TOKEN_ID = \"extra_issuer_token_id\";\n\n    @NonNull\n    public static final String EXTRA_STATUS_LIST = \"extra_status_list\";\n\n    @NonNull\n    public static final String EXTRA_TOKENIZATION_SESSION_ID = \"extra_tokenization_session_id\";\n\n    @NonNull\n    public static final String EXTRA_TOKEN_RESULT = \"extra_token_result\";\n\n    @NonNull\n    public static final String EXTRA_VIRTUAL_CARDS_RESULT = \"extra_virtual_cards_result\";\n\n    @NonNull\n    public static final String TOKEN_REQUESTOR_ID_WALLET = \"google_wallet\";\n\n    private TapAndPay() {\n    }\n\n    public interface DataChangedListener {\n        void onDataChanged();\n    }\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/TapAndPayClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tapandpay;\n\nimport android.app.Activity;\nimport android.app.PendingIntent;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.HasApiKey;\nimport com.google.android.gms.tapandpay.issuer.CreatePushProvisionSessionRequest;\nimport com.google.android.gms.tapandpay.issuer.IsTokenizedRequest;\nimport com.google.android.gms.tapandpay.issuer.PushProvisionSessionContext;\nimport com.google.android.gms.tapandpay.issuer.PushTokenizeRequest;\nimport com.google.android.gms.tapandpay.issuer.ServerPushProvisionRequest;\nimport com.google.android.gms.tapandpay.issuer.TokenInfo;\nimport com.google.android.gms.tapandpay.issuer.TokenStatus;\nimport com.google.android.gms.tapandpay.issuer.ViewTokenRequest;\nimport com.google.android.gms.tasks.Task;\n\nimport java.util.List;\n\npublic interface TapAndPayClient extends HasApiKey<Api.ApiOptions.NotRequiredOptions> {\n\n    @NonNull\n    String DATA_CHANGED_LISTENER_KEY = \"tapAndPayDataChangedListener\";\n\n    @NonNull\n    Task<PushProvisionSessionContext> createPushProvisionSession(@NonNull CreatePushProvisionSessionRequest request);\n\n    void createWallet(@NonNull Activity activity, int i);\n\n    @NonNull\n    Task<String> getActiveWalletId();\n\n    @NonNull\n    Task<String> getEnvironment();\n\n    @NonNull\n    Task<String> getLinkingToken(@NonNull String str);\n\n    @NonNull\n    Task<String> getStableHardwareId();\n\n    @NonNull\n    Task<TokenStatus> getTokenStatus(int i, @NonNull String str);\n\n    @NonNull\n    Task<Boolean> isTokenized(@NonNull IsTokenizedRequest request);\n\n    @NonNull\n    Task<List<TokenInfo>> listTokens();\n\n    void pushTokenize(@NonNull Activity activity, @NonNull PushTokenizeRequest request, int i);\n\n    @NonNull\n    Task<Void> registerDataChangedListener(@NonNull TapAndPay.DataChangedListener listener);\n\n    @NonNull\n    Task<Void> removeDataChangedListener(@NonNull TapAndPay.DataChangedListener listener);\n\n    void requestDeleteToken(@NonNull Activity activity, @NonNull String str, int i, int i2);\n\n    void requestSelectToken(@NonNull Activity activity, @NonNull String str, int i, int i2);\n\n    void serverPushProvision(@NonNull Activity activity, @NonNull ServerPushProvisionRequest request, int i);\n\n    void tokenize(@NonNull Activity activity, @Nullable String str, int i, @NonNull String str2, int i2, int i3);\n\n    @NonNull\n    Task<PendingIntent> viewToken(@NonNull ViewTokenRequest request);\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/TapAndPayStatusCodes.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tapandpay;\n\nimport com.google.android.gms.common.api.CommonStatusCodes;\n\nimport org.microg.gms.common.PublicApi;\n\n@PublicApi\npublic class TapAndPayStatusCodes extends CommonStatusCodes {\n    public static final int TAP_AND_PAY_NO_ACTIVE_WALLET = 15002;\n    public static final int TAP_AND_PAY_TOKEN_NOT_FOUND = 15003;\n    public static final int TAP_AND_PAY_INVALID_TOKEN_STATE = 15004;\n    public static final int TAP_AND_PAY_ATTESTATION_ERROR = 15005;\n    public static final int TAP_AND_PAY_UNAVAILABLE = 15009;\n    public static final int TAP_AND_PAY_SAVE_CARD_ERROR = 15019;\n    public static final int TAP_AND_PAY_INELIGIBLE_FOR_TOKENIZATION = 15021;\n    public static final int TAP_AND_PAY_TOKENIZATION_DECLINED = 15022;\n    public static final int TAP_AND_PAY_CHECK_ELIGIBILITY_ERROR = 15023;\n    public static final int TAP_AND_PAY_TOKENIZE_ERROR = 15024;\n    public static final int TAP_AND_PAY_TOKEN_ACTIVATION_REQUIRED = 15025;\n    public static final int TAP_AND_PAY_PAYMENT_CREDENTIALS_DELIVERY_TIMEOUT = 15026;\n    public static final int TAP_AND_PAY_USER_CANCELED_FLOW = 15027;\n    public static final int TAP_AND_PAY_ENROLL_FOR_VIRTUAL_CARDS_FAILED = 15028;\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/firstparty/AccountInfo.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tapandpay.firstparty;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.Arrays;\nimport java.util.Objects;\n\n@SafeParcelable.Class\npublic class AccountInfo extends AbstractSafeParcelable {\n    @Field(2)\n    public final String accountId;\n    @Field(3)\n    public final String accountName;\n    @Field(4)\n    public final int accountType;\n\n    @Constructor\n    public AccountInfo(@Param(2) String accountId, @Param(3) String accountName, @Param(4) int accountType) {\n        this.accountId = accountId;\n        this.accountName = accountName;\n        this.accountType = accountType;\n    }\n\n    @Override\n    public boolean equals(@Nullable Object obj) {\n        if (!(obj instanceof AccountInfo)) return false;\n        return Objects.equals(accountId, ((AccountInfo) obj).accountId) && Objects.equals(accountName, ((AccountInfo) obj).accountName);\n    }\n\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(new Object[]{accountId, accountName});\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return new ToStringHelper(\"AccountInfo\")\n                .field(\"accountId\", accountId)\n                .field(\"accountName\", accountName)\n                .field(\"accountType\", accountType)\n                .end();\n    }\n\n    public static final SafeParcelableCreatorAndWriter<AccountInfo> CREATOR = findCreator(AccountInfo.class);\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/firstparty/BadgeInfo.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tapandpay.firstparty;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class BadgeInfo extends AbstractSafeParcelable {\n    @Field(1)\n    public String clientTokenId;\n    @Field(2)\n    public byte[] serverToken;\n    @Field(3)\n    public int cardNetwork;\n    @Field(4)\n    public TokenStatus tokenStatus;\n    @Field(5)\n    public String tokenLastDigits;\n    @Field(6)\n    public TransactionInfo transactionInfo;\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"BadgeInfo\")\n                .field(\"clientTokenId\", clientTokenId)\n                .field(\"serverToken\", serverToken)\n                .field(\"cardNetwork\", cardNetwork)\n                .field(\"tokenStatus\", tokenStatus)\n                .field(\"tokenLastDigits\", tokenLastDigits)\n                .field(\"transactionInfo\", transactionInfo)\n                .end();\n    }\n\n    public static final SafeParcelableCreatorAndWriter<BadgeInfo> CREATOR = findCreator(BadgeInfo.class);\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/firstparty/CardInfo.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tapandpay.firstparty;\n\nimport android.net.Uri;\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport java.util.List;\n\n@SafeParcelable.Class\npublic class CardInfo extends AbstractSafeParcelable {\n    @Field(2)\n    public String billingCardId;\n    @Field(3)\n    public byte[] serverToken;\n    @Field(4)\n    public String cardholderName;\n    @Field(5)\n    public String displayName;\n    @Field(6)\n    public int cardNetwork;\n    @Field(7)\n    public TokenStatus tokenStatus;\n    @Field(8)\n    public String panLastDigits;\n    @Field(9)\n    @Nullable\n    public Uri cardImageUrl;\n    @Field(10)\n    public int cardColor;\n    @Field(11)\n    public int overlayTextColor;\n    @Field(12)\n    public IssuerInfo issuerInfo;\n    @Field(13)\n    public String tokenLastDigits;\n    @Field(15)\n    public TransactionInfo transactionInfo;\n    @Field(16)\n    public String issuerTokenId;\n    @Field(17)\n    public byte[] inAppCardToken;\n    @Field(18)\n    public int cachedEligibility;\n    @Field(20)\n    public int paymentProtocol;\n    @Field(21)\n    public int tokenType;\n    @Field(22)\n    public InStoreCvmConfig inStoreCvmConfig;\n    @Field(23)\n    public InAppCvmConfig inAppCvmConfig;\n    @Field(24)\n    public String tokenDisplayName;\n    @Field(25)\n    public OnlineAccountCardLinkInfo[] onlineAccountCardLinkInfos;\n    @Field(26)\n    public boolean allowAidSelection;\n    @Field(27)\n    public List<BadgeInfo> badges;\n    @Field(28)\n    public boolean upgradeAvailable;\n    @Field(29)\n    public boolean requiresSignature;\n    @Field(30)\n    public long googleTokenId;\n    @Field(31)\n    public long lastTapTimestamp;\n    @Field(32)\n    public boolean isTransit;\n    @Field(33)\n    public long googleWalletId;\n    @Field(34)\n    public String devicePaymentMethodId;\n    @Field(35)\n    public String cloudPaymentMethodId;\n    @Field(36)\n    @Nullable\n    public CardRewardsInfo cardRewardsInfo;\n    @Field(37)\n    public int tapStrategy;\n    @Field(38)\n    public boolean hideFromGlobalActions;\n    @Field(39)\n    @Nullable\n    public String rawPanLastDigits;\n    @Field(40)\n    public int cardDisplayType;\n    @Field(41)\n    public boolean b41;\n    @Field(42)\n    public long auxiliaryGoogleTokenId;\n    @Field(43)\n    public String auxiliaryIssuerTokenId;\n    @Field(44)\n    public int auxiliaryNetwork;\n    @Field(45)\n    public String auxClientTokenId;\n\n    public static final SafeParcelableCreatorAndWriter<CardInfo> CREATOR = findCreator(CardInfo.class);\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/firstparty/CardRewardsInfo.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tapandpay.firstparty;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class CardRewardsInfo extends AbstractSafeParcelable {\n    @Field(1)\n    public long expirationTimestamp;\n    @Field(2)\n    public String websiteUrl;\n    @Field(3)\n    public String websiteRedirectText;\n    @Field(4)\n    public String legalDisclaimer;\n    @Field(5)\n    public String summary;\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"CardRewardsInfo\")\n                .field(\"expirationTimestamp\", expirationTimestamp)\n                .field(\"websiteUrl\", websiteUrl)\n                .field(\"websiteRedirectText\", websiteRedirectText)\n                .field(\"legalDisclaimer\", legalDisclaimer)\n                .field(\"summary\", summary)\n                .end();\n    }\n\n    public static final SafeParcelableCreatorAndWriter<CardRewardsInfo> CREATOR = findCreator(CardRewardsInfo.class);\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/firstparty/GetActiveAccountResponse.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tapandpay.firstparty;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.tapandpay.internal.firstparty.SetActiveAccountRequest;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n@SafeParcelable.Class\npublic class GetActiveAccountResponse extends AbstractSafeParcelable {\n    @Field(2)\n    @Nullable\n    public final AccountInfo accountInfo;\n\n    @Constructor\n    public GetActiveAccountResponse(@Nullable @Param(2) AccountInfo accountInfo) {\n        this.accountInfo = accountInfo;\n    }\n\n    public static final SafeParcelableCreatorAndWriter<GetActiveAccountResponse> CREATOR = findCreator(GetActiveAccountResponse.class);\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/firstparty/GetAllCardsResponse.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tapandpay.firstparty;\n\nimport android.util.SparseArray;\nimport androidx.annotation.Nullable;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class GetAllCardsResponse extends AutoSafeParcelable {\n    @Field(2)\n    @Nullable\n    public final CardInfo[] cardInfos;\n    @Field(3)\n    @Nullable\n    public final AccountInfo accountInfo;\n    @Field(4)\n    @Nullable\n    public final String defaultClientTokenId;\n    @Field(5)\n    @Nullable\n    public final String overrideClientTokenId;\n    // FIXME: Add support for SparseArray in SafeParcelable library\n//    @Field(6)\n    public final SparseArray<String> seDefaultCards;\n    @Field(7)\n    public final byte[] wearSortOrder;\n\n    private GetAllCardsResponse() {\n        cardInfos = new CardInfo[0];\n        accountInfo = null;\n        defaultClientTokenId = null;\n        overrideClientTokenId = null;\n        seDefaultCards = new SparseArray<>();\n        wearSortOrder = new byte[0];\n    }\n\n    public GetAllCardsResponse(CardInfo[] cardInfos, AccountInfo accountInfo, String defaultClientTokenId, String overrideClientTokenId, SparseArray<String> seDefaultCards, byte[] wearSortOrder) {\n        this.cardInfos = cardInfos;\n        this.accountInfo = accountInfo;\n        this.defaultClientTokenId = defaultClientTokenId;\n        this.overrideClientTokenId = overrideClientTokenId;\n        this.seDefaultCards = seDefaultCards;\n        this.wearSortOrder = wearSortOrder;\n    }\n\n    public static final Creator<GetAllCardsResponse> CREATOR = new AutoCreator<>(GetAllCardsResponse.class);\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/firstparty/GetSecurityParamsResponse.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tapandpay.firstparty;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class GetSecurityParamsResponse extends AbstractSafeParcelable {\n    @Field(2)\n    public final boolean isDeviceSecure;\n    @Field(3)\n    public final boolean hasValidPaymentBundles;\n    @Field(4)\n    public final boolean hasDigitalCarKey;\n    @Field(5)\n    public final boolean hasMobileDocument;\n\n    @Constructor\n    public GetSecurityParamsResponse(@Param(2) boolean isDeviceSecure, @Param(3) boolean hasValidPaymentBundles, @Param(4) boolean hasDigitalCarKey, @Param(5) boolean hasMobileDocument) {\n        this.isDeviceSecure = isDeviceSecure;\n        this.hasValidPaymentBundles = hasValidPaymentBundles;\n        this.hasDigitalCarKey = hasDigitalCarKey;\n        this.hasMobileDocument = hasMobileDocument;\n    }\n\n    public static final SafeParcelableCreatorAndWriter<GetSecurityParamsResponse> CREATOR = findCreator(GetSecurityParamsResponse.class);\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/firstparty/InAppCvmConfig.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tapandpay.firstparty;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class InAppCvmConfig extends AbstractSafeParcelable {\n    @Field(2)\n    public int cdcvmExpirationInSecs;\n    @Field(3)\n    public int cdcvmTransactionLimit;\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"InAppCvmConfig\")\n                .field(\"cdcvmExpirationInSecs\", cdcvmExpirationInSecs)\n                .field(\"cdcvmTransactionLimit\", cdcvmTransactionLimit)\n                .end();\n    }\n\n    public static final SafeParcelableCreatorAndWriter<InAppCvmConfig> CREATOR = findCreator(InAppCvmConfig.class);\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/firstparty/InStoreCvmConfig.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tapandpay.firstparty;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class InStoreCvmConfig extends AbstractSafeParcelable {\n    @Field(2)\n    public boolean requireCdcvmPassing;\n    @Field(3)\n    public int cdcvmExpirationInSecs;\n    @Field(4)\n    public int unlockedTapLimit;\n    @Field(5)\n    public int cdcvmTapLimit;\n    @Field(6)\n    public boolean prioritizeOnlinePinOverCdcvm;\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"InStoreCvmConfig\")\n                .field(\"requireCdcvmPassing\", requireCdcvmPassing)\n                .field(\"cdcvmExpirationInSecs\", cdcvmExpirationInSecs)\n                .field(\"unlockedTapLimit\", unlockedTapLimit)\n                .field(\"cdcvmTapLimit\", cdcvmTapLimit)\n                .field(\"prioritizeOnlinePinOverCdcvm\", prioritizeOnlinePinOverCdcvm)\n                .end();\n    }\n\n    public static final SafeParcelableCreatorAndWriter<InStoreCvmConfig> CREATOR = findCreator(InStoreCvmConfig.class);\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/firstparty/IsDeviceRecentlyUnlockedRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tapandpay.firstparty;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class IsDeviceRecentlyUnlockedRequest extends AbstractSafeParcelable {\n    public static final SafeParcelableCreatorAndWriter<IsDeviceRecentlyUnlockedRequest> CREATOR = findCreator(IsDeviceRecentlyUnlockedRequest.class);\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/firstparty/IsDeviceRecentlyUnlockedResponse.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tapandpay.firstparty;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class IsDeviceRecentlyUnlockedResponse extends AbstractSafeParcelable {\n    @Field(1)\n    public final boolean isDeviceRecentlyUnlocked;\n\n    @Constructor\n    public IsDeviceRecentlyUnlockedResponse(@Param(1) boolean isDeviceRecentlyUnlocked) {\n        this.isDeviceRecentlyUnlocked = isDeviceRecentlyUnlocked;\n    }\n\n    public static final SafeParcelableCreatorAndWriter<IsDeviceRecentlyUnlockedResponse> CREATOR = findCreator(IsDeviceRecentlyUnlockedResponse.class);\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/firstparty/IssuerInfo.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tapandpay.firstparty;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class IssuerInfo extends AbstractSafeParcelable {\n    @Field(2)\n    public String issuerName;\n    @Field(3)\n    public String issuerPhoneNumber;\n    @Field(4)\n    public String appLogoUrl;\n    @Field(5)\n    public String appName;\n    @Field(6)\n    public String appDeveloperName;\n    @Field(7)\n    public String appPackageName;\n    @Field(8)\n    public String privacyNoticeUrl;\n    @Field(9)\n    public String termsAndConditionsUrl;\n    @Field(10)\n    public String productShortName;\n    @Field(11)\n    public String appAction;\n    @Field(12)\n    public String appIntentExtraMessage;\n    @Field(13)\n    public String issuerMessageHeadline;\n    @Field(14)\n    public String issuerMessageBody;\n    @Field(15)\n    public long issuerMessageExpiryTimestampMillis;\n    @Field(16)\n    public String issuerMessageLinkPackageName;\n    @Field(17)\n    public String issuerMessageLinkAction;\n    @Field(18)\n    public String issuerMessageLinkExtraText;\n    @Field(20)\n    public String issuerMessageLinkUrl;\n    @Field(21)\n    public String issuerMessageLinkText;\n    @Field(22)\n    public String issuerWebLinkUrl;\n    @Field(23)\n    public String issuerWebLinkText;\n    @Field(24)\n    public int issuerMessageType;\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"IssuerInfo\")\n                .field(\"issuerName\", issuerName)\n                .field(\"issuerPhoneNumber\", issuerPhoneNumber)\n                .field(\"appLogoUrl\", appLogoUrl)\n                .field(\"appName\", appName)\n                .field(\"appDeveloperName\", appDeveloperName)\n                .field(\"appPackageName\", appPackageName)\n                .field(\"privacyNoticeUrl\", privacyNoticeUrl)\n                .field(\"termsAndConditionsUrl\", termsAndConditionsUrl)\n                .field(\"productShortName\", productShortName)\n                .field(\"appAction\", appAction)\n                .field(\"appIntentExtraMessage\", appIntentExtraMessage)\n                .field(\"issuerMessageHeadline\", issuerMessageHeadline)\n                .field(\"issuerMessageBody\", issuerMessageBody)\n                .field(\"issuerMessageExpiryTimestampMillis\", issuerMessageExpiryTimestampMillis)\n                .field(\"issuerMessageLinkPackageName\", issuerMessageLinkPackageName)\n                .field(\"issuerMessageLinkAction\", issuerMessageLinkAction)\n                .field(\"issuerMessageLinkExtraText\", issuerMessageLinkExtraText)\n                .field(\"issuerMessageLinkUrl\", issuerMessageLinkUrl)\n                .field(\"issuerMessageLinkText\", issuerMessageLinkText)\n                .field(\"issuerWebLinkUrl\", issuerWebLinkUrl)\n                .field(\"issuerWebLinkText\", issuerWebLinkText)\n                .field(\"issuerMessageType\", issuerMessageType)\n                .end();\n    }\n\n    public static final SafeParcelableCreatorAndWriter<IssuerInfo> CREATOR = findCreator(IssuerInfo.class);\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/firstparty/LogUserCurrentScreenRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tapandpay.firstparty;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class LogUserCurrentScreenRequest extends AbstractSafeParcelable {\n    @Field(1)\n    public int i1;\n    @Field(2)\n    public int i2;\n    @Field(3)\n    public int i3;\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"LogUserCurrentScreenRequest\").value(i1).value(i2).value(i3).end();\n    }\n\n    public static final SafeParcelableCreatorAndWriter<LogUserCurrentScreenRequest> CREATOR = findCreator(LogUserCurrentScreenRequest.class);\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/firstparty/OnlineAccountCardLinkInfo.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tapandpay.firstparty;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class OnlineAccountCardLinkInfo extends AbstractSafeParcelable {\n    @Field(1)\n    public int accountType;\n    @Field(2)\n    public int status;\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"OnlineAccountCardLinkInfo\")\n                .field(\"accountType\", accountType)\n                .field(\"status\", status)\n                .end();\n    }\n\n    public static final SafeParcelableCreatorAndWriter<OnlineAccountCardLinkInfo> CREATOR = findCreator(OnlineAccountCardLinkInfo.class);\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/firstparty/RefreshSeCardsResponse.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tapandpay.firstparty;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class RefreshSeCardsResponse extends AutoSafeParcelable {\n    public static final Creator<RefreshSeCardsResponse> CREATOR = new AutoCreator<>(RefreshSeCardsResponse.class);\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/firstparty/RegisterServiceListenerRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tapandpay.firstparty;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class RegisterServiceListenerRequest extends AbstractSafeParcelable {\n    @Field(1)\n    public String s1;\n    @Field(2)\n    public byte[] f2;\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"RegisterServiceListenerRequest\").value(s1).value(f2).end();\n    }\n\n    public static final SafeParcelableCreatorAndWriter<RegisterServiceListenerRequest> CREATOR = findCreator(RegisterServiceListenerRequest.class);\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/firstparty/TokenReference.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tapandpay.firstparty;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class TokenReference extends AutoSafeParcelable {\n    @Field(2)\n    public String tokenReferenceId;\n    @Field(3)\n    public int tokenProvider;\n\n    public static final Creator<TokenReference> CREATOR = new AutoCreator<>(TokenReference.class);\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/firstparty/TokenStatus.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tapandpay.firstparty;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class TokenStatus extends AutoSafeParcelable {\n    @Field(2)\n    public TokenReference tokenReference;\n    @Field(3)\n    public int tokenState;\n    @Field(4)\n    public boolean isSelected;\n\n    public static final Creator<TokenStatus> CREATOR = new AutoCreator<>(TokenStatus.class);\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/firstparty/TransactionInfo.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tapandpay.firstparty;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class TransactionInfo extends AbstractSafeParcelable {\n    @Field(2)\n    public int transactionDelivery;\n    @Field(3)\n    public int transactionLimit;\n    @Field(4)\n    public int supportedTransactions;\n    @Field(5)\n    public int deliveryPreference;\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"TransactionInfo\")\n                .field(\"transactionDelivery\", transactionDelivery)\n                .field(\"transactionLimit\", transactionLimit)\n                .field(\"supportedTransactions\", supportedTransactions)\n                .field(\"deliveryPreference\", deliveryPreference)\n                .end();\n    }\n\n    public static final SafeParcelableCreatorAndWriter<TransactionInfo> CREATOR = findCreator(TransactionInfo.class);\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/internal/firstparty/GetActiveAccountRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tapandpay.internal.firstparty;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class GetActiveAccountRequest extends AutoSafeParcelable {\n    public static final Creator<GetActiveAccountRequest> CREATOR = new AutoCreator<>(GetActiveAccountRequest.class);\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/internal/firstparty/GetAllCardsRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tapandpay.internal.firstparty;\n\nimport android.accounts.Account;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class GetAllCardsRequest extends AutoSafeParcelable {\n    @Field(2)\n    public boolean refreshSeCards;\n    @Field(3)\n    public Account account;\n    @Field(4)\n    public int sortOrderCollectionId;\n\n    public static final Creator<GetAllCardsRequest> CREATOR = new AutoCreator<>(GetAllCardsRequest.class);\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/internal/firstparty/IsDeviceUnlockedForPaymentRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tapandpay.internal.firstparty;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class IsDeviceUnlockedForPaymentRequest extends AbstractSafeParcelable {\n    public static final SafeParcelableCreatorAndWriter<IsDeviceUnlockedForPaymentRequest> CREATOR = findCreator(IsDeviceUnlockedForPaymentRequest.class);\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/internal/firstparty/RefreshSeCardsRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tapandpay.internal.firstparty;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class RefreshSeCardsRequest extends AutoSafeParcelable {\n    public static final Creator<RefreshSeCardsRequest> CREATOR = new AutoCreator<>(RefreshSeCardsRequest.class);\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/internal/firstparty/SetActiveAccountRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tapandpay.internal.firstparty;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class SetActiveAccountRequest extends AbstractSafeParcelable {\n    @Field(2)\n    public String accountName;\n    @Field(3)\n    public boolean allowSetupErrorMessage;\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"SetActiveAccountRequest\").value(accountName)\n                .field(\"allowSetupErrorMessage\", allowSetupErrorMessage)\n                .end();\n    }\n\n    public static final SafeParcelableCreatorAndWriter<SetActiveAccountRequest> CREATOR = findCreator(SetActiveAccountRequest.class);\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/internal/firstparty/SetSelectedTokenRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tapandpay.internal.firstparty;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class SetSelectedTokenRequest extends AbstractSafeParcelable {\n    @Field(2)\n    public String clientTokenId;\n    @Field(3)\n    public long time;\n    @Field(4)\n    public boolean b4;\n    @Field(5)\n    public int priority;\n    @Field(6)\n    public long l6;\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"SetSelectedTokenRequest\")\n                .field(\"clientTokenId\", clientTokenId)\n                .field(\"time\", time)\n                .field(\"b4\", b4)\n                .field(\"priority\", priority)\n                .field(\"l6\", l6)\n                .end();\n    }\n\n    public static final SafeParcelableCreatorAndWriter<SetSelectedTokenRequest> CREATOR = findCreator(SetSelectedTokenRequest.class);\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/issuer/CobadgedTokenInfo.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tapandpay.issuer;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class CobadgedTokenInfo extends AbstractSafeParcelable {\n    public static final SafeParcelableCreatorAndWriter<CobadgedTokenInfo> CREATOR = findCreator(CobadgedTokenInfo.class);\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/issuer/CreatePushProvisionSessionRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tapandpay.issuer;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class CreatePushProvisionSessionRequest extends AbstractSafeParcelable {\n    public static final SafeParcelableCreatorAndWriter<CreatePushProvisionSessionRequest> CREATOR = findCreator(CreatePushProvisionSessionRequest.class);\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/issuer/IsTokenizedRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tapandpay.issuer;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class IsTokenizedRequest extends AbstractSafeParcelable {\n    public static final SafeParcelableCreatorAndWriter<IsTokenizedRequest> CREATOR = findCreator(IsTokenizedRequest.class);\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/issuer/ListTokensRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tapandpay.issuer;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class ListTokensRequest extends AbstractSafeParcelable {\n    public static final SafeParcelableCreatorAndWriter<ListTokensRequest> CREATOR = findCreator(ListTokensRequest.class);\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/issuer/PushProvisionSessionContext.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tapandpay.issuer;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class PushProvisionSessionContext extends AbstractSafeParcelable {\n    public static final SafeParcelableCreatorAndWriter<PushProvisionSessionContext> CREATOR = findCreator(PushProvisionSessionContext.class);\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/issuer/PushTokenizeExtraOptions.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tapandpay.issuer;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class PushTokenizeExtraOptions extends AbstractSafeParcelable {\n    public static final SafeParcelableCreatorAndWriter<PushTokenizeExtraOptions> CREATOR = findCreator(PushTokenizeExtraOptions.class);\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/issuer/PushTokenizeRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tapandpay.issuer;\n\nimport android.os.IBinder;\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.tapandpay.TapAndPay;\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class PushTokenizeRequest extends AbstractSafeParcelable {\n\n    @Field(2)\n    public final int network;\n\n    @Field(3)\n    public final int tokenServiceProvider;\n\n    @Field(4)\n    @NonNull\n    public final byte[] opaquePaymentCard;\n\n    @Field(5)\n    @NonNull\n    public final String lastDigits;\n\n    @Field(6)\n    @NonNull\n    public final String displayName;\n\n    @Field(7)\n    @NonNull\n    public final UserAddress userAddress;\n\n    @Field(8)\n    public final boolean isTransit;\n\n    @Field(9)\n    @Nullable\n    public final int[] supportedCallbackRequestTypes;\n\n    @Field(value = 10, type = \"android.os.IBinder\", getter = \"$object.pushTokenizeCallbacks.asBinder()\")\n    @Nullable\n    public final IPushTokenizeRequestCallbacks pushTokenizeCallbacks;\n\n    @Field(11)\n    @Nullable\n    public final CobadgedTokenInfo cobadgedTokenInfo;\n\n    @Field(12)\n    @Nullable\n    public final SupervisedUserInfo supervisedUserInfo;\n\n    @Field(13)\n    @Nullable\n    public final String[] supportedTokenRequestorIds;\n\n    @Field(14)\n    @Nullable\n    public final PushTokenizeExtraOptions pushTokenizeExtraOptions;\n\n    @Constructor\n    PushTokenizeRequest(@Param(2) int network, @Param(3) int tokenServiceProvider, @Param(4) byte[] opaquePaymentCard, @Param(5) String lastDigits, @Param(6) String displayName, @Param(7) UserAddress userAddress, @Param(8) boolean isTransit, @Param(9) int[] supportedCallbackRequestTypes, @Param(10) IBinder pushTokenizeCallbacks, @Param(11) CobadgedTokenInfo cobadgedTokenInfo, @Param(12) SupervisedUserInfo supervisedUserInfo, @Param(13) String[] supportedTokenRequestorIds, @Param(14) PushTokenizeExtraOptions pushTokenizeExtraOptions) {\n        this(network, tokenServiceProvider, opaquePaymentCard, lastDigits, displayName, userAddress, isTransit, supportedCallbackRequestTypes, IPushTokenizeRequestCallbacks.Stub.asInterface(pushTokenizeCallbacks), cobadgedTokenInfo, supervisedUserInfo, supportedTokenRequestorIds, pushTokenizeExtraOptions);\n    }\n\n    public PushTokenizeRequest(@TapAndPay.CardNetwork int network, @TapAndPay.TokenServiceProvider int tokenServiceProvider, @NonNull byte[] opaquePaymentCard, @NonNull String lastDigits, @NonNull String displayName, @NonNull UserAddress userAddress, boolean isTransit, @Nullable int[] supportedCallbackRequestTypes, @Nullable IPushTokenizeRequestCallbacks pushTokenizeCallbacks, @Nullable CobadgedTokenInfo cobadgedTokenInfo, @Nullable SupervisedUserInfo supervisedUserInfo, @Nullable String[] supportedTokenRequestorIds, @Nullable PushTokenizeExtraOptions pushTokenizeExtraOptions) {\n        this.network = network;\n        this.tokenServiceProvider = tokenServiceProvider;\n        this.opaquePaymentCard = opaquePaymentCard;\n        this.lastDigits = lastDigits;\n        this.displayName = displayName;\n        this.userAddress = userAddress;\n        this.isTransit = isTransit;\n        this.supportedCallbackRequestTypes = supportedCallbackRequestTypes;\n        this.pushTokenizeCallbacks = pushTokenizeCallbacks;\n        this.cobadgedTokenInfo = cobadgedTokenInfo;\n        this.supervisedUserInfo = supervisedUserInfo;\n        this.supportedTokenRequestorIds = supportedTokenRequestorIds;\n        this.pushTokenizeExtraOptions = pushTokenizeExtraOptions;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"PushTokenizeRequest\")\n                .field(\"network\", network)\n                .field(\"tokenServiceProvider\", tokenServiceProvider)\n                .field(\"opaquePaymentCard\", opaquePaymentCard)\n                .field(\"lastDigits\", lastDigits)\n                .field(\"displayName\", displayName)\n                .field(\"userAddress\", userAddress)\n                .field(\"isTransit\", isTransit)\n                .field(\"supportedCallbackRequestTypes\", supportedCallbackRequestTypes)\n                .field(\"pushTokenizeCallbacks\", pushTokenizeCallbacks)\n                .field(\"cobadgedTokenInfo\", cobadgedTokenInfo)\n                .field(\"supervisedUserInfo\", supervisedUserInfo)\n                .field(\"supportedTokenRequestorIds\", supportedTokenRequestorIds)\n                .field(\"pushTokenizeExtraOptions\", pushTokenizeExtraOptions)\n                .end();\n    }\n\n    public static final SafeParcelableCreatorAndWriter<PushTokenizeRequest> CREATOR = findCreator(PushTokenizeRequest.class);\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/issuer/ServerPushProvisionRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tapandpay.issuer;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class ServerPushProvisionRequest extends AbstractSafeParcelable {\n    public static final SafeParcelableCreatorAndWriter<ServerPushProvisionRequest> CREATOR = findCreator(ServerPushProvisionRequest.class);\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/issuer/SupervisedUserInfo.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tapandpay.issuer;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class SupervisedUserInfo extends AbstractSafeParcelable {\n    public static final SafeParcelableCreatorAndWriter<SupervisedUserInfo> CREATOR = findCreator(SupervisedUserInfo.class);\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/issuer/TokenInfo.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.gms.tapandpay.issuer;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.tapandpay.TapAndPay;\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class TokenInfo extends AbstractSafeParcelable {\n    @Field(1)\n    @NonNull\n    private final String issuerTokenId;\n    @Field(2)\n    @NonNull\n    private final String issuerName;\n    @Field(3)\n    @NonNull\n    private final String fpanLastFour;\n    @Field(4)\n    @NonNull\n    private final String dpanLastFour;\n    @Field(5)\n    private final int tokenServiceProvider;\n    @Field(6)\n    private final int network;\n    @Field(7)\n    private final int tokenState;\n    @Field(8)\n    private final boolean isDefaultToken;\n    @Field(9)\n    @NonNull\n    private final String portfolioName;\n\n    @Constructor\n    public TokenInfo(@NonNull @Param(1) String issuerTokenId, @NonNull @Param(2) String issuerName, @NonNull @Param(3) String fpanLastFour, @NonNull @Param(4) String dpanLastFour, @Param(5) @TapAndPay.TokenServiceProvider int tokenServiceProvider, @Param(6) @TapAndPay.CardNetwork int network, @Param(7) @TapAndPay.TokenState int tokenState, @Param(8) boolean isDefaultToken, @Param(9) @NonNull String portfolioName) {\n        this.issuerTokenId = issuerTokenId;\n        this.issuerName = issuerName;\n        this.fpanLastFour = fpanLastFour;\n        this.dpanLastFour = dpanLastFour;\n        this.tokenServiceProvider = tokenServiceProvider;\n        this.network = network;\n        this.tokenState = tokenState;\n        this.isDefaultToken = isDefaultToken;\n        this.portfolioName = portfolioName;\n    }\n\n    @NonNull\n    public String getDpanLastFour() {\n        return dpanLastFour;\n    }\n\n    @NonNull\n    public String getFpanLastFour() {\n        return fpanLastFour;\n    }\n\n    public boolean getIsDefaultToken() {\n        return isDefaultToken;\n    }\n\n    @NonNull\n    public String getIssuerName() {\n        return issuerName;\n    }\n\n    @NonNull\n    public String getIssuerTokenId() {\n        return issuerTokenId;\n    }\n\n    @TapAndPay.CardNetwork\n    public int getNetwork() {\n        return network;\n    }\n\n    @NonNull\n    public String getPortfolioName() {\n        return portfolioName;\n    }\n\n    @TapAndPay.TokenServiceProvider\n    public int getTokenServiceProvider() {\n        return tokenServiceProvider;\n    }\n\n    @TapAndPay.TokenState\n    public int getTokenState() {\n        return tokenState;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"TokenInfo\").value(issuerTokenId)\n                .field(\"issuerName\", issuerName)\n                .field(\"fpanLastFour\", fpanLastFour)\n                .field(\"dpanLastFour\", dpanLastFour)\n                .field(\"tokenServiceProvider\", tokenServiceProvider)\n                .field(\"network\", network)\n                .field(\"tokenState\", tokenState)\n                .field(\"isDefaultToken\", isDefaultToken)\n                .field(\"portfolioName\", portfolioName)\n                .end();\n    }\n\n    public static final SafeParcelableCreatorAndWriter<TokenInfo> CREATOR = findCreator(TokenInfo.class);\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/issuer/TokenStatus.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tapandpay.issuer;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\n@SafeParcelable.Class\npublic class TokenStatus extends AbstractSafeParcelable {\n    @Field(2)\n    @NonNull\n    public final String issuerTokenId;\n    @Field(value = 3, getterName = \"getTokenState\")\n    private final int tokenState;\n    @Field(value = 4, getterName = \"isSelected\")\n    private final boolean selected;\n\n    @Constructor\n    public TokenStatus(@NonNull @Param(2) String issuerTokenId, @Param(3) int tokenState, @Param(4) boolean selected) {\n        this.issuerTokenId = issuerTokenId;\n        this.tokenState = tokenState;\n        this.selected = selected;\n    }\n\n    public int getTokenState() {\n        return tokenState;\n    }\n\n    public boolean isSelected() {\n        return selected;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"TokenStatus\").value(issuerTokenId)\n                .field(\"tokenState\", tokenState)\n                .field(\"selected\", selected)\n                .end();\n    }\n\n    public static final SafeParcelableCreatorAndWriter<TokenStatus> CREATOR = findCreator(TokenStatus.class);\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/issuer/UserAddress.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tapandpay.issuer;\n\nimport android.content.Intent;\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport static com.google.android.gms.common.internal.safeparcel.SafeParcelable.*;\n\n@SafeParcelable.Class\npublic class UserAddress extends AbstractSafeParcelable {\n    private static final String EXTRA_ADDRESS = \"com.google.android.gms.identity.intents.EXTRA_ADDRESS\";\n\n    @Field(value = 2, getterName = \"getName\")\n    @NonNull\n    private final String name;\n    @Field(value = 3, getterName = \"getAddress1\")\n    @NonNull\n    private final String address1;\n    @Field(value = 4, getterName = \"getAddress2\")\n    @NonNull\n    private final String address2;\n    @Field(value = 5, getterName = \"getAddress3\")\n    @NonNull\n    private final String address3;\n    @Field(value = 6, getterName = \"getAddress4\")\n    @NonNull\n    private final String address4;\n    @Field(value = 7, getterName = \"getAddress5\")\n    @NonNull\n    private final String address5;\n    @Field(value = 8, getterName = \"getAdministrativeArea\")\n    @NonNull\n    private final String administrativeArea;\n    @Field(value = 9, getterName = \"getLocality\")\n    @NonNull\n    private final String locality;\n    @Field(value = 10, getterName = \"getCountryCode\")\n    @NonNull\n    private final String countryCode;\n    @Field(value = 11, getterName = \"getPostalCode\")\n    @NonNull\n    private final String postalCode;\n    @Field(value = 12, getterName = \"getSortingCode\")\n    @NonNull\n    private final String sortingCode;\n    @Field(value = 13, getterName = \"getPhoneNumber\")\n    @NonNull\n    private final String phoneNumber;\n    @Field(value = 14, getterName = \"isPostBox\")\n    private final boolean postBox;\n    @Field(value = 15, getterName = \"getCompanyName\")\n    @NonNull\n    private final String companyName;\n    @Field(value = 16, getterName = \"getEmailAddress\")\n    @NonNull\n    private final String emailAddress;\n\n    @Constructor\n    public UserAddress(@NonNull @Param(2) String name, @NonNull @Param(3) String address1, @NonNull @Param(4) String address2, @NonNull @Param(5) String address3, @NonNull @Param(6) String address4, @NonNull @Param(7) String address5, @NonNull @Param(8) String administrativeArea, @NonNull @Param(9) String locality, @NonNull @Param(10) String countryCode, @NonNull @Param(11) String postalCode, @NonNull @Param(12) String sortingCode, @NonNull @Param(13) String phoneNumber, @Param(14) boolean postBox, @NonNull @Param(15) String companyName, @NonNull @Param(16) String emailAddress) {\n        this.name = name;\n        this.address1 = address1;\n        this.address2 = address2;\n        this.address3 = address3;\n        this.address4 = address4;\n        this.address5 = address5;\n        this.administrativeArea = administrativeArea;\n        this.locality = locality;\n        this.countryCode = countryCode;\n        this.postalCode = postalCode;\n        this.sortingCode = sortingCode;\n        this.phoneNumber = phoneNumber;\n        this.postBox = postBox;\n        this.companyName = companyName;\n        this.emailAddress = emailAddress;\n    }\n\n\n    @Nullable\n    public static UserAddress fromIntent(@NonNull Intent data) {\n        if (!data.hasExtra(EXTRA_ADDRESS)) return null;\n        return (UserAddress) data.getParcelableExtra(EXTRA_ADDRESS);\n    }\n\n    @NonNull\n    public String getAddress1() {\n        return address1;\n    }\n\n    @NonNull\n    public String getAddress2() {\n        return address2;\n    }\n\n    @NonNull\n    public String getAddress3() {\n        return address3;\n    }\n\n    @NonNull\n    public String getAddress4() {\n        return address4;\n    }\n\n    @NonNull\n    public String getAddress5() {\n        return address5;\n    }\n\n    @NonNull\n    public String getAdministrativeArea() {\n        return administrativeArea;\n    }\n\n    @NonNull\n    public String getCompanyName() {\n        return companyName;\n    }\n\n    @NonNull\n    public String getCountryCode() {\n        return countryCode;\n    }\n\n    @NonNull\n    public String getEmailAddress() {\n        return emailAddress;\n    }\n\n    @NonNull\n    public String getLocality() {\n        return locality;\n    }\n\n    @NonNull\n    public String getName() {\n        return name;\n    }\n\n    @NonNull\n    public String getPhoneNumber() {\n        return phoneNumber;\n    }\n\n    @NonNull\n    public String getPostalCode() {\n        return postalCode;\n    }\n\n    @NonNull\n    public String getSortingCode() {\n        return sortingCode;\n    }\n\n    public boolean isPostBox() {\n        return postBox;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"UserAddress\").value(name)\n                .value(address1).value(address2).value(address3).value(address4).value(address5)\n                .field(\"administrativeArea\", administrativeArea)\n                .field(\"locality\", locality)\n                .field(\"countryCode\", countryCode)\n                .field(\"postalCode\", postalCode)\n                .field(\"sortingCode\", sortingCode)\n                .field(\"phoneNumber\", phoneNumber)\n                .field(\"postBox\", postBox)\n                .field(\"companyName\", companyName)\n                .field(\"emailAddress\", emailAddress)\n                .end();\n    }\n\n    public static final SafeParcelableCreatorAndWriter<UserAddress> CREATOR = findCreator(UserAddress.class);\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/issuer/ViewTokenRequest.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tapandpay.issuer;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class ViewTokenRequest extends AbstractSafeParcelable {\n    public static final SafeParcelableCreatorAndWriter<ViewTokenRequest> CREATOR = findCreator(ViewTokenRequest.class);\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n}\n"
  },
  {
    "path": "play-services-tapandpay/src/main/java/com/google/android/gms/tapandpay/issuer/WalletAvailabilityChecker.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tapandpay.issuer;\n\nimport androidx.annotation.NonNull;\n\npublic interface WalletAvailabilityChecker {\n    boolean isAvailable(@NonNull String walletId);\n}\n"
  },
  {
    "path": "play-services-tasks/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2020 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\nandroid {\n    namespace \"com.google.android.gms.tasks\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n}\n\napply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG implementation of play-services-tasks'\n\ndependencies {\n    // Dependencies from play-services-tasks:18.4.0\n    api project(':play-services-basement')\n}\n"
  },
  {
    "path": "play-services-tasks/ktx/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2021, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'kotlin-android'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\ndependencies {\n    api project(\":play-services-tasks\")\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion\"\n    implementation \"org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutineVersion\"\n    implementation \"org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutineVersion\"\n}\n\nandroid {\n    namespace \"org.microg.gms.tasks.ktx\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    sourceSets {\n        main.java.srcDirs += 'src/main/kotlin'\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n\n    kotlinOptions {\n        jvmTarget = \"1.8\"\n    }\n}\n\napply from: '../../gradle/publish-android.gradle'\n\ndescription = 'microG kotlin extensions for play-services-tasks'\n"
  },
  {
    "path": "play-services-tasks/ktx/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2021, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<manifest />\n"
  },
  {
    "path": "play-services-tasks/ktx/src/main/kotlin/com/google/android/gms/tasks/Tasks.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2016 JetBrains s.r.o.\n * SPDX-FileCopyrightText: 2021 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.tasks\n\nimport kotlinx.coroutines.*\nimport kotlin.coroutines.*\n\n/**\n * Converts this deferred to the instance of [Task].\n * If deferred is cancelled then resulting task will be cancelled as well.\n */\nfun <T> Deferred<T>.asTask(): Task<T> {\n    val cancellation = CancellationTokenSource()\n    val source = TaskCompletionSource<T>(cancellation.token)\n\n    invokeOnCompletion callback@{\n        if (it is CancellationException) {\n            cancellation.cancel()\n            return@callback\n        }\n\n        val t = getCompletionExceptionOrNull()\n        if (t == null) {\n            source.setResult(getCompleted())\n        } else {\n            source.setException(t as? Exception ?: RuntimeExecutionException(t))\n        }\n    }\n\n    return source.task\n}\n\n/**\n * Converts this task to an instance of [Deferred].\n * If task is cancelled then resulting deferred will be cancelled as well.\n * However, the opposite is not true: if the deferred is cancelled, the [Task] will not be cancelled.\n * For bi-directional cancellation, an overload that accepts [CancellationTokenSource] can be used.\n */\nfun <T> Task<T>.asDeferred(): Deferred<T> = asDeferredImpl(null)\n\n/**\n * Converts this task to an instance of [Deferred] with a [CancellationTokenSource] to control cancellation.\n * The cancellation of this function is bi-directional:\n * * If the given task is cancelled, the resulting deferred will be cancelled.\n * * If the resulting deferred is cancelled, the provided [cancellationTokenSource] will be cancelled.\n *\n * Providing a [CancellationTokenSource] that is unrelated to the receiving [Task] is not supported and\n * leads to an unspecified behaviour.\n */\n@ExperimentalCoroutinesApi // Since 1.5.1, tentatively until 1.6.0\nfun <T> Task<T>.asDeferred(cancellationTokenSource: CancellationTokenSource): Deferred<T> =\n        asDeferredImpl(cancellationTokenSource)\n\nprivate fun <T> Task<T>.asDeferredImpl(cancellationTokenSource: CancellationTokenSource?): Deferred<T> {\n    val deferred = CompletableDeferred<T>()\n    if (isComplete) {\n        val e = exception\n        if (e == null) {\n            if (isCanceled) {\n                deferred.cancel()\n            } else {\n                @Suppress(\"UNCHECKED_CAST\")\n                deferred.complete(result as T)\n            }\n        } else {\n            deferred.completeExceptionally(e)\n        }\n    } else {\n        addOnCompleteListener {\n            val e = it.exception\n            if (e == null) {\n                @Suppress(\"UNCHECKED_CAST\")\n                if (it.isCanceled) deferred.cancel() else deferred.complete(it.result as T)\n            } else {\n                deferred.completeExceptionally(e)\n            }\n        }\n    }\n\n    if (cancellationTokenSource != null) {\n        deferred.invokeOnCompletion {\n            cancellationTokenSource.cancel()\n        }\n    }\n    // Prevent casting to CompletableDeferred and manual completion.\n    return object : Deferred<T> by deferred {}\n}\n\n/**\n * Awaits the completion of the task without blocking a thread.\n *\n * This suspending function is cancellable.\n * If the [Job] of the current coroutine is cancelled or completed while this suspending function is waiting, this function\n * stops waiting for the completion stage and immediately resumes with [CancellationException].\n *\n * For bi-directional cancellation, an overload that accepts [CancellationTokenSource] can be used.\n */\nsuspend fun <T> Task<T>.await(): T = awaitImpl(null)\n\n/**\n * Awaits the completion of the task that is linked to the given [CancellationTokenSource] to control cancellation.\n *\n * This suspending function is cancellable and cancellation is bi-directional:\n * * If the [Job] of the current coroutine is cancelled or completed while this suspending function is waiting, this function\n * cancels the [cancellationTokenSource] and throws a [CancellationException].\n * * If the task is cancelled, then this function will throw a [CancellationException].\n *\n * Providing a [CancellationTokenSource] that is unrelated to the receiving [Task] is not supported and\n * leads to an unspecified behaviour.\n */\n@ExperimentalCoroutinesApi // Since 1.5.1, tentatively until 1.6.0\nsuspend fun <T> Task<T>.await(cancellationTokenSource: CancellationTokenSource): T = awaitImpl(cancellationTokenSource)\n\nprivate suspend fun <T> Task<T>.awaitImpl(cancellationTokenSource: CancellationTokenSource?): T {\n    // fast path\n    if (isComplete) {\n        val e = exception\n        return if (e == null) {\n            if (isCanceled) {\n                throw CancellationException(\"Task $this was cancelled normally.\")\n            } else {\n                @Suppress(\"UNCHECKED_CAST\")\n                result as T\n            }\n        } else {\n            throw e\n        }\n    }\n\n    return suspendCancellableCoroutine { cont ->\n        addOnCompleteListener {\n            val e = it.exception\n            if (e == null) {\n                @Suppress(\"UNCHECKED_CAST\")\n                if (it.isCanceled) cont.cancel() else cont.resume(it.result as T)\n            } else {\n                cont.resumeWithException(e)\n            }\n        }\n\n        if (cancellationTokenSource != null) {\n            cont.invokeOnCancellation {\n                cancellationTokenSource.cancel()\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-tasks/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<manifest />\n"
  },
  {
    "path": "play-services-tasks/src/main/java/com/google/android/gms/tasks/CancellationToken.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020 microG Project Team\n * SPDX-License-Identifier: Apache-2.0 AND CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.tasks;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Propagates notification that operations should be canceled.\n * <p/>\n * Developers writing methods that return a Task should take a {@code CancellationToken} as a parameter if they wish to\n * make the Task cancelable (see below code snippet). A {@code CancellationToken} can only be created by creating a new\n * instance of {@link CancellationTokenSource}. {@code CancellationToken} is immutable and must be canceled by calling\n * {@link CancellationTokenSource#cancel()} on the {@link CancellationTokenSource} that creates it. It can only be\n * canceled once. If canceled, it should not be passed to future operations.\n * <p/>\n * When {@link CancellationTokenSource#cancel()} is called, all the Tasks with the {@code CancellationToken} from that\n * {@link CancellationTokenSource} will be canceled. This operation only flags those Tasks as canceled, and the API\n * author is responsible for stopping whatever the Task is actually doing to free up the resources.\n * <p/>\n * Cancellable {@link Task} example:\n * <pre>\n * public Task<Integer> doSomething(CancellationToken token) {\n *\n *     // Attach a listener that will be called once cancellation is requested.\n *     token.onCanceledRequested(new OnTokenCanceledListener() {\n *         &#64;Override\n *         public void onCanceled() {\n *             // Some other operations to cancel this Task, such as free resources...\n *         }\n *     });\n *\n *     final TaskCompletionSource<Integer> tcs = new TaskCompletionSource<>(token);\n *\n *     // do something...\n *\n * }\n *\n * CancellationTokenSource cts = new CancellationTokenSource();\n * Task<Integer> task = doSomething(cts.getToken());\n * cts.cancel();\n * </pre>\n * Cancellable {@link Task} example in {@link android.app.Activity} context:\n * <pre>\n * public class MyActivity extends Activity {\n *     // ...\n *\n *     &#64;Override\n *     public void onStart() {\n *         super.onStart();\n *\n *         // Typically use one cancellation source per lifecycle.\n *         cancellationSource = new TaskCancellationSource();\n *\n *         // That source's token can be passed to multiple calls.\n *         doSomethingCancellable(cancellationSource.getToken())\n *             .onSuccessTask(result -> doSomethingElse(result, cancellationSource.getToken()));\n *     }\n *\n *     &#64;Override\n *     public void onStop() {\n *         super.onStop();\n *         cancellationSource.cancel();\n *     }\n * }\n * </pre>\n */\n@PublicApi\npublic abstract class CancellationToken {\n    /**\n     * Checks if cancellation has been requested from the {@link CancellationTokenSource}.\n     *\n     * @return {@code true} if cancellation is requested, {@code false} otherwise\n     */\n    public abstract boolean isCancellationRequested();\n\n    /**\n     * Adds an {@link OnTokenCanceledListener} to this {@link CancellationToken}.\n     *\n     * @param listener the listener that will fire once the cancellation request succeeds.\n     */\n    public abstract CancellationToken onCanceledRequested(OnTokenCanceledListener listener);\n}\n"
  },
  {
    "path": "play-services-tasks/src/main/java/com/google/android/gms/tasks/CancellationTokenSource.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0 AND CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.tasks;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.tasks.CancellationTokenImpl;\n\n/**\n * Creates a new {@link CancellationToken} or cancels one that has already created. There is a 1:1 {@link CancellationTokenSource} to {@link CancellationToken} relationship.\n * <p>\n * To create a {@link CancellationToken}, create a {@link CancellationTokenSource} first and then call {@link #getToken()} to get the {@link CancellationToken} for this {@link CancellationTokenSource}.\n *\n * @see CancellationToken\n */\n@PublicApi\npublic class CancellationTokenSource {\n    private CancellationTokenImpl token = new CancellationTokenImpl();\n\n    /**\n     * Creates a new {@link CancellationTokenSource} instance.\n     */\n    public CancellationTokenSource() {\n    }\n\n    /**\n     * Cancels the {@link CancellationToken} if cancellation has not been requested yet.\n     */\n    public void cancel() {\n        token.cancel();\n    }\n\n    /**\n     * Gets the {@link CancellationToken} for this {@link CancellationTokenSource}.\n     *\n     * @return the {@link CancellationToken} that can be passed to asynchronous {@link Task} to cancel the Task.\n     */\n    public CancellationToken getToken() {\n        return token;\n    }\n}\n"
  },
  {
    "path": "play-services-tasks/src/main/java/com/google/android/gms/tasks/Continuation.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2016 microG Project Team\n * SPDX-License-Identifier: Apache-2.0 AND CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.tasks;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * A function that is called to continue execution after completion of a {@link Task}.\n *\n * @see Task#continueWith(Continuation)\n * @see Task#continueWithTask(Continuation)\n */\n@PublicApi\npublic interface Continuation<TResult, TContinuationResult> {\n    /**\n     * Returns the result of applying this Continuation to {@code task}.\n     * <p/>\n     * To propagate failure from the completed Task call {@link Task#getResult()} and allow the\n     * {@link RuntimeExecutionException} to propagate. The RuntimeExecutionException will be\n     * unwrapped such that the Task returned by {@link Task#continueWith(Continuation)} or\n     * {@link Task#continueWithTask(Continuation)} fails with the original exception.\n     * <p/>\n     * To suppress specific failures call {@link Task#getResult(Class)} and catch the exception\n     * types of interest:\n     * <pre>\n     * task.continueWith(new Continuation<String, String>() {\n     *     &#64;Override\n     *     public String then(Task<String> task) {\n     *         try {\n     *             return task.getResult(IOException.class);\n     *         } catch (FileNotFoundException e) {\n     *             return \"Not found\";\n     *         } catch (IOException e) {\n     *             return \"Read failed\";\n     *         }\n     *     }\n     * }</pre>\n     * <p/>\n     * To suppress all failures guard any calls to {@link Task#getResult()} with {@link Task#isSuccessful()}:\n     * <pre>\n     * task.continueWith(new Continuation<String, String>() {\n     *     &#64;Override\n     *     public String then(Task<String> task) {\n     *         if (task.isSuccessful()) {\n     *             return task.getResult();\n     *         } else {\n     *             return DEFAULT_VALUE;\n     *         }\n     *     }\n     * }</pre>\n     *\n     * @param task the completed Task. Never null\n     * @throws Exception if the result couldn't be produced\n     */\n    TContinuationResult then(Task<TResult> task);\n}\n"
  },
  {
    "path": "play-services-tasks/src/main/java/com/google/android/gms/tasks/DuplicateTaskCompletionException.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0 AND CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.tasks;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * An exception indicating that something attempted to set a result, exception, or cancellation on a {@link Task} that was already completed.\n */\n@PublicApi\npublic class DuplicateTaskCompletionException extends IllegalStateException {\n\n    private DuplicateTaskCompletionException(String s) {\n        super(s);\n    }\n\n    /**\n     * Creates a DuplicateTaskCompletionException from a {@link Task}.\n     *\n     * The {@link Task} must be complete.\n     */\n    public static DuplicateTaskCompletionException of(Task<?> task) {\n        if (!task.isComplete()) throw new IllegalStateException(\"Task is not yet completed\");\n        return new DuplicateTaskCompletionException(\"Task is already completed\");\n    }\n}\n"
  },
  {
    "path": "play-services-tasks/src/main/java/com/google/android/gms/tasks/OnCanceledListener.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0 AND CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.tasks;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Listener called when a {@link Task} is canceled.\n */\n@PublicApi\npublic interface OnCanceledListener {\n    /**\n     * Called when the Task is canceled successfully.\n     */\n    public abstract void onCanceled();\n}\n"
  },
  {
    "path": "play-services-tasks/src/main/java/com/google/android/gms/tasks/OnCompleteListener.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2016, microG Project Team\n * SPDX-License-Identifier: Apache-2.0 AND CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.tasks;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Listener called when a {@link Task} completes.\n *\n * @see Task#addOnCompleteListener(OnCompleteListener)\n */\n@PublicApi\npublic interface OnCompleteListener<TResult> {\n    /**\n     * Called when the Task completes.\n     *\n     * @param task the completed Task. Never null\n     */\n    void onComplete(Task<TResult> task);\n}\n"
  },
  {
    "path": "play-services-tasks/src/main/java/com/google/android/gms/tasks/OnFailureListener.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2016, microG Project Team\n * SPDX-License-Identifier: Apache-2.0 AND CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.tasks;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Listener called when a {@link Task} fails with an exception.\n *\n * @see Task#addOnFailureListener(OnFailureListener)\n */\n@PublicApi\npublic interface OnFailureListener {\n\n    /**\n     * Called when the Task fails with an exception.\n     *\n     * @param e the exception that caused the Task to fail. Never null\n     */\n    void onFailure(Exception e);\n}\n"
  },
  {
    "path": "play-services-tasks/src/main/java/com/google/android/gms/tasks/OnSuccessListener.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2016, microG Project Team\n * SPDX-License-Identifier: Apache-2.0 AND CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.tasks;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Listener called when a {@link Task} completes successfully.\n *\n * @see Task#addOnSuccessListener(OnSuccessListener)\n */\n@PublicApi\npublic interface OnSuccessListener<TResult> {\n    /**\n     * Called when the {@link Task} completes successfully.\n     *\n     * @param result the result of the Task\n     */\n    void onSuccess(TResult result);\n}\n"
  },
  {
    "path": "play-services-tasks/src/main/java/com/google/android/gms/tasks/OnTokenCanceledListener.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0 AND CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.tasks;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Listener called when a {@link CancellationToken} is canceled successfully.\n *\n * @see CancellationToken#onCanceledRequested(OnTokenCanceledListener)\n */\n@PublicApi\npublic interface OnTokenCanceledListener {\n    /**\n     * Called when the {@link CancellationToken} is canceled successfully.\n     */\n    void onCanceled();\n}\n"
  },
  {
    "path": "play-services-tasks/src/main/java/com/google/android/gms/tasks/RuntimeExecutionException.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2016, microG Project Team\n * SPDX-License-Identifier: Apache-2.0 AND CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.tasks;\n\nimport org.microg.gms.common.PublicApi;\n\nimport java.util.concurrent.ExecutionException;\n\n/**\n * Runtime version of {@link ExecutionException}.\n *\n * @see Task#getResult(Class)\n */\n@PublicApi\npublic class RuntimeExecutionException extends RuntimeException {\n    public RuntimeExecutionException(Throwable cause) {\n        super(cause);\n    }\n}\n"
  },
  {
    "path": "play-services-tasks/src/main/java/com/google/android/gms/tasks/SuccessContinuation.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020 microG Project Team\n * SPDX-License-Identifier: Apache-2.0 AND CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.tasks;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * A function that is called to continue execution then a {@link Task} succeeds.\n * @see Task#onSuccessTask\n */\n@PublicApi\npublic interface SuccessContinuation<TResult, TContinuationResult> {\n    /**\n     * Returns the result of applying this SuccessContinuation to Task.\n     * <p>\n     * The SuccessContinuation only happens then the Task is successful. If the previous Task fails, the onSuccessTask\n     * continuation will be skipped and failure listeners will be invoked.\n     * <p>\n     * <pre>\n     * private Task<String> doSomething(String string) {\n     *     // do something\n     * }\n     * task.onSuccessTask(new SuccessContinuation<String, String>() {\n     *     &#64;NonNull\n     *     &#64;Override\n     *     public Task<String> then(String string) {\n     *         return doSomething(string);\n     *     }\n     * });\n     * </pre>\n     *\n     * @param result the result of completed Task\n     * @throws Exception if the result couldn't be produced\n     */\n    Task<TContinuationResult> then(TResult result) throws Exception;\n}\n"
  },
  {
    "path": "play-services-tasks/src/main/java/com/google/android/gms/tasks/Task.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2016 microG Project Team\n * SPDX-License-Identifier: Apache-2.0 AND CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.tasks;\n\nimport android.app.Activity;\n\nimport org.microg.gms.common.PublicApi;\n\nimport java.util.concurrent.Executor;\n\n/**\n * Represents an asynchronous operation.\n */\n@PublicApi\npublic abstract class Task<TResult> {\n\n    public Task() {\n    }\n\n    /**\n     * Adds a listener that is called if the Task is canceled.\n     * <p>\n     * The listener will be called on main application thread. If the Task has already been canceled, a call to the listener will be immediately scheduled. If multiple listeners are added, they will be called in the order in which they were added.\n     *\n     * @return this Task\n     */\n    public Task<TResult> addOnCanceledListener(OnCanceledListener listener) {\n        throw new UnsupportedOperationException(\"addOnCanceledListener is not implemented\");\n    }\n\n    /**\n     * Adds a listener that is called if the Task is canceled.\n     * <p>\n     * If the Task has already been canceled, a call to the listener will be immediately scheduled. If multiple listeners are added, they will be called in the order in which they were added.\n     *\n     * @param executor the executor to use to call the listener\n     * @return this Task\n     */\n    public Task<TResult> addOnCanceledListener(Executor executor, OnCanceledListener listener) {\n        throw new UnsupportedOperationException(\"addOnCanceledListener is not implemented\");\n    }\n\n    /**\n     * Adds an Activity-scoped listener that is called if the Task is canceled.\n     * <p>\n     * The listener will be called on main application thread. If the Task has already been canceled, a call to the listener will be immediately scheduled. If multiple listeners are added, they will be called in the order in which they were added.\n     * <p>\n     * The listener will be automatically removed during {@link Activity#onStop()}.\n     *\n     * @return this Task\n     */\n    public Task<TResult> addOnCanceledListener(Activity activity, OnCanceledListener listener) {\n        throw new UnsupportedOperationException(\"addOnCanceledListener is not implemented\");\n    }\n\n    /**\n     * Adds a listener that is called when the Task completes.\n     * <p/>\n     * The listener will be called on main application thread. If the Task is already complete, a\n     * call to the listener will be immediately scheduled. If multiple listeners are added, they\n     * will be called in the order in which they were added.\n     *\n     * @return this Task\n     */\n    public Task<TResult> addOnCompleteListener(OnCompleteListener<TResult> listener) {\n        throw new UnsupportedOperationException(\"addOnCompleteListener is not implemented\");\n    }\n\n    /**\n     * Adds an Activity-scoped listener that is called when the Task completes.\n     * <p/>\n     * The listener will be called on main application thread. If the Task is already complete, a\n     * call to the listener will be immediately scheduled. If multiple listeners are added, they\n     * will be called in the order in which they were added.\n     * <p/>\n     * The listener will be automatically removed during {@link Activity#onStop()}.\n     *\n     * @return this Task\n     */\n    public Task<TResult> addOnCompleteListener(Activity activity, OnCompleteListener<TResult> listener) {\n        throw new UnsupportedOperationException(\"addOnCompleteListener is not implemented\");\n    }\n\n    /**\n     * Adds a listener that is called when the Task completes.\n     * <p/>\n     * If the Task is already complete, a call to the listener will be immediately scheduled. If\n     * multiple listeners are added, they will be called in the order in which they were added.\n     *\n     * @param executor the executor to use to call the listener\n     * @return this Task\n     */\n    public Task<TResult> addOnCompleteListener(Executor executor, OnCompleteListener<TResult> listener) {\n        throw new UnsupportedOperationException(\"addOnCompleteListener is not implemented\");\n    }\n\n    /**\n     * Adds an Activity-scoped listener that is called if the Task fails.\n     * <p/>\n     * The listener will be called on main application thread. If the Task has already failed, a\n     * call to the listener will be immediately scheduled. If multiple listeners are added, they\n     * will be called in the order in which they were added.\n     * <p/>\n     * The listener will be automatically removed during {@link Activity#onStop()}.\n     *\n     * @return this Task\n     */\n    public abstract Task<TResult> addOnFailureListener(Activity activity, OnFailureListener listener);\n\n    /**\n     * Adds a listener that is called if the Task fails.\n     * <p/>\n     * The listener will be called on main application thread. If the Task has already failed, a\n     * call to the listener will be immediately scheduled. If multiple listeners are added, they\n     * will be called in the order in which they were added.\n     *\n     * @return this Task\n     */\n    public abstract Task<TResult> addOnFailureListener(OnFailureListener listener);\n\n    /**\n     * Adds a listener that is called if the Task fails.\n     * <p/>\n     * If the Task has already failed, a call to the listener will be immediately scheduled. If\n     * multiple listeners are added, they will be called in the order in which they were added.\n     *\n     * @param executor the executor to use to call the listener\n     * @return this Task\n     */\n    public abstract Task<TResult> addOnFailureListener(Executor executor, OnFailureListener listener);\n\n\n    /**\n     * Adds a listener that is called if the Task completes successfully.\n     * <p/>\n     * If multiple listeners are added, they will be called in the order in which they were added. If\n     * the Task has already completed successfully, a call to the listener will be immediately scheduled.\n     *\n     * @param executor the executor to use to call the listener\n     * @return this Task\n     */\n    public abstract Task<TResult> addOnSuccessListener(Executor executor, OnSuccessListener<? super TResult> listener);\n\n    /**\n     * Adds a listener that is called if the Task completes successfully.\n     * <p/>\n     * The listener will be called on the main application thread. If the Task has already\n     * completed successfully, a call to the listener will be immediately scheduled. If multiple\n     * listeners are added, they will be called in the order in which they were added.\n     *\n     * @return this Task\n     */\n    public abstract Task<TResult> addOnSuccessListener(OnSuccessListener<? super TResult> listener);\n\n    /**\n     * Adds an Activity-scoped listener that is called if the Task completes successfully.\n     * <p/>\n     * The listener will be called on the main application thread. If the Task has already\n     * completed successfully, a call to the listener will be immediately scheduled. If multiple\n     * listeners are added, they will be called in the order in which they were added.\n     * <p/>\n     * The listener will be automatically removed during {@link Activity#onStop()}.\n     *\n     * @return this Task\n     */\n    public abstract Task<TResult> addOnSuccessListener(Activity activity, OnSuccessListener<? super TResult> listener);\n\n\n    /**\n     * Returns a new Task that will be completed with the result of applying the specified\n     * Continuation to this Task.\n     * <p/>\n     * The Continuation will be called on the main application thread.\n     * <p/>\n     * If the previous Task is canceled, the returned Task will also be canceled and the Continuation would not execute.\n     *\n     * @see Continuation#then(Task)\n     */\n    public <TContinuationResult> Task<TContinuationResult> continueWith(Continuation<TResult, TContinuationResult> continuation) {\n        throw new UnsupportedOperationException(\"continueWith is not implemented\");\n    }\n\n    /**\n     * Returns a new Task that will be completed with the result of applying the specified Continuation to this Task.\n     * <p/>\n     * If the previous Task is canceled, the returned Task will also be canceled and the Continuation would not execute.\n     *\n     * @param executor the executor to use to call the Continuation\n     * @see Continuation#then(Task)\n     */\n    public <TContinuationResult> Task<TContinuationResult> continueWith(Executor executor, Continuation<TResult, TContinuationResult> continuation) {\n        throw new UnsupportedOperationException(\"continueWith is not implemented\");\n    }\n\n    /**\n     * Returns a new Task that will be completed with the result of applying the specified\n     * Continuation to this Task.\n     * <p/>\n     * The Continuation will be called on the main application thread.\n     * <p/>\n     * If the previous Task is canceled, the Continuation would still execute and task.isCanceled() is true can be\n     * observed in the Continuation.\n     *\n     * @see Continuation#then(Task)\n     */\n    public <TContinuationResult> Task<TContinuationResult> continueWithTask(Continuation<TResult, Task<TContinuationResult>> continuation) {\n        throw new UnsupportedOperationException(\"continueWithTask is not implemented\");\n    }\n\n    /**\n     * Returns a new Task that will be completed with the result of applying the specified Continuation to this Task.\n     * <p/>\n     * If the previous Task is canceled, the Continuation would still execute and task.isCanceled() is true can be\n     * observed in the Continuation.\n     *\n     * @param executor the executor to use to call the Continuation\n     * @see Continuation#then(Task)\n     */\n    public <TContinuationResult> Task<TContinuationResult> continueWithTask(Executor executor, Continuation<TResult, Task<TContinuationResult>> continuation) {\n        throw new UnsupportedOperationException(\"continueWithTask is not implemented\");\n    }\n\n    /**\n     * Returns the exception that caused the Task to fail. Returns {@code null} if the Task is not\n     * yet complete, or completed successfully.\n     */\n    public abstract Exception getException();\n\n    /**\n     * Gets the result of the Task, if it has already completed.\n     *\n     * @throws IllegalStateException     if the Task is not yet complete\n     * @throws RuntimeExecutionException if the Task failed with an exception\n     */\n    public abstract TResult getResult();\n\n    /**\n     * Gets the result of the Task, if it has already completed.\n     *\n     * @throws IllegalStateException     if the Task is not yet complete\n     * @throws X                         if the Task failed with an exception of type X\n     * @throws RuntimeExecutionException if the Task failed with an exception that was not of type X\n     */\n    public abstract <X extends Throwable> TResult getResult(Class<X> exceptionType) throws X;\n\n    /**\n     * Returns {@code true} if the Task is canceled; {@code false} otherwise.\n     */\n    public abstract boolean isCanceled();\n\n    /**\n     * Returns {@code true} if the Task is complete; {@code false} otherwise.\n     */\n    public abstract boolean isComplete();\n\n    /**\n     * Returns {@code true} if the Task has completed successfully; {@code false} otherwise.\n     */\n    public abstract boolean isSuccessful();\n\n    /**\n     * Returns a new Task that will be completed with the result of applying the specified SuccessContinuation to this Task when this Task completes successfully. If the previous Task fails, the onSuccessTask completion will be skipped and failure listeners will be invoked.\n     * <p>\n     * The SuccessContinuation will be called on the main application thread.\n     * <p>\n     * If the previous Task is canceled, the returned Task will also be canceled and the SuccessContinuation would not execute.\n     *\n     * @see SuccessContinuation#then\n     */\n    public <TContinuationResult> Task<TContinuationResult> onSuccessTask(SuccessContinuation<TResult, TContinuationResult> successContinuation) {\n        throw new UnsupportedOperationException(\"onSuccessTask is not implemented\");\n    }\n\n    /**\n     * Returns a new Task that will be completed with the result of applying the specified SuccessContinuation to this Task when this Task completes successfully. If the previous Task fails, the onSuccessTask completion will be skipped and failure listeners will be invoked.\n     * <p>\n     * If the previous Task is canceled, the returned Task will also be canceled and the SuccessContinuation would not execute.\n     *\n     * @param executor the executor to use to call the SuccessContinuation\n     * @see SuccessContinuation#then\n     */\n    public <TContinuationResult> Task<TContinuationResult> onSuccessTask(Executor executor, SuccessContinuation<TResult, TContinuationResult> successContinuation) {\n        throw new UnsupportedOperationException(\"onSuccessTask is not implemented\");\n    }\n\n}\n"
  },
  {
    "path": "play-services-tasks/src/main/java/com/google/android/gms/tasks/TaskCompletionSource.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2016 microG Project Team\n * SPDX-License-Identifier: Apache-2.0 AND CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.tasks;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.tasks.TaskImpl;\n\n/**\n * Provides the ability to create an incomplete {@link Task}-based APIs.\n * <p/>\n * Use a {@code TaskCompletionSource} to set a result or exception on a Task returned from an asynchronous API:\n * <pre>\n * public class MarcoPolo {\n *     public static Task<String> marco(int delay) {\n *         TaskCompletionSource<String> taskCompletionSource = new TaskCompletionSource<>();\n *\n *         new Handler().postDelayed(() -> taskCompletionSource.setResult(\"polo\"), delay);\n *\n *         return taskCompletionSource.getTask();\n *     }\n * }\n * </pre>\n * And then your APIs can be used as any other {@link Task}-consuming APIs:\n * <pre>\n * public class MyActivity extends Activity {\n *     &#64;Override\n *     public void onStart() {\n *         super.onStart();\n *\n *         marco(1000).addOnCompleteListener(\n *             task -> Log.d(TAG, \"got message after one second: \" + task.getResult()));\n *     }\n * }\n * </pre>\n *\n * and later complete it by either\n * calling {@link #setResult(TResult)} or {@link #setException(Exception)}.\n */\n@PublicApi\npublic class TaskCompletionSource<TResult> {\n    private TaskImpl<TResult> task = new TaskImpl<>();\n\n    /**\n     * Creates an instance of {@link TaskCompletionSource}.\n     */\n    public TaskCompletionSource() {\n    }\n\n    /**\n     * Creates an instance of {@link TaskCompletionSource} with a {@link CancellationToken} so that the Task can be set to canceled when {@link CancellationToken} is canceled.\n     */\n    public TaskCompletionSource(CancellationToken token) {\n        token.onCanceledRequested(() -> {\n            try {\n                task.cancel();\n            } catch (DuplicateTaskCompletionException ignored) {\n            }\n        });\n    }\n\n    /**\n     * Returns the Task.\n     */\n    public Task<TResult> getTask() {\n        return task;\n    }\n\n    /**\n     * Completes the Task with the specified exception.\n     *\n     * @throws IllegalStateException if the Task is already complete\n     */\n    public void setException(Exception e) {\n        task.setException(e);\n    }\n\n    /**\n     * Completes the Task with the specified exception, unless the Task has already completed.\n     * If the Task has already completed, the call does nothing.\n     *\n     * @return {@code true} if the exception was set successfully, {@code false} otherwise\n     */\n    public boolean trySetException(Exception e) {\n        try {\n            setException(e);\n            return true;\n        } catch (DuplicateTaskCompletionException ignored) {\n            return false;\n        }\n    }\n\n    /**\n     * Completes the Task with the specified result.\n     *\n     * @throws IllegalStateException if the Task is already complete\n     */\n    public void setResult(TResult result) {\n        task.setResult(result);\n    }\n\n    /**\n     * Completes the Task with the specified result, unless the Task has already completed.\n     * If the Task has already completed, the call does nothing.\n     *\n     * @return {@code true} if the result was set successfully, {@code false} otherwise\n     */\n    public boolean trySetResult(TResult result) {\n        try {\n            setResult(result);\n            return true;\n        } catch (DuplicateTaskCompletionException ignored) {\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-tasks/src/main/java/com/google/android/gms/tasks/TaskExecutors.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0 AND CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.tasks;\n\nimport android.os.Handler;\nimport android.os.Looper;\n\nimport org.microg.gms.common.PublicApi;\n\nimport java.util.concurrent.Executor;\n\n/**\n * Standard {@link Executor} instances for use with {@link Task}.\n */\n@PublicApi\npublic final class TaskExecutors {\n    /**\n     * An Executor that uses the main application thread.\n     */\n    public static final Executor MAIN_THREAD = new Executor() {\n        private Handler handler = new Handler(Looper.getMainLooper());\n        @Override\n        public void execute(Runnable command) {\n            handler.post(command);\n        }\n    };\n}\n"
  },
  {
    "path": "play-services-tasks/src/main/java/com/google/android/gms/tasks/Tasks.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2016 microG Project Team\n * SPDX-License-Identifier: Apache-2.0 AND CC-BY-4.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.tasks;\n\nimport android.os.Handler;\nimport android.os.Looper;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.tasks.CancellationTokenImpl;\nimport org.microg.gms.tasks.TaskImpl;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.CancellationException;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.atomic.AtomicReference;\n\n/**\n * {@link Task} utility methods.\n */\n@PublicApi\npublic final class Tasks {\n\n    /**\n     * Blocks until the specified Task is complete.\n     *\n     * @return the Task's result\n     * @throws ExecutionException   if the Task fails\n     * @throws InterruptedException if an interrupt occurs while waiting for the Task to complete\n     * @throws TimeoutException     if the specified timeout is reached before the Task completes\n     */\n    public static <TResult> TResult await(Task<TResult> task, long timeout, TimeUnit unit) throws ExecutionException, InterruptedException, TimeoutException {\n        if (task == null) throw new IllegalArgumentException(\"Task must not be null\");\n        if (timeout <= 0) throw new IllegalArgumentException(\"Timeout must be positive\");\n        if (unit == null) throw new IllegalArgumentException(\"TimeUnit must not be null\");\n        if (task.isComplete()) return handleCompletedTask(task);\n        CountDownLatch latch = new CountDownLatch(1);\n        task.addOnCompleteListener(Runnable::run, completedTask -> latch.countDown());\n        if (latch.await(timeout, unit)) {\n            return handleCompletedTask(task);\n        }\n        throw new TimeoutException(\"Timed out waiting for Task\");\n    }\n\n    /**\n     * Blocks until the specified Task is complete.\n     *\n     * @return the Task's result\n     * @throws ExecutionException   if the Task fails\n     * @throws InterruptedException if an interrupt occurs while waiting for the Task to complete\n     */\n    public static <TResult> TResult await(Task<TResult> task) throws ExecutionException, InterruptedException {\n        if (Looper.getMainLooper().getThread() == Thread.currentThread())\n            throw new IllegalStateException(\"Must not be invoked on main thread\");\n        if (task == null) throw new IllegalArgumentException(\"Task must not be null\");\n        if (task.isComplete()) return handleCompletedTask(task);\n        CountDownLatch latch = new CountDownLatch(1);\n        task.addOnCompleteListener(Runnable::run, completedTask -> latch.countDown());\n        latch.await();\n        return handleCompletedTask(task);\n    }\n\n    private static <TResult> TResult handleCompletedTask(Task<TResult> task) throws ExecutionException {\n        if (task.isSuccessful()) {\n            return task.getResult();\n        }\n        if (task.isCanceled()) {\n            throw new CancellationException(\"Task is already canceled\");\n        }\n        throw new ExecutionException(task.getException());\n    }\n\n    /**\n     * Returns a {@link Task} that will be completed with the result of the specified {@code Callable}.\n     * <p/>\n     * If a non-{@link Exception} throwable is thrown in the callable, the {@link Task} will be failed with a\n     * {@link RuntimeException} whose cause is the original throwable.\n     * <p/>\n     * The {@code Callable} will be called on the main application thread.\n     *\n     * @deprecated Use {@link TaskCompletionSource} instead, which allows the caller to manage their own Executor.\n     */\n    @Deprecated\n    public static <TResult> Task<TResult> call(Callable<TResult> callable) {\n        return call(TaskExecutors.MAIN_THREAD, callable);\n    }\n\n    /**\n     * Returns a {@link Task} that will be completed with the result of the specified {@code Callable}.\n     * <p/>\n     * If a non-{@link Exception} throwable is thrown in the callable, the {@link Task} will be failed with a\n     * {@link RuntimeException} whose cause is the original throwable.\n     *\n     * @param executor the Executor to use to call the {@code Callable}\n     * @deprecated Use {@link TaskCompletionSource} instead, which allows the caller to manage their own Executor.\n     */\n    @Deprecated\n    public static <TResult> Task<TResult> call(Executor executor, Callable<TResult> callable) {\n        if (executor == null) throw new IllegalArgumentException(\"Executor must not be null\");\n        if (callable == null) throw new IllegalArgumentException(\"Callable must not be null\");\n        TaskCompletionSource<TResult> taskCompletionSource = new TaskCompletionSource<>();\n        executor.execute(() -> {\n            try {\n                taskCompletionSource.setResult(callable.call());\n            } catch (Exception e) {\n                taskCompletionSource.trySetException(e);\n            } catch (Throwable t) {\n                taskCompletionSource.trySetException(new RuntimeException(t));\n            }\n        });\n        return taskCompletionSource.getTask();\n    }\n\n    /**\n     * Returns a canceled Task.\n     */\n    public static <TResult> Task<TResult> forCancelled() {\n        TaskImpl<TResult> task = new TaskImpl<>();\n        task.cancel();\n        return task;\n    }\n\n    /**\n     * Returns a completed Task with the specified exception.\n     */\n    public static <TResult> Task<TResult> forException(Exception e) {\n        TaskImpl<TResult> task = new TaskImpl<>();\n        task.setException(e);\n        return task;\n    }\n\n    /**\n     * Returns a completed Task with the specified result.\n     */\n    public static <TResult> Task<TResult> forResult(TResult result) {\n        TaskImpl<TResult> task = new TaskImpl<>();\n        task.setResult(result);\n        return task;\n    }\n\n    /**\n     * Returns a Task that completes successfully when all of the specified Tasks complete\n     * successfully. Does not accept nulls.\n     * <p/>\n     * The returned Task would fail if any of the provided Tasks fail. The returned Task would be set to canceled if\n     * any of the provided Tasks is canceled and no failure is detected.\n     *\n     * @throws NullPointerException if any of the provided Tasks are null\n     */\n    public static Task<Void> whenAll(Collection<? extends Task<?>> tasks) {\n        if (tasks == null || tasks.isEmpty()) {\n            return forResult(null);\n        }\n        for (Task<?> task : tasks) {\n            if (task == null) throw new NullPointerException(\"null tasks are not accepted\");\n        }\n        TaskImpl<Void> allTask = new TaskImpl<>();\n        AtomicInteger finishedTasks = new AtomicInteger(0);\n        AtomicInteger failedTasks = new AtomicInteger(0);\n        AtomicReference<Exception> exceptionReference = new AtomicReference<>(null);\n        AtomicBoolean isCancelled = new AtomicBoolean(false);\n        for (Task<?> task : tasks) {\n            task.addOnCompleteListener(Runnable::run, completedTask -> {\n                if (!completedTask.isSuccessful()) {\n                    if (completedTask.isCanceled()) {\n                        isCancelled.set(true);\n                    } else {\n                        exceptionReference.set(completedTask.getException());\n                        failedTasks.incrementAndGet();\n                    }\n                }\n                if (finishedTasks.incrementAndGet() != tasks.size()) return;\n                Exception exception = exceptionReference.get();\n                if (exception != null) {\n                    allTask.setException(new ExecutionException(failedTasks.get() + \" out of \" + tasks.size() + \" underlying tasks failed\", exception));\n                } else if (isCancelled.get()) {\n                    allTask.cancel();\n                } else {\n                    allTask.setResult(null);\n                }\n            });\n        }\n        return allTask;\n    }\n\n    /**\n     * Returns a Task that completes successfully when all of the specified Tasks complete\n     * successfully. Does not accept nulls.\n     * <p/>\n     * The returned Task would fail if any of the provided Tasks fail. The returned Task would be set to canceled if\n     * any of the provided Tasks is canceled and no failure is detected.\n     *\n     * @throws NullPointerException if any of the provided Tasks are null\n     */\n    public static Task<Void> whenAll(Task<?>... tasks) {\n        if (tasks == null || tasks.length == 0) {\n            return forResult(null);\n        }\n        return whenAll(Arrays.asList(tasks));\n    }\n\n    /**\n     * Returns a Task with a list of Tasks that completes successfully when all of the specified Tasks complete. This\n     * Task would always succeed even if any of the provided Tasks fail or canceled. Does not accept nulls.\n     *\n     * @throws NullPointerException if any of the provided Tasks are null\n     */\n    public static Task<List<Task<?>>> whenAllComplete(Task<?>... tasks) {\n        if (tasks == null || tasks.length == 0) {\n            return forResult(Collections.emptyList());\n        }\n        return whenAllComplete(Arrays.asList(tasks));\n    }\n\n    /**\n     * Returns a Task with a list of Tasks that completes successfully when all of the specified Tasks complete. This\n     * Task would always succeed even if any of the provided Tasks fail or canceled. Does not accept nulls.\n     *\n     * @throws NullPointerException if any of the provided Tasks are null\n     */\n    public static Task<List<Task<?>>> whenAllComplete(Collection<? extends Task<?>> tasks) {\n        if (tasks == null || tasks.isEmpty()) {\n            return forResult(Collections.emptyList());\n        }\n        return whenAll(tasks).continueWithTask(TaskExecutors.MAIN_THREAD, allTask -> forResult(new ArrayList<>(tasks)));\n    }\n\n    /**\n     * Returns a Task with a list of Task results that completes successfully when all of the specified Tasks complete\n     * successfully. This Task would fail if any of the provided Tasks fail. Does not accept nulls.\n     * <p/>\n     * This Task would be set to canceled if any of the provided Tasks is canceled and no failure is detected.\n     *\n     * @throws NullPointerException if any of the provided Tasks are null\n     */\n    public static <TResult> Task<List<TResult>> whenAllSuccess(Task<? extends TResult>... tasks) {\n        if (tasks == null || tasks.length == 0) {\n            return forResult(Collections.emptyList());\n        }\n        return whenAllSuccess(Arrays.asList(tasks));\n    }\n\n    /**\n     * Returns a Task with a list of Task results that completes successfully when all of the specified Tasks complete\n     * successfully. This Task would fail if any of the provided Tasks fail. Does not accept nulls.\n     * <p/>\n     * This Task would be set to canceled if any of the provided Tasks is canceled and no failure is detected.\n     *\n     * @throws NullPointerException if any of the provided Tasks are null\n     */\n    public static <TResult> Task<List<TResult>> whenAllSuccess(Collection<? extends Task<? extends TResult>> tasks) {\n        if (tasks == null || tasks.isEmpty()) {\n            return forResult(Collections.emptyList());\n        }\n        return whenAll(tasks).continueWithTask(TaskExecutors.MAIN_THREAD, allTask -> {\n            List<TResult> results = new ArrayList<>(tasks.size());\n            for (Task<? extends TResult> task : tasks) {\n                results.add(task.getResult());\n            }\n            return forResult(results);\n        });\n    }\n\n    /**\n     * Returns a new Task which will return a TimeoutException if a result is not returned within the specified time\n     * period.\n     *\n     * @return A new Task.\n     */\n    public static <T> Task<T> withTimeout(Task<T> task, long timeout, TimeUnit unit) {\n        if (task == null) throw new IllegalArgumentException(\"Task must not be null\");\n        if (timeout <= 0) throw new IllegalArgumentException(\"Timeout must be positive\");\n        if (unit == null) throw new IllegalArgumentException(\"TimeUnit must not be null\");\n        CancellationTokenImpl cancellationToken = new CancellationTokenImpl();\n        TaskCompletionSource<T> taskCompletionSource = new TaskCompletionSource<>(cancellationToken);\n        Handler handler = new Handler(Looper.getMainLooper());\n        handler.postDelayed(() -> taskCompletionSource.trySetException(new TimeoutException()), unit.toMillis(timeout));\n        task.addOnCompleteListener(completedTask -> {\n            handler.removeCallbacksAndMessages(null);\n            if (completedTask.isSuccessful()) {\n                taskCompletionSource.trySetResult(completedTask.getResult());\n            } else if (completedTask.isCanceled()) {\n                cancellationToken.cancel();\n            } else {\n                taskCompletionSource.trySetException(completedTask.getException());\n            }\n        });\n        return taskCompletionSource.getTask();\n    }\n}\n"
  },
  {
    "path": "play-services-tasks/src/main/java/org/microg/gms/tasks/CancellationTokenImpl.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.tasks;\n\nimport com.google.android.gms.tasks.CancellationToken;\nimport com.google.android.gms.tasks.DuplicateTaskCompletionException;\nimport com.google.android.gms.tasks.OnTokenCanceledListener;\n\npublic class CancellationTokenImpl extends CancellationToken {\n    private TaskImpl<Void> task = new TaskImpl<>();\n\n    @Override\n    public boolean isCancellationRequested() {\n        return task.isComplete();\n    }\n\n    @Override\n    public CancellationToken onCanceledRequested(OnTokenCanceledListener listener) {\n        task.addOnSuccessListener(aVoid -> listener.onCanceled());\n        return this;\n    }\n\n    public void cancel() {\n        try {\n            task.cancel();\n        } catch (DuplicateTaskCompletionException ignored) {\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-tasks/src/main/java/org/microg/gms/tasks/CancelledExecutor.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.tasks;\n\nimport com.google.android.gms.tasks.OnCanceledListener;\nimport com.google.android.gms.tasks.Task;\n\nimport java.util.concurrent.Executor;\n\npublic class CancelledExecutor<TResult> extends UpdateExecutor<TResult> {\n    private OnCanceledListener listener;\n\n    public CancelledExecutor(Executor executor, OnCanceledListener listener) {\n        super(executor);\n        this.listener = listener;\n    }\n\n    @Override\n    public void onTaskUpdate(Task<TResult> task) {\n        if (task.isCanceled()) {\n            execute(() -> listener.onCanceled());\n        }\n    }\n\n    @Override\n    public void cancel() {\n        super.cancel();\n        listener = null;\n    }\n}\n\n"
  },
  {
    "path": "play-services-tasks/src/main/java/org/microg/gms/tasks/CompletedExecutor.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.tasks;\n\nimport com.google.android.gms.tasks.OnCompleteListener;\nimport com.google.android.gms.tasks.Task;\n\nimport java.util.concurrent.Executor;\n\npublic class CompletedExecutor<TResult> extends UpdateExecutor<TResult> {\n    private OnCompleteListener<TResult> listener;\n\n    public CompletedExecutor(Executor executor, OnCompleteListener<TResult> listener) {\n        super(executor);\n        this.listener = listener;\n    }\n\n    @Override\n    public void onTaskUpdate(Task<TResult> task) {\n        if (task.isComplete()) {\n            execute(() -> listener.onComplete(task));\n        }\n    }\n\n    @Override\n    public void cancel() {\n        super.cancel();\n        listener = null;\n    }\n}\n"
  },
  {
    "path": "play-services-tasks/src/main/java/org/microg/gms/tasks/ContinuationExecutor.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.tasks;\n\nimport com.google.android.gms.tasks.Continuation;\nimport com.google.android.gms.tasks.Task;\nimport com.google.android.gms.tasks.TaskCompletionSource;\n\nimport java.util.concurrent.Executor;\n\npublic class ContinuationExecutor<TResult, TContinuationResult> extends UpdateExecutor<TResult> {\n    private Continuation<TResult, TContinuationResult> continuation;\n    private TaskCompletionSource<TContinuationResult> completionSource = new TaskCompletionSource<>();\n\n    public ContinuationExecutor(Executor executor, Continuation<TResult, TContinuationResult> continuation) {\n        super(executor);\n        this.continuation = continuation;\n    }\n\n    @Override\n    public void onTaskUpdate(Task<TResult> task) {\n        if (task.isComplete()) {\n            execute(() -> {\n                try {\n                    completionSource.setResult(continuation.then(task));\n                } catch (Exception e) {\n                    completionSource.setException(e);\n                }\n            });\n        }\n    }\n\n    public Task<TContinuationResult> getTask() {\n        return completionSource.getTask();\n    }\n\n    @Override\n    public void cancel() {\n        super.cancel();\n        continuation = null;\n        completionSource = null;\n    }\n}\n"
  },
  {
    "path": "play-services-tasks/src/main/java/org/microg/gms/tasks/ContinuationWithExecutor.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.tasks;\n\nimport com.google.android.gms.tasks.Continuation;\nimport com.google.android.gms.tasks.Task;\nimport com.google.android.gms.tasks.TaskCompletionSource;\n\nimport java.util.concurrent.Executor;\n\npublic class ContinuationWithExecutor<TResult, TContinuationResult> extends UpdateExecutor<TResult> {\n    private Continuation<TResult, Task<TContinuationResult>> continuation;\n    private TaskCompletionSource<TContinuationResult> completionSource = new TaskCompletionSource<>();\n\n    public ContinuationWithExecutor(Executor executor, Continuation<TResult, Task<TContinuationResult>> continuation) {\n        super(executor);\n        this.continuation = continuation;\n    }\n\n    @Override\n    public void onTaskUpdate(Task<TResult> task) {\n        if (task.isComplete()) {\n            execute(() -> {\n                try {\n                    continuation.then(task).addOnCompleteListener(this, (subTask) -> {\n                        if (subTask.isSuccessful()) {\n                            completionSource.setResult(subTask.getResult());\n                        } else {\n                            completionSource.setException(subTask.getException());\n                        }\n                    });\n                } catch (Exception e) {\n                    completionSource.setException(e);\n                }\n            });\n        }\n    }\n\n    public Task<TContinuationResult> getTask() {\n        return completionSource.getTask();\n    }\n\n    @Override\n    public void cancel() {\n        super.cancel();\n        continuation = null;\n        completionSource = null;\n    }\n}\n"
  },
  {
    "path": "play-services-tasks/src/main/java/org/microg/gms/tasks/FailureExecutor.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.tasks;\n\nimport com.google.android.gms.tasks.OnFailureListener;\nimport com.google.android.gms.tasks.Task;\n\nimport java.util.concurrent.Executor;\n\npublic class FailureExecutor<TResult> extends UpdateExecutor<TResult> {\n    private OnFailureListener listener;\n\n    public FailureExecutor(Executor executor, OnFailureListener listener) {\n        super(executor);\n        this.listener = listener;\n    }\n\n    @Override\n    public void onTaskUpdate(Task<TResult> task) {\n        if (task.isComplete() && !task.isSuccessful() && !task.isCanceled()) {\n            execute(() -> listener.onFailure(task.getException()));\n        }\n    }\n\n    @Override\n    public void cancel() {\n        super.cancel();\n        listener = null;\n    }\n}\n"
  },
  {
    "path": "play-services-tasks/src/main/java/org/microg/gms/tasks/SuccessContinuationExecutor.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.tasks;\n\nimport com.google.android.gms.tasks.SuccessContinuation;\nimport com.google.android.gms.tasks.Task;\nimport com.google.android.gms.tasks.TaskCompletionSource;\n\nimport java.util.concurrent.Executor;\n\npublic class SuccessContinuationExecutor<TResult, TContinuationResult> extends UpdateExecutor<TResult> {\n    private SuccessContinuation<TResult, TContinuationResult> continuation;\n    private TaskCompletionSource<TContinuationResult> completionSource = new TaskCompletionSource<>();\n\n    public SuccessContinuationExecutor(Executor executor, SuccessContinuation<TResult, TContinuationResult> continuation) {\n        super(executor);\n        this.continuation = continuation;\n    }\n\n    @Override\n    public void onTaskUpdate(Task<TResult> task) {\n        if (task.isSuccessful()) {\n            execute(() -> {\n                try {\n                    continuation.then(task.getResult()).addOnCompleteListener(this, (subTask) -> {\n                        if (subTask.isSuccessful()) {\n                            completionSource.setResult(subTask.getResult());\n                        } else {\n                            completionSource.setException(subTask.getException());\n                        }\n                    });\n                } catch (Exception e) {\n                    completionSource.setException(e);\n                }\n            });\n        } else {\n            completionSource.setException(task.getException());\n        }\n    }\n\n    public Task<TContinuationResult> getTask() {\n        return completionSource.getTask();\n    }\n\n    @Override\n    public void cancel() {\n        super.cancel();\n        continuation = null;\n        completionSource = null;\n    }\n}\n"
  },
  {
    "path": "play-services-tasks/src/main/java/org/microg/gms/tasks/SuccessExecutor.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.tasks;\n\nimport com.google.android.gms.tasks.OnSuccessListener;\nimport com.google.android.gms.tasks.Task;\n\nimport java.util.concurrent.Executor;\n\npublic class SuccessExecutor<TResult> extends UpdateExecutor<TResult> {\n    private OnSuccessListener<? super TResult> listener;\n\n    public SuccessExecutor(Executor executor, OnSuccessListener<? super TResult> listener) {\n        super(executor);\n        this.listener = listener;\n    }\n\n    @Override\n    public void onTaskUpdate(Task<TResult> task) {\n        if (task.isSuccessful()) {\n            execute(() -> listener.onSuccess(task.getResult()));\n        }\n    }\n\n    @Override\n    public void cancel() {\n        super.cancel();\n        listener = null;\n    }\n}\n"
  },
  {
    "path": "play-services-tasks/src/main/java/org/microg/gms/tasks/TaskImpl.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.tasks;\n\nimport android.app.Activity;\n\nimport com.google.android.gms.tasks.Continuation;\nimport com.google.android.gms.tasks.DuplicateTaskCompletionException;\nimport com.google.android.gms.tasks.OnCanceledListener;\nimport com.google.android.gms.tasks.OnCompleteListener;\nimport com.google.android.gms.tasks.OnFailureListener;\nimport com.google.android.gms.tasks.OnSuccessListener;\nimport com.google.android.gms.tasks.RuntimeExecutionException;\nimport com.google.android.gms.tasks.SuccessContinuation;\nimport com.google.android.gms.tasks.Task;\n\nimport java.util.Queue;\nimport java.util.concurrent.CancellationException;\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.LinkedBlockingQueue;\n\nimport static com.google.android.gms.tasks.TaskExecutors.MAIN_THREAD;\n\npublic class TaskImpl<TResult> extends Task<TResult> {\n    private final Object lock = new Object();\n    private boolean completed;\n    private boolean cancelled;\n    private TResult result;\n    private Exception exception;\n    private Queue<UpdateListener<TResult>> completionQueue = new LinkedBlockingQueue<>();\n\n    @Override\n    public Task<TResult> addOnCanceledListener(OnCanceledListener listener) {\n        return addOnCanceledListener(MAIN_THREAD, listener);\n    }\n\n    @Override\n    public Task<TResult> addOnCanceledListener(Executor executor, OnCanceledListener listener) {\n        return enqueueOrInvoke(new CancelledExecutor<>(executor, listener));\n    }\n\n    @Override\n    public Task<TResult> addOnCanceledListener(Activity activity, OnCanceledListener listener) {\n        return enqueueOrInvoke(activity, new CancelledExecutor<>(MAIN_THREAD, listener));\n    }\n\n    @Override\n    public Task<TResult> addOnCompleteListener(OnCompleteListener<TResult> listener) {\n        return addOnCompleteListener(MAIN_THREAD, listener);\n    }\n\n    @Override\n    public Task<TResult> addOnCompleteListener(Executor executor, OnCompleteListener<TResult> listener) {\n        return enqueueOrInvoke(new CompletedExecutor<>(executor, listener));\n    }\n\n    @Override\n    public Task<TResult> addOnCompleteListener(Activity activity, OnCompleteListener<TResult> listener) {\n        return enqueueOrInvoke(activity, new CompletedExecutor<>(MAIN_THREAD, listener));\n    }\n\n    @Override\n    public Task<TResult> addOnFailureListener(OnFailureListener listener) {\n        return addOnFailureListener(MAIN_THREAD, listener);\n    }\n\n    @Override\n    public Task<TResult> addOnFailureListener(Executor executor, OnFailureListener listener) {\n        return enqueueOrInvoke(new FailureExecutor<>(executor, listener));\n    }\n\n    @Override\n    public Task<TResult> addOnFailureListener(Activity activity, OnFailureListener listener) {\n        return enqueueOrInvoke(activity, new FailureExecutor<>(MAIN_THREAD, listener));\n    }\n\n    @Override\n    public Task<TResult> addOnSuccessListener(OnSuccessListener<? super TResult> listener) {\n        return addOnSuccessListener(MAIN_THREAD, listener);\n    }\n\n    @Override\n    public Task<TResult> addOnSuccessListener(Executor executor, OnSuccessListener<? super TResult> listener) {\n        return enqueueOrInvoke(new SuccessExecutor<>(executor, listener));\n    }\n\n    @Override\n    public Task<TResult> addOnSuccessListener(Activity activity, OnSuccessListener<? super TResult> listener) {\n        return enqueueOrInvoke(activity, new SuccessExecutor<>(MAIN_THREAD, listener));\n    }\n\n    @Override\n    public <TContinuationResult> Task<TContinuationResult> continueWith(Continuation<TResult, TContinuationResult> continuation) {\n        return continueWith(MAIN_THREAD, continuation);\n    }\n\n    @Override\n    public <TContinuationResult> Task<TContinuationResult> continueWith(Executor executor, Continuation<TResult, TContinuationResult> continuation) {\n        ContinuationExecutor<TResult, TContinuationResult> c = new ContinuationExecutor<>(executor, continuation);\n        enqueueOrInvoke(c);\n        return c.getTask();\n    }\n\n    @Override\n    public <TContinuationResult> Task<TContinuationResult> continueWithTask(Continuation<TResult, Task<TContinuationResult>> continuation) {\n        return continueWithTask(MAIN_THREAD, continuation);\n    }\n\n    @Override\n    public <TContinuationResult> Task<TContinuationResult> continueWithTask(Executor executor, Continuation<TResult, Task<TContinuationResult>> continuation) {\n        ContinuationWithExecutor<TResult, TContinuationResult> c = new ContinuationWithExecutor<>(executor, continuation);\n        enqueueOrInvoke(c);\n        return c.getTask();\n    }\n\n    @Override\n    public Exception getException() {\n        synchronized (lock) {\n            return exception;\n        }\n    }\n\n    @Override\n    public TResult getResult() {\n        synchronized (lock) {\n            if (!completed) throw new IllegalStateException(\"Task is not yet complete\");\n            if (cancelled) throw new CancellationException(\"Task is canceled\");\n            if (exception != null) throw new RuntimeExecutionException(exception);\n            return result;\n        }\n    }\n\n    @Override\n    public <X extends Throwable> TResult getResult(Class<X> exceptionType) throws X {\n        synchronized (lock) {\n            if (!completed) throw new IllegalStateException(\"Task is not yet complete\");\n            if (cancelled) throw new CancellationException(\"Task is canceled\");\n            if (exceptionType.isInstance(exception)) throw exceptionType.cast(exception);\n            if (exception != null) throw new RuntimeExecutionException(exception);\n            return result;\n        }\n    }\n\n    @Override\n    public boolean isCanceled() {\n        synchronized (lock) {\n            return cancelled;\n        }\n    }\n\n    @Override\n    public boolean isComplete() {\n        synchronized (lock) {\n            return completed;\n        }\n    }\n\n    @Override\n    public boolean isSuccessful() {\n        synchronized (lock) {\n            return completed && !cancelled && exception == null;\n        }\n    }\n\n    private void registerActivityStop(Activity activity, UpdateListener<TResult> listener) {\n        UpdateListenerLifecycleObserver.getObserverForActivity(activity).registerActivityStopListener(listener);\n    }\n\n    private Task<TResult> enqueueOrInvoke(Activity activity, UpdateListener<TResult> listener) {\n        synchronized (lock) {\n            if (completed) {\n                listener.onTaskUpdate(this);\n            } else {\n                completionQueue.offer(listener);\n                registerActivityStop(activity, listener);\n            }\n        }\n        return this;\n    }\n\n    private Task<TResult> enqueueOrInvoke(UpdateListener<TResult> listener) {\n        synchronized (lock) {\n            if (completed) {\n                listener.onTaskUpdate(this);\n            } else {\n                completionQueue.offer(listener);\n            }\n        }\n        return this;\n    }\n\n    private void notifyQueue() {\n        UpdateListener<TResult> listener;\n        while ((listener = completionQueue.poll()) != null) {\n            listener.onTaskUpdate(this);\n        }\n    }\n\n    public void cancel() {\n        synchronized (lock) {\n            if (completed) throw DuplicateTaskCompletionException.of(this);\n            this.completed = true;\n            this.cancelled = true;\n            notifyQueue();\n        }\n    }\n\n    public void setResult(TResult result) {\n        synchronized (lock) {\n            if (completed) throw DuplicateTaskCompletionException.of(this);\n            this.completed = true;\n            this.result = result;\n            notifyQueue();\n        }\n    }\n\n    public void setException(Exception exception) {\n        synchronized (lock) {\n            if (completed) throw DuplicateTaskCompletionException.of(this);\n            this.completed = true;\n            this.exception = exception;\n            notifyQueue();\n        }\n    }\n\n    @Override\n    public <TContinuationResult> Task<TContinuationResult> onSuccessTask(SuccessContinuation<TResult, TContinuationResult> successContinuation) {\n        return onSuccessTask(MAIN_THREAD, successContinuation);\n    }\n\n    @Override\n    public <TContinuationResult> Task<TContinuationResult> onSuccessTask(Executor executor, SuccessContinuation<TResult, TContinuationResult> successContinuation) {\n        SuccessContinuationExecutor<TResult, TContinuationResult> c = new SuccessContinuationExecutor<>(executor, successContinuation);\n        enqueueOrInvoke(c);\n        return c.getTask();\n    }\n}\n"
  },
  {
    "path": "play-services-tasks/src/main/java/org/microg/gms/tasks/UpdateExecutor.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.tasks;\n\nimport java.util.concurrent.Executor;\n\npublic abstract class UpdateExecutor<TResult> implements UpdateListener<TResult>, Executor {\n    private Executor executor;\n\n    public UpdateExecutor(Executor executor) {\n        this.executor = executor;\n    }\n\n    @Override\n    public void execute(Runnable runnable) {\n        if (executor == null) return;\n        executor.execute(runnable);\n    }\n\n    @Override\n    public void cancel() {\n        executor = null;\n    }\n}\n"
  },
  {
    "path": "play-services-tasks/src/main/java/org/microg/gms/tasks/UpdateListener.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.tasks;\n\nimport com.google.android.gms.tasks.Task;\n\npublic interface UpdateListener<TResult> {\n    void onTaskUpdate(Task<TResult> task);\n\n    void cancel();\n}\n"
  },
  {
    "path": "play-services-tasks/src/main/java/org/microg/gms/tasks/UpdateListenerLifecycleObserver.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.tasks;\n\nimport android.app.Activity;\nimport android.app.Application;\nimport android.os.Bundle;\n\nimport java.lang.ref.WeakReference;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.WeakHashMap;\n\npublic class UpdateListenerLifecycleObserver {\n    private static WeakHashMap<Activity, WeakReference<UpdateListenerLifecycleObserver>> map = new WeakHashMap<>();\n    private static boolean activityLifecycleCallbacksRegistered = false;\n    private List<WeakReference<UpdateListener<?>>> list = new ArrayList<>();\n\n    public synchronized static UpdateListenerLifecycleObserver getObserverForActivity(Activity activity) {\n        WeakReference<UpdateListenerLifecycleObserver> ref = map.get(activity);\n        if (ref != null) {\n            UpdateListenerLifecycleObserver observer = ref.get();\n            if (observer != null) {\n                return observer;\n            }\n        }\n\n        if (!activityLifecycleCallbacksRegistered) {\n            activity.getApplication().registerActivityLifecycleCallbacks(new MyActivityLifecycleCallbacks());\n            activityLifecycleCallbacksRegistered = true;\n        }\n\n        UpdateListenerLifecycleObserver newInstance = new UpdateListenerLifecycleObserver();\n        map.put(activity, new WeakReference<>(newInstance));\n        return newInstance;\n    }\n\n    private UpdateListenerLifecycleObserver() {\n    }\n\n    public synchronized void registerActivityStopListener(UpdateListener<?> listener) {\n        list.add(new WeakReference<>(listener));\n    }\n\n    public synchronized void onStop() {\n        for (WeakReference<UpdateListener<?>> ref : list) {\n            UpdateListener<?> listener = ref.get();\n            listener.cancel();\n        }\n        list.clear();\n    }\n\n    private static class MyActivityLifecycleCallbacks implements Application.ActivityLifecycleCallbacks {\n        @Override\n        public void onActivityCreated(Activity activity, Bundle savedInstanceState) {\n\n        }\n\n        @Override\n        public void onActivityStarted(Activity activity) {\n\n        }\n\n        @Override\n        public void onActivityResumed(Activity activity) {\n\n        }\n\n        @Override\n        public void onActivityPaused(Activity activity) {\n\n        }\n\n        @Override\n        public void onActivityStopped(Activity activity) {\n            WeakReference<UpdateListenerLifecycleObserver> ref = map.get(activity);\n            if (ref != null) {\n                UpdateListenerLifecycleObserver observer = ref.get();\n                if (observer != null) {\n                    observer.onStop();\n                }\n            }\n        }\n\n        @Override\n        public void onActivitySaveInstanceState(Activity activity, Bundle outState) {\n\n        }\n\n        @Override\n        public void onActivityDestroyed(Activity activity) {\n\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-threadnetwork/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\nandroid {\n    namespace \"com.google.android.gms.threadnetwork\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n}\n\n// Nothing to publish yet\n//apply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG implementation of play-services-threadnetwork'\n\ndependencies {\n    // Dependencies from play-services-threadnetwork:16.2.1\n    api project(':play-services-base')\n    api project(':play-services-basement')\n    api project(':play-services-tasks')\n\n    annotationProcessor project(':safe-parcel-processor')\n}\n"
  },
  {
    "path": "play-services-threadnetwork/core/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'kotlin-android'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\ndependencies {\n    api project(':play-services-threadnetwork')\n\n    implementation project(':play-services-base-core')\n    implementation \"androidx.annotation:annotation:$annotationVersion\"\n}\n\nandroid {\n    namespace \"org.microg.gms.threadnetwork.core\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    sourceSets {\n        main {\n            java.srcDirs += 'src/main/kotlin'\n        }\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n\n    kotlinOptions {\n        jvmTarget = 1.8\n    }\n}\n\n// Nothing to publish yet\n//apply from: '../../gradle/publish-android.gradle'\n\ndescription = 'microG service implementation for play-services-threadnetwork'\n"
  },
  {
    "path": "play-services-threadnetwork/core/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2024 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <application>\n        <service\n            android:name=\"org.microg.gms.threadnetwork.ThreadNetworkService\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.threadnetwork.service.START\" />\n            </intent-filter>\n        </service>\n    </application>\n</manifest>\n"
  },
  {
    "path": "play-services-threadnetwork/core/src/main/kotlin/org/microg/gms/threadnetwork/ThreadNetworkService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.threadnetwork\n\nimport android.content.Context\nimport android.util.Log\nimport com.google.android.gms.common.ConnectionResult\nimport com.google.android.gms.common.Feature\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.common.api.Status\nimport com.google.android.gms.common.api.internal.IStatusCallback\nimport com.google.android.gms.common.internal.ConnectionInfo\nimport com.google.android.gms.common.internal.GetServiceRequest\nimport com.google.android.gms.common.internal.IGmsCallbacks\nimport com.google.android.gms.threadnetwork.ThreadBorderAgent\nimport com.google.android.gms.threadnetwork.ThreadNetworkCredentials\nimport com.google.android.gms.threadnetwork.ThreadNetworkStatusCodes\nimport com.google.android.gms.threadnetwork.internal.*\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.GmsService\n\nprivate const val TAG = \"ThreadNetworkService\"\n\nclass ThreadNetworkService : BaseService(TAG, GmsService.THREADNETWORK) {\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        val connectionInfo = ConnectionInfo()\n        connectionInfo.features = arrayOf(Feature(\"threadnetwork\", 8))\n        callback.onPostInitCompleteWithConnectionInfo(\n            ConnectionResult.SUCCESS, ThreadNetworkServiceImpl(this, request.packageName).asBinder(), connectionInfo\n        )\n    }\n}\n\nclass ThreadNetworkServiceImpl(private val context: Context, private val packageName: String) : IThreadNetworkService.Stub() {\n    private val THREAD_NETWORK_NOT_FOUND = Status(ThreadNetworkStatusCodes.THREAD_NETWORK_NOT_FOUND, \"THREAD_NETWORK_NOT_FOUND\")\n\n    override fun addCredentials(callback: IStatusCallback?, borderAgent: ThreadBorderAgent?, credentials: ThreadNetworkCredentials?) {\n        if (borderAgent == null || credentials == null) {\n            runCatching { callback?.onResult(Status(CommonStatusCodes.DEVELOPER_ERROR, \"Illegal arguments\")) }\n            return\n        }\n        Log.d(TAG, \"Not yet implemented: addCredentials\")\n        runCatching { callback?.onResult(Status.SUCCESS) }\n    }\n\n    override fun removeCredentials(callback: IStatusCallback?, borderAgent: ThreadBorderAgent?) {\n        if (borderAgent == null) {\n            runCatching { callback?.onResult(Status(CommonStatusCodes.DEVELOPER_ERROR, \"Illegal arguments\")) }\n            return\n        }\n        Log.d(TAG, \"Not yet implemented: removeCredentials\")\n        runCatching { callback?.onResult(Status.SUCCESS) }\n    }\n\n    override fun getAllCredentials(callbacks: IThreadNetworkServiceCallbacks?) {\n        Log.d(TAG, \"Not yet implemented: getAllCredentials\")\n        runCatching { callbacks?.onCredentials(Status.SUCCESS, emptyList()) }\n    }\n\n    override fun getCredentialsByExtendedPanId(callback: IGetCredentialsByExtendedPanIdCallback?, extendedPanId: ByteArray?) {\n        if (extendedPanId == null) {\n            runCatching { callback?.onCredentials(Status(CommonStatusCodes.DEVELOPER_ERROR, \"Illegal arguments\"), null) }\n            return\n        }\n        Log.d(TAG, \"Not yet implemented: getCredentialsByExtendedPanId\")\n        runCatching { callback?.onCredentials(THREAD_NETWORK_NOT_FOUND, null) }\n    }\n\n    override fun getCredentialsByBorderAgent(callbacks: IThreadNetworkServiceCallbacks?, borderAgent: ThreadBorderAgent?) {\n        if (borderAgent == null) {\n            runCatching { callbacks?.onCredentials(Status(CommonStatusCodes.DEVELOPER_ERROR, \"Illegal arguments\"), emptyList()) }\n            return\n        }\n        Log.d(TAG, \"Not yet implemented: getCredentialsByBorderAgent: $borderAgent\")\n        runCatching { callbacks?.onCredentials(Status.SUCCESS, emptyList()) }\n    }\n\n    override fun getPreferredCredentials(callback: IGetPreferredCredentialsCallback?) {\n        Log.d(TAG, \"Not yet implemented: getPreferredCredentials\")\n        runCatching { callback?.onPreferredCredentials(THREAD_NETWORK_NOT_FOUND, null) }\n    }\n\n    override fun isPreferredCredentials(callback: IIsPreferredCredentialsCallback?, credentials: ThreadNetworkCredentials?) {\n        if (credentials == null) {\n            runCatching { callback?.onIsPreferredCredentials(Status(CommonStatusCodes.DEVELOPER_ERROR, \"Illegal arguments\"), false) }\n            return\n        }\n        Log.d(TAG, \"Not yet implemented: isPreferredCredentials: $credentials\")\n        runCatching { callback?.onIsPreferredCredentials(THREAD_NETWORK_NOT_FOUND, false) }\n    }\n\n}"
  },
  {
    "path": "play-services-threadnetwork/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2024 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest />\n"
  },
  {
    "path": "play-services-threadnetwork/src/main/aidl/com/google/android/gms/threadnetwork/ThreadBorderAgent.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.threadnetwork;\n\nparcelable ThreadBorderAgent;"
  },
  {
    "path": "play-services-threadnetwork/src/main/aidl/com/google/android/gms/threadnetwork/ThreadNetworkCredentials.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.threadnetwork;\n\nparcelable ThreadNetworkCredentials;"
  },
  {
    "path": "play-services-threadnetwork/src/main/aidl/com/google/android/gms/threadnetwork/internal/IGetCredentialsByExtendedPanIdCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.threadnetwork.internal;\n\nimport android.content.IntentSender;\nimport com.google.android.gms.common.api.Status;\n\ninterface IGetCredentialsByExtendedPanIdCallback {\n    void onCredentials(in Status status, in @nullable IntentSender intentSender) = 0;\n}"
  },
  {
    "path": "play-services-threadnetwork/src/main/aidl/com/google/android/gms/threadnetwork/internal/IGetPreferredCredentialsCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.threadnetwork.internal;\n\nimport android.content.IntentSender;\nimport com.google.android.gms.common.api.Status;\n\ninterface IGetPreferredCredentialsCallback {\n    void onPreferredCredentials(in Status status, in @nullable IntentSender intentSender) = 0;\n}"
  },
  {
    "path": "play-services-threadnetwork/src/main/aidl/com/google/android/gms/threadnetwork/internal/IIsPreferredCredentialsCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.threadnetwork.internal;\n\nimport com.google.android.gms.common.api.Status;\n\ninterface IIsPreferredCredentialsCallback {\n    void onIsPreferredCredentials(in Status status, boolean isPreferred) = 0;\n}"
  },
  {
    "path": "play-services-threadnetwork/src/main/aidl/com/google/android/gms/threadnetwork/internal/IThreadNetworkService.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.threadnetwork.internal;\n\nimport com.google.android.gms.common.api.internal.IStatusCallback;\n\nimport com.google.android.gms.threadnetwork.ThreadBorderAgent;\nimport com.google.android.gms.threadnetwork.ThreadNetworkCredentials;\n\nimport com.google.android.gms.threadnetwork.internal.IGetCredentialsByExtendedPanIdCallback;\nimport com.google.android.gms.threadnetwork.internal.IGetPreferredCredentialsCallback;\nimport com.google.android.gms.threadnetwork.internal.IIsPreferredCredentialsCallback;\nimport com.google.android.gms.threadnetwork.internal.IThreadNetworkServiceCallbacks;\n\ninterface IThreadNetworkService {\n    void addCredentials(IStatusCallback callback, in ThreadBorderAgent borderAgent, in ThreadNetworkCredentials credentials) = 0;\n    void removeCredentials(IStatusCallback callback, in ThreadBorderAgent borderAgent) = 1;\n    void getAllCredentials(IThreadNetworkServiceCallbacks callbacks) = 3;\n    void getCredentialsByExtendedPanId(IGetCredentialsByExtendedPanIdCallback callback, in byte[] extendedPanId) = 4;\n    void getCredentialsByBorderAgent(IThreadNetworkServiceCallbacks callbacks, in ThreadBorderAgent borderAgent) = 5;\n    void getPreferredCredentials(IGetPreferredCredentialsCallback callback) = 7;\n    void isPreferredCredentials(IIsPreferredCredentialsCallback callback, in ThreadNetworkCredentials credentials) = 8;\n}"
  },
  {
    "path": "play-services-threadnetwork/src/main/aidl/com/google/android/gms/threadnetwork/internal/IThreadNetworkServiceCallbacks.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.threadnetwork.internal;\n\nimport com.google.android.gms.common.api.Status;\n\nimport com.google.android.gms.threadnetwork.ThreadNetworkCredentials;\n\ninterface IThreadNetworkServiceCallbacks {\n    void onCredentials(in Status status, in List<ThreadNetworkCredentials> credentials) = 0;\n}"
  },
  {
    "path": "play-services-threadnetwork/src/main/java/com/google/android/gms/threadnetwork/IsPreferredCredentialsResult.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.threadnetwork;\n\nimport androidx.annotation.IntDef;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Marks the result of {@link ThreadNetworkClient#isPreferredCredentials(ThreadNetworkCredentials)}.\n */\n@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})\n@Retention(RetentionPolicy.SOURCE)\n@IntDef({IsPreferredCredentialsResult.PREFERRED_CREDENTIALS_NOT_FOUND, IsPreferredCredentialsResult.PREFERRED_CREDENTIALS_NOT_MATCHED, IsPreferredCredentialsResult.PREFERRED_CREDENTIALS_MATCHED})\npublic @interface IsPreferredCredentialsResult {\n    /**\n     * The preferred Thread network credentials don't exist.\n     */\n    int PREFERRED_CREDENTIALS_NOT_FOUND = -1;\n    /**\n     * The preferred Thread network credentials don't match given credentials.\n     */\n    int PREFERRED_CREDENTIALS_NOT_MATCHED = 0;\n    /**\n     * The preferred Thread network credentials match given credentials.\n     */\n    int PREFERRED_CREDENTIALS_MATCHED = 1;\n}\n"
  },
  {
    "path": "play-services-threadnetwork/src/main/java/com/google/android/gms/threadnetwork/ThreadBorderAgent.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.threadnetwork;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n/**\n * Data interface for Thread Border Agent.\n */\n@SafeParcelable.Class\npublic class ThreadBorderAgent extends AbstractSafeParcelable {\n    @Field(value = 2, getterName = \"getId\")\n    private final byte[] id;\n\n    @Constructor\n    public ThreadBorderAgent(@Param(2) byte[] id) {\n        this.id = id;\n    }\n\n    /**\n     * Returns the id which uniquely identifies a Thread Border Agent device.\n     */\n    public byte[] getId() {\n        return id;\n    }\n\n    /**\n     * Creates a new {@link ThreadBorderAgent.Builder} for constructing a {@link ThreadBorderAgent}.\n     *\n     * @param id the id which uniquely identifies a Border Agent. The length must be 16 bytes.\n     * @throws IllegalArgumentException if the id is not of length 16 bytes.\n     */\n    public static Builder newBuilder(byte[] id) {\n        if (id.length != 16) throw new IllegalArgumentException(\"the id is not of length 16 bytes\");\n        return new Builder(id);\n    }\n\n    /**\n     * Builder for constructing {@link ThreadBorderAgent} instances.\n     */\n    public static class Builder {\n        private byte[] id;\n\n        private Builder(byte[] id) {\n            this.id = id;\n        }\n\n        /**\n         * Constructs a {@link ThreadBorderAgent} as configured by this builder.\n         */\n        public ThreadBorderAgent build() {\n            return new ThreadBorderAgent(id);\n        }\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    private static String byteArrayToHex(byte[] a) {\n        StringBuilder sb = new StringBuilder(a.length * 2);\n        for (byte b : a) sb.append(String.format(\"%02x\", b));\n        return sb.toString();\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return \"ThreadBorderAgent{\" + byteArrayToHex(id) + \"}\";\n    }\n\n    public static final SafeParcelableCreatorAndWriter<ThreadBorderAgent> CREATOR = findCreator(ThreadBorderAgent.class);\n}\n"
  },
  {
    "path": "play-services-threadnetwork/src/main/java/com/google/android/gms/threadnetwork/ThreadNetworkClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.threadnetwork;\n\npublic interface ThreadNetworkClient {\n}\n"
  },
  {
    "path": "play-services-threadnetwork/src/main/java/com/google/android/gms/threadnetwork/ThreadNetworkCredentials.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.threadnetwork;\n\nimport android.os.Parcel;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n/**\n * Data interface for managing Thread Network Credentials.\n */\n@SafeParcelable.Class\npublic class ThreadNetworkCredentials extends AbstractSafeParcelable {\n    /**\n     * The minimum 2.4GHz channel.\n     */\n    public static final int CHANNEL_MIN_2P4GHZ = 11;\n    /**\n     * The maximum 2.4GHz channel.\n     */\n    public static final int CHANNEL_MAX_2P4GHZ = 26;\n    /**\n     * The 2.4 GHz channel page.\n     */\n    public static final int CHANNEL_PAGE_2P4GHZ = 0;\n\n    /**\n     * The length of Extended PAN ID that can be set by {@link ThreadNetworkCredentials.Builder#setExtendedPanId(byte[])}.\n     */\n    public static final int LENGTH_EXTENDED_PANID = 8;\n    /**\n     * The maximum length of NetworkName that can be set by {@link ThreadNetworkCredentials.Builder#setNetworkName(String)}.\n     */\n    public static final int LENGTH_MAX_NETWORK_NAME = 16;\n    /**\n     * The maximum length of Operational Dataset that can be set by {@link #fromActiveOperationalDataset(byte[])}.\n     */\n    public static final int LENGTH_MAX_OPERATIONAL_DATASET = 256;\n    /**\n     * The maximum length of Security Policy Flags that can be set by {@link ThreadNetworkCredentials.SecurityPolicy#SecurityPolicy(int, byte[])}.\n     */\n    public static final int LENGTH_MAX_SECURITY_POLICY_FLAGS = 2;\n    /**\n     * The length of Mesh-Local Prefix that can be set by {@link ThreadNetworkCredentials.Builder#setMeshLocalPrefix(byte[])}.\n     */\n    public static final int LENGTH_MESH_LOCAL_PREFIX = 8;\n    /**\n     * The minimum length of Network Name that can be set by {@link ThreadNetworkCredentials.Builder#setNetworkName(String)}.\n     */\n    public static final int LENGTH_MIN_NETWORK_NAME = 1;\n    /**\n     * The minimum length of Security Policy Flags that can be set by {@link ThreadNetworkCredentials.SecurityPolicy#SecurityPolicy(int, byte[])}.\n     */\n    public static final int LENGTH_MIN_SECURITY_POLICY_FLAGS = 1;\n    /**\n     * The length of Network Key that can be set by {@link ThreadNetworkCredentials.Builder#setNetworkKey(byte[])}.\n     */\n    public static final int LENGTH_NETWORK_KEY = 16;\n    /**\n     * The length of PSKc that can be set by {@link ThreadNetworkCredentials.Builder#setPskc(byte[])}.\n     */\n    public static final int LENGTH_PSKC = 16;\n    /**\n     * The fisrt byte of Mesh-Local Prefix that can be set by {@link ThreadNetworkCredentials.Builder#setMeshLocalPrefix(byte[])}.\n     */\n    public static final byte MESH_LOCAL_PREFIX_FIRST_BYTE = -3;\n\n    /**\n     * The default channel mask which enables all 2.4GHz channels.\n     */\n    public static final ThreadNetworkCredentials.ChannelMaskEntry DEFAULT_CHANNEL_MASK = new ChannelMaskEntry(0, new byte[]{0, 31, -1, -32});\n    /**\n     * The default Thread 1.2 Security Policy.\n     */\n    public static final ThreadNetworkCredentials.SecurityPolicy DEFAULT_SECURITY_POLICY = new SecurityPolicy(672, new byte[]{-1, -8});\n\n    @Field(value = 1, getterName = \"getActiveOperationalDataset\")\n    private final byte[] activeOperationalDataset;\n    @Field(value = 2, getterName = \"getCreatedAtMillis\")\n    private final long createdAtMillis;\n    @Field(value = 3, getterName = \"getUpdatedAtMillis\")\n    private final long updatedAtMillis;\n\n    @Constructor\n    public ThreadNetworkCredentials(@Param(1) byte[] activeOperationalDataset, @Param(2) long createdAtMillis, @Param(3) long updatedAtMillis) {\n        this.activeOperationalDataset = activeOperationalDataset;\n        this.createdAtMillis = createdAtMillis;\n        this.updatedAtMillis = updatedAtMillis;\n    }\n\n    /**\n     * Returns the Thread active operational dataset as encoded Thread TLV list.\n     */\n    public byte[] getActiveOperationalDataset() {\n        return activeOperationalDataset;\n    }\n\n    /**\n     * Returns the Unix epoch in Milliseconds the {@link ThreadNetworkCredentials} instance is created at. Note that this is the\n     * time when the Thread network credentials is first added to the Thread Network service via\n     * {@link ThreadNetworkClient#addCredentials(ThreadBorderAgent, ThreadNetworkCredentials)}. Zero will be returned\n     * if this instance is not returned by ThreadNetworkClient methods (e.g. created with\n     * {@link #fromActiveOperationalDataset(byte[])}).\n     */\n    public long getCreatedAtMillis() {\n        return createdAtMillis;\n    }\n\n    /**\n     * Returns the Unix epoch in Milliseconds the {@link ThreadNetworkCredentials} instance is updated at. Note that this is the\n     * time when the Thread network credentials was last added/updated to the Thread Network service via\n     * {@link ThreadNetworkClient#addCredentials(ThreadBorderAgent, ThreadNetworkCredentials). Zero will be returned\n     * if this instance is not returned by ThreadNetworkClient methods (e.g. created with\n     * {@link #fromActiveOperationalDataset(byte[])}).\n     */\n    public long getUpdatedAtMillis() {\n        return updatedAtMillis;\n    }\n\n    /**\n     * The Channel Mask Entry of Thread Operational Dataset.\n     */\n    public static class ChannelMaskEntry {\n        private final int page;\n        private final byte[] mask;\n\n        /**\n         * Creates a new {@link ChannelMaskEntry} object.\n         *\n         * @throws IllegalArgumentException if page exceeds range [0, 255].\n         */\n        public ChannelMaskEntry(int page, byte[] mask) {\n            if (page < 0 || page > 255) throw new IllegalArgumentException(\"page exceeds range [0, 255].\");\n            this.page = page;\n            this.mask = mask;\n        }\n\n        /**\n         * Returns the Channel Mask.\n         */\n        public byte[] getMask() {\n            return mask;\n        }\n\n        /**\n         * Returns the Channel Page.\n         */\n        public int getPage() {\n            return page;\n        }\n    }\n\n    /**\n     * The class represents Thread Security Policy.\n     */\n    public static class SecurityPolicy {\n        private final int rotationTimeHours;\n        private final byte[] flags;\n\n        /**\n         * Creates a new {@link SecurityPolicy} object.\n         *\n         * @param rotationTimeHours the value for Thread key rotation in hours. Must be in range of 0x1-0xffff.\n         * @param flags             security policy flags with length of either 1 byte for Thread 1.1 or 2 bytes for Thread 1.2 or higher.\n         * @throws IllegalArgumentException if {@code rotationTimeHours} is not in range of 0x1-0xffff or\n         *                                  length of flags is smaller than {@link ThreadNetworkCredentials#LENGTH_MIN_SECURITY_POLICY_FLAGS}.\n         */\n        public SecurityPolicy(int rotationTimeHours, byte[] flags) {\n            if (rotationTimeHours < 1 || rotationTimeHours > 0xffff) throw new IllegalArgumentException(\"rotationTimeHours is not in range of 0x1-0xffff\");\n            if (flags.length < LENGTH_MIN_SECURITY_POLICY_FLAGS) throw new IllegalArgumentException(\"length of flags is smaller than LENGTH_MIN_SECURITY_POLICY_FLAGS\");\n            this.rotationTimeHours = rotationTimeHours;\n            this.flags = flags;\n        }\n\n        /**\n         * Returns 1 byte flags for Thread 1.1 or 2 bytes flags for Thread 1.2.\n         */\n        public byte[] getFlags() {\n            return flags;\n        }\n\n        /**\n         * Returns the Security Policy Rotation Time in hours.\n         */\n        public int getRotationTimeHours() {\n            return rotationTimeHours;\n        }\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<ThreadNetworkCredentials> CREATOR = findCreator(ThreadNetworkCredentials.class);\n}\n"
  },
  {
    "path": "play-services-threadnetwork/src/main/java/com/google/android/gms/threadnetwork/ThreadNetworkStatusCodes.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.threadnetwork;\n\nimport com.google.android.gms.common.api.CommonStatusCodes;\nimport com.google.android.gms.tasks.Task;\n\n/**\n * Status codes for {@link ThreadNetworkClient} methods result {@link Task} failures.\n * <p>\n * The codes are supplementary to common status codes in {@link CommonStatusCodes}.\n */\npublic class ThreadNetworkStatusCodes extends CommonStatusCodes {\n    /**\n     * Operation is not permitted.\n     */\n    public static final int PERMISSION_DENIED = 44000;\n    /**\n     * Local Wi-Fi or Ethernet network is not connected.\n     */\n    public static final int LOCAL_NETWORK_NOT_CONNECTED = 44001;\n    /**\n     * Operation is not supported on current platform.\n     */\n    public static final int PLATFORM_NOT_SUPPORTED = 44002;\n    /**\n     * Failed to add Thread network credentials because the storage quota is exceeded.\n     */\n    public static final int MAX_STORAGE_SIZE_EXCEEDED = 44003;\n    public static final int THREAD_NETWORK_NOT_FOUND = 44004;\n}\n"
  },
  {
    "path": "play-services-vision/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\nandroid {\n    namespace \"com.google.android.gms.vision\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n}\n\napply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG implementation of play-services-vision'\n\ndependencies {\n    // Dependencies from play-services-vision:20.1.3\n    api project(':play-services-base')\n    api project(':play-services-basement')\n    api project(':play-services-vision-common')\n\n    annotationProcessor project(\":safe-parcel-processor\")\n}\n"
  },
  {
    "path": "play-services-vision/core/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'kotlin-android'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\ndependencies {\n    api project(':play-services-mlkit-barcode-scanning')\n    api project(':play-services-mlkit-face-detection')\n    api project(':play-services-vision')\n\n    implementation project(':play-services-base-core')\n    implementation \"androidx.annotation:annotation:$annotationVersion\"\n    implementation \"com.google.zxing:core:3.5.2\"\n\n    implementation 'org.opencv:opencv:4.11.0'\n\n    implementation \"androidx.camera:camera-core:1.3.0\"\n    implementation \"androidx.camera:camera-camera2:1.3.0\"\n    implementation \"androidx.camera:camera-lifecycle:1.3.0\"\n    implementation \"androidx.camera:camera-view:1.3.0\"\n}\n\nandroid {\n    namespace \"org.microg.gms.vision.core\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    sourceSets {\n        main {\n            java.srcDirs += 'src/main/kotlin'\n        }\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n\n    kotlinOptions {\n        jvmTarget = 1.8\n    }\n}\n\napply from: '../../gradle/publish-android.gradle'\n\ndescription = 'microG service implementation for play-services-vision'\n"
  },
  {
    "path": "play-services-vision/core/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\" xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <uses-sdk tools:overrideLibrary=\"org.opencv\"/>\n    <uses-permission android:name=\"android.permission.CAMERA\"/>\n    <uses-feature\n            android:name=\"android.hardware.camera\"\n            android:required=\"false\"/>\n\n    <application>\n    </application>\n</manifest>\n"
  },
  {
    "path": "play-services-vision/core/src/main/java/com/google/android/gms/dynamite/descriptors/com/google/android/gms/vision/barcode/ModuleDescriptor.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.dynamite.descriptors.com.google.android.gms.vision.barcode;\n\npublic class ModuleDescriptor {\n    public static final String MODULE_ID = \"com.google.android.gms.vision.barcode\";\n    public static final int MODULE_VERSION = 1;\n}\n"
  },
  {
    "path": "play-services-vision/core/src/main/java/com/google/android/gms/dynamite/descriptors/com/google/android/gms/vision/dynamite/ModuleDescriptor.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.dynamite.descriptors.com.google.android.gms.vision.dynamite;\n\npublic class ModuleDescriptor {\n    public static final String MODULE_ID = \"com.google.android.gms.vision.dynamite\";\n    public static final int MODULE_VERSION = 1;\n}\n"
  },
  {
    "path": "play-services-vision/core/src/main/java/com/google/android/gms/dynamite/descriptors/com/google/android/gms/vision/dynamite/barcode/ModuleDescriptor.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.dynamite.descriptors.com.google.android.gms.vision.dynamite.barcode;\n\npublic class ModuleDescriptor {\n    public static final String MODULE_ID = \"com.google.android.gms.vision.dynamite.barcode\";\n    public static final int MODULE_VERSION = 1;\n}\n"
  },
  {
    "path": "play-services-vision/core/src/main/java/com/google/android/gms/dynamite/descriptors/com/google/android/gms/vision/dynamite/face/ModuleDescriptor.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.dynamite.descriptors.com.google.android.gms.vision.dynamite.face;\n\npublic class ModuleDescriptor {\n    public static final String MODULE_ID = \"com.google.android.gms.vision.dynamite.face\";\n    public static final int MODULE_VERSION = 1;\n}\n"
  },
  {
    "path": "play-services-vision/core/src/main/java/com/google/android/gms/dynamite/descriptors/com/google/android/gms/vision/face/ModuleDescriptor.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.dynamite.descriptors.com.google.android.gms.vision.face;\n\npublic class ModuleDescriptor {\n    public static final String MODULE_ID = \"com.google.android.gms.vision.face\";\n    public static final int MODULE_VERSION = 1;\n}\n"
  },
  {
    "path": "play-services-vision/core/src/main/java/com/google/android/gms/dynamite/descriptors/com/google/mlkit/dynamite/face/ModuleDescriptor.java",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.dynamite.descriptors.com.google.mlkit.dynamite.face;\n\npublic class ModuleDescriptor {\n    public static final String MODULE_ID = \"com.google.mlkit.dynamite.face\";\n    public static final int MODULE_VERSION = 1;\n}\n"
  },
  {
    "path": "play-services-vision/core/src/main/kotlin/com/google/android/gms/vision/barcode/ChimeraNativeBarcodeDetectorCreator.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.vision.barcode\n\nimport android.content.Context\nimport androidx.annotation.Keep\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.vision.barcode.internal.client.BarcodeDetectorOptions\nimport com.google.android.gms.vision.barcode.internal.client.INativeBarcodeDetector\nimport com.google.android.gms.vision.barcode.internal.client.INativeBarcodeDetectorCreator\nimport com.google.android.gms.dynamic.unwrap\nimport org.microg.gms.vision.barcode.BarcodeDetector\n\n@Keep\nclass ChimeraNativeBarcodeDetectorCreator : INativeBarcodeDetectorCreator.Stub() {\n    override fun create(context: IObjectWrapper, options: BarcodeDetectorOptions): INativeBarcodeDetector {\n        return BarcodeDetector(context.unwrap<Context>()!!, options)\n    }\n}\n"
  },
  {
    "path": "play-services-vision/core/src/main/kotlin/com/google/android/gms/vision/barcode/mlkit/BarcodeScannerCreator.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.vision.barcode.mlkit\n\nimport android.content.Context\nimport androidx.annotation.Keep\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.unwrap\nimport com.google.mlkit.vision.barcode.aidls.IBarcodeScannerCreator\nimport com.google.mlkit.vision.barcode.aidls.IBarcodeScanner\nimport com.google.mlkit.vision.barcode.internal.BarcodeScannerOptions\nimport org.microg.gms.vision.barcode.BarcodeScanner\n\n@Keep\nclass BarcodeScannerCreator : IBarcodeScannerCreator.Stub() {\n    override fun create(context: IObjectWrapper, options: BarcodeScannerOptions): IBarcodeScanner {\n        return BarcodeScanner(context.unwrap<Context>()!!, options)\n    }\n}"
  },
  {
    "path": "play-services-vision/core/src/main/kotlin/com/google/android/gms/vision/client/DynamiteNativeBarcodeDetectorCreator.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.vision.client\n\nimport android.content.Context\nimport androidx.annotation.Keep\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.unwrap\nimport com.google.android.gms.vision.barcode.internal.client.BarcodeDetectorOptions\nimport com.google.android.gms.vision.barcode.internal.client.INativeBarcodeDetector\nimport com.google.android.gms.vision.barcode.internal.client.INativeBarcodeDetectorCreator\nimport org.microg.gms.vision.barcode.BarcodeDetector\n\n@Keep\nclass DynamiteNativeBarcodeDetectorCreator : INativeBarcodeDetectorCreator.Stub() {\n    override fun create(context: IObjectWrapper, options: BarcodeDetectorOptions): INativeBarcodeDetector {\n        return BarcodeDetector(context.unwrap<Context>()!!, options)\n    }\n}\n"
  },
  {
    "path": "play-services-vision/core/src/main/kotlin/com/google/android/gms/vision/client/DynamiteNativeFaceDetectorCreator.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.vision.client\n\nimport android.content.Context\nimport android.os.SystemClock\nimport android.util.Log\nimport androidx.annotation.Keep\nimport com.google.android.gms.common.GooglePlayServicesUtil\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.unwrap\nimport com.google.android.gms.vision.face.internal.client.DetectionOptions\nimport com.google.android.gms.vision.face.internal.client.INativeFaceDetector\nimport com.google.android.gms.vision.face.internal.client.INativeFaceDetectorCreator\nimport org.microg.gms.vision.face.TAG\nimport org.microg.gms.vision.face.FaceDetector\nimport org.opencv.android.OpenCVLoader\n\n@Keep\nclass DynamiteNativeFaceDetectorCreator : INativeFaceDetectorCreator.Stub() {\n\n    override fun newFaceDetector(context: IObjectWrapper?, faceDetectionOptions: DetectionOptions?): INativeFaceDetector? {\n        Log.d(TAG, \"DynamiteNativeFaceDetectorCreator newFaceDetector faceDetectionOptions:${faceDetectionOptions.toString()}\")\n        try {\n            val elapsedRealtime = SystemClock.elapsedRealtime()\n            val context = context.unwrap<Context>() ?: throw RuntimeException(\"Context is null\")\n            val remoteContext = GooglePlayServicesUtil.getRemoteContext(context) ?: throw RuntimeException(\"remoteContext is null\")\n            Log.d(TAG, \"newFaceDetector: context: ${context.packageName} remoteContext: ${remoteContext.packageName}\")\n            if (!OpenCVLoader.initLocal()) {\n                throw RuntimeException(\"Unable to load OpenCV\")\n            }\n            Log.d(TAG, \"DynamiteNativeFaceDetectorCreator newFaceDetector: load <openCV> library in ${SystemClock.elapsedRealtime() - elapsedRealtime}ms\")\n            return FaceDetector(remoteContext, faceDetectionOptions)\n        } catch (e: Throwable) {\n            Log.w(TAG, \"DynamiteNativeFaceDetectorCreator newFaceDetector load failed \", e)\n            return null\n        }\n    }\n}"
  },
  {
    "path": "play-services-vision/core/src/main/kotlin/com/google/android/gms/vision/face/ChimeraNativeFaceDetectorCreator.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.vision.face\n\nimport android.content.Context\nimport android.os.SystemClock\nimport android.util.Log\nimport androidx.annotation.Keep\nimport com.google.android.gms.common.GooglePlayServicesUtil\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.unwrap\nimport com.google.android.gms.vision.face.internal.client.DetectionOptions\nimport com.google.android.gms.vision.face.internal.client.INativeFaceDetector\nimport com.google.android.gms.vision.face.internal.client.INativeFaceDetectorCreator\nimport org.microg.gms.vision.face.FaceDetector\nimport org.microg.gms.vision.face.TAG\nimport org.opencv.android.OpenCVLoader\n\n@Keep\nclass ChimeraNativeFaceDetectorCreator : INativeFaceDetectorCreator.Stub() {\n    override fun newFaceDetector(context: IObjectWrapper?, faceDetectionOptions: DetectionOptions?): INativeFaceDetector? {\n        Log.d(TAG, \"ChimeraNativeFaceDetectorCreator newFaceDetector faceDetectionOptions:${faceDetectionOptions.toString()}\")\n        try {\n            val elapsedRealtime = SystemClock.elapsedRealtime()\n            val context = context.unwrap<Context>() ?: throw RuntimeException(\"Context is null\")\n            val remoteContext = GooglePlayServicesUtil.getRemoteContext(context) ?: throw RuntimeException(\"remoteContext is null\")\n            Log.d(TAG, \"newFaceDetector: context: ${context.packageName} remoteContext: ${remoteContext.packageName}\")\n            if (!OpenCVLoader.initLocal()) {\n                throw RuntimeException(\"Unable to load OpenCV\")\n            }\n            Log.d(TAG, \"ChimeraNativeFaceDetectorCreator newFaceDetector: load <openCV> library in ${SystemClock.elapsedRealtime() - elapsedRealtime}ms\")\n            return FaceDetector(remoteContext, faceDetectionOptions)\n        } catch (e: Throwable) {\n            Log.w(TAG, \"ChimeraNativeFaceDetectorCreator newFaceDetector load failed \", e)\n            return null\n        }\n    }\n}"
  },
  {
    "path": "play-services-vision/core/src/main/kotlin/com/google/android/gms/vision/face/mlkit/FaceDetectorCreator.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.vision.face.mlkit\n\nimport android.content.Context\nimport android.os.SystemClock\nimport android.util.Log\nimport androidx.annotation.Keep\nimport com.google.android.gms.common.GooglePlayServicesUtil\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.unwrap\nimport com.google.mlkit.vision.face.FaceDetectionOptions\nimport com.google.mlkit.vision.face.aidls.IFaceDetector\nimport com.google.mlkit.vision.face.aidls.IFaceDetectorCreator\nimport org.microg.gms.vision.face.TAG\nimport org.microg.gms.vision.face.mlkit.FaceDetector\nimport org.opencv.android.OpenCVLoader\n\n@Keep\nclass FaceDetectorCreator : IFaceDetectorCreator.Stub() {\n\n    override fun newFaceDetector(context: IObjectWrapper?, faceDetectionOptions: FaceDetectionOptions?): IFaceDetector? {\n        Log.d(TAG, \"MLKit newFaceDetector options:${faceDetectionOptions}\")\n        try {\n            val elapsedRealtime = SystemClock.elapsedRealtime()\n            val context = context.unwrap<Context>() ?: throw RuntimeException(\"Context is null\")\n            val remoteContext = GooglePlayServicesUtil.getRemoteContext(context) ?: throw RuntimeException(\"remoteContext is null\")\n            Log.d(TAG, \"newFaceDetector: context: ${context.packageName} remoteContext: ${remoteContext.packageName}\")\n            if (!OpenCVLoader.initLocal()) {\n                throw RuntimeException(\"Unable to load OpenCV\")\n            }\n            Log.d(TAG, \"FaceDetectorCreator newFaceDetector: load <openCV> library in ${SystemClock.elapsedRealtime() - elapsedRealtime}ms\")\n            return FaceDetector(remoteContext, faceDetectionOptions)\n        } catch (e: Throwable) {\n            Log.w(TAG, \"FaceDetectorCreator newFaceDetector load failed \", e)\n            return null\n        }\n    }\n}"
  },
  {
    "path": "play-services-vision/core/src/main/kotlin/com/google/mlkit/vision/face/bundled/internal/ThickFaceDetectorCreator.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.mlkit.vision.face.bundled.internal\n\nimport android.content.Context\nimport android.os.SystemClock\nimport android.util.Log\nimport androidx.annotation.Keep\nimport com.google.android.gms.common.GooglePlayServicesUtil\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.unwrap\nimport com.google.mlkit.vision.face.FaceDetectionOptions\nimport com.google.mlkit.vision.face.aidls.IFaceDetector\nimport com.google.mlkit.vision.face.aidls.IFaceDetectorCreator\nimport org.microg.gms.vision.face.TAG\nimport org.microg.gms.vision.face.mlkit.FaceDetector\nimport org.opencv.android.OpenCVLoader\n\n@Keep\nclass ThickFaceDetectorCreator : IFaceDetectorCreator.Stub() {\n\n    override fun newFaceDetector(context: IObjectWrapper?, faceDetectionOptions: FaceDetectionOptions?): IFaceDetector? {\n        Log.d(TAG, \"MLKit newFaceDetector options:${faceDetectionOptions}\")\n        try {\n            val elapsedRealtime = SystemClock.elapsedRealtime()\n            val context = context.unwrap<Context>() ?: throw RuntimeException(\"Context is null\")\n            val remoteContext = GooglePlayServicesUtil.getRemoteContext(context) ?: throw RuntimeException(\"remoteContext is null\")\n            Log.d(TAG, \"ThickFaceDetectorCreator newFaceDetector: context: ${context.packageName} remoteContext: ${remoteContext.packageName}\")\n            if (!OpenCVLoader.initLocal()) {\n                throw RuntimeException(\"Unable to load OpenCV\")\n            }\n            Log.d(TAG, \"ThickFaceDetectorCreator newFaceDetector: load <openCV> library in ${SystemClock.elapsedRealtime() - elapsedRealtime}ms\")\n            return FaceDetector(remoteContext, faceDetectionOptions)\n        } catch (e: Throwable) {\n            Log.w(TAG, \"ThickFaceDetectorCreator newFaceDetector load failed \", e)\n            return null\n        }\n    }\n}"
  },
  {
    "path": "play-services-vision/core/src/main/kotlin/org/microg/gms/vision/barcode/BarcodeDecodeHelper.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.vision.barcode\n\nimport android.graphics.Bitmap\nimport android.graphics.ImageFormat\nimport android.media.Image\nimport android.os.Build.VERSION.SDK_INT\nimport android.util.Log\nimport androidx.annotation.RequiresApi\nimport com.google.zxing.BarcodeFormat\nimport com.google.zxing.BinaryBitmap\nimport com.google.zxing.ChecksumException\nimport com.google.zxing.DecodeHintType\nimport com.google.zxing.FormatException\nimport com.google.zxing.LuminanceSource\nimport com.google.zxing.NotFoundException\nimport com.google.zxing.PlanarYUVLuminanceSource\nimport com.google.zxing.RGBLuminanceSource\nimport com.google.zxing.Result\nimport com.google.zxing.common.HybridBinarizer\nimport java.nio.ByteBuffer\nimport java.nio.IntBuffer\n\nprivate const val TAG = \"BarcodeDecodeHelper\"\n\nclass BarcodeDecodeHelper(formats: List<BarcodeFormat>, multi: Boolean = true) {\n    private val reader = MultiBarcodeReader(\n        mapOf(\n            DecodeHintType.TRY_HARDER to true,\n            DecodeHintType.ALSO_INVERTED to true,\n            DecodeHintType.POSSIBLE_FORMATS to formats\n        )\n    )\n\n    fun decodeFromSource(source: LuminanceSource): List<Result> {\n        return try {\n            reader.multiDecode(BinaryBitmap(HybridBinarizer(source))).also {\n                if (it.isNotEmpty()) reader.reset()\n            }\n        } catch (e: NotFoundException) {\n            emptyList()\n        } catch (e: FormatException) {\n            emptyList()\n        } catch (e: ChecksumException) {\n            emptyList()\n        } catch (e: Exception) {\n            Log.w(TAG, \"Exception with $this: $e\")\n            emptyList()\n        }\n    }\n\n    fun decodeFromLuminanceBytes(rawBarcodeData: RawBarcodeData, rotate: Int): List<Result> {\n        Log.d(TAG, \"decodeFromLuminanceBytes rotate:\")\n        rawBarcodeData.rotateDetail(rotate)\n        return decodeFromSource(\n            PlanarYUVLuminanceSource(\n                rawBarcodeData.bytes, rawBarcodeData.width, rawBarcodeData.height,\n                0, 0, rawBarcodeData.width, rawBarcodeData.height, false\n            )\n        )\n    }\n\n    fun decodeFromLuminanceBytes(buffer: ByteBuffer, width: Int, height: Int, rotate: Int = 0): List<Result> {\n        val bytes = ByteArray(buffer.remaining())\n        buffer.get(bytes)\n        buffer.rewind()\n        val rawBarcodeData = RawBarcodeData(bytes, width, height)\n        return decodeFromLuminanceBytes(rawBarcodeData, rotate)\n    }\n\n    @RequiresApi(19)\n    fun decodeFromImage(image: Image, rotate: Int = 0): List<Result> {\n        if (image.format !in SUPPORTED_IMAGE_FORMATS) return emptyList()\n        val rawBarcodeData =RawBarcodeData(getYUVBytesFromImage(image), image.width, image.height)\n        return decodeFromLuminanceBytes(rawBarcodeData, rotate)\n    }\n\n    private fun getYUVBytesFromImage(image: Image): ByteArray {\n        val planes = image.planes\n        val width = image.width\n        val height = image.height\n        val yuvBytes = ByteArray(width * height * 3 / 2)\n        var offset = 0\n\n        for (i in planes.indices) {\n            val buffer = planes[i].buffer\n            val rowStride = planes[i].rowStride\n            val pixelStride = planes[i].pixelStride\n            val planeWidth = if ((i == 0)) width else width / 2\n            val planeHeight = if ((i == 0)) height else height / 2\n\n            val planeBytes = ByteArray(buffer.capacity())\n            buffer[planeBytes]\n\n            for (row in 0 until planeHeight) {\n                for (col in 0 until planeWidth) {\n                    yuvBytes[offset++] = planeBytes[row * rowStride + col * pixelStride]\n                }\n            }\n        }\n        return yuvBytes\n    }\n\n    fun decodeFromBitmap(bitmap: Bitmap): List<Result> {\n        val frameBuf: IntBuffer = IntBuffer.allocate(bitmap.byteCount)\n        bitmap.copyPixelsToBuffer(frameBuf)\n        return decodeFromSource(RGBLuminanceSource(bitmap.width, bitmap.height, frameBuf.array()))\n    }\n\n    companion object {\n        @RequiresApi(19)\n        val SUPPORTED_IMAGE_FORMATS =\n            listOfNotNull(ImageFormat.YUV_420_888, if (SDK_INT >= 23) ImageFormat.YUV_422_888 else null, if (SDK_INT >= 23) ImageFormat.YUV_444_888 else null)\n    }\n}"
  },
  {
    "path": "play-services-vision/core/src/main/kotlin/org/microg/gms/vision/barcode/BarcodeDetector.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.vision.barcode\n\nimport android.content.Context\nimport android.graphics.Bitmap\nimport android.graphics.Point\nimport android.util.Log\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.ObjectWrapper\nimport com.google.android.gms.dynamic.unwrap\nimport com.google.android.gms.vision.barcode.Barcode\nimport com.google.android.gms.vision.barcode.internal.client.BarcodeDetectorOptions\nimport com.google.android.gms.vision.barcode.internal.client.INativeBarcodeDetector\nimport com.google.android.gms.vision.internal.FrameMetadataParcel\nimport com.google.zxing.*\nimport com.google.zxing.client.result.*\nimport java.nio.ByteBuffer\nimport java.nio.IntBuffer\nimport java.util.*\n\nprivate const val TAG = \"BarcodeDetector\"\n\nclass BarcodeDetector(val context: Context, val options: BarcodeDetectorOptions) : INativeBarcodeDetector.Stub() {\n    private val helper = BarcodeDecodeHelper(options.formats.gmsToZXingBarcodeFormats())\n    private var loggedOnce = false\n\n    override fun detectBitmap(wrappedBitmap: IObjectWrapper, metadata: FrameMetadataParcel): Array<Barcode> {\n        if (!loggedOnce) Log.d(TAG, \"detectBitmap(${ObjectWrapper.unwrap(wrappedBitmap)}, $metadata)\").also { loggedOnce = true }\n        val bitmap = wrappedBitmap.unwrap<Bitmap>() ?: return emptyArray()\n        return helper.decodeFromBitmap(bitmap)\n            .mapNotNull { runCatching { it.toGms(metadata) }.getOrNull() }.toTypedArray()\n    }\n\n    override fun detectBytes(wrappedByteBuffer: IObjectWrapper, metadata: FrameMetadataParcel): Array<Barcode> {\n        if (!loggedOnce) Log.d(TAG, \"detectBytes(${ObjectWrapper.unwrap(wrappedByteBuffer)}, $metadata)\").also { loggedOnce = true }\n        val bytes = wrappedByteBuffer.unwrap<ByteBuffer>() ?: return emptyArray()\n        return helper.decodeFromLuminanceBytes(bytes, metadata.width, metadata.height, metadata.rotation)\n            .mapNotNull { runCatching { it.toGms(metadata) }.getOrNull() }.toTypedArray()\n    }\n\n    override fun close() {\n        Log.d(TAG, \"close()\")\n    }\n}\n\nprivate fun Int.gmsToZXingBarcodeFormats(): List<BarcodeFormat> {\n    return listOfNotNull(\n        BarcodeFormat.AZTEC.takeIf { (this and Barcode.AZTEC) > 0 || this == Barcode.ALL_FORMATS },\n        BarcodeFormat.CODABAR.takeIf { (this and Barcode.CODABAR) > 0 || this == Barcode.ALL_FORMATS },\n        BarcodeFormat.CODE_39.takeIf { (this and Barcode.CODE_39) > 0 || this == Barcode.ALL_FORMATS },\n        BarcodeFormat.CODE_93.takeIf { (this and Barcode.CODE_93) > 0 || this == Barcode.ALL_FORMATS },\n        BarcodeFormat.CODE_128.takeIf { (this and Barcode.CODE_128) > 0 || this == Barcode.ALL_FORMATS },\n        BarcodeFormat.DATA_MATRIX.takeIf { (this and Barcode.DATA_MATRIX) > 0 || this == Barcode.ALL_FORMATS },\n        BarcodeFormat.EAN_8.takeIf { (this and Barcode.EAN_8) > 0 || this == Barcode.ALL_FORMATS },\n        BarcodeFormat.EAN_13.takeIf { (this and Barcode.EAN_13) > 0 || this == Barcode.ALL_FORMATS },\n        BarcodeFormat.ITF.takeIf { (this and Barcode.ITF) > 0 || this == Barcode.ALL_FORMATS },\n        BarcodeFormat.PDF_417.takeIf { (this and Barcode.PDF417) > 0 || this == Barcode.ALL_FORMATS },\n        BarcodeFormat.QR_CODE.takeIf { (this and Barcode.QR_CODE) > 0 || this == Barcode.ALL_FORMATS },\n        BarcodeFormat.UPC_A.takeIf { (this and Barcode.UPC_A) > 0 || this == Barcode.ALL_FORMATS },\n        BarcodeFormat.UPC_E.takeIf { (this and Barcode.UPC_E) > 0 || this == Barcode.ALL_FORMATS },\n    )\n}\n\n\nprivate fun BarcodeFormat.toGms(): Int = when (this) {\n    BarcodeFormat.AZTEC -> Barcode.AZTEC\n    BarcodeFormat.CODABAR -> Barcode.CODABAR\n    BarcodeFormat.CODE_39 -> Barcode.CODE_39\n    BarcodeFormat.CODE_93 -> Barcode.CODE_93\n    BarcodeFormat.CODE_128 -> Barcode.CODE_128\n    BarcodeFormat.DATA_MATRIX -> Barcode.DATA_MATRIX\n    BarcodeFormat.EAN_13 -> Barcode.EAN_13\n    BarcodeFormat.EAN_8 -> Barcode.EAN_8\n    BarcodeFormat.ITF -> Barcode.ITF\n    BarcodeFormat.PDF_417 -> Barcode.PDF417\n    BarcodeFormat.QR_CODE -> Barcode.QR_CODE\n    BarcodeFormat.UPC_A -> Barcode.UPC_A\n    BarcodeFormat.UPC_E -> Barcode.UPC_E\n    else -> throw UnsupportedOperationException()\n}\n\nprivate fun ParsedResultType.toGms(): Int = when (this) {\n    ParsedResultType.ADDRESSBOOK -> Barcode.CONTACT_INFO\n    ParsedResultType.CALENDAR -> Barcode.CALENDAR_EVENT\n    ParsedResultType.EMAIL_ADDRESS -> Barcode.EMAIL\n    ParsedResultType.GEO -> Barcode.GEO\n    ParsedResultType.ISBN -> Barcode.ISBN\n    ParsedResultType.PRODUCT -> Barcode.PRODUCT\n    ParsedResultType.SMS -> Barcode.SMS\n    ParsedResultType.TEL -> Barcode.PHONE\n    ParsedResultType.TEXT -> Barcode.TEXT\n    ParsedResultType.URI -> Barcode.URL\n    ParsedResultType.WIFI -> Barcode.WIFI\n    else -> Barcode.TEXT\n}\n\nprivate fun AddressBookParsedResult.toGms(): Barcode.ContactInfo {\n    val contactInfo = Barcode.ContactInfo()\n    // TODO: contactInfo.name\n    contactInfo.organization = org\n    contactInfo.title = title\n    contactInfo.phones = phoneNumbers.orEmpty().mapIndexed { i, a ->\n        Barcode.Phone().apply {\n            type = when (phoneTypes?.getOrNull(i)) {\n                \"WORK\" -> Barcode.Phone.WORK\n                \"HOME\" -> Barcode.Phone.HOME\n                \"FAX\" -> Barcode.Phone.FAX\n                \"MOBILE\" -> Barcode.Phone.MOBILE\n                else -> Barcode.Phone.UNKNOWN\n            }\n            number = a\n        }\n    }.toTypedArray()\n    contactInfo.emails = emails.orEmpty().mapIndexed { i, a ->\n        Barcode.Email().apply {\n            type = when (emailTypes?.getOrNull(i)) {\n                \"WORK\" -> Barcode.Email.WORK\n                \"HOME\" -> Barcode.Email.HOME\n                else -> Barcode.Email.UNKNOWN\n            }\n            address = a\n        }\n    }.toTypedArray()\n    contactInfo.urls = urLs\n    contactInfo.addresses = addresses.orEmpty().mapIndexed { i, a ->\n        Barcode.Address().apply {\n            type = when (addressTypes?.getOrNull(i)) {\n                \"WORK\" -> Barcode.Address.WORK\n                \"HOME\" -> Barcode.Address.HOME\n                else -> Barcode.Address.UNKNOWN\n            }\n            addressLines = a.split(\"\\n\").toTypedArray()\n        }\n    }.toTypedArray()\n\n    return contactInfo\n}\n\nprivate fun CalendarParsedResult.toGms(): Barcode.CalendarEvent {\n    fun createDateTime(timestamp: Long, isAllDay: Boolean) = Barcode.CalendarDateTime().apply {\n        val calendar = Calendar.getInstance()\n        calendar.time = Date(timestamp)\n        year = calendar.get(Calendar.YEAR)\n        month = calendar.get(Calendar.MONTH)\n        day = calendar.get(Calendar.DAY_OF_MONTH)\n        if (isAllDay) {\n            hours = -1\n            minutes = -1\n            seconds = -1\n        } else {\n            hours = calendar.get(Calendar.HOUR_OF_DAY)\n            minutes = calendar.get(Calendar.MINUTE)\n            seconds = calendar.get(Calendar.SECOND)\n        }\n    }\n\n\n    val event = Barcode.CalendarEvent()\n    event.summary = summary\n    event.description = description\n    event.location = location\n    event.organizer = organizer\n    event.start = createDateTime(startTimestamp, isStartAllDay)\n    event.end = createDateTime(endTimestamp, isEndAllDay)\n    return event\n}\n\nprivate fun EmailAddressParsedResult.toGms(): Barcode.Email {\n    val email = Barcode.Email()\n    email.address = tos?.getOrNull(0)\n    email.subject = subject\n    email.body = body\n    return email\n}\n\nprivate fun GeoParsedResult.toGms(): Barcode.GeoPoint {\n    val geo = Barcode.GeoPoint()\n    geo.lat = latitude\n    geo.lng = longitude\n    return geo\n}\n\nprivate fun TelParsedResult.toGms(): Barcode.Phone {\n    val phone = Barcode.Phone()\n    phone.number = number\n    return phone\n}\n\nprivate fun SMSParsedResult.toGms(): Barcode.Sms {\n    val sms = Barcode.Sms()\n    sms.message = body\n    sms.phoneNumber = numbers?.getOrNull(0)\n    return sms\n}\n\nprivate fun WifiParsedResult.toGms(): Barcode.WiFi {\n    val wifi = Barcode.WiFi()\n    wifi.ssid = ssid\n    wifi.password = password\n    wifi.encryptionType = when (networkEncryption) {\n        \"OPEN\" -> Barcode.WiFi.OPEN\n        \"WEP\" -> Barcode.WiFi.WEP\n        \"WPA\" -> Barcode.WiFi.WPA\n        \"WPA2\" -> Barcode.WiFi.WPA\n        else -> 0\n    }\n    return wifi\n}\n\nprivate fun URIParsedResult.toGms(): Barcode.UrlBookmark {\n    val url = Barcode.UrlBookmark()\n    url.url = uri\n    url.title = title\n    return url\n}\n\nprivate fun Result.toGms(metadata: FrameMetadataParcel): Barcode {\n    val barcode = Barcode()\n    barcode.format = barcodeFormat.toGms()\n    barcode.rawBytes = rawBytes\n    barcode.rawValue = text\n    barcode.cornerPoints = resultPoints.map {\n        Point(it.x.toInt(), it.y.toInt())\n    }.toTypedArray()\n\n    val parsed = ResultParser.parseResult(this)\n\n    barcode.displayValue = parsed.displayResult\n    barcode.valueFormat = parsed.type.toGms()\n    when (parsed) {\n        is EmailAddressParsedResult ->\n            barcode.email = parsed.toGms()\n\n        is TelParsedResult ->\n            barcode.phone = parsed.toGms()\n\n        is SMSParsedResult ->\n            barcode.sms = parsed.toGms()\n\n        is WifiParsedResult ->\n            barcode.wifi = parsed.toGms()\n\n        is URIParsedResult ->\n            barcode.url = parsed.toGms()\n\n        is GeoParsedResult ->\n            barcode.geoPoint = parsed.toGms()\n\n        is CalendarParsedResult ->\n            barcode.calendarEvent = parsed.toGms()\n\n        is AddressBookParsedResult ->\n            barcode.contactInfo = parsed.toGms()\n    }\n\n    return barcode\n}"
  },
  {
    "path": "play-services-vision/core/src/main/kotlin/org/microg/gms/vision/barcode/BarcodeScanner.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.vision.barcode\n\nimport android.content.Context\nimport android.graphics.Bitmap\nimport android.graphics.ImageFormat\nimport android.media.Image\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.Parcel\nimport android.util.Log\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.ObjectWrapper\nimport com.google.android.gms.dynamic.unwrap\nimport com.google.mlkit.vision.barcode.aidls.IBarcodeScanner\nimport com.google.mlkit.vision.barcode.internal.*\nimport com.google.zxing.BarcodeFormat\nimport org.microg.gms.utils.warnOnTransactionIssues\nimport java.nio.ByteBuffer\n\nprivate const val TAG = \"BarcodeScanner\"\n\nclass BarcodeScanner(val context: Context, val options: BarcodeScannerOptions) : IBarcodeScanner.Stub() {\n    private val helper =\n        BarcodeDecodeHelper(if (options.allPotentialBarcodesEnabled) BarcodeFormat.values().toList() else options.supportedFormats.mlKitToZXingBarcodeFormats())\n    private var loggedOnce = false\n\n    override fun init() {\n        Log.d(TAG, \"init()\")\n    }\n\n    override fun close() {\n        Log.d(TAG, \"close()\")\n    }\n\n    override fun detect(wrappedImage: IObjectWrapper, metadata: ImageMetadata): List<Barcode> {\n        if (!loggedOnce) Log.d(TAG, \"detect(${ObjectWrapper.unwrap(wrappedImage)}, $metadata)\").also { loggedOnce = true }\n        return when (metadata.format) {\n            -1 -> wrappedImage.unwrap<Bitmap>()?.let { helper.decodeFromBitmap(it) }\n            ImageFormat.NV21 -> wrappedImage.unwrap<ByteBuffer>()?.let { helper.decodeFromLuminanceBytes(it, metadata.width, metadata.height, metadata.rotation) }\n            ImageFormat.YUV_420_888 -> if (SDK_INT >= 19) wrappedImage.unwrap<Image>()?.let { image -> helper.decodeFromImage(image, metadata.rotation) } else null\n\n            else -> null\n        }?.map { it.toMlKit(metadata) } ?: emptyList()\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =\n        warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n}"
  },
  {
    "path": "play-services-vision/core/src/main/kotlin/org/microg/gms/vision/barcode/MultiBarcodeReader.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.vision.barcode\n\nimport com.google.zxing.*\nimport com.google.zxing.multi.MultipleBarcodeReader\nimport kotlin.math.max\nimport kotlin.math.min\n\nclass MultiBarcodeReader(val hints: Map<DecodeHintType, *>) : MultipleBarcodeReader, Reader {\n    val delegate = MultiFormatReader().apply { setHints(hints) }\n\n    fun multiDecode(image: BinaryBitmap): List<Result> {\n        return doDecodeMultiple(image)\n    }\n\n    override fun decodeMultiple(image: BinaryBitmap): Array<Result> {\n        return multiDecode(image).toTypedArray()\n    }\n\n    override fun decodeMultiple(image: BinaryBitmap, hints: MutableMap<DecodeHintType, *>?): Array<Result> {\n        return multiDecode(image).toTypedArray()\n    }\n\n    override fun decode(image: BinaryBitmap): Result {\n        return delegate.decodeWithState(image)\n    }\n\n    override fun decode(image: BinaryBitmap, hints: MutableMap<DecodeHintType, *>?): Result {\n        return delegate.decodeWithState(image)\n    }\n\n    override fun reset() {\n        delegate.reset()\n    }\n\n    // Derived from com.google.zxing.multi GenericMultipleBarcodeReader\n    // Copyright 2009 ZXing authors\n    // Licensed under the Apache License, Version 2.0\n    private fun doDecodeMultiple(\n        image: BinaryBitmap,\n        results: MutableList<Result> = arrayListOf(),\n        xOffset: Int = 0,\n        yOffset: Int = 0,\n        currentDepth: Int = 0,\n        maxDepth: Int = 2\n    ): List<Result> {\n        val result = kotlin.runCatching { delegate.decodeWithState(image) }.getOrNull() ?: return results\n\n        if (results.none { it.text == result.text }) {\n            results.add(translateResultPoints(result, xOffset, yOffset))\n        }\n\n        val resultPoints = result.resultPoints\n        if (resultPoints != null && resultPoints.isNotEmpty() && currentDepth + 1 < maxDepth) {\n            val width = image.width\n            val height = image.height\n            var minX = width.toFloat()\n            var minY = height.toFloat()\n            var maxX = 0.0f\n            var maxY = 0.0f\n\n            for (point in resultPoints) {\n                if (point != null) {\n                    minX = min(point.x, minX)\n                    minY = min(point.y, minY)\n                    maxX = max(point.x, maxX)\n                    maxY = max(point.y, maxY)\n                }\n            }\n\n            if (minX > 100.0f) {\n                this.doDecodeMultiple(image.crop(0, 0, minX.toInt(), height), results, xOffset, yOffset, currentDepth + 1, maxDepth)\n            }\n\n            if (minY > 100.0f) {\n                this.doDecodeMultiple(image.crop(0, 0, width, minY.toInt()), results, xOffset, yOffset, currentDepth + 1, maxDepth)\n            }\n\n            if (maxX < (width - 100).toFloat()) {\n                this.doDecodeMultiple(image.crop(maxX.toInt(), 0, width - maxX.toInt(), height), results, xOffset + maxX.toInt(), yOffset, currentDepth + 1, maxDepth)\n            }\n\n            if (maxY < (height - 100).toFloat()) {\n                this.doDecodeMultiple(image.crop(0, maxY.toInt(), width, height - maxY.toInt()), results, xOffset, yOffset + maxY.toInt(), currentDepth + 1, maxDepth)\n            }\n        }\n        return results\n    }\n\n    private fun translateResultPoints(result: Result, xOffset: Int, yOffset: Int): Result {\n        val oldResultPoints = result.resultPoints\n        if (oldResultPoints == null) {\n            return result\n        } else {\n            val newResultPoints = arrayOfNulls<ResultPoint>(oldResultPoints.size)\n\n            for (i in oldResultPoints.indices) {\n                val oldPoint = oldResultPoints[i]\n                if (oldPoint != null) {\n                    newResultPoints[i] = ResultPoint(oldPoint.x + xOffset.toFloat(), oldPoint.y + yOffset.toFloat())\n                }\n            }\n\n            val newResult = Result(result.text, result.rawBytes, result.numBits, newResultPoints, result.barcodeFormat, result.timestamp)\n            newResult.putAllMetadata(result.resultMetadata)\n            return newResult\n        }\n    }\n\n}"
  },
  {
    "path": "play-services-vision/core/src/main/kotlin/org/microg/gms/vision/barcode/QRCodeScannerView.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.vision.barcode\n\nimport android.content.Context\nimport android.graphics.Canvas\nimport android.graphics.Paint\nimport android.graphics.RectF\nimport android.util.AttributeSet\nimport android.view.View\nimport android.widget.FrameLayout\nimport androidx.annotation.RequiresApi\nimport androidx.camera.core.CameraSelector\nimport androidx.camera.core.ImageAnalysis\nimport androidx.camera.core.ImageProxy\nimport androidx.camera.core.Preview\nimport androidx.camera.lifecycle.ProcessCameraProvider\nimport androidx.camera.view.PreviewView\nimport androidx.core.content.ContextCompat\nimport com.google.common.util.concurrent.ListenableFuture\nimport com.google.mlkit.vision.barcode.internal.Barcode\nimport com.google.zxing.BarcodeFormat\nimport com.google.zxing.BinaryBitmap\nimport com.google.zxing.DecodeHintType\nimport com.google.zxing.MultiFormatReader\nimport com.google.zxing.NotFoundException\nimport com.google.zxing.PlanarYUVLuminanceSource\nimport com.google.zxing.common.HybridBinarizer\nimport java.util.concurrent.ExecutorService\nimport java.util.concurrent.Executors\n\n@RequiresApi(21)\nclass QRCodeScannerView @JvmOverloads constructor(\n    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0\n) : FrameLayout(context, attrs, defStyleAttr) {\n\n    private var cameraExecutor: ExecutorService = Executors.newSingleThreadExecutor()\n    private lateinit var cameraProviderFuture: ListenableFuture<ProcessCameraProvider>\n    private var onQRCodeScanned: ((Barcode?) -> Unit)? = null\n    private val previewView: PreviewView = PreviewView(context).apply {\n        layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)\n    }\n\n    init {\n        addView(previewView)\n        addView(ScanOverlayView(context))\n    }\n\n    fun startScanner(onScanned: (Barcode?) -> Unit) {\n        this.onQRCodeScanned = onScanned\n        startCamera()\n    }\n\n    private fun startCamera() {\n        cameraProviderFuture = ProcessCameraProvider.getInstance(context)\n        cameraProviderFuture.addListener({\n            val cameraProvider = cameraProviderFuture.get()\n\n            val preview = Preview.Builder().build().also { it.setSurfaceProvider(previewView.surfaceProvider) }\n\n            val imageAnalyzer = ImageAnalysis.Builder().setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST).build().also {\n                it.setAnalyzer(cameraExecutor, QRCodeAnalyzer { result ->\n                    post { onQRCodeScanned?.invoke(result) }\n                })\n            }\n\n            val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA\n\n            try {\n                cameraProvider.unbindAll()\n                cameraProvider.bindToLifecycle(context as androidx.lifecycle.LifecycleOwner, cameraSelector, preview, imageAnalyzer)\n            } catch (e: Exception) {\n                e.printStackTrace()\n            }\n        }, ContextCompat.getMainExecutor(context))\n    }\n\n    override fun onDetachedFromWindow() {\n        super.onDetachedFromWindow()\n        cameraExecutor.shutdown()\n    }\n}\n\nprivate class ScanOverlayView(context: Context) : View(context) {\n    private val cornerLength = 160f\n    private val cornerThickness = 10f\n    private val paint = Paint().apply {\n        isAntiAlias = true\n        strokeWidth = cornerThickness\n        style = Paint.Style.STROKE\n    }\n\n    override fun onDraw(canvas: Canvas) {\n        super.onDraw(canvas)\n\n        val frameSize = width.coerceAtMost(height) * 0.6f\n        val left = (width - frameSize) / 2f\n        val top = (height - frameSize) / 2f\n        val right = left + frameSize\n        val bottom = top + frameSize\n        val frame = RectF(left, top, right, bottom)\n\n        val colors = listOf(0xFF4285F4.toInt(), 0xFFEA4335.toInt(), 0xFFFBBC05.toInt(), 0xFF34A853.toInt())\n\n        paint.color = colors[0]\n        canvas.drawLine(frame.left, frame.top, frame.left + cornerLength, frame.top, paint)\n        canvas.drawLine(frame.left, frame.top, frame.left, frame.top + cornerLength, paint)\n\n        paint.color = colors[1]\n        canvas.drawLine(frame.right, frame.top, frame.right - cornerLength, frame.top, paint)\n        canvas.drawLine(frame.right, frame.top, frame.right, frame.top + cornerLength, paint)\n\n        paint.color = colors[2]\n        canvas.drawLine(frame.left, frame.bottom, frame.left + cornerLength, frame.bottom, paint)\n        canvas.drawLine(frame.left, frame.bottom, frame.left, frame.bottom - cornerLength, paint)\n\n        paint.color = colors[3]\n        canvas.drawLine(frame.right, frame.bottom, frame.right - cornerLength, frame.bottom, paint)\n        canvas.drawLine(frame.right, frame.bottom, frame.right, frame.bottom - cornerLength, paint)\n    }\n}\n\n@RequiresApi(21)\nprivate class QRCodeAnalyzer(private val onQRCodeScanned: (Barcode?) -> Unit) : ImageAnalysis.Analyzer {\n\n    private val reader = MultiFormatReader().apply {\n        setHints(mapOf(DecodeHintType.POSSIBLE_FORMATS to listOf(BarcodeFormat.QR_CODE)))\n    }\n\n    override fun analyze(image: ImageProxy) {\n        val buffer = image.planes[0].buffer\n        val bytes = ByteArray(buffer.remaining())\n        buffer.get(bytes)\n\n        val source = PlanarYUVLuminanceSource(bytes, image.width, image.height, 0, 0, image.width, image.height, false)\n        val binaryBitmap = BinaryBitmap(HybridBinarizer(source))\n\n        try {\n            val result = reader.decode(binaryBitmap)\n            onQRCodeScanned(result.toMlKit())\n        } catch (e: NotFoundException) {\n            onQRCodeScanned(null)\n        } finally {\n            image.close()\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-vision/core/src/main/kotlin/org/microg/gms/vision/barcode/RawBarcodeData.kt",
    "content": "package org.microg.gms.vision.barcode\n\nimport android.util.Log\nimport android.view.Surface\n\nclass RawBarcodeData(var bytes: ByteArray, var width: Int, var height: Int) {\n\n    fun rotateDetail(rotate: Int){\n        when (rotate) {\n            Surface.ROTATION_90 -> rotateDegree90()\n            Surface.ROTATION_180 -> rotateDegree180()\n            Surface.ROTATION_270 -> rotateDegree270()\n            else -> this\n        }\n    }\n\n    private fun rotateDegree90(){\n        val rotatedData = ByteArray(bytes.size)\n        var index = 0\n\n        // Rotate Y plane\n        for (col in 0 until width) {\n            for (row in height - 1 downTo 0) {\n                rotatedData[index++] = bytes[row * width + col]\n            }\n        }\n\n        // Rotate UV planes (UV interleaved)\n        val uvHeight = height / 2\n        for (col in 0 until width step 2) {\n            for (row in uvHeight - 1 downTo 0) {\n                rotatedData[index++] = bytes[width * height + row * width + col]\n                rotatedData[index++] = bytes[width * height + row * width + col + 1]\n            }\n        }\n        bytes = rotatedData\n        val temp = width\n        width = height\n        height = temp\n    }\n\n    private fun rotateDegree180() {\n        val rotatedData = ByteArray(bytes.size)\n        var index = 0\n\n        // Rotate Y plane\n        for (row in height - 1 downTo 0) {\n            for (col in width - 1 downTo 0) {\n                rotatedData[index++] = bytes[row * width + col]\n            }\n        }\n\n        // Rotate UV planes (UV interleaved)\n        val uvHeight = height / 2\n        val uvWidth = width / 2\n        for (row in uvHeight - 1 downTo 0) {\n            for (col in uvWidth - 1 downTo 0) {\n                val offset = width * height + row * width + col * 2\n                rotatedData[index++] = bytes[offset]\n                rotatedData[index++] = bytes[offset + 1]\n            }\n        }\n        bytes = rotatedData\n    }\n\n\n    private fun rotateDegree270(){\n        val rotatedData = ByteArray(bytes.size)\n        var index = 0\n\n        // Rotate Y plane\n        for (col in width - 1 downTo 0) {\n            for (row in 0 until height) {\n                rotatedData[index++] = bytes[row * width + col]\n            }\n        }\n\n        // Rotate UV planes (UV interleaved)\n        val uvHeight = height / 2\n        for (col in width - 1 downTo 0 step 2) {\n            for (row in 0 until uvHeight) {\n                rotatedData[index++] = bytes[width * height + row * width + col - 1]\n                rotatedData[index++] = bytes[width * height + row * width + col]\n            }\n        }\n        bytes = rotatedData\n        val temp = width\n        width = height\n        height = temp\n    }\n\n    override fun toString(): String {\n        return \"RawBarcodeData(bytes=${bytes.size}, width=$width, height=$height)\"\n    }\n}"
  },
  {
    "path": "play-services-vision/core/src/main/kotlin/org/microg/gms/vision/barcode/extensions.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.vision.barcode\n\nimport android.graphics.Point\nimport com.google.mlkit.vision.barcode.internal.Address\nimport com.google.mlkit.vision.barcode.internal.Barcode\nimport com.google.mlkit.vision.barcode.internal.CalendarDateTime\nimport com.google.mlkit.vision.barcode.internal.CalendarEvent\nimport com.google.mlkit.vision.barcode.internal.ContactInfo\nimport com.google.mlkit.vision.barcode.internal.Email\nimport com.google.mlkit.vision.barcode.internal.GeoPoint\nimport com.google.mlkit.vision.barcode.internal.ImageMetadata\nimport com.google.mlkit.vision.barcode.internal.Phone\nimport com.google.mlkit.vision.barcode.internal.Sms\nimport com.google.mlkit.vision.barcode.internal.UrlBookmark\nimport com.google.mlkit.vision.barcode.internal.WiFi\nimport com.google.zxing.BarcodeFormat\nimport com.google.zxing.Result\nimport com.google.zxing.client.result.AddressBookParsedResult\nimport com.google.zxing.client.result.CalendarParsedResult\nimport com.google.zxing.client.result.EmailAddressParsedResult\nimport com.google.zxing.client.result.GeoParsedResult\nimport com.google.zxing.client.result.ParsedResultType\nimport com.google.zxing.client.result.ResultParser\nimport com.google.zxing.client.result.SMSParsedResult\nimport com.google.zxing.client.result.TelParsedResult\nimport com.google.zxing.client.result.URIParsedResult\nimport com.google.zxing.client.result.WifiParsedResult\nimport java.util.Calendar\nimport java.util.Date\nimport kotlin.collections.mapIndexed\nimport kotlin.collections.orEmpty\nimport kotlin.text.split\n\nfun Int.mlKitToZXingBarcodeFormats(): List<BarcodeFormat> {\n    return listOfNotNull(\n        BarcodeFormat.AZTEC.takeIf { (this and Barcode.AZTEC) > 0 || this == Barcode.ALL_FORMATS },\n        BarcodeFormat.CODABAR.takeIf { (this and Barcode.CODABAR) > 0 || this == Barcode.ALL_FORMATS },\n        BarcodeFormat.CODE_39.takeIf { (this and Barcode.CODE_39) > 0 || this == Barcode.ALL_FORMATS },\n        BarcodeFormat.CODE_93.takeIf { (this and Barcode.CODE_93) > 0 || this == Barcode.ALL_FORMATS },\n        BarcodeFormat.CODE_128.takeIf { (this and Barcode.CODE_128) > 0 || this == Barcode.ALL_FORMATS },\n        BarcodeFormat.DATA_MATRIX.takeIf { (this and Barcode.DATA_MATRIX) > 0 || this == Barcode.ALL_FORMATS },\n        BarcodeFormat.EAN_8.takeIf { (this and Barcode.EAN_8) > 0 || this == Barcode.ALL_FORMATS },\n        BarcodeFormat.EAN_13.takeIf { (this and Barcode.EAN_13) > 0 || this == Barcode.ALL_FORMATS },\n        BarcodeFormat.ITF.takeIf { (this and Barcode.ITF) > 0 || this == Barcode.ALL_FORMATS },\n        BarcodeFormat.PDF_417.takeIf { (this and Barcode.PDF417) > 0 || this == Barcode.ALL_FORMATS },\n        BarcodeFormat.QR_CODE.takeIf { (this and Barcode.QR_CODE) > 0 || this == Barcode.ALL_FORMATS },\n        BarcodeFormat.UPC_A.takeIf { (this and Barcode.UPC_A) > 0 || this == Barcode.ALL_FORMATS },\n        BarcodeFormat.UPC_E.takeIf { (this and Barcode.UPC_E) > 0 || this == Barcode.ALL_FORMATS },\n    )\n}\n\nfun BarcodeFormat.toMlKit(): Int = when (this) {\n    BarcodeFormat.AZTEC -> Barcode.AZTEC\n    BarcodeFormat.CODABAR -> Barcode.CODABAR\n    BarcodeFormat.CODE_39 -> Barcode.CODE_39\n    BarcodeFormat.CODE_93 -> Barcode.CODE_93\n    BarcodeFormat.CODE_128 -> Barcode.CODE_128\n    BarcodeFormat.DATA_MATRIX -> Barcode.DATA_MATRIX\n    BarcodeFormat.EAN_8 -> Barcode.EAN_8\n    BarcodeFormat.EAN_13 -> Barcode.EAN_13\n    BarcodeFormat.ITF -> Barcode.ITF\n    BarcodeFormat.PDF_417 -> Barcode.PDF417\n    BarcodeFormat.QR_CODE -> Barcode.QR_CODE\n    BarcodeFormat.UPC_A -> Barcode.UPC_A\n    BarcodeFormat.UPC_E -> Barcode.UPC_E\n    else -> Barcode.UNKNOWN_FORMAT\n}\n\nfun ParsedResultType.toMlKit(): Int = when (this) {\n    ParsedResultType.ADDRESSBOOK -> Barcode.CONTACT_INFO\n    ParsedResultType.CALENDAR -> Barcode.CALENDAR_EVENT\n    ParsedResultType.EMAIL_ADDRESS -> Barcode.EMAIL\n    ParsedResultType.GEO -> Barcode.GEO\n    ParsedResultType.ISBN -> Barcode.ISBN\n    ParsedResultType.PRODUCT -> Barcode.PRODUCT\n    ParsedResultType.SMS -> Barcode.SMS\n    ParsedResultType.TEL -> Barcode.PHONE\n    ParsedResultType.TEXT -> Barcode.TEXT\n    ParsedResultType.URI -> Barcode.URL\n    ParsedResultType.WIFI -> Barcode.WIFI\n    else -> Barcode.UNKNOWN_TYPE\n}\n\nfun AddressBookParsedResult.toMlKit(): ContactInfo {\n    val contactInfo = ContactInfo()\n    // TODO: contactInfo.name\n    contactInfo.organization = org\n    contactInfo.title = title\n    contactInfo.phones = phoneNumbers.orEmpty().mapIndexed { i, a ->\n        Phone().apply {\n            type = when (phoneTypes?.getOrNull(i)) {\n                \"WORK\" -> Phone.WORK\n                \"HOME\" -> Phone.HOME\n                \"FAX\" -> Phone.FAX\n                \"MOBILE\" -> Phone.MOBILE\n                else -> Phone.UNKNOWN\n            }\n            number = a\n        }\n    }.toTypedArray()\n    contactInfo.emails = emails.orEmpty().mapIndexed { i, a ->\n        Email().apply {\n            type = when (emailTypes?.getOrNull(i)) {\n                \"WORK\" -> Email.WORK\n                \"HOME\" -> Email.HOME\n                else -> Email.UNKNOWN\n            }\n            address = a\n        }\n    }.toTypedArray()\n    contactInfo.urls = urLs\n    contactInfo.addresses = addresses.orEmpty().mapIndexed { i, a ->\n        Address().apply {\n            type = when (addressTypes?.getOrNull(i)) {\n                \"WORK\" -> Address.WORK\n                \"HOME\" -> Address.HOME\n                else -> Address.UNKNOWN\n            }\n            addressLines = a.split(\"\\n\").toTypedArray()\n        }\n    }.toTypedArray()\n\n    return contactInfo\n}\n\nfun CalendarParsedResult.toMlKit(): CalendarEvent {\n    fun createDateTime(timestamp: Long, isAllDay: Boolean) = CalendarDateTime().apply {\n        val calendar = Calendar.getInstance()\n        calendar.time = Date(timestamp)\n        year = calendar.get(Calendar.YEAR)\n        month = calendar.get(Calendar.MONTH)\n        day = calendar.get(Calendar.DAY_OF_MONTH)\n        if (isAllDay) {\n            hours = -1\n            minutes = -1\n            seconds = -1\n        } else {\n            hours = calendar.get(Calendar.HOUR_OF_DAY)\n            minutes = calendar.get(Calendar.MINUTE)\n            seconds = calendar.get(Calendar.SECOND)\n        }\n    }\n\n\n    val event = CalendarEvent()\n    event.summary = summary\n    event.description = description\n    event.location = location\n    event.organizer = organizer\n    event.start = createDateTime(startTimestamp, isStartAllDay)\n    event.end = createDateTime(endTimestamp, isEndAllDay)\n    return event\n}\n\nfun EmailAddressParsedResult.toMlKit(): Email {\n    val email = Email()\n    email.address = tos?.getOrNull(0)\n    email.subject = subject\n    email.body = body\n    return email\n}\n\nfun GeoParsedResult.toMlKit(): GeoPoint {\n    val geo = GeoPoint()\n    geo.lat = latitude\n    geo.lng = longitude\n    return geo\n}\n\nfun TelParsedResult.toMlKit(): Phone {\n    val phone = Phone()\n    phone.number = number\n    return phone\n}\n\nfun SMSParsedResult.toMlKit(): Sms {\n    val sms = Sms()\n    sms.message = body\n    sms.phoneNumber = numbers?.getOrNull(0)\n    return sms\n}\n\nfun WifiParsedResult.toMlKit(): WiFi {\n    val wifi = WiFi()\n    wifi.ssid = ssid\n    wifi.password = password\n    wifi.encryptionType = when (networkEncryption) {\n        \"OPEN\" -> WiFi.OPEN\n        \"WEP\" -> WiFi.WEP\n        \"WPA\" -> WiFi.WPA\n        \"WPA2\" -> WiFi.WPA\n        else -> 0\n    }\n    return wifi\n}\n\nfun URIParsedResult.toMlKit(): UrlBookmark {\n    val url = UrlBookmark()\n    url.url = uri\n    url.title = title\n    return url\n}\n\nfun Result.toMlKit(metadata: ImageMetadata? = null): Barcode {\n    val barcode = Barcode()\n    barcode.format = barcodeFormat.toMlKit()\n    barcode.rawBytes = rawBytes\n    barcode.rawValue = text\n    barcode.cornerPoints = resultPoints.map {\n        when (metadata?.rotation ?: -1) {\n            1 -> Point(metadata!!.height - it.y.toInt(), it.x.toInt())\n            2 -> Point(metadata!!.width - it.x.toInt(), metadata.height - it.y.toInt())\n            3 -> Point(it.y.toInt(), metadata!!.width - it.x.toInt())\n            else -> Point(it.x.toInt(), it.y.toInt())\n        }\n    }.toTypedArray()\n\n    val parsed = ResultParser.parseResult(this)\n\n    barcode.displayValue = parsed.displayResult\n    barcode.valueType = parsed.type.toMlKit()\n    when (parsed) {\n        is EmailAddressParsedResult -> barcode.email = parsed.toMlKit()\n        is TelParsedResult -> barcode.phone = parsed.toMlKit()\n        is SMSParsedResult -> barcode.sms = parsed.toMlKit()\n        is WifiParsedResult -> barcode.wifi = parsed.toMlKit()\n        is URIParsedResult -> barcode.urlBookmark = parsed.toMlKit()\n        is GeoParsedResult -> barcode.geoPoint = parsed.toMlKit()\n        is CalendarParsedResult -> barcode.calendarEvent = parsed.toMlKit()\n        is AddressBookParsedResult -> barcode.contactInfo = parsed.toMlKit()\n    }\n    return barcode\n}"
  },
  {
    "path": "play-services-vision/core/src/main/kotlin/org/microg/gms/vision/face/FaceDetector.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.vision.face\n\nimport android.content.Context\nimport android.util.Log\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.unwrap\nimport com.google.android.gms.vision.face.Contour\nimport com.google.android.gms.vision.face.Landmark\nimport com.google.android.gms.vision.face.internal.client.DetectionOptions\nimport com.google.android.gms.vision.face.internal.client.FaceParcel\nimport com.google.android.gms.vision.face.internal.client.INativeFaceDetector\nimport com.google.android.gms.vision.internal.FrameMetadataParcel\nimport com.google.mlkit.vision.face.Face\nimport java.nio.ByteBuffer\n\nclass FaceDetector(val context: Context, private val options: DetectionOptions?) : INativeFaceDetector.Stub() {\n\n    private val mFaceDetector by lazy { FaceDetectorHelper(context) }\n\n    override fun closeDetectorJni() {\n        Log.d(TAG, \"closeDetectorJni\")\n        mFaceDetector.release()\n    }\n\n    override fun isNativeFaceDetectorAvailable(i: Int): Boolean {\n        Log.d(TAG, \"isNativeFaceDetectorAvailable type:${i}\")\n        return true\n    }\n\n    override fun detectFacesFromPlanes(\n        planeFirst: IObjectWrapper?,\n        planeSencond: IObjectWrapper?,\n        planeThird: IObjectWrapper?,\n        firstPixelStride: Int,\n        secondPixelStride: Int,\n        thirdPixelStride: Int,\n        firstRowStride: Int,\n        secondRowStride: Int,\n        thirdRowStride: Int,\n        metadataParcel: FrameMetadataParcel?\n    ): Array<FaceParcel> {\n        Log.d(\n            TAG,\n            \"detectFacesFromPlanes planeFirst:${planeFirst} ,planeSecond:${planeSencond} ,planeThird:${planeThird},\" + \"firstPixelStride:${firstPixelStride} ,secondPixelStride:${secondPixelStride} ,thirdPixelStride:${thirdPixelStride} ,\" + \"firstRowStride:${firstRowStride} ,secondRowStride:${secondRowStride} ,thirdRowStride:${thirdRowStride},\" + \"metadataParcel:${metadataParcel}\"\n        )\n        val yBuffer = planeFirst?.unwrap<ByteBuffer>() ?: return emptyArray()\n        val uBuffer = planeSencond?.unwrap<ByteBuffer>() ?: return emptyArray()\n        val vBuffer = planeThird?.unwrap<ByteBuffer>() ?: return emptyArray()\n        val width = metadataParcel?.width ?: return emptyArray()\n        val height = metadataParcel?.height ?: return emptyArray()\n        val rotation = metadataParcel.rotation\n        val nv21 = ByteArray(width * height * 3 / 2)\n        var offset = 0\n        for (row in 0 until height) {\n            yBuffer.position(row * firstRowStride)\n            yBuffer.get(nv21, offset, width)\n            offset += width\n        }\n        val chromaWidth = width / 2\n        val chromaHeight = height / 2\n        for (row in 0 until chromaHeight) {\n            for (col in 0 until chromaWidth) {\n                val uIndex = row * secondRowStride + col * secondPixelStride\n                val vIndex = row * thirdRowStride + col * thirdPixelStride\n                nv21[offset++] = vBuffer.get(vIndex)\n                nv21[offset++] = uBuffer.get(uIndex)\n            }\n        }\n        return mFaceDetector.detectFaces(nv21, width, height, rotation).map {\n            it.toFaceParcel()\n        }.toTypedArray().also {\n            it.forEach { Log.d(TAG, \"detectFacesFromPlanes: $it\") }\n        }\n    }\n\n    override fun detectFaceParcels(wrapper: IObjectWrapper?, metadata: FrameMetadataParcel?): Array<FaceParcel> {\n        Log.d(TAG, \"detectFaceParcels byteBuffer:${wrapper} ,metadataParcel:${metadata}\")\n        if (wrapper == null || metadata == null) return emptyArray()\n        val buffer = wrapper.unwrap<ByteBuffer>() ?: return emptyArray()\n        return mFaceDetector.detectFaces(buffer.array(), metadata.width, metadata.height, metadata.rotation).map {\n            it.toFaceParcel()\n        }.toTypedArray().also {\n            it.forEach { Log.d(TAG, \"detectFaceParcels: $it\") }\n        }\n    }\n}\n\nprivate fun com.google.mlkit.vision.face.aidls.FaceParcel.toFaceParcel() = FaceParcel(\n    1,\n    id,\n    (boundingBox.left + boundingBox.width() / 2).toFloat(),\n    (boundingBox.top + boundingBox.height() / 2).toFloat(),\n    boundingBox.width().toFloat(),\n    boundingBox.height().toFloat(),\n    panAngle,\n    rollAngle,\n    tiltAngle,\n    landmarkParcelList.map { landmark -> Landmark(landmark.type, landmark.position.x, landmark.position.y, landmark.type) }.toTypedArray(),\n    leftEyeOpenProbability,\n    rightEyeOpenProbability,\n    smileProbability,\n    contourParcelList.map { contour -> Contour(contour.type, contour.pointsList) }.toTypedArray(),\n    confidenceScore\n)"
  },
  {
    "path": "play-services-vision/core/src/main/kotlin/org/microg/gms/vision/face/FaceDetectorHelper.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.vision.face\n\nimport android.content.Context\nimport android.graphics.Bitmap\nimport android.graphics.BitmapFactory\nimport android.graphics.ImageFormat\nimport android.graphics.PointF\nimport android.graphics.Rect\nimport android.graphics.YuvImage\nimport android.media.Image\nimport android.util.Log\nimport com.google.mlkit.vision.face.FaceContour\nimport com.google.mlkit.vision.face.FaceLandmark\nimport com.google.mlkit.vision.face.aidls.ContourParcel\nimport com.google.mlkit.vision.face.aidls.FaceParcel\nimport com.google.mlkit.vision.face.aidls.LandmarkParcel\nimport org.opencv.android.Utils\nimport org.opencv.core.Core\nimport org.opencv.core.CvType\nimport org.opencv.core.Mat\nimport org.opencv.core.MatOfByte\nimport org.opencv.core.Size\nimport org.opencv.imgproc.Imgproc\nimport org.opencv.objdetect.FaceDetectorYN\nimport java.io.ByteArrayOutputStream\nimport kotlin.math.hypot\n\nconst val TAG = \"FaceDetection\"\n\nclass FaceDetectorHelper(context: Context) {\n\n    private var faceDetectorYN: FaceDetectorYN? = null\n    private var inputSize = Size(320.0, 320.0)\n\n    init {\n        try {\n            val buffer: ByteArray\n            context.assets.open(\"face_detection_yunet_2023mar.onnx\").use {\n                val size = it.available()\n                buffer = ByteArray(size)\n                it.read(buffer)\n            }\n            faceDetectorYN = FaceDetectorYN.create(\"onnx\", MatOfByte(*buffer), MatOfByte(), inputSize, 0.7f, 0.3f, 5000)\n        } catch (e: Exception) {\n            throw RuntimeException(\"faceDetectorYN initialization failed\")\n        }\n    }\n\n    fun detectFaces(bitmap: Bitmap, rotation: Int): List<FaceParcel> {\n        Log.d(TAG, \"detectFaces: source is bitmap\")\n        val rootMat = bitmapToMat(bitmap) ?: return emptyList()\n        return processMat(rootMat, rotation)\n    }\n\n    fun detectFaces(nv21ByteArray: ByteArray, width: Int, height: Int, rotation: Int): List<FaceParcel> {\n        Log.d(TAG, \"detectFaces: source is nv21Buffer\")\n        val rootMat = nv21ToMat(nv21ByteArray, width, height) ?: return emptyList()\n        return processMat(rootMat, rotation)\n    }\n\n    fun detectFaces(image: Image, rotation: Int): List<FaceParcel> {\n        Log.d(TAG, \"detectFaces: source is image\")\n        val rootMat = imageToMat(image) ?: return emptyList()\n        return processMat(rootMat, rotation)\n    }\n\n    fun release() {\n        try {\n            faceDetectorYN = null\n        } catch (e: Exception) {\n            Log.d(TAG, \"release failed\", e)\n        }\n    }\n\n    private fun processMat(mat: Mat, rotation: Int): List<FaceParcel> {\n        val faceDetector = faceDetectorYN ?: return emptyList()\n        val facesMat = Mat()\n        val degree = degree(rotation)\n        Log.d(TAG, \"processMat: degree: $degree\")\n        when (degree) {\n            2 -> Core.rotate(mat, facesMat, Core.ROTATE_90_COUNTERCLOCKWISE)\n            3 -> Core.rotate(mat, facesMat, Core.ROTATE_180)\n            4 -> Core.rotate(mat, facesMat, Core.ROTATE_90_CLOCKWISE)\n            else -> mat.copyTo(facesMat)\n        }\n        val matSize = Size(facesMat.cols().toDouble(), facesMat.rows().toDouble())\n        Log.d(TAG, \"processMat: inputSize: $inputSize\")\n        if (inputSize != matSize) {\n            inputSize = matSize\n            faceDetector.inputSize = matSize\n        }\n        Log.d(TAG, \"processMat: matSize: $matSize\")\n        val result = Mat()\n        val status = faceDetectorYN!!.detect(facesMat, result)\n        Log.d(TAG, \"processMat: detect: $status facesMat: ${result.size()}\")\n        return parseDetections(result)\n    }\n\n    /**\n     * faces: detection results stored in a 2D cv::Mat of shape [num_faces, 15]\n     * 0-1: x, y of bbox top left corner\n     * 2-3: width, height of bbox\n     * 4-5: x, y of right eye (blue point in the example image)\n     * 6-7: x, y of left eye (red point in the example image)\n     * 8-9: x, y of nose tip (green point in the example image)\n     * 10-11: x, y of right corner of mouth (pink point in the example image)\n     * 12-13: x, y of left corner of mouth (yellow point in the example image)\n     * 14: face score\n     */\n    private fun parseDetections(detections: Mat): List<FaceParcel> {\n        val faces = mutableListOf<FaceParcel>()\n        val faceData = FloatArray(detections.cols() * detections.channels())\n        for (i in 0 until detections.rows()) {\n            detections.get(i, 0, faceData)\n            val confidence = faceData[14]\n            val boundingBox = Rect(faceData[0].toInt(), faceData[1].toInt(), (faceData[0] + faceData[2]).toInt(), (faceData[1] + faceData[3]).toInt())\n\n            val leftEyeMark = LandmarkParcel(FaceLandmark.LEFT_EYE, PointF(faceData[4], faceData[5]))\n            val mouthLeftMark = LandmarkParcel(FaceLandmark.MOUTH_LEFT, PointF(faceData[10], faceData[11]))\n            val noseBaseMark = LandmarkParcel(FaceLandmark.NOSE_BASE, PointF(faceData[8], faceData[9]))\n            val rightEyeMark = LandmarkParcel(FaceLandmark.RIGHT_EYE, PointF(faceData[6], faceData[7]))\n            val mouthRightMark = LandmarkParcel(FaceLandmark.MOUTH_RIGHT, PointF(faceData[12], faceData[13]))\n\n            // These are calculated for better compatibility, the model doesn't actually provide proper values here\n            val mouthBottomMark = LandmarkParcel(FaceLandmark.MOUTH_BOTTOM, calculateMidPoint(mouthLeftMark, mouthRightMark))\n            val leftCheekMark = LandmarkParcel(FaceLandmark.LEFT_CHEEK, calculateMidPoint(leftEyeMark, mouthLeftMark))\n            val leftEarMark = LandmarkParcel(FaceLandmark.LEFT_EAR, PointF(boundingBox.right.toFloat(), noseBaseMark.position.y))\n            val rightCheekMark = LandmarkParcel(FaceLandmark.RIGHT_CHEEK, calculateMidPoint(rightEyeMark, mouthRightMark))\n            val rightEarMark = LandmarkParcel(FaceLandmark.RIGHT_EAR, PointF(boundingBox.left.toFloat(), noseBaseMark.position.y))\n\n            val smilingProbability = calculateSmilingProbability(mouthLeftMark, mouthRightMark)\n            val leftEyeOpenProbability = calculateEyeOpenProbability(rightEyeMark, mouthRightMark)\n            val rightEyeOpenProbability = calculateEyeOpenProbability(leftEyeMark, mouthLeftMark)\n\n            val faceContour = ContourParcel(FaceContour.FACE, arrayListOf(\n                PointF(boundingBox.left.toFloat(), boundingBox.top.toFloat()),\n                PointF(boundingBox.left.toFloat(), boundingBox.bottom.toFloat()),\n                PointF(boundingBox.right.toFloat(), boundingBox.bottom.toFloat()),\n                PointF(boundingBox.right.toFloat(), boundingBox.top.toFloat()),\n            ))\n            val leftEyebrowTopContour = ContourParcel(FaceContour.LEFT_EYEBROW_TOP, arrayListOf(leftEyeMark.position))\n            val leftEyebrowBottomContour = ContourParcel(FaceContour.LEFT_EYEBROW_BOTTOM, arrayListOf(leftEyeMark.position))\n            val rightEyebrowTopContour = ContourParcel(FaceContour.RIGHT_EYEBROW_TOP, arrayListOf(rightEyeMark.position))\n            val rightEyebrowBottomContour = ContourParcel(FaceContour.RIGHT_EYEBROW_BOTTOM, arrayListOf(rightEyeMark.position))\n            val leftEyeContour = ContourParcel(FaceContour.LEFT_EYE, arrayListOf(leftEyeMark.position))\n            val rightEyeContour = ContourParcel(FaceContour.RIGHT_EYE, arrayListOf(rightEyeMark.position))\n            val upperLipTopContour = ContourParcel(FaceContour.UPPER_LIP_TOP, arrayListOf(mouthLeftMark.position, mouthBottomMark.position, mouthRightMark.position, mouthBottomMark.position))\n            val upperLipBottomContour = ContourParcel(FaceContour.UPPER_LIP_BOTTOM, arrayListOf(mouthLeftMark.position, mouthBottomMark.position, mouthRightMark.position, mouthBottomMark.position))\n            val lowerLipTopContour = ContourParcel(FaceContour.LOWER_LIP_TOP, arrayListOf(mouthLeftMark.position, mouthBottomMark.position, mouthRightMark.position, mouthBottomMark.position))\n            val lowerLipBottomContour = ContourParcel(FaceContour.LOWER_LIP_BOTTOM, arrayListOf(mouthLeftMark.position, mouthBottomMark.position, mouthRightMark.position, mouthBottomMark.position))\n            val noseBridgeContour = ContourParcel(FaceContour.NOSE_BRIDGE, arrayListOf(noseBaseMark.position))\n            val noseBottomContour = ContourParcel(FaceContour.NOSE_BOTTOM, arrayListOf(noseBaseMark.position))\n            val leftCheekContour = ContourParcel(FaceContour.LEFT_CHEEK, arrayListOf(leftCheekMark.position))\n            val rightCheekContour = ContourParcel(FaceContour.RIGHT_CHEEK, arrayListOf(rightCheekMark.position))\n\n            faces.add(FaceParcel(\n                i,\n                boundingBox,\n                0f,\n                0f,\n                0f,\n                leftEyeOpenProbability,\n                rightEyeOpenProbability,\n                smilingProbability,\n                confidence,\n                arrayListOf(mouthBottomMark, leftCheekMark, leftEarMark, leftEyeMark, mouthLeftMark, noseBaseMark, rightCheekMark, rightEarMark, rightEyeMark, mouthRightMark),\n                arrayListOf(faceContour, leftEyebrowTopContour, leftEyebrowBottomContour, rightEyebrowTopContour, rightEyebrowBottomContour, leftEyeContour, rightEyeContour, upperLipTopContour, upperLipBottomContour, lowerLipTopContour, lowerLipBottomContour, noseBridgeContour, noseBottomContour, leftCheekContour, rightCheekContour)\n            ).also {\n                Log.d(TAG, \"parseDetections: face->$it\")\n            })\n        }\n        Log.d(TAG, \"parseDetections: faces->${faces.size}\")\n        return faces\n    }\n\n    private fun calculateSmilingProbability(rightMouthCorner: LandmarkParcel, leftMouthCorner: LandmarkParcel): Float {\n        val mouthWidth = hypot(\n            (rightMouthCorner.position.x - leftMouthCorner.position.x).toDouble(), (rightMouthCorner.position.y - leftMouthCorner.position.y).toDouble()\n        ).toFloat()\n        return (mouthWidth / 100).coerceIn(0f, 1f)\n    }\n\n    private fun calculateEyeOpenProbability(eye: LandmarkParcel, mouthCorner: LandmarkParcel): Float {\n        val eyeMouthDistance = hypot(\n            (eye.position.x - mouthCorner.position.x).toDouble(), (eye.position.y - mouthCorner.position.y).toDouble()\n        ).toFloat()\n        return (eyeMouthDistance / 50).coerceIn(0f, 1f)\n    }\n\n    private fun calculateMidPoint(eye: LandmarkParcel, mouth: LandmarkParcel): PointF {\n        return PointF((eye.position.x + mouth.position.x) / 2, (eye.position.y + mouth.position.y) / 2)\n    }\n\n    private fun yuv420ToBitmap(image: Image): Bitmap? {\n        val width = image.width\n        val height = image.height\n\n        val yBuffer = image.planes[0].buffer\n        val uBuffer = image.planes[1].buffer\n        val vBuffer = image.planes[2].buffer\n\n        val ySize = yBuffer.remaining()\n        val uSize = uBuffer.remaining()\n        val vSize = vBuffer.remaining()\n\n        val nv21 = ByteArray(ySize + uSize + vSize)\n        yBuffer.get(nv21, 0, ySize)\n        vBuffer.get(nv21, ySize, vSize)\n        uBuffer.get(nv21, ySize + vSize, uSize)\n\n        return nv21toBitmap(nv21, width, height)\n    }\n\n    private fun nv21toBitmap(byteArray: ByteArray, width: Int, height: Int): Bitmap? {\n        try {\n            val yuvImage = YuvImage(byteArray, ImageFormat.NV21, width, height, null)\n            val out = ByteArrayOutputStream()\n            yuvImage.compressToJpeg(Rect(0, 0, width, height), 100, out)\n            val jpegBytes = out.toByteArray()\n            return BitmapFactory.decodeByteArray(jpegBytes, 0, jpegBytes.size)\n        } catch (e: Exception) {\n            Log.w(TAG, \"nv21toBitmap: failed \", e)\n            return null\n        }\n    }\n\n    private fun bitmapToMat(bitmap: Bitmap): Mat? {\n        try {\n            val mat = Mat(bitmap.height, bitmap.width, CvType.CV_8UC4)\n            Utils.bitmapToMat(bitmap, mat)\n            Imgproc.cvtColor(mat, mat, Imgproc.COLOR_RGBA2BGR)\n            return mat\n        } catch (e: Exception) {\n            Log.w(TAG, \"bitmapToMat: failed\", e)\n            return null\n        }\n    }\n\n    private fun imageToMat(image: Image): Mat? {\n        val bitmap = when (image.format) {\n            ImageFormat.JPEG -> {\n                val buffer = image.planes[0].buffer\n                val bytes = ByteArray(buffer.remaining())\n                buffer.get(bytes)\n                BitmapFactory.decodeByteArray(bytes, 0, bytes.size)\n            }\n\n            ImageFormat.YUV_420_888 -> {\n                yuv420ToBitmap(image)\n            }\n\n            else -> {\n                null\n            }\n        }\n        return bitmap?.let { bitmapToMat(it) }\n    }\n\n    private fun nv21ToMat(nv21ByteArray: ByteArray, width: Int, height: Int): Mat? {\n        val bitmap = nv21toBitmap(nv21ByteArray, width, height)\n        return bitmap?.let { bitmapToMat(it) }\n    }\n\n    private fun degree(rotation: Int): Int {\n        if (rotation == 0) return 1\n        if (rotation == 1) return 4\n        if (rotation == 2) return 3\n        if (rotation == 3) return 2\n        return 1\n    }\n\n}\n\n"
  },
  {
    "path": "play-services-vision/core/src/main/kotlin/org/microg/gms/vision/face/mlkit/FaceDetector.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.gms.vision.face.mlkit\n\nimport android.content.Context\nimport android.graphics.Bitmap\nimport android.graphics.ImageFormat\nimport android.media.Image\nimport android.util.Log\nimport com.google.android.gms.dynamic.IObjectWrapper\nimport com.google.android.gms.dynamic.unwrap\nimport com.google.mlkit.vision.face.FaceDetectionOptions\nimport com.google.mlkit.vision.face.FrameMetadataParcel\nimport com.google.mlkit.vision.face.aidls.FaceParcel\nimport com.google.mlkit.vision.face.aidls.IFaceDetector\nimport org.microg.gms.vision.face.TAG\nimport org.microg.gms.vision.face.FaceDetectorHelper\nimport java.nio.ByteBuffer\n\nclass FaceDetector(val context: Context, val options: FaceDetectionOptions?) : IFaceDetector.Stub() {\n\n    private var mFaceDetector: FaceDetectorHelper? = null\n\n    override fun detectFaces(wrapper: IObjectWrapper?, metadata: FrameMetadataParcel?): List<FaceParcel> {\n        Log.d(TAG, \"MLKit detectFaces method: metadata:${metadata}\")\n        if (wrapper == null || metadata == null || mFaceDetector == null) return arrayListOf()\n        val format = metadata.format\n        val rotation = metadata.rotation\n        if (format == -1) {\n            val bitmap = wrapper.unwrap<Bitmap>() ?: return arrayListOf()\n            return mFaceDetector?.detectFaces(bitmap, rotation) ?: arrayListOf()\n        }\n        if (format == ImageFormat.NV21) {\n            val byteBuffer = wrapper.unwrap<ByteBuffer>() ?: return arrayListOf()\n            return mFaceDetector?.detectFaces(byteBuffer.array(), metadata.width, metadata.height, rotation) ?: arrayListOf()\n        }\n        if (format == ImageFormat.YUV_420_888) {\n            val image = wrapper.unwrap<Image>() ?: return arrayListOf()\n            return mFaceDetector?.detectFaces(image, rotation) ?: arrayListOf()\n        }\n        return arrayListOf()\n    }\n\n    override fun initDetector() {\n        Log.d(TAG, \"MLKit initDetector method isInitialized\")\n        if (mFaceDetector == null) {\n            try {\n                mFaceDetector = FaceDetectorHelper(context)\n            } catch (e: Exception) {\n                Log.d(TAG, \"initDetector: failed\", e)\n            }\n        }\n    }\n\n    override fun close() {\n        Log.d(TAG, \"MLKit close\")\n        mFaceDetector?.release()\n        mFaceDetector = null\n    }\n}"
  },
  {
    "path": "play-services-vision/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest />\n"
  },
  {
    "path": "play-services-vision/src/main/aidl/com/google/android/gms/vision/barcode/Barcode.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.vision.barcode;\n\nparcelable Barcode;\n"
  },
  {
    "path": "play-services-vision/src/main/aidl/com/google/android/gms/vision/barcode/internal/client/BarcodeDetectorOptions.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.vision.barcode.internal.client;\n\nparcelable BarcodeDetectorOptions;\n"
  },
  {
    "path": "play-services-vision/src/main/aidl/com/google/android/gms/vision/barcode/internal/client/INativeBarcodeDetector.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.vision.barcode.internal.client;\n\nimport com.google.android.gms.vision.barcode.Barcode;\nimport com.google.android.gms.vision.barcode.internal.client.BarcodeDetectorOptions;\nimport com.google.android.gms.vision.internal.FrameMetadataParcel;\nimport com.google.android.gms.dynamic.IObjectWrapper;\n\ninterface INativeBarcodeDetector {\n    Barcode[] detectBytes(IObjectWrapper byteBuffer, in FrameMetadataParcel metadata) = 0;\n    Barcode[] detectBitmap(IObjectWrapper bitmap, in FrameMetadataParcel metadata) = 1;\n    void close() = 2;\n}\n"
  },
  {
    "path": "play-services-vision/src/main/aidl/com/google/android/gms/vision/barcode/internal/client/INativeBarcodeDetectorCreator.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.vision.barcode.internal.client;\n\nimport com.google.android.gms.vision.barcode.internal.client.BarcodeDetectorOptions;\nimport com.google.android.gms.vision.barcode.internal.client.INativeBarcodeDetector;\nimport com.google.android.gms.dynamic.IObjectWrapper;\n\ninterface INativeBarcodeDetectorCreator {\n    INativeBarcodeDetector create(IObjectWrapper context, in BarcodeDetectorOptions options) = 0;\n}\n"
  },
  {
    "path": "play-services-vision/src/main/aidl/com/google/android/gms/vision/face/Contour.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.vision.face;\n\nparcelable Contour;"
  },
  {
    "path": "play-services-vision/src/main/aidl/com/google/android/gms/vision/face/Landmark.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.vision.face;\n\nparcelable Landmark;"
  },
  {
    "path": "play-services-vision/src/main/aidl/com/google/android/gms/vision/face/internal/client/DetectionOptions.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.vision.face.internal.client;\n\nparcelable DetectionOptions;"
  },
  {
    "path": "play-services-vision/src/main/aidl/com/google/android/gms/vision/face/internal/client/FaceParcel.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.vision.face.internal.client;\n\nparcelable FaceParcel;"
  },
  {
    "path": "play-services-vision/src/main/aidl/com/google/android/gms/vision/face/internal/client/INativeFaceDetector.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.vision.face.internal.client;\n\nimport com.google.android.gms.vision.face.internal.client.FaceParcel;\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.vision.internal.FrameMetadataParcel;\n\ninterface INativeFaceDetector {\n    FaceParcel[] detectFaceParcels(IObjectWrapper byteBuffer, in FrameMetadataParcel metadata) = 0;\n    boolean isNativeFaceDetectorAvailable(int type) = 1;\n    void closeDetectorJni() = 2;\n    FaceParcel[] detectFacesFromPlanes(IObjectWrapper planeFirst, IObjectWrapper planeSecond, IObjectWrapper planeThird, int firstPixelStride, int secondPixelStride, int thirdPixelStride, int firstRowStride, int secondRowStride, int thirdRowStride, in FrameMetadataParcel metadata) = 3;\n}"
  },
  {
    "path": "play-services-vision/src/main/aidl/com/google/android/gms/vision/face/internal/client/INativeFaceDetectorCreator.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.vision.face.internal.client;\n\nimport com.google.android.gms.vision.face.internal.client.DetectionOptions;\nimport com.google.android.gms.dynamic.IObjectWrapper;\nimport com.google.android.gms.vision.face.internal.client.INativeFaceDetector;\n\ninterface INativeFaceDetectorCreator {\n    INativeFaceDetector newFaceDetector(IObjectWrapper context, in DetectionOptions detectionOptions) = 0;\n}"
  },
  {
    "path": "play-services-vision/src/main/java/com/google/android/gms/vision/barcode/Barcode.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.vision.barcode;\n\nimport android.graphics.Point;\nimport android.graphics.Rect;\n\nimport androidx.annotation.Nullable;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\n\n/**\n * Barcode represents a single recognized barcode and its value.\n * <p>\n * The barcode's raw, unmodified, and uninterpreted content is returned in the {@link #rawValue} field, while the barcode type (i.e. its encoding) can be found in the {@link #format} field.\n * <p>\n * Barcodes that contain structured data (commonly done with QR codes) are parsed and iff valid, the {@link #valueFormat} field is set to one of the value format constants (e.g. {@link #GEO}) and the corresponding field is set (e.g. {@link #geoPoint}).\n */\n@PublicApi\npublic class Barcode extends AutoSafeParcelable {\n    /**\n     * Barcode value format constant for contact information.\n     * Specifies the format of a Barcode value via the {@link #valueFormat} field.\n     */\n    public static final int CONTACT_INFO = 1;\n    /**\n     * Barcode value format constant for email message details.\n     * Specifies the format of a Barcode value via the {@link #valueFormat} field.\n     */\n    public static final int EMAIL = 2;\n    /**\n     * Barcode value format constant for ISBNs.\n     * Specifies the format of a Barcode value via the {@link #valueFormat} field.\n     */\n    public static final int ISBN = 3;\n    /**\n     * Barcode value format constant for phone numbers.\n     * Specifies the format of a Barcode value via the {@link #valueFormat} field.\n     */\n    public static final int PHONE = 4;\n    /**\n     * Barcode value format constant for product codes.\n     * Specifies the format of a Barcode value via the {@link #valueFormat} field.\n     */\n    public static final int PRODUCT = 5;\n    /**\n     * Barcode value format constant for SMS details.\n     * Specifies the format of a Barcode value via the {@link #valueFormat} field.\n     */\n    public static final int SMS = 6;\n    /**\n     * Barcode value format constant for plain text.\n     * Specifies the format of a Barcode value via the {@link #valueFormat} field.\n     */\n    public static final int TEXT = 7;\n    /**\n     * Barcode value format constant for URLs/bookmarks.\n     * Specifies the format of a Barcode value via the {@link #valueFormat} field.\n     */\n    public static final int URL = 8;\n    /**\n     * Barcode value format constant for WiFi access point details.\n     * Specifies the format of a Barcode value via the {@link #valueFormat} field.\n     */\n    public static final int WIFI = 9;\n    /**\n     * Barcode value format constant for geographic coordinates.\n     * Specifies the format of a Barcode value via the {@link #valueFormat} field.\n     */\n    public static final int GEO = 10;\n    /**\n     * Barcode value format constant for calendar events.\n     * Specifies the format of a Barcode value via the {@link #valueFormat} field.\n     */\n    public static final int CALENDAR_EVENT = 11;\n    public static final int DRIVER_LICENSE = 12;\n\n    /**\n     * Barcode format constant representing the union of all supported formats.\n     * Pass into {@link BarcodeDetector.Builder#setBarcodeFormats(int)} to select formats to recognize.\n     * This is also the default setting.\n     */\n    public static final int ALL_FORMATS = 0;\n    /**\n     * Barcode format constant for Code 128.\n     * Pass into {@link BarcodeDetector.Builder#setBarcodeFormats(int)} to select formats to recognize,\n     * and also specifies a detected Barcode's {@link #format} via the format field.\n     */\n    public static final int CODE_128 = 1;\n    /**\n     * Barcode format constant for Code 39.\n     * Pass into {@link BarcodeDetector.Builder#setBarcodeFormats(int)} to select formats to recognize,\n     * and also specifies a detected Barcode's {@link #format} via the format field.\n     */\n    public static final int CODE_39 = 2;\n    /**\n     * Barcode format constant for Code 93.\n     * Pass into {@link BarcodeDetector.Builder#setBarcodeFormats(int)} to select formats to recognize,\n     * and also specifies a detected Barcode's {@link #format} via the format field.\n     */\n    public static final int CODE_93 = 4;\n    /**\n     * Barcode format constant for Codebar.\n     * Pass into {@link BarcodeDetector.Builder#setBarcodeFormats(int)} to select formats to recognize,\n     * and also specifies a detected Barcode's {@link #format} via the format field.\n     */\n    public static final int CODABAR = 8;\n    /**\n     * Barcode format constant for Data Matrix.\n     * Pass into {@link BarcodeDetector.Builder#setBarcodeFormats(int)} to select formats to recognize,\n     * and also specifies a detected Barcode's {@link #format} via the format field.\n     */\n    public static final int DATA_MATRIX = 16;\n    /**\n     * Barcode format constant for EAN-13.\n     * Pass into {@link BarcodeDetector.Builder#setBarcodeFormats(int)} to select formats to recognize,\n     * and also specifies a detected Barcode's {@link #format} via the format field.\n     */\n    public static final int EAN_13 = 32;\n    /**\n     * Barcode format constant for EAN-8.\n     * Pass into {@link BarcodeDetector.Builder#setBarcodeFormats(int)} to select formats to recognize,\n     * and also specifies a detected Barcode's {@link #format} via the format field.\n     */\n    public static final int EAN_8 = 64;\n    /**\n     * Barcode format constant for ITF (Interleaved Two-of-Five).\n     * Pass into {@link BarcodeDetector.Builder#setBarcodeFormats(int)} to select formats to recognize,\n     * and also specifies a detected Barcode's {@link #format} via the format field.\n     */\n    public static final int ITF = 128;\n    /**\n     * Barcode format constant for QR Code.\n     * Pass into {@link BarcodeDetector.Builder#setBarcodeFormats(int)} to select formats to recognize,\n     * and also specifies a detected Barcode's {@link #format} via the format field.\n     */\n    public static final int QR_CODE = 256;\n    /**\n     * Barcode format constant for UPC-A.\n     * Pass into {@link BarcodeDetector.Builder#setBarcodeFormats(int)} to select formats to recognize,\n     * and also specifies a detected Barcode's {@link #format} via the format field.\n     */\n    public static final int UPC_A = 512;\n    /**\n     * Barcode format constant for UPC-E.\n     * Pass into {@link BarcodeDetector.Builder#setBarcodeFormats(int)} to select formats to recognize,\n     * and also specifies a detected Barcode's {@link #format} via the format field.\n     */\n    public static final int UPC_E = 1024;\n    /**\n     * Barcode format constant for PDF-417.\n     * Pass into {@link BarcodeDetector.Builder#setBarcodeFormats(int)} to select formats to recognize,\n     * and also specifies a detected Barcode's {@link #format} via the format field.\n     */\n    public static final int PDF417 = 2048;\n    /**\n     * Barcode format constant for AZTEC.\n     * Pass into {@link BarcodeDetector.Builder#setBarcodeFormats(int)} to select formats to recognize,\n     * and also specifies a detected Barcode's {@link #format} via the format field.\n     */\n    public static final int AZTEC = 4096;\n\n    @Field(1)\n    private final int versionCode = 1;\n    /**\n     * Barcode format, for example {@link #EAN_13}.\n     * <p>\n     * Note that this field may contain values not present in the current set of format constants.\n     * When mapping this value to something else, it is advisable to have a default/fallback case.\n     */\n    @Field(2)\n    public int format;\n    /**\n     * Barcode value as it was encoded in the barcode. Structured values are not parsed, for example: 'MEBKM:TITLE:Google;URL://www.google.com;;' Does not include the supplement value.\n     */\n    @Field(3)\n    public String rawValue;\n    /**\n     * Barcode value in a user-friendly format.\n     * May omit some of the information encoded in the barcode.\n     * For example, in the case above the display_value might be '//www.google.com'.\n     * If {@link #valueFormat}=={@link #TEXT}, this field will be equal to {@link #rawValue}.\n     * This value may be multiline, for example, when line breaks are encoded into the original {@link #TEXT} barcode value.\n     * May include the supplement value.\n     */\n    @Field(4)\n    public String displayValue;\n    /**\n     * Format of the barcode value. For example, {@link #TEXT}, {@link #PRODUCT}, {@link #URL}, etc.\n     * <p>\n     * Note that this field may contain values not present in the current set of value format constants.\n     * When mapping this value to something else, it is advisable to have a default/fallback case.\n     */\n    @Field(5)\n    public int valueFormat;\n    /**\n     * 4 corner points in clockwise direction starting with top-left.\n     * Due to the possible perspective distortions, this is not necessarily a rectangle.\n     */\n    @Field(6)\n    public Point[] cornerPoints;\n    /**\n     * Parsed email details (set iff {@link #valueFormat} is {@link #EMAIL}).\n     */\n    @Nullable\n    @Field(7)\n    public Barcode.Email email;\n    /**\n     * Parsed phone details (set iff {@link #valueFormat} is {@link #PHONE}).\n     */\n    @Nullable\n    @Field(8)\n    public Barcode.Phone phone;\n    /**\n     * Parsed SMS details (set iff {@link #valueFormat} is {@link #SMS}).\n     */\n    @Nullable\n    @Field(9)\n    public Barcode.Sms sms;\n    /**\n     * Parsed WiFi AP details (set iff {@link #valueFormat} is {@link #WIFI}).\n     */\n    @Nullable\n    @Field(10)\n    public Barcode.WiFi wifi;\n    /**\n     * Parsed URL bookmark details (set iff {@link #valueFormat} is {@link #URL}).\n     */\n    @Nullable\n    @Field(11)\n    public Barcode.UrlBookmark url;\n    /**\n     * Parsed geo coordinates (set iff {@link #valueFormat} is {@link #GEO}).\n     */\n    @Nullable\n    @Field(12)\n    public Barcode.GeoPoint geoPoint;\n    /**\n     * Parsed calendar event details (set iff {@link #valueFormat} is {@link #CALENDAR_EVENT}).\n     */\n    @Nullable\n    @Field(13)\n    public Barcode.CalendarEvent calendarEvent;\n    /**\n     * Parsed contact details (set iff {@link #valueFormat} is {@link #CONTACT_INFO}).\n     */\n    @Nullable\n    @Field(14)\n    public Barcode.ContactInfo contactInfo;\n    /**\n     * Parsed driver's license details (set iff {@link #valueFormat} is {@link #DRIVER_LICENSE}).\n     */\n    @Nullable\n    @Field(15)\n    public Barcode.DriverLicense driverLicense;\n    /**\n     * Barcode value as it was encoded in the barcode as byte array.\n     */\n    @Field(16)\n    public byte[] rawBytes;\n    /**\n     * If outputUnrecognizedBarcodes is set, isRecognized can be set to false to indicate failure in decoding the detected barcode.\n     */\n    @Field(17)\n    public boolean isRecognized;\n\n    /**\n     * Returns the barcode's axis-aligned bounding box.\n     */\n    public Rect getBoundingBox() {\n        int left = Integer.MAX_VALUE, top = Integer.MIN_VALUE, right = Integer.MIN_VALUE, bottom = Integer.MAX_VALUE;\n        for (Point point : cornerPoints) {\n            left = Math.min(left, point.x);\n            top = Math.max(top, point.y);\n            right = Math.max(right, point.x);\n            bottom = Math.min(bottom, point.y);\n        }\n        return new Rect(left, top, right, bottom);\n    }\n\n    /**\n     * An address.\n     */\n    public static class Address extends AutoSafeParcelable {\n        /**\n         * Address type.\n         */\n        public static final int UNKNOWN = 0;\n        public static final int WORK = 1;\n        public static final int HOME = 2;\n\n        @Field(1)\n        private int versionCode = 1;\n        @Field(2)\n        public int type;\n        /**\n         * Formatted address, multiple lines when appropriate. This field always contains at least one line.\n         */\n        @Field(3)\n        public String[] addressLines;\n\n        public static Creator<Address> CREATOR = new AutoCreator<>(Address.class);\n    }\n\n    /**\n     * DateTime data type used in calendar events. If hours/minutes/seconds are not specified in the barcode value, they will be set to -1.\n     */\n    public static class CalendarDateTime extends AutoSafeParcelable {\n        @Field(1)\n        private int versionCode = 1;\n        @Field(2)\n        public int year;\n        @Field(3)\n        public int month;\n        @Field(4)\n        public int day;\n        @Field(5)\n        public int hours;\n        @Field(6)\n        public int minutes;\n        @Field(7)\n        public int seconds;\n        @Field(8)\n        public boolean isUtc;\n        @Field(9)\n        public String rawValue;\n\n        public static Creator<CalendarDateTime> CREATOR = new AutoCreator<>(CalendarDateTime.class);\n    }\n\n    /**\n     * A calendar event extracted from QRCode.\n     */\n    public static class CalendarEvent extends AutoSafeParcelable {\n        @Field(1)\n        private int versionCode = 1;\n        @Field(2)\n        public String summary;\n        @Field(3)\n        public String description;\n        @Field(4)\n        public String location;\n        @Field(5)\n        public String organizer;\n        @Field(6)\n        public String status;\n        @Field(7)\n        public Barcode.CalendarDateTime start;\n        @Field(8)\n        public Barcode.CalendarDateTime end;\n\n        public static Creator<CalendarEvent> CREATOR = new AutoCreator<>(CalendarEvent.class);\n    }\n\n    /**\n     * A person's or organization's business card. For example a VCARD.\n     */\n    public static class ContactInfo extends AutoSafeParcelable {\n        @Field(1)\n        private int versionCode = 1;\n        @Field(2)\n        public Barcode.PersonName name;\n        @Field(3)\n        public String organization;\n        @Field(4)\n        public String title;\n        @Field(5)\n        public Barcode.Phone[] phones;\n        @Field(6)\n        public Barcode.Email[] emails;\n        @Field(7)\n        public String[] urls;\n        @Field(8)\n        public Barcode.Address[] addresses;\n\n        public static Creator<ContactInfo> CREATOR = new AutoCreator<>(ContactInfo.class);\n    }\n\n    /**\n     * A driver license or ID card.\n     */\n    public static class DriverLicense extends AutoSafeParcelable {\n        @Field(1)\n        private int versionCode = 1;\n        /**\n         * \"DL\" for driver licenses, \"ID\" for ID cards.\n         */\n        @Field(2)\n        public String documentType;\n        /**\n         * Holder's first name.\n         */\n        @Field(3)\n        public String firstName;\n        @Field(4)\n        public String middleName;\n        @Field(5)\n        public String lastName;\n        /**\n         * Gender. 1 - male, 2 - female.\n         */\n        @Field(6)\n        public String gender;\n        /**\n         * Holder's street address.\n         */\n        @Field(7)\n        public String addressStreet;\n        @Field(8)\n        public String addressCity;\n        @Field(9)\n        public String addressState;\n        @Field(10)\n        public String addressZip;\n        /**\n         * Driver license ID number.\n         */\n        @Field(11)\n        public String licenseNumber;\n        /**\n         * The date format depends on the issuing country. MMDDYYYY for the US, YYYYMMDD for Canada.\n         */\n        @Field(12)\n        public String issueDate;\n        @Field(13)\n        public String expiryDate;\n        @Field(14)\n        public String birthDate;\n        /**\n         * Country in which DL/ID was issued. US = \"USA\", Canada = \"CAN\".\n         */\n        @Field(15)\n        public String issuingCountry;\n\n        public static Creator<DriverLicense> CREATOR = new AutoCreator<>(DriverLicense.class);\n    }\n\n    /**\n     * An email message from a 'MAILTO:' or similar QRCode type.\n     */\n    public static class Email extends AutoSafeParcelable {\n        /**\n         * Email type.\n         */\n        public static final int UNKNOWN = 0;\n        public static final int WORK = 1;\n        public static final int HOME = 2;\n\n        @Field(1)\n        private int versionCode = 1;\n        @Field(2)\n        public int type;\n        @Field(3)\n        public String address;\n        @Field(4)\n        public String subject;\n        @Field(5)\n        public String body;\n\n        public static Creator<Email> CREATOR = new AutoCreator<>(Email.class);\n    }\n\n    /**\n     * GPS coordinates from a 'GEO:' or similar QRCode type.\n     */\n    public static class GeoPoint extends AutoSafeParcelable {\n        @Field(1)\n        private int versionCode = 1;\n        @Field(2)\n        public double lat;\n        @Field(3)\n        public double lng;\n\n        public static Creator<GeoPoint> CREATOR = new AutoCreator<>(GeoPoint.class);\n    }\n\n    /**\n     * A person's name, both formatted version and individual name components.\n     */\n    public static class PersonName extends AutoSafeParcelable {\n        @Field(1)\n        private int versionCode = 1;\n        /**\n         * Properly formatted name.\n         */\n        @Field(2)\n        public String formattedName;\n        /**\n         * Designates a text string to be set as the kana name in the phonebook. Used for Japanese contacts.\n         */\n        @Field(3)\n        public String pronunciation;\n        @Field(4)\n        public String prefix;\n        @Field(5)\n        public String first;\n        @Field(6)\n        public String middle;\n        @Field(7)\n        public String last;\n        @Field(8)\n        public String suffix;\n\n        public static Creator<PersonName> CREATOR = new AutoCreator<>(PersonName.class);\n    }\n\n    /**\n     * A phone number from a 'TEL:' or similar QRCode type.\n     */\n    public static class Phone extends AutoSafeParcelable {\n        /**\n         * Phone type.\n         */\n        public static final int UNKNOWN = 0;\n        public static final int WORK = 1;\n        public static final int HOME = 2;\n        public static final int FAX = 3;\n        public static final int MOBILE = 4;\n\n        @Field(1)\n        private int versionCode = 1;\n        @Field(2)\n        public int type;\n        @Field(3)\n        public String number;\n\n        public static Creator<Phone> CREATOR = new AutoCreator<>(Phone.class);\n    }\n\n    /**\n     * An sms message from an 'SMS:' or similar QRCode type.\n     */\n    public static class Sms extends AutoSafeParcelable {\n        @Field(1)\n        private int versionCode = 1;\n        @Field(2)\n        public String message;\n        @Field(3)\n        public String phoneNumber;\n\n        public static Creator<Sms> CREATOR = new AutoCreator<>(Sms.class);\n    }\n\n    /**\n     * A URL and title from a 'MEBKM:' or similar QRCode type.\n     */\n    public static class UrlBookmark extends AutoSafeParcelable {\n        @Field(1)\n        private int versionCode = 1;\n        @Field(2)\n        public String title;\n        /**\n         * Bookmark URL. Note that some common errors may be corrected here. For example, \"http//...\", \"http:...\", etc. will be replaced with \"//\".\n         */\n        @Field(3)\n        public String url;\n\n        public static Creator<UrlBookmark> CREATOR = new AutoCreator<>(UrlBookmark.class);\n    }\n\n    /**\n     * A wifi network parameters from a 'WIFI:' or similar QRCode type.\n     */\n    public static class WiFi extends AutoSafeParcelable {\n        /**\n         * WiFi encryption type.\n         */\n        public static final int OPEN = 1;\n        public static final int WPA = 2;\n        public static final int WEP = 3;\n\n        @Field(1)\n        private int versionCode = 1;\n        @Field(2)\n        public String ssid;\n        @Nullable\n        @Field(3)\n        public String password;\n        @Field(4)\n        public int encryptionType;\n\n        public static Creator<WiFi> CREATOR = new AutoCreator<>(WiFi.class);\n    }\n\n    public static final Creator<Barcode> CREATOR = new AutoCreator<>(Barcode.class);\n}\n"
  },
  {
    "path": "play-services-vision/src/main/java/com/google/android/gms/vision/barcode/BarcodeDetector.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.vision.barcode;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.os.IInterface;\nimport android.os.RemoteException;\nimport android.util.SparseArray;\n\nimport com.google.android.gms.dynamic.ObjectWrapper;\nimport com.google.android.gms.vision.Detector;\nimport com.google.android.gms.vision.Frame;\nimport com.google.android.gms.vision.barcode.internal.client.BarcodeDetectorOptions;\nimport com.google.android.gms.vision.barcode.internal.client.INativeBarcodeDetector;\nimport com.google.android.gms.vision.barcode.internal.client.INativeBarcodeDetectorCreator;\nimport com.google.android.gms.vision.internal.FrameMetadataParcel;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Recognizes barcodes (in a variety of 1D and 2D formats) in a supplied {@link Frame}.\n * <p>\n * Build new BarcodeDetector instances using {@link BarcodeDetector.Builder}. By default, BarcodeDetector searches for barcodes in every supported format. For the best performance it is highly recommended that you specify a narrower set of barcode formats to detect.\n * <p>\n * Recognition results are returned by {@link #detect(Frame)} as Barcode instances.\n */\n@PublicApi\npublic class BarcodeDetector extends Detector<Barcode> {\n    private INativeBarcodeDetector remote;\n\n    private BarcodeDetector(INativeBarcodeDetector remote) {\n        this.remote = remote;\n    }\n\n    /**\n     * Recognizes barcodes in the supplied {@link Frame}.\n     *\n     * @return mapping of int to {@link Barcode}, where the int domain represents an opaque ID for the barcode. Identical barcodes (as determined by their raw value) will have the same ID across frames.\n     */\n    @Override\n    public SparseArray<Barcode> detect(Frame frame) {\n        if (frame == null) throw new IllegalArgumentException(\"No frame supplied.\");\n        SparseArray<Barcode> result = new SparseArray<>();\n        if (remote != null) {\n            FrameMetadataParcel metadataParcel = frame.getMetadata().createParcel();\n            Barcode[] barcodes = null;\n            if (frame.getBitmap() != null) {\n                try {\n                    barcodes = remote.detectBitmap(ObjectWrapper.wrap(frame.getBitmap()), metadataParcel);\n                } catch (RemoteException e) {\n                    // Ignore\n                }\n            } else {\n                try {\n                    barcodes = remote.detectBytes(ObjectWrapper.wrap(frame.getGrayscaleImageData()), metadataParcel);\n                } catch (RemoteException e) {\n                    // Ignore\n                }\n            }\n            if (barcodes != null) {\n                for (Barcode barcode : barcodes) {\n                    result.append(barcode.rawValue.hashCode(), barcode);\n                }\n            }\n        }\n\n        return result;\n    }\n\n    @Override\n    public boolean isOperational() {\n        return remote != null && super.isOperational();\n    }\n\n    @Override\n    public void release() {\n        super.release();\n        try {\n            remote.close();\n        } catch (RemoteException e) {\n            // Ignore\n        }\n        remote = null;\n    }\n\n    /**\n     * Barcode detector builder.\n     */\n    public static class Builder {\n        private Context context;\n        private BarcodeDetectorOptions options = new BarcodeDetectorOptions();\n\n        /**\n         * Builder for BarcodeDetector.\n         */\n        public Builder(Context context) {\n            this.context = context;\n        }\n\n        /**\n         * Bit mask (containing values like {@link Barcode#QR_CODE} and so on) that selects which formats this barcode detector should recognize.\n         * <p>\n         * By default, the detector will recognize all supported formats. This corresponds to the special {@link Barcode#ALL_FORMATS} constant.\n         */\n        public Builder setBarcodeFormats(int formats) {\n            options.formats = formats;\n            return this;\n        }\n\n        /**\n         * Builds a barcode detector instance using the provided settings. If the underlying native implementation is unavailable (e.g. hasn't been downloaded yet), the detector will always return an empty result set. In this case, it will report that it is non-operational via {@link BarcodeDetector#isOperational()}.\n         * <p>\n         * Note that this method may cause blocking disk reads and should not be called on an application's main thread. To avoid blocking the main thread, consider moving Detector construction to a background thread using {@link android.os.AsyncTask}. Enable {@link android.os.StrictMode} to automatically detect blocking operations on the main thread.\n         *\n         * @return new {@link BarcodeDetector} instance\n         */\n        public BarcodeDetector build() {\n            // TODO: Actually implement dynamite or load from remote\n            INativeBarcodeDetector remote = null;\n            try {\n                Class<?> clazz = Class.forName(\"com.google.android.gms.vision.barcode.ChimeraNativeBarcodeDetectorCreator\");\n                Object instance = clazz.getConstructor().newInstance();\n                INativeBarcodeDetectorCreator creator = INativeBarcodeDetectorCreator.Stub.asInterface(((IInterface) instance).asBinder());\n                remote = creator.create(ObjectWrapper.wrap(context), options);\n            } catch (Exception e) {\n                // Ignore\n            }\n            return new BarcodeDetector(remote);\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-vision/src/main/java/com/google/android/gms/vision/barcode/internal/client/BarcodeDetectorOptions.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.vision.barcode.internal.client;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class BarcodeDetectorOptions extends AutoSafeParcelable {\n    @Field(1)\n    public int versionCode = 1;\n    @Field(2)\n    public int formats;\n\n    public static Creator<BarcodeDetectorOptions> CREATOR = new AutoCreator<>(BarcodeDetectorOptions.class);\n}\n"
  },
  {
    "path": "play-services-vision/src/main/java/com/google/android/gms/vision/face/Contour.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.vision.face;\n\nimport android.graphics.PointF;\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\nimport java.util.List;\n\n@SafeParcelable.Class\npublic class Contour extends AbstractSafeParcelable {\n\n    @Field(1)\n    public int type;\n    @Field(2)\n    public List<PointF> points;\n\n    @Constructor\n    public Contour(@Param(1) int type, @Param(2) List<PointF> points) {\n        this.type = type;\n        this.points = points;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<Contour> CREATOR = findCreator(Contour.class);\n\n}\n"
  },
  {
    "path": "play-services-vision/src/main/java/com/google/android/gms/vision/face/Landmark.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.vision.face;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class Landmark extends AbstractSafeParcelable {\n\n    @Field(1)\n    public int id;\n    @Field(2)\n    public Float x;\n    @Field(3)\n    public Float y;\n    @Field(4)\n    public int type;\n\n    @Constructor\n    public Landmark(@Param(1) int id, @Param(2) Float x, @Param(3) Float y, @Param(4) int type) {\n        this.id = id;\n        this.x = x;\n        this.y = y;\n        this.type = type;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<Landmark> CREATOR = findCreator(Landmark.class);\n\n}\n"
  },
  {
    "path": "play-services-vision/src/main/java/com/google/android/gms/vision/face/internal/client/DetectionOptions.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.vision.face.internal.client;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\n\n@SafeParcelable.Class\npublic class DetectionOptions extends AbstractSafeParcelable {\n\n    @Field(2)\n    public int mode;\n    @Field(3)\n    public int landmarkType;\n    @Field(4)\n    public int classificationType;\n    @Field(5)\n    public boolean prominentFaceOnly;\n    @Field(6)\n    public boolean trackingEnabled;\n    @Field(7)\n    public float minFaceSize;\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<DetectionOptions> CREATOR = findCreator(DetectionOptions.class);\n}\n"
  },
  {
    "path": "play-services-vision/src/main/java/com/google/android/gms/vision/face/internal/client/FaceParcel.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.vision.face.internal.client;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelable;\nimport com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;\nimport com.google.android.gms.vision.face.Contour;\nimport com.google.android.gms.vision.face.Landmark;\n\n@SafeParcelable.Class\npublic class FaceParcel extends AbstractSafeParcelable {\n\n    @Field(value = 1, defaultValue = \"1\")\n    public final int versionCode;\n    @Field(2)\n    public final int id;\n    @Field(3)\n    public final float centerX;\n    @Field(4)\n    public final float centerY;\n    @Field(5)\n    public final float width;\n    @Field(6)\n    public final float height;\n    @Field(7)\n    public final float eulerY;\n    @Field(8)\n    public final float eulerZ;\n    @Field(14)\n    public final float eulerX;\n    @Field(9)\n    public final Landmark[] landmarks;\n    @Field(10)\n    public final float leftEyeOpenProbability;\n    @Field(11)\n    public final float rightEyeOpenProbability;\n    @Field(12)\n    public final float smileProbability;\n    @Field(13)\n    public final Contour[] contours;\n    @Field(value = 15, defaultValue = \"-1.0f\")\n    public final float confidenceScore;\n\n    @Constructor\n    public FaceParcel(@Param(1) int versionCode, @Param(2) int id, @Param(3) float centerX, @Param(4) float centerY, @Param(5) float width, @Param(6) float height, @Param(7) float eulerY, @Param(8) float eulerZ, @Param(14) float eulerX, @Param(9) Landmark[] landmarks, @Param(10) float leftEyeOpenProbability, @Param(11) float rightEyeOpenProbability, @Param(12) float smileProbability, @Param(13) Contour[] contours, @Param(15) float confidenceScore) {\n        this.versionCode = versionCode;\n        this.id = id;\n        this.centerX = centerX;\n        this.centerY = centerY;\n        this.width = width;\n        this.height = height;\n        this.eulerY = eulerY;\n        this.eulerZ = eulerZ;\n        this.eulerX = eulerX;\n        this.landmarks = landmarks;\n        this.leftEyeOpenProbability = leftEyeOpenProbability;\n        this.rightEyeOpenProbability = rightEyeOpenProbability;\n        this.smileProbability = smileProbability;\n        this.contours = contours;\n        this.confidenceScore = confidenceScore;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        CREATOR.writeToParcel(this, dest, flags);\n    }\n\n    public static final SafeParcelableCreatorAndWriter<FaceParcel> CREATOR = findCreator(FaceParcel.class);\n}\n"
  },
  {
    "path": "play-services-vision-common/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\nandroid {\n    namespace \"com.google.android.gms.vision_common\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n}\n\napply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG implementation of play-services-vision-common'\n\ndependencies {\n    // Dependencies from play-services-vision-common:19.1.3\n    api project(':play-services-base')\n    api project(':play-services-basement')\n    api project(':play-services-clearcut')\n    //api project(':play-services-flags')\n    api project(':play-services-phenotype')\n}\n"
  },
  {
    "path": "play-services-vision-common/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2020, microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<manifest />\n"
  },
  {
    "path": "play-services-vision-common/src/main/aidl/com/google/android/gms/vision/internal/FrameMetadataParcel.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.vision.internal;\n\nparcelable FrameMetadataParcel;\n"
  },
  {
    "path": "play-services-vision-common/src/main/java/com/google/android/gms/vision/CameraSource.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.vision;\n\nimport android.content.Context;\nimport android.graphics.ImageFormat;\nimport android.graphics.SurfaceTexture;\nimport android.hardware.Camera;\nimport android.os.SystemClock;\nimport android.view.Surface;\nimport android.view.SurfaceHolder;\nimport android.view.WindowManager;\n\nimport androidx.annotation.GuardedBy;\n\nimport com.google.android.gms.common.images.Size;\n\nimport org.microg.gms.common.PublicApi;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.util.ArrayList;\n\n/**\n * Manages the camera in conjunction with an underlying {@link Detector}. This receives preview frames from the camera\n * at a specified rate, sending those frames to the detector as fast as it is able to process those frames.\n * <p>\n * This camera source makes a best effort to manage processing on preview frames as fast as possible, while at the same\n * time minimizing lag. As such, frames may be dropped if the detector is unable to keep up with the rate of frames\n * generated by the camera. You should use {@link CameraSource.Builder#setRequestedFps(float)} to specify a frame rate\n * that works well with the capabilities of the camera hardware and the detector options that you have selected.\n * If CPU utilization is higher than you'd like, then you may want to consider reducing FPS.\n * If the camera preview or detector results are too \"jerky\", then you may want to consider increasing FPS.\n * <p>\n * The following Android permission is required to use the camera:\n * <ul>\n * <li>android.permissions.CAMERA</li>\n * </ul>\n */\n@PublicApi\npublic class CameraSource {\n    public static final int CAMERA_FACING_BACK = 0;\n    public static final int CAMERA_FACING_FRONT = 1;\n\n    private final Object cameraLock = new Object();\n    @GuardedBy(\"cameraLock\")\n    private Camera camera;\n    private Context context;\n    private int facing = CAMERA_FACING_BACK;\n    private boolean autoFocusEnabled;\n    private String focusMode;\n    private float requestedFps = 30;\n    private int requestedWidth = 1024;\n    private int requestedHeight = 768;\n    private Size previewSize;\n    private int rotation;\n    private Thread detectorThread;\n    private DetectorRunner detectorRunner = new DetectorRunner();\n    private Detector<?> detector;\n\n    /**\n     * Returns the selected camera; one of {@link #CAMERA_FACING_BACK} or {@link #CAMERA_FACING_FRONT}.\n     */\n    public int getCameraFacing() {\n        return facing;\n    }\n\n    /**\n     * Returns the preview size that is currently in use by the underlying camera.\n     */\n    public Size getPreviewSize() {\n        return previewSize;\n    }\n\n    /**\n     * Stops the camera and releases the resources of the camera and underlying detector.\n     */\n    public void release() {\n        synchronized (cameraLock) {\n            stop();\n            if (detector != null) detector.release();\n        }\n    }\n\n    /**\n     * Opens the camera and starts sending preview frames to the underlying detector. The preview frames are not displayed.\n     *\n     * @throws IOException if the camera's preview texture or display could not be initialized\n     */\n    public CameraSource start() throws IOException {\n        synchronized (cameraLock) {\n            if (camera == null) {\n                camera = createCamera();\n                camera.setPreviewTexture(new SurfaceTexture(100));\n                camera.startPreview();\n                startDetectorThread();\n            }\n            return this;\n        }\n    }\n\n    /**\n     * Opens the camera and starts sending preview frames to the underlying detector.\n     * The supplied surface holder is used for the preview so frames can be displayed to the user.\n     *\n     * @param surfaceHolder the surface holder to use for the preview frames\n     * @throws IOException if the supplied surface holder could not be used as the preview display\n     */\n    public CameraSource start(SurfaceHolder surfaceHolder) throws IOException {\n        synchronized (cameraLock) {\n            if (camera == null) {\n                camera = createCamera();\n                camera.setPreviewDisplay(surfaceHolder);\n                camera.startPreview();\n                startDetectorThread();\n            }\n            return this;\n        }\n    }\n\n    /**\n     * Closes the camera and stops sending frames to the underlying frame detector.\n     * <p>\n     * This camera source may be restarted again by calling {@link #start()} or {@link #start(SurfaceHolder)}.\n     * <p>\n     * Call {@link #release()} instead to completely shut down this camera source and release the resources of the underlying detector.\n     */\n    public void stop() {\n        synchronized (cameraLock) {\n            detectorRunner.setActive(false);\n            if (detectorThread != null) {\n                try {\n                    detectorThread.join();\n                } catch (InterruptedException e) {\n                    // Ignore\n                }\n                detectorThread = null;\n            }\n            if (camera != null) {\n                camera.stopPreview();\n                camera.setPreviewCallbackWithBuffer(null);\n                try {\n                    camera.setPreviewTexture(null);\n                } catch (IOException e) {\n                    // Ignore\n                }\n                try {\n                    camera.setPreviewDisplay(null);\n                } catch (IOException e) {\n                    // Ignore\n                }\n                camera.release();\n                camera = null;\n            }\n        }\n    }\n\n    /**\n     * Initiates taking a picture, which happens asynchronously.\n     * The camera source should have been activated previously with {@link #start()} or {@link #start(SurfaceHolder)}.\n     * The camera preview is suspended while the picture is being taken, but will resume once picture taking is done.\n     *\n     * @param shutter the callback for image capture moment, or null\n     * @param jpeg    the callback for JPEG image data, or null\n     */\n    public void takePicture(CameraSource.ShutterCallback shutter, CameraSource.PictureCallback jpeg) {\n        synchronized (this.cameraLock) {\n            if (camera != null) {\n                camera.takePicture(shutter::onShutter, null, null, (data, camera) -> jpeg.onPictureTaken(data));\n            }\n        }\n    }\n\n    /**\n     * Builder for configuring and creating an associated camera source.\n     */\n    public static class Builder {\n        private CameraSource cameraSource = new CameraSource();\n\n        /**\n         * Creates a camera source builder with the supplied context and detector.\n         * Camera preview images will be streamed to the associated detector upon starting the camera source.\n         */\n        public Builder(Context context, Detector<?> detector) {\n            if (context == null) throw new IllegalArgumentException(\"No context supplied.\");\n            if (detector == null) throw new IllegalArgumentException(\"No detector supplied.\");\n            this.cameraSource.context = context;\n            this.cameraSource.detector = detector;\n        }\n\n        /**\n         * Creates an instance of the camera source.\n         */\n        public CameraSource build() {\n            return cameraSource;\n        }\n\n        /**\n         * Sets whether to enable camera auto focus. If set to false (default), the camera's default focus setting is used. If set to true, a continuous video focus setting is used (if supported by the camera hardware).\n         * Default: false.\n         */\n        public Builder setAutoFocusEnabled(boolean autoFocusEnabled) {\n            this.cameraSource.autoFocusEnabled = autoFocusEnabled;\n            return this;\n        }\n\n        /**\n         * Sets the camera to use (either {@link CameraSource#CAMERA_FACING_BACK} or {@link CameraSource#CAMERA_FACING_FRONT}).\n         * Default: back facing.\n         */\n        public Builder setFacing(int facing) {\n            this.cameraSource.facing = facing;\n            return this;\n        }\n\n        /**\n         * Sets which FocusMode will be used for camera focus. Only FOCUS_MODE_CONTINUOUS_PICTURE and FOCUS_MODE_CONTINUOUS_VIDEO are supported for now.\n         */\n        public Builder setFocusMode(String focusMode) {\n            this.cameraSource.focusMode = focusMode;\n            return this;\n        }\n\n        /**\n         * Sets the requested frame rate in frames per second. If the exact requested value is not not available, the best matching available value is selected.\n         * Default: 30.\n         */\n        public Builder setRequestedFps(float fps) {\n            this.cameraSource.requestedFps = fps;\n            return this;\n        }\n\n        /**\n         * Sets the desired width and height of the camera frames in pixels. If the exact desired values are not available options, the best matching available options are selected. Also, we try to select a preview size which corresponds to the aspect ratio of an associated full picture size, if applicable.\n         * Default: 1024x768.\n         */\n        public Builder setRequestedPreviewSize(int width, int height) {\n            this.cameraSource.requestedWidth = width;\n            this.cameraSource.requestedHeight = height;\n            return this;\n        }\n    }\n\n    /**\n     * Callback interface used to supply image data from a photo capture.\n     */\n    public interface PictureCallback {\n        /**\n         * Called when image data is available after a picture is taken. The format of the data is a jpeg binary.\n         */\n        void onPictureTaken(byte[] data);\n    }\n\n    /**\n     * Callback interface used to signal the moment of actual image capture.\n     */\n    public interface ShutterCallback {\n        /**\n         * Called as near as possible to the moment when a photo is captured from the sensor. This is a good opportunity to play a shutter sound or give other feedback of camera operation. This may be some time after the photo was triggered, but some time before the actual data is available.\n         */\n        void onShutter();\n    }\n\n    private void startDetectorThread() {\n        if (detectorThread != null && detectorThread.isAlive()) return;\n        detectorThread = new Thread(detectorRunner);\n        detectorThread.setName(\"gms.vision.CameraSource\");\n        detectorRunner.setActive(true);\n        detectorThread.start();\n    }\n\n    private Camera createCamera() throws IOException {\n        int cameraId = getFacingCameraId();\n        Camera camera = Camera.open(cameraId);\n        try {\n            Camera.Parameters parameters = camera.getParameters();\n\n            // Set size\n            SizePair size = pickCameraSize(camera);\n            previewSize = size.preview;\n            parameters.setPreviewSize(previewSize.getWidth(), previewSize.getHeight());\n            if (size.picture != null) {\n                parameters.setPictureSize(size.picture.getWidth(), size.picture.getHeight());\n            }\n\n            // Set FPS\n            int[] fpsRange = pickFpsRange(camera);\n            parameters.setPreviewFpsRange(fpsRange[0], fpsRange[1]);\n\n            // Set focus mode\n            if (autoFocusEnabled && (focusMode == null || !parameters.getSupportedFocusModes().contains(focusMode))) {\n                if (parameters.getSupportedFocusModes().contains(\"continuous-video\")) {\n                    focusMode = \"continuous-video\";\n                } else {\n                    focusMode = null;\n                }\n            }\n            if (focusMode != null && parameters.getSupportedFocusModes().contains(focusMode)) {\n                parameters.setFocusMode(focusMode);\n            }\n\n            // Handle rotation\n            WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);\n            int displayRotation = 0;\n            switch (windowManager.getDefaultDisplay().getRotation()) {\n                case Surface.ROTATION_90: displayRotation = 90; break;\n                case Surface.ROTATION_180: displayRotation = 180; break;\n                case Surface.ROTATION_270: displayRotation = 270; break;\n            }\n            Camera.CameraInfo cameraInfo = new Camera.CameraInfo();\n            Camera.getCameraInfo(cameraId, cameraInfo);\n            if (facing == CAMERA_FACING_FRONT) {\n                rotation = ((cameraInfo.orientation + displayRotation) % 360) / 90;\n                camera.setDisplayOrientation((360 - (cameraInfo.orientation + displayRotation)) % 360);\n            } else {\n                rotation = ((cameraInfo.orientation - displayRotation + 360) % 360) / 90;\n                camera.setDisplayOrientation((cameraInfo.orientation - displayRotation + 360) % 360);\n            }\n\n            parameters.setRotation(rotation * 90);\n            parameters.setPreviewFormat(ImageFormat.NV21);\n            camera.setParameters(parameters);\n\n            // Add processing\n            camera.setPreviewCallbackWithBuffer(new Camera.PreviewCallback() {\n                @Override\n                public void onPreviewFrame(byte[] data, Camera frameCamera) {\n                    detectorRunner.onPreviewFrame(data, frameCamera);\n                }\n            });\n            camera.addCallbackBuffer(new byte[(int) Math.ceil((double) ((long) (previewSize.getHeight() * previewSize.getWidth() * ImageFormat.getBitsPerPixel(parameters.getPreviewFormat()))) / 8.0D) + 1]);\n\n            return camera;\n        } catch (Exception e) {\n            camera.release();\n            throw e;\n        }\n    }\n\n    private int getFacingCameraId() throws IOException {\n        Camera.CameraInfo info = new Camera.CameraInfo();\n        for (int i = 0; i < Camera.getNumberOfCameras(); i++) {\n            Camera.getCameraInfo(i, info);\n            if (info.facing == facing) {\n                return i;\n            }\n        }\n        throw new IOException(\"Could not find requested camera.\");\n    }\n\n    private int[] pickFpsRange(Camera camera) throws IOException {\n        int requestsFpms = (int) (requestedFps * 1000.0F);\n        int[] selectedFpsRange = null;\n        int selectedPreviewFpsOffset = Integer.MAX_VALUE;\n\n        for (int[] previewFpsRange : camera.getParameters().getSupportedPreviewFpsRange()) {\n            int minOffset = requestsFpms - previewFpsRange[0];\n            int maxOffset = requestsFpms - previewFpsRange[1];\n            int previewFpsOffset;\n            if ((previewFpsOffset = Math.abs(minOffset) + Math.abs(maxOffset)) < selectedPreviewFpsOffset) {\n                selectedFpsRange = previewFpsRange;\n                selectedPreviewFpsOffset = previewFpsOffset;\n            }\n        }\n        if (selectedFpsRange == null) throw new IOException(\"Could not find suitable preview frames per second range.\");\n        return selectedFpsRange;\n    }\n\n    private SizePair pickCameraSize(Camera camera) throws IOException {\n        ArrayList<SizePair> sizeCandidates = new ArrayList<>();\n        for (Camera.Size previewSize : camera.getParameters().getSupportedPreviewSizes()) {\n            float previewAspectRatio = (float) (previewSize).width / (float) previewSize.height;\n            for (Camera.Size pictureSize : camera.getParameters().getSupportedPictureSizes()) {\n                float pictureAspectRatio = (float) (pictureSize).width / (float) pictureSize.height;\n                if (Math.abs(previewAspectRatio - pictureAspectRatio) < 0.01F) { // Approximately same aspect ratio\n                    sizeCandidates.add(new SizePair(previewSize, pictureSize));\n                    break;\n                }\n            }\n        }\n        if (sizeCandidates.size() == 0) {\n            for (Camera.Size previewSize : camera.getParameters().getSupportedPreviewSizes()) {\n                sizeCandidates.add(new SizePair(previewSize, null));\n            }\n        }\n\n        SizePair sizePair = null;\n        int selectedSizeOffset = Integer.MAX_VALUE;\n        int sizeOffset;\n        for (SizePair candidate : sizeCandidates) {\n            Size candidatePreviewSize = candidate.preview;\n            sizeOffset = Math.abs(candidatePreviewSize.getWidth() - requestedWidth) + Math.abs(candidatePreviewSize.getHeight() - requestedHeight);\n            if (sizeOffset < selectedSizeOffset) {\n                sizePair = candidate;\n                selectedSizeOffset = sizeOffset;\n            }\n        }\n\n        if (sizePair == null) throw new IOException(\"Could not find suitable preview size.\");\n        return sizePair;\n    }\n\n    private static class SizePair {\n        Size preview;\n        Size picture;\n\n        public SizePair(Camera.Size preview, Camera.Size picture) {\n            this.preview = new Size(preview.width, preview.height);\n            if (picture != null) {\n                this.picture = new Size(picture.width, picture.height);\n            }\n        }\n    }\n\n    private class DetectorRunner implements Runnable {\n        private final Object lock = new Object();\n        private long startElapsedRealtime = SystemClock.elapsedRealtime();\n        private long timestampMillis;\n        private byte[] frameData;\n        private ByteBuffer frameBuffer;\n        private ByteBuffer frameDataBuffer;\n        private int frameId = 0;\n        private boolean active;\n\n        public void setActive(boolean active) {\n            synchronized (lock) {\n                this.active = active;\n                lock.notifyAll();\n            }\n        }\n\n        @Override\n        public void run() {\n            while (true) {\n                Frame frame;\n                synchronized (lock) {\n                    while (active && frameBuffer == null) {\n                        try {\n                            lock.wait();\n                        } catch (InterruptedException e) {\n                            return;\n                        }\n                    }\n\n                    if (!active) return;\n\n                    frame = new Frame.Builder().setId(frameId).setImageData(frameBuffer, previewSize.getWidth(), previewSize.getHeight(), ImageFormat.NV21).setTimestampMillis(timestampMillis).setRotation(rotation).build();\n                    frameBuffer = null;\n                }\n                try {\n                    detector.receiveFrame(frame);\n                } catch (Exception e) {\n                    // Ignore\n                } finally {\n                    camera.addCallbackBuffer(frameData);\n                }\n            }\n        }\n\n        public void onPreviewFrame(byte[] data, Camera camera) {\n            synchronized (lock) {\n                if (frameData == null) {\n                    frameData = data;\n                    frameDataBuffer = ByteBuffer.wrap(data);\n                }\n                if (data == frameData) {\n                    frameId++;\n                    timestampMillis = SystemClock.elapsedRealtime();\n                    frameBuffer = frameDataBuffer;\n                    lock.notifyAll();\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-vision-common/src/main/java/com/google/android/gms/vision/Detector.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.vision;\n\nimport android.util.SparseArray;\n\nimport androidx.annotation.GuardedBy;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Detector is the base class for implementing specific detector instances, such as a barcode detector or face detector. A detector receives a Frame as input, and produces a number of detected items as output. The Detector implementation is generic, parameterized by T, the type of the detected items.\n */\n@PublicApi\npublic abstract class Detector<T> {\n    private final Object processorLock = new Object();\n    @GuardedBy(\"processorLock\")\n    private Processor<T> processor;\n\n    /**\n     * Analyzes the supplied frame to find target item instances (e.g., the face detector finds faces). Subclasses implement this method for calling specific detection code, returning result objects with associated tracking ID mappings.\n     *\n     * @return mapping of int to detected object, where the int domain represents the ID of the associated item. If tracking is enabled, as the same object is detected in consecutive frames, the detector will return the same ID for that item.\n     */\n    public abstract SparseArray<T> detect(Frame frame);\n\n    /**\n     * Indicates whether the detector has all of the required dependencies available locally in order to do detection.\n     * <p>\n     * When an app is first installed, it may be necessary to download required files. If this returns false, those files are not yet available. Usually this download is taken care of at application install time, but this is not guaranteed. In some cases the download may have been delayed.\n     * <p>\n     * If your code has added a processor, an indication of the detector operational state is also indicated with the {@link Detector.Detections#detectorIsOperational()} method. You can check this in your app as it processes detection results, and can convey this state to the user if appropriate.\n     *\n     * @return true if the detector is operational, false if the dependency download is in progress\n     */\n    public boolean isOperational() {\n        return true;\n    }\n\n    /**\n     * Pipeline method (see class level documentation above) for receiving frames for detection. Detection results are forwarded onto a processor that was previously registered with this class (see {@link #setProcessor(Detector.Processor)}).\n     * <p>\n     * Alternatively, if you are just looking to synchronously run the detector on a single frame, use {@link #detect(Frame)} instead.\n     */\n    public void receiveFrame(Frame frame) {\n        Detections<T> detections = new Detections<>(detect(frame), frame.getMetadata().withRotationAppliedToSize(), isOperational());\n        synchronized (processorLock) {\n            if (processor == null) {\n                throw new IllegalStateException(\"Detector processor must first be set with setProcessor in order to receive detection results.\");\n            } else {\n                processor.receiveDetections(detections);\n            }\n        }\n    }\n\n    /**\n     * Shuts down the detector, releasing any underlying resources.\n     */\n    public void release() {\n        synchronized (processorLock) {\n            if (processor != null) {\n                processor.release();\n                processor = null;\n            }\n        }\n    }\n\n    /**\n     * Sets the ID of the detected item in which to exclusively track in future use of the detector. This can be used to avoid unnecessary work in detecting all items in future frames, when it's only necessary to receive results for a specific item. After setting this ID, the detector may only return results for the associated tracked item. When that item is no longer present in a frame, the detector will revert back to detecting all items.\n     * <p>\n     * Optionally, subclasses may override this to support optimized tracking.\n     *\n     * @param id tracking ID to become the focus for future detections. This is a mapping ID as returned from {@link #detect(Frame)} or received from {@link Detector.Detections#getDetectedItems()}.\n     */\n    public boolean setFocus(int id) {\n        return true;\n    }\n\n    /**\n     * Pipeline method (see class level documentation above) which sets the {@link Detector.Processor} instance.\n     * This is used in creating the pipeline structure, associating a post-processor with the detector.\n     */\n    public void setProcessor(Processor<T> processor) {\n        synchronized (processorLock) {\n            if (this.processor != null) {\n                this.processor.release();\n            }\n            this.processor = processor;\n        }\n    }\n\n    /**\n     * Detection result object containing both detected items and the associated frame metadata.\n     */\n    public static class Detections<T> {\n        private final SparseArray<T> detectedItems;\n        private final Frame.Metadata frameMetadata;\n        private final boolean isOperational;\n\n        @PublicApi(exclude = true)\n        public Detections(SparseArray<T> detectedItems, Frame.Metadata frameMetadata, boolean isOperational) {\n            this.isOperational = isOperational;\n            this.detectedItems = detectedItems;\n            this.frameMetadata = frameMetadata;\n        }\n\n        /**\n         * Returns true if the detector is operational, false if it is not operational. In the non-operational case, the detector will return no results.\n         * <p>\n         * A detector may be non-operational for a while when starting an app for the first time, if a download is required to obtain the associated library and model files required to do detection.\n         */\n        public boolean detectorIsOperational() {\n            return isOperational;\n        }\n\n        /**\n         * Returns a collection of the detected items that were identified in the frame.\n         *\n         * @return mapping of int to detected object, where the int domain represents the consistent tracking ID of the associated item. As the same object is detected in consecutive frames, the detector will return the same ID for that item.\n         */\n        public SparseArray<T> getDetectedItems() {\n            return detectedItems;\n        }\n\n        /**\n         * Returns the metadata of the associated frame in which the detection originated.\n         */\n        public Frame.Metadata getFrameMetadata() {\n            return frameMetadata;\n        }\n    }\n\n    /**\n     * Interface for defining a post-processing action to be executed for each detection, when using the detector as part of a pipeline (see the class level docs above). An instance of a processor is associated with the detector via the {@link Detector#setProcessor(Detector.Processor)} method.\n     */\n    public interface Processor<T> {\n        /**\n         * Called by the detector to deliver detection results to the processor.\n         */\n        void receiveDetections(Detections<T> detections);\n\n        /**\n         * Shuts down and releases associated processor resources.\n         */\n        void release();\n    }\n}\n"
  },
  {
    "path": "play-services-vision-common/src/main/java/com/google/android/gms/vision/Frame.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.google.android.gms.vision;\n\nimport android.graphics.Bitmap;\nimport android.graphics.Color;\nimport android.graphics.ImageFormat;\nimport android.view.Display;\n\nimport com.google.android.gms.vision.internal.FrameMetadataParcel;\n\nimport org.microg.gms.common.PublicApi;\n\nimport java.nio.ByteBuffer;\n\n/**\n * Image data with associated {@link Metadata}.\n * <p>\n * A frame is constructed via the {@link Builder} class, specifying the image data, dimensions, and sequencing information (frame ID, timestamp).\n */\npublic class Frame {\n    public static final int ROTATION_0 = 0;\n    public static final int ROTATION_90 = 1;\n    public static final int ROTATION_180 = 2;\n    public static final int ROTATION_270 = 3;\n\n    private Bitmap bitmap;\n    private ByteBuffer imageData;\n    private final Metadata metadata = new Metadata();\n\n    /**\n     * Returns the bitmap which was specified in creating this frame, or null if no bitmap was used to create this frame. If the bitmap is not available, then {@link #getGrayscaleImageData()} should be called instead.\n     */\n    public Bitmap getBitmap() {\n        return bitmap;\n    }\n\n    /**\n     * Returns the grayscale version of the frame data, with one byte per pixel. Note that the returned byte buffer will be prefixed by the Y channel (i.e., the grayscale image data), but may optionally include additional image data beyond the Y channel (this can be ignored).\n     * <p>\n     * If a bitmap was specified when creating this frame, the bitmap is first converted to a grayscale byte[] (allocation / copy required). It is recommended that you use the bitmap directly through {@link #getBitmap()} if the associated native detection code supports it, since this would move the grayscale conversion into native code where it will be faster.\n     */\n    public ByteBuffer getGrayscaleImageData() {\n        if (bitmap == null) {\n            return imageData;\n        }\n        int width = metadata.width;\n        int height = metadata.height;\n        int[] pixels = new int[width * height];\n        bitmap.getPixels(pixels, 0, width, 0, 0, width, height);\n        byte[] values = new byte[width * height];\n\n        for (int i = 0; i < pixels.length; i++) {\n            values[i] = (byte)((int)((float) Color.red(pixels[i]) * 0.299F + (float)Color.green(pixels[i]) * 0.587F + (float)Color.blue(pixels[i]) * 0.114F));\n        }\n\n        return ByteBuffer.wrap(values);\n    }\n\n    /**\n     * Returns the metadata associated with the frame.\n     */\n    public Frame.Metadata getMetadata() {\n        return metadata;\n    }\n\n    /**\n     * Builder for creating a frame instance.\n     * At a minimum, image information must be specified either through {@link #setBitmap(Bitmap)} or {@link #setImageData(ByteBuffer, int, int, int)}.\n     */\n    public static class Builder {\n        private final Frame frame = new Frame();\n\n        /**\n         * Creates the frame instance.\n         *\n         * @throws IllegalStateException if the image data has not been set via {@link #setBitmap(Bitmap)} or {@link #setImageData(ByteBuffer, int, int, int)}.\n         */\n        public Frame build() {\n            if (this.frame.bitmap == null && this.frame.imageData == null) {\n                throw new IllegalStateException(\"Missing image data.  Call either setBitmap or setImageData to specify the image\");\n            }\n            return frame;\n        }\n\n        /**\n         * Sets the image data for the frame from a supplied bitmap.\n         * <p>\n         * While this is a convenient way to specify certain images (e.g., images read from a file), note that a copy is required to extract pixel information for use in detectors -- this could mean extra GC overhead. Using {@link #setImageData(ByteBuffer, int, int, int)} is the preferred way to specify image data if you can handle the data in a supported byte format and reuse the byte buffer, since it does not require a making a copy.\n         */\n        public Builder setBitmap(Bitmap bitmap) {\n            this.frame.bitmap = bitmap;\n            this.frame.metadata.width = bitmap.getWidth();\n            this.frame.metadata.height = bitmap.getHeight();\n            return this;\n        }\n\n        /**\n         * Sets the frame ID. A frame source such as a live video camera or a video player is expected to assign IDs in monotonically increasing order, to indicate the sequence that the frame appeared relative to other frames.\n         * <p>\n         * A {@link Detector.Processor} implementation may rely upon this sequence ID to detect frame sequence gaps, to compute velocity, etc.\n         */\n        public Builder setId(int id) {\n            this.frame.metadata.id = id;\n            return this;\n        }\n\n        /**\n         * Sets the image data from the supplied byte buffer, size, and format.\n         *\n         * @param data   contains image byte data according to the associated format.\n         * @param width\n         * @param height\n         * @param format one of {@link ImageFormat#NV16}, {@link ImageFormat#NV21}, or {@link ImageFormat#YV12}.\n         * @throws IllegalArgumentException if the supplied data is null, or an invalid image format was supplied.\n         */\n        public Builder setImageData(ByteBuffer data, int width, int height, int format) {\n            if (data == null) throw new IllegalArgumentException(\"Null image data supplied\");\n            if (data.capacity() < width * height) throw new IllegalArgumentException(\"Invalid image data size\");\n            if (format != ImageFormat.NV16 && format != ImageFormat.NV21 && format != ImageFormat.YV12)\n                throw new IllegalArgumentException(\"Unsupported image format: \" + format);\n            this.frame.imageData = data;\n            this.frame.metadata.width = width;\n            this.frame.metadata.height = height;\n            this.frame.metadata.format = format;\n            return this;\n        }\n\n        /**\n         * Sets the image rotation, indicating the rotation from the upright orientation.\n         * <p>\n         * Since the camera may deliver images that are rotated (e.g., if the user holds the device upside down), specifying the rotation with the image indicates how to make the image be upright, if necessary. Some detectors may rely upon rotating the image before attempting detection, whereas others may not. In preserving the original image from the camera along with this value, the detector may choose whether to make this correction (and to assume the associated cost).\n         * <p>\n         * However, note that the detector is expected to report detection position coordinates that are relative to the upright version of the image (whether or not the image was actually rotated by the detector). The {@link Detector} will always deliver frame metadata to the {@link Detector.Processor} that indicates the dimensions and orientation of an unrotated, upright frame.\n         *\n         * @param rotation one of {@link Frame#ROTATION_0}, {@link Frame#ROTATION_90}, {@link Frame#ROTATION_180}, {@link Frame#ROTATION_270}. Has the same meaning as {@link Display#getRotation()}.\n         */\n        public Builder setRotation(int rotation) {\n            this.frame.metadata.rotation = rotation;\n            return this;\n        }\n\n        /**\n         * Sets the frame timestamp, in milliseconds. A frame source such as a live video camera or a video player is expected to assign timestamps in a way that makes sense for the medium. For example, live video may use the capture time of each frame, whereas a video player may use the elapsed time to the frame within the video. Timestamps should be in monotonically increasing order, to indicate the passage of time.\n         * <p>\n         * A {@link Detector.Processor} implementation may rely upon this sequence ID to detect frame sequence gaps, to compute velocity, etc.\n         */\n        public Builder setTimestampMillis(long timestampMillis) {\n            this.frame.metadata.timestampMillis = timestampMillis;\n            return this;\n        }\n    }\n\n    /**\n     * Frame metadata, describing the image dimensions, rotation, and sequencing information.\n     */\n    public static class Metadata {\n        private int format = -1;\n        private int height;\n        private int id;\n        private int rotation;\n        private long timestampMillis;\n        private int width;\n\n        public Metadata() {\n        }\n\n        private Metadata(Metadata metadata) {\n            this.format = metadata.format;\n            this.height = metadata.height;\n            this.id = metadata.id;\n            this.rotation = metadata.rotation;\n            this.timestampMillis = metadata.timestampMillis;\n            this.width = metadata.width;\n        }\n\n        /**\n         * Returns the format of this image if image data is set.\n         *\n         * @return one of {@link ImageFormat#NV16}, {@link ImageFormat#NV21, {@link ImageFormat#YV12} or {@link ImageFormat#YUV_420_888}.\n         */\n        public int getFormat() {\n            return format;\n        }\n\n        /**\n         * Returns the frame height.\n         */\n        public int getHeight() {\n            return height;\n        }\n\n        /**\n         * Returns the frame ID. A frame source such as a live video camera or a video player is expected to assign IDs in monotonically increasing order, to indicate the sequence that the frame appeared relative to other frames.\n         */\n        public int getId() {\n            return id;\n        }\n\n        /**\n         * Returns the image rotation, indicating the counter-clockwise rotation from the upright orientation. Has the same meaning as in {@link Display#getRotation()}.\n         * <p>\n         * Since the camera may deliver images that are rotated (e.g., if the user holds the device upside down), specifying the rotation with the image indicates how to make the image be upright, if necessary. Some detectors may rely upon rotating the image before attempting detection, whereas others may not. In preserving the original image from the camera along with this value, the detector may choose whether to make this correction (and to assume the associated cost).\n         * <p>\n         * However, note that the detector is expected to report detection position coordinates that are relative to the upright version of the image (whether or not the image was actually rotated by the detector). The {@link Detector} will always deliver frame metadata to the {@link Detector.Processor} that indicates the dimensions and orientation of an unrotated, upright frame.\n         *\n         * @return one of {@link Frame#ROTATION_0}, {@link Frame#ROTATION_90}, {@link Frame#ROTATION_180}, {@link Frame#ROTATION_270}.\n         */\n        public int getRotation() {\n            return rotation;\n        }\n\n        /**\n         * Returns the timestamp, in milliseconds.\n         * <p>\n         * A frame source such as a live video camera or a video player is expected to assign timestamps in a way that makes sense for the medium. For example, live video may use the capture time of each frame, whereas a video player may use the elapsed time to the frame within the video. Timestamps should be in monotonically increasing order, to indicate the passage of time.\n         */\n        public long getTimestampMillis() {\n            return timestampMillis;\n        }\n\n        /**\n         * Returns the frame width.\n         */\n        public int getWidth() {\n            return width;\n        }\n\n        @PublicApi(exclude = true)\n        public FrameMetadataParcel createParcel() {\n            FrameMetadataParcel parcel = new FrameMetadataParcel();\n            parcel.width = width;\n            parcel.height = height;\n            parcel.id = id;\n            parcel.timestampMillis = timestampMillis;\n            parcel.rotation = rotation;\n            return parcel;\n        }\n\n        @PublicApi(exclude = true)\n        public Metadata withRotationAppliedToSize() {\n            Metadata metadata = new Metadata(this);\n            if (metadata.rotation % 2 != 0) {\n                metadata.width = height;\n                metadata.height = width;\n            }\n            metadata.rotation = 0;\n            return metadata;\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-vision-common/src/main/java/com/google/android/gms/vision/internal/FrameMetadataParcel.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2020, microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.gms.vision.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class FrameMetadataParcel extends AutoSafeParcelable {\n    @Field(1)\n    private final int versionCode = 1;\n    @Field(2)\n    public int width;\n    @Field(3)\n    public int height;\n    @Field(4)\n    public int id;\n    @Field(5)\n    public long timestampMillis;\n    @Field(6)\n    public int rotation;\n\n    public static Creator<FrameMetadataParcel> CREATOR = new AutoCreator<>(FrameMetadataParcel.class);\n}\n"
  },
  {
    "path": "play-services-wearable/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2015 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'com.squareup.wire'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\nandroid {\n    namespace \"com.google.android.gms.wearable\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    buildFeatures {\n        aidl = true\n    }\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n\n    lintOptions {\n        disable 'InvalidPackage'\n    }\n}\n\nwire {\n    java {\n\n    }\n}\n\napply from: '../gradle/publish-android.gradle'\n\ndescription = 'microG implementation of play-services-wearable'\n\ndependencies {\n    implementation \"com.squareup.wire:wire-runtime:$wireVersion\"\n\n    // Dependencies from play-services-wearable:17.1.0\n    api \"androidx.core:core:1.0.0\"\n    api project(':play-services-base')\n    api project(':play-services-basement')\n    api project(':play-services-tasks')\n}\n"
  },
  {
    "path": "play-services-wearable/core/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.library'\napply plugin: 'kotlin-android'\napply plugin: 'maven-publish'\napply plugin: 'signing'\n\ndependencies {\n    implementation project(':play-services-base-core')\n\n    implementation project(':play-services-location')\n    implementation project(':play-services-wearable')\n\n    implementation \"org.microg:wearable:$wearableVersion\"\n}\n\nandroid {\n    namespace \"org.microg.gms.wearable.core\"\n\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    defaultConfig {\n        versionName version\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n    }\n\n    buildFeatures {\n        dataBinding = true\n    }\n\n    sourceSets {\n        main.java.srcDirs += 'src/main/kotlin'\n    }\n\n    lintOptions {\n        disable 'MissingTranslation'\n    }\n\n    compileOptions {\n        sourceCompatibility = 1.8\n        targetCompatibility = 1.8\n    }\n\n    kotlinOptions {\n        jvmTarget = 1.8\n    }\n}\n\napply from: '../../gradle/publish-android.gradle'\n\ndescription = 'microG service implementation for play-services-wearable'\n"
  },
  {
    "path": "play-services-wearable/core/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2022 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <application>\n    </application>\n</manifest>\n"
  },
  {
    "path": "play-services-wearable/core/src/main/java/org/microg/gms/wearable/CapabilityManager.java",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 org.microg.gms.wearable;\n\nimport android.content.Context;\nimport android.net.Uri;\n\nimport com.google.android.gms.common.api.CommonStatusCodes;\nimport com.google.android.gms.common.data.DataHolder;\nimport com.google.android.gms.wearable.Node;\nimport com.google.android.gms.wearable.WearableStatusCodes;\nimport com.google.android.gms.wearable.internal.NodeParcelable;\n\nimport org.microg.gms.common.PackageUtils;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\npublic class CapabilityManager {\n    private static final Uri ROOT = Uri.parse(\"wear:/capabilities/\");\n    private final Context context;\n    private final WearableImpl wearable;\n    private final String packageName;\n\n    private Set<String> capabilities = new HashSet<String>();\n\n    public CapabilityManager(Context context, WearableImpl wearable, String packageName) {\n        this.context = context;\n        this.wearable = wearable;\n        this.packageName = packageName;\n    }\n\n    private Uri buildCapabilityUri(String capability, boolean withAuthority) {\n        Uri.Builder builder = ROOT.buildUpon();\n        if (withAuthority) builder.authority(wearable.getLocalNodeId());\n        builder.appendPath(packageName);\n        builder.appendPath(PackageUtils.firstSignatureDigest(context, packageName));\n        builder.appendPath(Uri.encode(capability));\n        return builder.build();\n    }\n\n    public Set<String> getNodesForCapability(String capability) {\n        DataHolder dataHolder = wearable.getDataItemsByUriAsHolder(buildCapabilityUri(capability, false), packageName);\n        Set<String> nodes = new HashSet<>();\n        for (int i = 0; i < dataHolder.getCount(); i++) {\n            nodes.add(dataHolder.getString(\"host\", i, 0));\n        }\n        dataHolder.close();\n        return nodes;\n    }\n\n    public int add(String capability) {\n        if (this.capabilities.contains(capability)) {\n            return WearableStatusCodes.DUPLICATE_CAPABILITY;\n        }\n        DataItemInternal dataItem = new DataItemInternal(buildCapabilityUri(capability, true));\n        DataItemRecord record = wearable.putDataItem(packageName, PackageUtils.firstSignatureDigest(context, packageName), wearable.getLocalNodeId(), dataItem);\n        this.capabilities.add(capability);\n        wearable.syncRecordToAll(record);\n        return CommonStatusCodes.SUCCESS;\n    }\n\n    public int remove(String capability) {\n        if (!this.capabilities.contains(capability)) {\n            return WearableStatusCodes.UNKNOWN_CAPABILITY;\n        }\n        wearable.deleteDataItems(buildCapabilityUri(capability, true), packageName);\n        capabilities.remove(capability);\n        return CommonStatusCodes.SUCCESS;\n    }\n}\n"
  },
  {
    "path": "play-services-wearable/core/src/main/java/org/microg/gms/wearable/ClockworkNodePreferences.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.wearable;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\n\nimport java.util.UUID;\n\npublic class ClockworkNodePreferences {\n\n    private static final String CLOCKWORK_NODE_PREFERENCES = \"cw_node\";\n    private static final String CLOCKWORK_NODE_PREFERENCE_NODE_ID = \"node_id\";\n    private static final String CLOCKWORK_NODE_PREFERENCE_NEXT_SEQ_ID_BLOCK = \"nextSeqIdBlock\";\n\n    private static final Object lock = new Object();\n    private static long seqIdBlock;\n    private static long seqIdInBlock = -1;\n\n    private Context context;\n\n    public ClockworkNodePreferences(Context context) {\n        this.context = context;\n    }\n\n    public String getLocalNodeId() {\n        SharedPreferences preferences = context.getSharedPreferences(CLOCKWORK_NODE_PREFERENCES, Context.MODE_PRIVATE);\n        String nodeId = preferences.getString(CLOCKWORK_NODE_PREFERENCE_NODE_ID, null);\n        if (nodeId == null) {\n            nodeId = UUID.randomUUID().toString();\n            preferences.edit().putString(CLOCKWORK_NODE_PREFERENCE_NODE_ID, nodeId).apply();\n        }\n        return nodeId;\n    }\n\n    public long getNextSeqId() {\n        synchronized (lock) {\n            SharedPreferences preferences = context.getSharedPreferences(CLOCKWORK_NODE_PREFERENCES, Context.MODE_PRIVATE);\n            if (seqIdInBlock < 0) seqIdInBlock = 1000;\n            if (seqIdInBlock >= 1000) {\n                seqIdBlock = preferences.getLong(CLOCKWORK_NODE_PREFERENCE_NEXT_SEQ_ID_BLOCK, 100);\n                preferences.edit().putLong(CLOCKWORK_NODE_PREFERENCE_NEXT_SEQ_ID_BLOCK, seqIdBlock + seqIdInBlock).apply();\n                seqIdInBlock = 0;\n            }\n            return seqIdBlock + seqIdInBlock++;\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-wearable/core/src/main/java/org/microg/gms/wearable/ConfigurationDatabaseHelper.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.wearable;\n\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.database.sqlite.SQLiteDatabase;\nimport android.database.sqlite.SQLiteOpenHelper;\n\nimport com.google.android.gms.wearable.ConnectionConfiguration;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Random;\n\npublic class ConfigurationDatabaseHelper extends SQLiteOpenHelper {\n\n    public static final String NULL_STRING = \"NULL_STRING\";\n    public static final String TABLE_NAME = \"connectionConfigurations\";\n    public static final String BY_NAME = \"name=?\";\n\n    public ConfigurationDatabaseHelper(Context context) {\n        super(context, \"connectionconfig.db\", null, 2);\n    }\n\n    @Override\n    public void onCreate(SQLiteDatabase db) {\n        db.execSQL(\"CREATE TABLE connectionConfigurations (_id INTEGER PRIMARY KEY AUTOINCREMENT,androidId TEXT,name TEXT NOT NULL,pairedBtAddress TEXT NOT NULL,connectionType INTEGER NOT NULL,role INTEGER NOT NULL,connectionEnabled INTEGER NOT NULL,nodeId TEXT, UNIQUE(name) ON CONFLICT REPLACE);\");\n    }\n\n    @Override\n    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {\n\n    }\n\n    private static ConnectionConfiguration configFromCursor(final Cursor cursor) {\n        String name = cursor.getString(cursor.getColumnIndexOrThrow(\"name\"));\n        String pairedBtAddress = cursor.getString(cursor.getColumnIndexOrThrow(\"pairedBtAddress\"));\n        int connectionType = cursor.getInt(cursor.getColumnIndexOrThrow(\"connectionType\"));\n        int role = cursor.getInt(cursor.getColumnIndexOrThrow(\"role\"));\n        int enabled = cursor.getInt(cursor.getColumnIndexOrThrow(\"connectionEnabled\"));\n        String nodeId = cursor.getString(cursor.getColumnIndexOrThrow(\"nodeId\"));\n        if (NULL_STRING.equals(name)) name = null;\n        if (NULL_STRING.equals(pairedBtAddress)) pairedBtAddress = null;\n        return new ConnectionConfiguration(name, pairedBtAddress, connectionType, role, enabled > 0, nodeId);\n    }\n\n    public ConnectionConfiguration getConfiguration(String name) {\n        Cursor cursor = getReadableDatabase().query(TABLE_NAME, null, BY_NAME, new String[]{name}, null, null, null);\n        ConnectionConfiguration config = null;\n        if (cursor != null) {\n            if (cursor.moveToNext())\n                config = configFromCursor(cursor);\n            cursor.close();\n        }\n        return config;\n    }\n\n    public void putConfiguration(ConnectionConfiguration config) {\n        putConfiguration(config, null);\n    }\n\n    public void putConfiguration(ConnectionConfiguration config, String oldNodeId) {\n        ContentValues contentValues = new ContentValues();\n        if (config.name != null) {\n            contentValues.put(\"name\", config.name);\n        } else if (config.role == 2) {\n            contentValues.put(\"name\", \"server\");\n        } else {\n            contentValues.put(\"name\", \"NULL_STRING\");\n        }\n        if (config.address != null) {\n            contentValues.put(\"pairedBtAddress\", config.address);\n        } else {\n            contentValues.put(\"pairedBtAddress\", \"NULL_STRING\");\n        }\n        contentValues.put(\"connectionType\", config.type);\n        contentValues.put(\"role\", config.role);\n        contentValues.put(\"connectionEnabled\", true);\n        contentValues.put(\"nodeId\", config.nodeId);\n        if (oldNodeId == null) {\n            getWritableDatabase().insert(TABLE_NAME, null, contentValues);\n        } else {\n            getWritableDatabase().update(TABLE_NAME, contentValues, \"nodeId=?\", new String[]{oldNodeId});\n        }\n    }\n\n    public ConnectionConfiguration[] getAllConfigurations() {\n        Cursor cursor = getReadableDatabase().query(TABLE_NAME, null, null, null, null, null, null);\n        if (cursor != null) {\n            List<ConnectionConfiguration> configurations = new ArrayList<ConnectionConfiguration>();\n            while (cursor.moveToNext()) {\n                configurations.add(configFromCursor(cursor));\n            }\n            cursor.close();\n            return configurations.toArray(new ConnectionConfiguration[configurations.size()]);\n        } else {\n            return null;\n        }\n    }\n\n    public void setEnabledState(String name, boolean enabled) {\n        getWritableDatabase().execSQL(\"UPDATE connectionConfigurations SET connectionEnabled=? WHERE name=?\", new String[]{enabled ? \"1\" : \"0\", name});\n    }\n\n    public int deleteConfiguration(String name) {\n        return getWritableDatabase().delete(TABLE_NAME, BY_NAME, new String[]{name});\n    }\n}\n"
  },
  {
    "path": "play-services-wearable/core/src/main/java/org/microg/gms/wearable/DataItemInternal.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.wearable;\n\nimport android.net.Uri;\n\nimport com.google.android.gms.wearable.Asset;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class DataItemInternal {\n    public final String host;\n    public final String path;\n    public final Uri uri;\n    public byte[] data;\n    private Map<String, Asset> assets = new HashMap<String, Asset>();\n\n    public DataItemInternal(String host, String path) {\n        this.host = host;\n        this.path = path;\n        this.uri = new Uri.Builder().scheme(\"wear\").authority(host).path(path).build();\n    }\n\n    public DataItemInternal(Uri uri) {\n        this.uri = uri;\n        this.host = uri.getAuthority();\n        this.path = uri.getPath();\n    }\n\n    public DataItemInternal addAsset(String key, Asset asset) {\n        this.assets.put(key, asset);\n        return this;\n    }\n\n    public Map<String, Asset> getAssets() {\n        return Collections.unmodifiableMap(new HashMap<String, Asset>(assets));\n    }\n\n    @Override\n    public String toString() {\n        final StringBuilder sb = new StringBuilder(\"DataItemInternal{\");\n        sb.append(\"uri=\").append(uri);\n        sb.append(\", assets=\").append(assets.size());\n        sb.append('}');\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "play-services-wearable/core/src/main/java/org/microg/gms/wearable/DataItemRecord.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.wearable;\n\nimport android.content.ContentValues;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.util.Log;\n\nimport com.google.android.gms.common.data.DataHolder;\nimport com.google.android.gms.wearable.Asset;\nimport com.google.android.gms.wearable.internal.DataItemAssetParcelable;\nimport com.google.android.gms.wearable.internal.DataItemParcelable;\n\nimport org.microg.wearable.proto.AssetEntry;\nimport org.microg.wearable.proto.SetDataItem;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport okio.ByteString;\n\npublic class DataItemRecord {\n    private static String[] EVENT_DATA_HOLDER_FIELDS = new String[] { \"event_type\", \"path\", \"data\", \"tags\", \"asset_key\", \"asset_id\" };\n\n    public DataItemInternal dataItem;\n    public String source;\n    public long seqId;\n    public long v1SeqId;\n    public long lastModified;\n    public boolean deleted;\n    public boolean assetsAreReady;\n    public String packageName;\n    public String signatureDigest;\n\n    public ContentValues toContentValues() {\n        ContentValues contentValues = new ContentValues();\n        contentValues.put(\"sourceNode\", source);\n        contentValues.put(\"seqId\", seqId);\n        contentValues.put(\"v1SourceNode\", source);\n        contentValues.put(\"v1SeqId\", v1SeqId);\n        contentValues.put(\"timestampMs\", lastModified);\n        if (deleted) {\n            contentValues.put(\"deleted\", 1);\n            contentValues.putNull(\"data\");\n        } else {\n            contentValues.put(\"deleted\", 0);\n            contentValues.put(\"data\", dataItem.data);\n        }\n        contentValues.put(\"assetsPresent\", assetsAreReady ? 1 : 0);\n        return contentValues;\n    }\n\n    public DataHolder toEventDataHolder() {\n        DataHolder.Builder builder = DataHolder.builder(EVENT_DATA_HOLDER_FIELDS);\n        HashMap<String, Object> data = new HashMap<String, Object>();\n        data.put(\"path\", dataItem.uri.toString());\n        if (deleted) {\n            data.put(\"event_type\", 2);\n            builder.withRow(data);\n        } else {\n            data.put(\"event_type\", 1);\n            data.put(\"data\", dataItem.data);\n            data.put(\"tags\", \"\");\n            boolean added = false;\n            for (Map.Entry<String, Asset> entry : dataItem.getAssets().entrySet()) {\n                added = true;\n                data.put(\"asset_id\", entry.getValue().getDigest());\n                data.put(\"asset_key\", entry.getKey());\n                builder.withRow(data);\n                data = new HashMap<String, Object>();\n                data.put(\"path\", dataItem.uri.toString());\n            }\n            if (!added) {\n                builder.withRow(data);\n            }\n        }\n        return builder.build(0);\n    }\n\n    public DataItemParcelable toParcelable() {\n        Map<String, DataItemAssetParcelable> assets = new HashMap<>();\n        for (Map.Entry<String, Asset> entry : dataItem.getAssets().entrySet()) {\n            assets.put(entry.getKey(), new DataItemAssetParcelable(entry.getValue().getDigest(), entry.getKey()));\n        }\n        DataItemParcelable parcelable = new DataItemParcelable(dataItem.uri, assets);\n        parcelable.data = dataItem.data;\n        return parcelable;\n    }\n\n    public SetDataItem toSetDataItem() {\n        SetDataItem.Builder builder = new SetDataItem.Builder()\n                .packageName(packageName)\n                .signatureDigest(signatureDigest)\n                .uri(dataItem.uri.toString())\n                .seqId(seqId)\n                .deleted(deleted)\n                .lastModified(lastModified);\n        if (source != null) builder.source(source);\n        if (dataItem.data != null) builder.data(ByteString.of(dataItem.data));\n        List<AssetEntry> protoAssets = new ArrayList<AssetEntry>();\n        Map<String, Asset> assets = dataItem.getAssets();\n        for (String key : assets.keySet()) {\n            protoAssets.add(new AssetEntry.Builder()\n                    .key(key)\n                    .unknown3(4)\n                    .value(new org.microg.wearable.proto.Asset.Builder()\n                            .digest(assets.get(key).getDigest())\n                            .build()).build());\n        }\n        builder.assets(protoAssets);\n        return builder.build();\n    }\n\n    public static DataItemRecord fromCursor(Cursor cursor) {\n        DataItemRecord record = new DataItemRecord();\n        record.packageName = cursor.getString(1);\n        record.signatureDigest = cursor.getString(2);\n        record.dataItem = new DataItemInternal(cursor.getString(3), cursor.getString(4));\n        record.seqId = cursor.getLong(5);\n        record.deleted = cursor.getLong(6) > 0;\n        record.source = cursor.getString(7);\n        record.dataItem.data = cursor.getBlob(8);\n        record.lastModified = cursor.getLong(9);\n        record.assetsAreReady = cursor.getLong(10) > 0;\n        if (cursor.getString(11) != null) {\n            record.dataItem.addAsset(cursor.getString(11), Asset.createFromRef(cursor.getString(12)));\n            while (cursor.moveToNext()) {\n                if (cursor.getLong(5) == record.seqId) {\n                    record.dataItem.addAsset(cursor.getString(11), Asset.createFromRef(cursor.getString(12)));\n                }\n            }\n            cursor.moveToPrevious();\n        }\n        return record;\n    }\n\n    public static DataItemRecord fromSetDataItem(SetDataItem setDataItem) {\n        DataItemRecord record = new DataItemRecord();\n        record.dataItem = new DataItemInternal(Uri.parse(setDataItem.uri));\n        if (setDataItem.data != null) record.dataItem.data = setDataItem.data.toByteArray();\n        if (setDataItem.assets != null) {\n            for (AssetEntry asset : setDataItem.assets) {\n                record.dataItem.addAsset(asset.key, Asset.createFromRef(asset.value.digest));\n            }\n        }\n        record.source = setDataItem.source;\n        record.seqId = setDataItem.seqId;\n        record.v1SeqId = -1;\n        record.lastModified = setDataItem.lastModified;\n        record.deleted = setDataItem.deleted == null ? false : setDataItem.deleted;\n        record.packageName = setDataItem.packageName;\n        record.signatureDigest = setDataItem.signatureDigest;\n        return record;\n    }\n\n    @Override\n    public String toString() {\n        final StringBuilder sb = new StringBuilder(\"DataItemRecord{\");\n        sb.append(\"dataItem=\").append(dataItem);\n        sb.append(\", source='\").append(source).append('\\'');\n        sb.append(\", seqId=\").append(seqId);\n        sb.append(\", v1SeqId=\").append(v1SeqId);\n        sb.append(\", lastModified=\").append(lastModified);\n        sb.append(\", deleted=\").append(deleted);\n        sb.append(\", assetsAreReady=\").append(assetsAreReady);\n        sb.append(\", packageName='\").append(packageName).append('\\'');\n        sb.append(\", signatureDigest='\").append(signatureDigest).append('\\'');\n        sb.append('}');\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "play-services-wearable/core/src/main/java/org/microg/gms/wearable/MessageHandler.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.wearable;\n\nimport android.content.Context;\nimport android.text.TextUtils;\nimport android.util.Log;\n\nimport com.google.android.gms.wearable.Asset;\nimport com.google.android.gms.wearable.ConnectionConfiguration;\nimport com.google.android.gms.wearable.internal.MessageEventParcelable;\n\nimport org.microg.gms.profile.Build;\nimport org.microg.gms.settings.SettingsContract;\nimport org.microg.wearable.ServerMessageListener;\nimport org.microg.wearable.proto.AckAsset;\nimport org.microg.wearable.proto.Connect;\nimport org.microg.wearable.proto.FetchAsset;\nimport org.microg.wearable.proto.FilePiece;\nimport org.microg.wearable.proto.Heartbeat;\nimport org.microg.wearable.proto.Request;\nimport org.microg.wearable.proto.RootMessage;\nimport org.microg.wearable.proto.SetAsset;\nimport org.microg.wearable.proto.SetDataItem;\nimport org.microg.wearable.proto.SyncStart;\nimport org.microg.wearable.proto.SyncTableEntry;\n\nimport java.io.IOException;\nimport java.util.Arrays;\n\npublic class MessageHandler extends ServerMessageListener {\n    private static final String TAG = \"GmsWearMsgHandler\";\n    private final WearableImpl wearable;\n    private final String oldConfigNodeId;\n    private String peerNodeId;\n\n    public MessageHandler(Context context, WearableImpl wearable, ConnectionConfiguration config) {\n        this(wearable, config, Build.MODEL, config.nodeId, SettingsContract.getSettings(context, SettingsContract.CheckIn.INSTANCE.getContentUri(context), new String[]{SettingsContract.CheckIn.ANDROID_ID}, cursor -> cursor.getLong(0)));\n    }\n\n    private MessageHandler(WearableImpl wearable, ConnectionConfiguration config, String name, String networkId, long androidId) {\n        super(new Connect.Builder()\n                .name(name)\n                .id(wearable.getLocalNodeId())\n                .networkId(networkId)\n                .peerAndroidId(androidId)\n                .unknown4(3)\n                .peerVersion(1)\n                .build());\n        this.wearable = wearable;\n        this.oldConfigNodeId = config.nodeId;\n    }\n\n    @Override\n    public void onConnect(Connect connect) {\n        super.onConnect(connect);\n        peerNodeId = connect.id;\n        wearable.onConnectReceived(getConnection(), oldConfigNodeId, connect);\n        try {\n            getConnection().writeMessage(new RootMessage.Builder().syncStart(new SyncStart.Builder()\n                    .receivedSeqId(-1L)\n                    .version(2)\n                    .syncTable(Arrays.asList(\n                            new SyncTableEntry.Builder().key(\"cloud\").value(1L).build(),\n                            new SyncTableEntry.Builder().key(wearable.getLocalNodeId()).value(wearable.getCurrentSeqId(wearable.getLocalNodeId())).build(), // TODO\n                            new SyncTableEntry.Builder().key(peerNodeId).value(wearable.getCurrentSeqId(peerNodeId)).build() // TODO\n                    )).build()).build());\n        } catch (IOException e) {\n            Log.w(TAG, e);\n        }\n    }\n\n    @Override\n    public void onDisconnected() {\n        Connect connect = getRemoteConnect();\n        if (connect == null)\n            connect = new Connect.Builder().id(oldConfigNodeId).name(\"Wear device\").build();\n        wearable.onDisconnectReceived(getConnection(), connect);\n        super.onDisconnected();\n    }\n\n    @Override\n    public void onSetAsset(SetAsset setAsset) {\n        Log.d(TAG, \"onSetAsset: \" + setAsset);\n        Asset asset;\n        if (setAsset.data != null) {\n            asset = Asset.createFromBytes(setAsset.data.toByteArray());\n        } else {\n            asset = Asset.createFromRef(setAsset.digest);\n        }\n        wearable.addAssetToDatabase(asset, setAsset.appkeys.appKeys);\n    }\n\n    @Override\n    public void onAckAsset(AckAsset ackAsset) {\n        Log.d(TAG, \"onAckAsset: \" + ackAsset);\n    }\n\n    @Override\n    public void onFetchAsset(FetchAsset fetchAsset) {\n        Log.d(TAG, \"onFetchAsset: \" + fetchAsset);\n    }\n\n    @Override\n    public void onSyncStart(SyncStart syncStart) {\n        Log.d(TAG, \"onSyncStart: \" + syncStart);\n        if (syncStart.version < 2) {\n            Log.d(TAG, \"Sync uses version \" + syncStart.version + \" which is not supported (yet)\");\n        }\n        boolean hasLocalNode = false;\n        if (syncStart.syncTable != null) {\n            for (SyncTableEntry entry : syncStart.syncTable) {\n                wearable.syncToPeer(peerNodeId, entry.key, entry.value);\n                if (wearable.getLocalNodeId().equals(entry.key)) hasLocalNode = true;\n            }\n        } else {\n            Log.d(TAG, \"No sync table given.\");\n        }\n        if (!hasLocalNode) wearable.syncToPeer(peerNodeId, wearable.getLocalNodeId(), 0);\n    }\n\n    @Override\n    public void onSetDataItem(SetDataItem setDataItem) {\n        Log.d(TAG, \"onSetDataItem: \" + setDataItem);\n        wearable.putDataItem(DataItemRecord.fromSetDataItem(setDataItem));\n    }\n\n    @Override\n    public void onRpcRequest(Request rpcRequest) {\n        Log.d(TAG, \"onRpcRequest: \" + rpcRequest);\n        if (TextUtils.isEmpty(rpcRequest.targetNodeId) || rpcRequest.targetNodeId.equals(wearable.getLocalNodeId())) {\n            MessageEventParcelable messageEvent = new MessageEventParcelable();\n            messageEvent.data = rpcRequest.rawData != null ? rpcRequest.rawData.toByteArray() : null;\n            messageEvent.path = rpcRequest.path;\n            messageEvent.requestId = rpcRequest.requestId + 31 * (rpcRequest.generation + 527);\n            messageEvent.sourceNodeId = TextUtils.isEmpty(rpcRequest.sourceNodeId) ? peerNodeId : rpcRequest.sourceNodeId;\n\n            wearable.sendMessageReceived(rpcRequest.packageName, messageEvent);\n        } else if (rpcRequest.targetNodeId.equals(peerNodeId)) {\n            // Drop it\n        } else {\n            // TODO: find next hop\n        }\n        try {\n            getConnection().writeMessage(new RootMessage.Builder().heartbeat(new Heartbeat()).build());\n        } catch (IOException e) {\n            onDisconnected();\n        }\n    }\n\n    @Override\n    public void onHeartbeat(Heartbeat heartbeat) {\n        Log.d(TAG, \"onHeartbeat: \" + heartbeat);\n    }\n\n    @Override\n    public void onFilePiece(FilePiece filePiece) {\n        Log.d(TAG, \"onFilePiece: \" + filePiece);\n        wearable.handleFilePiece(getConnection(), filePiece.fileName, filePiece.piece.toByteArray(), filePiece.finalPiece ? filePiece.digest : null);\n    }\n\n    @Override\n    public void onChannelRequest(Request channelRequest) {\n        Log.d(TAG, \"onChannelRequest:\" + channelRequest);\n    }\n}\n"
  },
  {
    "path": "play-services-wearable/core/src/main/java/org/microg/gms/wearable/NodeDatabaseHelper.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.wearable;\n\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.database.sqlite.SQLiteDatabase;\nimport android.database.sqlite.SQLiteOpenHelper;\nimport android.text.TextUtils;\nimport android.util.Log;\n\nimport com.google.android.gms.wearable.Asset;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\npublic class NodeDatabaseHelper extends SQLiteOpenHelper {\n    private static final String TAG = \"GmsWearNodeDB\";\n\n    private static final String DB_NAME = \"node.db\";\n    private static final String[] GDIBHAP_FIELDS = new String[]{\"dataitems_id\", \"packageName\", \"signatureDigest\", \"host\", \"path\", \"seqId\", \"deleted\", \"sourceNode\", \"data\", \"timestampMs\", \"assetsPresent\", \"assetname\", \"assets_digest\", \"v1SourceNode\", \"v1SeqId\"};\n    private static final int VERSION = 9;\n\n    private ClockworkNodePreferences clockworkNodePreferences;\n\n    public NodeDatabaseHelper(Context context) {\n        super(context, DB_NAME, null, VERSION);\n        clockworkNodePreferences = new ClockworkNodePreferences(context);\n    }\n\n    @Override\n    public void onCreate(SQLiteDatabase db) {\n        db.execSQL(\"CREATE TABLE appkeys(_id INTEGER PRIMARY KEY AUTOINCREMENT,packageName TEXT NOT NULL,signatureDigest TEXT NOT NULL);\");\n        db.execSQL(\"CREATE TABLE dataitems(_id INTEGER PRIMARY KEY AUTOINCREMENT, appkeys_id INTEGER NOT NULL REFERENCES appkeys(_id), host TEXT NOT NULL, path TEXT NOT NULL, seqId INTEGER NOT NULL, deleted INTEGER NOT NULL, sourceNode TEXT NOT NULL, data BLOB, timestampMs INTEGER NOT NULL, assetsPresent INTEGER NOT NULL, v1SourceNode TEXT NOT NULL, v1SeqId INTEGER NOT NULL);\");\n        db.execSQL(\"CREATE TABLE assets(digest TEXT PRIMARY KEY, dataPresent INTEGER NOT NULL DEFAULT 0, timestampMs INTEGER NOT NULL);\");\n        db.execSQL(\"CREATE TABLE assetrefs(assetname TEXT NOT NULL, dataitems_id INTEGER NOT NULL REFERENCES dataitems(_id), assets_digest TEXT NOT NULL REFERENCES assets(digest));\");\n        db.execSQL(\"CREATE TABLE assetsacls(appkeys_id INTEGER NOT NULL REFERENCES appkeys(_id), assets_digest TEXT NOT NULL);\");\n        db.execSQL(\"CREATE TABLE nodeinfo(node TEXT NOT NULL PRIMARY KEY, seqId INTEGER, lastActivityMs INTEGER);\");\n        db.execSQL(\"CREATE VIEW appKeyDataItems AS SELECT appkeys._id AS appkeys_id, appkeys.packageName AS packageName, appkeys.signatureDigest AS signatureDigest, dataitems._id AS dataitems_id, dataitems.host AS host, dataitems.path AS path, dataitems.seqId AS seqId, dataitems.deleted AS deleted, dataitems.sourceNode AS sourceNode, dataitems.data AS data, dataitems.timestampMs AS timestampMs, dataitems.assetsPresent AS assetsPresent, dataitems.v1SourceNode AS v1SourceNode, dataitems.v1SeqId AS v1SeqId FROM appkeys, dataitems WHERE appkeys._id=dataitems.appkeys_id\");\n        db.execSQL(\"CREATE VIEW appKeyAcls AS SELECT appkeys._id AS appkeys_id, appkeys.packageName AS packageName, appkeys.signatureDigest AS signatureDigest, assetsacls.assets_digest AS assets_digest FROM appkeys, assetsacls WHERE _id=appkeys_id\");\n        db.execSQL(\"CREATE VIEW dataItemsAndAssets AS SELECT appKeyDataItems.packageName AS packageName, appKeyDataItems.signatureDigest AS signatureDigest, appKeyDataItems.dataitems_id AS dataitems_id, appKeyDataItems.host AS host, appKeyDataItems.path AS path, appKeyDataItems.seqId AS seqId, appKeyDataItems.deleted AS deleted, appKeyDataItems.sourceNode AS sourceNode, appKeyDataItems.data AS data, appKeyDataItems.timestampMs AS timestampMs, appKeyDataItems.assetsPresent AS assetsPresent, assetrefs.assetname AS assetname, assetrefs.assets_digest AS assets_digest, appKeyDataItems.v1SourceNode AS v1SourceNode, appKeyDataItems.v1SeqId AS v1SeqId FROM appKeyDataItems LEFT OUTER JOIN assetrefs ON appKeyDataItems.dataitems_id=assetrefs.dataitems_id\");\n        db.execSQL(\"CREATE VIEW assetsReadyStatus AS SELECT  dataitems_id AS dataitems_id,  COUNT(*) = SUM(dataPresent) AS nowReady,  assetsPresent AS markedReady FROM assetrefs, dataitems LEFT OUTER JOIN assets ON  assetrefs.assets_digest = assets.digest WHERE assetrefs.dataitems_id=dataitems._id GROUP BY dataitems_id;\");\n        db.execSQL(\"CREATE UNIQUE INDEX appkeys_NAME_AND_SIG ON appkeys(packageName,signatureDigest);\");\n        db.execSQL(\"CREATE UNIQUE INDEX assetrefs_ASSET_REFS ON assetrefs(assets_digest,dataitems_id,assetname);\");\n        db.execSQL(\"CREATE UNIQUE INDEX assets_DIGEST ON assets(digest);\");\n        db.execSQL(\"CREATE UNIQUE INDEX assetsacls_APPKEY_AND_DIGEST ON assetsacls(appkeys_id,assets_digest);\");\n        db.execSQL(\"CREATE UNIQUE INDEX dataitems_APPKEY_HOST_AND_PATH ON dataitems(appkeys_id,host,path);\");\n        db.execSQL(\"CREATE UNIQUE INDEX dataitems_SOURCENODE_AND_SEQID ON dataitems(sourceNode,seqId);\");\n        db.execSQL(\"CREATE UNIQUE INDEX dataitems_SOURCENODE_DELETED_AND_SEQID ON dataitems(sourceNode,deleted,seqId);\");\n    }\n\n    public synchronized Cursor getDataItemsForDataHolder(String packageName, String signatureDigest) {\n        return getDataItemsForDataHolderByHostAndPath(packageName, signatureDigest, null, null);\n    }\n\n    public synchronized Cursor getDataItemsForDataHolderByHostAndPath(String packageName, String signatureDigest, String host, String path) {\n        String[] params;\n        String selection;\n        if (path == null) {\n            params = new String[]{packageName, signatureDigest};\n            selection = \"packageName = ? AND signatureDigest = ?\";\n        } else if (TextUtils.isEmpty(host)) {\n            if (path.endsWith(\"/\")) path = path + \"%\";\n            path = path.replace(\"*\", \"%\");\n            params = new String[]{packageName, signatureDigest, path};\n            selection = \"packageName = ? AND signatureDigest = ? AND path LIKE ?\";\n        } else {\n            if (path.endsWith(\"/\")) path = path + \"%\";\n            path = path.replace(\"*\", \"%\");\n            host = host.replace(\"*\", \"%\");\n            params = new String[]{packageName, signatureDigest, host, path};\n            selection = \"packageName = ? AND signatureDigest = ? AND host = ? AND path LIKE ?\";\n        }\n        selection += \" AND deleted=0 AND assetsPresent !=0\";\n        return getReadableDatabase().rawQuery(\"SELECT host AS host,path AS path,data AS data,\\'\\' AS tags,assetname AS asset_key,assets_digest AS asset_id FROM dataItemsAndAssets WHERE \" + selection, params);\n    }\n\n    public synchronized Cursor getDataItemsByHostAndPath(String packageName, String signatureDigest, String host, String path) {\n        Log.d(TAG, \"getDataItemsByHostAndPath: \" + packageName + \", \" + signatureDigest + \", \" + host + \", \" + path);\n        return getDataItemsByHostAndPath(getReadableDatabase(), packageName, signatureDigest, host, path);\n    }\n\n    @Override\n    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {\n        if (oldVersion != VERSION) {\n            // TODO: Upgrade not supported, cleaning up\n            db.execSQL(\"DROP TABLE IF EXISTS appkeys;\");\n            db.execSQL(\"DROP TABLE IF EXISTS dataitems;\");\n            db.execSQL(\"DROP TABLE IF EXISTS assets;\");\n            db.execSQL(\"DROP TABLE IF EXISTS assetrefs;\");\n            db.execSQL(\"DROP TABLE IF EXISTS assetsacls;\");\n            db.execSQL(\"DROP TABLE IF EXISTS nodeinfo;\");\n            db.execSQL(\"DROP VIEW IF EXISTS appKeyDataItems;\");\n            db.execSQL(\"DROP VIEW IF EXISTS appKeyAcls;\");\n            db.execSQL(\"DROP VIEW IF EXISTS dataItemsAndAssets;\");\n            db.execSQL(\"DROP VIEW IF EXISTS assetsReadyStatus;\");\n            onCreate(db);\n        }\n    }\n\n    private static synchronized long getAppKey(SQLiteDatabase db, String packageName, String signatureDigest) {\n        Cursor cursor = db.rawQuery(\"SELECT _id FROM appkeys WHERE packageName=? AND signatureDigest=?\", new String[]{packageName, signatureDigest});\n        if (cursor != null) {\n            try {\n                if (cursor.moveToNext()) {\n                    return cursor.getLong(0);\n                }\n            } finally {\n                cursor.close();\n            }\n        }\n        ContentValues appKey = new ContentValues();\n        appKey.put(\"packageName\", packageName);\n        appKey.put(\"signatureDigest\", signatureDigest);\n        return db.insert(\"appkeys\", null, appKey);\n    }\n\n    public synchronized void putRecord(DataItemRecord record) {\n        SQLiteDatabase db = getWritableDatabase();\n        db.beginTransaction();\n        Cursor cursor = getDataItemsByHostAndPath(db, record.packageName, record.signatureDigest, record.dataItem.host, record.dataItem.path);\n        try {\n            String key;\n            if (cursor.moveToNext()) {\n                // update\n                key = cursor.getString(0);\n                updateRecord(db, key, record);\n            } else {\n                // insert\n                key = insertRecord(db, record);\n            }\n            if (record.assetsAreReady) {\n                ContentValues update = new ContentValues();\n                update.put(\"assetsPresent\", 1);\n                db.update(\"dataitems\", update, \"_id=?\", new String[]{key});\n            }\n            db.setTransactionSuccessful();\n        } finally {\n            cursor.close();\n        }\n        db.endTransaction();\n    }\n\n    private static void updateRecord(SQLiteDatabase db, String key, DataItemRecord record) {\n        ContentValues cv = record.toContentValues();\n        db.update(\"dataitems\", cv, \"_id=?\", new String[]{key});\n        finishRecord(db, key, record);\n    }\n\n    private static String insertRecord(SQLiteDatabase db, DataItemRecord record) {\n        ContentValues contentValues = record.toContentValues();\n        contentValues.put(\"appkeys_id\", getAppKey(db, record.packageName, record.signatureDigest));\n        contentValues.put(\"host\", record.dataItem.host);\n        contentValues.put(\"path\", record.dataItem.path);\n        String key = Long.toString(db.insertWithOnConflict(\"dataitems\", \"host\", contentValues, SQLiteDatabase.CONFLICT_REPLACE));\n        return finishRecord(db, key, record);\n    }\n\n    private static String finishRecord(SQLiteDatabase db, String key, DataItemRecord record) {\n        if (!record.deleted) {\n            for (Map.Entry<String, Asset> asset : record.dataItem.getAssets().entrySet()) {\n                ContentValues assetValues = new ContentValues();\n                assetValues.put(\"assets_digest\", asset.getValue().getDigest());\n                assetValues.put(\"dataitems_id\", key);\n                assetValues.put(\"assetname\", asset.getKey());\n                db.insertWithOnConflict(\"assetrefs\", \"assetname\", assetValues, SQLiteDatabase.CONFLICT_IGNORE);\n            }\n            Cursor status = db.query(\"assetsReadyStatus\", new String[]{\"nowReady\"}, \"dataitems_id=?\", new String[]{key}, null, null, null);\n            if (status.moveToNext()) {\n                record.assetsAreReady = status.getLong(0) != 0;\n            }\n            status.close();\n        } else {\n            record.assetsAreReady = false;\n        }\n        return key;\n    }\n\n    private static Cursor getDataItemsByHostAndPath(SQLiteDatabase db, String packageName, String signatureDigest, String host, String path) {\n        String[] params;\n        String selection;\n        if (path == null) {\n            params = new String[]{packageName, signatureDigest};\n            selection = \"packageName =? AND signatureDigest =?\";\n        } else if (host == null) {\n            params = new String[]{packageName, signatureDigest, path};\n            selection = \"packageName =? AND signatureDigest =? AND path =?\";\n        } else {\n            params = new String[]{packageName, signatureDigest, host, path};\n            selection = \"packageName =? AND signatureDigest =? AND host =? AND path =?\";\n        }\n        selection += \" AND deleted=0\";\n        return db.query(\"dataItemsAndAssets\", GDIBHAP_FIELDS, selection, params, null, null, \"packageName, signatureDigest, host, path\");\n    }\n\n    public Cursor getModifiedDataItems(final String nodeId, final long seqId, final boolean excludeDeleted) {\n        String selection = \"sourceNode =? AND seqId >?\" + (excludeDeleted ? \" AND deleted =0\" : \"\");\n        return getReadableDatabase().query(\"dataItemsAndAssets\", GDIBHAP_FIELDS, selection, new String[]{nodeId, Long.toString(seqId)}, null, null, \"seqId\", null);\n    }\n\n    public synchronized List<DataItemRecord> deleteDataItems(String packageName, String signatureDigest, String host, String path) {\n        List<DataItemRecord> updated = new ArrayList<DataItemRecord>();\n        SQLiteDatabase db = getWritableDatabase();\n        db.beginTransaction();\n        Cursor cursor = getDataItemsByHostAndPath(db, packageName, signatureDigest, host, path);\n        while (cursor.moveToNext()) {\n            DataItemRecord record = DataItemRecord.fromCursor(cursor);\n            record.deleted = true;\n            record.assetsAreReady = true;\n            record.dataItem.data = null;\n            record.seqId = clockworkNodePreferences.getNextSeqId();\n            record.v1SeqId = record.seqId;\n            updateRecord(db, cursor.getString(0), record);\n            updated.add(record);\n        }\n        db.setTransactionSuccessful();\n        db.endTransaction();\n        return updated;\n    }\n\n    public long getCurrentSeqId(String sourceNode) {\n        if (TextUtils.isEmpty(sourceNode)) return 1;\n        return getCurrentSeqId(getReadableDatabase(), sourceNode);\n    }\n\n    private long getCurrentSeqId(SQLiteDatabase db, String sourceNode) {\n        Cursor cursor = db.query(\"dataItemsAndAssets\", new String[]{\"seqId\"}, \"sourceNode=?\", new String[]{sourceNode}, null, null, \"seqId DESC\", \"1\");\n        long res = 1;\n        if (cursor != null) {\n            if (cursor.moveToFirst()) {\n                res = cursor.getLong(0);\n            }\n            cursor.close();\n        }\n        return res;\n    }\n\n    public synchronized void putAsset(Asset asset, boolean dataPresent) {\n        ContentValues cv = new ContentValues();\n        cv.put(\"digest\", asset.getDigest());\n        cv.put(\"dataPresent\", dataPresent ? 1 : 0);\n        cv.put(\"timestampMs\", System.currentTimeMillis());\n        getWritableDatabase().insertWithOnConflict(\"assets\", null, cv, SQLiteDatabase.CONFLICT_REPLACE);\n    }\n\n    public synchronized void allowAssetAccess(String digest, String packageName, String signatureDigest) {\n        SQLiteDatabase db = getWritableDatabase();\n        ContentValues cv = new ContentValues();\n        cv.put(\"assets_digest\", digest);\n        cv.put(\"appkeys_id\", getAppKey(db, packageName, signatureDigest));\n        db.insertWithOnConflict(\"assetsacls\", null, cv, SQLiteDatabase.CONFLICT_REPLACE);\n    }\n\n    public Cursor listMissingAssets() {\n        return getReadableDatabase().query(\"dataItemsAndAssets\", GDIBHAP_FIELDS, \"assetsPresent = 0 AND assets_digest NOT NULL\", null, null, null, \"packageName, signatureDigest, host, path\");\n    }\n\n    public boolean hasAsset(Asset asset) {\n        Cursor cursor = getReadableDatabase().query(\"assets\", new String[]{\"dataPresent\"}, \"digest=?\", new String[]{asset.getDigest()}, null, null, null);\n        if (cursor == null) return false;\n        try {\n            return (cursor.moveToNext() && cursor.getInt(0) == 1);\n        } finally {\n            cursor.close();\n        }\n    }\n\n    public synchronized void markAssetAsPresent(String digest) {\n        ContentValues cv = new ContentValues();\n        cv.put(\"dataPresent\", 1);\n        SQLiteDatabase db = getWritableDatabase();\n        db.update(\"assets\", cv, \"digest=?\", new String[]{digest});\n        Cursor status = db.query(\"assetsReadyStatus\", null, \"nowReady != markedReady\", null, null, null, null);\n        while (status.moveToNext()) {\n            cv = new ContentValues();\n            cv.put(\"assetsPresent\", status.getInt(status.getColumnIndexOrThrow(\"nowReady\")));\n            db.update(\"dataitems\", cv, \"_id=?\", new String[]{Integer.toString(status.getInt(status.getColumnIndexOrThrow(\"dataitems_id\")))});\n        }\n        status.close();\n    }\n}\n"
  },
  {
    "path": "play-services-wearable/core/src/main/java/org/microg/gms/wearable/RpcHelper.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.wearable;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class RpcHelper {\n    private final Map<String, RpcConnectionState> rpcStateMap = new HashMap<String, RpcConnectionState>();\n    private final SharedPreferences preferences;\n    private final Context context;\n\n    public RpcHelper(Context context) {\n        this.context = context;\n        this.preferences = context.getSharedPreferences(\"wearable.rpc_service.settings\", 0);\n    }\n\n    private String getRpcConnectionId(String packageName, String targetNodeId, String path) {\n        String mode = \"lo\";\n        if (packageName.equals(\"com.google.android.wearable.app\") && path.startsWith(\"/s3\"))\n            mode = \"hi\";\n        return targetNodeId + \":\" + mode;\n    }\n\n    public RpcHelper.RpcConnectionState useConnectionState(String packageName, String targetNodeId, String path) {\n        String rpcConnectionId = getRpcConnectionId(packageName, targetNodeId, path);\n        synchronized (rpcStateMap) {\n            if (!rpcStateMap.containsKey(rpcConnectionId)) {\n                int g = preferences.getInt(rpcConnectionId, 1)+1;\n                preferences.edit().putInt(rpcConnectionId, g).apply();\n                rpcStateMap.put(rpcConnectionId, new RpcConnectionState(g));\n            }\n            RpcHelper.RpcConnectionState res = rpcStateMap.get(rpcConnectionId);\n            res.lastRequestId++;\n            return res.freeze();\n        }\n    }\n\n    public static class RpcConnectionState {\n        public int generation;\n        public int lastRequestId;\n\n        public RpcConnectionState(int generation) {\n            this.generation = generation;\n        }\n\n        public RpcConnectionState freeze() {\n            RpcConnectionState res = new RpcConnectionState(generation);\n            res.lastRequestId = lastRequestId;\n            return res;\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-wearable/core/src/main/java/org/microg/gms/wearable/WearableImpl.java",
    "content": "/*\n * Copyright (C) 2013-2019 microG Project Team\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 org.microg.gms.wearable;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.os.Handler;\nimport android.os.Looper;\nimport android.os.RemoteException;\nimport android.text.TextUtils;\nimport android.util.Base64;\nimport android.util.Log;\n\nimport androidx.annotation.Nullable;\n\nimport com.google.android.gms.common.data.DataHolder;\nimport com.google.android.gms.wearable.Asset;\nimport com.google.android.gms.wearable.ConnectionConfiguration;\nimport com.google.android.gms.wearable.Node;\nimport com.google.android.gms.wearable.internal.IWearableListener;\nimport com.google.android.gms.wearable.internal.MessageEventParcelable;\nimport com.google.android.gms.wearable.internal.NodeParcelable;\nimport com.google.android.gms.wearable.internal.PutDataRequest;\n\nimport org.microg.gms.common.PackageUtils;\nimport org.microg.gms.common.RemoteListenerProxy;\nimport org.microg.gms.common.Utils;\nimport org.microg.wearable.SocketConnectionThread;\nimport org.microg.wearable.WearableConnection;\nimport org.microg.wearable.proto.AckAsset;\nimport org.microg.wearable.proto.AppKey;\nimport org.microg.wearable.proto.AppKeys;\nimport org.microg.wearable.proto.Connect;\nimport org.microg.wearable.proto.FetchAsset;\nimport org.microg.wearable.proto.FilePiece;\nimport org.microg.wearable.proto.Request;\nimport org.microg.wearable.proto.RootMessage;\nimport org.microg.wearable.proto.SetAsset;\nimport org.microg.wearable.proto.SetDataItem;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\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.Map;\nimport java.util.Set;\nimport java.util.concurrent.CountDownLatch;\n\nimport okio.ByteString;\n\npublic class WearableImpl {\n\n    private static final String TAG = \"GmsWear\";\n\n    private static final int WEAR_TCP_PORT = 5601;\n\n    private final Context context;\n    private final NodeDatabaseHelper nodeDatabase;\n    private final ConfigurationDatabaseHelper configDatabase;\n    private final Map<String, List<ListenerInfo>> listeners = new HashMap<String, List<ListenerInfo>>();\n    private final Set<Node> connectedNodes = new HashSet<Node>();\n    private final Map<String, WearableConnection> activeConnections = new HashMap<String, WearableConnection>();\n    private RpcHelper rpcHelper;\n    private SocketConnectionThread sct;\n    private ConnectionConfiguration[] configurations;\n    private boolean configurationsUpdated = false;\n    private ClockworkNodePreferences clockworkNodePreferences;\n    private CountDownLatch networkHandlerLock = new CountDownLatch(1);\n    public Handler networkHandler;\n\n    public WearableImpl(Context context, NodeDatabaseHelper nodeDatabase, ConfigurationDatabaseHelper configDatabase) {\n        this.context = context;\n        this.nodeDatabase = nodeDatabase;\n        this.configDatabase = configDatabase;\n        this.clockworkNodePreferences = new ClockworkNodePreferences(context);\n        this.rpcHelper = new RpcHelper(context);\n        new Thread(() -> {\n            Looper.prepare();\n            networkHandler = new Handler(Looper.myLooper());\n            networkHandlerLock.countDown();\n            Looper.loop();\n        }).start();\n    }\n\n    public String getLocalNodeId() {\n        return clockworkNodePreferences.getLocalNodeId();\n    }\n\n    public DataItemRecord putDataItem(String packageName, String signatureDigest, String source, DataItemInternal dataItem) {\n        DataItemRecord record = new DataItemRecord();\n        record.packageName = packageName;\n        record.signatureDigest = signatureDigest;\n        record.deleted = false;\n        record.source = source;\n        record.dataItem = dataItem;\n        record.v1SeqId = clockworkNodePreferences.getNextSeqId();\n        if (record.source.equals(getLocalNodeId())) record.seqId = record.v1SeqId;\n        nodeDatabase.putRecord(record);\n        return record;\n    }\n\n    public DataItemRecord putDataItem(DataItemRecord record) {\n        nodeDatabase.putRecord(record);\n        if (!record.assetsAreReady) {\n            for (Asset asset : record.dataItem.getAssets().values()) {\n                if (!nodeDatabase.hasAsset(asset)) {\n                    Log.d(TAG, \"Asset is missing: \" + asset);\n                }\n            }\n        }\n        Intent intent = new Intent(\"com.google.android.gms.wearable.DATA_CHANGED\");\n        intent.setPackage(record.packageName);\n        intent.setData(record.dataItem.uri);\n        invokeListeners(intent, listener -> listener.onDataChanged(record.toEventDataHolder()));\n        return record;\n    }\n\n    private Asset prepareAsset(String packageName, Asset asset) {\n        if (asset.getFd() != null && asset.data == null) {\n            try {\n                asset.data = Utils.readStreamToEnd(new FileInputStream(asset.getFd().getFileDescriptor()));\n            } catch (IOException e) {\n                Log.w(TAG, e);\n            }\n        }\n        if (asset.data != null) {\n            String digest = calculateDigest(asset.data);\n            File assetFile = createAssetFile(digest);\n            boolean success = assetFile.exists();\n            if (!success) {\n                File tmpFile = new File(assetFile.getParent(), assetFile.getName() + \".tmp\");\n\n                try {\n                    FileOutputStream stream = new FileOutputStream(tmpFile);\n                    stream.write(asset.data);\n                    stream.close();\n                    success = tmpFile.renameTo(assetFile);\n                } catch (IOException e) {\n                    Log.w(TAG, e);\n                }\n            }\n            if (success) {\n                Log.d(TAG, \"Successfully created asset file \" + assetFile);\n                return Asset.createFromRef(digest);\n            } else {\n                Log.w(TAG, \"Failed creating asset file \" + assetFile);\n            }\n        }\n        return null;\n    }\n\n    public File createAssetFile(String digest) {\n        File dir = new File(new File(context.getFilesDir(), \"assets\"), digest.substring(digest.length() - 2));\n        dir.mkdirs();\n        return new File(dir, digest + \".asset\");\n    }\n\n    private File createAssetReceiveTempFile(String name) {\n        File dir = new File(context.getFilesDir(), \"piece\");\n        dir.mkdirs();\n        return new File(dir, name);\n    }\n\n    private String calculateDigest(byte[] data) {\n        try {\n            return Base64.encodeToString(MessageDigest.getInstance(\"SHA1\").digest(data), Base64.NO_WRAP | Base64.NO_PADDING | Base64.URL_SAFE);\n        } catch (NoSuchAlgorithmException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public synchronized ConnectionConfiguration[] getConfigurations() {\n        if (configurations == null) {\n            configurations = configDatabase.getAllConfigurations();\n        }\n        if (configurationsUpdated) {\n            configurationsUpdated = false;\n            ConnectionConfiguration[] newConfigurations = configDatabase.getAllConfigurations();\n            for (ConnectionConfiguration configuration : configurations) {\n                for (ConnectionConfiguration newConfiguration : newConfigurations) {\n                    if (newConfiguration.name.equals(configuration.name)) {\n                        newConfiguration.connected = configuration.connected;\n                        newConfiguration.peerNodeId = configuration.peerNodeId;\n                        newConfiguration.nodeId = configuration.nodeId;\n                        break;\n                    }\n                }\n            }\n            configurations = newConfigurations;\n        }\n        Log.d(TAG, \"Configurations reported: \" + Arrays.toString(configurations));\n        return configurations;\n    }\n\n    private void addConnectedNode(Node node) {\n        connectedNodes.add(node);\n        onConnectedNodes(getConnectedNodesParcelableList());\n    }\n\n    private void removeConnectedNode(String nodeId) {\n        for (Node connectedNode : new ArrayList<Node>(connectedNodes)) {\n            if (connectedNode.getId().equals(nodeId))\n                connectedNodes.remove(connectedNode);\n        }\n        onConnectedNodes(getConnectedNodesParcelableList());\n    }\n\n\n    public Context getContext() {\n        return context;\n    }\n\n    public void syncToPeer(String peerNodeId, String nodeId, long seqId) {\n        Log.d(TAG, \"-- Start syncing over to \" + peerNodeId + \", nodeId \" + nodeId + \" starting with seqId \" + seqId);\n        Cursor cursor = nodeDatabase.getModifiedDataItems(nodeId, seqId, true);\n        if (cursor != null) {\n            while (cursor.moveToNext()) {\n                if (!syncRecordToPeer(peerNodeId, DataItemRecord.fromCursor(cursor))) break;\n            }\n            cursor.close();\n        }\n        Log.d(TAG, \"-- Done syncing over to \" + peerNodeId + \", nodeId \" + nodeId + \" starting with seqId \" + seqId);\n    }\n\n\n    void syncRecordToAll(DataItemRecord record) {\n        for (String nodeId : new ArrayList<String>(activeConnections.keySet())) {\n            syncRecordToPeer(nodeId, record);\n        }\n    }\n\n    private boolean syncRecordToPeer(String nodeId, DataItemRecord record) {\n        for (Asset asset : record.dataItem.getAssets().values()) {\n            try {\n                syncAssetToPeer(nodeId, record, asset);\n            } catch (Exception e) {\n                Log.w(TAG, \"Could not sync asset \" + asset + \" for \" + nodeId + \" and \" + record, e);\n                closeConnection(nodeId);\n                return false;\n            }\n        }\n\n        try {\n            SetDataItem item = record.toSetDataItem();\n            activeConnections.get(nodeId).writeMessage(new RootMessage.Builder().setDataItem(item).build());\n        } catch (Exception e) {\n            Log.w(TAG, e);\n            closeConnection(nodeId);\n            return false;\n        }\n        return true;\n    }\n\n    private void syncAssetToPeer(String nodeId, DataItemRecord record, Asset asset) throws IOException {\n        RootMessage announceMessage = new RootMessage.Builder().setAsset(new SetAsset.Builder()\n                .digest(asset.getDigest())\n                .appkeys(new AppKeys(Collections.singletonList(new AppKey(record.packageName, record.signatureDigest))))\n                .build()).hasAsset(true).build();\n        activeConnections.get(nodeId).writeMessage(announceMessage);\n        File assetFile = createAssetFile(asset.getDigest());\n        String fileName = calculateDigest(announceMessage.encode());\n        FileInputStream fis = new FileInputStream(assetFile);\n        byte[] arr = new byte[12215];\n        ByteString lastPiece = null;\n        int c = 0;\n        while ((c = fis.read(arr)) > 0) {\n            if (lastPiece != null) {\n                activeConnections.get(nodeId).writeMessage(new RootMessage.Builder().filePiece(new FilePiece(fileName, false, lastPiece, null)).build());\n            }\n            lastPiece = ByteString.of(arr, 0, c);\n        }\n        activeConnections.get(nodeId).writeMessage(new RootMessage.Builder().filePiece(new FilePiece(fileName, true, lastPiece, asset.getDigest())).build());\n    }\n\n    public void addAssetToDatabase(Asset asset, List<AppKey> appKeys) {\n        nodeDatabase.putAsset(asset, false);\n        for (AppKey appKey : appKeys) {\n            nodeDatabase.allowAssetAccess(asset.getDigest(), appKey.packageName, appKey.signatureDigest);\n        }\n    }\n\n    public long getCurrentSeqId(String nodeId) {\n        return nodeDatabase.getCurrentSeqId(nodeId);\n    }\n\n    public void handleFilePiece(WearableConnection connection, String fileName, byte[] bytes, String finalPieceDigest) {\n        File file = createAssetReceiveTempFile(fileName);\n        try {\n            FileOutputStream fos = new FileOutputStream(file, true);\n            fos.write(bytes);\n            fos.close();\n        } catch (IOException e) {\n            Log.w(TAG, e);\n        }\n        if (finalPieceDigest != null) {\n            // This is a final piece. If digest matches we're so happy!\n            try {\n                String digest = calculateDigest(Utils.readStreamToEnd(new FileInputStream(file)));\n                if (digest.equals(finalPieceDigest)) {\n                    if (file.renameTo(createAssetFile(digest))) {\n                        nodeDatabase.markAssetAsPresent(digest);\n                        connection.writeMessage(new RootMessage.Builder().ackAsset(new AckAsset(digest)).build());\n                    } else {\n                        Log.w(TAG, \"Could not rename to target file name. delete=\" + file.delete());\n                    }\n                } else {\n                    Log.w(TAG, \"Received digest does not match. delete=\" + file.delete());\n                }\n            } catch (IOException e) {\n                Log.w(TAG, \"Failed working with temp file. delete=\" + file.delete(), e);\n            }\n        }\n    }\n\n    public void onConnectReceived(WearableConnection connection, String nodeId, Connect connect) {\n        for (ConnectionConfiguration config : getConfigurations()) {\n            if (config.nodeId.equals(nodeId)) {\n                if (config.nodeId != nodeId) {\n                    config.nodeId = connect.id;\n                    configDatabase.putConfiguration(config, nodeId);\n                }\n                config.peerNodeId = connect.id;\n                config.connected = true;\n            }\n        }\n        Log.d(TAG, \"Adding connection to list of open connections: \" + connection + \" with connect \" + connect);\n        activeConnections.put(connect.id, connection);\n        onPeerConnected(new NodeParcelable(connect.id, connect.name));\n        // Fetch missing assets\n        Cursor cursor = nodeDatabase.listMissingAssets();\n        if (cursor != null) {\n            while (cursor.moveToNext()) {\n                try {\n                    Log.d(TAG, \"Fetch for \" + cursor.getString(12));\n                    connection.writeMessage(new RootMessage.Builder()\n                            .fetchAsset(new FetchAsset.Builder()\n                                    .assetName(cursor.getString(12))\n                                    .packageName(cursor.getString(1))\n                                    .signatureDigest(cursor.getString(2))\n                                    .permission(false)\n                                    .build()).build());\n                } catch (IOException e) {\n                    Log.w(TAG, e);\n                    closeConnection(connect.id);\n                }\n            }\n            cursor.close();\n        }\n    }\n\n    public void onDisconnectReceived(WearableConnection connection, Connect connect) {\n        for (ConnectionConfiguration config : getConfigurations()) {\n            if (config.nodeId.equals(connect.id)) {\n                config.connected = false;\n            }\n        }\n        Log.d(TAG, \"Removing connection from list of open connections: \" + connection);\n        activeConnections.remove(connect.id);\n        onPeerDisconnected(new NodeParcelable(connect.id, connect.name));\n    }\n\n    public List<NodeParcelable> getConnectedNodesParcelableList() {\n        List<NodeParcelable> nodes = new ArrayList<NodeParcelable>();\n        for (Node connectedNode : connectedNodes) {\n            nodes.add(new NodeParcelable(connectedNode));\n        }\n        return nodes;\n    }\n\n    interface ListenerInvoker {\n        void invoke(IWearableListener listener) throws RemoteException;\n    }\n\n    private void invokeListeners(@Nullable Intent intent, ListenerInvoker invoker) {\n        for (String packageName : new ArrayList<>(listeners.keySet())) {\n            List<ListenerInfo> listeners = this.listeners.get(packageName);\n            if (listeners == null) continue;\n            for (int i = 0; i < listeners.size(); i++) {\n                boolean filterMatched = false;\n                if (intent != null) {\n                    for (IntentFilter filter : listeners.get(i).filters) {\n                        filterMatched |= filter.match(context.getContentResolver(), intent, false, TAG) > 0;\n                    }\n                }\n                if (filterMatched || listeners.get(i).filters.length == 0) {\n                    try {\n                        invoker.invoke(listeners.get(i).listener);\n                    } catch (RemoteException e) {\n                        Log.w(TAG, \"Registered listener at package \" + packageName + \" failed, removing.\");\n                        listeners.remove(i);\n                        i--;\n                    }\n                }\n            }\n            if (listeners.isEmpty()) {\n                this.listeners.remove(packageName);\n            }\n        }\n        if (intent != null) {\n            try {\n                invoker.invoke(RemoteListenerProxy.get(context, intent, IWearableListener.class, \"com.google.android.gms.wearable.BIND_LISTENER\"));\n            } catch (RemoteException e) {\n                Log.w(TAG, \"Failed to deliver message received to \" + intent, e);\n            }\n        }\n    }\n\n    public void onPeerConnected(NodeParcelable node) {\n        Log.d(TAG, \"onPeerConnected: \" + node);\n        invokeListeners(null, listener -> listener.onPeerConnected(node));\n        addConnectedNode(node);\n    }\n\n    public void onPeerDisconnected(NodeParcelable node) {\n        Log.d(TAG, \"onPeerDisconnected: \" + node);\n        invokeListeners(null, listener -> listener.onPeerDisconnected(node));\n        removeConnectedNode(node.getId());\n    }\n\n    public void onConnectedNodes(List<NodeParcelable> nodes) {\n        Log.d(TAG, \"onConnectedNodes: \" + nodes);\n        invokeListeners(null, listener -> listener.onConnectedNodes(nodes));\n    }\n\n    public DataItemRecord putData(PutDataRequest request, String packageName) {\n        DataItemInternal dataItem = new DataItemInternal(fixHost(request.getUri().getHost(), true), request.getUri().getPath());\n        for (Map.Entry<String, Asset> assetEntry : request.getAssets().entrySet()) {\n            Asset asset = prepareAsset(packageName, assetEntry.getValue());\n            if (asset != null) {\n                nodeDatabase.putAsset(asset, true);\n                dataItem.addAsset(assetEntry.getKey(), asset);\n            }\n        }\n        dataItem.data = request.getData();\n        DataItemRecord record = putDataItem(packageName, PackageUtils.firstSignatureDigest(context, packageName), getLocalNodeId(), dataItem);\n        syncRecordToAll(record);\n        return record;\n    }\n\n    public DataHolder getDataItemsAsHolder(String packageName) {\n        Cursor dataHolderItems = nodeDatabase.getDataItemsForDataHolder(packageName, PackageUtils.firstSignatureDigest(context, packageName));\n        return new DataHolder(dataHolderItems, 0, null);\n    }\n\n    private String fixHost(String host, boolean nothingToLocal) {\n        if (TextUtils.isEmpty(host) && nothingToLocal) return getLocalNodeId();\n        if (TextUtils.isEmpty(host)) return null;\n        if (host.equals(\"local\")) return getLocalNodeId();\n        return host;\n    }\n\n    public DataHolder getDataItemsByUriAsHolder(Uri uri, String packageName) {\n        String firstSignature;\n        try {\n            firstSignature = PackageUtils.firstSignatureDigest(context, packageName);\n        } catch (Exception e) {\n            return null;\n        }\n        Cursor dataHolderItems = nodeDatabase.getDataItemsForDataHolderByHostAndPath(packageName, firstSignature, fixHost(uri.getHost(), false), uri.getPath());\n        DataHolder dataHolder = new DataHolder(dataHolderItems, 0, null);\n        Log.d(TAG, \"Returning data holder of size \" + dataHolder.getCount() + \" for query \" + uri);\n        return dataHolder;\n    }\n\n    public synchronized void addListener(String packageName, IWearableListener listener, IntentFilter[] filters) {\n        if (!listeners.containsKey(packageName)) {\n            listeners.put(packageName, new ArrayList<ListenerInfo>());\n        }\n        listeners.get(packageName).add(new ListenerInfo(listener, filters));\n    }\n\n    public void removeListener(IWearableListener listener) {\n        for (List<ListenerInfo> list : listeners.values()) {\n            for (int i = 0; i < list.size(); i++) {\n                if (list.get(i).listener.equals(listener)) {\n                    list.remove(i);\n                    i--;\n                }\n            }\n        }\n    }\n\n    public void enableConnection(String name) {\n        configDatabase.setEnabledState(name, true);\n        configurationsUpdated = true;\n        if (name.equals(\"server\") && sct == null) {\n            Log.d(TAG, \"Starting server on :\" + WEAR_TCP_PORT);\n            (sct = SocketConnectionThread.serverListen(WEAR_TCP_PORT, new MessageHandler(context, this, configDatabase.getConfiguration(name)))).start();\n        }\n    }\n\n    public void disableConnection(String name) {\n        configDatabase.setEnabledState(name, false);\n        configurationsUpdated = true;\n        if (name.equals(\"server\") && sct != null) {\n            activeConnections.remove(sct.getWearableConnection());\n            sct.close();\n            sct.interrupt();\n            sct = null;\n        }\n    }\n\n    public void deleteConnection(String name) {\n        configDatabase.deleteConfiguration(name);\n        configurationsUpdated = true;\n    }\n\n    public void createConnection(ConnectionConfiguration config) {\n        if (config.nodeId == null) config.nodeId = getLocalNodeId();\n        Log.d(TAG, \"putConfig[nyp]: \" + config);\n        configDatabase.putConfiguration(config);\n        configurationsUpdated = true;\n    }\n\n    public int deleteDataItems(Uri uri, String packageName) {\n        List<DataItemRecord> records = nodeDatabase.deleteDataItems(packageName, PackageUtils.firstSignatureDigest(context, packageName), fixHost(uri.getHost(), false), uri.getPath());\n        for (DataItemRecord record : records) {\n            syncRecordToAll(record);\n        }\n        return records.size();\n    }\n\n    public void sendMessageReceived(String packageName, MessageEventParcelable messageEvent) {\n        Log.d(TAG, \"onMessageReceived: \" + messageEvent);\n        Intent intent = new Intent(\"com.google.android.gms.wearable.MESSAGE_RECEIVED\");\n        intent.setPackage(packageName);\n        intent.setData(Uri.parse(\"wear://\" + getLocalNodeId() + \"/\" + messageEvent.getPath()));\n        invokeListeners(intent, listener -> listener.onMessageReceived(messageEvent));\n    }\n\n    public DataItemRecord getDataItemByUri(Uri uri, String packageName) {\n        Cursor cursor = nodeDatabase.getDataItemsByHostAndPath(packageName, PackageUtils.firstSignatureDigest(context, packageName), fixHost(uri.getHost(), true), uri.getPath());\n        DataItemRecord record = null;\n        if (cursor != null) {\n            if (cursor.moveToNext()) {\n                record = DataItemRecord.fromCursor(cursor);\n            }\n            cursor.close();\n        }\n        Log.d(TAG, \"getDataItem: \" + record);\n        return record;\n    }\n\n    private IWearableListener getListener(String packageName, String action, Uri uri) {\n        Intent intent = new Intent(action);\n        intent.setPackage(packageName);\n        intent.setData(uri);\n\n        return RemoteListenerProxy.get(context, intent, IWearableListener.class, \"com.google.android.gms.wearable.BIND_LISTENER\");\n    }\n\n    private void closeConnection(String nodeId) {\n        WearableConnection connection = activeConnections.get(nodeId);\n        try {\n            connection.close();\n        } catch (IOException e1) {\n            Log.w(TAG, e1);\n        }\n        if (connection == sct.getWearableConnection()) {\n            sct.close();\n            sct = null;\n        }\n        activeConnections.remove(nodeId);\n        for (ConnectionConfiguration config : getConfigurations()) {\n            if (nodeId.equals(config.nodeId) || nodeId.equals(config.peerNodeId)) {\n                config.connected = false;\n            }\n        }\n        onPeerDisconnected(new NodeParcelable(nodeId, \"Wear device\"));\n        Log.d(TAG, \"Closed connection to \" + nodeId + \" on error\");\n    }\n\n    public int sendMessage(String packageName, String targetNodeId, String path, byte[] data) {\n        if (activeConnections.containsKey(targetNodeId)) {\n            WearableConnection connection = activeConnections.get(targetNodeId);\n            RpcHelper.RpcConnectionState state = rpcHelper.useConnectionState(packageName, targetNodeId, path);\n            try {\n                connection.writeMessage(new RootMessage.Builder().rpcRequest(new Request.Builder()\n                        .targetNodeId(targetNodeId)\n                        .path(path)\n                        .rawData(ByteString.of(data))\n                        .packageName(packageName)\n                        .signatureDigest(PackageUtils.firstSignatureDigest(context, packageName))\n                        .sourceNodeId(getLocalNodeId())\n                        .generation(state.generation)\n                        .requestId(state.lastRequestId)\n                        .build()).build());\n            } catch (IOException e) {\n                Log.w(TAG, \"Error while writing, closing link\", e);\n                closeConnection(targetNodeId);\n                return -1;\n            }\n            return (state.generation + 527) * 31 + state.lastRequestId;\n        }\n        Log.d(TAG, targetNodeId + \" seems not reachable\");\n        return -1;\n    }\n\n    public void stop() {\n        try {\n            this.networkHandlerLock.await();\n            this.networkHandler.getLooper().quit();\n        } catch (InterruptedException e) {\n            Log.w(TAG, e);\n        }\n    }\n\n    private class ListenerInfo {\n        private IWearableListener listener;\n        private IntentFilter[] filters;\n\n        private ListenerInfo(IWearableListener listener, IntentFilter[] filters) {\n            this.listener = listener;\n            this.filters = filters;\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-wearable/core/src/main/java/org/microg/gms/wearable/WearableService.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.wearable;\n\nimport android.os.RemoteException;\n\nimport com.google.android.gms.common.internal.GetServiceRequest;\nimport com.google.android.gms.common.internal.IGmsCallbacks;\n\nimport org.microg.gms.BaseService;\nimport org.microg.gms.common.GmsService;\nimport org.microg.gms.common.PackageUtils;\n\npublic class WearableService extends BaseService {\n\n    private WearableImpl wearable;\n\n    public WearableService() {\n        super(\"GmsWearSvc\", GmsService.WEAR);\n    }\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n        ConfigurationDatabaseHelper configurationDatabaseHelper = new ConfigurationDatabaseHelper(getApplicationContext());\n        NodeDatabaseHelper nodeDatabaseHelper = new NodeDatabaseHelper(getApplicationContext());\n        wearable = new WearableImpl(getApplicationContext(), nodeDatabaseHelper, configurationDatabaseHelper);\n    }\n\n    @Override\n    public void onDestroy() {\n        super.onDestroy();\n        wearable.stop();\n    }\n\n    @Override\n    public void handleServiceRequest(IGmsCallbacks callback, GetServiceRequest request, GmsService service) throws RemoteException {\n        PackageUtils.getAndCheckCallingPackage(this, request.packageName);\n        callback.onPostInitComplete(0, new WearableServiceImpl(this, wearable, request.packageName), null);\n    }\n}\n"
  },
  {
    "path": "play-services-wearable/core/src/main/java/org/microg/gms/wearable/WearableServiceImpl.java",
    "content": "/*\n * Copyright (C) 2013-2019 microG Project Team\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 org.microg.gms.wearable;\n\nimport android.content.Context;\nimport android.net.Uri;\nimport android.os.Handler;\nimport android.os.Parcel;\nimport android.os.ParcelFileDescriptor;\nimport android.os.RemoteException;\nimport android.util.Base64;\nimport android.util.Log;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.wearable.Asset;\nimport com.google.android.gms.wearable.ConnectionConfiguration;\nimport com.google.android.gms.wearable.internal.*;\n\nimport java.io.FileNotFoundException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Set;\n\npublic class WearableServiceImpl extends IWearableService.Stub {\n    private static final String TAG = \"GmsWearSvcImpl\";\n\n    private final Context context;\n    private final String packageName;\n    private final WearableImpl wearable;\n    private final Handler mainHandler;\n    private final CapabilityManager capabilities;\n\n    public WearableServiceImpl(Context context, WearableImpl wearable, String packageName) {\n        this.context = context;\n        this.wearable = wearable;\n        this.packageName = packageName;\n        this.capabilities = new CapabilityManager(context, wearable, packageName);\n        this.mainHandler = new Handler(context.getMainLooper());\n    }\n\n    private void postMain(IWearableCallbacks callbacks, RemoteExceptionRunnable runnable) {\n        mainHandler.post(new CallbackRunnable(callbacks) {\n            @Override\n            public void run(IWearableCallbacks callbacks) throws RemoteException {\n                runnable.run();\n            }\n        });\n    }\n\n    private void postNetwork(IWearableCallbacks callbacks, RemoteExceptionRunnable runnable) {\n        this.wearable.networkHandler.post(new CallbackRunnable(callbacks) {\n            @Override\n            public void run(IWearableCallbacks callbacks) throws RemoteException {\n                runnable.run();\n            }\n        });\n    }\n\n    /*\n     * Config\n     */\n\n    @Override\n    public void putConfig(IWearableCallbacks callbacks, final ConnectionConfiguration config) throws RemoteException {\n        postMain(callbacks, () -> {\n            wearable.createConnection(config);\n            callbacks.onStatus(Status.SUCCESS);\n        });\n    }\n\n    @Override\n    public void deleteConfig(IWearableCallbacks callbacks, final String name) throws RemoteException {\n        postMain(callbacks, () -> {\n            wearable.deleteConnection(name);\n            callbacks.onStatus(Status.SUCCESS);\n        });\n    }\n\n    @Override\n    public void getConfigs(IWearableCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"getConfigs\");\n        postMain(callbacks, () -> {\n            try {\n                callbacks.onGetConfigsResponse(new GetConfigsResponse(0, wearable.getConfigurations()));\n            } catch (Exception e) {\n                callbacks.onGetConfigsResponse(new GetConfigsResponse(8, new ConnectionConfiguration[0]));\n            }\n        });\n    }\n\n\n    @Override\n    public void enableConfig(IWearableCallbacks callbacks, final String name) throws RemoteException {\n        Log.d(TAG, \"enableConfig: \" + name);\n        postMain(callbacks, () -> {\n            wearable.enableConnection(name);\n            callbacks.onStatus(Status.SUCCESS);\n        });\n    }\n\n    @Override\n    public void disableConfig(IWearableCallbacks callbacks, final String name) throws RemoteException {\n        Log.d(TAG, \"disableConfig: \" + name);\n        postMain(callbacks, () -> {\n            wearable.disableConnection(name);\n            callbacks.onStatus(Status.SUCCESS);\n        });\n    }\n\n    /*\n     * DataItems\n     */\n\n    @Override\n    public void putData(IWearableCallbacks callbacks, final PutDataRequest request) throws RemoteException {\n        Log.d(TAG, \"putData: \" + request.toString(true));\n        this.wearable.networkHandler.post(new CallbackRunnable(callbacks) {\n            @Override\n            public void run(IWearableCallbacks callbacks) throws RemoteException {\n                DataItemRecord record = wearable.putData(request, packageName);\n                callbacks.onPutDataResponse(new PutDataResponse(0, record.toParcelable()));\n            }\n        });\n    }\n\n    @Override\n    public void getDataItem(IWearableCallbacks callbacks, final Uri uri) throws RemoteException {\n        Log.d(TAG, \"getDataItem: \" + uri);\n        postMain(callbacks, () -> {\n            DataItemRecord record = wearable.getDataItemByUri(uri, packageName);\n            if (record != null) {\n                callbacks.onGetDataItemResponse(new GetDataItemResponse(0, record.toParcelable()));\n            } else {\n                callbacks.onGetDataItemResponse(new GetDataItemResponse(0, null));\n            }\n        });\n    }\n\n    @Override\n    public void getDataItems(final IWearableCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"getDataItems: \" + callbacks);\n        postMain(callbacks, () -> {\n            callbacks.onDataItemChanged(wearable.getDataItemsAsHolder(packageName));\n        });\n    }\n\n    @Override\n    public void getDataItemsByUri(IWearableCallbacks callbacks, Uri uri) throws RemoteException {\n        getDataItemsByUriWithFilter(callbacks, uri, 0);\n    }\n\n    @Override\n    public void getDataItemsByUriWithFilter(IWearableCallbacks callbacks, final Uri uri, int typeFilter) throws RemoteException {\n        Log.d(TAG, \"getDataItemsByUri: \" + uri);\n        postMain(callbacks, () -> {\n            callbacks.onDataItemChanged(wearable.getDataItemsByUriAsHolder(uri, packageName));\n        });\n    }\n\n    @Override\n    public void deleteDataItems(IWearableCallbacks callbacks, Uri uri) throws RemoteException {\n        deleteDataItemsWithFilter(callbacks, uri, 0);\n    }\n\n    @Override\n    public void deleteDataItemsWithFilter(IWearableCallbacks callbacks, final Uri uri, int typeFilter) throws RemoteException {\n        Log.d(TAG, \"deleteDataItems: \" + uri);\n        this.wearable.networkHandler.post(new CallbackRunnable(callbacks) {\n            @Override\n            public void run(IWearableCallbacks callbacks) throws RemoteException {\n                callbacks.onDeleteDataItemsResponse(new DeleteDataItemsResponse(0, wearable.deleteDataItems(uri, packageName)));\n            }\n        });\n    }\n\n    @Override\n    public void sendMessage(IWearableCallbacks callbacks, final String targetNodeId, final String path, final byte[] data) throws RemoteException {\n        Log.d(TAG, \"sendMessage: \" + targetNodeId + \" / \" + path + \": \" + (data == null ? null : Base64.encodeToString(data, Base64.NO_WRAP)));\n        this.wearable.networkHandler.post(new CallbackRunnable(callbacks) {\n            @Override\n            public void run(IWearableCallbacks callbacks) throws RemoteException {\n                SendMessageResponse sendMessageResponse = new SendMessageResponse();\n                try {\n                    sendMessageResponse.requestId = wearable.sendMessage(packageName, targetNodeId, path, data);\n                    if (sendMessageResponse.requestId == -1) {\n                        sendMessageResponse.statusCode = 4000;\n                    }\n                } catch (Exception e) {\n                    sendMessageResponse.statusCode = 8;\n                }\n                mainHandler.post(() -> {\n                    try {\n                        callbacks.onSendMessageResponse(sendMessageResponse);\n                    } catch (RemoteException e) {\n                        e.printStackTrace();\n                    }\n                });\n            }\n        });\n    }\n\n    @Override\n    public void getFdForAsset(IWearableCallbacks callbacks, final Asset asset) throws RemoteException {\n        Log.d(TAG, \"getFdForAsset \" + asset);\n        postMain(callbacks, () -> {\n            // TODO: Access control\n            try {\n                callbacks.onGetFdForAssetResponse(new GetFdForAssetResponse(0, ParcelFileDescriptor.open(wearable.createAssetFile(asset.getDigest()), ParcelFileDescriptor.MODE_READ_ONLY)));\n            } catch (FileNotFoundException e) {\n                callbacks.onGetFdForAssetResponse(new GetFdForAssetResponse(8, null));\n            }\n        });\n    }\n\n    @Override\n    public void optInCloudSync(IWearableCallbacks callbacks, boolean enable) throws RemoteException {\n        callbacks.onStatus(Status.SUCCESS);\n    }\n\n    @Override\n    @Deprecated\n    public void getCloudSyncOptInDone(IWearableCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: getCloudSyncOptInDone\");\n    }\n\n    @Override\n    public void setCloudSyncSetting(IWearableCallbacks callbacks, boolean enable) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: setCloudSyncSetting\");\n    }\n\n    @Override\n    public void getCloudSyncSetting(IWearableCallbacks callbacks) throws RemoteException {\n        callbacks.onGetCloudSyncSettingResponse(new GetCloudSyncSettingResponse(0, false));\n    }\n\n    @Override\n    public void getCloudSyncOptInStatus(IWearableCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: getCloudSyncOptInStatus\");\n    }\n\n    @Override\n    public void sendRemoteCommand(IWearableCallbacks callbacks, byte b) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: sendRemoteCommand: \" + b);\n    }\n\n    @Override\n    public void getLocalNode(IWearableCallbacks callbacks) throws RemoteException {\n        postMain(callbacks, () -> {\n            try {\n                callbacks.onGetLocalNodeResponse(new GetLocalNodeResponse(0, new NodeParcelable(wearable.getLocalNodeId(), wearable.getLocalNodeId())));\n            } catch (Exception e) {\n                callbacks.onGetLocalNodeResponse(new GetLocalNodeResponse(8, null));\n            }\n        });\n    }\n\n    @Override\n    public void getConnectedNodes(IWearableCallbacks callbacks) throws RemoteException {\n        postMain(callbacks, () -> {\n            callbacks.onGetConnectedNodesResponse(new GetConnectedNodesResponse(0, wearable.getConnectedNodesParcelableList()));\n        });\n    }\n\n    /*\n     * Capability\n     */\n\n    @Override\n    public void getConnectedCapability(IWearableCallbacks callbacks, String capability, int nodeFilter) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: getConnectedCapability \" + capability + \", \" + nodeFilter);\n        postMain(callbacks, () -> {\n            List<NodeParcelable> nodes = new ArrayList<>();\n            for (String host : capabilities.getNodesForCapability(capability)) {\n                nodes.add(new NodeParcelable(host, host));\n            }\n            CapabilityInfoParcelable capabilityInfo = new CapabilityInfoParcelable(capability, nodes);\n            callbacks.onGetCapabilityResponse(new GetCapabilityResponse(0, capabilityInfo));\n        });\n    }\n\n    @Override\n    public void getAllCapabilities(IWearableCallbacks callbacks, int nodeFilter) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: getConnectedCapaibilties: \" + nodeFilter);\n        callbacks.onGetAllCapabilitiesResponse(new GetAllCapabilitiesResponse());\n    }\n\n    @Override\n    public void addLocalCapability(IWearableCallbacks callbacks, String capability) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: addLocalCapability: \" + capability);\n        this.wearable.networkHandler.post(new CallbackRunnable(callbacks) {\n            @Override\n            public void run(IWearableCallbacks callbacks) throws RemoteException {\n                callbacks.onAddLocalCapabilityResponse(new AddLocalCapabilityResponse(capabilities.add(capability)));\n            }\n        });\n    }\n\n    @Override\n    public void removeLocalCapability(IWearableCallbacks callbacks, String capability) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: removeLocalCapability: \" + capability);\n        this.wearable.networkHandler.post(new CallbackRunnable(callbacks) {\n            @Override\n            public void run(IWearableCallbacks callbacks) throws RemoteException {\n                callbacks.onRemoveLocalCapabilityResponse(new RemoveLocalCapabilityResponse(capabilities.remove(capability)));\n            }\n        });\n    }\n\n    @Override\n    public void addListener(IWearableCallbacks callbacks, AddListenerRequest request) throws RemoteException {\n        if (request.listener != null) {\n            wearable.addListener(packageName, request.listener, request.intentFilters);\n        }\n        callbacks.onStatus(Status.SUCCESS);\n    }\n\n    @Override\n    public void removeListener(IWearableCallbacks callbacks, RemoveListenerRequest request) throws RemoteException {\n        wearable.removeListener(request.listener);\n        callbacks.onStatus(Status.SUCCESS);\n    }\n\n    @Override\n    public void getStorageInformation(IWearableCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: getStorageInformation\");\n    }\n\n    @Override\n    public void clearStorage(IWearableCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: clearStorage\");\n    }\n\n    @Override\n    public void endCall(IWearableCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: endCall\");\n    }\n\n    @Override\n    public void acceptRingingCall(IWearableCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: acceptRingingCall\");\n    }\n\n    @Override\n    public void silenceRinger(IWearableCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: silenceRinger\");\n    }\n\n    /*\n     * Apple Notification Center Service\n     */\n\n    @Override\n    public void injectAncsNotificationForTesting(IWearableCallbacks callbacks, AncsNotificationParcelable notification) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: injectAncsNotificationForTesting: \" + notification);\n    }\n\n    @Override\n    public void doAncsPositiveAction(IWearableCallbacks callbacks, int i) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: doAncsPositiveAction: \" + i);\n    }\n\n    @Override\n    public void doAncsNegativeAction(IWearableCallbacks callbacks, int i) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: doAncsNegativeAction: \" + i);\n    }\n\n    @Override\n    public void openChannel(IWearableCallbacks callbacks, String s1, String s2) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: openChannel; \" + s1 + \", \" + s2);\n    }\n\n    /*\n     * Channels\n     */\n\n    @Override\n    public void closeChannel(IWearableCallbacks callbacks, String s) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: closeChannel: \" + s);\n    }\n\n    @Override\n    public void closeChannelWithError(IWearableCallbacks callbacks, String s, int errorCode) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: closeChannelWithError:\" + s + \", \" + errorCode);\n\n    }\n\n    @Override\n    public void getChannelInputStream(IWearableCallbacks callbacks, IChannelStreamCallbacks channelCallbacks, String s) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: getChannelInputStream: \" + s);\n    }\n\n    @Override\n    public void getChannelOutputStream(IWearableCallbacks callbacks, IChannelStreamCallbacks channelCallbacks, String s) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: getChannelOutputStream: \" + s);\n    }\n\n    @Override\n    public void writeChannelInputToFd(IWearableCallbacks callbacks, String s, ParcelFileDescriptor fd) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: writeChannelInputToFd: \" + s);\n    }\n\n    @Override\n    public void readChannelOutputFromFd(IWearableCallbacks callbacks, String s, ParcelFileDescriptor fd, long l1, long l2) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: readChannelOutputFromFd: \" + s + \", \" + l1 + \", \" + l2);\n    }\n\n    @Override\n    public void syncWifiCredentials(IWearableCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: syncWifiCredentials\");\n    }\n\n    /*\n     * Connection deprecated\n     */\n\n    @Override\n    @Deprecated\n    public void putConnection(IWearableCallbacks callbacks, ConnectionConfiguration config) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: putConnection\");\n    }\n\n    @Override\n    @Deprecated\n    public void getConnection(IWearableCallbacks callbacks) throws RemoteException {\n        Log.d(TAG, \"getConfig\");\n        postMain(callbacks, () -> {\n            ConnectionConfiguration[] configurations = wearable.getConfigurations();\n            if (configurations == null || configurations.length == 0) {\n                callbacks.onGetConfigResponse(new GetConfigResponse(1, new ConnectionConfiguration(null, null, 0, 0, false)));\n            } else {\n                callbacks.onGetConfigResponse(new GetConfigResponse(0, configurations[0]));\n            }\n        });\n    }\n\n    @Override\n    @Deprecated\n    public void enableConnection(IWearableCallbacks callbacks) throws RemoteException {\n        postMain(callbacks, () -> {\n            ConnectionConfiguration[] configurations = wearable.getConfigurations();\n            if (configurations.length > 0) {\n                enableConfig(callbacks, configurations[0].name);\n            }\n        });\n    }\n\n    @Override\n    @Deprecated\n    public void disableConnection(IWearableCallbacks callbacks) throws RemoteException {\n        postMain(callbacks, () -> {\n            ConnectionConfiguration[] configurations = wearable.getConfigurations();\n            if (configurations.length > 0) {\n                disableConfig(callbacks, configurations[0].name);\n            }\n        });\n    }\n\n    @Override\n    public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {\n        if (super.onTransact(code, data, reply, flags)) return true;\n        Log.d(TAG, \"onTransact [unknown]: \" + code + \", \" + data + \", \" + flags);\n        return false;\n    }\n\n    public abstract class CallbackRunnable implements Runnable {\n        private IWearableCallbacks callbacks;\n\n        public CallbackRunnable(IWearableCallbacks callbacks) {\n            this.callbacks = callbacks;\n        }\n\n        @Override\n        public void run() {\n            try {\n                run(callbacks);\n            } catch (RemoteException e) {\n                mainHandler.post(() -> {\n                    try {\n                        callbacks.onStatus(Status.CANCELED);\n                    } catch (RemoteException e2) {\n                        Log.w(TAG, e);\n                    }\n                });\n            }\n        }\n\n        public abstract void run(IWearableCallbacks callbacks) throws RemoteException;\n    }\n\n    public interface RemoteExceptionRunnable {\n        void run() throws RemoteException;\n    }\n}\n"
  },
  {
    "path": "play-services-wearable/core/src/main/java/org/microg/gms/wearable/location/WearableLocationService.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.wearable.location;\n\nimport android.content.Context;\nimport android.util.Log;\n\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.location.LocationRequest;\nimport com.google.android.gms.common.internal.ClientIdentity;\nimport com.google.android.gms.location.internal.LocationRequestInternal;\nimport com.google.android.gms.wearable.DataMap;\nimport com.google.android.gms.wearable.MessageEvent;\nimport com.google.android.gms.wearable.Node;\nimport com.google.android.gms.wearable.Wearable;\nimport com.google.android.gms.wearable.WearableListenerService;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\npublic class WearableLocationService extends WearableListenerService {\n    private static final String TAG = \"GmsWearLocSvc\";\n\n    public static final String PATH_LOCATION_REQUESTS = \"com/google/android/location/fused/wearable/LOCATION_REQUESTS\";\n    public static final String PATH_CAPABILITY_QUERY = \"com/google/android/location/fused/wearable/CAPABILITY_QUERY\";\n    public static final String PATH_CAPABILITY = \"com/google/android/location/fused/wearable/CAPABILITY\";\n\n    private GoogleApiClient apiClient;\n    private Map<String, Collection<LocationRequestInternal>> requestMap = new HashMap<String, Collection<LocationRequestInternal>>();\n\n    @Override\n    public void onMessageReceived(MessageEvent messageEvent) {\n        if (messageEvent.getPath().equals(PATH_LOCATION_REQUESTS)) {\n            DataMap dataMap = DataMap.fromByteArray(messageEvent.getData());\n            onLocationRequests(messageEvent.getSourceNodeId(), readLocationRequestList(dataMap, this), dataMap.getBoolean(\"TRIGGER_UPDATE\", false));\n        } else if (messageEvent.getPath().equals(PATH_CAPABILITY_QUERY)) {\n            onCapabilityQuery(messageEvent.getSourceNodeId());\n        }\n    }\n\n    @Override\n    public void onPeerDisconnected(Node peer) {\n        onLocationRequests(peer.getId(), null, false);\n    }\n\n    public void onLocationRequests(String nodeId, Collection<LocationRequestInternal> requests, boolean triggerUpdate) {\n        if (requests == null || requests.isEmpty()) {\n            requestMap.remove(nodeId);\n        } else {\n            requestMap.put(nodeId, requests);\n        }\n        Log.d(TAG, \"Requests: \"+requestMap.entrySet());\n        // TODO actually request\n    }\n\n    public void onCapabilityQuery(String nodeId) {\n        Wearable.MessageApi.sendMessage(getApiClient(), nodeId, PATH_CAPABILITY, writeLocationCapability(new DataMap(), true).toByteArray());\n    }\n\n    private GoogleApiClient getApiClient() {\n        if (apiClient == null) {\n            apiClient = new GoogleApiClient.Builder(this).addApi(Wearable.API).build();\n        }\n        if (!apiClient.isConnected()) {\n            apiClient.connect();\n        }\n        return apiClient;\n    }\n\n    public static DataMap writeLocationCapability(DataMap dataMap, boolean locationCapable) {\n        dataMap.putBoolean(\"CAPABILITY_LOCATION\", locationCapable);\n        return dataMap;\n    }\n\n    public static Collection<LocationRequestInternal> readLocationRequestList(DataMap dataMap, Context context) {\n        if (!dataMap.containsKey(\"REQUEST_LIST\")) {\n            Log.w(TAG, \"malformed DataMap: missing key REQUEST_LIST\");\n            return Collections.emptyList();\n        }\n        List<DataMap> requestMapList = dataMap.getDataMapArrayList(\"REQUEST_LIST\");\n        List<LocationRequestInternal> locationRequests = new ArrayList<LocationRequestInternal>();\n        for (DataMap map : requestMapList) {\n            locationRequests.add(readLocationRequest(map, context));\n        }\n        return locationRequests;\n    }\n\n    private static LocationRequestInternal readLocationRequest(DataMap dataMap, Context context) {\n        LocationRequest locationRequest = new LocationRequest();\n        LocationRequestInternal request = new LocationRequestInternal(locationRequest);\n        request.triggerUpdate = true;\n        request.clients = Collections.emptyList();\n\n        if (dataMap.containsKey(\"PRIORITY\"))\n            locationRequest.setPriority(dataMap.getInt(\"PRIORITY\", 0));\n        if (dataMap.containsKey(\"INTERVAL_MS\"))\n            locationRequest.setInterval(dataMap.getLong(\"INTERVAL_MS\", 0));\n        if (dataMap.containsKey(\"FASTEST_INTERVAL_MS\"))\n            locationRequest.setFastestInterval(dataMap.getLong(\"FASTEST_INTERVAL_MS\", 0));\n        if (dataMap.containsKey(\"MAX_WAIT_TIME_MS\"))\n            locationRequest.setMaxWaitTime(dataMap.getLong(\"MAX_WAIT_TIME_MS\", 0));\n        if (dataMap.containsKey(\"SMALLEST_DISPLACEMENT_METERS\"))\n            locationRequest.setSmallestDisplacement(dataMap.getFloat(\"SMALLEST_DISPLACEMENT_METERS\", 0));\n        if (dataMap.containsKey(\"NUM_UPDATES\"))\n            locationRequest.setNumUpdates(dataMap.getInt(\"NUM_UPDATES\", 0));\n        if (dataMap.containsKey(\"EXPIRATION_DURATION_MS\"))\n            locationRequest.setExpirationDuration(dataMap.getLong(\"EXPIRATION_DURATION_MS\", 0));\n        if (dataMap.containsKey(\"TAG\"))\n            request.tag = dataMap.getString(\"TAG\");\n        if (dataMap.containsKey(\"CLIENTS_PACKAGE_ARRAY\")) {\n            String[] packages = dataMap.getStringArray(\"CLIENTS_PACKAGE_ARRAY\");\n            if (packages != null) {\n                request.clients = new ArrayList<ClientIdentity>();\n                for (String packageName : packages) {\n                    request.clients.add(generateClientIdentity(packageName, context));\n                }\n            }\n        }\n\n        return request;\n    }\n\n    private static ClientIdentity generateClientIdentity(String packageName, Context context) {\n        return null;\n        /*try {\n            return new ClientIdentity(context.getPackageManager().getApplicationInfo(packageName, 0).uid, packageName);\n        } catch (PackageManager.NameNotFoundException e) {\n            Log.w(TAG, \"Unknown client identity: \" + packageName, e);\n            return new ClientIdentity(context.getApplicationInfo().uid, context.getPackageName());\n        }*/\n    }\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2013-2017 microG Project Team\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<manifest />\n"
  },
  {
    "path": "play-services-wearable/src/main/aidl/com/google/android/gms/wearable/Asset.aidl",
    "content": "package com.google.android.gms.wearable;\n\nparcelable Asset;"
  },
  {
    "path": "play-services-wearable/src/main/aidl/com/google/android/gms/wearable/ConnectionConfiguration.aidl",
    "content": "package com.google.android.gms.wearable;\n\nparcelable ConnectionConfiguration;"
  },
  {
    "path": "play-services-wearable/src/main/aidl/com/google/android/gms/wearable/internal/AddListenerRequest.aidl",
    "content": "package com.google.android.gms.wearable.internal;\n\nparcelable AddListenerRequest;"
  },
  {
    "path": "play-services-wearable/src/main/aidl/com/google/android/gms/wearable/internal/AddLocalCapabilityResponse.aidl",
    "content": "package com.google.android.gms.wearable.internal;\n\nparcelable AddLocalCapabilityResponse;"
  },
  {
    "path": "play-services-wearable/src/main/aidl/com/google/android/gms/wearable/internal/AmsEntityUpdateParcelable.aidl",
    "content": "package com.google.android.gms.wearable.internal;\n\nparcelable AmsEntityUpdateParcelable;"
  },
  {
    "path": "play-services-wearable/src/main/aidl/com/google/android/gms/wearable/internal/AncsNotificationParcelable.aidl",
    "content": "package com.google.android.gms.wearable.internal;\n\nparcelable AncsNotificationParcelable;"
  },
  {
    "path": "play-services-wearable/src/main/aidl/com/google/android/gms/wearable/internal/CapabilityInfoParcelable.aidl",
    "content": "package com.google.android.gms.wearable.internal;\n\nparcelable CapabilityInfoParcelable;"
  },
  {
    "path": "play-services-wearable/src/main/aidl/com/google/android/gms/wearable/internal/ChannelEventParcelable.aidl",
    "content": "package com.google.android.gms.wearable.internal;\n\nparcelable ChannelEventParcelable;"
  },
  {
    "path": "play-services-wearable/src/main/aidl/com/google/android/gms/wearable/internal/ChannelReceiveFileResponse.aidl",
    "content": "package com.google.android.gms.wearable.internal;\n\nparcelable ChannelReceiveFileResponse;"
  },
  {
    "path": "play-services-wearable/src/main/aidl/com/google/android/gms/wearable/internal/ChannelSendFileResponse.aidl",
    "content": "package com.google.android.gms.wearable.internal;\n\nparcelable ChannelSendFileResponse;"
  },
  {
    "path": "play-services-wearable/src/main/aidl/com/google/android/gms/wearable/internal/CloseChannelResponse.aidl",
    "content": "package com.google.android.gms.wearable.internal;\n\nparcelable CloseChannelResponse;"
  },
  {
    "path": "play-services-wearable/src/main/aidl/com/google/android/gms/wearable/internal/DeleteDataItemsResponse.aidl",
    "content": "package com.google.android.gms.wearable.internal;\n\nparcelable DeleteDataItemsResponse;"
  },
  {
    "path": "play-services-wearable/src/main/aidl/com/google/android/gms/wearable/internal/GetAllCapabilitiesResponse.aidl",
    "content": "package com.google.android.gms.wearable.internal;\n\nparcelable GetAllCapabilitiesResponse;"
  },
  {
    "path": "play-services-wearable/src/main/aidl/com/google/android/gms/wearable/internal/GetCapabilityResponse.aidl",
    "content": "package com.google.android.gms.wearable.internal;\n\nparcelable GetCapabilityResponse;"
  },
  {
    "path": "play-services-wearable/src/main/aidl/com/google/android/gms/wearable/internal/GetChannelInputStreamResponse.aidl",
    "content": "package com.google.android.gms.wearable.internal;\n\nparcelable GetChannelInputStreamResponse;"
  },
  {
    "path": "play-services-wearable/src/main/aidl/com/google/android/gms/wearable/internal/GetChannelOutputStreamResponse.aidl",
    "content": "package com.google.android.gms.wearable.internal;\n\nparcelable GetChannelOutputStreamResponse;"
  },
  {
    "path": "play-services-wearable/src/main/aidl/com/google/android/gms/wearable/internal/GetCloudSyncOptInOutDoneResponse.aidl",
    "content": "package com.google.android.gms.wearable.internal;\n\nparcelable GetCloudSyncOptInOutDoneResponse;"
  },
  {
    "path": "play-services-wearable/src/main/aidl/com/google/android/gms/wearable/internal/GetCloudSyncOptInStatusResponse.aidl",
    "content": "package com.google.android.gms.wearable.internal;\n\nparcelable GetCloudSyncOptInStatusResponse;"
  },
  {
    "path": "play-services-wearable/src/main/aidl/com/google/android/gms/wearable/internal/GetCloudSyncSettingResponse.aidl",
    "content": "package com.google.android.gms.wearable.internal;\n\nparcelable GetCloudSyncSettingResponse;"
  },
  {
    "path": "play-services-wearable/src/main/aidl/com/google/android/gms/wearable/internal/GetConfigResponse.aidl",
    "content": "package com.google.android.gms.wearable.internal;\n\nparcelable GetConfigResponse;"
  },
  {
    "path": "play-services-wearable/src/main/aidl/com/google/android/gms/wearable/internal/GetConfigsResponse.aidl",
    "content": "package com.google.android.gms.wearable.internal;\n\nparcelable GetConfigsResponse;"
  },
  {
    "path": "play-services-wearable/src/main/aidl/com/google/android/gms/wearable/internal/GetConnectedNodesResponse.aidl",
    "content": "package com.google.android.gms.wearable.internal;\n\nparcelable GetConnectedNodesResponse;"
  },
  {
    "path": "play-services-wearable/src/main/aidl/com/google/android/gms/wearable/internal/GetDataItemResponse.aidl",
    "content": "package com.google.android.gms.wearable.internal;\n\nparcelable GetDataItemResponse;"
  },
  {
    "path": "play-services-wearable/src/main/aidl/com/google/android/gms/wearable/internal/GetFdForAssetResponse.aidl",
    "content": "package com.google.android.gms.wearable.internal;\n\nparcelable GetFdForAssetResponse;"
  },
  {
    "path": "play-services-wearable/src/main/aidl/com/google/android/gms/wearable/internal/GetLocalNodeResponse.aidl",
    "content": "package com.google.android.gms.wearable.internal;\n\nparcelable GetLocalNodeResponse;"
  },
  {
    "path": "play-services-wearable/src/main/aidl/com/google/android/gms/wearable/internal/IChannelStreamCallbacks.aidl",
    "content": "package com.google.android.gms.wearable.internal;\n\ninterface IChannelStreamCallbacks {\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/aidl/com/google/android/gms/wearable/internal/IWearableCallbacks.aidl",
    "content": "package com.google.android.gms.wearable.internal;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.common.data.DataHolder;\nimport com.google.android.gms.wearable.internal.AddLocalCapabilityResponse;\nimport com.google.android.gms.wearable.internal.ChannelReceiveFileResponse;\nimport com.google.android.gms.wearable.internal.ChannelSendFileResponse;\nimport com.google.android.gms.wearable.internal.CloseChannelResponse;\nimport com.google.android.gms.wearable.internal.DeleteDataItemsResponse;\nimport com.google.android.gms.wearable.internal.GetAllCapabilitiesResponse;\nimport com.google.android.gms.wearable.internal.GetCapabilityResponse;\nimport com.google.android.gms.wearable.internal.GetChannelInputStreamResponse;\nimport com.google.android.gms.wearable.internal.GetChannelOutputStreamResponse;\nimport com.google.android.gms.wearable.internal.GetCloudSyncOptInOutDoneResponse;\nimport com.google.android.gms.wearable.internal.GetCloudSyncOptInStatusResponse;\nimport com.google.android.gms.wearable.internal.GetCloudSyncSettingResponse;\nimport com.google.android.gms.wearable.internal.GetConfigResponse;\nimport com.google.android.gms.wearable.internal.GetConfigsResponse;\nimport com.google.android.gms.wearable.internal.GetConnectedNodesResponse;\nimport com.google.android.gms.wearable.internal.GetDataItemResponse;\nimport com.google.android.gms.wearable.internal.GetFdForAssetResponse;\nimport com.google.android.gms.wearable.internal.GetLocalNodeResponse;\nimport com.google.android.gms.wearable.internal.OpenChannelResponse;\nimport com.google.android.gms.wearable.internal.PutDataResponse;\nimport com.google.android.gms.wearable.internal.RemoveLocalCapabilityResponse;\nimport com.google.android.gms.wearable.internal.SendMessageResponse;\nimport com.google.android.gms.wearable.internal.StorageInfoResponse;\n\ninterface IWearableCallbacks {\n    // Config\n    void onGetConfigResponse(in GetConfigResponse response) = 1;\n    void onGetConfigsResponse(in GetConfigsResponse response) = 12;\n\n    // Cloud Sync\n    void onGetCloudSyncOptInOutDoneResponse(in GetCloudSyncOptInOutDoneResponse response) = 27;\n    void onGetCloudSyncSettingResponse(in GetCloudSyncSettingResponse response) = 28;\n    void onGetCloudSyncOptInStatusResponse(in GetCloudSyncOptInStatusResponse response) = 29;\n\n    // Data\n    void onPutDataResponse(in PutDataResponse response) = 2;\n    void onGetDataItemResponse(in GetDataItemResponse response) = 3;\n    void onDataItemChanged(in DataHolder dataHolder) = 4;\n    void onDeleteDataItemsResponse(in DeleteDataItemsResponse response) = 5;\n    void onSendMessageResponse(in SendMessageResponse response) = 6;\n    void onGetFdForAssetResponse(in GetFdForAssetResponse response) = 7;\n    void onGetLocalNodeResponse(in GetLocalNodeResponse response) = 8;\n    void onGetConnectedNodesResponse(in GetConnectedNodesResponse response) = 9;\n\n    // Channels\n    void onOpenChannelResponse(in OpenChannelResponse response) = 13;\n    void onCloseChannelResponse(in CloseChannelResponse response) = 14;\n    void onGetChannelInputStreamResponse(in GetChannelInputStreamResponse response) = 16;\n    void onGetChannelOutputStreamResponse(in GetChannelOutputStreamResponse response) = 17;\n    void onChannelReceiveFileResponse(in ChannelReceiveFileResponse response) = 18;\n    void onChannelSendFileResponse(in ChannelSendFileResponse response) = 19;\n\n    void onStatus(in Status status) = 10;\n    void onStorageInfoResponse(in StorageInfoResponse response) = 11;\n\n    // Capabilities\n    void onGetCapabilityResponse(in GetCapabilityResponse response) = 21;\n    void onGetAllCapabilitiesResponse(in GetAllCapabilitiesResponse response) = 22;\n    void onAddLocalCapabilityResponse(in AddLocalCapabilityResponse response) = 25;\n    void onRemoveLocalCapabilityResponse(in RemoveLocalCapabilityResponse response) = 26;\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/aidl/com/google/android/gms/wearable/internal/IWearableListener.aidl",
    "content": "package com.google.android.gms.wearable.internal;\n\nimport com.google.android.gms.common.data.DataHolder;\nimport com.google.android.gms.wearable.internal.AmsEntityUpdateParcelable;\nimport com.google.android.gms.wearable.internal.AncsNotificationParcelable;\nimport com.google.android.gms.wearable.internal.CapabilityInfoParcelable;\nimport com.google.android.gms.wearable.internal.ChannelEventParcelable;\nimport com.google.android.gms.wearable.internal.MessageEventParcelable;\nimport com.google.android.gms.wearable.internal.NodeParcelable;\n\ninterface IWearableListener {\n    void onDataChanged(in DataHolder data) = 0;\n    void onMessageReceived(in MessageEventParcelable messageEvent) = 1;\n    void onPeerConnected(in NodeParcelable node) = 2;\n    void onPeerDisconnected(in NodeParcelable node) = 3;\n    void onConnectedNodes(in List<NodeParcelable> nodes) = 4;\n    void onNotificationReceived(in AncsNotificationParcelable notification) = 5;\n    void onChannelEvent(in ChannelEventParcelable channelEvent) = 6;\n    void onConnectedCapabilityChanged(in CapabilityInfoParcelable capabilityInfo) = 7;\n    void onEntityUpdate(in AmsEntityUpdateParcelable update) = 8;\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/aidl/com/google/android/gms/wearable/internal/IWearableService.aidl",
    "content": "package com.google.android.gms.wearable.internal;\n\nimport com.google.android.gms.wearable.Asset;\nimport com.google.android.gms.wearable.ConnectionConfiguration;\nimport com.google.android.gms.wearable.internal.AddListenerRequest;\nimport com.google.android.gms.wearable.internal.AncsNotificationParcelable;\nimport com.google.android.gms.wearable.internal.PutDataRequest;\nimport com.google.android.gms.wearable.internal.RemoveListenerRequest;\nimport com.google.android.gms.wearable.internal.IChannelStreamCallbacks;\nimport com.google.android.gms.wearable.internal.IWearableCallbacks;\nimport com.google.android.gms.wearable.internal.IWearableService;\n\ninterface IWearableService {\n    // Configs\n    void putConfig(IWearableCallbacks callbacks, in ConnectionConfiguration config) = 19;\n    void deleteConfig(IWearableCallbacks callbacks, String name) = 20;\n    void getConfigs(IWearableCallbacks callbacks) = 21;\n    void enableConfig(IWearableCallbacks callbacks, String name) = 22;\n    void disableConfig(IWearableCallbacks callbacks, String name) = 23;\n\n    // DataItems\n    void putData(IWearableCallbacks callbacks, in PutDataRequest request) = 5;\n    void getDataItem(IWearableCallbacks callbacks, in Uri uri) = 6;\n    void getDataItems(IWearableCallbacks callbacks) = 7;\n    void getDataItemsByUri(IWearableCallbacks callbacks, in Uri uri) = 8;\n    void getDataItemsByUriWithFilter(IWearableCallbacks callbacks, in Uri uri, int typeFilter) = 39;\n    void deleteDataItems(IWearableCallbacks callbacks, in Uri uri) = 10;\n    void deleteDataItemsWithFilter(IWearableCallbacks callbacks, in Uri uri, int typeFilter) = 40;\n\n    void sendMessage(IWearableCallbacks callbacks, String targetNodeId, String path, in byte[] data) = 11;\n    void getFdForAsset(IWearableCallbacks callbacks, in Asset asset) = 12;\n\n    void getLocalNode(IWearableCallbacks callbacks) = 13;\n    void getConnectedNodes(IWearableCallbacks callbacks) = 14;\n\n    // Capabilties\n    void getConnectedCapability(IWearableCallbacks callbacks, String capability, int nodeFilter) = 41;\n    void getAllCapabilities(IWearableCallbacks callbacks, int nodeFilter) = 42;\n    void addLocalCapability(IWearableCallbacks callbacks, String capability) = 45;\n    void removeLocalCapability(IWearableCallbacks callbacks, String capability) = 46;\n\n    void addListener(IWearableCallbacks callbacks, in AddListenerRequest request) = 15;\n    void removeListener(IWearableCallbacks callbacks, in RemoveListenerRequest request) = 16;\n\n    void getStorageInformation(IWearableCallbacks callbacks) = 17;\n    void clearStorage(IWearableCallbacks callbacks) = 18;\n\n    void endCall(IWearableCallbacks callbacks) = 24;\n    void acceptRingingCall(IWearableCallbacks callbacks) = 25;\n    void silenceRinger(IWearableCallbacks callbacks) = 29;\n\n    // Apple Notification Center Service\n    void injectAncsNotificationForTesting(IWearableCallbacks callbacks, in AncsNotificationParcelable notification) = 26;\n    void doAncsPositiveAction(IWearableCallbacks callbacks, int i) = 27;\n    void doAncsNegativeAction(IWearableCallbacks callbacks, int i) = 28;\n\n    // Channels\n    void openChannel(IWearableCallbacks callbacks, String s1, String s2) = 30;\n    void closeChannel(IWearableCallbacks callbacks, String s) = 31;\n    void closeChannelWithError(IWearableCallbacks callbacks, String s, int errorCode) = 32;\n    void getChannelInputStream(IWearableCallbacks callbacks, IChannelStreamCallbacks channelCallbacks, String s) = 33;\n    void getChannelOutputStream(IWearableCallbacks callbacks, IChannelStreamCallbacks channelCallbacks, String s) = 34;\n    void writeChannelInputToFd(IWearableCallbacks callbacks, String s, in ParcelFileDescriptor fd) = 37;\n    void readChannelOutputFromFd(IWearableCallbacks callbacks, String s, in ParcelFileDescriptor fd, long l1, long l2) = 38;\n\n    void syncWifiCredentials(IWearableCallbacks callbacks) = 36;\n\n    // Cloud Sync\n    void optInCloudSync(IWearableCallbacks callbacks, boolean enable) = 47;\n    void getCloudSyncOptInDone(IWearableCallbacks callbacks) = 48; // deprecated\n    void setCloudSyncSetting(IWearableCallbacks callbacks, boolean enable) = 49;\n    void getCloudSyncSetting(IWearableCallbacks callbacks) = 50;\n    void getCloudSyncOptInStatus(IWearableCallbacks callbacks) = 51;\n\n    void sendRemoteCommand(IWearableCallbacks callbacks, byte b) = 52;\n\n    // deprecated Connection\n    void putConnection(IWearableCallbacks callbacks, in ConnectionConfiguration config) = 1;\n    void getConnection(IWearableCallbacks callbacks) = 2;\n    void enableConnection(IWearableCallbacks callbacks) = 3;\n    void disableConnection(IWearableCallbacks callbacks) = 4;\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/aidl/com/google/android/gms/wearable/internal/MessageEventParcelable.aidl",
    "content": "package com.google.android.gms.wearable.internal;\n\nparcelable MessageEventParcelable;"
  },
  {
    "path": "play-services-wearable/src/main/aidl/com/google/android/gms/wearable/internal/NodeParcelable.aidl",
    "content": "package com.google.android.gms.wearable.internal;\n\nparcelable NodeParcelable;"
  },
  {
    "path": "play-services-wearable/src/main/aidl/com/google/android/gms/wearable/internal/OpenChannelResponse.aidl",
    "content": "package com.google.android.gms.wearable.internal;\n\nparcelable OpenChannelResponse;"
  },
  {
    "path": "play-services-wearable/src/main/aidl/com/google/android/gms/wearable/internal/PutDataRequest.aidl",
    "content": "package com.google.android.gms.wearable.internal;\n\nparcelable PutDataRequest;"
  },
  {
    "path": "play-services-wearable/src/main/aidl/com/google/android/gms/wearable/internal/PutDataResponse.aidl",
    "content": "package com.google.android.gms.wearable.internal;\n\nparcelable PutDataResponse;"
  },
  {
    "path": "play-services-wearable/src/main/aidl/com/google/android/gms/wearable/internal/RemoveListenerRequest.aidl",
    "content": "package com.google.android.gms.wearable.internal;\n\nparcelable RemoveListenerRequest;"
  },
  {
    "path": "play-services-wearable/src/main/aidl/com/google/android/gms/wearable/internal/RemoveLocalCapabilityResponse.aidl",
    "content": "package com.google.android.gms.wearable.internal;\n\nparcelable RemoveLocalCapabilityResponse;"
  },
  {
    "path": "play-services-wearable/src/main/aidl/com/google/android/gms/wearable/internal/SendMessageResponse.aidl",
    "content": "package com.google.android.gms.wearable.internal;\n\nparcelable SendMessageResponse;"
  },
  {
    "path": "play-services-wearable/src/main/aidl/com/google/android/gms/wearable/internal/StorageInfoResponse.aidl",
    "content": "package com.google.android.gms.wearable.internal;\n\nparcelable StorageInfoResponse;"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/AmsEntityUpdate.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable;\n\npublic interface AmsEntityUpdate {\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/AncsNotification.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable;\n\npublic interface AncsNotification {\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/Asset.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable;\n\nimport android.net.Uri;\nimport android.os.ParcelFileDescriptor;\n\nimport com.google.android.gms.wearable.internal.PutDataRequest;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\nimport java.util.Arrays;\n\n/**\n * An asset is a binary blob shared between data items that is replicated across the wearable\n * network on demand.\n * <p/>\n * It may represent an asset not yet added with the Android Wear network. DataItemAssets\n * are representations of an asset after it has been added to the network through a\n * {@link PutDataRequest}.\n */\n@PublicApi\npublic class Asset extends AutoSafeParcelable {\n\n    @SafeParceled(1)\n    private int versionCode = 1;\n    @SafeParceled(2)\n    @PublicApi(exclude = true)\n    public byte[] data;\n    @SafeParceled(3)\n    private String digest;\n    @SafeParceled(4)\n    private ParcelFileDescriptor fd;\n    @SafeParceled(5)\n    private Uri uri;\n\n    private Asset() {\n    }\n\n    private Asset(byte[] data, String digest, ParcelFileDescriptor fd, Uri uri) {\n        this.data = data;\n        this.digest = digest;\n        this.fd = fd;\n        this.uri = uri;\n    }\n\n    /**\n     * Creates an Asset using a byte array.\n     */\n    public static Asset createFromBytes(byte[] assetData) {\n        return null;\n    }\n\n    /**\n     * Creates an Asset using a file descriptor. The FD should be closed after being successfully\n     * sent in a putDataItem request.\n     */\n    public static Asset createFromFd(ParcelFileDescriptor fd) {\n        if (fd == null) {\n            throw new IllegalArgumentException(\"Asset fd cannot be null\");\n        }\n        return new Asset(null, null, fd, null);\n    }\n\n    /**\n     * Create an Asset using an existing Asset's digest.\n     */\n    public static Asset createFromRef(String digest) {\n        if (digest == null) {\n            throw new IllegalArgumentException(\"Asset digest cannot be null\");\n        }\n        return new Asset(null, digest, null, null);\n    }\n\n    /**\n     * Creates an Asset using a content URI. Google Play services must have permission to read this\n     * Uri.\n     */\n    public static Asset createFromUri(Uri uri) {\n        return null;\n    }\n\n    /**\n     * @return the digest associated with the asset data. A digest is a content identifier used to\n     * identify the asset across devices.\n     */\n    public String getDigest() {\n        return digest;\n    }\n\n    /**\n     * @return the file descriptor referencing the asset.\n     */\n    public ParcelFileDescriptor getFd() {\n        return fd;\n    }\n\n    /**\n     * @return the uri referencing the asset data.\n     */\n    public Uri getUri() {\n        return uri;\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        Asset asset = (Asset) o;\n\n        if (!Arrays.equals(data, asset.data)) return false;\n        if (digest != null ? !digest.equals(asset.digest) : asset.digest != null) return false;\n        if (fd != null ? !fd.equals(asset.fd) : asset.fd != null) return false;\n        return !(uri != null ? !uri.equals(asset.uri) : asset.uri != null);\n\n    }\n\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(new Object[]{data, digest, fd, uri});\n    }\n\n    @Override\n    public String toString() {\n        final StringBuilder sb = new StringBuilder();\n        sb.append(\"Asset[@\")\n                .append(Integer.toHexString(hashCode()))\n                .append(\", \")\n                .append(digest != null ? digest : \"nodigest\");\n        if (this.data != null) sb.append(\", size=\").append(data.length);\n        if (this.fd != null) sb.append(\", fd=\").append(fd);\n        if (this.uri != null) sb.append(\", uri=\").append(uri);\n        return sb.append(\"]\").toString();\n    }\n\n    public static final Creator<Asset> CREATOR = new AutoCreator<Asset>(Asset.class);\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/CapabilityApi.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable;\n\nimport android.net.Uri;\n\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.GoogleApiClient.Builder;\nimport com.google.android.gms.common.api.PendingResult;\nimport com.google.android.gms.common.api.Result;\nimport com.google.android.gms.common.api.Status;\n\nimport org.microg.gms.common.PublicApi;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.Map;\n\n/**\n * Exposes an API to learn about capabilities provided by nodes on the Wear network.\n * <p/>\n * Capabilities are local to an application.\n */\n@PublicApi\npublic interface CapabilityApi {\n    /**\n     * Capability changed action for use in manifest-based listener filters.\n     * <p/>\n     * Capability events do not support filtering by host, but can be filtered by path.\n     *\n     * @see WearableListenerService\n     */\n    String ACTION_CAPABILITY_CHANGED = \"com.google.android.gms.wearable.CAPABILITY_CHANGED\";\n\n    /**\n     * Filter type for {@link #getCapability(GoogleApiClient, String, int)}, {@link #getAllCapabilities(GoogleApiClient, int)}:\n     * If this filter is set then the full set of nodes that declare the given capability will be\n     * included in the capability's CapabilityInfo.\n     */\n    int FILTER_ALL = 0;\n\n    /**\n     * Filter type for {@link #addListener(GoogleApiClient, CapabilityListener, Uri, int)}, if this\n     * filter is set, the given URI will be taken as a literal path, and the operation will apply\n     * to the matching capability only.\n     */\n    int FILTER_LITERAL = 0;\n\n    /**\n     * Filter type for {@link #addListener(GoogleApiClient, CapabilityListener, Uri, int)}, if this\n     * filter is set, the given URI will be taken as a path prefix, and the operation will apply\n     * to all matching capabilities.\n     */\n    int FILTER_PREFIX = 1;\n\n    /**\n     * Filter type for {@link #getCapability(GoogleApiClient, String, int)}, {@link #getAllCapabilities(GoogleApiClient, int):\n     * If this filter is set then only reachable nodes that declare the given capability will be\n     * included in the capability's CapabilityInfo.\n     */\n    int FILTER_REACHABLE = 1;\n\n    /**\n     * Registers a listener to be notified of a specific capability being added to or removed from\n     * the Wear network. Calls to this method should be balanced with {@link #removeCapabilityListener(GoogleApiClient, CapabilityListener, String)}\n     * to avoid leaking resources.\n     * <p/>\n     * Listener events will be called on the main thread, or the handler specified on {@code client}\n     * when it was built (using {@link Builder#setHandler(Handler)}).\n     * <p/>\n     * Callers wishing to be notified of events in the background should use {@link WearableListenerService}.\n     */\n    PendingResult<Status> addCapabilityListener(GoogleApiClient client, CapabilityListener listener, String capability);\n\n    /**\n     * Registers a listener to be notified of capabilities being added to or removed from the Wear\n     * network. Calls to this method should be balanced with {@link #removeListener(GoogleApiClient, CapabilityListener)}\n     * to avoid leaking resources.\n     * <p/>\n     * {@code uri} and {@code filterType} can be used to filter the capability changes sent to the\n     * listener. For example, if {@code uri} and {@code filterType} create a prefix filter, then\n     * only capabilities matching that prefix will be notified. The {@code uri} follows the rules\n     * of the {@code <data>} element of {@code <intent-filter>}. The path is ignored if a URI host\n     * is not specified. To match capabilities by name or name prefix, the host must be {@code *}. i.e:\n     * <p/>\n     * <pre>wear://* /<capability_name></pre>\n     * Listener events will be called on the main thread, or the handler specified on {@code client}\n     * when it was built (using {@link Builder#setHandler(Handler)}).\n     *\n     * Callers wishing to be notified of events in the background should use WearableListenerService.\n     */\n    PendingResult<Status> addListener(GoogleApiClient client, CapabilityListener listener, Uri uri, @CapabilityFilterType int filterType);\n\n    /**\n     * Announces that a capability has become available on the local node.\n     */\n    PendingResult<AddLocalCapabilityResult> addLocalCapability(GoogleApiClient client, String capability);\n\n    /**\n     * Returns information about all capabilities, including the nodes that declare those\n     * capabilities. The filter parameter controls whether all nodes are returned, {@link #FILTER_ALL},\n     * or only those that are currently reachable by this node, {@link #FILTER_REACHABLE}.\n     * <p/>\n     * The local node will never be returned in the set of nodes.\n     */\n    PendingResult<GetAllCapabilitiesResult> getAllCapabilities(GoogleApiClient client, @NodeFilterType int nodeFilter);\n\n    /**\n     * Returns information about a capabilities, including the nodes that declare this capability.\n     * The filter parameter controls whether all nodes are returned, {@link #FILTER_ALL}, or only\n     * those that are currently reachable by this node, {@link #FILTER_REACHABLE}.\n     * <p/>\n     * The local node will never be returned in the set of nodes.\n     */\n    PendingResult<GetCapabilityResult> getCapability(GoogleApiClient client, String capability, @NodeFilterType int nodeFilter);\n\n    /**\n     * Removes a listener which was previously added through {@link #addCapabilityListener(GoogleApiClient, CapabilityListener, String)}.\n     * The listener is only removed from listening for the capability provided and will continue to\n     * receive messages for any other capabilities it was previously registered for that have not\n     * also been removed.\n     */\n    PendingResult<Status> removeCapabilityListener(GoogleApiClient client, CapabilityListener listener, String capability);\n\n    /**\n     * Removes a listener which was previously added through {@link #addListener(GoogleApiClient, CapabilityListener, Uri, int)}.\n     * The listener is only removed from listening for the capability provided and will continue to\n     * receive messages for any other capabilities it was previously registered for that have not\n     * also been removed.\n     */\n    PendingResult<Status> removeListener(GoogleApiClient client, CapabilityListener listener);\n\n    /**\n     * Announces that a capability is no longer available on the local node. Note: this will not\n     * remove any capabilities announced in the Manifest for an app.\n     */\n    PendingResult<RemoveLocalCapabilityResult> removeLocalCapability(GoogleApiClient client, String capability);\n\n    /**\n     * Result returned from {@link #addLocalCapability(GoogleApiClient, String)}\n     */\n    interface AddLocalCapabilityResult extends Result {\n    }\n\n    @Retention(RetentionPolicy.SOURCE)\n    @interface CapabilityFilterType {\n    }\n\n    /**\n     * Listener for changes in the reachable nodes providing a capability.\n     */\n    interface CapabilityListener {\n        void onCapabilityChanged(CapabilityInfo capabilityInfo);\n    }\n\n    /**\n     * Result returned from {@link #getAllCapabilities(GoogleApiClient, int)}\n     */\n    interface GetAllCapabilitiesResult extends Result {\n        Map<String, CapabilityInfo> getAllCapabilities();\n    }\n\n    /**\n     * Result returned from {@link #getCapability(GoogleApiClient, String, int)}\n     */\n    interface GetCapabilityResult extends Result {\n        CapabilityInfo getCapability();\n    }\n\n    @Retention(RetentionPolicy.SOURCE)\n    @interface NodeFilterType {\n    }\n\n    /**\n     * Result returned from {@link #removeLocalCapability(GoogleApiClient, String)}\n     */\n    interface RemoveLocalCapabilityResult extends Result {\n    }\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/CapabilityInfo.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable;\n\nimport java.util.Set;\n\n/**\n * Information about a Capability on the network and where it is available.\n */\npublic interface CapabilityInfo {\n    /**\n     * Returns the name of the capability.\n     */\n    String getName();\n\n    /**\n     * Returns the set of nodes for the capability. Disconnected nodes may or may not be included in the set.\n     */\n    Set<Node> getNodes();\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/Channel.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable;\n\nimport android.net.Uri;\nimport android.os.Parcelable;\n\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.PendingResult;\nimport com.google.android.gms.common.api.Releasable;\nimport com.google.android.gms.common.api.Result;\nimport com.google.android.gms.common.api.Status;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\n/**\n * A channel created through {@link ChannelApi#openChannel(GoogleApiClient, String, String)}.\n * <p/>\n * The implementation of this interface is parcelable and immutable, and implements reasonable {@link #equals(Object)}\n * and {@link #hashCode()} methods, so can be used in collections.\n */\npublic interface Channel extends Parcelable {\n\n    PendingResult<Status> addListener(GoogleApiClient client, ChannelApi.ChannelListener listener);\n\n    PendingResult<Status> close(GoogleApiClient client, int errorCode);\n\n    PendingResult<Status> close(GoogleApiClient client);\n\n    PendingResult<GetInputStreamResult> getInputStream(GoogleApiClient client);\n\n    PendingResult<GetOutputStreamResult> getOutputStream(GoogleApiClient client);\n\n    String getPath();\n\n    PendingResult<Status> receiveFile(GoogleApiClient client, Uri uri, boolean append);\n\n    PendingResult<Status> removeListener(GoogleApiClient client, ChannelApi.ChannelListener listener);\n\n    PendingResult<Status> sendFile(GoogleApiClient client, Uri uri);\n\n    PendingResult<Status> sendFile(GoogleApiClient client, Uri uri, long startOffset, long length);\n\n    interface GetInputStreamResult extends Releasable, Result {\n        /**\n         * Returns an input stream which can read data from the remote node. The stream should be\n         * closed when no longer needed. This method will only return {@code null} if this result's\n         * {@linkplain #getStatus() status} was not {@linkplain Status#isSuccess() success}.\n         * <p/>\n         * The returned stream will throw {@link IOException} on read if any connection errors\n         * occur. This exception might be a {@link ChannelIOException}.\n         * <p/>\n         * Since data for this stream comes over the network, reads may block for a long time.\n         * <p/>\n         * Multiple calls to this method will return the same instance.\n         */\n        InputStream getInputStream();\n    }\n\n    interface GetOutputStreamResult extends Releasable, Result {\n        /**\n         * Returns an output stream which can send data to a remote node. The stream should be\n         * closed when no longer needed. This method will only return {@code null} if this result's\n         * {@linkplain #getStatus() status} was not {@linkplain Status#isSuccess() success}.\n         * <p/>\n         * The returned stream will throw {@link IOException} on read if any connection errors\n         * occur. This exception might be a {@link ChannelIOException}.\n         * <p/>\n         * Since data for this stream comes over the network, reads may block for a long time.\n         * <p/>\n         * Data written to this stream is buffered. If you wish to send the current data without\n         * waiting for the buffer to fill up, {@linkplain OutputStream#flush() flush} the stream.\n         * <p/>\n         * Multiple calls to this method will return the same instance.\n         */\n        OutputStream getOutputStream();\n    }\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/ChannelApi.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable;\n\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.GoogleApiClient.Builder;\nimport com.google.android.gms.common.api.PendingResult;\nimport com.google.android.gms.common.api.Result;\nimport com.google.android.gms.common.api.Status;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\n/**\n * Client interface for Wearable Channel API. Allows apps on a wearable device to send and receive\n * data from other wearable nodes.\n * <p/>\n * Channels are bidirectional. Each side, both the initiator and the receiver may both read and\n * write to the channel by using {@link Channel#getOutputStream(GoogleApiClient)} and {@link Channel#getInputStream(GoogleApiClient)}.\n * Once a channel is established, the API for the initiator and receiver are identical.\n * <p/>\n * Channels are only available when the wearable nodes are connected. When the remote node\n * disconnects, all existing channels will be closed. Any listeners (added through {@link #addListener(GoogleApiClient, ChannelListener)}\n * and any installed {@link WearableListenerService}) will be notified of the channel closing.\n */\npublic interface ChannelApi {\n    /**\n     * Channel action for use in listener filters.\n     *\n     * @see WearableListenerService\n     */\n    String ACTION_CHANNEL_EVENT = \"com.google.android.gms.wearable.CHANNEL_EVENT\";\n\n    /**\n     * Registers a listener to be notified of channel events. Calls to this method should be\n     * balanced with calls to {@link #removeListener(GoogleApiClient, ChannelListener)} to avoid\n     * leaking resources.\n     * <p/>\n     * Listener events will be called on the main thread, or the handler specified on {@code client}\n     * when it was built (using {@link Builder#setHandler(Handler)}).\n     * <p/>\n     * Callers wishing to be notified of events in the background should use {@link WearableListenerService}.\n     *\n     * @param client   a connected client\n     * @param listener a listener which will be notified of changes to any channel\n     */\n    PendingResult<Status> addListener(GoogleApiClient client, ChannelListener listener);\n\n    /**\n     * Opens a channel to exchange data with a remote node.\n     * <p/>\n     * Channel which are no longer needed should be closed using {@link Channel#close(GoogleApiClient)}.\n     * <p/>\n     * This call involves a network round trip, so may be long running. {@code client} must remain\n     * connected during that time, or the request will be cancelled (like any other Play Services\n     * API calls).\n     *\n     * @param client a connected client\n     * @param nodeId the node ID of a wearable node, as returned from {@link NodeApi#getConnectedNodes(GoogleApiClient)}\n     * @param path   an app-specific identifier for the channel\n     */\n    PendingResult<OpenChannelResult> openChannel(GoogleApiClient client, String nodeId, String path);\n\n    /**\n     * Removes a listener which was previously added through {@link #addListener(GoogleApiClient, ChannelListener)}.\n     *\n     * @param client   a connected client\n     * @param listener a listener which was added using {@link #addListener(GoogleApiClient, ChannelListener)}\n     */\n    PendingResult<Status> removeListener(GoogleApiClient client, ChannelListener listener);\n\n    /**\n     * A listener which will be notified on changes to channels.\n     */\n    interface ChannelListener {\n        /**\n         * Value passed to {@link #onChannelClosed(Channel, int, int)}, {@link #onInputClosed(Channel, int, int)}\n         * and {@link #onOutputClosed(Channel, int, int)} when the closing is due to a remote node\n         * being disconnected.\n         */\n        int CLOSE_REASON_DISCONNECTED = 1;\n\n        /**\n         * Value passed to {@link #onChannelClosed(Channel, int, int)}, {@link #onInputClosed(Channel, int, int)}\n         * and {@link #onOutputClosed(Channel, int, int)} when the stream is closed due to the\n         * local node calling {@link Channel#close(GoogleApiClient)} or {@link Channel#close(GoogleApiClient, int)}.\n         */\n        int CLOSE_REASON_LOCAL_CLOSE = 3;\n\n        /**\n         * Value passed to {@link #onInputClosed(Channel, int, int)} or {@link #onOutputClosed(Channel, int, int)}\n         * (but not {@link #onChannelClosed(Channel, int, int)}), when the stream was closed under\n         * normal conditions, e.g the whole file was read, or the OutputStream on the remote node\n         * was closed normally.\n         */\n        int CLOSE_REASON_NORMAL = 0;\n\n        /**\n         * Value passed to {@link #onChannelClosed(Channel, int, int)}, {@link #onInputClosed(Channel, int, int)}\n         * and {@link #onOutputClosed(Channel, int, int)} when the stream is closed due to the\n         * remote node calling {@link Channel#close(GoogleApiClient)} or {@link Channel#close(GoogleApiClient, int)}.\n         */\n        int CLOSE_REASON_REMOTE_CLOSE = 2;\n\n        /**\n         * Called when a channel is closed. This can happen through an explicit call to {@link Channel#close(GoogleApiClient)}\n         * or {@link #close(GoogleApiClient, int)} on either side of the connection, or due to\n         * disconnecting from the remote node.\n         *\n         * @param closeReason          the reason for the channel closing. One of {@link #CLOSE_REASON_DISCONNECTED},\n         *                             {@link #CLOSE_REASON_REMOTE_CLOSE}, or {@link #CLOSE_REASON_LOCAL_CLOSE}.\n         * @param appSpecificErrorCode the error code specified on {@link Channel#close(GoogleApiClient, int)},\n         *                             or 0 if closeReason is {@link #CLOSE_REASON_DISCONNECTED}.\n         */\n        void onChannelClosed(Channel channel, int closeReason, int appSpecificErrorCode);\n\n        /**\n         * Called when a new channel is opened by a remote node.\n         */\n        void onChannelOpened(Channel channel);\n\n        /**\n         * Called when the input side of a channel is closed.\n         *\n         * @param closeReason          the reason for the channel closing. One of {@link #CLOSE_REASON_DISCONNECTED},\n         *                             {@link #CLOSE_REASON_REMOTE_CLOSE}, {@link #CLOSE_REASON_LOCAL_CLOSE}\n         *                             or {@link #CLOSE_REASON_NORMAL}.\n         * @param appSpecificErrorCode the error code specified on {@link Channel#close(GoogleApiClient, int)},\n         *                             or 0 if closeReason is {@link #CLOSE_REASON_DISCONNECTED} or\n         *                             {@link #CLOSE_REASON_NORMAL}.\n         */\n        void onInputClosed(Channel channel, @CloseReason int closeReason, int appSpecificErrorCode);\n\n        /**\n         * Called when the output side of a channel is closed.\n         *\n         * @param closeReason          the reason for the channel closing. One of {@link #CLOSE_REASON_DISCONNECTED},\n         *                             {@link #CLOSE_REASON_REMOTE_CLOSE}, {@link #CLOSE_REASON_LOCAL_CLOSE}\n         *                             or {@link #CLOSE_REASON_NORMAL}.\n         * @param appSpecificErrorCode the error code specified on {@link Channel#close(GoogleApiClient, int)},\n         *                             or 0 if closeReason is {@link #CLOSE_REASON_DISCONNECTED} or\n         *                             {@link #CLOSE_REASON_NORMAL}.\n         */\n        void onOutputClosed(Channel channel, @CloseReason int closeReason, int appSpecificErrorCode);\n    }\n\n    /**\n     * An annotation for values passed to {@link ChannelListener#onChannelClosed(Channel, int, int)},\n     * and other methods on the {@link ChannelListener} interface. Annotated method parameters will\n     * always take one of the following values:\n     * <ul>\n     * <li>{@link ChannelListener#CLOSE_REASON_DISCONNECTED}</li>\n     * <li>{@link ChannelListener#CLOSE_REASON_NORMAL}</li>\n     * <li>{@link ChannelListener#CLOSE_REASON_LOCAL_CLOSE}</li>\n     * <li>{@link ChannelListener#CLOSE_REASON_REMOTE_CLOSE}</li>\n     * </ul>\n     */\n    @Retention(RetentionPolicy.SOURCE)\n    @interface CloseReason {\n    }\n\n    /**\n     * Result of {@link #openChannel(GoogleApiClient, String, String)}.\n     */\n    interface OpenChannelResult extends Result {\n        /**\n         * Returns the newly created channel, or {@code null}, if the connection couldn't be opened.\n         */\n        Channel getChannel();\n    }\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/ChannelIOException.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable;\n\nimport com.google.android.gms.wearable.ChannelApi.ChannelListener;\n\nimport java.io.IOException;\n\n/**\n * A subclass of {@link IOException} which can be thrown from the streams returned by\n * {@link Channel#getInputStream(GoogleApiClient)} and {@link Channel#getOutputStream(GoogleApiClient)}.\n */\npublic class ChannelIOException extends IOException {\n\n    private int closeReason;\n    private int appSpecificErrorCode;\n\n    public ChannelIOException(String message, int closeReason, int appSpecificErrorCode) {\n        super(message);\n        this.closeReason = closeReason;\n        this.appSpecificErrorCode = appSpecificErrorCode;\n    }\n\n    /**\n     * Returns the app-specific error code passed to {@link Channel#close(GoogleApiClient, int)} if\n     * that's the reason for the stream closing, or {@code 0} otherwise.\n     */\n    public int getAppSpecificErrorCode() {\n        return appSpecificErrorCode;\n    }\n\n    /**\n     * Returns one of {@link ChannelListener#CLOSE_REASON_NORMAL}, {@link ChannelListener#CLOSE_REASON_DISCONNECTED},\n     * {@link ChannelListener#CLOSE_REASON_REMOTE_CLOSE}, or {@link ChannelListener#CLOSE_REASON_LOCAL_CLOSE},\n     * to indicate the reason for the stream closing.\n     */\n    public int getCloseReason() {\n        return closeReason;\n    }\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/ConnectionConfiguration.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class ConnectionConfiguration extends AutoSafeParcelable {\n\n    @SafeParceled(1)\n    private int versionCode = 1;\n    @SafeParceled(2)\n    public final String name;\n    @SafeParceled(3)\n    public final String address;\n    @SafeParceled(4)\n    public final int type;\n    @SafeParceled(5)\n    public final int role;\n    @SafeParceled(6)\n    public final boolean enabled;\n    @SafeParceled(7)\n    public boolean connected = false;\n    @SafeParceled(8)\n    public String peerNodeId;\n    @SafeParceled(9)\n    public boolean btlePriority = true;\n    @SafeParceled(10)\n    public String nodeId;\n\n    private ConnectionConfiguration() {\n        name = address = null;\n        type = role = 0;\n        enabled = false;\n    }\n\n    public ConnectionConfiguration(String name, String address, int type, int role, boolean enabled) {\n        this.name = name;\n        this.address = address;\n        this.type = type;\n        this.role = role;\n        this.enabled = enabled;\n    }\n\n    public ConnectionConfiguration(String name, String address, int type, int role, boolean enabled, String nodeId) {\n        this.name = name;\n        this.address = address;\n        this.type = type;\n        this.role = role;\n        this.enabled = enabled;\n        this.nodeId = nodeId;\n    }\n\n    @Override\n    public String toString() {\n        final StringBuilder sb = new StringBuilder(\"ConnectionConfiguration{\");\n        sb.append(\"name='\").append(name).append('\\'');\n        sb.append(\", address='\").append(address).append('\\'');\n        sb.append(\", type=\").append(type);\n        sb.append(\", role=\").append(role);\n        sb.append(\", enabled=\").append(enabled);\n        sb.append(\", connected=\").append(connected);\n        sb.append(\", peerNodeId='\").append(peerNodeId).append('\\'');\n        sb.append(\", btlePriority=\").append(btlePriority);\n        sb.append(\", nodeId='\").append(nodeId).append('\\'');\n        sb.append('}');\n        return sb.toString();\n    }\n\n    public static final Creator<ConnectionConfiguration> CREATOR = new AutoCreator<ConnectionConfiguration>(ConnectionConfiguration.class);\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/DataApi.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable;\n\nimport android.net.Uri;\nimport android.os.ParcelFileDescriptor;\n\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.PendingResult;\nimport com.google.android.gms.common.api.Result;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.common.data.Freezable;\nimport com.google.android.gms.wearable.internal.PutDataRequest;\n\nimport org.microg.gms.common.PublicApi;\n\nimport java.io.InputStream;\n\n/**\n * Exposes an API for components to read or write data items and assets.\n * <p/>\n * A {@link DataItem} is synchronized across all devices in an Android Wear network. It is possible\n * to set data items while not connected to any nodes. Those data items will be synchronized when\n * the nodes eventually come online.\n * <p/>\n * Data items are private to the application that created them, and are only accessible by that\n * application on other nodes. They should generally be small in size, relying on assets for the\n * transfer of larger, more persistent data objects such as images.\n * <p/>\n * Each data item is identified by a URI, accessible with {@link DataItem#getUri()}, that indicates\n * the item's creator and path. Fully specified URIs follow the following format:\n * {@code wear://<node_id>/<path>}, where <node_id> is the node ID of the wearable node that\n * created the data item, and <path> is an application-defined path. This means that given a data\n * item's URI, calling {@link Uri#getHost()} will return the creator's node ID.\n * <p/>\n * In some of the methods below (such as {@link #getDataItems(GoogleApiClient, Uri)}), it is\n * possible to omit the node ID from the URI, and only leave a path. In that case, the URI may\n * refer to multiple data items, since multiple nodes may create data items with the same path.\n * Partially specified data item URIs follow the following format:\n * {@ocde wear:/<path>}\n * Note the single / after wear:.\n */\n@PublicApi\npublic interface DataApi {\n    /**\n     * Registers a listener to receive data item changed and deleted events. This call should be\n     * balanced with a call to {@link #removeListener(GoogleApiClient, DataListener)}, to avoid\n     * leaking resources.\n     * <p/>\n     * The listener will be notified of changes initiated by this node.\n     */\n    PendingResult<Status> addListener(GoogleApiClient client, DataListener listener);\n\n    /**\n     * Removes all specified data items from the Android Wear network.\n     * <p/>\n     * If uri is fully specified, this method will delete at most one data item. If {@code uri}\n     * contains no host, multiple data items may be deleted, since different nodes may create data\n     * items with the same path. See {@link DataApi} for details of the URI format.\n     */\n    PendingResult<DeleteDataItemsResult> deleteDataItems(GoogleApiClient client, Uri uri);\n\n    /**\n     * Retrieves a single {@link DataItem} from the Android Wear network. A fully qualified URI\n     * must be specified. The URI's host must be the ID of the node that created the item.\n     * <p/>\n     * See {@link DataApi} for details of the URI format.\n     */\n    PendingResult<DataItemResult> getDataItem(GoogleApiClient client, Uri uri);\n\n    /**\n     * Retrieves all data items from the Android Wear network.\n     * <p/>\n     * Callers must call {@link DataItemBuffer#release()} on the returned buffer when finished\n     * processing results.\n     */\n    PendingResult<DataItemBuffer> getDataItems(GoogleApiClient client);\n\n    /**\n     * Retrieves all data items matching the provided URI, from the Android Wear network.\n     * <p/>\n     * The URI must contain a path. If {@code uri} is fully specified, at most one data item will\n     * be returned. If uri contains no host, multiple data items may be returned, since different\n     * nodes may create data items with the same path. See {@link DataApi} for details of the URI\n     * format.\n     * <p/>\n     * Callers must call {@link DataItemBuffer#release()} on the returned buffer when finished\n     * processing results.\n     */\n    PendingResult<DataItemBuffer> getDataItems(GoogleApiClient client, Uri uri);\n\n    /**\n     * Retrieves a {@link ParcelFileDescriptor} pointing at the bytes of an asset. Only assets\n     * previously stored in a {@link DataItem} may be retrieved.\n     */\n    PendingResult<GetFdForAssetResult> getFdForAsset(GoogleApiClient client, DataItemAsset asset);\n\n    /**\n     * Retrieves a {@link ParcelFileDescriptor} pointing at the bytes of an asset. Only assets\n     * previously stored in a {@link DataItem} may be retrieved.\n     */\n    PendingResult<GetFdForAssetResult> getFdForAsset(GoogleApiClient client, Asset asset);\n\n    /**\n     * Adds a {@link DataItem} to the Android Wear network. The updated item is synchronized across\n     * all devices.\n     */\n    PendingResult<DataItemResult> putDataItem(GoogleApiClient client, PutDataRequest request);\n\n    /**\n     * Removes a data listener which was previously added through\n     * {@link #addListener(GoogleApiClient, DataListener)}.\n     */\n    PendingResult<Status> removeListener(GoogleApiClient client, DataListener listener);\n\n    interface DataItemResult extends Result {\n        /**\n         * @return data item, or {@code null} if the item does not exit.\n         */\n        DataItem getDataItem();\n    }\n\n    interface DataListener {\n        /**\n         * Notification that a set of data items have been changed or deleted. The data buffer is\n         * released upon completion of this method. If a caller wishes to use the events outside\n         * this callback, they should be sure to {@link Freezable#freeze()} the DataEvent objects\n         * they wish to use.\n         */\n        void onDataChanged(DataEventBuffer dataEvents);\n    }\n\n    interface DeleteDataItemsResult extends Result {\n        /**\n         * @return the number of items deleted by\n         * {@link DataApi#deleteDataItems(GoogleApiClient, Uri)}.\n         */\n        int getNumDeleted();\n    }\n\n    interface GetFdForAssetResult extends Result {\n        /**\n         * @return a file descriptor for the requested asset.\n         */\n        ParcelFileDescriptor getFd();\n\n        /**\n         * @return an input stream wrapping the file descriptor. When this input stream is closed, the file descriptor is, as well.\n         */\n        InputStream getInputStream();\n    }\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/DataEvent.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable;\n\nimport com.google.android.gms.common.data.Freezable;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Data interface for data events.\n */\n@PublicApi\npublic interface DataEvent extends Freezable<DataEvent> {\n\n    /**\n     * Indicates that the enclosing {@link DataEvent} was triggered by a data item being added or\n     * changed.\n     */\n    int TYPE_CHANGED = 1;\n\n    /**\n     * Indicates that the enclosing {@link DataEvent} was triggered by a data item being deleted.\n     */\n    int TYPE_DELETED = 2;\n\n    /**\n     * @return the data item modified in this event. An event of {@link #TYPE_DELETED} will only\n     * have its {@link DataItem#getUri} populated.\n     */\n    DataItem getDataItem();\n\n    /**\n     * @return the type of event this is. One of {@link #TYPE_CHANGED}, {@link #TYPE_DELETED}.\n     */\n    int getType();\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/DataEventBuffer.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable;\n\nimport com.google.android.gms.common.api.Result;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.common.data.AbstractDataBuffer;\nimport com.google.android.gms.common.data.DataBuffer;\nimport com.google.android.gms.common.data.DataHolder;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Data structure holding references to a set of events.\n */\n@PublicApi\npublic class DataEventBuffer extends AbstractDataBuffer<DataEvent> implements Result {\n    private Status status;\n\n    @PublicApi(exclude = true)\n    public DataEventBuffer(DataHolder dataHolder) {\n        super(dataHolder);\n        status = new Status(dataHolder.getStatusCode());\n    }\n\n    @Override\n    public DataEvent get(int position) {\n        return null;\n    }\n\n    @Override\n    public Status getStatus() {\n        return null;\n    }\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/DataItem.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable;\n\nimport android.net.Uri;\n\nimport com.google.android.gms.common.data.Freezable;\n\nimport org.microg.gms.common.PublicApi;\n\nimport java.util.Map;\n\n/**\n * The base object of data stored in the Android Wear network. {@link DataItem} are replicated\n * across all devices in the network. It contains a small blob of data and associated assets.\n * <p/>\n * A {@link DataItem} is identified by its Uri, which contains its creator and a path.\n */\n@PublicApi\npublic interface DataItem extends Freezable<DataItem> {\n    /**\n     * A map of assets associated with this data item.\n     */\n    Map<String, DataItemAsset> getAssets();\n\n    /**\n     * An array of data stored at the specified {@link Uri}.\n     */\n    byte[] getData();\n\n    /**\n     * Returns the DataItem's Uri. {@link Uri#getHost()} returns the id of the node that created it.\n     */\n    Uri getUri();\n\n    /**\n     * Sets the data in a data item.\n     * <p/>\n     * The current maximum data item size limit is approximately 100k. Data items should generally be much smaller than this limit.\n     */\n    DataItem setData(byte[] data);\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/DataItemAsset.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable;\n\nimport com.google.android.gms.common.data.Freezable;\n\n/**\n * A reference to an asset stored in a data item. Used to fetch file descriptors using\n * DataApi#getFdForAsset(GoogleApiClient, DataItemAsset).\n */\npublic interface DataItemAsset extends Freezable<DataItemAsset> {\n    /**\n     * @return the identifier used to address this asset in the context of an existing\n     * {@link DataItem}.\n     */\n    String getDataItemKey();\n\n    /**\n     * @return the Android Wear-wide unique identifier for a particular asset.\n     */\n    String getId();\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/DataItemBuffer.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable;\n\nimport com.google.android.gms.common.api.Result;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.common.data.AbstractDataBuffer;\nimport com.google.android.gms.common.data.DataBuffer;\nimport com.google.android.gms.common.data.DataHolder;\n\nimport org.microg.gms.common.PublicApi;\n\n@PublicApi\npublic class DataItemBuffer extends AbstractDataBuffer<DataItem> implements Result {\n    private Status status;\n\n    @PublicApi(exclude = true)\n    public DataItemBuffer(DataHolder dataHolder) {\n        super(dataHolder);\n        status = new Status(dataHolder.getStatusCode());\n    }\n\n    @Override\n    public DataItem get(int position) {\n        return null;\n    }\n\n    @Override\n    public Status getStatus() {\n        return null;\n    }\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/DataMap.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable;\n\nimport android.os.Bundle;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.wearable.databundle.DataBundleUtil;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\n\nimport static org.microg.gms.wearable.databundle.DataBundleUtil.ASSET_TYPE_CODE;\nimport static org.microg.gms.wearable.databundle.DataBundleUtil.BOOLEAN_TYPE_CODE;\nimport static org.microg.gms.wearable.databundle.DataBundleUtil.BYTE_ARRAY_TYPE_CODE;\nimport static org.microg.gms.wearable.databundle.DataBundleUtil.BYTE_TYPE_CODE;\nimport static org.microg.gms.wearable.databundle.DataBundleUtil.DATAMAP_TYPE_CODE;\nimport static org.microg.gms.wearable.databundle.DataBundleUtil.DOUBLE_TYPE_CODE;\nimport static org.microg.gms.wearable.databundle.DataBundleUtil.FLOAT_ARRAY_TYPE_CODE;\nimport static org.microg.gms.wearable.databundle.DataBundleUtil.FLOAT_TYPE_CODE;\nimport static org.microg.gms.wearable.databundle.DataBundleUtil.INTEGER_TYPE_CODE;\nimport static org.microg.gms.wearable.databundle.DataBundleUtil.LIST_TYPE_CODE;\nimport static org.microg.gms.wearable.databundle.DataBundleUtil.LONG_ARRAY_TYPE_CODE;\nimport static org.microg.gms.wearable.databundle.DataBundleUtil.LONG_TYPE_CODE;\nimport static org.microg.gms.wearable.databundle.DataBundleUtil.STRING_ARRAY_TYPE_CODE;\nimport static org.microg.gms.wearable.databundle.DataBundleUtil.STRING_TYPE_CODE;\n\n/**\n * A map of data supported by {@link PutDataMapRequest} and {@link DataMapItem}s. DataMap may\n * convert to and from Bundles, but will drop any types not explicitly supported by DataMap in the\n * conversion process.\n */\n@PublicApi\npublic class DataMap {\n    public static String TAG = \"GmsDataMap\";\n\n    private Map<String, Object> data = new HashMap<String, Object>();\n    private Map<String, StoredType> types = new HashMap<String, StoredType>();\n\n    public DataMap() {\n\n    }\n\n    /**\n     * @return an ArrayList of DataMaps from an ArrayList of Bundles. Any elements in the Bundles not supported by DataMap will be dropped.\n     */\n    public static ArrayList<DataMap> arrayListFromBundleArrayList(ArrayList<Bundle> bundleArrayList) {\n        ArrayList<DataMap> res = new ArrayList<DataMap>();\n        for (Bundle bundle : bundleArrayList) {\n            res.add(fromBundle(bundle));\n        }\n        return res;\n    }\n\n    /**\n     * Removes all elements from the mapping of this DataMap.\n     */\n    public void clear() {\n        data.clear();\n    }\n\n    /**\n     * @return true if the given key is contained in the mapping of this DataMap.\n     */\n    public boolean containsKey(String key) {\n        return data.containsKey(key);\n    }\n\n    /**\n     * @return true if the given Object is a DataMap equivalent to this one.\n     */\n    @Override\n    public boolean equals(Object o) {\n        return o instanceof DataMap && data.equals(((DataMap) o).data);\n    }\n\n    public StoredType getType(String key) {\n        return types.get(key);\n    }\n\n    @PublicApi(exclude = true)\n    public enum StoredType {\n        Asset(ASSET_TYPE_CODE), Boolean(BOOLEAN_TYPE_CODE), Byte(BYTE_TYPE_CODE),\n        ByteArray(BYTE_ARRAY_TYPE_CODE), DataMap(DATAMAP_TYPE_CODE), DataMapArrayList(DataMap),\n        Double(DOUBLE_TYPE_CODE), Float(FLOAT_TYPE_CODE), FloatArray(FLOAT_ARRAY_TYPE_CODE),\n        Integer(INTEGER_TYPE_CODE), IntegerArrayList(Integer), Long(LONG_TYPE_CODE),\n        LongArray(LONG_ARRAY_TYPE_CODE), String(STRING_TYPE_CODE),\n        StringArray(STRING_ARRAY_TYPE_CODE), StringArrayList(String);\n\n        private int typeCode;\n        private StoredType listType;\n\n        StoredType(int typeCode) {\n            this.typeCode = typeCode;\n        }\n\n        StoredType(StoredType listType) {\n            this.typeCode = LIST_TYPE_CODE;\n            this.listType = listType;\n        }\n\n        public int getTypeCode() {\n            return typeCode;\n        }\n\n        public StoredType getListType() {\n            return listType;\n        }\n    }\n\n    /**\n     * @return a DataMap from a Bundle. The input Bundle is expected to contain only elements\n     * supported by DataMap. Any elements in the Bundle not supported by DataMap will be dropped.\n     */\n    public static DataMap fromBundle(Bundle bundle) {\n        DataMap res = new DataMap();\n        if (bundle != null) {\n            for (String key : bundle.keySet()) {\n                Object val = bundle.get(key);\n                if (val instanceof Asset) {\n                    res.putAsset(key, (Asset) val);\n                } else if (val instanceof Boolean) {\n                    res.putBoolean(key, (Boolean) val);\n                } else if (val instanceof Byte) {\n                    res.putByte(key, (Byte) val);\n                } else if (val instanceof byte[]) {\n                    res.putByteArray(key, (byte[]) val);\n                } else if (val instanceof Bundle) {\n                    res.putDataMap(key, DataMap.fromBundle((Bundle) val));\n                } else if (val instanceof Double) {\n                    res.putDouble(key, (Double) val);\n                } else if (val instanceof Float) {\n                    res.putFloat(key, (Float) val);\n                } else if (val instanceof float[]) {\n                    res.putFloatArray(key, (float[]) val);\n                } else if (val instanceof Integer) {\n                    res.putInt(key, (Integer) val);\n                } else if (val instanceof Long) {\n                    res.putLong(key, (Long) val);\n                } else if (val instanceof long[]) {\n                    res.putLongArray(key, (long[]) val);\n                } else if (val instanceof String) {\n                    res.putString(key, (String) val);\n                } else if (val instanceof String[]) {\n                    res.putStringArray(key, (String[]) val);\n                } else if (val instanceof ArrayList) {\n                    if (((ArrayList) val).isEmpty() || ((ArrayList) val).get(0) instanceof String) {\n                        res.putStringArrayList(key, (ArrayList<String>) val);\n                    } else if (((ArrayList) val).get(0) instanceof Bundle) {\n                        ArrayList<DataMap> dataMaps = new ArrayList<DataMap>();\n                        for (Bundle b : ((ArrayList<Bundle>) val)) {\n                            dataMaps.add(DataMap.fromBundle(b));\n                        }\n                        res.putDataMapArrayList(key, dataMaps);\n                    } else if (((ArrayList) val).get(0) instanceof Integer) {\n                        res.putIntegerArrayList(key, (ArrayList<Integer>) val);\n                    }\n                }\n            }\n        }\n        return res;\n    }\n\n    /**\n     * @return a DataMap from a byte[].\n     */\n    public static DataMap fromByteArray(byte[] bytes) {\n        return DataBundleUtil.readDataMap(bytes, Collections.<Asset>emptyList());\n    }\n\n    /**\n     * @return the entry with the given key as an object, or null\n     */\n    public <T> T get(String key) {\n        return (T) data.get(key);\n    }\n\n    public Asset getAsset(String key) {\n        return types.get(key) == StoredType.Asset ? (Asset) data.get(key) : null;\n    }\n\n    public boolean getBoolean(String key) {\n        return getBoolean(key, false);\n    }\n\n    public boolean getBoolean(String key, boolean defaultValue) {\n        return types.get(key) == StoredType.Boolean ? (Boolean) data.get(key) : defaultValue;\n    }\n\n    public byte getByte(String key) {\n        return getByte(key, (byte) 0);\n    }\n\n    public byte getByte(String key, byte defaultValue) {\n        return types.get(key) == StoredType.Byte ? (Byte) data.get(key) : defaultValue;\n    }\n\n    public byte[] getByteArray(String key) {\n        return types.get(key) == StoredType.ByteArray ? (byte[]) data.get(key) : null;\n    }\n\n    public DataMap getDataMap(String key) {\n        return types.get(key) == StoredType.DataMap ? (DataMap) data.get(key) : null;\n    }\n\n    public ArrayList<DataMap> getDataMapArrayList(String key) {\n        return types.get(key) == StoredType.DataMapArrayList ? (ArrayList<DataMap>) data.get(key) : null;\n    }\n\n    public double getDouble(String key) {\n        return getDouble(key, 0.0);\n    }\n\n    public double getDouble(String key, double defaultValue) {\n        return types.get(key) == StoredType.Double ? (Double) data.get(key) : defaultValue;\n    }\n\n    public float getFloat(String key) {\n        return getFloat(key, 0.0f);\n    }\n\n    public float getFloat(String key, float defaultValue) {\n        return types.get(key) == StoredType.Float ? (Float) data.get(key) : defaultValue;\n    }\n\n    public float[] getFloatArray(String key) {\n        return types.get(key) == StoredType.FloatArray ? (float[]) data.get(key) : null;\n    }\n\n    public int getInt(String key) {\n        return getInt(key, 0);\n    }\n\n    public int getInt(String key, int defaultValue) {\n        return types.get(key) == StoredType.Integer ? (Integer) data.get(key) : defaultValue;\n    }\n\n    public ArrayList<Integer> getIntegerArrayList(String key) {\n        return types.get(key) == StoredType.IntegerArrayList ? (ArrayList<Integer>) data.get(key) : null;\n    }\n\n    public long getLong(String key) {\n        return getLong(key, 0L);\n    }\n\n    public long getLong(String key, long defaultValue) {\n        return types.get(key) == StoredType.Long ? (Long) data.get(key) : defaultValue;\n    }\n\n    public long[] getLongArray(String key) {\n        return types.get(key) == StoredType.LongArray ? (long[]) data.get(key) : null;\n    }\n\n    public String getString(String key) {\n        return getString(key, null);\n    }\n\n    public String getString(String key, String defaultValue) {\n        return types.get(key) == StoredType.String ? (String) data.get(key) : defaultValue;\n    }\n\n    public String[] getStringArray(String key) {\n        return types.get(key) == StoredType.StringArray ? (String[]) data.get(key) : null;\n    }\n\n    public ArrayList<String> getStringArrayList(String key) {\n        return types.get(key) == StoredType.StringArrayList ? (ArrayList<String>) data.get(key) : null;\n    }\n\n    public int hashCode() {\n        return data.hashCode();\n    }\n\n    public boolean isEmpty() {\n        return data.isEmpty();\n    }\n\n    public Set<String> keySet() {\n        return data.keySet();\n    }\n\n    public void putAll(DataMap dataMap) {\n        for (String key : dataMap.keySet()) {\n            data.put(key, dataMap.data.get(key));\n            types.put(key, dataMap.types.get(key));\n        }\n    }\n\n    public void putAsset(String key, Asset value) {\n        data.put(key, value);\n        types.put(key, StoredType.Asset);\n    }\n\n    public void putBoolean(String key, boolean value) {\n        data.put(key, value);\n        types.put(key, StoredType.Boolean);\n    }\n\n    public void putByte(String key, byte value) {\n        data.put(key, value);\n        types.put(key, StoredType.Byte);\n    }\n\n    public void putByteArray(String key, byte[] value) {\n        data.put(key, value);\n        types.put(key, StoredType.ByteArray);\n    }\n\n    public void putDataMap(String key, DataMap value) {\n        data.put(key, value);\n        types.put(key, StoredType.DataMap);\n    }\n\n    public void putDataMapArrayList(String key, ArrayList<DataMap> value) {\n        data.put(key, value);\n        types.put(key, StoredType.DataMapArrayList);\n    }\n\n    public void putDouble(String key, double value) {\n        data.put(key, value);\n        types.put(key, StoredType.Double);\n    }\n\n    public void putFloat(String key, float value) {\n        data.put(key, value);\n        types.put(key, StoredType.Float);\n    }\n\n    public void putFloatArray(String key, float[] value) {\n        data.put(key, value);\n        types.put(key, StoredType.FloatArray);\n    }\n\n    public void putInt(String key, int value) {\n        data.put(key, value);\n        types.put(key, StoredType.Integer);\n    }\n\n    public void putIntegerArrayList(String key, ArrayList<Integer> value) {\n        data.put(key, value);\n        types.put(key, StoredType.IntegerArrayList);\n    }\n\n    public void putLong(String key, long value) {\n        data.put(key, value);\n        types.put(key, StoredType.Long);\n    }\n\n    public void putLongArray(String key, long[] value) {\n        data.put(key, value);\n        types.put(key, StoredType.LongArray);\n    }\n\n    public void putString(String key, String value) {\n        data.put(key, value);\n        types.put(key, StoredType.String);\n    }\n\n    public void putStringArray(String key, String[] value) {\n        data.put(key, value);\n        types.put(key, StoredType.StringArray);\n    }\n\n    public void putStringArrayList(String key, ArrayList<String> value) {\n        data.put(key, value);\n        types.put(key, StoredType.StringArrayList);\n    }\n\n    public Object remove(String key) {\n        types.remove(key);\n        return data.remove(key);\n    }\n\n    public int size() {\n        return data.size();\n    }\n\n    public Bundle toBundle() {\n        Bundle bundle = new Bundle();\n        for (String key : data.keySet()) {\n            switch (types.get(key)) {\n                case Asset:\n                    bundle.putParcelable(key, (Asset) data.get(key));\n                    break;\n                case Boolean:\n                    bundle.putBoolean(key, (Boolean) data.get(key));\n                    break;\n                case Byte:\n                    bundle.putByte(key, (Byte) data.get(key));\n                    break;\n                case ByteArray:\n                    bundle.putByteArray(key, (byte[]) data.get(key));\n                    break;\n                case DataMap:\n                    bundle.putBundle(key, ((DataMap) data.get(key)).toBundle());\n                    break;\n                case DataMapArrayList:\n                    ArrayList<Bundle> bundles = new ArrayList<Bundle>();\n                    for (DataMap dataMap : ((ArrayList<DataMap>) data.get(key))) {\n                        bundles.add(dataMap.toBundle());\n                    }\n                    bundle.putParcelableArrayList(key, bundles);\n                    break;\n                case Double:\n                    bundle.putDouble(key, (Double) data.get(key));\n                    break;\n                case Float:\n                    bundle.putFloat(key, (Float) data.get(key));\n                    break;\n                case FloatArray:\n                    bundle.putFloatArray(key, (float[]) data.get(key));\n                    break;\n                case Integer:\n                    bundle.putInt(key, (Integer) data.get(key));\n                    break;\n                case IntegerArrayList:\n                    bundle.putIntegerArrayList(key, (ArrayList<Integer>) data.get(key));\n                    break;\n                case Long:\n                    bundle.putLong(key, (Long) data.get(key));\n                    break;\n                case LongArray:\n                    bundle.putLongArray(key, (long[]) data.get(key));\n                    break;\n                case String:\n                    bundle.putString(key, (String) data.get(key));\n                    break;\n                case StringArray:\n                    bundle.putStringArray(key, (String[]) data.get(key));\n                    break;\n                case StringArrayList:\n                    bundle.putStringArrayList(key, (ArrayList<String>) data.get(key));\n                    break;\n            }\n        }\n        return bundle;\n    }\n\n    public byte[] toByteArray() {\n        return DataBundleUtil.createBytes(this);\n    }\n\n    public String toString() {\n        return \"DataMap{size=\" + size() + \"}\";\n    }\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/DataMapItem.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable;\n\nimport android.net.Uri;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Creates a new dataItem-like object containing structured and serializable data.\n */\n@PublicApi\npublic class DataMapItem {\n    /**\n     * Provides a {@link DataMapItem} wrapping a dataItem.\n     *\n     * @param dataItem the base for the wrapped {@link DataMapItem}. {@code dataItem} should not\n     *                 be modified after wrapping it.\n     */\n    public static DataMapItem fromDataItem(DataItem dataItem) {\n        return null;\n    }\n\n    public DataMap getDataMap() {\n        return null;\n    }\n\n    public Uri getUri() {\n        return null;\n    }\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/MessageApi.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable;\n\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.PendingResult;\nimport com.google.android.gms.common.api.Result;\nimport com.google.android.gms.common.api.Status;\n\nimport org.microg.gms.common.PublicApi;\n\n@PublicApi\npublic interface MessageApi {\n\n    /**\n     * A value returned by {@link SendMessageResult#getRequestId()} when\n     * {@link #sendMessage(GoogleApiClient, String, String, byte[])} fails.\n     */\n    int UNKNOWN_REQUEST_ID = -1;\n\n    /**\n     * Registers a listener to be notified of received messages. Calls to this method should\n     * balanced with {@link #removeListener(GoogleApiClient, MessageListener)} to avoid leaking\n     * resources.\n     * <p/>\n     * Callers wishing to be notified of events in the background should use {@link WearableListenerService}.\n     */\n    PendingResult<Status> addListener(GoogleApiClient client, MessageListener listener);\n\n    /**\n     * Removes a message listener which was previously added through\n     * {@link #addListener(GoogleApiClient, MessageListener)}.\n     */\n    PendingResult<Status> removeListener(GoogleApiClient client, MessageListener listener);\n\n    /**\n     * Sends {@code byte[]} data to the specified node.\n     *\n     * @param nodeId identifier for a particular node on the Android Wear network. Valid targets\n     *               may be obtained through {@link NodeApi#getConnectedNodes(GoogleApiClient)}\n     *               or from the host in {@link DataItem#getUri()}.\n     * @param path   identifier used to specify a particular endpoint at the receiving node\n     * @param data   small array of information to pass to the target node. Generally not larger\n     *               than 100k\n     */\n    PendingResult<SendMessageResult> sendMessage(GoogleApiClient client, String nodeId,\n                                                 String path, byte[] data);\n\n    /**\n     * Used with {@link MessageApi#addListener(GoogleApiClient, MessageListener)} to receive\n     * message events.\n     * <p/>\n     * Callers wishing to be notified of events in the background should use\n     * {@link WearableListenerService}.\n     */\n    interface MessageListener {\n        /**\n         * Notification that a message has been received.\n         */\n        void onMessageReceived(MessageEvent messageEvent);\n    }\n\n    /**\n     * Contains the request id assigned to the message. On failure, the id will be\n     * {@link MessageApi#UNKNOWN_REQUEST_ID} and the status will be unsuccessful.\n     */\n    interface SendMessageResult extends Result {\n        /**\n         * @return an ID used to identify the sent message. If {@link #getStatus()} is not\n         * successful, this value will be {@link MessageApi#UNKNOWN_REQUEST_ID}.\n         */\n        int getRequestId();\n    }\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/MessageEvent.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable;\n\nimport org.microg.gms.common.PublicApi;\n\n@PublicApi\npublic interface MessageEvent {\n    /**\n     * @return the data passed by the message.\n     */\n    byte[] getData();\n\n    /**\n     * @return the path the message is being delivered to\n     */\n    String getPath();\n\n    /**\n     * @return the request id of the message, generated by the sender\n     */\n    int getRequestId();\n\n    /**\n     * @return the node ID of the sender.\n     */\n    String getSourceNodeId();\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/Node.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Information about a particular node in the Android Wear network.\n */\n@PublicApi\npublic interface Node {\n    /**\n     * Returns a human readable description of the node. Sometimes generated from the Bluetooth\n     * device name\n     */\n    String getDisplayName();\n\n    /**\n     * Returns an opaque string that represents a node in the Android Wear network.\n     */\n    String getId();\n\n    /**\n     * Indicates that this node can be considered geographically nearby the local node.\n     */\n    boolean isNearby();\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/NodeApi.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable;\n\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.PendingResult;\nimport com.google.android.gms.common.api.Result;\nimport com.google.android.gms.common.api.Status;\n\nimport org.microg.gms.common.PublicApi;\n\nimport java.util.List;\n\n/**\n * Exposes an API for to learn about local or connected Nodes.\n * <p/>\n * Node events are delivered to all applications on a device.\n */\n@PublicApi\npublic interface NodeApi {\n\n    /**\n     * Registers a listener to receive all node events. Calls to this method should balanced with\n     * {@link #removeListener(GoogleApiClient, NodeListener)}, to avoid leaking resources.\n     * <p/>\n     * Callers wishing to be notified of node events in the background should use WearableListenerService.\n     */\n    PendingResult<Status> addListener(GoogleApiClient client, NodeListener listener);\n\n    /**\n     * Gets a list of nodes to which this device is currently connected.\n     * <p/>\n     * The returned list will not include the {@link #getLocalNode(GoogleApiClient) local node}.\n     */\n    PendingResult<GetConnectedNodesResult> getConnectedNodes(GoogleApiClient client);\n\n    /**\n     * Gets the {@link Node} that refers to this device. The information in the returned Node\n     * can be passed to other devices using the {@link MessageApi}, for example.\n     */\n    PendingResult<GetLocalNodeResult> getLocalNode(GoogleApiClient client);\n\n    /**\n     * Removes a listener which was previously added through\n     * {@link #addListener(GoogleApiClient, NodeListener)}.\n     */\n    PendingResult<Status> removeListener(GoogleApiClient client, NodeListener listener);\n\n\n    /**\n     * Contains a list of connected nodes.\n     */\n    interface GetConnectedNodesResult extends Result {\n        /**\n         * @return a list of connected nodes. This list doesn't include the local node.\n         */\n        List<Node> getNodes();\n    }\n\n    /**\n     * Contains the name and id that represents this device.\n     */\n    interface GetLocalNodeResult extends Result {\n        /**\n         * @return a {@link Node} object which represents this device.\n         */\n        Node getNode();\n    }\n\n    /**\n     * Used with {@link NodeApi#addListener(GoogleApiClient, NodeListener)} to receive node events.\n     */\n    interface NodeListener {\n        /**\n         * Notification that a peer has been connected.\n         */\n        void onPeerConnected(Node peer);\n\n        /**\n         * Notification that a peer has been disconnected.\n         */\n        void onPeerDisconnected(Node peer);\n    }\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/PutDataMapRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable;\n\nimport android.net.Uri;\n\nimport com.google.android.gms.wearable.internal.PutDataRequest;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * PutDataMapRequest is a DataMap-aware version of {@link PutDataRequest}.\n */\n@PublicApi\npublic class PutDataMapRequest {\n\n    private DataMapItem dataMapItem;\n\n    private PutDataMapRequest(DataMapItem dataMapItem) {\n        this.dataMapItem = dataMapItem;\n    }\n\n    /**\n     * Creates a {@link PutDataRequest} containing the data and assets in this\n     * {@link PutDataMapRequest}.\n     */\n    public PutDataRequest asPutDataRequest() {\n        // TODO\n        return PutDataRequest.create((Uri) null);\n    }\n\n    /**\n     * Creates a {@link PutDataMapRequest} with the provided, complete, path.\n     */\n    public static PutDataMapRequest create(String path) {\n        // TODO\n        return new PutDataMapRequest(null);\n    }\n\n    /**\n     * Creates a {@link PutDataMapRequest} from a {@link DataMapItem} using the provided source.\n     */\n    public static PutDataMapRequest createFromDataMapItem(DataMapItem source) {\n        return new PutDataMapRequest(source);\n    }\n\n    /**\n     * Creates a {@link PutDataMapRequest} with a randomly generated id prefixed with the provided\n     * path.\n     */\n    public static PutDataMapRequest createWithAutoAppendedId(String pathPrefix) {\n        // TODO\n        return new PutDataMapRequest(null);\n    }\n\n    /**\n     * @return the structured data associated with this data item.\n     */\n    public DataMap getDataMap() {\n        return dataMapItem.getDataMap();\n    }\n\n    /**\n     * @return a {@link Uri} for the pending data item. If this is a modification of an existing\n     * data item, {@link Uri#getHost()} will return the id of the node that originally created it.\n     * Otherwise, a new data item will be created with the requesting device's node.\n     */\n    public Uri getUri() {\n        return dataMapItem.getUri();\n    }\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/Wearable.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable;\n\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.common.api.GoogleApiClient;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.wearable.DataApiImpl;\nimport org.microg.gms.wearable.MessageApiImpl;\nimport org.microg.gms.wearable.NodeApiImpl;\nimport org.microg.gms.wearable.WearableApiClientBuilder;\n\n/**\n * An API for the Android Wear platform.\n */\n@PublicApi\npublic class Wearable {\n    /**\n     * Token to pass to {@link GoogleApiClient.Builder#addApi(Api)} to enable the Wearable features.\n     */\n    public static final Api<WearableOptions> API = new Api<WearableOptions>(new WearableApiClientBuilder());\n\n    public static final DataApi DataApi = new DataApiImpl();\n    public static final MessageApi MessageApi = new MessageApiImpl();\n    public static final NodeApi NodeApi = new NodeApiImpl();\n\n    public static class WearableOptions implements Api.ApiOptions.Optional {\n        /**\n         * Special option for microG to allow implementation of a FOSS first party Android Wear app\n         */\n        @PublicApi(exclude = true)\n        public boolean firstPartyMode = false;\n\n        public static class Builder {\n            public WearableOptions build() {\n                return new WearableOptions();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/WearableListenerService.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable;\n\nimport android.app.Service;\nimport android.content.Intent;\nimport android.os.Binder;\nimport android.os.Handler;\nimport android.os.HandlerThread;\nimport android.os.IBinder;\nimport android.os.Looper;\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport com.google.android.gms.common.data.DataHolder;\nimport com.google.android.gms.wearable.internal.AmsEntityUpdateParcelable;\nimport com.google.android.gms.wearable.internal.AncsNotificationParcelable;\nimport com.google.android.gms.wearable.internal.CapabilityInfoParcelable;\nimport com.google.android.gms.wearable.internal.ChannelEventParcelable;\nimport com.google.android.gms.wearable.internal.IWearableListener;\nimport com.google.android.gms.wearable.internal.MessageEventParcelable;\nimport com.google.android.gms.wearable.internal.NodeParcelable;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.gms.wearable.ChannelImpl;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport static org.microg.gms.common.Constants.GMS_PACKAGE_NAME;\n\n@PublicApi\npublic abstract class WearableListenerService extends Service implements CapabilityApi.CapabilityListener, ChannelApi.ChannelListener, DataApi.DataListener, MessageApi.MessageListener, NodeApi.NodeListener {\n    private static final String BIND_LISTENER_INTENT_ACTION = \"com.google.android.gms.wearable.BIND_LISTENER\";\n    private static final String TAG = \"GmsWearListenerSvc\";\n\n    private HandlerThread handlerThread;\n    private IWearableListener listener;\n    private ServiceHandler serviceHandler;\n    private Object lock = new Object();\n    private boolean disconnected = false;\n\n    @Override\n    public IBinder onBind(Intent intent) {\n        if (BIND_LISTENER_INTENT_ACTION.equals(intent.getAction())) {\n            return listener.asBinder();\n        }\n        return null;\n    }\n\n    @Override\n    public void onCapabilityChanged(CapabilityInfo capabilityInfo) {\n    }\n\n    public void onConnectedNodes(List<Node> connectedNodes) {\n    }\n\n    @Override\n    public void onChannelClosed(Channel channel, int closeReason, int appSpecificErrorCode) {\n    }\n\n    @Override\n    public void onChannelOpened(Channel channel) {\n    }\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n        handlerThread = new HandlerThread(\"WearableListenerService\");\n        handlerThread.start();\n        serviceHandler = new ServiceHandler(handlerThread.getLooper());\n        listener = new Listener();\n    }\n\n    @Override\n    public void onDataChanged(DataEventBuffer dataEvents) {\n    }\n\n    @Override\n    public void onDestroy() {\n        synchronized (lock) {\n            if (serviceHandler == null) {\n                throw new IllegalStateException(\"serviceHandler not set, did you override onCreate() but forget to call super.onCreate()?\");\n            }\n            serviceHandler.getLooper().quit();\n        }\n        super.onDestroy();\n    }\n\n    @PublicApi(exclude = true)\n    public void onEntityUpdate(AmsEntityUpdate entityUpdate) {\n    }\n\n    @Override\n    public void onInputClosed(Channel channel, @ChannelApi.CloseReason int closeReason, int appSpecificErrorCode) {\n    }\n\n    @Override\n    public void onMessageReceived(MessageEvent messageEvent) {\n    }\n\n    @PublicApi(exclude = true)\n    public void onNotificationReceived(AncsNotification notification) {\n    }\n\n    @Override\n    public void onOutputClosed(Channel channel, @ChannelApi.CloseReason int closeReason, int appSpecificErrorCode) {\n    }\n\n    @Override\n    public void onPeerConnected(Node peer) {\n    }\n\n    @Override\n    public void onPeerDisconnected(Node peer) {\n    }\n\n    private class Listener extends IWearableListener.Stub {\n        private int knownGoodUid = -1;\n\n        private boolean post(Runnable runnable) {\n            int callingUid = Binder.getCallingUid();\n            if (callingUid != knownGoodUid) {\n                // TODO: Verify Gms is calling\n                String[] packagesForUid = getPackageManager().getPackagesForUid(callingUid);\n                if (packagesForUid != null) {\n                    if (Arrays.asList(packagesForUid).contains(GMS_PACKAGE_NAME)) {\n                        knownGoodUid = callingUid;\n                    } else {\n                        throw new SecurityException(\"Caller is not Services Core\");\n                    }\n                }\n            }\n            synchronized (lock) {\n                if (disconnected) {\n                    return false;\n                }\n                serviceHandler.post(runnable);\n                return true;\n            }\n        }\n\n        @Override\n        public void onDataChanged(final DataHolder data) throws RemoteException {\n            post(new Runnable() {\n                @Override\n                public void run() {\n                    WearableListenerService.this.onDataChanged(new DataEventBuffer(data));\n                }\n            });\n        }\n\n        @Override\n        public void onMessageReceived(final MessageEventParcelable messageEvent) throws RemoteException {\n            post(new Runnable() {\n                @Override\n                public void run() {\n                    WearableListenerService.this.onMessageReceived(messageEvent);\n                }\n            });\n        }\n\n        @Override\n        public void onPeerConnected(final NodeParcelable node) throws RemoteException {\n            post(new Runnable() {\n                @Override\n                public void run() {\n                    WearableListenerService.this.onPeerConnected(node);\n                }\n            });\n        }\n\n        @Override\n        public void onPeerDisconnected(final NodeParcelable node) throws RemoteException {\n            post(new Runnable() {\n                @Override\n                public void run() {\n                    WearableListenerService.this.onPeerDisconnected(node);\n                }\n            });\n        }\n\n        @Override\n        public void onConnectedNodes(final List<NodeParcelable> nodes) throws RemoteException {\n            post(new Runnable() {\n                @Override\n                public void run() {\n                    WearableListenerService.this.onConnectedNodes(new ArrayList<Node>(nodes));\n                }\n            });\n        }\n\n        @Override\n        public void onConnectedCapabilityChanged(final CapabilityInfoParcelable capabilityInfo) throws RemoteException {\n            post(new Runnable() {\n                @Override\n                public void run() {\n                    WearableListenerService.this.onCapabilityChanged(capabilityInfo);\n                }\n            });\n        }\n\n        @Override\n        public void onNotificationReceived(final AncsNotificationParcelable notification) throws RemoteException {\n            post(new Runnable() {\n                @Override\n                public void run() {\n                    WearableListenerService.this.onNotificationReceived(notification);\n                }\n            });\n        }\n\n        @Override\n        public void onEntityUpdate(final AmsEntityUpdateParcelable update) throws RemoteException {\n            post(new Runnable() {\n                @Override\n                public void run() {\n                    WearableListenerService.this.onEntityUpdate(update);\n                }\n            });\n        }\n\n        @Override\n        public void onChannelEvent(final ChannelEventParcelable channelEvent) throws RemoteException {\n            post(new Runnable() {\n                @Override\n                public void run() {\n                    switch (channelEvent.eventType) {\n                        case 1:\n                            WearableListenerService.this.onChannelOpened(new ChannelImpl(channelEvent.channel));\n                            break;\n                        case 2:\n                            WearableListenerService.this.onChannelClosed(new ChannelImpl(channelEvent.channel), channelEvent.closeReason, channelEvent.appSpecificErrorCode);\n                            break;\n                        case 3:\n                            WearableListenerService.this.onInputClosed(new ChannelImpl(channelEvent.channel), channelEvent.closeReason, channelEvent.appSpecificErrorCode);\n                            break;\n                        case 4:\n                            WearableListenerService.this.onOutputClosed(new ChannelImpl(channelEvent.channel), channelEvent.closeReason, channelEvent.appSpecificErrorCode);\n                            break;\n                        default:\n                            Log.w(TAG, \"Unknown ChannelEvent.eventType\");\n                    }\n                }\n            });\n        }\n    }\n\n    private class ServiceHandler extends Handler {\n        public ServiceHandler(Looper looper) {\n            super(looper);\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/WearableStatusCodes.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable;\n\nimport com.google.android.gms.common.api.CommonStatusCodes;\n\nimport org.microg.gms.common.PublicApi;\n\n/**\n * Error codes for wearable API failures. These values may be returned by APIs to indicate the\n * success or failure of a request.\n */\n@PublicApi\npublic class WearableStatusCodes extends CommonStatusCodes {\n    /**\n     * Indicates that the targeted node is not accessible in the wearable network.\n     */\n    public static final int TARGET_NODE_NOT_CONNECTED = 4000;\n    /**\n     * Indicates that the specified listener is already registered.\n     */\n    public static final int DUPLICATE_LISTENER = 4001;\n    /**\n     * Indicates that the specified listener is not recognized.\n     */\n    public static final int UNKNOWN_LISTENER = 4002;\n    /**\n     * Indicates that the data item was too large to set.\n     */\n    public static final int DATA_ITEM_TOO_LARGE = 4003;\n    /**\n     * Indicates that the targeted node is not a valid node in the wearable network.\n     */\n    public static final int INVALID_TARGET_NODE = 4004;\n    /**\n     * Indicates that the requested asset is unavailable.\n     */\n    public static final int ASSET_UNAVAILABLE = 4005;\n    /**\n     * Indicates that the specified capability already exists.\n     */\n    public static final int DUPLICATE_CAPABILITY = 4006;\n    /**\n     * Indicates that the specified capability is not recognized.\n     */\n    public static final int UNKNOWN_CAPABILITY = 4007;\n    /**\n     * Indicates that the WiFi credential sync no credential fetched.\n     */\n    public static final int WIFI_CREDENTIAL_SYNC_NO_CREDENTIAL_FETCHED = 4008;\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/internal/AddListenerRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable.internal;\n\nimport android.content.IntentFilter;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class AddListenerRequest extends AutoSafeParcelable {\n    @SafeParceled(1)\n    private int versionCode = 1;\n    @SafeParceled(2)\n    public final IWearableListener listener;\n    @SafeParceled(3)\n    public final IntentFilter[] intentFilters;\n    @SafeParceled(4)\n    public final String channelTokenString;\n\n    private AddListenerRequest() {\n        listener = null;\n        intentFilters = null;\n        channelTokenString = null;\n    }\n\n    public AddListenerRequest(IWearableListener listener, IntentFilter[] intentFilters, String channelTokenString) {\n        this.listener = listener;\n        this.intentFilters = intentFilters;\n        this.channelTokenString = channelTokenString;\n    }\n\n    public static final Creator<AddListenerRequest> CREATOR = new AutoCreator<AddListenerRequest>(AddListenerRequest.class);\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/internal/AddLocalCapabilityResponse.java",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 com.google.android.gms.wearable.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class AddLocalCapabilityResponse extends AutoSafeParcelable {\n    @SafeParceled(1)\n    private int versionCode = 1;\n    @SafeParceled(2)\n    private int status = 0;\n\n    private AddLocalCapabilityResponse() {\n    }\n\n    public AddLocalCapabilityResponse(int status) {\n        this.status = status;\n    }\n\n    public static final Creator<AddLocalCapabilityResponse> CREATOR = new AutoCreator<AddLocalCapabilityResponse>(AddLocalCapabilityResponse.class);\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/internal/AmsEntityUpdateParcelable.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable.internal;\n\nimport com.google.android.gms.wearable.AmsEntityUpdate;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class AmsEntityUpdateParcelable extends AutoSafeParcelable implements AmsEntityUpdate {\n    public static final Creator<AmsEntityUpdateParcelable> CREATOR = new AutoCreator<AmsEntityUpdateParcelable>(AmsEntityUpdateParcelable.class);\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/internal/AncsNotificationParcelable.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable.internal;\n\nimport com.google.android.gms.wearable.AncsNotification;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class AncsNotificationParcelable extends AutoSafeParcelable implements AncsNotification {\n    public static final Creator<AncsNotificationParcelable> CREATOR = new AutoCreator<AncsNotificationParcelable>(AncsNotificationParcelable.class);\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/internal/CapabilityInfoParcelable.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable.internal;\n\nimport com.google.android.gms.wearable.CapabilityInfo;\nimport com.google.android.gms.wearable.Node;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\npublic class CapabilityInfoParcelable extends AutoSafeParcelable implements CapabilityInfo {\n    @SafeParceled(1)\n    private int versionCode = 1;\n\n    @SafeParceled(2)\n    private String name;\n\n    @SafeParceled(value = 3, subClass = NodeParcelable.class)\n    private List<NodeParcelable> nodeParcelables;\n\n    private Set<Node> nodes;\n    private Object lock = new Object();\n\n    private CapabilityInfoParcelable() {\n    }\n\n    public CapabilityInfoParcelable(String name, List<NodeParcelable> nodeParcelables) {\n        this.name = name;\n        this.nodeParcelables = nodeParcelables;\n    }\n\n    @Override\n    public String getName() {\n        return name;\n    }\n\n    @Override\n    public synchronized Set<Node> getNodes() {\n        if (nodes == null) {\n            nodes = new HashSet<Node>(nodeParcelables);\n        }\n        return nodes;\n    }\n\n    @Override\n    public boolean equals(Object other) {\n        if (this == other) return true;\n        if (other == null || getClass() != other.getClass()) return false;\n\n        CapabilityInfoParcelable that = (CapabilityInfoParcelable) other;\n\n        if (versionCode != that.versionCode) return false;\n        if (name != null ? !name.equals(that.name) : that.name != null) return false;\n        return nodeParcelables != null ? nodeParcelables.equals(that.nodeParcelables) : that.nodeParcelables == null;\n    }\n\n    @Override\n    public int hashCode() {\n        int result = versionCode;\n        result = 31 * result + (name != null ? name.hashCode() : 0);\n        result = 31 * result + (nodeParcelables != null ? nodeParcelables.hashCode() : 0);\n        return result;\n    }\n\n    @Override\n    public String toString() {\n        return \"CapabilityInfo{\" + name + \", \" + nodeParcelables + \"}\";\n    }\n\n    public static final Creator<CapabilityInfoParcelable> CREATOR = new AutoCreator<CapabilityInfoParcelable>(CapabilityInfoParcelable.class);\n\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/internal/ChannelEventParcelable.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class ChannelEventParcelable extends AutoSafeParcelable {\n\n    @SafeParceled(1)\n    private int versionCode = 1;\n    @SafeParceled(2)\n    public ChannelParcelable channel;\n    @SafeParceled(3)\n    public int eventType;\n    @SafeParceled(4)\n    public int closeReason;\n    @SafeParceled(5)\n    public int appSpecificErrorCode;\n\n    public static final Creator<ChannelEventParcelable> CREATOR = new AutoCreator<ChannelEventParcelable>(ChannelEventParcelable.class);\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/internal/ChannelParcelable.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class ChannelParcelable extends AutoSafeParcelable {\n    @SafeParceled(1)\n    private int versionCode = 1;\n    @SafeParceled(2)\n    public String token;\n    @SafeParceled(3)\n    public String nodeId;\n    @SafeParceled(4)\n    public String path;\n\n    private ChannelParcelable() {\n    }\n\n    public ChannelParcelable(String token, String nodeId, String path) {\n        this.token = token;\n        this.nodeId = nodeId;\n        this.path = path;\n    }\n\n    public static final Creator<ChannelParcelable> CREATOR = new AutoCreator<ChannelParcelable>(ChannelParcelable.class);\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/internal/ChannelReceiveFileResponse.java",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 com.google.android.gms.wearable.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class ChannelReceiveFileResponse extends AutoSafeParcelable {\n    @SafeParceled(1)\n    private int versionCode = 1;\n    public static final Creator<ChannelReceiveFileResponse> CREATOR = new AutoCreator<ChannelReceiveFileResponse>(ChannelReceiveFileResponse.class);\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/internal/ChannelSendFileResponse.java",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 com.google.android.gms.wearable.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class ChannelSendFileResponse extends AutoSafeParcelable {\n    @SafeParceled(1)\n    private int versionCode = 1;\n    public static final Creator<ChannelSendFileResponse> CREATOR = new AutoCreator<ChannelSendFileResponse>(ChannelSendFileResponse.class);\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/internal/CloseChannelResponse.java",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 com.google.android.gms.wearable.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class CloseChannelResponse extends AutoSafeParcelable {\n    @SafeParceled(1)\n    private int versionCode = 1;\n    public static final Creator<CloseChannelResponse> CREATOR = new AutoCreator<CloseChannelResponse>(CloseChannelResponse.class);\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/internal/DataItemAssetParcelable.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable.internal;\n\nimport com.google.android.gms.wearable.DataItemAsset;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class DataItemAssetParcelable extends AutoSafeParcelable implements DataItemAsset {\n\n    @SafeParceled(1)\n    private int versionCode = 1;\n    @SafeParceled(2)\n    private String id;\n    @SafeParceled(3)\n    private String key;\n\n    private DataItemAssetParcelable() {\n    }\n\n    public DataItemAssetParcelable(String id, String key) {\n        this.id = id;\n        this.key = key;\n    }\n\n    @Override\n    public String getDataItemKey() {\n        return key;\n    }\n\n    @Override\n    public String getId() {\n        return id;\n    }\n\n    @Override\n    public DataItemAsset freeze() {\n        return this;\n    }\n\n    @Override\n    public boolean isDataValid() {\n        return true;\n    }\n\n    public static final Creator<DataItemAssetParcelable> CREATOR = new AutoCreator<DataItemAssetParcelable>(DataItemAssetParcelable.class);\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/internal/DataItemParcelable.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable.internal;\n\nimport android.net.Uri;\nimport android.os.Bundle;\n\nimport com.google.android.gms.wearable.DataItem;\nimport com.google.android.gms.wearable.DataItemAsset;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class DataItemParcelable extends AutoSafeParcelable implements DataItem {\n    @SafeParceled(1)\n    private int versionCode = 1;\n    @SafeParceled(2)\n    private Uri uri;\n    @SafeParceled(4)\n    private Bundle assets = new Bundle();\n    @SafeParceled(5)\n    public byte[] data;\n\n    private DataItemParcelable() {\n    }\n\n    public DataItemParcelable(Uri uri) {\n        this(uri, new HashMap<String, DataItemAssetParcelable>());\n    }\n\n    public DataItemParcelable(Uri uri, Map<String, DataItemAssetParcelable> assets) {\n        this.uri = uri;\n        for (String key : assets.keySet()) {\n            this.assets.putParcelable(key, assets.get(key));\n        }\n        data = null;\n    }\n\n    public Map<String, DataItemAsset> getAssets() {\n        Map<String, DataItemAsset> assets = new HashMap<String, DataItemAsset>();\n        this.assets.setClassLoader(DataItemAssetParcelable.class.getClassLoader());\n        for (String key : this.assets.keySet()) {\n            assets.put(key, (DataItemAssetParcelable) this.assets.getParcelable(key));\n        }\n        return assets;\n    }\n\n    @Override\n    public byte[] getData() {\n        return data;\n    }\n\n    @Override\n    public Uri getUri() {\n        return uri;\n    }\n\n    @Override\n    public DataItem setData(byte[] data) {\n        this.data = data;\n        return this;\n    }\n\n    @Override\n    public DataItem freeze() {\n        return this;\n    }\n\n    @Override\n    public boolean isDataValid() {\n        return true;\n    }\n\n    public static final Creator<DataItemParcelable> CREATOR = new AutoCreator<DataItemParcelable>(DataItemParcelable.class);\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/internal/DeleteDataItemsResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class DeleteDataItemsResponse extends AutoSafeParcelable {\n\n    @SafeParceled(1)\n    private int versionCode = 1;\n    @SafeParceled(2)\n    private int status;\n    @SafeParceled(3)\n    private int count;\n\n    private DeleteDataItemsResponse() {\n    }\n\n    public DeleteDataItemsResponse(int status, int count) {\n        this.status = status;\n        this.count = count;\n    }\n\n    public static final Creator<DeleteDataItemsResponse> CREATOR = new AutoCreator<DeleteDataItemsResponse>(DeleteDataItemsResponse.class);\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/internal/GetAllCapabilitiesResponse.java",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 com.google.android.gms.wearable.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\nimport java.util.List;\n\npublic class GetAllCapabilitiesResponse extends AutoSafeParcelable {\n    @Field(1)\n    private int versionCode = 1;\n    @Field(2)\n    public int statusCode;\n    @Field(3)\n    public List<CapabilityInfoParcelable> capabilities;\n\n    public static final Creator<GetAllCapabilitiesResponse> CREATOR = findCreator(GetAllCapabilitiesResponse.class);\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/internal/GetCapabilityResponse.java",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 com.google.android.gms.wearable.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class GetCapabilityResponse extends AutoSafeParcelable {\n    @SafeParceled(1)\n    private int versionCode = 1;\n    @SafeParceled(2)\n    private int status;\n    @SafeParceled(3)\n    private CapabilityInfoParcelable capabilityInfo;\n\n    private GetCapabilityResponse() {\n    }\n\n    public GetCapabilityResponse(int status, CapabilityInfoParcelable capabilityInfo) {\n        this.status = status;\n        this.capabilityInfo = capabilityInfo;\n    }\n\n    public static final Creator<GetCapabilityResponse> CREATOR = new AutoCreator<GetCapabilityResponse>(GetCapabilityResponse.class);\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/internal/GetChannelInputStreamResponse.java",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 com.google.android.gms.wearable.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class GetChannelInputStreamResponse extends AutoSafeParcelable {\n    @SafeParceled(1)\n    private int versionCode = 1;\n    public static final Creator<GetChannelInputStreamResponse> CREATOR = new AutoCreator<GetChannelInputStreamResponse>(GetChannelInputStreamResponse.class);\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/internal/GetChannelOutputStreamResponse.java",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 com.google.android.gms.wearable.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class GetChannelOutputStreamResponse extends AutoSafeParcelable {\n    @SafeParceled(1)\n    private int versionCode = 1;\n    public static final Creator<GetChannelOutputStreamResponse> CREATOR = new AutoCreator<GetChannelOutputStreamResponse>(GetChannelOutputStreamResponse.class);\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/internal/GetCloudSyncOptInOutDoneResponse.java",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 com.google.android.gms.wearable.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class GetCloudSyncOptInOutDoneResponse extends AutoSafeParcelable {\n    @SafeParceled(1)\n    private int versionCode = 1;\n    public static final Creator<GetCloudSyncOptInOutDoneResponse> CREATOR = new AutoCreator<GetCloudSyncOptInOutDoneResponse>(GetCloudSyncOptInOutDoneResponse.class);\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/internal/GetCloudSyncOptInStatusResponse.java",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 com.google.android.gms.wearable.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class GetCloudSyncOptInStatusResponse extends AutoSafeParcelable {\n    @SafeParceled(1)\n    private int versionCode = 1;\n    public static final Creator<GetCloudSyncOptInStatusResponse> CREATOR = new AutoCreator<GetCloudSyncOptInStatusResponse>(GetCloudSyncOptInStatusResponse.class);\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/internal/GetCloudSyncSettingResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class GetCloudSyncSettingResponse extends AutoSafeParcelable {\n    @SafeParceled(1)\n    private int versionCode = 1;\n    @SafeParceled(2)\n    public int statusCode;\n    @SafeParceled(3)\n    public boolean cloudSyncEnabled;\n\n    private GetCloudSyncSettingResponse() {}\n\n    public GetCloudSyncSettingResponse(int statusCode, boolean cloudSyncEnabled) {\n        this.statusCode = statusCode;\n        this.cloudSyncEnabled = cloudSyncEnabled;\n    }\n\n    public static final Creator<GetCloudSyncSettingResponse> CREATOR = new AutoCreator<GetCloudSyncSettingResponse>(GetCloudSyncSettingResponse.class);\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/internal/GetConfigResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable.internal;\n\nimport com.google.android.gms.wearable.ConnectionConfiguration;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class GetConfigResponse extends AutoSafeParcelable {\n    @SafeParceled(1)\n    private int versionCode = 1;\n    @SafeParceled(2)\n    public final int statusCode;\n    @SafeParceled(3)\n    public final ConnectionConfiguration connectionConfiguration;\n\n    private GetConfigResponse() {\n        statusCode = 0;\n        connectionConfiguration = null;\n    }\n\n    public GetConfigResponse(int statusCode, ConnectionConfiguration connectionConfiguration) {\n        this.statusCode = statusCode;\n        this.connectionConfiguration = connectionConfiguration;\n    }\n\n    public static final Creator<GetConfigResponse> CREATOR = new AutoCreator<GetConfigResponse>(GetConfigResponse.class);\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/internal/GetConfigsResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable.internal;\n\nimport com.google.android.gms.wearable.ConnectionConfiguration;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class GetConfigsResponse extends AutoSafeParcelable {\n    @SafeParceled(1)\n    private int versionCode = 1;\n    @SafeParceled(2)\n    public final int statusCode;\n    @SafeParceled(3)\n    public final ConnectionConfiguration[] configurations;\n\n    private GetConfigsResponse() {\n        statusCode = 0;\n        configurations = null;\n    }\n\n    public GetConfigsResponse(int statusCode, ConnectionConfiguration[] configurations) {\n        this.statusCode = statusCode;\n        this.configurations = configurations;\n    }\n\n    public static final Creator<GetConfigsResponse> CREATOR = new AutoCreator<GetConfigsResponse>(GetConfigsResponse.class);\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/internal/GetConnectedNodesResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\nimport java.util.List;\n\npublic class GetConnectedNodesResponse extends AutoSafeParcelable {\n    @SafeParceled(1)\n    private int versionCode = 1;\n    @SafeParceled(2)\n    public final int statusCode;\n    @SafeParceled(value = 3, subClass = NodeParcelable.class)\n    public final List<NodeParcelable> nodes;\n\n    private GetConnectedNodesResponse() {\n        statusCode = 0;\n        nodes = null;\n    }\n\n    public GetConnectedNodesResponse(int statusCode, List<NodeParcelable> nodes) {\n        this.statusCode = statusCode;\n        this.nodes = nodes;\n    }\n\n    public static final Creator<GetConnectedNodesResponse> CREATOR = new AutoCreator<GetConnectedNodesResponse>(GetConnectedNodesResponse.class);\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/internal/GetDataItemResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class GetDataItemResponse extends AutoSafeParcelable {\n    @SafeParceled(1)\n    private int versionCode = 1;\n    @SafeParceled(2)\n    public final int statusCode;\n    @SafeParceled(3)\n    public final DataItemParcelable dataItem;\n\n    private GetDataItemResponse() {\n        statusCode = 0;\n        dataItem = null;\n    }\n\n    public GetDataItemResponse(int statusCode, DataItemParcelable dataItem) {\n        this.statusCode = statusCode;\n        this.dataItem = dataItem;\n    }\n\n    public static final Creator<GetDataItemResponse> CREATOR = new AutoCreator<GetDataItemResponse>(GetDataItemResponse.class);\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/internal/GetFdForAssetResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable.internal;\n\nimport android.os.ParcelFileDescriptor;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class GetFdForAssetResponse extends AutoSafeParcelable {\n    @SafeParceled(1)\n    private int versionCode = 1;\n\n    @SafeParceled(2)\n    public int statusCode;\n\n    @SafeParceled(3)\n    public ParcelFileDescriptor pfd;\n\n    private GetFdForAssetResponse() {\n    }\n\n    public GetFdForAssetResponse(int statusCode, ParcelFileDescriptor pfd) {\n        this.statusCode = statusCode;\n        this.pfd = pfd;\n    }\n\n    public static final Creator<GetFdForAssetResponse> CREATOR = new AutoCreator<GetFdForAssetResponse>(GetFdForAssetResponse.class);\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/internal/GetLocalNodeResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class GetLocalNodeResponse extends AutoSafeParcelable {\n    @SafeParceled(1)\n    private int versionCode = 1;\n    @SafeParceled(2)\n    public final int statusCode;\n    @SafeParceled(3)\n    public final NodeParcelable node;\n\n    private GetLocalNodeResponse() {\n        statusCode = 0;\n        node = null;\n    }\n\n    public GetLocalNodeResponse(int statusCode, NodeParcelable node) {\n        this.statusCode = statusCode;\n        this.node = node;\n    }\n\n    public static final Creator<GetLocalNodeResponse> CREATOR = new AutoCreator<GetLocalNodeResponse>(GetLocalNodeResponse.class);\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/internal/MessageEventParcelable.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable.internal;\n\nimport com.google.android.gms.wearable.MessageEvent;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class MessageEventParcelable extends AutoSafeParcelable implements MessageEvent {\n\n    @SafeParceled(1)\n    private int versionCode = 1;\n    @SafeParceled(2)\n    public int requestId;\n    @SafeParceled(3)\n    public String path;\n    @SafeParceled(4)\n    public byte[] data;\n    @SafeParceled(5)\n    public String sourceNodeId;\n\n    @Override\n    public byte[] getData() {\n        return data;\n    }\n\n    @Override\n    public String getPath() {\n        return path;\n    }\n\n    @Override\n    public int getRequestId() {\n        return requestId;\n    }\n\n    @Override\n    public String getSourceNodeId() {\n        return sourceNodeId;\n    }\n\n    @Override\n    public String toString() {\n        return \"MessageEventParcelable{\" +\n                \"requestId=\" + requestId +\n                \", path='\" + path + '\\'' +\n                \", dataSize=\" + (data != null ? data.length : -1) +\n                \", sourceNodeId='\" + sourceNodeId + '\\'' +\n                '}';\n    }\n\n    public static final Creator<MessageEventParcelable> CREATOR = new AutoCreator<MessageEventParcelable>(MessageEventParcelable.class);\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/internal/NodeParcelable.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable.internal;\n\nimport com.google.android.gms.wearable.Node;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\n/**\n * Parcelable implementation of the {@link com.google.android.gms.wearable.Node} interface.\n */\npublic class NodeParcelable extends AutoSafeParcelable implements Node {\n    @SafeParceled(1)\n    private int versionCode = 1;\n    @SafeParceled(2)\n    private final String nodeId;\n    @SafeParceled(3)\n    private final String displayName;\n    @SafeParceled(4)\n    private final int hops;\n    @SafeParceled(5)\n    private final boolean isNearby;\n\n    private NodeParcelable() {\n        nodeId = displayName = null;\n        hops = 0;\n        isNearby = false;\n    }\n\n    public NodeParcelable(String nodeId, String displayName, int hops, boolean isNearby) {\n        this.nodeId = nodeId;\n        this.displayName = displayName;\n        this.hops = hops;\n        this.isNearby = isNearby;\n    }\n\n    public NodeParcelable(String nodeId, String displayName) {\n        this(nodeId, displayName, 0, false);\n    }\n\n    public NodeParcelable(Node node) {\n        this(node.getId(), node.getDisplayName(), 0, node.isNearby());\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        NodeParcelable that = (NodeParcelable) o;\n\n        if (!nodeId.equals(that.nodeId)) return false;\n        if (!displayName.equals(that.displayName)) return false;\n\n        return true;\n    }\n\n    @Override\n    public String getDisplayName() {\n        return displayName;\n    }\n\n    @Override\n    public String getId() {\n        return nodeId;\n    }\n\n    @Override\n    public boolean isNearby() {\n        return isNearby;\n    }\n\n    @Override\n    public int hashCode() {\n        return nodeId.hashCode();\n    }\n\n    @Override\n    public String toString() {\n        return \"NodeParcelable{\" + displayName + \", id=\" + displayName + \", hops=\" + hops + \", isNearby=\" + isNearby + \"}\";\n    }\n\n    public static final Creator<NodeParcelable> CREATOR = new AutoCreator<NodeParcelable>(NodeParcelable.class);\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/internal/OpenChannelResponse.java",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 com.google.android.gms.wearable.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class OpenChannelResponse extends AutoSafeParcelable {\n    @SafeParceled(1)\n    private int versionCode = 1;\n    public static final Creator<OpenChannelResponse> CREATOR = new AutoCreator<OpenChannelResponse>(OpenChannelResponse.class);\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/internal/PutDataRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable.internal;\n\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.text.TextUtils;\nimport android.util.Base64;\n\nimport com.google.android.gms.wearable.Asset;\nimport com.google.android.gms.wearable.DataItem;\n\nimport org.microg.gms.common.PublicApi;\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * {@link PutDataRequest} is used to create new data items in the Android Wear network.\n */\n@PublicApi\npublic class PutDataRequest extends AutoSafeParcelable {\n    public static final String WEAR_URI_SCHEME = \"wear\";\n    private static final int DEFAULT_SYNC_DEADLINE = 30 * 60 * 1000;\n\n    @SafeParceled(1)\n    private int versionCode = 1;\n    @SafeParceled(2)\n    final Uri uri;\n    @SafeParceled(4)\n    private final Bundle assets;\n    @SafeParceled(5)\n    byte[] data;\n    @SafeParceled(6)\n    long syncDeadline = DEFAULT_SYNC_DEADLINE;\n\n    private PutDataRequest() {\n        uri = null;\n        assets = new Bundle();\n    }\n\n    private PutDataRequest(Uri uri) {\n        this.uri = uri;\n        assets = new Bundle();\n    }\n\n    public static PutDataRequest create(Uri uri) {\n        return new PutDataRequest(uri);\n    }\n\n    public static PutDataRequest create(String path) {\n        if (TextUtils.isEmpty(path)) {\n            throw new IllegalArgumentException(\"An empty path was supplied.\");\n        } else if (!path.startsWith(\"/\")) {\n            throw new IllegalArgumentException(\"A path must start with a single / .\");\n        } else if (path.startsWith(\"//\")) {\n            throw new IllegalArgumentException(\"A path must start with a single / .\");\n        } else {\n            return create((new Uri.Builder()).scheme(WEAR_URI_SCHEME).path(path).build());\n        }\n    }\n\n    public static PutDataRequest createFromDataItem(DataItem source) {\n        PutDataRequest dataRequest = new PutDataRequest(source.getUri());\n        dataRequest.data = source.getData();\n        // TODO: assets\n        return dataRequest;\n    }\n\n    public static PutDataRequest createWithAutoAppendedId(String pathPrefix) {\n        return new PutDataRequest(null);\n    }\n\n    public Asset getAsset(String key) {\n        return assets.getParcelable(key);\n    }\n\n    public Map<String, Asset> getAssets() {\n        Map<String, Asset> map = new HashMap<String, Asset>();\n        assets.setClassLoader(DataItemAssetParcelable.class.getClassLoader());\n        for (String key : assets.keySet()) {\n            map.put(key, (Asset) assets.getParcelable(key));\n        }\n        return map;\n    }\n\n    public byte[] getData() {\n        return data;\n    }\n\n    public Uri getUri() {\n        return uri;\n    }\n\n    public boolean hasAsset(String key) {\n        return assets.containsKey(key);\n    }\n\n    public PutDataRequest putAsset(String key, Asset value) {\n        assets.putParcelable(key, value);\n        return this;\n    }\n\n    public PutDataRequest removeAsset(String key) {\n        assets.remove(key);\n        return this;\n    }\n\n    public PutDataRequest setData(byte[] data) {\n        this.data = data;\n        return this;\n    }\n\n    @Override\n    public String toString() {\n        return toString(false);\n    }\n\n    public String toString(boolean verbose) {\n        StringBuilder sb = new StringBuilder();\n        sb.append(\"PutDataRequest[uri=\").append(uri)\n                .append(\", data=\").append(data == null ? \"null\" : Base64.encodeToString(data, Base64.NO_WRAP))\n                .append(\", numAssets=\").append(getAssets().size());\n        if (verbose && !getAssets().isEmpty()) {\n            sb.append(\", assets=[\");\n            for (String key : getAssets().keySet()) {\n                sb.append(key).append('=').append(getAsset(key)).append(\", \");\n            }\n            sb.delete(sb.length() - 2, sb.length()).append(']');\n        }\n        sb.append(\"]\");\n        return sb.toString();\n    }\n\n    public static final Creator<PutDataRequest> CREATOR = new AutoCreator<PutDataRequest>(PutDataRequest.class);\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/internal/PutDataResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class PutDataResponse extends AutoSafeParcelable {\n    @SafeParceled(1)\n    private int versionCode = 1;\n    @SafeParceled(2)\n    public final int statusCode;\n    @SafeParceled(3)\n    public final DataItemParcelable dataItem;\n\n    private PutDataResponse() {\n        statusCode = 0;\n        dataItem = null;\n    }\n\n    public PutDataResponse(int statusCode, DataItemParcelable dataItem) {\n        this.statusCode = statusCode;\n        this.dataItem = dataItem;\n    }\n\n    public static final Creator<PutDataResponse> CREATOR = new AutoCreator<PutDataResponse>(PutDataResponse.class);\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/internal/RemoveListenerRequest.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class RemoveListenerRequest extends AutoSafeParcelable {\n    @SafeParceled(1)\n    private int versionCode = 1;\n    @SafeParceled(2)\n    public final IWearableListener listener;\n\n    private RemoveListenerRequest() {\n        listener = null;\n    }\n\n    public RemoveListenerRequest(IWearableListener listener) {\n        this.listener = listener;\n    }\n\n    public static final Creator<RemoveListenerRequest> CREATOR = new AutoCreator<RemoveListenerRequest>(RemoveListenerRequest.class);\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/internal/RemoveLocalCapabilityResponse.java",
    "content": "/*\n * Copyright (C) 2019 microG Project Team\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 com.google.android.gms.wearable.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class RemoveLocalCapabilityResponse extends AutoSafeParcelable {\n    @SafeParceled(1)\n    private int versionCode = 1;\n    @SafeParceled(2)\n    private int status = 0;\n\n    private RemoveLocalCapabilityResponse() {\n    }\n\n    public RemoveLocalCapabilityResponse(int status) {\n        this.status = status;\n    }\n\n    public static final Creator<RemoveLocalCapabilityResponse> CREATOR = new AutoCreator<RemoveLocalCapabilityResponse>(RemoveLocalCapabilityResponse.class);\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/internal/SendMessageResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\nimport org.microg.safeparcel.SafeParceled;\n\npublic class SendMessageResponse extends AutoSafeParcelable {\n\n    @SafeParceled(1)\n    private int versionCode = 1;\n\n    @SafeParceled(2)\n    public int statusCode;\n\n    @SafeParceled(3)\n    public int requestId = -1;\n\n    public static final Creator<SendMessageResponse> CREATOR = new AutoCreator<SendMessageResponse>(SendMessageResponse.class);\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/com/google/android/gms/wearable/internal/StorageInfoResponse.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 com.google.android.gms.wearable.internal;\n\nimport org.microg.safeparcel.AutoSafeParcelable;\n\npublic class StorageInfoResponse extends AutoSafeParcelable {\n    public static final Creator<StorageInfoResponse> CREATOR = new AutoCreator<StorageInfoResponse>(StorageInfoResponse.class);\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/org/microg/gms/wearable/BaseWearableCallbacks.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.wearable;\n\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.common.data.DataHolder;\nimport com.google.android.gms.wearable.internal.AddLocalCapabilityResponse;\nimport com.google.android.gms.wearable.internal.ChannelReceiveFileResponse;\nimport com.google.android.gms.wearable.internal.ChannelSendFileResponse;\nimport com.google.android.gms.wearable.internal.CloseChannelResponse;\nimport com.google.android.gms.wearable.internal.DeleteDataItemsResponse;\nimport com.google.android.gms.wearable.internal.GetAllCapabilitiesResponse;\nimport com.google.android.gms.wearable.internal.GetCapabilityResponse;\nimport com.google.android.gms.wearable.internal.GetChannelInputStreamResponse;\nimport com.google.android.gms.wearable.internal.GetChannelOutputStreamResponse;\nimport com.google.android.gms.wearable.internal.GetCloudSyncOptInOutDoneResponse;\nimport com.google.android.gms.wearable.internal.GetCloudSyncOptInStatusResponse;\nimport com.google.android.gms.wearable.internal.GetCloudSyncSettingResponse;\nimport com.google.android.gms.wearable.internal.GetConfigResponse;\nimport com.google.android.gms.wearable.internal.GetConfigsResponse;\nimport com.google.android.gms.wearable.internal.GetConnectedNodesResponse;\nimport com.google.android.gms.wearable.internal.GetDataItemResponse;\nimport com.google.android.gms.wearable.internal.GetFdForAssetResponse;\nimport com.google.android.gms.wearable.internal.GetLocalNodeResponse;\nimport com.google.android.gms.wearable.internal.IWearableCallbacks;\nimport com.google.android.gms.wearable.internal.OpenChannelResponse;\nimport com.google.android.gms.wearable.internal.PutDataResponse;\nimport com.google.android.gms.wearable.internal.RemoveLocalCapabilityResponse;\nimport com.google.android.gms.wearable.internal.SendMessageResponse;\nimport com.google.android.gms.wearable.internal.StorageInfoResponse;\n\npublic class BaseWearableCallbacks extends IWearableCallbacks.Stub {\n    private static final String TAG = \"GmsWearBaseCallback\";\n\n    @Override\n    public void onGetConfigResponse(GetConfigResponse response) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: onGetConfigResponse\");\n\n    }\n\n    @Override\n    public void onPutDataResponse(PutDataResponse response) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: onPutDataResponse\");\n\n    }\n\n    @Override\n    public void onGetDataItemResponse(GetDataItemResponse response) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: onGetDataItemResponse\");\n\n    }\n\n    @Override\n    public void onDataItemChanged(DataHolder dataHolder) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: onDataItemChanged\");\n\n    }\n\n    @Override\n    public void onDeleteDataItemsResponse(DeleteDataItemsResponse response) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: onDeleteDataItemsResponse\");\n\n    }\n\n    @Override\n    public void onSendMessageResponse(SendMessageResponse response) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: onSendMessageResponse\");\n\n    }\n\n    @Override\n    public void onGetFdForAssetResponse(GetFdForAssetResponse response) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: onGetFdForAssetResponse\");\n\n    }\n\n    @Override\n    public void onGetLocalNodeResponse(GetLocalNodeResponse response) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: onGetLocalNodeResponse\");\n\n    }\n\n    @Override\n    public void onGetConnectedNodesResponse(GetConnectedNodesResponse response) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: onGetConnectedNodesResponse\");\n\n    }\n\n    @Override\n    public void onOpenChannelResponse(OpenChannelResponse response) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: onOpenChannelResponse\");\n\n    }\n\n    @Override\n    public void onCloseChannelResponse(CloseChannelResponse response) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: onCloseChannelResponse\");\n\n    }\n\n    @Override\n    public void onGetChannelInputStreamResponse(GetChannelInputStreamResponse response) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: onGetChannelInputStreamResponse\");\n\n    }\n\n    @Override\n    public void onGetChannelOutputStreamResponse(GetChannelOutputStreamResponse response) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: onGetChannelOutputStreamResponse\");\n\n    }\n\n    @Override\n    public void onChannelReceiveFileResponse(ChannelReceiveFileResponse response) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: onChannelReceiveFileResponse\");\n\n    }\n\n    @Override\n    public void onChannelSendFileResponse(ChannelSendFileResponse response) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: onChannelSendFileResponse\");\n\n    }\n\n    @Override\n    public void onStatus(Status status) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: onStatus\");\n\n    }\n\n    @Override\n    public void onStorageInfoResponse(StorageInfoResponse response) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: onStorageInfoResponse\");\n\n    }\n\n    @Override\n    public void onGetCapabilityResponse(GetCapabilityResponse response) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: onGetCapabilityResponse\");\n\n    }\n\n    @Override\n    public void onGetAllCapabilitiesResponse(GetAllCapabilitiesResponse response) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: onGetAllCapabilitiesResponse\");\n\n    }\n\n    @Override\n    public void onAddLocalCapabilityResponse(AddLocalCapabilityResponse response) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: onAddLocalCapabilityResponse\");\n\n    }\n\n    @Override\n    public void onRemoveLocalCapabilityResponse(RemoveLocalCapabilityResponse response) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: onRemoveLocalCapabilityResponse\");\n\n    }\n\n    @Override\n    public void onGetConfigsResponse(GetConfigsResponse response) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: onGetConfigsResponse\");\n\n    }\n\n    @Override\n    public void onGetCloudSyncOptInOutDoneResponse(GetCloudSyncOptInOutDoneResponse response) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: onGetCloudSyncOptInOutDoneResponse\");\n\n    }\n\n    @Override\n    public void onGetCloudSyncSettingResponse(GetCloudSyncSettingResponse response) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: onGetCloudSyncSettingResponse\");\n\n    }\n\n    @Override\n    public void onGetCloudSyncOptInStatusResponse(GetCloudSyncOptInStatusResponse response) throws RemoteException {\n        Log.d(TAG, \"unimplemented Method: onGetCloudSyncOptInStatusResponse\");\n\n    }\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/org/microg/gms/wearable/ChannelImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.wearable;\n\nimport android.net.Uri;\nimport android.util.Log;\n\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.PendingResult;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.wearable.Channel;\nimport com.google.android.gms.wearable.ChannelApi;\nimport com.google.android.gms.wearable.internal.ChannelParcelable;\n\npublic class ChannelImpl extends ChannelParcelable implements Channel {\n    private static final String TAG = \"GmsWearChannelImpl\";\n\n    public ChannelImpl(String token, String nodeId, String path) {\n        super(token, nodeId, path);\n    }\n\n    public ChannelImpl(ChannelParcelable wrapped) {\n        this(wrapped.token, wrapped.nodeId, wrapped.path);\n    }\n\n\n    @Override\n    public PendingResult<Status> addListener(GoogleApiClient client, ChannelApi.ChannelListener listener) {\n        Log.d(TAG, \"unimplemented Method: addListener\");\n        return null;\n    }\n\n    @Override\n    public PendingResult<Status> close(GoogleApiClient client, int errorCode) {\n        Log.d(TAG, \"unimplemented Method: close\");\n        return null;\n    }\n\n    @Override\n    public PendingResult<Status> close(GoogleApiClient client) {\n        Log.d(TAG, \"unimplemented Method: close\");\n        return null;\n    }\n\n    @Override\n    public PendingResult<GetInputStreamResult> getInputStream(GoogleApiClient client) {\n        Log.d(TAG, \"unimplemented Method: getInputStream\");\n        return null;\n    }\n\n    @Override\n    public PendingResult<GetOutputStreamResult> getOutputStream(GoogleApiClient client) {\n        Log.d(TAG, \"unimplemented Method: getOutputStream\");\n        return null;\n    }\n\n    public String getNodeId() {\n        return nodeId;\n    }\n\n    @Override\n    public String getPath() {\n        return path;\n    }\n\n    public String getToken() {\n        return token;\n    }\n\n    @Override\n    public PendingResult<Status> receiveFile(GoogleApiClient client, Uri uri, boolean append) {\n        Log.d(TAG, \"unimplemented Method: receiveFile\");\n        return null;\n    }\n\n    @Override\n    public PendingResult<Status> removeListener(GoogleApiClient client, ChannelApi.ChannelListener listener) {\n        Log.d(TAG, \"unimplemented Method: removeListener\");\n        return null;\n    }\n\n    @Override\n    public PendingResult<Status> sendFile(GoogleApiClient client, Uri uri) {\n        Log.d(TAG, \"unimplemented Method: sendFile\");\n        return null;\n    }\n\n    @Override\n    public PendingResult<Status> sendFile(GoogleApiClient client, Uri uri, long startOffset, long length) {\n        Log.d(TAG, \"unimplemented Method: sendFile\");\n        return null;\n    }\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/org/microg/gms/wearable/DataApiImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.wearable;\n\nimport android.net.Uri;\n\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.PendingResult;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.wearable.Asset;\nimport com.google.android.gms.wearable.DataApi;\nimport com.google.android.gms.wearable.DataItemAsset;\nimport com.google.android.gms.wearable.DataItemBuffer;\nimport com.google.android.gms.wearable.internal.PutDataRequest;\n\npublic class DataApiImpl implements DataApi {\n    @Override\n    public PendingResult<Status> addListener(GoogleApiClient client, DataListener listener) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public PendingResult<DeleteDataItemsResult> deleteDataItems(GoogleApiClient client, Uri uri) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public PendingResult<DataItemResult> getDataItem(GoogleApiClient client, Uri uri) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public PendingResult<DataItemBuffer> getDataItems(GoogleApiClient client) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public PendingResult<DataItemBuffer> getDataItems(GoogleApiClient client, Uri uri) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public PendingResult<GetFdForAssetResult> getFdForAsset(GoogleApiClient client, DataItemAsset asset) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public PendingResult<GetFdForAssetResult> getFdForAsset(GoogleApiClient client, Asset asset) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public PendingResult<DataItemResult> putDataItem(GoogleApiClient client, PutDataRequest request) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public PendingResult<Status> removeListener(GoogleApiClient client, DataListener listener) {\n        throw new UnsupportedOperationException();\n    }\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/org/microg/gms/wearable/MessageApiImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.wearable;\n\nimport android.os.RemoteException;\n\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.PendingResult;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.wearable.MessageApi;\nimport com.google.android.gms.wearable.Wearable;\nimport com.google.android.gms.wearable.internal.SendMessageResponse;\n\nimport org.microg.gms.common.GmsConnector;\n\npublic class MessageApiImpl implements MessageApi {\n    @Override\n    public PendingResult<Status> addListener(GoogleApiClient client, MessageListener listener) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public PendingResult<Status> removeListener(GoogleApiClient client, MessageListener listener) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public PendingResult<SendMessageResult> sendMessage(GoogleApiClient client, final String nodeId, final String path, final byte[] data) {\n        return GmsConnector.call(client, Wearable.API, new GmsConnector.Callback<WearableClientImpl, SendMessageResult>() {\n            @Override\n            public void onClientAvailable(WearableClientImpl client, final ResultProvider<SendMessageResult> resultProvider) throws RemoteException {\n                client.getServiceInterface().sendMessage(new BaseWearableCallbacks() {\n                    @Override\n                    public void onSendMessageResponse(SendMessageResponse response) throws RemoteException {\n                        resultProvider.onResultAvailable(new SendMessageResultImpl(response));\n                    }\n                }, nodeId, path, data);\n            }\n        });\n    }\n\n    public static class SendMessageResultImpl implements SendMessageResult {\n        private SendMessageResponse response;\n\n        public SendMessageResultImpl(SendMessageResponse response) {\n            this.response = response;\n        }\n\n        @Override\n        public int getRequestId() {\n            return response.requestId;\n        }\n\n        @Override\n        public Status getStatus() {\n            return new Status(response.statusCode);\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/org/microg/gms/wearable/NodeApiImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.wearable;\n\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.PendingResult;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.gms.wearable.NodeApi;\n\npublic class NodeApiImpl implements NodeApi {\n    @Override\n    public PendingResult<Status> addListener(GoogleApiClient client, NodeListener listener) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public PendingResult<GetConnectedNodesResult> getConnectedNodes(GoogleApiClient client) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public PendingResult<GetLocalNodeResult> getLocalNode(GoogleApiClient client) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public PendingResult<Status> removeListener(GoogleApiClient client, NodeListener listener) {\n        throw new UnsupportedOperationException();\n    }\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/org/microg/gms/wearable/WearableApiClientBuilder.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.wearable;\n\nimport android.content.Context;\nimport android.os.Looper;\n\nimport com.google.android.gms.common.api.Api;\nimport com.google.android.gms.wearable.Wearable;\n\nimport org.microg.gms.common.api.ApiClientBuilder;\nimport com.google.android.gms.common.internal.ClientSettings;\nimport com.google.android.gms.common.api.internal.ConnectionCallbacks;\nimport com.google.android.gms.common.api.internal.OnConnectionFailedListener;\n\npublic class WearableApiClientBuilder implements ApiClientBuilder<Wearable.WearableOptions> {\n    private static final String TAG = \"GmsWearableApi\";\n\n    @Override\n    public Api.Client build(Wearable.WearableOptions options, Context context, Looper looper, ClientSettings clientSettings, ConnectionCallbacks callbacks, OnConnectionFailedListener connectionFailedListener) {\n        return new WearableClientImpl(context, options, callbacks, connectionFailedListener);\n    }\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/org/microg/gms/wearable/WearableClientImpl.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.wearable;\n\nimport android.content.Context;\nimport android.os.IBinder;\nimport android.util.Log;\n\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.wearable.Wearable;\nimport com.google.android.gms.wearable.internal.IWearableService;\n\nimport org.microg.gms.common.GmsClient;\nimport org.microg.gms.common.GmsService;\nimport com.google.android.gms.common.api.internal.ConnectionCallbacks;\nimport org.microg.gms.common.api.GoogleApiClientImpl;\nimport com.google.android.gms.common.api.internal.OnConnectionFailedListener;\n\npublic class WearableClientImpl extends GmsClient<IWearableService> {\n    private static final String TAG = \"GmsWearClient\";\n\n    public WearableClientImpl(Context context, Wearable.WearableOptions options, ConnectionCallbacks callbacks, OnConnectionFailedListener connectionFailedListener) {\n        super(context, callbacks, connectionFailedListener, GmsService.WEAR.ACTION);\n        serviceId = GmsService.WEAR.SERVICE_ID;\n        if (options != null && options.firstPartyMode)\n            extras.putBoolean(\"firstPartyMode\", true);\n        Log.d(TAG, \"<init>\");\n    }\n\n    @Override\n    protected IWearableService interfaceFromBinder(IBinder binder) {\n        return IWearableService.Stub.asInterface(binder);\n    }\n\n    public static WearableClientImpl get(GoogleApiClient apiClient) {\n        if (apiClient instanceof GoogleApiClientImpl) {\n            return (WearableClientImpl) ((GoogleApiClientImpl) apiClient).getApiConnection(Wearable.API);\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/java/org/microg/gms/wearable/databundle/DataBundleUtil.java",
    "content": "/*\n * Copyright (C) 2013-2017 microG Project Team\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 org.microg.gms.wearable.databundle;\n\nimport android.util.SparseArray;\n\nimport com.google.android.gms.wearable.Asset;\nimport com.google.android.gms.wearable.DataMap;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport okio.ByteString;\n\npublic class DataBundleUtil {\n\n    public static DataMap readDataMap(byte[] bytes, List<Asset> assets) {\n        try {\n            return readDataMap(DataBundle.ADAPTER.decode(bytes), assets);\n        } catch (IOException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public static DataMap readDataMap(DataBundle dataBundle, List<Asset> assets) {\n        return readDataMap(dataBundle.entries, assets);\n    }\n\n    public static DataMap readDataMap(List<DataBundleEntry> entries, List<Asset> assets) {\n        DataMap dataMap = new DataMap();\n        for (DataBundleEntry entry : entries) {\n            readAndStore(dataMap, entry.key, entry.typedValue, assets);\n        }\n        return dataMap;\n    }\n\n    public static byte[] createBytes(DataMap dataMap) {\n        AssetAnnotatedDataBundle dataBundle = createDataBundle(dataMap);\n        if (!dataBundle.getAssets().isEmpty()) {\n            throw new UnsupportedOperationException();\n        }\n        return dataBundle.getData();\n    }\n\n    public static AssetAnnotatedDataBundle createDataBundle(DataMap dataMap) {\n        AssetAnnotatedDataBundle dataBundle = new AssetAnnotatedDataBundle();\n        dataBundle.assets = new ArrayList<Asset>();\n        dataBundle.dataBundle = new DataBundle.Builder().entries(createEntryList(dataMap, dataBundle.assets)).build();\n        return dataBundle;\n    }\n\n    private static List<DataBundleEntry> createEntryList(DataMap dataMap, List<Asset> assets) {\n        List<DataBundleEntry> entries = new ArrayList<DataBundleEntry>();\n        for (String key : dataMap.keySet()) {\n            entries.add(getTypeHelper(dataMap.getType(key)).loadAndCreateEntry(dataMap, key, assets));\n        }\n        return entries;\n    }\n\n    private static void readAndStore(DataMap dataMap, String key, DataBundleTypedValue value, List<Asset> assets) {\n        if (value.type == null) return;\n        getTypeHelper(value.type).readAndStore(dataMap, key, value, assets);\n    }\n\n\n    private static SparseArray<TypeHelper> typeHelperByCode;\n\n    private static void rememberTypeReader(TypeHelper typeHelper) {\n        typeHelperByCode.put(typeHelper.type, typeHelper);\n    }\n\n    static TypeHelper getTypeHelper(int type) {\n        if (typeHelperByCode.get(type) != null) {\n            return typeHelperByCode.get(type);\n        } else {\n            throw new IllegalArgumentException();\n        }\n    }\n\n    static TypeHelper getTypeHelper(DataMap.StoredType type) {\n        return getTypeHelper(type.getTypeCode());\n    }\n\n    static TypeHelper getListInnerTypeHelper(DataMap.StoredType type) {\n        return getTypeHelper(type.getListType());\n    }\n\n    public static final int BYTE_ARRAY_TYPE_CODE = 1;\n    static TypeHelper<byte[]> BYTEARRAY = new TypeHelper<byte[]>(BYTE_ARRAY_TYPE_CODE) {\n        @Override\n        byte[] read(DataBundleValue value, List<Asset> assets) {\n            return value.byteArray.toByteArray();\n        }\n\n        @Override\n        DataBundleValue create(byte[] value, List<Asset> assets) {\n            return new DataBundleValue.Builder().byteArray(ByteString.of(value)).build();\n        }\n\n        @Override\n        void store(DataMap dataMap, String key, byte[] value) {\n            dataMap.putByteArray(key, value);\n        }\n\n        @Override\n        byte[] load(DataMap dataMap, String key) {\n            return dataMap.getByteArray(key);\n        }\n    };\n\n    public static final int STRING_TYPE_CODE = 2;\n    static TypeHelper<String> STRING = new TypeHelper<String>(STRING_TYPE_CODE) {\n        @Override\n        String read(DataBundleValue value, List<Asset> assets) {\n            return value.stringVal;\n        }\n\n        @Override\n        DataBundleValue create(String value, List<Asset> assets) {\n            return new DataBundleValue.Builder().stringVal(value).build();\n        }\n\n        @Override\n        void store(DataMap dataMap, String key, String value) {\n            if (value != null) dataMap.putString(key, value);\n        }\n\n        @Override\n        void storeList(DataMap dataMap, String key, ArrayList<String> valueList) {\n            dataMap.putStringArrayList(key, valueList);\n        }\n\n        @Override\n        String load(DataMap dataMap, String key) {\n            return dataMap.getString(key);\n        }\n\n        @Override\n        AnnotatedArrayList<String> loadList(DataMap dataMap, String key) {\n            AnnotatedArrayList<String> list = new AnnotatedArrayList<String>(this);\n            list.addAll(dataMap.getStringArrayList(key));\n            return list;\n        }\n    };\n\n    public static final int DOUBLE_TYPE_CODE = 3;\n    static TypeHelper<Double> DOUBLE = new TypeHelper<Double>(DOUBLE_TYPE_CODE) {\n        @Override\n        Double read(DataBundleValue value, List<Asset> assets) {\n            return value.doubleVal;\n        }\n\n        @Override\n        DataBundleValue create(Double value, List<Asset> assets) {\n            return new DataBundleValue.Builder().doubleVal(value).build();\n        }\n\n        @Override\n        void store(DataMap dataMap, String key, Double value) {\n            if (value != null) dataMap.putDouble(key, value);\n        }\n\n        @Override\n        Double load(DataMap dataMap, String key) {\n            return dataMap.getDouble(key);\n        }\n    };\n\n    public static final int FLOAT_TYPE_CODE = 4;\n    static TypeHelper<Float> FLOAT = new TypeHelper<Float>(FLOAT_TYPE_CODE) {\n        @Override\n        Float read(DataBundleValue value, List<Asset> assets) {\n            return value.floatVal;\n        }\n\n        @Override\n        DataBundleValue create(Float value, List<Asset> assets) {\n            return new DataBundleValue.Builder().floatVal(value).build();\n        }\n\n        @Override\n        void store(DataMap dataMap, String key, Float value) {\n            if (value != null) dataMap.putFloat(key, value);\n        }\n\n        @Override\n        Float load(DataMap dataMap, String key) {\n            return dataMap.getFloat(key);\n        }\n    };\n\n    public static final int LONG_TYPE_CODE = 5;\n    static TypeHelper<Long> LONG = new TypeHelper<Long>(LONG_TYPE_CODE) {\n        @Override\n        Long read(DataBundleValue value, List<Asset> assets) {\n            return value.longVal;\n        }\n\n        @Override\n        DataBundleValue create(Long value, List<Asset> assets) {\n            return new DataBundleValue.Builder().longVal(value).build();\n        }\n\n        @Override\n        void store(DataMap dataMap, String key, Long value) {\n            if (value != null) dataMap.putLong(key, value);\n        }\n\n        @Override\n        Long load(DataMap dataMap, String key) {\n            return dataMap.getLong(key);\n        }\n    };\n\n    public static final int INTEGER_TYPE_CODE = 6;\n    static TypeHelper<Integer> INTEGER = new TypeHelper<Integer>(INTEGER_TYPE_CODE) {\n        @Override\n        Integer read(DataBundleValue value, List<Asset> assets) {\n            return value.intVal;\n        }\n\n        @Override\n        DataBundleValue create(Integer value, List<Asset> assets) {\n            return new DataBundleValue.Builder().intVal(value).build();\n        }\n\n        @Override\n        void store(DataMap dataMap, String key, Integer value) {\n            if (value != null) dataMap.putInt(key, value);\n        }\n\n        @Override\n        void storeList(DataMap dataMap, String key, ArrayList<Integer> valueList) {\n            dataMap.putIntegerArrayList(key, valueList);\n        }\n\n        @Override\n        Integer load(DataMap dataMap, String key) {\n            return dataMap.getInt(key);\n        }\n\n        @Override\n        AnnotatedArrayList<Integer> loadList(DataMap dataMap, String key) {\n            AnnotatedArrayList<Integer> list = new AnnotatedArrayList<Integer>(this);\n            list.addAll(dataMap.getIntegerArrayList(key));\n            return list;\n        }\n    };\n\n    public static final int BYTE_TYPE_CODE = 7;\n    static TypeHelper<Byte> BYTE = new TypeHelper<Byte>(BYTE_TYPE_CODE) {\n        @Override\n        Byte read(DataBundleValue value, List<Asset> assets) {\n            return (byte) (int) value.byteVal;\n        }\n\n        @Override\n        DataBundleValue create(Byte value, List<Asset> assets) {\n            return new DataBundleValue.Builder().byteVal((int) (byte) value).build();\n        }\n\n        @Override\n        void store(DataMap dataMap, String key, Byte value) {\n            if (value != null) dataMap.putByte(key, value);\n        }\n\n        @Override\n        Byte load(DataMap dataMap, String key) {\n            return dataMap.getByte(key);\n        }\n    };\n\n    public static final int BOOLEAN_TYPE_CODE = 8;\n    static TypeHelper<Boolean> BOOLEAN = new TypeHelper<Boolean>(BOOLEAN_TYPE_CODE) {\n        @Override\n        Boolean read(DataBundleValue value, List<Asset> assets) {\n            return value.booleanVal;\n        }\n\n        @Override\n        DataBundleValue create(Boolean value, List<Asset> assets) {\n            return new DataBundleValue.Builder().booleanVal(value).build();\n        }\n\n        @Override\n        void store(DataMap dataMap, String key, Boolean value) {\n            if (value != null) dataMap.putBoolean(key, value);\n        }\n\n        @Override\n        Boolean load(DataMap dataMap, String key) {\n            return dataMap.getBoolean(key);\n        }\n    };\n\n    public static final int DATAMAP_TYPE_CODE = 9;\n    static TypeHelper<DataMap> DATAMAP = new TypeHelper<DataMap>(DATAMAP_TYPE_CODE) {\n        @Override\n        DataMap read(DataBundleValue value, List<Asset> assets) {\n            return readDataMap(value.map, assets);\n        }\n\n        @Override\n        DataBundleValue create(DataMap value, List<Asset> assets) {\n            return new DataBundleValue.Builder().map(createEntryList(value, assets)).build();\n        }\n\n        @Override\n        void store(DataMap dataMap, String key, DataMap value) {\n            dataMap.putDataMap(key, value);\n        }\n\n        @Override\n        void storeList(DataMap dataMap, String key, ArrayList<DataMap> valueList) {\n            dataMap.putDataMapArrayList(key, valueList);\n        }\n\n        @Override\n        DataMap load(DataMap dataMap, String key) {\n            return dataMap.getDataMap(key);\n        }\n\n        @Override\n        AnnotatedArrayList<DataMap> loadList(DataMap dataMap, String key) {\n            AnnotatedArrayList<DataMap> list = new AnnotatedArrayList<DataMap>(this);\n            list.addAll(dataMap.getDataMapArrayList(key));\n            return list;\n        }\n    };\n\n    public static final int LIST_TYPE_CODE = 10;\n    static TypeHelper<AnnotatedArrayList<?>> ARRAYLIST = new TypeHelper<AnnotatedArrayList<?>>(LIST_TYPE_CODE) {\n        @Override\n        AnnotatedArrayList read(DataBundleValue value, List<Asset> assets) {\n            TypeHelper innerTypeHelper = NULL;\n            for (DataBundleTypedValue typedValue : value.list) {\n                if (innerTypeHelper == NULL) {\n                    innerTypeHelper = getTypeHelper(typedValue.type);\n                } else if (typedValue.type != innerTypeHelper.type && typedValue.type != NULL.type) {\n                    throw new IllegalArgumentException(\"List has elements of different types: \" + innerTypeHelper.type + \" and \" + typedValue.type);\n                }\n            }\n            return innerTypeHelper.readList(value.list, assets);\n        }\n\n        @Override\n        DataBundleValue create(AnnotatedArrayList<?> value, List<Asset> assets) {\n            return new DataBundleValue.Builder().list(value.createList(assets)).build();\n        }\n\n        @Override\n        void store(DataMap dataMap, String key, AnnotatedArrayList value) {\n            value.store(dataMap, key);\n        }\n\n        @Override\n        AnnotatedArrayList load(DataMap dataMap, String key) {\n            return getListInnerTypeHelper(dataMap.getType(key)).loadList(dataMap, key);\n        }\n    };\n\n    public static final int STRING_ARRAY_TYPE_CODE = 11;\n    static TypeHelper<String[]> STRINGARRAY = new TypeHelper<String[]>(STRING_ARRAY_TYPE_CODE) {\n        @Override\n        String[] read(DataBundleValue value, List<Asset> assets) {\n            return value.stringArray.toArray(new String[value.stringArray.size()]);\n        }\n\n        @Override\n        DataBundleValue create(String[] value, List<Asset> assets) {\n            return new DataBundleValue.Builder().stringArray(Arrays.asList(value)).build();\n        }\n\n        @Override\n        void store(DataMap dataMap, String key, String[] value) {\n            dataMap.putStringArray(key, value);\n        }\n\n        @Override\n        String[] load(DataMap dataMap, String key) {\n            return dataMap.getStringArray(key);\n        }\n    };\n\n    public static final int LONG_ARRAY_TYPE_CODE = 12;\n    static TypeHelper<long[]> LONGARRAY = new TypeHelper<long[]>(LONG_ARRAY_TYPE_CODE) {\n        @Override\n        long[] read(DataBundleValue value, List<Asset> assets) {\n            long[] longArr = new long[value.longArray.size()];\n            for (int i = 0; i < value.longArray.size(); i++) {\n                longArr[i] = value.longArray.get(i);\n            }\n            return longArr;\n        }\n\n        @Override\n        DataBundleValue create(long[] value, List<Asset> assets) {\n            List<Long> longList = new ArrayList<Long>(value.length);\n            for (long l : value) {\n                longList.add(l);\n            }\n            return new DataBundleValue.Builder().longArray(longList).build();\n        }\n\n        @Override\n        void store(DataMap dataMap, String key, long[] value) {\n            dataMap.putLongArray(key, value);\n        }\n\n        @Override\n        long[] load(DataMap dataMap, String key) {\n            return dataMap.getLongArray(key);\n        }\n    };\n\n    public static final int ASSET_TYPE_CODE = 13;\n    static TypeHelper<Asset> ASSET = new TypeHelper<Asset>(ASSET_TYPE_CODE) {\n        @Override\n        Asset read(DataBundleValue value, List<Asset> assets) {\n            return assets.get(value.assetIndex);\n        }\n\n        @Override\n        DataBundleValue create(Asset value, List<Asset> assets) {\n            int index;\n            if (assets.contains(value)) {\n                index = assets.indexOf(value);\n            } else {\n                index = assets.size();\n                assets.add(value);\n            }\n            return new DataBundleValue.Builder().assetIndex(index).build();\n        }\n\n        @Override\n        void store(DataMap dataMap, String key, Asset value) {\n            dataMap.putAsset(key, value);\n        }\n\n        @Override\n        Asset load(DataMap dataMap, String key) {\n            return dataMap.getAsset(key);\n        }\n    };\n\n    public static final int NULL_TYPE_CODE = 14;\n    static TypeHelper<String> NULL = new TypeHelper<String>(NULL_TYPE_CODE) {\n        @Override\n        String read(DataBundleValue value, List<Asset> assets) {\n            return null;\n        }\n\n        @Override\n        DataBundleValue create(String value, List<Asset> assets) {\n            return new DataBundleValue.Builder().build();\n        }\n\n        @Override\n        void store(DataMap dataMap, String key, String value) {\n            dataMap.putString(key, value);\n        }\n\n        @Override\n        void storeList(DataMap dataMap, String key, ArrayList<String> valueList) {\n            dataMap.putStringArrayList(key, valueList);\n        }\n\n        @Override\n        String load(DataMap dataMap, String key) {\n            return null;\n        }\n\n        @Override\n        AnnotatedArrayList<String> loadList(DataMap dataMap, String key) {\n            AnnotatedArrayList<String> list = new AnnotatedArrayList<String>(this);\n            list.addAll(dataMap.getStringArrayList(key));\n            return list;\n        }\n    };\n\n    public static final int FLOAT_ARRAY_TYPE_CODE = 15;\n    static TypeHelper<float[]> FLOATARRAY = new TypeHelper<float[]>(FLOAT_ARRAY_TYPE_CODE) {\n        @Override\n        float[] read(DataBundleValue value, List<Asset> assets) {\n            float[] floatArr = new float[value.floatArray.size()];\n            for (int i = 0; i < value.floatArray.size(); i++) {\n                floatArr[i] = value.floatArray.get(i);\n            }\n            return floatArr;\n        }\n\n        @Override\n        DataBundleValue create(float[] value, List<Asset> assets) {\n            List<Float> floatList = new ArrayList<Float>(value.length);\n            for (float f : value) {\n                floatList.add(f);\n            }\n            return new DataBundleValue.Builder().floatArray(floatList).build();\n        }\n\n        @Override\n        void store(DataMap dataMap, String key, float[] value) {\n            dataMap.putFloatArray(key, value);\n        }\n\n        @Override\n        float[] load(DataMap dataMap, String key) {\n            return dataMap.getFloatArray(key);\n        }\n    };\n\n    static {\n        typeHelperByCode = new SparseArray<TypeHelper>();\n        rememberTypeReader(BYTEARRAY);\n        rememberTypeReader(STRING);\n        rememberTypeReader(DOUBLE);\n        rememberTypeReader(FLOAT);\n        rememberTypeReader(LONG);\n        rememberTypeReader(INTEGER);\n        rememberTypeReader(BYTE);\n        rememberTypeReader(BOOLEAN);\n        rememberTypeReader(DATAMAP);\n        rememberTypeReader(ARRAYLIST);\n        rememberTypeReader(STRINGARRAY);\n        rememberTypeReader(LONGARRAY);\n        rememberTypeReader(ASSET);\n        rememberTypeReader(NULL);\n        rememberTypeReader(FLOATARRAY);\n    }\n\n    static class AssetAnnotatedDataBundle {\n        private DataBundle dataBundle;\n        private List<Asset> assets;\n\n        public List<Asset> getAssets() {\n            return assets;\n        }\n\n        public byte[] getData() {\n            return dataBundle.encode();\n        }\n    }\n\n    static class AnnotatedArrayList<T> extends ArrayList<T> {\n        private TypeHelper<T> innerType;\n\n        public AnnotatedArrayList(TypeHelper<T> innerType) {\n            this.innerType = innerType;\n        }\n\n        void store(DataMap dataMap, String key) {\n            innerType.storeList(dataMap, key, this);\n        }\n\n        public List<DataBundleTypedValue> createList(List<Asset> assets) {\n            return innerType.createList(this, assets);\n        }\n    }\n\n    static abstract class TypeHelper<T> {\n        private int type;\n\n        public TypeHelper(int type) {\n            this.type = type;\n        }\n\n        abstract T read(DataBundleValue value, List<Asset> assets);\n\n        abstract DataBundleValue create(T value, List<Asset> assets);\n\n        T read(DataBundleTypedValue value, List<Asset> assets) {\n            if (value.type == NULL_TYPE_CODE) {\n                return null;\n            } else if (value.type == type) {\n                return read(value.value, assets);\n            } else {\n                throw new IllegalArgumentException();\n            }\n        }\n\n        abstract void store(DataMap dataMap, String key, T value);\n\n        void storeList(DataMap dataMap, String key, ArrayList<T> valueList) {\n            throw new UnsupportedOperationException();\n        }\n\n        abstract T load(DataMap dataMap, String key);\n\n        AnnotatedArrayList<T> loadList(DataMap dataMap, String key) {\n            throw new UnsupportedOperationException();\n        }\n\n        void readAndStore(DataMap dataMap, String key, DataBundleValue value, List<Asset> assets) {\n            store(dataMap, key, read(value, assets));\n        }\n\n        void readAndStore(DataMap dataMap, String key, DataBundleTypedValue value, List<Asset> assets) {\n            store(dataMap, key, read(value, assets));\n        }\n\n        void readAndStore(DataMap dataMap, DataBundleEntry entry, List<Asset> assets) {\n            readAndStore(dataMap, entry.key, entry.typedValue, assets);\n        }\n\n        AnnotatedArrayList<T> readList(List<DataBundleTypedValue> values, List<Asset> assets) {\n            AnnotatedArrayList<T> list = new AnnotatedArrayList<T>(this);\n            for (DataBundleTypedValue value : values) {\n                list.add(read(value, assets));\n            }\n            return list;\n        }\n\n        List<DataBundleTypedValue> createList(AnnotatedArrayList<T> value, List<Asset> assets) {\n            List<DataBundleTypedValue> list = new ArrayList<DataBundleTypedValue>();\n            for (T val : value) {\n                list.add(createTyped(val, assets));\n            }\n            return list;\n        }\n\n        void readAndStore(DataMap dataMap, String key, List<DataBundleTypedValue> values, List<Asset> assets) {\n            storeList(dataMap, key, readList(values, assets));\n        }\n\n        DataBundleTypedValue createTyped(T value, List<Asset> assets) {\n            return new DataBundleTypedValue.Builder().type(type).value(create(value, assets)).build();\n        }\n\n        DataBundleValue loadAndCreate(DataMap dataMap, String key, List<Asset> assets) {\n            return create(load(dataMap, key), assets);\n        }\n\n        DataBundleTypedValue loadAndCreateTyped(DataMap dataMap, String key, List<Asset> assets) {\n            return createTyped(load(dataMap, key), assets);\n        }\n\n        DataBundleEntry loadAndCreateEntry(DataMap dataMap, String key, List<Asset> assets) {\n            return new DataBundleEntry.Builder().key(key).typedValue(loadAndCreateTyped(dataMap, key, assets)).build();\n        }\n    }\n}\n"
  },
  {
    "path": "play-services-wearable/src/main/proto/databundle.proto",
    "content": "option java_package = \"org.microg.gms.wearable.databundle\";\noption java_outer_classname = \"DataBundleProto\";\n\nmessage DataBundle {\n    repeated DataBundleEntry entries = 1;\n}\n\nmessage DataBundleEntry {\n    optional string key = 1;\n    optional DataBundleTypedValue typedValue = 2;\n}\n\nmessage DataBundleTypedValue {\n    optional int32 type = 1;\n    optional DataBundleValue value = 2;\n}\n\nmessage DataBundleValue {\n    optional bytes byteArray = 1;\n    optional string stringVal = 2;\n    optional double doubleVal = 3;\n    optional float floatVal = 4;\n    optional int64 longVal = 5;\n    optional int32 intVal = 6;\n    optional int32 byteVal = 7;\n    optional bool booleanVal = 8;\n    repeated DataBundleEntry map = 9;\n    repeated DataBundleTypedValue list = 10;\n    repeated string stringArray = 11;\n    repeated int64 longArray = 12;\n    optional int32 assetIndex = 13;\n    repeated float floatArray = 14;\n}\n"
  },
  {
    "path": "proguard.flags",
    "content": "# We're referencing stuff that is unknown to the system\n#-libraryjar ../unifiednlp-compat/build/classes/java/main\n-dontwarn java.awt.**\n-dontwarn javax.annotation.**\n\n# External libs\n-dontwarn okio.**\n-dontwarn com.squareup.okhttp.**\n-dontwarn org.oscim.tiling.source.OkHttpEngine\n-dontwarn org.oscim.tiling.source.OkHttpEngine$OkHttpFactory\n-dontwarn com.caverock.androidsvg.**\n-dontwarn org.slf4j.**\n-dontwarn org.codehaus.jackson.**\n-dontwarn com.android.location.provider.**\n\n# Disable ProGuard Notes, they won't help here\n-dontnote\n\n# Keep dynamically loaded GMS classes\n-keep public class com.google.android.gms.maps.internal.CreatorImpl { public *; }\n-keep public class com.google.android.gms.common.security.ProviderInstallerImpl { public *; }\n-keep public class com.google.android.gms.plus.plusone.PlusOneButtonCreatorImpl { public *; }\n-keep public class com.google.android.gms.dynamic.IObjectWrapper { public *; }\n-keep public class com.google.android.gms.chimera.container.DynamiteLoaderImpl { public *; }\n-keep public class com.google.android.gms.dynamite.descriptors.** { public *; }\n-keep public class com.google.android.gms.cast.framework.internal.CastDynamiteModuleImpl { public *; }\n\n# Keep AutoSafeParcelables\n-keep public class * extends org.microg.safeparcel.AutoSafeParcelable {\n    @org.microg.safeparcel.SafeParceled *;\n    @org.microg.safeparcel.SafeParcelable.Field *;\n    <init>(...);\n}\n\n# Keep form data\n-keepclassmembers class * {\n    @org.microg.gms.common.HttpFormClient$* *;\n}\n\n# Keep our stuff\n-keep class org.microg.** { *; }\n-keep class com.google.android.gms.** { *; }\n\n# Keep asInterface method cause it's accessed from SafeParcel\n-keepattributes InnerClasses\n-keepclassmembers interface * extends android.os.IInterface {\n    public static class *;\n}\n-keep public class * extends android.os.Binder { public static *; }\n\n# Keep library info\n-keep class **.BuildConfig { *; }\n\n# Keep protobuf class builders\n-keep public class com.squareup.wire.Message\n-keep public class * extends com.squareup.wire.Message\n-keep public class * extends com.squareup.wire.Message$Builder { public <init>(...); }\n\n# Proguard configuration for Jackson 1.x\n-keepclassmembers class * {\n     @org.codehaus.jackson.annotate.* *;\n}\n"
  },
  {
    "path": "safe-parcel-processor/build.gradle",
    "content": "apply plugin: 'kotlin'"
  },
  {
    "path": "safe-parcel-processor/src/main/AndroidManifest.xml",
    "content": "<!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<manifest package=\"org.microg.safeparcel.processor\"/>"
  },
  {
    "path": "safe-parcel-processor/src/main/kotlin/org/microg/safeparcel/SafeParcelProcessor.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage org.microg.safeparcel\n\nimport javax.annotation.processing.AbstractProcessor\nimport javax.annotation.processing.ProcessingEnvironment\nimport javax.annotation.processing.RoundEnvironment\nimport javax.annotation.processing.SupportedAnnotationTypes\nimport javax.annotation.processing.SupportedSourceVersion\nimport javax.lang.model.SourceVersion\nimport javax.lang.model.element.Element\nimport javax.lang.model.element.ElementKind\nimport javax.lang.model.element.ExecutableElement\nimport javax.lang.model.element.Modifier\nimport javax.lang.model.element.TypeElement\nimport javax.lang.model.element.VariableElement\nimport javax.tools.Diagnostic\n\nconst val SafeParcelable = \"com.google.android.gms.common.internal.safeparcel.SafeParcelable\"\nconst val SafeParcelReader = \"com.google.android.gms.common.internal.safeparcel.SafeParcelReader\"\nconst val SafeParcelWriter = \"com.google.android.gms.common.internal.safeparcel.SafeParcelWriter\"\nconst val SafeParcelableCreatorAndWriter = \"com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter\"\n\nconst val Field = \"java.lang.reflect.Field\"\nconst val Constructor = \"java.lang.reflect.Constructor\"\n\nconst val Log = \"android.util.Log\"\nconst val Parcel = \"android.os.Parcel\"\nconst val Parcelable = \"android.os.Parcelable\"\nconst val IInterface = \"android.os.IInterface\"\n\nval NATIVE_SUPPORTED_TYPES = setOf(\n    \"int\", \"byte\", \"short\", \"boolean\", \"long\", \"float\", \"double\",\n    \"java.lang.Boolean\", \"java.lang.Byte\", \"java.lang.Char\", \"java.lang.Short\", \"java.lang.Integer\", \"java.lang.Long\", \"java.lang.Float\", \"java.lang.Double\",\n    \"java.lang.String\", \"android.os.Bundle\", \"android.os.IBinder\",\n    \"int[]\", \"byte[]\", \"byte[][]\", \"float[]\", \"java.lang.String[]\",\n    \"java.util.List<java.lang.String>\", \"java.util.ArrayList<java.lang.String>\",\n\n    \"java.util.List<java.lang.Integer>\", \"java.util.List<java.lang.Boolean>\",\n    \"java.util.List<java.lang.Long>\", \"java.util.List<java.lang.Float>\", \"java.util.List<java.lang.Double>\",\n    \"java.util.ArrayList<java.lang.Integer>\", \"java.util.ArrayList<java.lang.Boolean>\",\n    \"java.util.ArrayList<java.lang.Long>\", \"java.util.ArrayList<java.lang.Float>\", \"java.util.ArrayList<java.lang.Float>\",\n)\n\n@SupportedSourceVersion(SourceVersion.RELEASE_8)\n@SupportedAnnotationTypes(\"$SafeParcelable.Class\")\nclass SafeParcelProcessor : AbstractProcessor() {\n    override fun process(set: Set<TypeElement>, roundEnvironment: RoundEnvironment): Boolean {\n        val safeParcelableClassTypeElement = set.firstOrNull() ?: return false\n\n        classes@ for (classElement in roundEnvironment.getElementsAnnotatedWith(safeParcelableClassTypeElement)) {\n            val clazz = ClassInfo(classElement)\n            if (clazz.check(processingEnv)) {\n                processingEnv.filer.createSourceFile(clazz.fullCreatorName, clazz.classElement).openWriter().use { it.write(clazz.generateCreator()) }\n            }\n        }\n        return false\n    }\n}\n\nclass ClassInfo(val classElement: Element) {\n    val name = classElement.simpleName.toString()\n    val fullName = classElement.toString()\n    val packageName = let {\n        var upmostClassElement = classElement\n        while (upmostClassElement.enclosingElement != null) upmostClassElement = upmostClassElement.enclosingElement\n        upmostClassElement.toString()\n    }\n\n    val creatorName = \"$name\\$000Creator\"\n    val fullCreatorName = \"$packageName.$creatorName\"\n\n    val fields = classElement.enclosedElements\n        .filter { it.kind == ElementKind.FIELD && !it.modifiers.contains(Modifier.STATIC) }\n        .filterIsInstance<VariableElement>()\n        .filter { it.annotationMirrors.any { it.annotationType.toString() == \"$SafeParcelable.Field\" } }\n        .map { FieldInfo(this, it) }\n    val constructor = classElement.enclosedElements\n        .filter { it.kind == ElementKind.CONSTRUCTOR }\n        .filterIsInstance<ExecutableElement>()\n        .filter { it.annotationMirrors.any { it.annotationType.toString() == \"$SafeParcelable.Constructor\" } || it.parameters.isEmpty() }\n        .let { if (it.size == 2) it.first { it.parameters.isNotEmpty() } else it.firstOrNull() }\n        ?.let { ConstructorInfo(this, it) }\n\n    fun check(processingEnv: ProcessingEnvironment): Boolean {\n        fun note(message: String) = processingEnv.messager.printMessage(Diagnostic.Kind.NOTE, message)\n        fun error(message: String) = processingEnv.messager.printMessage(Diagnostic.Kind.ERROR, message)\n        if (constructor == null) {\n            error(\"No suitable constructor found for $fullName\")\n            return false\n        }\n        if (constructor.parameters.any { it.annotationMirrors.none { it.annotationType.toString() == \"$SafeParcelable.Param\" } }) {\n            error(\"Tagged constructor for $fullName has parameters without @Param.\")\n            return false\n        }\n        if (constructor.fieldIds.any { id -> fields.none { it.id == id } }) {\n            error(\"Constructor for $fullName has parameters with @Param value without matching @Field.\")\n            return false\n        }\n        if (constructor.isPrivate) {\n            note(\"Using reflection to construct $fullName from parcel. Consider providing a suitable package-visible constructor for improved performance.\")\n        }\n        for (field in fields) {\n            if (field.type !in NATIVE_SUPPORTED_TYPES) {\n                val typeName = field.listItemType ?: field.type\n                val type = runCatching { processingEnv.typeUtils.getDeclaredType(processingEnv.elementUtils.getTypeElement(typeName)) }.getOrNull()\n                val parcelable = processingEnv.typeUtils.getDeclaredType(processingEnv.elementUtils.getTypeElement(Parcelable))\n                val iinterface = processingEnv.typeUtils.getDeclaredType(processingEnv.elementUtils.getTypeElement(IInterface))\n                if (type != null && processingEnv.typeUtils.isAssignable(type, parcelable)) {\n                    field.isParcelable = true\n                } else if (type != null && processingEnv.typeUtils.isAssignable(type, iinterface)) {\n                    field.isIInterface = true\n                } else {\n                    error(\"Field ${field.name} in $fullName has unsupported type ${if (typeName != field.type) \"$typeName in ${field.type}\" else field.type}.\")\n                    return false\n                }\n            }\n            val readReflect = field.isPrivate && field.getter == null\n            val writeReflect = field.isPrivate && !constructor.fieldIds.contains(field.id)\n            when {\n                readReflect && writeReflect -> note(\"Using reflection when accessing ${field.name} in $fullName. Consider adding it to the @Constructor and a getter to the annotation for improved performance.\")\n                writeReflect -> note(\"Using reflection when writing ${field.name} in $fullName. Consider adding it to the @Constructor for improved performance.\")\n                readReflect -> note(\"Using reflection when reading ${field.name} in $fullName. Consider adding a getter to the annotation for improved performance.\")\n            }\n        }\n        return true\n    }\n\n    fun generateCreator(): String {\n        if (constructor == null) throw IllegalStateException(\"Can't create Creator for class without constructor\")\n        fun List<String>.linesToString(prefix: String = \"\") = joinToString(\"\\n                            $prefix\")\n        val variableDeclarations = fields.map { it.variableDeclaration }.linesToString()\n        val setVariablesDefault = fields.map { it.setVariableDefault }.linesToString()\n        val readVariablesFromParcel = fields.map { it.readVariableFromParcelCase }.linesToString(\"        \")\n        val writeVariableToParcel = fields.map { it.writeVariableToParcel }.linesToString()\n        val setFieldsFromVariables = fields.filter { it.id !in constructor.fieldIds }.flatMap { it.setFieldFromVariable }.linesToString()\n        val invokeConstructor = constructor.invocation.linesToString()\n        val setVariablesFromFields = fields.flatMap { it.setVariableFromField }.linesToString()\n        val file = \"\"\"\n                package $packageName;\n\n                //@javax.annotation.processing.Generated // Not supported by Android\n                @androidx.annotation.Keep\n                @org.microg.gms.common.Hide\n                public class $creatorName implements $SafeParcelableCreatorAndWriter<$fullName> {\n                    @Override\n                    public $fullName createFromParcel($Parcel parcel) {\n                        int end = $SafeParcelReader.readObjectHeader(parcel);\n                        $fullName object;\n                        try {\n                            $variableDeclarations\n                            $setVariablesDefault\n                            while (parcel.dataPosition() < end) {\n                                int header = $SafeParcelReader.readHeader(parcel);\n                                int fieldId = $SafeParcelReader.getFieldId(header);\n                                switch (fieldId) {\n                                    $readVariablesFromParcel\n                                    default:\n                                        $Log.d(\"SafeParcel\", String.format(\"Unknown field id %d in %s, skipping.\", fieldId, \"$fullName\"));\n                                        $SafeParcelReader.skip(parcel, header);\n                                }\n                            }\n                            $invokeConstructor\n                            $setFieldsFromVariables\n                        } catch (Exception e) {\n                            throw new RuntimeException(String.format(\"Error reading %s\", \"$fullName\"), e);\n                        }\n                        if (parcel.dataPosition() > end) {\n                            throw new RuntimeException(String.format(\"Overread allowed size end=%d\", end));\n                        }\n                        return object;\n                    }\n\n                    @Override\n                    public void writeToParcel($fullName object, $Parcel parcel, int flags) {\n                        int start = $SafeParcelWriter.writeObjectHeader(parcel);\n                        try {\n                            $variableDeclarations\n                            $setVariablesFromFields\n                            $writeVariableToParcel\n                        } catch (Exception e) {\n                            throw new RuntimeException(String.format(\"Error writing %s\", \"$fullName\"), e);\n                        }\n                        $SafeParcelWriter.finishObjectHeader(parcel, start);\n                    }\n\n                    @Override\n                    public $fullName[] newArray(int size) {\n                        return new $fullName[size];\n                    }\n                }\n            \"\"\".trimIndent()\n        return file\n    }\n}\n\nclass ConstructorInfo(val clazz: ClassInfo, val constructorElement: ExecutableElement) {\n    val isPrivate by lazy { constructorElement.modifiers.contains(Modifier.PRIVATE) }\n    val parameters by lazy { constructorElement.parameters }\n    val fieldIds by lazy {\n        parameters.map {\n            it.annotationMirrors\n                .first { it.annotationType.toString() == \"$SafeParcelable.Param\" }\n                .elementValues\n                .filter { it.key.simpleName.toString() == \"value\" }\n                .firstNotNullOfOrNull { it.value }\n                .toString()\n        }\n    }\n    val argTypes by lazy { fieldIds.map { id -> clazz.fields.first { it.id == id }.type } }\n    val args by lazy { fieldIds.map { id -> clazz.fields.first { it.id == id }.variableName } }\n    val invocation by lazy {\n        if (isPrivate) {\n            listOf(\n                \"$Constructor<${clazz.fullName}> constructor = ${clazz.fullName}.class.getConstructor(${argTypes.map { \"$it.class\" }.joinToString(\", \")});\",\n                \"constructor.setAccessible(true);\",\n                \"object = constructor.newInstance(${args.joinToString(\", \")});\"\n            )\n        } else {\n            listOf(\"object = new ${clazz.fullName}(${args.joinToString(\", \")});\")\n        }\n    }\n}\n\nclass FieldInfo(val clazz: ClassInfo, val fieldElement: VariableElement) {\n    val name by lazy { fieldElement.simpleName.toString() }\n    val type by lazy {\n        fieldElement.annotationMirrors\n            .first { it.annotationType.toString() == \"$SafeParcelable.Field\" }\n            .elementValues\n            .filter { it.key.simpleName.toString() == \"type\" }\n            .firstNotNullOfOrNull { it.value.value }\n            ?.toString()?.takeIf { it.isNotEmpty() }\n            ?: fieldElement.asType().toString()\n    }\n    var isParcelable: Boolean = false\n    var isIInterface: Boolean = false\n    val isPrivate by lazy { fieldElement.modifiers.contains(Modifier.PRIVATE) }\n\n    val id by lazy {\n        fieldElement.annotationMirrors\n            .first { it.annotationType.toString() == \"$SafeParcelable.Field\" }\n            .elementValues\n            .filter { it.key.simpleName.toString() == \"value\" }\n            .firstNotNullOfOrNull { it.value.value }\n            .toString()\n    }\n    val mayNull by lazy {\n        fieldElement.annotationMirrors\n            .first { it.annotationType.toString() == \"$SafeParcelable.Field\" }\n            .elementValues\n            .filter { it.key.simpleName.toString() == \"mayNull\" }\n            .firstNotNullOfOrNull { it.value.value }\n            ?.toString()\n            ?.toBoolean() == true\n    }\n    val useValueParcel by lazy {\n        fieldElement.annotationMirrors\n            .first { it.annotationType.toString() == \"$SafeParcelable.Field\" }\n            .elementValues\n            .filter { it.key.simpleName.toString() == \"useValueParcel\" }\n            .firstNotNullOfOrNull { it.value.value }\n            ?.toString()\n            ?.toBoolean() == true\n    }\n    val getter by lazy {\n        fieldElement.annotationMirrors\n            .first { it.annotationType.toString() == \"$SafeParcelable.Field\" }\n            .elementValues\n            .filter { it.key.simpleName.toString() == \"getter\" }\n            .firstNotNullOfOrNull { it.value.value }\n            ?.toString()?.takeIf { it.isNotEmpty() }\n            ?.replace(\"\\$object\", \"object\")\n            ?.replace(\"\\$type\", type)\n            ?: fieldElement.annotationMirrors\n                .first { it.annotationType.toString() == \"$SafeParcelable.Field\" }\n                .elementValues\n                .filter { it.key.simpleName.toString() == \"getterName\" }\n                .firstNotNullOfOrNull { it.value.value }\n                ?.toString()?.takeIf { it.isNotEmpty() }\n                ?.let { \"object.$it()\" }\n    }\n    val subType by lazy {\n        fieldElement.annotationMirrors\n            .first { it.annotationType.toString() == \"$SafeParcelable.Field\" }\n            .elementValues\n            .filter { it.key.simpleName.toString() == \"subClass\" }\n            .firstNotNullOfOrNull { it.value.value }\n            ?.toString()?.takeIf { it.isNotEmpty() }\n    }\n    val isList by lazy { type.startsWith(\"java.util.List<\") || type.startsWith(\"java.util.ArrayList<\") }\n    val isArray by lazy { type.endsWith(\"[]\") }\n    val listItemType by lazy {\n        subType ?: when {\n            type.startsWith(\"java.util.List<\") -> type.substring(15, type.length - 1)\n            type.startsWith(\"java.util.ArrayList<\") -> type.substring(20, type.length - 1)\n            type.endsWith(\"[]\") -> type.substring(0, type.length - 2)\n            else -> null\n        }\n    }\n\n    val variableName by lazy { \"_$name\\$000\" }\n    val variableDeclaration by lazy { \"$type $variableName;\" }\n    val defaultValue by lazy {\n        fieldElement.annotationMirrors\n            .first { it.annotationType.toString() == \"$SafeParcelable.Field\" }\n            .elementValues\n            .filter { it.key.simpleName.toString() == \"defaultValue\" }\n            .firstNotNullOfOrNull { it.value.value }\n            ?.toString()?.takeIf { it.isNotEmpty() }\n            ?: when (type) {\n                \"boolean\" -> \"false\"\n                \"byte\", \"char\", \"short\", \"int\", \"long\", \"float\", \"double\" -> \"0\"\n                else -> \"null\"\n            }\n    }\n    val setVariableDefault by lazy { \"$variableName = $defaultValue;\" }\n\n    val readVariableFromParcel by lazy {\n        when (type) {\n            \"int\", \"java.lang.Integer\" -> \"$variableName = $SafeParcelReader.readInt(parcel, header)\"\n            \"byte\", \"java.lang.Byte\" -> \"$variableName = $SafeParcelReader.readByte(parcel, header)\"\n            \"short\", \"java.lang.Short\" -> \"$variableName = $SafeParcelReader.readShort(parcel, header)\"\n            \"boolean\", \"java.lang.Boolean\" -> \"$variableName = $SafeParcelReader.readBool(parcel, header)\"\n            \"long\", \"java.lang.Long\" -> \"$variableName = $SafeParcelReader.readLong(parcel, header)\"\n            \"float\", \"java.lang.Float\" -> \"$variableName = $SafeParcelReader.readFloat(parcel, header)\"\n            \"double\", \"java.lang.Double\" -> \"$variableName = $SafeParcelReader.readDouble(parcel, header)\"\n            \"java.lang.String\" -> \"$variableName = $SafeParcelReader.readString(parcel, header)\"\n            \"android.os.Bundle\" -> \"$variableName = $SafeParcelReader.readBundle(parcel, header, ${clazz.fullName}.class.getClassLoader())\"\n            \"android.os.IBinder\" -> \"$variableName = $SafeParcelReader.readBinder(parcel, header)\"\n            \"java.lang.String[]\" -> \"$variableName = $SafeParcelReader.readStringArray(parcel, header)\"\n            \"byte[]\" -> \"$variableName = $SafeParcelReader.readByteArray(parcel, header)\"\n            \"byte[][]\" -> \"$variableName = $SafeParcelReader.readByteArrayArray(parcel, header)\"\n            \"float[]\" -> \"$variableName = $SafeParcelReader.readFloatArray(parcel, header)\"\n            \"int[]\" -> \"$variableName = $SafeParcelReader.readIntArray(parcel, header)\"\n            \"java.util.List<java.lang.String>\", \"java.util.ArrayList<java.lang.String>\" -> when {\n                !useValueParcel -> \"$variableName = $SafeParcelReader.readStringList(parcel, header)\"\n                else -> \"$variableName = $SafeParcelReader.readList(parcel, header, java.lang.String.class.getClassLoader())\"\n            }\n            \"java.util.List<java.lang.Integer>\", \"java.util.ArrayList<java.lang.Integer>\" -> when {\n                !useValueParcel -> \"$variableName = $SafeParcelReader.readIntegerList(parcel, header)\"\n                else -> \"$variableName = $SafeParcelReader.readList(parcel, header, java.lang.Integer.class.getClassLoader())\"\n            }\n            \"java.util.List<java.lang.Boolean>\", \"java.util.ArrayList<java.lang.Boolean>\" -> when {\n                !useValueParcel -> \"$variableName = $SafeParcelReader.readBooleanList(parcel, header)\"\n                else -> \"$variableName = $SafeParcelReader.readList(parcel, header, java.lang.Boolean.class.getClassLoader())\"\n            }\n            \"java.util.List<java.lang.Long>\", \"java.util.ArrayList<java.lang.Long>\" -> when {\n                !useValueParcel -> \"$variableName = $SafeParcelReader.readLongList(parcel, header)\"\n                else -> \"$variableName = $SafeParcelReader.readList(parcel, header, java.lang.Long.class.getClassLoader())\"\n            }\n            \"java.util.List<java.lang.Float>\", \"java.util.ArrayList<java.lang.Float>\" -> when {\n                !useValueParcel -> \"$variableName = $SafeParcelReader.readFloatList(parcel, header)\"\n                else -> \"$variableName = $SafeParcelReader.readList(parcel, header, java.lang.Float.class.getClassLoader())\"\n            }\n            \"java.util.List<java.lang.Double>\", \"java.util.ArrayList<java.lang.Double>\" -> when {\n                !useValueParcel -> \"$variableName = $SafeParcelReader.readDoubleList(parcel, header)\"\n                else -> \"$variableName = $SafeParcelReader.readList(parcel, header, java.lang.Double.class.getClassLoader())\"\n            }\n            else -> when {\n                isList && isParcelable && !useValueParcel -> \"$variableName = $SafeParcelReader.readParcelableList(parcel, header, $listItemType.CREATOR)\"\n                isArray && isParcelable -> \"$variableName = $SafeParcelReader.readParcelableArray(parcel, header, $listItemType.CREATOR)\"\n                isList -> \"$variableName = $SafeParcelReader.readList(parcel, header, $listItemType.class.getClassLoader())\"\n                isParcelable -> \"$variableName = $SafeParcelReader.readParcelable(parcel, header, $type.CREATOR)\"\n                !isList && isIInterface -> \"$variableName = $type.Stub.asInterface($SafeParcelReader.readBinder(parcel, header))\"\n                else -> throw UnsupportedOperationException(\"Field $name in ${clazz.fullName} has unsupported type $type.\")\n            }\n        }\n    }\n    val readVariableFromParcelCase by lazy { \"case $id: $readVariableFromParcel; break;\" }\n    val writeVariableToParcel by lazy {\n        when (type) {\n            \"boolean\", \"byte\", \"char\", \"short\", \"int\", \"long\", \"float\", \"double\",\n            \"java.lang.Boolean\", \"java.lang.Byte\", \"java.lang.Char\", \"java.lang.Short\", \"java.lang.Integer\", \"java.lang.Long\", \"java.lang.Float\", \"java.lang.Double\" ->\n                \"$SafeParcelWriter.write(parcel, $id, $variableName);\"\n\n            \"java.util.List<java.lang.String>\", \"java.util.ArrayList<java.lang.String>\" -> when {\n                !useValueParcel -> \"$SafeParcelWriter.writeStringList(parcel, $id, $variableName, $mayNull);\"\n                else -> \"$SafeParcelWriter.write(parcel, $id, $variableName, $mayNull);\"\n            }\n\n            \"java.util.List<java.lang.Integer>\", \"java.util.ArrayList<java.lang.Integer>\" -> when {\n                !useValueParcel -> \"$SafeParcelWriter.writeIntegerList(parcel, $id, $variableName, $mayNull);\"\n                else -> \"$SafeParcelWriter.write(parcel, $id, $variableName, $mayNull);\"\n            }\n\n            \"java.util.List<java.lang.Boolean>\", \"java.util.ArrayList<java.lang.Boolean>\" -> when {\n                !useValueParcel -> \"$SafeParcelWriter.writeBooleanList(parcel, $id, $variableName, $mayNull);\"\n                else -> \"$SafeParcelWriter.write(parcel, $id, $variableName, $mayNull);\"\n            }\n\n            \"java.util.List<java.lang.Long>\", \"java.util.ArrayList<java.lang.Long>\" -> when {\n                !useValueParcel -> \"$SafeParcelWriter.writeLongList(parcel, $id, $variableName, $mayNull);\"\n                else -> \"$SafeParcelWriter.write(parcel, $id, $variableName, $mayNull);\"\n            }\n\n            \"java.util.List<java.lang.Float>\", \"java.util.ArrayList<java.lang.Float>\" -> when {\n                !useValueParcel -> \"$SafeParcelWriter.writeFloatList(parcel, $id, $variableName, $mayNull);\"\n                else -> \"$SafeParcelWriter.write(parcel, $id, $variableName, $mayNull);\"\n            }\n\n            \"java.util.List<java.lang.Double>\", \"java.util.ArrayList<java.lang.Double>\" -> when {\n                !useValueParcel -> \"$SafeParcelWriter.writeDoubleList(parcel, $id, $variableName, $mayNull);\"\n                else -> \"$SafeParcelWriter.write(parcel, $id, $variableName, $mayNull);\"\n            }\n\n            else -> when {\n                isParcelable -> \"$SafeParcelWriter.write(parcel, $id, $variableName, flags, $mayNull);\"\n                isIInterface -> \"$SafeParcelWriter.write(parcel, $id, $variableName.asBinder(), $mayNull);\"\n                else -> \"$SafeParcelWriter.write(parcel, $id, $variableName, $mayNull);\"\n            }\n        }\n    }\n\n    val reflectionFieldName by lazy { \"_${name}\\$field\" }\n    val reflectionFieldGetter by lazy {\n        when (type) {\n            \"boolean\" -> \"$reflectionFieldName.getBoolean\"\n            \"byte\" -> \"$reflectionFieldName.getByte\"\n            \"char\" -> \"$reflectionFieldName.getChar\"\n            \"short\" -> \"$reflectionFieldName.getShort\"\n            \"int\" -> \"$reflectionFieldName.getInt\"\n            \"long\" -> \"$reflectionFieldName.getLong\"\n            \"float\" -> \"$reflectionFieldName.getFloat\"\n            \"double\" -> \"$reflectionFieldName.getDouble\"\n            else -> \"(${type}) $reflectionFieldName.get\"\n        }\n    }\n    val reflectionFieldSetter by lazy {\n        when (type) {\n            \"boolean\" -> \"$reflectionFieldName.setBoolean\"\n            \"byte\" -> \"$reflectionFieldName.setByte\"\n            \"char\" -> \"$reflectionFieldName.setChar\"\n            \"short\" -> \"$reflectionFieldName.setShort\"\n            \"int\" -> \"$reflectionFieldName.setInt\"\n            \"long\" -> \"$reflectionFieldName.setLong\"\n            \"float\" -> \"$reflectionFieldName.setFloat\"\n            \"double\" -> \"$reflectionFieldName.setDouble\"\n            else -> \"$reflectionFieldName.set\"\n        }\n    }\n\n    val setVariableFromField by lazy {\n        when {\n            getter != null -> listOf(\"$variableName = $getter;\")\n            isPrivate -> listOf(\n                \"$Field $reflectionFieldName = ${clazz.fullName}.class.getDeclaredField(\\\"$name\\\");\",\n                \"$reflectionFieldName.setAccessible(true);\",\n                \"$variableName = $reflectionFieldGetter(object);\"\n            )\n\n            else -> listOf(\"$variableName = object.$name;\")\n        }\n    }\n    val setFieldFromVariable by lazy {\n        if (isPrivate) {\n            listOf(\n                \"$Field $reflectionFieldName = ${clazz.fullName}.class.getDeclaredField(\\\"$name\\\");\",\n                \"$reflectionFieldName.setAccessible(true);\",\n                \"$reflectionFieldSetter(object, $variableName);\"\n            )\n        } else {\n            listOf(\"object.$name = $variableName;\")\n        }\n    }\n}"
  },
  {
    "path": "safe-parcel-processor/src/main/resources/META-INF/gradle/incremental.annotation.processors",
    "content": "#\n# SPDX-FileCopyrightText: 2024 microG Project Team\n# SPDX-License-Identifier: Apache-2.0\n#\n\norg.microg.safeparcel.SafeParcelProcessor, isolating"
  },
  {
    "path": "safe-parcel-processor/src/main/resources/META-INF/services/javax.annotation.processing.Processor",
    "content": "#\n# SPDX-FileCopyrightText: 2023 microG Project Team\n# SPDX-License-Identifier: Apache-2.0\n#\n\norg.microg.safeparcel.SafeParcelProcessor"
  },
  {
    "path": "settings.gradle",
    "content": "def sublude(name) {\n  def projectName = ':' + name.substring(1).replace(':', '-')\n  include projectName\n  project(projectName).projectDir = file(name.substring(1).replace(':', '/'))\n}\n\ndef localProperties = new Properties()\ntry {\n  var stream = new File(rootDir, 'local.properties').newDataInputStream()\n  localProperties.load(stream)\n  stream.close()\n} catch (ignored) {\n  // Ignore\n}\ndef hasModule = (String name, boolean enabledByDefault) -> {\n  return localProperties.getProperty(\"modules.\" + name, enabledByDefault.toString()).toBoolean()\n}\n\ninclude ':fake-signature'\ninclude ':safe-parcel-processor'\ninclude ':vending-app'\n\ninclude ':play-services-ads'\ninclude ':play-services-ads-base'\ninclude ':play-services-ads-identifier'\ninclude ':play-services-ads-lite'\ninclude ':play-services-appinvite'\ninclude ':play-services-appset'\ninclude ':play-services-auth'\ninclude ':play-services-auth-api-phone'\ninclude ':play-services-auth-base'\ninclude ':play-services-auth-blockstore'\ninclude ':play-services-auth-workaccount'\ninclude ':play-services-base'\ninclude ':play-services-basement'\ninclude ':play-services-cast'\ninclude ':play-services-cast-framework'\ninclude ':play-services-clearcut'\ninclude ':play-services-drive'\ninclude ':play-services-droidguard'\ninclude ':play-services-fido'\ninclude ':play-services-games'\ninclude ':play-services-gcm'\ninclude ':play-services-gmscompliance'\ninclude ':play-services-iid'\ninclude ':play-services-location'\ninclude ':play-services-maps'\ninclude ':play-services-measurement-base'\nsublude ':play-services-mlkit:barcode-scanning'\nsublude ':play-services-mlkit:face-detection'\ninclude ':play-services-nearby'\ninclude ':play-services-oss-licenses'\ninclude ':play-services-panorama'\ninclude ':play-services-pay'\ninclude ':play-services-phenotype'\ninclude ':play-services-places'\ninclude ':play-services-places-placereport'\ninclude ':play-services-recaptcha'\ninclude ':play-services-safetynet'\ninclude ':play-services-tapandpay'\ninclude ':play-services-threadnetwork'\ninclude ':play-services-tasks'\ninclude ':play-services-vision'\ninclude ':play-services-vision-common'\ninclude ':play-services-wearable'\ninclude ':play-services-fitness'\n\ninclude ':play-services-api'\ninclude ':play-services'\n\ninclude ':firebase-auth'\ninclude ':firebase-dynamic-links'\n\n// core only\n\ninclude ':play-services-core-proto'\n\nsublude ':play-services-basement:ktx'\nsublude ':play-services-tasks:ktx'\n\nsublude ':play-services-ads:core'\nsublude ':play-services-ads-identifier:core'\nsublude ':play-services-ads-lite:core'\nsublude ':play-services-appinvite:core'\nsublude ':play-services-appset:core'\nsublude ':play-services-auth-api-phone:core'\nsublude ':play-services-auth-blockstore:core'\nsublude ':play-services-auth-workaccount:core'\nsublude ':play-services-base:core'\nsublude ':play-services-base:core:package'\nsublude ':play-services-cast:core'\nsublude ':play-services-cast-framework:core'\ninclude ':play-services-chimera-core'\ninclude ':play-services-conscrypt-provider-core'\nsublude ':play-services-cronet:core'\nsublude ':play-services-droidguard:core'\nsublude ':play-services-fido:core'\nsublude ':play-services-fitness:core'\nsublude ':play-services-gmscompliance:core'\nsublude ':play-services-location:core'\nsublude ':play-services-location:core:base'\nsublude ':play-services-location:core:provider'\nsublude ':play-services-location:core:system-api'\nif (hasModule(\"hms\", false)) sublude ':play-services-maps:core:hms'\nsublude ':play-services-maps:core:mapbox'\nsublude ':play-services-maps:core:vtm'\nsublude ':play-services-maps:core:vtm:microg-theme'\nif (hasModule(\"nearby\", true)) sublude ':play-services-nearby:core'\nif (hasModule(\"nearby\", true)) sublude ':play-services-nearby:core:package'\nsublude ':play-services-oss-licenses:core'\nsublude ':play-services-panorama:core'\nsublude ':play-services-pay:core'\nsublude ':play-services-safetynet:core'\nsublude ':play-services-recaptcha:core'\nsublude ':play-services-tapandpay:core'\nsublude ':play-services-threadnetwork:core'\nsublude ':play-services-vision:core'\nsublude ':play-services-wearable:core'\n\nsublude ':firebase-auth:core'\n\ninclude ':play-services-core:microg-ui-tools' // Legacy\ninclude ':play-services-core'\n"
  },
  {
    "path": "vending-app/build.gradle",
    "content": "/*\n * SPDX-FileCopyrightText: 2015 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\napply plugin: 'com.android.application'\napply plugin: 'kotlin-android'\napply plugin: 'com.squareup.wire'\n\nandroid {\n    namespace \"com.android.vending\"\n    compileSdkVersion androidCompileSdk\n    buildToolsVersion \"$androidBuildVersionTools\"\n\n    defaultConfig {\n        versionName vendingAppVersionName\n        versionCode vendingAppVersionCode\n        minSdkVersion androidMinSdk\n        targetSdkVersion androidTargetSdk\n\n        multiDexEnabled true\n    }\n\n    buildTypes {\n        debug {\n            postprocessing {\n                removeUnusedCode true\n                removeUnusedResources false\n                obfuscate false\n                optimizeCode false\n                proguardFile 'proguard-rules.pro'\n            }\n        }\n        release {\n            postprocessing {\n                removeUnusedCode true\n                removeUnusedResources true\n                obfuscate false\n                optimizeCode true\n                proguardFile 'proguard-rules.pro'\n            }\n        }\n    }\n\n    flavorDimensions = ['target']\n    productFlavors {\n        \"default\" {\n            dimension 'target'\n        }\n        \"huawei\" {\n            dimension 'target'\n            versionNameSuffix \"-hw\"\n        }\n        \"huaweilh\" {\n            dimension 'target'\n            versionNameSuffix \"-lh\"\n            versionCode vendingAppVersionCode - 1000\n            matchingFallbacks = ['huawei']\n        }\n    }\n\n    sourceSets {\n        main {\n            java {\n                srcDirs += \"build/generated/source/proto/main/java\"\n            }\n        }\n    }\n\n\n    buildFeatures {\n        aidl = true\n        buildConfig = true\n        compose true\n    }\n\n    lintOptions {\n        disable 'MissingTranslation', 'GetLocales'\n    }\n\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n\n    kotlinOptions {\n        jvmTarget = 1.8\n    }\n    composeOptions {\n        kotlinCompilerExtensionVersion '1.5.10'\n    }\n}\n\ndependencies {\n    implementation project(':fake-signature')\n    implementation project(':play-services-auth')\n    implementation project(':play-services-base-core')\n    implementation project(':play-services-core-proto')\n\n    implementation \"com.squareup.wire:wire-runtime:$wireVersion\"\n    implementation \"com.squareup.wire:wire-grpc-client:$wireVersion\"\n\n    implementation \"com.squareup.okhttp3:okhttp:$okHttpVersion\"\n    implementation \"io.ktor:ktor-client-core:$ktorVersion\"\n    implementation \"io.ktor:ktor-client-okhttp:$ktorVersion\"\n\n    implementation \"androidx.webkit:webkit:$webkitVersion\"\n\n\n    //compose\n    implementation platform('androidx.compose:compose-bom:2022.10.00')\n    implementation 'androidx.compose.ui:ui'\n    implementation 'androidx.compose.material3:material3'\n    implementation 'androidx.compose.animation:animation-graphics'\n    implementation 'androidx.activity:activity-compose:1.7.2'\n    implementation(\"io.coil-kt:coil-compose:2.4.0\")\n    implementation(\"io.coil-kt:coil-svg:2.2.2\")\n    implementation \"com.google.android.material:material:$materialVersion\"\n    implementation \"com.google.accompanist:accompanist-systemuicontroller:0.28.0\"\n\n    implementation 'androidx.compose.ui:ui-tooling-preview'\n    debugImplementation 'androidx.compose.ui:ui-tooling'\n\n    // Coil (image loading)\n    implementation(\"io.coil-kt:coil-compose:2.7.0\")\n\n    //droidguard\n    implementation project(':play-services-droidguard')\n    implementation project(':play-services-tasks-ktx')\n\n    implementation \"org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutineVersion\"\n    implementation \"org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutineVersion\"\n\n    //androidx\n    implementation \"androidx.lifecycle:lifecycle-runtime-ktx:$lifecycleVersion\"\n    implementation \"androidx.core:core-ktx:$coreVersion\"\n    implementation \"androidx.appcompat:appcompat:$appcompatVersion\"\n    implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.6.2'\n    implementation \"androidx.preference:preference-ktx:$preferenceVersion\"\n\n    // tink\n    implementation \"com.google.crypto.tink:tink-android:$tinkVersion\"\n\n    // multidex\n    implementation \"androidx.multidex:multidex:$multidexVersion\"\n}\n\nwire {\n    kotlin {\n        javaInterop = true\n    }\n}\n\nif (file('user.gradle').exists()) {\n    apply from: 'user.gradle'\n}\n\nandroid.applicationVariants.all { variant ->\n    variant.outputs.each { output ->\n        output.outputFileName = variant.applicationId + \"-\" + variant.versionCode + variant.versionName.substring(vendingAppVersionName.length()) + \".apk\"\n    }\n}\n"
  },
  {
    "path": "vending-app/proguard-rules.pro",
    "content": "# SPDX-FileCopyrightText: 2025 e foundation\n# SPDX-License-Identifier: Apache-2.0\n\n# OKHttp rules\n-dontwarn okhttp3.internal.platform.**\n-dontwarn org.conscrypt.**\n-dontwarn org.bouncycastle.**\n-dontwarn org.openjsse.**\n-dontwarn org.slf4j.impl.StaticLoggerBinder"
  },
  {
    "path": "vending-app/src/huawei/AndroidManifest.xml",
    "content": "<!--\n  ~ SPDX-FileCopyrightText: 2024 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <application tools:overrideLibrary=\"coil.svg\">\n        <activity\n            android:name=\"org.microg.vending.ui.MainActivity\"\n            android:exported=\"true\"\n            android:theme=\"@style/Theme.Dialog.NoActionBar\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.INFO\" />\n            </intent-filter>\n        </activity>\n    </application>\n</manifest>"
  },
  {
    "path": "vending-app/src/huaweilh/AndroidManifest.xml",
    "content": "<!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <application tools:overrideLibrary=\"coil.svg\">\n        <activity-alias\n            android:name=\"org.lighthouseex.MainActivity\"\n            android:exported=\"true\"\n            android:targetActivity=\"org.microg.vending.ui.MainActivity\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity-alias>\n    </application>\n</manifest>"
  },
  {
    "path": "vending-app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ SPDX-FileCopyrightText: 2014 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<manifest xmlns:tools=\"http://schemas.android.com/tools\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <permission\n        android:name=\"com.android.vending.CHECK_LICENSE\"\n        android:protectionLevel=\"normal\" />\n\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n    <uses-permission android:name=\"android.permission.POST_NOTIFICATIONS\" />\n    <uses-permission\n        android:name=\"android.permission.GET_ACCOUNTS\"\n        android:maxSdkVersion=\"22\" />\n    <uses-permission android:name=\"org.microg.gms.permission.READ_SETTINGS\" />\n    <uses-permission android:name=\"org.microg.gms.permission.WRITE_SETTINGS\" />\n    <uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\" />\n    <uses-permission android:name=\"com.google.android.gms.permission.READ_SETTINGS\" />\n    <uses-permission android:name=\"com.google.android.gms.permission.WRITE_SETTINGS\" />\n    <uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />\n    <uses-permission android:name=\"android.permission.REQUEST_INSTALL_PACKAGES\"/>\n    <uses-permission android:name=\"android.permission.QUERY_ALL_PACKAGES\" />\n\n    <uses-permission android:name=\"android.permission.INSTALL_PACKAGES\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission android:name=\"android.permission.DELETE_PACKAGES\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission android:name=\"com.google.android.gms.auth.permission.GOOGLE_ACCOUNT_CHANGE\"/>\n\n    <permission\n        android:description=\"@string/billing_permission_desc\"\n        android:label=\"@string/billing_permission_label\"\n        android:name=\"com.android.vending.BILLING\"\n        android:protectionLevel=\"instant|normal\"/>\n\n    <uses-permission\n        android:name=\"android.permission.USE_CREDENTIALS\"\n        android:maxSdkVersion=\"22\" />\n\n    <uses-permission android:name=\"android.permission.FOREGROUND_SERVICE\" />\n\n    <queries>\n        <intent>\n            <action android:name=\"android.intent.action.VIEW\" />\n            <data android:scheme=\"market\" />\n        </intent>\n        <intent>\n            <action android:name=\"android.intent.action.VIEW\" />\n            <data\n                android:scheme=\"https\"\n                android:host=\"market.android.com\" />\n        </intent>\n        <intent>\n            <action android:name=\"android.intent.action.VIEW\" />\n            <data\n                android:scheme=\"https\"\n                android:host=\"play.google.com\" />\n        </intent>\n    </queries>\n\n    <uses-sdk tools:overrideLibrary=\"coil.svg, coil.compose.singleton, coil.compose.base,\n        androidx.compose.material.icons,com.google.accompanist.drawablepainter,androidx.compose.ui.util,\n        androidx.compose.ui.unit,androidx.compose.ui.text,androidx.compose.ui.graphics,androidx.compose.ui.geometry,\n        androidx.activity.compose,androidx.compose.runtime.saveable,\n        androidx.compose.material.ripple,androidx.compose.foundation.layout,androidx.compose.animation.core,\n        coil.singleton, coil.base, androidx.compose.material3, com.google.accompanist.systemuicontroller, androidx.compose.animation.graphics,\n        androidx.compose.ui.tooling.data, androidx.compose.ui.tooling.preview\" />\n\n    <application\n        android:forceQueryable=\"true\"\n        android:icon=\"@mipmap/ic_app\"\n        android:roundIcon=\"@mipmap/ic_app\"\n        android:label=\"@string/app_name\"\n        android:name=\"androidx.multidex.MultiDexApplication\">\n\n        <meta-data\n            android:name=\"org.microg.gms.settings:source-package\"\n            android:value=\"com.google.android.gms\" />\n\n        <meta-data\n            android:name=\"org.microg.gms.profile:source-package\"\n            android:value=\"com.google.android.gms\" />\n\n        <activity\n            android:name=\".GrantFakeSignaturePermissionActivity\"\n            android:exported=\"true\"\n            android:theme=\"@style/Theme.Dialog.NoActionBar\" />\n\n        <service\n            android:name=\"com.android.vending.licensing.LicensingService\"\n            android:permission=\"com.android.vending.CHECK_LICENSE\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.android.vending.licensing.ILicensingService\" />\n            </intent-filter>\n        </service>\n\n        <service\n            android:name=\"com.google.android.finsky.externalreferrer.GetInstallReferrerService\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.google.android.finsky.BIND_GET_INSTALL_REFERRER_SERVICE\" />\n            </intent-filter>\n        </service>\n\n        <activity\n            android:name=\"org.microg.vending.ui.MainActivity\"\n            android:theme=\"@style/Theme.Dialog.NoActionBar\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n\n                <category android:name=\"android.intent.category.INFO\" />\n            </intent-filter>\n        </activity>\n\n        <activity-alias\n            android:name=\"com.google.android.finsky.activities.MarketDeepLinkHandlerActivity\"\n            android:exported=\"true\"\n            android:targetActivity=\"org.microg.vending.MarketIntentRedirect\">\n        </activity-alias>\n\n        <activity\n            android:name=\"org.microg.vending.MarketIntentRedirect\"\n            android:theme=\"@style/Theme.Dialog.NoActionBar\"\n            android:exported=\"true\">\n            <intent-filter android:priority=\"-100\">\n                <action android:name=\"android.intent.action.VIEW\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n\n                <data android:scheme=\"market\" />\n            </intent-filter>\n            <!--\n            Play Store website opens this via intent:// URI if BROWSABLE category is added.\n            If the only other valid or the configured default retriever of the intent is the web browser itself,\n            this would cause an infinite loop of redirects between the redirector and the web browser opening\n            the Play Store website.\n\n            To prevent this, we remove the BROWSABLE category. This ensure best possible compatibility without running\n            into the aforementioned issue.\n            -->\n            <intent-filter\n                android:priority=\"-100\"\n                tools:ignore=\"AppLinkUrlError\">\n                <action android:name=\"android.intent.action.VIEW\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n\n                <data android:scheme=\"http\" />\n                <data android:scheme=\"https\" />\n                <data android:host=\"play.google.com\" />\n                <data android:host=\"market.android.com\" />\n            </intent-filter>\n        </activity>\n\n        <receiver\n            android:name=\"com.android.vending.licensing.IgnoreReceiver\"\n            android:exported=\"false\" />\n        <receiver\n            android:name=\"com.android.vending.licensing.SignInReceiver\"\n            android:exported=\"false\" />\n\n        <activity\n            android:name=\"org.microg.vending.billing.PurchaseActivity\"\n            android:exported=\"true\"\n            android:theme=\"@style/Theme.Translucent\"\n            android:process=\":ui\">\n            <intent-filter>\n                <action android:name=\"com.android.vending.billing.PURCHASE\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </activity>\n\n        <service android:name=\"com.google.android.finsky.splitinstallservice.SplitInstallService\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.google.android.play.core.splitinstall.BIND_SPLIT_INSTALL_SERVICE\"/>\n            </intent-filter>\n        </service>\n\n        <service\n            android:name=\"com.google.android.finsky.appcontentservice.engage.AppEngageServiceV2\"\n            android:exported=\"true\"\n            android:process=\":background\">\n            <intent-filter>\n                <action android:name=\"com.google.android.engage.BIND_APP_ENGAGE_SERVICE\"/>\n            </intent-filter>\n        </service>\n\n\n        <service\n            android:name=\"com.android.vending.billing.InAppBillingService\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.android.vending.billing.InAppBillingService.BIND\" />\n            </intent-filter>\n        </service>\n\n        <activity\n            android:name=\"org.microg.vending.billing.ui.InAppBillingHostActivity\"\n            android:exported=\"true\"\n            android:theme=\"@style/InAppBillingStyle\"\n            android:windowSoftInputMode=\"adjustResize\" />\n\n        <activity\n            android:name=\"org.microg.vending.billing.ui.PlayWebViewActivity\"\n            android:process=\":ui\"\n            android:exported=\"false\" />\n\n        <service\n            android:name=\"com.google.android.finsky.assetmoduleservice.AssetModuleService\"\n            android:enabled=\"true\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.google.android.play.core.assetmoduleservice.BIND_ASSET_MODULE_SERVICE\" />\n            </intent-filter>\n        </service>\n\n        <receiver\n            android:name=\".installer.SessionResultReceiver\"\n            android:exported=\"false\"\n            tools:targetApi=\"21\" />\n\n        <receiver\n            android:name=\".installer.InstallReceiver\"\n            android:exported=\"false\"\n            tools:targetApi=\"21\" />\n\n        <!-- Work account store -->\n        <activity android:name=\"org.microg.vending.ui.WorkAppsActivity\"\n            android:exported=\"true\"\n            android:theme=\"@style/Theme.Material3.DayNight\"\n            android:label=\"@string/vending_activity_name\"\n            android:enabled=\"false\"\n            tools:targetApi=\"21\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n\n        <service android:name=\".installer.InstallService\"\n            android:foregroundServiceType=\"dataSync\"\n            android:exported=\"false\"\n            tools:targetApi=\"21\" />\n\n        <receiver android:name=\"org.microg.vending.WorkAccountChangedReceiver\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"org.microg.vending.WORK_ACCOUNT_CHANGED\" />\n            </intent-filter>\n        </receiver>\n\n        <service\n            android:name=\"com.google.android.finsky.integrityservice.IntegrityService\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.google.android.play.core.integrityservice.BIND_INTEGRITY_SERVICE\" />\n            </intent-filter>\n        </service>\n\n        <service\n            android:name=\"com.google.android.finsky.expressintegrityservice.ExpressIntegrityService\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.google.android.play.core.expressintegrityservice.BIND_EXPRESS_INTEGRITY_SERVICE\"/>\n            </intent-filter>\n        </service>\n      \n        <receiver\n            android:name=\"com.google.android.finsky.accounts.impl.AccountsChangedReceiver\"\n            android:permission=\"com.google.android.gms.auth.permission.GOOGLE_ACCOUNT_CHANGE\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.auth.GOOGLE_ACCOUNT_CHANGE\"/>\n            </intent-filter>\n        </receiver>\n\n        <service\n            android:name=\"com.google.android.finsky.services.PlayGearheadService\"\n            android:exported=\"true\" />\n\n        <service android:name=\"com.google.android.finsky.installservice.DevTriggeredUpdateService\"\n            android:enabled=\"true\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.google.android.play.core.install.BIND_UPDATE_SERVICE\"/>\n            </intent-filter>\n        </service>\n\n        <service\n            android:name=\"com.google.android.finsky.inappreviewservice.InAppReviewService\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.google.android.finsky.BIND_IN_APP_REVIEW_SERVICE\"/>\n            </intent-filter>\n        </service>\n\n        <activity\n            android:name=\"com.google.android.finsky.inappreviewdialog.InAppReviewActivity\"\n            android:exported=\"false\"\n            android:excludeFromRecents=\"true\"\n            android:configChanges=\"orientation|keyboardHidden\"\n            android:windowSoftInputMode=\"stateHidden\"/>\n\n        <activity\n            android:name=\"org.microg.vending.installer.AppInstallActivity\"\n            android:exported=\"true\"\n            android:excludeFromRecents=\"true\"\n            android:theme=\"@style/Theme.App.Translucent\"\n            tools:targetApi=\"21\">\n            <intent-filter>\n                <action android:name=\"org.microg.vending.action.INSTALL_PACKAGE\"/>\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <data android:mimeType=\"application/vnd.android.package-archive\" />\n            </intent-filter>\n        </activity>\n\n        <activity\n            android:name=\"org.microg.vending.installer.AskInstallReminderActivity\"\n            android:exported=\"false\"\n            android:excludeFromRecents=\"true\"\n            android:theme=\"@style/Theme.AppCompat.NoActionBar\"\n            tools:targetApi=\"21\"/>\n\n    </application>\n</manifest>\n"
  },
  {
    "path": "vending-app/src/main/aidl/com/android/vending/billing/IInAppBillingCreateAlternativeBillingOnlyTokenCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.android.vending.billing;\n\nimport android.os.Bundle;\n\ninterface IInAppBillingCreateAlternativeBillingOnlyTokenCallback {\n    /**\n     * @param bundle a Bundle with the following keys:\n     *        \"RESPONSE_CODE\" - Integer\n     *        \"DEBUG_MESSAGE\" - String\n     *        \"CREATE_ALTERNATIVE_BILLING_ONLY_REPORTING_DETAILS\" - String with JSON encoded reporting details with the following keys:\n     *            \"externalTransactionToken\" - String used to report a transaction made via alternative billing\n     */\n    void callback(in Bundle bundle);\n}"
  },
  {
    "path": "vending-app/src/main/aidl/com/android/vending/billing/IInAppBillingCreateExternalPaymentReportingDetailsCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.android.vending.billing;\n\nimport android.os.Bundle;\n\ninterface IInAppBillingCreateExternalPaymentReportingDetailsCallback {\n    /**\n     * @param bundle a Bundle with the following keys:\n     *        \"RESPONSE_CODE\" - Integer\n     *        \"DEBUG_MESSAGE\" - String\n     */\n    void callback(in Bundle bundle);\n}"
  },
  {
    "path": "vending-app/src/main/aidl/com/android/vending/billing/IInAppBillingDelegateToBackendCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.android.vending.billing;\n\nimport android.os.Bundle;\n\ninterface IInAppBillingDelegateToBackendCallback {\n\n}"
  },
  {
    "path": "vending-app/src/main/aidl/com/android/vending/billing/IInAppBillingGetAlternativeBillingOnlyDialogIntentCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.android.vending.billing;\n\nimport android.os.Bundle;\n\ninterface IInAppBillingGetAlternativeBillingOnlyDialogIntentCallback {\n    /**\n     * @param bundle a Bundle with the following keys:\n     *        \"RESPONSE_CODE\" - Integer\n     *        \"DEBUG_MESSAGE\" - String\n     *        \"ALTERNATIVE_BILLING_ONLY_DIALOG_INTENT\" - PendingIntent\n     */\n    void callback(in Bundle bundle);\n}"
  },
  {
    "path": "vending-app/src/main/aidl/com/android/vending/billing/IInAppBillingGetBillingConfigCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.android.vending.billing;\n\nimport android.os.Bundle;\n\ninterface IInAppBillingGetBillingConfigCallback {\n    /**\n     * @param bundle a Bundle with the following keys:\n     *        \"BILLING_CONFIG\" - String with JSON encoded billing config with following keys:\n     *            \"countryCode\" - String with customer's country code (ISO-3166-1 alpha2)\n     */\n    void callback(in Bundle bundle);\n}"
  },
  {
    "path": "vending-app/src/main/aidl/com/android/vending/billing/IInAppBillingGetExternalPaymentDialogIntentCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.android.vending.billing;\n\nimport android.os.Bundle;\n\ninterface IInAppBillingGetExternalPaymentDialogIntentCallback {\n    /**\n     * @param bundle a Bundle with the following keys:\n     *        \"RESPONSE_CODE\" - Integer\n     *        \"DEBUG_MESSAGE\" - String\n     *        \"EXTERNAL_PAYMENT_DIALOG_INTENT\" - PendingIntent\n     */\n    void callback(in Bundle bundle);\n}"
  },
  {
    "path": "vending-app/src/main/aidl/com/android/vending/billing/IInAppBillingInitializeCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2026 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.android.vending.billing;\n\nimport android.os.Bundle;\n\ninterface IInAppBillingInitializeCallback {\n    void callback(in Bundle bundle);\n}\n"
  },
  {
    "path": "vending-app/src/main/aidl/com/android/vending/billing/IInAppBillingIsAlternativeBillingOnlyAvailableCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.android.vending.billing;\n\nimport android.os.Bundle;\n\ninterface IInAppBillingIsAlternativeBillingOnlyAvailableCallback {\n    /**\n     * @param bundle a Bundle with the following keys:\n     *        \"RESPONSE_CODE\" - Integer\n     *        \"DEBUG_MESSAGE\" - String\n     */\n    void callback(in Bundle bundle);\n}"
  },
  {
    "path": "vending-app/src/main/aidl/com/android/vending/billing/IInAppBillingIsExternalPaymentAvailableCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.android.vending.billing;\n\nimport android.os.Bundle;\n\ninterface IInAppBillingIsExternalPaymentAvailableCallback {\n    /**\n     * @param bundle a Bundle with the following keys:\n     *        \"RESPONSE_CODE\" - Integer\n     *        \"DEBUG_MESSAGE\" - String\n     */\n    void callback(in Bundle bundle);\n}"
  },
  {
    "path": "vending-app/src/main/aidl/com/android/vending/billing/IInAppBillingService.aidl",
    "content": "package com.android.vending.billing;\n\nimport android.os.Bundle;\nimport com.android.vending.billing.IInAppBillingServiceCallback;\nimport com.android.vending.billing.IInAppBillingCreateAlternativeBillingOnlyTokenCallback;\nimport com.android.vending.billing.IInAppBillingCreateExternalPaymentReportingDetailsCallback;\nimport com.android.vending.billing.IInAppBillingDelegateToBackendCallback;\nimport com.android.vending.billing.IInAppBillingGetAlternativeBillingOnlyDialogIntentCallback;\nimport com.android.vending.billing.IInAppBillingGetBillingConfigCallback;\nimport com.android.vending.billing.IInAppBillingGetExternalPaymentDialogIntentCallback;\nimport com.android.vending.billing.IInAppBillingIsAlternativeBillingOnlyAvailableCallback;\nimport com.android.vending.billing.IInAppBillingIsExternalPaymentAvailableCallback;\nimport com.android.vending.billing.IInAppBillingInitializeCallback;\n\n\n/**\n * InAppBillingService is the service that provides in-app billing version 3 and beyond.\n * This service provides the following features:\n * 1. Provides a new API to get details of in-app items published for the app including\n *    price, type, title and description.\n * 2. The purchase flow is synchronous and purchase information is available immediately\n *    after it completes.\n * 3. Purchase information of in-app purchases is maintained within the Google Play system\n *    till the purchase is consumed.\n * 4. An API to consume a purchase of an inapp item. All purchases of one-time\n *    in-app items are consumable and thereafter can be purchased again.\n * 5. An API to get current purchases of the user immediately. This will not contain any\n *    consumed purchases.\n *\n * All calls will give a response code with the following possible values\n * RESULT_OK = 0 - success\n * RESULT_USER_CANCELED = 1 - User pressed back or canceled a dialog\n * RESULT_SERVICE_UNAVAILABLE = 2 - The network connection is down\n * RESULT_BILLING_UNAVAILABLE = 3 - This billing API version is not supported for the type requested\n * RESULT_ITEM_UNAVAILABLE = 4 - Requested SKU is not available for purchase\n * RESULT_DEVELOPER_ERROR = 5 - Invalid arguments provided to the API\n * RESULT_ERROR = 6 - Fatal error during the API action\n * RESULT_ITEM_ALREADY_OWNED = 7 - Failure to purchase since item is already owned\n * RESULT_ITEM_NOT_OWNED = 8 - Failure to consume since item is not owned\n */\ninterface IInAppBillingService {\n    /**\n     * Checks support for the requested billing API version, package and in-app type.\n     * Minimum API version supported by this interface is 3.\n     * @param apiVersion billing API version that the app is using\n     * @param packageName the package name of the calling app\n     * @param type type of the in-app item being purchased (\"inapp\" for one-time purchases\n     *        and \"subs\" for subscriptions)\n     * @return RESULT_OK(0) on success and appropriate response code on failures.\n     */\n    int isBillingSupported(int apiVersion, String packageName, String type) = 0;\n\n    /**\n     * Provides details of a list of SKUs\n     * Given a list of SKUs of a valid type in the skusBundle, this returns a bundle\n     * with a list JSON strings containing the productId, price, title and description.\n     * This API can be called with a maximum of 20 SKUs.\n     * @param apiVersion billing API version that the app is using\n     * @param packageName the package name of the calling app\n     * @param type of the in-app items (\"inapp\" for one-time purchases\n     *        and \"subs\" for subscriptions)\n     * @param skusBundle bundle containing a StringArrayList of SKUs with key \"ITEM_ID_LIST\"\n     * @return Bundle containing the following key-value pairs\n     *         \"RESPONSE_CODE\" with int value, RESULT_OK(0) if success, appropriate response codes\n     *                         on failures.\n     *         \"DETAILS_LIST\" with a StringArrayList containing purchase information\n     *                        in JSON format similar to:\n     *                        '{ \"productId\" : \"exampleSku\",\n     *                           \"type\" : \"inapp\",\n     *                           \"price\" : \"$5.00\",\n     *                           \"price_currency\": \"USD\",\n     *                           \"price_amount_micros\": 5000000,\n     *                           \"title : \"Example Title\",\n     *                           \"description\" : \"This is an example description\" }'\n     */\n    Bundle getSkuDetails(int apiVersion, String packageName, String type, in Bundle skusBundle) = 1;\n\n    /**\n     * Returns a pending intent to launch the purchase flow for an in-app item by providing a SKU,\n     * the type, a unique purchase token and an optional developer payload.\n     * @param apiVersion billing API version that the app is using\n     * @param packageName package name of the calling app\n     * @param sku the SKU of the in-app item as published in the developer console\n     * @param type of the in-app item being purchased (\"inapp\" for one-time purchases\n     *        and \"subs\" for subscriptions)\n     * @param developerPayload optional argument to be sent back with the purchase information\n     * @return Bundle containing the following key-value pairs\n     *         \"RESPONSE_CODE\" with int value, RESULT_OK(0) if success, appropriate response codes\n     *                         on failures.\n     *         \"BUY_INTENT\" - PendingIntent to start the purchase flow\n     *\n     * The Pending intent should be launched with startIntentSenderForResult. When purchase flow\n     * has completed, the onActivityResult() will give a resultCode of OK or CANCELED.\n     * If the purchase is successful, the result data will contain the following key-value pairs\n     *         \"RESPONSE_CODE\" with int value, RESULT_OK(0) if success, appropriate response\n     *                         codes on failures.\n     *         \"INAPP_PURCHASE_DATA\" - String in JSON format similar to\n     *                                 '{\"orderId\":\"12999763169054705758.1371079406387615\",\n     *                                   \"packageName\":\"com.example.app\",\n     *                                   \"productId\":\"exampleSku\",\n     *                                   \"purchaseTime\":1345678900000,\n     *                                   \"purchaseToken\" : \"122333444455555\",\n     *                                   \"developerPayload\":\"example developer payload\" }'\n     *         \"INAPP_DATA_SIGNATURE\" - String containing the signature of the purchase data that\n     *                                  was signed with the private key of the developer\n     */\n    Bundle getBuyIntent(int apiVersion, String packageName, String sku, String type,\n        String developerPayload) = 2;\n\n    /**\n     * Returns the current SKUs owned by the user of the type and package name specified along with\n     * purchase information and a signature of the data to be validated.\n     * This will return all SKUs that have been purchased in V3 and managed items purchased using\n     * V1 and V2 that have not been consumed.\n     * @param apiVersion billing API version that the app is using\n     * @param packageName package name of the calling app\n     * @param type of the in-app items being requested (\"inapp\" for one-time purchases\n     *        and \"subs\" for subscriptions)\n     * @param continuationToken to be set as null for the first call, if the number of owned\n     *        skus are too many, a continuationToken is returned in the response bundle.\n     *        This method can be called again with the continuation token to get the next set of\n     *        owned skus.\n     * @return Bundle containing the following key-value pairs\n     *         \"RESPONSE_CODE\" with int value, RESULT_OK(0) if success, appropriate response codes\n                               on failures.\n     *         \"INAPP_PURCHASE_ITEM_LIST\" - StringArrayList containing the list of SKUs\n     *         \"INAPP_PURCHASE_DATA_LIST\" - StringArrayList containing the purchase information\n     *         \"INAPP_DATA_SIGNATURE_LIST\"- StringArrayList containing the signatures\n     *                                      of the purchase information\n     *         \"INAPP_CONTINUATION_TOKEN\" - String containing a continuation token for the\n     *                                      next set of in-app purchases. Only set if the\n     *                                      user has more owned skus than the current list.\n     */\n    Bundle getPurchases(int apiVersion, String packageName, String type, String continuationToken) = 3;\n\n    /**\n     * Consume the last purchase of the given SKU. This will result in this item being removed\n     * from all subsequent responses to getPurchases() and allow re-purchase of this item.\n     * @param apiVersion billing API version that the app is using\n     * @param packageName package name of the calling app\n     * @param purchaseToken token in the purchase information JSON that identifies the purchase\n     *        to be consumed\n     * @return RESULT_OK(0) if consumption succeeded, appropriate response codes on failures.\n     */\n    int consumePurchase(int apiVersion, String packageName, String purchaseToken) = 4;\n\n    int isPromoEligible(int apiVersion, String packageName, String type) = 5;\n\n    /**\n     * Returns a pending intent to launch the purchase flow for upgrading or downgrading a\n     * subscription. The existing owned SKU(s) should be provided along with the new SKU that\n     * the user is upgrading or downgrading to.\n     * @param apiVersion billing API version that the app is using, must be 5 or later\n     * @param packageName package name of the calling app\n     * @param oldSkus the SKU(s) that the user is upgrading or downgrading from,\n     *        if null or empty this method will behave like {@link #getBuyIntent}\n     * @param newSku the SKU that the user is upgrading or downgrading to\n     * @param type of the item being purchased, currently must be \"subs\"\n     * @param developerPayload optional argument to be sent back with the purchase information\n     * @return Bundle containing the following key-value pairs\n     *         \"RESPONSE_CODE\" with int value, RESULT_OK(0) if success, appropriate response codes\n     *                         on failures.\n     *         \"BUY_INTENT\" - PendingIntent to start the purchase flow\n     *\n     * The Pending intent should be launched with startIntentSenderForResult. When purchase flow\n     * has completed, the onActivityResult() will give a resultCode of OK or CANCELED.\n     * If the purchase is successful, the result data will contain the following key-value pairs\n     *         \"RESPONSE_CODE\" with int value, RESULT_OK(0) if success, appropriate response\n     *                         codes on failures.\n     *         \"INAPP_PURCHASE_DATA\" - String in JSON format similar to\n     *                                 '{\"orderId\":\"12999763169054705758.1371079406387615\",\n     *                                   \"packageName\":\"com.example.app\",\n     *                                   \"productId\":\"exampleSku\",\n     *                                   \"purchaseTime\":1345678900000,\n     *                                   \"purchaseToken\" : \"122333444455555\",\n     *                                   \"developerPayload\":\"example developer payload\" }'\n     *         \"INAPP_DATA_SIGNATURE\" - String containing the signature of the purchase data that\n     *                                  was signed with the private key of the developer\n     */\n    Bundle getBuyIntentToReplaceSkus(int apiVersion, String packageName,\n        in List<String> oldSkus, String newSku, String type, String developerPayload) = 6;\n\n    /**\n     * Returns a pending intent to launch the purchase flow for an in-app item. This method is\n     * a variant of the {@link #getBuyIntent} method and takes an additional {@code extraParams}\n     * parameter. This parameter is a Bundle of optional keys and values that affect the\n     * operation of the method.\n     * @param apiVersion billing API version that the app is using, must be 6 or later\n     * @param packageName package name of the calling app\n     * @param sku the SKU of the in-app item as published in the developer console\n     * @param type of the in-app item being purchased (\"inapp\" for one-time purchases\n     *        and \"subs\" for subscriptions)\n     * @param developerPayload optional argument to be sent back with the purchase information\n     * @extraParams a Bundle with the following optional keys:\n     *        \"skusToReplace\" - List<String> - an optional list of SKUs that the user is\n     *                          upgrading or downgrading from.\n     *                          Pass this field if the purchase is upgrading or downgrading\n     *                          existing subscriptions.\n     *                          The specified SKUs are replaced with the SKUs that the user is\n     *                          purchasing. Google Play replaces the specified SKUs at the start of\n     *                          the next billing cycle.\n     * \"replaceSkusProration\" - Boolean - whether the user should be credited for any unused\n     *                          subscription time on the SKUs they are upgrading or downgrading.\n     *                          If you set this field to true, Google Play swaps out the old SKUs\n     *                          and credits the user with the unused value of their subscription\n     *                          time on a pro-rated basis.\n     *                          Google Play applies this credit to the new subscription, and does\n     *                          not begin billing the user for the new subscription until after\n     *                          the credit is used up.\n     *                          If you set this field to false, the user does not receive credit for\n     *                          any unused subscription time and the recurrence date does not\n     *                          change.\n     *                          Default value is true. Ignored if you do not pass skusToReplace.\n     *            \"accountId\" - String - an optional obfuscated string that is uniquely\n     *                          associated with the user's account in your app.\n     *                          If you pass this value, Google Play can use it to detect irregular\n     *                          activity, such as many devices making purchases on the same\n     *                          account in a short period of time.\n     *                          Do not use the developer ID or the user's Google ID for this field.\n     *                          In addition, this field should not contain the user's ID in\n     *                          cleartext.\n     *                          We recommend that you use a one-way hash to generate a string from\n     *                          the user's ID, and store the hashed string in this field.\n     *                   \"vr\" - Boolean - an optional flag indicating whether the returned intent\n     *                          should start a VR purchase flow. The apiVersion must also be 7 or\n     *                          later to use this flag.\n     */\n    Bundle getBuyIntentExtraParams(int apiVersion, String packageName, String sku,\n        String type, String developerPayload, in Bundle extraParams) = 7;\n\n    /**\n     * Returns the most recent purchase made by the user for each SKU, even if that purchase is\n     * expired, canceled, or consumed.\n     * @param apiVersion billing API version that the app is using, must be 6 or later\n     * @param packageName package name of the calling app\n     * @param type of the in-app items being requested (\"inapp\" for one-time purchases\n     *        and \"subs\" for subscriptions)\n     * @param continuationToken to be set as null for the first call, if the number of owned\n     *        skus is too large, a continuationToken is returned in the response bundle.\n     *        This method can be called again with the continuation token to get the next set of\n     *        owned skus.\n     * @param extraParams a Bundle with the following optional keys:\n     *        \"playBillingLibraryVersion\" - String\n     *        \"enablePendingPurchases\" - Boolean\n     * @return Bundle containing the following key-value pairs\n     *         \"RESPONSE_CODE\" with int value: RESULT_OK(0) if success,\n     *         {@link IabHelper#BILLING_RESPONSE_RESULT_*} response codes on failures.\n     *         \"DEBUG_MESSAGE\" - String\n     *         \"INAPP_PURCHASE_ITEM_LIST\" - ArrayList<String> containing the list of SKUs\n     *         \"INAPP_PURCHASE_DATA_LIST\" - ArrayList<String> containing the purchase information\n     *         \"INAPP_DATA_SIGNATURE_LIST\"- ArrayList<String> containing the signatures\n     *                                      of the purchase information\n     *         \"INAPP_CONTINUATION_TOKEN\" - String containing a continuation token for the\n     *                                      next set of in-app purchases. Only set if the\n     *                                      user has more owned skus than the current list.\n     */\n    Bundle getPurchaseHistory(int apiVersion, String packageName, String type,\n        String continuationToken, in Bundle extraParams) = 8;\n\n    /**\n     * This method is a variant of {@link #isBillingSupported}} that takes an additional\n     * {@code extraParams} parameter.\n     * @param apiVersion billing API version that the app is using, must be 7 or later\n     * @param packageName package name of the calling app\n     * @param type of the in-app item being purchased (\"inapp\" for one-time purchases and \"subs\"\n     *        for subscriptions)\n     * @param extraParams a Bundle with the following optional keys:\n     *        \"vr\" - Boolean - an optional flag to indicate whether {link #getBuyIntentExtraParams}\n     *               supports returning a VR purchase flow.\n     * @return RESULT_OK(0) on success and appropriate response code on failures.\n     */\n    int isBillingSupportedExtraParams(int apiVersion, String packageName, String type, in Bundle extraParams) = 9;\n\n    /**\n     * This method is a variant of {@link #getPurchases}} that takes an additional\n     * {@code extraParams} parameter.\n     * @param apiVersion billing API version that the app is using, must be 9 or later\n     * @param packageName package name of the calling app\n     * @param type of the in-app items being requested (\"inapp\" for one-time purchases\n     *        and \"subs\" for subscriptions)\n     * @param continuationToken to be set as null for the first call, if the number of owned\n     *        skus are too many, a continuationToken is returned in the response bundle.\n     *        This method can be called again with the continuation token to get the next set of\n     *        owned skus.\n     * @param extraParams a Bundle with the following optional keys:\n     *        \"playBillingLibraryVersion\" - String\n     *        \"enablePendingPurchases\" - Boolean\n     * @return Bundle containing the following key-value pairs\n     *         \"RESPONSE_CODE\" with int value, RESULT_OK(0) if success, appropriate response codes\n                               on failures.\n     *         \"DEBUG_MESSAGE\" - String\n     *         \"INAPP_PURCHASE_ITEM_LIST\" - StringArrayList containing the list of SKUs\n     *         \"INAPP_PURCHASE_DATA_LIST\" - StringArrayList containing the purchase information\n     *         \"INAPP_DATA_SIGNATURE_LIST\"- StringArrayList containing the signatures\n     *                                      of the purchase information\n     *         \"INAPP_CONTINUATION_TOKEN\" - String containing a continuation token for the\n     *                                      next set of in-app purchases. Only set if the\n     *                                      user has more owned skus than the current list.\n     */\n    Bundle getPurchasesExtraParams(int apiVersion, String packageName, String type, String continuationToken, in Bundle extraParams) = 10;\n\n    /**\n     * This method is a variant of {@link #consumePurchase}} that takes an additional\n     * {@code extraParams} parameter.\n     * @param apiVersion billing API version that the app is using, must be 9 or later\n     * @param packageName package name of the calling app\n     * @param purchaseToken token in the purchase information JSON that identifies the purchase\n     *        to be consumed\n     * @param extraParams a Bundle with the following optional keys:\n     *        \"playBillingLibraryVersion\" - String\n     * @return Bundle containing the following key-value pairs\n     *         \"RESPONSE_CODE\" with int value, RESULT_OK(0) if success, appropriate response codes\n     *                         on failures.\n     *         \"DEBUG_MESSAGE\" - String\n     */\n    Bundle consumePurchaseExtraParams(int apiVersion, String packageName, String purchaseToken, in Bundle extraParams) = 11;\n\n    Bundle getPriceChangeConfirmationIntent(int apiVersion, String packageName, String sku, String type, in Bundle extraParams) = 800;\n\n    /**\n     * This method is a variant of {@link #getSkuDetails}} that takes an additional\n     * {@code extraParams} parameter.\n     * @param apiVersion billing API version that the app is using, must be 9 or later\n     * @param packageName package name of the calling app\n     * @param type of the in-app item being purchased (\"inapp\" for one-time purchases and \"subs\"\n     *        for subscriptions)\n     * @param skusBundle bundle containing a StringArrayList of SKUs with key \"ITEM_ID_LIST\"\n     * @param extraParams a Bundle with the following optional keys:\n     *        \"SKU_DETAILS_RESPONSE_FORMAT\" - String\n     *        \"SKU_OFFER_ID_TOKEN_LIST\" - ArrayList<String>\n     *        \"SKU_SERIALIZED_DOCID_LIST\" - ArrayList<String>\n     *        \"accountName\" - String\n     *        \"playBillingLibraryVersion\" - String\n     *        \"enablePendingPurchases\" - Boolean\n     * @return Bundle containing the following key-value pairs\n     *         \"RESPONSE_CODE\" with int value, RESULT_OK(0) if success, appropriate response codes\n     *                         on failures.\n     *         \"DEBUG_MESSAGE\" - String\n     *         \"DETAILS_LIST\" with a StringArrayList containing purchase information\n     *                        in JSON format similar to:\n     *                        '{ \"productId\" : \"exampleSku\",\n     *                           \"type\" : \"inapp\",\n     *                           \"price\" : \"$5.00\",\n     *                           \"price_currency\": \"USD\",\n     *                           \"price_amount_micros\": 5000000,\n     *                           \"title : \"Example Title\",\n     *                           \"description\" : \"This is an example description\" }'\n     */\n    Bundle getSkuDetailsExtraParams(int apiVersion, String packageName, String type, in Bundle skuBundle, in Bundle extraParams) = 900;\n\n    /**\n     * @param apiVersion billing API version that the app is using, must be 12 or later\n     * @param packageName package name of the calling app\n     * @param extraParams a Bundle with the following optional keys:\n     *        \"playBillingLibraryVersion\" - String\n     * @return Bundle containing the following key-value pairs\n     *         \"RESPONSE_CODE\" with int value, RESULT_OK(0) if success, appropriate response codes\n     *                         on failures.\n     *         \"DEBUG_MESSAGE\" - String\n     */\n    Bundle acknowledgePurchase(int apiVersion, String packageName, String purchaseToken, in Bundle extraParams) = 901;\n\n    Bundle o(int apiVersion, String packageName, String arg3, in Bundle arg4) = 1100;\n\n    /**\n     * @param apiVersion billing API version that the app is using, must be 12 or later\n     * @param packageName package name of the calling app\n     * @param extraParams a Bundle with the following optional keys:\n     *        \"KEY_WINDOW_TOKEN\" - IBinder\n     *        \"KEY_DIMEN_LEFT\" - Integer\n     *        \"KEY_DIMEN_TOP\" - Integer\n     *        \"KEY_DIMEN_RIGHT\" - Integer\n     *        \"KEY_DIMEN_BOTTOM\" - Integer\n     *        \"KEY_DIMEN_BOTTOM\" - Integer\n     *        \"KEY_CATEGORY_IDS\" - ArrayList<Integer>\n     *        \"playBillingLibraryVersion\" - String\n     * @param callback callback that is invoked with the result, see IInAppBillingServiceCallback.aidl for details\n     */\n    void showInAppMessages(int apiVersion, String packageName, in Bundle extraParams, IInAppBillingServiceCallback callback) = 1200;\n\n    /**\n     * @param apiVersion billing API version that the app is using, must be 18 or later\n     * @param packageName package name of the calling app\n     * @param extraParams a Bundle with the following optional keys:\n     *        \"playBillingLibraryVersion\" - String\n     * @param callback callback that is invoked with the result, see IInAppBillingGetBillingConfigCallback.aidl for details\n     */\n    void getBillingConfig(int apiVersion, String packageName, in Bundle extraParams, IInAppBillingGetBillingConfigCallback callback) = 1300;\n\n    /**\n     * @param apiVersion billing API version that the app is using, must be 21 or later\n     * @param packageName package name of the calling app\n     * @param extraParams a Bundle with the following optional keys:\n     *        \"playBillingLibraryVersion\" - String\n     * @param callback callback that is invoked with the result, see IInAppBillingIsAlternativeBillingOnlyAvailableCallback.aidl for details\n     */\n    void isAlternativeBillingOnlyAvailable(int apiVersion, String packageName, in Bundle extraParams, IInAppBillingIsAlternativeBillingOnlyAvailableCallback callback) = 1400;\n\n    /**\n     * @param apiVersion billing API version that the app is using, must be 21 or later\n     * @param packageName package name of the calling app\n     * @param extraParams a Bundle with the following optional keys:\n     *        \"playBillingLibraryVersion\" - String\n     * @param callback callback that is invoked with the result, see IInAppBillingCreateAlternativeBillingOnlyTokenCallback.aidl for details\n     */\n    void createAlternativeBillingOnlyToken(int apiVersion, String packageName, in Bundle extraParams, IInAppBillingCreateAlternativeBillingOnlyTokenCallback callback) = 1500;\n\n    /**\n     * @param apiVersion billing API version that the app is using, must be 21 or later\n     * @param packageName package name of the calling app\n     * @param extraParams a Bundle with the following optional keys:\n     *        \"playBillingLibraryVersion\" - String\n     * @param callback callback that is invoked with the result, see IInAppBillingGetAlternativeBillingOnlyDialogIntentCallback.aidl for details\n     */\n    void getAlternativeBillingOnlyDialogIntent(int apiVersion, String packageName, in Bundle extraParams, IInAppBillingGetAlternativeBillingOnlyDialogIntentCallback callback) = 1600;\n\n    /**\n     * @param apiVersion billing API version that the app is using, must be 22 or later\n     * @param packageName package name of the calling app\n     * @param extraParams a Bundle with the following optional keys:\n     *        \"playBillingLibraryVersion\" - String\n     * @param callback callback that is invoked with the result, see IInAppBillingIsExternalPaymentAvailableCallback.aidl for details\n     */\n    void isExternalOfferAvailable(int apiVersion, String packageName, in Bundle extraParams, IInAppBillingIsExternalPaymentAvailableCallback callback) = 1700;\n\n    /**\n     * @param apiVersion billing API version that the app is using, must be 22 or later\n     * @param packageName package name of the calling app\n     * @param extraParams a Bundle with the following optional keys:\n     *        \"playBillingLibraryVersion\" - String\n     * @param callback callback that is invoked with the result, see IInAppBillingCreateExternalPaymentReportingDetailsCallback.aidl for details\n     */\n    void createExternalOfferReportingDetails(int apiVersion, String packageName, in Bundle extraParams, IInAppBillingCreateExternalPaymentReportingDetailsCallback callback) = 1800;\n\n    /**\n     * @param apiVersion billing API version that the app is using, must be 22 or later\n     * @param packageName package name of the calling app\n     * @param extraParams a Bundle with the following optional keys:\n     *        \"playBillingLibraryVersion\" - String\n     * @param callback callback that is invoked with the result, see IInAppBillingGetExternalPaymentDialogIntentCallback.aidl for details\n     */\n    void showExternalOfferInformationDialog(int apiVersion, String packageName, in Bundle extraParams, IInAppBillingGetExternalPaymentDialogIntentCallback callback) = 1900;\n\n    void delegateToBackend(in Bundle bundle, IInAppBillingDelegateToBackendCallback callback) = 2000;\n\n    /**\n     * @param apiVersion billing API version that the app is using, must be 22 or later\n     * @param packageName package name of the calling app\n     * @param extraParams a Bundle with the following optional keys:\n     *        \"callingPackage\" - String\n     *        \"enablePendingPurchases\" - Boolean\n     * @param callback callback that is invoked with the result, see IInAppBillingInitializeCallback.aidl for details\n     */\n    void initialize(int apiVersion, String packageName, in Bundle extraParams, IInAppBillingInitializeCallback callback) = 2100;\n}\n"
  },
  {
    "path": "vending-app/src/main/aidl/com/android/vending/billing/IInAppBillingServiceCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.android.vending.billing;\n\nimport android.os.Bundle;\n\ninterface IInAppBillingServiceCallback {\n    /**\n     * @param bundle a Bundle with the following keys:\n     *        \"KEY_LAUNCH_INTENT\" - PendingIntent\n     */\n    void callback(in Bundle bundle);\n}"
  },
  {
    "path": "vending-app/src/main/aidl/com/android/vending/licensing/ILicenseResultListener.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2010 The Android Open Source Project\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.android.vending.licensing;\n\ninterface ILicenseResultListener {\n    oneway void verifyLicense(int responseCode, String signedData, String signature);\n}"
  },
  {
    "path": "vending-app/src/main/aidl/com/android/vending/licensing/ILicenseV2ResultListener.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2010 The Android Open Source Project\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.android.vending.licensing;\n\ninterface ILicenseV2ResultListener {\n    oneway void verifyLicense(int responseCode, in Bundle responsePayload);\n}"
  },
  {
    "path": "vending-app/src/main/aidl/com/android/vending/licensing/ILicensingService.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2010 The Android Open Source Project\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.android.vending.licensing;\n\nimport com.android.vending.licensing.ILicenseResultListener;\nimport com.android.vending.licensing.ILicenseV2ResultListener;\n\ninterface ILicensingService {\n    oneway void checkLicense(long nonce, String packageName, ILicenseResultListener listener);\n    oneway void checkLicenseV2(String packageName, ILicenseV2ResultListener listener, in Bundle extraParams);\n\n}"
  },
  {
    "path": "vending-app/src/main/aidl/com/google/android/engage/protocol/IAppEngageService.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n package com.google.android.engage.protocol;\n\n import android.os.Bundle;\n import com.google.android.engage.protocol.IAppEngageServicePublishClustersCallback;\n import com.google.android.engage.protocol.IAppEngageServiceDeleteClustersCallback;\n import com.google.android.engage.protocol.IAppEngageServiceAvailableCallback;\n import com.google.android.engage.protocol.IAppEngageServicePublishStatusCallback;\n\n interface IAppEngageService {\n     /**\n      * Publishes clusters of app engagement data.\n      *\n      * @param bundle Contains cluster data to be published\n      * @param callback Callback to receive results of the publish operation\n      */\n     void publishClusters(in Bundle bundle, IAppEngageServicePublishClustersCallback callback);\n\n     /**\n      * Deletes previously published clusters of app engagement data.\n      *\n      * @param bundle Contains specifications about which clusters to delete\n      * @param callback Callback to receive results of the delete operation\n      */\n     void deleteClusters(in Bundle bundle, IAppEngageServiceDeleteClustersCallback callback);\n\n     /**\n      * Checks if the App Engage Service is available for the calling application.\n      *\n      * @param bundle Contains parameters for the availability check\n      * @param callback Callback to receive availability status\n      */\n     void isServiceAvailable(in Bundle bundle, IAppEngageServiceAvailableCallback callback);\n\n     /**\n      * Updates the publishing status for previously published clusters.\n      *\n      * @param bundle Contains status update information\n      * @param callback Callback to receive results of the status update operation\n      */\n     void updatePublishStatus(in Bundle bundle, IAppEngageServicePublishStatusCallback callback);\n }"
  },
  {
    "path": "vending-app/src/main/aidl/com/google/android/engage/protocol/IAppEngageServiceAvailableCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.engage.protocol;\n\nimport android.os.Bundle;\n\n/**\n * Callback interface for isServiceAvailable operation.\n * This callback is used to receive the availability status of the App Engage Service.\n */\ninterface IAppEngageServiceAvailableCallback {\n    /**\n     * Called with the service availability result.\n     *\n     * @param result Bundle containing availability information.\n     *               The key \"availability\" contains a boolean indicating whether the service is available.\n     */\n    void onResult(in Bundle result);\n}"
  },
  {
    "path": "vending-app/src/main/aidl/com/google/android/engage/protocol/IAppEngageServiceDeleteClustersCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.engage.protocol;\n\nimport android.os.Bundle;\n\n/**\n * Callback interface for deleteClusters operation.\n * This callback is used to receive the result of a cluster deletion operation.\n */\ninterface IAppEngageServiceDeleteClustersCallback {\n    /**\n     * Called when the delete operation has completed.\n     *\n     * @param result Bundle containing the result of the delete operation\n     */\n    void onResult(in Bundle result);\n}"
  },
  {
    "path": "vending-app/src/main/aidl/com/google/android/engage/protocol/IAppEngageServicePublishClustersCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n package com.google.android.engage.protocol;\n\n import android.os.Bundle;\n\n /**\n  * Callback interface for publishClusters operation.\n  * This callback is used to receive the result of a cluster publishing operation.\n  */\n interface IAppEngageServicePublishClustersCallback {\n     /**\n      * Called when the publish operation has completed.\n      *\n      * @param result Bundle containing the result of the publish operation\n      */\n     void onResult(in Bundle result);\n }"
  },
  {
    "path": "vending-app/src/main/aidl/com/google/android/engage/protocol/IAppEngageServicePublishStatusCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.engage.protocol;\n\nimport android.os.Bundle;\n\n/**\n * Callback interface for updatePublishStatus operation.\n * This callback is used to receive the result of a status update operation.\n */\ninterface IAppEngageServicePublishStatusCallback {\n    /**\n     * Called when the status update operation has completed.\n     *\n     * @param result Bundle containing the result of the status update operation\n     */\n    void onResult(in Bundle result);\n}"
  },
  {
    "path": "vending-app/src/main/aidl/com/google/android/finsky/externalreferrer/IGetInstallReferrerService.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.finsky.externalreferrer;\n\ninterface IGetInstallReferrerService {\n    Bundle getInstallReferrer(in Bundle request);\n}"
  },
  {
    "path": "vending-app/src/main/aidl/com/google/android/finsky/services/IPlayGearheadService.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.finsky.services;\n\ninterface IPlayGearheadService {\n    Bundle isPackageInstalledByPlayCheck(in String pkgName);\n}"
  },
  {
    "path": "vending-app/src/main/aidl/com/google/android/gms/checkin/internal/ICheckinService.aidl",
    "content": "package com.google.android.gms.checkin.internal;\n\ninterface ICheckinService {\n    String getDeviceDataVersionInfo();\n    long getLastCheckinSuccessTime();\n    String getLastSimOperator();\n}"
  },
  {
    "path": "vending-app/src/main/aidl/com/google/android/play/core/appupdate/protocol/IAppUpdateService.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.play.core.appupdate.protocol;\n\nimport com.google.android.play.core.appupdate.protocol.IAppUpdateServiceCallback;\n\ninterface IAppUpdateService {\n    oneway void requestUpdateInfo(String packageName, in Bundle bundle, in IAppUpdateServiceCallback callback) = 1;\n    oneway void completeUpdate(String packageName, in Bundle bundle, in IAppUpdateServiceCallback callback) = 2;\n    oneway void updateProgress(in Bundle bundle) = 3;\n}"
  },
  {
    "path": "vending-app/src/main/aidl/com/google/android/play/core/appupdate/protocol/IAppUpdateServiceCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.play.core.appupdate.protocol;\n\ninterface IAppUpdateServiceCallback {\n    oneway void onUpdateResult(in Bundle bundle) = 1;\n    oneway void onCompleteResult(in Bundle bundle) = 2;\n}"
  },
  {
    "path": "vending-app/src/main/aidl/com/google/android/play/core/assetpacks/protocol/IAssetModuleService.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.play.core.assetpacks.protocol;\n\nimport com.google.android.play.core.assetpacks.protocol.IAssetModuleServiceCallback;\n\ninterface IAssetModuleService {\n    oneway void startDownload(String packageName, in List<Bundle> list, in Bundle bundle, in IAssetModuleServiceCallback callback) = 1;\n    oneway void getSessionStates(String packageName, in Bundle bundle, in IAssetModuleServiceCallback callback) = 4;\n    oneway void notifyChunkTransferred(String packageName, in Bundle bundle, in Bundle bundle2, in IAssetModuleServiceCallback callback) = 5;\n    oneway void notifyModuleCompleted(String packageName, in Bundle bundle, in Bundle bundle2, in IAssetModuleServiceCallback callback) = 6;\n    oneway void notifySessionFailed(String packageName, in Bundle bundle, in Bundle bundle2, in IAssetModuleServiceCallback callback) = 8;\n    oneway void keepAlive(String packageName, in Bundle bundle, in IAssetModuleServiceCallback callback) = 9;\n    oneway void getChunkFileDescriptor(String packageName, in Bundle bundle, in Bundle bundle2, in IAssetModuleServiceCallback callback) = 10;\n    oneway void requestDownloadInfo(String packageName, in List<Bundle> list, in Bundle bundle, in IAssetModuleServiceCallback callback) = 11;\n    oneway void removeModule(String packageName, in Bundle bundle, in Bundle bundle2, in IAssetModuleServiceCallback callback) = 12;\n    oneway void cancelDownloads(String packageName, in List<Bundle> list, in Bundle bundle, in IAssetModuleServiceCallback callback) = 13;\n}"
  },
  {
    "path": "vending-app/src/main/aidl/com/google/android/play/core/assetpacks/protocol/IAssetModuleServiceCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.play.core.assetpacks.protocol;\n\ninterface IAssetModuleServiceCallback {\n    oneway void onStartDownload(int sessionId, in Bundle bundle) = 1;\n    oneway void onCancelDownload(int status, in Bundle bundle) = 2;\n    oneway void onGetSession(int status, in Bundle bundle) = 3;\n    oneway void onGetSessionStates(in List<Bundle> list) = 4;\n    oneway void onNotifyChunkTransferred(in Bundle bundle, in Bundle bundle2) = 5;\n    oneway void onError(in Bundle bundle) = 6;\n    oneway void onNotifyModuleCompleted(in Bundle bundle, in Bundle bundle2) = 7;\n    oneway void onNotifySessionFailed(in Bundle bundle) = 9;\n    oneway void onKeepAlive(in Bundle bundle, in Bundle bundle2) = 10;\n    oneway void onGetChunkFileDescriptor(in Bundle bundle, in Bundle bundle2) = 11;\n    oneway void onRequestDownloadInfo(in Bundle bundle, in Bundle bundle2) = 12;\n    oneway void onRemoveModule(in Bundle bundle, in Bundle bundle2) = 13;\n    oneway void onCancelDownloads(in Bundle bundle) = 14;\n}"
  },
  {
    "path": "vending-app/src/main/aidl/com/google/android/play/core/inappreview/protocol/IInAppReviewService.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.play.core.inappreview.protocol;\n\nimport com.google.android.play.core.inappreview.protocol.IInAppReviewServiceCallback;\n\ninterface IInAppReviewService {\n    oneway void requestInAppReview(String packageName, in Bundle bundle, in IInAppReviewServiceCallback callback) = 1;\n}"
  },
  {
    "path": "vending-app/src/main/aidl/com/google/android/play/core/inappreview/protocol/IInAppReviewServiceCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.play.core.inappreview.protocol;\n\nimport android.os.Bundle;\n\ninterface IInAppReviewServiceCallback {\n    oneway void onResult(in Bundle bundle) = 1;\n}"
  },
  {
    "path": "vending-app/src/main/aidl/com/google/android/play/core/integrity/protocol/IExpressIntegrityService.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.play.core.integrity.protocol;\n\nimport com.google.android.play.core.integrity.protocol.IExpressIntegrityServiceCallback;\nimport com.google.android.play.core.integrity.protocol.IRequestDialogCallback;\n\ninterface IExpressIntegrityService {\n    void warmUpIntegrityToken(in Bundle bundle, in IExpressIntegrityServiceCallback callback) = 1;\n    void requestExpressIntegrityToken(in Bundle bundle, in IExpressIntegrityServiceCallback callback) = 2;\n    void requestAndShowDialog(in Bundle bundle, in IRequestDialogCallback callback) = 5;\n}"
  },
  {
    "path": "vending-app/src/main/aidl/com/google/android/play/core/integrity/protocol/IExpressIntegrityServiceCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.play.core.integrity.protocol;\n\ninterface IExpressIntegrityServiceCallback {\n    void onWarmUpExpressIntegrityToken(in Bundle bundle) = 1;\n    void onRequestExpressIntegrityToken(in Bundle bundle) = 2;\n    void onRequestIntegrityToken(in Bundle bundle) = 3;\n}\n"
  },
  {
    "path": "vending-app/src/main/aidl/com/google/android/play/core/integrity/protocol/IIntegrityService.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.play.core.integrity.protocol;\n\nimport com.google.android.play.core.integrity.protocol.IIntegrityServiceCallback;\nimport com.google.android.play.core.integrity.protocol.IRequestDialogCallback;\n\ninterface IIntegrityService {\n    void requestDialog(in Bundle bundle, in IRequestDialogCallback callback) = 0;\n    void requestIntegrityToken(in Bundle request, in IIntegrityServiceCallback callback) = 1;\n    void requestAndShowDialog(in Bundle bundle, in IRequestDialogCallback callback) = 2;\n}"
  },
  {
    "path": "vending-app/src/main/aidl/com/google/android/play/core/integrity/protocol/IIntegrityServiceCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.play.core.integrity.protocol;\n\ninterface IIntegrityServiceCallback {\n    void onRequestIntegrityToken(in Bundle bundle) = 1;\n}"
  },
  {
    "path": "vending-app/src/main/aidl/com/google/android/play/core/integrity/protocol/IRequestDialogCallback.aidl",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.play.core.integrity.protocol;\n\ninterface IRequestDialogCallback {\n    void onRequestDialog(in Bundle bundle);\n}"
  },
  {
    "path": "vending-app/src/main/aidl/com/google/android/play/core/splitinstall/protocol/ISplitInstallService.aidl",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.play.core.splitinstall.protocol;\nimport com.google.android.play.core.splitinstall.protocol.ISplitInstallServiceCallback;\n\ninterface ISplitInstallService {\n    void startInstall(String pkg,in List<Bundle> splits,in Bundle bundle, ISplitInstallServiceCallback callback) = 1;\n    void completeInstalls(String pkg, int sessionId,in Bundle bundle, ISplitInstallServiceCallback callback) = 2;\n    void cancelInstall(String pkg, int sessionId, ISplitInstallServiceCallback callback) = 3;\n    void getSessionState(String pkg, int sessionId, ISplitInstallServiceCallback callback) = 4;\n    void getSessionStates(String pkg, ISplitInstallServiceCallback callback) = 5;\n    void splitRemoval(String pkg,in List<Bundle> splits, ISplitInstallServiceCallback callback) = 6;\n    void splitDeferred(String pkg,in List<Bundle> splits,in Bundle bundle, ISplitInstallServiceCallback callback) = 7;\n    void getSessionState2(String pkg, int sessionId, ISplitInstallServiceCallback callback) = 8;\n    void getSessionStates2(String pkg, ISplitInstallServiceCallback callback) = 9;\n    void getSplitsAppUpdate(String pkg, ISplitInstallServiceCallback callback) = 10;\n    void completeInstallAppUpdate(String pkg, ISplitInstallServiceCallback callback) = 11;\n    void languageSplitInstall(String pkg,in List<Bundle> splits,in Bundle bundle, ISplitInstallServiceCallback callback) = 12;\n    void languageSplitUninstall(String pkg,in List<Bundle> splits, ISplitInstallServiceCallback callback) =13;\n}"
  },
  {
    "path": "vending-app/src/main/aidl/com/google/android/play/core/splitinstall/protocol/ISplitInstallServiceCallback.aidl",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.play.core.splitinstall.protocol;\n\n\ninterface ISplitInstallServiceCallback {\n    oneway void onStartInstall(int status, in Bundle bundle) = 1;\n    oneway void onInstallCompleted(int status, in Bundle bundle) = 2;\n    oneway void onCancelInstall(int status, in Bundle bundle) = 3;\n    oneway void onGetSessionState(int status, in Bundle bundle) = 4;\n    oneway void onError(in Bundle bundle) = 5;\n    oneway void onGetSessionStates(in List<Bundle> list) = 6;\n    oneway void onDeferredUninstall(in Bundle bundle) = 7;\n    oneway void onDeferredInstall(in Bundle bundle) = 8;\n    oneway void onDeferredLanguageInstall(in Bundle bundle) = 11;\n    oneway void onDeferredLanguageUninstall(in Bundle bundle) = 12;\n}"
  },
  {
    "path": "vending-app/src/main/java/com/android/billingclient/api/BillingClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n * Notice: Portions of this file are reproduced from work created and shared by Google and used\n *         according to terms described in the Creative Commons 4.0 Attribution License.\n *         See https://developers.google.com/readme/policies for details.\n */\n\npackage com.android.billingclient.api;\n\nimport android.app.Activity;\nimport android.os.Bundle;\nimport androidx.annotation.AnyThread;\nimport androidx.annotation.UiThread;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\n/**\n * Main interface for communication between the library and user application code.\n * <p>\n * It provides convenience methods for in-app billing. You can create one instance of this class for your application and\n * use it to process in-app billing operations. It provides synchronous (blocking) and asynchronous (non-blocking)\n * methods for many common in-app billing operations.\n * <p>\n * It's strongly recommended that you instantiate only one BillingClient instance at one time to avoid multiple\n * {@link PurchasesUpdatedListener#onPurchasesUpdated} callbacks for a single event.\n * <p>\n * All methods annotated with {@link AnyThread} can be called from any thread and all the asynchronous callbacks will be\n * returned on the same thread. Methods annotated with {@link UiThread} should be called from the Ui thread and all the\n * asynchronous callbacks will be returned on the Ui thread as well.\n * <p>\n * After instantiating, you must perform setup in order to start using the object. To perform setup, call the\n * {@link #startConnection} method and provide a listener; that listener will be notified when setup is complete, after which\n * (and not before) you may start calling other methods. After setup is complete, you will typically want to request an\n * inventory of owned items and subscriptions. See {@link #queryPurchasesAsync} and {@link #queryProductDetailsAsync}.\n * <p>\n * When you are done with this object, don't forget to call {@link #endConnection} to ensure proper cleanup. This object holds a\n * binding to the in-app billing service and the manager to handle broadcast events, which will leak unless you dispose it\n * correctly. If you created the object inside the {@link Activity#onCreate(Bundle)}  method, then the recommended place to dispose is\n * the {@link Activity#onDestroy()} method. After cleanup, it cannot be reused again for connection.\n * <p>\n * To get library logs inside Android logcat, set corresponding logging level. E.g.: {@code adb shell setprop\n * log.tag.BillingClient VERBOSE}\n */\npublic abstract class BillingClient {\n\n    /**\n     * Possible response codes.\n     */\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface BillingResponseCode {\n        /**\n         * The request has reached the maximum timeout before Google Play responds.\n         * <p>\n         * Since this state is transient, your app should automatically retry (e.g. with exponential back off) to recover from this\n         * error. Be mindful of how long you retry if the retry is happening during a user interaction.\n         *\n         * @deprecated See {@link #SERVICE_UNAVAILABLE} which will be used instead of this code.\n         */\n        @Deprecated\n        int SERVICE_TIMEOUT = -3;\n        /**\n         * The requested feature is not supported by the Play Store on the current device.\n         * <p>\n         * If your app would like to check if a feature is supported before trying to use the feature your app can call\n         * {@link #isFeatureSupported} to check if a feature is supported. For a list of feature types that can be supported, see\n         * {@link FeatureType}.\n         * <p>\n         * For example: Before calling {@link #showInAppMessages} API, you can call {@link #isFeatureSupported} with the\n         * {@link FeatureType#IN_APP_MESSAGING} featureType to check if it is supported.\n         */\n        int FEATURE_NOT_SUPPORTED = -2;\n\n        /**\n         * The app is not connected to the Play Store service via the Google Play Billing Library.\n         * <p>\n         * Examples where this error may occur:\n         * <ul>\n         * <li>The Play Store could have been updated in the background while your app was still running and the library lost\n         *     connection.</li>\n         * <li>{@link #startConnection} was never called or has not completed yet.</li>\n         * </ul>\n         * Since this state is transient, your app should automatically retry (e.g. with exponential back off) to recover from this\n         * error. Be mindful of how long you retry if the retry is happening during a user interaction. The retry should lead to a\n         * call to {@link #startConnection} right after or in some time after you received this code.\n         */\n        int SERVICE_DISCONNECTED = -1;\n\n        /**\n         * Success.\n         */\n        int OK = 0;\n\n        /**\n         * Transaction was canceled by the user.\n         */\n        int USER_CANCELED = 1;\n\n        /**\n         * The service is currently unavailable.\n         * <p>\n         * Since this state is transient, your app should automatically retry (e.g. with exponential back off) to recover from this\n         * error. Be mindful of how long you retry if the retry is happening during a user interaction.\n         */\n        int SERVICE_UNAVAILABLE = 2;\n\n        /**\n         * A user billing error occurred during processing.\n         * <p>\n         * Examples where this error may occur:\n         * <ul>\n         * <li>The Play Store app on the user's device is out of date.</li>\n         * <li>The user is in an unsupported country.</li>\n         * <li>The user is an enterprise user and their enterprise admin has disabled users from making purchases.</li>\n         * <li>Google Play is unable to charge the user?s payment method.</li>\n         * </ul>\n         * Letting the user retry may succeed if the condition causing the error has changed (e.g. An enterprise user's admin has allowed purchases for the organization).\n         */\n        int BILLING_UNAVAILABLE = 3;\n\n        /**\n         * The requested product is not available for purchase.\n         * <p>\n         * Please ensure the product is available in the user?s country. If you recently changed the country availability and are\n         * still receiving this error then it may be because of a propagation delay.\n         */\n        int ITEM_UNAVAILABLE = 4;\n\n        /**\n         * Error resulting from incorrect usage of the API.\n         * <p>\n         * Examples where this error may occur:\n         * <ul>\n         * <li>Invalid arguments such as providing an empty product list where required.</li>\n         * <li>Misconfiguration of the app such as not signing the app or not having the necessary permissions in the manifest.</li>\n         * </ul>\n         */\n        int DEVELOPER_ERROR = 5;\n\n        /**\n         * Fatal error during the API action.\n         * <p>\n         * This is an internal Google Play error that may be transient or due to an unexpected condition during processing. You\n         * can automatically retry (e.g. with exponential back off) for this case and contact Google Play if issues persist. Be\n         * mindful of how long you retry if the retry is happening during a user interaction.\n         */\n        int ERROR = 6;\n\n        /**\n         * The purchase failed because the item is already owned.\n         * <p>\n         * Make sure your app is up-to-date with recent purchases using guidance in the Fetching purchases section in the\n         * integration guide. If this error occurs despite making the check for recent purchases, then it may be due to stale\n         * purchase information that was cached on the device by Play. When you receive this error, the cache should get\n         * updated. After this, your purchases should be reconciled, and you can process them as outlined in the processing\n         * purchases section in the integration guide.\n         */\n        int ITEM_ALREADY_OWNED = 7;\n\n        /**\n         * Requested action on the item failed since it is not owned by the user.\n         * <p>\n         * Make sure your app is up-to-date with recent purchases using guidance in the Fetching purchases section in the\n         * integration guide. If this error occurs despite making the check for recent purchases, then it may be due to stale\n         * purchase information cached on the device by Play. When you receive this error, the cache should get updated. After\n         * this, your purchases should be reconciled, and you can process the purchases accordingly. For example, if you are\n         * trying to consume an item and if the updated purchase information says it is already consumed, you can ignore the\n         * error now.\n         */\n        int ITEM_NOT_OWNED = 8;\n\n        int EXPIRED_OFFER_TOKEN = 11;\n\n        /**\n         * A network error occurred during the operation.\n         * <p>\n         * This error indicates that there was a problem with the network connection between the device and Play systems. This\n         * could potentially also be due to the user not having an active network connection.\n         */\n        int NETWORK_ERROR = 12;\n\n        int RESPONSE_CODE_UNSPECIFIED = -999;\n    }\n\n    /**\n     * Supported Product types.\n     */\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface ProductType {\n        /**\n         * A Product type for Android apps in-app products.\n         */\n        String INAPP = \"inapp\";\n        /**\n         * A Product type for Android apps subscriptions.\n         */\n        String SUBS = \"subs\";\n    }\n\n    /**\n     * Supported SKU types.\n     * @deprecated Use {@link ProductType} instead.\n     */\n    @Deprecated\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface SkuType {\n        /**\n         * A type of SKU for Android apps in-app products.\n         */\n        String INAPP = ProductType.INAPP;\n        /**\n         * A type of SKU for Android apps subscriptions.\n         */\n        String SUBS = ProductType.SUBS;\n    }\n}\n"
  },
  {
    "path": "vending-app/src/main/java/com/android/billingclient/package-info.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\n/**\n * TODO: Move to own library, as a drop-in to replace com.android.billingclient:billing\n */\npackage com.android.billingclient;"
  },
  {
    "path": "vending-app/src/main/java/com/android/vending/GrantFakeSignaturePermissionActivity.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2016 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.android.vending;\n\nimport android.app.Activity;\nimport android.content.pm.PackageManager;\nimport android.os.Bundle;\nimport androidx.annotation.RequiresApi;\n\n@RequiresApi(23)\npublic class GrantFakeSignaturePermissionActivity extends Activity {\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        if (checkSelfPermission(\"android.permission.FAKE_PACKAGE_SIGNATURE\") != PackageManager.PERMISSION_GRANTED) {\n            requestPermissions(new String[]{\"android.permission.FAKE_PACKAGE_SIGNATURE\"}, 1);\n        } else {\n            setResult(RESULT_OK);\n            finish();\n        }\n    }\n\n    @Override\n    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {\n        if (requestCode == 1 && grantResults.length == 1) {\n            setResult(grantResults[0] == PackageManager.PERMISSION_GRANTED ? RESULT_OK : RESULT_CANCELED);\n            finish();\n        }\n    }\n}\n"
  },
  {
    "path": "vending-app/src/main/java/com/android/vending/VendingPreferences.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023, e Foundation\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.android.vending\n\nimport android.content.Context\nimport org.microg.gms.settings.SettingsContract\n\nobject VendingPreferences {\n    @JvmStatic\n    fun isLicensingEnabled(context: Context): Boolean {\n        val projection = arrayOf(SettingsContract.Vending.LICENSING)\n        return SettingsContract.getSettings(context, SettingsContract.Vending.getContentUri(context), projection) { c ->\n            c.getInt(0) != 0\n        }\n    }\n\n    @JvmStatic\n    fun isLicensingPurchaseFreeAppsEnabled(context: Context): Boolean {\n        val projection = arrayOf(SettingsContract.Vending.LICENSING_PURCHASE_FREE_APPS)\n        return SettingsContract.getSettings(context, SettingsContract.Vending.getContentUri(context), projection) { c ->\n            c.getInt(0) != 0\n        }\n    }\n\n    @JvmStatic\n    fun isSplitInstallEnabled(context: Context): Boolean {\n        val projection = arrayOf(SettingsContract.Vending.SPLIT_INSTALL)\n        return SettingsContract.getSettings(context, SettingsContract.Vending.getContentUri(context), projection) { c ->\n            c.getInt(0) != 0\n        }\n    }\n\n    @JvmStatic\n    fun isBillingEnabled(context: Context): Boolean {\n        val projection = arrayOf(SettingsContract.Vending.BILLING)\n        return SettingsContract.getSettings(context, SettingsContract.Vending.getContentUri(context), projection) { c ->\n            c.getInt(0) != 0\n        }\n    }\n\n    @JvmStatic\n    fun isAssetDeliveryEnabled(context: Context): Boolean {\n        val projection = arrayOf(SettingsContract.Vending.ASSET_DELIVERY)\n        return SettingsContract.getSettings(context, SettingsContract.Vending.getContentUri(context), projection) { c ->\n            c.getInt(0) != 0\n        }\n    }\n\n    @JvmStatic\n    fun isDeviceSyncEnabled(context: Context): Boolean {\n        val projection = arrayOf(SettingsContract.Vending.ASSET_DEVICE_SYNC)\n        return SettingsContract.getSettings(context, SettingsContract.Vending.getContentUri(context), projection) { c ->\n            c.getInt(0) != 0\n        }\n    }\n\n    @JvmStatic\n    fun isInstallEnabled(context: Context): Boolean {\n        val projection = arrayOf(SettingsContract.Vending.APPS_INSTALL)\n        return SettingsContract.getSettings(context, SettingsContract.Vending.getContentUri(context), projection) { c ->\n            c.getInt(0) != 0\n        }\n    }\n\n    @JvmStatic\n    fun getInstallerList(context: Context): String {\n        val projection = arrayOf(SettingsContract.Vending.APPS_INSTALLER_LIST)\n        return SettingsContract.getSettings(context, SettingsContract.Vending.getContentUri(context), projection) { c ->\n            c.getString(0)\n        }\n    }\n\n    @JvmStatic\n    fun setInstallerList(context: Context, content: String) {\n        SettingsContract.setSettings(context, SettingsContract.Vending.getContentUri(context)) {\n            put(SettingsContract.Vending.APPS_INSTALLER_LIST, content)\n        }\n    }\n\n    @JvmStatic\n    fun isDeviceAttestationEnabled(context: Context): Boolean {\n        return SettingsContract.getSettings(context, SettingsContract.SafetyNet.getContentUri(context), SettingsContract.SafetyNet.PROJECTION) { c ->\n            c.getInt(0) != 0\n        }\n    }\n\n    @JvmStatic\n    fun getPlayIntegrityAppList(context: Context): String {\n        val projection = arrayOf(SettingsContract.Vending.PLAY_INTEGRITY_APP_LIST)\n        return SettingsContract.getSettings(context, SettingsContract.Vending.getContentUri(context), projection) { c ->\n            c.getString(0)\n        }\n    }\n\n    @JvmStatic\n    fun setPlayIntegrityAppList(context: Context, content: String) {\n        SettingsContract.setSettings(context, SettingsContract.Vending.getContentUri(context)) {\n            put(SettingsContract.Vending.PLAY_INTEGRITY_APP_LIST, content)\n        }\n    }\n}"
  },
  {
    "path": "vending-app/src/main/java/com/android/vending/billing/InAppBillingService.kt",
    "content": "package com.android.vending.billing\n\nimport android.app.Service\nimport android.content.Intent\nimport android.os.IBinder\nimport androidx.annotation.RequiresApi\nimport org.microg.gms.profile.ProfileManager\nimport org.microg.vending.billing.ContextProvider\nimport org.microg.vending.billing.InAppBillingServiceImpl\n\n@RequiresApi(21)\nclass InAppBillingService: Service() {\n    override fun onCreate() {\n        super.onCreate()\n        ProfileManager.ensureInitialized(this)\n        ContextProvider.init(application)\n    }\n\n    override fun onBind(intent: Intent): IBinder {\n        return InAppBillingServiceImpl(this)\n    }\n\n\n}"
  },
  {
    "path": "vending-app/src/main/java/com/android/vending/licensing/LicenseChecker.kt",
    "content": "package com.android.vending.licensing\n\nimport android.accounts.Account\nimport android.accounts.AccountManager\nimport android.accounts.AuthenticatorException\nimport android.accounts.OperationCanceledException\nimport android.content.pm.PackageInfo\nimport android.os.RemoteException\nimport android.util.Log\nimport com.android.vending.AUTH_TOKEN_SCOPE\nimport com.android.vending.buildRequestHeaders\nimport com.android.vending.getAuthToken\nimport org.microg.vending.billing.core.HttpClient\nimport org.microg.vending.billing.proto.GoogleApiResponse\nimport java.io.IOException\n\nprivate const val TAG = \"FakeLicenseChecker\"\n\n/* Possible response codes for checkLicense v1, from\n * https://developer.android.com/google/play/licensing/licensing-reference#server-response-codes and\n * the LVL library.\n */\n\n/**\n * The application is licensed to the user. The user has purchased the application, or is authorized to\n * download and install the alpha or beta version of the application.\n */\nconst val LICENSED: Int = 0x0\n\n/**\n * The application is not licensed to the user.\n */\nconst val NOT_LICENSED: Int = 0x1\n\n/**\n * The application is licensed to the user, but there is an updated application version available that is\n * signed with a different key.\n */\nconst val LICENSED_OLD_KEY: Int = 0x2\n\n/**\n * Server error — the application (package name) was not recognized by Google Play.\n */\nconst val ERROR_NOT_MARKET_MANAGED: Int = 0x3\n\n/**\n * Server error — the server could not load the application's key pair for licensing.\n */\nconst val ERROR_SERVER_FAILURE: Int = 0x4\nconst val ERROR_OVER_QUOTA: Int = 0x5\n\n/**\n * Local error — the Google Play application was not able to reach the licensing server, possibly because\n * of network availability problems.\n */\nconst val ERROR_CONTACTING_SERVER: Int = 0x101\n\n/**\n * Local error — the application requested a license check for a package that is not installed on the device.\n */\nconst val ERROR_INVALID_PACKAGE_NAME: Int = 0x102\n\n/**\n * Local error — the application requested a license check for a package whose UID (package, user ID pair)\n * does not match that of the requesting application.\n */\nconst val ERROR_NON_MATCHING_UID: Int = 0x103\n\n\nsealed class LicenseRequestParameters\ndata class V1Parameters(\n    val nonce: Long\n) : LicenseRequestParameters()\nobject V2Parameters : LicenseRequestParameters()\n\nsealed class LicenseResponse(\n    val result: Int\n)\nclass V1Response(\n    result: Int,\n    val signedData: String,\n    val signature: String\n) : LicenseResponse(result)\nclass V2Response(\n    result: Int,\n    val jwt: String?\n): LicenseResponse(result)\nclass ErrorResponse(\n    result: Int\n): LicenseResponse(result)\n\n/**\n * Performs license check including caller UID verification, using a given account, for which\n * an auth token is fetched.\n */\n@Throws(RemoteException::class)\nsuspend fun HttpClient.checkLicense(\n    account: Account,\n    accountManager: AccountManager,\n    androidId: String?,\n    packageInfo: PackageInfo,\n    packageName: String,\n    queryData: LicenseRequestParameters\n) : LicenseResponse {\n\n    val auth = try {\n        getAuthToken(accountManager, account, AUTH_TOKEN_SCOPE)\n            .getString(AccountManager.KEY_AUTHTOKEN)\n    } catch (e: AuthenticatorException) {\n        Log.e(TAG, \"Could not fetch auth token for account $account\")\n        return ErrorResponse(ERROR_CONTACTING_SERVER)\n    }\n\n    if (auth == null) {\n        return ErrorResponse(ERROR_CONTACTING_SERVER)\n    }\n\n    val decodedAndroidId = androidId?.toLong(16) ?: 1\n\n    return try {\n        when (queryData) {\n            is V1Parameters -> makeLicenseV1Request(\n                packageName, auth, packageInfo.versionCode, queryData.nonce, decodedAndroidId\n            )\n            is V2Parameters -> makeLicenseV2Request(\n                packageName, auth, packageInfo.versionCode, decodedAndroidId\n            )\n        } ?: ErrorResponse(NOT_LICENSED)\n    } catch (e: IOException) {\n        Log.e(TAG, \"Encountered a network error during operation\", e)\n        ErrorResponse(ERROR_CONTACTING_SERVER)\n    } catch (e: OperationCanceledException) {\n        ErrorResponse(ERROR_CONTACTING_SERVER)\n    }\n}\n\nsuspend fun HttpClient.makeLicenseV1Request(\n    packageName: String, auth: String, versionCode: Int, nonce: Long, androidId: Long\n): V1Response? = get(\n    url = \"https://play-fe.googleapis.com/fdfe/apps/checkLicense?pkgn=$packageName&vc=$versionCode&nnc=$nonce\",\n    headers = buildRequestHeaders(auth, androidId),\n    adapter = GoogleApiResponse.ADAPTER\n).payload?.licenseV1Response?.let {\n    if (it.result != null && it.signedData != null && it.signature != null) {\n        V1Response(it.result, it.signedData, it.signature)\n    } else null\n}\n\nsuspend fun HttpClient.makeLicenseV2Request(\n    packageName: String,\n    auth: String,\n    versionCode: Int,\n    androidId: Long\n): V2Response? = get(\n    url = \"https://play-fe.googleapis.com/fdfe/apps/checkLicenseServerFallback?pkgn=$packageName&vc=$versionCode\",\n    headers = buildRequestHeaders(auth, androidId),\n    adapter = GoogleApiResponse.ADAPTER\n).payload?.licenseV2Response?.license?.jwt?.let {\n    // Field present ←→ user has license\n    V2Response(LICENSED, it)\n}"
  },
  {
    "path": "vending-app/src/main/java/com/android/vending/licensing/LicenseServiceNotification.kt",
    "content": "package com.android.vending.licensing\n\nimport android.Manifest\nimport android.app.NotificationChannel\nimport android.app.NotificationManager\nimport android.content.BroadcastReceiver\nimport android.content.Context\nimport android.content.Intent\nimport android.content.pm.PackageManager\nimport android.os.Build.VERSION.SDK_INT\nimport android.util.Log\nimport androidx.core.app.ActivityCompat\nimport androidx.core.app.NotificationCompat\nimport androidx.core.app.NotificationManagerCompat\nimport androidx.core.app.PendingIntentCompat\nimport com.android.vending.R\nimport java.util.TreeSet\n\n\nprivate const val TAG = \"FakeLicenseNotification\"\nprivate const val GMS_PACKAGE_NAME = \"com.google.android.gms\"\nprivate const val GMS_AUTH_INTENT_ACTION = \"com.google.android.gms.auth.login.LOGIN\"\n\nprivate const val PREFERENCES_KEY_IGNORE_PACKAGES_LIST = \"ignorePackages\"\nprivate const val PREFERENCES_FILE_NAME = \"licensing\"\n\nprivate const val INTENT_KEY_IGNORE_PACKAGE_NAME = \"package\"\nprivate const val INTENT_KEY_NOTIFICATION_ID = \"id\"\n\nprivate const val CHANNEL_ID = \"LicenseNotification\"\n\nfun Context.sendLicenseServiceNotification(\n    callerPackageName: String,\n    callerAppName: CharSequence,\n    callerUid: Int\n) {\n    registerLicenseServiceNotificationChannel()\n\n    val preferences = getSharedPreferences(PREFERENCES_FILE_NAME, Context.MODE_PRIVATE)\n\n    val ignoreList = preferences.getStringSet(PREFERENCES_KEY_IGNORE_PACKAGES_LIST, emptySet())\n    for (ignoredPackage in ignoreList!!) {\n        if (callerPackageName == ignoredPackage) {\n            Log.d(TAG, \"Not notifying about license check, as user has ignored \" +\n                    \"notifications for package $ignoredPackage\"\n            )\n            return\n        }\n    }\n\n    val authIntent = Intent(this, SignInReceiver::class.java).apply {\n        putExtra(INTENT_KEY_NOTIFICATION_ID, callerUid)\n    }.let {\n        PendingIntentCompat.getBroadcast(\n            this, callerUid * 2, it, 0, false\n        )\n    }\n\n    val ignoreIntent = Intent(this, IgnoreReceiver::class.java).apply {\n        putExtra(INTENT_KEY_IGNORE_PACKAGE_NAME, callerPackageName)\n        putExtra(INTENT_KEY_NOTIFICATION_ID, callerUid)\n    }.let {\n        PendingIntentCompat.getBroadcast(\n            this, callerUid * 2 + 1, it, 0, true\n        )\n    }\n\n    val contentText = getString(R.string.license_notification_body)\n    val notification = NotificationCompat.Builder(this, CHANNEL_ID)\n        .setSmallIcon(R.drawable.ic_notification)\n        .setSound(null)\n        .setContentTitle(getString(R.string.license_notification_title, callerAppName))\n        .setContentText(contentText)\n        .setStyle(NotificationCompat.BigTextStyle().bigText(contentText))\n        .addAction(\n            NotificationCompat.Action.Builder(\n                null,\n                getString(R.string.license_notification_sign_in),\n                authIntent\n            ).build()\n        )\n        .addAction(\n            NotificationCompat.Action.Builder(\n                null,\n                getString(R.string.license_notification_ignore),\n                ignoreIntent\n            ).build()\n        )\n        .setAutoCancel(true)\n        .build()\n\n    val notificationManager = NotificationManagerCompat.from(this)\n    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) ==\n        PackageManager.PERMISSION_GRANTED\n    ) {\n        notificationManager.notify(callerUid, notification)\n    }\n}\n\nprivate fun Context.registerLicenseServiceNotificationChannel() {\n    if (SDK_INT >= 26) {\n        val channel = NotificationChannel(\n            CHANNEL_ID,\n            getString(R.string.license_notification_channel_name),\n            NotificationManager.IMPORTANCE_HIGH\n        )\n        channel.description =\n            getString(R.string.license_notification_channel_description)\n        channel.setSound(null, null)\n\n        val notificationManager = getSystemService(\n            NotificationManager::class.java\n        )\n        notificationManager.createNotificationChannel(channel)\n    }\n}\n\nclass IgnoreReceiver : BroadcastReceiver() {\n    override fun onReceive(context: Context, intent: Intent) {\n        // Dismiss ignored notification\n\n        NotificationManagerCompat.from(context)\n            .cancel(intent.getIntExtra(INTENT_KEY_NOTIFICATION_ID, -1))\n\n        val preferences =\n            context.getSharedPreferences(PREFERENCES_FILE_NAME, Context.MODE_PRIVATE)\n\n        val ignoreList: MutableSet<String> = TreeSet(\n            preferences.getStringSet(PREFERENCES_KEY_IGNORE_PACKAGES_LIST, emptySet())\n        )\n\n        val newIgnorePackage = intent.getStringExtra(INTENT_KEY_IGNORE_PACKAGE_NAME)\n        if (newIgnorePackage == null) {\n            Log.e(TAG, \"Received no ignore package; can't add to ignore list.\")\n            return\n        }\n\n        Log.d(TAG, \"Adding package $newIgnorePackage to ignore list\")\n\n        ignoreList.add(newIgnorePackage)\n        preferences.edit()\n            .putStringSet(PREFERENCES_KEY_IGNORE_PACKAGES_LIST, ignoreList)\n            .apply()\n    }\n}\n\nclass SignInReceiver : BroadcastReceiver() {\n    override fun onReceive(context: Context, intent: Intent) {\n\n        // Dismiss all notifications\n        NotificationManagerCompat.from(context).cancelAll()\n\n        Log.d(TAG, \"Starting sign in activity\")\n        Intent(GMS_AUTH_INTENT_ACTION).apply {\n            setPackage(GMS_PACKAGE_NAME)\n            addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)\n        }.let { context.startActivity(it) }\n    }\n}"
  },
  {
    "path": "vending-app/src/main/java/com/android/vending/licensing/LicensingService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.android.vending.licensing\n\nimport android.accounts.Account\nimport android.accounts.AccountManager\nimport android.app.Service\nimport android.content.Intent\nimport android.content.pm.PackageManager\nimport android.net.Uri\nimport android.os.Bundle\nimport android.os.IBinder\nimport android.os.RemoteException\nimport android.util.Log\nimport com.android.vending.VendingPreferences.isLicensingEnabled\nimport com.android.vending.VendingPreferences.isLicensingPurchaseFreeAppsEnabled\nimport kotlinx.coroutines.runBlocking\nimport org.microg.gms.auth.AuthConstants\nimport org.microg.gms.profile.ProfileManager.ensureInitialized\nimport org.microg.vending.billing.acquireFreeAppLicense\nimport org.microg.vending.billing.core.HttpClient\n\nclass LicensingService : Service() {\n    private lateinit var accountManager: AccountManager\n    private lateinit var androidId: String\n    private lateinit var httpClient: HttpClient\n\n    private val mLicenseService: ILicensingService.Stub = object : ILicensingService.Stub() {\n\n        @Throws(RemoteException::class)\n        override fun checkLicense(\n            nonce: Long,\n            packageName: String,\n            listener: ILicenseResultListener\n        ): Unit = runBlocking {\n            Log.v(TAG, \"checkLicense($nonce, $packageName)\")\n\n            val response = checkLicenseCommon(packageName, V1Parameters(nonce))\n\n            /* If a license is found, it is now stored in `lastResponse`. Otherwise, it now contains\n             * an error. In either case, we should send it to the application.\n             */\n            try {\n                when (response) {\n                    is V1Response -> listener.verifyLicense(response.result, response.signedData, response.signature)\n                    is ErrorResponse -> listener.verifyLicense(response.result, null, null)\n                    is V2Response -> Unit // should never happen\n                    null -> Unit // no license check was performed at all\n                }\n            } catch (e: Exception) {\n                Log.w(TAG, \"Remote threw an exception while returning license result ${response}\")\n            }\n        }\n\n        @Throws(RemoteException::class)\n        override fun checkLicenseV2(\n            packageName: String,\n            listener: ILicenseV2ResultListener,\n            extraParams: Bundle\n        ): Unit = runBlocking {\n            Log.v(TAG, \"checkLicenseV2($packageName, $extraParams)\")\n\n            val response = checkLicenseCommon(packageName, V2Parameters)\n\n            /*\n             * Suppress failures on V2. V2 is commonly used by free apps whose checker\n             * will not throw users out of the app if it never receives a response.\n             *\n             * This means that users who are signed in to a Google account will not\n             * get a worse experience in these apps than users that are not signed in.\n             *\n             * Normally, we would otherwise always send the response.\n             */\n            if (response?.result == LICENSED && response is V2Response) {\n                val bundle = Bundle()\n                bundle.putString(KEY_V2_RESULT_JWT, response.jwt)\n\n                try {\n                    listener.verifyLicense(response.result, bundle)\n                } catch (e: Exception) {\n                    Log.w(TAG, \"Remote threw an exception while returning license result ${response}\")\n                }\n            } else {\n                Log.i(TAG, \"Suppressed negative license result for package $packageName\")\n            }\n\n        }\n\n        /**\n         * Checks for license on all accounts.\n         *\n         * @return `null` if no check is performed (for example, because the feature is disabled),\n         * an instance of [LicenseResponse] otherwise.\n         */\n        suspend fun checkLicenseCommon(\n            packageName: String,\n            request: LicenseRequestParameters\n        ): LicenseResponse? {\n            val callingUid = getCallingUid()\n\n            if (!isLicensingEnabled(this@LicensingService)) {\n                Log.d(TAG, \"not checking license, as it is disabled by user\")\n                return null\n            }\n\n            val packageInfo = try {\n                packageManager.getPackageInfo(packageName, 0)\n            } catch (e: PackageManager.NameNotFoundException) {\n                Log.e(TAG,\n                    \"an app tried to request licenses for package $packageName, which does not exist\"\n                )\n                return ErrorResponse(ERROR_INVALID_PACKAGE_NAME)\n            }\n\n            // Verify caller identity\n            if (packageInfo.applicationInfo?.uid != callingUid) {\n                Log.e(\n                    TAG,\n                    \"an app illegally tried to request licenses for another app (caller: $callingUid)\"\n                )\n                return ErrorResponse(ERROR_NON_MATCHING_UID)\n            }\n\n            val accounts = accountManager.getAccountsByType(AuthConstants.DEFAULT_ACCOUNT_TYPE)\n            val packageManager = packageManager\n\n            lateinit var lastResponse: LicenseResponse\n            if (accounts.isEmpty()) {\n                handleNoAccounts(packageName, packageManager)\n                return null\n            } else for (account: Account in accounts) {\n\n                lastResponse = httpClient.checkLicense(\n                    account, accountManager, androidId, packageInfo, packageName, request\n                )\n\n                if (lastResponse.result == LICENSED) {\n                    return lastResponse;\n                }\n            }\n\n            // Attempt to acquire license if app is free (\"auto-purchase\")\n            if (isLicensingPurchaseFreeAppsEnabled(this@LicensingService)) {\n                val firstAccount = accounts[0]\n                if (httpClient.acquireFreeAppLicense(\n                        this@LicensingService,\n                        firstAccount,\n                        packageName\n                    )\n                ) {\n                    lastResponse = httpClient.checkLicense(\n                        firstAccount, accountManager, androidId, packageInfo, packageName, request\n                    )\n                }\n            } else {\n                Log.d(TAG, \"Not auto-purchasing $packageName as it is disabled by the user\")\n            }\n\n            return lastResponse\n        }\n\n        private fun handleNoAccounts(packageName: String, packageManager: PackageManager) {\n            try {\n                Log.e(TAG, \"not checking license, as user is not signed in\")\n\n                packageManager.getPackageInfo(packageName, 0)!!.let {\n                    sendLicenseServiceNotification(\n                        packageName,\n                        packageManager.getApplicationLabel(it.applicationInfo!!),\n                        it.applicationInfo!!.uid\n                    )\n                }\n\n            } catch (e: PackageManager.NameNotFoundException) {\n                Log.e(TAG, \"ignored license request, but package name $packageName was not known!\")\n                // don't send sign in notification\n            } catch (e: NullPointerException) {\n                Log.e(TAG, \"ignored license request, but couldn't get package info for $packageName\")\n            }\n        }\n    }\n\n    override fun onBind(intent: Intent): IBinder {\n\n        ensureInitialized(this)\n\n        contentResolver.query(\n            CHECKIN_SETTINGS_PROVIDER,\n            arrayOf(\"androidId\"),\n            null,\n            null,\n            null\n        ).use { cursor ->\n            if (cursor != null) {\n                cursor.moveToNext()\n                androidId = java.lang.Long.toHexString(cursor.getLong(0))\n            }\n        }\n        accountManager = AccountManager.get(this)\n        httpClient = HttpClient()\n\n        return mLicenseService\n    }\n\n\n    companion object {\n        private const val TAG = \"FakeLicenseService\"\n        private const val KEY_V2_RESULT_JWT = \"LICENSE_DATA\"\n\n        private val CHECKIN_SETTINGS_PROVIDER: Uri =\n            Uri.parse(\"content://com.google.android.gms.microg.settings/check-in\")\n    }\n}\n"
  },
  {
    "path": "vending-app/src/main/java/com/google/android/finsky/externalreferrer/GetInstallReferrerService.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.finsky.externalreferrer;\n\nimport android.app.Service;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.os.IBinder;\nimport android.os.RemoteException;\n\npublic class GetInstallReferrerService extends Service {\n    private static final String TAG = \"FakeReferrerService\";\n\n    private final IGetInstallReferrerService.Stub service = new IGetInstallReferrerService.Stub() {\n        // https://developer.android.com/google/play/installreferrer/igetinstallreferrerservice\n        @Override\n        public Bundle getInstallReferrer(Bundle request) throws RemoteException {\n            Bundle result = new Bundle();\n            result.putString(\"install_referrer\", \"utm_source=google-play&utm_medium=organic\");\n            result.putLong(\"referrer_click_timestamp_seconds\", 0);\n            result.putLong(\"referrer_click_timestamp_server_seconds\", 0);\n            result.putLong(\"install_begin_timestamp_seconds\", 0);\n            result.putLong(\"install_begin_timestamp_server_seconds\", 0);\n            result.putString(\"install_version\", null);\n            result.putBoolean(\"google_play_instant\", false);\n            return result;\n        }\n    };\n\n    @Override\n    public IBinder onBind(Intent intent) {\n        return service.asBinder();\n    }\n}\n"
  },
  {
    "path": "vending-app/src/main/java/com/google/android/play/core/assetpacks/AssetLocation.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.play.core.assetpacks;\n\nimport com.google.android.play.core.assetpacks.model.AssetPackStorageMethod;\n\n/**\n * Location of a single asset, belonging to an asset pack.\n * <p>\n * If the AssetPackStorageMethod for the pack is {@link AssetPackStorageMethod#APK_ASSETS}, this will be the path to the\n * APK containing the asset, the offset of the asset inside the APK and the size of the asset. The asset file will be\n * uncompressed, unless `bundletool` has been explicitly configured to compress the asset pack.\n * <p>\n * If the AssetPackStorageMethod for the pack is {@link AssetPackStorageMethod#STORAGE_FILES}, this will be the path to\n * the specific asset, the offset will be 0 and the size will be the size of the asset file. The asset file will be\n * uncompressed.\n */\npublic abstract class AssetLocation {\n    /**\n     * Returns the file offset where the asset starts, in bytes.\n     */\n    public abstract long offset();\n\n    /**\n     * Returns the path to the file containing the asset.\n     */\n    public abstract String path();\n\n    /**\n     * Returns the size of the asset, in bytes.\n     */\n    public abstract long size();\n}\n"
  },
  {
    "path": "vending-app/src/main/java/com/google/android/play/core/assetpacks/AssetPackException.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.play.core.assetpacks;\n\nimport com.google.android.gms.common.api.ApiException;\nimport com.google.android.gms.common.api.Status;\nimport com.google.android.play.core.assetpacks.model.AssetPackErrorCode;\nimport org.microg.gms.common.Hide;\n\n/**\n * An exception indicating something went wrong with the Asset Delivery API.\n * <p>\n * See {@link #getErrorCode()} for the specific problem.\n */\npublic class AssetPackException extends ApiException {\n    @Hide\n    public AssetPackException(@AssetPackErrorCode int errorCode) {\n        super(new Status(errorCode, \"Asset Pack Download Error(\" + errorCode + \")\"));\n    }\n\n    /**\n     * Returns an error code value from {@link AssetPackErrorCode}.\n     */\n    @AssetPackErrorCode\n    public int getErrorCode() {\n        return super.getStatusCode();\n    }\n\n    /**\n     * Returns the error code resulting from the operation. The value is one of the constants in {@link AssetPackErrorCode}.\n     * getStatusCode() is unsupported by AssetPackException, please use getErrorCode() instead.\n     */\n    @Override\n    public int getStatusCode() {\n        return super.getStatusCode();\n    }\n}\n"
  },
  {
    "path": "vending-app/src/main/java/com/google/android/play/core/assetpacks/AssetPackLocation.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.play.core.assetpacks;\n\nimport androidx.annotation.Nullable;\nimport com.google.android.play.core.assetpacks.model.AssetPackStorageMethod;\n\n/**\n * Location of an asset pack on the device.\n */\npublic abstract class AssetPackLocation {\n    /**\n     * Returns the file path to the folder containing the pack's assets, if the storage method is\n     * {@link AssetPackStorageMethod#STORAGE_FILES}.\n     * <p>\n     * The files found at this path should not be modified.\n     * <p>\n     * If the storage method is {@link AssetPackStorageMethod#APK_ASSETS}, this method will return {@code null}. To access assets\n     * from packs installed as APKs, use Asset Manager.\n     */\n    @Nullable\n    public abstract String assetsPath();\n\n    /**\n     * Returns whether the pack is installed as an APK or extracted into a folder on the filesystem.\n     *\n     * @return a value from {@link AssetPackStorageMethod}\n     */\n    @AssetPackStorageMethod\n    public abstract int packStorageMethod();\n\n    /**\n     * Returns the file path to the folder containing the extracted asset pack, if the storage method is\n     * {@link AssetPackStorageMethod#STORAGE_FILES}.\n     * <p>\n     * The files found at this path should not be modified.\n     * <p>\n     * If the storage method is {@link AssetPackStorageMethod#APK_ASSETS}, this method will return {@code null}. To access assets\n     * from packs installed as APKs, use Asset Manager.\n     */\n    @Nullable\n    public abstract String path();\n}\n"
  },
  {
    "path": "vending-app/src/main/java/com/google/android/play/core/assetpacks/AssetPackManager.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.play.core.assetpacks;\n\nimport android.app.Activity;\n\nimport androidx.activity.result.ActivityResultLauncher;\nimport androidx.activity.result.IntentSenderRequest;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.google.android.gms.tasks.Task;\nimport com.google.android.play.core.assetpacks.model.AssetPackStatus;\n\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * Manages downloads of asset packs.\n */\npublic interface AssetPackManager {\n\n    /**\n     * Requests to cancel the download of the specified asset packs.\n     * <p>\n     * Note: Only active downloads can be canceled.\n     *\n     * @return The new state for all specified packs.\n     */\n    AssetPackStates cancel(@NonNull List<String> packNames);\n\n    /**\n     * Unregisters all listeners previously added using {@link #registerListener}.\n     */\n    void clearListeners();\n\n    /**\n     * Requests to download the specified asset packs.\n     * <p>\n     * This method will fail if the app is not in the foreground.\n     *\n     * @return the state of all specified pack names\n     */\n    Task<AssetPackStates> fetch(List<String> packNames);\n\n    /**\n     * [advanced API] Returns the location of an asset in a pack, or {@code null} if the asset is not present in the given pack.\n     * <p>\n     * You don't need to use this API for common use-cases: you can use the standard File API for accessing assets from\n     * asset packs that were extracted into the filesystem; and you can use Android's AssetManager API to access assets\n     * from packs that were installed as APKs.\n     * <p>\n     * This API is useful for game engines that don't use Asset Manager and for developers that want a unified method to\n     * access assets, independently from the delivery mode.\n     */\n    @Nullable\n    AssetLocation getAssetLocation(@NonNull String packName, @NonNull String assetPath);\n\n    /**\n     * Returns the location of the specified asset pack on the device or {@code null} if this pack is not downloaded.\n     * <p>\n     * The files found at this path should not be modified.\n     */\n    @Nullable\n    AssetPackLocation getPackLocation(@NonNull String packName);\n\n    /**\n     * Returns the location of all installed asset packs as a mapping from the asset pack name to an {@link AssetPackLocation}.\n     * <p>\n     * The files found at these paths should not be modified.\n     */\n    Map<String, AssetPackLocation> getPackLocations();\n\n    /**\n     * Requests download state or details for the specified asset packs.\n     * <p>\n     * Do not use this method to determine whether an asset pack is downloaded. Instead use {@link #getPackLocation}.\n     */\n    Task<AssetPackStates> getPackStates(List<String> packNames);\n\n    /**\n     * Registers a listener that will be notified of changes to the state of pack downloads for this app. Listeners should be\n     * subsequently unregistered using {@link #unregisterListener}.\n     */\n    void registerListener(@NonNull AssetPackStateUpdateListener listener);\n\n    /**\n     * Deletes the specified asset pack from the internal storage of the app.\n     * <p>\n     * Use this method to delete asset packs instead of deleting files manually. This ensures that the Asset Pack will not be\n     * re-downloaded during an app update.\n     * <p>\n     * If the asset pack is currently being downloaded or installed, this method does not cancel the process. For this case,\n     * use {@link #cancel} instead.\n     *\n     * @return A task that will be successful only if files were successfully deleted.\n     */\n\n    Task<Void> removePack(@NonNull String packName);\n\n    /**\n     * Shows a confirmation dialog to resume all pack downloads that are currently in the\n     * {@link AssetPackStatus#WAITING_FOR_WIFI} state. If the user accepts the dialog, packs are downloaded over cellular data.\n     * <p>\n     * The status of an asset pack is set to {@link AssetPackStatus#WAITING_FOR_WIFI} if the user is currently not on a Wi-Fi\n     * connection and the asset pack is large or the user has set their download preference in the Play Store to only\n     * download apps over Wi-Fi. By showing this dialog, your app can ask the user if they accept downloading the asset\n     * pack over cellular data instead of waiting for Wi-Fi.\n     * <p>\n     * The confirmation activity returns one of the following values:\n     * <ul>\n     *   <li>{@link Activity#RESULT_OK Activity#RESULT_OK} if the user accepted.\n     *   <li>{@link Activity#RESULT_CANCELED Activity#RESULT_CANCELED} if the user denied or the dialog has been closed in any other way (e.g.\n     *   backpress).\n     * </ul>\n     *\n     * @param activityResultLauncher an activityResultLauncher to launch the confirmation dialog.\n     * @return whether the confirmation dialog has been started.\n     * @deprecated This API has been deprecated in favor of {@link #showConfirmationDialog(ActivityResultLauncher)}.\n     */\n    @Deprecated\n    boolean showCellularDataConfirmation(@NonNull ActivityResultLauncher<IntentSenderRequest> activityResultLauncher);\n\n    /**\n     * Shows a confirmation dialog to resume all pack downloads that are currently in the\n     * {@link AssetPackStatus#WAITING_FOR_WIFI} state. If the user accepts the dialog, packs are downloaded over cellular data.\n     * <p>\n     * The status of an asset pack is set to {@link AssetPackStatus#WAITING_FOR_WIFI} if the user is currently not on a Wi-Fi\n     * connection and the asset pack is large or the user has set their download preference in the Play Store to only\n     * download apps over Wi-Fi. By showing this dialog, your app can ask the user if they accept downloading the asset\n     * pack over cellular data instead of waiting for Wi-Fi.\n     *\n     * @param activity the activity on top of which the confirmation dialog is displayed. Use your current\n     *                 activity for this.\n     * @return A {@link Task} that completes once the dialog has been accepted, denied or closed. A successful task\n     * result contains one of the following values:\n     * <ul>\n     *   <li>{@link Activity#RESULT_OK Activity#RESULT_OK} if the user accepted.\n     *   <li>{@link Activity#RESULT_CANCELED Activity#RESULT_CANCELED} if the user denied or the dialog has been closed in any other way (e.g.\n     *   backpress).\n     * </ul>\n     * @deprecated This API has been deprecated in favor of {@link #showConfirmationDialog(Activity)}.\n     */\n    @Deprecated\n    Task<Integer> showCellularDataConfirmation(@NonNull Activity activity);\n\n    /**\n     * Shows a dialog that asks the user for consent to download packs that are currently in either the\n     * {@link AssetPackStatus#REQUIRES_USER_CONFIRMATION} state or the {@link AssetPackStatus#WAITING_FOR_WIFI} state.\n     * <p>\n     * If the app has not been installed by Play, an update may be triggered to ensure that a valid version is installed. This\n     * will cause the app to restart and all asset requests to be cancelled. These assets should be requested again after the\n     * app restarts.\n     * <p>\n     * The confirmation activity returns one of the following values:\n     * <ul>\n     *   <li>{@link Activity#RESULT_OK Activity#RESULT_OK} if the user accepted.\n     *   <li>{@link Activity#RESULT_CANCELED Activity#RESULT_CANCELED} if the user denied or the dialog has been closed in any other way (e.g.\n     *   backpress).\n     * </ul>\n     *\n     * @param activityResultLauncher an activityResultLauncher to launch the confirmation dialog.\n     * @return whether the confirmation dialog has been started.\n     */\n    boolean showConfirmationDialog(@NonNull ActivityResultLauncher<IntentSenderRequest> activityResultLauncher);\n\n    /**\n     * Shows a dialog that asks the user for consent to download packs that are currently in either the\n     * {@link AssetPackStatus#REQUIRES_USER_CONFIRMATION} state or the {@link AssetPackStatus#WAITING_FOR_WIFI} state.\n     * <p>\n     * If the app has not been installed by Play, an update may be triggered to ensure that a valid version is installed. This\n     * will cause the app to restart and all asset requests to be cancelled. These assets should be requested again after the\n     * app restarts.\n     *\n     * @param activity the activity on top of which the confirmation dialog is displayed. Use your current\n     *                 activity for this.\n     * @return A {@link Task} that completes once the dialog has been accepted, denied or closed. A successful task\n     * result contains one of the following values:\n     * <ul>\n     *   <li>{@link Activity#RESULT_OK Activity#RESULT_OK} if the user accepted.\n     *   <li>{@link Activity#RESULT_CANCELED Activity#RESULT_CANCELED} if the user denied or the dialog has been closed in any other way (e.g.\n     *   backpress).\n     * </ul>\n     */\n    Task<Integer> showConfirmationDialog(@NonNull Activity activity);\n\n    /**\n     * Unregisters a listener previously added using {@link #registerListener}.\n     */\n    void unregisterListener(@NonNull AssetPackStateUpdateListener listener);\n}\n"
  },
  {
    "path": "vending-app/src/main/java/com/google/android/play/core/assetpacks/AssetPackManagerFactory.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.play.core.assetpacks;\n\nimport android.content.Context;\nimport androidx.annotation.NonNull;\n\n/**\n * Creates instances of {@link AssetPackManager}.\n */\npublic final class AssetPackManagerFactory {\n    private AssetPackManagerFactory() {\n    }\n\n    /**\n     * Creates an instance of {@link AssetPackManager}.\n     *\n     * @param applicationContext a fully initialized application context\n     */\n    @NonNull\n    public static AssetPackManager getInstance(Context applicationContext) {\n        return new AssetPackManagerImpl();\n    }\n}\n"
  },
  {
    "path": "vending-app/src/main/java/com/google/android/play/core/assetpacks/AssetPackManagerImpl.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.play.core.assetpacks;\n\nimport android.app.Activity;\nimport androidx.activity.result.ActivityResultLauncher;\nimport androidx.activity.result.IntentSenderRequest;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.tasks.Task;\nimport com.google.android.play.core.assetpacks.model.AssetPackStatus;\nimport org.microg.gms.common.Hide;\n\nimport java.util.List;\nimport java.util.Map;\n\n@Hide\npublic class AssetPackManagerImpl implements AssetPackManager {\n    @Override\n    public AssetPackStates cancel(@NonNull List<String> packNames) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void clearListeners() {\n    }\n\n    @Override\n    public Task<AssetPackStates> fetch(List<String> packNames) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Nullable\n    @Override\n    public AssetLocation getAssetLocation(@NonNull String packName, @NonNull String assetPath) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Nullable\n    @Override\n    public AssetPackLocation getPackLocation(@NonNull String packName) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public Map<String, AssetPackLocation> getPackLocations() {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public Task<AssetPackStates> getPackStates(List<String> packNames) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void registerListener(@NonNull AssetPackStateUpdateListener listener) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public Task<Void> removePack(@NonNull String packName) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public boolean showCellularDataConfirmation(@NonNull ActivityResultLauncher<IntentSenderRequest> activityResultLauncher) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public Task<Integer> showCellularDataConfirmation(@NonNull Activity activity) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public boolean showConfirmationDialog(@NonNull ActivityResultLauncher<IntentSenderRequest> activityResultLauncher) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public Task<Integer> showConfirmationDialog(@NonNull Activity activity) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void unregisterListener(@NonNull AssetPackStateUpdateListener listener) {\n\n    }\n\n    public @AssetPackStatus int getLocalStatus(String packName, int remoteStatus) {\n        throw new UnsupportedOperationException();\n    }\n\n    public int getTransferProgressPercentage(String packName) {\n        throw new UnsupportedOperationException();\n    }\n\n    public String getInstalledVersionTag(String packName) {\n        throw new UnsupportedOperationException();\n    }\n}\n"
  },
  {
    "path": "vending-app/src/main/java/com/google/android/play/core/assetpacks/AssetPackServiceClient.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.play.core.assetpacks;\n\nimport android.content.Context;\nimport android.os.Bundle;\nimport android.os.ParcelFileDescriptor;\nimport android.os.RemoteException;\nimport android.util.Log;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.tasks.Task;\nimport com.google.android.gms.tasks.TaskCompletionSource;\nimport com.google.android.play.core.assetpacks.model.AssetPackErrorCode;\nimport com.google.android.play.core.assetpacks.model.AssetPackStatus;\nimport com.google.android.play.core.assetpacks.protocol.*;\nimport org.microg.gms.common.Hide;\n\nimport java.util.*;\n\n@Hide\npublic class AssetPackServiceClient {\n    private static final String TAG = \"AssetPackServiceClient\";\n    private List<TaskCompletionSource<?>> pendingCalls = new ArrayList<>();\n    private Context context;\n    private AssetPackManagerImpl assetPackManager;\n\n    private interface PendingCall<TResult> {\n        void execute(IAssetModuleService service, TaskCompletionSource<TResult> completionSource) throws Exception;\n    }\n\n    private <TResult> Task<TResult> execute(PendingCall<TResult> pendingCall) {\n        TaskCompletionSource<TResult> completionSource = new TaskCompletionSource<>();\n        pendingCalls.add(completionSource);\n        try {\n            pendingCall.execute(null, completionSource);\n        } catch (Exception e) {\n            completionSource.trySetException(e);\n        }\n        Task<TResult> task = completionSource.getTask();\n        task.addOnCompleteListener(ignored -> pendingCalls.remove(completionSource));\n        return task;\n    }\n\n    private Bundle getOptionsBundle() {\n        Bundle options = new Bundle();\n        // TODO\n        BundleKeys.put(options, BundleKeys.PLAY_CORE_VERSION_CODE, 20202);\n        BundleKeys.put(options, BundleKeys.SUPPORTED_COMPRESSION_FORMATS, new ArrayList<>(Arrays.asList(CompressionFormat.UNSPECIFIED, CompressionFormat.BROTLI)));\n        BundleKeys.put(options, BundleKeys.SUPPORTED_PATCH_FORMATS, new ArrayList<>(Arrays.asList(PatchFormat.PATCH_GDIFF, PatchFormat.GZIPPED_GDIFF)));\n        return options;\n    }\n\n    private ArrayList<Bundle> getModuleNameBundles(List<String> packNames) {\n        ArrayList<Bundle> moduleNameBundles = new ArrayList<>();\n        for (String packName : packNames) {\n            Bundle arg = new Bundle();\n            BundleKeys.put(arg, BundleKeys.MODULE_NAME, packName);\n            moduleNameBundles.add(arg);\n        }\n        return moduleNameBundles;\n    }\n\n    private Bundle getInstalledAssetModulesBundle(Map<String, Long> installedAssetModules) {\n        Bundle installedAssetModulesBundle = getOptionsBundle();\n        ArrayList<Bundle> installedAssetModuleBundles = new ArrayList<>();\n        for (String moduleName : installedAssetModules.keySet()) {\n            Bundle installedAssetModuleBundle = new Bundle();\n            BundleKeys.put(installedAssetModuleBundle, BundleKeys.INSTALLED_ASSET_MODULE_NAME, moduleName);\n            BundleKeys.put(installedAssetModuleBundle, BundleKeys.INSTALLED_ASSET_MODULE_VERSION, installedAssetModules.get(moduleName));\n            installedAssetModuleBundles.add(installedAssetModuleBundle);\n        }\n        BundleKeys.put(installedAssetModulesBundle, BundleKeys.INSTALLED_ASSET_MODULE, installedAssetModuleBundles);\n        return installedAssetModulesBundle;\n    }\n\n    private Bundle getSessionIdentifierBundle(int sessionId) {\n        Bundle sessionIdentifierBundle = new Bundle();\n        BundleKeys.put(sessionIdentifierBundle, BundleKeys.SESSION_ID, sessionId);\n        return sessionIdentifierBundle;\n    }\n\n    private Bundle getModuleIdentifierBundle(int sessionId, String moduleName) {\n        Bundle moduleIdentifierBundle = getSessionIdentifierBundle(sessionId);\n        BundleKeys.put(moduleIdentifierBundle, BundleKeys.MODULE_NAME, moduleName);\n        return moduleIdentifierBundle;\n    }\n\n    private Bundle getChunkIdentifierBundle(int sessionId, String moduleName, String sliceId, int chunkNumber) {\n        Bundle chunkIdentifierBundle = getModuleIdentifierBundle(sessionId, moduleName);\n        BundleKeys.put(chunkIdentifierBundle, BundleKeys.SLICE_ID, sliceId);\n        BundleKeys.put(chunkIdentifierBundle, BundleKeys.CHUNK_NUMBER, chunkNumber);\n        return chunkIdentifierBundle;\n    }\n\n    public Task<ParcelFileDescriptor> getChunkFileDescriptor(int sessionId, String moduleName, String sliceId, int chunkNumber) {\n        return execute((service, completionSource) -> {\n            service.getChunkFileDescriptor(context.getPackageName(), getChunkIdentifierBundle(sessionId, moduleName, sliceId, chunkNumber), getOptionsBundle(), new BaseCallback(completionSource) {\n                @Override\n                public void onGetChunkFileDescriptor(ParcelFileDescriptor chunkFileDescriptor) {\n                    completionSource.trySetResult(chunkFileDescriptor);\n                }\n            });\n        });\n    }\n\n    public Task<AssetPackStates> getPackStates(List<String> packNames, Map<String, Long> installedAssetModules) {\n        return execute((service, completionSource) -> {\n            service.requestDownloadInfo(context.getPackageName(), getModuleNameBundles(packNames), getInstalledAssetModulesBundle(installedAssetModules), new BaseCallback(completionSource) {\n                @Override\n                public void onRequestDownloadInfo(Bundle bundle, Bundle bundle2) {\n                    completionSource.trySetResult(AssetPackStatesImpl.fromBundle(bundle, assetPackManager));\n                }\n            });\n        });\n    }\n\n    public Task<AssetPackStates> startDownload(List<String> packNames, Map<String, Long> installedAssetModules) {\n        Task<AssetPackStates> task = execute((service, completionSource) -> {\n            service.startDownload(context.getPackageName(), getModuleNameBundles(packNames), getInstalledAssetModulesBundle(installedAssetModules), new BaseCallback(completionSource) {\n                @Override\n                public void onStartDownload(int status, Bundle bundle) {\n                    completionSource.trySetResult(AssetPackStatesImpl.fromBundle(bundle, assetPackManager, true));\n                }\n            });\n        });\n        task.addOnSuccessListener(ignored -> keepAlive());\n        return task;\n    }\n\n    public Task<List<String>> syncPacks(Map<String, Long> installedAssetModules) {\n        return execute((service, completionSource) -> {\n            service.getSessionStates(context.getPackageName(), getInstalledAssetModulesBundle(installedAssetModules), new BaseCallback(completionSource) {\n                @Override\n                public void onGetSessionStates(List<Bundle> list) {\n                    ArrayList<String> packNames = new ArrayList<>();\n                    for (Bundle bundle : list) {\n                        Collection<AssetPackState> packStates = AssetPackStatesImpl.fromBundle(bundle, assetPackManager, true).packStates().values();\n                        if (!packStates.isEmpty()) {\n                            AssetPackState state = packStates.iterator().next();\n                            switch (state.status()) {\n                                case AssetPackStatus.PENDING:\n                                case AssetPackStatus.DOWNLOADING:\n                                case AssetPackStatus.TRANSFERRING:\n                                case AssetPackStatus.WAITING_FOR_WIFI:\n                                case AssetPackStatus.REQUIRES_USER_CONFIRMATION:\n                                    packNames.add(state.name());\n                            }\n                        }\n                    }\n                    completionSource.trySetResult(packNames);\n                }\n            });\n        });\n    }\n\n    public void cancelDownloads(List<String> packNames) {\n        execute((service, completionSource) -> {\n            service.cancelDownloads(context.getPackageName(), getModuleNameBundles(packNames), getOptionsBundle(), new BaseCallback(completionSource) {\n                @Override\n                public void onCancelDownloads() {\n                    completionSource.trySetResult(null);\n                }\n            });\n        });\n    }\n\n    public void keepAlive() {\n        // TODO\n    }\n\n    public void notifyChunkTransferred(int sessionId, String moduleName, String sliceId, int chunkNumber) {\n        execute((service, completionSource) -> {\n            service.notifyChunkTransferred(context.getPackageName(), getChunkIdentifierBundle(sessionId, moduleName, sliceId, chunkNumber), getOptionsBundle(), new BaseCallback(completionSource) {\n                @Override\n                public void onNotifyChunkTransferred(int sessionId, String moduleName, String sliceId, int chunkNumber) {\n                    completionSource.trySetResult(null);\n                }\n            });\n        });\n    }\n\n    public void notifyModuleCompleted(int sessionId, String moduleName) {\n        notifyModuleCompleted(sessionId, moduleName, 10);\n    }\n\n    public void notifyModuleCompleted(int sessionId, String moduleName, int maxRetries) {\n        execute((service, completionSource) -> {\n            service.notifyModuleCompleted(context.getPackageName(), getModuleIdentifierBundle(sessionId, moduleName), getOptionsBundle(), new BaseCallback(completionSource) {\n                @Override\n                public void onError(int errorCode) {\n                    if (maxRetries > 0) {\n                        notifyModuleCompleted(sessionId, moduleName, maxRetries - 1);\n                    }\n                }\n            });\n        });\n    }\n\n    public void notifySessionFailed(int sessionId) {\n        execute((service, completionSource) -> {\n            service.notifySessionFailed(context.getPackageName(), getSessionIdentifierBundle(sessionId), getOptionsBundle(), new BaseCallback(completionSource) {\n                @Override\n                public void onNotifySessionFailed(int sessionId) {\n                    completionSource.trySetResult(null);\n                }\n            });\n        });\n    }\n\n    public void removePack(String packName) {\n        execute((service, completionSource) -> {\n            service.removeModule(context.getPackageName(), getModuleIdentifierBundle(0, packName), getOptionsBundle(), new BaseCallback(completionSource) {\n                @Override\n                public void onRemoveModule() {\n                    completionSource.trySetResult(null);\n                }\n            });\n        });\n    }\n\n    private static class BaseCallback extends IAssetModuleServiceCallback.Stub {\n        @NonNull\n        private final TaskCompletionSource<?> completionSource;\n\n        public BaseCallback(@NonNull TaskCompletionSource<?> completionSource) {\n            this.completionSource = completionSource;\n        }\n\n        @Override\n        public void onStartDownload(int sessionId, Bundle bundle) {\n            Log.i(TAG, \"onStartDownload(\" + sessionId + \")\");\n            onStartDownload(sessionId);\n        }\n\n        public void onStartDownload(int sessionId) {\n            completionSource.trySetException(new Exception(\"Unexpected callback: onStartDownload\"));\n        }\n\n        @Override\n        public void onCancelDownload(int status, Bundle bundle) {\n            Log.i(TAG, \"onCancelDownload(\" + status + \")\");\n            onCancelDownload(status);\n        }\n\n        public void onCancelDownload(int status) {\n            completionSource.trySetException(new Exception(\"Unexpected callback: onCancelDownload\"));\n        }\n\n        @Override\n        public void onGetSession(int status, Bundle bundle) {\n            Log.i(TAG, \"onGetSession(\" + status + \")\");\n            onGetSession(status);\n        }\n\n        public void onGetSession(int status) {\n            completionSource.trySetException(new Exception(\"Unexpected callback: onGetSession\"));\n        }\n\n        @Override\n        public void onGetSessionStates(List<Bundle> list) {\n            completionSource.trySetException(new Exception(\"Unexpected callback: onGetSessionStates\"));\n        }\n\n        @Override\n        public void onNotifyChunkTransferred(Bundle bundle, Bundle bundle2) {\n            int sessionId = BundleKeys.get(bundle, BundleKeys.SESSION_ID, 0);\n            String moduleName = BundleKeys.get(bundle, BundleKeys.MODULE_NAME);\n            String sliceId = BundleKeys.get(bundle, BundleKeys.SLICE_ID);\n            int chunkNumber = BundleKeys.get(bundle, BundleKeys.CHUNK_NUMBER, 0);\n            Log.i(TAG, \"onNotifyChunkTransferred(\" + sessionId + \", \" + moduleName + \", \" + sliceId + \", \" + chunkNumber + \")\");\n            onNotifyChunkTransferred(sessionId, moduleName, sliceId, chunkNumber);\n        }\n\n        public void onNotifyChunkTransferred(int sessionId, String moduleName, String sliceId, int chunkNumber) {\n            completionSource.trySetException(new Exception(\"Unexpected callback: onNotifyChunkTransferred\"));\n        }\n\n        @Override\n        public void onError(Bundle bundle) {\n            int errorCode = BundleKeys.get(bundle, BundleKeys.ERROR_CODE, AssetPackErrorCode.INTERNAL_ERROR);\n            onError(errorCode);\n        }\n\n        public void onError(int errorCode) {\n            completionSource.trySetException(new AssetPackException(errorCode));\n        }\n\n        @Override\n        public void onNotifyModuleCompleted(Bundle bundle, Bundle bundle2) {\n            int sessionId = BundleKeys.get(bundle, BundleKeys.SESSION_ID, 0);\n            String moduleName = BundleKeys.get(bundle, BundleKeys.MODULE_NAME);\n            Log.i(TAG, \"onNotifyModuleCompleted(\" + sessionId + \", \" + moduleName + \")\");\n            onNotifyModuleCompleted(sessionId, moduleName);\n        }\n\n        public void onNotifyModuleCompleted(int sessionId, String moduleName) {\n            completionSource.trySetException(new Exception(\"Unexpected callback: onNotifyModuleCompleted\"));\n        }\n\n        @Override\n        public void onNotifySessionFailed(Bundle bundle) {\n            int sessionId = BundleKeys.get(bundle, BundleKeys.SESSION_ID, 0);\n            Log.i(TAG, \"onNotifySessionFailed(\" + sessionId + \")\");\n            onNotifySessionFailed(sessionId);\n        }\n\n        public void onNotifySessionFailed(int sessionId) {\n            completionSource.trySetException(new Exception(\"Unexpected callback: onNotifySessionFailed\"));\n        }\n\n        @Override\n        public void onKeepAlive(Bundle bundle, Bundle bundle2) {\n            boolean keepAlive = BundleKeys.get(bundle, BundleKeys.KEEP_ALIVE, false);\n            Log.i(TAG, \"onKeepAlive(\" + keepAlive + \")\");\n            onKeepAlive(keepAlive);\n        }\n\n        public void onKeepAlive(boolean keepAlive) {\n            completionSource.trySetException(new Exception(\"Unexpected callback: onKeepAlive\"));\n        }\n\n        @Override\n        public void onGetChunkFileDescriptor(Bundle bundle, Bundle bundle2) {\n            ParcelFileDescriptor chunkFileDescriptor = BundleKeys.get(bundle, BundleKeys.CHUNK_FILE_DESCRIPTOR);\n            Log.i(TAG, \"onGetChunkFileDescriptor(...)\");\n            onGetChunkFileDescriptor(chunkFileDescriptor);\n        }\n\n        public void onGetChunkFileDescriptor(ParcelFileDescriptor chunkFileDescriptor) {\n            completionSource.trySetException(new Exception(\"Unexpected callback: onGetChunkFileDescriptor\"));\n        }\n\n        @Override\n        public void onRequestDownloadInfo(Bundle bundle, Bundle bundle2) {\n            Log.i(TAG, \"onRequestDownloadInfo()\");\n            onRequestDownloadInfo();\n        }\n\n        public void onRequestDownloadInfo() {\n            completionSource.trySetException(new Exception(\"Unexpected callback: onRequestDownloadInfo\"));\n        }\n\n        @Override\n        public void onRemoveModule(Bundle bundle, Bundle bundle2) {\n            Log.i(TAG, \"onRemoveModule()\");\n            onRemoveModule();\n        }\n\n        public void onRemoveModule() {\n            completionSource.trySetException(new Exception(\"Unexpected callback: onRemoveModule\"));\n        }\n\n        @Override\n        public void onCancelDownloads(Bundle bundle) {\n            Log.i(TAG, \"onCancelDownload()\");\n            onCancelDownloads();\n        }\n\n        public void onCancelDownloads() {\n            completionSource.trySetException(new Exception(\"Unexpected callback: onCancelDownloads\"));\n        }\n    }\n}\n"
  },
  {
    "path": "vending-app/src/main/java/com/google/android/play/core/assetpacks/AssetPackState.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.play.core.assetpacks;\n\nimport com.google.android.play.core.assetpacks.model.AssetPackErrorCode;\nimport com.google.android.play.core.assetpacks.model.AssetPackStatus;\nimport com.google.android.play.core.assetpacks.model.AssetPackUpdateAvailability;\n\n/**\n * The state of an individual asset pack.\n */\npublic abstract class AssetPackState {\n    public abstract String availableVersionTag();\n\n    /**\n     * Returns the total number of bytes already downloaded for the pack.\n     */\n    public abstract long bytesDownloaded();\n\n    /**\n     * Returns the error code for the pack, if Play has failed to download the pack. Returns\n     * {@link AssetPackErrorCode#NO_ERROR} if the download was successful or is in progress or has not been attempted.\n     *\n     * @return A value from {@link AssetPackErrorCode}.\n     */\n    @AssetPackErrorCode\n    public abstract int errorCode();\n\n    public abstract String installedVersionTag();\n\n    /**\n     * Returns the name of the pack.\n     */\n    public abstract String name();\n\n    /**\n     * Returns the download status of the pack.\n     * <p>\n     * If the pack has never been requested before its status is {@link AssetPackStatus#UNKNOWN}.\n     *\n     * @return a value from {@link AssetPackStatus}\n     */\n    @AssetPackStatus\n    public abstract int status();\n\n    /**\n     * Returns the total size of the pack in bytes.\n     */\n    public abstract long totalBytesToDownload();\n\n    /**\n     * Returns the percentage of the asset pack already transferred to the app.\n     * <p>\n     * This value is only defined when the status is {@link AssetPackStatus#TRANSFERRING}.\n     *\n     * @return a value between 0 and 100 inclusive.\n     */\n    public abstract int transferProgressPercentage();\n\n    @AssetPackUpdateAvailability\n    public abstract int updateAvailability();\n}\n"
  },
  {
    "path": "vending-app/src/main/java/com/google/android/play/core/assetpacks/AssetPackStateImpl.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.play.core.assetpacks;\n\nimport android.os.Bundle;\nimport androidx.annotation.NonNull;\nimport com.google.android.play.core.assetpacks.model.AssetPackErrorCode;\nimport com.google.android.play.core.assetpacks.model.AssetPackStatus;\nimport com.google.android.play.core.assetpacks.model.AssetPackUpdateAvailability;\nimport com.google.android.play.core.assetpacks.protocol.BundleKeys;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.utils.ToStringHelper;\n\n@Hide\npublic class AssetPackStateImpl extends AssetPackState {\n    private final String name;\n    private final @AssetPackStatus int status;\n    private final @AssetPackErrorCode int errorCode;\n    private final long bytesDownloaded;\n    private final long totalBytesToDownload;\n    private final int transferProgressPercentage;\n    @AssetPackUpdateAvailability\n    private final int updateAvailability;\n    private final String availableVersionTag;\n    private final String installedVersionTag;\n\n    public AssetPackStateImpl(String name, @AssetPackStatus int status, @AssetPackErrorCode int errorCode, long bytesDownloaded, long totalBytesToDownload, int transferProgressPercentage, @AssetPackUpdateAvailability int updateAvailability, String availableVersionTag, String installedVersionTag) {\n        this.name = name;\n        this.status = status;\n        this.errorCode = errorCode;\n        this.bytesDownloaded = bytesDownloaded;\n        this.totalBytesToDownload = totalBytesToDownload;\n        this.transferProgressPercentage = transferProgressPercentage;\n        this.updateAvailability = updateAvailability;\n        this.availableVersionTag = availableVersionTag;\n        this.installedVersionTag = installedVersionTag;\n    }\n\n    @NonNull\n    public static AssetPackState fromBundle(Bundle bundle, @NonNull String name, AssetPackManagerImpl assetPackManager) {\n        return fromBundle(bundle, name, assetPackManager, false);\n    }\n\n    @NonNull\n    public static AssetPackState fromBundle(Bundle bundle, @NonNull String name, AssetPackManagerImpl assetPackManager, boolean ignoreLocalStatus) {\n        @AssetPackStatus int remoteStatus =  BundleKeys.get(bundle, BundleKeys.STATUS, name, 0);\n        @AssetPackStatus int status = ignoreLocalStatus ? remoteStatus : assetPackManager.getLocalStatus(name, remoteStatus);\n        @AssetPackErrorCode int errorCode = BundleKeys.get(bundle, BundleKeys.ERROR_CODE, name, 0);\n        long bytesDownloaded = BundleKeys.get(bundle, BundleKeys.BYTES_DOWNLOADED, name, 0L);\n        long totalBytesToDownload = BundleKeys.get(bundle, BundleKeys.TOTAL_BYTES_TO_DOWNLOAD, name, 0L);\n        int transferProgressPercentage = assetPackManager.getTransferProgressPercentage(name);\n        long packVersion = BundleKeys.get(bundle, BundleKeys.PACK_VERSION, name, 0L);\n        long packBaseVersion = BundleKeys.get(bundle, BundleKeys.PACK_BASE_VERSION, name, 0L);\n        int appVersionCode = BundleKeys.get(bundle, BundleKeys.APP_VERSION_CODE, 0);\n        String availableVersionTag = BundleKeys.get(bundle, BundleKeys.PACK_VERSION_TAG, name, Integer.toString(appVersionCode));\n        String installedVersionTag = assetPackManager.getInstalledVersionTag(name);\n        int updateAvailability = AssetPackUpdateAvailability.UPDATE_NOT_AVAILABLE;\n        if (status == AssetPackStatus.COMPLETED && packBaseVersion != 0 && packBaseVersion != packVersion) {\n            updateAvailability = AssetPackUpdateAvailability.UPDATE_AVAILABLE;\n        }\n        return new AssetPackStateImpl(name, status, errorCode, bytesDownloaded, totalBytesToDownload, transferProgressPercentage, updateAvailability, availableVersionTag, installedVersionTag);\n    }\n\n    @Override\n    public String availableVersionTag() {\n        return availableVersionTag;\n    }\n\n    @Override\n    public long bytesDownloaded() {\n        return bytesDownloaded;\n    }\n\n    @Override\n    @AssetPackErrorCode\n    public int errorCode() {\n        return errorCode;\n    }\n\n    @Override\n    public String installedVersionTag() {\n        return installedVersionTag;\n    }\n\n    @Override\n    public String name() {\n        return name;\n    }\n\n    @Override\n    @AssetPackStatus\n    public int status() {\n        return status;\n    }\n\n    @Override\n    public long totalBytesToDownload() {\n        return totalBytesToDownload;\n    }\n\n    @Override\n    public int transferProgressPercentage() {\n        return transferProgressPercentage;\n    }\n\n    @Override\n    @AssetPackUpdateAvailability\n    public int updateAvailability() {\n        return updateAvailability;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"AssetPackState\")\n                .field(\"name\", name)\n                .field(\"status\", status)\n                .field(\"errorCode\", errorCode)\n                .field(\"bytesDownloaded\", bytesDownloaded)\n                .field(\"totalBytesToDownload\", totalBytesToDownload)\n                .field(\"transferProgressPercentage\", transferProgressPercentage)\n                .field(\"updateAvailability\", updateAvailability)\n                .field(\"availableVersionTag\", availableVersionTag)\n                .field(\"installedVersionTag\", installedVersionTag)\n                .end();\n    }\n}\n"
  },
  {
    "path": "vending-app/src/main/java/com/google/android/play/core/assetpacks/AssetPackStateUpdateListener.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.play.core.assetpacks;\n\nimport com.google.android.play.core.listener.StateUpdateListener;\n\n/**\n * Listener that may be registered for updates on the state of the download of asset packs.\n */\npublic interface AssetPackStateUpdateListener extends StateUpdateListener<AssetPackState> {\n}\n"
  },
  {
    "path": "vending-app/src/main/java/com/google/android/play/core/assetpacks/AssetPackStates.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.play.core.assetpacks;\n\nimport java.util.Map;\n\n/**\n * Contains the state for all requested packs.\n */\npublic abstract class AssetPackStates {\n    /**\n     * Returns a map from a pack's name to its state.\n     */\n    public abstract Map<String, AssetPackState> packStates();\n\n    /**\n     * Returns total size of all requested packs in bytes.\n     */\n    public abstract long totalBytes();\n}\n"
  },
  {
    "path": "vending-app/src/main/java/com/google/android/play/core/assetpacks/AssetPackStatesImpl.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.play.core.assetpacks;\n\nimport android.os.Bundle;\nimport androidx.annotation.NonNull;\nimport com.google.android.play.core.assetpacks.protocol.BundleKeys;\nimport org.microg.gms.common.Hide;\nimport org.microg.gms.utils.ToStringHelper;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.Map;\n\n@Hide\npublic class AssetPackStatesImpl extends AssetPackStates {\n    private final long totalBytes;\n    @NonNull\n    private final Map<String, AssetPackState> packStates;\n\n    public AssetPackStatesImpl(long totalBytes, @NonNull Map<String, AssetPackState> packStates) {\n        this.totalBytes = totalBytes;\n        this.packStates = packStates;\n    }\n\n    public static AssetPackStates fromBundle(@NonNull Bundle bundle, @NonNull AssetPackManagerImpl assetPackManager) {\n        return fromBundle(bundle, assetPackManager, false);\n    }\n\n    @NonNull\n    public static AssetPackStates fromBundle(@NonNull Bundle bundle, @NonNull AssetPackManagerImpl assetPackManager, boolean ignoreLocalStatus) {\n        long totalBytes = BundleKeys.get(bundle, BundleKeys.TOTAL_BYTES_TO_DOWNLOAD, 0L);\n        ArrayList<String> packNames = BundleKeys.get(bundle, BundleKeys.PACK_NAMES);\n        Map<String, AssetPackState> packStates = new HashMap<>();\n        if (packNames != null) {\n            for (String packName : packNames) {\n                packStates.put(packName, AssetPackStateImpl.fromBundle(bundle, packName, assetPackManager, ignoreLocalStatus));\n            }\n        }\n        return new AssetPackStatesImpl(totalBytes, packStates);\n    }\n\n    @Override\n    @NonNull\n    public Map<String, AssetPackState> packStates() {\n        return packStates;\n    }\n\n    @Override\n    public long totalBytes() {\n        return totalBytes;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"AssetPackStates\")\n                .field(\"totalBytes\", totalBytes)\n                .field(\"packStates\", packStates)\n                .end();\n    }\n}\n"
  },
  {
    "path": "vending-app/src/main/java/com/google/android/play/core/assetpacks/model/AssetPackErrorCode.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.play.core.assetpacks.model;\n\nimport android.app.Activity;\nimport androidx.annotation.IntDef;\nimport com.google.android.play.core.assetpacks.AssetPackManager;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Error codes for the download of an asset pack.\n */\n@Target({ElementType.TYPE_USE})\n@Retention(RetentionPolicy.CLASS)\n@IntDef({AssetPackErrorCode.NO_ERROR, AssetPackErrorCode.APP_UNAVAILABLE, AssetPackErrorCode.PACK_UNAVAILABLE, AssetPackErrorCode.INVALID_REQUEST, AssetPackErrorCode.DOWNLOAD_NOT_FOUND, AssetPackErrorCode.API_NOT_AVAILABLE, AssetPackErrorCode.NETWORK_ERROR, AssetPackErrorCode.ACCESS_DENIED, AssetPackErrorCode.INSUFFICIENT_STORAGE, AssetPackErrorCode.APP_NOT_OWNED, AssetPackErrorCode.PLAY_STORE_NOT_FOUND, AssetPackErrorCode.NETWORK_UNRESTRICTED, AssetPackErrorCode.CONFIRMATION_NOT_REQUIRED, AssetPackErrorCode.UNRECOGNIZED_INSTALLATION, AssetPackErrorCode.INTERNAL_ERROR})\npublic @interface AssetPackErrorCode {\n    int NO_ERROR = 0;\n    /**\n     * The requesting app is unavailable.\n     */\n    int APP_UNAVAILABLE = -1;\n    /**\n     * The requested asset pack isn't available.\n     * <p>\n     * This can happen if the asset pack wasn't included in the Android App Bundle that was published to the Play Store.\n     */\n    int PACK_UNAVAILABLE = -2;\n    /**\n     * The request is invalid.\n     */\n    int INVALID_REQUEST = -3;\n    /**\n     * The requested download isn't found.\n     */\n    int DOWNLOAD_NOT_FOUND = -4;\n    /**\n     * The Asset Delivery API isn't available.\n     */\n    int API_NOT_AVAILABLE = -5;\n    /**\n     * Network error. Unable to obtain the asset pack details.\n     */\n    int NETWORK_ERROR = -6;\n    /**\n     * Download not permitted under the current device circumstances (e.g. in background).\n     */\n    int ACCESS_DENIED = -7;\n    /**\n     * Asset pack download failed due to insufficient storage.\n     */\n    int INSUFFICIENT_STORAGE = -10;\n    /**\n     * The Play Store app is either not installed or not the official version.\n     */\n    int PLAY_STORE_NOT_FOUND = -11;\n    /**\n     * Returned if {@link AssetPackManager#showCellularDataConfirmation(Activity)} is called but no asset packs are\n     * waiting for Wi-Fi.\n     */\n    int NETWORK_UNRESTRICTED = -12;\n    /**\n     * The app isn't owned by any user on this device. An app is \"owned\" if it has been installed via the Play Store.\n     */\n    int APP_NOT_OWNED = -13;\n    /**\n     * Returned if {@link AssetPackManager#showConfirmationDialog(Activity)} is called but no asset packs require user\n     * confirmation.\n     */\n    int CONFIRMATION_NOT_REQUIRED = -14;\n    /**\n     * The installed app version is not recognized by Play. This can happen if the app was not installed by Play.\n     */\n    int UNRECOGNIZED_INSTALLATION = -15;\n    /**\n     * Unknown error downloading an asset pack.\n     */\n    int INTERNAL_ERROR = -100;\n}\n"
  },
  {
    "path": "vending-app/src/main/java/com/google/android/play/core/assetpacks/model/AssetPackStatus.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.play.core.assetpacks.model;\n\nimport android.app.Activity;\nimport androidx.annotation.IntDef;\nimport com.google.android.play.core.assetpacks.AssetPackManager;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Status of the download of an asset pack.\n */\n@Target({ElementType.TYPE_USE})\n@Retention(RetentionPolicy.CLASS)\n@IntDef({AssetPackStatus.UNKNOWN, AssetPackStatus.PENDING, AssetPackStatus.DOWNLOADING, AssetPackStatus.TRANSFERRING, AssetPackStatus.COMPLETED, AssetPackStatus.FAILED, AssetPackStatus.CANCELED, AssetPackStatus.WAITING_FOR_WIFI, AssetPackStatus.NOT_INSTALLED, AssetPackStatus.REQUIRES_USER_CONFIRMATION})\npublic @interface AssetPackStatus {\n    /**\n     * The asset pack state is unknown.\n     */\n    int UNKNOWN = 0;\n    /**\n     * The asset pack download is pending and will be processed soon.\n     */\n    int PENDING = 1;\n    /**\n     * The asset pack download is in progress.\n     */\n    int DOWNLOADING = 2;\n    /**\n     * The asset pack is being decompressed and copied (or patched) to the app's internal storage.\n     */\n    int TRANSFERRING = 3;\n    /**\n     * The asset pack download and transfer is complete; the assets are available to the app.\n     */\n    int COMPLETED = 4;\n    /**\n     * The asset pack download or transfer has failed.\n     */\n    int FAILED = 5;\n    /**\n     * The asset pack download has been canceled by the user through the Play Store or the download notification.\n     */\n    int CANCELED = 6;\n    /**\n     * The asset pack download is waiting for Wi-Fi to become available before proceeding.\n     * <p>\n     * The app can ask the user to download a session that is waiting for Wi-Fi over cellular data by using\n     * {@link AssetPackManager#showCellularDataConfirmation(Activity)}.\n     */\n    int WAITING_FOR_WIFI = 7;\n    /**\n     * The asset pack is not installed.\n     */\n    int NOT_INSTALLED = 8;\n    /**\n     * The asset pack requires user consent to be downloaded.\n     * <p>\n     * This can happen if the current app version was not installed by Play.\n     * <p>\n     * If the asset pack is also waiting for Wi-Fi, this state takes precedence.\n     */\n    int REQUIRES_USER_CONFIRMATION = 9;\n}\n"
  },
  {
    "path": "vending-app/src/main/java/com/google/android/play/core/assetpacks/model/AssetPackStorageMethod.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.play.core.assetpacks.model;\n\nimport androidx.annotation.IntDef;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Method used to store an asset pack.\n */\n@Target({ElementType.TYPE_USE})\n@Retention(RetentionPolicy.CLASS)\n@IntDef({AssetPackStorageMethod.STORAGE_FILES, AssetPackStorageMethod.APK_ASSETS})\npublic @interface AssetPackStorageMethod {\n    /**\n     * The asset pack is extracted into a folder containing individual asset files.\n     * <p>\n     * Assets contained by this asset pack can be accessed via standard File APIs.\n     */\n    int STORAGE_FILES = 0;\n    /**\n     * The asset pack is installed as APKs containing asset files.\n     * <p>\n     * Assets contained by this asset pack can be accessed via Asset Manager.\n     */\n    int APK_ASSETS = 1;\n}\n"
  },
  {
    "path": "vending-app/src/main/java/com/google/android/play/core/assetpacks/model/AssetPackUpdateAvailability.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.play.core.assetpacks.model;\n\nimport androidx.annotation.IntDef;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Target({ElementType.TYPE_USE})\n@Retention(RetentionPolicy.CLASS)\n@IntDef({AssetPackUpdateAvailability.UNKNOWN, AssetPackUpdateAvailability.UPDATE_NOT_AVAILABLE, AssetPackUpdateAvailability.UPDATE_AVAILABLE})\npublic @interface AssetPackUpdateAvailability {\n    int UNKNOWN = 0;\n    int UPDATE_NOT_AVAILABLE = 1;\n    int UPDATE_AVAILABLE = 2;\n}\n"
  },
  {
    "path": "vending-app/src/main/java/com/google/android/play/core/assetpacks/protocol/BroadcastConstants.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.play.core.assetpacks.protocol;\n\nimport org.microg.gms.common.Hide;\n\n@Hide\npublic class BroadcastConstants {\n    public static String ACTION_SESSION_UPDATE = \"com.google.android.play.core.assetpacks.receiver.ACTION_SESSION_UPDATE\";\n    public static String EXTRA_SESSION_STATE = \"com.google.android.play.core.assetpacks.receiver.EXTRA_SESSION_STATE\";\n    public static String EXTRA_FLAGS = \"com.google.android.play.core.FLAGS\";\n    public static String KEY_USING_EXTRACTOR_STREAM = \"usingExtractorStream\";\n}\n"
  },
  {
    "path": "vending-app/src/main/java/com/google/android/play/core/assetpacks/protocol/BundleKeys.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.play.core.assetpacks.protocol;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.os.ParcelFileDescriptor;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.os.BundleCompat;\nimport org.microg.gms.common.Hide;\n\nimport java.util.ArrayList;\n\n@Hide\npublic final class BundleKeys {\n    public static RootKey<Integer> APP_VERSION_CODE = new RootKey.Int(\"app_version_code\");\n    public static RootKey<Integer> CHUNK_NUMBER = new RootKey.Int(\"chunk_number\");\n    public static RootKey<ParcelFileDescriptor> CHUNK_FILE_DESCRIPTOR = new RootKey.Parcelable<>(\"chunk_file_descriptor\", ParcelFileDescriptor.class);\n    public static RootKey<Boolean> KEEP_ALIVE = new RootKey.Bool(\"keep_alive\");\n    public static RootKey<String> MODULE_NAME = new RootKey.String(\"module_name\");\n    public static RootKey<String> SLICE_ID = new RootKey.String(\"slice_id\");\n    public static RootKey<ArrayList<String>> PACK_NAMES = new RootKey.StringArrayList(\"pack_names\");\n\n    // OptionsBundle\n    public static RootKey<Integer> PLAY_CORE_VERSION_CODE = new RootKey.Int(\"playcore_version_code\");\n    public static RootKey<ArrayList<@CompressionFormat Integer>> SUPPORTED_COMPRESSION_FORMATS = new RootKey.IntArrayList(\"supported_compression_formats\");\n    public static RootKey<ArrayList<@PatchFormat Integer>> SUPPORTED_PATCH_FORMATS = new RootKey.IntArrayList(\"supported_patch_formats\");\n\n    // InstalledAssetModulesBundle\n    public static RootKey<ArrayList<Bundle>> INSTALLED_ASSET_MODULE = new RootKey.ParcelableArrayList<>(\"installed_asset_module\", Bundle.class);\n    public static RootKey<String> INSTALLED_ASSET_MODULE_NAME = new RootKey.String(\"installed_asset_module_name\");\n    public static RootKey<Long> INSTALLED_ASSET_MODULE_VERSION = new RootKey.Long(\"installed_asset_module_version\");\n\n    public static RootAndPackKey<Integer> SESSION_ID = new RootAndPackKey.Int(\"session_id\");\n    public static RootAndPackKey<Integer> STATUS = new RootAndPackKey.Int(\"status\");\n    public static RootAndPackKey<Integer> ERROR_CODE = new RootAndPackKey.Int(\"error_code\");\n    public static RootAndPackKey<Long> BYTES_DOWNLOADED = new RootAndPackKey.Long(\"bytes_downloaded\");\n    public static RootAndPackKey<Long> TOTAL_BYTES_TO_DOWNLOAD = new RootAndPackKey.Long(\"total_bytes_to_download\");\n\n    public static PackKey<Long> PACK_VERSION = new PackKey.Long(\"pack_version\");\n    public static PackKey<Long> PACK_BASE_VERSION = new PackKey.Long(\"pack_base_version\");\n    public static PackKey<String> PACK_VERSION_TAG = new PackKey.String(\"pack_version_tag\");\n    public static PackKey<ArrayList<String>> SLICE_IDS = new PackKey.StringArrayList(\"slice_ids\");\n\n    public static SliceKey<ArrayList<Intent>> CHUNK_INTENTS = new SliceKey.ParcelableArrayList<>(\"chunk_intents\", Intent.class);\n    public static SliceKey<@CompressionFormat Integer> COMPRESSION_FORMAT = new SliceKey.Int(\"compression_format\");\n    public static SliceKey<@PatchFormat Integer> PATCH_FORMAT = new SliceKey.Int(\"patch_format\");\n    public static SliceKey<String> UNCOMPRESSED_HASH_SHA256 = new SliceKey.String(\"uncompressed_hash_sha256\");\n    public static SliceKey<Long> UNCOMPRESSED_SIZE = new SliceKey.Long(\"uncompressed_size\");\n\n    private BundleKeys() {\n    }\n\n    @Nullable\n    public static <T> T get(Bundle bundle, @NonNull RootKey<T> key) {\n        return key.get(bundle, key.baseKey());\n    }\n\n    public static <T> T get(Bundle bundle, @NonNull RootKey<T> key, T def) {\n        return key.get(bundle, key.baseKey(), def);\n    }\n\n    public static <T> void put(Bundle bundle, @NonNull RootKey<T> key, T value) {\n        key.put(bundle, key.baseKey(), value);\n    }\n\n    @Nullable\n    public static <T> T get(Bundle bundle, @NonNull PackKey<T> key, String packName) {\n        return key.get(bundle, packKey(packName, key.baseKey()));\n    }\n\n    public static <T> T get(Bundle bundle, @NonNull PackKey<T> key, String packName, T def) {\n        return key.get(bundle, packKey(packName, key.baseKey()), def);\n    }\n\n    public static <T> void put(Bundle bundle, @NonNull PackKey<T> key, String packName, T value) {\n        key.put(bundle, packKey(packName, key.baseKey()), value);\n    }\n\n    @Nullable\n    public static <T> T get(Bundle bundle, @NonNull SliceKey<T> key, String packName, String sliceId) {\n        return key.get(bundle, sliceKey(packName, sliceId, key.baseKey()));\n    }\n\n    public static <T> T get(Bundle bundle, @NonNull SliceKey<T> key, String packName, String sliceId, T def) {\n        return key.get(bundle, sliceKey(packName, sliceId, key.baseKey()), def);\n    }\n\n    public static <T> void put(Bundle bundle, @NonNull SliceKey<T> key, String packName, String sliceId, T value) {\n        key.put(bundle, sliceKey(packName, sliceId, key.baseKey()), value);\n    }\n\n    @NonNull\n    private static String packKey(String packName, String baseKey) {\n        return baseKey + \":\" + packName;\n    }\n\n    @NonNull\n    private static String sliceKey(String packName, String sliceId, String baseKey) {\n        return baseKey + \":\" + packName + \":\" + sliceId;\n    }\n\n    public interface TypedBundleKey<T> {\n        @NonNull\n        java.lang.String baseKey();\n\n        @Nullable\n        T get(@NonNull Bundle bundle, @NonNull java.lang.String key);\n\n        T get(@NonNull Bundle bundle, @NonNull java.lang.String key, T def);\n\n        void put(@NonNull Bundle bundle, @NonNull java.lang.String key, T value);\n\n        abstract class Base<T> implements TypedBundleKey<T> {\n            @NonNull\n            public final java.lang.String baseKey;\n\n            public Base(@NonNull java.lang.String baseKey) {\n                this.baseKey = baseKey;\n            }\n\n            @NonNull\n            @Override\n            public java.lang.String baseKey() {\n                return baseKey;\n            }\n        }\n\n        class Int extends Base<Integer> {\n\n            public Int(@NonNull java.lang.String key) {\n                super(key);\n            }\n\n            @Override\n            public Integer get(@NonNull Bundle bundle, @NonNull java.lang.String key) {\n                return bundle.getInt(key);\n            }\n\n            @Override\n            public Integer get(@NonNull Bundle bundle, @NonNull java.lang.String key, Integer def) {\n                return bundle.getInt(key, def);\n            }\n\n            @Override\n            public void put(@NonNull Bundle bundle, @NonNull java.lang.String key, Integer value) {\n                bundle.putInt(key, value);\n            }\n        }\n\n        class Long extends Base<java.lang.Long> {\n\n            public Long(@NonNull java.lang.String key) {\n                super(key);\n            }\n\n            @Override\n            public java.lang.Long get(@NonNull Bundle bundle, @NonNull java.lang.String key) {\n                return bundle.getLong(key);\n            }\n\n            @Override\n            public java.lang.Long get(@NonNull Bundle bundle, @NonNull java.lang.String key, java.lang.Long def) {\n                return bundle.getLong(key, def);\n            }\n\n            @Override\n            public void put(@NonNull Bundle bundle, @NonNull java.lang.String key, java.lang.Long value) {\n                bundle.putLong(key, value);\n            }\n        }\n\n        class Bool extends Base<Boolean> {\n\n            public Bool(@NonNull java.lang.String key) {\n                super(key);\n            }\n\n            @Override\n            public Boolean get(@NonNull Bundle bundle, @NonNull java.lang.String key) {\n                return bundle.getBoolean(key);\n            }\n\n            @Override\n            public Boolean get(@NonNull Bundle bundle, @NonNull java.lang.String key, Boolean def) {\n                return bundle.getBoolean(key, def);\n            }\n\n            @Override\n            public void put(@NonNull Bundle bundle, @NonNull java.lang.String key, Boolean value) {\n                bundle.putBoolean(key, value);\n            }\n        }\n\n        class String extends Base<java.lang.String> {\n\n            public String(@NonNull java.lang.String key) {\n                super(key);\n            }\n\n            @Override\n            public java.lang.String get(@NonNull Bundle bundle, @NonNull java.lang.String key) {\n                return bundle.getString(key);\n            }\n\n            @Override\n            public java.lang.String get(@NonNull Bundle bundle, @NonNull java.lang.String key, java.lang.String def) {\n                return bundle.getString(key, def);\n            }\n\n            @Override\n            public void put(@NonNull Bundle bundle, @NonNull java.lang.String key, java.lang.String value) {\n                bundle.putString(key, value);\n            }\n        }\n\n        class Parcelable<T extends android.os.Parcelable> extends Base<T> {\n            @NonNull\n            private final Class<T> tClass;\n\n            public Parcelable(@NonNull java.lang.String key, @NonNull Class<T> tClass) {\n                super(key);\n                this.tClass = tClass;\n            }\n\n            @Override\n            public T get(@NonNull Bundle bundle, @NonNull java.lang.String key) {\n                return BundleCompat.getParcelable(bundle, key, tClass);\n            }\n\n            @Override\n            public T get(@NonNull Bundle bundle, @NonNull java.lang.String key, T def) {\n                if (bundle.containsKey(key)) {\n                    return BundleCompat.getParcelable(bundle, key, tClass);\n                } else {\n                    return def;\n                }\n            }\n\n            @Override\n            public void put(@NonNull Bundle bundle, @NonNull java.lang.String key, T value) {\n                bundle.putParcelable(key, value);\n            }\n        }\n\n        class StringArrayList extends Base<ArrayList<java.lang.String>> {\n            public StringArrayList(@NonNull java.lang.String key) {\n                super(key);\n            }\n\n            @Override\n            public ArrayList<java.lang.String> get(@NonNull Bundle bundle, @NonNull java.lang.String key) {\n                return bundle.getStringArrayList(key);\n            }\n\n            @Override\n            public ArrayList<java.lang.String> get(@NonNull Bundle bundle, @NonNull java.lang.String key, ArrayList<java.lang.String> def) {\n                if (bundle.containsKey(key)) {\n                    return bundle.getStringArrayList(key);\n                } else {\n                    return def;\n                }\n            }\n\n            @Override\n            public void put(@NonNull Bundle bundle, @NonNull java.lang.String key, ArrayList<java.lang.String> value) {\n                bundle.putStringArrayList(key, value);\n            }\n        }\n\n        class IntArrayList extends Base<ArrayList<Integer>> {\n            public IntArrayList(@NonNull java.lang.String key) {\n                super(key);\n            }\n\n            @Override\n            public ArrayList<Integer> get(@NonNull Bundle bundle, @NonNull java.lang.String key) {\n                return bundle.getIntegerArrayList(key);\n            }\n\n            @Override\n            public ArrayList<Integer> get(@NonNull Bundle bundle, @NonNull java.lang.String key, ArrayList<Integer> def) {\n                if (bundle.containsKey(key)) {\n                    return bundle.getIntegerArrayList(key);\n                } else {\n                    return def;\n                }\n            }\n\n            @Override\n            public void put(@NonNull Bundle bundle, @NonNull java.lang.String key, ArrayList<Integer> value) {\n                bundle.putIntegerArrayList(key, value);\n            }\n        }\n\n        class ParcelableArrayList<T extends android.os.Parcelable> extends Base<ArrayList<T>> {\n            @NonNull\n            private final Class<T> tClass;\n\n            public ParcelableArrayList(@NonNull java.lang.String key, @NonNull Class<T> tClass) {\n                super(key);\n                this.tClass = tClass;\n            }\n\n            @Override\n            public ArrayList<T> get(@NonNull Bundle bundle, @NonNull java.lang.String key) {\n                return BundleCompat.getParcelableArrayList(bundle, key, tClass);\n            }\n\n            @Override\n            public ArrayList<T> get(@NonNull Bundle bundle, @NonNull java.lang.String key, ArrayList<T> def) {\n                if (bundle.containsKey(key)) {\n                    return BundleCompat.getParcelableArrayList(bundle, key, tClass);\n                } else {\n                    return def;\n                }\n            }\n\n            @Override\n            public void put(@NonNull Bundle bundle, @NonNull java.lang.String key, ArrayList<T> value) {\n                bundle.putParcelableArrayList(key, value);\n            }\n        }\n    }\n\n\n    public interface PackKey<T> extends TypedBundleKey<T> {\n        class Int extends TypedBundleKey.Int implements PackKey<Integer> {\n            public Int(@NonNull java.lang.String key) {\n                super(key);\n            }\n        }\n\n        class Long extends TypedBundleKey.Long implements PackKey<java.lang.Long> {\n            public Long(@NonNull java.lang.String key) {\n                super(key);\n            }\n        }\n\n        class String extends TypedBundleKey.String implements PackKey<java.lang.String> {\n            public String(@NonNull java.lang.String key) {\n                super(key);\n            }\n        }\n\n        class StringArrayList extends TypedBundleKey.StringArrayList implements PackKey<ArrayList<java.lang.String>> {\n            public StringArrayList(@NonNull java.lang.String key) {\n                super(key);\n            }\n        }\n    }\n\n    public interface SliceKey<T> extends TypedBundleKey<T> {\n        class Int extends TypedBundleKey.Int implements SliceKey<Integer> {\n            public Int(@NonNull java.lang.String key) {\n                super(key);\n            }\n        }\n\n        class Long extends TypedBundleKey.Long implements SliceKey<java.lang.Long> {\n            public Long(@NonNull java.lang.String key) {\n                super(key);\n            }\n        }\n\n        class String extends TypedBundleKey.String implements SliceKey<java.lang.String> {\n            public String(@NonNull java.lang.String key) {\n                super(key);\n            }\n        }\n\n        class ParcelableArrayList<T extends android.os.Parcelable> extends TypedBundleKey.ParcelableArrayList<T> implements SliceKey<ArrayList<T>> {\n            public ParcelableArrayList(@NonNull java.lang.String key, @NonNull Class<T> tClass) {\n                super(key, tClass);\n            }\n        }\n    }\n\n    public interface RootKey<T> extends TypedBundleKey<T> {\n        class Int extends TypedBundleKey.Int implements RootKey<Integer> {\n            public Int(@NonNull java.lang.String key) {\n                super(key);\n            }\n        }\n\n        class Long extends TypedBundleKey.Long implements RootKey<java.lang.Long> {\n            public Long(@NonNull java.lang.String key) {\n                super(key);\n            }\n        }\n\n        class Bool extends TypedBundleKey.Bool implements RootKey<Boolean> {\n            public Bool(@NonNull java.lang.String key) {\n                super(key);\n            }\n        }\n\n        class String extends TypedBundleKey.String implements RootKey<java.lang.String> {\n            public String(@NonNull java.lang.String key) {\n                super(key);\n            }\n        }\n\n        class Parcelable<T extends android.os.Parcelable> extends TypedBundleKey.Parcelable<T> implements RootKey<T> {\n            public Parcelable(@NonNull java.lang.String key, @NonNull Class<T> tClass) {\n                super(key, tClass);\n            }\n        }\n\n        class StringArrayList extends TypedBundleKey.StringArrayList implements RootKey<ArrayList<java.lang.String>> {\n            public StringArrayList(@NonNull java.lang.String key) {\n                super(key);\n            }\n        }\n\n        class IntArrayList extends TypedBundleKey.IntArrayList implements RootKey<ArrayList<Integer>> {\n            public IntArrayList(@NonNull java.lang.String key) {\n                super(key);\n            }\n        }\n\n        class ParcelableArrayList<T extends android.os.Parcelable> extends TypedBundleKey.ParcelableArrayList<T> implements RootKey<ArrayList<T>> {\n            public ParcelableArrayList(@NonNull java.lang.String key, @NonNull Class<T> tClass) {\n                super(key, tClass);\n            }\n        }\n    }\n\n    public interface RootAndPackKey<T> extends RootKey<T>, PackKey<T> {\n\n        class Int extends TypedBundleKey.Int implements RootAndPackKey<Integer> {\n            public Int(@NonNull java.lang.String key) {\n                super(key);\n            }\n        }\n\n        class Long extends TypedBundleKey.Long implements RootAndPackKey<java.lang.Long> {\n            public Long(@NonNull java.lang.String key) {\n                super(key);\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "vending-app/src/main/java/com/google/android/play/core/assetpacks/protocol/CompressionFormat.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.play.core.assetpacks.protocol;\n\nimport androidx.annotation.IntDef;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Target({ElementType.TYPE_USE})\n@Retention(RetentionPolicy.CLASS)\n@IntDef({CompressionFormat.UNSPECIFIED, CompressionFormat.BROTLI, CompressionFormat.GZIP, CompressionFormat.CHUNKED_GZIP, CompressionFormat.CHUNKED_BROTLI})\npublic @interface CompressionFormat {\n    int UNSPECIFIED = 0;\n    int BROTLI = 1;\n    int GZIP = 2;\n    int CHUNKED_GZIP = 3;\n    int CHUNKED_BROTLI = 4;\n}\n"
  },
  {
    "path": "vending-app/src/main/java/com/google/android/play/core/assetpacks/protocol/PatchFormat.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.play.core.assetpacks.protocol;\n\n\nimport androidx.annotation.IntDef;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Target({ElementType.TYPE_USE})\n@Retention(RetentionPolicy.CLASS)\n@IntDef({PatchFormat.UNKNOWN_PATCHING_FORMAT, PatchFormat.PATCH_GDIFF, PatchFormat.GZIPPED_GDIFF, PatchFormat.GZIPPED_BSDIFF, PatchFormat.GZIPPED_FILEBYFILE, PatchFormat.BROTLI_FILEBYFILE, PatchFormat.BROTLI_BSDIFF, PatchFormat.BROTLI_FILEBYFILE_RECURSIVE, PatchFormat.BROTLI_FILEBYFILE_ANDROID_AWARE, PatchFormat.BROTLI_FILEBYFILE_RECURSIVE_ANDROID_AWARE, PatchFormat.BROTLI_FILEBYFILE_ANDROID_AWARE_NO_RECOMPRESSION})\npublic @interface PatchFormat {\n    int UNKNOWN_PATCHING_FORMAT = 0;\n    int PATCH_GDIFF = 1;\n    int GZIPPED_GDIFF = 2;\n    int GZIPPED_BSDIFF = 3;\n    int GZIPPED_FILEBYFILE = 4;\n    int BROTLI_FILEBYFILE = 5;\n    int BROTLI_BSDIFF = 6;\n    int BROTLI_FILEBYFILE_RECURSIVE = 7;\n    int BROTLI_FILEBYFILE_ANDROID_AWARE = 8;\n    int BROTLI_FILEBYFILE_RECURSIVE_ANDROID_AWARE = 9;\n    int BROTLI_FILEBYFILE_ANDROID_AWARE_NO_RECOMPRESSION = 10;\n}\n"
  },
  {
    "path": "vending-app/src/main/java/com/google/android/play/core/listener/StateUpdateListener.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.play.core.listener;\n\n/**\n * Base interface for state update listeners.\n */\npublic interface StateUpdateListener<StateT> {\n    /**\n     * Callback triggered whenever the state has changed.\n     */\n    void onStateUpdate(StateT state);\n}\n"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/MarketIntentRedirect.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.vending;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.content.pm.ResolveInfo;\nimport android.os.Bundle;\nimport android.util.Log;\nimport android.widget.Toast;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\npublic class MarketIntentRedirect extends Activity {\n    private static final String TAG = \"IntentForwarder\";\n\n    @Override\n    protected void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        Intent intent = getIntent();\n        if (intent != null) {\n            try {\n                processIntent(intent);\n            } catch (Exception e) {\n                Log.w(TAG, \"Failed forwarding\", e);\n            }\n        } else {\n            Log.w(TAG, \"Intent is null, ignoring\");\n        }\n        finish();\n    }\n\n    private boolean isNonSelfIntent(@NonNull Intent intent) {\n        ResolveInfo resolveInfo = getPackageManager().resolveActivity(intent, 0);\n        return resolveInfo != null && resolveInfo.activityInfo != null && !getPackageName().equals(resolveInfo.activityInfo.packageName);\n    }\n\n    private void processIntent(@NonNull Intent intent) {\n        Log.d(TAG, \"Received \" + intent);\n        Intent newIntent = new Intent(intent);\n        newIntent.setPackage(null);\n        newIntent.setComponent(null);\n        if (\"market\".equals(newIntent.getScheme())) {\n            try {\n                if (isNonSelfIntent(newIntent)) {\n                    Log.d(TAG, \"Redirect to \" + newIntent);\n                    startActivity(newIntent);\n                    return;\n                }\n            } catch (Exception e) {\n                Log.w(TAG, e);\n            }\n            // Rewrite to market.android.com as there is no handler for market://\n            // This allows to always still open in a web browser\n            newIntent.setData(newIntent.getData().buildUpon()\n                    .scheme(\"https\").authority(\"market.android.com\")\n                    .encodedPath(newIntent.getData().getAuthority() + newIntent.getData().getEncodedPath())\n                    .build());\n            Log.d(TAG, \"Rewrote as \" + newIntent + \" (\" + newIntent.getDataString() + \")\");\n        }\n        if (\"market.android.com\".equals(newIntent.getData().getAuthority()) && newIntent.getData().getPath().startsWith(\"/details\")) {\n            // Rewrite to play.google.com for better compatibility\n            newIntent.setData(newIntent.getData().buildUpon()\n                    .scheme(\"https\").authority(\"play.google.com\")\n                    .encodedPath(\"/store/apps\" + newIntent.getData().getEncodedPath())\n                    .build());\n            Log.d(TAG, \"Rewrote as \" + newIntent + \" (\" + newIntent.getDataString() + \")\");\n        }\n        try {\n            if (isNonSelfIntent(newIntent)) {\n                Log.d(TAG, \"Redirect to \" + newIntent);\n                startActivity(newIntent);\n                return;\n            }\n        } catch (Exception e) {\n            Log.w(TAG, e);\n            Toast.makeText(this, \"Unable to open\", Toast.LENGTH_SHORT).show();\n        }\n        Log.w(TAG, \"Not forwarded \" + intent);\n    }\n}\n"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/WorkAccountChangedReceiver.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.vending\n\nimport android.accounts.AccountManager\nimport android.content.BroadcastReceiver\nimport android.content.ComponentName\nimport android.content.Context\nimport android.content.Intent\nimport android.content.pm.PackageManager\nimport android.util.Log\nimport org.microg.gms.auth.AuthConstants\nimport org.microg.vending.ui.WorkAppsActivity\n\nclass WorkAccountChangedReceiver : BroadcastReceiver() {\n\n    override fun onReceive(context: Context, intent: Intent?) {\n        val accountManager = AccountManager.get(context)\n        val hasWorkAccounts = accountManager.getAccountsByType(AuthConstants.WORK_ACCOUNT_TYPE).isNotEmpty()\n\n\n        if (android.os.Build.VERSION.SDK_INT >= 21) {\n            Log.d(TAG, \"setting VendingActivity state to enabled = $hasWorkAccounts\")\n\n            val componentName = ComponentName(\n                context,\n                WorkAppsActivity::class.java\n            )\n            context.packageManager.setComponentEnabledSetting(\n                componentName,\n                if (hasWorkAccounts) PackageManager.COMPONENT_ENABLED_STATE_ENABLED else PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,\n                0\n            )\n        }\n    }\n\n    companion object {\n        const val TAG = \"GmsVendingWorkAccRcvr\"\n    }\n}"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/AcquireFreeAppLicense.kt",
    "content": "package org.microg.vending.billing\n\nimport android.accounts.Account\nimport android.content.Context\nimport android.util.Log\nimport io.ktor.utils.io.errors.IOException\nimport org.microg.vending.billing.core.GooglePlayApi.Companion.URL_DETAILS\nimport org.microg.vending.billing.core.GooglePlayApi.Companion.URL_PURCHASE\nimport org.microg.vending.billing.core.HeaderProvider\nimport org.microg.vending.billing.core.HttpClient\nimport org.microg.vending.billing.proto.GoogleApiResponse\n\nsuspend fun HttpClient.acquireFreeAppLicense(context: Context, account: Account, packageName: String): Boolean {\n    val authData = AuthManager.getAuthData(context, account)\n\n    val deviceInfo = createDeviceEnvInfo(context)\n    if (deviceInfo == null || authData == null) {\n        Log.e(TAG, \"Unable to auto-purchase $packageName when deviceInfo = $deviceInfo and authData = $authData\")\n        return false\n    }\n\n    val headers = HeaderProvider.getDefaultHeaders(authData, deviceInfo)\n\n    // Check if app is free\n    val detailsResult = try {\n        get(\n            url = URL_DETAILS,\n            headers = headers,\n            params = mapOf(\"doc\" to packageName),\n            adapter = GoogleApiResponse.ADAPTER\n        ).payload?.detailsResponse\n    } catch (e: IOException) {\n        Log.e(TAG, \"Unable to auto-purchase $packageName because of a network error or unexpected response when gathering app data\", e)\n        return false\n    }\n\n    val item = detailsResult?.item\n    val appDetails = item?.details?.appDetails\n    val versionCode = appDetails?.versionCode\n    if (detailsResult == null || versionCode == null || appDetails.packageName != packageName) {\n        Log.e(TAG, \"Unable to auto-purchase $packageName because the server did not send sufficient or matching details\")\n        return false\n    }\n\n    val offer = item.offer\n    if (offer == null) {\n        Log.e(TAG, \"Unable to auto-purchase $packageName because the app is not being offered at the store\")\n    }\n\n    val freeApp = detailsResult.item.offer?.micros == 0L\n    if (!freeApp) {\n        Log.e(TAG, \"Unable to auto-purchase $packageName because it is not a free app\")\n        return false\n    }\n\n    // Purchase app\n    val parameters = mapOf(\n        \"ot\" to (offer?.offerType ?: 1).toString(),\n        \"doc\" to packageName,\n        \"vc\" to versionCode.toString()\n    )\n\n    val buyResult = try {\n        post(\n            url = URL_PURCHASE,\n            headers = headers,\n            params = parameters,\n            adapter = GoogleApiResponse.ADAPTER\n        ).payload?.buyResponse\n    } catch (e: IOException) {\n        Log.e(TAG, \"Unable to auto-purchase $packageName because of a network error or unexpected response during purchase\", e)\n        return false\n    }\n\n    if (buyResult?.deliveryToken.isNullOrBlank()) {\n        Log.e(TAG, \"Auto-purchasing $packageName failed. Was the purchase rejected by the server?\")\n        return false\n    } else {\n        Log.i(TAG, \"Auto-purchased $packageName.\")\n    }\n\n    return true\n}"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/AuthManager.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.vending.billing\n\nimport android.accounts.Account\nimport android.accounts.AccountManager\nimport android.content.Context\nimport android.content.Intent\nimport android.util.Log\nimport org.microg.vending.billing.core.AuthData\nimport java.util.concurrent.TimeUnit\n\nobject AuthManager {\n    private const val TOKEN_TYPE = \"oauth2:https://www.googleapis.com/auth/googleplay https://www.googleapis.com/auth/accounts.reauth\"\n    fun getAuthData(context: Context, account: Account? = AccountManager.get(context).getAccountsByType(DEFAULT_ACCOUNT_TYPE).firstOrNull()): AuthData? {\n\n        if (account == null) return null\n\n        val deviceCheckInConsistencyToken = CheckinServiceClient.getConsistencyToken(context)\n        val gsfId = GServices.getString(context.contentResolver, \"android_id\", \"0\")!!.toBigInteger().toString(16)\n        if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"gsfId: $gsfId, deviceDataVersionInfo: $deviceCheckInConsistencyToken\")\n        val accountManager: AccountManager = AccountManager.get(context)\n        val future = accountManager.getAuthToken(account, TOKEN_TYPE, false, null, null)\n        val bundle = future.getResult(15, TimeUnit.SECONDS)\n        val launch = bundle.getParcelable(AccountManager.KEY_INTENT) as Intent?\n        return if (launch != null) {\n            Log.e(TAG, \"[getAuthData]need start activity by intent: $launch\")\n            null\n        } else {\n            bundle.getString(AccountManager.KEY_AUTHTOKEN)?.let {\n                AuthData(account.name, it, gsfId, deviceCheckInConsistencyToken)\n            }\n        }\n    }\n}"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/CheckinServiceClient.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.vending.billing\n\nimport android.content.ComponentName\nimport android.content.Context\nimport android.content.Context.BIND_AUTO_CREATE\nimport android.content.Intent\nimport android.content.ServiceConnection\nimport android.os.IBinder\nimport android.util.Log\nimport com.google.android.gms.checkin.internal.ICheckinService\nimport java.util.concurrent.LinkedBlockingQueue\nimport java.util.concurrent.TimeUnit\n\n// TODO: Connect to check-in settings provider instead\nobject CheckinServiceClient {\n    private val serviceQueue = LinkedBlockingQueue<ICheckinService>()\n\n    fun getConsistencyToken(context: Context): String {\n        try {\n            val conn = object : ServiceConnection {\n                override fun onServiceConnected(name: ComponentName?, service: IBinder?) {\n                    service?.let { serviceQueue.add(ICheckinService.Stub.asInterface(it)) }\n                }\n\n                override fun onServiceDisconnected(name: ComponentName?) {\n                    serviceQueue.clear()\n                }\n            }\n            val intent = Intent(\"com.google.android.gms.checkin.BIND_TO_SERVICE\")\n            intent.setPackage(\"com.google.android.gms\")\n            val res = context.bindService(intent, conn, BIND_AUTO_CREATE)\n            if (!res) return \"\"\n            try {\n                val service = serviceQueue.poll(10, TimeUnit.SECONDS) ?: return \"\"\n                return service.deviceDataVersionInfo ?: \"\"\n            } finally {\n                context.unbindService(conn)\n            }\n        } catch (e: Exception) {\n            Log.e(TAG, \"getConsistencyToken\", e)\n            return \"\"\n        }\n    }\n}"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/Constants.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.vending.billing\n\nconst val TAG = \"Billing\"\n\n// TODO: What versions to use?\nconst val VENDING_VERSION_CODE = 83061810L\nconst val VENDING_VERSION_NAME = \"30.6.18-21 [0] [PR] 450795914\"\nconst val VENDING_PACKAGE_NAME = \"com.android.vending\"\n// TODO: Replace key name\nconst val KEY_IAP_SHEET_UI_PARAM = \"key_iap_sheet_ui_param\"\nconst val DEFAULT_ACCOUNT_TYPE = \"com.google\"\nconst val ADD_PAYMENT_METHOD_URL = \"https://play.google.com/store/paymentmethods\""
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/ContextProvider.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.vending.billing\n\nimport android.app.Application\nimport org.microg.gms.profile.ProfileManager\n\n// TODO: Get rid\nobject ContextProvider {\n    lateinit var context: Application\n        private set\n\n    fun init(application: Application) {\n        context = application\n    }\n}"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/DeviceIdentifier.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.vending.billing\n\nimport java.util.Random\n\n// TODO: Use existing code\nobject DeviceIdentifier {\n    var wifiMac = randomMacAddress()\n    var meid = randomMeid()\n    var serial = randomSerial(\"008741A0B2C4D6E8\")\n    var esn: String = \"\"\n\n\n    private fun randomMacAddress(): String {\n        var mac = \"b407f9\"\n        val rand = Random()\n        for (i in 0..5) {\n            mac += rand.nextInt(16).toString(16)\n        }\n        return mac\n    }\n\n    private fun randomSerial(\n        template: String,\n        prefixLength: Int = (template.length / 2).coerceAtMost(6)\n    ): String {\n        val serial = StringBuilder()\n        template.forEachIndexed { index, c ->\n            serial.append(\n                when {\n                    index < prefixLength -> c\n                    c.isDigit() -> '0' + kotlin.random.Random.nextInt(10)\n                    c.isLowerCase() && c <= 'f' -> 'a' + kotlin.random.Random.nextInt(6)\n                    c.isLowerCase() -> 'a' + kotlin.random.Random.nextInt(26)\n                    c.isUpperCase() && c <= 'F' -> 'A' + kotlin.random.Random.nextInt(6)\n                    c.isUpperCase() -> 'A' + kotlin.random.Random.nextInt(26)\n                    else -> c\n                }\n            )\n        }\n        return serial.toString()\n    }\n\n    private fun randomMeid(): String {\n        // http://en.wikipedia.org/wiki/International_Mobile_Equipment_Identity\n        // We start with a known base, and generate random MEID\n        var meid = \"35503104\"\n        val rand = Random()\n        for (i in 0..5) {\n            meid += rand.nextInt(10).toString()\n        }\n\n        // Luhn algorithm (check digit)\n        var sum = 0\n        for (i in meid.indices) {\n            var c = meid[i].toString().toInt()\n            if ((meid.length - i - 1) % 2 == 0) {\n                c *= 2\n                c = c % 10 + c / 10\n            }\n            sum += c\n        }\n        val check = (100 - sum) % 10\n        meid += check.toString()\n        return meid\n    }\n}"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/GServices.kt",
    "content": "package org.microg.vending.billing\n\nimport android.content.ContentResolver\nimport android.net.Uri\n\n// TODO: Move\nobject GServices {\n    private val CONTENT_URI: Uri = Uri.parse(\"content://com.google.android.gsf.gservices\")\n\n    fun getString(resolver: ContentResolver, key: String, defaultValue: String?): String? {\n        var result = defaultValue\n        val cursor = resolver.query(CONTENT_URI, null, null, arrayOf(key), null)\n        cursor?.use {\n            if (cursor.moveToNext()) {\n                result = cursor.getString(1)\n            }\n        }\n        return result\n    }\n}"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/InAppBillingServiceImpl.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.vending.billing\n\nimport android.accounts.Account\nimport android.app.PendingIntent.FLAG_CANCEL_CURRENT\nimport android.content.Context\nimport android.content.Intent\nimport android.os.Bundle\nimport android.os.Parcel\nimport android.util.Log\nimport androidx.annotation.RequiresApi\nimport androidx.core.app.PendingIntentCompat\nimport androidx.core.os.bundleOf\nimport com.android.billingclient.api.BillingClient.BillingResponseCode\nimport com.android.billingclient.api.BillingClient.ProductType\nimport com.android.vending.VendingPreferences\nimport com.android.vending.billing.IInAppBillingCreateAlternativeBillingOnlyTokenCallback\nimport com.android.vending.billing.IInAppBillingCreateExternalPaymentReportingDetailsCallback\nimport com.android.vending.billing.IInAppBillingDelegateToBackendCallback\nimport com.android.vending.billing.IInAppBillingGetAlternativeBillingOnlyDialogIntentCallback\nimport com.android.vending.billing.IInAppBillingGetBillingConfigCallback\nimport com.android.vending.billing.IInAppBillingGetExternalPaymentDialogIntentCallback\nimport com.android.vending.billing.IInAppBillingInitializeCallback\nimport com.android.vending.billing.IInAppBillingIsAlternativeBillingOnlyAvailableCallback\nimport com.android.vending.billing.IInAppBillingIsExternalPaymentAvailableCallback\nimport com.android.vending.billing.IInAppBillingService\nimport com.android.vending.billing.IInAppBillingServiceCallback\nimport org.microg.vending.billing.ui.InAppBillingHostActivity\nimport org.microg.vending.billing.ui.logic.BuyFlowResult\nimport com.google.android.gms.droidguard.DroidGuardClient\nimport kotlinx.coroutines.CoroutineScope\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.async\nimport kotlinx.coroutines.runBlocking\nimport org.json.JSONObject\nimport org.microg.gms.utils.toHexString\nimport org.microg.gms.utils.warnOnTransactionIssues\nimport org.microg.vending.billing.core.*\nimport java.util.Locale\n\nprivate class BuyFlowCacheEntry(\n    var packageName: String,\n    var account: Account,\n    var buyFlowParams: BuyFlowParams? = null,\n    var lastAcquireResult: AcquireResult? = null,\n    var droidGuardResult: String = \"\"\n)\n\nprivate const val EXPIRE_MS = 1 * 60 * 1000\n\nprivate data class IAPCoreCacheEntry(\n    val iapCore: IAPCore,\n    val expiredAt: Long\n)\n\n\nprivate const val requestCode = 10001\n@RequiresApi(21)\nclass InAppBillingServiceImpl(private val context: Context) : IInAppBillingService.Stub() {\n\n\n    companion object {\n        private val buyFlowCacheMap = mutableMapOf<String, BuyFlowCacheEntry>()\n        private val iapCoreCacheMap = mutableMapOf<String, IAPCoreCacheEntry>()\n        private val typeList = listOf(\n            ProductType.SUBS,\n            ProductType.INAPP,\n            \"first_party\",\n            \"audio_book\",\n            \"book\",\n            \"book_subs\",\n            \"nest_subs\",\n            \"play_pass_subs\",\n            \"stadia_item\",\n            \"stadia_subs\",\n            \"movie\",\n            \"tv_show\",\n            \"tv_episode\",\n            \"tv_season\"\n        )\n        fun acquireRequest(\n            context: Context,\n            cacheKey: String,\n            actionContexts: List<ByteArray> = emptyList(),\n            authToken: String? = null,\n            firstRequest: Boolean = false\n        ): BuyFlowResult {\n            if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"acquireRequest(cacheKey=$cacheKey, actionContexts=${actionContexts.map { it.toHexString() }}, authToken=$authToken)\")\n            val buyFlowCacheEntry = buyFlowCacheMap[cacheKey] ?: return BuyFlowResult(\n                null, null, resultBundle(BillingResponseCode.DEVELOPER_ERROR, \"Parameter check error.\")\n            )\n            val buyFlowParams = buyFlowCacheEntry.buyFlowParams ?: return BuyFlowResult(\n                null, buyFlowCacheEntry.account, resultBundle(BillingResponseCode.DEVELOPER_ERROR, \"Parameter check error.\")\n            )\n            val params = AcquireParams(\n                buyFlowParams = buyFlowParams,\n                actionContext = actionContexts,\n                authToken = authToken,\n                droidGuardResult = buyFlowCacheEntry.droidGuardResult.takeIf { !firstRequest },\n                lastAcquireResult = buyFlowCacheEntry.lastAcquireResult.takeIf { !firstRequest }\n            )\n\n            val coreResult = try {\n                val deferred = CoroutineScope(Dispatchers.IO).async {\n                    createIAPCore(\n                        context,\n                        buyFlowCacheEntry.account,\n                        buyFlowCacheEntry.packageName\n                    ).doAcquireRequest(\n                        params\n                    )\n                }\n                runBlocking { deferred.await() }\n            } catch (e: RuntimeException) {\n                if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"acquireRequest\", e)\n                return BuyFlowResult(null, buyFlowCacheEntry.account, resultBundle(BillingResponseCode.DEVELOPER_ERROR, e.message))\n            } catch (e: Exception) {\n                if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"acquireRequest\", e)\n                return BuyFlowResult(null, buyFlowCacheEntry.account, resultBundle(BillingResponseCode.DEVELOPER_ERROR, \"Internal error.\"))\n            }\n            if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"acquireRequest acquireParsedResult: ${coreResult.acquireParsedResult}\")\n            buyFlowCacheEntry.lastAcquireResult = coreResult\n            if (coreResult.acquireParsedResult.action?.droidGuardMap?.isNotEmpty() == true) {\n                DroidGuardClient.getResults(context, \"phonesky_acquire_flow\", coreResult.acquireParsedResult.action.droidGuardMap).addOnCompleteListener { task ->\n                    buyFlowCacheEntry.droidGuardResult = task.result\n                }\n            }\n            coreResult.acquireParsedResult.purchaseItems.forEach {\n                PurchaseManager.addPurchase(buyFlowCacheEntry.account, buyFlowCacheEntry.packageName, it)\n            }\n            return BuyFlowResult(\n                coreResult.acquireParsedResult,\n                buyFlowCacheEntry.account,\n                coreResult.acquireParsedResult.result.toBundle()\n            )\n        }\n\n        fun requestAuthProofToken(context: Context, cacheKey: String, password: String): String {\n            val buyFlowCacheEntry = buyFlowCacheMap[cacheKey]\n                ?: throw IllegalStateException(\"Nothing cached: $cacheKey\")\n            val deferred = CoroutineScope(Dispatchers.IO).async {\n                createIAPCore(\n                    context,\n                    buyFlowCacheEntry.account,\n                    buyFlowCacheEntry.packageName\n                ).requestAuthProofToken(password)\n            }\n            return runBlocking { deferred.await() }\n        }\n\n        private fun createIAPCore(context: Context, account: Account, pkgName: String): IAPCore {\n            val key = \"$pkgName:${account.name}\"\n            val cacheEntry = iapCoreCacheMap[key]\n            if (cacheEntry != null) {\n                if (cacheEntry.expiredAt > System.currentTimeMillis())\n                    return cacheEntry.iapCore\n                iapCoreCacheMap.remove(key)\n            }\n            val authData = AuthManager.getAuthData(context, account)\n                ?: throw RuntimeException(\"Failed to obtain login token.\")\n            val deviceEnvInfo = createDeviceEnvInfo(context)\n                ?: throw RuntimeException(\"Failed to retrieve device information.\")\n            val clientInfo = createClient(context, pkgName)\n                ?: throw RuntimeException(\"Failed to retrieve client information.\")\n            val iapCore = IAPCore(context.applicationContext, deviceEnvInfo, clientInfo, authData)\n            iapCoreCacheMap[key] =\n                IAPCoreCacheEntry(iapCore, System.currentTimeMillis() + EXPIRE_MS)\n            return iapCore\n        }\n    }\n\n    private fun getPreferredAccount(extraParams: Bundle?): Account {\n        val name = extraParams?.getString(\"accountName\")\n        name?.let {\n            extraParams.remove(\"accountName\")\n        }\n        return getGoogleAccount(context, name)\n            ?: throw RuntimeException(\"No Google account found.\")\n    }\n\n    private fun isBillingSupported(\n        apiVersion: Int,\n        type: String?,\n        packageName: String,\n        extraParams: Bundle?\n    ): Bundle {\n        if (!VendingPreferences.isBillingEnabled(context)) {\n            Log.w(TAG, \"isBillingSupported: Billing is disabled\")\n            return resultBundle(BillingResponseCode.BILLING_UNAVAILABLE, \"Billing is disabled\")\n        }\n        if (apiVersion < 3) {\n            return resultBundle(BillingResponseCode.BILLING_UNAVAILABLE, \"Client does not support the requesting billing API.\")\n        }\n        if (extraParams != null && apiVersion < 7) {\n            return resultBundle(BillingResponseCode.DEVELOPER_ERROR, \"ExtraParams was introduced in API version 7.\")\n        }\n        if (type.isNullOrBlank()) {\n            return resultBundle(BillingResponseCode.DEVELOPER_ERROR, \"SKU type can't be empty.\")\n        }\n        if (!typeList.contains(type)) {\n            return resultBundle(BillingResponseCode.DEVELOPER_ERROR, \"Invalid SKU type: $type\")\n        }\n        if (extraParams != null && !extraParams.isEmpty && extraParams.getBoolean(\"vr\") && type == \"subs\") {\n            return resultBundle(BillingResponseCode.BILLING_UNAVAILABLE, \"subscription is not supported in VR Mode.\")\n        }\n        return resultBundle(BillingResponseCode.OK, \"\")\n    }\n\n    override fun isBillingSupported(apiVersion: Int, packageName: String?, type: String?): Int {\n        val result = isBillingSupported(apiVersion, type, packageName!!, null)\n        Log.d(TAG, \"isBillingSupported(apiVersion=$apiVersion, packageName=$packageName, type=$type)=$result\")\n        return result.getInt(\"RESPONSE_CODE\")\n    }\n\n    override fun getSkuDetails(\n        apiVersion: Int,\n        packageName: String?,\n        type: String?,\n        skusBundle: Bundle?\n    ): Bundle {\n        Log.d(TAG, \"getSkuDetails(apiVersion=$apiVersion, packageName=$packageName, type=$type, skusBundle=$skusBundle)\")\n        return resultBundle(BillingResponseCode.BILLING_UNAVAILABLE, \"Not yet implemented\")\n    }\n\n    override fun getBuyIntent(\n        apiVersion: Int,\n        packageName: String?,\n        sku: String?,\n        type: String?,\n        developerPayload: String?\n    ): Bundle {\n        if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"getBuyIntent(apiVersion=$apiVersion, packageName=$packageName, sku=$sku, type=$type, developerPayload=$developerPayload)\")\n        return runCatching { getBuyIntentExtraParams(apiVersion, packageName!!, sku!!, type!!, developerPayload, null) }\n            .getOrDefault(resultBundle(BillingResponseCode.BILLING_UNAVAILABLE, \"Not yet implemented\"))\n    }\n\n    override fun getPurchases(\n        apiVersion: Int,\n        packageName: String?,\n        type: String?,\n        continuationToken: String?\n    ): Bundle {\n        if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"getPurchases(apiVersion=$apiVersion, packageName=$packageName, type=$type, continuationToken=$continuationToken)\")\n        return resultBundle(BillingResponseCode.BILLING_UNAVAILABLE, \"Not yet implemented\")\n    }\n\n    override fun consumePurchase(\n        apiVersion: Int,\n        packageName: String?,\n        purchaseToken: String?\n    ): Int {\n        Log.d(TAG, \"consumePurchase(apiVersion=$apiVersion, packageName=$packageName, purchaseToken=$purchaseToken)\")\n        return BillingResponseCode.BILLING_UNAVAILABLE\n    }\n\n    override fun isPromoEligible(apiVersion: Int, packageName: String?, type: String?): Int {\n        Log.d(TAG, \"isPromoEligible(apiVersion=$apiVersion, packageName=$packageName, type=$type)\")\n        return BillingResponseCode.BILLING_UNAVAILABLE\n    }\n\n    override fun getBuyIntentToReplaceSkus(\n        apiVersion: Int,\n        packageName: String?,\n        oldSkus: MutableList<String>?,\n        newSku: String?,\n        type: String?,\n        developerPayload: String?\n    ): Bundle {\n        Log.d(TAG, \"getBuyIntentToReplaceSkus(apiVersion=$apiVersion, packageName=$packageName, oldSkus=$oldSkus, newSku=$newSku, type=$type, developerPayload=$developerPayload)\")\n        return resultBundle(BillingResponseCode.BILLING_UNAVAILABLE, \"Not yet implemented\")\n    }\n\n    override fun getBuyIntentExtraParams(\n        apiVersion: Int,\n        packageName: String,\n        sku: String,\n        type: String,\n        developerPayload: String?,\n        extraParams: Bundle?\n    ): Bundle {\n        if (!VendingPreferences.isBillingEnabled(context)) {\n            Log.w(TAG, \"getBuyIntentExtraParams: Billing is disabled\")\n            return resultBundle(BillingResponseCode.BILLING_UNAVAILABLE, \"Billing is disabled\")\n        }\n        extraParams?.size()\n        Log.d(TAG, \"getBuyIntentExtraParams(apiVersion=$apiVersion, packageName=$packageName, sku=$sku, type=$type, developerPayload=$developerPayload, extraParams=$extraParams)\")\n\n\n        val skuSerializedDocIdList =\n            extraParams?.getStringArrayList(\"SKU_SERIALIZED_DOCID_LIST\")\n        skuSerializedDocIdList?.forEach {\n            if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"serializedDocId=$it\")\n        }\n        val skuOfferTypeList = extraParams?.getIntegerArrayList(\"SKU_OFFER_TYPE_LIST\")\n        skuOfferTypeList?.forEach {\n            if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"skuOfferType=$it\")\n        }\n        val skuOfferIdTokenList = extraParams?.getStringArrayList(\"SKU_OFFER_ID_TOKEN_LIST\")\n        skuOfferIdTokenList?.forEach {\n            if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"skuOfferIdToken=$it\")\n        }\n        val accountName = extraParams?.getString(\"accountName\")?.also {\n            if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"accountName=$it\")\n        }\n        val oldSkuPurchaseToken = extraParams?.getString(\"oldSkuPurchaseToken\")?.also {\n            if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"oldSkuPurchaseToken=$it\")\n        }\n        val oldSkuPurchaseId = extraParams?.getString(\"oldSkuPurchaseId\")?.also {\n            if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"oldSkuPurchaseId=$it\")\n        }\n\n        extraParams?.let {\n            it.remove(\"skusToReplace\")\n            it.remove(\"oldSkuPurchaseToken\")\n            it.remove(\"vr\")\n            it.remove(\"isDynamicSku\")\n            it.remove(\"rewardToken\")\n            it.remove(\"childDirected\")\n            it.remove(\"underAgeOfConsent\")\n            it.remove(\"additionalSkus\")\n            it.remove(\"additionalSkuTypes\")\n            it.remove(\"SKU_OFFER_ID_TOKEN_LIST\")\n            it.remove(\"SKU_OFFER_ID_LIST\")\n            it.remove(\"SKU_OFFER_TYPE_LIST\")\n            it.remove(\"SKU_SERIALIZED_DOCID_LIST\")\n            it.remove(\"oldSkuPurchaseId\")\n        }\n\n        val account = try {\n            getPreferredAccount(extraParams)\n        } catch (e: RuntimeException) {\n            return resultBundle(BillingResponseCode.BILLING_UNAVAILABLE, e.message)\n        }\n        val params = BuyFlowParams(\n            apiVersion = apiVersion,\n            sku = sku,\n            skuType = type,\n            developerPayload = developerPayload ?: \"\",\n            skuParams = bundleToMap(extraParams),\n            needAuth = SettingsManager(context).getAuthStatus(),\n            skuSerializedDockIdList = skuSerializedDocIdList,\n            skuOfferIdTokenList = skuOfferIdTokenList,\n            oldSkuPurchaseId = oldSkuPurchaseId,\n            oldSkuPurchaseToken = oldSkuPurchaseToken\n        )\n        val cacheEntryKey = \"${packageName}:${account.name}\"\n        buyFlowCacheMap[cacheEntryKey] =\n            BuyFlowCacheEntry(packageName, account, buyFlowParams = params)\n        val intent = Intent(context, InAppBillingHostActivity::class.java)\n        intent.putExtra(KEY_IAP_SHEET_UI_PARAM, cacheEntryKey)\n        val buyFlowPendingIntent = PendingIntentCompat.getActivity(context, requestCode, intent, FLAG_CANCEL_CURRENT, false)\n        return resultBundle(BillingResponseCode.OK, \"\", bundleOf(\"BUY_INTENT\" to buyFlowPendingIntent))\n    }\n\n    override fun getPurchaseHistory(\n        apiVersion: Int,\n        packageName: String?,\n        type: String?,\n        continuationToken: String?,\n        extraParams: Bundle?\n    ): Bundle {\n        if (!VendingPreferences.isBillingEnabled(context)) {\n            Log.w(TAG, \"getPurchaseHistory: Billing is disabled\")\n            return resultBundle(BillingResponseCode.BILLING_UNAVAILABLE, \"Billing is disabled\")\n        }\n        extraParams?.size()\n        Log.d(TAG, \"getPurchaseHistory(apiVersion=$apiVersion, packageName=$packageName, type=$type, continuationToken=$continuationToken, extraParams=$extraParams)\")\n        val account = try {\n            getPreferredAccount(extraParams)\n        } catch (e: RuntimeException) {\n            return resultBundle(BillingResponseCode.BILLING_UNAVAILABLE, e.message)\n        }\n        val params = GetPurchaseHistoryParams(\n            apiVersion = apiVersion,\n            type = type!!,\n            continuationToken = continuationToken,\n            extraParams = bundleToMap(extraParams)\n        )\n        val coreResult = try {\n            val deferred = CoroutineScope(Dispatchers.IO).async {\n                createIAPCore(context, account, packageName!!).getPurchaseHistory(params)\n            }\n            runBlocking {\n                deferred.await()\n            }\n        } catch (e: RuntimeException) {\n            return resultBundle(BillingResponseCode.DEVELOPER_ERROR, e.message)\n        } catch (e: Exception) {\n            Log.e(TAG, \"getPurchaseHistory\", e)\n            return resultBundle(BillingResponseCode.DEVELOPER_ERROR, \"Internal error.\")\n        }\n        if (coreResult.getCode() == BillingResponseCode.OK) {\n            val itemList = ArrayList<String>()\n            val dataList = ArrayList<String>()\n            val signatureList = ArrayList<String>()\n            coreResult.purchaseHistoryList?.forEach {\n                itemList.add(it.sku)\n                dataList.add(it.jsonData)\n                signatureList.add(it.signature)\n            }\n            val result = Bundle()\n            result.putStringArrayList(\"INAPP_PURCHASE_ITEM_LIST\", itemList)\n            result.putStringArrayList(\"INAPP_PURCHASE_DATA_LIST\", dataList)\n            result.putStringArrayList(\"INAPP_DATA_SIGNATURE_LIST\", signatureList)\n            if (!coreResult.continuationToken.isNullOrEmpty()) {\n                result.putString(\"INAPP_CONTINUATION_TOKEN\", coreResult.continuationToken)\n            }\n            return resultBundle(BillingResponseCode.OK, \"\", result)\n        }\n        return coreResult.resultMap.toBundle()\n    }\n\n    override fun isBillingSupportedExtraParams(\n        apiVersion: Int,\n        packageName: String?,\n        type: String?,\n        extraParams: Bundle?\n    ): Int {\n        extraParams?.size()\n        val result = isBillingSupported(apiVersion, type, packageName!!, extraParams)\n        Log.d(TAG, \"isBillingSupportedExtraParams(apiVersion=$apiVersion, packageName=$packageName, type=$type, extraParams=$extraParams)=$result\")\n        return result.getInt(\"RESPONSE_CODE\")\n    }\n\n    override fun getPurchasesExtraParams(\n        apiVersion: Int,\n        packageName: String?,\n        type: String?,\n        continuationToken: String?,\n        extraParams: Bundle?\n    ): Bundle {\n        if (!VendingPreferences.isBillingEnabled(context)) {\n            Log.w(TAG, \"getPurchasesExtraParams: Billing is disabled\")\n            return resultBundle(BillingResponseCode.BILLING_UNAVAILABLE, \"Billing is disabled\")\n        }\n        extraParams?.size()\n        Log.d(TAG, \"getPurchasesExtraParams(apiVersion=$apiVersion, packageName=$packageName, type=$type, continuationToken=$continuationToken, extraParams=$extraParams)\")\n        if (apiVersion < 7 && extraParams != null) {\n            return resultBundle(BillingResponseCode.DEVELOPER_ERROR, \"Parameter check error.\")\n        }\n        val account = try {\n            getPreferredAccount(extraParams)\n        } catch (e: RuntimeException) {\n            return resultBundle(BillingResponseCode.BILLING_UNAVAILABLE, e.message)\n        }\n        val enablePendingPurchases = extraParams?.getBoolean(\"enablePendingPurchases\", false) ?: false\n        val itemList = ArrayList<String>()\n        val dataList = ArrayList<String>()\n        val signatureList = ArrayList<String>()\n        PurchaseManager.queryPurchases(account, packageName!!, type!!).filter {\n            if (it.type == \"subs\" && it.expireAt < System.currentTimeMillis()) return@filter false\n            true\n        }.forEach {\n            if (enablePendingPurchases || it.purchaseState != 4) {\n                itemList.add(it.sku)\n                dataList.add(it.jsonData)\n                signatureList.add(it.signature)\n            }\n        }\n        val result = Bundle()\n        result.putStringArrayList(\"INAPP_PURCHASE_ITEM_LIST\", itemList)\n        result.putStringArrayList(\"INAPP_PURCHASE_DATA_LIST\", dataList)\n        result.putStringArrayList(\"INAPP_DATA_SIGNATURE_LIST\", signatureList)\n        return resultBundle(BillingResponseCode.OK, \"\", result)\n    }\n\n    override fun consumePurchaseExtraParams(\n        apiVersion: Int,\n        packageName: String?,\n        purchaseToken: String,\n        extraParams: Bundle?\n    ): Bundle {\n        if (!VendingPreferences.isBillingEnabled(context)) {\n            Log.w(TAG, \"consumePurchaseExtraParams: Billing is disabled\")\n            return resultBundle(BillingResponseCode.BILLING_UNAVAILABLE, \"Billing is disabled\")\n        }\n        extraParams?.size()\n        Log.d(TAG, \"consumePurchaseExtraParams(apiVersion=$apiVersion, packageName=$packageName, purchaseToken=$purchaseToken, extraParams=$extraParams)\")\n        val account = try {\n            getPreferredAccount(extraParams)\n        } catch (e: RuntimeException) {\n            return resultBundle(BillingResponseCode.BILLING_UNAVAILABLE, e.message)\n        }\n        val params = ConsumePurchaseParams(\n            apiVersion = apiVersion,\n            purchaseToken = purchaseToken,\n            extraParams = bundleToMap(extraParams)\n        )\n        val coreResult = try {\n            val deferred = CoroutineScope(Dispatchers.IO).async {\n                val coreResult = createIAPCore(context, account, packageName!!).consumePurchase(params)\n                if (coreResult.getCode() == BillingResponseCode.OK) {\n                    PurchaseManager.removePurchase(purchaseToken)\n                }\n                coreResult\n            }\n            runBlocking { deferred.await() }\n        } catch (e: RuntimeException) {\n            return resultBundle(BillingResponseCode.DEVELOPER_ERROR, e.message)\n        } catch (e: Exception) {\n            Log.e(TAG, \"consumePurchaseExtraParams\", e)\n            return resultBundle(BillingResponseCode.DEVELOPER_ERROR, \"Internal error.\")\n        }\n\n        return coreResult.resultMap.toBundle()\n    }\n\n    override fun getPriceChangeConfirmationIntent(\n        apiVersion: Int,\n        packageName: String?,\n        sku: String?,\n        type: String?,\n        extraParams: Bundle?\n    ): Bundle {\n        extraParams?.size()\n        Log.d(TAG, \"getPriceChangeConfirmationIntent(apiVersion=$apiVersion, packageName=$packageName, sku=$sku, type=$type, extraParams=$extraParams)\")\n        return resultBundle(BillingResponseCode.BILLING_UNAVAILABLE, \"Not yet implemented\")\n    }\n\n    override fun getSkuDetailsExtraParams(\n        apiVersion: Int,\n        packageName: String?,\n        type: String?,\n        skuBundle: Bundle?,\n        extraParams: Bundle?\n    ): Bundle {\n        if (!VendingPreferences.isBillingEnabled(context)) {\n            Log.w(TAG, \"getSkuDetailsExtraParams: Billing is disabled\")\n            return resultBundle(BillingResponseCode.BILLING_UNAVAILABLE, \"Billing is disabled\")\n        }\n        extraParams?.size()\n        skuBundle?.size()\n        Log.d(TAG, \"getSkuDetailsExtraParams(apiVersion=$apiVersion, packageName=$packageName, type=$type, skusBundle=$skuBundle, extraParams=$extraParams)\")\n        val account = try {\n            getPreferredAccount(extraParams)\n        } catch (e: RuntimeException) {\n            return resultBundle(BillingResponseCode.BILLING_UNAVAILABLE, e.message)\n        }\n        val idList = skuBundle?.getStringArrayList(\"ITEM_ID_LIST\")\n        val dynamicPriceTokensList = skuBundle?.getStringArrayList(\"DYNAMIC_PRICE_TOKENS_LIST\")\n        if (idList.isNullOrEmpty()) {\n            Log.e(TAG, \"Input Error: skusBundle must contain an array associated with key ITEM_ID_LIST.\")\n            return resultBundle(BillingResponseCode.DEVELOPER_ERROR, \"SKU bundle must contain sku list\")\n        }\n        idList.sort()\n        if (dynamicPriceTokensList != null && dynamicPriceTokensList.isEmpty()) {\n            Log.e(TAG, \"Input Error: skusBundle array associated with key ITEM_ID_LIST or key DYNAMIC_PRICE_TOKENS_LIST cannot be empty.\")\n            return resultBundle(BillingResponseCode.DEVELOPER_ERROR, \"SKU bundle must contain sku list\")\n        }\n        if (apiVersion < 9 && extraParams?.isEmpty == false) {\n            return resultBundle(BillingResponseCode.DEVELOPER_ERROR, \"Must specify an API version >= 9 to use this API.\")\n        }\n        val params = GetSkuDetailsParams(\n            apiVersion = apiVersion,\n            skuType = type!!,\n            skuIdList = idList,\n            skuPkgName = extraParams?.getString(\"SKU_PACKAGE_NAME\")?.also {\n                extraParams.remove(\"SKU_PACKAGE_NAME\")\n            } ?: \"\",\n            sdkVersion = extraParams?.getString(\"playBillingLibraryVersion\") ?: \"\",\n            multiOfferSkuDetail = extraParams?.let { bundleToMap(it) } ?: emptyMap()\n        )\n\n        val coreResult = try {\n            val deferred = CoroutineScope(Dispatchers.IO).async {\n                createIAPCore(context, account, packageName!!).getSkuDetails(params)\n            }\n            runBlocking { deferred.await() }\n        } catch (e: RuntimeException) {\n            Log.e(TAG, \"getSkuDetailsExtraParams\", e)\n            return resultBundle(BillingResponseCode.DEVELOPER_ERROR, e.message)\n        } catch (e: Exception) {\n            Log.e(TAG, \"getSkuDetailsExtraParams\", e)\n            return resultBundle(BillingResponseCode.DEVELOPER_ERROR, \"Internal error.\")\n        }\n\n        coreResult.let { detailsResult ->\n            val details = ArrayList(detailsResult.skuDetailsList.map { it.jsonDetails })\n            if (detailsResult.getCode() == BillingResponseCode.OK) {\n                return resultBundle(BillingResponseCode.OK, \"\", bundleOf(\"DETAILS_LIST\" to details))\n            } else {\n                return resultBundle(detailsResult.getCode(), detailsResult.getMessage())\n            }\n        }\n    }\n\n    override fun acknowledgePurchase(\n        apiVersion: Int,\n        packageName: String?,\n        purchaseToken: String?,\n        extraParams: Bundle?\n    ): Bundle {\n        if (!VendingPreferences.isBillingEnabled(context)) {\n            Log.w(TAG, \"acknowledgePurchase: Billing is disabled\")\n            return resultBundle(BillingResponseCode.BILLING_UNAVAILABLE, \"Billing is disabled\")\n        }\n        extraParams?.size()\n        Log.d(TAG, \"acknowledgePurchase(apiVersion=$apiVersion, packageName=$packageName, purchaseToken=$purchaseToken, extraParams=$extraParams)\")\n        val account = try {\n            getPreferredAccount(extraParams)\n        } catch (e: RuntimeException) {\n            return resultBundle(BillingResponseCode.BILLING_UNAVAILABLE, e.message)\n        }\n        val params = AcknowledgePurchaseParams(\n            apiVersion = apiVersion,\n            purchaseToken = purchaseToken!!,\n            extraParams = bundleToMap(extraParams)\n        )\n        val coreResult = try {\n            val deferred = CoroutineScope(Dispatchers.IO).async {\n                val coreResult = createIAPCore(context, account, packageName!!).acknowledgePurchase(params)\n                if (coreResult.getCode() == BillingResponseCode.OK && coreResult.purchaseItem != null) {\n                    PurchaseManager.updatePurchase(coreResult.purchaseItem)\n                }\n                coreResult\n            }\n            runBlocking { deferred.await() }\n        } catch (e: RuntimeException) {\n            return resultBundle(BillingResponseCode.DEVELOPER_ERROR, e.message)\n        } catch (e: Exception) {\n            Log.e(TAG, \"acknowledgePurchase\", e)\n            return resultBundle(BillingResponseCode.DEVELOPER_ERROR, \"Internal error.\")\n        }\n\n        return coreResult.resultMap.toBundle()\n    }\n\n    override fun o(\n        apiVersion: Int,\n        packageName: String?,\n        arg3: String?,\n        extraParams: Bundle?\n    ): Bundle {\n        extraParams?.size()\n        Log.d(TAG, \"o(apiVersion=$apiVersion, packageName=$packageName, arg3=$arg3, extraParams=$extraParams)\")\n        return resultBundle(BillingResponseCode.BILLING_UNAVAILABLE, \"Not yet implemented\")\n    }\n\n    override fun showInAppMessages(apiVersion: Int, packageName: String?, extraParams: Bundle?, callback: IInAppBillingServiceCallback?) {\n        Log.d(TAG, \"showInAppMessages Not yet implemented\")\n    }\n\n    override fun getBillingConfig(apiVersion: Int, packageName: String?, bundle: Bundle?, callback: IInAppBillingGetBillingConfigCallback) {\n        Log.d(TAG, \"getBillingConfig apiVersion:$apiVersion packageName:$packageName bundle:$bundle\")\n        val result = resultBundle(BillingResponseCode.OK, \"\", bundleOf(\n            \"BILLING_CONFIG\" to JSONObject().apply { put(\"countryCode\", Locale.getDefault().country) }.toString()\n        ))\n        callback.callback(result)\n    }\n\n    override fun isAlternativeBillingOnlyAvailable(\n        apiVersion: Int,\n        packageName: String?,\n        extraParams: Bundle?,\n        callback: IInAppBillingIsAlternativeBillingOnlyAvailableCallback?\n    ) {\n        Log.d(TAG, \"isAlternativeBillingOnlyAvailable Not yet implemented\")\n    }\n\n    override fun createAlternativeBillingOnlyToken(\n        apiVersion: Int,\n        packageName: String?,\n        extraParams: Bundle?,\n        callback: IInAppBillingCreateAlternativeBillingOnlyTokenCallback?\n    ) {\n        Log.d(TAG, \"createAlternativeBillingOnlyToken Not yet implemented\")\n    }\n\n    override fun getAlternativeBillingOnlyDialogIntent(\n        apiVersion: Int,\n        packageName: String?,\n        extraParams: Bundle?,\n        callback: IInAppBillingGetAlternativeBillingOnlyDialogIntentCallback?\n    ) {\n        Log.d(TAG, \"getAlternativeBillingOnlyDialogIntent Not yet implemented\")\n        callback?.callback(Bundle())\n    }\n\n    override fun isExternalOfferAvailable(\n        apiVersion: Int,\n        packageName: String?,\n        extraParams: Bundle?,\n        callback: IInAppBillingIsExternalPaymentAvailableCallback?\n    ) {\n        Log.d(TAG, \"isExternalOfferAvailable Not yet implemented\")\n    }\n\n    override fun createExternalOfferReportingDetails(\n        apiVersion: Int,\n        packageName: String?,\n        extraParams: Bundle?,\n        callback: IInAppBillingCreateExternalPaymentReportingDetailsCallback?\n    ) {\n        Log.d(TAG, \"createExternalOfferReportingDetails Not yet implemented\")\n    }\n\n    override fun showExternalOfferInformationDialog(\n        apiVersion: Int,\n        packageName: String?,\n        extraParams: Bundle?,\n        callback: IInAppBillingGetExternalPaymentDialogIntentCallback?\n    ) {\n        Log.d(TAG, \"showExternalOfferInformationDialog Not yet implemented\")\n    }\n\n    override fun delegateToBackend(bundle: Bundle?, callback: IInAppBillingDelegateToBackendCallback?) {\n        Log.d(TAG, \"delegateToBackend Not yet implemented\")\n    }\n\n    override fun initialize(\n        apiVersion: Int,\n        packageName: String?,\n        extraParams: Bundle?,\n        callback: IInAppBillingInitializeCallback?\n    ) {\n        extraParams?.keySet()\n        Log.w(TAG, \"initialize: apiVersion: $apiVersion packageName:$packageName params:$extraParams\")\n        callback?.callback(resultBundle(BillingResponseCode.OK, \"\", bundleOf(\n            \"BILLING_API_VERSION_KEY\" to apiVersion\n        )))\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =\n        warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n}\n"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/PurchaseActivity.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.vending.billing;\n\nimport static org.microg.vending.billing.ui.PlayWebViewActivityKt.KEY_WEB_VIEW_ACCOUNT;\nimport static org.microg.vending.billing.ui.PlayWebViewActivityKt.KEY_WEB_VIEW_ACTION;\nimport static org.microg.vending.billing.ui.PlayWebViewActivityKt.KEY_WEB_VIEW_OPEN_URL;\n\nimport android.accounts.Account;\nimport android.accounts.AccountManager;\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.text.TextUtils;\nimport android.widget.Toast;\n\nimport androidx.annotation.Nullable;\n\nimport com.android.vending.R;\n\nimport org.microg.gms.auth.AuthConstants;\nimport org.microg.vending.billing.ui.PlayWebViewActivity;\nimport org.microg.vending.billing.ui.WebViewAction;\n\npublic class PurchaseActivity extends Activity {\n    @Override\n    protected void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        String authAccount = getIntent().getStringExtra(\"authAccount\");\n        AccountManager accountManager = AccountManager.get(this);\n        Account[] accounts = accountManager.getAccountsByType(AuthConstants.DEFAULT_ACCOUNT_TYPE);\n        String referralUrl = getIntent().getStringExtra(\"referral_url\");\n        if (!TextUtils.isEmpty(referralUrl) && accounts.length > 0) {\n            Account currAccount = null;\n            for (Account account : accounts) {\n                if (account.name.equals(authAccount)) {\n                    currAccount = account;\n                    break;\n                }\n            }\n            if (!referralUrl.startsWith(\"https\")) {\n                referralUrl = referralUrl.replace(\"http\", \"https\");\n            }\n            //Perform host judgment on URLs to prevent risky URLs from being exploited\n            if (referralUrl.startsWith(\"https://play.google.com/store\")) {\n                Intent intent = new Intent(this, PlayWebViewActivity.class);\n                intent.putExtra(KEY_WEB_VIEW_ACTION, WebViewAction.OPEN_GP_PRODUCT_DETAIL.toString());\n                intent.putExtra(KEY_WEB_VIEW_OPEN_URL, referralUrl);\n                intent.putExtra(KEY_WEB_VIEW_ACCOUNT, currAccount);\n                startActivity(intent);\n            } else {\n                Toast.makeText(this, getString(R.string.pay_disabled), Toast.LENGTH_SHORT).show();\n            }\n        } else {\n            Toast.makeText(this, getString(R.string.pay_disabled), Toast.LENGTH_SHORT).show();\n        }\n        finish();\n    }\n}\n"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/PurchaseManager.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.vending.billing\n\nimport android.accounts.Account\nimport android.content.ContentValues\nimport android.content.Context\nimport android.database.sqlite.SQLiteDatabase\nimport android.database.sqlite.SQLiteOpenHelper\nimport org.microg.vending.billing.core.PurchaseItem\n\nobject PurchaseManager {\n    private val database by lazy { PurchaseDB(ContextProvider.context) }\n\n    fun queryPurchases(account: Account, pkgName: String, type: String): List<PurchaseItem> =\n        database.queryPurchases(account, pkgName, type)\n\n    fun updatePurchase(purchaseItem: PurchaseItem) = database.updatePurchase(purchaseItem)\n\n    fun removePurchase(purchaseToken: String) = database.removePurchase(purchaseToken)\n\n    fun addPurchase(account: Account, pkgName: String, purchaseItem: PurchaseItem) =\n        database.addPurchase(account, pkgName, purchaseItem)\n\n    private class PurchaseDB(mContext: Context?) : SQLiteOpenHelper(\n        mContext, DATABASE_NAME, null, DATABASE_VERSION\n    ) {\n        @Synchronized\n        fun queryPurchases(account: Account, pkgName: String, type: String): List<PurchaseItem> {\n            val result = mutableListOf<PurchaseItem>()\n            val cursor = readableDatabase.query(\n                PURCHASE_TABLE,\n                null,\n                \"account=? and package_name=? and type=?\",\n                arrayOf(account.name, pkgName, type),\n                null,\n                null,\n                null\n            )\n            cursor?.use {\n                while (it.moveToNext()) {\n                    val item = PurchaseItem(\n                        it.getString(2),\n                        it.getString(3),\n                        it.getString(1),\n                        it.getString(4),\n                        it.getInt(5),\n                        it.getString(6),\n                        it.getString(7),\n                        it.getLong(8),\n                        it.getLong(9)\n                    )\n                    result.add(item)\n                }\n            }\n\n            return result\n        }\n\n        @Synchronized\n        fun updatePurchase(purchaseItem: PurchaseItem): Int {\n            val upItem = ContentValues()\n            upItem.put(\"purchase_state\", purchaseItem.purchaseState)\n            upItem.put(\"json_data\", purchaseItem.jsonData)\n            upItem.put(\"signature\", purchaseItem.signature)\n            return writableDatabase.update(\n                PURCHASE_TABLE,\n                upItem,\n                \"purchase_token=?\",\n                arrayOf(purchaseItem.purchaseToken)\n            )\n        }\n\n        @Synchronized\n        fun removePurchase(purchaseToken: String) {\n            writableDatabase.delete(PURCHASE_TABLE, \"purchase_token=?\", arrayOf(purchaseToken))\n        }\n\n        @Synchronized\n        fun addPurchase(account: Account, pkgName: String, purchaseItem: PurchaseItem) {\n            val cv = ContentValues()\n            cv.put(\"account\", account.name)\n            cv.put(\"package_name\", pkgName)\n            cv.put(\"type\", purchaseItem.type)\n            cv.put(\"sku\", purchaseItem.sku)\n            cv.put(\"purchase_token\", purchaseItem.purchaseToken)\n            cv.put(\"purchase_state\", purchaseItem.purchaseState)\n            cv.put(\"json_data\", purchaseItem.jsonData)\n            cv.put(\"signature\", purchaseItem.signature)\n            cv.put(\"start_at\", purchaseItem.startAt)\n            cv.put(\"expire_at\", purchaseItem.expireAt)\n            writableDatabase.insertWithOnConflict(\n                PURCHASE_TABLE,\n                null,\n                cv,\n                SQLiteDatabase.CONFLICT_REPLACE\n            )\n        }\n\n        override fun onCreate(db: SQLiteDatabase) {\n            db.execSQL(CREATE_TABLE_PURCHASES)\n        }\n\n        override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {}\n\n        companion object {\n            private const val TAG = \"PurchaseDB\"\n            private const val DATABASE_NAME = \"purchase.db\"\n            private const val PURCHASE_TABLE = \"purchases\"\n            private const val DATABASE_VERSION = 1\n            private const val CREATE_TABLE_PURCHASES =\n                \"CREATE TABLE IF NOT EXISTS $PURCHASE_TABLE ( \" +\n                        \"account TEXT, \" +\n                        \"package_name TEXT, \" +\n                        \"type TEXT, \" +\n                        \"sku TEXT, \" +\n                        \"purchase_token TEXT, \" +\n                        \"purchase_state INTEGER, \" +\n                        \"json_data TEXT, \" +\n                        \"signature TEXT, \" +\n                        \"start_at INTEGER, \" +\n                        \"expire_at INTEGER, \" +\n                        \"PRIMARY KEY (purchase_token));\"\n        }\n    }\n}"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/SettingsManager.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.vending.billing\n\nimport android.content.Context\nimport android.content.SharedPreferences\nimport android.util.Log\nimport androidx.preference.PreferenceManager\n\n// TODO: Better name?\nprivate const val AUTH_STATUS_KEY = \"key_auth_status\"\n\nclass SettingsManager(private val context: Context) {\n    private val preferences: SharedPreferences by lazy {\n        PreferenceManager.getDefaultSharedPreferences(context.applicationContext)\n    }\n\n    fun setAuthStatus(needAuth: Boolean) {\n        if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"setAuthStatus: $needAuth\")\n        val editor = preferences.edit()\n        editor.putBoolean(AUTH_STATUS_KEY, needAuth)\n        editor.apply()\n    }\n\n    fun getAuthStatus(): Boolean {\n        return preferences.getBoolean(AUTH_STATUS_KEY, true)\n    }\n}"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/Utils.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.vending.billing\n\nimport android.accounts.Account\nimport android.accounts.AccountManager\nimport android.annotation.SuppressLint\nimport android.content.Context\nimport android.content.IntentFilter\nimport android.content.pm.PackageManager\nimport android.icu.util.TimeZone\nimport android.net.ConnectivityManager\nimport android.net.Uri\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.Bundle\nimport android.os.SystemClock\nimport android.provider.Settings\nimport android.util.Base64\nimport android.util.Log\nimport android.view.WindowManager\nimport androidx.core.app.ActivityCompat\nimport androidx.core.os.bundleOf\nimport com.android.billingclient.api.BillingClient.BillingResponseCode\nimport org.microg.gms.profile.Build\nimport org.microg.gms.profile.ProfileManager\nimport org.microg.gms.utils.digest\nimport org.microg.gms.utils.getExtendedPackageInfo\nimport org.microg.gms.utils.toBase64\nimport org.microg.vending.billing.core.*\nimport java.util.*\nimport kotlin.collections.Collection\nimport kotlin.collections.List\nimport kotlin.collections.Map\nimport kotlin.collections.Set\nimport kotlin.collections.any\nimport kotlin.collections.filter\nimport kotlin.collections.firstOrNull\nimport kotlin.collections.joinToString\nimport kotlin.collections.map\nimport kotlin.collections.mutableListOf\nimport kotlin.collections.mutableMapOf\nimport kotlin.collections.set\nimport kotlin.collections.toByteArray\nimport kotlin.collections.toList\nimport kotlin.collections.toSet\nimport kotlin.collections.toTypedArray\n\nfun Map<String, Any?>.toBundle(): Bundle = bundleOf(*this.toList().toTypedArray())\n\n/**\n * Returns true if the receiving collection contains any of the specified elements.\n *\n * @param elements the elements to look for in the receiving collection.\n * @return true if any element in [elements] is found in the receiving collection.\n */\nfun <T> Collection<T>.containsAny(vararg elements: T): Boolean {\n    return containsAny(elements.toSet())\n}\n\n/**\n * Returns true if the receiving collection contains any of the elements in the specified collection.\n *\n * @param elements the elements to look for in the receiving collection.\n * @return true if any element in [elements] is found in the receiving collection.\n */\nfun <T> Collection<T>.containsAny(elements: Collection<T>): Boolean {\n    val set = if (elements is Set) elements else elements.toSet()\n    return any(set::contains)\n}\n\nfun String.decodeHex(): ByteArray {\n    check(length % 2 == 0) { \"Must have an even length\" }\n    return chunked(2)\n        .map { it.toInt(16).toByte() }\n        .toByteArray()\n}\n\nfun resultBundle(@BillingResponseCode code: Int, msg: String?, data: Bundle = Bundle.EMPTY): Bundle {\n    val res = bundleOf(\n        \"RESPONSE_CODE\" to code,\n        \"DEBUG_MESSAGE\" to msg\n    )\n    res.putAll(data)\n    Log.d(TAG, \"Result: $res\")\n    return res\n}\n\n@SuppressLint(\"MissingPermission\")\nfun getDeviceIdentifier(context: Context): String {\n    // TODO: Improve dummy data\n    val deviceId = DeviceIdentifier.meid /*try {\n        (context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager?)?.let {\n            it.subscriberId ?: it.deviceId\n        }\n    } catch (e: Exception) {\n        null\n    }*/\n    if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"getDeviceIdentifier deviceId: $deviceId\")\n    return deviceId.toByteArray(Charsets.UTF_8).digest(\"SHA-1\").toBase64(Base64.URL_SAFE + Base64.NO_WRAP + Base64.NO_PADDING)\n}\n\nfun getGoogleAccount(context: Context, name: String? = null): Account? {\n    var accounts =\n        AccountManager.get(context).getAccountsByType(DEFAULT_ACCOUNT_TYPE).toList()\n    name?.let { accounts = accounts.filter { it.name == name } }\n    if (accounts.isEmpty())\n        return null\n    return accounts[0]\n}\n\nfun createClient(context: Context, pkgName: String): ClientInfo? {\n    return try {\n        val packageInfo = context.packageManager.getExtendedPackageInfo(pkgName)\n        ClientInfo(\n            pkgName,\n            packageInfo.certificates.firstOrNull()?.digest(\"MD5\")?.toBase64(Base64.URL_SAFE + Base64.NO_WRAP + Base64.NO_PADDING) ?: \"\",\n            packageInfo.shortVersionCode\n        )\n    } catch (e: Exception) {\n        if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"createClient\", e)\n        null\n    }\n}\n\nfun bundleToMap(bundle: Bundle?): Map<String, Any> {\n    val result = mutableMapOf<String, Any>()\n    if (bundle == null)\n        return result\n    for (key in bundle.keySet()) {\n        bundle.get(key)?.let {\n            result[key] = it\n        }\n    }\n    return result\n}\n\nfun getDisplayInfo(context: Context): DisplayMetrics? {\n    return try {\n        val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager\n        if (windowManager != null) {\n            val displayMetrics = android.util.DisplayMetrics()\n            windowManager.defaultDisplay.getRealMetrics(displayMetrics)\n            return DisplayMetrics(\n                displayMetrics.widthPixels,\n                displayMetrics.heightPixels,\n                displayMetrics.xdpi,\n                displayMetrics.ydpi,\n                displayMetrics.densityDpi\n            )\n        }\n        return DisplayMetrics(\n            context.resources.displayMetrics.widthPixels,\n            context.resources.displayMetrics.heightPixels,\n            context.resources.displayMetrics.xdpi,\n            context.resources.displayMetrics.ydpi,\n            context.resources.displayMetrics.densityDpi\n        )\n    } catch (e: Exception) {\n        null\n    }\n}\n\n// TODO: Improve privacy\nfun getBatteryLevel(context: Context): Int {\n    var batteryLevel = -1;\n    val intentFilter = IntentFilter(\"android.intent.action.BATTERY_CHANGED\")\n    context.registerReceiver(null, intentFilter)?.let {\n        val level = it.getIntExtra(\"level\", -1)\n        val scale = it.getIntExtra(\"scale\", -1)\n        if (scale > 0) {\n            batteryLevel = level * 100 / scale\n        }\n    }\n    if (batteryLevel == -1 && SDK_INT >= 33) {\n        context.registerReceiver(null, intentFilter, Context.RECEIVER_EXPORTED)?.let {\n            val level = it.getIntExtra(\"level\", -1)\n            val scale = it.getIntExtra(\"scale\", -1)\n            if (scale > 0) {\n                batteryLevel = level * 100 / scale\n            }\n        }\n    }\n    return batteryLevel\n}\n\nfun getTelephonyData(context: Context): TelephonyData? {\n    // TODO: Dummy data\n    return null /*try {\n        context.getSystemService(Context.TELEPHONY_SERVICE)?.let {\n            val telephonyManager = it as TelephonyManager\n            return TelephonyData(\n                telephonyManager.simOperatorName!!,\n                DeviceIdentifier.meid,\n                telephonyManager.networkOperator!!,\n                telephonyManager.simOperator!!,\n                telephonyManager.phoneType\n            )\n        }\n    } catch (e: Exception) {\n        if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"getTelephonyData\", e)\n        null\n    }*/\n}\n\nfun hasPermissions(context: Context, permissions: List<String>): Boolean {\n    for (permission in permissions) {\n        if (ActivityCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED)\n            return false\n    }\n    return true\n}\n\n@SuppressLint(\"MissingPermission\")\nfun getLocationData(context: Context): LocationData? {\n    // TODO: Dummy data\n    return null /*try {\n        (context.getSystemService(Context.LOCATION_SERVICE) as LocationManager?)?.let { locationManager ->\n            if (hasPermissions(\n                    context,\n                    listOf(\n                        Manifest.permission.ACCESS_FINE_LOCATION,\n                        Manifest.permission.ACCESS_COARSE_LOCATION\n                    )\n                )\n            ) {\n                locationManager.getLastKnownLocation(\"network\")?.let { location ->\n                    return LocationData(\n                        location.altitude,\n                        location.latitude,\n                        location.longitude,\n                        location.accuracy,\n                        location.time.toDouble()\n                    )\n                }\n            } else {\n                null\n            }\n        }\n    } catch (e: Exception) {\n        if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"getLocationData\", e)\n        null\n    }*/\n}\n\nfun getNetworkData(context: Context): NetworkData {\n    val connectivityManager =\n        context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager?\n    var linkDownstreamBandwidth: Long = 0\n    var linkUpstreamBandwidth: Long = 0\n    // TODO: Dummy data\n    /*\n    if (hasPermissions(context, listOf(Manifest.permission.ACCESS_NETWORK_STATE)) && SDK_INT >= 23) {\n        connectivityManager?.getNetworkCapabilities(connectivityManager.activeNetwork)?.let {\n            linkDownstreamBandwidth = (it.linkDownstreamBandwidthKbps * 1000 / 8).toLong()\n            linkUpstreamBandwidth = (it.linkUpstreamBandwidthKbps * 1000 / 8).toLong()\n        }\n    }\n     */\n    val isActiveNetworkMetered = connectivityManager?.isActiveNetworkMetered ?: false\n    val netAddressList = mutableListOf<String>()\n    // TODO: Dummy data\n    /*try {\n        NetworkInterface.getNetworkInterfaces()?.let { enumeration ->\n            while (true) {\n                if (!enumeration.hasMoreElements()) {\n                    break\n                }\n                val enumeration1 = enumeration.nextElement().inetAddresses\n                while (enumeration1.hasMoreElements()) {\n                    val inetAddress = enumeration1.nextElement() as InetAddress\n                    if (inetAddress.isLoopbackAddress) {\n                        continue\n                    }\n                    netAddressList.add(inetAddress.hostAddress)\n                }\n            }\n        }\n    } catch (socketException: NullPointerException) {\n        if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"getNetworkData:${socketException.message}\")\n    }*/\n    return NetworkData(\n        linkDownstreamBandwidth,\n        linkUpstreamBandwidth,\n        isActiveNetworkMetered,\n        netAddressList\n    )\n}\n\n@SuppressLint(\"HardwareIds\")\nfun getAndroidId(context: Context): String {\n    return Settings.Secure.getString(context.contentResolver, Settings.Secure.ANDROID_ID) ?: \"\"\n}\n\nfun getUserAgent(): String {\n    return \"Android-Finsky/${Uri.encode(VENDING_VERSION_NAME)} (api=3,versionCode=$VENDING_VERSION_CODE,sdk=${Build.VERSION.SDK_INT},device=${Build.DEVICE},hardware=${Build.HARDWARE},product=${Build.PRODUCT},platformVersionRelease=${Build.VERSION.RELEASE},model=${Uri.encode(Build.MODEL)},buildId=${Build.ID},isWideScreen=0,supportedAbis=${Build.SUPPORTED_ABIS.joinToString(\";\")})\"\n}\n\nfun createDeviceEnvInfo(context: Context): DeviceEnvInfo? {\n    try {\n        val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0)\n        return DeviceEnvInfo(\n            gpVersionCode = VENDING_VERSION_CODE,\n            gpVersionName = VENDING_VERSION_NAME,\n            gpPkgName = VENDING_PACKAGE_NAME,\n            androidId = getAndroidId(context),\n            biometricSupport = true,\n            biometricSupportCDD = true,\n            deviceId = getDeviceIdentifier(context),\n            serialNo = Build.SERIAL ?: \"\",\n            locale = Locale.getDefault(),\n            userAgent = getUserAgent(),\n            gpLastUpdateTime = packageInfo.lastUpdateTime,\n            gpFirstInstallTime = packageInfo.firstInstallTime,\n            gpSourceDir = packageInfo.applicationInfo!!.sourceDir!!,\n            device = Build.DEVICE ?: \"\",\n            displayMetrics = getDisplayInfo(context),\n            telephonyData = getTelephonyData(context),\n            product = Build.PRODUCT ?: \"\",\n            model = Build.MODEL ?: \"\",\n            manufacturer = Build.MANUFACTURER ?: \"\",\n            fingerprint = Build.FINGERPRINT ?: \"\",\n            release = Build.VERSION.RELEASE ?: \"\",\n            brand = Build.BRAND ?: \"\",\n            batteryLevel = getBatteryLevel(context),\n            timeZoneOffset = if (SDK_INT >= 24) TimeZone.getDefault().rawOffset.toLong() else 0,\n            locationData = getLocationData(context),\n            isAdbEnabled = false, //Settings.Global.getInt(context.contentResolver, \"adb_enabled\", 0) == 1,\n            installNonMarketApps = true, //Settings.Secure.getInt(context.contentResolver, \"install_non_market_apps\", 0) == 1,\n            networkData = getNetworkData(context),\n            uptimeMillis = SystemClock.uptimeMillis(),\n            timeZoneDisplayName = if (SDK_INT >= 24) TimeZone.getDefault().displayName!! else \"\",\n            googleAccounts = AccountManager.get(context).getAccountsByType(DEFAULT_ACCOUNT_TYPE).map { it.name }\n        )\n    } catch (e: Exception) {\n        if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"createDeviceInfo\", e)\n        return null\n    }\n}"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/core/AcknowledgePurchaseParams.kt",
    "content": "package org.microg.vending.billing.core\n\ndata class AcknowledgePurchaseParams(\n    val apiVersion: Int,\n    val purchaseToken: String,\n    val extraParams: Map<String, Any> = emptyMap()\n)"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/core/AcknowledgePurchaseResult.kt",
    "content": "package org.microg.vending.billing.core\n\nimport org.microg.vending.billing.proto.AcknowledgePurchaseResponse\n\nclass AcknowledgePurchaseResult(\n    val purchaseItem: PurchaseItem? = null,\n    resultMap: Map<String, Any> = mapOf(\n        \"RESPONSE_CODE\" to 0,\n        \"DEBUG_MESSAGE\" to \"\"\n    )\n) : IAPResult(resultMap) {\n    companion object {\n        fun parseFrom(\n            response: AcknowledgePurchaseResponse?\n        ): AcknowledgePurchaseResult {\n            if (response == null) {\n                throw NullPointerException(\"response is null\")\n            }\n            if (response.failedResponse != null) {\n                return AcknowledgePurchaseResult(\n                    null,\n                    mapOf(\n                        \"RESPONSE_CODE\" to response.failedResponse.statusCode,\n                        \"DEBUG_MESSAGE\" to response.failedResponse.msg\n                    )\n                )\n            }\n            if (response.purchaseItem == null) {\n                throw NullPointerException(\"AcknowledgePurchaseResponse PurchaseItem is null\")\n            }\n            if (response.purchaseItem.purchaseItemData.size != 1)\n                throw IllegalStateException(\"AcknowledgePurchaseResult purchase item count != 1\")\n            return AcknowledgePurchaseResult(parsePurchaseItem(response.purchaseItem).getOrNull(0))\n        }\n    }\n}"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/core/AcquireParams.kt",
    "content": "package org.microg.vending.billing.core\n\ndata class AcquireParams(\n    val buyFlowParams: BuyFlowParams,\n    val actionContext: List<ByteArray> = emptyList(),\n    val droidGuardResult: String? = null,\n    val authToken: String? = null,\n    var lastAcquireResult: AcquireResult? = null\n)"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/core/AcquireResult.kt",
    "content": "package org.microg.vending.billing.core\n\nimport org.microg.vending.billing.core.ui.AcquireParsedResult\nimport org.microg.vending.billing.core.ui.parseAcquireResponse\nimport org.microg.vending.billing.proto.AcquireRequest\nimport org.microg.vending.billing.proto.AcquireResponse\n\ndata class AcquireResult(\n    val acquireParsedResult: AcquireParsedResult,\n    val acquireRequest: AcquireRequest,\n    val acquireResponse: AcquireResponse,\n) {\n    companion object {\n        fun parseFrom(\n            acquireParams: AcquireParams,\n            acquireRequest: AcquireRequest,\n            acquireResponse: AcquireResponse?\n        ): AcquireResult {\n            if (acquireResponse == null) {\n                throw NullPointerException(\"AcquireResponse is null\")\n            }\n            return AcquireResult(\n                parseAcquireResponse(acquireParams, acquireResponse),\n                acquireRequest,\n                acquireResponse\n            )\n        }\n    }\n}"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/core/AuthData.kt",
    "content": "package org.microg.vending.billing.core\n\ndata class AuthData(\n    val email: String,\n    val authToken: String,\n    val gsfId: String = \"\",\n    val deviceCheckInConsistencyToken: String = \"\",\n    val deviceConfigToken: String = \"\",\n    val experimentsConfigToken: String = \"\",\n    val dfeCookie: String = \"\"\n)\n"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/core/BuyFlowParams.kt",
    "content": "package org.microg.vending.billing.core\n\ndata class BuyFlowParams(\n    val apiVersion: Int,\n    val sku: String,\n    val skuType: String,\n    val developerPayload: String = \"\",\n    val sdkVersion: String = \"\",\n    val needAuth: Boolean = false,\n    val skuParams: Map<String, Any> = emptyMap(),\n    val skuSerializedDockIdList: List<String>? = null,\n    val skuOfferIdTokenList: List<String>? = null,\n    val oldSkuPurchaseToken: String? = null,\n    val oldSkuPurchaseId: String? = null\n)"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/core/ClientInfo.kt",
    "content": "package org.microg.vending.billing.core\n\ndata class ClientInfo(\n    val pkgName: String,\n    val signatureMD5: String,\n    val versionCode: Int\n)"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/core/ConsumePurchaseParams.kt",
    "content": "package org.microg.vending.billing.core\n\ndata class ConsumePurchaseParams(\n    val apiVersion: Int,\n    val purchaseToken: String,\n    val extraParams: Map<String, Any> = emptyMap()\n)"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/core/ConsumePurchaseResult.kt",
    "content": "package org.microg.vending.billing.core\n\nimport org.microg.vending.billing.proto.ConsumePurchaseResponse\n\n\nclass ConsumePurchaseResult(\n    resultMap: Map<String, Any> = mapOf(\n        \"RESPONSE_CODE\" to 0,\n        \"DEBUG_MESSAGE\" to \"\"\n    )\n) : IAPResult(resultMap) {\n    companion object {\n        fun parseFrom(\n            consumePurchaseResponse: ConsumePurchaseResponse?\n        ): ConsumePurchaseResult {\n            if (consumePurchaseResponse == null) {\n                throw NullPointerException(\"consumePurchaseResponse is null\")\n            }\n            if (consumePurchaseResponse.failedResponse != null) {\n                return ConsumePurchaseResult(\n                    mapOf(\n                        \"RESPONSE_CODE\" to consumePurchaseResponse.failedResponse.statusCode,\n                        \"DEBUG_MESSAGE\" to consumePurchaseResponse.failedResponse.msg\n                    )\n                )\n            }\n            return ConsumePurchaseResult()\n        }\n    }\n}"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/core/DeviceEnvInfo.kt",
    "content": "package org.microg.vending.billing.core\n\nimport java.util.Locale\n\ndata class DeviceEnvInfo(\n    val gpVersionCode: Long,\n    val gpVersionName: String,\n    val gpPkgName: String,\n    val gpLastUpdateTime: Long,\n    val gpFirstInstallTime: Long,\n    val gpSourceDir: String,\n    val androidId: String,\n    val biometricSupport: Boolean,\n    val biometricSupportCDD: Boolean,\n    val deviceId: String,\n    val serialNo: String,\n    val locale: Locale,\n    val userAgent: String,\n    val device: String,\n    val displayMetrics: DisplayMetrics?,\n    val telephonyData: TelephonyData?,\n    val locationData: LocationData?,\n    val networkData: NetworkData?,\n    val product: String,\n    val model: String,\n    val manufacturer: String,\n    val fingerprint: String,\n    val release: String,\n    val brand: String,\n    val batteryLevel: Int,\n    val timeZoneOffset: Long,\n    val isAdbEnabled: Boolean,\n    val installNonMarketApps: Boolean,\n    val uptimeMillis: Long,\n    val timeZoneDisplayName: String,\n    val googleAccounts: List<String>\n)\n\ndata class DisplayMetrics(\n    val widthPixels: Int,\n    val heightPixels: Int,\n    val xdpi: Float,\n    val ydpi: Float,\n    val densityDpi: Int\n)\n\ndata class TelephonyData(\n    val simOperatorName: String,\n    val phoneDeviceId: String,\n    val networkOperator: String,\n    val simOperator: String,\n    val phoneType: Int = -1\n)\n\ndata class LocationData(\n    val altitude: Double,\n    val latitude: Double,\n    val longitude: Double,\n    val accuracy: Float,\n    val time: Double\n)\n\ndata class NetworkData(\n    val linkDownstreamBandwidth: Long,\n    val linkUpstreamBandwidth: Long,\n    val isActiveNetworkMetered: Boolean,\n    val netAddressList: List<String>,\n)"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/core/GetPurchaseHistoryParams.kt",
    "content": "package org.microg.vending.billing.core\n\ndata class GetPurchaseHistoryParams(\n    val apiVersion: Int,\n    val type: String,\n    val continuationToken: String? = null,\n    val extraParams: Map<String, Any> = emptyMap()\n)"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/core/GetPurchaseHistoryResult.kt",
    "content": "package org.microg.vending.billing.core\n\nimport org.microg.vending.billing.proto.PurchaseHistoryResponse\n\nclass GetPurchaseHistoryResult(\n    val purchaseHistoryList: List<PurchaseHistoryItem>?,\n    val continuationToken: String?,\n    resultMap: Map<String, Any> = mapOf(\n        \"RESPONSE_CODE\" to 0,\n        \"DEBUG_MESSAGE\" to \"\"\n    )\n) : IAPResult(resultMap) {\n    companion object {\n        fun parseFrom(\n            response: PurchaseHistoryResponse?\n        ): GetPurchaseHistoryResult {\n            if (response == null) {\n                throw NullPointerException(\"PurchaseHistoryResponse is null\")\n            }\n            if (response.failedResponse != null) {\n                return GetPurchaseHistoryResult(\n                    null,\n                    null,\n                    mapOf(\n                        \"RESPONSE_CODE\" to response.failedResponse.statusCode,\n                        \"DEBUG_MESSAGE\" to response.failedResponse.msg\n                    )\n                )\n            }\n            if (response.productId.size != response.purchaseJson.size || response.purchaseJson.size != response.signature.size) {\n                throw IllegalStateException(\"GetPurchaseHistoryResult item count error\")\n            }\n            val purchaseHistoryList = mutableListOf<PurchaseHistoryItem>()\n            var continuationToken: String? = null\n            for (cnt in 0 until response.productId.size) {\n                purchaseHistoryList.add(\n                    PurchaseHistoryItem(\n                        response.productId[cnt],\n                        response.purchaseJson[cnt],\n                        response.signature[cnt]\n                    )\n                )\n            }\n            if (!response.continuationToken.isNullOrEmpty()) {\n                continuationToken = response.continuationToken\n            }\n\n            return GetPurchaseHistoryResult(purchaseHistoryList, continuationToken)\n        }\n    }\n\n    class PurchaseHistoryItem(val sku: String, val jsonData: String, val signature: String)\n}"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/core/GetSkuDetailsParams.kt",
    "content": "package org.microg.vending.billing.core\n\ndata class GetSkuDetailsParams(\n    val apiVersion: Int,\n    val skuType: String,\n    val skuIdList: List<String>,\n    val skuPkgName: String = \"\",\n    val sdkVersion: String = \"\",\n    val multiOfferSkuDetail: Map<String, Any> = emptyMap()\n)"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/core/GetSkuDetailsResult.kt",
    "content": "package org.microg.vending.billing.core\n\nimport android.util.Log\nimport org.microg.vending.billing.proto.DocId\nimport org.microg.vending.billing.proto.SkuDetailsResponse\nimport org.microg.vending.billing.proto.SkuInfo\n\n\nclass GetSkuDetailsResult private constructor(\n    val skuDetailsList: List<SkuDetailsItem>,\n    resultMap: Map<String, Any> = mapOf(\"RESPONSE_CODE\" to 0, \"DEBUG_MESSAGE\" to \"\")\n) : IAPResult(resultMap) {\n    companion object {\n        fun parseFrom(skuDetailsResponse: SkuDetailsResponse?): GetSkuDetailsResult {\n            if (skuDetailsResponse == null) {\n                throw NullPointerException(\"SkuDetailsResponse is null\")\n            }\n            if (skuDetailsResponse.failedResponse != null) {\n                return GetSkuDetailsResult(\n                    emptyList(),\n                    mapOf(\n                        \"RESPONSE_CODE\" to skuDetailsResponse.failedResponse.statusCode,\n                        \"DEBUG_MESSAGE\" to skuDetailsResponse.failedResponse.msg\n                    )\n                )\n            }\n            val skuDetailsList =\n                skuDetailsResponse.details.filter { it.skuDetails.isNotBlank() }\n                    .map { skuDetails ->\n                        val skuInfo = skuDetails.skuInfo ?: SkuInfo()\n                        SkuDetailsItem(\n                            skuDetails.skuDetails,\n                            skuInfo.skuItem.associate { it.token to it.docId }\n                        )\n                    }\n            return GetSkuDetailsResult(skuDetailsList)\n        }\n    }\n\n\n    data class SkuDetailsItem(\n        val jsonDetails: String,\n        val docIdMap: Map<String, DocId?>\n    )\n}"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/core/GooglePlayApi.kt",
    "content": "package org.microg.vending.billing.core\n\nclass GooglePlayApi {\n    companion object {\n        const val URL_BASE = \"https://play-fe.googleapis.com\"\n        const val URL_FDFE = \"$URL_BASE/fdfe\"\n        const val URL_SKU_DETAILS = \"$URL_FDFE/skuDetails\"\n        const val URL_EES_ACQUIRE = \"$URL_FDFE/ees/acquire\"\n        const val URL_ACKNOWLEDGE_PURCHASE = \"$URL_FDFE/acknowledgePurchase\"\n        const val URL_CONSUME_PURCHASE = \"$URL_FDFE/consumePurchase\"\n        const val URL_GET_PURCHASE_HISTORY = \"$URL_FDFE/inAppPurchaseHistory\"\n        const val URL_AUTH_PROOF_TOKENS = \"https://www.googleapis.com/reauth/v1beta/users/me/reauthProofTokens\"\n        const val URL_DETAILS = \"$URL_FDFE/details\"\n        const val URL_ITEM_DETAILS = \"$URL_FDFE/getItems\"\n        const val URL_PURCHASE = \"$URL_FDFE/purchase\"\n        const val URL_DELIVERY = \"$URL_FDFE/delivery\"\n        const val URL_ENTERPRISE_CLIENT_POLICY = \"$URL_FDFE/getEnterpriseClientPolicy\"\n        const val URL_SYNC = \"$URL_FDFE/sync\"\n        const val URL_BULK = \"$URL_FDFE/bulkGrantEntitlement\"\n    }\n}"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/core/HeaderProvider.kt",
    "content": "package org.microg.vending.billing.core\n\nimport android.util.Log\nimport org.microg.vending.billing.TAG\n\nobject HeaderProvider {\n    fun getBaseHeaders(authData: AuthData, deviceInfo: DeviceEnvInfo): MutableMap<String, String> {\n        val headers: MutableMap<String, String> = HashMap()\n        headers[\"Authorization\"] = \"Bearer \" + authData.authToken\n        headers[\"User-Agent\"] = deviceInfo.userAgent\n        return headers\n    }\n\n    fun getDefaultHeaders(authData: AuthData, deviceInfo: DeviceEnvInfo): MutableMap<String, String> {\n        val headers: MutableMap<String, String> = HashMap()\n        headers[\"Authorization\"] = \"Bearer \" + authData.authToken\n        headers[\"User-Agent\"] = deviceInfo.userAgent\n        headers[\"X-DFE-Device-Id\"] = authData.gsfId\n        headers[\"Accept-Language\"] = \"${deviceInfo.locale.language}-${deviceInfo.locale.country}\"\n        headers[\"X-Limit-Ad-Tracking-Enabled\"] = \"true\"\n        headers[\"X-DFE-Network-Type\"] = \"4\"\n        headers[\"X-DFE-Client-Id\"] = \"am-google\"\n\n        // TODO: Magic constants?\n        headers[\"X-DFE-Phenotype\"] =\n            \"H4sIAAAAAAAAAOOKcXb0DQ4oNzCoKNV1c0zMsywL9PVwqvBPcsr2TykJ8HUv9gx1La6I9Dcw9k7xTYtIMnasSopIq0g0SI8IdwxwDbfIygxw8U-PdPR1THML1DXNS_L0yffOinRxtLWVYgAAjtXkomAAAAA\"\n        headers[\"X-DFE-Encoded-Targets\"] =\n            \"CAEaSuMFBdCPgQYJxAIED+cBfS+6AVYBIQojDSI3hAEODGxYvQGMAhRMWQEVWxniBQSSAjycAuESkgrgBeAfgCv4KI8VgxHqGNxrRbkI\"\n\n        headers[\"X-DFE-Request-Params\"] = \"timeoutMs=4000\"\n        headers[\"X-Ad-Id\"] = \"00000000-0000-0000-0000-000000000000\"\n        headers[\"Connection\"] = \"Keep-Alive\"\n        if (deviceInfo.androidId.isNotBlank())\n            headers[\"x-public-android-id\"] = deviceInfo.androidId\n        if (authData.dfeCookie.isNotBlank())\n            headers[\"x-dfe-cookie\"] = authData.dfeCookie\n        if (authData.deviceCheckInConsistencyToken.isNotBlank()) {\n            headers[\"X-DFE-Device-Checkin-Consistency-Token\"] =\n                authData.deviceCheckInConsistencyToken\n        }\n        return headers\n    }\n}"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/core/HttpClient.kt",
    "content": "package org.microg.vending.billing.core\n\nimport android.content.Context\nimport android.net.Uri\nimport android.util.Log\nimport com.squareup.wire.Message\nimport com.squareup.wire.ProtoAdapter\nimport io.ktor.client.HttpClient\nimport io.ktor.client.call.body\nimport io.ktor.client.engine.okhttp.OkHttp\nimport io.ktor.client.plugins.HttpTimeout\nimport io.ktor.client.plugins.cache.HttpCache\nimport io.ktor.client.plugins.timeout\nimport io.ktor.client.request.forms.submitForm\nimport io.ktor.client.request.get\nimport io.ktor.client.request.headers\nimport io.ktor.client.request.post\nimport io.ktor.client.request.prepareGet\nimport io.ktor.client.request.setBody\nimport io.ktor.client.request.url\nimport io.ktor.http.HttpHeaders\nimport io.ktor.http.HttpStatusCode\nimport io.ktor.http.ParametersImpl\nimport io.ktor.http.URLBuilder\nimport io.ktor.http.Url\nimport io.ktor.utils.io.ByteReadChannel\nimport io.ktor.utils.io.pool.ByteArrayPool\nimport org.json.JSONObject\nimport org.microg.gms.utils.singleInstanceOf\nimport java.io.File\nimport java.io.FileOutputStream\nimport java.io.IOException\nimport java.io.OutputStream\n\nprivate const val POST_TIMEOUT = 8000L\nprivate const val TAG = \"HttpClient\"\n\nclass HttpClient {\n\n    private val client = singleInstanceOf { HttpClient(OkHttp) {\n        expectSuccess = true\n        install(HttpTimeout)\n    } }\n\n    private val clientWithCache = singleInstanceOf { HttpClient(OkHttp) {\n        expectSuccess = true\n        install(HttpCache)\n        install(HttpTimeout)\n    } }\n\n    suspend fun download(\n        url: String,\n        downloadFile: File,\n        params: Map<String, String> = emptyMap()\n    ): File = downloadFile.also { toFile ->\n        val parentDir = downloadFile.getParentFile()\n        if (parentDir != null && !parentDir.exists() && !parentDir.mkdirs()) {\n            throw IOException(\"Failed to create directories: ${parentDir.absolutePath}\")\n        }\n\n        FileOutputStream(toFile).use { download(url, it, params) }\n    }\n\n    suspend fun download(\n            url: String,\n            downloadTo: OutputStream,\n            params: Map<String, String> = emptyMap(),\n            downloadedBytes: Long = 0,\n            emitProgress: (bytesDownloaded: Long) -> Unit = {}\n    ) {\n        try {\n            Log.d(TAG, \"download downloadedBytes:$downloadedBytes\")\n            client.prepareGet(url.asUrl(params)){\n                if (downloadedBytes > 0) {\n                    headers {\n                        append(HttpHeaders.Range, \"bytes=$downloadedBytes-\")\n                    }\n                }\n            }.execute { response ->\n                val body: ByteReadChannel = response.body()\n                // Modified version of `ByteReadChannel.copyTo(OutputStream, Long)` to indicate progress\n                val buffer = ByteArrayPool.borrow()\n                try {\n                    var copied = downloadedBytes\n                    val bufferSize = buffer.size\n\n                    do {\n                        val rc = body.readAvailable(buffer, 0, bufferSize)\n                        copied += rc\n                        if (rc > 0) {\n                            downloadTo.write(buffer, 0, rc)\n                            emitProgress(copied)\n                        }\n                    } while (rc > 0)\n                } finally {\n                    ByteArrayPool.recycle(buffer)\n                }\n                // don't close `downloadTo` yet\n            }\n        } catch (e: Exception) {\n            Log.w(TAG, \"download error : $e\")\n            throw e\n        }\n    }\n\n    suspend fun <O> get(\n        url: String,\n        headers: Map<String, String> = emptyMap(),\n        params: Map<String, String> = emptyMap(),\n        adapter: ProtoAdapter<O>,\n        cache: Boolean = true\n    ): O {\n\n        val response = (if (cache) clientWithCache else client).get(url.asUrl(params)) {\n            headers {\n                headers.forEach {\n                    append(it.key, it.value)\n                }\n            }\n        }\n        if (response.status != HttpStatusCode.OK) throw IOException(\"Server responded with status ${response.status}\")\n        else return adapter.decode(response.body<ByteArray>())\n    }\n\n    /**\n     * Post empty body.\n     */\n    suspend fun <I : Message<I, *>, O> post(\n        url: String,\n        headers: Map<String, String> = emptyMap(),\n        params: Map<String, String> = emptyMap(),\n        adapter: ProtoAdapter<O>,\n        cache: Boolean = false\n    ): O {\n        val response = (if (cache) clientWithCache else client).post(url.asUrl(params)) {\n            setBody(ByteArray(0))\n            headers {\n                headers.forEach {\n                    append(it.key, it.value)\n                }\n\n                append(HttpHeaders.ContentType, \"application/x-protobuf\")\n            }\n            timeout {\n                requestTimeoutMillis = POST_TIMEOUT\n            }\n        }\n        return adapter.decode(response.body<ByteArray>())\n    }\n\n    /**\n     * Post protobuf-encoded body.\n     */\n    suspend fun <I : Message<I, *>, O> post(\n        url: String,\n        headers: Map<String, String> = emptyMap(),\n        params: Map<String, String> = emptyMap(),\n        payload: I,\n        adapter: ProtoAdapter<O>,\n        cache: Boolean = false\n    ): O {\n        val response = (if (cache) clientWithCache else client).post(url.asUrl(params)) {\n            setBody(ByteReadChannel(payload.encode()))\n            headers {\n                headers.forEach {\n                    append(it.key, it.value)\n                }\n\n                append(HttpHeaders.ContentType, \"application/x-protobuf\")\n            }\n            timeout {\n                requestTimeoutMillis = POST_TIMEOUT\n            }\n        }\n        return adapter.decode(response.body<ByteArray>())\n    }\n\n    /**\n     * Post JSON body.\n     */\n    suspend fun post(\n        url: String,\n        headers: Map<String, String> = emptyMap(),\n        params: Map<String, String> = emptyMap(),\n        payload: JSONObject,\n        cache: Boolean = false\n    ): JSONObject {\n        val response = (if (cache) clientWithCache else client).post(url.asUrl(params)) {\n            setBody(payload.toString())\n            headers {\n                headers.forEach {\n                    append(it.key, it.value)\n                }\n\n                append(HttpHeaders.ContentType, \"application/json\")\n            }\n            timeout {\n                requestTimeoutMillis = POST_TIMEOUT\n            }\n        }\n        return JSONObject(response.body<String>())\n    }\n\n    /**\n     * Post form body.\n     */\n    suspend fun <O> post(\n        url: String,\n        headers: Map<String, String> = emptyMap(),\n        params: Map<String, String> = emptyMap(),\n        form: Map<String, String> = emptyMap(),\n        adapter: ProtoAdapter<O>,\n        cache: Boolean = false\n    ): O {\n        val response = (if (cache) clientWithCache else client).submitForm(\n            formParameters = ParametersImpl(form.mapValues { listOf(it.key) }),\n            encodeInQuery = false\n        ) {\n            url(url.asUrl(params))\n            headers { // Content-Type is set to `x-www-form-urlencode` automatically\n                headers.forEach {\n                    append(it.key, it.value)\n                }\n            }\n            timeout {\n                requestTimeoutMillis = POST_TIMEOUT\n            }\n        }\n        return adapter.decode(response.body<ByteArray>())\n    }\n\n    private fun String.asUrl(params: Map<String, String>): Url = URLBuilder(this).apply {\n        params.forEach {\n            parameters.append(it.key, it.value)\n        }\n    }.build()\n}"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/core/IAPCacheManager.kt",
    "content": "package org.microg.vending.billing.core\n\nimport android.util.LruCache\nimport org.microg.gms.utils.digest\nimport org.microg.gms.utils.toHexString\n\noperator fun <K, V> LruCache<K, V>.set(key: K, value: V) { put(key, value) }\n\nclass CacheEntry(\n    val data: ByteArray,\n    val expiredAt: Long\n)\n\nclass IAPCacheManager(maxSize: Int = 1024, private val expireMs: Int = 7200000) {\n    private val lruCache = LruCache<String, CacheEntry>(maxSize)\n\n    @Synchronized\n    fun get(requestBody: ByteArray): ByteArray? {\n        val entry = lruCache[calculateHash(requestBody)]\n        if (entry == null || entry.expiredAt < System.currentTimeMillis())\n            return null\n        return entry.data\n    }\n\n    @Synchronized\n    fun put(requestBody: ByteArray, responseData: ByteArray) {\n        val key = calculateHash(requestBody)\n        lruCache[key] = CacheEntry(responseData, System.currentTimeMillis() + expireMs)\n    }\n\n    private fun calculateHash(body: ByteArray): String {\n        return body.digest(\"SHA-256\").toHexString()\n    }\n}\n"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/core/IAPCore.kt",
    "content": "package org.microg.vending.billing.core\n\nimport android.content.Context\nimport android.util.Base64\nimport android.util.Log\nimport org.json.JSONObject\nimport org.microg.gms.utils.toBase64\nimport org.microg.vending.billing.proto.*\nimport org.microg.vending.proto.Timestamp\nimport java.io.IOException\nimport java.util.concurrent.TimeUnit\n\nprivate val skuDetailsCache = IAPCacheManager(2048)\n\nclass IAPCore(\n    private val context: Context,\n    private val deviceInfo: DeviceEnvInfo,\n    private val clientInfo: ClientInfo,\n    private val authData: AuthData\n) {\n    suspend fun requestAuthProofToken(password: String): String {\n        return HttpClient().post(\n            GooglePlayApi.URL_AUTH_PROOF_TOKENS,\n            headers = HeaderProvider.getBaseHeaders(authData, deviceInfo),\n            payload = JSONObject().apply {\n                put(\"credentialType\", \"password\")\n                put(\"credential\", password)\n            }\n        ).getString(\"encodedRapt\")\n    }\n\n    suspend fun getSkuDetails(params: GetSkuDetailsParams): GetSkuDetailsResult {\n        val builder = SkuDetailsRequest.Builder()\n        builder.apply {\n            apiVersion = params.apiVersion\n            type = params.skuType\n            package_ = clientInfo.pkgName\n            isWifi = true\n            skuPackage = params.skuPkgName\n            skuId = params.skuIdList\n            val skuDetailsExtraBuilder = SkuDetailsExtra.Builder()\n            skuDetailsExtraBuilder.apply {\n                version = params.sdkVersion\n            }\n            skuDetailsExtra = skuDetailsExtraBuilder.build()\n\n            val multiOfferSkuDetailTemp: MutableList<MultiOfferSkuDetail> = mutableListOf()\n            params.multiOfferSkuDetail.forEach {\n                multiOfferSkuDetailTemp.add(\n                    if (it.key == \"SKU_SERIALIZED_DOCID_LIST\") {\n                        val multiOfferSkuDetailBuilder = MultiOfferSkuDetail.Builder()\n                        val skuSerializedDocIdList = SkuSerializedDocIds.Builder()\n                        val docIdList = params.multiOfferSkuDetail[\"SKU_SERIALIZED_DOCID_LIST\"]\n                        if (docIdList != null) {\n                            skuSerializedDocIdList.docIds(docIdList as List<String>)\n                            multiOfferSkuDetailBuilder.apply {\n                                key = it.key\n                                skuSerializedDocIds = skuSerializedDocIdList.build()\n                            }\n                        }\n                        multiOfferSkuDetailBuilder.build()\n                    } else {\n                        when (val value = it.value) {\n                            is Boolean -> {\n                                val multiOfferSkuDetailBuilder = MultiOfferSkuDetail.Builder()\n                                multiOfferSkuDetailBuilder.apply {\n                                    key = it.key\n                                    bv = value\n                                }\n                                multiOfferSkuDetailBuilder.build()\n                            }\n\n                            is Long -> {\n                                val multiOfferSkuDetailBuilder = MultiOfferSkuDetail.Builder()\n                                multiOfferSkuDetailBuilder.apply {\n                                    key = it.key\n                                    iv = value\n                                }\n                                multiOfferSkuDetailBuilder.build()\n                            }\n\n                            is Int -> {\n                                val multiOfferSkuDetailBuilder = MultiOfferSkuDetail.Builder()\n                                multiOfferSkuDetailBuilder.apply {\n                                    key = it.key\n                                    iv = value.toLong()\n                                }\n                                multiOfferSkuDetailBuilder.build()\n                            }\n\n                            else -> {\n                                val multiOfferSkuDetailBuilder = MultiOfferSkuDetail.Builder()\n                                multiOfferSkuDetailBuilder.apply {\n                                    key = it.key\n                                    sv = value.toString()\n                                }\n                                multiOfferSkuDetailBuilder.build()\n                            }\n                        }\n                    }\n                )\n            }\n            this.multiOfferSkuDetail = multiOfferSkuDetailTemp\n        }\n        val skuDetailsRequest = builder.build()\n        return try {\n            val requestBody = skuDetailsRequest.encode()\n            val cacheEntry = skuDetailsCache.get(requestBody)\n            if (cacheEntry != null) {\n                val getSkuDetailsResult = GetSkuDetailsResult.parseFrom(GoogleApiResponse.ADAPTER.decode(cacheEntry).payload?.skuDetailsResponse)\n                if (getSkuDetailsResult.skuDetailsList != null && getSkuDetailsResult.skuDetailsList.isNotEmpty()) {\n                    Log.d(\"IAPCore\", \"getSkuDetails from cache \")\n                    return getSkuDetailsResult\n                }\n            }\n            Log.d(\"IAPCore\", \"getSkuDetails: \")\n            val response = HttpClient().post(\n                GooglePlayApi.URL_SKU_DETAILS,\n                headers = HeaderProvider.getDefaultHeaders(authData, deviceInfo),\n                payload = skuDetailsRequest,\n                adapter = GoogleApiResponse.ADAPTER\n            )\n            skuDetailsCache.put(requestBody, response.encode())\n            GetSkuDetailsResult.parseFrom(response.payload?.skuDetailsResponse)\n        } catch (e: Exception) {\n            throw RuntimeException(\"Network request failed. message=${e.message}\")\n        }\n    }\n\n    private fun createAcquireRequest(params: AcquireParams): AcquireRequest {\n        val theme = 2\n\n        val skuPackageName = params.buyFlowParams.skuParams[\"skuPackageName\"] ?: clientInfo.pkgName\n        val docId = if (params.buyFlowParams.skuSerializedDockIdList?.isNotEmpty() == true) {\n            val sDocIdBytes = Base64.decode(params.buyFlowParams.skuSerializedDockIdList[0], Base64.URL_SAFE + Base64.NO_WRAP)\n            DocId.ADAPTER.decode(sDocIdBytes)\n        } else {\n            val docIdBuilder = DocId.Builder()\n            docIdBuilder.apply {\n                backendDocId =\n                    \"${params.buyFlowParams.skuType}:$skuPackageName:${params.buyFlowParams.sku}\"\n                type = getSkuType(params.buyFlowParams.skuType)\n                backend = 3\n            }\n            docIdBuilder.build()\n        }\n        val documentInfo = DocumentInfo.Builder().apply {\n            this.docId = docId\n            this.unknown2 = 1\n            if (params.buyFlowParams.skuOfferIdTokenList?.isNotEmpty() == true) {\n                if (params.buyFlowParams.skuOfferIdTokenList[0].isNotBlank())\n                    this.token14 = params.buyFlowParams.skuOfferIdTokenList[0]\n            }\n        }.build()\n\n        val authFrequency = if (params.buyFlowParams.needAuth) 0 else 3\n        return AcquireRequest.Builder().apply {\n            this.documentInfo = documentInfo\n            this.clientInfo = org.microg.vending.billing.proto.ClientInfo.Builder().apply {\n                this.apiVersion = params.buyFlowParams.apiVersion\n                this.package_ = this@IAPCore.clientInfo.pkgName\n                this.versionCode = this@IAPCore.clientInfo.versionCode\n                this.signatureMD5 = this@IAPCore.clientInfo.signatureMD5\n                this.skuParamList = mapToSkuParamList(params.buyFlowParams.skuParams)\n                this.unknown8 = 1\n                this.installerPackage = deviceInfo.gpPkgName\n                this.unknown10 = false\n                this.unknown11 = false\n                this.unknown15 = UnkMessage1.Builder().apply {\n                    this.unknown1 = UnkMessage2.Builder().apply {\n                        this.unknown1 = 1\n                    }.build()\n                }.build()\n                this.versionCode1 = this@IAPCore.clientInfo.versionCode\n                if (params.buyFlowParams.oldSkuPurchaseToken?.isNotBlank() == true)\n                    this.oldSkuPurchaseToken = params.buyFlowParams.oldSkuPurchaseToken\n                if (params.buyFlowParams.oldSkuPurchaseId?.isNotBlank() == true)\n                    this.oldSkuPurchaseId = params.buyFlowParams.oldSkuPurchaseId\n            }.build()\n            this.clientTokenB64 =\n                createClientToken(this@IAPCore.deviceInfo, this@IAPCore.authData)\n            this.deviceAuthInfo = DeviceAuthInfo.Builder().apply {\n                this.canAuthenticate = true\n                this.unknown5 = 1\n                this.unknown9 = true\n                this.authFrequency = authFrequency\n                this.itemColor = ItemColor.Builder().apply {\n                    this.androidAppsColor = -16735885\n                    this.booksColor = -11488012\n                    this.musicColor = -45771\n                    this.moviesColor = -52375\n                    this.newsStandColor = -7686920\n                }.build()\n            }.build()\n            this.unknown12 = UnkMessage5.Builder().apply {\n                this.unknown1 = 9\n            }.build()\n            this.deviceIDBase64 = deviceInfo.deviceId\n            this.newAcquireCacheKey = getAcquireCacheKey(\n                this@IAPCore.deviceInfo,\n                this@IAPCore.authData.email,\n                listOf(\n                    CKDocument.Builder().apply {\n                        this.docId = docId\n                        this.token3 = documentInfo.token3\n                        this.token14 = documentInfo.token14\n                        this.unknown3 = 1\n                    }.build()\n                ),\n                this@IAPCore.clientInfo.pkgName,\n                mapOf(\n                    \"enablePendingPurchases\" to (params.buyFlowParams.skuParams[\"enablePendingPurchases\"]\n                        ?: false).toString()\n                ),\n                authFrequency\n            )\n            this.nonce = createNonce()\n            this.theme = theme\n            this.ts = Timestamp.Builder().apply {\n                val ts = System.currentTimeMillis()\n                this.seconds = TimeUnit.MILLISECONDS.toSeconds(ts)\n                this.nanos = ((ts + TimeUnit.HOURS.toMillis(1L)) % 1000L * 1000000L).toInt()\n            }.build()\n        }.build()\n    }\n\n    suspend fun doAcquireRequest(params: AcquireParams): AcquireResult {\n        val acquireRequest =\n            if (params.lastAcquireResult == null) {\n                createAcquireRequest(params)\n            } else {\n                params.lastAcquireResult!!.acquireRequest.copy().newBuilder().apply {\n                    this.serverContextToken =\n                        params.lastAcquireResult!!.acquireResponse.serverContextToken\n                    this.actionContext = (params.actionContext.toByteStringList())\n                    if (params.lastAcquireResult!!.acquireRequest.deviceAuthInfo != null) {\n                        this.deviceAuthInfo = params.lastAcquireResult!!.acquireRequest.deviceAuthInfo!!.copy().newBuilder().apply {\n                            if (params.droidGuardResult?.isNotBlank() == true) {\n                                this.droidGuardPayload = params.droidGuardResult\n                            }\n                        }.build()\n                    }\n                    val authTokensTemp = mutableMapOf<String, String>()\n                    params.authToken?.let {\n                        authTokensTemp[\"rpt\"] = it\n\n                    }\n                    this.authTokens = authTokensTemp\n                    this.ts = Timestamp.Builder().apply {\n                        val ts = System.currentTimeMillis()\n                        this.seconds = TimeUnit.MILLISECONDS.toSeconds(ts)\n                        this.nanos = ((ts + TimeUnit.HOURS.toMillis(1L)) % 1000L * 1000000L).toInt()\n                    }.build()\n                }.build()\n            }\n        return try {\n            val response = HttpClient().post(\n                GooglePlayApi.URL_EES_ACQUIRE,\n                headers = HeaderProvider.getDefaultHeaders(authData, deviceInfo),\n                params = mapOf(\"theme\" to acquireRequest.theme.toString()),\n                payload = acquireRequest,\n                GoogleApiResponse.ADAPTER\n            )\n            AcquireResult.parseFrom(params, acquireRequest, response.payload?.acquireResponse)\n        } catch (e: Exception) {\n            throw RuntimeException(\"Network request failed. message=${e.message}\")\n        }\n    }\n\n    suspend fun consumePurchase(params: ConsumePurchaseParams): ConsumePurchaseResult {\n        val iabx = IABX.Builder().apply {\n            this.skuParam = mapToSkuParamList(params.extraParams)\n        }.build().encode().toBase64(Base64.URL_SAFE + Base64.NO_WRAP)\n        val request = mapOf(\n            \"pt\" to params.purchaseToken,\n            \"ot\" to \"1\",\n            \"shpn\" to clientInfo.pkgName,\n            \"iabx\" to iabx\n        )\n\n        return try {\n            val response = HttpClient().post(\n                GooglePlayApi.URL_CONSUME_PURCHASE,\n                headers = HeaderProvider.getDefaultHeaders(authData, deviceInfo),\n                form = request,\n                adapter = GoogleApiResponse.ADAPTER\n            )\n            ConsumePurchaseResult.parseFrom(response.payload?.consumePurchaseResponse)\n        } catch (e: Exception) {\n            throw RuntimeException(\"Network request failed. message=${e.message}\")\n        }\n    }\n\n    suspend fun acknowledgePurchase(params: AcknowledgePurchaseParams): AcknowledgePurchaseResult {\n        val acknowledgePurchaseRequest = AcknowledgePurchaseRequest.Builder().apply {\n            this.purchaseToken = params.purchaseToken\n            params.extraParams[\"developerPayload\"]?.let {\n                this.developerPayload = it as String\n            }\n        }.build()\n\n        return try {\n            val response = HttpClient().post(\n                GooglePlayApi.URL_ACKNOWLEDGE_PURCHASE,\n                headers = HeaderProvider.getDefaultHeaders(authData, deviceInfo),\n                payload = acknowledgePurchaseRequest,\n                adapter = GoogleApiResponse.ADAPTER\n            )\n            AcknowledgePurchaseResult.parseFrom(response.payload?.acknowledgePurchaseResponse)\n        } catch (e: Exception) {\n            throw RuntimeException(\"Network request failed. message=${e.message}\")\n        }\n    }\n\n    suspend fun getPurchaseHistory(params: GetPurchaseHistoryParams): GetPurchaseHistoryResult {\n        val reqParams = mutableMapOf(\n            \"bav\" to params.apiVersion.toString(),\n            \"shpn\" to clientInfo.pkgName,\n            \"iabt\" to params.type\n        )\n        if (!params.continuationToken.isNullOrEmpty()) {\n            reqParams[\"ctntkn\"] = params.continuationToken\n        }\n        if (params.extraParams.isNotEmpty()) {\n            reqParams[\"iabx\"] = IABX.Builder().apply {\n                this.skuParam = mapToSkuParamList(params.extraParams)\n            }.build().encode().toBase64(Base64.URL_SAFE + Base64.NO_WRAP)\n        }\n\n        return try {\n            val response = HttpClient().get(\n                GooglePlayApi.URL_GET_PURCHASE_HISTORY,\n                HeaderProvider.getDefaultHeaders(authData, deviceInfo),\n                reqParams,\n                GoogleApiResponse.ADAPTER\n            )\n            GetPurchaseHistoryResult.parseFrom(response.payload?.purchaseHistoryResponse)\n        } catch (e: IOException) {\n            throw RuntimeException(\"Network request failed. message=${e.message}\")\n        }\n    }\n}"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/core/IAPResult.kt",
    "content": "package org.microg.vending.billing.core\n\nopen class IAPResult(val resultMap: Map<String, Any>) {\n    fun getCode(): Int {\n        return resultMap[\"RESPONSE_CODE\"] as Int\n    }\n\n    fun getMessage(): String {\n        return resultMap[\"RESPONSE_MESSAGE\"] as String\n    }\n}"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/core/PurchaseItem.kt",
    "content": "package org.microg.vending.billing.core\n\n// TODO: Use class from billing client instead\ndata class PurchaseItem(\n    val type: String,\n    val sku: String,\n    val pkgName: String,\n    val purchaseToken: String,\n    val purchaseState: Int,\n    val jsonData: String,\n    val signature: String,\n    val startAt: Long = 0L,\n    val expireAt: Long = 0L,\n) {\n    override fun equals(other: Any?): Boolean {\n        if (this === other) return true\n        if (other !is PurchaseItem) return false\n        if (purchaseToken != other.purchaseToken) return false\n        return true\n    }\n\n    override fun hashCode(): Int {\n        return purchaseToken.hashCode()\n    }\n}\n"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/core/Utils.kt",
    "content": "package org.microg.vending.billing.core\n\nimport android.util.Base64\nimport android.util.Log\nimport com.android.billingclient.api.BillingClient.ProductType\nimport okio.ByteString\nimport okio.ByteString.Companion.toByteString\nimport org.json.JSONObject\nimport org.microg.vending.billing.TAG\nimport org.microg.vending.billing.proto.*\nimport org.microg.vending.billing.proto.PurchaseItem\nimport java.security.InvalidParameterException\nimport java.security.SecureRandom\nimport java.util.*\n\nfun List<ByteArray>.toByteStringList(): List<ByteString> {\n    return this.map { it.toByteString() }\n}\n\nfun mapToSkuParamList(map: Map<String, Any>?): List<SkuParam> {\n    val result = mutableListOf<SkuParam>()\n    if (map == null)\n        return result\n    map.forEach { entry ->\n        result.add(\n            when (val value = entry.value) {\n                is Boolean -> SkuParam.Builder().apply {\n                    name = entry.key\n                    bv = value\n                }.build()\n\n                is Long -> SkuParam.Builder().apply {\n                    name = entry.key\n                    i64v = value\n                }.build()\n\n                is Int -> SkuParam.Builder().apply {\n                    name = entry.key\n                    i64v = value.toLong()\n                }.build()\n\n                is ArrayList<*> -> SkuParam.Builder().apply {\n                    name = entry.key\n                    svList = value.map { it as String }\n                }.build()\n\n                is String -> SkuParam.Builder().apply {\n                    name = entry.key\n                    sv = value\n                }.build()\n\n                else -> SkuParam.Builder().apply {\n                    name = entry.key\n                    sv = value.toString()\n                }.build()\n            }\n        )\n    }\n\n    return result\n}\n\nfun localeToString(locale: Locale): String {\n    val result = StringBuilder()\n    result.append(locale.language)\n    locale.country?.let {\n        if (it.isNotEmpty())\n            result.append(\"-$it\")\n    }\n    locale.variant?.let {\n        if (it.isNotEmpty())\n            result.append(\"-$it\")\n    }\n    return result.toString()\n}\n\nfun createClientToken(deviceInfo: DeviceEnvInfo, authData: AuthData): String {\n    val clientToken = ClientToken.Builder().apply {\n        this.info1 = ClientToken.Info1.Builder().apply {\n            this.locale = localeToString(deviceInfo.locale)\n            this.unknown8 = 2\n            this.gpVersionCode = deviceInfo.gpVersionCode\n            this.deviceInfo = ClientToken.DeviceInfo.Builder().apply {\n                this.unknown3 = \"33\"\n                this.device = deviceInfo.device\n                deviceInfo.displayMetrics?.let {\n                    this.widthPixels = it.widthPixels\n                    this.heightPixels = it.heightPixels\n                    this.xdpi = it.xdpi\n                    this.ydpi = it.ydpi\n                    this.densityDpi = it.densityDpi\n                }\n                this.gpPackage = deviceInfo.gpPkgName\n                this.gpVersionCode = deviceInfo.gpVersionCode.toString()\n                this.gpVersionName = deviceInfo.gpVersionName\n                this.envInfo = ClientToken.EnvInfo.Builder().apply {\n                    this.deviceData = ClientToken.DeviceData.Builder().apply {\n                        this.unknown1 = 0\n                        deviceInfo.telephonyData?.let {\n                            this.simOperatorName = it.simOperatorName\n                            this.phoneDeviceId = it.phoneDeviceId\n                            this.phoneDeviceId1 = it.phoneDeviceId\n                        }\n                        this.gsfId = authData.gsfId.toLong(16)\n                        this.device = deviceInfo.device\n                        this.product = deviceInfo.product\n                        this.model = deviceInfo.model\n                        this.manufacturer = deviceInfo.manufacturer\n                        this.fingerprint = deviceInfo.fingerprint\n                        this.release = deviceInfo.release\n                        this.brand = deviceInfo.brand\n                        this.serial = deviceInfo.serialNo\n                        this.isEmulator = false\n                    }.build()\n                    this.otherInfo = ClientToken.OtherInfo.Builder().apply {\n                        this.gpInfo = mutableListOf((\n                            ClientToken.GPInfo.Builder().apply {\n                                this.package_ = deviceInfo.gpPkgName\n                                this.versionCode = deviceInfo.gpVersionCode.toString()\n                                this.lastUpdateTime = deviceInfo.gpLastUpdateTime\n                                this.firstInstallTime = deviceInfo.gpFirstInstallTime\n                                this.sourceDir = deviceInfo.gpSourceDir\n                            }).build())\n                        this.batteryLevel = deviceInfo.batteryLevel\n                        this.timeZoneOffset = deviceInfo.timeZoneOffset\n                        this.location = ClientToken.Location.Builder().apply {\n                            deviceInfo.locationData?.let {\n                                this.altitude = it.altitude\n                                this.latitude = it.latitude\n                                this.longitude = it.longitude\n                                this.accuracy = it.accuracy\n                                this.time = it.time\n                            }\n                            this.isMock = false\n                        }.build()\n                        this.isAdbEnabled = deviceInfo.isAdbEnabled\n                        this.installNonMarketApps = deviceInfo.installNonMarketApps\n                        this.iso3Language = deviceInfo.locale.isO3Language\n                        this.netAddress = deviceInfo.networkData?.netAddressList ?: emptyList()\n                        this.locale = deviceInfo.locale.toString()\n                        deviceInfo.telephonyData?.let {\n                            this.networkOperator = it.networkOperator\n                            this.simOperator = it.simOperator\n                            this.phoneType = it.phoneType\n                        }\n                        this.language = deviceInfo.locale.language\n                        this.country = deviceInfo.locale.country\n                        this.uptimeMillis = deviceInfo.uptimeMillis\n                        this.timeZoneDisplayName = deviceInfo.timeZoneDisplayName\n                        this.googleAccountCount = deviceInfo.googleAccounts.size\n                    }.build()\n                }.build()\n                this.marketClientId = \"am-google\"\n                this.unknown15 = 1\n                this.unknown16 = 2\n                this.unknown22 = 2\n                deviceInfo.networkData?.let {\n                    this.linkDownstreamBandwidth = it.linkDownstreamBandwidth\n                    this.linkUpstreamBandwidth = it.linkUpstreamBandwidth\n                    this.isActiveNetworkMetered = it.isActiveNetworkMetered\n                }\n                this.unknown34 = 2\n                this.uptimeMillis = deviceInfo.uptimeMillis\n                this.timeZoneDisplayName = deviceInfo.timeZoneDisplayName\n                this.unknown40 = 1\n            }.build()\n            this.unknown11 = \"-5228872483831680725\"\n            this.googleAccounts = deviceInfo.googleAccounts\n        }.build()\n        this.info2 = ClientToken.Info2.Builder().apply {\n            this.unknown1 =\n                \"https://play.app.goo.gl/?link=http%3A%2F%2Funused.google.com&apn=com.android.vending&al=google-orchestration%3A%2F%2Freturn\"\n            this.unknown3 = 1\n            this.unknown4 = mutableListOf(2)\n            this.unknown5 = 1\n        }.build()\n    }.build()\n    return Base64.encodeToString(\n        clientToken.encode(),\n        Base64.URL_SAFE + Base64.NO_WRAP\n    )\n}\n\nfun getAcquireCacheKey(\n    deviceInfo: DeviceEnvInfo,\n    accountName: String,\n    docList: List<CKDocument>,\n    callingPackage: String,\n    extras: Map<String, String>,\n    authFrequency: Int\n): String {\n    val stringBuilder = StringBuilder()\n    stringBuilder.append(accountName)\n    for (item in docList) {\n        stringBuilder.append(\"#\")\n        stringBuilder.append(Base64.encodeToString(item.encode(), Base64.NO_WRAP))\n    }\n    stringBuilder.append(\"#simId=${deviceInfo.deviceId}\")\n    stringBuilder.append(\"#clientTheme=2\")\n    stringBuilder.append(\"#fingerprintValid=false\")\n    stringBuilder.append(\"#desiredAuthMethod=0\")\n    stringBuilder.append(\"#authFrequency=$authFrequency\")\n    stringBuilder.append(\"#userHasFop=false\")\n    stringBuilder.append(\"#callingAppPackageName=$callingPackage\")\n    for (item in extras) {\n        stringBuilder.append(\"#${item.key}=${item.value}\")\n    }\n    return stringBuilder.toString()\n}\n\nfun createNonce(): String {\n    val secureRandom = SecureRandom.getInstance(\"SHA1PRNG\")\n        ?: throw RuntimeException(\"Uninitialized SecureRandom.\")\n    val result = ByteArray(0x100)\n    secureRandom.nextBytes(result)\n    return \"nonce=\" + Base64.encodeToString(result, Base64.URL_SAFE + Base64.NO_WRAP + Base64.NO_PADDING)\n}\n\nfun responseBundleToMap(responseBundle: ResponseBundle?): Map<String, Any> {\n    val result = mutableMapOf<String, Any>()\n    if (responseBundle != null) {\n        for (bundleItem in responseBundle.bundleItem) {\n            if (bundleItem.bv != null) {\n                result[bundleItem.key] = bundleItem.bv\n            } else if (bundleItem.i32v != null) {\n                result[bundleItem.key] = bundleItem.i32v\n            } else if (bundleItem.i64v != null) {\n                result[bundleItem.key] = bundleItem.i64v\n            } else if (bundleItem.sv != null) {\n                result[bundleItem.key] = bundleItem.sv\n            } else if (bundleItem.sList != null) {\n                result[bundleItem.key] =\n                    ArrayList(bundleItem.sList.value_)\n            } else {\n\n            }\n        }\n    }\n    return result\n}\n\nfun getSkuType(skuType: String): Int {\n    return when (skuType) {\n        ProductType.SUBS -> 15\n        ProductType.INAPP -> 11\n        \"first_party\" -> 15\n        else -> throw InvalidParameterException(\"unknown skuType: $skuType\")\n    }\n}\n\nfun splitDocId(docId: DocId): List<String> {\n    return docId.backendDocId.split(\":\")\n}\n\nfun parsePurchaseItem(purchaseItem: PurchaseItem): List<org.microg.vending.billing.core.PurchaseItem> {\n    val result = mutableListOf<org.microg.vending.billing.core.PurchaseItem>()\n    for (it in purchaseItem.purchaseItemData) {\n        if (it == null)\n            continue\n        val spr = if (it.docId != null) {\n            splitDocId(it.docId)\n        } else {\n            emptyList()\n        }\n        if (spr.size < 3)\n            continue\n        val (type, _, sku) = spr\n        var startAt = 0L\n        var expireAt = 0L\n        val (jsonData, signature) = when (type) {\n            ProductType.INAPP -> {\n                if (it.inAppPurchase == null)\n                    continue\n                it.inAppPurchase.jsonData to it.inAppPurchase.signature\n            }\n\n            ProductType.SUBS -> {\n                if (it.subsPurchase == null)\n                    continue\n                startAt = it.subsPurchase.startAt\n                expireAt = it.subsPurchase.expireAt\n                it.subsPurchase.jsonData to it.subsPurchase.signature\n            }\n\n            else -> {\n                Log.e(TAG, \"unknown sku type $type\")\n                continue\n            }\n        }\n        val jdo = JSONObject(jsonData)\n        val pkgName = jdo.optString(\"packageName\").takeIf { it.isNotBlank() } ?: continue\n        val purchaseToken = jdo.optString(\"purchaseToken\").takeIf { it.isNotBlank() } ?: continue\n        val purchaseState = jdo.optInt(\"purchaseState\", -1).takeIf { it != -1 } ?: continue\n        result.add(\n            PurchaseItem(\n                type,\n                sku,\n                pkgName,\n                purchaseToken,\n                purchaseState,\n                jsonData,\n                signature,\n                startAt,\n                expireAt\n            )\n        )\n    }\n    return result\n}"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/core/ui/UIComponents.kt",
    "content": "package org.microg.vending.billing.core.ui\n\ndata class BAction(\n    var type: ActionType,\n    var delay: Int? = null,\n    var result: Map<String, Any>? = null,\n    var uiInfo: BUIInfo? = null,\n    var srcScreenId: String? = null,\n    var screenId: String? = null,\n    var droidGuardMap: Map<String, String> = emptyMap(),\n    var actionContext: MutableList<ByteArray> = mutableListOf()\n)\n\nenum class ActionType {\n    DELAY,\n    SHOW,\n    UNKNOWN\n}\n\ndata class BScreen(\n    val uiInfo: BUIInfo? = null,\n    val action: BAction? = null,\n    val uiComponents: BUIComponents? = null\n)\n\ndata class BUIInfo(\n    val uiType: UIType\n)\n\ndata class BAcquireResult(\n    val action: BAction? = null,\n    val screenMap: Map<String, BScreen> = emptyMap()\n)\n\ndata class BUIComponents(\n    val headerComponents: List<BComponent>,\n    val contentComponents: List<BComponent>,\n    val footerComponents: List<BComponent>\n)\n\ndata class BComponent(\n    val tag: String? = null,\n    val uiInfo: BUIInfo? = null,\n    val viewInfo: BViewInfo? = null,\n    val viewType: ViewType,\n    val clickableTextView: BClickableTextView? = null,\n    val viewGroup: BViewGroup? = null,\n    val dividerView: BDividerView? = null,\n    val moduloImageView: BModuloImageView? = null,\n    val iconTextCombinationView: BIconTextCombinationView? = null,\n    val buttonGroupView: BButtonGroupView? = null,\n    val instrumentItemView: BInstrumentItemView? = null\n)\n\ndata class BClickableTextView(val playTextView: BPlayTextView? = null)\n\ndata class BViewGroup(\n    val imageView1: BImageView? = null,\n    val imageView2: BImageView? = null,\n    val imageView3: BImageView? = null,\n    val imageView4: BImageView? = null,\n    val playTextView: BPlayTextView? = null\n)\n\ndata class BImageGroup(\n    val imageViews: List<BImageView>,\n    val viewInfo: BViewInfo? = null\n)\n\nclass BDividerView\n\ndata class BModuloImageView(\n    val imageView: BImageView? = null\n)\n\ndata class BIconTextCombinationView(\n    val headerImageView: BImageView? = null,\n    val playTextView: BPlayTextView? = null,\n    val badgeTextView: BPlayTextView? = null,\n    val middleTextViewList: List<BSingleLineTextView>? = null,\n    val footerImageGroup: BImageGroup? = null,\n    val viewInfo: BViewInfo? = null\n)\n\ndata class BSingleLineTextView(\n    val playTextView1: BPlayTextView? = null,\n    val playTextView2: BPlayTextView? = null\n)\n\ndata class BPlayTextView(\n    val text: String,\n    val isHtml: Boolean = true,\n    val textInfo: BTextInfo? = null,\n    val viewInfo: BViewInfo? = null,\n    val textSpan: List<BTextSpan>,\n)\n\ndata class BBulletSpan(\n    val gapWidth: Int\n)\n\ndata class BImageInfo(\n    val colorFilterValue: Int? = null,\n    val colorFilterType: Int? = null,\n    val filterMode: Int? = null,\n    val scaleType: Int? = null\n)\n\ndata class BTextSpan(\n    val textSpanType: TextSpanType,\n    val bulletSpan: BBulletSpan? = null,\n)\n\ndata class BImageView(\n    val viewInfo: BViewInfo? = null,\n    val imageInfo: BImageInfo? = null,\n    val lightUrl: String? = null,\n    val darkUrl: String? = null,\n    val animation: BAnimation? = null,\n    val iconView: BIconView? = null\n)\n\ndata class BAnimation(\n    val type: Int?,\n    val repeatCount: Int?\n)\n\ndata class BIconView(\n    val type: Int?,\n    val text: String?\n)\n\ndata class BTextInfo(\n    val colorType: ColorType? = null,\n    val maxLines: Int? = null,\n    val gravityList: List<BGravity>? = null,\n    val textAlignmentType: TextAlignmentType? = null,\n    val styleType: Int? = null\n)\n\ndata class BButtonGroupView(\n    val buttonViewList: List<BButtonView>\n)\n\ndata class BInstrumentItemView(\n    val icon: BImageView? = null,\n    val text: BPlayTextView? = null,\n    val tips: BPlayTextView? = null,\n    val extraInfo: BPlayTextView? = null,\n    val state: BImageView? = null,\n    val action: BAction? = null,\n)\n\ndata class BButtonView(\n    val text: String,\n    val viewInfo: BViewInfo? = null,\n    val action: BAction? = null\n)\n\ndata class BViewInfo(\n    val tag: String? = null,\n    val width: Float? = null,\n    val height: Float? = null,\n    val startMargin: Float? = null,\n    val topMargin: Float? = null,\n    val endMargin: Float? = null,\n    val bottomMargin: Float? = null,\n    val startPadding: Float? = null,\n    val topPadding: Float? = null,\n    val endPadding: Float? = null,\n    val bottomPadding: Float? = null,\n    val contentDescription: String? = null,\n    val gravityList: List<BGravity>? = null,\n    val backgroundColorType: ColorType? = null,\n    val borderColorType: ColorType? = null,\n    val action: BAction? = null,\n    val visibilityType: Int? = null\n)\n\nenum class TextAlignmentType(val value: Int) {\n    TEXT_ALIGNMENT_INHERIT(0),\n    TEXT_ALIGNMENT_GRAVITY(1),\n    TEXT_ALIGNMENT_CENTER(4),\n    TEXT_ALIGNMENT_TEXT_START(2),\n    TEXT_ALIGNMENT_TEXT_END(3),\n    TEXT_ALIGNMENT_VIEW_START(5),\n    TEXT_ALIGNMENT_VIEW_END(6)\n}\n\nenum class ColorType(val value: Int) {\n    PHONESKY_SEMANTIC_COLOR_NAME_UNKNOWN(0),\n    BACKGROUND_PRIMARY(1),\n    BACKGROUND_SECONDARY(2),\n    APPS_PRIMARY(3),\n    APPS_2(4),\n    APPS_3(5),\n    BOOKS_PRIMARY(6),\n    BOOKS_2(7),\n    BOOKS_3(8),\n    MOVIES_PRIMARY(9),\n    MOVIES_2(10),\n    MOVIES_3(11),\n    MUSIC_PRIMARY(12),\n    MUSIC_2(13),\n    MUSIC_3(14),\n    ENTERPRISE_PRIMARY(15),\n    ENTERPRISE_2(16),\n    ENTERPRISE_3(17),\n    TEXT_PRIMARY(18),\n    TEXT_SECONDARY(19),\n    TEXT_TERTIARY(20),\n    ICON_DEFAULT(21),\n    ICON_HIGH_CONTRAST(22),\n    PRIMARY_BUTTON_LABEL(23),\n    PRIMARY_BUTTON_LABEL_DISABLED(24),\n    PRIMARY_BUTTON_FILL_DISABLED(25),\n    SECONDARY_BUTTON_FILL_DISABLED(26),\n    CHIP_TEXT_SECONDARY(27),\n    HAIR_LINE(28),\n    ERROR_COLOR_PRIMARY(29),\n    ERROR_COLOR_SECONDARY(30),\n    BLANK_UNIFORM_ICON(31),\n    PROGRESS_BAR_BACKGROUND(32),\n    BRONZE_PRIMARY(33),\n    BRONZE_2(34),\n    BRONZE_3(35),\n    SILVER_PRIMARY(36),\n    SILVER_2(37),\n    SILVER_3(38),\n    GOLD_PRIMARY(39),\n    GOLD_2(40),\n    GOLD_3(41),\n    PLATINUM_PRIMARY(42),\n    PLATINUM_2(43),\n    PLATINUM_3(44),\n    DIAMOND_PRIMARY(45),\n    DIAMOND_2(46),\n    DIAMOND_3(0x2F),\n    NEWS_PRIMARY(0x30),\n    BACKGROUND_PRIMARY_INVERSE(49),\n    TEXT_PRIMARY_DISABLED(50),\n    TEXT_SECONDARY_DISABLED(51),\n    RATING_STAR_OUTLINE(52),\n    TOOLTIP_BACKGROUND(53),\n    YOUTUBE_COMMERCE_NEUTRAL_BLUE(54),\n    YOUTUBE_COMMERCE_NEUTRAL_BLUE_2(62),\n    YOUTUBE_COMMERCE_NEUTRAL_BLUE_3(0x3F),\n    YOUTUBE_COMMERCE_NEUTRAL_BLUE_RIPPLE(55),\n    YOUTUBE_COMMERCE_DEEP_PURPLE(56),\n    YOUTUBE_COMMERCE_DEEP_PURPLE_2(0x40),\n    YOUTUBE_COMMERCE_DEEP_PURPLE_3(65),\n    YOUTUBE_COMMERCE_DEEP_PURPLE_RIPPLE(57),\n    YOUTUBE_COMMERCE_MAGENTA(58),\n    YOUTUBE_COMMERCE_MAGENTA_2(66),\n    YOUTUBE_COMMERCE_MAGENTA_3(67),\n    YOUTUBE_COMMERCE_MAGENTA_RIPPLE(59),\n    YOUTUBE_COMMERCE_TEAL(60),\n    YOUTUBE_COMMERCE_TEAL_2(68),\n    YOUTUBE_COMMERCE_TEAL_3(69),\n    YOUTUBE_COMMERCE_TEAL_RIPPLE(61)\n}\n\nenum class BGravity(val value: Int) {\n    NO_GRAVITY(0),\n    BOTTOM(80),\n    CENTER(17),\n    CENTER_HORIZONTAL(1),\n    CENTER_VERTICAL(16),\n    CLIP_HORIZONTAL(8),\n    CLIP_VERTICAL(0x80),\n    END(0x800005),\n    FILL(0x77),\n    FILL_HORIZONTAL(7),\n    FILL_VERTICAL(0x70),\n    LEFT(0x3),\n    RIGHT(0x5),\n    START(0x800003),\n    TOP(0x30)\n}\n\nenum class ViewType {\n    CLICKABLETEXTVIEW,\n    VIEWGROUP,\n    DIVIDERVIEW,\n    MODULOIMAGEVIEW,\n    ICONTEXTCOMBINATIONVIEW,\n    BUTTONGROUPVIEW,\n    INSTRUMENTITEMVIEW,\n    UNKNOWNVIEW\n}\n\n\nenum class TextSpanType {\n    BULLETSPAN,\n    UNKNOWNSPAN\n}\n\nenum class AnimationType(val value: Int) {\n    CHECK_MARK(21),\n    UNKNOWN(0)\n}"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/core/ui/UIParser.kt",
    "content": "package org.microg.vending.billing.core.ui\n\nimport okio.ByteString\nimport org.json.JSONObject\nimport org.microg.vending.billing.core.AcquireParams\nimport org.microg.vending.billing.core.PurchaseItem\nimport org.microg.vending.billing.core.parsePurchaseItem\nimport org.microg.vending.billing.core.responseBundleToMap\nimport org.microg.vending.billing.proto.*\n\ndata class AcquireParsedResult(\n    val action: BAction? = null,\n    val result: Map<String, Any> = mapOf(\"RESPONSE_CODE\" to 4, \"DEBUG_MESSAGE\" to \"\"),\n    val purchaseItems: List<PurchaseItem>,\n    val screenMap: Map<String, BScreen> = emptyMap()\n)\n\nprivate fun typeToDpSize(type: Int): Float {\n    return when (type) {\n        1 -> 2.0f\n        2 -> 4.0f\n        3 -> 8.0f\n        4 -> 12.0f\n        5 -> 16.0f\n        6 -> 24.0f\n        7 -> 32.0f\n        8 -> 24.0f\n        9 -> 18.0f\n        10 -> 0.0f\n        11 -> 6.0f\n        else -> {\n            0.0f\n        }\n    }\n}\n\nprivate fun parseUIInfo(uiInfo: UIInfo): BUIInfo {\n    if (uiInfo.classType == 1) return BUIInfo(UIType.UNKNOWN)\n    return BUIInfo(UIType.fromValue(uiInfo.uiType))\n}\n\nprivate fun parseScreen(screen: Screen): BScreen {\n    var uiInfo: BUIInfo? = null\n    var uiComponents: BUIComponents? = null\n    var action: BAction? = null\n    screen.uiInfo?.let {\n        uiInfo = parseUIInfo(it)\n    }\n    screen.uiComponents?.let {\n        uiComponents = parseScreenComponents(it)\n    }\n    screen.action?.let {\n        action = BAction(ActionType.UNKNOWN)\n        parseAction(it, action!!)\n    }\n    return BScreen(uiInfo, action, uiComponents)\n}\n\nprivate fun parseScreenMap(screenMap: Map<String, Screen>): Map<String, BScreen> {\n    val result: MutableMap<String, BScreen> = mutableMapOf()\n    for ((screenId, screen) in screenMap) {\n        val bScreen = parseScreen(screen)\n        result[screenId] = bScreen\n    }\n    return result\n}\n\nfun parseAcquireResponse(acquireResponse: AcquireResponse): BAcquireResult {\n    val action = BAction(ActionType.UNKNOWN)\n    parseAction(acquireResponse.action, action)\n    val screenMap = parseScreenMap(acquireResponse.screen)\n    return BAcquireResult(action, screenMap)\n}\n\nprivate fun parseAction(action: Action?, result: BAction): Boolean {\n    if (action == null) return false\n    if (action.actionContext != ByteString.EMPTY) {\n        result.actionContext.add(action.actionContext.toByteArray())\n    }\n    if (action.timerAction != null) {\n        result.delay = action.timerAction.delay\n        result.type = ActionType.DELAY\n        result.result = responseBundleToMap(action.timerAction.responseBundle)\n        return true\n    }\n    if (action.actionExt?.extAction != null) {\n        val extAction = action.actionExt.extAction\n        if (extAction.droidGuardMap != null) {\n            result.droidGuardMap = extAction.droidGuardMap.map\n        }\n        if (extAction.action != null) {\n            return parseAction(extAction.action, result)\n        }\n    }\n    if (action.showAction != null) {\n        result.type = ActionType.SHOW\n        result.screenId = action.showAction.screenId\n        if (action.showAction.action1 != null) {\n            parseAction(action.showAction.action1, result)\n        }\n        if (action.showAction.action != null) {\n            parseAction(action.showAction.action, result)\n        }\n        return true\n    }\n    if (action.viewClickAction != null) {\n        if (action.viewClickAction.uiInfo != null && result.uiInfo == null) {\n            result.uiInfo = parseUIInfo(action.viewClickAction.uiInfo)\n        }\n        return parseAction(action.viewClickAction.action, result)\n    }\n    if (action.optionalAction != null) {\n        return parseAction(action.optionalAction.action1, result)\n    }\n    if (action.navigateToPage != null) {\n        result.srcScreenId = action.navigateToPage.from\n        return parseAction(action.navigateToPage.action, result)\n    }\n    return false\n}\n\nprivate fun parseAnimation(animation: Animation): BAnimation {\n    var type: Int? = null\n    var repeatCount: Int? = null\n    if (animation.type != 0) {\n        type = animation.type\n    }\n    if (animation.repeatCount != 0) {\n        repeatCount = animation.repeatCount\n    }\n    return BAnimation(type, repeatCount)\n}\n\nprivate fun parseIconView(iconView: IconView): BIconView {\n    var type: Int? = null\n    var text: String? = null\n    if (iconView.type != 0) {\n        type = iconView.type\n    }\n    if (iconView.text.isNotBlank()) {\n        text = iconView.text\n    }\n    return BIconView(type, text)\n}\n\nprivate fun parseInstrumentItemView(instrumentItemView: InstrumentItemView): BInstrumentItemView {\n    var icon: BImageView? = null\n    var text: BPlayTextView? = null\n    var tips: BPlayTextView? = null\n    var extraInfo: BPlayTextView? = null\n    var state: BImageView? = null\n    var action: BAction? = null\n    if (instrumentItemView.icon != null) {\n        icon = parseImageView(instrumentItemView.icon)\n    }\n    if (instrumentItemView.text != null) {\n        text = parsePlayTextView(instrumentItemView.text)\n    }\n    if (instrumentItemView.tips != null) {\n        tips = parsePlayTextView(instrumentItemView.tips)\n    }\n    if (instrumentItemView.state != null) {\n        state = parseImageView(instrumentItemView.state)\n    }\n    if (instrumentItemView.action != null) {\n        action = BAction(ActionType.UNKNOWN)\n        parseAction(instrumentItemView.action, action)\n    }\n    if (instrumentItemView.extraInfo != null) {\n        extraInfo = parsePlayTextView(instrumentItemView.extraInfo)\n    }\n    return BInstrumentItemView(icon, text, tips, extraInfo, state, action)\n}\n\nprivate fun parseImageGroup(imageGroup: ImageGroup): BImageGroup {\n    val imageViews = mutableListOf<BImageView>()\n    var viewInfo: BViewInfo? = null\n\n    if (imageGroup.viewInfo != null) {\n        viewInfo = parseViewInfo(imageGroup.viewInfo)\n    }\n    imageGroup.imageView.forEach {\n        imageViews.add(parseImageView(it))\n    }\n    return BImageGroup(imageViews, viewInfo)\n}\n\nprivate fun parseImageView(imageView: ImageView): BImageView {\n    var darkUrl: String? = null\n    var lightUrl: String? = null\n    var viewInfo: BViewInfo? = null\n    var imageInfo: BImageInfo? = null\n    var iconView: BIconView? = null\n    var animation: BAnimation? = null\n    if (imageView.thumbnailImageView != null) {\n        if (imageView.thumbnailImageView.darkUrl.isNotBlank())\n            darkUrl = imageView.thumbnailImageView.darkUrl\n        if (imageView.thumbnailImageView.lightUrl.isNotBlank())\n            lightUrl = imageView.thumbnailImageView.lightUrl\n    }\n    if (imageView.viewInfo != null) {\n        viewInfo = parseViewInfo(imageView.viewInfo)\n    }\n    if (imageView.imageInfo != null) {\n        imageInfo = parseImageInfo(imageView.imageInfo)\n    }\n    if (imageView.iconView != null) {\n        iconView = parseIconView(imageView.iconView)\n    }\n    if (imageView.animation != null) {\n        animation = parseAnimation(imageView.animation)\n    }\n    return BImageView(viewInfo, imageInfo, lightUrl, darkUrl, animation, iconView)\n}\n\nprivate fun parseTextInfo(textInfo: TextInfo): BTextInfo {\n    var colorType: ColorType? = null\n    var maxLines: Int? = null\n    var gravityList: List<BGravity>? = null\n    var textAlignmentType: TextAlignmentType? = null\n    var styleType: Int? = null\n    if (textInfo.maxLines != 0) {\n        maxLines = textInfo.maxLines\n    }\n    if (textInfo.gravity.isNotEmpty()) {\n        gravityList = textInfo.gravity.map { BGravity.values()[it] }\n    }\n    if (textInfo.textColorType != null) {\n        colorType = ColorType.values()[textInfo.textColorType]\n    }\n    if (textInfo.textAlignmentType != 0) {\n        textAlignmentType = TextAlignmentType.values()[textInfo.textAlignmentType]\n    }\n    if (textInfo.styleType != 0) {\n        styleType = textInfo.styleType\n    }\n    return BTextInfo(colorType, maxLines, gravityList, textAlignmentType, styleType)\n}\n\nprivate fun parseBulletSpan(bulletSpan: BulletSpan): BBulletSpan {\n    return BBulletSpan(bulletSpan.gapWidth?.unitValue?.toInt() ?: 0)\n}\n\nprivate fun parseTextSpan(textSpan: TextSpan): BTextSpan {\n    return if (textSpan.bulletSpan != null) {\n        BTextSpan(\n            TextSpanType.BULLETSPAN,\n            parseBulletSpan(textSpan.bulletSpan)\n        )\n    } else {\n        BTextSpan(TextSpanType.UNKNOWNSPAN)\n    }\n}\n\nprivate fun parsePlayTextView(playTextView: PlayTextView): BPlayTextView {\n    var textInfo: BTextInfo? = null\n    var viewInfo: BViewInfo? = null\n    var textSpanList: MutableList<BTextSpan> = mutableListOf()\n    if (playTextView.textInfo != null) {\n        textInfo = parseTextInfo(playTextView.textInfo)\n    }\n    if (playTextView.viewInfo != null) {\n        viewInfo = parseViewInfo(playTextView.viewInfo)\n    }\n    if (playTextView.textSpan.isNotEmpty()) {\n        playTextView.textSpan.forEach {\n            textSpanList.add(parseTextSpan(it))\n        }\n    }\n    return BPlayTextView(\n        playTextView.text ?: \"\",\n        playTextView.isHtml,\n        textInfo,\n        viewInfo,\n        textSpanList\n    )\n}\n\nprivate fun parseSingleLineTextView(singleLineTextView: SingleLineTextView): BSingleLineTextView {\n    var playTextView1: BPlayTextView? = null\n    var playTextView2: BPlayTextView? = null\n\n    if (singleLineTextView.playTextView1 != null)\n        playTextView1 = parsePlayTextView(singleLineTextView.playTextView1)\n    if (singleLineTextView.playTextView2 != null)\n        playTextView2 = parsePlayTextView(singleLineTextView.playTextView2)\n\n    return BSingleLineTextView(playTextView1, playTextView2)\n}\n\nprivate fun parseIconTextCombinationView(iconTextCombinationView: IconTextCombinationView): BIconTextCombinationView {\n    var headerImageView: BImageView? = null\n    var playTextView: BPlayTextView? = null\n    var badgeTextView: BPlayTextView? = null\n    var middleTextViewList: List<BSingleLineTextView>? = null\n    var viewInfo: BViewInfo? = null\n    var footerImageGroup: BImageGroup? = null\n\n    if (iconTextCombinationView.headerImageView != null) {\n        headerImageView = parseImageView(iconTextCombinationView.headerImageView)\n    }\n    if (iconTextCombinationView.playTextView != null) {\n        playTextView = parsePlayTextView(iconTextCombinationView.playTextView)\n    }\n    if (iconTextCombinationView.badgeTextView != null) {\n        badgeTextView = parsePlayTextView(iconTextCombinationView.badgeTextView)\n    }\n    if (iconTextCombinationView.singleLineTextView.isNotEmpty()) {\n        middleTextViewList =\n            iconTextCombinationView.singleLineTextView.map { parseSingleLineTextView(it) }\n    }\n    if (iconTextCombinationView.footerImageGroup != null) {\n        footerImageGroup = parseImageGroup(iconTextCombinationView.footerImageGroup)\n    }\n    if (iconTextCombinationView.viewInfo != null) {\n        viewInfo = parseViewInfo(iconTextCombinationView.viewInfo)\n    }\n\n    return BIconTextCombinationView(\n        headerImageView,\n        playTextView,\n        badgeTextView,\n        middleTextViewList,\n        footerImageGroup,\n        viewInfo\n    )\n}\n\nprivate fun parseClickableTextView(clickableTextView: ClickableTextView): BClickableTextView {\n    var playTextView: BPlayTextView? = null\n    if (clickableTextView.playTextView != null)\n        playTextView = parsePlayTextView(clickableTextView.playTextView)\n    return BClickableTextView(playTextView)\n}\n\nprivate fun parseViewGroup(viewGroup: ViewGroup): BViewGroup {\n    var imageView1: BImageView? = null\n    var imageView2: BImageView? = null\n    var imageView3: BImageView? = null\n    var imageView4: BImageView? = null\n    var playTextView: BPlayTextView? = null\n    if (viewGroup.imageView1 != null) {\n        imageView1 = parseImageView(viewGroup.imageView1)\n    }\n    if (viewGroup.imageView2 != null) {\n        imageView2 = parseImageView(viewGroup.imageView2)\n    }\n    if (viewGroup.imageView3 != null) {\n        imageView3 = parseImageView(viewGroup.imageView3)\n    }\n    if (viewGroup.imageView4 != null) {\n        imageView4 = parseImageView(viewGroup.imageView4)\n    }\n    if (viewGroup.playTextView != null) {\n        playTextView = parsePlayTextView(viewGroup.playTextView)\n    }\n    return BViewGroup(imageView1, imageView2, imageView3, imageView4, playTextView)\n}\n\nprivate fun parseModuloImageView(moduloImageView: ModuloImageView): BModuloImageView {\n    var imageView: BImageView? = null\n    if (moduloImageView.imageView != null) {\n        imageView = parseImageView(moduloImageView.imageView)\n    }\n    return BModuloImageView(imageView)\n}\n\nprivate fun parseDividerView(dividerView: DividerView): BDividerView {\n    return BDividerView()\n}\n\nprivate fun parseImageInfo(imageInfo: ImageInfo): BImageInfo {\n    var colorFilterValue: Int? = null\n    var colorFilterType: Int? = null\n    var filterMode: Int? = null\n    var scaleType: Int? = null\n    if (imageInfo.value_ != null) {\n        colorFilterValue = imageInfo.value_\n    } else if (imageInfo.valueType != null) {\n        colorFilterType = imageInfo.valueType\n    }\n    if (imageInfo.modeType != 0) {\n        filterMode = imageInfo.modeType\n    }\n    if (imageInfo.scaleType != 0) {\n        scaleType = imageInfo.scaleType\n    }\n    return BImageInfo(colorFilterValue, colorFilterType, filterMode, scaleType)\n}\n\nprivate fun parseViewInfo(viewInfo: ViewInfo): BViewInfo {\n    var tag: String? = null\n    var width: Float? = null\n    var height: Float? = null\n    var startMargin: Float? = null\n    var topMargin: Float? = null\n    var endMargin: Float? = null\n    var bottomMargin: Float? = null\n    var startPadding: Float? = null\n    var topPadding: Float? = null\n    var endPadding: Float? = null\n    var bottomPadding: Float? = null\n    var contentDescription: String? = null\n    var gravityList: List<BGravity>? = null\n    var backgroundColorType: ColorType? = null\n    var borderColorType: ColorType? = null\n    var action: BAction? = null\n    var visibilityType: Int? = null\n\n    if (viewInfo.tag.isNotBlank()) {\n        tag = viewInfo.tag\n    }\n    if (viewInfo.widthValue != 0f) {\n        width = viewInfo.widthValue\n    }\n    if (viewInfo.heightValue != 0f) {\n        height = viewInfo.heightValue\n    }\n    if (viewInfo.startMargin != 0f) {\n        startMargin = viewInfo.startMargin\n    }\n    if (viewInfo.topMargin != 0f) {\n        topMargin = viewInfo.topMargin\n    }\n    if (viewInfo.endMargin != 0f) {\n        endMargin = viewInfo.endMargin\n    }\n    if (viewInfo.bottomMargin != 0f) {\n        bottomMargin = viewInfo.bottomMargin\n    }\n    if (viewInfo.startPadding != 0f) {\n        startPadding = viewInfo.startPadding\n    }\n    if (viewInfo.topPadding != 0f) {\n        topPadding = viewInfo.topPadding\n    }\n    if (viewInfo.endPadding != 0f) {\n        endPadding = viewInfo.endPadding\n    }\n    if (viewInfo.bottomPadding != 0f) {\n        bottomPadding = viewInfo.bottomPadding\n    }\n    if (viewInfo.startMarginType != 0) {\n        startMargin = typeToDpSize(viewInfo.startMarginType)\n    }\n    if (viewInfo.topMarginType != 0) {\n        topMargin = typeToDpSize(viewInfo.topMarginType)\n    }\n    if (viewInfo.endMarginType != 0) {\n        endMargin = typeToDpSize(viewInfo.endMarginType)\n    }\n    if (viewInfo.bottomMarginType != 0) {\n        bottomMargin = typeToDpSize(viewInfo.bottomMarginType)\n    }\n    if (viewInfo.startPaddingType != 0) {\n        startPadding = typeToDpSize(viewInfo.startPaddingType)\n    }\n    if (viewInfo.topPaddingType != 0) {\n        topPadding = typeToDpSize(viewInfo.topPaddingType)\n    }\n    if (viewInfo.endPaddingType != 0) {\n        endPadding = typeToDpSize(viewInfo.endPaddingType)\n    }\n    if (viewInfo.bottomPaddingType != 0) {\n        bottomPadding = typeToDpSize(viewInfo.bottomPaddingType)\n    }\n    if (viewInfo.contentDescription.isNotBlank()) {\n        contentDescription = viewInfo.contentDescription\n    }\n    if (viewInfo.gravity.isNotEmpty()) {\n        gravityList = viewInfo.gravity.map { BGravity.values()[it] }\n    }\n    if (viewInfo.backgroundColorType != 0) {\n        backgroundColorType = ColorType.values()[viewInfo.backgroundColorType]\n    }\n    if (viewInfo.borderColorType != 0) {\n        borderColorType = ColorType.values()[viewInfo.borderColorType]\n    }\n    if (viewInfo.action != null) {\n        action = BAction(ActionType.UNKNOWN)\n        parseAction(viewInfo.action, action)\n    }\n    if (viewInfo.visibilityType != 0) {\n        visibilityType = viewInfo.visibilityType\n    }\n    return BViewInfo(\n        tag,\n        width,\n        height,\n        startMargin,\n        topMargin,\n        endMargin,\n        bottomMargin,\n        startPadding,\n        topPadding,\n        endPadding,\n        bottomPadding,\n        contentDescription,\n        gravityList,\n        backgroundColorType,\n        borderColorType,\n        action,\n        visibilityType\n    )\n}\n\nprivate fun parseContentComponent(contentComponent: ContentComponent): BComponent {\n    val tag = contentComponent.tag\n    var viewInfo: BViewInfo? = null\n    var uiInfo: BUIInfo? = null\n    if (contentComponent.viewInfo != null) {\n        viewInfo = parseViewInfo(contentComponent.viewInfo)\n    }\n    if (contentComponent.uiInfo != null) {\n        uiInfo = parseUIInfo(contentComponent.uiInfo)\n    }\n    return if (contentComponent.iconTextCombinationView != null) {\n        BComponent(\n            tag,\n            uiInfo,\n            viewInfo,\n            ViewType.ICONTEXTCOMBINATIONVIEW,\n            iconTextCombinationView = parseIconTextCombinationView(contentComponent.iconTextCombinationView)\n        )\n    } else if (contentComponent.clickableTextView != null) {\n        BComponent(\n            tag,\n            uiInfo,\n            viewInfo,\n            ViewType.CLICKABLETEXTVIEW,\n            clickableTextView = parseClickableTextView(contentComponent.clickableTextView)\n        )\n    } else if (contentComponent.viewGroup != null) {\n        BComponent(\n            tag,\n            uiInfo,\n            viewInfo,\n            ViewType.VIEWGROUP,\n            viewGroup = parseViewGroup(contentComponent.viewGroup)\n        )\n    } else if (contentComponent.dividerView != null) {\n        BComponent(\n            tag,\n            uiInfo,\n            viewInfo,\n            ViewType.DIVIDERVIEW,\n            dividerView = parseDividerView(contentComponent.dividerView)\n        )\n    } else if (contentComponent.moduloImageView != null) {\n        BComponent(\n            tag,\n            uiInfo,\n            viewInfo,\n            ViewType.MODULOIMAGEVIEW,\n            moduloImageView = parseModuloImageView(contentComponent.moduloImageView)\n        )\n    } else if (contentComponent.buttonGroupView != null) {\n        BComponent(\n            tag,\n            uiInfo,\n            viewInfo,\n            ViewType.BUTTONGROUPVIEW,\n            buttonGroupView = parseButtonGroupView(contentComponent.buttonGroupView)\n        )\n    } else if (contentComponent.instrumentItemView != null) {\n        BComponent(\n            tag,\n            uiInfo,\n            viewInfo,\n            ViewType.INSTRUMENTITEMVIEW,\n            instrumentItemView = parseInstrumentItemView(contentComponent.instrumentItemView)\n        )\n    } else {\n        BComponent(viewType = ViewType.UNKNOWNVIEW)\n    }\n}\n\nprivate fun parseButtonView(buttonView: ButtonView): BButtonView {\n    var text = \"\"\n    var viewInfo: BViewInfo? = null\n    val action = BAction(ActionType.UNKNOWN)\n    text = buttonView.text ?: \"\"\n    if (buttonView.viewInfo != null) {\n        viewInfo = parseViewInfo(buttonView.viewInfo)\n    }\n    if (buttonView.action != null) {\n        parseAction(buttonView.action, action)\n    }\n    return BButtonView(text, viewInfo, action)\n}\n\nprivate fun parseButtonGroupView(buttonGroupView: ButtonGroupView): BButtonGroupView {\n    var buttonViewList = mutableListOf<BButtonView>()\n\n    if (buttonGroupView.newButtonView != null) {\n        if (buttonGroupView.newButtonView.buttonView != null) {\n            buttonViewList.add(parseButtonView(buttonGroupView.newButtonView.buttonView))\n        }\n        if (buttonGroupView.newButtonView.buttonView2 != null) {\n            buttonViewList.add(parseButtonView(buttonGroupView.newButtonView.buttonView2))\n        }\n    }\n    return BButtonGroupView(buttonViewList)\n}\n\nprivate fun parseFooterComponent(footerComponent: FooterComponent): BComponent {\n    val tag = footerComponent.tag\n    var viewInfo: BViewInfo? = null\n    var uiInfo: BUIInfo? = null\n    if (footerComponent.viewInfo != null) {\n        viewInfo = parseViewInfo(footerComponent.viewInfo)\n    }\n    if (footerComponent.uiInfo != null) {\n        uiInfo = parseUIInfo(footerComponent.uiInfo)\n    }\n    return if (footerComponent.buttonGroupView != null) {\n        BComponent(\n            tag,\n            uiInfo,\n            viewInfo,\n            ViewType.BUTTONGROUPVIEW,\n            buttonGroupView = parseButtonGroupView(footerComponent.buttonGroupView)\n        )\n    } else if (footerComponent.dividerView != null) {\n        BComponent(\n            tag,\n            uiInfo,\n            viewInfo,\n            ViewType.DIVIDERVIEW,\n            dividerView = parseDividerView(footerComponent.dividerView)\n        )\n    } else {\n        BComponent(viewType = ViewType.UNKNOWNVIEW)\n    }\n}\n\nprivate fun parseScreenComponents(uiComponents: UiComponents): BUIComponents {\n    val headerComponents = mutableListOf<BComponent>()\n    val contentComponents = mutableListOf<BComponent>()\n    val footerComponents = mutableListOf<BComponent>()\n    for (contentComponent in uiComponents.contentComponent1) {\n        headerComponents.add(parseContentComponent(contentComponent))\n    }\n    for (contentComponent in uiComponents.contentComponent2) {\n        contentComponents.add(parseContentComponent(contentComponent))\n    }\n    for (footerComponent in uiComponents.footerComponent) {\n        footerComponents.add(parseFooterComponent(footerComponent))\n    }\n\n    return BUIComponents(headerComponents, contentComponents, footerComponents)\n}\n\nfun parsePurchaseResponse(\n    acquireParams: AcquireParams,\n    purchaseResponse: PurchaseResponse?\n): Pair<Map<String, Any>, PurchaseItem?> {\n    if (purchaseResponse == null) {\n        return mapOf<String, Any>(\"RESPONSE_CODE\" to 0, \"DEBUG_MESSAGE\" to \"\") to null\n    }\n    val resultMap = responseBundleToMap(purchaseResponse.responseBundle)\n    val code = resultMap[\"RESPONSE_CODE\"] as Int? ?: return mapOf<String, Any>(\n        \"RESPONSE_CODE\" to 0,\n        \"DEBUG_MESSAGE\" to \"\"\n    ) to null\n    val pd = resultMap[\"INAPP_PURCHASE_DATA\"] as String? ?: return resultMap to null\n    val ps = resultMap[\"INAPP_DATA_SIGNATURE\"] as String? ?: return resultMap to null\n    if (code != 0) return resultMap to null\n    val pdj = JSONObject(pd)\n    val packageName =\n        pdj.optString(\"packageName\").takeIf { it.isNotBlank() } ?: return resultMap to null\n    val purchaseToken =\n        pdj.optString(\"purchaseToken\").takeIf { it.isNotBlank() } ?: return resultMap to null\n    val purchaseState =\n        pdj.optInt(\"purchaseState\", -1).takeIf { it != -1 } ?: return resultMap to null\n    return resultMap to PurchaseItem(\n        acquireParams.buyFlowParams.skuType,\n        acquireParams.buyFlowParams.sku,\n        packageName,\n        purchaseToken,\n        purchaseState,\n        pd, ps\n    )\n}\n\nfun parseAcquireResponse(\n    acquireParams: AcquireParams,\n    acquireResponse: AcquireResponse\n): AcquireParsedResult {\n    val action = BAction(ActionType.UNKNOWN)\n    parseAction(acquireResponse.action, action)\n    val screenMap = parseScreenMap(acquireResponse.screen)\n    val (result, purchaseItem) = parsePurchaseResponse(\n        acquireParams,\n        acquireResponse.acquireResult?.purchaseResponse\n    )\n    val purchaseItems = mutableSetOf<PurchaseItem>()\n    if (acquireResponse.acquireResult?.ownedPurchase != null) {\n        acquireResponse.acquireResult.ownedPurchase.purchaseItem.forEach {\n            purchaseItems.addAll(parsePurchaseItem(it))\n        }\n    }\n    if (purchaseItem != null) purchaseItems.add(purchaseItem)\n    return AcquireParsedResult(action, result, purchaseItems.toList(), screenMap)\n}"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/core/ui/UIType.kt",
    "content": "package org.microg.vending.billing.core.ui\n\nval UITypeIndexMap: Map<Int, UIType> = UIType.values().associateBy { it.value }\n\nenum class UIType(val value: Int) {\n    UNKNOWN(-1),\n    LOADING_SPINNER(213),\n    PURCHASE_CART_BUY_BUTTON(711),\n    PURCHASE_CART_CONTINUE_BUTTON(712),\n    PURCHASE_CART_PAYMENT_OPTIONS_LINK(714),\n    PURCHASE_AUTH_SCREEN(750),\n    PURCHASE_ERROR_SCREEN(770),\n    BILLING_PROFILE_OPTION_REDEEM_CODE(815),\n    BILLING_PROFILE_OPTION_ADD_PLAY_CREDIT(816),\n    BILLING_PROFILE_OPTION_CREATE_INSTRUMENT(817),\n    BILLING_PROFILE_EXISTING_INSTRUMENT(818),\n    BILLING_PROFILE_BUTTON_UPDATE_INSTRUMENT(819),\n    PURCHASE_SUCCESS_SCREEN_WITH_AUTH_CHOICES(1250),\n    PURCHASE_CHANGE_SUBSCRIPTION_CONTINUE_BUTTON(1281),\n    PURCHASE_PAYMENT_DECLINED_CONTINUE_BUTTON(1301),\n    BILLING_PROFILE_MORE_OPTION_BUTTON_SHOW_HIDEABLE_INSTRUMENT(12034),\n    PURCHASE_CONSENT_COLLECTION_REFUND_RIGHTS_CONTINUE_BUTTON(11872),\n    BILLING_PROFILE_SCREEN_ABANDON(12035);\n\n    companion object {\n        fun fromValue(value: Int): UIType {\n            return UITypeIndexMap[value] ?: UNKNOWN\n        }\n    }\n}"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/ui/Extends.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.vending.billing.ui\n\nimport androidx.compose.foundation.BorderStroke\nimport androidx.compose.foundation.background\nimport androidx.compose.foundation.border\nimport androidx.compose.foundation.clickable\nimport androidx.compose.foundation.layout.ColumnScope\nimport androidx.compose.foundation.layout.RowScope\nimport androidx.compose.foundation.layout.height\nimport androidx.compose.foundation.layout.padding\nimport androidx.compose.foundation.layout.size\nimport androidx.compose.foundation.layout.width\nimport androidx.compose.foundation.shape.RoundedCornerShape\nimport androidx.compose.runtime.Composable\nimport androidx.compose.ui.Alignment\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.composed\nimport androidx.compose.ui.layout.layout\nimport androidx.compose.ui.unit.Dp\nimport androidx.compose.ui.unit.DpSize\nimport androidx.compose.ui.unit.dp\nimport org.microg.vending.billing.containsAny\nimport org.microg.vending.billing.core.ui.BGravity\nimport org.microg.vending.billing.core.ui.BViewInfo\nimport org.microg.vending.billing.core.ui.UIType\n\nfun RowScope.applyAlignment(modifier: Modifier, viewInfo: BViewInfo?): Modifier {\n    val gravitys = viewInfo?.gravityList ?: return modifier\n    var newModifier = modifier\n    if (gravitys.containsAny(listOf(BGravity.TOP))) {\n        newModifier = newModifier.align(Alignment.Top)\n    }\n    if (gravitys.containsAny(listOf(BGravity.CENTER, BGravity.CENTER_VERTICAL))) {\n        newModifier = newModifier.align(Alignment.CenterVertically)\n    }\n    if (gravitys.containsAny(listOf(BGravity.BOTTOM))) {\n        newModifier = newModifier.align(Alignment.Bottom)\n    }\n\n    return newModifier\n}\n\nfun ColumnScope.applyAlignment(modifier: Modifier, viewInfo: BViewInfo?): Modifier {\n    val gravitys = viewInfo?.gravityList ?: return modifier\n    var newModifier = modifier\n    if (gravitys.containsAny(listOf(BGravity.START, BGravity.LEFT))) {\n        newModifier = newModifier.align(Alignment.Start)\n    }\n    if (gravitys.containsAny(listOf(BGravity.CENTER, BGravity.CENTER_HORIZONTAL))) {\n        newModifier = newModifier.align(Alignment.CenterHorizontally)\n    }\n    if (gravitys.containsAny(listOf(BGravity.RIGHT, BGravity.END))) {\n        newModifier = newModifier.align(Alignment.End)\n    }\n\n    return newModifier\n}\n\nfun Modifier.visibility(visibleType: Int): Modifier {\n    val visible = when (visibleType) {\n        1 -> false\n        else -> true\n    }\n    return this.layout { measurable, constraints ->\n        val placeable = measurable.measure(constraints)\n        if (visible) {\n            layout(placeable.width, placeable.height) {\n                // place this item in the original position\n                placeable.placeRelative(0, 0)\n            }\n        } else {\n            layout(0, 0) {}\n        }\n    }\n}\n\nfun Modifier.applySize(size: DpSize?): Modifier = composed {\n    this.let { mit ->\n        var newModifier = mit\n        size?.let {\n            newModifier = newModifier.size(size)\n        }\n        newModifier\n    }\n}\n\n@Composable\nfun Modifier.applyViewInfo(viewInfo: BViewInfo?): Modifier {\n    return this.let { mit ->\n        var newModifier = mit\n        viewInfo?.visibilityType?.let {\n            newModifier = newModifier.visibility(it)\n        }\n        viewInfo?.startMargin?.let {\n            newModifier = newModifier.padding(start = Dp(it.takeIf { it > 0 } ?: 0f))\n        }\n        viewInfo?.topMargin?.let {\n            newModifier = newModifier.padding(top = Dp(it.takeIf { it > 0 } ?: 0f))\n        }\n        viewInfo?.endMargin?.let {\n            newModifier = newModifier.padding(end = Dp(it.takeIf { it > 0 } ?: 0f))\n        }\n        viewInfo?.bottomMargin?.let {\n            newModifier = newModifier.padding(bottom = Dp(it.takeIf { it > 0 } ?: 0f))\n        }\n        viewInfo?.action?.let { action ->\n            when (action.uiInfo?.uiType) {\n                UIType.BILLING_PROFILE_SCREEN_ABANDON,\n                UIType.PURCHASE_CART_PAYMENT_OPTIONS_LINK,\n                UIType.BILLING_PROFILE_OPTION_REDEEM_CODE,\n                UIType.BILLING_PROFILE_OPTION_ADD_PLAY_CREDIT,\n                UIType.BILLING_PROFILE_OPTION_CREATE_INSTRUMENT -> {\n                    val viewState = LocalBillingUiViewState.current\n                    newModifier = newModifier.clickable {\n                        viewState.onClickAction(action)\n                    }\n                }\n\n                else -> {}\n            }\n        }\n        viewInfo?.width?.let {\n            newModifier = newModifier.width(Dp(it))\n        }\n        viewInfo?.height?.let {\n            newModifier = newModifier.height(Dp(it))\n        }\n        getColorByType(viewInfo?.borderColorType)?.let {\n            newModifier = newModifier.border(BorderStroke(1.dp, it), shape = RoundedCornerShape(5))\n        }\n        getColorByType(viewInfo?.backgroundColorType)?.let {\n            newModifier = newModifier.background(it)\n        }\n        viewInfo?.startPadding?.let {\n            newModifier = newModifier.padding(start = Dp(it.takeIf { it > 0 } ?: 0f))\n        }\n        viewInfo?.topPadding?.let {\n            newModifier = newModifier.padding(top = Dp(it.takeIf { it > 0 } ?: 0f))\n        }\n        viewInfo?.endPadding?.let {\n            newModifier = newModifier.padding(end = Dp(it.takeIf { it > 0 } ?: 0f))\n        }\n        viewInfo?.bottomPadding?.let {\n            newModifier = newModifier.padding(bottom = Dp(it.takeIf { it > 0 } ?: 0f))\n        }\n\n        newModifier\n    }\n}\n\nfun Modifier.applyUITypePadding(uiType: UIType?): Modifier {\n    if (uiType == UIType.PURCHASE_ERROR_SCREEN) {\n        return this.padding(top = 15.dp, start = 30.dp, end = 30.dp)\n    }\n    return this\n}"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/ui/HtmlText.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.vending.billing.ui\n\nimport android.graphics.Typeface\nimport android.os.Build.VERSION.SDK_INT\nimport android.text.Html\nimport android.text.Spanned\nimport android.text.style.ForegroundColorSpan\nimport android.text.style.StrikethroughSpan\nimport android.text.style.StyleSpan\nimport android.text.style.URLSpan\nimport android.text.style.UnderlineSpan\nimport androidx.annotation.StringRes\nimport androidx.compose.foundation.gestures.detectTapGestures\nimport androidx.compose.foundation.text.InlineTextContent\nimport androidx.compose.material3.LocalTextStyle\nimport androidx.compose.material3.MaterialTheme\nimport androidx.compose.material3.Text\nimport androidx.compose.runtime.Composable\nimport androidx.compose.runtime.mutableStateOf\nimport androidx.compose.runtime.remember\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.graphics.Color\nimport androidx.compose.ui.input.pointer.pointerInput\nimport androidx.compose.ui.platform.LocalContext\nimport androidx.compose.ui.platform.LocalUriHandler\nimport androidx.compose.ui.semantics.CustomAccessibilityAction\nimport androidx.compose.ui.semantics.Role\nimport androidx.compose.ui.semantics.customActions\nimport androidx.compose.ui.semantics.onClick\nimport androidx.compose.ui.semantics.role\nimport androidx.compose.ui.semantics.semantics\nimport androidx.compose.ui.text.AnnotatedString\nimport androidx.compose.ui.text.SpanStyle\nimport androidx.compose.ui.text.TextLayoutResult\nimport androidx.compose.ui.text.TextStyle\nimport androidx.compose.ui.text.buildAnnotatedString\nimport androidx.compose.ui.text.font.FontFamily\nimport androidx.compose.ui.text.font.FontStyle\nimport androidx.compose.ui.text.font.FontWeight\nimport androidx.compose.ui.text.style.TextAlign\nimport androidx.compose.ui.text.style.TextDecoration\nimport androidx.compose.ui.text.style.TextOverflow\nimport androidx.compose.ui.unit.TextUnit\nimport androidx.core.text.HtmlCompat\nimport androidx.core.text.getSpans\n\n/**\n * Simple Text composable to show the text with html styling from a String.\n * Supported are:\n *\n * &lt;b>Bold&lt;/b>\n *\n * &lt;i>Italic&lt;/i>\n *\n * &lt;u>Underlined&lt;/u>\n *\n * &lt;strike>Strikethrough&lt;/strike>\n *\n * &lt;a href=\"https://google.de\">Link&lt;/a>\n *\n * @see androidx.compose.material.Text\n *\n */\n@Composable\nfun HtmlText(\n    modifier: Modifier = Modifier,\n    text: String,\n    urlSpanStyle: SpanStyle = SpanStyle(\n        color = MaterialTheme.colorScheme.secondary,\n        textDecoration = TextDecoration.Underline\n    ),\n    colorMapping: Map<Color, Color> = emptyMap(),\n    color: Color = Color.Unspecified,\n    fontSize: TextUnit = TextUnit.Unspecified,\n    fontStyle: FontStyle? = null,\n    fontWeight: FontWeight? = null,\n    fontFamily: FontFamily? = null,\n    letterSpacing: TextUnit = TextUnit.Unspecified,\n    textDecoration: TextDecoration? = null,\n    textAlign: TextAlign? = null,\n    lineHeight: TextUnit = TextUnit.Unspecified,\n    overflow: TextOverflow = TextOverflow.Clip,\n    softWrap: Boolean = true,\n    maxLines: Int = Int.MAX_VALUE,\n    inlineContent: Map<String, InlineTextContent> = mapOf(),\n    onTextLayout: (TextLayoutResult) -> Unit = {},\n    style: TextStyle = LocalTextStyle.current,\n    onUriClick: ((String) -> Unit)? = null,\n) {\n    val annotatedString = HtmlCompat.fromHtml(text, HtmlCompat.FROM_HTML_MODE_LEGACY).toAnnotatedString(urlSpanStyle, colorMapping)\n\n    HtmlText(\n        modifier = modifier,\n        annotatedString = annotatedString,\n        color = color,\n        fontSize = fontSize,\n        fontStyle = fontStyle,\n        fontWeight = fontWeight,\n        fontFamily = fontFamily,\n        letterSpacing = letterSpacing,\n        textDecoration = textDecoration,\n        textAlign = textAlign,\n        lineHeight = lineHeight,\n        overflow = overflow,\n        softWrap = softWrap,\n        maxLines = maxLines,\n        inlineContent = inlineContent,\n        onTextLayout = onTextLayout,\n        style = style,\n        onUriClick = onUriClick\n    )\n}\n\n/**\n * Simple Text composable to show the text with html styling from a String.\n * Supported are:\n *\n * &lt;b>Bold&lt;/b>\n *\n * &lt;i>Italic&lt;/i>\n *\n * &lt;u>Underlined&lt;/u>\n *\n * &lt;strike>Strikethrough&lt;/strike>\n *\n * &lt;a href=\"https://google.de\">Link&lt;/a>\n *\n * @see androidx.compose.material.Text\n *\n */\n@Composable\nfun HtmlText(\n    modifier: Modifier = Modifier,\n    annotatedString: AnnotatedString,\n    color: Color = Color.Unspecified,\n    fontSize: TextUnit = TextUnit.Unspecified,\n    fontStyle: FontStyle? = null,\n    fontWeight: FontWeight? = null,\n    fontFamily: FontFamily? = null,\n    letterSpacing: TextUnit = TextUnit.Unspecified,\n    textDecoration: TextDecoration? = null,\n    textAlign: TextAlign? = null,\n    lineHeight: TextUnit = TextUnit.Unspecified,\n    overflow: TextOverflow = TextOverflow.Clip,\n    softWrap: Boolean = true,\n    maxLines: Int = Int.MAX_VALUE,\n    inlineContent: Map<String, InlineTextContent> = mapOf(),\n    onTextLayout: (TextLayoutResult) -> Unit = {},\n    style: TextStyle = LocalTextStyle.current,\n    onUriClick: ((String) -> Unit)? = null,\n) {\n    val clickable =\n        annotatedString.getStringAnnotations(0, annotatedString.length - 1).any { it.tag == \"url\" }\n\n    val uriHandler = LocalUriHandler.current\n    val layoutResult = remember { mutableStateOf<TextLayoutResult?>(null) }\n\n    val urls = remember(layoutResult, annotatedString) {\n        annotatedString.getStringAnnotations(\"url\", 0, annotatedString.lastIndex)\n    }\n\n    Text(\n        modifier = modifier.then(if (clickable) Modifier\n            .pointerInput(Unit) {\n                detectTapGestures(onTap = { pos ->\n                    layoutResult.value?.let { layoutResult ->\n                        val position = layoutResult.getOffsetForPosition(pos)\n                        annotatedString\n                            .getStringAnnotations(position, position)\n                            .firstOrNull()\n                            ?.let { sa ->\n                                if (sa.tag == \"url\") { // NON-NLS\n                                    val url = sa.item\n                                    onUriClick?.let { it(url) } ?: uriHandler.openUri(url)\n                                }\n                            }\n                    }\n                })\n            }\n            .semantics {\n                if (urls.size == 1) {\n                    role = Role.Button\n                    onClick(\"Link (${annotatedString.substring(urls[0].start, urls[0].end)}\") {\n                        val url = urls[0].item\n                        onUriClick?.let { it(url) } ?: uriHandler.openUri(url)\n                        true\n                    }\n                } else {\n                    customActions = urls.map {\n                        CustomAccessibilityAction(\"Link (${annotatedString.substring(it.start, it.end)})\") {\n                            val url = it.item\n                            onUriClick?.let { it(url) } ?: uriHandler.openUri(url)\n                            true\n                        }\n                    }\n                }\n            } else Modifier),\n        text = annotatedString,\n        color = color,\n        fontSize = fontSize,\n        fontStyle = fontStyle,\n        fontWeight = fontWeight,\n        fontFamily = fontFamily,\n        letterSpacing = letterSpacing,\n        textDecoration = textDecoration,\n        textAlign = textAlign,\n        lineHeight = lineHeight,\n        overflow = overflow,\n        softWrap = softWrap,\n        maxLines = maxLines,\n        inlineContent = inlineContent,\n        onTextLayout = {\n            layoutResult.value = it\n            onTextLayout(it)\n        },\n        style = style\n    )\n}\n\nfun Spanned.toAnnotatedString(\n    urlSpanStyle: SpanStyle = SpanStyle(\n        color = Color.Blue,\n        textDecoration = TextDecoration.Underline\n    ),\n    colorMapping: Map<Color, Color> = emptyMap(),\n): AnnotatedString {\n    return buildAnnotatedString {\n        append(this@toAnnotatedString.toString())\n        val urlSpans = getSpans<URLSpan>()\n        val styleSpans = getSpans<StyleSpan>()\n        val colorSpans = getSpans<ForegroundColorSpan>()\n        val underlineSpans = getSpans<UnderlineSpan>()\n        val strikethroughSpans = getSpans<StrikethroughSpan>()\n        urlSpans.forEach { urlSpan ->\n            val start = getSpanStart(urlSpan)\n            val end = getSpanEnd(urlSpan)\n            addStyle(urlSpanStyle, start, end)\n            addStringAnnotation(\"url\", urlSpan.url, start, end) // NON-NLS\n        }\n        colorSpans.forEach { colorSpan ->\n            val start = getSpanStart(colorSpan)\n            val end = getSpanEnd(colorSpan)\n            addStyle(\n                SpanStyle(color = colorMapping.getOrElse(Color(colorSpan.foregroundColor)) { Color(colorSpan.foregroundColor) }),\n                start,\n                end\n            )\n        }\n        styleSpans.forEach { styleSpan ->\n            val start = getSpanStart(styleSpan)\n            val end = getSpanEnd(styleSpan)\n            when (styleSpan.style) {\n                Typeface.BOLD -> addStyle(SpanStyle(fontWeight = FontWeight.Bold), start, end)\n                Typeface.ITALIC -> addStyle(SpanStyle(fontStyle = FontStyle.Italic), start, end)\n                Typeface.BOLD_ITALIC -> addStyle(\n                    SpanStyle(fontWeight = FontWeight.Bold, fontStyle = FontStyle.Italic),\n                    start,\n                    end\n                )\n            }\n        }\n        underlineSpans.forEach { underlineSpan ->\n            val start = getSpanStart(underlineSpan)\n            val end = getSpanEnd(underlineSpan)\n            addStyle(SpanStyle(textDecoration = TextDecoration.Underline), start, end)\n        }\n        strikethroughSpans.forEach { strikethroughSpan ->\n            val start = getSpanStart(strikethroughSpan)\n            val end = getSpanEnd(strikethroughSpan)\n            addStyle(SpanStyle(textDecoration = TextDecoration.LineThrough), start, end)\n        }\n    }\n}"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/ui/InAppBillingHostActivity.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.vending.billing.ui\n\nimport android.accounts.Account\nimport android.content.Intent\nimport android.content.res.Configuration\nimport android.graphics.Rect\nimport android.os.Bundle\nimport android.util.Log\nimport android.view.Gravity\nimport android.view.MotionEvent\nimport android.view.View\nimport android.view.Window\nimport android.view.WindowManager\nimport androidx.activity.ComponentActivity\nimport androidx.activity.compose.setContent\nimport androidx.activity.viewModels\nimport androidx.annotation.RequiresApi\nimport androidx.core.os.bundleOf\nimport androidx.lifecycle.lifecycleScope\nimport com.android.billingclient.api.BillingClient\nimport org.microg.vending.billing.ui.logic.NotificationEventId\nimport org.microg.vending.billing.ui.logic.InAppBillingViewModel\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.launch\nimport kotlinx.coroutines.withContext\nimport org.microg.vending.billing.ADD_PAYMENT_METHOD_URL\nimport org.microg.vending.billing.TAG\n\nprivate const val ADD_PAYMENT_REQUEST_CODE = 30002\n\n@RequiresApi(21)\nclass InAppBillingHostActivity : ComponentActivity() {\n    private val inAppBillingViewModel by viewModels<InAppBillingViewModel>()\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"InAppBillingHostActivity.onCreate\")\n        requestWindowFeature(Window.FEATURE_NO_TITLE)\n        super.onCreate(savedInstanceState)\n        lifecycleScope.launchWhenCreated {\n            initEventHandler()\n        }\n        loadView(savedInstanceState != null)\n    }\n\n    private fun loadView(isRebuild: Boolean) {\n        if (!isRebuild) {\n            inAppBillingViewModel.startParams = intent.extras\n            lifecycleScope.launch(Dispatchers.IO) {\n                try {\n                    inAppBillingViewModel.loadData(this@InAppBillingHostActivity)\n                } catch (e: Exception) {\n                    if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"loadSheetUIViewData\", e)\n                    withContext(Dispatchers.Main) {\n                        finishWithResult(\n                            bundleOf(\n                                \"RESPONSE_CODE\" to BillingClient.BillingResponseCode.DEVELOPER_ERROR,\n                                \"DEBUG_MESSAGE\" to \"init ui failed\"\n                            )\n                        )\n                    }\n                }\n            }\n        }\n        initWindow()\n        setContent { BillingUiPage(viewModel = inAppBillingViewModel) }\n    }\n\n    private suspend fun initEventHandler() {\n        inAppBillingViewModel.event.collect {\n            when (it.id) {\n                NotificationEventId.FINISH -> finishWithResult(it.params)\n                NotificationEventId.OPEN_PAYMENT_METHOD_ACTIVITY -> {\n                    val account = it.params.getParcelable<Account>(\"account\")\n                    val src = it.params.getString(\"src\")\n                    openPaymentMethodActivity(src, account)\n                }\n            }\n        }\n    }\n\n    private fun initWindow() {\n        val lp = window.attributes\n        lp.width = getWindowWidth(this)\n        lp.height = WindowManager.LayoutParams.WRAP_CONTENT\n        lp.gravity = Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL\n        window.attributes = lp\n        window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)\n        if (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE)\n            window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_FULLSCREEN\n    }\n\n    private fun openPaymentMethodActivity(src: String?, account: Account?) {\n        val intent = Intent(this, PlayWebViewActivity::class.java)\n        intent.putExtra(KEY_WEB_VIEW_ACTION, WebViewAction.ADD_PAYMENT_METHOD.toString())\n        intent.putExtra(KEY_WEB_VIEW_OPEN_URL, ADD_PAYMENT_METHOD_URL)\n        account?.let {\n            intent.putExtra(KEY_WEB_VIEW_ACCOUNT, account)\n        }\n        startActivityForResult(intent, ADD_PAYMENT_REQUEST_CODE)\n    }\n\n    override fun onTouchEvent(event: MotionEvent?): Boolean {\n        return when (event?.action) {\n            MotionEvent.ACTION_UP -> {\n                val r = Rect(0, 0, 0, 0)\n                this.window.decorView.getHitRect(r)\n                val intersects: Boolean = r.contains(event.x.toInt(), event.y.toInt())\n                if (!intersects) {\n                    inAppBillingViewModel.close()\n                    return true\n                }\n                super.onTouchEvent(event)\n            }\n\n            else -> super.onTouchEvent(event)\n        }\n    }\n\n    private fun finishWithResult(result: Bundle) {\n        if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"InAppBillingHostActivity.finishWithResult $result\")\n        val resultIntent = Intent()\n        resultIntent.putExtras(result)\n        setResult(RESULT_OK, resultIntent)\n        finish()\n    }\n\n    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {\n        when (requestCode) {\n            ADD_PAYMENT_REQUEST_CODE -> {\n                if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"add payment method resultCode: $resultCode, data: $data\")\n                loadView(false)\n            }\n\n            else -> {\n                super.onActivityResult(requestCode, resultCode, data)\n                finishWithResult(\n                    bundleOf(\n                        \"RESPONSE_CODE\" to BillingClient.BillingResponseCode.USER_CANCELED\n                    )\n                )\n            }\n        }\n    }\n}"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/ui/PlayWebViewActivity.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.vending.billing.ui\n\nimport android.accounts.Account\nimport android.os.Bundle\nimport android.util.Log\nimport android.view.View\nimport android.view.Window\nimport android.webkit.WebView\nimport android.widget.ProgressBar\nimport android.widget.RelativeLayout\nimport androidx.activity.ComponentActivity\nimport org.microg.vending.billing.TAG\n\nprivate val ALLOWED_WEB_PREFIXES = setOf(\n    \"https://play.google.com/accounts\",\n    \"https://play.google.com/store/paymentmethods\",\n    \"https://play.google.com/store/paymentmethods\",\n    \"https://pay.google.com/payments\",\n    \"https://payments.google.com/payments\",\n)\n\nenum class WebViewAction {\n    ADD_PAYMENT_METHOD,\n    OPEN_GP_PRODUCT_DETAIL,\n    UNKNOWN\n}\n\nconst val KEY_WEB_VIEW_ACTION = \"key_web_view_action\"\nconst val KEY_WEB_VIEW_OPEN_URL = \"key_web_view_open_url\"\nconst val KEY_WEB_VIEW_ACCOUNT = \"key_web_view_account\"\n\nclass PlayWebViewActivity : ComponentActivity() {\n    private lateinit var webView: WebView\n    private lateinit var openUrl: String\n    private lateinit var action: WebViewAction\n    private var account: Account? = null\n\n    private fun parseParams(): Boolean {\n        val actionStr = intent.getStringExtra(KEY_WEB_VIEW_ACTION) ?: return false\n        this.action = try {\n            WebViewAction.valueOf(actionStr)\n        } catch (e: Exception) {\n            if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"\", e)\n            return false\n        }\n        if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"PlayWebView action:$action\")\n        this.openUrl = intent.getStringExtra(KEY_WEB_VIEW_OPEN_URL) ?: return false\n        if (openUrl.isBlank())\n            return false\n        this.account = intent.getParcelableExtra(KEY_WEB_VIEW_ACCOUNT)\n        return true\n    }\n\n    private fun doAction() {\n        when (action) {\n            WebViewAction.OPEN_GP_PRODUCT_DETAIL,WebViewAction.ADD_PAYMENT_METHOD -> createWebView()\n            else -> {\n                if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"PlayWebView unknown action:$action\")\n                finish()\n            }\n        }\n    }\n\n    private fun createWebView() {\n        val layout = RelativeLayout(this)\n        layout.addView(ProgressBar(this).apply {\n            layoutParams = RelativeLayout.LayoutParams(\n                RelativeLayout.LayoutParams.WRAP_CONTENT,\n                RelativeLayout.LayoutParams.WRAP_CONTENT\n            ).apply {\n                addRule(RelativeLayout.CENTER_HORIZONTAL)\n                addRule(RelativeLayout.CENTER_VERTICAL)\n            }\n            isIndeterminate = true\n        })\n        webView = WebView(this).apply {\n            layoutParams = RelativeLayout.LayoutParams(\n                RelativeLayout.LayoutParams.MATCH_PARENT,\n                RelativeLayout.LayoutParams.MATCH_PARENT\n            )\n            visibility = View.INVISIBLE\n        }\n        layout.addView(webView)\n        setContentView(layout)\n        WebViewHelper(this, webView, ALLOWED_WEB_PREFIXES).openWebView(openUrl, account, action)\n        setResult(RESULT_OK)\n    }\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        requestWindowFeature(Window.FEATURE_NO_TITLE)\n        val extras = intent?.extras?.also { it.keySet() }\n        if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"Invoked with ${intent.action} and extras $extras\")\n        super.onCreate(savedInstanceState)\n        if (!parseParams()) {\n            finish()\n            return\n        }\n        doAction()\n    }\n}"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/ui/SheetUIPage.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.vending.billing.ui\n\nimport android.util.Log\nimport androidx.activity.compose.BackHandler\nimport androidx.annotation.DrawableRes\nimport androidx.annotation.RequiresApi\nimport androidx.compose.animation.graphics.ExperimentalAnimationGraphicsApi\nimport androidx.compose.animation.graphics.res.animatedVectorResource\nimport androidx.compose.animation.graphics.res.rememberAnimatedVectorPainter\nimport androidx.compose.animation.graphics.vector.AnimatedImageVector\nimport androidx.compose.foundation.*\nimport androidx.compose.foundation.layout.*\nimport androidx.compose.foundation.shape.RoundedCornerShape\nimport androidx.compose.material.icons.Icons\nimport androidx.compose.material.icons.filled.ArrowBack\nimport androidx.compose.material.icons.filled.CheckCircle\nimport androidx.compose.material.icons.filled.KeyboardArrowRight\nimport androidx.compose.material.icons.outlined.Info\nimport androidx.compose.material3.*\nimport androidx.compose.runtime.*\nimport androidx.compose.ui.Alignment\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.graphics.Color\nimport androidx.compose.ui.graphics.ColorFilter\nimport androidx.compose.ui.layout.ContentScale\nimport androidx.compose.ui.res.painterResource\nimport androidx.compose.ui.unit.DpSize\nimport androidx.compose.ui.unit.dp\nimport coil.compose.AsyncImage\nimport com.android.vending.R\nimport com.google.accompanist.systemuicontroller.rememberSystemUiController\nimport org.microg.vending.billing.TAG\nimport org.microg.vending.billing.core.ui.*\nimport org.microg.vending.billing.ui.logic.BillingUiViewState\nimport org.microg.vending.billing.ui.logic.InAppBillingViewModel\nimport org.microg.vending.billing.ui.theme.InAppBillingTheme\nimport org.microg.vending.billing.ui.widgets.LoadingDialog\nimport org.microg.vending.billing.ui.widgets.PasswdInputDialog\n\nval LocalBillingUiViewState =\n    compositionLocalOf<BillingUiViewState> { error(\"No default value provided.\") }\n\n@Composable\nfun SetStatusBarColor(color: Color) {\n    val systemUiController = rememberSystemUiController()\n    SideEffect {\n        systemUiController.setSystemBarsColor(color)\n    }\n}\n\n@RequiresApi(21)\n@Composable\nfun BillingUiPage(viewModel: InAppBillingViewModel) {\n    InAppBillingTheme {\n        SetStatusBarColor(MaterialTheme.colorScheme.background)\n        CompositionLocalProvider(LocalBillingUiViewState provides viewModel.billingUiViewState) {\n            BillingUiView(viewModel.billingUiViewState)\n        }\n        LoadingDialog(viewModel.loadingDialogVisible)\n        PasswdInputDialog(viewModel.passwdInputViewState)\n    }\n}\n\n@Composable\nprivate fun BillingUiView(viewState: BillingUiViewState) {\n    if (!viewState.visible)\n        return\n    BackHandler(true) {\n        if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"OnBackPressed\")\n    }\n    Surface(\n        modifier = Modifier\n            .wrapContentHeight()\n            .wrapContentWidth(),\n        color = MaterialTheme.colorScheme.background\n    ) {\n        Column(\n            modifier = Modifier\n        ) {\n            UIComponents(viewState)\n        }\n    }\n}\n\n@Composable\nprivate fun UIComponents(viewState: BillingUiViewState) {\n    val uiComponents = viewState.showScreen.uiComponents ?: return\n    val headerComponents = uiComponents.headerComponents\n    val contentComponents = uiComponents.contentComponents\n    val footerComponents = uiComponents.footerComponents\n    val action = viewState.showScreen.action\n    if (headerComponents.isNotEmpty()) {\n        Column(\n            modifier = Modifier\n                .wrapContentHeight(Alignment.CenterVertically)\n                .wrapContentWidth()\n        ) {\n            for (component in headerComponents) {\n                if (component.uiInfo?.uiType == UIType.BILLING_PROFILE_MORE_OPTION_BUTTON_SHOW_HIDEABLE_INSTRUMENT)\n                    continue\n                UIComponent(Modifier, component, viewState)\n            }\n        }\n    }\n    if (contentComponents.isNotEmpty() || footerComponents.isNotEmpty()) {\n        Column(\n            modifier = Modifier\n                .applyUITypePadding(viewState.showScreen.uiInfo?.uiType)\n                .wrapContentHeight(Alignment.CenterVertically)\n                .wrapContentWidth()\n                .verticalScroll(rememberScrollState())\n        ) {\n            for (component in contentComponents) {\n                UIComponent(\n                    Modifier,\n                    component,\n                    viewState\n                )\n            }\n            if (viewState.showScreen.uiInfo?.uiType == UIType.PURCHASE_ERROR_SCREEN) {\n                Box(\n                    modifier = Modifier\n                        .padding(top = 40.dp)\n                )\n            }\n\n            for (component in footerComponents) {\n                UIComponent(Modifier, component, viewState)\n            }\n        }\n    }\n\n    Box(modifier = Modifier.padding(top = 15.dp))\n    if (action?.type == ActionType.DELAY && action.delay != null) {\n        viewState.onClickAction(action)\n    }\n}\n\n@Composable\nprivate fun UIComponent(\n    modifier: Modifier = Modifier,\n    component: BComponent,\n    viewState: BillingUiViewState\n) {\n    Column(\n        modifier = modifier\n            .fillMaxWidth()\n            .applyViewInfo(\n                component.viewInfo\n            )\n            .wrapContentHeight(align = Alignment.CenterVertically),\n    ) {\n        when (val type = component.viewType) {\n            ViewType.ICONTEXTCOMBINATIONVIEW -> IconTextCombinationView(\n                modifier = applyAlignment(Modifier, component.viewInfo),\n                component.iconTextCombinationView!!\n            )\n\n            ViewType.CLICKABLETEXTVIEW -> ClickableTextView(\n                modifier = applyAlignment(Modifier, component.viewInfo),\n                component.clickableTextView!!\n            )\n\n            ViewType.VIEWGROUP -> ViewGroup(\n                modifier = applyAlignment(Modifier, component.viewInfo),\n                component.viewGroup!!\n            )\n\n            ViewType.DIVIDERVIEW -> DividerView(\n                modifier = applyAlignment(Modifier, component.viewInfo)\n            )\n\n            ViewType.MODULOIMAGEVIEW -> ModuloImageView(\n                modifier = applyAlignment(Modifier, component.viewInfo),\n                component.moduloImageView!!\n            )\n\n            ViewType.BUTTONGROUPVIEW -> ButtonGroupView(\n                modifier = applyAlignment(Modifier, component.viewInfo),\n                viewState,\n                component.buttonGroupView!!\n            )\n\n            ViewType.INSTRUMENTITEMVIEW -> InstrumentItemView(\n                modifier = applyAlignment(Modifier, component.viewInfo),\n                viewState,\n                component.instrumentItemView!!\n            )\n\n            else -> Log.d(TAG, \"invalid component type $type\")\n        }\n    }\n}\n\n@Composable\nprivate fun PlayTextView(\n    modifier: Modifier = Modifier,\n    data: BPlayTextView\n) {\n    val textColor = getColorByType(data.textInfo?.colorType)\n        ?: LocalContentColor.current\n    var textValue = \"\"\n    if (data.textSpan.isNotEmpty()) {\n        data.textSpan.forEach {\n            when (it.textSpanType) {\n                TextSpanType.BULLETSPAN -> textValue += \"\\u2022 \"\n                else -> {\n                    if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"Unknown TextSpan type\")\n                }\n            }\n        }\n    }\n    val fontSize = getFontSizeByType(data.textInfo?.styleType)\n    textValue += data.text\n    HtmlText(\n        text = textValue,\n        color = textColor,\n        fontSize = fontSize,\n        textAlign = getTextAlignment(data.textInfo),\n        maxLines = data.textInfo?.maxLines ?: Int.MAX_VALUE,\n        modifier = modifier.applyViewInfo(data.viewInfo),\n        lineHeight = fontSize.times(1.1)\n    )\n}\n\n@Composable\nprivate fun IconTextCombinationView(\n    modifier: Modifier = Modifier,\n    data: BIconTextCombinationView\n) {\n    Column(\n        modifier = modifier\n            .wrapContentHeight()\n            .wrapContentWidth()\n    ) {\n        //角标\n        data.badgeTextView?.let {\n            PlayTextView(\n                modifier = applyAlignment(Modifier, it.viewInfo),\n                data = it\n            )\n        }\n        Row(\n            modifier = Modifier\n                .wrapContentHeight()\n                .wrapContentWidth(),\n            verticalAlignment = Alignment.CenterVertically\n        ) {\n            data.headerImageView?.let {\n                ImageView(\n                    data = it,\n                    modifier = applyAlignment(Modifier, it.viewInfo),\n                )\n            }\n            data.playTextView?.let {\n                PlayTextView(modifier = applyAlignment(Modifier, it.viewInfo), data = it)\n            }\n            if (data.middleTextViewList == null)\n                return\n            Column(\n                modifier = applyAlignment(Modifier, data.viewInfo)\n                    .applyViewInfo(data.viewInfo)\n                    .wrapContentHeight()\n                    .wrapContentWidth()\n            ) {\n                for (singleLineTextView in data.middleTextViewList) {\n                    Row(\n                        modifier = Modifier\n                            .wrapContentWidth()\n                            .wrapContentHeight()\n                    ) {\n                        singleLineTextView.playTextView1?.let {\n                            PlayTextView(\n                                applyAlignment(\n                                    Modifier,\n                                    it.viewInfo\n                                ).wrapContentWidth(align = Alignment.CenterHorizontally),\n                                data = it\n                            )\n                        }\n                        singleLineTextView.playTextView2?.let {\n                            PlayTextView(\n                                applyAlignment(\n                                    Modifier,\n                                    it.viewInfo\n                                ).fillMaxWidth(),\n                                data = it\n                            )\n                        }\n                    }\n                }\n            }\n            if (data.footerImageGroup?.imageViews?.isNotEmpty() == true) {\n                val viewInfo = data.footerImageGroup.viewInfo\n                val imageViews = data.footerImageGroup.imageViews\n                Spacer(\n                    modifier = Modifier\n                        .weight(1f)\n                        .fillMaxHeight()\n                )\n                Column(\n                    modifier = applyAlignment(Modifier, viewInfo)\n                        .applyViewInfo(viewInfo)\n                        .wrapContentHeight()\n                        .wrapContentWidth()\n                ) {\n                    imageViews.forEach {\n                        ImageView(\n                            data = it,\n                            modifier = applyAlignment(Modifier, it.viewInfo),\n                        )\n                    }\n                }\n            }\n        }\n    }\n}\n\n@Composable\nprivate fun ClickableTextView(\n    modifier: Modifier = Modifier,\n    data: BClickableTextView\n) {\n    val playTextView = data.playTextView ?: return\n    if (playTextView.text.isEmpty())\n        return\n    PlayTextView(modifier, data = playTextView)\n}\n\n@Composable\nprivate fun InstrumentItemView(\n    modifier: Modifier = Modifier,\n    viewState: BillingUiViewState,\n    data: BInstrumentItemView\n) {\n    var newModify = modifier\n        .wrapContentHeight()\n        .fillMaxWidth()\n    newModify = when (data.action?.uiInfo?.uiType) {\n        UIType.BILLING_PROFILE_EXISTING_INSTRUMENT,\n        UIType.BILLING_PROFILE_OPTION_ADD_PLAY_CREDIT,\n        UIType.BILLING_PROFILE_OPTION_REDEEM_CODE,\n        UIType.BILLING_PROFILE_OPTION_CREATE_INSTRUMENT -> {\n            newModify.clickable {\n                viewState.onClickAction(data.action)\n            }\n        }\n\n        else -> newModify\n    }\n\n    Row(\n        modifier = newModify\n    ) {\n        data.icon?.let {\n            ImageView(\n                data = it,\n                modifier = applyAlignment(Modifier, it.viewInfo)\n                    .align(Alignment.CenterVertically),\n                size = DpSize(32.dp, 32.dp)\n            )\n        }\n        if (data.text != null || data.tips != null) {\n            Column(\n                modifier = Modifier\n                    .align(Alignment.CenterVertically)\n                    .wrapContentSize(),\n                horizontalAlignment = Alignment.Start,\n                verticalArrangement = Arrangement.Center\n            ) {\n                data.text?.let {\n                    PlayTextView(\n                        applyAlignment(\n                            Modifier,\n                            it.viewInfo\n                        ).wrapContentSize(),\n                        data = it\n                    )\n                }\n                data.tips?.let {\n                    PlayTextView(\n                        applyAlignment(\n                            Modifier,\n                            it.viewInfo\n                        ).wrapContentSize(),\n                        data = it\n                    )\n                }\n                data.extraInfo?.let {\n                    PlayTextView(\n                        applyAlignment(\n                            Modifier,\n                            it.viewInfo\n                        ).wrapContentSize(),\n                        data = it\n                    )\n                }\n            }\n        }\n        data.state?.let {\n            Spacer(\n                modifier = Modifier\n                    .weight(1f)\n                    .fillMaxHeight()\n                    .background(Color.Red)\n            )\n            ImageView(\n                data = it,\n                modifier = applyAlignment(Modifier, it.viewInfo)\n                    .align(Alignment.CenterVertically),\n                size = DpSize(32.dp, 32.dp)\n            )\n        }\n    }\n}\n\n@Composable\nprivate fun ButtonGroupView(\n    modifier: Modifier = Modifier,\n    viewState: BillingUiViewState,\n    data: BButtonGroupView\n) {\n    if (data.buttonViewList.isNullOrEmpty())\n        return\n    Row(\n        modifier = modifier\n            .wrapContentHeight(align = Alignment.CenterVertically)\n            .fillMaxWidth(),\n        horizontalArrangement = Arrangement.SpaceBetween\n    ) {\n        data.buttonViewList.forEach {\n            Button(\n                onClick = { viewState.onClickAction(it.action) },\n                shape = RoundedCornerShape(10),\n                modifier = modifier\n                    .weight(1f)\n                    .defaultMinSize(minWidth = 1.dp, minHeight = 1.dp),\n                contentPadding = PaddingValues(7.dp)\n            ) {\n                Text(\n                    text = it.text\n                )\n            }\n        }\n    }\n}\n\n@Composable\nprivate fun ImageView(\n    modifier: Modifier = Modifier,\n    data: BImageView,\n    size: DpSize? = null,\n) {\n    ((if (isSystemInDarkTheme()) data.darkUrl else data.lightUrl) ?: data.darkUrl\n    ?: data.lightUrl)?.let {\n        AsyncImage(\n            modifier = modifier\n                .applyViewInfo(data.viewInfo)\n                .applySize(size),\n            model = it,\n            contentDescription = data.viewInfo?.contentDescription,\n            colorFilter = getColorFilter(data.imageInfo),\n            contentScale = getContentScale(data.imageInfo) ?: ContentScale.Fit\n        )\n    }\n    data.animation?.let {\n        if (it.type == AnimationType.CHECK_MARK.value) {\n            AnimatedVector(\n                modifier = modifier\n                    .applyViewInfo(data.viewInfo)\n                    .applySize(size),\n                R.drawable.anim_check_mark\n            )\n        }\n    }\n    data.iconView?.let {\n        when (it.type) {\n            1 -> Icon(\n                Icons.Filled.CheckCircle,\n                modifier = modifier\n                    .applyViewInfo(data.viewInfo)\n                    .size(24.dp),\n                contentDescription = data.viewInfo?.contentDescription\n            )\n\n            3 -> Icon(\n                Icons.Filled.KeyboardArrowRight,\n                modifier = modifier\n                    .applyViewInfo(data.viewInfo)\n                    .size(24.dp),\n                contentDescription = data.viewInfo?.contentDescription\n            )\n\n            21 -> Icon(\n                Icons.Filled.ArrowBack,\n                modifier = modifier\n                    .applyViewInfo(data.viewInfo)\n                    .size(48.dp),\n                contentDescription = data.viewInfo?.contentDescription\n            )\n\n            27 -> Icon(\n                Icons.Outlined.Info,\n                modifier = modifier\n                    .applyViewInfo(data.viewInfo)\n                    .size(11.dp),\n                contentDescription = data.viewInfo?.contentDescription\n            )\n\n            99 -> Image(\n                painter = painterResource(R.drawable.google_play),\n                modifier = modifier\n                    .applyViewInfo(data.viewInfo)\n                    .applySize(size),\n                contentDescription = data.viewInfo?.contentDescription,\n                colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onBackground)\n            )\n        }\n    }\n}\n\n@Composable\nprivate fun ModuloImageView(\n    modifier: Modifier = Modifier,\n    data: BModuloImageView\n) {\n    data.imageView?.let {\n        ImageView(modifier = modifier, data = it)\n    }\n}\n\n@Composable\nprivate fun ViewGroup(\n    modifier: Modifier = Modifier,\n    data: BViewGroup\n) {\n    Row(\n        modifier = modifier\n            .wrapContentHeight()\n            .wrapContentHeight()\n    ) {\n        data.imageView2?.let {\n            ImageView(modifier = applyAlignment(Modifier, it.viewInfo), data = it)\n        }\n        data.playTextView?.let {\n            PlayTextView(modifier = applyAlignment(Modifier, it.viewInfo), data = it)\n        }\n        data.imageView3?.let {\n            Spacer(modifier = Modifier.weight(1f))\n            ImageView(modifier = applyAlignment(Modifier, it.viewInfo), data = it)\n        }\n    }\n}\n\n@Composable\nprivate fun DividerView(\n    modifier: Modifier = Modifier\n) {\n    Divider(\n        modifier = modifier\n    )\n}\n\n@OptIn(ExperimentalAnimationGraphicsApi::class)\n@Composable\nprivate fun AnimatedVector(modifier: Modifier = Modifier, @DrawableRes drawableId: Int) {\n    val image = AnimatedImageVector.animatedVectorResource(drawableId)\n    var atEnd by remember { mutableStateOf(false) }\n    Image(\n        painter = rememberAnimatedVectorPainter(image, atEnd),\n        contentDescription = \"\",\n        modifier = modifier\n    )\n    atEnd = true\n}"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/ui/Utils.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.vending.billing.ui\n\nimport android.content.Context\nimport android.content.res.Configuration\nimport android.util.Log\nimport androidx.compose.foundation.isSystemInDarkTheme\nimport androidx.compose.material3.MaterialTheme\nimport androidx.compose.runtime.Composable\nimport androidx.compose.ui.graphics.Color\nimport androidx.compose.ui.graphics.ColorFilter\nimport androidx.compose.ui.layout.ContentScale\nimport androidx.compose.ui.text.style.TextAlign\nimport androidx.compose.ui.unit.TextUnit\nimport androidx.compose.ui.unit.sp\nimport org.microg.vending.billing.TAG\nimport org.microg.vending.billing.core.ui.BGravity\nimport org.microg.vending.billing.core.ui.BImageInfo\nimport org.microg.vending.billing.core.ui.BTextInfo\nimport org.microg.vending.billing.core.ui.ColorType\nimport org.microg.vending.billing.core.ui.TextAlignmentType\n\nfun getWindowWidth(context: Context): Int {\n    val resources = context.resources\n    return when (resources.configuration.orientation) {\n        Configuration.ORIENTATION_PORTRAIT -> resources.displayMetrics.widthPixels\n        Configuration.ORIENTATION_LANDSCAPE -> (resources.displayMetrics.widthPixels * 0.6).toInt()\n        else -> resources.displayMetrics.widthPixels\n    }\n}\n\n@Composable\nfun DayNightColor(day: Long, night: Long): Color = if (isSystemInDarkTheme()) Color(night) else Color(day)\n\n// TODO: Manage colors in theme\n@Composable\nfun getColorByType(t: ColorType?): Color? {\n    if (t == null)\n        return null\n    return when (t) {\n        ColorType.BACKGROUND_PRIMARY -> MaterialTheme.colorScheme.background\n        ColorType.APPS_PRIMARY -> MaterialTheme.colorScheme.primary\n        ColorType.APPS_2 -> DayNightColor(0xff5f6368, 0xffcae2ff)\n        ColorType.APPS_3 -> DayNightColor(0xff5f6368, 0xff003b92)\n        ColorType.MUSIC_3 -> Color.Transparent\n        ColorType.TEXT_PRIMARY -> DayNightColor(0xff202124, 0xffe8eaed)\n        ColorType.TEXT_SECONDARY -> DayNightColor(0xff5f6368, 0xff9aa0a6)\n        ColorType.PRIMARY_BUTTON_LABEL_DISABLED -> DayNightColor(0xff5f6368, 0xff5b5e64)\n        ColorType.ERROR_COLOR_PRIMARY -> MaterialTheme.colorScheme.error\n        else -> {\n            if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"invalid color type $t\")\n            Color.Transparent\n        }\n    }\n}\n\n@Composable\nfun getColorFilter(imageInfo: BImageInfo?): ColorFilter? {\n    if (imageInfo?.colorFilterValue != null)\n        return ColorFilter.tint(Color(imageInfo.colorFilterValue))\n    if (imageInfo?.colorFilterType != null) {\n        return when (imageInfo.colorFilterType) {\n            21, 3 -> ColorFilter.tint(\n                if (isSystemInDarkTheme()) Color(0xffe8eaed) else Color(\n                    0xff202124\n                )\n            )\n\n            else -> {\n                if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"Unknown color filter type: ${imageInfo.colorFilterType}\")\n                null\n            }\n        }\n    }\n    return null\n}\n\nfun getContentScale(imageInfo: BImageInfo?): ContentScale? {\n    return null\n}\n\nfun getFontSizeByType(t: Int?): TextUnit {\n    return when (t) {\n        10 -> 18.sp\n        12 -> 16.sp\n        14 -> 14.sp\n        20 -> 14.sp\n        21 -> 12.sp\n        null -> 14.sp\n        else -> {\n            if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"invalid font type $t\")\n            14.sp\n        }\n    }\n}\n\nfun getTextAlignment(textInfo: BTextInfo?): TextAlign {\n    val gravitys = textInfo?.gravityList\n    if (gravitys?.containsAll(listOf(BGravity.LEFT, BGravity.START)) == true)\n        return TextAlign.Left\n    if (gravitys?.containsAll(listOf(BGravity.CENTER, BGravity.CENTER_HORIZONTAL)) == true)\n        return TextAlign.Center\n    if (gravitys?.containsAll(listOf(BGravity.RIGHT, BGravity.END)) == true)\n        return TextAlign.Right\n    return when (val t = textInfo?.textAlignmentType) {\n        TextAlignmentType.TEXT_ALIGNMENT_TEXT_END -> TextAlign.Right\n        TextAlignmentType.TEXT_ALIGNMENT_TEXT_START -> TextAlign.Left\n        TextAlignmentType.TEXT_ALIGNMENT_CENTER -> TextAlign.Center\n        TextAlignmentType.TEXT_ALIGNMENT_VIEW_END -> TextAlign.Right\n        null -> TextAlign.Left\n        else -> {\n            if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"invalid text alignment type $t\")\n            TextAlign.Left\n        }\n    }\n}"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/ui/WebViewHelper.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.vending.billing.ui\n\nimport android.accounts.Account\nimport android.accounts.AccountManager\nimport android.graphics.Bitmap\nimport android.net.Uri\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.Message\nimport android.util.Log\nimport android.view.View\nimport android.webkit.CookieManager\nimport android.webkit.WebChromeClient\nimport android.webkit.WebResourceRequest\nimport android.webkit.WebSettings\nimport android.webkit.WebView\nimport android.widget.ProgressBar\nimport android.widget.RelativeLayout\nimport androidx.activity.ComponentActivity\nimport androidx.lifecycle.lifecycleScope\nimport androidx.webkit.WebResourceErrorCompat\nimport androidx.webkit.WebViewClientCompat\nimport com.google.android.material.bottomsheet.BottomSheetDialog\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.launch\nimport org.microg.gms.profile.Build\nimport org.microg.vending.billing.TAG\nimport java.net.URLEncoder\nimport java.util.Locale\nimport java.util.concurrent.TimeUnit\n\nclass WebViewHelper(\n    private val activity: ComponentActivity,\n    private val webView: WebView,\n    private val allowedPrefixes: Set<String> = emptySet()\n) {\n    fun openWebView(url: String, account: Account?, webAction: WebViewAction) {\n        prepareWebViewSettings(webView.settings, webAction == WebViewAction.ADD_PAYMENT_METHOD)\n        webView.webChromeClient = PayWebChromeClient(webAction)\n        webView.webViewClient = object : WebViewClientCompat() {\n            override fun onReceivedError(view: WebView, request: WebResourceRequest, error: WebResourceErrorCompat) {\n                Log.e(TAG, \"Error loading: $error\")\n            }\n\n            override fun onPageFinished(view: WebView?, url: String?) {\n                super.onPageFinished(view, url)\n                if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"onPageFinished $url\")\n                webView.visibility = View.VISIBLE\n            }\n\n            override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {\n                if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"Navigating to $url\")\n                // TODO: figure out to not embed page of third parties, but allow bank confirmations\n//                if (allowedPrefixes.isNotEmpty() && allowedPrefixes.none { url.startsWith(it) }) {\n//                    try {\n//                        activity.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url)).apply { addCategory(Intent.CATEGORY_BROWSABLE) })\n//                    } catch (e: Exception) {\n//                        Log.d(TAG, \"Error forwarding to browser\", e)\n//                    }\n//                    return true\n//                }\n                return false\n            }\n        }\n\n        val urlWithLanguage: String = addLanguageParam(url)\n        if (account != null) {\n            activity.lifecycleScope.launch(Dispatchers.IO) {\n                openWebWithAccount(account, urlWithLanguage)\n            }\n        } else {\n            loadWebViewUrl(urlWithLanguage)\n        }\n    }\n\n    private fun loadWebViewUrl(url: String) {\n        webView.loadUrl(url)\n    }\n\n    private fun addLanguageParam(url: String): String {\n        val language = Locale.getDefault().language\n        return if (language.isNotEmpty()) {\n            Uri.parse(url).buildUpon().appendQueryParameter(\"hl\", language).toString()\n        } else {\n            url\n        }\n    }\n\n    private fun openWebWithAccount(account: Account, url: String) {\n        try {\n            val service = \"weblogin:continue=\" + URLEncoder.encode(url, \"utf-8\")\n            val accountManager: AccountManager = AccountManager.get(activity)\n            val future = accountManager.getAuthToken(account, service, null, null, null, null)\n            val bundle = future.getResult(20, TimeUnit.SECONDS)\n            val authUrl = bundle.getString(AccountManager.KEY_AUTHTOKEN)\n                ?: throw RuntimeException(\"authUrl is null\")\n            if (authUrl.contains(\"WILL_NOT_SIGN_IN\")) {\n                throw RuntimeException(\"Would not sign in\")\n            }\n            if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"Opening $authUrl\")\n            webView.post {\n                if (SDK_INT >= 21) {\n                    CookieManager.getInstance().removeAllCookies {\n                        if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"Cookies removed\")\n                        loadWebViewUrl(authUrl)\n                    }\n                } else {\n                    CookieManager.getInstance().removeAllCookie()\n                    loadWebViewUrl(authUrl)\n                }\n\n            }\n        } catch (e: Exception) {\n            if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"Failed to get weblogin auth.\", e)\n            activity.finish()\n        }\n    }\n\n    private fun prepareWebViewSettings(settings: WebSettings, enableMultiWindow: Boolean = false) {\n        settings.javaScriptEnabled = true\n        settings.setSupportMultipleWindows(enableMultiWindow)\n        settings.allowFileAccess = false\n        settings.databaseEnabled = false\n        settings.setNeedInitialFocus(false)\n        settings.useWideViewPort = false\n        settings.setSupportZoom(false)\n        settings.javaScriptCanOpenWindowsAutomatically = false\n        settings.userAgentString = Build.generateWebViewUserAgentString(settings.userAgentString)\n    }\n\n    private class PayWebChromeClient(val webAction: WebViewAction) : WebChromeClient() {\n\n        override fun onCreateWindow(view: WebView?, isDialog: Boolean, isUserGesture: Boolean, resultMsg: Message?): Boolean {\n            Log.d(TAG, \"onCreateWindow: isDialog:$isDialog isUserGesture:$isUserGesture resultMsg: ${resultMsg.toString()}\")\n            if (webAction != WebViewAction.ADD_PAYMENT_METHOD) {\n                return super.onCreateWindow(view, isDialog, isUserGesture, resultMsg)\n            }\n            // Add third-party payment methods, such as PayPal/GrabPay/Alipay.\n            // WebView needs to support multi-window mode, and the child view will call the js method registered by the parent view\n            // to refresh the page and close it by itself.\n            var bottomSheetDialog: BottomSheetDialog? = null\n            val parentContext = view!!.context\n            val subWebView = WebView(parentContext).apply {\n                settings.apply {\n                    javaScriptEnabled = true\n                    domStorageEnabled = true\n                }\n                webViewClient = object : WebViewClientCompat() {\n                    override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {\n                        super.onPageStarted(view, url, favicon)\n                        Log.d(TAG, \"sub_window starts loading: $url\")\n                    }\n\n                    override fun onPageFinished(view: WebView?, url: String?) {\n                        super.onPageFinished(view, url)\n                        Log.d(TAG, \"sub_window loaded : $url\")\n                        visibility = View.VISIBLE\n                    }\n                }\n                webChromeClient = object : WebChromeClient() {\n                    override fun onCloseWindow(window: WebView?) {\n                        Log.d(TAG, \"sub_window closed\")\n                        bottomSheetDialog?.dismiss()\n                    }\n                }\n                layoutParams = RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT)\n                visibility = View.INVISIBLE\n            }\n            bottomSheetDialog = BottomSheetDialog(parentContext).apply {\n                setOnDismissListener { subWebView.destroy() }\n            }\n            val layout = RelativeLayout(parentContext)\n            layout.addView(ProgressBar(parentContext).apply {\n                layoutParams = RelativeLayout.LayoutParams(\n                    RelativeLayout.LayoutParams.WRAP_CONTENT,\n                    RelativeLayout.LayoutParams.WRAP_CONTENT\n                ).apply {\n                    addRule(RelativeLayout.CENTER_HORIZONTAL)\n                    addRule(RelativeLayout.CENTER_VERTICAL)\n                }\n                isIndeterminate = true\n            })\n            bottomSheetDialog.setContentView(layout.apply { addView(subWebView) })\n            bottomSheetDialog.show()\n\n            (resultMsg?.obj as? WebView.WebViewTransport)?.webView = subWebView\n            resultMsg?.sendToTarget()\n            return true\n        }\n    }\n}"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/ui/logic/InAppBillingViewModel.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.vending.billing.ui.logic\n\nimport android.content.Context\nimport android.os.Bundle\nimport android.util.Log\nimport androidx.annotation.RequiresApi\nimport androidx.compose.runtime.getValue\nimport androidx.compose.runtime.mutableStateOf\nimport androidx.compose.runtime.setValue\nimport androidx.core.os.bundleOf\nimport androidx.lifecycle.ViewModel\nimport androidx.lifecycle.viewModelScope\nimport com.android.billingclient.api.BillingClient\nimport io.ktor.utils.io.errors.IOException\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.channels.Channel\nimport kotlinx.coroutines.delay\nimport kotlinx.coroutines.flow.receiveAsFlow\nimport kotlinx.coroutines.launch\nimport org.microg.gms.utils.toHexString\nimport org.microg.vending.billing.*\nimport org.microg.vending.billing.core.ui.ActionType\nimport org.microg.vending.billing.core.ui.BAction\nimport org.microg.vending.billing.core.ui.UIType\n\nenum class NotificationEventId {\n    FINISH,\n    OPEN_PAYMENT_METHOD_ACTIVITY\n}\n\nenum class ErrorMessageRef {\n    PASSWORD_ERROR,\n    NETWORK_ERROR,\n}\n\ndata class NotificationEvent(\n    val id: NotificationEventId,\n    val params: Bundle\n)\n\n@RequiresApi(21)\nclass InAppBillingViewModel : ViewModel() {\n    private val _event = Channel<NotificationEvent>()\n    val event = _event.receiveAsFlow()\n    var startParams: Bundle? = null\n\n    var loadingDialogVisible by mutableStateOf(value = false)\n        private set\n    var billingUiViewState by mutableStateOf(\n        value = BillingUiViewState(\n            onClickAction = ::handleClickAction\n        )\n    )\n        private set\n    var passwdInputViewState by mutableStateOf(\n        value = PasswdInputViewState(\n            onDismissRequest = ::handlePasswdInputViewDismiss,\n            onButtonClicked = ::handlePasswdInput,\n            onCheckedChange = ::handlePasswdCheckedChange,\n            checked = !SettingsManager(ContextProvider.context).getAuthStatus()\n        )\n    )\n    private lateinit var lastBuyFlowResult: BuyFlowResult\n\n    private fun finishWithResult(result: Bundle) {\n        viewModelScope.launch {\n            _event.send(NotificationEvent(NotificationEventId.FINISH, result))\n        }\n    }\n\n    private fun handlePasswdInputViewDismiss() {\n        if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"handlePasswdInputViewDismiss called\")\n        passwdInputViewState = passwdInputViewState.copy(visible = false)\n    }\n\n    private suspend fun submitBuyAction(authToken: String? = null) {\n        val param = startParams?.getString(KEY_IAP_SHEET_UI_PARAM) ?: return finishWithResult(\n            billingUiViewState.result\n        )\n        val buyFlowResult =\n            InAppBillingServiceImpl.acquireRequest(ContextProvider.context, param, billingUiViewState.actionContextList, authToken)\n        handleBuyFlowResult(buyFlowResult)\n    }\n\n    private suspend fun doAcquireRequest() {\n        val param = startParams?.getString(KEY_IAP_SHEET_UI_PARAM) ?: return finishWithResult(\n            billingUiViewState.result\n        )\n        val buyFlowResult = InAppBillingServiceImpl.acquireRequest(ContextProvider.context, param, billingUiViewState.actionContextList)\n        handleBuyFlowResult(buyFlowResult)\n    }\n\n    private fun handlePasswdInput(password: String) {\n        loadingDialogVisible = true\n        passwdInputViewState = passwdInputViewState.copy(visible = false)\n        billingUiViewState = billingUiViewState.copy(visible = false)\n        viewModelScope.launch(Dispatchers.IO) {\n            val param = startParams!!.getString(KEY_IAP_SHEET_UI_PARAM)\n            val (statusCode, encodedRapt) = try {\n                200 to InAppBillingServiceImpl.requestAuthProofToken(ContextProvider.context, param!!, password)\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n                -1 to null\n            }\n            if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"requestAuthProofToken statusCode=$statusCode, encodedRapt=$encodedRapt\")\n            if (encodedRapt.isNullOrEmpty()) {\n                loadingDialogVisible = false\n                val errMsg = when (statusCode) {\n                    400 -> ErrorMessageRef.PASSWORD_ERROR\n                    else -> ErrorMessageRef.NETWORK_ERROR\n                }\n                passwdInputViewState =\n                    passwdInputViewState.copy(visible = true, hasError = true, errMsg = errMsg)\n                billingUiViewState = billingUiViewState.copy(visible = true)\n                return@launch\n            }\n            if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"handleBuyButtonClicked encodedRapt: $encodedRapt\")\n            SettingsManager(ContextProvider.context).setAuthStatus(!passwdInputViewState.checked)\n            submitBuyAction(authToken = encodedRapt)\n        }\n    }\n\n    private fun handlePasswdCheckedChange(checked: Boolean) {\n        if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"handlePasswdCheckedChange checked: $checked\")\n        passwdInputViewState = passwdInputViewState.copy(checked = checked)\n    }\n\n    private fun handleBuyButtonClicked(action: BAction) {\n        val nextShowScreen = billingUiViewState.screenMap[action.screenId]\n            ?: return finishWithResult(billingUiViewState.result)\n        when (val uiType = nextShowScreen.uiInfo?.uiType) {\n            UIType.LOADING_SPINNER -> {\n                showLoading()\n                billingUiViewState.actionContextList.addAll(action.actionContext)\n                viewModelScope.launch(Dispatchers.IO) {\n                    submitBuyAction()\n                }\n            }\n\n            UIType.PURCHASE_AUTH_SCREEN -> {\n                if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"handleBuyButtonClicked need auth\")\n                val account =\n                    lastBuyFlowResult.account ?: return finishWithResult(billingUiViewState.result)\n                // TODO: Magic constants? These are protobufs!\n                billingUiViewState.actionContextList.add(\"ea010408011001b80301\".decodeHex())\n                billingUiViewState.actionContextList.add(\"0a020802b80301\".decodeHex())\n                passwdInputViewState = passwdInputViewState.copy(\n                    visible = true,\n                    label = account.name\n                )\n            }\n\n            else -> {\n                if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"handleBuyButtonClicked unknown next uiType: $uiType\")\n                finishWithResult(billingUiViewState.result)\n            }\n        }\n    }\n\n    private fun showLoading() {\n        loadingDialogVisible = true\n        passwdInputViewState = passwdInputViewState.copy(visible = false)\n        billingUiViewState = billingUiViewState.copy(visible = false)\n    }\n\n    private fun handleClickAction(action: BAction?) {\n        if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"handleClickAction action: $action (contexts: ${action?.actionContext?.map { it.toHexString() }}\")\n        when (action?.type) {\n            ActionType.SHOW -> {\n                when (action.uiInfo?.uiType) {\n                    UIType.PURCHASE_CART_BUY_BUTTON -> handleBuyButtonClicked(action)\n                    UIType.PURCHASE_CHANGE_SUBSCRIPTION_CONTINUE_BUTTON,\n                    UIType.PURCHASE_PAYMENT_DECLINED_CONTINUE_BUTTON,\n                    UIType.PURCHASE_CART_PAYMENT_OPTIONS_LINK,\n                    UIType.PURCHASE_CART_CONTINUE_BUTTON,\n                    UIType.PURCHASE_CONSENT_COLLECTION_REFUND_RIGHTS_CONTINUE_BUTTON,\n                    UIType.BILLING_PROFILE_SCREEN_ABANDON -> {\n                        if (action.screenId?.isNotBlank() == true) {\n                            if (showScreen(action.screenId!!)) {\n                                if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"showScreen ${action.screenId} success\")\n                                return\n                            }\n                            if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"showScreen ${action.screenId} false\")\n                        }\n                        finishWithResult(billingUiViewState.result)\n                    }\n\n                    UIType.BILLING_PROFILE_OPTION_CREATE_INSTRUMENT,\n                    UIType.BILLING_PROFILE_OPTION_ADD_PLAY_CREDIT,\n                    UIType.BILLING_PROFILE_BUTTON_UPDATE_INSTRUMENT,\n                    UIType.BILLING_PROFILE_OPTION_REDEEM_CODE -> {\n                        viewModelScope.launch(Dispatchers.IO) {\n                            showPaymentMethodPage(\"action\")\n                        }\n                    }\n\n                    else -> finishWithResult(billingUiViewState.result)\n                }\n            }\n\n            ActionType.DELAY -> {\n                viewModelScope.launch {\n                    delay(action.delay!!.toLong())\n                    finishWithResult(billingUiViewState.result)\n                }\n            }\n\n            else -> {\n                when (action?.uiInfo?.uiType) {\n                    UIType.PURCHASE_CART_CONTINUE_BUTTON -> viewModelScope.launch(Dispatchers.IO) {\n                        submitBuyAction()\n                    }\n\n                    UIType.PURCHASE_SUCCESS_SCREEN_WITH_AUTH_CHOICES -> {\n                        viewModelScope.launch {\n                            delay(3000)\n                            finishWithResult(billingUiViewState.result)\n                        }\n                    }\n\n                    UIType.BILLING_PROFILE_EXISTING_INSTRUMENT -> {\n                        if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"switch payment method context: ${action.actionContext[0].toHexString()}\")\n                        showLoading()\n                        billingUiViewState.actionContextList.addAll(action.actionContext)\n                        viewModelScope.launch(Dispatchers.IO) {\n                            doAcquireRequest()\n                        }\n                    }\n\n                    UIType.PURCHASE_CART_PAYMENT_OPTIONS_LINK -> {\n                        if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"open payment option page context: ${action.actionContext[0].toHexString()}\")\n                        showLoading()\n                        billingUiViewState.actionContextList.addAll(action.actionContext)\n                        viewModelScope.launch(Dispatchers.IO) {\n                            doAcquireRequest()\n                        }\n                    }\n\n                    else -> finishWithResult(billingUiViewState.result)\n                }\n            }\n        }\n    }\n\n    private fun showScreen(screenId: String): Boolean {\n        val showScreen = billingUiViewState.screenMap[screenId] ?: return false\n        billingUiViewState = billingUiViewState.copy(\n            showScreen = showScreen,\n            visible = true\n        )\n        loadingDialogVisible = false\n        return true\n    }\n\n    private suspend fun showPaymentMethodPage(src: String): Boolean {\n        _event.send(\n            NotificationEvent(\n                NotificationEventId.OPEN_PAYMENT_METHOD_ACTIVITY,\n                bundleOf(\"account\" to lastBuyFlowResult.account, \"src\" to src)\n            )\n        )\n        return true\n    }\n\n    private suspend fun handleBuyFlowResult(buyFlowResult: BuyFlowResult) {\n        val failAction = suspend {\n            _event.send(NotificationEvent(NotificationEventId.FINISH, buyFlowResult.result))\n        }\n        val action = buyFlowResult.acquireResult?.action ?: return failAction()\n        val screenMap = buyFlowResult.acquireResult.screenMap\n        val showScreen = screenMap[action.screenId] ?: return failAction()\n        if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"handleAcquireResult, showScreen:$showScreen result:${buyFlowResult.acquireResult}\")\n        if (action.type != ActionType.SHOW) return failAction()\n        lastBuyFlowResult = buyFlowResult\n        billingUiViewState.screenMap.putAll(screenMap)\n        billingUiViewState = billingUiViewState.copy(\n            showScreen = showScreen,\n            result = buyFlowResult.result,\n            actionContextList = action.actionContext,\n            visible = true\n        )\n        loadingDialogVisible = false\n    }\n\n    private suspend fun doLoadSheetUIAction(context: Context, param: String) {\n        val buyFlowResult = InAppBillingServiceImpl.acquireRequest(context, param, firstRequest = true)\n        handleBuyFlowResult(buyFlowResult)\n    }\n\n    suspend fun loadData(context: Context) {\n        val param = startParams?.getString(KEY_IAP_SHEET_UI_PARAM)\n            ?: throw RuntimeException(\"get action param failed\")\n        if (Log.isLoggable(TAG, Log.DEBUG)) Log.d(TAG, \"loadData param:$param\")\n        showLoading()\n        doLoadSheetUIAction(context, param)\n    }\n\n    fun close() {\n        val result = if (billingUiViewState.result.containsKey(\"INAPP_PURCHASE_DATA\"))\n            billingUiViewState.result\n        else\n            resultBundle(BillingClient.BillingResponseCode.USER_CANCELED, \"\")\n        finishWithResult(result)\n    }\n}"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/ui/logic/Models.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.vending.billing.ui.logic\n\nimport android.accounts.Account\nimport android.os.Bundle\nimport org.microg.vending.billing.core.ui.AcquireParsedResult\nimport org.microg.vending.billing.core.ui.BAction\nimport org.microg.vending.billing.core.ui.BScreen\n\ndata class BillingUiViewState(\n    val visible: Boolean = false,\n    val screenMap: MutableMap<String, BScreen> = mutableMapOf(),\n    val showScreen: BScreen = BScreen(),\n    val result: Bundle = Bundle.EMPTY,\n    val actionContextList: MutableList<ByteArray> = mutableListOf(),\n    val onClickAction: (BAction?) -> Unit\n)\n\ndata class PasswdInputViewState(\n    var visible: Boolean = false,\n    var label: String = \"\",\n    var hasError: Boolean = false,\n    var errMsg: ErrorMessageRef? = null,\n    var checked: Boolean = false,\n    val onButtonClicked: (passwd: String) -> Unit,\n    val onCheckedChange: (value: Boolean) -> Unit,\n    val onDismissRequest: () -> Unit\n)\n\ndata class BuyFlowResult(\n    val acquireResult: AcquireParsedResult?,\n    val account: Account?,\n    val result: Bundle\n)"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/ui/theme/Color.kt",
    "content": "package org.microg.vending.billing.ui.theme\n\nimport androidx.compose.ui.graphics.Color\n\n// TODO: Use colors from Play\n\nval Purple80 = Color(0xFFD0BCFF)\nval PurpleGrey80 = Color(0xFFCCC2DC)\nval Pink80 = Color(0xFFEFB8C8)\n\nval Purple40 = Color(0xFF6650a4)\nval PurpleGrey40 = Color(0xFF625b71)\nval Pink40 = Color(0xFF7D5260)"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/ui/theme/Theme.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.vending.billing.ui.theme\n\nimport android.app.Activity\nimport android.os.Build.VERSION.SDK_INT\nimport androidx.annotation.RequiresApi\nimport androidx.compose.foundation.isSystemInDarkTheme\nimport androidx.compose.material3.MaterialTheme\nimport androidx.compose.material3.darkColorScheme\nimport androidx.compose.material3.dynamicDarkColorScheme\nimport androidx.compose.material3.dynamicLightColorScheme\nimport androidx.compose.material3.lightColorScheme\nimport androidx.compose.runtime.Composable\nimport androidx.compose.runtime.SideEffect\nimport androidx.compose.ui.graphics.toArgb\nimport androidx.compose.ui.platform.LocalContext\nimport androidx.compose.ui.platform.LocalView\nimport androidx.core.view.WindowCompat\n\n// TODO: Use theme from Play\n\nprivate val DarkColorScheme = darkColorScheme(\n    primary = Purple80,\n    secondary = PurpleGrey80,\n    tertiary = Pink80\n)\n\nprivate val LightColorScheme = lightColorScheme(\n    primary = Purple40,\n    secondary = PurpleGrey40,\n    tertiary = Pink40\n\n    /* Other default colors to override\n    background = Color(0xFFFFFBFE),\n    surface = Color(0xFFFFFBFE),\n    onPrimary = Color.White,\n    onSecondary = Color.White,\n    onTertiary = Color.White,\n    onBackground = Color(0xFF1C1B1F),\n    onSurface = Color(0xFF1C1B1F),\n    */\n)\n@RequiresApi(21)\n@Composable\nfun InAppBillingTheme(\n    darkTheme: Boolean = isSystemInDarkTheme(),\n    // Dynamic color is available on Android 12+\n    dynamicColor: Boolean = true,\n    content: @Composable () -> Unit\n) {\n    val colorScheme = when {\n        dynamicColor && SDK_INT >= 31 -> {\n            val context = LocalContext.current\n            if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)\n        }\n\n        darkTheme -> DarkColorScheme\n        else -> LightColorScheme\n    }\n    val view = LocalView.current\n    if (!view.isInEditMode) {\n        SideEffect {\n            val window = (view.context as Activity).window\n            window.statusBarColor = colorScheme.primary.toArgb()\n            WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme\n        }\n    }\n\n    MaterialTheme(\n        colorScheme = colorScheme,\n        typography = Typography,\n        content = content\n    )\n}"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/ui/theme/Type.kt",
    "content": "package org.microg.vending.billing.ui.theme\n\nimport androidx.compose.material3.Typography\nimport androidx.compose.ui.text.TextStyle\nimport androidx.compose.ui.text.font.FontFamily\nimport androidx.compose.ui.text.font.FontWeight\nimport androidx.compose.ui.unit.sp\n\n// Set of Material typography styles to start with\nval Typography = Typography(\n    bodyLarge = TextStyle(\n        fontFamily = FontFamily.Default,\n        fontWeight = FontWeight.Normal,\n        fontSize = 16.sp,\n        lineHeight = 24.sp,\n        letterSpacing = 0.5.sp\n    )\n    /* Other default text styles to override\n    titleLarge = TextStyle(\n        fontFamily = FontFamily.Default,\n        fontWeight = FontWeight.Normal,\n        fontSize = 22.sp,\n        lineHeight = 28.sp,\n        letterSpacing = 0.sp\n    ),\n    labelSmall = TextStyle(\n        fontFamily = FontFamily.Default,\n        fontWeight = FontWeight.Medium,\n        fontSize = 11.sp,\n        lineHeight = 16.sp,\n        letterSpacing = 0.5.sp\n    )\n    */\n)"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/ui/widgets/LoadingDialog.kt",
    "content": "package org.microg.vending.billing.ui.widgets\n\nimport androidx.activity.compose.BackHandler\nimport androidx.compose.foundation.background\nimport androidx.compose.foundation.layout.Box\nimport androidx.compose.foundation.layout.fillMaxSize\nimport androidx.compose.foundation.layout.fillMaxWidth\nimport androidx.compose.foundation.layout.height\nimport androidx.compose.material3.CircularProgressIndicator\nimport androidx.compose.material3.MaterialTheme\nimport androidx.compose.runtime.Composable\nimport androidx.compose.ui.Alignment\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.platform.LocalConfiguration\nimport androidx.compose.ui.unit.dp\n\n@Composable\nfun LoadingDialog(visible: Boolean) {\n    if (visible) {\n        BackHandler(enabled = true) {\n\n        }\n        Box(\n            modifier = Modifier\n                .height(LocalConfiguration.current.screenHeightDp.dp.times(0.3f))\n                .fillMaxWidth()\n                .background(MaterialTheme.colorScheme.background)\n        ) {\n            CircularProgressIndicator(\n                modifier = Modifier\n                    .align(alignment = Alignment.Center),\n                color = MaterialTheme.colorScheme.primary\n            )\n        }\n    }\n}"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/billing/ui/widgets/PasswdInputDialog.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.vending.billing.ui.widgets\n\nimport android.app.ActionBar\nimport android.view.Gravity\nimport androidx.compose.foundation.background\nimport androidx.compose.foundation.clickable\nimport androidx.compose.foundation.layout.Column\nimport androidx.compose.foundation.layout.PaddingValues\nimport androidx.compose.foundation.layout.Row\nimport androidx.compose.foundation.layout.defaultMinSize\nimport androidx.compose.foundation.layout.fillMaxWidth\nimport androidx.compose.foundation.layout.padding\nimport androidx.compose.foundation.layout.wrapContentHeight\nimport androidx.compose.foundation.layout.wrapContentWidth\nimport androidx.compose.foundation.shape.RoundedCornerShape\nimport androidx.compose.foundation.text.KeyboardOptions\nimport androidx.compose.material3.Button\nimport androidx.compose.material3.Checkbox\nimport androidx.compose.material3.ExperimentalMaterial3Api\nimport androidx.compose.material3.LocalContentColor\nimport androidx.compose.material3.MaterialTheme\nimport androidx.compose.material3.OutlinedTextField\nimport androidx.compose.material3.Surface\nimport androidx.compose.material3.Text\nimport androidx.compose.material3.TextFieldDefaults\nimport androidx.compose.runtime.Composable\nimport androidx.compose.runtime.LaunchedEffect\nimport androidx.compose.runtime.getValue\nimport androidx.compose.runtime.mutableStateOf\nimport androidx.compose.runtime.remember\nimport androidx.compose.runtime.setValue\nimport androidx.compose.ui.Alignment\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.focus.FocusRequester\nimport androidx.compose.ui.focus.focusRequester\nimport androidx.compose.ui.platform.LocalContext\nimport androidx.compose.ui.platform.LocalView\nimport androidx.compose.ui.res.stringResource\nimport androidx.compose.ui.text.input.ImeAction\nimport androidx.compose.ui.text.input.KeyboardType\nimport androidx.compose.ui.text.input.PasswordVisualTransformation\nimport androidx.compose.ui.unit.dp\nimport androidx.compose.ui.unit.sp\nimport androidx.compose.ui.window.Dialog\nimport androidx.compose.ui.window.DialogWindowProvider\nimport org.microg.vending.billing.ui.HtmlText\nimport org.microg.vending.billing.ui.getWindowWidth\nimport org.microg.vending.billing.ui.logic.PasswdInputViewState\nimport com.android.vending.R\nimport org.microg.vending.billing.ui.logic.ErrorMessageRef\n\n@OptIn(ExperimentalMaterial3Api::class)\n@Composable\nfun PasswdInputDialog(viewState: PasswdInputViewState) {\n    if (viewState.visible) {\n        Dialog(onDismissRequest = viewState.onDismissRequest) {\n            val dialogWindow = (LocalView.current.parent as DialogWindowProvider).window\n            val lp = dialogWindow.attributes\n            lp.width = getWindowWidth(LocalContext.current)\n            lp.height = ActionBar.LayoutParams.WRAP_CONTENT\n            lp.gravity = Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL\n            dialogWindow.attributes = lp\n            Surface(\n                modifier = Modifier\n                    .wrapContentHeight()\n                    .wrapContentWidth(),\n                color = MaterialTheme.colorScheme.background\n            ) {\n                Column(\n                    Modifier\n                        .background(MaterialTheme.colorScheme.background)\n                        .wrapContentHeight()\n                        .wrapContentWidth()\n                ) {\n                    var inputText by remember { mutableStateOf(\"\") }\n                    val focusRequester = remember { FocusRequester() }\n                    OutlinedTextField(\n                        modifier = Modifier\n                            .padding(top = 15.dp, start = 20.dp, end = 20.dp)\n                            .fillMaxWidth()\n                            .focusRequester(focusRequester),\n                        value = inputText,\n                        label = { Text(text = viewState.label) },\n                        placeholder = { Text(text = stringResource(R.string.tips_input_passwd)) },\n                        onValueChange = {\n                            inputText = it\n                            viewState.hasError = false\n                        },\n                        visualTransformation = PasswordVisualTransformation(),\n                        keyboardOptions = KeyboardOptions(\n                            keyboardType = KeyboardType.Password,\n                            imeAction = ImeAction.Done\n                        ),\n                        singleLine = true,\n                        isError = viewState.hasError,\n                        colors = TextFieldDefaults.outlinedTextFieldColors(\n                            errorLabelColor = if (viewState.hasError) MaterialTheme.colorScheme.error else LocalContentColor.current,\n                            errorBorderColor = if (viewState.hasError) MaterialTheme.colorScheme.error else LocalContentColor.current\n                        ),\n                        supportingText = {\n                            if (viewState.hasError) {\n                                Text(\n                                    text = when (viewState.errMsg) {\n                                        ErrorMessageRef.PASSWORD_ERROR -> stringResource(R.string.error_passwd)\n                                        ErrorMessageRef.NETWORK_ERROR -> stringResource(R.string.error_network)\n                                        null -> \"\"\n                                    },\n                                    color = MaterialTheme.colorScheme.error\n                                )\n                            }\n                        }\n                    )\n                    LaunchedEffect(Unit) {\n                        focusRequester.requestFocus()\n                    }\n                    Row(\n                        modifier = Modifier\n                            .fillMaxWidth()\n                            .wrapContentHeight()\n                            .padding(start = 15.dp, end = 20.dp, top = 8.dp, bottom = 8.dp),\n                        verticalAlignment = Alignment.CenterVertically\n                    ) {\n                        Checkbox(\n                            modifier = Modifier.align(Alignment.CenterVertically),\n                            checked = viewState.checked,\n                            onCheckedChange = {\n                                viewState.onCheckedChange(it)\n                            }\n                        )\n                        Text(\n                            text = stringResource(R.string.tips_remember_login_info),\n                            modifier = Modifier\n                                .padding(start = 14.dp)\n                                .align(Alignment.CenterVertically)\n                                .clickable {\n                                    viewState.onCheckedChange(!viewState.checked)\n                                },\n                            fontSize = 14.sp\n                        )\n                    }\n                    Row(\n                        modifier = Modifier\n                            .fillMaxWidth()\n                            .wrapContentHeight()\n                            .padding(start = 20.dp, end = 20.dp, bottom = 8.dp),\n                        verticalAlignment = Alignment.CenterVertically\n                    ) {\n                        HtmlText(\n                            text = \"<a href=\\\"https://accounts.google.com/RecoverAccount?fpOnly=1&amp;Email=${viewState.label}\\\">${stringResource(R.string.tips_forget_passwd)}</a>\",\n                            fontSize = 14.sp\n                        )\n                        HtmlText(\n                            modifier = Modifier.padding(start = 5.dp),\n                            text = \"<a href=\\\"https://support.google.com/googleplay/answer/1626831\\\" target=\\\"_blank\\\">${stringResource(R.string.tips_more_details)}</a>\",\n                            fontSize = 14.sp\n                        )\n                    }\n                    Button(\n                        modifier = Modifier\n                            .defaultMinSize(minWidth = 1.dp, minHeight = 1.dp)\n                            .fillMaxWidth()\n                            .wrapContentHeight()\n                            .padding(start = 20.dp, end = 20.dp),\n                        enabled = inputText.isNotBlank(),\n                        onClick = { viewState.onButtonClicked(inputText) },\n                        shape = RoundedCornerShape(20),\n                        contentPadding = PaddingValues(7.dp)\n                    ) {\n                        Text(\n                            text = stringResource(R.string.text_verify_button)\n                        )\n                    }\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/delivery/Delivery.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.vending.delivery\n\nimport android.accounts.AccountManager\nimport android.content.Context\nimport android.util.Log\nimport com.android.vending.buildRequestHeaders\nimport com.google.android.finsky.BulkGrant\nimport com.google.android.finsky.BulkRequest\nimport com.google.android.finsky.BulkRequestWrapper\nimport com.google.android.finsky.BulkResponseWrapper\nimport com.google.android.finsky.DeviceSyncInfo\nimport com.google.android.finsky.SyncResponse\nimport com.google.android.finsky.splitinstallservice.PackageComponent\nimport com.google.android.finsky.syncDeviceInfo\nimport org.microg.vending.billing.core.AuthData\nimport org.microg.vending.billing.core.GooglePlayApi\nimport org.microg.vending.billing.core.GooglePlayApi.Companion.URL_DELIVERY\nimport org.microg.vending.billing.core.HttpClient\nimport org.microg.vending.billing.proto.GoogleApiResponse\nimport org.microg.vending.splitinstall.SPLIT_LANGUAGE_TAG\n\nprivate const val TAG = \"GmsVendingDelivery\"\n\n/**\n * Call the FDFE delivery endpoint to retrieve download URLs for the\n * desired components. If specific split install packages are requested,\n * only those will be contained in the result.\n */\nsuspend fun HttpClient.requestDownloadUrls(\n        context: Context,\n        packageName: String,\n        versionCode: Long,\n        auth: AuthData,\n        requestSplitPackages: List<String>? = null,\n        deliveryToken: String? = null,\n): List<PackageComponent> {\n\n    val requestUrl = StringBuilder(\"$URL_DELIVERY?doc=$packageName&ot=1&vc=$versionCode\")\n\n    requestSplitPackages?.apply {\n        requestUrl.append(\n            \"&bvc=$versionCode&pf=1&pf=2&pf=3&pf=4&pf=5&pf=7&pf=8&pf=9&pf=10&bda=4&bf=4&fdcf=1&fdcf=2&ch=\"\n        )\n        forEach { requestUrl.append(\"&mn=\").append(it) }\n    }\n\n    deliveryToken?.let {\n        requestUrl.append(\"&dtok=$it\")\n    }\n\n    Log.v(TAG, \"requestDownloadUrls start\")\n    val languages = requestSplitPackages?.filter { it.startsWith(SPLIT_LANGUAGE_TAG) }?.map {\n        it.replace(SPLIT_LANGUAGE_TAG, \"\")\n    }\n    Log.d(TAG, \"requestDownloadUrls languages: $languages\")\n\n    val androidId = auth.gsfId.toLong(16)\n    val headers = buildRequestHeaders(\n        auth = auth.authToken,\n        androidId = androidId,\n        languages\n    ).minus(\n        // TODO: understand behavior. According to tests, these headers break split install queries but may be needed for normal ones\n        (if (requestSplitPackages != null) listOf(\"X-DFE-Encoded-Targets\", \"X-DFE-Phenotype\", \"X-DFE-Device-Id\", \"X-DFE-Client-Id\") else emptyList()).toSet()\n    )\n\n    kotlin.runCatching {\n        //Authorize the account to prevent the inability to obtain split information\n        post(\n                url = GooglePlayApi.URL_BULK,\n                headers = headers,\n                payload = BulkRequestWrapper.build {\n                    request(BulkRequest.build {\n                        packageName(packageName)\n                        grant(BulkGrant.build { grantLevel = 1 })\n                    })\n                },\n                adapter = BulkResponseWrapper.ADAPTER\n        )\n    }\n\n    val response = get(\n        url = requestUrl.toString(),\n        headers = headers,\n        adapter = GoogleApiResponse.ADAPTER\n    )\n    Log.d(TAG, \"requestDownloadUrls end response -> $response\")\n\n    val basePackage = response.payload!!.deliveryResponse!!.deliveryData?.let {\n        if (it.baseUrl != null && it.baseBytes != null) {\n            PackageComponent(packageName, \"base\", it.baseUrl, it.baseBytes.toLong())\n        } else null\n    }\n    val splitComponents = response.payload.deliveryResponse!!.deliveryData!!.splitPackages.filter {\n        !it.splitPackageName.isNullOrEmpty() && !it.downloadUrl.isNullOrEmpty()\n    }.map {\n        if (requestSplitPackages != null) {\n            // Only download requested, if specific components were requested\n            requestSplitPackages.firstOrNull { requestComponent ->\n                (it.splitPackageName?.contains(requestComponent) == true || requestComponent.contains(it.splitPackageName!!))\n            }?.let { requestComponent ->\n                PackageComponent(packageName, it.splitPackageName!!, it.downloadUrl!!, it.size!!.toLong())\n            }\n        } else {\n            // Download all offered components (server chooses)\n            PackageComponent(packageName, it.splitPackageName!!, it.downloadUrl!!, it.size!!.toLong())\n        }\n    }\n\n    val components = if (requestSplitPackages != null) {\n        splitComponents\n    } else {\n        listOf(basePackage) + splitComponents\n    }.filterNotNull()\n\n    Log.d(TAG, \"requestDownloadUrls end -> $components\")\n\n    return components\n}"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/enterprise/App.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.vending.enterprise\n\nopen class App(\n    val packageName: String,\n    val versionCode: Int?,\n    val displayName: String,\n    val iconUrl: String?,\n    val dependencies: List<App>,\n    val deliveryToken: String?\n) {\n    override fun equals(other: Any?): Boolean {\n        if (this === other) return true\n        if (other !is App) return false\n\n        if (packageName != other.packageName) return false\n\n        return true\n    }\n\n    override fun hashCode(): Int = packageName.hashCode()\n}"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/enterprise/AppState.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.vending.enterprise\n\ninternal sealed interface AppState\n\n/**\n * App cannot be installed on this user's device\n */\ninternal data object NotCompatible : AppState\n\n/**\n * App is available, but not installed on the user's device.\n */\ninternal data object NotInstalled : AppState\n\n/**\n * App is already installed on the device, but an update is available.\n */\ninternal data object UpdateAvailable : AppState\n\n/**\n * An unspecific app operation is currently outstanding\n */\ninternal data object Pending : AppState\n\n/**\n * App is installed on device and up to date.\n */\ninternal data object Installed : AppState"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/enterprise/EnterpriseApp.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.vending.enterprise\n\nimport org.microg.vending.enterprise.proto.AppInstallPolicy\n\nclass EnterpriseApp(\n    packageName: String,\n    versionCode: Int?,\n    displayName: String,\n    iconUrl: String?,\n    deliveryToken: String?,\n    dependencies: List<App>,\n    val policy: AppInstallPolicy\n) : App(packageName, versionCode, displayName, iconUrl, dependencies, deliveryToken)"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/enterprise/InstallProgress.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.vending.enterprise\n\nimport android.app.PendingIntent\n\ninternal sealed interface InstallProgress\n\ninternal data class Downloading(\n    val bytesDownloaded: Long,\n    val bytesTotal: Long\n) : InstallProgress, AppState\ninternal data object CommitingSession : InstallProgress\ninternal data object InstallComplete : InstallProgress\ninternal data class InstallError(\n    val errorMessage: String\n) : InstallProgress"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/splitinstall/Constants.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.vending.splitinstall\n\nconst val SPLIT_LANGUAGE_TAG = \"config.\"\n"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/ui/InstallProgressNotification.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.vending.ui\n\nimport android.app.Notification\nimport android.app.NotificationChannel\nimport android.app.NotificationManager\nimport android.app.PendingIntent\nimport android.content.Context\nimport android.content.pm.ApplicationInfo\nimport android.content.pm.PackageManager\nimport android.content.pm.PackageManager.NameNotFoundException\nimport android.util.Log\nimport androidx.core.app.NotificationCompat\nimport androidx.core.app.NotificationManagerCompat\nimport com.android.vending.R\nimport org.microg.gms.ui.TAG\nimport org.microg.vending.enterprise.CommitingSession\nimport org.microg.vending.enterprise.Downloading\nimport org.microg.vending.enterprise.InstallComplete\nimport org.microg.vending.enterprise.InstallError\nimport org.microg.vending.enterprise.InstallProgress\n\nprivate const val INSTALL_NOTIFICATION_CHANNEL_ID = \"packageInstall\"\n\ninternal fun Context.notifyInstallPrompt(packageName: String, sessionId: Int, installIntent: PendingIntent, deleteIntent: PendingIntent) {\n    val notificationManager = NotificationManagerCompat.from(this)\n    val label = try {\n        val applicationInfo = packageManager.getPackageInfo(packageName, 0).applicationInfo\n        applicationInfo?.loadLabel(packageManager) ?: return\n    } catch (e: NameNotFoundException) {\n        Log.e(TAG, \"Couldn't load label for $packageName (${e.message}). Is it not installed?\")\n        return\n    }\n    getInstallPromptNotificationBuilder().apply {\n        setDeleteIntent(deleteIntent)\n        setContentTitle(getString(R.string.installer_notification_progress_splitinstall_click_install, label))\n        addAction(R.drawable.ic_download, getString(R.string.vending_overview_row_action_install), installIntent)\n        setContentIntent(installIntent)\n        setAutoCancel(true)\n    }.apply {\n        notificationManager.notify(sessionId, this.build())\n    }\n}\n\ninternal fun Context.notifySplitInstallProgress(packageName: String, sessionId: Int, progress: InstallProgress) {\n\n    val label = try {\n        val applicationInfo = packageManager.getPackageInfo(packageName, 0).applicationInfo\n        applicationInfo?.loadLabel(packageManager) ?: return\n    } catch (e: NameNotFoundException) {\n        Log.e(TAG, \"Couldn't load label for $packageName (${e.message}). Is it not installed?\")\n        return\n    } catch (e: NullPointerException) {\n        Log.e(TAG, \"Couldn't get application info for $packageName (${e.message})\")\n        return\n    }\n\n    createNotificationChannel()\n\n    val notificationManager = NotificationManagerCompat.from(this)\n\n    when (progress) {\n        is Downloading -> getDownloadNotificationBuilder().apply {\n            setContentTitle(getString(R.string.installer_notification_progress_splitinstall_downloading, label))\n            setProgress(100, ((progress.bytesDownloaded.toFloat() / progress.bytesTotal) * 100).toInt().coerceIn(0, 100), false)\n        }\n        CommitingSession -> {\n            // Check whether silent installation is possible. Only show the notification if silent installation is supported,\n            // to prevent cases where the user cancels the install page and the notification is not removed.\n            if (isSystem(packageManager)) {\n                getDownloadNotificationBuilder().apply {\n                    setContentTitle(getString(R.string.installer_notification_progress_splitinstall_commiting, label))\n                    setProgress(0, 1, true)\n                }\n            } else {\n                notificationManager.cancel(sessionId)\n                null\n            }\n        }\n        else -> null.also { notificationManager.cancel(sessionId) }\n    }?.apply {\n        setOngoing(true)\n\n        notificationManager.notify(sessionId, this.build())\n    }\n\n}\n\n/**\n * @return The notification after it had been posted _if_ it is an ongoing notification.\n */\ninternal fun Context.notifyInstallProgress(\n    displayName: String,\n    sessionId: Int,\n    progress: InstallProgress,\n    isDependency: Boolean = false\n): Notification? {\n\n    createNotificationChannel()\n    getDownloadNotificationBuilder().apply {\n\n        val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager\n\n        when (progress) {\n            is Downloading -> {\n                setContentTitle(\n                    getString(\n                        if (isDependency) R.string.installer_notification_progress_splitinstall_downloading\n                        else R.string.installer_notification_progress_downloading,\n                        displayName\n                    )\n                )\n                setProgress(progress.bytesTotal.toInt(), progress.bytesDownloaded.toInt(), false)\n                setOngoing(true)\n                return this.build().also { notificationManager.notify(sessionId, it) }\n            }\n            CommitingSession -> {\n                // Check whether silent installation is possible. Only show the notification if silent installation is supported,\n                // to prevent cases where the user cancels the install page and the notification is not removed.\n                if (isSystem(packageManager)) {\n                    setContentTitle(\n                            getString(\n                                    if (isDependency) R.string.installer_notification_progress_splitinstall_commiting\n                                    else R.string.installer_notification_progress_commiting,\n                                    displayName\n                            )\n                    )\n                    setProgress(0, 0, true)\n                    setOngoing(true)\n                    return this.build().also { notificationManager.notify(sessionId, it) }\n                } else {\n                    notificationManager.cancel(sessionId)\n                    return null\n                }\n            }\n            InstallComplete -> {\n                if (!isDependency) {\n                    setContentTitle(\n                        getString(\n                            R.string.installer_notification_progress_complete,\n                            displayName\n                        )\n                    )\n                    setSmallIcon(android.R.drawable.stat_sys_download_done)\n                    notificationManager.notify(sessionId, this.build())\n                } else {\n                    notificationManager.cancel(sessionId)\n                }\n                return null\n            }\n            is InstallError -> {\n                if (!isDependency) {\n                    setContentTitle(\n                        getString(\n                            R.string.installer_notification_progress_failed,\n                            displayName\n                        )\n                    )\n                    setSmallIcon(android.R.drawable.stat_notify_error)\n                    // see `InstallComplete` case\n                    notificationManager.notify(sessionId, this.build())\n                } else {\n                    notificationManager.cancel(sessionId)\n                }\n                return null\n            }\n        }\n    }\n\n}\n\nprivate fun Context.getInstallPromptNotificationBuilder() =\n        NotificationCompat.Builder(this, INSTALL_NOTIFICATION_CHANNEL_ID)\n                .setPriority(NotificationCompat.PRIORITY_LOW)\n                .setSmallIcon(android.R.drawable.stat_sys_download)\n                .setLocalOnly(true)\n\nprivate fun Context.getDownloadNotificationBuilder() =\n    NotificationCompat.Builder(this, INSTALL_NOTIFICATION_CHANNEL_ID)\n        .setSmallIcon(android.R.drawable.stat_sys_download)\n        .setPriority(NotificationCompat.PRIORITY_LOW)\n        .setLocalOnly(true)\n\nprivate fun Context.createNotificationChannel() {\n    if (android.os.Build.VERSION.SDK_INT >= 26) {\n        val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager\n        notificationManager.createNotificationChannel(\n            NotificationChannel(\n                INSTALL_NOTIFICATION_CHANNEL_ID,\n                getString(R.string.installer_notification_channel_name),\n                NotificationManager.IMPORTANCE_LOW\n            ).apply {\n                description = getString(R.string.installer_notification_channel_description)\n                enableVibration(false)\n                enableLights(false)\n                setShowBadge(false)\n            }\n        )\n    }\n}\n\nprivate fun Context.isSystem(pm: PackageManager): Boolean {\n    try {\n        val ai = pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA)\n        return (ai.flags and (ApplicationInfo.FLAG_SYSTEM or ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0\n    } catch (e: NameNotFoundException) {\n        return false\n    }\n}"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/ui/MainActivity.java",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.vending.ui;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.util.Log;\nimport android.widget.Toast;\nimport com.android.vending.R;\n\npublic class MainActivity extends Activity {\n    private static final String TAG = \"MainActivity\";\n    private static final String GMS_PACKAGE_NAME = \"com.google.android.gms\";\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        try {\n            Intent intent = new Intent(Intent.ACTION_MAIN);\n            intent.setPackage(GMS_PACKAGE_NAME);\n            try {\n                startActivity(intent);\n            } catch (Exception e) {\n                Log.w(TAG, \"MAIN activity is not DEFAULT. Trying to resolve instead.\");\n                intent.setClassName(GMS_PACKAGE_NAME, getPackageManager().resolveActivity(intent, 0).activityInfo.name);\n                startActivity(intent);\n            }\n            Toast.makeText(this, R.string.toast_installed, Toast.LENGTH_LONG).show();\n        } catch (Exception e) {\n            Log.w(TAG, \"Failed launching microG Settings\", e);\n            Toast.makeText(this, R.string.toast_not_installed, Toast.LENGTH_LONG).show();\n        }\n        finish();\n    }\n}\n"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/ui/NetworkState.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.vending.ui\n\nenum class NetworkState {\n    ACTIVE,\n    PASSIVE,\n    ERROR\n}"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/ui/WorkAppsActivity.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.vending.ui\n\nimport android.accounts.Account\nimport android.accounts.AccountManager\nimport android.content.ComponentName\nimport android.content.Context\nimport android.content.Intent\nimport android.content.ServiceConnection\nimport android.os.Bundle\nimport android.os.IBinder\nimport android.util.Log\nimport androidx.activity.ComponentActivity\nimport androidx.activity.compose.setContent\nimport androidx.activity.enableEdgeToEdge\nimport androidx.annotation.RequiresApi\nimport androidx.compose.foundation.layout.Column\nimport androidx.compose.foundation.layout.padding\nimport androidx.compose.material3.ExperimentalMaterial3Api\nimport androidx.compose.material3.MaterialTheme\nimport androidx.compose.material3.Scaffold\nimport androidx.compose.runtime.Composable\nimport androidx.compose.runtime.getValue\nimport androidx.compose.runtime.mutableStateMapOf\nimport androidx.compose.runtime.mutableStateOf\nimport androidx.compose.runtime.setValue\nimport androidx.compose.ui.Modifier\nimport com.android.vending.buildRequestHeaders\nimport com.android.vending.installer.uninstallPackage\nimport kotlinx.coroutines.runBlocking\nimport org.microg.gms.auth.AuthConstants\nimport org.microg.gms.common.DeviceConfiguration\nimport org.microg.gms.common.asProto\nimport org.microg.gms.profile.Build\nimport org.microg.gms.profile.ProfileManager\nimport org.microg.vending.UploadDeviceConfigRequest\nimport org.microg.vending.WorkAccountChangedReceiver\nimport org.microg.vending.billing.AuthManager\nimport org.microg.vending.billing.core.AuthData\nimport org.microg.vending.billing.core.GooglePlayApi.Companion.URL_ENTERPRISE_CLIENT_POLICY\nimport org.microg.vending.billing.core.GooglePlayApi.Companion.URL_FDFE\nimport org.microg.vending.billing.core.GooglePlayApi.Companion.URL_ITEM_DETAILS\nimport org.microg.vending.billing.core.HttpClient\nimport org.microg.vending.billing.createDeviceEnvInfo\nimport org.microg.vending.billing.proto.GoogleApiResponse\nimport org.microg.vending.enterprise.EnterpriseApp\nimport org.microg.vending.enterprise.App\nimport org.microg.vending.enterprise.AppState\nimport org.microg.vending.enterprise.Installed\nimport org.microg.vending.enterprise.NotCompatible\nimport org.microg.vending.enterprise.NotInstalled\nimport org.microg.vending.enterprise.Pending\nimport org.microg.vending.enterprise.UpdateAvailable\nimport org.microg.vending.enterprise.proto.AppInstallPolicy\nimport com.android.vending.installer.InstallService\nimport org.microg.vending.proto.AppMeta\nimport org.microg.vending.proto.GetItemsRequest\nimport org.microg.vending.proto.RequestApp\nimport org.microg.vending.proto.RequestItem\nimport org.microg.vending.ui.components.EnterpriseList\nimport org.microg.vending.ui.components.NetworkState\nimport java.io.IOException\n\n@RequiresApi(21)\nclass WorkAppsActivity : ComponentActivity() {\n\n    private val apps: MutableMap<EnterpriseApp, AppState> = mutableStateMapOf()\n    private var networkState by mutableStateOf(NetworkState.ACTIVE)\n\n    private var auth: AuthData? = null\n        set(value) {\n            field = value\n            installService?.auth = value\n        }\n\n    private var installService: InstallService? = null\n\n    private val serviceConnection = object : ServiceConnection {\n        override fun onServiceConnected(name: ComponentName?, service: IBinder?) {\n            installService = (service as InstallService.LocalBinder).getService()\n            installService?.auth = auth\n            installService?.apps = apps\n        }\n\n        override fun onServiceDisconnected(name: ComponentName?) {\n            installService = null\n        }\n    }\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        enableEdgeToEdge()\n        super.onCreate(savedInstanceState)\n\n        ProfileManager.ensureInitialized(this)\n\n        val accountManager = AccountManager.get(this)\n        val accounts = accountManager.getAccountsByType(AuthConstants.WORK_ACCOUNT_TYPE)\n        if (accounts.isEmpty()) {\n            // Component should not be enabled; disable through receiver, and redirect to main activity\n            WorkAccountChangedReceiver().onReceive(this, null)\n            startActivity(Intent(this, MainActivity::class.java))\n            finish()\n        } else if (accounts.size > 1) {\n            Log.w(TAG, \"Multiple work accounts found. This is unexpected and could point \" +\n                    \"towards misuse of the work account service API by the DPC.\")\n        }\n        val account = accounts.first()\n\n        load(account)\n\n        setContent {\n            VendingUi(account,\n                install = { app: EnterpriseApp, isUpdate: Boolean ->\n                    Intent(this@WorkAppsActivity, InstallService::class.java).let {\n                        if (android.os.Build.VERSION.SDK_INT >= 26) {\n                            startForegroundService(it)\n                        } else {\n                            startService(it)\n                        }\n                    }\n                    installService?.installAsync(app, isUpdate)\n                },\n\n                    //Thread { runBlocking { install(app, isUpdate) } }.start() },\n                uninstall = { app -> Thread { runBlocking { uninstall(app) } }.start() }\n            )\n        }\n    }\n\n    override fun onStart() {\n        super.onStart()\n        bindService(\n            Intent(this, InstallService::class.java),\n            serviceConnection, Context.BIND_AUTO_CREATE\n        )\n    }\n\n    override fun onStop() {\n        super.onStop()\n        unbindService(serviceConnection)\n    }\n\n    private fun load(account: Account) {\n        networkState = NetworkState.ACTIVE\n        Thread {\n            runBlocking {\n                try {\n                    // Authenticate\n                    auth = AuthManager.getAuthData(this@WorkAppsActivity, account)\n                    val authData = auth\n                    val deviceInfo = createDeviceEnvInfo(this@WorkAppsActivity)\n                    if (deviceInfo == null || authData == null) {\n                        Log.e(TAG, \"Unable to open play store when deviceInfo = $deviceInfo and authData = $authData\")\n                        networkState = NetworkState.ERROR\n                        return@runBlocking\n                    }\n\n                    val headers = buildRequestHeaders(authData.authToken, authData.gsfId.toLong(16))\n                    val client = HttpClient()\n\n                    // Register device for server-side compatibility checking\n                    val upload = client.post(\n                        url = \"$URL_FDFE/uploadDeviceConfig\",\n                        headers = headers.minus(\"X-PS-RH\"),\n                        payload = UploadDeviceConfigRequest(\n                            DeviceConfiguration(this@WorkAppsActivity).asProto(),\n                            manufacturer = Build.MANUFACTURER,\n                            //gcmRegistrationId = TODO: looks like remote-triggered app downloads may be announced through GCM?\n                        ),\n                        adapter = GoogleApiResponse.ADAPTER\n                    )\n                    Log.d(TAG, \"uploaddc: ${upload.payload!!.uploadDeviceConfigResponse}\")\n\n                    // Fetch list of apps available to the scoped enterprise account\n                    val apps = client.post(\n                        url = URL_ENTERPRISE_CLIENT_POLICY,\n                        headers = headers.plus(\"content-type\" to \"application/x-protobuf\"),\n                        adapter = GoogleApiResponse.ADAPTER\n                    ).payload?.enterpriseClientPolicyResponse?.policy?.apps?.filter { it.packageName != null }\n\n                    if (apps == null) {\n                        Log.e(TAG, \"unexpected network response: missing expected fields\")\n                        networkState = NetworkState.ERROR\n                        return@runBlocking\n                    }\n\n                    Log.v(TAG, \"app policy: ${apps.joinToString { \"${it.packageName}: ${it.policy}\" }}\")\n\n                    if (apps.isEmpty()) {\n                        // Don't fetch details of empty app list (otherwise HTTP 400)\n                        networkState = NetworkState.PASSIVE\n                        this@WorkAppsActivity.apps.clear()\n                        return@runBlocking\n                    }\n\n                    // Fetch details about all available apps\n                    val details = client.post(\n                        url = URL_ITEM_DETAILS,\n                        // TODO: meaning unclear, but returns 400 without. constant? possibly has influence on which fields are returned?\n                        headers = headers.plus(\"x-dfe-item-field-mask\" to \"GgWGHay3ByILPP/Avy+4A4YlCRM\"),\n                        payload = GetItemsRequest(\n                            apps.map {\n                                RequestItem(RequestApp(AppMeta(it.packageName)))\n                            }\n                        ),\n                        adapter = GoogleApiResponse.ADAPTER\n                    ).getItemsResponses.mapNotNull { it.response }.associate { item ->\n                        val packageName = item.meta!!.packageName!!\n                        val installedDetails = this@WorkAppsActivity.packageManager.getInstalledPackages(0).find {\n                            it.applicationInfo?.packageName == packageName\n                        }\n\n                        val available = item.offer?.delivery != null\n\n                        val versionCode = if (available) {\n                            item.offer!!.version!!.versionCode!!\n                        } else null\n\n                        val state = if (!available && installedDetails == null) NotCompatible\n                        else if (!available && installedDetails != null) Installed\n                        else if (available && installedDetails == null) NotInstalled\n                        else if (available && installedDetails != null && installedDetails.versionCode < versionCode!!) UpdateAvailable\n                        else /* if (available && installedDetails != null) */ Installed\n\n                        EnterpriseApp(\n                            packageName,\n                            versionCode,\n                            item.detail!!.name!!.displayName!!,\n                            item.detail.icon?.icon?.paint?.url,\n                            item.offer?.delivery?.key,\n                            item.offer?.delivery?.dependencies?.map {\n                                App(it.packageName!!, it.versionCode!!, it.packageName, null, emptyList(), null)\n                            } ?: emptyList(),\n                            apps.find { it.packageName!! == item.meta.packageName }!!.policy ?: AppInstallPolicy.OPTIONAL,\n                        ) to state\n                    }.onEach {\n                        Log.v(TAG, \"${it.key.packageName} (state: ${it.value}) delivery token: ${it.key.deliveryToken ?: \"none acquired\"}\")\n                    }\n\n                    this@WorkAppsActivity.apps.apply {\n                        clear()\n                        putAll(details)\n                    }\n                    networkState = NetworkState.PASSIVE\n                } catch (e: IOException) {\n                    networkState = NetworkState.ERROR\n                    Log.e(TAG, \"Network error: ${e.message}\")\n                    e.printStackTrace()\n                } catch (e: Exception) {\n                    networkState = NetworkState.ERROR\n                    Log.e(TAG, \"Unexpected network response, cannot process\")\n                    e.printStackTrace()\n                }\n            }\n        }.start()\n\n    }\n\n    private suspend fun uninstall(app: EnterpriseApp) {\n        val previousState = apps[app]!!\n        apps[app] = Pending\n        runCatching { uninstallPackage(app.packageName) }.onSuccess {\n            apps[app] = NotInstalled\n        }.onFailure {\n            apps[app] = previousState\n        }\n    }\n\n    @OptIn(ExperimentalMaterial3Api::class)\n    @Composable\n    fun VendingUi(\n        account: Account,\n        install: (app: EnterpriseApp, isUpdate: Boolean) -> Unit,\n        uninstall: (app: EnterpriseApp) -> Unit\n    ) {\n        MaterialTheme {\n            Scaffold(\n                topBar = {\n                    WorkVendingTopAppBar()\n                }\n            ) { innerPadding ->\n                Column(Modifier.padding(innerPadding)) {\n                    NetworkState(networkState, { load(account) }) {\n                        EnterpriseList(apps, install, uninstall)\n                    }\n                }\n            }\n        }\n    }\n\n    companion object {\n        const val TAG = \"GmsVendingWorkApp\"\n    }\n}"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/ui/WorkVendingTopAppBar.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.vending.ui\n\nimport androidx.compose.foundation.layout.Row\nimport androidx.compose.foundation.layout.padding\nimport androidx.compose.material3.ExperimentalMaterial3Api\nimport androidx.compose.material3.Icon\nimport androidx.compose.material3.LocalContentColor\nimport androidx.compose.material3.MaterialTheme\nimport androidx.compose.material3.Text\nimport androidx.compose.material3.TopAppBar\nimport androidx.compose.material3.TopAppBarDefaults\nimport androidx.compose.runtime.Composable\nimport androidx.compose.ui.Alignment\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.res.painterResource\nimport androidx.compose.ui.res.stringResource\nimport androidx.compose.ui.tooling.preview.Preview\nimport androidx.compose.ui.unit.dp\nimport com.android.vending.R\n\n@OptIn(ExperimentalMaterial3Api::class)\n@Composable\nfun WorkVendingTopAppBar() = TopAppBar(\n    title = {\n        Row {\n            Icon(\n                painterResource(R.drawable.ic_work),\n                contentDescription = null,\n                Modifier.align(Alignment.CenterVertically),\n                tint = LocalContentColor.current\n            )\n            Text(\n                stringResource(R.string.vending_activity_name),\n                Modifier\n                    .align(Alignment.CenterVertically)\n                    .padding(start = 8.dp)\n            )\n        }\n    },\n    colors = TopAppBarDefaults.smallTopAppBarColors(\n        containerColor = MaterialTheme.colorScheme.primaryContainer,\n        titleContentColor = MaterialTheme.colorScheme.onPrimaryContainer\n    )\n)\n\n@Preview\n@Composable\nfun PreviewWorkVendingTopAppBar() {\n    WorkVendingTopAppBar()\n}"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/ui/components/AppRow.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.vending.ui.components\n\nimport androidx.compose.foundation.layout.Arrangement\nimport androidx.compose.foundation.layout.Row\nimport androidx.compose.foundation.layout.Spacer\nimport androidx.compose.foundation.layout.padding\nimport androidx.compose.foundation.layout.size\nimport androidx.compose.material.icons.Icons\nimport androidx.compose.material.icons.filled.Delete\nimport androidx.compose.material.icons.filled.Warning\nimport androidx.compose.material3.CircularProgressIndicator\nimport androidx.compose.material3.FilledIconButton\nimport androidx.compose.material3.Icon\nimport androidx.compose.material3.IconButton\nimport androidx.compose.material3.IconButtonDefaults\nimport androidx.compose.material3.MaterialTheme\nimport androidx.compose.material3.Text\nimport androidx.compose.runtime.Composable\nimport androidx.compose.ui.Alignment\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.res.painterResource\nimport androidx.compose.ui.res.stringResource\nimport androidx.compose.ui.tooling.preview.Preview\nimport androidx.compose.ui.unit.dp\nimport coil.compose.AsyncImage\nimport com.android.vending.R\nimport org.microg.vending.enterprise.App\nimport org.microg.vending.enterprise.AppState\nimport org.microg.vending.enterprise.Downloading\nimport org.microg.vending.enterprise.Installed\nimport org.microg.vending.enterprise.NotCompatible\nimport org.microg.vending.enterprise.NotInstalled\nimport org.microg.vending.enterprise.Pending\nimport org.microg.vending.enterprise.UpdateAvailable\n\n@Composable\ninternal fun AppRow(app: App, state: AppState, install: () -> Unit, update: () -> Unit, uninstall: () -> Unit) {\n    Row(\n        Modifier.padding(top = 8.dp, bottom = 8.dp),\n        horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.Start),\n        verticalAlignment = Alignment.CenterVertically\n    ) {\n        val iconSpace = Modifier.size(48.dp)\n        if (app.iconUrl != null) {\n            AsyncImage(\n                model = app.iconUrl,\n                modifier = iconSpace,\n                contentDescription = null,\n            )\n        } else {\n            Spacer(iconSpace)\n        }\n        Text(app.displayName, Modifier.weight(1f))\n\n        if (state == NotCompatible) {\n            Icon(Icons.Default.Warning, null, Modifier.padding(end=8.dp), tint = MaterialTheme.colorScheme.secondary)\n            // TODO better UI\n        }\n        if (state == UpdateAvailable || state == Installed) {\n            IconButton(uninstall) {\n                Icon(Icons.Default.Delete, stringResource(R.string.vending_overview_row_action_uninstall), tint = MaterialTheme.colorScheme.secondary)\n            }\n        }\n        if (state == UpdateAvailable) {\n            FilledIconButton(update, colors = IconButtonDefaults.filledIconButtonColors(containerColor = MaterialTheme.colorScheme.secondaryContainer)) {\n                Icon(painterResource(R.drawable.ic_update), stringResource(R.string.vending_overview_row_action_update), tint = MaterialTheme.colorScheme.secondary)\n            }\n        }\n        if (state == NotInstalled) {\n            FilledIconButton(install, colors = IconButtonDefaults.filledIconButtonColors(containerColor = MaterialTheme.colorScheme.secondaryContainer)) {\n                Icon(painterResource(R.drawable.ic_download), stringResource(R.string.vending_overview_row_action_install), tint = MaterialTheme.colorScheme.secondary)\n            }\n        }\n        if (state == Pending) {\n            CircularProgressIndicator(Modifier.padding(4.dp))\n        }\n        if (state is Downloading) {\n            CircularProgressIndicator(\n                progress = state.bytesDownloaded.toFloat() / state.bytesTotal.toFloat(),\n                modifier = Modifier.padding(4.dp)\n            )\n        }\n    }\n\n}\n\nprivate val previewApp = App(\"org.mozilla.firefox\", 0, \"Firefox\", null, emptyList(), null)\n@Preview\n@Composable\nfun AppRowNotCompatiblePreview() {\n    AppRow(previewApp, NotCompatible, {}, {}, {})\n}\n\n@Preview\n@Composable\nfun AppRowNotInstalledPreview() {\n    AppRow(previewApp, NotInstalled, {}, {}, {})\n}\n\n@Preview\n@Composable\nfun AppRowUpdateablePreview() {\n    AppRow(previewApp, UpdateAvailable, {}, {}, {})\n}\n\n@Preview\n@Composable\nfun AppRowInstalledPreview() {\n    AppRow(previewApp, Installed, {}, {}, {})\n}\n\n@Preview\n@Composable\nfun AppRowPendingPreview() {\n    AppRow(previewApp, Pending, {}, {}, {})\n}\n\n@Preview\n@Composable\nfun AppRowProgressPreview() {\n    AppRow(previewApp, Downloading(75, 100), {}, {}, {})\n}\n\n@Preview\n@Composable\nfun AppRowVeryLongPreview() {\n    val longPreviewApp = App(\"com.example\", 0, \"This is an application that has a very long title which would (if we didn't fix that) push out the icons\", null, emptyList(), null)\n    AppRow(longPreviewApp, UpdateAvailable, {}, {}, {})\n}\n"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/ui/components/EnterpriseList.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.vending.ui.components\n\nimport androidx.annotation.StringRes\nimport androidx.compose.foundation.background\nimport androidx.compose.foundation.layout.Arrangement\nimport androidx.compose.foundation.layout.Box\nimport androidx.compose.foundation.layout.Column\nimport androidx.compose.foundation.layout.Row\nimport androidx.compose.foundation.layout.Spacer\nimport androidx.compose.foundation.layout.fillMaxSize\nimport androidx.compose.foundation.layout.padding\nimport androidx.compose.foundation.lazy.LazyColumn\nimport androidx.compose.foundation.lazy.items\nimport androidx.compose.foundation.shape.RoundedCornerShape\nimport androidx.compose.material.icons.Icons\nimport androidx.compose.material.icons.filled.Info\nimport androidx.compose.material.icons.filled.Warning\nimport androidx.compose.material3.Icon\nimport androidx.compose.material3.MaterialTheme\nimport androidx.compose.material3.Text\nimport androidx.compose.runtime.Composable\nimport androidx.compose.ui.Alignment\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.draw.clip\nimport androidx.compose.ui.res.stringResource\nimport androidx.compose.ui.text.style.TextAlign\nimport androidx.compose.ui.tooling.preview.Preview\nimport androidx.compose.ui.unit.dp\nimport com.android.vending.R\nimport org.microg.vending.enterprise.AppState\nimport org.microg.vending.enterprise.EnterpriseApp\nimport org.microg.vending.enterprise.Installed\nimport org.microg.vending.enterprise.NotCompatible\nimport org.microg.vending.enterprise.NotInstalled\nimport org.microg.vending.enterprise.proto.AppInstallPolicy\n\n\n@Composable\ninternal fun EnterpriseList(appStates: Map<EnterpriseApp, AppState>, install: (app: EnterpriseApp, isUpdate: Boolean) -> Unit, uninstall: (app: EnterpriseApp) -> Unit) {\n    if (appStates.isNotEmpty()) LazyColumn(Modifier.padding(horizontal = 16.dp)) {\n\n        val apps = appStates.keys\n        val requiredApps = apps.filter { it.policy == AppInstallPolicy.MANDATORY }\n        if (requiredApps.isNotEmpty()) {\n            item { InListHeading(R.string.vending_overview_enterprise_row_mandatory) }\n            item { InListWarning(R.string.vending_overview_enterprise_row_mandatory_hint) }\n            items(requiredApps.sortedBy { it.packageName }) {\n                AppRow(it, appStates[it]!!, { install(it, false) }, { install(it, true) }, { uninstall(it) })\n            }\n        }\n\n        val optionalApps = apps.filter { it.policy == AppInstallPolicy.OPTIONAL }\n        if (optionalApps.isNotEmpty()) {\n            item { InListHeading(R.string.vending_overview_enterprise_row_offered) }\n            items(optionalApps.sortedBy { it.packageName }) {\n                AppRow(it, appStates[it]!!, { install(it, false) }, { install(it, true) }, { uninstall(it) })\n            }\n        }\n\n    } else Box(\n        Modifier\n            .fillMaxSize()\n            .padding(24.dp)\n    ) {\n        Column(Modifier.align(Alignment.Center), verticalArrangement = Arrangement.spacedBy(32.dp)) {\n            Text(\n                stringResource(R.string.vending_overview_enterprise_no_apps_available),\n                textAlign = TextAlign.Center\n            )\n\n                Row(\n                    Modifier\n                        .clip(shape = RoundedCornerShape(16.dp))\n                        .background(MaterialTheme.colorScheme.primaryContainer),\n                    verticalAlignment = Alignment.CenterVertically\n                ) {\n                    Icon(\n                        Icons.Default.Info,\n                        contentDescription = null,\n                        Modifier.padding(start = 16.dp, top = 16.dp, bottom = 16.dp, end = 16.dp),\n                        MaterialTheme.colorScheme.onPrimaryContainer\n                    )\n                    Text(\n                        stringResource(R.string.vending_overview_enterprise_no_apps_available_wait),\n                        Modifier.padding(top = 16.dp, bottom = 16.dp, end = 16.dp),\n                        MaterialTheme.colorScheme.onPrimaryContainer\n                    )\n                }\n        }\n    }\n\n}\n\n@Composable\nfun InListHeading(@StringRes text: Int) {\n    Text(\n        stringResource(text),\n        modifier = Modifier.padding(top = 24.dp, bottom = 8.dp),\n        style = MaterialTheme.typography.headlineSmall\n    )\n}\n\n@Composable\nfun InListWarning(@StringRes text: Int) {\n    Column(Modifier.padding(bottom = 8.dp)) {\n        Row(\n            Modifier\n                .clip(shape = RoundedCornerShape(16.dp))\n                .background(MaterialTheme.colorScheme.errorContainer),\n            verticalAlignment = Alignment.CenterVertically\n        ) {\n            Icon(\n                Icons.Default.Warning,\n                contentDescription = null,\n                Modifier.padding(start = 16.dp, top = 16.dp, bottom = 16.dp, end = 16.dp),\n                MaterialTheme.colorScheme.onErrorContainer\n            )\n            Text(\n                stringResource(text),\n                Modifier.padding(top = 16.dp, bottom = 16.dp, end = 16.dp),\n                MaterialTheme.colorScheme.onErrorContainer\n            )\n        }\n    }\n\n}\n\n@Preview\n@Composable\nfun EnterpriseListPreview() {\n    EnterpriseList(\n        mapOf(\n            EnterpriseApp(\"com.android.vending\", 0, \"Market\", null, \"\", emptyList(), AppInstallPolicy.MANDATORY) to Installed,\n            EnterpriseApp(\"org.mozilla.firefox\", 0, \"Firefox\", null, \"\", emptyList(), AppInstallPolicy.OPTIONAL) to NotInstalled,\n            EnterpriseApp(\"org.thoughtcrime.securesms\", 0, \"Signal\", null, \"\", emptyList(), AppInstallPolicy.OPTIONAL) to NotCompatible\n        ), { _, _ -> }, {}\n    )\n}\n\n@Preview\n@Composable\nfun EnterpriseListEmptyPreview() {\n    EnterpriseList(emptyMap(), { _, _ -> }, {})\n}\n"
  },
  {
    "path": "vending-app/src/main/java/org/microg/vending/ui/components/NetworkState.kt",
    "content": "package org.microg.vending.ui.components\n\nimport androidx.compose.foundation.layout.Box\nimport androidx.compose.foundation.layout.Column\nimport androidx.compose.foundation.layout.fillMaxSize\nimport androidx.compose.foundation.layout.padding\nimport androidx.compose.material3.Button\nimport androidx.compose.material3.CircularProgressIndicator\nimport androidx.compose.material3.MaterialTheme\nimport androidx.compose.material3.Text\nimport androidx.compose.runtime.Composable\nimport androidx.compose.ui.Alignment\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.res.stringResource\nimport androidx.compose.ui.tooling.preview.Preview\nimport androidx.compose.ui.unit.dp\nimport com.android.vending.R\nimport org.microg.vending.ui.NetworkState\n\n@Composable\nfun NetworkState(networkState: NetworkState, retry: () -> Unit, content: @Composable () -> Unit) {\n    when (networkState) {\n        NetworkState.ACTIVE -> {\n            Box(Modifier.fillMaxSize()) {\n                CircularProgressIndicator(\n                    modifier = Modifier.align(Alignment.Center),\n                    color = MaterialTheme.colorScheme.primary\n                )\n            }\n        }\n\n        NetworkState.ERROR -> {\n            Box(Modifier.fillMaxSize().padding(24.dp)) {\n                Column(Modifier.align(Alignment.Center), horizontalAlignment = Alignment.CenterHorizontally) {\n                    Text(stringResource(R.string.error_network))\n                    Button(retry, Modifier.padding(top = 8.dp)) {\n                        Text(stringResource(R.string.error_retry))\n                    }\n                }\n            }\n        }\n\n        NetworkState.PASSIVE -> {\n            content()\n        }\n    }\n}\n\n\n@Preview\n@Composable\nfun NetworkStateActivePreview() {\n    NetworkState(NetworkState.ACTIVE, { }) {}\n}\n\n@Preview\n@Composable\nfun NetworkStateErrorPreview() {\n    NetworkState(NetworkState.ERROR, { }) {}\n}\n\n@Preview\n@Composable\nfun NetworkStatePassivePreview() {\n    NetworkState(NetworkState.PASSIVE, {}) {\n        Text(\"Network operation complete.\", Modifier.padding(16.dp))\n    }\n}"
  },
  {
    "path": "vending-app/src/main/kotlin/com/android/vending/extensions.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.android.vending\n\nimport android.accounts.Account\nimport android.accounts.AccountManager\nimport android.accounts.AccountManagerFuture\nimport android.os.Bundle\nimport android.util.Base64\nimport android.util.Log\nimport okio.ByteString\nimport org.microg.gms.profile.Build\nimport org.microg.vending.billing.getUserAgent\nimport org.microg.vending.proto.AndroidVersionMeta\nimport org.microg.vending.proto.DeviceMeta\nimport org.microg.vending.proto.EncodedTriple\nimport org.microg.vending.proto.EncodedTripleWrapper\nimport org.microg.vending.proto.IntWrapper\nimport org.microg.vending.proto.Locality\nimport org.microg.vending.proto.LocalityWrapper\nimport org.microg.vending.proto.RequestHeader\nimport org.microg.vending.proto.RequestLanguagePackage\nimport org.microg.vending.proto.StringWrapper\nimport org.microg.vending.proto.Timestamp\nimport org.microg.vending.proto.TimestampContainer\nimport org.microg.vending.proto.TimestampContainer1\nimport org.microg.vending.proto.TimestampContainer1Wrapper\nimport org.microg.vending.proto.TimestampContainer2\nimport org.microg.vending.proto.TimestampStringWrapper\nimport org.microg.vending.proto.TimestampWrapper\nimport org.microg.vending.proto.UnknownByte12\nimport org.microg.vending.proto.UserAgent\nimport org.microg.vending.proto.Uuid\nimport java.io.ByteArrayOutputStream\nimport java.io.IOException\nimport java.net.URLEncoder\nimport java.util.UUID\nimport java.util.zip.GZIPOutputStream\nimport kotlin.coroutines.resume\nimport kotlin.coroutines.resumeWithException\nimport kotlin.coroutines.suspendCoroutine\n\nprivate const val TAG = \"VendingRequestHeaders\"\n\nconst val AUTH_TOKEN_SCOPE: String = \"oauth2:https://www.googleapis.com/auth/googleplay\"\n\nprivate const val BASE64_FLAGS = Base64.URL_SAFE or Base64.NO_WRAP or Base64.NO_PADDING\nprivate const val FINSKY_VERSION = \"Finsky/37.5.24-29%20%5B0%5D%20%5BPR%5D%20565477504\"\n\nfun buildRequestHeaders(auth: String, androidId: Long, language: List<String>? = null): Map<String, String> {\n    var millis = System.currentTimeMillis()\n    val timestamp = TimestampContainer.Builder().container2(\n        TimestampContainer2.Builder().wrapper(TimestampWrapper.Builder().timestamp(makeTimestamp(millis)).build()).timestamp(makeTimestamp(millis)).build()\n    )\n    millis = System.currentTimeMillis()\n    timestamp.container1Wrapper(\n        TimestampContainer1Wrapper.Builder().androidId(androidId.toString()).container(\n            TimestampContainer1.Builder().timestamp(millis.toString() + \"000\").wrapper(makeTimestamp(millis)).build()\n        ).build()\n    )\n\n    val encodedTimestamps = String(Base64.encode(timestamp.build().encode().encodeGzip(), BASE64_FLAGS))\n    val locality = Locality.Builder().unknown1(1).unknown2(2).countryCode(\"\").region(\n        TimestampStringWrapper.Builder().string(\"\").timestamp(makeTimestamp(System.currentTimeMillis())).build()\n    ).country(\n        TimestampStringWrapper.Builder().string(\"\").timestamp(makeTimestamp(System.currentTimeMillis())).build()\n    ).unknown3(0).build()\n    val encodedLocality = String(\n        Base64.encode(locality.encode(), BASE64_FLAGS)\n    )\n\n    val header = RequestHeader.Builder().encodedTimestamps(StringWrapper.Builder().string(encodedTimestamps).build()).triple(\n        EncodedTripleWrapper.Builder().triple(\n            EncodedTriple.Builder().encoded1(\"\").encoded2(\"\").empty(\"\").build()\n        ).build()\n    ).locality(LocalityWrapper.Builder().encodedLocalityProto(encodedLocality).build()).unknown(IntWrapper.Builder().integer(5).build()).empty(\"\").deviceMeta(\n        DeviceMeta.Builder().android(\n            AndroidVersionMeta.Builder().androidSdk(Build.VERSION.SDK_INT).buildNumber(Build.ID).androidVersion(Build.VERSION.RELEASE).unknown(0).build()\n        ).unknown1(\n            UnknownByte12.Builder().bytes(ByteString.EMPTY).build().toString()\n        ).unknown2(1).build()\n    ).userAgent(\n        UserAgent.Builder().deviceName(Build.DEVICE).deviceHardware(Build.HARDWARE).deviceModelName(Build.MODEL).finskyVersion(FINSKY_VERSION)\n            .deviceProductName(Build.MODEL).androidId(androidId) // must not be 0\n            .buildFingerprint(Build.FINGERPRINT).build()\n    ).uuid(\n        Uuid.Builder().uuid(UUID.randomUUID().toString()).unknown(2).build()\n    ).apply {\n        if (language != null) {\n            languages(\n                RequestLanguagePackage.Builder().language(language).build()\n            )\n        }\n    }.build().encode()\n\n    val xPsRh = String(Base64.encode(header.encodeGzip(), BASE64_FLAGS))\n    Log.v(TAG, \"X-PS-RH: $xPsRh\")\n    val userAgent = getUserAgent()\n\n    return mapOf(\n        \"X-PS-RH\" to xPsRh,\n        \"User-Agent\" to userAgent,\n        \"Accept-Language\" to \"en-US\",\n        \"Connection\" to \"Keep-Alive\",\n        \"X-DFE-Device-Id\" to androidId.toBigInteger().toString(16),\n        \"X-DFE-Client-Id\" to \"am-google\",\n        \"X-DFE-Encoded-Targets\" to \"CAESN/qigQYC2AMBFfUbyA7SM5Ij/CvfBoIDgxHqGP8R3xzIBvoQtBKFDZ4HAY4FrwSVMasHBO0O2Q8akgYRAQECAQO7AQEpKZ0CnwECAwRrAQYBr9PPAoK7sQMBAQMCBAkIDAgBAwEDBAICBAUZEgMEBAMLAQEBBQEBAcYBARYED+cBfS8CHQEKkAEMMxcBIQoUDwYHIjd3DQ4MFk0JWGYZEREYAQOLAYEBFDMIEYMBAgICAgICOxkCD18LGQKEAcgDBIQBAgGLARkYCy8oBTJlBCUocxQn0QUBDkkGxgNZQq0BZSbeAmIDgAEBOgGtAaMCDAOQAZ4BBIEBKUtQUYYBQscDDxPSARA1oAEHAWmnAsMB2wFyywGLAxol+wImlwOOA80CtwN26A0WjwJVbQEJPAH+BRDeAfkHK/ABASEBCSAaHQemAzkaRiu2Ad8BdXeiAwEBGBUBBN4LEIABK4gB2AFLfwECAdoENq0CkQGMBsIBiQEtiwGgA1zyAUQ4uwS8AwhsvgPyAcEDF27vApsBHaICGhl3GSKxAR8MC6cBAgItmQYG9QIeywLvAeYBDArLAh8HASI4ELICDVmVBgsY/gHWARtcAsMBpALiAdsBA7QBpAJmIArpByn0AyAKBwHTARIHAX8D+AMBcRIBBbEDmwUBMacCHAciNp0BAQF0OgQLJDuSAh54kwFSP0eeAQQ4M5EBQgMEmwFXywFo0gFyWwMcapQBBugBPUW2AVgBKmy3AR6PAbMBGQxrUJECvQR+8gFoWDsYgQNwRSczBRXQAgtRswEW0ALMAREYAUEBIG6yATYCRE8OxgER8gMBvQEDRkwLc8MBTwHZAUOnAXiiBakDIbYBNNcCIUmuArIBSakBrgFHKs0EgwV/G3AD0wE6LgECtQJ4xQFwFbUCjQPkBS6vAQqEAUZF3QIM9wEhCoYCQhXsBCyZArQDugIziALWAdIBlQHwBdUErQE6qQaSA4EEIvYBHir9AQVLmgMCApsCKAwHuwgrENsBAjNYswEVmgIt7QJnN4wDEnta+wGfAcUBxgEtEFXQAQWdAUAeBcwBAQM7rAEJATJ0LENrdh73A6UBhAE+qwEeASxLZUMhDREuH0CGARbd7K0GlQo\",\n        \"X-DFE-Phenotype\" to \"H4sIAAAAAAAAAB3OO3KjMAAA0KRNuWXukBkBQkAJ2MhgAZb5u2GCwQZbCH_EJ77QHmgvtDtbv-Z9_H63zXXU0NVPB1odlyGy7751Q3CitlPDvFd8lxhz3tpNmz7P92CFw73zdHU2Ie0Ad2kmR8lxhiErTFLt3RPGfJQHSDy7Clw10bg8kqf2owLokN4SecJTLoSwBnzQSd652_MOf2d1vKBNVedzg4ciPoLz2mQ8efGAgYeLou-l-PXn_7Sna1MfhHuySxt-4esulEDp8Sbq54CPPKjpANW-lkU2IZ0F92LBI-ukCKSptqeq1eXU96LD9nZfhKHdtjSWwJqUm_2r6pMHOxk01saVanmNopjX3YxQafC4iC6T55aRbC8nTI98AF_kItIQAJb5EQxnKTO7TZDWnr01HVPxelb9A2OWX6poidMWl16K54kcu_jhXw-JSBQkVcD_fPsLSZu6joIBAAA\"\n    ) + if (auth.isNotEmpty()) mapOf(\"Authorization\" to \"Bearer $auth\") else emptyMap()\n}\n\nfun makeTimestamp(millis: Long): Timestamp {\n    return Timestamp.Builder().seconds((millis / 1000)).nanos(((millis % 1000) * 1000000).toInt()).build()\n}\n\nprivate fun encodeString(s: String?): String {\n    return URLEncoder.encode(s).replace(\"+\", \"%20\")\n}\n\n/**\n * From [StackOverflow](https://stackoverflow.com/a/46688434/), CC BY-SA 4.0 by Sergey Frolov, adapted.\n */\nfun ByteArray.encodeGzip(): ByteArray {\n    try {\n        ByteArrayOutputStream().use { byteOutput ->\n            GZIPOutputStream(byteOutput).use { gzipOutput ->\n                gzipOutput.write(this)\n                gzipOutput.finish()\n                return byteOutput.toByteArray()\n            }\n        }\n    } catch (e: IOException) {\n        Log.e(TAG, \"Failed to encode bytes as GZIP\")\n        return ByteArray(0)\n    }\n}\nsuspend fun getAuthToken(accountManager: AccountManager, account: Account, authTokenType: String) =\n    suspendCoroutine<Bundle> { continuation ->\n        accountManager.getAuthToken(account, authTokenType, false, { future: AccountManagerFuture<Bundle> ->\n            try {\n                val result = future.result\n                continuation.resume(result)\n            } catch (e: Exception) {\n                continuation.resumeWithException(e)\n            }\n        }, null)\n    }\n"
  },
  {
    "path": "vending-app/src/main/kotlin/com/android/vending/installer/Constants.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.android.vending.installer\n\nimport android.content.Context\nimport java.io.File\n\nprivate const val FILE_SAVE_PATH = \"phonesky-download-service\"\ninternal const val TAG = \"GmsPackageInstaller\"\n\nconst val KEY_BYTES_DOWNLOADED = \"bytes_downloaded\"\nconst val VENDING_INSTALL_ACTION = \"com.android.vending.ACTION_INSTALL\"\nconst val VENDING_INSTALL_DELETE_ACTION = \"com.android.vending.ACTION_INSTALL_DELETE\"\nconst val SESSION_ID = \"session_id\"\nconst val SESSION_RESULT_RECEIVER_INTENT = \"session_result_receiver_intent\"\nconst val SPLIT_LANGUAGE_TAG = \"config.\"\n\nfun Context.packageDownloadLocation() = File(cacheDir, FILE_SAVE_PATH).apply {\n    if (!exists()) mkdir()\n}\n"
  },
  {
    "path": "vending-app/src/main/kotlin/com/android/vending/installer/Install.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.android.vending.installer\n\nimport android.annotation.SuppressLint\nimport android.app.PendingIntent\nimport android.content.Context\nimport android.content.Intent\nimport android.content.pm.PackageInfo\nimport android.content.pm.PackageInstaller\nimport android.content.pm.PackageInstaller.SessionParams\nimport android.content.pm.PackageManager\nimport android.util.Log\nimport androidx.annotation.RequiresApi\nimport androidx.core.app.PendingIntentCompat\nimport androidx.core.content.pm.PackageInfoCompat\nimport com.google.android.finsky.splitinstallservice.PackageComponent\nimport kotlinx.coroutines.CompletableDeferred\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\nimport org.microg.vending.billing.core.HttpClient\nimport org.microg.vending.enterprise.CommitingSession\nimport org.microg.vending.enterprise.Downloading\nimport org.microg.vending.enterprise.InstallComplete\nimport org.microg.vending.enterprise.InstallError\nimport org.microg.vending.enterprise.InstallProgress\nimport java.io.File\nimport java.io.FileInputStream\nimport java.io.IOException\nimport java.io.OutputStream\n\n@RequiresApi(21)\ninternal suspend fun Context.installPackages(\n        packageName: String,\n        componentFiles: List<File>,\n        isUpdate: Boolean = false,\n        splitInstall: Boolean = false,\n) {\n    val notifyId = createNotificationId(packageName, emptyList())\n    installPackagesInternal(\n            packageName = packageName,\n            componentNames = componentFiles.map { it.name },\n            notifyId = notifyId,\n            isUpdate = isUpdate,\n            splitInstall = splitInstall,\n    ) {_, notifyId, fileName, to ->\n        val component = componentFiles.find { it.name == fileName }!!\n        FileInputStream(component).use { it.copyTo(to) }\n        component.delete()\n    }\n}\n\n@RequiresApi(21)\ninternal suspend fun Context.installPackagesFromNetwork(\n        packageName: String,\n        components: List<PackageComponent>,\n        httpClient: HttpClient = HttpClient(),\n        isUpdate: Boolean = false,\n        splitInstall: Boolean = false,\n        emitProgress: (notifyId: Int, InstallProgress) -> Unit = { _, _ -> }\n) {\n\n    val downloadProgress = mutableMapOf<PackageComponent, Long>()\n    //Generate a notifyId based on the package name and download module to prevent multiple notifications from appearing when the download content is the same\n    val notifyId = createNotificationId(packageName, components)\n    installPackagesInternal(\n            packageName = packageName,\n            componentNames = components.map { it.componentName },\n            notifyId = notifyId,\n            isUpdate = isUpdate,\n            splitInstall = splitInstall,\n            emitProgress = emitProgress,\n    ) {downloadedBytes, notifyId, fileName, to ->\n        val component = components.find { it.componentName == fileName }!!\n        Log.v(TAG, \"installing $fileName for $packageName from network apk size:\" + component.size + \" downloaded: \" + downloadedBytes)\n        if (downloadedBytes < component.size) {\n            // Emit progress for the first time as soon as possible, before any network interaction\n            emitProgress(notifyId, Downloading(\n                    bytesDownloaded = downloadProgress.values.sum(),\n                    bytesTotal = components.sumOf { it.size }\n            ))\n            httpClient.download(component.url, to, downloadedBytes = downloadedBytes) { progress ->\n                downloadProgress[component] = progress\n                emitProgress(notifyId, Downloading(\n                        bytesDownloaded = downloadProgress.values.sum(),\n                        bytesTotal = components.sumOf { it.size }\n                ))\n            }\n        }\n    }\n}\n\n@RequiresApi(21)\nprivate suspend fun Context.installPackagesInternal(\n        packageName: String,\n        componentNames: List<String>,\n        notifyId: Int,\n        isUpdate: Boolean = false,\n        splitInstall: Boolean = false,\n        emitProgress: (notifyId: Int, InstallProgress) -> Unit = { _, _ -> },\n        writeComponent: suspend (downloadedBytes: Long, notifyId: Int, componentName: String, to: OutputStream) -> Unit\n) {\n    Log.v(TAG, \"installPackages start $packageName\")\n    //Some systems are unable to retrieve information about installed apps, making the `installed` status unreliable.\n    val installed = packageManager.getInstalledPackages(0).any {\n        it.applicationInfo?.packageName == packageName\n    }\n    val packageInstaller = packageManager.packageInstaller\n    // Contrary to docs, MODE_INHERIT_EXISTING cannot be used if package is not yet installed.\n    val params = SessionParams(\n            if (!splitInstall && (!installed || isUpdate)) SessionParams.MODE_FULL_INSTALL\n            else SessionParams.MODE_INHERIT_EXISTING\n    )\n    params.setAppPackageName(packageName)\n    val key = computeUniqueKey(packageName, componentNames)\n    params.setAppLabel(key)\n    params.setInstallLocation(PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY)\n    try {\n        @SuppressLint(\"PrivateApi\") val method = SessionParams::class.java.getDeclaredMethod(\n                \"setDontKillApp\", Boolean::class.javaPrimitiveType\n        )\n        method.invoke(params, true)\n    } catch (e: Exception) {\n        Log.w(TAG, \"Error setting dontKillApp\", e)\n    }\n    var sessionId: Int\n    var session: PackageInstaller.Session? = null\n    try {\n        val sessionInfo = packageInstaller.mySessions.firstOrNull{ it.appLabel == key }\n        // This needs to be handled to prevent reusing sessions that are not in the active state,\n        // which could cause `openRead` to throw an error.\n        val existingSessionId = if (sessionInfo != null && sessionInfo.isActive) {\n            sessionInfo.sessionId\n        } else {\n            Log.w(TAG, \"installPackagesInternal my session fail\")\n            null\n        }\n        sessionId = existingSessionId ?: packageInstaller.createSession(params)\n        for (info in packageInstaller.mySessions) {\n            Log.d(TAG, \"id=${info.sessionId}, createdBy=${info.appLabel}, isActive=${info.isActive}\")\n        }\n        Log.d(TAG, \"installPackagesInternal sessionId: $sessionId\")\n        session = packageInstaller.openSession(sessionId)\n\n        for (component in componentNames) {\n            val currentSize: Long = try {\n                val inputStream = session!!.openRead(component)\n                val totalSize = withContext(Dispatchers.IO) {\n                    val buffer = ByteArray(4096)\n                    var total = 0L\n                    var bytesRead: Int\n                    while (inputStream.read(buffer).also { bytesRead = it } != -1) {\n                        total += bytesRead\n                    }\n                    inputStream.close()\n                    total\n                }\n                totalSize\n            } catch (e: IOException) {\n                Log.w(TAG, \"installPackagesInternal session open read error, ${e.message}\")\n                0L\n            } catch (e: SecurityException) {\n                Log.w(TAG, \"installPackagesInternal session open read error, ${e.message}\")\n                //Handling exceptions java.lang.SecurityException: openRead not allowed after commit\n                session!!.abandon()\n                sessionId = packageInstaller.createSession(params)\n                session = packageInstaller.openSession(sessionId)\n                0L\n            }\n\n            Log.d(TAG, \"installPackagesInternal component: $component currentSize:$currentSize\")\n            session!!.openWrite(component, currentSize, -1).use { outputStream ->\n                try {\n                    writeComponent(currentSize, notifyId, component, outputStream)\n                    session.fsync(outputStream)\n                } catch (e: Exception) {\n                    Log.w(TAG, \"Error writing component notifyId $notifyId\")\n                    emitProgress(notifyId, InstallError(\"Download Error\"))\n                    throw e\n                }\n            }\n        }\n        val deferred = CompletableDeferred<Unit>()\n        Log.w(TAG, \"installPackagesInternal pendingSessions size: ${SessionResultReceiver.pendingSessions.size}\")\n        SessionResultReceiver.pendingSessions[sessionId] = SessionResultReceiver.OnResult(\n                onSuccess = {\n                    deferred.complete(Unit)\n                    emitProgress(notifyId, InstallComplete)\n                },\n                onFailure = { message ->\n                    deferred.completeExceptionally(RuntimeException(message))\n                    emitProgress(notifyId, InstallError(message ?: \"UNKNOWN\"))\n                }\n        )\n        val intent = Intent(this, SessionResultReceiver::class.java)\n        intent.putExtra(SessionResultReceiver.KEY_NOTIFY_ID, notifyId)\n        intent.putExtra(SessionResultReceiver.KEY_PACKAGE_NAME, packageName)\n        val pendingIntent = PendingIntentCompat.getBroadcast(\n                this, sessionId, intent,\n                PendingIntent.FLAG_UPDATE_CURRENT, true\n        )!!\n\n        emitProgress(notifyId, CommitingSession)\n        session!!.commit(pendingIntent.intentSender)\n        // don't abandon if `finally` step is reached after this point\n        //session.close()\n\n        Log.d(TAG, \"installPackages session commit\")\n        return deferred.await()\n    } catch (e: Exception) {\n        Log.w(TAG, \"Error installing packages\", e)\n        emitProgress(notifyId, InstallError(e.message ?: \"UNKNOWN\"))\n        throw e\n    } finally {\n        // Close the session to release resources after error\n        session?.let {\n            Log.d(TAG, \"Error occurred, session cleanup may be required\")\n            it.close()\n        }\n    }\n}\n\nprivate fun Context.computeUniqueKey(packageName: String, componentNames: List<String>) : String {\n    try {\n        val packageInfo = packageManager.getPackageInfo(packageName, 0)\n        if (packageInfo != null) {\n            val versionCode = PackageInfoCompat.getLongVersionCode(\n                    packageManager.getPackageInfo(packageName, 0)\n            )\n            return componentNames.joinToString(separator = \"_\", prefix = \"${packageName}_${versionCode}\")\n        }\n    } catch (e: PackageManager.NameNotFoundException) {\n        Log.w(TAG, \"Package not found\", e)\n    }\n    return componentNames.joinToString(separator = \"_\", prefix = packageName)\n}\n\nprivate fun createNotificationId(packageName: String, components: List<PackageComponent>) : Int{\n    val hash = (packageName + components.joinToString(\"\") { it.componentName }).hashCode()\n    return hash and Int.MAX_VALUE\n}\n"
  },
  {
    "path": "vending-app/src/main/kotlin/com/android/vending/installer/InstallReceiver.kt",
    "content": "package com.android.vending.installer\n\nimport android.app.PendingIntent\nimport android.content.BroadcastReceiver\nimport android.content.Context\nimport android.content.Intent\nimport android.content.pm.PackageInstaller\nimport android.util.Log\nimport androidx.annotation.RequiresApi\n\n@RequiresApi(21)\nclass InstallReceiver : BroadcastReceiver() {\n    override fun onReceive(context: Context, intent: Intent) {\n        Log.d(TAG, \"onReceive: \" + intent.action)\n        val sessionId = intent.getIntExtra(SESSION_ID, -1)\n        Log.d(TAG, \"onReceive sessionId: $sessionId\")\n        if (intent.action == VENDING_INSTALL_ACTION) {\n            if (sessionId != -1) {\n                val packageInstaller = context.packageManager.packageInstaller\n                var session: PackageInstaller.Session? = null\n                session = packageInstaller.openSession(sessionId)\n                Log.d(TAG, \"onReceive: $session\")\n                val pendingIntent = intent.getParcelableExtra<PendingIntent>(SESSION_RESULT_RECEIVER_INTENT)\n                if (pendingIntent != null) {\n                    session.commit(pendingIntent.intentSender)\n                }\n            }\n        } else if (intent.action == VENDING_INSTALL_DELETE_ACTION) {\n            if (sessionId != -1) {\n                val packageInstaller = context.packageManager.packageInstaller\n                val session = packageInstaller.openSession(sessionId)\n                session.abandon()\n            }\n        }\n    }\n}"
  },
  {
    "path": "vending-app/src/main/kotlin/com/android/vending/installer/InstallService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.android.vending.installer\n\nimport android.app.Service\nimport android.content.Intent\nimport android.content.pm.ServiceInfo\nimport android.os.Binder\nimport android.os.IBinder\nimport android.util.Log\nimport androidx.annotation.RequiresApi\nimport androidx.core.app.ServiceCompat\nimport com.android.vending.buildRequestHeaders\nimport kotlinx.coroutines.runBlocking\nimport org.microg.vending.billing.core.AuthData\nimport org.microg.vending.billing.core.GooglePlayApi.Companion.URL_PURCHASE\nimport org.microg.vending.billing.core.HttpClient\nimport org.microg.vending.billing.proto.GoogleApiResponse\nimport org.microg.vending.delivery.requestDownloadUrls\nimport org.microg.vending.enterprise.AppState\nimport org.microg.vending.enterprise.CommitingSession\nimport org.microg.vending.enterprise.Downloading\nimport org.microg.vending.enterprise.EnterpriseApp\nimport org.microg.vending.enterprise.InstallError\nimport org.microg.vending.enterprise.Installed\nimport org.microg.vending.enterprise.Pending\nimport org.microg.vending.enterprise.proto.AppInstallPolicy\nimport org.microg.vending.ui.notifyInstallProgress\nimport java.util.concurrent.atomic.AtomicBoolean\nimport java.util.concurrent.atomic.AtomicInteger\nimport kotlin.random.Random\n\n@RequiresApi(21)\nclass InstallService : Service() {\n\n    private val binder = LocalBinder()\n\n    private val runningThreads = AtomicInteger(0)\n\n    /**\n     * Note: `isForeground` can be `false` even if the service is actually\n     * running in the foreground while installing a dependency, see below.\n     * State `false` means that the next notification must be designated as\n     * foreground notification.\n     */\n    private val isForeground = AtomicBoolean(false)\n\n    internal var auth: AuthData? = null\n    internal lateinit var apps: MutableMap<EnterpriseApp, AppState>\n\n    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {\n        return START_STICKY\n    }\n\n    fun installAsync(app: EnterpriseApp, isUpdate: Boolean) =\n        Thread {\n            runningThreads.incrementAndGet()\n            runBlocking { install(app, isUpdate) }\n            if (runningThreads.decrementAndGet() == 0) {\n                // Demote ourselves explicitly – notification cannot be removed otherwise\n                ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_DETACH)\n                stopSelf()\n            }\n        }.start()\n\n    suspend fun install(app: EnterpriseApp, isUpdate: Boolean) {\n\n        val previousState = apps[app]!!\n        apps[app] = Pending\n\n        val client = HttpClient()\n\n        // Purchase app (only needs to be done once, in theory – behaviour seems flaky)\n        // Ignore failures\n        runCatching {\n            if (app.policy != AppInstallPolicy.MANDATORY) {\n                val parameters = mapOf(\n                    \"ot\" to \"1\",\n                    \"doc\" to app.packageName,\n                    \"vc\" to app.versionCode.toString()\n                )\n                client.post(\n                    url = URL_PURCHASE,\n                    headers = buildRequestHeaders(\n                        auth!!.authToken,\n                        auth!!.gsfId.toLong(16)\n                    ),\n                    params = parameters,\n                    adapter = GoogleApiResponse.ADAPTER\n                )\n            }\n        }.onFailure { Log.i(TAG, \"couldn't purchase ${app.packageName}: ${it.message}\") }\n            .onSuccess { Log.d(TAG, \"purchased ${app.packageName} successfully\") }\n\n        // Install dependencies (different package name → needs to happen in a separate transaction)\n        if (android.os.Build.VERSION.SDK_INT >= 26) for (dependency in app.dependencies) {\n\n            val installedDetails = packageManager.getSharedLibraries(0)\n                .map { it.declaringPackage }\n                // multiple different library versions can be installed at the same time\n                .filter { it.packageName == dependency.packageName }\n                .maxByOrNull { it.versionCode }\n\n            val upToDate = installedDetails?.let {\n                it.versionCode >= dependency.versionCode!!\n            }\n\n            if (upToDate == true) {\n                Log.d(\n                    TAG, \"not installing ${dependency.packageName} as it is already up to date \" +\n                        \"(need version ${dependency.versionCode}, we have version ${installedDetails.versionCode})\")\n                continue\n            } else if (upToDate == false) {\n                Log.d(\n                    TAG, \"${dependency.packageName} is already installed, but an update is necessary \" +\n                        \"(need version ${dependency.versionCode}, we only have version ${installedDetails.versionCode})\")\n            }\n\n            val downloadUrls = runCatching {\n\n                client.requestDownloadUrls(\n                        this,\n                    dependency.packageName,\n                    dependency.versionCode!!.toLong(),\n                    auth!!\n                    // no delivery token available\n                ) }\n\n            if (downloadUrls.isFailure) {\n                Log.w(TAG, \"Failed to request download URLs for dependency ${dependency.packageName}: ${downloadUrls.exceptionOrNull()!!.message}\")\n                apps[app] = previousState\n                return\n            }\n\n            runCatching {\n\n                var lastNotification = 0L\n                // This method posts its first notification as soon as the install session is created (i.e. before network interaction)\n                installPackagesFromNetwork(\n                    packageName = dependency.packageName,\n                    components = downloadUrls.getOrThrow(),\n                    httpClient = client,\n                    isUpdate = false // static libraries may never be installed as updates\n                ) { session, progress ->\n\n                    // Android rate limits notification updates by some vague rule of \"not too many in less than one second\"\n                    if (progress !is Downloading || lastNotification + NOTIFICATION_INTERVAL < System.currentTimeMillis()) {\n                        notifyInstallProgress(app.displayName, session, progress, isDependency = true)?.let {\n                            /* We can tolerate if this notification is removed by the Android platform,\n                             * since we would post it again while download is running / discard it ourselves\n                             * after download has finished.\n                             * On the other hand, we couldn't tolerate Android system to prevent us from\n                             * cancelling this notification ourselves, since it has a different ID\n                             * (separate session) compared to the main download that happens after all\n                             * dependencies are loaded.\n                             * Therefore, do _not_ set `isForeground` to `true` here, so that another\n                             * notification takes this role soon.\n                             */\n                            if (!isForeground.get()) {\n                                ServiceCompat.startForeground(\n                                    this, session, it, ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC\n                                )\n                            }\n                        }\n                        lastNotification = System.currentTimeMillis()\n                    }\n                }\n            }.onFailure { exception ->\n                Log.w(TAG, \"Installation from network unsuccessful.\", exception)\n                notifyInstallProgress(app.displayName, sessionId = Random.nextInt(), progress = InstallError(\"unused\"), false)\n                apps[app] = previousState\n                return\n            }\n        }\n\n        // Get download links for requested package\n        val downloadUrls = runCatching {\n\n            client.requestDownloadUrls(\n                    this,\n                app.packageName,\n                app.versionCode!!.toLong(),\n                auth!!,\n                deliveryToken = app.deliveryToken\n            ) }\n\n        if (downloadUrls.isFailure) {\n            Log.w(TAG, \"Failed to request download URLs: ${downloadUrls.exceptionOrNull()!!.message}\")\n            apps[app] = previousState\n            return\n        }\n\n        runCatching {\n\n            var lastNotification = 0L\n            installPackagesFromNetwork(\n                packageName = app.packageName,\n                components = downloadUrls.getOrThrow(),\n                httpClient = client,\n                isUpdate = isUpdate\n            ) { session, progress ->\n\n\n                // Android rate limits notification updates by some vague rule of \"not too many in less than one second\"\n                if (progress !is Downloading || lastNotification + NOTIFICATION_INTERVAL < System.currentTimeMillis()) {\n                    notifyInstallProgress(app.displayName, session, progress)?.let {\n                        if (!isForeground.getAndSet(true)) {\n                            ServiceCompat.startForeground(\n                                this, session, it, ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC\n                            )\n                        }\n                    }\n                    lastNotification = System.currentTimeMillis()\n                }\n\n                if (progress is Downloading) apps[app] = progress\n                else if (progress is CommitingSession) apps[app] = Pending\n            }\n        }.onSuccess {\n            apps[app] = Installed\n        }.onFailure { exception ->\n            Log.w(TAG, \"Installation from network unsuccessful.\", exception)\n            apps[app] = previousState\n        }\n    }\n\n    inner class LocalBinder : Binder() {\n        fun getService(): InstallService = this@InstallService\n    }\n\n    override fun onBind(intent: Intent?): IBinder {\n        return binder\n    }\n\n    companion object {\n        const val TAG = \"GmsInstallService\"\n\n        const val NOTIFICATION_INTERVAL = 500\n    }\n\n}"
  },
  {
    "path": "vending-app/src/main/kotlin/com/android/vending/installer/SessionResultReceiver.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.android.vending.installer\n\nimport android.app.KeyguardManager\nimport android.app.PendingIntent\nimport android.content.BroadcastReceiver\nimport android.content.Context\nimport android.content.Intent\nimport android.content.pm.PackageInstaller\nimport android.util.Log\nimport androidx.annotation.RequiresApi\nimport androidx.core.app.NotificationManagerCompat\nimport androidx.core.app.PendingIntentCompat\nimport androidx.core.content.ContextCompat\nimport org.microg.vending.ui.notifyInstallPrompt\n\n@RequiresApi(21)\ninternal class SessionResultReceiver : BroadcastReceiver() {\n    override fun onReceive(context: Context, intent: Intent) {\n        val status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS, -1)\n        val sessionId = intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1)\n        val notifyId = intent.getIntExtra(KEY_NOTIFY_ID, -1)\n        Log.d(TAG, \"onReceive status: $status sessionId: $sessionId\")\n        try {\n            when (status) {\n                PackageInstaller.STATUS_SUCCESS -> {\n                    Log.d(TAG, \"SessionResultReceiver received a successful transaction\")\n                    if (sessionId != -1) {\n                        pendingSessions[sessionId]?.apply { onSuccess() }\n                        pendingSessions.remove(sessionId)\n                    }\n                }\n\n                PackageInstaller.STATUS_PENDING_USER_ACTION -> {\n                    val keyguardManager = context.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager\n                    if (keyguardManager.isKeyguardLocked) {\n                        handleKeyguardLocked(sessionId, notifyId, intent, context)\n                    } else {\n                        val extraIntent = intent.extras?.getParcelable(Intent.EXTRA_INTENT) as Intent?\n                        extraIntent?.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)\n                        extraIntent?.run { ContextCompat.startActivity(context, this, null) }\n                    }\n                }\n\n                else -> {\n                    val errorMessage = intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE)\n                    Log.w(TAG, \"SessionResultReceiver received a failed transaction result: $errorMessage\")\n                    if (sessionId != -1) {\n                        val onResult = pendingSessions[sessionId]\n                        if (onResult != null) {\n                            onResult.apply { onFailure(errorMessage) }\n                            pendingSessions.remove(sessionId)\n                        } else {\n                            //Prevent notifications from being removed after the process is killed\n                            Log.d(TAG, \"onReceive onResult is null\")\n                            val notificationManager = NotificationManagerCompat.from(context)\n                            notificationManager.cancel(notifyId)\n                        }\n                    }\n                }\n            }\n        } catch (e: Exception) {\n            Log.w(TAG, \"SessionResultReceiver encountered error while handling session result\", e)\n            if (sessionId != -1) {\n                pendingSessions[sessionId]?.apply { onFailure(e.message) }\n            }\n        }\n    }\n\n    private fun handleKeyguardLocked(sessionId: Int, notifyId: Int, intent: Intent, context: Context) {\n        val errorMsg = \"The screen is locked and waiting for the user to click the notification to install\"\n        Log.d(TAG, errorMsg)\n        if (sessionId != -1) {\n            val onResult = pendingSessions[sessionId]\n            if (onResult != null) {\n                onResult.apply { onFailure(errorMsg) }\n                pendingSessions.remove(sessionId)\n            } else {\n                Log.d(TAG, \"onReceive onResult is null\")\n                val notificationManager = NotificationManagerCompat.from(context)\n                notificationManager.cancel(notifyId)\n            }\n            val pendingIntent = PendingIntentCompat.getBroadcast(\n                    context, sessionId, intent,\n                    PendingIntent.FLAG_UPDATE_CURRENT, true\n            )\n            val packageName = intent.getStringExtra(KEY_PACKAGE_NAME)\n            Log.d(TAG, \"handleKeyguardLocked: $packageName notifyId:$notifyId\")\n            context.notifyInstallPrompt(packageName!!, notifyId, createPendingIntent(context, VENDING_INSTALL_ACTION, sessionId, pendingIntent)\n                    , createPendingIntent(context, VENDING_INSTALL_DELETE_ACTION, sessionId, null))\n        }\n    }\n\n    @RequiresApi(21)\n    private fun createPendingIntent(context: Context, action: String, sessionId: Int, pendingIntent: PendingIntent? = null): PendingIntent {\n        val installIntent = Intent(context.applicationContext, InstallReceiver::class.java).apply {\n            this.action = action\n            putExtra(SESSION_ID, sessionId)\n            if (pendingIntent != null) {\n                putExtra(SESSION_RESULT_RECEIVER_INTENT, pendingIntent)\n            }\n        }\n\n        val pendingInstallIntent = PendingIntentCompat.getBroadcast(\n                context.applicationContext,\n                0,\n                installIntent,\n                PendingIntent.FLAG_UPDATE_CURRENT, false\n        )\n        return pendingInstallIntent!!\n    }\n\n    data class OnResult(\n            val onSuccess: () -> Unit,\n            val onFailure: (message: String?) -> Unit\n    )\n\n    companion object {\n        val pendingSessions: MutableMap<Int, OnResult> = mutableMapOf()\n        const val KEY_NOTIFY_ID = \"notify_id\"\n        const val KEY_PACKAGE_NAME = \"package_name\"\n    }\n}"
  },
  {
    "path": "vending-app/src/main/kotlin/com/android/vending/installer/Uninstall.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.android.vending.installer\n\nimport android.app.PendingIntent\nimport android.content.Context\nimport android.content.Intent\nimport android.content.pm.PackageInstaller\nimport androidx.annotation.RequiresApi\nimport androidx.core.app.PendingIntentCompat\nimport kotlinx.coroutines.CompletableDeferred\n\n@RequiresApi(21)\nsuspend fun Context.uninstallPackage(packageName: String) {\n    val installer = packageManager.packageInstaller\n    val sessionParams = PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL)\n    val session = installer.createSession(sessionParams)\n\n    val deferred = CompletableDeferred<Unit>()\n\n    SessionResultReceiver.pendingSessions[session] = SessionResultReceiver.OnResult(\n        onSuccess = { deferred.complete(Unit) },\n        onFailure = { message -> deferred.completeExceptionally(RuntimeException(message)) }\n    )\n\n    installer.uninstall(\n        packageName, PendingIntentCompat.getBroadcast(\n            this, session, Intent(this, SessionResultReceiver::class.java).apply {\n                // for an unknown reason, the session ID is not added to the response automatically :(\n                putExtra(PackageInstaller.EXTRA_SESSION_ID, session)\n            },\n            PendingIntent.FLAG_UPDATE_CURRENT, true\n        )!!.intentSender\n    )\n\n    deferred.await()\n\n}\n"
  },
  {
    "path": "vending-app/src/main/kotlin/com/google/android/finsky/DeviceSyncInfo.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.finsky\n\nimport android.accounts.Account\nimport android.accounts.AccountManager\nimport android.annotation.SuppressLint\nimport android.app.ActivityManager\nimport android.app.admin.DevicePolicyManager\nimport android.content.Context\nimport android.content.pm.PackageInfo\nimport android.content.pm.PackageManager\nimport android.content.res.Configuration\nimport android.graphics.Point\nimport android.opengl.GLES10\nimport android.telephony.TelephonyManager\nimport android.text.TextUtils\nimport android.util.Base64\nimport android.util.DisplayMetrics\nimport android.util.Log\nimport android.os.Build.VERSION.SDK_INT\nimport android.view.WindowManager\nimport org.microg.gms.common.Constants\nimport org.microg.gms.profile.Build\nimport java.security.MessageDigest\nimport java.security.NoSuchAlgorithmException\nimport java.util.Arrays\nimport java.util.Objects\nimport java.util.Random\nimport java.util.TimeZone\nimport java.util.regex.Pattern\nimport java.util.stream.Collectors\nimport javax.microedition.khronos.egl.EGL10\nimport javax.microedition.khronos.egl.EGLConfig\nimport javax.microedition.khronos.egl.EGLContext\nimport javax.microedition.khronos.egl.EGLDisplay\nimport javax.microedition.khronos.egl.EGLSurface\nimport kotlin.math.abs\n\nobject DeviceSyncInfo {\n\n    private const val TAG = \"DeviceSyncInfo\"\n    private val glInfoList = ArrayList<FetchedGlStrings>()\n\n    fun buildSyncRequest(context: Context, androidId: Long, account: Account): SyncReqWrapper {\n        Log.d(TAG, \"cachePayload: \")\n        val builder = SyncReqWrapper.Builder()\n        val payloads = buildPayloads(context, androidId, account)\n        val syncRequests = builder.request.toMutableList()\n        for (payload in payloads) {\n            payload?.run { syncRequests.add(this) }\n        }\n        builder.request = syncRequests\n        return builder.build()\n    }\n\n    private fun buildPayloads(context: Context, androidId: Long, account: Account): Array<SyncRequest?> {\n        val fetchedGlStrings: ArrayList<FetchedGlStrings> = fetchGLInfo()\n        //---------------------------------------GPU info--------------------------------------------------------------------\n        val accountSha256 = accountSha256(androidId, account)\n        val accountAssValue = AccountAssValue.Builder().value_(accountSha256).build()\n        val accountAssociationPayload = AccountAssociationPayload.Builder().accountAss(accountAssValue).build()\n        val accountAssociationPayloadRequest = SyncRequest.Builder().accountAssociationPayload(accountAssociationPayload).build()\n        //--------------------------------------------------------------------------------------------------------------------\n        val carrierPropertiesPayloadRequest = createCarrierPropertiesPayloadRequest(context, androidId)\n        val deviceAccountsPayloadRequest = createDeviceAccountsPayloadRequest(context, androidId)\n        val deviceInfoCollect = createDeviceInfoCollect(context, fetchedGlStrings.toList())\n        val deviceCapabilitiesPayloadRequest = createDeviceCapabilitiesPayloadRequest(deviceInfoCollect)\n        val deviceInputPropertiesPayloadRequest = createDeviceInputPropertiesPayloadRequest(deviceInfoCollect)\n        val deviceModelPayloadRequest = createDeviceModelPayloadRequest()\n        val enterprisePropertiesPayloadRequest = createEnterprisePropertiesPayloadRequest(context)\n        val hardwareIdentifierPayloadRequest = createHardwareIdentifierPayloadRequest(context)\n        val hardwarePropertiesPayloadRequest = createHardwarePropertiesPayloadRequest(deviceInfoCollect)\n        val localePropertiesPayloadRequest = createLocalePropertiesPayloadRequest()\n        val playPartnerPropertiesPayloadRequest = createPlayPartnerPropertiesPayloadRequest()\n        val playPropertiesPayloadRequest = createPlayPropertiesPayload(context)\n        val screenPropertiesPayloadRequest = createScreenPropertiesPayloadRequest(deviceInfoCollect)\n        val systemPropertiesPayloadRequest = createSystemPropertiesPayloadRequest(deviceInfoCollect)\n        val gpuPayloadRequest = createGpuPayloadRequest(fetchedGlStrings.toList())\n        return arrayOf(\n            accountAssociationPayloadRequest, carrierPropertiesPayloadRequest, deviceAccountsPayloadRequest,\n            deviceCapabilitiesPayloadRequest, deviceInputPropertiesPayloadRequest, deviceModelPayloadRequest,\n            enterprisePropertiesPayloadRequest, hardwareIdentifierPayloadRequest, hardwarePropertiesPayloadRequest,\n            localePropertiesPayloadRequest, playPartnerPropertiesPayloadRequest, playPropertiesPayloadRequest,\n            screenPropertiesPayloadRequest, systemPropertiesPayloadRequest, gpuPayloadRequest\n        )\n    }\n\n    private fun createDeviceInfoCollect(context: Context, gpuInfoList: List<FetchedGlStrings>): DeviceInfoCollect {\n        val builder = DeviceInfoCollect.Builder()\n            .reqTouchScreen(0)\n            .reqKeyboardType(0)\n            .reqNavigation(0)\n            .deviceStablePoint(0)\n            .reqInputFeaturesV1(false)\n            .reqInputFeaturesV2(false)\n            .deviceStable(0)\n            .reqGlEsVersion(0)\n        val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager\n        val configurationInfo = activityManager.deviceConfigurationInfo\n        if (configurationInfo != null) {\n            if (configurationInfo.reqTouchScreen != Configuration.TOUCHSCREEN_UNDEFINED) {\n                builder.reqTouchScreen(configurationInfo.reqTouchScreen)\n            }\n            if (configurationInfo.reqKeyboardType != Configuration.KEYBOARD_UNDEFINED) {\n                builder.reqKeyboardType(configurationInfo.reqKeyboardType)\n            }\n            if (configurationInfo.reqNavigation != Configuration.NAVIGATION_UNDEFINED) {\n                builder.reqNavigation(configurationInfo.reqNavigation)\n            }\n            builder.reqGlEsVersion(configurationInfo.reqGlEsVersion)\n            builder.reqInputFeaturesV1((configurationInfo.reqInputFeatures and 1) == 1)\n                .reqInputFeaturesV2((configurationInfo.reqInputFeatures and 2) > 0)\n        }\n        val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager\n        val size = Point()\n        windowManager.defaultDisplay.getSize(size)\n        builder.displayX(size.x).displayY(size.y)\n        if (SDK_INT >= 24) {\n            builder.deviceStable(DisplayMetrics.DENSITY_DEVICE_STABLE)\n                .deviceStablePoint(calculatePoint(size, DisplayMetrics.DENSITY_DEVICE_STABLE))\n        }\n        val configuration = context.resources.configuration\n        builder.screenLayout(configuration.screenLayout)\n            .smallestScreenWidthDp(configuration.smallestScreenWidthDp)\n            .systemSharedLibraryNames(listOf(*Objects.requireNonNull(context.packageManager.systemSharedLibraryNames)))\n            .locales(listOf(*context.assets.locales))\n        if (SDK_INT >= 24) {\n            builder.glExtensions(gpuInfoList.stream()\n                .flatMap { fetchedGlStrings: FetchedGlStrings -> fetchedGlStrings.glExtensions?.let { Arrays.stream(it.toTypedArray()) } }\n                .collect(Collectors.toList()))\n                .isLowRamDevice(activityManager.isLowRamDevice)\n        }\n        val memoryInfo = ActivityManager.MemoryInfo()\n        activityManager.getMemoryInfo(memoryInfo)\n        builder.totalMem(memoryInfo.totalMem)\n            .availableProcessors(Runtime.getRuntime().availableProcessors())\n        val systemAvailableFeatures = context.packageManager.systemAvailableFeatures\n        for (featureInfo in systemAvailableFeatures) {\n            if (!TextUtils.isEmpty(featureInfo.name)) {\n                var featureInfoProto = FeatureInfoProto.Builder().build()\n                if (SDK_INT >= 24) {\n                    featureInfoProto = FeatureInfoProto.Builder().name(featureInfo.name).version(featureInfo.version).build()\n                }\n                builder.featureInfoList = builder.featureInfoList.toMutableList().apply {\n                    add(featureInfoProto)\n                }\n                builder.featureNames = builder.featureNames.toMutableList().apply {\n                    add(featureInfoProto.name!!)\n                }\n            }\n        }\n        if (SDK_INT >= 21) {\n            builder.supportedAbi(listOf(*Build.SUPPORTED_ABIS))\n        }\n        var prop = getSystemProperty(\"ro.oem.key1\", \"\")\n        if (!TextUtils.isEmpty(prop)) {\n            builder.oemKey(prop)\n        }\n        builder.buildCodeName(Build.VERSION.CODENAME)\n        prop = getSystemProperty(\"ro.build.version.preview_sdk_fingerprint\", \"\")\n        if (!TextUtils.isEmpty(prop)) {\n            builder.previewSdkFingerprint(prop)\n        }\n        return builder.build()\n    }\n\n    private fun createGpuPayloadRequest(glStringsList: List<FetchedGlStrings>): SyncRequest? {\n        var gpuPayloadRequest: SyncRequest? = null\n        try {\n            var infos = glStringsList\n            var gpuPayloads = emptyList<GpuPayload>()\n            if (SDK_INT >= 24) {\n                infos = infos.stream()\n                    .filter { fetchedGlStrings: FetchedGlStrings ->\n                        fetchedGlStrings.glRenderer!!.isNotEmpty() || fetchedGlStrings.glVendor!!.isNotEmpty() || fetchedGlStrings.glVersion!!.isNotEmpty()\n                    }.collect(Collectors.toList())\n                val maxVersion = infos.stream()\n                    .max(Comparator.comparingInt { fetchedGlStrings: FetchedGlStrings ->\n                        fetchedGlStrings.contextClientVersion\n                    }).map { obj: FetchedGlStrings ->\n                        obj.contextClientVersion\n                    }\n                if (maxVersion.isPresent) {\n                    infos = infos.stream()\n                        .filter { fetchedGlStrings: FetchedGlStrings ->\n                            fetchedGlStrings.contextClientVersion == maxVersion.get()\n                        }.collect(Collectors.toList())\n                }\n                gpuPayloads = infos.stream().map { fetchedGlStrings: FetchedGlStrings ->\n                    val gpuInfoWrapper = GpuInfoWrapper.Builder()\n                    if (!TextUtils.isEmpty(fetchedGlStrings.glRenderer)) gpuInfoWrapper.glRenderer(fetchedGlStrings.glRenderer)\n                    if (!TextUtils.isEmpty(fetchedGlStrings.glVendor)) gpuInfoWrapper.glVendor(fetchedGlStrings.glVendor)\n                    if (!TextUtils.isEmpty(fetchedGlStrings.glVersion)) gpuInfoWrapper.glVersion(fetchedGlStrings.glVersion)\n                    GpuPayload.Builder().gpuInfo(gpuInfoWrapper.build()).build()\n                }.distinct().collect(Collectors.toList())\n            }\n            gpuPayloadRequest = SyncRequest.Builder().gpuPayload(if (gpuPayloads.isEmpty()) GpuPayload.Builder().build() else gpuPayloads[0]).build()\n        } catch (e: Exception) {\n            Log.w(TAG, \"createGpuPayloadRequest error\", e)\n        }\n        return gpuPayloadRequest\n    }\n\n    private fun createHardwarePropertiesPayloadRequest(deviceInfoCollect: DeviceInfoCollect): SyncRequest {\n        val hardwarePropertiesPayload = HardwarePropertiesPayload.Builder()\n            .isLowRamDevice(deviceInfoCollect.isLowRamDevice)\n            .totalMem(deviceInfoCollect.totalMem)\n            .availableProcessors(deviceInfoCollect.availableProcessors)\n            .supportedAbi(deviceInfoCollect.supportedAbi)\n            .build()\n        return SyncRequest.Builder().hardwarePropertiesPayload(hardwarePropertiesPayload).build()\n    }\n\n    @SuppressLint(\"DefaultLocale\")\n    private fun createLocalePropertiesPayloadRequest(): SyncRequest {\n        val timeZone = TimeZone.getDefault()\n        val gmtFormat = String.format(\n            \"GMT%+d:%02d\",\n            timeZone.rawOffset / (60 * 60 * 1000),\n            abs(timeZone.rawOffset / (60 * 1000) % 60)\n        )\n        val localePropertiesPayload = LocalePropertiesPayload.Builder()\n            .locale(gmtFormat)\n            .build()\n        return SyncRequest.Builder().localePropertiesPayload(localePropertiesPayload).build()\n    }\n\n    private fun createPlayPartnerPropertiesPayloadRequest(): SyncRequest {\n        val playPartnerPropertiesPayload = PlayPartnerPropertiesPayload.Builder()\n            .marketId(\"am-google\")\n            .partnerIdMs(\"play-ms-android-google\")\n            .partnerIdAd(\"play-ad-ms-android-google\")\n            .build()\n        return SyncRequest.Builder().playPartnerPropertiesPayload(playPartnerPropertiesPayload).build()\n    }\n\n    private fun createPlayPropertiesPayload(context: Context): SyncRequest {\n        var version = 0\n        try {\n            version = context.packageManager.getPackageInfo(Constants.VENDING_PACKAGE_NAME, 0).versionCode\n        } catch (exception: PackageManager.NameNotFoundException) {\n            Log.w(TAG, \"[DAS] Could not find our package\", exception)\n        }\n        val playPropertiesPayload = PlayPropertiesPayload.Builder().playVersion(version).build()\n        return SyncRequest.Builder().playPropertiesPayload(playPropertiesPayload).build()\n    }\n\n    private fun createScreenPropertiesPayloadRequest(deviceInfoCollect: DeviceInfoCollect): SyncRequest {\n        val screenPropertiesPayload = ScreenPropertiesPayload.Builder()\n            .reqTouchScreen(deviceInfoCollect.reqTouchScreen)\n            .displayX(deviceInfoCollect.displayX)\n            .displayY(deviceInfoCollect.displayY)\n            .deviceStablePoint(deviceInfoCollect.deviceStablePoint)\n            .deviceStable(deviceInfoCollect.deviceStable)\n            .build()\n        return SyncRequest.Builder().screenPropertiesPayload(screenPropertiesPayload).build()\n    }\n\n    private fun createSystemPropertiesPayloadRequest(deviceInfoCollect: DeviceInfoCollect): SyncRequest {\n        val systemPropertiesPayload = SystemPropertiesPayload.Builder()\n            .fingerprint(Build.FINGERPRINT)\n            .sdkInt(Build.VERSION.SDK_INT.toLong())\n            .previewSdkFingerprint(deviceInfoCollect.previewSdkFingerprint)\n            .buildCodeName(deviceInfoCollect.buildCodeName)\n            .oemKey(deviceInfoCollect.oemKey)\n            .reqGlEsVersion(deviceInfoCollect.reqGlEsVersion)\n            .build()\n        return SyncRequest.Builder().systemPropertiesPayload(systemPropertiesPayload).build()\n    }\n\n    private fun createHardwareIdentifierPayloadRequest(context: Context): SyncRequest? {\n        var hardwareIdentifierPayloadRequest: SyncRequest? = null\n        try {\n            val builder = HardwareIdentifierPayload.Builder()\n            val randomIMEI = generateRandomIMEI()\n            val imeId: Long = if (TextUtils.isEmpty(randomIMEI) || !Pattern.compile(\"^[0-9]{15}$\").matcher(randomIMEI).matches())\n                0L else randomIMEI.toLong(10) or 0x1000000000000000L\n            builder.imeId(imeId)\n            hardwareIdentifierPayloadRequest = SyncRequest.Builder().hardwareIdentifierPayload(builder.build()).build()\n        } catch (e: Exception) {\n            Log.w(TAG, \"createHardwareIdentifierPayloadRequest error\", e)\n        }\n        return hardwareIdentifierPayloadRequest\n    }\n\n    private fun createEnterprisePropertiesPayloadRequest(context: Context): SyncRequest? {\n        var enterprisePropertiesPayloadRequest: SyncRequest? = null\n        try {\n            val enterprisePropertiesPayload = EnterprisePropertiesPayload.Builder()\n            val devicePolicyManager = context.getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager\n            val activeAdmins = devicePolicyManager.activeAdmins\n            if (activeAdmins != null) {\n                for (componentName in activeAdmins) {\n                    val packageName = componentName.packageName\n                    val packageInfo: PackageInfo? = context.packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES)\n                    val isDeviceOwner = devicePolicyManager.isDeviceOwnerApp(packageName)\n                    var isProfileOwner = false\n                    if (SDK_INT >= 21) {\n                        isProfileOwner = devicePolicyManager.isProfileOwnerApp(packageName)\n                    }\n                    val policyType =\n                        if (isDeviceOwner) MangedScope.MANAGED_DEVICES else if (isProfileOwner) MangedScope.MANAGED_PROFILES else MangedScope.LEGACY_DEVICE_ADMINS\n                    val profileInfo = ProfileInfo.Builder()\n                        .pkgName(componentName.packageName)\n                        .policyType(policyType)\n                        .pkgSHA1(calculateSHA(packageInfo!!.signatures!![0].toByteArray(), \"SHA1\"))\n                        .pkgSHA256(calculateSHA(packageInfo.signatures!![0].toByteArray(), \"SHA256\")).build()\n                    if (isProfileOwner) {\n                        enterprisePropertiesPayload.profileOwner(profileInfo)\n                    }\n                    enterprisePropertiesPayload.default = enterprisePropertiesPayload.default.toMutableList()\n                        .apply { add(profileInfo) }\n                }\n            }\n            enterprisePropertiesPayloadRequest = SyncRequest.Builder().enterprisePropertiesPayload(enterprisePropertiesPayload.build()).build()\n        } catch (e: Exception) {\n            Log.w(TAG, \"createEnterprisePropertiesPayloadRequest error\", e)\n        }\n        return enterprisePropertiesPayloadRequest\n    }\n\n    private fun createDeviceInputPropertiesPayloadRequest(deviceInfoCollect: DeviceInfoCollect): SyncRequest {\n        val builder = DeviceInputPropertiesPayload.Builder()\n            .reqInputFeatures(deviceInfoCollect.reqInputFeaturesV1)\n            .reqKeyboardType(deviceInfoCollect.reqKeyboardType)\n            .reqNavigation(deviceInfoCollect.reqNavigation)\n        return SyncRequest.Builder().deviceInputPropertiesPayload(builder.build()).build()\n    }\n\n    private fun createDeviceModelPayloadRequest(): SyncRequest {\n        val builder = DeviceModelPayload.Builder()\n            .manufacturer(Build.MANUFACTURER)\n            .model(Build.MODEL)\n            .device(Build.DEVICE)\n            .product(Build.PRODUCT)\n            .brand(Build.BRAND)\n        return SyncRequest.Builder().deviceModelPayload(builder.build()).build()\n    }\n\n    private fun createDeviceCapabilitiesPayloadRequest(deviceInfoCollect: DeviceInfoCollect): SyncRequest {\n        val builder = DeviceCapabilitiesPayload.Builder()\n        builder.glExtensions(deviceInfoCollect.glExtensions)\n        val featureInfoList = builder.featureInfo.toMutableList()\n        for (featureInfoProto in deviceInfoCollect.featureInfoList) {\n            featureInfoList.add(\n                FeatureInfoProto.Builder()\n                    .name(featureInfoProto.name)\n                    .version(featureInfoProto.version)\n                    .build()\n            )\n        }\n        builder.featureInfo = featureInfoList\n        builder.systemSharedLibraryNames(deviceInfoCollect.systemSharedLibraryNames)\n            .locales(deviceInfoCollect.locales)\n            .unknownFlag(false)\n        return SyncRequest.Builder().deviceCapabilitiesPayload(builder.build()).build()\n    }\n\n    private fun createDeviceAccountsPayloadRequest(context: Context, androidId: Long): SyncRequest? {\n        var deviceAccountsPayloadRequest: SyncRequest? = null\n        try {\n            val accountManager = context.getSystemService(Context.ACCOUNT_SERVICE) as AccountManager\n            val accounts = accountManager.accounts\n            val builder = DeviceAccountsPayload.Builder()\n            val accountAssValues = builder.accountAss.toMutableList()\n            for (account in accounts) {\n                accountAssValues.add(AccountAssValue.Builder().value_(accountSha256(androidId, account)).build())\n            }\n            builder.accountAss = accountAssValues\n            deviceAccountsPayloadRequest = SyncRequest.Builder().deviceAccountsPayload(builder.build()).build()\n        } catch (e: Exception) {\n            Log.w(TAG, \"createDeviceAccountsPayloadRequest error\", e)\n        }\n        return deviceAccountsPayloadRequest\n    }\n\n    @SuppressLint(\"HardwareIds\")\n    private fun createCarrierPropertiesPayloadRequest(context: Context, androidId: Long): SyncRequest? {\n        var carrierPropertiesPayloadRequest: SyncRequest? = null\n        try {\n            val telephonyManager = context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager\n            var simCardId = 0\n            if (SDK_INT >= 28) {\n                simCardId = telephonyManager.simCarrierId\n            }\n            var carrierIdFromSimMccMnc = 0\n            if (SDK_INT >= 29) {\n                carrierIdFromSimMccMnc = telephonyManager.carrierIdFromSimMccMnc\n            }\n            val telephonyInfo = TelephonyInfo.Builder()\n                .subscriberId(androidId)\n                .operatorName(telephonyManager.simOperatorName)\n                .simCardId(simCardId)\n                .carrierIdFromSimMccMnc(carrierIdFromSimMccMnc)\n                .build()\n            val telephonyStateWrapper = TelephonyStateWrapper.Builder().telephonyInfo(telephonyInfo).build()\n            val carrierPropertiesPayload =\n                CarrierPropertiesPayload.Builder().telephonyStateValue(telephonyStateWrapper).simOperator(telephonyManager.simOperator).build()\n            carrierPropertiesPayloadRequest = SyncRequest.Builder().carrierPropertiesPayload(carrierPropertiesPayload).build()\n        } catch (securityException: SecurityException) {\n            Log.w(TAG, \"SecurityException when reading IMSI.\", securityException)\n        } catch (stateException: IllegalStateException) {\n            Log.w(TAG, \"IllegalStateException when reading IMSI. This is a known SDK 31 Samsung bug.\", stateException)\n        } catch (e: Exception) {\n            Log.w(TAG, \"createCarrierPropertiesPayloadRequest error\", e)\n        }\n        return carrierPropertiesPayloadRequest\n    }\n\n    private fun accountSha256(androidId: Long, account: Account): String? {\n        return try {\n            val androidIdAcc = (androidId.toString() + \"-\" + account.name).toByteArray()\n            val messageDigest0 = MessageDigest.getInstance(\"SHA256\")\n            messageDigest0.update(androidIdAcc, 0, androidIdAcc.size)\n            Base64.encodeToString(messageDigest0.digest(), 11)\n        } catch (ignored: Exception) {\n            null\n        }\n    }\n\n    private fun generateRandomIMEI(): String {\n        val random = Random()\n        val imeiBuilder = StringBuilder()\n        for (i in 0..13) {\n            val digit = random.nextInt(10)\n            imeiBuilder.append(digit)\n        }\n        val imei = imeiBuilder.toString()\n        val checkDigit = calculateCheckDigit(imei)\n        imeiBuilder.append(checkDigit)\n        return imeiBuilder.toString()\n    }\n\n    private fun calculateCheckDigit(imei: String): Int {\n        var sum = 0\n        for (i in imei.indices) {\n            var digit = Character.getNumericValue(imei[i])\n            if (i % 2 == 1) {\n                digit *= 2\n            }\n            if (digit > 9) {\n                digit -= 9\n            }\n            sum += digit\n        }\n        return (10 - (sum % 10)) % 10\n    }\n\n    private fun calculateSHA(data: ByteArray, algorithm: String?): String? {\n        val messageDigest0: MessageDigest\n        try {\n            messageDigest0 = algorithm?.let { MessageDigest.getInstance(it) }!!\n        } catch (noSuchAlgorithmException0: NoSuchAlgorithmException) {\n            Log.w(TAG, \"[DC] No support for %s?\", noSuchAlgorithmException0)\n            return null\n        }\n        messageDigest0.update(data, 0, data.size)\n        return Base64.encodeToString(messageDigest0.digest(), 11)\n    }\n\n    private fun fetchGLInfo(): ArrayList<FetchedGlStrings> {\n        if (glInfoList.isNotEmpty()) return glInfoList\n        try {\n            val eGL100 = EGLContext.getEGL() as? EGL10\n            val result = ArrayList<FetchedGlStrings>()\n            val egl10Instance = eGL100?.let { EGL10Wrapper(it) }\n            val eglDisplay = eGL100!!.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY)\n            eGL100.eglInitialize(eglDisplay, IntArray(2))\n            val ints = IntArray(1)\n            val configCount = if (eGL100.eglGetConfigs(eglDisplay, null, 0, ints)) ints[0] else 0\n            val arrEglConfig = arrayOfNulls<EGLConfig>(configCount)\n            val eglConfigs = if (eGL100.eglGetConfigs(eglDisplay, arrEglConfig, configCount, IntArray(1))) arrEglConfig else null\n            val arrV1 = intArrayOf(0x3057, 1, 0x3056, 1, 0x3038)\n            for (v1 in 0 until configCount) {\n                if (egl10Instance?.eglGetConfigAttrib(eglDisplay, eglConfigs?.get(v1), 0x3027) != 0x3050\n                    && (egl10Instance?.eglGetConfigAttrib(eglDisplay, eglConfigs?.get(v1), 0x3033)?.and(1)) != 0\n                ) {\n                    val v2 = egl10Instance?.eglGetConfigAttrib(eglDisplay, eglConfigs?.get(v1), 0x3040)\n                    if ((v2?.and(1)) != 0) {\n                        egl10Instance?.let { wrapper -> buildGLStrings(wrapper, eglDisplay, eglConfigs?.get(v1), arrV1, null)?.let { result.add(it) } }\n                    }\n                    if ((v2?.and(4)) != 0) {\n                        egl10Instance?.let { wrapper ->\n                            buildGLStrings(\n                                wrapper,\n                                eglDisplay,\n                                eglConfigs?.get(v1),\n                                arrV1,\n                                intArrayOf(0x3098, 2, 0x3038)\n                            )?.let { result.add(it) }\n                        }\n                    }\n                }\n            }\n            egl10Instance?.instance?.eglTerminate(eglDisplay)\n            return result.also { glInfoList.addAll(it) }\n        } catch (e: Exception) {\n            Log.d(TAG, \"fetchGLInfo: error\", e)\n        }\n        return ArrayList()\n    }\n\n    private fun buildGLStrings(egl10Tools: EGL10Wrapper, eglDisplay: EGLDisplay, eglConfig: EGLConfig?, arrV: IntArray, arrV1: IntArray?): FetchedGlStrings? {\n        val eglContext = egl10Tools.instance.eglCreateContext(eglDisplay, eglConfig, EGL10.EGL_NO_CONTEXT, arrV1)\n        if (eglContext != EGL10.EGL_NO_CONTEXT) {\n            val eglSurface = egl10Tools.instance.eglCreatePbufferSurface(eglDisplay, eglConfig, arrV)\n            if (eglSurface == EGL10.EGL_NO_SURFACE) {\n                egl10Tools.eglDestroyContext(eglDisplay, eglContext)\n                return null\n            }\n            egl10Tools.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)\n            val result = FetchedGlStrings(0, null, null, null, null)\n            val glExtensions = GLES10.glGetString(GLES10.GL_EXTENSIONS)\n            if (!TextUtils.isEmpty(glExtensions)) {\n                result.glExtensions = glExtensions.split(\" \".toRegex()).dropLastWhile { it.isEmpty() }\n            }\n            result.glRenderer = GLES10.glGetString(GLES10.GL_RENDERER)\n            result.glVendor = GLES10.glGetString(GLES10.GL_VENDOR)\n            result.glVersion = GLES10.glGetString(GLES10.GL_VERSION)\n            if (result.glExtensions != null) {\n                egl10Tools.eglMakeCurrent(eglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT)\n                egl10Tools.instance.eglDestroySurface(eglDisplay, eglSurface)\n                egl10Tools.eglDestroyContext(eglDisplay, eglContext)\n                return result\n            }\n            throw IllegalStateException(\"Missing required properties <glExtensions>\")\n        }\n        return null\n    }\n\n    private fun getSystemProperty(key: String?, defaultValue: String?): String? {\n        var value = defaultValue\n        try {\n            @SuppressLint(\"PrivateApi\") val systemPropertiesClass = Class.forName(\"android.os.SystemProperties\")\n            val getMethod = systemPropertiesClass.getMethod(\"get\", String::class.java, String::class.java)\n            value = getMethod.invoke(null, key, defaultValue) as String\n        } catch (e: Exception) {\n            Log.w(TAG, \"Unable to retrieve system property\", e)\n        }\n        return value\n    }\n\n    private fun calculatePoint(point: Point, v: Int): Int {\n        val f = point.x.toFloat()\n        val v1 = ((point.y.toFloat()) * (160.0f / (v.toFloat()))).toInt()\n        if (v1 < 470) {\n            return 17\n        }\n        val v2 = (f * (160.0f / (v.toFloat()))).toInt()\n        if (v1 >= 960 && v2 >= 720) {\n            return if (v1 * 3 / 5 < v2 - 1) 20 else 4\n        }\n        val v3 = if (v1 < 640 || v2 < 480) 2 else 3\n        return if (v1 * 3 / 5 < v2 - 1) v3 or 16 else v3\n    }\n\n    internal class EGL10Wrapper(val instance: EGL10) {\n        fun eglGetConfigAttrib(eglDisplay: EGLDisplay?, eglConfig: EGLConfig?, v: Int): Int {\n            val value = IntArray(1)\n            instance.eglGetConfigAttrib(eglDisplay, eglConfig, v, value)\n            return value[0]\n        }\n\n        fun eglDestroyContext(eglDisplay: EGLDisplay?, eglContext: EGLContext?) {\n            instance.eglDestroyContext(eglDisplay, eglContext)\n        }\n\n        fun eglMakeCurrent(eglDisplay: EGLDisplay?, draw: EGLSurface?, read: EGLSurface?, eglContext: EGLContext?) {\n            instance.eglMakeCurrent(eglDisplay, draw, read, eglContext)\n        }\n    }\n\n    internal class FetchedGlStrings(\n        var contextClientVersion: Int,\n        var glExtensions: List<String>?,\n        var glRenderer: String?,\n        var glVendor: String?,\n        var glVersion: String?\n    )\n}"
  },
  {
    "path": "vending-app/src/main/kotlin/com/google/android/finsky/DownloadManager.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.finsky\n\nimport android.annotation.SuppressLint\nimport android.app.NotificationChannel\nimport android.app.NotificationManager\nimport android.app.PendingIntent\nimport android.content.BroadcastReceiver\nimport android.content.Context\nimport android.content.Intent\nimport android.content.IntentFilter\nimport android.content.pm.PackageManager\nimport android.graphics.Bitmap\nimport android.graphics.Canvas\nimport android.graphics.drawable.BitmapDrawable\nimport android.net.Uri\nimport android.os.Build.VERSION.SDK_INT\nimport android.util.Log\nimport androidx.core.app.NotificationCompat\nimport androidx.core.app.NotificationCompat.Action\nimport androidx.core.app.NotificationManagerCompat\nimport androidx.core.app.PendingIntentCompat\nimport com.android.vending.R\nimport com.google.android.finsky.assetmoduleservice.DownloadData\nimport com.google.android.finsky.assetmoduleservice.getChunkFile\nimport com.google.android.play.core.assetpacks.model.AssetPackStatus\nimport java.io.File\nimport java.io.FileOutputStream\nimport java.io.IOException\nimport java.net.HttpURLConnection\nimport java.net.URL\nimport java.util.concurrent.ConcurrentHashMap\nimport java.util.concurrent.Future\nimport java.util.concurrent.LinkedBlockingQueue\nimport java.util.concurrent.ThreadPoolExecutor\nimport java.util.concurrent.TimeUnit\n\nprivate const val corePoolSize = 0\nprivate const val maximumPoolSize = 1\nprivate const val keepAliveTime = 30L\n\nprivate const val CHANNEL_ID = \"progress_notification_channel\"\nprivate const val NOTIFICATION_ID = 1\nprivate const val CANCEL_ACTION = \"CANCEL_DOWNLOAD\"\n\nprivate const val TAG = \"DownloadManager\"\n\nclass DownloadManager(private val context: Context) {\n\n    private val notifyBuilderMap = ConcurrentHashMap<String, NotificationCompat.Builder>()\n    private val downloadingRecord = ConcurrentHashMap<String, Future<*>>()\n\n    @Volatile\n    private var shouldStops = false\n\n    private val cancelReceiver = object : BroadcastReceiver() {\n        override fun onReceive(context: Context, intent: Intent) {\n            val moduleName = intent.getStringExtra(KEY_MODULE_NAME)\n            if (moduleName != null) {\n                cancelDownload(moduleName)\n            }\n        }\n    }\n\n    init {\n        createNotificationChannel()\n        val filter = IntentFilter(CANCEL_ACTION)\n        context.registerReceiver(cancelReceiver, filter)\n    }\n\n    private fun createNotificationChannel() {\n        if (SDK_INT >= 26) {\n            val channel = NotificationChannel(CHANNEL_ID, \"Download Progress\", NotificationManager.IMPORTANCE_LOW)\n            val notificationManager: NotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager\n            notificationManager.createNotificationChannel(channel)\n        }\n    }\n\n    private val executor by lazy {\n        ThreadPoolExecutor(\n            corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, LinkedBlockingQueue()\n        ) { r -> Thread(r).apply { name = \"DownloadThread\" } }\n    }\n\n    private fun initNotification(moduleName: String, packageName: String) {\n        val cancelIntent = Intent(CANCEL_ACTION).apply {\n            putExtra(KEY_MODULE_NAME, moduleName)\n        }\n        val cancelPendingIntent = PendingIntentCompat.getBroadcast(\n            context, 0, cancelIntent, PendingIntent.FLAG_UPDATE_CURRENT, false\n        )\n        val packageManager: PackageManager = context.packageManager\n        val applicationInfo = packageManager.getApplicationInfo(packageName, 0)\n        val appName = packageManager.getApplicationLabel(applicationInfo).toString()\n        val appIcon = packageManager.getApplicationIcon(applicationInfo)\n        val largeIconBitmap = if (appIcon is BitmapDrawable) {\n            appIcon.bitmap\n        } else {\n            Bitmap.createBitmap(appIcon.intrinsicWidth, appIcon.intrinsicHeight, Bitmap.Config.ARGB_8888).apply {\n                val canvas = Canvas(this)\n                appIcon.setBounds(0, 0, canvas.width, canvas.height)\n                appIcon.draw(canvas)\n            }\n        }\n\n        val notifyBuilder = NotificationCompat.Builder(context, CHANNEL_ID)\n            .setSmallIcon(R.drawable.ic_notification)\n            .setContentTitle(context.getString(R.string.download_notification_attachment_file, appName))\n            .setContentText(context.getString(R.string.download_notification_tips))\n            .setLargeIcon(largeIconBitmap)\n            .setProgress(100, 0, false)\n            .setPriority(NotificationCompat.PRIORITY_HIGH)\n            .setOngoing(true)\n            .setOnlyAlertOnce(true)\n            .addAction(Action.Builder(R.drawable.ic_cancel, context.getString(android.R.string.cancel), cancelPendingIntent).setSemanticAction(Action.SEMANTIC_ACTION_DELETE).build())\n\n        notifyBuilderMap[moduleName] = notifyBuilder\n\n        NotificationManagerCompat.from(context).notify(NOTIFICATION_ID, notifyBuilder.build())\n    }\n\n    private fun updateProgress(moduleName: String, progress: Int) {\n        val notifyBuilder = notifyBuilderMap[moduleName] ?: return\n\n        notifyBuilder.setProgress(100, progress, false)\n        NotificationManagerCompat.from(context).notify(NOTIFICATION_ID, notifyBuilder.build())\n    }\n\n    fun shouldStop(shouldStop: Boolean) {\n        shouldStops = shouldStop\n    }\n\n    fun prepareDownload(downloadData: DownloadData, moduleName: String) {\n        Log.d(TAG, \"prepareDownload: ${downloadData.packageName}\")\n        initNotification(moduleName, downloadData.packageName)\n        val future = executor.submit {\n            val packData = downloadData.getModuleData(moduleName)\n            downloadData.updateDownloadStatus(moduleName, AssetPackStatus.DOWNLOADING)\n            for (chunkData in packData.chunks) {\n                val moduleName: String = chunkData.moduleName\n                val chunkSourceUri: String = chunkData.chunkSourceUri ?: continue\n                val destination = chunkData.getChunkFile(context)\n                startDownload(moduleName, chunkSourceUri, destination, downloadData)\n                sendBroadcastForExistingFile(context, downloadData, moduleName, chunkData, destination)\n            }\n            updateProgress(moduleName, 100)\n            notifyBuilderMap[moduleName]?.setOngoing(false)\n            NotificationManagerCompat.from(context).cancel(NOTIFICATION_ID)\n        }\n        downloadingRecord[moduleName] = future\n    }\n\n    fun cancelDownload(moduleName: String) {\n        Log.d(TAG, \"Download for module $moduleName has been canceled.\")\n        downloadingRecord[moduleName]?.cancel(true)\n        shouldStops = true\n        notifyBuilderMap[moduleName]?.setOngoing(false)\n        NotificationManagerCompat.from(context).cancel(NOTIFICATION_ID)\n    }\n\n    private fun startDownload(moduleName: String, downloadLink: String, destinationFile: File, downloadData: DownloadData) {\n        val packData = downloadData.getModuleData(moduleName)\n        val uri = Uri.parse(downloadLink).toString()\n        val connection = URL(uri).openConnection() as HttpURLConnection\n        var bytes: Long = 0\n        try {\n            connection.requestMethod = \"GET\"\n            connection.connectTimeout = 20000\n            connection.readTimeout = 20000\n            connection.connect()\n            if (connection.responseCode != HttpURLConnection.HTTP_OK) {\n                throw IOException(\"Failed to download file: HTTP response code ${connection.responseCode}\")\n            }\n            if (destinationFile.exists()) {\n                destinationFile.delete()\n            } else destinationFile.parentFile?.mkdirs()\n\n            connection.inputStream.use { input ->\n                FileOutputStream(destinationFile).use { output ->\n                    val buffer = ByteArray(4096)\n                    var bytesRead: Int\n                    while (input.read(buffer).also { bytesRead = it } != -1) {\n                        if (shouldStops) {\n                            Log.d(TAG, \"Download interrupted for module: $moduleName\")\n                            downloadData.updateDownloadStatus(moduleName, AssetPackStatus.CANCELED)\n                            return\n                        }\n                        output.write(buffer, 0, bytesRead)\n                        bytes += bytesRead.toLong()\n                        downloadData.incrementModuleBytesDownloaded(moduleName, bytesRead.toLong())\n                        if (bytes >= 1048576) {\n                            val progress = ((packData.bytesDownloaded.toDouble() / packData.totalBytesToDownload.toDouble()) * 100).toInt()\n                            updateProgress(moduleName, progress)\n                            sendBroadcastForExistingFile(context, downloadData, moduleName, null, null)\n                            bytes = 0\n                        }\n                    }\n                }\n            }\n        } catch (e: Exception) {\n            Log.e(TAG, \"prepareDownload: startDownload error \", e)\n            downloadData.updateDownloadStatus(moduleName, AssetPackStatus.FAILED)\n            cancelDownload(moduleName)\n            downloadData.getModuleData(moduleName).bytesDownloaded = 0\n        } finally {\n            connection.disconnect()\n        }\n    }\n\n    companion object {\n        @SuppressLint(\"StaticFieldLeak\")\n        @Volatile\n        private var instance: DownloadManager? = null\n        fun get(context: Context): DownloadManager {\n            return instance ?: synchronized(this) {\n                instance ?: DownloadManager(context.applicationContext).also { instance = it }\n            }\n        }\n    }\n}"
  },
  {
    "path": "vending-app/src/main/kotlin/com/google/android/finsky/IntegrityExtensions.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.finsky\n\nimport android.accounts.AccountManager\nimport android.accounts.AccountManagerFuture\nimport android.content.Context\nimport android.content.pm.ApplicationInfo\nimport android.content.pm.PackageInfo\nimport android.content.pm.PackageManager\nimport android.content.pm.Signature\nimport android.net.ConnectivityManager\nimport android.os.Bundle\nimport android.security.keystore.KeyGenParameterSpec\nimport android.security.keystore.KeyProperties\nimport android.text.TextUtils\nimport android.util.Base64\nimport android.util.Log\nimport androidx.core.content.edit\nimport com.android.vending.VendingPreferences\nimport com.android.vending.buildRequestHeaders\nimport com.android.vending.makeTimestamp\nimport com.google.android.finsky.expressintegrityservice.ExpressIntegritySession\nimport com.google.android.finsky.expressintegrityservice.IntermediateIntegrityResponseData\nimport com.google.android.finsky.expressintegrityservice.PackageInformation\nimport com.google.android.finsky.model.IntegrityErrorCode\nimport com.google.android.finsky.model.StandardIntegrityException\nimport com.google.android.gms.droidguard.DroidGuard\nimport com.google.android.gms.droidguard.internal.DroidGuardResultsRequest\nimport com.google.android.gms.tasks.await\nimport com.google.crypto.tink.Aead\nimport com.google.crypto.tink.BinaryKeysetReader\nimport com.google.crypto.tink.BinaryKeysetWriter\nimport com.google.crypto.tink.CleartextKeysetHandle\nimport com.google.crypto.tink.KeysetHandle\nimport com.google.crypto.tink.aead.AesGcmKeyManager\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\nimport okio.ByteString\nimport okio.ByteString.Companion.decodeBase64\nimport okio.ByteString.Companion.encode\nimport okio.ByteString.Companion.toByteString\nimport org.microg.gms.common.Constants\nimport org.microg.gms.profile.Build\nimport org.microg.gms.profile.ProfileManager\nimport org.microg.gms.utils.getFirstSignatureDigest\nimport org.microg.gms.vending.PlayIntegrityData\nimport org.microg.vending.billing.DEFAULT_ACCOUNT_TYPE\nimport org.microg.vending.billing.GServices\nimport org.microg.vending.billing.core.HttpClient\nimport org.microg.vending.proto.Timestamp\nimport java.io.ByteArrayOutputStream\nimport java.io.File\nimport java.io.FileInputStream\nimport java.io.FileOutputStream\nimport java.nio.ByteBuffer\nimport java.security.KeyPair\nimport java.security.KeyPairGenerator\nimport java.security.KeyStore\nimport java.security.MessageDigest\nimport java.security.NoSuchAlgorithmException\nimport java.security.ProviderException\nimport java.security.spec.ECGenParameterSpec\nimport kotlin.coroutines.resume\nimport kotlin.coroutines.suspendCoroutine\n\nconst val INTEGRITY_PREFIX_ERROR = \"ERROR :\"\nconst val INTEGRITY_FLOW_NAME = \"pia_attest_e1\"\nconst val EXPRESS_INTEGRITY_FLOW_NAME = \"pia_express\"\n\nconst val KEY_PACKAGE_NAME = \"package.name\"\nconst val KEY_NONCE = \"nonce\"\nconst val KEY_CLOUD_PROJECT = \"cloud.prj\"\nconst val KEY_REQUEST_MODE = \"webview.request.mode\"\nconst val KEY_OPT_PACKAGE = \"opted.out.pkg\"\nconst val KEY_DROID_GUARD_SESSION_TOKEN_V1 = \"droid_guard_session_token_v1\"\nconst val KEY_REQUEST_VERDICT_OPT_OUT = \"request.verdict.opt.out\"\nconst val KEY_REQUEST_TOKEN_SID = \"request.token.sid\"\nconst val KEY_WARM_UP_SID = \"warm.up.sid\"\nconst val KEY_ERROR = \"error\"\nconst val KEY_TOKEN = \"token\"\n\nconst val PARAMS_PKG_KEY = \"pkg_key\"\nconst val PARAMS_VC_KEY = \"vc_key\"\nconst val PARAMS_NONCE_SHA256_KEY = \"nonce_sha256_key\"\nconst val PARAMS_TM_S_KEY = \"tm_s_key\"\nconst val PARAMS_BINDING_KEY = \"binding_key\"\nconst val PARAMS_GCP_N_KEY = \"gcp_n_key\"\nconst val PARAMS_PIA_EXPRESS_DEVICE_KEY = \"piaExpressDeviceKey\"\n\nconst val RESULT_UN_AUTH = \"<UNAUTH>\"\n\nprivate const val KEY_VERSION_MAJOR = \"playcore.integrity.version.major\"\nprivate const val KEY_VERSION_MINOR = \"playcore.integrity.version.minor\"\nprivate const val KEY_VERSION_PATCH = \"playcore.integrity.version.patch\"\n\nprivate const val DEVICE_INTEGRITY_SOFT_EXPIRATION_CHECK_PERIOD = 600L // 10 minutes\nprivate const val TEMPORARY_DEVICE_KEY_VALIDITY = 64800L // 18 hours\nprivate const val DEVICE_INTEGRITY_SOFT_EXPIRATION = 100800L // 28 hours\nprivate const val DEVICE_INTEGRITY_HARD_EXPIRATION = 432000L // 5 day\nconst val INTERMEDIATE_INTEGRITY_HARD_EXPIRATION = 86400L // 1 day\nprivate const val TAG = \"IntegrityExtensions\"\n\nfun callerAppToIntegrityData(context: Context, callingPackage: String): PlayIntegrityData {\n    val pkgSignSha256ByteArray = context.packageManager.getFirstSignatureDigest(callingPackage, \"SHA-256\")\n    if (pkgSignSha256ByteArray == null) {\n        throw StandardIntegrityException(IntegrityErrorCode.APP_NOT_INSTALLED, \"$callingPackage signature is null\")\n    }\n    val pkgSignSha256 = Base64.encodeToString(pkgSignSha256ByteArray, Base64.NO_WRAP)\n    Log.d(TAG, \"callerToVisitData $callingPackage pkgSignSha256: $pkgSignSha256\")\n    val playIntegrityAppList = VendingPreferences.getPlayIntegrityAppList(context)\n    val loadDataSet = PlayIntegrityData.loadDataSet(playIntegrityAppList)\n    if (loadDataSet.isEmpty() || loadDataSet.none { it.packageName == callingPackage && it.pkgSignSha256 == pkgSignSha256 }) {\n        return PlayIntegrityData(true, callingPackage, pkgSignSha256, System.currentTimeMillis())\n    }\n    return loadDataSet.first { it.packageName == callingPackage && it.pkgSignSha256 == pkgSignSha256 }\n}\n\nfun PlayIntegrityData.updateAppIntegrityContent(context: Context, time: Long, result: String, status: Boolean = false) {\n    val playIntegrityAppList = VendingPreferences.getPlayIntegrityAppList(context)\n    val loadDataSet = PlayIntegrityData.loadDataSet(playIntegrityAppList)\n    val dataSetString = PlayIntegrityData.updateDataSetString(loadDataSet, apply {\n        lastTime = time\n        lastResult = result\n        lastStatus = status\n    })\n    VendingPreferences.setPlayIntegrityAppList(context, dataSetString)\n}\n\nfun IntegrityRequestWrapper.getExpirationTime() = runCatching {\n    val creationTimeStamp = deviceIntegrityWrapper?.creationTime ?: Timestamp(0, 0)\n    val creationTime = (creationTimeStamp.seconds ?: 0) * 1000 + (creationTimeStamp.nanos ?: 0) / 1_000_000\n    val currentTimeStamp = makeTimestamp(System.currentTimeMillis())\n    val currentTime = (currentTimeStamp.seconds ?: 0) * 1000 + (currentTimeStamp.nanos ?: 0) / 1_000_000\n    return@runCatching currentTime - creationTime\n}.getOrDefault(0)\n\nprivate fun Context.getProtoFile(): File {\n    val directory = File(filesDir, \"finsky/shared\")\n    if (!directory.exists()) {\n        directory.mkdirs()\n    }\n    val file = File(directory, \"express_integrity_valuestore.pb\")\n    if (!file.exists()) {\n        file.createNewFile()\n    }\n    return file\n}\n\nfun Context.isNetworkConnected(): Boolean {\n    return try {\n        val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager\n        connectivityManager.activeNetworkInfo?.isConnected == true\n    } catch (_: RuntimeException) {\n        false\n    }\n}\n\nprivate fun getExpressFilePB(context: Context): ExpressFilePB {\n    return runCatching { FileInputStream(context.getProtoFile()).use { input -> ExpressFilePB.ADAPTER.decode(input) } }\n        .onFailure { Log.w(TAG, \"Failed to read express cache \", it) }\n        .getOrDefault(ExpressFilePB())\n}\n\nfun PackageManager.getPackageInfoCompat(packageName: String, flags: Int = 0): PackageInfo {\n    return runCatching {\n        if (Build.VERSION.SDK_INT >= 33) {\n            getPackageInfo(packageName, PackageManager.PackageInfoFlags.of(flags.toLong()))\n        } else {\n            getPackageInfo(packageName, flags)\n        }\n    }.getOrDefault(getPackageInfo(packageName, flags))\n}\n\nval SIGNING_FLAGS = if (Build.VERSION.SDK_INT >= 28) {\n    PackageManager.GET_SIGNING_CERTIFICATES\n} else {\n    @Suppress(\"DEPRECATION\") PackageManager.GET_SIGNATURES\n}\n\nval PackageInfo.signaturesCompat: Array<Signature>\n    get() {\n        return if (Build.VERSION.SDK_INT >= 28) {\n            val signingInfo = signingInfo ?: return emptyArray()\n            if (signingInfo.hasMultipleSigners()) {\n                signingInfo.apkContentsSigners\n            } else {\n                signingInfo.signingCertificateHistory\n            }\n        } else {\n            @Suppress(\"DEPRECATION\") signatures ?: emptyArray()\n        }\n    }\n\nfun ByteArray.encodeBase64(noPadding: Boolean, noWrap: Boolean = true, urlSafe: Boolean = true): String {\n    var flags = 0\n    if (noPadding) flags = flags or Base64.NO_PADDING\n    if (noWrap) flags = flags or Base64.NO_WRAP\n    if (urlSafe) flags = flags or Base64.URL_SAFE\n    return Base64.encodeToString(this, flags)\n}\n\nfun ByteArray.md5(): ByteArray? {\n    return try {\n        val md5 = MessageDigest.getInstance(\"MD5\")\n        md5.digest(this)\n    } catch (e: NoSuchAlgorithmException) {\n        null\n    }\n}\n\nfun ByteArray.sha256(): ByteArray {\n    return MessageDigest.getInstance(\"SHA-256\").digest(this)\n}\n\nfun Bundle.getPlayCoreVersion() = PlayCoreVersion(\n    major = getInt(KEY_VERSION_MAJOR, 0), minor = getInt(KEY_VERSION_MINOR, 0), patch = getInt(KEY_VERSION_PATCH, 0)\n)\n\nfun List<AdviceType>?.ensureContainsLockBootloader(): List<AdviceType> {\n    if (isNullOrEmpty()) return listOf(AdviceType.LOCK_BOOTLOADER)\n    return if (contains(AdviceType.LOCK_BOOTLOADER)) this else listOf(AdviceType.LOCK_BOOTLOADER) + this\n}\n\nfun readAes128GcmBuilderFromClientKey(clientKey: ClientKey?): Aead? {\n    if (clientKey == null) {\n        return null\n    }\n    return try {\n        val keySetHandle = CleartextKeysetHandle.read(BinaryKeysetReader.withBytes(clientKey.keySetHandle?.toByteArray()))\n        keySetHandle.getPrimitive(Aead::class.java)\n    } catch (e: Exception) {\n        null\n    }\n}\n\nsuspend fun getIntegrityRequestWrapper(context: Context, expressIntegritySession: ExpressIntegritySession, accountName: String) = withContext(Dispatchers.IO) {\n    fun getUpdatedWebViewRequestMode(webViewRequestMode: Int): Int {\n        return when (webViewRequestMode) {\n            in 0..2 -> webViewRequestMode + 1\n            else -> 1\n        }\n    }\n    val expressFilePB = getExpressFilePB(context)\n    expressFilePB.integrityRequestWrapper.filter { item ->\n        TextUtils.equals(item.packageName, expressIntegritySession.packageName) && item.cloudProjectNumber == expressIntegritySession.cloudProjectNumber && getUpdatedWebViewRequestMode(\n            expressIntegritySession.webViewRequestMode\n        ) == getUpdatedWebViewRequestMode(\n            item.webViewRequestMode ?: 0\n        )\n    }.firstOrNull { item ->\n        TextUtils.equals(item.accountName, accountName)\n    }\n}\n\nfun fetchCertificateChain(context: Context, attestationChallenge: ByteArray?): List<ByteString> {\n    if (android.os.Build.VERSION.SDK_INT >= 24) {\n        val devicePropertiesAttestationIncluded = context.packageManager.hasSystemFeature(\"android.software.device_id_attestation\")\n        val keyGenParameterSpecBuilder =\n            KeyGenParameterSpec.Builder(\"integrity.api.key.alias\", KeyProperties.PURPOSE_SIGN).apply {\n                this.setAlgorithmParameterSpec(ECGenParameterSpec(\"secp256r1\"))\n                this.setDigests(KeyProperties.DIGEST_SHA512)\n                if (devicePropertiesAttestationIncluded) {\n                    this.setAttestationChallenge(attestationChallenge)\n                }\n                if (android.os.Build.VERSION.SDK_INT >= 31) {\n                    this.setDevicePropertiesAttestationIncluded(devicePropertiesAttestationIncluded)\n                }\n            }\n        val generator = KeyPairGenerator.getInstance(\"EC\", \"AndroidKeyStore\")\n        var generateKeyPair = false\n        var keyPair: KeyPair? = null\n        val exceptionClassesCaught = HashSet<Class<Exception>>()\n        while (!generateKeyPair) {\n            try {\n                generator.initialize(keyGenParameterSpecBuilder.build())\n                keyPair = generator.generateKeyPair()\n                generateKeyPair = true\n            } catch (e: Exception) {\n                // Catch each exception class at most once.\n                // If we've caught the exception before, tried to correct it, and still catch the\n                // same exception, then we can't fix it and the exception should be thrown further\n                if (exceptionClassesCaught.contains(e.javaClass)) {\n                    break\n                }\n                exceptionClassesCaught.add(e.javaClass)\n                if (e is ProviderException) {\n                    keyGenParameterSpecBuilder.setAttestationChallenge(null)\n                }\n            }\n        }\n        if (keyPair == null) {\n            Log.w(TAG, \"Failed to create the key pair.\")\n            return emptyList()\n        }\n        val keyStore: KeyStore = KeyStore.getInstance(\"AndroidKeyStore\").apply { load(null) }\n        val certificateChainList = keyStore.getCertificateChain(\"integrity.api.key.alias\")?.let { chain ->\n            chain.map { it.encoded.toByteString() }\n        }\n        if (certificateChainList.isNullOrEmpty()) {\n            Log.w(TAG, \"Failed to get the certificate chain.\")\n            return emptyList()\n        }\n        return certificateChainList\n    } else {\n        return emptyList()\n    }\n}\n\nsuspend fun updateLocalExpressFilePB(context: Context, intermediateIntegrityResponseData: IntermediateIntegrityResponseData) = withContext(Dispatchers.IO) {\n    val intermediateIntegrity = intermediateIntegrityResponseData.intermediateIntegrity\n    val expressFilePB = getExpressFilePB(context)\n\n    val integrityResponseWrapper = IntegrityRequestWrapper.Builder().apply {\n        accountName = intermediateIntegrity.accountName\n        packageName = intermediateIntegrity.packageName\n        cloudProjectNumber = intermediateIntegrity.cloudProjectNumber\n        callerKey = intermediateIntegrity.callerKey\n        webViewRequestMode = intermediateIntegrity.webViewRequestMode.takeIf { it in 0..2 } ?: 0\n        deviceIntegrityWrapper = DeviceIntegrityWrapper.Builder().apply {\n            creationTime = intermediateIntegrity.callerKey.generated\n            serverGenerated = intermediateIntegrity.serverGenerated\n            deviceIntegrityToken = intermediateIntegrity.intermediateToken\n        }.build()\n        intermediateIntegrity.integrityAdvice?.let { advice = it }\n    }.build()\n\n    val requestList = expressFilePB.integrityRequestWrapper.toMutableList()\n\n    for ((index, item) in requestList.withIndex()) {\n        if (TextUtils.equals(item.packageName, intermediateIntegrity.packageName) && item.cloudProjectNumber == intermediateIntegrity.cloudProjectNumber && TextUtils.equals(\n                item.accountName, intermediateIntegrity.accountName\n            )\n        ) {\n            if (integrityResponseWrapper.webViewRequestMode == item.webViewRequestMode) {\n                requestList[index] = integrityResponseWrapper\n                val newExpressFilePB = expressFilePB.newBuilder().integrityRequestWrapper(requestList).build()\n                FileOutputStream(context.getProtoFile()).use { output -> ExpressFilePB.ADAPTER.encode(output, newExpressFilePB) }\n                return@withContext\n            }\n        }\n    }\n    requestList.add(integrityResponseWrapper)\n    val newExpressFilePB = expressFilePB.newBuilder().integrityRequestWrapper(requestList).build()\n    FileOutputStream(context.getProtoFile()).use { output -> ExpressFilePB.ADAPTER.encode(output, newExpressFilePB) }\n}\n\nsuspend fun updateExpressSessionTime(context: Context, expressIntegritySession: ExpressIntegritySession, refreshWarmUpMethodTime: Boolean, refreshRequestMethodTime: Boolean) =\n    withContext(Dispatchers.IO) {\n        val packageName = if (expressIntegritySession.webViewRequestMode != 0) {\n            \"WebView_\" + expressIntegritySession.packageName\n        } else {\n            expressIntegritySession.packageName\n        }\n\n        val expressFilePB = getExpressFilePB(context)\n\n        val clientKey = expressFilePB.integrityTokenTimeMap ?: IntegrityTokenTimeMap()\n        val timeMutableMap = clientKey.newBuilder().timeMap.toMutableMap()\n\n        if (refreshWarmUpMethodTime) {\n            timeMutableMap[packageName] = IntegrityTokenTime.Builder().warmUpTokenTime(\n                TokenTime.Builder().type(1).timestamp(makeTimestamp(System.currentTimeMillis())).build()\n            ).build()\n        }\n\n        if (refreshRequestMethodTime) {\n            timeMutableMap[packageName] = IntegrityTokenTime.Builder().requestTokenTime(\n                TokenTime.Builder().type(1).timestamp(makeTimestamp(System.currentTimeMillis())).build()\n            ).build()\n        }\n\n        val newExpressFilePB = expressFilePB.newBuilder().integrityTokenTimeMap(IntegrityTokenTimeMap.Builder().timeMap(timeMutableMap).build()).build()\n        FileOutputStream(context.getProtoFile()).use { output -> ExpressFilePB.ADAPTER.encode(output, newExpressFilePB) }\n    }\n\nsuspend fun updateExpressClientKey(context: Context) = withContext(Dispatchers.IO) {\n    val expressFilePB = getExpressFilePB(context)\n    val oldClientKey = expressFilePB.clientKey ?: ClientKey()\n    val generated = makeTimestamp(System.currentTimeMillis())\n\n    val oldGeneratedSec = oldClientKey.generated?.seconds ?: 0\n    val newGeneratedSec = generated.seconds ?: 0\n\n    val useOld = oldClientKey.keySetHandle?.size != 0 && oldGeneratedSec >= newGeneratedSec - TEMPORARY_DEVICE_KEY_VALIDITY\n\n    val clientKey = if (useOld) {\n        Log.d(TAG, \"Using existing clientKey, not expired. oldGeneratedSec=$oldGeneratedSec newGeneratedSec=$newGeneratedSec\")\n        oldClientKey\n    } else {\n        Log.d(TAG, \"Generating new clientKey. oldKeyValid=${oldClientKey.keySetHandle?.size != 0} expired=${oldGeneratedSec < newGeneratedSec - TEMPORARY_DEVICE_KEY_VALIDITY}\")\n        val keySetHandle = KeysetHandle.generateNew(AesGcmKeyManager.aes128GcmTemplate())\n        val keyBytes = ByteArrayOutputStream().use { output ->\n            CleartextKeysetHandle.write(keySetHandle, BinaryKeysetWriter.withOutputStream(output))\n            output.toByteArray()\n        }\n        Log.d(TAG, \"New clientKey generated at timestamp: ${generated.seconds}\")\n        ClientKey.Builder()\n            .generated(generated)\n            .keySetHandle(ByteBuffer.wrap(keyBytes).toByteString())\n            .build()\n    }\n\n    val newExpressFilePB = expressFilePB.newBuilder().clientKey(clientKey).build()\n    FileOutputStream(context.getProtoFile()).use { output -> ExpressFilePB.ADAPTER.encode(output, newExpressFilePB) }\n    clientKey\n}\n\nsuspend fun updateExpressAuthTokenWrapper(context: Context, expressIntegritySession: ExpressIntegritySession, authToken: String, clientKey: ClientKey) = withContext(Dispatchers.IO) {\n    var expressFilePB = getExpressFilePB(context)\n\n    val createTimeSeconds = expressFilePB.tokenWrapper?.deviceIntegrityWrapper?.creationTime?.seconds ?: 0\n    val lastManualSoftRefreshTime = expressFilePB.tokenWrapper?.lastManualSoftRefreshTime?.seconds ?: 0\n    if (createTimeSeconds < System.currentTimeMillis() - DEVICE_INTEGRITY_HARD_EXPIRATION) {\n        expressFilePB = expressFilePB.newBuilder().tokenWrapper(regenerateToken(context, authToken, expressIntegritySession.packageName, clientKey)).build()\n    } else if (lastManualSoftRefreshTime <= System.currentTimeMillis() - DEVICE_INTEGRITY_SOFT_EXPIRATION_CHECK_PERIOD && createTimeSeconds < System.currentTimeMillis() - DEVICE_INTEGRITY_SOFT_EXPIRATION) {\n        expressFilePB = expressFilePB.newBuilder().tokenWrapper(regenerateToken(context, authToken, expressIntegritySession.packageName, clientKey)).build()\n    }\n\n    FileOutputStream(context.getProtoFile()).use { output -> ExpressFilePB.ADAPTER.encode(output, expressFilePB) }\n\n    expressFilePB\n}\n\nprivate suspend fun regenerateToken(\n    context: Context, authToken: String, packageName: String, clientKey: ClientKey\n): AuthTokenWrapper {\n    Log.d(TAG, \"regenerateToken authToken:$authToken, packageName:$packageName, clientKey:$clientKey\")\n    try {\n        val prefs = context.getSharedPreferences(\"droid_guard_token_session_id\", Context.MODE_PRIVATE)\n        val droidGuardTokenSession = try {\n            val droidGuardSessionTokenResponse = requestDroidGuardSessionToken(context, authToken)\n            if (droidGuardSessionTokenResponse.tokenWrapper == null) {\n                throw RuntimeException(\"regenerateToken droidGuardSessionTokenResponse.tokenWrapper is Empty!\")\n            }\n            val droidGuardTokenType = droidGuardSessionTokenResponse.tokenWrapper.tokenContent?.tokenType?.firstOrNull { it.type?.toInt() == 5 }\n                ?: throw RuntimeException(\"regenerateToken droidGuardTokenType is null!\")\n            val sessionId = droidGuardTokenType.tokenSessionWrapper?.wrapper?.sessionContent?.session?.id\n            if (sessionId.isNullOrEmpty()) {\n                throw RuntimeException(\"regenerateToken sessionId is null\")\n            }\n            sessionId.also { prefs.edit { putString(packageName, it) } }\n        } catch (e: Exception) {\n            Log.d(TAG, \"regenerateToken: error \", e)\n            prefs.getString(packageName, null)\n        }\n\n        Log.d(TAG, \"regenerateToken: sessionId: $droidGuardTokenSession\")\n        if (droidGuardTokenSession.isNullOrEmpty()) {\n            throw RuntimeException(\"regenerateToken droidGuardTokenSession is null\")\n        }\n\n        val data = mutableMapOf(KEY_DROID_GUARD_SESSION_TOKEN_V1 to droidGuardTokenSession)\n        val droidGuardData = withContext(Dispatchers.IO) {\n            val droidGuardResultsRequest = DroidGuardResultsRequest().apply {\n                bundle.putByteArray(PARAMS_PIA_EXPRESS_DEVICE_KEY, clientKey.keySetHandle?.toByteArray())\n            }\n            Log.d(TAG, \"Running DroidGuard (flow: $EXPRESS_INTEGRITY_FLOW_NAME, data: $data)\")\n            DroidGuard.getClient(context).getResults(EXPRESS_INTEGRITY_FLOW_NAME, data, droidGuardResultsRequest).await().encode()\n        }\n\n        val deviceIntegrityTokenResponse = requestDeviceIntegrityToken(context, authToken, droidGuardTokenSession, droidGuardData)\n\n        val deviceIntegrityTokenType = deviceIntegrityTokenResponse.tokenWrapper?.tokenContent?.tokenType?.firstOrNull { it.type?.toInt() == 5 }\n            ?: throw RuntimeException(\"regenerateToken deviceIntegrityTokenType is null!\")\n\n        val deviceIntegrityToken = deviceIntegrityTokenType.tokenSessionWrapper?.wrapper?.sessionContent?.tokenContent?.tokenWrapper?.token\n\n        return AuthTokenWrapper.Builder().apply {\n            this.clientKey = clientKey\n            this.deviceIntegrityWrapper = DeviceIntegrityWrapper.Builder().apply {\n                this.deviceIntegrityToken = deviceIntegrityToken ?: ByteString.EMPTY\n                this.creationTime = makeTimestamp(System.currentTimeMillis())\n            }.build()\n            this.lastManualSoftRefreshTime = makeTimestamp(System.currentTimeMillis())\n        }.build()\n    } catch (e: Exception) {\n        Log.d(TAG, \"regenerateToken: error \", e)\n        return AuthTokenWrapper()\n    }\n}\n\nprivate suspend fun requestDroidGuardSessionToken(context: Context, authToken: String): TokenResponse {\n    val tokenWrapper = TokenRequestWrapper.Builder().apply {\n        request = mutableListOf(TokenRequest.Builder().apply {\n            droidGuardBody = DroidGuardBody.Builder().apply {\n                tokenBody = DroidGuardSessionTokenContent()\n            }.build()\n        }.build())\n    }.build()\n    return requestExpressSyncData(context, authToken, tokenWrapper)\n}\n\nprivate suspend fun requestDeviceIntegrityToken(\n    context: Context, authToken: String, session: String, token: ByteString\n): TokenResponse {\n    val tokenWrapper = TokenRequestWrapper.Builder().apply {\n        request = mutableListOf(TokenRequest.Builder().apply {\n            droidGuardBody = DroidGuardBody.Builder().apply {\n                deviceBody = DeviceIntegrityTokenContent.Builder().apply {\n                    sessionWrapper = SessionWrapper.Builder().apply {\n                        type = KEY_DROID_GUARD_SESSION_TOKEN_V1\n                        this.session = Session.Builder().apply {\n                            id = session\n                        }.build()\n                    }.build()\n                    this.token = token.utf8()\n                    flowName = EXPRESS_INTEGRITY_FLOW_NAME\n                }.build()\n            }.build()\n        }.build())\n    }.build()\n    return requestExpressSyncData(context, authToken, tokenWrapper)\n}\n\n// TODO: deduplicate with vending/extensions.kt\nsuspend fun getAuthToken(context: Context, authTokenType: String): String {\n    val accountManager = AccountManager.get(context)\n    val accounts = accountManager.getAccountsByType(DEFAULT_ACCOUNT_TYPE)\n    var oauthToken = \"\"\n    if (accounts.isEmpty()) {\n        Log.w(TAG, \"getAuthToken: No Google account found\")\n    } else for (account in accounts) {\n        val result = suspendCoroutine { continuation ->\n            accountManager.getAuthToken(account, authTokenType, false, { future: AccountManagerFuture<Bundle> ->\n                try {\n                    val result = future.result.getString(AccountManager.KEY_AUTHTOKEN)\n                    continuation.resume(result)\n                } catch (e: Exception) {\n                    Log.w(TAG, \"getAuthToken: \", e)\n                    continuation.resume(null)\n                }\n            }, null)\n        }\n        if (result != null) {\n            oauthToken = result\n            break\n        }\n    }\n    return oauthToken\n}\n\nsuspend fun requestIntegritySyncData(context: Context, authToken: String, request: IntegrityRequest): IntegrityResponse {\n    val androidId = GServices.getString(context.contentResolver, \"android_id\", \"1\")?.toLong() ?: 1\n    return HttpClient().post(\n        url = \"https://play-fe.googleapis.com/fdfe/integrity\",\n        headers = buildRequestHeaders(authToken, androidId),\n        payload = request,\n        adapter = IntegrityResponse.ADAPTER\n    )\n}\n\nsuspend fun requestExpressSyncData(context: Context, authToken: String, request: TokenRequestWrapper): TokenResponse {\n    val androidId = GServices.getString(context.contentResolver, \"android_id\", \"1\")?.toLong() ?: 1\n    return HttpClient().post(\n        url = \"https://play-fe.googleapis.com/fdfe/sync?nocache_qos=lt\",\n        headers = buildRequestHeaders(authToken, androidId),\n        payload = request,\n        adapter = TokenResponse.ADAPTER\n    )\n}\n\nsuspend fun requestIntermediateIntegrity(\n    context: Context, authToken: String, request: IntermediateIntegrityRequest\n): IntermediateIntegrityResponseWrapperExtend {\n    val androidId = GServices.getString(context.contentResolver, \"android_id\", \"1\")?.toLong() ?: 1\n    return HttpClient().post(\n        url = \"https://play-fe.googleapis.com/fdfe/intermediateIntegrity\",\n        headers = buildRequestHeaders(authToken, androidId),\n        payload = request,\n        adapter = IntermediateIntegrityResponseWrapperExtend.ADAPTER\n    )\n}\n\nfun buildClientKeyExtend(\n    context: Context,\n    session: ExpressIntegritySession,\n    packageInformation: PackageInformation,\n    clientKey: ClientKey\n): ClientKeyExtend {\n    return ClientKeyExtend.Builder().apply {\n        cloudProjectNumber = session.cloudProjectNumber\n        keySetHandle = clientKey.keySetHandle\n        if (session.webViewRequestMode == 2) {\n            this.optPackageName = KEY_OPT_PACKAGE\n            this.versionCode = 0\n        } else {\n            this.optPackageName = session.packageName\n            this.versionCode = packageInformation.versionCode\n            this.certificateSha256Hashes = packageInformation.certificateSha256Hashes\n        }\n        this.deviceSerialHash = ProfileManager.getSerial(context).toByteArray().sha256().toByteString()\n    }.build()\n}\n\nfun buildInstallSourceMetaData(\n    context: Context,\n    packageName: String\n): InstallSourceMetaData {\n    fun resolveInstallerType(name: String?): InstallerType = when {\n        name.isNullOrEmpty() -> InstallerType.UNSPECIFIED_INSTALLER\n        name == Constants.VENDING_PACKAGE_NAME -> InstallerType.PHONESKY_INSTALLER\n        else -> InstallerType.OTHER_INSTALLER\n    }\n\n    fun resolvePackageSourceType(type: Int): PackageSourceType = when (type) {\n        1 -> PackageSourceType.PACKAGE_SOURCE_OTHER\n        2 -> PackageSourceType.PACKAGE_SOURCE_STORE\n        3 -> PackageSourceType.PACKAGE_SOURCE_LOCAL_FILE\n        4 -> PackageSourceType.PACKAGE_SOURCE_DOWNLOADED_FILE\n        else -> PackageSourceType.PACKAGE_SOURCE_UNSPECIFIED\n    }\n\n    val builder = InstallSourceMetaData.Builder().apply {\n        installingPackageName = InstallerType.UNSPECIFIED_INSTALLER\n        initiatingPackageName = InstallerType.UNSPECIFIED_INSTALLER\n        originatingPackageName = InstallerType.UNSPECIFIED_INSTALLER\n        updateOwnerPackageName = InstallerType.UNSPECIFIED_INSTALLER\n        packageSourceType = PackageSourceType.PACKAGE_SOURCE_UNSPECIFIED\n    }\n\n    val applicationInfo = runCatching {\n        context.packageManager.getApplicationInfo(packageName, 0)\n    }.getOrNull()\n\n    if (Build.VERSION.SDK_INT >= 30) {\n        runCatching {\n            val info = context.packageManager.getInstallSourceInfo(packageName)\n            builder.apply {\n                initiatingPackageName = resolveInstallerType(info.initiatingPackageName)\n                installingPackageName = resolveInstallerType(info.installingPackageName)\n                originatingPackageName = resolveInstallerType(info.originatingPackageName)\n\n                if (Build.VERSION.SDK_INT >= 34) {\n                    updateOwnerPackageName = resolveInstallerType(info.updateOwnerPackageName)\n                }\n                if (Build.VERSION.SDK_INT >= 33) {\n                    packageSourceType = resolvePackageSourceType(info.packageSource)\n                }\n            }\n        }\n    } else {\n        builder.installingPackageName = runCatching {\n            resolveInstallerType(context.packageManager.getInstallerPackageName(packageName))\n        }.getOrElse { InstallerType.UNSPECIFIED_INSTALLER }\n    }\n\n    builder.appFlags = applicationInfo?.let { info ->\n        buildList {\n            if (info.flags and ApplicationInfo.FLAG_SYSTEM != 0) add(SystemAppFlag.FLAG_SYSTEM)\n            if (info.flags and ApplicationInfo.FLAG_UPDATED_SYSTEM_APP != 0) {\n                add(SystemAppFlag.FLAG_UPDATED_SYSTEM_APP)\n            }\n        }.ifEmpty { listOf(SystemAppFlag.SYSTEM_APP_INFO_UNSPECIFIED) }\n    } ?: listOf(SystemAppFlag.SYSTEM_APP_INFO_UNSPECIFIED)\n\n    return builder.build()\n}\n\nfun validateIntermediateIntegrityResponse(intermediateIntegrityResponse: IntermediateIntegrityResponseData) {\n    val intermediateIntegrity = intermediateIntegrityResponse.intermediateIntegrity\n\n    requireNotNull(intermediateIntegrity.intermediateToken) { \"Null intermediateToken\" }\n    requireNotNull(intermediateIntegrity.serverGenerated) { \"Null serverGenerated\" }\n}\n\n"
  },
  {
    "path": "vending-app/src/main/kotlin/com/google/android/finsky/accounts/impl/AccountsChangedReceiver.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.finsky.accounts.impl\n\nimport android.accounts.AccountManager\nimport android.content.BroadcastReceiver\nimport android.content.Context\nimport android.content.Intent\nimport android.util.Log\nimport com.android.vending.VendingPreferences\nimport com.android.vending.AUTH_TOKEN_SCOPE\nimport com.android.vending.getAuthToken\nimport com.google.android.finsky.syncDeviceInfo\nimport kotlinx.coroutines.DelicateCoroutinesApi\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.GlobalScope\nimport kotlinx.coroutines.launch\nimport org.microg.gms.auth.AuthConstants\nimport org.microg.gms.profile.ProfileManager\nimport org.microg.vending.billing.GServices\n\nprivate const val TAG = \"AccountsChangedReceiver\"\n\nclass AccountsChangedReceiver : BroadcastReceiver() {\n\n    @OptIn(DelicateCoroutinesApi::class)\n    override fun onReceive(context: Context, intent: Intent?) {\n        Log.d(TAG, \"onReceive: intent-> $intent\")\n        val deviceSyncEnabled = VendingPreferences.isDeviceSyncEnabled(context)\n        if (!deviceSyncEnabled) {\n            Log.d(TAG, \"onReceive: deviceSyncEnabled is false\")\n            return\n        }\n        var accountName: String? = null\n        if (intent?.let { accountName = it.getStringExtra(AccountManager.KEY_ACCOUNT_NAME) } == null) {\n            Log.d(TAG, \"onReceive: accountName is empty\")\n            return\n        }\n        GlobalScope.launch(Dispatchers.IO) {\n            val account = AccountManager.get(context).getAccountsByType(AuthConstants.DEFAULT_ACCOUNT_TYPE).firstOrNull {\n                it.name == accountName\n            } ?: throw RuntimeException(\"account is null\")\n            ProfileManager.ensureInitialized(context)\n            val androidId = GServices.getString(context.contentResolver, \"android_id\", \"1\")?.toLong() ?: 1\n            val authToken = account.let {\n                getAuthToken(AccountManager.get(context), it, AUTH_TOKEN_SCOPE).getString(AccountManager.KEY_AUTHTOKEN)\n            } ?: throw RuntimeException(\"oauthToken is null\")\n            syncDeviceInfo(context, account, authToken, androidId)\n        }\n    }\n\n}"
  },
  {
    "path": "vending-app/src/main/kotlin/com/google/android/finsky/appcontentservice/engage/AppEngageServiceV2.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.finsky.appcontentservice.engage\n\nimport android.content.Intent\nimport android.content.ServiceConnection\nimport android.os.IBinder\nimport android.util.Log\nimport androidx.lifecycle.LifecycleService\n\nclass AppEngageServiceV2 : LifecycleService() {\n    private val TAG = \"AppEngageServiceV2\"\n    override fun onCreate() {\n        super.onCreate()\n        Log.d(TAG, \"onCreate: \")\n    }\n\n    override fun onBind(intent: Intent): IBinder? {\n        super.onBind(intent)\n        Log.d(TAG, \"onBind: \")\n        return AppEngageServiceV2Impl(lifecycle).asBinder()\n    }\n\n    override fun unbindService(conn: ServiceConnection) {\n        super.unbindService(conn)\n    }\n}"
  },
  {
    "path": "vending-app/src/main/kotlin/com/google/android/finsky/appcontentservice/engage/AppEngageServiceV2Impl.kt",
    "content": "package com.google.android.finsky.appcontentservice.engage\n\nimport android.os.Bundle\nimport android.util.Log\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.LifecycleOwner\nimport com.google.android.engage.protocol.IAppEngageService\nimport com.google.android.engage.protocol.IAppEngageServiceAvailableCallback\nimport com.google.android.engage.protocol.IAppEngageServiceDeleteClustersCallback\nimport com.google.android.engage.protocol.IAppEngageServicePublishClustersCallback\nimport com.google.android.engage.protocol.IAppEngageServicePublishStatusCallback\n\nclass AppEngageServiceV2Impl(override val lifecycle: Lifecycle) : IAppEngageService.Stub(), LifecycleOwner {\n    private val TAG = \"AppEngageServiceV2Impl\"\n    override fun publishClusters(bundle: Bundle?, callback: IAppEngageServicePublishClustersCallback?) {\n        Log.d(TAG, \"publishClusters: \")\n    }\n\n    override fun deleteClusters(bundle: Bundle?, callback: IAppEngageServiceDeleteClustersCallback?) {\n        Log.d(TAG, \"deleteClusters: \")\n    }\n\n    override fun isServiceAvailable(bundle: Bundle?, callback: IAppEngageServiceAvailableCallback?) {\n        Log.d(TAG, \"isServiceAvailable: \")\n        val result = Bundle()\n        result.putBoolean(\"availability\", false)\n        callback?.onResult(result)\n    }\n\n    override fun updatePublishStatus(bundle: Bundle?, callback: IAppEngageServicePublishStatusCallback?) {\n        Log.d(TAG, \"updatePublishStatus: \")\n    }\n}"
  },
  {
    "path": "vending-app/src/main/kotlin/com/google/android/finsky/assetmoduleservice/AbstractAssetModuleServiceImpl.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.finsky.assetmoduleservice\n\nimport android.content.Context\nimport android.os.Bundle\nimport android.os.Parcel\nimport android.util.Log\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.LifecycleOwner\nimport androidx.lifecycle.lifecycleScope\nimport com.android.vending.VendingPreferences\nimport com.google.android.finsky.AssetModuleOptions\nimport com.google.android.finsky.bundleOf\nimport com.google.android.finsky.get\nimport com.google.android.play.core.assetpacks.model.AssetPackErrorCode\nimport com.google.android.play.core.assetpacks.protocol.BundleKeys\nimport com.google.android.play.core.assetpacks.protocol.IAssetModuleService\nimport com.google.android.play.core.assetpacks.protocol.IAssetModuleServiceCallback\nimport org.microg.gms.common.PackageUtils\nimport org.microg.gms.utils.warnOnTransactionIssues\n\nclass AssetPackException(val code: @AssetPackErrorCode Int, message: String? = null) : Exception(message ?: \"AssetPackException(code=$code)\")\n\ndata class StartDownloadParameters(val moduleNames: List<String>, val installedAssetModules: Map<String, Long>, val options: AssetModuleOptions)\ndata class GetSessionStatesParameters(val installedAssetModules: Map<String, Long>, val options: AssetModuleOptions)\ndata class NotifyModuleCompletedParameters(val moduleName: String, val sessionId: Int, val options: AssetModuleOptions)\ndata class NotifySessionFailedParameters(val sessionId: Int, val options: AssetModuleOptions)\ndata class RequestDownloadInfoParameters(val moduleNames: List<String>, val installedAssetModules: Map<String, Long>, val options: AssetModuleOptions)\ndata class RemoveModuleParameters(val moduleName: String, val sessionId: Int, val options: AssetModuleOptions)\ndata class CancelDownloadsParameters(val moduleNames: List<String>, val options: AssetModuleOptions)\ndata class KeepAliveParameters(val options: AssetModuleOptions)\n\ndata class NotifyChunkTransferredParameters(\n    val moduleName: String,\n    val sliceId: String,\n    val chunkNumber: Int,\n    val sessionId: Int,\n    val options: AssetModuleOptions\n)\n\ndata class GetChunkFileDescriptorParameters(\n    val moduleName: String,\n    val sliceId: String,\n    val chunkNumber: Int,\n    val sessionId: Int,\n    val options: AssetModuleOptions\n)\n\nabstract class AbstractAssetModuleServiceImpl(val context: Context, override val lifecycle: Lifecycle) : IAssetModuleService.Stub(), LifecycleOwner {\n    private fun List<Bundle>.getModuleNames(): List<String> = mapNotNull { it.get(BundleKeys.MODULE_NAME).takeIf { !it.isNullOrBlank() } }\n    private fun Bundle?.getInstalledAssetModules(): Map<String, Long> = get(BundleKeys.INSTALLED_ASSET_MODULE).orEmpty()\n        .map { it.get(BundleKeys.INSTALLED_ASSET_MODULE_NAME) to it.get(BundleKeys.INSTALLED_ASSET_MODULE_VERSION) }\n        .filter { it.first != null && it.second != null }\n        .associate { it.first!! to it.second!! }\n\n    private fun Bundle?.getOptions() = AssetModuleOptions(\n        this.get(BundleKeys.PLAY_CORE_VERSION_CODE, 0),\n        this.get(BundleKeys.SUPPORTED_COMPRESSION_FORMATS).orEmpty(),\n        this.get(BundleKeys.SUPPORTED_PATCH_FORMATS).orEmpty(),\n    )\n\n    private fun sendError(callback: IAssetModuleServiceCallback?, method: String, errorCode: @AssetPackErrorCode Int) {\n        Log.w(TAG, \"Sending error from $method: $errorCode\")\n        callback?.onError(bundleOf(BundleKeys.ERROR_CODE to errorCode))\n    }\n\n    private fun <T: Any> run(\n        uncheckedPackageName: String?,\n        method: String,\n        callback: IAssetModuleServiceCallback?,\n        parseParameters: (packageName: String) -> T,\n        logic: suspend (params: T, packageName: String, callback: IAssetModuleServiceCallback?) -> Unit\n    ) {\n        val packageName = try {\n            PackageUtils.getAndCheckCallingPackage(context, uncheckedPackageName)!!\n        } catch (e: Exception) {\n            Log.w(TAG, e)\n            return sendError(callback, method, AssetPackErrorCode.ACCESS_DENIED)\n        }\n\n        if (!VendingPreferences.isAssetDeliveryEnabled(context)) {\n            return sendError(callback, method, AssetPackErrorCode.API_NOT_AVAILABLE)\n        }\n\n        val input = try {\n            parseParameters(packageName)\n        } catch (e: AssetPackException) {\n            return sendError(callback, method, e.code)\n        } catch (e: Exception) {\n            Log.w(TAG, e)\n            return sendError(callback, method, AssetPackErrorCode.INVALID_REQUEST)\n        }\n\n        Log.d(TAG, \"$method[$packageName]${input.toString().substring(input.javaClass.simpleName.length)}\")\n\n        lifecycleScope.launchWhenStarted {\n            try {\n                logic.invoke(input, packageName, callback)\n            } catch (e: AssetPackException) {\n                sendError(callback, method, e.code)\n            } catch (e: UnsupportedOperationException) {\n                Log.w(TAG, \"Unsupported: $method\")\n                sendError(callback, method, AssetPackErrorCode.API_NOT_AVAILABLE)\n            } catch (e: Exception) {\n                Log.w(TAG, e)\n                sendError(callback, method, AssetPackErrorCode.INTERNAL_ERROR)\n            }\n        }\n    }\n\n    protected abstract fun getDefaultSessionId(packageName: String, moduleName: String): Int\n\n    override fun startDownload(uncheckedPackageName: String?, list: MutableList<Bundle>?, bundle: Bundle?, callback: IAssetModuleServiceCallback?) {\n        run(uncheckedPackageName, \"startDownload\", callback, { _ ->\n            StartDownloadParameters(list!!.getModuleNames().also { require(it.isNotEmpty()) }, bundle.getInstalledAssetModules(), bundle.getOptions())\n        }, this::startDownload)\n    }\n\n    abstract suspend fun startDownload(params: StartDownloadParameters, packageName: String, callback: IAssetModuleServiceCallback?)\n\n    override fun getSessionStates(uncheckedPackageName: String?, bundle: Bundle?, callback: IAssetModuleServiceCallback?) {\n        run(uncheckedPackageName, \"getSessionStates\", callback, { _ ->\n            GetSessionStatesParameters(bundle.getInstalledAssetModules(), bundle.getOptions())\n        }, this::getSessionStates)\n    }\n\n    abstract suspend fun getSessionStates(params: GetSessionStatesParameters, packageName: String, callback: IAssetModuleServiceCallback?)\n\n    override fun notifyChunkTransferred(uncheckedPackageName: String?, bundle: Bundle?, bundle2: Bundle?, callback: IAssetModuleServiceCallback?) {\n        run(uncheckedPackageName, \"notifyChunkTransferred\", callback, { packageName ->\n            val moduleName = bundle.get(BundleKeys.MODULE_NAME)!!.also { require(it.isNotEmpty()) }\n            NotifyChunkTransferredParameters(\n                moduleName,\n                bundle.get(BundleKeys.SLICE_ID)!!.also { require(it.isNotEmpty()) },\n                bundle.get(BundleKeys.CHUNK_NUMBER, 0),\n                bundle.get(BundleKeys.SESSION_ID, getDefaultSessionId(packageName, moduleName)),\n                bundle2.getOptions()\n            )\n        }, this::notifyChunkTransferred)\n    }\n\n    abstract suspend fun notifyChunkTransferred(params: NotifyChunkTransferredParameters, packageName: String, callback: IAssetModuleServiceCallback?)\n\n    override fun notifyModuleCompleted(uncheckedPackageName: String?, bundle: Bundle?, bundle2: Bundle?, callback: IAssetModuleServiceCallback?) {\n        run(uncheckedPackageName, \"notifyModuleCompleted\", callback, { packageName ->\n            val moduleName = bundle.get(BundleKeys.MODULE_NAME)!!.also { require(it.isNotEmpty()) }\n            NotifyModuleCompletedParameters(\n                moduleName,\n                bundle.get(BundleKeys.SESSION_ID, getDefaultSessionId(packageName, moduleName)),\n                bundle2.getOptions()\n            )\n        }, this::notifyModuleCompleted)\n    }\n\n    abstract suspend fun notifyModuleCompleted(params: NotifyModuleCompletedParameters, packageName: String, callback: IAssetModuleServiceCallback?)\n\n    override fun notifySessionFailed(uncheckedPackageName: String?, bundle: Bundle?, bundle2: Bundle?, callback: IAssetModuleServiceCallback?) {\n        run(uncheckedPackageName, \"notifySessionFailed\", callback, { _ ->\n            NotifySessionFailedParameters(bundle.get(BundleKeys.SESSION_ID, 0), bundle2.getOptions())\n        }, this::notifySessionFailed)\n    }\n\n    abstract suspend fun notifySessionFailed(params: NotifySessionFailedParameters, packageName: String, callback: IAssetModuleServiceCallback?)\n\n    override fun getChunkFileDescriptor(uncheckedPackageName: String?, bundle: Bundle?, bundle2: Bundle?, callback: IAssetModuleServiceCallback?) {\n        run(uncheckedPackageName, \"getChunkFileDescriptor\", callback, { packageName ->\n            val moduleName = bundle.get(BundleKeys.MODULE_NAME)!!.also { require(it.isNotEmpty()) }\n            GetChunkFileDescriptorParameters(\n                moduleName,\n                bundle.get(BundleKeys.SLICE_ID)!!,\n                bundle.get(BundleKeys.CHUNK_NUMBER, 0),\n                bundle.get(BundleKeys.SESSION_ID, getDefaultSessionId(packageName, moduleName)),\n                bundle2.getOptions()\n            )\n        }, this::getChunkFileDescriptor)\n    }\n\n    abstract suspend fun getChunkFileDescriptor(params: GetChunkFileDescriptorParameters, packageName: String, callback: IAssetModuleServiceCallback?)\n\n    override fun requestDownloadInfo(uncheckedPackageName: String?, list: MutableList<Bundle>?, bundle: Bundle?, callback: IAssetModuleServiceCallback?) {\n        run(uncheckedPackageName, \"requestDownloadInfo\", callback, { _ ->\n            RequestDownloadInfoParameters(list!!.getModuleNames().also { require(it.isNotEmpty()) }, bundle.getInstalledAssetModules(), bundle.getOptions())\n        }, this::requestDownloadInfo)\n    }\n\n    abstract suspend fun requestDownloadInfo(params: RequestDownloadInfoParameters, packageName: String, callback: IAssetModuleServiceCallback?)\n\n    override fun removeModule(uncheckedPackageName: String?, bundle: Bundle?, bundle2: Bundle?, callback: IAssetModuleServiceCallback?) {\n        run(uncheckedPackageName, \"removeModule\", callback, { packageName ->\n            val moduleName = bundle?.get(BundleKeys.MODULE_NAME)!!\n            RemoveModuleParameters(\n                moduleName,\n                bundle.get(BundleKeys.SESSION_ID, getDefaultSessionId(packageName, moduleName)),\n                bundle2.getOptions()\n            )\n        }, this::removeModule)\n    }\n\n    abstract suspend fun removeModule(params: RemoveModuleParameters, packageName: String, callback: IAssetModuleServiceCallback?)\n\n    override fun cancelDownloads(uncheckedPackageName: String?, list: MutableList<Bundle>?, bundle: Bundle?, callback: IAssetModuleServiceCallback?) {\n        run(uncheckedPackageName, \"cancelDownloads\", callback, { _ ->\n            CancelDownloadsParameters(list!!.getModuleNames().also { require(it.isNotEmpty()) }, bundle.getOptions())\n        }, this::cancelDownloads)\n    }\n\n    abstract suspend fun cancelDownloads(params: CancelDownloadsParameters, packageName: String, callback: IAssetModuleServiceCallback?)\n\n    override fun keepAlive(packageName: String?, bundle: Bundle?, callback: IAssetModuleServiceCallback?) {\n        run(packageName, \"keepAlive\", callback, { KeepAliveParameters(bundle.getOptions()) }, this::keepAlive)\n    }\n\n    abstract suspend fun keepAlive(params: KeepAliveParameters, packageName: String, callback: IAssetModuleServiceCallback?)\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =\n        warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n}"
  },
  {
    "path": "vending-app/src/main/kotlin/com/google/android/finsky/assetmoduleservice/AssetModuleService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.finsky.assetmoduleservice\n\nimport android.accounts.AccountManager\nimport android.content.Context\nimport android.content.Intent\nimport android.net.Uri\nimport android.os.Bundle\nimport android.os.IBinder\nimport android.os.ParcelFileDescriptor\nimport android.util.Log\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.LifecycleService\nimport com.google.android.finsky.*\nimport com.google.android.play.core.assetpacks.model.AssetPackErrorCode\nimport com.google.android.play.core.assetpacks.model.AssetPackStatus\nimport com.google.android.play.core.assetpacks.protocol.BundleKeys\nimport com.google.android.play.core.assetpacks.protocol.IAssetModuleServiceCallback\nimport org.microg.gms.profile.ProfileManager\nimport org.microg.vending.billing.core.HttpClient\nimport java.io.File\n\nconst val TAG = \"AssetModuleService\"\n\nclass AssetModuleService : LifecycleService() {\n    private lateinit var httpClient: HttpClient\n    private lateinit var accountManager: AccountManager\n\n    override fun onBind(intent: Intent): IBinder {\n        super.onBind(intent)\n        Log.d(TAG, \"onBind: \")\n        ProfileManager.ensureInitialized(this)\n        accountManager = AccountManager.get(this)\n        httpClient = HttpClient()\n        return AssetModuleServiceImpl(this, lifecycle, httpClient, accountManager, packageDownloadData).asBinder()\n    }\n\n    override fun onDestroy() {\n        Log.d(TAG, \"onDestroy: \")\n        // TODO cancel downloads\n        super.onDestroy()\n    }\n\n    companion object {\n        private val packageDownloadData = mutableMapOf<String, DownloadData?>()\n    }\n}\n\nclass AssetModuleServiceImpl(\n    context: Context, lifecycle: Lifecycle,\n    private val httpClient: HttpClient,\n    private val accountManager: AccountManager,\n    private val packageDownloadData: MutableMap<String, DownloadData?>\n) : AbstractAssetModuleServiceImpl(context, lifecycle) {\n    private val fileDescriptorMap = mutableMapOf<File, ParcelFileDescriptor>()\n    private val lock = Any()\n\n    private fun checkSessionValid(packageName: String, sessionId: Int) {\n        Log.d(TAG, \"checkSessionValid: $packageName $sessionId ${packageDownloadData[packageName]?.sessionIds}\")\n        if (packageDownloadData[packageName]?.sessionIds?.values?.contains(sessionId) != true) {\n            Log.w(TAG, \"No active session with id $sessionId in $packageName\")\n            throw AssetPackException(AssetPackErrorCode.ACCESS_DENIED)\n        }\n    }\n\n    override fun getDefaultSessionId(packageName: String, moduleName: String): Int = synchronized(lock) {\n        packageDownloadData[packageName]?.sessionIds?.get(moduleName) ?: 0\n    }\n\n    override suspend fun startDownload(params: StartDownloadParameters, packageName: String, callback: IAssetModuleServiceCallback?) {\n        val needInit = synchronized(lock) {\n            packageDownloadData[packageName] == null ||\n                packageDownloadData[packageName]?.packageName != packageName ||\n                packageDownloadData[packageName]?.moduleNames?.intersect(params.moduleNames.toSet())?.isEmpty() == true\n        }\n\n        if (needInit) {\n            val newData = httpClient.initAssetModuleData(context, packageName, accountManager, params.moduleNames, params.options)\n            synchronized(lock) {\n                packageDownloadData[packageName] = packageDownloadData[packageName].merge(newData)\n            }\n            if (packageDownloadData[packageName] == null) {\n                throw AssetPackException(AssetPackErrorCode.API_NOT_AVAILABLE)\n            }\n        }\n        if (packageDownloadData[packageName] != null && packageDownloadData[packageName]?.moduleNames?.all {\n                packageDownloadData[packageName]?.getModuleData(it)?.status == AssetPackStatus.COMPLETED\n            } == true && params.installedAssetModules.isEmpty()) {\n            Log.d(TAG, \"startDownload: resetAllModuleStatus \")\n            packageDownloadData[packageName]?.resetAllModuleStatus()\n        }\n        params.moduleNames.forEach {\n            val moduleData = packageDownloadData[packageName]?.getModuleData(it)\n            if (moduleData?.status != AssetPackStatus.DOWNLOADING && moduleData?.status != AssetPackStatus.COMPLETED) {\n                packageDownloadData[packageName]?.updateDownloadStatus(it, AssetPackStatus.PENDING)\n                sendBroadcastForExistingFile(context, packageDownloadData[packageName]!!, it, null, null)\n            }\n            if (moduleData?.status == AssetPackStatus.FAILED) {\n                // FIXME: If we start download later, we shouldn't send a failure callback now\n                callback?.onError(Bundle().apply { put(BundleKeys.ERROR_CODE, AssetPackErrorCode.NETWORK_ERROR) })\n            }\n            packageDownloadData[packageName]?.getModuleData(it)?.chunks?.forEach { chunkData ->\n                val destination = chunkData.getChunkFile(context)\n                if (destination.exists() && destination.length() == chunkData.chunkBytesToDownload) {\n                    sendBroadcastForExistingFile(context, packageDownloadData[packageName]!!, it, chunkData, destination)\n                }\n            }\n        }\n        val bundleData = buildDownloadBundle(packageDownloadData[packageName]!!, params.moduleNames)\n        Log.d(TAG, \"startDownload: $bundleData\")\n        callback?.onStartDownload(-1, bundleData)\n        params.moduleNames.forEach {\n            val packData = packageDownloadData[packageName]?.getModuleData(it)\n            if (packData?.status == AssetPackStatus.PENDING) {\n                DownloadManager.get(context).shouldStop(false)\n                DownloadManager.get(context).prepareDownload(packageDownloadData[packageName]!!, it)\n            }\n        }\n    }\n\n    override suspend fun getSessionStates(params: GetSessionStatesParameters, packageName: String, callback: IAssetModuleServiceCallback?) {\n        val listBundleData: MutableList<Bundle> = mutableListOf()\n\n        synchronized(lock) {\n            if (packageDownloadData[packageName] != null && packageDownloadData[packageName]?.moduleNames?.all {\n                    packageDownloadData[packageName]?.getModuleData(it)?.status == AssetPackStatus.COMPLETED\n                } == true && params.installedAssetModules.isEmpty()) {\n                Log.d(TAG, \"getSessionStates: resetAllModuleStatus: $listBundleData\")\n                packageDownloadData[packageName]?.resetAllModuleStatus()\n                callback?.onGetSessionStates(listBundleData)\n                return\n            }\n\n            packageDownloadData[packageName]?.moduleNames?.forEach { moduleName ->\n                if (moduleName in params.installedAssetModules) return@forEach\n\n                listBundleData.add(sendBroadcastForExistingFile(context, packageDownloadData[packageName]!!, moduleName, null, null))\n\n                packageDownloadData[packageName]?.getModuleData(moduleName)?.chunks?.forEach { chunkData ->\n                    val destination = chunkData.getChunkFile(context)\n                    if (destination.exists() && destination.length() == chunkData.chunkBytesToDownload) {\n                        sendBroadcastForExistingFile(context, packageDownloadData[packageName]!!, moduleName, chunkData, destination)\n                    }\n                }\n            }\n        }\n\n        Log.d(TAG, \"getSessionStates: $listBundleData\")\n        callback?.onGetSessionStates(listBundleData)\n    }\n\n    override suspend fun notifyChunkTransferred(params: NotifyChunkTransferredParameters, packageName: String, callback: IAssetModuleServiceCallback?) {\n        checkSessionValid(packageName, params.sessionId)\n\n        synchronized(lock) {\n            val downLoadFile = context.getChunkFile(params.sessionId, params.moduleName, params.sliceId, params.chunkNumber)\n            fileDescriptorMap[downLoadFile]?.close()\n            fileDescriptorMap.remove(downLoadFile)\n        }\n        // TODO: Remove chunk after successful transfer of chunk or only with module?\n        callback?.onNotifyChunkTransferred(\n            bundleOf(BundleKeys.MODULE_NAME to params.moduleName) +\n                    (BundleKeys.SLICE_ID to params.sliceId) +\n                    (BundleKeys.CHUNK_NUMBER to params.chunkNumber) +\n                    (BundleKeys.SESSION_ID to params.sessionId),\n            bundleOf(BundleKeys.ERROR_CODE to AssetPackErrorCode.NO_ERROR)\n        )\n    }\n\n    override suspend fun notifyModuleCompleted(params: NotifyModuleCompletedParameters, packageName: String, callback: IAssetModuleServiceCallback?) {\n        checkSessionValid(packageName, params.sessionId)\n\n        synchronized(lock) {\n            packageDownloadData[packageName]?.updateDownloadStatus(params.moduleName, AssetPackStatus.COMPLETED)\n            sendBroadcastForExistingFile(context, packageDownloadData[packageName]!!, params.moduleName, null, null)\n        }\n\n        val directory = context.getModuleDir(params.sessionId, params.moduleName)\n        if (directory.exists()) {\n            directory.deleteRecursively()\n            Log.d(TAG, \"Directory $directory deleted successfully.\")\n        } else {\n            Log.d(TAG, \"Directory $directory does not exist.\")\n        }\n        callback?.onNotifyModuleCompleted(\n            bundleOf(BundleKeys.MODULE_NAME to params.moduleName) +\n                    (BundleKeys.SESSION_ID to params.sessionId),\n            bundleOf(BundleKeys.ERROR_CODE to AssetPackErrorCode.NO_ERROR)\n        )\n    }\n\n    override suspend fun notifySessionFailed(params: NotifySessionFailedParameters, packageName: String, callback: IAssetModuleServiceCallback?) {\n        checkSessionValid(packageName, params.sessionId)\n\n        // TODO: Implement\n        callback?.onNotifySessionFailed(bundleOf(BundleKeys.SESSION_ID to params.sessionId))\n        //throw UnsupportedOperationException()\n    }\n\n    override suspend fun keepAlive(params: KeepAliveParameters, packageName: String, callback: IAssetModuleServiceCallback?) {\n        // TODO: Implement\n        // Not throwing an exception is the better fallback implementation\n    }\n\n    override suspend fun getChunkFileDescriptor(params: GetChunkFileDescriptorParameters, packageName: String, callback: IAssetModuleServiceCallback?) {\n        checkSessionValid(packageName, params.sessionId)\n\n        val parcelFileDescriptor = synchronized(lock) {\n            val downLoadFile = context.getChunkFile(params.sessionId, params.moduleName, params.sliceId, params.chunkNumber)\n            ParcelFileDescriptor.open(downLoadFile, ParcelFileDescriptor.MODE_READ_ONLY).also {\n                fileDescriptorMap[downLoadFile] = it\n            }\n        }\n\n        Log.d(TAG, \"getChunkFileDescriptor -> $parcelFileDescriptor\")\n        callback?.onGetChunkFileDescriptor(\n            bundleOf(BundleKeys.CHUNK_FILE_DESCRIPTOR to parcelFileDescriptor),\n            bundleOf(BundleKeys.ERROR_CODE to AssetPackErrorCode.NO_ERROR)\n        )\n    }\n\n    override suspend fun requestDownloadInfo(params: RequestDownloadInfoParameters, packageName: String, callback: IAssetModuleServiceCallback?) {\n        val needInit = synchronized(lock) {\n            packageDownloadData[packageName] == null ||\n                packageDownloadData[packageName]?.packageName != packageName ||\n                packageDownloadData[packageName]?.moduleNames?.intersect(params.moduleNames.toSet())?.isEmpty() == true\n        }\n\n        if (needInit) {\n            val newData = httpClient.initAssetModuleData(context, packageName, accountManager, params.moduleNames, params.options)\n            synchronized(lock) {\n                packageDownloadData[packageName] = packageDownloadData[packageName].merge(newData)\n            }\n            if (packageDownloadData[packageName] == null) {\n                throw AssetPackException(AssetPackErrorCode.API_NOT_AVAILABLE)\n            }\n        }\n        if (packageDownloadData[packageName] != null && packageDownloadData[packageName]?.moduleNames?.all {\n                packageDownloadData[packageName]?.getModuleData(it)?.status == AssetPackStatus.COMPLETED\n            } == true && params.installedAssetModules.isEmpty()) {\n            Log.d(TAG, \"requestDownloadInfo: resetAllModuleStatus \")\n            packageDownloadData[packageName]?.resetAllModuleStatus()\n        }\n        params.moduleNames.forEach {\n            val packData = packageDownloadData[packageName]?.getModuleData(it)\n            if (packData?.status == AssetPackStatus.FAILED) {\n                // FIXME: If we start download later, we shouldn't send a failure callback now\n                callback?.onError(Bundle().apply { put(BundleKeys.ERROR_CODE, AssetPackErrorCode.NETWORK_ERROR) })\n            }\n        }\n        val bundleData = buildDownloadBundle(packageDownloadData[packageName]!!, params.moduleNames)\n        Log.d(TAG, \"requestDownloadInfo -> $bundleData\")\n        callback?.onRequestDownloadInfo(bundleData, bundleData)\n    }\n\n    override suspend fun removeModule(params: RemoveModuleParameters, packageName: String, callback: IAssetModuleServiceCallback?) {\n        checkSessionValid(packageName, params.sessionId)\n        // TODO: Implement\n        throw UnsupportedOperationException()\n    }\n\n    override suspend fun cancelDownloads(params: CancelDownloadsParameters, packageName: String, callback: IAssetModuleServiceCallback?) {\n        // TODO: Implement\n        callback?.onCancelDownloads(bundleOf(BundleKeys.ERROR_CODE to AssetPackErrorCode.NO_ERROR))\n        //throw UnsupportedOperationException()\n    }\n}"
  },
  {
    "path": "vending-app/src/main/kotlin/com/google/android/finsky/assetmoduleservice/DownloadData.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.finsky.assetmoduleservice\n\nimport android.content.Context\nimport android.util.Log\nimport com.google.android.finsky.getChunkFile\nimport com.google.android.play.core.assetpacks.model.AssetPackStatus\nimport com.google.android.play.core.assetpacks.protocol.CompressionFormat\nimport java.io.File\nimport java.io.Serializable\n\ndata class DownloadData(\n    var packageName: String = \"\",\n    var errorCode: Int = 0,\n    var sessionIds: Map<String, Int> = emptyMap(),\n    var status: Int = 0,\n    var moduleNames: Set<String> = emptySet(),\n    var appVersionCode: Long = 0,\n    var moduleDataMap: Map<String, ModuleData> = emptyMap()\n) : Serializable {\n\n    fun getModuleData(moduleName: String): ModuleData {\n        return moduleDataMap[moduleName] ?: throw IllegalArgumentException(\"ModuleData for moduleName '$moduleName' not found.\")\n    }\n\n    fun incrementModuleBytesDownloaded(packName: String, bytes: Long) {\n        getModuleData(packName).incrementBytesDownloaded(bytes)\n    }\n\n    fun updateDownloadStatus(packName: String, statusCode: Int) {\n        getModuleData(packName).apply {\n            status = statusCode\n        }\n    }\n\n    fun resetAllModuleStatus() {\n        // After the user clears the data, the completed module needs to be reset\n        status = AssetPackStatus.NOT_INSTALLED\n        moduleNames.forEach { getModuleData(it).resetStatus() }\n    }\n}\n\nfun DownloadData?.merge(data: DownloadData?): DownloadData? {\n    if (this == null) return data\n    if (data == null) return this\n    moduleNames += data.moduleNames\n    sessionIds += data.sessionIds.filter { it.key !in sessionIds.keys }\n    moduleDataMap += data.moduleDataMap.filter { it.key !in moduleDataMap.keys }\n    return this\n}\n\ndata class ModuleData(\n    var packVersionCode: Long = 0,\n    var moduleVersion: Long = 0,\n    var errorCode: Int = 0,\n    var status: Int = 0,\n    var bytesDownloaded: Long = 0,\n    var totalBytesToDownload: Long = 0,\n    var chunks: List<ChunkData> = emptyList(),\n    var sliceIds: ArrayList<String>? = null\n) : Serializable {\n    fun incrementBytesDownloaded(bytes: Long) {\n        bytesDownloaded += bytes\n    }\n    fun resetStatus() {\n        bytesDownloaded = 0\n        status = AssetPackStatus.NOT_INSTALLED\n    }\n}\n\ndata class ChunkData(\n    var sessionId: Int,\n    val moduleName: String,\n    val sliceId: String,\n    val chunkSourceUri: String?,\n    val chunkBytesToDownload: Long,\n    val chunkIndex: Int,\n    val sliceCompressionFormat: @CompressionFormat Int,\n    val sliceUncompressedSize: Long,\n    val sliceUncompressedHashSha256: String?,\n    val numberOfChunksInSlice: Int\n)\n\nfun ChunkData.getChunkFile(context: Context) = context.getChunkFile(sessionId, moduleName, sliceId, chunkIndex)"
  },
  {
    "path": "vending-app/src/main/kotlin/com/google/android/finsky/expressintegrityservice/DeviceIntegrity.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.finsky.expressintegrityservice\n\nimport com.google.android.finsky.ClientKey\nimport okio.ByteString\nimport org.microg.vending.proto.Timestamp\n\ndata class DeviceIntegrity(\n    var clientKey: ClientKey?, var deviceIntegrityToken: ByteString?, var creationTime: Timestamp?, var lastManualSoftRefreshTime: Timestamp?\n)"
  },
  {
    "path": "vending-app/src/main/kotlin/com/google/android/finsky/expressintegrityservice/DeviceIntegrityAndExpiredKey.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.finsky.expressintegrityservice\n\ndata class DeviceIntegrityAndExpiredKey(var deviceIntegrity: DeviceIntegrity, var expiredDeviceKey: Any?)"
  },
  {
    "path": "vending-app/src/main/kotlin/com/google/android/finsky/expressintegrityservice/DeviceIntegrityResponse.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.finsky.expressintegrityservice\ndata class DeviceIntegrityResponse(\n    var deviceIntegrity: DeviceIntegrity, var attemptedDroidGuardTokenRefresh: Boolean, var deviceKeyMd5: String, var expiredDeviceKey: Any?\n)\n"
  },
  {
    "path": "vending-app/src/main/kotlin/com/google/android/finsky/expressintegrityservice/ExpressIntegrityService.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.finsky.expressintegrityservice\n\nimport android.accounts.AccountManager\nimport android.content.Context\nimport android.content.Intent\nimport android.content.pm.PackageManager\nimport android.os.Bundle\nimport android.os.IBinder\nimport android.text.TextUtils\nimport android.util.Base64\nimport android.util.Log\nimport androidx.core.os.bundleOf\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.LifecycleOwner\nimport androidx.lifecycle.LifecycleService\nimport androidx.lifecycle.lifecycleScope\nimport com.android.vending.AUTH_TOKEN_SCOPE\nimport com.android.vending.VendingPreferences\nimport com.android.vending.makeTimestamp\nimport com.google.android.finsky.AuthTokenWrapper\nimport com.google.android.finsky.ClientKey\nimport com.google.android.finsky.DeviceIntegrityWrapper\nimport com.google.android.finsky.ExpressIntegrityResponse\nimport com.google.android.finsky.INTERMEDIATE_INTEGRITY_HARD_EXPIRATION\nimport com.google.android.finsky.IntegrityAdvice\nimport com.google.android.finsky.IntermediateIntegrityRequest\nimport com.google.android.finsky.IntermediateIntegrityResponse\nimport com.google.android.finsky.IntermediateIntegritySession\nimport com.google.android.finsky.KEY_CLOUD_PROJECT\nimport com.google.android.finsky.KEY_ERROR\nimport com.google.android.finsky.KEY_NONCE\nimport com.google.android.finsky.KEY_PACKAGE_NAME\nimport com.google.android.finsky.KEY_REQUEST_MODE\nimport com.google.android.finsky.KEY_REQUEST_TOKEN_SID\nimport com.google.android.finsky.KEY_REQUEST_VERDICT_OPT_OUT\nimport com.google.android.finsky.KEY_TOKEN\nimport com.google.android.finsky.KEY_WARM_UP_SID\nimport com.google.android.finsky.PlayProtectDetails\nimport com.google.android.finsky.PlayProtectState\nimport com.google.android.finsky.RESULT_UN_AUTH\nimport com.google.android.finsky.RequestMode\nimport com.google.android.finsky.TestErrorType\nimport com.google.android.finsky.buildClientKeyExtend\nimport com.google.android.finsky.buildInstallSourceMetaData\nimport com.google.android.finsky.callerAppToIntegrityData\nimport com.google.android.finsky.encodeBase64\nimport com.google.android.finsky.ensureContainsLockBootloader\nimport com.google.android.finsky.getAuthToken\nimport com.google.android.finsky.getExpirationTime\nimport com.google.android.finsky.getIntegrityRequestWrapper\nimport com.google.android.finsky.getPackageInfoCompat\nimport com.google.android.finsky.getPlayCoreVersion\nimport com.google.android.finsky.isNetworkConnected\nimport com.google.android.finsky.md5\nimport com.google.android.finsky.model.IntegrityErrorCode\nimport com.google.android.finsky.model.StandardIntegrityException\nimport com.google.android.finsky.readAes128GcmBuilderFromClientKey\nimport com.google.android.finsky.requestIntermediateIntegrity\nimport com.google.android.finsky.sha256\nimport com.google.android.finsky.signaturesCompat\nimport com.google.android.finsky.updateAppIntegrityContent\nimport com.google.android.finsky.updateExpressAuthTokenWrapper\nimport com.google.android.finsky.updateExpressClientKey\nimport com.google.android.finsky.updateExpressSessionTime\nimport com.google.android.finsky.updateLocalExpressFilePB\nimport com.google.android.finsky.validateIntermediateIntegrityResponse\nimport com.google.android.play.core.integrity.protocol.IExpressIntegrityService\nimport com.google.android.play.core.integrity.protocol.IExpressIntegrityServiceCallback\nimport com.google.android.play.core.integrity.protocol.IRequestDialogCallback\nimport com.google.crypto.tink.config.TinkConfig\nimport okio.ByteString.Companion.toByteString\nimport org.microg.gms.profile.ProfileManager\nimport org.microg.gms.vending.PlayIntegrityData\nimport org.microg.vending.billing.DEFAULT_ACCOUNT_TYPE\nimport org.microg.vending.proto.Timestamp\nimport kotlin.random.Random\n\nprivate const val TAG = \"ExpressIntegrityService\"\n\nclass ExpressIntegrityService : LifecycleService() {\n\n    override fun onBind(intent: Intent): IBinder? {\n        super.onBind(intent)\n        ProfileManager.ensureInitialized(this)\n        Log.d(TAG, \"onBind\")\n        TinkConfig.register()\n        return ExpressIntegrityServiceImpl(this, lifecycle).asBinder()\n    }\n\n    override fun onUnbind(intent: Intent?): Boolean {\n        Log.d(TAG, \"onUnbind\")\n        return super.onUnbind(intent)\n    }\n}\n\nprivate class ExpressIntegrityServiceImpl(private val context: Context, override val lifecycle: Lifecycle) : IExpressIntegrityService.Stub(), LifecycleOwner {\n\n    private var visitData: PlayIntegrityData? = null\n\n    override fun warmUpIntegrityToken(bundle: Bundle, callback: IExpressIntegrityServiceCallback?) {\n        lifecycleScope.launchWhenCreated {\n            runCatching {\n                val callingPackageName = bundle.getString(KEY_PACKAGE_NAME)\n                if (callingPackageName == null) {\n                    throw StandardIntegrityException(IntegrityErrorCode.INTERNAL_ERROR, \"Null packageName.\")\n                }\n                visitData = callerAppToIntegrityData(context, callingPackageName)\n                if (visitData?.allowed != true) {\n                    throw StandardIntegrityException(IntegrityErrorCode.API_NOT_AVAILABLE, \"Not allowed visit\")\n                }\n                val playIntegrityEnabled = VendingPreferences.isDeviceAttestationEnabled(context)\n                if (!playIntegrityEnabled) {\n                    throw StandardIntegrityException(IntegrityErrorCode.API_NOT_AVAILABLE, \"API is disabled\")\n                }\n\n                if (!context.isNetworkConnected()) {\n                    throw StandardIntegrityException(IntegrityErrorCode.NETWORK_ERROR, \"No network is available\")\n                }\n\n                val expressIntegritySession = ExpressIntegritySession(\n                    packageName = callingPackageName ?: \"\",\n                    cloudProjectNumber = bundle.getLong(KEY_CLOUD_PROJECT, 0L),\n                    sessionId = Random.nextLong(),\n                    null,\n                    0,\n                    null,\n                    webViewRequestMode = bundle.getInt(KEY_REQUEST_MODE, 0)\n                )\n                Log.d(TAG, \"warmUpIntegrityToken session:$expressIntegritySession}\")\n\n                updateExpressSessionTime(context, expressIntegritySession, refreshWarmUpMethodTime = true, refreshRequestMethodTime = false)\n\n                val clientKey = updateExpressClientKey(context)\n\n                val authToken = getAuthToken(context, AUTH_TOKEN_SCOPE)\n                if (TextUtils.isEmpty(authToken)) {\n                    Log.w(TAG, \"warmUpIntegrityToken: Got null auth token for type: $AUTH_TOKEN_SCOPE\")\n                }\n                Log.d(TAG, \"warmUpIntegrityToken authToken: $authToken\")\n\n                val expressFilePB = updateExpressAuthTokenWrapper(context, expressIntegritySession, authToken, clientKey)\n\n                val tokenWrapper = expressFilePB.tokenWrapper ?: AuthTokenWrapper()\n                val tokenClientKey = tokenWrapper.clientKey ?: ClientKey()\n                val deviceIntegrityWrapper = tokenWrapper.deviceIntegrityWrapper ?: DeviceIntegrityWrapper()\n                val creationTime = tokenWrapper.deviceIntegrityWrapper?.creationTime ?: Timestamp()\n                val lastManualSoftRefreshTime = tokenWrapper.lastManualSoftRefreshTime ?: Timestamp()\n\n                val deviceIntegrityAndExpiredKey = DeviceIntegrityAndExpiredKey(\n                    deviceIntegrity = DeviceIntegrity(\n                        tokenClientKey, deviceIntegrityWrapper.deviceIntegrityToken, creationTime, lastManualSoftRefreshTime\n                    ), expressFilePB.expiredDeviceKey ?: ClientKey()\n                )\n\n                val deviceIntegrity = deviceIntegrityAndExpiredKey.deviceIntegrity\n                if (deviceIntegrity.deviceIntegrityToken?.size == 0 || deviceIntegrity.clientKey?.keySetHandle?.size == 0) {\n                    throw StandardIntegrityException(\"DroidGuard token is empty.\")\n                }\n\n                val deviceKeyMd5 = Base64.encodeToString(\n                    deviceIntegrity.clientKey?.keySetHandle?.md5()?.toByteArray(), Base64.NO_PADDING or Base64.NO_WRAP or Base64.URL_SAFE\n                )\n                if (deviceKeyMd5.isNullOrEmpty()) {\n                    throw StandardIntegrityException(\"Null deviceKeyMd5.\")\n                }\n\n                val deviceIntegrityResponse = DeviceIntegrityResponse(\n                    deviceIntegrity, false, deviceKeyMd5, deviceIntegrityAndExpiredKey.expiredDeviceKey\n                )\n\n                val packageInfo = context.packageManager.getPackageInfoCompat(\n                    expressIntegritySession.packageName, PackageManager.GET_SIGNING_CERTIFICATES or PackageManager.GET_SIGNATURES\n                )\n                val certificateSha256Hashes = packageInfo.signaturesCompat.map {\n                    it.toByteArray().sha256().encodeBase64(noPadding = true, noWrap = true, urlSafe = true)\n                }\n\n                val packageInformation = PackageInformation(certificateSha256Hashes, packageInfo.versionCode)\n                val clientKeyExtend = buildClientKeyExtend(context, expressIntegritySession, packageInformation, clientKey)\n                val intermediateIntegrityRequest = IntermediateIntegrityRequest.Builder().apply {\n                    deviceIntegrityToken(deviceIntegrityResponse.deviceIntegrity.deviceIntegrityToken)\n                    readAes128GcmBuilderFromClientKey(deviceIntegrityResponse.deviceIntegrity.clientKey)?.let {\n                        clientKeyExtendBytes(it.encrypt(clientKeyExtend.encode(), null).toByteString())\n                    }\n                    playCoreVersion(bundle.getPlayCoreVersion())\n                    sessionId(expressIntegritySession.sessionId)\n                    installSourceMetaData(buildInstallSourceMetaData(context, expressIntegritySession.packageName))\n                    cloudProjectNumber(expressIntegritySession.cloudProjectNumber)\n                    playProtectDetails(PlayProtectDetails(PlayProtectState.PLAY_PROTECT_STATE_NONE))\n                    if (expressIntegritySession.webViewRequestMode != 0) {\n                        requestMode(RequestMode.Builder().mode(expressIntegritySession.webViewRequestMode.takeIf { it in 0..2 } ?: 0).build())\n                    }\n                }.build()\n\n                Log.d(TAG, \"intermediateIntegrityRequest: $intermediateIntegrityRequest\")\n\n                val intermediateIntegrityResponse = requestIntermediateIntegrity(context, authToken, intermediateIntegrityRequest).intermediateIntegrityResponseWrapper?.intermediateIntegrityResponse\n                    ?: IntermediateIntegrityResponse()\n\n                Log.d(TAG, \"requestIntermediateIntegrity response: ${intermediateIntegrityResponse.encode().encodeBase64(true)}\")\n\n                val errorCode = intermediateIntegrityResponse.errorInfo?.let { error ->\n                    if (error.errorCode == null) {\n                        null\n                    } else if (error.testErrorType == TestErrorType.REQUEST_EXPRESS) {\n                        error.errorCode\n                    } else if (error.testErrorType == TestErrorType.WARMUP) {\n                        throw StandardIntegrityException(error.errorCode, \"Server-specified exception\")\n                    } else null\n                }\n\n                val defaultAccountName: String = runCatching {\n                    if (expressIntegritySession.webViewRequestMode != 0) {\n                        RESULT_UN_AUTH\n                    } else {\n                        AccountManager.get(context).getAccountsByType(DEFAULT_ACCOUNT_TYPE).firstOrNull()?.name ?: RESULT_UN_AUTH\n                    }\n                }.getOrDefault(RESULT_UN_AUTH)\n\n                val callerKeyMd5 = clientKey.encode().md5() ?: throw StandardIntegrityException(\"Null callerKeyMd5\")\n                val refreshClientKey = clientKey.newBuilder()\n                    .generated(makeTimestamp(System.currentTimeMillis()))\n                    .build()\n                val fixedAdvice = IntegrityAdvice.Builder()\n                    .advices(intermediateIntegrityResponse.integrityAdvice?.advices.ensureContainsLockBootloader())\n                    .build()\n                val intermediateIntegrityResponseData = IntermediateIntegrityResponseData(\n                    intermediateIntegrity = IntermediateIntegrity(\n                        expressIntegritySession.packageName,\n                        expressIntegritySession.cloudProjectNumber,\n                        defaultAccountName,\n                        refreshClientKey,\n                        intermediateIntegrityResponse.intermediateToken,\n                        intermediateIntegrityResponse.serverGenerated,\n                        expressIntegritySession.webViewRequestMode,\n                        errorCode,\n                        fixedAdvice\n                    ),\n                    callerKeyMd5 = callerKeyMd5.encodeBase64(noPadding = true),\n                    appVersionCode = packageInformation.versionCode,\n                    deviceIntegrityResponse = deviceIntegrityResponse,\n                    appAccessRiskVerdictEnabled = intermediateIntegrityResponse.appAccessRiskVerdictEnabled\n                )\n\n                validateIntermediateIntegrityResponse(intermediateIntegrityResponseData)\n\n                updateLocalExpressFilePB(context, intermediateIntegrityResponseData)\n\n                visitData?.updateAppIntegrityContent(context, System.currentTimeMillis(), \"$TAG visited success.\", true)\n                callback?.onWarmResult(bundleOf(KEY_WARM_UP_SID to expressIntegritySession.sessionId))\n            }.onFailure {\n                val exception = it as? StandardIntegrityException ?: StandardIntegrityException(it.message)\n                Log.w(TAG, \"warm up has failed: code=${exception.code}, message=${exception.message}\", exception)\n                visitData?.updateAppIntegrityContent(context, System.currentTimeMillis(), \"$TAG visited failed. ${exception.message}\")\n                callback?.onWarmResult(bundleOf(KEY_ERROR to exception.code))\n            }\n        }\n    }\n\n    override fun requestExpressIntegrityToken(bundle: Bundle, callback: IExpressIntegrityServiceCallback?) {\n        Log.d(TAG, \"requestExpressIntegrityToken bundle:$bundle\")\n        lifecycleScope.launchWhenCreated {\n            runCatching {\n                val callingPackageName = bundle.getString(KEY_PACKAGE_NAME)\n                if (callingPackageName == null) {\n                    throw StandardIntegrityException(IntegrityErrorCode.INTERNAL_ERROR, \"Null packageName.\")\n                }\n                visitData = callerAppToIntegrityData(context, callingPackageName)\n                if (visitData?.allowed != true) {\n                    throw StandardIntegrityException(IntegrityErrorCode.API_NOT_AVAILABLE, \"Not allowed visit\")\n                }\n                val playIntegrityEnabled = VendingPreferences.isDeviceAttestationEnabled(context)\n                if (!playIntegrityEnabled) {\n                    throw StandardIntegrityException(IntegrityErrorCode.API_NOT_AVAILABLE, \"API is disabled\")\n                }\n\n                val expressIntegritySession = ExpressIntegritySession(\n                    packageName = callingPackageName,\n                    cloudProjectNumber = bundle.getLong(KEY_CLOUD_PROJECT, 0L),\n                    sessionId = Random.nextLong(),\n                    requestHash = bundle.getString(KEY_NONCE),\n                    originatingWarmUpSessionId = bundle.getLong(KEY_WARM_UP_SID, 0),\n                    verdictOptOut = bundle.getIntegerArrayList(KEY_REQUEST_VERDICT_OPT_OUT),\n                    webViewRequestMode = bundle.getInt(KEY_REQUEST_MODE, 0)\n                )\n\n                Log.d(TAG, \"requestExpressIntegrityToken session:$expressIntegritySession}\")\n\n                if (TextUtils.isEmpty(expressIntegritySession.packageName)) {\n                    Log.w(TAG, \"packageName is empty.\")\n                    callback?.onRequestResult(bundleOf(KEY_ERROR to IntegrityErrorCode.INTERNAL_ERROR))\n                    return@launchWhenCreated\n                }\n\n                if (expressIntegritySession.cloudProjectNumber <= 0L) {\n                    Log.w(TAG, \"cloudProjectVersion error\")\n                    callback?.onRequestResult(bundleOf(KEY_ERROR to IntegrityErrorCode.CLOUD_PROJECT_NUMBER_IS_INVALID))\n                    return@launchWhenCreated\n                }\n\n                if (expressIntegritySession.requestHash?.length!! > 500) {\n                    Log.w(TAG, \"requestHash error\")\n                    callback?.onRequestResult(bundleOf(KEY_ERROR to IntegrityErrorCode.REQUEST_HASH_TOO_LONG))\n                    return@launchWhenCreated\n                }\n\n                updateExpressSessionTime(context, expressIntegritySession, refreshWarmUpMethodTime = false, refreshRequestMethodTime = true)\n\n                val defaultAccountName: String = runCatching {\n                    if (expressIntegritySession.webViewRequestMode != 0) {\n                        RESULT_UN_AUTH\n                    } else {\n                        AccountManager.get(context).getAccountsByType(DEFAULT_ACCOUNT_TYPE).firstOrNull()?.name ?: RESULT_UN_AUTH\n                    }\n                }.getOrDefault(RESULT_UN_AUTH)\n\n                val integrityRequestWrapper = getIntegrityRequestWrapper(context, expressIntegritySession, defaultAccountName)\n                if (integrityRequestWrapper == null) {\n                    Log.w(TAG, \"integrityRequestWrapper is null\")\n                    callback?.onRequestResult(bundleOf(KEY_ERROR to IntegrityErrorCode.INTEGRITY_TOKEN_PROVIDER_INVALID))\n                    return@launchWhenCreated\n                }\n\n                integrityRequestWrapper.deviceIntegrityWrapper?.errorCode?.let {\n                    throw StandardIntegrityException(it, \"Server-specified exception\")\n                }\n                val expirationTime = integrityRequestWrapper.getExpirationTime()\n\n                if (expirationTime > INTERMEDIATE_INTEGRITY_HARD_EXPIRATION * 1000) {\n                    Log.w(TAG, \"Intermediate integrity hard expiration reached.\")\n                    callback?.onRequestResult(bundleOf(KEY_ERROR to IntegrityErrorCode.INTEGRITY_TOKEN_PROVIDER_INVALID))\n                    return@launchWhenCreated\n                }\n                Log.d(TAG, \"Intermediate integrity token generated time $expirationTime.\")\n\n                val integritySession = IntermediateIntegritySession.Builder().creationTime(makeTimestamp(System.currentTimeMillis())).requestHash(expressIntegritySession.requestHash)\n                    .sessionId(Random.nextBytes(8).toByteString()).timestampMillis(expirationTime.toInt()).build()\n\n                val expressIntegrityResponse = ExpressIntegrityResponse.Builder().apply {\n                    this.deviceIntegrityToken = integrityRequestWrapper.deviceIntegrityWrapper?.deviceIntegrityToken\n                    this.sessionHashAes128 = readAes128GcmBuilderFromClientKey(integrityRequestWrapper.callerKey)?.encrypt(\n                        integritySession.encode(), null\n                    )?.toByteString()\n                }.build()\n\n                val token = Base64.encodeToString(\n                    expressIntegrityResponse.encode(), Base64.NO_PADDING or Base64.NO_WRAP or Base64.URL_SAFE\n                )\n\n                Log.d(TAG, \"requestExpressIntegrityToken token: $token, sid: ${expressIntegritySession.sessionId}, mode: ${expressIntegritySession.webViewRequestMode}\")\n                visitData?.updateAppIntegrityContent(context, System.currentTimeMillis(), \"$TAG visited success.\", true)\n                callback?.onRequestResult(\n                    bundleOf(\n                        KEY_TOKEN to token,\n                        KEY_REQUEST_TOKEN_SID to expressIntegritySession.sessionId,\n                        KEY_REQUEST_MODE to expressIntegritySession.webViewRequestMode\n                    )\n                )\n            }.onFailure {\n                val exception = it as? StandardIntegrityException ?: StandardIntegrityException(it.message)\n                Log.w(TAG, \"requesting token has failed: code=${exception.code}, message=${exception.message}\", exception)\n                visitData?.updateAppIntegrityContent(context, System.currentTimeMillis(), \"$TAG visited failed. ${exception.message}\")\n                callback?.onRequestResult(bundleOf(KEY_ERROR to exception.code))\n            }\n        }\n    }\n\n    override fun requestAndShowDialog(bundle: Bundle?, callback: IRequestDialogCallback?) {\n        Log.d(TAG, \"requestAndShowDialog bundle:$bundle\")\n        callback?.onRequestDialog(bundleOf(KEY_ERROR to IntegrityErrorCode.INTERNAL_ERROR))\n    }\n\n}\n\nprivate fun IExpressIntegrityServiceCallback.onWarmResult(result: Bundle) {\n    if (asBinder()?.isBinderAlive == false) {\n        Log.e(TAG, \"onWarmResult IExpressIntegrityServiceCallback Binder died\")\n        return\n    }\n    Log.d(TAG, \"IExpressIntegrityServiceCallback onWarmResult success: $result\")\n    try {\n        onWarmUpExpressIntegrityToken(result)\n    } catch (e: Exception) {\n        Log.w(TAG, \"error -> $e\")\n    }\n}\n\nprivate fun IExpressIntegrityServiceCallback.onRequestResult(result: Bundle) {\n    if (asBinder()?.isBinderAlive == false) {\n        Log.e(TAG, \"onRequestResult IExpressIntegrityServiceCallback Binder died\")\n        return\n    }\n    Log.d(TAG, \"IExpressIntegrityServiceCallback onRequestResult success: $result\")\n    try {\n        onRequestExpressIntegrityToken(result)\n    } catch (e: Exception) {\n        Log.w(TAG, \"error -> $e\")\n    }\n}"
  },
  {
    "path": "vending-app/src/main/kotlin/com/google/android/finsky/expressintegrityservice/ExpressIntegritySession.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.finsky.expressintegrityservice\ndata class ExpressIntegritySession(\n    var packageName: String,\n    var cloudProjectNumber: Long,\n    var sessionId: Long,\n    var requestHash: String?,\n    var originatingWarmUpSessionId: Long,\n    var verdictOptOut: List<Int>?,\n    var webViewRequestMode: Int\n) {\n    override fun toString(): String {\n        return \"ExpressIntegritySession(packageName='$packageName', cloudProjectNumber=$cloudProjectNumber, sessionId=$sessionId, requestHash=$requestHash, originatingWarmUpSessionId=$originatingWarmUpSessionId, verdictOptOut=${\n            verdictOptOut?.joinToString(\n                prefix = \"[\", postfix = \"]\"\n            )\n        }, webViewRequestMode=$webViewRequestMode)\"\n    }\n}"
  },
  {
    "path": "vending-app/src/main/kotlin/com/google/android/finsky/expressintegrityservice/IntermediateIntegrity.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.finsky.expressintegrityservice\n\nimport com.google.android.finsky.ClientKey\nimport com.google.android.finsky.IntegrityAdvice\nimport okio.ByteString\nimport org.microg.vending.proto.Timestamp\n\ndata class IntermediateIntegrity(\n    var packageName: String,\n    var cloudProjectNumber: Long,\n    var accountName: String,\n    var callerKey: ClientKey,\n    var intermediateToken: ByteString?,\n    var serverGenerated: Timestamp?,\n    var webViewRequestMode: Int,\n    var testErrorCode: Int?,\n    var integrityAdvice: IntegrityAdvice?\n)"
  },
  {
    "path": "vending-app/src/main/kotlin/com/google/android/finsky/expressintegrityservice/IntermediateIntegrityResponse.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.finsky.expressintegrityservice\n\ndata class IntermediateIntegrityResponseData(\n    var intermediateIntegrity: IntermediateIntegrity, var callerKeyMd5: String, var appVersionCode: Int, var deviceIntegrityResponse: DeviceIntegrityResponse, var appAccessRiskVerdictEnabled: Boolean?\n)\n"
  },
  {
    "path": "vending-app/src/main/kotlin/com/google/android/finsky/expressintegrityservice/PackageInformation.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.finsky.expressintegrityservice\ndata class PackageInformation(var certificateSha256Hashes: List<String>, var versionCode: Int)\n"
  },
  {
    "path": "vending-app/src/main/kotlin/com/google/android/finsky/extensions.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.finsky\n\nimport android.accounts.Account\nimport android.accounts.AccountManager\nimport android.content.Context\nimport android.content.Intent\nimport android.content.pm.PackageManager\nimport android.net.Uri\nimport android.os.Bundle\nimport android.util.Log\nimport androidx.collection.ArraySet\nimport androidx.collection.arrayMapOf\nimport androidx.collection.arraySetOf\nimport androidx.core.content.pm.PackageInfoCompat\nimport com.android.vending.AUTH_TOKEN_SCOPE\nimport com.android.vending.VendingPreferences\nimport com.android.vending.buildRequestHeaders\nimport com.google.android.finsky.assetmoduleservice.AssetPackException\nimport com.google.android.finsky.assetmoduleservice.ChunkData\nimport com.google.android.finsky.assetmoduleservice.DownloadData\nimport com.google.android.finsky.assetmoduleservice.ModuleData\nimport com.google.android.play.core.assetpacks.model.AssetPackErrorCode\nimport com.google.android.play.core.assetpacks.model.AssetPackStatus\nimport com.google.android.play.core.assetpacks.protocol.BroadcastConstants\nimport com.google.android.play.core.assetpacks.protocol.BundleKeys\nimport com.google.android.play.core.assetpacks.protocol.CompressionFormat\nimport com.google.android.play.core.assetpacks.protocol.PatchFormat\nimport org.microg.gms.auth.AuthConstants\nimport org.microg.vending.billing.GServices\nimport org.microg.vending.billing.core.GooglePlayApi\nimport org.microg.vending.billing.core.HttpClient\nimport java.io.File\nimport java.util.Collections\n\nconst val KEY_MODULE_NAME = \"module_name\"\n\nconst val TAG_REQUEST = \"asset_module\"\n\nprivate const val ASSET_MODULE_DELIVERY_URL = \"https://play-fe.googleapis.com/fdfe/assetModuleDelivery\"\n\nprivate const val TAG = \"AssetModuleRequest\"\n\nfun getAppVersionCode(context: Context, packageName: String): Long? {\n    return try {\n        PackageInfoCompat.getLongVersionCode(context.packageManager.getPackageInfo(packageName, 0))\n    } catch (e: PackageManager.NameNotFoundException) {\n        throw AssetPackException(AssetPackErrorCode.APP_UNAVAILABLE, e.message)\n    }\n}\n\nfun <T> Bundle?.get(key: BundleKeys.RootKey<T>): T? = if (this == null) null else BundleKeys.get(this, key)\nfun <T> Bundle?.get(key: BundleKeys.RootKey<T>, def: T): T = if (this == null) def else BundleKeys.get(this, key, def)\nfun <T> Bundle.put(key: BundleKeys.RootKey<T>, v: T) = BundleKeys.put(this, key, v)\nfun <T> Bundle.put(key: BundleKeys.PackKey<T>, packName: String, v: T) = BundleKeys.put(this, key, packName, v)\nfun <T> Bundle.put(key: BundleKeys.SliceKey<T>, packName: String, sliceId: String, v: T) = BundleKeys.put(this, key, packName, sliceId, v)\nfun <T> bundleOf(pair: Pair<BundleKeys.RootKey<T>, T>): Bundle = Bundle().apply { put(pair.first, pair.second) }\noperator fun Bundle.plus(other: Bundle): Bundle = Bundle(this).apply { putAll(other) }\noperator fun <T> Bundle.plus(pair: Pair<BundleKeys.RootKey<T>, T>): Bundle = this + bundleOf(pair)\n\nval Context.assetPacksDir: File\n    get() = File(filesDir, \"assetpacks\")\nfun Context.getSessionDir(sessionId: Int) =\n    File(assetPacksDir, sessionId.toString())\nfun Context.getModuleDir(sessionId: Int, moduleName: String): File =\n    File(getSessionDir(sessionId), moduleName)\nfun Context.getSliceDir(sessionId: Int, moduleName: String, sliceId: String) =\n    File(getModuleDir(sessionId, moduleName), sliceId)\nfun Context.getChunkFile(sessionId: Int, moduleName: String, sliceId: String, chunkNumber: Int): File =\n    File(getSliceDir(sessionId, moduleName, sliceId), chunkNumber.toString())\n\ndata class AssetModuleOptions(val playCoreVersionCode: Int, val supportedCompressionFormats: List<Int>, val supportedPatchFormats: List<Int>)\n\nsuspend fun HttpClient.initAssetModuleData(\n    context: Context,\n    packageName: String,\n    accountManager: AccountManager,\n    requestedAssetModuleNames: List<String?>,\n    options: AssetModuleOptions,\n    playCoreVersionCode: Int = options.playCoreVersionCode,\n    supportedCompressionFormats: List<Int> = options.supportedCompressionFormats.takeIf { it.isNotEmpty() } ?: listOf(CompressionFormat.UNSPECIFIED, CompressionFormat.CHUNKED_GZIP),\n    supportedPatchFormats: List<Int> = options.supportedPatchFormats.takeIf { it.isNotEmpty() } ?: listOf(PatchFormat.PATCH_GDIFF, PatchFormat.GZIPPED_GDIFF),\n): DownloadData? {\n    val accounts = accountManager.getAccountsByType(AuthConstants.DEFAULT_ACCOUNT_TYPE)\n    var authToken: String? = null\n    var account: Account? = null\n    if (accounts.isEmpty()) {\n        return null\n    } else {\n        for (candidate in accounts) {\n            authToken = com.android.vending.getAuthToken(accountManager, candidate, AUTH_TOKEN_SCOPE).getString(AccountManager.KEY_AUTHTOKEN)\n            if (authToken != null) {\n                account = candidate\n                break\n            }\n        }\n    }\n\n    if (authToken == null || account == null) {\n        return null\n    }\n\n    val appVersionCode = getAppVersionCode(context, packageName)\n    val requestPayload = AssetModuleDeliveryRequest.Builder().callerInfo(CallerInfo(appVersionCode)).packageName(packageName)\n        .playCoreVersion(playCoreVersionCode).supportedCompressionFormats(supportedCompressionFormats)\n        .supportedPatchFormats(supportedPatchFormats).modules(ArrayList<AssetModuleInfo>().apply {\n            requestedAssetModuleNames.forEach { add(AssetModuleInfo.Builder().name(it).build()) }\n        }).build()\n\n    val androidId = GServices.getString(context.contentResolver, \"android_id\", \"1\")?.toLong() ?: 1\n    // Make sure device is synced\n    syncDeviceInfo(context, account, authToken, androidId)\n\n    val moduleDeliveryInfo = post(\n        url = ASSET_MODULE_DELIVERY_URL,\n        headers = buildRequestHeaders(authToken, androidId),\n        payload = requestPayload,\n        adapter = AssetModuleDeliveryResponse.ADAPTER\n    ).wrapper?.deliveryInfo\n    Log.d(TAG, \"initAssetModuleData: moduleDeliveryInfo-> $moduleDeliveryInfo\")\n    return initModuleDownloadInfo(packageName, appVersionCode, moduleDeliveryInfo)\n}\n\nconst val DEVICE_INFO_SYNC_INTERVAL = 24 * 60 * 60 * 1000L // 1 day\nsuspend fun syncDeviceInfo(context: Context, account: Account, authToken: String, androidId: Long) {\n    val deviceSyncEnabled = VendingPreferences.isDeviceSyncEnabled(context)\n    if (!deviceSyncEnabled) {\n        Log.d(TAG, \"syncDeviceInfo deviceSyncEnabled is false\")\n        return\n    }\n    val prefs = context.getSharedPreferences(\"device_sync\", Context.MODE_PRIVATE)\n    val lastSync = prefs.getLong(\"${account.name}_last\", 0)\n    if (lastSync > System.currentTimeMillis() - DEVICE_INFO_SYNC_INTERVAL) {\n        return\n    }\n    runCatching {\n        HttpClient().post(\n            url = GooglePlayApi.URL_SYNC,\n            headers = buildRequestHeaders(authToken, androidId),\n            payload = DeviceSyncInfo.buildSyncRequest(context, androidId, account),\n            adapter = SyncResponse.ADAPTER\n        )\n        prefs.edit().putLong(\"${account.name}_last\", System.currentTimeMillis()).apply()\n        Log.d(TAG, \"syncDeviceInfo: sync success\")\n    }.onFailure {\n        Log.d(TAG, \"syncDeviceInfo: sync error\", it)\n    }\n}\n\nprivate val sessionIdMap: MutableMap<String, Int> = mutableMapOf()\n\nprivate val lock = Any()\nprivate fun Context.generateSessionId(): Int {\n    synchronized(lock) {\n        val sharedPreferences = getSharedPreferences(\"AssetModuleSessionIdGenerator\", 0)\n        val latest = sharedPreferences.getInt(\"Latest\", 0) + 1\n        val edit = sharedPreferences.edit()\n        edit.putInt(\"Latest\", latest)\n        edit.commit()\n        return latest\n    }\n}\n\nprivate fun getSessionIdForPackage(packageName: String): Int {\n    synchronized(lock) {\n        return sessionIdMap.getOrPut(packageName) { 10 }\n    }\n}\n\nprivate fun updateSessionIdForPackage(packageName: String, increment: Int) {\n    synchronized(lock) {\n        val currentSessionId = sessionIdMap[packageName] ?: 10\n        sessionIdMap[packageName] = currentSessionId + increment\n    }\n}\n\nprivate fun initModuleDownloadInfo(packageName: String, appVersionCode: Long?, deliveryInfo: ModuleDeliveryInfo?): DownloadData? {\n    if (deliveryInfo == null || deliveryInfo.status != null) {\n        return null\n    }\n    val moduleNames: ArraySet<String> = arraySetOf()\n    var totalBytesToDownload = 0L\n    var packVersionCode = 0L\n    val sessionIds = arrayMapOf<String, Int>()\n    val moduleDataMap = arrayMapOf<String, ModuleData>()\n    val baseSessionId = getSessionIdForPackage(packageName)\n    for (moduleIndex in deliveryInfo.modules.indices) {\n        val moduleInfo: ModuleInfo = deliveryInfo.modules[moduleIndex]\n        packVersionCode = moduleInfo.packVersion ?: 0\n        val slices: List<SliceInfo> = moduleInfo.slices\n        val moduleName: String = moduleInfo.moduleName ?: continue\n        var moduleBytesToDownload = 0L\n        moduleNames.add(moduleName)\n        sessionIds[moduleName] = baseSessionId + moduleIndex\n        var totalSumOfSubcontractedModules = 0\n        val sliceIds: ArrayList<String> = ArrayList()\n        val chunkDatas: ArrayList<ChunkData> = arrayListOf()\n        for (sliceIndex in slices.indices) {\n            val sliceInfo: SliceInfo = slices[sliceIndex]\n            if (sliceInfo.metadata == null || sliceInfo.fullDownloadInfo == null) {\n                continue\n            }\n            val chunks = sliceInfo.fullDownloadInfo.chunks\n            val numberOfChunks = chunks.size\n            val uncompressedSize = sliceInfo.fullDownloadInfo.uncompressedSize\n            val uncompressedHashSha256 = sliceInfo.fullDownloadInfo.uncompressedHashSha256\n            val sliceId = sliceInfo.metadata.sliceId?.also { sliceIds.add(it) } ?: continue\n            var sliceBytesToDownload = 0L\n            for (chunkIndex in chunks.indices) {\n                val dResource: ChunkInfo = chunks[chunkIndex]\n                sliceBytesToDownload += dResource.bytesToDownload!!\n                totalSumOfSubcontractedModules += 1\n                chunkDatas.add(ChunkData(\n                    sessionId = sessionIds[moduleName]!!,\n                    moduleName = moduleName,\n                    sliceId = sliceId,\n                    chunkSourceUri = dResource.sourceUri,\n                    chunkBytesToDownload = dResource.bytesToDownload,\n                    chunkIndex = chunkIndex,\n                    sliceCompressionFormat = sliceInfo.fullDownloadInfo.compressionFormat ?: CompressionFormat.UNSPECIFIED,\n                    sliceUncompressedSize = uncompressedSize ?: 0,\n                    sliceUncompressedHashSha256 = uncompressedHashSha256,\n                    numberOfChunksInSlice = numberOfChunks\n                ))\n            }\n            moduleBytesToDownload += sliceBytesToDownload\n        }\n        val moduleData = ModuleData(\n            packVersionCode = packVersionCode,\n            moduleVersion = 0,\n            errorCode = AssetPackErrorCode.NO_ERROR,\n            status = AssetPackStatus.NOT_INSTALLED,\n            bytesDownloaded = 0,\n            totalBytesToDownload = moduleBytesToDownload,\n            chunks = chunkDatas,\n            sliceIds = sliceIds\n        )\n        totalBytesToDownload += moduleBytesToDownload\n        moduleDataMap[moduleName] = moduleData\n    }\n    updateSessionIdForPackage(packageName, deliveryInfo.modules.size)\n    return DownloadData(\n        packageName = packageName,\n        errorCode = AssetPackErrorCode.NO_ERROR,\n        sessionIds = sessionIds,\n        status = AssetPackStatus.NOT_INSTALLED,\n        moduleNames = moduleNames,\n        appVersionCode = appVersionCode ?: packVersionCode,\n        moduleDataMap\n    )\n}\n\nfun buildDownloadBundle(downloadData: DownloadData, list: List<String>? = null): Bundle {\n    val bundleData = Bundle()\n    val arrayList = arrayListOf<String>()\n    var totalBytesToDownload = 0L\n    var bytesDownloaded = 0L\n\n    list?.forEach { moduleName ->\n        val packData = downloadData.getModuleData(moduleName)\n        bundleData.put(BundleKeys.STATUS, packData.status)\n        downloadData.sessionIds[moduleName]?.let { sessionId ->\n            bundleData.put(BundleKeys.SESSION_ID, sessionId)\n            bundleData.put(BundleKeys.SESSION_ID, moduleName, packData.status)\n        }\n        bundleData.put(BundleKeys.PACK_VERSION_TAG, moduleName, null)\n        bundleData.put(BundleKeys.STATUS, moduleName, packData.status)\n        bundleData.put(BundleKeys.ERROR_CODE, moduleName, packData.errorCode)\n        bundleData.put(BundleKeys.PACK_VERSION, moduleName, packData.packVersionCode)\n        bundleData.put(BundleKeys.PACK_BASE_VERSION, moduleName, packData.moduleVersion)\n        bundleData.put(BundleKeys.BYTES_DOWNLOADED, moduleName, packData.bytesDownloaded)\n        bundleData.put(BundleKeys.TOTAL_BYTES_TO_DOWNLOAD, moduleName, packData.totalBytesToDownload)\n        arrayList.add(moduleName)\n        totalBytesToDownload += packData.totalBytesToDownload\n        bytesDownloaded += packData.bytesDownloaded\n    }\n    bundleData.put(BundleKeys.ERROR_CODE, downloadData.errorCode)\n    bundleData.put(BundleKeys.PACK_NAMES, arrayList)\n    bundleData.put(BundleKeys.TOTAL_BYTES_TO_DOWNLOAD, totalBytesToDownload)\n    bundleData.put(BundleKeys.BYTES_DOWNLOADED, bytesDownloaded)\n    return bundleData\n}\n\nfun sendBroadcastForExistingFile(context: Context, downloadData: DownloadData, moduleName: String, chunkData: ChunkData?, destination: File?): Bundle {\n    val packData = downloadData.getModuleData(moduleName)\n    try {\n        val downloadBundle = Bundle()\n        downloadBundle.put(BundleKeys.APP_VERSION_CODE, downloadData.appVersionCode.toInt())\n        downloadBundle.put(BundleKeys.ERROR_CODE, AssetPackErrorCode.NO_ERROR)\n        downloadBundle.put(BundleKeys.SESSION_ID, downloadData.sessionIds[moduleName] ?: downloadData.status)\n        downloadBundle.put(BundleKeys.STATUS, packData.status)\n        downloadBundle.put(BundleKeys.PACK_NAMES, arrayListOf(moduleName))\n        downloadBundle.put(BundleKeys.BYTES_DOWNLOADED, packData.bytesDownloaded)\n        downloadBundle.put(BundleKeys.TOTAL_BYTES_TO_DOWNLOAD, packData.totalBytesToDownload)\n        downloadBundle.put(BundleKeys.TOTAL_BYTES_TO_DOWNLOAD, moduleName, packData.totalBytesToDownload)\n        downloadBundle.put(BundleKeys.PACK_VERSION, moduleName, packData.packVersionCode)\n        downloadBundle.put(BundleKeys.STATUS, moduleName, packData.status)\n        downloadBundle.put(BundleKeys.ERROR_CODE, moduleName, AssetPackErrorCode.NO_ERROR)\n        downloadBundle.put(BundleKeys.BYTES_DOWNLOADED, moduleName, packData.bytesDownloaded)\n        downloadBundle.put(BundleKeys.PACK_BASE_VERSION, moduleName, packData.moduleVersion)\n        downloadBundle.put(BundleKeys.PACK_VERSION_TAG, moduleName, null)\n        packData.chunks.map { it.copy() }.forEach {\n            val sliceId = it.sliceId\n            val chunkIntents = ArrayList(Collections.nCopies<Intent?>(it.numberOfChunksInSlice, null))\n            if (chunkData != null && destination != null) {\n                val uri = Uri.fromFile(destination)\n                context.grantUriPermission(moduleName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION)\n                val intent = Intent(Intent.ACTION_VIEW)\n                intent.setDataAndType(uri, context.contentResolver.getType(uri))\n                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)\n                if (destination.exists() && chunkData.moduleName == moduleName && chunkData.sliceId == sliceId) {\n                    if (chunkIntents[chunkData.chunkIndex] == null) {\n                        chunkIntents[chunkData.chunkIndex] = intent\n                    }\n                }\n            }\n            downloadBundle.put(BundleKeys.CHUNK_INTENTS, moduleName, sliceId, chunkIntents)\n            downloadBundle.put(BundleKeys.UNCOMPRESSED_SIZE, moduleName, sliceId, it.sliceUncompressedSize)\n            downloadBundle.put(BundleKeys.COMPRESSION_FORMAT, moduleName, sliceId, it.sliceCompressionFormat)\n            downloadBundle.put(BundleKeys.UNCOMPRESSED_HASH_SHA256, moduleName, sliceId, it.sliceUncompressedHashSha256)\n        }\n        downloadBundle.put(BundleKeys.SLICE_IDS, moduleName, ArrayList(packData.chunks.map { it.sliceId }.distinct()))\n        sendBroadCast(context, downloadData, downloadBundle)\n        return downloadBundle\n    } catch (e: Exception) {\n        Log.w(TAG, \"sendBroadcastForExistingFile error:\" + e.message)\n        return Bundle(Bundle().apply { put(BundleKeys.ERROR_CODE, AssetPackErrorCode.API_NOT_AVAILABLE) })\n    }\n}\n\nprivate fun sendBroadCast(context: Context, downloadData: DownloadData, result: Bundle) {\n    val intent = Intent()\n    intent.setAction(BroadcastConstants.ACTION_SESSION_UPDATE)\n    intent.putExtra(BroadcastConstants.EXTRA_SESSION_STATE, result)\n    intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)\n    intent.putExtra(BroadcastConstants.EXTRA_FLAGS, Bundle().apply { putBoolean(BroadcastConstants.KEY_USING_EXTRACTOR_STREAM, true) })\n    intent.setPackage(downloadData.packageName)\n    context.sendBroadcast(intent)\n}\n"
  },
  {
    "path": "vending-app/src/main/kotlin/com/google/android/finsky/inappreviewdialog/InAppReviewActivity.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.finsky.inappreviewdialog\n\nimport android.os.Bundle\nimport androidx.appcompat.app.AppCompatActivity\n\nclass InAppReviewActivity: AppCompatActivity() {\n    companion object {\n        const val CALLING_PACKAGE = \"calling_package\"\n    }\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        setResult(RESULT_OK)\n        finish()\n    }\n}"
  },
  {
    "path": "vending-app/src/main/kotlin/com/google/android/finsky/inappreviewservice/InAppReviewService.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.finsky.inappreviewservice\n\nimport android.app.PendingIntent.FLAG_UPDATE_CURRENT\nimport android.content.Context\nimport android.content.Intent\nimport android.os.Bundle\nimport android.os.IBinder\nimport android.os.Parcel\nimport android.util.Log\nimport androidx.core.app.PendingIntentCompat\nimport androidx.lifecycle.LifecycleService\nimport com.google.android.finsky.inappreviewdialog.InAppReviewActivity\nimport com.google.android.play.core.inappreview.protocol.IInAppReviewService\nimport com.google.android.play.core.inappreview.protocol.IInAppReviewServiceCallback\nimport org.microg.gms.utils.warnOnTransactionIssues\n\nprivate const val TAG = \"InAppReviewService\"\n\nclass InAppReviewService : LifecycleService() {\n\n    override fun onBind(intent: Intent): IBinder? {\n        super.onBind(intent)\n        Log.d(TAG, \"onBind\")\n        return InAppReviewServiceImpl(this).asBinder()\n    }\n\n    override fun onUnbind(intent: Intent?): Boolean {\n        Log.d(TAG, \"onUnbind\")\n        return super.onUnbind(intent)\n    }\n}\n\nclass InAppReviewServiceImpl(val context: Context) : IInAppReviewService.Stub() {\n\n    override fun requestInAppReview(packageName: String?, bundle: Bundle?, callback: IInAppReviewServiceCallback?) {\n        Log.d(TAG, \"requestInAppReview: packageName: $packageName bundle:$bundle\")\n        if (packageName == null) return\n        val pendingIntent = Intent(context, InAppReviewActivity::class.java).apply {\n            putExtra(InAppReviewActivity.CALLING_PACKAGE, packageName)\n        }.let {\n            PendingIntentCompat.getActivity(context, 0, it, FLAG_UPDATE_CURRENT, false)\n        }\n        val bundle = Bundle()\n        bundle.putBoolean(\"is_review_no_op\", false)\n        bundle.putParcelable(\"confirmation_intent\", pendingIntent)\n        try {\n            callback?.onResult(bundle)\n        } catch (e: Exception) {\n            Log.w(TAG, \"Exception on in-app review service\", e)\n        }\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int) = warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n}\n"
  },
  {
    "path": "vending-app/src/main/kotlin/com/google/android/finsky/installservice/DevTriggeredUpdateService.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.finsky.installservice\n\nimport android.content.Context\nimport android.content.Intent\nimport android.os.Bundle\nimport android.os.IBinder\nimport android.os.Parcel\nimport android.util.Log\nimport androidx.core.os.bundleOf\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.LifecycleOwner\nimport androidx.lifecycle.LifecycleService\nimport com.google.android.play.core.appupdate.protocol.IAppUpdateService\nimport com.google.android.play.core.appupdate.protocol.IAppUpdateServiceCallback\nimport org.microg.gms.utils.warnOnTransactionIssues\n\nprivate const val TAG = \"TriggeredUpdateService\"\n\nclass DevTriggeredUpdateService : LifecycleService() {\n\n    override fun onBind(intent: Intent): IBinder? {\n        super.onBind(intent)\n        Log.d(TAG, \"onBind\")\n        return DevTriggeredUpdateServiceImpl(this, lifecycle).asBinder()\n    }\n\n    override fun onUnbind(intent: Intent?): Boolean {\n        Log.d(TAG, \"onUnbind\")\n        return super.onUnbind(intent)\n    }\n}\n\nclass DevTriggeredUpdateServiceImpl(private val context: Context, override val lifecycle: Lifecycle) : IAppUpdateService.Stub(), LifecycleOwner {\n\n    override fun requestUpdateInfo(packageName: String?, bundle: Bundle?, callback: IAppUpdateServiceCallback?) {\n        bundle?.keySet()\n        Log.d(TAG, \"requestUpdateInfo: packageName: $packageName bundle: $bundle\")\n        callback?.onUpdateResult(bundleOf(\"error.code\" to 0, \"update.availability\" to 1))\n    }\n\n    override fun completeUpdate(packageName: String?, bundle: Bundle?, callback: IAppUpdateServiceCallback?) {\n        bundle?.keySet()\n        Log.d(TAG, \"completeUpdate: packageName: $packageName bundle: $bundle\")\n        callback?.onCompleteResult(bundleOf(\"error.code\" to 0))\n    }\n\n    override fun updateProgress(bundle: Bundle?) {\n        Log.d(TAG, \"updateProgress:  bundle: $bundle\")\n    }\n\n    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }\n}"
  },
  {
    "path": "vending-app/src/main/kotlin/com/google/android/finsky/integrityservice/IntegrityService.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.finsky.integrityservice\n\nimport android.content.Context\nimport android.content.Intent\nimport android.os.Bundle\nimport android.os.IBinder\nimport android.os.SystemClock\nimport android.text.TextUtils\nimport android.util.Base64\nimport android.util.Log\nimport androidx.core.os.bundleOf\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.LifecycleOwner\nimport androidx.lifecycle.LifecycleService\nimport androidx.lifecycle.lifecycleScope\nimport com.android.vending.AUTH_TOKEN_SCOPE\nimport com.android.vending.VendingPreferences\nimport com.android.vending.makeTimestamp\nimport com.google.android.finsky.AccessibilityAbuseSignalDataWrapper\nimport com.google.android.finsky.AppAccessRiskDetailsResponse\nimport com.google.android.finsky.DisplayListenerMetadataWrapper\nimport com.google.android.finsky.INTEGRITY_FLOW_NAME\nimport com.google.android.finsky.INTEGRITY_PREFIX_ERROR\nimport com.google.android.finsky.InstalledAppsSignalDataWrapper\nimport com.google.android.finsky.IntegrityParams\nimport com.google.android.finsky.IntegrityRequest\nimport com.google.android.finsky.KEY_CLOUD_PROJECT\nimport com.google.android.finsky.KEY_NONCE\nimport com.google.android.finsky.KEY_PACKAGE_NAME\nimport com.google.android.finsky.PARAMS_BINDING_KEY\nimport com.google.android.finsky.PARAMS_GCP_N_KEY\nimport com.google.android.finsky.PARAMS_NONCE_SHA256_KEY\nimport com.google.android.finsky.PARAMS_PKG_KEY\nimport com.google.android.finsky.PARAMS_TM_S_KEY\nimport com.google.android.finsky.PARAMS_VC_KEY\nimport com.google.android.finsky.PackageNameWrapper\nimport com.google.android.finsky.PlayProtectDetails\nimport com.google.android.finsky.PlayProtectState\nimport com.google.android.finsky.SIGNING_FLAGS\nimport com.google.android.finsky.ScreenCaptureSignalDataWrapper\nimport com.google.android.finsky.ScreenOverlaySignalDataWrapper\nimport com.google.android.finsky.VersionCodeWrapper\nimport com.google.android.finsky.callerAppToIntegrityData\nimport com.google.android.finsky.getPlayCoreVersion\nimport com.google.android.finsky.encodeBase64\nimport com.google.android.finsky.getAuthToken\nimport com.google.android.finsky.getPackageInfoCompat\nimport com.google.android.finsky.model.IntegrityErrorCode\nimport com.google.android.finsky.model.StandardIntegrityException\nimport com.google.android.finsky.requestIntegritySyncData\nimport com.google.android.finsky.sha256\nimport com.google.android.finsky.signaturesCompat\nimport com.google.android.finsky.updateAppIntegrityContent\nimport com.google.android.gms.droidguard.DroidGuard\nimport com.google.android.gms.droidguard.internal.DroidGuardResultsRequest\nimport com.google.android.gms.tasks.await\nimport com.google.android.play.core.integrity.protocol.IIntegrityService\nimport com.google.android.play.core.integrity.protocol.IIntegrityServiceCallback\nimport com.google.android.play.core.integrity.protocol.IRequestDialogCallback\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\nimport okio.ByteString.Companion.toByteString\nimport org.microg.gms.profile.ProfileManager\nimport org.microg.gms.vending.PlayIntegrityData\n\nprivate const val TAG = \"IntegrityService\"\n\nclass IntegrityService : LifecycleService() {\n\n    override fun onBind(intent: Intent): IBinder? {\n        super.onBind(intent)\n        ProfileManager.ensureInitialized(this)\n        Log.d(TAG, \"onBind\")\n        return IntegrityServiceImpl(this, lifecycle).asBinder()\n    }\n\n    override fun onUnbind(intent: Intent?): Boolean {\n        Log.d(TAG, \"onUnbind\")\n        return super.onUnbind(intent)\n    }\n}\n\nprivate class IntegrityServiceImpl(private val context: Context, override val lifecycle: Lifecycle) : IIntegrityService.Stub(), LifecycleOwner {\n\n    private var integrityData: PlayIntegrityData? = null\n\n    override fun requestDialog(bundle: Bundle, callback: IRequestDialogCallback) {\n        Log.d(TAG, \"Method (requestDialog) called but not implemented \")\n        requestAndShowDialog(bundle, callback)\n    }\n\n    override fun requestAndShowDialog(bundle: Bundle?, callback: IRequestDialogCallback?) {\n        Log.d(TAG, \"Not yet implemented: requestAndShowDialog\")\n    }\n\n    override fun requestIntegrityToken(request: Bundle, callback: IIntegrityServiceCallback) {\n        Log.d(TAG, \"Method (requestIntegrityToken) called\")\n        lifecycleScope.launchWhenCreated {\n            runCatching {\n                val packageName = request.getString(KEY_PACKAGE_NAME)\n                if (packageName == null) {\n                    throw StandardIntegrityException(IntegrityErrorCode.INTERNAL_ERROR, \"Null packageName.\")\n                }\n                integrityData = callerAppToIntegrityData(context, packageName)\n                if (integrityData?.allowed != true) {\n                    throw StandardIntegrityException(IntegrityErrorCode.INTERNAL_ERROR, \"Not allowed to request integrity token.\")\n                }\n                val playIntegrityEnabled = VendingPreferences.isDeviceAttestationEnabled(context)\n                if (!playIntegrityEnabled) {\n                    throw StandardIntegrityException(IntegrityErrorCode.INTERNAL_ERROR, \"API is disabled.\")\n                }\n                val nonceArr = request.getByteArray(KEY_NONCE)\n                if (nonceArr == null) {\n                    throw StandardIntegrityException(IntegrityErrorCode.INTERNAL_ERROR, \"Nonce missing.\")\n                }\n                if (nonceArr.size < 16) {\n                    throw StandardIntegrityException(IntegrityErrorCode.NONCE_TOO_SHORT, \"Nonce too short.\")\n                }\n                if (nonceArr.size >= 500) {\n                    throw StandardIntegrityException(IntegrityErrorCode.NONCE_TOO_LONG, \"Nonce too long.\")\n                }\n                val cloudProjectNumber = request.getLong(KEY_CLOUD_PROJECT, 0L)\n                val playCoreVersion = request.getPlayCoreVersion()\n                Log.d(TAG, \"requestIntegrityToken(packageName: $packageName, nonce: ${nonceArr.encodeBase64(false)}, cloudProjectNumber: $cloudProjectNumber, playCoreVersion: $playCoreVersion)\")\n\n                val packageInfo = context.packageManager.getPackageInfoCompat(packageName, SIGNING_FLAGS)\n                val timestamp = makeTimestamp(System.currentTimeMillis())\n                val versionCode = packageInfo.versionCode\n\n                val integrityParams = IntegrityParams(\n                    packageName = PackageNameWrapper(packageName),\n                    versionCode = VersionCodeWrapper(versionCode),\n                    nonce = nonceArr.encodeBase64(noPadding = false, noWrap = true, urlSafe = true),\n                    certificateSha256Digests = packageInfo.signaturesCompat.map {\n                        it.toByteArray().sha256().encodeBase64(noPadding = true, noWrap = true, urlSafe = true)\n                    },\n                    timestampAtRequest = timestamp,\n                    cloudProjectNumber = cloudProjectNumber.takeIf { it > 0L }\n                )\n\n                val data = mutableMapOf(\n                    PARAMS_PKG_KEY to packageName,\n                    PARAMS_VC_KEY to versionCode.toString(),\n                    PARAMS_NONCE_SHA256_KEY to nonceArr.sha256().encodeBase64(noPadding = true, noWrap = true, urlSafe = true),\n                    PARAMS_TM_S_KEY to timestamp.seconds.toString(),\n                    PARAMS_BINDING_KEY to integrityParams.encode().encodeBase64(noPadding = false, noWrap = true, urlSafe = true),\n                )\n                if (cloudProjectNumber > 0L) {\n                    data[PARAMS_GCP_N_KEY] = cloudProjectNumber.toString()\n                }\n\n                var mapSize = 0\n                data.entries.forEach { mapSize += it.key.toByteArray().size + it.value.toByteArray().size }\n                if (mapSize > 65536) {\n                    throw StandardIntegrityException(IntegrityErrorCode.INTERNAL_ERROR, \"Content binding size exceeded maximum allowed size.\")\n                }\n\n                val authToken = getAuthToken(context, AUTH_TOKEN_SCOPE)\n                if (TextUtils.isEmpty(authToken)) {\n                    Log.w(TAG, \"requestIntegrityToken: Got null auth token for type: $AUTH_TOKEN_SCOPE\")\n                }\n                Log.d(TAG, \"requestIntegrityToken authToken: $authToken\")\n\n                val droidGuardData = withContext(Dispatchers.IO) {\n                    val droidGuardResultsRequest = DroidGuardResultsRequest()\n                    droidGuardResultsRequest.bundle.putString(\"thirdPartyCallerAppPackageName\", packageName)\n                    Log.d(TAG, \"Running DroidGuard (flow: $INTEGRITY_FLOW_NAME, data: $data)\")\n                    val droidGuardToken = DroidGuard.getClient(context).getResults(INTEGRITY_FLOW_NAME, data, droidGuardResultsRequest).await()\n                    Log.d(TAG, \"Running DroidGuard (flow: $INTEGRITY_FLOW_NAME, droidGuardToken: $droidGuardToken)\")\n                    Base64.decode(droidGuardToken, Base64.NO_PADDING or Base64.NO_WRAP or Base64.URL_SAFE).toByteString()\n                }\n\n                if (droidGuardData.utf8().startsWith(INTEGRITY_PREFIX_ERROR)) {\n                    Log.w(TAG, \"droidGuardData: ${droidGuardData.utf8()}\")\n                    throw StandardIntegrityException(IntegrityErrorCode.NETWORK_ERROR, \"DroidGuard failed.\")\n                }\n\n                val integrityRequest = IntegrityRequest(\n                    params = integrityParams,\n                    flowName = INTEGRITY_FLOW_NAME,\n                    droidGuardTokenRaw = droidGuardData,\n                    playCoreVersion = playCoreVersion,\n                    playProtectDetails = PlayProtectDetails(PlayProtectState.PLAY_PROTECT_STATE_NO_PROBLEMS),\n                    appAccessRiskDetailsResponse = AppAccessRiskDetailsResponse(\n                        installedAppsSignalDataWrapper = InstalledAppsSignalDataWrapper(\".\"),\n                        screenCaptureSignalDataWrapper = ScreenCaptureSignalDataWrapper(\".\"),\n                        screenOverlaySignalDataWrapper = ScreenOverlaySignalDataWrapper(\".\"),\n                        accessibilityAbuseSignalDataWrapper = AccessibilityAbuseSignalDataWrapper(),\n                        displayListenerMetadataWrapper = DisplayListenerMetadataWrapper(\n                            lastDisplayAddedTimeDelta = makeTimestamp(SystemClock.elapsedRealtimeNanos())\n                        )\n                    )\n                )\n                Log.d(TAG, \"requestIntegrityToken integrityRequest: $integrityRequest\")\n                val integrityResponse = requestIntegritySyncData(context, authToken, integrityRequest)\n                Log.d(TAG, \"requestIntegrityToken integrityResponse: $integrityResponse\")\n\n                val integrityToken = integrityResponse.contentWrapper?.content?.token\n                if (integrityToken.isNullOrEmpty()) {\n                    if (integrityResponse.integrityResponseError?.error != null) {\n                        throw StandardIntegrityException(IntegrityErrorCode.INTERNAL_ERROR, integrityResponse.integrityResponseError.error)\n                    }\n                    throw StandardIntegrityException(IntegrityErrorCode.INTERNAL_ERROR, \"No token in response.\")\n                }\n\n                Log.d(TAG, \"requestIntegrityToken integrityToken: $integrityToken\")\n                integrityData?.updateAppIntegrityContent(context, System.currentTimeMillis(), \"Delivered encrypted integrity token.\", true)\n                callback.onSuccess(packageName, integrityToken)\n            }.onFailure {\n                Log.w(TAG, \"requestIntegrityToken has exception: \", it)\n                integrityData?.updateAppIntegrityContent(context, System.currentTimeMillis(), \"Integrity check failed: ${it.message}\")\n                callback.onError(integrityData?.packageName, IntegrityErrorCode.INTERNAL_ERROR, it.message ?: \"Exception\")\n            }\n        }\n    }\n}\n\nprivate fun IIntegrityServiceCallback.onError(packageName: String?, errorCode: Int, errorMsg: String) {\n    if (asBinder()?.isBinderAlive == false) {\n        Log.e(TAG, \"IIntegrityServiceCallback onError Binder died\")\n        return\n    }\n    Log.d(TAG, \"requestIntegrityToken() failed for $packageName error -> $errorMsg\")\n    try {\n        onRequestIntegrityToken(bundleOf(\"error\" to errorCode))\n    } catch (e: Exception) {\n        Log.e(TAG, \"exception $packageName error -> $e\")\n    }\n}\n\nprivate fun IIntegrityServiceCallback.onSuccess(packageName: String?, token: String) {\n    if (asBinder()?.isBinderAlive == false) {\n        Log.e(TAG, \"IIntegrityServiceCallback onSuccess Binder died\")\n        return\n    }\n    Log.d(TAG, \"requestIntegrityToken() success for $packageName)\")\n    try {\n        onRequestIntegrityToken(bundleOf(\"token\" to token))\n    } catch (e: Exception) {\n        Log.e(TAG, \"exception $packageName error -> $e\")\n    }\n}"
  },
  {
    "path": "vending-app/src/main/kotlin/com/google/android/finsky/model/IntegrityErrorCode.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.finsky.model\n\nimport org.microg.gms.common.PublicApi\n\n@PublicApi\nannotation class IntegrityErrorCode {\n    companion object {\n        /**\n         * Integrity API is not available.\n         *\n         * Integrity API is not enabled, or the Play Store version might be old.\n         *\n         * Recommended actions:\n         * Make sure that Integrity API is enabled in Google Play Console.\n         * Ask the user to update Play Store.\n         */\n        const val API_NOT_AVAILABLE = -1\n\n        /**\n         * PackageManager could not find this app.\n         *\n         * Something is wrong (possibly an attack). Non-actionable.\n         */\n        const val APP_NOT_INSTALLED = -5\n\n        /**\n         * The calling app UID (user id) does not match the one from Package Manager.\n         *\n         * Something is wrong (possibly an attack). Non-actionable.\n         */\n        const val APP_UID_MISMATCH = -7\n\n        /**\n         * Binding to the service in the Play Store has failed.\n         * This can be due to having an old Play Store version installed on the device.\n         *\n         * Ask the user to update Play Store.\n         */\n        const val CANNOT_BIND_TO_SERVICE = -9\n\n        /**\n         * The provided request hash is too long.\n         *\n         * The request hash length must be less than 500 bytes.\n         * Retry with a shorter request hash.\n         * */\n        const val REQUEST_HASH_TOO_LONG = -17\n\n        /**\n         * There is a transient error on the calling device.\n         *\n         * Retry with an exponential backoff.\n         *\n         * Introduced in Integrity Play Core version 1.1.0 (prior versions returned a token with empty Device Integrity Verdict).\n         * If the error persists after a few retries, you should assume that the device has failed integrity checks and act accordingly.\n         */\n        const val CLIENT_TRANSIENT_ERROR = -18\n\n        /**\n         * The StandardIntegrityTokenProvider is invalid (e.g. it is outdated).\n         *\n         * Request a new integrity token provider by calling StandardIntegrityManager#prepareIntegrityToken.\n         * */\n        const val INTEGRITY_TOKEN_PROVIDER_INVALID = -19\n\n        /**\n         * The provided cloud project number is invalid.\n         *\n         * Use the cloud project number which can be found in Project info in\n         * your Google Cloud Console for the cloud project where Play Integrity API is enabled.\n         */\n        const val CLOUD_PROJECT_NUMBER_IS_INVALID = -16\n\n        /**\n         * Unknown internal Google server error.\n         *\n         * Retry with an exponential backoff. Consider filing a bug if fails consistently.\n         */\n        const val GOOGLE_SERVER_UNAVAILABLE = -12\n\n        /**\n         * Unknown error processing integrity request.\n         *\n         * Retry with an exponential backoff. Consider filing a bug if fails consistently.\n         */\n        const val INTERNAL_ERROR = -100\n\n        /**\n         * Network error: unable to obtain integrity details.\n         *\n         * Ask the user to check for a connection.\n         */\n        const val NETWORK_ERROR = -3\n\n        /**\n         * Nonce is not encoded as a base64 web-safe no-wrap string.\n         *\n         * Retry with correct nonce format.\n         */\n        const val NONCE_IS_NOT_BASE64 = -13\n\n        /**\n         * Nonce length is too long. The nonce must be less than 500 bytes before base64 encoding.\n         *\n         * Retry with a shorter nonce.\n         */\n        const val NONCE_TOO_LONG = -11\n\n        /**\n         * Nonce length is too short. The nonce must be a minimum of 16 bytes (before base64 encoding) to allow for a better security.\n         *\n         * Retry with a longer nonce.\n         */\n        const val NONCE_TOO_SHORT = -10\n\n        /**\n         * No error.\n         *\n         * This is the default value.\n         */\n        const val NO_ERROR = 0\n\n        /**\n         * Google Play Services is not available or version is too old.\n         *\n         * Ask the user to Install or Update Play Services.\n         */\n        const val PLAY_SERVICES_NOT_FOUND = -6\n\n        /**\n         * The Play Services needs to be updated.\n         *\n         * Ask the user to update Google Play Services.\n         */\n        const val PLAY_SERVICES_VERSION_OUTDATED = -15\n\n        /**\n         * No active account found in the Play Store app.\n         * Note that the Play Integrity API now supports unauthenticated requests.\n         * This error code is used only for older Play Store versions that lack support.\n         *\n         * Ask the user to authenticate in Play Store.\n         */\n        const val PLAY_STORE_ACCOUNT_NOT_FOUND = -4\n\n        /**\n         * The Play Store app is either not installed or not the official version.\n         *\n         * Ask the user to install an official and recent version of Play Store.\n         */\n        const val PLAY_STORE_NOT_FOUND = -2\n\n        /**\n         * The Play Store needs to be updated.\n         *\n         * Ask the user to update the Google Play Store.\n         */\n        const val PLAY_STORE_VERSION_OUTDATED = -14\n\n        /**\n         * The calling app is making too many requests to the API and hence is throttled.\n         *\n         * Retry with an exponential backoff.\n         */\n        const val TOO_MANY_REQUESTS = -8\n    }\n}"
  },
  {
    "path": "vending-app/src/main/kotlin/com/google/android/finsky/model/StandardIntegrityException.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.finsky.model\n\nclass StandardIntegrityException : Exception {\n    val code: Int\n\n    constructor(code: Int, message: String) : super(message) {\n        this.code = code\n    }\n\n    constructor(cause: String?) : super(cause) {\n        this.code = IntegrityErrorCode.INTERNAL_ERROR\n    }\n}"
  },
  {
    "path": "vending-app/src/main/kotlin/com/google/android/finsky/services/PlayGearheadService.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.finsky.services\n\nimport android.content.Context\nimport android.content.Intent\nimport android.os.Bundle\nimport android.os.IBinder\nimport android.util.Log\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.LifecycleOwner\nimport androidx.lifecycle.LifecycleService\n\nprivate const val TAG = \"PlayGearheadService\"\n\nclass PlayGearheadService : LifecycleService() {\n\n    override fun onBind(intent: Intent): IBinder? {\n        super.onBind(intent)\n        Log.d(TAG, \"onBind\")\n        return PlayGearheadServiceImpl(this, lifecycle).asBinder()\n    }\n\n    override fun onUnbind(intent: Intent?): Boolean {\n        Log.d(TAG, \"onUnbind\")\n        return super.onUnbind(intent)\n    }\n}\n\nprivate class PlayGearheadServiceImpl(\n    private val context: Context, override val lifecycle: Lifecycle\n) : IPlayGearheadService.Stub(), LifecycleOwner {\n\n    override fun isPackageInstalledByPlayCheck(pkgName: String?): Bundle {\n        Log.d(TAG, \"isPackageInstalledByPlayCheck: pkgName: $pkgName\")\n        return Bundle().apply { putBoolean(\"Finsky.IsValid\", true) }\n    }\n}\n"
  },
  {
    "path": "vending-app/src/main/kotlin/com/google/android/finsky/splitinstallservice/DownloadStatus.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.finsky.splitinstallservice\n\nenum class DownloadStatus {\n    PENDING,\n    FAILED,\n    COMPLETE\n}"
  },
  {
    "path": "vending-app/src/main/kotlin/com/google/android/finsky/splitinstallservice/PackageComponent.kt",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.finsky.splitinstallservice\n\ndata class PackageComponent(\n    val packageName: String,\n    val componentName: String,\n    val url: String,\n    /**\n     * Size in bytes\n     */\n    val size: Long\n)"
  },
  {
    "path": "vending-app/src/main/kotlin/com/google/android/finsky/splitinstallservice/SplitInstallManager.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\npackage com.google.android.finsky.splitinstallservice\n\nimport android.accounts.AccountManager\nimport android.content.Context\nimport android.content.Intent\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.Bundle\nimport android.util.Log\nimport androidx.annotation.RequiresApi\nimport androidx.collection.arraySetOf\nimport androidx.core.content.pm.PackageInfoCompat\nimport com.android.vending.installer.KEY_BYTES_DOWNLOADED\nimport com.android.vending.installer.SPLIT_LANGUAGE_TAG\nimport com.android.vending.installer.installPackagesFromNetwork\nimport com.google.android.finsky.syncDeviceInfo\nimport kotlinx.coroutines.CompletableDeferred\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.sync.Mutex\nimport kotlinx.coroutines.sync.withLock\nimport kotlinx.coroutines.withContext\nimport org.microg.vending.billing.AuthManager\nimport org.microg.vending.billing.core.HttpClient\nimport org.microg.vending.delivery.requestDownloadUrls\nimport org.microg.vending.enterprise.Downloading\nimport org.microg.vending.ui.notifySplitInstallProgress\n\nprivate const val KEY_LANGUAGE = \"language\"\nprivate const val KEY_LANGUAGES = \"languages\"\nprivate const val KEY_MODULE_NAME = \"module_name\"\nprivate const val KEY_TOTAL_BYTES_TO_DOWNLOAD = \"total_bytes_to_download\"\nprivate const val KEY_STATUS = \"status\"\nprivate const val KEY_ERROR_CODE = \"error_code\"\nprivate const val KEY_SESSION_ID = \"session_id\"\nprivate const val KEY_MODULE_NAMES = \"module_names\"\nprivate const val KEY_SESSION_STATE = \"session_state\"\n\nprivate const val ACTION_UPDATE_SERVICE = \"com.google.android.play.core.splitinstall.receiver.SplitInstallUpdateIntentService\"\n\nprivate const val TAG = \"SplitInstallManager\"\n\nclass SplitInstallManager(val context: Context) {\n\n    private var httpClient: HttpClient = HttpClient()\n    private val mutex = Mutex()\n\n    suspend fun splitInstallFlow(callingPackage: String, splits: List<Bundle>): Boolean {\n        var packagesToDownload: List<String> = listOf()\n        var components:List<PackageComponent>? = null\n        mutex.withLock {\n            if (SDK_INT < 23) return false\n//        val callingPackage = runCatching { PackageUtils.getAndCheckCallingPackage(context, packageName) }.getOrNull() ?: return\n            if (splits.all { it.getString(KEY_LANGUAGE) == null && it.getString(KEY_MODULE_NAME) == null }) return false\n            Log.v(TAG, \"splitInstallFlow: start\")\n\n            packagesToDownload = splits.mapNotNull { split ->\n                split.getString(KEY_LANGUAGE)?.let { \"$SPLIT_LANGUAGE_TAG$it\" }\n                        ?: split.getString(KEY_MODULE_NAME)\n            }.filter { shouldDownload(callingPackage, it) }\n\n            Log.v(TAG, \"splitInstallFlow will query for these packages: $packagesToDownload\")\n            if (packagesToDownload.isEmpty()) return false\n\n\n            val authData = runCatching { withContext(Dispatchers.IO) {\n                AuthManager.getAuthData(context)\n            } }.getOrNull()\n            Log.v(TAG, \"splitInstallFlow oauthToken: $authData\")\n            if (authData?.authToken.isNullOrEmpty()) return false\n            authData!!\n\n            components = runCatching {\n                kotlin.runCatching {\n                    //Synchronize account device information to prevent failure to obtain sub-package download information\n                    syncDeviceInfo(context, AccountManager.get(context).accounts.firstOrNull { it.name == authData.email }!!, authData.authToken, authData.gsfId.toLong(16))\n                }\n                httpClient.requestDownloadUrls(\n                        context = context,\n                        packageName = callingPackage,\n                        versionCode = PackageInfoCompat.getLongVersionCode(\n                                context.packageManager.getPackageInfo(callingPackage, 0)\n                        ),\n                        auth = authData,\n                        requestSplitPackages = packagesToDownload\n                )\n            }.getOrNull()\n\n            Log.v(TAG, \"splitInstallFlow requestDownloadUrls returned these components: $components\")\n            if (components.isNullOrEmpty()) {\n                return false\n            }\n            components!!.forEach {\n                splitInstallRecord[it] = DownloadStatus.PENDING\n            }\n        }\n\n        val success = runCatching {\n\n            var lastNotification = 0L\n            context.installPackagesFromNetwork(\n                    packageName = callingPackage,\n                    components = components!!,\n                    httpClient = httpClient,\n                    isUpdate = false,\n                    splitInstall = true,\n            ) { notifyId, progress ->\n                // Android rate limits notification updates by some vague rule of \"not too many in less than one second\"\n                if (progress !is Downloading || lastNotification + 250 < System.currentTimeMillis()) {\n                    context.notifySplitInstallProgress(callingPackage, notifyId, progress)\n                    lastNotification = System.currentTimeMillis()\n                }\n            }\n        }.isSuccess\n\n        return if (success) {\n            sendCompleteBroad(context, callingPackage, components!!.sumOf { it.size }, packagesToDownload)\n            components!!.forEach { splitInstallRecord[it] = DownloadStatus.COMPLETE }\n            true\n        } else {\n            components!!.forEach { splitInstallRecord[it] = DownloadStatus.FAILED }\n            false\n        }\n    }\n\n    /**\n     * Tests if a split apk has already been requested in this session. Returns true if it is\n     * pending or downloaded, and returns false if download failed or it is not yet known.\n     */\n    @RequiresApi(23)\n    private fun shouldDownload(callingPackage: String, splitName: String): Boolean {\n        return splitInstallRecord.keys.find { it.packageName == callingPackage && it.componentName == splitName }\n                ?.let {\n                    splitInstallRecord[it] == DownloadStatus.FAILED\n                } ?: true\n    }\n\n    private fun sendCompleteBroad(context: Context, packageName: String, bytes: Long, moduleList: List<String>) {\n        Log.d(TAG, \"sendCompleteBroadcast: $bytes bytes splits:$moduleList\")\n        val moduleNames = arraySetOf<String>()\n        val languages = arraySetOf<String>()\n        moduleList?.forEach {\n            if (it.startsWith(SPLIT_LANGUAGE_TAG)) {\n                languages.add(it)\n            } else {\n                moduleNames.add(it)\n            }\n        }\n        Log.d(TAG, \"sendInstallCompleteBroad: moduleNames -> $moduleNames languages -> $languages\")\n        val extra = Bundle().apply {\n            putInt(KEY_STATUS, 5)\n            putInt(KEY_ERROR_CODE, 0)\n            putInt(KEY_SESSION_ID, 0)\n            putLong(KEY_TOTAL_BYTES_TO_DOWNLOAD, bytes)\n            if (languages.isNotEmpty()) {\n                putStringArrayList(KEY_LANGUAGES, ArrayList(languages))\n            }\n            if (moduleNames.isNotEmpty()) {\n                putStringArrayList(KEY_MODULE_NAMES, ArrayList(moduleNames))\n            }\n            putLong(KEY_BYTES_DOWNLOADED, bytes)\n        }\n\n        val broadcastIntent = Intent(ACTION_UPDATE_SERVICE).apply {\n            setPackage(packageName)\n            putExtra(KEY_SESSION_STATE, extra)\n            addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)\n            addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)\n        }\n        context.sendBroadcast(broadcastIntent)\n    }\n\n    fun release() {\n        splitInstallRecord.clear()\n        deferredMap.clear()\n    }\n\n    companion object {\n        // Installation records, including (sub)package name, download path, and installation status\n        internal val splitInstallRecord: MutableMap<PackageComponent, DownloadStatus> = mutableMapOf()\n        private val deferredMap = mutableMapOf<Int, CompletableDeferred<Intent>>()\n    }\n}\n"
  },
  {
    "path": "vending-app/src/main/kotlin/com/google/android/finsky/splitinstallservice/SplitInstallService.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2024 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage com.google.android.finsky.splitinstallservice\n\nimport android.content.Context\nimport android.content.Intent\nimport android.os.Bundle\nimport android.os.IBinder\nimport android.util.Log\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.LifecycleOwner\nimport androidx.lifecycle.LifecycleService\nimport androidx.lifecycle.lifecycleScope\nimport com.android.vending.VendingPreferences\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.play.core.splitinstall.protocol.ISplitInstallService\nimport com.google.android.play.core.splitinstall.protocol.ISplitInstallServiceCallback\nimport kotlinx.coroutines.launch\nimport org.microg.gms.common.PackageUtils\nimport org.microg.gms.profile.ProfileManager\n\nprivate const val TAG = \"SplitInstallService\"\n\nclass SplitInstallService : LifecycleService() {\n\n    private lateinit var splitInstallManager: SplitInstallManager\n\n    override fun onCreate() {\n        super.onCreate()\n        ProfileManager.ensureInitialized(this)\n        splitInstallManager = SplitInstallManager(this)\n    }\n\n    override fun onBind(intent: Intent): IBinder? {\n        super.onBind(intent)\n        return SplitInstallServiceImpl(splitInstallManager, this, lifecycle).asBinder()\n    }\n\n    override fun onDestroy() {\n        splitInstallManager.release()\n        super.onDestroy()\n    }\n}\n\nclass SplitInstallServiceImpl(private val installManager: SplitInstallManager, private val context: Context, override val lifecycle: Lifecycle) : ISplitInstallService.Stub(),\n    LifecycleOwner {\n\n    override fun startInstall(targetPackage: String, splits: List<Bundle>, bundle0: Bundle, callback: ISplitInstallServiceCallback) {\n        val packageName = PackageUtils.getAndCheckCallingPackage(context, targetPackage)!!\n        Log.d(TAG, \"startInstall(${splits.joinToString()}) called for $targetPackage\")\n        if (VendingPreferences.isSplitInstallEnabled(context)) {\n            lifecycleScope.launch {\n                val installStatus = installManager.splitInstallFlow(packageName, splits)\n                Log.d(TAG, \"startInstall result $installStatus for $targetPackage\")\n                runCatching { callback.onStartInstall(CommonStatusCodes.SUCCESS, Bundle()) }\n            }\n        } else {\n            Log.w(TAG, \"startInstall rejected for $packageName, service is disabled\")\n            runCatching { callback.onStartInstall(CommonStatusCodes.ERROR, Bundle()) }\n        }\n    }\n\n    override fun completeInstalls(targetPackage: String, sessionId: Int, bundle0: Bundle, callback: ISplitInstallServiceCallback) {\n        val packageName = PackageUtils.getAndCheckCallingPackage(context, targetPackage)!!\n        Log.w(TAG, \"completeInstalls($sessionId) called for $packageName, but is not implemented\")\n    }\n\n    override fun cancelInstall(targetPackage: String, sessionId: Int, callback: ISplitInstallServiceCallback) {\n        val packageName = PackageUtils.getAndCheckCallingPackage(context, targetPackage)!!\n        Log.w(TAG, \"cancelInstall($sessionId) called for $packageName, but is not implemented\")\n    }\n\n    override fun getSessionState(targetPackage: String, sessionId: Int, callback: ISplitInstallServiceCallback) {\n        val packageName = PackageUtils.getAndCheckCallingPackage(context, targetPackage)!!\n        Log.w(TAG, \"getSessionState($sessionId) called for $packageName, but is not implemented\")\n    }\n\n    override fun getSessionStates(targetPackage: String, callback: ISplitInstallServiceCallback) {\n        val packageName = PackageUtils.getAndCheckCallingPackage(context, targetPackage)!!\n        Log.w(TAG, \"getSessionStates() called for $packageName, but is not implemented\")\n        runCatching { callback.onGetSessionStates(ArrayList<Bundle>(1)) }\n    }\n\n    override fun splitRemoval(targetPackage: String, splits: List<Bundle>, callback: ISplitInstallServiceCallback) {\n        val packageName = PackageUtils.getAndCheckCallingPackage(context, targetPackage)!!\n        Log.w(TAG, \"splitRemoval(${splits.joinToString()}) called for $packageName, but is not implemented\")\n    }\n\n    override fun splitDeferred(targetPackage: String, splits: List<Bundle>, bundle0: Bundle, callback: ISplitInstallServiceCallback) {\n        val packageName = PackageUtils.getAndCheckCallingPackage(context, targetPackage)!!\n        Log.w(TAG, \"splitDeferred(${splits.joinToString()}) called for $packageName, but is not implemented\")\n        runCatching { callback.onDeferredInstall(Bundle()) }\n    }\n\n    override fun getSessionState2(targetPackage: String, sessionId: Int, callback: ISplitInstallServiceCallback) {\n        val packageName = PackageUtils.getAndCheckCallingPackage(context, targetPackage)!!\n        Log.w(TAG, \"getSessionState2($sessionId) called for $packageName, but is not implemented\")\n    }\n\n    override fun getSessionStates2(targetPackage: String, callback: ISplitInstallServiceCallback) {\n        val packageName = PackageUtils.getAndCheckCallingPackage(context, targetPackage)!!\n        Log.w(TAG, \"getSessionStates2() called for $packageName, but is not implemented\")\n    }\n\n    override fun getSplitsAppUpdate(targetPackage: String, callback: ISplitInstallServiceCallback) {\n        val packageName = PackageUtils.getAndCheckCallingPackage(context, targetPackage)!!\n        Log.w(TAG, \"getSessionStates2() called for $packageName, but is not implemented\")\n    }\n\n    override fun completeInstallAppUpdate(targetPackage: String, callback: ISplitInstallServiceCallback) {\n        val packageName = PackageUtils.getAndCheckCallingPackage(context, targetPackage)!!\n        Log.w(TAG, \"completeInstallAppUpdate() called for $packageName, but is not implemented\")\n    }\n\n    override fun languageSplitInstall(targetPackage: String, splits: List<Bundle>, bundle0: Bundle, callback: ISplitInstallServiceCallback) {\n        val packageName = PackageUtils.getAndCheckCallingPackage(context, targetPackage)!!\n        Log.w(TAG, \"languageSplitInstall(${splits.joinToString()}) called for $packageName, but is not implemented\")\n    }\n\n    override fun languageSplitUninstall(targetPackage: String, splits: List<Bundle>, callback: ISplitInstallServiceCallback) {\n        val packageName = PackageUtils.getAndCheckCallingPackage(context, targetPackage)!!\n        Log.w(TAG, \"languageSplitUninstall(${splits.joinToString()}) called for $packageName, but is not implemented\")\n    }\n\n}\n"
  },
  {
    "path": "vending-app/src/main/kotlin/org/microg/vending/installer/AppInstallActivity.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.vending.installer\n\nimport android.content.Intent\nimport android.net.Uri\nimport android.os.Bundle\nimport android.os.Handler\nimport android.os.Looper\nimport android.os.Message\nimport android.os.Messenger\nimport android.provider.Settings\nimport android.util.Base64\nimport android.util.Log\nimport androidx.annotation.RequiresApi\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.core.net.toUri\nimport androidx.lifecycle.lifecycleScope\nimport com.android.vending.VendingPreferences\nimport com.android.vending.installer.installPackages\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.launch\nimport kotlinx.coroutines.withContext\nimport org.microg.gms.profile.Build.VERSION.SDK_INT\nimport org.microg.gms.profile.ProfileManager\nimport org.microg.gms.utils.getFirstSignatureDigest\nimport org.microg.gms.vending.AllowType\nimport org.microg.gms.vending.InstallerData\nimport kotlin.coroutines.resume\nimport kotlin.coroutines.suspendCoroutine\n\nprivate const val REQUEST_INSTALL_PERMISSION = 1001\n\n@RequiresApi(21)\nclass AppInstallActivity : AppCompatActivity() {\n\n    private val callingPackageName: String?\n        get() = callingActivity?.packageName\n\n    private val packUris: List<Uri>\n        get() {\n            val list = if (SDK_INT >= 33) {\n                intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM, Uri::class.java)\n            } else {\n                intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM)\n            }\n            if (list != null && !list.isEmpty()) return list\n            val streamUri = if (SDK_INT >= 33) {\n                intent.getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java)\n            } else {\n                intent.getParcelableExtra(Intent.EXTRA_STREAM)\n            }\n            if (streamUri != null) return listOf(streamUri)\n            return listOfNotNull(intent.data)\n        }\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        val installEnabled = VendingPreferences.isInstallEnabled(this)\n        if (!installEnabled) {\n            return onResult(RESULT_CANCELED, \"Install is disabled\")\n        }\n        ProfileManager.ensureInitialized(this)\n\n        if (callingPackageName.isNullOrEmpty()) {\n            Log.d(TAG, \"onCreate: No calling activity, use startActivityForResult()\")\n            return onResult(RESULT_CANCELED, \"No calling activity\")\n        }\n\n        if (packUris.isEmpty()) {\n            Log.d(TAG, \"onCreate: Missing package URI: $intent\")\n            return onResult(RESULT_CANCELED, \"Missing package URI\")\n        }\n\n        val pkgSignSha256ByteArray = packageManager.getFirstSignatureDigest(callingPackageName!!, \"SHA-256\")\n            ?: return onResult(RESULT_CANCELED, \"$callingPackageName request install permission denied: signature is null\")\n\n        val pkgSignSha256Base64 = Base64.encodeToString(pkgSignSha256ByteArray, Base64.NO_WRAP)\n        Log.d(TAG, \"onCreate $callingPackageName pkgSignSha256Base64: $pkgSignSha256Base64\")\n\n        val installerList = VendingPreferences.getInstallerList(this)\n        val installerDataSet = InstallerData.loadDataSet(installerList)\n\n        val callerInstallerData = callerToInstallerData(installerDataSet, callingPackageName!!, pkgSignSha256Base64)\n        if (callerInstallerData.allowType == AllowType.REJECT_ALWAYS.value) {\n            return onResult(RESULT_CANCELED, \"$callingPackageName is not allowed to install\")\n        }\n\n        val appInfo = extractInstallAppInfo(packUris) ?:\n            return onResult(RESULT_CANCELED, \"Can't extract app information from provided .apk\")\n\n        lifecycleScope.launchWhenStarted {\n            var callerAllow = callerInstallerData.allowType\n            if (callerAllow == AllowType.REJECT_ONCE.value || callerAllow == AllowType.ALLOW_ONCE.value) {\n                callerAllow = showRequestInstallReminder(appInfo)\n            }\n            Log.d(TAG, \"onCreate: callerPackagePermissionType: $callerAllow\")\n\n            val newInstallerDataString = InstallerData.updateDataSetString(installerDataSet, callerInstallerData.apply { this.allowType = callerAllow })\n            VendingPreferences.setInstallerList(this@AppInstallActivity, newInstallerDataString)\n            Log.d(TAG, \"onCreate: newInstallerDataString: $newInstallerDataString\")\n\n            if (callerAllow == AllowType.ALLOW_ALWAYS.value || callerAllow == AllowType.ALLOW_ONCE.value) {\n                if (hasInstallPermission()) {\n                    Log.d(TAG, \"onCreate: hasInstallPermission\")\n                    handleInstallRequest(appInfo.packageName)\n                } else {\n                    openInstallPermissionSettings()\n                }\n                return@launchWhenStarted\n            }\n\n            onResult(RESULT_CANCELED, \"$callingPackageName request install permission denied\", appInfo.packageName)\n        }\n    }\n\n    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {\n        super.onActivityResult(requestCode, resultCode, data)\n        if (requestCode == REQUEST_INSTALL_PERMISSION) {\n            if (hasInstallPermission()) {\n                Log.d(TAG, \"onCreate: requestInstallPermission granted\")\n                val appInfo = extractInstallAppInfo(packUris!!) ?: return onResult(RESULT_CANCELED, \"File changed while granting permission\")\n                handleInstallRequest(appInfo.packageName)\n            } else {\n                onResult(RESULT_CANCELED, \"Install Permission denied\")\n            }\n        }\n    }\n\n    private fun callerToInstallerData(installerDataSet: Set<InstallerData>, callingPackage: String, pkgSignSha256: String): InstallerData {\n        if (installerDataSet.isEmpty() || installerDataSet.none { it.packageName == callingPackage && it.pkgSignSha256 == pkgSignSha256 }) {\n            return InstallerData(callingPackage, AllowType.REJECT_ONCE.value, pkgSignSha256)\n        }\n        return installerDataSet.first { it.packageName == callingPackage && it.pkgSignSha256 == pkgSignSha256 }\n    }\n\n    private fun handleInstallRequest(installPackageName: String) {\n        lifecycleScope.launch {\n            val isSuccess = runCatching {\n                withContext(Dispatchers.IO) {\n                    installPackages(\n                        packageName = installPackageName,\n                        componentFiles = uriToApkFiles(packUris!!),\n                        isUpdate = true\n                    )\n                }\n            }.isSuccess\n            Log.d(TAG, \"handleInstallRequest: installPackages<$installPackageName> isSuccess: $isSuccess\")\n            if (isSuccess) {\n                onResult(RESULT_OK, installPackageName = installPackageName)\n            } else {\n                onResult(RESULT_CANCELED, \"Install failed\")\n            }\n        }\n    }\n\n    private suspend fun showRequestInstallReminder(appInfo: InstallAppInfo) = suspendCoroutine { con ->\n        val intent = Intent(this, AskInstallReminderActivity::class.java)\n        intent.putExtra(EXTRA_MESSENGER, Messenger(object : Handler(Looper.getMainLooper()) {\n            override fun handleMessage(msg: Message) {\n                con.resume(msg.what)\n            }\n        }))\n        intent.putExtra(EXTRA_CALLER_PACKAGE, callingPackageName)\n        intent.putExtra(EXTRA_INSTALL_PACKAGE_NAME, appInfo.packageName)\n        intent.putExtra(EXTRA_INSTALL_PACKAGE_LABEL, appInfo.appLabel)\n        intent.putExtra(EXTRA_INSTALL_PACKAGE_ICON, appInfo.appIcon?.toByteArrayOrNull())\n        intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK\n        startActivity(intent)\n    }\n\n    private fun openInstallPermissionSettings() {\n        Log.d(TAG, \"openInstallPermissionSettings: request \")\n        val intent = if (SDK_INT >= 26) {\n            Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES).apply {\n                data = \"package:$packageName\".toUri()\n            }\n        } else {\n            Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {\n                data = Uri.fromParts(\"package\", packageName, null)\n            }\n        }\n        startActivityForResult(intent, REQUEST_INSTALL_PERMISSION)\n    }\n\n    private fun onResult(result: Int = RESULT_OK, error: String? = null, installPackageName: String? = null) {\n        Log.d(TAG, \"onResult: error: $error \")\n        sendBroadcastReceiver(callingPackageName, installPackageName, result, error)\n        setResult(result, Intent().apply { putExtra(\"error\", error) })\n        finishAndRemoveTask()\n    }\n}"
  },
  {
    "path": "vending-app/src/main/kotlin/org/microg/vending/installer/AppInstallExtensions.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.vending.installer\n\nimport android.content.Context\nimport android.content.Intent\nimport android.content.pm.PackageInstaller\nimport android.content.pm.PackageManager\nimport android.graphics.Bitmap\nimport android.graphics.BitmapFactory\nimport android.graphics.Canvas\nimport android.graphics.drawable.BitmapDrawable\nimport android.graphics.drawable.Drawable\nimport android.net.Uri\nimport android.util.Log\nimport androidx.annotation.RequiresApi\nimport androidx.core.graphics.createBitmap\nimport androidx.core.graphics.drawable.toDrawable\nimport org.microg.gms.profile.Build.VERSION.SDK_INT\nimport java.io.ByteArrayOutputStream\nimport java.io.File\n\nconst val TAG = \"AppInstall\"\nconst val EXTRA_MESSENGER = \"messenger\"\nconst val EXTRA_CALLER_PACKAGE = \"calling_package\"\nconst val EXTRA_INSTALL_PACKAGE = \"installed_app_package\"\nconst val EXTRA_INSTALL_PACKAGE_ICON = \"installPackageIcon\"\nconst val EXTRA_INSTALL_PACKAGE_NAME = \"installPackageName\"\nconst val EXTRA_INSTALL_PACKAGE_LABEL = \"installPackageLabel\"\nconst val INSTALL_RESULT_RECV_ACTION = \"com.android.vending.install.PACAKGE\"\nconst val SOURCE_PACKAGE = \"source_package\"\n\nfun Context.hasInstallPermission() = if (SDK_INT >= 26) {\n    packageManager.canRequestPackageInstalls()\n} else {\n    true\n}\n\ndata class InstallAppInfo(val packageName: String, val appLabel: String, val appIcon: Drawable?)\n\nfun Context.extractInstallAppInfo(uris: List<Uri>): InstallAppInfo? {\n    var packageName: String? = null\n    var appLabel: String? = null\n    var appIcon: Drawable? = null\n    for (item in uris) {\n        var tempFile: File? = null\n        try {\n            tempFile = File.createTempFile(\"temp_apk_\", \".apk\", cacheDir).apply {\n                contentResolver.openInputStream(item)?.use { input ->\n                    outputStream().use { output -> input.copyTo(output) }\n                }\n            }\n            val packageInfo = if (SDK_INT >= 33) {\n                packageManager.getPackageArchiveInfo(tempFile.absolutePath, PackageManager.PackageInfoFlags.of(PackageManager.GET_META_DATA.toLong()))\n            } else {\n                @Suppress(\"DEPRECATION\")\n                packageManager.getPackageArchiveInfo(tempFile.absolutePath, PackageManager.GET_META_DATA)\n            } ?: continue\n            Log.d(TAG, \"Package: $packageInfo, App: ${packageInfo.applicationInfo}\")\n            if (packageName != null && packageInfo.packageName != packageName) {\n                Log.w(TAG, \"Inconsistent packages\")\n                return null\n            }\n            packageName = packageInfo.packageName\n            val appInfo = packageInfo.applicationInfo.apply {\n                this?.sourceDir = tempFile.absolutePath\n                this?.publicSourceDir = tempFile.absolutePath\n            } ?: continue\n            val thisAppLabel = packageManager.getApplicationLabel(appInfo).toString()\n            Log.d(TAG, \"Got app label: $thisAppLabel\")\n            if (thisAppLabel != packageName && thisAppLabel.isNotBlank()) appLabel = thisAppLabel\n            appIcon = packageManager.getApplicationIcon(appInfo)\n            if (appLabel != null) break\n        } catch (e: Exception) {\n            Log.w(TAG, \"Failed to extract app info: ${e.message}\", e)\n        } finally {\n            tempFile?.delete()\n        }\n    }\n    if (packageName != null) {\n        return InstallAppInfo(packageName, appLabel ?: packageName, appIcon)\n    }\n    return null\n}\n\nfun Context.uriToApkFiles(uriList: List<Uri>): List<File> {\n    return uriList.mapIndexedNotNull { uriIndex, uri ->\n        File.createTempFile(\"temp_apk_\", \".$uriIndex.apk\", cacheDir).apply {\n            contentResolver.openInputStream(uri)?.use { input ->\n                outputStream().use { output -> input.copyTo(output) }\n            }\n        }\n    }\n}\n\nfun Drawable.toByteArrayOrNull(): ByteArray? = runCatching {\n    val bitmap = if (this is BitmapDrawable) {\n        this.bitmap\n    } else {\n        createBitmap(intrinsicWidth, intrinsicHeight).also { bmp ->\n            val canvas = Canvas(bmp)\n            setBounds(0, 0, canvas.width, canvas.height)\n            draw(canvas)\n        }\n    }\n\n    ByteArrayOutputStream().use { outputStream ->\n        bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream)\n        if (this !is BitmapDrawable) {\n            bitmap.recycle()\n        }\n        outputStream.toByteArray()\n    }\n}.onFailure { e ->\n    Log.w(TAG, \"Failed to convert Drawable to ByteArray: ${e.message}\", e)\n}.getOrNull()\n\nfun ByteArray.toDrawableOrNull(context: Context): Drawable? = runCatching {\n    val bitmap = BitmapFactory.decodeByteArray(this, 0, size)\n    bitmap.toDrawable(context.resources)\n}.onFailure { e ->\n    Log.w(TAG, \"Failed to convert ByteArray to Drawable: ${e.message}\", e)\n}.getOrNull()\n\n@RequiresApi(21)\nfun Context.sendBroadcastReceiver(callingPackage: String?, installingPackage: String?, status: Int = 0, statusMessage: String? = null, sessionId: Int = 0) {\n    try {\n        Log.d(TAG, \"transform broadcast to caller app start : $callingPackage, status: $status, sessionId:${sessionId}\")\n        if (callingPackage.isNullOrEmpty() || installingPackage.isNullOrEmpty()) {\n            return\n        }\n        val forwardIntent = Intent(INSTALL_RESULT_RECV_ACTION).apply {\n            putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId)\n            putExtra(PackageInstaller.EXTRA_STATUS, status)\n            putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, statusMessage)\n            putExtra(SOURCE_PACKAGE, packageName)\n            putExtra(EXTRA_INSTALL_PACKAGE, installingPackage)\n            setPackage(callingPackage)\n        }\n        sendBroadcast(forwardIntent)\n        Log.d(TAG, \"transform broadcast to caller app end: $callingPackage, status: $status, sessionId:${sessionId}\")\n    } catch (e: Exception) {\n        Log.d(TAG, \"error:${e.message}\")\n    }\n}"
  },
  {
    "path": "vending-app/src/main/kotlin/org/microg/vending/installer/AskInstallReminderActivity.kt",
    "content": "/**\n * SPDX-FileCopyrightText: 2025 microG Project Team\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage org.microg.vending.installer\n\nimport android.os.Bundle\nimport android.os.Message\nimport android.os.Messenger\nimport android.widget.Button\nimport android.widget.CheckBox\nimport android.widget.ImageView\nimport android.widget.TextView\nimport androidx.annotation.RequiresApi\nimport androidx.appcompat.app.AppCompatActivity\nimport com.android.vending.R\nimport org.microg.gms.utils.getApplicationLabel\nimport org.microg.gms.vending.AllowType\n\n@RequiresApi(21)\nclass AskInstallReminderActivity : AppCompatActivity() {\n\n    private lateinit var permissionDesc: TextView\n    private lateinit var appIconView: ImageView\n    private lateinit var appNameView: TextView\n    private lateinit var checkBox: CheckBox\n    private lateinit var btnAllow: Button\n    private lateinit var btnClose: ImageView\n    private var isNotShowAgainChecked: Boolean = false\n    private var isBtnClick: Boolean = false\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        setContentView(R.layout.activity_install_reminder)\n        setupViews()\n        setupListeners()\n    }\n\n    private fun setupViews() {\n        val callerPackage = intent.extras?.getString(EXTRA_CALLER_PACKAGE)?.takeIf { it.isNotEmpty() }\n            ?: return finishWithReply(AllowType.REJECT_ONCE.value)\n        val callerLabel = runCatching { packageManager.getApplicationLabel(callerPackage) }.getOrNull()\n            ?: return finishWithReply(AllowType.REJECT_ONCE.value)\n        val appIcon = intent?.getByteArrayExtra(EXTRA_INSTALL_PACKAGE_ICON)?.toDrawableOrNull(this)\n        val appLabel = intent?.getStringExtra(EXTRA_INSTALL_PACKAGE_LABEL)?.takeIf { it.isNotEmpty() }\n            ?: return finishWithReply(AllowType.REJECT_ONCE.value)\n\n        permissionDesc = findViewById(R.id.tv_description)\n        permissionDesc.text = getString(R.string.app_install_allow_to_install_third_app, callerLabel)\n        appIconView = findViewById(R.id.iv_app_icon)\n        appIcon?.let { appIconView.setImageDrawable(it) }\n        appNameView = findViewById(R.id.tv_app_name)\n        appNameView.text = appLabel\n        checkBox = findViewById(R.id.cb_dont_show_again)\n        checkBox.setOnCheckedChangeListener { _, isChecked -> isNotShowAgainChecked = isChecked }\n\n        btnAllow = findViewById(R.id.btn_allow)\n        btnClose = findViewById(R.id.btn_close)\n    }\n\n    private fun setupListeners() {\n        btnClose.setOnClickListener {\n            isBtnClick = true\n            finishWithReply(if (isNotShowAgainChecked) AllowType.REJECT_ALWAYS.value else AllowType.REJECT_ONCE.value)\n        }\n        btnAllow.setOnClickListener {\n            isBtnClick = true\n            finishWithReply(if (isNotShowAgainChecked) AllowType.ALLOW_ALWAYS.value else AllowType.ALLOW_ONCE.value)\n        }\n    }\n\n    override fun onStop() {\n        super.onStop()\n        if (!isBtnClick) {\n            finishWithReply()\n        }\n    }\n\n    private fun finishWithReply(code: Int = AllowType.REJECT_ONCE.value) {\n        intent?.getParcelableExtra<Messenger>(EXTRA_MESSENGER)?.let {\n            runCatching {\n                it.send(Message.obtain().apply { what = code })\n            }\n        }\n        finishAndRemoveTask()\n    }\n}"
  },
  {
    "path": "vending-app/src/main/proto/AssetModule.proto",
    "content": "option java_package = \"com.google.android.finsky\";\noption java_multiple_files = true;\n\nimport \"Timestamp.proto\";\n\nmessage AssetModuleDeliveryRequest {\n  optional string packageName = 1;\n  optional CallerInfo callerInfo = 2;\n  optional uint32 playCoreVersion = 3;\n  repeated uint32 supportedCompressionFormats = 4;\n  repeated uint32 supportedPatchFormats = 5;\n  repeated AssetModuleInfo modules = 6;\n  optional bool isInstantApp = 7;\n}\n\nmessage CallerInfo {\n  oneof Version {\n    int64 appVersionCode = 1;\n    string internalSharingId = 3;\n  }\n}\n\nmessage AssetModuleInfo {\n  optional string name = 1;\n  optional int64 type = 2;\n}\n\nmessage AssetModuleDeliveryResponse {\n  optional ModuleDeliveryWrapper wrapper = 1;\n}\n\nmessage ModuleDeliveryWrapper {\n  optional ModuleDeliveryInfo deliveryInfo = 151;\n}\n\nmessage ModuleDeliveryInfo {\n  repeated ModuleInfo modules = 3;\n  optional int32 status = 4;\n}\n\nmessage ModuleInfo {\n  optional string moduleName = 1;\n  optional int64 packVersion = 2;\n  repeated SliceInfo slices = 3;\n  optional int64 packBaseVersion = 4;\n  optional string packVersionTag = 5;\n}\n\nmessage SliceInfo {\n  optional SliceMetadata metadata = 1;\n  optional FullDownloadInfo fullDownloadInfo = 2;\n  optional PatchInfo patchInfo = 3;\n}\n\nmessage SliceMetadata {\n  optional string sliceId = 1;\n}\n\nmessage FullDownloadInfo {\n  optional int64 uncompressedSize = 1;\n  optional string uncompressedHashSha256 = 2;\n  optional uint32 compressionFormat = 3;\n  repeated ChunkInfo chunks = 4;\n}\n\nmessage PatchInfo {\n  optional uint32 patchFormat = 1;\n  repeated ChunkInfo chunks = 2;\n}\n\nmessage ChunkInfo {\n  optional int64 bytesToDownload = 1;\n  optional string sha256 = 2;\n  optional string sourceUri = 3;\n}\n"
  },
  {
    "path": "vending-app/src/main/proto/BulkGrant.proto",
    "content": "option java_package = \"com.google.android.finsky\";\noption java_multiple_files = true;\n\nmessage BulkRequestWrapper {\n\toptional BulkRequest request = 1;\n}\n\nmessage BulkRequest {\n\toptional string packageName = 1;\n\toptional BulkGrant grant = 2;\n}\n\nmessage BulkGrant{\n\toptional int32 grantLevel = 4;\n}\n\nmessage BulkResponseWrapper {\n\toptional BulkResponse response = 1;\n\toptional BulkBulkResponseError error = 2;\n}\n\nmessage BulkResponse {\n\n}\n\nmessage BulkBulkResponseError {\n\toptional string errorMsg = 2;\n}"
  },
  {
    "path": "vending-app/src/main/proto/DeliveryResponse.proto",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\noption java_package = \"org.microg.vending.delivery.proto\";\noption java_multiple_files = true;\n\nmessage DeliveryResponse {\n    optional DeliveryStatus status = 1;\n    optional DeliveryData deliveryData = 2;\n}\n\nenum DeliveryStatus {\n    SUCCESS = 1;\n    NOT_SUPPORTED = 2;\n    NOT_PURCHASED = 3;\n    APP_REMOVED = 7;\n    APP_NOT_SUPPORTED = 9;\n}\n\nmessage DeliveryData {\n    /*\n     * Size of the file downloaded through `baseUrl` in bytes.\n     */\n    optional uint32 baseBytes = 1;\n    /*\n     * Location of `base.apk`.\n     */\n    optional string baseUrl = 3;\n    repeated SplitDeliveryData splitPackages = 15;\n}\n\n/*\n * Encodes additional app bundle components (according to observations, both\n * OBB and split APK files).\n */\nmessage SplitDeliveryData {\n    optional string splitPackageName = 1;\n    /*\n     * Size of the package described by this message, i.e. the file at `downloadUrl`.\n     */\n    optional uint32 size = 2;\n    optional string sha1 = 4;\n    optional string downloadUrl = 5;\n    /*\n     * Alternative download? Meaning not clear, unused.\n     */\n    optional DownloadInfo downloadInfo1 = 8;\n    optional string sha256 = 9;\n    optional string unknownInfoString = 15;\n    /*\n     * Alternative download? Meaning not clear, unused.\n     */\n    optional DownloadInfo downloadInfo2 = 16;\n}\n\nmessage DownloadInfo {\n    optional int32 id = 1;\n    optional uint32 bytes = 2;\n    optional string url = 3;\n}\n"
  },
  {
    "path": "vending-app/src/main/proto/EnterpriseClientPolicy.proto",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\nsyntax = \"proto3\";\n\noption java_package = \"org.microg.vending.enterprise.proto\";\noption java_multiple_files = true;\n\nmessage EnterpriseClientPolicyResponse {\n    optional EnterprisePolicy policy = 1;\n}\n\nmessage EnterprisePolicy {\n    repeated App apps = 1;\n    // There are six more elements with unknown purpose.\n}\n\nmessage App {\n    optional string packageName = 1;\n    optional AppInstallPolicy policy = 2;\n    optional string emptyString = 4; // = \"\"\n    optional int32 unknownNumber = 9; // = 1\n}\n\n// TODO: could be inaccurate\nenum AppInstallPolicy {\n    UNKNOWN = 0;\n    OPTIONAL = 1;\n    MANDATORY = 3;\n}"
  },
  {
    "path": "vending-app/src/main/proto/GetItemsRequest.proto",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\nsyntax = \"proto3\";\n\noption java_package = \"org.microg.vending.proto\";\noption java_multiple_files = true;\n\nmessage GetItemsRequest {\n    repeated RequestItem items = 2;\n}\n\n// Reason for hierarchy is unknown.\n\nmessage RequestItem {\n    RequestApp app = 1;\n    LocalData local = 2;\n}\n\nmessage RequestApp {\n    AppMeta meta = 1;\n}\n\nmessage AppMeta {\n    optional string packageName = 1;\n}\n\nmessage LocalData {\n    // suspected to contain local version code and signature, if available\n}"
  },
  {
    "path": "vending-app/src/main/proto/GetItemsResponse.proto",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\nsyntax = \"proto3\";\n\noption java_package = \"org.microg.vending.proto\";\noption java_multiple_files = true;\n\nimport \"GetItemsRequest.proto\";\n\nmessage GetItemsResponse {\n    optional RequestApp query = 1;\n    optional ItemResponse response = 2;\n}\n\nmessage ItemResponse {\n    optional AppMeta meta = 1;\n    optional ItemAppDetail detail = 2;\n    optional ItemOffer offer = 3;\n}\n\nmessage ItemAppDetail {\n    optional Name name = 1;\n    optional ItemIcon icon = 2;\n}\n\nmessage Name {\n    optional string displayName = 1;\n}\n\nmessage ItemIcon {\n    optional IconVariant icon = 1;\n}\n\nmessage IconVariant {\n    optional IconPaint paint = 6;\n}\n\nmessage IconPaint {\n    optional string url = 1;\n}\n\nmessage ItemOffer {\n    optional ItemVersion version = 2;\n    optional ItemDelivery delivery = 28;\n}\n\nmessage ItemVersion {\n    optional int32 versionCode = 1;\n    optional int32 versionName = 2;\n}\n\nmessage ItemDelivery {\n    repeated ItemDependency dependencies = 10;\n    optional string key = 14;\n}\n\nmessage ItemDependency {\n    optional string packageName = 1;\n    optional int32 versionCode = 2;\n}\n"
  },
  {
    "path": "vending-app/src/main/proto/GooglePlayResponse.proto",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\nsyntax = \"proto3\";\n\noption java_package = \"org.microg.vending.billing.proto\";\noption java_multiple_files = true;\n\nimport \"EnterpriseClientPolicy.proto\";\nimport \"DeliveryResponse.proto\";\nimport \"LicenseResult.proto\";\nimport \"UploadDeviceConfigResponse.proto\";\nimport \"GetItemsResponse.proto\";\nimport \"Purchase.proto\";\n\nmessage GoogleApiResponse {\n    optional Payload payload = 1;\n    optional ServerCommands commands = 2;\n    repeated PreFetch preFetch = 3;\n    optional ServerMeta meta = 5;\n\n    optional bytes serverLogsCookie = 9; // not used\n\n    /*\n     * For getItems queries, field 1.145 only encodes some kind of index. The\n     * real content is here, at field 11.\n     */\n    repeated GetItemsResponse getItemsResponses = 11;\n}\n\nmessage Payload {\n    optional DetailsResponse detailsResponse = 2;\n    optional BuyResponse buyResponse = 4;\n    optional DeliveryResponse deliveryResponse = 21;\n    optional UploadDeviceConfigResponse uploadDeviceConfigResponse = 28;\n    optional ConsumePurchaseResponse consumePurchaseResponse = 30;\n    optional PurchaseHistoryResponse purchaseHistoryResponse = 67;\n    optional LicenseCheckV1Response licenseV1Response = 76;\n    optional SkuDetailsResponse skuDetailsResponse = 82;\n    optional AcquireResponse acquireResponse = 94;\n    optional EnterpriseClientPolicyResponse enterpriseClientPolicyResponse = 135;\n    optional AcknowledgePurchaseResponse acknowledgePurchaseResponse = 140;\n    optional LicenseCheckV2Response licenseV2Response = 173;\n    //    optional SyncApiResp syncResult = 183;\n}\n\nmessage ServerCommands {\n    bool clearCache = 1;\n    string displayErrorMessage = 2;\n    string logErrorStacktrace = 3;\n}\n\nmessage PreFetch {\n    string url = 1;\n    GoogleApiResponse response = 2;\n    string etag = 3;\n    int64 ttl = 4;\n    int64 softTtl = 5;\n}\n\nmessage ServerMeta {\n    optional int64 latencyMillis = 1;\n}"
  },
  {
    "path": "vending-app/src/main/proto/Integrity.proto",
    "content": "/*\n * SPDX-License-Identifier: Apache-2.0\n */\n\noption java_package = \"com.google.android.finsky\";\noption java_multiple_files = true;\n\nimport \"Timestamp.proto\";\n\nmessage IntegrityRequest {\n  oneof droidGuardToken {\n    string droidGuardTokenBase64 = 2;\n    bytes droidGuardTokenRaw = 5;\n  }\n  optional IntegrityParams params = 1;\n  optional CompressType compressType = 4;\n  optional string flowName = 3;\n  optional PlayCoreVersion playCoreVersion = 6;\n  optional PlayProtectDetails playProtectDetails = 7;\n  optional AppAccessRiskDetailsResponse appAccessRiskDetailsResponse = 8;\n}\n\nenum CompressType {\n  UNKNOWN_COMPRESSION_FORMAT = 0;\n  GZIP = 1;\n}\n\nmessage PackageNameWrapper {\n  optional string value = 1;\n}\n\nmessage VersionCodeWrapper {\n  optional int32 value = 1;\n}\n\nmessage IntegrityParams {\n  optional PackageNameWrapper packageName = 1;\n  optional VersionCodeWrapper versionCode = 2;\n  optional string nonce = 3;\n  repeated string certificateSha256Digests = 4;\n  optional Timestamp timestampAtRequest = 5;\n  optional int64 cloudProjectNumber = 6;\n}\n\nmessage InstalledAppsSignalDataWrapper {\n  optional string installedAppsSignalData = 1;\n}\n\nmessage ScreenCaptureSignalDataWrapper {\n  optional string screenCaptureSignalData = 1;\n}\n\nmessage ScreenOverlaySignalDataWrapper {\n  optional string screenOverlaySignalData = 1;\n}\n\nmessage AccessibilityAbuseSignalDataWrapper {\n  optional string accessibilityAbuseSignalData = 1;\n}\n\nmessage DisplayListenerMetadataWrapper {\n  optional int32 isActiveDisplayPresent = 1;\n  optional Timestamp displayListenerInitialisationTimeDelta = 2;\n  optional Timestamp lastDisplayAddedTimeDelta = 3;\n  optional int32 displayListenerUsed = 4;\n}\n\nmessage AppAccessRiskDetailsResponse {\n  optional InstalledAppsSignalDataWrapper installedAppsSignalDataWrapper = 1;\n  optional ScreenCaptureSignalDataWrapper screenCaptureSignalDataWrapper = 2;\n  optional ScreenOverlaySignalDataWrapper screenOverlaySignalDataWrapper = 3;\n  optional AccessibilityAbuseSignalDataWrapper accessibilityAbuseSignalDataWrapper = 4;\n  optional DisplayListenerMetadataWrapper displayListenerMetadataWrapper = 5;\n}\n\nmessage IntegrityResponse {\n  optional IntegrityContentWrapper contentWrapper = 1;\n  optional IntegrityResponseError integrityResponseError = 2;\n}\n\nmessage IntegrityResponseError {\n  optional string error = 2;\n}\n\nmessage IntegrityContentWrapper {\n  optional IntegrityContent content = 186;\n}\n\nmessage IntegrityContent {\n  optional string token = 1;\n}\n\nmessage PlayCoreVersion {\n  optional int32 major = 1;\n  optional int32 minor = 2;\n  optional int32 patch = 3;\n}\n\nmessage PlayProtectDetails {\n  optional PlayProtectState state = 1;\n}\n\nenum PlayProtectState {\n  PLAY_PROTECT_STATE_UNKNOWN_PHA_STATE = 0;\n  PLAY_PROTECT_STATE_NONE = 1;\n  PLAY_PROTECT_STATE_NO_PROBLEMS = 2;\n  PLAY_PROTECT_STATE_WARNING = 3;\n  PLAY_PROTECT_STATE_DANGER = 4;\n  PLAY_PROTECT_STATE_OFF = 5;\n}\n\nmessage MetricsUpdate {\n  optional string requestHash = 1;\n  optional int32 statesStored = 2;\n  optional int32 additionalStatesSet = 3;\n  optional int32 bytesStored = 4;\n}\n\nenum InstallerType {\n  UNSPECIFIED_INSTALLER = 0;\n  PHONESKY_INSTALLER = 1;\n  OTHER_INSTALLER = 2;\n}\n\nenum PackageSourceType {\n  PACKAGE_SOURCE_UNSPECIFIED = 0;\n  PACKAGE_SOURCE_STORE = 1;\n  PACKAGE_SOURCE_LOCAL_FILE = 2;\n  PACKAGE_SOURCE_DOWNLOADED_FILE = 3;\n  PACKAGE_SOURCE_OTHER = 4;\n}\n\nenum SystemAppFlag {\n  SYSTEM_APP_INFO_UNSPECIFIED = 0;\n  FLAG_SYSTEM = 1;\n  FLAG_UPDATED_SYSTEM_APP = 2;\n}\n\nmessage InstallSourceMetaData {\n  optional InstallerType initiatingPackageName = 1;\n  optional InstallerType installingPackageName = 2;\n  optional InstallerType originatingPackageName = 3;\n  optional InstallerType updateOwnerPackageName = 4;\n  repeated SystemAppFlag appFlags = 5;\n  optional PackageSourceType packageSourceType = 6;\n}\n\nmessage IntermediateIntegrityRequest {\n  optional bytes clientKeyExtendBytes = 1;\n  optional bytes deviceIntegrityToken = 2;\n  optional PlayCoreVersion playCoreVersion = 3;\n  optional PlayProtectDetails playProtectDetails = 4;\n  optional bytes expiredDeviceKey = 5;\n  optional RequestMode requestMode = 6;\n  optional int64 sessionId = 7;\n  message CertificateChainWrapper {\n    repeated bytes certificateChains = 1;\n  }\n  optional CertificateChainWrapper certificateChainWrapper = 8;\n  optional InstallSourceMetaData installSourceMetaData = 9;\n  optional int64 cloudProjectNumber = 10;\n}\n\nmessage IntermediateIntegrityResponseWrapperExtend {\n  optional IntermediateIntegrityResponseWrapper intermediateIntegrityResponseWrapper = 1;\n}\n\nmessage IntermediateIntegrityResponseWrapper {\n  optional IntermediateIntegrityResponse intermediateIntegrityResponse = 221;\n}\n\nenum AdviceType {\n  DEVICE_INTEGRITY_ADVICE_UNSPECIFIED = 0;\n  RESTORE_TO_FACTORY_ROM = 1;\n  LOCK_BOOTLOADER = 2;\n  REBOOT_DEVICE = 3;\n  GENERIC_NON_ACTIONABLE_ADVICE = 4;\n  INSTALL_SYSTEM_UPDATE = 5;\n}\n\nmessage IntegrityAdvice {\n  repeated AdviceType advices = 1 [packed=true];\n}\n\nmessage IntermediateIntegrityResponse {\n  optional bytes intermediateToken = 1;\n  optional Timestamp serverGenerated = 2;\n  optional bool appAccessRiskVerdictEnabled = 4;\n  optional TestErrorResponse errorInfo = 5;\n  optional IntegrityAdvice integrityAdvice = 6;\n}\n\nmessage ExpressIntegrityResponse {\n  optional bytes deviceIntegrityToken = 1;\n  optional bytes sessionHashAes128 = 3;\n  optional bytes appAccessRiskDetailsResponse = 4;\n}\n\nenum TestErrorType {\n  WARMUP = 1;\n  REQUEST_EXPRESS = 2;\n}\n\nmessage TestErrorResponse {\n  optional int32 errorCode = 1;\n  optional TestErrorType testErrorType = 2;\n}\n\nmessage IntermediateIntegritySession {\n  optional string requestHash = 1;\n  optional Timestamp creationTime = 2;\n  optional bytes sessionId = 3;\n  optional int32 timestampMillis = 4;\n}\n\nmessage TokenTime {\n  optional int64 type = 2;\n  optional Timestamp timestamp = 3;\n}\n\nmessage IntegrityTokenTime {\n  optional TokenTime warmUpTokenTime = 1;\n  optional TokenTime requestTokenTime = 2;\n}\n\nmessage IntegrityTokenTimeMap {\n  map<string, IntegrityTokenTime> timeMap = 1;\n}\n\nmessage ClientKey {\n  optional Timestamp generated = 2;\n  optional bytes keySetHandle = 3;\n}\n\nmessage AuthTokenWrapper {\n  optional DeviceIntegrityWrapper deviceIntegrityWrapper = 1;\n  optional ClientKey clientKey = 2;\n  optional Timestamp lastManualSoftRefreshTime = 3;\n}\n\nmessage DeviceIntegrityWrapper {\n  optional bytes deviceIntegrityToken = 1;\n  optional Timestamp creationTime = 2;\n  optional Timestamp serverGenerated = 3;\n  optional int32 errorCode = 5;\n}\n\nmessage IntegrityRequestWrapper {\n  optional DeviceIntegrityWrapper deviceIntegrityWrapper = 1;\n  optional ClientKey callerKey = 2;\n  optional string packageName = 3;\n  optional string accountName = 4;\n  optional uint64 cloudProjectNumber = 5;\n  optional int32 webViewRequestMode = 7;\n  optional IntegrityAdvice advice = 8;\n}\n\nmessage ExpressFilePB {\n  optional AuthTokenWrapper tokenWrapper = 2;\n  repeated IntegrityRequestWrapper integrityRequestWrapper = 3;\n  optional ClientKey clientKey = 4;\n  optional IntegrityTokenTimeMap integrityTokenTimeMap = 5;\n  optional ClientKey expiredDeviceKey = 6;\n}\n\nmessage AccountNameWrapper {\n  optional string accountName = 1;\n}\n\nenum INSTALLED_APPS_STATUS {\n  UNKNOWN_INSTALLED_APPS_SIGNAL = 0;\n  RECOGNIZED_APPS_INSTALLED = 1;\n  UNRECOGNIZED_APPS_INSTALLED = 2;\n}\n\nmessage RequestMode {\n  optional int32 mode = 1;\n}\n\nmessage ClientKeyExtend {\n  optional string optPackageName = 1;\n  optional int32 versionCode = 2;\n  repeated string certificateSha256Hashes = 3;\n  optional int64 cloudProjectNumber = 4;\n  optional bytes keySetHandle = 5;\n  optional bytes deviceSerialHash = 6;\n  optional InstallSourceMetaData installSourceMetaData = 7;\n}\n\nmessage TokenRequestWrapper {\n  repeated TokenRequest request = 1;\n}\n\nmessage TokenRequest {\n  oneof body {\n    DroidGuardBody droidGuardBody = 5;\n  }\n}\n\nmessage DroidGuardBody {\n  oneof content {\n    DeviceIntegrityTokenContent deviceBody = 1;\n    DroidGuardSessionTokenContent tokenBody = 2;\n  }\n}\n\nmessage DeviceIntegrityTokenContent {\n  oneof session {\n    SessionWrapper sessionWrapper = 1;\n  }\n  optional string token = 2;\n  optional string flowName = 3;\n}\n\nmessage SessionWrapper {\n  optional string type = 1;\n  optional Session session = 2;\n}\n\nmessage Session {\n  optional string id = 1;\n}\n\nmessage DroidGuardSessionTokenContent {}\n\nmessage TokenResponse {\n  optional TokenWrapper tokenWrapper = 1;\n}\n\nmessage TokenWrapper {\n  optional TokenContent tokenContent = 183;\n}\n\nmessage TokenContent {\n  repeated TokenType tokenType = 1;\n  repeated string c = 3;\n}\n\nmessage TokenType {\n  oneof token {\n    TokenSessionWrapper tokenSessionWrapper = 2;\n  }\n  optional int64 type = 1;\n}\n\nmessage TokenSessionWrapper {\n  optional SessionContentWrapper wrapper = 1;\n}\n\nmessage SessionContentWrapper {\n  oneof content {\n    SessionContent sessionContent = 4;\n  }\n}\n\nmessage SessionContent {\n  oneof content {\n    TokenV1Content tokenContent = 2;\n  }\n  optional Session session = 1;\n}\n\nmessage TokenV1Content {\n  optional TokenV1Wrapper tokenWrapper = 1;\n}\n\nmessage TokenV1Wrapper {\n  optional bytes token = 1;\n}"
  },
  {
    "path": "vending-app/src/main/proto/LicenseResult.proto",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\nsyntax = \"proto2\";\n\noption java_package = \"org.microg.vending.licensing.proto\";\noption java_multiple_files = true;\n\nmessage LicenseCheckV1Response {\n  optional uint32 result = 1;\n  optional string signedData = 2;\n  optional string signature = 3;\n\n}\n\nmessage LicenseCheckV2Response {\n  optional AppLicense license = 1;\n}\n\nmessage AppLicense {\n  optional string jwt = 1;\n}"
  },
  {
    "path": "vending-app/src/main/proto/Locality.proto",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\nsyntax = \"proto2\";\n\noption java_package = \"org.microg.vending.proto\";\noption java_multiple_files = true;\n\nimport \"Timestamp.proto\";\n\nmessage Locality {\n  optional uint32 unknown1 = 2; // value: 1\n  optional uint32 unknown2 = 3; // value: 0\n  optional string countryCode = 4; // e.g. \"DE\"\n  optional TimestampStringWrapper region = 8; // e.g. \"DE-BY\" and a timestamp\n  optional TimestampStringWrapper country = 9; // e.g. \"DE\" and a timestamp\n  optional uint32 unknown3 = 11; // value: 0\n\n}\n\nmessage TimestampStringWrapper {\n  optional string string = 1;\n  optional Timestamp timestamp = 2;\n}\n"
  },
  {
    "path": "vending-app/src/main/proto/Purchase.proto",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 microG project team\n * SPDX-License-Identifier: Apache-2.0\n */\n\nsyntax = \"proto3\";\n\noption java_package = \"org.microg.vending.billing.proto\";\noption java_multiple_files = true;\n\nimport \"Timestamp.proto\";\n\n\nmessage SkuDetailsRequest {\n  int32 apiVersion = 1;\n  string package = 2;\n  string type = 3;\n  repeated string skuId = 4;\n  repeated DynamicSku dynamicSku = 5;\n  bool isWifi = 6;\n  SkuDetailsExtra skuDetailsExtra = 7;\n  string skuPackage = 8;\n  repeated OfferSku offerSkus = 9;\n  repeated MultiOfferSkuDetail multiOfferSkuDetail = 10;\n}\n\nmessage AcquireRequest {\n  DocumentInfo documentInfo = 1;\n  ClientInfo clientInfo = 2;\n  bytes serverContextToken = 3;\n  repeated bytes actionContext = 4;\n  string clientTokenB64 = 5;\n  DeviceAuthInfo deviceAuthInfo = 8;\n  map<string, string> authTokens = 9;\n  UnkMessage5 unknown12 = 12;\n  string deviceIDBase64 = 19;\n  string newAcquireCacheKey = 20;\n  string nonce = 22;\n  int32 theme = 25;\n  Timestamp ts = 31;\n}\n\nmessage CKDocument {\n  DocId docId = 1;\n  oneof SkuOfferIdToken {\n    string token3 = 2;\n    string token14 = 4;\n  }\n  int32 unknown3 = 3;\n}\n\nmessage DeviceAuthInfo {\n  bool canAuthenticate = 1; \n  bool isBiometricStrong = 2;\n  bool fingerprintValid = 3;\n  int32 desiredAuthMethod = 4;\n  int32 unknown5 = 5;\n  int32 authFrequency = 6;\n  bool unknown9 = 9;\n  bool userHasFop = 16;\n  map<string, string> authParams = 18;\n  bool unknown20 = 20;\n  ItemColor itemColor = 26;\n  string droidGuardPayload = 30;\n}\n\nmessage UnkMessage5 {\n  int32 unknown1 = 1;\n}\n\nmessage ItemColor {\n  int32 androidAppsColor = 1;\n  int32 booksColor = 2;\n  int32 musicColor = 3;\n  int32 moviesColor = 4;\n  int32 newsStandColor = 5;\n}\n\nmessage ClientInfo {\n  int32 apiVersion = 1;\n  string package = 2;\n  int32 versionCode = 3;\n  string signatureMD5 = 4;\n  repeated SkuParam skuParamList = 7;\n  int32 unknown8 = 8;\n  string installerPackage = 9;\n  bool unknown10 = 10;\n  bool unknown11 = 11;\n  UnkMessage1 unknown15 = 15;\n  oneof OldSkuPurchase {\n    string oldSkuPurchaseToken = 16;\n    string oldSkuPurchaseId = 17;\n  }\n  int32 versionCode1 = 18;\n}\n\nmessage ClientToken {\n  Info1 info1 = 1;\n  Info2 info2 = 2;\n  message Info1 {\n    bytes unknown2 = 2;\n    string locale = 7;\n    int32 unknown8 = 8;\n    int64 gpVersionCode = 9;\n    DeviceInfo deviceInfo = 10;\n    string unknown11 = 11;\n    repeated string googleAccounts = 19;\n  }\n  message Info2 {\n    string unknown1 = 1;\n    int32 unknown3 = 3;\n    repeated int32 unknown4 = 4;\n    int32 unknown5 = 5;\n  }\n  message DeviceInfo {\n    string unknown3 = 3;\n    string device = 4;\n    int32 widthPixels = 5;\n    int32 heightPixels = 6;\n    float xdpi = 7;\n    float ydpi = 8;\n    string gpPackage = 9;\n    string gpVersionCode = 10;\n    string gpVersionName = 11;\n    EnvInfo envInfo = 12;\n    string callingPackage = 13;\n    string marketClientId = 14;\n    int32 unknown15 = 15;\n    int32 unknown16 = 16;\n    string simOperatorName = 17;\n    string groupIdLevel1 = 18;\n    int64 subscriberId = 19;\n    int32 unknown22 = 22;\n    int64 linkDownstreamBandwidth = 23;\n    int64 linkUpstreamBandwidth = 24;\n    bool  isActiveNetworkMetered = 25;\n    int32 densityDpi = 28;\n    int32 unknown34 = 34;\n    int64 uptimeMillis = 35;\n    string timeZoneDisplayName = 36;\n    int32 unknown40 = 40;\n  }\n\n  message EnvInfo {\n    DeviceData deviceData = 1;\n    OtherInfo otherInfo = 2;\n  }\n\n  message DeviceData {\n    int32 unknown1 = 1;\n    string simOperatorName = 2;\n    string phoneDeviceId = 3;\n    string phoneDeviceId1 = 5;\n    string line1Number = 6;\n    int64 gsfId = 7;\n    string device = 9;\n    string product = 10;\n    string model = 11;\n    string manufacturer = 12;\n    string fingerprint = 13;\n    string release = 15;\n    string brand = 21;\n    string serial = 22;\n    bool isEmulator = 24;\n  }\n\n  message OtherInfo {\n    repeated GPInfo gpInfo = 1;\n    int32 batteryLevel = 3;\n    int64 timeZoneOffset = 4;\n    Location location = 6;\n    bool isAdbEnabled = 7;\n    bool installNonMarketApps = 8;\n    string iso3Language = 9;\n    repeated string netAddress = 10;\n    string locale = 11;\n    string networkOperator = 14;\n    string simOperator = 15;\n    string language = 18;\n    string country = 19;\n    int32 phoneType = 20;\n    int64 uptimeMillis = 21;\n    string timeZoneDisplayName = 22;\n    int32 googleAccountCount = 23;\n    bool isUserAMonkey = 24;\n    bool isAudioWork = 25;\n    bool hasUsbFeature = 26;\n    bool isChanging = 27;\n    int32 brightness = 28;\n  }\n  message GPInfo {\n    string package = 1;\n    string versionCode = 2;\n    int64 lastUpdateTime = 3;\n    int64 firstInstallTime = 4;\n    string sourceDir = 5;\n  }\n  message Location {\n    double altitude = 1;\n    double latitude = 2;\n    double longitude = 3;\n    float accuracy = 4;\n    double time = 5;\n    bool isMock = 6;\n  }\n}\n\nmessage UnkMessage1 {\n  oneof Type {\n    UnkMessage2 unknown1 = 1;\n    UnkMessage3 unknown2 = 2;\n    UnkMessage4 unknown3 = 3;\n  }\n}\n\nmessage UnkMessage2 {\n  int32 unknown1 = 1;\n}\n\nmessage UnkMessage3 {\n  int32 unknown1 = 1;\n}\n\nmessage UnkMessage4 {\n  int32 unknown1 = 1;\n}\n\nmessage SkuParam {\n  string name = 1;\n  string sv = 2;\n  bool bv = 3;\n  int64 i64v = 4;\n  repeated string svList = 5;\n}\n\nmessage DocumentInfo {\n  DocId docId = 1;\n  int32 unknown2 = 2;\n  oneof SkuOfferIdToken {\n    string token3 = 3;\n    string token14 = 14;\n  }\n}\n\nmessage AcknowledgePurchaseRequest {\n  string purchaseToken = 1;\n  string developerPayload = 2;\n}\n\nmessage MultiOfferSkuDetail {\n  string key = 1;\n  oneof value {\n    string sv = 2;\n    bool  bv = 3;\n    int64 iv = 4;\n    SkuSerializedDocIds skuSerializedDocIds = 5;\n  }\n}\n\nmessage SkuSerializedDocIds {\n  repeated string docIds = 1;\n}\n\nmessage OfferSku {\n  string unknown1 = 1;\n  string unknown2 = 2;\n}\n\nmessage SkuDetailsExtra {\n  string version = 1;\n}\n\nmessage DynamicSku {\n  string unknown1 = 1;\n  string unknown2 = 2;\n  string unknown3 = 3;\n}\n\nmessage DetailsResponse {\n  Item item = 4;\n}\n\nmessage BuyResponse {\n  string deliveryToken = 55;\n}\n\nmessage Item {\n  Offer offer = 8;\n  repeated Item subItem = 11;\n  DocumentDetails details = 13;\n}\n\nmessage DocumentDetails {\n  AppDetails appDetails = 1;\n}\n\nmessage AppDetails {\n  int32 versionCode = 3;\n  string packageName = 14;\n}\n\nmessage Offer {\n  int64 micros = 1;\n  int32 offerType = 8;\n  string offerId = 19;\n}\n\nmessage AcquireResponse {\n  map<string, Screen> screen = 1;\n  AcquireResult acquireResult = 3;\n  bytes serverContextToken = 4;\n  Action action = 8;\n  bool needClear = 11;\n}\n\nmessage AcquireResult {\n  repeated PurchaseItem purchaseItem = 3;\n  OwnedPurchase ownedPurchase = 8;\n  string signature = 9;\n  PurchaseResponse purchaseResponse = 10;\n}\n\nmessage OwnedPurchase {\n  repeated PurchaseItem purchaseItem = 1;\n}\n\nmessage PurchaseResponse {\n  bool isSuccessful = 1;\n  ResponseBundle responseBundle = 2;\n}\n\nmessage ResponseBundle {\n  repeated BundleItem bundleItem = 1;\n}\n\nmessage BundleItem {\n  string key = 1;\n  oneof value {\n    string sv = 2;\n    bool bv = 3;\n    int64 i64v = 4;\n    int32 i32v = 5;\n    BundleStringList sList = 6;\n  }\n}\n\nmessage BundleStringList {\n  repeated string value = 1;\n}\n\nmessage Screen {\n  UIInfo uiInfo = 1;\n  Action action = 5;\n  UiComponents uiComponents = 175996169;\n}\n\nmessage UiComponents {\n  repeated ContentComponent contentComponent1 = 1;\n  repeated ContentComponent contentComponent2 = 2;\n  repeated FooterComponent footerComponent = 3;\n}\n\nmessage ContentComponent {\n  UIInfo uiInfo = 1;\n  ViewInfo viewInfo = 2;\n  string tag = 4;\n  oneof UiComponent {\n    ClickableTextView clickableTextView = 20;\n    ViewGroup viewGroup = 21;\n    DividerView dividerView = 23;\n    InstrumentItemView instrumentItemView = 26;\n    ModuloImageView moduloImageView = 27;\n    IconTextCombinationView iconTextCombinationView = 37;\n    ButtonGroupView buttonGroupView = 57;\n  }\n}\n\nmessage InstrumentItemView {\n  ImageView icon = 1;\n  PlayTextView text = 2;\n  PlayTextView tips = 3;\n  ImageView state = 5;\n  Action action = 6;\n  PlayTextView extraInfo = 7;\n}\n\nmessage ModuloImageView {\n  ImageView imageView = 1;\n  Action action = 2;\n}\n\nmessage DividerView {\n}\n\nmessage ClickableTextView {\n  PlayTextView playTextView = 1;\n  Action action = 2;\n}\n\nmessage IconView {\n  int32 type = 1;\n  string text = 2;\n}\n\nmessage ImageInfo {\n  oneof ColorFilter{\n    int32 value = 1;\n    int32 valueType = 3;\n  }\n  int32 modeType = 2;\n  int32 scaleType = 5;\n}\n\nmessage ImageView {\n  ThumbnailImageView thumbnailImageView = 1;\n  ViewInfo viewInfo = 2;\n  ImageInfo imageInfo = 4;\n  IconView iconView = 5;\n  oneof AnimationType{\n    Animation animation = 6;\n  }\n}\n\nmessage Animation {\n  int32 type = 1;\n  int32 repeatCount = 2;\n}\n\nmessage ViewGroup {\n  ImageView imageView1 = 1;\n  ImageView imageView2 = 2;\n  ImageView imageView3 = 3;\n  ImageView imageView4 = 4;\n  PlayTextView playTextView = 5;\n}\n\nmessage ViewInfo {\n  string tag = 1;\n  float widthValue = 2;\n  float heightValue = 3;\n  float startMargin = 4;\n  float topMargin = 5;\n  float endMargin = 6;\n  float bottomMargin = 7;\n  float startPadding = 8;\n  float topPadding = 9;\n  float endPadding = 10;\n  float bottomPadding = 11;\n  int32 backgroundColor = 12;\n  int32 backgroundColorType = 37;\n  string contentDescription = 14;\n  Action action = 20;\n  repeated int32 gravity = 22;\n  int32 widthTypedValue = 23;\n  int32 heightTypedValue = 24;\n  int32 visibilityType = 29;\n  int32 borderColorType = 30;\n  int32 startMarginType = 41;\n  int32 topMarginType = 42;\n  int32 endMarginType = 43;\n  int32 bottomMarginType = 44;\n  int32 startPaddingType = 45;\n  int32 topPaddingType = 46;\n  int32 endPaddingType = 47;\n  int32 bottomPaddingType = 48;\n}\n\nmessage ThumbnailImageView {\n  string lightUrl = 5;\n  string darkUrl = 28;\n}\n\nmessage ImageGroup {\n  repeated ImageView imageView = 1;\n  ViewInfo viewInfo = 2;\n}\n\nmessage IconTextCombinationView {\n  ImageView headerImageView = 1;\n  PlayTextView playTextView = 2;\n  repeated SingleLineTextView singleLineTextView = 5;\n  ViewInfo viewInfo = 6;\n  PlayTextView badgeTextView = 9;\n  ImageGroup footerImageGroup = 12;\n}\n\nmessage SingleLineTextView {\n  PlayTextView playTextView1 = 1;\n  PlayTextView playTextView2 = 2;\n}\n\nmessage Dimension {\n  int32 unitType = 1;\n  float unitValue = 2;\n}\n\nmessage BulletSpan {\n  Dimension gapWidth = 1;\n}\n\nmessage TextSpan {\n  oneof Span {\n    BulletSpan bulletSpan = 4;\n  }\n}\n\nmessage PlayTextView {\n  oneof TextData {\n    string text = 1;\n    int32 textType = 10;\n  }\n  bool isHtml = 2;\n  ViewInfo viewInfo = 3;\n  TextInfo textInfo = 4;\n  repeated TextSpan textSpan = 7;\n}\n\nmessage TextInfo {\n  oneof TextColor {\n    int32 textColorValue = 2;\n    int32 textColorType = 39;\n  }\n  int32 maxLines = 6;\n  repeated int32 gravity = 17;\n  int32 textAlignmentType = 36;\n  int32 styleType = 41;\n}\n\nmessage FooterComponent {\n  UIInfo uiInfo = 1;\n  ViewInfo viewInfo = 2;\n  string tag = 5;\n  oneof UiComponent {\n    ButtonGroupView buttonGroupView = 22;\n    DividerView dividerView = 24;\n    IconTextCombinationView iconTextCombinationView = 25;\n  }\n}\n\nmessage ButtonGroupView {\n  NewButtonView newButtonView = 6;\n}\n\nmessage NewButtonView {\n  ButtonView buttonView = 1;\n  ButtonView buttonView2 = 2;\n}\n\nmessage ButtonView {\n  oneof TextData {\n    string text = 1;\n    int32 fixedTextType = 9;\n  }\n  Action action = 2;\n  ViewInfo viewInfo = 4;\n}\n\nmessage UIInfo {\n  int32 uiType = 1;\n  bytes context = 2;\n  int32 classType = 5;\n}\n\nmessage NavigateToPage {\n  string id = 1;\n  string from = 2;\n  Action action = 3;\n}\n\nmessage Action {\n  TimerAction timerAction = 3;\n  ShowAction showAction = 4;\n  bytes actionContext = 7;\n  NavigateToPage navigateToPage = 8;\n  ViewClickAction viewClickAction = 10;\n  OptionalAction optionalAction = 19;\n  ActionExt actionExt = 148814548;\n}\n\nmessage OptionalAction {\n  repeated int32 unknown1 = 1;\n  Action action1 = 2;\n  Action action2 = 3;\n}\n\nmessage ViewClickAction {\n  UIInfo uiInfo = 2;\n  Action action = 3;\n}\n\nmessage TimerAction {\n  ResponseBundle responseBundle = 1;\n  bool isSuccessful = 2;\n  int32 delay = 3;\n  string url = 4;\n}\n\nmessage ShowAction {\n  string screenId = 1;\n  Action action = 7;\n  Action action1 = 8;\n}\n\nmessage ExtAction {\n  Action action = 1;\n  DroidGuardMap droidGuardMap = 20;\n}\n\nmessage IABX {\n  repeated SkuParam skuParam = 1;\n}\n\nmessage DroidGuardMap {\n  map<string, string> map = 1;\n  int32 type = 2;\n}\n\nmessage ActionExt {\n  ExtAction extAction = 1;\n}\n\nmessage AcknowledgePurchaseResponse {\n  PurchaseItem purchaseItem = 1;\n  FailedResponse failedResponse = 2;\n}\n\nmessage SkuDetailsResponse {\n  repeated SkuDetails details = 1;\n  bool unknown2 = 2;\n  FailedResponse failedResponse = 4;\n  repeated SkuInfo skuInfo = 6;\n}\n\nmessage SkuInfo {\n  repeated SkuItem skuItem = 1;\n}\n\nmessage SkuItem {\n  DocId docId = 1;\n  string unknown2 = 2;\n  string token = 3;\n}\n\nmessage DocId {\n  string backendDocId = 1;\n  int32 type = 2;\n  int32 backend = 3;\n}\n\nmessage SkuDetails {\n  string skuDetails = 1;\n  SkuInfo skuInfo = 4;\n}\n\nmessage ConsumePurchaseResponse {\n  PurchaseItem purchaseItem = 1;\n  FailedResponse failedResponse = 3;\n}\n\nmessage PurchaseItem {\n  repeated PurchaseItemData purchaseItemData = 4;\n}\n\nmessage PurchaseItemData {\n  DocId docId = 1;\n  SubsPurchase subsPurchase = 6;\n  InAppPurchase inAppPurchase = 7;\n}\n\nmessage InAppPurchase {\n  string jsonData = 1;\n  string signature = 2;\n}\n\nmessage SubsPurchase {\n  int64 startAt = 1;\n  int64 expireAt = 2;\n  string jsonData = 5;\n  string signature = 6;\n}\n\nmessage FailedResponse {\n  int32 statusCode = 1;\n  string msg = 2;\n}\n\nmessage PurchaseHistoryResponse {\n  repeated string productId = 1;\n  repeated string purchaseJson = 2;\n  repeated string signature = 3;\n  string continuationToken = 4;\n  FailedResponse failedResponse = 5;\n}"
  },
  {
    "path": "vending-app/src/main/proto/RequestHeader.proto",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\nsyntax = \"proto2\";\n\noption java_package = \"org.microg.vending.proto\";\noption java_multiple_files = true;\n\nmessage RequestHeader {\n  optional StringWrapper encodedTimestamps = 1;\n  optional EncodedTripleWrapper triple = 10;\n  optional LocalityWrapper locality = 11;\n  optional IntWrapper unknown = 12;\n  optional string empty = 14;\n  optional RequestLanguagePackage languages = 15;\n  optional DeviceMeta deviceMeta = 20;\n  optional UserAgent userAgent = 21;\n  optional Uuid uuid = 27;\n}\n\nmessage StringWrapper {\n  optional string string = 1;\n}\n\nmessage EncodedTripleWrapper {\n  optional EncodedTriple triple = 1;\n}\n\nmessage EncodedTriple {\n  optional string encoded1 = 1;\n  optional string encoded2 = 2;\n  optional string empty = 3;\n}\n\nmessage LocalityWrapper {\n  optional string encodedLocalityProto = 1;\n}\n\nmessage IntWrapper {\n  optional uint32 integer = 1;\n}\n\nmessage RequestLanguagePackage {\n  repeated string language = 1;\n}\n\nmessage DeviceMeta {\n  optional AndroidVersionMeta android = 1;\n  optional string unknown1 = 2; // inconsistent observations; a field of type \"UnknownByte12\" was observed as well\n  optional uint32 unknown2 = 3; // observed value: 1\n\n}\n\nmessage AndroidVersionMeta {\n  optional uint32 androidSdk = 1;\n  optional string buildNumber = 2;\n  optional string androidVersion = 3;\n  optional uint32 unknown = 4;\n}\n\nmessage UnknownByte12 {\n  optional bytes bytes = 12;\n}\n\nmessage UserAgent {\n  // The names of these attributes are vague guesses and should be adapted if needed.\n  optional string deviceName = 1; // e.g. \"OnePlusNord\"\n  optional string deviceHardware = 2; // e.g. \"qcom\"\n  optional string deviceModelName = 3; // e.g. \"OnePlus Nord\"\n  optional string finskyVersion = 4; // e.g. \"Finsky/37.5.24-29%20%5B0%5D%20%5BPR%5D%20565477504\"\n  optional string deviceProductName = 5; // e.g. \"OnePlusNord\"\n  optional uint64 androidId = 6;\n  optional string buildFingerprint = 7; // e.g. \"google/walleye/walleye:8.1.0/OPM1.171019.011/4448085:user/release-keys\"\n}\n\nmessage Uuid {\n  optional string uuid = 1;\n  optional uint32 unknown = 2; // might be a constant, e.g. format ID. Observed value: 2.\n}\n"
  },
  {
    "path": "vending-app/src/main/proto/SyncRequest.proto",
    "content": "/*\n * SPDX-License-Identifier: Apache-2.0\n */\n\noption java_package = \"com.google.android.finsky\";\noption java_multiple_files = true;\n\nmessage SyncReqWrapper {\n  repeated SyncRequest request = 1;\n}\n\nmessage SyncRequest {\n  oneof payload {\n    AccountAssociationPayload accountAssociationPayload = 7;\n    DeviceAccountsPayload deviceAccountsPayload = 8;\n    CarrierPropertiesPayload carrierPropertiesPayload = 9;\n    DeviceCapabilitiesPayload deviceCapabilitiesPayload = 10;\n    DeviceInputPropertiesPayload deviceInputPropertiesPayload = 11;\n    DeviceModelPayload deviceModelPayload = 12;\n    EnterprisePropertiesPayload enterprisePropertiesPayload = 13;\n    HardwareIdentifierPayload hardwareIdentifierPayload = 14;\n    HardwarePropertiesPayload hardwarePropertiesPayload = 15;\n    LocalePropertiesPayload localePropertiesPayload = 16;\n    NotificationRoutingInfoPayload notificationRoutingInfoPayload = 17;\n    PlayPartnerPropertiesPayload playPartnerPropertiesPayload = 18;\n    PlayPropertiesPayload playPropertiesPayload = 19;\n    ScreenPropertiesPayload screenPropertiesPayload = 20;\n    SystemPropertiesPayload systemPropertiesPayload = 21;\n    GpuPayload gpuPayload = 24;\n  }\n}\n\nmessage AccountAssociationPayload {\n  optional AccountAssValue accountAss = 1;\n}\n\nmessage AccountAssValue {\n  optional string value = 1;\n}\n\nmessage DeviceAccountsPayload {\n  repeated AccountAssValue accountAss = 1;\n}\n\nmessage CarrierPropertiesPayload {\n  optional string simOperator = 1;\n  optional TelephonyStateWrapper telephonyStateValue = 2;\n}\n\nmessage TelephonyStateWrapper {\n  optional TelephonyInfo telephonyInfo = 1;\n}\n\nmessage TelephonyInfo {\n  optional int64 subscriberId = 1;\n  optional string operatorName = 2;\n  optional string groupIdLevel = 3;\n  optional int32 simCardId = 6;\n  optional int32 carrierIdFromSimMccMnc = 7;\n}\n\nmessage DeviceCapabilitiesPayload {\n  repeated FeatureInfoProto featureInfo = 1;\n  repeated string systemSharedLibraryNames = 2;\n  repeated string locales = 3;\n  repeated string glExtensions = 4;\n  optional bool unknownFlag = 5;\n}\n\nmessage DeviceInputPropertiesPayload {\n  optional int32 reqKeyboardType = 1;\n  optional bool reqInputFeatures = 2;\n  optional int32 reqNavigation = 3;\n}\n\nmessage DeviceModelPayload {\n  optional string manufacturer = 1;\n  optional string model = 2;\n  optional string device = 3;\n  optional string product = 4;\n  optional string brand = 5;\n}\n\nmessage EnterprisePropertiesPayload {\n  optional ProfileInfo profileOwner = 1;\n  repeated ProfileInfo default = 2;\n}\n\nmessage ProfileInfo {\n  optional string pkgName = 1;\n  optional string pkgSHA1 = 2;\n  optional string pkgSHA256 = 3;\n  optional MangedScope policyType = 4;\n}\n\nenum MangedScope {\n  UNKNOWN_MANAGED_SCOPE = 0;\n  MANAGED_DEVICES = 1;\n  MANAGED_PROFILES = 2;\n  MANAGED_AVENGER = 3;\n  LEGACY_DEVICE_ADMINS = 4;\n}\n\nmessage HardwareIdentifierPayload {\n  optional fixed64 imeId = 1;\n}\n\nmessage HardwarePropertiesPayload {\n  optional bool isLowRamDevice = 1;\n  optional int64 totalMem = 2;\n  optional int32 availableProcessors = 3;\n  repeated string supportedAbi = 4;\n}\n\nmessage LocalePropertiesPayload {\n  optional string locale = 1;\n}\n\nmessage NotificationRoutingInfoPayload {\n  optional string info = 1;\n}\n\nmessage PlayPartnerPropertiesPayload {\n  optional string marketId = 1;\n  optional string partnerIdMs = 2;\n  optional string partnerIdAd = 3;\n}\n\nmessage PlayPropertiesPayload {\n  optional int32 playVersion = 2;\n}\n\nmessage ScreenPropertiesPayload {\n  optional int32 reqTouchScreen = 1;\n  optional int32 displayX = 2;\n  optional int32 displayY = 3;\n  optional int32 deviceStablePoint = 4;\n  optional int32 deviceStable = 5;\n}\n\nmessage SystemPropertiesPayload {\n  optional string fingerprint = 1;\n  optional int64 sdkInt = 2;\n  optional string previewSdkFingerprint = 3;\n  optional string buildCodeName = 4;\n  optional string oemKey = 5;\n  optional int32 reqGlEsVersion = 6;\n}\n\nmessage GpuPayload {\n  optional GpuInfoWrapper gpuInfo = 1;\n}\n\nmessage GpuInfoWrapper {\n  optional string glRenderer = 1;\n  optional string glVendor = 2;\n  optional string glVersion = 3;\n}\n\nmessage DeviceInfoCollect {\n  optional int32 reqTouchScreen = 1;\n  optional int32 reqKeyboardType = 2;\n  optional int32 reqNavigation = 3;\n  optional int32 deviceStablePoint = 4;\n  optional bool reqInputFeaturesV1 = 5;\n  optional bool reqInputFeaturesV2 = 6;\n  optional int32 deviceStable = 7;\n  optional int32 reqGlEsVersion = 8;\n  repeated string systemSharedLibraryNames = 9;\n  repeated string featureNames = 10;\n  repeated string supportedAbi = 11;\n  optional int32 displayX = 12;\n  optional int32 displayY = 13;\n  repeated string locales = 14;\n  repeated string glExtensions = 15;\n  optional int32 smallestScreenWidthDp = 18;\n  optional bool isLowRamDevice = 19;\n  optional int64 totalMem = 20;\n  optional int32 availableProcessors = 21;\n  repeated FeatureInfoProto featureInfoList = 26;\n  optional int32 screenLayout = 27;\n  optional string oemKey = 29;\n  optional string buildCodeName = 30;\n  optional string previewSdkFingerprint = 31;\n}\n\nmessage FeatureInfoProto {\n  optional string name = 1;\n  optional int32 version = 2;\n}\n\nmessage SyncResponse {}\n"
  },
  {
    "path": "vending-app/src/main/proto/Timestamp.proto",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\nsyntax = \"proto2\";\n\noption java_package = \"org.microg.vending.proto\";\noption java_multiple_files = true;\n\nmessage TimestampContainer {\n  optional TimestampContainer1Wrapper container1Wrapper = 3;\n  optional TimestampContainer2 container2 = 6;\n}\n\nmessage TimestampContainer1Wrapper {\n  optional string androidId = 1;\n  optional TimestampContainer1 container = 2;\n}\n\nmessage TimestampContainer1 {\n  optional string timestamp = 1;\n  optional Timestamp wrapper = 2;\n}\n\nmessage Timestamp {\n  optional uint64 seconds = 1;\n  optional uint32 nanos = 2;\n}\n\nmessage TimestampContainer2 {\n  optional TimestampWrapper wrapper = 1;\n  optional Timestamp timestamp = 2;\n}\n\nmessage TimestampWrapper {\n  optional Timestamp timestamp = 1;\n}"
  },
  {
    "path": "vending-app/src/main/proto/UploadDeviceConfigResponse.proto",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 e foundation\n * SPDX-License-Identifier: Apache-2.0\n */\n\nsyntax = \"proto3\";\n\noption java_package = \"org.microg.vending.proto\";\n\nmessage UploadDeviceConfigResponse {\n    optional string deviceConfigToken = 1;\n}"
  },
  {
    "path": "vending-app/src/main/res/drawable/ic_cancel.xml",
    "content": "<!--\n  ~ SPDX-FileCopyrightText: 2024 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:height=\"24dp\"\n    android:tint=\"?attr/colorControlNormal\"\n    android:viewportHeight=\"24\"\n    android:viewportWidth=\"24\"\n    android:width=\"24dp\">\n\n    <path\n        android:fillColor=\"#FFFFFF\"\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\n</vector>\n"
  },
  {
    "path": "vending-app/src/main/res/drawable/ic_download.xml",
    "content": "<!--\n  ~ SPDX-FileCopyrightText: Android Open Source Project\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\" android:height=\"24dp\" android:tint=\"#000000\" android:viewportHeight=\"24\" android:viewportWidth=\"24\" android:width=\"24dp\">\n      \n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M5,20h14v-2H5V20zM19,9h-4V3H9v6H5l7,7L19,9z\"/>\n    \n</vector>\n"
  },
  {
    "path": "vending-app/src/main/res/drawable/ic_notification.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: CC-BY-SA-4.0\n  -->\n\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"225.27\"\n    android:viewportHeight=\"225.27\">\n    <group\n        android:scaleX=\"1\"\n        android:scaleY=\"1\"\n        android:translateX=\"0\"\n        android:translateY=\"0\">\n        <path\n            android:pathData=\"m151.55,151.53a55,55 0,0 1,-66.39 8.74\"\n            android:strokeWidth=\"30\"\n            android:fillColor=\"#00000000\"\n            android:strokeColor=\"#e91e63\"\n            android:strokeLineCap=\"butt\" />\n        <path\n            android:pathData=\"M85.16,160.27A55,55 0,0 1,59.53 98.4\"\n            android:strokeWidth=\"30\"\n            android:fillColor=\"#00000000\"\n            android:strokeColor=\"#ff9800\"\n            android:strokeLineCap=\"butt\" />\n        <path\n            android:pathData=\"m59.53,98.4a55,55 0,0 1,25.63 -33.4\"\n            android:strokeWidth=\"30\"\n            android:fillColor=\"#00000000\"\n            android:strokeColor=\"#cddc39\"\n            android:strokeLineCap=\"butt\" />\n        <path\n            android:pathData=\"m85.16,65.01a55,55 0,0 1,66.39 8.74\"\n            android:strokeWidth=\"30\"\n            android:fillColor=\"#00000000\"\n            android:strokeColor=\"#009688\"\n            android:strokeLineCap=\"butt\" />\n    </group>\n</vector>\n"
  },
  {
    "path": "vending-app/src/main/res/drawable/ic_update.xml",
    "content": "<!--\n  ~ SPDX-FileCopyrightText: Android Open Source Project\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:tint=\"#000000\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M21,10.12h-6.78l2.74,-2.82c-2.73,-2.7 -7.15,-2.8 -9.88,-0.1c-2.73,2.71 -2.73,7.08 0,9.79s7.15,2.71 9.88,0C18.32,15.65 19,14.08 19,12.1h2c0,1.98 -0.88,4.55 -2.64,6.29c-3.51,3.48 -9.21,3.48 -12.72,0c-3.5,-3.47 -3.53,-9.11 -0.02,-12.58s9.14,-3.47 12.65,0L21,3V10.12zM12.5,8v4.25l3.5,2.08l-0.72,1.21L11,13V8H12.5z\" />\n\n</vector>\n"
  },
  {
    "path": "vending-app/src/main/res/drawable/ic_work.xml",
    "content": "<!--\n  ~ SPDX-FileCopyrightText: Android Open Source Project\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\" android:height=\"24dp\" android:tint=\"#4285F4\" android:viewportHeight=\"24\" android:viewportWidth=\"24\" android:width=\"24dp\">\n      \n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M20,6h-4L16,4c0,-1.11 -0.89,-2 -2,-2h-4c-1.11,0 -2,0.89 -2,2v2L4,6c-1.11,0 -1.99,0.89 -1.99,2L2,19c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2L22,8c0,-1.11 -0.89,-2 -2,-2zM14,6h-4L10,4h4v2z\"/>\n    \n</vector>\n"
  },
  {
    "path": "vending-app/src/main/res/drawable-v21/anim_check_mark.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<animated-vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\">\n    <aapt:attr name=\"android:drawable\">\n        <vector\n            android:name=\"vector\"\n            android:width=\"48.0dp\"\n            android:height=\"48.0dp\"\n            android:viewportWidth=\"48.0\"\n            android:viewportHeight=\"48.0\">\n            <group android:name=\"group\">\n                <path\n                    android:name=\"circle\"\n                    android:fillColor=\"@color/colorBackground\"\n                    android:pathData=\"M 24 0 C 17.637 0 11.529 2.53 7.029 7.029 C 2.53 11.529 0 17.637 0 24 C 0 30.363 2.53 36.471 7.029 40.971 C 11.529 45.47 17.637 48 24 48 C 30.363 48 36.471 45.47 40.971 40.971 C 45.47 36.471 48 30.363 48 24 C 48 17.637 45.47 11.529 40.971 7.029 C 36.471 2.53 30.363 0 24 0 Z\"\n                    android:strokeWidth=\"1.0\" />\n                <path\n                    android:name=\"markend_1\"\n                    android:fillColor=\"@color/colorForeground\"\n                    android:pathData=\"M 33.3 19.6 L 22 30.9 C 21.5 31.4 20.8 31.4 20.3 30.9 L 19.4 30 C 18.9 29.5 18.9 28.8 19.4 28.3 L 30.7 17 C 31.2 16.5 31.9 16.5 32.4 17 L 33.3 17.9 C 33.8 18.4 33.8 19.1 33.3 19.6 Z\"\n                    android:strokeWidth=\"1.0\" />\n                <path\n                    android:name=\"markstart_1\"\n                    android:fillColor=\"@color/colorForeground\"\n                    android:pathData=\"M 20.3 30.9 L 14.9 25.5 C 14.4 25 14.4 24.3 14.9 23.8 L 15.8 22.9 C 16.3 22.4 17 22.4 17.5 22.9 L 22.9 28.3 C 23.4 28.8 23.4 29.5 22.9 30 L 22 30.9 C 21.6 31.4 20.8 31.4 20.3 30.9 Z\"\n                    android:strokeWidth=\"1.0\" />\n            </group>\n        </vector>\n    </aapt:attr>\n\n    <target android:name=\"group\">\n        <aapt:attr name=\"android:animation\">\n            <set>\n                <objectAnimator\n                    android:duration=\"151\"\n                    android:interpolator=\"@android:interpolator/fast_out_slow_in\"\n                    android:propertyName=\"scaleX\"\n                    android:valueFrom=\"0.5\"\n                    android:valueTo=\"1\"\n                    android:valueType=\"floatType\" />\n                <objectAnimator\n                    android:duration=\"151\"\n                    android:interpolator=\"@android:interpolator/fast_out_slow_in\"\n                    android:propertyName=\"scaleY\"\n                    android:valueFrom=\"0.5\"\n                    android:valueTo=\"1\"\n                    android:valueType=\"floatType\" />\n                <objectAnimator\n                    android:duration=\"151\"\n                    android:interpolator=\"@android:interpolator/fast_out_slow_in\"\n                    android:propertyName=\"translateX\"\n                    android:valueFrom=\"12\"\n                    android:valueTo=\"0\"\n                    android:valueType=\"floatType\" />\n                <objectAnimator\n                    android:duration=\"151\"\n                    android:interpolator=\"@android:interpolator/fast_out_slow_in\"\n                    android:propertyName=\"translateY\"\n                    android:valueFrom=\"12\"\n                    android:valueTo=\"0\"\n                    android:valueType=\"floatType\" />\n                <objectAnimator\n                    android:duration=\"449\"\n                    android:interpolator=\"@android:interpolator/fast_out_slow_in\"\n                    android:propertyName=\"scaleX\"\n                    android:startOffset=\"151\"\n                    android:valueFrom=\"1\"\n                    android:valueTo=\"1\"\n                    android:valueType=\"floatType\" />\n                <objectAnimator\n                    android:duration=\"449\"\n                    android:interpolator=\"@android:interpolator/fast_out_slow_in\"\n                    android:propertyName=\"scaleY\"\n                    android:startOffset=\"151\"\n                    android:valueFrom=\"1\"\n                    android:valueTo=\"1\"\n                    android:valueType=\"floatType\" />\n                <objectAnimator\n                    android:duration=\"449\"\n                    android:interpolator=\"@android:interpolator/fast_out_slow_in\"\n                    android:propertyName=\"translateX\"\n                    android:startOffset=\"151\"\n                    android:valueFrom=\"0\"\n                    android:valueTo=\"0\"\n                    android:valueType=\"floatType\" />\n                <objectAnimator\n                    android:duration=\"449\"\n                    android:interpolator=\"@android:interpolator/fast_out_slow_in\"\n                    android:propertyName=\"translateY\"\n                    android:startOffset=\"151\"\n                    android:valueFrom=\"0\"\n                    android:valueTo=\"0\"\n                    android:valueType=\"floatType\" />\n            </set>\n        </aapt:attr>\n    </target>\n    <target android:name=\"markstart_1\">\n        <aapt:attr name=\"android:animation\">\n            <set>\n                <objectAnimator\n                    android:duration=\"100\"\n                    android:interpolator=\"@android:interpolator/fast_out_slow_in\"\n                    android:propertyName=\"pathData\"\n                    android:valueFrom=\"M 15.2 25.8 L 14.9 25.5 C 14.4 25 14.4 24.3 14.9 23.8 L 15.8 22.9 C 16.3 22.4 17 22.4 17.5 22.9 L 17.8 23.2 C 18.3 23.7 18.3 24.4 17.8 24.9 L 16.9 25.8 C 16.4 26.2 15.7 26.2 15.2 25.8 Z\"\n                    android:valueTo=\"M 20.3 30.9 L 14.9 25.5 C 14.4 25 14.4 24.3 14.9 23.8 L 15.8 22.9 C 16.3 22.4 17 22.4 17.5 22.9 L 22.9 28.3 C 23.4 28.8 23.4 29.5 22.9 30 L 22 30.9 C 21.6 31.4 20.8 31.4 20.3 30.9 Z\"\n                    android:valueType=\"pathType\" />\n                <objectAnimator\n                    android:duration=\"500\"\n                    android:interpolator=\"@android:interpolator/fast_out_slow_in\"\n                    android:propertyName=\"pathData\"\n                    android:startOffset=\"100\"\n                    android:valueFrom=\"M 20.3 30.9 L 14.9 25.5 C 14.4 25 14.4 24.3 14.9 23.8 L 15.8 22.9 C 16.3 22.4 17 22.4 17.5 22.9 L 22.9 28.3 C 23.4 28.8 23.4 29.5 22.9 30 L 22 30.9 C 21.6 31.4 20.8 31.4 20.3 30.9 Z\"\n                    android:valueTo=\"M 20.3 30.9 L 14.9 25.5 C 14.4 25 14.4 24.3 14.9 23.8 L 15.8 22.9 C 16.3 22.4 17 22.4 17.5 22.9 L 22.9 28.3 C 23.4 28.8 23.4 29.5 22.9 30 L 22 30.9 C 21.6 31.4 20.8 31.4 20.3 30.9 Z\"\n                    android:valueType=\"pathType\" />\n            </set>\n        </aapt:attr>\n    </target>\n    <target android:name=\"markend_1\">\n        <aapt:attr name=\"android:animation\">\n            <set>\n                <objectAnimator\n                    android:duration=\"100\"\n                    android:interpolator=\"@android:interpolator/fast_out_slow_in\"\n                    android:propertyName=\"fillAlpha\"\n                    android:valueFrom=\"0\"\n                    android:valueTo=\"0\"\n                    android:valueType=\"floatType\" />\n                <objectAnimator\n                    android:duration=\"1\"\n                    android:interpolator=\"@android:interpolator/fast_out_slow_in\"\n                    android:propertyName=\"fillAlpha\"\n                    android:startOffset=\"100\"\n                    android:valueFrom=\"0\"\n                    android:valueTo=\"1\"\n                    android:valueType=\"floatType\" />\n                <objectAnimator\n                    android:duration=\"499\"\n                    android:interpolator=\"@android:interpolator/fast_out_slow_in\"\n                    android:propertyName=\"fillAlpha\"\n                    android:startOffset=\"101\"\n                    android:valueFrom=\"1\"\n                    android:valueTo=\"1\"\n                    android:valueType=\"floatType\" />\n                <objectAnimator\n                    android:duration=\"100\"\n                    android:interpolator=\"@android:interpolator/fast_out_slow_in\"\n                    android:propertyName=\"pathData\"\n                    android:valueFrom=\"M 22.6 30.4 L 22 30.9 C 21.5 31.4 20.8 31.4 20.3 30.9 L 19.4 30 C 18.9 29.5 18.9 28.8 19.4 28.3 L 20 27.8 C 20.5 27.3 21.2 27.3 21.7 27.8 L 22.6 28.7 C 23.1 29.2 23.1 29.9 22.6 30.4 Z\"\n                    android:valueTo=\"M 22.6 30.4 L 22 30.9 C 21.5 31.4 20.8 31.4 20.3 30.9 L 19.4 30 C 18.9 29.5 18.9 28.8 19.4 28.3 L 20 27.8 C 20.5 27.3 21.2 27.3 21.7 27.8 L 22.6 28.7 C 23.1 29.2 23.1 29.9 22.6 30.4 Z\"\n                    android:valueType=\"pathType\" />\n                <objectAnimator\n                    android:duration=\"130\"\n                    android:interpolator=\"@android:interpolator/fast_out_slow_in\"\n                    android:propertyName=\"pathData\"\n                    android:startOffset=\"100\"\n                    android:valueFrom=\"M 22.6 30.4 L 22 30.9 C 21.5 31.4 20.8 31.4 20.3 30.9 L 19.4 30 C 18.9 29.5 18.9 28.8 19.4 28.3 L 20 27.8 C 20.5 27.3 21.2 27.3 21.7 27.8 L 22.6 28.7 C 23.1 29.2 23.1 29.9 22.6 30.4 Z\"\n                    android:valueTo=\"M 34.1 18.7 L 22 30.9 C 21.5 31.4 20.8 31.4 20.3 30.9 L 19.4 30 C 18.9 29.5 18.9 28.8 19.4 28.3 L 31.5 16.1 C 32 15.6 32.7 15.6 33.2 16.1 L 34.1 17 C 34.6 17.5 34.6 18.2 34.1 18.7 Z\"\n                    android:valueType=\"pathType\" />\n                <objectAnimator\n                    android:duration=\"200\"\n                    android:interpolator=\"@android:interpolator/fast_out_slow_in\"\n                    android:propertyName=\"pathData\"\n                    android:startOffset=\"230\"\n                    android:valueFrom=\"M 34.1 18.7 L 22 30.9 C 21.5 31.4 20.8 31.4 20.3 30.9 L 19.4 30 C 18.9 29.5 18.9 28.8 19.4 28.3 L 31.5 16.1 C 32 15.6 32.7 15.6 33.2 16.1 L 34.1 17 C 34.6 17.5 34.6 18.2 34.1 18.7 Z\"\n                    android:valueTo=\"M 33.1 19.7 L 22 30.9 C 21.5 31.4 20.8 31.4 20.3 30.9 L 19.4 30 C 18.9 29.5 18.9 28.8 19.4 28.3 L 30.5 17.1 C 31 16.6 31.7 16.6 32.2 17.1 L 33.1 18 C 33.6 18.5 33.6 19.2 33.1 19.7 Z\"\n                    android:valueType=\"pathType\" />\n                <objectAnimator\n                    android:duration=\"170\"\n                    android:interpolator=\"@android:interpolator/fast_out_slow_in\"\n                    android:propertyName=\"pathData\"\n                    android:startOffset=\"430\"\n                    android:valueFrom=\"M 33.1 19.7 L 22 30.9 C 21.5 31.4 20.8 31.4 20.3 30.9 L 19.4 30 C 18.9 29.5 18.9 28.8 19.4 28.3 L 30.5 17.1 C 31 16.6 31.7 16.6 32.2 17.1 L 33.1 18 C 33.6 18.5 33.6 19.2 33.1 19.7 Z\"\n                    android:valueTo=\"M 33.3 19.6 L 22 30.9 C 21.5 31.4 20.8 31.4 20.3 30.9 L 19.4 30 C 18.9 29.5 18.9 28.8 19.4 28.3 L 30.7 17 C 31.2 16.5 31.9 16.5 32.4 17 L 33.3 17.9 C 33.8 18.4 33.8 19.1 33.3 19.6 Z\"\n                    android:valueType=\"pathType\" />\n            </set>\n        </aapt:attr>\n    </target>\n</animated-vector>"
  },
  {
    "path": "vending-app/src/main/res/drawable-v21/google_play.xml",
    "content": "<!--\n  ~ SPDX-FileCopyrightText: 2024 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"79dp\"\n    android:height=\"16dp\"\n    android:viewportWidth=\"79\"\n    android:viewportHeight=\"16\">\n  <path\n      android:fillColor=\"#ff000000\"\n      android:pathData=\"M25.2,4.5c-2.2,0 -4,1.6 -4,4a4,4 0,0 0,4 4,4 4,0 0,0 4,-4c0,-2.4 -1.8,-4 -4,-4zM25.2,10.9c-1.2,0 -2.2,-1 -2.2,-2.4S24,6 25.2,6c1.2,0 2.2,1 2.2,2.5 0,1.4 -1,2.4 -2.2,2.4zM36,5.4a2.8,2.8 0,0 0,-2.1 -1,4 4,0 0,0 0,8c1,0 1.7,-0.4 2,-0.9v0.6c0,1.5 -0.7,2.3 -2,2.3 -1,0 -1.7,-0.8 -2,-1.4l-1.5,0.6c0.4,1 1.6,2.4 3.5,2.4 2,0 3.7,-1.2 3.7,-4.1L37.6,4.7L36,4.7v0.7zM34,10.9c-1.2,0 -2.2,-1 -2.2,-2.4s1,-2.4 2.2,-2.4c1.2,0 2,1 2,2.4 0.1,1.4 -0.8,2.4 -2,2.4zM16.6,4.5c-2.2,0 -4,1.6 -4,4a4,4 0,0 0,4 4,4 4,0 0,0 4,-4 4,4 0,0 0,-4 -4zM16.6,10.9c-1.2,0 -2.2,-1 -2.2,-2.4s1,-2.5 2.2,-2.5 2.2,1 2.2,2.5c0,1.4 -1,2.4 -2.2,2.4zM6.2,5.7v1.6h4a3,3 0,0 1,-0.9 2.2,4 4,0 0,1 -3,1.2c-2.5,0 -4.5,-2 -4.5,-4.5s2,-4.5 4.4,-4.5a4,4 0,0 1,3 1.2l1.3,-1.2A6,6 0,0 0,6.2 0C3,0 0,2.8 0,6.1s2.9,6.2 6.2,6.2c1.8,0 3.2,-0.6 4.3,-1.7a5.6,5.6 0,0 0,1.5 -4l-0.1,-1L6.2,5.6zM48.4,7c-0.3,-1 -1.3,-2.5 -3.3,-2.5 -2,0 -3.7,1.6 -3.7,4 0,2.2 1.6,4 3.9,4a4,4 0,0 0,3.3 -1.8l-1.4,-1c-0.4,0.7 -1,1.2 -2,1.2 -0.8,0 -1.4,-0.4 -1.8,-1.2l5.2,-2.3 -0.2,-0.4zM43.1,8.4C43,6.8 44.3,6 45,6s1.3,0.4 1.5,0.9L43,8.4zM38.7,12.2h1.8L40.5,0.5h-1.8v11.7zM56.6,0.5h-4.2v11.7h1.8L54.2,7.7h2.4c1.9,0 3.8,-1.4 3.8,-3.6S58.5,0.5 56.6,0.5zM56.6,6.1h-2.4v-4h2.4a2,2 0,0 1,2.1 2c0,1 -0.8,2 -2,2zM61.4,12.1L63,12.1L63,0.6h-1.7v11.7zM67.4,4.5c-1.3,0 -2.6,0.5 -3.1,1.7l1.5,0.7c0.4,-0.7 1,-0.9 1.6,-0.9 1,0 1.9,0.6 1.9,1.5v0.1c-0.4,-0.2 -1,-0.4 -1.9,-0.4 -1.6,0 -3.3,0.9 -3.3,2.6 0,1.6 1.3,2.6 2.9,2.6 1.1,0 1.8,-0.5 2.2,-1.2v1L71,12.2L71,7.5c0,-2 -1.5,-3.1 -3.5,-3.1zM67.2,10.9c-0.6,0 -1.4,-0.3 -1.4,-1 0,-1 1,-1.3 1.9,-1.3a3,3 0,0 1,1.6 0.4c-0.2,1 -1.1,1.9 -2.1,1.9zM77,4.7l-2,5 -2,-5h-2l3.2,7 -1.8,4h1.8l4.8,-11h-2z\"\n      android:strokeAlpha=\"0.5\"\n      android:fillAlpha=\"0.5\"/>\n</vector>\n"
  },
  {
    "path": "vending-app/src/main/res/drawable-v26/ic_app_foreground.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: CC-BY-SA-4.0\n  -->\n\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"225.27\"\n    android:viewportHeight=\"225.27\">\n    <group\n        android:scaleX=\"0.50\"\n        android:scaleY=\"0.50\"\n        android:translateX=\"56.3175\"\n        android:translateY=\"56.3175\">\n        <path\n            android:pathData=\"M112.64,112.64m-105.55,0a105.55,105.55 0,1 1,211.1 0a105.55,105.55 0,1 1,-211.1 0\"\n            android:strokeWidth=\"30.57332802\"\n            android:fillColor=\"#ffffff\"\n            android:strokeColor=\"#00000000\"\n            android:strokeLineCap=\"butt\" />\n        <path\n            android:pathData=\"m151.55,151.53a55,55 0,0 1,-66.39 8.74\"\n            android:strokeWidth=\"30\"\n            android:fillColor=\"#00000000\"\n            android:strokeColor=\"#e91e63\"\n            android:strokeLineCap=\"butt\" />\n        <path\n            android:pathData=\"M85.16,160.27A55,55 0,0 1,59.53 98.4\"\n            android:strokeWidth=\"30\"\n            android:fillColor=\"#00000000\"\n            android:strokeColor=\"#ff9800\"\n            android:strokeLineCap=\"butt\" />\n        <path\n            android:pathData=\"m59.53,98.4a55,55 0,0 1,25.63 -33.4\"\n            android:strokeWidth=\"30\"\n            android:fillColor=\"#00000000\"\n            android:strokeColor=\"#cddc39\"\n            android:strokeLineCap=\"butt\" />\n        <path\n            android:pathData=\"m85.16,65.01a55,55 0,0 1,66.39 8.74\"\n            android:strokeWidth=\"30\"\n            android:fillColor=\"#00000000\"\n            android:strokeColor=\"#009688\"\n            android:strokeLineCap=\"butt\" />\n    </group>\n</vector>\n"
  },
  {
    "path": "vending-app/src/main/res/drawable-v26/ic_app_foreground_mono.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: CC-BY-SA-4.0\n  -->\n\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"225.27\"\n    android:viewportHeight=\"225.27\">\n    <group\n        android:scaleX=\"0.50\"\n        android:scaleY=\"0.50\"\n        android:translateX=\"56.3175\"\n        android:translateY=\"56.3175\">\n        <path\n            android:pathData=\"M112.64,112.64m-105.55,0a105.55,105.55 0,1 1,211.1 0a105.55,105.55 0,1 1,-211.1 0\"\n            android:strokeWidth=\"30.57332802\"\n            android:fillColor=\"#000000\"\n            android:strokeColor=\"#00000000\"\n            android:fillAlpha=\"0.1\"\n            android:strokeLineCap=\"butt\" />\n        <path\n            android:pathData=\"m151.55,151.53a55,55 0,0 1,-66.39 8.74\"\n            android:strokeAlpha=\"0.8\"\n            android:strokeWidth=\"30\"\n            android:fillColor=\"#00000000\"\n            android:strokeColor=\"#000000\"\n            android:fillAlpha=\"0.8\"\n            android:strokeLineCap=\"butt\" />\n        <path\n            android:pathData=\"M85.16,160.27A55,55 0,0 1,59.53 98.4\"\n            android:strokeAlpha=\"0.6\"\n            android:strokeWidth=\"30\"\n            android:fillColor=\"#00000000\"\n            android:strokeColor=\"#000000\"\n            android:fillAlpha=\"0.6\"\n            android:strokeLineCap=\"butt\" />\n        <path\n            android:pathData=\"m59.53,98.4a55,55 0,0 1,25.63 -33.4\"\n            android:strokeAlpha=\"0.5\"\n            android:strokeWidth=\"30\"\n            android:fillColor=\"#00000000\"\n            android:strokeColor=\"#000000\"\n            android:fillAlpha=\"0.5\"\n            android:strokeLineCap=\"butt\" />\n        <path\n            android:pathData=\"m85.16,65.01a55,55 0,0 1,66.39 8.74\"\n            android:strokeAlpha=\"0.7\"\n            android:strokeWidth=\"30\"\n            android:fillColor=\"#00000000\"\n            android:strokeColor=\"#000000\"\n            android:fillAlpha=\"0.7\"\n            android:strokeLineCap=\"butt\" />\n    </group>\n</vector>\n"
  },
  {
    "path": "vending-app/src/main/res/layout/activity_install_reminder.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout 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\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"horizontal\"\n        android:gravity=\"center_vertical\"\n        android:layout_margin=\"24dp\">\n\n        <TextView\n            android:id=\"@+id/tv_title\"\n            android:layout_width=\"0dp\"\n            android:layout_weight=\"1\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginEnd=\"8dp\"\n            android:text=\"@string/app_install_needs_permissions_title\"\n            android:textSize=\"20sp\"\n            android:textStyle=\"bold\" />\n\n        <ImageView\n            android:id=\"@+id/btn_close\"\n            android:layout_width=\"32dp\"\n            android:layout_height=\"32dp\"\n            android:src=\"@drawable/ic_cancel\"/>\n\n    </LinearLayout>\n\n    <TextView\n        android:id=\"@+id/tv_description\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/app_install_allow_to_install_third_app\"\n        android:textSize=\"16sp\"\n        android:textStyle=\"bold\"\n        android:layout_marginHorizontal=\"24dp\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        android:gravity=\"center\"\n        android:layout_margin=\"24dp\">\n\n        <ImageView\n            android:id=\"@+id/iv_app_icon\"\n            android:layout_width=\"80dp\"\n            android:layout_height=\"80dp\"\n            android:src=\"@android:drawable/sym_def_app_icon\" />\n\n        <TextView\n            android:id=\"@+id/tv_app_name\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:textSize=\"16sp\"\n            android:layout_marginTop=\"8dp\"\n            android:textStyle=\"bold\" />\n\n    </LinearLayout>\n\n    <TextView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/app_install_refuse_permission_remind\"\n        android:textSize=\"16sp\"\n        android:textStyle=\"bold\"\n        android:layout_marginHorizontal=\"24dp\"\n        android:layout_marginBottom=\"6dp\"/>\n\n    <TextView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/app_install_refuse_permission_remind_sub\"\n        android:textSize=\"14sp\"\n        android:layout_marginHorizontal=\"24dp\"\n        android:layout_marginBottom=\"24dp\" />\n\n    <CheckBox\n        android:id=\"@+id/cb_dont_show_again\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/app_install_not_remind_again\"\n        android:textSize=\"14sp\"\n        android:layout_marginHorizontal=\"24dp\"\n        android:layout_marginBottom=\"24dp\" />\n\n    <Button\n        android:id=\"@+id/btn_allow\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"48dp\"\n        android:layout_marginHorizontal=\"24dp\"\n        android:text=\"@string/app_install_permission_allowed\"\n        android:textSize=\"14sp\" />\n\n</LinearLayout> "
  },
  {
    "path": "vending-app/src/main/res/layout/activiy_confirm_purchase.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:gravity=\"center\"\n    android:layout_height=\"match_parent\">\n\n    <Button\n        android:id=\"@+id/purchaseButton\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/confirm_purchase\" />\n\n</LinearLayout>"
  },
  {
    "path": "vending-app/src/main/res/mipmap-anydpi-v26/ic_app.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: CC-BY-SA-4.0\n  -->\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@color/ic_app_background\"/>\n    <foreground android:drawable=\"@drawable/ic_app_foreground\"/>\n\n    <monochrome android:drawable=\"@drawable/ic_app_foreground_mono\" />\n</adaptive-icon>"
  },
  {
    "path": "vending-app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorBackground\">#01875f</color>\n    <color name=\"colorForeground\">@android:color/white</color>\n</resources>"
  },
  {
    "path": "vending-app/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2014 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<resources>\n    <string name=\"app_name\">microG Companion</string>\n    <string name=\"toast_installed\">microG Companion cannot be used standalone. Opened microG Services settings instead.</string>\n    <string name=\"toast_not_installed\">microG Companion cannot be used standalone. Please install microG Services to use microG.</string>\n\n    <string name=\"license_notification_channel_name\">License notifications</string>\n    <string name=\"license_notification_channel_description\">Notifies when an app tries to validate its license, but you are not signed in to any Google account.</string>\n    <string name=\"license_notification_title\">%1$s could not verify license</string>\n    <string name=\"license_notification_body\">If the app is misbehaving, sign in to a Google account with which you have bought the app.</string>\n\n    <string name=\"license_notification_sign_in\">Sign In</string>\n    <string name=\"license_notification_ignore\">Ignore</string>\n\n    <string name=\"vending_activity_name\">Work app store</string>\n    <string name=\"vending_overview_enterprise_row_mandatory\">Installation required</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_hint\">Your administrator requires these apps to be installed in your managed profile.</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_missing_hint\">Your device is missing mandatory apps chosen by your administrator.</string>\n    <string name=\"vending_overview_enterprise_row_offered\">Available apps</string>\n    <string name=\"vending_overview_enterprise_row_offered_hint\">These are all the apps made available by your enterprise.</string>\n    <string name=\"vending_overview_enterprise_no_apps_available\">No apps have been made available by your administrator.</string>\n    <string name=\"vending_overview_enterprise_no_apps_available_wait\">It may take a few hours after setting up your work profile before apps are ready to download.</string>\n    <string name=\"vending_overview_row_update_available\">Update available</string>\n    <string name=\"vending_overview_row_installed\">Installed apps</string>\n    <string name=\"vending_overview_row_action_install\">Install</string>\n    <string name=\"vending_overview_row_action_update\">Update</string>\n    <string name=\"vending_overview_row_action_uninstall\">Uninstall</string>\n\n    <string name=\"pay_disabled\">Pay currently not possible</string>\n\n    <string name=\"confirm_purchase\">Confirm Purchase</string>\n    <string name=\"error_network\">Not connected to the internet. Please make sure Wi-Fi or mobile network is turned on and try again.</string>\n    <string name=\"error_passwd\">The password you entered is incorrect.</string>\n    <string name=\"error_unknown\">Unknown error, please exit and try again.</string>\n    <string name=\"error_retry\">Retry</string>\n    <string name=\"tips_input_passwd\">Enter your password</string>\n    <string name=\"tips_remember_login_info\">Remember my login on this device</string>\n    <string name=\"tips_forget_passwd\">Forget password?</string>\n    <string name=\"tips_more_details\">Learn more</string>\n    <string name=\"text_verify_button\">Verify</string>\n\n    <string name=\"installer_notification_channel_name\">App and component installation</string>\n    <string name=\"installer_notification_channel_description\">Shows app and component installation progress, success and failure messages.</string>\n    <string name=\"installer_notification_progress_downloading\">Downloading \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_commiting\">Installing \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_complete\">Installed \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_failed\">Failed to install \\\"%s\\\"</string>\n\n    <string name=\"installer_dependency_noun\">Required components for %s</string>\n    <string name=\"installer_notification_progress_splitinstall_downloading\">Downloading required components for %s</string>\n    <string name=\"installer_notification_progress_splitinstall_commiting\">Installing required components for %s</string>\n    <string name=\"download_notification_attachment_file\">Additional files for %s</string>\n    <string name=\"download_notification_tips\">Downloading</string>\n    <string name=\"installer_notification_progress_splitinstall_click_install\">Click to install the components required by %s</string>\n    <string name=\"billing_permission_desc\">Allows the user to purchase items through Google Play from within this app.</string>\n    <string name=\"billing_permission_label\">Google Play billing service</string>\n\n    <string name=\"app_install_permission_allowed\">Allow</string>\n    <string name=\"app_install_needs_permissions_title\">App Installer</string>\n    <string name=\"app_install_allow_to_install_third_app\">Allow \\\"microG Companion\\\" to install apps downloaded from \\\"%1$s\\\"</string>\n    <string name=\"app_install_refuse_permission_remind\">If you decline, the application installation will fail.</string>\n    <string name=\"app_install_refuse_permission_remind_sub\">You can modify the authorization status permissions at any time in microG Service Settings.</string>\n    <string name=\"app_install_not_remind_again\">Keep this selection and don\\'t ask again</string>\n\n</resources>\n"
  },
  {
    "path": "vending-app/src/main/res/values/styles.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2014 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<resources>\n    <style name=\"Theme.Dialog.NoActionBar\" parent=\"@android:style/Theme.Dialog\">\n        <item name=\"android:windowNoTitle\">true</item>\n        <item name=\"android:windowBackground\">@android:color/transparent</item>\n    </style>\n\n    <!-- Base application theme. -->\n    <style name=\"MyDialogStyle\" parent=\"android:Theme.Dialog\">\n        <item name=\"android:windowFrame\">@null</item>\n        <item name=\"android:windowIsFloating\">false</item>\n        <item name=\"android:windowIsTranslucent\">true</item>\n        <item name=\"android:windowNoTitle\">true</item>\n        <item name=\"android:windowBackground\">@android:color/transparent</item>\n        <item name=\"android:backgroundDimEnabled\">true</item>\n        <item name=\"android:windowTranslucentNavigation\">true</item>\n    </style>\n\n    <style name=\"InAppBillingStyle\">\n        <item name=\"android:windowBackground\">@android:color/transparent</item>\n        <item name=\"android:windowIsFloating\">false</item>\n        <item name=\"android:windowIsTranslucent\">true</item>\n        <item name=\"android:windowContentOverlay\">@null</item>\n        <item name=\"android:windowAnimationStyle\">@null</item>\n        <item name=\"android:backgroundDimEnabled\">true</item>\n        <item name=\"android:colorBackgroundCacheHint\">@null</item>\n    </style>\n</resources>\n"
  },
  {
    "path": "vending-app/src/main/res/values-ar/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\">مرافق مايكرو-جي</string>\n    <string name=\"toast_not_installed\">لا يمكن استخدام مرافق مايكرو-جي بشكل مستقل. يرجى تثبيت خدمات مايكرو-جي لاستخدام مايكرو-جي.</string>\n    <string name=\"toast_installed\">لا يمكن استخدام مرافق مايكرو-جي بشكل مستقل. تم فتح إعدادات خدمات مايكرو-جي بدلًا من ذلك.</string>\n    <string name=\"license_notification_channel_name\">إشعارات التراخيص</string>\n    <string name=\"license_notification_title\">تعذر على %1$s التحقق من الترخيص</string>\n    <string name=\"license_notification_body\">إن قام التطبيق بتصرفات غير متوقعة، فسجل الدخول إلى حساب جوجل الذي اشتريت التطبيق بواسطته.</string>\n    <string name=\"license_notification_sign_in\">سَجِّل الدخول</string>\n    <string name=\"license_notification_ignore\">تجاهل</string>\n    <string name=\"pay_disabled\">الدفع غير متاح حاليًا</string>\n    <string name=\"confirm_purchase\">تأكيد عملية الشراء</string>\n    <string name=\"error_network\">أنت غير متصلٍ بالإنترنت. يرجى التأكد من تشغيل شبكة الـ Wi-Fi أو شبكة الجوال أَعِد المحاولة.</string>\n    <string name=\"error_passwd\">كلمة المرور غير صحيحة.</string>\n    <string name=\"error_unknown\">حدث خطأ مجهول، يرجى الخروج والمحاولة مرة أخرى.</string>\n    <string name=\"tips_input_passwd\">أدخل كلمة المرور</string>\n    <string name=\"tips_remember_login_info\">تذكر تسجيل دخولي على هذا الجهاز</string>\n    <string name=\"tips_forget_passwd\">هل نسيت كلمة المرور؟</string>\n    <string name=\"tips_more_details\">معرفة المزيد</string>\n    <string name=\"text_verify_button\">تحقق</string>\n    <string name=\"license_notification_channel_description\">يتم إشعارك عندما يحاول تطبيق من التحقق من صحة ترخيصه، ولكنك لم تقم بتسجيل الدخول إلى أي حساب جوجل.</string>\n    <string name=\"vending_overview_enterprise_row_offered\">التطبيقات المتاحة</string>\n    <string name=\"vending_overview_enterprise_row_offered_hint\">هذه هي جميع التطبيقات التي توفرها مؤسستك.</string>\n    <string name=\"vending_overview_enterprise_no_apps_available\">لم يتم توفير أي تطبيقات من قبل المشرف.</string>\n    <string name=\"vending_overview_row_update_available\">التحديث متاح</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_missing_hint\">يفتقر جهازك إلى التطبيقات الإلزامية التي اختارها المشرف.</string>\n    <string name=\"vending_activity_name\">متجر تطبيقات العمل</string>\n    <string name=\"vending_overview_enterprise_no_apps_available_wait\">قد يستغرق الأمر بضع ساعات بعد إعداد الملف الشخصي للعمل قبل أن تصبح التطبيقات جاهزة للتنزيل.</string>\n    <string name=\"vending_overview_enterprise_row_mandatory\">التثبيت مطلوب</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_hint\">يطلب المشرف تثبيت هذه التطبيقات في ملفك الشخصي المدار.</string>\n    <string name=\"error_retry\">إعادة المحاولة</string>\n    <string name=\"installer_notification_progress_downloading\">يتم تنزيل \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_commiting\">يتم تثبيت \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_complete\">تم تثبيت \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_failed\">فشل تثبيت \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_splitinstall_downloading\">يتم تنزيل المكونات المطلوبة لـ%s</string>\n    <string name=\"installer_notification_progress_splitinstall_commiting\">يتم تثبيت المكونات المطلوبة لـ%s</string>\n    <string name=\"download_notification_tips\">يتم الآن التنزيل</string>\n    <string name=\"vending_overview_row_action_update\">تحديث</string>\n    <string name=\"installer_notification_channel_name\">تثبيت التطبيق والمكونات</string>\n    <string name=\"installer_dependency_noun\">المكونات المطلوبة لـ%s</string>\n    <string name=\"download_notification_attachment_file\">ملفات إضافية لـ%s</string>\n    <string name=\"installer_notification_channel_description\">يظهر تقدم تثبيت التطبيق والمكونات ورسائل النجاح والفشل.</string>\n    <string name=\"vending_overview_row_action_uninstall\">إلغاء التثبيت</string>\n    <string name=\"vending_overview_row_installed\">التطبيقات المثبتة</string>\n    <string name=\"vending_overview_row_action_install\">تثبيت</string>\n    <string name=\"installer_notification_progress_splitinstall_click_install\">انقر لتثبيت المكونات المطلوبة من %s</string>\n    <string name=\"billing_permission_desc\">يتيح للمستخدم بشراء عناصر من جوجل بلاي من داخل هذا التطبيق.</string>\n    <string name=\"billing_permission_label\">خدمة الفوترة في جوجل بلاي</string>\n    <string name=\"app_install_permission_allowed\">سماح</string>\n    <string name=\"app_install_needs_permissions_title\">مثبت التطبيق</string>\n    <string name=\"app_install_allow_to_install_third_app\">السماح لـ ”مرافق مايكرو-جي“ بتثبيت التطبيقات التي تم تنزيلها من ”%1$s“</string>\n    <string name=\"app_install_refuse_permission_remind\">إذا رفضت، فسيفشل تثبيت التطبيق.</string>\n    <string name=\"app_install_refuse_permission_remind_sub\">يمكنك تعديل أذونات حالة التفويض في أي وقت في إعدادات خدمة microG.</string>\n    <string name=\"app_install_not_remind_again\">حفظ هذا الاختيار وعدم السؤال مرة أخرى</string>\n</resources>\n"
  },
  {
    "path": "vending-app/src/main/res/values-ast/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\">microG Companion</string>\n    <string name=\"toast_installed\">microG Companion nun se pue usar de mou independiente. Abrióse la configuración de microG.</string>\n    <string name=\"toast_not_installed\">microG Companion nun se pue usar de mou independiente. Instala los servicios de microG pa poder usar microG.</string>\n    <string name=\"error_passwd\">La contraseña qu\\'introduxesti ye incorreuta.</string>\n    <string name=\"error_unknown\">Error desconocíu. Cola y volvi tentalo.</string>\n    <string name=\"tips_forget_passwd\">¿Escaeciesti la contraseña?</string>\n    <string name=\"tips_more_details\">Saber más</string>\n    <string name=\"text_verify_button\">Verificar</string>\n    <string name=\"license_notification_channel_name\">Avisos de llicencia</string>\n    <string name=\"license_notification_channel_description\">Esta opción unvia un avisu cuando una aplicación tenta de validar la so llicencia, mas nun aniciesti la sesión en nenguna cuenta de Google.</string>\n    <string name=\"license_notification_title\">«%1$s» nun pudo verificar la llicencia</string>\n    <string name=\"license_notification_ignore\">Inorar</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_hint\">L\\'alministrador rique qu\\'estes aplicaciones s\\'instalen nel perfil xestionáu.</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_missing_hint\">Al preséu fálten-y les aplicaciones obligatories qu\\'escoyó l\\'alministrador</string>\n    <string name=\"license_notification_sign_in\">Aniciar la sesión</string>\n</resources>\n"
  },
  {
    "path": "vending-app/src/main/res/values-az/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\">microG Companion</string>\n    <string name=\"toast_not_installed\">microG Companion müstəqil istifadə edilə bilməz. microG istifadə etmək üçün microG Xidmətlərin quraşdır.</string>\n    <string name=\"license_notification_channel_description\">Tətbiq lisenziyasını təsdiqləməyə çalışdıqda xəbərdar edir, lakin siz heç bir Google hesabına daxil olmamısınız.</string>\n    <string name=\"license_notification_sign_in\">Daxil ol</string>\n    <string name=\"pay_disabled\">Hazırda ödəniş mümkün deyil</string>\n    <string name=\"confirm_purchase\">Satınalmanı Təsdiqlə</string>\n    <string name=\"error_unknown\">Naməlum xəta, çıxın və yenidən cəhd edin.</string>\n    <string name=\"tips_input_passwd\">Parolunuzu daxil edin</string>\n    <string name=\"tips_remember_login_info\">Bu cihazdakı girişimi xatırla</string>\n    <string name=\"tips_forget_passwd\">Parolu unutmusunuz?</string>\n    <string name=\"tips_more_details\">Daha ətraflı</string>\n    <string name=\"text_verify_button\">Təsdiqlə</string>\n    <string name=\"toast_installed\">microG Companion müstəqil istifadə edilə bilməz. Əvəzinə microG Xidmətləri tənzimləmələri açıldı.</string>\n    <string name=\"license_notification_channel_name\">Lisenziya bildirişləri</string>\n    <string name=\"license_notification_title\">%1$s lisenziyanı təsdiqləyə bilmədi</string>\n    <string name=\"license_notification_body\">Tətbiq səhv işləyirsə, tətbiqi aldığınız Google hesabına daxil olun.</string>\n    <string name=\"license_notification_ignore\">Məhəl qoyma</string>\n    <string name=\"error_network\">İnternetə qoşulu deyil. Wi-Fi və ya mobil şəbəkənin aktiv olduğuna əmin olun və yenidən cəhd edin.</string>\n    <string name=\"error_passwd\">Daxil etdiyiniz parol səhvdir.</string>\n</resources>"
  },
  {
    "path": "vending-app/src/main/res/values-be/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_notification_title\">%1$s не можа праверыць ліцэнзію</string>\n    <string name=\"license_notification_body\">Калі прыкладанне працуе няправільна, увайдзіце ва ўліковы запіс Google, з дапамогай якой вы купілі дадатак.</string>\n    <string name=\"license_notification_sign_in\">Увайсці</string>\n    <string name=\"license_notification_ignore\">Ігнараваць</string>\n    <string name=\"license_notification_channel_name\">Паведамлення ліцэнзій</string>\n    <string name=\"license_notification_channel_description\">Паведамляе, калі прыкладанне спрабуе праверыць сваю ліцэнзію, але вы не ўвайшлі ні ў адзін уліковы запіс Google.</string>\n    <string name=\"app_name\">microG Companion</string>\n    <string name=\"toast_installed\">microG Companion не можа выкарыстоўвацца асобна. Адкрываюцца наладкі сэрвісаў microG.</string>\n    <string name=\"toast_not_installed\">microG Companion не можа выкарыстоўвацца асобна. Калі ласка, усталюйце сэрвісы microG каб выкарыстоўваць microG.</string>\n    <string name=\"pay_disabled\">Функцыя аплаты недаступная</string>\n    <string name=\"tips_input_passwd\">Увядзіце пароль</string>\n    <string name=\"tips_forget_passwd\">Забылі пароль?</string>\n    <string name=\"tips_more_details\">Больш падрабязна</string>\n    <string name=\"confirm_purchase\">Пацвярджэнне пакупкі</string>\n    <string name=\"error_network\">Адсутнічае падлучэнне да Інтэрнэту. Пераканайцеся, што Wi-Fi або перадача даных уключаны, і паспрабуйце яшчэ раз.</string>\n    <string name=\"error_passwd\">Уведзены вамі пароль няправільны.</string>\n    <string name=\"error_unknown\">Невядомая памылка. Выйдзіце і паўторыце спробу.</string>\n    <string name=\"tips_remember_login_info\">Запомніць аўтарызацыю на гэтай прыладзе</string>\n    <string name=\"text_verify_button\">Пацвердзіць</string>\n</resources>"
  },
  {
    "path": "vending-app/src/main/res/values-bn/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n</resources>"
  },
  {
    "path": "vending-app/src/main/res/values-ca/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\">Company del microG</string>\n    <string name=\"toast_installed\">El company del microG no es pot utilitzar de forma autònoma. S\\'ha obert la configuració dels serveis microG en el seu lloc.</string>\n    <string name=\"toast_not_installed\">El compamy del microG no funciona de forma autònoma. Per favor, instal·leu els serveis del microG per tal d\\'utilitzar microG.</string>\n    <string name=\"license_notification_channel_name\">Notificacions de llicència</string>\n    <string name=\"license_notification_channel_description\">Informa quan una aplicació intenta validar la seva llicència però no heu iniciat sessió en cap compte de Google.</string>\n    <string name=\"license_notification_title\">%1$s no ha pogut verificar la llicència</string>\n    <string name=\"license_notification_body\">Si l\\'aplicació no funciona correctament, inicia la sessió en un compte de Google amb el qual heu comprat l\\'aplicació.</string>\n    <string name=\"license_notification_sign_in\">Iniciar sessió</string>\n    <string name=\"license_notification_ignore\">Ignorar</string>\n    <string name=\"vending_activity_name\">Botiga d\\'aplicacions de treball</string>\n    <string name=\"vending_overview_enterprise_row_mandatory\">Instal·lació requerida</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_hint\">El vostre administrador requereix que aquestes aplicacions siguen instal·lades al vostre perfil gestionat.</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_missing_hint\">El vostre dispositiu manca d\\'aplicacions obligatòries escollides pel vostre administrador.</string>\n    <string name=\"vending_overview_enterprise_row_offered\">Aplicacions disponibles</string>\n    <string name=\"vending_overview_enterprise_row_offered_hint\">Aquestes són totes les aplicacions a disposició de la vostra empresa.</string>\n    <string name=\"vending_overview_row_installed\">Aplicacions instal·lades</string>\n    <string name=\"vending_overview_row_action_install\">Instal·lar</string>\n    <string name=\"vending_overview_row_action_update\">Actualitzar</string>\n    <string name=\"vending_overview_row_action_uninstall\">Desinstal·lar</string>\n    <string name=\"pay_disabled\">Actualment no és possible pagar</string>\n    <string name=\"confirm_purchase\">Confirmar la compra</string>\n    <string name=\"error_network\">No esteu connectat a internet. Assegureu-vos que el Wi-Fi o la xarxa mòbil estiguin activats i torneu-ho a provar.</string>\n    <string name=\"error_passwd\">La contrasenya que heu introduït és incorrecta.</string>\n    <string name=\"error_unknown\">Error desconegut. Si us plau, tanqueu i torneu-ho a provar.</string>\n    <string name=\"error_retry\">Reintentar</string>\n    <string name=\"tips_input_passwd\">Introduïu la vostra contrasenya</string>\n    <string name=\"tips_remember_login_info\">Recordar el meu inici de sessió en aquest dispositiu</string>\n    <string name=\"tips_forget_passwd\">Heu oblidat la contrasenya?</string>\n    <string name=\"tips_more_details\">Més informació</string>\n    <string name=\"text_verify_button\">Verificar</string>\n    <string name=\"installer_notification_channel_name\">Instal·lació d\\'aplicacions i components</string>\n    <string name=\"vending_overview_enterprise_no_apps_available\">No hi ha aplicacions disponibles per l\\'administrador.</string>\n    <string name=\"vending_overview_enterprise_no_apps_available_wait\">Pot trigar unes hores després de configurar el teu perfil de treball abans que les aplicacions estiguin llestes per baixar.</string>\n    <string name=\"vending_overview_row_update_available\">Actualització disponible</string>\n    <string name=\"installer_notification_channel_description\">Mostra el progrés de la instal·lació d\\'aplicacions i components, l\\'èxit i els missatges de fallada.</string>\n    <string name=\"installer_notification_progress_downloading\">Descarregant \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_commiting\">Instal·lant \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_complete\">S\\'ha instal·lat \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_failed\">No s\\'ha pogut instal·lar \\\"%s\\\"</string>\n    <string name=\"installer_dependency_noun\">Components necessaris per a %s</string>\n    <string name=\"installer_notification_progress_splitinstall_downloading\">Baixant components necessaris per a %s</string>\n    <string name=\"installer_notification_progress_splitinstall_commiting\">Instal·lant components necessaris per a %s</string>\n    <string name=\"download_notification_attachment_file\">Fitxers addicionals per a %s</string>\n    <string name=\"download_notification_tips\">Baixant</string>\n    <string name=\"installer_notification_progress_splitinstall_click_install\">Feu clic per instal·lar els components requerits per %s</string>\n    <string name=\"billing_permission_desc\">Permet a l\\'usuari comprar articles amb Google Play des d\\'aquesta aplicació.</string>\n    <string name=\"billing_permission_label\">Servei de facturació de Google Play</string>\n    <string name=\"app_install_permission_allowed\">Permet</string>\n    <string name=\"app_install_needs_permissions_title\">Instal·lador d\\'aplicacions</string>\n    <string name=\"app_install_allow_to_install_third_app\">Permetre que el company del microG instal·li aplicacions baixades de \\\"%1$s\\\"</string>\n    <string name=\"app_install_refuse_permission_remind\">Si declineu, la instal·lació de l\\'aplicació fallarà.</string>\n    <string name=\"app_install_refuse_permission_remind_sub\">Podeu modificar els permisos de l\\'estat d\\'autorització en qualsevol moment a la configuració del servei microG.</string>\n    <string name=\"app_install_not_remind_again\">Mantenir aquesta selecció i no tornar a preguntar</string>\n</resources>\n"
  },
  {
    "path": "vending-app/src/main/res/values-cs/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\">Doprovodná aplikace microG</string>\n    <string name=\"toast_installed\">Doprovodnou aplikaci microG nelze používat samostatně. Namísto toho byla otevřena Nastavení microG.</string>\n    <string name=\"toast_not_installed\">Doprovodnou aplikaci microG nelze používat samostatně. Pro používání microG si nainstalujte Služby microG.</string>\n    <string name=\"license_notification_channel_name\">Oznámení o licencích</string>\n    <string name=\"license_notification_title\">Aplikaci %1$s se nepodařilo ověřit licenci</string>\n    <string name=\"license_notification_body\">Pokud aplikace nefunguje správně, přihlaste se do účtu Google, se kterým jste si aplikaci zakoupili.</string>\n    <string name=\"license_notification_ignore\">Ignorovat</string>\n    <string name=\"confirm_purchase\">Potvrdit platbu</string>\n    <string name=\"error_network\">Nejste připojeni k internetu. Ujistěte se, že máte zapnutou Wi-Fi nebo mobilní data a zkuste to znovu.</string>\n    <string name=\"error_passwd\">Zadané heslo je nesprávné.</string>\n    <string name=\"error_unknown\">Neznámá chyba, ukončete prosím aplikaci a zkuste to znovu.</string>\n    <string name=\"tips_remember_login_info\">Zapamatovat si mě na tomto zařízení</string>\n    <string name=\"tips_more_details\">Zjistit více</string>\n    <string name=\"text_verify_button\">Ověřit</string>\n    <string name=\"pay_disabled\">Platby momentálně nejsou možné</string>\n    <string name=\"license_notification_channel_description\">Oznámí, když se aplikace pokusí ověřit svou licenci, ale vy nejste přihlášeni do žádného účtu Google.</string>\n    <string name=\"license_notification_sign_in\">Přihlásit se</string>\n    <string name=\"tips_input_passwd\">Zadejte své heslo</string>\n    <string name=\"tips_forget_passwd\">Zapomněli jste heslo?</string>\n    <string name=\"download_notification_tips\">Stahování</string>\n    <string name=\"download_notification_attachment_file\">Dodatečné soubory pro %s</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_missing_hint\">V zařízení chybí povinné aplikace vybrané administrátorem.</string>\n    <string name=\"vending_overview_enterprise_row_offered\">Dostupné aplikace</string>\n    <string name=\"vending_overview_enterprise_no_apps_available\">Váš administrátor nezpřístupnil žádné aplikace.</string>\n    <string name=\"vending_overview_row_installed\">Nainstalované aplikace</string>\n    <string name=\"vending_overview_row_update_available\">Dostupná aktualizace</string>\n    <string name=\"vending_overview_row_action_install\">Instalovat</string>\n    <string name=\"installer_notification_progress_downloading\">Stahování „%s“</string>\n    <string name=\"installer_notification_progress_complete\">Aplikace „%s“ nainstalována</string>\n    <string name=\"installer_dependency_noun\">Vyžadované součásti pro %s</string>\n    <string name=\"installer_notification_progress_splitinstall_downloading\">Stahování vyžadovaných součástí pro %s</string>\n    <string name=\"vending_activity_name\">Obchod s pracovními aplikacemi</string>\n    <string name=\"error_retry\">Zkusit znovu</string>\n    <string name=\"vending_overview_row_action_uninstall\">Odinstalovat</string>\n    <string name=\"vending_overview_row_action_update\">Aktualizovat</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_hint\">Váš administrátor vyžaduje, aby byly tyto aplikace nainstalovány ve vašem spravovaném profilu.</string>\n    <string name=\"vending_overview_enterprise_row_offered_hint\">Toto jsou všechny aplikace zpřístupněné vaším zaměstnavatelem.</string>\n    <string name=\"vending_overview_enterprise_no_apps_available_wait\">Po nastavení pracovního profilu může trvat několik hodin, než budou aplikace dostupné ke stažení.</string>\n    <string name=\"vending_overview_enterprise_row_mandatory\">Vyžadována instalace</string>\n    <string name=\"installer_notification_channel_name\">Instalace aplikací a součástí</string>\n    <string name=\"installer_notification_progress_failed\">Nepodařilo se nainstalovat „%s“</string>\n    <string name=\"installer_notification_progress_splitinstall_commiting\">Instalace vyžadovaných součástí pro %s</string>\n    <string name=\"installer_notification_channel_description\">Zobrazuje postup instalace aplikací a součástí a zprávy o úspěchu nebo chybě.</string>\n    <string name=\"installer_notification_progress_commiting\">Instalace „%s“</string>\n    <string name=\"billing_permission_desc\">Umožňuje uživateli zakoupit si položky skrze Obchod Play z této aplikace.</string>\n    <string name=\"billing_permission_label\">Fakturační služba Google Play</string>\n    <string name=\"installer_notification_progress_splitinstall_click_install\">Klikněte pro instalaci komponent vyžadovaných aplikací %s</string>\n    <string name=\"app_install_permission_allowed\">Povolit</string>\n    <string name=\"app_install_needs_permissions_title\">Instalátor aplikací</string>\n    <string name=\"app_install_allow_to_install_third_app\">Povolte „Doprovodné aplikaci microG“ instalovat aplikace stažené z „%1$s“</string>\n    <string name=\"app_install_refuse_permission_remind\">Pokud tuto akci odmítnete, instalace aplikace selže.</string>\n    <string name=\"app_install_refuse_permission_remind_sub\">Oprávnění stavu autorizace můžete kdykoli upravit v nastavení služby microG.</string>\n    <string name=\"app_install_not_remind_again\">Ponechat tento výběr a již se neptat</string>\n</resources>\n"
  },
  {
    "path": "vending-app/src/main/res/values-de/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\">microG Companion</string>\n    <string name=\"toast_installed\">microG Companion kann nicht eigenständig verwendet werden. Öffne stattdessen die microG-Services-Einstellungen.</string>\n    <string name=\"toast_not_installed\">microG Companion kann nicht eigenständig verwendet werden. Bitte installiere microG Services, um microG zu nutzen.</string>\n    <string name=\"pay_disabled\">Bezahlung derzeit nicht möglich</string>\n    <string name=\"confirm_purchase\">Kauf bestätigen</string>\n    <string name=\"error_passwd\">Das eingegebene Passwort ist falsch.</string>\n    <string name=\"error_network\">Keine Verbindung zum Internet. Bitte stelle sicher, dass WLAN oder mobile Daten eingeschaltet sind und probiere es dann erneut.</string>\n    <string name=\"error_unknown\">Unbekannter Fehler, bitte beenden und erneut versuchen.</string>\n    <string name=\"tips_input_passwd\">Passwort eingeben</string>\n    <string name=\"tips_remember_login_info\">Passwort auf diesem Gerät speichern</string>\n    <string name=\"tips_more_details\">Mehr erfahren</string>\n    <string name=\"tips_forget_passwd\">Passwort vergessen?</string>\n    <string name=\"text_verify_button\">Prüfen</string>\n    <string name=\"license_notification_channel_name\">Lizenzbenachrichtigungen</string>\n    <string name=\"license_notification_channel_description\">Benachrichtigt, wenn eine App versucht, ihre Lizenz zu validieren, du aber nicht in einem Google-Konto angemeldet bist.</string>\n    <string name=\"license_notification_title\">%1$s konnte die Lizenz nicht überprüfen</string>\n    <string name=\"license_notification_body\">Wenn die App nicht ordnungsgemäß funktioniert, melde dich mit dem Google-Konto an, mit dem du die App gekauft haben.</string>\n    <string name=\"license_notification_sign_in\">Anmelden</string>\n    <string name=\"license_notification_ignore\">Ignorieren</string>\n    <string name=\"download_notification_attachment_file\">Zusätzliche Dateien für %s</string>\n    <string name=\"download_notification_tips\">Wird heruntergeladen</string>\n    <string name=\"vending_overview_enterprise_no_apps_available\">Von deinem Administrator wurden keine Apps zur Verfügung gestellt.</string>\n    <string name=\"vending_overview_row_action_uninstall\">Deinstallieren</string>\n    <string name=\"installer_notification_channel_name\">App- und Komponenteninstallation</string>\n    <string name=\"installer_notification_channel_description\">Zeigt den Fortschritt der App- und Komponenteninstallation sowie Erfolgs- und Fehlermeldungen an.</string>\n    <string name=\"installer_notification_progress_commiting\">„%s“ wird installiert</string>\n    <string name=\"installer_dependency_noun\">Erforderliche Komponenten für %s</string>\n    <string name=\"vending_overview_row_update_available\">Aktualisierung verfügbar</string>\n    <string name=\"installer_notification_progress_complete\">„%s“ installiert</string>\n    <string name=\"installer_notification_progress_splitinstall_commiting\">Erforderliche Komponenten für %s werden installiert</string>\n    <string name=\"vending_overview_row_action_install\">Installieren</string>\n    <string name=\"vending_overview_enterprise_row_offered_hint\">Dies sind alle Apps, die von deinem Arbeitgeber zur Verfügung gestellt werden.</string>\n    <string name=\"vending_overview_row_installed\">Installierte Apps</string>\n    <string name=\"installer_notification_progress_splitinstall_downloading\">Erforderliche Komponenten für %s werden heruntergeladen</string>\n    <string name=\"error_retry\">Erneut versuchen</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_missing_hint\">Auf deinem Gerät fehlen die von deinem Administrator ausgewählten obligatorischen Apps.</string>\n    <string name=\"vending_overview_enterprise_row_offered\">Verfügbare Apps</string>\n    <string name=\"vending_overview_row_action_update\">Aktualisieren</string>\n    <string name=\"vending_overview_enterprise_no_apps_available_wait\">Nach dem Einrichten deines Arbeitsprofils kann es ein paar Stunden dauern, bis die Apps zum Herunterladen bereitstehen.</string>\n    <string name=\"installer_notification_progress_downloading\">„%s“ wird heruntergeladen</string>\n    <string name=\"installer_notification_progress_failed\">„%s“ konnte nicht installiert werden</string>\n    <string name=\"vending_overview_enterprise_row_mandatory\">Installation erforderlich</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_hint\">Dein Administrator verlangt, dass diese Apps in deinem verwalteten Profil installiert sind.</string>\n    <string name=\"vending_activity_name\">App-Store für die Arbeit</string>\n    <string name=\"billing_permission_desc\">Ermöglicht dem Benutzer, innerhalb dieser App Artikel über Google Play zu kaufen.</string>\n    <string name=\"billing_permission_label\">Google-Play-Abrechnungsdienst</string>\n    <string name=\"installer_notification_progress_splitinstall_click_install\">Klicken, um die von %s benötigten Komponenten zu installieren</string>\n    <string name=\"app_install_permission_allowed\">Erlauben</string>\n    <string name=\"app_install_needs_permissions_title\">App-Installationsprogramm</string>\n    <string name=\"app_install_allow_to_install_third_app\">„microG Companion“ darf Apps installieren, die von „%1$s“ heruntergeladen wurden</string>\n    <string name=\"app_install_refuse_permission_remind\">Wenn du ablehnst, schlägt die Installation der Anwendung fehl.</string>\n    <string name=\"app_install_refuse_permission_remind_sub\">Du kannst die Berechtigungen für den Autorisierungsstatus jederzeit in den microG-Diensteinstellungen ändern.</string>\n    <string name=\"app_install_not_remind_again\">Diese Auswahl beibehalten und nicht erneut nachfragen</string>\n</resources>\n"
  },
  {
    "path": "vending-app/src/main/res/values-eo/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources></resources>"
  },
  {
    "path": "vending-app/src/main/res/values-es/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\">Acompañante de microG</string>\n    <string name=\"toast_installed\">No se puede utilizar el Acompañante de microG de forma independiente. Se abrió la configuración de microG en su lugar.</string>\n    <string name=\"toast_not_installed\">El Acompañante de microG no puede utilizarse de forma independiente. Instale los servicios de microG para utilizar microG.</string>\n    <string name=\"license_notification_title\">%1$s no pudo verificar la licencia</string>\n    <string name=\"license_notification_body\">Si la aplicación no funciona correctamente, accede a la cuenta de Google con la que compraste la aplicación.</string>\n    <string name=\"license_notification_sign_in\">Acceder</string>\n    <string name=\"license_notification_ignore\">Ignorar</string>\n    <string name=\"license_notification_channel_name\">Notificaciones de licencia</string>\n    <string name=\"license_notification_channel_description\">Cuando una aplicación intenta validar su licencia pero no has iniciado sesión en ninguna cuenta de Google, se emitirá una notificación.</string>\n    <string name=\"pay_disabled\">Actualmente no es posible pagar</string>\n    <string name=\"error_passwd\">La contraseña que ha introducido es incorrecta.</string>\n    <string name=\"error_unknown\">Error desconocido. Salga y vuelva a intentarlo.</string>\n    <string name=\"tips_forget_passwd\">¿Olvidó su contraseña?</string>\n    <string name=\"tips_more_details\">Más información</string>\n    <string name=\"confirm_purchase\">Confirmar compra</string>\n    <string name=\"error_network\">Sin conexión a internet. Cerciórese de que la red wifi o móvil esté activada y vuelva a intentarlo.</string>\n    <string name=\"tips_input_passwd\">Introduzca su contraseña</string>\n    <string name=\"tips_remember_login_info\">Recordar el inicio de sesión en este dispositivo</string>\n    <string name=\"text_verify_button\">Verificar</string>\n    <string name=\"download_notification_attachment_file\">Archivos adicionales para %s</string>\n    <string name=\"download_notification_tips\">Descargando</string>\n    <string name=\"vending_activity_name\">Tienda de aplicaciones para el trabajo</string>\n    <string name=\"vending_overview_enterprise_row_mandatory\">Se requiere la instalación</string>\n    <string name=\"vending_overview_enterprise_row_offered\">Aplicaciones disponibles</string>\n    <string name=\"vending_overview_enterprise_row_offered_hint\">Su empresa le brinda estas aplicaciones.</string>\n    <string name=\"vending_overview_row_update_available\">Actualización disponible</string>\n    <string name=\"vending_overview_enterprise_no_apps_available_wait\">Pueden transcurrir algunas horas tras configurar el perfil laboral para que haya aplicaciones disponibles para descargar.</string>\n    <string name=\"vending_overview_row_installed\">Aplicaciones instaladas</string>\n    <string name=\"vending_overview_row_action_install\">Instalar</string>\n    <string name=\"vending_overview_row_action_update\">Actualizar</string>\n    <string name=\"vending_overview_row_action_uninstall\">Desinstalar</string>\n    <string name=\"error_retry\">Reintentar</string>\n    <string name=\"installer_notification_channel_name\">Instalación de aplicaciones y componentes</string>\n    <string name=\"installer_notification_channel_description\">Muestra el progreso de la instalación de aplicaciones y componentes, así como mensajes de éxito y fallo.</string>\n    <string name=\"installer_notification_progress_downloading\">Descargando «%s»</string>\n    <string name=\"installer_notification_progress_complete\">Se instaló «%s»</string>\n    <string name=\"installer_dependency_noun\">Componentes requeridos para %s</string>\n    <string name=\"installer_notification_progress_failed\">No se pudo instalar «%s»</string>\n    <string name=\"installer_notification_progress_splitinstall_downloading\">Descargando componentes requeridos para %s</string>\n    <string name=\"installer_notification_progress_splitinstall_commiting\">Instalando componentes requeridos para %s</string>\n    <string name=\"installer_notification_progress_commiting\">Instalando «%s»</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_hint\">Su administrador requiere que estas aplicaciones se instalen en su perfil administrado.</string>\n    <string name=\"vending_overview_enterprise_no_apps_available\">Su administrador no ha puesto ninguna aplicación a disposición.</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_missing_hint\">A su dispositivo le faltan aplicaciones obligatorias elegidas por su administrador.</string>\n    <string name=\"installer_notification_progress_splitinstall_click_install\">Haga clic para instalar los componentes requeridos por %s</string>\n    <string name=\"billing_permission_desc\">Permite al usuario comprar artículos a través de Google Play desde esta aplicación.</string>\n    <string name=\"billing_permission_label\">Servicio de facturación de Google Play</string>\n    <string name=\"app_install_permission_allowed\">Permitir</string>\n    <string name=\"app_install_needs_permissions_title\">Instalador de Apps</string>\n    <string name=\"app_install_allow_to_install_third_app\">Permitir que \\\"microG Companion\\\" instale Apps descargadas desde \\\"%1$s\\\"</string>\n    <string name=\"app_install_refuse_permission_remind\">Si lo rechaza, la instalación de la aplicación fallará.</string>\n    <string name=\"app_install_refuse_permission_remind_sub\">Puede modificar el estado de autorización de los permisos en cualquier momento en la configuración de los Servicios de microG.</string>\n    <string name=\"app_install_not_remind_again\">Mantener esta selección y no volver a preguntar</string>\n</resources>\n"
  },
  {
    "path": "vending-app/src/main/res/values-fa/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"toast_installed\">همراه میکروجی نمی‌تواند به تنهایی استفاده شود. به جای آن تنظیمات خدمات میکروجی باز شد.</string>\n    <string name=\"toast_not_installed\">همراه میکروجی نمی‌تواند به تنهایی استفاده شود. لطفاً برای استفاده از میکروجی، خدمات میکروجی را نصب کنید.</string>\n    <string name=\"license_notification_channel_name\">آگاه‌سازهای پروانه</string>\n    <string name=\"license_notification_channel_description\">هنگامی که برنامه‌ای سعی در راستی‌آزمایی پروانه خود دارد، اما شما در هیچ حساب گوگل وارد نشده‌اید، آگاه‌ساز نمایش می‌دهد.</string>\n    <string name=\"license_notification_title\">%1$s نتوانست پروانه را راستی‌آزمایی کند</string>\n    <string name=\"license_notification_body\">اگر برنامه درست کار نمی‌کند، با حسابی از گوگل که با آن برنامه را خریده‌اید وارد شوید.</string>\n    <string name=\"license_notification_sign_in\">ورود</string>\n    <string name=\"license_notification_ignore\">نادیده گرفتن</string>\n    <string name=\"vending_activity_name\">فروشگاه برنامه کاری</string>\n    <string name=\"vending_overview_enterprise_row_mandatory\">نصب لازم است</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_hint\">مدیر شما نیاز دارد این برنامه‌ها در نمایه مدیریت‌شده شما نصب شوند.</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_missing_hint\">دستگاه شما برنامه‌های لازم انتخاب شده توسط مدیر را ندارد.</string>\n    <string name=\"vending_overview_enterprise_row_offered_hint\">این‌ها همه برنامه‌هایی هستند که سازمان شما در دسترس قرار داده است.</string>\n    <string name=\"vending_overview_enterprise_no_apps_available\">هیچ برنامه‌ای توسط مدیر شما در دسترس قرار نگرفته است.</string>\n    <string name=\"vending_overview_enterprise_no_apps_available_wait\">ممکن است پس از راه‌اندازی نمایه کاری، چند ساعت طول بکشد تا برنامه‌ها آماده بارگیری شوند.</string>\n    <string name=\"vending_overview_row_installed\">برنامه‌های نصب شده</string>\n    <string name=\"vending_overview_row_action_install\">نصب</string>\n    <string name=\"vending_overview_row_action_update\">به‌روزرسانی</string>\n    <string name=\"vending_overview_row_action_uninstall\">حذف نصب</string>\n    <string name=\"pay_disabled\">پرداخت در حال حاضر امکان‌پذیر نیست</string>\n    <string name=\"confirm_purchase\">پذیرش خرید</string>\n    <string name=\"error_network\">به اینترنت متصل نیستید. لطفاً مطمئن شوید وای‌فای یا شبکه تلفن همراه روشن است و دوباره تلاش کنید.</string>\n    <string name=\"error_passwd\">گذرواژه وارد شده نادرست است.</string>\n    <string name=\"error_unknown\">خطای ناشناخته، لطفاً خارج شوید و دوباره تلاش کنید.</string>\n    <string name=\"tips_input_passwd\">گذرواژه خود را وارد کنید</string>\n    <string name=\"tips_remember_login_info\">داده‌های ورود من را در این دستگاه به خاطر بسپار</string>\n    <string name=\"tips_forget_passwd\">گذرواژه را فراموش کرده‌اید؟</string>\n    <string name=\"tips_more_details\">آگاهی بیشتر</string>\n    <string name=\"text_verify_button\">راستی‌آزمایی</string>\n    <string name=\"installer_notification_channel_name\">نصب برنامه و بخش</string>\n    <string name=\"installer_notification_channel_description\">پیشرفت نصب برنامه و بخش، پیام‌های موفقیت و شکست را نشان می‌دهد.</string>\n    <string name=\"installer_notification_progress_downloading\">در حال بارگیری \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_commiting\">در حال نصب \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_complete\">نصب شده \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_failed\">نصب \\\"%s\\\" شکست خورد</string>\n    <string name=\"installer_dependency_noun\">بخش‌های مورد نیاز برای %s</string>\n    <string name=\"installer_notification_progress_splitinstall_downloading\">در حال بارگیری بخش‌های مورد نیاز برای %s</string>\n    <string name=\"installer_notification_progress_splitinstall_commiting\">در حال نصب بخش‌های مورد نیاز برای %s</string>\n    <string name=\"download_notification_attachment_file\">پرونده‌های افزوده برای %s</string>\n    <string name=\"app_name\">همراه میکروجی</string>\n    <string name=\"vending_overview_enterprise_row_offered\">برنامه‌های در دسترس</string>\n    <string name=\"vending_overview_row_update_available\">به‌روزرسانی در دسترس است</string>\n    <string name=\"error_retry\">تلاش دوباره</string>\n    <string name=\"download_notification_tips\">در حال بارگیری</string>\n    <string name=\"installer_notification_progress_splitinstall_click_install\">برای نصب اجزای مورد نیاز %s کلیک کنید</string>\n    <string name=\"billing_permission_desc\">به کاربر اجازه ی خریدرا از طریق گوگل پلی از داخل برنامه میدهد.</string>\n    <string name=\"billing_permission_label\">خدمات صورتحساب گوگل پلی</string>\n    <string name=\"app_install_permission_allowed\">اجازه دادن</string>\n    <string name=\"app_install_needs_permissions_title\">نصب کننده برنامه</string>\n    <string name=\"app_install_allow_to_install_third_app\">اجازه به \\\"microG Companion\\\" برای نصب برنامه های دانلودشده از \\\"%1$s\\\"</string>\n    <string name=\"app_install_refuse_permission_remind\">در صورت رد کردن، نصب برنامه لغو می‌شود.</string>\n</resources>\n"
  },
  {
    "path": "vending-app/src/main/res/values-fi/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_notification_sign_in\">Kirjaudu sisään</string>\n    <string name=\"license_notification_ignore\">Hylkää</string>\n    <string name=\"pay_disabled\">Maksaminen ei ole tällä hetkellä mahdollista</string>\n    <string name=\"confirm_purchase\">Vahvista osto</string>\n    <string name=\"error_network\">Ei verkkoyhteyttä. Varmista, että Wi-Fi tai matkapuhelinverkko on päällä ja yritä uudelleen.</string>\n    <string name=\"error_passwd\">Syöttämäsi salasana on virheellinen.</string>\n    <string name=\"error_unknown\">Tuntematon virhe, sulje ja yritä uudelleen.</string>\n    <string name=\"tips_input_passwd\">Syötä salasana</string>\n    <string name=\"tips_remember_login_info\">Muista kirjautumiseni tälle laitteelle</string>\n    <string name=\"tips_forget_passwd\">Unohditko salasanasi?</string>\n    <string name=\"tips_more_details\">Lisätietoja</string>\n    <string name=\"text_verify_button\">Vahvista</string>\n    <string name=\"download_notification_tips\">Ladataan</string>\n    <string name=\"app_name\">microG Avustaja</string>\n    <string name=\"toast_installed\">microG-avustajaa ei voi käyttää sellaisenaan. Avattiin microG Palvelut asetukset sen sijaan.</string>\n    <string name=\"toast_not_installed\">microG Avustaja ohjelmaa ei voi käyttää itsenäisesti. Asenna microG Palvelut käyttääksesi microG:tä.</string>\n    <string name=\"license_notification_channel_name\">Lisenssi-ilmoitukset</string>\n    <string name=\"license_notification_channel_description\">Ilmoittaa kun ohjelma yrittää varmentaa lisenssiään, mutta et ole kirjautuneena yhteenkään Google-tiliin.</string>\n    <string name=\"license_notification_title\">%1$s ei voinut varmentaa lisenssiä</string>\n</resources>\n"
  },
  {
    "path": "vending-app/src/main/res/values-fil/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_notification_ignore\">Huwag pansinin</string>\n    <string name=\"app_name\">Kasamahan ng microG</string>\n    <string name=\"toast_installed\">Hindi magagamit ang Kasamahan ng microG nang nakapag-iisa. Binuksan na lang ang mga setting ng Mga Serbisyo ng microG sa halip.</string>\n    <string name=\"toast_not_installed\">Hindi magagamit ang Kasamahan ng microG nang nakapag-iisa. Paki-install ang Mga Serbisyo ng microG para gamitin ang microG.</string>\n    <string name=\"license_notification_channel_name\">Mga notification ng lisensya</string>\n    <string name=\"license_notification_channel_description\">Aabisuhan kapag sinusubukan ng isang app na patunayin ang lisensya, ngunit hindi ka naka-sign in sa anumang Google account.</string>\n    <string name=\"license_notification_title\">Hindi mapatunay ng %1$s ang lisensya</string>\n    <string name=\"license_notification_body\">Kung hindi gumagana ang app, mag-sign in sa isang Google account kung saan mo binili ang app.</string>\n    <string name=\"license_notification_sign_in\">Mag-Sign In</string>\n    <string name=\"pay_disabled\">Kasalukuyang hindi posible ang pagbili</string>\n    <string name=\"confirm_purchase\">Kumpirmahin ang Pagbili</string>\n    <string name=\"error_network\">Hindi nakakonekta sa internet. Pakisigurado na nakabukas ang Wi-Fi o mobile network at subukan muli.</string>\n    <string name=\"error_passwd\">Mali ang inilagay mong password.</string>\n    <string name=\"error_unknown\">Hindi alam na error, mangyaring umalis at subukan muli.</string>\n    <string name=\"tips_input_passwd\">Ilagay ang iyong password</string>\n    <string name=\"tips_remember_login_info\">Tandaan ang login sa device na ito</string>\n    <string name=\"tips_forget_passwd\">Nakalimutan ang password?</string>\n    <string name=\"tips_more_details\">Matuto pa</string>\n    <string name=\"text_verify_button\">I-verify</string>\n    <string name=\"download_notification_attachment_file\">Mga karagdagang file para sa %s</string>\n    <string name=\"download_notification_tips\">Dina-download</string>\n    <string name=\"vending_overview_enterprise_row_offered\">Mga available na app</string>\n    <string name=\"vending_overview_row_installed\">Mga naka-install na app</string>\n    <string name=\"installer_notification_channel_description\">Ipinapakita ang pag-usad ng pag-install ng app at bahagi, mga mensahe ng tagumpay at pagkabigo.</string>\n    <string name=\"installer_notification_progress_complete\">Na-install ang \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_splitinstall_downloading\">Dina-download ang mga kinakailangang component para sa %s</string>\n    <string name=\"installer_notification_progress_splitinstall_commiting\">Ini-install ang mga kinakailangang component para sa %s</string>\n    <string name=\"vending_overview_row_update_available\">Available ang update</string>\n    <string name=\"error_retry\">Subukan muli</string>\n    <string name=\"installer_notification_progress_commiting\">Ini-install ang \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_failed\">Nabigong i-install ang \\\"%s\\\"</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_hint\">Kinakailangan ng iyong tagapangasiwa ang mga app na ito na naka-install sa iyong pinamamahalaang profile.</string>\n    <string name=\"vending_activity_name\">App store ng trabaho</string>\n    <string name=\"vending_overview_enterprise_row_mandatory\">Nangangailangan ng pag-install</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_missing_hint\">Ang iyong device ay walang mga mandatoryong app na pinili ng iyong tagapangasiwa.</string>\n    <string name=\"vending_overview_enterprise_row_offered_hint\">Ito ang lahat ng app na ginawang available ng iyong negosyo.</string>\n    <string name=\"installer_notification_progress_downloading\">Dina-download ang \\\"%s\\\"</string>\n    <string name=\"vending_overview_row_action_uninstall\">I-uninstall</string>\n    <string name=\"vending_overview_enterprise_no_apps_available\">Walang mga app ay ginawang available ng iyong tagapangasiwa.</string>\n    <string name=\"vending_overview_enterprise_no_apps_available_wait\">Maaaring tumagal ng ilang oras pagkatapos i-set up ang iyong profile sa trabaho bago handa na i-download ang mga app.</string>\n    <string name=\"vending_overview_row_action_update\">I-update</string>\n    <string name=\"vending_overview_row_action_install\">I-install</string>\n    <string name=\"installer_notification_channel_name\">Pag-install ng app at component</string>\n    <string name=\"installer_dependency_noun\">Mga kinakailangang component para sa %s</string>\n    <string name=\"installer_notification_progress_splitinstall_click_install\">I-click para i-install ang mga component na kinakailangan ng %s</string>\n    <string name=\"billing_permission_desc\">Pinapayagan ang user na bumili ng mga item sa pamamagitan ng Google Play mula sa loob ng app na ito.</string>\n    <string name=\"billing_permission_label\">Google Play billing service</string>\n</resources>\n"
  },
  {
    "path": "vending-app/src/main/res/values-fr/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_notification_channel_description\">Signale lorsqu\\'une application tente de valider sa licence, mais que vous n\\'êtes connecté(e) à aucun compte Google.</string>\n    <string name=\"license_notification_title\">%1$s n\\'a pas pu vérifier la licence</string>\n    <string name=\"license_notification_body\">Si l\\'application ne fonctionne pas correctement, connectez-vous au compte Google avec lequel vous avez acheté l\\'application.</string>\n    <string name=\"license_notification_sign_in\">S\\'identifier</string>\n    <string name=\"license_notification_channel_name\">Notifications de licence</string>\n    <string name=\"license_notification_ignore\">Ignorer</string>\n    <string name=\"app_name\">Compagnon microG</string>\n    <string name=\"pay_disabled\">Pay actuellement impossible</string>\n    <string name=\"confirm_purchase\">Confirmer l\\'achat</string>\n    <string name=\"error_network\">Non connecté à internet. Merci de vérifier que le Wi-Fi ou les données mobiles sont actifs et réessayer.</string>\n    <string name=\"error_passwd\">Le mot de passe saisi est incorrect.</string>\n    <string name=\"error_unknown\">Erreur inconnue, merci de quitter et réessayer.</string>\n    <string name=\"tips_input_passwd\">Saisir le mot de passe</string>\n    <string name=\"tips_remember_login_info\">Se souvenir de moi sur cet appareil</string>\n    <string name=\"tips_forget_passwd\">Mot de passe oublié ?</string>\n    <string name=\"tips_more_details\">En savoir plus</string>\n    <string name=\"text_verify_button\">Vérifier</string>\n    <string name=\"toast_not_installed\">Le compagnon microG ne peut pas être utilisé seul. Merci d\\'installer les services microG pour utiliser microG.</string>\n    <string name=\"toast_installed\">Le compagnon microG ne peut pas être directement utilisé. Consultez plutôt les paramètres des services microG.</string>\n    <string name=\"download_notification_attachment_file\">Fichiers additionnels pour %s</string>\n    <string name=\"download_notification_tips\">Téléchargement en cours</string>\n    <string name=\"vending_overview_enterprise_row_offered\">Applis disponibles</string>\n    <string name=\"vending_overview_enterprise_row_mandatory\">Installation requise</string>\n    <string name=\"vending_activity_name\">Magasin d\\'applications (entreprise)</string>\n    <string name=\"vending_overview_enterprise_no_apps_available\">Aucune appli n\\'est mise à disposition par votre administrateur.</string>\n    <string name=\"vending_overview_enterprise_row_offered_hint\">Ces applis sont toutes celles mises à disposition par votre entreprise.</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_hint\">Votre administrateur requiert l\\'installation de ces applis sur votre profil professionnel.</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_missing_hint\">Il manque sur votre appareil des applis imposées par votre administrateur.</string>\n    <string name=\"vending_overview_row_action_uninstall\">Désinstaller</string>\n    <string name=\"error_retry\">Réessayer</string>\n    <string name=\"installer_notification_progress_failed\">Échec de l\\'installation de \\\"%s\\\"</string>\n    <string name=\"installer_dependency_noun\">Composants requis pour %s</string>\n    <string name=\"installer_notification_progress_complete\">\\\"%s\\\" installé</string>\n    <string name=\"vending_overview_row_action_update\">Mettre à jour</string>\n    <string name=\"installer_notification_channel_description\">Notifications montrant la progression, succès ou échec de l\\'installation des applis et composants.</string>\n    <string name=\"vending_overview_row_update_available\">Mise à jour disponible</string>\n    <string name=\"vending_overview_enterprise_no_apps_available_wait\">Cela peut prendre quelques heures après avoir configuré votre profil professionnel avant de pouvoir télécharger des applis.</string>\n    <string name=\"vending_overview_row_action_install\">Installer</string>\n    <string name=\"installer_notification_channel_name\">Installation d\\'applis et composants</string>\n    <string name=\"installer_notification_progress_splitinstall_downloading\">Téléchargement des composants requis pour %s</string>\n    <string name=\"installer_notification_progress_downloading\">Téléchargement de\\\" %s\\\"</string>\n    <string name=\"installer_notification_progress_commiting\">Installation de \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_splitinstall_commiting\">Installation des composants requis pour %s</string>\n    <string name=\"vending_overview_row_installed\">Applis installées</string>\n    <string name=\"installer_notification_progress_splitinstall_click_install\">Cliquer pour installer les composants requis par %s</string>\n    <string name=\"billing_permission_desc\">Permet à l\\'utilisateur d\\'acheter des articles sur Google Play depuis cette application.</string>\n    <string name=\"billing_permission_label\">Service de facturation Google Play</string>\n    <string name=\"app_install_needs_permissions_title\">Installateur d\\'applications</string>\n    <string name=\"app_install_permission_allowed\">Autoriser</string>\n    <string name=\"app_install_allow_to_install_third_app\">Autoriser « microG Companion » à installer les applications téléchargées depuis « %1$s »</string>\n    <string name=\"app_install_refuse_permission_remind\">Si vous refusez, l’installation de l’application échouera.</string>\n    <string name=\"app_install_refuse_permission_remind_sub\">Vous pouvez modifier les autorisations d’état d’autorisation à tout moment dans les paramètres du service microG.</string>\n    <string name=\"app_install_not_remind_again\">Gardez cette sélection et ne demandez plus</string>\n</resources>\n"
  },
  {
    "path": "vending-app/src/main/res/values-ga/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_notification_body\">Má tá an aip mí-iompair, sínigh isteach ar chuntas Google a bhfuil an aip ceannaithe agat leis.</string>\n    <string name=\"license_notification_sign_in\">Sínigh Isteach</string>\n    <string name=\"pay_disabled\">Ní féidir íoc faoi láthair</string>\n    <string name=\"confirm_purchase\">Deimhnigh Ceannach</string>\n    <string name=\"error_network\">Níl sé ceangailte leis an Idirlíon. Cinntigh go bhfuil Wi-Fi nó líonra móibíleach ar siúl agus bain triail eile as.</string>\n    <string name=\"error_unknown\">Earráid anaithnid, scoir agus bain triail eile as.</string>\n    <string name=\"tips_input_passwd\">Cuir isteach do phasfhocal</string>\n    <string name=\"tips_forget_passwd\">Dearmad pasfhocal?</string>\n    <string name=\"tips_more_details\">Foghlaim níos mó</string>\n    <string name=\"license_notification_channel_name\">Fógraí ceadúnais</string>\n    <string name=\"toast_not_installed\">Ní féidir microG Companion a úsáid ina aonar. Suiteáil Seirbhísí MicroG chun microG a úsáid.</string>\n    <string name=\"app_name\">microG Compánach</string>\n    <string name=\"toast_installed\">Ní féidir microG Companion a úsáid ina aonar. Osclaíodh socruithe MicroG Services ina ionad sin.</string>\n    <string name=\"license_notification_channel_description\">Tugtar fógra nuair a dhéanann aip iarracht a ceadúnas a bhailíochtú, ach níl tú sínithe isteach ar aon chuntas Google.</string>\n    <string name=\"license_notification_title\">Níorbh fhéidir le %1$s ceadúnas a fhíorú</string>\n    <string name=\"license_notification_ignore\">Déan neamhaird de</string>\n    <string name=\"error_passwd\">Tá an pasfhocal a d\\'iontráil tú mícheart.</string>\n    <string name=\"tips_remember_login_info\">Cuimhnigh ar mo logáil isteach ar an ngléas seo</string>\n    <string name=\"text_verify_button\">Fíoraigh</string>\n    <string name=\"download_notification_tips\">Ag íosluchtú</string>\n    <string name=\"download_notification_attachment_file\">Comhaid bhreise le haghaidh %s</string>\n    <string name=\"vending_activity_name\">Siopa aip oibre</string>\n    <string name=\"vending_overview_enterprise_row_mandatory\">Suiteáil ag teastáil</string>\n    <string name=\"vending_overview_enterprise_row_offered_hint\">Seo iad na haipeanna go léir a chuireann d’fhiontar ar fáil.</string>\n    <string name=\"vending_overview_enterprise_no_apps_available\">Níor chuir do riarthóir aon aip ar fáil.</string>\n    <string name=\"vending_overview_enterprise_no_apps_available_wait\">Seans go dtógfaidh sé cúpla uair an chloig tar éis do phróifíl oibre a shocrú sula mbeidh aipeanna réidh le híoslódáil.</string>\n    <string name=\"vending_overview_row_action_update\">Nuashonrú</string>\n    <string name=\"vending_overview_row_action_uninstall\">Díshuiteáil</string>\n    <string name=\"error_retry\">Bain triail eile as</string>\n    <string name=\"installer_notification_progress_downloading\">\\\"%s\\\" á íosluchtú</string>\n    <string name=\"installer_notification_progress_commiting\">Suiteáil \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_complete\">Suiteáilte \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_failed\">Theip ar shuiteáil \\\"%s\\\"</string>\n    <string name=\"installer_dependency_noun\">Comhpháirteanna riachtanacha le haghaidh %s</string>\n    <string name=\"installer_notification_progress_splitinstall_downloading\">Comhpháirteanna riachtanacha le haghaidh %s á n-íosluchtú</string>\n    <string name=\"installer_notification_progress_splitinstall_commiting\">Comhpháirteanna riachtanacha le haghaidh %s a shuiteáil</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_hint\">Éilíonn do riarthóir na haipeanna seo a shuiteáil i do phróifíl bhainistithe.</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_missing_hint\">Tá aipeanna éigeantacha roghnaithe ag do riarthóir in easnamh ar do ghléas.</string>\n    <string name=\"vending_overview_row_action_install\">Suiteáil</string>\n    <string name=\"installer_notification_channel_description\">Taispeánann sé teachtaireachtaí maidir le dul chun cinn, rathúlacht agus teip maidir le suiteáil aipeanna agus comhpháirteanna.</string>\n    <string name=\"vending_overview_enterprise_row_offered\">Aipeanna ar fáil</string>\n    <string name=\"vending_overview_row_update_available\">Nuashonrú ar fáil</string>\n    <string name=\"vending_overview_row_installed\">Aipeanna suiteáilte</string>\n    <string name=\"installer_notification_channel_name\">Suiteáil aip agus comhpháirteanna</string>\n    <string name=\"billing_permission_desc\">Ligeann sé don úsáideoir earraí a cheannach trí Google Play ón aip seo.</string>\n    <string name=\"billing_permission_label\">Seirbhís billeála Google Play</string>\n    <string name=\"installer_notification_progress_splitinstall_click_install\">Cliceáil chun na comhpháirteanna atá riachtanach faoi %s a shuiteáil</string>\n    <string name=\"app_install_permission_allowed\">Ceadaigh</string>\n    <string name=\"app_install_needs_permissions_title\">Suiteálaí Aipeanna</string>\n    <string name=\"app_install_allow_to_install_third_app\">Ceadaigh do \\\"microG Companion\\\" aipeanna a shuiteáil a íoslódáladh ó \\\"%1$s\\\"</string>\n    <string name=\"app_install_refuse_permission_remind\">Má dhiúltaíonn tú, teipfidh ar shuiteáil an fheidhmchláir.</string>\n    <string name=\"app_install_refuse_permission_remind_sub\">Is féidir leat ceadanna stádais údaraithe a mhodhnú tráth ar bith i Socruithe Seirbhíse microG.</string>\n    <string name=\"app_install_not_remind_again\">Coinnigh an rogha seo agus ná fiafraigh arís</string>\n</resources>\n"
  },
  {
    "path": "vending-app/src/main/res/values-hu/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\">microG társ</string>\n    <string name=\"toast_installed\">A microG társ nem használható önállóan. Helyette a microG szolgáltatások lett megnyitva.</string>\n    <string name=\"toast_not_installed\">microG társat nem lehet önálló appként használni. Kérlek telepítsd a microG szolgáltatások appot, hogy használd a microG-t.</string>\n    <string name=\"license_notification_channel_name\">Licenc értesítések</string>\n</resources>\n"
  },
  {
    "path": "vending-app/src/main/res/values-in/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"toast_installed\">microG Companion tidak dapat digunakan secara mandiri. Sebagai gantinya, pengaturan microG Services dibuka.</string>\n    <string name=\"toast_not_installed\">microG Companian tidak dapat digunakan secara sendirian. Mohon install microG Services untuk menggunakan microG.</string>\n    <string name=\"license_notification_channel_name\">Pemberitahuan lisensi</string>\n    <string name=\"app_name\">microG Companion</string>\n    <string name=\"license_notification_channel_description\">Memberi tahu saat aplikasi mencoba memvalidasi lisensinya, tetapi Anda tidak masuk ke akun Google manapun.</string>\n    <string name=\"license_notification_title\">%1$s tidak dapat memverifikasi lisensi</string>\n    <string name=\"license_notification_body\">Jika aplikasi bermasalah, masuk ke akun Google yang Anda gunakan untuk membeli aplikasi tersebut.</string>\n    <string name=\"license_notification_sign_in\">Masuk</string>\n    <string name=\"license_notification_ignore\">Abaikan</string>\n    <string name=\"vending_activity_name\">Toko aplikasi kerja</string>\n    <string name=\"vending_overview_enterprise_row_mandatory\">Pemasangan diperlukan</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_hint\">Administrator Anda mengharuskan aplikasi berikut untuk dipasang di profil yang Anda kelola.</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_missing_hint\">Perangkat milik Anda kehilangan aplikasi wajib yang dipilih oleh administrator Anda.</string>\n    <string name=\"vending_overview_enterprise_row_offered\">Aplikasi yang tersedia</string>\n    <string name=\"vending_overview_enterprise_row_offered_hint\">Berikut adalah aplikasi yang disediakan oleh perusahaan Anda.</string>\n    <string name=\"vending_overview_enterprise_no_apps_available\">Belum ada aplikasi yang disediakan oleh administrator Anda.</string>\n    <string name=\"vending_overview_enterprise_no_apps_available_wait\">Kemungkinan diperlukan beberapa jam setelah profil kerja Anda berhasil disiapkan sebelum aplikasi siap diunduh.</string>\n    <string name=\"vending_overview_row_update_available\">Pembaharuan tersedia</string>\n    <string name=\"vending_overview_row_installed\">Aplikasi terpasang</string>\n    <string name=\"vending_overview_row_action_install\">Pasang</string>\n    <string name=\"vending_overview_row_action_update\">Baharukan</string>\n    <string name=\"confirm_purchase\">Konfirmasi Pembelian</string>\n    <string name=\"error_network\">Tidak terhubung ke internet. Pastikan Wi-Fi atau jaringan seluler dihidupkan lalu coba lagi.</string>\n    <string name=\"error_passwd\">Kata sandi yang Anda masukkan salah.</string>\n    <string name=\"vending_overview_row_action_uninstall\">Copot pemasangan</string>\n    <string name=\"pay_disabled\">Pembayaran tidak memungkinkan untuk saat ini</string>\n    <string name=\"error_unknown\">Error tidak diketahui, mohon keluar dan coba lagi.</string>\n    <string name=\"error_retry\">Coba kembali</string>\n    <string name=\"tips_input_passwd\">Masukkan kata sandi Anda</string>\n    <string name=\"tips_remember_login_info\">Ingat login saya di perangkat ini</string>\n    <string name=\"tips_forget_passwd\">Lupa kata sandi?</string>\n    <string name=\"tips_more_details\">Pelajari lebih lanjut</string>\n    <string name=\"text_verify_button\">Buktikan</string>\n    <string name=\"installer_notification_channel_name\">Aplikasi dan komponen instalasi</string>\n    <string name=\"installer_notification_progress_downloading\">Mengunduh \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_commiting\">Memasang \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_complete\">Terpasang \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_failed\">Gagal memasang \\\"%s\\\"</string>\n    <string name=\"installer_dependency_noun\">Komponen yang dibutuhkan untuk %s</string>\n    <string name=\"installer_notification_progress_splitinstall_downloading\">Mengunduh komponen yang dibutuhkan untuk %s</string>\n    <string name=\"installer_notification_progress_splitinstall_commiting\">Memasang komponen yang dibutuhkan untuk %s</string>\n    <string name=\"download_notification_attachment_file\">File tambahan untuk %s</string>\n    <string name=\"download_notification_tips\">Mengunduh</string>\n    <string name=\"installer_notification_channel_description\">Menampilkan kemajuan pemasangan aplikasi dan komponen, pesan keberhasilan dan kegagalan.</string>\n    <string name=\"installer_notification_progress_splitinstall_click_install\">Klik untuk memasang komponen yang diperlukan oleh %s</string>\n    <string name=\"billing_permission_desc\">Memungkinkan pengguna untuk membeli item melalui Google Play dari dalam aplikasi ini.</string>\n    <string name=\"billing_permission_label\">Layanan penagihan Google Play</string>\n    <string name=\"app_install_permission_allowed\">Izinkan</string>\n    <string name=\"app_install_needs_permissions_title\">Penginstal Apl</string>\n    <string name=\"app_install_allow_to_install_third_app\">Izinkan \\\"microG Companion\\\" untuk menginstal aplikasi yang diunduh dari \\\"%1$s\\\"</string>\n    <string name=\"app_install_refuse_permission_remind\">Jika Anda menolak, proses instalasi aplikasi akan gagal.</string>\n    <string name=\"app_install_refuse_permission_remind_sub\">Anda dapat mengubah izin status otorisasi kapan saja di Pengaturan Layanan microG.</string>\n    <string name=\"app_install_not_remind_again\">Simpan pilihan ini dan jangan tanya lagi</string>\n</resources>\n"
  },
  {
    "path": "vending-app/src/main/res/values-is/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"tips_input_passwd\">Settu inn lykilorðið þitt</string>\n    <string name=\"tips_remember_login_info\">Muna innskráningu mína á þessu tæki</string>\n    <string name=\"tips_forget_passwd\">Gleymt lykilorð?</string>\n    <string name=\"tips_more_details\">Kanna nánar</string>\n    <string name=\"text_verify_button\">Sannreyna</string>\n    <string name=\"license_notification_sign_in\">Skrá inn</string>\n    <string name=\"license_notification_ignore\">Hunsa</string>\n    <string name=\"app_name\">microG Companion fylgiforrit</string>\n    <string name=\"license_notification_channel_name\">Tilkynningar vegna notkunarleyfa</string>\n    <string name=\"pay_disabled\">Greiðsla ekki möguleg í augnablikinu</string>\n    <string name=\"confirm_purchase\">Staðfesta kaup</string>\n    <string name=\"error_passwd\">Lykilorðið sem þú settir inn er rangt.</string>\n    <string name=\"toast_installed\">microG Companion fylgiforritið er ekki hægt að nota sjálfstætt. Opnaði í staðinn stillingar fyrir microG-þjónustur.</string>\n    <string name=\"toast_not_installed\">microG Companion fylgiforritið er ekki hægt að nota sjálfstætt. Settu upp microG-þjónustur til að nota microG.</string>\n    <string name=\"license_notification_channel_description\">Lætur vita þegar forrit reynir að sannvotta notkunarleyfi þess, en þú sért ekki með virka innskráningu á neinn Google-reikning.</string>\n    <string name=\"license_notification_title\">%1$s tókst ekki að sannreyna notkunarleyfi</string>\n    <string name=\"error_network\">Engin tenging við internetið. Gakktu úr skugga um að kveikt sé á þráðlausu neti eða farsímagögnum og reyndu síðan aftur.</string>\n    <string name=\"license_notification_body\">Ef forritið hegðar sér undarlega, skaltu skrá þig inn á Google-reikninginn sem þú notaðir til að kaupa forritið.</string>\n    <string name=\"error_unknown\">Óþekkt villa kom upp, farðu út úr forritinu og reyndu svo aftur.</string>\n    <string name=\"download_notification_attachment_file\">Viðbótarskrár fyrir %s</string>\n    <string name=\"download_notification_tips\">Sæki</string>\n    <string name=\"vending_overview_row_update_available\">Uppfærsla í boði</string>\n    <string name=\"vending_overview_row_installed\">Uppsett forrit</string>\n    <string name=\"vending_overview_row_action_update\">Uppfæra</string>\n    <string name=\"installer_notification_progress_commiting\">Set upp \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_splitinstall_downloading\">Sæki nauðsynlegar einingar fyrir %s</string>\n    <string name=\"installer_notification_progress_splitinstall_commiting\">Set upp nauðsynlegar einingar fyrir %s</string>\n    <string name=\"vending_overview_enterprise_row_offered_hint\">Þetta eru öll forritin sem fyrirtækið þitt hefur gerð aðgengileg.</string>\n    <string name=\"vending_overview_enterprise_row_mandatory\">Uppsetning er nauðsynleg</string>\n    <string name=\"vending_overview_row_action_uninstall\">Fjarlægja</string>\n    <string name=\"installer_notification_progress_downloading\">Sæki \\\"%s\\\"</string>\n    <string name=\"error_retry\">Prófa aftur</string>\n    <string name=\"installer_notification_channel_name\">Uppsetning forrits og forritseininga</string>\n    <string name=\"vending_overview_enterprise_row_offered\">Tiltæk forrit</string>\n    <string name=\"vending_overview_row_action_install\">Setja upp</string>\n    <string name=\"vending_overview_enterprise_no_apps_available\">Engin forrit hafa verið gerð aðgengileg af kerfisstjóranum þínum.</string>\n    <string name=\"vending_activity_name\">Safn vinnuforrita</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_hint\">Kerfisstjórinn þinn krefst að þessi forrit séu sett upp í stýrða aðgangnum þinum.</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_missing_hint\">Tækið þitt vantar nauðsynleg forrit sem valin hafa verið af kerfisstjóranum þínum.</string>\n    <string name=\"installer_notification_channel_description\">Birtir framvindu uppsetningar forrits og forritseininga, það sem tekst og það sem mistekst.</string>\n    <string name=\"vending_overview_enterprise_no_apps_available_wait\">Það gæti tekið nokkrar klukkustundir eftir að vinnusniðið þitt hefur verið sett upp áður en hægt er að sækja forritin.</string>\n    <string name=\"installer_notification_progress_complete\">Setti inn \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_failed\">Mistókst að setja inn \\\"%s\\\"</string>\n    <string name=\"installer_dependency_noun\">Nauðsynlegar einingar fyrir %s</string>\n    <string name=\"billing_permission_desc\">Gerir notandanum kleift að kaupa hluti í gegnum Google Play inni í þessu forriti.</string>\n    <string name=\"billing_permission_label\">Innheimtuþjónusta Google Play</string>\n    <string name=\"installer_notification_progress_splitinstall_click_install\">Smelltu til að setja upp hlutana sem nauðsynlegir eru fyrir %s</string>\n</resources>\n"
  },
  {
    "path": "vending-app/src/main/res/values-it/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"toast_installed\">L\\'app microG Companion non può essere usata da sola. Sono state aperte le impostazioni di microG.</string>\n    <string name=\"toast_not_installed\">L\\'app microG Companion non può essere usata da sola. Installa l\\'app microG Services per utilizzare microG.</string>\n    <string name=\"app_name\">microG Companion</string>\n    <string name=\"pay_disabled\">Al momento non è possibile effettuare pagamenti</string>\n    <string name=\"license_notification_channel_name\">Notifiche di licenza</string>\n    <string name=\"license_notification_channel_description\">Avvisa quando un\\'applicazione cerca di convalidare la propria licenza, ma non sei connesso a nessun account Google.</string>\n    <string name=\"license_notification_title\">%1$s non è riuscita a verificare la licenza</string>\n    <string name=\"license_notification_body\">Se l\\'app non funziona correttamente, accedi con un account Google con cui hai acquistato l\\'app.</string>\n    <string name=\"license_notification_sign_in\">Accedi</string>\n    <string name=\"license_notification_ignore\">Ignora</string>\n    <string name=\"confirm_purchase\">Conferma acquisto</string>\n    <string name=\"error_passwd\">La password inserita è errata.</string>\n    <string name=\"error_unknown\">Errore sconosciuto, esci e riprova.</string>\n    <string name=\"tips_forget_passwd\">Password dimenticata?</string>\n    <string name=\"tips_input_passwd\">Inserisci la password</string>\n    <string name=\"tips_more_details\">Maggiori informazioni</string>\n    <string name=\"text_verify_button\">Verifica</string>\n    <string name=\"tips_remember_login_info\">Ricorda le mie credenziali su questo dispositivo</string>\n    <string name=\"error_network\">Connessione a Internet assente. Verifica che la connessione Wi-Fi o alla rete cellulare sia attiva e riprova.</string>\n    <string name=\"download_notification_tips\">Download in corso</string>\n    <string name=\"download_notification_attachment_file\">File aggiuntivi per %s</string>\n    <string name=\"vending_activity_name\">App del profilo di lavoro</string>\n    <string name=\"vending_overview_enterprise_row_mandatory\">Installazione richiesta</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_missing_hint\">Sul tuo dispositivo mancano delle app richieste dall\\'amministratore.</string>\n    <string name=\"vending_overview_enterprise_row_offered\">App disponibili</string>\n    <string name=\"vending_overview_enterprise_row_offered_hint\">Queste sono le app rese disponibili dalla tua organizzazione.</string>\n    <string name=\"vending_overview_enterprise_no_apps_available\">L\\'amministratore non ha reso disponibile nessuna app.</string>\n    <string name=\"vending_overview_row_installed\">App installate</string>\n    <string name=\"vending_overview_row_action_install\">Installa</string>\n    <string name=\"vending_overview_row_action_uninstall\">Disinstalla</string>\n    <string name=\"error_retry\">Riprova</string>\n    <string name=\"installer_notification_channel_name\">Installazione di app e componenti</string>\n    <string name=\"installer_notification_channel_description\">Mostra messaggi di avanzamento, completamento ed errore relativi all\\'installazione di app e componenti.</string>\n    <string name=\"installer_notification_progress_downloading\">Download di \\\"%s\\\" in corso</string>\n    <string name=\"installer_notification_progress_complete\">\\\"%s\\\" è stata installata</string>\n    <string name=\"installer_notification_progress_failed\">Installazione di \\\"%s\\\" fallita</string>\n    <string name=\"installer_dependency_noun\">Componenti richiesti per %s</string>\n    <string name=\"installer_notification_progress_splitinstall_commiting\">Installazione dei componenti richiesti per %s in corso</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_hint\">L\\'amministratore richiede che queste app siano installate nel tuo profilo gestito.</string>\n    <string name=\"vending_overview_enterprise_no_apps_available_wait\">Potrebbe essere necessario attendere alcune ore dopo la configurazione del profilo di lavoro prima che le app siano disponibili per il download.</string>\n    <string name=\"installer_notification_progress_commiting\">Installazione di \\\"%s\\\" in corso</string>\n    <string name=\"vending_overview_row_update_available\">Aggiornamento disponibile</string>\n    <string name=\"vending_overview_row_action_update\">Aggiorna</string>\n    <string name=\"installer_notification_progress_splitinstall_downloading\">Download dei componenti richiesti per %s in corso</string>\n    <string name=\"installer_notification_progress_splitinstall_click_install\">Tocca per installare i componenti richiesti da %s</string>\n    <string name=\"billing_permission_desc\">Consente all\\'utente di acquistare articoli tramite Google Play da questa app.</string>\n    <string name=\"billing_permission_label\">Servizio di fatturazione Google Play</string>\n    <string name=\"app_install_permission_allowed\">Consenti</string>\n    <string name=\"app_install_needs_permissions_title\">Installatore App</string>\n    <string name=\"app_install_allow_to_install_third_app\">Consenti a “microG Companion” di installare le app scaricate da “%1$s”</string>\n    <string name=\"app_install_refuse_permission_remind\">Se rifiuti, l’installazione dell’app fallirà.</string>\n    <string name=\"app_install_refuse_permission_remind_sub\">Puoi modificare l’autorizzazione in qualsiasi momento nelle Impostazioni di microG.</string>\n    <string name=\"app_install_not_remind_again\">Mantieni la scelta e non chiedere più</string>\n</resources>\n"
  },
  {
    "path": "vending-app/src/main/res/values-iw/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n</resources>"
  },
  {
    "path": "vending-app/src/main/res/values-ja/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"toast_installed\">microG Companion 単体では使用できません。 代わりに microG 設定を開きました。</string>\n    <string name=\"toast_not_installed\">microG Companion は単体では使用できません。microG を利用するには microG Services をインストールしてください。</string>\n    <string name=\"app_name\">microG Companion</string>\n    <string name=\"pay_disabled\">お支払いは現在使用できません</string>\n    <string name=\"confirm_purchase\">購入を確認</string>\n    <string name=\"error_network\">インターネットに接続できません。Wi-Fi またはモバイルネットワークが有効なことを確認し、もう一度お試しください。</string>\n    <string name=\"error_passwd\">入力したパスワードが間違っています。</string>\n    <string name=\"error_unknown\">不明なエラーです。終了してもう一度お試しください。</string>\n    <string name=\"tips_input_passwd\">パスワードを入力</string>\n    <string name=\"tips_remember_login_info\">ログイン情報を端末に記憶させる</string>\n    <string name=\"tips_forget_passwd\">パスワードを忘れましたか？</string>\n    <string name=\"tips_more_details\">詳細情報</string>\n    <string name=\"text_verify_button\">確認</string>\n    <string name=\"license_notification_title\">%1$s はライセンスを確認できませんでした</string>\n    <string name=\"license_notification_body\">アプリが正しく動作しない場合は、アプリを購入したときの Google アカウントにサインインしてください。</string>\n    <string name=\"license_notification_sign_in\">ログイン</string>\n    <string name=\"license_notification_ignore\">無視</string>\n    <string name=\"license_notification_channel_name\">ライセンス通知</string>\n    <string name=\"license_notification_channel_description\">Google アカウントにログインしていないときに、アプリがライセンスを確認しようとすると通知します。</string>\n    <string name=\"vending_overview_enterprise_row_mandatory\">インストールが必要です</string>\n    <string name=\"app_install_permission_allowed\">許可</string>\n    <string name=\"app_install_needs_permissions_title\">アプリインストーラー</string>\n    <string name=\"installer_notification_progress_commiting\">\\\"%s\\\" をインストール中</string>\n    <string name=\"installer_notification_progress_complete\">\\\"%s\\\" をインストールしました</string>\n    <string name=\"installer_notification_progress_failed\">\\\"%s\\\" のインストールに失敗しました</string>\n    <string name=\"installer_dependency_noun\">%s に必要なコンポーネント</string>\n    <string name=\"installer_notification_progress_splitinstall_downloading\">%s に必要なコンポーネントをダウンロード中</string>\n    <string name=\"installer_notification_progress_splitinstall_commiting\">%s に必要なコンポーネントをインストール中</string>\n    <string name=\"download_notification_attachment_file\">%s の追加ファイル</string>\n    <string name=\"download_notification_tips\">ダウンロード中</string>\n    <string name=\"installer_notification_progress_splitinstall_click_install\">%s に必要なコンポーネントをインストールするにはクリックしてください</string>\n    <string name=\"billing_permission_desc\">ユーザーは本アプリ内からGoogle Playを通じてアイテムを購入できます。</string>\n    <string name=\"billing_permission_label\">Google Play 課金サービス</string>\n    <string name=\"app_install_allow_to_install_third_app\">\\\"microG Companion\\\" が \\\"%1$s\\\" からダウンロードしたアプリをインストールすることを許可します</string>\n    <string name=\"app_install_refuse_permission_remind\">拒否した場合、アプリケーションのインストールは失敗します。</string>\n    <string name=\"app_install_refuse_permission_remind_sub\">microG サービス設定で、いつでも認証状態の権限を変更できます。</string>\n    <string name=\"app_install_not_remind_again\">この選択を維持し、再度確認しない</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_hint\">管理者は、これらのアプリを管理対象プロファイルにインストールすることを要求しています。</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_missing_hint\">管理者が選択した必須アプリがデバイスにインストールされていません。</string>\n    <string name=\"vending_overview_enterprise_row_offered\">利用可能なアプリ</string>\n    <string name=\"vending_overview_enterprise_row_offered_hint\">これらはすべて、企業で利用できるアプリです。</string>\n    <string name=\"vending_overview_enterprise_no_apps_available\">管理者により提供されたアプリケーションはありません。</string>\n    <string name=\"vending_overview_enterprise_no_apps_available_wait\">仕事用プロファイルの設定後、アプリがダウンロード可能になるまで数時間かかる場合があります。</string>\n    <string name=\"vending_overview_row_update_available\">アップデートが利用可能です</string>\n    <string name=\"vending_overview_row_installed\">インストール済みアプリ</string>\n    <string name=\"vending_overview_row_action_install\">インストール</string>\n    <string name=\"vending_overview_row_action_update\">アップデート</string>\n    <string name=\"vending_overview_row_action_uninstall\">アンインストール</string>\n    <string name=\"installer_notification_channel_name\">アプリおよびコンポーネントのインストール</string>\n    <string name=\"installer_notification_channel_description\">アプリとコンポーネントのインストール進捗状況、成功および失敗の通知を表示します。</string>\n    <string name=\"installer_notification_progress_downloading\">\\\"%s\\\" をダウンロード中</string>\n    <string name=\"vending_activity_name\">仕事向けアプリストア</string>\n    <string name=\"error_retry\">再試行</string>\n</resources>\n"
  },
  {
    "path": "vending-app/src/main/res/values-ko/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\">microG Companion</string>\n    <string name=\"toast_installed\">microG Companion은 독립적으로 사용될 수 없습니다. microG 서비스 설정을 대신 열었습니다.</string>\n    <string name=\"toast_not_installed\">microG Companion은 독립적으로 사용될 수 없습니다. microG를 사용하려면 microG 서비스를 설치해 주세요.</string>\n    <string name=\"license_notification_channel_name\">라이선스 알림</string>\n    <string name=\"license_notification_channel_description\">앱이 라이선스를 검증하려고 하지만 Google 계정에 로그인되어 있지 않으면 알립니다.</string>\n    <string name=\"license_notification_title\">%1$s가 라이선스를 확인하는데 실패했습니다</string>\n    <string name=\"license_notification_body\">앱이 잘못 작동하는 경우, 앱을 구매한 Google 계정에 로그인하세요.</string>\n    <string name=\"license_notification_sign_in\">로그인</string>\n    <string name=\"license_notification_ignore\">무시</string>\n    <string name=\"vending_activity_name\">작업 앱 스토어</string>\n    <string name=\"vending_overview_enterprise_row_mandatory\">설치 필요</string>\n    <string name=\"vending_overview_enterprise_row_offered\">사용 가능한 앱</string>\n    <string name=\"vending_overview_row_action_install\">설치</string>\n    <string name=\"vending_overview_row_action_update\">업데이트</string>\n    <string name=\"vending_overview_row_action_uninstall\">삭제</string>\n    <string name=\"error_retry\">재시도</string>\n    <string name=\"text_verify_button\">확인</string>\n    <string name=\"download_notification_tips\">다운로드 중</string>\n    <string name=\"vending_overview_row_update_available\">업데이트 사용 가능</string>\n    <string name=\"vending_overview_row_installed\">설치된 앱</string>\n    <string name=\"confirm_purchase\">구매 확인</string>\n    <string name=\"tips_more_details\">더 알아보기</string>\n    <string name=\"installer_notification_progress_downloading\">\\\"%s\\\" 다운로드 중</string>\n    <string name=\"installer_notification_progress_commiting\">\\\"%s\\\" 설치 중</string>\n    <string name=\"installer_notification_progress_complete\">\\\"%s\\\" 설치 완료</string>\n    <string name=\"tips_input_passwd\">비밀번호를 입력하세요</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_hint\">귀하의 관리자가 다음 앱을 관리된 프로필에 설치하도록 했습니다.</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_missing_hint\">이 기기에 관리자가 선택한 필수 앱이 없습니다.</string>\n    <string name=\"vending_overview_enterprise_row_offered_hint\">다음은 귀사에서 제공하는 모든 앱들입니다.</string>\n    <string name=\"vending_overview_enterprise_no_apps_available\">귀하의 관리자가 제공한 앱이 없습니다.</string>\n    <string name=\"vending_overview_enterprise_no_apps_available_wait\">작업 프로필을 설정한 후 앱을 다운로드할 준비가 되기까지 몇 시간이 걸릴 수 있습니다.</string>\n    <string name=\"pay_disabled\">현재 Pay 사용 불가</string>\n    <string name=\"error_network\">인터넷에 연결되지 않았습니다. Wi-Fi 또는 모바일 네트워크가 켜져 있는지 확인한 후 다시 시도해 주세요.</string>\n    <string name=\"error_passwd\">입력한 비밀번호가 잘못되었습니다.</string>\n    <string name=\"error_unknown\">알 수 없는 오류입니다. 종료하고 다시 시도해 주세요.</string>\n    <string name=\"tips_remember_login_info\">이 기기에서 로그인 정보 기억하기</string>\n    <string name=\"tips_forget_passwd\">비밀번호를 잊어버리셨나요?</string>\n    <string name=\"installer_notification_channel_name\">앱 및 구성 요소 설치</string>\n    <string name=\"installer_notification_channel_description\">앱 및 구성 요소 설치 진행 상황, 성공 및 실패 메시지를 표시합니다.</string>\n    <string name=\"installer_notification_progress_failed\">\\\"%s\\\" 설치 실패</string>\n    <string name=\"installer_dependency_noun\">%s에 필요한 구성 요소</string>\n    <string name=\"installer_notification_progress_splitinstall_downloading\">%s에 필요한 구성 요소 다운로드 중</string>\n    <string name=\"installer_notification_progress_splitinstall_commiting\">%s에 필요한 구성 요소 설치 중</string>\n    <string name=\"download_notification_attachment_file\">%s에 대한 추가 파일</string>\n    <string name=\"installer_notification_progress_splitinstall_click_install\">%s에 필요한 구성 요소를 설치하려면 클릭하세요</string>\n    <string name=\"billing_permission_desc\">사용자가 이 앱 내에서 Google Play를 통해 상품을 구매할 수 있도록 허용합니다.</string>\n    <string name=\"billing_permission_label\">Google Play 결제 서비스</string>\n    <string name=\"app_install_permission_allowed\">허용</string>\n    <string name=\"app_install_needs_permissions_title\">앱 설치</string>\n    <string name=\"app_install_allow_to_install_third_app\">\\\"microG Companion\\\"이 \\\"%1$s\\\"에서 다운로드한 앱을 설치하도록 허용</string>\n    <string name=\"app_install_refuse_permission_remind\">거부하면 애플리케이션 설치가 실패합니다.</string>\n    <string name=\"app_install_refuse_permission_remind_sub\">microG 서비스 설정에서 언제든지 권한 상태를 수정할 수 있습니다.</string>\n    <string name=\"app_install_not_remind_again\">이 설정을 유지하고 다시 묻지 않기</string>\n</resources>\n"
  },
  {
    "path": "vending-app/src/main/res/values-lv/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources></resources>"
  },
  {
    "path": "vending-app/src/main/res/values-lzh/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"toast_installed\">microG不可獨用，開啟時當引至microG服務設定界面。</string>\n    <string name=\"app_name\">MicroG假商店</string>\n</resources>"
  },
  {
    "path": "vending-app/src/main/res/values-ml/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"error_passwd\">നിങ്ങൾ ടൈപ്പ് ചെയ്ത പാസ്‌വേഡ് തെറ്റാണ്.</string>\n    <string name=\"error_unknown\">പ്രശ്നം വ്യക്തമല്ല. ദയവു ചെയ്ത് പുറകോട്ട് പോയിട്ട് ഒന്നുകൂടെ ശ്രമിക്കൂ.</string>\n    <string name=\"error_retry\">വീണ്ടും ശ്രമിക്കൂ</string>\n    <string name=\"tips_input_passwd\">പാസ്‌വേഡ് ടൈപ്പ് ചെയ്യൂ</string>\n    <string name=\"app_name\">മൈക്രോജി കമ്പാനിയൻ</string>\n    <string name=\"toast_installed\">മൈക്രോജി കമ്പാനിയൻ ഒറ്റയ്ക്ക് ഉപയോഗിക്കാൻ കഴിയില്ല. പകരം മൈക്രോജി സേവന ക്രമീകരണങ്ങൾ തുറന്നു.</string>\n    <string name=\"toast_not_installed\">മൈക്രോജി കമ്പാനിയൻ ഒറ്റയ്ക്ക് ഉപയോഗിക്കാൻ കഴിയില്ല. മൈക്രോജി ഉപയോഗിക്കാൻ മൈക്രോജി സേവനങ്ങൾ ഇൻസ്റ്റാൾ ചെയ്യുക.</string>\n    <string name=\"license_notification_channel_name\">ലൈസൻസ് അറിയിപ്പുകൾ</string>\n    <string name=\"license_notification_channel_description\">ഒരു ആപ്പ് അതിന്റെ ലൈസൻസ് സാധൂകരിക്കാൻ ശ്രമിക്കുമ്പോൾ, എന്നാൽ നിങ്ങൾ ഒരു ഗൂഗിൾ അക്കൗണ്ടിലേക്കും സൈൻ ഇൻ ചെയ്തിട്ടില്ലെങ്കിൽ അറിയിക്കുന്നു.</string>\n    <string name=\"license_notification_title\">%1$s-ന് ലൈസൻസ് പരിശോധിക്കാൻ കഴിഞ്ഞില്ല</string>\n    <string name=\"license_notification_body\">ആപ്പ് മോശമായി പ്രവർത്തിക്കുകയാണെങ്കിൽ, നിങ്ങൾ ആപ്പ് വാങ്ങിയ ഗൂഗിൾ അക്കൗണ്ടിലേക്ക് സൈൻ ഇൻ ചെയ്യുക.</string>\n    <string name=\"license_notification_sign_in\">സൈൻ ഇൻ</string>\n    <string name=\"license_notification_ignore\">അവഗണിക്കുക</string>\n</resources>\n"
  },
  {
    "path": "vending-app/src/main/res/values-nb-rNO/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\">microG-følgeapp</string>\n    <string name=\"toast_installed\">microG-følgeappen kan ikke brukes alene. Åpnet microG-tjenesteinnstillinger istedenfor.</string>\n    <string name=\"toast_not_installed\">microG-følgeappen kan ikke brukes alene. Installer microG-tjenestene for å bruke microG.</string>\n    <string name=\"license_notification_channel_name\">Lisensvarsler</string>\n    <string name=\"license_notification_channel_description\">Varsler når appen prøver å validere lisensen sin, men du ikke er logget inn med en Google-konto.</string>\n    <string name=\"license_notification_title\">%1$s kunne ikke bekrefte lisensen sin</string>\n    <string name=\"license_notification_body\">Hvis en app ikke oppfører seg riktig, logg inn til en Google-konto som du har kjøpt appen med.</string>\n    <string name=\"license_notification_sign_in\">Logg inn</string>\n    <string name=\"license_notification_ignore\">Ignorer</string>\n    <string name=\"vending_activity_name\">Appbutikk til arbeid</string>\n    <string name=\"vending_overview_enterprise_row_mandatory\">Må installeres</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_hint\">Administratoren din krever at disse appene må installeres til den administrerte profilen din.</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_missing_hint\">Enheten din mangler påkrevete apper utvalgt av administratoren din.</string>\n    <string name=\"vending_overview_enterprise_row_offered\">Tilgjengelige apper</string>\n    <string name=\"vending_overview_enterprise_row_offered_hint\">Dette er alle appene som er gjort tilgjengelig av jobben din.</string>\n    <string name=\"vending_overview_enterprise_no_apps_available\">Ingen apper er tilgjengelige fra administratoren din.</string>\n    <string name=\"vending_overview_enterprise_no_apps_available_wait\">Det kan ta noen timer etter at du har satt opp jobbprofilen din før apper bli klare til å laste ned.</string>\n    <string name=\"vending_overview_row_update_available\">Oppdatering tilgjengelig</string>\n    <string name=\"vending_overview_row_installed\">Installerte apper</string>\n    <string name=\"vending_overview_row_action_install\">Installer</string>\n    <string name=\"vending_overview_row_action_update\">Oppdater</string>\n    <string name=\"vending_overview_row_action_uninstall\">Avinstaller</string>\n    <string name=\"pay_disabled\">Betaling er for øyeblikket ikke mulig</string>\n    <string name=\"confirm_purchase\">Bekreft kjøp</string>\n    <string name=\"error_network\">Ikke koblet til internett. Sjekk at Wi-Fi eller mobilt internett er skrudd på og prøv igjen.</string>\n    <string name=\"error_passwd\">Passordet du oppga er feil.</string>\n    <string name=\"error_unknown\">Ukjent feil, avslutt og prøv igjen.</string>\n    <string name=\"error_retry\">Prøv igjen</string>\n    <string name=\"tips_input_passwd\">Oppgi passordet ditt</string>\n    <string name=\"tips_remember_login_info\">Hold meg innlogget på denne enheten</string>\n    <string name=\"tips_forget_passwd\">Glemt passordet ditt?</string>\n    <string name=\"tips_more_details\">Les mer</string>\n    <string name=\"text_verify_button\">Bekreft</string>\n    <string name=\"installer_notification_channel_name\">App- og komponentinstallasjon</string>\n    <string name=\"installer_notification_channel_description\">Viser hvor langt installasjonen av appen og komponentene har kommet, med fremgangs- og feilmeldinger.</string>\n    <string name=\"installer_notification_progress_downloading\">Laster ned «%s»</string>\n    <string name=\"installer_notification_progress_commiting\">Installerer «%s»</string>\n    <string name=\"installer_notification_progress_complete\">Installerte «%s»</string>\n    <string name=\"installer_notification_progress_failed\">Kunne ikke installere «%s»</string>\n    <string name=\"installer_dependency_noun\">Nødvendige komponenter til %s</string>\n    <string name=\"installer_notification_progress_splitinstall_downloading\">Laster ned nødvendige komponenter til %s</string>\n    <string name=\"installer_notification_progress_splitinstall_commiting\">Installerer nødvendige komponenter til %s</string>\n    <string name=\"download_notification_attachment_file\">Tilleggsfiler til %s</string>\n    <string name=\"download_notification_tips\">Laster ned</string>\n    <string name=\"installer_notification_progress_splitinstall_click_install\">Klikk for å installere komponentene som er nødvendige for %s</string>\n    <string name=\"billing_permission_desc\">Lar brukeren kjøpe ting gjennom Google Play fra inne i denne appen.</string>\n    <string name=\"billing_permission_label\">Google Play-faktureringstjeneste</string>\n    <string name=\"app_install_permission_allowed\">Tillat</string>\n    <string name=\"app_install_needs_permissions_title\">Appinstallerer</string>\n    <string name=\"app_install_allow_to_install_third_app\">La «microG-følgeapp» installere apper lastet ned fra «%1$s»</string>\n    <string name=\"app_install_refuse_permission_remind\">Om du nekter kommer installasjonen til å mislykkes.</string>\n    <string name=\"app_install_refuse_permission_remind_sub\">Du kan modifisere autoriseringsstatusen når som helst i microGs serviceinnstillinger.</string>\n    <string name=\"app_install_not_remind_again\">Behold dette valget og ikke spør igjen</string>\n</resources>\n"
  },
  {
    "path": "vending-app/src/main/res/values-nl/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"vending_overview_enterprise_row_mandatory_missing_hint\">Op uw apparaat ontbreken verplichte apps die door uw beheerder zijn geselecteerd.</string>\n    <string name=\"tips_remember_login_info\">Onthoud mijn inloggegevens op dit apparaat</string>\n</resources>\n"
  },
  {
    "path": "vending-app/src/main/res/values-pl/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"toast_installed\">Nie można używać microG Companion niezależnie. Zamiast tego otwarto ustawienia usług microG.</string>\n    <string name=\"toast_not_installed\">Nie można używać microG Companion niezależnie. Zainstaluj usługi microG, aby korzystać z microG.</string>\n    <string name=\"app_name\">microG Companion</string>\n    <string name=\"pay_disabled\">Płatność nie jest obecnie możliwa</string>\n    <string name=\"error_passwd\">Wprowadzone hasło jest nieprawidłowe.</string>\n    <string name=\"error_unknown\">Nieznany błąd, wyjdź i spróbuj ponownie.</string>\n    <string name=\"tips_remember_login_info\">Zapamiętaj moje dane do logowania na tym urządzeniu</string>\n    <string name=\"tips_forget_passwd\">Nie pamiętasz hasła?</string>\n    <string name=\"text_verify_button\">Zweryfikuj</string>\n    <string name=\"tips_input_passwd\">Wprowadź hasło</string>\n    <string name=\"license_notification_ignore\">Ignoruj</string>\n    <string name=\"tips_more_details\">Dowiedz się więcej</string>\n    <string name=\"confirm_purchase\">Potwierdź zakup</string>\n    <string name=\"error_network\">Brak połączenia z internetem. Upewnij się, że sieć Wi-Fi lub komórkowa jest włączona i spróbuj ponownie.</string>\n    <string name=\"license_notification_channel_name\">Powiadomienia dotyczące licencji</string>\n    <string name=\"license_notification_channel_description\">Powiadamia, gdy aplikacja próbuje zweryfikować swoją licencję, ale użytkownik nie jest zalogowany do żadnego konta Google.</string>\n    <string name=\"license_notification_title\">%1$s nie może zweryfikować licencji</string>\n    <string name=\"license_notification_body\">Jeśli aplikacja działa nieprawidłowo, zaloguj się na konto Google, za pomocą którego aplikacja została zakupiona.</string>\n    <string name=\"license_notification_sign_in\">Zaloguj się</string>\n    <string name=\"download_notification_attachment_file\">Dodatkowe pliki dla %s</string>\n    <string name=\"download_notification_tips\">Pobieranie</string>\n    <string name=\"vending_overview_enterprise_row_offered\">Dostępne aplikacje</string>\n    <string name=\"vending_overview_row_update_available\">Dostępna aktualizacja</string>\n    <string name=\"vending_overview_row_action_update\">Zaktualizuj</string>\n    <string name=\"installer_notification_channel_description\">Pokazuje postęp instalacji aplikacji i komponentów, komunikaty o powodzeniu i niepowodzeniu.</string>\n    <string name=\"installer_dependency_noun\">Wymagane składniki dla %s</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_missing_hint\">Na urządzeniu brakuje obowiązkowych aplikacji wybranych przez administratora.</string>\n    <string name=\"vending_overview_row_installed\">Zainstalowane aplikacje</string>\n    <string name=\"error_retry\">Ponów</string>\n    <string name=\"vending_overview_row_action_install\">Zainstaluj</string>\n    <string name=\"vending_overview_enterprise_no_apps_available_wait\">Po skonfigurowaniu profilu służbowego może minąć kilka godzin, zanim aplikacje będą gotowe do pobrania.</string>\n    <string name=\"vending_overview_enterprise_row_offered_hint\">Są to wszystkie aplikacje udostępnione przez twoją firmę.</string>\n    <string name=\"installer_notification_progress_complete\">Zainstalowano \\\"%s\\\"</string>\n    <string name=\"vending_activity_name\">Sklep z aplikacjami służbowymi</string>\n    <string name=\"vending_overview_enterprise_row_mandatory\">Wymagana instalacja</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_hint\">Administrator wymaga zainstalowania tych aplikacji w profilu zarządzanym.</string>\n    <string name=\"vending_overview_enterprise_no_apps_available\">Administrator nie udostępnił żadnych aplikacji.</string>\n    <string name=\"installer_notification_progress_splitinstall_downloading\">Pobieranie wymaganych składników dla %s</string>\n    <string name=\"vending_overview_row_action_uninstall\">Odinstaluj</string>\n    <string name=\"installer_notification_channel_name\">Instalacja aplikacji i komponentów</string>\n    <string name=\"installer_notification_progress_downloading\">Pobieranie \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_commiting\">Instalowanie \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_splitinstall_commiting\">Instalowanie wymaganych składników dla %s</string>\n    <string name=\"installer_notification_progress_failed\">Błąd podczas instalacji \\\"%s\\\"</string>\n    <string name=\"billing_permission_desc\">Umożliwia użytkownikowi zakup przedmiotów za pośrednictwem Google Play z poziomu tej aplikacji.</string>\n    <string name=\"billing_permission_label\">Usługa rozliczeniowa Google Play</string>\n    <string name=\"installer_notification_progress_splitinstall_click_install\">Dotknij aby zainstalować komponenty wymagane przez %s</string>\n    <string name=\"app_install_permission_allowed\">Zezwól</string>\n    <string name=\"app_install_needs_permissions_title\">Instalator aplikacji</string>\n    <string name=\"app_install_allow_to_install_third_app\">Zezwalaj aplikacji „microG Companion” na instalowanie aplikacji pobranych z „%1$s”</string>\n    <string name=\"app_install_refuse_permission_remind\">Jeśli odmówisz, instalacja aplikacji nie powiedzie się.</string>\n    <string name=\"app_install_refuse_permission_remind_sub\">W dowolnym momencie można zmodyfikować uprawnienia statusu autoryzacji w ustawieniach usługi microG.</string>\n    <string name=\"app_install_not_remind_again\">Zachowaj ten wybór i nie pytaj ponownie</string>\n</resources>\n"
  },
  {
    "path": "vending-app/src/main/res/values-pt/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\">Acompanhante do microG</string>\n    <string name=\"toast_installed\">O acompanhante do microG não pode ser utilizado sozinho. Abrindo as configurações dos Serviços microG.</string>\n    <string name=\"toast_not_installed\">O acompanhante do microG não pode ser utilizado sozinho. Instale os Serviços microG para utilizar o microG.</string>\n    <string name=\"license_notification_channel_name\">Notificações de licença</string>\n    <string name=\"license_notification_channel_description\">Notifica quando uma app tenta validar a sua licença, mas não está conectado a uma conta do Google.</string>\n    <string name=\"license_notification_title\">%1$s não conseguiu verificar a sua licença</string>\n    <string name=\"license_notification_body\">Se uma app não funcionar bem, conecte-se a uma conta do Google com qual comprou a app.</string>\n    <string name=\"license_notification_sign_in\">Conectar-se</string>\n    <string name=\"license_notification_ignore\">Ignorar</string>\n    <string name=\"vending_activity_name\">Loja de apps de trabalho</string>\n    <string name=\"vending_overview_enterprise_row_mandatory\">Instalação necessária</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_hint\">O seu administrador requer que estas apps sejam instaladas no seu perfil gerido.</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_missing_hint\">O seu dispositivo não contém todas as apps obrigatórias escolhidos pelo seu administrador.</string>\n    <string name=\"vending_overview_enterprise_row_offered\">Apps disponíveis</string>\n    <string name=\"vending_overview_enterprise_row_offered_hint\">Estas são todas as apps disponibilizados pela sua empresa.</string>\n    <string name=\"vending_overview_enterprise_no_apps_available\">Nenhuma app foi disponibilizada pelo seu administrador.</string>\n    <string name=\"vending_overview_enterprise_no_apps_available_wait\">Pode demorar algumas horas após a configuração do seu perfil de trabalho para que as apps estejam prontas a serem descarregados.</string>\n    <string name=\"vending_overview_row_update_available\">Atualização disponível</string>\n    <string name=\"vending_overview_row_installed\">Apps instalados</string>\n    <string name=\"vending_overview_row_action_install\">Instalar</string>\n    <string name=\"vending_overview_row_action_update\">Atualizar</string>\n    <string name=\"vending_overview_row_action_uninstall\">Desinstalar</string>\n    <string name=\"pay_disabled\">Pagamentos não são possíveis no momento</string>\n    <string name=\"confirm_purchase\">Confirmar compra</string>\n    <string name=\"error_network\">Não conectado à internet. Tenha certeza que o Wi-Fi ou os dados móveis estão ativados e tente novamente.</string>\n    <string name=\"error_passwd\">A palavra-passe que digitou está incorreta.</string>\n    <string name=\"error_unknown\">Erro desconhecido, por favor, saia e tente novamente.</string>\n    <string name=\"error_retry\">Tentar novamente</string>\n    <string name=\"tips_input_passwd\">Digite a sua palavra-passe</string>\n    <string name=\"tips_remember_login_info\">Lembrar da minha conta neste dispositivo</string>\n    <string name=\"tips_forget_passwd\">Esqueceu-se da palavra-passe?</string>\n    <string name=\"tips_more_details\">Saber mais</string>\n    <string name=\"text_verify_button\">Verificar</string>\n    <string name=\"installer_notification_channel_name\">Instalação de apps e componentes</string>\n    <string name=\"installer_notification_channel_description\">Mostra mensagens do progresso de instalação de apps e componentes.</string>\n    <string name=\"installer_notification_progress_downloading\">A descarregar \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_commiting\">A instalar \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_complete\">\\\"%s\\\" foi instalado</string>\n    <string name=\"installer_notification_progress_failed\">Falha ao instalar \\\"%s\\\"</string>\n    <string name=\"installer_dependency_noun\">Componentes necessários para %s</string>\n    <string name=\"installer_notification_progress_splitinstall_downloading\">A descarregar componentes necessários para %s</string>\n    <string name=\"installer_notification_progress_splitinstall_commiting\">A instalar os componentes necessários para %s</string>\n    <string name=\"download_notification_attachment_file\">Ficheiros adicionais para %s</string>\n    <string name=\"download_notification_tips\">A descarregar</string>\n    <string name=\"installer_notification_progress_splitinstall_click_install\">Click para instalar os componentes necessários para %s</string>\n    <string name=\"billing_permission_desc\">Permite que o utilizador compre elementos pelo Google Play nesta app.</string>\n    <string name=\"billing_permission_label\">Serviço de cobrança do Google Play</string>\n</resources>\n"
  },
  {
    "path": "vending-app/src/main/res/values-pt-rBR/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_notification_channel_name\">Notificações de licença</string>\n    <string name=\"license_notification_channel_description\">Notifica quando um app tenta validar sua licença, mas você não está conectado à uma conta do Google.</string>\n    <string name=\"license_notification_title\">%1$s não conseguiu verificar sua licença</string>\n    <string name=\"license_notification_body\">Se um app não estiver funcionando direito, conecte-se à uma conta do Google em qual você comprou o app.</string>\n    <string name=\"license_notification_sign_in\">Conectar-se</string>\n    <string name=\"license_notification_ignore\">Ignorar</string>\n    <string name=\"app_name\">Acompanhante do microG</string>\n    <string name=\"toast_installed\">O acompanhante do microG não pode ser utilizado sozinho. Abrindo as configurações dos Serviços microG.</string>\n    <string name=\"toast_not_installed\">O acompanhante do microG não pode ser utilizado sozinho. Instale os Serviços microG para utilizar o microG.</string>\n    <string name=\"pay_disabled\">Pagamentos não são possíveis no momento</string>\n    <string name=\"error_passwd\">A senha que você digitou está incorreta.</string>\n    <string name=\"tips_input_passwd\">Digite sua senha</string>\n    <string name=\"text_verify_button\">Verificar</string>\n    <string name=\"confirm_purchase\">Confirmar compra</string>\n    <string name=\"error_network\">Não conectado à internet. Tenha certeza que o Wi-Fi ou os dados móveis estão ativados e tente novamente.</string>\n    <string name=\"error_unknown\">Erro desconhecido, por favor, saia e tente novamente.</string>\n    <string name=\"tips_remember_login_info\">Lembrar da minha conta neste dispositivo</string>\n    <string name=\"tips_forget_passwd\">Esqueceu a senha?</string>\n    <string name=\"tips_more_details\">Saber mais</string>\n    <string name=\"download_notification_tips\">Baixando</string>\n    <string name=\"download_notification_attachment_file\">Arquivos adicionais para %s</string>\n    <string name=\"vending_overview_enterprise_row_offered_hint\">Esses são todos os apps disponibilizados pela sua empresa.</string>\n    <string name=\"vending_overview_enterprise_no_apps_available_wait\">Pode demorar algumas horas após a configuração do seu perfil de trabalho para que os apps estejam prontos para serem baixados.</string>\n    <string name=\"vending_overview_row_installed\">Apps instalados</string>\n    <string name=\"vending_overview_row_action_update\">Atualizar</string>\n    <string name=\"error_retry\">Tentar novamente</string>\n    <string name=\"installer_notification_channel_description\">Mostra mensagens do progresso de instalação de apps e componentes.</string>\n    <string name=\"installer_notification_progress_downloading\">Baixando \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_commiting\">Instalando \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_complete\">\\\"%s\\\" foi instalado</string>\n    <string name=\"installer_dependency_noun\">Componentes necessários para %s</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_missing_hint\">Seu dispositivo não contém todos os apps obrigatórios escolhidos pelo seu administrador.</string>\n    <string name=\"vending_overview_enterprise_row_offered\">Apps disponíveis</string>\n    <string name=\"vending_overview_enterprise_no_apps_available\">Nenhum app foi disponibilizado pelo seu administrador.</string>\n    <string name=\"vending_activity_name\">Loja de apps de trabalho</string>\n    <string name=\"vending_overview_enterprise_row_mandatory\">Instalação necessária</string>\n    <string name=\"vending_overview_row_update_available\">Atualização disponível</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_hint\">Seu administrador requer que esses apps sejam instalados no seu perfil gerenciado.</string>\n    <string name=\"vending_overview_row_action_install\">Instalar</string>\n    <string name=\"vending_overview_row_action_uninstall\">Desinstalar</string>\n    <string name=\"installer_notification_channel_name\">Instalação de apps e componentes</string>\n    <string name=\"installer_notification_progress_splitinstall_commiting\">Instalando os componentes necessários para %s</string>\n    <string name=\"installer_notification_progress_failed\">Falha ao instalar \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_splitinstall_downloading\">Baixando os componentes necessários para %s</string>\n    <string name=\"billing_permission_desc\">Permite que o usuário compre itens pelo Google Play dentro deste app.</string>\n    <string name=\"billing_permission_label\">Serviço de cobrança do Google Play</string>\n    <string name=\"installer_notification_progress_splitinstall_click_install\">Click para instalar os componentes necessários para %s</string>\n    <string name=\"app_install_permission_allowed\">Permitir</string>\n    <string name=\"app_install_needs_permissions_title\">Instalador de apps</string>\n    <string name=\"app_install_allow_to_install_third_app\">Permitir que o \\\"Acompanhante do microG\\\" instale apps baixados por \\\"%1$s\\\"</string>\n    <string name=\"app_install_refuse_permission_remind\">Se você negar, a instalação do aplicativo falhará.</string>\n    <string name=\"app_install_refuse_permission_remind_sub\">Você pode modificar o estado de autorização a qualquer momento nas Configurações do microG.</string>\n    <string name=\"app_install_not_remind_again\">Manter esta seleção e não perguntar novamente</string>\n</resources>\n"
  },
  {
    "path": "vending-app/src/main/res/values-ro/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"toast_installed\">Companionul microG nu poate fi utilizat independent. În schimb, deschide setările microG Services.</string>\n    <string name=\"toast_not_installed\">Companionul microG nu poate fi utilizat independent. Instalează serviciile microG pentru a utiliza microG.</string>\n    <string name=\"app_name\">Companion microG</string>\n    <string name=\"license_notification_channel_description\">Notifică când o aplicație încearcă să-și valideze licența, dar nu ești conectat la niciun cont Google.</string>\n    <string name=\"license_notification_channel_name\">Notificări de licență</string>\n    <string name=\"license_notification_title\">%1$s nu poate verifica licența</string>\n    <string name=\"license_notification_body\">Dacă aplicația se comportă greșit, conectează-te la un Cont Google cu care ai cumpărat aplicația.</string>\n    <string name=\"license_notification_sign_in\">Conectează-te</string>\n    <string name=\"license_notification_ignore\">Ignoră</string>\n    <string name=\"pay_disabled\">Funcția de plată nu este disponibilă</string>\n    <string name=\"error_passwd\">Parola pe care a-i introdus-o este incorectă.</string>\n    <string name=\"error_unknown\">Eroare necunoscută, ieși și încearcă din nou.</string>\n    <string name=\"tips_input_passwd\">Introdu parola</string>\n    <string name=\"tips_forget_passwd\">Parolă uitată?</string>\n    <string name=\"confirm_purchase\">Confirmă achiziția</string>\n    <string name=\"error_network\">Nu este conectat la internet. Asigură-te că rețeaua Wi-Fi sau mobilă este activată și încearcă din nou.</string>\n    <string name=\"tips_remember_login_info\">Memorizează autentificarea mea pe acest dispozitiv</string>\n    <string name=\"tips_more_details\">Află mai multe</string>\n    <string name=\"text_verify_button\">Verifică</string>\n    <string name=\"download_notification_tips\">Se descarcă</string>\n    <string name=\"download_notification_attachment_file\">Fișiere suplimentare pentru %s</string>\n    <string name=\"vending_activity_name\">Magazin aplicații de serviciu</string>\n    <string name=\"vending_overview_enterprise_row_mandatory\">Instalare necesară</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_hint\">Administratorul solicită instalarea acestor aplicații în profilul gestionat.</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_missing_hint\">Dispozitivului în lipsesc aplicații obligatorii alese de administrator.</string>\n    <string name=\"vending_overview_enterprise_row_offered\">Aplicații disponibile</string>\n    <string name=\"vending_overview_enterprise_row_offered_hint\">Acestea sunt toate aplicațiile puse la dispoziție de întreprinderea ta.</string>\n    <string name=\"vending_overview_enterprise_no_apps_available\">Nu au fost puse la dispoziție aplicații de către administrator.</string>\n    <string name=\"vending_overview_enterprise_no_apps_available_wait\">Poate dura câteva ore după configurarea profilului de lucru înainte ca aplicațiile să fie gata de descărcare.</string>\n    <string name=\"vending_overview_row_update_available\">Actualizare disponibilă</string>\n    <string name=\"vending_overview_row_installed\">Aplicații instalate</string>\n    <string name=\"vending_overview_row_action_install\">Instalează</string>\n    <string name=\"vending_overview_row_action_update\">Actualizează</string>\n    <string name=\"vending_overview_row_action_uninstall\">Dezinstalează</string>\n    <string name=\"error_retry\">Reîncearcă</string>\n    <string name=\"installer_notification_channel_name\">Instalarea aplicațiilor și a componentelor</string>\n    <string name=\"installer_notification_channel_description\">Afișează procesul de instalare a aplicațiilor și a componentelor, mesajele de succes și eșec.</string>\n    <string name=\"installer_notification_progress_downloading\">Se descarcă ”%s”</string>\n    <string name=\"installer_notification_progress_commiting\">Se instalează \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_complete\">S-a instalat \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_failed\">Nu a reușit instalarea \\\"%s\\\"</string>\n    <string name=\"installer_dependency_noun\">Componente necesare pentru %s</string>\n    <string name=\"installer_notification_progress_splitinstall_downloading\">Descărcarea componentelor necesare pentru %s</string>\n    <string name=\"installer_notification_progress_splitinstall_commiting\">Instalarea componentelor necesare pentru %s</string>\n    <string name=\"billing_permission_desc\">Permite utilizatorului să cumpere articole prin Google Play din această aplicație.</string>\n    <string name=\"billing_permission_label\">Serviciul de facturare Google Play</string>\n    <string name=\"installer_notification_progress_splitinstall_click_install\">Clic pentru a instala componentele cerute de %s</string>\n    <string name=\"app_install_permission_allowed\">Permite</string>\n    <string name=\"app_install_needs_permissions_title\">Instalator de aplicații</string>\n    <string name=\"app_install_allow_to_install_third_app\">Permite ca „microG Companion” să instaleze aplicații descărcate de la „%1$s”</string>\n    <string name=\"app_install_refuse_permission_remind\">Dacă refuzi, instalarea aplicației va eșua.</string>\n    <string name=\"app_install_refuse_permission_remind_sub\">Poți modifica oricând permisiunile privind starea autorizației în Setările serviciului microG.</string>\n    <string name=\"app_install_not_remind_again\">Memorizează această opțiune și nu mai întreba</string>\n</resources>\n"
  },
  {
    "path": "vending-app/src/main/res/values-ru/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_notification_channel_name\">Уведомления лицензий</string>\n    <string name=\"license_notification_channel_description\">Уведомляет, когда приложение пытается проверить свою лицензию, но вы не вошли ни в одну учетную запись Google.</string>\n    <string name=\"license_notification_title\">%1$s не может проверить лицензию</string>\n    <string name=\"license_notification_body\">Если приложение работает неправильно, войдите в учетную запись Google, с помощью которой вы купили приложение.</string>\n    <string name=\"license_notification_sign_in\">Войти</string>\n    <string name=\"license_notification_ignore\">Игнорировать</string>\n    <string name=\"app_name\">Компаньон microG</string>\n    <string name=\"toast_installed\">Компаньон microG не может использоваться отдельно. Открываются настройки сервисов microG.</string>\n    <string name=\"toast_not_installed\">Компаньон microG не может использоваться отдельно. Пожалуйста, установите сервисы microG чтобы использовать microG.</string>\n    <string name=\"pay_disabled\">Функция оплаты недоступна</string>\n    <string name=\"error_unknown\">Неизвестная ошибка. Выйдите и повторите попытку.</string>\n    <string name=\"tips_more_details\">Подробнее</string>\n    <string name=\"error_network\">Отсутствует подключение к Интернету. Убедитесь, что Wi-Fi или передача данных включены, и повторите попытку.</string>\n    <string name=\"error_passwd\">Введенный вами пароль неверен.</string>\n    <string name=\"tips_input_passwd\">Введите пароль</string>\n    <string name=\"tips_remember_login_info\">Запомнить авторизацию на этом устройстве</string>\n    <string name=\"tips_forget_passwd\">Забыли пароль?</string>\n    <string name=\"text_verify_button\">Подтвердить</string>\n    <string name=\"confirm_purchase\">Подтверждение покупки</string>\n    <string name=\"download_notification_tips\">Скачивание</string>\n    <string name=\"download_notification_attachment_file\">Дополнительные файлы для %s</string>\n    <string name=\"vending_overview_enterprise_row_mandatory\">Требуется установка</string>\n    <string name=\"vending_overview_enterprise_row_offered\">Доступные приложения</string>\n    <string name=\"vending_overview_row_update_available\">Доступно обновление</string>\n    <string name=\"vending_overview_row_installed\">Установленные приложения</string>\n    <string name=\"vending_overview_row_action_install\">Установить</string>\n    <string name=\"vending_overview_row_action_uninstall\">Удалить</string>\n    <string name=\"error_retry\">Повторить</string>\n    <string name=\"installer_notification_channel_name\">Установка приложения и компонента</string>\n    <string name=\"installer_notification_progress_downloading\">Скачивание \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_commiting\">Установка \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_complete\">Установлено \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_failed\">Не удалось установить \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_splitinstall_commiting\">Установка необходимых компонентов для %s</string>\n    <string name=\"installer_dependency_noun\">Необходимые компоненты для %s</string>\n    <string name=\"vending_overview_row_action_update\">Обновить</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_missing_hint\">На вашем устройстве отсутствуют обязательные приложения, выбранные вашим администратором.</string>\n    <string name=\"installer_notification_channel_description\">Показывает ход установки приложения и компонента, сообщения об успехах и неудачах.</string>\n    <string name=\"installer_notification_progress_splitinstall_downloading\">Скачивание необходимых компонентов для %s</string>\n    <string name=\"vending_activity_name\">Магазин приложений для работы</string>\n    <string name=\"vending_overview_enterprise_no_apps_available\">Ваш администратор не предоставил ни одного приложения.</string>\n    <string name=\"vending_overview_enterprise_row_offered_hint\">Это все приложения, которые стали доступны вашей организацией.</string>\n    <string name=\"vending_overview_enterprise_no_apps_available_wait\">После настройки рабочего профиля может пройти несколько часов, прежде чем приложения будут готовы к загрузке.</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_hint\">Ваш администратор требует установку этих приложений в управляемом профиле.</string>\n    <string name=\"billing_permission_desc\">Позволяет пользователю покупать через Google Play из этого приложения.</string>\n    <string name=\"billing_permission_label\">Платёжный сервис Google Play</string>\n    <string name=\"installer_notification_progress_splitinstall_click_install\">Нажмите, чтобы установить компоненты, необходимые %s</string>\n    <string name=\"app_install_permission_allowed\">Разрешить</string>\n    <string name=\"app_install_needs_permissions_title\">Установщик приложений</string>\n    <string name=\"app_install_allow_to_install_third_app\">Разрешить \\\"microG Companion\\\" устанавливать приложения скачанные с \\\"%1$s\\\"</string>\n    <string name=\"app_install_refuse_permission_remind\">Если вы отклоните, установка приложения не удастся.</string>\n    <string name=\"app_install_refuse_permission_remind_sub\">Вы можете изменить состояние разрешений авторизации в любое время в настройках microG Service.</string>\n    <string name=\"app_install_not_remind_again\">Запомнить выбор и больше не спрашивать</string>\n</resources>\n"
  },
  {
    "path": "vending-app/src/main/res/values-sl/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n</resources>"
  },
  {
    "path": "vending-app/src/main/res/values-sr/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"toast_installed\">microG пратилац се не може користити самостално. Уместо тога, отворена су подешавања microG услуга.</string>\n    <string name=\"toast_not_installed\">microG пратилац се не може користити самостално. Инсталирајте microG услуге да бисте користили microG.</string>\n    <string name=\"app_name\">microG пратилац</string>\n    <string name=\"pay_disabled\">Плаћање тренутно није могуће</string>\n    <string name=\"license_notification_channel_name\">Обавештења о лиценци</string>\n    <string name=\"license_notification_title\">%1$s није могао да потврди лиценцу</string>\n    <string name=\"license_notification_body\">Ако апликација не ради лоше, пријавите се на Google налог са којим сте купили апликацију.</string>\n    <string name=\"license_notification_channel_description\">Обавештава када апликација покуша да потврди своју лиценцу, али нисте пријављени ни на један Google налог.</string>\n    <string name=\"license_notification_ignore\">Занемари</string>\n    <string name=\"license_notification_sign_in\">Пријави се</string>\n    <string name=\"confirm_purchase\">Потврди куповину</string>\n    <string name=\"tips_forget_passwd\">Заборављена лозинка?</string>\n    <string name=\"tips_more_details\">Сазнај више</string>\n    <string name=\"tips_input_passwd\">Унесите своју лозинку</string>\n    <string name=\"error_network\">Није повезан на интернет. Уверите се да је Wi-Fi или мобилна мрежа укључена и покушајте поново.</string>\n    <string name=\"text_verify_button\">Верификуј</string>\n    <string name=\"error_passwd\">Лозинка коју сте унели је нетачна.</string>\n    <string name=\"tips_remember_login_info\">Запамти моју пријаву на овом уређају</string>\n    <string name=\"error_unknown\">Непозната грешка, изађите и покушајте поново.</string>\n    <string name=\"download_notification_attachment_file\">Додатни фајлови за %s</string>\n    <string name=\"download_notification_tips\">Преузимање</string>\n    <string name=\"vending_activity_name\">Радна продавница апликација</string>\n    <string name=\"vending_overview_enterprise_row_mandatory\">Потребна инсталација</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_hint\">Ваш администратор захтева да ове апликације буду инсталиране на вашем управљаном профилу.</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_missing_hint\">На уређају недостају обавезне апликације које је изабрао администратор.</string>\n    <string name=\"vending_overview_enterprise_row_offered\">Доступне апликације</string>\n    <string name=\"vending_overview_enterprise_no_apps_available\">Администратор није учинио доступном ниједну апликацију.</string>\n    <string name=\"vending_overview_row_update_available\">Доступно ажурирање</string>\n    <string name=\"vending_overview_row_installed\">Инсталиране апликације</string>\n    <string name=\"vending_overview_row_action_install\">Инсталирај</string>\n    <string name=\"vending_overview_row_action_update\">Ажурирај</string>\n    <string name=\"vending_overview_row_action_uninstall\">Деинсталирај</string>\n    <string name=\"error_retry\">Покушај поново</string>\n    <string name=\"installer_notification_channel_name\">Инсталација апликација и компоненти</string>\n    <string name=\"installer_notification_progress_downloading\">Преузимање „%s“</string>\n    <string name=\"installer_notification_progress_commiting\">Инсталирање „%s“</string>\n    <string name=\"installer_notification_progress_failed\">Неуспешно инсталирано „%s“</string>\n    <string name=\"installer_notification_progress_splitinstall_downloading\">Преузимање потребних компоненти за %s</string>\n    <string name=\"installer_notification_progress_splitinstall_commiting\">Инсталирање потребних компоненти за %s</string>\n    <string name=\"vending_overview_enterprise_no_apps_available_wait\">Може проћи неколико сати након подешавања радног профила пре него што апликације буду спремне за преузимање.</string>\n    <string name=\"installer_notification_progress_complete\">Инсталирано „%s“</string>\n    <string name=\"installer_dependency_noun\">Потребне компоненте за %s</string>\n    <string name=\"installer_notification_channel_description\">Приказује напредак инсталације апликација и компоненти, поруке о успеху и неуспеху.</string>\n    <string name=\"vending_overview_enterprise_row_offered_hint\">Ово су све апликације које је ваше предузеће учинило доступним.</string>\n    <string name=\"billing_permission_desc\">Омогућава кориснику да купује ставке предмете преко Google Play-а из ове апликације.</string>\n    <string name=\"billing_permission_label\">Google Play услуга наплате</string>\n    <string name=\"installer_notification_progress_splitinstall_click_install\">Додирните да бисте инсталирали компоненте које захтева %s</string>\n</resources>\n"
  },
  {
    "path": "vending-app/src/main/res/values-sv/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"toast_installed\">microG Companion kan inte användas fristående. Öppnade inställningar för microG-tjänster istället.</string>\n    <string name=\"toast_not_installed\">microG Companion kan inte användas fristående. Installera microG-tjänster för att använda microG.</string>\n    <string name=\"app_name\">microG Companion</string>\n    <string name=\"license_notification_channel_name\">Licensaviseringar</string>\n    <string name=\"license_notification_channel_description\">Meddelar när en app försöker validera sin licens, men du inte är inloggad på något Google-konto.</string>\n    <string name=\"license_notification_title\">%1$s kunde inte verifera licens</string>\n    <string name=\"license_notification_body\">Om appen beter sig illa, logga in på det Google-konto som du har köpt appen med.</string>\n    <string name=\"license_notification_sign_in\">Logga in</string>\n    <string name=\"license_notification_ignore\">Ignorera</string>\n    <string name=\"pay_disabled\">Betalning är för närvarande inte möjlig</string>\n    <string name=\"error_passwd\">Du angav ett felaktigt lösenord.</string>\n    <string name=\"tips_input_passwd\">Ange ditt lösenord</string>\n    <string name=\"tips_remember_login_info\">Kom ihåg mina inloggningsuppgifter på denna enhet</string>\n    <string name=\"confirm_purchase\">Bekräfta köp</string>\n    <string name=\"error_network\">Inte ansluten till internet. Se till att Wi-Fi eller mobilnät är aktiverat och försök igen.</string>\n    <string name=\"error_unknown\">Okänt fel, avsluta och försök igen.</string>\n    <string name=\"tips_forget_passwd\">Glömt lösenordet?</string>\n    <string name=\"tips_more_details\">Läs mer</string>\n    <string name=\"text_verify_button\">Verifiera</string>\n    <string name=\"download_notification_attachment_file\">Fler filer för %s</string>\n    <string name=\"download_notification_tips\">Laddar ner</string>\n    <string name=\"vending_overview_enterprise_row_offered\">Tillgängliga appar</string>\n    <string name=\"vending_overview_row_installed\">Installerade appar</string>\n    <string name=\"installer_notification_progress_commiting\">Installerar \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_failed\">Kunde inte installera \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_complete\">Installerade \\\"%s\\\"</string>\n    <string name=\"installer_notification_channel_name\">App och komponentinstallation</string>\n    <string name=\"installer_notification_progress_downloading\">Laddar ner \\\"%s\\\"</string>\n    <string name=\"installer_dependency_noun\">Nödvändiga komponenter för %s</string>\n    <string name=\"vending_overview_enterprise_row_offered_hint\">Dessa är alla appar som görs tillgängliga av ditt företag.</string>\n    <string name=\"vending_activity_name\">Work App Store</string>\n    <string name=\"vending_overview_row_action_uninstall\">Avinstallera</string>\n    <string name=\"installer_notification_channel_description\">Visar förlopp för app- och komponentinstallation, framgångs- och felmeddelanden.</string>\n    <string name=\"vending_overview_enterprise_no_apps_available_wait\">Det kan ta några timmar efter installationen av din arbetsprofil innan appar är redo att laddas ner.</string>\n    <string name=\"vending_overview_enterprise_no_apps_available\">Inga appar har gjorts tillgängliga av din administratör.</string>\n    <string name=\"vending_overview_row_action_install\">Installera</string>\n    <string name=\"installer_notification_progress_splitinstall_commiting\">Installerar nödvändiga komponenter för %s</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_hint\">Din administratör kräver att dessa appar installeras i din hanterade profil.</string>\n    <string name=\"vending_overview_enterprise_row_mandatory\">Installation krävs</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_missing_hint\">Din enhet saknas obligatoriska appar som valts av din administratör.</string>\n    <string name=\"vending_overview_row_update_available\">Uppdatering tillgänglig</string>\n    <string name=\"vending_overview_row_action_update\">Uppdatera</string>\n    <string name=\"error_retry\">Försök igen</string>\n    <string name=\"installer_notification_progress_splitinstall_downloading\">Laddar ner nödvändiga komponenter för %s</string>\n    <string name=\"billing_permission_desc\">Tillåter användaren att köpa objekt via Google Play inifrån denna app.</string>\n    <string name=\"billing_permission_label\">Google Play faktureringstjänst</string>\n    <string name=\"installer_notification_progress_splitinstall_click_install\">Klicka för att installera de komponenter som krävs av %s</string>\n    <string name=\"app_install_permission_allowed\">Tillåt</string>\n    <string name=\"app_install_needs_permissions_title\">App Installer</string>\n    <string name=\"app_install_allow_to_install_third_app\">Tillåt \\\"MikroG Companion\\\" att installera appar som hämtats från \\\"%1$s\\\"</string>\n    <string name=\"app_install_refuse_permission_remind\">Om du nekar kommer appinstallationen att misslyckas.</string>\n    <string name=\"app_install_refuse_permission_remind_sub\">Du kan ändra auktoriseringsstatus när som helst i mikroG Service inställningar.</string>\n    <string name=\"app_install_not_remind_again\">Behåll detta val och fråga inte igen</string>\n</resources>\n"
  },
  {
    "path": "vending-app/src/main/res/values-ta/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\">நுண்சீ தோழமை</string>\n    <string name=\"toast_installed\">நுண்சீ தோழமை தனித்தனியாகப் பயன்படுத்த முடியாது. அதற்குப் பதிலாக நுண்சீ பணி அமைப்புகளைத் திறந்தது.</string>\n    <string name=\"toast_not_installed\">நுண்சீ தோழமை தனித்தனியாகப் பயன்படுத்த முடியாது. நுண்சீயைப் பயன்படுத்த நுண்சீ சேவைகளை நிறுவவும்.</string>\n    <string name=\"license_notification_channel_name\">உரிம அறிவிப்புகள்</string>\n    <string name=\"license_notification_channel_description\">ஒரு பயன்பாடு அதன் உரிமத்தை சரிபார்க்க முயற்சிக்கும்போது அறிவிக்கிறது, ஆனால் நீங்கள் எந்தக் கூகிள் கணக்கிலும் உள்நுழையவில்லை.</string>\n    <string name=\"license_notification_title\">%1$s உரிமத்தை சரிபார்க்க முடியவில்லை</string>\n    <string name=\"license_notification_body\">பயன்பாடு தவறாக நடந்து கொண்டால், நீங்கள் பயன்பாட்டை வாங்கிய கூகிள் கணக்கில் உள்நுழைக.</string>\n    <string name=\"license_notification_sign_in\">விடுபதிகை</string>\n    <string name=\"license_notification_ignore\">புறக்கணி</string>\n    <string name=\"pay_disabled\">கட்டணம் தற்போது சாத்தியமில்லை</string>\n    <string name=\"confirm_purchase\">வாங்குவதை உறுதிப்படுத்து</string>\n    <string name=\"error_network\">இணையத்துடன் இணைக்கப்படவில்லை. வைபை அல்லது மொபைல் பிணையம் இயக்கப்பட்டிருப்பதை உறுதிசெய்து மீண்டும் முயற்சிக்கவும்.</string>\n    <string name=\"error_passwd\">நீங்கள் உள்ளிட்ட கடவுச்சொல் தவறானது.</string>\n    <string name=\"error_unknown\">தெரியாத பிழை, தயவுசெய்து வெளியேறி மீண்டும் முயற்சி.</string>\n    <string name=\"tips_input_passwd\">உங்கள் கடவுச்சொல்லை உள்ளிடவும்</string>\n    <string name=\"tips_remember_login_info\">இந்தச் சாதனத்தில் எனது உள்நுழைவை நினைவில் கொள்</string>\n    <string name=\"tips_forget_passwd\">கடவுச்சொல்லை மறக்கவா?</string>\n    <string name=\"tips_more_details\">மேலும் அறிக</string>\n    <string name=\"text_verify_button\">சரிபார்</string>\n    <string name=\"download_notification_attachment_file\">%s க்கான கூடுதல் கோப்புகள்</string>\n    <string name=\"download_notification_tips\">பதிவிறக்குகிறது</string>\n    <string name=\"vending_activity_name\">வேலை ஆப் கடை</string>\n    <string name=\"vending_overview_enterprise_row_mandatory\">நிறுவல் தேவை</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_hint\">உங்கள் நிர்வகிக்கப்பட்ட சுயவிவரத்தில் இந்த பயன்பாடுகள் நிறுவப்பட வேண்டும்.</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_missing_hint\">உங்கள் நிர்வாகி தேர்ந்தெடுக்கப்பட்ட கட்டாய பயன்பாடுகளை உங்கள் சாதனம் காணவில்லை.</string>\n    <string name=\"vending_overview_enterprise_row_offered\">கிடைக்கும் பயன்பாடுகள்</string>\n    <string name=\"vending_overview_enterprise_row_offered_hint\">இவை அனைத்தும் உங்கள் நிறுவனத்தால் கிடைக்கக்கூடிய பயன்பாடுகள்.</string>\n    <string name=\"vending_overview_enterprise_no_apps_available\">உங்கள் நிர்வாகியால் பயன்பாடுகள் எதுவும் கிடைக்கவில்லை.</string>\n    <string name=\"vending_overview_enterprise_no_apps_available_wait\">பயன்பாடுகள் பதிவிறக்கம் செய்யத் தயாராக இருப்பதற்கு முன்பு உங்கள் பணி சுயவிவரத்தை அமைத்த சில மணிநேரங்கள் ஆகலாம்.</string>\n    <string name=\"vending_overview_row_update_available\">புதுப்பிப்பு கிடைக்கிறது</string>\n    <string name=\"vending_overview_row_installed\">நிறுவப்பட்ட பயன்பாடுகள்</string>\n    <string name=\"vending_overview_row_action_install\">நிறுவவும்</string>\n    <string name=\"vending_overview_row_action_update\">புதுப்பிப்பு</string>\n    <string name=\"vending_overview_row_action_uninstall\">நிறுவல் நீக்க</string>\n    <string name=\"error_retry\">மீண்டும் முயற்சிக்கவும்</string>\n    <string name=\"installer_notification_channel_name\">பயன்பாடு மற்றும் கூறு நிறுவல்</string>\n    <string name=\"installer_notification_channel_description\">பயன்பாடு மற்றும் கூறு நிறுவல் முன்னேற்றம், செய் மற்றும் தோல்வி செய்திகளைக் காட்டுகிறது.</string>\n    <string name=\"installer_notification_progress_downloading\">\\\"%s\\\" ஐ பதிவிறக்குகிறது</string>\n    <string name=\"installer_notification_progress_commiting\">\\\"%s\\\" ஐ நிறுவுதல்</string>\n    <string name=\"installer_notification_progress_complete\">நிறுவப்பட்டது \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_failed\">\\\"%s\\\" ஐ நிறுவுவதில் தோல்வி</string>\n    <string name=\"installer_dependency_noun\">%s க்கு தேவையான கூறுகள்</string>\n    <string name=\"installer_notification_progress_splitinstall_downloading\">%s க்கு தேவையான கூறுகளைப் பதிவிறக்குகிறது</string>\n    <string name=\"installer_notification_progress_splitinstall_commiting\">%s க்கு தேவையான கூறுகளை நிறுவுதல்</string>\n    <string name=\"installer_notification_progress_splitinstall_click_install\">%s-க்குத் தேவையான கூறுகளை நிறுவ கிளிக் செய்யவும்</string>\n    <string name=\"billing_permission_desc\">இந்தப் பயன்பாட்டிலிருந்தே Google Play மூலம் பொருட்களை வாங்க பயனரை அனுமதிக்கிறது.</string>\n    <string name=\"billing_permission_label\">கூகிள் ப்ளே பில்லிங் சேவை</string>\n    <string name=\"app_install_permission_allowed\">இசைவு</string>\n    <string name=\"app_install_needs_permissions_title\">பயன்பாட்டு நிறுவி</string>\n    <string name=\"app_install_allow_to_install_third_app\">\\\"%1$s\\\" இலிருந்து பதிவிறக்கம் செய்யப்பட்ட பயன்பாடுகளை நிறுவ \\\"நுண்சி துணைவன்\\\" ஐ இசைவு\\\"</string>\n    <string name=\"app_install_refuse_permission_remind\">நீங்கள் மறுத்தால், பயன்பாட்டு நிறுவல் தோல்வியடையும்.</string>\n    <string name=\"app_install_refuse_permission_remind_sub\">நுண்சி சேவை அமைப்புகளில் எந்த நேரத்திலும் அங்கீகார நிலை இசைவுகளை நீங்கள் மாற்றலாம்.</string>\n    <string name=\"app_install_not_remind_again\">இந்த தேர்வை வைத்திருங்கள், மீண்டும் கேட்க வேண்டாம்</string>\n</resources>\n"
  },
  {
    "path": "vending-app/src/main/res/values-th/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_notification_title\">%1$s ไม่สามารถตรวจสอบใบอนุญาตได้</string>\n    <string name=\"license_notification_body\">หากแอปทำงานผิดปกติ ให้ลงชื่อเข้าใช้ด้วยบัญชี Google ที่คุณใช้ซื้อแอปนี้</string>\n    <string name=\"license_notification_sign_in\">เข้าสู่ระบบ</string>\n    <string name=\"app_name\">microG Companion</string>\n    <string name=\"toast_installed\">microG Companion ไม่สามารถใช้งานโดยลำพังได้ ให้เปิดการตั้งค่าบริการจาก microG ก่อน</string>\n    <string name=\"toast_not_installed\">microG Companion ไม่สามารถติดตั้งและใช้งานเพียงตัวเดียวได้ โปรดติดตั้ง บริการของ microG เพื่อเข้าใช้งาน</string>\n    <string name=\"license_notification_channel_name\">การแจ้งเตือนใบอนุญาต</string>\n    <string name=\"license_notification_channel_description\">แจ้งเตือนเมื่อแอปพยายามตรวจสอบสิทธิ์การใช้งาน แต่คุณยังไม่ได้ลงชื่อเข้าใช้ด้วยบัญชี Google ใด ๆ</string>\n    <string name=\"license_notification_ignore\">เพิกเฉย</string>\n    <string name=\"pay_disabled\">ไม่สามารถชำระเงินได้ในขณะนี้</string>\n    <string name=\"confirm_purchase\">ยืนยันการชำระเงิน</string>\n    <string name=\"error_network\">ไม่ได้เชื่อมต่ออินเทอร์เน็ต โปรดตรวจสอบให้แน่ใจว่าเปิด Wi-Fi หรือเครือข่ายมือถือแล้วลองอีกครั้ง</string>\n    <string name=\"error_passwd\">รหัสผ่านที่คุณป้อนไม่ถูกต้อง</string>\n    <string name=\"error_unknown\">ข้อผิดพลาดที่ไม่รู้จัก กรุณาออกแล้วลองอีกครั้ง</string>\n    <string name=\"tips_input_passwd\">กรอกรหัสผ่านของคุณ</string>\n    <string name=\"tips_remember_login_info\">จดจำการเข้าสู่ระบบของฉันบนอุปกรณ์นี้</string>\n    <string name=\"tips_forget_passwd\">ลืมรหัสผ่าน?</string>\n    <string name=\"tips_more_details\">เรียนรู้เพิ่มเติม</string>\n    <string name=\"text_verify_button\">ตรวจสอบ</string>\n    <string name=\"download_notification_attachment_file\">ไฟล์เพิ่มเติมสำหรับ %s</string>\n    <string name=\"download_notification_tips\">กำลังดาวน์โหลด</string>\n    <string name=\"vending_overview_enterprise_row_offered\">แอปที่มีพร้อมใช้งาน</string>\n    <string name=\"vending_overview_row_action_install\">ติดตั้ง</string>\n    <string name=\"vending_overview_row_action_update\">อัปเดต</string>\n    <string name=\"installer_notification_progress_downloading\">กำลังดาวน์โหลด \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_complete\">ติดตั้งแล้ว \\\"%s\\\"</string>\n    <string name=\"installer_dependency_noun\">ส่วนประกอบที่จำเป็นสำหรับ %s</string>\n    <string name=\"installer_notification_progress_splitinstall_downloading\">กำลังดาวน์โหลดส่วนประกอบที่จำเป็นสำหรับ %s</string>\n    <string name=\"installer_notification_progress_splitinstall_commiting\">กำลังติดตั้งส่วนประกอบที่จำเป็นสำหรับ %s</string>\n    <string name=\"vending_overview_row_action_uninstall\">ถอนการติดตั้ง</string>\n    <string name=\"vending_overview_enterprise_no_apps_available\">ยังไม่มีแอปใดที่ผู้ดูแลระบบเปิดให้ใช้งาน</string>\n    <string name=\"vending_overview_row_installed\">แอปที่ติดตั้งแล้ว</string>\n    <string name=\"installer_notification_channel_name\">การติดตั้งแอปและองค์ประกอบ</string>\n    <string name=\"installer_notification_channel_description\">แสดงความคืบหน้าการติดตั้งแอปและส่วนประกอบ พร้อมข้อความแสดงความสำเร็จหรือความล้มเหลว</string>\n    <string name=\"installer_notification_progress_commiting\">กำลังติดตั้ง \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_failed\">ไม่สามารถติดตั้งได้ \\\"%s\\\"</string>\n    <string name=\"vending_overview_enterprise_row_mandatory\">จำเป็นต้องติดตั้ง</string>\n    <string name=\"vending_overview_row_update_available\">มีอัปเดตพร้อมใช้งาน</string>\n    <string name=\"vending_overview_enterprise_row_offered_hint\">แอปทั้งหมดนี้เป็นแอปที่องค์กรของคุณเปิดให้ใช้งาน</string>\n    <string name=\"vending_activity_name\">คลังแอปของบริษัท</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_hint\">ผู้ดูแลระบบกำหนดให้ต้องติดตั้งแอปเหล่านี้ในโปรไฟล์ที่มีการจัดการของคุณ</string>\n    <string name=\"vending_overview_enterprise_no_apps_available_wait\">อาจต้องใช้เวลาหลายชั่วโมงหลังจากตั้งค่าโปรไฟล์งานก่อนที่แอปจะพร้อมให้ดาวน์โหลด</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_missing_hint\">อุปกรณ์ของคุณไม่มีแอปที่จำเป็นซึ่งผู้ดูแลระบบเป็นผู้กำหนดไว้</string>\n    <string name=\"error_retry\">ลองใหม่อีกครั้ง</string>\n    <string name=\"billing_permission_desc\">อนุญาตให้ผู้ใช้ซื้อสินค้าได้ผ่าน Google Play จากภายในแอปนี้</string>\n    <string name=\"billing_permission_label\">บริการชำระเงินของ Google Play</string>\n    <string name=\"installer_notification_progress_splitinstall_click_install\">คลิกเพื่อติดตั้งส่วนประกอบที่จำเป็นโดย %s</string>\n    <string name=\"app_install_permission_allowed\">อนุญาต</string>\n    <string name=\"app_install_needs_permissions_title\">โปรแกรมติดตั้งแอป</string>\n    <string name=\"app_install_allow_to_install_third_app\">อนุญาตให้ \\\"microG Companion\\\" ติดตั้งแอปที่ดาวน์โหลดจาก \\\"%1$s\\\"</string>\n    <string name=\"app_install_refuse_permission_remind\">หากคุณปฏิเสธ การติดตั้งแอปพลิเคชันจะล้มเหลว</string>\n    <string name=\"app_install_refuse_permission_remind_sub\">คุณสามารถแก้ไขสถานะการอนุญาตได้ตลอดเวลาในการตั้งค่าบริการ microG</string>\n    <string name=\"app_install_not_remind_again\">เก็บการเลือกนี้ไว้และไม่ต้องถามซ้ำอีก</string>\n</resources>\n"
  },
  {
    "path": "vending-app/src/main/res/values-tr/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"toast_not_installed\">microG Servisleri tek başına kullanılamaz. microG\\'yi kullanmak için lütfen microG Servisleri\\'ni yükleyin.</string>\n    <string name=\"license_notification_title\">%1$s lisansı doğrulanamadı</string>\n    <string name=\"license_notification_body\">Eğer uygulama hatalı davranıyorsa, uygulamayı satın aldığınız Google hesabınız ile giriş yapın.</string>\n    <string name=\"license_notification_ignore\">Yoksay</string>\n    <string name=\"pay_disabled\">Ödeme henüz mümkün değil</string>\n    <string name=\"confirm_purchase\">Ödemeyi onayla</string>\n    <string name=\"error_network\">İnternete bağlı değilsiniz. Lütfen Wi-Fi veya mobil verinin açık olduğundan emin olun ve ardından tekrar deneyin.</string>\n    <string name=\"error_unknown\">Bilinmeyen hata, lütfen çıkın ve tekrar deneyin.</string>\n    <string name=\"tips_input_passwd\">Şifrenizi girin</string>\n    <string name=\"tips_remember_login_info\">Bu cihazdaki oturumumu hatırla</string>\n    <string name=\"tips_forget_passwd\">Şifrenizi mi unuttunuz?</string>\n    <string name=\"tips_more_details\">Daha fazla bilgi</string>\n    <string name=\"license_notification_channel_description\">Bir uygulama lisansını doğrulamaya çalıştığında ancak siz herhangi bir Google hesabında oturum açmadığınızda bildirim gönderir.</string>\n    <string name=\"license_notification_sign_in\">Giriş yap</string>\n    <string name=\"toast_installed\">microG Eşlikçisi tek başına kullanılamaz. Onun yerine microG Servisleri ayarları açılıyor.</string>\n    <string name=\"license_notification_channel_name\">Lisans bildirimleri</string>\n    <string name=\"error_passwd\">Girdiğiniz şifre yanlış.</string>\n    <string name=\"text_verify_button\">Onayla</string>\n    <string name=\"app_name\">microG Eşlikçisi</string>\n    <string name=\"download_notification_attachment_file\">%s için ek dosyalar</string>\n    <string name=\"download_notification_tips\">İndiriliyor</string>\n    <string name=\"vending_overview_enterprise_row_mandatory\">Kurulum gerekli</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_hint\">Yöneticiniz, bu uygulamaların yönetilen profilinize yüklenmesini gerektiriyor.</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_missing_hint\">Cihazınız, yöneticiniz tarafından zorunlu kılınan uygulamalara sahip değil.</string>\n    <string name=\"vending_overview_enterprise_row_offered\">Mevcut uygulamalar</string>\n    <string name=\"vending_overview_enterprise_row_offered_hint\">Bu uygulamalar kuruluşunuz tarafından sunuldu.</string>\n    <string name=\"vending_overview_enterprise_no_apps_available\">Kuruluşunuz tarafından sunulan herhangi bir uygulama yok.</string>\n    <string name=\"vending_overview_row_update_available\">Güncelleme mevcut</string>\n    <string name=\"vending_overview_row_installed\">Yüklenen uygulamalar</string>\n    <string name=\"vending_overview_row_action_install\">Yükle</string>\n    <string name=\"vending_overview_row_action_update\">Güncelle</string>\n    <string name=\"vending_overview_row_action_uninstall\">Kaldır</string>\n    <string name=\"error_retry\">Tekrar dene</string>\n    <string name=\"installer_notification_channel_name\">Uygulama ve bileşen kurulumu</string>\n    <string name=\"vending_activity_name\">İş uygulama mağazası</string>\n    <string name=\"installer_notification_progress_downloading\">\\\"%s\\\" indiriliyor</string>\n    <string name=\"installer_notification_progress_commiting\">\\\"%s\\\" yükleniyor</string>\n    <string name=\"installer_notification_progress_complete\">\\\"%s\\\" yüklendi</string>\n    <string name=\"installer_notification_progress_failed\">\\\"%s\\\" kurarken hata</string>\n    <string name=\"installer_dependency_noun\">%s için gerekli bileşenler</string>\n    <string name=\"installer_notification_progress_splitinstall_downloading\">%s için gerekli bileşenler indiriliyor</string>\n    <string name=\"installer_notification_progress_splitinstall_commiting\">%s için gerekli bileşenler kuruluyor</string>\n    <string name=\"installer_notification_progress_splitinstall_click_install\">%s için gerekli bileşenleri kurmak için dokunun</string>\n    <string name=\"billing_permission_label\">Google Play satın alma servisi</string>\n    <string name=\"billing_permission_desc\">Kullanıcının bu uygulama içinde Google Play üzerinden öğe satın almasına izin verir.</string>\n    <string name=\"vending_overview_enterprise_no_apps_available_wait\">İş profilinizi oluşturduktan sonra uygulamaların indirilmeye hazır hale gelmesi birkaç saat sürebilir.</string>\n    <string name=\"installer_notification_channel_description\">Uygulama ve bileşen kurulumunun ilerlemesini, başarı ve hata mesajlarını gösterir.</string>\n    <string name=\"app_install_permission_allowed\">İzin ver</string>\n    <string name=\"app_install_needs_permissions_title\">Uygulama Kurucu</string>\n    <string name=\"app_install_allow_to_install_third_app\">\\\"microG Eşlikçisi\\\" uygulamasının \\\"%1$s\\\" üzerinden indirilen uygulamaları kurmasına izin ver</string>\n    <string name=\"app_install_refuse_permission_remind\">Reddederseniz, uygulama kurulumu başarısız olacaktır.</string>\n    <string name=\"app_install_refuse_permission_remind_sub\">Yetki durumu izinlerini microG Hizmet Ayarlarında istediğiniz zaman değiştirebilirsiniz.</string>\n    <string name=\"app_install_not_remind_again\">Bu seçimi koru ve tekrar sorma</string>\n</resources>\n"
  },
  {
    "path": "vending-app/src/main/res/values-ug/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"license_notification_title\">%1$s ئىجازەتنامىنى دەلىللىيەلمىدى</string>\n    <string name=\"license_notification_body\">ئەگەر ئەپتە خاتالىق كۆرۈلسە، مەزكۇر ئەپنى سېتىۋالغاندا ئىشلەتكەن Google ھېساباتىغا تىزىمغا كىرىڭ.</string>\n    <string name=\"license_notification_channel_description\">ئەپ ئىجازەتنامىسىنى دەلىللەشنى سىناپ ئەمما ھېچقانداق Google ھېساباتىغا تىزىمغا كىرەلمىسە ئۇقتۇرىدۇ.</string>\n    <string name=\"confirm_purchase\">سېتىۋېلىشنى جەزملەڭ</string>\n    <string name=\"license_notification_ignore\">پەرۋا قىلما</string>\n    <string name=\"pay_disabled\">نۆۋەتتە چىقىم ئىقتىدارىنى ئىشلەتكىلى بولمايدۇ</string>\n    <string name=\"error_network\">ئىنتېرنېتقا باغلانمىغان. Wi-Fi ياكى كۆچمە تورنىڭ ئوچۇق ئىكەنلىكىنى جەزملەپ ئاندىن قايتا سىناڭ.</string>\n    <string name=\"error_passwd\">سىز كىرگۈزگەن ئىم خاتا.</string>\n    <string name=\"error_unknown\">يوچۇن خاتالىق، چېكىنىپ قايتا سىناڭ.</string>\n    <string name=\"tips_input_passwd\">ئىم كىرگۈزۈلىدۇ</string>\n    <string name=\"tips_remember_login_info\">بۇ ئۈسكۈنىدە تىزىمغا كىرگىنىمنى ئەستە تۇت</string>\n    <string name=\"download_notification_attachment_file\">%s نىڭ قوشۇمچە ھۆججىتى</string>\n    <string name=\"toast_installed\">microG Companion نى ئايرىم ئىشلەتكىلى بولمايدۇ. ئورنىغا microG مۇلازىمەت تەڭشىكىنى ئاچتى.</string>\n    <string name=\"toast_not_installed\">microG Companion نى ئايرىم ئىشلەتكىلى بولمايدۇ. microG نى ئىشلىتىش ئۈچۈن microG مۇلازىمىتىنى ئورنىتىڭ.</string>\n    <string name=\"license_notification_channel_name\">ئىجازەتنامە ئۇقتۇرۇشى</string>\n    <string name=\"license_notification_sign_in\">تىزىمغا كىرىڭ</string>\n    <string name=\"app_name\">microG شېرىكلىرى</string>\n    <string name=\"tips_forget_passwd\">ئىم ئۇنتۇلغانمۇ؟</string>\n    <string name=\"tips_more_details\">تېخىمۇ كۆپ بىلىملەر</string>\n    <string name=\"text_verify_button\">دەلىللە</string>\n    <string name=\"download_notification_tips\">چۈشۈرۈۋاتىدۇ</string>\n    <string name=\"vending_activity_name\">خىزمەت ئەپ دۇكىنى</string>\n    <string name=\"vending_overview_enterprise_row_offered\">بار ئەپلەر</string>\n    <string name=\"vending_overview_row_update_available\">يېڭىلاش بار</string>\n    <string name=\"vending_overview_row_action_install\">ئورنات</string>\n    <string name=\"vending_overview_row_action_update\">يېڭىلا</string>\n    <string name=\"vending_overview_row_action_uninstall\">ئورنىتىشنى ئۆچۈر</string>\n    <string name=\"error_retry\">قايتا سىنا</string>\n    <string name=\"installer_notification_channel_name\">ئەپ ۋە بۆلەك ئورنىتىش</string>\n    <string name=\"installer_notification_progress_downloading\">چۈشۈرۈۋاتقىنى «%s»</string>\n    <string name=\"installer_notification_progress_complete\">«%s» ئورنىتىلدى</string>\n    <string name=\"installer_notification_progress_failed\">«%s» نى ئورنىتالمىدى</string>\n    <string name=\"installer_notification_progress_splitinstall_downloading\">%s غا زۆرۈر بۆلەكلەرنى چۈشۈرۈۋاتىدۇ</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_hint\">باشقۇرغۇچىڭىز باشقۇرۇلىدىغان تەرجىمىھالغا بۇ ئەپلەرنىڭ ئورنىتىلغان بولۇشنى تەلەپ قىلىدۇ.</string>\n    <string name=\"vending_overview_enterprise_no_apps_available\">باشقۇرغۇچىڭىز ئىشلىتىشكە ھېچقانداق ئەپ تەمىنلىمىگەن.</string>\n    <string name=\"vending_overview_row_installed\">ئورنىتىلغان ئەپ</string>\n    <string name=\"installer_notification_channel_description\">ئەپ ۋە بۆلەك ئورنىتىشنىڭ جەريانى، مۇۋەپپەقىيەتلىك ۋە مەغلۇپ بولغانلىق ئۇچۇرىنى كۆرسىتىدۇ.</string>\n    <string name=\"vending_overview_enterprise_row_offered_hint\">كارخانىڭىز ئىشلىتىشكە تەمىنلىگەن ئەپلەر.</string>\n    <string name=\"vending_overview_enterprise_row_mandatory\">ئورنىتىش زۆرۈر</string>\n    <string name=\"installer_notification_progress_splitinstall_commiting\">%s غا زۆرۈر بۆلەكلەرنى ئورنىتىۋاتىدۇ</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_missing_hint\">ئۈسكۈنىڭىزدە باشقۇرغۇچى بەلگىلىگەن مەجبۇرىي ئەپ كەم.</string>\n    <string name=\"vending_overview_enterprise_no_apps_available_wait\">خىزمەت تەرجىمىھالىنى تەڭشىگەندىن كېيىن ئىشلىتىدىغان ئەپنىڭ چۈشۈرۈشكە تەييار بولۇشىغا بىر قانچە سائەت كېتىشى مۇمكىن.</string>\n    <string name=\"installer_dependency_noun\">%s غا زۆرۈر بۆلەكلەر</string>\n    <string name=\"installer_notification_progress_commiting\">«%s» نى ئورنىتىۋاتىدۇ</string>\n    <string name=\"installer_notification_progress_splitinstall_click_install\">چېكىلسە %s غا زۆرۈر بولغان بۆلەكنى ئورنىتىدۇ</string>\n    <string name=\"billing_permission_desc\">ئىشلەتكۈچىنىڭ Google Play ئارقىلىق بۇ ئەپتە مەھسۇلات سېتىۋېلىشىغا يول قويىدۇ.</string>\n    <string name=\"billing_permission_label\">Google Play ھېسابات مۇلازىمىتى</string>\n    <string name=\"app_install_permission_allowed\">يول قوي</string>\n    <string name=\"app_install_needs_permissions_title\">ئەپ ئورناتقۇچ</string>\n    <string name=\"app_install_allow_to_install_third_app\">«microG بۆلىكى» نىڭ «%1$s» دىن چۈشۈرگەن ئەپنى ئورنىتىشىغا يول قويىدۇ</string>\n    <string name=\"app_install_refuse_permission_remind\">ئەگەر رەت قىلسىڭىز، ئەپ ئورنىتىش مەغلۇپ بولىدۇ.</string>\n    <string name=\"app_install_refuse_permission_remind_sub\">سىز microG مۇلازىمەت تەڭشىكىدىن خالىغان ۋاقىتتا سالاھىيەت دەلىللەش ئىجازەت ھالىتىنى ئۆزگەرتەلەيسىز.</string>\n    <string name=\"app_install_not_remind_again\">بۇ تاللانمىنى ساقلاپ قالپ ۋە قايتا سورىما</string>\n</resources>\n"
  },
  {
    "path": "vending-app/src/main/res/values-uk/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"toast_installed\">microG Companion не можна використовувати окремо. Натомість відкрито налаштування служб microG.</string>\n    <string name=\"toast_not_installed\">microG Companion не можна використовувати окремо. Будь ласка, встановіть microG служби, щоб використовувати microG.</string>\n    <string name=\"app_name\">microG Companion</string>\n    <string name=\"pay_disabled\">Оплатити наразі неможливо</string>\n    <string name=\"error_passwd\">Введено неправильний пароль.</string>\n    <string name=\"tips_input_passwd\">Введіть пароль</string>\n    <string name=\"tips_more_details\">Докладніше</string>\n    <string name=\"text_verify_button\">Підтвердити</string>\n    <string name=\"license_notification_body\">Якщо застосунок поводиться неправильно, увійдіть в обліковий запис Google, за допомогою якого ви придбали його.</string>\n    <string name=\"confirm_purchase\">Підтвердити покупку</string>\n    <string name=\"error_network\">Не під\\'єднано до мережі. Переконайтеся, що Wi-Fi або мобільна мережа ввімкнені, й спробуйте ще раз.</string>\n    <string name=\"error_unknown\">Невідома помилка, вийдіть та спробуйте ще раз.</string>\n    <string name=\"tips_remember_login_info\">Запам\\'ятати мої дані входу на цьому пристрої</string>\n    <string name=\"tips_forget_passwd\">Забули пароль?</string>\n    <string name=\"license_notification_channel_name\">Сповіщення про ліцензії</string>\n    <string name=\"license_notification_channel_description\">Сповіщає, коли застосунок намагається підтвердити свою ліцензію, але ви не ввійшли до жодного облікового запису Google.</string>\n    <string name=\"license_notification_title\">%1$s не вдалося підтвердити ліцензію</string>\n    <string name=\"license_notification_sign_in\">Увійти</string>\n    <string name=\"license_notification_ignore\">Ігнорувати</string>\n    <string name=\"download_notification_attachment_file\">Додаткові файли для %s</string>\n    <string name=\"download_notification_tips\">Завантаження</string>\n    <string name=\"vending_activity_name\">Магазин робочих застосунків</string>\n    <string name=\"vending_overview_enterprise_row_mandatory\">Потрібне встановлення</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_hint\">Ваш адміністратор вимагає, щоб ці застосунки були встановлені у вашому керованому профілі.</string>\n    <string name=\"vending_overview_enterprise_row_offered_hint\">Це всі застосунки, доступні у вашій компанії.</string>\n    <string name=\"vending_overview_row_update_available\">Доступне оновлення</string>\n    <string name=\"vending_overview_row_installed\">Встановлені застосунки</string>\n    <string name=\"vending_overview_row_action_install\">Встановити</string>\n    <string name=\"vending_overview_row_action_update\">Оновити</string>\n    <string name=\"vending_overview_row_action_uninstall\">Видалити</string>\n    <string name=\"installer_notification_channel_name\">Встановлення застосунків і компонентів</string>\n    <string name=\"installer_notification_channel_description\">Показує хід встановлення застосунку та компонентів, повідомлення про успіх та невдачу.</string>\n    <string name=\"installer_notification_progress_downloading\">Завантаження «%s»</string>\n    <string name=\"installer_notification_progress_commiting\">Встановлення «%s»</string>\n    <string name=\"installer_notification_progress_complete\">«%s» встановлено</string>\n    <string name=\"installer_notification_progress_failed\">Не вдалося встановити «%s»</string>\n    <string name=\"installer_dependency_noun\">Необхідні компоненти для %s</string>\n    <string name=\"installer_notification_progress_splitinstall_downloading\">Завантаження необхідних компонентів для %s</string>\n    <string name=\"installer_notification_progress_splitinstall_commiting\">Встановлення необхідних компонентів для %s</string>\n    <string name=\"vending_overview_enterprise_no_apps_available\">Ваш адміністратор не надав доступ до жодного застосунку.</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_missing_hint\">На вашому пристрої відсутні обов\\'язкові застосунки, вибрані вашим адміністратором.</string>\n    <string name=\"vending_overview_enterprise_no_apps_available_wait\">Після налаштування робочого профілю може знадобитися кілька годин, перш ніж застосунки будуть готові до завантаження.</string>\n    <string name=\"vending_overview_enterprise_row_offered\">Доступні застосунки</string>\n    <string name=\"error_retry\">Повторити</string>\n    <string name=\"billing_permission_desc\">Дозволяє користувачеві купувати товари через Google Play із цієї програми.</string>\n    <string name=\"billing_permission_label\">Платіжний сервіс Google Play</string>\n    <string name=\"installer_notification_progress_splitinstall_click_install\">Натисніть, щоби встановити компоненти, необхідні для %s</string>\n    <string name=\"app_install_permission_allowed\">Дозволити</string>\n    <string name=\"app_install_needs_permissions_title\">Встановлювач застосунків</string>\n    <string name=\"app_install_allow_to_install_third_app\">Дозволити «microG Companion» установлювати застосунки, завантажені з «%1$s»</string>\n    <string name=\"app_install_refuse_permission_remind\">Якщо ви відхилите, встановлення заcтосунку не вдасться.</string>\n    <string name=\"app_install_refuse_permission_remind_sub\">Ви можете змінити дозволи статусу авторизації в будь-який час у налаштуваннях сервісів microG.</string>\n    <string name=\"app_install_not_remind_again\">Запам’ятати вибір і більше не запитувати</string>\n</resources>\n"
  },
  {
    "path": "vending-app/src/main/res/values-v11/styles.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2014 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n<resources>\n\n    <style name=\"Theme.Dialog.NoActionBar\" parent=\"@android:style/Theme.Dialog\">\n        <item name=\"android:windowActionBar\">false</item>\n        <item name=\"android:windowNoTitle\">true</item>\n        <item name=\"android:windowBackground\">@android:color/transparent</item>\n    </style>\n</resources>\n"
  },
  {
    "path": "vending-app/src/main/res/values-v26/ic_app_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ SPDX-FileCopyrightText: 2023 microG Project Team\n  ~ SPDX-License-Identifier: Apache-2.0\n  -->\n\n<resources>\n    <color name=\"ic_app_background\">#C0CA33</color>\n</resources>"
  },
  {
    "path": "vending-app/src/main/res/values-vi/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\">Trợ lý microG</string>\n    <string name=\"toast_installed\">Trợ lý microG không thể hoạt động độc lập. Chuyển hướng sang cài đặt Dịch vụ microG.</string>\n    <string name=\"toast_not_installed\">Trợ lý microG không thể hoạt động độc lập. Vui lòng cài đặt Dịch vụ microG để tiếp tục sử dụng.</string>\n    <string name=\"license_notification_channel_name\">Thông báo giấy phép</string>\n    <string name=\"license_notification_channel_description\">Thông báo khi một ứng dụng cố gắng xác minh giấy phép, nhưng bạn chưa đăng nhập vào bất kỳ tài khoản Google nào.</string>\n    <string name=\"license_notification_title\">không thể xác minh giấy phép %1$s</string>\n    <string name=\"license_notification_body\">Nếu ứng dụng hoạt động không đúng, hãy đăng nhập bằng tài khoản Google mà bạn đã dùng để mua ứng dụng đó.</string>\n    <string name=\"license_notification_sign_in\">Đăng nhập</string>\n    <string name=\"license_notification_ignore\">Bỏ qua</string>\n    <string name=\"pay_disabled\">Hiện tại không thể thanh toán</string>\n    <string name=\"confirm_purchase\">Xác nhận mua hàng</string>\n    <string name=\"error_network\">Không kết nối được với Internet. Vui lòng kết nối Wi-Fi hoặc dữ liệu di động và thử lại.</string>\n    <string name=\"error_passwd\">Mật khẩu bạn nhập không đúng.</string>\n    <string name=\"error_unknown\">Lỗi không xác định, vui lòng thoát và thử lại.</string>\n    <string name=\"tips_input_passwd\">Nhập mật khẩu của bạn</string>\n    <string name=\"tips_remember_login_info\">Nhớ thông tin đăng nhập của tôi trên thiết bị này</string>\n    <string name=\"tips_forget_passwd\">Quên mật khẩu?</string>\n    <string name=\"tips_more_details\">Tìm hiểu thêm</string>\n    <string name=\"text_verify_button\">Xác minh</string>\n    <string name=\"download_notification_attachment_file\">Các tệp tin bổ sung cho %s</string>\n    <string name=\"download_notification_tips\">Đang tải xuống</string>\n    <string name=\"vending_overview_enterprise_row_offered\">Các ứng dụng hiện có</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_missing_hint\">Thiết bị của bạn thiếu các ứng dụng cần thiết do quản trị viên yêu cầu.</string>\n    <string name=\"vending_overview_row_installed\">Ứng dụng đã cài đặt</string>\n    <string name=\"vending_overview_row_action_install\">Cài đặt</string>\n    <string name=\"error_retry\">Thử lại</string>\n    <string name=\"vending_overview_row_action_uninstall\">Gỡ cài đặt</string>\n    <string name=\"installer_notification_channel_name\">Cài đặt ứng dụng và thành phần bổ sung</string>\n    <string name=\"installer_notification_progress_downloading\">Đang tải xuống \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_commiting\">Đang cài đặt \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_complete\">Đã cài đặt \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_failed\">Không thể cài đặt \\\"%s\\\"</string>\n    <string name=\"installer_dependency_noun\">Các thành phần cần thiết cho %s</string>\n    <string name=\"installer_notification_progress_splitinstall_downloading\">Đang tải xuống các thành phần cần thiết cho %s</string>\n    <string name=\"installer_notification_progress_splitinstall_commiting\">Đang cài đặt các thành phần cần thiết cho %s</string>\n    <string name=\"vending_overview_enterprise_row_offered_hint\">Đây là tất cả các ứng dụng được cung cấp bởi doanh nghiệp của bạn.</string>\n    <string name=\"vending_overview_row_update_available\">Đã có bản cập nhật</string>\n    <string name=\"vending_overview_enterprise_no_apps_available\">Không có ứng dụng nào được cung cấp bởi quản trị viên của bạn.</string>\n    <string name=\"vending_overview_row_action_update\">Cập nhật</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_hint\">Quản trị viên yêu cầu bạn cài đặt các ứng dụng này trong hồ sơ được quản lý.</string>\n    <string name=\"vending_overview_enterprise_row_mandatory\">Yêu cầu cài đặt</string>\n    <string name=\"vending_activity_name\">Cửa hàng ứng dụng doanh nghiệp</string>\n    <string name=\"vending_overview_enterprise_no_apps_available_wait\">Sau khi thiết lập hồ sơ công việc, có thể mất vài giờ trước khi các ứng dụng sẵn sàng để tải xuống.</string>\n    <string name=\"installer_notification_channel_description\">Hiển thị quá trình cài đặt ứng dụng và thành phần, cũng như thông báo thành công hoặc lỗi.</string>\n    <string name=\"billing_permission_desc\">Cho phép người dùng mua hàng thông qua Google Play từ trong ứng dụng này.</string>\n    <string name=\"billing_permission_label\">Dịch vụ thanh toán Google Play</string>\n    <string name=\"installer_notification_progress_splitinstall_click_install\">Nhấn để cài đặt thành phần cần thiết cho %s</string>\n</resources>\n"
  },
  {
    "path": "vending-app/src/main/res/values-zh-rCN/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"toast_installed\">microG 伴侣 不可单独使用。已转而打开 microG 服务设置。</string>\n    <string name=\"toast_not_installed\">microG 伴侣 不可单独使用。请安装 microG 服务以使用 microG。</string>\n    <string name=\"pay_disabled\">支付功能不可用</string>\n    <string name=\"confirm_purchase\">确定购买</string>\n    <string name=\"error_network\">未连接到互联网。请确保WLAN网络或移动数据网络已开启，然后重试。</string>\n    <string name=\"error_passwd\">您输入的密码有误。</string>\n    <string name=\"error_unknown\">未知错误，请退出重试。</string>\n    <string name=\"tips_input_passwd\">输入您的密码</string>\n    <string name=\"tips_remember_login_info\">在此设备上记住我的登录信息</string>\n    <string name=\"tips_forget_passwd\">忘记了密码？</string>\n    <string name=\"tips_more_details\">了解详情</string>\n    <string name=\"text_verify_button\">验证</string>\n    <string name=\"license_notification_channel_name\">许可证通知</string>\n    <string name=\"license_notification_channel_description\">当应用尝试验证其许可证但您未登录任何 Google 账户时发出通知。</string>\n    <string name=\"license_notification_title\">%1$s无法验证许可证</string>\n    <string name=\"license_notification_body\">如果应用出现异常，请登录您购买该应用所使用的 Google 帐号。</string>\n    <string name=\"license_notification_sign_in\">登录</string>\n    <string name=\"license_notification_ignore\">忽略</string>\n    <string name=\"installer_notification_progress_splitinstall_downloading\">正在下载 %s 所需的组件</string>\n    <string name=\"app_name\">microG 伴侣</string>\n    <string name=\"download_notification_attachment_file\">%s的附件文件</string>\n    <string name=\"download_notification_tips\">文件下载中</string>\n    <string name=\"vending_activity_name\">Work 应用商店</string>\n    <string name=\"vending_overview_enterprise_row_mandatory\">需要安装</string>\n    <string name=\"vending_overview_enterprise_row_offered\">可用的应用</string>\n    <string name=\"vending_overview_row_update_available\">有更新可用</string>\n    <string name=\"vending_overview_row_action_install\">安装</string>\n    <string name=\"vending_overview_row_action_update\">更新</string>\n    <string name=\"vending_overview_row_action_uninstall\">卸载</string>\n    <string name=\"error_retry\">重试</string>\n    <string name=\"installer_notification_channel_name\">应用和组件安装</string>\n    <string name=\"installer_notification_progress_downloading\">正在下载“%s”</string>\n    <string name=\"installer_notification_channel_description\">显示应用和组件安装进度，成功和失败消息。</string>\n    <string name=\"installer_notification_progress_commiting\">正在安装“%s”</string>\n    <string name=\"installer_notification_progress_complete\">已安装“%s”</string>\n    <string name=\"installer_notification_progress_failed\">未能安装“%s”</string>\n    <string name=\"installer_dependency_noun\">%s 的必需组件</string>\n    <string name=\"installer_notification_progress_splitinstall_commiting\">正在安装 %s 的必需组件</string>\n    <string name=\"vending_overview_enterprise_no_apps_available_wait\">设置好工作资料后可能要过几个小时才能下载其中的应用。</string>\n    <string name=\"vending_overview_enterprise_row_offered_hint\">这些应用均由你的企业提供。</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_hint\">你的管理员要求在你的受管理的资料中安装这些应用。</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_missing_hint\">你的设备缺少由你的管理员选择的强制应用。</string>\n    <string name=\"vending_overview_enterprise_no_apps_available\">你的管理员尚未提供应用。</string>\n    <string name=\"vending_overview_row_installed\">已安装的应用</string>\n    <string name=\"installer_notification_progress_splitinstall_click_install\">点击安装 %s 所需的组件</string>\n    <string name=\"billing_permission_desc\">允许用户通过 Google Play 在此应用内购买商品。</string>\n    <string name=\"billing_permission_label\">Google Play 结算服务</string>\n    <string name=\"app_install_permission_allowed\">允许</string>\n    <string name=\"app_install_needs_permissions_title\">必要授权提醒</string>\n    <string name=\"app_install_allow_to_install_third_app\">允许 “microG 伴侣” 安装从 “%1$s” 下载的应用程序</string>\n    <string name=\"app_install_refuse_permission_remind\">如果您拒绝，应用程序将安装失败。</string>\n    <string name=\"app_install_refuse_permission_remind_sub\">您可以随时在 “microG 设置页面” 中修改授权状态权限。</string>\n    <string name=\"app_install_not_remind_again\">保留此选择，不再询问</string>\n</resources>\n"
  },
  {
    "path": "vending-app/src/main/res/values-zh-rTW/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"vending_overview_enterprise_row_offered\">可用的應用程式</string>\n    <string name=\"vending_overview_row_update_available\">更新可用</string>\n    <string name=\"vending_overview_row_installed\">已安裝的應用程式</string>\n    <string name=\"vending_overview_row_action_install\">安裝</string>\n    <string name=\"installer_notification_progress_commiting\">正在安裝 \\\"%s\\\"</string>\n    <string name=\"installer_notification_progress_splitinstall_commiting\">正在為 %s 安裝需要的元件</string>\n    <string name=\"toast_installed\">microG Companion 無法單獨使用，已改為開啟 microG Services 設定。</string>\n    <string name=\"vending_overview_enterprise_no_apps_available\">您的管理員尚未提供任何可用的應用程式。</string>\n    <string name=\"installer_notification_channel_name\">應用程式與元件安裝</string>\n    <string name=\"installer_notification_progress_downloading\">正在下載 \\\"%s\\\"</string>\n    <string name=\"vending_overview_row_action_uninstall\">解除安裝</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_hint\">您的管理員要求在受管理的設定檔中安裝這些應用程式。</string>\n    <string name=\"vending_overview_enterprise_no_apps_available_wait\">在設定工作設定檔後，可能需要幾個小時應用程式才會準備好供下載。</string>\n    <string name=\"installer_notification_channel_description\">顯示應用程式與元件的安裝進度、成功與失敗訊息。</string>\n    <string name=\"vending_activity_name\">工作應用程式商店</string>\n    <string name=\"installer_notification_progress_splitinstall_downloading\">正在下載 %s 所需的元件</string>\n    <string name=\"vending_overview_row_action_update\">更新</string>\n    <string name=\"vending_overview_enterprise_row_mandatory\">需要安裝</string>\n    <string name=\"vending_overview_enterprise_row_offered_hint\">這些是您的企業提供的所有可用應用程式。</string>\n    <string name=\"error_network\">未連接至網際網路。請確認已開啟 Wi-Fi 或行動網路，然後再試一次。</string>\n    <string name=\"vending_overview_enterprise_row_mandatory_missing_hint\">您的裝置缺少管理員指定的必要應用程式。</string>\n    <string name=\"installer_notification_progress_complete\">已安裝 \\\"%s\\\"</string>\n    <string name=\"confirm_purchase\">確認購買</string>\n    <string name=\"error_retry\">重試</string>\n    <string name=\"installer_notification_progress_failed\">\\\"%s\\\" 安裝失敗</string>\n    <string name=\"installer_dependency_noun\">需要 %s 的元件</string>\n    <string name=\"pay_disabled\">支付功能目前不可用</string>\n    <string name=\"error_passwd\">您輸入的密碼錯誤。</string>\n    <string name=\"error_unknown\">未知錯誤，請退出再試。</string>\n    <string name=\"tips_input_passwd\">輸入您的密碼</string>\n    <string name=\"tips_remember_login_info\">在此設備上記住我的登入資訊</string>\n    <string name=\"tips_forget_passwd\">忘記密碼？</string>\n    <string name=\"tips_more_details\">了解詳情</string>\n    <string name=\"text_verify_button\">驗證</string>\n    <string name=\"license_notification_channel_description\">當應用程式嘗試驗證其授權，但您尚未登入任何 Google 帳戶時通知您。</string>\n    <string name=\"license_notification_channel_name\">授權通知</string>\n    <string name=\"license_notification_title\">%1$s 無法驗證授權</string>\n    <string name=\"license_notification_body\">如果應用程式出現異常，請登入您購買該應用程式所使用的 Google 帳號。</string>\n    <string name=\"license_notification_sign_in\">登入</string>\n    <string name=\"license_notification_ignore\">忽略</string>\n    <string name=\"app_name\">microG Companion</string>\n    <string name=\"toast_not_installed\">microG Companion 無法單獨使用，請安裝 microG Services 以使用 microG 。</string>\n    <string name=\"download_notification_attachment_file\">%s 的附加元件</string>\n    <string name=\"download_notification_tips\">下載中</string>\n    <string name=\"billing_permission_desc\">允許使用者透過 Google Play 在此應用程式內購買商品。</string>\n    <string name=\"billing_permission_label\">Google Play 結帳服務</string>\n</resources>\n"
  }
]